From 6ca07eca689b477e95b1bef17321aec75de93ae1 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Fri, 22 Mar 2019 12:40:12 +0800 Subject: [PATCH 001/486] esp_common: add version definitions in code and build system Closes https://github.com/espressif/esp-idf/issues/2482 Closes IDF-253 --- .gitlab-ci.yml | 12 ++++ .../esp_common/include/esp_idf_version.h | 58 +++++++++++++++++ components/esp_common/include/esp_system.h | 9 +-- docs/Doxyfile | 2 + docs/en/api-guides/build-system-cmake.rst | 1 + docs/en/api-guides/build-system.rst | 1 + docs/en/api-reference/system/system.rst | 16 +++++ docs/zh_CN/api-guides/build-system-cmake.rst | 1 + docs/zh_CN/api-guides/build-system.rst | 1 + make/common.mk | 3 + make/project.mk | 2 +- make/version.mk | 3 + tools/ci/check_idf_version.sh | 62 +++++++++++++++++++ tools/ci/executable-list.txt | 1 + tools/cmake/idf.cmake | 1 + tools/cmake/version.cmake | 3 + 16 files changed, 167 insertions(+), 9 deletions(-) create mode 100644 components/esp_common/include/esp_idf_version.h create mode 100644 make/version.mk create mode 100755 tools/ci/check_idf_version.sh create mode 100644 tools/cmake/version.cmake diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 48a9624ef3..6ca788c665 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -855,6 +855,18 @@ check_permissions: script: - tools/ci/check-executable.sh +check_version: + <<: *check_job_template + # Don't run this for feature/bugfix branches, so that it is possible to modify + # esp_idf_version.h in a branch before tagging the next version. + only: + - master + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ + script: + - export IDF_PATH=$PWD + - tools/ci/check_idf_version.sh + check_examples_cmake_make: <<: *check_job_template except: diff --git a/components/esp_common/include/esp_idf_version.h b/components/esp_common/include/esp_idf_version.h new file mode 100644 index 0000000000..52601ca8f6 --- /dev/null +++ b/components/esp_common/include/esp_idf_version.h @@ -0,0 +1,58 @@ +// Copyright 2019 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 + +#ifdef __cplusplus +extern "C" { +#endif + +/** Major version number (X.x.x) */ +#define ESP_IDF_VERSION_MAJOR 4 +/** Minor version number (x.X.x) */ +#define ESP_IDF_VERSION_MINOR 0 +/** Patch version number (x.x.X) */ +#define ESP_IDF_VERSION_PATCH 0 + +/** + * Macro to convert IDF version number into an integer + * + * To be used in comparisons, such as ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) + */ +#define ESP_IDF_VERSION_VAL(major, minor, patch) ((major << 16) | (minor << 8) | (patch)) + +/** + * Current IDF version, as an integer + * + * To be used in comparisons, such as ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) + */ +#define ESP_IDF_VERSION ESP_IDF_VERSION_VAL(ESP_IDF_VERSION_MAJOR, \ + ESP_IDF_VERSION_MINOR, \ + ESP_IDF_VERSION_PATCH) + +/** + * Return full IDF version string, same as 'git describe' output. + * + * @note If you are printing the ESP-IDF version in a log file or other information, + * this function provides more information than using the numerical version macros. + * For example, numerical version macros don't differentiate between development, + * pre-release and release versions, but the output of this function does. + * + * @return constant string from IDF_VER + */ +const char* esp_get_idf_version(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_common/include/esp_system.h b/components/esp_common/include/esp_system.h index 97dc916222..13c8f198df 100644 --- a/components/esp_common/include/esp_system.h +++ b/components/esp_common/include/esp_system.h @@ -20,6 +20,7 @@ #include "esp_err.h" #include "esp_attr.h" #include "esp_bit_defs.h" +#include "esp_idf_version.h" #include "sdkconfig.h" @@ -311,14 +312,6 @@ esp_err_t esp_derive_local_mac(uint8_t* local_mac, const uint8_t* universal_mac) const char* system_get_sdk_version(void) __attribute__ ((deprecated)); /** @endcond */ -/** - * Get IDF version - * - * @return constant string from IDF_VER - */ -const char* esp_get_idf_version(void); - - /** * @brief Chip models */ diff --git a/docs/Doxyfile b/docs/Doxyfile index cd92c69096..0673440bdc 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -179,6 +179,8 @@ INPUT = \ ## Base MAC address ## NOTE: for line below header_file.inc is not used ../../components/esp_common/include/esp_system.h \ + ## IDF version + ../../components/esp_common/include/esp_idf_version.h \ ## ## ULP Coprocessor - API Guides ## diff --git a/docs/en/api-guides/build-system-cmake.rst b/docs/en/api-guides/build-system-cmake.rst index a3c068bf90..b524481221 100644 --- a/docs/en/api-guides/build-system-cmake.rst +++ b/docs/en/api-guides/build-system-cmake.rst @@ -350,6 +350,7 @@ from the component CMakeLists.txt: - ``PROJECT_DIR``: Absolute path of the project directory containing the project CMakeLists. Same as the ``CMAKE_SOURCE_DIR`` variable. - ``COMPONENTS``: Names of all components that are included in this build, formatted as a semicolon-delimited CMake list. - ``IDF_VER``: Git version of ESP-IDF (produced by ``git describe``) +- ``IDF_VERSION_MAJOR``, ``IDF_VERSION_MINOR``, ``IDF_VERSION_PATCH``: Components of ESP-IDF version, to be used in conditional expressions. Note that this information is less precise than that provided by ``IDF_VER`` variable. ``v4.0-dev-*``, ``v4.0-beta1``, ``v4.0-rc1`` and ``v4.0`` will all have the same values of ``IDF_VERSION_*`` variables, but different ``IDF_VER`` values. - ``IDF_TARGET``: Name of the target for which the project is being built. - ``PROJECT_VER``: Project version. diff --git a/docs/en/api-guides/build-system.rst b/docs/en/api-guides/build-system.rst index 8c85c65d3c..5f936c05f3 100644 --- a/docs/en/api-guides/build-system.rst +++ b/docs/en/api-guides/build-system.rst @@ -188,6 +188,7 @@ The following variables are set at the project level, but exported for use in th - ``CC``, ``LD``, ``AR``, ``OBJCOPY``: Full paths to each tool from the gcc xtensa cross-toolchain. - ``HOSTCC``, ``HOSTLD``, ``HOSTAR``: Full names of each tool from the host native toolchain. - ``IDF_VER``: ESP-IDF version, retrieved from either ``$(IDF_PATH)/version.txt`` file (if present) else using git command ``git describe``. Recommended format here is single liner that specifies major IDF release version, e.g. ``v2.0`` for a tagged release or ``v2.0-275-g0efaa4f`` for an arbitrary commit. Application can make use of this by calling :cpp:func:`esp_get_idf_version`. +- ``IDF_VERSION_MAJOR``, ``IDF_VERSION_MINOR``, ``IDF_VERSION_PATCH``: Components of ESP-IDF version, to be used in conditional expressions. Note that this information is less precise than that provided by ``IDF_VER`` variable. ``v4.0-dev-*``, ``v4.0-beta1``, ``v4.0-rc1`` and ``v4.0`` will all have the same values of ``ESP_IDF_VERSION_*`` variables, but different ``IDF_VER`` values. - ``PROJECT_VER``: Project version. * If ``PROJECT_VER`` variable is set in project Makefile file, its value will be used. diff --git a/docs/en/api-reference/system/system.rst b/docs/en/api-reference/system/system.rst index a15860e8a1..719452c3f5 100644 --- a/docs/en/api-reference/system/system.rst +++ b/docs/en/api-reference/system/system.rst @@ -109,6 +109,21 @@ SDK version :cpp:func:`esp_get_idf_version` returns a string describing the IDF version which was used to compile the application. This is the same value as the one available through ``IDF_VER`` variable of the build system. The version string generally has the format of ``git describe`` output. +To get the version at build time, additional version macros are provided. They can be used to enable or disable parts of the program depending on IDF version. + +* :c:macro:`ESP_IDF_VERSION_MAJOR`, :c:macro:`ESP_IDF_VERSION_MINOR`, :c:macro:`ESP_IDF_VERSION_PATCH` are defined to integers representing major, minor, and patch version. + +* :c:macro:`ESP_IDF_VERSION_VAL` and :c:macro:`ESP_IDF_VERSION` can be used when implementing version checks: + + .. code-block:: c + + #include "esp_idf_version.h" + + #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) + // enable functionality present in IDF v4.0 + #endif + + App version ----------- Application version is stored in :cpp:class:`esp_app_desc_t` structure. It is located in DROM sector and has a fixed offset from the beginning of the binary file. @@ -125,5 +140,6 @@ API Reference ------------- .. include:: /_build/inc/esp_system.inc +.. include:: /_build/inc/esp_idf_version.inc diff --git a/docs/zh_CN/api-guides/build-system-cmake.rst b/docs/zh_CN/api-guides/build-system-cmake.rst index 96b46aa926..43935a3ae5 100644 --- a/docs/zh_CN/api-guides/build-system-cmake.rst +++ b/docs/zh_CN/api-guides/build-system-cmake.rst @@ -315,6 +315,7 @@ ESP-IDF 在搜索所有待构建的组件时,会按照 ``COMPONENT_DIRS`` 指 - ``COMPONENTS``:此次构建中包含的所有组件的名称,具体格式为用分号隔开的 CMake 列表。 - ``CONFIG_*``:项目配置中的每个值在 cmake 中都对应一个以 ``CONFIG_`` 开头的变量。更多详细信息请参阅 :doc:`Kconfig `。 - ``IDF_VER``:ESP-IDF 的 git 版本号,由 ``git describe`` 命令生成。 +- ``IDF_VERSION_MAJOR``, ``IDF_VERSION_MINOR``, ``IDF_VERSION_PATCH``: ESP-IDF 的组件版本,可用于条件表达式。请注意这些信息的精确度不如 ``IDF_VER`` 变量,版本号 ``v4.0-dev-*``, ``v4.0-beta1``, ``v4.0-rc1`` 和 ``v4.0`` 对应的 ``IDF_VERSION_*`` 变量值是相同的,但是 ``IDF_VER`` 的值是不同的。 - ``IDF_TARGET``:项目的硬件目标名称。 - ``PROJECT_VER``:项目版本号。 diff --git a/docs/zh_CN/api-guides/build-system.rst b/docs/zh_CN/api-guides/build-system.rst index 366f7d79f6..60bba24ef0 100644 --- a/docs/zh_CN/api-guides/build-system.rst +++ b/docs/zh_CN/api-guides/build-system.rst @@ -176,6 +176,7 @@ ESP-IDF 搜索组件时,会按照 ``COMPONENT_DIRS`` 指定的顺序依次进 - ``CC``,``LD``,``AR``,``OBJCOPY``: gcc xtensa 交叉编译工具链中每个工具的完整路径。 - ``HOSTCC``,``HOSTLD``,``HOSTAR``: 主机本地工具链中每个工具的全名。 - ``IDF_VER``: ESP-IDF 的版本号,可以通过检索 ``$(IDF_PATH)/version.txt`` 文件(假如存在的话)或者使用 git 命令 ``git describe`` 来获取。这里推荐的格式是在一行中指定主 IDF 的发布版本号,例如标记为 ``v2.0`` 的发布版本或者是标记任意一次提交记录的 ``v2.0-275-g0efaa4f``。应用程序可以通过调用 :cpp:func:`esp_get_idf_version` 函数来使用该变量。 +- ``IDF_VERSION_MAJOR``, ``IDF_VERSION_MINOR``, ``IDF_VERSION_PATCH``: ESP-IDF 的组件版本,可用于条件表达式。请注意这些信息的精确度不如 ``IDF_VER`` 变量,版本号 ``v4.0-dev-*``, ``v4.0-beta1``, ``v4.0-rc1`` 和 ``v4.0`` 对应的 ``IDF_VERSION_*`` 变量值是相同的,但是 ``IDF_VER`` 的值是不同的。 如果您在 ``component.mk`` 文件中修改这些变量,这并不会影响其它组件的构建,但可能会使您的组件变得难以构建或调试。 diff --git a/make/common.mk b/make/common.mk index 6280ca4a87..bb0000a101 100644 --- a/make/common.mk +++ b/make/common.mk @@ -38,6 +38,9 @@ ifdef CONFIG_SDK_MAKE_WARN_UNDEFINED_VARIABLES MAKEFLAGS += --warn-undefined-variables endif +# Get version variables +include $(IDF_PATH)/make/version.mk + # General make utilities # convenience variable for printing an 80 asterisk wide separator line diff --git a/make/project.mk b/make/project.mk index 2f1def70d2..bd375afaf6 100644 --- a/make/project.mk +++ b/make/project.mk @@ -126,7 +126,7 @@ export PROJECT_PATH endif # A list of the "common" makefiles, to use as a target dependency -COMMON_MAKEFILES := $(abspath $(IDF_PATH)/make/project.mk $(IDF_PATH)/make/common.mk $(IDF_PATH)/make/component_wrapper.mk $(firstword $(MAKEFILE_LIST))) +COMMON_MAKEFILES := $(abspath $(IDF_PATH)/make/project.mk $(IDF_PATH)/make/common.mk $(IDF_PATH)/make/version.mk $(IDF_PATH)/make/component_wrapper.mk $(firstword $(MAKEFILE_LIST))) export COMMON_MAKEFILES # The directory where we put all objects/libraries/binaries. The project Makefile can diff --git a/make/version.mk b/make/version.mk new file mode 100644 index 0000000000..9dcda422af --- /dev/null +++ b/make/version.mk @@ -0,0 +1,3 @@ +IDF_VERSION_MAJOR := 4 +IDF_VERSION_MINOR := 0 +IDF_VERSION_PATCH := 0 diff --git a/tools/ci/check_idf_version.sh b/tools/ci/check_idf_version.sh new file mode 100755 index 0000000000..36fdf003f2 --- /dev/null +++ b/tools/ci/check_idf_version.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +set -u +set -e + +echo "Checking if IDF version in esp_idf_version.h matches 'git describe' output" + +function get_ver_from_header() { + # Get the 3rd word from '#define ESP_IDF_VERSION_X ' line. + grep -E "^#define ${1}" components/esp_common/include/esp_idf_version.h | awk '{print $3;}' +} + +function get_ver_from_make() { + grep -E "^${1} :=" make/version.mk | awk '{print $3;}' +} + +function get_ver_from_cmake() { + grep -E "^set\(${1}" tools/cmake/version.cmake | sed -En "s/set\(${1} ([0-9])\)/\1/p" +} + +header_ver_major=$(get_ver_from_header ESP_IDF_VERSION_MAJOR) +header_ver_minor=$(get_ver_from_header ESP_IDF_VERSION_MINOR) +header_ver_patch=$(get_ver_from_header ESP_IDF_VERSION_PATCH) +version_from_header="${header_ver_major}.${header_ver_minor}.${header_ver_patch}" + +make_ver_major=$(get_ver_from_make IDF_VERSION_MAJOR) +make_ver_minor=$(get_ver_from_make IDF_VERSION_MINOR) +make_ver_patch=$(get_ver_from_make IDF_VERSION_PATCH) +version_from_make="${make_ver_major}.${make_ver_minor}.${make_ver_patch}" + +cmake_ver_major=$(get_ver_from_cmake IDF_VERSION_MAJOR) +cmake_ver_minor=$(get_ver_from_cmake IDF_VERSION_MINOR) +cmake_ver_patch=$(get_ver_from_cmake IDF_VERSION_PATCH) +version_from_cmake="${cmake_ver_major}.${cmake_ver_minor}.${cmake_ver_patch}" + +git_desc=$(git describe --tags) +git_desc_regex="^v([0-9]+)\.([0-9]+)(\.([0-9]+))?.*$" +if [[ ! ${git_desc} =~ ${git_desc_regex} ]]; then + echo "Could not determine the version from 'git describe' output: ${git_desc}" + exit 1 +fi +version_from_git="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.${BASH_REMATCH[4]:-0}" + +echo "From esp_idf_version.h: ${version_from_header}" +echo "From version.mk: ${version_from_make}" +echo "From version.cmake: ${version_from_cmake}" +echo "From git describe: ${version_from_git}" + +if [[ "${version_from_header}" != "${version_from_git}" ]]; then + echo "esp_idf_version.h does not match 'git describe' output" + exit 1 +fi + +if [[ "${version_from_make}" != "${version_from_git}" ]]; then + echo "version.mk does not match 'git describe' output" + exit 1 +fi + +if [[ "${version_from_cmake}" != "${version_from_git}" ]]; then + echo "version.cmake does not match 'git describe' output" + exit 1 +fi diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index 14071ab2eb..49bb916268 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -21,6 +21,7 @@ docs/gen-version-specific-includes.py tools/ci/apply_bot_filter.py tools/ci/build_examples.sh tools/ci/build_examples_cmake.sh +tools/ci/check_idf_version.sh tools/ci/check-executable.sh tools/ci/check-line-endings.sh tools/ci/checkout_project_ref.py diff --git a/tools/cmake/idf.cmake b/tools/cmake/idf.cmake index 9d45fd9ddf..e97d83fcd9 100644 --- a/tools/cmake/idf.cmake +++ b/tools/cmake/idf.cmake @@ -38,6 +38,7 @@ if(NOT __idf_env_set) include(utilities) include(targets) include(ldgen) + include(version) __build_init("${idf_path}") diff --git a/tools/cmake/version.cmake b/tools/cmake/version.cmake new file mode 100644 index 0000000000..265ab33b7b --- /dev/null +++ b/tools/cmake/version.cmake @@ -0,0 +1,3 @@ +set(IDF_VERSION_MAJOR 4) +set(IDF_VERSION_MINOR 0) +set(IDF_VERSION_PATCH 0) From 6b08e8b44966fadba83e09cbc47f6f86bac03e51 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 20 May 2019 19:07:28 +0800 Subject: [PATCH 002/486] esp_timer: handle esp_timer_delete in timer task Closes https://github.com/espressif/esp-idf/issues/3458 --- components/esp32/test/test_esp_timer.c | 55 ++++++++++++++++++++++ components/esp_common/src/esp_timer.c | 63 ++++++++------------------ 2 files changed, 74 insertions(+), 44 deletions(-) diff --git a/components/esp32/test/test_esp_timer.c b/components/esp32/test/test_esp_timer.c index b46cca5608..e3444503a1 100644 --- a/components/esp32/test/test_esp_timer.c +++ b/components/esp32/test/test_esp_timer.c @@ -536,6 +536,61 @@ TEST_CASE("Can delete timer from callback", "[esp_timer]") vSemaphoreDelete(args.notify_from_timer_cb); } + +typedef struct { + SemaphoreHandle_t delete_start; + SemaphoreHandle_t delete_done; + SemaphoreHandle_t test_done; + esp_timer_handle_t timer; +} timer_delete_test_args_t; + +static void timer_delete_task(void* arg) +{ + timer_delete_test_args_t* args = (timer_delete_test_args_t*) arg; + xSemaphoreTake(args->delete_start, portMAX_DELAY); + printf("Deleting the timer\n"); + esp_timer_delete(args->timer); + printf("Timer deleted\n"); + xSemaphoreGive(args->delete_done); + vTaskDelete(NULL); +} + +static void timer_delete_test_callback(void* arg) +{ + timer_delete_test_args_t* args = (timer_delete_test_args_t*) arg; + printf("Timer callback called\n"); + xSemaphoreGive(args->delete_start); + xSemaphoreTake(args->delete_done, portMAX_DELAY); + printf("Callback complete\n"); + xSemaphoreGive(args->test_done); +} + +TEST_CASE("Can delete timer from a separate task, triggered from callback", "[esp_timer]") +{ + timer_delete_test_args_t args = { + .delete_start = xSemaphoreCreateBinary(), + .delete_done = xSemaphoreCreateBinary(), + .test_done = xSemaphoreCreateBinary(), + }; + + esp_timer_create_args_t timer_args = { + .callback = &timer_delete_test_callback, + .arg = &args + }; + esp_timer_handle_t timer; + TEST_ESP_OK(esp_timer_create(&timer_args, &timer)); + args.timer = timer; + + xTaskCreate(timer_delete_task, "deleter", 4096, &args, 5, NULL); + + esp_timer_start_once(timer, 100); + TEST_ASSERT(xSemaphoreTake(args.test_done, pdMS_TO_TICKS(1000))); + + vSemaphoreDelete(args.delete_done); + vSemaphoreDelete(args.delete_start); + vSemaphoreDelete(args.test_done); +} + TEST_CASE("esp_timer_impl_advance moves time base correctly", "[esp_timer]") { ref_clock_init(); diff --git a/components/esp_common/src/esp_timer.c b/components/esp_common/src/esp_timer.c index 616cc25458..82a2d0b85b 100644 --- a/components/esp_common/src/esp_timer.c +++ b/components/esp_common/src/esp_timer.c @@ -39,12 +39,17 @@ #endif #include "sys/queue.h" +#define EVENT_ID_DELETE_TIMER 0xF0DE1E1E + #define TIMER_EVENT_QUEUE_SIZE 16 struct esp_timer { uint64_t alarm; uint64_t period; - esp_timer_cb_t callback; + union { + esp_timer_cb_t callback; + uint32_t event_id; + }; void* arg; #if WITH_PROFILING const char* name; @@ -77,23 +82,18 @@ static LIST_HEAD(esp_timer_list, esp_timer) s_timers = // all the timers static LIST_HEAD(esp_inactive_timer_list, esp_timer) s_inactive_timers = LIST_HEAD_INITIALIZER(s_timers); -// used to keep track of the timer when executing the callback -static esp_timer_handle_t s_timer_in_callback; #endif // task used to dispatch timer callbacks static TaskHandle_t s_timer_task; // counting semaphore used to notify the timer task from ISR static SemaphoreHandle_t s_timer_semaphore; -// mutex which protects timers from deletion during callback execution -static SemaphoreHandle_t s_timer_delete_mutex; #if CONFIG_SPIRAM_USE_MALLOC -// memory for s_timer_semaphore and s_timer_delete_mutex +// memory for s_timer_semaphore static StaticQueue_t s_timer_semaphore_memory; -static StaticQueue_t s_timer_delete_mutex_memory; #endif -// lock protecting s_timers, s_inactive_timers, s_timer_in_callback +// lock protecting s_timers, s_inactive_timers static portMUX_TYPE s_timer_lock = portMUX_INITIALIZER_UNLOCKED; @@ -164,15 +164,10 @@ esp_err_t esp_timer_delete(esp_timer_handle_t timer) if (timer_armed(timer)) { return ESP_ERR_INVALID_STATE; } - xSemaphoreTakeRecursive(s_timer_delete_mutex, portMAX_DELAY); -#if WITH_PROFILING - if (timer == s_timer_in_callback) { - s_timer_in_callback = NULL; - } - timer_remove_inactive(timer); -#endif - free(timer); - xSemaphoreGiveRecursive(s_timer_delete_mutex); + timer->event_id = EVENT_ID_DELETE_TIMER; + timer->alarm = esp_timer_get_time() + 50; + timer->period = 0; + timer_insert(timer); return ESP_OK; } @@ -267,13 +262,17 @@ static void timer_process_alarm(esp_timer_dispatch_t dispatch_method) /* unused, provision to allow running callbacks from ISR */ (void) dispatch_method; - xSemaphoreTakeRecursive(s_timer_delete_mutex, portMAX_DELAY); timer_list_lock(); uint64_t now = esp_timer_impl_get_time(); esp_timer_handle_t it = LIST_FIRST(&s_timers); while (it != NULL && it->alarm < now) { LIST_REMOVE(it, list_entry); + if (it->event_id == EVENT_ID_DELETE_TIMER) { + free(it); + it = LIST_FIRST(&s_timers); + continue; + } if (it->period > 0) { it->alarm += it->period; timer_insert(it); @@ -285,21 +284,14 @@ static void timer_process_alarm(esp_timer_dispatch_t dispatch_method) } #if WITH_PROFILING uint64_t callback_start = now; - s_timer_in_callback = it; #endif timer_list_unlock(); (*it->callback)(it->arg); timer_list_lock(); now = esp_timer_impl_get_time(); #if WITH_PROFILING - /* The callback might have deleted the timer. - * If this happens, esp_timer_delete will set s_timer_in_callback - * to NULL. - */ - if (s_timer_in_callback) { - s_timer_in_callback->times_triggered++; - s_timer_in_callback->total_callback_run_time += now - callback_start; - } + it->times_triggered++; + it->total_callback_run_time += now - callback_start; #endif it = LIST_FIRST(&s_timers); } @@ -308,7 +300,6 @@ static void timer_process_alarm(esp_timer_dispatch_t dispatch_method) esp_timer_impl_set_alarm(first->alarm); } timer_list_unlock(); - xSemaphoreGiveRecursive(s_timer_delete_mutex); } static void timer_task(void* arg) @@ -356,18 +347,6 @@ esp_err_t esp_timer_init(void) goto out; } -#if CONFIG_SPIRAM_USE_MALLOC - memset(&s_timer_delete_mutex_memory, 0, sizeof(StaticQueue_t)); - s_timer_delete_mutex = xSemaphoreCreateRecursiveMutexStatic(&s_timer_delete_mutex_memory); -#else - s_timer_delete_mutex = xSemaphoreCreateRecursiveMutex(); -#endif - if (!s_timer_delete_mutex) { - err = ESP_ERR_NO_MEM; - goto out; - } - - int ret = xTaskCreatePinnedToCore(&timer_task, "esp_timer", ESP_TASK_TIMER_STACK, NULL, ESP_TASK_TIMER_PRIO, &s_timer_task, PRO_CPU_NUM); if (ret != pdPASS) { @@ -391,10 +370,6 @@ out: vSemaphoreDelete(s_timer_semaphore); s_timer_semaphore = NULL; } - if (s_timer_delete_mutex) { - vSemaphoreDelete(s_timer_delete_mutex); - s_timer_delete_mutex = NULL; - } return ESP_ERR_NO_MEM; } From e1db12993bcfe9528e2da7cd5d92d3d2493731bf Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Wed, 8 May 2019 14:49:52 +0800 Subject: [PATCH 003/486] bootloader: pass legacy header config variable to subproject --- components/bootloader/project_include.cmake | 4 ++++ components/bootloader/subproject/CMakeLists.txt | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/components/bootloader/project_include.cmake b/components/bootloader/project_include.cmake index a4faae97e3..49e51b9cbb 100644 --- a/components/bootloader/project_include.cmake +++ b/components/bootloader/project_include.cmake @@ -63,6 +63,10 @@ if((NOT CONFIG_SECURE_BOOT_ENABLED) OR -DSECURE_BOOT_SIGNING_KEY=${secure_boot_signing_key} -DPYTHON_DEPS_CHECKED=1 -DEXTRA_COMPONENT_DIRS=${CMAKE_CURRENT_LIST_DIR} + # LEGACY_INCLUDE_COMMON_HEADERS has to be passed in via cache variable since + # the bootloader common component requirements depends on this and + # config variables are not available before project() call. + -DLEGACY_INCLUDE_COMMON_HEADERS=${CONFIG_LEGACY_INCLUDE_COMMON_HEADERS} INSTALL_COMMAND "" BUILD_ALWAYS 1 # no easy way around this... BUILD_BYPRODUCTS ${bootloader_binary_files} diff --git a/components/bootloader/subproject/CMakeLists.txt b/components/bootloader/subproject/CMakeLists.txt index 1f39199152..d6334ae155 100644 --- a/components/bootloader/subproject/CMakeLists.txt +++ b/components/bootloader/subproject/CMakeLists.txt @@ -19,7 +19,7 @@ set(COMPONENTS bootloader esptool_py partition_table soc bootloader_support log set(BOOTLOADER_BUILD 1) include("${IDF_PATH}/tools/cmake/project.cmake") set(common_req log esp_rom esp_common xtensa) -if (CONFIG_LEGACY_INCLUDE_COMMON_HEADERS) +if(LEGACY_INCLUDE_COMMON_HEADERS) list(APPEND common_req soc) endif() idf_build_set_property(__COMPONENT_REQUIRES_COMMON "${common_req}") From d68f1907ef7df254d84c9c6056c94c9271f49e49 Mon Sep 17 00:00:00 2001 From: chenjianqiang Date: Mon, 20 May 2019 15:26:52 +0800 Subject: [PATCH 004/486] bugfix(flash): improve flash dio read timing When flash work in DIO Mode, in order to ensure the fast read mode of flash is a fixed value, we merged the mode bits into address part, and the fast read mode value is 0 (the default value). --- components/bootloader_support/src/bootloader_init.c | 5 +++-- components/esp32/spiram_psram.c | 6 ++++-- components/esp_rom/include/esp32/rom/spi_flash.h | 3 ++- components/spi_flash/spi_flash_rom_patch.c | 1 + 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/components/bootloader_support/src/bootloader_init.c b/components/bootloader_support/src/bootloader_init.c index ca0f435df3..0353a3b6ac 100644 --- a/components/bootloader_support/src/bootloader_init.c +++ b/components/bootloader_support/src/bootloader_init.c @@ -321,10 +321,11 @@ static void IRAM_ATTR flash_gpio_configure(const esp_image_header_t* pfhdr) int drv = 2; switch (pfhdr->spi_mode) { case ESP_IMAGE_SPI_MODE_QIO: - spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN; + spi_cache_dummy = SPI0_R_QIO_DUMMY_CYCLELEN; break; case ESP_IMAGE_SPI_MODE_DIO: - spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN; //qio 3 + spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN; + SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_ADDR_BITLEN_V, SPI0_R_DIO_ADDR_BITSLEN, SPI_USR_ADDR_BITLEN_S); break; case ESP_IMAGE_SPI_MODE_QOUT: case ESP_IMAGE_SPI_MODE_DOUT: diff --git a/components/esp32/spiram_psram.c b/components/esp32/spiram_psram.c index f6cda3fa3b..fe0299c9bb 100644 --- a/components/esp32/spiram_psram.c +++ b/components/esp32/spiram_psram.c @@ -516,9 +516,11 @@ static void IRAM_ATTR psram_gpio_config(psram_io_t psram_io, psram_cache_mode_t { int spi_cache_dummy = 0; uint32_t rd_mode_reg = READ_PERI_REG(SPI_CTRL_REG(0)); - if (rd_mode_reg & (SPI_FREAD_QIO_M | SPI_FREAD_DIO_M)) { + if (rd_mode_reg & SPI_FREAD_QIO_M) { spi_cache_dummy = SPI0_R_QIO_DUMMY_CYCLELEN; - } else if (rd_mode_reg & (SPI_FREAD_QUAD_M | SPI_FREAD_DUAL_M)) { + } else if (rd_mode_reg & SPI_FREAD_DIO_M) { + spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN; + } else if (rd_mode_reg & (SPI_FREAD_QUAD_M | SPI_FREAD_DUAL_M)) { spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN; } else { spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN; diff --git a/components/esp_rom/include/esp32/rom/spi_flash.h b/components/esp_rom/include/esp32/rom/spi_flash.h index ea25146d71..ea995e3499 100644 --- a/components/esp_rom/include/esp32/rom/spi_flash.h +++ b/components/esp_rom/include/esp32/rom/spi_flash.h @@ -90,7 +90,8 @@ extern "C" { #define SPI0_R_QIO_DUMMY_CYCLELEN 3 #define SPI0_R_QIO_ADDR_BITSLEN 31 #define SPI0_R_FAST_DUMMY_CYCLELEN 7 -#define SPI0_R_DIO_DUMMY_CYCLELEN 3 +#define SPI0_R_DIO_DUMMY_CYCLELEN 1 +#define SPI0_R_DIO_ADDR_BITSLEN 27 #define SPI0_R_FAST_ADDR_BITSLEN 23 #define SPI0_R_SIO_ADDR_BITSLEN 23 diff --git a/components/spi_flash/spi_flash_rom_patch.c b/components/spi_flash/spi_flash_rom_patch.c index aacc62a7f5..313a995143 100644 --- a/components/spi_flash/spi_flash_rom_patch.c +++ b/components/spi_flash/spi_flash_rom_patch.c @@ -324,6 +324,7 @@ static void spi_cache_mode_switch(uint32_t modebit) REG_SET_FIELD(SPI_USER2_REG(0), SPI_USR_COMMAND_VALUE, 0x6B); REG_SET_FIELD(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN, SPI0_R_FAST_DUMMY_CYCLELEN + g_rom_spiflash_dummy_len_plus[0]); } else if ((modebit & SPI_FREAD_DIO)) { + REG_SET_FIELD(SPI_USER1_REG(0), SPI_USR_ADDR_BITLEN, SPI0_R_DIO_ADDR_BITSLEN); REG_SET_FIELD(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN, SPI0_R_DIO_DUMMY_CYCLELEN + g_rom_spiflash_dummy_len_plus[0]); REG_SET_FIELD(SPI_USER2_REG(0), SPI_USR_COMMAND_VALUE, 0xBB); } else if ((modebit & SPI_FREAD_DUAL)) { From 05be37c87c17f6372bf5f5743aaea9e6dcc3e2f7 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 21 Feb 2019 15:02:29 +1100 Subject: [PATCH 005/486] idf_size: Support JSON output Pass -DOUTPUT_JSON=1 to get JSON formatted output from CMake targets --- docs/en/api-guides/build-system-cmake.rst | 2 +- tools/cmake/project.cmake | 13 +- tools/idf_size.py | 150 +- tools/test_idf_size/expected_output | 2632 +++++++++++++++++++++ tools/test_idf_size/test.sh | 14 +- tools/test_idf_size/test_idf_size.py | 17 +- 6 files changed, 2767 insertions(+), 61 deletions(-) diff --git a/docs/en/api-guides/build-system-cmake.rst b/docs/en/api-guides/build-system-cmake.rst index a3c068bf90..7af329f68e 100644 --- a/docs/en/api-guides/build-system-cmake.rst +++ b/docs/en/api-guides/build-system-cmake.rst @@ -97,7 +97,7 @@ Advanced Commands - ``idf.py app``, ``idf.py bootloader``, ``idf.py partition_table`` can be used to build only the app, bootloader, or partition table from the project as applicable. - There are matching commands ``idf.py app-flash``, etc. to flash only that single part of the project to the ESP32. - ``idf.py -p PORT erase_flash`` will use esptool.py to erase the ESP32's entire flash chip. -- ``idf.py size`` prints some size information about the app. ``size-components`` and ``size-files`` are similar commands which print more detailed per-component or per-source-file information, respectively. +- ``idf.py size`` prints some size information about the app. ``size-components`` and ``size-files`` are similar commands which print more detailed per-component or per-source-file information, respectively. If you define variable ``-DOUTPUT_JSON=1`` when running CMake (or ``idf.py``), the output will be formatted as JSON not as human readable text. - ``idf.py reconfigure`` re-runs CMake_ even if it doesn't seem to need re-running. This isn't necessary during normal usage, but can be useful after adding/removing files from the source tree, or when modifying CMake cache variables. For example, ``idf.py -DNAME='VALUE' reconfigure`` can be used to set variable ``NAME`` in CMake cache to value ``VALUE``. The order of multiple ``idf.py`` commands on the same invocation is not important, they will automatically be executed in the correct order for everything to take effect (ie building before flashing, erasing before flashing, etc.). diff --git a/tools/cmake/project.cmake b/tools/cmake/project.cmake index 3726fa0fb1..0f3d45f0d9 100644 --- a/tools/cmake/project.cmake +++ b/tools/cmake/project.cmake @@ -384,20 +384,27 @@ macro(project project_name) idf_build_get_property(idf_path IDF_PATH) idf_build_get_property(python PYTHON) + set(idf_size ${python} ${idf_path}/tools/idf_size.py) + if(DEFINED OUTPUT_JSON AND OUTPUT_JSON) + list(APPEND idf_size "--json") + endif() + # Add size targets, depend on map file, run idf_size.py add_custom_target(size DEPENDS ${project_elf} - COMMAND ${python} ${idf_path}/tools/idf_size.py ${mapfile} + COMMAND ${idf_size} ${mapfile} ) add_custom_target(size-files DEPENDS ${project_elf} - COMMAND ${python} ${idf_path}/tools/idf_size.py --files ${mapfile} + COMMAND ${idf_size} --files ${mapfile} ) add_custom_target(size-components DEPENDS ${project_elf} - COMMAND ${python} ${idf_path}/tools/idf_size.py --archives ${mapfile} + COMMAND ${idf_size} --archives ${mapfile} ) + unset(idf_size) + idf_build_executable(${project_elf}) __project_info("${test_components}") diff --git a/tools/idf_size.py b/tools/idf_size.py index 2fdb6a8096..e89312dd44 100755 --- a/tools/idf_size.py +++ b/tools/idf_size.py @@ -22,9 +22,13 @@ # from __future__ import print_function from __future__ import unicode_literals +from __future__ import division import argparse -import re +import collections +import json import os.path +import re +import sys DEFAULT_TOOLCHAIN_PREFIX = "xtensa-esp32-elf-" @@ -38,6 +42,12 @@ CHIP_SIZES = { } +def _json_dump(obj): + """ Pretty-print JSON object to stdout """ + json.dump(obj, sys.stdout, indent=4) + print('\n') + + def scan_to_header(f, header_line): """ Scan forward in a file until you reach 'header_line', then return """ for line in f: @@ -160,6 +170,11 @@ def main(): help="Triplet prefix to add before objdump executable", default=DEFAULT_TOOLCHAIN_PREFIX) + parser.add_argument( + '--json', + help="Output results as JSON", + action="store_true") + parser.add_argument( 'map_file', help='MAP file produced by linker', type=argparse.FileType('r')) @@ -176,20 +191,18 @@ def main(): args = parser.parse_args() memory_config, sections = load_map_data(args.map_file) - print_summary(memory_config, sections) + if not args.json or not (args.archives or args.files or args.archive_details): + print_summary(memory_config, sections, args.json) if args.archives: - print("Per-archive contributions to ELF file:") - print_detailed_sizes(sections, "archive", "Archive File") + print_detailed_sizes(sections, "archive", "Archive File", args.json) if args.files: - print("Per-file contributions to ELF file:") - print_detailed_sizes(sections, "file", "Object File") + print_detailed_sizes(sections, "file", "Object File", args.json) if args.archive_details: - print("Symbols within the archive:", args.archive_details, "(Not all symbols may be reported)") - print_archive_symbols(sections, args.archive_details) + print_archive_symbols(sections, args.archive_details, args.json) -def print_summary(memory_config, sections): +def print_summary(memory_config, sections, as_json=False): def get_size(section): try: return sections[section]["size"] @@ -202,40 +215,53 @@ def print_summary(memory_config, sections): used_data = get_size(".dram0.data") used_bss = get_size(".dram0.bss") used_dram = used_data + used_bss + try: + used_dram_ratio = used_dram / total_dram + except ZeroDivisionError: + used_dram_ratio = float('nan') used_iram = sum(get_size(s) for s in sections if s.startswith(".iram0")) + try: + used_iram_ratio = used_iram / total_iram + except ZeroDivisionError: + used_iram_ratio = float('nan') flash_code = get_size(".flash.text") flash_rodata = get_size(".flash.rodata") total_size = used_data + used_iram + flash_code + flash_rodata - print("Total sizes:") - print(" DRAM .data size: %7d bytes" % used_data) - print(" DRAM .bss size: %7d bytes" % used_bss) - print("Used static DRAM: %7d bytes (%7d available, %.1f%% used)" % - (used_dram, total_dram - used_dram, - 100.0 * used_dram / total_dram)) - print("Used static IRAM: %7d bytes (%7d available, %.1f%% used)" % - (used_iram, total_iram - used_iram, - 100.0 * used_iram / total_iram)) - print(" Flash code: %7d bytes" % flash_code) - print(" Flash rodata: %7d bytes" % flash_rodata) - print("Total image size:~%7d bytes (.bin may be padded larger)" % (total_size)) + if as_json: + _json_dump(collections.OrderedDict([ + ("dram_data", used_data), + ("dram_bss", used_bss), + ("used_dram", used_dram), + ("available_dram", total_dram - used_dram), + ("used_dram_ratio", used_dram_ratio), + ("used_iram", used_iram), + ("available_iram", total_iram - used_iram), + ("used_iram_ratio", used_iram_ratio), + ("flash_code", flash_code), + ("flash_rodata", flash_rodata), + ("total_size", total_size) + ])) + else: + print("Total sizes:") + print(" DRAM .data size: %7d bytes" % used_data) + print(" DRAM .bss size: %7d bytes" % used_bss) + print("Used static DRAM: %7d bytes (%7d available, %.1f%% used)" % + (used_dram, total_dram - used_dram, 100.0 * used_dram_ratio)) + print("Used static IRAM: %7d bytes (%7d available, %.1f%% used)" % + (used_iram, total_iram - used_iram, 100.0 * used_iram_ratio)) + print(" Flash code: %7d bytes" % flash_code) + print(" Flash rodata: %7d bytes" % flash_rodata) + print("Total image size:~%7d bytes (.bin may be padded larger)" % (total_size)) -def print_detailed_sizes(sections, key, header): +def print_detailed_sizes(sections, key, header, as_json=False): sizes = sizes_by_key(sections, key) - headings = (header, - "DRAM .data", - "& .bss", - "IRAM", - "Flash code", - "& rodata", - "Total") - print("%24s %10s %6s %6s %10s %8s %7s" % headings) result = {} for k in sizes: v = sizes[k] - result[k] = {} + result[k] = collections.OrderedDict() result[k]["data"] = v.get(".dram0.data", 0) result[k]["bss"] = v.get(".dram0.bss", 0) result[k]["iram"] = sum(t for (s,t) in v.items() if s.startswith(".iram0")) @@ -250,20 +276,37 @@ def print_detailed_sizes(sections, key, header): def return_header(elem): return elem[0] s = sorted(list(result.items()), key=return_header) + # do a secondary sort in order to have consistent order (for diff-ing the output) - for k,v in sorted(s, key=return_total_size, reverse=True): - if ":" in k: # print subheadings for key of format archive:file - sh,k = k.split(":") - print("%24s %10d %6d %6d %10d %8d %7d" % (k[:24], - v["data"], - v["bss"], - v["iram"], - v["flash_text"], - v["flash_rodata"], - v["total"])) + s = sorted(s, key=return_total_size, reverse=True) + + if as_json: + _json_dump(collections.OrderedDict(s)) + else: + print("Per-%s contributions to ELF file:" % key) + headings = (header, + "DRAM .data", + "& .bss", + "IRAM", + "Flash code", + "& rodata", + "Total") + header_format = "%24s %10d %6d %6d %10d %8d %7d" + print(header_format.replace("d", "s") % headings) + + for k,v in s: + if ":" in k: # print subheadings for key of format archive:file + sh,k = k.split(":") + print(header_format % (k[:24], + v["data"], + v["bss"], + v["iram"], + v["flash_text"], + v["flash_rodata"], + v["total"])) -def print_archive_symbols(sections, archive): +def print_archive_symbols(sections, archive, as_json=False): interested_sections = [".dram0.data", ".dram0.bss", ".iram0.text", ".iram0.vectors", ".flash.text", ".flash.rodata"] result = {} for t in interested_sections: @@ -277,15 +320,26 @@ def print_archive_symbols(sections, archive): continue s["sym_name"] = re.sub("(.text.|.literal.|.data.|.bss.|.rodata.)", "", s["sym_name"]) result[section_name][s["sym_name"]] = result[section_name].get(s["sym_name"], 0) + s["size"] + + # build a new ordered dict of each section, where each entry is an ordereddict of symbols to sizes + section_symbols = collections.OrderedDict() for t in interested_sections: - print("\nSymbols from section:", t) - section_total = 0 s = sorted(list(result[t].items()), key=lambda k_v: k_v[0]) # do a secondary sort in order to have consistent order (for diff-ing the output) - for key,val in sorted(s, key=lambda k_v: k_v[1], reverse=True): - print(("%s(%d)" % (key.replace(t + ".", ""), val)), end=' ') - section_total += val - print("\nSection total:",section_total) + s = sorted(s, key=lambda k_v: k_v[1], reverse=True) + section_symbols[t] = collections.OrderedDict(s) + + if as_json: + _json_dump(section_symbols) + else: + print("Symbols within the archive: %s (Not all symbols may be reported)" % (archive)) + for t,s in section_symbols.items(): + section_total = 0 + print("\nSymbols from section:", t) + for key, val in s.items(): + print(("%s(%d)" % (key.replace(t + ".", ""), val)), end=' ') + section_total += val + print("\nSection total:",section_total) if __name__ == "__main__": diff --git a/tools/test_idf_size/expected_output b/tools/test_idf_size/expected_output index 34bb8d8f04..2845ec61c7 100644 --- a/tools/test_idf_size/expected_output +++ b/tools/test_idf_size/expected_output @@ -1,3 +1,6 @@ + +*** +Running idf_size.py... Total sizes: DRAM .data size: 9324 bytes DRAM .bss size: 8296 bytes @@ -6,6 +9,9 @@ Used static IRAM: 38932 bytes ( 92140 available, 29.7% used) Flash code: 146944 bytes Flash rodata: 39580 bytes Total image size:~ 234780 bytes (.bin may be padded larger) + +*** +Running idf_size.py --archives... Total sizes: DRAM .data size: 9324 bytes DRAM .bss size: 8296 bytes @@ -54,6 +60,9 @@ libxtensa-debug-module.a 0 0 8 0 0 8 libwpa2.a 0 0 0 0 0 0 libwpa_supplicant.a 0 0 0 0 0 0 libwps.a 0 0 0 0 0 0 + +*** +Running idf_size.py --files... Total sizes: DRAM .data size: 9324 bytes DRAM .bss size: 8296 bytes @@ -345,6 +354,9 @@ ieee80211_action_vendor. 0 0 0 0 0 0 wpa2_internal.o 0 0 0 0 0 0 os_xtensa.o 0 0 0 0 0 0 wps_internal.o 0 0 0 0 0 0 + +*** +Running idf_size.py --archive_details... Total sizes: DRAM .data size: 9324 bytes DRAM .bss size: 8296 bytes @@ -378,6 +390,2626 @@ Section total: 961 Symbols from section: .flash.rodata str1.4(249) get_clk_en_mask(128) get_rst_en_mask(128) __FUNCTION__$5441(24) TG(8) Section total: 537 + +***]nProducing JSON output... +{ + "dram_data": 9324, + "dram_bss": 8296, + "used_dram": 17620, + "available_dram": 163116, + "used_dram_ratio": 0.09749026203966006, + "used_iram": 38932, + "available_iram": 92140, + "used_iram_ratio": 0.297027587890625, + "flash_code": 146944, + "flash_rodata": 39580, + "total_size": 234780 +} + +{ + "liblwip.a": { + "data": 14, + "bss": 3751, + "iram": 0, + "flash_text": 66978, + "flash_rodata": 13936, + "total": 84679 + }, + "libc.a": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 55583, + "flash_rodata": 3889, + "total": 59472 + }, + "libesp32.a": { + "data": 2635, + "bss": 2375, + "iram": 7758, + "flash_text": 4814, + "flash_rodata": 8133, + "total": 25715 + }, + "libfreertos.a": { + "data": 4156, + "bss": 832, + "iram": 12853, + "flash_text": 0, + "flash_rodata": 1545, + "total": 19386 + }, + "libspi_flash.a": { + "data": 36, + "bss": 359, + "iram": 7004, + "flash_text": 886, + "flash_rodata": 1624, + "total": 9909 + }, + "libsoc.a": { + "data": 660, + "bss": 8, + "iram": 3887, + "flash_text": 0, + "flash_rodata": 3456, + "total": 8011 + }, + "libheap.a": { + "data": 1331, + "bss": 4, + "iram": 4376, + "flash_text": 1218, + "flash_rodata": 980, + "total": 7909 + }, + "libgcc.a": { + "data": 4, + "bss": 20, + "iram": 104, + "flash_text": 5488, + "flash_rodata": 888, + "total": 6504 + }, + "libvfs.a": { + "data": 232, + "bss": 103, + "iram": 0, + "flash_text": 3770, + "flash_rodata": 403, + "total": 4508 + }, + "libunity.a": { + "data": 0, + "bss": 121, + "iram": 0, + "flash_text": 2316, + "flash_rodata": 830, + "total": 3267 + }, + "libstdc++.a": { + "data": 8, + "bss": 16, + "iram": 0, + "flash_text": 1827, + "flash_rodata": 1062, + "total": 2913 + }, + "libnewlib.a": { + "data": 152, + "bss": 272, + "iram": 853, + "flash_text": 803, + "flash_rodata": 86, + "total": 2166 + }, + "libpthread.a": { + "data": 16, + "bss": 12, + "iram": 174, + "flash_text": 774, + "flash_rodata": 638, + "total": 1614 + }, + "libdriver.a": { + "data": 40, + "bss": 20, + "iram": 0, + "flash_text": 961, + "flash_rodata": 537, + "total": 1558 + }, + "liblog.a": { + "data": 8, + "bss": 268, + "iram": 456, + "flash_text": 396, + "flash_rodata": 166, + "total": 1294 + }, + "libapp_update.a": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 123, + "flash_rodata": 717, + "total": 840 + }, + "libtcpip_adapter.a": { + "data": 0, + "bss": 81, + "iram": 0, + "flash_text": 180, + "flash_rodata": 359, + "total": 620 + }, + "libhal.a": { + "data": 0, + "bss": 0, + "iram": 515, + "flash_text": 0, + "flash_rodata": 32, + "total": 547 + }, + "libm.a": { + "data": 0, + "bss": 0, + "iram": 92, + "flash_text": 0, + "flash_rodata": 0, + "total": 92 + }, + "libmain.a": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 53, + "flash_rodata": 10, + "total": 63 + }, + "libcxx.a": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 11, + "flash_rodata": 0, + "total": 11 + }, + "libxtensa-debug-module.a": { + "data": 0, + "bss": 0, + "iram": 8, + "flash_text": 0, + "flash_rodata": 0, + "total": 8 + }, + "libbootloader_support.a": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libcoexist.a": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libcore.a": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libethernet.a": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libmbedtls.a": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libmesh.a": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnvs_flash.a": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libphy.a": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libpp.a": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "librtc.a": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libsmartconfig_ack.a": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libwpa.a": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libwpa2.a": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libwpa_supplicant.a": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libwps.a": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + } +} + +{ + "libc.a:lib_a-vfprintf.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 14193, + "flash_rodata": 756, + "total": 14949 + }, + "libc.a:lib_a-svfprintf.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 13834, + "flash_rodata": 756, + "total": 14590 + }, + "libc.a:lib_a-svfiprintf.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 9642, + "flash_rodata": 1210, + "total": 10852 + }, + "libc.a:lib_a-vfiprintf.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 9933, + "flash_rodata": 738, + "total": 10671 + }, + "liblwip.a:nd6.o": { + "data": 8, + "bss": 1027, + "iram": 0, + "flash_text": 8427, + "flash_rodata": 136, + "total": 9598 + }, + "liblwip.a:tcp_in.o": { + "data": 0, + "bss": 54, + "iram": 0, + "flash_text": 8127, + "flash_rodata": 916, + "total": 9097 + }, + "libfreertos.a:tasks.o": { + "data": 20, + "bss": 700, + "iram": 5667, + "flash_text": 0, + "flash_rodata": 503, + "total": 6890 + }, + "liblwip.a:tcp_out.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 5060, + "flash_rodata": 1124, + "total": 6184 + }, + "liblwip.a:sockets.o": { + "data": 0, + "bss": 728, + "iram": 0, + "flash_text": 4627, + "flash_rodata": 824, + "total": 6179 + }, + "liblwip.a:tcp.o": { + "data": 4, + "bss": 23, + "iram": 0, + "flash_text": 4290, + "flash_rodata": 1384, + "total": 5701 + }, + "liblwip.a:api_msg.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 3763, + "flash_rodata": 1366, + "total": 5129 + }, + "liblwip.a:dhcp.o": { + "data": 0, + "bss": 8, + "iram": 0, + "flash_text": 3456, + "flash_rodata": 1401, + "total": 4865 + }, + "libesp32.a:panic.o": { + "data": 2579, + "bss": 5, + "iram": 2145, + "flash_text": 0, + "flash_rodata": 0, + "total": 4729 + }, + "libesp32.a:esp_err_to_name.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 50, + "flash_rodata": 4091, + "total": 4141 + }, + "libgcc.a:unwind-dw2-fde.o": { + "data": 4, + "bss": 20, + "iram": 0, + "flash_text": 3316, + "flash_rodata": 404, + "total": 3744 + }, + "liblwip.a:pbuf.o": { + "data": 0, + "bss": 1, + "iram": 0, + "flash_text": 2453, + "flash_rodata": 1161, + "total": 3615 + }, + "libfreertos.a:portasm.o": { + "data": 3084, + "bss": 0, + "iram": 480, + "flash_text": 0, + "flash_rodata": 0, + "total": 3564 + }, + "libc.a:lib_a-dtoa.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 3522, + "flash_rodata": 13, + "total": 3535 + }, + "liblwip.a:etharp.o": { + "data": 0, + "bss": 241, + "iram": 0, + "flash_text": 2618, + "flash_rodata": 658, + "total": 3517 + }, + "liblwip.a:ip6.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 3212, + "flash_rodata": 124, + "total": 3336 + }, + "liblwip.a:dns.o": { + "data": 0, + "bss": 1292, + "iram": 0, + "flash_text": 1809, + "flash_rodata": 206, + "total": 3307 + }, + "libspi_flash.a:spi_flash_rom_patch.o": { + "data": 0, + "bss": 0, + "iram": 2518, + "flash_text": 0, + "flash_rodata": 766, + "total": 3284 + }, + "liblwip.a:udp.o": { + "data": 2, + "bss": 4, + "iram": 0, + "flash_text": 3020, + "flash_rodata": 216, + "total": 3242 + }, + "libesp32.a:intr_alloc.o": { + "data": 8, + "bss": 22, + "iram": 726, + "flash_text": 1749, + "flash_rodata": 710, + "total": 3215 + }, + "libheap.a:multi_heap.o": { + "data": 857, + "bss": 0, + "iram": 2217, + "flash_text": 0, + "flash_rodata": 0, + "total": 3074 + }, + "libfreertos.a:queue.o": { + "data": 8, + "bss": 56, + "iram": 2569, + "flash_text": 0, + "flash_rodata": 369, + "total": 3002 + }, + "libspi_flash.a:flash_ops.o": { + "data": 32, + "bss": 41, + "iram": 2352, + "flash_text": 99, + "flash_rodata": 0, + "total": 2524 + }, + "libgcc.a:unwind-dw2-xtensa.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 2172, + "flash_rodata": 324, + "total": 2496 + }, + "libsoc.a:rtc_clk.o": { + "data": 660, + "bss": 8, + "iram": 1794, + "flash_text": 0, + "flash_rodata": 0, + "total": 2462 + }, + "libc.a:lib_a-mprec.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 2134, + "flash_rodata": 296, + "total": 2430 + }, + "libvfs.a:vfs.o": { + "data": 192, + "bss": 40, + "iram": 0, + "flash_text": 1995, + "flash_rodata": 132, + "total": 2359 + }, + "liblwip.a:ip6_frag.o": { + "data": 0, + "bss": 6, + "iram": 0, + "flash_text": 1905, + "flash_rodata": 442, + "total": 2353 + }, + "liblwip.a:api_lib.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 1425, + "flash_rodata": 919, + "total": 2344 + }, + "liblwip.a:igmp.o": { + "data": 0, + "bss": 12, + "iram": 0, + "flash_text": 1604, + "flash_rodata": 707, + "total": 2323 + }, + "libesp32.a:dbg_stubs.o": { + "data": 0, + "bss": 2072, + "iram": 32, + "flash_text": 100, + "flash_rodata": 0, + "total": 2204 + }, + "libvfs.a:vfs_uart.o": { + "data": 40, + "bss": 63, + "iram": 0, + "flash_text": 1775, + "flash_rodata": 271, + "total": 2149 + }, + "libunity.a:unity_platform.o": { + "data": 0, + "bss": 13, + "iram": 0, + "flash_text": 1511, + "flash_rodata": 600, + "total": 2124 + }, + "libesp32.a:esp_timer_esp32.o": { + "data": 8, + "bss": 26, + "iram": 1295, + "flash_text": 254, + "flash_rodata": 526, + "total": 2109 + }, + "libsoc.a:rtc_periph.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 2080, + "total": 2080 + }, + "libspi_flash.a:flash_mmap.o": { + "data": 0, + "bss": 296, + "iram": 1298, + "flash_text": 124, + "flash_rodata": 327, + "total": 2045 + }, + "libheap.a:heap_caps.o": { + "data": 4, + "bss": 0, + "iram": 1195, + "flash_text": 188, + "flash_rodata": 593, + "total": 1980 + }, + "libstdc++.a:eh_personality.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 1561, + "flash_rodata": 384, + "total": 1945 + }, + "liblwip.a:ip4.o": { + "data": 0, + "bss": 6, + "iram": 0, + "flash_text": 1664, + "flash_rodata": 139, + "total": 1809 + }, + "liblwip.a:netif.o": { + "data": 0, + "bss": 241, + "iram": 0, + "flash_text": 1239, + "flash_rodata": 287, + "total": 1767 + }, + "libfreertos.a:xtensa_vectors.o": { + "data": 8, + "bss": 0, + "iram": 1697, + "flash_text": 0, + "flash_rodata": 36, + "total": 1741 + }, + "libesp32.a:cpu_start.o": { + "data": 0, + "bss": 1, + "iram": 806, + "flash_text": 277, + "flash_rodata": 486, + "total": 1570 + }, + "libesp32.a:clk.o": { + "data": 0, + "bss": 0, + "iram": 67, + "flash_text": 581, + "flash_rodata": 893, + "total": 1541 + }, + "libfreertos.a:timers.o": { + "data": 8, + "bss": 56, + "iram": 1149, + "flash_text": 0, + "flash_rodata": 233, + "total": 1446 + }, + "liblwip.a:sys_arch.o": { + "data": 0, + "bss": 8, + "iram": 0, + "flash_text": 1216, + "flash_rodata": 222, + "total": 1446 + }, + "libheap.a:multi_heap_poisoning.o": { + "data": 470, + "bss": 0, + "iram": 964, + "flash_text": 0, + "flash_rodata": 0, + "total": 1434 + }, + "libheap.a:heap_caps_init.o": { + "data": 0, + "bss": 4, + "iram": 0, + "flash_text": 1030, + "flash_rodata": 387, + "total": 1421 + }, + "liblwip.a:mld6.o": { + "data": 0, + "bss": 4, + "iram": 0, + "flash_text": 1334, + "flash_rodata": 0, + "total": 1338 + }, + "libspi_flash.a:cache_utils.o": { + "data": 4, + "bss": 14, + "iram": 836, + "flash_text": 81, + "flash_rodata": 390, + "total": 1325 + }, + "liblwip.a:raw.o": { + "data": 0, + "bss": 4, + "iram": 0, + "flash_text": 1087, + "flash_rodata": 223, + "total": 1314 + }, + "libesp32.a:esp_timer.o": { + "data": 8, + "bss": 20, + "iram": 702, + "flash_text": 429, + "flash_rodata": 142, + "total": 1301 + }, + "liblog.a:log.o": { + "data": 8, + "bss": 268, + "iram": 456, + "flash_text": 396, + "flash_rodata": 166, + "total": 1294 + }, + "libesp32.a:system_api.o": { + "data": 0, + "bss": 8, + "iram": 589, + "flash_text": 0, + "flash_rodata": 662, + "total": 1259 + }, + "libsoc.a:soc_memory_layout.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 1239, + "total": 1239 + }, + "liblwip.a:icmp.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 769, + "flash_rodata": 371, + "total": 1140 + }, + "libfreertos.a:xtensa_intr_asm.o": { + "data": 1024, + "bss": 0, + "iram": 51, + "flash_text": 0, + "flash_rodata": 0, + "total": 1075 + }, + "libfreertos.a:port.o": { + "data": 0, + "bss": 16, + "iram": 617, + "flash_text": 0, + "flash_rodata": 369, + "total": 1002 + }, + "libpthread.a:pthread.o": { + "data": 8, + "bss": 8, + "iram": 174, + "flash_text": 298, + "flash_rodata": 512, + "total": 1000 + }, + "liblwip.a:icmp6.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 863, + "flash_rodata": 127, + "total": 990 + }, + "libsoc.a:rtc_init.o": { + "data": 0, + "bss": 0, + "iram": 980, + "flash_text": 0, + "flash_rodata": 0, + "total": 980 + }, + "libunity.a:unity.o": { + "data": 0, + "bss": 108, + "iram": 0, + "flash_text": 767, + "flash_rodata": 90, + "total": 965 + }, + "libsoc.a:rtc_time.o": { + "data": 0, + "bss": 0, + "iram": 803, + "flash_text": 0, + "flash_rodata": 137, + "total": 940 + }, + "libesp32.a:dport_access.o": { + "data": 8, + "bss": 40, + "iram": 539, + "flash_text": 189, + "flash_rodata": 129, + "total": 905 + }, + "libc.a:lib_a-fseeko.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 862, + "flash_rodata": 0, + "total": 862 + }, + "libnewlib.a:time.o": { + "data": 0, + "bss": 32, + "iram": 139, + "flash_text": 691, + "flash_rodata": 0, + "total": 862 + }, + "liblwip.a:tcpip.o": { + "data": 0, + "bss": 16, + "iram": 0, + "flash_text": 644, + "flash_rodata": 191, + "total": 851 + }, + "libapp_update.a:esp_ota_ops.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 123, + "flash_rodata": 717, + "total": 840 + }, + "libdriver.a:periph_ctrl.o": { + "data": 8, + "bss": 0, + "iram": 0, + "flash_text": 520, + "flash_rodata": 256, + "total": 784 + }, + "liblwip.a:timers.o": { + "data": 0, + "bss": 12, + "iram": 0, + "flash_text": 638, + "flash_rodata": 131, + "total": 781 + }, + "libspi_flash.a:partition.o": { + "data": 0, + "bss": 8, + "iram": 0, + "flash_text": 582, + "flash_rodata": 141, + "total": 731 + }, + "libnewlib.a:locks.o": { + "data": 8, + "bss": 0, + "iram": 552, + "flash_text": 0, + "flash_rodata": 84, + "total": 644 + }, + "libesp32.a:ipc.o": { + "data": 0, + "bss": 36, + "iram": 159, + "flash_text": 329, + "flash_rodata": 104, + "total": 628 + }, + "libtcpip_adapter.a:tcpip_adapter_lwip.o": { + "data": 0, + "bss": 81, + "iram": 0, + "flash_text": 180, + "flash_rodata": 359, + "total": 620 + }, + "libpthread.a:pthread_local_storage.o": { + "data": 8, + "bss": 4, + "iram": 0, + "flash_text": 476, + "flash_rodata": 126, + "total": 614 + }, + "liblwip.a:inet_chksum.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 580, + "flash_rodata": 0, + "total": 580 + }, + "libesp32.a:crosscore_int.o": { + "data": 8, + "bss": 8, + "iram": 204, + "flash_text": 126, + "flash_rodata": 148, + "total": 494 + }, + "liblwip.a:netbuf.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 154, + "flash_rodata": 326, + "total": 480 + }, + "liblwip.a:vfs_lwip.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 307, + "flash_rodata": 155, + "total": 462 + }, + "libnewlib.a:syscall_table.o": { + "data": 144, + "bss": 240, + "iram": 0, + "flash_text": 67, + "flash_rodata": 0, + "total": 451 + }, + "libdriver.a:timer.o": { + "data": 16, + "bss": 0, + "iram": 0, + "flash_text": 112, + "flash_rodata": 281, + "total": 409 + }, + "libesp32.a:int_wdt.o": { + "data": 0, + "bss": 1, + "iram": 87, + "flash_text": 301, + "flash_rodata": 0, + "total": 389 + }, + "libstdc++.a:eh_globals.o": { + "data": 0, + "bss": 16, + "iram": 0, + "flash_text": 149, + "flash_rodata": 193, + "total": 358 + }, + "libesp32.a:brownout.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 145, + "flash_rodata": 191, + "total": 336 + }, + "libesp32.a:freertos_hooks.o": { + "data": 8, + "bss": 128, + "iram": 43, + "flash_text": 137, + "flash_rodata": 0, + "total": 316 + }, + "libhal.a:windowspill_asm.o": { + "data": 0, + "bss": 0, + "iram": 311, + "flash_text": 0, + "flash_rodata": 0, + "total": 311 + }, + "libsoc.a:cpu_util.o": { + "data": 0, + "bss": 0, + "iram": 310, + "flash_text": 0, + "flash_rodata": 0, + "total": 310 + }, + "libdriver.a:rtc_module.o": { + "data": 8, + "bss": 8, + "iram": 0, + "flash_text": 291, + "flash_rodata": 0, + "total": 307 + }, + "libfreertos.a:xtensa_context.o": { + "data": 0, + "bss": 0, + "iram": 299, + "flash_text": 0, + "flash_rodata": 0, + "total": 299 + }, + "libstdc++.a:eh_terminate.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 117, + "flash_rodata": 141, + "total": 258 + }, + "liblwip.a:ethernet.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 244, + "flash_rodata": 12, + "total": 256 + }, + "libc.a:lib_a-puts.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 182, + "flash_rodata": 60, + "total": 242 + }, + "libesp32.a:dport_panic_highint_hdl.o": { + "data": 8, + "bss": 0, + "iram": 234, + "flash_text": 0, + "flash_rodata": 0, + "total": 242 + }, + "libc.a:lib_a-reent.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 232, + "flash_rodata": 0, + "total": 232 + }, + "libc.a:lib_a-fopen.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 228, + "flash_rodata": 0, + "total": 228 + }, + "liblwip.a:dhcpserver.o": { + "data": 0, + "bss": 4, + "iram": 0, + "flash_text": 203, + "flash_rodata": 0, + "total": 207 + }, + "libunity.a:test_utils.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 38, + "flash_rodata": 140, + "total": 178 + }, + "libc.a:lib_a-sprintf.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 167, + "flash_rodata": 0, + "total": 167 + }, + "libesp32.a:cache_err_int.o": { + "data": 0, + "bss": 0, + "iram": 56, + "flash_text": 98, + "flash_rodata": 0, + "total": 154 + }, + "libfreertos.a:list.o": { + "data": 0, + "bss": 0, + "iram": 142, + "flash_text": 0, + "flash_rodata": 0, + "total": 142 + }, + "libfreertos.a:xtensa_intr.o": { + "data": 0, + "bss": 0, + "iram": 104, + "flash_text": 0, + "flash_rodata": 35, + "total": 139 + }, + "libnewlib.a:syscalls.o": { + "data": 0, + "bss": 0, + "iram": 94, + "flash_text": 45, + "flash_rodata": 0, + "total": 139 + }, + "libstdc++.a:si_class_type_info.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 136, + "total": 136 + }, + "libc.a:lib_a-assert.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 68, + "flash_rodata": 60, + "total": 128 + }, + "libc.a:lib_a-flags.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 127, + "flash_rodata": 0, + "total": 127 + }, + "libc.a:lib_a-printf.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 116, + "flash_rodata": 0, + "total": 116 + }, + "liblwip.a:ip4_addr.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 72, + "flash_rodata": 40, + "total": 112 + }, + "libstdc++.a:class_type_info.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 112, + "total": 112 + }, + "libc.a:lib_a-s_frexp.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 110, + "flash_rodata": 0, + "total": 110 + }, + "liblwip.a:ip.o": { + "data": 0, + "bss": 60, + "iram": 0, + "flash_text": 50, + "flash_rodata": 0, + "total": 110 + }, + "liblwip.a:memp.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 108, + "total": 108 + }, + "libgcc.a:lib2funcs.o": { + "data": 0, + "bss": 0, + "iram": 104, + "flash_text": 0, + "flash_rodata": 0, + "total": 104 + }, + "libc.a:lib_a-vprintf.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 94, + "flash_rodata": 0, + "total": 94 + }, + "libm.a:lib_a-s_fpclassify.o": { + "data": 0, + "bss": 0, + "iram": 92, + "flash_text": 0, + "flash_rodata": 0, + "total": 92 + }, + "liblwip.a:def.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 91, + "flash_rodata": 0, + "total": 91 + }, + "libc.a:lib_a-fiprintf.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 84, + "flash_rodata": 0, + "total": 84 + }, + "libesp32.a:hw_random.o": { + "data": 0, + "bss": 4, + "iram": 74, + "flash_text": 0, + "flash_rodata": 0, + "total": 78 + }, + "libesp32.a:stack_check.o": { + "data": 0, + "bss": 4, + "iram": 0, + "flash_text": 32, + "flash_rodata": 42, + "total": 78 + }, + "libhal.a:clock.o": { + "data": 0, + "bss": 0, + "iram": 72, + "flash_text": 0, + "flash_rodata": 0, + "total": 72 + }, + "libnewlib.a:reent_init.o": { + "data": 0, + "bss": 0, + "iram": 68, + "flash_text": 0, + "flash_rodata": 2, + "total": 70 + }, + "libmain.a:app_main.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 53, + "flash_rodata": 10, + "total": 63 + }, + "libhal.a:state_asm--restore_extra_nw.o": { + "data": 0, + "bss": 0, + "iram": 62, + "flash_text": 0, + "flash_rodata": 0, + "total": 62 + }, + "libhal.a:state_asm--save_extra_nw.o": { + "data": 0, + "bss": 0, + "iram": 62, + "flash_text": 0, + "flash_rodata": 0, + "total": 62 + }, + "libdriver.a:uart.o": { + "data": 8, + "bss": 12, + "iram": 0, + "flash_text": 38, + "flash_rodata": 0, + "total": 58 + }, + "libstdc++.a:new_opv.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 56, + "total": 56 + }, + "libfreertos.a:xtensa_vector_defaults.o": { + "data": 0, + "bss": 0, + "iram": 46, + "flash_text": 0, + "flash_rodata": 0, + "total": 46 + }, + "libc.a:lib_a-fseek.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 45, + "flash_rodata": 0, + "total": 45 + }, + "libgcc.a:_divdi3.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 40, + "total": 40 + }, + "libgcc.a:_moddi3.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 40, + "total": 40 + }, + "libgcc.a:_udivdi3.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 40, + "total": 40 + }, + "libgcc.a:_umoddi3.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 40, + "total": 40 + }, + "libstdc++.a:new_op.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 40, + "total": 40 + }, + "libfreertos.a:xtensa_init.o": { + "data": 0, + "bss": 4, + "iram": 32, + "flash_text": 0, + "flash_rodata": 0, + "total": 36 + }, + "libhal.a:interrupts--intlevel.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 32, + "total": 32 + }, + "liblwip.a:init.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 27, + "flash_rodata": 0, + "total": 27 + }, + "libesp32.a:wifi_init.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 17, + "flash_rodata": 9, + "total": 26 + }, + "liblwip.a:ip6_addr.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 20, + "total": 20 + }, + "libc.a:lib_a-errno.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 10, + "flash_rodata": 0, + "total": 10 + }, + "libhal.a:int_asm--set_intclear.o": { + "data": 0, + "bss": 0, + "iram": 8, + "flash_text": 0, + "flash_rodata": 0, + "total": 8 + }, + "libxtensa-debug-module.a:eri.o": { + "data": 0, + "bss": 0, + "iram": 8, + "flash_text": 0, + "flash_rodata": 0, + "total": 8 + }, + "libcxx.a:cxx_exception_stubs.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 6, + "flash_rodata": 0, + "total": 6 + }, + "libcxx.a:cxx_guards.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 5, + "flash_rodata": 0, + "total": 5 + }, + "libfreertos.a:FreeRTOS-openocd.o": { + "data": 4, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 4 + }, + "libstdc++.a:eh_term_handler.o": { + "data": 4, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 4 + }, + "libstdc++.a:eh_unex_handler.o": { + "data": 4, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 4 + }, + "libbootloader_support.a:bootloader_flash.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libbootloader_support.a:bootloader_sha.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libbootloader_support.a:esp_image_format.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libc.a:lib_a-fputs.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libc.a:lib_a-snprintf.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libc.a:lib_a-strerror.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libc.a:lib_a-sysgettod.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libc.a:lib_a-u_strerr.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libc.a:lib_a-vsnprintf.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libc.a:lib_a-xpg_strerror_r.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libcoexist.a:coexist_api.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libcoexist.a:coexist_arbit.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libcoexist.a:coexist_core.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libcoexist.a:coexist_dbg.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libcoexist.a:coexist_hw.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libcoexist.a:coexist_param.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libcoexist.a:coexist_timer.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libcore.a:misc_nvs.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libdriver.a:gpio.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libesp32.a:ets_timer_legacy.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libesp32.a:event_default_handlers.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libesp32.a:event_loop.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libesp32.a:lib_printf.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libesp32.a:phy_init.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libesp32.a:sha.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libesp32.a:wifi_os_adapter.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libethernet.a:emac_dev.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libethernet.a:emac_main.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libfreertos.a:event_groups.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libfreertos.a:ringbuf.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libgcc.a:_addsubdf3.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libgcc.a:_cmpdf2.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libgcc.a:_divdf3.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libgcc.a:_divsf3.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libgcc.a:_extendsfdf2.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libgcc.a:_fixdfsi.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libgcc.a:_floatdidf.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libgcc.a:_floatdisf.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libgcc.a:_floatsidf.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libgcc.a:_muldf3.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libgcc.a:_popcountsi2.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "liblwip.a:ethernetif.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "liblwip.a:ethip6.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "liblwip.a:wlanif.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libmbedtls.a:esp_sha256.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libmesh.a:mesh.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libmesh.a:mesh_common.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libmesh.a:mesh_config.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libmesh.a:mesh_main.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libmesh.a:mesh_parent.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libmesh.a:mesh_route.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libmesh.a:mesh_schedule.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libmesh.a:mesh_timer.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libmesh.a:mesh_utilities.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libmesh.a:mesh_wifi.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_action.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_action_vendor.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_api.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_crypto.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_crypto_ccmp.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_crypto_tkip.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_crypto_wep.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_debug.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_ets.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_hostap.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_ht.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_ie_vendor.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_input.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_ioctl.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_mesh_quick.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_misc.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_nvs.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_output.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_phy.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_power.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_proto.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_regdomain.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_rfid.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_scan.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_sta.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:ieee80211_timer.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:wl_chm.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnet80211.a:wl_cnx.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnvs_flash.a:nvs_api.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnvs_flash.a:nvs_item_hash_list.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnvs_flash.a:nvs_page.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnvs_flash.a:nvs_pagemanager.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnvs_flash.a:nvs_storage.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libnvs_flash.a:nvs_types.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libphy.a:phy.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libphy.a:phy_chip_v7.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libphy.a:phy_chip_v7_ana.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libphy.a:phy_chip_v7_cal.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libpp.a:esf_buf.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libpp.a:if_hwctrl.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libpp.a:lmac.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libpp.a:pm.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libpp.a:pm_for_bcn_only_mode.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libpp.a:pp.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libpp.a:pp_debug.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libpp.a:pp_timer.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libpp.a:rate_control.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libpp.a:trc.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libpp.a:wdev.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "librtc.a:bt_bb.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "librtc.a:pm.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "librtc.a:rtc.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "librtc.a:rtc_analog.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libsmartconfig_ack.a:smartconfig_ack.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libsoc.a:gpio_periph.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libsoc.a:rtc_sleep.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libstdc++.a:bad_alloc.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libstdc++.a:del_op.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libstdc++.a:del_opv.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libstdc++.a:eh_exception.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libstdc++.a:new_handler.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libstdc++.a:pure.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libstdc++.a:tinfo.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libwpa.a:ap_config.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libwpa.a:common.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libwpa.a:wpa.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libwpa.a:wpa_auth.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libwpa.a:wpa_auth_ie.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libwpa.a:wpa_common.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libwpa.a:wpa_debug.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libwpa.a:wpa_ie.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libwpa.a:wpa_main.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libwpa.a:wpabuf.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libwpa.a:wpas_glue.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libwpa2.a:wpa2_internal.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libwpa_supplicant.a:os_xtensa.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + }, + "libwps.a:wps_internal.o": { + "data": 0, + "bss": 0, + "iram": 0, + "flash_text": 0, + "flash_rodata": 0, + "total": 0 + } +} + +{ + ".dram0.data": { + "timer_spinlock": 16, + "periph_spinlock": 8, + "s_rtc_isr_handler_list_lock": 8, + "uart_selectlock": 8 + }, + ".dram0.bss": { + "p_uart_obj": 12, + "s_rtc_isr_handle": 4, + "s_rtc_isr_handler_list": 4 + }, + ".iram0.text": {}, + ".iram0.vectors": {}, + ".flash.text": { + "get_clk_en_mask": 211, + "get_rst_en_mask": 157, + "timer_group_intr_enable": 112, + "rtc_isr": 86, + "periph_module_enable": 78, + "rtc_isr_ensure_installed": 75, + "rtc_gpio_force_hold_dis_all": 65, + "rtc_isr_register": 65, + "is_wifi_clk_peripheral": 28, + "uart_set_select_notif_callback": 26, + "get_rst_en_reg": 25, + "get_clk_en_reg": 21, + "uart_get_selectlock": 12 + }, + ".flash.rodata": { + "str1.4": 249, + "get_clk_en_mask": 128, + "get_rst_en_mask": 128, + "__FUNCTION__$5441": 24, + "TG": 8 + } +} + + +*** +Running idf_size_tests.py... Total sizes: DRAM .data size: 0 bytes DRAM .bss size: 0 bytes +Used static DRAM: 0 bytes ( 0 available, nan% used) +Used static IRAM: 0 bytes ( 0 available, nan% used) + Flash code: 0 bytes + Flash rodata: 0 bytes +Total image size:~ 0 bytes (.bin may be padded larger) diff --git a/tools/test_idf_size/test.sh b/tools/test_idf_size/test.sh index 5b2edd1cf9..0270fa3640 100755 --- a/tools/test_idf_size/test.sh +++ b/tools/test_idf_size/test.sh @@ -2,11 +2,23 @@ { coverage debug sys \ && coverage erase &> output \ + && echo -e "\n***\nRunning idf_size.py..." >> output \ && coverage run -a $IDF_PATH/tools/idf_size.py app.map &>> output \ + && echo -e "\n***\nRunning idf_size.py --archives..." >> output \ && coverage run -a $IDF_PATH/tools/idf_size.py --archives app.map &>> output \ + && echo -e "\n***\nRunning idf_size.py --files..." >> output \ && coverage run -a $IDF_PATH/tools/idf_size.py --files app.map &>> output \ + && echo -e "\n***\nRunning idf_size.py --archive_details..." >> output \ && coverage run -a $IDF_PATH/tools/idf_size.py --archive_details libdriver.a app.map &>> output \ + && echo -e "\n***]nProducing JSON output..." >> output \ + && coverage run -a $IDF_PATH/tools/idf_size.py --json app.map &>> output \ + && coverage run -a $IDF_PATH/tools/idf_size.py --json --archives app.map &>> output \ + && coverage run -a $IDF_PATH/tools/idf_size.py --json --files app.map &>> output \ + && coverage run -a $IDF_PATH/tools/idf_size.py --json --archive_details libdriver.a app.map &>> output \ + && echo -e "\n***\nRunning idf_size_tests.py..." >> output \ && coverage run -a $IDF_PATH/tools/test_idf_size/test_idf_size.py &>> output \ - && diff output expected_output \ + && diff -Z output expected_output \ && coverage report \ ; } || { echo 'The test for idf_size has failed. Please examine the artifacts.' ; exit 1; } + +# Note: "diff -Z is used because some versions of Python print trailing whitespace for JSON pretty-printing, and some don't diff --git a/tools/test_idf_size/test_idf_size.py b/tools/test_idf_size/test_idf_size.py index adafea9294..4f7a93c032 100644 --- a/tools/test_idf_size/test_idf_size.py +++ b/tools/test_idf_size/test_idf_size.py @@ -24,18 +24,19 @@ except ImportError: if __name__ == "__main__": + # Should deliver a RuntimeError as the 'test' header doesn't exist try: idf_size.scan_to_header([], 'test') - except RuntimeError: - pass + except RuntimeError as e: + assert "Didn't find line" in str(e) + # Should deliver a RuntimeError as there's no content under the heading try: idf_size.load_memory_config(["Memory Configuration"]) pass - except RuntimeError: - pass + except RuntimeError as e: + assert "End of file" in str(e) - try: - idf_size.print_summary({"iram0_0_seg": {"length":0}, "dram0_0_seg": {"length":0}}, {}) - except ZeroDivisionError: - pass + # This used to crash with a division by zero error but now it just prints nan% due to + # zero lengths + idf_size.print_summary({"iram0_0_seg": {"length":0}, "dram0_0_seg": {"length":0}}, {}) From 13908160fb73c7942cd57fab397ded08361ee8ae Mon Sep 17 00:00:00 2001 From: baohongde Date: Thu, 30 May 2019 20:19:43 +0800 Subject: [PATCH 006/486] components/bt: Fix make errors due to macro usage error --- .../profile/std/hf_client/bta_hf_client_co.c | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/components/bt/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c b/components/bt/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c index 6e756fc6ce..b8b2ea40c7 100644 --- a/components/bt/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c +++ b/components/bt/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c @@ -212,30 +212,29 @@ void bta_hf_client_sco_co_open(UINT16 handle, UINT8 air_mode, UINT8 inout_pkt_si #endif /// (HFP_DYNAMIC_MEMORY == TRUE) - bta_hf_dec_init(); - bta_hf_enc_init(); + bta_hf_dec_init(); + bta_hf_enc_init(); - return; - -error_exit:; -#if (HFP_DYNAMIC_MEMORY == TRUE) - if (bta_hf_client_co_cb_ptr) { - osi_free(bta_hf_client_co_cb_ptr); - bta_hf_client_co_cb_ptr = NULL; - } - -#if (PLC_INCLUDED == TRUE) - if (bta_hf_ct_plc_ptr) { - osi_free(bta_hf_ct_plc_ptr); - bta_hf_ct_plc_ptr = NULL; - } -#endif ///(PLC_INCLUDED == TRUE) - -#endif /// (HFP_DYNAMIC_MEMORY == TRUE) + return; } else { + return; // Nothing to do } +#if (HFP_DYNAMIC_MEMORY == TRUE) +error_exit:; + if (bta_hf_client_co_cb_ptr) { + osi_free(bta_hf_client_co_cb_ptr); + bta_hf_client_co_cb_ptr = NULL; + } + +#if (PLC_INCLUDED == TRUE) + if (bta_hf_ct_plc_ptr) { + osi_free(bta_hf_ct_plc_ptr); + bta_hf_ct_plc_ptr = NULL; + } +#endif ///(PLC_INCLUDED == TRUE) +#endif /// (HFP_DYNAMIC_MEMORY == TRUE) return; } From 89e2b48a1847f999acc930a539fa6164f8dbe5c8 Mon Sep 17 00:00:00 2001 From: baohongde Date: Mon, 3 Jun 2019 19:29:54 +0800 Subject: [PATCH 007/486] components/bt: Add API to config EIR data --- components/bt/CMakeLists.txt | 1 + components/bt/bluedroid/api/esp_gap_bt_api.c | 32 ++ .../bluedroid/api/include/api/esp_bt_defs.h | 3 +- .../api/include/api/esp_gap_bt_api.h | 62 ++- components/bt/bluedroid/bta/dm/bta_dm_act.c | 413 +++++++++++++----- components/bt/bluedroid/bta/dm/bta_dm_api.c | 42 ++ components/bt/bluedroid/bta/dm/bta_dm_cfg.c | 20 +- components/bt/bluedroid/bta/dm/bta_dm_main.c | 1 + .../bt/bluedroid/bta/dm/include/bta_dm_int.h | 21 +- .../bt/bluedroid/bta/include/bta/bta_api.h | 39 +- .../bluedroid/bta/include/bta/bta_gap_bt_co.h | 29 ++ components/bt/bluedroid/btc/core/btc_util.c | 34 ++ .../bt/bluedroid/btc/include/btc/btc_util.h | 1 + .../btc/profile/std/gap/bta_gap_bt_co.c | 40 ++ .../btc/profile/std/gap/btc_gap_bt.c | 73 +++- .../btc/profile/std/include/btc_gap_bt.h | 7 + .../bluedroid/common/include/common/bt_defs.h | 1 + .../common/include/common/bt_target.h | 12 +- components/bt/bluedroid/stack/btm/btm_inq.c | 5 +- .../bluedroid/stack/include/stack/bt_types.h | 1 + .../bluedroid/stack/include/stack/btm_api.h | 6 +- .../bluedroid/stack/include/stack/hcidefs.h | 1 + 22 files changed, 688 insertions(+), 156 deletions(-) create mode 100644 components/bt/bluedroid/bta/include/bta/bta_gap_bt_co.h create mode 100644 components/bt/bluedroid/btc/profile/std/gap/bta_gap_bt_co.c diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index 50ff9abf60..081e2a606e 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -126,6 +126,7 @@ if(CONFIG_BT_ENABLED) "bluedroid/btc/profile/std/avrc/bta_avrc_co.c" "bluedroid/btc/profile/std/gap/btc_gap_ble.c" "bluedroid/btc/profile/std/gap/btc_gap_bt.c" + "bluedroid/btc/profile/std/gap/bta_gap_bt_co.c" "bluedroid/btc/profile/std/gatt/btc_gatt_common.c" "bluedroid/btc/profile/std/gatt/btc_gatt_util.c" "bluedroid/btc/profile/std/gatt/btc_gattc.c" diff --git a/components/bt/bluedroid/api/esp_gap_bt_api.c b/components/bt/bluedroid/api/esp_gap_bt_api.c index ff3f945c48..f096b0fd01 100644 --- a/components/bt/bluedroid/api/esp_gap_bt_api.c +++ b/components/bt/bluedroid/api/esp_gap_bt_api.c @@ -144,6 +144,38 @@ uint8_t *esp_bt_gap_resolve_eir_data(uint8_t *eir, esp_bt_eir_type_t type, uint8 return BTM_CheckEirData(eir, type, length); } +esp_err_t esp_bt_gap_config_eir_data(esp_bt_eir_data_t *eir_data) +{ + btc_msg_t msg; + btc_gap_bt_args_t arg; + + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + if (eir_data == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (eir_data->manufacturer_len > ESP_BT_EIR_MAX_LEN + || eir_data->url_len > ESP_BT_EIR_MAX_LEN) { + return ESP_ERR_INVALID_ARG; + } + + if ((eir_data->manufacturer_len > 0 && eir_data->p_manufacturer_data == NULL) + || (eir_data->url_len > 0 && eir_data->p_url == NULL)) { + return ESP_ERR_INVALID_ARG; + } + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_GAP_BT; + msg.act = BTC_GAP_BT_ACT_CONFIG_EIR; + + memcpy(&arg.config_eir, eir_data, sizeof(esp_bt_eir_data_t)); + + return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), btc_gap_bt_arg_deep_copy) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + esp_err_t esp_bt_gap_set_cod(esp_bt_cod_t cod, esp_bt_cod_mode_t mode) { btc_msg_t msg; diff --git a/components/bt/bluedroid/api/include/api/esp_bt_defs.h b/components/bt/bluedroid/api/include/api/esp_bt_defs.h index 7e1063c71c..51044d45c7 100644 --- a/components/bt/bluedroid/api/include/api/esp_bt_defs.h +++ b/components/bt/bluedroid/api/include/api/esp_bt_defs.h @@ -51,7 +51,8 @@ typedef enum { ESP_BT_STATUS_PEER_LE_DATA_LEN_UNSUPPORTED, /* relate to BTM_PEER_LE_DATA_LEN_UNSUPPORTED in stack/btm_api.h */ ESP_BT_STATUS_CONTROL_LE_DATA_LEN_UNSUPPORTED,/* relate to BTM_CONTROL_LE_DATA_LEN_UNSUPPORTED in stack/btm_api.h */ ESP_BT_STATUS_ERR_ILLEGAL_PARAMETER_FMT, /* relate to HCI_ERR_ILLEGAL_PARAMETER_FMT in stack/hcidefs.h */ - ESP_BT_STATUS_MEMORY_FULL, /* relate to BT_STATUS_MEMORY_FULL in bt_def.h */ + ESP_BT_STATUS_MEMORY_FULL = 20, /* relate to BT_STATUS_MEMORY_FULL in bt_def.h */ + ESP_BT_STATUS_EIR_TOO_LARGE, /* relate to BT_STATUS_EIR_TOO_LARGE in bt_def.h */ } esp_bt_status_t; diff --git a/components/bt/bluedroid/api/include/api/esp_gap_bt_api.h b/components/bt/bluedroid/api/include/api/esp_gap_bt_api.h index 084cabec23..076f59caf7 100644 --- a/components/bt/bluedroid/api/include/api/esp_gap_bt_api.h +++ b/components/bt/bluedroid/api/include/api/esp_gap_bt_api.h @@ -90,8 +90,30 @@ typedef enum { ESP_BT_EIR_TYPE_SHORT_LOCAL_NAME = 0x08, /*!< Shortened Local Name */ ESP_BT_EIR_TYPE_CMPL_LOCAL_NAME = 0x09, /*!< Complete Local Name */ ESP_BT_EIR_TYPE_TX_POWER_LEVEL = 0x0a, /*!< Tx power level, value is 1 octet ranging from -127 to 127, unit is dBm*/ + ESP_BT_EIR_TYPE_URL = 0x24, /*!< Uniform resource identifier */ ESP_BT_EIR_TYPE_MANU_SPECIFIC = 0xff, /*!< Manufacturer specific data */ } esp_bt_eir_type_t; +#define ESP_BT_EIR_TYPE_MAX_NUM 12 /*!< MAX number of EIR type */ + +/* ESP_BT_EIR_FLAG bit definition */ +#define ESP_BT_EIR_FLAG_LIMIT_DISC (0x01 << 0) +#define ESP_BT_EIR_FLAG_GEN_DISC (0x01 << 1) +#define ESP_BT_EIR_FLAG_BREDR_NOT_SPT (0x01 << 2) +#define ESP_BT_EIR_FLAG_DMT_CONTROLLER_SPT (0x01 << 3) +#define ESP_BT_EIR_FLAG_DMT_HOST_SPT (0x01 << 4) + +#define ESP_BT_EIR_MAX_LEN 240 +/// EIR data content, according to "Supplement to the Bluetooth Core Specification" +typedef struct { + bool fec_required; /*!< FEC is required or not, true by default */ + bool include_txpower; /*!< EIR data include TX power, false by default */ + bool include_uuid; /*!< EIR data include UUID, false by default */ + uint8_t flag; /*!< EIR flags, see ESP_BT_EIR_FLAG for details, EIR will not include flag if it is 0, 0 by default */ + uint16_t manufacturer_len; /*!< Manufacturer data length, 0 by default */ + uint8_t *p_manufacturer_data; /*!< Manufacturer data point */ + uint16_t url_len; /*!< URL length, 0 by default */ + uint8_t *p_url; /*!< URL point */ +} esp_bt_eir_data_t; /// Major service class field of Class of Device, mutiple bits can be set typedef enum { @@ -179,6 +201,7 @@ typedef enum { ESP_BT_GAP_KEY_NOTIF_EVT, /*!< Simple Pairing Passkey Notification */ ESP_BT_GAP_KEY_REQ_EVT, /*!< Simple Pairing Passkey request */ ESP_BT_GAP_READ_RSSI_DELTA_EVT, /*!< read rssi event */ + ESP_BT_GAP_CONFIG_EIR_DATA_EVT, /*!< config EIR data event */ ESP_BT_GAP_EVT_MAX, } esp_bt_gap_cb_event_t; @@ -237,6 +260,19 @@ typedef union { int8_t rssi_delta; /*!< rssi delta value range -128 ~127, The value zero indicates that the RSSI is inside the Golden Receive Power Range, the Golden Receive Power Range is from ESP_BT_GAP_RSSI_LOW_THRLD to ESP_BT_GAP_RSSI_HIGH_THRLD */ } read_rssi_delta; /*!< read rssi parameter struct */ + /** + * @brief ESP_BT_GAP_CONFIG_EIR_DATA_EVT * + */ + struct config_eir_data_param { + esp_bt_status_t stat; /*!< config EIR status: + ESP_BT_STATUS_SUCCESS: config success + ESP_BT_STATUS_EIR_TOO_LARGE: the EIR data is more than 240B. The EIR may not contain the whole data. + others: failed + */ + uint8_t eir_type_num; /*!< the number of EIR types in EIR type */ + esp_bt_eir_type_t eir_type[ESP_BT_EIR_TYPE_MAX_NUM]; /*!< EIR types in EIR type */ + } config_eir_data; /*!< config EIR data */ + /** * @brief ESP_BT_GAP_AUTH_CMPL_EVT */ @@ -368,8 +404,8 @@ esp_err_t esp_bt_gap_set_scan_mode(esp_bt_connection_mode_t c_mode, esp_bt_disco /** * @brief Start device discovery. This function should be called after esp_bluedroid_enable() completes successfully. - * esp_bt_gap_cb_t will is called with ESP_BT_GAP_DISC_STATE_CHANGED_EVT if discovery is started or halted. - * esp_bt_gap_cb_t will is called with ESP_BT_GAP_DISC_RES_EVT if discovery result is got. + * esp_bt_gap_cb_t will be called with ESP_BT_GAP_DISC_STATE_CHANGED_EVT if discovery is started or halted. + * esp_bt_gap_cb_t will be called with ESP_BT_GAP_DISC_RES_EVT if discovery result is got. * * @param[in] mode - inquiry mode * @param[in] inq_len - inquiry duration in 1.28 sec units, ranging from 0x01 to 0x30 @@ -385,7 +421,7 @@ esp_err_t esp_bt_gap_start_discovery(esp_bt_inq_mode_t mode, uint8_t inq_len, ui /** * @brief Cancel device discovery. This function should be called after esp_bluedroid_enable() completes successfully - * esp_bt_gap_cb_t will is called with ESP_BT_GAP_DISC_STATE_CHANGED_EVT if discovery is stopped. + * esp_bt_gap_cb_t will be called with ESP_BT_GAP_DISC_STATE_CHANGED_EVT if discovery is stopped. * * @return * - ESP_OK : Succeed @@ -396,7 +432,7 @@ esp_err_t esp_bt_gap_cancel_discovery(void); /** * @brief Start SDP to get remote services. This function should be called after esp_bluedroid_enable() completes successfully. - * esp_bt_gap_cb_t will is called with ESP_BT_GAP_RMT_SRVCS_EVT after service discovery ends + * esp_bt_gap_cb_t will be called with ESP_BT_GAP_RMT_SRVCS_EVT after service discovery ends * * @return * - ESP_OK : Succeed @@ -409,7 +445,7 @@ esp_err_t esp_bt_gap_get_remote_services(esp_bd_addr_t remote_bda); * @brief Start SDP to look up the service matching uuid on the remote device. This function should be called after * esp_bluedroid_enable() completes successfully * - * esp_bt_gap_cb_t will is called with ESP_BT_GAP_RMT_SRVC_REC_EVT after service discovery ends + * esp_bt_gap_cb_t will be called with ESP_BT_GAP_RMT_SRVC_REC_EVT after service discovery ends * @return * - ESP_OK : Succeed * - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled @@ -429,9 +465,23 @@ esp_err_t esp_bt_gap_get_remote_service_record(esp_bd_addr_t remote_bda, esp_bt_ */ uint8_t *esp_bt_gap_resolve_eir_data(uint8_t *eir, esp_bt_eir_type_t type, uint8_t *length); +/** + * @brief This function is called to config EIR data. + * + * esp_bt_gap_cb_t will be called with ESP_BT_GAP_CONFIG_EIR_DATA_EVT after config EIR ends. + * + * @param[in] eir_data - pointer of EIR data content + * @return + * - ESP_OK : Succeed + * - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_ERR_INVALID_ARG: if param is invalid + * - ESP_FAIL: others + */ +esp_err_t esp_bt_gap_config_eir_data(esp_bt_eir_data_t *eir_data); + /** * @brief This function is called to set class of device. - * esp_bt_gap_cb_t will is called with ESP_BT_GAP_SET_COD_EVT after set COD ends + * esp_bt_gap_cb_t will be called with ESP_BT_GAP_SET_COD_EVT after set COD ends * Some profile have special restrictions on class of device, * changes may cause these profile do not work * diff --git a/components/bt/bluedroid/bta/dm/bta_dm_act.c b/components/bt/bluedroid/bta/dm/bta_dm_act.c index c02987c9fb..49cce8749a 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_act.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_act.c @@ -131,7 +131,7 @@ static void bta_dm_observe_discard_cb (uint32_t num_dis); static void bta_dm_delay_role_switch_cback(TIMER_LIST_ENT *p_tle); extern void sdpu_uuid16_to_uuid128(UINT16 uuid16, UINT8 *p_uuid128); static void bta_dm_disable_timer_cback(TIMER_LIST_ENT *p_tle); - +extern int bredr_txpwr_get(int *min_power_level, int *max_power_level); const UINT16 bta_service_id_to_uuid_lkup_tbl [BTA_MAX_SERVICE_ID] = { UUID_SERVCLASS_PNP_INFORMATION, /* Reserved */ @@ -325,6 +325,58 @@ void bta_dm_deinit_cb(void) memset(&bta_dm_cb, 0, sizeof(bta_dm_cb)); } +/******************************************************************************* + * + * Function bta_dm_eir_cfg_init + * + * Description Initializes the p_bta_dm_eir_cfg + * + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_eir_cfg_init(void) +{ + p_bta_dm_eir_cfg->bta_dm_eir_fec_required = BTM_EIR_DEFAULT_FEC_REQUIRED; + p_bta_dm_eir_cfg->bta_dm_eir_min_name_len = 50; + + p_bta_dm_eir_cfg->bta_dm_eir_included_uuid = TRUE; + p_bta_dm_eir_cfg->bta_dm_eir_included_tx_power = FALSE; + p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power = 3; + p_bta_dm_eir_cfg->bta_dm_eir_flags = 0; + + p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len = 0; + p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec = NULL; + + p_bta_dm_eir_cfg->bta_dm_eir_url_len = 0; + p_bta_dm_eir_cfg->bta_dm_eir_url = NULL; +} + +/******************************************************************************* + * + * Function bta_dm_eir_cfg_deinit + * + * Description De-initializes the p_bta_dm_eir_cfg + * + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_eir_cfg_deinit(void) +{ + p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len = 0; + if (p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec) { + osi_free(p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec); + p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec = NULL; + } + + p_bta_dm_eir_cfg->bta_dm_eir_url_len = 0; + if (p_bta_dm_eir_cfg->bta_dm_eir_url) { + osi_free(p_bta_dm_eir_cfg->bta_dm_eir_url); + p_bta_dm_eir_cfg->bta_dm_eir_url = NULL; + } +} + /******************************************************************************* ** ** Function bta_dm_sys_hw_cback @@ -363,6 +415,9 @@ static void bta_dm_sys_hw_cback( tBTA_SYS_HW_EVT status ) /* reinitialize the control block */ bta_dm_deinit_cb(); + /* reinitialize the Extended Inquiry Response */ + bta_dm_eir_cfg_deinit(); + bta_sys_free_timer(&bta_dm_search_cb.search_timer); #if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) #if ((defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) && SDP_INCLUDED == TRUE) @@ -391,6 +446,9 @@ static void bta_dm_sys_hw_cback( tBTA_SYS_HW_EVT status ) /* make sure the control block is properly initialized */ bta_dm_init_cb(); + /* make sure the Extended Inquiry Response is properly initialized */ + bta_dm_eir_cfg_init(); + /* and retrieve the callback */ bta_dm_cb.p_sec_cback = temp_cback; bta_dm_cb.is_bta_dm_active = TRUE; @@ -588,9 +646,52 @@ static void bta_dm_disable_timer_cback (TIMER_LIST_ENT *p_tle) *******************************************************************************/ void bta_dm_set_dev_name (tBTA_DM_MSG *p_data) { - BTM_SetLocalDeviceName((char *)p_data->set_name.name); +#if CLASSIC_BT_INCLUDED bta_dm_set_eir ((char *)p_data->set_name.name); +#endif /// CLASSIC_BT_INCLUDED +} + +void bta_dm_config_eir (tBTA_DM_MSG *p_data) +{ + tBTA_DM_API_CONFIG_EIR *config_eir = &p_data->config_eir; + + p_bta_dm_eir_cfg->bta_dm_eir_fec_required = config_eir->eir_fec_required; + p_bta_dm_eir_cfg->bta_dm_eir_included_uuid = config_eir->eir_included_uuid; + p_bta_dm_eir_cfg->bta_dm_eir_included_tx_power = config_eir->eir_included_tx_power; + p_bta_dm_eir_cfg->bta_dm_eir_flags = config_eir->eir_flags; + p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len = config_eir->eir_manufac_spec_len; + p_bta_dm_eir_cfg->bta_dm_eir_url_len = config_eir->eir_url_len; + + if (p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec) { + osi_free(p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec); + p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec = NULL; + } + if (config_eir->eir_manufac_spec) { + p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec = osi_malloc(config_eir->eir_manufac_spec_len); + if (p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec) { + memcpy(p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec, config_eir->eir_manufac_spec, config_eir->eir_manufac_spec_len); + } else { + APPL_TRACE_ERROR("%s, malloc failed.", __func__); + p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len = 0; + } + } + + if (p_bta_dm_eir_cfg->bta_dm_eir_url) { + osi_free(p_bta_dm_eir_cfg->bta_dm_eir_url); + p_bta_dm_eir_cfg->bta_dm_eir_url = NULL; + } + if (config_eir->eir_url) { + p_bta_dm_eir_cfg->bta_dm_eir_url = osi_malloc(config_eir->eir_url_len); + if (p_bta_dm_eir_cfg->bta_dm_eir_url == NULL) { + memcpy(p_bta_dm_eir_cfg->bta_dm_eir_url, config_eir->eir_url, config_eir->eir_url_len); + } else { + APPL_TRACE_ERROR("%s, malloc failed.", __func__); + p_bta_dm_eir_cfg->bta_dm_eir_url_len = 0; + } + } + + bta_dm_set_eir(NULL); } void bta_dm_update_white_list(tBTA_DM_MSG *p_data) @@ -3719,23 +3820,37 @@ static void bta_dm_set_eir (char *local_name) UINT8 custom_uuid_idx; #endif // BTA_EIR_SERVER_NUM_CUSTOM_UUID #endif // BTA_EIR_CANNED_UUID_LIST -#if (BTM_EIR_DEFAULT_FEC_REQUIRED == FALSE) - UINT8 free_eir_length = HCI_EXT_INQ_RESPONSE_LEN; -#else // BTM_EIR_DEFAULT_FEC_REQUIRED - UINT8 free_eir_length = HCI_DM5_PACKET_SIZE; -#endif // BTM_EIR_DEFAULT_FEC_REQUIRED + + UINT8 free_eir_length; + if (p_bta_dm_eir_cfg->bta_dm_eir_fec_required) { + free_eir_length = HCI_DM5_PACKET_SIZE; + } else { + free_eir_length = HCI_EXT_INQ_RESPONSE_LEN; + } + UINT8 num_uuid; UINT8 data_type; UINT8 local_name_len; + UINT8 eir_type[BTM_EIR_TYPE_MAX_NUM]; + UINT8 eir_type_num = 0; + + tBTA_STATUS status = BTA_SUCCESS; + /* wait until complete to disable */ if (bta_dm_cb.disable_timer.in_use) { + if (p_bta_dm_eir_cfg->config_eir_callback) { + p_bta_dm_eir_cfg->config_eir_callback(BTA_WRONG_MODE, eir_type_num , eir_type); + } return; } #if ( BTA_EIR_CANNED_UUID_LIST != TRUE ) /* wait until App is ready */ if (bta_dm_cb.app_ready_timer.in_use) { + if (p_bta_dm_eir_cfg->config_eir_callback) { + p_bta_dm_eir_cfg->config_eir_callback(BTA_WRONG_MODE, eir_type_num , eir_type); + } return; } @@ -3750,6 +3865,9 @@ static void bta_dm_set_eir (char *local_name) /* Allocate a buffer to hold HCI command */ if ((p_buf = (BT_HDR *)osi_malloc(BTM_CMD_BUF_SIZE)) == NULL) { APPL_TRACE_ERROR("bta_dm_set_eir couldn't allocate buffer"); + if (p_bta_dm_eir_cfg->config_eir_callback) { + p_bta_dm_eir_cfg->config_eir_callback(BTA_NO_RESOURCES, eir_type_num , eir_type); + } return; } p = (UINT8 *)p_buf + BTM_HCI_EIR_OFFSET; @@ -3790,6 +3908,7 @@ static void bta_dm_set_eir (char *local_name) UINT8_TO_STREAM(p, local_name_len + 1); UINT8_TO_STREAM(p, data_type); + eir_type[eir_type_num++] = data_type; if (local_name != NULL) { memcpy(p, local_name, local_name_len); @@ -3797,164 +3916,218 @@ static void bta_dm_set_eir (char *local_name) } free_eir_length -= local_name_len + 2; + /* if UUIDs are provided in configuration */ + if (p_bta_dm_eir_cfg->bta_dm_eir_included_uuid) { #if (BTA_EIR_CANNED_UUID_LIST == TRUE) - /* if UUID list is provided as static data in configuration */ - if (( p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len > 0 ) - && (p_bta_dm_eir_cfg->bta_dm_eir_uuid16)) { - if ( free_eir_length > LEN_UUID_16 + 2) { - free_eir_length -= 2; + /* if UUID list is provided as static data in configuration */ + if (( p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len > 0 ) + && (p_bta_dm_eir_cfg->bta_dm_eir_uuid16)) { + if ( free_eir_length > LEN_UUID_16 + 2) { + free_eir_length -= 2; - if ( free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len) { - num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len / LEN_UUID_16; - data_type = BTM_EIR_COMPLETE_16BITS_UUID_TYPE; - } else { /* not enough room for all UUIDs */ - APPL_TRACE_WARNING("BTA EIR: UUID 16-bit list is truncated"); - num_uuid = free_eir_length / LEN_UUID_16; - data_type = BTM_EIR_MORE_16BITS_UUID_TYPE; + if ( free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len) { + num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len / LEN_UUID_16; + data_type = BTM_EIR_COMPLETE_16BITS_UUID_TYPE; + } else { /* not enough room for all UUIDs */ + APPL_TRACE_WARNING("BTA EIR: UUID 16-bit list is truncated"); + num_uuid = free_eir_length / LEN_UUID_16; + data_type = BTM_EIR_MORE_16BITS_UUID_TYPE; + } + UINT8_TO_STREAM(p, num_uuid * LEN_UUID_16 + 1); + UINT8_TO_STREAM(p, data_type); + eir_type[eir_type_num++] = data_type; + memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_uuid16, num_uuid * LEN_UUID_16 ); + p += num_uuid * LEN_UUID_16; + free_eir_length -= num_uuid * LEN_UUID_16; + } else { + status = BTA_EIR_TOO_LARGE; } - UINT8_TO_STREAM(p, num_uuid * LEN_UUID_16 + 1); - UINT8_TO_STREAM(p, data_type); - memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_uuid16, num_uuid * LEN_UUID_16 ); - p += num_uuid * LEN_UUID_16; - free_eir_length -= num_uuid * LEN_UUID_16; } - } #else /* (BTA_EIR_CANNED_UUID_LIST == TRUE) */ - /* if UUID list is dynamic */ - if ( free_eir_length >= 2) { - p_length = p++; - p_type = p++; - num_uuid = 0; + /* if UUID list is dynamic */ + if ( free_eir_length >= 2) { + p_length = p++; + p_type = p++; + num_uuid = 0; - max_num_uuid = (free_eir_length - 2) / LEN_UUID_16; - data_type = BTM_GetEirSupportedServices( bta_dm_cb.eir_uuid, &p, max_num_uuid, &num_uuid ); + max_num_uuid = (free_eir_length - 2) / LEN_UUID_16; + data_type = BTM_GetEirSupportedServices( bta_dm_cb.eir_uuid, &p, max_num_uuid, &num_uuid ); - if ( data_type == BTM_EIR_MORE_16BITS_UUID_TYPE ) { - APPL_TRACE_WARNING("BTA EIR: UUID 16-bit list is truncated"); - } + if ( data_type == BTM_EIR_MORE_16BITS_UUID_TYPE ) { + APPL_TRACE_WARNING("BTA EIR: UUID 16-bit list is truncated"); + } #if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) - else { + else { + for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; custom_uuid_idx++) { + if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_16) { + if ( num_uuid < max_num_uuid ) { + UINT16_TO_STREAM(p, bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid16); + num_uuid++; + } else { + data_type = BTM_EIR_MORE_16BITS_UUID_TYPE; + APPL_TRACE_WARNING("BTA EIR: UUID 16-bit list is truncated"); + break; + } + } + } + } +#endif /* (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) */ + + UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_16 + 1); + UINT8_TO_STREAM(p_type, data_type); + eir_type[eir_type_num++] = data_type; + free_eir_length -= num_uuid * LEN_UUID_16 + 2; + } else { + status = BTA_EIR_TOO_LARGE; + } +#endif /* (BTA_EIR_CANNED_UUID_LIST == TRUE) */ + +#if ( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) + /* Adding 32-bit UUID list */ + if ( free_eir_length >= 2) { + p_length = p++; + p_type = p++; + num_uuid = 0; + data_type = BTM_EIR_COMPLETE_32BITS_UUID_TYPE; + + max_num_uuid = (free_eir_length - 2) / LEN_UUID_32; + for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; custom_uuid_idx++) { - if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_16) { + if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_32) { if ( num_uuid < max_num_uuid ) { - UINT16_TO_STREAM(p, bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid16); + UINT32_TO_STREAM(p, bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid32); num_uuid++; } else { - data_type = BTM_EIR_MORE_16BITS_UUID_TYPE; - APPL_TRACE_WARNING("BTA EIR: UUID 16-bit list is truncated"); + data_type = BTM_EIR_MORE_32BITS_UUID_TYPE; + APPL_TRACE_WARNING("BTA EIR: UUID 32-bit list is truncated"); break; } } } + + UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_32 + 1); + UINT8_TO_STREAM(p_type, data_type); + eir_type[eir_type_num++] = data_type; + free_eir_length -= num_uuid * LEN_UUID_32 + 2; + } else { + status = BTA_EIR_TOO_LARGE; } -#endif /* (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) */ - UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_16 + 1); - UINT8_TO_STREAM(p_type, data_type); - free_eir_length -= num_uuid * LEN_UUID_16 + 2; - } -#endif /* (BTA_EIR_CANNED_UUID_LIST == TRUE) */ + /* Adding 128-bit UUID list */ + if ( free_eir_length >= 2) { + p_length = p++; + p_type = p++; + num_uuid = 0; + data_type = BTM_EIR_COMPLETE_128BITS_UUID_TYPE; -#if ( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) - /* Adding 32-bit UUID list */ - if ( free_eir_length >= 2) { - p_length = p++; - p_type = p++; - num_uuid = 0; - data_type = BTM_EIR_COMPLETE_32BITS_UUID_TYPE; + max_num_uuid = (free_eir_length - 2) / LEN_UUID_128; - max_num_uuid = (free_eir_length - 2) / LEN_UUID_32; - - for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; custom_uuid_idx++) { - if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_32) { - if ( num_uuid < max_num_uuid ) { - UINT32_TO_STREAM(p, bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid32); - num_uuid++; - } else { - data_type = BTM_EIR_MORE_32BITS_UUID_TYPE; - APPL_TRACE_WARNING("BTA EIR: UUID 32-bit list is truncated"); - break; + for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; custom_uuid_idx++) { + if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_128) { + if ( num_uuid < max_num_uuid ) { + ARRAY16_TO_STREAM(p, bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid128); + num_uuid++; + } else { + data_type = BTM_EIR_MORE_128BITS_UUID_TYPE; + APPL_TRACE_WARNING("BTA EIR: UUID 128-bit list is truncated"); + break; + } } } + + UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_128 + 1); + UINT8_TO_STREAM(p_type, data_type); + eir_type[eir_type_num++] = data_type; + free_eir_length -= num_uuid * LEN_UUID_128 + 2; } - - UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_32 + 1); - UINT8_TO_STREAM(p_type, data_type); - free_eir_length -= num_uuid * LEN_UUID_32 + 2; - } - - /* Adding 128-bit UUID list */ - if ( free_eir_length >= 2) { - p_length = p++; - p_type = p++; - num_uuid = 0; - data_type = BTM_EIR_COMPLETE_128BITS_UUID_TYPE; - - max_num_uuid = (free_eir_length - 2) / LEN_UUID_128; - - for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; custom_uuid_idx++) { - if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_128) { - if ( num_uuid < max_num_uuid ) { - ARRAY16_TO_STREAM(p, bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid128); - num_uuid++; - } else { - data_type = BTM_EIR_MORE_128BITS_UUID_TYPE; - APPL_TRACE_WARNING("BTA EIR: UUID 128-bit list is truncated"); - break; - } - } + else { + status = BTA_EIR_TOO_LARGE; } - - UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_128 + 1); - UINT8_TO_STREAM(p_type, data_type); - free_eir_length -= num_uuid * LEN_UUID_128 + 2; - } #endif /* ( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) */ + } /* if Flags are provided in configuration */ - if (( p_bta_dm_eir_cfg->bta_dm_eir_flag_len > 0 ) - && ( p_bta_dm_eir_cfg->bta_dm_eir_flags ) - && ( free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 2 )) { - UINT8_TO_STREAM(p, p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 1); - UINT8_TO_STREAM(p, BTM_EIR_FLAGS_TYPE); - memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_flags, - p_bta_dm_eir_cfg->bta_dm_eir_flag_len); - p += p_bta_dm_eir_cfg->bta_dm_eir_flag_len; - free_eir_length -= p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 2; + if ( p_bta_dm_eir_cfg->bta_dm_eir_flags != 0 ) { + if ( free_eir_length >= 3 ) { + UINT8_TO_STREAM(p, 2); + UINT8_TO_STREAM(p, BTM_EIR_FLAGS_TYPE); + eir_type[eir_type_num++] = BTM_EIR_FLAGS_TYPE; + UINT8_TO_STREAM(p, p_bta_dm_eir_cfg->bta_dm_eir_flags); + free_eir_length -= 3; + } else { + status = BTA_EIR_TOO_LARGE; + } } /* if Manufacturer Specific are provided in configuration */ if (( p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len > 0 ) - && ( p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec ) - && ( free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 2 )) { - p_length = p; + && ( p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec )) { + if ( free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 2) { + p_length = p; - UINT8_TO_STREAM(p, p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 1); - UINT8_TO_STREAM(p, BTM_EIR_MANUFACTURER_SPECIFIC_TYPE); - memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec, + UINT8_TO_STREAM(p, p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 1); + UINT8_TO_STREAM(p, BTM_EIR_MANUFACTURER_SPECIFIC_TYPE); + eir_type[eir_type_num++] = BTM_EIR_MANUFACTURER_SPECIFIC_TYPE; + memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec, p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len); - p += p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len; - free_eir_length -= p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 2; - + p += p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len; + free_eir_length -= p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 2; + } else { + status = BTA_EIR_TOO_LARGE; + } } else { p_length = NULL; } /* if Inquiry Tx Resp Power compiled */ - if ((p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power) && - (free_eir_length >= 3)) { - UINT8_TO_STREAM(p, 2); /* Length field */ - UINT8_TO_STREAM(p, BTM_EIR_TX_POWER_LEVEL_TYPE); - UINT8_TO_STREAM(p, *(p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power)); - free_eir_length -= 3; + if (p_bta_dm_eir_cfg->bta_dm_eir_included_tx_power) { + if (free_eir_length >= 3) { + int min_power_level, max_power_level; + if (bredr_txpwr_get(&min_power_level, &max_power_level) == 0) { + INT8 btm_tx_power[BTM_TX_POWER_LEVEL_MAX + 1] = BTM_TX_POWER; + p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power = btm_tx_power[max_power_level]; + UINT8_TO_STREAM(p, 2); /* Length field */ + UINT8_TO_STREAM(p, BTM_EIR_TX_POWER_LEVEL_TYPE); + eir_type[eir_type_num++] = BTM_EIR_TX_POWER_LEVEL_TYPE; + UINT8_TO_STREAM(p, p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power); + free_eir_length -= 3; + } + } else { + status = BTA_EIR_TOO_LARGE; + } + } + + /* if URL are provided in configuration */ + if (( p_bta_dm_eir_cfg->bta_dm_eir_url_len > 0 ) + && ( p_bta_dm_eir_cfg->bta_dm_eir_url )) { + if ( free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_url_len + 2 ) { + UINT8_TO_STREAM(p, p_bta_dm_eir_cfg->bta_dm_eir_url_len + 1); + UINT8_TO_STREAM(p, BTM_EIR_URL_TYPE); + eir_type[eir_type_num++] = BTM_EIR_URL_TYPE; + memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_url, + p_bta_dm_eir_cfg->bta_dm_eir_url_len); + p += p_bta_dm_eir_cfg->bta_dm_eir_url_len; + free_eir_length -= p_bta_dm_eir_cfg->bta_dm_eir_url_len + 2; + } else { + status = BTA_EIR_TOO_LARGE; + } } if ( free_eir_length ) { UINT8_TO_STREAM(p, 0); /* terminator of significant part */ } - BTM_WriteEIR( p_buf ); + tBTM_STATUS btm_status = BTM_WriteEIR( p_buf, p_bta_dm_eir_cfg->bta_dm_eir_fec_required ); + if ( btm_status == BTM_MODE_UNSUPPORTED) { + status = BTA_WRONG_MODE; + } else if (btm_status != BTM_SUCCESS) { + status = BTA_FAILURE; + } + + if (p_bta_dm_eir_cfg->config_eir_callback) { + p_bta_dm_eir_cfg->config_eir_callback(status, eir_type_num, eir_type); + } } /******************************************************************************* diff --git a/components/bt/bluedroid/bta/dm/bta_dm_api.c b/components/bt/bluedroid/bta/dm/bta_dm_api.c index 078903d31a..927257733f 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_api.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_api.c @@ -183,6 +183,48 @@ void BTA_DmSetDeviceName(const char *p_name) } +void BTA_DmConfigEir(tBTA_DM_EIR_CONF *eir_config) +{ + tBTA_DM_API_CONFIG_EIR *p_msg; + + UINT8 eir_manufac_spec_len = eir_config->bta_dm_eir_manufac_spec_len; + UINT8 eir_url_len = eir_config->bta_dm_eir_url_len; + + if (eir_manufac_spec_len > HCI_EXT_INQ_RESPONSE_LEN) { + APPL_TRACE_WARNING ("%s: Manufacturer data is too long(%d), cut it to %d\n", + __func__, eir_manufac_spec_len, HCI_EXT_INQ_RESPONSE_LEN); + eir_manufac_spec_len = HCI_EXT_INQ_RESPONSE_LEN; + } + if (eir_url_len > HCI_EXT_INQ_RESPONSE_LEN) { + APPL_TRACE_WARNING ("%s: URL is too long(%d), cut it to %d\n", + __func__, eir_url_len, HCI_EXT_INQ_RESPONSE_LEN); + eir_url_len = HCI_EXT_INQ_RESPONSE_LEN; + } + + if ((p_msg = (tBTA_DM_API_CONFIG_EIR *) osi_malloc(sizeof(tBTA_DM_API_CONFIG_EIR) + eir_manufac_spec_len + eir_url_len)) != NULL) { + p_msg->hdr.event = BTA_DM_API_CONFIG_EIR_EVT; + + p_msg->eir_fec_required = eir_config->bta_dm_eir_fec_required; + p_msg->eir_included_tx_power = eir_config->bta_dm_eir_included_tx_power; + p_msg->eir_included_uuid = eir_config->bta_dm_eir_included_uuid; + p_msg->eir_flags = eir_config->bta_dm_eir_flags; + p_msg->eir_manufac_spec_len = eir_manufac_spec_len; + p_msg->eir_manufac_spec = p_msg->data; + p_msg->eir_url_len = eir_url_len; + p_msg->eir_url = p_msg->data + eir_manufac_spec_len; + + if (eir_manufac_spec_len > 0) { + memcpy(p_msg->eir_manufac_spec, eir_config->bta_dm_eir_manufac_spec, eir_manufac_spec_len); + } + + if (eir_url_len > 0) { + memcpy(p_msg->eir_url, eir_config->bta_dm_eir_url, eir_url_len); + } + + bta_sys_sendmsg(p_msg); + } +} + void BTA_DmUpdateWhiteList(BOOLEAN add_remove, BD_ADDR remote_addr, tBLE_ADDR_TYPE addr_type, tBTA_ADD_WHITELIST_CBACK *add_wl_cb) { tBTA_DM_API_UPDATE_WHITE_LIST *p_msg; diff --git a/components/bt/bluedroid/bta/dm/bta_dm_cfg.c b/components/bt/bluedroid/bta/dm/bta_dm_cfg.c index e9ad1f38d2..14462e4409 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_cfg.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_cfg.c @@ -29,6 +29,7 @@ #include "bta/bta_api.h" #include "bta_dm_int.h" #include "bta/bta_jv_api.h" +#include "bta/bta_gap_bt_co.h" #ifndef BTA_DM_LINK_POLICY_SETTINGS #define BTA_DM_LINK_POLICY_SETTINGS (HCI_ENABLE_MASTER_SLAVE_SWITCH | HCI_ENABLE_HOLD_MODE | HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_PARK_MODE) @@ -411,10 +412,12 @@ const UINT8 bta_dm_eir_uuid16_list[] = { 0x08, 0x11, /* Headset */ #endif // BTA_EIR_CANNED_UUID_LIST /* Extended Inquiry Response */ -const tBTA_DM_EIR_CONF bta_dm_eir_cfg = { +tBTA_DM_EIR_CONF bta_dm_eir_cfg = { + BTM_EIR_DEFAULT_FEC_REQUIRED, /* FEC required */ 50, /* minimum length of local name when it is shortened */ /* if length of local name is longer than this and EIR has not enough */ /* room for all UUID list then local name is shortened to this length */ + TRUE, /* Included UUIDs */ #if (BTA_EIR_CANNED_UUID_LIST == TRUE) 8, (UINT8 *)bta_dm_eir_uuid16_list, @@ -425,12 +428,17 @@ const tBTA_DM_EIR_CONF bta_dm_eir_cfg = { /* BTM_EIR_UUID_LKUP_TBL can be overrided */ }, #endif // BTA_EIR_CANNED_UUID_LIST - NULL, /* Inquiry TX power */ - 0, /* length of flags in bytes */ - NULL, /* flags for EIR */ + FALSE, /* Not included TX power*/ + 3, /* Inquiry TX power */ + 0, /* flags for EIR */ 0, /* length of manufacturer specific in bytes */ NULL, /* manufacturer specific */ - 0, /* length of additional data in bytes */ - NULL /* additional data */ + 0, /* length of URL in bytes */ + NULL, /* URL */ +#if (BTC_GAP_BT_INCLUDED == TRUE) + (tBTA_DM_CONFIG_EIR_CBACK *)btc_gap_bt_config_eir_cmpl_callback /* callback */ +#else + NULL +#endif /* #if (BTC_GAP_BT_INCLUDED == TRUE) */ }; tBTA_DM_EIR_CONF *p_bta_dm_eir_cfg = (tBTA_DM_EIR_CONF *) &bta_dm_eir_cfg; diff --git a/components/bt/bluedroid/bta/dm/bta_dm_main.c b/components/bt/bluedroid/bta/dm/bta_dm_main.c index 0f45dfbe97..3b9a7cc4ce 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_main.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_main.c @@ -56,6 +56,7 @@ const tBTA_DM_ACTION bta_dm_action[BTA_DM_MAX_EVT] = { bta_dm_enable, /* BTA_DM_API_ENABLE_EVT */ bta_dm_disable, /* BTA_DM_API_DISABLE_EVT */ bta_dm_set_dev_name, /* BTA_DM_API_SET_NAME_EVT */ + bta_dm_config_eir, /* BTA_DM_API_CONFIG_EIR_EVT */ bta_dm_set_visibility, /* BTA_DM_API_SET_VISIBILITY_EVT */ bta_dm_acl_change, /* BTA_DM_ACL_CHANGE_EVT */ bta_dm_add_device, /* BTA_DM_API_ADD_DEVICE_EVT */ diff --git a/components/bt/bluedroid/bta/dm/include/bta_dm_int.h b/components/bt/bluedroid/bta/dm/include/bta_dm_int.h index 9ff577481c..2c21b0c574 100644 --- a/components/bt/bluedroid/bta/dm/include/bta_dm_int.h +++ b/components/bt/bluedroid/bta/dm/include/bta_dm_int.h @@ -52,6 +52,7 @@ enum { BTA_DM_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_DM), BTA_DM_API_DISABLE_EVT, BTA_DM_API_SET_NAME_EVT, + BTA_DM_API_CONFIG_EIR_EVT, BTA_DM_API_SET_VISIBILITY_EVT, BTA_DM_ACL_CHANGE_EVT, @@ -188,6 +189,20 @@ typedef struct { BD_NAME name; /* max 248 bytes name, plus must be Null terminated */ } tBTA_DM_API_SET_NAME; +/* data type for BTA_DM_API_CONFIG_EIR_EVT */ +typedef struct { + BT_HDR hdr; + BOOLEAN eir_fec_required; + BOOLEAN eir_included_tx_power; + BOOLEAN eir_included_uuid; + UINT8 eir_flags; + UINT8 eir_manufac_spec_len; + UINT8 *eir_manufac_spec; + UINT8 eir_url_len; + UINT8 *eir_url; + UINT8 data[]; +}tBTA_DM_API_CONFIG_EIR; + typedef struct { BT_HDR hdr; BOOLEAN add_remove; @@ -478,7 +493,7 @@ typedef struct { typedef struct { BT_HDR hdr; - BOOLEAN add; + BOOLEAN add; UINT32 static_passkey; } tBTA_DM_API_SET_DEFAULT_PASSKEY; @@ -784,6 +799,7 @@ typedef union { tBTA_DM_API_ENABLE enable; tBTA_DM_API_SET_NAME set_name; + tBTA_DM_API_CONFIG_EIR config_eir; tBTA_DM_API_UPDATE_WHITE_LIST white_list; tBTA_DM_API_READ_ADV_TX_POWER read_tx_power; @@ -1185,7 +1201,7 @@ extern tBTA_DM_SSR_SPEC *p_bta_dm_ssr_spec; #endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */ /* update dynamic BRCM Aware EIR data */ -extern const tBTA_DM_EIR_CONF bta_dm_eir_cfg; +extern tBTA_DM_EIR_CONF bta_dm_eir_cfg; extern tBTA_DM_EIR_CONF *p_bta_dm_eir_cfg; /* DM control block */ @@ -1222,6 +1238,7 @@ extern void bta_dm_search_sm_disable( void ); extern void bta_dm_enable (tBTA_DM_MSG *p_data); extern void bta_dm_disable (tBTA_DM_MSG *p_data); extern void bta_dm_set_dev_name (tBTA_DM_MSG *p_data); +extern void bta_dm_config_eir (tBTA_DM_MSG *p_data); extern void bta_dm_update_white_list(tBTA_DM_MSG *p_data); extern void bta_dm_ble_read_adv_tx_power(tBTA_DM_MSG *p_data); extern void bta_dm_ble_read_rssi(tBTA_DM_MSG *p_data); diff --git a/components/bt/bluedroid/bta/include/bta/bta_api.h b/components/bt/bluedroid/bta/include/bta/bta_api.h index c7bad21fed..a7dc0185f3 100644 --- a/components/bt/bluedroid/bta/include/bta/bta_api.h +++ b/components/bt/bluedroid/bta/include/bta/bta_api.h @@ -46,6 +46,7 @@ #define BTA_BUSY 3 #define BTA_NO_RESOURCES 4 #define BTA_WRONG_MODE 5 +#define BTA_EIR_TOO_LARGE 6 typedef UINT8 tBTA_STATUS; @@ -295,21 +296,31 @@ typedef struct { #endif } tBTA_DM_INQ; +/* Config EIR callback */ +typedef void (tBTA_DM_CONFIG_EIR_CBACK) (tBTA_STATUS status, UINT8 eir_type_num, UINT8 *eir_type); + typedef struct { + BOOLEAN bta_dm_eir_fec_required; /* FEC required */ UINT8 bta_dm_eir_min_name_len; /* minimum length of local name when it is shortened */ + + BOOLEAN bta_dm_eir_included_uuid; /* Included UUIDs or not */ #if (BTA_EIR_CANNED_UUID_LIST == TRUE) UINT8 bta_dm_eir_uuid16_len; /* length of 16-bit UUIDs */ UINT8 *bta_dm_eir_uuid16; /* 16-bit UUIDs */ #else - UINT32 uuid_mask[BTM_EIR_SERVICE_ARRAY_SIZE]; /* mask of UUID list in EIR */ + UINT32 uuid_mask[BTM_EIR_SERVICE_ARRAY_SIZE]; /* mask of UUID list in EIR */ #endif - INT8 *bta_dm_eir_inq_tx_power; /* Inquiry TX power */ - UINT8 bta_dm_eir_flag_len; /* length of flags in bytes */ - UINT8 *bta_dm_eir_flags; /* flags for EIR */ + + BOOLEAN bta_dm_eir_included_tx_power; /* Included inquiry TX power or not */ + INT8 bta_dm_eir_inq_tx_power; /* Inquiry TX power */ + + UINT8 bta_dm_eir_flags; /* flags for EIR */ UINT8 bta_dm_eir_manufac_spec_len; /* length of manufacturer specific in bytes */ UINT8 *bta_dm_eir_manufac_spec; /* manufacturer specific */ - UINT8 bta_dm_eir_additional_len; /* length of additional data in bytes */ - UINT8 *bta_dm_eir_additional; /* additional data */ + UINT8 bta_dm_eir_url_len; /* length of URL in bytes */ + UINT8 *bta_dm_eir_url; /* URL data */ + + tBTA_DM_CONFIG_EIR_CBACK *config_eir_callback; /* callback */ } tBTA_DM_EIR_CONF; #if BLE_INCLUDED == TRUE @@ -1450,6 +1461,18 @@ extern void BTA_DisableTestMode(void); *******************************************************************************/ extern void BTA_DmSetDeviceName(const char *p_name); +/******************************************************************************* +** +** Function BTA_DmConfigEir +** +** Description This function config EIR data of the local device. +** +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmConfigEir(tBTA_DM_EIR_CONF *eir_config); + extern void BTA_DmUpdateWhiteList(BOOLEAN add_remove, BD_ADDR remote_addr, tBLE_ADDR_TYPE addr_type, tBTA_ADD_WHITELIST_CBACK *add_wl_cb); extern void BTA_DmBleReadAdvTxPower(tBTA_CMPL_CB *cmpl_cb); @@ -2292,8 +2315,8 @@ extern void BTA_DmBleSetScanRspRaw (UINT8 *p_raw_scan_rsp, UINT32 raw_scan_rsp_l ** Returns None ** *******************************************************************************/ -extern void BTA_DmUpdateDuplicateExceptionalList(UINT8 subcode, UINT32 type, - BD_ADDR device_info, +extern void BTA_DmUpdateDuplicateExceptionalList(UINT8 subcode, UINT32 type, + BD_ADDR device_info, tBTA_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_CMPL_CBACK p_update_duplicate_exceptional_list_cback); /******************************************************************************* diff --git a/components/bt/bluedroid/bta/include/bta/bta_gap_bt_co.h b/components/bt/bluedroid/bta/include/bta/bta_gap_bt_co.h new file mode 100644 index 0000000000..9e030ec354 --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta/bta_gap_bt_co.h @@ -0,0 +1,29 @@ +// Copyright 2018 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. + + +/****************************************************************************** + * + * This is the interface file for BT GAP call-out functions. + * + ******************************************************************************/ +#ifndef BTA_GAP_BT_CO_H +#define BTA_GAP_BT_CO_H + +#if (BTC_GAP_BT_INCLUDED == TRUE) + +extern void btc_gap_bt_config_eir_cmpl_callback (uint8_t status, uint8_t eir_type_num, uint8_t *eir_type); + +#endif /// (BTC_GAP_BT_INCLUDED == TRUE) +#endif /// BTA_GAP_BT_CO_H \ No newline at end of file diff --git a/components/bt/bluedroid/btc/core/btc_util.c b/components/bt/bluedroid/btc/core/btc_util.c index 633b03c60d..4174a1152f 100644 --- a/components/bt/bluedroid/btc/core/btc_util.c +++ b/components/bt/bluedroid/btc/core/btc_util.c @@ -32,6 +32,7 @@ #endif ///BTA_AV_INCLUDED == TRUE #include "common/bt_defs.h" #include "stack/btm_api.h" +#include "bta/bta_api.h" /************************************************************************************ ** Constants & Macros @@ -246,3 +247,36 @@ esp_bt_status_t btc_btm_status_to_esp_status (uint8_t btm_status) return esp_status; } + +esp_bt_status_t btc_bta_status_to_esp_status (uint8_t bta_status) +{ + esp_bt_status_t esp_status = ESP_BT_STATUS_FAIL; + switch(bta_status){ + case BTA_SUCCESS: + esp_status = ESP_BT_STATUS_SUCCESS; + break; + case BTA_FAILURE: + esp_status = ESP_BT_STATUS_FAIL; + break; + case BTA_PENDING: + esp_status = ESP_BT_STATUS_PENDING; + break; + case BTA_BUSY: + esp_status = ESP_BT_STATUS_BUSY; + break; + case BTA_NO_RESOURCES: + esp_status = ESP_BT_STATUS_NOMEM; + break; + case BTA_WRONG_MODE: + esp_status = ESP_BT_STATUS_NOT_READY; + break; + case BTA_EIR_TOO_LARGE: + esp_status = ESP_BT_STATUS_EIR_TOO_LARGE; + break; + default: + esp_status = ESP_BT_STATUS_FAIL; + break; + } + + return esp_status; +} \ No newline at end of file diff --git a/components/bt/bluedroid/btc/include/btc/btc_util.h b/components/bt/bluedroid/btc/include/btc/btc_util.h index df44297c3b..bc0570dd37 100644 --- a/components/bt/bluedroid/btc/include/btc/btc_util.h +++ b/components/bt/bluedroid/btc/include/btc/btc_util.h @@ -46,5 +46,6 @@ void uuid_to_string_legacy(bt_uuid_t *p_uuid, char *str); esp_bt_status_t btc_hci_to_esp_status(uint8_t hci_status); esp_bt_status_t btc_btm_status_to_esp_status (uint8_t btm_status); +esp_bt_status_t btc_bta_status_to_esp_status (uint8_t bta_status); #endif /* __BTC_UTIL_H__ */ diff --git a/components/bt/bluedroid/btc/profile/std/gap/bta_gap_bt_co.c b/components/bt/bluedroid/btc/profile/std/gap/bta_gap_bt_co.c new file mode 100644 index 0000000000..9710dcfa7a --- /dev/null +++ b/components/bt/bluedroid/btc/profile/std/gap/bta_gap_bt_co.c @@ -0,0 +1,40 @@ +// Copyright 2018 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 +#include "btc_gap_bt.h" +#include "btc/btc_util.h" + +#if (BTC_GAP_BT_INCLUDED == TRUE) +void btc_gap_bt_config_eir_cmpl_callback (uint8_t status, uint8_t eir_type_num, uint8_t *eir_type) +{ + esp_bt_gap_cb_param_t param; + bt_status_t ret; + btc_msg_t msg; + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_GAP_BT; + msg.act = BTC_GAP_BT_CONFIG_EIR_DATA_EVT; + + param.config_eir_data.stat = btc_bta_status_to_esp_status(status); + param.config_eir_data.eir_type_num = eir_type_num; + memcpy(param.config_eir_data.eir_type, eir_type, eir_type_num); + + ret = btc_transfer_context(&msg, ¶m, + sizeof(esp_bt_gap_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__); + } +} +#endif /// (BTC_GAP_BT_INCLUDED == TRUE) \ No newline at end of file diff --git a/components/bt/bluedroid/btc/profile/std/gap/btc_gap_bt.c b/components/bt/bluedroid/btc/profile/std/gap/btc_gap_bt.c index 8de802f2ea..af2cfd2068 100644 --- a/components/bt/bluedroid/btc/profile/std/gap/btc_gap_bt.c +++ b/components/bt/bluedroid/btc/profile/std/gap/btc_gap_bt.c @@ -687,11 +687,27 @@ static void btc_gap_bt_ssp_passkey_reply(btc_gap_bt_args_t *arg) static void btc_gap_bt_ssp_confirm(btc_gap_bt_args_t *arg) { BTA_DmConfirm(arg->confirm_reply.bda.address, arg->confirm_reply.accept); - } #endif ///BT_SSP_INCLUDED == TRUE +static void btc_gap_bt_config_eir(btc_gap_bt_args_t *arg) +{ + tBTA_DM_EIR_CONF eir_config; + esp_bt_eir_data_t *eir_data = &arg->config_eir.eir_data; + + eir_config.bta_dm_eir_fec_required = eir_data->fec_required; + eir_config.bta_dm_eir_included_tx_power = eir_data->include_txpower; + eir_config.bta_dm_eir_included_uuid = eir_data->include_uuid; + eir_config.bta_dm_eir_flags = eir_data->flag; + eir_config.bta_dm_eir_manufac_spec_len = eir_data->manufacturer_len; + eir_config.bta_dm_eir_manufac_spec = eir_data->p_manufacturer_data; + eir_config.bta_dm_eir_url_len = eir_data->url_len; + eir_config.bta_dm_eir_url = eir_data->p_url; + + BTA_DmConfigEir(&eir_config); +} + void btc_gap_bt_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) { switch (msg->act) { @@ -712,13 +728,11 @@ void btc_gap_bt_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) break; case BTC_GAP_BT_ACT_SET_SECURITY_PARAM:{ btc_gap_bt_args_t *src = (btc_gap_bt_args_t *)p_src; - btc_gap_bt_args_t *dst = (btc_gap_bt_args_t *) p_dest; - uint8_t length = 0; + btc_gap_bt_args_t *dst = (btc_gap_bt_args_t *)p_dest; if (src->set_security_param.value) { - length = dst->set_security_param.len; - dst->set_security_param.value = osi_malloc(length); + dst->set_security_param.value = osi_malloc(src->set_security_param.len); if (dst->set_security_param.value != NULL) { - memcpy(dst->set_security_param.value, src->set_security_param.value, length); + memcpy(dst->set_security_param.value, src->set_security_param.value, src->set_security_param.len); } else { BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act); } @@ -726,6 +740,30 @@ void btc_gap_bt_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) break; } #endif ///BT_SSP_INCLUDED == TRUE + + case BTC_GAP_BT_ACT_CONFIG_EIR:{ + btc_gap_bt_args_t *src = (btc_gap_bt_args_t *)p_src; + btc_gap_bt_args_t *dst = (btc_gap_bt_args_t *)p_dest; + if (src->config_eir.eir_data.p_manufacturer_data) { + dst->config_eir.eir_data.p_manufacturer_data = osi_malloc(src->config_eir.eir_data.manufacturer_len); + if (dst->config_eir.eir_data.p_manufacturer_data != NULL) { + memcpy(dst->config_eir.eir_data.p_manufacturer_data, src->config_eir.eir_data.p_manufacturer_data, src->config_eir.eir_data.manufacturer_len); + } else { + dst->config_eir.eir_data.manufacturer_len = 0; + BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act); + } + } + if (src->config_eir.eir_data.p_url) { + dst->config_eir.eir_data.p_url = osi_malloc(src->config_eir.eir_data.url_len); + if (dst->config_eir.eir_data.p_url != NULL) { + memcpy(dst->config_eir.eir_data.p_url, src->config_eir.eir_data.p_url, src->config_eir.eir_data.url_len); + } else { + dst->config_eir.eir_data.url_len = 0; + BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act); + } + } + break; + } default: BTC_TRACE_ERROR("Unhandled deep copy %d\n", msg->act); break; @@ -752,9 +790,20 @@ void btc_gap_bt_arg_deep_free(btc_msg_t *msg) case BTC_GAP_BT_ACT_CONFIRM_REPLY: break; case BTC_GAP_BT_ACT_SET_SECURITY_PARAM: - osi_free(arg->set_security_param.value); + if (arg->set_security_param.value) { + osi_free(arg->set_security_param.value); + } break; #endif ///BT_SSP_INCLUDED == TRUE + + case BTC_GAP_BT_ACT_CONFIG_EIR: + if (arg->config_eir.eir_data.p_manufacturer_data) { + osi_free(arg->config_eir.eir_data.p_manufacturer_data); + } + if (arg->config_eir.eir_data.p_url) { + osi_free(arg->config_eir.eir_data.p_url); + } + break; default: BTC_TRACE_ERROR("Unhandled deep copy %d, arg: %p\n", msg->act, arg); break; @@ -820,7 +869,10 @@ void btc_gap_bt_call_handler(btc_msg_t *msg) break; } #endif ///BT_SSP_INCLUDED == TRUE - + case BTC_GAP_BT_ACT_CONFIG_EIR: { + btc_gap_bt_config_eir(arg); + break; + } default: break; } @@ -853,6 +905,7 @@ void btc_gap_bt_cb_deep_free(btc_msg_t *msg) osi_free(((tBTA_DM_SEARCH_PARAM *) (msg->arg)) ->p_data); break; case BTC_GAP_BT_READ_RSSI_DELTA_EVT: + case BTC_GAP_BT_CONFIG_EIR_DATA_EVT: case BTC_GAP_BT_AUTH_CMPL_EVT: case BTC_GAP_BT_PIN_REQ_EVT: #if (BT_SSP_INCLUDED == TRUE) @@ -886,6 +939,10 @@ void btc_gap_bt_cb_handler(btc_msg_t *msg) btc_gap_bt_cb_to_app(ESP_BT_GAP_READ_RSSI_DELTA_EVT, (esp_bt_gap_cb_param_t *)msg->arg); break; } + case BTC_GAP_BT_CONFIG_EIR_DATA_EVT: { + btc_gap_bt_cb_to_app(ESP_BT_GAP_CONFIG_EIR_DATA_EVT, (esp_bt_gap_cb_param_t *)msg->arg); + break; + } case BTC_GAP_BT_AUTH_CMPL_EVT:{ btc_gap_bt_cb_to_app(ESP_BT_GAP_AUTH_CMPL_EVT, (esp_bt_gap_cb_param_t *)msg->arg); break; diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_gap_bt.h b/components/bt/bluedroid/btc/profile/std/include/btc_gap_bt.h index 51e685965b..cae2a09bc1 100644 --- a/components/bt/bluedroid/btc/profile/std/include/btc_gap_bt.h +++ b/components/bt/bluedroid/btc/profile/std/include/btc_gap_bt.h @@ -32,6 +32,7 @@ typedef enum { BTC_GAP_BT_KEY_NOTIF_EVT, BTC_GAP_BT_KEY_REQ_EVT, BTC_GAP_BT_READ_RSSI_DELTA_EVT, + BTC_GAP_BT_CONFIG_EIR_DATA_EVT, }btc_gap_bt_evt_t; typedef enum { @@ -48,6 +49,7 @@ typedef enum { BTC_GAP_BT_ACT_SET_SECURITY_PARAM, BTC_GAP_BT_ACT_PASSKEY_REPLY, BTC_GAP_BT_ACT_CONFIRM_REPLY, + BTC_GAP_BT_ACT_CONFIG_EIR, } btc_gap_bt_act_t; /* btc_bt_gap_args_t */ @@ -124,6 +126,11 @@ typedef union { bt_bdaddr_t bda; bool accept; } confirm_reply; + + // BTC_GAP_BT_ACT_CONFIG_EIR + struct config_eir_args { + esp_bt_eir_data_t eir_data; + } config_eir; } btc_gap_bt_args_t; void btc_gap_bt_call_handler(btc_msg_t *msg); diff --git a/components/bt/bluedroid/common/include/common/bt_defs.h b/components/bt/bluedroid/common/include/common/bt_defs.h index 77719bc847..7cfa3d5b8e 100644 --- a/components/bt/bluedroid/common/include/common/bt_defs.h +++ b/components/bt/bluedroid/common/include/common/bt_defs.h @@ -88,6 +88,7 @@ typedef enum { BT_STATUS_PARAM_OUT_OF_RANGE, BT_STATUS_TIMEOUT, BT_STATUS_MEMORY_FULL, + BT_STATUS_EIR_TOO_LARGE, } bt_status_t; #ifndef CPU_LITTLE_ENDIAN diff --git a/components/bt/bluedroid/common/include/common/bt_target.h b/components/bt/bluedroid/common/include/common/bt_target.h index 98dbe7a16c..1745ab0dfa 100644 --- a/components/bt/bluedroid/common/include/common/bt_target.h +++ b/components/bt/bluedroid/common/include/common/bt_target.h @@ -151,13 +151,13 @@ #ifndef CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM #define BLE_ADV_REPORT_FLOW_CONTROL_NUM 100 -#else +#else #define BLE_ADV_REPORT_FLOW_CONTROL_NUM CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM #endif /* CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM */ #ifndef CONFIG_BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD #define BLE_ADV_REPORT_DISCARD_THRSHOLD 20 -#else +#else #define BLE_ADV_REPORT_DISCARD_THRSHOLD CONFIG_BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD #endif /* CONFIG_BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD */ @@ -1056,6 +1056,14 @@ #define BTM_BLE_ADV_TX_POWER {-12, -9, -6, -3, 0, 3, 6, 9} #endif +#ifndef BTM_TX_POWER +#define BTM_TX_POWER {-12, -9, -6, -3, 0, 3, 6, 9} +#endif + +#ifndef BTM_TX_POWER_LEVEL_MAX +#define BTM_TX_POWER_LEVEL_MAX 7 +#endif + #ifndef BLE_BATCH_SCAN_INCLUDED #define BLE_BATCH_SCAN_INCLUDED TRUE diff --git a/components/bt/bluedroid/stack/btm/btm_inq.c b/components/bt/bluedroid/stack/btm/btm_inq.c index 7feda0e6ab..4845ac5ab0 100644 --- a/components/bt/bluedroid/stack/btm/btm_inq.c +++ b/components/bt/bluedroid/stack/btm/btm_inq.c @@ -2387,16 +2387,17 @@ void btm_read_linq_tx_power_complete(UINT8 *p) ** ** Parameters p_buff - allocated HCI command buffer including extended ** inquriry response +** fec_required - FEC is required or not ** ** Returns BTM_SUCCESS - if successful ** BTM_MODE_UNSUPPORTED - if local device cannot support it ** *******************************************************************************/ -tBTM_STATUS BTM_WriteEIR( BT_HDR *p_buff ) +tBTM_STATUS BTM_WriteEIR( BT_HDR *p_buff, BOOLEAN fec_required) { if (controller_get_interface()->supports_extended_inquiry_response()) { BTM_TRACE_API("Write Extended Inquiry Response to controller\n"); - btsnd_hcic_write_ext_inquiry_response (p_buff, BTM_EIR_DEFAULT_FEC_REQUIRED); + btsnd_hcic_write_ext_inquiry_response (p_buff, fec_required); return BTM_SUCCESS; } else { osi_free(p_buff); diff --git a/components/bt/bluedroid/stack/include/stack/bt_types.h b/components/bt/bluedroid/stack/include/stack/bt_types.h index 52385cb513..f8b15919d2 100644 --- a/components/bt/bluedroid/stack/include/stack/bt_types.h +++ b/components/bt/bluedroid/stack/include/stack/bt_types.h @@ -446,6 +446,7 @@ typedef struct { #define BT_EIR_OOB_COD_TYPE 0x0D #define BT_EIR_OOB_SSP_HASH_C_TYPE 0x0E #define BT_EIR_OOB_SSP_RAND_R_TYPE 0x0F +#define BT_EIR_URL_TYPE 0x24 #define BT_EIR_MANUFACTURER_SPECIFIC_TYPE 0xFF #define BT_OOB_COD_SIZE 3 diff --git a/components/bt/bluedroid/stack/include/stack/btm_api.h b/components/bt/bluedroid/stack/include/stack/btm_api.h index 6aa833c036..9667b4c76d 100644 --- a/components/bt/bluedroid/stack/include/stack/btm_api.h +++ b/components/bt/bluedroid/stack/include/stack/btm_api.h @@ -540,8 +540,11 @@ typedef UINT8 tBTM_EIR_SEARCH_RESULT; #define BTM_EIR_SHORTENED_LOCAL_NAME_TYPE HCI_EIR_SHORTENED_LOCAL_NAME_TYPE /* 0x08 */ #define BTM_EIR_COMPLETE_LOCAL_NAME_TYPE HCI_EIR_COMPLETE_LOCAL_NAME_TYPE /* 0x09 */ #define BTM_EIR_TX_POWER_LEVEL_TYPE HCI_EIR_TX_POWER_LEVEL_TYPE /* 0x0A */ +#define BTM_EIR_URL_TYPE HCI_EIR_URL_TYPE /* 0x24 */ #define BTM_EIR_MANUFACTURER_SPECIFIC_TYPE HCI_EIR_MANUFACTURER_SPECIFIC_TYPE /* 0xFF */ +#define BTM_EIR_TYPE_MAX_NUM 12 /* Max EIR types */ + /* the following EIR tags are defined to OOB, not regular EIR data */ #define BTM_EIR_OOB_BD_ADDR_TYPE HCI_EIR_OOB_BD_ADDR_TYPE /* 6 bytes */ #define BTM_EIR_OOB_COD_TYPE HCI_EIR_OOB_COD_TYPE /* 3 bytes */ @@ -3867,13 +3870,14 @@ tBTM_STATUS BTM_DeleteStoredLinkKey(BD_ADDR bd_addr, tBTM_CMPL_CB *p_cb); ** ** Parameters p_buff - allocated HCI command buffer including extended ** inquriry response +** fec_required - FEC is required or not ** ** Returns BTM_SUCCESS - if successful ** BTM_MODE_UNSUPPORTED - if local device cannot support it ** *******************************************************************************/ //extern -tBTM_STATUS BTM_WriteEIR( BT_HDR *p_buff ); +tBTM_STATUS BTM_WriteEIR( BT_HDR *p_buff, BOOLEAN fec_required); /******************************************************************************* ** diff --git a/components/bt/bluedroid/stack/include/stack/hcidefs.h b/components/bt/bluedroid/stack/include/stack/hcidefs.h index 6249f2c395..b1b73efa78 100644 --- a/components/bt/bluedroid/stack/include/stack/hcidefs.h +++ b/components/bt/bluedroid/stack/include/stack/hcidefs.h @@ -1139,6 +1139,7 @@ #define HCI_EIR_SHORTENED_LOCAL_NAME_TYPE BT_EIR_SHORTENED_LOCAL_NAME_TYPE #define HCI_EIR_COMPLETE_LOCAL_NAME_TYPE BT_EIR_COMPLETE_LOCAL_NAME_TYPE #define HCI_EIR_TX_POWER_LEVEL_TYPE BT_EIR_TX_POWER_LEVEL_TYPE +#define HCI_EIR_URL_TYPE BT_EIR_URL_TYPE #define HCI_EIR_MANUFACTURER_SPECIFIC_TYPE BT_EIR_MANUFACTURER_SPECIFIC_TYPE #define HCI_EIR_OOB_BD_ADDR_TYPE BT_EIR_OOB_BD_ADDR_TYPE #define HCI_EIR_OOB_COD_TYPE BT_EIR_OOB_COD_TYPE From c8d967417c50728a7ed9e77f903d062457cc0702 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Wed, 5 Jun 2019 14:43:23 +0800 Subject: [PATCH 008/486] bootloader: remove duplicate region overlap logic (MINOR CHANGE) --- components/bootloader_support/include/bootloader_util.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/bootloader_support/include/bootloader_util.h b/components/bootloader_support/include/bootloader_util.h index 30f8bd8d2c..500498d397 100644 --- a/components/bootloader_support/include/bootloader_util.h +++ b/components/bootloader_support/include/bootloader_util.h @@ -29,6 +29,7 @@ static inline bool bootloader_util_regions_overlap( const intptr_t start1, const intptr_t end1, const intptr_t start2, const intptr_t end2) { - return (end1 > start2 && end2 > start1) || - !(end1 <= start2 || end2 <= start1); + assert(end1>start1); + assert(end2>start2); + return (end1 > start2 && end2 > start1); } From 7a6ff35a2ae055781438e2b72c8e1e9a000035c5 Mon Sep 17 00:00:00 2001 From: Sergei Silnov Date: Mon, 3 Jun 2019 12:37:52 +0200 Subject: [PATCH 009/486] idf.py: Add check for new cmake cache values --- tools/idf.py | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/tools/idf.py b/tools/idf.py index c9a3e464ee..8184fdd708 100755 --- a/tools/idf.py +++ b/tools/idf.py @@ -150,6 +150,32 @@ def detect_cmake_generator(): raise FatalError("To use %s, either the 'ninja' or 'GNU make' build tool must be available in the PATH" % PROG) +def _strip_quotes(value, regexp=re.compile(r"^\"(.*)\"$|^'(.*)'$|^(.*)$")): + """ + Strip quotes like CMake does during parsing cache entries + """ + + return [x for x in regexp.match(value).groups() if x is not None][0].rstrip() + + +def _new_cmakecache_entries(cache_path, new_cache_entries): + if not os.path.exists(cache_path): + return True + + current_cache = parse_cmakecache(cache_path) + + if new_cache_entries: + current_cache = parse_cmakecache(cache_path) + + for entry in new_cache_entries: + key, value = entry.split("=", 1) + current_value = current_cache.get(key, None) + if current_value is None or _strip_quotes(value) != current_value: + return True + + return False + + def _ensure_build_directory(args, always_run_cmake=False): """Check the build directory exists and that cmake has been run there. @@ -175,7 +201,8 @@ def _ensure_build_directory(args, always_run_cmake=False): if not os.path.isdir(build_dir): os.makedirs(build_dir) cache_path = os.path.join(build_dir, "CMakeCache.txt") - if not os.path.exists(cache_path) or always_run_cmake: + + if always_run_cmake or _new_cmakecache_entries(cache_path, args.define_cache_entry): if args.generator is None: args.generator = detect_cmake_generator() try: @@ -230,7 +257,7 @@ def parse_cmakecache(path): for line in f: # cmake cache lines look like: CMAKE_CXX_FLAGS_DEBUG:STRING=-g # groups are name, type, value - m = re.match(r"^([^#/:=]+):([^:=]+)=(.+)\n$", line) + m = re.match(r"^([^#/:=]+):([^:=]+)=(.*)\n$", line) if m: result[m.group(1)] = m.group(3) return result From 2503af2464a41fe21a98ee21381cf28d915e2c1b Mon Sep 17 00:00:00 2001 From: xiehang Date: Wed, 29 May 2019 11:52:51 +0800 Subject: [PATCH 010/486] wps: add overlap event modify some header files to be consistent with vnc --- components/esp_event/event_send_compat.inc | 5 +++++ components/esp_event/include/esp_event_legacy.h | 1 + components/esp_wifi/include/esp_wifi_types.h | 1 + components/esp_wifi/lib_esp32 | 2 +- .../wpa_supplicant/include/wpa2/eap_peer/eap_i.h | 10 ++++++++-- components/wpa_supplicant/include/wps/wps.h | 6 +++--- 6 files changed, 19 insertions(+), 6 deletions(-) diff --git a/components/esp_event/event_send_compat.inc b/components/esp_event/event_send_compat.inc index 42b4daf473..eff799975b 100644 --- a/components/esp_event/event_send_compat.inc +++ b/components/esp_event/event_send_compat.inc @@ -80,6 +80,7 @@ esp_err_t esp_event_send_to_default_loop(system_event_t *event) HANDLE_SYS_EVENT(WIFI, STA_WPS_ER_TIMEOUT); HANDLE_SYS_EVENT_ARG(WIFI, STA_WPS_ER_FAILED, sta_er_fail_reason); HANDLE_SYS_EVENT_ARG(WIFI, STA_WPS_ER_PIN, sta_er_pin); + HANDLE_SYS_EVENT(WIFI, STA_WPS_ER_PBC_OVERLAP); /* AP events */ HANDLE_SYS_EVENT(WIFI, AP_START); @@ -233,6 +234,10 @@ static void esp_system_event_debug(const system_event_t* event) ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_PIN"); break; } + case SYSTEM_EVENT_STA_WPS_ER_PBC_OVERLAP: { + ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_PBC_OVERLAP"); + break; + } case SYSTEM_EVENT_AP_START: { ESP_LOGD(TAG, "SYSTEM_EVENT_AP_START"); break; diff --git a/components/esp_event/include/esp_event_legacy.h b/components/esp_event/include/esp_event_legacy.h index 7748f69a0d..44e95546a1 100644 --- a/components/esp_event/include/esp_event_legacy.h +++ b/components/esp_event/include/esp_event_legacy.h @@ -40,6 +40,7 @@ typedef enum { SYSTEM_EVENT_STA_WPS_ER_FAILED, /*!< ESP32 station wps fails in enrollee mode */ SYSTEM_EVENT_STA_WPS_ER_TIMEOUT, /*!< ESP32 station wps timeout in enrollee mode */ SYSTEM_EVENT_STA_WPS_ER_PIN, /*!< ESP32 station wps pin code in enrollee mode */ + SYSTEM_EVENT_STA_WPS_ER_PBC_OVERLAP, /*!< ESP32 station wps overlap in enrollee mode */ SYSTEM_EVENT_AP_START, /*!< ESP32 soft-AP start */ SYSTEM_EVENT_AP_STOP, /*!< ESP32 soft-AP stop */ SYSTEM_EVENT_AP_STACONNECTED, /*!< a station connected to ESP32 soft-AP */ diff --git a/components/esp_wifi/include/esp_wifi_types.h b/components/esp_wifi/include/esp_wifi_types.h index 8e930c555d..426ba7f58a 100644 --- a/components/esp_wifi/include/esp_wifi_types.h +++ b/components/esp_wifi/include/esp_wifi_types.h @@ -508,6 +508,7 @@ typedef enum { WIFI_EVENT_STA_WPS_ER_FAILED, /**< ESP32 station wps fails in enrollee mode */ WIFI_EVENT_STA_WPS_ER_TIMEOUT, /**< ESP32 station wps timeout in enrollee mode */ WIFI_EVENT_STA_WPS_ER_PIN, /**< ESP32 station wps pin code in enrollee mode */ + WIFI_EVENT_STA_WPS_ER_PBC_OVERLAP, /**< ESP32 station wps overlap in enrollee mode */ WIFI_EVENT_AP_START, /**< ESP32 soft-AP start */ WIFI_EVENT_AP_STOP, /**< ESP32 soft-AP stop */ diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index b8b96f985a..fc518f822e 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit b8b96f985aee155682a2907c6c0f3b693bb43785 +Subproject commit fc518f822e23b6f4fd8870d61cb1dba107727df2 diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_i.h b/components/wpa_supplicant/include/wpa2/eap_peer/eap_i.h index 6204f46538..401d3687a9 100644 --- a/components/wpa_supplicant/include/wpa2/eap_peer/eap_i.h +++ b/components/wpa_supplicant/include/wpa2/eap_peer/eap_i.h @@ -98,6 +98,13 @@ struct eap_method { #define BLOB_NAME_LEN 3 #define BLOB_NUM 3 +enum SIG_WPA2 { + SIG_WPA2_START = 0, + SIG_WPA2_RX, + SIG_WPA2_TASK_DEL, + SIG_WPA2_MAX, +}; + /** * struct eap_sm - EAP state machine data */ @@ -114,8 +121,7 @@ struct eap_sm { u8 current_identifier; u8 ownaddr[ETH_ALEN]; #ifdef USE_WPA2_TASK -#define SIG_WPA2_NUM 2 - u8 wpa2_sig_cnt[SIG_WPA2_NUM]; + u8 wpa2_sig_cnt[SIG_WPA2_MAX]; #endif u8 finish_state; diff --git a/components/wpa_supplicant/include/wps/wps.h b/components/wpa_supplicant/include/wps/wps.h index 4254495741..7249d6eee8 100644 --- a/components/wpa_supplicant/include/wps/wps.h +++ b/components/wpa_supplicant/include/wps/wps.h @@ -1009,9 +1009,9 @@ enum wps_cb_status { typedef void (*wps_st_cb_t)(int status); #ifdef USE_WPS_TASK -#define SIG_WPS_START 0 -#define SIG_WPS_RX 1 -#define SIG_WPS_NUM 2 +#define SIG_WPS_START 2 +#define SIG_WPS_RX 3 +#define SIG_WPS_NUM 9 #endif #define WPS_EAP_EXT_VENDOR_TYPE "WFA-SimpleConfig-Enrollee-1-0" From 5f5428233e969f87e99d70f01a066d9878f48b9e Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 5 Jun 2019 12:58:27 +1000 Subject: [PATCH 011/486] partition table: Update documentation about "test" partition type Reported from forum: https://esp32.com/viewtopic.php?f=13&t=10777&p=44164#p44164 --- docs/en/api-guides/bootloader.rst | 6 ++++-- docs/en/api-guides/partition-tables.rst | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/en/api-guides/bootloader.rst b/docs/en/api-guides/bootloader.rst index 6e5efbcc04..aea98d6c91 100644 --- a/docs/en/api-guides/bootloader.rst +++ b/docs/en/api-guides/bootloader.rst @@ -42,13 +42,15 @@ Partition table.:: ota_0, 0, ota_0, , 512K ota_1, 0, ota_1, , 512K +.. _bootloader_boot_from_test_firmware: + Boot from TEST firmware ------------------------ The user can write a special firmware for testing in production, and run it as needed. The partition table also needs a dedicated partition for this testing firmware (See `partition table`). To trigger a test app you need to set :ref:`CONFIG_BOOTLOADER_APP_TEST`. -:ref:`CONFIG_BOOTLOADER_NUM_PIN_APP_TEST` - number of the GPIO input to boot TEST partition. The selected GPIO will be configured as an input with internal pull-up enabled. To trigger a test app, this GPIO must be pulled low on reset. -After the GPIO input is deactivated and the device reboots, the old application will boot (factory or any OTA slot). +:ref:`CONFIG_BOOTLOADER_NUM_PIN_APP_TEST` - GPIO number to boot TEST partition. The selected GPIO will be configured as an input with internal pull-up enabled. To trigger a test app, this GPIO must be pulled low on reset. +After the GPIO input is deactivated and the device reboots, the normally configured application will boot (factory or any OTA slot). :ref:`CONFIG_BOOTLOADER_HOLD_TIME_GPIO` - this is hold time of GPIO for reset/test mode (by default 5 seconds). The GPIO must be held low continuously for this period of time after reset before a factory reset or test partition boot (as applicable) is performed. diff --git a/docs/en/api-guides/partition-tables.rst b/docs/en/api-guides/partition-tables.rst index 502c7118c9..f538a507b9 100644 --- a/docs/en/api-guides/partition-tables.rst +++ b/docs/en/api-guides/partition-tables.rst @@ -92,7 +92,7 @@ The 8-bit subtype field is specific to a given partition type. esp-idf currently - OTA never updates the factory partition. - If you want to conserve flash usage in an OTA project, you can remove the factory partition and use ota_0 instead. - ota_0 (0x10) ... ota_15 (0x1F) are the OTA app slots. Refer to the :doc:`OTA documentation <../api-reference/system/ota>` for more details, which then use the OTA data partition to configure which app slot the bootloader should boot. If using OTA, an application should have at least two OTA application slots (ota_0 & ota_1). Refer to the :doc:`OTA documentation <../api-reference/system/ota>` for more details. - - test (0x2) is a reserved subtype for factory test procedures. It is not currently supported by the esp-idf bootloader. + - test (0x20) is a reserved subtype for factory test procedures. It will be used as the fallback boot partition if no other valid app partition is found. It is also possible to configure the bootloader to read a GPIO input during each boot, and boot this partition if the GPIO is held low, see :ref:`bootloader_boot_from_test_firmware`. * When type is "data", the subtype field can be specified as ota (0), phy (1), nvs (2), or nvs_keys (4). From 912c75372ccd1fab272d0edf932d343e8d4589a2 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Fri, 7 Jun 2019 19:57:47 +0800 Subject: [PATCH 012/486] confgen.py: don't output compatibility definitions for options which are not defined MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For example, if a renamed option CONFIG_NEW is a bool with value “n”, kconfiglib will not generate a define for it in the Kconfig file. The define (#define CONFIG_NEW 1) will only be generated if the option is “y” or “m”. However the compatibility definition was always generated: #define CONFIG_OLD CONFIG_NEW. This broke the #ifdef checks which depended on the old option names. This commit wraps each compatibility definition: #ifdef CONFIG_NEW #define CONFIG_OLD CONFIG_NEW #endif so that the CONFIG_OLD definition is only generated if CONFIG_NEW is defined. --- tools/kconfig_new/confgen.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/kconfig_new/confgen.py b/tools/kconfig_new/confgen.py index 4ea0331772..bbd4e28042 100755 --- a/tools/kconfig_new/confgen.py +++ b/tools/kconfig_new/confgen.py @@ -167,7 +167,8 @@ class DeprecatedOptions(object): f_o.write('\n/* List of deprecated options */\n') for dep_opt in sorted(self.r_dic): new_opt = self.r_dic[dep_opt] - f_o.write('#define {}{} {}{}\n'.format(self.config_prefix, dep_opt, self.config_prefix, new_opt)) + f_o.write('#ifdef {}{}\n#define {}{} {}{}\n#endif\n\n'.format(self.config_prefix, new_opt, + self.config_prefix, dep_opt, self.config_prefix, new_opt)) def main(): From f3aab7d5362b0c78b093299b1fac62cc28ef688a Mon Sep 17 00:00:00 2001 From: baohongde Date: Mon, 10 Jun 2019 15:14:23 +0800 Subject: [PATCH 013/486] components/bt: Fix assert due to alloc LMP TX buffer failed --- components/bt/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/lib b/components/bt/lib index 6834a6bfcf..45df297ff2 160000 --- a/components/bt/lib +++ b/components/bt/lib @@ -1 +1 @@ -Subproject commit 6834a6bfcfd395acc37249fae1c3121fc2e705cb +Subproject commit 45df297ff295c106171d8c3621216e9f48f7d8b4 From af3a2f3aba049341518c597f624705753255cb21 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Mon, 10 Jun 2019 18:19:15 +0800 Subject: [PATCH 014/486] esp_event: fix placement issue when building with make The CMake build uses the linker fragment file to place functions in IRAM on certain configurations. This commit does that for Make as well. --- components/esp_event/component.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esp_event/component.mk b/components/esp_event/component.mk index c59eccc41a..828cb6abac 100644 --- a/components/esp_event/component.mk +++ b/components/esp_event/component.mk @@ -4,6 +4,7 @@ COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_PRIV_INCLUDEDIRS := private_include COMPONENT_SRCDIRS := . +COMPONENT_ADD_LDFRAGMENTS := linker.lf ifdef CONFIG_ESP_EVENT_LOOP_PROFILING PROFILING_ENABLED := 1 From 243e0b229fc6aab97101cd6bac6471283e6b6b56 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 31 May 2019 15:37:51 +0200 Subject: [PATCH 015/486] tcp_transport: fix minor memory leak found by static analyzer Closes https://github.com/espressif/esp-idf/issues/3602 --- components/tcp_transport/transport_ws.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/tcp_transport/transport_ws.c b/components/tcp_transport/transport_ws.c index e31149e178..43f0bdd360 100644 --- a/components/tcp_transport/transport_ws.c +++ b/components/tcp_transport/transport_ws.c @@ -296,7 +296,10 @@ esp_transport_handle_t esp_transport_ws_init(esp_transport_handle_t parent_handl ws->parent = parent_handle; ws->path = strdup("/"); - ESP_TRANSPORT_MEM_CHECK(TAG, ws->path, return NULL); + ESP_TRANSPORT_MEM_CHECK(TAG, ws->path, { + free(ws); + return NULL; + }); ws->buffer = malloc(DEFAULT_WS_BUFFER); ESP_TRANSPORT_MEM_CHECK(TAG, ws->buffer, { free(ws->path); From bd537083d92fc8881d62a48eeacb178bdfb4bdc7 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 31 May 2019 11:23:02 +0200 Subject: [PATCH 016/486] esp_event: fix possible malloc free issues found by static analyzer --- components/esp_event/esp_event.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/components/esp_event/esp_event.c b/components/esp_event/esp_event.c index b51a74cb50..99a3cf70bb 100644 --- a/components/esp_event/esp_event.c +++ b/components/esp_event/esp_event.c @@ -212,7 +212,7 @@ static esp_err_t base_node_add_handler(esp_event_base_node_t* base_node, int32_t id_node = (esp_event_id_node_t*) calloc(1, sizeof(*id_node)); if (!id_node) { - ESP_LOGI(TAG, "alloc for new id node failed"); + ESP_LOGE(TAG, "alloc for new id node failed"); return ESP_ERR_NO_MEM; } @@ -229,6 +229,8 @@ static esp_err_t base_node_add_handler(esp_event_base_node_t* base_node, int32_t else { SLIST_INSERT_AFTER(last_id_node, id_node, next); } + } else { + free(id_node); } return err; @@ -280,6 +282,8 @@ static esp_err_t loop_node_add_handler(esp_event_loop_node_t* loop_node, esp_eve else { SLIST_INSERT_AFTER(last_base_node, base_node, next); } + } else { + free(base_node); } return err; @@ -414,7 +418,7 @@ esp_err_t esp_event_loop_create(const esp_event_loop_args_t* event_loop_args, es loop = calloc(1, sizeof(*loop)); if (loop == NULL) { ESP_LOGE(TAG, "alloc for event loop failed"); - goto on_err; + return err; } loop->queue = xQueueCreate(event_loop_args->queue_size , sizeof(esp_event_post_instance_t)); @@ -692,6 +696,8 @@ esp_err_t esp_event_handler_register_with(esp_event_loop_handle_t event_loop, es else { SLIST_INSERT_AFTER(last_loop_node, loop_node, next); } + } else { + free(loop_node); } } else { From c34de4cba658e8331f8a3ab2f466190c7640595b Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 29 May 2019 17:07:39 +0200 Subject: [PATCH 017/486] mdns: fix static analysis warnings --- components/mdns/mdns.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index e88672f82b..ad3dfb49e5 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -1312,6 +1312,7 @@ static mdns_tx_packet_t * _mdns_create_probe_packet(tcpip_adapter_if_t tcpip_if, q->domain = MDNS_DEFAULT_DOMAIN; if (!q->host || _mdns_question_exists(q, packet->questions)) { free(q); + continue; } else { queueToEnd(mdns_out_question_t, packet->questions, q); } @@ -2801,7 +2802,7 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) col = 1; } else if (!clas) { col = -1; - } else { + } else if (service) { // only detect srv collision if service existed col = _mdns_check_srv_collision(service->service, priority, weight, port, name->host, name->domain); } if (col && (parsed_packet->probe || parsed_packet->authoritative)) { @@ -3831,23 +3832,25 @@ static void _mdns_execute_action(mdns_action_t * action) break; case ACTION_SERVICE_DEL: a = _mdns_server->services; - if (_mdns_server->services == action->data.srv_del.service) { - _mdns_server->services = a->next; - _mdns_send_bye(&a, 1, false); - _mdns_remove_scheduled_service_packets(a->service); - _mdns_free_service(a->service); - free(a); - } else { - while (a->next && a->next != action->data.srv_del.service) { - a = a->next; - } - if (a->next == action->data.srv_del.service) { - mdns_srv_item_t * b = a->next; - a->next = a->next->next; - _mdns_send_bye(&b, 1, false); - _mdns_remove_scheduled_service_packets(b->service); - _mdns_free_service(b->service); - free(b); + if (action->data.srv_del.service) { + if (_mdns_server->services == action->data.srv_del.service) { + _mdns_server->services = a->next; + _mdns_send_bye(&a, 1, false); + _mdns_remove_scheduled_service_packets(a->service); + _mdns_free_service(a->service); + free(a); + } else { + while (a->next && a->next != action->data.srv_del.service) { + a = a->next; + } + if (a->next == action->data.srv_del.service) { + mdns_srv_item_t * b = a->next; + a->next = a->next->next; + _mdns_send_bye(&b, 1, false); + _mdns_remove_scheduled_service_packets(b->service); + _mdns_free_service(b->service); + free(b); + } } } From e08b787d790bf43fe733e94d5e2cace54ea91ed1 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 11 Jun 2019 10:15:42 +1000 Subject: [PATCH 018/486] ci: Adjust the test_confserver timeout to 2 seconds On a VM, it seems like 500ms is sometimes a very short time... --- tools/kconfig_new/test/test_confserver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/kconfig_new/test/test_confserver.py b/tools/kconfig_new/test/test_confserver.py index d5da31913c..20fce7e031 100755 --- a/tools/kconfig_new/test/test_confserver.py +++ b/tools/kconfig_new/test/test_confserver.py @@ -51,7 +51,7 @@ def main(): cmdline = "../confserver.py --kconfig Kconfig --config %s" % temp_sdkconfig_path print("Running: %s" % cmdline) - p = pexpect.spawn(cmdline, timeout=0.5) + p = pexpect.spawn(cmdline, timeout=2) p.logfile = args.logfile p.setecho(False) From 63bd57c1d72b1c1c4f0742eeccf36d383df2da0f Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Mon, 27 May 2019 11:07:54 +0800 Subject: [PATCH 019/486] partition_table: implement Python API for parttool Closes https://github.com/espressif/esp-idf/issues/1494 --- components/partition_table/Makefile.projbuild | 20 +- .../partition_table/gen_empty_partition.py | 64 ++++ components/partition_table/parttool.py | 359 +++++++++--------- .../partition_table/project_include.cmake | 2 +- .../gen_esp32part_tests.py | 28 +- components/spiffs/Makefile.projbuild | 8 +- docs/en/api-guides/partition-tables.rst | 96 +++++ tools/ci/executable-list.txt | 1 + 8 files changed, 373 insertions(+), 205 deletions(-) create mode 100644 components/partition_table/gen_empty_partition.py diff --git a/components/partition_table/Makefile.projbuild b/components/partition_table/Makefile.projbuild index 1785ad811e..353a7655d6 100644 --- a/components/partition_table/Makefile.projbuild +++ b/components/partition_table/Makefile.projbuild @@ -63,16 +63,16 @@ $(PARTITION_TABLE_BIN_UNSIGNED): $(PARTITION_TABLE_CSV_PATH) $(SDKCONFIG_MAKEFIL all_binaries: $(PARTITION_TABLE_BIN) partition_table_get_info check_table_contents partition_table_get_info: $(PARTITION_TABLE_BIN) - $(eval PHY_DATA_OFFSET:=$(shell $(GET_PART_INFO) --partition-type data --partition-subtype phy \ - --partition-table-file $(PARTITION_TABLE_BIN) get_partition_info --info offset)) - $(eval APP_OFFSET:=$(shell $(GET_PART_INFO) --partition-boot-default \ - --partition-table-file $(PARTITION_TABLE_BIN) get_partition_info --info offset)) - $(eval OTA_DATA_OFFSET:=$(shell $(GET_PART_INFO) --partition-type data --partition-subtype ota \ - --partition-table-file $(PARTITION_TABLE_BIN) get_partition_info --info offset)) - $(eval OTA_DATA_SIZE:=$(shell $(GET_PART_INFO) --partition-type data --partition-subtype ota \ - --partition-table-file $(PARTITION_TABLE_BIN) get_partition_info --info size)) - $(eval FACTORY_OFFSET:=$(shell $(GET_PART_INFO) --partition-type app --partition-subtype factory \ - --partition-table-file $(PARTITION_TABLE_BIN) get_partition_info --info offset)) + $(eval PHY_DATA_OFFSET:=$(shell $(GET_PART_INFO) --partition-table-file $(PARTITION_TABLE_BIN) \ + get_partition_info --partition-type data --partition-subtype phy --info offset)) + $(eval APP_OFFSET:=$(shell $(GET_PART_INFO) --partition-table-file $(PARTITION_TABLE_BIN) \ + get_partition_info --partition-boot-default --info offset)) + $(eval OTA_DATA_OFFSET:=$(shell $(GET_PART_INFO) --partition-table-file $(PARTITION_TABLE_BIN) \ + get_partition_info --partition-type data --partition-subtype ota --info offset)) + $(eval OTA_DATA_SIZE:=$(shell $(GET_PART_INFO) --partition-table-file $(PARTITION_TABLE_BIN) \ + get_partition_info --partition-type data --partition-subtype ota --info size)) + $(eval FACTORY_OFFSET:=$(shell $(GET_PART_INFO) --partition-table-file $(PARTITION_TABLE_BIN) \ + get_partition_info --partition-type app --partition-subtype factory --info offset)) export APP_OFFSET export PHY_DATA_OFFSET diff --git a/components/partition_table/gen_empty_partition.py b/components/partition_table/gen_empty_partition.py new file mode 100644 index 0000000000..f65f74d706 --- /dev/null +++ b/components/partition_table/gen_empty_partition.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# +# generates an empty binary file +# +# This tool generates an empty binary file of the required size. +# +# Copyright 2018 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. +from __future__ import print_function, division +from __future__ import unicode_literals +import argparse +import sys + +__version__ = '1.0' + +quiet = False + + +def generate_blanked_file(size, output_path): + output = b"\xFF" * size + try: + stdout_binary = sys.stdout.buffer # Python 3 + except AttributeError: + stdout_binary = sys.stdout + with stdout_binary if output_path == '-' else open(output_path, 'wb') as f: + f.write(output) + + +def main(): + parser = argparse.ArgumentParser(description='Generates an empty binary file of the required size.') + parser.add_argument('size', help='Size of generated the file', type=str) + + parser.add_argument('output', help='Path for binary file.', nargs='?', default='-') + args = parser.parse_args() + + size = int(args.size, 0) + if size > 0: + generate_blanked_file(size, args.output) + return 0 + + +class InputError(RuntimeError): + def __init__(self, e): + super(InputError, self).__init__(e) + + +if __name__ == '__main__': + try: + r = main() + sys.exit(r) + except InputError as e: + print(e, file=sys.stderr) + sys.exit(2) diff --git a/components/partition_table/parttool.py b/components/partition_table/parttool.py index 14fcdf4fe7..f2c005a10c 100755 --- a/components/partition_table/parttool.py +++ b/components/partition_table/parttool.py @@ -24,193 +24,165 @@ import subprocess import tempfile import gen_esp32part as gen -__version__ = '1.0' -IDF_COMPONENTS_PATH = os.path.expandvars(os.path.join("$IDF_PATH", "components")) +__version__ = '2.0' + +COMPONENTS_PATH = os.path.expandvars(os.path.join("$IDF_PATH", "components")) +ESPTOOL_PY = os.path.join(COMPONENTS_PATH, "esptool_py", "esptool", "esptool.py") + +PARTITION_TABLE_OFFSET = 0x8000 -ESPTOOL_PY = os.path.join(IDF_COMPONENTS_PATH, "esptool_py", "esptool", "esptool.py") quiet = False def status(msg): - """ Print status message to stderr """ if not quiet: print(msg) -def _invoke_esptool(esptool_args, args): - m_esptool_args = [sys.executable, ESPTOOL_PY] +class _PartitionId(): - if args.port != "": - m_esptool_args.extend(["--port", args.port]) - - m_esptool_args.extend(esptool_args) - - if quiet: - with open(os.devnull, "w") as fnull: - subprocess.check_call(m_esptool_args, stdout=fnull, stderr=fnull) - else: - subprocess.check_call(m_esptool_args) + def __init__(self, name=None, type=None, subtype=None): + self.name = name + self.type = type + self.subtype = subtype -def _get_partition_table(args): - partition_table = None +class PartitionName(_PartitionId): - gen.offset_part_table = int(args.partition_table_offset, 0) - - if args.partition_table_file: - status("Reading partition table from partition table file...") - - try: - with open(args.partition_table_file, "rb") as partition_table_file: - partition_table = gen.PartitionTable.from_binary(partition_table_file.read()) - status("Partition table read from binary file {}".format(partition_table_file.name)) - except (gen.InputError, TypeError): - with open(args.partition_table_file, "r") as partition_table_file: - partition_table_file.seek(0) - partition_table = gen.PartitionTable.from_csv(partition_table_file.read()) - status("Partition table read from CSV file {}".format(partition_table_file.name)) - else: - port_info = (" on port " + args.port if args.port else "") - status("Reading partition table from device{}...".format(port_info)) - - f_name = None - with tempfile.NamedTemporaryFile(delete=False) as f: - f_name = f.name - - try: - invoke_args = ["read_flash", str(gen.offset_part_table), str(gen.MAX_PARTITION_LENGTH), f_name] - _invoke_esptool(invoke_args, args) - with open(f_name, "rb") as f: - partition_table = gen.PartitionTable.from_binary(f.read()) - status("Partition table read from device" + port_info) - finally: - os.unlink(f_name) - - return partition_table + def __init__(self, name): + _PartitionId.__init__(self, name=name) -def _get_partition(args): - partition_table = _get_partition_table(args) +class PartitionType(_PartitionId): - partition = None - - if args.partition_name: - partition = partition_table.find_by_name(args.partition_name) - elif args.partition_type and args.partition_subtype: - partition = partition_table.find_by_type(args.partition_type, args.partition_subtype) - elif args.partition_boot_default: - search = ["factory"] + ["ota_{}".format(d) for d in range(16)] - for subtype in search: - partition = partition_table.find_by_type("app", subtype) - if partition is not None: - break - else: - raise RuntimeError("Invalid partition selection arguments. Specify --partition-name OR \ - --partition-type and --partition-subtype OR --partition--boot-default.") - - if partition: - status("Found partition {}".format(str(partition))) - - return partition + def __init__(self, type, subtype): + _PartitionId.__init__(self, type=type, subtype=subtype) -def _get_and_check_partition(args): - partition = None - - partition = _get_partition(args) - - if not partition: - raise RuntimeError("Unable to find specified partition.") - - return partition +PARTITION_BOOT_DEFAULT = _PartitionId() -def write_partition(args): - erase_partition(args) +class ParttoolTarget(): - partition = _get_and_check_partition(args) + def __init__(self, port=None, partition_table_offset=PARTITION_TABLE_OFFSET, partition_table_file=None): + self.port = port - status("Checking input file size...") + gen.offset_part_table = partition_table_offset - with open(args.input, "rb") as input_file: - content_len = len(input_file.read()) - - if content_len != partition.size: - status("File size (0x{:x}) does not match partition size (0x{:x})".format(content_len, partition.size)) + if partition_table_file: + try: + with open(partition_table_file, "rb") as f: + partition_table = gen.PartitionTable.from_binary(f.read()) + except (gen.InputError, IOError, TypeError): + with open(partition_table_file, "r") as f: + f.seek(0) + partition_table = gen.PartitionTable.from_csv(f.read()) else: - status("File size matches partition size (0x{:x})".format(partition.size)) - - _invoke_esptool(["write_flash", str(partition.offset), args.input], args) - - status("Written contents of file '{}' to device at offset 0x{:x}".format(args.input, partition.offset)) - - -def read_partition(args): - partition = _get_and_check_partition(args) - _invoke_esptool(["read_flash", str(partition.offset), str(partition.size), args.output], args) - status("Read partition contents from device at offset 0x{:x} to file '{}'".format(partition.offset, args.output)) - - -def erase_partition(args): - partition = _get_and_check_partition(args) - _invoke_esptool(["erase_region", str(partition.offset), str(partition.size)], args) - status("Erased partition at offset 0x{:x} on device".format(partition.offset)) - - -def get_partition_info(args): - partition = None - - if args.table: - partition_table = _get_partition_table(args) - - if args.table.endswith(".csv"): - partition_table = partition_table.to_csv() - else: - partition_table = partition_table.to_binary() - - with open(args.table, "wb") as table_file: - table_file.write(partition_table) - status("Partition table written to " + table_file.name) - else: - partition = _get_partition(args) - - if partition: - info_dict = { - "offset": '0x{:x}'.format(partition.offset), - "size": '0x{:x}'.format(partition.size) - } - - infos = [] + temp_file = tempfile.NamedTemporaryFile(delete=False) + temp_file.close() try: - for info in args.info: - infos += [info_dict[info]] - except KeyError: - raise RuntimeError("Request for unknown partition info {}".format(info)) + self._call_esptool(["read_flash", str(partition_table_offset), str(gen.MAX_PARTITION_LENGTH), temp_file.name]) + with open(temp_file.name, "rb") as f: + partition_table = gen.PartitionTable.from_binary(f.read()) + finally: + os.unlink(temp_file.name) - status("Requested partition information [{}]:".format(", ".join(args.info))) - print(" ".join(infos)) - else: - status("Partition not found") + self.partition_table = partition_table + + def _call_esptool(self, args, out=None): + esptool_args = [sys.executable, ESPTOOL_PY] + + if self.port: + esptool_args += ["--port", self.port] + + esptool_args += args + + with open(os.devnull, "w") as null_file: + subprocess.check_call(esptool_args, stdout=null_file, stderr=null_file) + + def get_partition_info(self, partition_id): + partition = None + + if partition_id.name: + partition = self.partition_table.find_by_name(partition_id.name) + elif partition_id.type and partition_id.subtype: + partition = self.partition_table.find_by_type(partition_id.type, partition_id.subtype) + else: # default boot partition + search = ["factory"] + ["ota_{}".format(d) for d in range(16)] + for subtype in search: + partition = self.partition_table.find_by_type("app", subtype) + if partition: + break + + if not partition: + raise Exception("Partition does not exist") + + return partition + + def erase_partition(self, partition_id): + partition = self.get_partition_info(partition_id) + self._call_esptool(["erase_region", str(partition.offset), str(partition.size)]) + + def read_partition(self, partition_id, output): + partition = self.get_partition_info(partition_id) + self._call_esptool(["read_flash", str(partition.offset), str(partition.size), output]) + + def write_partition(self, partition_id, input): + self.erase_partition(partition_id) + + partition = self.get_partition_info(partition_id) + + with open(input, "rb") as input_file: + content_len = len(input_file.read()) + + if content_len > partition.size: + raise Exception("Input file size exceeds partition size") + + self._call_esptool(["write_flash", str(partition.offset), input]) -def generate_blank_partition_file(args): - output = None - stdout_binary = None +def _write_partition(target, partition_id, input): + target.write_partition(partition_id, input) + partition = target.get_partition_info(partition_id) + status("Written contents of file '{}' at offset 0x{:x}".format(input, partition.offset)) - partition = _get_and_check_partition(args) - output = b"\xFF" * partition.size + +def _read_partition(target, partition_id, output): + target.read_partition(partition_id, output) + partition = target.get_partition_info(partition_id) + status("Read partition '{}' contents from device at offset 0x{:x} to file '{}'" + .format(partition.name, partition.offset, output)) + + +def _erase_partition(target, partition_id): + target.erase_partition(partition_id) + partition = target.get_partition_info(partition_id) + status("Erased partition '{}' at offset 0x{:x}".format(partition.name, partition.offset)) + + +def _get_partition_info(target, partition_id, info): + try: + partition = target.get_partition_info(partition_id) + except Exception: + return + + info_dict = { + "offset": '0x{:x}'.format(partition.offset), + "size": '0x{:x}'.format(partition.size) + } + + infos = [] try: - stdout_binary = sys.stdout.buffer # Python 3 - except AttributeError: - stdout_binary = sys.stdout + for i in info: + infos += [info_dict[i]] + except KeyError: + raise RuntimeError("Request for unknown partition info {}".format(i)) - with stdout_binary if args.output == "" else open(args.output, 'wb') as f: - f.write(output) - status("Blank partition file '{}' generated".format(args.output)) + print(" ".join(infos)) def main(): @@ -220,48 +192,45 @@ def main(): parser.add_argument("--quiet", "-q", help="suppress stderr messages", action="store_true") - # There are two possible sources for the partition table: a device attached to the host - # or a partition table CSV/binary file. These sources are mutually exclusive. - partition_table_info_source_args = parser.add_mutually_exclusive_group() + # By default the device attached to the specified port is queried for the partition table. If a partition table file + # is specified, that is used instead. + parser.add_argument("--port", "-p", help="port where the target device of the command is connected to; the partition table is sourced from this device \ + when the partition table file is not defined") - partition_table_info_source_args.add_argument("--port", "-p", help="port where the device to read the partition table from is attached", default="") - partition_table_info_source_args.add_argument("--partition-table-file", "-f", help="file (CSV/binary) to read the partition table from") + parser.add_argument("--partition-table-offset", "-o", help="offset to read the partition table from", type=str) + parser.add_argument("--partition-table-file", "-f", help="file (CSV/binary) to read the partition table from; \ + overrides device attached to specified port as the partition table source when defined") - parser.add_argument("--partition-table-offset", "-o", help="offset to read the partition table from", default="0x8000") + partition_selection_parser = argparse.ArgumentParser(add_help=False) # Specify what partition to perform the operation on. This can either be specified using the # partition name or the first partition that matches the specified type/subtype - partition_selection_args = parser.add_mutually_exclusive_group() + partition_selection_args = partition_selection_parser.add_mutually_exclusive_group() partition_selection_args.add_argument("--partition-name", "-n", help="name of the partition") partition_selection_args.add_argument("--partition-type", "-t", help="type of the partition") partition_selection_args.add_argument('--partition-boot-default', "-d", help='select the default boot partition \ using the same fallback logic as the IDF bootloader', action="store_true") - parser.add_argument("--partition-subtype", "-s", help="subtype of the partition") + partition_selection_parser.add_argument("--partition-subtype", "-s", help="subtype of the partition") subparsers = parser.add_subparsers(dest="operation", help="run parttool -h for additional help") # Specify the supported operations - read_part_subparser = subparsers.add_parser("read_partition", help="read partition from device and dump contents into a file") + read_part_subparser = subparsers.add_parser("read_partition", help="read partition from device and dump contents into a file", + parents=[partition_selection_parser]) read_part_subparser.add_argument("--output", help="file to dump the read partition contents to") - write_part_subparser = subparsers.add_parser("write_partition", help="write contents of a binary file to partition on device") + write_part_subparser = subparsers.add_parser("write_partition", help="write contents of a binary file to partition on device", + parents=[partition_selection_parser]) write_part_subparser.add_argument("--input", help="file whose contents are to be written to the partition offset") - subparsers.add_parser("erase_partition", help="erase the contents of a partition on the device") + subparsers.add_parser("erase_partition", help="erase the contents of a partition on the device", parents=[partition_selection_parser]) - print_partition_info_subparser = subparsers.add_parser("get_partition_info", help="get partition information") - print_partition_info_subparser_info_type = print_partition_info_subparser.add_mutually_exclusive_group() - print_partition_info_subparser_info_type.add_argument("--info", help="type of partition information to get", nargs="+") - print_partition_info_subparser_info_type.add_argument("--table", help="dump the partition table to a file") - - generate_blank_subparser = subparsers.add_parser("generate_blank_partition_file", help="generate a blank (all 0xFF) partition file of \ - the specified partition that can be flashed to the device") - generate_blank_subparser.add_argument("--output", help="blank partition file filename") + print_partition_info_subparser = subparsers.add_parser("get_partition_info", help="get partition information", parents=[partition_selection_parser]) + print_partition_info_subparser.add_argument("--info", help="type of partition information to get", nargs="+") args = parser.parse_args() - quiet = args.quiet # No operation specified, display help and exit @@ -270,17 +239,55 @@ def main(): parser.print_help() sys.exit(1) - # Else execute the operation - operation_func = globals()[args.operation] + # Prepare the partition to perform operation on + if args.partition_name: + partition_id = PartitionName(args.partition_name) + elif args.partition_type: + if not args.partition_subtype: + raise RuntimeError("--partition-subtype should be defined when --partition-type is defined") + partition_id = PartitionType(args.partition_type, args.partition_subtype) + elif args.partition_boot_default: + partition_id = PARTITION_BOOT_DEFAULT + else: + raise RuntimeError("Partition to operate on should be defined using --partition-name OR \ + partition-type,--partition-subtype OR partition-boot-default") + + # Prepare the device to perform operation on + target_args = {} + + if args.port: + target_args["port"] = args.port + + if args.partition_table_file: + target_args["partition_table_file"] = args.partition_table_file + + if args.partition_table_offset: + target_args["partition_table_offset"] = int(args.partition_table_offset, 0) + + target = ParttoolTarget(**target_args) + + # Create the operation table and execute the operation + common_args = {'target':target, 'partition_id':partition_id} + parttool_ops = { + 'erase_partition':(_erase_partition, []), + 'read_partition':(_read_partition, ["output"]), + 'write_partition':(_write_partition, ["input"]), + 'get_partition_info':(_get_partition_info, ["info"]) + } + + (op, op_args) = parttool_ops[args.operation] + + for op_arg in op_args: + common_args.update({op_arg:vars(args)[op_arg]}) if quiet: # If exceptions occur, suppress and exit quietly try: - operation_func(args) + op(**common_args) except Exception: sys.exit(2) else: - operation_func(args) + op(**common_args) if __name__ == '__main__': diff --git a/components/partition_table/project_include.cmake b/components/partition_table/project_include.cmake index d8e31c7d1d..9f0dc93854 100644 --- a/components/partition_table/project_include.cmake +++ b/components/partition_table/project_include.cmake @@ -39,7 +39,7 @@ function(partition_table_get_partition_info result get_part_info_args part_info) ${idf_path}/components/partition_table/parttool.py -q --partition-table-offset ${PARTITION_TABLE_OFFSET} --partition-table-file ${PARTITION_CSV_PATH} - ${get_part_info_args} get_partition_info --info ${part_info} + get_partition_info ${get_part_info_args} --info ${part_info} OUTPUT_VARIABLE info RESULT_VARIABLE exit_code OUTPUT_STRIP_TRAILING_WHITESPACE) diff --git a/components/partition_table/test_gen_esp32part_host/gen_esp32part_tests.py b/components/partition_table/test_gen_esp32part_host/gen_esp32part_tests.py index 989d4c4758..17f16c5b46 100755 --- a/components/partition_table/test_gen_esp32part_host/gen_esp32part_tests.py +++ b/components/partition_table/test_gen_esp32part_host/gen_esp32part_tests.py @@ -403,13 +403,13 @@ app,app, factory, 32K, 1M class PartToolTests(Py23TestCase): - def _run_parttool(self, csvcontents, args, info): + def _run_parttool(self, csvcontents, args): csvpath = tempfile.mktemp() with open(csvpath, "w") as f: f.write(csvcontents) try: - output = subprocess.check_output([sys.executable, "../parttool.py"] + args.split(" ") - + ["--partition-table-file", csvpath, "get_partition_info", "--info", info], + output = subprocess.check_output([sys.executable, "../parttool.py", "-q", "--partition-table-file", + csvpath, "get_partition_info"] + args, stderr=subprocess.STDOUT) self.assertNotIn(b"WARNING", output) m = re.search(b"0x[0-9a-fA-F]+", output) @@ -425,17 +425,17 @@ phy_init, data, phy, 0xf000, 0x1000 factory, app, factory, 0x10000, 1M """ - def rpt(args, info): - return self._run_parttool(csv, args, info) + def rpt(args): + return self._run_parttool(csv, args) self.assertEqual( - rpt("--partition-type=data --partition-subtype=nvs -q", "offset"), b"0x9000") + rpt(["--partition-type", "data", "--partition-subtype", "nvs", "--info", "offset"]), b"0x9000") self.assertEqual( - rpt("--partition-type=data --partition-subtype=nvs -q", "size"), b"0x4000") + rpt(["--partition-type", "data", "--partition-subtype", "nvs", "--info", "size"]), b"0x4000") self.assertEqual( - rpt("--partition-name=otadata -q", "offset"), b"0xd000") + rpt(["--partition-name", "otadata", "--info", "offset"]), b"0xd000") self.assertEqual( - rpt("--partition-boot-default -q", "offset"), b"0x10000") + rpt(["--partition-boot-default", "--info", "offset"]), b"0x10000") def test_fallback(self): csv = """ @@ -446,16 +446,16 @@ ota_0, app, ota_0, 0x30000, 1M ota_1, app, ota_1, , 1M """ - def rpt(args, info): - return self._run_parttool(csv, args, info) + def rpt(args): + return self._run_parttool(csv, args) self.assertEqual( - rpt("--partition-type=app --partition-subtype=ota_1 -q", "offset"), b"0x130000") + rpt(["--partition-type", "app", "--partition-subtype", "ota_1", "--info", "offset"]), b"0x130000") self.assertEqual( - rpt("--partition-boot-default -q", "offset"), b"0x30000") # ota_0 + rpt(["--partition-boot-default", "--info", "offset"]), b"0x30000") # ota_0 csv_mod = csv.replace("ota_0", "ota_2") self.assertEqual( - self._run_parttool(csv_mod, "--partition-boot-default -q", "offset"), + self._run_parttool(csv_mod, ["--partition-boot-default", "--info", "offset"]), b"0x130000") # now default is ota_1 diff --git a/components/spiffs/Makefile.projbuild b/components/spiffs/Makefile.projbuild index 2fab90b172..13b2223a9a 100644 --- a/components/spiffs/Makefile.projbuild +++ b/components/spiffs/Makefile.projbuild @@ -21,9 +21,9 @@ define spiffs_create_partition_image $(1)_bin: $(PARTITION_TABLE_BIN) | check_python_dependencies - partition_size=`$(GET_PART_INFO) --partition-name $(1) \ + partition_size=`$(GET_PART_INFO) \ --partition-table-file $(PARTITION_TABLE_BIN) \ - get_partition_info --info size`; \ + get_partition_info --partition-name $(1) --info size`; \ $(PYTHON) $(SPIFFSGEN_PY) $$$$partition_size $(2) $(BUILD_DIR_BASE)/$(1).bin \ --page-size=$(CONFIG_SPIFFS_PAGE_SIZE) \ --obj-name-len=$(CONFIG_SPIFFS_OBJ_NAME_LEN) \ @@ -41,5 +41,5 @@ endif endef ESPTOOL_ALL_FLASH_ARGS += $(foreach partition,$(SPIFFSGEN_FLASH_IN_PROJECT), \ -$(shell $(GET_PART_INFO) --partition-name $(partition) \ ---partition-table-file $(PARTITION_TABLE_BIN) get_partition_info --info offset) $(BUILD_DIR_BASE)/$(partition).bin) \ No newline at end of file +$(shell $(GET_PART_INFO) --partition-table-file $(PARTITION_TABLE_BIN) \ +get_partition_info --partition-name $(partition) --info offset) $(BUILD_DIR_BASE)/$(partition).bin) \ No newline at end of file diff --git a/docs/en/api-guides/partition-tables.rst b/docs/en/api-guides/partition-tables.rst index 502c7118c9..000a9b3616 100644 --- a/docs/en/api-guides/partition-tables.rst +++ b/docs/en/api-guides/partition-tables.rst @@ -169,4 +169,100 @@ A manual flashing command is also printed as part of ``make partition_table``. Note that updating the partition table doesn't erase data that may have been stored according to the old partition table. You can use ``make erase_flash`` (or ``esptool.py erase_flash``) to erase the entire flash contents. +Partition Tool (parttool.py) +---------------------------- + +The component `partition_table` provides a tool :component_file:`parttool.py` for performing partition-related operations on a target device. The following operations can be performed using the tool: + + - reading a partition and saving the contents to a file (read_partition) + - writing the contents of a file to a partition (write_partition) + - erasing a partition (erase_partition) + - retrieving info such as offset and size of a given partition (get_partition_info) + +The tool can either be imported and used from another Python script or invoked from shell script for users wanting to perform operation programmatically. This is facilitated by the tool's Python API +and command-line interface, respectively. + +Python API +~~~~~~~~~~~ + +Before anything else, make sure that the `parttool` module is imported. + +.. code-block:: python + + import sys + import os + + idf_path = os.environ["IDF_PATH"] # get value of IDF_PATH from environment + parttool_dir = os.path.join(idf_path, "components", "partition_table") # parttool.py lives in $IDF_PATH/components/partition_table + + sys.path.append(parttool_dir) # this enables Python to find parttool module + from parttool import * # import all names inside parttool module + +The starting point for using the tool's Python API to do is create a `ParttoolTarget` object: + +.. code-block:: python + + # Create a partool.py target device connected on serial port /dev/ttyUSB1 + target = ParttoolTarget("/dev/ttyUSB1") + +The created object can now be used to perform operations on the target device: + +.. code-block:: python + + # Erase partition with name 'storage' + target.erase_partition(PartitionName("storage")) + + # Read partition with type 'data' and subtype 'spiffs' and save to file 'spiffs.bin' + target.read_partition(PartitionType("data", "spiffs"), "spiffs.bin") + + # Write to partition 'factory' the contents of a file named 'factory.bin' + target.write_partition(PartitionName("factory"), "factory.bin") + + # Print the size of default boot partition + storage = target.get_partition_info(PARTITION_BOOT_DEFAULT) + print(storage.size) + +The partition to operate on is specified using `PartitionName` or `PartitionType` or PARTITION_BOOT_DEFAULT. As the name implies, these can be used to refer +to partitions of a particular name, type-subtype combination, or the default boot partition. + +More information on the Python API is available in the docstrings for the tool. + +Command-line Interface +~~~~~~~~~~~~~~~~~~~~~~ + +The command-line interface of `parttool.py` has the following structure: + +.. code-block:: bash + + parttool.py [command-args] [subcommand] [subcommand-args] + + - command-args - These are arguments that are needed for executing the main command (parttool.py), mostly pertaining to the target device + - subcommand - This is the operation to be performed + - subcommand-args - These are arguments that are specific to the chosen operation + +.. code-block:: bash + + # Erase partition with name 'storage' + parttool.py --port "/dev/ttyUSB1" erase_partition --partition-name=storage + + # Read partition with type 'data' and subtype 'spiffs' and save to file 'spiffs.bin' + parttool.py --port "/dev/ttyUSB1" read_partition --partition-type=data --partition-subtype=spiffs "spiffs.bin" + + # Write to partition 'factory' the contents of a file named 'factory.bin' + parttool.py --port "/dev/ttyUSB1" write_partition --partition-name=factory "factory.bin" + + # Print the size of default boot partition + parttool.py --port "/dev/ttyUSB1" get_partition_info --partition-boot-default --info size + +More information can be obtained by specifying `--help` as argument: + +.. code-block:: bash + + # Display possible subcommands and show main command argument descriptions + parttool.py --help + + # Show descriptions for specific subcommand arguments + parttool.py [subcommand] --help + + .. _secure boot: security/secure-boot.rst diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index 5cbf7b3a2b..0dc1c7fd15 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -7,6 +7,7 @@ components/espcoredump/test/test_espcoredump.sh components/heap/test_multi_heap_host/test_all_configs.sh components/idf_test/unit_test/TestCaseScript/IDFUnitTest/__init__.py components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py +components/partition_table/gen_empty_partition.py components/partition_table/gen_esp32part.py components/partition_table/parttool.py components/partition_table/test_gen_esp32part_host/gen_esp32part_tests.py From 1de627e68aee139255689c6ce16d8d26d9c9bd4b Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Mon, 27 May 2019 11:08:28 +0800 Subject: [PATCH 020/486] app_update: implement Python API for otatool --- components/app_update/CMakeLists.txt | 6 +- components/app_update/Makefile.projbuild | 3 +- components/app_update/otatool.py | 327 ++++++++++++----------- docs/en/api-reference/system/ota.rst | 98 +++++++ 4 files changed, 277 insertions(+), 157 deletions(-) diff --git a/components/app_update/CMakeLists.txt b/components/app_update/CMakeLists.txt index 2c705d5091..e869c188fb 100644 --- a/components/app_update/CMakeLists.txt +++ b/components/app_update/CMakeLists.txt @@ -33,10 +33,8 @@ if(NOT BOOTLOADER_BUILD) idf_build_get_property(idf_path IDF_PATH) idf_build_get_property(python PYTHON) add_custom_command(OUTPUT ${blank_otadata_file} - COMMAND ${python} ${idf_path}/components/partition_table/parttool.py - --partition-type data --partition-subtype ota -q - --partition-table-file ${PARTITION_CSV_PATH} generate_blank_partition_file - --output ${blank_otadata_file}) + COMMAND ${python} ${idf_path}/components/partition_table/gen_empty_partition.py + ${otadata_size} ${blank_otadata_file}) add_custom_target(blank_ota_data ALL DEPENDS ${blank_otadata_file}) add_dependencies(app blank_ota_data) diff --git a/components/app_update/Makefile.projbuild b/components/app_update/Makefile.projbuild index 435d7535ac..a20856a6ef 100644 --- a/components/app_update/Makefile.projbuild +++ b/components/app_update/Makefile.projbuild @@ -17,8 +17,7 @@ endif $(BLANK_OTA_DATA_FILE): partition_table_get_info $(PARTITION_TABLE_CSV_PATH) | check_python_dependencies $(shell if [ "$(OTA_DATA_OFFSET)" != "" ] && [ "$(OTA_DATA_SIZE)" != "" ]; then \ - $(PARTTOOL_PY) --partition-type data --partition-subtype ota --partition-table-file $(PARTITION_TABLE_CSV_PATH) \ - -q generate_blank_partition_file --output $(BLANK_OTA_DATA_FILE); \ + $(PYTHON) $(IDF_PATH)/components/partition_table/gen_empty_partition.py $(OTA_DATA_SIZE) $(BLANK_OTA_DATA_FILE); \ fi; ) $(eval BLANK_OTA_DATA_FILE = $(shell if [ "$(OTA_DATA_OFFSET)" != "" ] && [ "$(OTA_DATA_SIZE)" != "" ]; then \ echo $(BLANK_OTA_DATA_FILE); else echo " "; fi) ) diff --git a/components/app_update/otatool.py b/components/app_update/otatool.py index aead479d92..2cfecde18b 100755 --- a/components/app_update/otatool.py +++ b/components/app_update/otatool.py @@ -21,16 +21,20 @@ import argparse import os import sys import binascii -import subprocess import tempfile import collections import struct -__version__ = '1.0' +try: + from parttool import PartitionName, PartitionType, ParttoolTarget, PARTITION_TABLE_OFFSET +except ImportError: + COMPONENTS_PATH = os.path.expandvars(os.path.join("$IDF_PATH", "components")) + PARTTOOL_DIR = os.path.join(COMPONENTS_PATH, "partition_table") -IDF_COMPONENTS_PATH = os.path.expandvars(os.path.join("$IDF_PATH", "components")) + sys.path.append(PARTTOOL_DIR) + from parttool import PartitionName, PartitionType, ParttoolTarget, PARTITION_TABLE_OFFSET -PARTTOOL_PY = os.path.join(IDF_COMPONENTS_PATH, "partition_table", "parttool.py") +__version__ = '2.0' SPI_FLASH_SEC_SIZE = 0x2000 @@ -42,121 +46,69 @@ def status(msg): print(msg) -def _invoke_parttool(parttool_args, args, output=False, partition=None): - invoke_args = [] +class OtatoolTarget(): - if partition: - invoke_args += [sys.executable, PARTTOOL_PY] + partition - else: - invoke_args += [sys.executable, PARTTOOL_PY, "--partition-type", "data", "--partition-subtype", "ota"] + OTADATA_PARTITION = PartitionType("data", "ota") - if quiet: - invoke_args += ["-q"] + def __init__(self, port=None, partition_table_offset=PARTITION_TABLE_OFFSET, partition_table_file=None, spi_flash_sec_size=SPI_FLASH_SEC_SIZE): + self.target = ParttoolTarget(port, partition_table_offset, partition_table_file) + self.spi_flash_sec_size = spi_flash_sec_size - if args.port != "": - invoke_args += ["--port", args.port] + temp_file = tempfile.NamedTemporaryFile(delete=False) + temp_file.close() + try: + self.target.read_partition(OtatoolTarget.OTADATA_PARTITION, temp_file.name) + with open(temp_file.name, "rb") as f: + self.otadata = f.read() + except Exception: + self.otadata = None + finally: + os.unlink(temp_file.name) - if args.partition_table_file: - invoke_args += ["--partition-table-file", args.partition_table_file] + def _check_otadata_partition(self): + if not self.otadata: + raise Exception("No otadata partition found") - if args.partition_table_offset: - invoke_args += ["--partition-table-offset", args.partition_table_offset] + def erase_otadata(self): + self._check_otadata_partition() + self.target.erase_partition(OtatoolTarget.OTADATA_PARTITION) - invoke_args += parttool_args + def _get_otadata_info(self): + info = [] - if output: - return subprocess.check_output(invoke_args) - else: - return subprocess.check_call(invoke_args) + otadata_info = collections.namedtuple("otadata_info", "seq crc") + for i in range(2): + start = i * (self.spi_flash_sec_size >> 1) -def _get_otadata_contents(args, check=True): - global quiet + seq = bytearray(self.otadata[start:start + 4]) + crc = bytearray(self.otadata[start + 28:start + 32]) - if check: - check_args = ["get_partition_info", "--info", "offset", "size"] + seq = struct.unpack('>I', seq) + crc = struct.unpack('>I', crc) - quiet = True - output = _invoke_parttool(check_args, args, True).split(b" ") - quiet = args.quiet + info.append(otadata_info(seq[0], crc[0])) - if not output: - raise RuntimeError("No ota_data partition found") + return info - with tempfile.NamedTemporaryFile(delete=False) as f: - f_name = f.name + def _get_partition_id_from_ota_id(self, ota_id): + if isinstance(ota_id, int): + return PartitionType("app", "ota_" + str(ota_id)) + else: + return PartitionName(ota_id) - try: - invoke_args = ["read_partition", "--output", f_name] - _invoke_parttool(invoke_args, args) - with open(f_name, "rb") as f: - contents = f.read() - finally: - os.unlink(f_name) + def switch_ota_partition(self, ota_id): + self._check_otadata_partition() - return contents + sys.path.append(PARTTOOL_DIR) + import gen_esp32part as gen - -def _get_otadata_status(otadata_contents): - status = [] - - otadata_status = collections.namedtuple("otadata_status", "seq crc") - - for i in range(2): - start = i * (SPI_FLASH_SEC_SIZE >> 1) - - seq = bytearray(otadata_contents[start:start + 4]) - crc = bytearray(otadata_contents[start + 28:start + 32]) - - seq = struct.unpack('>I', seq) - crc = struct.unpack('>I', crc) - - status.append(otadata_status(seq[0], crc[0])) - - return status - - -def read_otadata(args): - status("Reading ota_data partition contents...") - otadata_info = _get_otadata_contents(args) - otadata_info = _get_otadata_status(otadata_info) - - print(otadata_info) - - print("\t\t{:11}\t{:8s}|\t{:8s}\t{:8s}".format("OTA_SEQ", "CRC", "OTA_SEQ", "CRC")) - print("Firmware: 0x{:8x} \t 0x{:8x} |\t0x{:8x} \t 0x{:8x}".format(otadata_info[0].seq, otadata_info[0].crc, - otadata_info[1].seq, otadata_info[1].crc)) - - -def erase_otadata(args): - status("Erasing ota_data partition contents...") - _invoke_parttool(["erase_partition"], args) - status("Erased ota_data partition contents") - - -def switch_otadata(args): - sys.path.append(os.path.join(IDF_COMPONENTS_PATH, "partition_table")) - import gen_esp32part as gen - - with tempfile.NamedTemporaryFile(delete=False) as f: - f_name = f.name - - try: - def is_otadata_status_valid(status): + def is_otadata_info_valid(status): seq = status.seq % (1 << 32) crc = hex(binascii.crc32(struct.pack("I", seq), 0xFFFFFFFF) % (1 << 32)) return seq < (int('0xFFFFFFFF', 16) % (1 << 32)) and status.crc == crc - status("Looking for ota app partitions...") - - # In order to get the number of ota app partitions, we need the partition table - partition_table = None - invoke_args = ["get_partition_info", "--table", f_name] - - _invoke_parttool(invoke_args, args) - - partition_table = open(f_name, "rb").read() - partition_table = gen.PartitionTable.from_binary(partition_table) + partition_table = self.target.partition_table ota_partitions = list() @@ -171,39 +123,36 @@ def switch_otadata(args): ota_partitions = sorted(ota_partitions, key=lambda p: p.subtype) if not ota_partitions: - raise RuntimeError("No ota app partitions found") - - status("Verifying partition to switch to exists...") + raise Exception("No ota app partitions found") # Look for the app partition to switch to ota_partition_next = None try: - if args.name: - ota_partition_next = filter(lambda p: p.name == args.name, ota_partitions) + if isinstance(ota_id, int): + ota_partition_next = filter(lambda p: p.subtype - gen.MIN_PARTITION_SUBTYPE_APP_OTA == ota_id, ota_partitions) else: - ota_partition_next = filter(lambda p: p.subtype - gen.MIN_PARTITION_SUBTYPE_APP_OTA == args.slot, ota_partitions) + ota_partition_next = filter(lambda p: p.name == ota_id, ota_partitions) ota_partition_next = list(ota_partition_next)[0] except IndexError: - raise RuntimeError("Partition to switch to not found") + raise Exception("Partition to switch to not found") - otadata_contents = _get_otadata_contents(args) - otadata_status = _get_otadata_status(otadata_contents) + otadata_info = self._get_otadata_info() # Find the copy to base the computation for ota sequence number on otadata_compute_base = -1 # Both are valid, take the max as computation base - if is_otadata_status_valid(otadata_status[0]) and is_otadata_status_valid(otadata_status[1]): - if otadata_status[0].seq >= otadata_status[1].seq: + if is_otadata_info_valid(otadata_info[0]) and is_otadata_info_valid(otadata_info[1]): + if otadata_info[0].seq >= otadata_info[1].seq: otadata_compute_base = 0 else: otadata_compute_base = 1 # Only one copy is valid, use that - elif is_otadata_status_valid(otadata_status[0]): + elif is_otadata_info_valid(otadata_info[0]): otadata_compute_base = 0 - elif is_otadata_status_valid(otadata_status[1]): + elif is_otadata_info_valid(otadata_info[1]): otadata_compute_base = 1 # Both are invalid (could be initial state - all 0xFF's) else: @@ -216,7 +165,7 @@ def switch_otadata(args): # Find the next ota sequence number if otadata_compute_base == 0 or otadata_compute_base == 1: - base_seq = otadata_status[otadata_compute_base].seq % (1 << 32) + base_seq = otadata_info[otadata_compute_base].seq % (1 << 32) i = 0 while base_seq > target_seq % ota_partitions_num + i * ota_partitions_num: @@ -231,47 +180,68 @@ def switch_otadata(args): ota_seq_crc_next = binascii.crc32(ota_seq_next, 0xFFFFFFFF) % (1 << 32) ota_seq_crc_next = struct.pack("I", ota_seq_crc_next) - with open(f_name, "wb") as otadata_next_file: - start = (1 if otadata_compute_base == 0 else 0) * (SPI_FLASH_SEC_SIZE >> 1) + temp_file = tempfile.NamedTemporaryFile(delete=False) + temp_file.close() - otadata_next_file.write(otadata_contents) + try: + with open(temp_file.name, "wb") as otadata_next_file: + start = (1 if otadata_compute_base == 0 else 0) * (self.spi_flash_sec_size >> 1) - otadata_next_file.seek(start) - otadata_next_file.write(ota_seq_next) + otadata_next_file.write(self.otadata) - otadata_next_file.seek(start + 28) - otadata_next_file.write(ota_seq_crc_next) + otadata_next_file.seek(start) + otadata_next_file.write(ota_seq_next) - otadata_next_file.flush() + otadata_next_file.seek(start + 28) + otadata_next_file.write(ota_seq_crc_next) - _invoke_parttool(["write_partition", "--input", f_name], args) - status("Updated ota_data partition") - finally: - os.unlink(f_name) + otadata_next_file.flush() + + self.target.write_partition(OtatoolTarget.OTADATA_PARTITION, temp_file.name) + finally: + os.unlink(temp_file.name) + + def read_ota_partition(self, ota_id, output): + self.target.read_partition(self._get_partition_id_from_ota_id(ota_id), output) + + def write_ota_partition(self, ota_id, input): + self.target.write_partition(self._get_partition_id_from_ota_id(ota_id), input) + + def erase_ota_partition(self, ota_id): + self.target.erase_partition(self._get_partition_id_from_ota_id(ota_id)) -def _get_partition_specifier(args): - if args.name: - return ["--partition-name", args.name] - else: - return ["--partition-type", "app", "--partition-subtype", "ota_" + str(args.slot)] +def _read_otadata(target): + target._check_otadata_partition() + + otadata_info = target._get_otadata_info(target.otadata) + + print("\t\t{:11}\t{:8s}|\t{:8s}\t{:8s}".format("OTA_SEQ", "CRC", "OTA_SEQ", "CRC")) + print("Firmware: 0x{:8x} \t 0x{:8x} |\t0x{:8x} \t 0x{:8x}".format(otadata_info[0].seq, otadata_info[0].crc, + otadata_info[1].seq, otadata_info[1].crc)) -def read_ota_partition(args): - invoke_args = ["read_partition", "--output", args.output] - _invoke_parttool(invoke_args, args, partition=_get_partition_specifier(args)) - status("Read ota partition contents to file {}".format(args.output)) +def _erase_otadata(target): + target.erase_otadata() + status("Erased ota_data partition contents") -def write_ota_partition(args): - invoke_args = ["write_partition", "--input", args.input] - _invoke_parttool(invoke_args, args, partition=_get_partition_specifier(args)) - status("Written contents of file {} to ota partition".format(args.input)) +def _switch_ota_partition(target, ota_id): + target.switch_ota_partition(ota_id) -def erase_ota_partition(args): - invoke_args = ["erase_partition"] - _invoke_parttool(invoke_args, args, partition=_get_partition_specifier(args)) +def _read_ota_partition(target, ota_id, output): + target.read_ota_partition(ota_id, output) + status("Read ota partition contents to file {}".format(output)) + + +def _write_ota_partition(target, ota_id, input): + target.write_ota_partition(ota_id, input) + status("Written contents of file {} to ota partition".format(input)) + + +def _erase_ota_partition(target, ota_id): + target.erase_ota_partition(ota_id) status("Erased contents of ota partition") @@ -284,17 +254,20 @@ def main(): # There are two possible sources for the partition table: a device attached to the host # or a partition table CSV/binary file. These sources are mutually exclusive. - partition_table_info_source_args = parser.add_mutually_exclusive_group() + parser.add_argument("--port", "-p", help="port where the device to read the partition table from is attached") - partition_table_info_source_args.add_argument("--port", "-p", help="port where the device to read the partition table from is attached", default="") - partition_table_info_source_args.add_argument("--partition-table-file", "-f", help="file (CSV/binary) to read the partition table from", default="") + parser.add_argument("--partition-table-offset", "-o", help="offset to read the partition table from", type=str) - parser.add_argument("--partition-table-offset", "-o", help="offset to read the partition table from", default="0x8000") + parser.add_argument("--partition-table-file", "-f", help="file (CSV/binary) to read the partition table from; \ + overrides device attached to specified port as the partition table source when defined") subparsers = parser.add_subparsers(dest="operation", help="run otatool -h for additional help") + spi_flash_sec_size = argparse.ArgumentParser(add_help=False) + spi_flash_sec_size.add_argument("--spi-flash-sec-size", help="value of SPI_FLASH_SEC_SIZE macro", type=str) + # Specify the supported operations - subparsers.add_parser("read_otadata", help="read otadata partition") + subparsers.add_parser("read_otadata", help="read otadata partition", parents=[spi_flash_sec_size]) subparsers.add_parser("erase_otadata", help="erase otadata partition") slot_or_name_parser = argparse.ArgumentParser(add_help=False) @@ -302,7 +275,7 @@ def main(): slot_or_name_parser_args.add_argument("--slot", help="slot number of the ota partition", type=int) slot_or_name_parser_args.add_argument("--name", help="name of the ota partition") - subparsers.add_parser("switch_otadata", help="switch otadata partition", parents=[slot_or_name_parser]) + subparsers.add_parser("switch_ota_partition", help="switch otadata partition", parents=[slot_or_name_parser, spi_flash_sec_size]) read_ota_partition_subparser = subparsers.add_parser("read_ota_partition", help="read contents of an ota partition", parents=[slot_or_name_parser]) read_ota_partition_subparser.add_argument("--output", help="file to write the contents of the ota partition to") @@ -322,17 +295,69 @@ def main(): parser.print_help() sys.exit(1) - # Else execute the operation - operation_func = globals()[args.operation] + target_args = {} + + if args.port: + target_args["port"] = args.port + + if args.partition_table_file: + target_args["partition_table_file"] = args.partition_table_file + + if args.partition_table_offset: + target_args["partition_table_offset"] = int(args.partition_table_offset, 0) + + try: + if args.spi_flash_sec_size: + target_args["spi_flash_sec_size"] = int(args.spi_flash_sec_size, 0) + except AttributeError: + pass + + target = OtatoolTarget(**target_args) + + # Create the operation table and execute the operation + common_args = {'target':target} + + ota_id = [] + + try: + if args.name is not None: + ota_id = ["name"] + else: + if args.slot is not None: + ota_id = ["slot"] + except AttributeError: + pass + + otatool_ops = { + 'read_otadata':(_read_otadata, []), + 'erase_otadata':(_erase_otadata, []), + 'switch_ota_partition':(_switch_ota_partition, ota_id), + 'read_ota_partition':(_read_ota_partition, ["output"] + ota_id), + 'write_ota_partition':(_write_ota_partition, ["input"] + ota_id), + 'erase_ota_partition':(_erase_ota_partition, ota_id) + } + + (op, op_args) = otatool_ops[args.operation] + + for op_arg in op_args: + common_args.update({op_arg:vars(args)[op_arg]}) + + try: + common_args['ota_id'] = common_args.pop('name') + except KeyError: + try: + common_args['ota_id'] = common_args.pop('slot') + except KeyError: + pass if quiet: # If exceptions occur, suppress and exit quietly try: - operation_func(args) + op(**common_args) except Exception: sys.exit(2) else: - operation_func(args) + op(**common_args) if __name__ == '__main__': diff --git a/docs/en/api-reference/system/ota.rst b/docs/en/api-reference/system/ota.rst index 50938a3776..d83a38dab3 100644 --- a/docs/en/api-reference/system/ota.rst +++ b/docs/en/api-reference/system/ota.rst @@ -199,6 +199,104 @@ Secure OTA Updates Without Secure boot The verification of signed OTA updates can be performed even without enabling hardware secure boot. For doing so, refer :ref:`signed-app-verify` + +OTA Tool (otatool.py) +--------------------- + +The component `app_update` provides a tool :component_file:`otatool.py` for performing OTA partition-related operations on a target device. The following operations can be performed using the tool: + + - read contents of otadata partition (read_otadata) + - erase otadata partition, effectively resetting device to factory app (erase_otadata) + - switch OTA partitions (switch_ota_partition) + - erasing OTA partition (erase_ota_partition) + - write to OTA partition (write_ota_partition) + - read contents of OTA partition (read_ota_partition) + +The tool can either be imported and used from another Python script or invoked from shell script for users wanting to perform operation programmatically. This is facilitated by the tool's Python API +and command-line interface, respectively. + +Python API +^^^^^^^^^^ + +Before anything else, make sure that the `otatool` module is imported. + +.. code-block:: python + + import sys + import os + + idf_path = os.environ["IDF_PATH"] # get value of IDF_PATH from environment + otatool_dir = os.path.join(idf_path, "components", "app_update") # otatool.py lives in $IDF_PATH/components/app_update + + sys.path.append(otatool_dir) # this enables Python to find otatool module + from otatool import * # import all names inside otatool module + +The starting point for using the tool's Python API to do is create a `OtatoolTarget` object: + +.. code-block:: python + + # Create a partool.py target device connected on serial port /dev/ttyUSB1 + target = OtatoolTarget("/dev/ttyUSB1") + +The created object can now be used to perform operations on the target device: + +.. code-block:: python + + # Erase otadata, reseting the device to factory app + target.erase_otadata() + + # Erase contents of OTA app slot 0 + target.erase_ota_partition(0) + + # Switch boot partition to that of app slot 1 + target.switch_ota_partition(1) + + # Read OTA partition 'ota_3' and save contents to a file named 'ota_3.bin' + target.read_ota_partition("ota_3", "ota_3.bin") + +The OTA partition to operate on is specified using either the app slot number or the partition name. + +More information on the Python API is available in the docstrings for the tool. + +Command-line Interface +^^^^^^^^^^^^^^^^^^^^^^ + +The command-line interface of `otatool.py` has the following structure: + +.. code-block:: bash + + otatool.py [command-args] [subcommand] [subcommand-args] + + - command-args - these are arguments that are needed for executing the main command (parttool.py), mostly pertaining to the target device + - subcommand - this is the operation to be performed + - subcommand-args - these are arguments that are specific to the chosen operation + +.. code-block:: bash + + # Erase otadata, resetting the device to factory app + otatool.py --port "/dev/ttyUSB1" erase_otadata + + # Erase contents of OTA app slot 0 + otatool.py --port "/dev/ttyUSB1" erase_ota_partition --slot 0 + + # Switch boot partition to that of app slot 1 + otatool.py --port "/dev/ttyUSB1" switch_ota_partition --slot 1 + + # Read OTA partition 'ota_3' and save contents to a file named 'ota_3.bin' + otatool.py --port "/dev/ttyUSB1" read_ota_partition --name=ota_3 + + +More information can be obtained by specifying `--help` as argument: + +.. code-block:: bash + + # Display possible subcommands and show main command argument descriptions + otatool.py --help + + # Show descriptions for specific subcommand arguments + otatool.py [subcommand] --help + + See also -------- From 5d413224123710bda58ae73773edb54241142335 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Mon, 27 May 2019 11:09:35 +0800 Subject: [PATCH 021/486] examples: create example for both Python and CLI parttool interfaces --- examples/storage/parttool/README.md | 39 ++-- examples/storage/parttool/parttool_example.py | 191 +++++------------- examples/storage/parttool/parttool_example.sh | 73 +++++++ tools/ci/executable-list.txt | 1 + 4 files changed, 141 insertions(+), 163 deletions(-) create mode 100644 examples/storage/parttool/parttool_example.sh diff --git a/examples/storage/parttool/README.md b/examples/storage/parttool/README.md index b84203e03f..8b888fcfdd 100644 --- a/examples/storage/parttool/README.md +++ b/examples/storage/parttool/README.md @@ -4,10 +4,11 @@ This example demonstrates common operations the partitions tool [parttool.py](.. - reading, writing and erasing partitions, - retrieving info on a certain partition, -- dumping the entire partition table, and -- generating a blank partition file. +- dumping the entire partition table -Users taking a look at this example should focus on the contents of the python script [parttool_example.py](parttool_example.py). The script contains programmatic invocations of [parttool.py](../../../components/partition_table/parttool.py) in Python for the operations mentioned above; and can serve as a guide for users wanting to do the same in their applications. +Users taking a look at this example should focus on the contents of the Python script [parttool_example.py](parttool_example.py) or shell script [parttool_example.sh](parttool_example.sh). The scripts contain +programmatic invocation of the tool's functions via the Python API and command-line interface, respectively. Note +that on Windows, the shell script example requires a POSIX-compatible environment via MSYS2/Git Bash/WSL etc. The example performs the operations mentioned above in a straightforward manner: it performs writes to partitions and then verifies correct content by reading it back. For partitions, contents are compared to the originally written file. For the partition table, contents are verified against the partition table CSV @@ -17,50 +18,54 @@ file. An erased partition's contents is compared to a generated blank file. ### Build and Flash -Before running the example script [parttool_example.py](parttool_example.py), it is necessary to build and flash the firmware using the usual means: +Before running either of the example scripts, it is necessary to build and flash the firmware using the usual means: +Make: ```bash -# If using Make make build flash +``` -# If using CMake +CMake: +```bash idf.py build flash ``` ### Running [parttool_example.py](parttool_example.py) -The example can be executed by running the script [parttool_example.py](parttool_example.py). Either run it directly using - -```bash -./parttool_example.py -``` - -or run it using +The example can be executed by running the script [parttool_example.py](parttool_example.py) or [parttool_example.sh](parttool_example.sh). +Python script: ```bash python parttool_example.py ``` +Shell script: +``` +./parttool_example.sh +``` + The script searches for valid target devices connected to the host and performs the operations on the first one it finds. To perform the operations on a specific device, specify the port it is attached to during script invocation: +Python script: ```bash -# The target device is attached to /dev/ttyUSB2, for example python parttool_example.py --port /dev/ttyUSB2 ``` +Shell script: +``` +./parttool_example.sh /dev/ttyUSB2 +``` + ## Example output Running the script produces the following output: ``` Checking if device app binary matches built binary -Checking if device partition table matches partition table csv -Retrieving data partition offset and size Found data partition at offset 0x110000 with size 0x10000 Writing to data partition Reading data partition Erasing data partition -Generating blank data partition file Reading data partition Partition tool operations performed successfully! diff --git a/examples/storage/parttool/parttool_example.py b/examples/storage/parttool/parttool_example.py index 24b8fcd18f..bf2c6f7cdf 100755 --- a/examples/storage/parttool/parttool_example.py +++ b/examples/storage/parttool/parttool_example.py @@ -18,19 +18,12 @@ # limitations under the License. import os import sys -import subprocess import argparse -IDF_PATH = os.path.expandvars("$IDF_PATH") - -PARTTOOL_PY = os.path.join(IDF_PATH, "components", "partition_table", "parttool.py") - -PARTITION_TABLE_OFFSET = 0x8000 - -INVOKE_ARGS = [sys.executable, PARTTOOL_PY, "-q", "--partition-table-offset", str(PARTITION_TABLE_OFFSET)] +PARTITION_TABLE_DIR = os.path.join("components", "partition_table", "") -def sized_file_compare(file1, file2): +def assert_file_same(file1, file2, err): with open(file1, "rb") as f1: with open(file2, "rb") as f2: f1 = f1.read() @@ -41,121 +34,17 @@ def sized_file_compare(file1, file2): else: f1 = f1[:len(f2)] - return f1 == f2 - - -def check(condition, message): - if not condition: - print("Error: " + message) - sys.exit(1) - - -def write_data_partition(size): - print("Writing to data partition") - with open("write.bin", "wb") as f: - # Create a file to write to the data partition with randomly generated content - f.write(os.urandom(int(size, 16))) - - # Invokes the command - # - # parttool.py --partition-table-offset 0x8000 -q --partition-name storage write_partition --input write.bin - # - # to write the contents of a file to a partition in the device. - invoke_args = INVOKE_ARGS + ["--partition-name", "storage", "write_partition", "--input", f.name] - subprocess.check_call(invoke_args) - return f.name - - -def read_data_partition(): - print("Reading data partition") - # Invokes the command - # - # parttool.py --partition-table-offset 0x8000 -q --partition-name storage read_partition --output read.bin - # - # to read the contents of a partition in the device, which is then written to a file. - f = "read.bin" - invoke_args = INVOKE_ARGS + ["--partition-name", "storage", "read_partition", "--output", f] - subprocess.check_call(invoke_args) - return f - - -def get_data_partition_info(): - print("Retrieving data partition offset and size") - # Invokes the command - # - # parttool.py --partition-table-offset 0x8000 -q --partition-name storage get_partition_info --info offset size - # - # to get the offset and size of a partition named 'storage'. - invoke_args = INVOKE_ARGS + ["--partition-name", "storage", "get_partition_info", "--info", "offset", "size"] - - (offset, size) = subprocess.check_output(invoke_args).strip().split(b" ") - return (offset, size) - - -def check_app(args): - print("Checking if device app binary matches built binary") - # Invokes the command - # - # parttool.py --partition-table-offset 0x8000 --partition-type app --partition-subtype factory read_partition --output app.bin" - # - # to read the app binary and write it to a file. The read app binary is compared to the built binary in the build folder. - invoke_args = INVOKE_ARGS + ["--partition-type", "app", "--partition-subtype", "factory", "read_partition", "--output", "app.bin"] - subprocess.check_call(invoke_args) - - app_same = sized_file_compare("app.bin", args.binary) - check(app_same, "Device app binary does not match built binary") - - -def check_partition_table(): - sys.path.append(os.path.join(IDF_PATH, "components", "partition_table")) - import gen_esp32part as gen - - print("Checking if device partition table matches partition table csv") - # Invokes the command - # - # parttool.py --partition-table-offset 0x8000 get_partition_info --table table.bin - # - # to read the device partition table and write it to a file. The read partition table is compared to - # the partition table csv. - invoke_args = INVOKE_ARGS + ["get_partition_info", "--table", "table.bin"] - subprocess.check_call(invoke_args) - - with open("table.bin", "rb") as read: - partition_table_csv = os.path.join(IDF_PATH, "examples", "storage", "parttool", "partitions_example.csv") - with open(partition_table_csv, "r") as csv: - read = gen.PartitionTable.from_binary(read.read()) - csv = gen.PartitionTable.from_csv(csv.read()) - check(read == csv, "Device partition table does not match csv partition table") - - -def erase_data_partition(): - print("Erasing data partition") - # Invokes the command - # - # parttool.py --partition-table-offset 0x8000 --partition-name storage erase_partition - # - # to erase the 'storage' partition. - invoke_args = INVOKE_ARGS + ["--partition-name", "storage", "erase_partition"] - subprocess.check_call(invoke_args) - - -def generate_blank_data_file(): - print("Generating blank data partition file") - - # Invokes the command - # - # parttool.py --partition-table-offset 0x8000 --partition-name storage generate_blank_partition_file --output blank.bin - # - # to generate a blank partition file and write it to a file. The blank partition file has the same size as the - # 'storage' partition. - f = "blank.bin" - invoke_args = INVOKE_ARGS + ["--partition-name", "storage", "generate_blank_partition_file", "--output", f] - subprocess.check_call(invoke_args) - return f + if not f1 == f2: + raise Exception(err) def main(): - global INVOKE_ARGS + COMPONENTS_PATH = os.path.expandvars(os.path.join("$IDF_PATH", "components")) + PARTTOOL_DIR = os.path.join(COMPONENTS_PATH, "partition_table") + + sys.path.append(PARTTOOL_DIR) + from parttool import PartitionName, PartitionType, ParttoolTarget + from gen_empty_partition import generate_blanked_file parser = argparse.ArgumentParser("ESP-IDF Partitions Tool Example") @@ -164,43 +53,53 @@ def main(): args = parser.parse_args() - if args.port: - INVOKE_ARGS += ["--port", args.port] + target = ParttoolTarget(args.port) - # Before proceeding, do checks to verify whether the app and partition table in the device matches the built binary and - # the generated partition table during build - check_app(args) - check_partition_table() + # Read app partition and save the contents to a file. The app partition is identified + # using type-subtype combination + print("Checking if device app binary matches built binary") + factory = PartitionType("app", "factory") + target.read_partition(factory, "app.bin") + assert_file_same(args.binary, "app.bin", "Device app binary does not match built binary") - # Get the offset and size of the data partition - (offset, size) = get_data_partition_info() + # Retrieve info on data storage partition, this time identifying it by name. + storage = PartitionName("storage") + storage_info = target.get_partition_info(storage) + print("Found data partition at offset 0x{:x} with size 0x{:x}".format(storage_info.offset, storage_info.size)) - print("Found data partition at offset %s with size %s" % (offset, size)) + # Create a file whose contents will be written to the storage partition + with open("write.bin", "wb") as f: + # Create a file to write to the data partition with randomly generated content + f.write(os.urandom(storage_info.size)) - # Write a generated file of random bytes to the found data partition - written = write_data_partition(size) + # Write the contents of the created file to storage partition + print("Writing to data partition") + target.write_partition(storage, "write.bin") - # Read back the contents of the data partition - read = read_data_partition() + # Read back the contents of the storage partition + print("Reading data partition") + target.read_partition(storage, "read.bin") - # Compare the written and read back data - data_same = sized_file_compare(read, written) - check(data_same, "Read contents of the data partition does not match written data") + assert_file_same("write.bin", "read.bin", "Read contents of storage partition does not match source file contents") - # Erase the data partition - erase_data_partition() + # Erase contents of the storage partition + print("Erasing data partition") + target.erase_partition(storage) - # Read back the erase data partition, which should be all 0xFF's after erasure - read = read_data_partition() + # Read back the erased data partition + print("Reading data partition") + target.read_partition(storage, "read.bin") - # Generate blank partition file (all 0xFF's) - blank = generate_blank_data_file() + # Generate a file of all 0xFF + generate_blanked_file(storage_info.size, "blank.bin") - # Verify that the partition has been erased by comparing the contents to the generated blank file - data_same = sized_file_compare(read, blank) - check(data_same, "Erased data partition contents does not match blank partition file") + assert_file_same("blank.bin", "read.bin", "Contents of storage partition not fully erased") + # Example end and cleanup print("\nPartition tool operations performed successfully!") + clean_files = ["app.bin", "read.bin", "blank.bin", "write.bin"] + for clean_file in clean_files: + os.unlink(clean_file) if __name__ == '__main__': diff --git a/examples/storage/parttool/parttool_example.sh b/examples/storage/parttool/parttool_example.sh new file mode 100644 index 0000000000..888c914686 --- /dev/null +++ b/examples/storage/parttool/parttool_example.sh @@ -0,0 +1,73 @@ +#!/bin/bash +# +# Demonstrates command-line interface of Partition Tool, parttool.py +# +# +# $1 - serial port where target device to operate on is connnected to, by default the first found valid serial port +# $2 - path to this example's built binary file (parttool.bin), by default $PWD/build/parttool.bin +PORT=$1 +PARTTOOL_PY="python $IDF_PATH/components/partition_table/parttool.py -q" + +if [[ "$PORT" != "" ]]; then + PARTTOOL_PY="$PARTTOOL_PY --port $PORT" +fi + +GEN_EMPTY_PARTITION_PY="python $IDF_PATH/components/partition_table/gen_empty_partition.py" + +BINARY=$2 + +if [[ "$BINARY" == "" ]]; then + BINARY=build/parttool.bin +fi + +function assert_file_same() +{ + sz_a=$(stat -c %s $1) + sz_b=$(stat -c %s $2) + sz=$((sz_a < sz_b ? sz_a : sz_b)) + res=$(cmp -s -n $sz $1 $2) || + (echo "!!!!!!!!!!!!!!!!!!!" + echo "FAILURE: $3" + echo "!!!!!!!!!!!!!!!!!!!") +} + +# Read app partition and save the contents to a file. The app partition is identified +# using type-subtype combination +echo "Checking if device app binary matches built binary" +$PARTTOOL_PY read_partition --partition-type=app --partition-subtype=factory --output=app.bin +assert_file_same app.bin $BINARY "Device app binary does not match built binary" + +# Retrieve info on data storage partition, this time identifying it by name. +offset=$($PARTTOOL_PY get_partition_info --partition-name=storage --info offset) +size=$($PARTTOOL_PY get_partition_info --partition-name=storage --info size) +echo "Found data partition at offset $offset with size $size" + +# Create a file whose contents will be written to the storage partition +head -c $(($size)) /dev/urandom > write.bin + +# Write the contents of the created file to storage partition +echo "Writing to data partition" +$PARTTOOL_PY write_partition --partition-name=storage --input write.bin + +# Read back the contents of the storage partition +echo "Reading data partition" +$PARTTOOL_PY read_partition --partition-name=storage --output read.bin + +assert_file_same write.bin read.bin "Read contents of storage partition does not match source file contents" + +# Erase contents of the storage partition +echo "Erasing data partition" +$PARTTOOL_PY erase_partition --partition-name=storage + +# Read back the erased data partition +echo "Reading data partition" +$PARTTOOL_PY read_partition --partition-name=storage --output read.bin + +# Generate a file of all 0xFF +$GEN_EMPTY_PARTITION_PY $(($size)) blank.bin + +assert_file_same read.bin blank.bin "Contents of storage partition not fully erased" + +# Example end and cleanup +printf "\nPartition tool operations performed successfully\n" +rm -rf app.bin read.bin blank.bin write.bin \ No newline at end of file diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index 0dc1c7fd15..f6ac3d1e7a 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -22,6 +22,7 @@ examples/build_system/cmake/idf_as_lib/build.sh examples/build_system/cmake/idf_as_lib/run-esp32.sh examples/build_system/cmake/idf_as_lib/run.sh examples/storage/parttool/parttool_example.py +examples/storage/parttool/parttool_example.sh examples/system/ota/otatool/otatool_example.py tools/check_kconfigs.py tools/check_python_dependencies.py From 7f7a9272f0f1aae4721c688f31f47957e37cb527 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Mon, 27 May 2019 11:10:00 +0800 Subject: [PATCH 022/486] examples: create example for both Python and CLI otatool interfaces --- examples/system/ota/otatool/README.md | 57 ++--- .../ota/otatool/get_running_partition.py | 87 ++++++++ .../system/ota/otatool/otatool_example.py | 194 ++++++------------ .../system/ota/otatool/otatool_example.sh | 95 +++++++++ tools/ci/executable-list.txt | 2 + 5 files changed, 275 insertions(+), 160 deletions(-) create mode 100644 examples/system/ota/otatool/get_running_partition.py create mode 100644 examples/system/ota/otatool/otatool_example.sh diff --git a/examples/system/ota/otatool/README.md b/examples/system/ota/otatool/README.md index c14e1cfb0d..9b52e8952c 100644 --- a/examples/system/ota/otatool/README.md +++ b/examples/system/ota/otatool/README.md @@ -6,7 +6,9 @@ This example demonstrates common operations the OTA tool [otatool.py](../../../c - switching boot partitions, and - switching to factory partition. -Users taking a look at this example should focus on the contents of the python script [otatool_example.py](otatool_example.py). The script contains programmatic invocations of the tool [otatool.py](../../../components/app_update/otatool.py) in Python for the operations mentioned above; and can serve as a guide for users wanting to do the same in their applications. +Users taking a look at this example should focus on the contents of the Python script [otatool_example.py](otatool_example.py) or shell script [otatool_example.sh](otatool_example.sh). The scripts contain +programmatic invocation of the tool's functions via the Python API and command-line interface, respectively. Note +that on Windows, the shell script example requires a POSIX-compatible environment via MSYS2/Git Bash/WSL etc. The built application in this example outputs the currently running partition, whose output is used to verify if the tool switched OTA partitions succesfully. The built application binary is written to all OTA partitions at the start of the example to be able to determine the running @@ -16,38 +18,46 @@ partition for all switches performed. ### Build and Flash -Before running the example script [otatool_example.py](otatool_example.py), it is necessary to build and flash the firmware using the usual means: +Before running either of the example scripts, it is necessary to build and flash the firmware using the usual means: +Make: ```bash -# If using Make make build flash +``` -# If using CMake +CMake: +```bash idf.py build flash ``` ### Running [otatool_example.py](otatool_example.py) -The example can be executed by running the script [otatool_example.py](otatool_example.py). Either run it directly using - -```bash -./otatool_example.py -``` - -or run it using +The example can be executed by running the script [otatool_example.py](otatool_example.py) or [otatool_example.sh](otatool_example.sh). +Python script: ```bash python otatool_example.py ``` -The script searches for valid target devices connected to the host and performs the operations on the first one it finds. This could present problems if there -are multiple viable target devices attached to the host. To perform the operations on a specific device, specify the port it is attached to during script invocation: +Shell script: +``` +./otatool_example.sh +``` +The script searches for valid target devices connected to the host and performs the operations on the first one it finds. This could present problems if there +are multiple viable target devices attached to the host. To perform the operations on a specific device, specify the port it is attached to during script invocation ("/dev/ttyUSB2" for example): + +Python script: ```bash -# The target device is attached to /dev/ttyUSB2, for example python otatool_example.py --port /dev/ttyUSB2 ``` + +Shell script: +``` +./otatool_example.sh /dev/ttyUSB2 +``` + ## Example output Running the script produces the following output: @@ -55,16 +65,13 @@ Running the script produces the following output: ``` Writing factory firmware to ota_0 Writing factory firmware to ota_1 -Checking written firmware to ota_0 and ota_1 match factory firmware -Switching to ota partition name factory -Switching to ota partition name factory -Switching to ota partition slot 0 -Switching to ota partition name ota_1 -Switching to ota partition slot 1 -Switching to ota partition name ota_0 -Switching to ota partition slot 0 -Switching to ota partition name factory -Switching to ota partition slot 1 +Switching to factory app +Switching to OTA slot 0 +Switching to OTA slot 1 (twice in a row) +Switching to OTA slot 0 (twice in a row) +Switching to factory app +Switching to OTA slot 1 + +Partition tool operations performed successfully -OTA tool operations executed successfully! ``` diff --git a/examples/system/ota/otatool/get_running_partition.py b/examples/system/ota/otatool/get_running_partition.py new file mode 100644 index 0000000000..b91d71a6d4 --- /dev/null +++ b/examples/system/ota/otatool/get_running_partition.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# +# Demonstrates the use of otatool.py, a tool for performing ota partition level +# operations. +# +# Copyright 2018 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. +import os +import sys +import serial +import subprocess +import re +import argparse + +from subprocess import CalledProcessError + + +def get_running_partition(port=None): + # Monitor the serial output of target device. The firmware outputs the currently + # running partition + + IDF_PATH = os.path.expandvars("$IDF_PATH") + sys.path.append(os.path.join(IDF_PATH, 'components', 'esptool_py', 'esptool')) + import esptool + + ESPTOOL_PY = os.path.join(IDF_PATH, "components", "esptool_py", "esptool", "esptool.py") + + baud = os.environ.get("ESPTOOL_BAUD", esptool.ESPLoader.ESP_ROM_BAUD) + + if not port: + error_message = "Unable to obtain default target device port.\nSerial log:\n\n" + try: + # Check what esptool.py finds on what port the device is connected to + output = subprocess.check_output([sys.executable, ESPTOOL_PY, "chip_id"]) # may raise CalledProcessError + pattern = r"Serial port ([\S]+)" + pattern = re.compile(pattern.encode()) + + port = re.search(pattern, output).group(1) # may raise AttributeError + except CalledProcessError as e: + raise Exception(error_message + e.output) + except AttributeError: + raise Exception(error_message + output) + + serial_instance = serial.serial_for_url(port.decode("utf-8"), baud, do_not_open=True) + + serial_instance.dtr = False + serial_instance.rts = False + + serial_instance.rts = True + serial_instance.open() + serial_instance.rts = False + + # Read until example end and find the currently running partition string + content = serial_instance.read_until(b"Example end") + pattern = re.compile(b"Running partition: ([a-z0-9_]+)") + running = re.search(pattern, content).group(1) + + return running.decode("utf-8") + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--port", default=None) + args = parser.parse_args() + + try: + res = get_running_partition(args.port) + except Exception as e: + print(e.message) + sys.exit(1) + + print(res) + + +if __name__ == "__main__": + main() diff --git a/examples/system/ota/otatool/otatool_example.py b/examples/system/ota/otatool/otatool_example.py index 17ed0cdb9e..b2a464eaec 100755 --- a/examples/system/ota/otatool/otatool_example.py +++ b/examples/system/ota/otatool/otatool_example.py @@ -18,20 +18,12 @@ # limitations under the License. import os import sys -import subprocess import argparse -import serial -import re -IDF_PATH = os.path.expandvars("$IDF_PATH") - -OTATOOL_PY = os.path.join(IDF_PATH, "components", "app_update", "otatool.py") -ESPTOOL_PY = os.path.join(IDF_PATH, "components", "esptool_py", "esptool", "esptool.py") - -INVOKE_ARGS = [sys.executable, OTATOOL_PY, "-q"] +from get_running_partition import get_running_partition -def sized_file_compare(file1, file2): +def assert_file_same(file1, file2, err): with open(file1, "rb") as f1: with open(file2, "rb") as f2: f1 = f1.read() @@ -42,122 +34,22 @@ def sized_file_compare(file1, file2): else: f1 = f1[:len(f2)] - return f1 == f2 + if not f1 == f2: + raise Exception(err) -def check(condition, message): - if not condition: - print("Error: " + message) - sys.exit(1) - - -def flash_example_firmware_to_ota_partitions(args): - # Invokes the command - # - # otatool.py -q write_ota_partition --slot or - # otatool.py -q write_ota_partition --name - # - # to write the contents of a file to the specified ota partition (either using name or the slot number) - print("Writing factory firmware to ota_0") - invoke_args = INVOKE_ARGS + ["write_ota_partition", "--slot", "0", "--input", args.binary] - subprocess.check_call(invoke_args) - - print("Writing factory firmware to ota_1") - invoke_args = INVOKE_ARGS + ["write_ota_partition", "--name", "ota_1", "--input", args.binary] - subprocess.check_call(invoke_args) - - # Verify that the contents of the two ota slots are the same as that of the factory partition - print("Checking written firmware to ota_0 and ota_1 match factory firmware") - - # Invokes the command - # - # otatool.py -q read_ota_partition --slot or - # otatool.py -q read_ota_partition --name - # - # to read the contents of a specified ota partition (either using name or the slot number) and write to a file - invoke_args = INVOKE_ARGS + ["read_ota_partition", "--slot", "0", "--output", "app_0.bin"] - subprocess.check_call(invoke_args) - - invoke_args = INVOKE_ARGS + ["read_ota_partition", "--name", "ota_1", "--output", "app_1.bin"] - subprocess.check_call(invoke_args) - - ota_same = sized_file_compare("app_0.bin", args.binary) - check(ota_same, "Slot 0 app does not match factory app") - - ota_same = sized_file_compare("app_1.bin", args.binary) - check(ota_same, "Slot 1 app does not match factory app") - - -def check_running_ota_partition(expected, port=None): - # Monitor the serial output of target device. The firmware outputs the currently - # running partition. It should match the partition the otatool switched to. - - if expected == 0 or expected == "ota_0": - expected = b"ota_0" - elif expected == 1 or expected == "ota_1": - expected = b"ota_1" - else: - expected = b"factory" - - sys.path.append(os.path.join(IDF_PATH, 'components', 'esptool_py', 'esptool')) - import esptool - - baud = os.environ.get("ESPTOOL_BAUD", esptool.ESPLoader.ESP_ROM_BAUD) - - if not port: - # Check what esptool.py finds on what port the device is connected to - output = subprocess.check_output([sys.executable, ESPTOOL_PY, "chip_id"]) - pattern = r"Serial port ([\S]+)" - pattern = re.compile(pattern.encode()) - port = re.search(pattern, output).group(1) - - serial_instance = serial.serial_for_url(port.decode("utf-8"), baud, do_not_open=True) - - serial_instance.dtr = False - serial_instance.rts = False - - serial_instance.rts = True - serial_instance.open() - serial_instance.rts = False - - # Read until example end and find the currently running partition string - content = serial_instance.read_until(b"Example end") - pattern = re.compile(b"Running partition: ([a-z0-9_]+)") - running = re.search(pattern, content).group(1) - - check(expected == running, "Running partition %s does not match expected %s" % (running, expected)) - - -def switch_partition(part, port): - if isinstance(part, int): - spec = "slot" - else: - spec = "name" - - print("Switching to ota partition %s %s" % (spec, str(part))) - - if str(part) == "factory": - # Invokes the command - # - # otatool.py -q erase_otadata - # - # to erase the otadata partition, effectively setting boot firmware to - # factory - subprocess.check_call(INVOKE_ARGS + ["erase_otadata"]) - else: - # Invokes the command - # - # otatool.py -q switch_otadata --slot or - # otatool.py -q switch_otadata --name - # - # to switch to the indicated ota partition (either using name or the slot number) - subprocess.check_call(INVOKE_ARGS + ["switch_otadata", "--" + spec, str(part)]) - - check_running_ota_partition(part, port) +def assert_running_partition(expected, port=None): + running = get_running_partition(port) + if running != expected: + raise Exception("Running partition %s does not match expected %s" % (running, expected)) def main(): - global INVOKE_ARGS + COMPONENTS_PATH = os.path.expandvars(os.path.join("$IDF_PATH", "components")) + OTATOOL_DIR = os.path.join(COMPONENTS_PATH, "app_update") + + sys.path.append(OTATOOL_DIR) + from otatool import OtatoolTarget parser = argparse.ArgumentParser("ESP-IDF OTA Tool Example") @@ -165,29 +57,61 @@ def main(): parser.add_argument("--binary", "-b", help="path to built example binary", default=os.path.join("build", "otatool.bin")) args = parser.parse_args() - if args.port: - INVOKE_ARGS += ["--port", args.port] + target = OtatoolTarget(args.port) - # Flash the factory firmware to all ota partitions - flash_example_firmware_to_ota_partitions(args) + print("Writing factory firmware to ota_0") + target.write_ota_partition(0, args.binary) - # Perform switching ota partitions - switch_partition("factory", args.port) - switch_partition("factory", args.port) # check switching to factory partition twice in a row + print("Writing factory firmware to ota_1") + target.write_ota_partition("ota_1", args.binary) - switch_partition(0, args.port) + # Verify that the contents of the two ota slots are the same as that of the factory partition + print("Checking written firmware to ota_0 and ota_1 match factory firmware") + target.read_ota_partition("ota_0", "app0.bin") + target.read_ota_partition(1, "app1.bin") - switch_partition("ota_1", args.port) - switch_partition(1, args.port) # check switching to ota_1 partition twice in a row + assert_file_same("app0.bin", args.binary, "Slot 0 app does not match factory app") + assert_file_same("app1.bin", args.binary, "Slot 1 app does not match factory app") - switch_partition("ota_0", args.port) - switch_partition(0, args.port) # check switching to ota_0 partition twice in a row + # Switch to factory app + print("Switching to factory app") + target.erase_otadata() + assert_running_partition("factory") - switch_partition("factory", args.port) + # Switch to slot 0 + print("Switching to OTA slot 0") + target.switch_ota_partition(0) + assert_running_partition("ota_0") - switch_partition(1, args.port) # check switching to ota_1 partition from factory + # Switch to slot 1 twice in a row + print("Switching to OTA slot 1 (twice in a row)") + target.switch_ota_partition(1) + assert_running_partition("ota_1") + target.switch_ota_partition("ota_1") + assert_running_partition("ota_1") + # Switch to slot 0 twice in a row + print("Switching to OTA slot 0 (twice in a row)") + target.switch_ota_partition(0) + assert_running_partition("ota_0") + target.switch_ota_partition("ota_0") + assert_running_partition("ota_0") + + # Switch to factory app + print("Switching to factory app") + target.erase_otadata() + assert_running_partition("factory") + + # Switch to slot 1 + print("Switching to OTA slot 1") + target.switch_ota_partition(1) + assert_running_partition("ota_1") + + # Example end and cleanup print("\nOTA tool operations executed successfully!") + clean_files = ["app0.bin", "app1.bin"] + for clean_file in clean_files: + os.unlink(clean_file) if __name__ == '__main__': diff --git a/examples/system/ota/otatool/otatool_example.sh b/examples/system/ota/otatool/otatool_example.sh new file mode 100644 index 0000000000..bcf8456dcc --- /dev/null +++ b/examples/system/ota/otatool/otatool_example.sh @@ -0,0 +1,95 @@ +#!/bin/bash +# +# Demonstrates command-line interface of OTA Partitions Tool, otatool.py +# +# +# $1 - serial port where target device to operate on is connnected to, by default the first found valid serial port +# $2 - path to this example's built binary file (parttool.bin), by default $PWD/build/otatool.bin + +PORT=$1 +OTATOOL_PY="python $IDF_PATH/components/app_update/otatool.py -q" + +if [[ "$PORT" != "" ]]; then + OTATOOL_PY="$OTATOOL_PY --port $PORT" +fi + +BINARY=$2 + +if [[ "$BINARY" == "" ]]; then + BINARY=build/otatool.bin +fi + +function assert_file_same() +{ + sz_a=$(stat -c %s $1) + sz_b=$(stat -c %s $2) + sz=$((sz_a < sz_b ? sz_a : sz_b)) + res=$(cmp -s -n $sz $1 $2) || + (echo "!!!!!!!!!!!!!!!!!!!" + echo "FAILURE: $3" + echo "!!!!!!!!!!!!!!!!!!!") +} + +function assert_running_partition() +{ + running=$(python get_running_partition.py) + if [[ "$running" != "$1" ]]; then + echo "!!!!!!!!!!!!!!!!!!!" + echo "FAILURE: Running partition '$running' does not match expected '$1'" + echo "!!!!!!!!!!!!!!!!!!!" + exit 1 + fi +} + +# Flash the example firmware to OTA partitions. The first write uses slot number to identify OTA +# partition, the second one uses the name. +echo "Writing factory firmware to ota_0" +$OTATOOL_PY write_ota_partition --slot 0 --input $BINARY + +echo "Writing factory firmware to ota_1" +$OTATOOL_PY write_ota_partition --name ota_1 --input $BINARY + +# Read back the written firmware +$OTATOOL_PY read_ota_partition --name ota_0 --output app0.bin +$OTATOOL_PY read_ota_partition --slot 1 --output app1.bin + +assert_file_same $BINARY app0.bin "Slot 0 app does not match factory app" +assert_file_same $BINARY app1.bin "Slot 1 app does not match factory app" + +# Switch to factory app +echo "Switching to factory app" +$OTATOOL_PY erase_otadata +assert_running_partition factory + +# Switch to slot 0 +echo "Switching to OTA slot 0" +$OTATOOL_PY switch_ota_partition --slot 0 +assert_running_partition ota_0 + +# Switch to slot 1 twice in a row +echo "Switching to OTA slot 1 (twice in a row)" +$OTATOOL_PY switch_ota_partition --slot 1 +assert_running_partition ota_1 +$OTATOOL_PY switch_ota_partition --name ota_1 +assert_running_partition ota_1 + +# Switch to slot 0 twice in a row +echo "Switching to OTA slot 0 (twice in a row)" +$OTATOOL_PY switch_ota_partition --slot 0 +assert_running_partition ota_0 +$OTATOOL_PY switch_ota_partition --name ota_0 +assert_running_partition ota_0 + +# Switch to factory app +echo "Switching to factory app" +$OTATOOL_PY erase_otadata +assert_running_partition factory + +# Switch to slot 1 +echo "Switching to OTA slot 1" +$OTATOOL_PY switch_ota_partition --slot 1 +assert_running_partition ota_1 + +# Example end and cleanup +printf "\nPartition tool operations performed successfully\n" +rm -rf app0.bin app1.bin \ No newline at end of file diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index f6ac3d1e7a..e0637d9bf8 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -23,7 +23,9 @@ examples/build_system/cmake/idf_as_lib/run-esp32.sh examples/build_system/cmake/idf_as_lib/run.sh examples/storage/parttool/parttool_example.py examples/storage/parttool/parttool_example.sh +examples/system/ota/otatool/get_running_partition.py examples/system/ota/otatool/otatool_example.py +examples/system/ota/otatool/otatool_example.sh tools/check_kconfigs.py tools/check_python_dependencies.py tools/ci/apply_bot_filter.py From 3836aa9ae679a3de7a220cd6142097a1bb4020bf Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Tue, 4 Jun 2019 15:49:55 +0800 Subject: [PATCH 023/486] partition_table,app_update: use config partition table offset --- components/app_update/CMakeLists.txt | 10 ++++++++-- components/app_update/Makefile.projbuild | 8 ++++++-- components/partition_table/Makefile.projbuild | 5 +++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/components/app_update/CMakeLists.txt b/components/app_update/CMakeLists.txt index e869c188fb..6e48af6942 100644 --- a/components/app_update/CMakeLists.txt +++ b/components/app_update/CMakeLists.txt @@ -42,10 +42,16 @@ if(NOT BOOTLOADER_BUILD) set(otatool_py ${python} ${COMPONENT_DIR}/otatool.py) add_custom_target(read_otadata DEPENDS "${PARTITION_CSV_PATH}" - COMMAND ${otatool_py} --partition-table-file ${PARTITION_CSV_PATH} read_otadata) + COMMAND ${otatool_py} + --partition-table-file ${PARTITION_CSV_PATH} + --partition-table-offset ${PARTITION_TABLE_OFFSET} + read_otadata) add_custom_target(erase_otadata DEPENDS "${PARTITION_CSV_PATH}" - COMMAND ${otatool_py} --partition-table-file ${PARTITION_CSV_PATH} erase_otadata) + COMMAND ${otatool_py} + --partition-table-file ${PARTITION_CSV_PATH} + --partition-table-offset ${PARTITION_TABLE_OFFSET} + erase_otadata) esptool_py_flash_project_args(otadata ${otadata_offset} "${blank_otadata_file}" FLASH_IN_PROJECT) endif() diff --git a/components/app_update/Makefile.projbuild b/components/app_update/Makefile.projbuild index a20856a6ef..a3f2f68423 100644 --- a/components/app_update/Makefile.projbuild +++ b/components/app_update/Makefile.projbuild @@ -29,10 +29,14 @@ blank_ota_data: $(BLANK_OTA_DATA_FILE) ESPTOOL_ALL_FLASH_ARGS += $(OTA_DATA_OFFSET) $(BLANK_OTA_DATA_FILE) erase_otadata: $(PARTITION_TABLE_CSV_PATH) partition_table_get_info | check_python_dependencies - $(OTATOOL_PY) --partition-table-file $(PARTITION_TABLE_CSV_PATH) erase_otadata + $(OTATOOL_PY) --partition-table-file $(PARTITION_TABLE_CSV_PATH) \ + --partition-table-offset $(PARTITION_TABLE_OFFSET) \ + erase_otadata read_otadata: $(PARTITION_TABLE_CSV_PATH) partition_table_get_info | check_python_dependencies - $(OTATOOL_PY) --partition-table-file $(PARTITION_TABLE_CSV_PATH) read_otadata + $(OTATOOL_PY) --partition-table-file $(PARTITION_TABLE_CSV_PATH) \ + --partition-table-offset $(partition_table_offset) \ + read_otadata erase_ota: erase_otadata @echo "WARNING: erase_ota is deprecated. Use erase_otadata instead." diff --git a/components/partition_table/Makefile.projbuild b/components/partition_table/Makefile.projbuild index 353a7655d6..6b28b093f5 100644 --- a/components/partition_table/Makefile.projbuild +++ b/components/partition_table/Makefile.projbuild @@ -64,14 +64,19 @@ all_binaries: $(PARTITION_TABLE_BIN) partition_table_get_info check_table_conten partition_table_get_info: $(PARTITION_TABLE_BIN) $(eval PHY_DATA_OFFSET:=$(shell $(GET_PART_INFO) --partition-table-file $(PARTITION_TABLE_BIN) \ + --partition-table-offset $(PARTITION_TABLE_OFFSET) \ get_partition_info --partition-type data --partition-subtype phy --info offset)) $(eval APP_OFFSET:=$(shell $(GET_PART_INFO) --partition-table-file $(PARTITION_TABLE_BIN) \ + --partition-table-offset $(PARTITION_TABLE_OFFSET) \ get_partition_info --partition-boot-default --info offset)) $(eval OTA_DATA_OFFSET:=$(shell $(GET_PART_INFO) --partition-table-file $(PARTITION_TABLE_BIN) \ + --partition-table-offset $(PARTITION_TABLE_OFFSET) \ get_partition_info --partition-type data --partition-subtype ota --info offset)) $(eval OTA_DATA_SIZE:=$(shell $(GET_PART_INFO) --partition-table-file $(PARTITION_TABLE_BIN) \ + --partition-table-offset $(PARTITION_TABLE_OFFSET) \ get_partition_info --partition-type data --partition-subtype ota --info size)) $(eval FACTORY_OFFSET:=$(shell $(GET_PART_INFO) --partition-table-file $(PARTITION_TABLE_BIN) \ + --partition-table-offset $(PARTITION_TABLE_OFFSET) \ get_partition_info --partition-type app --partition-subtype factory --info offset)) export APP_OFFSET From f59c3e7e3e20a0527916d1b7acbe9219eeadb162 Mon Sep 17 00:00:00 2001 From: Andrey Gramakov Date: Wed, 22 May 2019 12:11:25 +0300 Subject: [PATCH 024/486] Updated building-openocd-windows.rst instruction --- .../building-openocd-windows.rst | 86 +++++++++++++------ 1 file changed, 62 insertions(+), 24 deletions(-) diff --git a/docs/en/api-guides/jtag-debugging/building-openocd-windows.rst b/docs/en/api-guides/jtag-debugging/building-openocd-windows.rst index a04b89df62..2452235176 100644 --- a/docs/en/api-guides/jtag-debugging/building-openocd-windows.rst +++ b/docs/en/api-guides/jtag-debugging/building-openocd-windows.rst @@ -5,9 +5,27 @@ Building OpenOCD from Sources for Windows The following instructions are alternative to downloading binary OpenOCD from `Espressif GitHub `_. To quickly setup the binary OpenOCD, instead of compiling it yourself, backup and proceed to section :doc:`setup-openocd-windows`. - .. highlight:: bash +.. note:: + + Following instructions are assumed to be runned in MSYS2 environment with MINGW32 subsystem! + + +Install Dependencies +==================== + +Install packages that are required to compile OpenOCD:: + + pacman -S --noconfirm --needed autoconf automake git make \ + mingw-w64-i686-gcc \ + mingw-w64-i686-toolchain \ + mingw-w64-i686-libtool \ + mingw-w64-i686-pkg-config \ + mingw-w64-cross-winpthreads-git \ + p7zip + + Download Sources of OpenOCD =========================== @@ -16,30 +34,20 @@ The sources for the ESP32-enabled variant of OpenOCD are available from Espressi cd ~/esp git clone --recursive https://github.com/espressif/openocd-esp32.git + The clone of sources should be now saved in ``~/esp/openocd-esp32`` directory. -Install Dependencies -==================== +Downloading libusb +================== -Install packages that are required to compile OpenOCD: +Build and export variables for a following OpenOCD compilation:: -.. note:: + wget https://github.com/libusb/libusb/releases/download/v1.0.22/libusb-1.0.22.7z + 7z x -olibusb ./libusb-1.0.22.7z + export CPPFLAGS="$CPPFLAGS -I${PWD}/libusb/include/libusb-1.0" + export LDFLAGS="$LDFLAGS -L${PWD}/libusb/MinGW32/.libs/dll" - Install the following packages one by one, check if installation was successful and then proceed to the next package. Resolve reported problems before moving to the next step. - -:: - - pacman -S libtool - pacman -S autoconf - pacman -S automake - pacman -S texinfo - pacman -S mingw-w64-i686-libusb-compat-git - pacman -S pkg-config - -.. note:: - - Installation of ``pkg-config`` is breaking operation of esp-idf toolchain. After building of OpenOCD it should be uninstalled. It be covered at the end of this instruction. To build OpenOCD again, you will need to run ``pacman -S pkg-config`` once more. This issue does not concern other packages installed in this step (before ``pkg-config``). Build OpenOCD @@ -48,11 +56,15 @@ Build OpenOCD Proceed with configuring and building OpenOCD:: cd ~/esp/openocd-esp32 + export CPPFLAGS="$CPPFLAGS -D__USE_MINGW_ANSI_STDIO=1 -Wno-error"; export CFLAGS="$CFLAGS -Wno-error" ./bootstrap - ./configure + ./configure --disable-doxygen-pdf --enable-ftdi --enable-jlink --enable-ulink --build=i686-w64-mingw32 --host=i686-w64-mingw32 make + cp ../libusb/MinGW32/dll/libusb-1.0.dll ./src + cp /opt/i686-w64-mingw32/bin/libwinpthread-1.dll ./src + -Optionally you can add ``make install`` step at the end. Skip it, if you have an existing OpenOCD (from e.g. another development platform), as it may get overwritten. +Optionally you can add ``make install`` step at the end. Skip it, if you have an existing OpenOCD (from e.g. another development platform), as it may get overwritten. Also you could use ``export DESTDIR="/custom/install/dir"; make install``. .. note:: @@ -61,12 +73,38 @@ Optionally you can add ``make install`` step at the end. Skip it, if you have an * If the ``./configure`` is successfully run, information of enabled JTAG will be printed under ``OpenOCD configuration summary``. * If the information of your device is not shown in the log, use ``./configure`` to enable it as described in ``../openocd-esp32/doc/INSTALL.txt``. * For details concerning compiling OpenOCD, please refer to ``openocd-esp32/README.Windows``. + * Don't forget to copy `libusb-1.0.dll` and `libwinpthread-1.dll` into `OOCD_INSTALLDIR/bin` from ``~/esp/openocd-esp32/src``. -Once ``make`` process is successfully completed, the executable of OpenOCD will be saved in ``~/esp/openocd-esp32/src/openocd`` directory. +Once ``make`` process is successfully completed, the executable of OpenOCD will be saved in ``~/esp/openocd-esp32/src`` directory. -Remove ``pkg-config``, as discussed during installation of dependencies:: - pacman -Rs pkg-config +Full Listing +============ + +A complete described previously process is provided below for the faster execution, e.g. as a shell script:: + + pacman -S --noconfirm --needed autoconf automake git make mingw-w64-i686-gcc mingw-w64-i686-toolchain mingw-w64-i686-libtool mingw-w64-i686-pkg-config mingw-w64-cross-winpthreads-git p7zip + cd ~/esp + git clone --recursive https://github.com/espressif/openocd-esp32.git + + wget https://github.com/libusb/libusb/releases/download/v1.0.22/libusb-1.0.22.7z + 7z x -olibusb ./libusb-1.0.22.7z + export CPPFLAGS="$CPPFLAGS -I${PWD}/libusb/include/libusb-1.0"; export LDFLAGS="$LDFLAGS -L${PWD}/libusb/MinGW32/.libs/dll" + + export CPPFLAGS="$CPPFLAGS -D__USE_MINGW_ANSI_STDIO=1 -Wno-error"; export CFLAGS="$CFLAGS -Wno-error" + cd ~/esp/openocd-esp32 + ./bootstrap + ./configure --disable-doxygen-pdf --enable-ftdi --enable-jlink --enable-ulink --build=i686-w64-mingw32 --host=i686-w64-mingw32 + make + cp ../libusb/MinGW32/dll/libusb-1.0.dll ./src + cp /opt/i686-w64-mingw32/bin/libwinpthread-1.dll ./src + + # # optional + # export DESTDIR="$PWD" + # make install + # cp ./src/libusb-1.0.dll $DESTDIR/mingw32/bin + # cp ./src/libwinpthread-1.dll $DESTDIR/mingw32/bin + Next Steps From 33dd7011be064abf94e3c6e80887684796df4b40 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Fri, 24 May 2019 18:32:42 +0800 Subject: [PATCH 025/486] cmake: expand build components before generating config !4452 had config generation first before building the component list to be used in the build. This proved to be detrimental when a new target is added as config generation would consider configs from both targets. --- tools/cmake/build.cmake | 13 +++++++------ tools/cmake/kconfig.cmake | 17 ++++++++++------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/tools/cmake/build.cmake b/tools/cmake/build.cmake index 585d26e195..97c43e8a23 100644 --- a/tools/cmake/build.cmake +++ b/tools/cmake/build.cmake @@ -365,12 +365,6 @@ macro(idf_build_process target) # Check for required Python modules __build_check_python() - # Generate config values in different formats - idf_build_get_property(sdkconfig SDKCONFIG) - idf_build_get_property(sdkconfig_defaults SDKCONFIG_DEFAULTS) - __kconfig_generate_config("${sdkconfig}" "${sdkconfig_defaults}") - __build_import_configs() - # Write the partial build properties to a temporary file. # The path to this generated file is set to a short-lived build # property BUILD_PROPERTIES_FILE. @@ -416,6 +410,7 @@ macro(idf_build_process target) idf_build_unset_property(BUILD_PROPERTIES_FILE) file(REMOVE ${build_properties_file}) + # Finally, do component expansion. In this case it simply means getting a final list # of build component targets given the requirements set by each component. if(__COMPONENTS) @@ -442,6 +437,12 @@ macro(idf_build_process target) idf_build_set_property(___COMPONENT_REQUIRES_COMMON ${lib} APPEND) endforeach() + # Generate config values in different formats + idf_build_get_property(sdkconfig SDKCONFIG) + idf_build_get_property(sdkconfig_defaults SDKCONFIG_DEFAULTS) + __kconfig_generate_config("${sdkconfig}" "${sdkconfig_defaults}") + __build_import_configs() + # Temporary trick to support both gcc5 and gcc8 builds if(CMAKE_C_COMPILER_VERSION VERSION_EQUAL 5.2.0) set(GCC_NOT_5_2_0 0 CACHE STRING "GCC is 5.2.0 version") diff --git a/tools/cmake/kconfig.cmake b/tools/cmake/kconfig.cmake index 020e595509..28be99371e 100644 --- a/tools/cmake/kconfig.cmake +++ b/tools/cmake/kconfig.cmake @@ -88,14 +88,17 @@ endfunction() function(__kconfig_generate_config sdkconfig sdkconfig_defaults) # List all Kconfig and Kconfig.projbuild in known components idf_build_get_property(component_targets __COMPONENT_TARGETS) + idf_build_get_property(build_component_targets __BUILD_COMPONENT_TARGETS) foreach(component_target ${component_targets}) - __component_get_property(kconfig ${component_target} KCONFIG) - __component_get_property(kconfig_projbuild ${component_target} KCONFIG_PROJBUILD) - if(kconfig) - list(APPEND kconfigs ${kconfig}) - endif() - if(kconfig_projbuild) - list(APPEND kconfig_projbuilds ${kconfig_projbuild}) + if(component_target IN_LIST build_component_targets) + __component_get_property(kconfig ${component_target} KCONFIG) + __component_get_property(kconfig_projbuild ${component_target} KCONFIG_PROJBUILD) + if(kconfig) + list(APPEND kconfigs ${kconfig}) + endif() + if(kconfig_projbuild) + list(APPEND kconfig_projbuilds ${kconfig_projbuild}) + endif() endif() endforeach() From 297b2c5a3974b376bb17dc3785e8ffffb2701913 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Tue, 28 May 2019 21:43:03 +0800 Subject: [PATCH 026/486] cmake: evaluate component requirements in one go !4452 simplified early expansion by using an early expansion script that only does one thing: get the public and private requirements for each component, albeit one by one. This was also dependent on parsing the command output of the expansion script. This commit makes it so that a list of all components to be processed to passed to the expansion script, generating a cmake file that sets each component requirements in one go. This also makes sure that only components that registered themselves get included in the final build list. --- tools/cmake/build.cmake | 46 ++-------- tools/cmake/component.cmake | 58 ++++++------ .../scripts/component_get_requirements.cmake | 88 +++++++++++++++---- 3 files changed, 107 insertions(+), 85 deletions(-) diff --git a/tools/cmake/build.cmake b/tools/cmake/build.cmake index 97c43e8a23..6cf9a73b55 100644 --- a/tools/cmake/build.cmake +++ b/tools/cmake/build.cmake @@ -195,7 +195,8 @@ function(__build_expand_requirements component_target) # Since there are circular dependencies, make sure that we do not infinitely # expand requirements for each component. idf_build_get_property(component_targets_seen __COMPONENT_TARGETS_SEEN) - if(component_target IN_LIST component_targets_seen) + __component_get_property(component_registered ${component_target} __COMPONENT_REGISTERED) + if(component_target IN_LIST component_targets_seen OR NOT component_registered) return() endif() @@ -365,51 +366,13 @@ macro(idf_build_process target) # Check for required Python modules __build_check_python() - # Write the partial build properties to a temporary file. - # The path to this generated file is set to a short-lived build - # property BUILD_PROPERTIES_FILE. - idf_build_get_property(build_dir BUILD_DIR) - set(build_properties_file ${build_dir}/build_properties.temp.cmake) - idf_build_set_property(BUILD_PROPERTIES_FILE ${build_properties_file}) - __build_write_properties(${build_properties_file}) + idf_build_set_property(__COMPONENT_REQUIRES_COMMON ${target} APPEND) + __component_get_requirements() # Perform early expansion of component CMakeLists.txt in CMake scripting mode. # It is here we retrieve the public and private requirements of each component. # It is also here we add the common component requirements to each component's # own requirements. - idf_build_get_property(component_targets __COMPONENT_TARGETS) - idf_build_set_property(__COMPONENT_REQUIRES_COMMON ${target} APPEND) - idf_build_get_property(common_reqs __COMPONENT_REQUIRES_COMMON) - foreach(component_target ${component_targets}) - get_property(component_dir TARGET ${component_target} PROPERTY COMPONENT_DIR) - __component_get_requirements(error reqs priv_reqs ${component_dir}) - if(error) - message(FATAL_ERROR "${error}") - endif() - - list(APPEND reqs "${common_reqs}") - - # Remove duplicates and the component itself from its requirements - __component_get_property(alias ${component_target} COMPONENT_ALIAS) - __component_get_property(_name ${component_target} COMPONENT_NAME) - - # Prevent component from linking to itself. - if(reqs) - list(REMOVE_DUPLICATES reqs) - list(REMOVE_ITEM reqs ${alias} ${_name}) - endif() - - if(priv_reqs) - list(REMOVE_DUPLICATES priv_reqs) - list(REMOVE_ITEM priv_reqs ${alias} ${_name}) - endif() - - __component_set_property(${component_target} REQUIRES "${reqs}") - __component_set_property(${component_target} PRIV_REQUIRES "${priv_reqs}") - endforeach() - idf_build_unset_property(BUILD_PROPERTIES_FILE) - file(REMOVE ${build_properties_file}) - # Finally, do component expansion. In this case it simply means getting a final list # of build component targets given the requirements set by each component. @@ -431,6 +394,7 @@ macro(idf_build_process target) # Get a list of common component requirements in component targets form (previously # we just have a list of component names) + idf_build_get_property(common_reqs __COMPONENT_REQUIRES_COMMON) foreach(common_req ${common_reqs}) __component_get_target(component_target ${common_req}) __component_get_property(lib ${component_target} COMPONENT_LIB) diff --git a/tools/cmake/component.cmake b/tools/cmake/component.cmake index b3dd460c83..6caca93a74 100644 --- a/tools/cmake/component.cmake +++ b/tools/cmake/component.cmake @@ -125,6 +125,23 @@ function(__component_dir_quick_check var component_dir) set(${var} ${res} PARENT_SCOPE) endfunction() +# +# Write a CMake file containing all component and their properties. This is possible because each component +# keeps a list of all its properties. +# +function(__component_write_properties output_file) + idf_build_get_property(component_targets __COMPONENT_TARGETS) + foreach(component_target ${component_targets}) + __component_get_property(component_properties ${component_target} __COMPONENT_PROPERTIES) + foreach(property ${component_properties}) + __component_get_property(val ${component_target} ${property}) + set(component_properties_text + "${component_properties_text}\nset(__component_${component_target}_${property} ${val})") + endforeach() + file(WRITE ${output_file} "${component_properties_text}") + endforeach() +endfunction() + # # Add a component to process in the build. The components are keeped tracked of in property # __COMPONENT_TARGETS in component target form. @@ -184,44 +201,35 @@ endfunction() # Given a component directory, get the requirements by expanding it early. The expansion is performed # using a separate CMake script (the expansion is performed in a separate instance of CMake in scripting mode). # -function(__component_get_requirements error requires_var priv_requires_var component_dir) +function(__component_get_requirements) idf_build_get_property(idf_path IDF_PATH) - idf_build_get_property(build_properties_file BUILD_PROPERTIES_FILE) - idf_build_get_property(idf_target IDF_TARGET) - # This function assumes that the directory has been checked to contain a component, thus - # no check is performed here. + idf_build_get_property(build_dir BUILD_DIR) + set(build_properties_file ${build_dir}/build_properties.temp.cmake) + set(component_properties_file ${build_dir}/component_properties.temp.cmake) + set(component_requires_file ${build_dir}/component_requires.temp.cmake) + + __build_write_properties(${build_properties_file}) + __component_write_properties(${component_properties_file}) + execute_process(COMMAND "${CMAKE_COMMAND}" - -D "IDF_PATH=${idf_path}" - -D "IDF_TARGET=${idf_target}" - -D "COMPONENT_DIR=${component_dir}" -D "BUILD_PROPERTIES_FILE=${build_properties_file}" - -D "CMAKE_BUILD_EARLY_EXPANSION=1" + -D "COMPONENT_PROPERTIES_FILE=${component_properties_file}" + -D "COMPONENT_REQUIRES_FILE=${component_requires_file}" -P "${idf_path}/tools/cmake/scripts/component_get_requirements.cmake" RESULT_VARIABLE result ERROR_VARIABLE error ) if(NOT result EQUAL 0) - set(error "${error}" PARENT_SCOPE) - return() + message(FATAL_ERROR "${error}") endif() - string(REGEX REPLACE ";" "\\\\;" _output "${error}") - string(REGEX REPLACE "\n" ";" _output "${_output}") - list(REVERSE _output) + include(${component_requires_file}) - if(_output) - list(GET _output 1 _output) - - string(REGEX MATCH "\(.*\):::\(.*\)" _output "${_output}") - - string(REPLACE ":" ";" requires "${CMAKE_MATCH_1}") - string(REPLACE ":" ";" priv_requires "${CMAKE_MATCH_2}") - endif() - - set(${requires_var} ${requires} PARENT_SCOPE) - set(${priv_requires_var} ${priv_requires} PARENT_SCOPE) + file(REMOVE ${build_properties_file}) + file(REMOVE ${component_properties_file}) + file(REMOVE ${component_requires_file}) endfunction() # __component_add_sources, __component_check_target diff --git a/tools/cmake/scripts/component_get_requirements.cmake b/tools/cmake/scripts/component_get_requirements.cmake index 8223f709be..0b0d18727e 100644 --- a/tools/cmake/scripts/component_get_requirements.cmake +++ b/tools/cmake/scripts/component_get_requirements.cmake @@ -1,10 +1,5 @@ -include(${IDF_PATH}/tools/cmake/utilities.cmake) - include("${BUILD_PROPERTIES_FILE}") -include("${SDKCONFIG_CMAKE}") - -macro(require_idf_targets) -endmacro() +include("${COMPONENT_PROPERTIES_FILE}") function(idf_build_get_property var property) cmake_parse_arguments(_ "GENERATOR_EXPRESSION" "" "" ${ARGN}) @@ -12,17 +7,20 @@ function(idf_build_get_property var property) message(FATAL_ERROR "Getting build property generator expression not supported before idf_component_register().") endif() - set(${var} ${property} PARENT_SCOPE) + set(${var} ${${property}} PARENT_SCOPE) endfunction() -function(print_requires requires priv_requires) - spaces2list(requires) - spaces2list(priv_requires) - string(REPLACE ";" ":" requires "${requires}") - string(REPLACE ";" ":" priv_requires "${priv_requires}") - message("${requires}:::${priv_requires}") +idf_build_get_property(idf_path IDF_PATH) +include(${idf_path}/tools/cmake/utilities.cmake) + +function(__component_get_property var component_target property) + set(_property __component_${component_target}_${property}) + set(${var} ${${_property}} PARENT_SCOPE) endfunction() +macro(require_idf_targets) +endmacro() + macro(idf_component_register) set(options) set(single_value) @@ -30,14 +28,16 @@ macro(idf_component_register) INCLUDE_DIRS PRIV_INCLUDE_DIRS LDFRAGMENTS REQUIRES PRIV_REQUIRES REQUIRED_IDF_TARGETS EMBED_FILES EMBED_TXTFILES) cmake_parse_arguments(_ "${options}" "${single_value}" "${multi_value}" "${ARGN}") - print_requires("${__REQUIRES}" "${__PRIV_REQUIRES}") - set(__is_component 1) + set(__component_requires "${__REQUIRES}") + set(__component_priv_requires "${__PRIV_REQUIRES}") + set(__component_registered 1) return() endmacro() macro(register_component) - print_requires("${COMPONENT_REQUIRES}" "${COMPONENT_PRIV_REQUIRES}") - set(__is_component 1) + set(__component_requires "${COMPONENT_REQUIRES}") + set(__component_priv_requires "${COMPONENT_PRIV_REQUIRES}") + set(__component_registered 1) return() endmacro() @@ -45,5 +45,55 @@ macro(register_config_only_component) register_component() endmacro() -set(CMAKE_BUILD_EARLY_EXPANSION) -include(${COMPONENT_DIR}/CMakeLists.txt OPTIONAL) +idf_build_get_property(__common_reqs __COMPONENT_REQUIRES_COMMON) +idf_build_get_property(__component_targets __COMPONENT_TARGETS) + +function(__component_get_requirements) + # This is in a function (separate variable context) so that variables declared + # and set by the included CMakeLists.txt does not bleed into the next inclusion. + # We are only interested in the public and private requirements of components + __component_get_property(__component_dir ${__component_target} COMPONENT_DIR) + include(${__component_dir}/CMakeLists.txt OPTIONAL) + + spaces2list(__component_requires) + spaces2list(__component_priv_requires) + + set(__component_requires "${__component_requires}" PARENT_SCOPE) + set(__component_priv_requires "${__component_priv_requires}" PARENT_SCOPE) + set(__component_registered ${__component_registered} PARENT_SCOPE) +endfunction() + +set(CMAKE_BUILD_EARLY_EXPANSION 1) +foreach(__component_target ${__component_targets}) + set(__component_requires "") + set(__component_priv_requires "") + set(__component_registered 0) + + __component_get_requirements() + + list(APPEND __component_requires "${__common_reqs}") + + # Remove duplicates and the component itself from its requirements + __component_get_property(__component_alias ${__component_target} COMPONENT_ALIAS) + __component_get_property(__component_name ${__component_target} COMPONENT_NAME) + + # Prevent component from linking to itself. + if(__component_requires) + list(REMOVE_DUPLICATES __component_requires) + list(REMOVE_ITEM __component_requires ${__component_alias} ${__component_name}) + endif() + + if(__component_requires) + list(REMOVE_DUPLICATES __component_priv_requires) + list(REMOVE_ITEM __component_priv_requires ${__component_alias} ${__component_name}) + endif() + + set(__contents +"__component_set_property(${__component_target} REQUIRES \"${__component_requires}\") +__component_set_property(${__component_target} PRIV_REQUIRES \"${__component_priv_requires}\") +__component_set_property(${__component_target} __COMPONENT_REGISTERED ${__component_registered})" + ) + set(__component_requires_contents "${__component_requires_contents}\n${__contents}") +endforeach() + +file(WRITE ${COMPONENT_REQUIRES_FILE} "${__component_requires_contents}") \ No newline at end of file From 70dfcb35d44430256cb56c9c7ec21cfdcc8639c8 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Tue, 4 Jun 2019 20:19:25 +0800 Subject: [PATCH 027/486] mbedtls: component CMakeLists.txt corrections Since !4452 the common component requirements automatically get privately linked to libraries built under ESP-IDF build system (this includes targets from third-party libraries). This removes a variable that was used for that purpose before !4452. Since the internal target names were changed, the compile definition for warning on using deprecated functions is not being passed. Since using the internal name is unreliable, prefer passing this compile definition from the test itself. --- components/mbedtls/CMakeLists.txt | 9 +-------- components/mbedtls/test/CMakeLists.txt | 6 ++++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/components/mbedtls/CMakeLists.txt b/components/mbedtls/CMakeLists.txt index 3b1fd504e2..44af366f45 100644 --- a/components/mbedtls/CMakeLists.txt +++ b/components/mbedtls/CMakeLists.txt @@ -2,8 +2,6 @@ set(COMPONENT_ADD_INCLUDEDIRS "port/include" "mbedtls/include") set(COMPONENT_SRCS "mbedtls.c") set(COMPONENT_REQUIRES lwip) -set(MBEDTLS_PRIV_REQUIRES ${IDF_COMPONENT_REQUIRES_COMMON} soc) - register_component() # Only build mbedtls libraries @@ -96,9 +94,4 @@ foreach(target ${mbedtls_targets}) endforeach() # Link mbedtls libraries to component library -target_link_libraries(${COMPONENT_LIB} ${mbedtls_targets}) - -# Catch usage of deprecated mbedTLS functions when building tests -if(mbedtls_test IN_LIST BUILD_TEST_COMPONENTS) - add_definitions(-DMBEDTLS_DEPRECATED_WARNING) -endif() \ No newline at end of file +target_link_libraries(${COMPONENT_LIB} ${mbedtls_targets}) \ No newline at end of file diff --git a/components/mbedtls/test/CMakeLists.txt b/components/mbedtls/test/CMakeLists.txt index e1aad74fac..5a8cfd8d33 100644 --- a/components/mbedtls/test/CMakeLists.txt +++ b/components/mbedtls/test/CMakeLists.txt @@ -4,3 +4,9 @@ set(COMPONENT_ADD_INCLUDEDIRS ".") set(COMPONENT_REQUIRES unity test_utils mbedtls) register_component() + +idf_component_get_property(mbedtls mbedtls COMPONENT_LIB) +target_compile_definitions(${mbedtls} PUBLIC "-DMBEDTLS_DEPRECATED_WARNING") +target_compile_definitions(mbedtls PUBLIC "-DMBEDTLS_DEPRECATED_WARNING") +target_compile_definitions(mbedcrypto PUBLIC "-DMBEDTLS_DEPRECATED_WARNING") +target_compile_definitions(mbedx509 PUBLIC "-DMBEDTLS_DEPRECATED_WARNING") From f0f861ccd9912f93a43b51037655e4cb5bfb0127 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Fri, 31 May 2019 11:30:44 +0800 Subject: [PATCH 028/486] ldgen: use user input filename for processed template Previously ldgen determines the output file name on its own. This commit makes it so that user can dictate what the output file name will be for the processed template, if the user needs it for something else. --- components/esp32/CMakeLists.txt | 3 ++- tools/cmake/ldgen.cmake | 7 +------ tools/cmake/utilities.cmake | 5 +++-- tools/ldgen/ldgen.py | 10 ++++++++++ 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/components/esp32/CMakeLists.txt b/components/esp32/CMakeLists.txt index 3710237896..0fca8aa0c0 100644 --- a/components/esp32/CMakeLists.txt +++ b/components/esp32/CMakeLists.txt @@ -58,7 +58,8 @@ else() # Process the template file through the linker script generation mechanism, and use the output for linking the # final binary - target_linker_script(${COMPONENT_LIB} "${CMAKE_CURRENT_LIST_DIR}/ld/esp32.project.ld.in" PROCESS) + target_linker_script(${COMPONENT_LIB} "${CMAKE_CURRENT_LIST_DIR}/ld/esp32.project.ld.in" + PROCESS "${CMAKE_CURRENT_BINARY_DIR}/ld/esp32.project.ld") target_linker_script(${COMPONENT_LIB} "ld/esp32.peripherals.ld") target_link_libraries(${COMPONENT_LIB} gcc) diff --git a/tools/cmake/ldgen.cmake b/tools/cmake/ldgen.cmake index 9161ecd8f1..b8cfaad499 100644 --- a/tools/cmake/ldgen.cmake +++ b/tools/cmake/ldgen.cmake @@ -27,7 +27,7 @@ endfunction() # # Passes a linker script template to the linker script generation tool for # processing -function(__ldgen_process_template output_var template) +function(__ldgen_process_template template output) idf_build_get_property(idf_target IDF_TARGET) idf_build_get_property(idf_path IDF_PATH) @@ -36,11 +36,6 @@ function(__ldgen_process_template output_var template) file(GENERATE OUTPUT ${build_dir}/ldgen_libraries.in CONTENT $) file(GENERATE OUTPUT ${build_dir}/ldgen_libraries INPUT ${build_dir}/ldgen_libraries.in) - get_filename_component(filename "${template}" NAME) - - set(output ${CMAKE_CURRENT_BINARY_DIR}/${filename}.ld) - set(${output_var} ${output} PARENT_SCOPE) - set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${build_dir}/ldgen_libraries.in" diff --git a/tools/cmake/utilities.cmake b/tools/cmake/utilities.cmake index 4e64c16201..f5f7f9693c 100644 --- a/tools/cmake/utilities.cmake +++ b/tools/cmake/utilities.cmake @@ -131,13 +131,14 @@ endfunction() # and then adds -T with the filename only. This allows INCLUDE directives to be # used to include other linker scripts in the same directory. function(target_linker_script target scriptfiles) - cmake_parse_arguments(_ "PROCESS" "" "" ${ARGN}) + cmake_parse_arguments(_ "" "PROCESS" "" ${ARGN}) foreach(scriptfile ${scriptfiles}) get_filename_component(abs_script "${scriptfile}" ABSOLUTE) message(STATUS "Adding linker script ${abs_script}") if(__PROCESS) - __ldgen_process_template(output ${abs_script}) + get_filename_component(output "${__PROCESS}" ABSOLUTE) + __ldgen_process_template(${abs_script} ${output}) set(abs_script ${output}) endif() diff --git a/tools/ldgen/ldgen.py b/tools/ldgen/ldgen.py index 7829e4dfb8..dcc0db4e07 100755 --- a/tools/ldgen/ldgen.py +++ b/tools/ldgen/ldgen.py @@ -19,6 +19,8 @@ import argparse import sys import tempfile import subprocess +import os +import errno from fragments import FragmentFile from sdkconfig import SDKConfig @@ -111,6 +113,14 @@ def main(): with tempfile.TemporaryFile("w+") as output: script_model.write(output) output.seek(0) + + if not os.path.exists(os.path.dirname(output_path)): + try: + os.makedirs(os.path.dirname(output_path)) + except OSError as exc: + if exc.errno != errno.EEXIST: + raise + with open(output_path, "w") as f: # only create output file after generation has suceeded f.write(output.read()) except LdGenFailure as e: From 6365658d3fb481ed45bd143ce7c1cc54d4f7ec45 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Fri, 31 May 2019 15:27:11 +0800 Subject: [PATCH 029/486] cmake: revert using EXCLUDE_FROM_ALL when adding component subdirectories Reverting (for now) the change in !4452 to use EXCLUDE_FROM_ALL. Apparently this also affects custom targets with ALL option specified, not causing them to be built with the project. This is apparently a bug which has a merged fix: https://gitlab.kitware.com/cmake/cmake/merge_requests/2816 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 141f903892..951c14ed36 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,9 +74,9 @@ foreach(component_target ${build_component_targets}) idf_build_get_property(build_prefix __PREFIX) set(__idf_component_context 1) if(NOT prefix STREQUAL build_prefix) - add_subdirectory(${dir} ${prefix}_${_name} EXCLUDE_FROM_ALL) + add_subdirectory(${dir} ${prefix}_${_name}) else() - add_subdirectory(${dir} ${_name} EXCLUDE_FROM_ALL) + add_subdirectory(${dir} ${_name}) endif() set(__idf_component_context 0) endforeach() From 3882e48e8adf6cd1f5d9e42be732f2253ba99db0 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Tue, 4 Jun 2019 19:05:33 +0800 Subject: [PATCH 030/486] cmake: use new signature form of target_link_library to link components !4452 used setting LINK_LIBRARIES and INTERFACE_LINK_LIBRARIES to link components built under ESP-IDF build system. However, LINK_LIBRARIES does not produce behavior same as linking PRIVATE. This MR uses the new signature for target_link_libraries directly instead. This also moves setting dependencies during component registration rather than after all components have been processed. The consequence is that internally, components have to use the new signature form as well. This does not affect linking the components to external targets, such as with idf_as_lib example. This only affects linking additional libraries to ESP-IDF libraries outside component processing (after idf_build_process), which is not even possible for CMake") - target_link_libraries(${COMPONENT_LIB} extra) + target_link_libraries(${COMPONENT_LIB} PUBLIC extra) else() - target_link_libraries(${COMPONENT_LIB} ${LIBC} ${LIBM} gcc) + target_link_libraries(${COMPONENT_LIB} PUBLIC ${LIBC} ${LIBM} gcc) endif() set_source_files_properties(heap.c PROPERTIES COMPILE_FLAGS -fno-builtin) if(EXTRA_LINK_FLAGS) - target_link_libraries(${COMPONENT_LIB} "${EXTRA_LINK_FLAGS}") + target_link_libraries(${COMPONENT_LIB} INTERFACE "${EXTRA_LINK_FLAGS}") endif() diff --git a/components/ulp/project_include.cmake b/components/ulp/project_include.cmake index b5ac4c54e2..95996b32f0 100644 --- a/components/ulp/project_include.cmake +++ b/components/ulp/project_include.cmake @@ -61,7 +61,7 @@ function(ulp_embed_binary app_name s_sources exp_dep_srcs) add_dependencies(${COMPONENT_LIB} ${app_name}_artifacts) - target_linker_script(${COMPONENT_LIB} ${CMAKE_CURRENT_BINARY_DIR}/${app_name}/${app_name}.ld) + target_linker_script(${COMPONENT_LIB} INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/${app_name}/${app_name}.ld) target_add_binary_data(${COMPONENT_LIB} ${CMAKE_CURRENT_BINARY_DIR}/${app_name}/${app_name}.bin BINARY) endif() endfunction() \ No newline at end of file diff --git a/components/vfs/CMakeLists.txt b/components/vfs/CMakeLists.txt index 1d8fb06ec0..0b2f640ca6 100644 --- a/components/vfs/CMakeLists.txt +++ b/components/vfs/CMakeLists.txt @@ -6,4 +6,4 @@ register_component() # Some newlib syscalls are implemented in vfs.c, make sure these are always # seen by the linker -target_link_libraries(${COMPONENT_LIB} "-u vfs_include_syscalls_impl") +target_link_libraries(${COMPONENT_LIB} INTERFACE "-u vfs_include_syscalls_impl") diff --git a/components/xtensa/CMakeLists.txt b/components/xtensa/CMakeLists.txt index 9044f14ae1..cb9c9ce49c 100644 --- a/components/xtensa/CMakeLists.txt +++ b/components/xtensa/CMakeLists.txt @@ -7,4 +7,4 @@ set(COMPONENT_PRIV_REQUIRES soc) register_component() -target_link_libraries(${COMPONENT_LIB} "${CMAKE_CURRENT_SOURCE_DIR}/${IDF_TARGET}/libhal.a") +target_link_libraries(${COMPONENT_LIB} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/${IDF_TARGET}/libhal.a") diff --git a/examples/build_system/cmake/import_lib/main/CMakeLists.txt b/examples/build_system/cmake/import_lib/main/CMakeLists.txt index 8111cbe6a3..fb136b8b97 100644 --- a/examples/build_system/cmake/import_lib/main/CMakeLists.txt +++ b/examples/build_system/cmake/import_lib/main/CMakeLists.txt @@ -23,4 +23,4 @@ endfunction() add_subdirectory(lib/tinyxml2) # Link tinyxml2 to main component -target_link_libraries(${COMPONENT_LIB} tinyxml2) +target_link_libraries(${COMPONENT_LIB} PUBLIC tinyxml2) diff --git a/tools/cmake/build.cmake b/tools/cmake/build.cmake index 6cf9a73b55..84f6f154fc 100644 --- a/tools/cmake/build.cmake +++ b/tools/cmake/build.cmake @@ -436,29 +436,8 @@ endmacro() # generating additional binary files, generating files related to flashing, etc.) function(idf_build_executable elf) # Propagate link dependencies from component library targets to the executable - idf_build_get_property(build_components BUILD_COMPONENTS) - foreach(build_component ${build_components}) - get_target_property(type ${build_component} TYPE) - if(type STREQUAL "INTERFACE_LIBRARY") - get_target_property(iface_link_depends ${build_component} INTERFACE_LINK_DEPENDS) - else() - get_target_property(link_depends ${build_component} LINK_DEPENDS) - get_target_property(iface_link_depends ${build_component} INTERFACE_LINK_DEPENDS) - endif() - if(iface_link_depends) - list(APPEND _link_depends ${iface_link_depends}) - endif() - if(link_depends) - list(APPEND _link_depends ${link_depends}) - endif() - endforeach() - - idf_build_get_property(link_depends LINK_DEPENDS) - if(link_depends) - list(APPEND _link_depends ${link_depends}) - endif() - - set_property(TARGET ${elf} APPEND PROPERTY LINK_DEPENDS "${_link_depends}") + idf_build_get_property(link_depends __LINK_DEPENDS) + set_property(TARGET ${elf} APPEND PROPERTY LINK_DEPENDS "${link_depends}") # Set the EXECUTABLE_NAME and EXECUTABLE properties since there are generator expression # from components that depend on it diff --git a/tools/cmake/component.cmake b/tools/cmake/component.cmake index 6caca93a74..22b3528ec6 100644 --- a/tools/cmake/component.cmake +++ b/tools/cmake/component.cmake @@ -288,6 +288,39 @@ macro(__component_check_target) endif() endmacro() +# __component_set_dependencies, __component_set_all_dependencies +# +# Links public and private requirements for the currently processed component +macro(__component_set_dependencies reqs type) + foreach(req ${reqs}) + if(req IN_LIST build_component_targets) + __component_get_property(req_lib ${req} COMPONENT_LIB) + target_link_libraries(${component_lib} ${type} ${req_lib}) + endif() + endforeach() +endmacro() + +macro(__component_set_all_dependencies) + __component_get_property(type ${component_target} COMPONENT_TYPE) + idf_build_get_property(build_component_targets __BUILD_COMPONENT_TARGETS) + + if(NOT type STREQUAL CONFIG_ONLY) + __component_get_property(reqs ${component_target} __REQUIRES) + __component_set_dependencies("${reqs}" PUBLIC) + + __component_get_property(priv_reqs ${component_target} __PRIV_REQUIRES) + __component_set_dependencies("${priv_reqs}" PRIVATE) + else() + __component_get_property(reqs ${component_target} __REQUIRES) + foreach(req ${reqs}) + if(req IN_LIST build_component_targets) + __component_get_property(req_lib ${req} COMPONENT_LIB) + target_link_libraries(${component_lib} INTERFACE ${req_lib}) + endif() + endforeach() + endif() +endmacro() + # idf_component_get_property # # @brief Retrieve the value of the specified component property @@ -331,6 +364,7 @@ function(idf_component_set_property component property val) endif() endfunction() + # idf_component_register # # @brief Register a component to the build, creating component library targets etc. @@ -431,6 +465,9 @@ function(idf_component_register) __ldgen_add_fragment_files("${__LDFRAGMENTS}") endif() + # Set dependencies + __component_set_all_dependencies() + # Add the component to built components idf_build_set_property(__BUILD_COMPONENTS ${component_lib} APPEND) idf_build_set_property(BUILD_COMPONENTS ${component_alias} APPEND) diff --git a/tools/cmake/ldgen.cmake b/tools/cmake/ldgen.cmake index b8cfaad499..27db72ae36 100644 --- a/tools/cmake/ldgen.cmake +++ b/tools/cmake/ldgen.cmake @@ -75,5 +75,5 @@ function(__ldgen_process_template template output) get_filename_component(_name ${output} NAME) add_custom_target(__ldgen_output_${_name} DEPENDS ${output}) add_dependencies(__idf_build_target __ldgen_output_${_name}) - idf_build_set_property(LINK_DEPENDS ${output} APPEND) + idf_build_set_property(__LINK_DEPENDS ${output} APPEND) endfunction() \ No newline at end of file diff --git a/tools/cmake/utilities.cmake b/tools/cmake/utilities.cmake index f5f7f9693c..83403d9ce9 100644 --- a/tools/cmake/utilities.cmake +++ b/tools/cmake/utilities.cmake @@ -130,7 +130,7 @@ endfunction() # Automatically adds a -L search path for the containing directory (if found), # and then adds -T with the filename only. This allows INCLUDE directives to be # used to include other linker scripts in the same directory. -function(target_linker_script target scriptfiles) +function(target_linker_script target deptype scriptfiles) cmake_parse_arguments(_ "" "PROCESS" "" ${ARGN}) foreach(scriptfile ${scriptfiles}) get_filename_component(abs_script "${scriptfile}" ABSOLUTE) @@ -145,12 +145,7 @@ function(target_linker_script target scriptfiles) get_filename_component(search_dir "${abs_script}" DIRECTORY) get_filename_component(scriptname "${abs_script}" NAME) - get_target_property(type ${target} TYPE) - if(type STREQUAL "INTERFACE_LIBRARY") - set(is_interface "INTERFACE") - endif() - - if(is_interface) + if(deptype STREQUAL INTERFACE OR deptype STREQUAL PUBLIC) get_target_property(link_libraries "${target}" INTERFACE_LINK_LIBRARIES) else() get_target_property(link_libraries "${target}" LINK_LIBRARIES) @@ -158,10 +153,10 @@ function(target_linker_script target scriptfiles) list(FIND "${link_libraries}" "-L ${search_dir}" found_search_dir) if(found_search_dir EQUAL "-1") # not already added as a search path - target_link_libraries("${target}" "${is_interface}" "-L ${search_dir}") + target_link_libraries("${target}" "${deptype}" "-L ${search_dir}") endif() - target_link_libraries("${target}" "${is_interface}" "-T ${scriptname}") + target_link_libraries("${target}" "${deptype}" "-T ${scriptname}") # Note: In ESP-IDF, most targets are libraries and libary LINK_DEPENDS don't propagate to # executable(s) the library is linked to. Attach manually to executable once it is known. @@ -169,11 +164,7 @@ function(target_linker_script target scriptfiles) # Property INTERFACE_LINK_DEPENDS is available in CMake 3.13 which should propagate link # dependencies. if(NOT __PROCESS) - if(is_interface) - set_property(TARGET ${target} APPEND PROPERTY INTERFACE_LINK_DEPENDS ${abs_script}) - else() - set_property(TARGET ${target} APPEND PROPERTY LINK_DEPENDS ${abs_script}) - endif() + idf_build_set_property(__LINK_DEPENDS ${abs_script} APPEND) endif() endforeach() endfunction() From 54ef60f26b15d92622c2e51bc4b5c9df96421e01 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Tue, 4 Jun 2019 20:32:43 +0800 Subject: [PATCH 031/486] component: revert some of the dependency corrections !4452 and !4897 made some ill-advised corrections to dependency info; revert those in this MR. Handling pre-built binaries as imported libraries is retained, however. --- components/bootloader_support/CMakeLists.txt | 8 ++++---- components/esp32/CMakeLists.txt | 4 ++-- components/esp_wifi/CMakeLists.txt | 3 +-- components/libsodium/CMakeLists.txt | 2 +- components/protocomm/CMakeLists.txt | 3 +-- components/spi_flash/CMakeLists.txt | 3 +-- 6 files changed, 10 insertions(+), 13 deletions(-) diff --git a/components/bootloader_support/CMakeLists.txt b/components/bootloader_support/CMakeLists.txt index d1373be307..2437829d54 100644 --- a/components/bootloader_support/CMakeLists.txt +++ b/components/bootloader_support/CMakeLists.txt @@ -9,8 +9,8 @@ set(COMPONENT_SRCS "src/bootloader_clock.c" if(BOOTLOADER_BUILD) set(COMPONENT_ADD_INCLUDEDIRS "include include_bootloader") - set(COMPONENT_REQUIRES spi_flash soc) #unfortunately the header directly uses SOC registers - set(COMPONENT_PRIV_REQUIRES micro-ecc efuse) + set(COMPONENT_REQUIRES soc) #unfortunately the header directly uses SOC registers + set(COMPONENT_PRIV_REQUIRES micro-ecc spi_flash efuse) list(APPEND COMPONENT_SRCS "src/bootloader_init.c" "src/${IDF_TARGET}/bootloader_sha.c" "src/${IDF_TARGET}/flash_encrypt.c" @@ -55,8 +55,8 @@ else() "src/idf/secure_boot_signatures.c") set(COMPONENT_ADD_INCLUDEDIRS "include") set(COMPONENT_PRIV_INCLUDEDIRS "include_bootloader") - set(COMPONENT_REQUIRES mbedtls soc) #unfortunately the header directly uses SOC registers - set(COMPONENT_PRIV_REQUIRES spi_flash efuse) + set(COMPONENT_REQUIRES soc) #unfortunately the header directly uses SOC registers + set(COMPONENT_PRIV_REQUIRES spi_flash mbedtls efuse) endif() register_component() \ No newline at end of file diff --git a/components/esp32/CMakeLists.txt b/components/esp32/CMakeLists.txt index 89b344b25e..abcc0ada17 100644 --- a/components/esp32/CMakeLists.txt +++ b/components/esp32/CMakeLists.txt @@ -34,12 +34,12 @@ else() "task_wdt.c") set(COMPONENT_ADD_INCLUDEDIRS "include") - set(COMPONENT_REQUIRES app_update driver esp_event efuse pthread soc) #unfortunately rom/uart uses SOC registers directly + set(COMPONENT_REQUIRES driver esp_event efuse soc) #unfortunately rom/uart uses SOC registers directly # driver is a public requirement because esp_sleep.h uses gpio_num_t & touch_pad_t # app_update is added here because cpu_start.c uses esp_ota_get_app_description() function. set(COMPONENT_PRIV_REQUIRES - app_trace app_update bootloader_support log mbedtls nvs_flash + app_trace app_update bootloader_support log mbedtls nvs_flash pthread smartconfig_ack spi_flash vfs wpa_supplicant espcoredump esp_common esp_wifi) set(COMPONENT_ADD_LDFRAGMENTS linker.lf ld/esp32_fragments.lf) diff --git a/components/esp_wifi/CMakeLists.txt b/components/esp_wifi/CMakeLists.txt index 0041234312..c8f31cd53c 100644 --- a/components/esp_wifi/CMakeLists.txt +++ b/components/esp_wifi/CMakeLists.txt @@ -8,8 +8,7 @@ set(COMPONENT_SRCS "src/wifi_init.c") set(COMPONENT_ADD_INCLUDEDIRS "include") set(COMPONENT_PRIV_INCLUDEDIRS) -set(COMPONENT_REQUIRES wpa_supplicant smartconfig_ack) -set(COMPONENT_PRIV_REQUIRES "nvs_flash") +set(COMPONENT_PRIV_REQUIRES wpa_supplicant nvs_flash) if(NOT CONFIG_ESP32_NO_BLOBS) set(COMPONENT_ADD_LDFRAGMENTS "linker.lf") diff --git a/components/libsodium/CMakeLists.txt b/components/libsodium/CMakeLists.txt index f0d5afc9da..caef522233 100644 --- a/components/libsodium/CMakeLists.txt +++ b/components/libsodium/CMakeLists.txt @@ -126,7 +126,7 @@ endif() set(COMPONENT_ADD_INCLUDEDIRS ${SRC}/include port_include) set(COMPONENT_PRIV_INCLUDEDIRS ${SRC}/include/sodium port_include/sodium port) -set(COMPONENT_REQUIRES mbedtls vfs) +set(COMPONENT_REQUIRES mbedtls) register_component() target_compile_definitions(${COMPONENT_LIB} PRIVATE diff --git a/components/protocomm/CMakeLists.txt b/components/protocomm/CMakeLists.txt index 79e824ceb6..9f9343815f 100644 --- a/components/protocomm/CMakeLists.txt +++ b/components/protocomm/CMakeLists.txt @@ -12,8 +12,7 @@ set(COMPONENT_SRCS "src/common/protocomm.c" "src/transports/protocomm_console.c" "src/transports/protocomm_httpd.c") -set(COMPONENT_REQUIRES protobuf-c bt) -set(COMPONENT_PRIV_REQUIRES mbedtls console esp_http_server) +set(COMPONENT_PRIV_REQUIRES protobuf-c mbedtls console esp_http_server bt) if(CONFIG_BT_ENABLED) if(CONFIG_BT_BLUEDROID_ENABLED) diff --git a/components/spi_flash/CMakeLists.txt b/components/spi_flash/CMakeLists.txt index db8fceee0e..be290e7c32 100644 --- a/components/spi_flash/CMakeLists.txt +++ b/components/spi_flash/CMakeLists.txt @@ -9,8 +9,7 @@ else() "flash_ops.c" "partition.c" "spi_flash_rom_patch.c") - set(COMPONENT_REQUIRES app_update) - set(COMPONENT_PRIV_REQUIRES bootloader_support soc) + set(COMPONENT_PRIV_REQUIRES bootloader_support app_update soc) endif() set(COMPONENT_ADD_INCLUDEDIRS include) From 517c61a4ec2f2506a18de7aa4e4c0bce221dcba5 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 10 Jun 2019 23:29:18 +0800 Subject: [PATCH 032/486] docs: fix generation of toolchain links Closes https://github.com/espressif/esp-idf/issues/3609 --- docs/gen-toolchain-links.py | 41 ++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/docs/gen-toolchain-links.py b/docs/gen-toolchain-links.py index ea90f47c70..8858174384 100644 --- a/docs/gen-toolchain-links.py +++ b/docs/gen-toolchain-links.py @@ -9,6 +9,15 @@ from __future__ import print_function import sys import os +from collections import namedtuple + +PlatformInfo = namedtuple("PlatformInfo", [ + "platform_name", + "platform_archive_suffix", + "extension", + "unpack_cmd", + "unpack_code" +]) def main(): @@ -44,35 +53,33 @@ def main(): scratch_build_code_linux_macos = """ :: - git clone -b xtensa-1.22.x https://github.com/espressif/crosstool-NG.git + git clone https://github.com/espressif/crosstool-NG.git cd crosstool-NG + git checkout {} ./bootstrap && ./configure --enable-local && make install """ - platform_info = [["linux64", "tar.gz", "z", unpack_code_linux_macos], - ["linux32", "tar.gz", "z", unpack_code_linux_macos], - ["osx", "tar.gz", "z", unpack_code_linux_macos], - ["win32", "zip", None, None]] + platform_info = [ + PlatformInfo("linux64", "linux-amd64", "tar.gz", "z", unpack_code_linux_macos), + PlatformInfo("linux32", "linux-i686","tar.gz", "z", unpack_code_linux_macos), + PlatformInfo("osx", "macos", "tar.gz", "z", unpack_code_linux_macos), + PlatformInfo("win32", "win32", "zip", None, None) + ] with open(os.path.join(out_dir, 'download-links.inc'), "w") as links_file: for p in platform_info: - platform_name = p[0] - extension = p[1] - unpack_cmd = p[2] - unpack_code = p[3] - - archive_name = 'xtensa-esp32-elf-{}-{}-{}.{}'.format( - platform_name, toolchain_desc, gcc_version, extension) + archive_name = 'xtensa-esp32-elf-gcc{}-{}-{}.{}'.format( + gcc_version.replace('.', '_'), toolchain_desc, p.platform_archive_suffix, p.extension) print('.. |download_link_{}| replace:: {}{}'.format( - platform_name, base_url, archive_name), file=links_file) + p.platform_name, base_url, archive_name), file=links_file) - if unpack_code is not None: - with open(os.path.join(out_dir, 'unpack-code-%s.inc' % platform_name), "w") as f: - print(unpack_code.format(unpack_cmd, archive_name), file=f) + if p.unpack_code is not None: + with open(os.path.join(out_dir, 'unpack-code-%s.inc' % p.platform_name), "w") as f: + print(p.unpack_code.format(p.unpack_cmd, archive_name), file=f) with open(os.path.join(out_dir, 'scratch-build-code.inc'), "w") as code_file: - print(scratch_build_code_linux_macos, file=code_file) + print(scratch_build_code_linux_macos.format(toolchain_desc), file=code_file) if __name__ == "__main__": From 67148e37a61a7e168ea324d70c17b373c4639e9f Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 11 Jun 2019 21:58:03 +0800 Subject: [PATCH 033/486] tools/windows: update toolchain URL in MSYS build script --- tools/windows/windows_install_prerequisites.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/windows/windows_install_prerequisites.sh b/tools/windows/windows_install_prerequisites.sh index f75f54eecb..993931081a 100644 --- a/tools/windows/windows_install_prerequisites.sh +++ b/tools/windows/windows_install_prerequisites.sh @@ -42,10 +42,11 @@ if [ -n "$IDF_PATH" ]; then fi # Automatically download precompiled toolchain, unpack at /opt/xtensa-esp32-elf/ -TOOLCHAIN_ZIP=xtensa-esp32-elf-win32-1.22.0-80-g6c4433a-5.2.0.zip +TOOLCHAIN_ZIP=xtensa-esp32-elf-gcc8_2_0-esp32-2019r1-win32.zip echo "Downloading precompiled toolchain ${TOOLCHAIN_ZIP}..." cd ~ curl -LO --retry 10 http://dl.espressif.com/dl/${TOOLCHAIN_ZIP} +mkdir -p /opt cd /opt rm -rf /opt/xtensa-esp32-elf # for upgrades unzip ~/${TOOLCHAIN_ZIP} From 0e6ffd08b7416ef4e05ff8d1bf2d3ae5389e4ace Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 11 Jun 2019 22:22:14 +0800 Subject: [PATCH 034/486] docs: update msys environment links for esp32-2019r1 toolchain --- docs/en/get-started/windows-setup.rst | 2 +- docs/zh_CN/get-started/windows-setup.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/get-started/windows-setup.rst b/docs/en/get-started/windows-setup.rst index ad7d821011..d2a2678283 100644 --- a/docs/en/get-started/windows-setup.rst +++ b/docs/en/get-started/windows-setup.rst @@ -14,7 +14,7 @@ Toolchain Setup The quick setup is to download the Windows all-in-one toolchain & MSYS2 zip file from dl.espressif.com: -https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20181001.zip +https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20190611.zip Unzip the zip file to ``C:\`` (or some other location, but this guide assumes ``C:\``) and it will create an ``msys32`` directory with a pre-prepared environment. diff --git a/docs/zh_CN/get-started/windows-setup.rst b/docs/zh_CN/get-started/windows-setup.rst index 348f5f6e77..3c02077bd3 100644 --- a/docs/zh_CN/get-started/windows-setup.rst +++ b/docs/zh_CN/get-started/windows-setup.rst @@ -15,7 +15,7 @@ Windows 没有内置的 "make" 环境,因此如果要安装工具链,你需 快速设置的方法是从 dl.espressif.com 下载集成在一起的工具链和 MSYS2 压缩文件: -https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20181001.zip +https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20190611.zip 将 zip 压缩文件解压到 ``C:\`` (或其它路径,这里假设是 ``C:\``),它会使用预先准备的环境创建一个 ``msys32`` 目录。 From 87aa341e9758528f8536c9d86f1719e5fe629587 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Fri, 5 Apr 2019 10:42:36 +0800 Subject: [PATCH 035/486] ldgen: mapping rules should be grouped by archive --- tools/ldgen/generation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ldgen/generation.py b/tools/ldgen/generation.py index 0c05cca1a7..b411c56b4b 100644 --- a/tools/ldgen/generation.py +++ b/tools/ldgen/generation.py @@ -345,7 +345,7 @@ class GenerationModel: message = GenerationException.UNDEFINED_REFERENCE + " to scheme '" + scheme_name + "'." raise GenerationException(message, mapping) - all_mapping_rules[mapping.name] = mapping_rules + all_mapping_rules[mapping.archive] = mapping_rules # Detect rule conflicts for mapping_rules in all_mapping_rules.items(): From 8ee90ee2f108413fe98b5902814561409d91e981 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Fri, 5 Apr 2019 14:32:21 +0800 Subject: [PATCH 036/486] ldgen: allow multiple mapping fragments to map same library --- tools/ldgen/fragments.py | 2 + tools/ldgen/generation.py | 31 +++++---- tools/ldgen/test/test_generation.py | 103 ++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 15 deletions(-) diff --git a/tools/ldgen/fragments.py b/tools/ldgen/fragments.py index dd8295f869..0339f5849e 100644 --- a/tools/ldgen/fragments.py +++ b/tools/ldgen/fragments.py @@ -279,6 +279,7 @@ class Mapping(Fragment): def __init__(self): Fragment.__init__(self) self.entries = set() + self.deprecated = False def set_key_value(self, key, parse_results): if key == "archive": @@ -382,6 +383,7 @@ class DeprecatedMapping(): fragment = Mapping() fragment.archive = toks[0].archive fragment.name = re.sub(r"[^0-9a-zA-Z]+", "_", fragment.archive) + fragment.deprecated = True fragment.entries = set() condition_true = False diff --git a/tools/ldgen/generation.py b/tools/ldgen/generation.py index b411c56b4b..686defc3aa 100644 --- a/tools/ldgen/generation.py +++ b/tools/ldgen/generation.py @@ -334,8 +334,8 @@ class GenerationModel: # Generate rules based on mapping fragments for mapping in self.mappings.values(): - mapping_rules = list() archive = mapping.archive + mapping_rules = all_mapping_rules[archive] for (obj, symbol, scheme_name) in mapping.entries: try: if not (obj == Mapping.MAPPING_ALL_OBJECTS and symbol is None and @@ -345,8 +345,6 @@ class GenerationModel: message = GenerationException.UNDEFINED_REFERENCE + " to scheme '" + scheme_name + "'." raise GenerationException(message, mapping) - all_mapping_rules[mapping.archive] = mapping_rules - # Detect rule conflicts for mapping_rules in all_mapping_rules.items(): self._detect_conflicts(mapping_rules) @@ -453,21 +451,24 @@ class GenerationModel: for fragment in fragment_file.fragments: dict_to_append_to = None - if isinstance(fragment, Scheme): - dict_to_append_to = self.schemes - elif isinstance(fragment, Sections): - dict_to_append_to = self.sections + if isinstance(fragment, Mapping) and fragment.deprecated and fragment.name in self.mappings.keys(): + self.mappings[fragment.name].entries |= fragment.entries else: - dict_to_append_to = self.mappings + if isinstance(fragment, Scheme): + dict_to_append_to = self.schemes + elif isinstance(fragment, Sections): + dict_to_append_to = self.sections + else: + dict_to_append_to = self.mappings - # Raise exception when the fragment of the same type is already in the stored fragments - if fragment.name in dict_to_append_to.keys(): - stored = dict_to_append_to[fragment.name].path - new = fragment.path - message = "Duplicate definition of fragment '%s' found in %s and %s." % (fragment.name, stored, new) - raise GenerationException(message) + # Raise exception when the fragment of the same type is already in the stored fragments + if fragment.name in dict_to_append_to.keys(): + stored = dict_to_append_to[fragment.name].path + new = fragment.path + message = "Duplicate definition of fragment '%s' found in %s and %s." % (fragment.name, stored, new) + raise GenerationException(message) - dict_to_append_to[fragment.name] = fragment + dict_to_append_to[fragment.name] = fragment class TemplateModel: diff --git a/tools/ldgen/test/test_generation.py b/tools/ldgen/test/test_generation.py index 48f7742f75..ec5de67283 100755 --- a/tools/ldgen/test/test_generation.py +++ b/tools/ldgen/test/test_generation.py @@ -1246,6 +1246,109 @@ entries: self.compare_rules(expected, actual) + def test_rule_generation_multiple_deprecated_mapping_definitions(self): + multiple_deprecated_definitions = u""" +[mapping] +archive: lib.a +entries: + : PERFORMANCE_LEVEL = 0 + : PERFORMANCE_LEVEL = 1 + obj1 (noflash) + : PERFORMANCE_LEVEL = 2 + obj1 (noflash) + : PERFORMANCE_LEVEL = 3 + obj1 (noflash) + +[mapping] +archive: lib.a +entries: + : PERFORMANCE_LEVEL = 1 + obj1 (noflash) # ignore duplicate definition + : PERFORMANCE_LEVEL = 2 + obj2 (noflash) + : PERFORMANCE_LEVEL = 3 + obj2 (noflash) + obj3 (noflash) +""" + + for perf_level in range(0, 4): + self.sdkconfig.config.syms["PERFORMANCE_LEVEL"].set_value(str(perf_level)) + + self.model.mappings = {} + self.add_fragments(multiple_deprecated_definitions) + + actual = self.model.generate_rules(self.sections_info) + expected = self.generate_default_rules() + + if perf_level < 4: + for append_no in range(1, perf_level + 1): + flash_text_default = self.get_default("flash_text", expected) + flash_rodata_default = self.get_default("flash_rodata", expected) + + iram_rule = PlacementRule("lib.a", "obj" + str(append_no), None, self.model.sections["text"].entries, "iram0_text") + dram_rule = PlacementRule("lib.a", "obj" + str(append_no), None, self.model.sections["rodata"].entries, "dram0_data") + + flash_text_default.add_exclusion(iram_rule) + flash_rodata_default.add_exclusion(dram_rule) + + expected["iram0_text"].append(iram_rule) + expected["dram0_data"].append(dram_rule) + + self.compare_rules(expected, actual) + + def test_rule_generation_multiple_mapping_definitions(self): + multiple_deprecated_definitions = u""" +[mapping:base] +archive: lib.a +entries: + if PERFORMANCE_LEVEL = 1: + obj1 (noflash) + elif PERFORMANCE_LEVEL = 2: + obj1 (noflash) + elif PERFORMANCE_LEVEL = 3: + obj1 (noflash) + else: + * (default) + +[mapping:extra] +archive: lib.a +entries: + if PERFORMANCE_LEVEL = 1: + obj1 (noflash) # ignore duplicate definition + elif PERFORMANCE_LEVEL = 2: + obj2 (noflash) + elif PERFORMANCE_LEVEL = 3: + obj2 (noflash) + obj3 (noflash) + else: + * (default) +""" + + for perf_level in range(0, 4): + self.sdkconfig.config.syms["PERFORMANCE_LEVEL"].set_value(str(perf_level)) + + self.model.mappings = {} + self.add_fragments(multiple_deprecated_definitions) + + actual = self.model.generate_rules(self.sections_info) + expected = self.generate_default_rules() + + if perf_level < 4: + for append_no in range(1, perf_level + 1): + flash_text_default = self.get_default("flash_text", expected) + flash_rodata_default = self.get_default("flash_rodata", expected) + + iram_rule = PlacementRule("lib.a", "obj" + str(append_no), None, self.model.sections["text"].entries, "iram0_text") + dram_rule = PlacementRule("lib.a", "obj" + str(append_no), None, self.model.sections["rodata"].entries, "dram0_data") + + flash_text_default.add_exclusion(iram_rule) + flash_rodata_default.add_exclusion(dram_rule) + + expected["iram0_text"].append(iram_rule) + expected["dram0_data"].append(dram_rule) + + self.compare_rules(expected, actual) + if __name__ == "__main__": unittest.main() From 7edef74347ed4901c143b2d6960aee5504b87cae Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Tue, 11 Jun 2019 12:06:04 +0800 Subject: [PATCH 037/486] cmake: set variables set by project call ESP-IDF overrides project() definition for user convenience. This redefinition lacks setting the variables documented at the project command documentation https://cmake.org/cmake/help/v3.5/command/project.html in the parent scope. This commit sets those variables. Closes https://github.com/espressif/esp-idf/issues/3611. --- tools/cmake/project.cmake | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tools/cmake/project.cmake b/tools/cmake/project.cmake index 754e4a2fd4..b048b0d25c 100644 --- a/tools/cmake/project.cmake +++ b/tools/cmake/project.cmake @@ -264,6 +264,31 @@ macro(project project_name) function(project) set(project_ARGV ARGV) __project(${${project_ARGV}}) + + # Set the variables that project() normally sets, documented in the + # command's docs. + # + # https://cmake.org/cmake/help/v3.5/command/project.html + # + # There is some nuance when it comes to setting version variables in terms of whether + # CMP0048 is set to OLD or NEW. However, the proper behavior should have bee already handled by the original + # project call, and we're just echoing the values those variables were set to. + set(PROJECT_NAME "${PROJECT_NAME}" PARENT_SCOPE) + set(PROJECT_BINARY_DIR "${PROJECT_BINARY_DIR}" PARENT_SCOPE) + set(PROJECT_SOURCE_DIR "${PROJECT_SOURCE_DIR}" PARENT_SCOPE) + set(PROJECT_VERSION "${PROJECT_VERSION}" PARENT_SCOPE) + set(PROJECT_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}" PARENT_SCOPE) + set(PROJECT_VERSION_MINOR "${PROJECT_VERSION_MINOR}" PARENT_SCOPE) + set(PROJECT_VERSION_PATCH "${PROJECT_VERSION_PATCH}" PARENT_SCOPE) + set(PROJECT_VERSION_TWEAK "${PROJECT_VERSION_TWEAK}" PARENT_SCOPE) + + set(${PROJECT_NAME}_BINARY_DIR "${${PROJECT_NAME}_BINARY_DIR}" PARENT_SCOPE) + set(${PROJECT_NAME}_SOURCE_DIR "${${PROJECT_NAME}_SOURCE_DIR}" PARENT_SCOPE) + set(${PROJECT_NAME}_VERSION "${${PROJECT_NAME}_VERSION}" PARENT_SCOPE) + set(${PROJECT_NAME}_VERSION_MAJOR "${${PROJECT_NAME}_VERSION_MAJOR}" PARENT_SCOPE) + set(${PROJECT_NAME}_VERSION_MINOR "${${PROJECT_NAME}_VERSION_MINOR}" PARENT_SCOPE) + set(${PROJECT_NAME}_VERSION_PATCH "${${PROJECT_NAME}_VERSION_PATCH}" PARENT_SCOPE) + set(${PROJECT_NAME}_VERSION_TWEAK "${${PROJECT_NAME}_VERSION_TWEAK}" PARENT_SCOPE) endfunction() # Prepare the following arguments for the idf_build_process() call using external From ae675973beacdb250900c066510d3bac806c6f02 Mon Sep 17 00:00:00 2001 From: Sachin Parekh Date: Mon, 15 Apr 2019 15:20:37 +0530 Subject: [PATCH 038/486] optimize: IGMP and MLD6 timers on demand config added Signed-off-by: Sachin Parekh --- components/lwip/Kconfig | 10 ++++++++++ components/lwip/lwip | 2 +- components/lwip/port/esp32/include/lwipopts.h | 8 ++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig index 6ccbdc113e..6fa8a507e2 100644 --- a/components/lwip/Kconfig +++ b/components/lwip/Kconfig @@ -27,6 +27,16 @@ menu "LWIP" If this feature is disabled, all lwip functions will be put into FLASH. + config LWIP_TIMERS_ONDEMAND + bool "Enable LWIP Timers on demand" + default y + help + If this feature is enabled, IGMP and MLD6 timers will be activated only + when joining groups or receiving QUERY packets. + + This feature will reduce the power consumption for applications which do not + use IGMP and MLD6. + config LWIP_MAX_SOCKETS int "Max number of open sockets" range 1 16 diff --git a/components/lwip/lwip b/components/lwip/lwip index fe9a58cb7a..88ccba0ccf 160000 --- a/components/lwip/lwip +++ b/components/lwip/lwip @@ -1 +1 @@ -Subproject commit fe9a58cb7abdc74e7a2196b7c4e0a29ff9042f88 +Subproject commit 88ccba0ccfc11cd968b80a9d50b3182972da9604 diff --git a/components/lwip/port/esp32/include/lwipopts.h b/components/lwip/port/esp32/include/lwipopts.h index 6f3f279e02..fd6e1262f8 100644 --- a/components/lwip/port/esp32/include/lwipopts.h +++ b/components/lwip/port/esp32/include/lwipopts.h @@ -779,6 +779,14 @@ #endif #define ESP_IRAM_ATTR +#ifdef CONFIG_LWIP_TIMERS_ONDEMAND +#define ESP_LWIP_IGMP_TIMERS_ONDEMAND 1 +#define ESP_LWIP_MLD6_TIMERS_ONDEMAND 1 +#else +#define ESP_LWIP_IGMP_TIMERS_ONDEMAND 0 +#define ESP_LWIP_MLD6_TIMERS_ONDEMAND 0 +#endif + #if ESP_PERF #define DBG_PERF_PATH_SET(dir, point) #define DBG_PERF_FILTER_LEN 1000 From a75be3413e6251e17ce5efd7581c04548d2ac2c1 Mon Sep 17 00:00:00 2001 From: Anurag Kar Date: Mon, 10 Jun 2019 17:49:30 +0530 Subject: [PATCH 039/486] Wi-Fi Provisioning : Bugfix in copying SSID and Passphrase These changes guarantee that the SSID and Passphrase received via protocomm are NULL terminated and size limited to their standard lengths. List of changes: * Corrected length of passphrase field in wifi_prov_config_set_data_t structure * Performing length checks on SSID, passphrase and bssid, when populating wifi_prov_config_set_data_t structure with received credentials --- .../include/wifi_provisioning/wifi_config.h | 2 +- .../wifi_provisioning/src/wifi_config.c | 41 ++++++++++++++----- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/components/wifi_provisioning/include/wifi_provisioning/wifi_config.h b/components/wifi_provisioning/include/wifi_provisioning/wifi_config.h index 4058540adb..2fa64448d4 100644 --- a/components/wifi_provisioning/include/wifi_provisioning/wifi_config.h +++ b/components/wifi_provisioning/include/wifi_provisioning/wifi_config.h @@ -76,7 +76,7 @@ typedef struct { */ typedef struct { char ssid[33]; /*!< SSID of the AP to which the slave is to be connected */ - char password[65]; /*!< Password of the AP */ + char password[64]; /*!< Password of the AP */ char bssid[6]; /*!< BSSID of the AP */ uint8_t channel; /*!< Channel of the AP */ } wifi_prov_config_set_data_t; diff --git a/components/wifi_provisioning/src/wifi_config.c b/components/wifi_provisioning/src/wifi_config.c index 09ccc37d53..93e3e85643 100644 --- a/components/wifi_provisioning/src/wifi_config.c +++ b/components/wifi_provisioning/src/wifi_config.c @@ -151,15 +151,36 @@ static esp_err_t cmd_set_config_handler(WiFiConfigPayload *req, wifi_prov_config_set_data_t req_data; memset(&req_data, 0, sizeof(req_data)); - memcpy(req_data.ssid, req->cmd_set_config->ssid.data, - req->cmd_set_config->ssid.len); - memcpy(req_data.password, req->cmd_set_config->passphrase.data, - req->cmd_set_config->passphrase.len); - memcpy(req_data.bssid, req->cmd_set_config->bssid.data, - req->cmd_set_config->bssid.len); - req_data.channel = req->cmd_set_config->channel; - if (h->set_config_handler(&req_data, &h->ctx) == ESP_OK) { - resp_payload->status = STATUS__Success; + + /* Check arguments provided in protobuf packet: + * - SSID / Passphrase string length must be within the standard limits + * - BSSID must either be NULL or have length equal to that imposed by the standard + * If any of these conditions are not satisfied, don't invoke the handler and + * send error status without closing connection */ + resp_payload->status = STATUS__InvalidArgument; + if (req->cmd_set_config->bssid.len != 0 && + req->cmd_set_config->bssid.len != sizeof(req_data.bssid)) { + ESP_LOGD(TAG, "Received invalid BSSID"); + } else if (req->cmd_set_config->ssid.len >= sizeof(req_data.ssid)) { + ESP_LOGD(TAG, "Received invalid SSID"); + } else if (req->cmd_set_config->passphrase.len >= sizeof(req_data.password)) { + ESP_LOGD(TAG, "Received invalid Passphrase"); + } else { + /* The received SSID and Passphrase are not NULL terminated so + * we memcpy over zeroed out arrays. Above length checks ensure + * that there is atleast 1 extra byte for null termination */ + memcpy(req_data.ssid, req->cmd_set_config->ssid.data, + req->cmd_set_config->ssid.len); + memcpy(req_data.password, req->cmd_set_config->passphrase.data, + req->cmd_set_config->passphrase.len); + memcpy(req_data.bssid, req->cmd_set_config->bssid.data, + req->cmd_set_config->bssid.len); + req_data.channel = req->cmd_set_config->channel; + if (h->set_config_handler(&req_data, &h->ctx) == ESP_OK) { + resp_payload->status = STATUS__Success; + } else { + resp_payload->status = STATUS__InternalError; + } } resp->payload_case = WI_FI_CONFIG_PAYLOAD__PAYLOAD_RESP_SET_CONFIG; @@ -188,7 +209,7 @@ static esp_err_t cmd_apply_config_handler(WiFiConfigPayload *req, if (h->apply_config_handler(&h->ctx) == ESP_OK) { resp_payload->status = STATUS__Success; } else { - resp_payload->status = STATUS__InvalidArgument; + resp_payload->status = STATUS__InternalError; } resp->payload_case = WI_FI_CONFIG_PAYLOAD__PAYLOAD_RESP_APPLY_CONFIG; From a8d19e6638ca83b11faf334b9f3e6d8811af9e19 Mon Sep 17 00:00:00 2001 From: Anurag Kar Date: Mon, 10 Jun 2019 17:23:53 +0530 Subject: [PATCH 040/486] Provisioning Examples : Bugfix in copying Wi-Fi SSID and Passphrase --- .../provisioning/ble_prov/main/app_prov_handlers.c | 12 ++++++++---- .../console_prov/main/app_prov_handlers.c | 12 ++++++++---- examples/provisioning/custom_config/main/app_prov.c | 4 ++-- .../custom_config/main/app_prov_handlers.c | 12 ++++++++---- examples/provisioning/softap_prov/main/app_prov.c | 4 ++-- .../softap_prov/main/app_prov_handlers.c | 12 ++++++++---- 6 files changed, 36 insertions(+), 20 deletions(-) diff --git a/examples/provisioning/ble_prov/main/app_prov_handlers.c b/examples/provisioning/ble_prov/main/app_prov_handlers.c index 4a0c0d99a7..05dc895dcc 100644 --- a/examples/provisioning/ble_prov/main/app_prov_handlers.c +++ b/examples/provisioning/ble_prov/main/app_prov_handlers.c @@ -98,10 +98,14 @@ static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data, ESP_LOGI(TAG, "WiFi Credentials Received : \n\tssid %s \n\tpassword %s", req_data->ssid, req_data->password); - memcpy((char *) wifi_cfg->sta.ssid, req_data->ssid, - strnlen(req_data->ssid, sizeof(wifi_cfg->sta.ssid))); - memcpy((char *) wifi_cfg->sta.password, req_data->password, - strnlen(req_data->password, sizeof(wifi_cfg->sta.password))); + + /* Using strncpy allows the max SSID length to be 32 bytes (as per 802.11 standard). + * But this doesn't guarantee that the saved SSID will be null terminated, because + * wifi_cfg->sta.ssid is also 32 bytes long (without extra 1 byte for null character). + * Although, this is not a matter for concern because esp_wifi library reads the SSID + * upto 32 bytes in absence of null termination */ + strncpy((char *) wifi_cfg->sta.ssid, req_data->ssid, sizeof(wifi_cfg->sta.ssid)); + strlcpy((char *) wifi_cfg->sta.password, req_data->password, sizeof(wifi_cfg->sta.password)); return ESP_OK; } diff --git a/examples/provisioning/console_prov/main/app_prov_handlers.c b/examples/provisioning/console_prov/main/app_prov_handlers.c index 49c29739f8..e3fa614962 100644 --- a/examples/provisioning/console_prov/main/app_prov_handlers.c +++ b/examples/provisioning/console_prov/main/app_prov_handlers.c @@ -98,10 +98,14 @@ static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data, ESP_LOGI(TAG, "WiFi Credentials Received : \n\tssid %s \n\tpassword %s", req_data->ssid, req_data->password); - memcpy((char *) wifi_cfg->sta.ssid, req_data->ssid, - strnlen(req_data->ssid, sizeof(wifi_cfg->sta.ssid))); - memcpy((char *) wifi_cfg->sta.password, req_data->password, - strnlen(req_data->password, sizeof(wifi_cfg->sta.password))); + + /* Using strncpy allows the max SSID length to be 32 bytes (as per 802.11 standard). + * But this doesn't guarantee that the saved SSID will be null terminated, because + * wifi_cfg->sta.ssid is also 32 bytes long (without extra 1 byte for null character). + * Although, this is not a matter for concern because esp_wifi library reads the SSID + * upto 32 bytes in absence of null termination */ + strncpy((char *) wifi_cfg->sta.ssid, req_data->ssid, sizeof(wifi_cfg->sta.ssid)); + strlcpy((char *) wifi_cfg->sta.password, req_data->password, sizeof(wifi_cfg->sta.password)); return ESP_OK; } diff --git a/examples/provisioning/custom_config/main/app_prov.c b/examples/provisioning/custom_config/main/app_prov.c index 4c30ac2186..5e0f68ea8e 100644 --- a/examples/provisioning/custom_config/main/app_prov.c +++ b/examples/provisioning/custom_config/main/app_prov.c @@ -303,13 +303,13 @@ static esp_err_t start_wifi_ap(const char *ssid, const char *pass) }; strncpy((char *) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid)); - wifi_config.ap.ssid_len = strlen(ssid); + wifi_config.ap.ssid_len = strnlen(ssid, sizeof(wifi_config.ap.ssid)); if (strlen(pass) == 0) { memset(wifi_config.ap.password, 0, sizeof(wifi_config.ap.password)); wifi_config.ap.authmode = WIFI_AUTH_OPEN; } else { - strncpy((char *) wifi_config.ap.password, pass, sizeof(wifi_config.ap.password)); + strlcpy((char *) wifi_config.ap.password, pass, sizeof(wifi_config.ap.password)); wifi_config.ap.authmode = WIFI_AUTH_WPA_WPA2_PSK; } diff --git a/examples/provisioning/custom_config/main/app_prov_handlers.c b/examples/provisioning/custom_config/main/app_prov_handlers.c index c67eeebca4..2f320890e0 100644 --- a/examples/provisioning/custom_config/main/app_prov_handlers.c +++ b/examples/provisioning/custom_config/main/app_prov_handlers.c @@ -110,10 +110,14 @@ static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data, ESP_LOGI(TAG, "WiFi Credentials Received : \n\tssid %s \n\tpassword %s", req_data->ssid, req_data->password); - memcpy((char *) wifi_cfg->sta.ssid, req_data->ssid, - strnlen(req_data->ssid, sizeof(wifi_cfg->sta.ssid))); - memcpy((char *) wifi_cfg->sta.password, req_data->password, - strnlen(req_data->password, sizeof(wifi_cfg->sta.password))); + + /* Using strncpy allows the max SSID length to be 32 bytes (as per 802.11 standard). + * But this doesn't guarantee that the saved SSID will be null terminated, because + * wifi_cfg->sta.ssid is also 32 bytes long (without extra 1 byte for null character). + * Although, this is not a matter for concern because esp_wifi library reads the SSID + * upto 32 bytes in absence of null termination */ + strncpy((char *) wifi_cfg->sta.ssid, req_data->ssid, sizeof(wifi_cfg->sta.ssid)); + strlcpy((char *) wifi_cfg->sta.password, req_data->password, sizeof(wifi_cfg->sta.password)); return ESP_OK; } diff --git a/examples/provisioning/softap_prov/main/app_prov.c b/examples/provisioning/softap_prov/main/app_prov.c index 35ad3edf8e..f7bca2df12 100644 --- a/examples/provisioning/softap_prov/main/app_prov.c +++ b/examples/provisioning/softap_prov/main/app_prov.c @@ -289,13 +289,13 @@ static esp_err_t start_wifi_ap(const char *ssid, const char *pass) }; strncpy((char *) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid)); - wifi_config.ap.ssid_len = strlen(ssid); + wifi_config.ap.ssid_len = strnlen(ssid, sizeof(wifi_config.ap.ssid)); if (strlen(pass) == 0) { memset(wifi_config.ap.password, 0, sizeof(wifi_config.ap.password)); wifi_config.ap.authmode = WIFI_AUTH_OPEN; } else { - strncpy((char *) wifi_config.ap.password, pass, sizeof(wifi_config.ap.password)); + strlcpy((char *) wifi_config.ap.password, pass, sizeof(wifi_config.ap.password)); wifi_config.ap.authmode = WIFI_AUTH_WPA_WPA2_PSK; } diff --git a/examples/provisioning/softap_prov/main/app_prov_handlers.c b/examples/provisioning/softap_prov/main/app_prov_handlers.c index 4a0c0d99a7..05dc895dcc 100644 --- a/examples/provisioning/softap_prov/main/app_prov_handlers.c +++ b/examples/provisioning/softap_prov/main/app_prov_handlers.c @@ -98,10 +98,14 @@ static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data, ESP_LOGI(TAG, "WiFi Credentials Received : \n\tssid %s \n\tpassword %s", req_data->ssid, req_data->password); - memcpy((char *) wifi_cfg->sta.ssid, req_data->ssid, - strnlen(req_data->ssid, sizeof(wifi_cfg->sta.ssid))); - memcpy((char *) wifi_cfg->sta.password, req_data->password, - strnlen(req_data->password, sizeof(wifi_cfg->sta.password))); + + /* Using strncpy allows the max SSID length to be 32 bytes (as per 802.11 standard). + * But this doesn't guarantee that the saved SSID will be null terminated, because + * wifi_cfg->sta.ssid is also 32 bytes long (without extra 1 byte for null character). + * Although, this is not a matter for concern because esp_wifi library reads the SSID + * upto 32 bytes in absence of null termination */ + strncpy((char *) wifi_cfg->sta.ssid, req_data->ssid, sizeof(wifi_cfg->sta.ssid)); + strlcpy((char *) wifi_cfg->sta.password, req_data->password, sizeof(wifi_cfg->sta.password)); return ESP_OK; } From a012025deb7e42703a2caa54021dafdebc84b6c6 Mon Sep 17 00:00:00 2001 From: Anurag Kar Date: Mon, 10 Jun 2019 18:02:45 +0530 Subject: [PATCH 041/486] Example restful_server : Minor fix in copying file system base path --- .../protocols/http_server/restful_server/main/rest_server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/protocols/http_server/restful_server/main/rest_server.c b/examples/protocols/http_server/restful_server/main/rest_server.c index 8c74ccec52..d68bd0a0aa 100644 --- a/examples/protocols/http_server/restful_server/main/rest_server.c +++ b/examples/protocols/http_server/restful_server/main/rest_server.c @@ -172,7 +172,7 @@ esp_err_t start_rest_server(const char *base_path) REST_CHECK(base_path, "wrong base path", err); rest_server_context_t *rest_context = calloc(1, sizeof(rest_server_context_t)); REST_CHECK(rest_context, "No memory for rest context", err); - strncpy(rest_context->base_path, base_path, ESP_VFS_PATH_MAX); + strlcpy(rest_context->base_path, base_path, sizeof(rest_context->base_path)); httpd_handle_t server = NULL; httpd_config_t config = HTTPD_DEFAULT_CONFIG(); From 842384a0d3963e1aa87a8a8d3add1552a44eb3f2 Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Tue, 11 Jun 2019 10:32:59 +0200 Subject: [PATCH 042/486] spi_flash: Fix Kconfig indentation Closes https://github.com/espressif/esp-idf/issues/3598 --- components/spi_flash/Kconfig | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/components/spi_flash/Kconfig b/components/spi_flash/Kconfig index 7ffb5660a3..969c7cc8a0 100644 --- a/components/spi_flash/Kconfig +++ b/components/spi_flash/Kconfig @@ -69,14 +69,12 @@ menu "SPI Flash driver" ROM functions. These functions should not be called directly from IDF applications. - config SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS - bool "Aborts" - config SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS - bool "Fails" - config SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED - bool "Allowed" + config SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS + bool "Aborts" + config SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS + bool "Fails" + config SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED + bool "Allowed" endchoice endmenu - - From 22d070e0aff16791bd78c1fb1b5aabe94c50349a Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Tue, 11 Jun 2019 10:45:26 +0200 Subject: [PATCH 043/486] spi_flash: Rename long Kconfig options --- components/spi_flash/Kconfig | 10 +++++----- components/spi_flash/flash_ops.c | 10 +++++----- components/spi_flash/include/esp_spi_flash.h | 4 ++-- components/spi_flash/sdkconfig.rename | 7 +++++++ components/spi_flash/test/test_out_of_bounds_write.c | 4 ++-- tools/ldgen/samples/sdkconfig | 6 +++--- tools/unit-test-app/sdkconfig.defaults | 2 +- 7 files changed, 25 insertions(+), 18 deletions(-) create mode 100644 components/spi_flash/sdkconfig.rename diff --git a/components/spi_flash/Kconfig b/components/spi_flash/Kconfig index 969c7cc8a0..6ba4d5180d 100644 --- a/components/spi_flash/Kconfig +++ b/components/spi_flash/Kconfig @@ -52,9 +52,9 @@ menu "SPI Flash driver" This option is needed to write to flash on ESP32-D2WD, and any configuration where external SPI flash is connected to non-default pins. - choice SPI_FLASH_WRITING_DANGEROUS_REGIONS + choice SPI_FLASH_DANGEROUS_WRITE bool "Writing to dangerous flash regions" - default SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS + default SPI_FLASH_DANGEROUS_WRITE_ABORTS help SPI flash APIs can optionally abort or return a failure code if erasing or writing addresses that fall at the beginning @@ -69,11 +69,11 @@ menu "SPI Flash driver" ROM functions. These functions should not be called directly from IDF applications. - config SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS + config SPI_FLASH_DANGEROUS_WRITE_ABORTS bool "Aborts" - config SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS + config SPI_FLASH_DANGEROUS_WRITE_FAILS bool "Fails" - config SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED + config SPI_FLASH_DANGEROUS_WRITE_ALLOWED bool "Allowed" endchoice diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index 8aae45f0e2..7b3f5b1f8a 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -77,7 +77,7 @@ const DRAM_ATTR spi_flash_guard_funcs_t g_flash_guard_default_ops = { .end = spi_flash_enable_interrupts_caches_and_other_cpu, .op_lock = spi_flash_op_lock, .op_unlock = spi_flash_op_unlock, -#if !CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED +#if !CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED .is_safe_write_address = is_safe_write_address #endif }; @@ -87,14 +87,14 @@ const DRAM_ATTR spi_flash_guard_funcs_t g_flash_guard_no_os_ops = { .end = spi_flash_enable_interrupts_caches_no_os, .op_lock = 0, .op_unlock = 0, -#if !CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED +#if !CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED .is_safe_write_address = 0 #endif }; static const spi_flash_guard_funcs_t *s_flash_guard_ops; -#ifdef CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS +#ifdef CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS #define UNSAFE_WRITE_ADDRESS abort() #else #define UNSAFE_WRITE_ADDRESS return false @@ -104,7 +104,7 @@ static const spi_flash_guard_funcs_t *s_flash_guard_ops; /* CHECK_WRITE_ADDRESS macro to fail writes which land in the bootloader, partition table, or running application region. */ -#if CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED +#if CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED #define CHECK_WRITE_ADDRESS(ADDR, SIZE) #else /* FAILS or ABORTS */ #define CHECK_WRITE_ADDRESS(ADDR, SIZE) do { \ @@ -112,7 +112,7 @@ static const spi_flash_guard_funcs_t *s_flash_guard_ops; return ESP_ERR_INVALID_ARG; \ } \ } while(0) -#endif // CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED +#endif // CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED static __attribute__((unused)) bool is_safe_write_address(size_t addr, size_t size) { diff --git a/components/spi_flash/include/esp_spi_flash.h b/components/spi_flash/include/esp_spi_flash.h index 254e408959..74c96fd36c 100644 --- a/components/spi_flash/include/esp_spi_flash.h +++ b/components/spi_flash/include/esp_spi_flash.h @@ -336,7 +336,7 @@ typedef bool (*spi_flash_is_safe_write_address_t)(size_t addr, size_t size); * - 'op_unlock' unlocks access to flash API internal data. * These two functions are recursive and can be used around the outside of multiple calls to * 'start' & 'end', in order to create atomic multi-part flash operations. - * 3) When CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is disabled, flash writing/erasing + * 3) When CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is disabled, flash writing/erasing * API checks for addresses provided by user to avoid corruption of critical flash regions * (bootloader, partition table, running application etc.). * @@ -354,7 +354,7 @@ typedef struct { spi_flash_guard_end_func_t end; /**< critical section end function. */ spi_flash_op_lock_func_t op_lock; /**< flash access API lock function.*/ spi_flash_op_unlock_func_t op_unlock; /**< flash access API unlock function.*/ -#if !CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED +#if !CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED spi_flash_is_safe_write_address_t is_safe_write_address; /**< checks flash write addresses.*/ #endif } spi_flash_guard_funcs_t; diff --git a/components/spi_flash/sdkconfig.rename b/components/spi_flash/sdkconfig.rename new file mode 100644 index 0000000000..6f9d592269 --- /dev/null +++ b/components/spi_flash/sdkconfig.rename @@ -0,0 +1,7 @@ +# sdkconfig replacement configurations for deprecated options formatted as +# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION + +CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS CONFIG_SPI_FLASH_DANGEROUS_WRITE +CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS +CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS +CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED diff --git a/components/spi_flash/test/test_out_of_bounds_write.c b/components/spi_flash/test/test_out_of_bounds_write.c index 3c9b017476..9b411b0365 100644 --- a/components/spi_flash/test/test_out_of_bounds_write.c +++ b/components/spi_flash/test/test_out_of_bounds_write.c @@ -4,11 +4,11 @@ #include "esp_spi_flash.h" #include "esp_ota_ops.h" -#if CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS || CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS +#if CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS || CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS static const char *data = "blah blah blah"; -#if CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS +#if CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS #define TEST_TAGS "[spi_flash]" #else // ABORTS #define TEST_TAGS "[spi_flash][ignore]" diff --git a/tools/ldgen/samples/sdkconfig b/tools/ldgen/samples/sdkconfig index fcbe556260..8fbfd61586 100644 --- a/tools/ldgen/samples/sdkconfig +++ b/tools/ldgen/samples/sdkconfig @@ -494,9 +494,9 @@ CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 CONFIG_SPI_FLASH_VERIFY_WRITE= CONFIG_SPI_FLASH_ENABLE_COUNTERS= CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y -CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y -CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS= -CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED= +CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y +CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS= +CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED= # # SPIFFS Configuration diff --git a/tools/unit-test-app/sdkconfig.defaults b/tools/unit-test-app/sdkconfig.defaults index fca065641e..ca30ad526d 100644 --- a/tools/unit-test-app/sdkconfig.defaults +++ b/tools/unit-test-app/sdkconfig.defaults @@ -19,7 +19,7 @@ CONFIG_MBEDTLS_HARDWARE_SHA=y CONFIG_SPI_FLASH_ENABLE_COUNTERS=y CONFIG_ESP32_ULP_COPROC_ENABLED=y CONFIG_ESP_TASK_WDT=n -CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS=y +CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS=y CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=7 CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y CONFIG_COMPILER_STACK_CHECK=y From 7971845fd4dedb30acf46bb85ac0be3aed7dd0a8 Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Tue, 4 Jun 2019 13:20:00 +0200 Subject: [PATCH 044/486] idf.py: Don't expect "_" env. variable to be available from PowerShell --- tools/idf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/idf.py b/tools/idf.py index a075dbd43f..cdaf84ecd0 100755 --- a/tools/idf.py +++ b/tools/idf.py @@ -1113,7 +1113,7 @@ if __name__ == "__main__": WINPTY_VAR = "WINPTY" WINPTY_EXE = "winpty" if ("MSYSTEM" in os.environ) and ( - not os.environ["_"].endswith(WINPTY_EXE) and WINPTY_VAR not in os.environ + not os.environ.get("_", "").endswith(WINPTY_EXE) and WINPTY_VAR not in os.environ ): os.environ[WINPTY_VAR] = "1" # the value is of no interest to us # idf.py calls itself with "winpty" and WINPTY global variable set From e6801912c5c4861f828ab1f447280628bba9a5d7 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 27 May 2019 16:06:48 +0200 Subject: [PATCH 045/486] mdns: added initial suite of api unit tests --- components/mdns/test/CMakeLists.txt | 3 + components/mdns/test/component.mk | 4 + components/mdns/test/test_mdns.c | 99 +++++++++++++++++++ .../partition_table_unit_test_app.csv | 2 +- 4 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 components/mdns/test/CMakeLists.txt create mode 100644 components/mdns/test/component.mk create mode 100644 components/mdns/test/test_mdns.c diff --git a/components/mdns/test/CMakeLists.txt b/components/mdns/test/CMakeLists.txt new file mode 100644 index 0000000000..7e694470f6 --- /dev/null +++ b/components/mdns/test/CMakeLists.txt @@ -0,0 +1,3 @@ +set(COMPONENT_SRCDIRS ".") +set(COMPONENT_PRIV_REQUIRES unity test_utils mdns) +register_component() \ No newline at end of file diff --git a/components/mdns/test/component.mk b/components/mdns/test/component.mk new file mode 100644 index 0000000000..5be873488b --- /dev/null +++ b/components/mdns/test/component.mk @@ -0,0 +1,4 @@ +# +#Component Makefile +# +COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive \ No newline at end of file diff --git a/components/mdns/test/test_mdns.c b/components/mdns/test/test_mdns.c new file mode 100644 index 0000000000..6ae5e835ff --- /dev/null +++ b/components/mdns/test/test_mdns.c @@ -0,0 +1,99 @@ +#include "test_utils.h" +#include "mdns.h" +#include "unity.h" + + +#define MDNS_HOSTNAME "test-hostname" +#define MDNS_INSTANCE "test-instance" +#define MDNS_SERVICE_NAME "_http" +#define MDNS_SERVICE_PROTO "_tcp" +#define MDNS_SERVICE_PORT 80 + + +static void yield_to_all_priorities(void) +{ + // Lower the test-task priority before testing to ensure other tasks got executed on forced context switch + size_t test_task_prio_before = uxTaskPriorityGet(NULL); + vTaskPrioritySet(NULL, tskIDLE_PRIORITY); + taskYIELD(); // Let the RTOS to switch context + vTaskPrioritySet(NULL, test_task_prio_before); +} + + +TEST_CASE("mdns api to fail in invalid state", "[mdns][leaks=64]") +{ + TEST_ASSERT_NOT_EQUAL(ESP_OK, mdns_init() ); + TEST_ASSERT_NOT_EQUAL(ESP_OK, mdns_hostname_set(MDNS_HOSTNAME) ); + TEST_ASSERT_NOT_EQUAL(ESP_OK, mdns_instance_name_set(MDNS_INSTANCE) ); + TEST_ASSERT_NOT_EQUAL(ESP_OK, mdns_service_add(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_SERVICE_PORT, NULL, 0) ); +} + +TEST_CASE("mdns init and deinit", "[mdns][leaks=64]") +{ + test_case_uses_tcpip(); + TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_create_default()); + TEST_ASSERT_EQUAL(ESP_OK, mdns_init() ); + yield_to_all_priorities(); // Make sure that mdns task has executed to complete initialization + mdns_free(); + esp_event_loop_delete_default(); +} + +TEST_CASE("mdns api return expected err-code and do not leak memory", "[mdns][leaks=64]") +{ + mdns_txt_item_t serviceTxtData[CONFIG_MDNS_MAX_SERVICES] = { {NULL, NULL}, + }; + for (int i=0; i Date: Wed, 12 Jun 2019 19:17:04 +0800 Subject: [PATCH 046/486] Doc/translate idf about --- docs/en/about.rst | 3 ++- docs/zh_CN/about.rst | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/docs/en/about.rst b/docs/en/about.rst index fc86b65748..c23ed2b602 100644 --- a/docs/en/about.rst +++ b/docs/en/about.rst @@ -1,9 +1,10 @@ About ===== +:link_to_translation:`zh_CN:[中文]` This is documentation of `ESP-IDF `_, the framework to develop applications for `ESP32 `_ chip by `Espressif `_. -The ESP32 is 2.4 GHz Wi-Fi and Bluetooth combo, 32 bit dual core chip with 600 DMIPS processing power. +The ESP32 is 2.4 GHz Wi-Fi and Bluetooth combo, which integrates one or two 32-bit microprocessors, with up to 600 DMIPS processing power. .. figure:: ../_static/about-doc.png :align: center diff --git a/docs/zh_CN/about.rst b/docs/zh_CN/about.rst index 63cda26962..af50eddfb6 100644 --- a/docs/zh_CN/about.rst +++ b/docs/zh_CN/about.rst @@ -1 +1,16 @@ -.. include:: ../en/about.rst \ No newline at end of file +关于本指南 +=========== +:link_to_translation:`en:[English]` + +本指南为 `乐鑫 `_ 公司 `ESP32 系列芯片 `_ 官方应用开发框架 `ESP-IDF `_ 的配套文档。 + +ESP32 芯片是一款 2.4 GHz Wi-Fi 和蓝牙双模芯片,内置 1 或 2 个 32 位处理器,运算能力最高可达 600 DMIPS。 + +.. figure:: ../_static/about-doc.png + :align: center + :alt: 乐鑫物联网综合开发框架 + :figclass: align-center + + 乐鑫物联网综合开发框架 + +ESP-IDF 即乐鑫物联网开发框架,可为在 Windows、Linux 和 macOS 系统平台上开发 ESP32 应用程序提供工具链、API、组件和工作流的支持。 From 2deb267be5a66acd478ef0b34ba09216b8a73128 Mon Sep 17 00:00:00 2001 From: He Yin Ling Date: Thu, 13 Jun 2019 11:14:39 +0800 Subject: [PATCH 047/486] test: fix some wifi case issues: * remove heap size check cases as we have bg tasks allocate memory * fix wifi connect to open ap issue --- .../idf_test/integration_test/KnownIssues | 13 ----- .../integration_test/TC_IT_WIFI_CONN.yml | 51 ++++--------------- 2 files changed, 9 insertions(+), 55 deletions(-) diff --git a/components/idf_test/integration_test/KnownIssues b/components/idf_test/integration_test/KnownIssues index f61c722ae1..818c27cba4 100644 --- a/components/idf_test/integration_test/KnownIssues +++ b/components/idf_test/integration_test/KnownIssues @@ -12,19 +12,6 @@ ESP32.WIFI_SCAN_0303 ESP32.WIFI_SCAN_0303_01 ESP32.WIFI_CONN_0302 ESP32.WIFI_CONN_0302_01 -ESP32.WIFI_CONN_0101 -ESP32.WIFI_CONN_0101_01 -ESP32.WIFI_CONN_0102 -ESP32.WIFI_CONN_0103 -ESP32.WIFI_CONN_0103_01 -ESP32.WIFI_SCAN_0101 -ESP32.WIFI_SCAN_0101_01 -ESP32.WIFI_SCAN_0102 -ESP32.WIFI_SCAN_0102_01 -ESP32.WIFI_SCAN_0103 -ESP32.WIFI_SCAN_0103_01 -ESP32.WIFI_SCAN_0104 -ESP32.WIFI_SCAN_0104_01 ESP32.WIFI_MODE_0102 ESP32.WIFI_MODE_0103 ESP32.WIFI_ADDR_0102 diff --git a/components/idf_test/integration_test/TC_IT_WIFI_CONN.yml b/components/idf_test/integration_test/TC_IT_WIFI_CONN.yml index f5cc01e929..7086310cdb 100644 --- a/components/idf_test/integration_test/TC_IT_WIFI_CONN.yml +++ b/components/idf_test/integration_test/TC_IT_WIFI_CONN.yml @@ -13,13 +13,13 @@ test cases: - '' - - SSC SSC1 ap -S -s -t 0 - - R SSC1 C +SAP:OK - - - SSC SSC2 sta -C -s -p + - - SSC SSC2 sta -C -s - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() - - SSC SSC1 ap -S -s -p -t 2 - - R SSC1 C +SAP:OK - - SSC SSC2 sta -C -s -p - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() - - - SSC SSC1 ap -S -s -p -t + - - SSC SSC1 ap -S -s -p -t 3 - - R SSC1 C +SAP:OK - - SSC SSC2 sta -C -s -p - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() @@ -29,6 +29,8 @@ test cases: - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() - - SSC SSC1 ap -S -s -p -t 1 - - R SSC1 C +SAP:OK + - - SSC SSC2 sta -D + - - R SSC2 C +QAP:OK - - SSC SSC2 sta -S - - R SSC2 RE "\+SCAN:%%s,.+,0,\d+"%%() C +SCANDONE - - SSC SSC1 ap -S -s -p -t 5 @@ -69,16 +71,18 @@ test cases: - '' - - SSC SSC1 ap -S -s -t 0 -n 1 - - R SSC1 C +SAP:OK - - - SSC SSC2 sta -C -s -p + - - SSC SSC2 sta -C -s - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() - - SSC SSC1 ap -S -s -t 0 -n 13 - - R SSC1 C +SAP:OK - - - SSC SSC2 sta -C -s -p + - - SSC SSC2 sta -C -s - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() - - SSC SSC1 ap -S -s -n 15 - - R SSC1 C +SAP:OK - - - SSC SSC2 sta -C -s -p + - - SSC SSC2 sta -C -s - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC2 sta -D + - - R SSC2 C +QAP:OK - - SSC SSC2 sta -S - - R SSC2 RE "\+SCAN:%%s,.+,\d+,1"%%() execution time: 0.0 @@ -1040,43 +1044,6 @@ test cases: test point 1: basic function test point 2: beacon delay version: v1 (2016-8-15) -- CI ready: 'Yes' - ID: WIFI_CONN_1101 - SDK: ESP32_IDF - Test App: SSC - allow fail: '' - auto test: 'Yes' - category: Function - cmd set: - - '' - - - SSC SSC1 ram -Q - - - R SSC1 A :\+FREEHEAP:(\d+)\r\n - - - SSC SSC1 op -W -a start - - - R SSC1 C +MODE:OK - - - SSC SSC1 op -W -a stop - - - R SSC1 C +MODE:OK - - - SSC SSC1 ram -Q - - - R SSC1 P - execution time: 0 - expected result: | - 1. get current heap size - 2.OK - 3.OK - 4.heap size unchanged - initial condition: WIFISTO - level: Integration - module: WIFI MAC - steps: | - 1. check heap size - 2. wifi start - 3. wifi stop - 4. check heap size - sub module: WIFI Connect - summary: wifi start and stop, heap size unchanged - test environment: SSC_T1_4 - test point 1: basic function - test point 2: wifi start and stop, heap size unchanged - version: v1 (2016-12-31) - CI ready: 'Yes' ID: WIFI_CONN_1201 SDK: ESP32_IDF From a98141cc0a61e214e8d4c5fd8c40bf893a94d377 Mon Sep 17 00:00:00 2001 From: Anton Maklakov Date: Thu, 13 Jun 2019 12:42:49 +0700 Subject: [PATCH 048/486] ci: keep executables list sorted to pass tests --- tools/ci/executable-list.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index dcb4610b77..dd001885a3 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -31,10 +31,10 @@ tools/check_python_dependencies.py tools/ci/apply_bot_filter.py tools/ci/build_examples.sh tools/ci/build_examples_cmake.sh -tools/ci/check_idf_version.sh tools/ci/check-executable.sh tools/ci/check-line-endings.sh tools/ci/check_examples_cmake_make.sh +tools/ci/check_idf_version.sh tools/ci/check_ut_cmake_make.sh tools/ci/checkout_project_ref.py tools/ci/envsubst.py From d127849d80cd92f943aedef108d0dd54bbada387 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 31 May 2019 15:35:05 +0200 Subject: [PATCH 049/486] can: suppress clang tidy warning about nullptr dereference --- components/driver/can.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/components/driver/can.c b/components/driver/can.c index 6001e65f22..0ddf892968 100644 --- a/components/driver/can.c +++ b/components/driver/can.c @@ -353,7 +353,7 @@ static void can_alert_handler(uint32_t alert_code, int *alert_req) } } -static void can_intr_handler_err_warn(can_status_reg_t *status, BaseType_t *task_woken, int *alert_req) +static void can_intr_handler_err_warn(can_status_reg_t *status, int *alert_req) { if (status->bus) { if (status->error) { @@ -478,10 +478,15 @@ static void can_intr_handler_main(void *arg) status.val = can_get_status(); intr_reason.val = (p_can_obj != NULL) ? can_get_interrupt_reason() : 0; //Incase intr occurs whilst driver is being uninstalled +#ifdef __clang_analyzer__ + if (intr_reason.val == 0) { // Teach clang-tidy that all bitfields are zero if a register is zero; othewise it warns about p_can_obj null dereference + intr_reason.err_warn = intr_reason.err_passive = intr_reason.bus_err = intr_reason.arb_lost = intr_reason.rx = intr_reason.tx = 0; + } +#endif //Handle error counter related interrupts if (intr_reason.err_warn) { //Triggers when Bus-Status or Error-status bits change - can_intr_handler_err_warn(&status, &task_woken, &alert_req); + can_intr_handler_err_warn(&status, &alert_req); } if (intr_reason.err_passive) { //Triggers when entering/returning error passive/active state From d18ed01b818836c5226dddbf788e2a338a56ecfd Mon Sep 17 00:00:00 2001 From: xueyunfei Date: Fri, 24 May 2019 11:58:48 +0800 Subject: [PATCH 050/486] lwip:fix bugfix/dns_bug --- components/lwip/lwip | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lwip/lwip b/components/lwip/lwip index 88ccba0ccf..5d9fce09e3 160000 --- a/components/lwip/lwip +++ b/components/lwip/lwip @@ -1 +1 @@ -Subproject commit 88ccba0ccfc11cd968b80a9d50b3182972da9604 +Subproject commit 5d9fce09e352a7b11949b79f386c907ce8d09fa8 From 353de1487fd53a164ee36c60fe716c4388ac6039 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 14 Jun 2019 11:42:11 +0200 Subject: [PATCH 051/486] log: fix minor memory leak when cleaning list of log levels --- components/log/log.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/log/log.c b/components/log/log.c index 72c232c68b..c59469cc02 100644 --- a/components/log/log.c +++ b/components/log/log.c @@ -174,8 +174,10 @@ void esp_log_level_set(const char* tag, esp_log_level_t level) void clear_log_level_list() { - while( !SLIST_EMPTY(&s_log_tags)) { + uncached_tag_entry_t *it; + while((it = SLIST_FIRST(&s_log_tags)) != NULL) { SLIST_REMOVE_HEAD(&s_log_tags, entries ); + free(it); } s_log_cache_entry_count = 0; s_log_cache_max_generation = 0; From da978bc5a12f7a1b6652863ea724b0c716ad2832 Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Mon, 4 Mar 2019 16:25:42 +0100 Subject: [PATCH 052/486] tools: Port the filtering option of IDF Monitor to the idf.py toolchain --- docs/en/api-guides/tools/idf-monitor.rst | 2 +- docs/zh_CN/api-guides/tools/idf-monitor.rst | 2 +- tools/idf.py | 25 +++++++++++++++++---- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/docs/en/api-guides/tools/idf-monitor.rst b/docs/en/api-guides/tools/idf-monitor.rst index f48275d8fb..2718a0adc5 100644 --- a/docs/en/api-guides/tools/idf-monitor.rst +++ b/docs/en/api-guides/tools/idf-monitor.rst @@ -115,7 +115,7 @@ In the background, IDF Monitor runs the following command:: Output Filtering ~~~~~~~~~~~~~~~~ -IDF monitor can be invoked as ``make monitor PRINT_FILTER=""`` (for make) or ``idf.py monitor PRINT_FILTER=""`` (for cmake), where ``PRINT_FILTER`` is the parameter for output filtering. The default value is an empty string, which means that everything is printed. +IDF monitor can be invoked as ``make monitor PRINT_FILTER=""`` (for make) or ``idf.py monitor --print-filter=""`` (for cmake), where ``PRINT_FILTER`` is the parameter for output filtering. The default value is an empty string, which means that everything is printed. Restrictions on what to print can be specified as a series of ``:`` items where ```` is the tag string and ```` is a character from the set ``{N, E, W, I, D, V, *}`` referring to a level for :doc:`logging <../../api-reference/system/log>`. diff --git a/docs/zh_CN/api-guides/tools/idf-monitor.rst b/docs/zh_CN/api-guides/tools/idf-monitor.rst index 3d842fbd13..c47a071708 100644 --- a/docs/zh_CN/api-guides/tools/idf-monitor.rst +++ b/docs/zh_CN/api-guides/tools/idf-monitor.rst @@ -103,7 +103,7 @@ IDF 监控器在后台运行如下命令:: 输出筛选 ~~~~~~~~~~~~~~~~ -IDF 监视器有两种启用方式:运行 ``make monitor PRINT_FILTER=""`` (适用于 Make)或者 ``idf.py monitor PRINT_FILTER=""`` (适用于 CMake),其中,``PRINT_FILTER`` 是输出筛选的参数。参数默认值为空字符串,可打印任何内容。 +IDF 监视器有两种启用方式:运行 ``make monitor PRINT_FILTER=""`` (适用于 Make)或者 ``idf.py monitor --print-filter=""`` (适用于 CMake),其中,``PRINT_FILTER`` 是输出筛选的参数。参数默认值为空字符串,可打印任何内容。 若需对打印内容设置限制,可指定 ``:`` 等选项,其中 ```` 是标签字符串,```` 是 ``{N, E, W, I, D, V, *}`` 集合中的一个字母,指的是 :doc:`日志 <../../api-reference/system/log>` 级别。 diff --git a/tools/idf.py b/tools/idf.py index cdaf84ecd0..abcdfc8701 100755 --- a/tools/idf.py +++ b/tools/idf.py @@ -361,7 +361,7 @@ def erase_flash(action, ctx, args): _run_tool("esptool.py", esptool_args, args.build_dir) -def monitor(action, ctx, args): +def monitor(action, ctx, args, print_filter): """ Run idf_monitor.py to watch build output """ @@ -385,6 +385,8 @@ def monitor(action, ctx, args): if args.port is not None: monitor_args += ["-p", args.port] monitor_args += ["-b", project_desc["monitor_baud"]] + if print_filter is not None: + monitor_args += ["--print_filter", print_filter] monitor_args += [elf_file] idf_py = [PYTHON] + get_commandline_options(ctx) # commands to re-run idf.py @@ -920,7 +922,7 @@ def init_cli(): }, "show_efuse_table": { "callback": build_target, - "help": "Print eFuse table", + "help": "Print eFuse table.", "order_dependencies": ["reconfigure"], }, "partition_table": { @@ -986,7 +988,7 @@ def init_cli(): "actions": { "flash": { "callback": flash, - "help": "Flash the project", + "help": "Flash the project.", "dependencies": ["all"], "order_dependencies": ["erase_flash"], }, @@ -997,6 +999,22 @@ def init_cli(): "monitor": { "callback": monitor, "help": "Display serial output.", + "options": [ + { + "names": ["--print-filter", "--print_filter"], + "help": ( + "Filter monitor output.\n" + "Restrictions on what to print can be specified as a series of : items " + "where is the tag string and is a character from the set " + "{N, E, W, I, D, V, *} referring to a level. " + 'For example, "tag1:W" matches and prints only the outputs written with ' + 'ESP_LOGW("tag1", ...) or at lower verbosity level, i.e. ESP_LOGE("tag1", ...). ' + 'Not specifying a or using "*" defaults to Verbose level.\n' + 'Please see the IDF Monitor section of the ESP-IDF documentation ' + 'for a more detailed description and further examples.'), + "default": None, + }, + ], "order_dependencies": [ "flash", "partition_table-flash", @@ -1042,7 +1060,6 @@ def init_cli(): ) # Add actions extensions - try: all_actions.append(action_extensions(base_actions, project_dir)) except NameError: From a77f01ec9dafc8311952e1167e436b6059579971 Mon Sep 17 00:00:00 2001 From: Sergei Silnov Date: Mon, 27 May 2019 09:18:38 +0200 Subject: [PATCH 053/486] Update order of arguments for idf.py in docs --- docs/en/api-guides/unit-tests-cmake.rst | 8 ++++---- docs/zh_CN/api-guides/unit-tests-cmake.rst | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/en/api-guides/unit-tests-cmake.rst b/docs/en/api-guides/unit-tests-cmake.rst index 355b7f4ed0..e08b912f87 100644 --- a/docs/en/api-guides/unit-tests-cmake.rst +++ b/docs/en/api-guides/unit-tests-cmake.rst @@ -130,13 +130,13 @@ Change into tools/unit-test-app directory to configure and build it: * `idf.py menuconfig` - configure unit test app. -* `idf.py build -T all` - build unit test app with tests for each component having tests in the ``test`` subdirectory. -* `idf.py build -T xxx` - build unit test app with tests for specific components. -* `idf.py build -T all -E xxx` - build unit test app with all unit tests, except for unit tests of some components. (For instance: `idf.py build -T all -E ulp mbedtls` - build all unit tests exludes ulp and mbedtls components). +* `idf.py -T all build` - build unit test app with tests for each component having tests in the ``test`` subdirectory. +* `idf.py -T xxx build` - build unit test app with tests for specific components. +* `idf.py -T all -E xxx build` - build unit test app with all unit tests, except for unit tests of some components. (For instance: `idf.py -T all -E ulp -E mbedtls build` - build all unit tests exludes ulp and mbedtls components). When the build finishes, it will print instructions for flashing the chip. You can simply run ``idf.py flash`` to flash all build output. -You can also run ``idf.py flash -T all`` or ``idf.py flash -T xxx`` to build and flash. Everything needed will be rebuilt automatically before flashing. +You can also run ``idf.py -T all flash`` or ``idf.py -T xxx flash`` to build and flash. Everything needed will be rebuilt automatically before flashing. Use menuconfig to set the serial port for flashing. diff --git a/docs/zh_CN/api-guides/unit-tests-cmake.rst b/docs/zh_CN/api-guides/unit-tests-cmake.rst index c5f8898b7d..1f3453f994 100644 --- a/docs/zh_CN/api-guides/unit-tests-cmake.rst +++ b/docs/zh_CN/api-guides/unit-tests-cmake.rst @@ -152,21 +152,21 @@ DUT2(slave)终端: - ``idf.py menuconfig`` - 配置单元测试程序。 -- ``idf.py build -T all`` - 编译单元测试程序,测试每个组件 ``test`` +- ``idf.py -T all build`` - 编译单元测试程序,测试每个组件 ``test`` 子目录下的用例。 -- ``idf.py build -T xxx`` - 编译单元测试程序,测试指定的组件。 +- ``idf.py -T xxx build`` - 编译单元测试程序,测试指定的组件。 -- ``idf.py build -T all -E xxx`` - +- ``idf.py -T all -E xxx build`` - 编译单元测试程序,测试所有(除开指定)的组件。例如 - ``idf.py build -T all -E ulp mbedtls`` - + ``idf.py -T all -E ulp mbedtls build`` - 编译所有的单元测试,不包括 ``ulp`` 和 ``mbedtls``\ 组件。 当编译完成时,它会打印出烧写芯片的指令。您只需要运行 ``idf.py flash`` 即可烧写所有编译输出的文件。 -您还可以运行 ``idf.py flash -T all`` 或者 -``idf.py flash -T xxx`` +您还可以运行 ``idf.py -T all flash`` 或者 +``idf.py -T xxx flash`` 来编译并烧写,所有需要的文件都会在烧写之前自动重新编译。 使用 ``menuconfig`` 可以设置烧写测试程序所使用的串口。 From 8e43cd4d6939bcf90c96a37703815a9e136183d0 Mon Sep 17 00:00:00 2001 From: Sergei Silnov Date: Tue, 11 Jun 2019 14:30:01 +0200 Subject: [PATCH 054/486] Add click package to linux setup instructions --- docs/en/get-started-cmake/linux-setup-scratch.rst | 4 ++-- docs/en/get-started-cmake/linux-setup.rst | 4 ++-- docs/zh_CN/get-started-cmake/linux-setup-scratch.rst | 4 ++-- docs/zh_CN/get-started-cmake/linux-setup.rst | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/en/get-started-cmake/linux-setup-scratch.rst b/docs/en/get-started-cmake/linux-setup-scratch.rst index a95c502842..cde88ccfc4 100644 --- a/docs/en/get-started-cmake/linux-setup-scratch.rst +++ b/docs/en/get-started-cmake/linux-setup-scratch.rst @@ -19,11 +19,11 @@ To compile with ESP-IDF you need to get the following packages: - Ubuntu and Debian:: - sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache + sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache - Arch:: - sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache + sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-click python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache .. note:: CMake version 3.5 or newer is required for use with ESP-IDF. Older Linux distributions may require updating, enabling of a "backports" repository, or installing of a "cmake3" package rather than "cmake". diff --git a/docs/en/get-started-cmake/linux-setup.rst b/docs/en/get-started-cmake/linux-setup.rst index 38766a7b7d..8df911f53c 100644 --- a/docs/en/get-started-cmake/linux-setup.rst +++ b/docs/en/get-started-cmake/linux-setup.rst @@ -17,11 +17,11 @@ To compile with ESP-IDF you need to get the following packages: - Ubuntu and Debian:: - sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache + sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache - Arch:: - sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pip python2-pyserial python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache + sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pip python2-pyserial python2-click python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache .. note:: CMake version 3.5 or newer is required for use with ESP-IDF. Older Linux distributions may require updating, enabling of a "backports" repository, or installing of a "cmake3" package rather than "cmake". diff --git a/docs/zh_CN/get-started-cmake/linux-setup-scratch.rst b/docs/zh_CN/get-started-cmake/linux-setup-scratch.rst index 0ba33490c3..967887f74d 100644 --- a/docs/zh_CN/get-started-cmake/linux-setup-scratch.rst +++ b/docs/zh_CN/get-started-cmake/linux-setup-scratch.rst @@ -19,11 +19,11 @@ - Ubuntu 和 Debian:: - sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache + sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache - Arch:: - sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache + sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-click python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache .. note:: diff --git a/docs/zh_CN/get-started-cmake/linux-setup.rst b/docs/zh_CN/get-started-cmake/linux-setup.rst index 6104d9f431..82afb790b0 100644 --- a/docs/zh_CN/get-started-cmake/linux-setup.rst +++ b/docs/zh_CN/get-started-cmake/linux-setup.rst @@ -17,11 +17,11 @@ Linux 平台工具链的标准设置 (CMake) - Ubuntu 和 Debian:: - sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache + sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache - Arch:: - sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache + sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-click python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache .. note:: 使用 ESP-IDF 需要 CMake 3.5 或以上版本。较早版本的 Linux 可能需要升级才能向后移植仓库,或安装 "cmake3" 软件包,而不是安装 "cmake"。 From c4f3afd4b5dc12e88d46b30350034b6cc9ea4c9b Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 20 Nov 2018 15:00:49 +0100 Subject: [PATCH 055/486] ci: add clang static analysis jobs Clang tidy 9.0.0 is to perform static analysis of IDF sources. All component sources are analysed with default sdkconfig configuration, based on examples/get-started/hello_world project (compilation commands are extracted from default build commands for this project). Configuration of static analysis is defined in tools/ci/static-analysis-rules.yml Closes https://github.com/espressif/esp-idf/issues/145 --- .gitlab-ci.yml | 81 ++++++++++++++++++++++++++++++ tools/ci/static-analysis-rules.yml | 23 +++++++++ 2 files changed, 104 insertions(+) create mode 100644 tools/ci/static-analysis-rules.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e782ae0c38..e8c830caa6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -525,6 +525,87 @@ test_ldgen_on_host: # check no crashes found - test -z "$(ls out/crashes/)" || exit 1 +.clang_tidy_check_template: &clang_tidy_check_template + stage: host_test + image: ${CI_DOCKER_REGISTRY}/clang-static-analysis + tags: + - host_test + dependencies: [] + artifacts: + reports: + junit: $IDF_PATH/output.xml + when: always + paths: + - $IDF_PATH/examples/get-started/hello_world/tidybuild/report/* + expire_in: 1 day + script: + - git clone $IDF_ANALYSIS_UTILS static_analysis_utils && cd static_analysis_utils + # Setup parameters of triggered/regular job + - export TRIGGERED_RELATIVE=${BOT_LABEL_STATIC_ANALYSIS-} && export TRIGGERED_ABSOLUTE=${BOT_LABEL_STATIC_ANALYSIS_ALL-} && export TARGET_BRANCH=${BOT_CUSTOMIZED_REVISION-} + - ./analyze.sh $IDF_PATH/examples/get-started/hello_world/ $IDF_PATH/tools/ci/static-analysis-rules.yml $IDF_PATH/output.xml + +.clang_tidy_deploy_template: &clang_tidy_deploy_template + stage: deploy + image: $CI_DOCKER_REGISTRY/esp32-ci-env + tags: + - deploy + script: + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - echo -n $DOCS_DEPLOY_KEY > ~/.ssh/id_rsa_base64 + - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa + - chmod 600 ~/.ssh/id_rsa + - echo -e "Host $DOCS_SERVER\n\tStrictHostKeyChecking no\n\tUser $DOCS_SERVER_USER\n" >> ~/.ssh/config + - export GIT_VER=$(git describe --always) + - cd $IDF_PATH/examples/get-started/hello_world/tidybuild + - mv report $GIT_VER + - tar czvf $GIT_VER.tar.gz $GIT_VER + - export STATIC_REPORT_PATH="web/static_analysis/esp-idf/" + - ssh $DOCS_SERVER -x "mkdir -p $STATIC_REPORT_PATH/clang-tidy" + - scp $GIT_VER.tar.gz $DOCS_SERVER:$STATIC_REPORT_PATH/clang-tidy + - ssh $DOCS_SERVER -x "cd $STATIC_REPORT_PATH/clang-tidy && tar xzvf $GIT_VER.tar.gz && rm -f latest && ln -s $GIT_VER latest" + # add link to view the report + - echo "[static analysis][clang tidy] $CI_DOCKER_REGISTRY/static_analysis/esp-idf/clang-tidy/${GIT_VER}/index.html" + - test ! -e ${GIT_VER}/FAILED_RULES || { echo 'Failed static analysis rules!'; cat ${GIT_VER}/FAILED_RULES; exit 1; } + +clang_tidy_check: + <<: *clang_tidy_check_template + variables: + BOT_NEEDS_TRIGGER_BY_NAME: 1 + BOT_LABEL_STATIC_ANALYSIS: 1 + +clang_tidy_check_regular: + <<: *clang_tidy_check_template + +clang_tidy_check_all: + <<: *clang_tidy_check_template + variables: + BOT_NEEDS_TRIGGER_BY_NAME: 1 + BOT_LABEL_STATIC_ANALYSIS_ALL: 1 + +clang_tidy_deploy: + <<: *clang_tidy_deploy_template + dependencies: + - clang_tidy_check + - clang_tidy_check_all + variables: + BOT_NEEDS_TRIGGER_BY_NAME: 1 + +clang_tidy_deploy_regular: + <<: *clang_tidy_deploy_template + dependencies: + - clang_tidy_check_regular + only: + refs: + - master + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ + - triggers + - schedules + variables: + - $BOT_LABEL_STATIC_ANALYSIS + - $BOT_LABEL_STATIC_ANALYSIS_ALL + test_mdns_fuzzer_on_host: <<: *host_fuzzer_test_template variables: diff --git a/tools/ci/static-analysis-rules.yml b/tools/ci/static-analysis-rules.yml new file mode 100644 index 0000000000..6678b85cb3 --- /dev/null +++ b/tools/ci/static-analysis-rules.yml @@ -0,0 +1,23 @@ +limits: + "clang-analyzer-core.NullDereference" : 9 + "clang-analyzer-unix.Malloc" : 9 + +ignore: + - "llvm-header-guard" + - "llvm-include-order" + +skip: + - "components/mbedtls/mbedtls" + - "components/lwip/lwip" + - "components/asio/asio" + - "components/bootloader/subproject/components/micro-ecc/micro-ecc" + - "components/bt/lib" + - "components/coap/libcoap" + - "components/esp_wifi/lib_esp32" + - "components/expat/expat" + - "components/json/cJSON" + - "components/libsodium/libsodium" + - "components/nghttp/nghttp2" + - "components/protobuf-c/protobuf-c" + - "components/spiffs/spiffs" + - "components/unity/unity" From 8a3cf8ca770711157dcc4e5cd2ab7461386bcba6 Mon Sep 17 00:00:00 2001 From: grumpy-dude Date: Wed, 12 Jun 2019 17:05:41 -0700 Subject: [PATCH 056/486] Allow configuration of local netif hostname via new LWIP component configuration menu item Signed-off-by: Sagar Bijwe Merges https://github.com/espressif/esp-idf/pull/3627 --- components/lwip/Kconfig | 6 ++++++ components/lwip/port/esp32/netif/ethernetif.c | 2 +- components/lwip/port/esp32/netif/nettestif.c | 2 +- components/lwip/port/esp32/netif/wlanif.c | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig index 6fa8a507e2..96bdcd5b20 100644 --- a/components/lwip/Kconfig +++ b/components/lwip/Kconfig @@ -1,5 +1,11 @@ menu "LWIP" + config LWIP_LOCAL_HOSTNAME + string "Local netif hostname" + default 'espressif' + help + The name this device will report to other devices on the network + config LWIP_L2_TO_L3_COPY bool "Enable copy between Layer2 and Layer3 packets" default n diff --git a/components/lwip/port/esp32/netif/ethernetif.c b/components/lwip/port/esp32/netif/ethernetif.c index d61653fcac..99ad88c274 100644 --- a/components/lwip/port/esp32/netif/ethernetif.c +++ b/components/lwip/port/esp32/netif/ethernetif.c @@ -222,7 +222,7 @@ ethernetif_init(struct netif *netif) /* Initialize interface hostname */ #if ESP_LWIP - netif->hostname = "espressif"; + netif->hostname = CONFIG_LWIP_LOCAL_HOSTNAME; #else netif->hostname = "lwip"; #endif diff --git a/components/lwip/port/esp32/netif/nettestif.c b/components/lwip/port/esp32/netif/nettestif.c index 741f542797..4422c21952 100644 --- a/components/lwip/port/esp32/netif/nettestif.c +++ b/components/lwip/port/esp32/netif/nettestif.c @@ -39,7 +39,7 @@ err_t nettestif_init(struct netif *netif) g_last_netif = netif; - netif->hostname = "espressif"; + netif->hostname = CONFIG_LWIP_LOCAL_HOSTNAME; /* * Initialize the snmp variables and counters inside the struct netif. diff --git a/components/lwip/port/esp32/netif/wlanif.c b/components/lwip/port/esp32/netif/wlanif.c index 7c60b69349..cd2bdac8d7 100644 --- a/components/lwip/port/esp32/netif/wlanif.c +++ b/components/lwip/port/esp32/netif/wlanif.c @@ -202,7 +202,7 @@ wlanif_init(struct netif *netif) /* Initialize interface hostname */ #if ESP_LWIP - netif->hostname = "espressif"; + netif->hostname = CONFIG_LWIP_LOCAL_HOSTNAME; #else netif->hostname = "lwip"; #endif From 1138133a78fb4e360dca10a71848b21f08499357 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Fri, 31 May 2019 15:23:10 +0800 Subject: [PATCH 057/486] spi: fix a possible concurrency issue --- components/driver/spi_slave.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/driver/spi_slave.c b/components/driver/spi_slave.c index f9f792a280..43c0b283df 100644 --- a/components/driver/spi_slave.c +++ b/components/driver/spi_slave.c @@ -361,12 +361,14 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg) } } + //Disable interrupt before checking to avoid concurrency issue. + esp_intr_disable(host->intr); //Grab next transaction r = xQueueReceiveFromISR(host->trans_queue, &trans, &do_yield); - if (!r) { - //No packet waiting. Disable interrupt. - esp_intr_disable(host->intr); - } else { + if (r) { + //enable the interrupt again if there is packet to send + esp_intr_enable(host->intr); + //We have a transaction. Send it. host->cur_trans = trans; From d156f0fc0f5f4331392aa5bf69bcb0bb9674d964 Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Tue, 11 Jun 2019 15:46:02 +0800 Subject: [PATCH 058/486] replace strncpy with strlcpy in wifi examples for safety's sake --- examples/provisioning/custom_config/main/app_prov.c | 3 +-- examples/provisioning/softap_prov/main/app_prov.c | 3 +-- examples/system/console/main/cmd_wifi.c | 6 +++--- examples/wifi/iperf/main/cmd_wifi.c | 12 ++++++------ 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/examples/provisioning/custom_config/main/app_prov.c b/examples/provisioning/custom_config/main/app_prov.c index 5e0f68ea8e..d9859cdb4a 100644 --- a/examples/provisioning/custom_config/main/app_prov.c +++ b/examples/provisioning/custom_config/main/app_prov.c @@ -302,8 +302,7 @@ static esp_err_t start_wifi_ap(const char *ssid, const char *pass) }, }; - strncpy((char *) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid)); - wifi_config.ap.ssid_len = strnlen(ssid, sizeof(wifi_config.ap.ssid)); + strlcpy((char *) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid)); if (strlen(pass) == 0) { memset(wifi_config.ap.password, 0, sizeof(wifi_config.ap.password)); diff --git a/examples/provisioning/softap_prov/main/app_prov.c b/examples/provisioning/softap_prov/main/app_prov.c index f7bca2df12..73c8bdfc62 100644 --- a/examples/provisioning/softap_prov/main/app_prov.c +++ b/examples/provisioning/softap_prov/main/app_prov.c @@ -288,8 +288,7 @@ static esp_err_t start_wifi_ap(const char *ssid, const char *pass) }, }; - strncpy((char *) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid)); - wifi_config.ap.ssid_len = strnlen(ssid, sizeof(wifi_config.ap.ssid)); + strlcpy((char *) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid)); if (strlen(pass) == 0) { memset(wifi_config.ap.password, 0, sizeof(wifi_config.ap.password)); diff --git a/examples/system/console/main/cmd_wifi.c b/examples/system/console/main/cmd_wifi.c index 3cca7c3db9..eb2024dabe 100644 --- a/examples/system/console/main/cmd_wifi.c +++ b/examples/system/console/main/cmd_wifi.c @@ -26,7 +26,7 @@ static EventGroupHandle_t wifi_event_group; const int CONNECTED_BIT = BIT0; -static void event_handler(void* arg, esp_event_base_t event_base, +static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { @@ -61,9 +61,9 @@ static bool wifi_join(const char *ssid, const char *pass, int timeout_ms) { initialise_wifi(); wifi_config_t wifi_config = { 0 }; - strncpy((char *) wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid)); + strlcpy((char *) wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid)); if (pass) { - strncpy((char *) wifi_config.sta.password, pass, sizeof(wifi_config.sta.password)); + strlcpy((char *) wifi_config.sta.password, pass, sizeof(wifi_config.sta.password)); } ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); diff --git a/examples/wifi/iperf/main/cmd_wifi.c b/examples/wifi/iperf/main/cmd_wifi.c index 9ef61be48c..a6fbdaa162 100644 --- a/examples/wifi/iperf/main/cmd_wifi.c +++ b/examples/wifi/iperf/main/cmd_wifi.c @@ -53,7 +53,7 @@ static EventGroupHandle_t wifi_event_group; const int CONNECTED_BIT = BIT0; const int DISCONNECTED_BIT = BIT1; -static void scan_done_handler(void* arg, esp_event_base_t event_base, +static void scan_done_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { uint16_t sta_number = 0; @@ -76,14 +76,14 @@ static void scan_done_handler(void* arg, esp_event_base_t event_base, ESP_LOGI(TAG, "sta scan done"); } -static void got_ip_handler(void* arg, esp_event_base_t event_base, +static void got_ip_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { xEventGroupClearBits(wifi_event_group, DISCONNECTED_BIT); xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); } -static void disconnect_handler(void* arg, esp_event_base_t event_base, +static void disconnect_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { if (reconnect) { @@ -128,7 +128,7 @@ static bool wifi_cmd_sta_join(const char* ssid, const char* pass) strlcpy((char*) wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid)); if (pass) { - strncpy((char*) wifi_config.sta.password, pass, sizeof(wifi_config.sta.password)); + strlcpy((char*) wifi_config.sta.password, pass, sizeof(wifi_config.sta.password)); } if (bits & CONNECTED_BIT) { @@ -205,14 +205,14 @@ static bool wifi_cmd_ap_set(const char* ssid, const char* pass) }; reconnect = false; - strncpy((char*) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid)); + strlcpy((char*) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid)); if (pass) { if (strlen(pass) != 0 && strlen(pass) < 8) { reconnect = true; ESP_LOGE(TAG, "password less than 8"); return false; } - strncpy((char*) wifi_config.ap.password, pass, sizeof(wifi_config.ap.password)); + strlcpy((char*) wifi_config.ap.password, pass, sizeof(wifi_config.ap.password)); } if (strlen(pass) == 0) { From 4faf2de035cd7d353399b0077ed115a29abcd716 Mon Sep 17 00:00:00 2001 From: Kirill Chalov Date: Mon, 17 Jun 2019 14:23:52 +0800 Subject: [PATCH 059/486] Doc/review api ref storage --- components/nvs_flash/README.rst | 132 ++++++------ .../nvs_partition_generator/README.rst | 141 ++++++------ components/spi_flash/README.rst | 151 +++++-------- components/vfs/README.rst | 81 +++---- components/wear_levelling/README.rst | 70 +++--- docs/en/api-reference/storage/fatfs.rst | 44 ++-- docs/en/api-reference/storage/index.rst | 2 +- docs/en/api-reference/storage/nvs_flash.rst | 18 +- docs/en/api-reference/storage/sdmmc.rst | 98 +++++---- docs/en/api-reference/storage/spi_flash.rst | 31 +-- docs/en/api-reference/storage/spiffs.rst | 103 ++++----- .../api-reference/storage/wear-levelling.rst | 2 +- tools/mass_mfg/docs/README.rst | 200 ++++++++++-------- 13 files changed, 538 insertions(+), 535 deletions(-) diff --git a/components/nvs_flash/README.rst b/components/nvs_flash/README.rst index 6a4652f2ff..f8c2f4a1f6 100644 --- a/components/nvs_flash/README.rst +++ b/components/nvs_flash/README.rst @@ -4,54 +4,60 @@ Non-volatile storage library Introduction ------------ -Non-volatile storage (NVS) library is designed to store key-value pairs in flash. This sections introduces some concepts used by NVS. +Non-volatile storage (NVS) library is designed to store key-value pairs in flash. This section introduces some concepts used by NVS. + Underlying storage ^^^^^^^^^^^^^^^^^^ -Currently NVS uses a portion of main flash memory through ``spi_flash_{read|write|erase}`` APIs. The library uses the all the partitions with ``data`` type and ``nvs`` subtype. The application can choose to use the partition with label ``nvs`` through ``nvs_open`` API or any of the other partition by specifying its name through ``nvs_open_from_part`` API. +Currently, NVS uses a portion of main flash memory through ``spi_flash_{read|write|erase}`` APIs. The library uses all the partitions with ``data`` type and ``nvs`` subtype. The application can choose to use the partition with the label ``nvs`` through the ``nvs_open`` API function or any other partition by specifying its name using the ``nvs_open_from_part`` API function. -Future versions of this library may add other storage backends to keep data in another flash chip (SPI or I2C), RTC, FRAM, etc. +Future versions of this library may have other storage backends to keep data in another flash chip (SPI or I2C), RTC, FRAM, etc. .. note:: if an NVS partition is truncated (for example, when the partition table layout is changed), its contents should be erased. ESP-IDF build system provides a ``make erase_flash`` target to erase all contents of the flash chip. -.. note:: NVS works best for storing many small values, rather than a few large values of type 'string' and 'blob'. If storing large blobs or strings is required, consider using the facilities provided by the FAT filesystem on top of the wear levelling library. +.. note:: NVS works best for storing many small values, rather than a few large values of the type 'string' and 'blob'. If you need to store large blobs or strings, consider using the facilities provided by the FAT filesystem on top of the wear levelling library. + Keys and values ^^^^^^^^^^^^^^^ -NVS operates on key-value pairs. Keys are ASCII strings, maximum key length is currently 15 characters. Values can have one of the following types: +NVS operates on key-value pairs. Keys are ASCII strings; the maximum key length is currently 15 characters. Values can have one of the following types: - integer types: ``uint8_t``, ``int8_t``, ``uint16_t``, ``int16_t``, ``uint32_t``, ``int32_t``, ``uint64_t``, ``int64_t`` - zero-terminated string - variable length binary data (blob) .. note:: - String values are currently limited to 4000 bytes. This includes the null terminator. Blob values are limited to 508000 bytes or (97.6% of the partition size - 4000) bytes whichever is lower. -Additional types, such as ``float`` and ``double`` may be added later. + String values are currently limited to 4000 bytes. This includes the null terminator. Blob values are limited to 508000 bytes or 97.6% of the partition size - 4000 bytes, whichever is lower. -Keys are required to be unique. Writing a value for a key which already exists behaves as follows: +Additional types, such as ``float`` and ``double`` might be added later. -- if the new value is of the same type as old one, value is updated -- if the new value has different data type, an error is returned +Keys are required to be unique. Assigning a new value to an existing key works as follows: + +- if the new value is of the same type as the old one, value is updated +- if the new value has a different data type, an error is returned + +Data type check is also performed when reading a value. An error is returned if the data type of the read operation does not match the data type of the value. -Data type check is also performed when reading a value. An error is returned if data type of read operation doesn’t match the data type of the value. Namespaces ^^^^^^^^^^ -To mitigate potential conflicts in key names between different components, NVS assigns each key-value pair to one of namespaces. Namespace names follow the same rules as key names, i.e. 15 character maximum length. Namespace name is specified in the ``nvs_open`` or ``nvs_open_from_part`` call. This call returns an opaque handle, which is used in subsequent calls to ``nvs_read_*``, ``nvs_write_*``, and ``nvs_commit`` functions. This way, handle is associated with a namespace, and key names will not collide with same names in other namespaces. -Please note that the namespaces with same name in different NVS partitions are considered as separate namespaces. +To mitigate potential conflicts in key names between different components, NVS assigns each key-value pair to one of namespaces. Namespace names follow the same rules as key names, i.e., the maximum length is 15 characters. Namespace name is specified in the ``nvs_open`` or ``nvs_open_from_part`` call. This call returns an opaque handle, which is used in subsequent calls to the ``nvs_read_*``, ``nvs_write_*``, and ``nvs_commit`` functions. This way, a handle is associated with a namespace, and key names will not collide with same names in other namespaces. +Please note that the namespaces with the same name in different NVS partitions are considered as separate namespaces. + Security, tampering, and robustness ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ NVS is not directly compatible with the ESP32 flash encryption system. However, data can still be stored in encrypted form if NVS encryption is used together with ESP32 flash encryption. Please refer to :ref:`nvs_encryption` for more details. -If NVS encryption is not used, it is possible for anyone with physical access to the flash chip to alter, erase, or add key-value pairs. With NVS encryption enabled, it is not possible to alter or add a key-value pair and get recognized as a valid pair without knowing corresponding NVS encryption keys. However, there is no tamper-resistance against erase operation. +If NVS encryption is not used, it is possible for anyone with physical access to the flash chip to alter, erase, or add key-value pairs. With NVS encryption enabled, it is not possible to alter or add a key-value pair and get recognized as a valid pair without knowing corresponding NVS encryption keys. However, there is no tamper-resistance against the erase operation. + +The library does try to recover from conditions when flash memory is in an inconsistent state. In particular, one should be able to power off the device at any point and time and then power it back on. This should not result in loss of data, except for the new key-value pair if it was being written at the moment of powering off. The library should also be able to initialize properly with any random data present in flash memory. -The library does try to recover from conditions when flash memory is in an inconsistent state. In particular, one should be able to power off the device at any point and time and then power it back on. This should not result in loss of data, except for the new key-value pair if it was being written at the moment of power off. The library should also be able to initialize properly with any random data present in flash memory. Internals --------- @@ -59,7 +65,7 @@ Internals Log of key-value pairs ^^^^^^^^^^^^^^^^^^^^^^ -NVS stores key-value pairs sequentially, with new key-value pairs being added at the end. When a value of any given key has to be updated, new key-value pair is added at the end of the log and old key-value pair is marked as erased. +NVS stores key-value pairs sequentially, with new key-value pairs being added at the end. When a value of any given key has to be updated, a new key-value pair is added at the end of the log and the old key-value pair is marked as erased. Pages and entries ^^^^^^^^^^^^^^^^^ @@ -67,22 +73,22 @@ Pages and entries NVS library uses two main entities in its operation: pages and entries. Page is a logical structure which stores a portion of the overall log. Logical page corresponds to one physical sector of flash memory. Pages which are in use have a *sequence number* associated with them. Sequence numbers impose an ordering on pages. Higher sequence numbers correspond to pages which were created later. Each page can be in one of the following states: Empty/uninitialized - Flash storage for the page is empty (all bytes are ``0xff``). Page isn't used to store any data at this point and doesn’t have a sequence number. + Flash storage for the page is empty (all bytes are ``0xff``). Page is not used to store any data at this point and does not have a sequence number. Active - Flash storage is initialized, page header has been written to flash, page has a valid sequence number. Page has some empty entries and data can be written there. At most one page can be in this state at any given moment. + Flash storage is initialized, page header has been written to flash, page has a valid sequence number. Page has some empty entries and data can be written there. No more than one page can be in this state at any given moment. Full Flash storage is in a consistent state and is filled with key-value pairs. Writing new key-value pairs into this page is not possible. It is still possible to mark some key-value pairs as erased. Erasing - Non-erased key-value pairs are being moved into another page so that the current page can be erased. This is a transient state, i.e. page should never stay in this state when any API call returns. In case of a sudden power off, move-and-erase process will be completed upon next power on. + Non-erased key-value pairs are being moved into another page so that the current page can be erased. This is a transient state, i.e., page should never stay in this state at the time when any API call returns. In case of a sudden power off, the move-and-erase process will be completed upon the next power-on. Corrupted - Page header contains invalid data, and further parsing of page data was canceled. Any items previously written into this page will not be accessible. Corresponding flash sector will not be erased immediately, and will be kept along with sectors in *uninitialized* state for later use. This may be useful for debugging. + Page header contains invalid data, and further parsing of page data was canceled. Any items previously written into this page will not be accessible. The corresponding flash sector will not be erased immediately and will be kept along with sectors in *uninitialized* state for later use. This may be useful for debugging. -Mapping from flash sectors to logical pages doesn't have any particular order. Library will inspect sequence numbers of pages found in each flash sector and organize pages in a list based on these numbers. +Mapping from flash sectors to logical pages does not have any particular order. The library will inspect sequence numbers of pages found in each flash sector and organize pages in a list based on these numbers. :: @@ -101,11 +107,11 @@ Mapping from flash sectors to logical pages doesn't have any particular order. L Structure of a page ^^^^^^^^^^^^^^^^^^^ -For now we assume that flash sector size is 4096 bytes and that ESP32 flash encryption hardware operates on 32-byte blocks. It is possible to introduce some settings configurable at compile-time (e.g. via menuconfig) to accommodate flash chips with different sector sizes (although it is not clear if other components in the system, e.g. SPI flash driver and SPI flash cache can support these other sizes). +For now, we assume that flash sector size is 4096 bytes and that ESP32 flash encryption hardware operates on 32-byte blocks. It is possible to introduce some settings configurable at compile-time (e.g., via menuconfig) to accommodate flash chips with different sector sizes (although it is not clear if other components in the system, e.g., SPI flash driver and SPI flash cache can support these other sizes). Page consists of three parts: header, entry state bitmap, and entries themselves. To be compatible with ESP32 flash encryption, entry size is 32 bytes. For integer types, entry holds one key-value pair. For strings and blobs, an entry holds part of key-value pair (more on that in the entry structure description). -The following diagram illustrates page structure. Numbers in parentheses indicate size of each part in bytes. :: +The following diagram illustrates the page structure. Numbers in parentheses indicate the size of each part in bytes. :: +-----------+--------------+-------------+-------------------------+ | State (4) | Seq. no. (4) | version (1) | Unused (19) | CRC32 (4) | Header (32) @@ -122,23 +128,23 @@ The following diagram illustrates page structure. Numbers in parentheses indicat | Entry 125 (32) | +------------------------------------------------------------------+ -Page header and entry state bitmap are always written to flash unencrypted. Entries are encrypted if flash encryption feature of the ESP32 is used. +Page header and entry state bitmap are always written to flash unencrypted. Entries are encrypted if flash encryption feature of ESP32 is used. -Page state values are defined in such a way that changing state is possible by writing 0 into some of the bits. Therefore it not necessary to erase the page to change page state, unless that is a change to *erased* state. +Page state values are defined in such a way that changing state is possible by writing 0 into some of the bits. Therefore it is not necessary to erase the page to change its state unless that is a change to the *erased* state. -The version field in the header reflects NVS format version used. For backward compatibility reasons, it is decremented for every version upgrade starting at 0xff (i.e. 0xff for version-1, 0xfe for version-2 and so on). +The version field in the header reflects the NVS format version used. For backward compatibility reasons, it is decremented for every version upgrade starting at 0xff (i.e., 0xff for version-1, 0xfe for version-2 and so on). -CRC32 value in header is calculated over the part which doesn't include state value (bytes 4 to 28). Unused part is currently filled with ``0xff`` bytes. +CRC32 value in the header is calculated over the part which does not include a state value (bytes 4 to 28). The unused part is currently filled with ``0xff`` bytes. -The following sections describe structure of entry state bitmap and entry itself. +The following sections describe the structure of entry state bitmap and entry itself. Entry and entry state bitmap ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Each entry can be in one of the following three states. Each state is represented with two bits in the entry state bitmap. Final four bits in the bitmap (256 - 2 * 126) are unused. +Each entry can be in one of the following three states represented with two bits in the entry state bitmap. The final four bits in the bitmap (256 - 2 * 126) are not used. Empty (2'b11) - Nothing is written into the specific entry yet. It is in an uninitialized state (all bytes ``0xff``). + Nothing is written into the specific entry yet. It is in an uninitialized state (all bytes are ``0xff``). Written (2'b10) A key-value pair (or part of key-value pair which spans multiple entries) has been written into the entry. @@ -152,7 +158,7 @@ Erased (2'b00) Structure of entry ^^^^^^^^^^^^^^^^^^ -For values of primitive types (currently integers from 1 to 8 bytes long), entry holds one key-value pair. For string and blob types, entry holds part of the whole key-value pair. For strings, in case when a key-value pair spans multiple entries, all entries are stored in the same page. Blobs are allowed to span over multiple pages by dividing them into smaller chunks. For the purpose tracking these chunks, an additional fixed length metadata entry is stored called "blob index" entry. Earlier format of blobs are still supported (can be read and modified). However, once the blobs are modified, they are stored using the new format. +For values of primitive types (currently integers from 1 to 8 bytes long), entry holds one key-value pair. For string and blob types, entry holds part of the whole key-value pair. For strings, in case when a key-value pair spans multiple entries, all entries are stored in the same page. Blobs are allowed to span over multiple pages by dividing them into smaller chunks. For tracking these chunks, an additional fixed length metadata entry is stored called "blob index". Earlier formats of blobs are still supported (can be read and modified). However, once the blobs are modified, they are stored using the new format. :: @@ -160,10 +166,10 @@ For values of primitive types (currently integers from 1 to 8 bytes long), entry | NS (1) | Type (1) | Span (1) | ChunkIndex (1) | CRC32 (4) | Key (16) | Data (8) | +--------+----------+----------+----------------+-----------+---------------+----------+ - Primitive +--------------------------------+ - +--------> | Data (8) | + Primitive +--------------------------------+ + +--------> | Data (8) | | Types +--------------------------------+ - +-> Fixed length -- + +-> Fixed length -- | | +---------+--------------+---------------+-------+ | +--------> | Size(4) | ChunkCount(1)| ChunkStart(1) | Rsv(2)| Data format ---+ Blob Index +---------+--------------+---------------+-------+ @@ -176,25 +182,25 @@ For values of primitive types (currently integers from 1 to 8 bytes long), entry Individual fields in entry structure have the following meanings: NS - Namespace index for this entry. See section on namespaces implementation for explanation of this value. + Namespace index for this entry. For more information on this value, see the section on namespaces implementation. Type - One byte indicating data type of value. See ``ItemType`` enumeration in ``nvs_types.h`` for possible values. + One byte indicating the value data type. See the ``ItemType`` enumeration in ``nvs_types.h`` for possible values. Span - Number of entries used by this key-value pair. For integer types, this is equal to 1. For strings and blobs this depends on value length. + Number of entries used by this key-value pair. For integer types, this is equal to 1. For strings and blobs, this depends on value length. ChunkIndex - Used to store index of the blob-data chunk for blob types. For other types, this should be ``0xff``. + Used to store the index of a blob-data chunk for blob types. For other types, this should be ``0xff``. CRC32 Checksum calculated over all the bytes in this entry, except for the CRC32 field itself. Key - Zero-terminated ASCII string containing key name. Maximum string length is 15 bytes, excluding zero terminator. + Zero-terminated ASCII string containing a key name. Maximum string length is 15 bytes, excluding a zero terminator. Data - For integer types, this field contains the value itself. If the value itself is shorter than 8 bytes it is padded to the right, with unused bytes filled with ``0xff``. + For integer types, this field contains the value itself. If the value itself is shorter than 8 bytes, it is padded to the right, with unused bytes filled with ``0xff``. For "blob index" entry, these 8 bytes hold the following information about data-chunks: @@ -205,23 +211,23 @@ Data (Only for blob index.) Total number of blob-data chunks into which the blob was divided during storage. - ChunkStart - (Only for blob index.) ChunkIndex of the first blob-data chunk of this blob. Subsequent chunks have chunkIndex incrementally allocated (step of 1) + (Only for blob index.) ChunkIndex of the first blob-data chunk of this blob. Subsequent chunks have chunkIndex incrementally allocated (step of 1). - For string and blob data chunks, these 8 bytes hold additional data about the value, described next: + For string and blob data chunks, these 8 bytes hold additional data about the value, which are described below: - Size - (Only for strings and blobs.) Size, in bytes, of actual data. For strings, this includes zero terminator. + (Only for strings and blobs.) Size, in bytes, of actual data. For strings, this includes zero terminators. - CRC32 (Only for strings and blobs.) Checksum calculated over all bytes of data. -Variable length values (strings and blobs) are written into subsequent entries, 32 bytes per entry. `Span` field of the first entry indicates how many entries are used. +Variable length values (strings and blobs) are written into subsequent entries, 32 bytes per entry. The `Span` field of the first entry indicates how many entries are used. Namespaces ^^^^^^^^^^ -As mentioned above, each key-value pair belongs to one of the namespaces. Namespaces identifiers (strings) are stored as keys of key-value pairs in namespace with index 0. Values corresponding to these keys are indexes of these namespaces. +As mentioned above, each key-value pair belongs to one of the namespaces. Namespace identifiers (strings) are stored as keys of key-value pairs in namespace with index 0. Values corresponding to these keys are indexes of these namespaces. :: @@ -239,23 +245,23 @@ As mentioned above, each key-value pair belongs to one of the namespaces. Namesp Item hash list ^^^^^^^^^^^^^^ -To reduce the number of reads performed from flash memory, each member of Page class maintains a list of pairs: (item index; item hash). This list makes searches much quicker. Instead of iterating over all entries, reading them from flash one at a time, ``Page::findItem`` first performs search for item hash in the hash list. This gives the item index within the page, if such an item exists. Due to a hash collision it is possible that a different item will be found. This is handled by falling back to iteration over items in flash. +To reduce the number of reads from flash memory, each member of the Page class maintains a list of pairs: item index; item hash. This list makes searches much quicker. Instead of iterating over all entries, reading them from flash one at a time, ``Page::findItem`` first performs a search for the item hash in the hash list. This gives the item index within the page if such an item exists. Due to a hash collision, it is possible that a different item will be found. This is handled by falling back to iteration over items in flash. -Each node in hash list contains a 24-bit hash and 8-bit item index. Hash is calculated based on item namespace, key name and ChunkIndex. CRC32 is used for calculation, result is truncated to 24 bits. To reduce overhead of storing 32-bit entries in a linked list, list is implemented as a doubly-linked list of arrays. Each array holds 29 entries, for the total size of 128 bytes, together with linked list pointers and 32-bit count field. Minimal amount of extra RAM usage per page is therefore 128 bytes, maximum is 640 bytes. +Each node in the hash list contains a 24-bit hash and 8-bit item index. Hash is calculated based on item namespace, key name, and ChunkIndex. CRC32 is used for calculation; the result is truncated to 24 bits. To reduce the overhead for storing 32-bit entries in a linked list, the list is implemented as a double-linked list of arrays. Each array holds 29 entries, for the total size of 128 bytes, together with linked list pointers and a 32-bit count field. The minimum amount of extra RAM usage per page is therefore 128 bytes; maximum is 640 bytes. .. _nvs_encryption: NVS Encryption -------------- -Data stored in NVS partitions can be encrypted using AES-XTS in the manner similar to one mentioned in disc encryption standard IEEE P1619. For the purpose of encryption, each entry is considered as one `sector` and relative address of the entry (w.r.t. partition-start) is fed to the encryption algorithm as `sector-number`. The keys required for nvs encryption are stored in yet another partition, which is protected using :doc:`Flash Encryption <../../security/flash-encryption>`. Therefore, enabling :doc:`Flash Encryption <../../security/flash-encryption>` is a prerequisite for NVS encryption. +Data stored in NVS partitions can be encrypted using AES-XTS in the manner similar to the one mentioned in disk encryption standard IEEE P1619. For the purpose of encryption, each entry is treated as one `sector` and relative address of the entry (w.r.t. partition-start) is fed to the encryption algorithm as `sector-number`. The keys required for NVS encryption are stored in yet another partition, which is protected using :doc:`Flash Encryption <../../security/flash-encryption>`. Therefore, enabling :doc:`Flash Encryption <../../security/flash-encryption>` is a prerequisite for NVS encryption. .. _nvs_key_partition: NVS key partition ^^^^^^^^^^^^^^^^^ -An application requiring NVS encryption support needs to be compiled with a key-partition of type `data` and subtype `key`. This partition should be marked as `encrypted`. Refer to :doc:`Partition Tables <../../api-guides/partition-tables>` for more details. The size of the partition should be 4096 bytes (minimum partition size). The structure of this partition is depicted below. +An application requiring NVS encryption support needs to be compiled with a key-partition of the type `data` and subtype `key`. This partition should be marked as `encrypted`. Refer to :doc:`Partition Tables <../../api-guides/partition-tables>` for more details. The size of the partition should be 4096 bytes (minimum partition size). The structure of this partition is depicted below. :: @@ -267,25 +273,33 @@ An application requiring NVS encryption support needs to be compiled with a key- | CRC32(4) | +---------------------------------------------+ -This partition can be generated using `nvs partition generator` utility and flashed onto the device. Since the partition is marked `encrypted` and :doc:`Flash Encryption <../../security/flash-encryption>` is enabled, bootloader will encrypt this partition using flash encryption key on first boot. Alternatively, the keys can be generated after startup using ``nvs_flash_generate_keys`` API provided by ``nvs_flash.h``, which will then write those keys onto the key-partition in encrypted form. +This partition can be generated using `nvs partition generator` utility and flashed onto the device. Since the partition is marked `encrypted` and :doc:`Flash Encryption <../../security/flash-encryption>` is enabled, bootloader will encrypt this partition using flash encryption key on the first boot. Alternatively, the keys can be generated after startup using the ``nvs_flash_generate_keys`` API function provided by ``nvs_flash.h``, which will then write those keys onto the key-partition in encrypted form. It is possible for an application to use different keys for different NVS partitions and thereby have multiple key-partitions. However, it is a responsibility of the application to provide correct key-partition/keys for the purpose of encryption/decryption. Encrypted Read/Write ^^^^^^^^^^^^^^^^^^^^ -The same NVS APIs ``nvs_read_*`` or ``nvs_write_*`` can be used for reading and writing of encrypted nvs partition as well. However, the APIs for initialising NVS partitions are different. ``nvs_flash_secure_init`` and ``nvs_flash_secure_init_partition`` are used for initialising instead of ``nvs_flash_init`` and ``nvs_flash_init_partition`` respectively. ``nvs_sec_cfg_t`` structure required for these APIs can be populated using ``nvs_flash_generate_keys`` or ``nvs_flash_read_security_cfg``. +The same NVS API functions ``nvs_read_*`` or ``nvs_write_*`` can be used for reading of, and writing to an encrypted nvs partition as well. However, the API functions for initialising NVS partitions are different: ``nvs_flash_secure_init`` and ``nvs_flash_secure_init_partition`` instead of ``nvs_flash_init`` and ``nvs_flash_init_partition`` respectively. The ``nvs_sec_cfg_t`` structure required for these API functions can be populated using ``nvs_flash_generate_keys`` or ``nvs_flash_read_security_cfg``. -Applications are expected to follow the following steps in order to perform NVS read/write operations with encryption enabled. +Applications are expected to follow the steps below in order to perform NVS read/write operations with encryption enabled. - 1. Find key partition and NVS data partition using ``esp_partition_find*`` APIs. - 2. Populate ``nvs_sec_cfg_t`` struct using ``nvs_flash_read_security_cfg`` or ``nvs_flash_generate_keys`` APIs. - 3. Initialise NVS flash partition using ``nvs_flash_secure_init`` or ``nvs_flash_secure_init_partition`` APIs. - 4. Open a namespace using ``nvs_open`` or ``nvs_open_from_part`` APIs - 5. Perform NVS read/write operations using ``nvs_read_*`` or ``nvs_write_*`` - 6. Deinitialise NVS partition using ``nvs_flash_deinit``. + 1. Find key partition and NVS data partition using ``esp_partition_find*`` API functions. + 2. Populate the ``nvs_sec_cfg_t`` struct using the ``nvs_flash_read_security_cfg`` or ``nvs_flash_generate_keys`` API functions. + 3. Initialise NVS flash partition using the ``nvs_flash_secure_init`` or ``nvs_flash_secure_init_partition`` API functions. + 4. Open a namespace using the ``nvs_open`` or ``nvs_open_from_part`` API functions. + 5. Perform NVS read/write operations using ``nvs_read_*`` or ``nvs_write_*``. + 6. Deinitialise an NVS partition using ``nvs_flash_deinit``. NVS iterators ^^^^^^^^^^^^^ -Iterators allow to list key-value pairs stored in NVS based on specified partition name, namespace and data type. ``nvs_entry_find`` returns an opaque handle, which is used in subsequent calls to ``nvs_entry_next`` and ``nvs_entry_info`` function. ``nvs_entry_next`` function returns iterator to the next key-value pair. If none or no other key-value pair was found for given criteria, ``nvs_entry_find`` and ``nvs_entry_next`` functions return NULL. In that case, iterator does not have to be released. Otherwise, ``nvs_release_iterator`` function has to be used, when iterator is no longer needed. Information about each key-value pair can be obtained from ``nvs_entry_info`` function. \ No newline at end of file +Iterators allow to list key-value pairs stored in NVS, based on specified partition name, namespace, and data type. + +There are the following functions available: + +- ``nvs_entry_find`` returns an opaque handle, which is used in subsequent calls to the ``nvs_entry_next`` and ``nvs_entry_info`` functions. +- ``nvs_entry_next`` returns iterator to the next key-value pair. +- ``nvs_entry_info`` returns information about each key-value pair + +If none or no other key-value pair was found for given criteria, ``nvs_entry_find`` and ``nvs_entry_next`` return NULL. In that case, the iterator does not have to be released. If the iterator is no longer needed, you can release it by using the function ``nvs_release_iterator``. diff --git a/components/nvs_flash/nvs_partition_generator/README.rst b/components/nvs_flash/nvs_partition_generator/README.rst index cf31261366..bcb74f7cd1 100644 --- a/components/nvs_flash/nvs_partition_generator/README.rst +++ b/components/nvs_flash/nvs_partition_generator/README.rst @@ -4,64 +4,81 @@ NVS Partition Generator Utility Introduction ------------ -:component_file:`nvs_flash/nvs_partition_generator/nvs_partition_gen.py` utility is designed to help create a binary file, compatible with NVS architecture defined in :doc:`Non-Volatile Storage `, based on user provided key-value pairs in a CSV file. -Utility is ideally suited for generating a binary blob, containing data specific to ODM/OEM, which can be flashed externally at the time of device manufacturing. This helps manufacturers set unique value for various parameters for each device, e.g. serial number, while using same application firmware for all devices. +The utility :component_file:`nvs_flash/nvs_partition_generator/nvs_partition_gen.py` creates a binary file based on key-value pairs provided in a CSV file. The binary file is compatible with NVS architecture defined in :doc:`Non-Volatile Storage `. +This utility is ideally suited for generating a binary blob, containing data specific to ODM/OEM, which can be flashed externally at the time of device manufacturing. This allows manufacturers to generate many instances of the same application firmware with customized parameters for each device, such as a serial number. + Prerequisites ------------- -To use this utility in encryption mode, the following packages need to be installed: +To use this utility in encryption mode, install the following packages: - cryptography package -These dependencies is already captured by including these packages in `requirement.txt` in top level IDF directory. +All the required packages are included in `requirements.txt` in the root of the esp-idf directory. + CSV file format --------------- -Each row of the .csv file should have 4 parameters, separated by comma. Below is the description of each of these parameters: +Each line of a .csv file should contain 4 parameters, separated by a comma. The table below provides the description for each of these parameters. -Key - Key of the data. Data can later be accessed from an application via this key. ++-----+-----------+----------------------------------------------------------------------+-----------------------------------------------------+ +| No. | Parameter | Description | Notes | ++=====+===========+======================================================================+=====================================================+ +| 1 | Key | Key of the data. The data can be accessed later from | | +| | | an application using this key. | | ++-----+-----------+----------------------------------------------------------------------+-----------------------------------------------------+ +| 2 | Type | Supported values are ``file``, ``data`` and ``namespace``. | | ++-----+-----------+----------------------------------------------------------------------+-----------------------------------------------------+ +| 3 | Encoding | Supported values are: ``u8``, ``i8``, ``u16``, ``u32``, | As of now, for the ``file`` type, | +| | | ``i32``, ``string``, ``hex2bin``, ``base64`` and ``binary``. | only ``hex2bin``, ``base64``, ``string``, | +| | | This specifies how actual data values are encoded in the | and ``binary`` encoding is supported. | +| | | resulting binary file. The difference between the ``string`` | | +| | | and ``binary`` encoding is that ``string`` data is terminated | | +| | | with a NULL character, whereas ``binary`` data is not. | | ++-----+-----------+----------------------------------------------------------------------+-----------------------------------------------------+ +| 4 | Value | Data value. | Encoding and Value cells for the ``namespace`` | +| | | | field type should be empty. Encoding and Value | +| | | | of ``namespace`` is fixed and is not configurable. | +| | | | Any values in these cells are ignored. | ++-----+-----------+----------------------------------------------------------------------+-----------------------------------------------------+ -Type - Supported values are ``file``, ``data`` and ``namespace``. +.. note:: The first line of the CSV file should always be the column header and it is not configurable. -Encoding - Supported values are: ``u8``, ``i8``, ``u16``, ``u32``, ``i32``, ``string``, ``hex2bin``, ``base64`` and ``binary``. This specifies how actual data values are encoded in the resultant binary file. Difference between ``string`` and ``binary`` encoding is that ``string`` data is terminated with a NULL character, whereas ``binary`` data is not. - -.. note:: For ``file`` type, only ``hex2bin``, ``base64``, ``string`` and ``binary`` is supported as of now. - -Value - Data value. - -.. note:: Encoding and Value cells for ``namespace`` field type should be empty. Encoding and Value of ``namespace`` is fixed and isn't configurable. Any value in these cells are ignored. - -.. note:: First row of the CSV file should always be column header and isn't configurable. - -Below is an example dump of such CSV file:: +Below is an example dump of such a CSV file:: key,type,encoding,value <-- column header namespace_name,namespace,, <-- First entry should be of type "namespace" key1,data,u8,1 key2,file,string,/path/to/file -.. note:: Make sure there are no spaces before and after ',' or at the end of each line in CSV file. + +.. note:: + + Make sure there are **no spaces**: + - before and after ',' + - at the end of each line in a CSV file + NVS Entry and Namespace association ----------------------------------- -When a new namespace entry is encountered in the CSV file, each follow-up entries will be part of that namespace, until next namespace entry is found, in which case all the follow-up entries will be part of the new namespace. +When a namespace entry is encountered in a CSV file, each following entry will be treated as part of that namespace until the next namespace entry is found. At this point, all the following entries will be treated as part of the new namespace. + +.. note:: First entry in a CSV file should always be a ``namespace`` entry. -.. note:: First entry in a CSV file should always be ``namespace`` entry. Multipage Blob Support ---------------------- -By default, binary blobs are allowed to span over multiple pages and written in the format mentioned in section :ref:`structure_of_entry`. -If older format is intended to be used, the utility provides an option to disable this feature. +By default, binary blobs are allowed to span over multiple pages and are written in the format mentioned in Section :ref:`structure_of_entry`. +If you intend to use an older format, the utility provides an option to disable this feature. + Encryption Support ------------------- -This utility allows you to create an enrypted binary file also. Encryption used is AES-XTS encryption. Refer to :ref:`nvs_encryption` for more details. + +The NVS Partition Generator utility also allows you to create an encrypted binary file. The utility uses the AES-XTS encryption. Please refer to :ref:`nvs_encryption` for more details. + Running the utility ------------------- @@ -74,29 +91,32 @@ Running the utility [--keyfile KEYFILE] [--outdir OUTDIR] -+------------------------+----------------------------------------------------------------------------------------------+ -| Arguments | Description | -+========================+==============================================================================================+ -| --input INPUT | Path to CSV file to parse. | -+------------------------+----------------------------------------------------------------------------------------------+ -| --output OUTPUT | Path to output generated binary file. | -+------------------------+----------------------------------------------------------------------------------------------+ -| --size SIZE | Size of NVS Partition in bytes (must be multiple of 4096) | -+------------------------+----------------------------------------------------------------------------------------------+ -| --version {v1,v2} | Set version. Default: v2 | -+------------------------+----------------------------------------------------------------------------------------------+ -| --keygen {true,false} | Generate keys for encryption. | -+------------------------+----------------------------------------------------------------------------------------------+ -| --encrypt {true,false} | Set encryption mode. Default: false | -+------------------------+----------------------------------------------------------------------------------------------+ -| --keyfile KEYFILE | File having key for encryption (Applicable only if encryption mode is true) | -+------------------------+----------------------------------------------------------------------------------------------+ -| --outdir OUTDIR | The output directory to store the files created (Default: current directory) | -+------------------------+----------------------------------------------------------------------------------------------+ ++------------------------+---------------------------------------------------+-------------------+ +| Arguments | Description | Default Value | ++========================+===================================================+===================+ +| --input INPUT | Path to a CSV file to parse. | | ++------------------------+---------------------------------------------------+-------------------+ +| --output OUTPUT | Path to the generated binary file. | | ++------------------------+---------------------------------------------------+-------------------+ +| --size SIZE | Size of NVS Partition in bytes | | +| | (must be multiple of 4096). | | ++------------------------+---------------------------------------------------+-------------------+ +| --version {v1,v2} | Set version. | v2 | ++------------------------+---------------------------------------------------+-------------------+ +| --keygen {true,false} | Generate keys for encryption. | | ++------------------------+---------------------------------------------------+-------------------+ +| --encrypt {true,false} | Set encryption mode. Default: false. | false | ++------------------------+---------------------------------------------------+-------------------+ +| --keyfile KEYFILE | File containing the key for encryption | | +| | (Applicable only if encryption mode is true). | | ++------------------------+---------------------------------------------------+-------------------+ +| --outdir OUTDIR | The output directory to store the created files. | current directory | ++------------------------+---------------------------------------------------+-------------------+ You can run this utility in two modes: - - Default mode - Binary generated in this mode is an unencrypted binary file. - - Encryption mode - Binary generated in this mode is an encrypted binary file. + + - **Default mode**: You get an unencrypted binary file. + - **Encryption mode**: You get an encrypted binary file. **In default mode:** @@ -109,12 +129,11 @@ You can run this utility in two modes: [--keygen {true,false}] [--encrypt {true,false}] [--keyfile KEYFILE] [--outdir OUTDIR] -You can run the utility using below command:: +You can run the utility using the command below:: python nvs_partition_gen.py --input sample.csv --output sample.bin --size 0x3000 - **In encryption mode:** ----------------------- @@ -126,21 +145,21 @@ You can run the utility using below command:: [--version {v1,v2}] [--outdir OUTDIR] -You can run the utility using below commands: +You can run the utility using one of the commands below: - - By enabling generation of encryption keys:: + - By enabling generation of encryption keys:: - python nvs_partition_gen.py --input sample.csv --output sample_encrypted.bin --size 0x3000 --encrypt true --keygen true + python nvs_partition_gen.py --input sample.csv --output sample_encrypted.bin --size 0x3000 --encrypt true --keygen true - - By taking encryption keys as an input file. A sample encryption keys binary file is provided with the utility:: + - By taking encryption keys as an input file. A sample binary file containing encryption keys is provided with the utility:: - python nvs_partition_gen.py --input sample.csv --output sample_encrypted.bin --size 0x3000 --encrypt true --keyfile testdata/sample_encryption_keys.bin + python nvs_partition_gen.py --input sample.csv --output sample_encrypted.bin --size 0x3000 --encrypt true --keyfile testdata/sample_encryption_keys.bin - - By enabling generation of encryption keys and storing the keys in custom filename:: + - By enabling generation of encryption keys and storing the keys in a binary file with a custom filename:: - python nvs_partition_gen.py --input sample.csv --output sample_encrypted.bin --size 0x3000 --encrypt true --keygen true --keyfile encryption_keys_generated.bin + python nvs_partition_gen.py --input sample.csv --output sample_encrypted.bin --size 0x3000 --encrypt true --keygen true --keyfile encryption_keys_generated.bin -.. note:: If `--keygen` is given with `--keyfile` argument, generated keys will be stored in `--keyfile` file. If `--keygen` argument is absent, `--keyfile` is taken as input file having key for encryption. +.. note:: If `--keygen` is given with the `--keyfile` argument, generated keys will be stored in the `--keyfile` file. If `--keygen` argument is absent, `--keyfile` is taken as input file containing encryption keys. *To generate* **only** *encryption keys with this utility*:: @@ -181,7 +200,7 @@ A sample CSV file is provided with the utility:: Caveats ------- -- Utility doesn't check for duplicate keys and will write data pertaining to both keys. User needs to make sure keys are distinct. -- Once a new page is created, no data will be written in the space left in previous page. Fields in the CSV file need to be ordered in such a way so as to optimize memory. +- Utility does not check for duplicate keys and will write data pertaining to both keys. You need to make sure that the keys are distinct. +- Once a new page is created, no data will be written in the space left on the previous page. Fields in the CSV file need to be ordered in such a way as to optimize memory. - 64-bit datatype is not yet supported. diff --git a/components/spi_flash/README.rst b/components/spi_flash/README.rst index 807b592d28..04376c6140 100644 --- a/components/spi_flash/README.rst +++ b/components/spi_flash/README.rst @@ -1,80 +1,55 @@ -SPI Flash APIs -============== +SPI Flash API +============= Overview -------- -The spi_flash component contains APIs related to reading, writing, erasing, -memory mapping data in the external SPI flash. It also has higher-level -APIs which work with partitions defined in the :doc:`partition table `. +The spi_flash component contains API functions related to reading, writing, erasing, memory mapping for data in the external SPI flash. The spi_flash component also has higher-level API functions which work with partitions defined in the :doc:`partition table `. -Note that all the functionality is limited to the "main" SPI flash chip, -the same SPI flash chip from which program runs. For ``spi_flash_*`` functions, -this is a software limitation. The underlying ROM functions which work with SPI flash -do not have provisions for working with flash chips attached to SPI peripherals -other than SPI0. +Note that all the functionality is limited to the "main" SPI flash chip, the same SPI flash chip from which programs are runs. For ``spi_flash_*`` functions, this is a software limitation. The underlying ROM functions which work with SPI flash do not have provisions for working with flash chips attached to SPI peripherals other than SPI0. -SPI flash access APIs ---------------------- +SPI flash access API +-------------------- -This is the set of APIs for working with data in flash: +This is the set of API functions for working with data in flash: -- :cpp:func:`spi_flash_read` used to read data from flash to RAM -- :cpp:func:`spi_flash_write` used to write data from RAM to flash -- :cpp:func:`spi_flash_erase_sector` used to erase individual sectors of flash -- :cpp:func:`spi_flash_erase_range` used to erase range of addresses in flash +- :cpp:func:`spi_flash_read` reads data from flash to RAM +- :cpp:func:`spi_flash_write` writes data from RAM to flash +- :cpp:func:`spi_flash_erase_sector` erases individual sectors of flash +- :cpp:func:`spi_flash_erase_range` erases ranges of addresses in flash - :cpp:func:`spi_flash_get_chip_size` returns flash chip size, in bytes, as configured in menuconfig -Generally, try to avoid using the raw SPI flash functions in favour of -:ref:`partition-specific functions `. +Generally, try to avoid using the raw SPI flash functions in favor of :ref:`partition-specific functions `. SPI Flash Size -------------- -The SPI flash size is configured by writing a field in the software bootloader -image header, flashed at offset 0x1000. +The SPI flash size is configured by writing a field in the software bootloader image header, flashed at offset 0x1000. -By default, the SPI flash size is detected by esptool.py when this bootloader is -written to flash, and the header is updated with the correct -size. Alternatively, it is possible to generate a fixed flash size by setting -:envvar:`CONFIG_ESPTOOLPY_FLASHSIZE` in ``make menuconfig``. +By default, the SPI flash size is detected by esptool.py when this bootloader is written to flash, and the header is updated with the correct size. Alternatively, it is possible to generate a fixed flash size by setting :envvar:`CONFIG_ESPTOOLPY_FLASHSIZE` in ``make menuconfig``. -If it is necessary to override the configured flash size at runtime, is is -possible to set the ``chip_size`` member of ``g_rom_flashchip`` structure. This -size is used by ``spi_flash_*`` functions (in both software & ROM) for bounds -checking. +If it is necessary to override the configured flash size at runtime, it is possible to set the ``chip_size`` member of the ``g_rom_flashchip`` structure. This size is used by ``spi_flash_*`` functions (in both software & ROM) to check the bounds. Concurrency Constraints ----------------------- -Because the SPI flash is also used for firmware execution (via the instruction & -data caches), these caches must be disabled while reading/writing/erasing. This -means that both CPUs must be running code from IRAM and only reading data from -DRAM while flash write operations occur. +Because the SPI flash is also used for firmware execution via the instruction & data caches, these caches must be disabled while reading/writing/erasing. This means that both CPUs must be running code from IRAM and must only be reading data from DRAM while flash write operations occur. -If you use the APIs documented here, then this happens automatically and -transparently. However note that it will have some performance impact on other -tasks in the system. +If you use the API functions documented here, then these constraints are applied automatically and transparently. However, note that it will have some performance impact on other tasks in the system. -Refer to the :ref:`application memory layout ` documentation for -an explanation of the differences between IRAM, DRAM and flash cache. +For differences between IRAM, DRAM, and flash cache, please refer to the :ref:`application memory layout ` documentation. -To avoid reading flash cache accidentally, when one CPU commences a flash write -or erase operation the other CPU is put into a blocked state and all -non-IRAM-safe interrupts are disabled on both CPUs, until the flash operation -completes. +To avoid reading flash cache accidentally, when one CPU initiates a flash write or erase operation, the other CPU is put into a blocked state, and all non-IRAM-safe interrupts are disabled on both CPUs until the flash operation completes. + +If one CPU initiates a flash write or erase operation, the other CPU is put into a blocked state to avoid reading flash cache accidentally. All interrupts not safe for IRAM are disabled on both CPUs until the flash operation completes. .. _iram-safe-interrupt-handlers: IRAM-Safe Interrupt Handlers ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -If you have an interrupt handler that you want to execute even when a flash -operation is in progress (for example, for low latency operations), set the -``ESP_INTR_FLAG_IRAM`` flag when the :doc:`interrupt handler is registered -`. +If you have an interrupt handler that you want to execute while a flash operation is in progress (for example, for low latency operations), set the ``ESP_INTR_FLAG_IRAM`` flag when the :doc:`interrupt handler is registered `. -You must ensure all data and functions accessed by these interrupt handlers are -located in IRAM or DRAM. This includes any functions that the handler calls. +You must ensure that all data and functions accessed by these interrupt handlers, including the ones that handlers call, are located in IRAM or DRAM. Use the ``IRAM_ATTR`` attribute for functions:: @@ -93,80 +68,56 @@ Use the ``DRAM_ATTR`` and ``DRAM_STR`` attributes for constant data:: const static char *MSG = DRAM_STR("I am a string stored in RAM"); } -Note that knowing which data should be marked with ``DRAM_ATTR`` can be hard, -the compiler will sometimes recognise that a variable or expression is constant -(even if it is not marked ``const``) and optimise it into flash, unless it is -marked with ``DRAM_ATTR``. +Note that knowing which data should be marked with ``DRAM_ATTR`` can be hard, the compiler will sometimes recognize that a variable or expression is constant (even if it is not marked ``const``) and optimize it into flash, unless it is marked with ``DRAM_ATTR``. -If a function or symbol is not correctly put into IRAM/DRAM and the interrupt -handler reads from the flash cache during a flash operation, it will cause a -crash due to Illegal Instruction exception (for code which should be in IRAM) or -garbage data to be read (for constant data which should be in DRAM). +If a function or symbol is not correctly put into IRAM/DRAM, and the interrupt handler reads from the flash cache during a flash operation, it will cause a crash due to Illegal Instruction exception (for code which should be in IRAM) or garbage data to be read (for constant data which should be in DRAM). .. _flash-partition-apis: -Partition table APIs --------------------- +Partition table API +------------------- -ESP-IDF projects use a partition table to maintain information about various regions of -SPI flash memory (bootloader, various application binaries, data, filesystems). -More information about partition tables can be found :doc:`here `. +ESP-IDF projects use a partition table to maintain information about various regions of SPI flash memory (bootloader, various application binaries, data, filesystems). More information on partition tables can be found :doc:`here `. -This component provides APIs to enumerate partitions found in the partition table -and perform operations on them. These functions are declared in ``esp_partition.h``: +This component provides API functions to enumerate partitions found in the partition table and perform operations on them. These functions are declared in ``esp_partition.h``: -- :cpp:func:`esp_partition_find` used to search partition table for entries with - specific type, returns an opaque iterator -- :cpp:func:`esp_partition_get` returns a structure describing the partition, for the given iterator -- :cpp:func:`esp_partition_next` advances iterator to the next partition found -- :cpp:func:`esp_partition_iterator_release` releases iterator returned by ``esp_partition_find`` -- :cpp:func:`esp_partition_find_first` is a convenience function which returns structure - describing the first partition found by ``esp_partition_find`` -- :cpp:func:`esp_partition_read`, :cpp:func:`esp_partition_write`, :cpp:func:`esp_partition_erase_range` - are equivalent to :cpp:func:`spi_flash_read`, :cpp:func:`spi_flash_write`, - :cpp:func:`spi_flash_erase_range`, but operate within partition boundaries +- :cpp:func:`esp_partition_find` checks a partition table for entries with specific type, returns an opaque iterator. +- :cpp:func:`esp_partition_get` returns a structure describing the partition for a given iterator. +- :cpp:func:`esp_partition_next` shifts the iterator to the next found partition. +- :cpp:func:`esp_partition_iterator_release` releases iterator returned by ``esp_partition_find``. +- :cpp:func:`esp_partition_find_first` - a convenience function which returns the structure describing the first partition found by ``esp_partition_find``. +- :cpp:func:`esp_partition_read`, :cpp:func:`esp_partition_write`, :cpp:func:`esp_partition_erase_range` are equivalent to :cpp:func:`spi_flash_read`, :cpp:func:`spi_flash_write`, :cpp:func:`spi_flash_erase_range`, but operate within partition boundaries. .. note:: - Most application code should use these ``esp_partition_*`` APIs instead of lower level - ``spi_flash_*`` APIs. Partition APIs do bounds checking and calculate correct - offsets in flash based on data stored in partition table. + Application code should mostly use these ``esp_partition_*`` API functions instead of lower level ``spi_flash_*`` API functions. Partition table API functions do bounds checking and calculate correct offsets in flash, based on data stored in a partition table. SPI Flash Encryption -------------------- -It is possible to encrypt SPI flash contents, and have it transparenlty decrypted by hardware. +It is possible to encrypt the contents of SPI flash and have it transparently decrypted by hardware. Refer to the :doc:`Flash Encryption documentation ` for more details. -Memory mapping APIs -------------------- +Memory mapping API +------------------ -ESP32 features memory hardware which allows regions of flash memory to be mapped -into instruction and data address spaces. This mapping works only for read operations, -it is not possible to modify contents of flash memory by writing to mapped memory -region. Mapping happens in 64KB pages. Memory mapping hardware can map up to -4 megabytes of flash into data address space, and up to 16 megabytes of flash into -instruction address space. See the technical reference manual for more details -about memory mapping hardware. +ESP32 features memory hardware which allows regions of flash memory to be mapped into instruction and data address spaces. This mapping works only for read operations. It is not possible to modify contents of flash memory by writing to a mapped memory region. -Note that some number of 64KB pages is used to map the application -itself into memory, so the actual number of available 64KB pages may be less. +Mapping happens in 64KB pages. Memory mapping hardware can map up to four megabytes of flash into data address space and up to 16 megabytes of flash into instruction address space. See the technical reference manual for more details about memory mapping hardware. -Reading data from flash using a memory mapped region is the only way to decrypt -contents of flash when :doc:`flash encryption ` is enabled. -Decryption is performed at hardware level. +Note that some 64KB pages are used to map the application itself into memory, so the actual number of available 64KB pages may be less. -Memory mapping APIs are declared in ``esp_spi_flash.h`` and ``esp_partition.h``: +Reading data from flash using a memory mapped region is the only way to decrypt contents of flash when :doc:`flash encryption ` is enabled. Decryption is performed at the hardware level. -- :cpp:func:`spi_flash_mmap` maps a region of physical flash addresses into instruction space or data space of the CPU -- :cpp:func:`spi_flash_munmap` unmaps previously mapped region -- :cpp:func:`esp_partition_mmap` maps part of a partition into the instruction space or data space of the CPU +Memory mapping API are declared in ``esp_spi_flash.h`` and ``esp_partition.h``: + +- :cpp:func:`spi_flash_mmap` maps a region of physical flash addresses into instruction space or data space of the CPU. +- :cpp:func:`spi_flash_munmap` unmaps previously mapped region. +- :cpp:func:`esp_partition_mmap` maps part of a partition into the instruction space or data space of the CPU. Differences between :cpp:func:`spi_flash_mmap` and :cpp:func:`esp_partition_mmap` are as follows: -- :cpp:func:`spi_flash_mmap` must be given a 64KB aligned physical address -- :cpp:func:`esp_partition_mmap` may be given any arbitrary offset within the partition, - it will adjust returned pointer to mapped memory as necessary +- :cpp:func:`spi_flash_mmap` must be given a 64KB aligned physical address. +- :cpp:func:`esp_partition_mmap` may be given any arbitrary offset within the partition, it will adjust the returned pointer to mapped memory as necessary -Note that because memory mapping happens in 64KB blocks, it may be possible to -read data outside of the partition provided to ``esp_partition_mmap``. +Note that since memory mapping happens in 64KB blocks, it may be possible to read data outside of the partition provided to ``esp_partition_mmap``. diff --git a/components/vfs/README.rst b/components/vfs/README.rst index 95ccefd840..20bc9770e7 100644 --- a/components/vfs/README.rst +++ b/components/vfs/README.rst @@ -4,18 +4,17 @@ Virtual filesystem component Overview -------- -Virtual filesystem (VFS) component provides a unified interface for drivers which can perform operations on file-like objects. This can be a real filesystems (FAT, SPIFFS, etc.), or device drivers which exposes file-like interface. +Virtual filesystem (VFS) component provides a unified interface for drivers which can perform operations on file-like objects. These can be real filesystems (FAT, SPIFFS, etc.) or device drivers which provide a file-like interface. -This component allows C library functions, such as fopen and fprintf, to work with FS drivers. At high level, each FS driver is associated with some path prefix. When one of C library functions needs to open a file, VFS component searches for the FS driver associated with the file's path, and forwards the call to that driver. VFS also forwards read, write, and other calls for the given file to the same FS driver. +This component allows C library functions, such as fopen and fprintf, to work with FS drivers. At a high level, each FS driver is associated with some path prefix. When one of C library functions needs to open a file, the VFS component searches for the FS driver associated with the file path and forwards the call to that driver. VFS also forwards read, write, and other calls for the given file to the same FS driver. + +For example, one can register a FAT filesystem driver with the ``/fat`` prefix and call ``fopen("/fat/file.txt", "w")``. The VFS component will then call the function ``open`` of the FAT driver and pass the argument ``/file.txt`` to it together with appropriate mode flags. All subsequent calls to C library functions for the returned ``FILE*`` stream will also be forwarded to the FAT driver. -For example, one can register a FAT filesystem driver with ``/fat`` prefix, and call ``fopen("/fat/file.txt", "w")``. VFS component will then call ``open`` function of FAT driver and pass ``/file.txt`` argument to it (and appropriate mode flags). All subsequent calls to C library functions for the returned ``FILE*`` stream will also be forwarded to the FAT driver. FS registration --------------- - - -To register an FS driver, application needs to define in instance of :cpp:type:`esp_vfs_t` structure and populate it with function pointers to FS APIs: +To register an FS driver, an application needs to define an instance of the :cpp:type:`esp_vfs_t` structure and populate it with function pointers to FS APIs: .. highlight:: c @@ -32,9 +31,9 @@ To register an FS driver, application needs to define in instance of :cpp:type:` ESP_ERROR_CHECK(esp_vfs_register("/data", &myfs, NULL)); -Depending on the way FS driver declares its APIs, either ``read``, ``write``, etc., or ``read_p``, ``write_p``, etc. should be used. +Depending on the way how the FS driver declares its API functions, either ``read``, ``write``, etc., or ``read_p``, ``write_p``, etc., should be used. -Case 1: API functions are declared without an extra context pointer (FS driver is a singleton):: +Case 1: API functions are declared without an extra context pointer (the FS driver is a singleton):: ssize_t myfs_write(int fd, const void * data, size_t size); @@ -46,7 +45,7 @@ Case 1: API functions are declared without an extra context pointer (FS driver i // When registering FS, context pointer (third argument) is NULL: ESP_ERROR_CHECK(esp_vfs_register("/data", &myfs, NULL)); -Case 2: API functions are declared with an extra context pointer (FS driver supports multiple instances):: +Case 2: API functions are declared with an extra context pointer (the FS driver supports multiple instances):: ssize_t myfs_write(myfs_t* fs, int fd, const void * data, size_t size); @@ -68,8 +67,8 @@ Synchronous input/output multiplexing ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If you want to use synchronous input/output multiplexing by :cpp:func:`select` -then you need to register the VFS with :cpp:func:`start_select` and -:cpp:func:`end_select` functions similarly to the following example: +then you need to register VFS with the functions :cpp:func:`start_select` and +:cpp:func:`end_select` similar to the following example: .. highlight:: c @@ -85,22 +84,27 @@ detection of read/write/error conditions on file descriptors belonging to the given VFS. :cpp:func:`end_select` is called to stop/deinitialize/free the environment which was setup by :cpp:func:`start_select`. Please refer to the reference implementation for the UART peripheral in -:component_file:`vfs/vfs_uart.c` and most particularly to functions -:cpp:func:`esp_vfs_dev_uart_register`, :cpp:func:`uart_start_select` and +:component_file:`vfs/vfs_uart.c` and most particularly to the functions +:cpp:func:`esp_vfs_dev_uart_register`, :cpp:func:`uart_start_select`, and :cpp:func:`uart_end_select`. -Examples demonstrating the use of :cpp:func:`select` with VFS file descriptors -are the :example:`peripherals/uart_select` and the :example:`system/select` -examples. +Please check the following examples that demonstrate the use of :cpp:func:`select` with VFS file descriptors: +- :example:`peripherals/uart_select` +- :example:`system/select` +<<<<<<< HEAD If :cpp:func:`select` is used for socket file descriptors only then one can enable the :envvar:`CONFIG_LWIP_USE_ONLY_LWIP_SELECT` option which can reduce the code +======= +If you use :cpp:func:`select` for socket file descriptors, you can enable the :envvar:`CONFIG_LWIP_USE_ONLY_LWIP_SELECT` option to reduce the code +>>>>>>> afc2fdf27... Review all the files in the esp-idf's api_ref/storage directory size and improve performance. + Paths ----- -Each registered FS has a path prefix associated with it. This prefix may be considered a "mount point" of this partition. +Each registered FS has a path prefix associated with it. This prefix can be considered as a "mount point" of this partition. In case when mount points are nested, the mount point with the longest matching path prefix is used when opening the file. For instance, suppose that the following filesystems are registered in VFS: @@ -111,45 +115,49 @@ Then: - FS 1 will be used when opening a file called ``/data/log.txt`` - FS 2 will be used when opening a file called ``/data/static/index.html`` -- Even if ``/index.html"`` doesn't exist in FS 2, FS 1 will *not* be searched for ``/static/index.html``. +- Even if ``/index.html"`` does not exist in FS 2, FS 1 will *not* be searched for ``/static/index.html``. -As a general rule, mount point names must start with the path separator (``/``) and must contain at least one character after path separator. However an empty mount point name is also supported, and may be used in cases when application needs to provide "fallback" filesystem, or override VFS functionality altogether. Such filesystem will be used if no prefix matches the path given. +As a general rule, mount point names must start with the path separator (``/``) and must contain at least one character after path separator. However, an empty mount point name is also supported and might be used in cases when an application needs to provide a "fallback" filesystem or to override VFS functionality altogether. Such filesystem will be used if no prefix matches the path given. -VFS does not handle dots (``.``) in path names in any special way. VFS does not treat ``..`` as a reference to the parent directory. I.e. in the above example, using a path ``/data/static/../log.txt`` will not result in a call to FS 1 to open ``/log.txt``. Specific FS drivers (such as FATFS) may handle dots in file names differently. +VFS does not handle dots (``.``) in path names in any special way. VFS does not treat ``..`` as a reference to the parent directory. In the above example, using a path ``/data/static/../log.txt`` will not result in a call to FS 1 to open ``/log.txt``. Specific FS drivers (such as FATFS) might handle dots in file names differently. -When opening files, FS driver will only be given relative path to files. For example: +When opening files, the FS driver receives only relative paths to files. For example: -- ``myfs`` driver is registered with ``/data`` as path prefix -- and application calls ``fopen("/data/config.json", ...)`` -- then VFS component will call ``myfs_open("/config.json", ...)``. -- ``myfs`` driver will open ``/config.json`` file +1. The ``myfs`` driver is registered with ``/data`` as a path prefix. +2. The application calls ``fopen("/data/config.json", ...)``. +3. The VFS component calls ``myfs_open("/config.json", ...)``. +4. The ``myfs`` driver opens the ``/config.json`` file. + +VFS does not impose any limit on total file path length, but it does limit the FS path prefix to ``ESP_VFS_PATH_MAX`` characters. Individual FS drivers may have their own filename length limitations. -VFS doesn't impose a limit on total file path length, but it does limit FS path prefix to ``ESP_VFS_PATH_MAX`` characters. Individual FS drivers may have their own filename length limitations. File descriptors ---------------- -File descriptors are small positive integers from ``0`` to ``FD_SETSIZE - 1`` where ``FD_SETSIZE`` is defined in newlib's ``sys/types.h``. The largest file descriptors (configured by ``CONFIG_LWIP_MAX_SOCKETS``) are reserved for sockets. The VFS component contains a lookup-table called ``s_fd_table`` for mapping global file descriptors to VFS driver indexes registered in the ``s_vfs`` array. +File descriptors are small positive integers from ``0`` to ``FD_SETSIZE - 1``, where ``FD_SETSIZE`` is defined in newlib's ``sys/types.h``. The largest file descriptors (configured by ``CONFIG_LWIP_MAX_SOCKETS``) are reserved for sockets. The VFS component contains a lookup-table called ``s_fd_table`` for mapping global file descriptors to VFS driver indexes registered in the ``s_vfs`` array. + Standard IO streams (stdin, stdout, stderr) ------------------------------------------- -If "UART for console output" menuconfig option is not set to "None", then ``stdin``, ``stdout``, and ``stderr`` are configured to read from, and write to, a UART. It is possible to use UART0 or UART1 for standard IO. By default, UART0 is used, with 115200 baud rate, TX pin is GPIO1 and RX pin is GPIO3. These parameters can be changed in menuconfig. +If the menuconfig option ``UART for console output`` is not set to ``None``, then ``stdin``, ``stdout``, and ``stderr`` are configured to read from, and write to, a UART. It is possible to use UART0 or UART1 for standard IO. By default, UART0 is used with 115200 baud rate; TX pin is GPIO1; RX pin is GPIO3. These parameters can be changed in menuconfig. Writing to ``stdout`` or ``stderr`` will send characters to the UART transmit FIFO. Reading from ``stdin`` will retrieve characters from the UART receive FIFO. -By default, VFS uses simple functions for reading from and writing to UART. Writes busy-wait until all data is put into UART FIFO, and reads are non-blocking, returning only the data present in the FIFO. Because of this non-blocking read behavior, higher level C library calls, such as ``fscanf("%d\n", &var);`` may not have desired results. +By default, VFS uses simple functions for reading from and writing to UART. Writes busy-wait until all data is put into UART FIFO, and reads are non-blocking, returning only the data present in the FIFO. Due to this non-blocking read behavior, higher level C library calls, such as ``fscanf("%d\n", &var);``, might not have desired results. -Applications which use UART driver may instruct VFS to use the driver's interrupt driven, blocking read and write functions instead. This can be done using a call to ``esp_vfs_dev_uart_use_driver`` function. It is also possible to revert to the basic non-blocking functions using a call to ``esp_vfs_dev_uart_use_nonblocking``. +Applications which use the UART driver can instruct VFS to use the driver's interrupt driven, blocking read and write functions instead. This can be done using a call to the ``esp_vfs_dev_uart_use_driver`` function. It is also possible to revert to the basic non-blocking functions using a call to ``esp_vfs_dev_uart_use_nonblocking``. -VFS also provides optional newline conversion feature for input and output. Internally, most applications send and receive lines terminated by LF (''\n'') character. Different terminal programs may require different line termination, such as CR or CRLF. Applications can configure this separately for input and output either via menuconfig, or by calls to ``esp_vfs_dev_uart_set_rx_line_endings`` and ``esp_vfs_dev_uart_set_tx_line_endings`` functions. +VFS also provides an optional newline conversion feature for input and output. Internally, most applications send and receive lines terminated by the LF (''\n'') character. Different terminal programs may require different line termination, such as CR or CRLF. Applications can configure this separately for input and output either via menuconfig, or by calls to the functions ``esp_vfs_dev_uart_set_rx_line_endings`` and ``esp_vfs_dev_uart_set_tx_line_endings``. Standard streams and FreeRTOS tasks ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -``FILE`` objects for ``stdin``, ``stdout``, and ``stderr`` are shared between all FreeRTOS tasks, but the pointers to these objects are are stored in per-task ``struct _reent``. The following code: +``FILE`` objects for ``stdin``, ``stdout``, and ``stderr`` are shared between all FreeRTOS tasks, but the pointers to these objects are stored in per-task ``struct _reent``. + +The following code is transferred to ``fprintf(__getreent()->_stderr, "42\n");`` by the preprocessor: .. highlight:: c @@ -157,14 +165,11 @@ Standard streams and FreeRTOS tasks fprintf(stderr, "42\n"); -actually is translated to to this (by the preprocessor):: - fprintf(__getreent()->_stderr, "42\n"); - -where the ``__getreent()`` function returns a per-task pointer to ``struct _reent`` (:component_file:`newlib/include/sys/reent.h#L370-L417`). This structure is allocated on the TCB of each task. When a task is initialized, ``_stdin``, ``_stdout`` and ``_stderr`` members of ``struct _reent`` are set to the values of ``_stdin``, ``_stdout`` and ``_stderr`` of ``_GLOBAL_REENT`` (i.e. the structure which is used before FreeRTOS is started). +The ``__getreent()`` function returns a per-task pointer to ``struct _reent`` (:component_file:`newlib/include/sys/reent.h#L370-L417`). This structure is allocated on the TCB of each task. When a task is initialized, ``_stdin``, ``_stdout``, and ``_stderr`` members of ``struct _reent`` are set to the values of ``_stdin``, ``_stdout``, and ``_stderr`` of ``_GLOBAL_REENT`` (i.e., the structure which is used before FreeRTOS is started). Such a design has the following consequences: -- It is possible to set ``stdin``, ``stdout``, and ``stderr`` for any given task without affecting other tasks, e.g. by doing ``stdin = fopen("/dev/uart/1", "r")``. -- Closing default ``stdin``, ``stdout``, or ``stderr`` using ``fclose`` will close the ``FILE`` stream object — this will affect all other tasks. +- It is possible to set ``stdin``, ``stdout``, and ``stderr`` for any given task without affecting other tasks, e.g., by doing ``stdin = fopen("/dev/uart/1", "r")``. +- Closing default ``stdin``, ``stdout``, or ``stderr`` using ``fclose`` will close the ``FILE`` stream object, which will affect all other tasks. - To change the default ``stdin``, ``stdout``, ``stderr`` streams for new tasks, modify ``_GLOBAL_REENT->_stdin`` (``_stdout``, ``_stderr``) before creating the task. diff --git a/components/wear_levelling/README.rst b/components/wear_levelling/README.rst index 88d54ee749..44def742e5 100644 --- a/components/wear_levelling/README.rst +++ b/components/wear_levelling/README.rst @@ -1,55 +1,47 @@ -Wear Levelling APIs -=================== +Wear Levelling API +================== Overview -------- -Most of the flash devices and specially SPI flash devices that are used in ESP32 -have sector based organization and have limited amount of erase/modification cycles -per memory sector. To avoid situation when one sector reach the limit of erases when -other sectors was used not often, we have made a component that avoid this situation. -The wear levelling component share the amount of erases between all sectors in the -memory without user interaction. -The wear_levelling component contains APIs related to reading, writing, erasing, -memory mapping data in the external SPI flash through the partition component. It -also has higher-level APIs which work with FAT filesystem defined in -the :doc:`FAT filesystem `. +Most of flash memory and especially SPI flash that is used in ESP32 has a sector-based organization and also has a limited number of erase/modification cycles per memory sector. The wear levelling component helps to distribute wear and tear among sectors more evenly without requiring any attention from the user. -The wear levelling component, together with FAT FS component, works with FAT FS sector size 4096 -bytes which is standard size of the flash devices. In this mode the component has best performance, -but needs additional memoty in the RAM. To save internal memory the component has two additional modes -to work with sector size 512 bytes: Performance and Safety modes. In Performance mode by erase sector -operation data will be stored to the RAM, sector will be erased and then data will be stored -back to the flash. If by this operation power off situation will occur, the complete 4096 bytes -will be lost. To prevent this the Safety mode was implemented. In safety mode the data will be first -stored to the flash and after sector will be erased, will be stored back. If power off situation will -occur, after power on, the data will be recovered. -By default defined the sector size 512 bytes and Performance mode. To change these values please use -the configuration menu. +The wear levelling component provides API functions related to reading, writing, erasing, and memory mapping of data in external SPI flash through the partition component. The component also has higher-level API functions which work with the FAT filesystem defined in :doc:`FAT filesystem `. + +The wear levelling component, together with the FAT FS component, uses FAT FS sectors of 4096 bytes, which is a standard size for flash memory. With this size, the component shows the best performance but needs additional memory in RAM. + +To save internal memory, the component has two additional modes which both use sectors of 512 bytes: + +- **Performance mode.** Erase sector operation data is stored in RAM, the sector is erased, and then data is copied back to flash memory. However, if a device is powered off for any reason, all 4096 bytes of data is lost. +- **Safety mode.** The data is first saved to flash memory, and after the sector is erased, the data is saved back. If a device is powered off, the data can be recovered as soon as the device boots up. + +The default settings are as follows: +- Sector size is 512 bytes +- Performance mode + +You can change the settings through the configuration menu. -The wear levelling component does not cache data in RAM. Write and erase functions -modify flash directly, and flash contents is consistent when the function returns. +The wear levelling component does not cache data in RAM. The write and erase functions modify flash directly, and flash contents are consistent when the function returns. -Wear Levelling access APIs --------------------------- +Wear Levelling access API functions +----------------------------------- -This is the set of APIs for working with data in flash: +This is the set of API functions for working with data in flash: -- ``wl_mount`` mount wear levelling module for defined partition -- ``wl_unmount`` used to unmount levelling module -- ``wl_erase_range`` used to erase range of addresses in flash -- ``wl_write`` used to write data to the partition -- ``wl_read`` used to read data from the partition -- ``wl_size`` return size of avalible memory in bytes -- ``wl_sector_size`` returns size of one sector +- ``wl_mount`` - initializes the wear levelling module and mounts the specified partition +- ``wl_unmount`` - unmounts the partition and deinitializes the wear levelling module +- ``wl_erase_range`` - erases a range of addresses in flash +- ``wl_write`` - writes data to a partition +- ``wl_read`` - reads data from a partition +- ``wl_size`` - returns the size of available memory in bytes +- ``wl_sector_size`` - returns the size of one sector + +As a rule, try to avoid using raw wear levelling functions and use filesystem-specific functions instead. -Generally, try to avoid using the raw wear levelling functions in favor of -filesystem-specific functions. Memory Size ----------- -The memory size calculated in the wear Levelling module based on parameters of -partition. The module use few sectors of flash for internal data. +The memory size is calculated in the wear levelling module based on partition parameters. The module uses some sectors of flash for internal data. diff --git a/docs/en/api-reference/storage/fatfs.rst b/docs/en/api-reference/storage/fatfs.rst index 6ad0163e12..8abb59da4a 100644 --- a/docs/en/api-reference/storage/fatfs.rst +++ b/docs/en/api-reference/storage/fatfs.rst @@ -1,36 +1,43 @@ FAT Filesystem Support ====================== -ESP-IDF uses `FatFs `_ library to work with FAT filesystems. FatFs library resides in ``fatfs`` component. Although it can be used directly, many of its features can be accessed via VFS using C standard library and POSIX APIs. +ESP-IDF uses the `FatFs `_ library to work with FAT filesystems. FatFs resides in the ``fatfs`` component. Although the library can be used directly, many of its features can be accessed via VFS, using the C standard library and POSIX API functions. + +Additionally, FatFs has been modified to support the runtime pluggable disk I/O layer. This allows mapping of FatFs drives to physical disks at runtime. -Additionally, FatFs has been modified to support run-time pluggable disk IO layer. This allows mapping of FatFs drives to physical disks at run-time. Using FatFs with VFS -------------------- -:component_file:`fatfs/src/esp_vfs_fat.h` header file defines functions to connect FatFs with VFS. :cpp:func:`esp_vfs_fat_register` function allocates a ``FATFS`` structure, and registers a given path prefix in VFS. Subsequent operations on files starting with this prefix are forwarded to FatFs APIs. :cpp:func:`esp_vfs_fat_unregister_path` function deletes the registration with VFS, and frees the ``FATFS`` structure. +The header file :component_file:`fatfs/src/esp_vfs_fat.h` defines the functions for connecting FatFs and VFS. -Most applications will use the following flow when working with ``esp_vfs_fat_`` functions: +The function :cpp:func:`esp_vfs_fat_register` allocates a ``FATFS`` structure and registers a given path prefix in VFS. Subsequent operations on files starting with this prefix are forwarded to FatFs APIs. +The function :cpp:func:`esp_vfs_fat_unregister_path` deletes the registration with VFS, and frees the ``FATFS`` structure. -1. Call :cpp:func:`esp_vfs_fat_register`, specifying path prefix where the filesystem has to be mounted (e.g. ``"/sdcard"``, ``"/spiflash"``), FatFs drive number, and a variable which will receive a pointer to ``FATFS`` structure. +Most applications use the following workflow when working with ``esp_vfs_fat_`` functions: -2. Call :cpp:func:`ff_diskio_register` function to register disk IO driver for the drive number used in step 1. +1. Call :cpp:func:`esp_vfs_fat_register` to specify: + - Path prefix where to mount the filesystem (e.g. ``"/sdcard"``, ``"/spiflash"``) + - FatFs drive number + - A variable which will receive the pointer to the ``FATFS`` structure -3. Call FatFs ``f_mount`` function (and optionally ``f_fdisk``, ``f_mkfs``) to mount the filesystem using the same drive number which was passed to :cpp:func:`esp_vfs_fat_register`. See `FatFs documentation for more details `. +2. Call :cpp:func:`ff_diskio_register` to register the disk I/O driver for the drive number used in Step 1. -4. Call POSIX and C standard library functions to open, read, write, erase, copy files, etc. Use paths starting with the prefix passed to :cpp:func:`esp_vfs_register` (such as ``"/sdcard/hello.txt"``). +3. Call the FatFs function ``f_mount``, and optionally ``f_fdisk``, ``f_mkfs``, to mount the filesystem using the same drive number which was passed to :cpp:func:`esp_vfs_fat_register`. For more information, see `FatFs documentation `. -5. Optionally, call FatFs library functions directly. Use paths without a VFS prefix in this case (``"/hello.txt"``). +4. Call the C standard library and POSIX API functions to perform such actions on files as open, read, write, erase, copy, etc. Use paths starting with the path prefix passed to :cpp:func:`esp_vfs_register` (for example, ``"/sdcard/hello.txt"``). + +5. Optionally, call the FatFs library functions directly. In this case, use paths without a VFS prefix (for example, ``"/hello.txt"``). 6. Close all open files. -7. Call FatFs ``f_mount`` function for the same drive number, with NULL ``FATFS*`` argument, to unmount the filesystem. +7. Call the FatFs function ``f_mount`` for the same drive number, with NULL ``FATFS*`` argument, to unmount the filesystem. -8. Call FatFs :cpp:func:`ff_diskio_register` with NULL ``ff_diskio_impl_t*`` argument and the same drive number. +8. Call the FatFs function :cpp:func:`ff_diskio_register` with NULL ``ff_diskio_impl_t*`` argument and the same drive number to unregister the disk I/O driver. -9. Call :cpp:func:`esp_vfs_fat_unregister_path` with the path where the file system is mounted to remove FatFs from VFS, and free the ``FATFS`` structure allocated on step 1. +9. Call :cpp:func:`esp_vfs_fat_unregister_path` with the path where the file system is mounted to remove FatFs from VFS, and free the ``FATFS`` structure allocated in Step 1. -Convenience functions, ``esp_vfs_fat_sdmmc_mount`` and ``esp_vfs_fat_sdmmc_unmount``, which wrap these steps and also handle SD card initialization, are described in the next section. +The convenience functions ``esp_vfs_fat_sdmmc_mount`` and ``esp_vfs_fat_sdmmc_unmount`` wrap the steps described above and also handle SD card initialization. These two functions are described in the next section. .. doxygenfunction:: esp_vfs_fat_register .. doxygenfunction:: esp_vfs_fat_unregister_path @@ -39,7 +46,9 @@ Convenience functions, ``esp_vfs_fat_sdmmc_mount`` and ``esp_vfs_fat_sdmmc_unmou Using FatFs with VFS and SD cards --------------------------------- -:component_file:`fatfs/src/esp_vfs_fat.h` header file also provides a convenience function to perform steps 1–3 and 7–9, and also handle SD card initialization: :cpp:func:`esp_vfs_fat_sdmmc_mount`. This function does only limited error handling. Developers are encouraged to look at its source code and incorporate more advanced versions into production applications. :cpp:func:`esp_vfs_fat_sdmmc_unmount` function unmounts the filesystem and releases resources acquired by :cpp:func:`esp_vfs_fat_sdmmc_mount`. +The header file :component_file:`fatfs/src/esp_vfs_fat.h` defines convenience functions :cpp:func:`esp_vfs_fat_sdmmc_mount` and :cpp:func:`esp_vfs_fat_sdmmc_unmount`. These function perform Steps 1–3 and 7–9 respectively and handle SD card initialization, but provide only limited error handling. Developers are encouraged to check its source code and incorporate more advanced features into production applications. + +The convenience function :cpp:func:`esp_vfs_fat_sdmmc_unmount` unmounts the filesystem and releases the resources acquired by :cpp:func:`esp_vfs_fat_sdmmc_mount`. .. doxygenfunction:: esp_vfs_fat_sdmmc_mount .. doxygenstruct:: esp_vfs_fat_mount_config_t @@ -50,17 +59,18 @@ Using FatFs with VFS and SD cards Using FatFs with VFS in read-only mode -------------------------------------- -Convenience functions, :cpp:func:`esp_vfs_fat_rawflash_mount` and :cpp:func:`esp_vfs_fat_rawflash_unmount`, are provided by :component_file:`fatfs/src/esp_vfs_fat.h` header file in order to perform steps 1-3 and 7-9 for read-only FAT partitions. These are particularly helpful for data partitions written only once during factory provisioning and need not be changed by production application throughout the lifetime. +The header file :component_file:`fatfs/src/esp_vfs_fat.h` also defines the convenience functions :cpp:func:`esp_vfs_fat_rawflash_mount` and :cpp:func:`esp_vfs_fat_rawflash_unmount`. These functions perform Steps 1-3 and 7-9 respectively for read-only FAT partitions. These are particularly helpful for data partitions written only once during factory provisioning which will not be changed by production application throughout the lifetime of the hardware. .. doxygenfunction:: esp_vfs_fat_rawflash_mount .. doxygenfunction:: esp_vfs_fat_rawflash_unmount + FatFS disk IO layer ------------------- -FatFs has been extended with an API to register disk IO driver at runtime. +FatFs has been extended with API functions that register the disk I/O driver at runtime. -Implementation of disk IO functions for SD/MMC cards is provided. It can be registered for the given FatFs drive number using :cpp:func:`ff_diskio_register_sdmmc` function. +They provide implementation of disk I/O functions for SD/MMC cards and can be registered for the given FatFs drive number using the function :cpp:func:`ff_diskio_register_sdmmc`. .. doxygenfunction:: ff_diskio_register .. doxygenstruct:: ff_diskio_impl_t diff --git a/docs/en/api-reference/storage/index.rst b/docs/en/api-reference/storage/index.rst index b4a6903560..d80e30b56e 100644 --- a/docs/en/api-reference/storage/index.rst +++ b/docs/en/api-reference/storage/index.rst @@ -15,4 +15,4 @@ Storage API Mass Manufacturing Utility -Example code for this API section is provided in :example:`storage` directory of ESP-IDF examples. +Code examples for this API section are provided in the :example:`storage` directory of ESP-IDF examples. diff --git a/docs/en/api-reference/storage/nvs_flash.rst b/docs/en/api-reference/storage/nvs_flash.rst index 4daa17ea21..b3e0e38c92 100644 --- a/docs/en/api-reference/storage/nvs_flash.rst +++ b/docs/en/api-reference/storage/nvs_flash.rst @@ -3,29 +3,29 @@ NVS Partition Generator Utility ------------------------------- -This utility helps in generating NVS-esque partition binary file which can be flashed separately on a dedicated partition via a flashing utility. Key-value pairs to be flashed onto the partition can be provided via a CSV file. Refer to :doc:`NVS Partition Generator Utility ` for more details. +This utility helps generate NVS partition binary files which can be flashed separately on a dedicated partition via a flashing utility. Key-value pairs to be flashed onto the partition can be provided via a CSV file. For more details, please refer to :doc:`NVS Partition Generator Utility `. Application Example ------------------- -Two examples are provided in :example:`storage` directory of ESP-IDF examples: +You can find two code examples in the :example:`storage` directory of ESP-IDF examples: :example:`storage/nvs_rw_value` - Demonstrates how to read and write a single integer value using NVS. + Demonstrates how to read a single integer value from, and write it to NVS. - The value holds the number of ESP32 module restarts. Since it is written to NVS, the value is preserved between restarts. + The value checked in this example holds the number of the ESP32 module restarts. The value's function as a counter is only possible due to its storing in NVS. - Example also shows how to check if read / write operation was successful, or certain value is not initialized in NVS. Diagnostic is provided in plain text to help track program flow and capture any issues on the way. + The example also shows how to check if a read / write operation was successful, or if a certain value has not been initialized in NVS. The diagnostic procedure is provided in plain text to help you track the program flow and capture any issues on the way. :example:`storage/nvs_rw_blob` - Demonstrates how to read and write a single integer value and a blob (binary large object) using NVS to preserve them between ESP32 module restarts. + Demonstrates how to read a single integer value and a blob (binary large object), and write them to NVS to preserve this value between ESP32 module restarts. - * value - tracks number of ESP32 module soft and hard restarts. - * blob - contains a table with module run times. The table is read from NVS to dynamically allocated RAM. New run time is added to the table on each manually triggered soft restart and written back to NVS. Triggering is done by pulling down GPIO0. + * value - tracks the number of the ESP32 module soft and hard restarts. + * blob - contains a table with module run times. The table is read from NVS to dynamically allocated RAM. A new run time is added to the table on each manually triggered soft restart, and then the added run time is written to NVS. Triggering is done by pulling down GPIO0. - Example also shows how to implement diagnostics if read / write operation was successful. + The example also shows how to implement the diagnostic procedure to check if the read / write operation was successful. API Reference diff --git a/docs/en/api-reference/storage/sdmmc.rst b/docs/en/api-reference/storage/sdmmc.rst index 2aae6a09c1..2b7490ddb3 100644 --- a/docs/en/api-reference/storage/sdmmc.rst +++ b/docs/en/api-reference/storage/sdmmc.rst @@ -4,77 +4,93 @@ SD/SDIO/MMC Driver Overview -------- -SD/SDIO/MMC driver currently supports SD memory, SDIO cards, and eMMC chips. This protocol level driver builds on top of SDMMC and SD SPI host drivers. +The SD/SDIO/MMC driver currently supports SD memory, SDIO cards, and eMMC chips. This is a protocol level driver built on top of SDMMC and SD SPI host drivers. -SDMMC and SD SPI host drivers (``driver/sdmmc_host.h``) provide APIs to send commands to the slave device(s), send and receive data, and handle error conditions on the bus. - -- See :doc:`SDMMC Host API <../peripherals/sdmmc_host>` for functions used to initialize and configure SDMMC host. -- See :doc:`SD SPI Host API <../peripherals/sdspi_host>` for functions used to initialize and configure SD SPI host. +SDMMC and SD SPI host drivers (:component:`driver/include/driver/sdmmc_host.h`) provide API functions for: -SDMMC protocol layer (``sdmmc_cmd.h``), described in this document, handles specifics of SD protocol such as card initialization and data transfer commands. +- Sending commands to slave devices +- Sending and receiving data +- Handling error conditions within the bus + +For functions used to initialize and configure: + +- SDMMC host, see :doc:`SDMMC Host API <../peripherals/sdmmc_host>` +- SD SPI host, see :doc:`SD SPI Host API <../peripherals/sdspi_host>` + + +The SDMMC protocol layer described in this document handles the specifics of the SD protocol, such as the card initialization and data transfer commands. + +The protocol layer works with the host via the :cpp:class:`sdmmc_host_t` structure. This structure contains pointers to various functions of the host. -Protocol layer works with the host via :cpp:class:`sdmmc_host_t` structure. This structure contains pointers to various functions of the host. Application Example ------------------- -An example which combines SDMMC driver with FATFS library is provided in ``examples/storage/sd_card`` directory. This example initializes the card, writes and reads data from it using POSIX and C library APIs. See README.md file in the example directory for more information. +An example which combines the SDMMC driver with the FATFS library is provided in the :example:`storage/sd_card` directory of ESP-IDF examples. This example initializes the card, then writes and reads data from it using POSIX and C library APIs. See README.md file in the example directory for more information. -Protocol layer APIs -------------------- -Protocol layer is given :cpp:class:`sdmmc_host_t` structure which describes the SD/MMC host driver, lists its capabilites, and provides pointers to functions of the driver. Protocol layer stores card-specific information in :cpp:class:`sdmmc_card_t` structure. When sending commands to the SD/MMC host driver, protocol layer uses :cpp:class:`sdmmc_command_t` structure to describe the command, argument, expected return value, and data to transfer, if any. +Protocol layer API +------------------ -Usage with SD memory cards -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -1. Call the host driver functions to initialize the host (e.g. :cpp:func:`sdmmc_host_init`, :cpp:func:`sdmmc_host_init_slot`). -2. Call :cpp:func:`sdmmc_card_init` to initialize the card, passing it host driver information (``host``) and a pointer to :cpp:class:`sdmmc_card_t` structure which will be filled in (``card``). -3. To read and write sectors of the card, use :cpp:func:`sdmmc_read_sectors` and :cpp:func:`sdmmc_write_sectors`, passing the pointer to card information structure (``card``). -4. When card is not used anymore, call the host driver function to disable the host peripheral and free resources allocated by the driver (e.g. :cpp:func:`sdmmc_host_deinit`). - -Usage with eMMC chips -^^^^^^^^^^^^^^^^^^^^^ - -From the perspective of the protocol layer, eMMC memory chips behave the same way as SD memory cards. Because of similarity of the protocol, even though eMMC are chips don't have the "card" form factor, same terminology is used as for SD cards (`sdmmc_card_t`, `sdmmc_card_init`). Note that eMMC chips can not be used over SPI, therefore are incompatible with SD SPI host driver. - -To initialize eMMC memory and do read/write operations, follow the steps listed above for SD cards. +The protocol layer is given the :cpp:class:`sdmmc_host_t` structure. This structure describes the SD/MMC host driver, lists its capabilities, and provides pointers to functions of the driver. The protocol layer stores card-specific information in the :cpp:class:`sdmmc_card_t` structure. When sending commands to the SD/MMC host driver, the protocol layer uses the :cpp:class:`sdmmc_command_t` structure to describe the command, arguments, expected return values, and data to transfer if there is any. -Usage with SDIO cards -^^^^^^^^^^^^^^^^^^^^^ +Using API with SD memory cards +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Initialization an probing process is the same as with SD memory cards. Only data transfer commands differ in SDIO mode. +1. To initialize the host, call the host driver functions, e.g., :cpp:func:`sdmmc_host_init`, :cpp:func:`sdmmc_host_init_slot`. +2. To initialize the card, call :cpp:func:`sdmmc_card_init` and pass to it the parameters ``host`` - the host driver information, and ``card`` - a pointer to the structure :cpp:class:`sdmmc_card_t` which will be filled with information about the card when the function completes. +3. To read and write sectors of the card, use :cpp:func:`sdmmc_read_sectors` and :cpp:func:`sdmmc_write_sectors` respectively and pass to it the parameter ``card`` - a pointer to the card information structure. +4. If the card is not used anymore, call the host driver function - e.g., :cpp:func:`sdmmc_host_deinit` - to disable the host peripheral and free the resources allocated by the driver. -During probing and card initialization (done by :cpp:func:`sdmmc_card_init`), the driver only configures the following registers of the IO card: -1. The IO portion of the card is reset by setting RES bit in "I/O Abort" (0x06) register. -2. If 4-line mode is enalbed in host and slot configuration, driver attempts to set "Bus width" field in "Bus Interface Control" (0x07) register. If that succeeds (which means that slave supports 4-line mode), host is also switched to 4-line mode. -3. If high-speed mode is enabled in host configuration, SHS bit is set in "High Speed" (0x13) register. +Using API with eMMC chips +^^^^^^^^^^^^^^^^^^^^^^^^^ -In particular, the driver does not set any of the bits in I/O Enable, Int Enable registers, IO block sizes, etc. Applications can set these by calling :cpp:func:`sdmmc_io_write_byte`. +From the protocol layer's perspective, eMMC memory chips behave exactly like SD memory cards. Even though eMMCs are chips and do not have a card form factor, the terminology for SD cards can still be applied to eMMC due to the similarity of the protocol (`sdmmc_card_t`, `sdmmc_card_init`). Note that eMMC chips cannot be used over SPI, which makes them incompatible with the SD SPI host driver. -For card configuration and data transfer, use one of the following functions: +To initialize eMMC memory and perform read/write operations, follow the steps listed for SD cards in the previous section. -- :cpp:func:`sdmmc_io_read_byte`, :cpp:func:`sdmmc_io_write_byte` — read and write single byte using IO_RW_DIRECT (CMD52). -- :cpp:func:`sdmmc_io_read_bytes`, :cpp:func:`sdmmc_io_write_bytes` — read and write multiple bytes using IO_RW_EXTENDED (CMD53), in byte mode. -- :cpp:func:`sdmmc_io_read_blocks`, :cpp:func:`sdmmc_io_write_blocks` — read and write blocks of data using IO_RW_EXTENDED (CMD53), in block mode. -SDIO interrupts can be enabled by the application using :cpp:func:`sdmmc_io_enable_int` function. When using SDIO in 1-line mode, D1 line also needs to be connected to use SDIO interrupts. +Using API with SDIO cards +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Initialization and the probing process is the same as with SD memory cards. The only difference is in data transfer commands in SDIO mode. + +During the card initialization and probing, performed with :cpp:func:`sdmmc_card_init`, the driver only configures the following registers of the IO card: + +1. The IO portion of the card is reset by setting RES bit in the I/O Abort (0x06) register. +2. If 4-line mode is enabled in host and slot configuration, the driver attempts to set the Bus width field in the Bus Interface Control (0x07) register. If setting the filed is successful, which means that the slave supports 4-line mode, the host is also switched to 4-line mode. +3. If high-speed mode is enabled in the host configuration, the SHS bit is set in the High Speed (0x13) register. + +In particular, the driver does not set any bits in (1) I/O Enable and Int Enable registers, (2) I/O block sizes, etc. Applications can set them by calling :cpp:func:`sdmmc_io_write_byte`. + +For card configuration and data transfer, choose the pair of functions relevant to your case from the table below. + +========================================================================= ================================= ================================= +Action Read Function Write Function +========================================================================= ================================= ================================= +Read and write a single byte using IO_RW_DIRECT (CMD52) :cpp:func:`sdmmc_io_read_byte` :cpp:func:`sdmmc_io_write_byte` +Read and write multiple bytes using IO_RW_EXTENDED (CMD53) in byte mode :cpp:func:`sdmmc_io_read_bytes` :cpp:func:`sdmmc_io_write_bytes` +Read and write blocks of data using IO_RW_EXTENDED (CMD53) in block mode :cpp:func:`sdmmc_io_read_blocks` :cpp:func:`sdmmc_io_write_blocks` +========================================================================= ================================= ================================= + +SDIO interrupts can be enabled by the application using the function :cpp:func:`sdmmc_io_enable_int`. When using SDIO in 1-line mode, the D1 line also needs to be connected to use SDIO interrupts. + +If you want the application to wait until the SDIO interrupt occurs, use :cpp:func:`sdmmc_io_wait_int`. -The application can wait for SDIO interrupt to occur using :cpp:func:`sdmmc_io_wait_int`. Combo (memory + IO) cards ^^^^^^^^^^^^^^^^^^^^^^^^^ -The driver does not support SD combo cards. Combo cards will be treated as IO cards. +The driver does not support SD combo cards. Combo cards are treated as IO cards. Thread safety ^^^^^^^^^^^^^ -Most applications need to use the protocol layer only in one task; therefore the protocol layer doesn't implement any kind of locking on the :cpp:class:`sdmmc_card_t` structure, or when accessing SDMMC or SD SPI host drivers. Such locking is usually implemented in the higher layer (e.g. in the filesystem driver). +Most applications need to use the protocol layer only in one task. For this reason, the protocol layer does not implement any kind of locking on the :cpp:class:`sdmmc_card_t` structure, or when accessing SDMMC or SD SPI host drivers. Such locking is usually implemented on a higher layer, e.g., in the filesystem driver. API Reference diff --git a/docs/en/api-reference/storage/spi_flash.rst b/docs/en/api-reference/storage/spi_flash.rst index 1dbb92bdd5..5595011d77 100644 --- a/docs/en/api-reference/storage/spi_flash.rst +++ b/docs/en/api-reference/storage/spi_flash.rst @@ -5,7 +5,7 @@ See also - :doc:`Partition Table documentation <../../api-guides/partition-tables>` - :doc:`Over The Air Update (OTA) API <../system/ota>` provides high-level API for updating app firmware stored in flash. -- :doc:`Non-Volatile Storage (NVS) API ` provides a structured API for storing small items of data in SPI flash. +- :doc:`Non-Volatile Storage (NVS) API ` provides a structured API for storing small pieces of data in SPI flash. .. _spi-flash-implementation-details: @@ -13,35 +13,20 @@ See also Implementation details ---------------------- -In order to perform some flash operations, we need to make sure both CPUs -are not running any code from flash for the duration of the flash operation. -In a single-core setup this is easy: we disable interrupts/scheduler and do -the flash operation. In the dual-core setup this is slightly more complicated. -We need to make sure that the other CPU doesn't run any code from flash. +In order to perform some flash operations, it is necessary to make sure that both CPUs are not running any code from flash for the duration of the flash operation: +- In a single-core setup, the SDK does it by disabling interrupts/scheduler before performing the flash operation. +- In a dual-core setup, this is slightly more complicated as the SDK needs to make sure that the other CPU is not running any code from flash. -When SPI flash API is called on CPU A (can be PRO or APP), we start -spi_flash_op_block_func function on CPU B using esp_ipc_call API. This API -wakes up high priority task on CPU B and tells it to execute given function, -in this case spi_flash_op_block_func. This function disables cache on CPU B and -signals that cache is disabled by setting s_flash_op_can_start flag. -Then the task on CPU A disables cache as well, and proceeds to execute flash -operation. +When SPI flash API is called on CPU A (can be PRO or APP), start the spi_flash_op_block_func function on CPU B using the esp_ipc_call API. This API wakes up a high priority task on CPU B and tells it to execute a given function, in this case, spi_flash_op_block_func. This function disables cache on CPU B and signals that the cache is disabled by setting the s_flash_op_can_start flag. Then the task on CPU A disables cache as well and proceeds to execute flash operation. -While flash operation is running, interrupts can still run on CPUs A and B. -We assume that all interrupt code is placed into RAM. Once interrupt allocation -API is added, we should add a flag to request interrupt to be disabled for -the duration of flash operations. +While a flash operation is running, interrupts can still run on CPUs A and B. It is assumed that all interrupt code is placed into RAM. Once the interrupt allocation API is added, a flag should be added to request the interrupt to be disabled for the duration of a flash operations. -Once flash operation is complete, function on CPU A sets another flag, -s_flash_op_complete, to let the task on CPU B know that it can re-enable -cache and release the CPU. Then the function on CPU A re-enables the cache on -CPU A as well and returns control to the calling code. +Once the flash operation is complete, the function on CPU A sets another flag, s_flash_op_complete, to let the task on CPU B know that it can re-enable cache and release the CPU. Then the function on CPU A re-enables the cache on CPU A as well and returns control to the calling code. Additionally, all API functions are protected with a mutex (s_flash_op_mutex). -In a single core environment (:ref:`CONFIG_FREERTOS_UNICORE` enabled), we simply -disable both caches, no inter-CPU communication takes place. +In a single core environment (:ref:`CONFIG_FREERTOS_UNICORE` enabled), you need to disable both caches, so that no inter-CPU communication can take place. API Reference - SPI Flash ------------------------- diff --git a/docs/en/api-reference/storage/spiffs.rst b/docs/en/api-reference/storage/spiffs.rst index 4c7b3cf779..dcd31a022f 100644 --- a/docs/en/api-reference/storage/spiffs.rst +++ b/docs/en/api-reference/storage/spiffs.rst @@ -4,15 +4,16 @@ SPIFFS Filesystem Overview -------- -SPIFFS is a file system intended for SPI NOR flash devices on embedded targets. -It supports wear leveling, file system consistency checks and more. +SPIFFS is a file system intended for SPI NOR flash devices on embedded targets. It supports wear levelling, file system consistency checks, and more. + Notes ----- - - Currently, SPIFFS does not support directories. It produces a flat structure. If SPIFFS is mounted under ``/spiffs``, then creating a file with path ``/spiffs/tmp/myfile.txt`` will create a file called ``/tmp/myfile.txt`` in SPIFFS, instead of ``myfile.txt`` under directory ``/spiffs/tmp``. - - It is not a realtime stack. One write operation might last much longer than another. - - Currently, it does not detect or handle bad blocks. + - Currently, SPIFFS does not support directories, it produces a flat structure. If SPIFFS is mounted under ``/spiffs``, then creating a file with the path ``/spiffs/tmp/myfile.txt`` will create a file called ``/tmp/myfile.txt`` in SPIFFS, instead of ``myfile.txt`` in the directory ``/spiffs/tmp``. + - It is not a real-time stack. One write operation might take much longer than another. + - For now, it does not detect or handle bad blocks. + Tools ----- @@ -21,29 +22,25 @@ spiffsgen.py ^^^^^^^^^^^^ :component_file:`spiffsgen.py` is a write-only Python SPIFFS implementation used to create filesystem -images from the contents of a host folder. To use ``spiffsgen.py``, simply invoke it from your favorite terminal:: +images from the contents of a host folder. To use ``spiffsgen.py``, open Terminal and run:: python spiffsgen.py -- image_size: size of the partition on which the created SPIFFS image will be flashed to -- base_dir: directory to create the SPIFFS image of -- output_file: SPIFFS image output file +The required arguments are as follows: -Besides the three required arguments: *image_size*, *base_dir* and *output_file*, there are other arguments -that control image generation. Documentation on these arguments exist in the tool's help:: +- **image_size**: size of the partition onto which the created SPIFFS image will be flashed. +- **base_dir**: directory for which the SPIFFS image needs to be created. +- **output_file**: SPIFFS image output file. + +There are also other arguments that control image generation. Documentation on these arguments can be found in the tool's help:: python spiffsgen.py --help -These optional arguments correspond to possible SPIFFS build configuration. -User should make sure that the image is generated with the same arguments/configuration as -SPIFFS was built with, else the user ends up with an invalid image. As a guide, the help output indicates the SPIFFS -build configuration the argument corresponds to. In cases when these arguments -are not specified, the default values shown in the help output are used. +These optional arguments correspond to a possible SPIFFS build configuration. To generate the right image, please make sure that you use the same arguments/configuration as were used to build SPIFFS. As a guide, the help output indicates the SPIFFS build configuration to which the argument corresponds. In cases when these arguments are not specified, the default values shown in the help output will be used. -Once the image has been created, it can be flashed using ``esptool.py`` or ``parttool.py``. +When the image is created, it can be flashed using ``esptool.py`` or ``parttool.py``. -Aside from invoking ``spiffsgen.py`` standalone, it is also possible to use it directly from the build system by calling -``spiffs_create_partition_image``. +Aside from invoking the ``spiffsgen.py`` standalone by manually running it from the command line or a script, it is also possible to invoke ``spiffsgen.py`` directly from the build system by calling ``spiffs_create_partition_image``. Make:: @@ -53,44 +50,42 @@ CMake:: spiffs_create_partition_image( [FLASH_IN_PROJECT]) -This is more convenient as the build configuration is automatically passed to the tool, -ensuring that the image generated is valid for that build. An example of this is while the *image_size* is required -for the standalone invocation, only the *partition* name is required when using ``spiffs_create_partition_image`` -- -the image size is automatically obtained from the project's partition table. -It is important to note that due to the differences in structure between the two build systems, -when using Make, ``spiffs_create_partition_image`` must be called from the project Makefile; -for CMake, it should be called from one of the component CMakeLists.txt. For both build systems, the image will be created in the build directory -with filename *partition*.bin. +This is more convenient as the build configuration is automatically passed to the tool, ensuring that the generated image is valid for that build. An example of this is while the *image_size* is required for the standalone invocation, only the *partition* name is required when using ``spiffs_create_partition_image`` -- the image size is automatically obtained from the project's partition table. -Optionally, user can opt to have the image automatically flashed together with the app binaries, partition tables, etc. on +Due to the differences in structure between Make and Cmake, it is important to note that: +- for Make ``spiffs_create_partition_image`` must be called from the project Makefile +- for CMake ``spiffs_create_partition_image`` must be called from one of the component CMakeLists.txt files + +For both build systems, the image will be created in the build directory with the filename *partition*.bin. + +Optionally, you can opt to have the image automatically flashed together with the app binaries, partition tables, etc., with ``idf.py flash`` or ``make flash`` by specifying ``FLASH_IN_PROJECT``. For example:: spiffs_create_partition_image(my_spiffs_partition my_folder FLASH_IN_PROJECT) -If FLASH_IN_PROJECT is not specified, the image is still generated, -but user has to flash it manually using ``esptool.py``, ``parttool.py`` or a custom build system target. +If FLASH_IN_PROJECT is not specified, the image will still be generated, but you will have to flash it manually using ``esptool.py``, ``parttool.py``, or a custom build system target. -For an example, see :example:`examples/storage/spiffsgen>`. ++For an example, see :example:`examples/storage/spiffsgen>`. mkspiffs ^^^^^^^^ -Another tool for creating SPIFS partition images is `mkspiffs `_. -Like ``spiffsgen.py``, it can be used to create image from a given folder and then flash that image with ``esptool.py`` +Another tool for creating SPIFFS partition images is `mkspiffs `_. +Similar to ``spiffsgen.py``, it can be used to create an image from a given folder and then flash that image using ``esptool.py`` -To do that you need to obtain some parameters: +For that, you need to obtain the following parameters: -- Block Size: 4096 (standard for SPI Flash) -- Page Size: 256 (standard for SPI Flash) -- Image Size: Size of the partition in bytes (can be obtained from partition table) -- Partition Offset: Starting address of the partition (can be obtained from partition table) +- **Block Size**: 4096 (standard for SPI Flash) +- **Page Size**: 256 (standard for SPI Flash) +- **Image Size**: Size of the partition in bytes (can be obtained from a partition table) +- **Partition Offset**: Starting address of the partition (can be obtained from a partition table) -To pack a folder into 1 Megabyte image:: +To pack a folder into a 1-Megabyte image, run:: mkspiffs -c [src_folder] -b 4096 -p 256 -s 0x100000 spiffs.bin -To flash the image to ESP32 at offset 0x110000:: +To flash the image onto ESP32 at offset 0x110000, run:: python esptool.py --chip esp32 --port [port] --baud [baud] write_flash -z 0x110000 spiffs.bin @@ -98,21 +93,15 @@ To flash the image to ESP32 at offset 0x110000:: Notes on which SPIFFS tool to use ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The two tools presented above offer very similar functionality. There are, however, reasons to prefer one -over the other depending on the use case. +The two tools presented above offer very similar functionality. However, there are reasons to prefer one over the other, depending on the use case. -If the intent is to simply generate a SPIFFS image during build, ``spiffsgen.py`` makes it very convenient -by providing functions/commands from the build system itself. This makes it easy to generate SPIFFS images -that match the build configuration and can be flashed together with the application. -Another case for choosing ``spiffsgen.py`` is when the host has no C/C++ compiler available, since ``mkspiffs`` -requires compilation. +Use ``spiffsgen.py`` in the following cases: +1. If you want to simply generate a SPIFFS image during the build. ``spiffsgen.py`` makes it very convenient by providing functions/commands from the build system itself. +2. If the host has no C/C++ compiler available, because ``spiffsgen.py`` does not require compilation. -On the other hand, ``mkspiffs`` offers unpacking SPIFFS images in addition to image generation. This is not -possible with ``spiffsgen.py``, at least not yet. There might also be environments where a Python interpreter -is not available, but a host compiler is or a pre-compiled ``mkspiffs`` binary -can do the job. However, there is no build system integration for ``mkspiffs`` and the user has to -do the corresponding work: compiling ``mkspiffs`` during build (if a pre-compiled binary is not used), creating build rules/targets -for the output files, passing proper parameters to the tool, etc. +Use ``mkspiffs`` in the following cases: +1. If you need to unpack SPIFFS images in addition to image generation. For now, it is not possible with ``spiffsgen.py``. +2. If you have an environment where a Python interpreter is not available, but a host compiler is available. Otherwise, a pre-compiled ``mkspiffs`` binary can do the job. However, there is no build system integration for ``mkspiffs`` and the user has to do the corresponding work: compiling ``mkspiffs`` during build (if a pre-compiled binary is not used), creating build rules/targets for the output files, passing proper parameters to the tool, etc. See also @@ -120,14 +109,14 @@ See also - :doc:`Partition Table documentation <../../api-guides/partition-tables>` + Application Example ------------------- -An example for using SPIFFS is provided in :example:`storage/spiffs` directory. This example initializes and mounts SPIFFS partition, and writes and reads data from it using POSIX and C library APIs. See README.md file in the example directory for more information. +An example of using SPIFFS is provided in the :example:`storage/spiffs` directory. This example initializes and mounts a SPIFFS partition, then writes and reads data from it using POSIX and C library APIs. See the README.md file in the example directory for more information. -High level API Reference + +High-level API Reference ------------------------ -* :component_file:`spiffs/include/esp_spiffs.h` - .. include:: /_build/inc/esp_spiffs.inc diff --git a/docs/en/api-reference/storage/wear-levelling.rst b/docs/en/api-reference/storage/wear-levelling.rst index 847da56e0c..580dd6f3b5 100644 --- a/docs/en/api-reference/storage/wear-levelling.rst +++ b/docs/en/api-reference/storage/wear-levelling.rst @@ -9,7 +9,7 @@ See also Application Example ------------------- -An example which combines wear levelling driver with FATFS library is provided in ``examples/storage/wear_levelling`` directory. This example initializes the wear levelling driver, mounts FATFS partition, and writes and reads data from it using POSIX and C library APIs. See README.md file in the example directory for more information. +An example which combines the wear levelling driver with the FATFS library is provided in the :example:`storage/wear_levelling` directory. This example initializes the wear levelling driver, mounts FATFS partition, as well as writes and reads data from it using POSIX and C library APIs. See the :example:`storage/wear_levelling/README.md` file for more information. High level API Reference ------------------------ diff --git a/tools/mass_mfg/docs/README.rst b/tools/mass_mfg/docs/README.rst index ba43dd5e9f..ce614f77ef 100644 --- a/tools/mass_mfg/docs/README.rst +++ b/tools/mass_mfg/docs/README.rst @@ -1,50 +1,56 @@ Manufacturing Utility ===================== - Introduction ----------------- +------------ + +This utility is designed to create instances of factory NVS partition images on a per-device basis for mass manufacturing purposes. The NVS partition images are created from CSV files containing user-provided configurations and values. + +Please note that this utility only creates manufacturing binary images which then need to be flashed onto your devices using: + +- esptool.py +- Flash Download tool (available on Windows only) +- Direct flash programming -This utility is designed to create per device instances factory nvs partition images for mass manufacturing purposes. -These images are created from user provided configuration and values csv files. -This utility only creates the manufacturing binary images and you can choose to use esptool.py or Windows based flash programming utility or direct flash programming to program these images at the time of manufacturing. Prerequisites ------------------- +------------- -**This utility is dependent on the esp-idf nvs partition utility.** +**This utility is dependent on esp-idf's NVS partition utility.** -* Operating System requirements: - - Linux / MacOS / Windows (standard distributions) +* Operating System requirements: + - Linux / MacOS / Windows (standard distributions) -* The following packages are needed for using this utility: - - Python version: 2.7 (minimum) is required. - - Link to install python: +* The following packages are needed to use this utility: + - Python version: 2.7 (minimum) is required. You can find it here: -.. note:: Make sure the python path is set in the PATH environment variable before using this utility. +.. note:: + + Before using this utility, please make sure that: + - The path to Python is added to the PATH environment variable. + - You have installed the packages from `requirement.txt`, the file in the root of the esp-idf directory. -Make sure to include packages from `requirement.txt` in top level IDF directory. Workflow ------------ +-------- .. blockdiag:: blockdiag { A [label = "CSV Configuration file"]; - B [label = "Master CSV Values file"]; + B [label = "Master Value CSV file"]; C [label = "Binary files", stacked]; A -- B -> C } -CSV Configuration File: ------------------------- +CSV Configuration File +---------------------- -This file contains the configuration of the device to be manufactured. +This file contains the configuration of the device to be flashed. -The data in configuration file **must** have the following format (`REPEAT` tag is optional):: +The data in the configuration file has the following format (the `REPEAT` tag is optional):: name1,namespace, <-- First entry should be of type "namespace" key1,type1,encoding1 @@ -53,12 +59,12 @@ The data in configuration file **must** have the following format (`REPEAT` tag key3,type3,encoding3 key4,type4,encoding4 -.. note:: First entry in this file should always be ``namespace`` entry. +.. note:: The first line in this file should always be the ``namespace`` entry. -Each row should have these 3 parameters: ``key,type,encoding`` separated by comma. -If ``REPEAT`` tag is present, the value corresponding to this key in the Master CSV Values File will be the same for all devices. +Each line should have three parameters: ``key,type,encoding``, separated by a comma. +If the ``REPEAT`` tag is present, the value corresponding to this key in the master value CSV file will be the same for all devices. -*Please refer to README of nvs_partition utility for detailed description of each parameter.* +*Please refer to README of the NVS Partition Generator utility for detailed description of each parameter.* Below is a sample example of such a configuration file:: @@ -69,115 +75,131 @@ Below is a sample example of such a configuration file:: device_no,data,i32 -.. note:: Make sure there are no spaces before and after ',' in the configuration file. +.. note:: -Master CSV Values File: ------------------------- + Make sure there are **no spaces**: + - before and after ',' + - at the end of each line in a CSV file -This file contains details of the device to be manufactured. Each row in this file corresponds to a device instance. + +Master Value CSV File +--------------------- + +This file contains details of the devices to be flashed. Each line in this file corresponds to a device instance. -The data in values file **must** have the following format:: +The data in the master value CSV file has the following format:: key1,key2,key3,..... value1,value2,value3,.... -.. note:: First line in this file should always be the ``key`` names. All the keys from the configuration file should be present here in the **same order**. This file can have additional columns(keys) and they will act like metadata and would not be part of final binary files. +.. note:: The first line in the file should always contain the ``key`` names. All the keys from the configuration file should be present here in the **same order**. This file can have additional columns (keys). The additional keys will be treated as metadata and would not be part of the final binary files. -Each row should have the ``value`` of the corresponding keys, separated by comma. If key has ``REPEAT`` tag, then its corresponding value **must** be entered in the second line only. Keep the entry empty for this value in the next lines. Below is the description of this parameter: +Each line should contain the ``value`` of the corresponding keys, separated by a comma. If the key has the ``REPEAT`` tag, its corresponding value **must** be entered in the second line only. Keep the entry empty for this value in the following lines. + +The description of this parameter is as follows: ``value`` - Data value. + Data value -Below is a sample example of such a values file:: +Data value is the value of data corresponding to the key. + +Below is a sample example of a master value CSV file:: id,firmware_key,serial_no,device_no 1,1a2b3c4d5e6faabb,A1,101 2,1a2b3c4d5e6fccdd,,102 3,1a2b3c4d5e6feeff,,103 -.. note:: *If 'REPEAT' tag is present, a new Master CSV Values File is created in the same folder as the input Master CSV File with the values inserted at each line for the key with 'REPEAT' tag.* +.. note:: *If the 'REPEAT' tag is present, a new master value CSV file will be created in the same folder as the input Master CSV File with the values inserted at each line for the key with the 'REPEAT' tag*. -.. note:: *Intermediate CSV files are created by this utility which are input to the nvs partition utility to generate the binary files.* +This utility creates intermediate CSV files which are used as input for the NVS partition utility to generate the binary files. -The format of this intermediate csv file will be:: +The format of this intermediate CSV file is as follows:: key,type,encoding,value key,namespace, , key1,type1,encoding1,value1 key2,type2,encoding2,value2 -.. note:: An intermediate csv file will be created for each device instance. +An instance of an intermediate CSV file will be created for each device on an individual basis. + Running the utility ----------------------- +------------------- -The mfg\_gen.py utility is using the generated CSV Configuration file and Master CSV Values file and is generating per device instance factory images. +The mfg\_gen.py utility uses the generated CSV Configuration file and the master value CSV file to generate factory images for each device. -*Sample CSV Configuration file and Master CSV Values file is provided with this utility.* +*A sample CSV Configuration file and a master value CSV file are both provided with this utility.* **Usage**:: - $ ./mfg_gen.py [-h] [--conf CONFIG_FILE] [--values VALUES_FILE] + ./mfg_gen.py [-h] [--conf CONFIG_FILE] [--values VALUES_FILE] [--prefix PREFIX] [--fileid FILEID] [--outdir OUTDIR] [--size PART_SIZE] [--version {v1,v2}] [--keygen {true,false}] [--encrypt {true,false}] [--keyfile KEYFILE] +The description of the arguments is given in the table below. -+------------------------+----------------------------------------------------------------------------------------------+ -| Arguments | Description | -+========================+==============================================================================================+ -| --conf CONFIG_FILE | the input configuration csv file | -+------------------------+----------------------------------------------------------------------------------------------+ -| --values VALUES_FILE | the input values csv file | -+------------------------+----------------------------------------------------------------------------------------------+ -| --prefix PREFIX | the unique name as each filename prefix | -+------------------------+----------------------------------------------------------------------------------------------+ -| --fileid FILEID | the unique file identifier(any key in values file) | -| | as each filename suffix (Default: numeric value(1,2,3...)) | -+------------------------+----------------------------------------------------------------------------------------------+ -| --outdir OUTDIR | the output directory to store the files created (Default: current directory) | -+------------------------+----------------------------------------------------------------------------------------------+ -| --size PART_SIZE | Size of NVS Partition in bytes (must be multiple of 4096) | -+------------------------+----------------------------------------------------------------------------------------------+ -| --version {v1,v2} | Set version. Default: v2 | -+------------------------+----------------------------------------------------------------------------------------------+ -| --keygen {true,false} | Generate keys for encryption. | -| | Default: false | -+------------------------+----------------------------------------------------------------------------------------------+ -| --encrypt {true,false} | Set encryption mode. Default: false | -+------------------------+----------------------------------------------------------------------------------------------+ -| --keyfile KEYFILE | File having key for encryption (Applicable only if encryption mode is true) | -+------------------------+----------------------------------------------------------------------------------------------+ ++------------------------+------------------------------------------------------------+-------------------+ +| Arguments | Description | Default Value | ++========================+============================================================+===================+ +| --conf CONFIG_FILE | Path to existing CSV configuration file | | ++------------------------+------------------------------------------------------------+-------------------+ +| --values VALUES_FILE | Path to existing master value CSV file | | ++------------------------+------------------------------------------------------------+-------------------+ +| --prefix PREFIX | Unique filename prefix | | ++------------------------+------------------------------------------------------------+-------------------+ +| --fileid FILEID | Unique file identifier (any key in the file with values) | numeric value | +| | as a filename suffix | (1,2,3...) | ++------------------------+------------------------------------------------------------+-------------------+ +| --outdir OUTDIR | Output directory to store created files | current directory | ++------------------------+------------------------------------------------------------+-------------------+ +| --size PART_SIZE | Size of NVS Partition in bytes (must be multiple of 4096) | | ++------------------------+------------------------------------------------------------+-------------------+ +| --version {v1,v2} | Set version | v2 | ++------------------------+------------------------------------------------------------+-------------------+ +| --keygen {true,false} | Generate keys for encryption | false | ++------------------------+------------------------------------------------------------+-------------------+ +| --encrypt {true,false} | Set encryption mode | false | ++------------------------+------------------------------------------------------------+-------------------+ +| --keyfile KEYFILE | File storing key for encryption (Applicable only if | | +| | Encryption mode is true). | | ++------------------------+------------------------------------------------------------+-------------------+ -*You can use the below commands to run this utility with the sample files provided*:: - - $ ./mfg_gen.py --conf samples/sample_config.csv --values samples/sample_values_singlepage_blob.csv --prefix Fan --size 0x3000 +*To run this utility with the provided sample files, use the commands below*:: - $ ./mfg_gen.py --conf samples/sample_config.csv --values samples/sample_values_multipage_blob.csv --prefix Fan --size 0x4000 - -.. note:: When you use this utility to generate per device instance factory images --conf, --values, --prefix and --size arguments are mandatory. - - $ ./mfg_gen.py --conf samples/sample_config.csv --values samples/sample_values_singlepage_blob.csv --prefix Fan --size 0x3000 --outdir tmp + ./mfg_gen.py --conf samples/sample_config.csv --values samples/sample_values_singlepage_blob.csv --prefix Fan --size 0x3000 -.. note:: The --outdir directory is created if not present. + ./mfg_gen.py --conf samples/sample_config.csv --values samples/sample_values_multipage_blob.csv --prefix Fan --size 0x4000 -.. note:: The file path given in the ``file`` type in the values file is expected to be relative to the current directory from which you are running the utility. - - $ ./mfg_gen.py --conf samples/sample_config.csv --values samples/sample_values_singlepage_blob.csv --prefix Fan --size 0x3000 --encrypt true --keygen true +When you use this utility to generate factory images on a per device basis, keep in mind that the arguments --conf, --values, --prefix, and --size are mandatory. -.. note:: ``keys/`` directory is generated with the encryption keys filename of the form ``prefix-fileid-keys.bin``. - -*You can also run the below command to use the utility to* **only** *generate encryption keys binary file ( following example 'keys/' directory is created in current path), which can further be used to encrypt per device instance factory images*:: - - $ ./mfg_gen.py --keygen true - - $ ./mfg_gen.py --keygen true --keyfile encr_keys.bin + ./mfg_gen.py --conf samples/sample_config.csv --values samples/sample_values_singlepage_blob.csv --prefix Fan --size 0x3000 --outdir tmp -.. note:: When running utility to generate only ``keys``, if --keyfile is given it will generate encryption keys with filename given in --keyfile argument. +.. note:: If the --outdir directory does not exist, it will be created. -.. note:: When you use this utility to generate only encryption keys --keygen argument is mandatory. +The master value CSV file should have the path in the ``file`` type relative to the directory from which you are running the utility. -.. note:: The default numeric value: 1,2,3... of ``fileid`` argument, corresponds to each row having device instance values in master csv values file. + ./mfg_gen.py --conf samples/sample_config.csv --values samples/sample_values_singlepage_blob.csv --prefix Fan --size 0x3000 --encrypt true --keygen true -.. note:: ``bin/`` **and** ``csv/`` **sub-directories are created in the** ``outdir`` **directory specified while running this utility. The binary files generated will be stored in** ``bin/`` **and the intermediate csv files generated will be stored in** ``csv/``. +.. note:: The generated ``keys/`` directory is named as the file with encryption keys of the form ``prefix-fileid-keys.bin``. + +*If you* **only** *want to generate a binary file with encryption keys, you can run the command below.*:: + + ./mfg_gen.py --keygen true + +.. note:: When you use this utility to generate encryption keys only, the --keygen argument is mandatory. + +In the following example, the 'keys/' directory will be created at the current path. This binary file can further be used to encrypt factory images created on the per device basis*.:: + + ./mfg_gen.py --keygen true --keyfile encr_keys.bin + +.. note:: When running the utility to generate encryption keys only, if --keyfile is given, it will generate encryption keys with the filename given in the --keyfile argument. + +The default numeric value: 1,2,3... of the ``fileid`` argument corresponds to each line bearing device instance values in the master value CSV file. + +While running the manufacturing utility, the following folders will be created in the specified ``outdir`` directory: + +- ``bin/`` for storing the generated binary files +- ``csv/`` for storing the generated intermediate CSV files From 76b3a64b760c41709b968868c19de318b7068c19 Mon Sep 17 00:00:00 2001 From: zhiweijian Date: Thu, 23 May 2019 14:44:16 +0800 Subject: [PATCH 060/486] Component/bt: add new api to get connection parameters --- components/bt/bluedroid/api/esp_gap_ble_api.c | 11 +++++++ .../api/include/api/esp_gap_ble_api.h | 22 +++++++++++++ .../bluedroid/api/include/api/esp_gatt_defs.h | 11 +++++++ .../bluedroid/api/include/api/esp_gattc_api.h | 1 + .../bluedroid/api/include/api/esp_gatts_api.h | 1 + .../bt/bluedroid/bta/gatt/bta_gattc_act.c | 12 ++++++- .../bt/bluedroid/bta/gatt/bta_gattc_utils.c | 5 ++- .../bt/bluedroid/bta/gatt/bta_gatts_act.c | 14 +++++++-- .../bta/gatt/include/bta_gattc_int.h | 3 +- .../bluedroid/bta/include/bta/bta_gatt_api.h | 8 +++++ .../btc/profile/std/gatt/btc_gattc.c | 3 ++ .../btc/profile/std/gatt/btc_gatts.c | 4 ++- components/bt/bluedroid/stack/btm/btm_ble.c | 31 +++++++++++++++++++ .../bt/bluedroid/stack/btm/btm_ble_gap.c | 25 +++++++++++++++ .../bluedroid/stack/btm/include/btm_ble_int.h | 2 ++ .../stack/include/stack/btm_ble_api.h | 13 ++++++++ 16 files changed, 160 insertions(+), 6 deletions(-) diff --git a/components/bt/bluedroid/api/esp_gap_ble_api.c b/components/bt/bluedroid/api/esp_gap_ble_api.c index cc9983b537..aef6b3d6d6 100644 --- a/components/bt/bluedroid/api/esp_gap_ble_api.c +++ b/components/bt/bluedroid/api/esp_gap_ble_api.c @@ -706,6 +706,17 @@ esp_err_t esp_ble_gap_disconnect(esp_bd_addr_t remote_device) return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gap_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } +esp_err_t esp_ble_get_current_conn_params(esp_bd_addr_t bd_addr, esp_gap_conn_params_t *conn_params) +{ + if(!bd_addr || !conn_params) { + return ESP_ERR_INVALID_ARG; + } + if(BTM_GetCurrentConnParams(bd_addr, &conn_params->interval, &conn_params->latency, &conn_params->timeout)) { + return ESP_OK; + } + return ESP_ERR_NOT_FOUND; +} + diff --git a/components/bt/bluedroid/api/include/api/esp_gap_ble_api.h b/components/bt/bluedroid/api/include/api/esp_gap_ble_api.h index 96123e8bce..f6097dfe70 100644 --- a/components/bt/bluedroid/api/include/api/esp_gap_ble_api.h +++ b/components/bt/bluedroid/api/include/api/esp_gap_ble_api.h @@ -377,6 +377,15 @@ typedef struct { advertising reports for each packet received */ } esp_ble_scan_params_t; +/// connection parameters information +typedef struct { + uint16_t interval; /*!< connection interval */ + uint16_t latency; /*!< Slave latency for the connection in number of connection events. Range: 0x0000 to 0x01F3 */ + uint16_t timeout; /*!< Supervision timeout for the LE Link. Range: 0x000A to 0x0C80. + Mandatory Range: 0x000A to 0x0C80 Time = N * 10 msec + Time Range: 100 msec to 32 seconds */ +} esp_gap_conn_params_t; + /// Connection update parameters typedef struct { esp_bd_addr_t bda; /*!< Bluetooth device address */ @@ -1233,6 +1242,19 @@ esp_err_t esp_ble_oob_req_reply(esp_bd_addr_t bd_addr, uint8_t *TK, uint8_t len) */ esp_err_t esp_ble_gap_disconnect(esp_bd_addr_t remote_device); +/** +* @brief This function is called to read the connection +* parameters information of the device +* +* @param[in] bd_addr: BD address of the peer device. +* @param[out] conn_params: the connection parameters information +* +* @return - ESP_OK : success +* - other : failed +* +*/ +esp_err_t esp_ble_get_current_conn_params(esp_bd_addr_t bd_addr, esp_gap_conn_params_t *conn_params); + #ifdef __cplusplus } #endif diff --git a/components/bt/bluedroid/api/include/api/esp_gatt_defs.h b/components/bt/bluedroid/api/include/api/esp_gatt_defs.h index d6c140a140..6deadeadcc 100644 --- a/components/bt/bluedroid/api/include/api/esp_gatt_defs.h +++ b/components/bt/bluedroid/api/include/api/esp_gatt_defs.h @@ -387,6 +387,17 @@ typedef enum { ESP_GATT_WRITE_TYPE_RSP, /*!< Gatt write attribute need remote response */ } esp_gatt_write_type_t; +/** + * @brief Connection parameters information + */ +typedef struct { + uint16_t interval; /*!< connection interval */ + uint16_t latency; /*!< Slave latency for the connection in number of connection events. Range: 0x0000 to 0x01F3 */ + uint16_t timeout; /*!< Supervision timeout for the LE Link. Range: 0x000A to 0x0C80. + Mandatory Range: 0x000A to 0x0C80 Time = N * 10 msec + Time Range: 100 msec to 32 seconds */ +} esp_gatt_conn_params_t; + #define ESP_GATT_IF_NONE 0xff /*!< If callback report gattc_if/gatts_if as this macro, means this event is not correspond to any app */ typedef uint8_t esp_gatt_if_t; /*!< Gatt interface type, different application on GATT client use different gatt_if */ diff --git a/components/bt/bluedroid/api/include/api/esp_gattc_api.h b/components/bt/bluedroid/api/include/api/esp_gattc_api.h index d18b2e4c4e..d8f8bf7ece 100644 --- a/components/bt/bluedroid/api/include/api/esp_gattc_api.h +++ b/components/bt/bluedroid/api/include/api/esp_gattc_api.h @@ -210,6 +210,7 @@ typedef union { struct gattc_connect_evt_param { uint16_t conn_id; /*!< Connection id */ esp_bd_addr_t remote_bda; /*!< Remote bluetooth device address */ + esp_gatt_conn_params_t conn_params; /*!< current connection parameters */ } connect; /*!< Gatt client callback param of ESP_GATTC_CONNECT_EVT */ /** diff --git a/components/bt/bluedroid/api/include/api/esp_gatts_api.h b/components/bt/bluedroid/api/include/api/esp_gatts_api.h index 97296b1c7a..a3aee4cc1a 100644 --- a/components/bt/bluedroid/api/include/api/esp_gatts_api.h +++ b/components/bt/bluedroid/api/include/api/esp_gatts_api.h @@ -197,6 +197,7 @@ typedef union { struct gatts_connect_evt_param { uint16_t conn_id; /*!< Connection id */ esp_bd_addr_t remote_bda; /*!< Remote bluetooth device address */ + esp_gatt_conn_params_t conn_params; /*!< current Connection parameters */ } connect; /*!< Gatt server callback param of ESP_GATTS_CONNECT_EVT */ /** diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_act.c b/components/bt/bluedroid/bta/gatt/bta_gattc_act.c index ed066d006c..e6df3e5189 100644 --- a/components/bt/bluedroid/bta/gatt/bta_gattc_act.c +++ b/components/bt/bluedroid/bta/gatt/bta_gattc_act.c @@ -729,7 +729,7 @@ void bta_gattc_conncback(tBTA_GATTC_RCB *p_rcb, tBTA_GATTC_DATA *p_data) if (p_rcb) { bta_gattc_send_connect_cback(p_rcb, p_data->int_conn.remote_bda, - p_data->int_conn.hdr.layer_specific); + p_data->int_conn.hdr.layer_specific, p_data->int_conn.conn_params); } } @@ -1654,6 +1654,16 @@ static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda, UINT16 conn_id, p_buf->int_conn.hdr.event = connected ? BTA_GATTC_INT_CONN_EVT : BTA_GATTC_INT_DISCONN_EVT; + if(p_buf->int_conn.hdr.event == BTA_GATTC_INT_CONN_EVT) { + tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(bda, BT_TRANSPORT_LE); + if(p_lcb != NULL) { + p_buf->int_conn.conn_params.interval = p_lcb->current_used_conn_interval; + p_buf->int_conn.conn_params.latency = p_lcb->current_used_conn_latency; + p_buf->int_conn.conn_params.timeout = p_lcb->current_used_conn_timeout; + } else { + APPL_TRACE_WARNING("%s not found connection parameters of the device ", __func__); + } + } p_buf->int_conn.hdr.layer_specific = conn_id; p_buf->int_conn.client_if = gattc_if; p_buf->int_conn.role = L2CA_GetBleConnRole(bda); diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_utils.c b/components/bt/bluedroid/bta/gatt/bta_gattc_utils.c index d202451447..ed9e4c20e4 100644 --- a/components/bt/bluedroid/bta/gatt/bta_gattc_utils.c +++ b/components/bt/bluedroid/bta/gatt/bta_gattc_utils.c @@ -738,7 +738,7 @@ void bta_gattc_send_open_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS status ** Returns ** *******************************************************************************/ -void bta_gattc_send_connect_cback( tBTA_GATTC_RCB *p_clreg, BD_ADDR remote_bda, UINT16 conn_id) +void bta_gattc_send_connect_cback( tBTA_GATTC_RCB *p_clreg, BD_ADDR remote_bda, UINT16 conn_id, tBTA_GATT_CONN_PARAMS conn_params) { tBTA_GATTC cb_data; @@ -747,6 +747,9 @@ void bta_gattc_send_connect_cback( tBTA_GATTC_RCB *p_clreg, BD_ADDR remote_bda, cb_data.connect.client_if = p_clreg->client_if; cb_data.connect.conn_id = conn_id; + cb_data.connect.conn_params.interval = conn_params.interval; + cb_data.connect.conn_params.latency = conn_params.latency; + cb_data.connect.conn_params.timeout = conn_params.timeout; bdcpy(cb_data.connect.remote_bda, remote_bda); (*p_clreg->p_cback)(BTA_GATTC_CONNECT_EVT, &cb_data); diff --git a/components/bt/bluedroid/bta/gatt/bta_gatts_act.c b/components/bt/bluedroid/bta/gatt/bta_gatts_act.c index 47bad4afba..95cb668c6b 100644 --- a/components/bt/bluedroid/bta/gatt/bta_gatts_act.c +++ b/components/bt/bluedroid/bta/gatt/bta_gatts_act.c @@ -35,6 +35,7 @@ #include "stack/btm_ble_api.h" #include #include "osi/allocator.h" +#include "l2c_int.h" static void bta_gatts_nv_save_cback(BOOLEAN is_saved, tGATTS_HNDL_RANGE *p_hndl_range); static BOOLEAN bta_gatts_nv_srv_chg_cback(tGATTS_SRV_CHG_CMD cmd, tGATTS_SRV_CHG_REQ *p_req, @@ -965,7 +966,7 @@ static void bta_gatts_conn_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected, tGATT_DISCONN_REASON reason, tGATT_TRANSPORT transport) { - tBTA_GATTS cb_data; + tBTA_GATTS cb_data = {0}; UINT8 evt = connected ? BTA_GATTS_CONNECT_EVT : BTA_GATTS_DISCONNECT_EVT; tBTA_GATTS_RCB *p_reg; @@ -993,7 +994,16 @@ static void bta_gatts_conn_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, bta_sys_conn_close( BTA_ID_GATTS , BTA_ALL_APP_ID, bda); } } - + if(evt == BTA_GATTS_CONNECT_EVT) { + tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(bda, BT_TRANSPORT_LE); + if(p_lcb != NULL) { + cb_data.conn.conn_params.interval = p_lcb->current_used_conn_interval; + cb_data.conn.conn_params.latency = p_lcb->current_used_conn_latency; + cb_data.conn.conn_params.timeout = p_lcb->current_used_conn_timeout; + }else { + APPL_TRACE_WARNING("%s not found connection parameters of the device ", __func__); + } + } cb_data.conn.conn_id = conn_id; cb_data.conn.server_if = gatt_if; cb_data.conn.reason = reason; diff --git a/components/bt/bluedroid/bta/gatt/include/bta_gattc_int.h b/components/bt/bluedroid/bta/gatt/include/bta_gattc_int.h index c25f5ddb30..9715ac681e 100644 --- a/components/bt/bluedroid/bta/gatt/include/bta_gattc_int.h +++ b/components/bt/bluedroid/bta/gatt/include/bta_gattc_int.h @@ -216,6 +216,7 @@ typedef struct { tBT_TRANSPORT transport; tGATT_DISCONN_REASON reason; BOOLEAN already_connect; + tBTA_GATT_CONN_PARAMS conn_params; } tBTA_GATTC_INT_CONN; typedef struct { @@ -467,7 +468,7 @@ extern void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN *p_data, tBTA_GATTC_RCB * extern void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN *p_data); extern void bta_gattc_send_open_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS status, BD_ADDR remote_bda, UINT16 conn_id, tBTA_TRANSPORT transport, UINT16 mtu); -extern void bta_gattc_send_connect_cback( tBTA_GATTC_RCB *p_clreg, BD_ADDR remote_bda, UINT16 conn_id); +extern void bta_gattc_send_connect_cback( tBTA_GATTC_RCB *p_clreg, BD_ADDR remote_bda, UINT16 conn_id, tBTA_GATT_CONN_PARAMS conn_params); extern void bta_gattc_send_disconnect_cback( tBTA_GATTC_RCB *p_clreg, tGATT_DISCONN_REASON reason, BD_ADDR remote_bda, UINT16 conn_id); extern void bta_gattc_process_api_refresh(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_msg); diff --git a/components/bt/bluedroid/bta/include/bta/bta_gatt_api.h b/components/bt/bluedroid/bta/include/bta/bta_gatt_api.h index 896ca151cc..cb69110b60 100644 --- a/components/bt/bluedroid/bta/include/bta/bta_gatt_api.h +++ b/components/bt/bluedroid/bta/include/bta/bta_gatt_api.h @@ -201,6 +201,12 @@ typedef struct { UINT8 name_spc; /* The name space of the description */ } tBTA_GATT_CHAR_PRES; +typedef struct { + UINT16 interval; + UINT16 latency; + UINT16 timeout; +} tBTA_GATT_CONN_PARAMS; + #define BTA_GATT_CLT_CONFIG_NONE GATT_CLT_CONFIG_NONE /* 0x0000 */ #define BTA_GATT_CLT_CONFIG_NOTIFICATION GATT_CLT_CONFIG_NOTIFICATION /* 0x0001 */ #define BTA_GATT_CLT_CONFIG_INDICATION GATT_CLT_CONFIG_INDICATION /* 0x0002 */ @@ -403,6 +409,7 @@ typedef struct { UINT16 conn_id; tBTA_GATTC_IF client_if; BD_ADDR remote_bda; + tBTA_GATT_CONN_PARAMS conn_params; } tBTA_GATTC_CONNECT; typedef struct { @@ -610,6 +617,7 @@ typedef struct { UINT16 conn_id; tBTA_GATT_REASON reason; /* report disconnect reason */ tBTA_GATT_TRANSPORT transport; + tBTA_GATT_CONN_PARAMS conn_params; } tBTA_GATTS_CONN; typedef struct { diff --git a/components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c b/components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c index 5eaee361b8..73214a67dc 100644 --- a/components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c +++ b/components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c @@ -901,6 +901,9 @@ void btc_gattc_cb_handler(btc_msg_t *msg) gattc_if = connect->client_if; param.connect.conn_id = BTC_GATT_GET_CONN_ID(connect->conn_id); memcpy(param.connect.remote_bda, connect->remote_bda, sizeof(esp_bd_addr_t)); + param.connect.conn_params.interval = connect->conn_params.interval; + param.connect.conn_params.latency = connect->conn_params.latency; + param.connect.conn_params.timeout = connect->conn_params.timeout; btc_gattc_cb_to_app(ESP_GATTC_CONNECT_EVT, gattc_if, ¶m); break; } diff --git a/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c b/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c index eff4d41a1e..5b29a8b1e1 100644 --- a/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c +++ b/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c @@ -901,7 +901,9 @@ void btc_gatts_cb_handler(btc_msg_t *msg) gatts_if = p_data->conn.server_if; param.connect.conn_id = BTC_GATT_GET_CONN_ID(p_data->conn.conn_id); memcpy(param.connect.remote_bda, p_data->conn.remote_bda, ESP_BD_ADDR_LEN); - + param.connect.conn_params.interval = p_data->conn.conn_params.interval; + param.connect.conn_params.latency = p_data->conn.conn_params.latency; + param.connect.conn_params.timeout = p_data->conn.conn_params.timeout; btc_gatts_cb_to_app(ESP_GATTS_CONNECT_EVT, gatts_if, ¶m); break; case BTA_GATTS_DISCONNECT_EVT: diff --git a/components/bt/bluedroid/stack/btm/btm_ble.c b/components/bt/bluedroid/stack/btm/btm_ble.c index 73f6387a8d..2b62cde415 100644 --- a/components/bt/bluedroid/stack/btm/btm_ble.c +++ b/components/bt/bluedroid/stack/btm/btm_ble.c @@ -2732,4 +2732,35 @@ void btm_ble_set_keep_rfu_in_auth_req(BOOLEAN keep_rfu) #endif /* BTM_BLE_CONFORMANCE_TESTING */ +/******************************************************************************* +** +** Function btm_get_current_conn_params +** +** Description This function is called to get current connection parameters +** information of the device +** +** Returns TRUE if the information is geted, else FALSE +** +*******************************************************************************/ + +BOOLEAN btm_get_current_conn_params(BD_ADDR bda, UINT16 *interval, UINT16 *latency, UINT16 *timeout) +{ + if( (interval == NULL) || (latency == NULL) || (timeout == NULL) ) { + BTM_TRACE_ERROR("%s invalid parameters ", __func__); + return FALSE; + } + + tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(bda, BT_TRANSPORT_LE); + if(p_lcb != NULL) { + (*interval) = p_lcb->current_used_conn_interval; + (*latency) = p_lcb->current_used_conn_latency; + (*timeout) = p_lcb->current_used_conn_timeout; + return TRUE; + } + BTM_TRACE_WARNING("%s Device is not connected", __func__); + + return FALSE; +} + + #endif /* BLE_INCLUDED */ diff --git a/components/bt/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/bluedroid/stack/btm/btm_ble_gap.c index fff66affa8..cbf349ded1 100644 --- a/components/bt/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/bluedroid/stack/btm/btm_ble_gap.c @@ -2045,6 +2045,31 @@ void BTM_Recovery_Pre_State(void) return; } +/******************************************************************************* +** +** Function BTM_GetCurrentConnParams +** +** Description This function is called to read the current connection parameters +** of the device +** +** Returns TRUE or FALSE +** +*******************************************************************************/ + +BOOLEAN BTM_GetCurrentConnParams(BD_ADDR bda, uint16_t *interval, uint16_t *latency, uint16_t *timeout) +{ + if( (interval == NULL) || (latency == NULL) || (timeout == NULL) ) { + BTM_TRACE_ERROR("%s error ", __func__); + return FALSE; + } + + if(btm_get_current_conn_params(bda, interval, latency, timeout)) { + return TRUE; + } + + return FALSE; +} + /******************************************************************************* ** ** Function btm_ble_build_adv_data diff --git a/components/bt/bluedroid/stack/btm/include/btm_ble_int.h b/components/bt/bluedroid/stack/btm/include/btm_ble_int.h index 369e60264f..4fc915e471 100644 --- a/components/bt/bluedroid/stack/btm/include/btm_ble_int.h +++ b/components/bt/bluedroid/stack/btm/include/btm_ble_int.h @@ -506,6 +506,8 @@ void btm_set_random_address(BD_ADDR random_bda); void btm_ble_set_keep_rfu_in_auth_req(BOOLEAN keep_rfu); #endif +BOOLEAN btm_get_current_conn_params(BD_ADDR bda, UINT16 *interval, UINT16 *latency, UINT16 *timeout); + /* #ifdef __cplusplus } diff --git a/components/bt/bluedroid/stack/include/stack/btm_ble_api.h b/components/bt/bluedroid/stack/include/stack/btm_ble_api.h index cdbb2db617..2ac01ea2eb 100644 --- a/components/bt/bluedroid/stack/include/stack/btm_ble_api.h +++ b/components/bt/bluedroid/stack/include/stack/btm_ble_api.h @@ -2099,6 +2099,19 @@ tBTM_STATUS BTM_SetBleDataLength(BD_ADDR bd_addr, UINT16 tx_pdu_length); *******************************************************************************/ tBTM_STATUS BTM_UpdateBleDuplicateExceptionalList(uint8_t subcode, uint32_t type, BD_ADDR device_info, tBTM_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_CMPL_CBACK update_exceptional_list_cmp_cb); + +/******************************************************************************* +** +** Function BTM_GetCurrentConnParams +** +** Description This function is called to read the current connection parameters +** of the device +** +** Returns TRUE or FALSE +** +*******************************************************************************/ + +BOOLEAN BTM_GetCurrentConnParams(BD_ADDR bda, uint16_t *interval, uint16_t *latency, uint16_t *timeout); /* #ifdef __cplusplus } From 8f2490cc6f611c6de4a03e44e10913a9fe8a12c7 Mon Sep 17 00:00:00 2001 From: zhiweijian Date: Wed, 8 May 2019 17:20:56 +0800 Subject: [PATCH 061/486] Component/bt: add svc_inst_id param for create service table event - add svc_inst_id param for create service table event - Closes https://github.com/espressif/esp-idf/issues/3256 --- components/bt/bluedroid/api/include/api/esp_gatts_api.h | 1 + components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/components/bt/bluedroid/api/include/api/esp_gatts_api.h b/components/bt/bluedroid/api/include/api/esp_gatts_api.h index 97296b1c7a..ca2201497c 100644 --- a/components/bt/bluedroid/api/include/api/esp_gatts_api.h +++ b/components/bt/bluedroid/api/include/api/esp_gatts_api.h @@ -255,6 +255,7 @@ typedef union { struct gatts_add_attr_tab_evt_param{ esp_gatt_status_t status; /*!< Operation status */ esp_bt_uuid_t svc_uuid; /*!< Service uuid type */ + uint8_t svc_inst_id; /*!< Service id */ uint16_t num_handle; /*!< The number of the attribute handle to be added to the gatts database */ uint16_t *handles; /*!< The number to the handles */ } add_attr_tab; /*!< Gatt server callback param of ESP_GATTS_CREAT_ATTR_TAB_EVT */ diff --git a/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c b/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c index eff4d41a1e..8ea7e21e4a 100644 --- a/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c +++ b/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c @@ -425,6 +425,8 @@ static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db, param.add_attr_tab.handles = btc_creat_tab_env.handles; memcpy(¶m.add_attr_tab.svc_uuid, &btc_creat_tab_env.svc_uuid, sizeof(esp_bt_uuid_t)); + param.add_attr_tab.svc_inst_id = srvc_inst_id; + btc_gatts_cb_to_app(ESP_GATTS_CREAT_ATTR_TAB_EVT, gatts_if, ¶m); //reset the env after sent the data to app memset(&btc_creat_tab_env, 0, sizeof(esp_btc_creat_tab_t)); From 483e82caf8bc50e2661773589b38080e4bd17bb7 Mon Sep 17 00:00:00 2001 From: zhiweijian Date: Fri, 26 Apr 2019 16:11:53 +0800 Subject: [PATCH 062/486] Component/bt: modify some logs level --- components/bt/bluedroid/hci/hci_hal_h4.c | 2 +- components/bt/bluedroid/stack/l2cap/l2c_ble.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/bt/bluedroid/hci/hci_hal_h4.c b/components/bt/bluedroid/hci/hci_hal_h4.c index 89fba87b5d..264d1cc3de 100644 --- a/components/bt/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/bluedroid/hci/hci_hal_h4.c @@ -321,7 +321,7 @@ static void hci_hal_h4_hdl_rx_packet(BT_HDR *packet) #if SCAN_QUEUE_CONGEST_CHECK if(BTU_check_queue_is_congest() && host_recv_adv_packet(packet)) { - HCI_TRACE_ERROR("BtuQueue is congested"); + HCI_TRACE_DEBUG("BtuQueue is congested"); osi_free(packet); return; } diff --git a/components/bt/bluedroid/stack/l2cap/l2c_ble.c b/components/bt/bluedroid/stack/l2cap/l2c_ble.c index 9a26969fac..c64994a80a 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_ble.c +++ b/components/bt/bluedroid/stack/l2cap/l2c_ble.c @@ -353,7 +353,7 @@ void l2cble_scanner_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE type, (conn_interval > p_dev_rec->conn_params.max_conn_int) || (conn_latency > p_dev_rec->conn_params.slave_latency) || (conn_timeout > p_dev_rec->conn_params.supervision_tout))) { - L2CAP_TRACE_ERROR ("upd_ll_conn_params: HANDLE=%d min_conn_int=%d max_conn_int=%d slave_latency=%d supervision_tout=%d", + L2CAP_TRACE_WARNING ("upd_ll_conn_params: HANDLE=%d min_conn_int=%d max_conn_int=%d slave_latency=%d supervision_tout=%d", handle, p_dev_rec->conn_params.min_conn_int, p_dev_rec->conn_params.max_conn_int, p_dev_rec->conn_params.slave_latency, p_dev_rec->conn_params.supervision_tout); From 4d8a46b3767ed3f0079c4d00c694d326502856c0 Mon Sep 17 00:00:00 2001 From: zhiweijian Date: Fri, 26 Apr 2019 17:24:34 +0800 Subject: [PATCH 063/486] component/bt: add readme doc for BLE demos - Closes:https://github.com/espressif/esp-idf/issues/3341 --- .../bluedroid/api/include/api/esp_gatt_defs.h | 5 + .../bt/bluedroid/stack/btm/btm_ble_gap.c | 7 +- .../bt/bluedroid/stack/hcic/hciblecmds.c | 2 + components/bt/include/esp_bt.h | 1 - docs/en/api-guides/blufi.rst | 270 +++++++++--------- docs/zh_CN/api-guides/blufi.rst | 74 +++-- .../ble_compatibility_test/README.md | 16 ++ .../ble_spp_client/main/spp_client_demo.c | 32 ++- examples/bluetooth/blufi/README.md | 16 +- .../bluetooth/gatt_server/main/gatts_demo.c | 6 +- 10 files changed, 229 insertions(+), 200 deletions(-) create mode 100644 examples/bluetooth/ble_compatibility_test/README.md diff --git a/components/bt/bluedroid/api/include/api/esp_gatt_defs.h b/components/bt/bluedroid/api/include/api/esp_gatt_defs.h index d6c140a140..3e51c0138d 100644 --- a/components/bt/bluedroid/api/include/api/esp_gatt_defs.h +++ b/components/bt/bluedroid/api/include/api/esp_gatt_defs.h @@ -50,11 +50,16 @@ extern "C" { #define ESP_GATT_UUID_HID_SVC 0x1812 /* HID Service*/ #define ESP_GATT_UUID_SCAN_PARAMETERS_SVC 0x1813 /* Scan Parameters Service*/ #define ESP_GATT_UUID_RUNNING_SPEED_CADENCE_SVC 0x1814 /* Running Speed and Cadence Service*/ +#define ESP_GATT_UUID_Automation_IO_SVC 0x1815 /* Automation IO Service*/ #define ESP_GATT_UUID_CYCLING_SPEED_CADENCE_SVC 0x1816 /* Cycling Speed and Cadence Service*/ #define ESP_GATT_UUID_CYCLING_POWER_SVC 0x1818 /* Cycling Power Service*/ #define ESP_GATT_UUID_LOCATION_AND_NAVIGATION_SVC 0x1819 /* Location and Navigation Service*/ +#define ESP_GATT_UUID_ENVIRONMENTAL_SENSING_SVC OX181A /* Environmental Sensing Service*/ +#define ESP_GATT_UUID_BODY_COMPOSITION 0x181B /* Body Composition Service*/ #define ESP_GATT_UUID_USER_DATA_SVC 0x181C /* User Data Service*/ #define ESP_GATT_UUID_WEIGHT_SCALE_SVC 0x181D /* Weight Scale Service*/ +#define ESP_GATT_UUID_BOND_MANAGEMENT_SVC 0x181E /* Bond Management Service*/ +#define ESP_GATT_UUID_CONT_GLUCOSE_MONITOR_SVC 0x181F /* Continuous Glucose Monitoring Service*/ #define ESP_GATT_UUID_PRI_SERVICE 0x2800 #define ESP_GATT_UUID_SEC_SERVICE 0x2801 diff --git a/components/bt/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/bluedroid/stack/btm/btm_ble_gap.c index fff66affa8..10a97bfb54 100644 --- a/components/bt/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/bluedroid/stack/btm/btm_ble_gap.c @@ -1654,6 +1654,10 @@ tBTM_STATUS BTM_BleWriteScanRsp(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p osi_mutex_lock(&adv_data_lock, OSI_MUTEX_MAX_TIMEOUT); memset(rsp_data, 0, BTM_BLE_AD_DATA_LEN); btm_ble_build_adv_data(&data_mask, &p, p_data); + if (data_mask != 0) { + //data length should not exceed 31 bytes + BTM_TRACE_WARNING("%s, Partial data write into ADV", __func__); + } if (btsnd_hcic_ble_set_scan_rsp_data((UINT8)(p - rsp_data), rsp_data)) { osi_sem_take(&adv_data_sem, OSI_SEM_MAX_TIMEOUT); @@ -1798,7 +1802,8 @@ tBTM_STATUS BTM_BleWriteAdvData(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p p_cb_data->p_pad = p; if (mask != 0) { - BTM_TRACE_DEBUG("Partial data write into ADV"); + //data length should not exceed 31 bytes + BTM_TRACE_WARNING("%s, Partial data write into ADV", __func__); } p_cb_data->data_mask &= ~mask; diff --git a/components/bt/bluedroid/stack/hcic/hciblecmds.c b/components/bt/bluedroid/stack/hcic/hciblecmds.c index 87785749b2..1d814cc8d0 100644 --- a/components/bt/bluedroid/stack/hcic/hciblecmds.c +++ b/components/bt/bluedroid/stack/hcic/hciblecmds.c @@ -160,6 +160,7 @@ BOOLEAN btsnd_hcic_ble_set_adv_data (UINT8 data_len, UINT8 *p_data) if (p_data != NULL && data_len > 0) { if (data_len > HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA) { data_len = HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA; + HCI_TRACE_WARNING("Data length exceeds 31 bytes, only the first 31 bytes are used.\n"); } UINT8_TO_STREAM (pp, data_len); @@ -193,6 +194,7 @@ BOOLEAN btsnd_hcic_ble_set_scan_rsp_data (UINT8 data_len, UINT8 *p_scan_rsp) if (data_len > HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP ) { data_len = HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP; + HCI_TRACE_WARNING("Data length exceeds 31 bytes, only the first 31 bytes are used.\n"); } UINT8_TO_STREAM (pp, data_len); diff --git a/components/bt/include/esp_bt.h b/components/bt/include/esp_bt.h index 1157843218..2e331b2e6f 100644 --- a/components/bt/include/esp_bt.h +++ b/components/bt/include/esp_bt.h @@ -304,7 +304,6 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg); * @brief De-initialize BT controller to free resource and delete task. * * This function should be called only once, after any other BT functions are called. - * This function is not whole completed, esp_bt_controller_init cannot called after this function. * @return ESP_OK - success, other - failed */ esp_err_t esp_bt_controller_deinit(void); diff --git a/docs/en/api-guides/blufi.rst b/docs/en/api-guides/blufi.rst index 61b8a03dfa..97b04dff2c 100644 --- a/docs/en/api-guides/blufi.rst +++ b/docs/en/api-guides/blufi.rst @@ -145,15 +145,15 @@ The format of Ack Frame(8 bit): * The data frame supports to be encrypted and verified. - **1.1 Control Frame (0x0b’00)** + **1.1 Control Frame (0x0 b’00)** +-------------------------+--------------------------------------------------------------+---------------------------------------------------------------+---------------------------------------------------------------+ - | Control Frame / 0x0b’00 | Implication | Explanation | Note | + | Control Frame (Binary) | Implication | Explanation | Note | +=========================+==============================================================+===============================================================+===============================================================+ - | 0x0b’000000 | Ack | The data field of the Ack frame uses the same | The data field consumes a byte and its value is | + | 0x0 (b’000000) | Ack | The data field of the Ack frame uses the same | The data field consumes a byte and its value is | | | | sequence value of the frame to reply to. | the same as the sequence field of the frame to reply to. | +-------------------------+--------------------------------------------------------------+---------------------------------------------------------------+---------------------------------------------------------------+ - | 0x1b’000001 | Set ESP32 to the security mode. | To inform ESP32 of the security mode to use | The data field consumes a byte. | + | 0x1 (b’000001) | Set ESP32 to the security mode. | To inform ESP32 of the security mode to use | The data field consumes a byte. | | | | when sending data, which is allowed to be reset | The higher 4 bits are for the security mode setting | | | | multiple times during the process. | of the control frame, and the lower 4 bits are for | | | | Each setting affects the subsequent security mode used. | the security mode setting of the data frame. | @@ -166,7 +166,7 @@ The format of Ack Frame(8 bit): + + + +---------------------------------------------------------------+ | | | | b’0011: with both checksum and encryption. | +-------------------------+--------------------------------------------------------------+---------------------------------------------------------------+---------------------------------------------------------------+ - | 0x2b’000010 | Set the opmode of Wi-Fi. | The frame contains opmode settings for | data[0] is for opmode settings, including: | + | 0x2 (b’000010) | Set the opmode of Wi-Fi. | The frame contains opmode settings for | data[0] is for opmode settings, including: | + + + configuring for the Wi-Fi mode of ESP32. +---------------------------------------------------------------+ | | | | 0x00: NULL; | + + + +---------------------------------------------------------------+ @@ -179,12 +179,12 @@ The format of Ack Frame(8 bit): | | | | Please set the SSID/Password/Max Connection Number of | | | | | the AP mode in the first place if an AP gets involved. | +-------------------------+--------------------------------------------------------------+---------------------------------------------------------------+---------------------------------------------------------------+ - | 0x3b’000011 | Connect ESP32 to the AP. | To notify ESP32 that the essential information has been sent | No data field is contained. | + | 0x3 (b’000011) | Connect ESP32 to the AP. | To notify ESP32 that the essential information has been sent | No data field is contained. | | | | and it is allowed to connect to the AP. | | +-------------------------+--------------------------------------------------------------+---------------------------------------------------------------+---------------------------------------------------------------+ - | 0x4b’000100 | Disconnect ESP32 from the AP. | | No data field is contained. | + | 0x4 (b’000100) | Disconnect ESP32 from the AP. | | No data field is contained. | +-------------------------+--------------------------------------------------------------+---------------------------------------------------------------+---------------------------------------------------------------+ - | 0x5b’000101 | To get the information of ESP32’s Wi-Fi mode and its status. | | No data field is contained. | + | 0x5 (b’000101) | To get the information of ESP32’s Wi-Fi mode and its status. | | No data field is contained. | | | | | When receiving this control frame, ESP32 will send back | | | | | a follow-up frame of Wi-Fi connection state report to | | | | | the mobile phone with the information of the current opmode, | @@ -192,142 +192,142 @@ The format of Ack Frame(8 bit): | | | | The types of information sent to the mobile phone is | | | | | defined by the application installed on the phone. | +-------------------------+--------------------------------------------------------------+---------------------------------------------------------------+---------------------------------------------------------------+ - | 0x6b’000110 | Disconnect the STA device from the SoftAP (in SoftAP mode). | | Date[0~5] is taken as the MAC address for the STA device. | + | 0x6 (b’000110) | Disconnect the STA device from the SoftAP (in SoftAP mode). | | Date[0~5] is taken as the MAC address for the STA device. | | | | | If there is a second STA device, then it uses data[6-11] | | | | | and the rest can be done in the same manner. | +-------------------------+--------------------------------------------------------------+---------------------------------------------------------------+---------------------------------------------------------------+ - | 0x7b'000111 | Get the version information. | | | + | 0x7 (b'000111) | Get the version information. | | | +-------------------------+--------------------------------------------------------------+---------------------------------------------------------------+---------------------------------------------------------------+ - | 0x8b’001000 | Disconnect the BLE GATT link. | | ESP32 will disconnect the BLE GATT link | + | 0x8 (b’001000) | Disconnect the BLE GATT link. | | ESP32 will disconnect the BLE GATT link | | | | | after receives this command. | +-------------------------+--------------------------------------------------------------+---------------------------------------------------------------+---------------------------------------------------------------+ - | 0x9b’001001 | Get the Wi-Fi list. | To get ESP32 to scan the Wi-Fi access points around. | No data field is contained. | + | 0x9 (b’001001) | Get the Wi-Fi list. | To get ESP32 to scan the Wi-Fi access points around. | No data field is contained. | | | | | When receiving this control frame, | | | | | ESP32 will send back a follow-up frame of Wi-Fi list | | | | | report to the mobile phone. | +-------------------------+--------------------------------------------------------------+---------------------------------------------------------------+---------------------------------------------------------------+ - **1.2 Data Frame (0x1b’01)** + **1.2 Data Frame (0x1 b’01)** - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ - | Data Frame | Implication | Explanation | Note | - +==============+====================================================+===============================================================+=======================================================================+ - | 0x0b’000000 | Send the negotiation data. | The negotiation data will be sent to the callback | The length of the data depends on the length field. | - | | | function registered in the application layer. | | - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ - | 0x1b’000001 | Send the BSSID for STA mode. | To send the BSSID of the AP for the STA device to | The length of the data depends on the length field. | - | | | connect under the condition that the SSID is hidden. | When the transmission direction is ESP32 to the mobile phone, | - | | | | it means to provide the mobile phone with the needed information. | - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ - | 0x2b’000010 | Send the SSID for STA mode. | To send the SSID of the AP for the STA device to connect. | The length of the data depends on the length field. | - | | | | When the transmission direction is ESP32 to the mobile phone, | - | | | | it means to provide the mobile phone with the needed information. | - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ - | 0x3b’000011 | Send the password for STA mode. | To send the password of the AP for the STA device to connect. | The length of the data depends on the length field. | - | | | | When the transmission direction is ESP32 to the mobile phone, | - | | | | it means to provide the mobile phone with the needed information. | - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ - | 0x4b’000100 | Send the SSID for SoftAP mode. | | The length of the data depends on the length field. | - | | | | When the transmission direction is ESP32 to the mobile phone, | - | | | | it means to provide the mobile phone with the needed information. | - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ - | 0x5b’000101 | Send the password for SoftAPmode. | | The length of the data depends on the length field. | - | | | | When the transmission direction is ESP32 to the mobile phone, | - | | | | it means to provide the mobile phone with the needed information. | - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ - | 0x6b’000110 | Set the maximum connection number for SoftAP mode. | | data[0] represents the value of the connection number, | - | | | | ranging from 1 to 4. When the transmission direction is ESP32 | - | | | | to the mobile phone, it means to provide the mobile phone with | - | | | | the needed information. | - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ - | 0x7b’000111 | Set the authentication mode for the SoftAP. | | data[0]: | - + + + +-----------------------------------------------------------------------+ - | | | | 0x00: OPEN | - + + + +-----------------------------------------------------------------------+ - | | | | 0x01: WEP | - + + + +-----------------------------------------------------------------------+ - | | | | 0x02: WPA_PSK | - + + + +-----------------------------------------------------------------------+ - | | | | 0x03: WPA2_PSK | - + + + +-----------------------------------------------------------------------+ - | | | | 0x04: WPA_WPA2_PSK | - + + + +-----------------------------------------------------------------------+ - | | | | When the transmission direction is ESP32 to the mobile phone, | - | | | | it means to provide the mobile phone with the needed information. | - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ - | 0x8b’001000 | Set the channel amount for SoftAP mode. | | data[0] represents the quantity of the supported channels, | - | | | | ranging from 1 to 14. | - | | | | When the transmission direction is ESP32 to the mobile phone, | - | | | | it means to provide the mobile phone with the needed information. | - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ - | 0x9b’001001 | Username | It provides the username of the GATT client when using | The length of the data depends on the length field. | - | | | encryption of enterprise level. | | - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ - | 0xab’001010 | CA Certification | It provides the CA Certification when using encryption | The length of the data depends on the length field. | - | | | of enterprise level. | The frame supports to be fragmented if the data length is not enough. | - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ - | 0xbb’001011 | Client Certification | It provides the client certification when | The length of the data depends on the length field. | - | | | using encryption of enterprise level. | The frame supports to be fragmented if the data length is not enough. | - | | | Whether the private key is contained or not | | - | | | depends on the content of the certification. | | - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ - | 0xcb’001100 | Server Certification | It provides the sever certification when using | The length of the data depends on the length field. | - | | | encryption of enterprise level. Whether the private key is | The frame supports to be fragmented if the data length is not enough. | - | | | contained or not depends on the content of the certification. | | - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ - | 0xdb’001101 | ClientPrivate Key | It provides the private key of the client when | The length of the data depends on the length field. | - | | | using encryption of enterprise level. | The frame supports to be fragmented if the data length is not enough. | - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ - | 0xeb’001110 | ServerPrivate Key | It provides the private key of the sever when | The length of the data depends on the length field. | - | | | using encryption of enterprise level. | The frame supports to be fragmented if the data length is not enough. | - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ - | 0xfb’001111 | Wi-Fi Connection State Report | To notify the phone of the ESP32's Wi-Fi status, | data[0] represents opmode, including: | - + + + including STA status and SoftAP status. +-----------------------------------------------------------------------+ - | | | It is for the STA device to connect to the | 0x00: NULL | - + + + mobile phone or the SoftAP. +-----------------------------------------------------------------------+ - | | | However, when the mobile phone receives the Wi-Fi status, | 0x01: STA | - + + + it can reply to other frames in addition to this frame. +-----------------------------------------------------------------------+ - | | | | 0x02: SoftAP | - + + + +-----------------------------------------------------------------------+ - | | | | 0x03: SoftAP&STA | - + + + +-----------------------------------------------------------------------+ - | | | | data[1]:the connection state of the STA device, | - | | | | 0x0 indicates a connection state, | - | | | | and others represent a disconnected state; | - + + + +-----------------------------------------------------------------------+ - | | | | data[2]:the connection state of the SoftAP, | - | | | | that is, how many STA devices have been connected. | - + + + +-----------------------------------------------------------------------+ - | | | | data[3] and the subsequent is in accordance with the | - | | | | format of SSID/BSSID information. | - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ - | 0x10b’010000 | Version | | data[0]= great versiondata[1]= sub version | - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ - | 0x11B’010001 | Wi-Fi List | To send the Wi-Fi list to ESP32. | The format of the data frame is length + RSSI + SSID | - | | | | and it supports to be sent into fragments | - | | | | if the data length is too long. | - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ - | 0x12B’010010 | Report Error | To notify the mobile phone that there is an error with BluFi. | 0x00: sequence error | - + + + +-----------------------------------------------------------------------+ - | | | | 0x01: checksum error | - + + + +-----------------------------------------------------------------------+ - | | | | 0x02: decrypt error | - + + + +-----------------------------------------------------------------------+ - | | | | 0x03: encrypt error | - + + + +-----------------------------------------------------------------------+ - | | | | 0x04: init security error | - + + + +-----------------------------------------------------------------------+ - | | | | 0x05: dh malloc error | - + + + +-----------------------------------------------------------------------+ - | | | | 0x06: dh param error | - + + + +-----------------------------------------------------------------------+ - | | | | 0x07: read param error | - + + + +-----------------------------------------------------------------------+ - | | | | 0x08: make public error | - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ - | 0x13B’010011 | Custom Data | To send or receive custom data. | The data frame supports to be sent into | - | | | | fragments if the data length is too long. | - +--------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + |Data Frame(Binary)| Implication | Explanation | Note | + +==================+====================================================+===============================================================+=======================================================================+ + | 0x0 (b’000000) | Send the negotiation data. | The negotiation data will be sent to the callback | The length of the data depends on the length field. | + | | | function registered in the application layer. | | + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + | 0x1 (b’000001) | Send the BSSID for STA mode. | To send the BSSID of the AP for the STA device to | The length of the data depends on the length field. | + | | | connect under the condition that the SSID is hidden. | When the transmission direction is ESP32 to the mobile phone, | + | | | | it means to provide the mobile phone with the needed information. | + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + | 0x2 (b’000010) | Send the SSID for STA mode. | To send the SSID of the AP for the STA device to connect. | The length of the data depends on the length field. | + | | | | When the transmission direction is ESP32 to the mobile phone, | + | | | | it means to provide the mobile phone with the needed information. | + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + | 0x3 (b’000011) | Send the password for STA mode. | To send the password of the AP for the STA device to connect. | The length of the data depends on the length field. | + | | | | When the transmission direction is ESP32 to the mobile phone, | + | | | | it means to provide the mobile phone with the needed information. | + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + | 0x4 (b’000100) | Send the SSID for SoftAP mode. | | The length of the data depends on the length field. | + | | | | When the transmission direction is ESP32 to the mobile phone, | + | | | | it means to provide the mobile phone with the needed information. | + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + | 0x5 (b’000101) | Send the password for SoftAPmode. | | The length of the data depends on the length field. | + | | | | When the transmission direction is ESP32 to the mobile phone, | + | | | | it means to provide the mobile phone with the needed information. | + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + | 0x6 (b’000110) | Set the maximum connection number for SoftAP mode. | | data[0] represents the value of the connection number, | + | | | | ranging from 1 to 4. When the transmission direction is ESP32 | + | | | | to the mobile phone, it means to provide the mobile phone with | + | | | | the needed information. | + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + | 0x7 (b’000111) | Set the authentication mode for the SoftAP. | | data[0]: | + + + + +-----------------------------------------------------------------------+ + | | | | 0x00: OPEN | + + + + +-----------------------------------------------------------------------+ + | | | | 0x01: WEP | + + + + +-----------------------------------------------------------------------+ + | | | | 0x02: WPA_PSK | + + + + +-----------------------------------------------------------------------+ + | | | | 0x03: WPA2_PSK | + + + + +-----------------------------------------------------------------------+ + | | | | 0x04: WPA_WPA2_PSK | + + + + +-----------------------------------------------------------------------+ + | | | | When the transmission direction is ESP32 to the mobile phone, | + | | | | it means to provide the mobile phone with the needed information. | + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + | 0x8 (b’001000) | Set the channel amount for SoftAP mode. | | data[0] represents the quantity of the supported channels, | + | | | | ranging from 1 to 14. | + | | | | When the transmission direction is ESP32 to the mobile phone, | + | | | | it means to provide the mobile phone with the needed information. | + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + | 0x9 (b’001001) | Username | It provides the username of the GATT client when using | The length of the data depends on the length field. | + | | | encryption of enterprise level. | | + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + | 0xa (b’001010) | CA Certification | It provides the CA Certification when using encryption | The length of the data depends on the length field. | + | | | of enterprise level. | The frame supports to be fragmented if the data length is not enough. | + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + | 0xb (b’001011) | Client Certification | It provides the client certification when | The length of the data depends on the length field. | + | | | using encryption of enterprise level. | The frame supports to be fragmented if the data length is not enough. | + | | | Whether the private key is contained or not | | + | | | depends on the content of the certification. | | + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + | 0xc (b’001100) | Server Certification | It provides the sever certification when using | The length of the data depends on the length field. | + | | | encryption of enterprise level. Whether the private key is | The frame supports to be fragmented if the data length is not enough. | + | | | contained or not depends on the content of the certification. | | + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + | 0xd (b’001101) | ClientPrivate Key | It provides the private key of the client when | The length of the data depends on the length field. | + | | | using encryption of enterprise level. | The frame supports to be fragmented if the data length is not enough. | + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + | 0xe (b’001110) | ServerPrivate Key | It provides the private key of the sever when | The length of the data depends on the length field. | + | | | using encryption of enterprise level. | The frame supports to be fragmented if the data length is not enough. | + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + | 0xf (b’001111) | Wi-Fi Connection State Report | To notify the phone of the ESP32's Wi-Fi status, | data[0] represents opmode, including: | + + + + including STA status and SoftAP status. +-----------------------------------------------------------------------+ + | | | It is for the STA device to connect to the | 0x00: NULL | + + + + mobile phone or the SoftAP. +-----------------------------------------------------------------------+ + | | | However, when the mobile phone receives the Wi-Fi status, | 0x01: STA | + + + + it can reply to other frames in addition to this frame. +-----------------------------------------------------------------------+ + | | | | 0x02: SoftAP | + + + + +-----------------------------------------------------------------------+ + | | | | 0x03: SoftAP&STA | + + + + +-----------------------------------------------------------------------+ + | | | | data[1]:the connection state of the STA device, | + | | | | 0x0 indicates a connection state, | + | | | | and others represent a disconnected state; | + + + + +-----------------------------------------------------------------------+ + | | | | data[2]:the connection state of the SoftAP, | + | | | | that is, how many STA devices have been connected. | + + + + +-----------------------------------------------------------------------+ + | | | | data[3] and the subsequent is in accordance with the | + | | | | format of SSID/BSSID information. | + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + | 0x10 (b’010000) | Version | | data[0]= great versiondata[1]= sub version | + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + | 0x11 (b’010001) | Wi-Fi List | To send the Wi-Fi list to ESP32. | The format of the data frame is length + RSSI + SSID | + | | | | and it supports to be sent into fragments | + | | | | if the data length is too long. | + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + | 0x12 (b’010010) | Report Error | To notify the mobile phone that there is an error with BluFi. | 0x00: sequence error | + + + + +-----------------------------------------------------------------------+ + | | | | 0x01: checksum error | + + + + +-----------------------------------------------------------------------+ + | | | | 0x02: decrypt error | + + + + +-----------------------------------------------------------------------+ + | | | | 0x03: encrypt error | + + + + +-----------------------------------------------------------------------+ + | | | | 0x04: init security error | + + + + +-----------------------------------------------------------------------+ + | | | | 0x05: dh malloc error | + + + + +-----------------------------------------------------------------------+ + | | | | 0x06: dh param error | + + + + +-----------------------------------------------------------------------+ + | | | | 0x07: read param error | + + + + +-----------------------------------------------------------------------+ + | | | | 0x08: make public error | + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ + | 0x13 (b’010011) | Custom Data | To send or receive custom data. | The data frame supports to be sent into | + | | | | fragments if the data length is too long. | + +------------------+----------------------------------------------------+---------------------------------------------------------------+-----------------------------------------------------------------------+ 2. Frame Control @@ -453,9 +453,3 @@ BluFi Service UUID: 0xFFFF,16 bit BluFi (the mobile -> ESP32): 0xFF01, writable Blufi (ESP32 -> the mobile phone): 0xFF02, readable and callable - -.. note:: - - 1. The Ack mechanism is already defined in the profile, but there is no implementation based on the code for the time being. - - 2. Other parts have been implemented. \ No newline at end of file diff --git a/docs/zh_CN/api-guides/blufi.rst b/docs/zh_CN/api-guides/blufi.rst index 667aca7514..6b15a98731 100644 --- a/docs/zh_CN/api-guides/blufi.rst +++ b/docs/zh_CN/api-guides/blufi.rst @@ -149,15 +149,15 @@ Ack 帧格式(8 bit): * 数据帧,可加密,可校验。 - **1.1 控制帧 (0x0b’00)** + **1.1 控制帧 (0x0 b’00)** +------------------+-----------------------------------+----------------------------------------------------------------+----------------------------------------------------------------------+ - | 控制帧 / 0x0b’00 | 含义 | 解释 | 备注 | + | 控制帧 (二进制) | 含义 | 解释 | 备注 | +==================+===================================+================================================================+======================================================================+ - | 0x0b’000000 | Ack | 用来回复对方发的帧, | Data 域使用1 byte Sequence 值, | + | 0x0 (b’000000) | Ack | 用来回复对方发的帧, | Data 域使用1 byte Sequence 值, | | | | Ack 帧的 Data 域使用回复对象帧的 Sequence 值。 | 与恢复对象帧的Sequence 值相同。 | +------------------+-----------------------------------+----------------------------------------------------------------+----------------------------------------------------------------------+ - | 0x1b’000001 | Set ESP32 to the security mode. | 通知 ESP32 发送数据时使用的安全模式, | Data 域占用 1 byte。 | + | 0x1 (b’000001) | Set ESP32 to the security mode. | 通知 ESP32 发送数据时使用的安全模式, | Data 域占用 1 byte。 | | | | 在该过程中可设置多次,每次设置后影响后续安全模式。 | 高 4 bit 为控制帧的安全模式,低 4bit 为数据帧的安全模式。 | + + + 在不设置的情况下,ESP32 默认控制帧和数据帧均为无校验、无加密。 +----------------------------------------------------------------------+ | | | 手机到 ESP32 方向依赖于帧 Control 域。 | b’0000:无校验、无加密; | @@ -168,7 +168,7 @@ Ack 帧格式(8 bit): + + + +----------------------------------------------------------------------+ | | | | b’0011:有校验、有加密。 | +------------------+-----------------------------------+----------------------------------------------------------------+----------------------------------------------------------------------+ - | 0x2b’000010 | Set the Wi-Fi opmode of ESP32. | 设置 ESP32 的 Wi-Fi 模式,帧包含 opmode 信息。 | data[0] 用于表示 opmode 类型,包括: | + | 0x2 (b’000010) | Set the Wi-Fi opmode of ESP32. | 设置 ESP32 的 Wi-Fi 模式,帧包含 opmode 信息。 | data[0] 用于表示 opmode 类型,包括: | + + + +----------------------------------------------------------------------+ | | | | 0x00: NULL; | + + + +----------------------------------------------------------------------+ @@ -181,67 +181,67 @@ Ack 帧格式(8 bit): | | | | 如果设置有包含 AP,请尽量优先 | | | | | 设置 AP 模式的SSID/Password/Max Conn Number 等。 | +------------------+-----------------------------------+----------------------------------------------------------------+----------------------------------------------------------------------+ - | 0x3b’000011 | Connect ESP32 to the AP. | 通知 ESP32,必要的信息已经发送完毕,可以连接 AP。 | 不包含 Data 域。 | + | 0x3 (b’000011) | Connect ESP32 to the AP. | 通知 ESP32,必要的信息已经发送完毕,可以连接 AP。 | 不包含 Data 域。 | +------------------+-----------------------------------+----------------------------------------------------------------+----------------------------------------------------------------------+ - | 0x4b’000100 | Disconnect ESP32 from the AP. | 通知 ESP32 断开与 AP 的连接 | 不包含 Data 域。 | + | 0x4 (b’000100) | Disconnect ESP32 from the AP. | 通知 ESP32 断开与 AP 的连接 | 不包含 Data 域。 | +------------------+-----------------------------------+----------------------------------------------------------------+----------------------------------------------------------------------+ - | 0x5b’000101 | Get the status of Wi-Fi. | 获取 ESP32 的 Wi-Fi 模式和状态等信息。 | 不包含 Data 域。 | + | 0x5 (b’000101) | Get the status of Wi-Fi. | 获取 ESP32 的 Wi-Fi 模式和状态等信息。 | 不包含 Data 域。 | | | | | ESP32 收到此控制帧后,后续会通过 Wi-Fi 连接状态 | | | | | 报告 (Wi-Fi Connection State Report) 数据帧来回复手机端当前 | | | | | 所处的 opmode、连接状态、SSID 等信息。提供给手机端的信息由应用决定。 | +------------------+-----------------------------------+----------------------------------------------------------------+----------------------------------------------------------------------+ - | 0x6b’000110 | Disconnect the STA device | 处于 SoftAP 模式时,踢掉某个 STA 设备。 | data[0~5] 为 STA 设备的 MAC 地址, | + | 0x6 (b’000110) | Disconnect the STA device | 处于 SoftAP 模式时,踢掉某个 STA 设备。 | data[0~5] 为 STA 设备的 MAC 地址, | | | from the SoftAP in SoftAP mode. | | 如有多个 STA,则 [6-11] 为第二个,依次类推。 | +------------------+-----------------------------------+----------------------------------------------------------------+----------------------------------------------------------------------+ - | 0x7b'000111 | Get the version. | | | + | 0x7 (b'000111) | Get the version. | | | +------------------+-----------------------------------+----------------------------------------------------------------+----------------------------------------------------------------------+ - | 0x8b’001000 | Tell ESP32 to disconnect | 通知 ESP32 断开蓝牙连接。 | ESP32 收到该指令后主动断开蓝牙连接。 | + | 0x8 (b’001000) | Tell ESP32 to disconnect | 通知 ESP32 断开蓝牙连接。 | ESP32 收到该指令后主动断开蓝牙连接。 | | | the BLE GATT link. | | | +------------------+-----------------------------------+----------------------------------------------------------------+----------------------------------------------------------------------+ - | 0x9b’001001 | Tell ESP32 to get the Wi-Fi list. | 通知 ESP32 扫描周围的 Wi-Fi 热点 | 不包含 Data 域。 | + | 0x9 (b’001001) | Tell ESP32 to get the Wi-Fi list. | 通知 ESP32 扫描周围的 Wi-Fi 热点 | 不包含 Data 域。 | | | | | ESP32 收到此控制帧后,会发送包含 Wi-Fi 热点 | | | | | 报告 (Wi-Fi List Report) 的数据帧回复 | | | | | 手机端 ESP32 周围的 Wi-Fi 热点。 | +------------------+-----------------------------------+----------------------------------------------------------------+----------------------------------------------------------------------+ - **1.2 数据帧 (0x1b’01)** + **1.2 数据帧 (0x1 b’01)** +---------------+----------------------------------------+------------------------------------------------+------------------------------------------------------+ - | 数据帧 | 含义 | 解释 | 备注 | + |数据帧 (二进制)| 含义 | 解释 | 备注 | +===============+========================================+================================================+======================================================+ - | 0x0 b’000000 | Negotiation data. | 用来发送协商数据,传输到应用层注册的回调函数。 | 数据长度与 Length 域有关。 | + | 0x0 (b’000000)| Negotiation data. | 用来发送协商数据,传输到应用层注册的回调函数。 | 数据长度与 Length 域有关。 | +---------------+----------------------------------------+------------------------------------------------+------------------------------------------------------+ - | 0x1 b’000001 | BSSID for STA mode. | STA 将要连接的 AP 的 BSSID(用于隐藏SSID)。 | 数据长度与 Length 域有关。 | + | 0x1 (b’000001)| BSSID for STA mode. | STA 将要连接的 AP 的 BSSID(用于隐藏SSID)。 | 数据长度与 Length 域有关。 | + + + +------------------------------------------------------+ | | | | 当传输方向为 ESP32 到手机时, | | | | | 表示向手机端提供信息。 | +---------------+----------------------------------------+------------------------------------------------+------------------------------------------------------+ - | 0x2 b’000010 | SSID for STA mode. | STA 将要连接的 AP 的 SSID。 | 数据长度与 Length 域有关。 | + | 0x2 (b’000010)| SSID for STA mode. | STA 将要连接的 AP 的 SSID。 | 数据长度与 Length 域有关。 | + + + +------------------------------------------------------+ | | | | 当传输方向为 ESP32 到手机时, | | | | | 表示向手机端提供信息。 | +---------------+----------------------------------------+------------------------------------------------+------------------------------------------------------+ - | 0x3 b’000011 | Password for STA mode. | STA 将要连接的 AP 的密码。 | 数据长度与 Length 域有关。 | + | 0x3 (b’000011)| Password for STA mode. | STA 将要连接的 AP 的密码。 | 数据长度与 Length 域有关。 | + + + +------------------------------------------------------+ | | | | 当传输方向为 ESP32 到手机时, | | | | | 表示向手机端提供信息。 | +---------------+----------------------------------------+------------------------------------------------+------------------------------------------------------+ - | 0x4 b’000100 | SSID for SoftAP mode. | SoftAP 模式使用的 SSID。 | 数据长度与 Length 域有关。 | + | 0x4 (b’000100)| SSID for SoftAP mode. | SoftAP 模式使用的 SSID。 | 数据长度与 Length 域有关。 | + + + +------------------------------------------------------+ | | | | 当传输方向为 ESP32 到手机时, | | | | | 表示向手机端提供信息。 | +---------------+----------------------------------------+------------------------------------------------+------------------------------------------------------+ - | 0x5 b’000101 | Password for SoftAPmode. | SoftAP 模式使用的密码。 | 数据长度与 Length 域有关。 | + | 0x5 (b’000101)| Password for SoftAPmode. | SoftAP 模式使用的密码。 | 数据长度与 Length 域有关。 | + + + +------------------------------------------------------+ | | | | 当传输方向为 ESP32 到手机时, | | | | | 表示向手机端提供信息。 | +---------------+----------------------------------------+------------------------------------------------+------------------------------------------------------+ - | 0x6 b’000110 | Max connection number for SoftAP mode. | AP 模式的最大连接数。 | data[0] 表示连接数的值,范围 1~4。 | + | 0x6 (b’000110)| Max connection number for SoftAP mode. | AP 模式的最大连接数。 | data[0] 表示连接数的值,范围 1~4。 | + + + +------------------------------------------------------+ | | | | 当传输方向为 ESP32 到手机时, | | | | | 表示向手机端提供信息。 | +---------------+----------------------------------------+------------------------------------------------+------------------------------------------------------+ - | 0x7b’000111 | Authentication mode for SoftAP mode. | AP 模式的认证模式。 | data[0]: | + | 0x7 (b’000111)| Authentication mode for SoftAP mode. | AP 模式的认证模式。 | data[0]: | + + + +------------------------------------------------------+ | | | | 0x00: OPEN; | + + + +------------------------------------------------------+ @@ -256,31 +256,31 @@ Ack 帧格式(8 bit): | | | | 当传输方向为 ESP32 到手机时, | | | | | 表示向手机端提供信息。 | +---------------+----------------------------------------+------------------------------------------------+------------------------------------------------------+ - | 0x8b’001000 | Channel for SoftAP mode. | SoftAP 模式的通道数量。 | data[0] 表示通道的数量,范围 1~14。 | + | 0x8 (b’001000)| Channel for SoftAP mode. | SoftAP 模式的通道数量。 | data[0] 表示通道的数量,范围 1~14。 | + + + +------------------------------------------------------+ | | | | 当传输方向为 ESP32 到手机时, | | | | | 表示向手机端提供信息。 | +---------------+----------------------------------------+------------------------------------------------+------------------------------------------------------+ - | 0x9b’001001 | Username. | 使用企业级加密时,Client 端的用户名。 | 数据长度与 Length 域有关。 | + | 0x9 (b’001001)| Username. | 使用企业级加密时,Client 端的用户名。 | 数据长度与 Length 域有关。 | +---------------+----------------------------------------+------------------------------------------------+------------------------------------------------------+ - | 0xab’001010 | CA certification. | 进行企业级加密时使用的 CA 证书。 | 数据长度与 Length 域有关, | + | 0xa (b’001010)| CA certification. | 进行企业级加密时使用的 CA 证书。 | 数据长度与 Length 域有关, | | | | | 长度不够,可用分片。 | +---------------+----------------------------------------+------------------------------------------------+------------------------------------------------------+ - | 0xbb’001011 | Client certification. | 进行企业级加密时,Client 端的证书。 | 数据长度与 Length 域有关, | + | 0xb (b’001011)| Client certification. | 进行企业级加密时,Client 端的证书。 | 数据长度与 Length 域有关, | + + +------------------------------------------------+ 长度不够,可用分片。 + | | | 可包含或不包含私钥,由证书内容决定。 | | +---------------+----------------------------------------+------------------------------------------------+------------------------------------------------------+ - | 0xcb’001100 | Server certification. | 进行企业级加密时,Server 端的证书。 | 数据长度与 Length 域有关, | + | 0xc (b’001100)| Server certification. | 进行企业级加密时,Server 端的证书。 | 数据长度与 Length 域有关, | + + +------------------------------------------------+ 长度不够,可用分片。 + | | | 可包含或不包含私钥,由证书内容决定。 | | +---------------+----------------------------------------+------------------------------------------------+------------------------------------------------------+ - | 0xdb’001101 | Client private key. | 进行企业级加密时,Client 端的私钥。 | 数据长度与 Length 域有关, | + | 0xd (b’001101)| Client private key. | 进行企业级加密时,Client 端的私钥。 | 数据长度与 Length 域有关, | | | | | 长度不够,可用分片。 | +---------------+----------------------------------------+------------------------------------------------+------------------------------------------------------+ - | 0xeb’001110 | Server private key. | 进行企业级加密时,Server 端的私钥。 | 数据长度与 Length 域有关, | + | 0xe (b’001110)| Server private key. | 进行企业级加密时,Server 端的私钥。 | 数据长度与 Length 域有关, | | | | | 长度不够,可用分片。 | +---------------+----------------------------------------+------------------------------------------------+------------------------------------------------------+ - | 0xf b’001111 | Wi-Fi connection state report. | 通知手机 ESP32 的 Wi-Fi 状态, | data[0] 表示 opmode,包括: | + | 0xf (b’001111)| Wi-Fi connection state report. | 通知手机 ESP32 的 Wi-Fi 状态, | data[0] 表示 opmode,包括: | | | | 包括 STA状态和 SoftAP 状态, | | | | | 用于手机配置 STA 连接时的通知, | | | | | 或有 STA 连接上 SoftAP 时的通知。 | | @@ -306,10 +306,10 @@ Ack 帧格式(8 bit): + + + +------------------------------------------------------+ | | | | data[1]=sub version | +---------------+----------------------------------------+------------------------------------------------+------------------------------------------------------+ - | 0x11 B’010001 | Wi-Fi list. | 通知手机 ESP32 周围的 Wi-Fi 热点列表。 | 数据帧数据格式为 Length + RSSI + SSID, | + |0x11 (b’010001)| Wi-Fi list. | 通知手机 ESP32 周围的 Wi-Fi 热点列表。 | 数据帧数据格式为 Length + RSSI + SSID, | | | | | 数据较长时可分片发送。 | +---------------+----------------------------------------+------------------------------------------------+------------------------------------------------------+ - | 0x12 B’010010 | Report error. | 通知手机 BluFi 过程出现异常错误。 | 0x00: sequence error; | + |0x12 (b’010010)| Report error. | 通知手机 BluFi 过程出现异常错误。 | 0x00: sequence error; | + + + +------------------------------------------------------+ | | | | 0x01: checksum error; | + + + +------------------------------------------------------+ @@ -327,7 +327,7 @@ Ack 帧格式(8 bit): + + + +------------------------------------------------------+ | | | | 0x08: make public error. | +---------------+----------------------------------------+------------------------------------------------+------------------------------------------------------+ - | 0x13 B’010011 | Custom data. | 用户发送或者接收自定义数据。 | 数据较长时可分片发送。 | + |0x13 (b’010011)| Custom data. | 用户发送或者接收自定义数据。 | 数据较长时可分片发送。 | +---------------+----------------------------------------+------------------------------------------------+------------------------------------------------------+ 2. Frame Control @@ -448,10 +448,4 @@ BluFi Service UUID: 0xFFFF,16 bit BluFi (手机 -> ESP32) 特性:0xFF01,主要权限:可写 -BluFi (ESP32 -> 手机) 特性:0xFF02,主要权限:可读可通知 - -.. note:: - - 1. 目前 Ack 机制已经在该 Profile 协议中定义,但是还没有代码实现。 - - 2. 其他部分均已实现。 \ No newline at end of file +BluFi (ESP32 -> 手机) 特性:0xFF02,主要权限:可读可通知 \ No newline at end of file diff --git a/examples/bluetooth/ble_compatibility_test/README.md b/examples/bluetooth/ble_compatibility_test/README.md new file mode 100644 index 0000000000..928a4b6a77 --- /dev/null +++ b/examples/bluetooth/ble_compatibility_test/README.md @@ -0,0 +1,16 @@ +ESP-IDF BLE Compatibility Test Example +======================================= + +This demo is to test the compatibility of Bluetooth and mobile phones. + +* ESP32 Module: ESP-WROOM-32 + +* IDF version: 7c29a39d6f9f2dfbefc49d34d34e9267afc7200d + +* [Test case](https://github.com/espressif/esp-idf/blob/master/examples/bluetooth/ble_compatibility_test/ble_compatibility_test_case.md) + +* Test APK: LightBlue V1.1.3 + +* [Test report](https://github.com/espressif/esp-idf/blob/master/examples/bluetooth/ble_compatibility_test/esp_ble_compatibility_test_report.md) + + diff --git a/examples/bluetooth/ble_spp_client/main/spp_client_demo.c b/examples/bluetooth/ble_spp_client/main/spp_client_demo.c index 03561acb8e..ae3da8e1c6 100644 --- a/examples/bluetooth/ble_spp_client/main/spp_client_demo.c +++ b/examples/bluetooth/ble_spp_client/main/spp_client_demo.c @@ -129,6 +129,10 @@ static void notify_event_handler(esp_ble_gattc_cb_param_t * p_data) ESP_LOGI(GATTC_TAG,"+INDICATE:handle = %d,length = %d ", p_data->notify.handle, p_data->notify.value_len); } handle = p_data->notify.handle; + if(db == NULL) { + ESP_LOGE(GATTC_TAG, " %s db is NULL\n", __func__); + return; + } if(handle == db[SPP_IDX_SPP_DATA_NTY_VAL].attribute_handle){ #ifdef SPP_DEBUG_MODE esp_log_buffer_char(GATTC_TAG, (char *)p_data->notify.value, p_data->notify.value_len); @@ -464,19 +468,21 @@ void spp_client_reg_task(void* arg) for(;;) { vTaskDelay(100 / portTICK_PERIOD_MS); if(xQueueReceive(cmd_reg_queue, &cmd_id, portMAX_DELAY)) { - if(cmd_id == SPP_IDX_SPP_DATA_NTY_VAL){ - ESP_LOGI(GATTC_TAG,"Index = %d,UUID = 0x%04x, handle = %d \n", cmd_id, (db+SPP_IDX_SPP_DATA_NTY_VAL)->uuid.uuid.uuid16, (db+SPP_IDX_SPP_DATA_NTY_VAL)->attribute_handle); - esp_ble_gattc_register_for_notify(spp_gattc_if, gl_profile_tab[PROFILE_APP_ID].remote_bda, (db+SPP_IDX_SPP_DATA_NTY_VAL)->attribute_handle); - }else if(cmd_id == SPP_IDX_SPP_STATUS_VAL){ - ESP_LOGI(GATTC_TAG,"Index = %d,UUID = 0x%04x, handle = %d \n", cmd_id, (db+SPP_IDX_SPP_STATUS_VAL)->uuid.uuid.uuid16, (db+SPP_IDX_SPP_STATUS_VAL)->attribute_handle); - esp_ble_gattc_register_for_notify(spp_gattc_if, gl_profile_tab[PROFILE_APP_ID].remote_bda, (db+SPP_IDX_SPP_STATUS_VAL)->attribute_handle); - } + if(db != NULL) { + if(cmd_id == SPP_IDX_SPP_DATA_NTY_VAL){ + ESP_LOGI(GATTC_TAG,"Index = %d,UUID = 0x%04x, handle = %d \n", cmd_id, (db+SPP_IDX_SPP_DATA_NTY_VAL)->uuid.uuid.uuid16, (db+SPP_IDX_SPP_DATA_NTY_VAL)->attribute_handle); + esp_ble_gattc_register_for_notify(spp_gattc_if, gl_profile_tab[PROFILE_APP_ID].remote_bda, (db+SPP_IDX_SPP_DATA_NTY_VAL)->attribute_handle); + }else if(cmd_id == SPP_IDX_SPP_STATUS_VAL){ + ESP_LOGI(GATTC_TAG,"Index = %d,UUID = 0x%04x, handle = %d \n", cmd_id, (db+SPP_IDX_SPP_STATUS_VAL)->uuid.uuid.uuid16, (db+SPP_IDX_SPP_STATUS_VAL)->attribute_handle); + esp_ble_gattc_register_for_notify(spp_gattc_if, gl_profile_tab[PROFILE_APP_ID].remote_bda, (db+SPP_IDX_SPP_STATUS_VAL)->attribute_handle); + } #ifdef SUPPORT_HEARTBEAT - else if(cmd_id == SPP_IDX_SPP_HEARTBEAT_VAL){ - ESP_LOGI(GATTC_TAG,"Index = %d,UUID = 0x%04x, handle = %d \n", cmd_id, (db+SPP_IDX_SPP_HEARTBEAT_VAL)->uuid.uuid.uuid16, (db+SPP_IDX_SPP_HEARTBEAT_VAL)->attribute_handle); - esp_ble_gattc_register_for_notify(spp_gattc_if, gl_profile_tab[PROFILE_APP_ID].remote_bda, (db+SPP_IDX_SPP_HEARTBEAT_VAL)->attribute_handle); - } + else if(cmd_id == SPP_IDX_SPP_HEARTBEAT_VAL){ + ESP_LOGI(GATTC_TAG,"Index = %d,UUID = 0x%04x, handle = %d \n", cmd_id, (db+SPP_IDX_SPP_HEARTBEAT_VAL)->uuid.uuid.uuid16, (db+SPP_IDX_SPP_HEARTBEAT_VAL)->attribute_handle); + esp_ble_gattc_register_for_notify(spp_gattc_if, gl_profile_tab[PROFILE_APP_ID].remote_bda, (db+SPP_IDX_SPP_HEARTBEAT_VAL)->attribute_handle); + } #endif + } } } } @@ -490,7 +496,7 @@ void spp_heart_beat_task(void * arg) vTaskDelay(50 / portTICK_PERIOD_MS); if(xQueueReceive(cmd_heartbeat_queue, &cmd_id, portMAX_DELAY)) { while(1){ - if((is_connect == true)&&((db+SPP_IDX_SPP_HEARTBEAT_VAL)->properties & (ESP_GATT_CHAR_PROP_BIT_WRITE_NR | ESP_GATT_CHAR_PROP_BIT_WRITE))){ + if((is_connect == true) && (db != NULL) && ((db+SPP_IDX_SPP_HEARTBEAT_VAL)->properties & (ESP_GATT_CHAR_PROP_BIT_WRITE_NR | ESP_GATT_CHAR_PROP_BIT_WRITE))){ esp_ble_gattc_write_char( spp_gattc_if, spp_conn_id, (db+SPP_IDX_SPP_HEARTBEAT_VAL)->attribute_handle, @@ -551,7 +557,7 @@ void uart_task(void *pvParameters) switch (event.type) { //Event of UART receving data case UART_DATA: - if (event.size && (is_connect == true) && ((db+SPP_IDX_SPP_DATA_RECV_VAL)->properties & (ESP_GATT_CHAR_PROP_BIT_WRITE_NR | ESP_GATT_CHAR_PROP_BIT_WRITE))) { + if (event.size && (is_connect == true) && (db != NULL) && ((db+SPP_IDX_SPP_DATA_RECV_VAL)->properties & (ESP_GATT_CHAR_PROP_BIT_WRITE_NR | ESP_GATT_CHAR_PROP_BIT_WRITE))) { uint8_t * temp = NULL; temp = (uint8_t *)malloc(sizeof(uint8_t)*event.size); if(temp == NULL){ diff --git a/examples/bluetooth/blufi/README.md b/examples/bluetooth/blufi/README.md index 3b074c72d9..c8246023ae 100644 --- a/examples/bluetooth/blufi/README.md +++ b/examples/bluetooth/blufi/README.md @@ -3,8 +3,16 @@ ESP-IDF Blufi demo This is the demo for bluetooth config wifi connection to ap. -attentions: - 1. Please use the BLEDEMO APK - 2. As the GATTServer start a litte slowly, so Please Wait for a period, then use apk scan the apk util find a random address devices named Espressif_008 - 3. Just a unstable version.. +To test this demo, you need to prepare a mobile phone with blufi application installed. You can download the blufi application from [Android version](https://github.com/EspressifApp/EspBlufi) and [iOS version](https://itunes.apple.com/cn/app/espblufi/id1450614082?mt=8). +Blufi is completely open source, here is the download link: + +* [blufi source code](https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/blufi) + +* [BluFi protocol](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/blufi.html?highlight=blufi#the-frame-formats-defined-in-blufi) + +* [iOS source code](https://github.com/EspressifApp/EspBlufiForiOS) + +* [Android source code](https://github.com/EspressifApp/EspBlufi) + +* [Bluetooth Network User Guide CN](https://www.espressif.com/sites/default/files/documentation/esp32_bluetooth_networking_user_guide_cn.pdf) \ No newline at end of file diff --git a/examples/bluetooth/gatt_server/main/gatts_demo.c b/examples/bluetooth/gatt_server/main/gatts_demo.c index 789f15fdad..6770d8f862 100644 --- a/examples/bluetooth/gatt_server/main/gatts_demo.c +++ b/examples/bluetooth/gatt_server/main/gatts_demo.c @@ -98,7 +98,7 @@ static uint8_t adv_service_uuid128[32] = { static esp_ble_adv_data_t adv_data = { .set_scan_rsp = false, .include_name = true, - .include_txpower = true, + .include_txpower = false, .min_interval = 0x0006, //slave connection min interval, Time = min_interval * 1.25 msec .max_interval = 0x0010, //slave connection max interval, Time = max_interval * 1.25 msec .appearance = 0x00, @@ -115,8 +115,8 @@ static esp_ble_adv_data_t scan_rsp_data = { .set_scan_rsp = true, .include_name = true, .include_txpower = true, - .min_interval = 0x0006, - .max_interval = 0x0010, + //.min_interval = 0x0006, + //.max_interval = 0x0010, .appearance = 0x00, .manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN, .p_manufacturer_data = NULL, //&test_manufacturer[0], From 0a040345cc9f45d16a6d4d9fb6dc6af21bee377e Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Wed, 12 Jun 2019 19:00:44 +0800 Subject: [PATCH 064/486] mbedtls: Fix Z->s in mbedtls_mpi_exp_mod() Z->s should never be zero, only 1 or -1. Added additional checks for X, Y and M args to correctly set Z->s. Closes: https://github.com/espressif/esp-idf/issues/1681 Closes: https://github.com/espressif/esp-idf/issues/3603 Closes: IDFGH-1313 --- components/mbedtls/port/esp_bignum.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/components/mbedtls/port/esp_bignum.c b/components/mbedtls/port/esp_bignum.c index 843c40d9b6..50e1d9f364 100644 --- a/components/mbedtls/port/esp_bignum.c +++ b/components/mbedtls/port/esp_bignum.c @@ -359,6 +359,18 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi* Z, const mbedtls_mpi* X, const mbedtls_mpi mbedtls_mpi *Rinv; /* points to _Rinv (if not NULL) othwerwise &RR_new */ mbedtls_mpi_uint Mprime; + if (mbedtls_mpi_cmp_int(M, 0) <= 0 || (M->p[0] & 1) == 0) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + if (mbedtls_mpi_cmp_int(Y, 0) < 0) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + if (mbedtls_mpi_cmp_int(Y, 0) == 0) { + return mbedtls_mpi_lset(Z, 1); + } + if (hw_words * 32 > 4096) { return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; } @@ -392,13 +404,24 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi* Z, const mbedtls_mpi* X, const mbedtls_mpi start_op(RSA_START_MODEXP_REG); /* X ^ Y may actually be shorter than M, but unlikely when used for crypto */ - MBEDTLS_MPI_CHK( mbedtls_mpi_grow(Z, m_words) ); + if ((ret = mbedtls_mpi_grow(Z, m_words)) != 0) { + esp_mpi_release_hardware(); + goto cleanup; + } wait_op_complete(RSA_START_MODEXP_REG); mem_block_to_mpi(Z, RSA_MEM_Z_BLOCK_BASE, m_words); esp_mpi_release_hardware(); + // Compensate for negative X + if (X->s == -1 && (Y->p[0] & 1) != 0) { + Z->s = -1; + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(Z, M, Z)); + } else { + Z->s = 1; + } + cleanup: if (_Rinv == NULL) { mbedtls_mpi_free(&Rinv_new); From bc8c8c68ddc8c2f4eeb1ae66bf763554e7aa388b Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Thu, 13 Jun 2019 22:09:50 +0800 Subject: [PATCH 065/486] mbedtls: Add UTs for modexp --- components/mbedtls/test/test_mbedtls_mpi.c | 80 ++++++++++++++++------ 1 file changed, 59 insertions(+), 21 deletions(-) diff --git a/components/mbedtls/test/test_mbedtls_mpi.c b/components/mbedtls/test/test_mbedtls_mpi.c index ade0fdb6b8..084fe34845 100644 --- a/components/mbedtls/test/test_mbedtls_mpi.c +++ b/components/mbedtls/test/test_mbedtls_mpi.c @@ -11,6 +11,7 @@ #include "unity.h" #include "sdkconfig.h" +#define MBEDTLS_OK 0 /* Debugging function to print an MPI number to stdout. Happens to print output that can be copy-pasted directly into a Python shell. @@ -116,11 +117,14 @@ TEST_CASE("test MPI multiplication", "[bignum]") 4096); } -static void test_bignum_modexp(const char *z_str, const char *x_str, const char *y_str, const char *m_str) +static bool test_bignum_modexp(const char *z_str, const char *x_str, const char *y_str, const char *m_str, int ret_error) { mbedtls_mpi Z, X, Y, M; char z_buf[400] = { 0 }; size_t z_buf_len = 0; + bool fail = false; + + printf("%s = (%s ^ %s) mod %s ret=%d ... ", z_str, x_str, y_str, m_str, ret_error); mbedtls_mpi_init(&Z); mbedtls_mpi_init(&X); @@ -136,38 +140,72 @@ static void test_bignum_modexp(const char *z_str, const char *x_str, const char //mbedtls_mpi_printf("M", &M); /* Z = (X ^ Y) mod M */ - TEST_ASSERT_FALSE(mbedtls_mpi_exp_mod(&Z, &X, &Y, &M, NULL)); - - mbedtls_mpi_write_string(&Z, 16, z_buf, sizeof(z_buf)-1, &z_buf_len); - TEST_ASSERT_EQUAL_STRING_MESSAGE(z_str, z_buf, "mbedtls_mpi_exp_mod incorrect"); + if (ret_error != mbedtls_mpi_exp_mod(&Z, &X, &Y, &M, NULL)) { + fail = true; + } + if (ret_error == MBEDTLS_OK) { + mbedtls_mpi_write_string(&Z, 16, z_buf, sizeof(z_buf)-1, &z_buf_len); + if (memcmp(z_str, z_buf, strlen(z_str)) != 0) { + printf("\n Expected '%s' Was '%s' \n", z_str, z_buf); + fail = true; + } + } + mbedtls_mpi_free(&Z); mbedtls_mpi_free(&X); mbedtls_mpi_free(&Y); mbedtls_mpi_free(&M); + + if (fail == true) { + printf(" FAIL\n"); + } else { + printf(" PASS\n"); + } + return fail; } TEST_CASE("test MPI modexp", "[bignum]") { - test_bignum_modexp("01000000", "1000", "2", "FFFFFFFF"); - test_bignum_modexp("014B5A90", "1234", "2", "FFFFFFF"); - test_bignum_modexp("01234321", "1111", "2", "FFFFFFFF"); - test_bignum_modexp("02", "5", "1", "3"); - test_bignum_modexp("22", "55", "1", "33"); - test_bignum_modexp("0222", "555", "1", "333"); - test_bignum_modexp("2222", "5555", "1", "3333"); - test_bignum_modexp("11", "5555", "1", "33"); + bool test_error = false; + printf("Z = (X ^ Y) mod M \n"); + // test_bignum_modexp(Z, X, Y, M, ret_error); + test_error |= test_bignum_modexp("01000000", "1000", "2", "FFFFFFFF", MBEDTLS_OK); + test_error |= test_bignum_modexp("014B5A90", "1234", "2", "FFFFFFF", MBEDTLS_OK); + test_error |= test_bignum_modexp("01234321", "1111", "2", "FFFFFFFF", MBEDTLS_OK); + test_error |= test_bignum_modexp("02", "5", "1", "3", MBEDTLS_OK); + test_error |= test_bignum_modexp("22", "55", "1", "33", MBEDTLS_OK); + test_error |= test_bignum_modexp("0222", "555", "1", "333", MBEDTLS_OK); + test_error |= test_bignum_modexp("2222", "5555", "1", "3333", MBEDTLS_OK); + test_error |= test_bignum_modexp("11", "5555", "1", "33", MBEDTLS_OK); + test_error |= test_bignum_modexp("55", "1111", "1", "77", MBEDTLS_OK); + test_error |= test_bignum_modexp("88", "1111", "2", "BB", MBEDTLS_OK); + test_error |= test_bignum_modexp("01000000", "2", "128", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", MBEDTLS_OK); + test_error |= test_bignum_modexp("0ABCDEF12345", "ABCDEF12345", "1", "FFFFFFFFFFFF", MBEDTLS_OK); + test_error |= test_bignum_modexp("0ABCDE", "ABCDE", "1", "FFFFF", MBEDTLS_OK); - test_bignum_modexp("55", "1111", "1", "77"); - test_bignum_modexp("88", "1111", "2", "BB"); + test_error |= test_bignum_modexp("04", "2", "2", "9", MBEDTLS_OK); + test_error |= test_bignum_modexp("04", "2", "-2", "9", MBEDTLS_ERR_MPI_BAD_INPUT_DATA); + test_error |= test_bignum_modexp("04", "2", "2", "-9", MBEDTLS_ERR_MPI_BAD_INPUT_DATA); + test_error |= test_bignum_modexp("04", "2", "-2", "-9", MBEDTLS_ERR_MPI_BAD_INPUT_DATA); - test_bignum_modexp("01000000", "2", "128", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + test_error |= test_bignum_modexp("01", "2", "0", "9", MBEDTLS_OK); + test_error |= test_bignum_modexp("04", "2", "0", "0", MBEDTLS_ERR_MPI_BAD_INPUT_DATA); + test_error |= test_bignum_modexp("04", "2", "2", "0", MBEDTLS_ERR_MPI_BAD_INPUT_DATA); + test_error |= test_bignum_modexp("00", "0", "2", "9", MBEDTLS_OK); + test_error |= test_bignum_modexp("01", "0", "0", "9", MBEDTLS_OK); - /* failures below here... */ - test_bignum_modexp("0ABCDEF12345", "ABCDEF12345", "1", "FFFFFFFFFFFF"); - test_bignum_modexp("0ABCDE", "ABCDE", "1", "FFFFF"); + test_error |= test_bignum_modexp("04", "-2", "2", "9", MBEDTLS_OK); + test_error |= test_bignum_modexp("01", "-2", "0", "9", MBEDTLS_OK); + test_error |= test_bignum_modexp("07", "-2", "7", "9", MBEDTLS_OK); + test_error |= test_bignum_modexp("07", "-2", "1", "9", MBEDTLS_OK); + test_error |= test_bignum_modexp("02", "2", "1", "9", MBEDTLS_OK); + test_error |= test_bignum_modexp("01", "2", "0", "9", MBEDTLS_OK); - test_bignum_modexp("04", "2", "2", "9"); + test_error |= test_bignum_modexp("05", "5", "7", "7", MBEDTLS_OK); + test_error |= test_bignum_modexp("02", "-5", "7", "7", MBEDTLS_OK); + test_error |= test_bignum_modexp("01", "-5", "7", "3", MBEDTLS_OK); + + TEST_ASSERT_FALSE_MESSAGE(test_error, "mbedtls_mpi_exp_mod incorrect for some tests\n"); } From b107b832caef09f4432e5716bd12bfad0eff04d6 Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Mon, 17 Jun 2019 15:44:25 +0800 Subject: [PATCH 066/486] sntp/lwip: Add SNTP_UPDATE_DELAY option in Kconfig Closes: https://github.com/espressif/esp-idf/issues/2277 Closes: IDFGH-337 --- components/lwip/Kconfig | 31 +++++++++++++------ components/lwip/port/esp32/include/lwipopts.h | 10 ++++++ 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig index 6fa8a507e2..2cca72b2fb 100644 --- a/components/lwip/Kconfig +++ b/components/lwip/Kconfig @@ -84,15 +84,6 @@ menu "LWIP" help Enabling this option allows checking for available data on a netconn. - config LWIP_DHCP_MAX_NTP_SERVERS - int "Maximum number of NTP servers" - default 1 - range 1 16 - help - Set maximum number of NTP servers used by LwIP SNTP module. - First argument of sntp_setserver/sntp_setservername functions - is limited to this value. - config LWIP_IP_FRAG bool "Enable fragment outgoing IP packets" default n @@ -572,4 +563,26 @@ menu "LWIP" endmenu # LWIP RAW API + menu "SNTP" + + config LWIP_DHCP_MAX_NTP_SERVERS + int "Maximum number of NTP servers" + default 1 + range 1 16 + help + Set maximum number of NTP servers used by LwIP SNTP module. + First argument of sntp_setserver/sntp_setservername functions + is limited to this value. + + config LWIP_SNTP_UPDATE_DELAY + int "Request interval to update time (ms)" + range 15000 4294967295 + default 3600000 + help + This option allows you to set the time update period via SNTP. + Default is 1 hour. Must not be below 15 seconds by specification. + (SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds). + + endmenu # SNTP + endmenu diff --git a/components/lwip/port/esp32/include/lwipopts.h b/components/lwip/port/esp32/include/lwipopts.h index fd6e1262f8..713d3ff097 100644 --- a/components/lwip/port/esp32/include/lwipopts.h +++ b/components/lwip/port/esp32/include/lwipopts.h @@ -841,6 +841,16 @@ enum { #define LWIP_DHCP_MAX_NTP_SERVERS CONFIG_LWIP_DHCP_MAX_NTP_SERVERS #define LWIP_TIMEVAL_PRIVATE 0 +/* + -------------------------------------- + ------------ SNTP options ------------ + -------------------------------------- +*/ +/* + * SNTP update delay - in milliseconds + */ +#define SNTP_UPDATE_DELAY CONFIG_LWIP_SNTP_UPDATE_DELAY + #define SNTP_SET_SYSTEM_TIME_US(sec, us) \ do { \ struct timeval tv = { .tv_sec = sec, .tv_usec = us }; \ From c5c716e9d7838b07d2c61e06cda4268919b69f46 Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Wed, 12 Jun 2019 11:52:23 +0800 Subject: [PATCH 067/486] esp_wifi: fix wrong path of phy_init_data Closes https://github.com/espressif/esp-idf/issues/3482 --- components/esp32/Makefile.projbuild | 36 +------------------ components/esp_wifi/CMakeLists.txt | 17 +++++---- components/esp_wifi/Makefile.projbuild | 32 +++++++++++++++++ components/esp_wifi/component.mk | 2 +- .../{ => esp32}/include/phy_init_data.h | 0 docs/en/api-guides/RF_calibration.rst | 2 +- tools/ci/test_build_system.sh | 13 +++++++ tools/ci/test_build_system_cmake.sh | 15 +++++++- 8 files changed, 72 insertions(+), 45 deletions(-) create mode 100644 components/esp_wifi/Makefile.projbuild rename components/esp_wifi/{ => esp32}/include/phy_init_data.h (100%) diff --git a/components/esp32/Makefile.projbuild b/components/esp32/Makefile.projbuild index b99415538e..0ae77a69d2 100644 --- a/components/esp32/Makefile.projbuild +++ b/components/esp32/Makefile.projbuild @@ -1,44 +1,10 @@ -ifdef CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION - -PHY_INIT_DATA_OBJ = $(BUILD_DIR_BASE)/phy_init_data.o -PHY_INIT_DATA_BIN = $(BUILD_DIR_BASE)/phy_init_data.bin - -# Command to flash PHY init data partition -PHY_INIT_DATA_FLASH_CMD = $(ESPTOOLPY_SERIAL) write_flash $(PHY_DATA_OFFSET) $(PHY_INIT_DATA_BIN) -ESPTOOL_ALL_FLASH_ARGS += $(PHY_DATA_OFFSET) $(PHY_INIT_DATA_BIN) - -ESP32_COMPONENT_PATH := $(COMPONENT_PATH) - -$(PHY_INIT_DATA_OBJ): $(ESP32_COMPONENT_PATH)/phy_init_data.h $(BUILD_DIR_BASE)/include/sdkconfig.h - $(summary) CC $(notdir $@) - printf "#include \"phy_init_data.h\"\n" | $(CC) -I $(BUILD_DIR_BASE)/include -I $(ESP32_COMPONENT_PATH) -I $(ESP32_COMPONENT_PATH)/include -c -o $@ -xc - - -$(PHY_INIT_DATA_BIN): $(PHY_INIT_DATA_OBJ) - $(summary) BIN $(notdir $@) - $(OBJCOPY) -O binary $< $@ - -phy_init_data: $(PHY_INIT_DATA_BIN) - -phy_init_data-flash: $(BUILD_DIR_BASE)/phy_init_data.bin - @echo "Flashing PHY init data..." - $(PHY_INIT_DATA_FLASH_CMD) - -phy_init_data-clean: - rm -f $(PHY_INIT_DATA_BIN) $(PHY_INIT_DATA_OBJ) - -all: phy_init_data -flash: phy_init_data - -endif # CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION - - # Enable psram cache bug workaround in compiler if selected ifdef CONFIG_SPIRAM_CACHE_WORKAROUND CFLAGS+=-mfix-esp32-psram-cache-issue CXXFLAGS+=-mfix-esp32-psram-cache-issue endif -# Enable dynamic esp_timer overflow value if building unit tests +# Enable dynamic esp_timer overflow value if building unit tests ifneq ("$(filter esp32,$(TEST_COMPONENTS_LIST))","") CPPFLAGS += -DESP_TIMER_DYNAMIC_OVERFLOW_VAL endif diff --git a/components/esp_wifi/CMakeLists.txt b/components/esp_wifi/CMakeLists.txt index c8f31cd53c..e4ba2db060 100644 --- a/components/esp_wifi/CMakeLists.txt +++ b/components/esp_wifi/CMakeLists.txt @@ -1,3 +1,6 @@ +idf_build_get_property(idf_target IDF_TARGET) +idf_build_get_property(build_dir BUILD_DIR) + set(COMPONENT_SRCS "src/coexist.c" "src/fast_crypto_ops.c" @@ -6,7 +9,7 @@ set(COMPONENT_SRCS "src/phy_init.c" "src/restore.c" "src/wifi_init.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") +set(COMPONENT_ADD_INCLUDEDIRS "include" "${idf_target}/include") set(COMPONENT_PRIV_INCLUDEDIRS) set(COMPONENT_PRIV_REQUIRES wpa_supplicant nvs_flash) @@ -15,13 +18,13 @@ if(NOT CONFIG_ESP32_NO_BLOBS) endif() register_component() -target_link_libraries(${COMPONENT_LIB} PUBLIC "-L ${CMAKE_CURRENT_SOURCE_DIR}/lib_${IDF_TARGET}") +target_link_libraries(${COMPONENT_LIB} PUBLIC "-L ${CMAKE_CURRENT_SOURCE_DIR}/lib_${idf_target}") if(NOT CONFIG_ESP32_NO_BLOBS) set(blobs coexist core espnow mesh net80211 phy pp rtc smartconfig wpa2 wpa wps) foreach(blob ${blobs}) add_library(${blob} STATIC IMPORTED) - set_property(TARGET ${blob} PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/lib_${IDF_TARGET}/lib${blob}.a) + set_property(TARGET ${blob} PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/lib_${idf_target}/lib${blob}.a) target_link_libraries(${COMPONENT_LIB} PUBLIC ${blob}) foreach(_blob ${blobs}) @@ -35,7 +38,7 @@ if(NOT CONFIG_ESP32_NO_BLOBS) endif() if(CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION) - idf_build_get_property(build_dir BUILD_DIR) + idf_component_get_property(esp_common_dir esp_common COMPONENT_DIR) partition_table_get_partition_info(phy_partition_offset "--partition-type data --partition-subtype phy" "offset") set(phy_init_data_bin "${build_dir}/phy_init_data.bin") @@ -43,11 +46,11 @@ if(CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION) # the object file to a raw binary add_custom_command( OUTPUT ${phy_init_data_bin} - DEPENDS ${CMAKE_CURRENT_LIST_DIR}/phy_init_data.h + DEPENDS ${CMAKE_CURRENT_LIST_DIR}/${idf_target}/include/phy_init_data.h COMMAND ${CMAKE_C_COMPILER} -x c -c - -I ${CMAKE_CURRENT_LIST_DIR} -I ${CMAKE_CURRENT_LIST_DIR}/include -I ${build_dir} + -I ${esp_common_dir}/include -I ${CMAKE_CURRENT_LIST_DIR}/include -I ${build_dir}/config -o phy_init_data.obj - ${CMAKE_CURRENT_LIST_DIR}/phy_init_data.h + ${CMAKE_CURRENT_LIST_DIR}/${idf_target}/include/phy_init_data.h COMMAND ${CMAKE_OBJCOPY} -O binary phy_init_data.obj ${phy_init_data_bin} ) add_custom_target(phy_init_data ALL DEPENDS ${phy_init_data_bin}) diff --git a/components/esp_wifi/Makefile.projbuild b/components/esp_wifi/Makefile.projbuild new file mode 100644 index 0000000000..3cc445ce08 --- /dev/null +++ b/components/esp_wifi/Makefile.projbuild @@ -0,0 +1,32 @@ +ifdef CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION + +PHY_INIT_DATA_OBJ = $(BUILD_DIR_BASE)/phy_init_data.o +PHY_INIT_DATA_BIN = $(BUILD_DIR_BASE)/phy_init_data.bin + +# Command to flash PHY init data partition +PHY_INIT_DATA_FLASH_CMD = $(ESPTOOLPY_SERIAL) write_flash $(PHY_DATA_OFFSET) $(PHY_INIT_DATA_BIN) +ESPTOOL_ALL_FLASH_ARGS += $(PHY_DATA_OFFSET) $(PHY_INIT_DATA_BIN) + +ESP_WIFI_COMPONENT_PATH := $(COMPONENT_PATH) + +$(PHY_INIT_DATA_OBJ): $(ESP_WIFI_COMPONENT_PATH)/$(IDF_TARGET)/include/phy_init_data.h $(BUILD_DIR_BASE)/include/sdkconfig.h + $(summary) CC $(notdir $@) + printf "#include \"phy_init_data.h\"\n" | $(CC) -I $(BUILD_DIR_BASE)/include -I $(ESP_WIFI_COMPONENT_PATH)/../esp_common/include -I $(ESP_WIFI_COMPONENT_PATH)/include -I $(ESP_WIFI_COMPONENT_PATH)/$(IDF_TARGET)/include -c -o $@ -xc - + +$(PHY_INIT_DATA_BIN): $(PHY_INIT_DATA_OBJ) + $(summary) BIN $(notdir $@) + $(OBJCOPY) -O binary $< $@ + +phy_init_data: $(PHY_INIT_DATA_BIN) + +phy_init_data-flash: $(BUILD_DIR_BASE)/phy_init_data.bin + @echo "Flashing PHY init data..." + $(PHY_INIT_DATA_FLASH_CMD) + +phy_init_data-clean: + rm -f $(PHY_INIT_DATA_BIN) $(PHY_INIT_DATA_OBJ) + +all: phy_init_data +flash: phy_init_data + +endif # CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION diff --git a/components/esp_wifi/component.mk b/components/esp_wifi/component.mk index a72ad1ccd5..866a1fdd11 100644 --- a/components/esp_wifi/component.mk +++ b/components/esp_wifi/component.mk @@ -2,7 +2,7 @@ # Component Makefile # -COMPONENT_ADD_INCLUDEDIRS := include +COMPONENT_ADD_INCLUDEDIRS := include $(IDF_TARGET)/include COMPONENT_SRCDIRS := src ifndef CONFIG_ESP32_NO_BLOBS diff --git a/components/esp_wifi/include/phy_init_data.h b/components/esp_wifi/esp32/include/phy_init_data.h similarity index 100% rename from components/esp_wifi/include/phy_init_data.h rename to components/esp_wifi/esp32/include/phy_init_data.h diff --git a/docs/en/api-guides/RF_calibration.rst b/docs/en/api-guides/RF_calibration.rst index 6b8aec0bd7..696cc53239 100644 --- a/docs/en/api-guides/RF_calibration.rst +++ b/docs/en/api-guides/RF_calibration.rst @@ -48,7 +48,7 @@ PHY initialization data The PHY initialization data is used for RF calibration. There are two ways to get the PHY initialization data. -One is the default initialization data which is located in the header file :idf_file:`components/esp32/phy_init_data.h`. +One is the default initialization data which is located in the header file :idf_file:`components/esp_wifi/esp32/include/phy_init_data.h`. It is embedded into the application binary after compiling and then stored into read-only memory (DROM). To use the default initialization data, please go to ``menuconfig`` and disable :ref:`CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION`. diff --git a/tools/ci/test_build_system.sh b/tools/ci/test_build_system.sh index 9ffea7042c..667691de06 100755 --- a/tools/ci/test_build_system.sh +++ b/tools/ci/test_build_system.sh @@ -57,6 +57,7 @@ function run_tests() BOOTLOADER_BINS="bootloader/bootloader.elf bootloader/bootloader.bin" APP_BINS="app-template.elf app-template.bin" + PHY_INIT_BIN="phy_init_data.bin" print_status "Initial clean build" # if make fails here, everything fails @@ -283,6 +284,18 @@ function run_tests() rm sdkconfig sdkconfig.defaults make defconfig + print_status "can build with phy_init_data" + make clean > /dev/null + rm -f sdkconfig.defaults + rm -f sdkconfig + echo "CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION=y" >> sdkconfig.defaults + make defconfig > /dev/null + make || failure "Failed to build with PHY_INIT_DATA" + assert_built ${APP_BINS} ${BOOTLOADER_BINS} ${PHY_INIT_BIN} + rm sdkconfig + rm sdkconfig.defaults + make defconfig + print_status "Empty directory not treated as a component" mkdir -p components/esp32 make || failure "Failed to build with empty esp32 directory in components" diff --git a/tools/ci/test_build_system_cmake.sh b/tools/ci/test_build_system_cmake.sh index 3e35eaf9b8..80686322c7 100755 --- a/tools/ci/test_build_system_cmake.sh +++ b/tools/ci/test_build_system_cmake.sh @@ -58,6 +58,7 @@ function run_tests() BOOTLOADER_BINS="bootloader/bootloader.elf bootloader/bootloader.bin" APP_BINS="app-template.elf app-template.bin" PARTITION_BIN="partition_table/partition-table.bin" + PHY_INIT_BIN="phy_init_data.bin" BUILD_ARTIFACTS="project_description.json flasher_args.json config/kconfig_menus.json config/sdkconfig.json" IDF_COMPONENT_PREFIX="__idf" @@ -342,6 +343,18 @@ function run_tests() rm sdkconfig; rm sdkconfig.defaults; + print_status "can build with phy_init_data" + idf.py clean > /dev/null; + idf.py fullclean > /dev/null; + rm -f sdkconfig.defaults; + rm -f sdkconfig; + echo "CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION=y" >> sdkconfig.defaults; + idf.py reconfigure > /dev/null; + idf.py build || failure "Failed to build with PHY_INIT_DATA" + assert_built ${APP_BINS} ${BOOTLOADER_BINS} ${PARTITION_BIN} ${PHY_INIT_BIN} + rm sdkconfig; + rm sdkconfig.defaults; + print_status "Building a project with CMake library imported and PSRAM workaround, all files compile with workaround" # Test for libraries compiled within ESP-IDF rm -rf build @@ -440,7 +453,7 @@ endmenu\n" >> ${IDF_PATH}/Kconfig; print_status "If a component directory is added to COMPONENT_DIRS, its sibling directories are not added" clean_build_dir - mkdir -p mycomponents/mycomponent + mkdir -p mycomponents/mycomponent echo "idf_component_register()" > mycomponents/mycomponent/CMakeLists.txt # first test by adding single component directory to EXTRA_COMPONENT_DIRS mkdir -p mycomponents/esp32 From 304e7119ceb9a505fca98d975e982d1cb287528f Mon Sep 17 00:00:00 2001 From: He Yin Ling Date: Mon, 17 Jun 2019 09:48:04 +0800 Subject: [PATCH 068/486] ci: fix random unit test CI failure: we use `-` command to check if DUT reset pass. If we input `-` command during DUT bootup, DUT could only receive `\n` and print test cases. Print test cases could take long time and lead to reset check timeout. Now we will add delay after reset, and enlarge reset check timeout to solve this problem. --- tools/unit-test-app/unit_test.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/unit-test-app/unit_test.py b/tools/unit-test-app/unit_test.py index 330b32ff31..2f80db6f5e 100755 --- a/tools/unit-test-app/unit_test.py +++ b/tools/unit-test-app/unit_test.py @@ -63,8 +63,9 @@ MULTI_DEVICE_ID = 2 DEFAULT_TIMEOUT = 20 +DUT_DELAY_AFTER_RESET = 2 DUT_STARTUP_CHECK_RETRY_COUNT = 5 -TEST_HISTORY_CHECK_TIMEOUT = 1 +TEST_HISTORY_CHECK_TIMEOUT = 2 class TestCaseFailed(AssertionError): @@ -164,6 +165,11 @@ def reset_dut(dut): # now use input cmd `-` and check test history to check if DUT is bootup. # we'll retry this step for a few times, # in case `dut.reset` returns during DUT bootup (when DUT can't process any command). + # + # during bootup, DUT might only receive part of the first `-` command. + # If it only receive `\n`, then it will print all cases. It could take more than 5 seconds, reset check will fail. + # To solve this problem, we will add a delay between reset and input `-` command. And we'll also enlarge expect timeout. + time.sleep(DUT_DELAY_AFTER_RESET) for _ in range(DUT_STARTUP_CHECK_RETRY_COUNT): dut.write("-") try: From ce4de867d61c042fd08137088218ff54dcc4809d Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 24 May 2017 12:35:12 +1000 Subject: [PATCH 069/486] spi_flash: New low-level flash API --- components/esp32/cpu_start.c | 5 +- .../spi_flash/include/spi_flash_lowlevel.h | 265 +++++++++ .../include/spi_flash_lowlevel_driver.h | 176 ++++++ .../include/spi_flash_lowlevel_generic.h | 151 +++++ components/spi_flash/linker.lf | 7 +- components/spi_flash/spi_flash_lowlevel_api.c | 552 ++++++++++++++++++ .../spi_flash/spi_flash_lowlevel_driver.c | 34 ++ .../spi_flash/spi_flash_lowlevel_generic.c | 498 ++++++++++++++++ .../spi_flash/spi_flash_lowlevel_idf_app.c | 60 ++ .../spi_flash/spi_flash_lowlevel_issi.c | 74 +++ .../spi_flash/spi_flash_lowlevel_noos.c | 51 ++ components/spi_flash/test/test_low_level.c | 181 ++++++ 12 files changed, 2052 insertions(+), 2 deletions(-) create mode 100644 components/spi_flash/include/spi_flash_lowlevel.h create mode 100644 components/spi_flash/include/spi_flash_lowlevel_driver.h create mode 100644 components/spi_flash/include/spi_flash_lowlevel_generic.h create mode 100644 components/spi_flash/spi_flash_lowlevel_api.c create mode 100644 components/spi_flash/spi_flash_lowlevel_driver.c create mode 100644 components/spi_flash/spi_flash_lowlevel_generic.c create mode 100644 components/spi_flash/spi_flash_lowlevel_idf_app.c create mode 100644 components/spi_flash/spi_flash_lowlevel_issi.c create mode 100644 components/spi_flash/spi_flash_lowlevel_noos.c create mode 100644 components/spi_flash/test/test_low_level.c diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index e8e1100993..266c7f5e30 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -43,6 +43,7 @@ #include "sdkconfig.h" #include "esp_system.h" #include "esp_spi_flash.h" +#include "spi_flash_lowlevel.h" #include "nvs_flash.h" #include "esp_event.h" #include "esp_spi_flash.h" @@ -388,6 +389,9 @@ void start_cpu0_default(void) spi_flash_init(); /* init default OS-aware flash access critical section */ spi_flash_guard_set(&g_flash_guard_default_ops); + /* Todo the following needs to be properly integrated */ + esp_flash_low_level_app_init(); + esp_flash_init_default_chip(); #ifdef CONFIG_PM_ENABLE esp_pm_impl_init(); #ifdef CONFIG_PM_DFS_INIT_AUTO @@ -399,7 +403,6 @@ void start_cpu0_default(void) esp_pm_configure(&cfg); #endif //CONFIG_PM_DFS_INIT_AUTO #endif //CONFIG_PM_ENABLE - #if CONFIG_ESP32_ENABLE_COREDUMP esp_core_dump_init(); size_t core_data_sz = 0; diff --git a/components/spi_flash/include/spi_flash_lowlevel.h b/components/spi_flash/include/spi_flash_lowlevel.h new file mode 100644 index 0000000000..0b4ebf9a31 --- /dev/null +++ b/components/spi_flash/include/spi_flash_lowlevel.h @@ -0,0 +1,265 @@ +#pragma once +#include +#include + +#include "soc/spi_struct.h" + +struct esp_flash_driver; + +/** @brief Mode used for reading from SPI flash */ +typedef enum { + ESP_FLASH_QIO, ///< Both address & data transferred using quad I/O + ESP_FLASH_QOUT, ///< Data read using quad I/O + ESP_FLASH_DIO, ///< Both address & data transferred using dual I/O + ESP_FLASH_DOUT, ///< Data read using dual I/O + ESP_FLASH_FASTRD, ///< Data read using single I/O, no limit on speed + ESP_FLASH_SLOWRD, ///< Data read using single I/O, some limits on speed + + ESP_FLASH_READ_MODE_MAX, +} esp_flash_read_mode_t; + +/** @brief Configured SPI flash clock speed */ +typedef enum { + ESP_FLASH_80MHZ, + ESP_FLASH_40MHZ, + ESP_FLASH_26MHZ, + ESP_FLASH_20MHZ, + ESP_FLASH_SPEED_MAX, +} esp_flash_speed_t; + +/** @brief Structure for describing a region of flash */ +typedef struct { + uint32_t offset; + uint32_t size; +} esp_flash_region_t; + +// TODO this is copied from SPI driver, should be unified somehow +typedef struct { + int mosi_io_num; ///< GPIO pin for Master Out Slave In (=spi_d) signal + int miso_io_num; ///< GPIO pin for Master In Slave Out (=spi_q) signal + int sclk_io_num; ///< GPIO pin for Spi CLocK signal + int quadwp_io_num; ///< GPIO pin for WP (Write Protect) signal which is used as D2 in 4-bit communication modes, or -1 if not used. + int quadhd_io_num; ///< GPIO pin for HD (HolD) signal which is used as D3 in 4-bit communication modes, or -1 if not used. +} esp_flash_pin_cfg_t; + +/** @brief Structure to describe a SPI flash chip connected to the system. + + Structure must be passed to esp_flash_init() before use. +*/ +typedef struct { + spi_dev_t *spi; ///< Pointer to hardware SPI bus registers used for connection (SP1, SPI2 or SPI3). Set before initialisation. + esp_flash_speed_t speed; ///< Configured SPI flash clock speed. Set before initialisation. + esp_flash_read_mode_t read_mode; ///< Configured SPI flash read mode. Set before initialisation. + uint32_t size; ///< Size of SPI flash in bytes. If 0, size will be detected during initialisation. + const struct esp_flash_driver *drv; ///< Pointer to chip-model-specific "driver" structure. If NULL, will be detected during initialisatiopn. + const esp_flash_pin_cfg_t *pins; ///< Pin configuration for the chip + + void *driver_data; ///< Currently unused, allows drivers to store driver-implementation-specific data on initialisation +} esp_flash_chip_t; + +/** @brief Possible errors returned from SPI flash low-level API */ +typedef enum { + FLASH_OK = 0, ///< Success + FLASH_ERR_NOT_INITIALISED, ///< esp_flash_chip_t structure not correctly initialised by esp_flash_init(). + FLASH_ERR_INVALID_ARG, ///< A supplied argument was invalid. + FLASH_ERR_NOT_FOUND, ///< A requested value is not found. + FLASH_ERR_NO_RESPONSE, ///< Chip did not respond to the command, or timed out. + FLASH_ERR_UNSUPPORTED_HOST, ///< Requested operation isn't supported via this host SPI bus (chip->spi field). + FLASH_ERR_UNSUPPORTED_CHIP, ///< Requested operation isn't supported by this model of SPI flash chip. + FLASH_ERR_PROTECTED, ///< Write operation failed due to chip's write protection being enabled. +} esp_flash_err_t; + +/** @brief Initialise SPI flash chip interface. + * + * This function must be called before any other API functions are called for this chip. + * + * @note Only the spi, speed & read_mode fields of the chip structure need to be initialised. Other fields will be auto-detected + * if left set to zero or NULL. + * + * @note If the chip->drv pointer is NULL, chip driver will be autodetected based on its manufacturer & product IDs. See + * esp_flash_registered_flash_drivers pointer for details of this process. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @return FLASH_OK on success, or a flash error code if initialisation fails. + */ +esp_flash_err_t esp_flash_init(esp_flash_chip_t *chip); + +/** @brief Read flash ID via the common "RDID" SPI flash command. + * + * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() + * @param[out] Pointer to receive ID value. + * + * ID is a 24-bit value. Lower 16 bits of 'id' are the chip ID, upper 8 bits are the manufacturer ID. + * + * @return FLASH_OK on success, or a flash error code if operation failed. + */ +esp_flash_err_t esp_flash_read_id(const esp_flash_chip_t *chip, uint32_t *id); + +/** @brief Detect flash size based on flash ID. + * + * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() + * @param[out] Detected size in bytes. + * + * @note Most flash chips use a common format for flash ID, where the lower 4 bits specify the size as a power of 2. If + * the manufacturer doesn't follow this convention, the size may be incorrectly detected. + * + * @return FLASH_OK on success, or a flash error code if operation failed. + */ +esp_flash_err_t esp_flash_detect_size(const esp_flash_chip_t *chip, uint32_t *size); + +/** @brief Erase flash chip contents + * + * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() + * + * + * @return FLASH_OK on success, or a flash error code if operation failed. + */ +esp_flash_err_t esp_flash_erase_chip(const esp_flash_chip_t *chip); + +/** @brief Erase a region of the flash chip + * + * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() + * @param start Address to start erasing flash. Must be sector aligned. + * @param len Length of region to erase. Must also be sector aligned. + * + * Sector size is specifyed in chip->drv->sector_size field (typically 4096 bytes.) FLASH_ERR_INVALID_ARG will be + * returned if the start & length are not a multiple of this size. + * + * Erase is performed using block (multi-sector) erases where possible (block size is specified in + * chip->drv->block_erase_size field, typically 65536 bytes). Remaining sectors are erased using individual sector erase + * commands. + * + * @return FLASH_OK on success, or a flash error code if operation failed. + */ +esp_flash_err_t esp_flash_erase_region(const esp_flash_chip_t *chip, uint32_t start, uint32_t len); + +/** @brief Read if the entire chip is write protected + * + * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() + * @param[out] write_protected Pointer to boolean, set to the value of the write protect flag. + * + * @note A correct result for this flag depends on the SPI flash chip model and driver in use (via the 'chip->drv' + * field). + * + * @return FLASH_OK on success, or a flash error code if operation failed. + */ +esp_flash_err_t esp_flash_get_chip_write_protect(const esp_flash_chip_t *chip, bool *write_protected); + +/** @brief Set write protection for the SPI flash chip + * + * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() + * @param write_protected Boolean value for the write protect flag + * + * @note Correct behaviour of this function depends on the SPI flash chip model and driver in use (via the 'chip->drv' + * field). + * + * If write protection is enabled, destructive operations will fail with FLASH_ERR_PROTECTED. + * + * Some SPI flash chips may require a power cycle before write protect status can be cleared. Otherwise, + * write protection can be removed via a follow-up call to this function. + * + * @return FLASH_OK on success, or a flash error code if operation failed. + */ +esp_flash_err_t esp_flash_set_chip_write_protect(const esp_flash_chip_t *chip, bool write_protect_chip); + + +/** @brief Read the list of individually protectable regions of this SPI flash chip. + * + * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() + * @param regions[out] Pointer to receive a pointer to the array of protectable regions of the chip. + * @param[out] Pointer to an integer receiving the count of protectable regions in the array returned in 'regions'. + * + * @note Correct behaviour of this function depends on the SPI flash chip model and driver in use (via the 'chip->drv' + * field). + * + * @return FLASH_OK on success, or a flash error code if operation failed. + */ +esp_flash_err_t esp_flash_get_protectable_regions(const esp_flash_chip_t *chip, const esp_flash_region_t **regions, uint32_t *num_regions); + + +/** @brief Detect if a region of the SPI flash chip is protected + * + * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() + * @param region Pointer to a struct describing a protected region. This must match one of the regions returned from esp_flash_get_protectable_regions(...). + * @param[out] protected Pointer to a flag which is set based on the protected status for this region. + * + * @note It is possible for this result to be false and write operations to still fail, if protection is enabled for the entire chip. + * + * @note Correct behaviour of this function depends on the SPI flash chip model and driver in use (via the 'chip->drv' + * field). + * + * @return FLASH_OK on success, or a flash error code if operation failed. + */ +esp_flash_err_t esp_flash_get_protected_region(const esp_flash_chip_t *chip, const esp_flash_region_t *region, bool *protected); + +/** @brief Update the protected status for a region of the SPI flash chip + * + * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() + * @param region Pointer to a struct describing a protected region. This must match one of the regions returned from esp_flash_get_protectable_regions(...). + * @param protected Write protection flag to set. + * + * @note It is possible for the region protection flag to be cleared and write operations to still fail, if protection is enabled for the entire chip. + * + * @note Correct behaviour of this function depends on the SPI flash chip model and driver in use (via the 'chip->drv' + * field). + * + * @return FLASH_OK on success, or a flash error code if operation failed. + */ +esp_flash_err_t esp_flash_set_protected_region(const esp_flash_chip_t *chip, const esp_flash_region_t *region, bool protected); + +/** @brief Read data from the SPI flash chip + * + * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() + * @param buffer Pointer to a buffer where the data will be read. + * @param address Address on flash to read from. Must be less than chip->size field. + * @param length Length (in bytes) of data to read. + * + * There are no alignment constraints on buffer, address or length. + * + * @note If on-chip flash encryption is used, this function returns raw (ie encrypted) data. Use the flash cache + * to transparently decrypt data. + * + * @return FLASH_OK on success, or a flash error code if operation failed. + */ +esp_flash_err_t esp_flash_read(const esp_flash_chip_t *chip, void *buffer, uint32_t address, uint32_t length); + +/** @brief Write data to the SPI flash chip + * + * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() + * @param address Address on flash to write to. Must be previously erased (SPI NOR flash can only write bits 1->0). + * @param buffer Pointer to a buffer with the data to write. + * @param length Length (in bytes) of data to write. + * + * There are no alignment constraints on buffer, address or length. + * + * @return FLASH_OK on success, or a flash error code if operation failed. + */ +esp_flash_err_t esp_flash_write(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length); + +/** @brief Encrypted and write data to the SPI flash chip using on-chip hardware flash encryption + * + * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() + * @param address Address on flash to write to. 16 byte aligned. Must be previously erased (SPI NOR flash can only write bits 1->0). + * @param buffer Pointer to a buffer with the data to write. + * @param length Length (in bytes) of data to write. 16 byte aligned. + * + * @note Both address & length must be 16 byte aligned, as this is the encryption block size + * + * @return FLASH_OK on success, or a flash error code if operation failed. + */ +esp_flash_err_t esp_flash_write_encrypted(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length); + +/** @brief Pointer to the "default" SPI flash chip, ie the main chip attached to the MCU. + + This chip is used if the 'chip' argument pass to esp_flash_xxx API functions is ever NULL. +*/ +extern const esp_flash_chip_t *esp_flash_default_chip; + +/** @brief Initialise the default SPI flash chip + * + * Called by OS startup code. You do not need to call this in your own applications. + */ +esp_flash_err_t esp_flash_init_default_chip(); + +/** Enable OS-level SPI flash protections in IDF */ +void esp_flash_low_level_app_init(); /* ROM TODO move this to IDF */ diff --git a/components/spi_flash/include/spi_flash_lowlevel_driver.h b/components/spi_flash/include/spi_flash_lowlevel_driver.h new file mode 100644 index 0000000000..0343cc7cb4 --- /dev/null +++ b/components/spi_flash/include/spi_flash_lowlevel_driver.h @@ -0,0 +1,176 @@ +#pragma once +#include "spi_flash_lowlevel.h" + +/** @brief SPI flash driver definition structure. + * + * The driver structure contains chip-specific pointers to functions to perform SPI flash operations, and some + * chip-specific numeric values. + * + * @note This is not a public API. Driver-specific functions are called from the public API (declared in + * spi_flash_lowlevel.h). They assume the caller has already validated arguments and enabled relevant protections + * (disabling flash cache, prevent concurrent SPI access, etc.) + * + * Do not call driver functions directly in other contexts. + * + * A generic driver and it's related operations are defined in spi_flash_lowlevel_generic.h which can be used as + * building blocks for written new/specific SPI flash chip drivers. + * + * @note All of these functions may be called with SPI flash cache disabled, so must only ever access IRAM/DRAM/ROM. + */ +typedef struct esp_flash_driver { + /* Probe to detect if a supported SPI flash chip is found. + * + * Attempts to configure 'chip' with these operations and probes for a matching SPI flash chip. + * + * Auto-detection of a SPI flash chip calls this function in turn on each registered driver (see esp_flash_registered_flash_drivers). + * + * ID - as read by spi_flash_generic_read_id() - is supplied so each probe + * function doesn't need to unnecessarily read ID, but probe is permitted + * to interrogate flash in any non-destructive way. + * + * It is permissible for the driver to modify the 'chip' structure if probing succeeds (specifically, to assign something to the + * driver_data pointer if that is useful for the driver.) + * + * @return FLASH_OK if probing was successful, an error otherwise. Driver may + * assume that returning FLASH_OK means it has claimed this chip. + */ + esp_flash_err_t (*probe)(esp_flash_chip_t *chip, uint32_t flash_id); + + /* Read SPI flash ID + * + * Sends RDID (or an equivalent command) to the device. + */ + esp_flash_err_t (*read_id)(const esp_flash_chip_t *chip, uint32_t *id); + + /* Detect SPI flash size + * + * Interrogate the chip to detect it's size. + */ + esp_flash_err_t (*detect_size)(const esp_flash_chip_t *chip, uint32_t *size); + + /* Erase the entire chip + + Caller has verified the chip is not write protected. + */ + esp_flash_err_t (*erase_chip)(const esp_flash_chip_t *chip); + + /* Erase a sector of the chip. Sector size is specified in the 'sector_size' field. + + sector_address is an offset in bytes. + + Caller has verified that this sector should be non-write-protected. + */ + esp_flash_err_t (*erase_sector)(const esp_flash_chip_t *chip, uint32_t sector_address); + + /* Erase a multi-sector block of the chip. Block size is specified in the 'block_erase_size' field. + sector_address is an offset in bytes. + + Caller has verified that this block should be non-write-protected. + */ + esp_flash_err_t (*erase_block)(const esp_flash_chip_t *chip, uint32_t block_address); + + uint32_t sector_size; /* Sector is minimum erase size */ + uint32_t block_erase_size; /* Optimal (fastest) block size for multi-sector erases on this chip */ + + /* Read the write protect status of the entire chip. */ + esp_flash_err_t (*get_chip_write_protect)(const esp_flash_chip_t *chip, bool *write_protected); + + /* Set the write protect status of the entire chip. */ + esp_flash_err_t (*set_chip_write_protect)(const esp_flash_chip_t *chip, bool write_protect_chip); + + /* Number of individually write protectable regions on this chip. Range 0-63. */ + uint8_t num_protectable_regions; + /* Pointer to an array describing each protectable region. Should have num_protectable_regions elements. */ + const esp_flash_region_t *protectable_regions; + /* Get a bitmask describing all protectable regions on the chip. Each bit represents one entry in the + protectable_regions array, ie bit (1<drv->set_read_mode(chip) in order to configure the chip's read mode correctly. + */ + esp_flash_err_t (*read)(const esp_flash_chip_t *chip, void *buffer, uint32_t address, uint32_t length); + + /* Write any amount of data to the chip. + */ + esp_flash_err_t (*write)(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length); + + + /* Use the page program command to write data to the chip. + * + * This function is expected to be called by chip->drv->write (if the + * chip->drv->write implementation doesn't call it then it can be left as NULL.) + * + * - The length argument supplied to this function is at most 'page_size' bytes. + * + * - The region between 'address' and 'address + length' will not cross a page_size aligned boundary (the write + * implementation is expected to split such a write into two before calling page_program.) + */ + esp_flash_err_t (*page_program)(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length); + + /* Page size as written by the page_program function. Usually 256 bytes. */ + uint32_t page_size; + + /* Perform an encrypted write to the chip, using internal flash encryption hardware. */ + esp_flash_err_t (*write_encrypted)(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length); + + /* Set the write enable flag. This function is called internally by other functions in this structure, before a destructive + operation takes place. */ + esp_flash_err_t (*write_enable)(const esp_flash_chip_t *chip); + + /* Wait for the SPI flash chip to be idle (any write operation to be complete.) This function is both called from the higher-level API functions, and from other functions in this structure. + + timeout_ms should be a timeout (in milliseconds) before the function returns FLASH_ERR_NO_RESPONSE. This is useful to avoid hanging + if the chip is otherwise unresponsive (ie returns all 0xFF or similar.) + */ + esp_flash_err_t (*wait_idle)(const esp_flash_chip_t *chip, unsigned timeout_ms); + + /* Configure both the SPI host and the chip for the read mode specified in chip->read_mode. + * + * This function is called by the higher-level API before the 'read' function is called. + * + * Can return FLASH_ERR_UNSUPPORTED_HOST or FLASH_ERR_UNSUPPORTED_CHIP if the specified mode is unsupported. + */ + esp_flash_err_t (*set_read_mode)(const esp_flash_chip_t *chip); +} esp_flash_driver_t; + +/* Pointer to an array of pointers to all known drivers for flash chips. This array is used + by esp_flash_init() to detect the flash chip driver, if none is supplied by the caller. + + Array is terminated with a NULL pointer. + + This pointer can be overwritten with a pointer to a new array, to update the list of known flash chips. + */ +extern const esp_flash_driver_t **esp_flash_registered_flash_drivers; + +/* Provide OS-level integration hooks for accessing flash chips + inside a running OS */ +typedef struct +{ + /* Call this function before commencing any flash operation. + + Does not need to be recursive (ie is called at most once for each call to 'end'. + */ + esp_flash_err_t (*start)(const esp_flash_chip_t *chip); + + /* Call this function after completing any flash operation. */ + esp_flash_err_t (*end)(const esp_flash_chip_t *chip); + + /* Delay for at least 'ms' milliseconds. + + This function will be called in between 'start' and 'end'. + */ + esp_flash_err_t (*delay_ms)(unsigned ms); +} esp_flash_os_functions_t; + +/* The default (ie initial boot) no-OS ROM esp_flash_os_functions_t */ +const esp_flash_os_functions_t esp_flash_noos_functions; + +/* Pointer to the current esp_flash_os_functions_t structure in use. + Can be changed at runtime to reflect different running conditions. + */ +extern const esp_flash_os_functions_t *esp_flash_os_functions; diff --git a/components/spi_flash/include/spi_flash_lowlevel_generic.h b/components/spi_flash/include/spi_flash_lowlevel_generic.h new file mode 100644 index 0000000000..75866c721e --- /dev/null +++ b/components/spi_flash/include/spi_flash_lowlevel_generic.h @@ -0,0 +1,151 @@ +#pragma once +#include "spi_flash_lowlevel_driver.h" +/* The 'generic' SPI flash operations are a lowest common subset of SPI flash commands, that work across most chips. + * + * These can be used as-is vai the esp_flash_common_chip_driver driver, or they can be used as "base driver" functions when + * creating a new esp_flash_driver_t driver structure. + * + * + * All of the functions in this header are internal functions, not part of a public API. See spi_flash_lowlevel.h for + * the public API. + */ + +/* SPI commands (actual on-wire commands not SPI controller bitmasks) + Suitable for use with spi_flash_common_command static function. +*/ +#define CMD_RDID 0x9F +#define CMD_WRSR 0x01 +#define CMD_WRSR2 0x31 /* Not all SPI flash uses this command */ +#define CMD_WREN 0x06 +#define CMD_WRDI 0x04 +#define CMD_RDSR 0x05 +#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */ + +#define CMD_FASTRD_QIO 0xEB +#define CMD_FASTRD_QUAD 0x6B +#define CMD_FASTRD_DIO 0xBB +#define CMD_FASTRD_DUAL 0x3B +#define CMD_FASTRD 0x0B +#define CMD_READ 0x03 /* Speed limited */ + +#define CMD_CHIP_ERASE 0xC7 +#define CMD_SECTOR_ERASE 0x20 +#define CMD_LARGE_BLOCK_ERASE 0xD8 /* 64KB block erase command */ + +#define SR_WIP (1<<0) /* Status register write-in-progress bit */ +#define SR_WREN (1<<1) /* Status register write enable bit */ + + +/** @brief Execute a simple SPI flash command against the chip. + * + * @param chip Pointer to the chip to use. + * @param command Command to execute (an on-wire hex command.) + * @param mosi_data Up to 32 bits of MOSI data to write after the command. + * @param mosi_len Length of MOSI data (in bits.) + * @param miso_len Length of MISO data (in bits.) + * @return MISO value read back, if any (depending on miso_len value.) + */ +uint32_t spi_flash_common_command(const esp_flash_chip_t *chip, uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len); + +/** @brief Returns true if the pin configuration for this chip uses the GPIO matrix for any signals. */ +bool spi_flash_uses_gpio_matrix(const esp_flash_chip_t *chip); + +/** @brief Generic probe function + * + * If chip->drv_read_id succeeds, the probe succeeds. + */ +esp_flash_err_t spi_flash_generic_probe(esp_flash_chip_t *chip, uint32_t flash_id); + +/** @brief Generic implementation of esp_flash_driver_t->read_id + * + * Uses the RDID command (9Fh) supported by most SPI flash chips. + * + * Results of all-zeroes or all-ones are considered failures (probably no chip attached.) + */ +esp_flash_err_t spi_flash_generic_read_id(const esp_flash_chip_t *chip, uint32_t *id); + +/** @brief Generic size detection function + * + * Tries to detect the size of chip by using the lower 4 bits of the chip->drv->read_id result = N, and assuming size is 2 ^ N. + */ +esp_flash_err_t spi_flash_generic_detect_size(const esp_flash_chip_t *chip, uint32_t *size); + +/** @brief Erase chip by using the generic erase chip (C7h) command. */ +esp_flash_err_t spi_flash_generic_erase_chip(const esp_flash_chip_t *chip); + +/** @brief Erase sector by using the generic sector erase (20h) command. */ +esp_flash_err_t spi_flash_generic_erase_sector(const esp_flash_chip_t *chip, uint32_t start_address); + +/** @brief Erase block by using the generic 64KB block erase (D8h) command */ +esp_flash_err_t spi_flash_generic_erase_block(const esp_flash_chip_t *chip, uint32_t start_address); + +/** @brief Read from flash by using a read command that matches the programmed read mode. */ +esp_flash_err_t spi_flash_generic_read(const esp_flash_chip_t *chip, void *buffer, uint32_t address, uint32_t length); + +/** @brief Perform a page program using the page program (02h) command. */ +esp_flash_err_t spi_flash_generic_page_program(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length); + +/** @brief Perform a generic write. Split the write buffer into + one page operations, and call chip->drv->page-program() for each. +*/ +esp_flash_err_t spi_flash_generic_write(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length); + +/** @brief Perform a write using on-chip flash encryption */ +esp_flash_err_t spi_flash_generic_write_encrypted(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length); + +/** @brief Send the write enable (06h) command and verify the expected bit (1) in the status register is set. */ +esp_flash_err_t spi_flash_generic_write_enable(const esp_flash_chip_t *chip); + +/** @brief Wait for the SPI host hardware state machine to be idle. + + This isn't a flash driver operation, but it's called by spi_flash_generic_wait_idle() and may be useful when implementing alternative drivers. + + timeout_ms will be decremented if the function needs to wait until the host hardware is idle. +*/ +esp_flash_err_t spi_flash_generic_wait_host_idle(const esp_flash_chip_t *chip, uint32_t *timeout_ms); + +/** @brief Read flash status via the RDSR command (05h) and wait for bit 0 (write in progress bit) to be cleared. */ +esp_flash_err_t spi_flash_generic_wait_idle(const esp_flash_chip_t *chip, uint32_t timeout_ms); + +/** @brief Utility function to configure the SPI host hardware registers for the specified read mode. + + Called by spi_flash_generic_set_read_mode() but may also be useful + when implementing other SPI flash drivers. + + Note that calling this configures SPI host registers, so if running any other commands as part of set_read_mode() then these must be run before calling this function. + */ +esp_flash_err_t spi_flash_common_configure_host_read_mode(const esp_flash_chip_t *chip); + +/** @brief Utility function for set_read_mode driver function + * + * Most setting of read mode follows a common pattern, except for how to enable Quad I/O modes (QIO/QOUT). + * These use different commands to read/write the status register, and a different bit is set/cleared. + * + * This is a generic utility function to implement set_read_mode() for this pattern. Also configures host + * registers via spi_flash_common_configure_host_read_mode(). + * + * @param qe_rdsr_command SPI flash command to read status register + * @param qe_wrsr_command SPI flash command to write status register + * @param qe_sr_bitwidth Width of the status register these commands operate on, in bits. + * @param qe_sr_bit Bit mask for enabling Quad Enable functions on this chio. + */ +esp_flash_err_t spi_flash_common_set_read_mode(const esp_flash_chip_t *chip, uint8_t qe_rdsr_command, uint8_t qe_wrsr_command, uint8_t qe_sr_bitwidth, unsigned qe_sr_bit); + +/** @brief Set the specified SPI read mode. + * + * Includes setting SPI host hardware registers, but also setting quad enable status register bit if needed. + */ +esp_flash_err_t spi_flash_generic_set_read_mode(const esp_flash_chip_t *chip); + +/** @brief Returns true if chip is configured for Quad I/O or + Quad Fast Read */ +inline static bool spi_flash_is_quad_mode(const esp_flash_chip_t *chip) +{ + return chip->read_mode == ESP_FLASH_QIO || chip->read_mode == ESP_FLASH_QOUT; +} + +/* Generic SPI flash driver, uses all the above functions for its operations. In default autodetection, this is used as + a catchall if a more specific driver is not found. +*/ +extern const esp_flash_driver_t esp_flash_generic_chip_driver; + diff --git a/components/spi_flash/linker.lf b/components/spi_flash/linker.lf index fbbb64ea74..e466c85a2b 100644 --- a/components/spi_flash/linker.lf +++ b/components/spi_flash/linker.lf @@ -1,5 +1,10 @@ [mapping:spi_flash] archive: libspi_flash.a -entries: +entries: spi_flash_rom_patch (noflash_text) + spi_flash_lowlevel_api (noflash) + spi_flash_lowlevel_generic (noflash) + spi_flash_lowlevel_issi (noflash) + spi_flash_lowlevel_idf_app (noflash) + spi_flash_driver_hs (noflash) diff --git a/components/spi_flash/spi_flash_lowlevel_api.c b/components/spi_flash/spi_flash_lowlevel_api.c new file mode 100644 index 0000000000..0a3d6f29a5 --- /dev/null +++ b/components/spi_flash/spi_flash_lowlevel_api.c @@ -0,0 +1,552 @@ +// Copyright 2017 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 +#include +#include +#include + +#include "spi_flash_lowlevel_driver.h" +#include "spi_flash_lowlevel_generic.h" +#include "soc/spi_reg.h" + +#define MAX_WRITE_CHUNK 8192 /* write in chunks */ + +/* Static function to notify OS of a new SPI flash operation. + + If returns an error result, caller must abort. If returns FLASH_OK, caller must + call spiflash_end() before returning. +*/ +static esp_flash_err_t spiflash_start(const esp_flash_chip_t *chip) +{ + if (esp_flash_os_functions != NULL + && esp_flash_os_functions->start != NULL) { + esp_flash_err_t err = esp_flash_os_functions->start(chip); + if (err != FLASH_OK) { + return err; + } + } + return FLASH_OK; +} + +/* Static function to notify OS that SPI flash operation is complete. + */ +static esp_flash_err_t spiflash_end(const esp_flash_chip_t *chip, esp_flash_err_t err) +{ + if (esp_flash_os_functions != NULL + && esp_flash_os_functions->end != NULL) { + esp_flash_err_t end_err = esp_flash_os_functions->end(chip); + if (err == FLASH_OK) { + err = end_err; // Only return the 'end' error if we haven't already failed + } + } + return err; +} + +/* Return true if regions 'a' and 'b' overlap at all, based on their start offsets and lengths. */ +inline static bool regions_overlap(uint32_t a_start, uint32_t a_len,uint32_t b_start, uint32_t b_len); + +/* Top-level API functions, calling into driver functions via chip->drv */ + +static esp_flash_err_t detect_spi_flash_chip(esp_flash_chip_t *chip); + +esp_flash_err_t esp_flash_init(esp_flash_chip_t *chip) +{ + if (chip->spi == NULL) { + return FLASH_ERR_INVALID_ARG; + } + + // TODO: configure SPI host clock speed, pin configuration + + if (chip->drv == NULL) { + // Detect driver + esp_flash_err_t err = detect_spi_flash_chip(chip); + if (err != FLASH_OK) { + return err; + } + } + + esp_flash_err_t err = spiflash_start(chip); + if (err != FLASH_OK) { + return err; + } + + if (chip->size == 0) { + // Detect flash size + err = chip->drv->detect_size(chip, &chip->size); + } + + if (err == FLASH_OK) { + // Try to set the flash mode to whatever default mode was chosen + // (this isn't necessary at this point for functionality, but init will fail + // if this mode can't be set on this chip.) + err = chip->drv->set_read_mode(chip); + } + + // Done: all fields on 'chip' are initialised + return spiflash_end(chip, err); +} + +static esp_flash_err_t detect_spi_flash_chip(esp_flash_chip_t *chip) +{ + esp_flash_err_t err; + uint32_t flash_id; + int retries = 10; + do { + err = spiflash_start(chip); + if (err != FLASH_OK) { + return err; + } + + // Send generic RDID command twice, check for a matching result and retry in case we just powered on (inner + // function fails if it sees all-ones or all-zeroes.) + err = spi_flash_generic_read_id(chip, &flash_id); + + if (err == FLASH_OK) { // check we see the same ID twice, in case of transient power-on errors + uint32_t new_id; + err = spi_flash_generic_read_id(chip, &new_id); + if (err == FLASH_OK && (new_id != flash_id)) { + err = FLASH_ERR_NOT_INITIALISED; + } + } + + err = spiflash_end(chip, err); + } while (err != FLASH_OK && retries-- > 0); + + // Detect the chip and set the driver structure for it + const esp_flash_driver_t **drivers = esp_flash_registered_flash_drivers; + while (*drivers != NULL && chip->drv == NULL) { + chip->drv = *drivers; + + // start/end SPI operation each time, for multitasking + // and also so esp_flash_registered_flash_drivers can live in flash + err = spiflash_start(chip); + if (err != FLASH_OK) { + return err; + } + + if (chip->drv->probe(chip, flash_id) != FLASH_OK) { + chip->drv = NULL; + } + // if probe succeeded, chip->drv stays set + drivers++; + + err = spiflash_end(chip, err); + if (err != FLASH_OK) { + return err; + } + } + + return (chip->drv == NULL) ? FLASH_ERR_NOT_FOUND : FLASH_OK; +} + +// Convenience macro for beginning of all API functions, +// check that the 'chip' parameter is properly initialised +// and supports the operation in question +#define VERIFY_OP(OP) do { \ + if (chip == NULL) { \ + chip = esp_flash_default_chip; \ + } \ + if (chip == NULL || chip->drv == NULL) { \ + return FLASH_ERR_NOT_INITIALISED; \ + } \ + if (chip->drv->OP == NULL) { \ + return FLASH_ERR_UNSUPPORTED_CHIP; \ + } \ + } while (0) + +esp_flash_err_t esp_flash_read_id(const esp_flash_chip_t *chip, uint32_t *id) +{ + printf("chip %p esp_flash_default_chip %p\n", + chip, esp_flash_default_chip); + VERIFY_OP(read_id); + if (id == NULL) { + return FLASH_ERR_INVALID_ARG; + } + esp_flash_err_t err = spiflash_start(chip); + if (err != FLASH_OK) { + return err; + } + + err = chip->drv->read_id(chip, id); + + return spiflash_end(chip, err); +} + +esp_flash_err_t esp_flash_detect_size(const esp_flash_chip_t *chip, uint32_t *size) +{ + VERIFY_OP(detect_size); + if (size == NULL) { + return FLASH_ERR_INVALID_ARG; + } + *size = 0; + + esp_flash_err_t err = spiflash_start(chip); + if (err != FLASH_OK) { + return err; + } + + err = chip->drv->detect_size(chip, size); + + return spiflash_end(chip, err); +} + +esp_flash_err_t esp_flash_erase_chip(const esp_flash_chip_t *chip) +{ + VERIFY_OP(erase_chip); + bool write_protect = false; + + esp_flash_err_t err = spiflash_start(chip); + if (err != FLASH_OK) { + return err; + } + + err = esp_flash_get_chip_write_protect(chip, &write_protect); + + if (err == FLASH_OK && write_protect) { + err = FLASH_ERR_PROTECTED; + } + + if (err == FLASH_OK) { + err = chip->drv->erase_chip(chip); + } + + return spiflash_end(chip, err); +} + +esp_flash_err_t esp_flash_erase_region(const esp_flash_chip_t *chip, uint32_t start, uint32_t len) +{ + VERIFY_OP(erase_sector); + uint32_t block_erase_size = chip->drv->erase_block == NULL ? 0 : chip->drv->block_erase_size; + uint32_t sector_size = chip->drv->sector_size; + bool write_protect = false; + + if (sector_size == 0 || (block_erase_size % sector_size) != 0) { + return FLASH_ERR_NOT_INITIALISED; + } + if (start > chip->size || start + len > chip->size) { + return FLASH_ERR_INVALID_ARG; + } + if ((start % chip->drv->sector_size) != 0 || (len % chip->drv->sector_size) != 0) { + // Can only erase multiples of the sector size, starting at sector boundary + return FLASH_ERR_INVALID_ARG; + } + + esp_flash_err_t err = spiflash_start(chip); + if (err != FLASH_OK) { + return err; + } + + // Check for write protection on whole chip + if (chip->drv->get_chip_write_protect != NULL) { + err = chip->drv->get_chip_write_protect(chip, &write_protect); + if (err == FLASH_OK && write_protect) { + err = FLASH_ERR_PROTECTED; + } + } + + // Check for write protected regions overlapping the erase region + if (err == FLASH_OK && chip->drv->get_protected_regions != NULL && chip->drv->num_protectable_regions > 0) { + uint64_t protected = 0; + err = chip->drv->get_protected_regions(chip, &protected); + if (protected != 0) { + for (int i = 0; i < chip->drv->num_protectable_regions && err == FLASH_OK; i++) { + const esp_flash_region_t *region = &chip->drv->protectable_regions[i]; + if ((protected & (1LL << i)) + && regions_overlap(start, len, region->offset, region->size)) { + err = FLASH_ERR_PROTECTED; + } + } + } + } + + // Don't lock the SPI flash for the entire erase, as this may be very long + err = spiflash_end(chip, err); + + while (err == FLASH_OK && len >= sector_size) { + esp_flash_err_t err = spiflash_start(chip); + if (err != FLASH_OK) { + return err; + } + + // If possible erase an entire multi-sector block + if (block_erase_size > 0 && len >= block_erase_size && (start % block_erase_size) == 0) { + err = chip->drv->erase_block(chip, start); + start += block_erase_size; + len -= block_erase_size; + } + else { + // Otherwise erase individual sector only + err = chip->drv->erase_sector(chip, start); + start += sector_size; + len -= sector_size; + } + + err = spiflash_end(chip, err); + } + + return err; +} + +esp_flash_err_t esp_flash_get_chip_write_protect(const esp_flash_chip_t *chip, bool *write_protected) +{ + VERIFY_OP(get_chip_write_protect); + if (write_protected == NULL) { + return FLASH_ERR_INVALID_ARG; + } + + esp_flash_err_t err = spiflash_start(chip); + if (err != FLASH_OK) { + return err; + } + + err = chip->drv->get_chip_write_protect(chip, write_protected); + + return spiflash_end(chip, err); +} + +esp_flash_err_t esp_flash_set_chip_write_protect(const esp_flash_chip_t *chip, bool write_protect_chip) +{ + VERIFY_OP(set_chip_write_protect); + + esp_flash_err_t err = spiflash_start(chip); + if (err != FLASH_OK) { + return err; + } + + err = chip->drv->set_chip_write_protect(chip, write_protect_chip); + + return spiflash_end(chip, err); +} + +esp_flash_err_t esp_flash_get_protectable_regions(const esp_flash_chip_t *chip, const esp_flash_region_t **regions, uint32_t *num_regions) +{ + if(num_regions != NULL) { + *num_regions = 0; // In case caller doesn't check result + } + VERIFY_OP(get_protected_regions); + + if(regions == NULL || num_regions == NULL) { + return FLASH_ERR_INVALID_ARG; + } + + *num_regions = chip->drv->num_protectable_regions; + *regions = chip->drv->protectable_regions; + return FLASH_OK; +} + +static esp_flash_err_t find_region(const esp_flash_chip_t *chip, const esp_flash_region_t *region, uint8_t *index) +{ + if (region == NULL) { + return FLASH_ERR_INVALID_ARG; + } + + for(*index = 0; *index < chip->drv->num_protectable_regions; (*index)++) { + if (memcmp(&chip->drv->protectable_regions[*index], + region, sizeof(esp_flash_region_t)) == 0) { + return FLASH_OK; + } + } + + return FLASH_ERR_NOT_FOUND; +} + +esp_flash_err_t esp_flash_get_protected_region(const esp_flash_chip_t *chip, const esp_flash_region_t *region, bool *protected) +{ + VERIFY_OP(get_protected_regions); + + if (protected == NULL) { + return FLASH_ERR_INVALID_ARG; + } + + uint8_t index; + esp_flash_err_t err = find_region(chip, region, &index); + if (err != FLASH_OK) { + return err; + } + + uint64_t protection_mask = 0; + err = spiflash_start(chip); + if (err != FLASH_OK) { + return err; + } + + err = chip->drv->get_protected_regions(chip, &protection_mask); + if (err == FLASH_OK) { + *protected = protection_mask & (1LL << index); + } + + return spiflash_end(chip, err); +} + +esp_flash_err_t esp_flash_set_protected_region(const esp_flash_chip_t *chip, const esp_flash_region_t *region, bool protected) +{ + VERIFY_OP(set_protected_regions); + + uint8_t index; + esp_flash_err_t err = find_region(chip, region, &index); + if (err != FLASH_OK) { + return err; + } + + uint64_t protection_mask = 0; + err = spiflash_start(chip); + if (err != FLASH_OK) { + return err; + } + + err = chip->drv->get_protected_regions(chip, &protection_mask); + if (err == FLASH_OK) { + if (protected) { + protection_mask |= (1LL << index); + } else { + protection_mask &= ~(1LL << index); + } + err = chip->drv->set_protected_regions(chip, protection_mask); + } + + return spiflash_end(chip, err); +} + +esp_flash_err_t esp_flash_read(const esp_flash_chip_t *chip, void *buffer, uint32_t address, uint32_t length) +{ + VERIFY_OP(read); + if (buffer == NULL || address > chip->size || address+length > chip->size) { + return FLASH_ERR_INVALID_ARG; + } + + esp_flash_err_t err = spiflash_start(chip); + if (err != FLASH_OK) { + return err; + } + + if (err == FLASH_OK) { + err = chip->drv->set_read_mode(chip); + } + + if (err == FLASH_OK) { + err = chip->drv->read(chip, buffer, address, length); + } + + return spiflash_end(chip, err); +} + +esp_flash_err_t esp_flash_write(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length) +{ + VERIFY_OP(write); + if (buffer == NULL || address > chip->size || address+length > chip->size) { + return FLASH_ERR_INVALID_ARG; + } + + /* If 'chip' is connected to the main SPI bus, we can only write directly from regions that are accessible + with cache disabled. */ +#ifdef ESP_PLATFORM + bool direct_write = ( chip->spi != &SPI1 + || ( (uintptr_t) address >= 0x3FFAE000 + && (uintptr_t) address < 0x40000000 ) ); +#else + bool direct_write = true; +#endif + + esp_flash_err_t err = FLASH_OK; + + /* Write output in chunks, either by buffering on stack or + by artificially cutting into MAX_WRITE_CHUNK parts (in an OS + environment, this prevents writing from causing interrupt or higher priority task + starvation.) */ + while(err == FLASH_OK && length > 0) { + uint32_t write_len; + const void *write_buf; + if (direct_write) { + write_len = MIN(length, MAX_WRITE_CHUNK); + write_buf = buffer; + } else { + uint32_t buf[8]; + write_len = MIN(length, sizeof(buf)); + memcpy(buf, buffer, write_len); + write_buf = buf; + } + + err = spiflash_start(chip); + if (err != FLASH_OK) { + return err; + } + + err = chip->drv->write(chip, address, write_buf, write_len); + + address += write_len; + buffer = (void *)((intptr_t)buffer + write_len); + length -= write_len; + + err = spiflash_end(chip, err); + } + return err; +} + +esp_flash_err_t esp_flash_write_encrypted(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length) +{ + VERIFY_OP(write_encrypted); + if (chip->spi != 0) { + // Encrypted operations have to use SPI0 + return FLASH_ERR_UNSUPPORTED_HOST; + } + if (buffer == NULL || address > chip->size || address+length > chip->size) { + return FLASH_ERR_INVALID_ARG; + } + + esp_flash_err_t err = spiflash_start(chip); + if (err != FLASH_OK) { + return err; + } + + err = chip->drv->write_encrypted(chip, address, buffer, length); + + return spiflash_end(chip, err); +} + + +inline static bool regions_overlap(uint32_t a_start, uint32_t a_len,uint32_t b_start, uint32_t b_len) +{ + uint32_t a_end = a_start + a_len; + uint32_t b_end = b_start + b_len; + + return ((a_start >= b_start && a_start <= b_end) + || (a_end >= b_start && a_end <= b_end) + || (b_start >= a_start && b_start <= a_end) + || (b_end >= a_start && b_end <= a_end)); +} + +const esp_flash_chip_t *esp_flash_default_chip; + +static esp_flash_chip_t default_chip; + +esp_flash_err_t esp_flash_init_default_chip() +{ + default_chip.spi = &SPI1; + default_chip.read_mode = ESP_FLASH_FASTRD; // TODO: initialise properly + default_chip.speed = ESP_FLASH_20MHZ; // TODO: initialise properly + + // ROM TODO: account for non-standard default pins in efuse + + // ROM TODO: to account for chips which are slow to power on, maybe keep probing in a loop here + + esp_flash_err_t err = esp_flash_init(&default_chip); + if (err != FLASH_OK) { + return err; + } + + esp_flash_default_chip = &default_chip; + return FLASH_OK; +} + +const esp_flash_os_functions_t *esp_flash_os_functions = &esp_flash_noos_functions; diff --git a/components/spi_flash/spi_flash_lowlevel_driver.c b/components/spi_flash/spi_flash_lowlevel_driver.c new file mode 100644 index 0000000000..e901ef1e21 --- /dev/null +++ b/components/spi_flash/spi_flash_lowlevel_driver.c @@ -0,0 +1,34 @@ +// Copyright 2017 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 +#include "spi_flash_lowlevel_driver.h" + +extern const esp_flash_driver_t esp_flash_generic_chip_driver; +extern const esp_flash_driver_t esp_flash_issi_chip_driver; + +/* Default registered chip drivers. + + Note these are tested in order and first match is taken, so generic/catchall entries + should go last. + + Note that the esp_flash_registered_flash_ops pointer can be + changed to point to a different array of registered ops, if desired. +*/ +static const esp_flash_driver_t *default_registered_flash_drivers[] = { + &esp_flash_issi_chip_driver, + &esp_flash_generic_chip_driver, + NULL, +}; + +const esp_flash_driver_t **esp_flash_registered_flash_drivers = default_registered_flash_drivers; diff --git a/components/spi_flash/spi_flash_lowlevel_generic.c b/components/spi_flash/spi_flash_lowlevel_generic.c new file mode 100644 index 0000000000..aef068e30f --- /dev/null +++ b/components/spi_flash/spi_flash_lowlevel_generic.c @@ -0,0 +1,498 @@ +// Copyright 2017 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 +#include // For MIN/MAX +#include + +#include "spi_flash_lowlevel_driver.h" +#include "spi_flash_lowlevel_generic.h" + +#define SPI_FLASH_GENERIC_CHIP_ERASE_TIMEOUT 4000 +#define SPI_FLASH_GENERIC_SECTOR_ERASE_TIMEOUT 500 +#define SPI_FLASH_GENERIC_BLOCK_ERASE_TIMEOUT 1000 + +#define DEFAULT_IDLE_TIMEOUT 200 +#define DEFAULT_PAGE_PROGRAM_TIMEOUT 500 + +/* Hardware host-specific constants */ +#define MAX_WRITE_BYTES 32 +#define MAX_READ_BYTES 64 + +#define ADDRESS_MASK_24BIT 0xFFFFFF + +uint32_t spi_flash_common_command(const esp_flash_chip_t *chip, uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len) +{ + typeof(chip->spi->user2) user2 = { + .usr_command_value = command, + .usr_command_bitlen = (8 -1), + }; + chip->spi->user2 = user2; + + typeof(chip->spi->user) user = { + .usr_miso = miso_len > 0, + .usr_mosi = mosi_len > 0, + .usr_dummy = 0, + .usr_command = 1, + }; + chip->spi->user = user; + + chip->spi->ctrl.val = 0; + chip->spi->miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0; + chip->spi->mosi_dlen.usr_mosi_dbitlen = mosi_len ? (mosi_len - 1) : 0; + + // TODO: there's a bug(?) here where if multiple bytes are written + // with each byte MSB-first (correct), but the bytes are + // written out LSB first... + // + // May be easier to just document this in the function interface... + chip->spi->data_buf[0] = mosi_data; + + if (spi_flash_uses_gpio_matrix(chip)) { + /* When flash pins are mapped via GPIO matrix, need a dummy cycle before reading via MISO */ + if (chip->speed == ESP_FLASH_80MHZ) { + chip->spi->user.usr_dummy = 1; + chip->spi->user1.usr_dummy_cyclelen = 1; + } else { + chip->spi->user.usr_dummy = 1; + chip->spi->user1.usr_dummy_cyclelen = 0; + } + } + + chip->spi->cmd.usr = 1; + while(chip->spi->cmd.usr != 0) + { } + + uint32_t miso = chip->spi->data_buf[0]; + + return miso; +} + +esp_flash_err_t spi_flash_generic_probe(esp_flash_chip_t *chip, uint32_t flash_id) +{ + // This is the catch-all probe function, claim the chip always if nothing + // else has claimed it yet. + return FLASH_OK; +} + +esp_flash_err_t spi_flash_generic_read_id(const esp_flash_chip_t *chip, uint32_t *id) +{ + uint32_t raw_flash_id = spi_flash_common_command(chip, CMD_RDID, 0, 0, 24); + if (raw_flash_id == 0xFFFFFF || raw_flash_id == 0) { + return FLASH_ERR_NO_RESPONSE; + } + + // Byte swap the flash id as it's usually written the other way around + uint8_t mfg_id = raw_flash_id & 0xFF; + uint16_t flash_id = (raw_flash_id >> 16) | (raw_flash_id & 0xFF00); + + *id = ((uint32_t)mfg_id << 16) | flash_id; + return FLASH_OK; +} + + +esp_flash_err_t spi_flash_generic_detect_size(const esp_flash_chip_t *chip, uint32_t *size) +{ + uint32_t id = 0; + *size = 0; + esp_flash_err_t err = chip->drv->read_id(chip, &id); + if (err != FLASH_OK) { + return err; + } + + /* Can't detect size unless the high byte of the product ID matches the same convention, which is usually 0x40 or + * 0xC0 or similar. */ + if ((id & 0x0F00) != 0) { + return FLASH_ERR_UNSUPPORTED_CHIP; + } + + *size = 1 << (id & 0xFF); + + return FLASH_OK; +} + + +esp_flash_err_t spi_flash_generic_erase_chip(const esp_flash_chip_t *chip) +{ + esp_flash_err_t err; + + err = chip->drv->write_enable(chip); + if (err == FLASH_OK) { + err = chip->drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); + } + if (err == FLASH_OK) { + chip->spi->ctrl.val = 0; + chip->spi->cmd.flash_ce = 1; + while(chip->spi->cmd.val != 0) { } + err = chip->drv->wait_idle(chip, SPI_FLASH_GENERIC_CHIP_ERASE_TIMEOUT); + } + + return err; +} + +esp_flash_err_t spi_flash_generic_erase_sector(const esp_flash_chip_t *chip, uint32_t start_address) +{ + esp_flash_err_t err = chip->drv->write_enable(chip); + if (err == FLASH_OK) { + err = chip->drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); + } + if (err == FLASH_OK) { + chip->spi->user1.usr_addr_bitlen = (24 - 1); + chip->spi->addr = start_address & ADDRESS_MASK_24BIT; + chip->spi->ctrl.val = 0; + chip->spi->cmd.flash_se = 1; + while(chip->spi->cmd.val != 0) { } + err = chip->drv->wait_idle(chip, SPI_FLASH_GENERIC_SECTOR_ERASE_TIMEOUT); + } + return err; +} + +esp_flash_err_t spi_flash_generic_erase_block(const esp_flash_chip_t *chip, uint32_t start_address) +{ + esp_flash_err_t err = chip->drv->write_enable(chip); + if (err == FLASH_OK) { + err = chip->drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); + } + if (err == FLASH_OK) { + chip->spi->user1.usr_addr_bitlen = (24 - 1); + chip->spi->addr = start_address & ADDRESS_MASK_24BIT; + chip->spi->cmd.flash_be = 1; + while(chip->spi->cmd.val != 0) { } + err = chip->drv->wait_idle(chip, SPI_FLASH_GENERIC_BLOCK_ERASE_TIMEOUT); + } + return err; +} + +esp_flash_err_t spi_flash_generic_read(const esp_flash_chip_t *chip, void *buffer, uint32_t address, uint32_t length) +{ + esp_flash_err_t err = FLASH_OK; + + while (err == FLASH_OK && length > 0) { + uint32_t read_len = MIN(length, MAX_READ_BYTES); + chip->spi->miso_dlen.usr_miso_dbitlen = (read_len * 8) - 1; + chip->spi->addr = address << 8; + + chip->spi->cmd.usr = 1; + while(chip->spi->cmd.val != 0) {} + + if(((intptr_t)buffer % 4 == 0) && (read_len % 4 == 0)) { + // If everything is word-aligned, do a faster memcpy + xthal_memcpy(buffer, (void *)chip->spi->data_buf, read_len); + length -= read_len; + buffer = (void *)((intptr_t)buffer + read_len); + address += read_len; + } else { + // Otherwise, slow(er) path copies word by word + for (int i = 0; i < (read_len+3)/4; i++) { + int word_len = MIN(sizeof(uint32_t), length); + uint32_t word = chip->spi->data_buf[i]; + xthal_memcpy(buffer, &word, word_len); + length -= word_len; + buffer = (void *)((intptr_t)buffer + word_len); + address += word_len; + } + } + } + + + return err; +} + +esp_flash_err_t spi_flash_generic_page_program(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length) +{ + esp_flash_err_t err; + + err = chip->drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); + + if (err == FLASH_OK) { + err = chip->drv->write_enable(chip); + } + + if (err == FLASH_OK) { + // Perform the actual Page Program command + chip->spi->user.usr_dummy = 0; + chip->spi->user1.usr_addr_bitlen = (24 - 1); + chip->spi->addr = (address & ADDRESS_MASK_24BIT) | (length << 24); + + // Load data registers, word at a time + int num_words = (length+3) / 4; + for (int i = 0; i < num_words; i++) { + uint32_t word = 0; + uint32_t word_len = MIN(length, sizeof(word)); + xthal_memcpy(&word, buffer, word_len); + chip->spi->data_buf[i] = word; + length -= word_len; + buffer = (void *)((intptr_t)buffer + word_len); + } + + chip->spi->cmd.flash_pp = 1; + while (chip->spi->cmd.val != 0) { } + + err = chip->drv->wait_idle(chip, DEFAULT_PAGE_PROGRAM_TIMEOUT); + } + + + return err; +} + +esp_flash_err_t spi_flash_generic_write(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length) +{ + esp_flash_err_t err = FLASH_OK; + const uint32_t page_size = chip->drv->page_size; + + while (err == FLASH_OK && length > 0) { + uint32_t page_len = MIN(MAX_WRITE_BYTES, MIN(page_size, length)); + if ((address + page_len) / page_size != address / page_size) { + // Most flash chips can't page write across a page boundary + page_len = page_size - (address % page_size); + } + err = chip->drv->page_program(chip, address, buffer, page_len); + address += page_len; + buffer = (void *)((intptr_t)buffer + page_len); + length -= page_len; + } + + + return err; +} + +esp_flash_err_t spi_flash_generic_write_encrypted(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length) +{ + return FLASH_ERR_UNSUPPORTED_HOST; // TODO +} + +esp_flash_err_t spi_flash_generic_write_enable(const esp_flash_chip_t *chip) +{ + esp_flash_err_t err = FLASH_OK; + + err = chip->drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); + + if (err == FLASH_OK) { + chip->spi->cmd.flash_wren = 1; + while(chip->spi->cmd.val != 0) { } + } + + uint8_t status = spi_flash_common_command(chip, CMD_RDSR, 0, 0, 8); + if ((status & SR_WREN) == 0) { + // WREN flag has not been set! + err = FLASH_ERR_NOT_FOUND; + } + + + return err; +} + +esp_flash_err_t spi_flash_generic_wait_host_idle(const esp_flash_chip_t *chip, uint32_t *timeout_ms) +{ + while(chip->spi->ext2.st != 0 && *timeout_ms > 0) { + if (*timeout_ms > 1) { + esp_flash_os_functions->delay_ms(1); + } + (*timeout_ms)--; + } + + // Not clear if this is necessary, or only necessary if + // chip->spi == SPI1. But probably doesn't hurt... + while(SPI0.ext2.st != 0 && *timeout_ms > 0) { + if (*timeout_ms > 1) { + esp_flash_os_functions->delay_ms(1); + } + (*timeout_ms)--; + } + + return (*timeout_ms > 0) ? FLASH_OK : FLASH_ERR_NO_RESPONSE; +} + +esp_flash_err_t spi_flash_generic_wait_idle(const esp_flash_chip_t *chip, uint32_t timeout_ms) +{ + timeout_ms++; // allow at least one pass before timeout, last one has no sleep cycle + + uint8_t status = 0; + while(timeout_ms > 0) { + + esp_flash_err_t err = spi_flash_generic_wait_host_idle(chip, &timeout_ms); + if (err != FLASH_OK) { + return err; + } + + status = spi_flash_common_command(chip, CMD_RDSR, 0, 0, 8); + if ((status & SR_WIP) == 0) { + break; // Write in progress is complete + } + if (timeout_ms > 1) { + esp_flash_os_functions->delay_ms(1); + } + timeout_ms--; + } + + return (timeout_ms > 0) ? FLASH_OK : FLASH_ERR_NO_RESPONSE; +} + +esp_flash_err_t spi_flash_common_configure_host_read_mode(const esp_flash_chip_t *chip) +{ + int dummy_cyclelen, addr_bitlen, read_command; + switch(chip->read_mode) { + case ESP_FLASH_QIO: + addr_bitlen = 32; + dummy_cyclelen = 4; // TODO check this works + read_command = CMD_FASTRD_QIO; + break; + case ESP_FLASH_QOUT: + addr_bitlen = 24; + dummy_cyclelen = 8; // TODO check this works + read_command = CMD_FASTRD_QUAD; + break; + case ESP_FLASH_DIO: + addr_bitlen = 32; + dummy_cyclelen = 0; + read_command = CMD_FASTRD_DIO; + break; + case ESP_FLASH_DOUT: + addr_bitlen = 24; + dummy_cyclelen = 8; + read_command = CMD_FASTRD_DUAL; + break; + case ESP_FLASH_FASTRD: + addr_bitlen = 24; + dummy_cyclelen = 8; + read_command = CMD_FASTRD; + break; + case ESP_FLASH_SLOWRD: + addr_bitlen = 24; + dummy_cyclelen = 0; + read_command = CMD_READ; + break; + default: + return FLASH_ERR_NOT_INITIALISED; + } + + // Add dummy cycles to compensate for GPIO matrix + // latency, if necessary... + if (spi_flash_uses_gpio_matrix(chip)) { + if (chip->speed == ESP_FLASH_80MHZ) { + dummy_cyclelen += 2; + } else if (chip->speed == ESP_FLASH_40MHZ) { + dummy_cyclelen += 1; + } + } + + chip->spi->user1.usr_dummy_cyclelen = (dummy_cyclelen - 1); + chip->spi->user1.usr_addr_bitlen = (addr_bitlen - 1); + chip->spi->user2.usr_command_value = read_command; + chip->spi->user2.usr_command_bitlen = (8 - 1); + + typeof (chip->spi->user) user = { + .usr_command = 1, + .usr_mosi = 0, + .usr_miso = 1, + .usr_dummy = (dummy_cyclelen > 0) ? 1 : 0, + .usr_addr = 1, + }; + chip->spi->user = user; + + typeof (chip->spi->ctrl) ctrl = { + .fread_qio = (chip->read_mode == ESP_FLASH_QIO), + .fread_quad = (chip->read_mode == ESP_FLASH_QOUT), + .fread_dio = (chip->read_mode == ESP_FLASH_DIO), + .fread_dual = (chip->read_mode == ESP_FLASH_DOUT), + .fastrd_mode = (chip->read_mode != ESP_FLASH_SLOWRD), + }; + chip->spi->ctrl = ctrl; + + return FLASH_OK; +} + +#include + +esp_flash_err_t spi_flash_common_set_read_mode(const esp_flash_chip_t *chip, uint8_t qe_rdsr_command, uint8_t qe_wrsr_command, uint8_t qe_sr_bitwidth, unsigned qe_sr_bit) +{ + if (spi_flash_is_quad_mode(chip)) { + // Ensure quad modes are enabled, using the Quad Enable parameters supplied. + unsigned sr = spi_flash_common_command(chip, qe_rdsr_command, 0, 0, qe_sr_bitwidth); + ets_printf("before 0x%x\n", sr); + if ((sr & qe_sr_bit) == 0) { + sr |= qe_sr_bit; + spi_flash_common_command(chip, qe_wrsr_command, sr, qe_sr_bitwidth, 0); + + /* Check the new QE bit has stayed set */ + sr = spi_flash_common_command(chip, qe_rdsr_command, 0, 0, qe_sr_bitwidth); + ets_printf("after 0x%x\n", sr); + if ((sr & qe_sr_bit) == 0) { + return FLASH_ERR_NO_RESPONSE; + } + } + } + + // Configure the host, and return + return spi_flash_common_configure_host_read_mode(chip); +} + +esp_flash_err_t spi_flash_generic_set_read_mode(const esp_flash_chip_t *chip) +{ + // On "generic" chips, this involves checking + // bit 1 (QE) of RDSR2 (35h) result + // (it works this way on GigaDevice & Fudan Micro chips, probably others...) + const uint8_t BIT_QE = 1<<1; + return spi_flash_common_set_read_mode(chip, CMD_RDSR2, CMD_WRSR2, 8, BIT_QE); +} + +bool spi_flash_uses_gpio_matrix(const esp_flash_chip_t *chip) +{ + if (chip->pins == NULL) { + return false; + } + if (chip->pins->mosi_io_num != -1 + || chip->pins->miso_io_num != -1 + || chip->pins->sclk_io_num != -1) { + return true; + } + if (spi_flash_is_quad_mode(chip)) { + if (chip->pins->quadwp_io_num != -1 + || chip->pins->quadhd_io_num != -1) { + return true; + } + } + return false; +} + +const esp_flash_driver_t esp_flash_generic_chip_driver = { + .probe = spi_flash_generic_probe, + .read_id = spi_flash_generic_read_id, + .detect_size = spi_flash_generic_detect_size, + .erase_chip = spi_flash_generic_erase_chip, + .erase_sector = spi_flash_generic_erase_sector, + .erase_block = spi_flash_generic_erase_block, + .sector_size = 4 * 1024, + .block_erase_size = 64 * 1024, + + // TODO: figure out if generic chip-wide protection bits exist across some manufacturers + .get_chip_write_protect = NULL, + .set_chip_write_protect = NULL, + + // Chip write protection regions do not appear to be standardised + // at all, this is implemented in chip-specific drivers only. + .num_protectable_regions = 0, + .protectable_regions = NULL, + .get_protected_regions = NULL, + .set_protected_regions = NULL, + + .read = spi_flash_generic_read, + .write = spi_flash_generic_write, + .page_program = spi_flash_generic_page_program, + .page_size = 256, + .write_encrypted = spi_flash_generic_write_encrypted, + + .write_enable = spi_flash_generic_write_enable, + .wait_idle = spi_flash_generic_wait_idle, + .set_read_mode = spi_flash_generic_set_read_mode, +}; diff --git a/components/spi_flash/spi_flash_lowlevel_idf_app.c b/components/spi_flash/spi_flash_lowlevel_idf_app.c new file mode 100644 index 0000000000..9b71a1e863 --- /dev/null +++ b/components/spi_flash/spi_flash_lowlevel_idf_app.c @@ -0,0 +1,60 @@ +// Copyright 2017 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 +#include "spi_flash_lowlevel_driver.h" + +#include "rom/ets_sys.h" +#include "esp_attr.h" +#include "esp_spi_flash.h" + +static esp_flash_err_t start(const esp_flash_chip_t *chip) +{ + if (chip->spi == &SPI1) { + g_flash_guard_default_ops.start(); + } + + // TODO figure out if we can coexist with the SPI master driver here, for other peripherals + + return FLASH_OK; +} +static esp_flash_err_t end(const esp_flash_chip_t *chip) +{ + if (chip->spi == &SPI1) { + g_flash_guard_default_ops.end(); + } + + // TODO figure out if we can coexist with the SPI master driver here, for other peripherals + + return FLASH_OK; +} + +static esp_flash_err_t delay_ms(unsigned ms) +{ + ets_delay_us(1000 * ms); + return FLASH_OK; +} + + +const esp_flash_os_functions_t default_os_functions = { + .start = start, + .end = end, + .delay_ms = delay_ms, +}; + +void esp_flash_low_level_app_init() +{ + esp_flash_os_functions = &default_os_functions; +} + + diff --git a/components/spi_flash/spi_flash_lowlevel_issi.c b/components/spi_flash/spi_flash_lowlevel_issi.c new file mode 100644 index 0000000000..f97ec5a0c0 --- /dev/null +++ b/components/spi_flash/spi_flash_lowlevel_issi.c @@ -0,0 +1,74 @@ +// Copyright 2017 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 +#include "spi_flash_lowlevel_driver.h" +#include "spi_flash_lowlevel_generic.h" + +/* Driver for ISSI flash chip, as used in ESP32 D2WD */ + +esp_flash_err_t issi_probe(esp_flash_chip_t *chip, uint32_t flash_id) +{ + /* Check manufacturer and product IDs match our desired masks */ + const uint8_t MFG_ID = 0x9D; + if (flash_id >> 16 != MFG_ID) { + return FLASH_ERR_NOT_FOUND; + } + + const uint16_t FLASH_ID_MASK = 0xCF00; + const uint16_t FLASH_ID_VALUE = 0x4000; + if ((flash_id & FLASH_ID_MASK) != FLASH_ID_VALUE) { + return FLASH_ERR_NOT_FOUND; + } + + return FLASH_OK; +} + +esp_flash_err_t issi_set_read_mode(const esp_flash_chip_t *chip) +{ + /* ISSI uses bit 6 of "basic" SR as Quad Enable */ + const uint8_t BIT_QE = 1<<6; + return spi_flash_common_set_read_mode(chip, CMD_RDSR, CMD_WRSR, 8, BIT_QE); +} + + +const esp_flash_driver_t esp_flash_issi_chip_driver = { + .probe = issi_probe, + .read_id = spi_flash_generic_read_id, + .detect_size = spi_flash_generic_detect_size, + .erase_chip = spi_flash_generic_erase_chip, + .erase_sector = spi_flash_generic_erase_sector, + .erase_block = spi_flash_generic_erase_block, + .sector_size = 4 * 1024, + .block_erase_size = 64 * 1024, + + // TODO: support get/set chip write protect for ISSI flash + .get_chip_write_protect = NULL, + .set_chip_write_protect = NULL, + + // TODO support protected regions on ISSI flash + .num_protectable_regions = 0, + .protectable_regions = NULL, + .get_protected_regions = NULL, + .set_protected_regions = NULL, + + .read = spi_flash_generic_read, + .write = spi_flash_generic_write, + .page_program = spi_flash_generic_page_program, + .page_size = 256, + .write_encrypted = spi_flash_generic_write_encrypted, + + .write_enable = spi_flash_generic_write_enable, + .wait_idle = spi_flash_generic_wait_idle, + .set_read_mode = issi_set_read_mode, +}; diff --git a/components/spi_flash/spi_flash_lowlevel_noos.c b/components/spi_flash/spi_flash_lowlevel_noos.c new file mode 100644 index 0000000000..3fb4b8c4bd --- /dev/null +++ b/components/spi_flash/spi_flash_lowlevel_noos.c @@ -0,0 +1,51 @@ +// Copyright 2017 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 +#include "spi_flash_lowlevel_driver.h" + +#include "rom/ets_sys.h" +#include "rom/cache.h" +#include "esp_attr.h" +#include "esp_spi_flash.h" + +static esp_flash_err_t start(const esp_flash_chip_t *chip) +{ + if (chip->spi == &SPI1) { + Cache_Read_Disable(0); + Cache_Read_Disable(1); + } + return FLASH_OK; +} +static esp_flash_err_t end(const esp_flash_chip_t *chip) +{ + if (chip->spi == &SPI1) { + Cache_Flush(0); + Cache_Flush(1); + Cache_Read_Enable(0); + Cache_Read_Enable(1); + } + return FLASH_OK; +} + +static esp_flash_err_t delay_ms(unsigned ms) +{ + ets_delay_us(1000 * ms); + return FLASH_OK; +} + +const esp_flash_os_functions_t esp_flash_noos_functions = { + .start = start, + .end = end, + .delay_ms = delay_ms, +}; diff --git a/components/spi_flash/test/test_low_level.c b/components/spi_flash/test/test_low_level.c new file mode 100644 index 0000000000..da77f892fb --- /dev/null +++ b/components/spi_flash/test/test_low_level.c @@ -0,0 +1,181 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +static uint8_t sector_buf[4096]; + +TEST_CASE("SPI flash metadata functions", "[spi_flash_ll]") +{ + uint32_t id, size; + + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_read_id(NULL, &id) ); + + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_detect_size(NULL, &size) ); + + printf("Flash ID %08x detected size %d bytes\n", id, size); +} + +static uint32_t erase_test_region(int num_sectors) +{ + const esp_partition_t *part = get_test_data_partition(); + uint32_t offs = part->address; + + /* chip should be initialised */ + TEST_ASSERT(esp_flash_default_chip != NULL + && esp_flash_default_chip->drv != NULL); + + TEST_ASSERT(num_sectors * 4096 <= part->size); + + bzero(sector_buf, sizeof(sector_buf)); + + printf("Erase @ 0x%x...\n", offs); + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_erase_region(NULL, offs, num_sectors * 4096) ); + + printf("Verify erased...\n"); + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_read(NULL, sector_buf, offs, sizeof(sector_buf)) ); + + printf("Buffer starts 0x%02x 0x%02x 0x%02x 0x%02x\n", sector_buf[0], sector_buf[1], sector_buf[2], sector_buf[3]); + for (int i = 0; i < sizeof(sector_buf); i++) { + TEST_ASSERT_EQUAL_HEX8(0xFF, sector_buf[i]); + } + + return offs; +} + +TEST_CASE("SPI flash simple read/write", "[spi_flash_ll]") +{ + uint32_t offs = erase_test_region(1); + + for (int i =0 ; i < sizeof(sector_buf); i++) { + sector_buf[i] = i & 0xFF; + } + + printf("Write...\n"); + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_write(NULL, offs, sector_buf, sizeof(sector_buf)) ); + + bzero(sector_buf, sizeof(sector_buf)); + + printf("Read back...\n"); + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_read(NULL, sector_buf, offs, sizeof(sector_buf)) ); + + printf("Buffer starts 0x%02x 0x%02x 0x%02x 0x%02x\n", sector_buf[0], sector_buf[1], sector_buf[2], sector_buf[3]); + + for (int i = 0; i < sizeof(sector_buf); i++) { + TEST_ASSERT_EQUAL_HEX8(i & 0xFF, sector_buf[i]); + } +} + +TEST_CASE("SPI flash unaligned read/write", "[spi_flash_ll]") +{ + uint32_t offs = erase_test_region(2); + + const char *msg = "i am a message"; + TEST_ASSERT(strlen(msg)+1 % 4 != 0); + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_write(NULL, offs+1, msg, strlen(msg)+1) ); + + char buf[strlen(msg) + 1]; + + memset(buf, 0xEE, sizeof(buf)); + + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_read(NULL, buf, offs+1, strlen(msg)+1) ); + TEST_ASSERT_EQUAL_STRING_LEN(msg, buf, strlen(msg)); + TEST_ASSERT(memcmp(buf, msg, strlen(msg)+1) == 0); +} + + +TEST_CASE("SPI flash single byte reads/writes", "[spi_flash_ll]") +{ + uint32_t offs = erase_test_region(2); + + for (unsigned v = 0; v < 512; v++) { + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_write(NULL, offs+v, &v, 1) ); + } + + for (unsigned v = 0; v < 512; v++) { + uint8_t readback; + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_read(NULL, &readback, offs+v, 1) ); + TEST_ASSERT_EQUAL_HEX8(v, readback); + } +} + +/* this test is notable because it generates a lot of unaligned reads/writes, + and also reads/writes across both a sector boundary & many page boundaries. +*/ +TEST_CASE("SPI flash three byte reads/writes", "[spi_flash_ll]") +{ + uint32_t offs = erase_test_region(2); + + for (uint32_t v = 0; v < 2000; v++) { + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_write(NULL, offs+3*v, &v, 3) ); + } + + for (uint32_t v = 0; v < 2000; v++) { + uint32_t readback; + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_read(NULL, &readback, offs+3*v, 3) ); + TEST_ASSERT_EQUAL_HEX32(v & 0xFFFFFF, readback & 0xFFFFFF); + } +} + +TEST_CASE("SPI flash erase large region", "[spi_flash_ll]") +{ + const esp_partition_t *part = get_test_data_partition(); + + /* Write some noise at the start and the end of the region */ + const char *ohai = "OHAI"; + uint32_t readback; + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_write(NULL, part->address, ohai, 5)); + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_write(NULL, part->address + part->size - 5, ohai, 5)); + + /* sanity check what we just wrote */ + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_read(NULL, &readback, part->address + part->size - 5, 4)); + TEST_ASSERT_EQUAL_HEX32(*((const uint32_t*)ohai), readback); + + /* Erase whole region */ + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_erase_region(NULL, part->address, part->size)); + + /* ensure both areas we wrote are now all-FFs */ + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_read(NULL, &readback, part->address, 4)); + TEST_ASSERT_EQUAL_HEX32(0xFFFFFFFF, readback); + + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_read(NULL, &readback, part->address + part->size - 5, 4)); + TEST_ASSERT_EQUAL_HEX32(0xFFFFFFFF, readback); +} + +TEST_CASE("SPI flash test reading with all speed/mode permutations", "[spi_flash_ll]") +{ + /* Note: this only works if the SPI flash chip supports all these modes & speeds */ + + uint32_t offs = erase_test_region(1); + + /* Write some test data */ + const char *message = "This is some test data."; + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_write(NULL, offs, message, strlen(message)+1) ); + + // Start by copying the default chip to a structure we can tweak + esp_flash_chip_t chip = *esp_flash_default_chip; + + for (chip.read_mode = 0; + chip.read_mode != ESP_FLASH_READ_MODE_MAX; + chip.read_mode++) { + for (chip.speed = 0; + chip.speed != ESP_FLASH_SPEED_MAX; + chip.speed++) { + printf("mode %d speed %d\n", chip.read_mode, chip.speed); + + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_init(&chip) ); + + char *buf[strlen(message)+1]; + memset(buf, 0xFF, sizeof(buf)); + TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_read(&chip, buf, offs, sizeof(buf)) ); + TEST_ASSERT_EQUAL_STRING_LEN(message, buf, strlen(message)); + } + } +} From 1036a091fe6876471ba4efd69cecd19daf974d17 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Tue, 8 Jan 2019 18:29:25 +0800 Subject: [PATCH 070/486] spi_flash: support working on differnt buses and frequency --- .gitlab-ci.yml | 6 + .../include/esp_flash_partitions.h | 11 + components/esp32/cpu_start.c | 10 +- components/esp_common/include/esp_err.h | 1 + .../test_fatfs_host/sdkconfig/sdkconfig.h | 2 + components/soc/CMakeLists.txt | 2 + .../soc/esp32/include/hal/spi_flash_ll.h | 370 +++++++++ components/soc/esp32/include/soc/spi_pins.h | 10 +- components/soc/include/hal/esp_flash_err.h | 39 + components/soc/include/hal/spi_flash_hal.h | 243 ++++++ .../soc/include/hal/spi_flash_host_drv.h | 112 +++ components/soc/linker.lf | 4 +- components/soc/src/hal/spi_flash_hal.c | 74 ++ components/soc/src/hal/spi_flash_hal_iram.c | 144 ++++ components/spi_flash/CMakeLists.txt | 13 +- components/spi_flash/Kconfig | 17 + components/spi_flash/README.rst | 100 ++- components/spi_flash/README_legacy.rst | 127 +++ components/spi_flash/component.mk | 1 + components/spi_flash/esp_flash_api.c | 747 ++++++++++++++++++ components/spi_flash/flash_ops.c | 32 +- .../{spi_flash_lowlevel.h => esp_flash.h} | 207 ++--- components/spi_flash/include/esp_spi_flash.h | 3 +- .../spi_flash/include/memspi_host_driver.h | 111 +++ ...level_driver.h => spi_flash_chip_driver.h} | 121 ++- .../include/spi_flash_chip_generic.h | 275 +++++++ .../spi_flash/include/spi_flash_chip_issi.h | 27 + .../include/spi_flash_lowlevel_generic.h | 151 ---- components/spi_flash/linker.lf | 8 +- components/spi_flash/memspi_host_driver.c | 101 +++ components/spi_flash/partition.c | 17 + .../private_include/spi_flash_defs.h | 44 ++ components/spi_flash/spi_flash_chip_drivers.c | 38 + components/spi_flash/spi_flash_chip_generic.c | 405 ++++++++++ ..._lowlevel_issi.c => spi_flash_chip_issi.c} | 53 +- components/spi_flash/spi_flash_lowlevel_api.c | 552 ------------- .../spi_flash/spi_flash_lowlevel_driver.c | 34 - .../spi_flash/spi_flash_lowlevel_generic.c | 498 ------------ .../spi_flash/spi_flash_lowlevel_idf_app.c | 60 -- components/spi_flash/spi_flash_os_func_app.c | 125 +++ ...wlevel_noos.c => spi_flash_os_func_noos.c} | 41 +- .../spi_flash/test/test_cache_disabled.c | 2 +- components/spi_flash/test/test_esp_flash.c | 549 +++++++++++++ .../spi_flash/test/test_large_flash_writes.c | 4 +- components/spi_flash/test/test_low_level.c | 181 ----- components/spi_flash/test/test_mmap.c | 4 +- .../spi_flash/test/test_out_of_bounds_write.c | 4 +- components/spi_flash/test/test_partitions.c | 2 +- components/spi_flash/test/test_read_write.c | 10 +- components/spi_flash/test/test_spi_flash.c | 4 +- .../test_spiffs_host/sdkconfig/sdkconfig.h | 2 + .../test_wl_host/sdkconfig/sdkconfig.h | 3 + 52 files changed, 3974 insertions(+), 1727 deletions(-) create mode 100644 components/soc/esp32/include/hal/spi_flash_ll.h create mode 100644 components/soc/include/hal/esp_flash_err.h create mode 100644 components/soc/include/hal/spi_flash_hal.h create mode 100644 components/soc/include/hal/spi_flash_host_drv.h create mode 100644 components/soc/src/hal/spi_flash_hal.c create mode 100644 components/soc/src/hal/spi_flash_hal_iram.c create mode 100644 components/spi_flash/README_legacy.rst create mode 100644 components/spi_flash/esp_flash_api.c rename components/spi_flash/include/{spi_flash_lowlevel.h => esp_flash.h} (54%) create mode 100644 components/spi_flash/include/memspi_host_driver.h rename components/spi_flash/include/{spi_flash_lowlevel_driver.h => spi_flash_chip_driver.h} (55%) create mode 100644 components/spi_flash/include/spi_flash_chip_generic.h create mode 100644 components/spi_flash/include/spi_flash_chip_issi.h delete mode 100644 components/spi_flash/include/spi_flash_lowlevel_generic.h create mode 100644 components/spi_flash/memspi_host_driver.c create mode 100644 components/spi_flash/private_include/spi_flash_defs.h create mode 100644 components/spi_flash/spi_flash_chip_drivers.c create mode 100644 components/spi_flash/spi_flash_chip_generic.c rename components/spi_flash/{spi_flash_lowlevel_issi.c => spi_flash_chip_issi.c} (53%) delete mode 100644 components/spi_flash/spi_flash_lowlevel_api.c delete mode 100644 components/spi_flash/spi_flash_lowlevel_driver.c delete mode 100644 components/spi_flash/spi_flash_lowlevel_generic.c delete mode 100644 components/spi_flash/spi_flash_lowlevel_idf_app.c create mode 100644 components/spi_flash/spi_flash_os_func_app.c rename components/spi_flash/{spi_flash_lowlevel_noos.c => spi_flash_os_func_noos.c} (54%) create mode 100644 components/spi_flash/test/test_esp_flash.c delete mode 100644 components/spi_flash/test/test_low_level.c diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e8c830caa6..b771bd3011 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1584,6 +1584,12 @@ UT_001_43: - ESP32_IDF - UT_T1_1 +UT_001_44: + <<: *unit_test_template + tags: + - ESP32_IDF + - UT_T1_1 + UT_002_01: <<: *unit_test_template tags: diff --git a/components/bootloader_support/include/esp_flash_partitions.h b/components/bootloader_support/include/esp_flash_partitions.h index e5305d836d..e652cc300c 100644 --- a/components/bootloader_support/include/esp_flash_partitions.h +++ b/components/bootloader_support/include/esp_flash_partitions.h @@ -103,6 +103,17 @@ inline static __attribute__((deprecated)) esp_err_t esp_partition_table_basic_ve { return esp_partition_table_verify(partition_table, log_errors, num_partitions); } + +/** + * Check whether the region on the main flash is safe to write. + * + * @param addr Start address of the region + * @param size Size of the region + * + * @return true if the region is safe to write, otherwise false. + */ +bool esp_partition_main_flash_region_safe(size_t addr, size_t size); + #ifdef __cplusplus } #endif diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 266c7f5e30..3a782f2985 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -43,7 +43,7 @@ #include "sdkconfig.h" #include "esp_system.h" #include "esp_spi_flash.h" -#include "spi_flash_lowlevel.h" +#include "esp_flash.h" #include "nvs_flash.h" #include "esp_event.h" #include "esp_spi_flash.h" @@ -389,9 +389,10 @@ void start_cpu0_default(void) spi_flash_init(); /* init default OS-aware flash access critical section */ spi_flash_guard_set(&g_flash_guard_default_ops); - /* Todo the following needs to be properly integrated */ - esp_flash_low_level_app_init(); - esp_flash_init_default_chip(); + + esp_flash_app_init(); + esp_err_t flash_ret = esp_flash_init_default_chip(); + assert(flash_ret == ESP_OK); #ifdef CONFIG_PM_ENABLE esp_pm_impl_init(); #ifdef CONFIG_PM_DFS_INIT_AUTO @@ -403,6 +404,7 @@ void start_cpu0_default(void) esp_pm_configure(&cfg); #endif //CONFIG_PM_DFS_INIT_AUTO #endif //CONFIG_PM_ENABLE + #if CONFIG_ESP32_ENABLE_COREDUMP esp_core_dump_init(); size_t core_data_sz = 0; diff --git a/components/esp_common/include/esp_err.h b/components/esp_common/include/esp_err.h index c46ae38372..105723976d 100644 --- a/components/esp_common/include/esp_err.h +++ b/components/esp_common/include/esp_err.h @@ -41,6 +41,7 @@ typedef int32_t esp_err_t; #define ESP_ERR_WIFI_BASE 0x3000 /*!< Starting number of WiFi error codes */ #define ESP_ERR_MESH_BASE 0x4000 /*!< Starting number of MESH error codes */ +#define ESP_ERR_FLASH_BASE 0x6000 /*!< Starting number of flash error codes */ /** * @brief Returns string for esp_err_t error codes diff --git a/components/fatfs/test_fatfs_host/sdkconfig/sdkconfig.h b/components/fatfs/test_fatfs_host/sdkconfig/sdkconfig.h index 45ca4b7061..05ff65a5cc 100644 --- a/components/fatfs/test_fatfs_host/sdkconfig/sdkconfig.h +++ b/components/fatfs/test_fatfs_host/sdkconfig/sdkconfig.h @@ -4,3 +4,5 @@ #define CONFIG_LOG_DEFAULT_LEVEL 3 #define CONFIG_PARTITION_TABLE_OFFSET 0x8000 #define CONFIG_ESPTOOLPY_FLASHSIZE "8MB" +//currently use the legacy implementation, since the stubs for new HAL are not done yet +#define CONFIG_SPI_FLASH_USE_LEGACY_IMPL diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index 3b5d84ebc6..572fb38f68 100644 --- a/components/soc/CMakeLists.txt +++ b/components/soc/CMakeLists.txt @@ -16,6 +16,8 @@ list(APPEND COMPONENT_SRCS "src/memory_layout_utils.c" "src/hal/spi_slave_hal.c" "src/hal/spi_slave_hal_iram.c" "src/soc_include_legacy_warn.c" + "src/hal/spi_flash_hal.c" + "src/hal/spi_flash_hal_iram.c" ) set(COMPONENT_ADD_LDFRAGMENTS linker.lf) diff --git a/components/soc/esp32/include/hal/spi_flash_ll.h b/components/soc/esp32/include/hal/spi_flash_ll.h new file mode 100644 index 0000000000..f9adbd5f1b --- /dev/null +++ b/components/soc/esp32/include/hal/spi_flash_ll.h @@ -0,0 +1,370 @@ +// Copyright 2015-2019 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. + +/******************************************************************************* + * NOTICE + * The ll is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +// The Lowlevel layer for SPI Flash + +#pragma once + +#include +#include "soc/spi_periph.h" +#include // For MIN/MAX +#include +#include + + +//Supported clock register values +#define SPI_FLASH_LL_CLKREG_VAL_5MHZ ((spi_flash_ll_clock_reg_t){.val=0x0000F1CF}) ///< Clock set to 5 MHz +#define SPI_FLASH_LL_CLKREG_VAL_10MHZ ((spi_flash_ll_clock_reg_t){.val=0x000070C7}) ///< Clock set to 10 MHz +#define SPI_FLASH_LL_CLKREG_VAL_20MHZ ((spi_flash_ll_clock_reg_t){.val=0x00003043}) ///< Clock set to 20 MHz +#define SPI_FLASH_LL_CLKREG_VAL_26MHZ ((spi_flash_ll_clock_reg_t){.val=0x00002002}) ///< Clock set to 26 MHz +#define SPI_FLASH_LL_CLKREG_VAL_40MHZ ((spi_flash_ll_clock_reg_t){.val=0x00001001}) ///< Clock set to 40 MHz +#define SPI_FLASH_LL_CLKREG_VAL_80MHZ ((spi_flash_ll_clock_reg_t){.val=0x80000000}) ///< Clock set to 80 MHz + +/// Get the start address of SPI peripheral registers by the host ID +#define spi_flash_ll_get_hw(n) ((n)==0||(n)==1? &SPI1:((n)==2?&SPI2:((n)==3?&SPI3:({abort();(spi_dev_t*)0;})))) + +///Slowest io mode supported by ESP32, currently SlowRd +#define SPI_FLASH_READ_MODE_MIN SPI_FLASH_SLOWRD + +/** @brief Mode used for reading from SPI flash */ +typedef enum { + SPI_FLASH_SLOWRD = 0, ///< Data read using single I/O, some limits on speed + SPI_FLASH_FASTRD, ///< Data read using single I/O, no limit on speed + SPI_FLASH_DOUT, ///< Data read using dual I/O + SPI_FLASH_DIO, ///< Both address & data transferred using dual I/O + SPI_FLASH_QOUT, ///< Data read using quad I/O + SPI_FLASH_QIO, ///< Both address & data transferred using quad I/O + + SPI_FLASH_READ_MODE_MAX, ///< The fastest io mode supported by the host is ``ESP_FLASH_READ_MODE_MAX-1``. +} esp_flash_read_mode_t; + +/// type to store pre-calculated register value in above layers +typedef typeof(SPI1.clock) spi_flash_ll_clock_reg_t; + +/*------------------------------------------------------------------------------ + * Control + *----------------------------------------------------------------------------*/ +/** + * Reset peripheral registers before configuration and starting control + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spi_flash_ll_reset(spi_dev_t *dev) +{ + dev->user.val = 0; + dev->ctrl.val = 0; +} + +/** + * Check whether the previous operation is done. + * + * @param dev Beginning address of the peripheral registers. + * + * @return true if last command is done, otherwise false. + */ +static inline bool spi_flash_ll_cmd_is_done(const spi_dev_t *dev) +{ + return (dev->cmd.val == 0); +} + +/** + * Erase the flash chip. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spi_flash_ll_erase_chip(spi_dev_t *dev) +{ + dev->cmd.flash_ce = 1; +} + +/** + * Erase the sector, the address should be set by spi_flash_ll_set_address. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spi_flash_ll_erase_sector(spi_dev_t *dev) +{ + dev->ctrl.val = 0; + dev->cmd.flash_se = 1; +} + +/** + * Erase the block, the address should be set by spi_flash_ll_set_address. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spi_flash_ll_erase_block(spi_dev_t *dev) +{ + dev->cmd.flash_be = 1; +} + +/** + * Enable/disable write protection for the flash chip. + * + * @param dev Beginning address of the peripheral registers. + * @param wp true to enable the protection, false to disable (write enable). + */ +static inline void spi_flash_ll_set_write_protect(spi_dev_t *dev, bool wp) +{ + if (wp) { + dev->cmd.flash_wrdi = 1; + } else { + dev->cmd.flash_wren = 1; + } +} + +/** + * Get the read data from the buffer after ``spi_flash_ll_read`` is done. + * + * @param dev Beginning address of the peripheral registers. + * @param buffer Buffer to hold the output data + * @param read_len Length to get out of the buffer + */ +static inline void spi_flash_ll_get_buffer_data(spi_dev_t *dev, void *buffer, uint32_t read_len) +{ + if (((intptr_t)buffer % 4 == 0) && (read_len % 4 == 0)) { + // If everything is word-aligned, do a faster memcpy + memcpy(buffer, (void *)dev->data_buf, read_len); + } else { + // Otherwise, slow(er) path copies word by word + int copy_len = read_len; + for (int i = 0; i < (read_len + 3) / 4; i++) { + int word_len = MIN(sizeof(uint32_t), copy_len); + uint32_t word = dev->data_buf[i]; + memcpy(buffer, &word, word_len); + buffer = (void *)((intptr_t)buffer + word_len); + copy_len -= word_len; + } + } +} + +/** + * Write a word to the data buffer. + * + * @param dev Beginning address of the peripheral registers. + * @param word Data to write at address 0. + */ +static inline void spi_flash_ll_write_word(spi_dev_t *dev, uint32_t word) +{ + dev->data_buf[0] = word; +} + +/** + * Program a page of the flash chip. Call ``spi_flash_ll_set_address`` before + * this to set the address to program. + * + * @param dev Beginning address of the peripheral registers. + * @param buffer Buffer holding the data to program + * @param length Length to program. + */ +static inline void spi_flash_ll_program_page(spi_dev_t *dev, const void *buffer, uint32_t length) +{ + dev->user.usr_dummy = 0; + + // Load data registers, word at a time + int num_words = (length + 3) / 4; + for (int i = 0; i < num_words; i++) { + uint32_t word = 0; + uint32_t word_len = MIN(length, sizeof(word)); + memcpy(&word, buffer, word_len); + dev->data_buf[i] = word; + length -= word_len; + buffer = (void *)((intptr_t)buffer + word_len); + } + + dev->cmd.flash_pp = 1; +} + +/** + * Trigger a user defined transaction. All phases, including command, address, dummy, and the data phases, + * should be configured before this is called. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spi_flash_ll_user_start(spi_dev_t *dev) +{ + dev->cmd.usr = 1; +} + +/** + * Check whether the host is idle to perform new commands. + * + * @param dev Beginning address of the peripheral registers. + * + * @return true if the host is idle, otherwise false + */ +static inline bool spi_flash_ll_host_idle(const spi_dev_t *dev) +{ + return dev->ext2.st != 0; +} + +/** + * Set phases for user-defined transaction to read + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spi_flash_ll_read_phase(spi_dev_t *dev) +{ + typeof (dev->user) user = { + .usr_command = 1, + .usr_mosi = 0, + .usr_miso = 1, + .usr_addr = 1, + }; + dev->user = user; +} +/*------------------------------------------------------------------------------ + * Configs + *----------------------------------------------------------------------------*/ +/** + * Select which pin to use for the flash + * + * @param dev Beginning address of the peripheral registers. + * @param pin Pin ID to use, 0-2. Set to other values to disable all the CS pins. + */ +static inline void spi_flash_ll_set_cs_pin(spi_dev_t *dev, int pin) +{ + dev->pin.cs0_dis = (pin == 0) ? 0 : 1; + dev->pin.cs1_dis = (pin == 1) ? 0 : 1; + dev->pin.cs2_dis = (pin == 2) ? 0 : 1; +} + +/** + * Set the read io mode. + * + * @param dev Beginning address of the peripheral registers. + * @param read_mode I/O mode to use in the following transactions. + */ +static inline void spi_flash_ll_set_read_mode(spi_dev_t *dev, esp_flash_read_mode_t read_mode) +{ + typeof (dev->ctrl) ctrl = dev->ctrl; + ctrl.val &= ~(SPI_FREAD_QIO_M | SPI_FREAD_QUAD_M | SPI_FREAD_DIO_M | SPI_FREAD_DUAL_M); + ctrl.val |= SPI_FASTRD_MODE_M; + switch (read_mode) { + case SPI_FLASH_FASTRD: + //the default option + break; + case SPI_FLASH_QIO: + ctrl.fread_qio = 1; + break; + case SPI_FLASH_QOUT: + ctrl.fread_quad = 1; + break; + case SPI_FLASH_DIO: + ctrl.fread_dio = 1; + break; + case SPI_FLASH_DOUT: + ctrl.fread_dual = 1; + break; + case SPI_FLASH_SLOWRD: + ctrl.fastrd_mode = 0; + break; + default: + abort(); + } + dev->ctrl = ctrl; +} + +/** + * Set clock frequency to work at. + * + * @param dev Beginning address of the peripheral registers. + * @param clock_val pointer to the clock value to set + */ +static inline void spi_flash_ll_set_clock(spi_dev_t *dev, spi_flash_ll_clock_reg_t *clock_val) +{ + dev->clock = *clock_val; +} + +/** + * Set the input length, in bits. + * + * @param dev Beginning address of the peripheral registers. + * @param bitlen Length of input, in bits. + */ +static inline void spi_flash_ll_set_miso_bitlen(spi_dev_t *dev, uint32_t bitlen) +{ + dev->user.usr_miso = bitlen > 0; + dev->miso_dlen.usr_miso_dbitlen = bitlen ? (bitlen - 1) : 0; +} + +/** + * Set the output length, in bits (not including command, address and dummy + * phases) + * + * @param dev Beginning address of the peripheral registers. + * @param bitlen Length of output, in bits. + */ +static inline void spi_flash_ll_set_mosi_bitlen(spi_dev_t *dev, uint32_t bitlen) +{ + dev->user.usr_mosi = bitlen > 0; + dev->mosi_dlen.usr_mosi_dbitlen = bitlen ? (bitlen - 1) : 0; +} + +/** + * Set the command with fixed length (8 bits). + * + * @param dev Beginning address of the peripheral registers. + * @param command Command to send + */ +static inline void spi_flash_ll_set_command8(spi_dev_t *dev, uint8_t command) +{ + dev->user.usr_command = 1; + typeof(dev->user2) user2 = { + .usr_command_value = command, + .usr_command_bitlen = (8 - 1), + }; + dev->user2 = user2; +} + +/** + * Set the address length to send, in bits. Should be called before commands that requires the address e.g. erase sector, read, write... + * + * @param dev Beginning address of the peripheral registers. + * @param bitlen Length of the address, in bits + */ +static inline void spi_flash_ll_set_addr_bitlen(spi_dev_t *dev, uint32_t bitlen) +{ + dev->user1.usr_addr_bitlen = (bitlen - 1); + dev->user.usr_addr = bitlen ? 1 : 0; +} + +/** + * Set the address to send. Should be called before commands that requires the address e.g. erase sector, read, write... + * + * @param dev Beginning address of the peripheral registers. + * @param addr Address to send + */ +static inline void spi_flash_ll_set_address(spi_dev_t *dev, uint32_t addr) +{ + dev->addr = addr; +} + +/** + * Set the length of dummy cycles. + * + * @param dev Beginning address of the peripheral registers. + * @param dummy_n Cycles of dummy phases + */ +static inline void spi_flash_ll_set_dummy(spi_dev_t *dev, uint32_t dummy_n) +{ + dev->user.usr_dummy = dummy_n ? 1 : 0; + dev->user1.usr_dummy_cyclelen = dummy_n - 1; +} diff --git a/components/soc/esp32/include/soc/spi_pins.h b/components/soc/esp32/include/soc/spi_pins.h index eb7af85827..80a17ff090 100644 --- a/components/soc/esp32/include/soc/spi_pins.h +++ b/components/soc/esp32/include/soc/spi_pins.h @@ -3,7 +3,7 @@ // 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 @@ -22,6 +22,14 @@ #define SPI_IOMUX_PIN_NUM_WP 10 #define SPI_IOMUX_PIN_NUM_HD 9 +//For D2WD and PICO-D4 chip +#define SPI_D2WD_PIN_NUM_MISO 17 +#define SPI_D2WD_PIN_NUM_MOSI 8 +#define SPI_D2WD_PIN_NUM_CLK 6 +#define SPI_D2WD_PIN_NUM_CS 16 +#define SPI_D2WD_PIN_NUM_WP 7 +#define SPI_D2WD_PIN_NUM_HD 11 + #define HSPI_IOMUX_PIN_NUM_MISO 12 #define HSPI_IOMUX_PIN_NUM_MOSI 13 #define HSPI_IOMUX_PIN_NUM_CLK 14 diff --git a/components/soc/include/hal/esp_flash_err.h b/components/soc/include/hal/esp_flash_err.h new file mode 100644 index 0000000000..c760f19fe6 --- /dev/null +++ b/components/soc/include/hal/esp_flash_err.h @@ -0,0 +1,39 @@ +// Copyright 2015-2019 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 + +#include +#include "esp_err.h" + +/* + * Possible errors returned from esp flash internal functions, these error codes + * should be consistent with esp_err_t codes. But in order to make the source + * files less dependent to esp_err_t, they use the error codes defined in this + * replacable header. This header should ensure the consistency to esp_err_t. + */ + +/* These should be consistent with esp_err_t errors */ +#define ESP_ERR_FLASH_SIZE_NOT_MATCH ESP_ERR_INVALID_SIZE ///< The chip doesn't have enough space for the current partition table +#define ESP_ERR_FLASH_NO_RESPONSE ESP_ERR_INVALID_RESPONSE ///< Chip did not respond to the command, or timed out. + + +#define ESP_ERR_FLASH_ERR_BASE 0x6000 ///< Starting number of Flash error codes */ +//The ROM code has already taken 1 and 2, to avoid possible conflicts, start from 3. +#define ESP_ERR_FLASH_NOT_INITIALISED (ESP_ERR_FLASH_ERR_BASE+3) ///< esp_flash_chip_t structure not correctly initialised by esp_flash_init(). +#define ESP_ERR_FLASH_UNSUPPORTED_HOST (ESP_ERR_FLASH_ERR_BASE+4) ///< Requested operation isn't supported via this host SPI bus (chip->spi field). +#define ESP_ERR_FLASH_UNSUPPORTED_CHIP (ESP_ERR_FLASH_ERR_BASE+5) ///< Requested operation isn't supported by this model of SPI flash chip. +#define ESP_ERR_FLASH_PROTECTED (ESP_ERR_FLASH_ERR_BASE+6) ///< Write operation failed due to chip's write protection being enabled. + + diff --git a/components/soc/include/hal/spi_flash_hal.h b/components/soc/include/hal/spi_flash_hal.h new file mode 100644 index 0000000000..1a5c373614 --- /dev/null +++ b/components/soc/include/hal/spi_flash_hal.h @@ -0,0 +1,243 @@ +// Copyright 2010-2019 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. + +/******************************************************************************* + * NOTICE + * The HAL is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +// The HAL layer for SPI Flash (common part) + +#pragma once + +#include "hal/spi_flash_ll.h" +#include "hal/spi_flash_host_drv.h" +#include "soc/soc_memory_layout.h" + +#define ESP_FLASH_DEFAULT_FREQ ESP_FLASH_20MHZ + +/* Hardware host-specific constants */ +#define SPI_FLASH_HAL_MAX_WRITE_BYTES 64 +#define SPI_FLASH_HAL_MAX_READ_BYTES 64 + +///Lowest speed supported by the driver, currently 5 MHz +#define ESP_FLASH_SPEED_MIN ESP_FLASH_5MHZ + +/** + * @brief SPI flash clock speed values, always refer to them by the enum rather + * than the actual value (more speed may be appended into the list). + * + * A strategy to select the maximum allowed speed is to enumerate from the + * ``ESP_FLSH_SPEED_MAX-1`` or highest frequency supported by your flash, and + * decrease the speed until the probing success. + */ +typedef enum { + ESP_FLASH_5MHZ = 0, ///< The flash runs under 5MHz + ESP_FLASH_10MHZ, ///< The flash runs under 10MHz + ESP_FLASH_20MHZ, ///< The flash runs under 20MHz + ESP_FLASH_26MHZ, ///< The flash runs under 26MHz + ESP_FLASH_40MHZ, ///< The flash runs under 40MHz + ESP_FLASH_80MHZ, ///< The flash runs under 80MHz + ESP_FLASH_SPEED_MAX, ///< The maximum frequency supported by the host is ``ESP_FLASH_SPEED_MAX-1``. +} esp_flash_speed_t; + +/** + * Generic driver context structure for all chips using the SPI peripheral. + * Include this into the HEAD of the driver data for other driver + * implementations that also use the SPI peripheral. + */ +typedef struct { + spi_dev_t *spi; ///< Pointer to SPI peripheral registers (SP1, SPI2 or SPI3). Set before initialisation. + int cs_num; ///< Which cs pin is used, 0-2. + int extra_dummy; + spi_flash_ll_clock_reg_t clock_conf; +} spi_flash_memspi_data_t; + +/// Configuration structure for the SPI driver. +typedef struct { + int host_id; ///< SPI peripheral ID, 1 for SPI1, 2 for SPI2 (HSPI), 3 for SPI3 (VSPI) + int cs_num; ///< Which cs pin is used, 0-2. + bool iomux; ///< Whether the IOMUX is used, used for timing compensation. + int input_delay_ns; ///< Input delay on the MISO pin after the launch clock, used for timing compensation. + esp_flash_speed_t speed;///< SPI flash clock speed to work at. +} spi_flash_memspi_config_t; + +/** + * Configure SPI flash hal settings. + * + * @param data Buffer to hold configured data, the buffer should be in DRAM to be available when cache disabled + * @param cfg Configurations to set + * + * @return + * - ESP_OK: success + * - ESP_ERR_INVALID_ARG: the data buffer is not in the DRAM. + */ +esp_err_t spi_flash_hal_init(spi_flash_memspi_data_t *data_out, const spi_flash_memspi_config_t *cfg); + +/** + * Configure the device-related register before transactions. + * + * @param driver The driver context. + * + * @return always return ESP_OK. + */ +esp_err_t spi_flash_hal_device_config(spi_flash_host_driver_t *driver); + +/** + * Send an user-defined spi transaction to the device. + * + * @note This is usually used when the memspi interface doesn't support some + * particular commands. Since this function supports timing compensation, it is + * also used to receive some data when the frequency is high. + * + * @param driver The driver context. + * @param trans The transaction to send, also holds the received data. + * + * @return always return ESP_OK. + */ +esp_err_t spi_flash_hal_common_command(spi_flash_host_driver_t *driver, spi_flash_trans_t *trans); + +/** + * Erase whole flash chip. + * + * @param driver The driver context. + */ +void spi_flash_hal_erase_chip(spi_flash_host_driver_t *driver); + +/** + * Erase a specific sector by its start address. + * + * @param driver The driver context. + * @param start_address Start address of the sector to erase. + */ +void spi_flash_hal_erase_sector(spi_flash_host_driver_t *driver, uint32_t start_address); + +/** + * Erase a specific block by its start address. + * + * @param driver The driver context. + * @param start_address Start address of the block to erase. + */ +void spi_flash_hal_erase_block(spi_flash_host_driver_t *driver, uint32_t start_address); + +/** + * Program a page of the flash. + * + * @param driver The driver context. + * @param address Address of the page to program + * @param buffer Data to program + * @param length Size of the buffer in bytes, no larger than ``SPI_FLASH_HAL_MAX_WRITE_BYTES`` (64) bytes. + */ +void spi_flash_hal_program_page(spi_flash_host_driver_t *driver, const void *buffer, uint32_t address, uint32_t length); + +/** + * Read from the flash. The read command should be set by ``spi_flash_hal_configure_host_read_mode`` before. + * + * @param driver The driver context. + * @param buffer Buffer to store the read data + * @param address Address to read + * @param length Length to read, no larger than ``SPI_FLASH_HAL_MAX_READ_BYTES`` (64) bytes. + * + * @return always return ESP_OK. + */ +esp_err_t spi_flash_hal_read(spi_flash_host_driver_t *driver, void *buffer, uint32_t address, uint32_t read_len); + +/** + * Enable or disable the write protection of the flash chip. + * + * @param driver The driver context. + * @param wp true to enable the write protection, otherwise false. + * + * @return always return ESP_OK. + */ +esp_err_t spi_flash_hal_set_write_protect(spi_flash_host_driver_t *chip_drv, bool wp); + +/** + * Check whether the SPI host is idle and can perform other operations. + * + * @param driver The driver context. + * + * @return ture if idle, otherwise false. + */ +bool spi_flash_hal_host_idle(spi_flash_host_driver_t *driver); + +/** + * Configure the SPI host hardware registers for the specified read mode. + * + * Note that calling this configures SPI host registers, so if running any + * other commands as part of set_read_mode() then these must be run before + * calling this function. + * + * @param driver The driver context + * @param read_mode The HW read mode to use + * @param addr_bitlen Length of the address phase, in bits + * @param dummy_cyclelen_base Base cycles of the dummy phase, some extra dummy cycles may be appended to compensate the timing. + * @param read_command Actual reading command to send to flash chip on the bus. + * + * @return always return ESP_OK. + */ +esp_err_t spi_flash_hal_configure_host_read_mode(spi_flash_host_driver_t *driver, esp_flash_read_mode_t read_mode, + uint32_t addr_bitlen, uint32_t dummy_cyclelen_base, + uint32_t read_command); + +/** + * Poll until the last operation is done. + * + * @param driver The driver context. + */ +void spi_flash_hal_poll_cmd_done(spi_flash_host_driver_t *driver); + +/** + * Check whether the given buffer can be used as the write buffer directly. If 'chip' is connected to the main SPI bus, we can only write directly from + * regions that are accessible ith cache disabled. * + * + * @param driver The driver context + * @param p The buffer holding data to send. + * + * @return True if the buffer can be used to send data, otherwise false. + */ +static inline bool spi_flash_hal_supports_direct_write(spi_flash_host_driver_t *driver, const void *p) +{ +#ifdef ESP_PLATFORM + bool direct_write = ( ((spi_flash_memspi_data_t *)driver->driver_data)->spi != &SPI1 + || esp_ptr_in_dram(p) ); +#else + //If it is not on real chips, there is no limitation that the data has to be in DRAM. + bool direct_write = true; +#endif + return direct_write; +} + +/** + * Check whether the given buffer can be used as the read buffer directly. If 'chip' is connected to the main SPI bus, we can only read directly from + * regions that are accessible ith cache disabled. * + * + * @param driver The driver context + * @param p The buffer to hold the received data. + * + * @return True if the buffer can be used to receive data, otherwise false. + */ +static inline bool spi_flash_hal_supports_direct_read(spi_flash_host_driver_t *driver, const void *p) +{ +#ifdef ESP_PLATFORM +//currently the driver doesn't support to read through DMA, no word-aligned requirements + bool direct_read = ( ((spi_flash_memspi_data_t *)driver->driver_data)->spi != &SPI1 + || esp_ptr_in_dram(p) ); +#else + //If it is not on real chips, there is no limitation that the data has to be in DRAM. + bool direct_read = true; +#endif + return direct_read; +} \ No newline at end of file diff --git a/components/soc/include/hal/spi_flash_host_drv.h b/components/soc/include/hal/spi_flash_host_drv.h new file mode 100644 index 0000000000..5095bc8f50 --- /dev/null +++ b/components/soc/include/hal/spi_flash_host_drv.h @@ -0,0 +1,112 @@ +// Copyright 2010-2019 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 + +#include "hal/spi_flash_ll.h" +#include "hal/esp_flash_err.h" + +/** Definition of a common transaction. Also holds the return value. */ +typedef struct { + uint8_t command; ///< Command to send, always 8bits + uint8_t mosi_len; ///< Output data length, in bits + uint8_t miso_len; ///< Input data length, in bits + uint32_t mosi_data; ///< Output data to slave + uint32_t miso_data[2]; ///< [out] Input data from slave, little endian +} spi_flash_trans_t; + + +struct spi_flash_host_driver_t; +typedef struct spi_flash_host_driver_t spi_flash_host_driver_t; + +/** Host driver configuration and context structure. */ +struct spi_flash_host_driver_t { + /** + * Configuration and static data used by the specific host driver. The type + * is determined by the host driver. + */ + void *driver_data; + /** + * Configure the device-related register before transactions. This saves + * some time to re-configure those registers when we send continuously + */ + esp_err_t (*dev_config)(spi_flash_host_driver_t *driver); + /** + * Send an user-defined spi transaction to the device. + */ + esp_err_t (*common_command)(spi_flash_host_driver_t *driver, spi_flash_trans_t *t); + /** + * Read flash ID. + */ + esp_err_t (*read_id)(spi_flash_host_driver_t *driver, uint32_t *id); + /** + * Erase whole flash chip. + */ + void (*erase_chip)(spi_flash_host_driver_t *driver); + /** + * Erase a specific sector by its start address. + */ + void (*erase_sector)(spi_flash_host_driver_t *driver, uint32_t start_address); + /** + * Erase a specific block by its start address. + */ + void (*erase_block)(spi_flash_host_driver_t *driver, uint32_t start_address); + /** + * Read the status of the flash chip. + */ + esp_err_t (*read_status)(spi_flash_host_driver_t *driver, uint8_t *out_sr); + /** + * Disable write protection. + */ + esp_err_t (*set_write_protect)(spi_flash_host_driver_t *driver, bool wp); + /** + * Program a page of the flash. Check ``max_write_bytes`` for the maximum allowed writing length. + */ + void (*program_page)(spi_flash_host_driver_t *driver, const void *buffer, uint32_t address, uint32_t length); + /** Check whether need to allocate new buffer to write */ + bool (*supports_direct_write)(spi_flash_host_driver_t *driver, const void *p); + /** Check whether need to allocate new buffer to read */ + bool (*supports_direct_read)(spi_flash_host_driver_t *driver, const void *p); + /** maximum length of program_page */ + int max_write_bytes; + /** + * Read data from the flash. Check ``max_read_bytes`` for the maximum allowed reading length. + */ + esp_err_t (*read)(spi_flash_host_driver_t *driver, void *buffer, uint32_t address, uint32_t read_len); + /** maximum length of read */ + int max_read_bytes; + /** + * Check whether the host is idle to perform new operations. + */ + bool (*host_idle)(spi_flash_host_driver_t *driver); + /** + * Configure the host to work at different read mode. + */ + esp_err_t (*configure_host_read_mode)(spi_flash_host_driver_t *driver, esp_flash_read_mode_t read_mode, uint32_t addr_bitlen, uint32_t dummy_bitlen_base, uint32_t read_command); + /** + * Internal use, poll the HW until the last operation is done. + */ + void (*poll_cmd_done)(spi_flash_host_driver_t *driver); + /** + * For some host (SPI1), they are shared with a cache. When the data is + * modified, the cache needs to be flushed. Left NULL if not supported. + */ + esp_err_t (*flush_cache)(spi_flash_host_driver_t* driver, uint32_t addr, uint32_t size); + /** + * Check if the given region is protected (e.g. is the bootloader). Left + * NULL if current host doesn't need protection. + */ + bool (*region_protected)(spi_flash_host_driver_t* driver, uint32_t addr, uint32_t size); +}; + diff --git a/components/soc/linker.lf b/components/soc/linker.lf index d91f728b6d..5cb2021091 100644 --- a/components/soc/linker.lf +++ b/components/soc/linker.lf @@ -12,4 +12,6 @@ entries: rtc_wdt (noflash_text) spi_hal_iram (noflash_text) spi_slave_hal_iram (noflash_text) - lldesc (noflash_text) \ No newline at end of file + spi_flash_hal_iram (noflash) + lldesc (noflash_text) + diff --git a/components/soc/src/hal/spi_flash_hal.c b/components/soc/src/hal/spi_flash_hal.c new file mode 100644 index 0000000000..6a88d35a17 --- /dev/null +++ b/components/soc/src/hal/spi_flash_hal.c @@ -0,0 +1,74 @@ +// Copyright 2015-2018 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 +#include "hal/spi_flash_hal.h" +#include "string.h" +#include "hal/hal_defs.h" + +#define APB_CYCLE_NS (1000*1000*1000LL/APB_CLK_FREQ) + +static const char TAG[] = "FLASH_HAL"; + +typedef struct { + int freq; + spi_flash_ll_clock_reg_t clock_reg_val; +} spi_flash_hal_clock_config_t; + + +static const spi_flash_hal_clock_config_t spi_flash_clk_cfg_reg[ESP_FLASH_SPEED_MAX] = { + {5e6, SPI_FLASH_LL_CLKREG_VAL_5MHZ}, + {10e6, SPI_FLASH_LL_CLKREG_VAL_10MHZ}, + {20e6, SPI_FLASH_LL_CLKREG_VAL_20MHZ}, + {26e6, SPI_FLASH_LL_CLKREG_VAL_26MHZ}, + {40e6, SPI_FLASH_LL_CLKREG_VAL_40MHZ}, + {80e6, SPI_FLASH_LL_CLKREG_VAL_80MHZ}, +}; + +static inline int get_dummy_n(bool gpio_is_used, int input_delay_ns, int eff_clk) +{ + const int apbclk_kHz = APB_CLK_FREQ / 1000; + //calculate how many apb clocks a period has + const int apbclk_n = APB_CLK_FREQ / eff_clk; + const int gpio_delay_ns = gpio_is_used ? (APB_CYCLE_NS * 2) : 0; + + //calculate how many apb clocks the delay is, the 1 is to compensate in case ``input_delay_ns`` is rounded off. + int apb_period_n = (1 + input_delay_ns + gpio_delay_ns) * apbclk_kHz / 1000 / 1000; + if (apb_period_n < 0) { + apb_period_n = 0; + } + + return apb_period_n / apbclk_n; +} + +esp_err_t spi_flash_hal_init(spi_flash_memspi_data_t *data_out, const spi_flash_memspi_config_t *cfg) +{ + if (!esp_ptr_internal(data_out)) { + return ESP_ERR_INVALID_ARG; + } + *data_out = (spi_flash_memspi_data_t) { + .spi = spi_flash_ll_get_hw(cfg->host_id), + .cs_num = cfg->cs_num, + .extra_dummy = get_dummy_n(!cfg->iomux, cfg->input_delay_ns, spi_flash_clk_cfg_reg[cfg->speed].freq), + .clock_conf = spi_flash_clk_cfg_reg[cfg->speed].clock_reg_val, + }; + + ESP_EARLY_LOGD(TAG, "extra_dummy: %d", data_out->extra_dummy); + return ESP_OK; +} + +static inline spi_dev_t *get_spi_dev(spi_flash_host_driver_t *chip_drv) +{ + return ((spi_flash_memspi_data_t *)chip_drv->driver_data)->spi; +} diff --git a/components/soc/src/hal/spi_flash_hal_iram.c b/components/soc/src/hal/spi_flash_hal_iram.c new file mode 100644 index 0000000000..ddd2c7d5f3 --- /dev/null +++ b/components/soc/src/hal/spi_flash_hal_iram.c @@ -0,0 +1,144 @@ +// Copyright 2015-2019 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 +#include "hal/spi_flash_hal.h" +#include "string.h" +#include "hal/hal_defs.h" + +#define ADDRESS_MASK_24BIT 0xFFFFFF + +static inline spi_dev_t *get_spi_dev(spi_flash_host_driver_t *chip_drv) +{ + return ((spi_flash_memspi_data_t *)chip_drv->driver_data)->spi; +} + +void spi_flash_hal_poll_cmd_done(spi_flash_host_driver_t *driver) +{ + while (!spi_flash_ll_cmd_is_done(get_spi_dev(driver))) { + //nop + } +} + +esp_err_t spi_flash_hal_device_config(spi_flash_host_driver_t *driver) +{ + spi_flash_memspi_data_t *drv_data = (spi_flash_memspi_data_t *)driver->driver_data; + spi_dev_t *dev = get_spi_dev(driver); + spi_flash_ll_reset(dev); + spi_flash_ll_set_cs_pin(dev, drv_data->cs_num); + spi_flash_ll_set_clock(dev, &drv_data->clock_conf); + return ESP_OK; +} + +esp_err_t spi_flash_hal_configure_host_read_mode(spi_flash_host_driver_t *driver, esp_flash_read_mode_t read_mode, + uint32_t addr_bitlen, uint32_t dummy_cyclelen_base, + uint32_t read_command) +{ + // Add dummy cycles to compensate for latency of GPIO matrix and external delay, if necessary... + int dummy_cyclelen = dummy_cyclelen_base + ((spi_flash_memspi_data_t *)driver->driver_data)->extra_dummy; + + spi_dev_t *dev = get_spi_dev(driver); + spi_flash_ll_set_addr_bitlen(dev, addr_bitlen); + spi_flash_ll_set_command8(dev, read_command); + spi_flash_ll_read_phase(dev); + spi_flash_ll_set_dummy(dev, dummy_cyclelen); + spi_flash_ll_set_read_mode(dev, read_mode); + return ESP_OK; +} + +esp_err_t spi_flash_hal_common_command(spi_flash_host_driver_t *chip_drv, spi_flash_trans_t *trans) +{ + chip_drv->configure_host_read_mode(chip_drv, SPI_FLASH_FASTRD, 0, 0, 0); + spi_dev_t *dev = get_spi_dev(chip_drv); + spi_flash_ll_set_command8(dev, trans->command); + spi_flash_ll_set_addr_bitlen(dev, 0); + spi_flash_ll_set_miso_bitlen(dev, trans->miso_len); + spi_flash_ll_set_mosi_bitlen(dev, trans->mosi_len); + + spi_flash_ll_write_word(dev, trans->mosi_data); + + spi_flash_ll_user_start(dev); + chip_drv->poll_cmd_done(chip_drv); + spi_flash_ll_get_buffer_data(dev, trans->miso_data, 8); + return ESP_OK; +} + +void spi_flash_hal_erase_chip(spi_flash_host_driver_t *chip_drv) +{ + spi_dev_t *dev = get_spi_dev(chip_drv); + spi_flash_ll_erase_chip(dev); + chip_drv->poll_cmd_done(chip_drv); +} + +void spi_flash_hal_erase_sector(spi_flash_host_driver_t *chip_drv, uint32_t start_address) +{ + spi_dev_t *dev = get_spi_dev(chip_drv); + spi_flash_ll_set_addr_bitlen(dev, 24); + spi_flash_ll_set_address(dev, start_address & ADDRESS_MASK_24BIT); + spi_flash_ll_erase_sector(dev); + chip_drv->poll_cmd_done(chip_drv); +} + +void spi_flash_hal_erase_block(spi_flash_host_driver_t *chip_drv, uint32_t start_address) +{ + spi_dev_t *dev = get_spi_dev(chip_drv); + spi_flash_ll_set_addr_bitlen(dev, 24); + spi_flash_ll_set_address(dev, start_address & ADDRESS_MASK_24BIT); + spi_flash_ll_erase_block(dev); + chip_drv->poll_cmd_done(chip_drv); +} + +void spi_flash_hal_program_page(spi_flash_host_driver_t *chip_drv, const void *buffer, uint32_t address, uint32_t length) +{ + spi_dev_t *dev = get_spi_dev(chip_drv); + spi_flash_ll_set_addr_bitlen(dev, 24); + spi_flash_ll_set_address(dev, (address & ADDRESS_MASK_24BIT) | (length << 24)); + spi_flash_ll_program_page(dev, buffer, length); + chip_drv->poll_cmd_done(chip_drv); +} + +esp_err_t spi_flash_hal_read(spi_flash_host_driver_t *chip_drv, void *buffer, uint32_t address, uint32_t read_len) +{ + spi_dev_t *dev = get_spi_dev(chip_drv); + //the command is already set by ``spi_flash_hal_configure_host_read_mode`` before. + spi_flash_ll_set_address(dev, address << 8); + spi_flash_ll_set_miso_bitlen(dev, read_len * 8); + spi_flash_ll_user_start(dev); + chip_drv->poll_cmd_done(chip_drv); + spi_flash_ll_get_buffer_data(dev, buffer, read_len); + return ESP_OK; +} + + +bool spi_flash_hal_host_idle(spi_flash_host_driver_t *chip_drv) +{ + spi_dev_t *dev = get_spi_dev(chip_drv); + bool idle = spi_flash_ll_host_idle(dev); + + // Not clear if this is necessary, or only necessary if + // chip->spi == SPI1. But probably doesn't hurt... + if (dev == &SPI1) { + idle &= spi_flash_ll_host_idle(&SPI0); + } + + return idle; +} + +esp_err_t spi_flash_hal_set_write_protect(spi_flash_host_driver_t *chip_drv, bool wp) +{ + spi_dev_t *dev = get_spi_dev(chip_drv); + spi_flash_ll_set_write_protect(dev, wp); + chip_drv->poll_cmd_done(chip_drv); + return ESP_OK; +} diff --git a/components/spi_flash/CMakeLists.txt b/components/spi_flash/CMakeLists.txt index be290e7c32..eb17b31eef 100644 --- a/components/spi_flash/CMakeLists.txt +++ b/components/spi_flash/CMakeLists.txt @@ -8,11 +8,22 @@ else() "flash_mmap.c" "flash_ops.c" "partition.c" - "spi_flash_rom_patch.c") + "spi_flash_rom_patch.c" + "spi_flash_chip_drivers.c" + "spi_flash_chip_generic.c" + "spi_flash_chip_issi.c" + "spi_flash_os_func_app.c" + "spi_flash_os_func_noos.c" + "memspi_host_driver.c" + ) + if(NOT CONFIG_SPI_FLASH_USE_LEGACY_IMPL) + list(APPEND COMPONENT_SRCS "esp_flash_api.c") + endif() set(COMPONENT_PRIV_REQUIRES bootloader_support app_update soc) endif() set(COMPONENT_ADD_INCLUDEDIRS include) +set(COMPONENT_PRIV_INCLUDEDIRS private_include) set(COMPONENT_ADD_LDFRAGMENTS linker.lf) register_component() diff --git a/components/spi_flash/Kconfig b/components/spi_flash/Kconfig index 6ba4d5180d..8a10651ff0 100644 --- a/components/spi_flash/Kconfig +++ b/components/spi_flash/Kconfig @@ -77,4 +77,21 @@ menu "SPI Flash driver" bool "Allowed" endchoice + config SPI_FLASH_USE_LEGACY_IMPL + bool "Use the legacy implementation before IDF v4.0" + default n + help + The implementation of SPI flash has been greatly changed in IDF v4.0. + Enable this option to use the legacy implementation. + + menu "Auto-detect flash chips" + + config SPI_FLASH_SUPPORT_ISSI_CHIP + bool "ISSI" + default y + help + Enable this to support auto detection of ISSI chips if chip vendor not specified. + This adds support for variant chips, however will extend detecting time. + endmenu #auto detect flash chips + endmenu diff --git a/components/spi_flash/README.rst b/components/spi_flash/README.rst index 04376c6140..e65b1ad4c6 100644 --- a/components/spi_flash/README.rst +++ b/components/spi_flash/README.rst @@ -3,22 +3,40 @@ SPI Flash API Overview -------- -The spi_flash component contains API functions related to reading, writing, erasing, memory mapping for data in the external SPI flash. The spi_flash component also has higher-level API functions which work with partitions defined in the :doc:`partition table `. +The spi_flash component contains API functions related to reading, writing, +erasing, memory mapping for data in the external flash. The spi_flash +component also has higher-level API functions which work with partitions +defined in the :doc:`partition table `. -Note that all the functionality is limited to the "main" SPI flash chip, the same SPI flash chip from which programs are runs. For ``spi_flash_*`` functions, this is a software limitation. The underlying ROM functions which work with SPI flash do not have provisions for working with flash chips attached to SPI peripherals other than SPI0. +Different from the API before IDF v4.0, the functionality is not limited to +the "main" SPI flash chip (the same SPI flash chip from which program runs). +With different chip pointers, you can access to external flashes chips on not +only SPI0/1 but also HSPI/VSPI buses. + +Kconfig option :ref:``CONFIG_SPI_FLASH_USE_LEGACY_IMPL`` can be used to switch +``spi_flash_*`` functions back to the implementation before IDF v4.0. +However, the code size may get bigger if you use the new API and the old API +the same time. + +Encrypted reads and writes use the old implementation, even if +:ref:``CONFIG_SPI_FLASH_USE_LEGACY_IMPL`` is not enabled. As such, encrypted +flash operations are only supported with the main flash chip (and not with +other flash chips on SPI1 with different CS). SPI flash access API -------------------- This is the set of API functions for working with data in flash: -- :cpp:func:`spi_flash_read` reads data from flash to RAM -- :cpp:func:`spi_flash_write` writes data from RAM to flash -- :cpp:func:`spi_flash_erase_sector` erases individual sectors of flash -- :cpp:func:`spi_flash_erase_range` erases ranges of addresses in flash -- :cpp:func:`spi_flash_get_chip_size` returns flash chip size, in bytes, as configured in menuconfig +- :cpp:func:`esp_flash_read` reads data from flash to RAM +- :cpp:func:`esp_flash_write` writes data from RAM to flash +- :cpp:func:`esp_flash_erase_region` erases specific region of flash +- :cpp:func:`esp_flash_erase_chip` erases the whole flash +- :cpp:func:`esp_flash_get_chip_size` returns flash chip size, in bytes, as configured in menuconfig -Generally, try to avoid using the raw SPI flash functions in favor of :ref:`partition-specific functions `. +Generally, try to avoid using the raw SPI flash functions to the "main" SPI +flash chip in favour of :ref:`partition-specific functions +`. SPI Flash Size -------------- @@ -27,7 +45,7 @@ The SPI flash size is configured by writing a field in the software bootloader i By default, the SPI flash size is detected by esptool.py when this bootloader is written to flash, and the header is updated with the correct size. Alternatively, it is possible to generate a fixed flash size by setting :envvar:`CONFIG_ESPTOOLPY_FLASHSIZE` in ``make menuconfig``. -If it is necessary to override the configured flash size at runtime, it is possible to set the ``chip_size`` member of the ``g_rom_flashchip`` structure. This size is used by ``spi_flash_*`` functions (in both software & ROM) to check the bounds. +If it is necessary to override the configured flash size at runtime, it is possible to set the ``chip_size`` member of the ``g_rom_flashchip`` structure. This size is used by ``esp_flash_*`` functions (in both software & ROM) to check the bounds. Concurrency Constraints ----------------------- @@ -121,3 +139,67 @@ Differences between :cpp:func:`spi_flash_mmap` and :cpp:func:`esp_partition_mmap - :cpp:func:`esp_partition_mmap` may be given any arbitrary offset within the partition, it will adjust the returned pointer to mapped memory as necessary Note that since memory mapping happens in 64KB blocks, it may be possible to read data outside of the partition provided to ``esp_partition_mmap``. + +Implementation +-------------- + +The ``esp_flash_t`` structure holds chip data as well as three important parts of this API: + +1. The host driver, which provides the hardware support to access the chip; +2. The chip driver, which provides compability service to different chips; +3. The OS functions, provides support of some OS functions (e.g. lock, delay) + in different stages (1st/2st boot, or the app). + +Host driver +^^^^^^^^^^^ + +The host driver relies on an interface (``spi_flash_host_driver_t``) defined +in the ``spi_flash_host_drv.h`` (in the ``soc/include/hal`` folder). This +interface provides some common functions to communicate with the chip. + +In other files of the SPI HAL, some of these functions are implemented with +existing ESP32 memory-spi functionalities. However due to the speed +limitations of ESP32, the HAL layer can't provide high-speed implementations +to some reading commands (So we didn't do it at all). The files +(``memspi_host_driver.h`` and ``.c``) implement the high-speed version of +these commands with the ``common_command`` function provided in the HAL, and +wrap these functions as ``spi_flash_host_driver_t`` for upper layer to use. + +You can also implement your own host driver, even with the GPIO. As long as +all the functions in the ``spi_flash_host_driver_t`` are implemented, the +esp_flash API can access to the flash regardless of the lowlevel hardware. + +Chip driver +^^^^^^^^^^^ + +The chip driver, defined in ``spi_flash_chip_driver.h``, wraps basic +functions provided by the host driver for the API layer to use. + +Some operations need some commands to be sent first, or read some status +after. Some chips need different command or value, or need special +communication ways. + +There is a type of chip called ``generic chip`` which stands for common +chips. Other special chip drivers can be developed on the base of the generic +chip. + +The chip driver relies on the host driver. + +OS functions +^^^^^^^^^^^^ + +Currently the OS function layer provides a lock and a delay entrance. + +The lock is used to resolve the conflicts between the SPI chip access and +other functions. E.g. the cache (used for the code and psram data fetch) +should be disabled when the flash chip on the SPI0/1 is being accessed. Also, +some devices which don't have CS wire, or the wire is controlled by the +software (e.g. SD card via SPI interface), requires the bus to be monopolized +during a period. + +The delay is used by some long operations which requires the master to wait +or polling periodly. + + +The top API wraps these the chip driver and OS functions into an entire +component, and also provides some argument checking. diff --git a/components/spi_flash/README_legacy.rst b/components/spi_flash/README_legacy.rst new file mode 100644 index 0000000000..a8e5da15a6 --- /dev/null +++ b/components/spi_flash/README_legacy.rst @@ -0,0 +1,127 @@ +SPI Flash API (Legacy) +======================== + +Overview +-------- + +This is the readme for the APIs before IDF v4.0. Enable the kconfig option ``SPI_FLASH_USE_LEGACY_IMPL`` to use the +legacy implementation. + +The spi_flash component contains API functions related to reading, writing, erasing, memory mapping for data in the external SPI flash. The spi_flash component also has higher-level API functions which work with partitions defined in the :doc:`partition table `. + +Note that all the functionality is limited to the "main" SPI flash chip, the same SPI flash chip from which programs are runs. For ``spi_flash_*`` functions, this is a software limitation. The underlying ROM functions which work with SPI flash do not have provisions for working with flash chips attached to SPI peripherals other than SPI0. + +SPI flash access API +-------------------- + +This is the set of API functions for working with data in flash: + +- :cpp:func:`spi_flash_read` reads data from flash to RAM +- :cpp:func:`spi_flash_write` writes data from RAM to flash +- :cpp:func:`spi_flash_erase_sector` erases individual sectors of flash +- :cpp:func:`spi_flash_erase_range` erases ranges of addresses in flash +- :cpp:func:`spi_flash_get_chip_size` returns flash chip size, in bytes, as configured in menuconfig + +Generally, try to avoid using the raw SPI flash functions in favor of :ref:`partition-specific functions `. + +SPI Flash Size +-------------- + +The SPI flash size is configured by writing a field in the software bootloader image header, flashed at offset 0x1000. + +By default, the SPI flash size is detected by esptool.py when this bootloader is written to flash, and the header is updated with the correct size. Alternatively, it is possible to generate a fixed flash size by setting :envvar:`CONFIG_ESPTOOLPY_FLASHSIZE` in ``make menuconfig``. + +If it is necessary to override the configured flash size at runtime, it is possible to set the ``chip_size`` member of the ``g_rom_flashchip`` structure. This size is used by ``spi_flash_*`` functions (in both software & ROM) to check the bounds. + +Concurrency Constraints +----------------------- + +Because the SPI flash is also used for firmware execution via the instruction & data caches, these caches must be disabled while reading/writing/erasing. This means that both CPUs must be running code from IRAM and must only be reading data from DRAM while flash write operations occur. + +If you use the API functions documented here, then these constraints are applied automatically and transparently. However, note that it will have some performance impact on other tasks in the system. + +For differences between IRAM, DRAM, and flash cache, please refer to the :ref:`application memory layout ` documentation. + +To avoid reading flash cache accidentally, when one CPU initiates a flash write or erase operation, the other CPU is put into a blocked state, and all non-IRAM-safe interrupts are disabled on both CPUs until the flash operation completes. + +If one CPU initiates a flash write or erase operation, the other CPU is put into a blocked state to avoid reading flash cache accidentally. All interrupts not safe for IRAM are disabled on both CPUs until the flash operation completes. + +.. _iram-safe-interrupt-handlers: + +IRAM-Safe Interrupt Handlers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you have an interrupt handler that you want to execute while a flash operation is in progress (for example, for low latency operations), set the ``ESP_INTR_FLAG_IRAM`` flag when the :doc:`interrupt handler is registered `. + +You must ensure that all data and functions accessed by these interrupt handlers, including the ones that handlers call, are located in IRAM or DRAM. + +Use the ``IRAM_ATTR`` attribute for functions:: + + #include "esp_attr.h" + + void IRAM_ATTR gpio_isr_handler(void* arg) + { + // ... + } + +Use the ``DRAM_ATTR`` and ``DRAM_STR`` attributes for constant data:: + + void IRAM_ATTR gpio_isr_handler(void* arg) + { + const static DRAM_ATTR uint8_t INDEX_DATA[] = { 45, 33, 12, 0 }; + const static char *MSG = DRAM_STR("I am a string stored in RAM"); + } + +Note that knowing which data should be marked with ``DRAM_ATTR`` can be hard, the compiler will sometimes recognize that a variable or expression is constant (even if it is not marked ``const``) and optimize it into flash, unless it is marked with ``DRAM_ATTR``. + +If a function or symbol is not correctly put into IRAM/DRAM, and the interrupt handler reads from the flash cache during a flash operation, it will cause a crash due to Illegal Instruction exception (for code which should be in IRAM) or garbage data to be read (for constant data which should be in DRAM). + +.. _flash-partition-apis: + +Partition table API +------------------- + +ESP-IDF projects use a partition table to maintain information about various regions of SPI flash memory (bootloader, various application binaries, data, filesystems). More information on partition tables can be found :doc:`here `. + +This component provides API functions to enumerate partitions found in the partition table and perform operations on them. These functions are declared in ``esp_partition.h``: + +- :cpp:func:`esp_partition_find` checks a partition table for entries with specific type, returns an opaque iterator. +- :cpp:func:`esp_partition_get` returns a structure describing the partition for a given iterator. +- :cpp:func:`esp_partition_next` shifts the iterator to the next found partition. +- :cpp:func:`esp_partition_iterator_release` releases iterator returned by ``esp_partition_find``. +- :cpp:func:`esp_partition_find_first` - a convenience function which returns the structure describing the first partition found by ``esp_partition_find``. +- :cpp:func:`esp_partition_read`, :cpp:func:`esp_partition_write`, :cpp:func:`esp_partition_erase_range` are equivalent to :cpp:func:`spi_flash_read`, :cpp:func:`spi_flash_write`, :cpp:func:`spi_flash_erase_range`, but operate within partition boundaries. + +.. note:: + Application code should mostly use these ``esp_partition_*`` API functions instead of lower level ``spi_flash_*`` API functions. Partition table API functions do bounds checking and calculate correct offsets in flash, based on data stored in a partition table. + +SPI Flash Encryption +-------------------- + +It is possible to encrypt the contents of SPI flash and have it transparently decrypted by hardware. + +Refer to the :doc:`Flash Encryption documentation ` for more details. + +Memory mapping API +------------------ + +ESP32 features memory hardware which allows regions of flash memory to be mapped into instruction and data address spaces. This mapping works only for read operations. It is not possible to modify contents of flash memory by writing to a mapped memory region. + +Mapping happens in 64KB pages. Memory mapping hardware can map up to four megabytes of flash into data address space and up to 16 megabytes of flash into instruction address space. See the technical reference manual for more details about memory mapping hardware. + +Note that some 64KB pages are used to map the application itself into memory, so the actual number of available 64KB pages may be less. + +Reading data from flash using a memory mapped region is the only way to decrypt contents of flash when :doc:`flash encryption ` is enabled. Decryption is performed at the hardware level. + +Memory mapping API are declared in ``esp_spi_flash.h`` and ``esp_partition.h``: + +- :cpp:func:`spi_flash_mmap` maps a region of physical flash addresses into instruction space or data space of the CPU. +- :cpp:func:`spi_flash_munmap` unmaps previously mapped region. +- :cpp:func:`esp_partition_mmap` maps part of a partition into the instruction space or data space of the CPU. + +Differences between :cpp:func:`spi_flash_mmap` and :cpp:func:`esp_partition_mmap` are as follows: + +- :cpp:func:`spi_flash_mmap` must be given a 64KB aligned physical address. +- :cpp:func:`esp_partition_mmap` may be given any arbitrary offset within the partition, it will adjust the returned pointer to mapped memory as necessary + +Note that since memory mapping happens in 64KB blocks, it may be possible to read data outside of the partition provided to ``esp_partition_mmap``. diff --git a/components/spi_flash/component.mk b/components/spi_flash/component.mk index 2ff786e2d5..64ab7548d7 100644 --- a/components/spi_flash/component.mk +++ b/components/spi_flash/component.mk @@ -1,4 +1,5 @@ COMPONENT_ADD_INCLUDEDIRS := include +COMPONENT_PRIV_INCLUDEDIRS := private_include COMPONENT_ADD_LDFRAGMENTS += linker.lf diff --git a/components/spi_flash/esp_flash_api.c b/components/spi_flash/esp_flash_api.c new file mode 100644 index 0000000000..3a48154c7b --- /dev/null +++ b/components/spi_flash/esp_flash_api.c @@ -0,0 +1,747 @@ +// Copyright 2015-2019 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 +#include +#include +#include + +#include "spi_flash_chip_driver.h" +#include "memspi_host_driver.h" +#include "esp32/rom/spi_flash.h" +#include "esp_log.h" +#include "sdkconfig.h" +#include "esp_heap_caps.h" + +static const char TAG[] = "spi_flash"; + +#define MAX_WRITE_CHUNK 8192 /* write in chunks */ +#define MAX_READ_CHUNK 16384 + +#ifdef CONFIG_ESPTOOLPY_FLASHFREQ_80M +#define DEFAULT_FLASH_SPEED ESP_FLASH_80MHZ +#elif defined CONFIG_ESPTOOLPY_FLASHFREQ_40M +#define DEFAULT_FLASH_SPEED ESP_FLASH_40MHZ +#elif defined CONFIG_ESPTOOLPY_FLASHFREQ_26M +#define DEFAULT_FLASH_SPEED ESP_FLASH_26MHZ +#elif defined CONFIG_ESPTOOLPY_FLASHFREQ_20M +#define DEFAULT_FLASH_SPEED ESP_FLASH_20MHZ +#else +#error flash frequency not defined! check sdkconfig.h +#endif + +#if defined(CONFIG_ESPTOOLPY_FLASHMODE_QIO) +#define DEFAULT_FLASH_MODE SPI_FLASH_QIO +#elif defined(CONFIG_ESPTOOLPY_FLASHMODE_QOUT) +#define DEFAULT_FLASH_MODE SPI_FLASH_QOUT +#elif defined(CONFIG_ESPTOOLPY_FLASHMODE_DIO) +#define DEFAULT_FLASH_MODE SPI_FLASH_DIO +#elif defined(CONFIG_ESPTOOLPY_FLASHMODE_DOUT) +#define DEFAULT_FLASH_MODE SPI_FLASH_DOUT +#else +#define DEFAULT_FLASH_MODE SPI_FLASH_FASTRD +#endif + +#ifdef CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS +#define UNSAFE_WRITE_ADDRESS abort() +#else +#define UNSAFE_WRITE_ADDRESS return ESP_ERR_INVALID_ARG +#endif + +/* CHECK_WRITE_ADDRESS macro to fail writes which land in the + bootloader, partition table, or running application region. +*/ +#if CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED +#define CHECK_WRITE_ADDRESS(CHIP, ADDR, SIZE) +#else /* FAILS or ABORTS */ +#define CHECK_WRITE_ADDRESS(CHIP, ADDR, SIZE) do { \ + if (CHIP && CHIP->host->region_protected && CHIP->host->region_protected(CHIP->host, ADDR, SIZE)) { \ + UNSAFE_WRITE_ADDRESS; \ + } \ + } while(0) +#endif // CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED + +#define IO_STR_LEN 7 + +static const char io_mode_str[][IO_STR_LEN] = { + "slowrd", + "fastrd", + "dout", + "dio", + "qout", + "qio", +}; + +_Static_assert(sizeof(io_mode_str)/IO_STR_LEN == SPI_FLASH_READ_MODE_MAX, "the io_mode_str should be consistent with the esp_flash_read_mode_t defined in spi_flash_ll.h"); + + +/* Static function to notify OS of a new SPI flash operation. + + If returns an error result, caller must abort. If returns ESP_OK, caller must + call spiflash_end() before returning. +*/ +static esp_err_t IRAM_ATTR spiflash_start(esp_flash_t *chip) +{ + if (chip->os_func != NULL && chip->os_func->start != NULL) { + esp_err_t err = chip->os_func->start(chip->os_func_data); + if (err != ESP_OK) { + return err; + } + } + chip->host->dev_config(chip->host); + return ESP_OK; +} + +/* Static function to notify OS that SPI flash operation is complete. + */ +static esp_err_t IRAM_ATTR spiflash_end(const esp_flash_t *chip, esp_err_t err) +{ + if (chip->os_func != NULL + && chip->os_func->end != NULL) { + esp_err_t end_err = chip->os_func->end(chip->os_func_data); + if (err == ESP_OK) { + err = end_err; // Only return the 'end' error if we haven't already failed + } + } + return err; +} + +/* Return true if regions 'a' and 'b' overlap at all, based on their start offsets and lengths. */ +inline static bool regions_overlap(uint32_t a_start, uint32_t a_len,uint32_t b_start, uint32_t b_len); + +/* Top-level API functions, calling into chip_drv functions via chip->drv */ + +static esp_err_t detect_spi_flash_chip(esp_flash_t *chip); + +bool esp_flash_chip_driver_initialized(const esp_flash_t *chip) +{ + if (!chip->chip_drv) return false; + return true; +} + +esp_err_t IRAM_ATTR esp_flash_init(esp_flash_t *chip) +{ + esp_err_t err = ESP_OK; + if (chip == NULL || chip->host == NULL || chip->host->driver_data == NULL || + ((memspi_host_data_t*)chip->host->driver_data)->spi == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (!esp_flash_chip_driver_initialized(chip)) { + // Detect chip_drv + err = detect_spi_flash_chip(chip); + if (err != ESP_OK) { + return err; + } + } + + // Detect flash size + uint32_t size; + err = esp_flash_get_size(chip, &size); + if (err != ESP_OK) { + ESP_LOGE(TAG, "failed to get chip size"); + return err; + } + + ESP_LOGI(TAG, "flash io: %s", io_mode_str[chip->read_mode]); + err = spiflash_start(chip); + if (err != ESP_OK) { + return err; + } + + if (err == ESP_OK) { + // Try to set the flash mode to whatever default mode was chosen + err = chip->chip_drv->set_read_mode(chip); + } + // Done: all fields on 'chip' are initialised + return spiflash_end(chip, err); +} + +static esp_err_t IRAM_ATTR detect_spi_flash_chip(esp_flash_t *chip) +{ + esp_err_t err; + uint32_t flash_id; + int retries = 10; + do { + err = spiflash_start(chip); + if (err != ESP_OK) { + return err; + } + + // Send generic RDID command twice, check for a matching result and retry in case we just powered on (inner + // function fails if it sees all-ones or all-zeroes.) + err = chip->host->read_id(chip->host, &flash_id); + + if (err == ESP_OK) { // check we see the same ID twice, in case of transient power-on errors + uint32_t new_id; + err = chip->host->read_id(chip->host, &new_id); + if (err == ESP_OK && (new_id != flash_id)) { + err = ESP_ERR_FLASH_NOT_INITIALISED; + } + } + + err = spiflash_end(chip, err); + } while (err != ESP_OK && retries-- > 0); + + + // Detect the chip and set the chip_drv structure for it + const spi_flash_chip_t **drivers = esp_flash_registered_chips; + while (*drivers != NULL && !esp_flash_chip_driver_initialized(chip)) { + chip->chip_drv = *drivers; + // start/end SPI operation each time, for multitasking + // and also so esp_flash_registered_flash_drivers can live in flash + ESP_LOGD(TAG, "trying chip: %s", chip->chip_drv->name); + + err = spiflash_start(chip); + if (err != ESP_OK) { + return err; + } + + if (chip->chip_drv->probe(chip, flash_id) != ESP_OK) { + chip->chip_drv = NULL; + } + // if probe succeeded, chip->drv stays set + drivers++; + + err = spiflash_end(chip, err); + if (err != ESP_OK) { + return err; + } + } + if (!esp_flash_chip_driver_initialized(chip)) { + return ESP_ERR_NOT_FOUND; + } + ESP_LOGI(TAG, "detected chip: %s", chip->chip_drv->name); + return ESP_OK; +} + +// Convenience macro for beginning of all API functions, +// check that the 'chip' parameter is properly initialised +// and supports the operation in question +#define VERIFY_OP(OP) do { \ + if (chip == NULL) { \ + chip = esp_flash_default_chip; \ + } \ + if (chip == NULL || !esp_flash_chip_driver_initialized(chip)) { \ + return ESP_ERR_FLASH_NOT_INITIALISED; \ + } \ + if (chip->chip_drv->OP == NULL) { \ + return ESP_ERR_FLASH_UNSUPPORTED_CHIP; \ + } \ + } while (0) + +esp_err_t IRAM_ATTR esp_flash_read_id(esp_flash_t *chip, uint32_t *id) +{ + if (chip == NULL) { + chip = esp_flash_default_chip; + } + if (chip == NULL || !esp_flash_chip_driver_initialized(chip)) { + return ESP_ERR_FLASH_NOT_INITIALISED; + } + if (id == NULL) { + return ESP_ERR_INVALID_ARG; + } + esp_err_t err = spiflash_start(chip); + if (err != ESP_OK) { + return err; + } + + err = chip->host->read_id(chip->host, id); + + return spiflash_end(chip, err); +} + +esp_err_t IRAM_ATTR esp_flash_get_size(esp_flash_t *chip, uint32_t *size) +{ + VERIFY_OP(detect_size); + if (size == NULL) { + return ESP_ERR_INVALID_ARG; + } + if (chip->size != 0) { + *size = chip->size; + return ESP_OK; + } + + esp_err_t err = spiflash_start(chip); + if (err != ESP_OK) { + return err; + } + uint32_t detect_size; + err = chip->chip_drv->detect_size(chip, &detect_size); + if (err == ESP_OK) { + chip->size = detect_size; + } + return spiflash_end(chip, err); +} + +esp_err_t IRAM_ATTR esp_flash_erase_chip(esp_flash_t *chip) +{ + VERIFY_OP(erase_chip); + CHECK_WRITE_ADDRESS(chip, 0, chip->size); + bool write_protect = false; + + esp_err_t err = spiflash_start(chip); + if (err != ESP_OK) { + return err; + } + + err = esp_flash_get_chip_write_protect(chip, &write_protect); + + if (err == ESP_OK && write_protect) { + err = ESP_ERR_FLASH_PROTECTED; + } + + if (err == ESP_OK) { + err = chip->chip_drv->erase_chip(chip); + } + + return spiflash_end(chip, err); +} + +esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, uint32_t len) +{ + VERIFY_OP(erase_sector); + VERIFY_OP(erase_block); + CHECK_WRITE_ADDRESS(chip, start, len); + uint32_t block_erase_size = chip->chip_drv->erase_block == NULL ? 0 : chip->chip_drv->block_erase_size; + uint32_t sector_size = chip->chip_drv->sector_size; + bool write_protect = false; + + if (sector_size == 0 || (block_erase_size % sector_size) != 0) { + return ESP_ERR_FLASH_NOT_INITIALISED; + } + if (start > chip->size || start + len > chip->size) { + return ESP_ERR_INVALID_ARG; + } + if ((start % chip->chip_drv->sector_size) != 0 || (len % chip->chip_drv->sector_size) != 0) { + // Can only erase multiples of the sector size, starting at sector boundary + return ESP_ERR_INVALID_ARG; + } + + esp_err_t err = spiflash_start(chip); + if (err != ESP_OK) { + return err; + } + + // Check for write protection on whole chip + if (chip->chip_drv->get_chip_write_protect != NULL) { + err = chip->chip_drv->get_chip_write_protect(chip, &write_protect); + if (err == ESP_OK && write_protect) { + err = ESP_ERR_FLASH_PROTECTED; + } + } + + // Check for write protected regions overlapping the erase region + if (err == ESP_OK && chip->chip_drv->get_protected_regions != NULL && chip->chip_drv->num_protectable_regions > 0) { + uint64_t protected = 0; + err = chip->chip_drv->get_protected_regions(chip, &protected); + if (err == ESP_OK && protected != 0) { + for (int i = 0; i < chip->chip_drv->num_protectable_regions && err == ESP_OK; i++) { + const esp_flash_region_t *region = &chip->chip_drv->protectable_regions[i]; + if ((protected & BIT64(i)) + && regions_overlap(start, len, region->offset, region->size)) { + err = ESP_ERR_FLASH_PROTECTED; + } + } + } + } + + // Don't lock the SPI flash for the entire erase, as this may be very long + err = spiflash_end(chip, err); + + while (err == ESP_OK && len >= sector_size) { + err = spiflash_start(chip); + if (err != ESP_OK) { + return err; + } + + // If possible erase an entire multi-sector block + if (block_erase_size > 0 && len >= block_erase_size && (start % block_erase_size) == 0) { + err = chip->chip_drv->erase_block(chip, start); + start += block_erase_size; + len -= block_erase_size; + } + else { + // Otherwise erase individual sector only + err = chip->chip_drv->erase_sector(chip, start); + start += sector_size; + len -= sector_size; + } + + err = spiflash_end(chip, err); + } + return err; +} + +esp_err_t IRAM_ATTR esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *write_protected) +{ + VERIFY_OP(get_chip_write_protect); + if (write_protected == NULL) { + return ESP_ERR_INVALID_ARG; + } + + esp_err_t err = spiflash_start(chip); + if (err != ESP_OK) { + return err; + } + + err = chip->chip_drv->get_chip_write_protect(chip, write_protected); + + return spiflash_end(chip, err); +} + +esp_err_t IRAM_ATTR esp_flash_set_chip_write_protect(esp_flash_t *chip, bool write_protect_chip) +{ + VERIFY_OP(set_chip_write_protect); + //TODO: skip writing if already locked or unlocked + + esp_err_t err = spiflash_start(chip); + if (err != ESP_OK) { + return err; + } + + err = chip->chip_drv->set_chip_write_protect(chip, write_protect_chip); + + return spiflash_end(chip, err); +} + +esp_err_t esp_flash_get_protectable_regions(const esp_flash_t *chip, const esp_flash_region_t **regions, uint32_t *num_regions) +{ + if(num_regions != NULL) { + *num_regions = 0; // In case caller doesn't check result + } + VERIFY_OP(get_protected_regions); + + if(regions == NULL || num_regions == NULL) { + return ESP_ERR_INVALID_ARG; + } + + *num_regions = chip->chip_drv->num_protectable_regions; + *regions = chip->chip_drv->protectable_regions; + return ESP_OK; +} + +static esp_err_t find_region(const esp_flash_t *chip, const esp_flash_region_t *region, uint8_t *index) +{ + if (region == NULL) { + return ESP_ERR_INVALID_ARG; + } + + for(*index = 0; *index < chip->chip_drv->num_protectable_regions; (*index)++) { + if (memcmp(&chip->chip_drv->protectable_regions[*index], + region, sizeof(esp_flash_region_t)) == 0) { + return ESP_OK; + } + } + + return ESP_ERR_NOT_FOUND; +} + +esp_err_t IRAM_ATTR esp_flash_get_protected_region(esp_flash_t *chip, const esp_flash_region_t *region, bool *protected) +{ + VERIFY_OP(get_protected_regions); + + if (protected == NULL) { + return ESP_ERR_INVALID_ARG; + } + + uint8_t index; + esp_err_t err = find_region(chip, region, &index); + if (err != ESP_OK) { + return err; + } + + uint64_t protection_mask = 0; + err = spiflash_start(chip); + if (err != ESP_OK) { + return err; + } + + err = chip->chip_drv->get_protected_regions(chip, &protection_mask); + if (err == ESP_OK) { + *protected = protection_mask & (1LL << index); + } + + return spiflash_end(chip, err); +} + +esp_err_t IRAM_ATTR esp_flash_set_protected_region(esp_flash_t *chip, const esp_flash_region_t *region, bool protected) +{ + VERIFY_OP(set_protected_regions); + + uint8_t index; + esp_err_t err = find_region(chip, region, &index); + if (err != ESP_OK) { + return err; + } + + uint64_t protection_mask = 0; + err = spiflash_start(chip); + if (err != ESP_OK) { + return err; + } + + err = chip->chip_drv->get_protected_regions(chip, &protection_mask); + if (err == ESP_OK) { + if (protected) { + protection_mask |= (1LL << index); + } else { + protection_mask &= ~(1LL << index); + } + err = chip->chip_drv->set_protected_regions(chip, protection_mask); + } + + return spiflash_end(chip, err); +} + +esp_err_t IRAM_ATTR esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length) +{ + if (length == 0) { + return ESP_OK; + } + VERIFY_OP(read); + if (buffer == NULL || address > chip->size || address+length > chip->size) { + return ESP_ERR_INVALID_ARG; + } + + //when the cache is disabled, only the DRAM can be read, check whether we need to receive in another buffer in DRAM. + bool direct_read = chip->host->supports_direct_read(chip->host, buffer); + uint8_t* temp_buffer = NULL; + + if (!direct_read) { + uint32_t length_to_allocate = MAX(MAX_READ_CHUNK, length); + length_to_allocate = (length_to_allocate+3)&(~3); + temp_buffer = heap_caps_malloc(length_to_allocate, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + ESP_LOGV(TAG, "allocate temp buffer: %p", temp_buffer); + if (temp_buffer == NULL) return ESP_ERR_NO_MEM; + } + + esp_err_t err = ESP_OK; + + do { + err = spiflash_start(chip); + if (err != ESP_OK) { + break; + } + //if required (dma buffer allocated), read to the buffer instead of the original buffer + uint8_t* buffer_to_read = (temp_buffer)? temp_buffer : buffer; + //each time, we at most read this length + //after that, we release the lock to allow some other operations + uint32_t length_to_read = MIN(MAX_READ_CHUNK, length); + + if (err == ESP_OK) { + err = chip->chip_drv->read(chip, buffer_to_read, address, length_to_read); + } + if (err != ESP_OK) { + spiflash_end(chip, err); + break; + } + //even if this is failed, the data is still valid, copy before quit + err = spiflash_end(chip, err); + + //copy back to the original buffer + if (temp_buffer) { + memcpy(buffer, temp_buffer, length_to_read); + } + address += length_to_read; + length -= length_to_read; + buffer += length_to_read; + } while (err == ESP_OK && length > 0); + + free(temp_buffer); + return err; +} + +esp_err_t IRAM_ATTR esp_flash_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length) +{ + if (length == 0) { + return ESP_OK; + } + VERIFY_OP(write); + CHECK_WRITE_ADDRESS(chip, address, length); + if (buffer == NULL || address > chip->size || address+length > chip->size) { + return ESP_ERR_INVALID_ARG; + } + + //when the cache is disabled, only the DRAM can be read, check whether we need to copy the data first + bool direct_write = chip->host->supports_direct_write(chip->host, buffer); + + esp_err_t err = ESP_OK; + /* Write output in chunks, either by buffering on stack or + by artificially cutting into MAX_WRITE_CHUNK parts (in an OS + environment, this prevents writing from causing interrupt or higher priority task + starvation.) */ + do { + uint32_t write_len; + const void *write_buf; + if (direct_write) { + write_len = MIN(length, MAX_WRITE_CHUNK); + write_buf = buffer; + } else { + uint32_t buf[8]; + write_len = MIN(length, sizeof(buf)); + memcpy(buf, buffer, write_len); + write_buf = buf; + } + + err = spiflash_start(chip); + if (err != ESP_OK) { + return err; + } + + err = chip->chip_drv->write(chip, write_buf, address, write_len); + + address += write_len; + buffer = (void *)((intptr_t)buffer + write_len); + length -= write_len; + + err = spiflash_end(chip, err); + } while (err == ESP_OK && length > 0); + return err; +} + +esp_err_t IRAM_ATTR esp_flash_write_encrypted(esp_flash_t *chip, uint32_t address, const void *buffer, uint32_t length) +{ + VERIFY_OP(write_encrypted); + if (((memspi_host_data_t*)chip->host->driver_data)->spi != 0) { + // Encrypted operations have to use SPI0 + return ESP_ERR_FLASH_UNSUPPORTED_HOST; + } + if (buffer == NULL || address > chip->size || address+length > chip->size) { + return ESP_ERR_INVALID_ARG; + } + + esp_err_t err = spiflash_start(chip); + if (err != ESP_OK) { + return err; + } + + err = chip->chip_drv->write_encrypted(chip, buffer, address, length); + + return spiflash_end(chip, err); +} + + +inline static IRAM_ATTR bool regions_overlap(uint32_t a_start, uint32_t a_len,uint32_t b_start, uint32_t b_len) +{ + uint32_t a_end = a_start + a_len; + uint32_t b_end = b_start + b_len; + return (a_end > b_start && b_end > a_start); +} + +#define ESP_FLASH_HOST_CONFIG_DEFAULT() (memspi_host_config_t){ \ + .host_id = 1,\ + .speed = DEFAULT_FLASH_SPEED, \ + .cs_num = 0, \ + .iomux = true, \ + .input_delay_ns = 25,\ +} + +static DRAM_ATTR spi_flash_host_driver_t esp_flash_default_host_drv = ESP_FLASH_DEFAULT_HOST_DRIVER(); + +static DRAM_ATTR memspi_host_data_t default_driver_data; + +/* The default (ie initial boot) no-OS ROM esp_flash_os_functions_t */ +extern const esp_flash_os_functions_t esp_flash_noos_functions; + +static DRAM_ATTR esp_flash_t default_chip = { + .read_mode = DEFAULT_FLASH_MODE, + .host = &esp_flash_default_host_drv, + .os_func = &esp_flash_noos_functions, +}; + +esp_flash_t *esp_flash_default_chip = &default_chip; + +esp_err_t esp_flash_init_default_chip() +{ + memspi_host_config_t cfg = ESP_FLASH_HOST_CONFIG_DEFAULT(); + //the host is already initialized, only do init for the data and load it to the host + spi_flash_hal_init(&default_driver_data, &cfg); + default_chip.host->driver_data = &default_driver_data; + + // ROM TODO: account for non-standard default pins in efuse + // ROM TODO: to account for chips which are slow to power on, maybe keep probing in a loop here + esp_err_t err = esp_flash_init(&default_chip); + if (err != ESP_OK) { + return err; + } + if (default_chip.size < g_rom_flashchip.chip_size) { + ESP_EARLY_LOGE(TAG, "detected size(%dk) smaller than the size in the binary image header(%dk). probe failed.", default_chip.size/1024, g_rom_flashchip.chip_size/1024); + return ESP_ERR_FLASH_SIZE_NOT_MATCH; + } else if (default_chip.size > g_rom_flashchip.chip_size) { + ESP_EARLY_LOGW(TAG, "detected size larger than the size in the binary image header. use the size in the binary image header."); + default_chip.size = g_rom_flashchip.chip_size; + } + default_chip.size = g_rom_flashchip.chip_size; + + esp_flash_default_chip = &default_chip; + return ESP_OK; +} + + +/*------------------------------------------------------------------------------ + Adapter layer to original api before IDF v4.0 +------------------------------------------------------------------------------*/ + +static esp_err_t spi_flash_translate_rc(esp_err_t err) +{ + switch (err) { + case ESP_OK: + return ESP_OK; + case ESP_ERR_INVALID_ARG: + return ESP_ERR_INVALID_ARG; + case ESP_ERR_FLASH_NOT_INITIALISED: + case ESP_ERR_FLASH_PROTECTED: + return ESP_ERR_INVALID_STATE; + case ESP_ERR_NOT_FOUND: + case ESP_ERR_FLASH_UNSUPPORTED_HOST: + case ESP_ERR_FLASH_UNSUPPORTED_CHIP: + return ESP_ERR_NOT_SUPPORTED; + case ESP_ERR_FLASH_NO_RESPONSE: + return ESP_ERR_INVALID_RESPONSE; + default: + ESP_EARLY_LOGE(TAG, "unexpected spi flash error code: %x", err); + abort(); + } + return ESP_OK; +} + +#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL +esp_err_t spi_flash_erase_range(uint32_t start_addr, uint32_t size) +{ + esp_err_t err = esp_flash_erase_region(NULL, start_addr, size); + return spi_flash_translate_rc(err); +} + +esp_err_t spi_flash_write(size_t dst, const void *srcv, size_t size) +{ + esp_err_t err = esp_flash_write(NULL, srcv, dst, size); + return spi_flash_translate_rc(err); + + //CHECK_WRITE_ADDRESS(dst, size); +} + +esp_err_t spi_flash_read(size_t src, void *dstv, size_t size) +{ + esp_err_t err = esp_flash_read(NULL, dstv, src, size); + return spi_flash_translate_rc(err); +} + +esp_err_t spi_flash_unlock() +{ + esp_err_t err = esp_flash_set_chip_write_protect(NULL, false); + return spi_flash_translate_rc(err); +} + +#endif diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index 7b3f5b1f8a..dcfc6cc4cb 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -33,8 +33,8 @@ #include "esp_log.h" #include "esp32/clk.h" #include "esp_flash_partitions.h" -#include "esp_ota_ops.h" #include "cache_utils.h" +#include "esp_flash.h" /* bytes erased by SPIEraseBlock() ROM function */ #define BLOCK_ERASE_SIZE 65536 @@ -116,20 +116,10 @@ static const spi_flash_guard_funcs_t *s_flash_guard_ops; static __attribute__((unused)) bool is_safe_write_address(size_t addr, size_t size) { - bool result = true; - if (addr <= ESP_PARTITION_TABLE_OFFSET + ESP_PARTITION_TABLE_MAX_LEN) { + if (!esp_partition_main_flash_region_safe(addr, size)) { UNSAFE_WRITE_ADDRESS; } - - const esp_partition_t *p = esp_ota_get_running_partition(); - if (addr >= p->address && addr < p->address + p->size) { - UNSAFE_WRITE_ADDRESS; - } - if (addr < p->address && addr + size > p->address) { - UNSAFE_WRITE_ADDRESS; - } - - return result; + return true; } @@ -184,6 +174,7 @@ static inline void IRAM_ATTR spi_flash_guard_op_unlock() } } +#ifdef CONFIG_SPI_FLASH_USE_LEGACY_IMPL static esp_rom_spiflash_result_t IRAM_ATTR spi_flash_unlock() { static bool unlocked = false; @@ -198,6 +189,16 @@ static esp_rom_spiflash_result_t IRAM_ATTR spi_flash_unlock() } return ESP_ROM_SPIFLASH_RESULT_OK; } +#else +static esp_rom_spiflash_result_t IRAM_ATTR spi_flash_unlock() +{ + esp_err_t err = esp_flash_set_chip_write_protect(NULL, false); + if (err != ESP_OK) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + return ESP_ROM_SPIFLASH_RESULT_OK; +} +#endif esp_err_t IRAM_ATTR spi_flash_erase_sector(size_t sec) { @@ -205,6 +206,8 @@ esp_err_t IRAM_ATTR spi_flash_erase_sector(size_t sec) return spi_flash_erase_range(sec * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE); } +#ifdef CONFIG_SPI_FLASH_USE_LEGACY_IMPL +//deprecated, only used in compatible mode esp_err_t IRAM_ATTR spi_flash_erase_range(uint32_t start_addr, uint32_t size) { CHECK_WRITE_ADDRESS(start_addr, size); @@ -416,6 +419,7 @@ out: return spi_flash_translate_rc(rc); } +#endif esp_err_t IRAM_ATTR spi_flash_write_encrypted(size_t dest_addr, const void *src, size_t size) { @@ -483,6 +487,7 @@ esp_err_t IRAM_ATTR spi_flash_write_encrypted(size_t dest_addr, const void *src, return spi_flash_translate_rc(rc); } +#ifdef CONFIG_SPI_FLASH_USE_LEGACY_IMPL esp_err_t IRAM_ATTR spi_flash_read(size_t src, void *dstv, size_t size) { // Out of bound reads are checked in ROM code, but we can give better @@ -624,6 +629,7 @@ out: COUNTER_STOP(read); return spi_flash_translate_rc(rc); } +#endif esp_err_t IRAM_ATTR spi_flash_read_encrypted(size_t src, void *dstv, size_t size) { diff --git a/components/spi_flash/include/spi_flash_lowlevel.h b/components/spi_flash/include/esp_flash.h similarity index 54% rename from components/spi_flash/include/spi_flash_lowlevel.h rename to components/spi_flash/include/esp_flash.h index 0b4ebf9a31..904b09b493 100644 --- a/components/spi_flash/include/spi_flash_lowlevel.h +++ b/components/spi_flash/include/esp_flash.h @@ -1,31 +1,28 @@ +// Copyright 2015-2019 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 +#include "esp_err.h" #include #include -#include "soc/spi_struct.h" +#include "hal/spi_flash_host_drv.h" -struct esp_flash_driver; +struct spi_flash_chip_t; +typedef struct spi_flash_chip_t spi_flash_chip_t; -/** @brief Mode used for reading from SPI flash */ -typedef enum { - ESP_FLASH_QIO, ///< Both address & data transferred using quad I/O - ESP_FLASH_QOUT, ///< Data read using quad I/O - ESP_FLASH_DIO, ///< Both address & data transferred using dual I/O - ESP_FLASH_DOUT, ///< Data read using dual I/O - ESP_FLASH_FASTRD, ///< Data read using single I/O, no limit on speed - ESP_FLASH_SLOWRD, ///< Data read using single I/O, some limits on speed - - ESP_FLASH_READ_MODE_MAX, -} esp_flash_read_mode_t; - -/** @brief Configured SPI flash clock speed */ -typedef enum { - ESP_FLASH_80MHZ, - ESP_FLASH_40MHZ, - ESP_FLASH_26MHZ, - ESP_FLASH_20MHZ, - ESP_FLASH_SPEED_MAX, -} esp_flash_speed_t; +typedef struct esp_flash_t esp_flash_t; /** @brief Structure for describing a region of flash */ typedef struct { @@ -33,56 +30,60 @@ typedef struct { uint32_t size; } esp_flash_region_t; -// TODO this is copied from SPI driver, should be unified somehow +/* OS-level integration hooks for accessing flash chips inside a running OS */ typedef struct { - int mosi_io_num; ///< GPIO pin for Master Out Slave In (=spi_d) signal - int miso_io_num; ///< GPIO pin for Master In Slave Out (=spi_q) signal - int sclk_io_num; ///< GPIO pin for Spi CLocK signal - int quadwp_io_num; ///< GPIO pin for WP (Write Protect) signal which is used as D2 in 4-bit communication modes, or -1 if not used. - int quadhd_io_num; ///< GPIO pin for HD (HolD) signal which is used as D3 in 4-bit communication modes, or -1 if not used. -} esp_flash_pin_cfg_t; + /** + * Called before commencing any flash operation. Does not need to be + * recursive (ie is called at most once for each call to 'end'). + */ + esp_err_t (*start)(void *arg); + + /** Called after completing any flash operation. */ + esp_err_t (*end)(void *arg); + + /** Delay for at least 'ms' milliseconds. Called in between 'start' and 'end'. */ + esp_err_t (*delay_ms)(void *arg, unsigned ms); +} esp_flash_os_functions_t; /** @brief Structure to describe a SPI flash chip connected to the system. Structure must be passed to esp_flash_init() before use. */ -typedef struct { - spi_dev_t *spi; ///< Pointer to hardware SPI bus registers used for connection (SP1, SPI2 or SPI3). Set before initialisation. - esp_flash_speed_t speed; ///< Configured SPI flash clock speed. Set before initialisation. +struct esp_flash_t { + const spi_flash_chip_t *chip_drv; ///< Pointer to chip-model-specific "adpater" structure. If NULL, will be detected during initialisatiopn. + spi_flash_host_driver_t *host; ///< Pointer to hardware-specific "host_driver" structure. + + const esp_flash_os_functions_t *os_func; ///< Pointer to os-specific hooker strcuture. + void *os_func_data; ///< Pointer to argument for os-specific hooker. + esp_flash_read_mode_t read_mode; ///< Configured SPI flash read mode. Set before initialisation. uint32_t size; ///< Size of SPI flash in bytes. If 0, size will be detected during initialisation. - const struct esp_flash_driver *drv; ///< Pointer to chip-model-specific "driver" structure. If NULL, will be detected during initialisatiopn. - const esp_flash_pin_cfg_t *pins; ///< Pin configuration for the chip +}; - void *driver_data; ///< Currently unused, allows drivers to store driver-implementation-specific data on initialisation -} esp_flash_chip_t; - -/** @brief Possible errors returned from SPI flash low-level API */ -typedef enum { - FLASH_OK = 0, ///< Success - FLASH_ERR_NOT_INITIALISED, ///< esp_flash_chip_t structure not correctly initialised by esp_flash_init(). - FLASH_ERR_INVALID_ARG, ///< A supplied argument was invalid. - FLASH_ERR_NOT_FOUND, ///< A requested value is not found. - FLASH_ERR_NO_RESPONSE, ///< Chip did not respond to the command, or timed out. - FLASH_ERR_UNSUPPORTED_HOST, ///< Requested operation isn't supported via this host SPI bus (chip->spi field). - FLASH_ERR_UNSUPPORTED_CHIP, ///< Requested operation isn't supported by this model of SPI flash chip. - FLASH_ERR_PROTECTED, ///< Write operation failed due to chip's write protection being enabled. -} esp_flash_err_t; /** @brief Initialise SPI flash chip interface. - * + * * This function must be called before any other API functions are called for this chip. * * @note Only the spi, speed & read_mode fields of the chip structure need to be initialised. Other fields will be auto-detected * if left set to zero or NULL. * - * @note If the chip->drv pointer is NULL, chip driver will be autodetected based on its manufacturer & product IDs. See + * @note If the chip->drv pointer is NULL, chip chip_drv will be autodetected based on its manufacturer & product IDs. See * esp_flash_registered_flash_drivers pointer for details of this process. * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. - * @return FLASH_OK on success, or a flash error code if initialisation fails. + * @return ESP_OK on success, or a flash error code if initialisation fails. */ -esp_flash_err_t esp_flash_init(esp_flash_chip_t *chip); +esp_err_t esp_flash_init(esp_flash_t *chip); + +/** + * Check if appropriate chip driver is set. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * + * @return true if set, otherwise false. + */ +bool esp_flash_chip_driver_initialized(const esp_flash_t *chip); /** @brief Read flash ID via the common "RDID" SPI flash command. * @@ -91,9 +92,9 @@ esp_flash_err_t esp_flash_init(esp_flash_chip_t *chip); * * ID is a 24-bit value. Lower 16 bits of 'id' are the chip ID, upper 8 bits are the manufacturer ID. * - * @return FLASH_OK on success, or a flash error code if operation failed. + * @return ESP_OK on success, or a flash error code if operation failed. */ -esp_flash_err_t esp_flash_read_id(const esp_flash_chip_t *chip, uint32_t *id); +esp_err_t esp_flash_read_id(esp_flash_t *chip, uint32_t *id); /** @brief Detect flash size based on flash ID. * @@ -103,18 +104,18 @@ esp_flash_err_t esp_flash_read_id(const esp_flash_chip_t *chip, uint32_t *id); * @note Most flash chips use a common format for flash ID, where the lower 4 bits specify the size as a power of 2. If * the manufacturer doesn't follow this convention, the size may be incorrectly detected. * - * @return FLASH_OK on success, or a flash error code if operation failed. + * @return ESP_OK on success, or a flash error code if operation failed. */ -esp_flash_err_t esp_flash_detect_size(const esp_flash_chip_t *chip, uint32_t *size); +esp_err_t esp_flash_get_size(esp_flash_t *chip, uint32_t *size); /** @brief Erase flash chip contents * * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() * * - * @return FLASH_OK on success, or a flash error code if operation failed. + * @return ESP_OK on success, or a flash error code if operation failed. */ -esp_flash_err_t esp_flash_erase_chip(const esp_flash_chip_t *chip); +esp_err_t esp_flash_erase_chip(esp_flash_t *chip); /** @brief Erase a region of the flash chip * @@ -122,45 +123,45 @@ esp_flash_err_t esp_flash_erase_chip(const esp_flash_chip_t *chip); * @param start Address to start erasing flash. Must be sector aligned. * @param len Length of region to erase. Must also be sector aligned. * - * Sector size is specifyed in chip->drv->sector_size field (typically 4096 bytes.) FLASH_ERR_INVALID_ARG will be + * Sector size is specifyed in chip->drv->sector_size field (typically 4096 bytes.) ESP_ERR_INVALID_ARG will be * returned if the start & length are not a multiple of this size. * * Erase is performed using block (multi-sector) erases where possible (block size is specified in * chip->drv->block_erase_size field, typically 65536 bytes). Remaining sectors are erased using individual sector erase * commands. * - * @return FLASH_OK on success, or a flash error code if operation failed. + * @return ESP_OK on success, or a flash error code if operation failed. */ -esp_flash_err_t esp_flash_erase_region(const esp_flash_chip_t *chip, uint32_t start, uint32_t len); +esp_err_t esp_flash_erase_region(esp_flash_t *chip, uint32_t start, uint32_t len); /** @brief Read if the entire chip is write protected * * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() * @param[out] write_protected Pointer to boolean, set to the value of the write protect flag. * - * @note A correct result for this flag depends on the SPI flash chip model and driver in use (via the 'chip->drv' + * @note A correct result for this flag depends on the SPI flash chip model and chip_drv in use (via the 'chip->drv' * field). * - * @return FLASH_OK on success, or a flash error code if operation failed. + * @return ESP_OK on success, or a flash error code if operation failed. */ -esp_flash_err_t esp_flash_get_chip_write_protect(const esp_flash_chip_t *chip, bool *write_protected); +esp_err_t esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *write_protected); /** @brief Set write protection for the SPI flash chip * * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() * @param write_protected Boolean value for the write protect flag * - * @note Correct behaviour of this function depends on the SPI flash chip model and driver in use (via the 'chip->drv' + * @note Correct behaviour of this function depends on the SPI flash chip model and chip_drv in use (via the 'chip->drv' * field). * - * If write protection is enabled, destructive operations will fail with FLASH_ERR_PROTECTED. + * If write protection is enabled, destructive operations will fail with ESP_ERR_FLASH_PROTECTED. * * Some SPI flash chips may require a power cycle before write protect status can be cleared. Otherwise, * write protection can be removed via a follow-up call to this function. * - * @return FLASH_OK on success, or a flash error code if operation failed. + * @return ESP_OK on success, or a flash error code if operation failed. */ -esp_flash_err_t esp_flash_set_chip_write_protect(const esp_flash_chip_t *chip, bool write_protect_chip); +esp_err_t esp_flash_set_chip_write_protect(esp_flash_t *chip, bool write_protect_chip); /** @brief Read the list of individually protectable regions of this SPI flash chip. @@ -169,12 +170,13 @@ esp_flash_err_t esp_flash_set_chip_write_protect(const esp_flash_chip_t *chip, b * @param regions[out] Pointer to receive a pointer to the array of protectable regions of the chip. * @param[out] Pointer to an integer receiving the count of protectable regions in the array returned in 'regions'. * - * @note Correct behaviour of this function depends on the SPI flash chip model and driver in use (via the 'chip->drv' + * @note Correct behaviour of this function depends on the SPI flash chip model and chip_drv in use (via the 'chip->drv' * field). * - * @return FLASH_OK on success, or a flash error code if operation failed. + * @return ESP_OK on success, or a flash error code if operation failed. */ -esp_flash_err_t esp_flash_get_protectable_regions(const esp_flash_chip_t *chip, const esp_flash_region_t **regions, uint32_t *num_regions); +esp_err_t +esp_flash_get_protectable_regions(const esp_flash_t *chip, const esp_flash_region_t **regions, uint32_t *num_regions); /** @brief Detect if a region of the SPI flash chip is protected @@ -185,12 +187,12 @@ esp_flash_err_t esp_flash_get_protectable_regions(const esp_flash_chip_t *chip, * * @note It is possible for this result to be false and write operations to still fail, if protection is enabled for the entire chip. * - * @note Correct behaviour of this function depends on the SPI flash chip model and driver in use (via the 'chip->drv' + * @note Correct behaviour of this function depends on the SPI flash chip model and chip_drv in use (via the 'chip->drv' * field). * - * @return FLASH_OK on success, or a flash error code if operation failed. + * @return ESP_OK on success, or a flash error code if operation failed. */ -esp_flash_err_t esp_flash_get_protected_region(const esp_flash_chip_t *chip, const esp_flash_region_t *region, bool *protected); +esp_err_t esp_flash_get_protected_region(esp_flash_t *chip, const esp_flash_region_t *region, bool *protected); /** @brief Update the protected status for a region of the SPI flash chip * @@ -200,17 +202,17 @@ esp_flash_err_t esp_flash_get_protected_region(const esp_flash_chip_t *chip, con * * @note It is possible for the region protection flag to be cleared and write operations to still fail, if protection is enabled for the entire chip. * - * @note Correct behaviour of this function depends on the SPI flash chip model and driver in use (via the 'chip->drv' + * @note Correct behaviour of this function depends on the SPI flash chip model and chip_drv in use (via the 'chip->drv' * field). * - * @return FLASH_OK on success, or a flash error code if operation failed. + * @return ESP_OK on success, or a flash error code if operation failed. */ -esp_flash_err_t esp_flash_set_protected_region(const esp_flash_chip_t *chip, const esp_flash_region_t *region, bool protected); +esp_err_t esp_flash_set_protected_region(esp_flash_t *chip, const esp_flash_region_t *region, bool protected); /** @brief Read data from the SPI flash chip * * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() - * @param buffer Pointer to a buffer where the data will be read. + * @param buffer Pointer to a buffer where the data will be read. To get better performance, this should be in the DRAM and word aligned. * @param address Address on flash to read from. Must be less than chip->size field. * @param length Length (in bytes) of data to read. * @@ -219,22 +221,26 @@ esp_flash_err_t esp_flash_set_protected_region(const esp_flash_chip_t *chip, con * @note If on-chip flash encryption is used, this function returns raw (ie encrypted) data. Use the flash cache * to transparently decrypt data. * - * @return FLASH_OK on success, or a flash error code if operation failed. + * @return + * - ESP_OK: success + * - ESP_ERR_NO_MEM: the buffer is not valid, however failed to malloc on + * the heap. + * - or a flash error code if operation failed. */ -esp_flash_err_t esp_flash_read(const esp_flash_chip_t *chip, void *buffer, uint32_t address, uint32_t length); +esp_err_t esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length); /** @brief Write data to the SPI flash chip * * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() * @param address Address on flash to write to. Must be previously erased (SPI NOR flash can only write bits 1->0). - * @param buffer Pointer to a buffer with the data to write. + * @param buffer Pointer to a buffer with the data to write. To get better performance, this should be in the DRAM and word aligned. * @param length Length (in bytes) of data to write. * * There are no alignment constraints on buffer, address or length. * - * @return FLASH_OK on success, or a flash error code if operation failed. + * @return ESP_OK on success, or a flash error code if operation failed. */ -esp_flash_err_t esp_flash_write(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length); +esp_err_t esp_flash_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length); /** @brief Encrypted and write data to the SPI flash chip using on-chip hardware flash encryption * @@ -245,21 +251,44 @@ esp_flash_err_t esp_flash_write(const esp_flash_chip_t *chip, uint32_t address, * * @note Both address & length must be 16 byte aligned, as this is the encryption block size * - * @return FLASH_OK on success, or a flash error code if operation failed. + * @return ESP_OK on success, or a flash error code if operation failed. */ -esp_flash_err_t esp_flash_write_encrypted(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length); +esp_err_t esp_flash_write_encrypted(esp_flash_t *chip, uint32_t address, const void *buffer, uint32_t length); + /** @brief Pointer to the "default" SPI flash chip, ie the main chip attached to the MCU. This chip is used if the 'chip' argument pass to esp_flash_xxx API functions is ever NULL. */ -extern const esp_flash_chip_t *esp_flash_default_chip; +extern esp_flash_t *esp_flash_default_chip; /** @brief Initialise the default SPI flash chip * * Called by OS startup code. You do not need to call this in your own applications. */ -esp_flash_err_t esp_flash_init_default_chip(); +esp_err_t esp_flash_init_default_chip(); -/** Enable OS-level SPI flash protections in IDF */ -void esp_flash_low_level_app_init(); /* ROM TODO move this to IDF */ +/** + * Enable OS-level SPI flash protections in IDF + * + * @return ESP_OK if success, otherwise failed. See return value of ``esp_flash_init_os_functions``. + */ +esp_err_t esp_flash_app_init(); /* ROM TODO move this to IDF */ + +/** + * Enable OS-level SPI flash for a specific chip. + * + * @param chip The chip to init os functions. + * @param host_id Which SPI host to use, 0 for SPI1, 1 for HSPI2 and 2 for VSPI. + * + * @return ESP_OK if success, otherwise failed. See return value of ``esp_flash_init_os_functions``. + */ +esp_err_t esp_flash_init_os_functions(esp_flash_t *chip, int host_id); + +/* The default (ie initial boot) no-OS ROM esp_flash_os_functions_t */ +extern const esp_flash_os_functions_t spi1_default_os_functions; //todo: put into non-ROM headers + +/* Pointer to the current esp_flash_os_functions_t structure in use. + Can be changed at runtime to reflect different running conditions. + */ +//extern const esp_flash_os_functions_t *os_func; diff --git a/components/spi_flash/include/esp_spi_flash.h b/components/spi_flash/include/esp_spi_flash.h index 74c96fd36c..795142f4a1 100644 --- a/components/spi_flash/include/esp_spi_flash.h +++ b/components/spi_flash/include/esp_spi_flash.h @@ -25,7 +25,6 @@ extern "C" { #endif -#define ESP_ERR_FLASH_BASE 0x10010 #define ESP_ERR_FLASH_OP_FAIL (ESP_ERR_FLASH_BASE + 1) #define ESP_ERR_FLASH_OP_TIMEOUT (ESP_ERR_FLASH_BASE + 2) @@ -36,7 +35,7 @@ extern "C" { /** * @brief Initialize SPI flash access driver * - * This function must be called exactly once, before any other + * This function must be called exactly once, before any other * spi_flash_* functions are called. * Currently this function is called from startup code. There is * no need to call it from application code. diff --git a/components/spi_flash/include/memspi_host_driver.h b/components/spi_flash/include/memspi_host_driver.h new file mode 100644 index 0000000000..2347398aa1 --- /dev/null +++ b/components/spi_flash/include/memspi_host_driver.h @@ -0,0 +1,111 @@ +// Copyright 2015-2019 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 +#include "hal/spi_flash_hal.h" + +/** Default configuration for the memspi (high speed version) */ +#define ESP_FLASH_DEFAULT_HOST_DRIVER() (spi_flash_host_driver_t) { \ + .dev_config = spi_flash_hal_device_config, \ + .common_command = spi_flash_hal_common_command, \ + .read_id = memspi_host_read_id_hs, \ + .erase_chip = spi_flash_hal_erase_chip, \ + .erase_sector = spi_flash_hal_erase_sector, \ + .erase_block = spi_flash_hal_erase_block, \ + .read_status = memspi_host_read_status_hs, \ + .set_write_protect = spi_flash_hal_set_write_protect, \ + .supports_direct_write = spi_flash_hal_supports_direct_write, \ + .supports_direct_read = spi_flash_hal_supports_direct_read, \ + .program_page = spi_flash_hal_program_page, \ + .max_write_bytes = SPI_FLASH_HAL_MAX_WRITE_BYTES, \ + .read = spi_flash_hal_read, \ + .max_read_bytes = SPI_FLASH_HAL_MAX_READ_BYTES, \ + .host_idle = spi_flash_hal_host_idle, \ + .configure_host_read_mode = spi_flash_hal_configure_host_read_mode, \ + .poll_cmd_done = spi_flash_hal_poll_cmd_done, \ + .flush_cache = memspi_host_flush_cache, \ + .region_protected = memspi_region_protected, \ +} + +/// configuration for the memspi host +typedef spi_flash_memspi_config_t memspi_host_config_t; +/// context for the memspi host +typedef spi_flash_memspi_data_t memspi_host_data_t; + +/** + * Initialize the memory SPI host. + * + * @param host Pointer to the host structure. + * @param data Pointer to allocated space to hold the context of host driver. + * @param cfg Pointer to configuration structure + * + * @return always return ESP_OK + */ +esp_err_t memspi_host_init_pointers(spi_flash_host_driver_t *host, memspi_host_data_t *data, const memspi_host_config_t *cfg); + +/******************************************************************************* + * NOTICE + * Rest part of this file are part of the HAL layer + * The HAL is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +/** + * High speed implementation of RDID through memspi interface relying on the + * ``common_command``. + * + * @param driver The driver context. + * @param id Output of the read ID from the slave. + * + * @return + * - ESP_OK: if success + * - ESP_ERR_FLASH_NO_RESPONSE: if no response from chip + * - or other cases from ``spi_hal_common_command`` + */ +esp_err_t memspi_host_read_id_hs(spi_flash_host_driver_t *driver, uint32_t *id); + +/** + * High speed implementation of RDSR through memspi interface relying on the + * ``common_command``. + * + * @param driver The driver context. + * @param id Output of the read ID from the slave. + * + * @return + * - ESP_OK: if success + * - or other cases from ``spi_hal_common_command`` + */ +esp_err_t memspi_host_read_status_hs(spi_flash_host_driver_t *driver, uint8_t *out_sr); + +/** + * Flush the cache (if needed) after the contents are modified. + * + * @param driver The driver context. + * @param addr Start address of the modified region + * @param size Size of the region modified. + * + * @return always ESP_OK. + */ +esp_err_t memspi_host_flush_cache(spi_flash_host_driver_t* driver, uint32_t addr, uint32_t size); + +/** + * Check if the given region is protected. + * + * @param driver The driver context. + * @param addr Start address of the region. + * @param size Size of the region to check. + * + * @return true if protected, otherwise false. + */ +bool memspi_region_protected(spi_flash_host_driver_t* driver, uint32_t addr, uint32_t size); \ No newline at end of file diff --git a/components/spi_flash/include/spi_flash_lowlevel_driver.h b/components/spi_flash/include/spi_flash_chip_driver.h similarity index 55% rename from components/spi_flash/include/spi_flash_lowlevel_driver.h rename to components/spi_flash/include/spi_flash_chip_driver.h index 0343cc7cb4..fd5c1e4c92 100644 --- a/components/spi_flash/include/spi_flash_lowlevel_driver.h +++ b/components/spi_flash/include/spi_flash_chip_driver.h @@ -1,23 +1,43 @@ -#pragma once -#include "spi_flash_lowlevel.h" +// Copyright 2015-2019 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. -/** @brief SPI flash driver definition structure. +#pragma once +#include "esp_flash.h" + +struct esp_flash_t; +typedef struct esp_flash_t esp_flash_t; + +typedef struct spi_flash_chip_t spi_flash_chip_t; +/** @brief SPI flash chip driver definition structure. * - * The driver structure contains chip-specific pointers to functions to perform SPI flash operations, and some + * The chip driver structure contains chip-specific pointers to functions to perform SPI flash operations, and some * chip-specific numeric values. * - * @note This is not a public API. Driver-specific functions are called from the public API (declared in - * spi_flash_lowlevel.h). They assume the caller has already validated arguments and enabled relevant protections + * @note This is not a public API. These functions are called from the public API (declared in + * esp_flash.h). They assume the caller has already validated arguments and enabled relevant protections * (disabling flash cache, prevent concurrent SPI access, etc.) * - * Do not call driver functions directly in other contexts. + * Do not call chip driver functions directly in other contexts. * - * A generic driver and it's related operations are defined in spi_flash_lowlevel_generic.h which can be used as - * building blocks for written new/specific SPI flash chip drivers. + * A generic driver for generic chips and its related operations are defined in + * spi_flash_chip_generic.h which can be used as building blocks for written + * new/specific SPI flash chip drivers. * * @note All of these functions may be called with SPI flash cache disabled, so must only ever access IRAM/DRAM/ROM. */ -typedef struct esp_flash_driver { +struct spi_flash_chip_t { + const char *name; ///< Name of the chip driver /* Probe to detect if a supported SPI flash chip is found. * * Attempts to configure 'chip' with these operations and probes for a matching SPI flash chip. @@ -31,28 +51,25 @@ typedef struct esp_flash_driver { * It is permissible for the driver to modify the 'chip' structure if probing succeeds (specifically, to assign something to the * driver_data pointer if that is useful for the driver.) * - * @return FLASH_OK if probing was successful, an error otherwise. Driver may - * assume that returning FLASH_OK means it has claimed this chip. + * @return ESP_OK if probing was successful, an error otherwise. Driver may + * assume that returning ESP_OK means it has claimed this chip. */ - esp_flash_err_t (*probe)(esp_flash_chip_t *chip, uint32_t flash_id); + esp_err_t (*probe)(esp_flash_t *chip, uint32_t flash_id); + + esp_err_t (*reset)(esp_flash_t *chip); - /* Read SPI flash ID - * - * Sends RDID (or an equivalent command) to the device. - */ - esp_flash_err_t (*read_id)(const esp_flash_chip_t *chip, uint32_t *id); /* Detect SPI flash size * - * Interrogate the chip to detect it's size. + * Interrogate the chip to detect its size. */ - esp_flash_err_t (*detect_size)(const esp_flash_chip_t *chip, uint32_t *size); + esp_err_t (*detect_size)(esp_flash_t *chip, uint32_t *size); /* Erase the entire chip Caller has verified the chip is not write protected. */ - esp_flash_err_t (*erase_chip)(const esp_flash_chip_t *chip); + esp_err_t (*erase_chip)(esp_flash_t *chip); /* Erase a sector of the chip. Sector size is specified in the 'sector_size' field. @@ -60,23 +77,23 @@ typedef struct esp_flash_driver { Caller has verified that this sector should be non-write-protected. */ - esp_flash_err_t (*erase_sector)(const esp_flash_chip_t *chip, uint32_t sector_address); + esp_err_t (*erase_sector)(esp_flash_t *chip, uint32_t sector_address); /* Erase a multi-sector block of the chip. Block size is specified in the 'block_erase_size' field. sector_address is an offset in bytes. Caller has verified that this block should be non-write-protected. */ - esp_flash_err_t (*erase_block)(const esp_flash_chip_t *chip, uint32_t block_address); + esp_err_t (*erase_block)(esp_flash_t *chip, uint32_t block_address); uint32_t sector_size; /* Sector is minimum erase size */ uint32_t block_erase_size; /* Optimal (fastest) block size for multi-sector erases on this chip */ /* Read the write protect status of the entire chip. */ - esp_flash_err_t (*get_chip_write_protect)(const esp_flash_chip_t *chip, bool *write_protected); + esp_err_t (*get_chip_write_protect)(esp_flash_t *chip, bool *write_protected); /* Set the write protect status of the entire chip. */ - esp_flash_err_t (*set_chip_write_protect)(const esp_flash_chip_t *chip, bool write_protect_chip); + esp_err_t (*set_chip_write_protect)(esp_flash_t *chip, bool write_protect_chip); /* Number of individually write protectable regions on this chip. Range 0-63. */ uint8_t num_protectable_regions; @@ -84,20 +101,20 @@ typedef struct esp_flash_driver { const esp_flash_region_t *protectable_regions; /* Get a bitmask describing all protectable regions on the chip. Each bit represents one entry in the protectable_regions array, ie bit (1<drv->set_read_mode(chip) in order to configure the chip's read mode correctly. */ - esp_flash_err_t (*read)(const esp_flash_chip_t *chip, void *buffer, uint32_t address, uint32_t length); + esp_err_t (*read)(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length); /* Write any amount of data to the chip. */ - esp_flash_err_t (*write)(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length); + esp_err_t (*write)(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length); /* Use the page program command to write data to the chip. @@ -110,33 +127,33 @@ typedef struct esp_flash_driver { * - The region between 'address' and 'address + length' will not cross a page_size aligned boundary (the write * implementation is expected to split such a write into two before calling page_program.) */ - esp_flash_err_t (*page_program)(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length); + esp_err_t (*program_page)(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length); /* Page size as written by the page_program function. Usually 256 bytes. */ uint32_t page_size; /* Perform an encrypted write to the chip, using internal flash encryption hardware. */ - esp_flash_err_t (*write_encrypted)(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length); + esp_err_t (*write_encrypted)(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length); /* Set the write enable flag. This function is called internally by other functions in this structure, before a destructive operation takes place. */ - esp_flash_err_t (*write_enable)(const esp_flash_chip_t *chip); + esp_err_t (*set_write_protect)(esp_flash_t *chip, bool write_protect); /* Wait for the SPI flash chip to be idle (any write operation to be complete.) This function is both called from the higher-level API functions, and from other functions in this structure. - timeout_ms should be a timeout (in milliseconds) before the function returns FLASH_ERR_NO_RESPONSE. This is useful to avoid hanging + timeout_ms should be a timeout (in milliseconds) before the function returns ESP_ERR_TIMEOUT. This is useful to avoid hanging if the chip is otherwise unresponsive (ie returns all 0xFF or similar.) */ - esp_flash_err_t (*wait_idle)(const esp_flash_chip_t *chip, unsigned timeout_ms); + esp_err_t (*wait_idle)(esp_flash_t *chip, unsigned timeout_ms); /* Configure both the SPI host and the chip for the read mode specified in chip->read_mode. * * This function is called by the higher-level API before the 'read' function is called. * - * Can return FLASH_ERR_UNSUPPORTED_HOST or FLASH_ERR_UNSUPPORTED_CHIP if the specified mode is unsupported. + * Can return ESP_ERR_FLASH_UNSUPPORTED_HOST or ESP_ERR_FLASH_UNSUPPORTED_CHIP if the specified mode is unsupported. */ - esp_flash_err_t (*set_read_mode)(const esp_flash_chip_t *chip); -} esp_flash_driver_t; + esp_err_t (*set_read_mode)(esp_flash_t *chip); +}; /* Pointer to an array of pointers to all known drivers for flash chips. This array is used by esp_flash_init() to detect the flash chip driver, if none is supplied by the caller. @@ -145,32 +162,4 @@ typedef struct esp_flash_driver { This pointer can be overwritten with a pointer to a new array, to update the list of known flash chips. */ -extern const esp_flash_driver_t **esp_flash_registered_flash_drivers; - -/* Provide OS-level integration hooks for accessing flash chips - inside a running OS */ -typedef struct -{ - /* Call this function before commencing any flash operation. - - Does not need to be recursive (ie is called at most once for each call to 'end'. - */ - esp_flash_err_t (*start)(const esp_flash_chip_t *chip); - - /* Call this function after completing any flash operation. */ - esp_flash_err_t (*end)(const esp_flash_chip_t *chip); - - /* Delay for at least 'ms' milliseconds. - - This function will be called in between 'start' and 'end'. - */ - esp_flash_err_t (*delay_ms)(unsigned ms); -} esp_flash_os_functions_t; - -/* The default (ie initial boot) no-OS ROM esp_flash_os_functions_t */ -const esp_flash_os_functions_t esp_flash_noos_functions; - -/* Pointer to the current esp_flash_os_functions_t structure in use. - Can be changed at runtime to reflect different running conditions. - */ -extern const esp_flash_os_functions_t *esp_flash_os_functions; +extern const spi_flash_chip_t **esp_flash_registered_chips; diff --git a/components/spi_flash/include/spi_flash_chip_generic.h b/components/spi_flash/include/spi_flash_chip_generic.h new file mode 100644 index 0000000000..676e173111 --- /dev/null +++ b/components/spi_flash/include/spi_flash_chip_generic.h @@ -0,0 +1,275 @@ +// Copyright 2015-2019 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 + +#include +#include "esp_flash.h" +#include "spi_flash_chip_driver.h" + + +/* + * The 'chip_generic' SPI flash operations are a lowest common subset of SPI + * flash commands, that work across most chips. + * + * These can be used as-is via the esp_flash_common_chip_driver chip_drv, or + * they can be used as "base chip_drv" functions when creating a new + * spi_flash_host_driver_t chip_drv structure. + * + * All of the functions in this header are internal functions, not part of a + * public API. See esp_flash.h for the public API. + */ + +/** + * @brief Generic probe function + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param flash_id expected manufacture id. + * + * @return ESP_OK if the id read from chip->drv_read_id matches (always). + */ +esp_err_t spi_flash_chip_generic_probe(esp_flash_t *chip, uint32_t flash_id); + +/** + * @brief Generic reset function + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * + * @return ESP_OK if sending success, or error code passed from ``common_command`` or ``wait_idle`` functions of host driver. + */ +esp_err_t spi_flash_chip_generic_reset(esp_flash_t *chip); + +/** + * @brief Generic size detection function + * + * Tries to detect the size of chip by using the lower 4 bits of the chip->drv->read_id result = N, and assuming size is 2 ^ N. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param size Output of the detected size + * + * @return + * - ESP_OK if success + * - ESP_ERR_FLASH_UNSUPPORTED_CHIP if the manufacturer id is not correct, which may means an error in the reading + * - or other error passed from the ``read_id`` function of host driver + */ +esp_err_t spi_flash_chip_generic_detect_size(esp_flash_t *chip, uint32_t *size); + +/** + * @brief Erase chip by using the generic erase chip (C7h) command. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * + * @return + * - ESP_OK if success + * - or other error passed from the ``set_write_protect``, ``wait_idle`` or ``erase_chip`` function of host driver + */ +esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip); + +/** + * @brief Erase sector by using the generic sector erase (20h) command. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param start_address Start address of the sector to erase + * + * @return + * - ESP_OK if success + * - or other error passed from the ``set_write_protect``, ``wait_idle`` or ``erase_sector`` function of host driver + */ +esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_address); + +/** + * @brief Erase block by using the generic 64KB block erase (D8h) command + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param start_address Start address of the block to erase + * + * @return + * - ESP_OK if success + * - or other error passed from the ``set_write_protect``, ``wait_idle`` or ``erase_block`` function of host driver + */ +esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_address); + +/** + * @brief Read from flash by using a read command that matches the programmed + * read mode. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param buffer Buffer to hold the data read from flash + * @param address Start address of the data on the flash + * @param length Length to read + * + * @return always ESP_OK currently + */ +esp_err_t spi_flash_chip_generic_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length); + +/** + * @brief Perform a page program using the page program (02h) command. + * + * @note Length of each call should not excced the limitation in + * ``chip->host->max_write_bytes``. This function is called in + * ``spi_flash_chip_generic_write`` recursively until the whole page is + * programmed. Strongly suggest to call ``spi_flash_chip_generic_write`` + * instead. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param buffer Buffer holding the data to program + * @param address Start address to write to flash + * @param length Length to write, no longer than ``chip->host->max_write_bytes``. + * + * @return + * - ESP_OK if success + * - or other error passed from the ``wait_idle`` or ``program_page`` function of host driver + */ +esp_err_t +spi_flash_chip_generic_page_program(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length); + +/** + * @brief Perform a generic write. Split the write buffer into page program + * operations, and call chip->chip_drv->page-program() for each. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param buffer Buffer holding the data to program + * @param address Start address to write to flash + * @param length Length to write + * + * @return + * - ESP_OK if success + * - or other error passed from the ``wait_idle`` or ``program_page`` function of host driver + */ +esp_err_t spi_flash_chip_generic_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length); + +/** + * @brief Perform a write using on-chip flash encryption. Not implemented yet. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param buffer Buffer holding the data to program + * @param address Start address to write to flash + * @param length Length to write + * + * @return always ESP_ERR_FLASH_UNSUPPORTED_HOST. + */ +esp_err_t +spi_flash_chip_generic_write_encrypted(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length); + +/** + * @brief Send the write enable (06h) command and verify the expected bit (1) in + * the status register is set. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param write_protect true to enable write protection, false to send write enable. + * + * @return + * - ESP_OK if success + * - or other error passed from the ``wait_idle``, ``read_status`` or ``set_write_protect`` function of host driver + */ +esp_err_t spi_flash_chip_generic_write_enable(esp_flash_t *chip, bool write_protect); + +/** + * @brief Read flash status via the RDSR command (05h) and wait for bit 0 (write + * in progress bit) to be cleared. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param timeout_ms Time to wait before timeout, in ms. + * + * @return + * - ESP_OK if success + * - ESP_ERR_TIMEOUT if not idle before timeout + * - or other error passed from the ``wait_idle`` or ``read_status`` function of host driver + */ +esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_ms); + +/** + * @brief Set the specified SPI read mode according to the data in the chip + * context. Set quad enable status register bit if needed. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * + * @return + * - ESP_OK if success +* - ESP_ERR_TIMEOUT if not idle before timeout + * - or other error passed from the ``set_write_protect`` or ``common_command`` function of host driver + */ +esp_err_t spi_flash_chip_generic_set_read_mode(esp_flash_t *chip); + +/** + * Generic SPI flash chip_drv, uses all the above functions for its operations. + * In default autodetection, this is used as a catchall if a more specific + * chip_drv is not found. + */ +extern const spi_flash_chip_t esp_flash_chip_generic; + +/******************************************************************************* + * Utilities +*******************************************************************************/ + +/** + * @brief Wait for the SPI host hardware state machine to be idle. + * + * This isn't a flash chip_drv operation, but it's called by + * spi_flash_chip_generic_wait_idle() and may be useful when implementing + * alternative drivers. + * + * timeout_ms will be decremented if the function needs to wait until the host hardware is idle. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * + * @return + * - ESP_OK if success + * - ESP_ERR_TIMEOUT if not idle before timeout + * - or other error passed from the ``set_write_protect`` or ``common_command`` function of host driver + */ +esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_ms); + +/** + * @brief Utility function for set_read_mode chip_drv function + * + * Most setting of read mode follows a common pattern, except for how to enable Quad I/O modes (QIO/QOUT). + * These use different commands to read/write the status register, and a different bit is set/cleared. + * + * This is a generic utility function to implement set_read_mode() for this pattern. Also configures host + * registers via spi_flash_common_configure_host_read_mode(). + * + * @param qe_rdsr_command SPI flash command to read status register + * @param qe_wrsr_command SPI flash command to write status register + * @param qe_sr_bitwidth Width of the status register these commands operate on, in bits. + * @param qe_sr_bit Bit mask for enabling Quad Enable functions on this chip. + * + * @return always ESP_OK (currently). + */ +esp_err_t spi_flash_common_set_read_mode(esp_flash_t *chip, uint8_t qe_rdsr_command, uint8_t qe_wrsr_command, uint8_t qe_sr_bitwidth, unsigned qe_sr_bit); + +/** + * @brief Configure the host to use the specified read mode set in the ``chip->read_mode``. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * + * @return + * - ESP_OK if success + * - ESP_ERR_FLASH_NOT_INITIALISED if chip not initialized properly + * - or other error passed from the ``configure_host_mode`` function of host driver + */ +esp_err_t spi_flash_chip_generic_config_host_read_mode(esp_flash_t *chip); + +/** + * @brief Returns true if chip is configured for Quad I/O or Quad Fast Read. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * + * @return true if flash works in quad mode, otherwise false + */ +static inline bool spi_flash_is_quad_mode(const esp_flash_t *chip) +{ + return (chip->read_mode == SPI_FLASH_QIO) || (chip->read_mode == SPI_FLASH_QOUT); +} + diff --git a/components/spi_flash/include/spi_flash_chip_issi.h b/components/spi_flash/include/spi_flash_chip_issi.h new file mode 100644 index 0000000000..2b1d411552 --- /dev/null +++ b/components/spi_flash/include/spi_flash_chip_issi.h @@ -0,0 +1,27 @@ +// Copyright 2015-2019 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 + +#include +#include "esp_flash.h" +#include "spi_flash_chip_driver.h" + + +/** + * ISSI SPI flash chip_drv, uses all the above functions for its operations. In + * default autodetection, this is used as a catchall if a more specific chip_drv + * is not found. + */ +extern const spi_flash_chip_t esp_flash_chip_issi; diff --git a/components/spi_flash/include/spi_flash_lowlevel_generic.h b/components/spi_flash/include/spi_flash_lowlevel_generic.h deleted file mode 100644 index 75866c721e..0000000000 --- a/components/spi_flash/include/spi_flash_lowlevel_generic.h +++ /dev/null @@ -1,151 +0,0 @@ -#pragma once -#include "spi_flash_lowlevel_driver.h" -/* The 'generic' SPI flash operations are a lowest common subset of SPI flash commands, that work across most chips. - * - * These can be used as-is vai the esp_flash_common_chip_driver driver, or they can be used as "base driver" functions when - * creating a new esp_flash_driver_t driver structure. - * - * - * All of the functions in this header are internal functions, not part of a public API. See spi_flash_lowlevel.h for - * the public API. - */ - -/* SPI commands (actual on-wire commands not SPI controller bitmasks) - Suitable for use with spi_flash_common_command static function. -*/ -#define CMD_RDID 0x9F -#define CMD_WRSR 0x01 -#define CMD_WRSR2 0x31 /* Not all SPI flash uses this command */ -#define CMD_WREN 0x06 -#define CMD_WRDI 0x04 -#define CMD_RDSR 0x05 -#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */ - -#define CMD_FASTRD_QIO 0xEB -#define CMD_FASTRD_QUAD 0x6B -#define CMD_FASTRD_DIO 0xBB -#define CMD_FASTRD_DUAL 0x3B -#define CMD_FASTRD 0x0B -#define CMD_READ 0x03 /* Speed limited */ - -#define CMD_CHIP_ERASE 0xC7 -#define CMD_SECTOR_ERASE 0x20 -#define CMD_LARGE_BLOCK_ERASE 0xD8 /* 64KB block erase command */ - -#define SR_WIP (1<<0) /* Status register write-in-progress bit */ -#define SR_WREN (1<<1) /* Status register write enable bit */ - - -/** @brief Execute a simple SPI flash command against the chip. - * - * @param chip Pointer to the chip to use. - * @param command Command to execute (an on-wire hex command.) - * @param mosi_data Up to 32 bits of MOSI data to write after the command. - * @param mosi_len Length of MOSI data (in bits.) - * @param miso_len Length of MISO data (in bits.) - * @return MISO value read back, if any (depending on miso_len value.) - */ -uint32_t spi_flash_common_command(const esp_flash_chip_t *chip, uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len); - -/** @brief Returns true if the pin configuration for this chip uses the GPIO matrix for any signals. */ -bool spi_flash_uses_gpio_matrix(const esp_flash_chip_t *chip); - -/** @brief Generic probe function - * - * If chip->drv_read_id succeeds, the probe succeeds. - */ -esp_flash_err_t spi_flash_generic_probe(esp_flash_chip_t *chip, uint32_t flash_id); - -/** @brief Generic implementation of esp_flash_driver_t->read_id - * - * Uses the RDID command (9Fh) supported by most SPI flash chips. - * - * Results of all-zeroes or all-ones are considered failures (probably no chip attached.) - */ -esp_flash_err_t spi_flash_generic_read_id(const esp_flash_chip_t *chip, uint32_t *id); - -/** @brief Generic size detection function - * - * Tries to detect the size of chip by using the lower 4 bits of the chip->drv->read_id result = N, and assuming size is 2 ^ N. - */ -esp_flash_err_t spi_flash_generic_detect_size(const esp_flash_chip_t *chip, uint32_t *size); - -/** @brief Erase chip by using the generic erase chip (C7h) command. */ -esp_flash_err_t spi_flash_generic_erase_chip(const esp_flash_chip_t *chip); - -/** @brief Erase sector by using the generic sector erase (20h) command. */ -esp_flash_err_t spi_flash_generic_erase_sector(const esp_flash_chip_t *chip, uint32_t start_address); - -/** @brief Erase block by using the generic 64KB block erase (D8h) command */ -esp_flash_err_t spi_flash_generic_erase_block(const esp_flash_chip_t *chip, uint32_t start_address); - -/** @brief Read from flash by using a read command that matches the programmed read mode. */ -esp_flash_err_t spi_flash_generic_read(const esp_flash_chip_t *chip, void *buffer, uint32_t address, uint32_t length); - -/** @brief Perform a page program using the page program (02h) command. */ -esp_flash_err_t spi_flash_generic_page_program(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length); - -/** @brief Perform a generic write. Split the write buffer into - one page operations, and call chip->drv->page-program() for each. -*/ -esp_flash_err_t spi_flash_generic_write(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length); - -/** @brief Perform a write using on-chip flash encryption */ -esp_flash_err_t spi_flash_generic_write_encrypted(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length); - -/** @brief Send the write enable (06h) command and verify the expected bit (1) in the status register is set. */ -esp_flash_err_t spi_flash_generic_write_enable(const esp_flash_chip_t *chip); - -/** @brief Wait for the SPI host hardware state machine to be idle. - - This isn't a flash driver operation, but it's called by spi_flash_generic_wait_idle() and may be useful when implementing alternative drivers. - - timeout_ms will be decremented if the function needs to wait until the host hardware is idle. -*/ -esp_flash_err_t spi_flash_generic_wait_host_idle(const esp_flash_chip_t *chip, uint32_t *timeout_ms); - -/** @brief Read flash status via the RDSR command (05h) and wait for bit 0 (write in progress bit) to be cleared. */ -esp_flash_err_t spi_flash_generic_wait_idle(const esp_flash_chip_t *chip, uint32_t timeout_ms); - -/** @brief Utility function to configure the SPI host hardware registers for the specified read mode. - - Called by spi_flash_generic_set_read_mode() but may also be useful - when implementing other SPI flash drivers. - - Note that calling this configures SPI host registers, so if running any other commands as part of set_read_mode() then these must be run before calling this function. - */ -esp_flash_err_t spi_flash_common_configure_host_read_mode(const esp_flash_chip_t *chip); - -/** @brief Utility function for set_read_mode driver function - * - * Most setting of read mode follows a common pattern, except for how to enable Quad I/O modes (QIO/QOUT). - * These use different commands to read/write the status register, and a different bit is set/cleared. - * - * This is a generic utility function to implement set_read_mode() for this pattern. Also configures host - * registers via spi_flash_common_configure_host_read_mode(). - * - * @param qe_rdsr_command SPI flash command to read status register - * @param qe_wrsr_command SPI flash command to write status register - * @param qe_sr_bitwidth Width of the status register these commands operate on, in bits. - * @param qe_sr_bit Bit mask for enabling Quad Enable functions on this chio. - */ -esp_flash_err_t spi_flash_common_set_read_mode(const esp_flash_chip_t *chip, uint8_t qe_rdsr_command, uint8_t qe_wrsr_command, uint8_t qe_sr_bitwidth, unsigned qe_sr_bit); - -/** @brief Set the specified SPI read mode. - * - * Includes setting SPI host hardware registers, but also setting quad enable status register bit if needed. - */ -esp_flash_err_t spi_flash_generic_set_read_mode(const esp_flash_chip_t *chip); - -/** @brief Returns true if chip is configured for Quad I/O or - Quad Fast Read */ -inline static bool spi_flash_is_quad_mode(const esp_flash_chip_t *chip) -{ - return chip->read_mode == ESP_FLASH_QIO || chip->read_mode == ESP_FLASH_QOUT; -} - -/* Generic SPI flash driver, uses all the above functions for its operations. In default autodetection, this is used as - a catchall if a more specific driver is not found. -*/ -extern const esp_flash_driver_t esp_flash_generic_chip_driver; - diff --git a/components/spi_flash/linker.lf b/components/spi_flash/linker.lf index e466c85a2b..e5d886ca4b 100644 --- a/components/spi_flash/linker.lf +++ b/components/spi_flash/linker.lf @@ -2,9 +2,7 @@ archive: libspi_flash.a entries: spi_flash_rom_patch (noflash_text) - spi_flash_lowlevel_api (noflash) - spi_flash_lowlevel_generic (noflash) - spi_flash_lowlevel_issi (noflash) - spi_flash_lowlevel_idf_app (noflash) - spi_flash_driver_hs (noflash) + spi_flash_chip_generic (noflash) + spi_flash_chip_issi (noflash) + memspi_host_driver (noflash) diff --git a/components/spi_flash/memspi_host_driver.c b/components/spi_flash/memspi_host_driver.c new file mode 100644 index 0000000000..871616386f --- /dev/null +++ b/components/spi_flash/memspi_host_driver.c @@ -0,0 +1,101 @@ +// Copyright 2015-2019 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 "spi_flash_defs.h" +#include "memspi_host_driver.h" +#include "string.h" +#include "esp_log.h" +#include "cache_utils.h" +#include "esp_flash_partitions.h" + +static const char TAG[] = "memspi"; +static const spi_flash_host_driver_t esp_flash_default_host = ESP_FLASH_DEFAULT_HOST_DRIVER(); + +esp_err_t memspi_host_init_pointers(spi_flash_host_driver_t *host, memspi_host_data_t *data, const memspi_host_config_t *cfg) +{ + memcpy(host, &esp_flash_default_host, sizeof(spi_flash_host_driver_t)); + esp_err_t err = spi_flash_hal_init(data, cfg); + if (err != ESP_OK) { + return err; + } + + host->driver_data = data; + //some functions are not required if not SPI1 + if (data->spi != &SPI1) { + host->flush_cache = NULL; + host->region_protected = NULL; + } + return ESP_OK; +} + +esp_err_t memspi_host_read_id_hs(spi_flash_host_driver_t *chip_drv, uint32_t *id) +{ + //NOTE: we do have a read id function, however it doesn't work in high freq + spi_flash_trans_t t = { + .command = CMD_RDID, + .mosi_data = 0, + .mosi_len = 0, + .miso_len = 24 + }; + chip_drv->common_command(chip_drv, &t); + uint32_t raw_flash_id = t.miso_data[0]; + ESP_EARLY_LOGV(TAG, "raw_chip_id: %X\n", raw_flash_id); + if (raw_flash_id == 0xFFFFFF || raw_flash_id == 0) { + ESP_EARLY_LOGE(TAG, "no response\n"); + return ESP_ERR_FLASH_NO_RESPONSE; + } + + // Byte swap the flash id as it's usually written the other way around + uint8_t mfg_id = raw_flash_id & 0xFF; + uint16_t flash_id = (raw_flash_id >> 16) | (raw_flash_id & 0xFF00); + *id = ((uint32_t)mfg_id << 16) | flash_id; + ESP_EARLY_LOGV(TAG, "chip_id: %X\n", *id); + return ESP_OK; +} + +esp_err_t memspi_host_read_status_hs(spi_flash_host_driver_t *driver, uint8_t *out_sr) +{ + //NOTE: we do have a read id function, however it doesn't work in high freq + spi_flash_trans_t t = { + .command = CMD_RDSR, + .mosi_data = 0, + .mosi_len = 0, + .miso_len = 8 + }; + esp_err_t err = driver->common_command(driver, &t); + if (err != ESP_OK) { + return err; + } + *out_sr = t.miso_data[0]; + return ESP_OK; +} + +esp_err_t memspi_host_flush_cache(spi_flash_host_driver_t* driver, uint32_t addr, uint32_t size) +{ + if (((memspi_host_data_t*)(driver->driver_data))->spi == &SPI1) { + spi_flash_check_and_flush_cache(addr, size); + } + return ESP_OK; +} + +bool memspi_region_protected(spi_flash_host_driver_t* driver, uint32_t addr, uint32_t size) +{ + if (((memspi_host_data_t*)(driver->driver_data))->spi != &SPI1) { + return false; + } + if (!esp_partition_main_flash_region_safe(addr, size)) { + return true; + } + return false; +} \ No newline at end of file diff --git a/components/spi_flash/partition.c b/components/spi_flash/partition.c index 5aa99a36ab..5da204ae56 100644 --- a/components/spi_flash/partition.c +++ b/components/spi_flash/partition.c @@ -24,6 +24,7 @@ #include "esp_flash_encrypt.h" #include "esp_log.h" #include "bootloader_common.h" +#include "esp_ota_ops.h" #define HASH_LEN 32 /* SHA-256 digest length */ @@ -355,3 +356,19 @@ bool esp_partition_check_identity(const esp_partition_t *partition_1, const esp_ } return false; } + +bool esp_partition_main_flash_region_safe(size_t addr, size_t size) +{ + bool result = true; + if (addr <= ESP_PARTITION_TABLE_OFFSET + ESP_PARTITION_TABLE_MAX_LEN) { + return false; + } + const esp_partition_t *p = esp_ota_get_running_partition(); + if (addr >= p->address && addr < p->address + p->size) { + return false; + } + if (addr < p->address && addr + size > p->address) { + return false; + } + return result; +} diff --git a/components/spi_flash/private_include/spi_flash_defs.h b/components/spi_flash/private_include/spi_flash_defs.h new file mode 100644 index 0000000000..b210271e74 --- /dev/null +++ b/components/spi_flash/private_include/spi_flash_defs.h @@ -0,0 +1,44 @@ +// Copyright 2015-2019 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 + +/* SPI commands (actual on-wire commands not SPI controller bitmasks) + Suitable for use with spi_flash_hal_common_command static function. +*/ +#define CMD_RDID 0x9F +#define CMD_WRSR 0x01 +#define SR_WIP (1<<0) /* Status register write-in-progress bit */ +#define SR_WREN (1<<1) /* Status register write enable bit */ +#define CMD_WRSR2 0x31 /* Not all SPI flash uses this command */ +#define CMD_WREN 0x06 +#define CMD_WRDI 0x04 +#define CMD_RDSR 0x05 +#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */ + +#define CMD_FASTRD_QIO 0xEB +#define CMD_FASTRD_QUAD 0x6B +#define CMD_FASTRD_DIO 0xBB +#define CMD_FASTRD_DUAL 0x3B +#define CMD_FASTRD 0x0B +#define CMD_READ 0x03 /* Speed limited */ + +#define CMD_CHIP_ERASE 0xC7 +#define CMD_SECTOR_ERASE 0x20 +#define CMD_LARGE_BLOCK_ERASE 0xD8 /* 64KB block erase command */ + +#define CMD_RST_EN 0x66 +#define CMD_RST_DEV 0x99 + + diff --git a/components/spi_flash/spi_flash_chip_drivers.c b/components/spi_flash/spi_flash_chip_drivers.c new file mode 100644 index 0000000000..ae10bcec37 --- /dev/null +++ b/components/spi_flash/spi_flash_chip_drivers.c @@ -0,0 +1,38 @@ +// Copyright 2015-2019 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 +#include "spi_flash_chip_driver.h" +#include "spi_flash_chip_generic.h" +#include "spi_flash_chip_issi.h" +#include "sdkconfig.h" + +/* + * Default registered chip drivers. Note these are tested in order and first + * match is taken, so generic/catchall entries should go last. Note that the + * esp_flash_registered_flash_ops pointer can be changed to point to a different + * array of registered ops, if desired. + * + * It can be configured to support only available chips in the sdkconfig, to + * avoid possible issues, and speed up the auto-detecting. + */ +static const spi_flash_chip_t *default_registered_chips[] = { +#ifdef CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP + &esp_flash_chip_issi, +#endif + &esp_flash_chip_generic, + NULL, +}; + +const spi_flash_chip_t **esp_flash_registered_chips = default_registered_chips; diff --git a/components/spi_flash/spi_flash_chip_generic.c b/components/spi_flash/spi_flash_chip_generic.c new file mode 100644 index 0000000000..0e80e8eb1d --- /dev/null +++ b/components/spi_flash/spi_flash_chip_generic.c @@ -0,0 +1,405 @@ +// Copyright 2015-2019 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 +#include // For MIN/MAX +#include "spi_flash_chip_generic.h" +#include "spi_flash_defs.h" +#include "esp_log.h" + +static const char TAG[] = "chip_generic"; + +#define SPI_FLASH_GENERIC_CHIP_ERASE_TIMEOUT 4000 +#define SPI_FLASH_GENERIC_SECTOR_ERASE_TIMEOUT 500 +#define SPI_FLASH_GENERIC_BLOCK_ERASE_TIMEOUT 1000 + +#define DEFAULT_IDLE_TIMEOUT 200 +#define DEFAULT_PAGE_PROGRAM_TIMEOUT 500 + +esp_err_t spi_flash_chip_generic_probe(esp_flash_t *chip, uint32_t flash_id) +{ + // This is the catch-all probe function, claim the chip always if nothing + // else has claimed it yet. + return ESP_OK; +} + +esp_err_t spi_flash_chip_generic_reset(esp_flash_t *chip) +{ + //this is written following the winbond spec.. + spi_flash_trans_t t; + t = (spi_flash_trans_t) { + .command = CMD_RST_EN, + }; + esp_err_t err = chip->host->common_command(chip->host, &t); + if (err != ESP_OK) { + return err; + } + + t = (spi_flash_trans_t) { + .command = CMD_RST_DEV, + }; + err = chip->host->common_command(chip->host, &t); + if (err != ESP_OK) { + return err; + } + + err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); + return err; +} + +esp_err_t spi_flash_chip_generic_detect_size(esp_flash_t *chip, uint32_t *size) +{ + uint32_t id = 0; + *size = 0; + esp_err_t err = chip->host->read_id(chip->host, &id); + if (err != ESP_OK) { + return err; + } + + /* Can't detect size unless the high byte of the product ID matches the same convention, which is usually 0x40 or + * 0xC0 or similar. */ + if ((id & 0x0F00) != 0) { + return ESP_ERR_FLASH_UNSUPPORTED_CHIP; + } + + *size = 1 << (id & 0xFF); + return ESP_OK; +} + + +esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip) +{ + esp_err_t err; + + err = chip->chip_drv->set_write_protect(chip, false); + if (err == ESP_OK) { + err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); + } + if (err == ESP_OK) { + chip->host->erase_chip(chip->host); + //to save time, flush cache here + if (chip->host->flush_cache) { + err = chip->host->flush_cache(chip->host, 0, chip->size); + if (err != ESP_OK) { + return err; + } + } + err = chip->chip_drv->wait_idle(chip, SPI_FLASH_GENERIC_CHIP_ERASE_TIMEOUT); + } + return err; +} + +esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_address) +{ + esp_err_t err = chip->chip_drv->set_write_protect(chip, false); + if (err == ESP_OK) { + err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); + } + if (err == ESP_OK) { + chip->host->erase_sector(chip->host, start_address); + //to save time, flush cache here + if (chip->host->flush_cache) { + err = chip->host->flush_cache(chip->host, start_address, chip->chip_drv->sector_size); + if (err != ESP_OK) { + return err; + } + } + err = chip->chip_drv->wait_idle(chip, SPI_FLASH_GENERIC_SECTOR_ERASE_TIMEOUT); + } + return err; +} + +esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_address) +{ + esp_err_t err = chip->chip_drv->set_write_protect(chip, false); + if (err == ESP_OK) { + err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); + } + if (err == ESP_OK) { + chip->host->erase_block(chip->host, start_address); + //to save time, flush cache here + if (chip->host->flush_cache) { + err = chip->host->flush_cache(chip->host, start_address, chip->chip_drv->block_erase_size); + if (err != ESP_OK) { + return err; + } + } + err = chip->chip_drv->wait_idle(chip, SPI_FLASH_GENERIC_BLOCK_ERASE_TIMEOUT); + } + return err; +} + +esp_err_t spi_flash_chip_generic_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length) +{ + esp_err_t err = ESP_OK; + // Configure the host, and return + spi_flash_chip_generic_config_host_read_mode(chip); + + while (err == ESP_OK && length > 0) { + uint32_t read_len = MIN(length, chip->host->max_read_bytes); + err = chip->host->read(chip->host, buffer, address, read_len); + + buffer += read_len; + length -= read_len; + address += read_len; + } + + return err; +} + +esp_err_t spi_flash_chip_generic_page_program(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length) +{ + esp_err_t err; + + err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); + + if (err == ESP_OK) { + // Perform the actual Page Program command + chip->host->program_page(chip->host, buffer, address, length); + + err = chip->chip_drv->wait_idle(chip, DEFAULT_PAGE_PROGRAM_TIMEOUT); + } + return err; +} + +esp_err_t spi_flash_chip_generic_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length) +{ + esp_err_t err = ESP_OK; + const uint32_t page_size = chip->chip_drv->page_size; + + while (err == ESP_OK && length > 0) { + uint32_t page_len = MIN(chip->host->max_write_bytes, MIN(page_size, length)); + if ((address + page_len) / page_size != address / page_size) { + // Most flash chips can't page write across a page boundary + page_len = page_size - (address % page_size); + } + + err = chip->chip_drv->set_write_protect(chip, false); + + if (err == ESP_OK) { + err = chip->chip_drv->program_page(chip, buffer, address, page_len); + address += page_len; + buffer = (void *)((intptr_t)buffer + page_len); + length -= page_len; + } + } + if (err == ESP_OK && chip->host->flush_cache) { + err = chip->host->flush_cache(chip->host, address, length); + } + return err; +} + +esp_err_t spi_flash_chip_generic_write_encrypted(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length) +{ + return ESP_ERR_FLASH_UNSUPPORTED_HOST; // TODO +} + +esp_err_t spi_flash_chip_generic_write_enable(esp_flash_t *chip, bool write_protect) +{ + esp_err_t err = ESP_OK; + + err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); + + if (err == ESP_OK) { + chip->host->set_write_protect(chip->host, write_protect); + } + + uint8_t status; + err = chip->host->read_status(chip->host, &status); + if (err != ESP_OK) { + return err; + } + + if ((status & SR_WREN) == 0) { + // WREN flag has not been set! + err = ESP_ERR_NOT_FOUND; + } + + return err; +} + +esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_ms) +{ + while (chip->host->host_idle(chip->host) && *timeout_ms > 0) { + if (*timeout_ms > 1) { + chip->os_func->delay_ms(chip->os_func_data, 1); + } + (*timeout_ms)--; + } + return (*timeout_ms > 0) ? ESP_OK : ESP_ERR_TIMEOUT; +} + +esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_ms) +{ + timeout_ms++; // allow at least one pass before timeout, last one has no sleep cycle + + uint8_t status = 0; + while (timeout_ms > 0) { + + esp_err_t err = spi_flash_generic_wait_host_idle(chip, &timeout_ms); + if (err != ESP_OK) { + return err; + } + + err = chip->host->read_status(chip->host, &status); + if (err != ESP_OK) { + return err; + } + if ((status & SR_WIP) == 0) { + break; // Write in progress is complete + } + if (timeout_ms > 1) { + chip->os_func->delay_ms(chip->os_func_data, 1); + } + timeout_ms--; + } + + return (timeout_ms > 0) ? ESP_OK : ESP_ERR_TIMEOUT; +} + +esp_err_t spi_flash_chip_generic_config_host_read_mode(esp_flash_t *chip) +{ + uint32_t dummy_cyclelen_base; + uint32_t addr_bitlen; + uint32_t read_command; + + switch (chip->read_mode) { + case SPI_FLASH_QIO: + //for QIO mode, the 4 bit right after the address are used for continuous mode, should be set to 0 to avoid that. + addr_bitlen = 32; + dummy_cyclelen_base = 4; + read_command = CMD_FASTRD_QIO; + break; + case SPI_FLASH_QOUT: + addr_bitlen = 24; + dummy_cyclelen_base = 8; + read_command = CMD_FASTRD_QUAD; + break; + case SPI_FLASH_DIO: + //for DIO mode, the 4 bit right after the address are used for continuous mode, should be set to 0 to avoid that. + addr_bitlen = 28; + dummy_cyclelen_base = 2; + read_command = CMD_FASTRD_DIO; + break; + case SPI_FLASH_DOUT: + addr_bitlen = 24; + dummy_cyclelen_base = 8; + read_command = CMD_FASTRD_DUAL; + break; + case SPI_FLASH_FASTRD: + addr_bitlen = 24; + dummy_cyclelen_base = 8; + read_command = CMD_FASTRD; + break; + case SPI_FLASH_SLOWRD: + addr_bitlen = 24; + dummy_cyclelen_base = 0; + read_command = CMD_READ; + break; + default: + return ESP_ERR_FLASH_NOT_INITIALISED; + } + + return chip->host->configure_host_read_mode(chip->host, chip->read_mode, addr_bitlen, dummy_cyclelen_base, read_command); +} + +esp_err_t spi_flash_common_set_read_mode(esp_flash_t *chip, uint8_t qe_rdsr_command, uint8_t qe_wrsr_command, uint8_t qe_sr_bitwidth, unsigned qe_sr_bit) +{ + if (spi_flash_is_quad_mode(chip)) { + // Ensure quad modes are enabled, using the Quad Enable parameters supplied. + spi_flash_trans_t t = { + .command = qe_rdsr_command, + .mosi_data = 0, + .mosi_len = 0, + .miso_len = qe_sr_bitwidth, + }; + chip->host->common_command(chip->host, &t); + unsigned sr = t.miso_data[0]; + ESP_EARLY_LOGV(TAG, "set_read_mode: status before 0x%x", sr); + if ((sr & qe_sr_bit) == 0) { + //some chips needs the write protect to be disabled before writing to Status Register + chip->chip_drv->set_write_protect(chip, false); + + sr |= qe_sr_bit; + spi_flash_trans_t t = { + .command = qe_wrsr_command, + .mosi_data = sr, + .mosi_len = qe_sr_bitwidth, + .miso_len = 0, + }; + chip->host->common_command(chip->host, &t); + + /* Check the new QE bit has stayed set */ + spi_flash_trans_t t_rdsr = { + .command = qe_rdsr_command, + .mosi_data = 0, + .mosi_len = 0, + .miso_len = qe_sr_bitwidth + }; + chip->host->common_command(chip->host, &t_rdsr); + sr = t_rdsr.miso_data[0]; + ESP_EARLY_LOGV(TAG, "set_read_mode: status after 0x%x", sr); + if ((sr & qe_sr_bit) == 0) { + return ESP_ERR_FLASH_NO_RESPONSE; + } + + chip->chip_drv->set_write_protect(chip, true); + } + } + return ESP_OK; +} + +esp_err_t spi_flash_chip_generic_set_read_mode(esp_flash_t *chip) +{ + // On "generic" chips, this involves checking + // bit 1 (QE) of RDSR2 (35h) result + // (it works this way on GigaDevice & Fudan Micro chips, probably others...) + const uint8_t BIT_QE = 1 << 1; + return spi_flash_common_set_read_mode(chip, CMD_RDSR2, CMD_WRSR2, 8, BIT_QE); +} + +static const char chip_name[] = "generic"; + +const spi_flash_chip_t esp_flash_chip_generic = { + .name = chip_name, + .probe = spi_flash_chip_generic_probe, + .reset = spi_flash_chip_generic_reset, + .detect_size = spi_flash_chip_generic_detect_size, + .erase_chip = spi_flash_chip_generic_erase_chip, + .erase_sector = spi_flash_chip_generic_erase_sector, + .erase_block = spi_flash_chip_generic_erase_block, + .sector_size = 4 * 1024, + .block_erase_size = 64 * 1024, + + // TODO: figure out if generic chip-wide protection bits exist across some manufacturers + .get_chip_write_protect = NULL, + .set_chip_write_protect = NULL, + + // Chip write protection regions do not appear to be standardised + // at all, this is implemented in chip-specific drivers only. + .num_protectable_regions = 0, + .protectable_regions = NULL, + .get_protected_regions = NULL, + .set_protected_regions = NULL, + + .read = spi_flash_chip_generic_read, + .write = spi_flash_chip_generic_write, + .program_page = spi_flash_chip_generic_page_program, + .page_size = 256, + .write_encrypted = spi_flash_chip_generic_write_encrypted, + + .set_write_protect = spi_flash_chip_generic_write_enable, + .wait_idle = spi_flash_chip_generic_wait_idle, + .set_read_mode = spi_flash_chip_generic_set_read_mode, +}; diff --git a/components/spi_flash/spi_flash_lowlevel_issi.c b/components/spi_flash/spi_flash_chip_issi.c similarity index 53% rename from components/spi_flash/spi_flash_lowlevel_issi.c rename to components/spi_flash/spi_flash_chip_issi.c index f97ec5a0c0..d32c3a1929 100644 --- a/components/spi_flash/spi_flash_lowlevel_issi.c +++ b/components/spi_flash/spi_flash_chip_issi.c @@ -1,9 +1,9 @@ -// Copyright 2017 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2019 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 @@ -11,44 +11,49 @@ // 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 -#include "spi_flash_lowlevel_driver.h" -#include "spi_flash_lowlevel_generic.h" +#include "spi_flash_chip_generic.h" +#include "spi_flash_defs.h" /* Driver for ISSI flash chip, as used in ESP32 D2WD */ -esp_flash_err_t issi_probe(esp_flash_chip_t *chip, uint32_t flash_id) +esp_err_t spi_flash_chip_issi_probe(esp_flash_t *chip, uint32_t flash_id) { /* Check manufacturer and product IDs match our desired masks */ const uint8_t MFG_ID = 0x9D; if (flash_id >> 16 != MFG_ID) { - return FLASH_ERR_NOT_FOUND; + return ESP_ERR_NOT_FOUND; } const uint16_t FLASH_ID_MASK = 0xCF00; const uint16_t FLASH_ID_VALUE = 0x4000; if ((flash_id & FLASH_ID_MASK) != FLASH_ID_VALUE) { - return FLASH_ERR_NOT_FOUND; + return ESP_ERR_NOT_FOUND; } - return FLASH_OK; + return ESP_OK; } -esp_flash_err_t issi_set_read_mode(const esp_flash_chip_t *chip) +esp_err_t spi_flash_chip_issi_set_read_mode(esp_flash_t *chip) { /* ISSI uses bit 6 of "basic" SR as Quad Enable */ - const uint8_t BIT_QE = 1<<6; + const uint8_t BIT_QE = 1 << 6; return spi_flash_common_set_read_mode(chip, CMD_RDSR, CMD_WRSR, 8, BIT_QE); } +static const char chip_name[] = "issi"; -const esp_flash_driver_t esp_flash_issi_chip_driver = { - .probe = issi_probe, - .read_id = spi_flash_generic_read_id, - .detect_size = spi_flash_generic_detect_size, - .erase_chip = spi_flash_generic_erase_chip, - .erase_sector = spi_flash_generic_erase_sector, - .erase_block = spi_flash_generic_erase_block, +// The issi chip can use the functions for generic chips except from set read mode and probe, +// So we only replace these two functions. +const spi_flash_chip_t esp_flash_chip_issi = { + .name = chip_name, + .probe = spi_flash_chip_issi_probe, + .reset = spi_flash_chip_generic_reset, + .detect_size = spi_flash_chip_generic_detect_size, + .erase_chip = spi_flash_chip_generic_erase_chip, + .erase_sector = spi_flash_chip_generic_erase_sector, + .erase_block = spi_flash_chip_generic_erase_block, .sector_size = 4 * 1024, .block_erase_size = 64 * 1024, @@ -62,13 +67,13 @@ const esp_flash_driver_t esp_flash_issi_chip_driver = { .get_protected_regions = NULL, .set_protected_regions = NULL, - .read = spi_flash_generic_read, - .write = spi_flash_generic_write, - .page_program = spi_flash_generic_page_program, + .read = spi_flash_chip_generic_read, + .write = spi_flash_chip_generic_write, + .program_page = spi_flash_chip_generic_page_program, .page_size = 256, - .write_encrypted = spi_flash_generic_write_encrypted, + .write_encrypted = spi_flash_chip_generic_write_encrypted, - .write_enable = spi_flash_generic_write_enable, - .wait_idle = spi_flash_generic_wait_idle, - .set_read_mode = issi_set_read_mode, + .set_write_protect = spi_flash_chip_generic_write_enable, + .wait_idle = spi_flash_chip_generic_wait_idle, + .set_read_mode = spi_flash_chip_issi_set_read_mode, }; diff --git a/components/spi_flash/spi_flash_lowlevel_api.c b/components/spi_flash/spi_flash_lowlevel_api.c deleted file mode 100644 index 0a3d6f29a5..0000000000 --- a/components/spi_flash/spi_flash_lowlevel_api.c +++ /dev/null @@ -1,552 +0,0 @@ -// Copyright 2017 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 -#include -#include -#include - -#include "spi_flash_lowlevel_driver.h" -#include "spi_flash_lowlevel_generic.h" -#include "soc/spi_reg.h" - -#define MAX_WRITE_CHUNK 8192 /* write in chunks */ - -/* Static function to notify OS of a new SPI flash operation. - - If returns an error result, caller must abort. If returns FLASH_OK, caller must - call spiflash_end() before returning. -*/ -static esp_flash_err_t spiflash_start(const esp_flash_chip_t *chip) -{ - if (esp_flash_os_functions != NULL - && esp_flash_os_functions->start != NULL) { - esp_flash_err_t err = esp_flash_os_functions->start(chip); - if (err != FLASH_OK) { - return err; - } - } - return FLASH_OK; -} - -/* Static function to notify OS that SPI flash operation is complete. - */ -static esp_flash_err_t spiflash_end(const esp_flash_chip_t *chip, esp_flash_err_t err) -{ - if (esp_flash_os_functions != NULL - && esp_flash_os_functions->end != NULL) { - esp_flash_err_t end_err = esp_flash_os_functions->end(chip); - if (err == FLASH_OK) { - err = end_err; // Only return the 'end' error if we haven't already failed - } - } - return err; -} - -/* Return true if regions 'a' and 'b' overlap at all, based on their start offsets and lengths. */ -inline static bool regions_overlap(uint32_t a_start, uint32_t a_len,uint32_t b_start, uint32_t b_len); - -/* Top-level API functions, calling into driver functions via chip->drv */ - -static esp_flash_err_t detect_spi_flash_chip(esp_flash_chip_t *chip); - -esp_flash_err_t esp_flash_init(esp_flash_chip_t *chip) -{ - if (chip->spi == NULL) { - return FLASH_ERR_INVALID_ARG; - } - - // TODO: configure SPI host clock speed, pin configuration - - if (chip->drv == NULL) { - // Detect driver - esp_flash_err_t err = detect_spi_flash_chip(chip); - if (err != FLASH_OK) { - return err; - } - } - - esp_flash_err_t err = spiflash_start(chip); - if (err != FLASH_OK) { - return err; - } - - if (chip->size == 0) { - // Detect flash size - err = chip->drv->detect_size(chip, &chip->size); - } - - if (err == FLASH_OK) { - // Try to set the flash mode to whatever default mode was chosen - // (this isn't necessary at this point for functionality, but init will fail - // if this mode can't be set on this chip.) - err = chip->drv->set_read_mode(chip); - } - - // Done: all fields on 'chip' are initialised - return spiflash_end(chip, err); -} - -static esp_flash_err_t detect_spi_flash_chip(esp_flash_chip_t *chip) -{ - esp_flash_err_t err; - uint32_t flash_id; - int retries = 10; - do { - err = spiflash_start(chip); - if (err != FLASH_OK) { - return err; - } - - // Send generic RDID command twice, check for a matching result and retry in case we just powered on (inner - // function fails if it sees all-ones or all-zeroes.) - err = spi_flash_generic_read_id(chip, &flash_id); - - if (err == FLASH_OK) { // check we see the same ID twice, in case of transient power-on errors - uint32_t new_id; - err = spi_flash_generic_read_id(chip, &new_id); - if (err == FLASH_OK && (new_id != flash_id)) { - err = FLASH_ERR_NOT_INITIALISED; - } - } - - err = spiflash_end(chip, err); - } while (err != FLASH_OK && retries-- > 0); - - // Detect the chip and set the driver structure for it - const esp_flash_driver_t **drivers = esp_flash_registered_flash_drivers; - while (*drivers != NULL && chip->drv == NULL) { - chip->drv = *drivers; - - // start/end SPI operation each time, for multitasking - // and also so esp_flash_registered_flash_drivers can live in flash - err = spiflash_start(chip); - if (err != FLASH_OK) { - return err; - } - - if (chip->drv->probe(chip, flash_id) != FLASH_OK) { - chip->drv = NULL; - } - // if probe succeeded, chip->drv stays set - drivers++; - - err = spiflash_end(chip, err); - if (err != FLASH_OK) { - return err; - } - } - - return (chip->drv == NULL) ? FLASH_ERR_NOT_FOUND : FLASH_OK; -} - -// Convenience macro for beginning of all API functions, -// check that the 'chip' parameter is properly initialised -// and supports the operation in question -#define VERIFY_OP(OP) do { \ - if (chip == NULL) { \ - chip = esp_flash_default_chip; \ - } \ - if (chip == NULL || chip->drv == NULL) { \ - return FLASH_ERR_NOT_INITIALISED; \ - } \ - if (chip->drv->OP == NULL) { \ - return FLASH_ERR_UNSUPPORTED_CHIP; \ - } \ - } while (0) - -esp_flash_err_t esp_flash_read_id(const esp_flash_chip_t *chip, uint32_t *id) -{ - printf("chip %p esp_flash_default_chip %p\n", - chip, esp_flash_default_chip); - VERIFY_OP(read_id); - if (id == NULL) { - return FLASH_ERR_INVALID_ARG; - } - esp_flash_err_t err = spiflash_start(chip); - if (err != FLASH_OK) { - return err; - } - - err = chip->drv->read_id(chip, id); - - return spiflash_end(chip, err); -} - -esp_flash_err_t esp_flash_detect_size(const esp_flash_chip_t *chip, uint32_t *size) -{ - VERIFY_OP(detect_size); - if (size == NULL) { - return FLASH_ERR_INVALID_ARG; - } - *size = 0; - - esp_flash_err_t err = spiflash_start(chip); - if (err != FLASH_OK) { - return err; - } - - err = chip->drv->detect_size(chip, size); - - return spiflash_end(chip, err); -} - -esp_flash_err_t esp_flash_erase_chip(const esp_flash_chip_t *chip) -{ - VERIFY_OP(erase_chip); - bool write_protect = false; - - esp_flash_err_t err = spiflash_start(chip); - if (err != FLASH_OK) { - return err; - } - - err = esp_flash_get_chip_write_protect(chip, &write_protect); - - if (err == FLASH_OK && write_protect) { - err = FLASH_ERR_PROTECTED; - } - - if (err == FLASH_OK) { - err = chip->drv->erase_chip(chip); - } - - return spiflash_end(chip, err); -} - -esp_flash_err_t esp_flash_erase_region(const esp_flash_chip_t *chip, uint32_t start, uint32_t len) -{ - VERIFY_OP(erase_sector); - uint32_t block_erase_size = chip->drv->erase_block == NULL ? 0 : chip->drv->block_erase_size; - uint32_t sector_size = chip->drv->sector_size; - bool write_protect = false; - - if (sector_size == 0 || (block_erase_size % sector_size) != 0) { - return FLASH_ERR_NOT_INITIALISED; - } - if (start > chip->size || start + len > chip->size) { - return FLASH_ERR_INVALID_ARG; - } - if ((start % chip->drv->sector_size) != 0 || (len % chip->drv->sector_size) != 0) { - // Can only erase multiples of the sector size, starting at sector boundary - return FLASH_ERR_INVALID_ARG; - } - - esp_flash_err_t err = spiflash_start(chip); - if (err != FLASH_OK) { - return err; - } - - // Check for write protection on whole chip - if (chip->drv->get_chip_write_protect != NULL) { - err = chip->drv->get_chip_write_protect(chip, &write_protect); - if (err == FLASH_OK && write_protect) { - err = FLASH_ERR_PROTECTED; - } - } - - // Check for write protected regions overlapping the erase region - if (err == FLASH_OK && chip->drv->get_protected_regions != NULL && chip->drv->num_protectable_regions > 0) { - uint64_t protected = 0; - err = chip->drv->get_protected_regions(chip, &protected); - if (protected != 0) { - for (int i = 0; i < chip->drv->num_protectable_regions && err == FLASH_OK; i++) { - const esp_flash_region_t *region = &chip->drv->protectable_regions[i]; - if ((protected & (1LL << i)) - && regions_overlap(start, len, region->offset, region->size)) { - err = FLASH_ERR_PROTECTED; - } - } - } - } - - // Don't lock the SPI flash for the entire erase, as this may be very long - err = spiflash_end(chip, err); - - while (err == FLASH_OK && len >= sector_size) { - esp_flash_err_t err = spiflash_start(chip); - if (err != FLASH_OK) { - return err; - } - - // If possible erase an entire multi-sector block - if (block_erase_size > 0 && len >= block_erase_size && (start % block_erase_size) == 0) { - err = chip->drv->erase_block(chip, start); - start += block_erase_size; - len -= block_erase_size; - } - else { - // Otherwise erase individual sector only - err = chip->drv->erase_sector(chip, start); - start += sector_size; - len -= sector_size; - } - - err = spiflash_end(chip, err); - } - - return err; -} - -esp_flash_err_t esp_flash_get_chip_write_protect(const esp_flash_chip_t *chip, bool *write_protected) -{ - VERIFY_OP(get_chip_write_protect); - if (write_protected == NULL) { - return FLASH_ERR_INVALID_ARG; - } - - esp_flash_err_t err = spiflash_start(chip); - if (err != FLASH_OK) { - return err; - } - - err = chip->drv->get_chip_write_protect(chip, write_protected); - - return spiflash_end(chip, err); -} - -esp_flash_err_t esp_flash_set_chip_write_protect(const esp_flash_chip_t *chip, bool write_protect_chip) -{ - VERIFY_OP(set_chip_write_protect); - - esp_flash_err_t err = spiflash_start(chip); - if (err != FLASH_OK) { - return err; - } - - err = chip->drv->set_chip_write_protect(chip, write_protect_chip); - - return spiflash_end(chip, err); -} - -esp_flash_err_t esp_flash_get_protectable_regions(const esp_flash_chip_t *chip, const esp_flash_region_t **regions, uint32_t *num_regions) -{ - if(num_regions != NULL) { - *num_regions = 0; // In case caller doesn't check result - } - VERIFY_OP(get_protected_regions); - - if(regions == NULL || num_regions == NULL) { - return FLASH_ERR_INVALID_ARG; - } - - *num_regions = chip->drv->num_protectable_regions; - *regions = chip->drv->protectable_regions; - return FLASH_OK; -} - -static esp_flash_err_t find_region(const esp_flash_chip_t *chip, const esp_flash_region_t *region, uint8_t *index) -{ - if (region == NULL) { - return FLASH_ERR_INVALID_ARG; - } - - for(*index = 0; *index < chip->drv->num_protectable_regions; (*index)++) { - if (memcmp(&chip->drv->protectable_regions[*index], - region, sizeof(esp_flash_region_t)) == 0) { - return FLASH_OK; - } - } - - return FLASH_ERR_NOT_FOUND; -} - -esp_flash_err_t esp_flash_get_protected_region(const esp_flash_chip_t *chip, const esp_flash_region_t *region, bool *protected) -{ - VERIFY_OP(get_protected_regions); - - if (protected == NULL) { - return FLASH_ERR_INVALID_ARG; - } - - uint8_t index; - esp_flash_err_t err = find_region(chip, region, &index); - if (err != FLASH_OK) { - return err; - } - - uint64_t protection_mask = 0; - err = spiflash_start(chip); - if (err != FLASH_OK) { - return err; - } - - err = chip->drv->get_protected_regions(chip, &protection_mask); - if (err == FLASH_OK) { - *protected = protection_mask & (1LL << index); - } - - return spiflash_end(chip, err); -} - -esp_flash_err_t esp_flash_set_protected_region(const esp_flash_chip_t *chip, const esp_flash_region_t *region, bool protected) -{ - VERIFY_OP(set_protected_regions); - - uint8_t index; - esp_flash_err_t err = find_region(chip, region, &index); - if (err != FLASH_OK) { - return err; - } - - uint64_t protection_mask = 0; - err = spiflash_start(chip); - if (err != FLASH_OK) { - return err; - } - - err = chip->drv->get_protected_regions(chip, &protection_mask); - if (err == FLASH_OK) { - if (protected) { - protection_mask |= (1LL << index); - } else { - protection_mask &= ~(1LL << index); - } - err = chip->drv->set_protected_regions(chip, protection_mask); - } - - return spiflash_end(chip, err); -} - -esp_flash_err_t esp_flash_read(const esp_flash_chip_t *chip, void *buffer, uint32_t address, uint32_t length) -{ - VERIFY_OP(read); - if (buffer == NULL || address > chip->size || address+length > chip->size) { - return FLASH_ERR_INVALID_ARG; - } - - esp_flash_err_t err = spiflash_start(chip); - if (err != FLASH_OK) { - return err; - } - - if (err == FLASH_OK) { - err = chip->drv->set_read_mode(chip); - } - - if (err == FLASH_OK) { - err = chip->drv->read(chip, buffer, address, length); - } - - return spiflash_end(chip, err); -} - -esp_flash_err_t esp_flash_write(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length) -{ - VERIFY_OP(write); - if (buffer == NULL || address > chip->size || address+length > chip->size) { - return FLASH_ERR_INVALID_ARG; - } - - /* If 'chip' is connected to the main SPI bus, we can only write directly from regions that are accessible - with cache disabled. */ -#ifdef ESP_PLATFORM - bool direct_write = ( chip->spi != &SPI1 - || ( (uintptr_t) address >= 0x3FFAE000 - && (uintptr_t) address < 0x40000000 ) ); -#else - bool direct_write = true; -#endif - - esp_flash_err_t err = FLASH_OK; - - /* Write output in chunks, either by buffering on stack or - by artificially cutting into MAX_WRITE_CHUNK parts (in an OS - environment, this prevents writing from causing interrupt or higher priority task - starvation.) */ - while(err == FLASH_OK && length > 0) { - uint32_t write_len; - const void *write_buf; - if (direct_write) { - write_len = MIN(length, MAX_WRITE_CHUNK); - write_buf = buffer; - } else { - uint32_t buf[8]; - write_len = MIN(length, sizeof(buf)); - memcpy(buf, buffer, write_len); - write_buf = buf; - } - - err = spiflash_start(chip); - if (err != FLASH_OK) { - return err; - } - - err = chip->drv->write(chip, address, write_buf, write_len); - - address += write_len; - buffer = (void *)((intptr_t)buffer + write_len); - length -= write_len; - - err = spiflash_end(chip, err); - } - return err; -} - -esp_flash_err_t esp_flash_write_encrypted(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length) -{ - VERIFY_OP(write_encrypted); - if (chip->spi != 0) { - // Encrypted operations have to use SPI0 - return FLASH_ERR_UNSUPPORTED_HOST; - } - if (buffer == NULL || address > chip->size || address+length > chip->size) { - return FLASH_ERR_INVALID_ARG; - } - - esp_flash_err_t err = spiflash_start(chip); - if (err != FLASH_OK) { - return err; - } - - err = chip->drv->write_encrypted(chip, address, buffer, length); - - return spiflash_end(chip, err); -} - - -inline static bool regions_overlap(uint32_t a_start, uint32_t a_len,uint32_t b_start, uint32_t b_len) -{ - uint32_t a_end = a_start + a_len; - uint32_t b_end = b_start + b_len; - - return ((a_start >= b_start && a_start <= b_end) - || (a_end >= b_start && a_end <= b_end) - || (b_start >= a_start && b_start <= a_end) - || (b_end >= a_start && b_end <= a_end)); -} - -const esp_flash_chip_t *esp_flash_default_chip; - -static esp_flash_chip_t default_chip; - -esp_flash_err_t esp_flash_init_default_chip() -{ - default_chip.spi = &SPI1; - default_chip.read_mode = ESP_FLASH_FASTRD; // TODO: initialise properly - default_chip.speed = ESP_FLASH_20MHZ; // TODO: initialise properly - - // ROM TODO: account for non-standard default pins in efuse - - // ROM TODO: to account for chips which are slow to power on, maybe keep probing in a loop here - - esp_flash_err_t err = esp_flash_init(&default_chip); - if (err != FLASH_OK) { - return err; - } - - esp_flash_default_chip = &default_chip; - return FLASH_OK; -} - -const esp_flash_os_functions_t *esp_flash_os_functions = &esp_flash_noos_functions; diff --git a/components/spi_flash/spi_flash_lowlevel_driver.c b/components/spi_flash/spi_flash_lowlevel_driver.c deleted file mode 100644 index e901ef1e21..0000000000 --- a/components/spi_flash/spi_flash_lowlevel_driver.c +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2017 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 -#include "spi_flash_lowlevel_driver.h" - -extern const esp_flash_driver_t esp_flash_generic_chip_driver; -extern const esp_flash_driver_t esp_flash_issi_chip_driver; - -/* Default registered chip drivers. - - Note these are tested in order and first match is taken, so generic/catchall entries - should go last. - - Note that the esp_flash_registered_flash_ops pointer can be - changed to point to a different array of registered ops, if desired. -*/ -static const esp_flash_driver_t *default_registered_flash_drivers[] = { - &esp_flash_issi_chip_driver, - &esp_flash_generic_chip_driver, - NULL, -}; - -const esp_flash_driver_t **esp_flash_registered_flash_drivers = default_registered_flash_drivers; diff --git a/components/spi_flash/spi_flash_lowlevel_generic.c b/components/spi_flash/spi_flash_lowlevel_generic.c deleted file mode 100644 index aef068e30f..0000000000 --- a/components/spi_flash/spi_flash_lowlevel_generic.c +++ /dev/null @@ -1,498 +0,0 @@ -// Copyright 2017 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 -#include // For MIN/MAX -#include - -#include "spi_flash_lowlevel_driver.h" -#include "spi_flash_lowlevel_generic.h" - -#define SPI_FLASH_GENERIC_CHIP_ERASE_TIMEOUT 4000 -#define SPI_FLASH_GENERIC_SECTOR_ERASE_TIMEOUT 500 -#define SPI_FLASH_GENERIC_BLOCK_ERASE_TIMEOUT 1000 - -#define DEFAULT_IDLE_TIMEOUT 200 -#define DEFAULT_PAGE_PROGRAM_TIMEOUT 500 - -/* Hardware host-specific constants */ -#define MAX_WRITE_BYTES 32 -#define MAX_READ_BYTES 64 - -#define ADDRESS_MASK_24BIT 0xFFFFFF - -uint32_t spi_flash_common_command(const esp_flash_chip_t *chip, uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len) -{ - typeof(chip->spi->user2) user2 = { - .usr_command_value = command, - .usr_command_bitlen = (8 -1), - }; - chip->spi->user2 = user2; - - typeof(chip->spi->user) user = { - .usr_miso = miso_len > 0, - .usr_mosi = mosi_len > 0, - .usr_dummy = 0, - .usr_command = 1, - }; - chip->spi->user = user; - - chip->spi->ctrl.val = 0; - chip->spi->miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0; - chip->spi->mosi_dlen.usr_mosi_dbitlen = mosi_len ? (mosi_len - 1) : 0; - - // TODO: there's a bug(?) here where if multiple bytes are written - // with each byte MSB-first (correct), but the bytes are - // written out LSB first... - // - // May be easier to just document this in the function interface... - chip->spi->data_buf[0] = mosi_data; - - if (spi_flash_uses_gpio_matrix(chip)) { - /* When flash pins are mapped via GPIO matrix, need a dummy cycle before reading via MISO */ - if (chip->speed == ESP_FLASH_80MHZ) { - chip->spi->user.usr_dummy = 1; - chip->spi->user1.usr_dummy_cyclelen = 1; - } else { - chip->spi->user.usr_dummy = 1; - chip->spi->user1.usr_dummy_cyclelen = 0; - } - } - - chip->spi->cmd.usr = 1; - while(chip->spi->cmd.usr != 0) - { } - - uint32_t miso = chip->spi->data_buf[0]; - - return miso; -} - -esp_flash_err_t spi_flash_generic_probe(esp_flash_chip_t *chip, uint32_t flash_id) -{ - // This is the catch-all probe function, claim the chip always if nothing - // else has claimed it yet. - return FLASH_OK; -} - -esp_flash_err_t spi_flash_generic_read_id(const esp_flash_chip_t *chip, uint32_t *id) -{ - uint32_t raw_flash_id = spi_flash_common_command(chip, CMD_RDID, 0, 0, 24); - if (raw_flash_id == 0xFFFFFF || raw_flash_id == 0) { - return FLASH_ERR_NO_RESPONSE; - } - - // Byte swap the flash id as it's usually written the other way around - uint8_t mfg_id = raw_flash_id & 0xFF; - uint16_t flash_id = (raw_flash_id >> 16) | (raw_flash_id & 0xFF00); - - *id = ((uint32_t)mfg_id << 16) | flash_id; - return FLASH_OK; -} - - -esp_flash_err_t spi_flash_generic_detect_size(const esp_flash_chip_t *chip, uint32_t *size) -{ - uint32_t id = 0; - *size = 0; - esp_flash_err_t err = chip->drv->read_id(chip, &id); - if (err != FLASH_OK) { - return err; - } - - /* Can't detect size unless the high byte of the product ID matches the same convention, which is usually 0x40 or - * 0xC0 or similar. */ - if ((id & 0x0F00) != 0) { - return FLASH_ERR_UNSUPPORTED_CHIP; - } - - *size = 1 << (id & 0xFF); - - return FLASH_OK; -} - - -esp_flash_err_t spi_flash_generic_erase_chip(const esp_flash_chip_t *chip) -{ - esp_flash_err_t err; - - err = chip->drv->write_enable(chip); - if (err == FLASH_OK) { - err = chip->drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); - } - if (err == FLASH_OK) { - chip->spi->ctrl.val = 0; - chip->spi->cmd.flash_ce = 1; - while(chip->spi->cmd.val != 0) { } - err = chip->drv->wait_idle(chip, SPI_FLASH_GENERIC_CHIP_ERASE_TIMEOUT); - } - - return err; -} - -esp_flash_err_t spi_flash_generic_erase_sector(const esp_flash_chip_t *chip, uint32_t start_address) -{ - esp_flash_err_t err = chip->drv->write_enable(chip); - if (err == FLASH_OK) { - err = chip->drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); - } - if (err == FLASH_OK) { - chip->spi->user1.usr_addr_bitlen = (24 - 1); - chip->spi->addr = start_address & ADDRESS_MASK_24BIT; - chip->spi->ctrl.val = 0; - chip->spi->cmd.flash_se = 1; - while(chip->spi->cmd.val != 0) { } - err = chip->drv->wait_idle(chip, SPI_FLASH_GENERIC_SECTOR_ERASE_TIMEOUT); - } - return err; -} - -esp_flash_err_t spi_flash_generic_erase_block(const esp_flash_chip_t *chip, uint32_t start_address) -{ - esp_flash_err_t err = chip->drv->write_enable(chip); - if (err == FLASH_OK) { - err = chip->drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); - } - if (err == FLASH_OK) { - chip->spi->user1.usr_addr_bitlen = (24 - 1); - chip->spi->addr = start_address & ADDRESS_MASK_24BIT; - chip->spi->cmd.flash_be = 1; - while(chip->spi->cmd.val != 0) { } - err = chip->drv->wait_idle(chip, SPI_FLASH_GENERIC_BLOCK_ERASE_TIMEOUT); - } - return err; -} - -esp_flash_err_t spi_flash_generic_read(const esp_flash_chip_t *chip, void *buffer, uint32_t address, uint32_t length) -{ - esp_flash_err_t err = FLASH_OK; - - while (err == FLASH_OK && length > 0) { - uint32_t read_len = MIN(length, MAX_READ_BYTES); - chip->spi->miso_dlen.usr_miso_dbitlen = (read_len * 8) - 1; - chip->spi->addr = address << 8; - - chip->spi->cmd.usr = 1; - while(chip->spi->cmd.val != 0) {} - - if(((intptr_t)buffer % 4 == 0) && (read_len % 4 == 0)) { - // If everything is word-aligned, do a faster memcpy - xthal_memcpy(buffer, (void *)chip->spi->data_buf, read_len); - length -= read_len; - buffer = (void *)((intptr_t)buffer + read_len); - address += read_len; - } else { - // Otherwise, slow(er) path copies word by word - for (int i = 0; i < (read_len+3)/4; i++) { - int word_len = MIN(sizeof(uint32_t), length); - uint32_t word = chip->spi->data_buf[i]; - xthal_memcpy(buffer, &word, word_len); - length -= word_len; - buffer = (void *)((intptr_t)buffer + word_len); - address += word_len; - } - } - } - - - return err; -} - -esp_flash_err_t spi_flash_generic_page_program(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length) -{ - esp_flash_err_t err; - - err = chip->drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); - - if (err == FLASH_OK) { - err = chip->drv->write_enable(chip); - } - - if (err == FLASH_OK) { - // Perform the actual Page Program command - chip->spi->user.usr_dummy = 0; - chip->spi->user1.usr_addr_bitlen = (24 - 1); - chip->spi->addr = (address & ADDRESS_MASK_24BIT) | (length << 24); - - // Load data registers, word at a time - int num_words = (length+3) / 4; - for (int i = 0; i < num_words; i++) { - uint32_t word = 0; - uint32_t word_len = MIN(length, sizeof(word)); - xthal_memcpy(&word, buffer, word_len); - chip->spi->data_buf[i] = word; - length -= word_len; - buffer = (void *)((intptr_t)buffer + word_len); - } - - chip->spi->cmd.flash_pp = 1; - while (chip->spi->cmd.val != 0) { } - - err = chip->drv->wait_idle(chip, DEFAULT_PAGE_PROGRAM_TIMEOUT); - } - - - return err; -} - -esp_flash_err_t spi_flash_generic_write(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length) -{ - esp_flash_err_t err = FLASH_OK; - const uint32_t page_size = chip->drv->page_size; - - while (err == FLASH_OK && length > 0) { - uint32_t page_len = MIN(MAX_WRITE_BYTES, MIN(page_size, length)); - if ((address + page_len) / page_size != address / page_size) { - // Most flash chips can't page write across a page boundary - page_len = page_size - (address % page_size); - } - err = chip->drv->page_program(chip, address, buffer, page_len); - address += page_len; - buffer = (void *)((intptr_t)buffer + page_len); - length -= page_len; - } - - - return err; -} - -esp_flash_err_t spi_flash_generic_write_encrypted(const esp_flash_chip_t *chip, uint32_t address, const void *buffer, uint32_t length) -{ - return FLASH_ERR_UNSUPPORTED_HOST; // TODO -} - -esp_flash_err_t spi_flash_generic_write_enable(const esp_flash_chip_t *chip) -{ - esp_flash_err_t err = FLASH_OK; - - err = chip->drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); - - if (err == FLASH_OK) { - chip->spi->cmd.flash_wren = 1; - while(chip->spi->cmd.val != 0) { } - } - - uint8_t status = spi_flash_common_command(chip, CMD_RDSR, 0, 0, 8); - if ((status & SR_WREN) == 0) { - // WREN flag has not been set! - err = FLASH_ERR_NOT_FOUND; - } - - - return err; -} - -esp_flash_err_t spi_flash_generic_wait_host_idle(const esp_flash_chip_t *chip, uint32_t *timeout_ms) -{ - while(chip->spi->ext2.st != 0 && *timeout_ms > 0) { - if (*timeout_ms > 1) { - esp_flash_os_functions->delay_ms(1); - } - (*timeout_ms)--; - } - - // Not clear if this is necessary, or only necessary if - // chip->spi == SPI1. But probably doesn't hurt... - while(SPI0.ext2.st != 0 && *timeout_ms > 0) { - if (*timeout_ms > 1) { - esp_flash_os_functions->delay_ms(1); - } - (*timeout_ms)--; - } - - return (*timeout_ms > 0) ? FLASH_OK : FLASH_ERR_NO_RESPONSE; -} - -esp_flash_err_t spi_flash_generic_wait_idle(const esp_flash_chip_t *chip, uint32_t timeout_ms) -{ - timeout_ms++; // allow at least one pass before timeout, last one has no sleep cycle - - uint8_t status = 0; - while(timeout_ms > 0) { - - esp_flash_err_t err = spi_flash_generic_wait_host_idle(chip, &timeout_ms); - if (err != FLASH_OK) { - return err; - } - - status = spi_flash_common_command(chip, CMD_RDSR, 0, 0, 8); - if ((status & SR_WIP) == 0) { - break; // Write in progress is complete - } - if (timeout_ms > 1) { - esp_flash_os_functions->delay_ms(1); - } - timeout_ms--; - } - - return (timeout_ms > 0) ? FLASH_OK : FLASH_ERR_NO_RESPONSE; -} - -esp_flash_err_t spi_flash_common_configure_host_read_mode(const esp_flash_chip_t *chip) -{ - int dummy_cyclelen, addr_bitlen, read_command; - switch(chip->read_mode) { - case ESP_FLASH_QIO: - addr_bitlen = 32; - dummy_cyclelen = 4; // TODO check this works - read_command = CMD_FASTRD_QIO; - break; - case ESP_FLASH_QOUT: - addr_bitlen = 24; - dummy_cyclelen = 8; // TODO check this works - read_command = CMD_FASTRD_QUAD; - break; - case ESP_FLASH_DIO: - addr_bitlen = 32; - dummy_cyclelen = 0; - read_command = CMD_FASTRD_DIO; - break; - case ESP_FLASH_DOUT: - addr_bitlen = 24; - dummy_cyclelen = 8; - read_command = CMD_FASTRD_DUAL; - break; - case ESP_FLASH_FASTRD: - addr_bitlen = 24; - dummy_cyclelen = 8; - read_command = CMD_FASTRD; - break; - case ESP_FLASH_SLOWRD: - addr_bitlen = 24; - dummy_cyclelen = 0; - read_command = CMD_READ; - break; - default: - return FLASH_ERR_NOT_INITIALISED; - } - - // Add dummy cycles to compensate for GPIO matrix - // latency, if necessary... - if (spi_flash_uses_gpio_matrix(chip)) { - if (chip->speed == ESP_FLASH_80MHZ) { - dummy_cyclelen += 2; - } else if (chip->speed == ESP_FLASH_40MHZ) { - dummy_cyclelen += 1; - } - } - - chip->spi->user1.usr_dummy_cyclelen = (dummy_cyclelen - 1); - chip->spi->user1.usr_addr_bitlen = (addr_bitlen - 1); - chip->spi->user2.usr_command_value = read_command; - chip->spi->user2.usr_command_bitlen = (8 - 1); - - typeof (chip->spi->user) user = { - .usr_command = 1, - .usr_mosi = 0, - .usr_miso = 1, - .usr_dummy = (dummy_cyclelen > 0) ? 1 : 0, - .usr_addr = 1, - }; - chip->spi->user = user; - - typeof (chip->spi->ctrl) ctrl = { - .fread_qio = (chip->read_mode == ESP_FLASH_QIO), - .fread_quad = (chip->read_mode == ESP_FLASH_QOUT), - .fread_dio = (chip->read_mode == ESP_FLASH_DIO), - .fread_dual = (chip->read_mode == ESP_FLASH_DOUT), - .fastrd_mode = (chip->read_mode != ESP_FLASH_SLOWRD), - }; - chip->spi->ctrl = ctrl; - - return FLASH_OK; -} - -#include - -esp_flash_err_t spi_flash_common_set_read_mode(const esp_flash_chip_t *chip, uint8_t qe_rdsr_command, uint8_t qe_wrsr_command, uint8_t qe_sr_bitwidth, unsigned qe_sr_bit) -{ - if (spi_flash_is_quad_mode(chip)) { - // Ensure quad modes are enabled, using the Quad Enable parameters supplied. - unsigned sr = spi_flash_common_command(chip, qe_rdsr_command, 0, 0, qe_sr_bitwidth); - ets_printf("before 0x%x\n", sr); - if ((sr & qe_sr_bit) == 0) { - sr |= qe_sr_bit; - spi_flash_common_command(chip, qe_wrsr_command, sr, qe_sr_bitwidth, 0); - - /* Check the new QE bit has stayed set */ - sr = spi_flash_common_command(chip, qe_rdsr_command, 0, 0, qe_sr_bitwidth); - ets_printf("after 0x%x\n", sr); - if ((sr & qe_sr_bit) == 0) { - return FLASH_ERR_NO_RESPONSE; - } - } - } - - // Configure the host, and return - return spi_flash_common_configure_host_read_mode(chip); -} - -esp_flash_err_t spi_flash_generic_set_read_mode(const esp_flash_chip_t *chip) -{ - // On "generic" chips, this involves checking - // bit 1 (QE) of RDSR2 (35h) result - // (it works this way on GigaDevice & Fudan Micro chips, probably others...) - const uint8_t BIT_QE = 1<<1; - return spi_flash_common_set_read_mode(chip, CMD_RDSR2, CMD_WRSR2, 8, BIT_QE); -} - -bool spi_flash_uses_gpio_matrix(const esp_flash_chip_t *chip) -{ - if (chip->pins == NULL) { - return false; - } - if (chip->pins->mosi_io_num != -1 - || chip->pins->miso_io_num != -1 - || chip->pins->sclk_io_num != -1) { - return true; - } - if (spi_flash_is_quad_mode(chip)) { - if (chip->pins->quadwp_io_num != -1 - || chip->pins->quadhd_io_num != -1) { - return true; - } - } - return false; -} - -const esp_flash_driver_t esp_flash_generic_chip_driver = { - .probe = spi_flash_generic_probe, - .read_id = spi_flash_generic_read_id, - .detect_size = spi_flash_generic_detect_size, - .erase_chip = spi_flash_generic_erase_chip, - .erase_sector = spi_flash_generic_erase_sector, - .erase_block = spi_flash_generic_erase_block, - .sector_size = 4 * 1024, - .block_erase_size = 64 * 1024, - - // TODO: figure out if generic chip-wide protection bits exist across some manufacturers - .get_chip_write_protect = NULL, - .set_chip_write_protect = NULL, - - // Chip write protection regions do not appear to be standardised - // at all, this is implemented in chip-specific drivers only. - .num_protectable_regions = 0, - .protectable_regions = NULL, - .get_protected_regions = NULL, - .set_protected_regions = NULL, - - .read = spi_flash_generic_read, - .write = spi_flash_generic_write, - .page_program = spi_flash_generic_page_program, - .page_size = 256, - .write_encrypted = spi_flash_generic_write_encrypted, - - .write_enable = spi_flash_generic_write_enable, - .wait_idle = spi_flash_generic_wait_idle, - .set_read_mode = spi_flash_generic_set_read_mode, -}; diff --git a/components/spi_flash/spi_flash_lowlevel_idf_app.c b/components/spi_flash/spi_flash_lowlevel_idf_app.c deleted file mode 100644 index 9b71a1e863..0000000000 --- a/components/spi_flash/spi_flash_lowlevel_idf_app.c +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2017 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 -#include "spi_flash_lowlevel_driver.h" - -#include "rom/ets_sys.h" -#include "esp_attr.h" -#include "esp_spi_flash.h" - -static esp_flash_err_t start(const esp_flash_chip_t *chip) -{ - if (chip->spi == &SPI1) { - g_flash_guard_default_ops.start(); - } - - // TODO figure out if we can coexist with the SPI master driver here, for other peripherals - - return FLASH_OK; -} -static esp_flash_err_t end(const esp_flash_chip_t *chip) -{ - if (chip->spi == &SPI1) { - g_flash_guard_default_ops.end(); - } - - // TODO figure out if we can coexist with the SPI master driver here, for other peripherals - - return FLASH_OK; -} - -static esp_flash_err_t delay_ms(unsigned ms) -{ - ets_delay_us(1000 * ms); - return FLASH_OK; -} - - -const esp_flash_os_functions_t default_os_functions = { - .start = start, - .end = end, - .delay_ms = delay_ms, -}; - -void esp_flash_low_level_app_init() -{ - esp_flash_os_functions = &default_os_functions; -} - - diff --git a/components/spi_flash/spi_flash_os_func_app.c b/components/spi_flash/spi_flash_os_func_app.c new file mode 100644 index 0000000000..9b9738becf --- /dev/null +++ b/components/spi_flash/spi_flash_os_func_app.c @@ -0,0 +1,125 @@ +// Copyright 2015-2019 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 +#include "esp32/rom/ets_sys.h" +#include "esp_attr.h" +#include "esp_spi_flash.h" //for ``g_flash_guard_default_ops`` +#include "esp_flash.h" + +/* + * OS functions providing delay service and arbitration among chips, and with the cache. + * + * The cache needs to be disabled when chips on the SPI1 bus is under operation, hence these functions need to be put + * into the IRAM,and their data should be put into the DRAM. + */ + +typedef struct { + int host_id; +} app_func_arg_t; + +// in the future we will have arbitration among devices, including flash on the same flash bus +static IRAM_ATTR esp_err_t spi_bus_acquire(int host_id) +{ + return ESP_OK; +} + +static IRAM_ATTR esp_err_t spi_bus_release(int host_id) +{ + return ESP_OK; +} + +//for SPI1, we have to disable the cache and interrupts before using the SPI bus +static IRAM_ATTR esp_err_t spi1_start(void *arg) +{ + g_flash_guard_default_ops.start(); + + spi_bus_acquire(((app_func_arg_t *)arg)->host_id); + + return ESP_OK; +} +static IRAM_ATTR esp_err_t spi1_end(void *arg) +{ + g_flash_guard_default_ops.end(); + + spi_bus_release(((app_func_arg_t *)arg)->host_id); + + return ESP_OK; +} + +static esp_err_t spi23_start(void *arg) +{ + spi_bus_acquire(((app_func_arg_t *)arg)->host_id); + return ESP_OK; +} + +static esp_err_t spi23_end(void *arg) +{ + spi_bus_release(((app_func_arg_t *)arg)->host_id); + return ESP_OK; +} + +static IRAM_ATTR esp_err_t delay_ms(void *arg, unsigned ms) +{ + ets_delay_us(1000 * ms); + return ESP_OK; +} + +static DRAM_ATTR app_func_arg_t spi1_arg = { + .host_id = 0, //for SPI1, +}; + +static app_func_arg_t spi2_arg = { + .host_id = 1, //for SPI2, +}; + +static app_func_arg_t spi3_arg = { + .host_id = 2, //for SPI3, +}; + +//for SPI1, we have to disable the cache and interrupts before using the SPI bus +const DRAM_ATTR esp_flash_os_functions_t spi1_default_os_functions = { + .start = spi1_start, + .end = spi1_end, + .delay_ms = delay_ms, +}; + +const esp_flash_os_functions_t spi23_default_os_functions = { + .start = spi23_start, + .end = spi23_end, + .delay_ms = delay_ms, +}; + +esp_err_t esp_flash_init_os_functions(esp_flash_t *chip, int host_id) +{ + if (host_id == 0) { + //SPI1 + chip->os_func = &spi1_default_os_functions; + chip->os_func_data = &spi1_arg; + } else if (host_id == 1 || host_id == 2) { + //SPI2,3 + chip->os_func = &spi23_default_os_functions; + chip->os_func_data = (host_id == 1) ? &spi2_arg : &spi3_arg; + } else { + return ESP_ERR_INVALID_ARG; + } + return ESP_OK; +} + +esp_err_t esp_flash_app_init() +{ + return esp_flash_init_os_functions(esp_flash_default_chip, 0); +} + + diff --git a/components/spi_flash/spi_flash_lowlevel_noos.c b/components/spi_flash/spi_flash_os_func_noos.c similarity index 54% rename from components/spi_flash/spi_flash_lowlevel_noos.c rename to components/spi_flash/spi_flash_os_func_noos.c index 3fb4b8c4bd..4b494279b0 100644 --- a/components/spi_flash/spi_flash_lowlevel_noos.c +++ b/components/spi_flash/spi_flash_os_func_noos.c @@ -1,9 +1,9 @@ -// Copyright 2017 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2019 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 @@ -11,37 +11,34 @@ // 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 -#include "spi_flash_lowlevel_driver.h" +#include "esp_flash.h" -#include "rom/ets_sys.h" -#include "rom/cache.h" +#include "esp32/rom/ets_sys.h" +#include "esp32/rom/cache.h" #include "esp_attr.h" -#include "esp_spi_flash.h" -static esp_flash_err_t start(const esp_flash_chip_t *chip) + +static esp_err_t start(void *arg) { - if (chip->spi == &SPI1) { - Cache_Read_Disable(0); - Cache_Read_Disable(1); - } - return FLASH_OK; + Cache_Read_Disable(0); + Cache_Read_Disable(1); + return ESP_OK; } -static esp_flash_err_t end(const esp_flash_chip_t *chip) +static esp_err_t end(void *arg) { - if (chip->spi == &SPI1) { - Cache_Flush(0); - Cache_Flush(1); - Cache_Read_Enable(0); - Cache_Read_Enable(1); - } - return FLASH_OK; + Cache_Flush(0); + Cache_Flush(1); + Cache_Read_Enable(0); + Cache_Read_Enable(1); + return ESP_OK; } -static esp_flash_err_t delay_ms(unsigned ms) +static esp_err_t delay_ms(void *arg, unsigned ms) { ets_delay_us(1000 * ms); - return FLASH_OK; + return ESP_OK; } const esp_flash_os_functions_t esp_flash_noos_functions = { diff --git a/components/spi_flash/test/test_cache_disabled.c b/components/spi_flash/test/test_cache_disabled.c index ba4e8534e6..747ccdf3ab 100644 --- a/components/spi_flash/test/test_cache_disabled.c +++ b/components/spi_flash/test/test_cache_disabled.c @@ -30,7 +30,7 @@ static IRAM_ATTR void cache_test_task(void *arg) vTaskDelete(NULL); } -TEST_CASE("spi_flash_cache_enabled() works on both CPUs", "[spi_flash]") +TEST_CASE("spi_flash_cache_enabled() works on both CPUs", "[spi_flash][esp_flash]") { result_queue = xQueueCreate(1, sizeof(bool)); diff --git a/components/spi_flash/test/test_esp_flash.c b/components/spi_flash/test/test_esp_flash.c new file mode 100644 index 0000000000..58d6f50a8d --- /dev/null +++ b/components/spi_flash/test/test_esp_flash.c @@ -0,0 +1,549 @@ +#include +#include +#include +#include +#include + +#include +#include "esp_flash.h" +#include "spi_flash_chip_generic.h" +#include +#include "esp_log.h" + +#include + +#include "unity.h" +#include "driver/spi_common.h" +#include "memspi_host_driver.h" +#include "driver/gpio.h" +#include "soc/io_mux_reg.h" + + +#define FUNC_SPI 1 + +static uint8_t sector_buf[4096]; + +// #define TEST_SPI1_CS1 +// #define TEST_SPI2_CS0 +// #define TEST_SPI3_CS0 +#define TEST_SPI_SPEED ESP_FLASH_10MHZ +#define TEST_SPI_READ_MODE SPI_FLASH_FASTRD +//#define FORCE_GPIO_MATRIX + +#ifdef TEST_SPI2_CS0 +#define TEST_HOST HSPI_HOST +#define TEST_CS 0 +#define TEST_CS_PIN HSPI_IOMUX_PIN_NUM_CS +#define HSPI_PIN_NUM_MOSI HSPI_IOMUX_PIN_NUM_MOSI +#define HSPI_PIN_NUM_MISO HSPI_IOMUX_PIN_NUM_MISO +#define HSPI_PIN_NUM_CLK HSPI_IOMUX_PIN_NUM_CLK +#define HSPI_PIN_NUM_HD HSPI_IOMUX_PIN_NUM_HD +#define HSPI_PIN_NUM_WP HSPI_IOMUX_PIN_NUM_WP +#define TEST_INPUT_DELAY 20 +#elif defined TEST_SPI3_CS0 +#define TEST_HOST VSPI_HOST +#define TEST_CS 0 +#define TEST_CS_PIN VSPI_IOMUX_PIN_NUM_CS +#define VSPI_PIN_NUM_MOSI VSPI_IOMUX_PIN_NUM_MOSI +#define VSPI_PIN_NUM_MISO VSPI_IOMUX_PIN_NUM_MISO +#define VSPI_PIN_NUM_CLK VSPI_IOMUX_PIN_NUM_CLK +#define VSPI_PIN_NUM_HD VSPI_IOMUX_PIN_NUM_HD +#define VSPI_PIN_NUM_WP VSPI_IOMUX_PIN_NUM_WP +#define TEST_INPUT_DELAY 0 +#elif defined TEST_SPI1_CS1 +#define TEST_HOST SPI_HOST +#define TEST_CS 1 +// #define TEST_CS_PIN 14 +#define TEST_CS_PIN 16 //the pin which is usually used by the PSRAM +// #define TEST_CS_PIN 27 +#define TEST_INPUT_DELAY 25 + +#define EXTRA_SPI1_CLK_IO 17 //the pin which is usually used by the PSRAM clk + +#else +#define SKIP_EXTENDED_CHIP_TEST +#endif + + +static const char TAG[] = "test_esp_flash"; + + +#ifndef SKIP_EXTENDED_CHIP_TEST + +static esp_flash_t *test_chip = NULL; +static esp_flash_t chip_init; +static spi_flash_host_driver_t chip_host_driver; +static memspi_host_data_t driver_data = {}; + +static void IRAM_ATTR cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num, bool use_iomux) +{ + int spics_in = spi_periph_signal[host].spics_in; + int spics_out = spi_periph_signal[host].spics_out[cs_num]; + uint32_t iomux_reg = GPIO_PIN_MUX_REG[TEST_CS_PIN]; + //to avoid the panic caused by flash data line conflicts during cs line initialization, disable the cache temporarily + //some data from flash to be used should be read before the cache disabling + g_flash_guard_default_ops.start(); + if (use_iomux) { + GPIO.func_in_sel_cfg[spics_in].sig_in_sel = 0; + PIN_INPUT_ENABLE(iomux_reg); + GPIO.func_out_sel_cfg[spics_out].oen_sel = 0; + GPIO.func_out_sel_cfg[spics_out].oen_inv_sel = false; + PIN_FUNC_SELECT(iomux_reg, FUNC_SPI); + } else { + PIN_INPUT_ENABLE(iomux_reg); + if (cs_io_num < 32) { + GPIO.enable_w1ts = (0x1 << cs_io_num); + } else { + GPIO.enable1_w1ts.data = (0x1 << (cs_io_num - 32)); + } + GPIO.pin[cs_io_num].pad_driver = 0; + gpio_matrix_out(cs_io_num, spics_out, false, false); + if (cs_num == 0) { + gpio_matrix_in(cs_io_num, spics_in, false); + } + PIN_FUNC_SELECT(iomux_reg, PIN_FUNC_GPIO); + } + g_flash_guard_default_ops.end(); +} + +static void setup_new_chip(esp_flash_read_mode_t io_mode, esp_flash_speed_t speed) +{ + chip_init = (esp_flash_t) { + .read_mode = io_mode, + }; + +#ifdef TEST_SPI2_CS0 + bool spi_chan_claimed = spicommon_periph_claim(HSPI_HOST, "spi flash"); + TEST_ASSERT(spi_chan_claimed); + + spi_bus_config_t hspi_bus_cfg = { + .mosi_io_num = HSPI_PIN_NUM_MOSI, + .miso_io_num = HSPI_PIN_NUM_MISO, + .sclk_io_num = HSPI_PIN_NUM_CLK, + .quadhd_io_num = HSPI_PIN_NUM_HD, + .quadwp_io_num = HSPI_PIN_NUM_WP, + .max_transfer_sz = 64, + }; +#ifdef FORCE_GPIO_MATRIX + hspi_bus_cfg.quadhd_io_num = 23; +#endif + + uint32_t flags; + esp_err_t ret = spicommon_bus_initialize_io(HSPI_HOST, &hspi_bus_cfg, 0, SPICOMMON_BUSFLAG_MASTER | (&hspi_bus_cfg)->flags, &flags); + TEST_ESP_OK(ret); + bool use_iomux = (flags & SPICOMMON_BUSFLAG_NATIVE_PINS) ? 1 : 0; + + printf("setup flash on SPI2 (HSPI) CS0...\n"); + printf("use iomux:%d\n", use_iomux); + memspi_host_config_t cfg = { + .host_id = 2, + .speed = speed, + .iomux = use_iomux, + .cs_num = TEST_CS, + .input_delay_ns = TEST_INPUT_DELAY, + }; +#elif defined TEST_SPI3_CS0 + bool spi_chan_claimed = spicommon_periph_claim(VSPI_HOST, "spi flash"); + TEST_ASSERT(spi_chan_claimed); + + spi_bus_config_t vspi_bus_cfg = { + .mosi_io_num = VSPI_PIN_NUM_MOSI, + .miso_io_num = VSPI_PIN_NUM_MISO, + .sclk_io_num = VSPI_PIN_NUM_CLK, + .quadhd_io_num = VSPI_PIN_NUM_HD, + .quadwp_io_num = VSPI_PIN_NUM_WP, + .max_transfer_sz = 64, + }; +#ifdef FORCE_GPIO_MATRIX + vspi_bus_cfg.quadhd_io_num = 23; +#endif + + uint32_t flags; + esp_err_t ret = spicommon_bus_initialize_io(VSPI_HOST, &vspi_bus_cfg, 0, SPICOMMON_BUSFLAG_MASTER | (&vspi_bus_cfg)->flags, &flags); + TEST_ESP_OK(ret); + bool use_iomux = (flags & SPICOMMON_BUSFLAG_NATIVE_PINS) ? 1 : 0; + //TEST_ASSERT(use_iomux); + + printf("setup flash on SPI3 (VSPI) CS0...\n"); + printf("use iomux:%d\n", use_iomux); + memspi_host_config_t cfg = { + .host_id = 3, + .speed = speed, + .iomux = use_iomux, + .cs_num = TEST_CS, + .input_delay_ns = TEST_INPUT_DELAY, + }; +#elif defined TEST_SPI1_CS1 + printf("setup flash on SPI1 CS1...\n"); + memspi_host_config_t cfg = { + .host_id = 1, + .speed = speed, + .iomux = true, + .cs_num = TEST_CS, + .input_delay_ns = TEST_INPUT_DELAY, + }; + bool use_iomux = (TEST_CS_PIN == spi_periph_signal[TEST_HOST].spics0_iomux_pin) && (driver_data.cs_num == 0); + +# ifdef EXTRA_SPI1_CLK_IO + gpio_matrix_out(EXTRA_SPI1_CLK_IO, SPICLK_OUT_IDX, 0, 0); +# endif +#endif + + esp_err_t err = memspi_host_init_pointers(&chip_host_driver, &driver_data, &cfg); + cs_initialize(TEST_HOST, TEST_CS_PIN, driver_data.cs_num, use_iomux); + TEST_ESP_OK(err); + chip_init.host = &chip_host_driver; + + esp_flash_init_os_functions(&chip_init, TEST_HOST); + + err = esp_flash_init(&chip_init); + TEST_ESP_OK(err); + test_chip = &chip_init; +} + +void teardown_test_chip() +{ + if (TEST_HOST == HSPI_HOST || TEST_HOST == VSPI_HOST) { + spicommon_periph_free(TEST_HOST); + } +} + +#endif + +static void test_metadata(esp_flash_t *chip) +{ + ESP_LOGI(TAG, "Testing chip %p...", chip); + uint32_t id, size; + TEST_ESP_OK(esp_flash_read_id(chip, &id)); + TEST_ESP_OK(esp_flash_get_size(chip, &size)); + printf("Flash ID %08x detected size %d bytes\n", id, size); +} + +TEST_CASE("SPI flash metadata functions", "[esp_flash]") +{ +#ifndef SKIP_EXTENDED_CHIP_TEST + setup_new_chip(TEST_SPI_READ_MODE, TEST_SPI_SPEED); + test_metadata(test_chip); + teardown_test_chip(); +#endif + test_metadata(NULL); +} + +static uint32_t erase_test_region(esp_flash_t *chip, int num_sectors) +{ + const esp_partition_t *part = get_test_data_partition(); + uint32_t offs = part->address; + + /* chip should be initialised */ + TEST_ASSERT(esp_flash_default_chip != NULL + && esp_flash_chip_driver_initialized(esp_flash_default_chip)); + + TEST_ASSERT(num_sectors * 4096 <= part->size); + + bzero(sector_buf, sizeof(sector_buf)); + + printf("Erase @ 0x%x...\n", offs); + TEST_ASSERT_EQUAL_HEX32(ESP_OK, esp_flash_erase_region(chip, offs, num_sectors * 4096) ); + + printf("Verify erased...\n"); + for (int i = 0; i < num_sectors; i++) { + TEST_ASSERT_EQUAL_HEX32(ESP_OK, esp_flash_read(chip, sector_buf, offs + i * 4096, sizeof(sector_buf))); + + printf("Buffer starts 0x%02x 0x%02x 0x%02x 0x%02x\n", sector_buf[0], sector_buf[1], sector_buf[2], sector_buf[3]); + for (int i = 0; i < sizeof(sector_buf); i++) { + TEST_ASSERT_EQUAL_HEX8(0xFF, sector_buf[i]); + } + } + + return offs; +} + +void test_simple_read_write(void *chip) +{ + ESP_LOGI(TAG, "Testing chip %p...", chip); + uint32_t offs = erase_test_region(chip, 1); + + const int test_seed = 778; + srand(test_seed); + for (int i = 0 ; i < sizeof(sector_buf); i++) { + sector_buf[i] = rand(); + } + + printf("Write %p...\n", (void *)offs); + TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, sector_buf, offs, sizeof(sector_buf)) ); + + bzero(sector_buf, sizeof(sector_buf)); + + printf("Read back...\n"); + TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, sector_buf, offs, sizeof(sector_buf)) ); + + printf("Buffer starts 0x%02x 0x%02x 0x%02x 0x%02x\n", sector_buf[0], sector_buf[1], sector_buf[2], sector_buf[3]); + + srand(test_seed); + for (int i = 0; i < sizeof(sector_buf); i++) { + TEST_ASSERT_EQUAL_HEX8(rand() & 0xFF, sector_buf[i]); + } +} + +TEST_CASE("SPI flash simple read/write", "[esp_flash]") +{ + test_simple_read_write(NULL); +#ifndef SKIP_EXTENDED_CHIP_TEST + setup_new_chip(TEST_SPI_READ_MODE, TEST_SPI_SPEED); + test_simple_read_write(test_chip); + teardown_test_chip(); +#endif +} + +void test_unaligned_read_write(void *chip) +{ + ESP_LOGI(TAG, "Testing chip %p...", chip); + uint32_t offs = erase_test_region(chip, 2); + + const char *msg = "i am a message"; + TEST_ASSERT(strlen(msg) + 1 % 4 != 0); + TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, msg, offs + 1, strlen(msg) + 1) ); + + char buf[strlen(msg) + 1]; + + memset(buf, 0xEE, sizeof(buf)); + + TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, buf, offs + 1, strlen(msg) + 1) ); + TEST_ASSERT_EQUAL_STRING_LEN(msg, buf, strlen(msg)); + TEST_ASSERT(memcmp(buf, msg, strlen(msg) + 1) == 0); +} + +TEST_CASE("SPI flash unaligned read/write", "[esp_flash]") +{ +#ifndef SKIP_EXTENDED_CHIP_TEST + setup_new_chip(TEST_SPI_READ_MODE, TEST_SPI_SPEED); + test_unaligned_read_write(test_chip); + teardown_test_chip(); +#endif + test_unaligned_read_write(NULL); +} + +void test_single_read_write(void *chip) +{ + ESP_LOGI(TAG, "Testing chip %p...", chip); + uint32_t offs = erase_test_region(chip, 2); + + for (unsigned v = 0; v < 512; v++) { + TEST_ASSERT_EQUAL_HEX(ESP_OK, esp_flash_write(chip, &v, offs + v, 1) ); + } + + for (unsigned v = 0; v < 512; v++) { + uint8_t readback; + TEST_ASSERT_EQUAL_HEX(ESP_OK, esp_flash_read(chip, &readback, offs + v, 1) ); + TEST_ASSERT_EQUAL_HEX8(v, readback); + } +} + +TEST_CASE("SPI flash single byte reads/writes", "[esp_flash]") +{ + test_single_read_write(NULL); +#ifndef SKIP_EXTENDED_CHIP_TEST + setup_new_chip(TEST_SPI_READ_MODE, TEST_SPI_SPEED); + test_single_read_write(test_chip); + teardown_test_chip(); +#endif +} + + +/* this test is notable because it generates a lot of unaligned reads/writes, + and also reads/writes across both a sector boundary & many page boundaries. +*/ +void test_three_byte_read_write(void *chip) +{ + ESP_LOGI(TAG, "Testing chip %p...", chip); + uint32_t offs = erase_test_region(chip, 2); + ets_printf("offs:%X\n", offs); + + for (uint32_t v = 0; v < 2000; v++) { + TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, &v, offs + 3 * v, 3) ); + } + + for (uint32_t v = 0; v < 2000; v++) { + uint32_t readback; + TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, &readback, offs + 3 * v, 3) ); + TEST_ASSERT_EQUAL_HEX32(v & 0xFFFFFF, readback & 0xFFFFFF); + } +} + +TEST_CASE("SPI flash three byte reads/writes", "[esp_flash]") +{ +#ifndef SKIP_EXTENDED_CHIP_TEST + setup_new_chip(TEST_SPI_READ_MODE, TEST_SPI_SPEED); + test_three_byte_read_write(test_chip); + teardown_test_chip(); +#endif + test_three_byte_read_write(NULL); +} + +void test_erase_large_region(esp_flash_t *chip) +{ + ESP_LOGI(TAG, "Testing chip %p...", chip); + + const esp_partition_t *part = get_test_data_partition(); + + /* Write some noise at the start and the end of the region */ + const char *ohai = "OHAI"; + uint32_t readback; + TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, ohai, part->address, 5)); + TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, ohai, part->address + part->size - 5, 5)); + + /* sanity check what we just wrote. since the partition may haven't been erased, we only check the part which is written to 0. */ + uint32_t written_data = *((const uint32_t *)ohai); + TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, &readback, part->address + part->size - 5, 4)); + TEST_ASSERT_EQUAL_HEX32(0, readback & (~written_data)); + TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, &readback, part->address, 4)); + TEST_ASSERT_EQUAL_HEX32(0, readback & (~written_data)); + + /* Erase whole region */ + TEST_ASSERT_EQUAL(ESP_OK, esp_flash_erase_region(chip, part->address, part->size)); + + /* ensure both areas we wrote are now all-FFs */ + TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, &readback, part->address, 4)); + TEST_ASSERT_EQUAL_HEX32(0xFFFFFFFF, readback); + + TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, &readback, part->address + part->size - 5, 4)); + TEST_ASSERT_EQUAL_HEX32(0xFFFFFFFF, readback); +} + +TEST_CASE("SPI flash erase large region", "[esp_flash]") +{ + test_erase_large_region(NULL); +#ifndef SKIP_EXTENDED_CHIP_TEST + setup_new_chip(TEST_SPI_READ_MODE, TEST_SPI_SPEED); + test_erase_large_region(test_chip); + teardown_test_chip(); +#endif +} + +static const uint8_t large_const_buffer[16400] = { + 203, // first byte + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + [50 ... 99] = 2, + [1600 ... 2000] = 3, + [8000 ... 9000] = 77, + [15000 ... 16398] = 8, + 43 // last byte +}; + +static void test_write_large_buffer(esp_flash_t *chip, const uint8_t *source, size_t length); +static void write_large_buffer(esp_flash_t *chip, const esp_partition_t *part, const uint8_t *source, size_t length); +static void read_and_check(esp_flash_t *chip, const esp_partition_t *part, const uint8_t *source, size_t length); + +TEST_CASE("SPI flash test reading with all speed/mode permutations", "[esp_flash]") +{ + const int length = sizeof(large_const_buffer); + uint8_t *source_buf = malloc(length); + TEST_ASSERT_NOT_NULL(source_buf); + srand(778); + for (int i = 0; i < length; i++) { + source_buf[i] = rand(); + } + + const esp_partition_t *part = get_test_data_partition(); + TEST_ASSERT(part->size > length + 2 + SPI_FLASH_SEC_SIZE); + +#ifndef SKIP_EXTENDED_CHIP_TEST + //use the lowest speed to write and read to make sure success + setup_new_chip(TEST_SPI_READ_MODE, ESP_FLASH_SPEED_MIN); + write_large_buffer(test_chip, part, source_buf, length); + read_and_check(test_chip, part, source_buf, length); + teardown_test_chip(); + + esp_flash_read_mode_t io_mode = SPI_FLASH_READ_MODE_MIN; + while (io_mode != SPI_FLASH_READ_MODE_MAX) { + esp_flash_speed_t speed = ESP_FLASH_SPEED_MIN; + while (speed != ESP_FLASH_SPEED_MAX) { + ESP_LOGI(TAG, "test flash io mode: %d, speed: %d", io_mode, speed); + setup_new_chip(io_mode, speed); + read_and_check(test_chip, part, source_buf, length); + teardown_test_chip(); + speed++; + } + io_mode++; + } +#endif + + //test main flash BTW + write_large_buffer(NULL, part, source_buf, length); + read_and_check(NULL, part, source_buf, length); + + free(source_buf); +} + +TEST_CASE("Test esp_flash_write large const buffer", "[esp_flash]") +{ + //buffer in flash + test_write_large_buffer(NULL, large_const_buffer, sizeof(large_const_buffer)); +#ifndef SKIP_EXTENDED_CHIP_TEST + setup_new_chip(TEST_SPI_READ_MODE, TEST_SPI_SPEED); + test_write_large_buffer(test_chip, large_const_buffer, sizeof(large_const_buffer)); + teardown_test_chip(); +#endif +} + +#ifndef SKIP_EXTENDED_CHIP_TEST +TEST_CASE("Test esp_flash_write large RAM buffer", "[esp_flash]") +{ + // buffer in RAM + uint8_t *source_buf = malloc(sizeof(large_const_buffer)); + TEST_ASSERT_NOT_NULL(source_buf); + memcpy(source_buf, large_const_buffer, sizeof(large_const_buffer)); + + setup_new_chip(TEST_SPI_READ_MODE, TEST_SPI_SPEED); + test_write_large_buffer(test_chip, source_buf, sizeof(large_const_buffer)); + teardown_test_chip(); + + free(source_buf); +} +#endif + +static void write_large_buffer(esp_flash_t *chip, const esp_partition_t *part, const uint8_t *source, size_t length) +{ + printf("Writing chip %p, %d bytes from source %p\n", chip, length, source); + + ESP_ERROR_CHECK( esp_flash_erase_region(chip, part->address, (length + SPI_FLASH_SEC_SIZE) & ~(SPI_FLASH_SEC_SIZE - 1)) ); + + // note writing to unaligned address + ESP_ERROR_CHECK( esp_flash_write(chip, source, part->address + 1, length) ); +} + +static void read_and_check(esp_flash_t *chip, const esp_partition_t *part, const uint8_t *source, size_t length) +{ + printf("Checking chip %p, %d bytes\n", chip, length); + uint8_t *buf = malloc(length); + TEST_ASSERT_NOT_NULL(buf); + ESP_ERROR_CHECK( esp_flash_read(chip, buf, part->address + 1, length) ); + TEST_ASSERT_EQUAL_HEX8_ARRAY(source, buf, length); + free(buf); + + // check nothing was written at beginning or end + uint8_t ends[8]; + + ESP_ERROR_CHECK( esp_flash_read(chip, ends, part->address, sizeof(ends)) ); + TEST_ASSERT_EQUAL_HEX8(0xFF, ends[0]); + TEST_ASSERT_EQUAL_HEX8(source[0], ends[1]); + + ESP_ERROR_CHECK( esp_flash_read(chip, ends, part->address + length, sizeof(ends)) ); + + TEST_ASSERT_EQUAL_HEX8(source[length - 1], ends[0]); + TEST_ASSERT_EQUAL_HEX8(0xFF, ends[1]); + TEST_ASSERT_EQUAL_HEX8(0xFF, ends[2]); + TEST_ASSERT_EQUAL_HEX8(0xFF, ends[3]); +} + +static void test_write_large_buffer(esp_flash_t *chip, const uint8_t *source, size_t length) +{ + ESP_LOGI(TAG, "Testing chip %p...", chip); + const esp_partition_t *part = get_test_data_partition(); + TEST_ASSERT(part->size > length + 2 + SPI_FLASH_SEC_SIZE); + + write_large_buffer(chip, part, source, length); + read_and_check(chip, part, source, length); +} + diff --git a/components/spi_flash/test/test_large_flash_writes.c b/components/spi_flash/test/test_large_flash_writes.c index f530ca3788..11824cd11b 100644 --- a/components/spi_flash/test/test_large_flash_writes.c +++ b/components/spi_flash/test/test_large_flash_writes.c @@ -42,13 +42,13 @@ static const uint8_t large_const_buffer[16400] = { static void test_write_large_buffer(const uint8_t *source, size_t length); -TEST_CASE("Test spi_flash_write large const buffer", "[spi_flash]") +TEST_CASE("Test spi_flash_write large const buffer", "[spi_flash][esp_flash]") { // buffer in flash test_write_large_buffer(large_const_buffer, sizeof(large_const_buffer)); } -TEST_CASE("Test spi_flash_write large RAM buffer", "[spi_flash]") +TEST_CASE("Test spi_flash_write large RAM buffer", "[spi_flash][esp_flash]") { // buffer in RAM uint8_t *source_buf = malloc(sizeof(large_const_buffer)); diff --git a/components/spi_flash/test/test_low_level.c b/components/spi_flash/test/test_low_level.c deleted file mode 100644 index da77f892fb..0000000000 --- a/components/spi_flash/test/test_low_level.c +++ /dev/null @@ -1,181 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -static uint8_t sector_buf[4096]; - -TEST_CASE("SPI flash metadata functions", "[spi_flash_ll]") -{ - uint32_t id, size; - - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_read_id(NULL, &id) ); - - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_detect_size(NULL, &size) ); - - printf("Flash ID %08x detected size %d bytes\n", id, size); -} - -static uint32_t erase_test_region(int num_sectors) -{ - const esp_partition_t *part = get_test_data_partition(); - uint32_t offs = part->address; - - /* chip should be initialised */ - TEST_ASSERT(esp_flash_default_chip != NULL - && esp_flash_default_chip->drv != NULL); - - TEST_ASSERT(num_sectors * 4096 <= part->size); - - bzero(sector_buf, sizeof(sector_buf)); - - printf("Erase @ 0x%x...\n", offs); - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_erase_region(NULL, offs, num_sectors * 4096) ); - - printf("Verify erased...\n"); - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_read(NULL, sector_buf, offs, sizeof(sector_buf)) ); - - printf("Buffer starts 0x%02x 0x%02x 0x%02x 0x%02x\n", sector_buf[0], sector_buf[1], sector_buf[2], sector_buf[3]); - for (int i = 0; i < sizeof(sector_buf); i++) { - TEST_ASSERT_EQUAL_HEX8(0xFF, sector_buf[i]); - } - - return offs; -} - -TEST_CASE("SPI flash simple read/write", "[spi_flash_ll]") -{ - uint32_t offs = erase_test_region(1); - - for (int i =0 ; i < sizeof(sector_buf); i++) { - sector_buf[i] = i & 0xFF; - } - - printf("Write...\n"); - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_write(NULL, offs, sector_buf, sizeof(sector_buf)) ); - - bzero(sector_buf, sizeof(sector_buf)); - - printf("Read back...\n"); - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_read(NULL, sector_buf, offs, sizeof(sector_buf)) ); - - printf("Buffer starts 0x%02x 0x%02x 0x%02x 0x%02x\n", sector_buf[0], sector_buf[1], sector_buf[2], sector_buf[3]); - - for (int i = 0; i < sizeof(sector_buf); i++) { - TEST_ASSERT_EQUAL_HEX8(i & 0xFF, sector_buf[i]); - } -} - -TEST_CASE("SPI flash unaligned read/write", "[spi_flash_ll]") -{ - uint32_t offs = erase_test_region(2); - - const char *msg = "i am a message"; - TEST_ASSERT(strlen(msg)+1 % 4 != 0); - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_write(NULL, offs+1, msg, strlen(msg)+1) ); - - char buf[strlen(msg) + 1]; - - memset(buf, 0xEE, sizeof(buf)); - - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_read(NULL, buf, offs+1, strlen(msg)+1) ); - TEST_ASSERT_EQUAL_STRING_LEN(msg, buf, strlen(msg)); - TEST_ASSERT(memcmp(buf, msg, strlen(msg)+1) == 0); -} - - -TEST_CASE("SPI flash single byte reads/writes", "[spi_flash_ll]") -{ - uint32_t offs = erase_test_region(2); - - for (unsigned v = 0; v < 512; v++) { - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_write(NULL, offs+v, &v, 1) ); - } - - for (unsigned v = 0; v < 512; v++) { - uint8_t readback; - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_read(NULL, &readback, offs+v, 1) ); - TEST_ASSERT_EQUAL_HEX8(v, readback); - } -} - -/* this test is notable because it generates a lot of unaligned reads/writes, - and also reads/writes across both a sector boundary & many page boundaries. -*/ -TEST_CASE("SPI flash three byte reads/writes", "[spi_flash_ll]") -{ - uint32_t offs = erase_test_region(2); - - for (uint32_t v = 0; v < 2000; v++) { - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_write(NULL, offs+3*v, &v, 3) ); - } - - for (uint32_t v = 0; v < 2000; v++) { - uint32_t readback; - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_read(NULL, &readback, offs+3*v, 3) ); - TEST_ASSERT_EQUAL_HEX32(v & 0xFFFFFF, readback & 0xFFFFFF); - } -} - -TEST_CASE("SPI flash erase large region", "[spi_flash_ll]") -{ - const esp_partition_t *part = get_test_data_partition(); - - /* Write some noise at the start and the end of the region */ - const char *ohai = "OHAI"; - uint32_t readback; - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_write(NULL, part->address, ohai, 5)); - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_write(NULL, part->address + part->size - 5, ohai, 5)); - - /* sanity check what we just wrote */ - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_read(NULL, &readback, part->address + part->size - 5, 4)); - TEST_ASSERT_EQUAL_HEX32(*((const uint32_t*)ohai), readback); - - /* Erase whole region */ - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_erase_region(NULL, part->address, part->size)); - - /* ensure both areas we wrote are now all-FFs */ - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_read(NULL, &readback, part->address, 4)); - TEST_ASSERT_EQUAL_HEX32(0xFFFFFFFF, readback); - - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_read(NULL, &readback, part->address + part->size - 5, 4)); - TEST_ASSERT_EQUAL_HEX32(0xFFFFFFFF, readback); -} - -TEST_CASE("SPI flash test reading with all speed/mode permutations", "[spi_flash_ll]") -{ - /* Note: this only works if the SPI flash chip supports all these modes & speeds */ - - uint32_t offs = erase_test_region(1); - - /* Write some test data */ - const char *message = "This is some test data."; - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_write(NULL, offs, message, strlen(message)+1) ); - - // Start by copying the default chip to a structure we can tweak - esp_flash_chip_t chip = *esp_flash_default_chip; - - for (chip.read_mode = 0; - chip.read_mode != ESP_FLASH_READ_MODE_MAX; - chip.read_mode++) { - for (chip.speed = 0; - chip.speed != ESP_FLASH_SPEED_MAX; - chip.speed++) { - printf("mode %d speed %d\n", chip.read_mode, chip.speed); - - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_init(&chip) ); - - char *buf[strlen(message)+1]; - memset(buf, 0xFF, sizeof(buf)); - TEST_ASSERT_EQUAL(FLASH_OK, esp_flash_read(&chip, buf, offs, sizeof(buf)) ); - TEST_ASSERT_EQUAL_STRING_LEN(message, buf, strlen(message)); - } - } -} diff --git a/components/spi_flash/test/test_mmap.c b/components/spi_flash/test/test_mmap.c index 4cdb775943..fe14a8be05 100644 --- a/components/spi_flash/test/test_mmap.c +++ b/components/spi_flash/test/test_mmap.c @@ -200,7 +200,7 @@ TEST_CASE("Can mmap unordered pages into contiguous memory", "[spi_flash]") pages[i]=startpage+(nopages-1)-i; printf("Offset %x page %d\n", i*0x10000, pages[i]); } - + printf("Attempting mapping of unordered pages to contiguous memory area\n"); spi_flash_mmap_handle_t handle1; @@ -277,7 +277,7 @@ TEST_CASE("flash_mmap invalidates just-written data", "[spi_flash]") TEST_CASE("flash_mmap can mmap after get enough free MMU pages", "[spi_flash]") { - //this test case should make flash size >= 4MB, because max size of Dcache can mapped is 4MB + //this test case should make flash size >= 4MB, because max size of Dcache can mapped is 4MB setup_mmap_tests(); printf("Mapping %x (+%x)\n", start, end - start); diff --git a/components/spi_flash/test/test_out_of_bounds_write.c b/components/spi_flash/test/test_out_of_bounds_write.c index 9b411b0365..bc4a5d5745 100644 --- a/components/spi_flash/test/test_out_of_bounds_write.c +++ b/components/spi_flash/test/test_out_of_bounds_write.c @@ -9,9 +9,9 @@ static const char *data = "blah blah blah"; #if CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS -#define TEST_TAGS "[spi_flash]" +#define TEST_TAGS "[spi_flash][esp_flash]" #else // ABORTS -#define TEST_TAGS "[spi_flash][ignore]" +#define TEST_TAGS "[spi_flash][esp_flash][ignore]" #endif TEST_CASE("can't overwrite bootloader", TEST_TAGS) diff --git a/components/spi_flash/test/test_partitions.c b/components/spi_flash/test/test_partitions.c index d859d3dd2c..705f0bed75 100644 --- a/components/spi_flash/test/test_partitions.c +++ b/components/spi_flash/test/test_partitions.c @@ -25,7 +25,7 @@ #include #include -TEST_CASE("Test erase partition", "[spi_flash]") +TEST_CASE("Test erase partition", "[spi_flash][esp_flash]") { const esp_partition_t *part = get_test_data_partition(); diff --git a/components/spi_flash/test/test_read_write.c b/components/spi_flash/test/test_read_write.c index ecc7e23c49..febe95bf80 100644 --- a/components/spi_flash/test/test_read_write.c +++ b/components/spi_flash/test/test_read_write.c @@ -79,7 +79,7 @@ static void IRAM_ATTR test_read(int src_off, int dst_off, int len) spi_flash_disable_interrupts_caches_and_other_cpu(); esp_rom_spiflash_result_t rc = esp_rom_spiflash_write(start, src_buf, sizeof(src_buf)); spi_flash_enable_interrupts_caches_and_other_cpu(); - TEST_ASSERT_EQUAL_INT(rc, ESP_ROM_SPIFLASH_RESULT_OK); + TEST_ASSERT_EQUAL_HEX(rc, ESP_ROM_SPIFLASH_RESULT_OK); memset(dst_buf, 0x55, sizeof(dst_buf)); memset(dst_gold, 0x55, sizeof(dst_gold)); fill(dst_gold + dst_off, src_off, len); @@ -87,7 +87,7 @@ static void IRAM_ATTR test_read(int src_off, int dst_off, int len) TEST_ASSERT_EQUAL_INT(cmp_or_dump(dst_buf, dst_gold, sizeof(dst_buf)), 0); } -TEST_CASE("Test spi_flash_read", "[spi_flash]") +TEST_CASE("Test spi_flash_read", "[spi_flash][esp_flash]") { setup_tests(); #if CONFIG_SPI_FLASH_MINIMAL_TEST @@ -158,14 +158,16 @@ static void IRAM_ATTR test_write(int dst_off, int src_off, int len) fill(dst_gold + dst_off, src_off, len); } ESP_ERROR_CHECK(spi_flash_write(start + dst_off, src_buf + src_off, len)); + spi_flash_disable_interrupts_caches_and_other_cpu(); esp_rom_spiflash_result_t rc = esp_rom_spiflash_read(start, dst_buf, sizeof(dst_buf)); spi_flash_enable_interrupts_caches_and_other_cpu(); - TEST_ASSERT_EQUAL_INT(rc, ESP_ROM_SPIFLASH_RESULT_OK); + TEST_ASSERT_EQUAL_HEX(rc, ESP_ROM_SPIFLASH_RESULT_OK); + TEST_ASSERT_EQUAL_INT(cmp_or_dump(dst_buf, dst_gold, sizeof(dst_buf)), 0); } -TEST_CASE("Test spi_flash_write", "[spi_flash]") +TEST_CASE("Test spi_flash_write", "[spi_flash][esp_flash]") { setup_tests(); #if CONFIG_SPI_FLASH_MINIMAL_TEST diff --git a/components/spi_flash/test/test_spi_flash.c b/components/spi_flash/test/test_spi_flash.c index 7e3f2d228a..0010f86d83 100644 --- a/components/spi_flash/test/test_spi_flash.c +++ b/components/spi_flash/test/test_spi_flash.c @@ -124,7 +124,7 @@ static void read_task(void* varg) { vTaskDelete(NULL); } -TEST_CASE("spi flash functions can run along with IRAM interrupts", "[spi_flash]") +TEST_CASE("spi flash functions can run along with IRAM interrupts", "[spi_flash][esp_flash]") { const size_t size = 128; read_task_arg_t read_arg = { @@ -170,7 +170,7 @@ TEST_CASE("spi flash functions can run along with IRAM interrupts", "[spi_flash] #if portNUM_PROCESSORS > 1 -TEST_CASE("spi_flash deadlock with high priority busy-waiting task", "[spi_flash]") +TEST_CASE("spi_flash deadlock with high priority busy-waiting task", "[spi_flash][esp_flash]") { typedef struct { QueueHandle_t queue; diff --git a/components/spiffs/test_spiffs_host/sdkconfig/sdkconfig.h b/components/spiffs/test_spiffs_host/sdkconfig/sdkconfig.h index 44966c5581..5fd1979b19 100644 --- a/components/spiffs/test_spiffs_host/sdkconfig/sdkconfig.h +++ b/components/spiffs/test_spiffs_host/sdkconfig/sdkconfig.h @@ -17,3 +17,5 @@ #define CONFIG_PARTITION_TABLE_OFFSET 0x8000 #define CONFIG_ESPTOOLPY_FLASHSIZE "8MB" +//currently use the legacy implementation, since the stubs for new HAL are not done yet +#define CONFIG_SPI_FLASH_USE_LEGACY_IMPL diff --git a/components/wear_levelling/test_wl_host/sdkconfig/sdkconfig.h b/components/wear_levelling/test_wl_host/sdkconfig/sdkconfig.h index 0fe66cbbec..d630f1a8e4 100644 --- a/components/wear_levelling/test_wl_host/sdkconfig/sdkconfig.h +++ b/components/wear_levelling/test_wl_host/sdkconfig/sdkconfig.h @@ -4,3 +4,6 @@ #define CONFIG_LOG_DEFAULT_LEVEL 3 #define CONFIG_PARTITION_TABLE_OFFSET 0x8000 #define CONFIG_ESPTOOLPY_FLASHSIZE "8MB" +//currently use the legacy implementation, since the stubs for new HAL are not done yet +#define CONFIG_SPI_FLASH_USE_LEGACY_IMPL + From aebcbd98bf09521045348c7bf8be7898aaf05529 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Thu, 13 Jun 2019 15:59:11 +0300 Subject: [PATCH 071/486] ci: fix a duplicate job the CI. --- .gitlab-ci.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b771bd3011..08285f1d9c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1578,12 +1578,6 @@ UT_001_43: - ESP32_IDF - UT_T1_1 -UT_001_43: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - UT_001_44: <<: *unit_test_template tags: From f78eea97fe803875a4b0940ce50155cbb870f70b Mon Sep 17 00:00:00 2001 From: zhiweijian Date: Mon, 27 May 2019 21:43:43 +0800 Subject: [PATCH 072/486] Component/bt: add gattc and gatts coex example --- .../bluetooth/gattc_gatts_coex/CMakeLists.txt | 6 + examples/bluetooth/gattc_gatts_coex/Makefile | 10 + examples/bluetooth/gattc_gatts_coex/README.md | 14 + .../gattc_gatts_coex/main/CMakeLists.txt | 4 + .../gattc_gatts_coex/main/component.mk | 4 + .../gattc_gatts_coex/main/gattc_gatts_coex.c | 1028 +++++++++++++++++ .../gattc_gatts_coex/sdkconfig.defaults | 6 + 7 files changed, 1072 insertions(+) create mode 100644 examples/bluetooth/gattc_gatts_coex/CMakeLists.txt create mode 100644 examples/bluetooth/gattc_gatts_coex/Makefile create mode 100644 examples/bluetooth/gattc_gatts_coex/README.md create mode 100644 examples/bluetooth/gattc_gatts_coex/main/CMakeLists.txt create mode 100644 examples/bluetooth/gattc_gatts_coex/main/component.mk create mode 100644 examples/bluetooth/gattc_gatts_coex/main/gattc_gatts_coex.c create mode 100644 examples/bluetooth/gattc_gatts_coex/sdkconfig.defaults diff --git a/examples/bluetooth/gattc_gatts_coex/CMakeLists.txt b/examples/bluetooth/gattc_gatts_coex/CMakeLists.txt new file mode 100644 index 0000000000..f520a3ae27 --- /dev/null +++ b/examples/bluetooth/gattc_gatts_coex/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(gattc_gatts_coex) diff --git a/examples/bluetooth/gattc_gatts_coex/Makefile b/examples/bluetooth/gattc_gatts_coex/Makefile new file mode 100644 index 0000000000..e8b511866a --- /dev/null +++ b/examples/bluetooth/gattc_gatts_coex/Makefile @@ -0,0 +1,10 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := gattc_gatts_coex + +COMPONENT_ADD_INCLUDEDIRS := components/include + +include $(IDF_PATH)/make/project.mk diff --git a/examples/bluetooth/gattc_gatts_coex/README.md b/examples/bluetooth/gattc_gatts_coex/README.md new file mode 100644 index 0000000000..0fb1bf6ce1 --- /dev/null +++ b/examples/bluetooth/gattc_gatts_coex/README.md @@ -0,0 +1,14 @@ +ESP-IDF Gattc and Gatts Coexistence example +============================================== + +This example demonstrates the coexistence of gattc and gatts. + +This example creates a GATT service and starts ADV. The ADV name is `ESP_GATTS_DEMO`, then waits to be connected. At the same time, a gatt client is created, the ADV name is `ESP_GATTS_DEMO`, the device is connected, and the data is exchanged. If the device is not found within 120 seconds, the example will stop scanning. + +ESP-IDF also allows users to create a GATT service via an attribute table, rather than add attributes one by one. And it is recommended for users to use. For more information about this method, please refer to [gatt_server_service_table_demo](../gatt_server_service_table). + +To test this example, you can run the [gatt_client_demo](../gatt_client), which can scan for and connect to this example automatically, and run [gatt_server_demo](../gatt_server), Waiting to be connected. They will start exchanging data once the GATT client has enabled the notification function of the GATT server. + +Please check the [tutorial](tutorial/Gatt_Server_Example_Walkthrough.md) for more information about the gatts part of this example. +Please check the [tutorial](tutorial/Gatt_Client_Example_Walkthrough.md) for more information about the gattc part of this example. + diff --git a/examples/bluetooth/gattc_gatts_coex/main/CMakeLists.txt b/examples/bluetooth/gattc_gatts_coex/main/CMakeLists.txt new file mode 100644 index 0000000000..a3c8592c8d --- /dev/null +++ b/examples/bluetooth/gattc_gatts_coex/main/CMakeLists.txt @@ -0,0 +1,4 @@ +set(COMPONENT_SRCS "gattc_gatts_coex.c") +set(COMPONENT_ADD_INCLUDEDIRS ".") + +register_component() diff --git a/examples/bluetooth/gattc_gatts_coex/main/component.mk b/examples/bluetooth/gattc_gatts_coex/main/component.mk new file mode 100644 index 0000000000..a98f634eae --- /dev/null +++ b/examples/bluetooth/gattc_gatts_coex/main/component.mk @@ -0,0 +1,4 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/bluetooth/gattc_gatts_coex/main/gattc_gatts_coex.c b/examples/bluetooth/gattc_gatts_coex/main/gattc_gatts_coex.c new file mode 100644 index 0000000000..3e4989372c --- /dev/null +++ b/examples/bluetooth/gattc_gatts_coex/main/gattc_gatts_coex.c @@ -0,0 +1,1028 @@ +/* + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include +#include +#include "nvs.h" +#include "nvs_flash.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_bt.h" +#include "esp_gap_ble_api.h" +#include "esp_gattc_api.h" +#include "esp_gatt_defs.h" +#include "esp_bt_main.h" +#include "esp_gatt_common_api.h" +#include "esp_gatts_api.h" +#include "esp_bt_defs.h" +#include "esp_system.h" +#include "sdkconfig.h" + + +#define GATTS_SERVICE_UUID_TEST_A 0x00FF +#define GATTS_CHAR_UUID_TEST_A 0xFF01 +#define GATTS_NUM_HANDLE_TEST_A 4 + +#define GATTS_SERVICE_UUID_TEST_B 0x00EE +#define GATTS_CHAR_UUID_TEST_B 0xEE01 +#define GATTS_NUM_HANDLE_TEST_B 4 + +#define GATTS_DEMO_CHAR_VAL_LEN_MAX 0x40 +#define PREPARE_BUF_MAX_SIZE 1024 + +#define adv_config_flag (1 << 0) +#define scan_rsp_config_flag (1 << 1) + +#define GATTS_PROFILE_NUM 2 +#define GATTS_PROFILE_A_APP_ID 0 +#define GATTS_PROFILE_B_APP_ID 1 +#define GATTC_PROFILE_NUM 1 +#define GATTC_PROFILE_C_APP_ID 0 +// gattc +#define REMOTE_SERVICE_UUID 0x00FF +#define REMOTE_NOTIFY_CHAR_UUID 0xFF01 +#define INVALID_HANDLE 0 +#define GATTS_ADV_NAME "ESP_GATTS_DEMO" +#define COEX_TAG "GATTC_GATTS_COEX" +#define NOTIFY_ENABLE 0x0001 +#define INDICATE_ENABLE 0x0002 +#define NOTIFY_INDICATE_DISABLE 0x0000 + +static const char remote_device_name[] = "ESP_GATTS_DEMO"; + +typedef struct { + uint8_t *prepare_buf; + int prepare_len; +} prepare_type_env_t; + +struct gatts_profile_inst { + esp_gatts_cb_t gatts_cb; + uint16_t gatts_if; + uint16_t app_id; + uint16_t conn_id; + uint16_t service_handle; + esp_gatt_srvc_id_t service_id; + uint16_t char_handle; + esp_bt_uuid_t char_uuid; + esp_gatt_perm_t perm; + esp_gatt_char_prop_t property; + uint16_t descr_handle; + esp_bt_uuid_t descr_uuid; +}; + +struct gattc_profile_inst { + esp_gattc_cb_t gattc_cb; + uint16_t gattc_if; + uint16_t app_id; + uint16_t conn_id; + uint16_t service_start_handle; + uint16_t service_end_handle; + uint16_t char_handle; + esp_bd_addr_t remote_bda; +}; + +///Declare the static function +static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); +static void gatts_profile_b_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); +/* Declare static functions */ +static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param); +static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param); +static void example_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param); +static void example_exec_write_event_env(prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param); + +static esp_gatt_char_prop_t a_property = 0; +static esp_gatt_char_prop_t b_property = 0; +static prepare_type_env_t a_prepare_write_env; +static prepare_type_env_t b_prepare_write_env; +static uint8_t adv_config_done = 0; +static uint8_t char1_str[] = {0x11, 0x22, 0x33}; +static bool connect = false; +static bool get_server = false; +static esp_gattc_char_elem_t *char_elem_result = NULL; +static esp_gattc_descr_elem_t *descr_elem_result = NULL; + +esp_attr_value_t gatts_demo_char1_val = { + .attr_max_len = GATTS_DEMO_CHAR_VAL_LEN_MAX, + .attr_len = sizeof(char1_str), + .attr_value = char1_str, +}; + +static uint8_t service_uuid128[32] = { + /* LSB <--------------------------------------------------------------------------------> MSB */ + //first uuid, 16bit, [12],[13] is the value + 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAB, 0xCD, 0x00, 0x00, + //second uuid, 32bit, [12], [13], [14], [15] is the value + 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAB, 0xCD, 0xAB, 0xCD, +}; + +static esp_ble_adv_data_t adv_data = { + .set_scan_rsp = false, + .include_name = true, + .include_txpower = true, + .min_interval = 0x20, + .max_interval = 0x40, + .appearance = 0x00, + .manufacturer_len = 0, + .p_manufacturer_data = NULL, + .service_data_len = 0, + .p_service_data = NULL, + .service_uuid_len = 32, + .p_service_uuid = service_uuid128, + .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT), +}; + +// scan response data +static esp_ble_adv_data_t scan_rsp_data = { + .set_scan_rsp = true, + .include_name = true, + .include_txpower = true, + .min_interval = 0x0006, + .max_interval = 0x0010, + .appearance = 0x00, + .manufacturer_len = 0, + .p_manufacturer_data = NULL, + .service_data_len = 0, + .p_service_data = NULL, + .service_uuid_len = 0, + .p_service_uuid = NULL, + .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT), +}; + +static esp_ble_adv_params_t adv_params = { + .adv_int_min = 0x20, + .adv_int_max = 0x40, + .adv_type = ADV_TYPE_IND, + .own_addr_type = BLE_ADDR_TYPE_PUBLIC, + .channel_map = ADV_CHNL_ALL, + .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, +}; + +/* One gatt-based profile one app_id and one gatts_if, this array will store the gatts_if returned by ESP_GATTS_REG_EVT */ +static struct gatts_profile_inst gatts_profile_tab[GATTS_PROFILE_NUM] = { + [GATTS_PROFILE_A_APP_ID] = { + .gatts_cb = gatts_profile_a_event_handler, + .gatts_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */ + }, + [GATTS_PROFILE_B_APP_ID] = { + .gatts_cb = gatts_profile_b_event_handler, /* This demo does not implement, similar as profile A */ + .gatts_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */ + }, +}; + +static esp_bt_uuid_t remote_filter_service_uuid = { + .len = ESP_UUID_LEN_16, + .uuid = {.uuid16 = REMOTE_SERVICE_UUID,}, +}; + +static esp_bt_uuid_t remote_filter_char_uuid = { + .len = ESP_UUID_LEN_16, + .uuid = {.uuid16 = REMOTE_NOTIFY_CHAR_UUID,}, +}; + +static esp_bt_uuid_t notify_descr_uuid = { + .len = ESP_UUID_LEN_16, + .uuid = {.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG,}, +}; + +static esp_ble_scan_params_t ble_scan_params = { + .scan_type = BLE_SCAN_TYPE_ACTIVE, + .own_addr_type = BLE_ADDR_TYPE_PUBLIC, + .scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL, + .scan_interval = 0x50, + .scan_window = 0x30, + .scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE +}; + +/* One gatt-based profile one app_id and one gattc_if, this array will store the gattc_if returned by ESP_GATTS_REG_EVT */ +static struct gattc_profile_inst gattc_profile_tab[GATTC_PROFILE_NUM] = { + [GATTC_PROFILE_C_APP_ID] = { + .gattc_cb = gattc_profile_event_handler, + .gattc_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */ + }, +}; + +static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) +{ + uint8_t *adv_name = NULL; + uint8_t adv_name_len = 0; + + switch (event) { + + case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: + adv_config_done &= (~adv_config_flag); + if (adv_config_done == 0) { + esp_ble_gap_start_advertising(&adv_params); + } + break; + case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: + adv_config_done &= (~scan_rsp_config_flag); + if (adv_config_done == 0) { + esp_ble_gap_start_advertising(&adv_params); + } + break; + + case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: + //advertising start complete event to indicate advertising start successfully or failed + if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { + ESP_LOGE(COEX_TAG, "Advertising start failed\n"); + } + ESP_LOGI(COEX_TAG, "Advertising start successfully\n"); + break; + case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: + if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) { + ESP_LOGE(COEX_TAG, "Advertising stop failed\n"); + } else { + ESP_LOGI(COEX_TAG, "Stop adv successfully\n"); + } + break; + case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT: + ESP_LOGI(COEX_TAG, "update connection params status = %d, min_int = %d, max_int = %d,conn_int = %d,latency = %d, timeout = %d\n", + param->update_conn_params.status, + param->update_conn_params.min_int, + param->update_conn_params.max_int, + param->update_conn_params.conn_int, + param->update_conn_params.latency, + param->update_conn_params.timeout); + break; + case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT: + if (param->scan_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) { + ESP_LOGE(COEX_TAG, "scan stop failed, error status = %x\n", param->scan_stop_cmpl.status); + break; + } + ESP_LOGI(COEX_TAG, "ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT, stop scan successfully\n"); + break; + case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: { + ESP_LOGI(COEX_TAG, "ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT, set scan sparameters complete\n"); + //the unit of the duration is second + uint32_t duration = 120; + esp_ble_gap_start_scanning(duration); + break; + } + case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: + if (param->scan_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { + ESP_LOGE(COEX_TAG, "scan start failed, error status = %x\n", param->scan_start_cmpl.status); + break; + } + ESP_LOGI(COEX_TAG, "ESP_GAP_BLE_SCAN_START_COMPLETE_EVT, scan start success\n"); + break; + case ESP_GAP_BLE_SCAN_RESULT_EVT: { + esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param; + switch (scan_result->scan_rst.search_evt) { + case ESP_GAP_SEARCH_INQ_RES_EVT: + adv_name = esp_ble_resolve_adv_data(scan_result->scan_rst.ble_adv, + ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len); + if (adv_name != NULL) { + if (strlen(remote_device_name) == adv_name_len && strncmp((char *)adv_name, remote_device_name, adv_name_len) == 0) { + if (connect == false) { + connect = true; + ESP_LOGI(COEX_TAG, "connect to the remote device %s\n", remote_device_name); + esp_ble_gap_stop_scanning(); + esp_ble_gattc_open(gattc_profile_tab[GATTC_PROFILE_C_APP_ID].gattc_if, scan_result->scan_rst.bda, scan_result->scan_rst.ble_addr_type, true); + } + } + } + break; + case ESP_GAP_SEARCH_INQ_CMPL_EVT: + ESP_LOGI(COEX_TAG, "ESP_GAP_SEARCH_INQ_CMPL_EVT, scan stop\n"); + break; + default: + break; + } + break; + } + default: + break; + } +} + +static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) +{ + esp_ble_gattc_cb_param_t *p_data = (esp_ble_gattc_cb_param_t *)param; + + switch (event) { + case ESP_GATTC_REG_EVT: + ESP_LOGI(COEX_TAG, "REG_EVT\n"); + esp_err_t scan_ret = esp_ble_gap_set_scan_params(&ble_scan_params); + if (scan_ret) { + ESP_LOGE(COEX_TAG, "set scan params error, error code = %x", scan_ret); + } + break; + case ESP_GATTC_CONNECT_EVT: { + ESP_LOGI(COEX_TAG, "ESP_GATTC_CONNECT_EVT conn_id %d, if %d\n", p_data->connect.conn_id, gattc_if); + gattc_profile_tab[GATTC_PROFILE_C_APP_ID].conn_id = p_data->connect.conn_id; + memcpy(gattc_profile_tab[GATTC_PROFILE_C_APP_ID].remote_bda, p_data->connect.remote_bda, sizeof(esp_bd_addr_t)); + ESP_LOGI(COEX_TAG, "REMOTE BDA:"); + esp_log_buffer_hex(COEX_TAG, gattc_profile_tab[GATTC_PROFILE_C_APP_ID].remote_bda, sizeof(esp_bd_addr_t)); + esp_err_t mtu_ret = esp_ble_gattc_send_mtu_req (gattc_if, p_data->connect.conn_id); + if (mtu_ret) { + ESP_LOGE(COEX_TAG, "config MTU error, error code = %x\n", mtu_ret); + } + break; + } + case ESP_GATTC_OPEN_EVT: + if (param->open.status != ESP_GATT_OK) { + ESP_LOGE(COEX_TAG, "open failed, status %d\n", p_data->open.status); + break; + } + ESP_LOGI(COEX_TAG, "open success\n"); + break; + case ESP_GATTC_DIS_SRVC_CMPL_EVT: + if (param->dis_srvc_cmpl.status != ESP_GATT_OK) { + ESP_LOGE(COEX_TAG, "discover service failed, status %d\n", param->dis_srvc_cmpl.status); + break; + } + ESP_LOGI(COEX_TAG, "discover service complete conn_id %d\n", param->dis_srvc_cmpl.conn_id); + esp_ble_gattc_search_service(gattc_if, param->cfg_mtu.conn_id, &remote_filter_service_uuid); + break; + case ESP_GATTC_CFG_MTU_EVT: + if (param->cfg_mtu.status != ESP_GATT_OK) { + ESP_LOGE(COEX_TAG,"config mtu failed, error status = %x\n", param->cfg_mtu.status); + } + ESP_LOGI(COEX_TAG, "ESP_GATTC_CFG_MTU_EVT, Status %d, MTU %d, conn_id %d\n", param->cfg_mtu.status, param->cfg_mtu.mtu, param->cfg_mtu.conn_id); + break; + case ESP_GATTC_SEARCH_RES_EVT: { + ESP_LOGI(COEX_TAG, "SEARCH RES: conn_id = %x is primary service %d\n", p_data->search_res.conn_id, p_data->search_res.is_primary); + ESP_LOGI(COEX_TAG, "start handle %d end handle %d current handle value %d\n", p_data->search_res.start_handle, p_data->search_res.end_handle, p_data->search_res.srvc_id.inst_id); + if (p_data->search_res.srvc_id.uuid.len == ESP_UUID_LEN_16 && p_data->search_res.srvc_id.uuid.uuid.uuid16 == REMOTE_SERVICE_UUID) { + ESP_LOGI(COEX_TAG, "service found\n"); + get_server = true; + gattc_profile_tab[GATTC_PROFILE_C_APP_ID].service_start_handle = p_data->search_res.start_handle; + gattc_profile_tab[GATTC_PROFILE_C_APP_ID].service_end_handle = p_data->search_res.end_handle; + ESP_LOGI(COEX_TAG, "UUID16: %x\n", p_data->search_res.srvc_id.uuid.uuid.uuid16); + } + break; + } + case ESP_GATTC_SEARCH_CMPL_EVT: + if (p_data->search_cmpl.status != ESP_GATT_OK) { + ESP_LOGE(COEX_TAG, "search service failed, error status = %x\n", p_data->search_cmpl.status); + break; + } + if(p_data->search_cmpl.searched_service_source == ESP_GATT_SERVICE_FROM_REMOTE_DEVICE) { + ESP_LOGI(COEX_TAG, "Get service information from remote device\n"); + } else if (p_data->search_cmpl.searched_service_source == ESP_GATT_SERVICE_FROM_NVS_FLASH) { + ESP_LOGI(COEX_TAG, "Get service information from flash\n"); + } else { + ESP_LOGI(COEX_TAG, "unknown service source\n"); + } + ESP_LOGI(COEX_TAG, "ESP_GATTC_SEARCH_CMPL_EVT\n"); + if (get_server) { + uint16_t count = 0; + esp_gatt_status_t status = esp_ble_gattc_get_attr_count( gattc_if, + p_data->search_cmpl.conn_id, + ESP_GATT_DB_CHARACTERISTIC, + gattc_profile_tab[GATTC_PROFILE_C_APP_ID].service_start_handle, + gattc_profile_tab[GATTC_PROFILE_C_APP_ID].service_end_handle, + INVALID_HANDLE, + &count); + if (status != ESP_GATT_OK) { + ESP_LOGE(COEX_TAG, "esp_ble_gattc_get_attr_count error\n"); + } + + if (count > 0) { + char_elem_result = (esp_gattc_char_elem_t *)malloc(sizeof(esp_gattc_char_elem_t) * count); + if (!char_elem_result) { + ESP_LOGE(COEX_TAG, "gattc no mem\n"); + }else { + status = esp_ble_gattc_get_char_by_uuid( gattc_if, + p_data->search_cmpl.conn_id, + gattc_profile_tab[GATTC_PROFILE_C_APP_ID].service_start_handle, + gattc_profile_tab[GATTC_PROFILE_C_APP_ID].service_end_handle, + remote_filter_char_uuid, + char_elem_result, + &count); + if (status != ESP_GATT_OK) { + ESP_LOGE(COEX_TAG, "esp_ble_gattc_get_char_by_uuid error\n"); + } + + /* Every service have only one char in our 'ESP_GATTS_DEMO' demo, so we used first 'char_elem_result' */ + if (count > 0 && (char_elem_result[0].properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY)) { + gattc_profile_tab[GATTC_PROFILE_C_APP_ID].char_handle = char_elem_result[0].char_handle; + esp_ble_gattc_register_for_notify (gattc_if, gattc_profile_tab[GATTC_PROFILE_C_APP_ID].remote_bda, char_elem_result[0].char_handle); + } + } + /* free char_elem_result */ + free(char_elem_result); + } else { + ESP_LOGE(COEX_TAG, "no char found\n"); + } + } + break; + case ESP_GATTC_REG_FOR_NOTIFY_EVT: { + ESP_LOGI(COEX_TAG, "ESP_GATTC_REG_FOR_NOTIFY_EVT\n"); + if (p_data->reg_for_notify.status != ESP_GATT_OK) { + ESP_LOGE(COEX_TAG, "REG FOR NOTIFY failed: error status = %d\n", p_data->reg_for_notify.status); + } else { + uint16_t count = 0; + uint16_t notify_en = 1; + esp_gatt_status_t ret_status = esp_ble_gattc_get_attr_count( gattc_if, + gattc_profile_tab[GATTC_PROFILE_C_APP_ID].conn_id, + ESP_GATT_DB_DESCRIPTOR, + gattc_profile_tab[GATTC_PROFILE_C_APP_ID].service_start_handle, + gattc_profile_tab[GATTC_PROFILE_C_APP_ID].service_end_handle, + gattc_profile_tab[GATTC_PROFILE_C_APP_ID].char_handle, + &count); + if (ret_status != ESP_GATT_OK) { + ESP_LOGE(COEX_TAG, "esp_ble_gattc_get_attr_count error\n"); + } + if (count > 0) { + descr_elem_result = malloc(sizeof(esp_gattc_descr_elem_t) * count); + if (!descr_elem_result) { + ESP_LOGE(COEX_TAG, "malloc error, gattc no mem\n"); + } else { + ret_status = esp_ble_gattc_get_descr_by_char_handle( gattc_if, + gattc_profile_tab[GATTC_PROFILE_C_APP_ID].conn_id, + p_data->reg_for_notify.handle, + notify_descr_uuid, + descr_elem_result, + &count); + if (ret_status != ESP_GATT_OK) { + ESP_LOGE(COEX_TAG, "esp_ble_gattc_get_descr_by_char_handle error\n"); + } + /* Every char has only one descriptor in our 'ESP_GATTS_DEMO' demo, so we used first 'descr_elem_result' */ + if (count > 0 && descr_elem_result[0].uuid.len == ESP_UUID_LEN_16 && descr_elem_result[0].uuid.uuid.uuid16 == ESP_GATT_UUID_CHAR_CLIENT_CONFIG) { + ret_status = esp_ble_gattc_write_char_descr( gattc_if, + gattc_profile_tab[GATTC_PROFILE_C_APP_ID].conn_id, + descr_elem_result[0].handle, + sizeof(notify_en), + (uint8_t *)¬ify_en, + ESP_GATT_WRITE_TYPE_RSP, + ESP_GATT_AUTH_REQ_NONE); + } + + if (ret_status != ESP_GATT_OK) { + ESP_LOGE(COEX_TAG, "esp_ble_gattc_write_char_descr error\n"); + } + + /* free descr_elem_result */ + free(descr_elem_result); + } + } else { + ESP_LOGE(COEX_TAG, "decsr not found\n"); + } + + } + break; + } + case ESP_GATTC_NOTIFY_EVT: + if (p_data->notify.is_notify) { + ESP_LOGI(COEX_TAG, "ESP_GATTC_NOTIFY_EVT, receive notify value:"); + } else { + ESP_LOGI(COEX_TAG, "ESP_GATTC_NOTIFY_EVT, receive indicate value:"); + } + esp_log_buffer_hex(COEX_TAG, p_data->notify.value, p_data->notify.value_len); + break; + case ESP_GATTC_WRITE_DESCR_EVT: + if (p_data->write.status != ESP_GATT_OK) { + ESP_LOGE(COEX_TAG, "write descr failed, error status = %x\n", p_data->write.status); + break; + } + ESP_LOGI(COEX_TAG, "write descr success \n"); + uint8_t write_char_data[35]; + for (int i = 0; i < sizeof(write_char_data); ++ i) { + write_char_data[i] = i % 256; + } + esp_ble_gattc_write_char( gattc_if, + gattc_profile_tab[GATTC_PROFILE_C_APP_ID].conn_id, + gattc_profile_tab[GATTC_PROFILE_C_APP_ID].char_handle, + sizeof(write_char_data), + write_char_data, + ESP_GATT_WRITE_TYPE_RSP, + ESP_GATT_AUTH_REQ_NONE); + break; + case ESP_GATTC_SRVC_CHG_EVT: { + esp_bd_addr_t bda; + memcpy(bda, p_data->srvc_chg.remote_bda, sizeof(esp_bd_addr_t)); + ESP_LOGI(COEX_TAG, "ESP_GATTC_SRVC_CHG_EVT, bd_addr:"); + esp_log_buffer_hex(COEX_TAG, bda, sizeof(esp_bd_addr_t)); + break; + } + case ESP_GATTC_WRITE_CHAR_EVT: + if (p_data->write.status != ESP_GATT_OK) { + ESP_LOGE(COEX_TAG, "write char failed, error status = %x\n", p_data->write.status); + break; + } + ESP_LOGI(COEX_TAG, "write char success \n"); + break; + case ESP_GATTC_DISCONNECT_EVT: { + connect = false; + get_server = false; + ESP_LOGI(COEX_TAG, "ESP_GATTC_DISCONNECT_EVT, reason = %d\n", p_data->disconnect.reason); + break; + } + default: + break; + } +} + +static void example_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param) { + esp_gatt_status_t status = ESP_GATT_OK; + if (param->write.need_rsp) { + if (param->write.is_prep) { + if (prepare_write_env->prepare_buf == NULL) { + prepare_write_env->prepare_buf = (uint8_t *)malloc(PREPARE_BUF_MAX_SIZE*sizeof(uint8_t)); + prepare_write_env->prepare_len = 0; + if (prepare_write_env->prepare_buf == NULL) { + ESP_LOGE(COEX_TAG, "Gatt_server prep no mem\n"); + status = ESP_GATT_NO_RESOURCES; + } + } else { + if(param->write.offset > PREPARE_BUF_MAX_SIZE) { + status = ESP_GATT_INVALID_OFFSET; + } else if ((param->write.offset + param->write.len) > PREPARE_BUF_MAX_SIZE) { + status = ESP_GATT_INVALID_ATTR_LEN; + } + } + + esp_gatt_rsp_t *gatt_rsp = (esp_gatt_rsp_t *)malloc(sizeof(esp_gatt_rsp_t)); + gatt_rsp->attr_value.len = param->write.len; + gatt_rsp->attr_value.handle = param->write.handle; + gatt_rsp->attr_value.offset = param->write.offset; + gatt_rsp->attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE; + memcpy(gatt_rsp->attr_value.value, param->write.value, param->write.len); + esp_err_t response_err = esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, status, gatt_rsp); + if (response_err != ESP_OK) { + ESP_LOGE(COEX_TAG, "Send response error\n"); + } + free(gatt_rsp); + if (status != ESP_GATT_OK) { + return; + } + memcpy(prepare_write_env->prepare_buf + param->write.offset, + param->write.value, + param->write.len); + prepare_write_env->prepare_len += param->write.len; + + } else { + esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, status, NULL); + } + } +} + +static void example_exec_write_event_env(prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param) { + if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) { + esp_log_buffer_hex(COEX_TAG, prepare_write_env->prepare_buf, prepare_write_env->prepare_len); + } else { + ESP_LOGI(COEX_TAG,"ESP_GATT_PREP_WRITE_CANCEL\n"); + } + if (prepare_write_env->prepare_buf) { + free(prepare_write_env->prepare_buf); + prepare_write_env->prepare_buf = NULL; + } + prepare_write_env->prepare_len = 0; +} + +static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { + switch (event) { + case ESP_GATTS_REG_EVT: + ESP_LOGI(COEX_TAG, "REGISTER_APP_EVT, status %d, app_id %d\n", param->reg.status, param->reg.app_id); + gatts_profile_tab[GATTS_PROFILE_A_APP_ID].service_id.is_primary = true; + gatts_profile_tab[GATTS_PROFILE_A_APP_ID].service_id.id.inst_id = 0x00; + gatts_profile_tab[GATTS_PROFILE_A_APP_ID].service_id.id.uuid.len = ESP_UUID_LEN_16; + gatts_profile_tab[GATTS_PROFILE_A_APP_ID].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_TEST_A; + + esp_err_t set_dev_name_ret = esp_ble_gap_set_device_name(GATTS_ADV_NAME); + if (set_dev_name_ret) { + ESP_LOGE(COEX_TAG, "set device name failed, error code = %x\n", set_dev_name_ret); + } +#ifdef CONFIG_SET_RAW_ADV_DATA + esp_err_t raw_adv_ret = esp_ble_gap_config_adv_data_raw(raw_adv_data, sizeof(raw_adv_data)); + if (raw_adv_ret) { + ESP_LOGE(COEX_TAG, "config raw adv data failed, error code = %x \n", raw_adv_ret); + } + adv_config_done |= adv_config_flag; + esp_err_t raw_scan_ret = esp_ble_gap_config_scan_rsp_data_raw(raw_scan_rsp_data, sizeof(raw_scan_rsp_data)); + if (raw_scan_ret) { + ESP_LOGE(COEX_TAG, "config raw scan rsp data failed, error code = %x\n", raw_scan_ret); + } + adv_config_done |= scan_rsp_config_flag; +#else + //config adv data + esp_err_t ret = esp_ble_gap_config_adv_data(&adv_data); + if (ret) { + ESP_LOGE(COEX_TAG, "config adv data failed, error code = %x\n", ret); + } + adv_config_done |= adv_config_flag; + //config scan response data + ret = esp_ble_gap_config_adv_data(&scan_rsp_data); + if (ret) { + ESP_LOGE(COEX_TAG, "config scan response data failed, error code = %x\n", ret); + } + adv_config_done |= scan_rsp_config_flag; + +#endif + esp_ble_gatts_create_service(gatts_if, &gatts_profile_tab[GATTS_PROFILE_A_APP_ID].service_id, GATTS_NUM_HANDLE_TEST_A); + break; + case ESP_GATTS_READ_EVT: { + ESP_LOGI(COEX_TAG, "GATT_READ_EVT, conn_id %d, trans_id %d, handle %d\n", param->read.conn_id, param->read.trans_id, param->read.handle); + esp_gatt_rsp_t rsp; + memset(&rsp, 0, sizeof(esp_gatt_rsp_t)); + rsp.attr_value.handle = param->read.handle; + rsp.attr_value.len = 4; + rsp.attr_value.value[0] = 0xde; + rsp.attr_value.value[1] = 0xed; + rsp.attr_value.value[2] = 0xbe; + rsp.attr_value.value[3] = 0xef; + esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, + ESP_GATT_OK, &rsp); + break; + } + case ESP_GATTS_WRITE_EVT: { + ESP_LOGI(COEX_TAG, "GATT_WRITE_EVT, conn_id %d, trans_id %d, handle %d\n", param->write.conn_id, param->write.trans_id, param->write.handle); + if (!param->write.is_prep) { + ESP_LOGI(COEX_TAG, "GATT_WRITE_EVT, value len %d, value :", param->write.len); + esp_log_buffer_hex(COEX_TAG, param->write.value, param->write.len); + if (gatts_profile_tab[GATTS_PROFILE_A_APP_ID].descr_handle == param->write.handle && param->write.len == 2) { + uint16_t descr_value = param->write.value[1]<<8 | param->write.value[0]; + if (descr_value == NOTIFY_ENABLE) { + if (a_property & ESP_GATT_CHAR_PROP_BIT_NOTIFY) { + ESP_LOGI(COEX_TAG, "notify enable\n"); + uint8_t notify_data[15]; + for (int i = 0; i < sizeof(notify_data); ++ i) { + notify_data[i] = i%0xff; + } + //the size of notify_data[] need less than MTU size + esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, gatts_profile_tab[GATTS_PROFILE_A_APP_ID].char_handle, + sizeof(notify_data), notify_data, false); + } + } else if (descr_value == INDICATE_ENABLE) { + if (a_property & ESP_GATT_CHAR_PROP_BIT_INDICATE) { + ESP_LOGI(COEX_TAG, "indicate enable\n"); + uint8_t indicate_data[15]; + for (int i = 0; i < sizeof(indicate_data); ++ i) { + indicate_data[i] = i%0xff; + } + //the size of indicate_data[] need less than MTU size + esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, gatts_profile_tab[GATTS_PROFILE_A_APP_ID].char_handle, + sizeof(indicate_data), indicate_data, true); + } + } else if (descr_value == NOTIFY_INDICATE_DISABLE) { + ESP_LOGI(COEX_TAG, "notify/indicate disable \n"); + } else { + ESP_LOGE(COEX_TAG, "unknown descr value\n"); + esp_log_buffer_hex(COEX_TAG, param->write.value, param->write.len); + } + + } + } + example_write_event_env(gatts_if, &a_prepare_write_env, param); + break; + } + case ESP_GATTS_EXEC_WRITE_EVT: + ESP_LOGI(COEX_TAG,"ESP_GATTS_EXEC_WRITE_EVT\n"); + esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL); + example_exec_write_event_env(&a_prepare_write_env, param); + break; + case ESP_GATTS_MTU_EVT: + ESP_LOGI(COEX_TAG, "ESP_GATTS_MTU_EVT, MTU %d\n", param->mtu.mtu); + break; + case ESP_GATTS_CREATE_EVT: + ESP_LOGI(COEX_TAG, "CREATE_SERVICE_EVT, status %d, service_handle %d\n", param->create.status, param->create.service_handle); + gatts_profile_tab[GATTS_PROFILE_A_APP_ID].service_handle = param->create.service_handle; + gatts_profile_tab[GATTS_PROFILE_A_APP_ID].char_uuid.len = ESP_UUID_LEN_16; + gatts_profile_tab[GATTS_PROFILE_A_APP_ID].char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_TEST_A; + + esp_ble_gatts_start_service(gatts_profile_tab[GATTS_PROFILE_A_APP_ID].service_handle); + a_property = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY; + esp_err_t add_char_ret = esp_ble_gatts_add_char(gatts_profile_tab[GATTS_PROFILE_A_APP_ID].service_handle, &gatts_profile_tab[GATTS_PROFILE_A_APP_ID].char_uuid, + ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, + a_property, + &gatts_demo_char1_val, NULL); + if (add_char_ret) { + ESP_LOGE(COEX_TAG, "add char failed, error code =%x\n",add_char_ret); + } + break; + case ESP_GATTS_ADD_CHAR_EVT: { + ESP_LOGI(COEX_TAG, "ADD_CHAR_EVT, status %d, attr_handle %d, service_handle %d\n", + param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle); + gatts_profile_tab[GATTS_PROFILE_A_APP_ID].char_handle = param->add_char.attr_handle; + gatts_profile_tab[GATTS_PROFILE_A_APP_ID].descr_uuid.len = ESP_UUID_LEN_16; + gatts_profile_tab[GATTS_PROFILE_A_APP_ID].descr_uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG; + + esp_err_t add_descr_ret = esp_ble_gatts_add_char_descr(gatts_profile_tab[GATTS_PROFILE_A_APP_ID].service_handle, &gatts_profile_tab[GATTS_PROFILE_A_APP_ID].descr_uuid, + ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, NULL, NULL); + if (add_descr_ret) { + ESP_LOGE(COEX_TAG, "add char descr failed, error code =%x\n", add_descr_ret); + } + break; + } + case ESP_GATTS_ADD_CHAR_DESCR_EVT: + gatts_profile_tab[GATTS_PROFILE_A_APP_ID].descr_handle = param->add_char_descr.attr_handle; + ESP_LOGI(COEX_TAG, "ADD_DESCR_EVT, status %d, attr_handle %d, service_handle %d\n", + param->add_char_descr.status, param->add_char_descr.attr_handle, param->add_char_descr.service_handle); + break; + case ESP_GATTS_START_EVT: + ESP_LOGI(COEX_TAG, "SERVICE_START_EVT, status %d, service_handle %d\n", + param->start.status, param->start.service_handle); + break; + case ESP_GATTS_CONNECT_EVT: { + + ESP_LOGI(COEX_TAG, "ESP_GATTS_CONNECT_EVT, conn_id %d, remote %02x:%02x:%02x:%02x:%02x:%02x\n", + param->connect.conn_id, + param->connect.remote_bda[0], param->connect.remote_bda[1], param->connect.remote_bda[2], + param->connect.remote_bda[3], param->connect.remote_bda[4], param->connect.remote_bda[5]); + gatts_profile_tab[GATTS_PROFILE_A_APP_ID].conn_id = param->connect.conn_id; + break; + } + case ESP_GATTS_DISCONNECT_EVT: + ESP_LOGI(COEX_TAG, "ESP_GATTS_DISCONNECT_EVT, disconnect reason 0x%x\n", param->disconnect.reason); + esp_ble_gap_start_advertising(&adv_params); + break; + case ESP_GATTS_CONF_EVT: + ESP_LOGI(COEX_TAG, "ESP_GATTS_CONF_EVT, status %d attr_handle %d\n", param->conf.status, param->conf.handle); + if (param->conf.status != ESP_GATT_OK) { + esp_log_buffer_hex(COEX_TAG, param->conf.value, param->conf.len); + } + break; + case ESP_GATTS_OPEN_EVT: + default: + break; + } +} + +static void gatts_profile_b_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { + switch (event) { + case ESP_GATTS_REG_EVT: + ESP_LOGI(COEX_TAG, "REGISTER_APP_EVT, status %d, app_id %d\n", param->reg.status, param->reg.app_id); + gatts_profile_tab[GATTS_PROFILE_B_APP_ID].service_id.is_primary = true; + gatts_profile_tab[GATTS_PROFILE_B_APP_ID].service_id.id.inst_id = 0x00; + gatts_profile_tab[GATTS_PROFILE_B_APP_ID].service_id.id.uuid.len = ESP_UUID_LEN_16; + gatts_profile_tab[GATTS_PROFILE_B_APP_ID].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_TEST_B; + + esp_ble_gatts_create_service(gatts_if, &gatts_profile_tab[GATTS_PROFILE_B_APP_ID].service_id, GATTS_NUM_HANDLE_TEST_B); + break; + case ESP_GATTS_READ_EVT: { + ESP_LOGI(COEX_TAG, "GATT_READ_EVT, conn_id %d, trans_id %d, handle %d\n", param->read.conn_id, param->read.trans_id, param->read.handle); + esp_gatt_rsp_t rsp; + memset(&rsp, 0, sizeof(esp_gatt_rsp_t)); + rsp.attr_value.handle = param->read.handle; + rsp.attr_value.len = 4; + rsp.attr_value.value[0] = 0xde; + rsp.attr_value.value[1] = 0xed; + rsp.attr_value.value[2] = 0xbe; + rsp.attr_value.value[3] = 0xef; + esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, + ESP_GATT_OK, &rsp); + break; + } + case ESP_GATTS_WRITE_EVT: { + ESP_LOGI(COEX_TAG, "GATT_WRITE_EVT, conn_id %d, trans_id %d, handle %d\n", param->write.conn_id, param->write.trans_id, param->write.handle); + if (!param->write.is_prep) { + ESP_LOGI(COEX_TAG, "GATT_WRITE_EVT, value len %d, value :", param->write.len); + esp_log_buffer_hex(COEX_TAG, param->write.value, param->write.len); + if (gatts_profile_tab[GATTS_PROFILE_B_APP_ID].descr_handle == param->write.handle && param->write.len == 2) { + uint16_t descr_value= param->write.value[1]<<8 | param->write.value[0]; + if (descr_value == NOTIFY_ENABLE) { + if (b_property & ESP_GATT_CHAR_PROP_BIT_NOTIFY) { + ESP_LOGI(COEX_TAG, "notify enable\n"); + uint8_t notify_data[15]; + for (int i = 0; i < sizeof(notify_data); ++ i) { + notify_data[i] = i%0xff; + } + //the size of notify_data[] need less than MTU size + esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, gatts_profile_tab[GATTS_PROFILE_B_APP_ID].char_handle, + sizeof(notify_data), notify_data, false); + } + } else if (descr_value == INDICATE_ENABLE) { + if (b_property & ESP_GATT_CHAR_PROP_BIT_INDICATE) { + ESP_LOGI(COEX_TAG, "indicate enable\n"); + uint8_t indicate_data[15]; + for (int i = 0; i < sizeof(indicate_data); ++ i) { + indicate_data[i] = i%0xff; + } + //the size of indicate_data[] need less than MTU size + esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, gatts_profile_tab[GATTS_PROFILE_B_APP_ID].char_handle, + sizeof(indicate_data), indicate_data, true); + } + } else if (descr_value == NOTIFY_INDICATE_DISABLE) { + ESP_LOGI(COEX_TAG, "notify/indicate disable \n"); + } else { + ESP_LOGE(COEX_TAG, "unknown value\n"); + } + + } + } + example_write_event_env(gatts_if, &b_prepare_write_env, param); + break; + } + case ESP_GATTS_EXEC_WRITE_EVT: + ESP_LOGI(COEX_TAG,"ESP_GATTS_EXEC_WRITE_EVT\n"); + esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL); + example_exec_write_event_env(&b_prepare_write_env, param); + break; + case ESP_GATTS_MTU_EVT: + ESP_LOGI(COEX_TAG, "ESP_GATTS_MTU_EVT, MTU %d\n", param->mtu.mtu); + break; + case ESP_GATTS_UNREG_EVT: + break; + case ESP_GATTS_CREATE_EVT: + ESP_LOGI(COEX_TAG, "CREATE_SERVICE_EVT, status %d, service_handle %d\n", param->create.status, param->create.service_handle); + gatts_profile_tab[GATTS_PROFILE_B_APP_ID].service_handle = param->create.service_handle; + gatts_profile_tab[GATTS_PROFILE_B_APP_ID].char_uuid.len = ESP_UUID_LEN_16; + gatts_profile_tab[GATTS_PROFILE_B_APP_ID].char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_TEST_B; + + esp_ble_gatts_start_service(gatts_profile_tab[GATTS_PROFILE_B_APP_ID].service_handle); + b_property = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY; + esp_err_t add_char_ret =esp_ble_gatts_add_char( gatts_profile_tab[GATTS_PROFILE_B_APP_ID].service_handle, &gatts_profile_tab[GATTS_PROFILE_B_APP_ID].char_uuid, + ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, + b_property, + NULL, NULL); + if (add_char_ret) { + ESP_LOGE(COEX_TAG, "add char failed, error code =%x\n",add_char_ret); + } + break; + case ESP_GATTS_ADD_INCL_SRVC_EVT: + break; + case ESP_GATTS_ADD_CHAR_EVT: + ESP_LOGI(COEX_TAG, "ADD_CHAR_EVT, status %d, attr_handle %d, service_handle %d\n", + param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle); + + gatts_profile_tab[GATTS_PROFILE_B_APP_ID].char_handle = param->add_char.attr_handle; + gatts_profile_tab[GATTS_PROFILE_B_APP_ID].descr_uuid.len = ESP_UUID_LEN_16; + gatts_profile_tab[GATTS_PROFILE_B_APP_ID].descr_uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG; + esp_ble_gatts_add_char_descr(gatts_profile_tab[GATTS_PROFILE_B_APP_ID].service_handle, &gatts_profile_tab[GATTS_PROFILE_B_APP_ID].descr_uuid, + ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, + NULL, NULL); + break; + case ESP_GATTS_ADD_CHAR_DESCR_EVT: + gatts_profile_tab[GATTS_PROFILE_B_APP_ID].descr_handle = param->add_char_descr.attr_handle; + ESP_LOGI(COEX_TAG, "ADD_DESCR_EVT, status %d, attr_handle %d, service_handle %d\n", + param->add_char_descr.status, param->add_char_descr.attr_handle, param->add_char_descr.service_handle); + break; + case ESP_GATTS_DELETE_EVT: + break; + case ESP_GATTS_START_EVT: + ESP_LOGI(COEX_TAG, "SERVICE_START_EVT, status %d, service_handle %d\n", + param->start.status, param->start.service_handle); + break; + case ESP_GATTS_STOP_EVT: + break; + case ESP_GATTS_CONNECT_EVT: + ESP_LOGI(COEX_TAG, "CONNECT_EVT, conn_id %d, remote %02x:%02x:%02x:%02x:%02x:%02x\n", + param->connect.conn_id, + param->connect.remote_bda[0], param->connect.remote_bda[1], param->connect.remote_bda[2], + param->connect.remote_bda[3], param->connect.remote_bda[4], param->connect.remote_bda[5]); + gatts_profile_tab[GATTS_PROFILE_B_APP_ID].conn_id = param->connect.conn_id; + break; + case ESP_GATTS_CONF_EVT: + ESP_LOGI(COEX_TAG, "ESP_GATTS_CONF_EVT status %d attr_handle %d\n", param->conf.status, param->conf.handle); + if (param->conf.status != ESP_GATT_OK) { + esp_log_buffer_hex(COEX_TAG, param->conf.value, param->conf.len); + } + break; + case ESP_GATTS_DISCONNECT_EVT: + case ESP_GATTS_OPEN_EVT: + default: + break; + } +} + +static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) +{ + /* If event is register event, store the gattc_if for each profile */ + if (event == ESP_GATTC_REG_EVT) { + if (param->reg.status == ESP_GATT_OK) { + gattc_profile_tab[param->reg.app_id].gattc_if = gattc_if; + } else { + ESP_LOGI(COEX_TAG, "reg app failed, app_id %04x, status %d\n", + param->reg.app_id, + param->reg.status); + return; + } + } + + /* If the gattc_if equal to profile A, call profile A cb handler, + * so here call each profile's callback */ + do { + int idx; + for (idx = 0; idx < GATTC_PROFILE_NUM; idx ++) { + if (gattc_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */ + gattc_if == gattc_profile_tab[idx].gattc_if) { + if (gattc_profile_tab[idx].gattc_cb) { + gattc_profile_tab[idx].gattc_cb(event, gattc_if, param); + } + } + } + } while (0); +} + +static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) +{ + /* If event is register event, store the gatts_if for each profile */ + if (event == ESP_GATTS_REG_EVT) { + if (param->reg.status == ESP_GATT_OK) { + gatts_profile_tab[param->reg.app_id].gatts_if = gatts_if; + } else { + ESP_LOGI(COEX_TAG, "Reg app failed, app_id %04x, status %d\n", + param->reg.app_id, + param->reg.status); + return; + } + } + + /* If the gatts_if equal to profile A, call profile A cb handler, + * so here call each profile's callback */ + do { + int idx; + for (idx = 0; idx < GATTS_PROFILE_NUM; idx ++) { + if (gatts_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */ + gatts_if == gatts_profile_tab[idx].gatts_if) { + if (gatts_profile_tab[idx].gatts_cb) { + gatts_profile_tab[idx].gatts_cb(event, gatts_if, param); + } + } + } + } while (0); +} + +void app_main() +{ + esp_err_t ret; + + // Initialize NVS. + ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK( ret ); + + ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)); + + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + ret = esp_bt_controller_init(&bt_cfg); + if (ret) { + ESP_LOGE(COEX_TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(ret)); + return; + } + + ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); + if (ret) { + ESP_LOGE(COEX_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret)); + return; + } + + ret = esp_bluedroid_init(); + if (ret) { + ESP_LOGE(COEX_TAG, "%s init bluetooth failed: %s\n", __func__, esp_err_to_name(ret)); + return; + } + + ret = esp_bluedroid_enable(); + if (ret) { + ESP_LOGE(COEX_TAG, "%s enable bluetooth failed: %s\n", __func__, esp_err_to_name(ret)); + return; + } + + ret = esp_ble_gap_register_callback(gap_event_handler); + if (ret) { + ESP_LOGE(COEX_TAG, "gap register error, error code = %x", ret); + return; + } + + // gatts register + ret = esp_ble_gatts_register_callback(gatts_event_handler); + if (ret) { + ESP_LOGE(COEX_TAG, "gatts register error, error code = %x", ret); + return; + } + + ret = esp_ble_gatts_app_register(GATTS_PROFILE_A_APP_ID); + if (ret) { + ESP_LOGE(COEX_TAG, "gatts app register error, error code = %x", ret); + return; + } + + ret = esp_ble_gatts_app_register(GATTS_PROFILE_B_APP_ID); + if (ret) { + ESP_LOGE(COEX_TAG, "gatts app register error, error code = %x", ret); + return; + } + + // gattc regisrter + ret = esp_ble_gattc_register_callback(esp_gattc_cb); + if(ret) { + ESP_LOGE(COEX_TAG, "%s gattc register failed, error code = %x\n", __func__, ret); + return; + } + + ret = esp_ble_gattc_app_register(GATTC_PROFILE_C_APP_ID); + if (ret) { + ESP_LOGE(COEX_TAG, "%s gattc app register failed, error code = %x\n", __func__, ret); + } + + esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(500); + if (local_mtu_ret) { + ESP_LOGE(COEX_TAG, "set local MTU failed, error code = %x", local_mtu_ret); + } + + return; +} + diff --git a/examples/bluetooth/gattc_gatts_coex/sdkconfig.defaults b/examples/bluetooth/gattc_gatts_coex/sdkconfig.defaults new file mode 100644 index 0000000000..8dbe56f4f4 --- /dev/null +++ b/examples/bluetooth/gattc_gatts_coex/sdkconfig.defaults @@ -0,0 +1,6 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y +CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY= +CONFIG_BTDM_CTRL_MODE_BTDM= From 037c079e9a86a54d95b0daa934cd2e8200a7d79b Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Thu, 29 Nov 2018 17:06:21 +0800 Subject: [PATCH 073/486] esp32: Refactor backtrace and add esp_backtrace_print() This commit refactors backtracing within the panic handler so that a common function esp_backtrace_get_next_frame() is used iteratively to traverse a callstack. A esp_backtrace_print() function has also be added that allows the printing of a backtrace at runtime. The esp_backtrace_print() function allows unity to print the backtrace of failed test cases and jump back to the main test menu without the need reset the chip. esp_backtrace_print() can also be used as a debugging function by users. - esp_stack_ptr_is_sane() moved to soc_memory_layout.h - removed uncessary includes of "esp_debug_helpers.h" --- components/esp32/cpu_start.c | 1 - components/esp32/gdbstub.c | 2 +- components/esp32/panic.c | 42 +++++----- components/espcoredump/src/core_dump_port.c | 2 +- components/freertos/tasks.c | 1 - components/heap/test/test_malloc.c | 1 - components/soc/esp32/include/soc/cpu.h | 21 +++++ .../soc/include/soc/soc_memory_layout.h | 7 ++ components/unity/CMakeLists.txt | 4 + components/unity/Kconfig | 10 ++- components/unity/component.mk | 4 + components/unity/include/priv/setjmp.h | 14 ++++ components/xtensa/CMakeLists.txt | 2 +- components/xtensa/debug_helpers.c | 72 ++++++++++++++++ components/xtensa/debug_helpers_asm.S | 57 +++++++++++++ components/xtensa/include/esp_debug_helpers.h | 84 +++++++++++++++++-- tools/unit-test-app/sdkconfig.defaults | 1 + 17 files changed, 293 insertions(+), 32 deletions(-) create mode 100644 components/unity/include/priv/setjmp.h create mode 100644 components/xtensa/debug_helpers.c create mode 100644 components/xtensa/debug_helpers_asm.S diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 3a782f2985..7e5a1c93e2 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -59,7 +59,6 @@ #include "esp_phy_init.h" #include "esp32/cache_err_int.h" #include "esp_coexist_internal.h" -#include "esp_debug_helpers.h" #include "esp_core_dump.h" #include "esp_app_trace.h" #include "esp_private/dbg_stubs.h" diff --git a/components/esp32/gdbstub.c b/components/esp32/gdbstub.c index 08623dce4c..c690e42b59 100644 --- a/components/esp32/gdbstub.c +++ b/components/esp32/gdbstub.c @@ -22,8 +22,8 @@ #include "esp32/rom/ets_sys.h" #include "soc/uart_periph.h" #include "soc/gpio_periph.h" +#include "soc/soc_memory_layout.h" #include "esp_private/gdbstub.h" -#include "esp_debug_helpers.h" #include "driver/gpio.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" diff --git a/components/esp32/panic.c b/components/esp32/panic.c index b66ba9437a..e7ed6540e2 100644 --- a/components/esp32/panic.c +++ b/components/esp32/panic.c @@ -30,6 +30,7 @@ #include "soc/cpu.h" #include "soc/rtc.h" #include "soc/rtc_wdt.h" +#include "soc/soc_memory_layout.h" #include "esp_private/gdbstub.h" #include "esp_debug_helpers.h" @@ -446,33 +447,36 @@ static void esp_panic_dig_reset() static void putEntry(uint32_t pc, uint32_t sp) { - if (pc & 0x80000000) { - pc = (pc & 0x3fffffff) | 0x40000000; - } panicPutStr(" 0x"); panicPutHex(pc); panicPutStr(":0x"); panicPutHex(sp); } -static void doBacktrace(XtExcFrame *frame) +static void doBacktrace(XtExcFrame *exc_frame, int depth) { - uint32_t i = 0, pc = frame->pc, sp = frame->a1; + //Initialize stk_frame with first frame of stack + esp_backtrace_frame_t stk_frame = {.pc = exc_frame->pc, .sp = exc_frame->a1, .next_pc = exc_frame->a0}; panicPutStr("\r\nBacktrace:"); - /* Do not check sanity on first entry, PC could be smashed. */ - putEntry(pc, sp); - pc = frame->a0; - while (i++ < 100) { - uint32_t psp = sp; - if (!esp_stack_ptr_is_sane(sp) || i++ > 100) { - break; - } - sp = *((uint32_t *) (sp - 0x10 + 4)); - putEntry(pc - 3, sp); // stack frame addresses are return addresses, so subtract 3 to get the CALL address - pc = *((uint32_t *) (psp - 0x10)); - if (pc < 0x40000000) { - break; + putEntry(esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp); + + //Check if first frame is valid + bool corrupted = (esp_stack_ptr_is_sane(stk_frame.sp) && + esp_ptr_executable((void*)esp_cpu_process_stack_pc(stk_frame.pc))) ? + false : true; + uint32_t i = ((depth <= 0) ? INT32_MAX : depth) - 1; //Account for stack frame that's already printed + while (i-- > 0 && stk_frame.next_pc != 0 && !corrupted) { + if (!esp_backtrace_get_next_frame(&stk_frame)) { //Get next stack frame + corrupted = true; } + putEntry(esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp); + } + + //Print backtrace termination marker + if (corrupted) { + panicPutStr(" |<-CORRUPTED"); + } else if (stk_frame.next_pc != 0) { //Backtrace continues + panicPutStr(" |<-CONTINUES"); } panicPutStr("\r\n"); } @@ -549,7 +553,7 @@ static void commonErrorHandler_dump(XtExcFrame *frame, int core_id) panicPutStr("\r\n"); /* With windowed ABI backtracing is easy, let's do it. */ - doBacktrace(frame); + doBacktrace(frame, 100); panicPutStr("\r\n"); } diff --git a/components/espcoredump/src/core_dump_port.c b/components/espcoredump/src/core_dump_port.c index 3e3414a4cc..2ac1b6482b 100644 --- a/components/espcoredump/src/core_dump_port.c +++ b/components/espcoredump/src/core_dump_port.c @@ -13,7 +13,7 @@ // limitations under the License. #include #include -#include "esp_debug_helpers.h" +#include "soc/soc_memory_layout.h" #include "esp_core_dump_priv.h" const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump_port"; diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index 91c7616645..b19ba84a62 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -78,7 +78,6 @@ task.h is included from an application file. */ #include "esp32/rom/ets_sys.h" #include "esp_newlib.h" -#include "esp_debug_helpers.h" /* FreeRTOS includes. */ #include "FreeRTOS.h" diff --git a/components/heap/test/test_malloc.c b/components/heap/test/test_malloc.c index 1ed67ce50c..e2916e2bc3 100644 --- a/components/heap/test/test_malloc.c +++ b/components/heap/test/test_malloc.c @@ -14,7 +14,6 @@ #include "unity.h" #include "esp_heap_caps.h" -#include "esp_debug_helpers.h" #include "sdkconfig.h" diff --git a/components/soc/esp32/include/soc/cpu.h b/components/soc/esp32/include/soc/cpu.h index f28feb59fa..190786a433 100644 --- a/components/soc/esp32/include/soc/cpu.h +++ b/components/soc/esp32/include/soc/cpu.h @@ -110,4 +110,25 @@ void esp_cpu_reset(int cpu_id); */ bool esp_cpu_in_ocd_debug_mode(); +/** + * @brief Convert the PC register value to its true address + * + * The address of the current instruction is not stored as an exact uint32_t + * representation in PC register. This function will convert the value stored in + * the PC register to a uint32_t address. + * + * @param pc_raw The PC as stored in register format. + * + * @return Address in uint32_t format + */ +static inline uint32_t esp_cpu_process_stack_pc(uint32_t pc) +{ + if (pc & 0x80000000) { + //Top two bits of a0 (return address) specify window increment. Overwrite to map to address space. + pc = (pc & 0x3fffffff) | 0x40000000; + } + //Minus 3 to get PC of previous instruction (i.e. instruction executed before return address) + return pc - 3; +} + #endif diff --git a/components/soc/include/soc/soc_memory_layout.h b/components/soc/include/soc/soc_memory_layout.h index 6fb8c6519b..de7c449d51 100644 --- a/components/soc/include/soc/soc_memory_layout.h +++ b/components/soc/include/soc/soc_memory_layout.h @@ -203,3 +203,10 @@ inline static bool IRAM_ATTR esp_ptr_in_diram_dram(const void *p) { inline static bool IRAM_ATTR esp_ptr_in_diram_iram(const void *p) { return ((intptr_t)p >= SOC_DIRAM_IRAM_LOW && (intptr_t)p < SOC_DIRAM_IRAM_HIGH); } + + +inline static bool IRAM_ATTR esp_stack_ptr_is_sane(uint32_t sp) +{ + //Check if stack ptr is in between SOC_DRAM_LOW and SOC_DRAM_HIGH, and 16 byte aligned. + return !(sp < SOC_DRAM_LOW + 0x10 || sp > SOC_DRAM_HIGH - 0x10 || ((sp & 0xF) != 0)); +} diff --git a/components/unity/CMakeLists.txt b/components/unity/CMakeLists.txt index 3f8ecac230..53494ae0f0 100644 --- a/components/unity/CMakeLists.txt +++ b/components/unity/CMakeLists.txt @@ -4,6 +4,10 @@ set(COMPONENT_SRCS "unity/src/unity.c" set(COMPONENT_ADD_INCLUDEDIRS "include" "unity/src") +if(CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL) + list(APPEND COMPONENT_PRIV_INCLUDEDIRS "include/priv") +endif() + if(CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER) list(APPEND COMPONENT_SRCS "unity_runner.c") endif() diff --git a/components/unity/Kconfig b/components/unity/Kconfig index 4cf2a30731..e9efc6381e 100644 --- a/components/unity/Kconfig +++ b/components/unity/Kconfig @@ -42,4 +42,12 @@ menu "Unity unit testing library" the build. These provide an optional set of macros and functions to implement test groups. -endmenu # "Unity unit testing library" + config UNITY_ENABLE_BACKTRACE_ON_FAIL + bool "Print a backtrace when a unit test fails" + default n + help + If set, the unity framework will print the backtrace information before + jumping back to the test menu. The jumping is usually occurs in assert + functions such as TEST_ASSERT, TEST_FAIL etc. + +endmenu # "Unity unit testing library" \ No newline at end of file diff --git a/components/unity/component.mk b/components/unity/component.mk index 3e1501c79a..2d2a106d7c 100644 --- a/components/unity/component.mk +++ b/components/unity/component.mk @@ -9,6 +9,10 @@ endif COMPONENT_ADD_INCLUDEDIRS = include unity/src COMPONENT_SRCDIRS = unity/src . +ifdef CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL +COMPONENT_PRIV_INCLUDEDIRS += include/priv +endif + ifndef CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER COMPONENT_OBJEXCLUDE += unity_runner.o endif diff --git a/components/unity/include/priv/setjmp.h b/components/unity/include/priv/setjmp.h new file mode 100644 index 0000000000..c467cbd94a --- /dev/null +++ b/components/unity/include/priv/setjmp.h @@ -0,0 +1,14 @@ +#include_next +#include "esp_debug_helpers.h" + +/* + * This is the middle layer of setjmp to be used with the unity. + */ + +/** Insert backtrace before longjmp (TEST_ABORT). + * + * Currently we only do long jump before test is ignored or failed. + * If this is also called when test pass, we may need to add some check before + * backtrace is called. + */ +#define longjmp(buf, val) do {esp_backtrace_print(100); longjmp(buf, val);} while(0) diff --git a/components/xtensa/CMakeLists.txt b/components/xtensa/CMakeLists.txt index cb9c9ce49c..1bb997d673 100644 --- a/components/xtensa/CMakeLists.txt +++ b/components/xtensa/CMakeLists.txt @@ -1,4 +1,4 @@ -set(COMPONENT_SRCS "eri.c" "trax.c") +set(COMPONENT_SRCS "eri.c" "trax.c" "debug_helpers.c" "debug_helpers_asm.S") set(COMPONENT_ADD_INCLUDEDIRS "include" "${IDF_TARGET}/include") diff --git a/components/xtensa/debug_helpers.c b/components/xtensa/debug_helpers.c new file mode 100644 index 0000000000..564e6eb159 --- /dev/null +++ b/components/xtensa/debug_helpers.c @@ -0,0 +1,72 @@ +// Copyright 2015-2019 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 "esp_types.h" +#include "esp_attr.h" +#include "esp_err.h" +#include "esp_debug_helpers.h" +#include "esp32/rom/ets_sys.h" +#include "soc/soc_memory_layout.h" +#include "soc/cpu.h" + +bool IRAM_ATTR esp_backtrace_get_next_frame(esp_backtrace_frame_t *frame) +{ + //Use frame(i-1)'s BS area located below frame(i)'s sp to get frame(i-1)'s sp and frame(i-2)'s pc + void *base_save = (void *)frame->sp; //Base save area consists of 4 words under SP + frame->pc = frame->next_pc; + frame->next_pc = *((uint32_t *)(base_save - 16)); //If next_pc = 0, indicates frame(i-1) is the last frame on the stack + frame->sp = *((uint32_t *)(base_save - 12)); + + //Return true if both sp and pc of frame(i-1) are sane, false otherwise + return (esp_stack_ptr_is_sane(frame->sp) && esp_ptr_executable((void*)esp_cpu_process_stack_pc(frame->pc))); +} + +esp_err_t IRAM_ATTR esp_backtrace_print(int depth) +{ + //Check arguments + if (depth <= 0) { + return ESP_ERR_INVALID_ARG; + } + + //Initialize stk_frame with first frame of stack + esp_backtrace_frame_t stk_frame; + esp_backtrace_get_start(&(stk_frame.pc), &(stk_frame.sp), &(stk_frame.next_pc)); + //esp_cpu_get_backtrace_start(&stk_frame); + ets_printf("\r\n\r\nBacktrace:"); + ets_printf("0x%08X:0x%08X ", esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp); + + //Check if first frame is valid + bool corrupted = (esp_stack_ptr_is_sane(stk_frame.sp) && + esp_ptr_executable((void*)esp_cpu_process_stack_pc(stk_frame.pc))) ? + false : true; + + uint32_t i = (depth <= 0) ? INT32_MAX : depth; + while (i-- > 0 && stk_frame.next_pc != 0 && !corrupted) { + if (!esp_backtrace_get_next_frame(&stk_frame)) { //Get previous stack frame + corrupted = true; + } + ets_printf("0x%08X:0x%08X ", esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp); + } + + //Print backtrace termination marker + esp_err_t ret = ESP_OK; + if (corrupted) { + ets_printf(" |<-CORRUPTED"); + ret = ESP_FAIL; + } else if (stk_frame.next_pc != 0) { //Backtrace continues + ets_printf(" |<-CONTINUES"); + } + ets_printf("\r\n\r\n"); + return ret; +} diff --git a/components/xtensa/debug_helpers_asm.S b/components/xtensa/debug_helpers_asm.S new file mode 100644 index 0000000000..0df70df863 --- /dev/null +++ b/components/xtensa/debug_helpers_asm.S @@ -0,0 +1,57 @@ +// Copyright 2015-2019 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 +#include +#include +#include + +/* + * esp_backtrace_get_start(uint32_t *pc, uint32_t *sp, uint32_t *next_pc) + * + * High Addr + * .................. + * | i-3 BS | + * | i-1 locals | Function B + * .................. i-1 SP + * | i-2 BS | + * | i locals | Function A (Start of backtrace) + * ------------------ i SP + * | i-1 BS | + * | i+1 locals | Backtracing function (e.g. esp_backtrace_print()) + * ------------------ i+1 SP + * | i BS | + * | i+2 locals | esp_backtrace_get_start() <- This function + * ------------------ i+2 SP + * | i+1 BS | + * | i+3 locals | xthal_window_spill() + * ------------------ i+3 SP + * .................. Low Addr + */ + .section .iram1, "ax" + .align 4 + .global esp_backtrace_get_start + .type esp_backtrace_get_start, @function +esp_backtrace_get_start: + entry a1, 32 + call8 xthal_window_spill //Spill registers onto stack (excluding this function) + //a2, a3, a4 should be out arguments for i SP, i PC, i-1 PC respectively. Use a5 and a6 as scratch + l32e a5, sp, -16 //Get i PC, which is ret addres of i+1 + s32i a5, a2, 0 //Store i PC to arg *pc + l32e a6, sp, -12 //Get i+1 SP. Used to access i BS + l32e a5, a6, -12 //Get i SP + s32i a5, a3, 0 //Store i SP to arg *sp + l32e a5, a6, -16 //Get i-1 PC, which is ret address of i + s32i a5, a4, 0 //Store i-1 PC to arg *next_pc + retw diff --git a/components/xtensa/include/esp_debug_helpers.h b/components/xtensa/include/esp_debug_helpers.h index 981fa34a53..40167780c5 100644 --- a/components/xtensa/include/esp_debug_helpers.h +++ b/components/xtensa/include/esp_debug_helpers.h @@ -1,3 +1,17 @@ +// Copyright 2015-2019 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 #ifdef __cplusplus @@ -12,6 +26,24 @@ extern "C" { #define ESP_WATCHPOINT_STORE 0x80000000 #define ESP_WATCHPOINT_ACCESS 0xC0000000 +/* + * @brief Structure used for backtracing + * + * This structure stores the backtrace information of a particular stack frame + * (i.e. the PC and SP). This structure is used iteratively with the + * esp_cpu_get_next_backtrace_frame() function to traverse each frame within a + * single stack. The next_pc represents the PC of the current frame's caller, thus + * a next_pc of 0 indicates that the current frame is the last frame on the stack. + * + * @note Call esp_backtrace_get_start() to obtain initialization values for + * this structure + */ +typedef struct { + uint32_t pc; /* PC of the current frame */ + uint32_t sp; /* SP of the current frame */ + uint32_t next_pc; /* PC of the current frame's caller */ +} esp_backtrace_frame_t; + /** * @brief If an OCD is connected over JTAG. set breakpoint 0 to the given function * address. Do nothing otherwise. @@ -37,7 +69,6 @@ void esp_set_breakpoint_if_jtag(void *fn); */ esp_err_t esp_set_watchpoint(int no, void *adr, int size, int flags); - /** * @brief Clear a watchpoint * @@ -47,12 +78,53 @@ esp_err_t esp_set_watchpoint(int no, void *adr, int size, int flags); void esp_clear_watchpoint(int no); /** - * @brief Checks stack pointer + * Get the first frame of the current stack's backtrace + * + * Given the following function call flow (B -> A -> X -> esp_backtrace_get_start), + * this function will do the following. + * - Flush CPU registers and window frames onto the current stack + * - Return PC and SP of function A (i.e. start of the stack's backtrace) + * - Return PC of function B (i.e. next_pc) + * + * @note This function is implemented in assembly + * + * @param[out] pc PC of the first frame in the backtrace + * @param[out] sp SP of the first frame in the backtrace + * @param[out] next_pc PC of the first frame's caller */ -static inline bool esp_stack_ptr_is_sane(uint32_t sp) -{ - return !(sp < 0x3ffae010UL || sp > 0x3ffffff0UL || ((sp & 0xf) != 0)); -} +extern void esp_backtrace_get_start(uint32_t *pc, uint32_t *sp, uint32_t *next_pc); + +/** + * Get the next frame on a stack for backtracing + * + * Given a stack frame(i), this function will obtain the next stack frame(i-1) + * on the same call stack (i.e. the caller of frame(i)). This function is meant to be + * called iteratively when doing a backtrace. + * + * Entry Conditions: Frame structure containing valid SP and next_pc + * Exit Conditions: + * - Frame structure updated with SP and PC of frame(i-1). next_pc now points to frame(i-2). + * - If a next_pc of 0 is returned, it indicates that frame(i-1) is last frame on the stack + * + * @param[inout] frame Pointer to frame structure + * + * @return + * - True if the SP and PC of the next frame(i-1) are sane + * - False otherwise + */ +bool esp_backtrace_get_next_frame(esp_backtrace_frame_t *frame); + +/** + * @brief Print the backtrace of the current stack + * + * @param depth The maximum number of stack frames to print (should be > 0) + * + * @return + * - ESP_OK Backtrace successfully printed to completion or to depth limit + * - ESP_FAIL Backtrace is corrupted + */ +esp_err_t esp_backtrace_print(int depth); + #endif #ifdef __cplusplus diff --git a/tools/unit-test-app/sdkconfig.defaults b/tools/unit-test-app/sdkconfig.defaults index ca30ad526d..947c232873 100644 --- a/tools/unit-test-app/sdkconfig.defaults +++ b/tools/unit-test-app/sdkconfig.defaults @@ -31,3 +31,4 @@ CONFIG_SPI_MASTER_IN_IRAM=y CONFIG_EFUSE_VIRTUAL=y CONFIG_SPIRAM_BANKSWITCH_ENABLE=n CONFIG_FATFS_ALLOC_EXTRAM_FIRST=y +CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y From 71eece07a0f9fd22a678c0529955daef93bf8684 Mon Sep 17 00:00:00 2001 From: zhiweijian Date: Wed, 3 Apr 2019 20:11:17 +0800 Subject: [PATCH 074/486] Component/bt: add ble ancs demo --- examples/bluetooth/ble_ancs/CMakeLists.txt | 6 + examples/bluetooth/ble_ancs/Makefile | 10 + examples/bluetooth/ble_ancs/README.md | 18 + .../bluetooth/ble_ancs/main/CMakeLists.txt | 5 + examples/bluetooth/ble_ancs/main/ble_ancs.c | 228 ++++++ examples/bluetooth/ble_ancs/main/ble_ancs.h | 124 ++++ .../bluetooth/ble_ancs/main/ble_ancs_demo.c | 688 ++++++++++++++++++ examples/bluetooth/ble_ancs/main/component.mk | 9 + .../bluetooth/ble_ancs/sdkconfig.defaults | 6 + 9 files changed, 1094 insertions(+) create mode 100644 examples/bluetooth/ble_ancs/CMakeLists.txt create mode 100644 examples/bluetooth/ble_ancs/Makefile create mode 100644 examples/bluetooth/ble_ancs/README.md create mode 100644 examples/bluetooth/ble_ancs/main/CMakeLists.txt create mode 100644 examples/bluetooth/ble_ancs/main/ble_ancs.c create mode 100644 examples/bluetooth/ble_ancs/main/ble_ancs.h create mode 100644 examples/bluetooth/ble_ancs/main/ble_ancs_demo.c create mode 100644 examples/bluetooth/ble_ancs/main/component.mk create mode 100644 examples/bluetooth/ble_ancs/sdkconfig.defaults diff --git a/examples/bluetooth/ble_ancs/CMakeLists.txt b/examples/bluetooth/ble_ancs/CMakeLists.txt new file mode 100644 index 0000000000..84faba94ed --- /dev/null +++ b/examples/bluetooth/ble_ancs/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(ble_ancs) diff --git a/examples/bluetooth/ble_ancs/Makefile b/examples/bluetooth/ble_ancs/Makefile new file mode 100644 index 0000000000..a5208ef071 --- /dev/null +++ b/examples/bluetooth/ble_ancs/Makefile @@ -0,0 +1,10 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := ble_ancs + +COMPONENT_ADD_INCLUDEDIRS := components/include + +include $(IDF_PATH)/make/project.mk diff --git a/examples/bluetooth/ble_ancs/README.md b/examples/bluetooth/ble_ancs/README.md new file mode 100644 index 0000000000..06a7f4625e --- /dev/null +++ b/examples/bluetooth/ble_ancs/README.md @@ -0,0 +1,18 @@ +ESP-IDF BLE ANCS Example +========================== + +The purpose of the Apple Notification Center Service (ANCS) is to give Bluetooth accessories (that connect to iOS devices through a Bluetooth low-energy link) a simple and convenient way to access many kinds of notifications that are generated on iOS devices. + +The Apple Notification Center Service is a primary service whose service UUID is 7905F431-B5CE-4E99-A40F-4B1E122D00D0. + +Only one instance of the ANCS may be present on an NP. Due to the nature of iOS, the ANCS is not guaranteed to always be present. As a result, the NC should look for and subscribe to the Service Changed characteristic of the GATT service in order to monitor for the potential publishing and unpublishing of the ANCS at any time. + +In its basic form, the ANCS exposes three characteristics: +Notification Source: UUID 9FBF120D-6301-42D9-8C58-25E699A21DBD (notifiable) +Control Point: UUID 69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9 (writeable with response) +Data Source: UUID 22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB (notifiable) +All these characteristics require authorization for access. + + + + diff --git a/examples/bluetooth/ble_ancs/main/CMakeLists.txt b/examples/bluetooth/ble_ancs/main/CMakeLists.txt new file mode 100644 index 0000000000..7e64fd8041 --- /dev/null +++ b/examples/bluetooth/ble_ancs/main/CMakeLists.txt @@ -0,0 +1,5 @@ +set(COMPONENT_SRCS "ble_ancs_demo.c" + "ble_ancs.c") +set(COMPONENT_ADD_INCLUDEDIRS ".") + +register_component() diff --git a/examples/bluetooth/ble_ancs/main/ble_ancs.c b/examples/bluetooth/ble_ancs/main/ble_ancs.c new file mode 100644 index 0000000000..2035b67516 --- /dev/null +++ b/examples/bluetooth/ble_ancs/main/ble_ancs.c @@ -0,0 +1,228 @@ +// Copyright 2017-2018 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 +#include +#include "esp_log.h" +#include "ble_ancs.h" + +#define BLE_ANCS_TAG "BLE_ANCS" + +/* +| EventID(1 Byte) | EventFlags(1 Byte) | CategoryID(1 Byte) | CategoryCount(1 Byte) | NotificationUID(4 Bytes) | + +A GATT notification delivered through the Notification Source characteristic contains the following information: +* EventID: This field informs the accessory whether the given iOS notification was added, modified, or removed. The enumerated values for this field are defined + in EventID Values. +* EventFlags: A bitmask whose set bits inform an NC of specificities with the iOS notification. For example, if an iOS notification is considered “important”, + the NC may want to display a more aggressive user interface (UI) to make sure the user is properly alerted. The enumerated bits for this field + are defined in EventFlags. +* CategoryID: A numerical value providing a category in which the iOS notification can be classified. The NP will make a best effort to provide an accurate category + for each iOS notification. The enumerated values for this field are defined in CategoryID Values. +* CategoryCount: The current number of active iOS notifications in the given category. For example, if two unread emails are sitting in a user’s email inbox, and a new + email is pushed to the user’s iOS device, the value of CategoryCount is 3. +* NotificationUID: A 32-bit numerical value that is the unique identifier (UID) for the iOS notification. This value can be used as a handle in commands sent to the + Control Point characteristic to interact with the iOS notification. +*/ + +char *EventID_to_String(uint8_t EventID) +{ + char *str = NULL; + switch (EventID) + { + case EventIDNotificationAdded: + str = "New message"; + break; + case EventIDNotificationModified: + str = "Modified message"; + break; + case EventIDNotificationRemoved: + str = "Removed message"; + break; + default: + str = "unknown EventID"; + break; + } + return str; +} + +char *CategoryID_to_String(uint8_t CategoryID) +{ + char *Cidstr = NULL; + switch(CategoryID) { + case CategoryIDOther: + Cidstr = "Other"; + break; + case CategoryIDIncomingCall: + Cidstr = "IncomingCall"; + break; + case CategoryIDMissedCall: + Cidstr = "MissedCall"; + break; + case CategoryIDVoicemail: + Cidstr = "Voicemail"; + break; + case CategoryIDSocial: + Cidstr = "Social"; + break; + case CategoryIDSchedule: + Cidstr = "Schedule"; + break; + case CategoryIDEmail: + Cidstr = "Email"; + break; + case CategoryIDNews: + Cidstr = "News"; + break; + case CategoryIDHealthAndFitness: + Cidstr = "HealthAndFitness"; + break; + case CategoryIDBusinessAndFinance: + Cidstr = "BusinessAndFinance"; + break; + case CategoryIDLocation: + Cidstr = "Location"; + break; + case CategoryIDEntertainment: + Cidstr = "Entertainment"; + break; + default: + Cidstr = "Unknown CategoryID"; + break; + } + return Cidstr; +} + +/* +| EventID(1 Byte) | EventFlags(1 Byte) | CategoryID(1 Byte) | CategoryCount(1 Byte) | NotificationUID(4 Bytes) | +*/ + +void esp_receive_apple_notification_source(uint8_t *message, uint16_t message_len) +{ + if (!message || message_len < 5) { + return; + } + + uint8_t EventID = message[0]; + char *EventIDS = EventID_to_String(EventID); + uint8_t EventFlags = message[1]; + uint8_t CategoryID = message[2]; + char *Cidstr = CategoryID_to_String(CategoryID); + uint8_t CategoryCount = message[3]; + uint32_t NotificationUID = (message[4]) | (message[5]<< 8) | (message[6]<< 16) | (message[7] << 24); + ESP_LOGI(BLE_ANCS_TAG, "EventID:%s EventFlags:0x%x CategoryID:%s CategoryCount:%d NotificationUID:%d", EventIDS, EventFlags, Cidstr, CategoryCount, NotificationUID); +} + +void esp_receive_apple_data_source(uint8_t *message, uint16_t message_len) +{ + //esp_log_buffer_hex("data source", message, message_len); + if (!message || message_len == 0) { + return; + } + uint8_t Command_id = message[0]; + switch (Command_id) + { + case CommandIDGetNotificationAttributes: { + uint32_t NotificationUID = (message[1]) | (message[2]<< 8) | (message[3]<< 16) | (message[4] << 24); + uint32_t remian_attr_len = message_len - 5; + uint8_t *attrs = &message[5]; + ESP_LOGI(BLE_ANCS_TAG, "recevice Notification Attributes response Command_id %d NotificationUID %d", Command_id, NotificationUID); + while(remian_attr_len > 0) { + uint8_t AttributeID = attrs[0]; + uint16_t len = attrs[1] | (attrs[2] << 8); + if(len > (remian_attr_len -3)) { + ESP_LOGE(BLE_ANCS_TAG, "data error"); + break; + } + switch (AttributeID) + { + case NotificationAttributeIDAppIdentifier: + esp_log_buffer_char("Identifier", &attrs[3], len); + break; + case NotificationAttributeIDTitle: + esp_log_buffer_char("Title", &attrs[3], len); + break; + case NotificationAttributeIDSubtitle: + esp_log_buffer_char("Subtitle", &attrs[3], len); + break; + case NotificationAttributeIDMessage: + esp_log_buffer_char("Message", &attrs[3], len); + break; + case NotificationAttributeIDMessageSize: + esp_log_buffer_char("MessageSize", &attrs[3], len); + break; + case NotificationAttributeIDDate: + //yyyyMMdd'T'HHmmSS + esp_log_buffer_char("Date", &attrs[3], len); + break; + case NotificationAttributeIDPositiveActionLabel: + esp_log_buffer_hex("PActionLabel", &attrs[3], len); + break; + case NotificationAttributeIDNegativeActionLabel: + esp_log_buffer_hex("NActionLabel", &attrs[3], len); + break; + default: + esp_log_buffer_hex("unknownAttributeID", &attrs[3], len); + break; + } + + attrs += (1 + 2 + len); + remian_attr_len -= (1 + 2 + len); + } + + break; + } + case CommandIDGetAppAttributes: + ESP_LOGI(BLE_ANCS_TAG, "recevice APP Attributes response"); + break; + case CommandIDPerformNotificationAction: + ESP_LOGI(BLE_ANCS_TAG, "recevice Perform Notification Action"); + break; + default: + ESP_LOGI(BLE_ANCS_TAG, "unknown Command ID"); + break; + } +} + +char *Errcode_to_String(uint16_t status) +{ + char *Errstr = NULL; + switch (status) { + case Unknown_command: + Errstr = "Unknown_command"; + break; + case Invalid_command: + Errstr = "Invalid_command"; + break; + case Invalid_parameter: + Errstr = "Invalid_parameter"; + break; + case Action_failed: + Errstr = "Action_failed"; + break; + default: + Errstr = "unknown_failed"; + break; + } + return Errstr; + +} + + + + + + + + diff --git a/examples/bluetooth/ble_ancs/main/ble_ancs.h b/examples/bluetooth/ble_ancs/main/ble_ancs.h new file mode 100644 index 0000000000..64608ea029 --- /dev/null +++ b/examples/bluetooth/ble_ancs/main/ble_ancs.h @@ -0,0 +1,124 @@ +/* + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + + +#include +#include +#include + +//EventID values +typedef enum { + EventIDNotificationAdded = 0, + EventIDNotificationModified = 1, + EventIDNotificationRemoved = 2, + //Reserved EventID values = 3–255 +} esp_EventID; + +//EventFlags +typedef enum { + EventFlagSilent = (1 << 0), + EventFlagImportant = (1 << 1), + EventFlagPreExisting = (1 << 2), + EventFlagPositiveAction = (1 << 3), + EventFlagNegativeAction = (1 << 4), + //Reserved EventFlags = (1 << 5)–(1 << 7 +}esp_EventFlags; + +// CategoryID values +typedef enum { + CategoryIDOther = 0, + CategoryIDIncomingCall = 1, + CategoryIDMissedCall = 2, + CategoryIDVoicemail = 3, + CategoryIDSocial = 4, + CategoryIDSchedule = 5, + CategoryIDEmail = 6, + CategoryIDNews = 7, + CategoryIDHealthAndFitness = 8, + CategoryIDBusinessAndFinance = 9, + CategoryIDLocation = 10, + CategoryIDEntertainment = 11, + //Reserved CategoryID values = 12–255 +} esp_CategoryID; + +//CommandID values +typedef enum { + CommandIDGetNotificationAttributes = 0, + CommandIDGetAppAttributes = 1, + CommandIDPerformNotificationAction = 2, + //Reserved CommandID values = 3–255 +} esp_CommandID; + +//NotificationAttributeID +typedef enum { + NotificationAttributeIDAppIdentifier = 0, + NotificationAttributeIDTitle = 1, //(Needs to be followed by a 2-bytes max length parameter) + NotificationAttributeIDSubtitle = 2, //(Needs to be followed by a 2-bytes max length parameter) + NotificationAttributeIDMessage = 3, //(Needs to be followed by a 2-bytes max length parameter) + NotificationAttributeIDMessageSize = 4, + NotificationAttributeIDDate = 5, + NotificationAttributeIDPositiveActionLabel = 6, + NotificationAttributeIDNegativeActionLabel = 7, + //Reserved NotificationAttributeID values = 8–255 +} esp_NotificationAttributeID; + +/* +Note: The format of the NotificationAttributeIDMessageSize constant is a string that represents the integral value +of the message size. The format of the NotificationAttributeIDDate constant is a string that uses the Unicode Technical +Standard (UTS) #35 date format pattern yyyyMMdd'T'HHmmSS. The format of all the other constants in Table 3-5 are UTF-8 +strings. +*/ + +//ActionID values +typedef enum { + ActionIDPositive = 0, + ActionIDNegative = 1, + //Reserved ActionID values = 2–255 +} esp_ActionID; + +//AppAttributeID Values +typedef enum { + AppAttributeIDDisplayName = 0, + //Reserved AppAttributeID values = 1–255 +} esp_AppAttributeID; + +typedef struct { + uint8_t noti_attribute_id; + uint16_t attribute_len; +} esp_noti_attr_list_t; + +typedef enum { + Unknown_command = (0xA0), //The commandID was not recognized by the NP. + Invalid_command = (0xA1), //The command was improperly formatted. + Invalid_parameter = (0xA2), // One of the parameters (for example, the NotificationUID) does not refer to an existing object on the NP. + Action_failed = (0xA3), //The action was not performed +} esp_error_code; + +typedef enum { + attr_appidentifier_index = 0, //The commandID was not recognized by the NP. + attr_title_index, + attr_subtitle_index, + attr_message_index, + attr_messagesize_index, + attr_date_index, + attr_positiveactionlabel_index, + attr_negativeactionlabel_index, +} esp_attr_index; + +#define ESP_NOTIFICATIONUID_LEN 4 + + +char *EventID_to_String(uint8_t EventID); +char *CategoryID_to_String(uint8_t CategoryID); +void esp_receive_apple_notification_source(uint8_t *message, uint16_t message_len); +void esp_receive_apple_data_source(uint8_t *message, uint16_t message_len); +char *Errcode_to_String(uint16_t status); + + + + diff --git a/examples/bluetooth/ble_ancs/main/ble_ancs_demo.c b/examples/bluetooth/ble_ancs/main/ble_ancs_demo.c new file mode 100644 index 0000000000..28ca4629fc --- /dev/null +++ b/examples/bluetooth/ble_ancs/main/ble_ancs_demo.c @@ -0,0 +1,688 @@ +/* + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_system.h" +#include "esp_log.h" +#include "nvs_flash.h" +#include "esp_bt.h" + +#include "esp_gap_ble_api.h" +#include "esp_gatts_api.h" +#include "esp_bt_defs.h" +#include "esp_bt_main.h" +#include "esp_gattc_api.h" +#include "esp_gatt_defs.h" +#include "esp_gatt_common_api.h" +#include "ble_ancs.h" + +#define BLE_ANCS_TAG "BLE_ANCS" +#define EXCAMPLE_DEVICE_NAME "ESP_BLE_ANCS" +#define PROFILE_A_APP_ID 0 +#define PROFILE_NUM 1 +#define ADV_CONFIG_FLAG (1 << 0) +#define SCAN_RSP_CONFIG_FLAG (1 << 1) +#define INVALID_HANDLE 0 +static uint8_t adv_config_done = 0; +static bool get_service = false; +static esp_gattc_char_elem_t *char_elem_result = NULL; +static esp_gattc_descr_elem_t *descr_elem_result = NULL; +static void periodic_timer_callback(void* arg); +esp_timer_handle_t periodic_timer; + +const esp_timer_create_args_t periodic_timer_args = { + .callback = &periodic_timer_callback, + /* name is optional, but may help identify the timer when debugging */ + .name = "periodic" +}; + +struct data_source_buffer { + uint8_t buffer[1024]; + uint16_t len; +}; + +static struct data_source_buffer data_buffer = {0}; + +//In its basic form, the ANCS exposes three characteristics: +// service UUID: 7905F431-B5CE-4E99-A40F-4B1E122D00D0 +uint8_t Apple_NC_UUID[16] = {0xD0, 0x00, 0x2D, 0x12, 0x1E, 0x4B, 0x0F, 0xA4, 0x99, 0x4E, 0xCE, 0xB5, 0x31, 0xF4, 0x05, 0x79}; +// Notification Source UUID: 9FBF120D-6301-42D9-8C58-25E699A21DBD(notifiable) +uint8_t notification_source[16] = {0xbd, 0x1d, 0xa2, 0x99, 0xe6, 0x25, 0x58, 0x8c, 0xd9, 0x42, 0x01, 0x63, 0x0d, 0x12, 0xbf, 0x9f}; +// Control Point UUID:69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9(writeable with response) +uint8_t control_point[16] = {0xd9, 0xd9, 0xaa, 0xfd, 0xbd, 0x9b, 0x21, 0x98, 0xa8, 0x49, 0xe1, 0x45, 0xf3, 0xd8, 0xd1, 0x69}; +// Data Source UUID:22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB(notifiable) +uint8_t data_source[16] = {0xfb, 0x7b, 0x7c, 0xce, 0x6a, 0xb3, 0x44, 0xbe, 0xb5, 0x4b, 0xd6, 0x24, 0xe9, 0xc6, 0xea, 0x22}; + +/* +Note: There may be more characteristics present in the ANCS than the three listed above. That said, an NC may ignore any characteristic it does not recognize. +*/ + +static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param); + +static esp_bt_uuid_t apple_nc_uuid = { + .len = ESP_UUID_LEN_128, +}; + +static uint8_t hidd_service_uuid128[] = { + /* LSB <--------------------------------------------------------------------------------> MSB */ + //first uuid, 16bit, [12],[13] is the value + 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x12, 0x18, 0x00, 0x00, +}; + +// config adv data +static esp_ble_adv_data_t adv_config = { + .set_scan_rsp = false, + .include_txpower = false, + .min_interval = 0x0006, //slave connection min interval, Time = min_interval * 1.25 msec + .max_interval = 0x0010, //slave connection max interval, Time = max_interval * 1.25 msec + .appearance = ESP_BLE_APPEARANCE_GENERIC_HID, + .service_uuid_len = sizeof(hidd_service_uuid128), + .p_service_uuid = hidd_service_uuid128, + .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT), +}; +// config scan response data +static esp_ble_adv_data_t scan_rsp_config = { + .set_scan_rsp = true, + .include_name = true, + .manufacturer_len = 0, + .p_manufacturer_data = NULL, +}; + +static esp_ble_adv_params_t adv_params = { + .adv_int_min = 0x100, + .adv_int_max = 0x100, + .adv_type = ADV_TYPE_IND, + .own_addr_type = BLE_ADDR_TYPE_RANDOM, + .channel_map = ADV_CHNL_ALL, + .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, +}; + +struct gattc_profile_inst { + esp_gattc_cb_t gattc_cb; + uint16_t gattc_if; + uint16_t app_id; + uint16_t conn_id; + uint16_t service_start_handle; + uint16_t service_end_handle; + uint16_t notification_source_handle; + uint16_t data_source_handle; + uint16_t contol_point_handle; + esp_bd_addr_t remote_bda; + uint16_t MTU_size; +}; + +static struct gattc_profile_inst gl_profile_tab[PROFILE_NUM] = { + [PROFILE_A_APP_ID] = { + .gattc_cb = gattc_profile_event_handler, + .gattc_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */ + }, +}; + +esp_noti_attr_list_t p_attr[8] = { + [attr_appidentifier_index] = { + .noti_attribute_id = NotificationAttributeIDAppIdentifier, + .attribute_len = 0, + }, + [attr_title_index] = { + .noti_attribute_id = NotificationAttributeIDTitle, + .attribute_len = 0xFFFF, + }, + [attr_subtitle_index] = { + .noti_attribute_id = NotificationAttributeIDSubtitle, + .attribute_len = 0xFFFF, + }, + [attr_message_index] = { + .noti_attribute_id = NotificationAttributeIDMessage, + .attribute_len = 0xFFFF, + }, + [attr_messagesize_index] = { + .noti_attribute_id = NotificationAttributeIDMessageSize, + .attribute_len = 0, + }, + [attr_date_index] = { + .noti_attribute_id = NotificationAttributeIDDate, + .attribute_len = 0, + }, + [attr_positiveactionlabel_index] = { + .noti_attribute_id = NotificationAttributeIDPositiveActionLabel, + .attribute_len = 0, + }, + [attr_negativeactionlabel_index] = { + .noti_attribute_id = NotificationAttributeIDNegativeActionLabel, + .attribute_len = 0, + }, + +}; + +/* + | CommandID(1 Byte) | NotificationUID(4 Bytes) | AttributeIDs | +*/ + +void esp_get_notification_attributes(uint8_t *notificationUID, uint8_t num_attr, esp_noti_attr_list_t *p_attr) +{ + uint8_t cmd[600] = {0}; + uint32_t index = 0; + cmd[0] = CommandIDGetNotificationAttributes; + index ++; + memcpy(&cmd[index], notificationUID, ESP_NOTIFICATIONUID_LEN); + index += ESP_NOTIFICATIONUID_LEN; + while(num_attr > 0) { + cmd[index ++] = p_attr->noti_attribute_id; + if (p_attr->attribute_len > 0) { + cmd[index ++] = p_attr->attribute_len; + cmd[index ++] = (p_attr->attribute_len << 8); + } + p_attr ++; + num_attr --; + } + + esp_ble_gattc_write_char( gl_profile_tab[PROFILE_A_APP_ID].gattc_if, + gl_profile_tab[PROFILE_A_APP_ID].conn_id, + gl_profile_tab[PROFILE_A_APP_ID].contol_point_handle, + index, + cmd, + ESP_GATT_WRITE_TYPE_RSP, + ESP_GATT_AUTH_REQ_NONE); +} + +void esp_get_app_attributes(uint8_t *appidentifier, uint16_t appidentifier_len, uint8_t num_attr, uint8_t *p_app_attrs) +{ + uint8_t buffer[600] = {0}; + uint32_t index = 0; + buffer[0] = CommandIDGetAppAttributes; + index ++; + memcpy(&buffer[index], appidentifier, appidentifier_len); + index += appidentifier_len; + memcpy(&buffer[index], p_app_attrs, num_attr); + index += num_attr; + + esp_ble_gattc_write_char( gl_profile_tab[PROFILE_A_APP_ID].gattc_if, + gl_profile_tab[PROFILE_A_APP_ID].conn_id, + gl_profile_tab[PROFILE_A_APP_ID].contol_point_handle, + index, + buffer, + ESP_GATT_WRITE_TYPE_RSP, + ESP_GATT_AUTH_REQ_NONE); +} + +void esp_perform_notification_action(uint8_t *notificationUID, uint8_t ActionID) +{ + uint8_t buffer[600] = {0}; + uint32_t index = 0; + buffer[0] = CommandIDPerformNotificationAction; + index ++; + memcpy(&buffer[index], notificationUID, ESP_NOTIFICATIONUID_LEN); + index += ESP_NOTIFICATIONUID_LEN; + buffer[index] = ActionID; + index ++; + esp_ble_gattc_write_char( gl_profile_tab[PROFILE_A_APP_ID].gattc_if, + gl_profile_tab[PROFILE_A_APP_ID].conn_id, + gl_profile_tab[PROFILE_A_APP_ID].contol_point_handle, + index, + buffer, + ESP_GATT_WRITE_TYPE_RSP, + ESP_GATT_AUTH_REQ_NONE); +} + +static void periodic_timer_callback(void* arg) +{ + esp_timer_stop(periodic_timer); + if (data_buffer.len > 0) { + esp_receive_apple_data_source(data_buffer.buffer, data_buffer.len); + memset(data_buffer.buffer, 0, data_buffer.len); + data_buffer.len = 0; + } +} + +static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) +{ + ESP_LOGV(BLE_ANCS_TAG, "GAP_EVT, event %d\n", event); + + switch (event) { + case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: + adv_config_done &= (~SCAN_RSP_CONFIG_FLAG); + if (adv_config_done == 0) { + esp_ble_gap_start_advertising(&adv_params); + } + break; + case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: + adv_config_done &= (~ADV_CONFIG_FLAG); + if (adv_config_done == 0) { + esp_ble_gap_start_advertising(&adv_params); + } + break; + case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: + //advertising start complete event to indicate advertising start successfully or failed + if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { + ESP_LOGE(BLE_ANCS_TAG, "advertising start failed, error status = %x", param->adv_start_cmpl.status); + break; + } + ESP_LOGI(BLE_ANCS_TAG, "advertising start success"); + break; + case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */ + ESP_LOGI(BLE_ANCS_TAG, "ESP_GAP_BLE_PASSKEY_REQ_EVT"); + /* Call the following function to input the passkey which is displayed on the remote device */ + //esp_ble_passkey_reply(heart_rate_profile_tab[HEART_PROFILE_APP_IDX].remote_bda, true, 0x00); + break; + case ESP_GAP_BLE_OOB_REQ_EVT: { + ESP_LOGI(BLE_ANCS_TAG, "ESP_GAP_BLE_OOB_REQ_EVT"); + uint8_t tk[16] = {1}; //If you paired with OOB, both devices need to use the same tk + esp_ble_oob_req_reply(param->ble_security.ble_req.bd_addr, tk, sizeof(tk)); + break; + } + case ESP_GAP_BLE_NC_REQ_EVT: + /* The app will receive this evt when the IO has DisplayYesNO capability and the peer device IO also has DisplayYesNo capability. + show the passkey number to the user to confirm it with the number displayed by peer device. */ + esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, true); + ESP_LOGI(BLE_ANCS_TAG, "ESP_GAP_BLE_NC_REQ_EVT, the passkey Notify number:%d", param->ble_security.key_notif.passkey); + break; + case ESP_GAP_BLE_SEC_REQ_EVT: + /* send the positive(true) security response to the peer device to accept the security request. + If not accept the security request, should send the security response with negative(false) accept value*/ + esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true); + break; + case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: ///the app will receive this evt when the IO has Output capability and the peer device IO has Input capability. + ///show the passkey number to the user to input it in the peer device. + ESP_LOGI(BLE_ANCS_TAG, "The passkey Notify number:%06d", param->ble_security.key_notif.passkey); + break; + case ESP_GAP_BLE_AUTH_CMPL_EVT: { + esp_log_buffer_hex("addr", param->ble_security.auth_cmpl.bd_addr, ESP_BD_ADDR_LEN); + ESP_LOGI(BLE_ANCS_TAG, "pair status = %s",param->ble_security.auth_cmpl.success ? "success" : "fail"); + if (!param->ble_security.auth_cmpl.success) { + ESP_LOGI(BLE_ANCS_TAG, "fail reason = 0x%x",param->ble_security.auth_cmpl.fail_reason); + } + break; + } + case ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVT: + if (param->local_privacy_cmpl.status != ESP_BT_STATUS_SUCCESS) { + ESP_LOGE(BLE_ANCS_TAG, "config local privacy failed, error status = %x", param->local_privacy_cmpl.status); + break; + } + + esp_err_t ret = esp_ble_gap_config_adv_data(&adv_config); + if (ret) { + ESP_LOGE(BLE_ANCS_TAG, "config adv data failed, error code = %x", ret); + } else { + adv_config_done |= ADV_CONFIG_FLAG; + } + + ret = esp_ble_gap_config_adv_data(&scan_rsp_config); + if (ret) { + ESP_LOGE(BLE_ANCS_TAG, "config adv data failed, error code = %x", ret); + } else { + adv_config_done |= SCAN_RSP_CONFIG_FLAG; + } + + break; + default: + break; + } +} + +static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) +{ + switch (event) { + case ESP_GATTC_REG_EVT: + ESP_LOGI(BLE_ANCS_TAG, "REG_EVT"); + esp_ble_gap_set_device_name(EXCAMPLE_DEVICE_NAME); + esp_ble_gap_config_local_icon (ESP_BLE_APPEARANCE_GENERIC_WATCH); + //generate a resolvable random address + esp_ble_gap_config_local_privacy(true); + break; + case ESP_GATTC_OPEN_EVT: + if (param->open.status != ESP_GATT_OK) { + ESP_LOGE(BLE_ANCS_TAG, "open failed, error status = %x", param->open.status); + break; + } + ESP_LOGI(BLE_ANCS_TAG, "ESP_GATTC_OPEN_EVT"); + gl_profile_tab[PROFILE_A_APP_ID].conn_id = param->open.conn_id; + esp_ble_set_encryption(param->open.remote_bda, ESP_BLE_SEC_ENCRYPT_MITM); + esp_err_t mtu_ret = esp_ble_gattc_send_mtu_req (gattc_if, param->open.conn_id); + if (mtu_ret) { + ESP_LOGE(BLE_ANCS_TAG, "config MTU error, error code = %x", mtu_ret); + } + break; + case ESP_GATTC_CFG_MTU_EVT: + if (param->cfg_mtu.status != ESP_GATT_OK) { + ESP_LOGE(BLE_ANCS_TAG,"config mtu failed, error status = %x", param->cfg_mtu.status); + } + ESP_LOGI(BLE_ANCS_TAG, "ESP_GATTC_CFG_MTU_EVT, Status %d, MTU %d, conn_id %d", param->cfg_mtu.status, param->cfg_mtu.mtu, param->cfg_mtu.conn_id); + gl_profile_tab[PROFILE_A_APP_ID].MTU_size = param->cfg_mtu.mtu; + memcpy(apple_nc_uuid.uuid.uuid128, Apple_NC_UUID,16); + esp_ble_gattc_search_service(gl_profile_tab[PROFILE_A_APP_ID].gattc_if, gl_profile_tab[PROFILE_A_APP_ID].conn_id, &apple_nc_uuid); + break; + case ESP_GATTC_SEARCH_RES_EVT: { + if (param->search_res.srvc_id.uuid.len == ESP_UUID_LEN_128) { + gl_profile_tab[PROFILE_A_APP_ID].service_start_handle = param->search_res.start_handle; + gl_profile_tab[PROFILE_A_APP_ID].service_end_handle = param->search_res.end_handle; + get_service = true; + } + break; + } + case ESP_GATTC_SEARCH_CMPL_EVT: + if (param->search_cmpl.status != ESP_GATT_OK) { + ESP_LOGE(BLE_ANCS_TAG, "search service failed, error status = %x", param->search_cmpl.status); + break; + } + ESP_LOGI(BLE_ANCS_TAG, "ESP_GATTC_SEARCH_CMPL_EVT"); + if (get_service) { + uint16_t count = 0; + uint16_t offset = 0; + esp_gatt_status_t ret_status = esp_ble_gattc_get_attr_count(gattc_if, + gl_profile_tab[PROFILE_A_APP_ID].conn_id, + ESP_GATT_DB_CHARACTERISTIC, + gl_profile_tab[PROFILE_A_APP_ID].service_start_handle, + gl_profile_tab[PROFILE_A_APP_ID].service_end_handle, + INVALID_HANDLE, + &count); + if (ret_status != ESP_GATT_OK) { + ESP_LOGE(BLE_ANCS_TAG, "esp_ble_gattc_get_attr_count error, %d", __LINE__); + } + if (count > 0) { + char_elem_result = (esp_gattc_char_elem_t *)malloc(sizeof(esp_gattc_char_elem_t) * count); + memset(char_elem_result, 0xff, sizeof(esp_gattc_char_elem_t) * count); + if (!char_elem_result) { + ESP_LOGE(BLE_ANCS_TAG, "gattc no mem"); + } else { + ret_status = esp_ble_gattc_get_all_char(gattc_if, + gl_profile_tab[PROFILE_A_APP_ID].conn_id, + gl_profile_tab[PROFILE_A_APP_ID].service_start_handle, + gl_profile_tab[PROFILE_A_APP_ID].service_end_handle, + char_elem_result, + &count, + offset); + if (ret_status != ESP_GATT_OK) { + ESP_LOGE(BLE_ANCS_TAG, "esp_ble_gattc_get_all_char error, %d", __LINE__); + } + if (count > 0) { + + for (int i = 0; i < count; i ++) { + if (char_elem_result[i].uuid.len == ESP_UUID_LEN_128) { + if (char_elem_result[i].properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY + && memcmp(char_elem_result[i].uuid.uuid.uuid128, notification_source, 16) == 0) { + gl_profile_tab[PROFILE_A_APP_ID].notification_source_handle = char_elem_result[i].char_handle; + esp_ble_gattc_register_for_notify (gattc_if, + gl_profile_tab[PROFILE_A_APP_ID].remote_bda, + char_elem_result[i].char_handle); + ESP_LOGI(BLE_ANCS_TAG, "Find Apple noticification source char"); + + } else if (char_elem_result[i].properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY + && memcmp(char_elem_result[i].uuid.uuid.uuid128, data_source, 16) == 0) { + gl_profile_tab[PROFILE_A_APP_ID].data_source_handle = char_elem_result[i].char_handle; + esp_ble_gattc_register_for_notify (gattc_if, + gl_profile_tab[PROFILE_A_APP_ID].remote_bda, + char_elem_result[i].char_handle); + ESP_LOGI(BLE_ANCS_TAG, "Find Apple data source char"); + + } else if (char_elem_result[i].properties & ESP_GATT_CHAR_PROP_BIT_WRITE + && memcmp(char_elem_result[i].uuid.uuid.uuid128, control_point, 16) == 0) { + gl_profile_tab[PROFILE_A_APP_ID].contol_point_handle = char_elem_result[i].char_handle; + ESP_LOGI(BLE_ANCS_TAG, "Find Apple control point char"); + + } + } + } + } + } + free(char_elem_result); + } + } else { + ESP_LOGE(BLE_ANCS_TAG, "No Apple Notification Service found"); + } + + break; + case ESP_GATTC_REG_FOR_NOTIFY_EVT: { + if (param->reg_for_notify.status != ESP_GATT_OK) { + ESP_LOGI(BLE_ANCS_TAG, "ESP_GATTC_REG_FOR_NOTIFY_EVT status %d", param->reg_for_notify.status); + break; + } + uint16_t count = 0; + uint16_t offset = 0; + //uint16_t notify_en = 1; + uint8_t notify_en[2] = {0x01, 0x00}; + esp_gatt_status_t ret_status = esp_ble_gattc_get_attr_count(gattc_if, + gl_profile_tab[PROFILE_A_APP_ID].conn_id, + ESP_GATT_DB_DESCRIPTOR, + gl_profile_tab[PROFILE_A_APP_ID].service_start_handle, + gl_profile_tab[PROFILE_A_APP_ID].service_end_handle, + param->reg_for_notify.handle, + &count); + if (ret_status != ESP_GATT_OK) { + ESP_LOGE(BLE_ANCS_TAG, "esp_ble_gattc_get_attr_count error, %d", __LINE__); + } + if (count > 0) { + descr_elem_result = malloc(sizeof(esp_gattc_descr_elem_t) * count); + if (!descr_elem_result) { + ESP_LOGE(BLE_ANCS_TAG, "malloc error, gattc no mem"); + } else { + ret_status = esp_ble_gattc_get_all_descr(gattc_if, + gl_profile_tab[PROFILE_A_APP_ID].conn_id, + param->reg_for_notify.handle, + descr_elem_result, + &count, + offset); + if (ret_status != ESP_GATT_OK) { + ESP_LOGE(BLE_ANCS_TAG, "esp_ble_gattc_get_all_descr error, %d", __LINE__); + } + + for (int i = 0; i < count; ++ i) { + if (descr_elem_result[i].uuid.len == ESP_UUID_LEN_16 && descr_elem_result[i].uuid.uuid.uuid16 == ESP_GATT_UUID_CHAR_CLIENT_CONFIG) { + esp_ble_gattc_write_char_descr (gattc_if, + gl_profile_tab[PROFILE_A_APP_ID].conn_id, + descr_elem_result[i].handle, + sizeof(notify_en), + (uint8_t *)¬ify_en, + ESP_GATT_WRITE_TYPE_RSP, + ESP_GATT_AUTH_REQ_NONE); + + break; + } + } + } + free(descr_elem_result); + } + break; + } + case ESP_GATTC_NOTIFY_EVT: + //esp_log_buffer_hex(BLE_ANCS_TAG, param->notify.value, param->notify.value_len); + if (param->notify.handle == gl_profile_tab[PROFILE_A_APP_ID].notification_source_handle) { + esp_receive_apple_notification_source(param->notify.value, param->notify.value_len); + uint8_t *notificationUID = ¶m->notify.value[4]; + if (param->notify.value[0] == EventIDNotificationAdded && param->notify.value[2] == CategoryIDIncomingCall) { + ESP_LOGI(BLE_ANCS_TAG, "IncomingCall, reject"); + //Call reject + esp_perform_notification_action(notificationUID, ActionIDNegative); + } else if (param->notify.value[0] == EventIDNotificationAdded) { + //get more information + ESP_LOGI(BLE_ANCS_TAG, "Get detailed information"); + esp_get_notification_attributes(notificationUID, sizeof(p_attr)/sizeof(esp_noti_attr_list_t), p_attr); + } + } else if (param->notify.handle == gl_profile_tab[PROFILE_A_APP_ID].data_source_handle) { + memcpy(&data_buffer.buffer[data_buffer.len], param->notify.value, param->notify.value_len); + data_buffer.len += param->notify.value_len; + if (param->notify.value_len == (gl_profile_tab[PROFILE_A_APP_ID].MTU_size - 3)) { + // cpoy and wait next packet, start timer 500ms + esp_timer_start_periodic(periodic_timer, 500000); + } else { + esp_timer_stop(periodic_timer); + esp_receive_apple_data_source(data_buffer.buffer, data_buffer.len); + memset(data_buffer.buffer, 0, data_buffer.len); + data_buffer.len = 0; + } + } else { + ESP_LOGI(BLE_ANCS_TAG, "unknown handle, receive notify value:"); + } + break; + case ESP_GATTC_WRITE_DESCR_EVT: + if (param->write.status != ESP_GATT_OK) { + ESP_LOGE(BLE_ANCS_TAG, "write descr failed, error status = %x", param->write.status); + break; + } + //ESP_LOGI(BLE_ANCS_TAG, "write descr successfully"); + break; + case ESP_GATTC_SRVC_CHG_EVT: { + ESP_LOGI(BLE_ANCS_TAG, "ESP_GATTC_SRVC_CHG_EVT, bd_addr:"); + esp_log_buffer_hex(BLE_ANCS_TAG, param->srvc_chg.remote_bda, 6); + break; + } + case ESP_GATTC_WRITE_CHAR_EVT: + if (param->write.status != ESP_GATT_OK) { + char *Errstr = Errcode_to_String(param->write.status); + if (Errstr) { + ESP_LOGE(BLE_ANCS_TAG, "write control point error %s", Errstr); + } + break; + } + //ESP_LOGI(BLE_ANCS_TAG, "Write char success "); + break; + case ESP_GATTC_DISCONNECT_EVT: + ESP_LOGI(BLE_ANCS_TAG, "ESP_GATTC_DISCONNECT_EVT, reason = 0x%x", param->disconnect.reason); + get_service = false; + esp_ble_gap_start_advertising(&adv_params); + break; + case ESP_GATTC_CONNECT_EVT: + //ESP_LOGI(BLE_ANCS_TAG, "ESP_GATTC_CONNECT_EVT"); + //esp_log_buffer_hex("bda", param->connect.remote_bda, 6); + memcpy(gl_profile_tab[PROFILE_A_APP_ID].remote_bda, param->connect.remote_bda, 6); + // create gattc virtual connection + esp_ble_gattc_open(gl_profile_tab[PROFILE_A_APP_ID].gattc_if, gl_profile_tab[PROFILE_A_APP_ID].remote_bda, BLE_ADDR_TYPE_RANDOM, true); + break; + case ESP_GATTC_DIS_SRVC_CMPL_EVT: + ESP_LOGI(BLE_ANCS_TAG, "ESP_GATTC_DIS_SRVC_CMPL_EVT"); + break; + default: + break; + } +} + +static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) +{ + /* If event is register event, store the gattc_if for each profile */ + if (event == ESP_GATTC_REG_EVT) { + if (param->reg.status == ESP_GATT_OK) { + gl_profile_tab[param->reg.app_id].gattc_if = gattc_if; + } else { + ESP_LOGI(BLE_ANCS_TAG, "Reg app failed, app_id %04x, status %d", + param->reg.app_id, + param->reg.status); + return; + } + } + + /* If the gattc_if equal to profile A, call profile A cb handler, + * so here call each profile's callback */ + do { + int idx; + for (idx = 0; idx < PROFILE_NUM; idx++) { + if (gattc_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */ + gattc_if == gl_profile_tab[idx].gattc_if) { + if (gl_profile_tab[idx].gattc_cb) { + gl_profile_tab[idx].gattc_cb(event, gattc_if, param); + } + } + } + } while (0); +} + +void init_timer(void) +{ + ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer)); +} + +void app_main() +{ + esp_err_t ret; + + // Initialize NVS. + ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK( ret ); + + // init timer + init_timer(); + + ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)); + + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + ret = esp_bt_controller_init(&bt_cfg); + if (ret) { + ESP_LOGE(BLE_ANCS_TAG, "%s init controller failed: %s", __func__, esp_err_to_name(ret)); + return; + } + ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); + if (ret) { + ESP_LOGE(BLE_ANCS_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret)); + return; + } + + ESP_LOGI(BLE_ANCS_TAG, "%s init bluetooth", __func__); + ret = esp_bluedroid_init(); + if (ret) { + ESP_LOGE(BLE_ANCS_TAG, "%s init bluetooth failed: %s", __func__, esp_err_to_name(ret)); + return; + } + ret = esp_bluedroid_enable(); + if (ret) { + ESP_LOGE(BLE_ANCS_TAG, "%s enable bluetooth failed: %s", __func__, esp_err_to_name(ret)); + return; + } + + //register the callback function to the gattc module + ret = esp_ble_gattc_register_callback(esp_gattc_cb); + if (ret) { + ESP_LOGE(BLE_ANCS_TAG, "%s gattc register error, error code = %x\n", __func__, ret); + return; + } + + ret = esp_ble_gap_register_callback(gap_event_handler); + if (ret) { + ESP_LOGE(BLE_ANCS_TAG, "gap register error, error code = %x", ret); + return; + } + + ret = esp_ble_gattc_app_register(PROFILE_A_APP_ID); + if (ret) { + ESP_LOGE(BLE_ANCS_TAG, "%s gattc app register error, error code = %x\n", __func__, ret); + } + + ret = esp_ble_gatt_set_local_mtu(500); + if (ret) { + ESP_LOGE(BLE_ANCS_TAG, "set local MTU failed, error code = %x", ret); + } + + /* set the security iocap & auth_req & key size & init key response key parameters to the stack*/ + esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND; //bonding with peer device after authentication + esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE; //set the IO capability to No output No input + uint8_t key_size = 16; //the key size should be 7~16 bytes + uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; + uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; + //set static passkey + uint32_t passkey = 123456; + uint8_t auth_option = ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_DISABLE; + uint8_t oob_support = ESP_BLE_OOB_DISABLE; + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH, &auth_option, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_OOB_SUPPORT, &oob_support, sizeof(uint8_t)); + /* If your BLE device acts as a Slave, the init_key means you hope which types of key of the master should distribute to you, + and the response key means which key you can distribute to the master; + If your BLE device acts as a master, the response key means you hope which types of key of the slave should distribute to you, + and the init key means which key you can distribute to the slave. */ + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t)); +} + + + diff --git a/examples/bluetooth/ble_ancs/main/component.mk b/examples/bluetooth/ble_ancs/main/component.mk new file mode 100644 index 0000000000..f2f38c36c0 --- /dev/null +++ b/examples/bluetooth/ble_ancs/main/component.mk @@ -0,0 +1,9 @@ +# +# Main Makefile. This is basically the same as a component makefile. +# +# This Makefile should, at the very least, just include $(SDK_PATH)/make/component_common.mk. By default, +# this will take the sources in the src/ directory, compile them and link them into +# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, +# please read the ESP-IDF documents if you need to do this. +# + diff --git a/examples/bluetooth/ble_ancs/sdkconfig.defaults b/examples/bluetooth/ble_ancs/sdkconfig.defaults new file mode 100644 index 0000000000..50fc4ba9d8 --- /dev/null +++ b/examples/bluetooth/ble_ancs/sdkconfig.defaults @@ -0,0 +1,6 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y +CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY= +CONFIG_BTDM_CONTROLLER_MODE_BTDM= From faf23df19ac936710b12d36d56683d0bf0468189 Mon Sep 17 00:00:00 2001 From: baohongde Date: Fri, 14 Sep 2018 17:24:25 +0800 Subject: [PATCH 075/486] component/bt : modify OSI thread of bluedroid abstract of OSI thread to make bluedroid more compatible with different OS. --- components/bt/CMakeLists.txt | 1 + .../bt/bluedroid/bta/sys/bta_sys_main.c | 5 +- components/bt/bluedroid/btc/core/btc_task.c | 77 ++--- .../btc/profile/std/a2dp/btc_a2dp_sink.c | 132 +++----- .../btc/profile/std/a2dp/btc_a2dp_source.c | 133 +++------ .../common/include/common/bt_target.h | 8 + components/bt/bluedroid/hci/hci_hal_h4.c | 52 ++-- components/bt/bluedroid/hci/hci_layer.c | 83 ++---- .../bt/bluedroid/hci/include/hci/hci_layer.h | 3 + .../bt/bluedroid/osi/include/osi/thread.h | 92 ++---- components/bt/bluedroid/osi/thread.c | 282 ++++++++++++++++++ components/bt/bluedroid/stack/btu/btu_hcif.c | 4 +- components/bt/bluedroid/stack/btu/btu_init.c | 40 +-- components/bt/bluedroid/stack/btu/btu_task.c | 99 +++--- .../bt/bluedroid/stack/include/stack/btu.h | 14 + 15 files changed, 581 insertions(+), 444 deletions(-) create mode 100644 components/bt/bluedroid/osi/thread.c diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index e1d1fef01c..73f6879039 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -189,6 +189,7 @@ if(CONFIG_BT_ENABLED) "bluedroid/osi/mutex.c" "bluedroid/osi/osi.c" "bluedroid/osi/semaphore.c" + "bluedroid/osi/thread.c" "bluedroid/stack/a2dp/a2d_api.c" "bluedroid/stack/a2dp/a2d_sbc.c" "bluedroid/stack/avct/avct_api.c" diff --git a/components/bt/bluedroid/bta/sys/bta_sys_main.c b/components/bt/bluedroid/bta/sys/bta_sys_main.c index e3b8c77fa9..c9a7f450f4 100644 --- a/components/bt/bluedroid/bta/sys/bta_sys_main.c +++ b/components/bt/bluedroid/bta/sys/bta_sys_main.c @@ -29,6 +29,7 @@ #include "osi/alarm.h" #include "osi/thread.h" #include "stack/btm_api.h" +#include "stack/btu.h" #include "bta/bta_api.h" #include "bta/bta_sys.h" #include "bta_sys_int.h" @@ -571,7 +572,7 @@ void bta_sys_sendmsg(void *p_msg) // there is a procedure in progress that can schedule a task via this // message queue. This causes |btu_bta_msg_queue| to get cleaned up before // it gets used here; hence we check for NULL before using it. - if (btu_task_post(SIG_BTU_BTA_MSG, p_msg, TASK_POST_BLOCKING) != TASK_POST_SUCCESS) { + if (btu_task_post(SIG_BTU_BTA_MSG, p_msg, OSI_THREAD_BLOCKING) == false) { osi_free(p_msg); } } @@ -591,7 +592,7 @@ void bta_alarm_cb(void *data) assert(data != NULL); TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *)data; - btu_task_post(SIG_BTU_BTA_ALARM, p_tle, TASK_POST_BLOCKING); + btu_task_post(SIG_BTU_BTA_ALARM, p_tle, OSI_THREAD_BLOCKING); } void bta_sys_start_timer(TIMER_LIST_ENT *p_tle, UINT16 type, INT32 timeout_ms) diff --git a/components/bt/bluedroid/btc/core/btc_task.c b/components/bt/bluedroid/btc/core/btc_task.c index 86d2b4a63e..2787bc2056 100644 --- a/components/bt/bluedroid/btc/core/btc_task.c +++ b/components/bt/bluedroid/btc/core/btc_task.c @@ -47,9 +47,13 @@ #endif /* #if BTC_HF_CLIENT_INCLUDED */ #endif /* #if CONFIG_BT_CLASSIC_ENABLED */ +#define BTC_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) +#define BTC_TASK_STACK_SIZE (CONFIG_BTC_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) //by menuconfig +#define BTC_TASK_NAME "btcT" +#define BTC_TASK_PRIO (configMAX_PRIORITIES - 6) +#define BTC_TASK_QUEUE_LEN 60 -static xTaskHandle xBtcTaskHandle = NULL; -static xQueueHandle xBtcQueue = 0; +static osi_thread_t *btc_thread; static btc_func_t profile_tab[BTC_PID_NUM] = { [BTC_PID_MAIN_INIT] = {btc_main_call_handler, NULL }, @@ -96,38 +100,40 @@ static btc_func_t profile_tab[BTC_PID_NUM] = { ** ** Description Process profile Task Thread. ******************************************************************************/ -static void btc_task(void *arg) +static void btc_thread_handler(void *arg) { - btc_msg_t msg; + btc_msg_t *msg = (btc_msg_t *)arg; - for (;;) { - if (pdTRUE == xQueueReceive(xBtcQueue, &msg, (portTickType)portMAX_DELAY)) { - BTC_TRACE_DEBUG("%s msg %u %u %u %p\n", __func__, msg.sig, msg.pid, msg.act, msg.arg); - switch (msg.sig) { - case BTC_SIG_API_CALL: - profile_tab[msg.pid].btc_call(&msg); - break; - case BTC_SIG_API_CB: - profile_tab[msg.pid].btc_cb(&msg); - break; - default: - break; - } - if (msg.arg) { - osi_free(msg.arg); - } - } + BTC_TRACE_DEBUG("%s msg %u %u %u %p\n", __func__, msg->sig, msg->pid, msg->act, msg->arg); + switch (msg->sig) { + case BTC_SIG_API_CALL: + profile_tab[msg->pid].btc_call(msg); + break; + case BTC_SIG_API_CB: + profile_tab[msg->pid].btc_cb(msg); + break; + default: + break; } + + if (msg->arg) { + osi_free(msg->arg); + } + osi_free(msg); } -static bt_status_t btc_task_post(btc_msg_t *msg, task_post_t timeout) +static bt_status_t btc_task_post(btc_msg_t *msg, osi_thread_blocking_t blocking) { - if (msg == NULL) { - return BT_STATUS_PARM_INVALID; + btc_msg_t *lmsg; + + lmsg = (btc_msg_t *)osi_malloc(sizeof(btc_msg_t)); + if (lmsg == NULL) { + return BT_STATUS_NOMEM; } - if (xQueueSend(xBtcQueue, msg, timeout) != pdTRUE) { - BTC_TRACE_ERROR("Btc Post failed\n"); + memcpy(lmsg, msg, sizeof(btc_msg_t)); + + if (osi_thread_post(btc_thread, btc_thread_handler, lmsg, 0, blocking) == false) { return BT_STATUS_BUSY; } @@ -159,17 +165,18 @@ bt_status_t btc_transfer_context(btc_msg_t *msg, void *arg, int arg_len, btc_arg lmsg.arg = NULL; } - return btc_task_post(&lmsg, TASK_POST_BLOCKING); + return btc_task_post(&lmsg, OSI_THREAD_BLOCKING); + } int btc_init(void) { - xBtcQueue = xQueueCreate(BTC_TASK_QUEUE_LEN, sizeof(btc_msg_t)); - xTaskCreatePinnedToCore(btc_task, "Btc_task", BTC_TASK_STACK_SIZE, NULL, BTC_TASK_PRIO, &xBtcTaskHandle, BTC_TASK_PINNED_TO_CORE); - if (xBtcTaskHandle == NULL || xBtcQueue == 0){ + btc_thread = osi_thread_create("BTC_TASK", BTC_TASK_STACK_SIZE, BTC_TASK_PRIO, BTC_TASK_PINNED_TO_CORE, 1); + if (btc_thread == NULL) { return BT_STATUS_NOMEM; } + btc_gap_callback_init(); #if SCAN_QUEUE_CONGEST_CHECK btc_adv_list_init(); @@ -180,20 +187,18 @@ int btc_init(void) void btc_deinit(void) { - vTaskDelete(xBtcTaskHandle); - vQueueDelete(xBtcQueue); + osi_thread_free(btc_thread); + btc_thread = NULL; #if SCAN_QUEUE_CONGEST_CHECK btc_adv_list_deinit(); #endif - xBtcTaskHandle = NULL; - xBtcQueue = 0; } bool btc_check_queue_is_congest(void) { - UBaseType_t wait_size = uxQueueMessagesWaiting(xBtcQueue); - if(wait_size >= QUEUE_CONGEST_SIZE) { + if (osi_thread_queue_wait_size(btc_thread, 0) >= QUEUE_CONGEST_SIZE) { return true; } + return false; } diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c index a5d09b2ca1..c8e1ec9c90 100644 --- a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c +++ b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c @@ -45,6 +45,13 @@ #if (BTC_AV_SINK_INCLUDED == TRUE) +/* Macro */ +#define BTC_A2DP_SINK_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) +#define BTC_A2DP_SINK_TASK_STACK_SIZE (CONFIG_A2DP_SINK_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) // by menuconfig +#define BTC_A2DP_SINK_TASK_NAME "BtA2dSinkT" +#define BTC_A2DP_SINK_TASK_PRIO (configMAX_PRIORITIES - 3) + + /***************************************************************************** ** Constants *****************************************************************************/ @@ -64,10 +71,6 @@ enum { BTC_A2DP_SINK_STATE_SHUTTING_DOWN = 2 }; -enum { - BTC_A2DP_SINK_DATA_EVT = 0, -}; - /* * CONGESTION COMPENSATION CTRL :: * @@ -90,6 +93,11 @@ enum { /* 18 frames is equivalent to 6.89*18*2.9 ~= 360 ms @ 44.1 khz, 20 ms mediatick */ #define MAX_OUTPUT_A2DP_SNK_FRAME_QUEUE_SZ (18) +typedef struct { + uint32_t sig; + void *param; +} a2dp_sink_task_evt_t; + typedef struct { UINT16 num_frames_to_be_processed; UINT16 len; @@ -115,18 +123,15 @@ static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg); static void btc_a2dp_sink_handle_decoder_reset(tBTC_MEDIA_SINK_CFG_UPDATE *p_msg); static void btc_a2dp_sink_handle_clear_track(void); static BOOLEAN btc_a2dp_sink_clear_track(void); -static void btc_a2dp_sink_task_handler(void *arg); -static void btc_a2dp_sink_data_ready(UNUSED_ATTR void *context); +static void btc_a2dp_sink_ctrl_handler(void *arg); + +static void btc_a2dp_sink_data_ready(void *context); static tBTC_A2DP_SINK_CB btc_aa_snk_cb; static int btc_a2dp_sink_state = BTC_A2DP_SINK_STATE_OFF; static future_t *btc_a2dp_sink_future = NULL; -static xTaskHandle btc_aa_snk_task_hdl = NULL; -static QueueHandle_t btc_aa_snk_data_queue = NULL; -static QueueHandle_t btc_aa_snk_ctrl_queue = NULL; -static QueueSetHandle_t btc_aa_snk_queue_set; - +static osi_thread_t *btc_aa_snk_task_hdl = NULL; static esp_a2d_sink_data_cb_t bt_aa_snk_data_cb = NULL; void btc_a2dp_sink_reg_data_cb(esp_a2d_sink_data_cb_t callback) @@ -174,26 +179,28 @@ static inline void btc_a2d_cb_to_app(esp_a2d_cb_event_t event, esp_a2d_cb_param_ ** BTC ADAPTATION *****************************************************************************/ -static void btc_a2dp_sink_ctrl_post(uint32_t sig, void *par) +static bool btc_a2dp_sink_ctrl_post(uint32_t sig, void *param) { - BtTaskEvt_t *evt = (BtTaskEvt_t *)osi_malloc(sizeof(BtTaskEvt_t)); + a2dp_sink_task_evt_t *evt = (a2dp_sink_task_evt_t *)osi_malloc(sizeof(a2dp_sink_task_evt_t)); + if (evt == NULL) { - return; + return false; } evt->sig = sig; - evt->par = par; + evt->param = param; - if (xQueueSend(btc_aa_snk_ctrl_queue, &evt, portMAX_DELAY) != pdTRUE) { - APPL_TRACE_WARNING("btc_aa_snk_ctrl_queue failed, sig 0x%x\n", sig); - } + return osi_thread_post(btc_aa_snk_task_hdl, btc_a2dp_sink_ctrl_handler, evt, 0, OSI_THREAD_BLOCKING); } -static void btc_a2dp_sink_ctrl_handler(BtTaskEvt_t *e) +static void btc_a2dp_sink_ctrl_handler(void *arg) { + a2dp_sink_task_evt_t *e = (a2dp_sink_task_evt_t *)arg; + if (e == NULL) { return; } + switch (e->sig) { case BTC_MEDIA_TASK_SINK_INIT: btc_a2dp_sink_thread_init(NULL); @@ -202,7 +209,7 @@ static void btc_a2dp_sink_ctrl_handler(BtTaskEvt_t *e) btc_a2dp_sink_thread_cleanup(NULL); break; case BTC_MEDIA_AUDIO_SINK_CFG_UPDATE: - btc_a2dp_sink_handle_decoder_reset(e->par); + btc_a2dp_sink_handle_decoder_reset(e->param); break; case BTC_MEDIA_AUDIO_SINK_CLEAR_TRACK: btc_a2dp_sink_handle_clear_track(); @@ -213,29 +220,12 @@ static void btc_a2dp_sink_ctrl_handler(BtTaskEvt_t *e) default: APPL_TRACE_WARNING("media task unhandled evt: 0x%x\n", e->sig); } - if (e->par != NULL) { - osi_free(e->par); - } -} -static void btc_a2dp_sink_task_handler(void *arg) -{ - QueueSetMemberHandle_t xActivatedMember; - BtTaskEvt_t *e = NULL; - for (;;) { - xActivatedMember = xQueueSelectFromSet(btc_aa_snk_queue_set, portMAX_DELAY); - if (xActivatedMember == btc_aa_snk_data_queue) { - int32_t data_evt; - xQueueReceive(xActivatedMember, &data_evt, 0); - if (data_evt == BTC_A2DP_SINK_DATA_EVT) { - btc_a2dp_sink_data_ready(NULL); - } - } else if (xActivatedMember == btc_aa_snk_ctrl_queue) { - xQueueReceive(xActivatedMember, &e, 0); - btc_a2dp_sink_ctrl_handler(e); - osi_free(e); - } + if (e->param != NULL) { + osi_free(e->param); } + + osi_free(e); } bool btc_a2dp_sink_startup(void) @@ -257,26 +247,14 @@ bool btc_a2dp_sink_startup(void) } #endif /* BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE */ - btc_aa_snk_queue_set = xQueueCreateSet(BTC_A2DP_SINK_TASK_QUEUE_SET_LEN); - configASSERT(btc_aa_snk_queue_set); - btc_aa_snk_data_queue = xQueueCreate(BTC_A2DP_SINK_DATA_QUEUE_LEN, sizeof(int32_t)); - configASSERT(btc_aa_snk_data_queue); - xQueueAddToSet(btc_aa_snk_data_queue, btc_aa_snk_queue_set); - - btc_aa_snk_ctrl_queue = xQueueCreate(BTC_A2DP_SINK_CTRL_QUEUE_LEN, sizeof(void *)); - configASSERT(btc_aa_snk_ctrl_queue); - xQueueAddToSet(btc_aa_snk_ctrl_queue, btc_aa_snk_queue_set); - - if (!btc_aa_snk_data_queue || !btc_aa_snk_ctrl_queue || !btc_aa_snk_queue_set ) { - goto error_exit; - } - - xTaskCreatePinnedToCore(btc_a2dp_sink_task_handler, BTC_A2DP_SINK_TASK_NAME, BTC_A2DP_SINK_TASK_STACK_SIZE, NULL, BTC_A2DP_SINK_TASK_PRIO, &btc_aa_snk_task_hdl, BTC_A2DP_SINK_TASK_PINNED_TO_CORE); + btc_aa_snk_task_hdl = osi_thread_create(BTC_A2DP_SINK_TASK_NAME, BTC_A2DP_SINK_TASK_STACK_SIZE, BTC_A2DP_SINK_TASK_PRIO, BTC_A2DP_SINK_TASK_PINNED_TO_CORE, 2); if (btc_aa_snk_task_hdl == NULL) { goto error_exit; } - btc_a2dp_sink_ctrl_post(BTC_MEDIA_TASK_SINK_INIT, NULL); + if (btc_a2dp_sink_ctrl_post(BTC_MEDIA_TASK_SINK_INIT, NULL) == false) { + goto error_exit; + } APPL_TRACE_EVENT("## A2DP SINK MEDIA THREAD STARTED ##\n"); @@ -284,24 +262,11 @@ bool btc_a2dp_sink_startup(void) error_exit:; APPL_TRACE_ERROR("%s unable to start up media thread\n", __func__); - if (btc_aa_snk_task_hdl != NULL) { - vTaskDelete(btc_aa_snk_task_hdl); + osi_thread_free(btc_aa_snk_task_hdl); btc_aa_snk_task_hdl = NULL; } - if (btc_aa_snk_data_queue) { - vQueueDelete(btc_aa_snk_data_queue); - btc_aa_snk_data_queue = NULL; - } - if (btc_aa_snk_ctrl_queue) { - vQueueDelete(btc_aa_snk_ctrl_queue); - btc_aa_snk_ctrl_queue = NULL; - } - if (btc_aa_snk_queue_set) { - vQueueDelete(btc_aa_snk_queue_set); - btc_aa_snk_queue_set = NULL; - } #if (BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE) if (btc_sbc_decoder_context_ptr) { osi_free(btc_sbc_decoder_context_ptr); @@ -332,18 +297,9 @@ void btc_a2dp_sink_shutdown(void) future_await(btc_a2dp_sink_future); btc_a2dp_sink_future = NULL; - vTaskDelete(btc_aa_snk_task_hdl); + osi_thread_free(btc_aa_snk_task_hdl); btc_aa_snk_task_hdl = NULL; - vQueueDelete(btc_aa_snk_data_queue); - btc_aa_snk_data_queue = NULL; - - vQueueDelete(btc_aa_snk_ctrl_queue); - btc_aa_snk_ctrl_queue = NULL; - - vQueueDelete(btc_aa_snk_queue_set); - btc_aa_snk_queue_set = NULL; - #if (BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE) osi_free(btc_sbc_decoder_context_ptr); btc_sbc_decoder_context_ptr = NULL; @@ -397,11 +353,9 @@ void btc_a2dp_sink_on_suspended(tBTA_AV_SUSPEND *p_av) return; } -static void btc_a2dp_sink_data_post(int32_t data_type) +static void btc_a2dp_sink_data_post(void) { - if (xQueueSend(btc_aa_snk_data_queue, &data_type, 0) != pdTRUE) { - APPL_TRACE_DEBUG("Media data Q filled\n"); - } + osi_thread_post(btc_aa_snk_task_hdl, btc_a2dp_sink_data_ready, NULL, 1, OSI_THREAD_BLOCKING); } /******************************************************************************* @@ -415,8 +369,7 @@ static void btc_a2dp_sink_data_post(int32_t data_type) *******************************************************************************/ static BOOLEAN btc_a2dp_sink_clear_track(void) { - btc_a2dp_sink_ctrl_post(BTC_MEDIA_AUDIO_SINK_CLEAR_TRACK, NULL); - return TRUE; + return btc_a2dp_sink_ctrl_post(BTC_MEDIA_AUDIO_SINK_CLEAR_TRACK, NULL); } /* when true media task discards any rx frames */ @@ -685,8 +638,7 @@ BOOLEAN btc_a2dp_sink_rx_flush_req(void) return TRUE; } - btc_a2dp_sink_ctrl_post(BTC_MEDIA_FLUSH_AA_RX, NULL); - return TRUE; + return btc_a2dp_sink_ctrl_post(BTC_MEDIA_FLUSH_AA_RX, NULL); } /******************************************************************************* @@ -777,7 +729,7 @@ UINT8 btc_a2dp_sink_enque_buf(BT_HDR *p_pkt) p_msg->num_frames_to_be_processed = (*((UINT8 *)(p_msg + 1) + p_msg->offset)) & 0x0f; APPL_TRACE_VERBOSE("btc_a2dp_sink_enque_buf %d + \n", p_msg->num_frames_to_be_processed); fixed_queue_enqueue(btc_aa_snk_cb.RxSbcQ, p_msg); - btc_a2dp_sink_data_post(BTC_A2DP_SINK_DATA_EVT); + btc_a2dp_sink_data_post(); } else { /* let caller deal with a failed allocation */ APPL_TRACE_WARNING("btc_a2dp_sink_enque_buf No Buffer left - "); diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c index 64e563b440..893ade6e0d 100644 --- a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c +++ b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c @@ -50,6 +50,13 @@ #if BTC_AV_SRC_INCLUDED +/* Macro */ +#define BTC_A2DP_SOURCE_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) +#define BTC_A2DP_SOURCE_TASK_STACK_SIZE (CONFIG_A2DP_SOURCE_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) // by menuconfig +#define BTC_A2DP_SOURCE_TASK_NAME "BtA2dSourceT" +#define BTC_A2DP_SOURCE_TASK_PRIO (configMAX_PRIORITIES - 3) + + /***************************************************************************** ** Constants *****************************************************************************/ @@ -72,9 +79,6 @@ enum { BTC_A2DP_SOURCE_STATE_SHUTTING_DOWN = 2 }; -enum { - BTC_A2DP_SOURCE_DATA_EVT = 1, -}; /* Media task tick in milliseconds, must be set to multiple of (1000/TICKS_PER_SEC) */ @@ -127,6 +131,11 @@ enum { #define MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ (5) #define MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ (27) // 18 for 20ms tick +typedef struct { + uint32_t sig; + void *param; +} a2dp_src_task_evt_t; + typedef struct { UINT16 num_frames_to_be_processed; UINT16 len; @@ -174,15 +183,12 @@ static void btc_a2dp_source_aa_tx_flush(void); static void btc_a2dp_source_prep_2_send(UINT8 nb_frame); static void btc_a2dp_source_handle_timer(UNUSED_ATTR void *context); static void btc_a2dp_source_encoder_init(void); +static void btc_a2dp_source_ctrl_handler(void *arg); static tBTC_A2DP_SOURCE_CB btc_aa_src_cb; static int btc_a2dp_source_state = BTC_A2DP_SOURCE_STATE_OFF; static future_t *btc_a2dp_source_future = NULL; -static xTaskHandle btc_aa_src_task_hdl = NULL; -static QueueHandle_t btc_aa_src_data_queue = NULL; -static QueueHandle_t btc_aa_src_ctrl_queue = NULL; -static QueueSetHandle_t btc_aa_src_queue_set; - +static osi_thread_t *btc_aa_src_task_hdl = NULL; static esp_a2d_source_data_cb_t btc_aa_src_data_cb = NULL; static UINT64 last_frame_us = 0; @@ -234,26 +240,28 @@ bool btc_a2dp_source_is_task_shutting_down(void) return btc_a2dp_source_state == BTC_A2DP_SOURCE_STATE_SHUTTING_DOWN; } -static void btc_a2dp_source_ctrl_post(uint32_t sig, void *par) +static void btc_a2dp_source_ctrl_post(uint32_t sig, void *param) { - BtTaskEvt_t *evt = (BtTaskEvt_t *)osi_malloc(sizeof(BtTaskEvt_t)); + a2dp_src_task_evt_t *evt = (a2dp_src_task_evt_t *)osi_malloc(sizeof(a2dp_src_task_evt_t)); + if (evt == NULL) { return; } evt->sig = sig; - evt->par = par; + evt->param = param; - if (xQueueSend(btc_aa_src_ctrl_queue, &evt, portMAX_DELAY) != pdTRUE) { - APPL_TRACE_WARNING("btc_aa_src_ctrl_queue failed, sig 0x%x\n", sig); - } + osi_thread_post(btc_aa_src_task_hdl, btc_a2dp_source_ctrl_handler, evt, 0, OSI_THREAD_BLOCKING); } -static void btc_a2dp_source_ctrl_handler(BtTaskEvt_t *e) +static void btc_a2dp_source_ctrl_handler(void *arg) { + a2dp_src_task_evt_t *e = (a2dp_src_task_evt_t *)arg; + if (e == NULL) { return; } + switch (e->sig) { case BTC_MEDIA_TASK_INIT: btc_a2dp_source_thread_init(NULL); @@ -268,13 +276,13 @@ static void btc_a2dp_source_ctrl_handler(BtTaskEvt_t *e) btc_a2dp_source_aa_stop_tx(); break; case BTC_MEDIA_SBC_ENC_INIT: - btc_a2dp_source_enc_init(e->par); + btc_a2dp_source_enc_init(e->param); break; case BTC_MEDIA_SBC_ENC_UPDATE: - btc_a2dp_source_enc_update(e->par); + btc_a2dp_source_enc_update(e->param); break; case BTC_MEDIA_AUDIO_FEEDING_INIT: - btc_a2dp_source_audio_feeding_init(e->par); + btc_a2dp_source_audio_feeding_init(e->param); break; case BTC_MEDIA_FLUSH_AA_TX: btc_a2dp_source_aa_tx_flush(); @@ -282,29 +290,12 @@ static void btc_a2dp_source_ctrl_handler(BtTaskEvt_t *e) default: APPL_TRACE_WARNING("media task unhandled evt: 0x%x\n", e->sig); } - if (e->par != NULL) { - osi_free(e->par); - } -} -static void btc_a2dp_source_task_handler(void *arg) -{ - QueueSetMemberHandle_t xActivatedMember; - BtTaskEvt_t *e = NULL; - for (;;) { - xActivatedMember = xQueueSelectFromSet(btc_aa_src_queue_set, portMAX_DELAY); - if (xActivatedMember == btc_aa_src_data_queue) { - int32_t data_evt; - xQueueReceive(xActivatedMember, &data_evt, 0); - if (data_evt == BTC_A2DP_SOURCE_DATA_EVT) { - btc_a2dp_source_handle_timer(NULL); - } - } else if (xActivatedMember == btc_aa_src_ctrl_queue) { - xQueueReceive(xActivatedMember, &e, 0); - btc_a2dp_source_ctrl_handler(e); - osi_free(e); - } + if (e->param != NULL) { + osi_free(e->param); } + + osi_free(e); } bool btc_a2dp_source_startup(void) @@ -324,57 +315,28 @@ bool btc_a2dp_source_startup(void) } #endif /* #if BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE */ - btc_aa_src_queue_set = xQueueCreateSet(BTC_A2DP_SOURCE_TASK_QUEUE_SET_LEN); - configASSERT(btc_aa_src_queue_set); - btc_aa_src_data_queue = xQueueCreate(BTC_A2DP_SOURCE_DATA_QUEUE_LEN, sizeof(void *)); - configASSERT(btc_aa_src_data_queue); - xQueueAddToSet(btc_aa_src_data_queue, btc_aa_src_queue_set); - - btc_aa_src_ctrl_queue = xQueueCreate(BTC_A2DP_SOURCE_CTRL_QUEUE_LEN, sizeof(void *)); - configASSERT(btc_aa_src_ctrl_queue); - xQueueAddToSet(btc_aa_src_ctrl_queue, btc_aa_src_queue_set); - - if (!btc_aa_src_data_queue || !btc_aa_src_ctrl_queue || !btc_aa_src_queue_set ) { - goto error_exit; - } - - xTaskCreatePinnedToCore(btc_a2dp_source_task_handler, BTC_A2DP_SOURCE_TASK_NAME, BTC_A2DP_SOURCE_TASK_STACK_SIZE, NULL, BTC_A2DP_SOURCE_TASK_PRIO, &btc_aa_src_task_hdl, BTC_A2DP_SOURCE_TASK_PINNED_TO_CORE); + btc_aa_src_task_hdl = osi_thread_create(BTC_A2DP_SOURCE_TASK_NAME, BTC_A2DP_SOURCE_TASK_STACK_SIZE, BTC_A2DP_SOURCE_TASK_PRIO, BTC_A2DP_SOURCE_TASK_PINNED_TO_CORE, 2); if (btc_aa_src_task_hdl == NULL) { goto error_exit; } btc_a2dp_source_ctrl_post(BTC_MEDIA_TASK_INIT, NULL); - APPL_TRACE_EVENT("## A2DP SOURCE MEDIA THREAD STARTED ##\n"); return true; error_exit:; APPL_TRACE_ERROR("%s unable to start up media thread\n", __func__); + osi_thread_free(btc_aa_src_task_hdl); + btc_aa_src_task_hdl = NULL; - if (btc_aa_src_task_hdl != NULL) { - vTaskDelete(btc_aa_src_task_hdl); - btc_aa_src_task_hdl = NULL; - } - - if (btc_aa_src_data_queue) { - vQueueDelete(btc_aa_src_data_queue); - btc_aa_src_data_queue = NULL; - } - if (btc_aa_src_ctrl_queue) { - vQueueDelete(btc_aa_src_ctrl_queue); - btc_aa_src_ctrl_queue = NULL; - } - if (btc_aa_src_queue_set) { - vQueueDelete(btc_aa_src_queue_set); - btc_aa_src_queue_set = NULL; - } #if (BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE) if (btc_sbc_encoder_ptr) { osi_free(btc_sbc_encoder_ptr); btc_sbc_encoder_ptr = NULL; } #endif /* #if BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE */ + return false; } @@ -390,18 +352,9 @@ void btc_a2dp_source_shutdown(void) future_await(btc_a2dp_source_future); btc_a2dp_source_future = NULL; - vTaskDelete(btc_aa_src_task_hdl); + osi_thread_free(btc_aa_src_task_hdl); btc_aa_src_task_hdl = NULL; - vQueueDelete(btc_aa_src_data_queue); - btc_aa_src_data_queue = NULL; - - vQueueDelete(btc_aa_src_ctrl_queue); - btc_aa_src_ctrl_queue = NULL; - - vQueueDelete(btc_aa_src_queue_set); - btc_aa_src_queue_set = NULL; - #if (BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE) osi_free(btc_sbc_encoder_ptr); btc_sbc_encoder_ptr = NULL; @@ -472,11 +425,9 @@ void btc_a2dp_source_on_suspended(tBTA_AV_SUSPEND *p_av) btc_a2dp_source_stop_audio_req(); } -static void btc_a2dp_source_data_post(int32_t data_type) +static void btc_a2dp_source_data_post(void) { - if (xQueueSend(btc_aa_src_data_queue, &data_type, 0) != pdTRUE) { - APPL_TRACE_DEBUG("Media data Q filled\n"); - } + osi_thread_post(btc_aa_src_task_hdl, btc_a2dp_source_handle_timer, NULL, 1, OSI_THREAD_BLOCKING); } static UINT64 time_now_us() @@ -604,9 +555,13 @@ BOOLEAN btc_a2dp_source_stop_audio_req(void) * the "cleanup() -> btc_a2dp_stop_media_task()" processing during * the shutdown of the Bluetooth stack. */ +#if 0 if (btc_aa_src_ctrl_queue != NULL) { +#endif btc_a2dp_source_ctrl_post(BTC_MEDIA_STOP_AA_TX, NULL); +#if 0 } +#endif return TRUE; } @@ -696,9 +651,13 @@ BOOLEAN btc_a2dp_source_tx_flush_req(void) * the "cleanup() -> btc_a2dp_stop_media_task()" processing during * the shutdown of the Bluetooth stack. */ +#if 0 if (btc_aa_src_ctrl_queue != NULL) { +#endif btc_a2dp_source_ctrl_post(BTC_MEDIA_FLUSH_AA_TX, NULL); +#if 0 } +#endif return TRUE; } @@ -1515,7 +1474,7 @@ static void btc_a2dp_source_handle_timer(UNUSED_ATTR void *context) static void btc_a2dp_source_alarm_cb(UNUSED_ATTR void *context) { - btc_a2dp_source_data_post(BTC_A2DP_SOURCE_DATA_EVT); + btc_a2dp_source_data_post(); } /******************************************************************************* diff --git a/components/bt/bluedroid/common/include/common/bt_target.h b/components/bt/bluedroid/common/include/common/bt_target.h index 8b504e0010..3e9dac6131 100644 --- a/components/bt/bluedroid/common/include/common/bt_target.h +++ b/components/bt/bluedroid/common/include/common/bt_target.h @@ -39,6 +39,14 @@ #include "stack/dyn_mem.h" /* defines static and/or dynamic memory for components */ + +/* OS Configuration from User config (eg: sdkconfig) */ +#if CONFIG_BLUEDROID_PINNED_TO_CORE +#define TASK_PINNED_TO_CORE (CONFIG_BLUEDROID_PINNED_TO_CORE < portNUM_PROCESSORS ? CONFIG_BLUEDROID_PINNED_TO_CORE : tskNO_AFFINITY) +#else +#define TASK_PINNED_TO_CORE (0) +#endif + /****************************************************************************** ** ** Classic BT features diff --git a/components/bt/bluedroid/hci/hci_hal_h4.c b/components/bt/bluedroid/hci/hci_hal_h4.c index 89fba87b5d..4189aa2fe5 100644 --- a/components/bt/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/bluedroid/hci/hci_hal_h4.c @@ -27,9 +27,17 @@ #include "esp_bt.h" #include "stack/hcimsgs.h" +#define HCI_H4_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) +#define HCI_H4_TASK_STACK_SIZE (2048 + BT_TASK_EXTRA_STACK_SIZE) +#define HCI_H4_TASK_PRIO (configMAX_PRIORITIES - 4) +#define HCI_H4_TASK_NAME "hciH4T" +#define HCI_H4_QUEUE_LEN 1 + + #if (C2H_FLOW_CONTROL_INCLUDED == TRUE) #include "l2c_int.h" #endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE +#include "stack/hcimsgs.h" #define HCI_HAL_SERIAL_BUFFER_SIZE 1026 #define HCI_BLE_EVENT 0x3e @@ -63,9 +71,7 @@ static hci_hal_env_t hci_hal_env; static const hci_hal_t interface; static const hci_hal_callbacks_t *callbacks; static const esp_vhci_host_callback_t vhci_host_cb; - -static xTaskHandle xHciH4TaskHandle; -static xQueueHandle xHciH4Queue; +static osi_thread_t *hci_h4_thread; static void host_send_pkt_available_cb(void); static int host_recv_pkt_cb(uint8_t *data, uint16_t len); @@ -110,8 +116,10 @@ static bool hal_open(const hci_hal_callbacks_t *upper_callbacks) hci_hal_env_init(HCI_HAL_SERIAL_BUFFER_SIZE, QUEUE_SIZE_MAX); #endif - xHciH4Queue = xQueueCreate(HCI_H4_QUEUE_LEN, sizeof(BtTaskEvt_t)); - xTaskCreatePinnedToCore(hci_hal_h4_rx_handler, HCI_H4_TASK_NAME, HCI_H4_TASK_STACK_SIZE, NULL, HCI_H4_TASK_PRIO, &xHciH4TaskHandle, HCI_H4_TASK_PINNED_TO_CORE); + hci_h4_thread = osi_thread_create(HCI_H4_TASK_NAME, HCI_H4_TASK_STACK_SIZE, HCI_H4_TASK_PRIO, HCI_H4_TASK_PINNED_TO_CORE, 1); + if (hci_h4_thread == NULL) { + return false; + } //register vhci host cb if (esp_vhci_host_register_callback(&vhci_host_cb) != ESP_OK) { @@ -125,9 +133,8 @@ static void hal_close() { hci_hal_env_deinit(); - /* delete task and queue */ - vTaskDelete(xHciH4TaskHandle); - vQueueDelete(xHciH4Queue); + osi_thread_free(hci_h4_thread); + hci_h4_thread = NULL; } /** @@ -169,30 +176,12 @@ static uint16_t transmit_data(serial_data_type_t type, // Internal functions static void hci_hal_h4_rx_handler(void *arg) { - BtTaskEvt_t e; - - for (;;) { - if (pdTRUE == xQueueReceive(xHciH4Queue, &e, (portTickType)portMAX_DELAY)) { - if (e.sig == SIG_HCI_HAL_RECV_PACKET) { - fixed_queue_process(hci_hal_env.rx_q); - - } - } - } + fixed_queue_process(hci_hal_env.rx_q); } -task_post_status_t hci_hal_h4_task_post(task_post_t timeout) +bool hci_hal_h4_task_post(osi_thread_blocking_t blocking) { - BtTaskEvt_t evt; - - evt.sig = SIG_HCI_HAL_RECV_PACKET; - evt.par = 0; - - if (xQueueSend(xHciH4Queue, &evt, timeout) != pdTRUE) { - return TASK_POST_SUCCESS; - } - - return TASK_POST_FAIL; + return osi_thread_post(hci_h4_thread, hci_hal_h4_rx_handler, NULL, 0, blocking); } #if (C2H_FLOW_CONTROL_INCLUDED == TRUE) @@ -343,7 +332,7 @@ static void host_send_pkt_available_cb(void) { //Controller rx cache buffer is ready for receiving new host packet //Just Call Host main thread task to process pending packets. - hci_host_task_post(TASK_POST_BLOCKING); + hci_host_task_post(OSI_THREAD_BLOCKING); } static int host_recv_pkt_cb(uint8_t *data, uint16_t len) @@ -368,7 +357,8 @@ static int host_recv_pkt_cb(uint8_t *data, uint16_t len) pkt->layer_specific = 0; memcpy(pkt->data, data, len); fixed_queue_enqueue(hci_hal_env.rx_q, pkt); - hci_hal_h4_task_post(0); + hci_hal_h4_task_post(OSI_THREAD_NON_BLOCKING); + BTTRC_DUMP_BUFFER("Recv Pkt", pkt->data, len); diff --git a/components/bt/bluedroid/hci/hci_layer.c b/components/bt/bluedroid/hci/hci_layer.c index c2b6223ce7..67ed0a2bcc 100644 --- a/components/bt/bluedroid/hci/hci_layer.c +++ b/components/bt/bluedroid/hci/hci_layer.c @@ -21,6 +21,7 @@ #include "common/bt_trace.h" #include "stack/hcidefs.h" #include "stack/hcimsgs.h" +#include "stack/btu.h" #include "common/bt_vendor_lib.h" #include "hci/hci_internals.h" #include "hci/hci_hal.h" @@ -33,6 +34,12 @@ #include "osi/mutex.h" #include "osi/fixed_queue.h" +#define HCI_HOST_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) +#define HCI_HOST_TASK_STACK_SIZE (2048 + BT_TASK_EXTRA_STACK_SIZE) +#define HCI_HOST_TASK_PRIO (configMAX_PRIORITIES - 3) +#define HCI_HOST_TASK_NAME "hciHostT" +#define HCI_HOST_QUEUE_LEN 40 + typedef struct { uint16_t opcode; future_t *complete_future; @@ -70,10 +77,7 @@ static const uint32_t COMMAND_PENDING_TIMEOUT = 8000; static bool interface_created; static hci_t interface; static hci_host_env_t hci_host_env; - -static xTaskHandle xHciHostTaskHandle; -static xQueueHandle xHciHostQueue; - +static osi_thread_t *hci_host_thread; static bool hci_host_startup_flag; // Modules we import and callbacks we export @@ -102,8 +106,10 @@ int hci_start_up(void) goto error; } - xHciHostQueue = xQueueCreate(HCI_HOST_QUEUE_LEN, sizeof(BtTaskEvt_t)); - xTaskCreatePinnedToCore(hci_host_thread_handler, HCI_HOST_TASK_NAME, HCI_HOST_TASK_STACK_SIZE, NULL, HCI_HOST_TASK_PRIO, &xHciHostTaskHandle, HCI_HOST_TASK_PINNED_TO_CORE); + hci_host_thread = osi_thread_create(HCI_HOST_TASK_NAME, HCI_HOST_TASK_STACK_SIZE, HCI_HOST_TASK_PRIO, HCI_HOST_TASK_PINNED_TO_CORE, 1); + if (hci_host_thread == NULL) { + return -2; + } packet_fragmenter->init(&packet_fragmenter_callbacks); hal->open(&hal_callbacks); @@ -124,28 +130,15 @@ void hci_shut_down(void) //low_power_manager->cleanup(); hal->close(); - vTaskDelete(xHciHostTaskHandle); - vQueueDelete(xHciHostQueue); + + osi_thread_free(hci_host_thread); + hci_host_thread = NULL; } -task_post_status_t hci_host_task_post(task_post_t timeout) +bool hci_host_task_post(osi_thread_blocking_t blocking) { - BtTaskEvt_t evt; - - if (hci_host_startup_flag == false) { - return TASK_POST_FAIL; - } - - evt.sig = SIG_HCI_HOST_SEND_AVAILABLE; - evt.par = 0; - - if (xQueueSend(xHciHostQueue, &evt, timeout) != pdTRUE) { - HCI_TRACE_ERROR("xHciHostQueue failed\n"); - return TASK_POST_FAIL; - } - - return TASK_POST_SUCCESS; + return osi_thread_post(hci_host_thread, hci_host_thread_handler, NULL, 0, blocking); } static int hci_layer_init_env(void) @@ -218,27 +211,17 @@ static void hci_host_thread_handler(void *arg) * All packets will be directly copied to single queue in driver layer with * H4 type header added (1 byte). */ - - BtTaskEvt_t e; - - for (;;) { - if (pdTRUE == xQueueReceive(xHciHostQueue, &e, (portTickType)portMAX_DELAY)) { - - if (e.sig == SIG_HCI_HOST_SEND_AVAILABLE) { - if (esp_vhci_host_check_send_available()) { - /*Now Target only allowed one packet per TX*/ - BT_HDR *pkt = packet_fragmenter->fragment_current_packet(); - if (pkt != NULL) { - packet_fragmenter->fragment_and_dispatch(pkt); - } else { - if (!fixed_queue_is_empty(hci_host_env.command_queue) && - hci_host_env.command_credits > 0) { - fixed_queue_process(hci_host_env.command_queue); - } else if (!fixed_queue_is_empty(hci_host_env.packet_queue)) { - fixed_queue_process(hci_host_env.packet_queue); - } - } - } + if (esp_vhci_host_check_send_available()) { + /*Now Target only allowed one packet per TX*/ + BT_HDR *pkt = packet_fragmenter->fragment_current_packet(); + if (pkt != NULL) { + packet_fragmenter->fragment_and_dispatch(pkt); + } else { + if (!fixed_queue_is_empty(hci_host_env.command_queue) && + hci_host_env.command_credits > 0) { + fixed_queue_process(hci_host_env.command_queue); + } else if (!fixed_queue_is_empty(hci_host_env.packet_queue)) { + fixed_queue_process(hci_host_env.packet_queue); } } } @@ -271,7 +254,7 @@ static void transmit_command( BTTRC_DUMP_BUFFER(NULL, command->data + command->offset, command->len); fixed_queue_enqueue(hci_host_env.command_queue, wait_entry); - hci_host_task_post(TASK_POST_BLOCKING); + hci_host_task_post(OSI_THREAD_BLOCKING); } @@ -292,7 +275,7 @@ static future_t *transmit_command_futured(BT_HDR *command) command->event = MSG_STACK_TO_HC_HCI_CMD; fixed_queue_enqueue(hci_host_env.command_queue, wait_entry); - hci_host_task_post(TASK_POST_BLOCKING); + hci_host_task_post(OSI_THREAD_BLOCKING); return future; } @@ -305,7 +288,7 @@ static void transmit_downward(uint16_t type, void *data) fixed_queue_enqueue(hci_host_env.packet_queue, data); } - hci_host_task_post(TASK_POST_BLOCKING); + hci_host_task_post(OSI_THREAD_BLOCKING); } @@ -479,7 +462,7 @@ intercepted: /*Tell HCI Host Task to continue TX Pending commands*/ if (hci_host_env.command_credits && !fixed_queue_is_empty(hci_host_env.command_queue)) { - hci_host_task_post(TASK_POST_BLOCKING); + hci_host_task_post(OSI_THREAD_BLOCKING); } if (wait_entry) { @@ -507,7 +490,7 @@ static void dispatch_reassembled(BT_HDR *packet) { // Events should already have been dispatched before this point //Tell Up-layer received packet. - if (btu_task_post(SIG_BTU_HCI_MSG, packet, TASK_POST_BLOCKING) != TASK_POST_SUCCESS) { + if (btu_task_post(SIG_BTU_HCI_MSG, packet, OSI_THREAD_BLOCKING) == false) { osi_free(packet); } } diff --git a/components/bt/bluedroid/hci/include/hci/hci_layer.h b/components/bt/bluedroid/hci/include/hci/hci_layer.h index 4b1018098b..90f0a8221e 100644 --- a/components/bt/bluedroid/hci/include/hci/hci_layer.h +++ b/components/bt/bluedroid/hci/include/hci/hci_layer.h @@ -23,6 +23,8 @@ #include "osi/allocator.h" #include "osi/osi.h" #include "osi/future.h" +#include "osi/thread.h" + ///// LEGACY DEFINITIONS ///// /* Message event mask across Host/Controller lib and stack */ @@ -95,5 +97,6 @@ const hci_t *hci_layer_get_interface(); int hci_start_up(void); void hci_shut_down(void); +bool hci_host_task_post(osi_thread_blocking_t blocking); #endif /* _HCI_LAYER_H_ */ diff --git a/components/bt/bluedroid/osi/include/osi/thread.h b/components/bt/bluedroid/osi/include/osi/thread.h index bad1e48809..b3f77725f9 100644 --- a/components/bt/bluedroid/osi/include/osi/thread.h +++ b/components/bt/bluedroid/osi/include/osi/thread.h @@ -25,91 +25,33 @@ #define portBASE_TYPE int -struct bt_task_evt { - uint32_t sig; //task sig - void *par; //point to task param - void *cb; //point to function cb - void *arg; //point to function arg -}; -typedef struct bt_task_evt BtTaskEvt_t; +struct osi_thread; -typedef bt_status_t (* BtTaskCb_t)(void *arg); +typedef struct osi_thread osi_thread_t; + +typedef void (*osi_thread_func_t)(void *context); typedef enum { - SIG_HCI_HAL_RECV_PACKET = 0, - SIG_HCI_HAL_NUM, -} SIG_HCI_HAL_t; - + OSI_THREAD_CORE_0 = 0, + OSI_THREAD_CORE_1, + OSI_THREAD_CORE_AFFINITY, +} osi_thread_core_t; typedef enum { - SIG_HCI_HOST_SEND_AVAILABLE = 0, - SIG_HCI_HOST_NUM, -} SIG_HCI_HOST_t; + OSI_THREAD_NON_BLOCKING = 0, + OSI_THREAD_BLOCKING, +} osi_thread_blocking_t; -typedef enum { - SIG_BTU_START_UP = 0, - SIG_BTU_HCI_MSG, - SIG_BTU_BTA_MSG, - SIG_BTU_BTA_ALARM, - SIG_BTU_GENERAL_ALARM, - SIG_BTU_ONESHOT_ALARM, - SIG_BTU_L2CAP_ALARM, - SIG_BTU_NUM, -} SIG_BTU_t; +osi_thread_t *osi_thread_create(const char *name, size_t stack_size, int priority, osi_thread_core_t core, uint8_t work_queue_num); -#define TASK_PINNED_TO_CORE (CONFIG_BT_BLUEDROID_PINNED_TO_CORE < portNUM_PROCESSORS ? CONFIG_BT_BLUEDROID_PINNED_TO_CORE : tskNO_AFFINITY) +void osi_thread_free(osi_thread_t *thread); -#define HCI_HOST_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) -#define HCI_HOST_TASK_STACK_SIZE (2048 + BT_TASK_EXTRA_STACK_SIZE) -#define HCI_HOST_TASK_PRIO (configMAX_PRIORITIES - 3) -#define HCI_HOST_TASK_NAME "hciHostT" -#define HCI_HOST_QUEUE_LEN 40 +bool osi_thread_post(osi_thread_t *thread, osi_thread_func_t func, void *context, int queue_idx, osi_thread_blocking_t blocking); -#define HCI_H4_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) -#define HCI_H4_TASK_STACK_SIZE (2048 + BT_TASK_EXTRA_STACK_SIZE) -#define HCI_H4_TASK_PRIO (configMAX_PRIORITIES - 4) -#define HCI_H4_TASK_NAME "hciH4T" -#define HCI_H4_QUEUE_LEN 1 +bool osi_thread_set_priority(osi_thread_t *thread, int priority); -#define BTU_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) -#define BTU_TASK_STACK_SIZE (CONFIG_BT_BTU_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) -#define BTU_TASK_PRIO (configMAX_PRIORITIES - 5) -#define BTU_TASK_NAME "btuT" -#define BTU_QUEUE_LEN 50 +const char *osi_thread_name(osi_thread_t *thread); -#define BTC_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) -#define BTC_TASK_STACK_SIZE (CONFIG_BT_BTC_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) //by menuconfig -#define BTC_TASK_NAME "btcT" -#define BTC_TASK_PRIO (configMAX_PRIORITIES - 6) -#define BTC_TASK_QUEUE_LEN 60 - -#define BTC_A2DP_SINK_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) -#define BTC_A2DP_SINK_TASK_STACK_SIZE (CONFIG_BT_A2DP_SINK_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) // by menuconfig -#define BTC_A2DP_SINK_TASK_NAME "BtA2dSinkT" -#define BTC_A2DP_SINK_TASK_PRIO (configMAX_PRIORITIES - 3) -#define BTC_A2DP_SINK_DATA_QUEUE_LEN (3) -#define BTC_A2DP_SINK_CTRL_QUEUE_LEN (5) -#define BTC_A2DP_SINK_TASK_QUEUE_SET_LEN (BTC_A2DP_SINK_DATA_QUEUE_LEN + BTC_A2DP_SINK_CTRL_QUEUE_LEN) - -#define BTC_A2DP_SOURCE_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) -#define BTC_A2DP_SOURCE_TASK_STACK_SIZE (CONFIG_BT_A2DP_SOURCE_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) // by menuconfig -#define BTC_A2DP_SOURCE_TASK_NAME "BtA2dSourceT" -#define BTC_A2DP_SOURCE_TASK_PRIO (configMAX_PRIORITIES - 3) -#define BTC_A2DP_SOURCE_DATA_QUEUE_LEN (1) -#define BTC_A2DP_SOURCE_CTRL_QUEUE_LEN (5) -#define BTC_A2DP_SOURCE_TASK_QUEUE_SET_LEN (BTC_A2DP_SOURCE_DATA_QUEUE_LEN + BTC_A2DP_SOURCE_CTRL_QUEUE_LEN) - -#define TASK_POST_NON_BLOCKING (0) -#define TASK_POST_BLOCKING (portMAX_DELAY) -typedef uint32_t task_post_t; /* Timeout of task post return, unit TICK */ - -typedef enum { - TASK_POST_SUCCESS = 0, - TASK_POST_FAIL, -} task_post_status_t; - -task_post_status_t btu_task_post(uint32_t sig, void *param, task_post_t timeout); -task_post_status_t hci_host_task_post(task_post_t timeout); -task_post_status_t hci_hal_h4_task_post(task_post_t timeout); +int osi_thread_queue_wait_size(osi_thread_t *thread, int wq_idx); #endif /* __THREAD_H__ */ diff --git a/components/bt/bluedroid/osi/thread.c b/components/bt/bluedroid/osi/thread.c new file mode 100644 index 0000000000..ceac21bf89 --- /dev/null +++ b/components/bt/bluedroid/osi/thread.c @@ -0,0 +1,282 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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 + +#include "osi/allocator.h" +#include "osi/fixed_queue.h" +#include "osi/semaphore.h" +#include "osi/thread.h" + +struct osi_thread { + void *thread_handle; /*!< Store the thread object */ + int thread_id; /*!< May for some OS, such as Linux */ + bool stop; + uint8_t work_queue_num; /*!< Work queue number */ + fixed_queue_t **work_queues; /*!< Point to queue array, and the priority inverse array index */ + osi_sem_t work_sem; + osi_sem_t stop_sem; +}; + +struct osi_thread_start_arg { + osi_thread_t *thread; + osi_sem_t start_sem; + int error; +}; + +typedef struct { + osi_thread_func_t func; + void *context; +} work_item_t; + +static const size_t DEFAULT_WORK_QUEUE_CAPACITY = 100; + +static void osi_thread_run(void *arg) +{ + struct osi_thread_start_arg *start = (struct osi_thread_start_arg *)arg; + osi_thread_t *thread = start->thread; + + osi_sem_give(&start->start_sem); + + while (1) { + int idx = 0; + + osi_sem_take(&thread->work_sem, OSI_SEM_MAX_TIMEOUT); + + if (thread->stop) { + break; + } + + while (!thread->stop && idx < thread->work_queue_num) { + work_item_t *item = fixed_queue_try_dequeue(thread->work_queues[idx]); + if (item) { + item->func(item->context); + osi_free(item); + idx = 0; + continue; + } else { + idx++; + } + } + } + + thread->thread_handle = NULL; + osi_sem_give(&thread->stop_sem); + + vTaskDelete(NULL); +} + +static int osi_thread_join(osi_thread_t *thread, uint32_t wait_ms) +{ + assert(thread != NULL); + return osi_sem_take(&thread->stop_sem, wait_ms); +} + +static void osi_thread_stop(osi_thread_t *thread) +{ + int ret; + + assert(thread != NULL); + + //stop the thread + thread->stop = true; + osi_sem_give(&thread->work_sem); + + //join + ret = osi_thread_join(thread, 1000); //wait 1000ms + + //if join failed, delete the task here + if (ret != 0 && thread->thread_handle) { + vTaskDelete(thread->thread_handle); + } +} + +//in linux, the stack_size, priority and core may not be set here, the code will be ignore the arguments +osi_thread_t *osi_thread_create(const char *name, size_t stack_size, int priority, osi_thread_core_t core, uint8_t work_queue_num) +{ + int ret; + osi_thread_t *thread; + struct osi_thread_start_arg start_arg = {0}; + + if (stack_size <= 0 || + core < OSI_THREAD_CORE_0 || core > OSI_THREAD_CORE_AFFINITY || + work_queue_num <= 0) { + return NULL; + } + + thread = (osi_thread_t *)osi_malloc(sizeof(osi_thread_t)); + if (thread == NULL) { + goto _err; + } + + thread->stop = false; + thread->work_queue_num = work_queue_num; + thread->work_queues = (fixed_queue_t **)osi_malloc(sizeof(fixed_queue_t *) * work_queue_num); + if (thread->work_queues == NULL) { + goto _err; + } + + for (int i = 0; i < thread->work_queue_num; i++) { + thread->work_queues[i] = fixed_queue_new(DEFAULT_WORK_QUEUE_CAPACITY); + if (thread->work_queues[i] == NULL) { + goto _err; + } + } + + ret = osi_sem_new(&thread->work_sem, 1, 0); + if (ret != 0) { + goto _err; + } + + ret = osi_sem_new(&thread->stop_sem, 1, 0); + if (ret != 0) { + goto _err; + } + + start_arg.thread = thread; + ret = osi_sem_new(&start_arg.start_sem, 1, 0); + if (ret != 0) { + goto _err; + } + + if (xTaskCreatePinnedToCore(osi_thread_run, name, stack_size, &start_arg, priority, &thread->thread_handle, core) != pdPASS) { + goto _err; + } + + osi_sem_take(&start_arg.start_sem, OSI_SEM_MAX_TIMEOUT); + osi_sem_free(&start_arg.start_sem); + + return thread; + +_err: + + if (thread) { + if (start_arg.start_sem) { + osi_sem_free(&start_arg.start_sem); + } + + if (thread->thread_handle) { + vTaskDelete(thread->thread_handle); + } + + for (int i = 0; i < thread->work_queue_num; i++) { + if (thread->work_queues[i]) { + fixed_queue_free(thread->work_queues[i], osi_free_func); + } + } + + if (thread->work_queues) { + osi_free(thread->work_queues); + } + + if (thread->work_sem) { + osi_sem_free(&thread->work_sem); + } + + if (thread->stop_sem) { + osi_sem_free(&thread->stop_sem); + } + + osi_free(thread); + } + + return NULL; +} + +void osi_thread_free(osi_thread_t *thread) +{ + if (!thread) + return; + + osi_thread_stop(thread); + + for (int i = 0; i < thread->work_queue_num; i++) { + if (thread->work_queues[i]) { + fixed_queue_free(thread->work_queues[i], osi_free_func); + } + } + + if (thread->work_queues) { + osi_free(thread->work_queues); + } + + if (thread->work_sem) { + osi_sem_free(&thread->work_sem); + } + + if (thread->stop_sem) { + osi_sem_free(&thread->stop_sem); + } + + + osi_free(thread); +} + +bool osi_thread_post(osi_thread_t *thread, osi_thread_func_t func, void *context, int queue_idx, osi_thread_blocking_t blocking) +{ + assert(thread != NULL); + assert(func != NULL); + + if (queue_idx >= thread->work_queue_num) { + return false; + } + + work_item_t *item = (work_item_t *)osi_malloc(sizeof(work_item_t)); + if (item == NULL) { + return false; + } + item->func = func; + item->context = context; + + if (blocking == OSI_THREAD_BLOCKING) { + fixed_queue_enqueue(thread->work_queues[queue_idx], item); + } else { + if (fixed_queue_try_enqueue(thread->work_queues[queue_idx], item) == false) { + osi_free(item); + return false; + } + } + + osi_sem_give(&thread->work_sem); + + return true; +} + +bool osi_thread_set_priority(osi_thread_t *thread, int priority) +{ + assert(thread != NULL); + + vTaskPrioritySet(thread->thread_handle, priority); + return true; +} + +const char *osi_thread_name(osi_thread_t *thread) +{ + assert(thread != NULL); + + return pcTaskGetTaskName(thread->thread_handle); +} + +int osi_thread_queue_wait_size(osi_thread_t *thread, int wq_idx) +{ + if (wq_idx < 0 || wq_idx >= thread->work_queue_num) { + return -1; + } + + return fixed_queue_length(thread->work_queues[wq_idx]); +} diff --git a/components/bt/bluedroid/stack/btu/btu_hcif.c b/components/bt/bluedroid/stack/btu/btu_hcif.c index 7f0395a5b3..7d1ab95f96 100644 --- a/components/bt/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/bluedroid/stack/btu/btu_hcif.c @@ -1086,7 +1086,7 @@ static void btu_hcif_command_complete_evt(BT_HDR *response, void *context) event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK; - btu_task_post(SIG_BTU_HCI_MSG, event, TASK_POST_BLOCKING); + btu_task_post(SIG_BTU_HCI_MSG, event, OSI_THREAD_BLOCKING); } @@ -1291,7 +1291,7 @@ static void btu_hcif_command_status_evt(uint8_t status, BT_HDR *command, void *c event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK; - btu_task_post(SIG_BTU_HCI_MSG, event, TASK_POST_BLOCKING); + btu_task_post(SIG_BTU_HCI_MSG, event, OSI_THREAD_BLOCKING); } /******************************************************************************* diff --git a/components/bt/bluedroid/stack/btu/btu_init.c b/components/bt/bluedroid/stack/btu/btu_init.c index 7014cfde00..510fab7ecf 100644 --- a/components/bt/bluedroid/stack/btu/btu_init.c +++ b/components/bt/bluedroid/stack/btu/btu_init.c @@ -44,6 +44,12 @@ #endif #endif +#define BTU_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) +#define BTU_TASK_STACK_SIZE (4096 + BT_TASK_EXTRA_STACK_SIZE) +#define BTU_TASK_PRIO (configMAX_PRIORITIES - 5) +#define BTU_TASK_NAME "btuT" +#define BTU_QUEUE_LEN 50 + hash_map_t *btu_general_alarm_hash_map; osi_mutex_t btu_general_alarm_lock; static const size_t BTU_GENERAL_ALARM_HASH_MAP_SIZE = 34; @@ -56,16 +62,14 @@ hash_map_t *btu_l2cap_alarm_hash_map; osi_mutex_t btu_l2cap_alarm_lock; static const size_t BTU_L2CAP_ALARM_HASH_MAP_SIZE = 34; -//thread_t *bt_workqueue_thread; -//static const char *BT_WORKQUEUE_NAME = "bt_workqueue"; -xTaskHandle xBtuTaskHandle = NULL; -xQueueHandle xBtuQueue = 0; +osi_thread_t *btu_thread = NULL; extern void PLATFORM_DisableHciTransport(UINT8 bDisable); extern void btu_task_thread_handler(void *arg); void btu_task_start_up(void); void btu_task_shut_down(void); + /***************************************************************************** ** V A R I A B L E S * ******************************************************************************/ @@ -178,10 +182,14 @@ void BTU_StartUp(void) osi_mutex_new(&btu_l2cap_alarm_lock); - xBtuQueue = xQueueCreate(BTU_QUEUE_LEN, sizeof(BtTaskEvt_t)); - xTaskCreatePinnedToCore(btu_task_thread_handler, BTU_TASK_NAME, BTU_TASK_STACK_SIZE, NULL, BTU_TASK_PRIO, &xBtuTaskHandle, BTU_TASK_PINNED_TO_CORE); + btu_thread = osi_thread_create(BTU_TASK_NAME, BTU_TASK_STACK_SIZE, BTU_TASK_PRIO, BTU_TASK_PINNED_TO_CORE, 1); + if (btu_thread == NULL) { + goto error_exit; + } - btu_task_post(SIG_BTU_START_UP, NULL, TASK_POST_BLOCKING); + if (btu_task_post(SIG_BTU_START_UP, NULL, OSI_THREAD_BLOCKING) == false) { + goto error_exit; + } return; @@ -206,17 +214,14 @@ void BTU_ShutDown(void) hash_map_free(btu_l2cap_alarm_hash_map); osi_mutex_free(&btu_l2cap_alarm_lock); - vTaskDelete(xBtuTaskHandle); - vQueueDelete(xBtuQueue); - - btu_general_alarm_hash_map = NULL; + if (btu_thread) { + osi_thread_free(btu_thread); + btu_thread = NULL; + } + btu_general_alarm_hash_map = NULL; btu_oneshot_alarm_hash_map = NULL; - btu_l2cap_alarm_hash_map = NULL; - - xBtuTaskHandle = NULL; - xBtuQueue = 0; } /***************************************************************************** @@ -236,13 +241,14 @@ UINT16 BTU_BleAclPktSize(void) return 0; #endif } + #if SCAN_QUEUE_CONGEST_CHECK bool BTU_check_queue_is_congest(void) { - UBaseType_t wait_size = uxQueueMessagesWaiting(xBtuQueue); - if(wait_size >= QUEUE_CONGEST_SIZE ) { + if (osi_thread_queue_wait_size(btu_thread, 0) >= QUEUE_CONGEST_SIZE) { return true; } + return false; } #endif diff --git a/components/bt/bluedroid/stack/btu/btu_task.c b/components/bt/bluedroid/stack/btu/btu_task.c index 644731504d..916811df1e 100644 --- a/components/bt/bluedroid/stack/btu/btu_task.c +++ b/components/bt/bluedroid/stack/btu/btu_task.c @@ -81,6 +81,11 @@ extern void avdt_rcv_sync_info (BT_HDR *p_buf); #include "btm_ble_int.h" #endif +typedef struct { + uint32_t sig; + void *param; +} btu_thread_evt_t; + //#if (defined(BT_APP_DEMO) && BT_APP_DEMO == TRUE) //#include "bt_app_common.h" //#endif @@ -107,8 +112,8 @@ extern osi_mutex_t btu_oneshot_alarm_lock; extern hash_map_t *btu_l2cap_alarm_hash_map; extern osi_mutex_t btu_l2cap_alarm_lock; -extern xTaskHandle xBtuTaskHandle; -extern xQueueHandle xBtuQueue; +extern void *btu_thread; + extern bluedroid_init_done_cb_t bluedroid_init_done_cb; /* Define a function prototype to allow a generic timeout handler */ @@ -208,66 +213,52 @@ static void btu_bta_alarm_process(TIMER_LIST_ENT *p_tle) } #endif -/***************************************************************************** -** -** Function btu_task_thread_handler -** -** Description Process BTU Task Thread. -******************************************************************************/ -void btu_task_thread_handler(void *arg) +void btu_thread_handler(void *arg) { - BtTaskEvt_t e; + btu_thread_evt_t *evt = (btu_thread_evt_t *)arg; - for (;;) { - if (pdTRUE == xQueueReceive(xBtuQueue, &e, (portTickType)portMAX_DELAY)) { - - switch (e.sig) { - case SIG_BTU_START_UP: - btu_task_start_up(); - break; - case SIG_BTU_HCI_MSG: - btu_hci_msg_process((BT_HDR *)e.par); - break; + switch (evt->sig) { + case SIG_BTU_START_UP: + btu_task_start_up(); + break; + case SIG_BTU_HCI_MSG: + btu_hci_msg_process((BT_HDR *)evt->param); + break; #if (defined(BTA_INCLUDED) && BTA_INCLUDED == TRUE) - case SIG_BTU_BTA_MSG: - bta_sys_event((BT_HDR *)e.par); - break; - case SIG_BTU_BTA_ALARM: - btu_bta_alarm_process((TIMER_LIST_ENT *)e.par); - break; + case SIG_BTU_BTA_MSG: + bta_sys_event((BT_HDR *)evt->param); + break; + case SIG_BTU_BTA_ALARM: + btu_bta_alarm_process((TIMER_LIST_ENT *)evt->param); + break; #endif - case SIG_BTU_GENERAL_ALARM: - btu_general_alarm_process((TIMER_LIST_ENT *)e.par); - break; - case SIG_BTU_ONESHOT_ALARM: { - TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *)e.par; - btu_general_alarm_process(p_tle); - break; - } - case SIG_BTU_L2CAP_ALARM: - btu_l2cap_alarm_process((TIMER_LIST_ENT *)e.par); - break; - default: - break; - } - } + case SIG_BTU_GENERAL_ALARM: + case SIG_BTU_ONESHOT_ALARM: + btu_general_alarm_process((TIMER_LIST_ENT *)evt->param); + break; + case SIG_BTU_L2CAP_ALARM: + btu_l2cap_alarm_process((TIMER_LIST_ENT *)evt->param); + break; + default: + break; } + + osi_free(evt); } - -task_post_status_t btu_task_post(uint32_t sig, void *param, task_post_t timeout) +bool btu_task_post(uint32_t sig, void *param, osi_thread_blocking_t blocking) { - BtTaskEvt_t evt; + btu_thread_evt_t *evt; - evt.sig = sig; - evt.par = param; - - if (xQueueSend(xBtuQueue, &evt, timeout) != pdTRUE) { - HCI_TRACE_ERROR("xBtuQueue failed\n"); - return TASK_POST_FAIL; + evt = (btu_thread_evt_t *)osi_malloc(sizeof(btu_thread_evt_t)); + if (evt == NULL) { + return false; } - return TASK_POST_SUCCESS; + evt->sig = sig; + evt->param = param; + + return osi_thread_post(btu_thread, btu_thread_handler, evt, 0, blocking); } void btu_task_start_up(void) @@ -426,7 +417,7 @@ void btu_general_alarm_cb(void *data) assert(data != NULL); TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *)data; - btu_task_post(SIG_BTU_GENERAL_ALARM, p_tle, TASK_POST_BLOCKING); + btu_task_post(SIG_BTU_GENERAL_ALARM, p_tle, OSI_THREAD_BLOCKING); } void btu_start_timer(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout_sec) @@ -540,7 +531,7 @@ static void btu_l2cap_alarm_cb(void *data) assert(data != NULL); TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *)data; - btu_task_post(SIG_BTU_L2CAP_ALARM, p_tle, TASK_POST_BLOCKING); + btu_task_post(SIG_BTU_L2CAP_ALARM, p_tle, OSI_THREAD_BLOCKING); } void btu_start_quick_timer(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout_ticks) @@ -623,7 +614,7 @@ void btu_oneshot_alarm_cb(void *data) btu_stop_timer_oneshot(p_tle); - btu_task_post(SIG_BTU_ONESHOT_ALARM, p_tle, TASK_POST_BLOCKING); + btu_task_post(SIG_BTU_ONESHOT_ALARM, p_tle, OSI_THREAD_BLOCKING); } /* diff --git a/components/bt/bluedroid/stack/include/stack/btu.h b/components/bt/bluedroid/stack/include/stack/btu.h index 449b18da7e..a038ded1e1 100644 --- a/components/bt/bluedroid/stack/include/stack/btu.h +++ b/components/bt/bluedroid/stack/include/stack/btu.h @@ -29,6 +29,7 @@ #include "common/bt_target.h" #include "common/bt_defs.h" +#include "osi/thread.h" // HACK(zachoverflow): temporary dark magic #define BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK 0x1700 // didn't look used in bt_types...here goes nothing @@ -163,6 +164,17 @@ typedef void (*tBTU_EVENT_CALLBACK)(BT_HDR *p_hdr); #define BTU_TTYPE_UCD_TO 108 #define BTU_TTYPE_BLE_SCAN 109 +/* BTU Task Signal */ +typedef enum { + SIG_BTU_START_UP = 0, + SIG_BTU_HCI_MSG, + SIG_BTU_BTA_MSG, + SIG_BTU_BTA_ALARM, + SIG_BTU_GENERAL_ALARM, + SIG_BTU_ONESHOT_ALARM, + SIG_BTU_L2CAP_ALARM, + SIG_BTU_NUM, +} SIG_BTU_t; /* This is the inquiry response information held by BTU, and available ** to applications. @@ -276,6 +288,8 @@ void btu_task_shut_down(void); UINT16 BTU_BleAclPktSize(void); +bool btu_task_post(uint32_t sig, void *param, osi_thread_blocking_t blocking); + /* #ifdef __cplusplus } From 442b57b3eef919392ac3fea2f7f4caa9ca545f91 Mon Sep 17 00:00:00 2001 From: Anton Maklakov Date: Thu, 13 Jun 2019 10:05:14 +0700 Subject: [PATCH 076/486] ci: Adjust more 'spawn' settings in test_confserver --- tools/kconfig_new/test/test_confserver.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/kconfig_new/test/test_confserver.py b/tools/kconfig_new/test/test_confserver.py index 20fce7e031..ee9cf43497 100755 --- a/tools/kconfig_new/test/test_confserver.py +++ b/tools/kconfig_new/test/test_confserver.py @@ -51,9 +51,7 @@ def main(): cmdline = "../confserver.py --kconfig Kconfig --config %s" % temp_sdkconfig_path print("Running: %s" % cmdline) - p = pexpect.spawn(cmdline, timeout=2) - p.logfile = args.logfile - p.setecho(False) + p = pexpect.spawn(cmdline, timeout=30, logfile=args.logfile, echo=False, use_poll=True, maxread=1) p.expect("Server running.+\r\n") initial = expect_json(p) From 5c9dc44c496ec99e02fae746a5f77ba88e336b3f Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Thu, 13 Jun 2019 14:12:54 +0800 Subject: [PATCH 077/486] spi: multichip support move hardcoded numbers, etc. into soc files. create headers for shared types which needs to be documented. (MINOR CHANGE) --- components/driver/include/driver/spi_common.h | 28 ++++++------ components/driver/spi_common.c | 43 +++++++++++-------- components/driver/spi_master.c | 10 +++-- components/driver/spi_slave.c | 6 +-- components/driver/test/test_spi_master.c | 8 ++-- .../include/soc/{spi_pins.h => spi_caps.h} | 13 ++++-- components/soc/esp32/spi_periph.c | 5 +++ components/soc/include/hal/spi_hal.h | 6 ++- components/soc/include/hal/spi_ll.h | 4 +- components/soc/include/hal/spi_slave_hal.h | 1 + components/soc/include/hal/spi_types.h | 18 ++++++++ components/soc/include/soc/spi_periph.h | 5 ++- components/soc/src/hal/spi_hal_iram.c | 2 + docs/Doxyfile | 1 + .../api-reference/peripherals/spi_master.rst | 1 + 15 files changed, 102 insertions(+), 49 deletions(-) rename components/soc/esp32/include/soc/{spi_pins.h => spi_caps.h} (84%) create mode 100644 components/soc/include/hal/spi_types.h diff --git a/components/driver/include/driver/spi_common.h b/components/driver/include/driver/spi_common.h index 546735caa0..5fc2ce957c 100644 --- a/components/driver/include/driver/spi_common.h +++ b/components/driver/include/driver/spi_common.h @@ -21,6 +21,7 @@ #include "esp_err.h" #include "esp32/rom/lldesc.h" #include "soc/spi_periph.h" +#include "hal/spi_types.h" #include "sdkconfig.h" #ifdef __cplusplus @@ -61,15 +62,6 @@ extern "C" */ #define SPI_SWAP_DATA_RX(data, len) (__builtin_bswap32(data)>>(32-len)) -/** - * @brief Enum with the three SPI peripherals that are software-accessible in it - */ -typedef enum { - SPI_HOST=0, ///< SPI1, SPI - HSPI_HOST=1, ///< SPI2, HSPI - VSPI_HOST=2 ///< SPI3, VSPI -} spi_host_device_t; - /** * @brief This is a configuration structure for a SPI bus. * @@ -167,7 +159,7 @@ bool spicommon_dma_chan_free(int dma_chan); #define SPICOMMON_BUSFLAG_SLAVE 0 ///< Initialize I/O in slave mode #define SPICOMMON_BUSFLAG_MASTER (1<<0) ///< Initialize I/O in master mode -#define SPICOMMON_BUSFLAG_NATIVE_PINS (1<<1) ///< Check using iomux pins. Or indicates the pins are configured through the IO mux rather than GPIO matrix. +#define SPICOMMON_BUSFLAG_IOMUX_PINS (1<<1) ///< Check using iomux pins. Or indicates the pins are configured through the IO mux rather than GPIO matrix. #define SPICOMMON_BUSFLAG_SCLK (1<<2) ///< Check existing of SCLK pin. Or indicates CLK line initialized. #define SPICOMMON_BUSFLAG_MISO (1<<3) ///< Check existing of MISO pin. Or indicates MISO line initialized. #define SPICOMMON_BUSFLAG_MOSI (1<<4) ///< Check existing of MOSI pin. Or indicates CLK line initialized. @@ -175,6 +167,9 @@ bool spicommon_dma_chan_free(int dma_chan); #define SPICOMMON_BUSFLAG_WPHD (1<<6) ///< Check existing of WP and HD pins. Or indicates WP & HD pins initialized. #define SPICOMMON_BUSFLAG_QUAD (SPICOMMON_BUSFLAG_DUAL|SPICOMMON_BUSFLAG_WPHD) ///< Check existing of MOSI/MISO/WP/HD pins as output. Or indicates bus able to work under QIO mode. +#define SPICOMMON_BUSFLAG_NATIVE_PINS SPICOMMON_BUSFLAG_IOMUX_PINS + + /** * @brief Connect a SPI peripheral to GPIO pins * @@ -188,7 +183,7 @@ bool spicommon_dma_chan_free(int dma_chan); * @param flags Combination of SPICOMMON_BUSFLAG_* flags, set to ensure the pins set are capable with some functions: * - ``SPICOMMON_BUSFLAG_MASTER``: Initialize I/O in master mode * - ``SPICOMMON_BUSFLAG_SLAVE``: Initialize I/O in slave mode - * - ``SPICOMMON_BUSFLAG_NATIVE_PINS``: Pins set should match the iomux pins of the controller. + * - ``SPICOMMON_BUSFLAG_IOMUX_PINS``: Pins set should match the iomux pins of the controller. * - ``SPICOMMON_BUSFLAG_SCLK``, ``SPICOMMON_BUSFLAG_MISO``, ``SPICOMMON_BUSFLAG_MOSI``: * Make sure SCLK/MISO/MOSI is/are set to a valid GPIO. Also check output capability according to the mode. * - ``SPICOMMON_BUSFLAG_DUAL``: Make sure both MISO and MOSI are output capable so that DIO mode is capable. @@ -196,7 +191,7 @@ bool spicommon_dma_chan_free(int dma_chan); * - ``SPICOMMON_BUSFLAG_QUAD``: Combination of ``SPICOMMON_BUSFLAG_DUAL`` and ``SPICOMMON_BUSFLAG_WPHD``. * @param[out] flags_o A SPICOMMON_BUSFLAG_* flag combination of bus abilities will be written to this address. * Leave to NULL if not needed. - * - ``SPICOMMON_BUSFLAG_NATIVE_PINS``: The bus is connected to iomux pins. + * - ``SPICOMMON_BUSFLAG_IOMUX_PINS``: The bus is connected to iomux pins. * - ``SPICOMMON_BUSFLAG_SCLK``, ``SPICOMMON_BUSFLAG_MISO``, ``SPICOMMON_BUSFLAG_MOSI``: The bus has * CLK/MISO/MOSI connected. * - ``SPICOMMON_BUSFLAG_DUAL``: The bus is capable with DIO mode. @@ -294,6 +289,15 @@ spi_dev_t *spicommon_hw_for_host(spi_host_device_t host); */ int spicommon_irqsource_for_host(spi_host_device_t host); +/** + * @brief Get the IRQ source for a specific SPI DMA + * + * @param host The SPI host + * + * @return The hosts IRQ source + */ +int spicommon_irqdma_source_for_host(spi_host_device_t host); + /** * Callback, to be called when a DMA engine reset is completed */ diff --git a/components/driver/spi_common.c b/components/driver/spi_common.c index 6677ef6562..716a795a35 100644 --- a/components/driver/spi_common.c +++ b/components/driver/spi_common.c @@ -1,9 +1,9 @@ -// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2019 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 @@ -49,14 +49,13 @@ static const char *SPI_TAG = "spi"; typedef struct spi_device_t spi_device_t; -#define FUNC_SPI 1 //all pins of HSPI and VSPI shares this function number #define FUNC_GPIO PIN_FUNC_GPIO - #define DMA_CHANNEL_ENABLED(dma_chan) (BIT(dma_chan-1)) //Periph 1 is 'claimed' by SPI flash code. -static atomic_bool spi_periph_claimed[3] = { ATOMIC_VAR_INIT(true), ATOMIC_VAR_INIT(false), ATOMIC_VAR_INIT(false)}; +static atomic_bool spi_periph_claimed[SOC_SPI_PERIPH_NUM] = { ATOMIC_VAR_INIT(true), ATOMIC_VAR_INIT(false), ATOMIC_VAR_INIT(false), +}; static const char* spi_claiming_func[3] = {NULL, NULL, NULL}; static uint8_t spi_dma_chan_enabled = 0; static portMUX_TYPE spi_dma_spinlock = portMUX_INITIALIZER_UNLOCKED; @@ -96,15 +95,25 @@ int spicommon_irqsource_for_host(spi_host_device_t host) return spi_periph_signal[host].irq; } +int spicommon_irqdma_source_for_host(spi_host_device_t host) +{ + return spi_periph_signal[host].irq_dma; +} + spi_dev_t *spicommon_hw_for_host(spi_host_device_t host) { return spi_periph_signal[host].hw; } +static inline uint32_t get_dma_periph(int dma_chan) +{ + return PERIPH_SPI_DMA_MODULE; +} + bool spicommon_dma_chan_claim (int dma_chan) { bool ret = false; - assert( dma_chan == 1 || dma_chan == 2 ); + assert(dma_chan >= 1 && dma_chan <= SOC_SPI_DMA_CHAN_NUM); portENTER_CRITICAL(&spi_dma_spinlock); if ( !(spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan)) ) { @@ -112,7 +121,7 @@ bool spicommon_dma_chan_claim (int dma_chan) spi_dma_chan_enabled |= DMA_CHANNEL_ENABLED(dma_chan); ret = true; } - periph_module_enable( PERIPH_SPI_DMA_MODULE ); + periph_module_enable(get_dma_periph(dma_chan)); portEXIT_CRITICAL(&spi_dma_spinlock); return ret; @@ -133,7 +142,7 @@ bool spicommon_dma_chan_free(int dma_chan) spi_dma_chan_enabled &= ~DMA_CHANNEL_ENABLED(dma_chan); if ( spi_dma_chan_enabled == 0 ) { //disable the DMA only when all the channels are freed. - periph_module_disable( PERIPH_SPI_DMA_MODULE ); + periph_module_disable(get_dma_periph(dma_chan)); } portEXIT_CRITICAL(&spi_dma_spinlock); @@ -212,7 +221,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf //check if the selected pins correspond to the iomux pins of the peripheral bool use_iomux = bus_uses_iomux_pins(host, bus_config); - if (use_iomux) temp_flag |= SPICOMMON_BUSFLAG_NATIVE_PINS; + if (use_iomux) temp_flag |= SPICOMMON_BUSFLAG_IOMUX_PINS; uint32_t missing_flag = flags & ~temp_flag; missing_flag &= ~SPICOMMON_BUSFLAG_MASTER;//don't check this flag @@ -224,7 +233,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf if (missing_flag & SPICOMMON_BUSFLAG_MISO) ESP_LOGE(SPI_TAG, "miso pin required."); if (missing_flag & SPICOMMON_BUSFLAG_DUAL) ESP_LOGE(SPI_TAG, "not both mosi and miso output capable"); if (missing_flag & SPICOMMON_BUSFLAG_WPHD) ESP_LOGE(SPI_TAG, "both wp and hd required."); - if (missing_flag & SPICOMMON_BUSFLAG_NATIVE_PINS) ESP_LOGE(SPI_TAG, "not using iomux pins"); + if (missing_flag & SPICOMMON_BUSFLAG_IOMUX_PINS) ESP_LOGE(SPI_TAG, "not using iomux pins"); SPI_CHECK(missing_flag == 0, "not all required capabilities satisfied.", ESP_ERR_INVALID_ARG); } @@ -234,25 +243,25 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf ESP_LOGD(SPI_TAG, "SPI%d use iomux pins.", host+1); if (bus_config->mosi_io_num >= 0) { gpio_iomux_in(bus_config->mosi_io_num, spi_periph_signal[host].spid_in); - gpio_iomux_out(bus_config->mosi_io_num, FUNC_SPI, false); + gpio_iomux_out(bus_config->mosi_io_num, spi_periph_signal[host].func, false); } if (bus_config->miso_io_num >= 0) { gpio_iomux_in(bus_config->miso_io_num, spi_periph_signal[host].spiq_in); - gpio_iomux_out(bus_config->miso_io_num, FUNC_SPI, false); + gpio_iomux_out(bus_config->miso_io_num, spi_periph_signal[host].func, false); } if (bus_config->quadwp_io_num >= 0) { gpio_iomux_in(bus_config->quadwp_io_num, spi_periph_signal[host].spiwp_in); - gpio_iomux_out(bus_config->quadwp_io_num, FUNC_SPI, false); + gpio_iomux_out(bus_config->quadwp_io_num, spi_periph_signal[host].func, false); } if (bus_config->quadhd_io_num >= 0) { gpio_iomux_in(bus_config->quadhd_io_num, spi_periph_signal[host].spihd_in); - gpio_iomux_out(bus_config->quadhd_io_num, FUNC_SPI, false); + gpio_iomux_out(bus_config->quadhd_io_num, spi_periph_signal[host].func, false); } if (bus_config->sclk_io_num >= 0) { gpio_iomux_in(bus_config->sclk_io_num, spi_periph_signal[host].spiclk_in); - gpio_iomux_out(bus_config->sclk_io_num, FUNC_SPI, false); + gpio_iomux_out(bus_config->sclk_io_num, spi_periph_signal[host].func, false); } - temp_flag |= SPICOMMON_BUSFLAG_NATIVE_PINS; + temp_flag |= SPICOMMON_BUSFLAG_IOMUX_PINS; } else { //Use GPIO matrix ESP_LOGD(SPI_TAG, "SPI%d use gpio matrix.", host+1); @@ -354,7 +363,7 @@ void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num, if (!force_gpio_matrix && cs_io_num == spi_periph_signal[host].spics0_iomux_pin && cs_num == 0) { //The cs0s for all SPI peripherals map to pin mux source 1, so we use that instead of a define. gpio_iomux_in(cs_io_num, spi_periph_signal[host].spics_in); - gpio_iomux_out(cs_io_num, FUNC_SPI, false); + gpio_iomux_out(cs_io_num, spi_periph_signal[host].func, false); } else { //Use GPIO matrix if (GPIO_IS_VALID_OUTPUT_GPIO(cs_io_num)) { diff --git a/components/driver/spi_master.c b/components/driver/spi_master.c index 90382fd01a..fcbbdedc97 100644 --- a/components/driver/spi_master.c +++ b/components/driver/spi_master.c @@ -199,7 +199,7 @@ struct spi_device_t { bool waiting; //the device is waiting for the exclusive control of the bus }; -static spi_host_t *spihost[3]; +static spi_host_t *spihost[SOC_SPI_PERIPH_NUM]; static const char *SPI_TAG = "spi_master"; @@ -263,7 +263,7 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus int dma_desc_ct=0; spihost[host]->dma_chan=dma_chan; if (dma_chan == 0) { - spihost[host]->max_transfer_sz = 64; + spihost[host]->max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE; } else { //See how many dma descriptors we need and allocate them dma_desc_ct=lldesc_get_required_num(bus_config->max_transfer_sz); @@ -389,13 +389,15 @@ esp_err_t spi_bus_add_device(spi_host_device_t host, const spi_device_interface_ int freq; spi_hal_context_t *hal = &spihost[host]->hal; hal->half_duplex = dev_config->flags & SPI_DEVICE_HALFDUPLEX ? 1 : 0; +#ifdef SOC_SPI_SUPPORT_AS_CS hal->as_cs = dev_config->flags & SPI_DEVICE_CLK_AS_CS ? 1 : 0; +#endif hal->positive_cs = dev_config->flags & SPI_DEVICE_POSITIVE_CS ? 1 : 0; hal->no_compensate = dev_config->flags & SPI_DEVICE_NO_DUMMY ? 1 : 0; spi_hal_timing_conf_t temp_timing_conf; esp_err_t ret = spi_hal_get_clock_conf(hal, dev_config->clock_speed_hz, duty_cycle, - !(spihost[host]->flags & SPICOMMON_BUSFLAG_NATIVE_PINS), + !(spihost[host]->flags & SPICOMMON_BUSFLAG_IOMUX_PINS), dev_config->input_delay_ns, &freq, &temp_timing_conf); @@ -427,7 +429,7 @@ esp_err_t spi_bus_add_device(spi_host_device_t host, const spi_device_interface_ //Set CS pin, CS options if (dev_config->spics_io_num >= 0) { - spicommon_cs_initialize(host, dev_config->spics_io_num, freecs, !(spihost[host]->flags&SPICOMMON_BUSFLAG_NATIVE_PINS)); + spicommon_cs_initialize(host, dev_config->spics_io_num, freecs, !(spihost[host]->flags&SPICOMMON_BUSFLAG_IOMUX_PINS)); } *handle=dev; diff --git a/components/driver/spi_slave.c b/components/driver/spi_slave.c index f9f792a280..2cac4610ff 100644 --- a/components/driver/spi_slave.c +++ b/components/driver/spi_slave.c @@ -72,13 +72,13 @@ typedef struct { #endif } spi_slave_t; -static spi_slave_t *spihost[3]; +static spi_slave_t *spihost[SOC_SPI_PERIPH_NUM]; static void IRAM_ATTR spi_intr(void *arg); static inline bool bus_is_iomux(spi_slave_t *host) { - return host->flags&SPICOMMON_BUSFLAG_NATIVE_PINS; + return host->flags&SPICOMMON_BUSFLAG_IOMUX_PINS; } static void freeze_cs(spi_slave_t *host) @@ -149,7 +149,7 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b spihost[host]->max_transfer_sz = dma_desc_ct * SPI_MAX_DMA_LEN; } else { //We're limited to non-DMA transfers: the SPI work registers can hold 64 bytes at most. - spihost[host]->max_transfer_sz = 16 * 4; + spihost[host]->max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE; } #ifdef CONFIG_PM_ENABLE err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_slave", diff --git a/components/driver/test/test_spi_master.c b/components/driver/test/test_spi_master.c index 22b1961cc0..5b1c3c2335 100644 --- a/components/driver/test/test_spi_master.c +++ b/components/driver/test/test_spi_master.c @@ -329,7 +329,7 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]") uint32_t flags_expected; ESP_LOGI(TAG, "test 6 iomux output pins..."); - flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_NATIVE_PINS | SPICOMMON_BUSFLAG_QUAD; + flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_IOMUX_PINS | SPICOMMON_BUSFLAG_QUAD; cfg = (spi_bus_config_t){.mosi_io_num = HSPI_IOMUX_PIN_NUM_MOSI, .miso_io_num = HSPI_IOMUX_PIN_NUM_MISO, .sclk_io_num = HSPI_IOMUX_PIN_NUM_CLK, .quadhd_io_num = HSPI_IOMUX_PIN_NUM_HD, .quadwp_io_num = HSPI_IOMUX_PIN_NUM_WP, .max_transfer_sz = 8, .flags = flags_expected}; TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o)); @@ -338,7 +338,7 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]") TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o ); ESP_LOGI(TAG, "test 4 iomux output pins..."); - flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_NATIVE_PINS | SPICOMMON_BUSFLAG_DUAL; + flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_IOMUX_PINS | SPICOMMON_BUSFLAG_DUAL; cfg = (spi_bus_config_t){.mosi_io_num = HSPI_IOMUX_PIN_NUM_MOSI, .miso_io_num = HSPI_IOMUX_PIN_NUM_MISO, .sclk_io_num = HSPI_IOMUX_PIN_NUM_CLK, .quadhd_io_num = -1, .quadwp_io_num = -1, .max_transfer_sz = 8, .flags = flags_expected}; TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o)); @@ -396,7 +396,7 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]") TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o ); ESP_LOGI(TAG, "check native flag for 6 output pins..."); - flags_expected = SPICOMMON_BUSFLAG_NATIVE_PINS; + flags_expected = SPICOMMON_BUSFLAG_IOMUX_PINS; //swap MOSI and MISO cfg = (spi_bus_config_t){.mosi_io_num = HSPI_IOMUX_PIN_NUM_MISO, .miso_io_num = HSPI_IOMUX_PIN_NUM_MOSI, .sclk_io_num = HSPI_IOMUX_PIN_NUM_CLK, .quadhd_io_num = HSPI_IOMUX_PIN_NUM_HD, .quadwp_io_num = HSPI_IOMUX_PIN_NUM_WP, .max_transfer_sz = 8, .flags = flags_expected}; @@ -404,7 +404,7 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]") TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o)); ESP_LOGI(TAG, "check native flag for 4 output pins..."); - flags_expected = SPICOMMON_BUSFLAG_NATIVE_PINS; + flags_expected = SPICOMMON_BUSFLAG_IOMUX_PINS; //swap MOSI and MISO cfg = (spi_bus_config_t){.mosi_io_num = HSPI_IOMUX_PIN_NUM_MISO, .miso_io_num = HSPI_IOMUX_PIN_NUM_MOSI, .sclk_io_num = HSPI_IOMUX_PIN_NUM_CLK, .quadhd_io_num = -1, .quadwp_io_num = -1, .max_transfer_sz = 8, .flags = flags_expected}; diff --git a/components/soc/esp32/include/soc/spi_pins.h b/components/soc/esp32/include/soc/spi_caps.h similarity index 84% rename from components/soc/esp32/include/soc/spi_pins.h rename to components/soc/esp32/include/soc/spi_caps.h index 80a17ff090..881e229976 100644 --- a/components/soc/esp32/include/soc/spi_pins.h +++ b/components/soc/esp32/include/soc/spi_caps.h @@ -12,8 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef _SOC_SPI_PINS_H_ -#define _SOC_SPI_PINS_H_ +#ifndef _SOC_SPI_CAPS_H_ +#define _SOC_SPI_CAPS_H_ + +#define SOC_SPI_PERIPH_NUM 3 +#define SOC_SPI_DMA_CHAN_NUM 2 #define SPI_IOMUX_PIN_NUM_MISO 7 #define SPI_IOMUX_PIN_NUM_MOSI 8 @@ -44,4 +47,8 @@ #define VSPI_IOMUX_PIN_NUM_WP 22 #define VSPI_IOMUX_PIN_NUM_HD 21 -#endif /* _SOC_SPI_PINS_H_ */ \ No newline at end of file +#define SOC_SPI_MAXIMUM_BUFFER_SIZE 64 + +#define SOC_SPI_SUPPORT_AS_CS 1 //Support to toggle the CS while the clock toggles + +#endif /* _SOC_SPI_CAPS_H_ */ \ No newline at end of file diff --git a/components/soc/esp32/spi_periph.c b/components/soc/esp32/spi_periph.c index 0847777089..a800cc6ec5 100644 --- a/components/soc/esp32/spi_periph.c +++ b/components/soc/esp32/spi_periph.c @@ -14,6 +14,8 @@ #include "soc/spi_periph.h" +#define FUNC_SPI 1 //all pins of SPI1, HSPI and VSPI shares this function number + /* Bunch of constants for every SPI peripheral: GPIO signals, irqs, hw addr of registers etc */ @@ -40,6 +42,7 @@ const spi_signal_conn_t spi_periph_signal[3] = { .irq = ETS_SPI1_INTR_SOURCE, .irq_dma = ETS_SPI1_DMA_INTR_SOURCE, .module = PERIPH_SPI_MODULE, + .func = FUNC_SPI, .hw = &SPI1 }, { .spiclk_out = HSPICLK_OUT_IDX, @@ -63,6 +66,7 @@ const spi_signal_conn_t spi_periph_signal[3] = { .irq = ETS_SPI2_INTR_SOURCE, .irq_dma = ETS_SPI2_DMA_INTR_SOURCE, .module = PERIPH_HSPI_MODULE, + .func = FUNC_SPI, .hw = &SPI2 }, { .spiclk_out = VSPICLK_OUT_IDX, @@ -86,6 +90,7 @@ const spi_signal_conn_t spi_periph_signal[3] = { .irq = ETS_SPI3_INTR_SOURCE, .irq_dma = ETS_SPI3_DMA_INTR_SOURCE, .module = PERIPH_VSPI_MODULE, + .func = FUNC_SPI, .hw = &SPI3 } }; \ No newline at end of file diff --git a/components/soc/include/hal/spi_hal.h b/components/soc/include/hal/spi_hal.h index ddc34e29b6..2012433a26 100644 --- a/components/soc/include/hal/spi_hal.h +++ b/components/soc/include/hal/spi_hal.h @@ -34,7 +34,7 @@ // field comments. #pragma once -#include "spi_ll.h" +#include "hal/spi_ll.h" #include #include "soc/lldesc.h" @@ -85,7 +85,9 @@ typedef struct { uint32_t rx_lsbfirst : 1; ///< Whether LSB is received first for RX data, device specific uint32_t dma_enabled : 1; ///< Whether the DMA is enabled, do not update after initialization uint32_t no_compensate : 1; ///< No need to add dummy to compensate the timing, device specific - uint32_t as_cs : 1; ///< Whether the AS_CS feature is enabled, device specific +#ifdef SOC_SPI_SUPPORT_AS_CS + uint32_t as_cs : 1; ///< Whether to toggle the CS while the clock toggles, device specific +#endif uint32_t positive_cs : 1; ///< Whether the postive CS feature is abled, device specific };//boolean configurations diff --git a/components/soc/include/hal/spi_ll.h b/components/soc/include/hal/spi_ll.h index 31feb83302..0213d6dc12 100644 --- a/components/soc/include/hal/spi_ll.h +++ b/components/soc/include/hal/spi_ll.h @@ -18,11 +18,11 @@ * See readme.md in soc/include/hal/readme.md ******************************************************************************/ -// The LL layer for SPI register operations +// The LL layer for ESP32 SPI register operations #pragma once -#include "hal_defs.h" +#include "hal/hal_defs.h" #include "soc/spi_periph.h" #include "esp32/rom/lldesc.h" #include diff --git a/components/soc/include/hal/spi_slave_hal.h b/components/soc/include/hal/spi_slave_hal.h index 81d1706a7f..80e1113716 100644 --- a/components/soc/include/hal/spi_slave_hal.h +++ b/components/soc/include/hal/spi_slave_hal.h @@ -35,6 +35,7 @@ #include "soc/lldesc.h" #include "soc/spi_struct.h" #include +#include "soc/spi_caps.h" /** * Context that should be maintained by both the driver and the HAL. diff --git a/components/soc/include/hal/spi_types.h b/components/soc/include/hal/spi_types.h new file mode 100644 index 0000000000..12ee775e1e --- /dev/null +++ b/components/soc/include/hal/spi_types.h @@ -0,0 +1,18 @@ +#pragma once + +#include "soc/spi_caps.h" +#include "sdkconfig.h" + +/** + * @brief Enum with the three SPI peripherals that are software-accessible in it + */ +typedef enum { + SPI1_HOST=0, ///< SPI1 + SPI2_HOST=1, ///< SPI2 + SPI3_HOST=2, ///< SPI3 +} spi_host_device_t; + +//alias for different chips +#define SPI_HOST SPI1_HOST +#define HSPI_HOST SPI2_HOST +#define VSPI_HOST SPI3_HOST diff --git a/components/soc/include/soc/spi_periph.h b/components/soc/include/soc/spi_periph.h index 812c1becac..bbe864eb6f 100644 --- a/components/soc/include/soc/spi_periph.h +++ b/components/soc/include/soc/spi_periph.h @@ -17,7 +17,7 @@ #include "soc/soc.h" #include "soc/periph_defs.h" //include soc related (generated) definitions -#include "soc/spi_pins.h" +#include "soc/spi_caps.h" #include "soc/spi_reg.h" #include "soc/spi_struct.h" #include "soc/gpio_sig_map.h" @@ -52,10 +52,11 @@ typedef struct { const uint8_t irq; //irq source for interrupt mux const uint8_t irq_dma; //dma irq source for interrupt mux const periph_module_t module; //peripheral module, for enabling clock etc + const int func; //function number for IOMUX spi_dev_t *hw; //Pointer to the hardware registers } spi_signal_conn_t; -extern const spi_signal_conn_t spi_periph_signal[3]; +extern const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM]; #ifdef __cplusplus } diff --git a/components/soc/src/hal/spi_hal_iram.c b/components/soc/src/hal/spi_hal_iram.c index 2bf0aadb80..57f5607853 100644 --- a/components/soc/src/hal/spi_hal_iram.c +++ b/components/soc/src/hal/spi_hal_iram.c @@ -21,7 +21,9 @@ void spi_hal_setup_device(const spi_hal_context_t *hal) { //Configure clock settings spi_dev_t *hw = hal->hw; +#ifdef SOC_SPI_SUPPORT_AS_CS spi_ll_master_set_cksel(hw, hal->cs_pin_id, hal->as_cs); +#endif spi_ll_master_set_pos_cs(hw, hal->cs_pin_id, hal->positive_cs); spi_ll_master_set_clock_by_reg(hw, &hal->timing_conf->clock_reg); //Configure bit order diff --git a/docs/Doxyfile b/docs/Doxyfile index 858a6a39e0..5d7661e24d 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -87,6 +87,7 @@ INPUT = \ ../../components/driver/include/driver/touch_pad.h \ ../../components/driver/include/driver/uart.h \ ../../components/esp_adc_cal/include/esp_adc_cal.h \ + ../../components/soc/include/hal/spi_types.h \ ../../components/soc/esp32/include/soc/adc_channel.h \ ../../components/soc/esp32/include/soc/dac_channel.h \ ../../components/soc/esp32/include/soc/touch_channel.h \ diff --git a/docs/en/api-reference/peripherals/spi_master.rst b/docs/en/api-reference/peripherals/spi_master.rst index e02bda1513..13084274fc 100644 --- a/docs/en/api-reference/peripherals/spi_master.rst +++ b/docs/en/api-reference/peripherals/spi_master.rst @@ -538,6 +538,7 @@ Display graphics on the 320x240 LCD of WROVER-Kits: :example:`peripherals/spi_ma API Reference - SPI Common -------------------------- +.. include:: /_build/inc/spi_types.inc .. include:: /_build/inc/spi_common.inc From 2eff8f774237072240f9c8401acf4573ca12b4a8 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Thu, 13 Jun 2019 15:09:28 +0800 Subject: [PATCH 078/486] spi_slave: fix a example issue caused by word alignment --- examples/peripherals/spi_slave/receiver/main/app_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/peripherals/spi_slave/receiver/main/app_main.c b/examples/peripherals/spi_slave/receiver/main/app_main.c index c5362dd97b..1a51c653a4 100644 --- a/examples/peripherals/spi_slave/receiver/main/app_main.c +++ b/examples/peripherals/spi_slave/receiver/main/app_main.c @@ -109,8 +109,8 @@ void app_main() ret=spi_slave_initialize(HSPI_HOST, &buscfg, &slvcfg, 1); assert(ret==ESP_OK); - char sendbuf[129]=""; - char recvbuf[129]=""; + WORD_ALIGNED_ATTR char sendbuf[129]=""; + WORD_ALIGNED_ATTR char recvbuf[129]=""; memset(recvbuf, 0, 33); spi_slave_transaction_t t; memset(&t, 0, sizeof(t)); From caf121e4b6a67e7ce1746a69bc246257f972da1b Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Wed, 19 Jun 2019 16:37:55 +0800 Subject: [PATCH 079/486] esp_flash: break the inappropriate include chain in spi_flash_host_drv.h --- components/soc/esp32/include/hal/spi_flash_ll.h | 13 +------------ components/soc/include/hal/spi_flash_hal.h | 2 +- .../{spi_flash_host_drv.h => spi_flash_types.h} | 14 +++++++++++++- components/spi_flash/include/esp_flash.h | 2 +- 4 files changed, 16 insertions(+), 15 deletions(-) rename components/soc/include/hal/{spi_flash_host_drv.h => spi_flash_types.h} (87%) diff --git a/components/soc/esp32/include/hal/spi_flash_ll.h b/components/soc/esp32/include/hal/spi_flash_ll.h index f9adbd5f1b..7155e0a872 100644 --- a/components/soc/esp32/include/hal/spi_flash_ll.h +++ b/components/soc/esp32/include/hal/spi_flash_ll.h @@ -24,6 +24,7 @@ #include #include "soc/spi_periph.h" +#include "hal/spi_flash_types.h" #include // For MIN/MAX #include #include @@ -43,18 +44,6 @@ ///Slowest io mode supported by ESP32, currently SlowRd #define SPI_FLASH_READ_MODE_MIN SPI_FLASH_SLOWRD -/** @brief Mode used for reading from SPI flash */ -typedef enum { - SPI_FLASH_SLOWRD = 0, ///< Data read using single I/O, some limits on speed - SPI_FLASH_FASTRD, ///< Data read using single I/O, no limit on speed - SPI_FLASH_DOUT, ///< Data read using dual I/O - SPI_FLASH_DIO, ///< Both address & data transferred using dual I/O - SPI_FLASH_QOUT, ///< Data read using quad I/O - SPI_FLASH_QIO, ///< Both address & data transferred using quad I/O - - SPI_FLASH_READ_MODE_MAX, ///< The fastest io mode supported by the host is ``ESP_FLASH_READ_MODE_MAX-1``. -} esp_flash_read_mode_t; - /// type to store pre-calculated register value in above layers typedef typeof(SPI1.clock) spi_flash_ll_clock_reg_t; diff --git a/components/soc/include/hal/spi_flash_hal.h b/components/soc/include/hal/spi_flash_hal.h index 1a5c373614..49972c5199 100644 --- a/components/soc/include/hal/spi_flash_hal.h +++ b/components/soc/include/hal/spi_flash_hal.h @@ -23,7 +23,7 @@ #pragma once #include "hal/spi_flash_ll.h" -#include "hal/spi_flash_host_drv.h" +#include "hal/spi_flash_types.h" #include "soc/soc_memory_layout.h" #define ESP_FLASH_DEFAULT_FREQ ESP_FLASH_20MHZ diff --git a/components/soc/include/hal/spi_flash_host_drv.h b/components/soc/include/hal/spi_flash_types.h similarity index 87% rename from components/soc/include/hal/spi_flash_host_drv.h rename to components/soc/include/hal/spi_flash_types.h index 5095bc8f50..067d10fd4b 100644 --- a/components/soc/include/hal/spi_flash_host_drv.h +++ b/components/soc/include/hal/spi_flash_types.h @@ -14,7 +14,7 @@ #pragma once -#include "hal/spi_flash_ll.h" +#include #include "hal/esp_flash_err.h" /** Definition of a common transaction. Also holds the return value. */ @@ -26,6 +26,18 @@ typedef struct { uint32_t miso_data[2]; ///< [out] Input data from slave, little endian } spi_flash_trans_t; +/** @brief Mode used for reading from SPI flash */ +typedef enum { + SPI_FLASH_SLOWRD = 0, ///< Data read using single I/O, some limits on speed + SPI_FLASH_FASTRD, ///< Data read using single I/O, no limit on speed + SPI_FLASH_DOUT, ///< Data read using dual I/O + SPI_FLASH_DIO, ///< Both address & data transferred using dual I/O + SPI_FLASH_QOUT, ///< Data read using quad I/O + SPI_FLASH_QIO, ///< Both address & data transferred using quad I/O + + SPI_FLASH_READ_MODE_MAX, ///< The fastest io mode supported by the host is ``ESP_FLASH_READ_MODE_MAX-1``. +} esp_flash_read_mode_t; + struct spi_flash_host_driver_t; typedef struct spi_flash_host_driver_t spi_flash_host_driver_t; diff --git a/components/spi_flash/include/esp_flash.h b/components/spi_flash/include/esp_flash.h index 904b09b493..48eedcda37 100644 --- a/components/spi_flash/include/esp_flash.h +++ b/components/spi_flash/include/esp_flash.h @@ -17,7 +17,7 @@ #include #include -#include "hal/spi_flash_host_drv.h" +#include "hal/spi_flash_types.h" struct spi_flash_chip_t; typedef struct spi_flash_chip_t spi_flash_chip_t; From 026533cd72190bff864af971238bdeff0964fd32 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 19 Jun 2019 16:37:11 +0800 Subject: [PATCH 080/486] esp_flash: fix C++ compilation and some typos --- components/soc/include/hal/esp_flash_err.h | 8 +++- components/soc/include/hal/spi_flash_hal.h | 23 ---------- components/soc/include/hal/spi_flash_types.h | 28 ++++++++++++ components/spi_flash/README.rst | 10 ++--- components/spi_flash/esp_flash_api.c | 10 ++--- components/spi_flash/include/esp_flash.h | 46 ++++++++++++-------- components/spi_flash/spi_flash_os_func_app.c | 8 ++-- 7 files changed, 76 insertions(+), 57 deletions(-) diff --git a/components/soc/include/hal/esp_flash_err.h b/components/soc/include/hal/esp_flash_err.h index c760f19fe6..cde56aa507 100644 --- a/components/soc/include/hal/esp_flash_err.h +++ b/components/soc/include/hal/esp_flash_err.h @@ -17,6 +17,10 @@ #include #include "esp_err.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * Possible errors returned from esp flash internal functions, these error codes * should be consistent with esp_err_t codes. But in order to make the source @@ -36,4 +40,6 @@ #define ESP_ERR_FLASH_UNSUPPORTED_CHIP (ESP_ERR_FLASH_ERR_BASE+5) ///< Requested operation isn't supported by this model of SPI flash chip. #define ESP_ERR_FLASH_PROTECTED (ESP_ERR_FLASH_ERR_BASE+6) ///< Write operation failed due to chip's write protection being enabled. - +#ifdef __cplusplus +} +#endif diff --git a/components/soc/include/hal/spi_flash_hal.h b/components/soc/include/hal/spi_flash_hal.h index 49972c5199..cd0fb5d361 100644 --- a/components/soc/include/hal/spi_flash_hal.h +++ b/components/soc/include/hal/spi_flash_hal.h @@ -26,33 +26,10 @@ #include "hal/spi_flash_types.h" #include "soc/soc_memory_layout.h" -#define ESP_FLASH_DEFAULT_FREQ ESP_FLASH_20MHZ - /* Hardware host-specific constants */ #define SPI_FLASH_HAL_MAX_WRITE_BYTES 64 #define SPI_FLASH_HAL_MAX_READ_BYTES 64 -///Lowest speed supported by the driver, currently 5 MHz -#define ESP_FLASH_SPEED_MIN ESP_FLASH_5MHZ - -/** - * @brief SPI flash clock speed values, always refer to them by the enum rather - * than the actual value (more speed may be appended into the list). - * - * A strategy to select the maximum allowed speed is to enumerate from the - * ``ESP_FLSH_SPEED_MAX-1`` or highest frequency supported by your flash, and - * decrease the speed until the probing success. - */ -typedef enum { - ESP_FLASH_5MHZ = 0, ///< The flash runs under 5MHz - ESP_FLASH_10MHZ, ///< The flash runs under 10MHz - ESP_FLASH_20MHZ, ///< The flash runs under 20MHz - ESP_FLASH_26MHZ, ///< The flash runs under 26MHz - ESP_FLASH_40MHZ, ///< The flash runs under 40MHz - ESP_FLASH_80MHZ, ///< The flash runs under 80MHz - ESP_FLASH_SPEED_MAX, ///< The maximum frequency supported by the host is ``ESP_FLASH_SPEED_MAX-1``. -} esp_flash_speed_t; - /** * Generic driver context structure for all chips using the SPI peripheral. * Include this into the HEAD of the driver data for other driver diff --git a/components/soc/include/hal/spi_flash_types.h b/components/soc/include/hal/spi_flash_types.h index 067d10fd4b..28e591f82a 100644 --- a/components/soc/include/hal/spi_flash_types.h +++ b/components/soc/include/hal/spi_flash_types.h @@ -17,6 +17,10 @@ #include #include "hal/esp_flash_err.h" +#ifdef __cplusplus +extern "C" { +#endif + /** Definition of a common transaction. Also holds the return value. */ typedef struct { uint8_t command; ///< Command to send, always 8bits @@ -26,6 +30,27 @@ typedef struct { uint32_t miso_data[2]; ///< [out] Input data from slave, little endian } spi_flash_trans_t; +/** + * @brief SPI flash clock speed values, always refer to them by the enum rather + * than the actual value (more speed may be appended into the list). + * + * A strategy to select the maximum allowed speed is to enumerate from the + * ``ESP_FLSH_SPEED_MAX-1`` or highest frequency supported by your flash, and + * decrease the speed until the probing success. + */ +typedef enum { + ESP_FLASH_5MHZ = 0, ///< The flash runs under 5MHz + ESP_FLASH_10MHZ, ///< The flash runs under 10MHz + ESP_FLASH_20MHZ, ///< The flash runs under 20MHz + ESP_FLASH_26MHZ, ///< The flash runs under 26MHz + ESP_FLASH_40MHZ, ///< The flash runs under 40MHz + ESP_FLASH_80MHZ, ///< The flash runs under 80MHz + ESP_FLASH_SPEED_MAX, ///< The maximum frequency supported by the host is ``ESP_FLASH_SPEED_MAX-1``. +} esp_flash_speed_t; + +///Lowest speed supported by the driver, currently 5 MHz +#define ESP_FLASH_SPEED_MIN ESP_FLASH_5MHZ + /** @brief Mode used for reading from SPI flash */ typedef enum { SPI_FLASH_SLOWRD = 0, ///< Data read using single I/O, some limits on speed @@ -122,3 +147,6 @@ struct spi_flash_host_driver_t { bool (*region_protected)(spi_flash_host_driver_t* driver, uint32_t addr, uint32_t size); }; +#ifdef __cplusplus +} +#endif diff --git a/components/spi_flash/README.rst b/components/spi_flash/README.rst index e65b1ad4c6..26387c04a5 100644 --- a/components/spi_flash/README.rst +++ b/components/spi_flash/README.rst @@ -146,7 +146,7 @@ Implementation The ``esp_flash_t`` structure holds chip data as well as three important parts of this API: 1. The host driver, which provides the hardware support to access the chip; -2. The chip driver, which provides compability service to different chips; +2. The chip driver, which provides compatibility service to different chips; 3. The OS functions, provides support of some OS functions (e.g. lock, delay) in different stages (1st/2st boot, or the app). @@ -167,7 +167,7 @@ wrap these functions as ``spi_flash_host_driver_t`` for upper layer to use. You can also implement your own host driver, even with the GPIO. As long as all the functions in the ``spi_flash_host_driver_t`` are implemented, the -esp_flash API can access to the flash regardless of the lowlevel hardware. +esp_flash API can access to the flash regardless of the low-level hardware. Chip driver ^^^^^^^^^^^ @@ -188,17 +188,17 @@ The chip driver relies on the host driver. OS functions ^^^^^^^^^^^^ -Currently the OS function layer provides a lock and a delay entrance. +Currently the OS function layer provides a lock and a delay entries. The lock is used to resolve the conflicts between the SPI chip access and -other functions. E.g. the cache (used for the code and psram data fetch) +other functions. E.g. the cache (used for the code and PSRAM data fetch) should be disabled when the flash chip on the SPI0/1 is being accessed. Also, some devices which don't have CS wire, or the wire is controlled by the software (e.g. SD card via SPI interface), requires the bus to be monopolized during a period. The delay is used by some long operations which requires the master to wait -or polling periodly. +or polling periodically. The top API wraps these the chip driver and OS functions into an entire diff --git a/components/spi_flash/esp_flash_api.c b/components/spi_flash/esp_flash_api.c index 3a48154c7b..48533ec573 100644 --- a/components/spi_flash/esp_flash_api.c +++ b/components/spi_flash/esp_flash_api.c @@ -448,11 +448,11 @@ static esp_err_t find_region(const esp_flash_t *chip, const esp_flash_region_t * return ESP_ERR_NOT_FOUND; } -esp_err_t IRAM_ATTR esp_flash_get_protected_region(esp_flash_t *chip, const esp_flash_region_t *region, bool *protected) +esp_err_t IRAM_ATTR esp_flash_get_protected_region(esp_flash_t *chip, const esp_flash_region_t *region, bool *out_protected) { VERIFY_OP(get_protected_regions); - if (protected == NULL) { + if (out_protected == NULL) { return ESP_ERR_INVALID_ARG; } @@ -470,13 +470,13 @@ esp_err_t IRAM_ATTR esp_flash_get_protected_region(esp_flash_t *chip, const esp_ err = chip->chip_drv->get_protected_regions(chip, &protection_mask); if (err == ESP_OK) { - *protected = protection_mask & (1LL << index); + *out_protected = protection_mask & (1LL << index); } return spiflash_end(chip, err); } -esp_err_t IRAM_ATTR esp_flash_set_protected_region(esp_flash_t *chip, const esp_flash_region_t *region, bool protected) +esp_err_t IRAM_ATTR esp_flash_set_protected_region(esp_flash_t *chip, const esp_flash_region_t *region, bool protect) { VERIFY_OP(set_protected_regions); @@ -494,7 +494,7 @@ esp_err_t IRAM_ATTR esp_flash_set_protected_region(esp_flash_t *chip, const esp_ err = chip->chip_drv->get_protected_regions(chip, &protection_mask); if (err == ESP_OK) { - if (protected) { + if (protect) { protection_mask |= (1LL << index); } else { protection_mask &= ~(1LL << index); diff --git a/components/spi_flash/include/esp_flash.h b/components/spi_flash/include/esp_flash.h index 48eedcda37..81524dc5d2 100644 --- a/components/spi_flash/include/esp_flash.h +++ b/components/spi_flash/include/esp_flash.h @@ -19,6 +19,10 @@ #include "hal/spi_flash_types.h" +#ifdef __cplusplus +extern "C" { +#endif + struct spi_flash_chip_t; typedef struct spi_flash_chip_t spi_flash_chip_t; @@ -50,11 +54,11 @@ typedef struct { Structure must be passed to esp_flash_init() before use. */ struct esp_flash_t { - const spi_flash_chip_t *chip_drv; ///< Pointer to chip-model-specific "adpater" structure. If NULL, will be detected during initialisatiopn. + const spi_flash_chip_t *chip_drv; ///< Pointer to chip-model-specific "adapter" structure. If NULL, will be detected during initialisation. spi_flash_host_driver_t *host; ///< Pointer to hardware-specific "host_driver" structure. - const esp_flash_os_functions_t *os_func; ///< Pointer to os-specific hooker strcuture. - void *os_func_data; ///< Pointer to argument for os-specific hooker. + const esp_flash_os_functions_t *os_func; ///< Pointer to os-specific hook structure. + void *os_func_data; ///< Pointer to argument for os-specific hooks. esp_flash_read_mode_t read_mode; ///< Configured SPI flash read mode. Set before initialisation. uint32_t size; ///< Size of SPI flash in bytes. If 0, size will be detected during initialisation. @@ -65,7 +69,7 @@ struct esp_flash_t { * * This function must be called before any other API functions are called for this chip. * - * @note Only the spi, speed & read_mode fields of the chip structure need to be initialised. Other fields will be auto-detected + * @note Only the host, speed & read_mode fields of the chip structure need to be initialised. Other fields will be auto-detected * if left set to zero or NULL. * * @note If the chip->drv pointer is NULL, chip chip_drv will be autodetected based on its manufacturer & product IDs. See @@ -175,15 +179,14 @@ esp_err_t esp_flash_set_chip_write_protect(esp_flash_t *chip, bool write_protect * * @return ESP_OK on success, or a flash error code if operation failed. */ -esp_err_t -esp_flash_get_protectable_regions(const esp_flash_t *chip, const esp_flash_region_t **regions, uint32_t *num_regions); +esp_err_t esp_flash_get_protectable_regions(const esp_flash_t *chip, const esp_flash_region_t **regions, uint32_t *num_regions); /** @brief Detect if a region of the SPI flash chip is protected * * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() * @param region Pointer to a struct describing a protected region. This must match one of the regions returned from esp_flash_get_protectable_regions(...). - * @param[out] protected Pointer to a flag which is set based on the protected status for this region. + * @param[out] out_protected Pointer to a flag which is set based on the protected status for this region. * * @note It is possible for this result to be false and write operations to still fail, if protection is enabled for the entire chip. * @@ -192,13 +195,13 @@ esp_flash_get_protectable_regions(const esp_flash_t *chip, const esp_flash_regio * * @return ESP_OK on success, or a flash error code if operation failed. */ -esp_err_t esp_flash_get_protected_region(esp_flash_t *chip, const esp_flash_region_t *region, bool *protected); +esp_err_t esp_flash_get_protected_region(esp_flash_t *chip, const esp_flash_region_t *region, bool *out_protected); /** @brief Update the protected status for a region of the SPI flash chip * * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() * @param region Pointer to a struct describing a protected region. This must match one of the regions returned from esp_flash_get_protectable_regions(...). - * @param protected Write protection flag to set. + * @param protect Write protection flag to set. * * @note It is possible for the region protection flag to be cleared and write operations to still fail, if protection is enabled for the entire chip. * @@ -207,7 +210,7 @@ esp_err_t esp_flash_get_protected_region(esp_flash_t *chip, const esp_flash_regi * * @return ESP_OK on success, or a flash error code if operation failed. */ -esp_err_t esp_flash_set_protected_region(esp_flash_t *chip, const esp_flash_region_t *region, bool protected); +esp_err_t esp_flash_set_protected_region(esp_flash_t *chip, const esp_flash_region_t *region, bool protect); /** @brief Read data from the SPI flash chip * @@ -271,24 +274,29 @@ esp_err_t esp_flash_init_default_chip(); /** * Enable OS-level SPI flash protections in IDF * + * Called by OS startup code. You do not need to call this in your own applications. + * * @return ESP_OK if success, otherwise failed. See return value of ``esp_flash_init_os_functions``. */ -esp_err_t esp_flash_app_init(); /* ROM TODO move this to IDF */ +esp_err_t esp_flash_app_init(); /** * Enable OS-level SPI flash for a specific chip. * * @param chip The chip to init os functions. - * @param host_id Which SPI host to use, 0 for SPI1, 1 for HSPI2 and 2 for VSPI. + * @param host_id Which SPI host to use, 1 for SPI1, 2 for SPI2 (HSPI), 3 for SPI3 (VSPI) * - * @return ESP_OK if success, otherwise failed. See return value of ``esp_flash_init_os_functions``. + * @return + * - ESP_OK if success + * - ESP_ERR_INVALID_ARG if host_id is invalid */ esp_err_t esp_flash_init_os_functions(esp_flash_t *chip, int host_id); -/* The default (ie initial boot) no-OS ROM esp_flash_os_functions_t */ -extern const esp_flash_os_functions_t spi1_default_os_functions; //todo: put into non-ROM headers - -/* Pointer to the current esp_flash_os_functions_t structure in use. - Can be changed at runtime to reflect different running conditions. +/** + * The default FreeRTOS-compatible esp_flash_os_functions_t, used for flash chips attached to the SPI1 */ -//extern const esp_flash_os_functions_t *os_func; +extern const esp_flash_os_functions_t esp_flash_spi1_default_os_functions; + +#ifdef __cplusplus +} +#endif diff --git a/components/spi_flash/spi_flash_os_func_app.c b/components/spi_flash/spi_flash_os_func_app.c index 9b9738becf..8b293e5ebf 100644 --- a/components/spi_flash/spi_flash_os_func_app.c +++ b/components/spi_flash/spi_flash_os_func_app.c @@ -89,13 +89,13 @@ static app_func_arg_t spi3_arg = { }; //for SPI1, we have to disable the cache and interrupts before using the SPI bus -const DRAM_ATTR esp_flash_os_functions_t spi1_default_os_functions = { +const DRAM_ATTR esp_flash_os_functions_t esp_flash_spi1_default_os_functions = { .start = spi1_start, .end = spi1_end, .delay_ms = delay_ms, }; -const esp_flash_os_functions_t spi23_default_os_functions = { +const esp_flash_os_functions_t esp_flash_spi23_default_os_functions = { .start = spi23_start, .end = spi23_end, .delay_ms = delay_ms, @@ -105,11 +105,11 @@ esp_err_t esp_flash_init_os_functions(esp_flash_t *chip, int host_id) { if (host_id == 0) { //SPI1 - chip->os_func = &spi1_default_os_functions; + chip->os_func = &esp_flash_spi1_default_os_functions; chip->os_func_data = &spi1_arg; } else if (host_id == 1 || host_id == 2) { //SPI2,3 - chip->os_func = &spi23_default_os_functions; + chip->os_func = &esp_flash_spi23_default_os_functions; chip->os_func_data = (host_id == 1) ? &spi2_arg : &spi3_arg; } else { return ESP_ERR_INVALID_ARG; From cf2ba210ef028ecc563b04d403b37e34e71b470f Mon Sep 17 00:00:00 2001 From: chenjianqiang Date: Fri, 14 Jun 2019 11:01:30 +0800 Subject: [PATCH 081/486] uart: multichip support --- components/driver/include/driver/uart.h | 30 ++++++++-------- components/driver/uart.c | 26 ++++++++++++-- .../common/include/esp_modbus_common.h | 2 +- components/freemodbus/port/portserial.c | 2 +- components/freemodbus/port/portserial_m.c | 2 +- .../modbus_controller/mbc_serial_master.c | 2 +- .../modbus_controller/mbc_serial_slave.c | 2 +- components/soc/esp32/include/soc/uart_caps.h | 26 ++++++++++++++ components/soc/include/soc/uart_periph.h | 2 ++ components/vfs/vfs_uart.c | 35 +++++++++++++++---- 10 files changed, 101 insertions(+), 28 deletions(-) create mode 100644 components/soc/esp32/include/soc/uart_caps.h diff --git a/components/driver/include/driver/uart.h b/components/driver/include/driver/uart.h index 4f0c8c1ca1..4bf855c186 100644 --- a/components/driver/include/driver/uart.h +++ b/components/driver/include/driver/uart.h @@ -1,9 +1,9 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2019 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 @@ -12,15 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef _DRIVER_UART_H_ -#define _DRIVER_UART_H_ - +#pragma once #ifdef __cplusplus extern "C" { #endif #include "soc/uart_periph.h" +#include "soc/uart_caps.h" #include "esp_err.h" #include "esp_intr_alloc.h" #include "driver/periph_ctrl.h" @@ -82,7 +81,9 @@ typedef enum { typedef enum { UART_NUM_0 = 0x0, /*!< UART base address 0x3ff40000*/ UART_NUM_1 = 0x1, /*!< UART base address 0x3ff50000*/ +#if SOC_UART_NUM > 2 UART_NUM_2 = 0x2, /*!< UART base address 0x3ff6e000*/ +#endif UART_NUM_MAX, } uart_port_t; @@ -257,7 +258,7 @@ esp_err_t uart_get_baudrate(uart_port_t uart_num, uint32_t* baudrate); * * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 * @param inverse_mask Choose the wires that need to be inverted. - * Inverse_mask should be chosen from + * Inverse_mask should be chosen from * UART_INVERSE_RXD / UART_INVERSE_TXD / UART_INVERSE_RTS / UART_INVERSE_CTS, * combined with OR operation. * @@ -401,7 +402,7 @@ esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh); * @param fn Interrupt handler function. * @param arg parameter for handler function * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) - * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. + * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. * @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will * be returned here. * @@ -429,7 +430,7 @@ esp_err_t uart_isr_free(uart_port_t uart_num); * @note Internal signal can be output to multiple GPIO pads. * Only one GPIO pad can connect with input signal. * - * @note Instead of GPIO number a macro 'UART_PIN_NO_CHANGE' may be provided + * @note Instead of GPIO number a macro 'UART_PIN_NO_CHANGE' may be provided to keep the currently allocated pin. * * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 @@ -556,7 +557,7 @@ esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait); /** * @brief Send data to the UART port from a given buffer and length. - * + * * This function will not wait for enough space in TX FIFO. It will just fill the available TX FIFO and return when the FIFO is full. * @note This function should only be used when UART TX buffer is not enabled. * @@ -748,10 +749,10 @@ int uart_pattern_get_pos(uart_port_t uart_num); esp_err_t uart_pattern_queue_reset(uart_port_t uart_num, int queue_length); /** - * @brief UART set communication mode + * @brief UART set communication mode * @note This function must be executed after uart_driver_install(), when the driver object is initialized. * @param uart_num Uart number to configure - * @param mode UART UART mode to set + * @param mode UART UART mode to set * * @return * - ESP_OK Success @@ -763,8 +764,8 @@ esp_err_t uart_set_mode(uart_port_t uart_num, uart_mode_t mode); * @brief UART set threshold timeout for TOUT feature * * @param uart_num Uart number to configure - * @param tout_thresh This parameter defines timeout threshold in uart symbol periods. The maximum value of threshold is 126. - * tout_thresh = 1, defines TOUT interrupt timeout equal to transmission time of one symbol (~11 bit) on current baudrate. + * @param tout_thresh This parameter defines timeout threshold in uart symbol periods. The maximum value of threshold is 126. + * tout_thresh = 1, defines TOUT interrupt timeout equal to transmission time of one symbol (~11 bit) on current baudrate. * If the time is expired the UART_RXFIFO_TOUT_INT interrupt is triggered. If tout_thresh == 0, * the TOUT feature is disabled. * @@ -785,7 +786,7 @@ esp_err_t uart_set_rx_timeout(uart_port_t uart_num, const uint8_t tout_thresh); * @param collision_flag Pointer to variable of type bool to return collision flag. * * @return - * - ESP_OK Success + * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t uart_get_collision_flag(uart_port_t uart_num, bool* collision_flag); @@ -844,4 +845,3 @@ esp_err_t uart_get_wakeup_threshold(uart_port_t uart_num, int* out_wakeup_thresh } #endif -#endif /*_DRIVER_UART_H_*/ diff --git a/components/driver/uart.c b/components/driver/uart.c index b9d222f567..9a26f6423f 100644 --- a/components/driver/uart.c +++ b/components/driver/uart.c @@ -29,6 +29,8 @@ #include "driver/gpio.h" #include "driver/uart_select.h" +#define UART_NUM SOC_UART_NUM + #define XOFF (char)0x13 #define XON (char)0x11 @@ -113,8 +115,20 @@ typedef struct { static uart_obj_t *p_uart_obj[UART_NUM_MAX] = {0}; /* DRAM_ATTR is required to avoid UART array placed in flash, due to accessed from ISR */ -static DRAM_ATTR uart_dev_t* const UART[UART_NUM_MAX] = {&UART0, &UART1, &UART2}; -static portMUX_TYPE uart_spinlock[UART_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED}; +static DRAM_ATTR uart_dev_t* const UART[UART_NUM_MAX] = { + &UART0, + &UART1, +#if UART_NUM > 2 + &UART2 +#endif +}; +static portMUX_TYPE uart_spinlock[UART_NUM_MAX] = { + portMUX_INITIALIZER_UNLOCKED, + portMUX_INITIALIZER_UNLOCKED, +#if UART_NUM > 2 + portMUX_INITIALIZER_UNLOCKED +#endif +}; static portMUX_TYPE uart_selectlock = portMUX_INITIALIZER_UNLOCKED; esp_err_t uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit) @@ -528,9 +542,11 @@ esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, case UART_NUM_1: ret=esp_intr_alloc(ETS_UART1_INTR_SOURCE, intr_alloc_flags, fn, arg, handle); break; +#if UART_NUM > 2 case UART_NUM_2: ret=esp_intr_alloc(ETS_UART2_INTR_SOURCE, intr_alloc_flags, fn, arg, handle); break; +#endif case UART_NUM_0: default: ret=esp_intr_alloc(ETS_UART0_INTR_SOURCE, intr_alloc_flags, fn, arg, handle); @@ -577,12 +593,14 @@ esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int r rts_sig = U1RTS_OUT_IDX; cts_sig = U1CTS_IN_IDX; break; +#if UART_NUM > 2 case UART_NUM_2: tx_sig = U2TXD_OUT_IDX; rx_sig = U2RXD_IN_IDX; rts_sig = U2RTS_OUT_IDX; cts_sig = U2CTS_IN_IDX; break; +#endif case UART_NUM_MAX: default: tx_sig = U0TXD_OUT_IDX; @@ -656,8 +674,10 @@ esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_conf periph_module_enable(PERIPH_UART0_MODULE); } else if(uart_num == UART_NUM_1) { periph_module_enable(PERIPH_UART1_MODULE); +#if UART_NUM > 2 } else if(uart_num == UART_NUM_2) { periph_module_enable(PERIPH_UART2_MODULE); +#endif } r = uart_set_hw_flow_ctrl(uart_num, uart_config->flow_ctrl, uart_config->rx_flow_ctrl_thresh); if (r != ESP_OK) return r; @@ -1460,8 +1480,10 @@ esp_err_t uart_driver_delete(uart_port_t uart_num) periph_module_disable(PERIPH_UART0_MODULE); } else if(uart_num == UART_NUM_1) { periph_module_disable(PERIPH_UART1_MODULE); +#if UART_NUM > 2 } else if(uart_num == UART_NUM_2) { periph_module_disable(PERIPH_UART2_MODULE); +#endif } } return ESP_OK; diff --git a/components/freemodbus/common/include/esp_modbus_common.h b/components/freemodbus/common/include/esp_modbus_common.h index 7bec02476a..cd171c7557 100644 --- a/components/freemodbus/common/include/esp_modbus_common.h +++ b/components/freemodbus/common/include/esp_modbus_common.h @@ -24,7 +24,7 @@ // Default port defines #define MB_DEVICE_ADDRESS (1) // Default slave device address in Modbus #define MB_DEVICE_SPEED (115200) // Default Modbus speed for now hard defined -#define MB_UART_PORT (UART_NUM_2) // Default UART port number +#define MB_UART_PORT (UART_NUM_MAX - 1) // Default UART port number #define MB_PAR_INFO_TOUT (10) // Timeout for get parameter info #define MB_PARITY_NONE (UART_PARITY_DISABLE) diff --git a/components/freemodbus/port/portserial.c b/components/freemodbus/port/portserial.c index 54bbe8318b..10967af7ab 100644 --- a/components/freemodbus/port/portserial.c +++ b/components/freemodbus/port/portserial.c @@ -78,7 +78,7 @@ static TaskHandle_t xMbTaskHandle; static const CHAR *TAG = "MB_SERIAL"; // The UART hardware port number -static UCHAR ucUartNumber = UART_NUM_2; +static UCHAR ucUartNumber = UART_NUM_MAX - 1; static BOOL bRxStateEnabled = FALSE; // Receiver enabled flag static BOOL bTxStateEnabled = FALSE; // Transmitter enabled flag diff --git a/components/freemodbus/port/portserial_m.c b/components/freemodbus/port/portserial_m.c index 74a4a1be04..330269101a 100644 --- a/components/freemodbus/port/portserial_m.c +++ b/components/freemodbus/port/portserial_m.c @@ -73,7 +73,7 @@ static QueueHandle_t xMbUartQueue; static TaskHandle_t xMbTaskHandle; // The UART hardware port number -static UCHAR ucUartNumber = UART_NUM_2; +static UCHAR ucUartNumber = UART_NUM_MAX - 1; static BOOL bRxStateEnabled = FALSE; // Receiver enabled flag static BOOL bTxStateEnabled = FALSE; // Transmitter enabled flag diff --git a/components/freemodbus/serial_master/modbus_controller/mbc_serial_master.c b/components/freemodbus/serial_master/modbus_controller/mbc_serial_master.c index 8db15aea41..30aae200fc 100644 --- a/components/freemodbus/serial_master/modbus_controller/mbc_serial_master.c +++ b/components/freemodbus/serial_master/modbus_controller/mbc_serial_master.c @@ -83,7 +83,7 @@ static esp_err_t mbc_serial_master_setup(void* comm_info) MB_MASTER_CHECK(((comm_info_ptr->mode == MB_MODE_RTU) || (comm_info_ptr->mode == MB_MODE_ASCII)), ESP_ERR_INVALID_ARG, "mb incorrect mode = (0x%x).", (uint32_t)comm_info_ptr->mode); - MB_MASTER_CHECK((comm_info_ptr->port <= UART_NUM_2), ESP_ERR_INVALID_ARG, + MB_MASTER_CHECK((comm_info_ptr->port < UART_NUM_MAX), ESP_ERR_INVALID_ARG, "mb wrong port to set = (0x%x).", (uint32_t)comm_info_ptr->port); MB_MASTER_CHECK((comm_info_ptr->parity <= UART_PARITY_EVEN), ESP_ERR_INVALID_ARG, "mb wrong parity option = (0x%x).", (uint32_t)comm_info_ptr->parity); diff --git a/components/freemodbus/serial_slave/modbus_controller/mbc_serial_slave.c b/components/freemodbus/serial_slave/modbus_controller/mbc_serial_slave.c index 86e9616d02..72d753e520 100644 --- a/components/freemodbus/serial_slave/modbus_controller/mbc_serial_slave.c +++ b/components/freemodbus/serial_slave/modbus_controller/mbc_serial_slave.c @@ -69,7 +69,7 @@ static esp_err_t mbc_serial_slave_setup(void* comm_info) MB_SLAVE_CHECK((comm_settings->slave_addr <= MB_ADDRESS_MAX), ESP_ERR_INVALID_ARG, "mb wrong slave address = (0x%x).", (uint32_t)comm_settings->slave_addr); - MB_SLAVE_CHECK((comm_settings->port <= UART_NUM_2), ESP_ERR_INVALID_ARG, + MB_SLAVE_CHECK((comm_settings->port < UART_NUM_MAX), ESP_ERR_INVALID_ARG, "mb wrong port to set = (0x%x).", (uint32_t)comm_settings->port); MB_SLAVE_CHECK((comm_settings->parity <= UART_PARITY_EVEN), ESP_ERR_INVALID_ARG, "mb wrong parity option = (0x%x).", (uint32_t)comm_settings->parity); diff --git a/components/soc/esp32/include/soc/uart_caps.h b/components/soc/esp32/include/soc/uart_caps.h new file mode 100644 index 0000000000..4234b4b133 --- /dev/null +++ b/components/soc/esp32/include/soc/uart_caps.h @@ -0,0 +1,26 @@ +// Copyright 2017-2019 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 + +#ifdef __cplusplus +extern "C" { +#endif + +#define SOC_UART_NUM 3 + +#ifdef __cplusplus +} +#endif + diff --git a/components/soc/include/soc/uart_periph.h b/components/soc/include/soc/uart_periph.h index d149048aa1..27324cd1d5 100644 --- a/components/soc/include/soc/uart_periph.h +++ b/components/soc/include/soc/uart_periph.h @@ -13,6 +13,8 @@ // limitations under the License. #pragma once + +#include "soc/uart_caps.h" #include "soc/uart_reg.h" #include "soc/uart_struct.h" #include "soc/uart_channel.h" diff --git a/components/vfs/vfs_uart.c b/components/vfs/vfs_uart.c index 147c54cb70..7b0f3d3fb7 100644 --- a/components/vfs/vfs_uart.c +++ b/components/vfs/vfs_uart.c @@ -28,7 +28,7 @@ #include "esp32/rom/uart.h" // TODO: make the number of UARTs chip dependent -#define UART_NUM 3 +#define UART_NUM SOC_UART_NUM // Token signifying that no character is available #define NONE -1 @@ -47,12 +47,27 @@ static void uart_tx_char_via_driver(int fd, int c); static int uart_rx_char_via_driver(int fd); // Pointers to UART peripherals -static uart_dev_t* s_uarts[UART_NUM] = {&UART0, &UART1, &UART2}; +static uart_dev_t* s_uarts[UART_NUM] = { + &UART0, + &UART1, +#if UART_NUM > 2 + &UART2 +#endif +}; + +// One-character buffer used for newline conversion code, per UART +static int s_peek_char[UART_NUM] = { + NONE, + NONE, +#if UART_NUM > 2 + NONE +#endif +}; + // per-UART locks, lazily initialized static _lock_t s_uart_read_locks[UART_NUM]; static _lock_t s_uart_write_locks[UART_NUM]; -// One-character buffer used for newline conversion code, per UART -static int s_peek_char[UART_NUM] = { NONE, NONE, NONE }; + // Per-UART non-blocking flag. Note: default implementation does not honor this // flag, all reads are non-blocking. This option becomes effective if UART // driver is used. @@ -94,12 +109,20 @@ static void uart_end_select(); // Functions used to write bytes to UART. Default to "basic" functions. static tx_func_t s_uart_tx_func[UART_NUM] = { - &uart_tx_char, &uart_tx_char, &uart_tx_char + &uart_tx_char, + &uart_tx_char, +#if UART_NUM > 2 + &uart_tx_char +#endif }; // Functions used to read bytes from UART. Default to "basic" functions. static rx_func_t s_uart_rx_func[UART_NUM] = { - &uart_rx_char, &uart_rx_char, &uart_rx_char + &uart_rx_char, + &uart_rx_char, +#if UART_NUM > 2 + &uart_rx_char +#endif }; From b5c3ac0ec23b59db3da88f8085019e8f934d0c70 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Thu, 20 Jun 2019 01:18:20 +0800 Subject: [PATCH 082/486] vfs_uart: refactor to have static context structure --- components/vfs/vfs_uart.c | 202 +++++++++++++++++++------------------- 1 file changed, 102 insertions(+), 100 deletions(-) diff --git a/components/vfs/vfs_uart.c b/components/vfs/vfs_uart.c index 7b0f3d3fb7..2bb865b297 100644 --- a/components/vfs/vfs_uart.c +++ b/components/vfs/vfs_uart.c @@ -33,6 +33,22 @@ // Token signifying that no character is available #define NONE -1 +#if CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF +# define DEFAULT_TX_MODE ESP_LINE_ENDINGS_CRLF +#elif CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR +# define DEFAULT_TX_MODE ESP_LINE_ENDINGS_CR +#else +# define DEFAULT_TX_MODE ESP_LINE_ENDINGS_LF +#endif + +#if CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF +# define DEFAULT_RX_MODE ESP_LINE_ENDINGS_CRLF +#elif CONFIG_NEWLIB_STDIN_LINE_ENDING_CR +# define DEFAULT_RX_MODE ESP_LINE_ENDINGS_CR +#else +# define DEFAULT_RX_MODE ESP_LINE_ENDINGS_LF +#endif + // UART write bytes function type typedef void (*tx_func_t)(int, int); // UART read bytes function type @@ -46,33 +62,55 @@ static int uart_rx_char(int fd); static void uart_tx_char_via_driver(int fd, int c); static int uart_rx_char_via_driver(int fd); -// Pointers to UART peripherals -static uart_dev_t* s_uarts[UART_NUM] = { - &UART0, - &UART1, +typedef struct { + // Pointers to UART peripherals + uart_dev_t* uart; + // One-character buffer used for newline conversion code, per UART + int peek_char; + // per-UART locks, lazily initialized + _lock_t read_lock; + _lock_t write_lock; + // Per-UART non-blocking flag. Note: default implementation does not honor this + // flag, all reads are non-blocking. This option becomes effective if UART + // driver is used. + bool non_blocking; + // Newline conversion mode when transmitting + esp_line_endings_t tx_mode; + // Newline conversion mode when receiving + esp_line_endings_t rx_mode; + // Functions used to write bytes to UART. Default to "basic" functions. + tx_func_t tx_func; + // Functions used to read bytes from UART. Default to "basic" functions. + rx_func_t rx_func; +} vfs_uart_context_t; + +#define VFS_CTX_DEFAULT_VAL(uart_dev) (vfs_uart_context_t) {\ + .uart = (uart_dev),\ + .peek_char = NONE,\ + .tx_mode = DEFAULT_TX_MODE,\ + .rx_mode = DEFAULT_RX_MODE,\ + .tx_func = uart_tx_char,\ + .rx_func = uart_rx_char,\ +} + +//If the context should be dynamically initialized, remove this structure +//and point s_ctx to allocated data. +static vfs_uart_context_t s_context[UART_NUM] = { + VFS_CTX_DEFAULT_VAL(&UART0), + VFS_CTX_DEFAULT_VAL(&UART1), #if UART_NUM > 2 - &UART2 + VFS_CTX_DEFAULT_VAL(&UART2), #endif }; -// One-character buffer used for newline conversion code, per UART -static int s_peek_char[UART_NUM] = { - NONE, - NONE, +static vfs_uart_context_t* s_ctx[UART_NUM] = { + &s_context[0], + &s_context[1], #if UART_NUM > 2 - NONE + &s_context[2], #endif }; -// per-UART locks, lazily initialized -static _lock_t s_uart_read_locks[UART_NUM]; -static _lock_t s_uart_write_locks[UART_NUM]; - -// Per-UART non-blocking flag. Note: default implementation does not honor this -// flag, all reads are non-blocking. This option becomes effective if UART -// driver is used. -static bool s_non_blocking[UART_NUM]; - /* Lock ensuring that uart_select is used from only one task at the time */ static _lock_t s_one_select_lock; @@ -84,47 +122,9 @@ static fd_set *_readfds_orig = NULL; static fd_set *_writefds_orig = NULL; static fd_set *_errorfds_orig = NULL; -// Newline conversion mode when transmitting -static esp_line_endings_t s_tx_mode = -#if CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF - ESP_LINE_ENDINGS_CRLF; -#elif CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR - ESP_LINE_ENDINGS_CR; -#else - ESP_LINE_ENDINGS_LF; -#endif - -// Newline conversion mode when receiving -static esp_line_endings_t s_rx_mode[UART_NUM] = { [0 ... UART_NUM-1] = -#if CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF - ESP_LINE_ENDINGS_CRLF -#elif CONFIG_NEWLIB_STDIN_LINE_ENDING_CR - ESP_LINE_ENDINGS_CR -#else - ESP_LINE_ENDINGS_LF -#endif -}; static void uart_end_select(); -// Functions used to write bytes to UART. Default to "basic" functions. -static tx_func_t s_uart_tx_func[UART_NUM] = { - &uart_tx_char, - &uart_tx_char, -#if UART_NUM > 2 - &uart_tx_char -#endif -}; - -// Functions used to read bytes from UART. Default to "basic" functions. -static rx_func_t s_uart_rx_func[UART_NUM] = { - &uart_rx_char, - &uart_rx_char, -#if UART_NUM > 2 - &uart_rx_char -#endif -}; - static int uart_open(const char * path, int flags, int mode) { @@ -143,14 +143,14 @@ static int uart_open(const char * path, int flags, int mode) return fd; } - s_non_blocking[fd] = ((flags & O_NONBLOCK) == O_NONBLOCK); + s_ctx[fd]->non_blocking = ((flags & O_NONBLOCK) == O_NONBLOCK); return fd; } static void uart_tx_char(int fd, int c) { - uart_dev_t* uart = s_uarts[fd]; + uart_dev_t* uart = s_ctx[fd]->uart; while (uart->status.txfifo_cnt >= 127) { ; } @@ -165,7 +165,7 @@ static void uart_tx_char_via_driver(int fd, int c) static int uart_rx_char(int fd) { - uart_dev_t* uart = s_uarts[fd]; + uart_dev_t* uart = s_ctx[fd]->uart; if (uart->status.rxfifo_cnt == 0) { return NONE; } @@ -175,7 +175,7 @@ static int uart_rx_char(int fd) static int uart_rx_char_via_driver(int fd) { uint8_t c; - int timeout = s_non_blocking[fd] ? 0 : portMAX_DELAY; + int timeout = s_ctx[fd]->non_blocking ? 0 : portMAX_DELAY; int n = uart_read_bytes(fd, &c, 1, timeout); if (n <= 0) { return NONE; @@ -191,18 +191,18 @@ static ssize_t uart_write(int fd, const void * data, size_t size) * a dedicated UART lock if two streams (stdout and stderr) point to the * same UART. */ - _lock_acquire_recursive(&s_uart_write_locks[fd]); + _lock_acquire_recursive(&s_ctx[fd]->write_lock); for (size_t i = 0; i < size; i++) { int c = data_c[i]; - if (c == '\n' && s_tx_mode != ESP_LINE_ENDINGS_LF) { - s_uart_tx_func[fd](fd, '\r'); - if (s_tx_mode == ESP_LINE_ENDINGS_CR) { + if (c == '\n' && s_ctx[fd]->tx_mode != ESP_LINE_ENDINGS_LF) { + s_ctx[fd]->tx_func(fd, '\r'); + if (s_ctx[fd]->tx_mode == ESP_LINE_ENDINGS_CR) { continue; } } - s_uart_tx_func[fd](fd, c); + s_ctx[fd]->tx_func(fd, c); } - _lock_release_recursive(&s_uart_write_locks[fd]); + _lock_release_recursive(&s_ctx[fd]->write_lock); return size; } @@ -213,19 +213,19 @@ static ssize_t uart_write(int fd, const void * data, size_t size) static int uart_read_char(int fd) { /* return character from peek buffer, if it is there */ - if (s_peek_char[fd] != NONE) { - int c = s_peek_char[fd]; - s_peek_char[fd] = NONE; + if (s_ctx[fd]->peek_char != NONE) { + int c = s_ctx[fd]->peek_char; + s_ctx[fd]->peek_char = NONE; return c; } - return s_uart_rx_func[fd](fd); + return s_ctx[fd]->rx_func(fd); } /* Push back a character; it will be returned by next call to uart_read_char */ static void uart_return_char(int fd, int c) { - assert(s_peek_char[fd] == NONE); - s_peek_char[fd] = c; + assert(s_ctx[fd]->peek_char == NONE); + s_ctx[fd]->peek_char = c; } static ssize_t uart_read(int fd, void* data, size_t size) @@ -233,13 +233,13 @@ static ssize_t uart_read(int fd, void* data, size_t size) assert(fd >=0 && fd < 3); char *data_c = (char *) data; size_t received = 0; - _lock_acquire_recursive(&s_uart_read_locks[fd]); + _lock_acquire_recursive(&s_ctx[fd]->read_lock); while (received < size) { int c = uart_read_char(fd); if (c == '\r') { - if (s_rx_mode[fd] == ESP_LINE_ENDINGS_CR) { + if (s_ctx[fd]->rx_mode == ESP_LINE_ENDINGS_CR) { c = '\n'; - } else if (s_rx_mode[fd] == ESP_LINE_ENDINGS_CRLF) { + } else if (s_ctx[fd]->rx_mode == ESP_LINE_ENDINGS_CRLF) { /* look ahead */ int c2 = uart_read_char(fd); if (c2 == NONE) { @@ -266,7 +266,7 @@ static ssize_t uart_read(int fd, void* data, size_t size) break; } } - _lock_release_recursive(&s_uart_read_locks[fd]); + _lock_release_recursive(&s_ctx[fd]->read_lock); if (received > 0) { return received; } @@ -292,11 +292,11 @@ static int uart_fcntl(int fd, int cmd, int arg) assert(fd >=0 && fd < 3); int result = 0; if (cmd == F_GETFL) { - if (s_non_blocking[fd]) { + if (s_ctx[fd]->non_blocking) { result |= O_NONBLOCK; } } else if (cmd == F_SETFL) { - s_non_blocking[fd] = (arg & O_NONBLOCK) != 0; + s_ctx[fd]->non_blocking = (arg & O_NONBLOCK) != 0; } else { // unsupported operation result = -1; @@ -329,9 +329,9 @@ static int uart_access(const char *path, int amode) static int uart_fsync(int fd) { assert(fd >= 0 && fd < 3); - _lock_acquire_recursive(&s_uart_write_locks[fd]); + _lock_acquire_recursive(&s_ctx[fd]->write_lock); uart_tx_wait_idle((uint8_t) fd); - _lock_release_recursive(&s_uart_write_locks[fd]); + _lock_release_recursive(&s_ctx[fd]->write_lock); return 0; } @@ -500,11 +500,11 @@ static int uart_tcsetattr(int fd, int optional_actions, const struct termios *p) } if (p->c_iflag & IGNCR) { - s_rx_mode[fd] = ESP_LINE_ENDINGS_CRLF; + s_ctx[fd]->rx_mode = ESP_LINE_ENDINGS_CRLF; } else if (p->c_iflag & ICRNL) { - s_rx_mode[fd] = ESP_LINE_ENDINGS_CR; + s_ctx[fd]->rx_mode = ESP_LINE_ENDINGS_CR; } else { - s_rx_mode[fd] = ESP_LINE_ENDINGS_LF; + s_ctx[fd]->rx_mode = ESP_LINE_ENDINGS_LF; } // output line endings are not supported because there is no alternative in termios for converting LF to CR @@ -683,9 +683,9 @@ static int uart_tcgetattr(int fd, struct termios *p) memset(p, 0, sizeof(struct termios)); - if (s_rx_mode[fd] == ESP_LINE_ENDINGS_CRLF) { + if (s_ctx[fd]->rx_mode == ESP_LINE_ENDINGS_CRLF) { p->c_iflag |= IGNCR; - } else if (s_rx_mode[fd] == ESP_LINE_ENDINGS_CR) { + } else if (s_ctx[fd]->rx_mode == ESP_LINE_ENDINGS_CR) { p->c_iflag |= ICRNL; } @@ -942,31 +942,33 @@ void esp_vfs_dev_uart_register() void esp_vfs_dev_uart_set_rx_line_endings(esp_line_endings_t mode) { for (int i = 0; i < UART_NUM; ++i) { - s_rx_mode[i] = mode; + s_ctx[i]->rx_mode = mode; } } void esp_vfs_dev_uart_set_tx_line_endings(esp_line_endings_t mode) { - s_tx_mode = mode; + for (int i = 0; i < UART_NUM; ++i) { + s_ctx[i]->tx_mode = mode; + } } void esp_vfs_dev_uart_use_nonblocking(int uart_num) { - _lock_acquire_recursive(&s_uart_read_locks[uart_num]); - _lock_acquire_recursive(&s_uart_write_locks[uart_num]); - s_uart_tx_func[uart_num] = uart_tx_char; - s_uart_rx_func[uart_num] = uart_rx_char; - _lock_release_recursive(&s_uart_write_locks[uart_num]); - _lock_release_recursive(&s_uart_read_locks[uart_num]); + _lock_acquire_recursive(&s_ctx[uart_num]->read_lock); + _lock_acquire_recursive(&s_ctx[uart_num]->write_lock); + s_ctx[uart_num]->tx_func = uart_tx_char; + s_ctx[uart_num]->rx_func = uart_rx_char; + _lock_release_recursive(&s_ctx[uart_num]->write_lock); + _lock_release_recursive(&s_ctx[uart_num]->read_lock); } void esp_vfs_dev_uart_use_driver(int uart_num) { - _lock_acquire_recursive(&s_uart_read_locks[uart_num]); - _lock_acquire_recursive(&s_uart_write_locks[uart_num]); - s_uart_tx_func[uart_num] = uart_tx_char_via_driver; - s_uart_rx_func[uart_num] = uart_rx_char_via_driver; - _lock_release_recursive(&s_uart_write_locks[uart_num]); - _lock_release_recursive(&s_uart_read_locks[uart_num]); + _lock_acquire_recursive(&s_ctx[uart_num]->read_lock); + _lock_acquire_recursive(&s_ctx[uart_num]->write_lock); + s_ctx[uart_num]->tx_func = uart_tx_char_via_driver; + s_ctx[uart_num]->rx_func = uart_rx_char_via_driver; + _lock_release_recursive(&s_ctx[uart_num]->write_lock); + _lock_release_recursive(&s_ctx[uart_num]->read_lock); } From 21cce564bad7de6e7162de1a1ac0d08145de175b Mon Sep 17 00:00:00 2001 From: baohongde Date: Mon, 17 Sep 2018 16:44:38 +0800 Subject: [PATCH 083/486] component/bt: Macor from `sdkconfig.h` is used only in `bt_user_config.h` --- components/bt/bluedroid/api/esp_bt_main.c | 2 +- components/bt/bluedroid/btc/core/btc_task.c | 23 +- .../bt/bluedroid/btc/include/btc/btc_task.h | 6 +- .../btc/profile/std/a2dp/btc_a2dp_sink.c | 4 +- .../btc/profile/std/a2dp/btc_a2dp_source.c | 4 +- .../btc/profile/std/hf_client/btc_hf_client.c | 2 +- .../common/include/common/bt_target.h | 185 +++++---- .../common/include/common/bt_trace.h | 157 ++------ .../common/include/common/bt_user_config.h | 372 ++++++++++++++++++ components/bt/bluedroid/hci/hci_hal_h4.c | 3 +- components/bt/bluedroid/hci/hci_layer.c | 3 +- components/bt/bluedroid/osi/allocator.c | 31 +- .../bt/bluedroid/osi/include/osi/allocator.h | 21 +- components/bt/bluedroid/stack/btm/btm_sec.c | 96 ++--- components/bt/bluedroid/stack/btu/btu_init.c | 5 +- .../bluedroid/stack/include/stack/dyn_mem.h | 8 +- 16 files changed, 592 insertions(+), 330 deletions(-) create mode 100644 components/bt/bluedroid/common/include/common/bt_user_config.h diff --git a/components/bt/bluedroid/api/esp_bt_main.c b/components/bt/bluedroid/api/esp_bt_main.c index 1620ae9d80..0b1bcc6ab0 100644 --- a/components/bt/bluedroid/api/esp_bt_main.c +++ b/components/bt/bluedroid/api/esp_bt_main.c @@ -128,7 +128,7 @@ esp_err_t esp_bluedroid_init(void) return ESP_ERR_INVALID_STATE; } -#ifdef CONFIG_BT_BLUEDROID_MEM_DEBUG +#if HEAP_MEMORY_DEBUG osi_mem_dbg_init(); #endif diff --git a/components/bt/bluedroid/btc/core/btc_task.c b/components/bt/bluedroid/btc/core/btc_task.c index 2787bc2056..8b787405bc 100644 --- a/components/bt/bluedroid/btc/core/btc_task.c +++ b/components/bt/bluedroid/btc/core/btc_task.c @@ -30,7 +30,7 @@ #include "btc/btc_dm.h" #include "btc/btc_alarm.h" #include "bta/bta_gatt_api.h" -#if CONFIG_BT_CLASSIC_ENABLED +#if CLASSIC_BT_INCLUDED #include "btc/btc_profile_queue.h" #if (BTC_GAP_BT_INCLUDED == TRUE) #include "btc_gap_bt.h" @@ -39,19 +39,18 @@ #include "btc_av.h" #include "btc_avrc.h" #endif /* #if BTC_AV_INCLUDED */ -#if CONFIG_BT_SPP_ENABLED +#if (BTC_SPP_INCLUDED == TRUE) #include "btc_spp.h" -#endif /* #if CONFIG_BT_SPP_ENABLED */ +#endif /* #if (BTC_SPP_INCLUDED == TRUE) */ #if BTC_HF_CLIENT_INCLUDED #include "btc_hf_client.h" #endif /* #if BTC_HF_CLIENT_INCLUDED */ -#endif /* #if CONFIG_BT_CLASSIC_ENABLED */ +#endif /* #if CLASSIC_BT_INCLUDED */ #define BTC_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) -#define BTC_TASK_STACK_SIZE (CONFIG_BTC_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) //by menuconfig +#define BTC_TASK_STACK_SIZE (BT_BTC_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) //by menuconfig #define BTC_TASK_NAME "btcT" -#define BTC_TASK_PRIO (configMAX_PRIORITIES - 6) -#define BTC_TASK_QUEUE_LEN 60 +#define BTC_TASK_PRIO (BT_TASK_MAX_PRIORITIES - 6) static osi_thread_t *btc_thread; @@ -75,7 +74,7 @@ static btc_func_t profile_tab[BTC_PID_NUM] = { #endif ///GATTS_INCLUDED == TRUE [BTC_PID_DM_SEC] = {NULL, btc_dm_sec_cb_handler }, [BTC_PID_ALARM] = {btc_alarm_handler, NULL }, -#if CONFIG_BT_CLASSIC_ENABLED +#if CLASSIC_BT_INCLUDED #if (BTC_GAP_BT_INCLUDED == TRUE) [BTC_PID_GAP_BT] = {btc_gap_bt_call_handler, btc_gap_bt_cb_handler }, #endif /* (BTC_GAP_BT_INCLUDED == TRUE) */ @@ -85,13 +84,13 @@ static btc_func_t profile_tab[BTC_PID_NUM] = { [BTC_PID_AVRC_CT] = {btc_avrc_ct_call_handler, NULL }, [BTC_PID_AVRC_TG] = {btc_avrc_tg_call_handler, NULL }, #endif /* #if BTC_AV_INCLUDED */ -#if CONFIG_BT_SPP_ENABLED +#if (BTC_SPP_INCLUDED == TRUE) [BTC_PID_SPP] = {btc_spp_call_handler, btc_spp_cb_handler }, -#endif /* #if CONFIG_BT_SPP_ENABLED */ +#endif /* #if (BTC_SPP_INCLUDED == TRUE) */ #if BTC_HF_CLIENT_INCLUDED [BTC_PID_HF_CLIENT] = {btc_hf_client_call_handler, btc_hf_client_cb_handler}, #endif /* #if BTC_HF_CLIENT_INCLUDED */ -#endif /* #if CONFIG_BT_CLASSIC_ENABLED */ +#endif /* #if CLASSIC_BT_INCLUDED */ }; /***************************************************************************** @@ -122,7 +121,7 @@ static void btc_thread_handler(void *arg) osi_free(msg); } -static bt_status_t btc_task_post(btc_msg_t *msg, osi_thread_blocking_t blocking) +static bt_status_t btc_task_post(btc_msg_t *msg, osi_thread_blocking_t blocking) { btc_msg_t *lmsg; diff --git a/components/bt/bluedroid/btc/include/btc/btc_task.h b/components/bt/bluedroid/btc/include/btc/btc_task.h index 2ea76c1772..0ed02d911a 100644 --- a/components/bt/bluedroid/btc/include/btc/btc_task.h +++ b/components/bt/bluedroid/btc/include/btc/btc_task.h @@ -53,17 +53,17 @@ typedef enum { BTC_PID_BLUFI, BTC_PID_DM_SEC, BTC_PID_ALARM, -#if CONFIG_BT_CLASSIC_ENABLED +#if (CLASSIC_BT_INCLUDED == TRUE) BTC_PID_GAP_BT, BTC_PID_PRF_QUE, BTC_PID_A2DP, BTC_PID_AVRC_CT, BTC_PID_AVRC_TG, BTC_PID_SPP, -#if BTC_HF_CLIENT_INCLUDED +#if (BTC_HF_CLIENT_INCLUDED == TRUE) BTC_PID_HF_CLIENT, #endif /* BTC_HF_CLIENT_INCLUDED */ -#endif /* CONFIG_BT_CLASSIC_ENABLED */ +#endif /* CLASSIC_BT_INCLUDED */ BTC_PID_NUM, } btc_pid_t; //btc profile id diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c index c8e1ec9c90..d25a1e5de5 100644 --- a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c +++ b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c @@ -47,9 +47,9 @@ /* Macro */ #define BTC_A2DP_SINK_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) -#define BTC_A2DP_SINK_TASK_STACK_SIZE (CONFIG_A2DP_SINK_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) // by menuconfig +#define BTC_A2DP_SINK_TASK_STACK_SIZE (A2DP_SINK_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) // by menuconfig #define BTC_A2DP_SINK_TASK_NAME "BtA2dSinkT" -#define BTC_A2DP_SINK_TASK_PRIO (configMAX_PRIORITIES - 3) +#define BTC_A2DP_SINK_TASK_PRIO (BT_TASK_MAX_PRIORITIES - 3) /***************************************************************************** diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c index 893ade6e0d..d6f12b69f1 100644 --- a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c +++ b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c @@ -52,9 +52,9 @@ /* Macro */ #define BTC_A2DP_SOURCE_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) -#define BTC_A2DP_SOURCE_TASK_STACK_SIZE (CONFIG_A2DP_SOURCE_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) // by menuconfig +#define BTC_A2DP_SOURCE_TASK_STACK_SIZE (A2DP_SOURCE_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) // by menuconfig #define BTC_A2DP_SOURCE_TASK_NAME "BtA2dSourceT" -#define BTC_A2DP_SOURCE_TASK_PRIO (configMAX_PRIORITIES - 3) +#define BTC_A2DP_SOURCE_TASK_PRIO (BT_TASK_MAX_PRIORITIES - 3) /***************************************************************************** diff --git a/components/bt/bluedroid/btc/profile/std/hf_client/btc_hf_client.c b/components/bt/bluedroid/btc/profile/std/hf_client/btc_hf_client.c index 3ae296cf0f..d0cdbc5e66 100644 --- a/components/bt/bluedroid/btc/profile/std/hf_client/btc_hf_client.c +++ b/components/bt/bluedroid/btc/profile/std/hf_client/btc_hf_client.c @@ -174,7 +174,7 @@ bt_status_t btc_hf_client_init(void) btc_hf_client_cb.initialized = true; -#if CONFIG_BT_HFP_AUDIO_DATA_PATH_HCI +#if BTM_SCO_HCI_INCLUDED data_path = ESP_SCO_DATA_PATH_HCI; #else data_path = ESP_SCO_DATA_PATH_PCM; diff --git a/components/bt/bluedroid/common/include/common/bt_target.h b/components/bt/bluedroid/common/include/common/bt_target.h index 3e9dac6131..b781d435ac 100644 --- a/components/bt/bluedroid/common/include/common/bt_target.h +++ b/components/bt/bluedroid/common/include/common/bt_target.h @@ -34,25 +34,25 @@ #include "bdroid_buildcfg.h" #endif -#include "sdkconfig.h" +#include "bt_user_config.h" #include "stack/bt_types.h" /* This must be defined AFTER buildcfg.h */ #include "stack/dyn_mem.h" /* defines static and/or dynamic memory for components */ /* OS Configuration from User config (eg: sdkconfig) */ -#if CONFIG_BLUEDROID_PINNED_TO_CORE -#define TASK_PINNED_TO_CORE (CONFIG_BLUEDROID_PINNED_TO_CORE < portNUM_PROCESSORS ? CONFIG_BLUEDROID_PINNED_TO_CORE : tskNO_AFFINITY) -#else -#define TASK_PINNED_TO_CORE (0) -#endif +#define TASK_PINNED_TO_CORE UC_TASK_PINNED_TO_CORE +#define BT_TASK_MAX_PRIORITIES configMAX_PRIORITIES +#define BT_BTC_TASK_STACK_SIZE UC_BTC_TASK_STACK_SIZE +#define A2DP_SINK_TASK_STACK_SIZE UC_A2DP_SINK_TASK_STACK_SIZE +#define A2DP_SOURCE_TASK_STACK_SIZE UC_A2DP_SOURCE_TASK_STACK_SIZE /****************************************************************************** ** ** Classic BT features ** ******************************************************************************/ -#if CONFIG_BT_CLASSIC_ENABLED +#if (UC_BT_CLASSIC_ENABLED == TRUE) #define CLASSIC_BT_INCLUDED TRUE #define BTC_SM_INCLUDED TRUE #define BTC_PRF_QUEUE_INCLUDED TRUE @@ -61,7 +61,7 @@ #define BTA_DM_PM_INCLUDED TRUE #define SDP_INCLUDED TRUE -#if CONFIG_BT_A2DP_ENABLE +#if (UC_BT_A2DP_ENABLED == TRUE) #define BTA_AR_INCLUDED TRUE #define BTA_AV_INCLUDED TRUE #define AVDT_INCLUDED TRUE @@ -74,15 +74,15 @@ #define SBC_DEC_INCLUDED TRUE #define BTC_AV_SRC_INCLUDED TRUE #define SBC_ENC_INCLUDED TRUE -#endif /* CONFIG_BT_A2DP_ENABLE */ +#endif /* UC_BT_A2DP_ENABLED */ -#if CONFIG_BT_SPP_ENABLED +#if (UC_BT_SPP_ENABLED == TRUE) #define RFCOMM_INCLUDED TRUE #define BTA_JV_INCLUDED TRUE #define BTC_SPP_INCLUDED TRUE -#endif /* CONFIG_BT_SPP_ENABLED */ +#endif /* UC_BT_SPP_ENABLED */ -#if CONFIG_BT_HFP_CLIENT_ENABLE +#if (UC_BT_HFP_CLIENT_ENABLED == TRUE) #define BTC_HF_CLIENT_INCLUDED TRUE #define BTA_HF_INCLUDED TRUE #define PLC_INCLUDED TRUE @@ -95,96 +95,81 @@ #ifndef BTM_MAX_SCO_LINKS #define BTM_MAX_SCO_LINKS (1) #endif + #ifndef SBC_DEC_INCLUDED #define SBC_DEC_INCLUDED TRUE #endif #ifndef SBC_ENC_INCLUDED #define SBC_ENC_INCLUDED TRUE #endif -#endif /* CONFIG_HFP_HF_ENABLE */ +#endif /* UC_BT_HFP_CLIENT_ENABLED */ -#if CONFIG_BT_SSP_ENABLED +#if UC_BT_SSP_ENABLED #define BT_SSP_INCLUDED TRUE -#endif /* CONFIG_BT_SSP_ENABLED */ +#endif /* UC_BT_SSP_ENABLED */ -#endif /* #if CONFIG_BT_CLASSIC_ENABLED */ +#endif /* UC_BT_CLASSIC_ENABLED */ #ifndef CLASSIC_BT_INCLUDED #define CLASSIC_BT_INCLUDED FALSE #endif /* CLASSIC_BT_INCLUDED */ -#ifndef CONFIG_BT_GATTC_CACHE_NVS_FLASH -#define CONFIG_BT_GATTC_CACHE_NVS_FLASH FALSE -#endif /* CONFIG_BT_GATTC_CACHE_NVS_FLASH */ - /****************************************************************************** ** ** BLE features ** ******************************************************************************/ -#if (CONFIG_BT_GATTS_ENABLE) +#if (UC_BT_GATTS_ENABLE) #define GATTS_INCLUDED TRUE #else #define GATTS_INCLUDED FALSE -#endif /* CONFIG_BT_GATTS_ENABLE */ +#endif /* UC_BT_GATTS_ENABLE */ -#if (CONFIG_BT_GATTC_ENABLE) +#if (UC_BT_GATTC_ENABLE) #define GATTC_INCLUDED TRUE #else #define GATTC_INCLUDED FALSE -#endif /* CONFIG_BT_GATTC_ENABLE */ +#endif /* UC_BT_GATTC_ENABLE */ -#if (CONFIG_BT_GATTC_ENABLE && CONFIG_BT_GATTC_CACHE_NVS_FLASH) -#define GATTC_CACHE_NVS TRUE +#if (UC_BT_GATTC_ENABLE && UC_BT_GATTC_CACHE_NVS_FLASH_ENABLED) +#define GATTC_CACHE_NVS TRUE #else -#define GATTC_CACHE_NVS FALSE -#endif /* CONFIG_BT_GATTC_CACHE_NVS_FLASH */ +#define GATTC_CACHE_NVS FALSE +#endif /* UC_BT_GATTC_ENABLE && UC_BT_GATTC_CACHE_NVS_FLASH_ENABLED */ -#if (CONFIG_BT_SMP_ENABLE) -#define SMP_INCLUDED TRUE -#define BLE_PRIVACY_SPT TRUE +#if (UC_BT_SMP_ENABLE) +#define SMP_INCLUDED TRUE +#define BLE_PRIVACY_SPT TRUE #else -#define SMP_INCLUDED FALSE -#define BLE_PRIVACY_SPT FALSE -#endif /* CONFIG_BT_SMP_ENABLE */ +#define SMP_INCLUDED FALSE +#define BLE_PRIVACY_SPT FALSE +#endif /* UC_BT_SMP_ENABLE */ -#ifdef CONFIG_BT_SMP_SLAVE_CON_PARAMS_UPD_ENABLE -#if(CONFIG_BT_SMP_SLAVE_CON_PARAMS_UPD_ENABLE) -#define SMP_SLAVE_CON_PARAMS_UPD_ENABLE TRUE +#if(UC_BT_SMP_SLAVE_CON_PARAMS_UPD_ENABLE) +#define SMP_SLAVE_CON_PARAMS_UPD_ENABLE TRUE #else -#define SMP_SLAVE_CON_PARAMS_UPD_ENABLE FALSE -#endif -#else -#define SMP_SLAVE_CON_PARAMS_UPD_ENABLE FALSE -#endif +#define SMP_SLAVE_CON_PARAMS_UPD_ENABLE FALSE +#endif /* UC_BT_SMP_SLAVE_CON_PARAMS_UPD_ENABLE */ -#ifndef CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP -#define BLE_ADV_REPORT_FLOW_CONTROL FALSE -#else -#define BLE_ADV_REPORT_FLOW_CONTROL CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP -#endif /* CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP */ +#ifdef UC_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP +#define BLE_ADV_REPORT_FLOW_CONTROL UC_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP +#endif /* UC_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP */ -#ifndef CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM -#define BLE_ADV_REPORT_FLOW_CONTROL_NUM 100 -#else -#define BLE_ADV_REPORT_FLOW_CONTROL_NUM CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM -#endif /* CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM */ +#ifdef UC_BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM +#define BLE_ADV_REPORT_FLOW_CONTROL_NUM UC_BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM +#endif /* UC_BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM */ -#ifndef CONFIG_BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD -#define BLE_ADV_REPORT_DISCARD_THRSHOLD 20 -#else -#define BLE_ADV_REPORT_DISCARD_THRSHOLD CONFIG_BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD -#endif /* CONFIG_BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD */ +#ifdef UC_BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD +#define BLE_ADV_REPORT_DISCARD_THRSHOLD UC_BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD +#endif /* UC_BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD */ -#if (CONFIG_BT_ACL_CONNECTIONS) -#define MAX_ACL_CONNECTIONS CONFIG_BT_ACL_CONNECTIONS -#define GATT_MAX_PHY_CHANNEL CONFIG_BT_ACL_CONNECTIONS -#endif /* CONFIG_BT_ACL_CONNECTIONS */ +#ifdef UC_BT_ACL_CONNECTIONS +#define MAX_ACL_CONNECTIONS UC_BT_ACL_CONNECTIONS +#define GATT_MAX_PHY_CHANNEL UC_BT_ACL_CONNECTIONS +#endif /* UC_BT_ACL_CONNECTIONS */ -#if(CONFIG_BT_BLE_ESTAB_LINK_CONN_TOUT) -#define BLE_ESTABLISH_LINK_CONNECTION_TIMEOUT CONFIG_BT_BLE_ESTAB_LINK_CONN_TOUT -#else -#define BLE_ESTABLISH_LINK_CONNECTION_TIMEOUT 30 +#ifdef UC_BT_BLE_ESTAB_LINK_CONN_TOUT +#define BLE_ESTABLISH_LINK_CONNECTION_TIMEOUT UC_BT_BLE_ESTAB_LINK_CONN_TOUT #endif //------------------Added from bdroid_buildcfg.h--------------------- @@ -341,7 +326,7 @@ #endif #ifndef BTA_AVRCP_FF_RW_SUPPORT -#define BTA_AVRCP_FF_RW_SUPPORT FALSE//TRUE +#define BTA_AVRCP_FF_RW_SUPPORT FALSE #endif #ifndef BTA_AG_SCO_PKT_TYPES @@ -357,34 +342,30 @@ #endif #ifndef BTA_AV_CO_CP_SCMS_T -#define BTA_AV_CO_CP_SCMS_T FALSE//FALSE +#define BTA_AV_CO_CP_SCMS_T FALSE #endif #ifndef QUEUE_CONGEST_SIZE #define QUEUE_CONGEST_SIZE 40 #endif -#ifndef CONFIG_BT_BLE_HOST_QUEUE_CONG_CHECK +#if UC_BT_BLE_HOST_QUEUE_CONGESTION_CHECK +#define SCAN_QUEUE_CONGEST_CHECK TRUE +#else #define SCAN_QUEUE_CONGEST_CHECK FALSE -#else -#define SCAN_QUEUE_CONGEST_CHECK CONFIG_BT_BLE_HOST_QUEUE_CONG_CHECK #endif -#ifndef CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MODE -#define GATTS_SEND_SERVICE_CHANGE_MODE GATTS_SEND_SERVICE_CHANGE_AUTO -#else -#define GATTS_SEND_SERVICE_CHANGE_MODE CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MODE +#ifdef UC_BT_GATTS_SEND_SERVICE_CHANGE_MODE +#define GATTS_SEND_SERVICE_CHANGE_MODE UC_BT_GATTS_SEND_SERVICE_CHANGE_MODE #endif -#ifndef CONFIG_BT_BLE_ACT_SCAN_REP_ADV_SCAN -#define BTM_BLE_ACTIVE_SCAN_REPORT_ADV_SCAN_RSP_INDIVIDUALLY FALSE -#else -#define BTM_BLE_ACTIVE_SCAN_REPORT_ADV_SCAN_RSP_INDIVIDUALLY CONFIG_BT_BLE_ACT_SCAN_REP_ADV_SCAN +#ifdef UC_BT_BLE_ACT_SCAN_REP_ADV_SCAN +#define BTM_BLE_ACTIVE_SCAN_REPORT_ADV_SCAN_RSP_INDIVIDUALLY UC_BT_BLE_ACT_SCAN_REP_ADV_SCAN #endif /* This feature is used to eanble interleaved scan*/ #ifndef BTA_HOST_INTERLEAVE_SEARCH -#define BTA_HOST_INTERLEAVE_SEARCH FALSE//FALSE +#define BTA_HOST_INTERLEAVE_SEARCH FALSE #endif #ifndef BT_USE_TRACES @@ -412,7 +393,7 @@ #endif #ifndef BTIF_DM_OOB_TEST -#define BTIF_DM_OOB_TEST FALSE//TRUE +#define BTIF_DM_OOB_TEST FALSE #endif // How long to wait before activating sniff mode after entering the @@ -597,11 +578,11 @@ /* Includes SCO if TRUE */ #ifndef BTM_SCO_HCI_INCLUDED -#if CONFIG_BT_HFP_AUDIO_DATA_PATH_HCI +#if UC_BT_HFP_AUDIO_DATA_PATH_HCI #define BTM_SCO_HCI_INCLUDED TRUE /* TRUE includes SCO over HCI code */ #else #define BTM_SCO_HCI_INCLUDED FALSE -#endif /* CONFIG_BT_HFP_AUDIO_DATA_PATH_HCI */ +#endif /* UC_HFP_AUDIO_DATA_PATH_HCI */ #endif /* Includes WBS if TRUE */ @@ -1135,7 +1116,7 @@ #endif #ifndef ATT_DEBUG -#define ATT_DEBUG FALSE//TRUE +#define ATT_DEBUG FALSE #endif #ifndef BLE_PERIPHERAL_MODE_SUPPORT @@ -1537,12 +1518,12 @@ Range: 2 octets ******************************************************************************/ #ifndef BNEP_INCLUDED -#define BNEP_INCLUDED FALSE//TRUE +#define BNEP_INCLUDED FALSE #endif /* BNEP status API call is used mainly to get the L2CAP handle */ #ifndef BNEP_SUPPORTS_STATUS_API -#define BNEP_SUPPORTS_STATUS_API FALSE//TRUE +#define BNEP_SUPPORTS_STATUS_API FALSE #endif /* @@ -1550,7 +1531,7 @@ Range: 2 octets ** we will do an authentication check again on the new role */ #ifndef BNEP_DO_AUTH_FOR_ROLE_SWITCH -#define BNEP_DO_AUTH_FOR_ROLE_SWITCH FALSE//TRUE +#define BNEP_DO_AUTH_FOR_ROLE_SWITCH FALSE #endif @@ -1663,22 +1644,22 @@ Range: 2 octets /* This will enable the PANU role */ #ifndef PAN_SUPPORTS_ROLE_PANU -#define PAN_SUPPORTS_ROLE_PANU FALSE//TRUE +#define PAN_SUPPORTS_ROLE_PANU FALSE #endif /* This will enable the GN role */ #ifndef PAN_SUPPORTS_ROLE_GN -#define PAN_SUPPORTS_ROLE_GN FALSE//TRUE +#define PAN_SUPPORTS_ROLE_GN FALSE #endif /* This will enable the NAP role */ #ifndef PAN_SUPPORTS_ROLE_NAP -#define PAN_SUPPORTS_ROLE_NAP FALSE//TRUE +#define PAN_SUPPORTS_ROLE_NAP FALSE #endif /* This is just for debugging purposes */ #ifndef PAN_SUPPORTS_DEBUG_DUMP -#define PAN_SUPPORTS_DEBUG_DUMP FALSE//TRUE +#define PAN_SUPPORTS_DEBUG_DUMP FALSE #endif /* Maximum number of PAN connections allowed */ @@ -2000,7 +1981,7 @@ The maximum number of payload octets that the local device can receive in a sing ******************************************************************************/ #ifndef HCILP_INCLUDED -#define HCILP_INCLUDED FALSE//TRUE +#define HCILP_INCLUDED FALSE #endif /****************************************************************************** @@ -2042,7 +2023,7 @@ The maximum number of payload octets that the local device can receive in a sing #endif #ifndef BTA_DM_AVOID_A2DP_ROLESWITCH_ON_INQUIRY -#define BTA_DM_AVOID_A2DP_ROLESWITCH_ON_INQUIRY FALSE//TRUE +#define BTA_DM_AVOID_A2DP_ROLESWITCH_ON_INQUIRY FALSE #endif /****************************************************************************** @@ -2053,7 +2034,25 @@ The maximum number of payload octets that the local device can receive in a sing /* Enable/disable BTSnoop memory logging */ #ifndef BTSNOOP_MEM -#define BTSNOOP_MEM FALSE//TRUE +#define BTSNOOP_MEM FALSE +#endif + +#if UC_BT_BLUEDROID_MEM_DEBUG +#define HEAP_MEMORY_DEBUG TRUE +#else +#define HEAP_MEMORY_DEBUG FALSE +#endif + +#if UC_HEAP_ALLOCATION_FROM_SPIRAM_FIRST +#define HEAP_ALLOCATION_FROM_SPIRAM_FIRST TRUE +#else +#define HEAP_ALLOCATION_FROM_SPIRAM_FIRST FALSE +#endif + +#if UC_BT_BLE_DYNAMIC_ENV_MEMORY +#define BT_BLE_DYNAMIC_ENV_MEMORY TRUE +#else +#define BT_BLE_DYNAMIC_ENV_MEMORY FALSE #endif #include "common/bt_trace.h" diff --git a/components/bt/bluedroid/common/include/common/bt_trace.h b/components/bt/bluedroid/common/include/common/bt_trace.h index a0dbf9bc72..920cfa7134 100644 --- a/components/bt/bluedroid/common/include/common/bt_trace.h +++ b/components/bt/bluedroid/common/include/common/bt_trace.h @@ -19,17 +19,16 @@ #ifndef _BT_TRACE_H_ #define _BT_TRACE_H_ -#include "sdkconfig.h" - #include #include +#include "bt_user_config.h" #include "stack/bt_types.h" #ifndef LOG_LOCAL_LEVEL #ifndef BOOTLOADER_BUILD -#define LOG_LOCAL_LEVEL CONFIG_LOG_DEFAULT_LEVEL +#define LOG_LOCAL_LEVEL UC_LOG_DEFAULT_LEVEL #else -#define LOG_LOCAL_LEVEL CONFIG_BOOTLOADER_LOG_LEVEL +#define LOG_LOCAL_LEVEL UC_BOOTLOADER_LOG_LEVEL #endif #endif @@ -217,135 +216,31 @@ inline void trc_dump_buffer(const char *prefix, uint8_t *data, uint16_t len) // btla-specific ++ /* Core Stack default trace levels */ -#ifdef CONFIG_BT_LOG_HCI_TRACE_LEVEL -#define HCI_INITIAL_TRACE_LEVEL CONFIG_BT_LOG_HCI_TRACE_LEVEL -#else -#define HCI_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_BT_LOG_BTM_TRACE_LEVEL -#define BTM_INITIAL_TRACE_LEVEL CONFIG_BT_LOG_BTM_TRACE_LEVEL -#else -#define BTM_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_BT_LOG_L2CAP_TRACE_LEVEL -#define L2CAP_INITIAL_TRACE_LEVEL CONFIG_BT_LOG_L2CAP_TRACE_LEVEL -#else -#define L2CAP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL -#define RFCOMM_INITIAL_TRACE_LEVEL CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL -#else -#define RFCOMM_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_SDP_INITIAL_TRACE_LEVEL -#define SDP_INITIAL_TRACE_LEVEL CONFIG_SDP_INITIAL_TRACE_LEVEL -#else -#define SDP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_BT_LOG_GAP_TRACE_LEVEL -#define GAP_INITIAL_TRACE_LEVEL CONFIG_BT_LOG_GAP_TRACE_LEVEL -#else -#define GAP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_BT_LOG_BNEP_TRACE_LEVEL -#define BNEP_INITIAL_TRACE_LEVEL CONFIG_BT_LOG_BNEP_TRACE_LEVEL -#else -#define BNEP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_BT_LOG_PAN_TRACE_LEVEL -#define PAN_INITIAL_TRACE_LEVEL CONFIG_BT_LOG_PAN_TRACE_LEVEL -#else -#define PAN_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_BT_LOG_A2D_TRACE_LEVEL -#define A2D_INITIAL_TRACE_LEVEL CONFIG_BT_LOG_A2D_TRACE_LEVEL -#else -#define A2D_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_BT_LOG_AVDT_TRACE_LEVEL -#define AVDT_INITIAL_TRACE_LEVEL CONFIG_BT_LOG_AVDT_TRACE_LEVEL -#else -#define AVDT_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_BT_LOG_AVCT_TRACE_LEVEL -#define AVCT_INITIAL_TRACE_LEVEL CONFIG_BT_LOG_AVCT_TRACE_LEVEL -#else -#define AVCT_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_BT_LOG_AVRC_TRACE_LEVEL -#define AVRC_INITIAL_TRACE_LEVEL CONFIG_BT_LOG_AVRC_TRACE_LEVEL -#else -#define AVRC_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_BT_LOG_MCA_TRACE_LEVEL -#define MCA_INITIAL_TRACE_LEVEL CONFIG_BT_LOG_MCA_TRACE_LEVEL -#else -#define MCA_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_BT_LOG_HID_TRACE_LEVEL -#define HID_INITIAL_TRACE_LEVEL CONFIG_BT_LOG_HID_TRACE_LEVEL -#else -#define HID_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_BT_LOG_APPL_TRACE_LEVEL -#define APPL_INITIAL_TRACE_LEVEL CONFIG_BT_LOG_APPL_TRACE_LEVEL -#else -#define APPL_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_BT_LOG_GATT_TRACE_LEVEL -#define GATT_INITIAL_TRACE_LEVEL CONFIG_BT_LOG_GATT_TRACE_LEVEL -#else -#define GATT_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_BT_LOG_SMP_TRACE_LEVEL -#define SMP_INITIAL_TRACE_LEVEL CONFIG_BT_LOG_SMP_TRACE_LEVEL -#else -#define SMP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_BT_LOG_BTIF_TRACE_LEVEL -#define BTIF_INITIAL_TRACE_LEVEL CONFIG_BT_LOG_BTIF_TRACE_LEVEL -#else -#define BTIF_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_BT_LOG_BTC_TRACE_LEVEL -#define BTC_INITIAL_TRACE_LEVEL CONFIG_BT_LOG_BTC_TRACE_LEVEL -#else -#define BTC_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_BT_LOG_OSI_TRACE_LEVEL -#define OSI_INITIAL_TRACE_LEVEL CONFIG_BT_LOG_OSI_TRACE_LEVEL -#else -#define OSI_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_BT_LOG_BLUFI_TRACE_LEVEL -#define BLUFI_INITIAL_TRACE_LEVEL CONFIG_BT_LOG_BLUFI_TRACE_LEVEL -#else -#define BLUFI_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif +#define HCI_INITIAL_TRACE_LEVEL UC_BT_LOG_HCI_TRACE_LEVEL +#define BTM_INITIAL_TRACE_LEVEL UC_BT_LOG_BTM_TRACE_LEVEL +#define L2CAP_INITIAL_TRACE_LEVEL UC_BT_LOG_L2CAP_TRACE_LEVEL +#define RFCOMM_INITIAL_TRACE_LEVEL UC_BT_LOG_RFCOMM_TRACE_LEVEL +#define SDP_INITIAL_TRACE_LEVEL UC_BT_LOG_SDP_TRACE_LEVEL +#define GAP_INITIAL_TRACE_LEVEL UC_BT_LOG_GAP_TRACE_LEVEL +#define BNEP_INITIAL_TRACE_LEVEL UC_BT_LOG_BNEP_TRACE_LEVEL +#define PAN_INITIAL_TRACE_LEVEL UC_BT_LOG_PAN_TRACE_LEVEL +#define A2D_INITIAL_TRACE_LEVEL UC_BT_LOG_A2D_TRACE_LEVEL +#define AVDT_INITIAL_TRACE_LEVEL UC_BT_LOG_AVDT_TRACE_LEVEL +#define AVCT_INITIAL_TRACE_LEVEL UC_BT_LOG_AVCT_TRACE_LEVEL +#define AVRC_INITIAL_TRACE_LEVEL UC_BT_LOG_AVRC_TRACE_LEVEL +#define MCA_INITIAL_TRACE_LEVEL UC_BT_LOG_MCA_TRACE_LEVEL +#define HID_INITIAL_TRACE_LEVEL UC_BT_LOG_HID_TRACE_LEVEL +#define APPL_INITIAL_TRACE_LEVEL UC_BT_LOG_APPL_TRACE_LEVEL +#define GATT_INITIAL_TRACE_LEVEL UC_BT_LOG_GATT_TRACE_LEVEL +#define SMP_INITIAL_TRACE_LEVEL UC_BT_LOG_SMP_TRACE_LEVEL +#define BTIF_INITIAL_TRACE_LEVEL UC_BT_LOG_BTIF_TRACE_LEVEL +#define BTC_INITIAL_TRACE_LEVEL UC_BT_LOG_BTC_TRACE_LEVEL +#define OSI_INITIAL_TRACE_LEVEL UC_BT_LOG_OSI_TRACE_LEVEL +#define BLUFI_INITIAL_TRACE_LEVEL UC_BT_LOG_BLUFI_TRACE_LEVEL // btla-specific -- -#if !CONFIG_BT_STACK_NO_LOG +#if !UC_BT_STACK_NO_LOG #define LOG_ERROR(format, ... ) {if (LOG_LOCAL_LEVEL >= ESP_LOG_ERROR) esp_log_write(ESP_LOG_ERROR, "BT_LOG", LOG_FORMAT(E, format), esp_log_timestamp(), "BT_LOG", ##__VA_ARGS__); } #define LOG_WARN(format, ... ) {if (LOG_LOCAL_LEVEL >= ESP_LOG_WARN) esp_log_write(ESP_LOG_WARN, "BT_LOG", LOG_FORMAT(W, format), esp_log_timestamp(), "BT_LOG", ##__VA_ARGS__); } #define LOG_INFO(format, ... ) {if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) esp_log_write(ESP_LOG_INFO, "BT_LOG", LOG_FORMAT(I, format), esp_log_timestamp(), "BT_LOG", ##__VA_ARGS__); } @@ -695,7 +590,7 @@ extern UINT8 btif_trace_level; #define BLUFI_TRACE_EVENT(fmt, args...) #define BLUFI_TRACE_DEBUG(fmt, args...) #define BLUFI_TRACE_VERBOSE(fmt, args...) -#endif ///CONFIG_BT_STACK_NO_LOG +#endif ///!UC_BT_STACK_NO_LOG /* Simplified Trace Helper Macro diff --git a/components/bt/bluedroid/common/include/common/bt_user_config.h b/components/bt/bluedroid/common/include/common/bt_user_config.h new file mode 100644 index 0000000000..10568fbd07 --- /dev/null +++ b/components/bt/bluedroid/common/include/common/bt_user_config.h @@ -0,0 +1,372 @@ +// 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. + +#ifndef __BT_USER_CONFIG_H__ +#define __BT_USER_CONFIG_H__ + + + + +/* All the configuration from SDK defined here */ + +#include "sdkconfig.h" +#include "esp_task.h" + + +/********************************************************** + * Thread/Task reference + **********************************************************/ +#ifdef CONFIG_BLUEDROID_PINNED_TO_CORE +#define UC_TASK_PINNED_TO_CORE (CONFIG_BLUEDROID_PINNED_TO_CORE < portNUM_PROCESSORS ? CONFIG_BLUEDROID_PINNED_TO_CORE : tskNO_AFFINITY) +#else +#define UC_TASK_PINNED_TO_CORE (0) +#endif + +#ifdef CONFIG_BTC_TASK_STACK_SIZE +#define UC_BTC_TASK_STACK_SIZE CONFIG_BTC_TASK_STACK_SIZE +#else +#define UC_BTC_TASK_STACK_SIZE 3072 +#endif + +#ifdef CONFIG_A2DP_SINK_TASK_STACK_SIZE +#define UC_A2DP_SINK_TASK_STACK_SIZE CONFIG_A2DP_SINK_TASK_STACK_SIZE +#else +#define UC_A2DP_SINK_TASK_STACK_SIZE 2048 +#endif +#ifdef CONFIG_A2DP_SOURCE_TASK_STACK_SIZE +#define UC_A2DP_SOURCE_TASK_STACK_SIZE CONFIG_A2DP_SOURCE_TASK_STACK_SIZE +#else +#define UC_A2DP_SOURCE_TASK_STACK_SIZE 2048 +#endif + +/********************************************************** + * Profile reference + **********************************************************/ +//Classic BT reference +#ifdef CONFIG_BT_CLASSIC_ENABLED +#define UC_BT_CLASSIC_ENABLED CONFIG_BT_CLASSIC_ENABLED +#else +#define UC_BT_CLASSIC_ENABLED FALSE +#endif + +//A2DP +#ifdef CONFIG_BT_A2DP_ENABLE +#define UC_BT_A2DP_ENABLED CONFIG_BT_A2DP_ENABLE +#else +#define UC_BT_A2DP_ENABLED FALSE +#endif + +//SPP +#ifdef CONFIG_BT_SPP_ENABLED +#define UC_BT_SPP_ENABLED CONFIG_BT_SPP_ENABLED +#else +#define UC_BT_SPP_ENABLED FALSE +#endif + +//HFP +#ifdef CONFIG_BT_HFP_CLIENT_ENABLE +#define UC_BT_HFP_CLIENT_ENABLED CONFIG_BT_HFP_CLIENT_ENABLE +#else +#define UC_BT_HFP_CLIENT_ENABLED FALSE +#endif + +//SSP +#ifdef CONFIG_BT_SSP_ENABLED +#define UC_BT_SSP_ENABLED CONFIG_BT_SSP_ENABLED +#else +#define UC_BT_SSP_ENABLED FALSE +#endif + +//GATTS +#ifdef CONFIG_BT_GATTS_ENABLE +#define UC_BT_GATTS_ENABLED CONFIG_BT_GATTS_ENABLE +#else +#define UC_BT_GATTS_ENABLED FALSE +#endif + +//GATTC +#ifdef CONFIG_BT_GATTC_ENABLE +#define UC_BT_GATTC_ENABLED CONFIG_BT_GATTC_ENABLE +#else +#define UC_BT_GATTC_ENABLED FALSE +#endif + +//GATTC CACHE +#ifdef CONFIG_BT_GATTC_CACHE_NVS_FLASH +#define UC_BT_GATTC_CACHE_NVS_FLASH_ENABLED CONFIG_BT_GATTC_CACHE_NVS_FLASH +#else +#define UC_BT_GATTC_CACHE_NVS_FLASH_ENABLED FALSE +#endif + +//SMP +#ifdef CONFIG_BT_SMP_ENABLE +#define UC_BT_SMP_ENABLED CONFIG_BT_SMP_ENABLE +#else +#define UC_BT_SMP_ENABLED FALSE +#endif + +//SMP_SLAVE_CON_PARAMS_UPD_ENABLE +#ifdef CONFIG_BT_SMP_SLAVE_CON_PARAMS_UPD_ENABLE +#define UC_BT_SMP_SLAVE_CON_PARAMS_UPD_ENABLE CONFIG_BT_SMP_SLAVE_CON_PARAMS_UPD_ENABLE +#else +#define UC_BT_SMP_SLAVE_CON_PARAMS_UPD_ENABLE FALSE +#endif + +//BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP +#ifdef CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP +#define UC_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP +#else +#define UC_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP FALSE +#endif + +//SMP_SLAVE_CON_PARAMS_UPD_ENABLE +#ifdef CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM +#define UC_BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM +#else +#define UC_BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM 100 +#endif + +//BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP +#ifdef CONFIG_BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD +#define UC_BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD CONFIG_BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD +#else +#define UC_BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD 20 +#endif + +//BT ACL CONNECTIONS +#ifdef CONFIG_BT_ACL_CONNECTIONS +#define UC_BT_ACL_CONNECTIONS CONFIG_BT_ACL_CONNECTIONS +#else +#define UC_BT_ACL_CONNECTIONS 5 +#endif + +//BT_BLE_ESTAB_LINK_CONN_TOUT +#ifdef CONFIG_BT_BLE_ESTAB_LINK_CONN_TOUT +#define UC_BT_BLE_ESTAB_LINK_CONN_TOUT CONFIG_BT_BLE_ESTAB_LINK_CONN_TOUT +#else +#define UC_BT_BLE_ESTAB_LINK_CONN_TOUT 30 +#endif + + +//HOST QUEUE CONGEST CHECK +#ifdef CONFIG_BT_BLE_HOST_QUEUE_CONGESTION_CHECK +#define UC_BT_BLE_HOST_QUEUE_CONGESTION_CHECK CONFIG_BT_BLE_HOST_QUEUE_CONGESTION_CHECK +#else +#define UC_BT_BLE_HOST_QUEUE_CONGESTION_CHECK FALSE +#endif + +#ifdef CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MODE +#define UC_BT_GATTS_SEND_SERVICE_CHANGE_MODE CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MODE +#else +#define UC_BT_GATTS_SEND_SERVICE_CHANGE_MODE 0 +#endif + +#ifdef CONFIG_BT_BLE_ACT_SCAN_REP_ADV_SCAN +#define UC_BT_BLE_ACT_SCAN_REP_ADV_SCAN CONFIG_BT_BLE_ACT_SCAN_REP_ADV_SCAN +#else +#define UC_BT_BLE_ACT_SCAN_REP_ADV_SCAN FALSE +#endif + +//SCO VOICE OVER HCI +#ifdef CONFIG_BT_HFP_AUDIO_DATA_PATH_HCI +#define UC_BT_HFP_AUDIO_DATA_PATH_HCI CONFIG_BT_HFP_AUDIO_DATA_PATH_HCI +#else +#define UC_BT_HFP_AUDIO_DATA_PATH_HCI FALSE +#endif + + +/********************************************************** + * Memory reference + **********************************************************/ +//DYNAMIC ENV ALLOCATOR +#ifdef CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY +#define UC_BT_BLE_DYNAMIC_ENV_MEMORY CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY +#else +#define UC_BT_BLE_DYNAMIC_ENV_MEMORY FALSE +#endif + +//MEMORY ALLOCATOR +#ifdef CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST +#define UC_HEAP_ALLOCATION_FROM_SPIRAM_FIRST CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST +#else +#define UC_HEAP_ALLOCATION_FROM_SPIRAM_FIRST FALSE +#endif + +//MEMORY DEBUG +#ifdef CONFIG_BT_BLUEDROID_MEM_DEBUG +#define UC_BT_BLUEDROID_MEM_DEBUG CONFIG_BT_BLUEDROID_MEM_DEBUG +#else +#define UC_BT_BLUEDROID_MEM_DEBUG FALSE +#endif + + +/********************************************************** + * Trace reference + **********************************************************/ +#ifdef CONFIG_LOG_DEFAULT_LEVEL +#define UC_LOG_DEFAULT_LEVEL CONFIG_LOG_DEFAULT_LEVEL +#else +#define UC_LOG_DEFAULT_LEVEL 3 +#endif +#ifdef CONFIG_BOOTLOADER_LOG_LEVEL +#define UC_BOOTLOADER_LOG_LEVEL CONFIG_BOOTLOADER_LOG_LEVEL +#else +#define UC_BOOTLOADER_LOG_LEVEL 3 +#endif + +#ifdef CONFIG_BT_STACK_NO_LOG +#define UC_BT_STACK_NO_LOG CONFIG_BT_STACK_NO_LOG +#else +#define UC_BT_STACK_NO_LOG FALSE +#endif + +#define UC_TRACE_LEVEL_NONE 0 /* No trace messages to be generated */ +#define UC_TRACE_LEVEL_ERROR 1 /* Error condition trace messages */ +#define UC_TRACE_LEVEL_WARNING 2 /* Warning condition trace messages */ +#define UC_TRACE_LEVEL_API 3 /* API traces */ +#define UC_TRACE_LEVEL_EVENT 4 /* Debug messages for events */ +#define UC_TRACE_LEVEL_DEBUG 5 /* Full debug messages */ +#define UC_TRACE_LEVEL_VERBOSE 6 /* Verbose debug messages */ + +#ifdef CONFIG_BT_LOG_HCI_TRACE_LEVEL +#define UC_BT_LOG_HCI_TRACE_LEVEL CONFIG_BT_LOG_HCI_TRACE_LEVEL +#else +#define UC_BT_LOG_HCI_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_BTM_TRACE_LEVEL +#define UC_BT_LOG_BTM_TRACE_LEVEL CONFIG_BT_LOG_BTM_TRACE_LEVEL +#else +#define UC_BT_LOG_BTM_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_L2CAP_TRACE_LEVEL +#define UC_BT_LOG_L2CAP_TRACE_LEVEL CONFIG_BT_LOG_L2CAP_TRACE_LEVEL +#else +#define UC_BT_LOG_L2CAP_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL +#define UC_BT_LOG_RFCOMM_TRACE_LEVEL CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL +#else +#define UC_BT_LOG_RFCOMM_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_SDP_TRACE_LEVEL +#define UC_BT_LOG_SDP_TRACE_LEVEL CONFIG_BT_LOG_SDP_TRACE_LEVEL +#else +#define UC_BT_LOG_SDP_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_GAP_TRACE_LEVEL +#define UC_BT_LOG_GAP_TRACE_LEVEL CONFIG_BT_LOG_GAP_TRACE_LEVEL +#else +#define UC_BT_LOG_GAP_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_BNEP_TRACE_LEVEL +#define UC_BT_LOG_BNEP_TRACE_LEVEL CONFIG_BT_LOG_BNEP_TRACE_LEVEL +#else +#define UC_BT_LOG_BNEP_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_PAN_TRACE_LEVEL +#define UC_BT_LOG_PAN_TRACE_LEVEL CONFIG_BT_LOG_PAN_TRACE_LEVEL +#else +#define UC_BT_LOG_PAN_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_A2D_TRACE_LEVEL +#define UC_BT_LOG_A2D_TRACE_LEVEL CONFIG_BT_LOG_A2D_TRACE_LEVEL +#else +#define UC_BT_LOG_A2D_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_AVDT_TRACE_LEVEL +#define UC_BT_LOG_AVDT_TRACE_LEVEL CONFIG_BT_LOG_AVDT_TRACE_LEVEL +#else +#define UC_BT_LOG_AVDT_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_AVCT_TRACE_LEVEL +#define UC_BT_LOG_AVCT_TRACE_LEVEL CONFIG_BT_LOG_AVCT_TRACE_LEVEL +#else +#define UC_BT_LOG_AVCT_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_AVRC_TRACE_LEVEL +#define UC_BT_LOG_AVRC_TRACE_LEVEL CONFIG_BT_LOG_AVRC_TRACE_LEVEL +#else +#define UC_BT_LOG_AVRC_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_MCA_TRACE_LEVEL +#define UC_BT_LOG_MCA_TRACE_LEVEL CONFIG_BT_LOG_MCA_TRACE_LEVEL +#else +#define UC_BT_LOG_MCA_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_HID_TRACE_LEVEL +#define UC_BT_LOG_HID_TRACE_LEVEL CONFIG_BT_LOG_HID_TRACE_LEVEL +#else +#define UC_BT_LOG_HID_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_APPL_TRACE_LEVEL +#define UC_BT_LOG_APPL_TRACE_LEVEL CONFIG_BT_LOG_APPL_TRACE_LEVEL +#else +#define UC_BT_LOG_APPL_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_GATT_TRACE_LEVEL +#define UC_BT_LOG_GATT_TRACE_LEVEL CONFIG_BT_LOG_GATT_TRACE_LEVEL +#else +#define UC_BT_LOG_GATT_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_SMP_TRACE_LEVEL +#define UC_BT_LOG_SMP_TRACE_LEVEL CONFIG_BT_LOG_SMP_TRACE_LEVEL +#else +#define UC_BT_LOG_SMP_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_BTIF_TRACE_LEVEL +#define UC_BT_LOG_BTIF_TRACE_LEVEL CONFIG_BT_LOG_BTIF_TRACE_LEVEL +#else +#define UC_BT_LOG_BTIF_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_BTC_TRACE_LEVEL +#define UC_BT_LOG_BTC_TRACE_LEVEL CONFIG_BT_LOG_BTC_TRACE_LEVEL +#else +#define UC_BT_LOG_BTC_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_OSI_TRACE_LEVEL +#define UC_BT_LOG_OSI_TRACE_LEVEL CONFIG_BT_LOG_OSI_TRACE_LEVEL +#else +#define UC_BT_LOG_OSI_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_BLUFI_TRACE_LEVEL +#define UC_BT_LOG_BLUFI_TRACE_LEVEL CONFIG_BT_LOG_BLUFI_TRACE_LEVEL +#else +#define UC_BT_LOG_BLUFI_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + + +#endif /* __BT_USER_CONFIG_H__ */ + + + diff --git a/components/bt/bluedroid/hci/hci_hal_h4.c b/components/bt/bluedroid/hci/hci_hal_h4.c index 4189aa2fe5..b31deda79c 100644 --- a/components/bt/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/bluedroid/hci/hci_hal_h4.c @@ -29,9 +29,8 @@ #define HCI_H4_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) #define HCI_H4_TASK_STACK_SIZE (2048 + BT_TASK_EXTRA_STACK_SIZE) -#define HCI_H4_TASK_PRIO (configMAX_PRIORITIES - 4) +#define HCI_H4_TASK_PRIO (BT_TASK_MAX_PRIORITIES - 4) #define HCI_H4_TASK_NAME "hciH4T" -#define HCI_H4_QUEUE_LEN 1 #if (C2H_FLOW_CONTROL_INCLUDED == TRUE) diff --git a/components/bt/bluedroid/hci/hci_layer.c b/components/bt/bluedroid/hci/hci_layer.c index 67ed0a2bcc..00c6f19e7c 100644 --- a/components/bt/bluedroid/hci/hci_layer.c +++ b/components/bt/bluedroid/hci/hci_layer.c @@ -36,9 +36,8 @@ #define HCI_HOST_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) #define HCI_HOST_TASK_STACK_SIZE (2048 + BT_TASK_EXTRA_STACK_SIZE) -#define HCI_HOST_TASK_PRIO (configMAX_PRIORITIES - 3) +#define HCI_HOST_TASK_PRIO (BT_TASK_MAX_PRIORITIES - 3) #define HCI_HOST_TASK_NAME "hciHostT" -#define HCI_HOST_QUEUE_LEN 40 typedef struct { uint16_t opcode; diff --git a/components/bt/bluedroid/osi/allocator.c b/components/bt/bluedroid/osi/allocator.c index 866ccc2e26..de8c8da722 100644 --- a/components/bt/bluedroid/osi/allocator.c +++ b/components/bt/bluedroid/osi/allocator.c @@ -24,7 +24,8 @@ extern void *pvPortZalloc(size_t size); extern void vPortFree(void *pv); -#ifdef CONFIG_BT_BLUEDROID_MEM_DEBUG + +#if HEAP_MEMORY_DEBUG #define OSI_MEM_DBG_INFO_MAX 1024*3 typedef struct { @@ -130,48 +131,48 @@ char *osi_strdup(const char *str) void *osi_malloc_func(size_t size) { -#ifdef CONFIG_BT_BLUEDROID_MEM_DEBUG +#if HEAP_MEMORY_DEBUG void *p; -#if CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST +#if HEAP_ALLOCATION_FROM_SPIRAM_FIRST p = heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL); #else p = malloc(size); -#endif /* #if CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST */ +#endif /* #if HEAP_ALLOCATION_FROM_SPIRAM_FIRST */ osi_mem_dbg_record(p, size, __func__, __LINE__); return p; #else -#if CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST +#if HEAP_ALLOCATION_FROM_SPIRAM_FIRST return heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL); #else return malloc(size); -#endif /* #if CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST */ -#endif /* #ifdef CONFIG_BT_BLUEDROID_MEM_DEBUG */ +#endif /* #if HEAP_ALLOCATION_FROM_SPIRAM_FIRST */ +#endif /* #if HEAP_MEMORY_DEBUG */ } void *osi_calloc_func(size_t size) { -#ifdef CONFIG_BT_BLUEDROID_MEM_DEBUG +#if HEAP_MEMORY_DEBUG void *p; -#if CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST +#if HEAP_ALLOCATION_FROM_SPIRAM_FIRST p = heap_caps_calloc_prefer(1, size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL); #else p = calloc(1, size); -#endif /* #if CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST */ +#endif /* #if HEAP_ALLOCATION_FROM_SPIRAM_FIRST */ osi_mem_dbg_record(p, size, __func__, __LINE__); return p; #else -#if CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST +#if HEAP_ALLOCATION_FROM_SPIRAM_FIRST return heap_caps_calloc_prefer(1, size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL); #else return calloc(1, size); -#endif /* #if CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST */ -#endif /* #ifdef CONFIG_BT_BLUEDROID_MEM_DEBUG */ +#endif /* #if HEAP_ALLOCATION_FROM_SPIRAM_FIRST */ +#endif /* #if HEAP_MEMORY_DEBUG */ } void osi_free_func(void *ptr) { -#ifdef CONFIG_BT_BLUEDROID_MEM_DEBUG - osi_mem_dbg_clean(ptr, __func__, __LINE__); +#if HEAP_MEMORY_DEBUG + osi_mem_dbg_clean(ptr, __func__, __LINE__); #endif free(ptr); } diff --git a/components/bt/bluedroid/osi/include/osi/allocator.h b/components/bt/bluedroid/osi/include/osi/allocator.h index 3be366e76a..f30987e058 100644 --- a/components/bt/bluedroid/osi/include/osi/allocator.h +++ b/components/bt/bluedroid/osi/include/osi/allocator.h @@ -22,7 +22,6 @@ #include #include #include "esp_heap_caps.h" -#include "sdkconfig.h" char *osi_strdup(const char *str); @@ -30,14 +29,14 @@ void *osi_malloc_func(size_t size); void *osi_calloc_func(size_t size); void osi_free_func(void *ptr); -#ifdef CONFIG_BT_BLUEDROID_MEM_DEBUG +#if HEAP_MEMORY_DEBUG void osi_mem_dbg_init(void); void osi_mem_dbg_record(void *p, int size, const char *func, int line); void osi_mem_dbg_clean(void *p, const char *func, int line); void osi_mem_dbg_show(void); -#if CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST +#if HEAP_ALLOCATION_FROM_SPIRAM_FIRST #define osi_malloc(size) \ ({ \ void *p; \ @@ -76,7 +75,7 @@ void osi_mem_dbg_show(void); (void *)p; \ }) -#endif /* #if CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST */ +#endif /* #if HEAP_ALLOCATION_FROM_SPIRAM_FIRST */ #if 0 @@ -84,11 +83,11 @@ void osi_mem_dbg_show(void); do { \ void *p; \ \ -#if CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST \ +#if HEAP_ALLOCATION_FROM_SPIRAM_FIRST \ p = heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL); \ #else \ p = malloc((size)); \ -#endif /* #if CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST */ \ +#endif /* #if HEAP_ALLOCATION_FROM_SPIRAM_FIRST */ \ osi_mem_dbg_record(p, size, __func__, __LINE__); \ (void *)p; \ }while(0) @@ -97,13 +96,13 @@ do { \ do { \ void *p; \ \ -#if CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST \ +#if HEAP_ALLOCATION_FROM_SPIRAM_FIRST \ p = heap_caps_calloc_prefer(1, size, 2, \ MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, \ MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL); \ #else \ p = calloc(1, (size)); \ -#endif /* #if CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST */ \ +#endif /* #if HEAP_ALLOCATION_FROM_SPIRAM_FIRST */ \ osi_mem_dbg_record(p, size, __func__, __LINE__); \ (void *)p; \ } while(0) @@ -118,16 +117,16 @@ do { \ #else -#if CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST +#if HEAP_ALLOCATION_FROM_SPIRAM_FIRST #define osi_malloc(size) heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL) #define osi_calloc(size) heap_caps_calloc_prefer(1, size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL) #else #define osi_malloc(size) malloc((size)) #define osi_calloc(size) calloc(1, (size)) -#endif /* #if CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST */ +#endif /* #if HEAP_ALLOCATION_FROM_SPIRAM_FIRST */ #define osi_free(p) free((p)) -#endif /* CONFIG_BT_BLUEDROID_MEM_DEBUG */ +#endif /* HEAP_MEMORY_DEBUG */ #define FREE_AND_RESET(a) \ do { \ diff --git a/components/bt/bluedroid/stack/btm/btm_sec.c b/components/bt/bluedroid/stack/btm/btm_sec.c index 1ad3cfce3b..0a61eac6fd 100644 --- a/components/bt/bluedroid/stack/btm/btm_sec.c +++ b/components/bt/bluedroid/stack/btm/btm_sec.c @@ -1789,53 +1789,6 @@ UINT16 BTM_BuildOobData(UINT8 *p_data, UINT16 max_len, BT_OCTET16 c, return len; } -/******************************************************************************* -** -** Function BTM_BothEndsSupportSecureConnections -** -** Description This function is called to check if both the local device and the peer device -** specified by bd_addr support BR/EDR Secure Connections. -** -** Parameters: bd_addr - address of the peer -** -** Returns TRUE if BR/EDR Secure Connections are supported by both local -** and the remote device. -** else FALSE. -** -*******************************************************************************/ -BOOLEAN BTM_BothEndsSupportSecureConnections(BD_ADDR bd_addr) -{ - return ((controller_get_interface()->supports_secure_connections()) && - (BTM_PeerSupportsSecureConnections(bd_addr))); -} - -/******************************************************************************* -** -** Function BTM_PeerSupportsSecureConnections -** -** Description This function is called to check if the peer supports -** BR/EDR Secure Connections. -** -** Parameters: bd_addr - address of the peer -** -** Returns TRUE if BR/EDR Secure Connections are supported by the peer, -** else FALSE. -** -*******************************************************************************/ -BOOLEAN BTM_PeerSupportsSecureConnections(BD_ADDR bd_addr) -{ - tBTM_SEC_DEV_REC *p_dev_rec; - - if ((p_dev_rec = btm_find_dev(bd_addr)) == NULL) { - BTM_TRACE_WARNING("%s: unknown BDA: %08x%04x\n", __FUNCTION__, - (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3], - (bd_addr[4] << 8) + bd_addr[5]); - return FALSE; - } - - return (p_dev_rec->remote_supports_secure_connections); -} - /******************************************************************************* ** ** Function BTM_ReadOobData @@ -1899,6 +1852,54 @@ UINT8 *BTM_ReadOobData(UINT8 *p_data, UINT8 eir_tag, UINT8 *p_len) } #endif ///BTM_OOB_INCLUDED == TRUE && SMP_INCLUDED == TRUE +#if (CLASSIC_BT_INCLUDED == TRUE) +/******************************************************************************* +** +** Function BTM_BothEndsSupportSecureConnections +** +** Description This function is called to check if both the local device and the peer device +** specified by bd_addr support BR/EDR Secure Connections. +** +** Parameters: bd_addr - address of the peer +** +** Returns TRUE if BR/EDR Secure Connections are supported by both local +** and the remote device. +** else FALSE. +** +*******************************************************************************/ +BOOLEAN BTM_BothEndsSupportSecureConnections(BD_ADDR bd_addr) +{ + return ((controller_get_interface()->supports_secure_connections()) && + (BTM_PeerSupportsSecureConnections(bd_addr))); +} + +/******************************************************************************* +** +** Function BTM_PeerSupportsSecureConnections +** +** Description This function is called to check if the peer supports +** BR/EDR Secure Connections. +** +** Parameters: bd_addr - address of the peer +** +** Returns TRUE if BR/EDR Secure Connections are supported by the peer, +** else FALSE. +** +*******************************************************************************/ +BOOLEAN BTM_PeerSupportsSecureConnections(BD_ADDR bd_addr) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + + if ((p_dev_rec = btm_find_dev(bd_addr)) == NULL) { + BTM_TRACE_WARNING("%s: unknown BDA: %08x%04x\n", __FUNCTION__, + (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3], + (bd_addr[4] << 8) + bd_addr[5]); + return FALSE; + } + + return (p_dev_rec->remote_supports_secure_connections); +} + /******************************************************************************* ** ** Function BTM_SetOutService @@ -1913,7 +1914,6 @@ UINT8 *BTM_ReadOobData(UINT8 *p_data, UINT8 eir_tag, UINT8 *p_len) ** Returns void ** *******************************************************************************/ -#if (CLASSIC_BT_INCLUDED == TRUE) void BTM_SetOutService(BD_ADDR bd_addr, UINT8 service_id, UINT32 mx_chan_id) { tBTM_SEC_DEV_REC *p_dev_rec; diff --git a/components/bt/bluedroid/stack/btu/btu_init.c b/components/bt/bluedroid/stack/btu/btu_init.c index 510fab7ecf..bf3a55af8c 100644 --- a/components/bt/bluedroid/stack/btu/btu_init.c +++ b/components/bt/bluedroid/stack/btu/btu_init.c @@ -46,9 +46,8 @@ #define BTU_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) #define BTU_TASK_STACK_SIZE (4096 + BT_TASK_EXTRA_STACK_SIZE) -#define BTU_TASK_PRIO (configMAX_PRIORITIES - 5) +#define BTU_TASK_PRIO (BT_TASK_MAX_PRIORITIES - 5) #define BTU_TASK_NAME "btuT" -#define BTU_QUEUE_LEN 50 hash_map_t *btu_general_alarm_hash_map; osi_mutex_t btu_general_alarm_lock; @@ -219,7 +218,7 @@ void BTU_ShutDown(void) btu_thread = NULL; } - btu_general_alarm_hash_map = NULL; + btu_general_alarm_hash_map = NULL; btu_oneshot_alarm_hash_map = NULL; btu_l2cap_alarm_hash_map = NULL; } diff --git a/components/bt/bluedroid/stack/include/stack/dyn_mem.h b/components/bt/bluedroid/stack/include/stack/dyn_mem.h index f3f33537ca..2b2db28453 100644 --- a/components/bt/bluedroid/stack/include/stack/dyn_mem.h +++ b/components/bt/bluedroid/stack/include/stack/dyn_mem.h @@ -18,8 +18,8 @@ #ifndef DYN_MEM_H #define DYN_MEM_H -#include "sdkconfig.h" -#if CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY +#include "common/bt_target.h" +#if BT_BLE_DYNAMIC_ENV_MEMORY #define BTU_DYNAMIC_MEMORY TRUE #define BTM_DYNAMIC_MEMORY TRUE #define L2C_DYNAMIC_MEMORY TRUE @@ -53,7 +53,7 @@ #define BTC_SBC_DEC_DYNAMIC_MEMORY TRUE #define BTC_SBC_ENC_DYNAMIC_MEMORY TRUE -#else /* #if CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY */ +#else /* #if BT_BLE_DYNAMIC_ENV_MEMORY */ #define SDP_DYNAMIC_MEMORY FALSE #define RFC_DYNAMIC_MEMORY FALSE @@ -82,7 +82,7 @@ #define BTC_SBC_DEC_DYNAMIC_MEMORY FALSE #define BTC_SBC_ENC_DYNAMIC_MEMORY FALSE -#endif /* #if CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY */ +#endif /* #if BT_BLE_DYNAMIC_ENV_MEMORY */ /**************************************************************************** ** Define memory usage for each CORE component (if not defined in bdroid_buildcfg.h) ** The default for each component is to use static memory allocations. From 37cb673cd720d1e0ee19e5f92a4f3e2ad253e1a6 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Wed, 19 Jun 2019 20:35:55 +0800 Subject: [PATCH 084/486] esp_flash: update the document to the latest API --- components/spi_flash/README.rst | 12 +++++- components/spi_flash/esp_flash_api.c | 28 ++++++------- components/spi_flash/include/esp_flash.h | 44 +++++++++++---------- docs/Doxyfile | 3 +- docs/en/api-reference/storage/spi_flash.rst | 3 +- docs/sphinx-known-warnings.txt | 2 + 6 files changed, 53 insertions(+), 39 deletions(-) diff --git a/components/spi_flash/README.rst b/components/spi_flash/README.rst index 26387c04a5..a6f37b53cb 100644 --- a/components/spi_flash/README.rst +++ b/components/spi_flash/README.rst @@ -13,13 +13,21 @@ the "main" SPI flash chip (the same SPI flash chip from which program runs). With different chip pointers, you can access to external flashes chips on not only SPI0/1 but also HSPI/VSPI buses. -Kconfig option :ref:``CONFIG_SPI_FLASH_USE_LEGACY_IMPL`` can be used to switch +.. note:: + + Flash APIs after IDF v4.0 are no longer *atomic*. A writing operation + during another on-going read operation, on the overlapped flash address, + may cause the return data from the read operation to be partly same as + before, and partly updated as new written. + + +Kconfig option :ref:`CONFIG_SPI_FLASH_USE_LEGACY_IMPL` can be used to switch ``spi_flash_*`` functions back to the implementation before IDF v4.0. However, the code size may get bigger if you use the new API and the old API the same time. Encrypted reads and writes use the old implementation, even if -:ref:``CONFIG_SPI_FLASH_USE_LEGACY_IMPL`` is not enabled. As such, encrypted +:ref:`CONFIG_SPI_FLASH_USE_LEGACY_IMPL` is not enabled. As such, encrypted flash operations are only supported with the main flash chip (and not with other flash chips on SPI1 with different CS). diff --git a/components/spi_flash/esp_flash_api.c b/components/spi_flash/esp_flash_api.c index 48533ec573..58a8c30f2a 100644 --- a/components/spi_flash/esp_flash_api.c +++ b/components/spi_flash/esp_flash_api.c @@ -241,7 +241,7 @@ static esp_err_t IRAM_ATTR detect_spi_flash_chip(esp_flash_t *chip) } \ } while (0) -esp_err_t IRAM_ATTR esp_flash_read_id(esp_flash_t *chip, uint32_t *id) +esp_err_t IRAM_ATTR esp_flash_read_id(esp_flash_t *chip, uint32_t *out_id) { if (chip == NULL) { chip = esp_flash_default_chip; @@ -249,7 +249,7 @@ esp_err_t IRAM_ATTR esp_flash_read_id(esp_flash_t *chip, uint32_t *id) if (chip == NULL || !esp_flash_chip_driver_initialized(chip)) { return ESP_ERR_FLASH_NOT_INITIALISED; } - if (id == NULL) { + if (out_id == NULL) { return ESP_ERR_INVALID_ARG; } esp_err_t err = spiflash_start(chip); @@ -257,19 +257,19 @@ esp_err_t IRAM_ATTR esp_flash_read_id(esp_flash_t *chip, uint32_t *id) return err; } - err = chip->host->read_id(chip->host, id); + err = chip->host->read_id(chip->host, out_id); return spiflash_end(chip, err); } -esp_err_t IRAM_ATTR esp_flash_get_size(esp_flash_t *chip, uint32_t *size) +esp_err_t IRAM_ATTR esp_flash_get_size(esp_flash_t *chip, uint32_t *out_size) { VERIFY_OP(detect_size); - if (size == NULL) { + if (out_size == NULL) { return ESP_ERR_INVALID_ARG; } if (chip->size != 0) { - *size = chip->size; + *out_size = chip->size; return ESP_OK; } @@ -401,7 +401,7 @@ esp_err_t IRAM_ATTR esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *wr return spiflash_end(chip, err); } -esp_err_t IRAM_ATTR esp_flash_set_chip_write_protect(esp_flash_t *chip, bool write_protect_chip) +esp_err_t IRAM_ATTR esp_flash_set_chip_write_protect(esp_flash_t *chip, bool write_protect) { VERIFY_OP(set_chip_write_protect); //TODO: skip writing if already locked or unlocked @@ -411,24 +411,24 @@ esp_err_t IRAM_ATTR esp_flash_set_chip_write_protect(esp_flash_t *chip, bool wri return err; } - err = chip->chip_drv->set_chip_write_protect(chip, write_protect_chip); + err = chip->chip_drv->set_chip_write_protect(chip, write_protect); return spiflash_end(chip, err); } -esp_err_t esp_flash_get_protectable_regions(const esp_flash_t *chip, const esp_flash_region_t **regions, uint32_t *num_regions) +esp_err_t esp_flash_get_protectable_regions(const esp_flash_t *chip, const esp_flash_region_t **out_regions, uint32_t *out_num_regions) { - if(num_regions != NULL) { - *num_regions = 0; // In case caller doesn't check result + if(out_num_regions != NULL) { + *out_num_regions = 0; // In case caller doesn't check result } VERIFY_OP(get_protected_regions); - if(regions == NULL || num_regions == NULL) { + if(out_regions == NULL || out_num_regions == NULL) { return ESP_ERR_INVALID_ARG; } - *num_regions = chip->chip_drv->num_protectable_regions; - *regions = chip->chip_drv->protectable_regions; + *out_num_regions = chip->chip_drv->num_protectable_regions; + *out_regions = chip->chip_drv->protectable_regions; return ESP_OK; } diff --git a/components/spi_flash/include/esp_flash.h b/components/spi_flash/include/esp_flash.h index 81524dc5d2..84a349b489 100644 --- a/components/spi_flash/include/esp_flash.h +++ b/components/spi_flash/include/esp_flash.h @@ -30,11 +30,11 @@ typedef struct esp_flash_t esp_flash_t; /** @brief Structure for describing a region of flash */ typedef struct { - uint32_t offset; - uint32_t size; + uint32_t offset; ///< Start address of this region + uint32_t size; ///< Size of the region } esp_flash_region_t; -/* OS-level integration hooks for accessing flash chips inside a running OS */ +/** OS-level integration hooks for accessing flash chips inside a running OS */ typedef struct { /** * Called before commencing any flash operation. Does not need to be @@ -51,16 +51,16 @@ typedef struct { /** @brief Structure to describe a SPI flash chip connected to the system. - Structure must be passed to esp_flash_init() before use. + Structure must be initialized before use (passed to esp_flash_init()). */ struct esp_flash_t { + spi_flash_host_driver_t *host; ///< Pointer to hardware-specific "host_driver" structure. Must be initialized before used. const spi_flash_chip_t *chip_drv; ///< Pointer to chip-model-specific "adapter" structure. If NULL, will be detected during initialisation. - spi_flash_host_driver_t *host; ///< Pointer to hardware-specific "host_driver" structure. - const esp_flash_os_functions_t *os_func; ///< Pointer to os-specific hook structure. - void *os_func_data; ///< Pointer to argument for os-specific hooks. + const esp_flash_os_functions_t *os_func; ///< Pointer to os-specific hook structure. Call ``esp_flash_init_os_functions()`` to setup this field, after the host is properly initialized. + void *os_func_data; ///< Pointer to argument for os-specific hooks. Left NULL and will be initialized with ``os_func``. - esp_flash_read_mode_t read_mode; ///< Configured SPI flash read mode. Set before initialisation. + esp_flash_read_mode_t read_mode; ///< Configured SPI flash read mode. Set before ``esp_flash_init`` is called. uint32_t size; ///< Size of SPI flash in bytes. If 0, size will be detected during initialisation. }; @@ -69,11 +69,13 @@ struct esp_flash_t { * * This function must be called before any other API functions are called for this chip. * - * @note Only the host, speed & read_mode fields of the chip structure need to be initialised. Other fields will be auto-detected - * if left set to zero or NULL. + * @note Only the ``host`` and ``read_mode`` fields of the chip structure must + * be initialised before this function is called. Other fields may be + * auto-detected if left set to zero or NULL. * - * @note If the chip->drv pointer is NULL, chip chip_drv will be autodetected based on its manufacturer & product IDs. See - * esp_flash_registered_flash_drivers pointer for details of this process. + * @note If the chip->drv pointer is NULL, chip chip_drv will be auto-detected + * based on its manufacturer & product IDs. See + * ``esp_flash_registered_flash_drivers`` pointer for details of this process. * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. * @return ESP_OK on success, or a flash error code if initialisation fails. @@ -92,25 +94,25 @@ bool esp_flash_chip_driver_initialized(const esp_flash_t *chip); /** @brief Read flash ID via the common "RDID" SPI flash command. * * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() - * @param[out] Pointer to receive ID value. + * @param[out] out_id Pointer to receive ID value. * * ID is a 24-bit value. Lower 16 bits of 'id' are the chip ID, upper 8 bits are the manufacturer ID. * * @return ESP_OK on success, or a flash error code if operation failed. */ -esp_err_t esp_flash_read_id(esp_flash_t *chip, uint32_t *id); +esp_err_t esp_flash_read_id(esp_flash_t *chip, uint32_t *out_id); /** @brief Detect flash size based on flash ID. * * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() - * @param[out] Detected size in bytes. + * @param[out] out_size Detected size in bytes. * * @note Most flash chips use a common format for flash ID, where the lower 4 bits specify the size as a power of 2. If * the manufacturer doesn't follow this convention, the size may be incorrectly detected. * * @return ESP_OK on success, or a flash error code if operation failed. */ -esp_err_t esp_flash_get_size(esp_flash_t *chip, uint32_t *size); +esp_err_t esp_flash_get_size(esp_flash_t *chip, uint32_t *out_size); /** @brief Erase flash chip contents * @@ -153,7 +155,7 @@ esp_err_t esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *write_protec /** @brief Set write protection for the SPI flash chip * * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() - * @param write_protected Boolean value for the write protect flag + * @param write_protect Boolean value for the write protect flag * * @note Correct behaviour of this function depends on the SPI flash chip model and chip_drv in use (via the 'chip->drv' * field). @@ -165,21 +167,21 @@ esp_err_t esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *write_protec * * @return ESP_OK on success, or a flash error code if operation failed. */ -esp_err_t esp_flash_set_chip_write_protect(esp_flash_t *chip, bool write_protect_chip); +esp_err_t esp_flash_set_chip_write_protect(esp_flash_t *chip, bool write_protect); /** @brief Read the list of individually protectable regions of this SPI flash chip. * * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() - * @param regions[out] Pointer to receive a pointer to the array of protectable regions of the chip. - * @param[out] Pointer to an integer receiving the count of protectable regions in the array returned in 'regions'. + * @param[out] out_regions Pointer to receive a pointer to the array of protectable regions of the chip. + * @param[out] out_num_regions Pointer to an integer receiving the count of protectable regions in the array returned in 'regions'. * * @note Correct behaviour of this function depends on the SPI flash chip model and chip_drv in use (via the 'chip->drv' * field). * * @return ESP_OK on success, or a flash error code if operation failed. */ -esp_err_t esp_flash_get_protectable_regions(const esp_flash_t *chip, const esp_flash_region_t **regions, uint32_t *num_regions); +esp_err_t esp_flash_get_protectable_regions(const esp_flash_t *chip, const esp_flash_region_t **out_regions, uint32_t *out_num_regions); /** @brief Detect if a region of the SPI flash chip is protected diff --git a/docs/Doxyfile b/docs/Doxyfile index 858a6a39e0..3434ec5082 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -127,9 +127,10 @@ INPUT = \ ## Storage - API Reference ## ## SPI Flash and Partition APIs - ../../components/spi_flash/include/esp_spi_flash.h \ + ../../components/spi_flash/include/esp_flash.h \ ../../components/spi_flash/include/esp_partition.h \ ../../components/bootloader_support/include/esp_flash_encrypt.h \ + ../../components/soc/include/hal/spi_flash_types.h \ ## SPIFFS ../../components/spiffs/include/esp_spiffs.h \ ## SD/MMC Card Host diff --git a/docs/en/api-reference/storage/spi_flash.rst b/docs/en/api-reference/storage/spi_flash.rst index 5595011d77..ff70cfd35b 100644 --- a/docs/en/api-reference/storage/spi_flash.rst +++ b/docs/en/api-reference/storage/spi_flash.rst @@ -31,7 +31,8 @@ In a single core environment (:ref:`CONFIG_FREERTOS_UNICORE` enabled), you need API Reference - SPI Flash ------------------------- -.. include:: /_build/inc/esp_spi_flash.inc +.. include:: /_build/inc/esp_flash.inc +.. include:: /_build/inc/spi_flash_types.inc API Reference - Partition Table ------------------------------- diff --git a/docs/sphinx-known-warnings.txt b/docs/sphinx-known-warnings.txt index 72fb40a5b6..fe496b067f 100644 --- a/docs/sphinx-known-warnings.txt +++ b/docs/sphinx-known-warnings.txt @@ -77,6 +77,8 @@ If type alias or template alias: # spi_master.inc:line: WARNING: Duplicate declaration, struct spi_transaction_t spi_transaction_t spi_slave.inc:line: WARNING: Duplicate declaration, struct spi_slave_transaction_t spi_slave_transaction_t +esp_flash.inc:line: WARNING: Duplicate declaration, struct esp_flash_t esp_flash_t +spi_flash_types.inc:line: WARNING: Duplicate declaration, struct spi_flash_host_driver_t spi_flash_host_driver_t wear-levelling.rst:line: WARNING: Duplicate declaration, bool esp_vfs_fat_mount_config_t::format_if_mount_failed wear-levelling.rst:line: WARNING: Duplicate declaration, int esp_vfs_fat_mount_config_t::max_files wear-levelling.rst:line: WARNING: Duplicate declaration, size_t esp_vfs_fat_mount_config_t::allocation_unit_size From 2a2d932cfe2404057c71bc91d9d9416200e67a03 Mon Sep 17 00:00:00 2001 From: Tuan Date: Thu, 20 Jun 2019 15:37:40 +0800 Subject: [PATCH 085/486] esp_websocket_client: Add websocket client component Closes https://github.com/espressif/esp-idf/issues/2829 --- .../esp_websocket_client/CMakeLists.txt | 4 + components/esp_websocket_client/component.mk | 0 .../esp_websocket_client.c | 606 ++++++++++++++++++ .../include/esp_websocket_client.h | 195 ++++++ components/mqtt/esp-mqtt | 2 +- .../tcp_transport/include/esp_transport_ws.h | 17 + components/tcp_transport/transport_ssl.c | 2 + components/tcp_transport/transport_ws.c | 87 ++- docs/Doxyfile | 1 + .../protocols/esp_websocket_client.rst | 70 ++ docs/en/api-reference/protocols/index.rst | 1 + .../protocols/esp_websocket_client.rst | 1 + docs/zh_CN/api-reference/protocols/index.rst | 1 + examples/protocols/websocket/CMakeLists.txt | 10 + examples/protocols/websocket/Makefile | 10 + examples/protocols/websocket/README.md | 1 + examples/protocols/websocket/example_test.py | 41 ++ .../protocols/websocket/main/CMakeLists.txt | 4 + .../websocket/main/Kconfig.projbuild | 9 + .../protocols/websocket/main/component.mk | 0 .../websocket/main/websocket_example.c | 103 +++ 21 files changed, 1147 insertions(+), 18 deletions(-) create mode 100644 components/esp_websocket_client/CMakeLists.txt create mode 100644 components/esp_websocket_client/component.mk create mode 100644 components/esp_websocket_client/esp_websocket_client.c create mode 100644 components/esp_websocket_client/include/esp_websocket_client.h create mode 100644 docs/en/api-reference/protocols/esp_websocket_client.rst create mode 100644 docs/zh_CN/api-reference/protocols/esp_websocket_client.rst create mode 100644 examples/protocols/websocket/CMakeLists.txt create mode 100644 examples/protocols/websocket/Makefile create mode 100644 examples/protocols/websocket/README.md create mode 100644 examples/protocols/websocket/example_test.py create mode 100644 examples/protocols/websocket/main/CMakeLists.txt create mode 100644 examples/protocols/websocket/main/Kconfig.projbuild create mode 100644 examples/protocols/websocket/main/component.mk create mode 100644 examples/protocols/websocket/main/websocket_example.c diff --git a/components/esp_websocket_client/CMakeLists.txt b/components/esp_websocket_client/CMakeLists.txt new file mode 100644 index 0000000000..723199ce0f --- /dev/null +++ b/components/esp_websocket_client/CMakeLists.txt @@ -0,0 +1,4 @@ +set(COMPONENT_SRCS "esp_websocket_client.c") +set(COMPONENT_ADD_INCLUDEDIRS "include") +set(COMPONENT_REQUIRES lwip esp-tls tcp_transport nghttp) +register_component() diff --git a/components/esp_websocket_client/component.mk b/components/esp_websocket_client/component.mk new file mode 100644 index 0000000000..e69de29bb2 diff --git a/components/esp_websocket_client/esp_websocket_client.c b/components/esp_websocket_client/esp_websocket_client.c new file mode 100644 index 0000000000..9d4b1f053f --- /dev/null +++ b/components/esp_websocket_client/esp_websocket_client.c @@ -0,0 +1,606 @@ +// Copyright 2015-2018 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 + +#include "esp_websocket_client.h" +#include "esp_transport.h" +#include "esp_transport_tcp.h" +#include "esp_transport_ssl.h" +#include "esp_transport_ws.h" +#include "esp_transport_utils.h" +/* using uri parser */ +#include "http_parser.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/queue.h" +#include "freertos/event_groups.h" +#include "esp_log.h" +#include "esp_timer.h" + +static const char *TAG = "WEBSOCKET_CLIENT"; + +#define WEBSOCKET_TCP_DEFAULT_PORT (80) +#define WEBSOCKET_SSL_DEFAULT_PORT (443) +#define WEBSOCKET_BUFFER_SIZE_BYTE (1024) +#define WEBSOCKET_RECONNECT_TIMEOUT_MS (10*1000) +#define WEBSOCKET_TASK_PRIORITY (5) +#define WEBSOCKET_TASK_STACK (4*1024) +#define WEBSOCKET_NETWORK_TIMEOUT_MS (10*1000) +#define WEBSOCKET_PING_TIMEOUT_MS (10*1000) +#define WEBSOCKET_EVENT_QUEUE_SIZE (1) +#define WEBSOCKET_SEND_EVENT_TIMEOUT_MS (1000/portTICK_RATE_MS) + +const static int STOPPED_BIT = BIT0; + +ESP_EVENT_DEFINE_BASE(WEBSOCKET_EVENTS); + +typedef struct { + int task_stack; + int task_prio; + char *uri; + char *host; + char *path; + char *scheme; + char *username; + char *password; + int port; + bool auto_reconnect; + void *user_context; + int network_timeout_ms; +} websocket_config_storage_t; + +typedef enum { + WEBSOCKET_STATE_ERROR = -1, + WEBSOCKET_STATE_UNKNOW = 0, + WEBSOCKET_STATE_INIT, + WEBSOCKET_STATE_CONNECTED, + WEBSOCKET_STATE_WAIT_TIMEOUT, +} websocket_client_state_t; + +struct esp_websocket_client { + esp_event_loop_handle_t event_handle; + esp_transport_list_handle_t transport_list; + esp_transport_handle_t transport; + websocket_config_storage_t *config; + websocket_client_state_t state; + uint64_t keepalive_tick_ms; + uint64_t reconnect_tick_ms; + uint64_t ping_tick_ms; + int wait_timeout_ms; + int auto_reconnect; + bool run; + EventGroupHandle_t status_bits; + xSemaphoreHandle lock; + char *rx_buffer; + char *tx_buffer; + int buffer_size; +}; + +static uint64_t _tick_get_ms() +{ + return esp_timer_get_time()/1000; +} + +static esp_err_t esp_websocket_client_dispatch_event(esp_websocket_client_handle_t client, + esp_websocket_event_id_t event, + const char *data, + int data_len) +{ + esp_err_t err; + esp_websocket_event_data_t event_data; + event_data.data_ptr = data; + event_data.data_len = data_len; + + if ((err = esp_event_post_to(client->event_handle, + WEBSOCKET_EVENTS, event, + &event_data, + sizeof(esp_websocket_event_data_t), + WEBSOCKET_SEND_EVENT_TIMEOUT_MS)) != ESP_OK) { + return err; + } + return esp_event_loop_run(client->event_handle, WEBSOCKET_SEND_EVENT_TIMEOUT_MS); +} + +static esp_err_t esp_websocket_client_abort_connection(esp_websocket_client_handle_t client) +{ + esp_transport_close(client->transport); + client->wait_timeout_ms = WEBSOCKET_RECONNECT_TIMEOUT_MS; + client->reconnect_tick_ms = _tick_get_ms(); + client->state = WEBSOCKET_STATE_WAIT_TIMEOUT; + ESP_LOGI(TAG, "Reconnect after %d ms", client->wait_timeout_ms); + esp_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_DISCONNECTED, NULL, 0); + return ESP_OK; +} + +static esp_err_t esp_websocket_client_set_config(esp_websocket_client_handle_t client, const esp_websocket_client_config_t *config) +{ + websocket_config_storage_t *cfg = client->config; + cfg->task_prio = config->task_prio; + if (cfg->task_prio <= 0) { + cfg->task_prio = WEBSOCKET_TASK_PRIORITY; + } + + cfg->task_stack = config->task_stack; + if (cfg->task_stack == 0) { + cfg->task_stack = WEBSOCKET_TASK_STACK; + } + + if (config->host) { + cfg->host = strdup(config->host); + ESP_TRANSPORT_MEM_CHECK(TAG, cfg->host, return ESP_ERR_NO_MEM); + } + + if (config->port) { + cfg->port = config->port; + } + + if (config->username) { + free(cfg->username); + cfg->username = strdup(config->username); + ESP_TRANSPORT_MEM_CHECK(TAG, cfg->username, { + free(cfg->host); + return ESP_ERR_NO_MEM; + }); + } + + if (config->password) { + free(cfg->password); + cfg->password = strdup(config->password); + ESP_TRANSPORT_MEM_CHECK(TAG, cfg->password, { + free(cfg->host); + free(cfg->username); + return ESP_ERR_NO_MEM; + }); + } + + if (config->uri) { + free(cfg->uri); + cfg->uri = strdup(config->uri); + ESP_TRANSPORT_MEM_CHECK(TAG, cfg->uri, { + free(cfg->host); + free(cfg->username); + free(cfg->password); + return ESP_ERR_NO_MEM; + }); + } + if (config->path) { + free(cfg->path); + cfg->path = strdup(config->path); + ESP_TRANSPORT_MEM_CHECK(TAG, cfg->path, { + free(cfg->uri); + free(cfg->host); + free(cfg->username); + free(cfg->password); + return ESP_ERR_NO_MEM; + }); + } + + cfg->network_timeout_ms = WEBSOCKET_NETWORK_TIMEOUT_MS; + cfg->user_context = config->user_context; + cfg->auto_reconnect = true; + if (config->disable_auto_reconnect) { + cfg->auto_reconnect = false; + } + + + return ESP_OK; +} + +static esp_err_t esp_websocket_client_destroy_config(esp_websocket_client_handle_t client) +{ + if (client == NULL) { + return ESP_ERR_INVALID_ARG; + } + websocket_config_storage_t *cfg = client->config; + if (client->config == NULL) { + return ESP_ERR_INVALID_ARG; + } + free(cfg->host); + free(cfg->uri); + free(cfg->path); + free(cfg->scheme); + free(cfg->username); + free(cfg->password); + memset(cfg, 0, sizeof(websocket_config_storage_t)); + free(client->config); + client->config = NULL; + return ESP_OK; +} + +esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_client_config_t *config) +{ + esp_websocket_client_handle_t client = calloc(1, sizeof(struct esp_websocket_client)); + ESP_TRANSPORT_MEM_CHECK(TAG, client, return NULL); + + esp_event_loop_args_t event_args = { + .queue_size = WEBSOCKET_EVENT_QUEUE_SIZE, + .task_name = NULL // no task will be created + }; + + if (esp_event_loop_create(&event_args, &client->event_handle) != ESP_OK) { + ESP_LOGE(TAG, "Error create event handler for websocket client"); + free(client); + return NULL; + } + + client->lock = xSemaphoreCreateMutex(); + ESP_TRANSPORT_MEM_CHECK(TAG, client->lock, goto _websocket_init_fail); + + client->transport_list = esp_transport_list_init(); + ESP_TRANSPORT_MEM_CHECK(TAG, client->transport_list, goto _websocket_init_fail); + + esp_transport_handle_t tcp = esp_transport_tcp_init(); + ESP_TRANSPORT_MEM_CHECK(TAG, tcp, goto _websocket_init_fail); + + esp_transport_set_default_port(tcp, WEBSOCKET_TCP_DEFAULT_PORT); + esp_transport_list_add(client->transport_list, tcp, "_tcp"); // need to save to transport list, for cleanup + + + esp_transport_handle_t ws = esp_transport_ws_init(tcp); + ESP_TRANSPORT_MEM_CHECK(TAG, ws, goto _websocket_init_fail); + + esp_transport_set_default_port(ws, WEBSOCKET_TCP_DEFAULT_PORT); + esp_transport_list_add(client->transport_list, ws, "ws"); + if (config->transport == WEBSOCKET_TRANSPORT_OVER_TCP) { + asprintf(&client->config->scheme, "ws"); + ESP_TRANSPORT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail); + } + + esp_transport_handle_t ssl = esp_transport_ssl_init(); + ESP_TRANSPORT_MEM_CHECK(TAG, ssl, goto _websocket_init_fail); + + esp_transport_set_default_port(ssl, WEBSOCKET_SSL_DEFAULT_PORT); + if (config->cert_pem) { + esp_transport_ssl_set_cert_data(ssl, config->cert_pem, strlen(config->cert_pem)); + } + esp_transport_list_add(client->transport_list, ssl, "_ssl"); // need to save to transport list, for cleanup + + esp_transport_handle_t wss = esp_transport_ws_init(ssl); + ESP_TRANSPORT_MEM_CHECK(TAG, wss, goto _websocket_init_fail); + + esp_transport_set_default_port(wss, WEBSOCKET_SSL_DEFAULT_PORT); + + esp_transport_list_add(client->transport_list, wss, "wss"); + if (config->transport == WEBSOCKET_TRANSPORT_OVER_TCP) { + asprintf(&client->config->scheme, "wss"); + ESP_TRANSPORT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail); + } + + client->config = calloc(1, sizeof(websocket_config_storage_t)); + ESP_TRANSPORT_MEM_CHECK(TAG, client->config, goto _websocket_init_fail); + + if (config->uri) { + if (esp_websocket_client_set_uri(client, config->uri) != ESP_OK) { + ESP_LOGE(TAG, "Invalid uri"); + goto _websocket_init_fail; + } + } + + if (esp_websocket_client_set_config(client, config) != ESP_OK) { + ESP_LOGE(TAG, "Failed to set the configuration"); + goto _websocket_init_fail; + } + + if (client->config->scheme == NULL) { + asprintf(&client->config->scheme, "ws"); + ESP_TRANSPORT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail); + } + + client->keepalive_tick_ms = _tick_get_ms(); + client->reconnect_tick_ms = _tick_get_ms(); + client->ping_tick_ms = _tick_get_ms(); + + int buffer_size = config->buffer_size; + if (buffer_size <= 0) { + buffer_size = WEBSOCKET_BUFFER_SIZE_BYTE; + } + client->rx_buffer = malloc(buffer_size); + ESP_TRANSPORT_MEM_CHECK(TAG, client->rx_buffer, { + goto _websocket_init_fail; + }); + client->tx_buffer = malloc(buffer_size); + ESP_TRANSPORT_MEM_CHECK(TAG, client->tx_buffer, { + goto _websocket_init_fail; + }); + client->status_bits = xEventGroupCreate(); + ESP_TRANSPORT_MEM_CHECK(TAG, client->status_bits, { + goto _websocket_init_fail; + }); + + client->buffer_size = buffer_size; + return client; + +_websocket_init_fail: + esp_websocket_client_destroy(client); + return NULL; +} + +esp_err_t esp_websocket_client_destroy(esp_websocket_client_handle_t client) +{ + if (client == NULL) { + return ESP_ERR_INVALID_ARG; + } + if (client->run) { + esp_websocket_client_stop(client); + } + if (client->event_handle) { + esp_event_loop_delete(client->event_handle); + } + esp_websocket_client_destroy_config(client); + esp_transport_list_destroy(client->transport_list); + vQueueDelete(client->lock); + free(client->tx_buffer); + free(client->rx_buffer); + if (client->status_bits) { + vEventGroupDelete(client->status_bits); + } + free(client); + client = NULL; + return ESP_OK; +} + +esp_err_t esp_websocket_client_set_uri(esp_websocket_client_handle_t client, const char *uri) +{ + if (client == NULL || uri == NULL) { + return ESP_ERR_INVALID_ARG; + } + struct http_parser_url puri; + http_parser_url_init(&puri); + int parser_status = http_parser_parse_url(uri, strlen(uri), 0, &puri); + if (parser_status != 0) { + ESP_LOGE(TAG, "Error parse uri = %s", uri); + return ESP_FAIL; + } + if (puri.field_data[UF_SCHEMA].len) { + free(client->config->scheme); + asprintf(&client->config->scheme, "%.*s", puri.field_data[UF_SCHEMA].len, uri + puri.field_data[UF_SCHEMA].off); + ESP_TRANSPORT_MEM_CHECK(TAG, client->config->scheme, return ESP_ERR_NO_MEM); + } + + if (puri.field_data[UF_HOST].len) { + free(client->config->host); + asprintf(&client->config->host, "%.*s", puri.field_data[UF_HOST].len, uri + puri.field_data[UF_HOST].off); + ESP_TRANSPORT_MEM_CHECK(TAG, client->config->host, return ESP_ERR_NO_MEM); + } + + + if (puri.field_data[UF_PATH].len) { + free(client->config->path); + asprintf(&client->config->path, "%.*s", puri.field_data[UF_PATH].len, uri + puri.field_data[UF_PATH].off); + ESP_TRANSPORT_MEM_CHECK(TAG, client->config->path, return ESP_ERR_NO_MEM); + + esp_transport_handle_t trans = esp_transport_list_get_transport(client->transport_list, "ws"); + if (trans) { + esp_transport_ws_set_path(trans, client->config->path); + } + trans = esp_transport_list_get_transport(client->transport_list, "wss"); + if (trans) { + esp_transport_ws_set_path(trans, client->config->path); + } + } + if (puri.field_data[UF_PORT].off) { + client->config->port = strtol((const char*)(uri + puri.field_data[UF_PORT].off), NULL, 10); + } + + if (puri.field_data[UF_USERINFO].len) { + char *user_info = NULL; + asprintf(&user_info, "%.*s", puri.field_data[UF_USERINFO].len, uri + puri.field_data[UF_USERINFO].off); + if (user_info) { + char *pass = strchr(user_info, ':'); + if (pass) { + pass[0] = 0; //terminal username + pass ++; + free(client->config->password); + client->config->password = strdup(pass); + ESP_TRANSPORT_MEM_CHECK(TAG, client->config->password, return ESP_ERR_NO_MEM); + } + free(client->config->username); + client->config->username = strdup(user_info); + ESP_TRANSPORT_MEM_CHECK(TAG, client->config->username, return ESP_ERR_NO_MEM); + free(user_info); + } else { + return ESP_ERR_NO_MEM; + } + } + return ESP_OK; +} + +static void esp_websocket_client_task(void *pv) +{ + int rlen; + esp_websocket_client_handle_t client = (esp_websocket_client_handle_t) pv; + client->run = true; + + //get transport by scheme + client->transport = esp_transport_list_get_transport(client->transport_list, client->config->scheme); + + if (client->transport == NULL) { + ESP_LOGE(TAG, "There are no transports valid, stop websocket client"); + client->run = false; + } + //default port + if (client->config->port == 0) { + client->config->port = esp_transport_get_default_port(client->transport); + } + + client->state = WEBSOCKET_STATE_INIT; + xEventGroupClearBits(client->status_bits, STOPPED_BIT); + int read_select; + while (client->run) { + switch ((int)client->state) { + case WEBSOCKET_STATE_INIT: + if (client->transport == NULL) { + ESP_LOGE(TAG, "There are no transport"); + client->run = false; + break; + } + + if (esp_transport_connect(client->transport, + client->config->host, + client->config->port, + client->config->network_timeout_ms) < 0) { + ESP_LOGE(TAG, "Error transport connect"); + esp_websocket_client_abort_connection(client); + break; + } + ESP_LOGD(TAG, "Transport connected to %s://%s:%d", client->config->scheme, client->config->host, client->config->port); + + client->state = WEBSOCKET_STATE_CONNECTED; + esp_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_CONNECTED, NULL, 0); + + break; + case WEBSOCKET_STATE_CONNECTED: + read_select = esp_transport_poll_read(client->transport, 1000); //Poll every 1000ms + if (read_select < 0) { + ESP_LOGE(TAG, "Network error, errorno"); + esp_websocket_client_abort_connection(client); + break; + } + if (_tick_get_ms() - client->ping_tick_ms > WEBSOCKET_PING_TIMEOUT_MS) { + client->ping_tick_ms = _tick_get_ms(); + // Send PING + esp_transport_write(client->transport, NULL, 0, client->config->network_timeout_ms); + } + if (read_select == 0) { + ESP_LOGD(TAG, "Timeout..."); + continue; + } + client->ping_tick_ms = _tick_get_ms(); + + rlen = esp_transport_read(client->transport, client->rx_buffer, client->buffer_size, client->config->network_timeout_ms); + if (rlen < 0) { + ESP_LOGE(TAG, "Error read data"); + esp_websocket_client_abort_connection(client); + break; + } + if (rlen > 0) { + esp_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_DATA, client->rx_buffer, rlen); + } + break; + case WEBSOCKET_STATE_WAIT_TIMEOUT: + + if (!client->config->auto_reconnect) { + client->run = false; + break; + } + if (_tick_get_ms() - client->reconnect_tick_ms > client->wait_timeout_ms) { + client->state = WEBSOCKET_STATE_INIT; + client->reconnect_tick_ms = _tick_get_ms(); + ESP_LOGD(TAG, "Reconnecting..."); + } + vTaskDelay(client->wait_timeout_ms / 2 / portTICK_RATE_MS); + break; + } + } + + esp_transport_close(client->transport); + xEventGroupSetBits(client->status_bits, STOPPED_BIT); + client->state = WEBSOCKET_STATE_UNKNOW; + vTaskDelete(NULL); +} + +esp_err_t esp_websocket_client_start(esp_websocket_client_handle_t client) +{ + if (client == NULL) { + return ESP_ERR_INVALID_ARG; + } + if (client->state >= WEBSOCKET_STATE_INIT) { + ESP_LOGE(TAG, "The client has started"); + return ESP_FAIL; + } + if (xTaskCreate(esp_websocket_client_task, "websocket_task", client->config->task_stack, client, client->config->task_prio, NULL) != pdTRUE) { + ESP_LOGE(TAG, "Error create websocket task"); + return ESP_FAIL; + } + xEventGroupClearBits(client->status_bits, STOPPED_BIT); + return ESP_OK; +} + +esp_err_t esp_websocket_client_stop(esp_websocket_client_handle_t client) +{ + if (client == NULL) { + return ESP_ERR_INVALID_ARG; + } + if (!client->run) { + ESP_LOGW(TAG, "Client was not started"); + return ESP_FAIL; + } + client->run = false; + xEventGroupWaitBits(client->status_bits, STOPPED_BIT, false, true, portMAX_DELAY); + client->state = WEBSOCKET_STATE_UNKNOW; + return ESP_OK; +} + +int esp_websocket_client_send(esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout) +{ + int need_write = len; + int wlen = 0, widx = 0; + + if (client == NULL || data == NULL || len <= 0) { + ESP_LOGE(TAG, "Invalid arguments"); + return ESP_FAIL; + } + + if (!esp_websocket_client_is_connected(client)) { + ESP_LOGE(TAG, "Websocket client is not connected"); + return ESP_FAIL; + } + + if (client->transport == NULL) { + ESP_LOGE(TAG, "Invalid transport"); + return ESP_FAIL; + } + + if (xSemaphoreTake(client->lock, timeout) != pdPASS) { + return ESP_FAIL; + } + + while (widx < len) { + if (need_write > client->buffer_size) { + need_write = client->buffer_size; + } + memcpy(client->tx_buffer, data + widx, need_write); + wlen = esp_transport_write(client->transport, + (char *)client->tx_buffer, + need_write, + client->config->network_timeout_ms); + if (wlen <= 0) { + xSemaphoreGive(client->lock); + return wlen; + } + widx += wlen; + need_write = len - widx; + } + xSemaphoreGive(client->lock); + return widx; +} + +bool esp_websocket_client_is_connected(esp_websocket_client_handle_t client) +{ + if (client == NULL) { + return false; + } + return client->state == WEBSOCKET_STATE_CONNECTED; +} + +esp_err_t esp_websocket_register_events(esp_websocket_client_handle_t client, + esp_websocket_event_id_t event, + esp_event_handler_t event_handler, + void* event_handler_arg) { + if (client == NULL) { + return ESP_ERR_INVALID_ARG; + } + return esp_event_handler_register_with(client->event_handle, WEBSOCKET_EVENTS, event, event_handler, event_handler_arg); +} diff --git a/components/esp_websocket_client/include/esp_websocket_client.h b/components/esp_websocket_client/include/esp_websocket_client.h new file mode 100644 index 0000000000..898fab5ae0 --- /dev/null +++ b/components/esp_websocket_client/include/esp_websocket_client.h @@ -0,0 +1,195 @@ +// Copyright 2015-2018 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. + +#ifndef _ESP_WEBSOCKET_CLIENT_H_ +#define _ESP_WEBSOCKET_CLIENT_H_ + + +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "esp_err.h" +#include "esp_event.h" +#include "esp_event_loop.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct esp_websocket_client* esp_websocket_client_handle_t; + +ESP_EVENT_DECLARE_BASE(WEBSOCKET_EVENTS); // declaration of the task events family + +/** + * @brief Websocket Client events id + */ +typedef enum { + WEBSOCKET_EVENT_ANY = -1, + WEBSOCKET_EVENT_ERROR = 0, /*!< This event occurs when there are any errors during execution */ + WEBSOCKET_EVENT_CONNECTED, /*!< Once the Websocket has been connected to the server, no data exchange has been performed */ + WEBSOCKET_EVENT_DISCONNECTED, /*!< The connection has been disconnected */ + WEBSOCKET_EVENT_DATA, /*!< When receiving data from the server, possibly multiple portions of the packet */ + WEBSOCKET_EVENT_MAX +} esp_websocket_event_id_t; + +/** + * @brief Websocket event data + */ +typedef struct { + const char *data_ptr; /*!< Data pointer */ + int data_len; /*!< Data length */ +} esp_websocket_event_data_t; + +/** + * @brief Websocket Client transport + */ +typedef enum { + WEBSOCKET_TRANSPORT_UNKNOWN = 0x0, /*!< Transport unknown */ + WEBSOCKET_TRANSPORT_OVER_TCP, /*!< Transport over tcp */ + WEBSOCKET_TRANSPORT_OVER_SSL, /*!< Transport over ssl */ +} esp_websocket_transport_t; + +/** + * @brief Websocket Client events data + */ +typedef struct { + esp_websocket_event_id_t event_id; /*!< event_id, to know the cause of the event */ + esp_websocket_client_handle_t client; /*!< esp_websocket_client_handle_t context */ + void *user_context;/*!< user_data context, from esp_websocket_client_config_t user_data */ + char *data; /*!< data of the event */ + int data_len; /*!< length of data */ +} esp_websocket_event_t; + +typedef esp_websocket_event_t* esp_websocket_event_handle_t; +typedef esp_err_t (* websocket_event_callback_t)(esp_websocket_event_handle_t event); + +/** + * @brief Websocket client setup configuration + */ +typedef struct { + const char *uri; /*!< Websocket URI, the information on the URI can be overrides the other fields below, if any */ + const char *host; /*!< Domain or IP as string */ + int port; /*!< Port to connect, default depend on esp_websocket_transport_t (80 or 443) */ + const char *username; /*!< Using for Http authentication - Not supported for now */ + const char *password; /*!< Using for Http authentication - Not supported for now */ + const char *path; /*!< HTTP Path, if not set, default is `/` */ + bool disable_auto_reconnect; /*!< Disable the automatic reconnect function when disconnected */ + void *user_context; /*!< HTTP user data context */ + int task_prio; /*!< Websocket task priority */ + int task_stack; /*!< Websocket task stack */ + int buffer_size; /*!< Websocket buffer size */ + const char *cert_pem; /*!< SSL Certification, PEM format as string, if the client requires to verify server */ + esp_websocket_transport_t transport; /*!< Websocket transport type, see `esp_websocket_transport_t */ +} esp_websocket_client_config_t; + +/** + * @brief Start a Websocket session + * This function must be the first function to call, + * and it returns a esp_websocket_client_handle_t that you must use as input to other functions in the interface. + * This call MUST have a corresponding call to esp_websocket_client_destroy when the operation is complete. + * + * @param[in] config The configuration + * + * @return + * - `esp_websocket_client_handle_t` + * - NULL if any errors + */ +esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_client_config_t *config); + +/** + * @brief Set URL for client, when performing this behavior, the options in the URL will replace the old ones + * Must stop the WebSocket client before set URI if the client has been connected + * + * @param[in] client The client + * @param[in] uri The uri + * + * @return esp_err_t + */ +esp_err_t esp_websocket_client_set_uri(esp_websocket_client_handle_t client, const char *uri); + +/** + * @brief Open the WebSocket connection + * + * @param[in] client The client + * + * @return esp_err_t + */ +esp_err_t esp_websocket_client_start(esp_websocket_client_handle_t client); + +/** + * @brief Close the WebSocket connection + * + * @param[in] client The client + * + * @return esp_err_t + */ +esp_err_t esp_websocket_client_stop(esp_websocket_client_handle_t client); + +/** + * @brief Destroy the WebSocket connection and free all resources. + * This function must be the last function to call for an session. + * It is the opposite of the esp_websocket_client_init function and must be called with the same handle as input that a esp_websocket_client_init call returned. + * This might close all connections this handle has used. + * + * @param[in] client The client + * + * @return esp_err_t + */ +esp_err_t esp_websocket_client_destroy(esp_websocket_client_handle_t client); + +/** + * @brief Write data to the WebSocket connection + * + * @param[in] client The client + * @param[in] data The data + * @param[in] len The length + * @param[in] timeout Write data timeout + * + * @return + * - Number of data was sent + * - (-1) if any errors + */ +int esp_websocket_client_send(esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout); + +/** + * @brief Check the WebSocket connection status + * + * @param[in] client The client handle + * + * @return + * - true + * - false + */ +bool esp_websocket_client_is_connected(esp_websocket_client_handle_t client); + +/** + * @brief Register the Websocket Events + * + * @param client The client handle + * @param event The event id + * @param event_handler The callback function + * @param event_handler_arg User context + * @return esp_err_t + */ +esp_err_t esp_websocket_register_events(esp_websocket_client_handle_t client, + esp_websocket_event_id_t event, + esp_event_handler_t event_handler, + void* event_handler_arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/mqtt/esp-mqtt b/components/mqtt/esp-mqtt index e205913b2c..11f884623b 160000 --- a/components/mqtt/esp-mqtt +++ b/components/mqtt/esp-mqtt @@ -1 +1 @@ -Subproject commit e205913b2cf3eff20b1f8ced7c76cf03533f130b +Subproject commit 11f884623bd32cb4269f24f47847f5d046da93f5 diff --git a/components/tcp_transport/include/esp_transport_ws.h b/components/tcp_transport/include/esp_transport_ws.h index 582c5c7da2..f47fd049cf 100644 --- a/components/tcp_transport/include/esp_transport_ws.h +++ b/components/tcp_transport/include/esp_transport_ws.h @@ -23,8 +23,25 @@ extern "C" { */ esp_transport_handle_t esp_transport_ws_init(esp_transport_handle_t parent_handle); +/** + * @brief Set HTTP path to update protocol to websocket + * + * @param t websocket transport handle + * @param path The HTTP Path + */ void esp_transport_ws_set_path(esp_transport_handle_t t, const char *path); +/** + * @brief Set websocket sub protocol header + * + * @param t websocket transport handle + * @param sub_protocol Sub protocol string + * + * @return + * - ESP_OK on success + * - One of the error codes + */ +esp_err_t esp_transport_ws_set_subprotocol(esp_transport_handle_t t, const char *sub_protocol); #ifdef __cplusplus diff --git a/components/tcp_transport/transport_ssl.c b/components/tcp_transport/transport_ssl.c index 1ea4049878..257a58cba6 100644 --- a/components/tcp_transport/transport_ssl.c +++ b/components/tcp_transport/transport_ssl.c @@ -112,6 +112,7 @@ static int ssl_write(esp_transport_handle_t t, const char *buffer, int len, int ret = esp_tls_conn_write(ssl->tls, (const unsigned char *) buffer, len); if (ret < 0) { ESP_LOGE(TAG, "esp_tls_conn_write error, errno=%s", strerror(errno)); + return -1; } return ret; } @@ -129,6 +130,7 @@ static int ssl_read(esp_transport_handle_t t, char *buffer, int len, int timeout ret = esp_tls_conn_read(ssl->tls, (unsigned char *)buffer, len); if (ret < 0) { ESP_LOGE(TAG, "esp_tls_conn_read error, errno=%s", strerror(errno)); + return -1; } if (ret == 0) { ret = -1; diff --git a/components/tcp_transport/transport_ws.c b/components/tcp_transport/transport_ws.c index 43f0bdd360..599457b895 100644 --- a/components/tcp_transport/transport_ws.c +++ b/components/tcp_transport/transport_ws.c @@ -25,12 +25,13 @@ static const char *TAG = "TRANSPORT_WS"; #define WS_MASK 0x80 #define WS_SIZE16 126 #define WS_SIZE64 127 -#define MAX_WEBSOCKET_HEADER_SIZE 10 +#define MAX_WEBSOCKET_HEADER_SIZE 16 #define WS_RESPONSE_OK 101 typedef struct { char *path; char *buffer; + char *sub_protocol; esp_transport_handle_t parent; } transport_ws_t; @@ -80,7 +81,7 @@ static int ws_connect(esp_transport_handle_t t, const char *host, int port, int { transport_ws_t *ws = esp_transport_get_context_data(t); if (esp_transport_connect(ws->parent, host, port, timeout_ms) < 0) { - ESP_LOGE(TAG, "Error connect to the server"); + ESP_LOGE(TAG, "Error connecting to host %s:%d", host, port); return -1; } @@ -98,12 +99,15 @@ static int ws_connect(esp_transport_handle_t t, const char *host, int port, int "Host: %s:%d\r\n" "Upgrade: websocket\r\n" "Sec-WebSocket-Version: 13\r\n" - "Sec-WebSocket-Protocol: mqtt\r\n" "Sec-WebSocket-Key: %s\r\n" - "User-Agent: ESP32 Websocket Client\r\n\r\n", + "User-Agent: ESP32 Websocket Client\r\n", ws->path, host, port, client_key); + if (ws->sub_protocol) { + len += snprintf(ws->buffer + len, DEFAULT_WS_BUFFER - len, "Sec-WebSocket-Protocol: %s\r\n", ws->sub_protocol); + } + len += snprintf(ws->buffer + len, DEFAULT_WS_BUFFER - len, "\r\n"); if (len <= 0 || len >= DEFAULT_WS_BUFFER) { ESP_LOGE(TAG, "Error in request generation, %d", len); return -1; @@ -152,42 +156,70 @@ static int ws_connect(esp_transport_handle_t t, const char *host, int port, int return 0; } -static int ws_write(esp_transport_handle_t t, const char *buff, int len, int timeout_ms) +static int _ws_write(esp_transport_handle_t t, int opcode, int mask_flag, const char *b, int len, int timeout_ms) { transport_ws_t *ws = esp_transport_get_context_data(t); + char *buffer = (char *)b; char ws_header[MAX_WEBSOCKET_HEADER_SIZE]; char *mask; int header_len = 0, i; - char *buffer = (char *)buff; + int poll_write; if ((poll_write = esp_transport_poll_write(ws->parent, timeout_ms)) <= 0) { + ESP_LOGE(TAG, "Error transport_poll_write"); return poll_write; } + ws_header[header_len++] = opcode; - ws_header[header_len++] = WS_OPCODE_BINARY | WS_FIN; - - // NOTE: no support for > 16-bit sized messages - if (len > 125) { - ws_header[header_len++] = WS_SIZE16 | WS_MASK; + if (len <= 125) { + ws_header[header_len++] = (uint8_t)(len | mask_flag); + } else if (len < 65536) { + ws_header[header_len++] = WS_SIZE16 | mask_flag; ws_header[header_len++] = (uint8_t)(len >> 8); ws_header[header_len++] = (uint8_t)(len & 0xFF); } else { - ws_header[header_len++] = (uint8_t)(len | WS_MASK); + ws_header[header_len++] = WS_SIZE64 | mask_flag; + /* Support maximum 4 bytes length */ + ws_header[header_len++] = 0; //(uint8_t)((len >> 56) & 0xFF); + ws_header[header_len++] = 0; //(uint8_t)((len >> 48) & 0xFF); + ws_header[header_len++] = 0; //(uint8_t)((len >> 40) & 0xFF); + ws_header[header_len++] = 0; //(uint8_t)((len >> 32) & 0xFF); + ws_header[header_len++] = (uint8_t)((len >> 24) & 0xFF); + ws_header[header_len++] = (uint8_t)((len >> 16) & 0xFF); + ws_header[header_len++] = (uint8_t)((len >> 8) & 0xFF); + ws_header[header_len++] = (uint8_t)((len >> 0) & 0xFF); } - mask = &ws_header[header_len]; - getrandom(ws_header + header_len, 4, 0); - header_len += 4; + if (len) { + if (mask_flag) { + mask = &ws_header[header_len]; + getrandom(ws_header + header_len, 4, 0); + header_len += 4; + + for (i = 0; i < len; ++i) { + buffer[i] = (buffer[i] ^ mask[i % 4]); + } + } - for (i = 0; i < len; ++i) { - buffer[i] = (buffer[i] ^ mask[i % 4]); } if (esp_transport_write(ws->parent, ws_header, header_len, timeout_ms) != header_len) { ESP_LOGE(TAG, "Error write header"); return -1; } + if (len == 0) { + return 0; + } return esp_transport_write(ws->parent, buffer, len, timeout_ms); } +static int ws_write(esp_transport_handle_t t, const char *b, int len, int timeout_ms) +{ + if (len == 0) { + ESP_LOGD(TAG, "Write PING message"); + return _ws_write(t, WS_OPCODE_PING | WS_FIN, 0, NULL, 0, timeout_ms); + } + return _ws_write(t, WS_OPCODE_BINARY | WS_FIN, WS_MASK, b, len, timeout_ms); +} + static int ws_read(esp_transport_handle_t t, char *buffer, int len, int timeout_ms) { transport_ws_t *ws = esp_transport_get_context_data(t); @@ -279,6 +311,7 @@ static esp_err_t ws_destroy(esp_transport_handle_t t) transport_ws_t *ws = esp_transport_get_context_data(t); free(ws->buffer); free(ws->path); + free(ws->sub_protocol); free(ws); return 0; } @@ -288,6 +321,7 @@ void esp_transport_ws_set_path(esp_transport_handle_t t, const char *path) ws->path = realloc(ws->path, strlen(path) + 1); strcpy(ws->path, path); } + esp_transport_handle_t esp_transport_ws_init(esp_transport_handle_t parent_handle) { esp_transport_handle_t t = esp_transport_init(); @@ -315,3 +349,22 @@ esp_transport_handle_t esp_transport_ws_init(esp_transport_handle_t parent_handl return t; } +esp_err_t esp_transport_ws_set_subprotocol(esp_transport_handle_t t, const char *sub_protocol) +{ + if (t == NULL) { + return ESP_ERR_INVALID_ARG; + } + transport_ws_t *ws = esp_transport_get_context_data(t); + if (ws->sub_protocol) { + free(ws->sub_protocol); + } + if (sub_protocol == NULL) { + ws->sub_protocol = NULL; + return ESP_OK; + } + ws->sub_protocol = strdup(sub_protocol); + if (ws->sub_protocol == NULL) { + return ESP_ERR_NO_MEM; + } + return ESP_OK; +} diff --git a/docs/Doxyfile b/docs/Doxyfile index 858a6a39e0..c678d93319 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -104,6 +104,7 @@ INPUT = \ ## mDNS ../../components/mdns/include/mdns.h \ ../../components/esp_http_client/include/esp_http_client.h \ + ../../components/esp_websocket_client/include/esp_websocket_client.h \ ../../components/esp_http_server/include/esp_http_server.h \ ../../components/esp_https_server/include/esp_https_server.h \ ## diff --git a/docs/en/api-reference/protocols/esp_websocket_client.rst b/docs/en/api-reference/protocols/esp_websocket_client.rst new file mode 100644 index 0000000000..cd4db2413b --- /dev/null +++ b/docs/en/api-reference/protocols/esp_websocket_client.rst @@ -0,0 +1,70 @@ +ESP WebSocket Client +==================== + +Overview +-------- +The ESP WebSocket client is an implementation of `WebSocket protocol client `_ for ESP32 + +Features +-------- + * supports WebSocket over TCP, SSL with mbedtls + * Easy to setup with URI + * Multiple instances (Multiple clients in one application) + +Configuration +------------- +URI +^^^ + +- Supports ``ws``, ``wss`` schemes +- WebSocket samples: + + - ``ws://websocket.org``: WebSocket over TCP, default port 80 + - ``wss://websocket.org``: WebSocket over SSL, default port 443 + +- Minimal configurations: + +.. code:: c + + const esp_websocket_client_config_t ws_cfg = { + .uri = "ws://websocket.org", + }; + +- If there are any options related to the URI in + ``esp_websocket_client_config_t``, the option defined by the URI will be + overridden. Sample: + +.. code:: c + + const esp_websocket_client_config_t ws_cfg = { + .uri = "ws://websocket.org:123", + .port = 4567, + }; + //WebSocket client will connect to websocket.org using port 4567 + +SSL +^^^ + +- Get certificate from server, example: ``websocket.org`` + ``openssl s_client -showcerts -connect websocket.org:443 /dev/null|openssl x509 -outform PEM >websocket_org.pem`` +- Configuration: + +.. code:: cpp + + const esp_websocket_client_config_t ws_cfg = { + .uri = "wss://websocket.org", + .cert_pem = (const char *)websocket_org_pem_start, + }; + +For more options on ``esp_websocket_client_config_t``, please refer to API reference below + +Application Example +------------------- +Simple WebSocket example that uses esp_websocket_client to establish a websocket connection and send/receive data with the `websocket.org `_ Server: :example:`protocols/websocket`. + + +API Reference +------------- + +.. include:: /_build/inc/esp_websocket_client.inc + diff --git a/docs/en/api-reference/protocols/index.rst b/docs/en/api-reference/protocols/index.rst index f8edf9e811..97386abe4c 100644 --- a/docs/en/api-reference/protocols/index.rst +++ b/docs/en/api-reference/protocols/index.rst @@ -8,6 +8,7 @@ Application Protocols mDNS ESP-TLS HTTP Client + Websocket Client HTTP Server HTTPS Server ASIO diff --git a/docs/zh_CN/api-reference/protocols/esp_websocket_client.rst b/docs/zh_CN/api-reference/protocols/esp_websocket_client.rst new file mode 100644 index 0000000000..c318562404 --- /dev/null +++ b/docs/zh_CN/api-reference/protocols/esp_websocket_client.rst @@ -0,0 +1 @@ +.. include:: ../../../en/api-reference/protocols/esp_websocket_client.rst diff --git a/docs/zh_CN/api-reference/protocols/index.rst b/docs/zh_CN/api-reference/protocols/index.rst index 63513cbee0..9d893c29b6 100644 --- a/docs/zh_CN/api-reference/protocols/index.rst +++ b/docs/zh_CN/api-reference/protocols/index.rst @@ -8,6 +8,7 @@ mDNS ESP-TLS HTTP Client + Websocket Client HTTP 服务器 HTTPS Server ASIO diff --git a/examples/protocols/websocket/CMakeLists.txt b/examples/protocols/websocket/CMakeLists.txt new file mode 100644 index 0000000000..f77ad23e52 --- /dev/null +++ b/examples/protocols/websocket/CMakeLists.txt @@ -0,0 +1,10 @@ +# The following four lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +# (Not part of the boilerplate) +# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(websocket-example) diff --git a/examples/protocols/websocket/Makefile b/examples/protocols/websocket/Makefile new file mode 100644 index 0000000000..3b37d32062 --- /dev/null +++ b/examples/protocols/websocket/Makefile @@ -0,0 +1,10 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# +PROJECT_NAME := websocket-example + +EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/protocols/websocket/README.md b/examples/protocols/websocket/README.md new file mode 100644 index 0000000000..2969444fdc --- /dev/null +++ b/examples/protocols/websocket/README.md @@ -0,0 +1 @@ +# Websocket Sample application diff --git a/examples/protocols/websocket/example_test.py b/examples/protocols/websocket/example_test.py new file mode 100644 index 0000000000..ef0c3b2f2b --- /dev/null +++ b/examples/protocols/websocket/example_test.py @@ -0,0 +1,41 @@ +import re +import os +import sys +import IDF + +# this is a test case write with tiny-test-fw. +# to run test cases outside tiny-test-fw, +# we need to set environment variable `TEST_FW_PATH`, +# then get and insert `TEST_FW_PATH` to sys path before import FW module +test_fw_path = os.getenv("TEST_FW_PATH") +if test_fw_path and test_fw_path not in sys.path: + sys.path.insert(0, test_fw_path) + + +@IDF.idf_example_test(env_tag="Example_WIFI", ignore=True) +def test_examples_protocol_websocket(env, extra_data): + """ + steps: | + 1. join AP + 2. connect to ws://echo.websocket.org + 3. send and receive data + """ + dut1 = env.get_dut("websocket", "examples/protocols/websocket") + # check and log bin size + binary_file = os.path.join(dut1.app.binary_path, "websocket-example.bin") + bin_size = os.path.getsize(binary_file) + IDF.log_performance("websocket_bin_size", "{}KB".format(bin_size // 1024)) + IDF.check_performance("websocket_bin_size", bin_size // 1024) + # start test + dut1.start_app() + dut1.expect("Waiting for wifi ...") + dut1.expect("Connection established...", timeout=30) + dut1.expect("WEBSOCKET_EVENT_CONNECTED") + for i in range(0, 10): + dut1.expect(re.compile(r"Sending hello (\d)")) + dut1.expect(re.compile(r"Received=hello (\d)")) + dut1.expect("Websocket Stopped") + + +if __name__ == '__main__': + test_examples_protocol_websocket() diff --git a/examples/protocols/websocket/main/CMakeLists.txt b/examples/protocols/websocket/main/CMakeLists.txt new file mode 100644 index 0000000000..caf642155c --- /dev/null +++ b/examples/protocols/websocket/main/CMakeLists.txt @@ -0,0 +1,4 @@ +set(COMPONENT_SRCS "websocket_example.c") +set(COMPONENT_ADD_INCLUDEDIRS ".") + +register_component() diff --git a/examples/protocols/websocket/main/Kconfig.projbuild b/examples/protocols/websocket/main/Kconfig.projbuild new file mode 100644 index 0000000000..6af61c8f94 --- /dev/null +++ b/examples/protocols/websocket/main/Kconfig.projbuild @@ -0,0 +1,9 @@ +menu "Example Configuration" + + config WEBSOCKET_URI + string "Websocket endpoint URI" + default "ws://echo.websocket.org"; + help + URL of websocket endpoint this example connects to and sends echo + +endmenu diff --git a/examples/protocols/websocket/main/component.mk b/examples/protocols/websocket/main/component.mk new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/protocols/websocket/main/websocket_example.c b/examples/protocols/websocket/main/websocket_example.c new file mode 100644 index 0000000000..120a5b4fdf --- /dev/null +++ b/examples/protocols/websocket/main/websocket_example.c @@ -0,0 +1,103 @@ +/* ESP HTTP Client Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + + +#include +#include "esp_wifi.h" +#include "esp_system.h" +#include "nvs_flash.h" +#include "esp_event_loop.h" +#include "protocol_examples_common.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" + + +#include "esp_log.h" +#include "esp_websocket_client.h" +#include "esp_event.h" +#include "esp_event_loop.h" + +static const char *TAG = "WEBSOCKET"; +static const char *WEBSOCKET_ECHO_ENDPOINT = CONFIG_WEBSOCKET_URI; + + +static void websocket_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) +{ + // esp_websocket_client_handle_t client = (esp_websocket_client_handle_t)handler_args; + esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data; + switch (event_id) { + case WEBSOCKET_EVENT_CONNECTED: + ESP_LOGI(TAG, "WEBSOCKET_EVENT_CONNECTED"); + + + break; + case WEBSOCKET_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "WEBSOCKET_EVENT_DISCONNECTED"); + break; + + case WEBSOCKET_EVENT_DATA: + ESP_LOGI(TAG, "WEBSOCKET_EVENT_DATA"); + ESP_LOGW(TAG, "Received=%.*s\r\n", data->data_len, (char*)data->data_ptr); + break; + case WEBSOCKET_EVENT_ERROR: + ESP_LOGI(TAG, "WEBSOCKET_EVENT_ERROR"); + break; + } +} + +static void websocket_app_start(void) +{ + ESP_LOGI(TAG, "Connectiong to %s...", WEBSOCKET_ECHO_ENDPOINT); + + const esp_websocket_client_config_t websocket_cfg = { + .uri = WEBSOCKET_ECHO_ENDPOINT, // or wss://echo.websocket.org for websocket secure + }; + + esp_websocket_client_handle_t client = esp_websocket_client_init(&websocket_cfg); + esp_websocket_register_events(client, WEBSOCKET_EVENT_ANY, websocket_event_handler, (void *)client); + + esp_websocket_client_start(client); + char data[32]; + int i = 0; + while (i < 10) { + if (esp_websocket_client_is_connected(client)) { + int len = sprintf(data, "hello %04d", i++); + ESP_LOGI(TAG, "Sending %s", data); + esp_websocket_client_send(client, data, len, portMAX_DELAY); + } + vTaskDelay(1000 / portTICK_RATE_MS); + } + esp_websocket_client_stop(client); + ESP_LOGI(TAG, "Websocket Stopped"); + esp_websocket_client_destroy(client); +} + +void app_main() +{ + ESP_LOGI(TAG, "[APP] Startup.."); + ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); + ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version()); + esp_log_level_set("*", ESP_LOG_INFO); + esp_log_level_set("WEBSOCKET_CLIENT", ESP_LOG_DEBUG); + esp_log_level_set("TRANS_TCP", ESP_LOG_DEBUG); + + ESP_ERROR_CHECK(nvs_flash_init()); + tcpip_adapter_init(); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. + * Read "Establishing Wi-Fi or Ethernet Connection" section in + * examples/protocols/README.md for more information about this function. + */ + ESP_ERROR_CHECK(example_connect()); + + websocket_app_start(); +} From 0150982ae392e7d12a2a066157602ada77f2f13a Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Tue, 18 Jun 2019 17:37:07 +0200 Subject: [PATCH 086/486] tools: Fix Kconfig checker for comments and source after help --- tools/check_kconfigs.py | 25 ++++++++++++++++++++++--- tools/test_check_kconfigs.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/tools/check_kconfigs.py b/tools/check_kconfigs.py index 23a46e149c..bdc3953e46 100755 --- a/tools/check_kconfigs.py +++ b/tools/check_kconfigs.py @@ -84,6 +84,23 @@ class BaseChecker(object): pass +class SourceChecker(BaseChecker): + # allow to source only files which will be also checked by the script + # Note: The rules are complex and the LineRuleChecker cannot be used + def process_line(self, line, line_number): + m = re.search(r'^\s*source(\s*)"([^"]+)"', line) + if m: + if len(m.group(1)) == 0: + raise InputError(self.path_in_idf, line_number, '"source" has to been followed by space', + line.replace('source', 'source ')) + path = m.group(2) + if path in ['$COMPONENT_KCONFIGS_PROJBUILD', '$COMPONENT_KCONFIGS']: + pass + elif not path.endswith('/Kconfig.in') and path != 'Kconfig.in': + raise InputError(self.path_in_idf, line_number, "only Kconfig.in can be sourced", + line.replace(path, os.path.join(os.path.dirname(path), 'Kconfig.in'))) + + class LineRuleChecker(BaseChecker): """ checks LINE_ERROR_RULES for each line @@ -134,6 +151,7 @@ class IndentAndNameChecker(BaseChecker): |(menuconfig) |(help) |(if) + |(source) ) ''', re.X) @@ -193,7 +211,7 @@ class IndentAndNameChecker(BaseChecker): print('level+', new_item, ': ', self.level_stack, end=' -> ') # "config" and "menuconfig" don't have a closing pair. So if new_item is an item which need to be indented # outside the last "config" or "menuconfig" then we need to find to a parent where it belongs - if new_item in ['config', 'menuconfig', 'menu', 'choice', 'if']: + if new_item in ['config', 'menuconfig', 'menu', 'choice', 'if', 'source']: # item is not belonging to a previous "config" or "menuconfig" so need to indent to parent for i, item in enumerate(reversed(self.level_stack)): if item in ['menu', 'mainmenu', 'choice', 'if']: @@ -328,7 +346,7 @@ class IndentAndNameChecker(BaseChecker): new_item = m.group(1) current_level = self.update_level_for_dec_pattern(new_item) if new_item not in ['endif']: - # endif doesn't require to check the prefix because the items in inside if/endif belong to the + # endif doesn't require to check the prefix because the items inside if/endif belong to the # same prefix level self.check_common_prefix(line, line_number) @@ -384,11 +402,12 @@ def main(): with open(full_path, 'r', encoding='utf-8') as f, \ open(suggestions_full_path, 'w', encoding='utf-8', newline='\n') as f_o, \ LineRuleChecker(path_in_idf) as line_checker, \ + SourceChecker(path_in_idf) as source_checker, \ IndentAndNameChecker(path_in_idf, debug=args.verbose) as indent_and_name_checker: try: for line_number, line in enumerate(f, start=1): try: - for checker in [line_checker, indent_and_name_checker]: + for checker in [line_checker, indent_and_name_checker, source_checker]: checker.process_line(line, line_number) # The line is correct therefore we echo it to the output file f_o.write(line) diff --git a/tools/test_check_kconfigs.py b/tools/test_check_kconfigs.py index 737ae46570..a38f16ab91 100755 --- a/tools/test_check_kconfigs.py +++ b/tools/test_check_kconfigs.py @@ -16,6 +16,7 @@ import unittest from check_kconfigs import LineRuleChecker +from check_kconfigs import SourceChecker from check_kconfigs import InputError from check_kconfigs import IndentAndNameChecker from check_kconfigs import CONFIG_NAME_MAX_LENGTH @@ -71,6 +72,23 @@ class TestLineRuleChecker(unittest.TestCase, ApplyLine): self.expect_error('test \\', expect=None) +class TestSourceChecker(unittest.TestCase, ApplyLine): + def setUp(self): + self.checker = SourceChecker('Kconfig') + + def tearDown(self): + pass + + def test_source_file_name(self): + self.expect_error('source "Kconfig.test"', expect='source "Kconfig.in"') + self.expect_error('source "/tmp/Kconfig.test"', expect='source "/tmp/Kconfig.in"') + self.expect_error('source "Kconfig"', expect='source "Kconfig.in"') + self.expt_success('source "Kconfig.in"') + self.expt_success('source "/tmp/Kconfig.in"') + self.expect_error('source"Kconfig.in"', expect='source "Kconfig.in"') + self.expt_success('source "/tmp/Kconfig.in" # comment') + + class TestIndentAndNameChecker(unittest.TestCase, ApplyLine): def setUp(self): self.checker = IndentAndNameChecker('Kconfig') @@ -156,6 +174,21 @@ class TestIndent(TestIndentAndNameChecker): self.expt_success('config') self.expt_success(' help') + def test_source_after_config(self): + self.expt_success('menuconfig') + self.expt_success(' help') + self.expt_success(' text') + self.expect_error(' source', expect='source') + self.expt_success('source "Kconfig.in"') + + def test_comment_after_config(self): + self.expt_success('menuconfig') + self.expt_success(' # comment') + self.expt_success(' help') + self.expt_success(' text') + self.expect_error('# comment', expect=' # comment') + self.expt_success(' # second not realcomment"') + class TestName(TestIndentAndNameChecker): def setUp(self): From bd9fed44008bcc3e5a40c0e72a047917eebee9ad Mon Sep 17 00:00:00 2001 From: baohongde Date: Tue, 6 Nov 2018 15:34:38 +0800 Subject: [PATCH 087/486] component/bt: reduce the size of DRAM DRAM.data: 506B --> 196B DRAM.bss : 26857B --> 2170B --- components/bt/bluedroid/api/esp_bt_main.c | 4 +- .../bt/bluedroid/api/esp_hf_client_api.c | 5 + components/bt/bluedroid/api/esp_spp_api.c | 6 +- .../api/include/api/esp_hf_client_api.h | 5 + components/bt/bluedroid/bta/av/bta_av_sbc.c | 23 +- .../bt/bluedroid/bta/av/include/bta_av_int.h | 22 + components/bt/bluedroid/bta/dm/bta_dm_act.c | 10 +- components/bt/bluedroid/bta/dm/bta_dm_cfg.c | 14 +- components/bt/bluedroid/bta/dm/bta_dm_pm.c | 6 +- components/bt/bluedroid/bta/dm/bta_dm_sco.c | 35 +- .../bt/bluedroid/bta/dm/include/bta_dm_int.h | 26 +- .../bt/bluedroid/bta/gatt/bta_gattc_act.c | 4 +- .../bt/bluedroid/bta/gatt/bta_gattc_cache.c | 3 + .../bt/bluedroid/bta/gatt/bta_gattc_co.c | 188 +++++---- .../bt/bluedroid/bta/gatt/bta_gatts_act.c | 4 +- .../bt/bluedroid/bta/gatt/bta_gatts_api.c | 10 +- .../bt/bluedroid/bta/include/bta/bta_api.h | 11 + .../bluedroid/bta/include/bta/bta_gatt_api.h | 13 +- .../bluedroid/bta/include/bta/bta_sdp_api.h | 13 + components/bt/bluedroid/bta/jv/bta_jv_api.c | 19 +- components/bt/bluedroid/bta/jv/bta_jv_cfg.c | 9 +- components/bt/bluedroid/bta/jv/bta_jv_main.c | 2 + components/bt/bluedroid/bta/sdp/bta_sdp_api.c | 32 ++ components/bt/bluedroid/bta/sdp/bta_sdp_cfg.c | 8 +- .../bt/bluedroid/btc/core/btc_ble_storage.c | 6 +- components/bt/bluedroid/btc/core/btc_dm.c | 141 ++++--- components/bt/bluedroid/btc/core/btc_manage.c | 6 +- components/bt/bluedroid/btc/core/btc_task.c | 104 ++++- .../bt/bluedroid/btc/include/btc/btc_dm.h | 14 + .../bt/bluedroid/btc/include/btc/btc_manage.h | 5 + .../btc/profile/esp/blufi/blufi_prf.c | 22 +- .../btc/profile/esp/blufi/blufi_protocol.c | 2 +- .../btc/profile/esp/blufi/include/blufi_int.h | 37 +- .../btc/profile/std/a2dp/bta_av_co.c | 58 +-- .../btc/profile/std/a2dp/btc_a2dp_sink.c | 171 ++++---- .../btc/profile/std/a2dp/btc_a2dp_source.c | 387 +++++++++--------- .../bluedroid/btc/profile/std/a2dp/btc_av.c | 50 ++- .../btc/profile/std/a2dp/include/btc_av_co.h | 56 +++ .../bluedroid/btc/profile/std/avrc/btc_avrc.c | 44 +- .../btc/profile/std/gap/btc_gap_ble.c | 6 + .../btc/profile/std/gatt/btc_gatt_util.c | 2 +- .../btc/profile/std/gatt/btc_gatts.c | 56 ++- .../btc/profile/std/hf_client/btc_hf_client.c | 210 +++++----- .../btc/profile/std/include/btc_avrc.h | 44 ++ .../btc/profile/std/include/btc_gap_ble.h | 8 + .../btc/profile/std/include/btc_gatts.h | 16 + .../btc/profile/std/include/btc_hf_client.h | 28 ++ .../bluedroid/btc/profile/std/spp/btc_spp.c | 25 +- .../common/include/common/bt_target.h | 6 - components/bt/bluedroid/device/controller.c | 377 ++++++++--------- .../external/sbc/encoder/srce/sbc_analysis.c | 21 + components/bt/bluedroid/main/bte_init.c | 32 +- components/bt/bluedroid/osi/alarm.c | 19 +- .../bluedroid/stack/btm/btm_ble_adv_filter.c | 51 ++- .../bluedroid/stack/btm/btm_ble_batchscan.c | 27 +- .../bt/bluedroid/stack/btm/btm_ble_gap.c | 26 +- .../bluedroid/stack/btm/btm_ble_multi_adv.c | 26 +- .../bt/bluedroid/stack/btm/btm_ble_privacy.c | 2 + components/bt/bluedroid/stack/gap/gap_api.c | 26 ++ components/bt/bluedroid/stack/gap/gap_ble.c | 2 +- .../bt/bluedroid/stack/gap/include/gap_int.h | 7 +- components/bt/bluedroid/stack/gatt/gatt_api.c | 4 +- .../bt/bluedroid/stack/gatt/gatt_attr.c | 6 +- components/bt/bluedroid/stack/gatt/gatt_cl.c | 4 +- .../bluedroid/stack/include/stack/dyn_mem.h | 40 +- .../bluedroid/stack/include/stack/gap_api.h | 12 + .../bluedroid/stack/include/stack/gatt_api.h | 4 +- .../bluedroid/stack/include/stack/port_api.h | 11 + .../bt/bluedroid/stack/l2cap/l2c_main.c | 3 +- .../bt/bluedroid/stack/rfcomm/port_api.c | 25 +- .../stack/smp/include/p_256_ecc_pp.h | 9 + .../bt/bluedroid/stack/smp/include/smp_int.h | 2 +- .../bt/bluedroid/stack/smp/p_256_ecc_pp.c | 10 +- components/bt/bluedroid/stack/smp/smp_act.c | 4 + components/bt/bluedroid/stack/smp/smp_api.c | 6 + components/bt/bluedroid/stack/smp/smp_cmac.c | 2 +- components/bt/bluedroid/stack/smp/smp_keys.c | 2 + components/bt/bluedroid/stack/smp/smp_utils.c | 5 +- 78 files changed, 1705 insertions(+), 1036 deletions(-) diff --git a/components/bt/bluedroid/api/esp_bt_main.c b/components/bt/bluedroid/api/esp_bt_main.c index 0b1bcc6ab0..8097956d10 100644 --- a/components/bt/bluedroid/api/esp_bt_main.c +++ b/components/bt/bluedroid/api/esp_bt_main.c @@ -132,6 +132,8 @@ esp_err_t esp_bluedroid_init(void) osi_mem_dbg_init(); #endif + btc_init(); + future_p = btc_main_get_future_p(BTC_MAIN_INIT_FUTURE); *future_p = future_new(); if (*future_p == NULL) { @@ -139,8 +141,6 @@ esp_err_t esp_bluedroid_init(void) return ESP_ERR_NO_MEM; } - btc_init(); - msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_MAIN_INIT; msg.act = BTC_MAIN_ACT_INIT; diff --git a/components/bt/bluedroid/api/esp_hf_client_api.c b/components/bt/bluedroid/api/esp_hf_client_api.c index fbc5d475cc..7db990206a 100644 --- a/components/bt/bluedroid/api/esp_hf_client_api.c +++ b/components/bt/bluedroid/api/esp_hf_client_api.c @@ -466,6 +466,11 @@ void esp_hf_client_pcm_resample_init(uint32_t src_sps, uint32_t bits, uint32_t c BTA_DmPcmInitSamples(src_sps, bits, channels); } +void esp_hf_client_pcm_resample_deinit(void) +{ + BTA_DmPcmDeinitSamples(); +} + int32_t esp_hf_client_pcm_resample(void *src, uint32_t in_bytes, void *dst) { return BTA_DmPcmResample(src, in_bytes, dst); diff --git a/components/bt/bluedroid/api/esp_spp_api.c b/components/bt/bluedroid/api/esp_spp_api.c index 46878d659e..57c2e317ae 100644 --- a/components/bt/bluedroid/api/esp_spp_api.c +++ b/components/bt/bluedroid/api/esp_spp_api.c @@ -23,9 +23,9 @@ #if (defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE) -static const uint8_t UUID_SPP[16] = {0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00, - 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB - }; +static const uint8_t UUID_SPP[16] = {0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB + }; static tSDP_UUID sdp_uuid; esp_err_t esp_spp_register_callback(esp_spp_cb_t *callback) { diff --git a/components/bt/bluedroid/api/include/api/esp_hf_client_api.h b/components/bt/bluedroid/api/include/api/esp_hf_client_api.h index dfc06ed5d1..8e3dc956b7 100644 --- a/components/bt/bluedroid/api/include/api/esp_hf_client_api.h +++ b/components/bt/bluedroid/api/include/api/esp_hf_client_api.h @@ -615,6 +615,11 @@ void esp_hf_client_outgoing_data_ready(void); */ void esp_hf_client_pcm_resample_init(uint32_t src_sps, uint32_t bits, uint32_t channels); +/** + * @brief Deinitialize the down sampling converter. + */ +void esp_hf_client_pcm_resample_deinit(void); + /** * @brief Down sampling utility to convert high sampling rate into 8K/16bits 1-channel mode PCM * samples. This can only be used in the case that Voice Over HCI is enabled. diff --git a/components/bt/bluedroid/bta/av/bta_av_sbc.c b/components/bt/bluedroid/bta/av/bta_av_sbc.c index 30f178efb3..4e034c4246 100644 --- a/components/bt/bluedroid/bta/av/bta_av_sbc.c +++ b/components/bt/bluedroid/bta/av/bta_av_sbc.c @@ -31,24 +31,13 @@ #include "common/bt_defs.h" #if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE) +#include "bta_av_int.h" -typedef int (tBTA_AV_SBC_ACT)(void *p_src, void *p_dst, - UINT32 src_samples, UINT32 dst_samples, - UINT32 *p_ret); - -typedef struct { - INT32 cur_pos; /* current position */ - UINT32 src_sps; /* samples per second (source audio data) */ - UINT32 dst_sps; /* samples per second (converted audio data) */ - tBTA_AV_SBC_ACT *p_act; /* the action function to do the conversion */ - UINT16 bits; /* number of bits per pcm sample */ - UINT16 n_channels; /* number of channels (i.e. mono(1), stereo(2)...) */ - INT16 worker1; - INT16 worker2; - UINT8 div; -} tBTA_AV_SBC_UPS_CB; - -tBTA_AV_SBC_UPS_CB bta_av_sbc_ups_cb; +#if BTA_DYNAMIC_MEMORY == FALSE +static tBTA_AV_SBC_UPS_CB bta_av_sbc_ups_cb; +#else +tBTA_AV_SBC_UPS_CB *bta_av_sbc_ups_cb_ptr; +#endif /******************************************************************************* ** diff --git a/components/bt/bluedroid/bta/av/include/bta_av_int.h b/components/bt/bluedroid/bta/av/include/bta_av_int.h index 16a70f3ef3..9fb6c06c52 100644 --- a/components/bt/bluedroid/bta/av/include/bta_av_int.h +++ b/components/bt/bluedroid/bta/av/include/bta_av_int.h @@ -531,11 +531,32 @@ typedef struct { UINT8 video_streams; /* handle mask of streaming video channels */ } tBTA_AV_CB; +/* type for dealing with SBC data frames and codec capabilities functions */ +typedef int (tBTA_AV_SBC_ACT)(void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret); +/* type for AV up sample control block */ +typedef struct { + INT32 cur_pos; /* current position */ + UINT32 src_sps; /* samples per second (source audio data) */ + UINT32 dst_sps; /* samples per second (converted audio data) */ + tBTA_AV_SBC_ACT *p_act; /* the action function to do the conversion */ + UINT16 bits; /* number of bits per pcm sample */ + UINT16 n_channels; /* number of channels (i.e. mono(1), stereo(2)...) */ + INT16 worker1; + INT16 worker2; + UINT8 div; +} tBTA_AV_SBC_UPS_CB; /***************************************************************************** ** Global data *****************************************************************************/ +/* control block declaration up sample */ +#if BTA_DYNAMIC_MEMORY == TRUE +extern tBTA_AV_SBC_UPS_CB *bta_av_sbc_ups_cb_ptr; +#define bta_av_sbc_ups_cb (*bta_av_sbc_ups_cb_ptr) +#endif /* control block declaration */ #if BTA_DYNAMIC_MEMORY == FALSE @@ -670,3 +691,4 @@ extern void bta_av_reg_vdp (tAVDT_CS *p_cs, char *p_service_name, void *p_data); #endif ///BTA_AV_INCLUDED == TRUE #endif /* BTA_AV_INT_H */ + diff --git a/components/bt/bluedroid/bta/dm/bta_dm_act.c b/components/bt/bluedroid/bta/dm/bta_dm_act.c index 49cce8749a..efb685ecd6 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_act.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_act.c @@ -233,10 +233,12 @@ const tBTM_APPL_INFO bta_security = { #endif ///SMP_INCLUDED == TRUE #if (SDP_INCLUDED == TRUE) -#define MAX_DISC_RAW_DATA_BUF (1024) +#if BTA_DYNAMIC_MEMORY == FALSE UINT8 g_disc_raw_data_buf[MAX_DISC_RAW_DATA_BUF]; +#else +UINT8 *g_disc_raw_data_buf; +#endif #endif ///SDP_INCLUDED == TRUE -extern DEV_CLASS local_device_default_class; /******************************************************************************* ** @@ -2303,7 +2305,7 @@ static void bta_dm_find_services ( BD_ADDR bd_addr) APPL_TRACE_DEBUG("%s search UUID = %04x", __func__, uuid.uu.uuid16); SDP_InitDiscoveryDb (bta_dm_search_cb.p_sdp_db, BTA_DM_SDP_DB_SIZE, 1, &uuid, 0, NULL); - memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf)); + memset(g_disc_raw_data_buf, 0, MAX_DISC_RAW_DATA_BUF); bta_dm_search_cb.p_sdp_db->raw_data = g_disc_raw_data_buf; bta_dm_search_cb.p_sdp_db->raw_size = MAX_DISC_RAW_DATA_BUF; @@ -2496,7 +2498,7 @@ static void bta_dm_discover_device(BD_ADDR remote_bd_addr) if (transport == BT_TRANSPORT_LE) { if (bta_dm_search_cb.services_to_search & BTA_BLE_SERVICE_MASK) { //set the raw data buffer here - memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf)); + memset(g_disc_raw_data_buf, 0, MAX_DISC_RAW_DATA_BUF); bta_dm_search_cb.p_ble_rawdata = g_disc_raw_data_buf; bta_dm_search_cb.ble_raw_size = MAX_DISC_RAW_DATA_BUF; diff --git a/components/bt/bluedroid/bta/dm/bta_dm_cfg.c b/components/bt/bluedroid/bta/dm/bta_dm_cfg.c index 14462e4409..9e018de98d 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_cfg.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_cfg.c @@ -112,9 +112,9 @@ const tBTA_DM_RM bta_dm_rm_cfg[] = { }; -tBTA_DM_CFG *p_bta_dm_cfg = (tBTA_DM_CFG *) &bta_dm_cfg; +tBTA_DM_CFG *const p_bta_dm_cfg = (tBTA_DM_CFG *) &bta_dm_cfg; -tBTA_DM_RM *p_bta_dm_rm_cfg = (tBTA_DM_RM *) &bta_dm_rm_cfg; +tBTA_DM_RM *const p_bta_dm_rm_cfg = (tBTA_DM_RM *) &bta_dm_rm_cfg; #if BLE_INCLUDED == TRUE # define BTA_DM_NUM_PM_ENTRY 8 /* number of entries in bta_dm_pm_cfg except the first */ @@ -375,12 +375,12 @@ tBTA_DM_SSR_SPEC bta_dm_ssr_spec[] = { {360, 160, 2} /* BTA_DM_PM_SSR3 - HD */ }; -tBTA_DM_SSR_SPEC *p_bta_dm_ssr_spec = (tBTA_DM_SSR_SPEC *) &bta_dm_ssr_spec; +tBTA_DM_SSR_SPEC *const p_bta_dm_ssr_spec = (tBTA_DM_SSR_SPEC *) &bta_dm_ssr_spec; #endif -tBTA_DM_PM_CFG *p_bta_dm_pm_cfg = (tBTA_DM_PM_CFG *) &bta_dm_pm_cfg; -tBTA_DM_PM_SPEC *p_bta_dm_pm_spec = (tBTA_DM_PM_SPEC *) &bta_dm_pm_spec; -tBTM_PM_PWR_MD *p_bta_dm_pm_md = (tBTM_PM_PWR_MD *) &bta_dm_pm_md; +tBTA_DM_PM_CFG *const p_bta_dm_pm_cfg = (tBTA_DM_PM_CFG *) &bta_dm_pm_cfg; +tBTA_DM_PM_SPEC *const p_bta_dm_pm_spec = (tBTA_DM_PM_SPEC *) &bta_dm_pm_spec; +tBTM_PM_PWR_MD *const p_bta_dm_pm_md = (tBTM_PM_PWR_MD *) &bta_dm_pm_md; #endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */ @@ -441,4 +441,4 @@ tBTA_DM_EIR_CONF bta_dm_eir_cfg = { NULL #endif /* #if (BTC_GAP_BT_INCLUDED == TRUE) */ }; -tBTA_DM_EIR_CONF *p_bta_dm_eir_cfg = (tBTA_DM_EIR_CONF *) &bta_dm_eir_cfg; +tBTA_DM_EIR_CONF *const p_bta_dm_eir_cfg = (tBTA_DM_EIR_CONF *) &bta_dm_eir_cfg; diff --git a/components/bt/bluedroid/bta/dm/bta_dm_pm.c b/components/bt/bluedroid/bta/dm/bta_dm_pm.c index cf55b1c341..5b0978bf59 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_pm.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_pm.c @@ -32,7 +32,11 @@ #include "stack/btm_api.h" #include "osi/allocator.h" -tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs; +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs; +#else +tBTA_DM_CONNECTED_SRVCS *bta_dm_conn_srvcs_ptr; +#endif #if (BTA_DM_PM_INCLUDED == TRUE) static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr); diff --git a/components/bt/bluedroid/bta/dm/bta_dm_sco.c b/components/bt/bluedroid/bta/dm/bta_dm_sco.c index 9acfa9544a..df91799a87 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_sco.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_sco.c @@ -28,6 +28,7 @@ #include #include "bta/bta_api.h" #include "bta/bta_sys.h" +#include "osi/allocator.h" #if (BTM_SCO_HCI_INCLUDED == TRUE) @@ -67,7 +68,7 @@ typedef struct { UINT32 divisor; } tBTA_DM_PCM_RESAMPLE_CB; -tBTA_DM_PCM_RESAMPLE_CB bta_dm_pcm_cb; +static tBTA_DM_PCM_RESAMPLE_CB* p_bta_dm_pcm_cb; /***************************************************************************** ** Macro Definition @@ -560,7 +561,11 @@ INT32 Convert_16S_ToBT_NoFilter (void *pSrc, void *pDst, UINT32 dwSrcSamples, UI *******************************************************************************/ void BTA_DmPcmInitSamples (UINT32 src_sps, UINT32 bits, UINT32 n_channels) { - tBTA_DM_PCM_RESAMPLE_CB *p_cb = &bta_dm_pcm_cb; + if ((p_bta_dm_pcm_cb = (tBTA_DM_PCM_RESAMPLE_CB *)osi_malloc(sizeof(tBTA_DM_PCM_RESAMPLE_CB))) == NULL) { + APPL_TRACE_ERROR("%s malloc failed!", __func__); + return; + } + tBTA_DM_PCM_RESAMPLE_CB *p_cb = p_bta_dm_pcm_cb; p_cb->cur_pos = src_sps / 2; p_cb->src_sps = src_sps; @@ -615,6 +620,20 @@ void BTA_DmPcmInitSamples (UINT32 src_sps, UINT32 bits, UINT32 n_channels) } +/******************************************************************************* +** +** Function BTA_DmPcmDeinitSamples +** +** Description Deinitialize the down sample converter. +** +** Returns none +** +*******************************************************************************/ +void BTA_DmPcmDeinitSamples(void) { + osi_free(p_bta_dm_pcm_cb); + p_bta_dm_pcm_cb = NULL; +} + /************************************************************************************** ** Function BTA_DmPcmResample ** @@ -636,14 +655,14 @@ INT32 BTA_DmPcmResample (void *p_src, UINT32 in_bytes, void *p_dst) UINT32 out_sample; #if BTA_DM_SCO_DEBUG - APPL_TRACE_DEBUG("bta_pcm_resample : insamples %d", (in_bytes / bta_dm_pcm_cb.divisor)); + APPL_TRACE_DEBUG("bta_pcm_resample : insamples %d", (in_bytes / p_bta_dm_pcm_cb->divisor)); #endif - if (bta_dm_pcm_cb.can_be_filtered) { - out_sample = (*bta_dm_pcm_cb.filter) (p_src, p_dst, (in_bytes / bta_dm_pcm_cb.divisor), - bta_dm_pcm_cb.src_sps, (INT32 *) &bta_dm_pcm_cb.cur_pos, bta_dm_pcm_cb.overlap_area); + if (p_bta_dm_pcm_cb->can_be_filtered) { + out_sample = (*p_bta_dm_pcm_cb->filter) (p_src, p_dst, (in_bytes / p_bta_dm_pcm_cb->divisor), + p_bta_dm_pcm_cb->src_sps, (INT32 *) &(p_bta_dm_pcm_cb->cur_pos), p_bta_dm_pcm_cb->overlap_area); } else { - out_sample = (*bta_dm_pcm_cb.nofilter) (p_src, p_dst, - (in_bytes / bta_dm_pcm_cb.divisor), bta_dm_pcm_cb.src_sps); + out_sample = (*p_bta_dm_pcm_cb->nofilter) (p_src, p_dst, + (in_bytes / p_bta_dm_pcm_cb->divisor), p_bta_dm_pcm_cb->src_sps); } #if BTA_DM_SCO_DEBUG diff --git a/components/bt/bluedroid/bta/dm/include/bta_dm_int.h b/components/bt/bluedroid/bta/dm/include/bta_dm_int.h index 2c21b0c574..83fdb3bab7 100644 --- a/components/bt/bluedroid/bta/dm/include/bta_dm_int.h +++ b/components/bt/bluedroid/bta/dm/include/bta_dm_int.h @@ -976,7 +976,6 @@ typedef struct { } tBTA_DM_CONNECTED_SRVCS; -extern tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs; #if (BTA_DM_PM_INCLUDED == TRUE) @@ -1150,8 +1149,8 @@ typedef struct { } tBTA_DM_RM ; -extern tBTA_DM_CFG *p_bta_dm_cfg; -extern tBTA_DM_RM *p_bta_dm_rm_cfg; +extern tBTA_DM_CFG *const p_bta_dm_cfg; +extern tBTA_DM_RM *const p_bta_dm_rm_cfg; typedef struct { @@ -1192,11 +1191,11 @@ typedef struct { } tBTA_DM_LMP_VER_INFO; #if (BTA_DM_PM_INCLUDED == TRUE) -extern tBTA_DM_PM_CFG *p_bta_dm_pm_cfg; -extern tBTA_DM_PM_SPEC *p_bta_dm_pm_spec; -extern tBTM_PM_PWR_MD *p_bta_dm_pm_md; +extern tBTA_DM_PM_CFG *const p_bta_dm_pm_cfg; +extern tBTA_DM_PM_SPEC *const p_bta_dm_pm_spec; +extern tBTM_PM_PWR_MD *const p_bta_dm_pm_md; #if (BTM_SSR_INCLUDED == TRUE) -extern tBTA_DM_SSR_SPEC *p_bta_dm_ssr_spec; +extern tBTA_DM_SSR_SPEC *const p_bta_dm_ssr_spec; #endif #endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */ @@ -1228,6 +1227,19 @@ extern tBTA_DM_DI_CB *bta_dm_di_cb_ptr; #define bta_dm_di_cb (*bta_dm_di_cb_ptr) #endif +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs; +#else +extern tBTA_DM_CONNECTED_SRVCS *bta_dm_conn_srvcs_ptr; +#define bta_dm_conn_srvcs (*bta_dm_conn_srvcs_ptr) +#endif + +/* Discovery raw data buffer */ +#define MAX_DISC_RAW_DATA_BUF (1024) +#if BTA_DYNAMIC_MEMORY == TRUE +extern UINT8 *g_disc_raw_data_buf; +#endif + extern BOOLEAN bta_dm_sm_execute(BT_HDR *p_msg); extern void bta_dm_sm_disable( void ); extern void bta_dm_sm_deinit(void); diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_act.c b/components/bt/bluedroid/bta/gatt/bta_gattc_act.c index e6df3e5189..9f8f2b5198 100644 --- a/components/bt/bluedroid/bta/gatt/bta_gattc_act.c +++ b/components/bt/bluedroid/bta/gatt/bta_gattc_act.c @@ -68,7 +68,7 @@ static void bta_gattc_cong_cback (UINT16 conn_id, BOOLEAN congested); static void bta_gattc_req_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE type, tGATTS_DATA *p_data); static tBTA_GATTC_FIND_SERVICE_CB bta_gattc_register_service_change_notify(UINT16 conn_id, BD_ADDR remote_bda); -static tGATT_CBACK bta_gattc_cl_cback = { +static const tGATT_CBACK bta_gattc_cl_cback = { bta_gattc_conn_cback, bta_gattc_cmpl_cback, bta_gattc_disc_res_cback, @@ -79,7 +79,7 @@ static tGATT_CBACK bta_gattc_cl_cback = { }; /* opcode(tGATTC_OPTYPE) order has to be comply with internal event order */ -static UINT16 bta_gattc_opcode_to_int_evt[] = { +static const UINT16 bta_gattc_opcode_to_int_evt[] = { BTA_GATTC_API_READ_EVT, BTA_GATTC_API_WRITE_EVT, BTA_GATTC_API_EXEC_EVT, diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_cache.c b/components/bt/bluedroid/bta/gatt/bta_gattc_cache.c index 355d619a09..1da1000ae7 100644 --- a/components/bt/bluedroid/bta/gatt/bta_gattc_cache.c +++ b/components/bt/bluedroid/bta/gatt/bta_gattc_cache.c @@ -26,6 +26,7 @@ #include "common/bt_target.h" #if defined(GATTC_INCLUDED) && (GATTC_INCLUDED == TRUE) +//#if( defined GATTC_CACHE_NVS ) && (GATTC_CACHE_NVS == TRUE) #include #include "bta/utl.h" @@ -2190,5 +2191,7 @@ void bta_gattc_cache_reset(BD_ADDR server_bda) bta_gattc_co_cache_reset(server_bda); //unlink(fname); } + +//#endif /* GATTC_CACHE_NVS */ #endif /* BTA_GATT_INCLUDED */ diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_co.c b/components/bt/bluedroid/bta/gatt/bta_gattc_co.c index c11fb95895..98444458ae 100644 --- a/components/bt/bluedroid/bta/gatt/bta_gattc_co.c +++ b/components/bt/bluedroid/bta/gatt/bta_gattc_co.c @@ -33,6 +33,7 @@ #if( defined BLE_INCLUDED ) && (BLE_INCLUDED == TRUE) #if( defined BTA_GATT_INCLUDED ) && (GATTC_INCLUDED == TRUE) +// #if( defined GATTC_CACHE_NVS ) && (GATTC_CACHE_NVS == TRUE) #define GATT_CACHE_PREFIX "gatt_" #define INVALID_ADDR_NUM 0xff @@ -77,7 +78,6 @@ static void cacheReset(BD_ADDR bda) static const char *cache_key = "gattc_cache_key"; static const char *cache_addr = "cache_addr_tab"; -nvs_handle_t nvs_fp; typedef struct { //save the service data in the list according to the address @@ -96,7 +96,7 @@ typedef struct { cache_addr_info_t cache_addr[MAX_DEVICE_IN_CACHE]; }cache_env_t; -cache_env_t cache_env; +cache_env_t *cache_env = NULL; static void getFilename(char *buffer, hash_key_t hash) { @@ -108,9 +108,9 @@ static void cacheClose(BD_ADDR bda) { UINT8 index = 0; if ((index = bta_gattc_co_find_addr_in_cache(bda)) != INVALID_ADDR_NUM) { - if (cache_env.cache_addr[index].is_open) { - nvs_close(cache_env.cache_addr[index].cache_fp); - cache_env.cache_addr[index].is_open = FALSE; + if (cache_env->cache_addr[index].is_open) { + nvs_close(cache_env->cache_addr[index].cache_fp); + cache_env->cache_addr[index].is_open = FALSE; } } } @@ -124,18 +124,18 @@ static bool cacheOpen(BD_ADDR bda, bool to_save, UINT8 *index) hash_key_t hash_key = {0}; if (((*index = bta_gattc_co_find_addr_in_cache(bda)) != INVALID_ADDR_NUM) || ((assoc_addr = bta_gattc_co_cache_find_src_addr(bda, index)) != NULL)) { - if (cache_env.cache_addr[*index].is_open) { + if (cache_env->cache_addr[*index].is_open) { return TRUE; } else { - memcpy(hash_key, cache_env.cache_addr[*index].hash_key, sizeof(hash_key_t)); + memcpy(hash_key, cache_env->cache_addr[*index].hash_key, sizeof(hash_key_t)); getFilename(fname, hash_key); - if ((status = nvs_open(fname, NVS_READWRITE, &cache_env.cache_addr[*index].cache_fp)) == ESP_OK) { + if ((status = nvs_open(fname, NVS_READWRITE, &cache_env->cache_addr[*index].cache_fp)) == ESP_OK) { // Set the open flag to TRUE when success to open the hash file. - cache_env.cache_addr[*index].is_open = TRUE; + cache_env->cache_addr[*index].is_open = TRUE; } } } - + return ((status == ESP_OK) ? true : false); } @@ -144,67 +144,67 @@ static void cacheReset(BD_ADDR bda) char fname[255] = {0}; getFilename(fname, bda); UINT8 index = 0; - //cache_env.cache_addr + //cache_env->cache_addr if ((index = bta_gattc_co_find_addr_in_cache(bda)) != INVALID_ADDR_NUM) { //clear the association address pending in the source address. bta_gattc_co_cache_clear_assoc_addr(bda); - if (cache_env.cache_addr[index].is_open) { - nvs_erase_all(cache_env.cache_addr[index].cache_fp); - nvs_close(cache_env.cache_addr[index].cache_fp); - cache_env.cache_addr[index].is_open = FALSE; + if (cache_env->cache_addr[index].is_open) { + nvs_erase_all(cache_env->cache_addr[index].cache_fp); + nvs_close(cache_env->cache_addr[index].cache_fp); + cache_env->cache_addr[index].is_open = FALSE; } else { cacheOpen(bda, false, &index); - if (cache_env.cache_addr[index].is_open) { - nvs_erase_all(cache_env.cache_addr[index].cache_fp); - nvs_close(cache_env.cache_addr[index].cache_fp); - cache_env.cache_addr[index].is_open = FALSE; + if (cache_env->cache_addr[index].is_open) { + nvs_erase_all(cache_env->cache_addr[index].cache_fp); + nvs_close(cache_env->cache_addr[index].cache_fp); + cache_env->cache_addr[index].is_open = FALSE; } else { APPL_TRACE_ERROR("%s cacheOpen failed", __func__); return; } } - if(cache_env.num_addr == 0) { + if(cache_env->num_addr == 0) { APPL_TRACE_ERROR("%s cache addr list error", __func__); return; } - UINT8 num = cache_env.num_addr; + UINT8 num = cache_env->num_addr; //delete the server_bda in the addr_info list. for(UINT8 i = index; i < (num - 1); i++) { - memcpy(&cache_env.cache_addr[i], &cache_env.cache_addr[i+1], sizeof(cache_addr_info_t)); + memcpy(&cache_env->cache_addr[i], &cache_env->cache_addr[i+1], sizeof(cache_addr_info_t)); } //reduced the number address counter also - cache_env.num_addr--; + cache_env->num_addr--; //update addr list to nvs flash - if(cache_env.num_addr > 0) { + if(cache_env->num_addr > 0) { //update UINT8 *p_buf = osi_malloc(MAX_ADDR_LIST_CACHE_BUF); if(!p_buf) { - APPL_TRACE_ERROR("%s malloc error", __func__); - return; + APPL_TRACE_ERROR("%s malloc error", __func__); + return; } - UINT16 length = cache_env.num_addr*(sizeof(BD_ADDR) + sizeof(hash_key_t)); - for (UINT8 i = 0; i < cache_env.num_addr; i++) { + UINT16 length = cache_env->num_addr*(sizeof(BD_ADDR) + sizeof(hash_key_t)); + for (UINT8 i = 0; i < cache_env->num_addr; i++) { //copy the address to the buffer. - memcpy(p_buf + i*(sizeof(BD_ADDR) + sizeof(hash_key_t)), cache_env.cache_addr[i].addr, sizeof(BD_ADDR)); + memcpy(p_buf + i*(sizeof(BD_ADDR) + sizeof(hash_key_t)), cache_env->cache_addr[i].addr, sizeof(BD_ADDR)); //copy the hash key to the buffer. memcpy(p_buf + i*(sizeof(BD_ADDR) + sizeof(hash_key_t)) + sizeof(BD_ADDR), - cache_env.cache_addr[i].hash_key, sizeof(hash_key_t)); + cache_env->cache_addr[i].hash_key, sizeof(hash_key_t)); } - if (cache_env.is_open) { - if (nvs_set_blob(cache_env.addr_fp, cache_key, p_buf, length) != ESP_OK) { + if (cache_env->is_open) { + if (nvs_set_blob(cache_env->addr_fp, cache_key, p_buf, length) != ESP_OK) { APPL_TRACE_WARNING("%s, nvs set blob failed", __func__); } } osi_free(p_buf); - + } else { //erase - if (cache_env.is_open) { - nvs_erase_all(cache_env.addr_fp); - nvs_close(cache_env.addr_fp); - cache_env.is_open = FALSE; + if (cache_env->is_open) { + nvs_erase_all(cache_env->addr_fp); + nvs_close(cache_env->addr_fp); + cache_env->is_open = FALSE; } else { APPL_TRACE_WARNING("cache_env status is error"); } @@ -267,10 +267,10 @@ tBTA_GATT_STATUS bta_gattc_co_cache_load(tBTA_GATTC_NV_ATTR *attr, UINT8 index) tBTA_GATT_STATUS status = BTA_GATT_ERROR; size_t length = 0; // Read the size of memory space required for blob - nvs_get_blob(cache_env.cache_addr[index].cache_fp, cache_key, NULL, &length); + nvs_get_blob(cache_env->cache_addr[index].cache_fp, cache_key, NULL, &length); // Read previously saved blob if available - esp_err_t err_code = nvs_get_blob(cache_env.cache_addr[index].cache_fp, cache_key, attr, &length); #if (!CONFIG_BT_STACK_NO_LOG) + esp_err_t err_code = nvs_get_blob(cache_env->cache_addr[index].cache_fp, cache_key, attr, &length); num_attr = length / sizeof(tBTA_GATTC_NV_ATTR); #endif status = (err_code == ESP_OK && length != 0) ? BTA_GATT_OK : BTA_GATT_ERROR; @@ -288,7 +288,7 @@ size_t bta_gattc_get_cache_attr_length(UINT8 index) } // Read the size of memory space required for blob - nvs_get_blob(cache_env.cache_addr[index].cache_fp, cache_key, NULL, &length); + nvs_get_blob(cache_env->cache_addr[index].cache_fp, cache_key, NULL, &length); return length; } @@ -320,7 +320,7 @@ void bta_gattc_co_cache_save (BD_ADDR server_bda, UINT16 num_attr, bta_gattc_co_cache_addr_save(server_bda, hash_key); if (cacheOpen(server_bda, TRUE, &index)) { - esp_err_t err_code = nvs_set_blob(cache_env.cache_addr[index].cache_fp, cache_key, + esp_err_t err_code = nvs_set_blob(cache_env->cache_addr[index].cache_fp, cache_key, p_attr_list, sizeof(tBTA_GATTC_NV_ATTR)*num_attr); status = (err_code == ESP_OK) ? BTA_GATT_OK : BTA_GATT_ERROR; } else { @@ -380,12 +380,18 @@ void bta_gattc_co_cache_addr_init(void) nvs_handle_t fp; esp_err_t err_code; UINT8 num_addr; - UINT8 *p_buf = osi_malloc(MAX_ADDR_LIST_CACHE_BUF); size_t length = MAX_ADDR_LIST_CACHE_BUF; + UINT8 *p_buf = osi_malloc(MAX_ADDR_LIST_CACHE_BUF); + + cache_env = (cache_env_t *)osi_malloc(sizeof(cache_env_t)); + if (cache_env == NULL || p_buf == NULL) { + APPL_TRACE_ERROR("%s malloc failed!", __func__); + return; + } if ((err_code = nvs_open(cache_addr, NVS_READWRITE, &fp)) == ESP_OK) { - cache_env.addr_fp = fp; - cache_env.is_open = TRUE; + cache_env->addr_fp = fp; + cache_env->is_open = TRUE; // Read previously saved blob if available if ((err_code = nvs_get_blob(fp, cache_key, p_buf, &length)) != ESP_OK) { if(err_code != ESP_ERR_NVS_NOT_FOUND) { @@ -395,18 +401,18 @@ void bta_gattc_co_cache_addr_init(void) return; } num_addr = length / (sizeof(BD_ADDR) + sizeof(hash_key_t)); - cache_env.num_addr = num_addr; + cache_env->num_addr = num_addr; //read the address from nvs flash to cache address list. for (UINT8 i = 0; i < num_addr; i++) { - memcpy(cache_env.cache_addr[i].addr, p_buf + i*(sizeof(BD_ADDR) + sizeof(hash_key_t)), sizeof(BD_ADDR)); - memcpy(cache_env.cache_addr[i].hash_key, + memcpy(cache_env->cache_addr[i].addr, p_buf + i*(sizeof(BD_ADDR) + sizeof(hash_key_t)), sizeof(BD_ADDR)); + memcpy(cache_env->cache_addr[i].hash_key, p_buf + i*(sizeof(BD_ADDR) + sizeof(hash_key_t)) + sizeof(BD_ADDR), sizeof(hash_key_t)); - APPL_TRACE_DEBUG("cache_addr[%x] = %x:%x:%x:%x:%x:%x", i, cache_env.cache_addr[i].addr[0], cache_env.cache_addr[i].addr[1], cache_env.cache_addr[i].addr[2], - cache_env.cache_addr[i].addr[3], cache_env.cache_addr[i].addr[4], cache_env.cache_addr[i].addr[5]); - APPL_TRACE_DEBUG("hash_key[%x] = %x%x%x%x", i, cache_env.cache_addr[i].hash_key[0], cache_env.cache_addr[i].hash_key[1], - cache_env.cache_addr[i].hash_key[2], cache_env.cache_addr[i].hash_key[3]); - bta_gattc_co_cache_new_assoc_list(cache_env.cache_addr[i].addr, i); + APPL_TRACE_DEBUG("cache_addr[%x] = %x:%x:%x:%x:%x:%x", i, cache_env->cache_addr[i].addr[0], cache_env->cache_addr[i].addr[1], cache_env->cache_addr[i].addr[2], + cache_env->cache_addr[i].addr[3], cache_env->cache_addr[i].addr[4], cache_env->cache_addr[i].addr[5]); + APPL_TRACE_DEBUG("hash_key[%x] = %x%x%x%x", i, cache_env->cache_addr[i].hash_key[0], cache_env->cache_addr[i].hash_key[1], + cache_env->cache_addr[i].hash_key[2], cache_env->cache_addr[i].hash_key[3]); + bta_gattc_co_cache_new_assoc_list(cache_env->cache_addr[i].addr, i); } } else { APPL_TRACE_ERROR("%s, Line = %d, nvs flash open fail, err_code = %x", __func__, __LINE__, err_code); @@ -420,14 +426,14 @@ void bta_gattc_co_cache_addr_init(void) void bta_gattc_co_cache_addr_deinit(void) { - if(!cache_env.is_open) { + if(!cache_env->is_open) { return; - } - nvs_close(cache_env.addr_fp); - cache_env.is_open = false; - - for(UINT8 i = 0; i< cache_env.num_addr; i++) { - cache_addr_info_t *addr_info = &cache_env.cache_addr[i]; + } + nvs_close(cache_env->addr_fp); + cache_env->is_open = false; + + for(UINT8 i = 0; i< cache_env->num_addr; i++) { + cache_addr_info_t *addr_info = &cache_env->cache_addr[i]; if(addr_info) { nvs_close(addr_info->cache_fp); addr_info->is_open = false; @@ -436,13 +442,16 @@ void bta_gattc_co_cache_addr_deinit(void) } } } + + osi_free(cache_env); + cache_env = NULL; } BOOLEAN bta_gattc_co_addr_in_cache(BD_ADDR bda) { UINT8 addr_index = 0; - UINT8 num = cache_env.num_addr; - cache_addr_info_t *addr_info = &cache_env.cache_addr[0]; + UINT8 num = cache_env->num_addr; + cache_addr_info_t *addr_info = &cache_env->cache_addr[0]; for (addr_index = 0; addr_index < num; addr_index++) { if (!memcmp(addr_info->addr, bda, sizeof(BD_ADDR))) { return TRUE; @@ -455,8 +464,8 @@ BOOLEAN bta_gattc_co_addr_in_cache(BD_ADDR bda) UINT8 bta_gattc_co_find_addr_in_cache(BD_ADDR bda) { UINT8 addr_index = 0; - UINT8 num = cache_env.num_addr; - cache_addr_info_t *addr_info = &cache_env.cache_addr[0]; + UINT8 num = cache_env->num_addr; + cache_addr_info_t *addr_info = &cache_env->cache_addr[0]; for (addr_index = 0; addr_index < num; addr_index++, addr_info++) { if (!memcmp(addr_info->addr, bda, sizeof(BD_ADDR))) { @@ -470,8 +479,8 @@ UINT8 bta_gattc_co_find_addr_in_cache(BD_ADDR bda) UINT8 bta_gattc_co_find_hash_in_cache(hash_key_t hash_key) { UINT8 index = 0; - UINT8 num = cache_env.num_addr; - cache_addr_info_t *addr_info = &cache_env.cache_addr[0]; + UINT8 num = cache_env->num_addr; + cache_addr_info_t *addr_info = &cache_env->cache_addr[0]; for (index = 0; index < num; index++) { if (!memcmp(addr_info->hash_key, hash_key, sizeof(hash_key_t))) { return index; @@ -483,21 +492,21 @@ UINT8 bta_gattc_co_find_hash_in_cache(hash_key_t hash_key) UINT8 bta_gattc_co_get_addr_num(void) { - return cache_env.num_addr; + return cache_env->num_addr; } void bta_gattc_co_get_addr_list(BD_ADDR *addr_list) { - UINT8 num = cache_env.num_addr; + UINT8 num = cache_env->num_addr; for (UINT8 i = 0; i < num; i++) { - memcpy(addr_list[i], cache_env.cache_addr[i].addr, sizeof(BD_ADDR)); + memcpy(addr_list[i], cache_env->cache_addr[i].addr, sizeof(BD_ADDR)); } } void bta_gattc_co_cache_addr_save(BD_ADDR bd_addr, hash_key_t hash_key) { esp_err_t err_code; - UINT8 num = ++cache_env.num_addr; + UINT8 num = ++cache_env->num_addr; UINT8 index = 0; UINT8 *p_buf = osi_malloc(MAX_ADDR_LIST_CACHE_BUF); // check the address list has the same hash key or not @@ -506,39 +515,39 @@ void bta_gattc_co_cache_addr_save(BD_ADDR bd_addr, hash_key_t hash_key) if ((index = bta_gattc_co_find_addr_in_cache(bd_addr)) != INVALID_ADDR_NUM) { APPL_TRACE_DEBUG("%s(), the hash bd_addr already in the cache list, index = %x", __func__, index); //if the bd_addr already in the address list, update the hash key in it. - memcpy(cache_env.cache_addr[index].addr, bd_addr, sizeof(BD_ADDR)); - memcpy(cache_env.cache_addr[index].hash_key, hash_key, sizeof(hash_key_t)); + memcpy(cache_env->cache_addr[index].addr, bd_addr, sizeof(BD_ADDR)); + memcpy(cache_env->cache_addr[index].hash_key, hash_key, sizeof(hash_key_t)); } else { //if the bd_addr didn't in the address list, added the bd_addr to the last of the address list. - memcpy(cache_env.cache_addr[num - 1].hash_key, hash_key, sizeof(hash_key_t)); - memcpy(cache_env.cache_addr[num - 1].addr, bd_addr, sizeof(BD_ADDR)); + memcpy(cache_env->cache_addr[num - 1].hash_key, hash_key, sizeof(hash_key_t)); + memcpy(cache_env->cache_addr[num - 1].addr, bd_addr, sizeof(BD_ADDR)); } } else { APPL_TRACE_DEBUG("%s(), num = %d", __func__, num); - memcpy(cache_env.cache_addr[num - 1].addr, bd_addr, sizeof(BD_ADDR)); - memcpy(cache_env.cache_addr[num - 1].hash_key, hash_key, sizeof(hash_key_t)); + memcpy(cache_env->cache_addr[num - 1].addr, bd_addr, sizeof(BD_ADDR)); + memcpy(cache_env->cache_addr[num - 1].hash_key, hash_key, sizeof(hash_key_t)); } - nvs_handle_t *fp = &cache_env.addr_fp; + nvs_handle_t *fp = &cache_env->addr_fp; UINT16 length = num*(sizeof(BD_ADDR) + sizeof(hash_key_t)); for (UINT8 i = 0; i < num; i++) { //copy the address to the buffer. - memcpy(p_buf + i*(sizeof(BD_ADDR) + sizeof(hash_key_t)), cache_env.cache_addr[i].addr, sizeof(BD_ADDR)); + memcpy(p_buf + i*(sizeof(BD_ADDR) + sizeof(hash_key_t)), cache_env->cache_addr[i].addr, sizeof(BD_ADDR)); //copy the hash key to the buffer. memcpy(p_buf + i*(sizeof(BD_ADDR) + sizeof(hash_key_t)) + sizeof(BD_ADDR), - cache_env.cache_addr[i].hash_key, sizeof(hash_key_t)); + cache_env->cache_addr[i].hash_key, sizeof(hash_key_t)); } - if (cache_env.is_open) { - if ((err_code = nvs_set_blob(cache_env.addr_fp, cache_key, p_buf, length)) != ESP_OK) { + if (cache_env->is_open) { + if ((err_code = nvs_set_blob(cache_env->addr_fp, cache_key, p_buf, length)) != ESP_OK) { APPL_TRACE_WARNING("%s(), nvs set blob fail, err %d", __func__, err_code); } } else { if ((err_code = nvs_open(cache_addr, NVS_READWRITE , fp)) == ESP_OK) { - cache_env.is_open = true; - if (( err_code = nvs_set_blob(cache_env.addr_fp, cache_key, p_buf, length)) != ESP_OK) { + cache_env->is_open = true; + if (( err_code = nvs_set_blob(cache_env->addr_fp, cache_key, p_buf, length)) != ESP_OK) { APPL_TRACE_WARNING("%s(), nvs set blob fail, err %d", __func__, err_code); } } else { @@ -553,7 +562,7 @@ void bta_gattc_co_cache_addr_save(BD_ADDR bd_addr, hash_key_t hash_key) BOOLEAN bta_gattc_co_cache_new_assoc_list(BD_ADDR src_addr, UINT8 index) { - cache_addr_info_t *addr_info = &cache_env.cache_addr[index]; + cache_addr_info_t *addr_info = &cache_env->cache_addr[index]; addr_info->assoc_addr = list_new(osi_free_func); return (addr_info->assoc_addr != NULL ? TRUE : FALSE); } @@ -565,7 +574,7 @@ BOOLEAN bta_gattc_co_cache_append_assoc_addr(BD_ADDR src_addr, BD_ADDR assoc_add UINT8 *p_assoc_buf = osi_malloc(sizeof(BD_ADDR)); memcpy(p_assoc_buf, assoc_addr, sizeof(BD_ADDR)); if ((addr_index = bta_gattc_co_find_addr_in_cache(src_addr)) != INVALID_ADDR_NUM) { - addr_info = &cache_env.cache_addr[addr_index]; + addr_info = &cache_env->cache_addr[addr_index]; if (addr_info->assoc_addr == NULL) { addr_info->assoc_addr =list_new(NULL); } @@ -580,7 +589,7 @@ BOOLEAN bta_gattc_co_cache_remove_assoc_addr(BD_ADDR src_addr, BD_ADDR assoc_add UINT8 addr_index = 0; cache_addr_info_t *addr_info; if ((addr_index = bta_gattc_co_find_addr_in_cache(src_addr)) != INVALID_ADDR_NUM) { - addr_info = &cache_env.cache_addr[addr_index]; + addr_info = &cache_env->cache_addr[addr_index]; if (addr_info->assoc_addr != NULL) { for (list_node_t *sn = list_begin(addr_info->assoc_addr); sn != list_end(addr_info->assoc_addr); sn = list_next(sn)) { @@ -600,8 +609,8 @@ BOOLEAN bta_gattc_co_cache_remove_assoc_addr(BD_ADDR src_addr, BD_ADDR assoc_add UINT8* bta_gattc_co_cache_find_src_addr(BD_ADDR assoc_addr, UINT8 *index) { - UINT8 num = cache_env.num_addr; - cache_addr_info_t *addr_info = &cache_env.cache_addr[0]; + UINT8 num = cache_env->num_addr; + cache_addr_info_t *addr_info = &cache_env->cache_addr[0]; UINT8 *addr_data; //Check the assoc_addr list is NULL or not if (addr_info->assoc_addr == NULL) { @@ -610,7 +619,7 @@ UINT8* bta_gattc_co_cache_find_src_addr(BD_ADDR assoc_addr, UINT8 *index) } for (int i = 0; i < num; i++) { - for (const list_node_t *node = list_begin(addr_info->assoc_addr); node != list_end(addr_info->assoc_addr); + for (const list_node_t *node = list_begin(addr_info->assoc_addr); node != list_end(addr_info->assoc_addr); node = list_next(node)) { addr_data = (UINT8 *)list_node(node); if (!memcmp(addr_data, assoc_addr, sizeof(BD_ADDR))) { @@ -635,7 +644,7 @@ BOOLEAN bta_gattc_co_cache_clear_assoc_addr(BD_ADDR src_addr) UINT8 addr_index = 0; cache_addr_info_t *addr_info; if ((addr_index = bta_gattc_co_find_addr_in_cache(src_addr)) != INVALID_ADDR_NUM) { - addr_info = &cache_env.cache_addr[addr_index]; + addr_info = &cache_env->cache_addr[addr_index]; if (addr_info->assoc_addr != NULL) { list_clear(addr_info->assoc_addr); } else { @@ -647,6 +656,7 @@ BOOLEAN bta_gattc_co_cache_clear_assoc_addr(BD_ADDR src_addr) return FALSE; } +// #endif /* #if( defined GATTC_CACHE_NVS ) && (GATTC_CACHE_NVS == TRUE) */ #endif /* #if( defined BLE_INCLUDED ) && (BLE_INCLUDED == TRUE) */ #endif /* #if( defined BTA_GATT_INCLUDED ) && (BTA_GATT_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/bta/gatt/bta_gatts_act.c b/components/bt/bluedroid/bta/gatt/bta_gatts_act.c index 95cb668c6b..4dd804a47a 100644 --- a/components/bt/bluedroid/bta/gatt/bta_gatts_act.c +++ b/components/bt/bluedroid/bta/gatt/bta_gatts_act.c @@ -49,7 +49,7 @@ static void bta_gatts_send_request_cback (UINT16 conn_id, tGATTS_REQ_TYPE req_type, tGATTS_DATA *p_data); static void bta_gatts_cong_cback (UINT16 conn_id, BOOLEAN congested); -static tGATT_CBACK bta_gatts_cback = { +static const tGATT_CBACK bta_gatts_cback = { bta_gatts_conn_cback, NULL, NULL, @@ -59,7 +59,7 @@ static tGATT_CBACK bta_gatts_cback = { bta_gatts_cong_cback }; -tGATT_APPL_INFO bta_gatts_nv_cback = { +const tGATT_APPL_INFO bta_gatts_nv_cback = { bta_gatts_nv_save_cback, bta_gatts_nv_srv_chg_cback }; diff --git a/components/bt/bluedroid/bta/gatt/bta_gatts_api.c b/components/bt/bluedroid/bta/gatt/bta_gatts_api.c index 87e559ab72..aefe62d65a 100644 --- a/components/bt/bluedroid/bta/gatt/bta_gatts_api.c +++ b/components/bt/bluedroid/bta/gatt/bta_gatts_api.c @@ -82,7 +82,7 @@ void BTA_GATTS_Disable(void) ** Returns None ** *******************************************************************************/ -void BTA_GATTS_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTS_CBACK *p_cback) +void BTA_GATTS_AppRegister(const tBT_UUID * p_app_uuid, tBTA_GATTS_CBACK *p_cback) { tBTA_GATTS_API_REG *p_buf; @@ -149,7 +149,7 @@ void BTA_GATTS_AppDeregister(tBTA_GATTS_IF server_if) ** Returns void ** *******************************************************************************/ -void BTA_GATTS_CreateService(tBTA_GATTS_IF server_if, tBT_UUID *p_service_uuid, UINT8 inst, +void BTA_GATTS_CreateService(tBTA_GATTS_IF server_if, const tBT_UUID * p_service_uuid, UINT8 inst, UINT16 num_handle, BOOLEAN is_primary) { tBTA_GATTS_API_CREATE_SRVC *p_buf; @@ -214,8 +214,8 @@ void BTA_GATTS_AddIncludeService(UINT16 service_id, UINT16 included_service_id) ** Returns None ** *******************************************************************************/ -void BTA_GATTS_AddCharacteristic (UINT16 service_id, tBT_UUID *p_char_uuid, - tBTA_GATT_PERM perm, tBTA_GATT_CHAR_PROP property, tGATT_ATTR_VAL *attr_val, +void BTA_GATTS_AddCharacteristic (UINT16 service_id, const tBT_UUID * p_char_uuid, + tBTA_GATT_PERM perm, tBTA_GATT_CHAR_PROP property, tGATT_ATTR_VAL *attr_val, tBTA_GATTS_ATTR_CONTROL *control) { tBTA_GATTS_API_ADD_CHAR *p_buf; @@ -270,7 +270,7 @@ void BTA_GATTS_AddCharacteristic (UINT16 service_id, tBT_UUID *p_char_uuid, *******************************************************************************/ void BTA_GATTS_AddCharDescriptor (UINT16 service_id, tBTA_GATT_PERM perm, - tBT_UUID *p_descr_uuid, tBTA_GATT_ATTR_VAL *attr_val, + const tBT_UUID * p_descr_uuid, tBTA_GATT_ATTR_VAL *attr_val, tBTA_GATTS_ATTR_CONTROL *control) { tBTA_GATTS_API_ADD_DESCR *p_buf; diff --git a/components/bt/bluedroid/bta/include/bta/bta_api.h b/components/bt/bluedroid/bta/include/bta/bta_api.h index a7dc0185f3..aed71d7e46 100644 --- a/components/bt/bluedroid/bta/include/bta/bta_api.h +++ b/components/bt/bluedroid/bta/include/bta/bta_api.h @@ -1809,6 +1809,17 @@ extern void bta_dmexecutecallback (tBTA_DM_EXEC_CBACK *p_callback, void *p_param *******************************************************************************/ extern void BTA_DmPcmInitSamples (UINT32 src_sps, UINT32 bits, UINT32 n_channels); +/******************************************************************************* +** +** Function BTA_DmPcmDeinitSamples +** +** Description Deinitialize the down sample converter. +** +** Returns none +** +*******************************************************************************/ +extern void BTA_DmPcmDeinitSamples(void); + /************************************************************************************** ** Function BTA_DmPcmResample ** diff --git a/components/bt/bluedroid/bta/include/bta/bta_gatt_api.h b/components/bt/bluedroid/bta/include/bta/bta_gatt_api.h index cb69110b60..664536ddd1 100644 --- a/components/bt/bluedroid/bta/include/bta/bta_gatt_api.h +++ b/components/bt/bluedroid/bta/include/bta/bta_gatt_api.h @@ -30,7 +30,6 @@ #include "osi/list.h" #ifndef BTA_GATT_INCLUDED -#warning BTA_GATT_INCLUDED not defined #define BTA_GATT_INCLUDED FALSE #endif @@ -881,7 +880,7 @@ extern const tBTA_GATTC_CHARACTERISTIC* BTA_GATTC_GetCharacteristic(UINT16 conn_ *******************************************************************************/ extern const tBTA_GATTC_DESCRIPTOR* BTA_GATTC_GetDescriptor(UINT16 conn_id, UINT16 handle); -extern void BTA_GATTC_GetServiceWithUUID(UINT16 conn_id, tBT_UUID *svc_uuid, +extern void BTA_GATTC_GetServiceWithUUID(UINT16 conn_id, tBT_UUID *svc_uuid, btgatt_db_element_t **db, int *count); extern void BTA_GATTC_GetAllChar(UINT16 conn_id, UINT16 start_handle, UINT16 end_handle, @@ -1234,7 +1233,7 @@ extern void BTA_GATTS_Disable(void); ** Returns None ** *******************************************************************************/ -extern void BTA_GATTS_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTS_CBACK *p_cback); +extern void BTA_GATTS_AppRegister(const tBT_UUID * p_app_uuid, tBTA_GATTS_CBACK *p_cback); /******************************************************************************* @@ -1269,7 +1268,7 @@ extern void BTA_GATTS_AppDeregister(tBTA_GATTS_IF server_if); ** Returns void ** *******************************************************************************/ -extern void BTA_GATTS_CreateService(tBTA_GATTS_IF server_if, tBT_UUID *p_service_uuid, +extern void BTA_GATTS_CreateService(tBTA_GATTS_IF server_if, const tBT_UUID * p_service_uuid, UINT8 inst, UINT16 num_handle, BOOLEAN is_primary); /******************************************************************************* @@ -1304,8 +1303,8 @@ extern void BTA_GATTS_AddIncludeService(UINT16 service_id, UINT16 included_servi ** Returns None ** *******************************************************************************/ -extern void BTA_GATTS_AddCharacteristic (UINT16 service_id, tBT_UUID *p_char_uuid, - tBTA_GATT_PERM perm, tBTA_GATT_CHAR_PROP property, tGATT_ATTR_VAL *attr_val, +extern void BTA_GATTS_AddCharacteristic (UINT16 service_id, const tBT_UUID * p_char_uuid, + tBTA_GATT_PERM perm, tBTA_GATT_CHAR_PROP property, tGATT_ATTR_VAL *attr_val, tBTA_GATTS_ATTR_CONTROL *control); /******************************************************************************* @@ -1327,7 +1326,7 @@ extern void BTA_GATTS_AddCharacteristic (UINT16 service_id, tBT_UUID *p_char_u *******************************************************************************/ extern void BTA_GATTS_AddCharDescriptor (UINT16 service_id, tBTA_GATT_PERM perm, - tBT_UUID *p_descr_uuid, tBTA_GATT_ATTR_VAL *attr_val, + const tBT_UUID * p_descr_uuid, tBTA_GATT_ATTR_VAL *attr_val, tBTA_GATTS_ATTR_CONTROL *control); /******************************************************************************* diff --git a/components/bt/bluedroid/bta/include/bta/bta_sdp_api.h b/components/bt/bluedroid/bta/include/bta/bta_sdp_api.h index b88c0c263c..1d32b9204f 100644 --- a/components/bt/bluedroid/bta/include/bta/bta_sdp_api.h +++ b/components/bt/bluedroid/bta/include/bta/bta_sdp_api.h @@ -96,6 +96,19 @@ extern "C" *******************************************************************************/ extern tBTA_SDP_STATUS BTA_SdpEnable(tBTA_SDP_DM_CBACK *p_cback); +/******************************************************************************* +** +** Function BTA_SdpDisable +** +** Description Disable the SDP search I/F service. +** Free buffer for SDP configuration structure. +** +** Returns BTA_SDP_SUCCESS if successful. +** BTA_SDP_FAIL if internal failure. +** +*******************************************************************************/ +extern tBTA_SDP_STATUS BTA_SdpDisable(void); + /******************************************************************************* ** ** Function BTA_SdpSearch diff --git a/components/bt/bluedroid/bta/jv/bta_jv_api.c b/components/bt/bluedroid/bta/jv/bta_jv_api.c index 5430d36bcb..98465701db 100644 --- a/components/bt/bluedroid/bta/jv/bta_jv_api.c +++ b/components/bt/bluedroid/bta/jv/bta_jv_api.c @@ -67,8 +67,17 @@ tBTA_JV_STATUS BTA_JvEnable(tBTA_JV_DM_CBACK *p_cback) tBTA_JV_STATUS status = BTA_JV_FAILURE; tBTA_JV_API_ENABLE *p_buf; int i; - APPL_TRACE_API( "BTA_JvEnable"); + +#if BTA_DYNAMIC_MEMORY == TRUE + /* Malloc buffer for JV configuration structure */ + p_bta_jv_cfg->p_sdp_raw_data = (UINT8 *)osi_malloc(p_bta_jv_cfg->sdp_raw_size); + p_bta_jv_cfg->p_sdp_db = (tSDP_DISCOVERY_DB *)osi_malloc(p_bta_jv_cfg->sdp_db_size); + if (p_bta_jv_cfg->p_sdp_raw_data == NULL || p_bta_jv_cfg->p_sdp_db == NULL) { + return BTA_JV_NO_DATA; + } +#endif + if (p_cback && FALSE == bta_sys_is_register(BTA_ID_JV)) { memset(&bta_jv_cb, 0, sizeof(tBTA_JV_CB)); /* set handle to invalid value by default */ @@ -110,6 +119,14 @@ void BTA_JvDisable(void) p_buf->event = BTA_JV_API_DISABLE_EVT; bta_sys_sendmsg(p_buf); } + +#if BTA_DYNAMIC_MEMORY == TRUE + /* Free buffer for JV configuration structure */ + osi_free(p_bta_jv_cfg->p_sdp_raw_data); + osi_free(p_bta_jv_cfg->p_sdp_db); + p_bta_jv_cfg->p_sdp_raw_data = NULL; + p_bta_jv_cfg->p_sdp_db = NULL; +#endif } /******************************************************************************* diff --git a/components/bt/bluedroid/bta/jv/bta_jv_cfg.c b/components/bt/bluedroid/bta/jv/bta_jv_cfg.c index f617dfc513..9020efb8ab 100644 --- a/components/bt/bluedroid/bta/jv/bta_jv_cfg.c +++ b/components/bt/bluedroid/bta/jv/bta_jv_cfg.c @@ -43,15 +43,22 @@ * between BTA_JvEnable and BTA_JvDisable * p_bta_jv_cfg->p_sdp_raw_data can be allocated before calling BTA_JvStartDiscovery * it can be de-allocated after the last call to access the database */ +#if BTA_DYNAMIC_MEMORY == FALSE static UINT8 bta_jv_sdp_raw_data[BTA_JV_SDP_RAW_DATA_SIZE]; static UINT8 __attribute__ ((aligned(4))) bta_jv_sdp_db_data[BTA_JV_SDP_DB_SIZE]; +#endif /* JV configuration structure */ -const tBTA_JV_CFG bta_jv_cfg = { +/*const */tBTA_JV_CFG bta_jv_cfg = { BTA_JV_SDP_RAW_DATA_SIZE, /* The size of p_sdp_raw_data */ BTA_JV_SDP_DB_SIZE, /* The size of p_sdp_db_data */ +#if BTA_DYNAMIC_MEMORY == FALSE bta_jv_sdp_raw_data, /* The data buffer to keep raw data */ (tSDP_DISCOVERY_DB *)bta_jv_sdp_db_data /* The data buffer to keep SDP database */ +#else + NULL, + NULL +#endif }; tBTA_JV_CFG *p_bta_jv_cfg = (tBTA_JV_CFG *) &bta_jv_cfg; diff --git a/components/bt/bluedroid/bta/jv/bta_jv_main.c b/components/bt/bluedroid/bta/jv/bta_jv_main.c index 9523d6e893..b09ebcd469 100644 --- a/components/bt/bluedroid/bta/jv/bta_jv_main.c +++ b/components/bt/bluedroid/bta/jv/bta_jv_main.c @@ -35,6 +35,8 @@ #if BTA_DYNAMIC_MEMORY == FALSE tBTA_JV_CB bta_jv_cb; +#else +tBTA_JV_CB *bta_jv_cb_ptr; #endif /* state machine action enumeration list */ diff --git a/components/bt/bluedroid/bta/sdp/bta_sdp_api.c b/components/bt/bluedroid/bta/sdp/bta_sdp_api.c index 1d027cb79e..e26f93910c 100644 --- a/components/bt/bluedroid/bta/sdp/bta_sdp_api.c +++ b/components/bt/bluedroid/bta/sdp/bta_sdp_api.c @@ -61,6 +61,15 @@ tBTA_SDP_STATUS BTA_SdpEnable(tBTA_SDP_DM_CBACK *p_cback) tBTA_SDP_API_ENABLE *p_buf; APPL_TRACE_API("%s\n", __FUNCTION__); + +#if BTA_DYNAMIC_MEMORY == TRUE + /* Malloc buffer for SDP configuration structure */ + p_bta_sdp_cfg->p_sdp_db = (tSDP_DISCOVERY_DB *)osi_malloc(p_bta_sdp_cfg->sdp_db_size); + if (p_bta_sdp_cfg->p_sdp_db == NULL) { + return BTA_SDP_FAILURE; + } +#endif + if (p_cback && FALSE == bta_sys_is_register(BTA_ID_SDP)) { memset(&bta_sdp_cb, 0, sizeof(tBTA_SDP_CB)); @@ -78,6 +87,29 @@ tBTA_SDP_STATUS BTA_SdpEnable(tBTA_SDP_DM_CBACK *p_cback) return (status); } + +/******************************************************************************* +** +** Function BTA_SdpDisable +** +** Description Disable the SDP search I/F service. +** Free buffer for SDP configuration structure. +** +** Returns BTA_SDP_SUCCESS if successful. +** BTA_SDP_FAIL if internal failure. +** +*******************************************************************************/ +tBTA_SDP_STATUS BTA_SdpDisable(void) +{ + tBTA_SDP_STATUS status = BTA_SDP_SUCCESS; +#if BTA_DYNAMIC_MEMORY == TRUE + /* Free buffer for SDP configuration structure */ + osi_free(p_bta_sdp_cfg->p_sdp_db); + p_bta_sdp_cfg->p_sdp_db = NULL; +#endif + return (status); +} + /******************************************************************************* ** ** Function BTA_SdpSearch diff --git a/components/bt/bluedroid/bta/sdp/bta_sdp_cfg.c b/components/bt/bluedroid/bta/sdp/bta_sdp_cfg.c index fff5e321a2..322b25caec 100644 --- a/components/bt/bluedroid/bta/sdp/bta_sdp_cfg.c +++ b/components/bt/bluedroid/bta/sdp/bta_sdp_cfg.c @@ -30,12 +30,18 @@ #define BTA_SDP_DB_SIZE 1500 #endif +#if BTA_DYNAMIC_MEMORY == FALSE static UINT8 __attribute__ ((aligned(4))) bta_sdp_db_data[BTA_SDP_DB_SIZE]; +#endif /* SDP configuration structure */ -const tBTA_SDP_CFG bta_sdp_cfg = { +tBTA_SDP_CFG bta_sdp_cfg = { BTA_SDP_DB_SIZE, +#if BTA_DYNAMIC_MEMORY == FALSE (tSDP_DISCOVERY_DB *)bta_sdp_db_data /* The data buffer to keep SDP database */ +#else + NULL +#endif }; tBTA_SDP_CFG *p_bta_sdp_cfg = (tBTA_SDP_CFG *) &bta_sdp_cfg; diff --git a/components/bt/bluedroid/btc/core/btc_ble_storage.c b/components/bt/bluedroid/btc/core/btc_ble_storage.c index c8590ce803..9730dc612c 100644 --- a/components/bt/bluedroid/btc/core/btc_ble_storage.c +++ b/components/bt/bluedroid/btc/core/btc_ble_storage.c @@ -774,7 +774,7 @@ static bt_status_t _btc_storage_in_fetch_bonded_ble_device(const char *remote_bd BTC_TRACE_ERROR("%s, device_type = %x", __func__, device_type); return BT_STATUS_FAIL; } - + string_to_bdaddr(remote_bd_addr, &bd_addr); bdcpy(bta_bd_addr, bd_addr.address); @@ -817,7 +817,7 @@ static bt_status_t btc_storage_in_fetch_bonded_ble_devices(int add) for (const btc_config_section_iter_t *iter = btc_config_section_begin(); iter != btc_config_section_end(); iter = btc_config_section_next(iter)) { const char *name = btc_config_section_name(iter); - + if (!string_is_bdaddr(name) || !btc_config_get_int(name, BTC_BLE_STORAGE_DEV_TYPE_STR, (int *)&device_type) || ((device_type & BT_DEVICE_TYPE_BLE) != BT_DEVICE_TYPE_BLE)) { @@ -927,4 +927,4 @@ int btc_storage_get_num_ble_bond_devices(void) return num_dev; } #endif ///SMP_INCLUDED == TRUE - + diff --git a/components/bt/bluedroid/btc/core/btc_dm.c b/components/bt/bluedroid/btc/core/btc_dm.c index f3b9caeb42..ecc8f383a6 100644 --- a/components/bt/bluedroid/btc/core/btc_dm.c +++ b/components/bt/bluedroid/btc/core/btc_dm.c @@ -41,10 +41,10 @@ /****************************************************************************** ** Static variables ******************************************************************************/ -static tBTA_SERVICE_MASK btc_enabled_services = 0; -#if (SMP_INCLUDED == TRUE) -static btc_dm_pairing_cb_t pairing_cb; -static btc_dm_local_key_cb_t ble_local_key_cb; +#if BTC_DYNAMIC_MENDRY == FALSE +btc_dm_cb_t btc_dm_cb = {0}; +#else +btc_dm_cb_t *btc_dm_cb_ptr; #endif /****************************************************************************** @@ -131,21 +131,21 @@ static void btc_disable_bluetooth_evt(void) #if (SMP_INCLUDED == TRUE) void btc_dm_load_ble_local_keys(void) { - memset(&ble_local_key_cb, 0, sizeof(btc_dm_local_key_cb_t)); + memset(&btc_dm_cb.ble_local_key_cb, 0, sizeof(btc_dm_local_key_cb_t)); - if (btc_storage_get_ble_local_key(BTC_LE_LOCAL_KEY_ER,(char*)&ble_local_key_cb.er[0], + if (btc_storage_get_ble_local_key(BTC_LE_LOCAL_KEY_ER,(char*)&btc_dm_cb.ble_local_key_cb.er[0], BT_OCTET16_LEN)== BT_STATUS_SUCCESS) { - ble_local_key_cb.is_er_rcvd = TRUE; + btc_dm_cb.ble_local_key_cb.is_er_rcvd = TRUE; BTC_TRACE_DEBUG("%s BLE ER key loaded",__func__ ); } - if ((btc_storage_get_ble_local_key(BTC_LE_LOCAL_KEY_IR,(char*)&ble_local_key_cb.id_keys.ir[0], + if ((btc_storage_get_ble_local_key(BTC_LE_LOCAL_KEY_IR,(char*)&btc_dm_cb.ble_local_key_cb.id_keys.ir[0], BT_OCTET16_LEN)== BT_STATUS_SUCCESS )&& - (btc_storage_get_ble_local_key(BTC_LE_LOCAL_KEY_IRK, (char*)&ble_local_key_cb.id_keys.irk[0], + (btc_storage_get_ble_local_key(BTC_LE_LOCAL_KEY_IRK, (char*)&btc_dm_cb.ble_local_key_cb.id_keys.irk[0], BT_OCTET16_LEN)== BT_STATUS_SUCCESS)&& - (btc_storage_get_ble_local_key(BTC_LE_LOCAL_KEY_DHK,(char*)&ble_local_key_cb.id_keys.dhk[0], + (btc_storage_get_ble_local_key(BTC_LE_LOCAL_KEY_DHK,(char*)&btc_dm_cb.ble_local_key_cb.id_keys.dhk[0], BT_OCTET16_LEN)== BT_STATUS_SUCCESS)) { - ble_local_key_cb.is_id_keys_rcvd = TRUE; + btc_dm_cb.ble_local_key_cb.is_id_keys_rcvd = TRUE; BTC_TRACE_DEBUG("%s BLE ID keys loaded", __func__); } @@ -153,15 +153,15 @@ void btc_dm_load_ble_local_keys(void) void btc_dm_get_ble_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK *p_key_mask, BT_OCTET16 er, tBTA_BLE_LOCAL_ID_KEYS *p_id_keys) { - if (ble_local_key_cb.is_er_rcvd ) { - memcpy(&er[0], &ble_local_key_cb.er[0], sizeof(BT_OCTET16)); + if (btc_dm_cb.ble_local_key_cb.is_er_rcvd ) { + memcpy(&er[0], &btc_dm_cb.ble_local_key_cb.er[0], sizeof(BT_OCTET16)); *p_key_mask |= BTA_BLE_LOCAL_KEY_TYPE_ER; } - if (ble_local_key_cb.is_id_keys_rcvd) { - memcpy(&p_id_keys->ir[0], &ble_local_key_cb.id_keys.ir[0], sizeof(BT_OCTET16)); - memcpy(&p_id_keys->irk[0], &ble_local_key_cb.id_keys.irk[0], sizeof(BT_OCTET16)); - memcpy(&p_id_keys->dhk[0], &ble_local_key_cb.id_keys.dhk[0], sizeof(BT_OCTET16)); + if (btc_dm_cb.ble_local_key_cb.is_id_keys_rcvd) { + memcpy(&p_id_keys->ir[0], &btc_dm_cb.ble_local_key_cb.id_keys.ir[0], sizeof(BT_OCTET16)); + memcpy(&p_id_keys->irk[0], &btc_dm_cb.ble_local_key_cb.id_keys.irk[0], sizeof(BT_OCTET16)); + memcpy(&p_id_keys->dhk[0], &btc_dm_cb.ble_local_key_cb.id_keys.dhk[0], sizeof(BT_OCTET16)); *p_key_mask |= BTA_BLE_LOCAL_KEY_TYPE_ID; } BTC_TRACE_DEBUG("%s *p_key_mask=0x%02x",__func__, *p_key_mask); @@ -173,7 +173,7 @@ static void btc_dm_remove_ble_bonding_keys(void) bt_bdaddr_t bd_addr; BTC_TRACE_DEBUG("%s\n",__func__); - bdcpy(bd_addr.address, pairing_cb.bd_addr); + bdcpy(bd_addr.address, btc_dm_cb.pairing_cb.bd_addr); btc_storage_remove_remote_addr_type(&bd_addr, false); btc_storage_remove_ble_dev_auth_mode(&bd_addr, false); @@ -183,64 +183,64 @@ static void btc_dm_remove_ble_bonding_keys(void) static void btc_dm_save_ble_bonding_keys(void) { - if (!(pairing_cb.ble.is_penc_key_rcvd || pairing_cb.ble.is_pid_key_rcvd || pairing_cb.ble.is_pcsrk_key_rcvd || - pairing_cb.ble.is_lenc_key_rcvd || pairing_cb.ble.is_lcsrk_key_rcvd || pairing_cb.ble.is_lidk_key_rcvd)) { + if (!(btc_dm_cb.pairing_cb.ble.is_penc_key_rcvd || btc_dm_cb.pairing_cb.ble.is_pid_key_rcvd || btc_dm_cb.pairing_cb.ble.is_pcsrk_key_rcvd || + btc_dm_cb.pairing_cb.ble.is_lenc_key_rcvd || btc_dm_cb.pairing_cb.ble.is_lcsrk_key_rcvd || btc_dm_cb.pairing_cb.ble.is_lidk_key_rcvd)) { return ; } bt_bdaddr_t bd_addr; - bdcpy(bd_addr.address, pairing_cb.bd_addr); + bdcpy(bd_addr.address, btc_dm_cb.pairing_cb.bd_addr); btc_storage_set_ble_dev_type(&bd_addr, false); - BTC_TRACE_DEBUG("%s, penc = %d, pid = %d", __func__, pairing_cb.ble.is_penc_key_rcvd, pairing_cb.ble.is_pid_key_rcvd); - if (pairing_cb.ble.is_penc_key_rcvd) { + BTC_TRACE_DEBUG("%s, penc = %d, pid = %d", __func__, btc_dm_cb.pairing_cb.ble.is_penc_key_rcvd, btc_dm_cb.pairing_cb.ble.is_pid_key_rcvd); + if (btc_dm_cb.pairing_cb.ble.is_penc_key_rcvd) { btc_storage_add_ble_bonding_key(&bd_addr, - (char *) &pairing_cb.ble.penc_key, + (char *) &btc_dm_cb.pairing_cb.ble.penc_key, BTM_LE_KEY_PENC, sizeof(tBTM_LE_PENC_KEYS)); - pairing_cb.ble.is_penc_key_rcvd = false; + btc_dm_cb.pairing_cb.ble.is_penc_key_rcvd = false; } - if (pairing_cb.ble.is_pid_key_rcvd) { + if (btc_dm_cb.pairing_cb.ble.is_pid_key_rcvd) { btc_storage_add_ble_bonding_key(&bd_addr, - (char *) &pairing_cb.ble.pid_key, + (char *) &btc_dm_cb.pairing_cb.ble.pid_key, BTM_LE_KEY_PID, sizeof(tBTM_LE_PID_KEYS)); - pairing_cb.ble.is_pid_key_rcvd = false; + btc_dm_cb.pairing_cb.ble.is_pid_key_rcvd = false; } - if (pairing_cb.ble.is_pcsrk_key_rcvd) { + if (btc_dm_cb.pairing_cb.ble.is_pcsrk_key_rcvd) { btc_storage_add_ble_bonding_key(&bd_addr, - (char *) &pairing_cb.ble.pcsrk_key, + (char *) &btc_dm_cb.pairing_cb.ble.pcsrk_key, BTM_LE_KEY_PCSRK, sizeof(tBTM_LE_PCSRK_KEYS)); - pairing_cb.ble.is_pcsrk_key_rcvd = false; + btc_dm_cb.pairing_cb.ble.is_pcsrk_key_rcvd = false; } - if (pairing_cb.ble.is_lenc_key_rcvd) { + if (btc_dm_cb.pairing_cb.ble.is_lenc_key_rcvd) { btc_storage_add_ble_bonding_key(&bd_addr, - (char *) &pairing_cb.ble.lenc_key, + (char *) &btc_dm_cb.pairing_cb.ble.lenc_key, BTM_LE_KEY_LENC, sizeof(tBTM_LE_LENC_KEYS)); - pairing_cb.ble.is_lenc_key_rcvd = false; + btc_dm_cb.pairing_cb.ble.is_lenc_key_rcvd = false; } - if (pairing_cb.ble.is_lcsrk_key_rcvd) { + if (btc_dm_cb.pairing_cb.ble.is_lcsrk_key_rcvd) { btc_storage_add_ble_bonding_key(&bd_addr, - (char *) &pairing_cb.ble.lcsrk_key, + (char *) &btc_dm_cb.pairing_cb.ble.lcsrk_key, BTM_LE_KEY_LCSRK, sizeof(tBTM_LE_LCSRK_KEYS)); - pairing_cb.ble.is_lcsrk_key_rcvd = false; + btc_dm_cb.pairing_cb.ble.is_lcsrk_key_rcvd = false; } - if (pairing_cb.ble.is_lidk_key_rcvd) { + if (btc_dm_cb.pairing_cb.ble.is_lidk_key_rcvd) { btc_storage_add_ble_bonding_key(&bd_addr, NULL, BTM_LE_KEY_LID, 0); - pairing_cb.ble.is_lidk_key_rcvd = false; + btc_dm_cb.pairing_cb.ble.is_lidk_key_rcvd = false; } } @@ -252,20 +252,19 @@ static void btc_dm_ble_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl) int addr_type; bt_bdaddr_t bdaddr; bdcpy(bdaddr.address, p_auth_cmpl->bd_addr); - bdcpy(pairing_cb.bd_addr, p_auth_cmpl->bd_addr); + bdcpy(btc_dm_cb.pairing_cb.bd_addr, p_auth_cmpl->bd_addr); if (p_auth_cmpl->success) { status = BT_STATUS_SUCCESS; BTC_TRACE_DEBUG ("%s, - p_auth_cmpl->bd_addr: %08x%04x", __func__, (p_auth_cmpl->bd_addr[0] << 24) + (p_auth_cmpl->bd_addr[1] << 16) + (p_auth_cmpl->bd_addr[2] << 8) + p_auth_cmpl->bd_addr[3], (p_auth_cmpl->bd_addr[4] << 8) + p_auth_cmpl->bd_addr[5]); - BTC_TRACE_DEBUG ("%s, - pairing_cb.bd_addr: %08x%04x", __func__, - (pairing_cb.bd_addr[0] << 24) + (pairing_cb.bd_addr[1] << 16) + (pairing_cb.bd_addr[2] << 8) + pairing_cb.bd_addr[3], - (pairing_cb.bd_addr[4] << 8) + pairing_cb.bd_addr[5]); + // Check if need to save BLE keys if((p_auth_cmpl->auth_mode & SMP_AUTH_GEN_BOND) == 0) { return; } + if (btc_storage_get_remote_addr_type(&bdaddr, &addr_type) != BT_STATUS_SUCCESS) { btc_storage_set_remote_addr_type(&bdaddr, p_auth_cmpl->addr_type, true); } @@ -487,12 +486,12 @@ static void btc_dm_sp_key_req_evt(tBTA_DM_SP_KEY_REQ *p_key_req) tBTA_SERVICE_MASK btc_get_enabled_services_mask(void) { - return btc_enabled_services; + return btc_dm_cb.btc_enabled_services; } void btc_clear_services_mask(void) { - btc_enabled_services = 0; + btc_dm_cb.btc_enabled_services = 0; } static bt_status_t btc_in_execute_service_request(tBTA_SERVICE_ID service_id, @@ -530,9 +529,9 @@ bt_status_t btc_dm_enable_service(tBTA_SERVICE_ID service_id) { tBTA_SERVICE_ID *p_id = &service_id; - btc_enabled_services |= (1 << service_id); + btc_dm_cb.btc_enabled_services |= (1 << service_id); - BTC_TRACE_DEBUG("%s: current services:0x%x", __FUNCTION__, btc_enabled_services); + BTC_TRACE_DEBUG("%s: current services:0x%x", __FUNCTION__, btc_dm_cb.btc_enabled_services); btc_dm_execute_service_request(TRUE, (char *)p_id); @@ -543,9 +542,9 @@ bt_status_t btc_dm_disable_service(tBTA_SERVICE_ID service_id) { tBTA_SERVICE_ID *p_id = &service_id; - btc_enabled_services &= (tBTA_SERVICE_MASK)(~(1 << service_id)); + btc_dm_cb.btc_enabled_services &= (tBTA_SERVICE_MASK)(~(1 << service_id)); - BTC_TRACE_DEBUG("%s: Current Services:0x%x", __FUNCTION__, btc_enabled_services); + BTC_TRACE_DEBUG("%s: Current Services:0x%x", __FUNCTION__, btc_dm_cb.btc_enabled_services); btc_dm_execute_service_request(FALSE, (char *)p_id); @@ -693,9 +692,9 @@ void btc_dm_sec_cb_handler(btc_msg_t *msg) switch (p_data->ble_key.key_type) { case BTM_LE_KEY_PENC: { BTC_TRACE_DEBUG("Rcv BTA_LE_KEY_PENC"); - pairing_cb.ble.is_penc_key_rcvd = TRUE; - pairing_cb.ble.penc_key = p_data->ble_key.p_key_value->penc_key; - memcpy(&pairing_cb.ble.penc_key, &p_data->ble_key.p_key_value->penc_key, + btc_dm_cb.pairing_cb.ble.is_penc_key_rcvd = TRUE; + btc_dm_cb.pairing_cb.ble.penc_key = p_data->ble_key.p_key_value->penc_key; + memcpy(&btc_dm_cb.pairing_cb.ble.penc_key, &p_data->ble_key.p_key_value->penc_key, sizeof(tBTM_LE_PENC_KEYS)); memcpy(¶m.ble_security.ble_key.p_key_value.penc_key, &p_data->ble_key.p_key_value->penc_key, sizeof(tBTM_LE_PENC_KEYS)); @@ -703,8 +702,8 @@ void btc_dm_sec_cb_handler(btc_msg_t *msg) } case BTM_LE_KEY_PID: { BTC_TRACE_DEBUG("Rcv BTA_LE_KEY_PID"); - pairing_cb.ble.is_pid_key_rcvd = TRUE; - memcpy(&pairing_cb.ble.pid_key, &p_data->ble_key.p_key_value->pid_key, + btc_dm_cb.pairing_cb.ble.is_pid_key_rcvd = TRUE; + memcpy(&btc_dm_cb.pairing_cb.ble.pid_key, &p_data->ble_key.p_key_value->pid_key, sizeof(tBTM_LE_PID_KEYS)); memcpy(¶m.ble_security.ble_key.p_key_value.pid_key, &p_data->ble_key.p_key_value->pid_key, sizeof(tBTM_LE_PID_KEYS)); @@ -712,8 +711,8 @@ void btc_dm_sec_cb_handler(btc_msg_t *msg) } case BTM_LE_KEY_PCSRK: { BTC_TRACE_DEBUG("Rcv BTA_LE_KEY_PCSRK"); - pairing_cb.ble.is_pcsrk_key_rcvd = TRUE; - memcpy(&pairing_cb.ble.pcsrk_key, &p_data->ble_key.p_key_value->pcsrk_key, + btc_dm_cb.pairing_cb.ble.is_pcsrk_key_rcvd = TRUE; + memcpy(&btc_dm_cb.pairing_cb.ble.pcsrk_key, &p_data->ble_key.p_key_value->pcsrk_key, sizeof(tBTM_LE_PCSRK_KEYS)); memcpy(¶m.ble_security.ble_key.p_key_value.pcsrk_key, &p_data->ble_key.p_key_value->pcsrk_key, sizeof(tBTM_LE_PCSRK_KEYS)); @@ -721,8 +720,8 @@ void btc_dm_sec_cb_handler(btc_msg_t *msg) } case BTM_LE_KEY_LENC: { BTC_TRACE_DEBUG("Rcv BTA_LE_KEY_LENC"); - pairing_cb.ble.is_lenc_key_rcvd = TRUE; - memcpy(&pairing_cb.ble.lenc_key, &p_data->ble_key.p_key_value->lenc_key, + btc_dm_cb.pairing_cb.ble.is_lenc_key_rcvd = TRUE; + memcpy(&btc_dm_cb.pairing_cb.ble.lenc_key, &p_data->ble_key.p_key_value->lenc_key, sizeof(tBTM_LE_LENC_KEYS)); memcpy(¶m.ble_security.ble_key.p_key_value.lenc_key, &p_data->ble_key.p_key_value->lenc_key, sizeof(tBTM_LE_LENC_KEYS)); @@ -730,8 +729,8 @@ void btc_dm_sec_cb_handler(btc_msg_t *msg) } case BTM_LE_KEY_LCSRK: { BTC_TRACE_DEBUG("Rcv BTA_LE_KEY_LCSRK"); - pairing_cb.ble.is_lcsrk_key_rcvd = TRUE; - memcpy(&pairing_cb.ble.lcsrk_key, &p_data->ble_key.p_key_value->lcsrk_key, + btc_dm_cb.pairing_cb.ble.is_lcsrk_key_rcvd = TRUE; + memcpy(&btc_dm_cb.pairing_cb.ble.lcsrk_key, &p_data->ble_key.p_key_value->lcsrk_key, sizeof(tBTM_LE_LCSRK_KEYS)); memcpy(¶m.ble_security.ble_key.p_key_value.lcsrk_key, &p_data->ble_key.p_key_value->lcsrk_key, sizeof(tBTM_LE_LCSRK_KEYS)); @@ -739,7 +738,7 @@ void btc_dm_sec_cb_handler(btc_msg_t *msg) } case BTM_LE_KEY_LID: { BTC_TRACE_DEBUG("Rcv BTA_LE_KEY_LID"); - pairing_cb.ble.is_lidk_key_rcvd = TRUE; + btc_dm_cb.pairing_cb.ble.is_lidk_key_rcvd = TRUE; break; } default: @@ -778,20 +777,20 @@ void btc_dm_sec_cb_handler(btc_msg_t *msg) ble_msg.act = ESP_GAP_BLE_LOCAL_IR_EVT; memcpy(¶m.ble_security.ble_id_keys, &p_data->ble_id_keys, sizeof(tBTA_BLE_LOCAL_ID_KEYS)); BTC_TRACE_DEBUG("BTA_DM_BLE_LOCAL_IR_EVT. "); - ble_local_key_cb.is_id_keys_rcvd = TRUE; - memcpy(&ble_local_key_cb.id_keys.irk[0], + btc_dm_cb.ble_local_key_cb.is_id_keys_rcvd = TRUE; + memcpy(&btc_dm_cb.ble_local_key_cb.id_keys.irk[0], &p_data->ble_id_keys.irk[0], sizeof(BT_OCTET16)); - memcpy(&ble_local_key_cb.id_keys.ir[0], + memcpy(&btc_dm_cb.ble_local_key_cb.id_keys.ir[0], &p_data->ble_id_keys.ir[0], sizeof(BT_OCTET16)); - memcpy(&ble_local_key_cb.id_keys.dhk[0], + memcpy(&btc_dm_cb.ble_local_key_cb.id_keys.dhk[0], &p_data->ble_id_keys.dhk[0], sizeof(BT_OCTET16)); - btc_storage_add_ble_local_key( (char *)&ble_local_key_cb.id_keys.irk[0], + btc_storage_add_ble_local_key( (char *)&btc_dm_cb.ble_local_key_cb.id_keys.irk[0], BTC_LE_LOCAL_KEY_IRK, BT_OCTET16_LEN); - btc_storage_add_ble_local_key( (char *)&ble_local_key_cb.id_keys.ir[0], + btc_storage_add_ble_local_key( (char *)&btc_dm_cb.ble_local_key_cb.id_keys.ir[0], BTC_LE_LOCAL_KEY_IR, BT_OCTET16_LEN); - btc_storage_add_ble_local_key( (char *)&ble_local_key_cb.id_keys.dhk[0], + btc_storage_add_ble_local_key( (char *)&btc_dm_cb.ble_local_key_cb.id_keys.dhk[0], BTC_LE_LOCAL_KEY_DHK, BT_OCTET16_LEN); break; @@ -801,9 +800,9 @@ void btc_dm_sec_cb_handler(btc_msg_t *msg) ble_msg.act = ESP_GAP_BLE_LOCAL_ER_EVT; memcpy(¶m.ble_security.ble_id_keys, &p_data->ble_id_keys, sizeof(tBTA_BLE_LOCAL_ID_KEYS)); BTC_TRACE_DEBUG("BTA_DM_BLE_LOCAL_ER_EVT. "); - ble_local_key_cb.is_er_rcvd = TRUE; - memcpy(&ble_local_key_cb.er[0], &p_data->ble_er[0], sizeof(BT_OCTET16)); - btc_storage_add_ble_local_key( (char *)&ble_local_key_cb.er[0], + btc_dm_cb.ble_local_key_cb.is_er_rcvd = TRUE; + memcpy(&btc_dm_cb.ble_local_key_cb.er[0], &p_data->ble_er[0], sizeof(BT_OCTET16)); + btc_storage_add_ble_local_key( (char *)&btc_dm_cb.ble_local_key_cb.er[0], BTC_LE_LOCAL_KEY_ER, BT_OCTET16_LEN); break; diff --git a/components/bt/bluedroid/btc/core/btc_manage.c b/components/bt/bluedroid/btc/core/btc_manage.c index 81ecad4103..08afcb7543 100644 --- a/components/bt/bluedroid/btc/core/btc_manage.c +++ b/components/bt/bluedroid/btc/core/btc_manage.c @@ -19,7 +19,11 @@ #include "esp_bt_defs.h" #include "esp_gatt_defs.h" -static void *btc_profile_cb_tab[BTC_PID_NUM] = {}; +#if BTC_DYNAMIC_MENDRY == FALSE +void *btc_profile_cb_tab[BTC_PID_NUM] = {}; +#else +void **btc_profile_cb_tab; +#endif void esp_profile_cb_reset(void) { diff --git a/components/bt/bluedroid/btc/core/btc_task.c b/components/bt/bluedroid/btc/core/btc_task.c index 8b787405bc..e77f5ac4b9 100644 --- a/components/bt/bluedroid/btc/core/btc_task.c +++ b/components/bt/bluedroid/btc/core/btc_task.c @@ -21,12 +21,14 @@ #include "common/bt_defs.h" #include "osi/allocator.h" #include "btc/btc_main.h" +#include "btc/btc_manage.h" #include "btc/btc_dev.h" #include "btc_gatts.h" #include "btc_gattc.h" #include "btc_gatt_common.h" #include "btc_gap_ble.h" #include "btc_blufi_prf.h" +#include "blufi_int.h" #include "btc/btc_dm.h" #include "btc/btc_alarm.h" #include "bta/bta_gatt_api.h" @@ -38,6 +40,7 @@ #if BTC_AV_INCLUDED #include "btc_av.h" #include "btc_avrc.h" +#include "btc_av_co.h" #endif /* #if BTC_AV_INCLUDED */ #if (BTC_SPP_INCLUDED == TRUE) #include "btc_spp.h" @@ -54,7 +57,7 @@ static osi_thread_t *btc_thread; -static btc_func_t profile_tab[BTC_PID_NUM] = { +static const btc_func_t profile_tab[BTC_PID_NUM] = { [BTC_PID_MAIN_INIT] = {btc_main_call_handler, NULL }, [BTC_PID_DEV] = {btc_dev_call_handler, NULL }, #if (GATTS_INCLUDED == TRUE) @@ -168,6 +171,94 @@ bt_status_t btc_transfer_context(btc_msg_t *msg, void *arg, int arg_len, btc_arg } +#if BTC_DYNAMIC_MENDRY +static bt_status_t btc_init_mem(void) { + if ((btc_dm_cb_ptr = (btc_dm_cb_t *)osi_malloc(sizeof(btc_dm_cb_t))) == NULL) { + return BT_STATUS_NOMEM; + } + memset((void *)btc_dm_cb_ptr, 0, sizeof(btc_dm_cb_t)); + + if ((btc_profile_cb_tab = (void **)osi_malloc(sizeof(void *) * BTC_PID_NUM)) == NULL) { + return BT_STATUS_NOMEM; + } + memset((void *)btc_profile_cb_tab, 0, sizeof(void *) * BTC_PID_NUM); + + if ((gl_bta_adv_data_ptr = (tBTA_BLE_ADV_DATA *)osi_malloc(sizeof(tBTA_BLE_ADV_DATA))) == NULL) { + return BT_STATUS_NOMEM; + } + memset((void *)gl_bta_adv_data_ptr, 0, sizeof(tBTA_BLE_ADV_DATA)); + + if ((gl_bta_scan_rsp_data_ptr = (tBTA_BLE_ADV_DATA *)osi_malloc(sizeof(tBTA_BLE_ADV_DATA))) == NULL) { + return BT_STATUS_NOMEM; + } + memset((void *)gl_bta_scan_rsp_data_ptr, 0, sizeof(tBTA_BLE_ADV_DATA)); + +#if GATTS_INCLUDED == TRUE && GATT_DYNAMIC_MEMORY == TRUE + if ((btc_creat_tab_env_ptr = (esp_btc_creat_tab_t *)osi_malloc(sizeof(esp_btc_creat_tab_t))) == NULL) { + return BT_STATUS_NOMEM; + } + memset((void *)btc_creat_tab_env_ptr, 0, sizeof(esp_btc_creat_tab_t)); + + if ((blufi_env_ptr = (tBLUFI_ENV *)osi_malloc(sizeof(tBLUFI_ENV))) == NULL) { + return BT_STATUS_NOMEM; + } + memset((void *)blufi_env_ptr, 0, sizeof(tBLUFI_ENV)); +#endif + +#if BTC_HF_CLIENT_INCLUDED == TRUE && HFP_DYNAMIC_MEMORY == TRUE + if ((hf_client_local_param_ptr = (hf_client_local_param_t *)osi_malloc(sizeof(hf_client_local_param_t))) == NULL) { + return BT_STATUS_NOMEM; + } + memset((void *)hf_client_local_param_ptr, 0, sizeof(hf_client_local_param_t)); +#endif + +#if BTC_AV_INCLUDED == TRUE && AVRC_DYNAMIC_MEMORY == TRUE + if ((btc_rc_vb_ptr = (btc_rc_cb_t *)osi_malloc(sizeof(btc_rc_cb_t))) == NULL) { + return BT_STATUS_NOMEM; + } + memset((void *)btc_rc_vb_ptr, 0, sizeof(btc_rc_cb_t)); + if ((bta_av_co_cb_ptr = (tBTA_AV_CO_CB *)osi_malloc(sizeof(tBTA_AV_CO_CB))) == NULL) { + return BT_STATUS_NOMEM; + } + memset((void *)bta_av_co_cb_ptr, 0, sizeof(tBTA_AV_CO_CB)); +#endif + + return BT_STATUS_SUCCESS; +} + +static void btc_deinit_mem(void) { + osi_free(btc_dm_cb_ptr); + btc_dm_cb_ptr = NULL; + + osi_free(btc_profile_cb_tab); + btc_profile_cb_tab = NULL; + + osi_free(gl_bta_adv_data_ptr); + gl_bta_adv_data_ptr = NULL; + + osi_free(gl_bta_scan_rsp_data_ptr); + gl_bta_scan_rsp_data_ptr = NULL; + +#if GATTS_INCLUDED == TRUE && GATT_DYNAMIC_MEMORY == TRUE + osi_free(btc_creat_tab_env_ptr); + btc_creat_tab_env_ptr = NULL; + osi_free(blufi_env_ptr); + blufi_env_ptr = NULL; +#endif + +#if BTC_HF_CLIENT_INCLUDED == TRUE && HFP_DYNAMIC_MEMORY == TRUE + osi_free(hf_client_local_param_ptr); + hf_client_local_param_ptr = NULL; +#endif + +#if BTC_AV_INCLUDED == TRUE && AVRC_DYNAMIC_MEMORY == TRUE + osi_free(btc_rc_vb_ptr); + btc_rc_vb_ptr = NULL; + osi_free(bta_av_co_cb_ptr); + bta_av_co_cb_ptr = NULL; +#endif +} +#endif int btc_init(void) { @@ -176,6 +267,12 @@ int btc_init(void) return BT_STATUS_NOMEM; } +#if BTC_DYNAMIC_MENDRY + if (btc_init_mem() != BT_STATUS_SUCCESS){ + return BT_STATUS_NOMEM; + } +#endif + btc_gap_callback_init(); #if SCAN_QUEUE_CONGEST_CHECK btc_adv_list_init(); @@ -186,8 +283,13 @@ int btc_init(void) void btc_deinit(void) { +#if BTC_DYNAMIC_MENDRY + btc_deinit_mem(); +#endif + osi_thread_free(btc_thread); btc_thread = NULL; + #if SCAN_QUEUE_CONGEST_CHECK btc_adv_list_deinit(); #endif diff --git a/components/bt/bluedroid/btc/include/btc/btc_dm.h b/components/bt/bluedroid/btc/include/btc/btc_dm.h index b6e7741ef6..1accc3970b 100644 --- a/components/bt/bluedroid/btc/include/btc/btc_dm.h +++ b/components/bt/bluedroid/btc/include/btc/btc_dm.h @@ -66,7 +66,21 @@ typedef struct btc_dm_local_key_id_t id_keys; /* ID kyes */ } btc_dm_local_key_cb_t; +typedef struct +{ + tBTA_SERVICE_MASK btc_enabled_services; +#if (SMP_INCLUDED == TRUE) + btc_dm_pairing_cb_t pairing_cb; + btc_dm_local_key_cb_t ble_local_key_cb; +#endif +} btc_dm_cb_t; +#if BTC_DYNAMIC_MENDRY == FALSE +extern btc_dm_cb_t btc_dm_cb; +#else +extern btc_dm_cb_t *btc_dm_cb_ptr; +#define btc_dm_cb (*btc_dm_cb_ptr) +#endif // void btc_dm_call_handler(btc_msg_t *msg); void btc_dm_sec_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC *data); diff --git a/components/bt/bluedroid/btc/include/btc/btc_manage.h b/components/bt/bluedroid/btc/include/btc/btc_manage.h index 46f746e8df..bd031a0e89 100644 --- a/components/bt/bluedroid/btc/include/btc/btc_manage.h +++ b/components/bt/bluedroid/btc/include/btc/btc_manage.h @@ -19,6 +19,11 @@ #include "btc/btc_task.h" #include "esp_bt_defs.h" +#if BTC_DYNAMIC_MENDRY == FALSE +extern void *btc_profile_cb_tab[BTC_PID_NUM]; +#else +extern void **btc_profile_cb_tab; +#endif /* reset gatt callback table */ void esp_profile_cb_reset(void); diff --git a/components/bt/bluedroid/btc/profile/esp/blufi/blufi_prf.c b/components/bt/bluedroid/btc/profile/esp/blufi/blufi_prf.c index 45c220b3ba..25ebba40d8 100644 --- a/components/bt/bluedroid/btc/profile/esp/blufi/blufi_prf.c +++ b/components/bt/bluedroid/btc/profile/esp/blufi/blufi_prf.c @@ -55,13 +55,17 @@ #define BLUFI_HDL_NUM 6 +#if GATT_DYNAMIC_MEMORY == FALSE tBLUFI_ENV blufi_env; +#else +tBLUFI_ENV *blufi_env_ptr; +#endif -static /* const */ tBT_UUID blufi_srvc_uuid = {LEN_UUID_16, {BLUFI_SERVICE_UUID}}; -static /* const */ tBT_UUID blufi_char_uuid_p2e = {LEN_UUID_16, {BLUFI_CHAR_P2E_UUID}}; -static /* const */ tBT_UUID blufi_char_uuid_e2p = {LEN_UUID_16, {BLUFI_CHAR_E2P_UUID}}; -static /* const */ tBT_UUID blufi_descr_uuid_e2p = {LEN_UUID_16, {BLUFI_DESCR_E2P_UUID}}; -static /* const */ tBT_UUID blufi_app_uuid = {LEN_UUID_16, {BLUFI_APP_UUID}}; +static const tBT_UUID blufi_srvc_uuid = {LEN_UUID_16, {BLUFI_SERVICE_UUID}}; +static const tBT_UUID blufi_char_uuid_p2e = {LEN_UUID_16, {BLUFI_CHAR_P2E_UUID}}; +static const tBT_UUID blufi_char_uuid_e2p = {LEN_UUID_16, {BLUFI_CHAR_E2P_UUID}}; +static const tBT_UUID blufi_descr_uuid_e2p = {LEN_UUID_16, {BLUFI_DESCR_E2P_UUID}}; +static const tBT_UUID blufi_app_uuid = {LEN_UUID_16, {BLUFI_APP_UUID}}; // static functions declare static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data); @@ -189,7 +193,7 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id, p_data->req_data.status, NULL); } - + if (p_data->req_data.p_data->write_req.handle == blufi_env.handle_char_p2e) { btc_blufi_recv_handler(&p_data->req_data.p_data->write_req.value[0], p_data->req_data.p_data->write_req.len); @@ -363,7 +367,7 @@ static void btc_blufi_send_notify(uint8_t *pkt, int pkt_len) UINT16 conn_id = blufi_env.conn_id; UINT16 attr_id = blufi_env.handle_char_e2p; bool rsp = false; - + BTA_GATTS_HandleValueIndication(conn_id, attr_id, pkt_len, pkt, rsp); } @@ -479,7 +483,7 @@ void btc_blufi_send_encap(uint8_t type, uint8_t *data, int total_data_len) hdr->type = type; hdr->fc |= BLUFI_FC_DIR_E2P; hdr->seq = blufi_env.send_seq++; - + if (BLUFI_TYPE_IS_CTRL(hdr->type)) { if ((blufi_env.sec_mode & BLUFI_CTRL_SEC_MODE_CHECK_MASK) && (blufi_env.cbs && blufi_env.cbs->checksum_func)) { @@ -1052,7 +1056,7 @@ void btc_blufi_call_deep_free(btc_msg_t *msg) case BTC_BLUFI_ACT_SEND_CUSTOM_DATA:{ uint8_t *data = arg->custom_data.data; if(data) { - osi_free(data); + osi_free(data); } break; } diff --git a/components/bt/bluedroid/btc/profile/esp/blufi/blufi_protocol.c b/components/bt/bluedroid/btc/profile/esp/blufi/blufi_protocol.c index b962d10051..ab81eac507 100644 --- a/components/bt/bluedroid/btc/profile/esp/blufi/blufi_protocol.c +++ b/components/bt/bluedroid/btc/profile/esp/blufi/blufi_protocol.c @@ -36,7 +36,7 @@ //#include "esp_wifi.h" #if (GATTS_INCLUDED == TRUE) -extern tBLUFI_ENV blufi_env; +// extern tBLUFI_ENV blufi_env; void btc_blufi_protocol_handler(uint8_t type, uint8_t *data, int len) { diff --git a/components/bt/bluedroid/btc/profile/esp/blufi/include/blufi_int.h b/components/bt/bluedroid/btc/profile/esp/blufi/include/blufi_int.h index 08be6703f5..cd6f5a200b 100644 --- a/components/bt/bluedroid/btc/profile/esp/blufi/include/blufi_int.h +++ b/components/bt/bluedroid/btc/profile/esp/blufi/include/blufi_int.h @@ -24,10 +24,10 @@ typedef struct { /* Protocol reference */ tGATT_IF gatt_if; UINT8 srvc_inst; - UINT16 handle_srvc; - UINT16 handle_char_p2e; - UINT16 handle_char_e2p; - UINT16 handle_descr_e2p; + UINT16 handle_srvc; + UINT16 handle_char_p2e; + UINT16 handle_char_e2p; + UINT16 handle_descr_e2p; UINT16 conn_id; BOOLEAN is_connected; BD_ADDR remote_bda; @@ -68,17 +68,24 @@ struct blufi_frag_hdr { }; typedef struct blufi_frag_hdr blufi_frag_hdr_t; -#define BLUFI_DATA_SEC_MODE_CHECK_MASK 0x01 -#define BLUFI_DATA_SEC_MODE_ENC_MASK 0x02 -#define BLUFI_CTRL_SEC_MODE_CHECK_MASK 0x10 +#if GATT_DYNAMIC_MEMORY == FALSE +extern tBLUFI_ENV blufi_env; +#else +extern tBLUFI_ENV *blufi_env_ptr; +#define blufi_env (*blufi_env_ptr) +#endif + +#define BLUFI_DATA_SEC_MODE_CHECK_MASK 0x01 +#define BLUFI_DATA_SEC_MODE_ENC_MASK 0x02 +#define BLUFI_CTRL_SEC_MODE_CHECK_MASK 0x10 #define BLUFI_CTRL_SEC_MODE_ENC_MASK 0x20 #define BLUFI_MAX_DATA_LEN 255 // packet type #define BLUFI_TYPE_MASK 0x03 -#define BLUFI_TYPE_SHIFT 0 +#define BLUFI_TYPE_SHIFT 0 #define BLUFI_SUBTYPE_MASK 0xFC -#define BLUFI_SUBTYPE_SHIFT 2 +#define BLUFI_SUBTYPE_SHIFT 2 #define BLUFI_GET_TYPE(type) ((type) & BLUFI_TYPE_MASK) #define BLUFI_GET_SUBTYPE(type) (((type) & BLUFI_SUBTYPE_MASK) >>BLUFI_SUBTYPE_SHIFT) @@ -161,12 +168,12 @@ typedef struct blufi_frag_hdr blufi_frag_hdr_t; #define BLUFI_FC_REQ_ACK 0x08 #define BLUFI_FC_FRAG 0x10 -#define BLUFI_FC_IS_ENC(fc) ((fc) & BLUFI_FC_ENC_MASK) -#define BLUFI_FC_IS_CHECK(fc) ((fc) & BLUFI_FC_CHECK_MASK) -#define BLUFI_FC_IS_DIR_P2E(fc) ((fc) & BLUFI_FC_DIR_P2E_MASK) -#define BLUFI_FC_IS_DIR_E2P(fc) (!((fc) & BLUFI_DIR_P2E_MASK)) -#define BLUFI_FC_IS_REQ_ACK(fc) ((fc) & BLUFI_FC_REQ_ACK_MASK) -#define BLUFI_FC_IS_FRAG(fc) ((fc) & BLUFI_FC_FRAG_MASK) +#define BLUFI_FC_IS_ENC(fc) ((fc) & BLUFI_FC_ENC_MASK) +#define BLUFI_FC_IS_CHECK(fc) ((fc) & BLUFI_FC_CHECK_MASK) +#define BLUFI_FC_IS_DIR_P2E(fc) ((fc) & BLUFI_FC_DIR_P2E_MASK) +#define BLUFI_FC_IS_DIR_E2P(fc) (!((fc) & BLUFI_DIR_P2E_MASK)) +#define BLUFI_FC_IS_REQ_ACK(fc) ((fc) & BLUFI_FC_REQ_ACK_MASK) +#define BLUFI_FC_IS_FRAG(fc) ((fc) & BLUFI_FC_FRAG_MASK) /* BLUFI HEADER + TOTAL(REMAIN) LENGTH + CRC + L2CAP RESERVED */ #define BLUFI_MTU_RESERVED_SIZE (sizeof(struct blufi_hdr) + 2 + 2 + 3) diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/bta_av_co.c b/components/bt/bluedroid/btc/profile/std/a2dp/bta_av_co.c index 2e72bd8cba..a3250cdac5 100644 --- a/components/bt/bluedroid/btc/profile/std/a2dp/bta_av_co.c +++ b/components/bt/bluedroid/btc/profile/std/a2dp/bta_av_co.c @@ -105,58 +105,12 @@ const tA2D_SBC_CIE btc_av_sbc_default_config = { A2D_SBC_IE_MIN_BITPOOL /* min_bitpool */ }; - -/***************************************************************************** -** Local data -*****************************************************************************/ -typedef struct { - UINT8 sep_info_idx; /* local SEP index (in BTA tables) */ - UINT8 seid; /* peer SEP index (in peer tables) */ - UINT8 codec_type; /* peer SEP codec type */ - UINT8 codec_caps[AVDT_CODEC_SIZE]; /* peer SEP codec capabilities */ - UINT8 num_protect; /* peer SEP number of CP elements */ - UINT8 protect_info[BTA_AV_CP_INFO_LEN]; /* peer SEP content protection info */ -} tBTA_AV_CO_SINK; - -typedef struct { - BD_ADDR addr; /* address of audio/video peer */ - tBTA_AV_CO_SINK snks[BTC_SV_AV_AA_SEP_INDEX]; /* array of supported sinks */ - tBTA_AV_CO_SINK srcs[BTC_SV_AV_AA_SEP_INDEX]; /* array of supported srcs */ - UINT8 num_snks; /* total number of sinks at peer */ - UINT8 num_srcs; /* total number of srcs at peer */ - UINT8 num_seps; /* total number of seids at peer */ - UINT8 num_rx_snks; /* number of received sinks */ - UINT8 num_rx_srcs; /* number of received srcs */ - UINT8 num_sup_snks; /* number of supported sinks in the snks array */ - UINT8 num_sup_srcs; /* number of supported srcs in the srcs array */ - tBTA_AV_CO_SINK *p_snk; /* currently selected sink */ - tBTA_AV_CO_SINK *p_src; /* currently selected src */ - UINT8 codec_cfg[AVDT_CODEC_SIZE]; /* current codec configuration */ - BOOLEAN cp_active; /* current CP configuration */ - BOOLEAN acp; /* acceptor */ - BOOLEAN recfg_needed; /* reconfiguration is needed */ - BOOLEAN opened; /* opened */ - UINT16 mtu; /* maximum transmit unit size */ - UINT16 uuid_to_connect; /* uuid of peer device */ -} tBTA_AV_CO_PEER; - -typedef struct { - BOOLEAN active; - UINT8 flag; -} tBTA_AV_CO_CP; - -typedef struct { - /* Connected peer information */ - tBTA_AV_CO_PEER peers[BTA_AV_NUM_STRS]; - /* Current codec configuration - access to this variable must be protected */ - tBTC_AV_CODEC_INFO codec_cfg; - tBTC_AV_CODEC_INFO codec_cfg_setconfig; /* remote peer setconfig preference */ - - tBTA_AV_CO_CP cp; -} tBTA_AV_CO_CB; - /* Control block instance */ -static tBTA_AV_CO_CB bta_av_co_cb; +#if AVRC_DYNAMIC_MEMORY == FALSE +tBTA_AV_CO_CB bta_av_co_cb; +#else +tBTA_AV_CO_CB *bta_av_co_cb_ptr; +#endif static BOOLEAN bta_av_co_audio_codec_build_config(const UINT8 *p_codec_caps, UINT8 *p_codec_cfg); static void bta_av_co_audio_peer_reset_config(tBTA_AV_CO_PEER *p_peer); @@ -1735,7 +1689,7 @@ BOOLEAN bta_av_co_get_remote_bitpool_pref(UINT8 *min, UINT8 *max) } /* the call out functions for audio stream */ -tBTA_AV_CO_FUNCTS bta_av_a2d_cos = { +const tBTA_AV_CO_FUNCTS bta_av_a2d_cos = { bta_av_co_audio_init, bta_av_co_audio_disc_res, bta_av_co_audio_getconfig, diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c index d25a1e5de5..ad1f5558b6 100644 --- a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c +++ b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c @@ -112,6 +112,15 @@ typedef struct { UINT32 sample_rate; } tBTC_A2DP_SINK_CB; +typedef struct { + tBTC_A2DP_SINK_CB btc_aa_snk_cb; + future_t *btc_a2dp_sink_future; + osi_thread_t *btc_aa_snk_task_hdl; + OI_CODEC_SBC_DECODER_CONTEXT context; + OI_UINT32 contextData[CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS)]; + OI_INT16 pcmData[15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS]; +} a2dp_sink_local_param_t; + static void btc_a2dp_sink_thread_init(UNUSED_ATTR void *context); static void btc_a2dp_sink_thread_cleanup(UNUSED_ATTR void *context); static void btc_a2dp_sink_flush_q(fixed_queue_t *p_q); @@ -128,11 +137,14 @@ static void btc_a2dp_sink_ctrl_handler(void *arg); static void btc_a2dp_sink_data_ready(void *context); -static tBTC_A2DP_SINK_CB btc_aa_snk_cb; static int btc_a2dp_sink_state = BTC_A2DP_SINK_STATE_OFF; -static future_t *btc_a2dp_sink_future = NULL; -static osi_thread_t *btc_aa_snk_task_hdl = NULL; static esp_a2d_sink_data_cb_t bt_aa_snk_data_cb = NULL; +#if A2D_DYNAMIC_MEMORY == FALSE +static a2dp_sink_local_param_t a2dp_sink_local_param; +#else +static a2dp_sink_local_param_t *a2dp_sink_local_param_ptr; +#define a2dp_sink_local_param (*a2dp_sink_local_param_ptr) +#endif ///A2D_DYNAMIC_MEMORY == FALSE void btc_a2dp_sink_reg_data_cb(esp_a2d_sink_data_cb_t callback) { @@ -148,21 +160,6 @@ static inline void btc_a2d_data_cb_to_app(const uint8_t *data, uint32_t len) } } -#define BTC_SBC_DEC_CONTEXT_DATA_LEN (CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS)) -#define BTC_SBC_DEC_PCM_DATA_LEN (15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS) - -#if BTC_SBC_DEC_DYNAMIC_MEMORY == FALSE -static OI_CODEC_SBC_DECODER_CONTEXT btc_sbc_decoder_context; -static OI_UINT32 btc_sbc_decoder_context_data[BTC_SBC_DEC_CONTEXT_DATA_LEN]; -static OI_INT16 btc_sbc_pcm_data[BTC_SBC_DEC_PCM_DATA_LEN]; -#else -static OI_CODEC_SBC_DECODER_CONTEXT *btc_sbc_decoder_context_ptr; -static OI_UINT32 *btc_sbc_decoder_context_data; -static OI_INT16 *btc_sbc_pcm_data; -#define btc_sbc_decoder_context (*btc_sbc_decoder_context_ptr) -#endif /* BTC_SBC_DEC_DYNAMIC_MEMORY == FALSE */ - - /***************************************************************************** ** Misc helper functions @@ -190,7 +187,7 @@ static bool btc_a2dp_sink_ctrl_post(uint32_t sig, void *param) evt->sig = sig; evt->param = param; - return osi_thread_post(btc_aa_snk_task_hdl, btc_a2dp_sink_ctrl_handler, evt, 0, OSI_THREAD_BLOCKING); + return osi_thread_post(a2dp_sink_local_param.btc_aa_snk_task_hdl, btc_a2dp_sink_ctrl_handler, evt, 0, OSI_THREAD_BLOCKING); } static void btc_a2dp_sink_ctrl_handler(void *arg) @@ -235,20 +232,18 @@ bool btc_a2dp_sink_startup(void) return false; } +#if A2D_DYNAMIC_MEMORY == TRUE + if ((a2dp_sink_local_param_ptr = (a2dp_sink_local_param_t *)osi_malloc(sizeof(a2dp_sink_local_param_t))) == NULL) { + APPL_TRACE_ERROR("%s malloc failed!", __func__); + return false; + } + memset((void *)a2dp_sink_local_param_ptr, 0, sizeof(a2dp_sink_local_param_t)); +#endif + APPL_TRACE_EVENT("## A2DP SINK START MEDIA THREAD ##"); -#if (BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE) - btc_sbc_decoder_context_ptr = osi_calloc(sizeof(OI_CODEC_SBC_DECODER_CONTEXT)); - btc_sbc_decoder_context_data = osi_calloc(BTC_SBC_DEC_CONTEXT_DATA_LEN * sizeof(OI_UINT32)); - btc_sbc_pcm_data = osi_calloc(BTC_SBC_DEC_PCM_DATA_LEN * sizeof(OI_INT16)); - if (!btc_sbc_decoder_context_ptr || !btc_sbc_decoder_context_data || !btc_sbc_pcm_data) { - APPL_TRACE_ERROR("failed to allocate SBC decoder"); - goto error_exit; - } -#endif /* BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE */ - - btc_aa_snk_task_hdl = osi_thread_create(BTC_A2DP_SINK_TASK_NAME, BTC_A2DP_SINK_TASK_STACK_SIZE, BTC_A2DP_SINK_TASK_PRIO, BTC_A2DP_SINK_TASK_PINNED_TO_CORE, 2); - if (btc_aa_snk_task_hdl == NULL) { + a2dp_sink_local_param.btc_aa_snk_task_hdl = osi_thread_create(BTC_A2DP_SINK_TASK_NAME, BTC_A2DP_SINK_TASK_STACK_SIZE, BTC_A2DP_SINK_TASK_PRIO, BTC_A2DP_SINK_TASK_PINNED_TO_CORE, 2); + if (a2dp_sink_local_param.btc_aa_snk_task_hdl == NULL) { goto error_exit; } @@ -262,25 +257,15 @@ bool btc_a2dp_sink_startup(void) error_exit:; APPL_TRACE_ERROR("%s unable to start up media thread\n", __func__); - if (btc_aa_snk_task_hdl != NULL) { - osi_thread_free(btc_aa_snk_task_hdl); - btc_aa_snk_task_hdl = NULL; + if (a2dp_sink_local_param.btc_aa_snk_task_hdl != NULL) { + osi_thread_free(a2dp_sink_local_param.btc_aa_snk_task_hdl); + a2dp_sink_local_param.btc_aa_snk_task_hdl = NULL; } -#if (BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE) - if (btc_sbc_decoder_context_ptr) { - osi_free(btc_sbc_decoder_context_ptr); - btc_sbc_decoder_context_ptr = NULL; - } - if (btc_sbc_decoder_context_data) { - osi_free(btc_sbc_decoder_context_data); - btc_sbc_decoder_context_data = NULL; - } - if (btc_sbc_pcm_data) { - osi_free(btc_sbc_pcm_data); - btc_sbc_pcm_data = NULL; - } -#endif /* BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE */ +#if A2D_DYNAMIC_MEMORY == TRUE + osi_free(a2dp_sink_local_param_ptr); + a2dp_sink_local_param_ptr = NULL; +#endif return false; } @@ -291,25 +276,19 @@ void btc_a2dp_sink_shutdown(void) // Exit thread btc_a2dp_sink_state = BTC_A2DP_SINK_STATE_SHUTTING_DOWN; - btc_a2dp_sink_future = future_new(); - assert(btc_a2dp_sink_future); + a2dp_sink_local_param.btc_a2dp_sink_future = future_new(); + assert(a2dp_sink_local_param.btc_a2dp_sink_future); btc_a2dp_sink_ctrl_post(BTC_MEDIA_TASK_SINK_CLEAN_UP, NULL); - future_await(btc_a2dp_sink_future); - btc_a2dp_sink_future = NULL; + future_await(a2dp_sink_local_param.btc_a2dp_sink_future); + a2dp_sink_local_param.btc_a2dp_sink_future = NULL; - osi_thread_free(btc_aa_snk_task_hdl); - btc_aa_snk_task_hdl = NULL; + osi_thread_free(a2dp_sink_local_param.btc_aa_snk_task_hdl); + a2dp_sink_local_param.btc_aa_snk_task_hdl = NULL; -#if (BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE) - osi_free(btc_sbc_decoder_context_ptr); - btc_sbc_decoder_context_ptr = NULL; - - osi_free(btc_sbc_decoder_context_data); - btc_sbc_decoder_context_data = NULL; - - osi_free(btc_sbc_pcm_data); - btc_sbc_pcm_data = NULL; -#endif /* BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE */ +#if A2D_DYNAMIC_MEMORY == TRUE + osi_free(a2dp_sink_local_param_ptr); + a2dp_sink_local_param_ptr = NULL; +#endif } /***************************************************************************** @@ -320,7 +299,7 @@ void btc_a2dp_sink_shutdown(void) void btc_a2dp_sink_on_idle(void) { - btc_aa_snk_cb.rx_flush = TRUE; + a2dp_sink_local_param.btc_aa_snk_cb.rx_flush = TRUE; btc_a2dp_sink_rx_flush_req(); btc_a2dp_sink_clear_track(); @@ -335,7 +314,7 @@ void btc_a2dp_sink_on_idle(void) void btc_a2dp_sink_on_stopped(tBTA_AV_SUSPEND *p_av) { - btc_aa_snk_cb.rx_flush = TRUE; + a2dp_sink_local_param.btc_aa_snk_cb.rx_flush = TRUE; btc_a2dp_sink_rx_flush_req(); btc_a2dp_control_set_datachnl_stat(FALSE); } @@ -348,14 +327,14 @@ void btc_a2dp_sink_on_stopped(tBTA_AV_SUSPEND *p_av) void btc_a2dp_sink_on_suspended(tBTA_AV_SUSPEND *p_av) { - btc_aa_snk_cb.rx_flush = TRUE; + a2dp_sink_local_param.btc_aa_snk_cb.rx_flush = TRUE; btc_a2dp_sink_rx_flush_req(); return; } static void btc_a2dp_sink_data_post(void) { - osi_thread_post(btc_aa_snk_task_hdl, btc_a2dp_sink_data_ready, NULL, 1, OSI_THREAD_BLOCKING); + osi_thread_post(a2dp_sink_local_param.btc_aa_snk_task_hdl, btc_a2dp_sink_data_ready, NULL, 1, OSI_THREAD_BLOCKING); } /******************************************************************************* @@ -376,7 +355,7 @@ static BOOLEAN btc_a2dp_sink_clear_track(void) void btc_a2dp_sink_set_rx_flush(BOOLEAN enable) { APPL_TRACE_EVENT("## DROP RX %d ##\n", enable); - btc_aa_snk_cb.rx_flush = enable; + a2dp_sink_local_param.btc_aa_snk_cb.rx_flush = enable; } /***************************************************************************** @@ -410,20 +389,20 @@ static void btc_a2dp_sink_data_ready(UNUSED_ATTR void *context) { tBT_SBC_HDR *p_msg; - if (fixed_queue_is_empty(btc_aa_snk_cb.RxSbcQ)) { + if (fixed_queue_is_empty(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ)) { APPL_TRACE_DEBUG(" QUE EMPTY "); } else { - if (btc_aa_snk_cb.rx_flush == TRUE) { - btc_a2dp_sink_flush_q(btc_aa_snk_cb.RxSbcQ); + if (a2dp_sink_local_param.btc_aa_snk_cb.rx_flush == TRUE) { + btc_a2dp_sink_flush_q(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ); return; } - while ((p_msg = (tBT_SBC_HDR *)fixed_queue_try_peek_first(btc_aa_snk_cb.RxSbcQ)) != NULL ) { + while ((p_msg = (tBT_SBC_HDR *)fixed_queue_try_peek_first(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ)) != NULL ) { if (btc_a2dp_sink_state != BTC_A2DP_SINK_STATE_ON){ return; } btc_a2dp_sink_handle_inc_media(p_msg); - p_msg = (tBT_SBC_HDR *)fixed_queue_try_dequeue(btc_aa_snk_cb.RxSbcQ); + p_msg = (tBT_SBC_HDR *)fixed_queue_try_dequeue(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ); if ( p_msg == NULL ) { APPL_TRACE_ERROR("Insufficient data in que "); break; @@ -463,13 +442,13 @@ static void btc_a2dp_sink_handle_decoder_reset(tBTC_MEDIA_SINK_CFG_UPDATE *p_msg return; } - btc_aa_snk_cb.sample_rate = btc_a2dp_sink_get_track_frequency(sbc_cie.samp_freq); - btc_aa_snk_cb.channel_count = btc_a2dp_sink_get_track_channel_count(sbc_cie.ch_mode); + a2dp_sink_local_param.btc_aa_snk_cb.sample_rate = btc_a2dp_sink_get_track_frequency(sbc_cie.samp_freq); + a2dp_sink_local_param.btc_aa_snk_cb.channel_count = btc_a2dp_sink_get_track_channel_count(sbc_cie.ch_mode); - btc_aa_snk_cb.rx_flush = FALSE; + a2dp_sink_local_param.btc_aa_snk_cb.rx_flush = FALSE; APPL_TRACE_EVENT("Reset to sink role"); - status = OI_CODEC_SBC_DecoderReset(&btc_sbc_decoder_context, btc_sbc_decoder_context_data, - BTC_SBC_DEC_CONTEXT_DATA_LEN * sizeof(OI_UINT32), 2, 2, FALSE, FALSE); + status = OI_CODEC_SBC_DecoderReset(&a2dp_sink_local_param.context, a2dp_sink_local_param.contextData, + sizeof(a2dp_sink_local_param.contextData), 2, 2, FALSE, FALSE); if (!OI_SUCCESS(status)) { APPL_TRACE_ERROR("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status); } @@ -585,14 +564,14 @@ static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg) UINT8 *sbc_start_frame = ((UINT8 *)(p_msg + 1) + p_msg->offset + 1); int count; UINT32 pcmBytes, availPcmBytes; - OI_INT16 *pcmDataPointer = btc_sbc_pcm_data; /*Will be overwritten on next packet receipt*/ + OI_INT16 *pcmDataPointer = a2dp_sink_local_param.pcmData; /*Will be overwritten on next packet receipt*/ OI_STATUS status; int num_sbc_frames = p_msg->num_frames_to_be_processed; UINT32 sbc_frame_len = p_msg->len - 1; - availPcmBytes = BTC_SBC_DEC_PCM_DATA_LEN * sizeof(OI_INT16); + availPcmBytes = sizeof(a2dp_sink_local_param.pcmData); /* XXX: Check if the below check is correct, we are checking for peer to be sink when we are sink */ - if (btc_av_get_peer_sep() == AVDT_TSEP_SNK || (btc_aa_snk_cb.rx_flush)) { + if (btc_av_get_peer_sep() == AVDT_TSEP_SNK || (a2dp_sink_local_param.btc_aa_snk_cb.rx_flush)) { APPL_TRACE_DEBUG(" State Changed happened in this tick "); return; } @@ -606,7 +585,7 @@ static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg) for (count = 0; count < num_sbc_frames && sbc_frame_len != 0; count ++) { pcmBytes = availPcmBytes; - status = OI_CODEC_SBC_DecodeFrame(&btc_sbc_decoder_context, (const OI_BYTE **)&sbc_start_frame, + status = OI_CODEC_SBC_DecodeFrame(&a2dp_sink_local_param.context, (const OI_BYTE **)&sbc_start_frame, (OI_UINT32 *)&sbc_frame_len, (OI_INT16 *)pcmDataPointer, (OI_UINT32 *)&pcmBytes); @@ -620,7 +599,7 @@ static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg) p_msg->len = sbc_frame_len + 1; } - btc_a2d_data_cb_to_app((uint8_t *)btc_sbc_pcm_data, (BTC_SBC_DEC_PCM_DATA_LEN * sizeof(OI_INT16) - availPcmBytes)); + btc_a2d_data_cb_to_app((uint8_t *)a2dp_sink_local_param.pcmData, (sizeof(a2dp_sink_local_param.pcmData) - availPcmBytes)); } /******************************************************************************* @@ -634,7 +613,7 @@ static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg) *******************************************************************************/ BOOLEAN btc_a2dp_sink_rx_flush_req(void) { - if (fixed_queue_is_empty(btc_aa_snk_cb.RxSbcQ) == TRUE) { /* Que is already empty */ + if (fixed_queue_is_empty(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ) == TRUE) { /* Que is already empty */ return TRUE; } @@ -655,7 +634,7 @@ static void btc_a2dp_sink_rx_flush(void) /* Flush all enqueued SBC buffers (encoded) */ APPL_TRACE_DEBUG("btc_a2dp_sink_rx_flush"); - btc_a2dp_sink_flush_q(btc_aa_snk_cb.RxSbcQ); + btc_a2dp_sink_flush_q(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ); } static int btc_a2dp_sink_get_track_frequency(UINT8 frequency) @@ -711,13 +690,13 @@ UINT8 btc_a2dp_sink_enque_buf(BT_HDR *p_pkt) return 0; } - if (btc_aa_snk_cb.rx_flush == TRUE) { /* Flush enabled, do not enque*/ - return fixed_queue_length(btc_aa_snk_cb.RxSbcQ); + if (a2dp_sink_local_param.btc_aa_snk_cb.rx_flush == TRUE) { /* Flush enabled, do not enque*/ + return fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ); } - if (fixed_queue_length(btc_aa_snk_cb.RxSbcQ) >= MAX_OUTPUT_A2DP_SNK_FRAME_QUEUE_SZ) { + if (fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ) >= MAX_OUTPUT_A2DP_SNK_FRAME_QUEUE_SZ) { APPL_TRACE_WARNING("Pkt dropped\n"); - return fixed_queue_length(btc_aa_snk_cb.RxSbcQ); + return fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ); } APPL_TRACE_DEBUG("btc_a2dp_sink_enque_buf + "); @@ -728,13 +707,13 @@ UINT8 btc_a2dp_sink_enque_buf(BT_HDR *p_pkt) memcpy(p_msg, p_pkt, (sizeof(BT_HDR) + p_pkt->offset + p_pkt->len)); p_msg->num_frames_to_be_processed = (*((UINT8 *)(p_msg + 1) + p_msg->offset)) & 0x0f; APPL_TRACE_VERBOSE("btc_a2dp_sink_enque_buf %d + \n", p_msg->num_frames_to_be_processed); - fixed_queue_enqueue(btc_aa_snk_cb.RxSbcQ, p_msg); + fixed_queue_enqueue(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, p_msg); btc_a2dp_sink_data_post(); } else { /* let caller deal with a failed allocation */ APPL_TRACE_WARNING("btc_a2dp_sink_enque_buf No Buffer left - "); } - return fixed_queue_length(btc_aa_snk_cb.RxSbcQ); + return fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ); } static void btc_a2dp_sink_handle_clear_track (void) @@ -761,11 +740,11 @@ static void btc_a2dp_sink_flush_q(fixed_queue_t *p_q) static void btc_a2dp_sink_thread_init(UNUSED_ATTR void *context) { APPL_TRACE_EVENT("%s\n", __func__); - memset(&btc_aa_snk_cb, 0, sizeof(btc_aa_snk_cb)); + memset(&a2dp_sink_local_param.btc_aa_snk_cb, 0, sizeof(a2dp_sink_local_param.btc_aa_snk_cb)); btc_a2dp_sink_state = BTC_A2DP_SINK_STATE_ON; - btc_aa_snk_cb.RxSbcQ = fixed_queue_new(QUEUE_SIZE_MAX); + a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ = fixed_queue_new(QUEUE_SIZE_MAX); btc_a2dp_control_init(); } @@ -778,9 +757,9 @@ static void btc_a2dp_sink_thread_cleanup(UNUSED_ATTR void *context) btc_a2dp_control_cleanup(); - fixed_queue_free(btc_aa_snk_cb.RxSbcQ, osi_free_func); + fixed_queue_free(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, osi_free_func); - future_ready(btc_a2dp_sink_future, NULL); + future_ready(a2dp_sink_local_param.btc_a2dp_sink_future, NULL); } #endif /* BTC_AV_SINK_INCLUDED */ diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c index d6f12b69f1..430d6f5fff 100644 --- a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c +++ b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c @@ -165,9 +165,17 @@ typedef struct { tBTC_AV_FEEDING_MODE feeding_mode; tBTC_AV_MEDIA_FEEDINGS_STATE media_feeding_state; tBTC_AV_MEDIA_FEEDINGS media_feeding; + SBC_ENC_PARAMS encoder; osi_alarm_t *media_alarm; } tBTC_A2DP_SOURCE_CB; +typedef struct { + tBTC_A2DP_SOURCE_CB btc_aa_src_cb; + future_t *btc_a2dp_source_future; + osi_thread_t *btc_aa_src_task_hdl; + UINT64 last_frame_us; +} a2dp_source_local_param_t; + static void btc_a2dp_source_thread_init(UNUSED_ATTR void *context); static void btc_a2dp_source_thread_cleanup(UNUSED_ATTR void *context); static void btc_a2dp_source_flush_q(fixed_queue_t *p_q); @@ -185,19 +193,14 @@ static void btc_a2dp_source_handle_timer(UNUSED_ATTR void *context); static void btc_a2dp_source_encoder_init(void); static void btc_a2dp_source_ctrl_handler(void *arg); -static tBTC_A2DP_SOURCE_CB btc_aa_src_cb; static int btc_a2dp_source_state = BTC_A2DP_SOURCE_STATE_OFF; -static future_t *btc_a2dp_source_future = NULL; -static osi_thread_t *btc_aa_src_task_hdl = NULL; static esp_a2d_source_data_cb_t btc_aa_src_data_cb = NULL; -static UINT64 last_frame_us = 0; - -#if BTC_SBC_ENC_DYNAMIC_MEMORY == FALSE -static SBC_ENC_PARAMS btc_sbc_encoder; +#if A2D_DYNAMIC_MEMORY == FALSE +static a2dp_source_local_param_t a2dp_source_local_param; #else -static SBC_ENC_PARAMS *btc_sbc_encoder_ptr; -#define btc_sbc_encoder (*btc_sbc_encoder_ptr) -#endif /* BTC_SBC_ENC_DYNAMIC_MEMORY == FALSE */ +static a2dp_source_local_param_t *a2dp_source_local_param_ptr; +#define a2dp_source_local_param (*a2dp_source_local_param_ptr) +#endif ///A2D_DYNAMIC_MEMORY == FALSE void btc_a2dp_src_reg_data_cb(esp_a2d_source_data_cb_t callback) { @@ -232,7 +235,7 @@ static inline void btc_aa_cb_to_app(esp_a2d_cb_event_t event, esp_a2d_cb_param_t bool btc_a2dp_source_is_streaming(void) { - return btc_aa_src_cb.is_tx_timer == TRUE; + return a2dp_source_local_param.btc_aa_src_cb.is_tx_timer == TRUE; } bool btc_a2dp_source_is_task_shutting_down(void) @@ -251,7 +254,7 @@ static void btc_a2dp_source_ctrl_post(uint32_t sig, void *param) evt->sig = sig; evt->param = param; - osi_thread_post(btc_aa_src_task_hdl, btc_a2dp_source_ctrl_handler, evt, 0, OSI_THREAD_BLOCKING); + osi_thread_post(a2dp_source_local_param.btc_aa_src_task_hdl, btc_a2dp_source_ctrl_handler, evt, 0, OSI_THREAD_BLOCKING); } static void btc_a2dp_source_ctrl_handler(void *arg) @@ -305,18 +308,18 @@ bool btc_a2dp_source_startup(void) return false; } +#if A2D_DYNAMIC_MEMORY == TRUE + if ((a2dp_source_local_param_ptr = (a2dp_source_local_param_t *)osi_malloc(sizeof(a2dp_source_local_param_t))) == NULL) { + APPL_TRACE_ERROR("%s malloc failed!", __func__); + return false; + } + memset((void *)a2dp_source_local_param_ptr, 0, sizeof(a2dp_source_local_param_t)); +#endif + APPL_TRACE_EVENT("## A2DP SOURCE START MEDIA THREAD ##"); -#if BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE - btc_sbc_encoder_ptr = osi_calloc(sizeof(SBC_ENC_PARAMS)); - if (!btc_sbc_encoder_ptr) { - APPL_TRACE_ERROR("failed to allocate SBC encoder"); - goto error_exit; - } -#endif /* #if BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE */ - - btc_aa_src_task_hdl = osi_thread_create(BTC_A2DP_SOURCE_TASK_NAME, BTC_A2DP_SOURCE_TASK_STACK_SIZE, BTC_A2DP_SOURCE_TASK_PRIO, BTC_A2DP_SOURCE_TASK_PINNED_TO_CORE, 2); - if (btc_aa_src_task_hdl == NULL) { + a2dp_source_local_param.btc_aa_src_task_hdl = osi_thread_create(BTC_A2DP_SOURCE_TASK_NAME, BTC_A2DP_SOURCE_TASK_STACK_SIZE, BTC_A2DP_SOURCE_TASK_PRIO, BTC_A2DP_SOURCE_TASK_PINNED_TO_CORE, 2); + if (a2dp_source_local_param.btc_aa_src_task_hdl == NULL) { goto error_exit; } @@ -327,15 +330,13 @@ bool btc_a2dp_source_startup(void) error_exit:; APPL_TRACE_ERROR("%s unable to start up media thread\n", __func__); - osi_thread_free(btc_aa_src_task_hdl); - btc_aa_src_task_hdl = NULL; + osi_thread_free(a2dp_source_local_param.btc_aa_src_task_hdl); + a2dp_source_local_param.btc_aa_src_task_hdl = NULL; -#if (BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE) - if (btc_sbc_encoder_ptr) { - osi_free(btc_sbc_encoder_ptr); - btc_sbc_encoder_ptr = NULL; - } -#endif /* #if BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE */ +#if A2D_DYNAMIC_MEMORY == TRUE + osi_free(a2dp_source_local_param_ptr); + a2dp_source_local_param_ptr = NULL; +#endif return false; } @@ -346,19 +347,19 @@ void btc_a2dp_source_shutdown(void) // Exit thread btc_a2dp_source_state = BTC_A2DP_SOURCE_STATE_SHUTTING_DOWN; - btc_a2dp_source_future = future_new(); - assert(btc_a2dp_source_future); + a2dp_source_local_param.btc_a2dp_source_future = future_new(); + assert(a2dp_source_local_param.btc_a2dp_source_future); btc_a2dp_source_ctrl_post(BTC_MEDIA_TASK_CLEAN_UP, NULL); - future_await(btc_a2dp_source_future); - btc_a2dp_source_future = NULL; + future_await(a2dp_source_local_param.btc_a2dp_source_future); + a2dp_source_local_param.btc_a2dp_source_future = NULL; - osi_thread_free(btc_aa_src_task_hdl); - btc_aa_src_task_hdl = NULL; + osi_thread_free(a2dp_source_local_param.btc_aa_src_task_hdl); + a2dp_source_local_param.btc_aa_src_task_hdl = NULL; -#if (BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE) - osi_free(btc_sbc_encoder_ptr); - btc_sbc_encoder_ptr = NULL; -#endif /* #if BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE */ +#if A2D_DYNAMIC_MEMORY == TRUE + osi_free(a2dp_source_local_param_ptr); + a2dp_source_local_param_ptr = NULL; +#endif } /***************************************************************************** @@ -391,7 +392,7 @@ void btc_a2dp_source_on_stopped(tBTA_AV_SUSPEND *p_av) } /* ensure tx frames are immediately suspended */ - btc_aa_src_cb.tx_flush = 1; + a2dp_source_local_param.btc_aa_src_cb.tx_flush = 1; /* request to stop media task */ btc_a2dp_source_tx_flush_req(); @@ -419,7 +420,7 @@ void btc_a2dp_source_on_suspended(tBTA_AV_SUSPEND *p_av) /* once stream is fully stopped we will ack back */ /* ensure tx frames are immediately flushed */ - btc_aa_src_cb.tx_flush = 1; + a2dp_source_local_param.btc_aa_src_cb.tx_flush = 1; /* stop timer tick */ btc_a2dp_source_stop_audio_req(); @@ -427,7 +428,7 @@ void btc_a2dp_source_on_suspended(tBTA_AV_SUSPEND *p_av) static void btc_a2dp_source_data_post(void) { - osi_thread_post(btc_aa_src_task_hdl, btc_a2dp_source_handle_timer, NULL, 1, OSI_THREAD_BLOCKING); + osi_thread_post(a2dp_source_local_param.btc_aa_src_task_hdl, btc_a2dp_source_handle_timer, NULL, 1, OSI_THREAD_BLOCKING); } static UINT64 time_now_us() @@ -448,7 +449,7 @@ static void log_tstamps_us(char *comment) static UINT64 prev_us = 0; UINT64 now_us = time_now_us(); APPL_TRACE_DEBUG("[%s] ts %08llu, diff : %08llu, queue sz %d", comment, now_us, now_us - prev_us, - fixed_queue_length(btc_aa_src_cb.TxAaQ)); + fixed_queue_length(a2dp_source_local_param.btc_aa_src_cb.TxAaQ)); prev_us = now_us; UNUSED(prev_us); } @@ -457,7 +458,7 @@ static void log_tstamps_us(char *comment) void btc_a2dp_source_set_tx_flush(BOOLEAN enable) { APPL_TRACE_EVENT("## DROP TX %d ##", enable); - btc_aa_src_cb.tx_flush = enable; + a2dp_source_local_param.btc_aa_src_cb.tx_flush = enable; } /***************************************************************************** @@ -516,7 +517,7 @@ BT_HDR *btc_a2dp_source_audio_readbuf(void) if (btc_a2dp_source_state != BTC_A2DP_SOURCE_STATE_ON){ return NULL; } - return fixed_queue_try_dequeue(btc_aa_src_cb.TxAaQ); + return fixed_queue_try_dequeue(a2dp_source_local_param.btc_aa_src_cb.TxAaQ); } /******************************************************************************* @@ -776,35 +777,35 @@ static void btc_a2dp_source_enc_init(BT_HDR *p_msg) APPL_TRACE_DEBUG("btc_a2dp_source_enc_init"); - btc_aa_src_cb.timestamp = 0; + a2dp_source_local_param.btc_aa_src_cb.timestamp = 0; /* SBC encoder config (enforced even if not used) */ - btc_sbc_encoder.sbc_mode = SBC_MODE_STD; - btc_sbc_encoder.s16ChannelMode = pInitAudio->ChannelMode; - btc_sbc_encoder.s16NumOfSubBands = pInitAudio->NumOfSubBands; - btc_sbc_encoder.s16NumOfBlocks = pInitAudio->NumOfBlocks; - btc_sbc_encoder.s16AllocationMethod = pInitAudio->AllocationMethod; - btc_sbc_encoder.s16SamplingFreq = pInitAudio->SamplingFreq; + a2dp_source_local_param.btc_aa_src_cb.encoder.sbc_mode = SBC_MODE_STD; + a2dp_source_local_param.btc_aa_src_cb.encoder.s16ChannelMode = pInitAudio->ChannelMode; + a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfSubBands = pInitAudio->NumOfSubBands; + a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfBlocks = pInitAudio->NumOfBlocks; + a2dp_source_local_param.btc_aa_src_cb.encoder.s16AllocationMethod = pInitAudio->AllocationMethod; + a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq = pInitAudio->SamplingFreq; - btc_sbc_encoder.u16BitRate = btc_a2dp_source_get_sbc_rate(); + a2dp_source_local_param.btc_aa_src_cb.encoder.u16BitRate = btc_a2dp_source_get_sbc_rate(); /* Default transcoding is PCM to SBC, modified by feeding configuration */ - btc_aa_src_cb.TxTranscoding = BTC_MEDIA_TRSCD_PCM_2_SBC; - btc_aa_src_cb.TxAaMtuSize = ((BTC_MEDIA_AA_BUF_SIZE - BTC_MEDIA_AA_SBC_OFFSET - sizeof(BT_HDR)) + a2dp_source_local_param.btc_aa_src_cb.TxTranscoding = BTC_MEDIA_TRSCD_PCM_2_SBC; + a2dp_source_local_param.btc_aa_src_cb.TxAaMtuSize = ((BTC_MEDIA_AA_BUF_SIZE - BTC_MEDIA_AA_SBC_OFFSET - sizeof(BT_HDR)) < pInitAudio->MtuSize) ? (BTC_MEDIA_AA_BUF_SIZE - BTC_MEDIA_AA_SBC_OFFSET - sizeof(BT_HDR)) : pInitAudio->MtuSize; APPL_TRACE_EVENT("btc_a2dp_source_enc_init mtu %d, peer mtu %d", - btc_aa_src_cb.TxAaMtuSize, pInitAudio->MtuSize); + a2dp_source_local_param.btc_aa_src_cb.TxAaMtuSize, pInitAudio->MtuSize); APPL_TRACE_EVENT(" ch mode %d, subnd %d, nb blk %d, alloc %d, rate %d, freq %d", - btc_sbc_encoder.s16ChannelMode, btc_sbc_encoder.s16NumOfSubBands, - btc_sbc_encoder.s16NumOfBlocks, - btc_sbc_encoder.s16AllocationMethod, btc_sbc_encoder.u16BitRate, - btc_sbc_encoder.s16SamplingFreq); + a2dp_source_local_param.btc_aa_src_cb.encoder.s16ChannelMode, a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfSubBands, + a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfBlocks, + a2dp_source_local_param.btc_aa_src_cb.encoder.s16AllocationMethod, a2dp_source_local_param.btc_aa_src_cb.encoder.u16BitRate, + a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq); /* Reset entirely the SBC encoder */ - SBC_Encoder_Init(&(btc_sbc_encoder)); - APPL_TRACE_DEBUG("btc_a2dp_source_enc_init bit pool %d", btc_sbc_encoder.s16BitPool); + SBC_Encoder_Init(&(a2dp_source_local_param.btc_aa_src_cb.encoder)); + APPL_TRACE_DEBUG("btc_a2dp_source_enc_init bit pool %d", a2dp_source_local_param.btc_aa_src_cb.encoder.s16BitPool); } @@ -821,7 +822,7 @@ static void btc_a2dp_source_enc_init(BT_HDR *p_msg) static void btc_a2dp_source_enc_update(BT_HDR *p_msg) { tBTC_MEDIA_UPDATE_AUDIO *pUpdateAudio = (tBTC_MEDIA_UPDATE_AUDIO *) p_msg; - SBC_ENC_PARAMS *pstrEncParams = &btc_sbc_encoder; + SBC_ENC_PARAMS *pstrEncParams = &a2dp_source_local_param.btc_aa_src_cb.encoder; UINT16 s16SamplingFreq; SINT16 s16BitPool = 0; SINT16 s16BitRate; @@ -832,9 +833,9 @@ static void btc_a2dp_source_enc_update(BT_HDR *p_msg) pUpdateAudio->MinMtuSize, pUpdateAudio->MaxBitPool, pUpdateAudio->MinBitPool); /* Only update the bitrate and MTU size while timer is running to make sure it has been initialized */ - //if (btc_aa_src_cb.is_tx_timer) + //if (a2dp_source_local_param.btc_aa_src_cb.is_tx_timer) { - btc_aa_src_cb.TxAaMtuSize = ((BTC_MEDIA_AA_BUF_SIZE - + a2dp_source_local_param.btc_aa_src_cb.TxAaMtuSize = ((BTC_MEDIA_AA_BUF_SIZE - BTC_MEDIA_AA_SBC_OFFSET - sizeof(BT_HDR)) < pUpdateAudio->MinMtuSize) ? (BTC_MEDIA_AA_BUF_SIZE - BTC_MEDIA_AA_SBC_OFFSET - sizeof(BT_HDR)) : pUpdateAudio->MinMtuSize; @@ -913,19 +914,19 @@ static void btc_a2dp_source_enc_update(BT_HDR *p_msg) if (s16BitPool > pUpdateAudio->MaxBitPool) { APPL_TRACE_DEBUG("%s computed bitpool too large (%d)", __FUNCTION__, s16BitPool); /* Decrease bitrate */ - btc_sbc_encoder.u16BitRate -= BTC_MEDIA_BITRATE_STEP; + a2dp_source_local_param.btc_aa_src_cb.encoder.u16BitRate -= BTC_MEDIA_BITRATE_STEP; /* Record that we have decreased the bitrate */ protect |= 1; } else if (s16BitPool < pUpdateAudio->MinBitPool) { APPL_TRACE_WARNING("%s computed bitpool too small (%d)", __FUNCTION__, s16BitPool); /* Increase bitrate */ - UINT16 previous_u16BitRate = btc_sbc_encoder.u16BitRate; - btc_sbc_encoder.u16BitRate += BTC_MEDIA_BITRATE_STEP; + UINT16 previous_u16BitRate = a2dp_source_local_param.btc_aa_src_cb.encoder.u16BitRate; + a2dp_source_local_param.btc_aa_src_cb.encoder.u16BitRate += BTC_MEDIA_BITRATE_STEP; /* Record that we have increased the bitrate */ protect |= 2; /* Check over-flow */ - if (btc_sbc_encoder.u16BitRate < previous_u16BitRate) { + if (a2dp_source_local_param.btc_aa_src_cb.encoder.u16BitRate < previous_u16BitRate) { protect |= 3; } } else { @@ -942,10 +943,10 @@ static void btc_a2dp_source_enc_update(BT_HDR *p_msg) pstrEncParams->s16BitPool = s16BitPool; APPL_TRACE_DEBUG("%s final bit rate %d, final bit pool %d", __FUNCTION__, - btc_sbc_encoder.u16BitRate, btc_sbc_encoder.s16BitPool); + a2dp_source_local_param.btc_aa_src_cb.encoder.u16BitRate, a2dp_source_local_param.btc_aa_src_cb.encoder.s16BitPool); /* make sure we reinitialize encoder with new settings */ - SBC_Encoder_Init(&(btc_sbc_encoder)); + SBC_Encoder_Init(&(a2dp_source_local_param.btc_aa_src_cb.encoder)); } } @@ -976,10 +977,10 @@ static void btc_a2dp_source_pcm2sbc_init(tBTC_MEDIA_INIT_AUDIO_FEEDING *p_feedin case 32000: case 48000: /* For these sampling_freq the AV connection must be 48000 */ - if (btc_sbc_encoder.s16SamplingFreq != SBC_sf48000) { + if (a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq != SBC_sf48000) { /* Reconfiguration needed at 48000 */ APPL_TRACE_DEBUG("SBC Reconfiguration needed at 48000"); - btc_sbc_encoder.s16SamplingFreq = SBC_sf48000; + a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq = SBC_sf48000; reconfig_needed = TRUE; } break; @@ -988,10 +989,10 @@ static void btc_a2dp_source_pcm2sbc_init(tBTC_MEDIA_INIT_AUDIO_FEEDING *p_feedin case 22050: case 44100: /* For these sampling_freq the AV connection must be 44100 */ - if (btc_sbc_encoder.s16SamplingFreq != SBC_sf44100) { + if (a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq != SBC_sf44100) { /* Reconfiguration needed at 44100 */ APPL_TRACE_DEBUG("SBC Reconfiguration needed at 44100"); - btc_sbc_encoder.s16SamplingFreq = SBC_sf44100; + a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq = SBC_sf44100; reconfig_needed = TRUE; } break; @@ -1001,21 +1002,21 @@ static void btc_a2dp_source_pcm2sbc_init(tBTC_MEDIA_INIT_AUDIO_FEEDING *p_feedin } /* Some AV Headsets do not support Mono => always ask for Stereo */ - if (btc_sbc_encoder.s16ChannelMode == SBC_MONO) { + if (a2dp_source_local_param.btc_aa_src_cb.encoder.s16ChannelMode == SBC_MONO) { APPL_TRACE_DEBUG("SBC Reconfiguration needed in Stereo"); - btc_sbc_encoder.s16ChannelMode = SBC_JOINT_STEREO; + a2dp_source_local_param.btc_aa_src_cb.encoder.s16ChannelMode = SBC_JOINT_STEREO; reconfig_needed = TRUE; } if (reconfig_needed != FALSE) { - APPL_TRACE_DEBUG("%s :: mtu %d", __FUNCTION__, btc_aa_src_cb.TxAaMtuSize); + APPL_TRACE_DEBUG("%s :: mtu %d", __FUNCTION__, a2dp_source_local_param.btc_aa_src_cb.TxAaMtuSize); APPL_TRACE_DEBUG("ch mode %d, nbsubd %d, nb %d, alloc %d, rate %d, freq %d", - btc_sbc_encoder.s16ChannelMode, - btc_sbc_encoder.s16NumOfSubBands, btc_sbc_encoder.s16NumOfBlocks, - btc_sbc_encoder.s16AllocationMethod, btc_sbc_encoder.u16BitRate, - btc_sbc_encoder.s16SamplingFreq); + a2dp_source_local_param.btc_aa_src_cb.encoder.s16ChannelMode, + a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfSubBands, a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfBlocks, + a2dp_source_local_param.btc_aa_src_cb.encoder.s16AllocationMethod, a2dp_source_local_param.btc_aa_src_cb.encoder.u16BitRate, + a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq); - SBC_Encoder_Init(&(btc_sbc_encoder)); + SBC_Encoder_Init(&(a2dp_source_local_param.btc_aa_src_cb.encoder)); } else { APPL_TRACE_DEBUG("%s no SBC reconfig needed", __FUNCTION__); } @@ -1037,13 +1038,13 @@ static void btc_a2dp_source_audio_feeding_init(BT_HDR *p_msg) APPL_TRACE_DEBUG("%s format:%d", __FUNCTION__, p_feeding->feeding.format); /* Save Media Feeding information */ - btc_aa_src_cb.feeding_mode = p_feeding->feeding_mode; - btc_aa_src_cb.media_feeding = p_feeding->feeding; + a2dp_source_local_param.btc_aa_src_cb.feeding_mode = p_feeding->feeding_mode; + a2dp_source_local_param.btc_aa_src_cb.media_feeding = p_feeding->feeding; /* Handle different feeding formats */ switch (p_feeding->feeding.format) { case BTC_AV_CODEC_PCM: - btc_aa_src_cb.TxTranscoding = BTC_MEDIA_TRSCD_PCM_2_SBC; + a2dp_source_local_param.btc_aa_src_cb.TxTranscoding = BTC_MEDIA_TRSCD_PCM_2_SBC; btc_a2dp_source_pcm2sbc_init(p_feeding); break; @@ -1067,10 +1068,10 @@ static void btc_a2dp_source_aa_tx_flush(void) /* Flush all enqueued music buffers (encoded) */ APPL_TRACE_DEBUG("%s", __FUNCTION__); - btc_aa_src_cb.media_feeding_state.pcm.counter = 0; - btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue = 0; + a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.counter = 0; + a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue = 0; - btc_a2dp_source_flush_q(btc_aa_src_cb.TxAaQ); + btc_a2dp_source_flush_q(a2dp_source_local_param.btc_aa_src_cb.TxAaQ); btc_aa_src_data_read(NULL, -1); } @@ -1088,35 +1089,35 @@ static UINT8 btc_get_num_aa_frame(void) { UINT8 result = 0; - switch (btc_aa_src_cb.TxTranscoding) { + switch (a2dp_source_local_param.btc_aa_src_cb.TxTranscoding) { case BTC_MEDIA_TRSCD_PCM_2_SBC: { - UINT32 pcm_bytes_per_frame = btc_sbc_encoder.s16NumOfSubBands * - btc_sbc_encoder.s16NumOfBlocks * - btc_aa_src_cb.media_feeding.cfg.pcm.num_channel * - btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8; + UINT32 pcm_bytes_per_frame = a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfSubBands * + a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfBlocks * + a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.num_channel * + a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8; UINT32 us_this_tick = BTC_MEDIA_TIME_TICK_MS * 1000; UINT64 now_us = time_now_us(); - if (last_frame_us != 0) { + if (a2dp_source_local_param.last_frame_us != 0) { #if _POSIX_TIMERS - us_this_tick = (now_us - last_frame_us); + us_this_tick = (now_us - a2dp_source_local_param.last_frame_us); #else // consider the case that the number of day increases and timeofday wraps around - us_this_tick = (now_us > last_frame_us) ? (now_us - last_frame_us) : - (now_us + 86400000000ull - last_frame_us); + us_this_tick = (now_us > a2dp_source_local_param.last_frame_us) ? (now_us - a2dp_source_local_param.last_frame_us) : + (now_us + 86400000000ull - a2dp_source_local_param.last_frame_us); #endif } - last_frame_us = now_us; + a2dp_source_local_param.last_frame_us = now_us; - btc_aa_src_cb.media_feeding_state.pcm.counter += - btc_aa_src_cb.media_feeding_state.pcm.bytes_per_tick * + a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.counter += + a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.bytes_per_tick * us_this_tick / (BTC_MEDIA_TIME_TICK_MS * 1000); /* calculate nbr of frames pending for this media tick */ - result = btc_aa_src_cb.media_feeding_state.pcm.counter / pcm_bytes_per_frame; + result = a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.counter / pcm_bytes_per_frame; /* limit the frames to be sent */ - UINT32 frm_nb_threshold = MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ - fixed_queue_length(btc_aa_src_cb.TxAaQ); + UINT32 frm_nb_threshold = MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ - fixed_queue_length(a2dp_source_local_param.btc_aa_src_cb.TxAaQ); if (frm_nb_threshold > MAX_PCM_FRAME_NUM_PER_TICK) { frm_nb_threshold = MAX_PCM_FRAME_NUM_PER_TICK; } @@ -1125,7 +1126,7 @@ static UINT8 btc_get_num_aa_frame(void) APPL_TRACE_EVENT("Limit frms to send from %d to %d", result, frm_nb_threshold); result = frm_nb_threshold; } - btc_aa_src_cb.media_feeding_state.pcm.counter -= result * pcm_bytes_per_frame; + a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.counter -= result * pcm_bytes_per_frame; BTC_TRACE_VERBOSE("WRITE %d FRAMES", result); } @@ -1133,7 +1134,7 @@ static UINT8 btc_get_num_aa_frame(void) default: APPL_TRACE_ERROR("ERROR btc_get_num_aa_frame Unsupported transcoding format 0x%x", - btc_aa_src_cb.TxTranscoding); + a2dp_source_local_param.btc_aa_src_cb.TxTranscoding); result = 0; break; } @@ -1153,13 +1154,13 @@ static UINT8 btc_get_num_aa_frame(void) BOOLEAN btc_media_aa_read_feeding(void) { - UINT16 blocm_x_subband = btc_sbc_encoder.s16NumOfSubBands * \ - btc_sbc_encoder.s16NumOfBlocks; + UINT16 blocm_x_subband = a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfSubBands * \ + a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfBlocks; UINT32 read_size; UINT16 sbc_sampling = 48000; UINT32 src_samples; - UINT16 bytes_needed = blocm_x_subband * btc_sbc_encoder.s16NumOfChannels * \ - btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8; + UINT16 bytes_needed = blocm_x_subband * a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfChannels * \ + a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8; static UINT16 up_sampled_buffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS * SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS * 2]; static UINT16 read_buffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS @@ -1172,7 +1173,7 @@ BOOLEAN btc_media_aa_read_feeding(void) UINT32 nb_byte_read = 0; /* Get the SBC sampling rate */ - switch (btc_sbc_encoder.s16SamplingFreq) { + switch (a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq) { case SBC_sf48000: sbc_sampling = 48000; break; @@ -1187,19 +1188,19 @@ BOOLEAN btc_media_aa_read_feeding(void) break; } - if (sbc_sampling == btc_aa_src_cb.media_feeding.cfg.pcm.sampling_freq) { - read_size = bytes_needed - btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue; + if (sbc_sampling == a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.sampling_freq) { + read_size = bytes_needed - a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue; nb_byte_read = btc_aa_src_data_read( - ((uint8_t *)btc_sbc_encoder.as16PcmBuffer) + - btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue, + ((uint8_t *)a2dp_source_local_param.btc_aa_src_cb.encoder.as16PcmBuffer) + + a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue, read_size); if (nb_byte_read == read_size) { - btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue = 0; + a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue = 0; return TRUE; } else { APPL_TRACE_WARNING("### UNDERFLOW :: ONLY READ %d BYTES OUT OF %d ###", nb_byte_read, read_size); - btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue += nb_byte_read; + a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue += nb_byte_read; return FALSE; } } @@ -1208,7 +1209,7 @@ BOOLEAN btc_media_aa_read_feeding(void) /* to read. */ /* E.g 128/6=21.3333 => read 22 and 21 and 21 => max = 2; threshold = 0*/ fract_needed = FALSE; /* Default */ - switch (btc_aa_src_cb.media_feeding.cfg.pcm.sampling_freq) { + switch (a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.sampling_freq) { case 32000: case 8000: fract_needed = TRUE; @@ -1224,26 +1225,26 @@ BOOLEAN btc_media_aa_read_feeding(void) /* Compute number of sample to read from source */ src_samples = blocm_x_subband; - src_samples *= btc_aa_src_cb.media_feeding.cfg.pcm.sampling_freq; + src_samples *= a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.sampling_freq; src_samples /= sbc_sampling; /* The previous division may have a remainder not null */ if (fract_needed) { - if (btc_aa_src_cb.media_feeding_state.pcm.aa_feed_counter <= fract_threshold) { + if (a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_counter <= fract_threshold) { src_samples++; /* for every read before threshold add one sample */ } /* do nothing if counter >= threshold */ - btc_aa_src_cb.media_feeding_state.pcm.aa_feed_counter++; /* one more read */ - if (btc_aa_src_cb.media_feeding_state.pcm.aa_feed_counter > fract_max) { - btc_aa_src_cb.media_feeding_state.pcm.aa_feed_counter = 0; + a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_counter++; /* one more read */ + if (a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_counter > fract_max) { + a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_counter = 0; } } /* Compute number of bytes to read from source */ read_size = src_samples; - read_size *= btc_aa_src_cb.media_feeding.cfg.pcm.num_channel; - read_size *= (btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8); + read_size *= a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.num_channel; + read_size *= (a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8); /* Read Data from data channel */ nb_byte_read = btc_aa_src_data_read((uint8_t *)read_buffer, read_size); @@ -1258,7 +1259,7 @@ BOOLEAN btc_media_aa_read_feeding(void) return FALSE; } - if (btc_aa_src_cb.feeding_mode == BTC_AV_FEEDING_ASYNCHRONOUS) { + if (a2dp_source_local_param.btc_aa_src_cb.feeding_mode == BTC_AV_FEEDING_ASYNCHRONOUS) { /* Fill the unfilled part of the read buffer with silence (0) */ memset(((UINT8 *)read_buffer) + nb_byte_read, 0, read_size - nb_byte_read); nb_byte_read = read_size; @@ -1266,34 +1267,34 @@ BOOLEAN btc_media_aa_read_feeding(void) } /* Initialize PCM up-sampling engine */ - bta_av_sbc_init_up_sample(btc_aa_src_cb.media_feeding.cfg.pcm.sampling_freq, - sbc_sampling, btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample, - btc_aa_src_cb.media_feeding.cfg.pcm.num_channel); + bta_av_sbc_init_up_sample(a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.sampling_freq, + sbc_sampling, a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample, + a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.num_channel); /* re-sample read buffer */ /* The output PCM buffer will be stereo, 16 bit per sample */ dst_size_used = bta_av_sbc_up_sample((UINT8 *)read_buffer, - (UINT8 *)up_sampled_buffer + btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue, + (UINT8 *)up_sampled_buffer + a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue, nb_byte_read, - sizeof(up_sampled_buffer) - btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue, + sizeof(up_sampled_buffer) - a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue, &src_size_used); /* update the residue */ - btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue += dst_size_used; + a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue += dst_size_used; /* only copy the pcm sample when we have up-sampled enough PCM */ - if (btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue >= bytes_needed) { + if (a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue >= bytes_needed) { /* Copy the output pcm samples in SBC encoding buffer */ - memcpy((UINT8 *)btc_sbc_encoder.as16PcmBuffer, + memcpy((UINT8 *)a2dp_source_local_param.btc_aa_src_cb.encoder.as16PcmBuffer, (UINT8 *)up_sampled_buffer, bytes_needed); /* update the residue */ - btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue -= bytes_needed; + a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue -= bytes_needed; - if (btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue != 0) { + if (a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue != 0) { memcpy((UINT8 *)up_sampled_buffer, (UINT8 *)up_sampled_buffer + bytes_needed, - btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue); + a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue); } return TRUE; } @@ -1313,13 +1314,13 @@ BOOLEAN btc_media_aa_read_feeding(void) static void btc_media_aa_prep_sbc_2_send(UINT8 nb_frame) { BT_HDR *p_buf; - UINT16 blocm_x_subband = btc_sbc_encoder.s16NumOfSubBands * - btc_sbc_encoder.s16NumOfBlocks; + UINT16 blocm_x_subband = a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfSubBands * + a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfBlocks; while (nb_frame) { if (NULL == (p_buf = osi_malloc(BTC_MEDIA_AA_BUF_SIZE))) { APPL_TRACE_ERROR ("ERROR btc_media_aa_prep_sbc_2_send no buffer TxCnt %d ", - fixed_queue_length(btc_aa_src_cb.TxAaQ)); + fixed_queue_length(a2dp_source_local_param.btc_aa_src_cb.TxAaQ)); return; } @@ -1330,53 +1331,53 @@ static void btc_media_aa_prep_sbc_2_send(UINT8 nb_frame) do { /* Write @ of allocated buffer in encoder.pu8Packet */ - btc_sbc_encoder.pu8Packet = (UINT8 *) (p_buf + 1) + p_buf->offset + p_buf->len; + a2dp_source_local_param.btc_aa_src_cb.encoder.pu8Packet = (UINT8 *) (p_buf + 1) + p_buf->offset + p_buf->len; /* Fill allocated buffer with 0 */ - memset(btc_sbc_encoder.as16PcmBuffer, 0, blocm_x_subband - * btc_sbc_encoder.s16NumOfChannels); + memset(a2dp_source_local_param.btc_aa_src_cb.encoder.as16PcmBuffer, 0, blocm_x_subband + * a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfChannels); /* Read PCM data and upsample them if needed */ if (btc_media_aa_read_feeding()) { /* SBC encode and descramble frame */ - SBC_Encoder(&(btc_sbc_encoder)); + SBC_Encoder(&(a2dp_source_local_param.btc_aa_src_cb.encoder)); /* Update SBC frame length */ - p_buf->len += btc_sbc_encoder.u16PacketLength; + p_buf->len += a2dp_source_local_param.btc_aa_src_cb.encoder.u16PacketLength; nb_frame--; p_buf->layer_specific++; } else { APPL_TRACE_WARNING("btc_media_aa_prep_sbc_2_send underflow %d, %d", - nb_frame, btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue); - btc_aa_src_cb.media_feeding_state.pcm.counter += nb_frame * - btc_sbc_encoder.s16NumOfSubBands * - btc_sbc_encoder.s16NumOfBlocks * - btc_aa_src_cb.media_feeding.cfg.pcm.num_channel * - btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8; + nb_frame, a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue); + a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.counter += nb_frame * + a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfSubBands * + a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfBlocks * + a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.num_channel * + a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8; /* no more pcm to read */ nb_frame = 0; /* break read loop if timer was stopped (media task stopped) */ - if ( btc_aa_src_cb.is_tx_timer == FALSE ) { + if ( a2dp_source_local_param.btc_aa_src_cb.is_tx_timer == FALSE ) { osi_free(p_buf); return; } } - } while (((p_buf->len + btc_sbc_encoder.u16PacketLength) < btc_aa_src_cb.TxAaMtuSize) + } while (((p_buf->len + a2dp_source_local_param.btc_aa_src_cb.encoder.u16PacketLength) < a2dp_source_local_param.btc_aa_src_cb.TxAaMtuSize) && (p_buf->layer_specific < 0x0F) && nb_frame); if (p_buf->len) { /* timestamp of the media packet header represent the TS of the first SBC frame i.e the timestamp before including this frame */ - *((UINT32 *) (p_buf + 1)) = btc_aa_src_cb.timestamp; + *((UINT32 *) (p_buf + 1)) = a2dp_source_local_param.btc_aa_src_cb.timestamp; - btc_aa_src_cb.timestamp += p_buf->layer_specific * blocm_x_subband; + a2dp_source_local_param.btc_aa_src_cb.timestamp += p_buf->layer_specific * blocm_x_subband; - if (btc_aa_src_cb.tx_flush) { + if (a2dp_source_local_param.btc_aa_src_cb.tx_flush) { APPL_TRACE_DEBUG("### tx suspended, discarded frame ###"); - if (fixed_queue_length(btc_aa_src_cb.TxAaQ) > 0) { - btc_a2dp_source_flush_q(btc_aa_src_cb.TxAaQ); + if (fixed_queue_length(a2dp_source_local_param.btc_aa_src_cb.TxAaQ) > 0) { + btc_a2dp_source_flush_q(a2dp_source_local_param.btc_aa_src_cb.TxAaQ); } osi_free(p_buf); @@ -1384,7 +1385,7 @@ static void btc_media_aa_prep_sbc_2_send(UINT8 nb_frame) } /* Enqueue the encoded SBC frame in AA Tx Queue */ - fixed_queue_enqueue(btc_aa_src_cb.TxAaQ, p_buf); + fixed_queue_enqueue(a2dp_source_local_param.btc_aa_src_cb.TxAaQ, p_buf); } else { osi_free(p_buf); } @@ -1407,24 +1408,24 @@ static void btc_a2dp_source_prep_2_send(UINT8 nb_frame) nb_frame = MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ; } - if (fixed_queue_length(btc_aa_src_cb.TxAaQ) > (MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ - nb_frame)) { + if (fixed_queue_length(a2dp_source_local_param.btc_aa_src_cb.TxAaQ) > (MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ - nb_frame)) { APPL_TRACE_WARNING("TX Q overflow: %d/%d", - fixed_queue_length(btc_aa_src_cb.TxAaQ), MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ - nb_frame); + fixed_queue_length(a2dp_source_local_param.btc_aa_src_cb.TxAaQ), MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ - nb_frame); } - while (fixed_queue_length(btc_aa_src_cb.TxAaQ) > (MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ - nb_frame)) { - osi_free(fixed_queue_try_dequeue(btc_aa_src_cb.TxAaQ)); + while (fixed_queue_length(a2dp_source_local_param.btc_aa_src_cb.TxAaQ) > (MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ - nb_frame)) { + osi_free(fixed_queue_try_dequeue(a2dp_source_local_param.btc_aa_src_cb.TxAaQ)); } // Transcode frame - switch (btc_aa_src_cb.TxTranscoding) { + switch (a2dp_source_local_param.btc_aa_src_cb.TxTranscoding) { case BTC_MEDIA_TRSCD_PCM_2_SBC: btc_media_aa_prep_sbc_2_send(nb_frame); break; default: - APPL_TRACE_ERROR("%s unsupported transcoding format 0x%x", __func__, btc_aa_src_cb.TxTranscoding); + APPL_TRACE_ERROR("%s unsupported transcoding format 0x%x", __func__, a2dp_source_local_param.btc_aa_src_cb.TxTranscoding); break; } } @@ -1464,7 +1465,7 @@ static void btc_a2dp_source_handle_timer(UNUSED_ATTR void *context) return; } - if (btc_aa_src_cb.is_tx_timer == TRUE) { + if (a2dp_source_local_param.btc_aa_src_cb.is_tx_timer == TRUE) { btc_a2dp_source_send_aa_frame(); } else { APPL_TRACE_WARNING("Media task Scheduled after Suspend"); @@ -1489,17 +1490,17 @@ static void btc_a2dp_source_alarm_cb(UNUSED_ATTR void *context) static void btc_a2dp_source_feeding_state_reset(void) { /* By default, just clear the entire state */ - memset(&btc_aa_src_cb.media_feeding_state, 0, sizeof(btc_aa_src_cb.media_feeding_state)); + memset(&a2dp_source_local_param.btc_aa_src_cb.media_feeding_state, 0, sizeof(a2dp_source_local_param.btc_aa_src_cb.media_feeding_state)); - if (btc_aa_src_cb.TxTranscoding == BTC_MEDIA_TRSCD_PCM_2_SBC) { - btc_aa_src_cb.media_feeding_state.pcm.bytes_per_tick = - (btc_aa_src_cb.media_feeding.cfg.pcm.sampling_freq * - btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8 * - btc_aa_src_cb.media_feeding.cfg.pcm.num_channel * + if (a2dp_source_local_param.btc_aa_src_cb.TxTranscoding == BTC_MEDIA_TRSCD_PCM_2_SBC) { + a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.bytes_per_tick = + (a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.sampling_freq * + a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8 * + a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.num_channel * BTC_MEDIA_TIME_TICK_MS) / 1000; APPL_TRACE_EVENT("pcm bytes per tick %d", - (int)btc_aa_src_cb.media_feeding_state.pcm.bytes_per_tick); + (int)a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.bytes_per_tick); } } @@ -1515,26 +1516,26 @@ static void btc_a2dp_source_feeding_state_reset(void) static void btc_a2dp_source_aa_start_tx(void) { APPL_TRACE_DEBUG("btc_a2dp_source_aa_start_tx is timer %d, feeding mode %d", - btc_aa_src_cb.is_tx_timer, btc_aa_src_cb.feeding_mode); + a2dp_source_local_param.btc_aa_src_cb.is_tx_timer, a2dp_source_local_param.btc_aa_src_cb.feeding_mode); - btc_aa_src_cb.is_tx_timer = TRUE; - last_frame_us = 0; + a2dp_source_local_param.btc_aa_src_cb.is_tx_timer = TRUE; + a2dp_source_local_param.last_frame_us = 0; /* Reset the media feeding state */ btc_a2dp_source_feeding_state_reset(); APPL_TRACE_EVENT("starting timer %dms", BTC_MEDIA_TIME_TICK_MS); - assert(btc_aa_src_cb.media_alarm == NULL); + assert(a2dp_source_local_param.btc_aa_src_cb.media_alarm == NULL); - btc_aa_src_cb.media_alarm = osi_alarm_new("aaTx", btc_a2dp_source_alarm_cb, NULL, BTC_MEDIA_TIME_TICK_MS); + a2dp_source_local_param.btc_aa_src_cb.media_alarm = osi_alarm_new("aaTx", btc_a2dp_source_alarm_cb, NULL, BTC_MEDIA_TIME_TICK_MS); - if (!btc_aa_src_cb.media_alarm) { + if (!a2dp_source_local_param.btc_aa_src_cb.media_alarm) { BTC_TRACE_ERROR("%s unable to allocate media alarm.", __func__); return; } - osi_alarm_set_periodic(btc_aa_src_cb.media_alarm, BTC_MEDIA_TIME_TICK_MS); + osi_alarm_set_periodic(a2dp_source_local_param.btc_aa_src_cb.media_alarm, BTC_MEDIA_TIME_TICK_MS); } /******************************************************************************* @@ -1548,17 +1549,17 @@ static void btc_a2dp_source_aa_start_tx(void) *******************************************************************************/ static void btc_a2dp_source_aa_stop_tx(void) { - APPL_TRACE_DEBUG("%s is_tx_timer: %d", __func__, btc_aa_src_cb.is_tx_timer); + APPL_TRACE_DEBUG("%s is_tx_timer: %d", __func__, a2dp_source_local_param.btc_aa_src_cb.is_tx_timer); - const bool send_ack = (btc_aa_src_cb.is_tx_timer != FALSE); + const bool send_ack = (a2dp_source_local_param.btc_aa_src_cb.is_tx_timer != FALSE); /* Stop the timer first */ - if (btc_aa_src_cb.media_alarm) { - osi_alarm_cancel(btc_aa_src_cb.media_alarm); - osi_alarm_free(btc_aa_src_cb.media_alarm); + if (a2dp_source_local_param.btc_aa_src_cb.media_alarm) { + osi_alarm_cancel(a2dp_source_local_param.btc_aa_src_cb.media_alarm); + osi_alarm_free(a2dp_source_local_param.btc_aa_src_cb.media_alarm); } - btc_aa_src_cb.media_alarm = NULL; - btc_aa_src_cb.is_tx_timer = FALSE; + a2dp_source_local_param.btc_aa_src_cb.media_alarm = NULL; + a2dp_source_local_param.btc_aa_src_cb.is_tx_timer = FALSE; /* Try to send acknowldegment once the media stream is stopped. This will make sure that the A2DP HAL layer is @@ -1576,8 +1577,8 @@ static void btc_a2dp_source_aa_stop_tx(void) } /* audio engine stopped, reset tx suspended flag */ - btc_aa_src_cb.tx_flush = 0; - last_frame_us = 0; + a2dp_source_local_param.btc_aa_src_cb.tx_flush = 0; + a2dp_source_local_param.last_frame_us = 0; /* Reset the feeding state */ btc_a2dp_source_feeding_state_reset(); @@ -1602,11 +1603,11 @@ static void btc_a2dp_source_flush_q(fixed_queue_t *p_q) static void btc_a2dp_source_thread_init(UNUSED_ATTR void *context) { APPL_TRACE_EVENT("%s\n", __func__); - memset(&btc_aa_src_cb, 0, sizeof(btc_aa_src_cb)); + memset(&a2dp_source_local_param.btc_aa_src_cb, 0, sizeof(a2dp_source_local_param.btc_aa_src_cb)); btc_a2dp_source_state = BTC_A2DP_SOURCE_STATE_ON; - btc_aa_src_cb.TxAaQ = fixed_queue_new(QUEUE_SIZE_MAX); + a2dp_source_local_param.btc_aa_src_cb.TxAaQ = fixed_queue_new(QUEUE_SIZE_MAX); btc_a2dp_control_init(); } @@ -1619,9 +1620,9 @@ static void btc_a2dp_source_thread_cleanup(UNUSED_ATTR void *context) btc_a2dp_control_cleanup(); - fixed_queue_free(btc_aa_src_cb.TxAaQ, osi_free_func); + fixed_queue_free(a2dp_source_local_param.btc_aa_src_cb.TxAaQ, osi_free_func); - future_ready(btc_a2dp_source_future, NULL); + future_ready(a2dp_source_local_param.btc_a2dp_source_future, NULL); } #endif /* BTC_AV_INCLUDED */ diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/btc_av.c b/components/bt/bluedroid/btc/profile/std/a2dp/btc_av.c index f428150bae..be1f1f9628 100644 --- a/components/bt/bluedroid/btc/profile/std/a2dp/btc_av.c +++ b/components/bt/bluedroid/btc/profile/std/a2dp/btc_av.c @@ -79,6 +79,9 @@ typedef struct { UINT8 flags; tBTA_AV_EDR edr; UINT8 peer_sep; /* sep type of peer device */ +#if BTC_AV_SRC_INCLUDED + osi_alarm_t *tle_av_open_on_rc; +#endif /* BTC_AV_SRC_INCLUDED */ } btc_av_cb_t; typedef struct { @@ -89,11 +92,12 @@ typedef struct { /***************************************************************************** ** Static variables ******************************************************************************/ +#if A2D_DYNAMIC_MEMORY == FALSE static btc_av_cb_t btc_av_cb = {0}; - -#if BTC_AV_SRC_INCLUDED -static osi_alarm_t *tle_av_open_on_rc = NULL; -#endif /* BTC_AV_SRC_INCLUDED */ +#else +static btc_av_cb_t *btc_av_cb_ptr = NULL; +#define btc_av_cb (*btc_av_cb_ptr) +#endif ///A2D_DYNAMIC_MEMORY == FALSE /* both interface and media task needs to be ready to alloc incoming request */ #define CHECK_BTAV_INIT() do \ @@ -337,8 +341,8 @@ static BOOLEAN btc_av_state_idle_handler(btc_sm_event_t event, void *p_data) #if BTC_AV_SRC_INCLUDED BTC_TRACE_DEBUG("BTA_AV_RC_OPEN_EVT received w/o AV"); - tle_av_open_on_rc = osi_alarm_new("AVconn", btc_initiate_av_open_tmr_hdlr, NULL, BTC_TIMEOUT_AV_OPEN_ON_RC_SECS * 1000); - osi_alarm_set(tle_av_open_on_rc, BTC_TIMEOUT_AV_OPEN_ON_RC_SECS * 1000); + btc_av_cb.tle_av_open_on_rc = osi_alarm_new("AVconn", btc_initiate_av_open_tmr_hdlr, NULL, BTC_TIMEOUT_AV_OPEN_ON_RC_SECS * 1000); + osi_alarm_set(btc_av_cb.tle_av_open_on_rc, BTC_TIMEOUT_AV_OPEN_ON_RC_SECS * 1000); #endif /* BTC_AV_SRC_INCLUDED */ btc_rc_handler(event, p_data); break; @@ -353,9 +357,9 @@ static BOOLEAN btc_av_state_idle_handler(btc_sm_event_t event, void *p_data) case BTA_AV_RC_CLOSE_EVT: #if BTC_AV_SRC_INCLUDED - if (tle_av_open_on_rc) { - osi_alarm_free(tle_av_open_on_rc); - tle_av_open_on_rc = NULL; + if (btc_av_cb.tle_av_open_on_rc) { + osi_alarm_free(btc_av_cb.tle_av_open_on_rc); + btc_av_cb.tle_av_open_on_rc = NULL; } #endif /* BTC_AV_SRC_INCLUDED */ btc_rc_handler(event, p_data); @@ -961,6 +965,19 @@ static void btc_av_event_free_data(btc_sm_event_t event, void *p_data) static bt_status_t btc_av_init(int service_id) { + +#if A2D_DYNAMIC_MEMORY == TRUE + if (btc_av_cb_ptr != NULL) { + return BT_STATUS_FAIL; + } + + if ((btc_av_cb_ptr = (btc_av_cb_t *)osi_malloc(sizeof(btc_av_cb_t))) == NULL) { + APPL_TRACE_ERROR("%s malloc failed!", __func__); + return BT_STATUS_NOMEM; + } + memset((void *)btc_av_cb_ptr, 0, sizeof(btc_av_cb_t)); +#endif + if (btc_av_cb.sm_handle == NULL) { btc_av_cb.service_id = service_id; bool stat = false; @@ -975,6 +992,10 @@ static bt_status_t btc_av_init(int service_id) } if (!stat) { +#if A2D_DYNAMIC_MEMORY == TRUE + osi_free(btc_av_cb_ptr); + btc_av_cb_ptr = NULL; +#endif return BT_STATUS_FAIL; } @@ -1034,9 +1055,9 @@ static void clean_up(int service_id) if (service_id == BTA_A2DP_SOURCE_SERVICE_ID) { #if BTC_AV_SRC_INCLUDED btc_a2dp_source_shutdown(); - if (tle_av_open_on_rc) { - osi_alarm_free(tle_av_open_on_rc); - tle_av_open_on_rc = NULL; + if (btc_av_cb.tle_av_open_on_rc) { + osi_alarm_free(btc_av_cb.tle_av_open_on_rc); + btc_av_cb.tle_av_open_on_rc = NULL; } #endif /* BTC_AV_SRC_INCLUDED */ } @@ -1056,6 +1077,11 @@ static void clean_up(int service_id) btc_a2dp_sink_shutdown(); #endif /* BTC_AV_SINK_INCLUDED */ } + +#if A2D_DYNAMIC_MEMORY == TRUE + osi_free(btc_av_cb_ptr); + btc_av_cb_ptr = NULL; +#endif } /******************************************************************************* diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/include/btc_av_co.h b/components/bt/bluedroid/btc/profile/std/a2dp/include/btc_av_co.h index cacaa01d8f..a7943b70cb 100644 --- a/components/bt/bluedroid/btc/profile/std/a2dp/include/btc_av_co.h +++ b/components/bt/bluedroid/btc/profile/std/a2dp/include/btc_av_co.h @@ -16,6 +16,7 @@ #define __BTC_AV_CO_H__ #include "btc_a2dp.h" +#include "bta/bta_av_co.h" #if (BTA_AV_INCLUDED == TRUE) /******************************************************************************* @@ -28,7 +29,62 @@ enum { BTC_SV_AV_AA_SEP_INDEX /* Last index */ }; +/***************************************************************************** +** Local data +*****************************************************************************/ +typedef struct { + UINT8 sep_info_idx; /* local SEP index (in BTA tables) */ + UINT8 seid; /* peer SEP index (in peer tables) */ + UINT8 codec_type; /* peer SEP codec type */ + UINT8 codec_caps[AVDT_CODEC_SIZE]; /* peer SEP codec capabilities */ + UINT8 num_protect; /* peer SEP number of CP elements */ + UINT8 protect_info[BTA_AV_CP_INFO_LEN]; /* peer SEP content protection info */ +} tBTA_AV_CO_SINK; +typedef struct { + BD_ADDR addr; /* address of audio/video peer */ + tBTA_AV_CO_SINK snks[BTC_SV_AV_AA_SEP_INDEX]; /* array of supported sinks */ + tBTA_AV_CO_SINK srcs[BTC_SV_AV_AA_SEP_INDEX]; /* array of supported srcs */ + UINT8 num_snks; /* total number of sinks at peer */ + UINT8 num_srcs; /* total number of srcs at peer */ + UINT8 num_seps; /* total number of seids at peer */ + UINT8 num_rx_snks; /* number of received sinks */ + UINT8 num_rx_srcs; /* number of received srcs */ + UINT8 num_sup_snks; /* number of supported sinks in the snks array */ + UINT8 num_sup_srcs; /* number of supported srcs in the srcs array */ + tBTA_AV_CO_SINK *p_snk; /* currently selected sink */ + tBTA_AV_CO_SINK *p_src; /* currently selected src */ + UINT8 codec_cfg[AVDT_CODEC_SIZE]; /* current codec configuration */ + BOOLEAN cp_active; /* current CP configuration */ + BOOLEAN acp; /* acceptor */ + BOOLEAN recfg_needed; /* reconfiguration is needed */ + BOOLEAN opened; /* opened */ + UINT16 mtu; /* maximum transmit unit size */ + UINT16 uuid_to_connect; /* uuid of peer device */ +} tBTA_AV_CO_PEER; + +typedef struct { + BOOLEAN active; + UINT8 flag; +} tBTA_AV_CO_CP; + +typedef struct { + /* Connected peer information */ + tBTA_AV_CO_PEER peers[BTA_AV_NUM_STRS]; + /* Current codec configuration - access to this variable must be protected */ + tBTC_AV_CODEC_INFO codec_cfg; + tBTC_AV_CODEC_INFO codec_cfg_setconfig; /* remote peer setconfig preference */ + + tBTA_AV_CO_CP cp; +} tBTA_AV_CO_CB; + +/* Control block instance */ +#if AVRC_DYNAMIC_MEMORY == FALSE +extern tBTA_AV_CO_CB bta_av_co_cb; +#else +extern tBTA_AV_CO_CB *bta_av_co_cb_ptr; +#define bta_av_co_cb (*bta_av_co_cb_ptr) +#endif /******************************************************************************* ** Functions ********************************************************************************/ diff --git a/components/bt/bluedroid/btc/profile/std/avrc/btc_avrc.c b/components/bt/bluedroid/btc/profile/std/avrc/btc_avrc.c index 6e204be482..841d55c360 100644 --- a/components/bt/bluedroid/btc/profile/std/avrc/btc_avrc.c +++ b/components/bt/bluedroid/btc/profile/std/avrc/btc_avrc.c @@ -35,40 +35,6 @@ #if BTC_AV_INCLUDED -/***************************************************************************** -** Constants & Macros -******************************************************************************/ -#define BTC_RC_CT_INIT_MAGIC 0x20181128 -#define BTC_RC_TG_INIT_MAGIC 0x20181129 - -#define MAX_RC_NOTIFICATIONS (13) // refer to ESP_AVRC_RN_MAX_EVT - -#define CHECK_ESP_RC_CONNECTED do { \ - BTC_TRACE_DEBUG("## %s ##", __FUNCTION__); \ - if (btc_rc_cb.rc_connected == FALSE) { \ - BTC_TRACE_WARNING("Function %s() called when RC is not connected", __FUNCTION__); \ - return ESP_ERR_INVALID_STATE; \ - } \ - } while (0) - -/***************************************************************************** -** Local type definitions -******************************************************************************/ -typedef struct { - BOOLEAN registered; - UINT8 label; -} btc_rc_reg_ntf_t; - -typedef struct { - BOOLEAN rc_connected; - UINT8 rc_handle; - tBTA_AV_FEAT rc_features; - UINT16 rc_ct_features; - UINT16 rc_tg_features; - BD_ADDR rc_addr; - btc_rc_reg_ntf_t rc_ntf[MAX_RC_NOTIFICATIONS]; -} btc_rc_cb_t; - static UINT8 opcode_from_pdu(UINT8 pdu); static void send_reject_response (UINT8 rc_handle, UINT8 label, UINT8 pdu, UINT8 status); static void handle_rc_connect (tBTA_AV_RC_OPEN *p_rc_open); @@ -86,7 +52,11 @@ static void btc_rc_upstreams_evt(UINT16 event, tAVRC_COMMAND *pavrc_cmd, UINT8 c static uint32_t s_rc_ct_init; static uint32_t s_rc_tg_init; +#if AVRC_DYNAMIC_MEMORY == FALSE static btc_rc_cb_t btc_rc_cb; +#else +btc_rc_cb_t *btc_rc_cb_ptr; +#endif ///AVRC_DYNAMIC_MEMORY == FALSE const static uint16_t cs_psth_allowed_cmd[8] = { 0x0000, /* bit mask: 0=SELECT, 1=UP, 2=DOWN, 3=LEFT, @@ -1031,7 +1001,9 @@ static void btc_avrc_ct_init(void) /// initialize CT-TG shared resources if (s_rc_tg_init != BTC_RC_TG_INIT_MAGIC) { - memset (&btc_rc_cb, 0, sizeof(btc_rc_cb)); + memset (&btc_rc_cb, 0, sizeof(btc_rc_cb_t)); + btc_rc_cb.rc_vol_label = MAX_LABEL; + btc_rc_cb.rc_volume = MAX_VOLUME; } } @@ -1059,7 +1031,7 @@ static void btc_avrc_ct_deinit(void) /// deinit CT-TG shared resources if (s_rc_tg_init != BTC_RC_TG_INIT_MAGIC) { - memset (&btc_rc_cb, 0, sizeof(btc_rc_cb)); + memset (&btc_rc_cb, 0, sizeof(btc_rc_cb_t)); } BTC_TRACE_API("## %s ## completed", __FUNCTION__); diff --git a/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c b/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c index ffac0c35f6..be270a430c 100644 --- a/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c +++ b/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c @@ -31,8 +31,14 @@ #include "osi/mutex.h" #include "esp_bt.h" +#if BTC_DYNAMIC_MENDRY == FALSE static tBTA_BLE_ADV_DATA gl_bta_adv_data; static tBTA_BLE_ADV_DATA gl_bta_scan_rsp_data; +#else +tBTA_BLE_ADV_DATA *gl_bta_adv_data_ptr; +tBTA_BLE_ADV_DATA *gl_bta_scan_rsp_data_ptr; +#endif + #if SCAN_QUEUE_CONGEST_CHECK static list_t *adv_filter_list; static osi_mutex_t adv_list_lock; diff --git a/components/bt/bluedroid/btc/profile/std/gatt/btc_gatt_util.c b/components/bt/bluedroid/btc/profile/std/gatt/btc_gatt_util.c index 8653f60561..37497a8afc 100644 --- a/components/bt/bluedroid/btc/profile/std/gatt/btc_gatt_util.c +++ b/components/bt/bluedroid/btc/profile/std/gatt/btc_gatt_util.c @@ -20,7 +20,7 @@ #define GATTC_READ_VALUE_TYPE_VALUE 0x0000 /* Attribute value itself */ #define GATTC_READ_VALUE_TYPE_AGG_FORMAT 0x2905 /* Characteristic Aggregate Format*/ -static unsigned char BASE_UUID[16] = { +static const unsigned char BASE_UUID[16] = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c b/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c index e93fc937ea..117b6b8614 100644 --- a/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c +++ b/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c @@ -30,19 +30,11 @@ #define A2C_GATTS_EVT(_bta_event) (_bta_event) //BTA TO BTC EVT #define C2A_GATTS_EVT(_btc_event) (_btc_event) //BTC TO BTA EVT -typedef struct { - future_t *complete_future; - uint16_t svc_start_hdl; - esp_bt_uuid_t svc_uuid; - bool is_tab_creat_svc; - bool is_use_svc; - uint8_t num_handle; - uint8_t handle_idx; - uint16_t handles[ESP_GATT_ATTR_HANDLE_MAX]; -} esp_btc_creat_tab_t; - +#if GATT_DYNAMIC_MEMORY == FALSE static esp_btc_creat_tab_t btc_creat_tab_env; - +#else +esp_btc_creat_tab_t *btc_creat_tab_env_ptr; +#endif static esp_gatt_status_t btc_gatts_check_valid_attr_tab(esp_gatts_attr_db_t *gatts_attr_db, uint8_t max_nb_attr); @@ -106,13 +98,13 @@ void btc_gatts_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) } } break; - + } case BTC_GATTS_ACT_ADD_CHAR: { if (src->add_char.char_val.attr_value && (src->add_char.char_val.attr_len > 0)) { dst->add_char.char_val.attr_value = (uint8_t *) osi_malloc(src->add_char.char_val.attr_len); if (dst->add_char.char_val.attr_value) { - memcpy(dst->add_char.char_val.attr_value, src->add_char.char_val.attr_value, + memcpy(dst->add_char.char_val.attr_value, src->add_char.char_val.attr_value, src->add_char.char_val.attr_len); } else { BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act); @@ -231,7 +223,7 @@ void btc_gatts_arg_deep_free(btc_msg_t *msg) } -static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db, +static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db, esp_gatt_if_t gatts_if, uint8_t max_nb_attr, uint8_t srvc_inst_id) @@ -283,7 +275,7 @@ static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db, esp_srvc_id.id.inst_id = srvc_inst_id; btc_gatts_uuid_format_convert(&esp_srvc_id.id.uuid,gatts_attr_db[i].att_desc.length, gatts_attr_db[i].att_desc.value); - + btc_to_bta_srvc_id(&srvc_id, &esp_srvc_id); if (btc_creat_tab_env.is_use_svc != true) { BTA_GATTS_CreateService(gatts_if, &srvc_id.id.uuid, @@ -297,7 +289,7 @@ static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db, memset(&btc_creat_tab_env, 0, sizeof(esp_btc_creat_tab_t)); return; } - + if (future_await(future_p) == FUTURE_FAIL) { BTC_TRACE_ERROR("%s failed\n", __func__); return; @@ -332,12 +324,12 @@ static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db, } case ESP_GATT_UUID_INCLUDE_SERVICE:{ esp_gatts_incl_svc_desc_t *incl_svc_desc = (esp_gatts_incl_svc_desc_t *)gatts_attr_db[i].att_desc.value; - + if(incl_svc_desc!= NULL){ if(btc_creat_tab_env.svc_start_hdl != 0){ - BTA_GATTS_AddIncludeService(btc_creat_tab_env.svc_start_hdl, + BTA_GATTS_AddIncludeService(btc_creat_tab_env.svc_start_hdl, incl_svc_desc->start_hdl); - + if (future_await(future_p) == FUTURE_FAIL) { BTC_TRACE_ERROR("%s failed\n", __func__); return; @@ -378,10 +370,10 @@ static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db, } } } - + break; } - case ESP_GATT_UUID_CHAR_EXT_PROP: + case ESP_GATT_UUID_CHAR_EXT_PROP: case ESP_GATT_UUID_CHAR_DESCRIPTION: case ESP_GATT_UUID_CHAR_CLIENT_CONFIG: case ESP_GATT_UUID_CHAR_SRVR_CONFIG: @@ -406,7 +398,7 @@ static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db, btc_to_bta_uuid(&bta_char_uuid, &uuid_temp); control.auto_rsp = gatts_attr_db[i].attr_control.auto_rsp; BTA_GATTS_AddCharDescriptor(svc_hal, perm, &bta_char_uuid, &attr_val, &control); - + if (future_await(future_p) == FUTURE_FAIL) { BTC_TRACE_ERROR("%s failed\n", __func__); return; @@ -419,7 +411,7 @@ static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db, break; } - + } param.add_attr_tab.handles = btc_creat_tab_env.handles; @@ -427,7 +419,7 @@ static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db, param.add_attr_tab.svc_inst_id = srvc_inst_id; - btc_gatts_cb_to_app(ESP_GATTS_CREAT_ATTR_TAB_EVT, gatts_if, ¶m); + btc_gatts_cb_to_app(ESP_GATTS_CREAT_ATTR_TAB_EVT, gatts_if, ¶m); //reset the env after sent the data to app memset(&btc_creat_tab_env, 0, sizeof(esp_btc_creat_tab_t)); @@ -504,7 +496,7 @@ static esp_gatt_status_t btc_gatts_check_valid_attr_tab(esp_gatts_attr_db_t *gat esp_gatt_status_t btc_gatts_get_attr_value(uint16_t attr_handle, uint16_t *length, uint8_t **value) { - + return BTA_GetAttributeValue(attr_handle, length, value); } @@ -568,14 +560,14 @@ static void btc_gatts_inter_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) { bt_status_t status; btc_msg_t msg; - + msg.sig = BTC_SIG_API_CB; msg.pid = BTC_PID_GATTS; msg.act = event; if(btc_creat_tab_env.is_tab_creat_svc && btc_creat_tab_env.complete_future) { switch(event) { case BTA_GATTS_CREATE_EVT: { - //save the service handle to the btc module after used + //save the service handle to the btc module after used //the attribute table method to creat a service bta_to_btc_uuid(&btc_creat_tab_env.svc_uuid, &p_data->create.uuid); uint8_t index = btc_creat_tab_env.handle_idx; @@ -663,7 +655,7 @@ void btc_gatts_call_handler(btc_msg_t *msg) btc_to_bta_uuid(&uuid, &arg->add_char.char_uuid); BTA_GATTS_AddCharacteristic(arg->add_char.service_handle, &uuid, - arg->add_char.perm, arg->add_char.property, + arg->add_char.perm, arg->add_char.property, (tGATT_ATTR_VAL *)&arg->add_char.char_val, (tBTA_GATTS_ATTR_CONTROL *)&arg->add_char.attr_control); break; @@ -672,7 +664,7 @@ void btc_gatts_call_handler(btc_msg_t *msg) tBT_UUID uuid; btc_to_bta_uuid(&uuid, &arg->add_descr.descr_uuid); BTA_GATTS_AddCharDescriptor(arg->add_descr.service_handle, arg->add_descr.perm, &uuid, - (tBTA_GATT_ATTR_VAL *)&arg->add_descr.descr_val, + (tBTA_GATT_ATTR_VAL *)&arg->add_descr.descr_val, (tBTA_GATTS_ATTR_CONTROL *)&arg->add_descr.attr_control); break; } @@ -700,7 +692,7 @@ void btc_gatts_call_handler(btc_msg_t *msg) break; } case BTC_GATTS_ACT_SET_ATTR_VALUE: - BTA_SetAttributeValue(arg->set_attr_val.handle, arg->set_attr_val.length, + BTA_SetAttributeValue(arg->set_attr_val.handle, arg->set_attr_val.length, arg->set_attr_val.value); break; case BTC_GATTS_ACT_OPEN: { @@ -785,7 +777,7 @@ void btc_gatts_cb_handler(btc_msg_t *msg) param.read.offset = p_data->req_data.p_data->read_req.offset; param.read.is_long = p_data->req_data.p_data->read_req.is_long; - param.read.need_rsp = p_data->req_data.p_data->read_req.need_rsp; + param.read.need_rsp = p_data->req_data.p_data->read_req.need_rsp; btc_gatts_cb_to_app(ESP_GATTS_READ_EVT, gatts_if, ¶m); break; } diff --git a/components/bt/bluedroid/btc/profile/std/hf_client/btc_hf_client.c b/components/bt/bluedroid/btc/profile/std/hf_client/btc_hf_client.c index d0cdbc5e66..d3ccd66997 100644 --- a/components/bt/bluedroid/btc/profile/std/hf_client/btc_hf_client.c +++ b/components/bt/bluedroid/btc/profile/std/hf_client/btc_hf_client.c @@ -61,42 +61,31 @@ BTA_HF_CLIENT_FEAT_CODEC) #endif -/************************************************************************************ -** Local type definitions -************************************************************************************/ -/* BTC-HF control block to map bdaddr to BTA handle */ -typedef struct -{ - bool initialized; - UINT16 handle; - bt_bdaddr_t connected_bda; - esp_hf_client_connection_state_t state; - esp_hf_vr_state_t vr_state; - tBTA_HF_CLIENT_PEER_FEAT peer_feat; - tBTA_HF_CLIENT_CHLD_FEAT chld_feat; -} btc_hf_client_cb_t; + /************************************************************************************ ** Static variables ************************************************************************************/ const char *btc_hf_client_version = "1.6"; -static UINT32 btc_hf_client_features = 0; -static btc_hf_client_cb_t btc_hf_client_cb; -static esp_hf_client_incoming_data_cb_t btc_hf_client_incoming_data_cb = NULL; -static esp_hf_client_outgoing_data_cb_t btc_hf_client_outgoing_data_cb = NULL; + +#if HFP_DYNAMIC_MEMORY == FALSE +static hf_client_local_param_t hf_client_local_param; +#else +hf_client_local_param_t *hf_client_local_param_ptr; +#endif /************************************************************************************ ** Static functions ************************************************************************************/ #define CHECK_HF_CLIENT_INIT() do { \ -if (! btc_hf_client_cb.initialized) { \ +if (! hf_client_local_param.btc_hf_client_cb.initialized) { \ return BT_STATUS_NOT_READY; \ } \ } while (0) #define CHECK_HF_CLIENT_SLC_CONNECTED() do { \ -if (! btc_hf_client_cb.initialized || \ - btc_hf_client_cb.state != ESP_HF_CLIENT_CONNECTION_STATE_SLC_CONNECTED) { \ +if (! hf_client_local_param.btc_hf_client_cb.initialized || \ + hf_client_local_param.btc_hf_client_cb.state != ESP_HF_CLIENT_CONNECTION_STATE_SLC_CONNECTED) { \ return BT_STATUS_NOT_READY; \ } \ } while (0) @@ -111,14 +100,14 @@ static inline void btc_hf_client_cb_to_app(esp_hf_client_cb_event_t event, esp_h static void clear_state(void) { - memset(&btc_hf_client_cb, 0, sizeof(btc_hf_client_cb_t)); + memset(&hf_client_local_param.btc_hf_client_cb, 0, sizeof(btc_hf_client_cb_t)); } static BOOLEAN is_connected(bt_bdaddr_t *bd_addr) { - if (((btc_hf_client_cb.state == ESP_HF_CLIENT_CONNECTION_STATE_CONNECTED) || - (btc_hf_client_cb.state == ESP_HF_CLIENT_CONNECTION_STATE_SLC_CONNECTED))&& - ((bd_addr == NULL) || (bdcmp(bd_addr->address, btc_hf_client_cb.connected_bda.address) == 0))) + if (((hf_client_local_param.btc_hf_client_cb.state == ESP_HF_CLIENT_CONNECTION_STATE_CONNECTED) || + (hf_client_local_param.btc_hf_client_cb.state == ESP_HF_CLIENT_CONNECTION_STATE_SLC_CONNECTED))&& + ((bd_addr == NULL) || (bdcmp(bd_addr->address, hf_client_local_param.btc_hf_client_cb.connected_bda.address) == 0))) return TRUE; return FALSE; } @@ -126,23 +115,23 @@ static BOOLEAN is_connected(bt_bdaddr_t *bd_addr) void btc_hf_client_reg_data_cb(esp_hf_client_incoming_data_cb_t recv, esp_hf_client_outgoing_data_cb_t send) { - btc_hf_client_incoming_data_cb = recv; - btc_hf_client_outgoing_data_cb = send; + hf_client_local_param.btc_hf_client_incoming_data_cb = recv; + hf_client_local_param.btc_hf_client_outgoing_data_cb = send; } void btc_hf_client_incoming_data_cb_to_app(const uint8_t *data, uint32_t len) { // todo: critical section protection - if (btc_hf_client_incoming_data_cb) { - btc_hf_client_incoming_data_cb(data, len); + if (hf_client_local_param.btc_hf_client_incoming_data_cb) { + hf_client_local_param.btc_hf_client_incoming_data_cb(data, len); } } uint32_t btc_hf_client_outgoing_data_cb_to_app(uint8_t *data, uint32_t len) { // todo: critical section protection - if (btc_hf_client_outgoing_data_cb) { - return btc_hf_client_outgoing_data_cb(data, len); + if (hf_client_local_param.btc_hf_client_outgoing_data_cb) { + return hf_client_local_param.btc_hf_client_outgoing_data_cb(data, len); } else { return 0; } @@ -172,7 +161,7 @@ bt_status_t btc_hf_client_init(void) clear_state(); - btc_hf_client_cb.initialized = true; + hf_client_local_param.btc_hf_client_cb.initialized = true; #if BTM_SCO_HCI_INCLUDED data_path = ESP_SCO_DATA_PATH_HCI; @@ -199,10 +188,10 @@ static bt_status_t connect_int( bt_bdaddr_t *bd_addr, uint16_t uuid ) return BT_STATUS_BUSY; } - btc_hf_client_cb.state = ESP_HF_CLIENT_CONNECTION_STATE_CONNECTING; - bdcpy(btc_hf_client_cb.connected_bda.address, bd_addr->address); + hf_client_local_param.btc_hf_client_cb.state = ESP_HF_CLIENT_CONNECTION_STATE_CONNECTING; + bdcpy(hf_client_local_param.btc_hf_client_cb.connected_bda.address, bd_addr->address); - BTA_HfClientOpen(btc_hf_client_cb.handle, btc_hf_client_cb.connected_bda.address, + BTA_HfClientOpen(hf_client_local_param.btc_hf_client_cb.handle, hf_client_local_param.btc_hf_client_cb.connected_bda.address, BTC_HF_CLIENT_SECURITY); return BT_STATUS_SUCCESS; @@ -232,7 +221,7 @@ void btc_hf_client_deinit( void ) btc_dm_disable_service(BTA_HFP_HS_SERVICE_ID); - btc_hf_client_cb.initialized = false; + hf_client_local_param.btc_hf_client_cb.initialized = false; } /******************************************************************************* @@ -250,7 +239,7 @@ bt_status_t btc_hf_client_disconnect( bt_bdaddr_t *bd_addr ) if (is_connected(bd_addr)) { - BTA_HfClientClose(btc_hf_client_cb.handle); + BTA_HfClientClose(hf_client_local_param.btc_hf_client_cb.handle); return BT_STATUS_SUCCESS; } @@ -272,13 +261,13 @@ bt_status_t btc_hf_client_connect_audio( bt_bdaddr_t *bd_addr ) if (is_connected(bd_addr)) { - if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_CODEC) + if (hf_client_local_param.btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_CODEC) { - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BCC, 0, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BCC, 0, 0, NULL); } else { - BTA_HfClientAudioOpen(btc_hf_client_cb.handle); + BTA_HfClientAudioOpen(hf_client_local_param.btc_hf_client_cb.handle); } /* Inform the application that the audio connection has been initiated successfully */ @@ -286,7 +275,7 @@ bt_status_t btc_hf_client_connect_audio( bt_bdaddr_t *bd_addr ) esp_hf_client_cb_param_t param; memset(¶m, 0, sizeof(esp_hf_client_cb_param_t)); param.audio_stat.state = ESP_HF_CLIENT_AUDIO_STATE_CONNECTING; - memcpy(param.audio_stat.remote_bda, &btc_hf_client_cb.connected_bda, sizeof(esp_bd_addr_t)); + memcpy(param.audio_stat.remote_bda, &hf_client_local_param.btc_hf_client_cb.connected_bda, sizeof(esp_bd_addr_t)); btc_hf_client_cb_to_app(ESP_HF_CLIENT_AUDIO_STATE_EVT, ¶m); } while (0); @@ -311,7 +300,7 @@ bt_status_t btc_hf_client_disconnect_audio( bt_bdaddr_t *bd_addr ) if (is_connected(bd_addr)) { - BTA_HfClientAudioClose(btc_hf_client_cb.handle); + BTA_HfClientAudioClose(hf_client_local_param.btc_hf_client_cb.handle); return BT_STATUS_SUCCESS; } @@ -331,9 +320,9 @@ static bt_status_t btc_hf_client_start_voice_recognition(void) { CHECK_HF_CLIENT_SLC_CONNECTED(); - if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_VREC) + if (hf_client_local_param.btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_VREC) { - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BVRA, 1, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BVRA, 1, 0, NULL); return BT_STATUS_SUCCESS; } @@ -355,9 +344,9 @@ static bt_status_t btc_hf_client_stop_voice_recognition(void) { CHECK_HF_CLIENT_SLC_CONNECTED(); - if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_VREC) + if (hf_client_local_param.btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_VREC) { - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BVRA, 0, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BVRA, 0, 0, NULL); return BT_STATUS_SUCCESS; } @@ -381,10 +370,10 @@ static bt_status_t btc_hf_client_volume_update(esp_hf_volume_control_target_t ty switch (type) { case ESP_HF_VOLUME_CONTROL_TARGET_SPK: - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_VGS, volume, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_VGS, volume, 0, NULL); break; case ESP_HF_VOLUME_CONTROL_TARGET_MIC: - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_VGM, volume, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_VGM, volume, 0, NULL); break; default: return BT_STATUS_UNSUPPORTED; @@ -408,11 +397,11 @@ static bt_status_t btc_hf_client_dial(const char *number) if (strlen(number) != 0) { - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_ATD, 0, 0, number); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_ATD, 0, 0, number); } else { - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BLDN, 0, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BLDN, 0, 0, NULL); } return BT_STATUS_SUCCESS; @@ -431,7 +420,7 @@ static bt_status_t btc_hf_client_dial_memory(int location) { CHECK_HF_CLIENT_SLC_CONNECTED(); - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_ATD, location, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_ATD, location, 0, NULL); return BT_STATUS_SUCCESS; } @@ -443,61 +432,61 @@ static bt_status_t btc_hf_client_send_chld_cmd(esp_hf_chld_type_t type, int idx) switch (type) { case ESP_HF_CHLD_TYPE_REL: - if (btc_hf_client_cb.chld_feat & BTA_HF_CLIENT_CHLD_REL) + if (hf_client_local_param.btc_hf_client_cb.chld_feat & BTA_HF_CLIENT_CHLD_REL) { - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 0, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 0, 0, NULL); break; } return BT_STATUS_UNSUPPORTED; case ESP_HF_CHLD_TYPE_REL_ACC: // CHLD 1 is mandatory for 3 way calling - if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_3WAY) + if (hf_client_local_param.btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_3WAY) { - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 1, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 1, 0, NULL); break; } return BT_STATUS_UNSUPPORTED; case ESP_HF_CHLD_TYPE_HOLD_ACC: // CHLD 2 is mandatory for 3 way calling - if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_3WAY) + if (hf_client_local_param.btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_3WAY) { - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 2, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 2, 0, NULL); break; } return BT_STATUS_UNSUPPORTED; case ESP_HF_CHLD_TYPE_MERGE: - if (btc_hf_client_cb.chld_feat & BTA_HF_CLIENT_CHLD_MERGE) + if (hf_client_local_param.btc_hf_client_cb.chld_feat & BTA_HF_CLIENT_CHLD_MERGE) { - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 3, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 3, 0, NULL); break; } return BT_STATUS_UNSUPPORTED; case ESP_HF_CHLD_TYPE_MERGE_DETACH: - if (btc_hf_client_cb.chld_feat & BTA_HF_CLIENT_CHLD_MERGE_DETACH) + if (hf_client_local_param.btc_hf_client_cb.chld_feat & BTA_HF_CLIENT_CHLD_MERGE_DETACH) { - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 4, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 4, 0, NULL); break; } return BT_STATUS_UNSUPPORTED; case ESP_HF_CHLD_TYPE_REL_X: - if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_ECC) + if (hf_client_local_param.btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_ECC) { if (idx < 1) { return BT_STATUS_FAIL; } - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 1, idx, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 1, idx, NULL); break; } return BT_STATUS_UNSUPPORTED; case ESP_HF_CHLD_TYPE_PRIV_X: - if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_ECC) + if (hf_client_local_param.btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_ECC) { if (idx < 1) { return BT_STATUS_FAIL; } - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 2, idx, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 2, idx, NULL); break; } return BT_STATUS_UNSUPPORTED; @@ -512,13 +501,13 @@ static bt_status_t btc_hf_client_send_btrh_cmd(esp_hf_btrh_cmd_t btrh) switch (btrh) { case ESP_HF_BTRH_CMD_HOLD: - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BTRH, 0, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BTRH, 0, 0, NULL); break; case ESP_HF_BTRH_CMD_ACCEPT: - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BTRH, 1, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BTRH, 1, 0, NULL); break; case ESP_HF_BTRH_CMD_REJECT: - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BTRH, 2, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BTRH, 2, 0, NULL); break; default: return BT_STATUS_FAIL; @@ -530,14 +519,14 @@ static bt_status_t btc_hf_client_send_btrh_cmd(esp_hf_btrh_cmd_t btrh) static bt_status_t btc_hf_client_answer_call(void) { CHECK_HF_CLIENT_SLC_CONNECTED(); - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_ATA, 0, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_ATA, 0, 0, NULL); return BT_STATUS_SUCCESS; } static bt_status_t btc_hf_client_reject_call(void) { CHECK_HF_CLIENT_SLC_CONNECTED(); - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHUP, 0, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHUP, 0, 0, NULL); return BT_STATUS_SUCCESS; } @@ -554,9 +543,9 @@ static bt_status_t btc_hf_client_query_current_calls(void) { CHECK_HF_CLIENT_SLC_CONNECTED(); - if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_ECS) + if (hf_client_local_param.btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_ECS) { - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CLCC, 0, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CLCC, 0, 0, NULL); return BT_STATUS_SUCCESS; } @@ -577,7 +566,7 @@ static bt_status_t btc_hf_client_query_current_operator_name(void) { CHECK_HF_CLIENT_SLC_CONNECTED(); - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_COPS, 0, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_COPS, 0, 0, NULL); return BT_STATUS_SUCCESS; } @@ -595,7 +584,7 @@ static bt_status_t btc_hf_client_retrieve_subscriber_info(void) { CHECK_HF_CLIENT_SLC_CONNECTED(); - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CNUM, 0, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CNUM, 0, 0, NULL); return BT_STATUS_SUCCESS; } @@ -613,7 +602,7 @@ static bt_status_t btc_hf_client_send_dtmf(char code) { CHECK_HF_CLIENT_SLC_CONNECTED(); - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_VTS, code, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_VTS, code, 0, NULL); return BT_STATUS_SUCCESS; } @@ -631,9 +620,9 @@ static bt_status_t btc_hf_client_request_last_voice_tag_number(void) { CHECK_HF_CLIENT_SLC_CONNECTED(); - if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_VTAG) + if (hf_client_local_param.btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_VTAG) { - BTA_HfClientSendAT(btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BINP, 1, 0, NULL); + BTA_HfClientSendAT(hf_client_local_param.btc_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BINP, 1, 0, NULL); return BT_STATUS_SUCCESS; } @@ -694,17 +683,17 @@ bt_status_t btc_hf_client_execute_service(BOOLEAN b_enable) else { BTC_TRACE_EVENT("No Codec Nego Supported"); - btc_hf_client_features = BTC_HF_CLIENT_FEATURES; - btc_hf_client_features = btc_hf_client_features & (~BTA_HF_CLIENT_FEAT_CODEC); - BTC_TRACE_EVENT("btc_hf_client_features is %d", btc_hf_client_features); - BTA_HfClientRegister(BTC_HF_CLIENT_SECURITY, btc_hf_client_features, + hf_client_local_param.btc_hf_client_features = BTC_HF_CLIENT_FEATURES; + hf_client_local_param.btc_hf_client_features = hf_client_local_param.btc_hf_client_features & (~BTA_HF_CLIENT_FEAT_CODEC); + BTC_TRACE_EVENT("hf_client_local_param.btc_hf_client_features is %d", hf_client_local_param.btc_hf_client_features); + BTA_HfClientRegister(BTC_HF_CLIENT_SECURITY, hf_client_local_param.btc_hf_client_features, BTC_HF_CLIENT_SERVICE_NAME); } } else { - BTA_HfClientDeregister(btc_hf_client_cb.handle); + BTA_HfClientDeregister(hf_client_local_param.btc_hf_client_cb.handle); BTA_HfClientDisable(); } return BT_STATUS_SUCCESS; @@ -769,44 +758,43 @@ void btc_hf_client_cb_handler(btc_msg_t *msg) case BTA_HF_CLIENT_DISABLE_EVT: break; case BTA_HF_CLIENT_REGISTER_EVT: - btc_hf_client_cb.handle = p_data->reg.handle; + hf_client_local_param.btc_hf_client_cb.handle = p_data->reg.handle; break; case BTA_HF_CLIENT_OPEN_EVT: if (p_data->open.status == BTA_HF_CLIENT_SUCCESS) { - bdcpy(btc_hf_client_cb.connected_bda.address, p_data->open.bd_addr); - btc_hf_client_cb.state = ESP_HF_CLIENT_CONNECTION_STATE_CONNECTED; - btc_hf_client_cb.peer_feat = 0; - btc_hf_client_cb.chld_feat = 0; + bdcpy(hf_client_local_param.btc_hf_client_cb.connected_bda.address, p_data->open.bd_addr); + hf_client_local_param.btc_hf_client_cb.state = ESP_HF_CLIENT_CONNECTION_STATE_CONNECTED; + hf_client_local_param.btc_hf_client_cb.peer_feat = 0; + hf_client_local_param.btc_hf_client_cb.chld_feat = 0; //clear_phone_state(); } - else if (btc_hf_client_cb.state == ESP_HF_CLIENT_CONNECTION_STATE_CONNECTING) + else if (hf_client_local_param.btc_hf_client_cb.state == ESP_HF_CLIENT_CONNECTION_STATE_CONNECTING) { - btc_hf_client_cb.state = ESP_HF_CLIENT_CONNECTION_STATE_DISCONNECTED; + hf_client_local_param.btc_hf_client_cb.state = ESP_HF_CLIENT_CONNECTION_STATE_DISCONNECTED; } else { BTC_TRACE_WARNING("%s: HF CLient open failed, but another device connected. status=%d state=%d connected device=%s", - __FUNCTION__, p_data->open.status, btc_hf_client_cb.state, bdaddr_to_string(&btc_hf_client_cb.connected_bda, bdstr, sizeof(bdstr))); + __FUNCTION__, p_data->open.status, hf_client_local_param.btc_hf_client_cb.state, bdaddr_to_string(&hf_client_local_param.btc_hf_client_cb.connected_bda, bdstr, sizeof(bdstr))); UNUSED(bdstr); break; } do { memset(¶m, 0, sizeof(esp_hf_client_cb_param_t)); - param.conn_stat.state = btc_hf_client_cb.state; + param.conn_stat.state = hf_client_local_param.btc_hf_client_cb.state; param.conn_stat.peer_feat = 0; param.conn_stat.chld_feat = 0; - memcpy(param.conn_stat.remote_bda, &btc_hf_client_cb.connected_bda, + memcpy(param.conn_stat.remote_bda, &hf_client_local_param.btc_hf_client_cb.connected_bda, sizeof(esp_bd_addr_t)); btc_hf_client_cb_to_app(ESP_HF_CLIENT_CONNECTION_STATE_EVT, ¶m); } while (0); - if (btc_hf_client_cb.state == ESP_HF_CLIENT_CONNECTION_STATE_DISCONNECTED) { - bdsetany(btc_hf_client_cb.connected_bda.address); - } + if (hf_client_local_param.btc_hf_client_cb.state == ESP_HF_CLIENT_CONNECTION_STATE_DISCONNECTED) + bdsetany(hf_client_local_param.btc_hf_client_cb.connected_bda.address); if (p_data->open.status != BTA_HF_CLIENT_SUCCESS) { btc_queue_advance(); @@ -815,24 +803,24 @@ void btc_hf_client_cb_handler(btc_msg_t *msg) break; case BTA_HF_CLIENT_CONN_EVT: - btc_hf_client_cb.peer_feat = p_data->conn.peer_feat; - btc_hf_client_cb.chld_feat = p_data->conn.chld_feat; - btc_hf_client_cb.state = ESP_HF_CLIENT_CONNECTION_STATE_SLC_CONNECTED; + hf_client_local_param.btc_hf_client_cb.peer_feat = p_data->conn.peer_feat; + hf_client_local_param.btc_hf_client_cb.chld_feat = p_data->conn.chld_feat; + hf_client_local_param.btc_hf_client_cb.state = ESP_HF_CLIENT_CONNECTION_STATE_SLC_CONNECTED; do { memset(¶m, 0, sizeof(esp_hf_client_cb_param_t)); - param.conn_stat.state = btc_hf_client_cb.state; - param.conn_stat.peer_feat = btc_hf_client_cb.peer_feat; - param.conn_stat.chld_feat = btc_hf_client_cb.chld_feat; + param.conn_stat.state = hf_client_local_param.btc_hf_client_cb.state; + param.conn_stat.peer_feat = hf_client_local_param.btc_hf_client_cb.peer_feat; + param.conn_stat.chld_feat = hf_client_local_param.btc_hf_client_cb.chld_feat; - memcpy(param.conn_stat.remote_bda, &btc_hf_client_cb.connected_bda, + memcpy(param.conn_stat.remote_bda, &hf_client_local_param.btc_hf_client_cb.connected_bda, sizeof(esp_bd_addr_t)); btc_hf_client_cb_to_app(ESP_HF_CLIENT_CONNECTION_STATE_EVT, ¶m); } while (0); /* Inform the application about in-band ringtone */ - if (btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_INBAND) + if (hf_client_local_param.btc_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_INBAND) { do { memset(¶m, 0, sizeof(esp_hf_client_cb_param_t)); @@ -845,22 +833,22 @@ void btc_hf_client_cb_handler(btc_msg_t *msg) break; case BTA_HF_CLIENT_CLOSE_EVT: - btc_hf_client_cb.state = ESP_HF_CLIENT_CONNECTION_STATE_DISCONNECTED; + hf_client_local_param.btc_hf_client_cb.state = ESP_HF_CLIENT_CONNECTION_STATE_DISCONNECTED; do { memset(¶m, 0, sizeof(esp_hf_client_cb_param_t)); param.conn_stat.state = ESP_HF_CLIENT_CONNECTION_STATE_DISCONNECTED; param.conn_stat.peer_feat = 0; param.conn_stat.chld_feat = 0; - memcpy(param.conn_stat.remote_bda, &btc_hf_client_cb.connected_bda, + memcpy(param.conn_stat.remote_bda, &hf_client_local_param.btc_hf_client_cb.connected_bda, sizeof(esp_bd_addr_t)); btc_hf_client_cb_to_app(ESP_HF_CLIENT_CONNECTION_STATE_EVT, ¶m); } while (0); - bdsetany(btc_hf_client_cb.connected_bda.address); - btc_hf_client_cb.peer_feat = 0; - btc_hf_client_cb.chld_feat = 0; + bdsetany(hf_client_local_param.btc_hf_client_cb.connected_bda.address); + hf_client_local_param.btc_hf_client_cb.peer_feat = 0; + hf_client_local_param.btc_hf_client_cb.chld_feat = 0; btc_queue_advance(); break; case BTA_HF_CLIENT_IND_EVT: @@ -983,7 +971,7 @@ void btc_hf_client_cb_handler(btc_msg_t *msg) do { memset(¶m, 0, sizeof(esp_hf_client_cb_param_t)); param.audio_stat.state = ESP_HF_CLIENT_AUDIO_STATE_CONNECTED; - memcpy(param.audio_stat.remote_bda, &btc_hf_client_cb.connected_bda, + memcpy(param.audio_stat.remote_bda, &hf_client_local_param.btc_hf_client_cb.connected_bda, sizeof(esp_bd_addr_t)); btc_hf_client_cb_to_app(ESP_HF_CLIENT_AUDIO_STATE_EVT, ¶m); } while (0); @@ -992,7 +980,7 @@ void btc_hf_client_cb_handler(btc_msg_t *msg) do { memset(¶m, 0, sizeof(esp_hf_client_cb_param_t)); param.audio_stat.state = ESP_HF_CLIENT_AUDIO_STATE_CONNECTED_MSBC; - memcpy(param.audio_stat.remote_bda, &btc_hf_client_cb.connected_bda, + memcpy(param.audio_stat.remote_bda, &hf_client_local_param.btc_hf_client_cb.connected_bda, sizeof(esp_bd_addr_t)); btc_hf_client_cb_to_app(ESP_HF_CLIENT_AUDIO_STATE_EVT, ¶m); } while (0); @@ -1001,7 +989,7 @@ void btc_hf_client_cb_handler(btc_msg_t *msg) do { memset(¶m, 0, sizeof(esp_hf_client_cb_param_t)); param.audio_stat.state = ESP_HF_CLIENT_AUDIO_STATE_DISCONNECTED; - memcpy(param.audio_stat.remote_bda, &btc_hf_client_cb.connected_bda, + memcpy(param.audio_stat.remote_bda, &hf_client_local_param.btc_hf_client_cb.connected_bda, sizeof(esp_bd_addr_t)); btc_hf_client_cb_to_app(ESP_HF_CLIENT_AUDIO_STATE_EVT, ¶m); } while (0); diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_avrc.h b/components/bt/bluedroid/btc/profile/std/include/btc_avrc.h index 7eaabecc17..7d72393d82 100644 --- a/components/bt/bluedroid/btc/profile/std/include/btc_avrc.h +++ b/components/bt/bluedroid/btc/profile/std/include/btc_avrc.h @@ -86,6 +86,50 @@ typedef enum { BTC_AVRC_TG_API_SEND_RN_RSP_EVT, } btc_avrc_tg_act_t; +/***************************************************************************** +** Constants & Macros +******************************************************************************/ +/* for AVRC 1.4 need to change this */ +#define BTC_RC_CT_INIT_MAGIC 0x20181128 +#define BTC_RC_TG_INIT_MAGIC 0x20181129 + +#define MAX_RC_NOTIFICATIONS (13) // refer to ESP_AVRC_RN_MAX_EVT + + +#define CHECK_ESP_RC_CONNECTED do { \ + BTC_TRACE_DEBUG("## %s ##", __FUNCTION__); \ + if (btc_rc_vb.rc_connected == FALSE) { \ + BTC_TRACE_WARNING("Function %s() called when RC is not connected", __FUNCTION__); \ + return ESP_ERR_INVALID_STATE; \ + } \ + } while (0) + +/***************************************************************************** +** Local type definitions +******************************************************************************/ +typedef struct { + BOOLEAN registered; + UINT8 label; +} btc_rc_reg_ntf_t; + +typedef struct { + BOOLEAN rc_connected; + UINT8 rc_handle; + tBTA_AV_FEAT rc_features; + UINT16 rc_ct_features; + UINT16 rc_tg_features; + BD_ADDR rc_addr; + btc_rc_reg_ntf_t rc_ntf[MAX_RC_NOTIFICATIONS]; +} btc_rc_cb_t; + +/***************************************************************************** +** Static variables +******************************************************************************/ +#if AVRC_DYNAMIC_MEMORY == TRUE +extern btc_rc_cb_t *btc_rc_cb_ptr; +#define btc_rc_cb (*btc_rc_cb_ptr) +#endif ///AVRC_DYNAMIC_MEMORY == FALSE + typedef struct { esp_avrc_rn_event_ids_t event_id; esp_avrc_rn_rsp_t rsp; diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_gap_ble.h b/components/bt/bluedroid/btc/profile/std/include/btc_gap_ble.h index be818269b2..b5e2effe7e 100644 --- a/components/bt/bluedroid/btc/profile/std/include/btc_gap_ble.h +++ b/components/bt/bluedroid/btc/profile/std/include/btc_gap_ble.h @@ -18,6 +18,14 @@ #include "esp_bt_defs.h" #include "esp_gap_ble_api.h" +#if BTC_DYNAMIC_MENDRY == TRUE +#include "bta/bta_api.h" +extern tBTA_BLE_ADV_DATA *gl_bta_adv_data_ptr; +extern tBTA_BLE_ADV_DATA *gl_bta_scan_rsp_data_ptr; +#define gl_bta_adv_data (*gl_bta_adv_data_ptr) +#define gl_bta_scan_rsp_data (*gl_bta_scan_rsp_data_ptr) +#endif + #define BLE_ISVALID_PARAM(x, min, max) (((x) >= (min) && (x) <= (max)) || ((x) == ESP_BLE_CONN_PARAM_UNDEF)) typedef enum { diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_gatts.h b/components/bt/bluedroid/btc/profile/std/include/btc_gatts.h index cad973a8a6..5cf1e84161 100644 --- a/components/bt/bluedroid/btc/profile/std/include/btc_gatts.h +++ b/components/bt/bluedroid/btc/profile/std/include/btc_gatts.h @@ -19,6 +19,7 @@ #include "esp_bt_defs.h" #include "esp_gatt_defs.h" #include "esp_gatts_api.h" +#include "osi/future.h" typedef enum { BTC_GATTS_ACT_APP_REGISTER = 0, @@ -150,6 +151,21 @@ typedef union { } btc_ble_gatts_args_t; +typedef struct { + future_t *complete_future; + uint16_t svc_start_hdl; + esp_bt_uuid_t svc_uuid; + bool is_tab_creat_svc; + bool is_use_svc; + uint8_t num_handle; + uint8_t handle_idx; + uint16_t handles[ESP_GATT_ATTR_HANDLE_MAX]; +} esp_btc_creat_tab_t; + +#if GATT_DYNAMIC_MEMORY == TRUE +extern esp_btc_creat_tab_t *btc_creat_tab_env_ptr; +#define btc_creat_tab_env (*btc_creat_tab_env_ptr) +#endif void btc_gatts_call_handler(btc_msg_t *msg); void btc_gatts_cb_handler(btc_msg_t *msg); diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_hf_client.h b/components/bt/bluedroid/btc/profile/std/include/btc_hf_client.h index 6500b9d878..04226e72a2 100644 --- a/components/bt/bluedroid/btc/profile/std/include/btc_hf_client.h +++ b/components/bt/bluedroid/btc/profile/std/include/btc_hf_client.h @@ -112,6 +112,34 @@ typedef union { } reg_data_cb; } btc_hf_client_args_t; +/************************************************************************************ +** Local type definitions +************************************************************************************/ +/* BTC-HF control block to map bdaddr to BTA handle */ +typedef struct +{ + bool initialized; + UINT16 handle; + bt_bdaddr_t connected_bda; + esp_hf_client_connection_state_t state; + esp_hf_vr_state_t vr_state; + tBTA_HF_CLIENT_PEER_FEAT peer_feat; + tBTA_HF_CLIENT_CHLD_FEAT chld_feat; +} btc_hf_client_cb_t; + +typedef struct +{ + UINT32 btc_hf_client_features; + btc_hf_client_cb_t btc_hf_client_cb; + esp_hf_client_incoming_data_cb_t btc_hf_client_incoming_data_cb; + esp_hf_client_outgoing_data_cb_t btc_hf_client_outgoing_data_cb; +}hf_client_local_param_t; + +#if HFP_DYNAMIC_MEMORY == TRUE +extern hf_client_local_param_t *hf_client_local_param_ptr; +#define hf_client_local_param (*hf_client_local_param_ptr) +#endif + /******************************************************************************* ** BTC HF AG API ********************************************************************************/ diff --git a/components/bt/bluedroid/btc/profile/std/spp/btc_spp.c b/components/bt/bluedroid/btc/profile/std/spp/btc_spp.c index bc2d62427d..93636ef71c 100644 --- a/components/bt/bluedroid/btc/profile/std/spp/btc_spp.c +++ b/components/bt/bluedroid/btc/profile/std/spp/btc_spp.c @@ -55,13 +55,20 @@ typedef struct { char service_name[ESP_SPP_SERVER_NAME_MAX + 1]; } spp_slot_t; -static struct spp_local_param_t { +typedef struct { spp_slot_t *spp_slots[BTA_JV_MAX_RFC_SR_SESSION + 1]; uint32_t spp_slot_id; esp_spp_mode_t spp_mode; osi_mutex_t spp_slot_mutex; esp_vfs_id_t spp_vfs_id; -} spp_local_param; +} spp_local_param_t; + +#if SPP_DYNAMIC_MEMORY == FALSE +static spp_local_param_t spp_local_param; +#else +static spp_local_param_t *spp_local_param_ptr; +#define spp_local_param (*spp_local_param_ptr) +#endif static void spp_osi_free(void *p) { @@ -313,6 +320,15 @@ static void btc_spp_dm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_d static void btc_spp_init(btc_spp_args_t *arg) { + +#if SPP_DYNAMIC_MEMORY == TRUE + if ((spp_local_param_ptr = (spp_local_param_t *)osi_malloc(sizeof(spp_local_param_t))) == NULL) { + BTC_TRACE_ERROR("%s malloc failed\n", __func__); + return; + } + memset((void *)spp_local_param_ptr, 0, sizeof(spp_local_param_t)); +#endif + if (osi_mutex_new(&spp_local_param.spp_slot_mutex) != 0) { BTC_TRACE_ERROR("%s osi_mutex_new failed\n", __func__); return; @@ -349,6 +365,11 @@ static void btc_spp_uninit(void) BTA_JvDisable(); osi_mutex_unlock(&spp_local_param.spp_slot_mutex); osi_mutex_free(&spp_local_param.spp_slot_mutex); + +#if SPP_DYNAMIC_MEMORY == TRUE + osi_free(spp_local_param_ptr); + spp_local_param_ptr = NULL; +#endif } static void btc_spp_start_discovery(btc_spp_args_t *arg) diff --git a/components/bt/bluedroid/common/include/common/bt_target.h b/components/bt/bluedroid/common/include/common/bt_target.h index b781d435ac..c8f15e8694 100644 --- a/components/bt/bluedroid/common/include/common/bt_target.h +++ b/components/bt/bluedroid/common/include/common/bt_target.h @@ -2049,12 +2049,6 @@ The maximum number of payload octets that the local device can receive in a sing #define HEAP_ALLOCATION_FROM_SPIRAM_FIRST FALSE #endif -#if UC_BT_BLE_DYNAMIC_ENV_MEMORY -#define BT_BLE_DYNAMIC_ENV_MEMORY TRUE -#else -#define BT_BLE_DYNAMIC_ENV_MEMORY FALSE -#endif - #include "common/bt_trace.h" #endif /* BT_TARGET_H */ diff --git a/components/bt/bluedroid/device/controller.c b/components/bt/bluedroid/device/controller.c index 45ef4ea504..df6c5018f6 100644 --- a/components/bt/bluedroid/device/controller.c +++ b/components/bt/bluedroid/device/controller.c @@ -46,38 +46,47 @@ const uint8_t SCO_HOST_BUFFER_SIZE = 0xff; #define BLE_SUPPORTED_STATES_SIZE 8 #define BLE_SUPPORTED_FEATURES_SIZE 8 -static const hci_t *hci; -static const hci_packet_factory_t *packet_factory; -static const hci_packet_parser_t *packet_parser; +typedef struct { + const hci_t *hci; + const hci_packet_factory_t *packet_factory; + const hci_packet_parser_t *packet_parser; -static bt_bdaddr_t address; -static bt_version_t bt_version; + bt_version_t bt_version; + bt_bdaddr_t address; -static uint8_t supported_commands[HCI_SUPPORTED_COMMANDS_ARRAY_SIZE]; -static bt_device_features_t features_classic[MAX_FEATURES_CLASSIC_PAGE_COUNT]; -static uint8_t last_features_classic_page_index; + uint8_t supported_commands[HCI_SUPPORTED_COMMANDS_ARRAY_SIZE]; + uint8_t last_features_classic_page_index; + bt_device_features_t features_classic[MAX_FEATURES_CLASSIC_PAGE_COUNT]; -static uint16_t acl_data_size_classic; -static uint16_t acl_data_size_ble; -static uint16_t acl_buffer_count_classic; -static uint8_t acl_buffer_count_ble; + uint16_t acl_data_size_classic; + uint16_t acl_data_size_ble; + uint16_t acl_buffer_count_classic; + uint8_t acl_buffer_count_ble; -static uint8_t sco_data_size; -static uint16_t sco_buffer_count; + uint8_t sco_data_size; + uint16_t sco_buffer_count; -static uint8_t ble_white_list_size; -static uint8_t ble_resolving_list_max_size; -static uint8_t ble_supported_states[BLE_SUPPORTED_STATES_SIZE]; -static bt_device_features_t features_ble; -static uint16_t ble_suggested_default_data_length; -static uint16_t ble_suggested_default_data_txtime; + uint8_t ble_white_list_size; + uint8_t ble_resolving_list_max_size; + uint8_t ble_supported_states[BLE_SUPPORTED_STATES_SIZE]; + bt_device_features_t features_ble; + uint16_t ble_suggested_default_data_length; + uint16_t ble_suggested_default_data_txtime; -static bool readable; -static bool ble_supported; -static bool simple_pairing_supported; -static bool secure_connections_supported; + bool readable; + bool ble_supported; + bool simple_pairing_supported; + bool secure_connections_supported; +} controller_local_param_t; -#define AWAIT_COMMAND(command) future_await(hci->transmit_command_futured(command)) +#if BT_BLE_DYNAMIC_ENV_MEMORY == FALSE +static controller_local_param_t controller_param; +#else +static controller_local_param_t *controller_param_ptr; +#define controller_param (*controller_param_ptr) +#endif + +#define AWAIT_COMMAND(command) future_await(controller_param.hci->transmit_command_futured(command)) // Module lifecycle functions @@ -86,19 +95,19 @@ static void start_up(void) BT_HDR *response; // Send the initial reset command - response = AWAIT_COMMAND(packet_factory->make_reset()); - packet_parser->parse_generic_command_complete(response); + response = AWAIT_COMMAND(controller_param.packet_factory->make_reset()); + controller_param.packet_parser->parse_generic_command_complete(response); // Request the classic buffer size next - response = AWAIT_COMMAND(packet_factory->make_read_buffer_size()); - packet_parser->parse_read_buffer_size_response( - response, &acl_data_size_classic, &acl_buffer_count_classic, - &sco_data_size, &sco_buffer_count); + response = AWAIT_COMMAND(controller_param.packet_factory->make_read_buffer_size()); + controller_param.packet_parser->parse_read_buffer_size_response( + response, &controller_param.acl_data_size_classic, &controller_param.acl_buffer_count_classic, + &controller_param.sco_data_size, &controller_param.sco_buffer_count); #if (C2H_FLOW_CONTROL_INCLUDED == TRUE) // Enable controller to host flow control - response = AWAIT_COMMAND(packet_factory->make_set_c2h_flow_control(HCI_HOST_FLOW_CTRL_ACL_ON)); - packet_parser->parse_generic_command_complete(response); + response = AWAIT_COMMAND(controller_param.packet_factory->make_set_c2h_flow_control(HCI_HOST_FLOW_CTRL_ACL_ON)); + controller_param.packet_parser->parse_generic_command_complete(response); #endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) // Enable adv flow control @@ -108,7 +117,7 @@ static void start_up(void) // Tell the controller about our buffer sizes and buffer counts next // TODO(zachoverflow): factor this out. eww l2cap contamination. And why just a hardcoded 10? response = AWAIT_COMMAND( - packet_factory->make_host_buffer_size( + controller_param.packet_factory->make_host_buffer_size( L2CAP_MTU_SIZE, SCO_HOST_BUFFER_SIZE, L2CAP_HOST_FC_ACL_BUFS, @@ -116,33 +125,33 @@ static void start_up(void) ) ); - packet_parser->parse_generic_command_complete(response); + controller_param.packet_parser->parse_generic_command_complete(response); // Read the local version info off the controller next, including // information such as manufacturer and supported HCI version - response = AWAIT_COMMAND(packet_factory->make_read_local_version_info()); - packet_parser->parse_read_local_version_info_response(response, &bt_version); + response = AWAIT_COMMAND(controller_param.packet_factory->make_read_local_version_info()); + controller_param.packet_parser->parse_read_local_version_info_response(response, &controller_param.bt_version); // Read the bluetooth address off the controller next - response = AWAIT_COMMAND(packet_factory->make_read_bd_addr()); - packet_parser->parse_read_bd_addr_response(response, &address); + response = AWAIT_COMMAND(controller_param.packet_factory->make_read_bd_addr()); + controller_param.packet_parser->parse_read_bd_addr_response(response, &controller_param.address); // Request the controller's supported commands next - response = AWAIT_COMMAND(packet_factory->make_read_local_supported_commands()); - packet_parser->parse_read_local_supported_commands_response( + response = AWAIT_COMMAND(controller_param.packet_factory->make_read_local_supported_commands()); + controller_param.packet_parser->parse_read_local_supported_commands_response( response, - supported_commands, + controller_param.supported_commands, HCI_SUPPORTED_COMMANDS_ARRAY_SIZE ); // Read page 0 of the controller features next uint8_t page_number = 0; - response = AWAIT_COMMAND(packet_factory->make_read_local_extended_features(page_number)); - packet_parser->parse_read_local_extended_features_response( + response = AWAIT_COMMAND(controller_param.packet_factory->make_read_local_extended_features(page_number)); + controller_param.packet_parser->parse_read_local_extended_features_response( response, &page_number, - &last_features_classic_page_index, - features_classic, + &controller_param.last_features_classic_page_index, + controller_param.features_classic, MAX_FEATURES_CLASSIC_PAGE_COUNT ); @@ -154,36 +163,37 @@ static void start_up(void) // next page, because the controller's response for page 1 may be // dependent on what we configure from page 0 #if (BT_SSP_INCLUDED == TRUE) - simple_pairing_supported = HCI_SIMPLE_PAIRING_SUPPORTED(features_classic[0].as_array); + controller_param.simple_pairing_supported = HCI_SIMPLE_PAIRING_SUPPORTED(controller_param.features_classic[0].as_array); #else - simple_pairing_supported = false; + controller_param.simple_pairing_supported = false; #endif - if (simple_pairing_supported) { - response = AWAIT_COMMAND(packet_factory->make_write_simple_pairing_mode(HCI_SP_MODE_ENABLED)); - packet_parser->parse_generic_command_complete(response); + + if (controller_param.simple_pairing_supported) { + response = AWAIT_COMMAND(controller_param.packet_factory->make_write_simple_pairing_mode(HCI_SP_MODE_ENABLED)); + controller_param.packet_parser->parse_generic_command_complete(response); } #if (BLE_INCLUDED == TRUE) - if (HCI_LE_SPT_SUPPORTED(features_classic[0].as_array)) { - uint8_t simultaneous_le_host = HCI_SIMUL_LE_BREDR_SUPPORTED(features_classic[0].as_array) ? BTM_BLE_SIMULTANEOUS_HOST : 0; + if (HCI_LE_SPT_SUPPORTED(controller_param.features_classic[0].as_array)) { + uint8_t simultaneous_le_host = HCI_SIMUL_LE_BREDR_SUPPORTED(controller_param.features_classic[0].as_array) ? BTM_BLE_SIMULTANEOUS_HOST : 0; response = AWAIT_COMMAND( - packet_factory->make_ble_write_host_support(BTM_BLE_HOST_SUPPORT, simultaneous_le_host) + controller_param.packet_factory->make_ble_write_host_support(BTM_BLE_HOST_SUPPORT, simultaneous_le_host) ); - packet_parser->parse_generic_command_complete(response); + controller_param.packet_parser->parse_generic_command_complete(response); } #endif // Done telling the controller about what page 0 features we support // Request the remaining feature pages - while (page_number <= last_features_classic_page_index && + while (page_number <= controller_param.last_features_classic_page_index && page_number < MAX_FEATURES_CLASSIC_PAGE_COUNT) { - response = AWAIT_COMMAND(packet_factory->make_read_local_extended_features(page_number)); - packet_parser->parse_read_local_extended_features_response( + response = AWAIT_COMMAND(controller_param.packet_factory->make_read_local_extended_features(page_number)); + controller_param.packet_parser->parse_read_local_extended_features_response( response, &page_number, - &last_features_classic_page_index, - features_classic, + &controller_param.last_features_classic_page_index, + controller_param.features_classic, MAX_FEATURES_CLASSIC_PAGE_COUNT ); @@ -191,299 +201,297 @@ static void start_up(void) } #if (SC_MODE_INCLUDED == TRUE) - secure_connections_supported = HCI_SC_CTRLR_SUPPORTED(features_classic[2].as_array); - if (secure_connections_supported) { - response = AWAIT_COMMAND(packet_factory->make_write_secure_connections_host_support(HCI_SC_MODE_ENABLED)); - packet_parser->parse_generic_command_complete(response); + controller_param.secure_connections_supported = HCI_SC_CTRLR_SUPPORTED(controller_param.features_classic[2].as_array); + if (controller_param.secure_connections_supported) { + response = AWAIT_COMMAND(controller_param.packet_factory->make_write_secure_connections_host_support(HCI_SC_MODE_ENABLED)); + controller_param.packet_parser->parse_generic_command_complete(response); } #endif #if (BLE_INCLUDED == TRUE) - ble_supported = last_features_classic_page_index >= 1 && HCI_LE_HOST_SUPPORTED(features_classic[1].as_array); - if (ble_supported) { + controller_param.ble_supported = controller_param.last_features_classic_page_index >= 1 && HCI_LE_HOST_SUPPORTED(controller_param.features_classic[1].as_array); + if (controller_param.ble_supported) { // Request the ble white list size next - response = AWAIT_COMMAND(packet_factory->make_ble_read_white_list_size()); - packet_parser->parse_ble_read_white_list_size_response(response, &ble_white_list_size); + response = AWAIT_COMMAND(controller_param.packet_factory->make_ble_read_white_list_size()); + controller_param.packet_parser->parse_ble_read_white_list_size_response(response, &controller_param.ble_white_list_size); // Request the ble buffer size next - response = AWAIT_COMMAND(packet_factory->make_ble_read_buffer_size()); - packet_parser->parse_ble_read_buffer_size_response( + response = AWAIT_COMMAND(controller_param.packet_factory->make_ble_read_buffer_size()); + controller_param.packet_parser->parse_ble_read_buffer_size_response( response, - &acl_data_size_ble, - &acl_buffer_count_ble + &controller_param.acl_data_size_ble, + &controller_param.acl_buffer_count_ble ); // Response of 0 indicates ble has the same buffer size as classic - if (acl_data_size_ble == 0) { - acl_data_size_ble = acl_data_size_classic; + if (controller_param.acl_data_size_ble == 0) { + controller_param.acl_data_size_ble = controller_param.acl_data_size_classic; } // Request the ble supported states next - response = AWAIT_COMMAND(packet_factory->make_ble_read_supported_states()); - packet_parser->parse_ble_read_supported_states_response( + response = AWAIT_COMMAND(controller_param.packet_factory->make_ble_read_supported_states()); + controller_param.packet_parser->parse_ble_read_supported_states_response( response, - ble_supported_states, - sizeof(ble_supported_states) + controller_param.ble_supported_states, + sizeof(controller_param.ble_supported_states) ); // Request the ble supported features next - response = AWAIT_COMMAND(packet_factory->make_ble_read_local_supported_features()); - packet_parser->parse_ble_read_local_supported_features_response( + response = AWAIT_COMMAND(controller_param.packet_factory->make_ble_read_local_supported_features()); + controller_param.packet_parser->parse_ble_read_local_supported_features_response( response, - &features_ble + &controller_param.features_ble ); - if (HCI_LE_ENHANCED_PRIVACY_SUPPORTED(features_ble.as_array)) { - response = AWAIT_COMMAND(packet_factory->make_ble_read_resolving_list_size()); - packet_parser->parse_ble_read_resolving_list_size_response( + if (HCI_LE_ENHANCED_PRIVACY_SUPPORTED(controller_param.features_ble.as_array)) { + response = AWAIT_COMMAND(controller_param.packet_factory->make_ble_read_resolving_list_size()); + controller_param.packet_parser->parse_ble_read_resolving_list_size_response( response, - &ble_resolving_list_max_size); + &controller_param.ble_resolving_list_max_size); } - if (HCI_LE_DATA_LEN_EXT_SUPPORTED(features_ble.as_array)) { + if (HCI_LE_DATA_LEN_EXT_SUPPORTED(controller_param.features_ble.as_array)) { /* set default tx data length to MAX 251 */ - response = AWAIT_COMMAND(packet_factory->make_ble_write_suggested_default_data_length(BTM_BLE_DATA_SIZE_MAX, BTM_BLE_DATA_TX_TIME_MAX)); - packet_parser->parse_generic_command_complete(response); + response = AWAIT_COMMAND(controller_param.packet_factory->make_ble_write_suggested_default_data_length(BTM_BLE_DATA_SIZE_MAX, BTM_BLE_DATA_TX_TIME_MAX)); + controller_param.packet_parser->parse_generic_command_complete(response); - response = AWAIT_COMMAND(packet_factory->make_ble_read_suggested_default_data_length()); - packet_parser->parse_ble_read_suggested_default_data_length_response( + response = AWAIT_COMMAND(controller_param.packet_factory->make_ble_read_suggested_default_data_length()); + controller_param.packet_parser->parse_ble_read_suggested_default_data_length_response( response, - &ble_suggested_default_data_length, - &ble_suggested_default_data_txtime); + &controller_param.ble_suggested_default_data_length, + &controller_param.ble_suggested_default_data_txtime); } // Set the ble event mask next - response = AWAIT_COMMAND(packet_factory->make_ble_set_event_mask(&BLE_EVENT_MASK)); - packet_parser->parse_generic_command_complete(response); + response = AWAIT_COMMAND(controller_param.packet_factory->make_ble_set_event_mask(&BLE_EVENT_MASK)); + controller_param.packet_parser->parse_generic_command_complete(response); } #endif - - response = AWAIT_COMMAND(packet_factory->make_set_event_mask(&CLASSIC_EVENT_MASK)); - packet_parser->parse_generic_command_complete(response); - + response = AWAIT_COMMAND(controller_param.packet_factory->make_set_event_mask(&CLASSIC_EVENT_MASK)); + controller_param.packet_parser->parse_generic_command_complete(response); #if (BTM_SCO_HCI_INCLUDED == TRUE) - response = AWAIT_COMMAND(packet_factory->make_write_sync_flow_control_enable(1)); - packet_parser->parse_generic_command_complete(response); + response = AWAIT_COMMAND(controller_param.packet_factory->make_write_sync_flow_control_enable(1)); + controller_param.packet_parser->parse_generic_command_complete(response); - response = AWAIT_COMMAND(packet_factory->make_write_default_erroneous_data_report(1)); - packet_parser->parse_generic_command_complete(response); + response = AWAIT_COMMAND(controller_param.packet_factory->make_write_default_erroneous_data_report(1)); + controller_param.packet_parser->parse_generic_command_complete(response); #endif - readable = true; + controller_param.readable = true; // return future_new_immediate(FUTURE_SUCCESS); return; } static void shut_down(void) { - readable = false; + controller_param.readable = false; } static bool get_is_ready(void) { - return readable; + return controller_param.readable; } static const bt_bdaddr_t *get_address(void) { - assert(readable); - return &address; + assert(controller_param.readable); + return &controller_param.address; } static const bt_version_t *get_bt_version(void) { - assert(readable); - return &bt_version; + assert(controller_param.readable); + return &controller_param.bt_version; } // TODO(zachoverflow): hide inside, move decoder inside too static const bt_device_features_t *get_features_classic(int index) { - assert(readable); + assert(controller_param.readable); assert(index < MAX_FEATURES_CLASSIC_PAGE_COUNT); - return &features_classic[index]; + return &controller_param.features_classic[index]; } static uint8_t get_last_features_classic_index(void) { - assert(readable); - return last_features_classic_page_index; + assert(controller_param.readable); + return controller_param.last_features_classic_page_index; } static const bt_device_features_t *get_features_ble(void) { - assert(readable); - assert(ble_supported); - return &features_ble; + assert(controller_param.readable); + assert(controller_param.ble_supported); + return &controller_param.features_ble; } static const uint8_t *get_ble_supported_states(void) { - assert(readable); - assert(ble_supported); - return ble_supported_states; + assert(controller_param.readable); + assert(controller_param.ble_supported); + return controller_param.ble_supported_states; } static bool supports_simple_pairing(void) { - assert(readable); - return simple_pairing_supported; + assert(controller_param.readable); + return controller_param.simple_pairing_supported; } static bool supports_secure_connections(void) { - assert(readable); - return secure_connections_supported; + assert(controller_param.readable); + return controller_param.secure_connections_supported; } static bool supports_simultaneous_le_bredr(void) { - assert(readable); - return HCI_SIMUL_LE_BREDR_SUPPORTED(features_classic[0].as_array); + assert(controller_param.readable); + return HCI_SIMUL_LE_BREDR_SUPPORTED(controller_param.features_classic[0].as_array); } static bool supports_reading_remote_extended_features(void) { - assert(readable); - return HCI_READ_REMOTE_EXT_FEATURES_SUPPORTED(supported_commands); + assert(controller_param.readable); + return HCI_READ_REMOTE_EXT_FEATURES_SUPPORTED(controller_param.supported_commands); } static bool supports_interlaced_inquiry_scan(void) { - assert(readable); - return HCI_LMP_INTERLACED_INQ_SCAN_SUPPORTED(features_classic[0].as_array); + assert(controller_param.readable); + return HCI_LMP_INTERLACED_INQ_SCAN_SUPPORTED(controller_param.features_classic[0].as_array); } static bool supports_rssi_with_inquiry_results(void) { - assert(readable); - return HCI_LMP_INQ_RSSI_SUPPORTED(features_classic[0].as_array); + assert(controller_param.readable); + return HCI_LMP_INQ_RSSI_SUPPORTED(controller_param.features_classic[0].as_array); } static bool supports_extended_inquiry_response(void) { - assert(readable); - return HCI_EXT_INQ_RSP_SUPPORTED(features_classic[0].as_array); + assert(controller_param.readable); + return HCI_EXT_INQ_RSP_SUPPORTED(controller_param.features_classic[0].as_array); } static bool supports_master_slave_role_switch(void) { - assert(readable); - return HCI_SWITCH_SUPPORTED(features_classic[0].as_array); + assert(controller_param.readable); + return HCI_SWITCH_SUPPORTED(controller_param.features_classic[0].as_array); } static bool supports_ble(void) { - assert(readable); - return ble_supported; + assert(controller_param.readable); + return controller_param.ble_supported; } static bool supports_ble_privacy(void) { - assert(readable); - assert(ble_supported); - return HCI_LE_ENHANCED_PRIVACY_SUPPORTED(features_ble.as_array); + assert(controller_param.readable); + assert(controller_param.ble_supported); + return HCI_LE_ENHANCED_PRIVACY_SUPPORTED(controller_param.features_ble.as_array); } static bool supports_ble_packet_extension(void) { - assert(readable); - assert(ble_supported); - return HCI_LE_DATA_LEN_EXT_SUPPORTED(features_ble.as_array); + assert(controller_param.readable); + assert(controller_param.ble_supported); + return HCI_LE_DATA_LEN_EXT_SUPPORTED(controller_param.features_ble.as_array); } static bool supports_ble_connection_parameters_request(void) { - assert(readable); - assert(ble_supported); - return HCI_LE_CONN_PARAM_REQ_SUPPORTED(features_ble.as_array); + assert(controller_param.readable); + assert(controller_param.ble_supported); + return HCI_LE_CONN_PARAM_REQ_SUPPORTED(controller_param.features_ble.as_array); } static uint16_t get_acl_data_size_classic(void) { - assert(readable); - return acl_data_size_classic; + assert(controller_param.readable); + return controller_param.acl_data_size_classic; } static uint16_t get_acl_data_size_ble(void) { - assert(readable); - assert(ble_supported); - return acl_data_size_ble; + assert(controller_param.readable); + assert(controller_param.ble_supported); + return controller_param.acl_data_size_ble; } static uint16_t get_acl_packet_size_classic(void) { - assert(readable); - return acl_data_size_classic + HCI_DATA_PREAMBLE_SIZE; + assert(controller_param.readable); + return controller_param.acl_data_size_classic + HCI_DATA_PREAMBLE_SIZE; } static uint16_t get_acl_packet_size_ble(void) { - assert(readable); - return acl_data_size_ble + HCI_DATA_PREAMBLE_SIZE; + assert(controller_param.readable); + return controller_param.acl_data_size_ble + HCI_DATA_PREAMBLE_SIZE; } static uint16_t get_ble_suggested_default_data_length(void) { - assert(readable); - assert(ble_supported); - return ble_suggested_default_data_length; + assert(controller_param.readable); + assert(controller_param.ble_supported); + return controller_param.ble_suggested_default_data_length; } static uint16_t get_ble_suggested_default_data_txtime(void) { - assert(readable); - assert(ble_supported); - return ble_suggested_default_data_txtime; + assert(controller_param.readable); + assert(controller_param.ble_supported); + return controller_param.ble_suggested_default_data_txtime; } static uint16_t get_acl_buffer_count_classic(void) { - assert(readable); - return acl_buffer_count_classic; + assert(controller_param.readable); + return controller_param.acl_buffer_count_classic; } static uint8_t get_acl_buffer_count_ble(void) { - assert(readable); - assert(ble_supported); - return acl_buffer_count_ble; + assert(controller_param.readable); + assert(controller_param.ble_supported); + return controller_param.acl_buffer_count_ble; } static uint8_t get_ble_white_list_size(void) { - assert(readable); - assert(ble_supported); - return ble_white_list_size; + assert(controller_param.readable); + assert(controller_param.ble_supported); + return controller_param.ble_white_list_size; } static uint8_t get_ble_resolving_list_max_size(void) { - assert(readable); - assert(ble_supported); - return ble_resolving_list_max_size; + assert(controller_param.readable); + assert(controller_param.ble_supported); + return controller_param.ble_resolving_list_max_size; } static void set_ble_resolving_list_max_size(int resolving_list_max_size) { - assert(readable); - assert(ble_supported); - ble_resolving_list_max_size = resolving_list_max_size; + assert(controller_param.readable); + assert(controller_param.ble_supported); + controller_param.ble_resolving_list_max_size = resolving_list_max_size; } #if (BTM_SCO_HCI_INCLUDED == TRUE) static uint8_t get_sco_data_size(void) { - assert(readable); - return sco_data_size; + assert(controller_param.readable); + return controller_param.sco_data_size; } static uint8_t get_sco_buffer_count(void) { - assert(readable); - return sco_buffer_count; + assert(controller_param.readable); + return controller_param.sco_buffer_count; } #endif /* (BTM_SCO_HCI_INCLUDED == TRUE) */ @@ -541,10 +549,13 @@ const controller_t *controller_get_interface() static bool loaded = false; if (!loaded) { loaded = true; - - hci = hci_layer_get_interface(); - packet_factory = hci_packet_factory_get_interface(); - packet_parser = hci_packet_parser_get_interface(); +#if BT_BLE_DYNAMIC_ENV_MEMORY == TRUE + controller_param_ptr = (controller_local_param_t *)osi_calloc(sizeof(controller_local_param_t)); + assert(controller_param_ptr); +#endif + controller_param.hci = hci_layer_get_interface(); + controller_param.packet_factory = hci_packet_factory_get_interface(); + controller_param.packet_parser = hci_packet_parser_get_interface(); } return &interface; diff --git a/components/bt/bluedroid/external/sbc/encoder/srce/sbc_analysis.c b/components/bt/bluedroid/external/sbc/encoder/srce/sbc_analysis.c index 12878f3156..a2d6db43c8 100644 --- a/components/bt/bluedroid/external/sbc/encoder/srce/sbc_analysis.c +++ b/components/bt/bluedroid/external/sbc/encoder/srce/sbc_analysis.c @@ -26,6 +26,7 @@ #include #include "sbc_encoder.h" #include "sbc_enc_func_declare.h" +#include "osi/allocator.h" /*#include */ #if (defined(SBC_ENC_INCLUDED) && SBC_ENC_INCLUDED == TRUE) @@ -158,9 +159,16 @@ #if (SBC_USE_ARM_PRAGMA==TRUE) #pragma arm section zidata = "sbc_s32_analysis_section" #endif +#if BT_BLE_DYNAMIC_ENV_MEMORY == FALSE static SINT32 s32DCTY[16] = {0}; static SINT32 s32X[ENC_VX_BUFFER_SIZE / 2]; static SINT16 *s16X = (SINT16 *) s32X; /* s16X must be 32 bits aligned cf SHIFTUP_X8_2*/ +#else +static SINT32 *s32DCTY; +static SINT32 *s32X; +static SINT16 *s16X; /* s16X must be 32 bits aligned cf SHIFTUP_X8_2*/ +#endif //BT_BLE_DYNAMIC_ENV_MEMORY == FALSE + #if (SBC_USE_ARM_PRAGMA==TRUE) #pragma arm section zidata #endif @@ -1076,6 +1084,19 @@ void SbcAnalysisFilter8 (SBC_ENC_PARAMS *pstrEncParams) void SbcAnalysisInit (void) { + static bool loaded = false; + if (!loaded) { + loaded = true; +#if BT_BLE_DYNAMIC_ENV_MEMORY == TRUE + s32X = (SINT32 *)osi_malloc(sizeof(SINT32) * (ENC_VX_BUFFER_SIZE / 2)); + s32DCTY = (SINT32 *)osi_malloc(sizeof(SINT32) * 16); + assert(s32X); + assert(s32DCTY); + memset(s32X, 0, sizeof(SINT16) * ENC_VX_BUFFER_SIZE); + memset(s32DCTY, 0, sizeof(SINT32) * 16); + s16X = (SINT16 *) s32X; +#endif + } memset(s16X, 0, ENC_VX_BUFFER_SIZE * sizeof(SINT16)); ShiftCounter = 0; } diff --git a/components/bt/bluedroid/main/bte_init.c b/components/bt/bluedroid/main/bte_init.c index 38cfc812fb..1d6e994291 100644 --- a/components/bt/bluedroid/main/bte_init.c +++ b/components/bt/bluedroid/main/bte_init.c @@ -116,7 +116,6 @@ #if BTA_JV_INCLUDED==TRUE #include "bta_jv_int.h" -tBTA_JV_CB *bta_jv_cb_ptr = NULL; #endif #if BTA_HL_INCLUDED == TRUE @@ -224,10 +223,14 @@ void BTE_InitStack(void) if ((bta_dm_di_cb_ptr = (tBTA_DM_DI_CB *)osi_malloc(sizeof(tBTA_DM_DI_CB))) == NULL) { return; } + if ((bta_dm_conn_srvcs_ptr = (tBTA_DM_CONNECTED_SRVCS *)osi_malloc(sizeof(tBTA_DM_CONNECTED_SRVCS))) == NULL) { + return; + } memset((void *)bta_sys_cb_ptr, 0, sizeof(tBTA_SYS_CB)); memset((void *)bta_dm_cb_ptr, 0, sizeof(tBTA_DM_CB)); memset((void *)bta_dm_search_cb_ptr, 0, sizeof(tBTA_DM_SEARCH_CB)); memset((void *)bta_dm_di_cb_ptr, 0, sizeof(tBTA_DM_DI_CB)); + memset((void *)bta_dm_conn_srvcs_ptr, 0, sizeof(tBTA_DM_CONNECTED_SRVCS)); //memset((void *)bta_prm_cb_ptr, 0, sizeof(tBTA_PRM_CB)); #if (defined BTA_HF_INCLUDED && BTA_HF_INCLUDED == TRUE) @@ -251,6 +254,12 @@ void BTE_InitStack(void) } memset((void *)bta_sdp_cb_ptr, 0, sizeof(tBTA_SDP_CB)); #endif +#if SDP_INCLUDED == TRUE + if ((g_disc_raw_data_buf = (UINT8 *)osi_malloc(MAX_DISC_RAW_DATA_BUF)) == NULL) { + return; + } + memset((void *)g_disc_raw_data_buf, 0, MAX_DISC_RAW_DATA_BUF); +#endif #if BTA_AR_INCLUDED==TRUE if ((bta_ar_cb_ptr = (tBTA_AR_CB *)osi_malloc(sizeof(tBTA_AR_CB))) == NULL) { return; @@ -262,6 +271,11 @@ void BTE_InitStack(void) return; } memset((void *)bta_av_cb_ptr, 0, sizeof(tBTA_AV_CB)); + + if ((bta_av_sbc_ups_cb_ptr = (tBTA_AV_SBC_UPS_CB *)osi_malloc(sizeof(tBTA_AV_SBC_UPS_CB))) == NULL) { + return; + } + memset((void *)bta_av_sbc_ups_cb_ptr, 0, sizeof(tBTA_AV_SBC_UPS_CB)); #endif #if BTA_HH_INCLUDED==TRUE if ((bta_hh_cb_ptr = (tBTA_HH_CB *)osi_malloc(sizeof(tBTA_HH_CB))) == NULL) { @@ -322,11 +336,17 @@ void BTE_DeinitStack(void) #if BTA_AV_INCLUDED==TRUE osi_free(bta_av_cb_ptr); bta_av_cb_ptr = NULL; + osi_free(bta_av_sbc_ups_cb_ptr); + bta_av_sbc_ups_cb_ptr = NULL; #endif #if BTA_AR_INCLUDED==TRUE osi_free(bta_ar_cb_ptr); bta_ar_cb_ptr = NULL; #endif +#if SDP_INCLUDED == TRUE + osi_free(g_disc_raw_data_buf); + g_disc_raw_data_buf = NULL; +#endif #if BTA_SDP_INCLUDED == TRUE osi_free(bta_sdp_cb_ptr); bta_sdp_cb_ptr = NULL; @@ -339,6 +359,8 @@ void BTE_DeinitStack(void) osi_free(bta_hf_client_cb_ptr); bta_hf_client_cb_ptr = NULL; #endif + osi_free(bta_dm_conn_srvcs_ptr); + bta_dm_conn_srvcs_ptr = NULL; osi_free(bta_dm_di_cb_ptr); bta_dm_di_cb_ptr = NULL; osi_free(bta_dm_search_cb_ptr); @@ -349,6 +371,10 @@ void BTE_DeinitStack(void) bta_sys_cb_ptr = NULL; #endif // BTA_INCLUDED == TRUE +#if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE) + GAP_Deinit(); +#endif + #if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE && AVCT_DYNAMIC_MEMORY == TRUE) osi_free(avct_cb_ptr); avct_cb_ptr = NULL; @@ -366,4 +392,8 @@ void BTE_DeinitStack(void) #if (defined(A2D_INCLUDED) && A2D_INCLUDED == TRUE) A2D_Deinit(); #endif + +#if (defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE) + RFCOMM_Deinit(); +#endif } diff --git a/components/bt/bluedroid/osi/alarm.c b/components/bt/bluedroid/osi/alarm.c index 5307010590..21241b96da 100644 --- a/components/bt/bluedroid/osi/alarm.c +++ b/components/bt/bluedroid/osi/alarm.c @@ -44,7 +44,11 @@ enum { static osi_mutex_t alarm_mutex; static int alarm_state; +#if BT_BLE_DYNAMIC_ENV_MEMORY == FALSE static struct alarm_t alarm_cbs[ALARM_CBS_NUM]; +#else +static struct alarm_t *alarm_cbs; +#endif static osi_alarm_err_t alarm_free(osi_alarm_t *alarm); static osi_alarm_err_t alarm_set(osi_alarm_t *alarm, period_ms_t timeout, bool is_periodic); @@ -78,7 +82,14 @@ void osi_alarm_init(void) OSI_TRACE_WARNING("%s, invalid state %d\n", __func__, alarm_state); goto end; } - memset(alarm_cbs, 0x00, sizeof(alarm_cbs)); +#if BT_BLE_DYNAMIC_ENV_MEMORY == TRUE + if ((alarm_cbs = (osi_alarm_t *)osi_malloc(sizeof(osi_alarm_t) * ALARM_CBS_NUM)) == NULL) { + OSI_TRACE_ERROR("%s, malloc failed\n", __func__); + goto end; + } +#endif + + memset(alarm_cbs, 0x00, sizeof(osi_alarm_t) * ALARM_CBS_NUM); alarm_state = ALARM_STATE_OPEN; end: @@ -100,6 +111,12 @@ void osi_alarm_deinit(void) alarm_free(&alarm_cbs[i]); } } + +#if BT_BLE_DYNAMIC_ENV_MEMORY == TRUE + osi_free(alarm_cbs); + alarm_cbs = NULL; +#endif + alarm_state = ALARM_STATE_IDLE; end: diff --git a/components/bt/bluedroid/stack/btm/btm_ble_adv_filter.c b/components/bt/bluedroid/stack/btm/btm_ble_adv_filter.c index 578e2c5dbc..438485359f 100644 --- a/components/bt/bluedroid/stack/btm/btm_ble_adv_filter.c +++ b/components/bt/bluedroid/stack/btm/btm_ble_adv_filter.c @@ -48,8 +48,16 @@ #define BTM_BLE_PF_BIT_TO_MASK(x) (UINT16)(1 << (x)) +#if BTM_DYNAMIC_MEMORY == FALSE tBTM_BLE_ADV_FILTER_CB btm_ble_adv_filt_cb; -tBTM_BLE_VSC_CB cmn_ble_vsc_cb; +tBTM_BLE_VSC_CB cmn_ble_adv_vsc_cb; +#else +tBTM_BLE_ADV_FILTER_CB *btm_ble_adv_filt_cb_ptr; +tBTM_BLE_VSC_CB *cmn_ble_adv_vsc_cb_ptr; +#define btm_ble_adv_filt_cb (*btm_ble_adv_filt_cb_ptr) +#define cmn_ble_adv_vsc_cb (*cmn_ble_adv_vsc_cb_ptr) +#endif + static const BD_ADDR na_bda = {0}; static UINT8 btm_ble_cs_update_pf_counter(tBTM_BLE_SCAN_COND_OP action, @@ -87,13 +95,13 @@ tBTM_STATUS btm_ble_obtain_vsc_details() tBTM_STATUS st = BTM_SUCCESS; #if BLE_VND_INCLUDED == TRUE - BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); - if (0 == cmn_ble_vsc_cb.max_filter) { + BTM_BleGetVendorCapabilities(&cmn_ble_adv_vsc_cb); + if (0 == cmn_ble_adv_vsc_cb.max_filter) { st = BTM_MODE_UNSUPPORTED; return st; } #else - cmn_ble_vsc_cb.max_filter = BTM_BLE_MAX_FILTER_COUNTER; + cmn_ble_adv_vsc_cb.max_filter = BTM_BLE_MAX_FILTER_COUNTER; #endif return st; } @@ -367,7 +375,7 @@ tBTM_BLE_PF_COUNT *btm_ble_find_addr_filter_counter(tBLE_BD_ADDR *p_le_bda) return &btm_ble_adv_filt_cb.p_addr_filter_count[0]; } - for (i = 0; i < cmn_ble_vsc_cb.max_filter; i ++, p_addr_filter ++) { + for (i = 0; i < cmn_ble_adv_vsc_cb.max_filter; i ++, p_addr_filter ++) { if (p_addr_filter->in_use && memcmp(p_le_bda->bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0) { return p_addr_filter; @@ -390,7 +398,7 @@ tBTM_BLE_PF_COUNT *btm_ble_alloc_addr_filter_counter(BD_ADDR bd_addr) UINT8 i; tBTM_BLE_PF_COUNT *p_addr_filter = &btm_ble_adv_filt_cb.p_addr_filter_count[1]; - for (i = 0; i < cmn_ble_vsc_cb.max_filter; i ++, p_addr_filter ++) { + for (i = 0; i < cmn_ble_adv_vsc_cb.max_filter; i ++, p_addr_filter ++) { if (memcmp(na_bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0) { memcpy(p_addr_filter->bd_addr, bd_addr, BD_ADDR_LEN); p_addr_filter->in_use = TRUE; @@ -418,7 +426,7 @@ BOOLEAN btm_ble_dealloc_addr_filter_counter(tBLE_BD_ADDR *p_bd_addr, UINT8 filte memset(&btm_ble_adv_filt_cb.p_addr_filter_count[0], 0, sizeof(tBTM_BLE_PF_COUNT)); } - for (i = 0; i < cmn_ble_vsc_cb.max_filter; i ++, p_addr_filter ++) { + for (i = 0; i < cmn_ble_adv_vsc_cb.max_filter; i ++, p_addr_filter ++) { if ((p_addr_filter->in_use) && (NULL == p_bd_addr || (NULL != p_bd_addr && memcmp(p_bd_addr->bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0))) { @@ -682,7 +690,7 @@ UINT8 btm_ble_cs_update_pf_counter(tBTM_BLE_SCAN_COND_OP action, } BTM_TRACE_DEBUG("counter = %d, maxfilt = %d, num_avbl=%d", - p_counter[cond_type], cmn_ble_vsc_cb.max_filter, num_available); + p_counter[cond_type], cmn_ble_adv_vsc_cb.max_filter, num_available); return p_counter[cond_type]; } } else { @@ -1052,12 +1060,12 @@ tBTM_STATUS BTM_BleAdvFilterParamSetup(int action, tBTM_BLE_PF_FILT_INDEX filt_i /* set onlost timeout */ UINT16_TO_STREAM(p, p_filt_params->lost_timeout); /* set num_of_track_entries for firmware greater than L-release version */ - if (cmn_ble_vsc_cb.version_supported > BTM_VSC_CHIP_CAPABILITY_L_VERSION) { + if (cmn_ble_adv_vsc_cb.version_supported > BTM_VSC_CHIP_CAPABILITY_L_VERSION) { UINT16_TO_STREAM(p, p_filt_params->num_of_tracking_entries); } } - if (cmn_ble_vsc_cb.version_supported == BTM_VSC_CHIP_CAPABILITY_L_VERSION) { + if (cmn_ble_adv_vsc_cb.version_supported == BTM_VSC_CHIP_CAPABILITY_L_VERSION) { len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_ADV_FILT_FEAT_SELN_LEN; } else { len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_ADV_FILT_FEAT_SELN_LEN + @@ -1248,14 +1256,24 @@ tBTM_STATUS BTM_BleCfgFilterCondition(tBTM_BLE_SCAN_COND_OP action, *******************************************************************************/ void btm_ble_adv_filter_init(void) { - memset(&btm_ble_adv_filt_cb, 0, sizeof(tBTM_BLE_MULTI_ADV_CB)); +#if BTM_DYNAMIC_MEMORY == TRUE + btm_ble_adv_filt_cb_ptr = (tBTM_BLE_ADV_FILTER_CB *)osi_malloc(sizeof(tBTM_BLE_ADV_FILTER_CB)); + cmn_ble_adv_vsc_cb_ptr = (tBTM_BLE_VSC_CB *)osi_malloc(sizeof(tBTM_BLE_VSC_CB)); + if (btm_ble_adv_filt_cb_ptr == NULL || cmn_ble_adv_vsc_cb_ptr == NULL) { + BTM_TRACE_ERROR("%s malloc failed", __func__); + return; + } + memset((void *)btm_ble_adv_filt_cb_ptr, 0, sizeof(tBTM_BLE_ADV_FILTER_CB)); + memset((void *)cmn_ble_adv_vsc_cb_ptr, 0, sizeof(tBTM_BLE_VSC_CB)); +#endif + memset(&btm_ble_adv_filt_cb, 0, sizeof(tBTM_BLE_ADV_FILTER_CB)); if (BTM_SUCCESS != btm_ble_obtain_vsc_details()) { return; } - if (cmn_ble_vsc_cb.max_filter > 0) { + if (cmn_ble_adv_vsc_cb.max_filter > 0) { btm_ble_adv_filt_cb.p_addr_filter_count = - (tBTM_BLE_PF_COUNT *) osi_malloc( sizeof(tBTM_BLE_PF_COUNT) * cmn_ble_vsc_cb.max_filter); + (tBTM_BLE_PF_COUNT *) osi_malloc( sizeof(tBTM_BLE_PF_COUNT) * cmn_ble_adv_vsc_cb.max_filter); } } @@ -1276,6 +1294,13 @@ void btm_ble_adv_filter_cleanup(void) osi_free(btm_ble_adv_filt_cb.p_addr_filter_count); btm_ble_adv_filt_cb.p_addr_filter_count = NULL; } + +#if BTM_DYNAMIC_MEMORY == TRUE + osi_free(btm_ble_adv_filt_cb_ptr); + btm_ble_adv_filt_cb_ptr = NULL; + osi_free(cmn_ble_adv_vsc_cb_ptr); + cmn_ble_adv_vsc_cb_ptr = NULL; +#endif } #endif diff --git a/components/bt/bluedroid/stack/btm/btm_ble_batchscan.c b/components/bt/bluedroid/stack/btm/btm_ble_batchscan.c index d9af18d5e1..5b0fcd8ff0 100644 --- a/components/bt/bluedroid/stack/btm/btm_ble_batchscan.c +++ b/components/bt/bluedroid/stack/btm/btm_ble_batchscan.c @@ -30,9 +30,15 @@ #if (BLE_INCLUDED == TRUE) -tBTM_BLE_BATCH_SCAN_CB ble_batchscan_cb; -tBTM_BLE_ADV_TRACK_CB ble_advtrack_cb; - +#if BTM_DYNAMIC_MEMORY == FALSE +tBTM_BLE_BATCH_SCAN_CB ble_batchscan_cb; +tBTM_BLE_ADV_TRACK_CB ble_advtrack_cb; +#else +tBTM_BLE_BATCH_SCAN_CB *ble_batchscan_cb_ptr; +tBTM_BLE_ADV_TRACK_CB *ble_advtrack_cb_ptr; +#define ble_batchscan_cb (*ble_batchscan_cb_ptr) +#define ble_advtrack_cb (*ble_advtrack_cb_ptr) +#endif /* length of each batch scan command */ #define BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN 4 @@ -896,6 +902,14 @@ tBTM_STATUS BTM_BleTrackAdvertiser(tBTM_BLE_TRACK_ADV_CBACK *p_track_cback, *******************************************************************************/ void btm_ble_batchscan_init(void) { +#if BTM_DYNAMIC_MEMORY == TRUE + ble_batchscan_cb_ptr = (tBTM_BLE_BATCH_SCAN_CB *)osi_malloc(sizeof(tBTM_BLE_BATCH_SCAN_CB)); + ble_advtrack_cb_ptr = (tBTM_BLE_ADV_TRACK_CB *)osi_malloc(sizeof(tBTM_BLE_ADV_TRACK_CB)); + if (ble_batchscan_cb_ptr == NULL || ble_advtrack_cb_ptr == NULL) { + BTM_TRACE_ERROR("%s malloc failed", __func__); + return; + } +#endif BTM_TRACE_EVENT (" btm_ble_batchscan_init"); memset(&ble_batchscan_cb, 0, sizeof(tBTM_BLE_BATCH_SCAN_CB)); memset(&ble_advtrack_cb, 0, sizeof(tBTM_BLE_ADV_TRACK_CB)); @@ -927,6 +941,13 @@ void btm_ble_batchscan_cleanup(void) memset(&ble_batchscan_cb, 0, sizeof(tBTM_BLE_BATCH_SCAN_CB)); memset(&ble_advtrack_cb, 0, sizeof(tBTM_BLE_ADV_TRACK_CB)); + +#if BTM_DYNAMIC_MEMORY == TRUE + osi_free(ble_batchscan_cb_ptr); + osi_free(ble_advtrack_cb_ptr); + ble_batchscan_cb_ptr = NULL; + ble_advtrack_cb_ptr = NULL; +#endif } #endif diff --git a/components/bt/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/bluedroid/stack/btm/btm_ble_gap.c index cbf349ded1..e7a4ba955b 100644 --- a/components/bt/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/bluedroid/stack/btm/btm_ble_gap.c @@ -57,7 +57,12 @@ #define MIN_ADV_LENGTH 2 #define BTM_VSC_CHIP_CAPABILITY_RSP_LEN_L_RELEASE 9 -static tBTM_BLE_VSC_CB cmn_ble_vsc_cb; +#if BTM_DYNAMIC_MEMORY == FALSE +static tBTM_BLE_VSC_CB cmn_ble_gap_vsc_cb; +#else +static tBTM_BLE_VSC_CB *cmn_ble_gap_vsc_cb_ptr; +#define cmn_ble_gap_vsc_cb (*cmn_ble_gap_vsc_cb_ptr) +#endif #if BLE_VND_INCLUDED == TRUE static tBTM_BLE_CTRL_FEATURES_CBACK *p_ctrl_le_feature_rd_cmpl_cback = NULL; @@ -447,7 +452,7 @@ tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT32 duration, btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN); #endif - if (cmn_ble_vsc_cb.extended_scan_support == 0) { + if (cmn_ble_gap_vsc_cb.extended_scan_support == 0) { btsnd_hcic_ble_set_scan_params(p_inq->scan_type, (UINT16)scan_interval, (UINT16)scan_window, btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type, @@ -4292,10 +4297,18 @@ BOOLEAN btm_ble_update_mode_operation(UINT8 link_role, BD_ADDR bd_addr, UINT8 st *******************************************************************************/ void btm_ble_init (void) { - tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; - BTM_TRACE_DEBUG("%s", __func__); +#if BTM_DYNAMIC_MEMORY == TRUE + cmn_ble_gap_vsc_cb_ptr = (tBTM_BLE_VSC_CB *)osi_malloc(sizeof(tBTM_BLE_VSC_CB)); + if (cmn_ble_gap_vsc_cb_ptr == NULL) { + BTM_TRACE_ERROR("%s malloc failed", __func__); + return; + } +#endif + + tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; + btu_free_timer(&p_cb->obs_timer_ent); btu_free_timer(&p_cb->scan_timer_ent); btu_free_timer(&p_cb->inq_var.fast_adv_timer); @@ -4340,6 +4353,11 @@ void btm_ble_free (void) BTM_TRACE_DEBUG("%s", __func__); fixed_queue_free(p_cb->conn_pending_q, osi_free_func); + +#if BTM_DYNAMIC_MEMORY == TRUE + osi_free(cmn_ble_gap_vsc_cb_ptr); + cmn_ble_gap_vsc_cb_ptr = NULL; +#endif } /******************************************************************************* diff --git a/components/bt/bluedroid/stack/btm/btm_ble_multi_adv.c b/components/bt/bluedroid/stack/btm/btm_ble_multi_adv.c index 5457324130..a3ad604437 100644 --- a/components/bt/bluedroid/stack/btm/btm_ble_multi_adv.c +++ b/components/bt/bluedroid/stack/btm/btm_ble_multi_adv.c @@ -45,8 +45,15 @@ /************************************************************************************ ** Static variables ************************************************************************************/ -tBTM_BLE_MULTI_ADV_CB btm_multi_adv_cb; -tBTM_BLE_MULTI_ADV_INST_IDX_Q btm_multi_adv_idx_q; +#if BTM_DYNAMIC_MEMORY == FALSE +tBTM_BLE_MULTI_ADV_CB btm_multi_adv_cb; +tBTM_BLE_MULTI_ADV_INST_IDX_Q btm_multi_adv_idx_q; +#else +tBTM_BLE_MULTI_ADV_CB *btm_multi_adv_cb_ptr; +tBTM_BLE_MULTI_ADV_INST_IDX_Q *btm_multi_adv_idx_q_ptr; +#define btm_multi_adv_cb (*btm_multi_adv_cb_ptr) +#define btm_multi_adv_idx_q (*btm_multi_adv_idx_q_ptr) +#endif /************************************************************************************ ** Externs @@ -764,6 +771,15 @@ void btm_ble_multi_adv_vse_cback(UINT8 len, UINT8 *p) *******************************************************************************/ void btm_ble_multi_adv_init() { +#if BTM_DYNAMIC_MEMORY == TRUE + btm_multi_adv_cb_ptr = (tBTM_BLE_MULTI_ADV_CB *)osi_malloc(sizeof(tBTM_BLE_MULTI_ADV_CB)); + btm_multi_adv_idx_q_ptr = (tBTM_BLE_MULTI_ADV_INST_IDX_Q *)osi_malloc(sizeof(tBTM_BLE_MULTI_ADV_INST_IDX_Q)); + if (btm_multi_adv_cb_ptr == NULL || btm_multi_adv_idx_q_ptr == NULL) { + BTM_TRACE_ERROR("%s malloc failed", __func__); + return; + } +#endif + UINT8 i = 0; memset(&btm_multi_adv_cb, 0, sizeof(tBTM_BLE_MULTI_ADV_CB)); memset (&btm_multi_adv_idx_q, 0, sizeof (tBTM_BLE_MULTI_ADV_INST_IDX_Q)); @@ -823,6 +839,12 @@ void btm_ble_multi_adv_cleanup(void) btm_multi_adv_cb.op_q.p_inst_id = NULL; } +#if BTM_DYNAMIC_MEMORY == TRUE + osi_free(btm_multi_adv_cb_ptr); + osi_free(btm_multi_adv_idx_q_ptr); + btm_multi_adv_cb_ptr = NULL; + btm_multi_adv_idx_q_ptr = NULL; +#endif } /******************************************************************************* diff --git a/components/bt/bluedroid/stack/btm/btm_ble_privacy.c b/components/bt/bluedroid/stack/btm/btm_ble_privacy.c index 71f06eb82f..0ec69d953e 100644 --- a/components/bt/bluedroid/stack/btm/btm_ble_privacy.c +++ b/components/bt/bluedroid/stack/btm/btm_ble_privacy.c @@ -882,6 +882,7 @@ void btm_ble_enable_resolving_list(UINT8 rl_mask) } } +#if 0 //Unused /******************************************************************************* ** ** Function btm_ble_resolving_list_empty @@ -896,6 +897,7 @@ BOOLEAN btm_ble_resolving_list_empty(void) return (controller_get_interface()->get_ble_resolving_list_max_size() == btm_cb.ble_ctr_cb.resolving_list_avail_size); } +#endif /******************************************************************************* ** diff --git a/components/bt/bluedroid/stack/gap/gap_api.c b/components/bt/bluedroid/stack/gap/gap_api.c index 305eadee0a..69b5d9629b 100644 --- a/components/bt/bluedroid/stack/gap/gap_api.c +++ b/components/bt/bluedroid/stack/gap/gap_api.c @@ -21,8 +21,13 @@ #include "common/bt_target.h" //#include "bt_utils.h" #include "gap_int.h" +#include "osi/allocator.h" +#if GAP_DYNAMIC_MEMORY == FALSE tGAP_CB gap_cb; +#else +tGAP_CB *gap_cb_ptr; +#endif /******************************************************************************* ** @@ -57,6 +62,10 @@ UINT8 GAP_SetTraceLevel (UINT8 new_level) *******************************************************************************/ void GAP_Init(void) { +#if GAP_DYNAMIC_MEMORY == TRUE + gap_cb_ptr = (tGAP_CB *)osi_malloc(sizeof(tGAP_CB)); +#endif + memset (&gap_cb, 0, sizeof (tGAP_CB)); #if defined(GAP_INITIAL_TRACE_LEVEL) @@ -74,3 +83,20 @@ void GAP_Init(void) #endif } +/******************************************************************************* +** +** Function GAP_Deinit +** +** Description This function is called to deinitialize the control block +** for this layer. +** +** Returns void +** +*******************************************************************************/ +void GAP_Deinit(void) +{ +#if GAP_DYNAMIC_MEMORY == TRUE + osi_free(gap_cb_ptr); + gap_cb_ptr = NULL; +#endif +} \ No newline at end of file diff --git a/components/bt/bluedroid/stack/gap/gap_ble.c b/components/bt/bluedroid/stack/gap/gap_ble.c index bb5db8c1b1..08f7c195ce 100644 --- a/components/bt/bluedroid/stack/gap/gap_ble.c +++ b/components/bt/bluedroid/stack/gap/gap_ble.c @@ -49,7 +49,7 @@ static void gap_ble_c_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn tGATT_DISCONN_REASON reason, tGATT_TRANSPORT transport); static void gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data); -static tGATT_CBACK gap_cback = { +static const tGATT_CBACK gap_cback = { gap_ble_c_connect_cback, gap_ble_c_cmpl_cback, NULL, diff --git a/components/bt/bluedroid/stack/gap/include/gap_int.h b/components/bt/bluedroid/stack/gap/include/gap_int.h index e278141184..8a3ae0e2f0 100644 --- a/components/bt/bluedroid/stack/gap/include/gap_int.h +++ b/components/bt/bluedroid/stack/gap/include/gap_int.h @@ -142,8 +142,13 @@ typedef struct { #endif } tGAP_CB; - +#if GAP_DYNAMIC_MEMORY == FALSE extern tGAP_CB gap_cb; +#else +extern tGAP_CB *gap_cb_ptr; +#define gap_cb (*gap_cb_ptr) +#endif + #if (GAP_CONN_INCLUDED == TRUE) extern void gap_conn_init(void); #endif diff --git a/components/bt/bluedroid/stack/gatt/gatt_api.c b/components/bt/bluedroid/stack/gatt/gatt_api.c index 7f360d52db..d093d2b9d4 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_api.c +++ b/components/bt/bluedroid/stack/gatt/gatt_api.c @@ -110,7 +110,7 @@ BOOLEAN GATTS_AddHandleRange(tGATTS_HNDL_RANGE *p_hndl_range) ** Returns TRUE if registered OK, else FALSE ** *******************************************************************************/ -BOOLEAN GATTS_NVRegister (tGATT_APPL_INFO *p_cb_info) +BOOLEAN GATTS_NVRegister (const tGATT_APPL_INFO *p_cb_info) { BOOLEAN status = FALSE; if (p_cb_info) { @@ -1192,7 +1192,7 @@ void GATT_SetIdleTimeout (BD_ADDR bd_addr, UINT16 idle_tout, tBT_TRANSPORT trans ** Returns 0 for error, otherwise the index of the client registered with GATT ** *******************************************************************************/ -tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, tGATT_CBACK *p_cb_info) +tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, const tGATT_CBACK *p_cb_info) { tGATT_REG *p_reg; UINT8 i_gatt_if = 0; diff --git a/components/bt/bluedroid/stack/gatt/gatt_attr.c b/components/bt/bluedroid/stack/gatt/gatt_attr.c index 5036241317..3a67a8bf25 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_attr.c +++ b/components/bt/bluedroid/stack/gatt/gatt_attr.c @@ -52,7 +52,7 @@ static void gatt_cl_op_cmpl_cback(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS static void gatt_cl_start_config_ccc(tGATT_PROFILE_CLCB *p_clcb); -static tGATT_CBACK gatt_profile_cback = { +static const tGATT_CBACK gatt_profile_cback = { gatt_connect_cback, gatt_cl_op_cmpl_cback, gatt_disc_res_cback, @@ -308,7 +308,7 @@ static void gatt_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, p_clcb->connected = TRUE; p_clcb->conn_id = conn_id; } - + if (!p_clcb->connected) { /* wait for connection */ @@ -348,7 +348,7 @@ void gatt_profile_db_init (void) service_handle = GATTS_CreateService (gatt_cb.gatt_if , &uuid, 0, GATTP_MAX_ATTR_NUM, TRUE); GATT_TRACE_DEBUG ("GATTS_CreateService: handle of service handle%x", service_handle); - + /* add Service Changed characteristic */ uuid.uu.uuid16 = gatt_cb.gattp_attr.uuid = GATT_UUID_GATT_SRV_CHGD; diff --git a/components/bt/bluedroid/stack/gatt/gatt_cl.c b/components/bt/bluedroid/stack/gatt/gatt_cl.c index daa911e8c2..4ffd7ca5a0 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_cl.c +++ b/components/bt/bluedroid/stack/gatt/gatt_cl.c @@ -47,7 +47,7 @@ *********************************************************************************/ void gatt_send_prepare_write(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb); -UINT8 disc_type_to_att_opcode[GATT_DISC_MAX] = { +static const UINT8 disc_type_to_att_opcode[GATT_DISC_MAX] = { 0, GATT_REQ_READ_BY_GRP_TYPE, /* GATT_DISC_SRVC_ALL = 1, */ GATT_REQ_FIND_TYPE_VALUE, /* GATT_DISC_SRVC_BY_UUID, */ @@ -56,7 +56,7 @@ UINT8 disc_type_to_att_opcode[GATT_DISC_MAX] = { GATT_REQ_FIND_INFO /* GATT_DISC_CHAR_DSCPT, */ }; -UINT16 disc_type_to_uuid[GATT_DISC_MAX] = { +static const UINT16 disc_type_to_uuid[GATT_DISC_MAX] = { 0, /* reserved */ GATT_UUID_PRI_SERVICE, /* DISC_SRVC_ALL */ GATT_UUID_PRI_SERVICE, /* for DISC_SERVC_BY_UUID */ diff --git a/components/bt/bluedroid/stack/include/stack/dyn_mem.h b/components/bt/bluedroid/stack/include/stack/dyn_mem.h index 2b2db28453..1241c3a85a 100644 --- a/components/bt/bluedroid/stack/include/stack/dyn_mem.h +++ b/components/bt/bluedroid/stack/include/stack/dyn_mem.h @@ -18,15 +18,19 @@ #ifndef DYN_MEM_H #define DYN_MEM_H -#include "common/bt_target.h" -#if BT_BLE_DYNAMIC_ENV_MEMORY +#include "common/bt_user_config.h" + +#if UC_BT_BLE_DYNAMIC_ENV_MEMORY +#define BT_BLE_DYNAMIC_ENV_MEMORY TRUE #define BTU_DYNAMIC_MEMORY TRUE #define BTM_DYNAMIC_MEMORY TRUE #define L2C_DYNAMIC_MEMORY TRUE #define GATT_DYNAMIC_MEMORY TRUE #define SMP_DYNAMIC_MEMORY TRUE #define BTA_DYNAMIC_MEMORY TRUE +#define BTC_DYNAMIC_MENDRY TRUE #define SDP_DYNAMIC_MEMORY TRUE +#define GAP_DYNAMIC_MEMORY TRUE #define RFC_DYNAMIC_MEMORY TRUE #define TCS_DYNAMIC_MEMORY TRUE #define BNEP_DYNAMIC_MEMORY TRUE @@ -51,11 +55,18 @@ #define SLIP_DYNAMIC_MEMORY TRUE #define LLCP_DYNAMIC_MEMORY TRUE #define BTC_SBC_DEC_DYNAMIC_MEMORY TRUE -#define BTC_SBC_ENC_DYNAMIC_MEMORY TRUE - -#else /* #if BT_BLE_DYNAMIC_ENV_MEMORY */ +#else /* #if UC_BT_BLE_DYNAMIC_ENV_MEMORY */ +#define BT_BLE_DYNAMIC_ENV_MEMORY FALSE +#define BTU_DYNAMIC_MEMORY FALSE +#define BTM_DYNAMIC_MEMORY FALSE +#define L2C_DYNAMIC_MEMORY FALSE +#define GATT_DYNAMIC_MEMORY FALSE +#define SMP_DYNAMIC_MEMORY FALSE +#define BTA_DYNAMIC_MEMORY FALSE +#define BTC_DYNAMIC_MENDRY FALSE #define SDP_DYNAMIC_MEMORY FALSE +#define GAP_DYNAMIC_MEMORY FALSE #define RFC_DYNAMIC_MEMORY FALSE #define TCS_DYNAMIC_MEMORY FALSE #define BNEP_DYNAMIC_MEMORY FALSE @@ -80,9 +91,13 @@ #define SLIP_DYNAMIC_MEMORY FALSE #define LLCP_DYNAMIC_MEMORY FALSE #define BTC_SBC_DEC_DYNAMIC_MEMORY FALSE -#define BTC_SBC_ENC_DYNAMIC_MEMORY FALSE -#endif /* #if BT_BLE_DYNAMIC_ENV_MEMORY */ +#endif /* #if UC_BT_BLE_DYNAMIC_ENV_MEMORY */ + +#ifndef BT_BLE_DYNAMIC_ENV_MEMORY +#define BT_BLE_DYNAMIC_ENV_MEMORY FALSE +#endif + /**************************************************************************** ** Define memory usage for each CORE component (if not defined in bdroid_buildcfg.h) ** The default for each component is to use static memory allocations. @@ -99,6 +114,10 @@ #define SDP_DYNAMIC_MEMORY FALSE #endif +#ifndef GAP_DYNAMIC_MEMORY +#define GAP_DYNAMIC_MEMORY FALSE +#endif + #ifndef L2C_DYNAMIC_MEMORY #define L2C_DYNAMIC_MEMORY FALSE #endif @@ -208,12 +227,15 @@ #endif /**************************************************************************** -** Define memory usage for BTA (if not defined in bdroid_buildcfg.h) +** Define memory usage for BTA and BTC (if not defined in bdroid_buildcfg.h) ** The default for each component is to use static memory allocations. */ #ifndef BTA_DYNAMIC_MEMORY #define BTA_DYNAMIC_MEMORY FALSE #endif -#endif /* #ifdef DYN_MEM_H */ +#ifndef BTC_DYNAMIC_MENDRY +#define BTC_DYNAMIC_MENDRY FALSE +#endif +#endif /* #ifdef DYN_MEM_H */ diff --git a/components/bt/bluedroid/stack/include/stack/gap_api.h b/components/bt/bluedroid/stack/include/stack/gap_api.h index 5d8d87645d..03af2956ce 100644 --- a/components/bt/bluedroid/stack/include/stack/gap_api.h +++ b/components/bt/bluedroid/stack/include/stack/gap_api.h @@ -325,6 +325,18 @@ extern UINT8 GAP_SetTraceLevel (UINT8 new_level); *******************************************************************************/ extern void GAP_Init(void); +/******************************************************************************* +** +** Function GAP_Deinit +** +** Description This function is called to deinitialize the control block +** for this layer. +** +** Returns void +** +*******************************************************************************/ +extern void GAP_Deinit(void); + #if (BLE_INCLUDED == TRUE) /******************************************************************************* ** diff --git a/components/bt/bluedroid/stack/include/stack/gatt_api.h b/components/bt/bluedroid/stack/include/stack/gatt_api.h index b2cecb0578..c250f9a3c1 100644 --- a/components/bt/bluedroid/stack/include/stack/gatt_api.h +++ b/components/bt/bluedroid/stack/include/stack/gatt_api.h @@ -707,7 +707,7 @@ extern BOOLEAN GATTS_AddHandleRange(tGATTS_HNDL_RANGE *p_hndl_range); ** Returns TRUE if registered OK, else FALSE ** *******************************************************************************/ -extern BOOLEAN GATTS_NVRegister (tGATT_APPL_INFO *p_cb_info); +extern BOOLEAN GATTS_NVRegister (const tGATT_APPL_INFO *p_cb_info); /******************************************************************************* @@ -1059,7 +1059,7 @@ extern void GATT_SetIdleTimeout (BD_ADDR bd_addr, UINT16 idle_tout, ** Returns 0 for error, otherwise the index of the client registered with GATT ** *******************************************************************************/ -extern tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, tGATT_CBACK *p_cb_info); +extern tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, const tGATT_CBACK *p_cb_info); /******************************************************************************* ** diff --git a/components/bt/bluedroid/stack/include/stack/port_api.h b/components/bt/bluedroid/stack/include/stack/port_api.h index 10b0378681..8145a177a0 100644 --- a/components/bt/bluedroid/stack/include/stack/port_api.h +++ b/components/bt/bluedroid/stack/include/stack/port_api.h @@ -623,6 +623,17 @@ extern int PORT_Test (UINT16 handle, UINT8 *p_data, UINT16 len); *******************************************************************************/ extern void RFCOMM_Init (void); +/******************************************************************************* +** +** Function RFCOMM_Deinit +** +** Description This function is called to deinitialize the control block +** for this layer. +** +** Returns void +** +*******************************************************************************/ +extern void RFCOMM_Deinit(void); /******************************************************************************* ** diff --git a/components/bt/bluedroid/stack/l2cap/l2c_main.c b/components/bt/bluedroid/stack/l2cap/l2c_main.c index 1035b44c6a..45baeaa3b9 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_main.c +++ b/components/bt/bluedroid/stack/l2cap/l2c_main.c @@ -52,6 +52,7 @@ tL2C_CB l2cb; tL2C_CB *l2c_cb_ptr; #endif +#if 0 //Unused /******************************************************************************* ** ** Function l2c_bcst_msg @@ -104,7 +105,7 @@ void l2c_bcst_msg( BT_HDR *p_buf, UINT16 psm ) bte_main_hci_send(p_buf, BT_EVT_TO_LM_HCI_ACL); } } - +#endif /******************************************************************************* ** diff --git a/components/bt/bluedroid/stack/rfcomm/port_api.c b/components/bt/bluedroid/stack/rfcomm/port_api.c index fd8246c53d..64f09149e6 100644 --- a/components/bt/bluedroid/stack/rfcomm/port_api.c +++ b/components/bt/bluedroid/stack/rfcomm/port_api.c @@ -826,6 +826,8 @@ int PORT_FlowControl (UINT16 handle, BOOLEAN enable) } return (PORT_SUCCESS); } + +#if 0 //Unused /******************************************************************************* ** ** Function PORT_FlowControl_MaxCredit @@ -839,7 +841,6 @@ int PORT_FlowControl (UINT16 handle, BOOLEAN enable) ** enable - enables data flow ** *******************************************************************************/ - int PORT_FlowControl_MaxCredit (UINT16 handle, BOOLEAN enable) { tPORT *p_port; @@ -896,7 +897,7 @@ int PORT_FlowControl_MaxCredit (UINT16 handle, BOOLEAN enable) } return (PORT_SUCCESS); } - +#endif /******************************************************************************* ** @@ -1713,7 +1714,7 @@ int PORT_Test (UINT16 handle, UINT8 *p_data, UINT16 len) *******************************************************************************/ void RFCOMM_Init (void) { -#if (RFC_DYNAMIC_MEMORY) +#if RFC_DYNAMIC_MEMORY == TRUE rfc_cb_ptr = (tRFC_CB *)osi_malloc(sizeof(tRFC_CB)); #endif /* #if (RFC_DYNAMIC_MEMORY) */ memset (&rfc_cb, 0, sizeof (tRFC_CB)); /* Init RFCOMM control block */ @@ -1729,6 +1730,24 @@ void RFCOMM_Init (void) rfcomm_l2cap_if_init (); } +/******************************************************************************* +** +** Function RFCOMM_Deinit +** +** Description This function is called to deinitialize the control block +** for this layer. +** +** Returns void +** +*******************************************************************************/ +void RFCOMM_Deinit(void) +{ +#if RFC_DYNAMIC_MEMORY == TRUE + osi_free(rfc_cb_ptr); + rfc_cb_ptr = NULL; +#endif +} + /******************************************************************************* ** ** Function PORT_SetTraceLevel diff --git a/components/bt/bluedroid/stack/smp/include/p_256_ecc_pp.h b/components/bt/bluedroid/stack/smp/include/p_256_ecc_pp.h index f91d6056b2..172dd24f10 100644 --- a/components/bt/bluedroid/stack/smp/include/p_256_ecc_pp.h +++ b/components/bt/bluedroid/stack/smp/include/p_256_ecc_pp.h @@ -25,6 +25,7 @@ #pragma once #include "p_256_multprecision.h" +#include "common/bt_target.h" typedef unsigned long DWORD; @@ -53,8 +54,16 @@ typedef struct { } elliptic_curve_t; +#if SMP_DYNAMIC_MEMORY == FALSE extern elliptic_curve_t curve; extern elliptic_curve_t curve_p256; +#else +extern elliptic_curve_t *curve_ptr; +extern elliptic_curve_t *curve_p256_ptr; +#define curve (*curve_ptr) +#define curve_p256 (*curve_p256_ptr) +#endif + void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength); diff --git a/components/bt/bluedroid/stack/smp/include/smp_int.h b/components/bt/bluedroid/stack/smp/include/smp_int.h index a261e14cba..cf3683c07c 100644 --- a/components/bt/bluedroid/stack/smp/include/smp_int.h +++ b/components/bt/bluedroid/stack/smp/include/smp_int.h @@ -479,7 +479,7 @@ extern void smp_proc_pairing_cmpl(tSMP_CB *p_cb); extern void smp_convert_string_to_tk(BT_OCTET16 tk, UINT32 passkey); extern void smp_mask_enc_key(UINT8 loc_enc_size, UINT8 *p_data); extern void smp_rsp_timeout(TIMER_LIST_ENT *p_tle); -extern void smp_xor_128(BT_OCTET16 a, BT_OCTET16 b); +extern void smp_xor_128(BT_OCTET16 a, const BT_OCTET16 b); extern BOOLEAN smp_encrypt_data (UINT8 *key, UINT8 key_len, UINT8 *plain_text, UINT8 pt_len, tSMP_ENC *p_out); diff --git a/components/bt/bluedroid/stack/smp/p_256_ecc_pp.c b/components/bt/bluedroid/stack/smp/p_256_ecc_pp.c index 0f7ab3ec41..aceb0b209a 100644 --- a/components/bt/bluedroid/stack/smp/p_256_ecc_pp.c +++ b/components/bt/bluedroid/stack/smp/p_256_ecc_pp.c @@ -26,9 +26,15 @@ #include #include "p_256_ecc_pp.h" #include "p_256_multprecision.h" +#include "common/bt_target.h" +#if SMP_DYNAMIC_MEMORY == FALSE elliptic_curve_t curve; elliptic_curve_t curve_p256; +#else +elliptic_curve_t *curve_ptr; +elliptic_curve_t *curve_p256_ptr; +#endif static void p_256_init_point(Point *q) { @@ -248,7 +254,7 @@ bool ECC_CheckPointIsInElliCur_P256(Point *p) DWORD x_x_q[KEY_LENGTH_DWORDS_P256] = {0x0}; /* x % q */ DWORD x_q[KEY_LENGTH_DWORDS_P256] = {0x0}; - /* x^2, To prevent overflow, the length of the x square here needs to + /* x^2, To prevent overflow, the length of the x square here needs to be expanded to two times the original one. */ DWORD x_x[2*KEY_LENGTH_DWORDS_P256] = {0x0}; /* y_y_q =(p->y)^2(mod q) */ @@ -259,7 +265,7 @@ bool ECC_CheckPointIsInElliCur_P256(Point *p) y^2 = (x^2 - 3)*x + b (mod q), so we calculate the x^2 - 3 value here */ x_x[0] -= 3; - /* Using math relations. (a*b) % q = ((a%q)*(b%q)) % q ==> + /* Using math relations. (a*b) % q = ((a%q)*(b%q)) % q ==> (x^2 - 3)*x = (((x^2 - 3) % q) * x % q) % q */ multiprecision_fast_mod_P256(x_x_q, x_x); /* x_x = x_x_q * x_q */ diff --git a/components/bt/bluedroid/stack/smp/smp_act.c b/components/bt/bluedroid/stack/smp/smp_act.c index d11506e650..d9f3369500 100644 --- a/components/bt/bluedroid/stack/smp/smp_act.c +++ b/components/bt/bluedroid/stack/smp/smp_act.c @@ -283,6 +283,7 @@ void smp_send_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) smp_send_cmd(SMP_OPCODE_CONFIRM, p_cb); } +#if 0 //Unused /******************************************************************************* ** Function smp_send_init ** Description process pairing initializer to slave device @@ -292,6 +293,7 @@ void smp_send_init(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) SMP_TRACE_DEBUG("%s\n", __func__); smp_send_cmd(SMP_OPCODE_INIT, p_cb); } +#endif /******************************************************************************* ** Function smp_send_rand @@ -675,6 +677,7 @@ void smp_proc_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) p_cb->flags |= SMP_PAIR_FLAGS_CMD_CONFIRM; } +#if 0 //Unused /******************************************************************************* ** Function smp_proc_init ** Description process pairing initializer from peer device @@ -694,6 +697,7 @@ void smp_proc_init(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) /* save the SRand for comparison */ STREAM_TO_ARRAY(p_cb->rrand, p, BT_OCTET16_LEN); } +#endif /******************************************************************************* ** Function smp_proc_rand diff --git a/components/bt/bluedroid/stack/smp/smp_api.c b/components/bt/bluedroid/stack/smp/smp_api.c index 8c3c3d8bc7..37aa2b9111 100644 --- a/components/bt/bluedroid/stack/smp/smp_api.c +++ b/components/bt/bluedroid/stack/smp/smp_api.c @@ -51,8 +51,12 @@ void SMP_Init(void) { #if SMP_DYNAMIC_MEMORY smp_cb_ptr = (tSMP_CB *)osi_malloc(sizeof(tSMP_CB)); + curve_ptr = (elliptic_curve_t *)osi_malloc(sizeof(elliptic_curve_t)); + curve_p256_ptr = (elliptic_curve_t *)osi_malloc(sizeof(elliptic_curve_t)); #endif memset(&smp_cb, 0, sizeof(tSMP_CB)); + memset(&curve, 0, sizeof(elliptic_curve_t)); + memset(&curve_p256, 0, sizeof(elliptic_curve_t)); #if defined(SMP_INITIAL_TRACE_LEVEL) smp_cb.trace_level = SMP_INITIAL_TRACE_LEVEL; @@ -71,6 +75,8 @@ void SMP_Free(void) memset(&smp_cb, 0, sizeof(tSMP_CB)); #if SMP_DYNAMIC_MEMORY FREE_AND_RESET(smp_cb_ptr); + FREE_AND_RESET(curve_ptr); + FREE_AND_RESET(curve_p256_ptr); #endif /* #if SMP_DYNAMIC_MEMORY */ } diff --git a/components/bt/bluedroid/stack/smp/smp_cmac.c b/components/bt/bluedroid/stack/smp/smp_cmac.c index 753c5188f2..0e7bab02c1 100644 --- a/components/bt/bluedroid/stack/smp/smp_cmac.c +++ b/components/bt/bluedroid/stack/smp/smp_cmac.c @@ -42,7 +42,7 @@ typedef struct { tCMAC_CB cmac_cb; /* Rb for AES-128 as block cipher, LSB as [0] */ -BT_OCTET16 const_Rb = { +const BT_OCTET16 const_Rb = { 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/components/bt/bluedroid/stack/smp/smp_keys.c b/components/bt/bluedroid/stack/smp/smp_keys.c index 4c523787c1..c993c7387f 100644 --- a/components/bt/bluedroid/stack/smp/smp_keys.c +++ b/components/bt/bluedroid/stack/smp/smp_keys.c @@ -93,6 +93,7 @@ void smp_debug_print_nbyte_little_endian(UINT8 *p, const UINT8 *key_name, UINT8 #endif } +#if 0 //Unused void smp_debug_print_nbyte_big_endian (UINT8 *p, const UINT8 *key_name, UINT8 len) { #if SMP_DEBUG == TRUE @@ -115,6 +116,7 @@ void smp_debug_print_nbyte_big_endian (UINT8 *p, const UINT8 *key_name, UINT8 le } #endif } +#endif /******************************************************************************* ** diff --git a/components/bt/bluedroid/stack/smp/smp_utils.c b/components/bt/bluedroid/stack/smp/smp_utils.c index 19c2cde99b..6d64f44abc 100644 --- a/components/bt/bluedroid/stack/smp/smp_utils.c +++ b/components/bt/bluedroid/stack/smp/smp_utils.c @@ -866,9 +866,10 @@ void smp_mask_enc_key(UINT8 loc_enc_size, UINT8 *p_data) ** Returns void ** *******************************************************************************/ -void smp_xor_128(BT_OCTET16 a, BT_OCTET16 b) +void smp_xor_128(BT_OCTET16 a, const BT_OCTET16 b) { - UINT8 i, *aa = a, *bb = b; + UINT8 i, *aa = a; + const UINT8 *bb = b; SMP_TRACE_EVENT("smp_xor_128\n"); for (i = 0; i < BT_OCTET16_LEN; i++) { From 5fd4cbb9d288f6d06c4e4279a1d592e8aaa353fd Mon Sep 17 00:00:00 2001 From: baohongde Date: Sat, 29 Sep 2018 16:04:50 +0800 Subject: [PATCH 088/486] component/bt: Add functions for heap memory debug --- components/bt/bluedroid/osi/allocator.c | 21 +++++++++++++++++++ .../bt/bluedroid/osi/include/osi/allocator.h | 8 ++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/components/bt/bluedroid/osi/allocator.c b/components/bt/bluedroid/osi/allocator.c index de8c8da722..624a11c176 100644 --- a/components/bt/bluedroid/osi/allocator.c +++ b/components/bt/bluedroid/osi/allocator.c @@ -38,6 +38,8 @@ typedef struct { static uint32_t mem_dbg_count = 0; static uint32_t mem_dbg_count2 = 0; static osi_mem_dbg_info_t mem_dbg_info[OSI_MEM_DBG_INFO_MAX]; +static uint32_t mem_dbg_total_size = 0; +static uint32_t mem_dbg_max_size = 0; void osi_mem_dbg_init(void) { @@ -51,6 +53,8 @@ void osi_mem_dbg_init(void) } mem_dbg_count = 0; mem_dbg_count2 = 0; + mem_dbg_total_size = 0; + mem_dbg_max_size = 0; } void osi_mem_dbg_record(void *p, int size, const char *func, int line) @@ -76,6 +80,11 @@ void osi_mem_dbg_record(void *p, int size, const char *func, int line) if (i >= OSI_MEM_DBG_INFO_MAX) { OSI_TRACE_ERROR("%s full %s %d !!\n", __func__, func, line); } + + mem_dbg_total_size += size; + if(mem_dbg_max_size < mem_dbg_total_size) { + mem_dbg_max_size = mem_dbg_total_size; + } } void osi_mem_dbg_clean(void *p, const char *func, int line) @@ -89,6 +98,7 @@ void osi_mem_dbg_clean(void *p, const char *func, int line) for (i = 0; i < OSI_MEM_DBG_INFO_MAX; i++) { if (mem_dbg_info[i].p == p) { + mem_dbg_total_size -= mem_dbg_info[i].size; mem_dbg_info[i].p = NULL; mem_dbg_info[i].size = 0; mem_dbg_info[i].func = NULL; @@ -113,6 +123,17 @@ void osi_mem_dbg_show(void) } } OSI_TRACE_ERROR("--> count %d\n", mem_dbg_count); + OSI_TRACE_ERROR("--> size %dB\n--> max size %dB\n", mem_dbg_total_size, mem_dbg_max_size); +} + +uint32_t osi_mem_dbg_get_max_size(void) +{ + return mem_dbg_max_size; +} + +uint32_t osi_mem_dbg_get_total_size(void) +{ + return mem_dbg_total_size; } #endif diff --git a/components/bt/bluedroid/osi/include/osi/allocator.h b/components/bt/bluedroid/osi/include/osi/allocator.h index f30987e058..f5e87a473a 100644 --- a/components/bt/bluedroid/osi/include/osi/allocator.h +++ b/components/bt/bluedroid/osi/include/osi/allocator.h @@ -35,6 +35,8 @@ void osi_mem_dbg_init(void); void osi_mem_dbg_record(void *p, int size, const char *func, int line); void osi_mem_dbg_clean(void *p, const char *func, int line); void osi_mem_dbg_show(void); +uint32_t osi_mem_dbg_get_max_size(void); +uint32_t osi_mem_dbg_get_total_size(void); #if HEAP_ALLOCATION_FROM_SPIRAM_FIRST #define osi_malloc(size) \ @@ -67,9 +69,9 @@ void osi_mem_dbg_show(void); (void *)p; \ }) -#define osi_calloc(size) \ -({ \ - void *p; \ +#define osi_calloc(size) \ +({ \ + void *p; \ p = calloc(1, (size)); \ osi_mem_dbg_record(p, size, __func__, __LINE__); \ (void *)p; \ From 930c304a57b618d9710264cb87560542b53734fc Mon Sep 17 00:00:00 2001 From: baohongde Date: Wed, 10 Oct 2018 16:10:20 +0800 Subject: [PATCH 089/486] components/bt: Combine two hci task into one --- components/bt/bluedroid/hci/hci_hal_h4.c | 18 +++++------------- components/bt/bluedroid/hci/hci_layer.c | 6 +++--- .../bt/bluedroid/hci/include/hci/hci_hal.h | 2 +- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/components/bt/bluedroid/hci/hci_hal_h4.c b/components/bt/bluedroid/hci/hci_hal_h4.c index b31deda79c..5985e32ae2 100644 --- a/components/bt/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/bluedroid/hci/hci_hal_h4.c @@ -27,12 +27,6 @@ #include "esp_bt.h" #include "stack/hcimsgs.h" -#define HCI_H4_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) -#define HCI_H4_TASK_STACK_SIZE (2048 + BT_TASK_EXTRA_STACK_SIZE) -#define HCI_H4_TASK_PRIO (BT_TASK_MAX_PRIORITIES - 4) -#define HCI_H4_TASK_NAME "hciH4T" - - #if (C2H_FLOW_CONTROL_INCLUDED == TRUE) #include "l2c_int.h" #endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE @@ -105,9 +99,11 @@ static void hci_hal_env_deinit(void) hci_hal_env.rx_q = NULL; } -static bool hal_open(const hci_hal_callbacks_t *upper_callbacks) +static bool hal_open(const hci_hal_callbacks_t *upper_callbacks, void *task_thread) { assert(upper_callbacks != NULL); + assert(task_thread != NULL); + callbacks = upper_callbacks; #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) hci_hal_env_init(HCI_HAL_SERIAL_BUFFER_SIZE, BLE_ADV_REPORT_FLOW_CONTROL_NUM + L2CAP_HOST_FC_ACL_BUFS + QUEUE_SIZE_MAX); // adv flow control num + ACL flow control num + hci cmd numeber @@ -115,10 +111,7 @@ static bool hal_open(const hci_hal_callbacks_t *upper_callbacks) hci_hal_env_init(HCI_HAL_SERIAL_BUFFER_SIZE, QUEUE_SIZE_MAX); #endif - hci_h4_thread = osi_thread_create(HCI_H4_TASK_NAME, HCI_H4_TASK_STACK_SIZE, HCI_H4_TASK_PRIO, HCI_H4_TASK_PINNED_TO_CORE, 1); - if (hci_h4_thread == NULL) { - return false; - } + hci_h4_thread = (osi_thread_t *)task_thread; //register vhci host cb if (esp_vhci_host_register_callback(&vhci_host_cb) != ESP_OK) { @@ -132,7 +125,6 @@ static void hal_close() { hci_hal_env_deinit(); - osi_thread_free(hci_h4_thread); hci_h4_thread = NULL; } @@ -180,7 +172,7 @@ static void hci_hal_h4_rx_handler(void *arg) bool hci_hal_h4_task_post(osi_thread_blocking_t blocking) { - return osi_thread_post(hci_h4_thread, hci_hal_h4_rx_handler, NULL, 0, blocking); + return osi_thread_post(hci_h4_thread, hci_hal_h4_rx_handler, NULL, 1, blocking); } #if (C2H_FLOW_CONTROL_INCLUDED == TRUE) diff --git a/components/bt/bluedroid/hci/hci_layer.c b/components/bt/bluedroid/hci/hci_layer.c index 00c6f19e7c..e426528d45 100644 --- a/components/bt/bluedroid/hci/hci_layer.c +++ b/components/bt/bluedroid/hci/hci_layer.c @@ -37,7 +37,7 @@ #define HCI_HOST_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) #define HCI_HOST_TASK_STACK_SIZE (2048 + BT_TASK_EXTRA_STACK_SIZE) #define HCI_HOST_TASK_PRIO (BT_TASK_MAX_PRIORITIES - 3) -#define HCI_HOST_TASK_NAME "hciHostT" +#define HCI_HOST_TASK_NAME "hciT" typedef struct { uint16_t opcode; @@ -105,13 +105,13 @@ int hci_start_up(void) goto error; } - hci_host_thread = osi_thread_create(HCI_HOST_TASK_NAME, HCI_HOST_TASK_STACK_SIZE, HCI_HOST_TASK_PRIO, HCI_HOST_TASK_PINNED_TO_CORE, 1); + hci_host_thread = osi_thread_create(HCI_HOST_TASK_NAME, HCI_HOST_TASK_STACK_SIZE, HCI_HOST_TASK_PRIO, HCI_HOST_TASK_PINNED_TO_CORE, 2); if (hci_host_thread == NULL) { return -2; } packet_fragmenter->init(&packet_fragmenter_callbacks); - hal->open(&hal_callbacks); + hal->open(&hal_callbacks, hci_host_thread); hci_host_startup_flag = true; return 0; diff --git a/components/bt/bluedroid/hci/include/hci/hci_hal.h b/components/bt/bluedroid/hci/include/hci/hci_hal.h index 2928f29ad3..daf3dfb81a 100644 --- a/components/bt/bluedroid/hci/include/hci/hci_hal.h +++ b/components/bt/bluedroid/hci/include/hci/hci_hal.h @@ -51,7 +51,7 @@ typedef struct hci_hal_t { //bool (*init)(const hci_hal_callbacks_t *upper_callbacks); // Connect to the underlying hardware, and let data start flowing. - bool (*open)(const hci_hal_callbacks_t *upper_callbacks); + bool (*open)(const hci_hal_callbacks_t *upper_callbacks, void *task_thread); // Disconnect from the underlying hardware, and close the HAL. // "Daisy, Daisy..." void (*close)(void); From 485c896740883007dbee7a0a937ba6563d15e7d3 Mon Sep 17 00:00:00 2001 From: baohongde Date: Wed, 31 Oct 2018 17:11:54 +0800 Subject: [PATCH 090/486] components/bt: Combine A2DP sink task and A2DP source task into btc task --- components/bt/bluedroid/btc/core/btc_task.c | 8 +++---- .../btc/profile/std/a2dp/btc_a2dp_sink.c | 18 +++------------- .../btc/profile/std/a2dp/btc_a2dp_source.c | 21 +++++++------------ 3 files changed, 14 insertions(+), 33 deletions(-) diff --git a/components/bt/bluedroid/btc/core/btc_task.c b/components/bt/bluedroid/btc/core/btc_task.c index e77f5ac4b9..72866dc3c5 100644 --- a/components/bt/bluedroid/btc/core/btc_task.c +++ b/components/bt/bluedroid/btc/core/btc_task.c @@ -55,7 +55,7 @@ #define BTC_TASK_NAME "btcT" #define BTC_TASK_PRIO (BT_TASK_MAX_PRIORITIES - 6) -static osi_thread_t *btc_thread; +osi_thread_t *btc_thread; static const btc_func_t profile_tab[BTC_PID_NUM] = { [BTC_PID_MAIN_INIT] = {btc_main_call_handler, NULL }, @@ -135,7 +135,7 @@ static bt_status_t btc_task_post(btc_msg_t *msg, osi_thread_blocking_t blocking) memcpy(lmsg, msg, sizeof(btc_msg_t)); - if (osi_thread_post(btc_thread, btc_thread_handler, lmsg, 0, blocking) == false) { + if (osi_thread_post(btc_thread, btc_thread_handler, lmsg, 2, blocking) == false) { return BT_STATUS_BUSY; } @@ -262,7 +262,7 @@ static void btc_deinit_mem(void) { int btc_init(void) { - btc_thread = osi_thread_create("BTC_TASK", BTC_TASK_STACK_SIZE, BTC_TASK_PRIO, BTC_TASK_PINNED_TO_CORE, 1); + btc_thread = osi_thread_create("BTC_TASK", BTC_TASK_STACK_SIZE, BTC_TASK_PRIO, BTC_TASK_PINNED_TO_CORE, 3); if (btc_thread == NULL) { return BT_STATUS_NOMEM; } @@ -297,7 +297,7 @@ void btc_deinit(void) bool btc_check_queue_is_congest(void) { - if (osi_thread_queue_wait_size(btc_thread, 0) >= QUEUE_CONGEST_SIZE) { + if (osi_thread_queue_wait_size(btc_thread, 2) >= QUEUE_CONGEST_SIZE) { return true; } diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c index ad1f5558b6..f1d51d80e3 100644 --- a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c +++ b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c @@ -45,12 +45,7 @@ #if (BTC_AV_SINK_INCLUDED == TRUE) -/* Macro */ -#define BTC_A2DP_SINK_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) -#define BTC_A2DP_SINK_TASK_STACK_SIZE (A2DP_SINK_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) // by menuconfig -#define BTC_A2DP_SINK_TASK_NAME "BtA2dSinkT" -#define BTC_A2DP_SINK_TASK_PRIO (BT_TASK_MAX_PRIORITIES - 3) - +extern osi_thread_t *btc_thread; /***************************************************************************** ** Constants @@ -242,10 +237,7 @@ bool btc_a2dp_sink_startup(void) APPL_TRACE_EVENT("## A2DP SINK START MEDIA THREAD ##"); - a2dp_sink_local_param.btc_aa_snk_task_hdl = osi_thread_create(BTC_A2DP_SINK_TASK_NAME, BTC_A2DP_SINK_TASK_STACK_SIZE, BTC_A2DP_SINK_TASK_PRIO, BTC_A2DP_SINK_TASK_PINNED_TO_CORE, 2); - if (a2dp_sink_local_param.btc_aa_snk_task_hdl == NULL) { - goto error_exit; - } + a2dp_sink_local_param.btc_aa_snk_task_hdl = btc_thread; if (btc_a2dp_sink_ctrl_post(BTC_MEDIA_TASK_SINK_INIT, NULL) == false) { goto error_exit; @@ -257,10 +249,7 @@ bool btc_a2dp_sink_startup(void) error_exit:; APPL_TRACE_ERROR("%s unable to start up media thread\n", __func__); - if (a2dp_sink_local_param.btc_aa_snk_task_hdl != NULL) { - osi_thread_free(a2dp_sink_local_param.btc_aa_snk_task_hdl); - a2dp_sink_local_param.btc_aa_snk_task_hdl = NULL; - } + a2dp_sink_local_param.btc_aa_snk_task_hdl = NULL; #if A2D_DYNAMIC_MEMORY == TRUE osi_free(a2dp_sink_local_param_ptr); @@ -282,7 +271,6 @@ void btc_a2dp_sink_shutdown(void) future_await(a2dp_sink_local_param.btc_a2dp_sink_future); a2dp_sink_local_param.btc_a2dp_sink_future = NULL; - osi_thread_free(a2dp_sink_local_param.btc_aa_snk_task_hdl); a2dp_sink_local_param.btc_aa_snk_task_hdl = NULL; #if A2D_DYNAMIC_MEMORY == TRUE diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c index 430d6f5fff..3591901002 100644 --- a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c +++ b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c @@ -50,12 +50,7 @@ #if BTC_AV_SRC_INCLUDED -/* Macro */ -#define BTC_A2DP_SOURCE_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) -#define BTC_A2DP_SOURCE_TASK_STACK_SIZE (A2DP_SOURCE_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) // by menuconfig -#define BTC_A2DP_SOURCE_TASK_NAME "BtA2dSourceT" -#define BTC_A2DP_SOURCE_TASK_PRIO (BT_TASK_MAX_PRIORITIES - 3) - +extern osi_thread_t *btc_thread; /***************************************************************************** ** Constants @@ -243,18 +238,18 @@ bool btc_a2dp_source_is_task_shutting_down(void) return btc_a2dp_source_state == BTC_A2DP_SOURCE_STATE_SHUTTING_DOWN; } -static void btc_a2dp_source_ctrl_post(uint32_t sig, void *param) +static bool btc_a2dp_source_ctrl_post(uint32_t sig, void *param) { a2dp_src_task_evt_t *evt = (a2dp_src_task_evt_t *)osi_malloc(sizeof(a2dp_src_task_evt_t)); if (evt == NULL) { - return; + return false; } evt->sig = sig; evt->param = param; - osi_thread_post(a2dp_source_local_param.btc_aa_src_task_hdl, btc_a2dp_source_ctrl_handler, evt, 0, OSI_THREAD_BLOCKING); + return osi_thread_post(a2dp_source_local_param.btc_aa_src_task_hdl, btc_a2dp_source_ctrl_handler, evt, 0, OSI_THREAD_BLOCKING); } static void btc_a2dp_source_ctrl_handler(void *arg) @@ -318,19 +313,18 @@ bool btc_a2dp_source_startup(void) APPL_TRACE_EVENT("## A2DP SOURCE START MEDIA THREAD ##"); - a2dp_source_local_param.btc_aa_src_task_hdl = osi_thread_create(BTC_A2DP_SOURCE_TASK_NAME, BTC_A2DP_SOURCE_TASK_STACK_SIZE, BTC_A2DP_SOURCE_TASK_PRIO, BTC_A2DP_SOURCE_TASK_PINNED_TO_CORE, 2); - if (a2dp_source_local_param.btc_aa_src_task_hdl == NULL) { + a2dp_source_local_param.btc_aa_src_task_hdl = btc_thread; + + if (btc_a2dp_source_ctrl_post(BTC_MEDIA_TASK_INIT, NULL) == false) { goto error_exit; } - btc_a2dp_source_ctrl_post(BTC_MEDIA_TASK_INIT, NULL); APPL_TRACE_EVENT("## A2DP SOURCE MEDIA THREAD STARTED ##\n"); return true; error_exit:; APPL_TRACE_ERROR("%s unable to start up media thread\n", __func__); - osi_thread_free(a2dp_source_local_param.btc_aa_src_task_hdl); a2dp_source_local_param.btc_aa_src_task_hdl = NULL; #if A2D_DYNAMIC_MEMORY == TRUE @@ -353,7 +347,6 @@ void btc_a2dp_source_shutdown(void) future_await(a2dp_source_local_param.btc_a2dp_source_future); a2dp_source_local_param.btc_a2dp_source_future = NULL; - osi_thread_free(a2dp_source_local_param.btc_aa_src_task_hdl); a2dp_source_local_param.btc_aa_src_task_hdl = NULL; #if A2D_DYNAMIC_MEMORY == TRUE From 84248221509670c132e96289dd9061b970499f00 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Sat, 15 Jun 2019 11:17:16 +0800 Subject: [PATCH 091/486] cmake: set CONFIG_DIR build property Add CONFIG_DIR as a build property, so that components don't have to derive it from one of the generated config files. --- components/esp32/CMakeLists.txt | 3 +-- components/esp_wifi/CMakeLists.txt | 3 ++- tools/cmake/component.cmake | 7 +++---- tools/cmake/kconfig.cmake | 1 + 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/components/esp32/CMakeLists.txt b/components/esp32/CMakeLists.txt index abcc0ada17..9d763b41b9 100644 --- a/components/esp32/CMakeLists.txt +++ b/components/esp32/CMakeLists.txt @@ -70,8 +70,7 @@ else() #symbols in it. target_link_libraries(${COMPONENT_LIB} INTERFACE "-u ld_include_panic_highint_hdl") - idf_build_get_property(sdkconfig_header SDKCONFIG_HEADER) - get_filename_component(config_dir ${sdkconfig_header} DIRECTORY) + idf_build_get_property(config_dir CONFIG_DIR) # Preprocess esp32.ld linker script to include configuration, becomes esp32_out.ld set(LD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ld) add_custom_command( diff --git a/components/esp_wifi/CMakeLists.txt b/components/esp_wifi/CMakeLists.txt index e4ba2db060..5349e905ac 100644 --- a/components/esp_wifi/CMakeLists.txt +++ b/components/esp_wifi/CMakeLists.txt @@ -44,11 +44,12 @@ if(CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION) # To get the phy_init_data.bin file, compile phy_init_data.h as a C file and then objcopy # the object file to a raw binary + idf_build_get_property(config_dir CONFIG_DIR) add_custom_command( OUTPUT ${phy_init_data_bin} DEPENDS ${CMAKE_CURRENT_LIST_DIR}/${idf_target}/include/phy_init_data.h COMMAND ${CMAKE_C_COMPILER} -x c -c - -I ${esp_common_dir}/include -I ${CMAKE_CURRENT_LIST_DIR}/include -I ${build_dir}/config + -I ${esp_common_dir}/include -I ${CMAKE_CURRENT_LIST_DIR}/include -I ${config_dir} -o phy_init_data.obj ${CMAKE_CURRENT_LIST_DIR}/${idf_target}/include/phy_init_data.h COMMAND ${CMAKE_OBJCOPY} -O binary phy_init_data.obj ${phy_init_data_bin} diff --git a/tools/cmake/component.cmake b/tools/cmake/component.cmake index 22b3528ec6..39b45a738f 100644 --- a/tools/cmake/component.cmake +++ b/tools/cmake/component.cmake @@ -427,8 +427,7 @@ function(idf_component_register) list(REMOVE_ITEM common_reqs ${component_lib}) link_libraries(${common_reqs}) - idf_build_get_property(sdkconfig_h SDKCONFIG_HEADER) - get_filename_component(sdkconfig_h ${sdkconfig_h} DIRECTORY) + idf_build_get_property(config_dir CONFIG_DIR) # The contents of 'sources' is from the __component_add_sources call if(sources OR __EMBED_FILES OR __EMBED_TXTFILES) @@ -436,14 +435,14 @@ function(idf_component_register) __component_set_property(${component_target} COMPONENT_TYPE LIBRARY) target_include_directories(${component_lib} PUBLIC ${__INCLUDE_DIRS}) target_include_directories(${component_lib} PRIVATE ${__PRIV_INCLUDE_DIRS}) - target_include_directories(${component_lib} PUBLIC ${sdkconfig_h}) + target_include_directories(${component_lib} PUBLIC ${config_dir}) set_target_properties(${component_lib} PROPERTIES OUTPUT_NAME ${COMPONENT_NAME}) __ldgen_add_component(${component_lib}) else() add_library(${component_lib} INTERFACE) __component_set_property(${component_target} COMPONENT_TYPE CONFIG_ONLY) target_include_directories(${component_lib} INTERFACE ${__INCLUDE_DIRS}) - target_include_directories(${component_lib} INTERFACE ${sdkconfig_h}) + target_include_directories(${component_lib} INTERFACE ${config_dir}) endif() # Alias the static/interface library created for linking to external targets. diff --git a/tools/cmake/kconfig.cmake b/tools/cmake/kconfig.cmake index 28be99371e..08344e78d9 100644 --- a/tools/cmake/kconfig.cmake +++ b/tools/cmake/kconfig.cmake @@ -189,6 +189,7 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) idf_build_set_property(SDKCONFIG_JSON ${sdkconfig_json}) idf_build_set_property(SDKCONFIG_CMAKE ${sdkconfig_cmake}) idf_build_set_property(SDKCONFIG_JSON_MENUS ${sdkconfig_json_menus}) + idf_build_set_property(CONFIG_DIR ${config_dir}) idf_build_get_property(menuconfig_depends __MENUCONFIG_DEPENDS) From 2fff500a1c60f44741c4279b6ad177eba6331438 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Sat, 15 Jun 2019 11:20:43 +0800 Subject: [PATCH 092/486] cmake: export IDF_TARGET to menuconfig Pass value of IDF_TARGET to menuconfig invocation. --- tools/cmake/kconfig.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/cmake/kconfig.cmake b/tools/cmake/kconfig.cmake index 08344e78d9..97702935ee 100644 --- a/tools/cmake/kconfig.cmake +++ b/tools/cmake/kconfig.cmake @@ -205,6 +205,7 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) "COMPONENT_KCONFIGS_PROJBUILD=${kconfig_projbuilds}" "IDF_CMAKE=y" "KCONFIG_CONFIG=${sdkconfig}" + "IDF_TARGET=${idf_target}" ${mconf} ${root_kconfig} # VERBATIM cannot be used here because it cannot handle ${mconf}="winpty mconf-idf" and the escaping must be # done manually From 64d37f5cb9d3e6b09bc37562c5bd9ad272516bab Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Sat, 15 Jun 2019 11:26:32 +0800 Subject: [PATCH 093/486] cmake: fix issues with build process Fix issue when COMPONENTS are is not specified for idf_build_process, no component is included in the build. --- tools/cmake/build.cmake | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/cmake/build.cmake b/tools/cmake/build.cmake index 84f6f154fc..ff43ba1023 100644 --- a/tools/cmake/build.cmake +++ b/tools/cmake/build.cmake @@ -367,15 +367,20 @@ macro(idf_build_process target) __build_check_python() idf_build_set_property(__COMPONENT_REQUIRES_COMMON ${target} APPEND) - __component_get_requirements() # Perform early expansion of component CMakeLists.txt in CMake scripting mode. # It is here we retrieve the public and private requirements of each component. # It is also here we add the common component requirements to each component's # own requirements. + __component_get_requirements() + + idf_build_get_property(component_targets __COMPONENT_TARGETS) # Finally, do component expansion. In this case it simply means getting a final list # of build component targets given the requirements set by each component. + + # Check if we need to trim the components first, and build initial components list + # from that. if(__COMPONENTS) unset(component_targets) foreach(component ${__COMPONENTS}) @@ -390,7 +395,7 @@ macro(idf_build_process target) foreach(component_target ${component_targets}) __build_expand_requirements(${component_target}) endforeach() - unset(__COMPONENT_TARGETS_SEEN) + idf_build_unset_property(__COMPONENT_TARGETS_SEEN) # Get a list of common component requirements in component targets form (previously # we just have a list of component names) From 7a19894aec84dd18ead58687212ff3fb4e15f6ea Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Mon, 17 Jun 2019 12:20:12 +0800 Subject: [PATCH 094/486] esptool_py: better display logs when generating binary Since OUTPUT argument of custom command does not currently support generator expressions, the project image is only generated as a side effect. The primary generated file is a timestamp file. Unfortunately as a consequence the output logs when the binary is about to be generated is not as helpful anymore. Set a custom comment that is more descriptive of what is happening, and provide more feedback as to what has been generated. --- components/esptool_py/project_include.cmake | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/components/esptool_py/project_include.cmake b/components/esptool_py/project_include.cmake index d6c888f437..b847680c88 100644 --- a/components/esptool_py/project_include.cmake +++ b/components/esptool_py/project_include.cmake @@ -75,28 +75,33 @@ set(PROJECT_BIN "${elf_name}.bin") # # Add 'app.bin' target - generates with elf2image # -add_custom_command(OUTPUT "${build_dir}/.app_hash" +add_custom_command(OUTPUT "${build_dir}/.bin_timestamp" COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS} ${ESPTOOLPY_ELF2IMAGE_OPTIONS} -o "${build_dir}/${unsigned_project_binary}" "${elf}" - COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${unsigned_project_binary}" > "${build_dir}/.app_hash" + COMMAND ${CMAKE_COMMAND} -E echo "Generated ${build_dir}/${unsigned_project_binary}" + COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${unsigned_project_binary}" > "${build_dir}/.bin_timestamp" DEPENDS ${elf} VERBATIM WORKING_DIRECTORY ${build_dir} + COMMENT "Generating binary image from built executable" ) -add_custom_target(gen_project_binary DEPENDS "${build_dir}/.app_hash") +add_custom_target(gen_project_binary DEPENDS "${build_dir}/.bin_timestamp") if(NOT BOOTLOADER_BUILD AND CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) # for locally signed secure boot image, add a signing step to get from unsigned app to signed app - add_custom_command(OUTPUT "${build_dir}/.signed_app_hash" + add_custom_command(OUTPUT "${build_dir}/.signed_bin_timestamp" COMMAND ${ESPSECUREPY} sign_data --keyfile ${secure_boot_signing_key} -o "${build_dir}/${PROJECT_BIN}" "${build_dir}/${unsigned_project_binary}" - COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${PROJECT_BIN}" > "${build_dir}/.signed_app_hash" - DEPENDS "${build_dir}/.app_hash" + COMMAND ${CMAKE_COMMAND} -E echo "Generated signed binary image ${build_dir}/${PROJECT_BIN}" + "from ${build_dir}/${unsigned_project_binary}" + COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${PROJECT_BIN}" > "${build_dir}/.signed_bin_timestamp" + DEPENDS "${build_dir}/.bin_timestamp" VERBATIM + COMMENT "Generating signed binary image" ) - add_custom_target(gen_signed_project_binary DEPENDS "${build_dir}/.signed_app_hash") + add_custom_target(gen_signed_project_binary DEPENDS "${build_dir}/.signed_bin_timestamp") add_dependencies(gen_project_binary gen_signed_project_binary) endif() @@ -106,6 +111,7 @@ else() add_custom_target(bootloader ALL DEPENDS gen_project_binary) endif() + if(NOT BOOTLOADER_BUILD AND CONFIG_SECURE_BOOT_ENABLED AND NOT CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) From 11924d76cb8b81c0b060bb1cd4b3a40ef44caff2 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Mon, 17 Jun 2019 12:14:02 +0800 Subject: [PATCH 095/486] cmake: clarify build trimming docs How idf_build_component and the COMPONENTS argument to idf_build_process interact is not clear/misleading. Clarify their interaction in the docs. Closes: https://github.com/espressif/esp-idf/issues/3630 --- docs/en/api-guides/build-system-cmake.rst | 10 ++++++++-- tools/cmake/build.cmake | 21 ++++++++++++++++----- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/docs/en/api-guides/build-system-cmake.rst b/docs/en/api-guides/build-system-cmake.rst index 08f9e3a396..455149fec5 100644 --- a/docs/en/api-guides/build-system-cmake.rst +++ b/docs/en/api-guides/build-system-cmake.rst @@ -943,7 +943,10 @@ the first element/member instead. idf_build_component(component_dir) -Add a directory *component_dir* that contains a component to the build. +Present a directory *component_dir* that contains a component to the build system. Relative paths are converted to absolute paths with respect to current directory. +All calls to this command must be performed before `idf_build_process`. + +This command does not guarantee that the component will be processed during build (see the `COMPONENTS` argument description for `idf_build_process`) .. code-block:: none @@ -970,7 +973,10 @@ The call requires the target chip to be specified with *target* argument. Option - SDKCONFIG - output path of generated sdkconfig file; defaults to PROJECT_DIR/sdkconfig or CMAKE_SOURCE_DIR/sdkconfig depending if PROJECT_DIR is set - SDKCONFIG_DEFAULTS - defaults file to use for the build; defaults to empty - BUILD_DIR - directory to place ESP-IDF build-related artifacts, such as generated binaries, text files, components; defaults to CMAKE_BINARY_DIR -- COMPONENTS - starting components for trimming the build; components not in the list are automatically if they are required in the expanded dependency tree +- COMPONENTS - select components to process among the components known by the build system (added via `idf_build_component`). This argument is used to trim the build. + Other components are automatically added if they are required in the dependency chain, i.e. + the public and private requirements of the components in this list are automatically added, and in turn the public and private requirements of those requirements, + so on and so forth. If not specified, all components known to the build system are processed. .. code-block:: none diff --git a/tools/cmake/build.cmake b/tools/cmake/build.cmake index ff43ba1023..5383581f12 100644 --- a/tools/cmake/build.cmake +++ b/tools/cmake/build.cmake @@ -163,12 +163,14 @@ endfunction() # idf_build_component # -# @brief Specify component directory for the build system to process. +# @brief Present a directory that contains a component to the build system. # Relative paths are converted to absolute paths with respect to current directory. -# Any component that needs to be processed has to be specified using this -# command before calling idf_build_process. +# All calls to this command must be performed before idf_build_process. # -# @param[in] component_dir directory of the component to process +# @note This command does not guarantee that the component will be processed +# during build (see the COMPONENTS argument description for command idf_build_process) +# +# @param[in] component_dir directory of the component function(idf_build_component component_dir) idf_build_get_property(prefix __PREFIX) __component_add(${component_dir} ${prefix} 0) @@ -335,7 +337,16 @@ endfunction() # @param[in, optional] SDKCONFIG_DEFAULTS (single value) config defaults file to use for the build; defaults # to none (Kconfig defaults or previously generated config are used) # @param[in, optional] BUILD_DIR (single value) directory for build artifacts; defautls to CMAKE_BINARY_DIR -# @param[in, optional] COMPONENTS (multivalue) starting components for trimming build +# @param[in, optional] COMPONENTS (multivalue) select components to process among the components +# known by the build system +# (added via `idf_build_component`). This argument is used to trim the build. +# Other components are automatically added if they are required +# in the dependency chain, i.e. +# the public and private requirements of the components in this list +# are automatically added, and in +# turn the public and private requirements of those requirements, +# so on and so forth. If not specified, all components known to the build system +# are processed. macro(idf_build_process target) set(options) set(single_value PROJECT_DIR PROJECT_VER PROJECT_NAME BUILD_DIR SDKCONFIG SDKCONFIG_DEFAULTS) From 07fef85a23111a4a238222a0273eae089e8faa05 Mon Sep 17 00:00:00 2001 From: baohongde Date: Mon, 12 Nov 2018 11:08:19 +0800 Subject: [PATCH 096/486] components/bt: Separation of BT and BLE --- components/bt/Kconfig | 16 +++-- components/bt/bluedroid/bta/dm/bta_dm_act.c | 47 +++++++++++++-- components/bt/bluedroid/bta/dm/bta_dm_api.c | 17 ++++-- .../bt/bluedroid/bta/dm/include/bta_dm_int.h | 17 ++++-- .../bt/bluedroid/bta/include/bta/bta_api.h | 10 ++-- .../bt/bluedroid/bta/include/bta/bta_dm_co.h | 1 + .../bt/bluedroid/btc/core/btc_ble_storage.c | 4 ++ components/bt/bluedroid/btc/core/btc_dm.c | 8 ++- components/bt/bluedroid/btc/core/btc_main.c | 5 ++ components/bt/bluedroid/btc/core/btc_task.c | 9 +++ .../btc/profile/std/gap/btc_gap_ble.c | 2 + .../common/include/common/bt_target.h | 22 +++---- .../common/include/common/bt_user_config.h | 6 ++ components/bt/bluedroid/stack/btm/btm_acl.c | 3 + components/bt/bluedroid/stack/btm/btm_ble.c | 26 ++++---- .../bt/bluedroid/stack/btm/btm_devctl.c | 4 +- components/bt/bluedroid/stack/btm/btm_sec.c | 41 +++++++++++-- .../bt/bluedroid/stack/btm/include/btm_int.h | 18 ++++-- components/bt/bluedroid/stack/btu/btu_hcif.c | 2 + .../bluedroid/stack/include/stack/btm_api.h | 10 ++-- .../bluedroid/stack/include/stack/l2c_api.h | 2 +- .../bluedroid/stack/include/stack/smp_api.h | 4 +- components/bt/bluedroid/stack/l2cap/l2c_api.c | 4 +- components/bt/bluedroid/stack/l2cap/l2c_ble.c | 44 +++++++------- .../bt/bluedroid/stack/l2cap/l2c_link.c | 8 ++- .../bt/bluedroid/stack/l2cap/l2c_main.c | 4 ++ .../bt/bluedroid/stack/l2cap/l2c_utils.c | 7 ++- .../bt/bluedroid/stack/smp/include/smp_int.h | 4 +- components/bt/bluedroid/stack/smp/smp_act.c | 59 +++++++++++++++++-- components/bt/bluedroid/stack/smp/smp_api.c | 4 ++ .../bt/bluedroid/stack/smp/smp_br_main.c | 2 +- components/bt/bluedroid/stack/smp/smp_keys.c | 9 ++- components/bt/bluedroid/stack/smp/smp_l2c.c | 15 ++++- components/bt/bluedroid/stack/smp/smp_main.c | 8 ++- components/bt/bluedroid/stack/smp/smp_utils.c | 21 +++++-- .../bluetooth/a2dp_sink/sdkconfig.defaults | 4 +- .../bluetooth/a2dp_source/sdkconfig.defaults | 4 +- .../bluetooth/bt_discovery/sdkconfig.defaults | 4 +- .../bt_spp_acceptor/sdkconfig.defaults | 1 + .../bt_spp_initiator/sdkconfig.defaults | 1 + .../bt_spp_vfs_acceptor/sdkconfig.defaults | 1 + .../bt_spp_vfs_initiator/sdkconfig.defaults | 1 + 42 files changed, 354 insertions(+), 125 deletions(-) diff --git a/components/bt/Kconfig b/components/bt/Kconfig index a15bd7dc2f..d292e66c20 100644 --- a/components/bt/Kconfig +++ b/components/bt/Kconfig @@ -1,6 +1,5 @@ menu Bluetooth - config BT_ENABLED bool "Bluetooth" help @@ -475,9 +474,16 @@ menu Bluetooth help This enables the Secure Simple Pairing. If disable this option, Bluedroid will only support Legacy Pairing + config BT_BLE_ENABLED + bool "Bluetooth Low Energy" + depends on BT_BLUEDROID_ENABLED + default y + help + This enables Bluetooth Low Energy + config BT_GATTS_ENABLE bool "Include GATT server module(GATTS)" - depends on BT_BLUEDROID_ENABLED && (BTDM_CTRL_MODE_BTDM || BTDM_CTRL_MODE_BLE_ONLY) + depends on BT_BLE_ENABLED default y help This option can be disabled when the app work only on gatt client mode @@ -510,21 +516,21 @@ menu Bluetooth config BT_GATTC_ENABLE bool "Include GATT client module(GATTC)" - depends on BT_BLUEDROID_ENABLED && (BTDM_CTRL_MODE_BTDM || BTDM_CTRL_MODE_BLE_ONLY) + depends on BT_BLE_ENABLED default y help This option can be close when the app work only on gatt server mode config BT_GATTC_CACHE_NVS_FLASH bool "Save gattc cache data to nvs flash" - depends on BT_GATTC_ENABLE && (BTDM_CTRL_MODE_BTDM || BTDM_CTRL_MODE_BLE_ONLY) + depends on BT_GATTC_ENABLE default n help This select can save gattc cache data to nvs flash config BT_BLE_SMP_ENABLE bool "Include BLE security module(SMP)" - depends on BT_BLUEDROID_ENABLED && (BTDM_CTRL_MODE_BTDM || BTDM_CTRL_MODE_BLE_ONLY) + depends on BT_BLE_ENABLED default y help This option can be close when the app not used the ble security connect. diff --git a/components/bt/bluedroid/bta/dm/bta_dm_act.c b/components/bt/bluedroid/bta/dm/bta_dm_act.c index efb685ecd6..a6fefeacfe 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_act.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_act.c @@ -60,7 +60,9 @@ static void bta_dm_sdp_callback (UINT16 sdp_status); #endif ///SDP_INCLUDED == TRUE #if (SMP_INCLUDED == TRUE) static UINT8 bta_dm_authorize_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, UINT8 *service_name, UINT8 service_id, BOOLEAN is_originator); +#if (CLASSIC_BT_INCLUDED == TRUE) static UINT8 bta_dm_pin_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, BOOLEAN min_16_digit); +#endif /// CLASSIC_BT_INCLUDED == TRUE static UINT8 bta_dm_new_link_key_cback(BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, LINK_KEY key, UINT8 key_type); static UINT8 bta_dm_authentication_complete_cback(BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, int result); #endif ///SMP_INCLUDED == TRUE @@ -125,9 +127,12 @@ static void bta_dm_ctrl_features_rd_cmpl_cback(tBTM_STATUS result); #if (SMP_INCLUDED == TRUE) static void bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr); #endif ///SMP_INCLUDED == TRUE +#if (BLE_INCLUDED == TRUE) static void bta_dm_observe_results_cb(tBTM_INQ_RESULTS *p_inq, UINT8 *p_eir); static void bta_dm_observe_cmpl_cb(void *p_result); static void bta_dm_observe_discard_cb (uint32_t num_dis); +#endif ///BLE_INCLUDED == TRUE + static void bta_dm_delay_role_switch_cback(TIMER_LIST_ENT *p_tle); extern void sdpu_uuid16_to_uuid128(UINT16 uuid16, UINT8 *p_uuid128); static void bta_dm_disable_timer_cback(TIMER_LIST_ENT *p_tle); @@ -215,7 +220,11 @@ const UINT32 bta_service_id_to_btm_srv_id_lkup_tbl [BTA_MAX_SERVICE_ID] = { #if (SMP_INCLUDED == TRUE) const tBTM_APPL_INFO bta_security = { &bta_dm_authorize_cback, +#if (CLASSIC_BT_INCLUDED == TRUE) &bta_dm_pin_cback, +#else + NULL, +#endif &bta_dm_new_link_key_cback, &bta_dm_authentication_complete_cback, &bta_dm_bond_cancel_complete_cback, @@ -581,7 +590,7 @@ void bta_dm_disable (tBTA_DM_MSG *p_data) bta_sys_start_timer(&bta_dm_cb.disable_timer, 0, 5000); } -#if BLE_PRIVACY_SPT == TRUE +#if BLE_INCLUDED == TRUE && BLE_PRIVACY_SPT == TRUE btm_ble_resolving_list_cleanup (); //by TH, because cmn_ble_vsc_cb.max_filter has something mistake as btm_ble_adv_filter_cleanup #endif @@ -698,25 +707,31 @@ void bta_dm_config_eir (tBTA_DM_MSG *p_data) void bta_dm_update_white_list(tBTA_DM_MSG *p_data) { +#if (BLE_INCLUDED == TRUE) BTM_BleUpdateAdvWhitelist(p_data->white_list.add_remove, p_data->white_list.remote_addr, p_data->white_list.addr_type, p_data->white_list.add_wl_cb); +#endif ///BLE_INCLUDED == TRUE } void bta_dm_ble_read_adv_tx_power(tBTA_DM_MSG *p_data) { +#if (BLE_INCLUDED == TRUE) if (p_data->read_tx_power.read_tx_power_cb != NULL) { BTM_BleReadAdvTxPower(p_data->read_tx_power.read_tx_power_cb); } else { APPL_TRACE_ERROR("%s(), the callback function can't be NULL.", __func__); } +#endif ///BLE_INCLUDED == TRUE } void bta_dm_ble_read_rssi(tBTA_DM_MSG *p_data) { +#if (BLE_INCLUDED == TRUE) if (p_data->rssi.read_rssi_cb != NULL) { BTM_ReadRSSI(p_data->rssi.remote_addr, p_data->rssi.transport, p_data->rssi.read_rssi_cb); } else { APPL_TRACE_ERROR("%s(), the callback function can't be NULL.", __func__); } +#endif ///BLE_INCLUDED == TRUE } /******************************************************************************* @@ -732,42 +747,52 @@ void bta_dm_ble_read_rssi(tBTA_DM_MSG *p_data) void bta_dm_set_visibility(tBTA_DM_MSG *p_data) { UINT16 window, interval; - UINT16 le_disc_mode = BTM_BleReadDiscoverability(); UINT16 disc_mode = BTM_ReadDiscoverability(&window, &interval); - UINT16 le_conn_mode = BTM_BleReadConnectability(); UINT16 conn_mode = BTM_ReadConnectability(&window, &interval); +#if (BLE_INCLUDED == TRUE) + UINT16 le_disc_mode = BTM_BleReadDiscoverability(); + UINT16 le_conn_mode = BTM_BleReadConnectability(); +#endif ///BLE_INCLUDED == TRUE /* set modes for Discoverability and connectability if not ignore */ if (p_data->set_visibility.disc_mode != (BTA_DM_IGNORE | BTA_DM_LE_IGNORE)) { +#if (BLE_INCLUDED == TRUE) if ((p_data->set_visibility.disc_mode & BTA_DM_LE_IGNORE) == BTA_DM_LE_IGNORE) { p_data->set_visibility.disc_mode = ((p_data->set_visibility.disc_mode & ~BTA_DM_LE_IGNORE) | le_disc_mode); } +#endif ///BLE_INCLUDED == TRUE if ((p_data->set_visibility.disc_mode & BTA_DM_IGNORE) == BTA_DM_IGNORE) { p_data->set_visibility.disc_mode = ((p_data->set_visibility.disc_mode & ~BTA_DM_IGNORE) | disc_mode); } +#if (CLASSIC_BT_INCLUDED == TRUE) BTM_SetDiscoverability(p_data->set_visibility.disc_mode, bta_dm_cb.inquiry_scan_window, bta_dm_cb.inquiry_scan_interval); +#endif } if (p_data->set_visibility.conn_mode != (BTA_DM_IGNORE | BTA_DM_LE_IGNORE)) { +#if (BLE_INCLUDED == TRUE) if ((p_data->set_visibility.conn_mode & BTA_DM_LE_IGNORE) == BTA_DM_LE_IGNORE) { p_data->set_visibility.conn_mode = ((p_data->set_visibility.conn_mode & ~BTA_DM_LE_IGNORE) | le_conn_mode); } +#endif ///BLE_INCLUDED == TRUE if ((p_data->set_visibility.conn_mode & BTA_DM_IGNORE) == BTA_DM_IGNORE) { p_data->set_visibility.conn_mode = ((p_data->set_visibility.conn_mode & ~BTA_DM_IGNORE) | conn_mode); } +#if (CLASSIC_BT_INCLUDED == TRUE) BTM_SetConnectability(p_data->set_visibility.conn_mode, bta_dm_cb.page_scan_window, bta_dm_cb.page_scan_interval); +#endif } /* Send False or True if not ignore */ @@ -1096,7 +1121,9 @@ void bta_dm_bond_cancel (tBTA_DM_MSG *p_data) *******************************************************************************/ void bta_dm_set_pin_type (tBTA_DM_MSG *p_data) { +#if (CLASSIC_BT_INCLUDED == TRUE) BTM_SetPinType (p_data->set_pin_type.pin_type, p_data->set_pin_type.p_pin, p_data->set_pin_type.pin_len); +#endif ///CLASSIC_BT_INCLUDED == TRUE } /******************************************************************************* @@ -1111,6 +1138,7 @@ void bta_dm_set_pin_type (tBTA_DM_MSG *p_data) *******************************************************************************/ void bta_dm_pin_reply (tBTA_DM_MSG *p_data) { +#if (CLASSIC_BT_INCLUDED == TRUE) UINT32 trusted_mask[BTM_SEC_SERVICE_ARRAY_SIZE]; UINT32 *current_trusted_mask; @@ -1128,7 +1156,7 @@ void bta_dm_pin_reply (tBTA_DM_MSG *p_data) } else { BTM_PINCodeReply(p_data->pin_reply.bd_addr, BTM_NOT_AUTHORIZED, 0, NULL, trusted_mask ); } - +#endif ///CLASSIC_BT_INCLUDED == TRUE } #endif ///SMP_INCLUDED == TRUE @@ -2792,6 +2820,8 @@ static UINT8 bta_dm_authorize_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NA } } + +#if (CLASSIC_BT_INCLUDED == TRUE) #if (BT_SSP_INCLUDED == TRUE) /******************************************************************************* ** @@ -2878,6 +2908,7 @@ static UINT8 bta_dm_pin_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_ bta_dm_cb.p_sec_cback(BTA_DM_PIN_REQ_EVT, &sec_event); return BTM_CMD_STARTED; } +#endif ///CLASSIC_BT_INCLUDED == TRUE /******************************************************************************* ** @@ -5797,6 +5828,7 @@ static void bta_dm_gattc_register(void) } } #endif /* GATTC_INCLUDED == TRUE */ + /******************************************************************************* ** ** Function btm_dm_start_disc_gatt_services @@ -5806,6 +5838,7 @@ static void bta_dm_gattc_register(void) ** Parameters: ** *******************************************************************************/ +#if (GATTC_INCLUDED == TRUE) static void btm_dm_start_disc_gatt_services (UINT16 conn_id) { tBT_UUID *p_uuid = bta_dm_search_cb.p_srvc_uuid + @@ -5817,6 +5850,7 @@ static void btm_dm_start_disc_gatt_services (UINT16 conn_id) /* always search for all services */ BTA_GATTC_ServiceSearchRequest(conn_id, p_uuid); } +#endif /* GATTC_INCLUDED == TRUE */ /******************************************************************************* ** @@ -5877,6 +5911,7 @@ static void bta_dm_gatt_disc_result(tBTA_GATT_ID service_id) ** Parameters: ** *******************************************************************************/ +#if (GATTC_INCLUDED == TRUE) static void bta_dm_gatt_disc_complete(UINT16 conn_id, tBTA_GATT_STATUS status) { tBTA_DM_MSG *p_msg; @@ -5934,6 +5969,7 @@ static void bta_dm_gatt_disc_complete(UINT16 conn_id, tBTA_GATT_STATUS status) bta_dm_search_cb.gatt_disc_active = FALSE; } } +#endif /* #if (GATTC_INCLUDED == TRUE) */ /******************************************************************************* ** @@ -6003,6 +6039,7 @@ static void bta_dm_cancel_gatt_discovery(BD_ADDR bd_addr) bta_dm_gatt_disc_complete(bta_dm_search_cb.conn_id, (tBTA_GATT_STATUS) BTA_GATT_ERROR); } #endif /* #if (GATTC_INCLUDED == TRUE) */ + /******************************************************************************* ** ** Function bta_dm_proc_open_evt @@ -6012,6 +6049,7 @@ static void bta_dm_cancel_gatt_discovery(BD_ADDR bd_addr) ** Parameters: ** *******************************************************************************/ +#if (GATTC_INCLUDED == TRUE) void bta_dm_proc_open_evt(tBTA_GATTC_OPEN *p_data) { UINT8 *p1; @@ -6042,6 +6080,7 @@ void bta_dm_proc_open_evt(tBTA_GATTC_OPEN *p_data) bta_dm_gatt_disc_complete(BTA_GATT_INVALID_CONN_ID, p_data->status); } } +#endif /* #if (GATTC_INCLUDED == TRUE) */ /******************************************************************************* ** diff --git a/components/bt/bluedroid/bta/dm/bta_dm_api.c b/components/bt/bluedroid/bta/dm/bta_dm_api.c index 927257733f..141d9ce2dd 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_api.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_api.c @@ -225,6 +225,7 @@ void BTA_DmConfigEir(tBTA_DM_EIR_CONF *eir_config) } } +#if (BLE_INCLUDED == TRUE) void BTA_DmUpdateWhiteList(BOOLEAN add_remove, BD_ADDR remote_addr, tBLE_ADDR_TYPE addr_type, tBTA_ADD_WHITELIST_CBACK *add_wl_cb) { tBTA_DM_API_UPDATE_WHITE_LIST *p_msg; @@ -248,6 +249,7 @@ void BTA_DmBleReadAdvTxPower(tBTA_CMPL_CB *cmpl_cb) bta_sys_sendmsg(p_msg); } } +#endif ///BLE_INCLUDED == TRUE void BTA_DmBleReadRSSI(BD_ADDR remote_addr, tBTA_TRANSPORT transport, tBTA_CMPL_CB *cmpl_cb) { @@ -475,10 +477,10 @@ void BTA_DmBondCancel(BD_ADDR bd_addr) bdcpy(p_msg->bd_addr, bd_addr); bta_sys_sendmsg(p_msg); } - - } +#endif ///SMP_INCLUDED == TRUE +#if (CLASSIC_BT_INCLUDED == TRUE) /******************************************************************************* ** ** Function BTA_DMSetPinType @@ -529,6 +531,7 @@ void BTA_DmPinReply(BD_ADDR bd_addr, BOOLEAN accept, UINT8 pin_len, UINT8 *p_pin } } +#endif ///CLASSIC_BT_INCLUDED == TRUE #if (BTM_OOB_INCLUDED == TRUE && SMP_INCLUDED == TRUE) /******************************************************************************* @@ -594,6 +597,7 @@ void BTA_DmOobReply(BD_ADDR bd_addr, UINT8 len, UINT8 *p_value) ** Returns void ** *******************************************************************************/ +#if (SMP_INCLUDED == TRUE) void BTA_DmConfirm(BD_ADDR bd_addr, BOOLEAN accept) { tBTA_DM_API_CONFIRM *p_msg; @@ -629,6 +633,7 @@ void BTA_DmPasskeyReqReply(BOOLEAN accept, BD_ADDR bd_addr, UINT32 passkey) } } #endif ///BT_SSP_INCLUDED == TRUE +#endif ///SMP_INCLUDED == TRUE /******************************************************************************* ** ** Function BTA_DmAddDevice @@ -705,7 +710,7 @@ tBTA_STATUS BTA_DmRemoveDevice(BD_ADDR bd_addr, tBT_TRANSPORT transport) return BTA_SUCCESS; } -#endif ///SMP_INCLUDED == TRUE +// #endif ///SMP_INCLUDED == TRUE /******************************************************************************* ** @@ -989,7 +994,6 @@ void BTA_DmBleSecurityGrant(BD_ADDR bd_addr, tBTA_DM_BLE_SEC_GRANT res) } } #endif ///SMP_INCLUDED == TRUE -#endif ///BLE_INCLUDED == TRUE /******************************************************************************* @@ -1207,7 +1211,7 @@ void BTA_DmSetBleAdvParamsAll (UINT16 adv_int_min, UINT16 adv_int_max, } #endif } - +#endif ///BLE_INCLUDED == TRUE /******************************************************************************* @@ -1796,6 +1800,8 @@ void BTA_DmBleUpdateConnectionParam(BD_ADDR bd_addr, UINT16 min_int, } #endif } + +#if BLE_INCLUDED == TRUE /******************************************************************************* ** ** Function BTA_DmBleConfigLocalPrivacy @@ -1826,7 +1832,6 @@ void BTA_DmBleConfigLocalPrivacy(BOOLEAN privacy_enable, tBTA_SET_LOCAL_PRIVACY_ #endif } -#if BLE_INCLUDED == TRUE /******************************************************************************* ** ** Function BTA_DmBleConfigLocalIcon diff --git a/components/bt/bluedroid/bta/dm/include/bta_dm_int.h b/components/bt/bluedroid/bta/dm/include/bta_dm_int.h index 83fdb3bab7..4fc8e650ce 100644 --- a/components/bt/bluedroid/bta/dm/include/bta_dm_int.h +++ b/components/bt/bluedroid/bta/dm/include/bta_dm_int.h @@ -203,6 +203,7 @@ typedef struct { UINT8 data[]; }tBTA_DM_API_CONFIG_EIR; +#if (BLE_INCLUDED == TRUE) typedef struct { BT_HDR hdr; BOOLEAN add_remove; @@ -223,6 +224,7 @@ typedef struct { BT_HDR hdr; tBTA_CMPL_CB *read_tx_power_cb; }tBTA_DM_API_READ_ADV_TX_POWER; +#endif ///BLE_INCLUDED == TRUE typedef struct { BT_HDR hdr; @@ -402,8 +404,8 @@ typedef struct { UINT8 hci_status; #if BLE_INCLUDED == TRUE UINT16 handle; - tBT_TRANSPORT transport; #endif + tBT_TRANSPORT transport; } tBTA_DM_ACL_CHANGE; #if (BTA_DM_PM_INCLUDED == TRUE) @@ -801,9 +803,12 @@ typedef union { tBTA_DM_API_SET_NAME set_name; tBTA_DM_API_CONFIG_EIR config_eir; +#if (BLE_INCLUDED == TRUE) tBTA_DM_API_UPDATE_WHITE_LIST white_list; tBTA_DM_API_READ_ADV_TX_POWER read_tx_power; tBTA_DM_API_READ_RSSI rssi; +#endif ///BLE_INCLUDED == TRUE + tBTA_DM_API_SET_VISIBILITY set_visibility; tBTA_DM_API_ADD_DEVICE add_dev; @@ -939,8 +944,8 @@ typedef struct { BOOLEAN remove_dev_pending; #if BLE_INCLUDED == TRUE UINT16 conn_handle; - tBT_TRANSPORT transport; #endif + tBT_TRANSPORT transport; } tBTA_DM_PEER_DEVICE; @@ -1031,6 +1036,8 @@ typedef struct { BOOLEAN disable_pair_mode; /* disable pair mode or not */ BOOLEAN conn_paired_only; /* allow connectable to paired device only or not */ tBTA_DM_API_SEARCH search_msg; + +#if (CLASSIC_BT_INCLUDED == TRUE) UINT16 page_scan_interval; UINT16 page_scan_window; UINT16 inquiry_scan_interval; @@ -1040,8 +1047,10 @@ typedef struct { BD_ADDR pin_bd_addr; DEV_CLASS pin_dev_class; tBTA_DM_SEC_EVT pin_evt; - UINT32 num_val; /* the numeric value for comparison. If just_works, do not show this number to UI */ - BOOLEAN just_works; /* TRUE, if "Just Works" association model */ + UINT32 num_val; /* the numeric value for comparison. If just_works, do not show this number to UI */ + BOOLEAN just_works; /* TRUE, if "Just Works" association model */ +#endif + #if ( BTA_EIR_CANNED_UUID_LIST != TRUE ) /* store UUID list for EIR */ TIMER_LIST_ENT app_ready_timer; diff --git a/components/bt/bluedroid/bta/include/bta/bta_api.h b/components/bt/bluedroid/bta/include/bta/bta_api.h index aed71d7e46..c9349e80ec 100644 --- a/components/bt/bluedroid/bta/include/bta/bta_api.h +++ b/components/bt/bluedroid/bta/include/bta/bta_api.h @@ -31,9 +31,9 @@ // #include "uipc_msg.h" #include "stack/sdp_api.h" -#if BLE_INCLUDED == TRUE +// #if BLE_INCLUDED == TRUE #include "stack/btm_ble_api.h" -#endif +// #endif /***************************************************************************** ** Constants and data types @@ -323,7 +323,7 @@ typedef struct { tBTA_DM_CONFIG_EIR_CBACK *config_eir_callback; /* callback */ } tBTA_DM_EIR_CONF; -#if BLE_INCLUDED == TRUE +// #if BLE_INCLUDED == TRUE /* ADV data flag bit definition used for BTM_BLE_AD_TYPE_FLAG */ #define BTA_BLE_LIMIT_DISC_FLAG BTM_BLE_LIMIT_DISC_FLAG #define BTA_BLE_GEN_DISC_FLAG BTM_BLE_GEN_DISC_FLAG @@ -510,7 +510,7 @@ enum { typedef tBTM_BLE_BATCH_SCAN_EVT tBTA_BLE_BATCH_SCAN_EVT; typedef tBTM_BLE_TRACK_ADV_ACTION tBTA_BLE_TRACK_ADV_ACTION; -#endif +// #endif /* BLE customer specific feature function type definitions */ /* data type used on customer specific feature for RSSI monitoring */ @@ -1473,9 +1473,11 @@ extern void BTA_DmSetDeviceName(const char *p_name); *******************************************************************************/ extern void BTA_DmConfigEir(tBTA_DM_EIR_CONF *eir_config); +#if (BLE_INCLUDED == TRUE) extern void BTA_DmUpdateWhiteList(BOOLEAN add_remove, BD_ADDR remote_addr, tBLE_ADDR_TYPE addr_type, tBTA_ADD_WHITELIST_CBACK *add_wl_cb); extern void BTA_DmBleReadAdvTxPower(tBTA_CMPL_CB *cmpl_cb); +#endif ///BLE_INCLUDED == TRUE extern void BTA_DmBleReadRSSI(BD_ADDR remote_addr, tBTA_TRANSPORT transport, tBTA_CMPL_CB *cmpl_cb); diff --git a/components/bt/bluedroid/bta/include/bta/bta_dm_co.h b/components/bt/bluedroid/bta/include/bta/bta_dm_co.h index b9e98b4653..3ef102c5aa 100644 --- a/components/bt/bluedroid/bta/include/bta/bta_dm_co.h +++ b/components/bt/bluedroid/bta/include/bta/bta_dm_co.h @@ -25,6 +25,7 @@ #define BTA_DM_CO_H #include "bta/bta_sys.h" +#include "esp_err.h" /***************************************************************************** ** Function Declarations diff --git a/components/bt/bluedroid/btc/core/btc_ble_storage.c b/components/bt/bluedroid/btc/core/btc_ble_storage.c index 9730dc612c..ecbe709364 100644 --- a/components/bt/bluedroid/btc/core/btc_ble_storage.c +++ b/components/bt/bluedroid/btc/core/btc_ble_storage.c @@ -96,6 +96,7 @@ void btc_storage_save(void) btc_config_unlock(); } +#if (BLE_INCLUDED == TRUE) static bt_status_t _btc_storage_add_ble_bonding_key(bt_bdaddr_t *remote_bd_addr, char *key, uint8_t key_type, @@ -552,6 +553,7 @@ bt_status_t btc_storage_remove_ble_dev_type(bt_bdaddr_t *remote_bd_addr, bool fl return ret; } +#endif ///BLE_INCLUDED == TRUE static bt_status_t _btc_storage_set_ble_dev_auth_mode(bt_bdaddr_t *remote_bd_addr, uint8_t auth_mode, bool flush) { @@ -725,6 +727,7 @@ bt_status_t btc_storage_get_remote_addr_type(bt_bdaddr_t *remote_bd_addr, return ret; } +#if (BLE_INCLUDED == TRUE) static void _btc_read_le_key(const uint8_t key_type, const size_t key_len, bt_bdaddr_t bd_addr, const uint8_t addr_type, const bool add_key, bool *device_added, bool *key_found) { @@ -926,5 +929,6 @@ int btc_storage_get_num_ble_bond_devices(void) return num_dev; } +#endif ///BLE_INCLUDED == TRUE #endif ///SMP_INCLUDED == TRUE diff --git a/components/bt/bluedroid/btc/core/btc_dm.c b/components/bt/bluedroid/btc/core/btc_dm.c index ecc8f383a6..011d1ff93d 100644 --- a/components/bt/bluedroid/btc/core/btc_dm.c +++ b/components/bt/bluedroid/btc/core/btc_dm.c @@ -129,6 +129,7 @@ static void btc_disable_bluetooth_evt(void) } #if (SMP_INCLUDED == TRUE) +#if (BLE_INCLUDED == TRUE) void btc_dm_load_ble_local_keys(void) { memset(&btc_dm_cb.ble_local_key_cb, 0, sizeof(btc_dm_local_key_cb_t)); @@ -296,6 +297,7 @@ static void btc_dm_ble_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl) return; } +#endif ///BLE_INCLUDED == TRUE #endif ///SMP_INCLUDED == TRUE static void btc_dm_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl) @@ -569,8 +571,10 @@ void btc_dm_sec_cb_handler(btc_msg_t *msg) btc_clear_services_mask(); #if (SMP_INCLUDED == TRUE) btc_storage_load_bonded_devices(); +#if (BLE_INCLUDED == TRUE) //load the bonding device to the btm layer btc_storage_load_bonded_ble_devices(); +#endif ///BLE_INCLUDED == TRUE #endif ///SMP_INCLUDED == TRUE /* Set initial device name, it can be overwritten later */ @@ -633,6 +637,7 @@ void btc_dm_sec_cb_handler(btc_msg_t *msg) #endif /* #if (SMP_INCLUDED == TRUE) */ break; } +#if (BLE_INCLUDED == TRUE) case BTA_DM_BLE_DEV_UNPAIRED_EVT: { #if (SMP_INCLUDED == TRUE) bt_bdaddr_t bd_addr; @@ -654,6 +659,7 @@ void btc_dm_sec_cb_handler(btc_msg_t *msg) #endif /* #if (SMP_INCLUDED == TRUE) */ break; } +#endif ///BLE_INCLUDED == TRUE case BTA_DM_BUSY_LEVEL_EVT: #if (BTC_GAP_BT_INCLUDED == TRUE) { @@ -668,7 +674,7 @@ void btc_dm_sec_cb_handler(btc_msg_t *msg) case BTA_DM_HW_ERROR_EVT: BTC_TRACE_DEBUG( "btc_dm_sec_cback : unhandled event (%d)\n", msg->act ); break; -#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE) && (SMP_INCLUDED == TRUE)) +#if ((BLE_INCLUDED == TRUE) && (SMP_INCLUDED == TRUE)) case BTA_DM_BLE_AUTH_CMPL_EVT: { rsp_app = true; ble_msg.act = ESP_GAP_BLE_AUTH_CMPL_EVT; diff --git a/components/bt/bluedroid/btc/core/btc_main.c b/components/bt/bluedroid/btc/core/btc_main.c index 75a2cd45cf..c91aedfb18 100644 --- a/components/bt/bluedroid/btc/core/btc_main.c +++ b/components/bt/bluedroid/btc/core/btc_main.c @@ -64,15 +64,20 @@ static void btc_init_bluetooth(void) bte_main_boot_entry(btc_init_callback); #if (SMP_INCLUDED) btc_config_init(); + +#if (BLE_INCLUDED == TRUE) //load the ble local key which has been stored in the flash btc_dm_load_ble_local_keys(); +#endif ///BLE_INCLUDED == TRUE #endif /* #if (SMP_INCLUDED) */ } static void btc_deinit_bluetooth(void) { +#if (BLE_INCLUDED == TRUE) btc_gap_ble_deinit(); +#endif ///BLE_INCLUDED == TRUE bta_dm_sm_deinit(); #if (GATTC_INCLUDED) bta_gattc_deinit(); diff --git a/components/bt/bluedroid/btc/core/btc_task.c b/components/bt/bluedroid/btc/core/btc_task.c index 72866dc3c5..911f1941b6 100644 --- a/components/bt/bluedroid/btc/core/btc_task.c +++ b/components/bt/bluedroid/btc/core/btc_task.c @@ -69,7 +69,11 @@ static const btc_func_t profile_tab[BTC_PID_NUM] = { #if (GATTS_INCLUDED == TRUE || GATTC_INCLUDED == TRUE) [BTC_PID_GATT_COMMON] = {btc_gatt_com_call_handler, NULL }, #endif //GATTC_INCLUDED == TRUE || GATTS_INCLUDED == TRUE +#if (BLE_INCLUDED == TRUE) [BTC_PID_GAP_BLE] = {btc_gap_ble_call_handler, btc_gap_ble_cb_handler }, +#else + [BTC_PID_GAP_BLE] = {NULL, NULL}, +#endif ///BLE_INCLUDED == TRUE [BTC_PID_BLE_HID] = {NULL, NULL}, [BTC_PID_SPPLIKE] = {NULL, NULL}, #if (GATTS_INCLUDED == TRUE) @@ -183,6 +187,7 @@ static bt_status_t btc_init_mem(void) { } memset((void *)btc_profile_cb_tab, 0, sizeof(void *) * BTC_PID_NUM); +#if (BLE_INCLUDED == TRUE) if ((gl_bta_adv_data_ptr = (tBTA_BLE_ADV_DATA *)osi_malloc(sizeof(tBTA_BLE_ADV_DATA))) == NULL) { return BT_STATUS_NOMEM; } @@ -192,6 +197,7 @@ static bt_status_t btc_init_mem(void) { return BT_STATUS_NOMEM; } memset((void *)gl_bta_scan_rsp_data_ptr, 0, sizeof(tBTA_BLE_ADV_DATA)); +#endif ///BLE_INCLUDED == TRUE #if GATTS_INCLUDED == TRUE && GATT_DYNAMIC_MEMORY == TRUE if ((btc_creat_tab_env_ptr = (esp_btc_creat_tab_t *)osi_malloc(sizeof(esp_btc_creat_tab_t))) == NULL) { @@ -273,7 +279,10 @@ int btc_init(void) } #endif +#if (BLE_INCLUDED == TRUE) btc_gap_callback_init(); +#endif ///BLE_INCLUDED == TRUE + #if SCAN_QUEUE_CONGEST_CHECK btc_adv_list_init(); #endif diff --git a/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c b/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c index be270a430c..3355a5924b 100644 --- a/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c +++ b/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c @@ -31,6 +31,7 @@ #include "osi/mutex.h" #include "esp_bt.h" +#if (BLE_INCLUDED == TRUE) #if BTC_DYNAMIC_MENDRY == FALSE static tBTA_BLE_ADV_DATA gl_bta_adv_data; static tBTA_BLE_ADV_DATA gl_bta_scan_rsp_data; @@ -1372,3 +1373,4 @@ void btc_adv_list_unlock(void) osi_mutex_unlock(&adv_list_lock); } #endif +#endif ///BLE_INCLUDED == TRUE \ No newline at end of file diff --git a/components/bt/bluedroid/common/include/common/bt_target.h b/components/bt/bluedroid/common/include/common/bt_target.h index c8f15e8694..6adf32a9f5 100644 --- a/components/bt/bluedroid/common/include/common/bt_target.h +++ b/components/bt/bluedroid/common/include/common/bt_target.h @@ -119,6 +119,12 @@ ** BLE features ** ******************************************************************************/ +#if (UC_BT_BLE_ENABLED ==TRUE) +#define BLE_INCLUDED TRUE +#else +#define BLE_INCLUDED FALSE +#endif /* UC_BT_BLE_ENABLED */ + #if (UC_BT_GATTS_ENABLE) #define GATTS_INCLUDED TRUE #else @@ -139,8 +145,12 @@ #if (UC_BT_SMP_ENABLE) #define SMP_INCLUDED TRUE +#if (BLE_INCLUDED == TRUE) #define BLE_PRIVACY_SPT TRUE #else +#define BLE_PRIVACY_SPT FALSE +#endif /*BLE_INCLUDED*/ +#else #define SMP_INCLUDED FALSE #define BLE_PRIVACY_SPT FALSE #endif /* UC_BT_SMP_ENABLE */ @@ -1024,7 +1034,7 @@ ******************************************************************************/ #ifndef BLE_INCLUDED -#define BLE_INCLUDED TRUE +#define BLE_INCLUDED FALSE #endif #ifndef BLE_ANDROID_CONTROLLER_SCAN_FILTER @@ -1181,12 +1191,6 @@ #endif #endif - -#if SMP_INCLUDED == TRUE && BLE_INCLUDED == FALSE -#error "can't have SMP without BLE" -#endif - - /****************************************************************************** ** ** SMP @@ -1200,10 +1204,6 @@ #endif #endif -#if SMP_INCLUDED == TRUE && BLE_INCLUDED == FALSE -#error "can't have SMP without BLE" -#endif - #ifndef SMP_DEBUG #define SMP_DEBUG FALSE #endif diff --git a/components/bt/bluedroid/common/include/common/bt_user_config.h b/components/bt/bluedroid/common/include/common/bt_user_config.h index 10568fbd07..5fdc1c2183 100644 --- a/components/bt/bluedroid/common/include/common/bt_user_config.h +++ b/components/bt/bluedroid/common/include/common/bt_user_config.h @@ -86,6 +86,12 @@ #define UC_BT_SSP_ENABLED CONFIG_BT_SSP_ENABLED #else #define UC_BT_SSP_ENABLED FALSE + +//BLE +#ifdef CONFIG_BT_BLE_ENABLED +#define UC_BT_BLE_ENABLED CONFIG_BT_BLE_ENABLED +#else +#define UC_BT_BLE_ENABLED FALSE #endif //GATTS diff --git a/components/bt/bluedroid/stack/btm/btm_acl.c b/components/bt/bluedroid/stack/btm/btm_acl.c index e42724f235..6f7ce092a6 100644 --- a/components/bt/bluedroid/stack/btm/btm_acl.c +++ b/components/bt/bluedroid/stack/btm/btm_acl.c @@ -2038,6 +2038,8 @@ tBTM_STATUS BTM_ReadTxPower (BD_ADDR remote_bda, tBT_TRANSPORT transport, tBTM_C /* If here, no BD Addr found */ return (BTM_UNKNOWN_ADDR); } + +#if (BLE_INCLUDED == TRUE) tBTM_STATUS BTM_BleReadAdvTxPower(tBTM_CMPL_CB *p_cb) { BOOLEAN ret; @@ -2074,6 +2076,7 @@ void BTM_BleGetWhiteListSize(uint16_t *length) *length = p_cb->white_list_avail_size; return; } +#endif ///BLE_INCLUDED == TRUE /******************************************************************************* ** diff --git a/components/bt/bluedroid/stack/btm/btm_ble.c b/components/bt/bluedroid/stack/btm/btm_ble.c index 2b62cde415..78accb1a4c 100644 --- a/components/bt/bluedroid/stack/btm/btm_ble.c +++ b/components/bt/bluedroid/stack/btm/btm_ble.c @@ -24,8 +24,6 @@ ******************************************************************************/ #include "common/bt_target.h" -#if BLE_INCLUDED == TRUE - #include #include "stack/bt_types.h" @@ -41,7 +39,7 @@ //#define LOG_TAG "bt_btm_ble" //#include "osi/include/log.h" - +#if BLE_INCLUDED == TRUE #if SMP_INCLUDED == TRUE // The temp variable to pass parameter between functions when in the connected event callback. static BOOLEAN temp_enhanced = FALSE; @@ -667,7 +665,7 @@ void BTM_ReadDevInfo (BD_ADDR remote_bda, tBT_DEVICE_TYPE *p_dev_type, tBLE_ADDR BTM_TRACE_DEBUG ("btm_find_dev_type - device_type = %d addr_type = %d", *p_dev_type , *p_addr_type); } - +#endif ///BLE_INCLUDED == TRUE /******************************************************************************* ** @@ -703,7 +701,7 @@ BOOLEAN BTM_ReadConnectedTransportAddress(BD_ADDR remote_bda, tBT_TRANSPORT tran } return FALSE; } - +#if (BLE_INCLUDED == TRUE) if (transport == BT_TRANSPORT_LE) { memcpy(remote_bda, p_dev_rec->ble.pseudo_addr, BD_ADDR_LEN); if (btm_bda_to_acl(p_dev_rec->ble.pseudo_addr, transport) != NULL) { @@ -712,10 +710,11 @@ BOOLEAN BTM_ReadConnectedTransportAddress(BD_ADDR remote_bda, tBT_TRANSPORT tran return FALSE; } } - +#endif ///BLE_INCLUDED == TRUE return FALSE; } +#if (BLE_INCLUDED == TRUE) /******************************************************************************* ** ** Function BTM_BleReceiverTest @@ -1104,6 +1103,7 @@ void btm_ble_increment_sign_ctr(BD_ADDR bd_addr, BOOLEAN is_local ) } } #endif ///SMP_INCLUDED == TRUE +#endif ///BLE_INCLUDED == TRUE /******************************************************************************* ** @@ -1116,6 +1116,7 @@ void btm_ble_increment_sign_ctr(BD_ADDR bd_addr, BOOLEAN is_local ) ** *******************************************************************************/ #if (SMP_INCLUDED == TRUE) +#if (BLE_INCLUDED == TRUE) BOOLEAN btm_ble_get_enc_key_type(BD_ADDR bd_addr, UINT8 *p_key_types) { tBTM_SEC_DEV_REC *p_dev_rec; @@ -1160,7 +1161,6 @@ BOOLEAN btm_get_local_div (BD_ADDR bd_addr, UINT16 *p_div) return status; } - /******************************************************************************* ** ** Function btm_sec_save_le_key @@ -1420,9 +1420,10 @@ void btm_ble_link_sec_check(BD_ADDR bd_addr, tBTM_LE_AUTH_REQ auth_req, tBTM_BLE } +#endif ///BLE_INCLUDED == TRUE #endif ///SMP_INCLUDED == TRUE - +#if (BLE_INCLUDED == TRUE) /******************************************************************************* ** ** Function btm_ble_set_encryption @@ -2113,10 +2114,9 @@ UINT8 btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data) } #endif - BTM_TRACE_DEBUG ("btm_cb pairing_state=%x pairing_flags=%x pin_code_len=%x", + BTM_TRACE_DEBUG ("btm_cb pairing_state=%x pairing_flags=%x", btm_cb.pairing_state, - btm_cb.pairing_flags, - btm_cb.pin_code_len ); + btm_cb.pairing_flags); BTM_TRACE_DEBUG ("btm_cb.pairing_bda %02x:%02x:%02x:%02x:%02x:%02x", btm_cb.pairing_bda[0], btm_cb.pairing_bda[1], btm_cb.pairing_bda[2], btm_cb.pairing_bda[3], btm_cb.pairing_bda[4], btm_cb.pairing_bda[5]); @@ -2737,7 +2737,7 @@ void btm_ble_set_keep_rfu_in_auth_req(BOOLEAN keep_rfu) ** Function btm_get_current_conn_params ** ** Description This function is called to get current connection parameters -** information of the device +** information of the device ** ** Returns TRUE if the information is geted, else FALSE ** @@ -2758,7 +2758,7 @@ BOOLEAN btm_get_current_conn_params(BD_ADDR bda, UINT16 *interval, UINT16 *laten return TRUE; } BTM_TRACE_WARNING("%s Device is not connected", __func__); - + return FALSE; } diff --git a/components/bt/bluedroid/stack/btm/btm_devctl.c b/components/bt/bluedroid/stack/btm/btm_devctl.c index dfd2c3bf60..23be3eb303 100644 --- a/components/bt/bluedroid/stack/btm/btm_devctl.c +++ b/components/bt/bluedroid/stack/btm/btm_devctl.c @@ -190,9 +190,9 @@ static void reset_complete(void) l2c_link_processs_ble_num_bufs(controller->get_acl_buffer_count_ble()); } #endif -#if (SMP_INCLUDED == TRUE) +#if (SMP_INCLUDED == TRUE && CLASSIC_BT_INCLUDED == TRUE) BTM_SetPinType (btm_cb.cfg.pin_type, btm_cb.cfg.pin_code, btm_cb.cfg.pin_code_len); -#endif ///SMP_INCLUDED == TRUE +#endif ///SMP_INCLUDED == TRUE && CLASSIC_BT_INCLUDED == TRUE for (int i = 0; i <= controller->get_last_features_classic_index(); i++) { btm_decode_ext_features_page(i, controller->get_features_classic(i)->as_array); } diff --git a/components/bt/bluedroid/stack/btm/btm_sec.c b/components/bt/bluedroid/stack/btm/btm_sec.c index 0a61eac6fd..1d7b3276c6 100644 --- a/components/bt/bluedroid/stack/btm/btm_sec.c +++ b/components/bt/bluedroid/stack/btm/btm_sec.c @@ -35,6 +35,7 @@ #include "l2c_int.h" #include "osi/fixed_queue.h" #include "osi/alarm.h" +#include "stack/btm_ble_api.h" #if (BT_USE_TRACES == TRUE && BT_TRACE_VERBOSE == FALSE) /* needed for sprintf() */ @@ -368,6 +369,7 @@ BOOLEAN BTM_GetSecurityFlagsByTransport (BD_ADDR bd_addr, UINT8 *p_sec_flags, return (FALSE); } +#if (CLASSIC_BT_INCLUDED == TRUE) /******************************************************************************* ** ** Function BTM_SetPinType @@ -392,6 +394,7 @@ void BTM_SetPinType (UINT8 pin_type, PIN_CODE pin_code, UINT8 pin_code_len) btm_cb.cfg.pin_code_len = pin_code_len; memcpy (btm_cb.cfg.pin_code, pin_code, pin_code_len); } +#endif ///CLASSIC_BT_INCLUDED == TRUE /******************************************************************************* ** @@ -824,6 +827,7 @@ void btm_sec_clr_temp_auth_service (BD_ADDR bda) ** *******************************************************************************/ #if (SMP_INCLUDED == TRUE) +#if (CLASSIC_BT_INCLUDED == TRUE) void BTM_PINCodeReply (BD_ADDR bd_addr, UINT8 res, UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[]) { tBTM_SEC_DEV_REC *p_dev_rec; @@ -930,6 +934,7 @@ void BTM_PINCodeReply (BD_ADDR bd_addr, UINT8 res, UINT8 pin_len, UINT8 *p_pin, #endif btsnd_hcic_pin_code_req_reply (bd_addr, pin_len, p_pin); } +#endif ///CLASSIC_BT_INCLUDED == TRUE #endif ///SMP_INCLUDED == TRUE @@ -995,12 +1000,14 @@ tBTM_STATUS btm_sec_bond_by_transport (BD_ADDR bd_addr, tBT_TRANSPORT transport, return (BTM_NO_RESOURCES); } +#if (CLASSIC_BT_INCLUDED == TRUE) /* Save the PIN code if we got a valid one */ if (p_pin && (pin_len <= PIN_CODE_LEN) && (pin_len != 0)) { btm_cb.pin_code_len = pin_len; p_dev_rec->pin_code_length = pin_len; memcpy (btm_cb.pin_code, p_pin, PIN_CODE_LEN); } +#endif ///CLASSIC_BT_INCLUDED == TRUE memcpy (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN); @@ -1034,6 +1041,8 @@ tBTM_STATUS btm_sec_bond_by_transport (BD_ADDR bd_addr, tBT_TRANSPORT transport, BTM_TRACE_DEBUG ("after update sec_flags=0x%x\n", p_dev_rec->sec_flags); + +#if (CLASSIC_BT_INCLUDED == TRUE) if (!controller_get_interface()->supports_simple_pairing()) { /* The special case when we authenticate keyboard. Set pin type to fixed */ /* It would be probably better to do it from the application, but it is */ @@ -1045,6 +1054,7 @@ tBTM_STATUS btm_sec_bond_by_transport (BD_ADDR bd_addr, tBT_TRANSPORT transport, btsnd_hcic_write_pin_type (HCI_PIN_TYPE_FIXED); } } +#endif ///CLASSIC_BT_INCLUDED == TRUE for (ii = 0; ii <= HCI_EXT_FEATURES_PAGE_MAX; ii++) { #if (!CONFIG_BT_STACK_NO_LOG) @@ -1133,6 +1143,7 @@ tBTM_STATUS btm_sec_bond_by_transport (BD_ADDR bd_addr, tBT_TRANSPORT transport, tBTM_STATUS BTM_SecBondByTransport (BD_ADDR bd_addr, tBT_TRANSPORT transport, UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[]) { +#if (BLE_INCLUDED == TRUE) tBT_DEVICE_TYPE dev_type; tBLE_ADDR_TYPE addr_type; @@ -1142,6 +1153,8 @@ tBTM_STATUS BTM_SecBondByTransport (BD_ADDR bd_addr, tBT_TRANSPORT transport, (transport == BT_TRANSPORT_BR_EDR && (dev_type & BT_DEVICE_TYPE_BREDR) == 0)) { return BTM_ILLEGAL_ACTION; } +#endif ///BLE_INCLUDED == TRUE + return btm_sec_bond_by_transport(bd_addr, transport, pin_len, p_pin, trusted_mask); } #endif ///SMP_INCLUDED == TRUE @@ -1165,9 +1178,11 @@ tBTM_STATUS BTM_SecBondByTransport (BD_ADDR bd_addr, tBT_TRANSPORT transport, tBTM_STATUS BTM_SecBond (BD_ADDR bd_addr, UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[]) { tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; +#if (BLE_INCLUDED == TRUE) if (BTM_UseLeLink(bd_addr)) { transport = BT_TRANSPORT_LE; } +#endif ///BLE_INCLUDED == TRUE return btm_sec_bond_by_transport(bd_addr, transport, pin_len, p_pin, trusted_mask); } /******************************************************************************* @@ -4117,8 +4132,10 @@ void btm_sec_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable) if (p_dev_rec->no_smp_on_br) { BTM_TRACE_DEBUG ("%s NO SM over BR/EDR\n", __func__); } else { +#if (CLASSIC_BT_INCLUDED == TRUE) BTM_TRACE_DEBUG ("%s start SM over BR/EDR\n", __func__); SMP_BR_PairWith(p_dev_rec->bd_addr); +#endif ///CLASSIC_BT_INCLUDED == TRUE } } } else { @@ -4924,6 +4941,7 @@ static void btm_sec_pairing_timeout (TIMER_LIST_ENT *p_tle) } } +#if (CLASSIC_BT_INCLUDED == TRUE) /******************************************************************************* ** ** Function btm_sec_pin_code_request @@ -5061,6 +5079,7 @@ void btm_sec_pin_code_request (UINT8 *p_bda) } return; } +#endif ///CLASSIC_BT_INCLUDED == TRUE #endif ///SMP_INCLUDED == TRUE @@ -5589,10 +5608,12 @@ static void btm_restore_mode(void) btsnd_hcic_write_auth_enable ((UINT8)(btm_cb.security_mode == BTM_SEC_MODE_LINK)); } +#if (CLASSIC_BT_INCLUDED == TRUE) if (btm_cb.pin_type_changed) { btm_cb.pin_type_changed = FALSE; btsnd_hcic_write_pin_type (btm_cb.cfg.pin_type); } +#endif ///CLASSIC_BT_INCLUDED == TRUE } #endif ///SMP_INCLUDED == TRUE @@ -5644,7 +5665,9 @@ static void btm_sec_change_pairing_state (tBTM_PAIRING_STATE new_state) btu_stop_timer (&btm_cb.pairing_tle); btm_cb.pairing_flags = 0; +#if (CLASSIC_BT_INCLUDED == TRUE) btm_cb.pin_code_len = 0; +#endif ///CLASSIC_BT_INCLUDED == TRUE /* Make sure the the lcb shows we are not bonding */ l2cu_update_lcb_4_bonding (btm_cb.pairing_bda, FALSE); @@ -5770,9 +5793,11 @@ static BOOLEAN btm_sec_queue_mx_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN } static BOOLEAN btm_sec_check_prefetch_pin (tBTM_SEC_DEV_REC *p_dev_rec) { + BOOLEAN rv = FALSE; +#if (CLASSIC_BT_INCLUDED == TRUE) UINT8 major = (UINT8)(p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK); UINT8 minor = (UINT8)(p_dev_rec->dev_class[2] & BTM_COD_MINOR_CLASS_MASK); - BOOLEAN rv = FALSE; + rv = TRUE; if ((major == BTM_COD_MAJOR_AUDIO) && ((minor == BTM_COD_MINOR_CONFM_HANDSFREE) || (minor == BTM_COD_MINOR_CAR_AUDIO)) ) { @@ -5810,7 +5835,8 @@ static BOOLEAN btm_sec_check_prefetch_pin (tBTM_SEC_DEV_REC *p_dev_rec) rv = TRUE; } - +#endif ///CLASSIC_BT_INCLUDED == TRUE +# return rv; } @@ -5993,6 +6019,7 @@ static UINT16 btm_sec_set_serv_level4_flags(UINT16 cur_security, BOOLEAN is_orig return cur_security | sec_level4_flags; } #endif ///SMP_INCLUDED == TRUE + /******************************************************************************* ** ** Function btm_sec_clear_ble_keys @@ -6004,6 +6031,7 @@ static UINT16 btm_sec_set_serv_level4_flags(UINT16 cur_security, BOOLEAN is_orig ** Returns void ** *******************************************************************************/ +#if (BLE_INCLUDED == TRUE) void btm_sec_clear_ble_keys (tBTM_SEC_DEV_REC *p_dev_rec) { @@ -6017,7 +6045,7 @@ void btm_sec_clear_ble_keys (tBTM_SEC_DEV_REC *p_dev_rec) #endif #endif } - +#endif ///BLE_INCLUDED == TRUE /******************************************************************************* ** ** Function btm_sec_is_a_bonded_dev @@ -6034,7 +6062,7 @@ BOOLEAN btm_sec_is_a_bonded_dev (BD_ADDR bda) BOOLEAN is_bonded = FALSE; if (p_dev_rec && -#if (SMP_INCLUDED == TRUE) +#if (SMP_INCLUDED == TRUE && BLE_INCLUDED == TRUE) ((p_dev_rec->ble.key_type && (p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_KNOWN)) || #else ( @@ -6057,10 +6085,10 @@ BOOLEAN btm_sec_is_a_bonded_dev (BD_ADDR bda) *******************************************************************************/ BOOLEAN btm_sec_is_le_capable_dev (BD_ADDR bda) { - tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda); BOOLEAN le_capable = FALSE; #if (BLE_INCLUDED== TRUE) + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda); if (p_dev_rec && (p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE) { le_capable = TRUE; } @@ -6077,6 +6105,7 @@ BOOLEAN btm_sec_is_le_capable_dev (BD_ADDR bda) ** Returns TRUE - found a bonded device ** *******************************************************************************/ +#if (BLE_INCLUDED == TRUE) BOOLEAN btm_sec_find_bonded_dev (UINT8 start_idx, UINT8 *p_found_idx, tBTM_SEC_DEV_REC **p_rec) { BOOLEAN found = FALSE; @@ -6101,7 +6130,7 @@ BOOLEAN btm_sec_find_bonded_dev (UINT8 start_idx, UINT8 *p_found_idx, tBTM_SEC_D #endif return (found); } - +#endif ///BLE_INCLUDED == TRUE /******************************************************************************* ** ** Function btm_sec_use_smp_br_chnl diff --git a/components/bt/bluedroid/stack/btm/include/btm_int.h b/components/bt/bluedroid/stack/btm/include/btm_int.h index 455ce7ca36..f575d8958a 100644 --- a/components/bt/bluedroid/stack/btm/include/btm_int.h +++ b/components/bt/bluedroid/stack/btm/include/btm_int.h @@ -32,13 +32,14 @@ #include "stack/rfcdefs.h" #include "stack/btm_api.h" +#include "osi/fixed_queue.h" #if (BLE_INCLUDED == TRUE) #include "btm_ble_int.h" +#endif #if (SMP_INCLUDED == TRUE) #include "stack/smp_api.h" #endif -#endif #if BTM_MAX_LOC_BD_NAME_LEN > 0 typedef char tBTM_LOC_BD_NAME[BTM_MAX_LOC_BD_NAME_LEN + 1]; @@ -855,9 +856,12 @@ typedef struct { BOOLEAN pairing_disabled; BOOLEAN connect_only_paired; BOOLEAN security_mode_changed; /* mode changed during bonding */ - BOOLEAN pin_type_changed; /* pin type changed during bonding */ BOOLEAN sec_req_pending; /* TRUE if a request is pending */ +#if (CLASSIC_BT_INCLUDED == TRUE) + BOOLEAN pin_type_changed; /* pin type changed during bonding */ +#endif ///CLASSIC_BT_INCLUDED == TRUE #if (SMP_INCLUDED == TRUE) +#if (CLASSIC_BT_INCLUDED == TRUE) // btla-specific ++ #ifdef PORCHE_PAIRING_CONFLICT UINT8 pin_code_len_saved; /* for legacy devices */ @@ -866,12 +870,14 @@ typedef struct { UINT8 pin_code_len; /* for legacy devices */ PIN_CODE pin_code; /* for legacy devices */ + UINT8 disc_reason; /* for legacy devices */ + UINT16 disc_handle; /* for legacy devices */ +#endif ///CLASSIC_BT_INCLUDED == TRUE tBTM_PAIRING_STATE pairing_state; /* The current pairing state */ UINT8 pairing_flags; /* The current pairing flags */ BD_ADDR pairing_bda; /* The device currently pairing */ TIMER_LIST_ENT pairing_tle; /* Timer for pairing process */ - UINT16 disc_handle; /* for legacy devices */ - UINT8 disc_reason; /* for legacy devices */ + #endif ///SMP_INCLUDED == TRUE #if SMP_INCLUDED == TRUE || CLASSIC_BT_INCLUDED == TRUE tBTM_SEC_SERV_REC sec_serv_rec[BTM_SEC_MAX_SERVICE_RECORDS]; @@ -1122,10 +1128,10 @@ BOOLEAN btm_sec_is_le_capable_dev (BD_ADDR bda); BOOLEAN btm_ble_init_pseudo_addr (tBTM_SEC_DEV_REC *p_dev_rec, BD_ADDR new_pseudo_addr); extern BOOLEAN btm_ble_start_sec_check(BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_originator, tBTM_SEC_CALLBACK *p_callback, void *p_ref_data); -extern tBTM_SEC_SERV_REC *btm_sec_find_first_serv (CONNECTION_TYPE conn_type, UINT16 psm); - #endif /* BLE_INCLUDED */ +extern tBTM_SEC_SERV_REC *btm_sec_find_first_serv (CONNECTION_TYPE conn_type, UINT16 psm); + tINQ_DB_ENT *btm_inq_db_new (BD_ADDR p_bda); #if BTM_OOB_INCLUDED == TRUE diff --git a/components/bt/bluedroid/stack/btu/btu_hcif.c b/components/bt/bluedroid/stack/btu/btu_hcif.c index 7d1ab95f96..5677491c5c 100644 --- a/components/bt/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/bluedroid/stack/btu/btu_hcif.c @@ -1436,6 +1436,7 @@ static void btu_hcif_ssr_evt (UINT8 *p, UINT16 evt_len) #if (SMP_INCLUDED == TRUE) static void btu_hcif_pin_code_request_evt (UINT8 *p) { +#if (CLASSIC_BT_INCLUDED == TRUE) BD_ADDR bda; STREAM_TO_BDADDR (bda, p); @@ -1445,6 +1446,7 @@ static void btu_hcif_pin_code_request_evt (UINT8 *p) l2c_pin_code_request (bda); btm_sec_pin_code_request (bda); +#endif ///CLASSIC_BT_INCLUDED == TRUE } diff --git a/components/bt/bluedroid/stack/include/stack/btm_api.h b/components/bt/bluedroid/stack/include/stack/btm_api.h index bf2b033bc0..b51ecb0069 100644 --- a/components/bt/bluedroid/stack/include/stack/btm_api.h +++ b/components/bt/bluedroid/stack/include/stack/btm_api.h @@ -645,8 +645,8 @@ typedef struct { INT8 rssi; /* Set to BTM_INQ_RES_IGNORE_RSSI if not valid */ UINT32 eir_uuid[BTM_EIR_SERVICE_ARRAY_SIZE]; BOOLEAN eir_complete_list; -#if (BLE_INCLUDED == TRUE) tBT_DEVICE_TYPE device_type; +#if (BLE_INCLUDED == TRUE) UINT8 inq_result_type; UINT8 ble_addr_type; tBTM_BLE_EVT_TYPE ble_evt_type; @@ -1394,12 +1394,12 @@ typedef UINT8 tBTM_SP_EVT; #define BTM_IO_CAP_IO 1 /* DisplayYesNo */ #define BTM_IO_CAP_IN 2 /* KeyboardOnly */ #define BTM_IO_CAP_NONE 3 /* NoInputNoOutput */ -#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE +// #if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE #define BTM_IO_CAP_KBDISP 4 /* Keyboard display */ #define BTM_IO_CAP_MAX 5 -#else -#define BTM_IO_CAP_MAX 4 -#endif +// #else +// #define BTM_IO_CAP_MAX 4 +// #endif typedef UINT8 tBTM_IO_CAP; diff --git a/components/bt/bluedroid/stack/include/stack/l2c_api.h b/components/bt/bluedroid/stack/include/stack/l2c_api.h index 147ed6c74c..33abaec7b3 100644 --- a/components/bt/bluedroid/stack/include/stack/l2c_api.h +++ b/components/bt/bluedroid/stack/include/stack/l2c_api.h @@ -1210,6 +1210,7 @@ extern BOOLEAN L2CA_EnableUpdateBleConnParams (BD_ADDR rem_bda, BOOLEAN enable); ** *******************************************************************************/ extern UINT8 L2CA_GetBleConnRole (BD_ADDR bd_addr); +#endif /* (BLE_INCLUDED == TRUE) */ /******************************************************************************* ** @@ -1228,7 +1229,6 @@ extern UINT16 L2CA_GetDisconnectReason (BD_ADDR remote_bda, tBT_TRANSPORT transp extern BOOLEAN L2CA_CheckIsCongest(UINT16 fixed_cid, UINT16 handle); -#endif /* (BLE_INCLUDED == TRUE) */ #ifdef __cplusplus } diff --git a/components/bt/bluedroid/stack/include/stack/smp_api.h b/components/bt/bluedroid/stack/include/stack/smp_api.h index 390f6209e6..1064237c8d 100644 --- a/components/bt/bluedroid/stack/include/stack/smp_api.h +++ b/components/bt/bluedroid/stack/include/stack/smp_api.h @@ -29,7 +29,7 @@ #define SMP_PIN_CODE_LEN_MAX PIN_CODE_LEN #define SMP_PIN_CODE_LEN_MIN 6 -#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE +// #if SMP_INCLUDED == TRUE /* SMP command code */ #define SMP_OPCODE_PAIRING_REQ 0x01 #define SMP_OPCODE_PAIRING_RSP 0x02 @@ -48,7 +48,7 @@ #define SMP_OPCODE_MAX SMP_OPCODE_PAIR_KEYPR_NOTIF #define SMP_OPCODE_MIN SMP_OPCODE_PAIRING_REQ #define SMP_OPCODE_PAIR_COMMITM 0x0F -#endif +// #endif /* SMP event type */ #define SMP_IO_CAP_REQ_EVT 1 /* IO capability request event */ diff --git a/components/bt/bluedroid/stack/l2cap/l2c_api.c b/components/bt/bluedroid/stack/l2cap/l2c_api.c index 906b961d20..9a50d4ba72 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_api.c +++ b/components/bt/bluedroid/stack/l2cap/l2c_api.c @@ -1301,6 +1301,7 @@ UINT8 L2CA_GetChnlFcrMode (UINT16 lcid) #endif ///CLASSIC_BT_INCLUDED == TRUE +#if (BLE_INCLUDED == TRUE) /******************************************************************************* ** ** Function L2CA_RegisterLECoc @@ -1610,8 +1611,7 @@ BOOLEAN L2CA_GetPeerLECocConfig (UINT16 lcid, tL2CAP_LE_CFG_INFO* peer_cfg) return TRUE; } - - +#endif ///BLE_INCLUDED == TRUE #if (L2CAP_NUM_FIXED_CHNLS > 0) /******************************************************************************* diff --git a/components/bt/bluedroid/stack/l2cap/l2c_ble.c b/components/bt/bluedroid/stack/l2cap/l2c_ble.c index 9a26969fac..b4e347335f 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_ble.c +++ b/components/bt/bluedroid/stack/l2cap/l2c_ble.c @@ -223,28 +223,6 @@ UINT8 L2CA_GetBleConnRole (BD_ADDR bd_addr) return role; } -/******************************************************************************* -** -** Function L2CA_GetDisconnectReason -** -** Description This function returns the disconnect reason code. -** -** Returns disconnect reason -** -*******************************************************************************/ -UINT16 L2CA_GetDisconnectReason (BD_ADDR remote_bda, tBT_TRANSPORT transport) -{ - tL2C_LCB *p_lcb; - UINT16 reason = 0; - - if ((p_lcb = l2cu_find_lcb_by_bd_addr (remote_bda, transport)) != NULL) { - reason = p_lcb->disc_reason; - } - - L2CAP_TRACE_DEBUG ("L2CA_GetDisconnectReason=%d ", reason); - - return reason; -} /******************************************************************************* ** @@ -1491,3 +1469,25 @@ BOOLEAN l2ble_sec_access_req(BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_originator, } #endif /* #if (SMP_INCLUDED == TRUE) */ #endif /* (BLE_INCLUDED == TRUE) */ +/******************************************************************************* +** +** Function L2CA_GetDisconnectReason +** +** Description This function returns the disconnect reason code. +** +** Returns disconnect reason +** +*******************************************************************************/ +UINT16 L2CA_GetDisconnectReason (BD_ADDR remote_bda, tBT_TRANSPORT transport) +{ + tL2C_LCB *p_lcb; + UINT16 reason = 0; + + if ((p_lcb = l2cu_find_lcb_by_bd_addr (remote_bda, transport)) != NULL) { + reason = p_lcb->disc_reason; + } + + L2CAP_TRACE_DEBUG ("L2CA_GetDisconnectReason=%d ", reason); + + return reason; +} \ No newline at end of file diff --git a/components/bt/bluedroid/stack/l2cap/l2c_link.c b/components/bt/bluedroid/stack/l2cap/l2c_link.c index 15de6060b1..1117a0abae 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_link.c +++ b/components/bt/bluedroid/stack/l2cap/l2c_link.c @@ -357,7 +357,9 @@ BOOLEAN l2c_link_hci_disc_comp (UINT16 handle, UINT8 reason) p_lcb = l2cu_find_lcb_by_handle (handle); /* If we don't have one, maybe an SCO link. Send to MM */ if (!p_lcb) { +#if (BLE_INCLUDED == TRUE) BTM_Recovery_Pre_State(); +#endif ///BLE_INCLUDED == TRUE status = FALSE; } else { /* There can be a case when we rejected PIN code authentication */ @@ -1026,8 +1028,10 @@ void l2c_link_check_send_pkts (tL2C_LCB *p_lcb, tL2C_CCB *p_ccb, BT_HDR *p_buf) /* Loop through, starting at the next */ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) { - /* If controller window is full, nothing to do */ +#if (BLE_INCLUDED == TRUE) L2CAP_TRACE_DEBUG("window = %d,robin_unacked = %d,robin_quota=%d",l2cb.controller_le_xmit_window,l2cb.ble_round_robin_unacked,l2cb.ble_round_robin_quota); +#endif ///BLE_INCLUDED == TRUE + /* If controller window is full, nothing to do */ if (((l2cb.controller_xmit_window == 0 || (l2cb.round_robin_unacked >= l2cb.round_robin_quota)) #if (BLE_INCLUDED == TRUE) @@ -1038,7 +1042,7 @@ void l2c_link_check_send_pkts (tL2C_LCB *p_lcb, tL2C_CCB *p_ccb, BT_HDR *p_buf) l2cb.controller_le_xmit_window == 0 ))) #else )) -#endif +#endif ///BLE_INCLUDED == TRUE break; diff --git a/components/bt/bluedroid/stack/l2cap/l2c_main.c b/components/bt/bluedroid/stack/l2cap/l2c_main.c index 45baeaa3b9..e50e59dceb 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_main.c +++ b/components/bt/bluedroid/stack/l2cap/l2c_main.c @@ -295,7 +295,9 @@ void l2c_rcv_acl_data (BT_HDR *p_msg) /* we have received credits more than max coc credits, * so disconnecting the Le Coc Channel */ +#if (BLE_INCLUDED == TRUE) l2cble_send_peer_disc_req (p_ccb); +#endif ///BLE_INCLUDED == TRUE } else { p_ccb->peer_conn_cfg.credits += credit; l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL); @@ -926,6 +928,7 @@ void l2c_process_timeout (TIMER_LIST_ENT *p_tle) l2c_info_timeout((tL2C_LCB *)p_tle->param); break; case BTU_TTYPE_L2CAP_UPDA_CONN_PARAMS: { +#if (BLE_INCLUDED == TRUE) UINT8 status = HCI_ERR_HOST_TIMEOUT; tL2C_LCB *p_lcb = (tL2C_LCB *)p_tle->param; if (p_lcb){ @@ -933,6 +936,7 @@ void l2c_process_timeout (TIMER_LIST_ENT *p_tle) p_lcb->conn_update_mask &= ~L2C_BLE_UPDATE_PARAM_FULL; } l2c_send_update_conn_params_cb(p_lcb, status); +#endif ///BLE_INCLUDED == TRUE break; } } diff --git a/components/bt/bluedroid/stack/l2cap/l2c_utils.c b/components/bt/bluedroid/stack/l2cap/l2c_utils.c index 4768d8808a..92e1eede37 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_utils.c +++ b/components/bt/bluedroid/stack/l2cap/l2c_utils.c @@ -243,6 +243,7 @@ void l2cu_release_lcb (tL2C_LCB *p_lcb) (*p_cb) (L2CAP_PING_RESULT_NO_LINK); } +#if (BLE_INCLUDED == TRUE) /* Check and release all the LE COC connections waiting for security */ if (p_lcb->le_sec_pending_q) { @@ -257,6 +258,7 @@ void l2cu_release_lcb (tL2C_LCB *p_lcb) fixed_queue_free(p_lcb->le_sec_pending_q, NULL); p_lcb->le_sec_pending_q = NULL; } +#endif ///BLE_INCLUDED == TRUE #if (C2H_FLOW_CONTROL_INCLUDED == TRUE) p_lcb->completed_packets = 0; @@ -1765,6 +1767,7 @@ tL2C_RCB *l2cu_allocate_rcb (UINT16 psm) return (NULL); } +#if (BLE_INCLUDED == TRUE) /******************************************************************************* ** ** Function l2cu_allocate_ble_rcb @@ -1796,6 +1799,7 @@ tL2C_RCB *l2cu_allocate_ble_rcb (UINT16 psm) /* If here, no free RCB found */ return (NULL); } +#endif ///BLE_INCLUDED == TRUE /******************************************************************************* ** @@ -1867,6 +1871,7 @@ tL2C_RCB *l2cu_find_rcb_by_psm (UINT16 psm) return (NULL); } +#if (BLE_INCLUDED == TRUE) /******************************************************************************* ** ** Function l2cu_find_ble_rcb_by_psm @@ -1892,7 +1897,7 @@ tL2C_RCB *l2cu_find_ble_rcb_by_psm (UINT16 psm) /* If here, no match found */ return (NULL); } - +#endif ///BLE_INCLUDED == TRUE /******************************************************************************* diff --git a/components/bt/bluedroid/stack/smp/include/smp_int.h b/components/bt/bluedroid/stack/smp/include/smp_int.h index cf3683c07c..d8fb55c381 100644 --- a/components/bt/bluedroid/stack/smp/include/smp_int.h +++ b/components/bt/bluedroid/stack/smp/include/smp_int.h @@ -24,7 +24,7 @@ #ifndef SMP_INT_H #define SMP_INT_H -#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE) +// #if (SMP_INCLUDED == TRUE) #include "stack/btu.h" #include "stack/btm_ble_api.h" @@ -537,6 +537,6 @@ extern BOOLEAN aes_cipher_msg_auth_code(BT_OCTET16 key, UINT8 *input, UINT16 len UINT16 tlen, UINT8 *p_signature); extern void print128(BT_OCTET16 x, const UINT8 *key_name); -#endif ///BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE +// #endif ///BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE #endif /* SMP_INT_H */ diff --git a/components/bt/bluedroid/stack/smp/smp_act.c b/components/bt/bluedroid/stack/smp/smp_act.c index d9f3369500..487dadf62c 100644 --- a/components/bt/bluedroid/stack/smp/smp_act.c +++ b/components/bt/bluedroid/stack/smp/smp_act.c @@ -46,10 +46,17 @@ const UINT8 smp_association_table[2][SMP_IO_CAP_MAX][SMP_IO_CAP_MAX] = { #define SMP_KEY_DIST_TYPE_MAX 4 const tSMP_ACT smp_distribute_act [] = { +#if (BLE_INCLUDED == TRUE) smp_generate_ltk, smp_send_id_info, smp_generate_csrk, smp_set_derive_link_key +#else + NULL, + NULL, + NULL, + NULL +#endif ///BLE_INCLUDED == TRUE }; extern UINT8 bta_dm_co_ble_get_accept_auth_enable(void); @@ -191,7 +198,7 @@ void smp_send_app_cback(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) smp_sm_event(p_cb, SMP_IO_RSP_EVT, NULL); break; - +#if (CLASSIC_BT_INCLUDED == TRUE) case SMP_BR_KEYS_REQ_EVT: p_cb->loc_enc_size = cb_data.io_req.max_key_size; p_cb->local_i_key = cb_data.io_req.init_keys; @@ -206,6 +213,7 @@ void smp_send_app_cback(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) smp_br_state_machine_event(p_cb, SMP_BR_KEYS_RSP_EVT, NULL); break; +#endif ///CLASSIC_BT_INCLUDED == TRUE } } } @@ -241,13 +249,15 @@ void smp_send_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) *******************************************************************************/ void smp_send_pair_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) { - tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_cb->pairing_bda); SMP_TRACE_DEBUG("%s\n", __func__); +#if (BLE_INCLUDED == TRUE) + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_cb->pairing_bda); /* erase all keys when master sends pairing req*/ if (p_dev_rec) { btm_sec_clear_ble_keys(p_dev_rec); } +#endif ///BLE_INCLUDED == TRUE /* do not manipulate the key, let app decide, leave out to BTM to mandate key distribution for bonding case */ smp_send_cmd(SMP_OPCODE_PAIRING_REQ, p_cb); @@ -261,6 +271,7 @@ void smp_send_pair_rsp(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) { SMP_TRACE_DEBUG("%s\n", __func__); +#if (BLE_INCLUDED == TRUE) p_cb->local_i_key &= p_cb->peer_i_key; p_cb->local_r_key &= p_cb->peer_r_key; @@ -271,6 +282,7 @@ void smp_send_pair_rsp(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) smp_decide_association_model(p_cb, NULL); } } +#endif ///BLE_INCLUDED == TRUE } /******************************************************************************* @@ -365,6 +377,7 @@ void smp_send_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) le_key.key_size = p_cb->loc_enc_size; le_key.sec_level = p_cb->sec_level; +#if (BLE_INCLUDED == TRUE) if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) { btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LENC, (tBTM_LE_KEY_VALUE *)&le_key, TRUE); @@ -373,6 +386,7 @@ void smp_send_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) SMP_TRACE_DEBUG ("%s\n", __func__); smp_key_distribution(p_cb, NULL); +#endif ///BLE_INCLUDED == TRUE } /******************************************************************************* @@ -381,21 +395,24 @@ void smp_send_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) *******************************************************************************/ void smp_send_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) { - tBTM_LE_KEY_VALUE le_key; SMP_TRACE_DEBUG("%s\n", __func__); smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ID, FALSE); smp_send_cmd(SMP_OPCODE_IDENTITY_INFO, p_cb); smp_send_cmd(SMP_OPCODE_ID_ADDR, p_cb); +#if (BLE_INCLUDED == TRUE) + tBTM_LE_KEY_VALUE le_key; if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) { btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LID, &le_key, TRUE); } +#endif ///BLE_INCLUDED == TRUE smp_key_distribution_by_transport(p_cb, NULL); } +#if (BLE_INCLUDED == TRUE) /******************************************************************************* ** Function smp_send_csrk_info ** Description send CSRK command. @@ -441,7 +458,6 @@ void smp_proc_sec_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) SMP_TRACE_DEBUG("%s auth_req=0x%x", __func__, auth_req); p_cb->cb_evt = 0; - btm_ble_link_sec_check(p_cb->pairing_bda, auth_req, &sec_req_act); SMP_TRACE_DEBUG("%s sec_req_act=0x%x", __func__, sec_req_act); @@ -478,6 +494,7 @@ void smp_proc_sec_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) break; } } +#endif ///BLE_INCLUDED == TRUE /******************************************************************************* ** Function smp_proc_sec_grant @@ -532,6 +549,7 @@ uint16_t smp_get_auth_mode (tSMP_ASSO_MODEL model) return auth; } +#if (BLE_INCLUDED == TRUE) /******************************************************************************* ** Function smp_proc_pair_cmd ** Description Process the SMP pairing request/response from peer device @@ -652,6 +670,7 @@ void smp_proc_pair_cmd(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) } } } +#endif ///BLE_INCLUDED == TRUE /******************************************************************************* ** Function smp_proc_confirm @@ -823,6 +842,7 @@ void smp_process_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) p_cb->cb_evt = SMP_PEER_KEYPR_NOT_EVT; } +#if (CLASSIC_BT_INCLUDED == TRUE) /******************************************************************************* ** Function smp_br_process_pairing_command ** Description Process the SMP pairing request/response from peer device via @@ -842,10 +862,12 @@ void smp_br_process_pairing_command(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) return; } +#if (BLE_INCLUDED == TRUE) /* erase all keys if it is slave proc pairing req*/ if (p_dev_rec && (p_cb->role == HCI_ROLE_SLAVE)) { btm_sec_clear_ble_keys(p_dev_rec); } +#endif ///BLE_INCLUDED == TRUE p_cb->flags |= SMP_PAIR_FLAG_ENC_AFTER_PAIR; @@ -966,7 +988,9 @@ void smp_br_select_next_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) } } } +#endif ///CLASSIC_BT_INCLUDED == TRUE +#if (BLE_INCLUDED == TRUE) /******************************************************************************* ** Function smp_proc_enc_info ** Description process encryption information from peer device @@ -980,6 +1004,8 @@ void smp_proc_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) smp_key_distribution(p_cb, NULL); } +#endif ///BLE_INCLUDED == TRUE + /******************************************************************************* ** Function smp_proc_master_id ** Description process master ID from slave device @@ -1001,6 +1027,7 @@ void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) le_key.sec_level = p_cb->sec_level; le_key.key_size = p_cb->loc_enc_size; +#if (BLE_INCLUDED == TRUE) if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) { btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PENC, @@ -1008,6 +1035,7 @@ void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) } smp_key_distribution(p_cb, NULL); +#endif ///BLE_INCLUDED == TRUE } /******************************************************************************* @@ -1044,11 +1072,14 @@ void smp_proc_id_addr(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) p_cb->id_addr_type = pid_key.addr_type; memcpy(p_cb->id_addr, pid_key.static_addr, BD_ADDR_LEN); +#if (BLE_INCLUDED == TRUE) /* store the ID key from peer device */ if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) { btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PID, (tBTM_LE_KEY_VALUE *)&pid_key, TRUE); } +#endif ///BLE_INCLUDED == TRUE + smp_key_distribution_by_transport(p_cb, NULL); } @@ -1058,6 +1089,7 @@ void smp_proc_id_addr(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) *******************************************************************************/ void smp_proc_srk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) { +#if (BLE_INCLUDED == TRUE) tBTM_LE_PCSRK_KEYS le_key; SMP_TRACE_DEBUG("%s", __func__); @@ -1073,6 +1105,8 @@ void smp_proc_srk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) BTM_LE_KEY_PCSRK, (tBTM_LE_KEY_VALUE *)&le_key, TRUE); } + +#endif ///BLE_INCLUDED == TRUE smp_key_distribution_by_transport(p_cb, NULL); } @@ -1107,6 +1141,7 @@ void smp_proc_compare(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) } } +#if (BLE_INCLUDED == TRUE) /******************************************************************************* ** Function smp_proc_sl_key ** Description process key ready events. @@ -1147,6 +1182,7 @@ void smp_start_enc(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); } } +#endif ///BLE_INCLUDED == TRUE /******************************************************************************* ** Function smp_proc_discard @@ -1246,7 +1282,7 @@ void smp_key_pick_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) while (i < SMP_KEY_DIST_TYPE_MAX) { SMP_TRACE_DEBUG("key to send = %02x, i = %d\n", key_to_dist, i); - if (key_to_dist & (1 << i)) { + if (key_to_dist & (1 << i) && smp_distribute_act[i] != NULL) { SMP_TRACE_DEBUG("smp_distribute_act[%d]\n", i); (* smp_distribute_act[i])(p_cb, p_data); break; @@ -1254,6 +1290,8 @@ void smp_key_pick_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) i ++; } } + +#if (BLE_INCLUDED == TRUE) /******************************************************************************* ** Function smp_key_distribution ** Description start key distribution if required. @@ -1417,6 +1455,7 @@ void smp_process_io_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) smp_send_pair_rsp(p_cb, NULL); } } +#endif ///BLE_INCLUDED == TRUE /******************************************************************************* ** Function smp_br_process_slave_keys_response @@ -1481,6 +1520,7 @@ void smp_idle_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) } } +#if (BLE_INCLUDED == TRUE) /******************************************************************************* ** Function smp_fast_conn_param ** Description apply default connection parameter for pairing process @@ -1706,6 +1746,7 @@ void smp_process_peer_nonce(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) SMP_TRACE_DEBUG("%s end\n ", __FUNCTION__); } +#endif ///BLE_INCLUDED == TRUE /******************************************************************************* ** Function smp_match_dhkey_checks @@ -1793,6 +1834,7 @@ void smp_wait_for_both_public_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) } } +#if (BLE_INCLUDED == TRUE) /******************************************************************************* ** Function smp_start_passkey_verification ** Description Starts SC passkey entry verification. @@ -2059,7 +2101,9 @@ void smp_derive_link_key_from_long_term_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data return; } } +#endif ///BLE_INCLUDED == TRUE +#if (CLASSIC_BT_INCLUDED == TRUE) /******************************************************************************* ** ** Function smp_br_process_link_key @@ -2087,6 +2131,7 @@ void smp_br_process_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, FALSE); smp_br_select_next_key(p_cb, NULL); } +#endif ///CLASSIC_BT_INCLUDED == TRUE /******************************************************************************* ** Function smp_key_distribution_by_transport @@ -2097,9 +2142,13 @@ void smp_key_distribution_by_transport(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) { SMP_TRACE_DEBUG("%s\n", __func__); if (p_cb->smp_over_br) { +#if (CLASSIC_BT_INCLUDED == TRUE) smp_br_select_next_key(p_cb, NULL); +#endif ///CLASSIC_BT_INCLUDED == TRUE } else { +#if (BLE_INCLUDED == TRUE) smp_key_distribution(p_cb, NULL); +#endif ///BLE_INCLUDED == TRUE } } diff --git a/components/bt/bluedroid/stack/smp/smp_api.c b/components/bt/bluedroid/stack/smp/smp_api.c index 37aa2b9111..89a32308e5 100644 --- a/components/bt/bluedroid/stack/smp/smp_api.c +++ b/components/bt/bluedroid/stack/smp/smp_api.c @@ -183,6 +183,7 @@ tSMP_STATUS SMP_Pair (BD_ADDR bd_addr) ** Returns SMP_STARTED if pairing started, otherwise reason for failure. ** *******************************************************************************/ +#if (CLASSIC_BT_INCLUDED == TRUE) tSMP_STATUS SMP_BR_PairWith (BD_ADDR bd_addr) { tSMP_CB *p_cb = &smp_cb; @@ -212,6 +213,7 @@ tSMP_STATUS SMP_BR_PairWith (BD_ADDR bd_addr) return SMP_STARTED; } +#endif ///CLASSIC_BT_INCLUDED == TRUE /******************************************************************************* ** @@ -258,6 +260,7 @@ void SMP_SecurityGrant(BD_ADDR bd_addr, UINT8 res) { SMP_TRACE_EVENT ("SMP_SecurityGrant "); +#if (CLASSIC_BT_INCLUDED == TRUE) if (smp_cb.smp_over_br) { if (smp_cb.br_state != SMP_BR_STATE_WAIT_APP_RSP || smp_cb.cb_evt != SMP_SEC_REQUEST_EVT || @@ -271,6 +274,7 @@ void SMP_SecurityGrant(BD_ADDR bd_addr, UINT8 res) smp_br_state_machine_event(&smp_cb, SMP_BR_API_SEC_GRANT_EVT, &res); return; } +#endif ///CLASSIC_BT_INCLUDED == TRUE if (smp_cb.state != SMP_STATE_WAIT_APP_RSP || smp_cb.cb_evt != SMP_SEC_REQUEST_EVT || diff --git a/components/bt/bluedroid/stack/smp/smp_br_main.c b/components/bt/bluedroid/stack/smp/smp_br_main.c index ba2eb97456..5ef7a7c694 100644 --- a/components/bt/bluedroid/stack/smp/smp_br_main.c +++ b/components/bt/bluedroid/stack/smp/smp_br_main.c @@ -21,7 +21,7 @@ #include #include "smp_int.h" -#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE) +#if ( CLASSIC_BT_INCLUDED== TRUE && SMP_INCLUDED == TRUE) const char *const smp_br_state_name [SMP_BR_STATE_MAX + 1] = { "SMP_BR_STATE_IDLE", diff --git a/components/bt/bluedroid/stack/smp/smp_keys.c b/components/bt/bluedroid/stack/smp/smp_keys.c index c993c7387f..4c39635d9f 100644 --- a/components/bt/bluedroid/stack/smp/smp_keys.c +++ b/components/bt/bluedroid/stack/smp/smp_keys.c @@ -23,7 +23,7 @@ ******************************************************************************/ #include "common/bt_target.h" -#if SMP_INCLUDED == TRUE +#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE) #if SMP_DEBUG == TRUE #include #endif @@ -380,10 +380,13 @@ void smp_generate_ltk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) BOOLEAN div_status; SMP_TRACE_DEBUG ("%s\n", __FUNCTION__); +#if (CLASSIC_BT_INCLUDED == TRUE) if (smp_get_br_state() == SMP_BR_STATE_BOND_PENDING) { smp_br_process_link_key(p_cb, NULL); return; - } else if (p_cb->le_secure_connections_mode_is_used) { + } +#endif ///CLASSIC_BT_INCLUDED == TRUE + if (p_cb->le_secure_connections_mode_is_used) { smp_process_secure_connection_long_term_key(); return; } @@ -432,7 +435,9 @@ void smp_compute_csrk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) if (!SMP_Encrypt(er, BT_OCTET16_LEN, buffer, 4, &output)) { SMP_TRACE_ERROR("smp_generate_csrk failed\n"); if (p_cb->smp_over_br) { +#if (CLASSIC_BT_INCLUDED == TRUE) smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status); +#endif ///CLASSIC_BT_INCLUDED == TRUE } else { smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status); } diff --git a/components/bt/bluedroid/stack/smp/smp_l2c.c b/components/bt/bluedroid/stack/smp/smp_l2c.c index a3ac356aca..67dd1ac5ae 100644 --- a/components/bt/bluedroid/stack/smp/smp_l2c.c +++ b/components/bt/bluedroid/stack/smp/smp_l2c.c @@ -35,10 +35,12 @@ static void smp_tx_complete_callback(UINT16 cid, UINT16 num_pkt); +#if (BLE_INCLUDED == TRUE) static void smp_connect_callback(UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason, tBT_TRANSPORT transport); static void smp_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf); +#endif ///BLE_INCLUDED == TRUE #if (CLASSIC_BT_INCLUDED == TRUE) static void smp_br_connect_callback(UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason, tBT_TRANSPORT transport); @@ -64,8 +66,6 @@ void smp_l2cap_if_init (void) fixed_reg.fixed_chnl_opts.mps = 0; fixed_reg.fixed_chnl_opts.tx_win_sz = 0; - fixed_reg.pL2CA_FixedConn_Cb = smp_connect_callback; - fixed_reg.pL2CA_FixedData_Cb = smp_data_received; fixed_reg.pL2CA_FixedTxComplete_Cb = smp_tx_complete_callback; fixed_reg.pL2CA_FixedCong_Cb = NULL; /* do not handle congestion on this channel */ @@ -75,7 +75,12 @@ void smp_l2cap_if_init (void) will cause the disconnect event to go back up for a long time. Set to 0 will be disconnected directly, and it will come up pairing failure, so it will not cause adverse effects. */ +#if (BLE_INCLUDED == TRUE) + fixed_reg.pL2CA_FixedConn_Cb = smp_connect_callback; + fixed_reg.pL2CA_FixedData_Cb = smp_data_received; L2CA_RegisterFixedChannel (L2CAP_SMP_CID, &fixed_reg); +#endif ///BLE_INCLUDED == TRUE + #if (CLASSIC_BT_INCLUDED == TRUE) fixed_reg.pL2CA_FixedConn_Cb = smp_br_connect_callback; fixed_reg.pL2CA_FixedData_Cb = smp_br_data_received; @@ -84,6 +89,7 @@ void smp_l2cap_if_init (void) #endif ///CLASSIC_BT_INCLUDED == TRUE } +#if (BLE_INCLUDED == TRUE) /******************************************************************************* ** ** Function smp_connect_callback @@ -107,7 +113,7 @@ static void smp_connect_callback (UINT16 channel, BD_ADDR bd_addr, BOOLEAN conne } if(!connected && &p_cb->rsp_timer_ent) { //free timer - btu_free_timer(&p_cb->rsp_timer_ent); + btu_free_timer(&p_cb->rsp_timer_ent); } if (memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0) { SMP_TRACE_EVENT ("%s() for pairing BDA: %08x%04x Event: %s\n", @@ -200,6 +206,7 @@ static void smp_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf) osi_free (p_buf); } +#endif ///BLE_INCLUDED == TRUE /******************************************************************************* ** @@ -223,7 +230,9 @@ static void smp_tx_complete_callback (UINT16 cid, UINT16 num_pkt) if (cid == L2CAP_SMP_CID) { smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); } else { +#if (CLASSIC_BT_INCLUDED == TRUE) smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason); +#endif ///CLASSIC_BT_INCLUDED == TRUE } } } diff --git a/components/bt/bluedroid/stack/smp/smp_main.c b/components/bt/bluedroid/stack/smp/smp_main.c index 0880fe910f..1becb36f01 100644 --- a/components/bt/bluedroid/stack/smp/smp_main.c +++ b/components/bt/bluedroid/stack/smp/smp_main.c @@ -163,7 +163,8 @@ enum { SMP_SM_NO_ACTION }; -static const tSMP_ACT smp_sm_action[] = { +#if (BLE_INCLUDED == TRUE) +static const tSMP_ACT smp_sm_action[SMP_SM_NO_ACTION] = { smp_proc_sec_req, smp_send_pair_req, smp_send_pair_rsp, @@ -226,6 +227,9 @@ static const tSMP_ACT smp_sm_action[] = { smp_idle_terminate, smp_fast_conn_param }; +#else +static const tSMP_ACT smp_sm_action[SMP_SM_NO_ACTION] = {NULL}; +#endif ///BLE_INCLUDED == TRUE /************ SMP Master FSM State/Event Indirection Table **************/ static const UINT8 smp_master_entry_map[][SMP_STATE_MAX] = { @@ -766,7 +770,7 @@ void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data) /* execute action */ /* execute action functions */ for (i = 0; i < SMP_NUM_ACTIONS; i++) { - if ((action = state_table[entry - 1][i]) != SMP_SM_NO_ACTION) { + if ((action = state_table[entry - 1][i]) != SMP_SM_NO_ACTION && smp_sm_action[action] != NULL) { (*smp_sm_action[action])(p_cb, (tSMP_INT_DATA *)p_data); } else { break; diff --git a/components/bt/bluedroid/stack/smp/smp_utils.c b/components/bt/bluedroid/stack/smp/smp_utils.c index 6d64f44abc..5edf0b8ab2 100644 --- a/components/bt/bluedroid/stack/smp/smp_utils.c +++ b/components/bt/bluedroid/stack/smp/smp_utils.c @@ -367,7 +367,9 @@ BOOLEAN smp_send_cmd(UINT8 cmd_code, tSMP_CB *p_cb) if (!sent) { if (p_cb->smp_over_br) { +#if (CLASSIC_BT_INCLUDED == TRUE) smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &failure); +#endif ///CLASSIC_BT_INCLUDED == TRUE } else { smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); } @@ -393,7 +395,9 @@ void smp_rsp_timeout(TIMER_LIST_ENT *p_tle) SMP_TRACE_EVENT("%s state:%d br_state:%d", __FUNCTION__, p_cb->state, p_cb->br_state); if (p_cb->smp_over_br) { +#if (CLASSIC_BT_INCLUDED == TRUE) smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &failure); +#endif ///CLASSIC_BT_INCLUDED == TRUE } else { smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); } @@ -550,6 +554,7 @@ static BT_HDR *smp_build_master_id_cmd(UINT8 cmd_code, tSMP_CB *p_cb) static BT_HDR *smp_build_identity_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb) { BT_HDR *p_buf = NULL ; +#if (BLE_INCLUDED == TRUE) UINT8 *p; BT_OCTET16 irk; UNUSED(cmd_code); @@ -568,6 +573,7 @@ static BT_HDR *smp_build_identity_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb) p_buf->len = SMP_ID_INFO_SIZE; } +#endif ///BLE_INCLUDED == TRUE return p_buf; } @@ -590,13 +596,16 @@ static BT_HDR *smp_build_id_addr_cmd(UINT8 cmd_code, tSMP_CB *p_cb) p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; UINT8_TO_STREAM (p, SMP_OPCODE_ID_ADDR); - /* Identity Address Information is used in the Transport Specific Key Distribution phase to distribute + /* Identity Address Information is used in the Transport Specific Key Distribution phase to distribute its public device address or static random address. if slave using static random address is encrypted, it should distribute its static random address */ +#if (BLE_INCLUDED == TRUE) if(btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type == BLE_ADDR_RANDOM && memcmp(btm_cb.ble_ctr_cb.addr_mgnt_cb.static_rand_addr, btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr,6) == 0) { UINT8_TO_STREAM (p, 0x01); BDADDR_TO_STREAM (p, btm_cb.ble_ctr_cb.addr_mgnt_cb.static_rand_addr); - } else { + } else +#endif ///BLE_INCLUDED == TRUE + { UINT8_TO_STREAM (p, 0); BDADDR_TO_STREAM (p, controller_get_interface()->get_address()->address); } @@ -997,6 +1006,7 @@ void smp_proc_pairing_cmpl(tSMP_CB *p_cb) memcpy (pairing_bda, p_cb->pairing_bda, BD_ADDR_LEN); +#if (BLE_INCLUDED == TRUE) #if (SMP_SLAVE_CON_PARAMS_UPD_ENABLE == TRUE) if (p_cb->role == HCI_ROLE_SLAVE) { if(p_rec && p_rec->ble.skip_update_conn_param) { @@ -1006,7 +1016,10 @@ void smp_proc_pairing_cmpl(tSMP_CB *p_cb) L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, TRUE); } } + #endif +#endif ///BLE_INCLUDED == TRUE + smp_reset_control_value(p_cb); if (p_callback) { @@ -1405,7 +1418,7 @@ void smp_collect_peer_io_capabilities(UINT8 *iocap, tSMP_CB *p_cb) iocap[1] = p_cb->peer_oob_flag; iocap[2] = p_cb->peer_auth_req; } - +#if (BLE_INCLUDED == TRUE) /******************************************************************************* ** Function smp_collect_local_ble_address ** @@ -1558,7 +1571,7 @@ BOOLEAN smp_calculate_f5_mackey_and_long_term_key(tSMP_CB *p_cb) SMP_TRACE_EVENT ("%s is completed\n", __func__); return TRUE; } - +#endif ///BLE_INCLUDED == TRUE /******************************************************************************* ** ** Function smp_request_oob_data diff --git a/examples/bluetooth/a2dp_sink/sdkconfig.defaults b/examples/bluetooth/a2dp_sink/sdkconfig.defaults index 132f512cb2..e27427a3bd 100644 --- a/examples/bluetooth/a2dp_sink/sdkconfig.defaults +++ b/examples/bluetooth/a2dp_sink/sdkconfig.defaults @@ -8,6 +8,4 @@ CONFIG_BT_BLUEDROID_ENABLED=y CONFIG_BT_CLASSIC_ENABLED=y CONFIG_BT_A2DP_ENABLE=y CONFIG_BT_SPP_ENABLED=n -CONFIG_BT_GATTS_ENABLE=n -CONFIG_BT_GATTC_ENABLE=n -CONFIG_BT_BLE_SMP_ENABLE=n +CONFIG_BT_BLE_ENABLED=n diff --git a/examples/bluetooth/a2dp_source/sdkconfig.defaults b/examples/bluetooth/a2dp_source/sdkconfig.defaults index fbee626500..c7adef6a5f 100644 --- a/examples/bluetooth/a2dp_source/sdkconfig.defaults +++ b/examples/bluetooth/a2dp_source/sdkconfig.defaults @@ -8,6 +8,4 @@ CONFIG_BT_BLUEDROID_ENABLED=y CONFIG_BT_CLASSIC_ENABLED=y CONFIG_BT_A2DP_ENABLE=y CONFIG_BT_SPP_ENABLED=n -CONFIG_BT_GATTS_ENABLE=n -CONFIG_BT_GATTC_ENABLE=n -CONFIG_BT_BLE_SMP_ENABLE=n +CONFIG_BT_BLE_ENABLED=n diff --git a/examples/bluetooth/bt_discovery/sdkconfig.defaults b/examples/bluetooth/bt_discovery/sdkconfig.defaults index af5b5d9d66..00e3d9971e 100644 --- a/examples/bluetooth/bt_discovery/sdkconfig.defaults +++ b/examples/bluetooth/bt_discovery/sdkconfig.defaults @@ -6,6 +6,4 @@ CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=y CONFIG_BTDM_CTRL_MODE_BTDM= CONFIG_BT_CLASSIC_ENABLED=y CONFIG_BT_A2DP_ENABLE=n -CONFIG_BT_GATTS_ENABLE=n -CONFIG_BT_GATTC_ENABLE=n -CONFIG_BT_BLE_SMP_ENABLE=n +CONFIG_BT_BLE_ENABLED=n diff --git a/examples/bluetooth/bt_spp_acceptor/sdkconfig.defaults b/examples/bluetooth/bt_spp_acceptor/sdkconfig.defaults index 7320428221..ea64364f53 100644 --- a/examples/bluetooth/bt_spp_acceptor/sdkconfig.defaults +++ b/examples/bluetooth/bt_spp_acceptor/sdkconfig.defaults @@ -7,3 +7,4 @@ CONFIG_BTDM_CTRL_MODE_BTDM= CONFIG_BT_CLASSIC_ENABLED=y CONFIG_WIFI_ENABLED=n CONFIG_BT_SPP_ENABLED=y +CONFIG_BT_BLE_ENABLED=n diff --git a/examples/bluetooth/bt_spp_initiator/sdkconfig.defaults b/examples/bluetooth/bt_spp_initiator/sdkconfig.defaults index 7320428221..ea64364f53 100644 --- a/examples/bluetooth/bt_spp_initiator/sdkconfig.defaults +++ b/examples/bluetooth/bt_spp_initiator/sdkconfig.defaults @@ -7,3 +7,4 @@ CONFIG_BTDM_CTRL_MODE_BTDM= CONFIG_BT_CLASSIC_ENABLED=y CONFIG_WIFI_ENABLED=n CONFIG_BT_SPP_ENABLED=y +CONFIG_BT_BLE_ENABLED=n diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/sdkconfig.defaults b/examples/bluetooth/bt_spp_vfs_acceptor/sdkconfig.defaults index 7320428221..ea64364f53 100644 --- a/examples/bluetooth/bt_spp_vfs_acceptor/sdkconfig.defaults +++ b/examples/bluetooth/bt_spp_vfs_acceptor/sdkconfig.defaults @@ -7,3 +7,4 @@ CONFIG_BTDM_CTRL_MODE_BTDM= CONFIG_BT_CLASSIC_ENABLED=y CONFIG_WIFI_ENABLED=n CONFIG_BT_SPP_ENABLED=y +CONFIG_BT_BLE_ENABLED=n diff --git a/examples/bluetooth/bt_spp_vfs_initiator/sdkconfig.defaults b/examples/bluetooth/bt_spp_vfs_initiator/sdkconfig.defaults index 7320428221..ea64364f53 100644 --- a/examples/bluetooth/bt_spp_vfs_initiator/sdkconfig.defaults +++ b/examples/bluetooth/bt_spp_vfs_initiator/sdkconfig.defaults @@ -7,3 +7,4 @@ CONFIG_BTDM_CTRL_MODE_BTDM= CONFIG_BT_CLASSIC_ENABLED=y CONFIG_WIFI_ENABLED=n CONFIG_BT_SPP_ENABLED=y +CONFIG_BT_BLE_ENABLED=n From 9863565a6f3d38b3a0857b7135b652d7106dd7c3 Mon Sep 17 00:00:00 2001 From: baohongde Date: Wed, 13 Feb 2019 10:38:26 +0800 Subject: [PATCH 097/486] components/bt: Optimization and bugfix of previous commit --- components/bt/bluedroid/bta/gatt/bta_gattc_co.c | 9 +++++++-- components/bt/bluedroid/btc/core/btc_config.c | 3 +-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_co.c b/components/bt/bluedroid/bta/gatt/bta_gattc_co.c index 98444458ae..06c51b07e8 100644 --- a/components/bt/bluedroid/bta/gatt/bta_gattc_co.c +++ b/components/bt/bluedroid/bta/gatt/bta_gattc_co.c @@ -96,7 +96,7 @@ typedef struct { cache_addr_info_t cache_addr[MAX_DEVICE_IN_CACHE]; }cache_env_t; -cache_env_t *cache_env = NULL; +static cache_env_t *cache_env = NULL; static void getFilename(char *buffer, hash_key_t hash) { @@ -382,10 +382,15 @@ void bta_gattc_co_cache_addr_init(void) UINT8 num_addr; size_t length = MAX_ADDR_LIST_CACHE_BUF; UINT8 *p_buf = osi_malloc(MAX_ADDR_LIST_CACHE_BUF); + if (p_buf == NULL) { + APPL_TRACE_ERROR("%s malloc failed!", __func__); + return; + } cache_env = (cache_env_t *)osi_malloc(sizeof(cache_env_t)); - if (cache_env == NULL || p_buf == NULL) { + if (cache_env == NULL) { APPL_TRACE_ERROR("%s malloc failed!", __func__); + osi_free(p_buf); return; } diff --git a/components/bt/bluedroid/btc/core/btc_config.c b/components/bt/bluedroid/btc/core/btc_config.c index b987a32e0c..fdababfe08 100644 --- a/components/bt/bluedroid/btc/core/btc_config.c +++ b/components/bt/bluedroid/btc/core/btc_config.c @@ -336,5 +336,4 @@ void btc_config_lock(void) void btc_config_unlock(void) { osi_mutex_unlock(&lock); -} - +} \ No newline at end of file From 2ad65bb434542dfab6a15658a82c177ef5de78f5 Mon Sep 17 00:00:00 2001 From: Tian Hao Date: Thu, 18 Apr 2019 11:57:28 +0800 Subject: [PATCH 098/486] Support timeout of fixed_queue and osi_thread 1. remove fixed_queue_try_dequeue and fixed_queue_try_enqueue, 2. add timeout parameter for fixed_queue_enqueue and fixed_queue_dequeue 3. replace where call fixed_queue_try_dequeue/enqueue to fixed_queue_dequeue/enqueue(..., timeout = 0) 4. replace where call fixed queue_enqueue/dequeue to fixed_queue_enqueue/dequeue( ..., timeout = FIXED_QUEUE_MAX_TIMEOUT) 5. modify the blocking_type of osi_thread_post to timeout. --- .../bt/bluedroid/bta/sys/bta_sys_main.c | 4 +- components/bt/bluedroid/btc/core/btc_task.c | 6 +-- .../btc/profile/std/a2dp/btc_a2dp_sink.c | 10 ++-- .../btc/profile/std/a2dp/btc_a2dp_source.c | 12 ++--- components/bt/bluedroid/hci/hci_hal_h4.c | 12 ++--- components/bt/bluedroid/hci/hci_layer.c | 24 +++++----- .../bt/bluedroid/hci/include/hci/hci_layer.h | 2 +- components/bt/bluedroid/osi/fixed_queue.c | 45 ++---------------- .../bluedroid/osi/include/osi/fixed_queue.h | 28 ++++------- .../bt/bluedroid/osi/include/osi/mutex.h | 4 +- .../bt/bluedroid/osi/include/osi/thread.h | 47 ++++++++++++++++--- components/bt/bluedroid/osi/thread.c | 14 ++---- .../bt/bluedroid/stack/avct/avct_lcb_act.c | 4 +- .../bt/bluedroid/stack/avdt/avdt_ccb_act.c | 8 ++-- components/bt/bluedroid/stack/avdt/avdt_msg.c | 8 ++-- .../bt/bluedroid/stack/avdt/avdt_scb_act.c | 12 ++--- components/bt/bluedroid/stack/btm/btm_acl.c | 8 ++-- .../bt/bluedroid/stack/btm/btm_ble_bgconn.c | 4 +- components/bt/bluedroid/stack/btm/btm_sco.c | 6 +-- components/bt/bluedroid/stack/btm/btm_sec.c | 6 +-- components/bt/bluedroid/stack/btu/btu_hcif.c | 4 +- components/bt/bluedroid/stack/btu/btu_init.c | 2 +- components/bt/bluedroid/stack/btu/btu_task.c | 10 ++-- components/bt/bluedroid/stack/gap/gap_ble.c | 6 +-- components/bt/bluedroid/stack/gap/gap_conn.c | 20 ++++---- .../bt/bluedroid/stack/gatt/gatt_auth.c | 6 +-- components/bt/bluedroid/stack/gatt/gatt_db.c | 2 +- components/bt/bluedroid/stack/gatt/gatt_sr.c | 8 ++-- .../bt/bluedroid/stack/gatt/gatt_utils.c | 18 +++---- .../bt/bluedroid/stack/include/stack/btu.h | 2 +- components/bt/bluedroid/stack/l2cap/l2c_api.c | 2 +- components/bt/bluedroid/stack/l2cap/l2c_ble.c | 6 +-- components/bt/bluedroid/stack/l2cap/l2c_csm.c | 2 +- components/bt/bluedroid/stack/l2cap/l2c_fcr.c | 20 ++++---- components/bt/bluedroid/stack/l2cap/l2c_ucd.c | 24 +++++----- .../bt/bluedroid/stack/l2cap/l2c_utils.c | 8 ++-- .../bt/bluedroid/stack/rfcomm/port_api.c | 10 ++-- .../bt/bluedroid/stack/rfcomm/port_rfc.c | 4 +- .../bt/bluedroid/stack/rfcomm/port_utils.c | 4 +- .../bt/bluedroid/stack/rfcomm/rfc_mx_fsm.c | 2 +- .../bt/bluedroid/stack/rfcomm/rfc_utils.c | 4 +- 41 files changed, 207 insertions(+), 221 deletions(-) diff --git a/components/bt/bluedroid/bta/sys/bta_sys_main.c b/components/bt/bluedroid/bta/sys/bta_sys_main.c index c9a7f450f4..c00abd7394 100644 --- a/components/bt/bluedroid/bta/sys/bta_sys_main.c +++ b/components/bt/bluedroid/bta/sys/bta_sys_main.c @@ -572,7 +572,7 @@ void bta_sys_sendmsg(void *p_msg) // there is a procedure in progress that can schedule a task via this // message queue. This causes |btu_bta_msg_queue| to get cleaned up before // it gets used here; hence we check for NULL before using it. - if (btu_task_post(SIG_BTU_BTA_MSG, p_msg, OSI_THREAD_BLOCKING) == false) { + if (btu_task_post(SIG_BTU_BTA_MSG, p_msg, OSI_THREAD_MAX_TIMEOUT) == false) { osi_free(p_msg); } } @@ -592,7 +592,7 @@ void bta_alarm_cb(void *data) assert(data != NULL); TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *)data; - btu_task_post(SIG_BTU_BTA_ALARM, p_tle, OSI_THREAD_BLOCKING); + btu_task_post(SIG_BTU_BTA_ALARM, p_tle, OSI_THREAD_MAX_TIMEOUT); } void bta_sys_start_timer(TIMER_LIST_ENT *p_tle, UINT16 type, INT32 timeout_ms) diff --git a/components/bt/bluedroid/btc/core/btc_task.c b/components/bt/bluedroid/btc/core/btc_task.c index 911f1941b6..cb8616d9b0 100644 --- a/components/bt/bluedroid/btc/core/btc_task.c +++ b/components/bt/bluedroid/btc/core/btc_task.c @@ -128,7 +128,7 @@ static void btc_thread_handler(void *arg) osi_free(msg); } -static bt_status_t btc_task_post(btc_msg_t *msg, osi_thread_blocking_t blocking) +static bt_status_t btc_task_post(btc_msg_t *msg, uint32_t timeout) { btc_msg_t *lmsg; @@ -139,7 +139,7 @@ static bt_status_t btc_task_post(btc_msg_t *msg, osi_thread_blocking_t blocking) memcpy(lmsg, msg, sizeof(btc_msg_t)); - if (osi_thread_post(btc_thread, btc_thread_handler, lmsg, 2, blocking) == false) { + if (osi_thread_post(btc_thread, btc_thread_handler, lmsg, 2, timeout) == false) { return BT_STATUS_BUSY; } @@ -171,7 +171,7 @@ bt_status_t btc_transfer_context(btc_msg_t *msg, void *arg, int arg_len, btc_arg lmsg.arg = NULL; } - return btc_task_post(&lmsg, OSI_THREAD_BLOCKING); + return btc_task_post(&lmsg, OSI_THREAD_MAX_TIMEOUT); } diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c index f1d51d80e3..1a65fbbdcf 100644 --- a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c +++ b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c @@ -182,7 +182,7 @@ static bool btc_a2dp_sink_ctrl_post(uint32_t sig, void *param) evt->sig = sig; evt->param = param; - return osi_thread_post(a2dp_sink_local_param.btc_aa_snk_task_hdl, btc_a2dp_sink_ctrl_handler, evt, 0, OSI_THREAD_BLOCKING); + return osi_thread_post(a2dp_sink_local_param.btc_aa_snk_task_hdl, btc_a2dp_sink_ctrl_handler, evt, 0, OSI_THREAD_MAX_TIMEOUT); } static void btc_a2dp_sink_ctrl_handler(void *arg) @@ -322,7 +322,7 @@ void btc_a2dp_sink_on_suspended(tBTA_AV_SUSPEND *p_av) static void btc_a2dp_sink_data_post(void) { - osi_thread_post(a2dp_sink_local_param.btc_aa_snk_task_hdl, btc_a2dp_sink_data_ready, NULL, 1, OSI_THREAD_BLOCKING); + osi_thread_post(a2dp_sink_local_param.btc_aa_snk_task_hdl, btc_a2dp_sink_data_ready, NULL, 1, OSI_THREAD_MAX_TIMEOUT); } /******************************************************************************* @@ -390,7 +390,7 @@ static void btc_a2dp_sink_data_ready(UNUSED_ATTR void *context) return; } btc_a2dp_sink_handle_inc_media(p_msg); - p_msg = (tBT_SBC_HDR *)fixed_queue_try_dequeue(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ); + p_msg = (tBT_SBC_HDR *)fixed_queue_dequeue(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, 0); if ( p_msg == NULL ) { APPL_TRACE_ERROR("Insufficient data in que "); break; @@ -695,7 +695,7 @@ UINT8 btc_a2dp_sink_enque_buf(BT_HDR *p_pkt) memcpy(p_msg, p_pkt, (sizeof(BT_HDR) + p_pkt->offset + p_pkt->len)); p_msg->num_frames_to_be_processed = (*((UINT8 *)(p_msg + 1) + p_msg->offset)) & 0x0f; APPL_TRACE_VERBOSE("btc_a2dp_sink_enque_buf %d + \n", p_msg->num_frames_to_be_processed); - fixed_queue_enqueue(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, p_msg); + fixed_queue_enqueue(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, p_msg, FIXED_QUEUE_MAX_TIMEOUT); btc_a2dp_sink_data_post(); } else { /* let caller deal with a failed allocation */ @@ -721,7 +721,7 @@ static void btc_a2dp_sink_handle_clear_track (void) static void btc_a2dp_sink_flush_q(fixed_queue_t *p_q) { while (! fixed_queue_is_empty(p_q)) { - osi_free(fixed_queue_try_dequeue(p_q)); + osi_free(fixed_queue_dequeue(p_q, 0)); } } diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c index 3591901002..7f1ef366be 100644 --- a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c +++ b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c @@ -249,7 +249,7 @@ static bool btc_a2dp_source_ctrl_post(uint32_t sig, void *param) evt->sig = sig; evt->param = param; - return osi_thread_post(a2dp_source_local_param.btc_aa_src_task_hdl, btc_a2dp_source_ctrl_handler, evt, 0, OSI_THREAD_BLOCKING); + return osi_thread_post(a2dp_source_local_param.btc_aa_src_task_hdl, btc_a2dp_source_ctrl_handler, evt, 0, OSI_THREAD_MAX_TIMEOUT); } static void btc_a2dp_source_ctrl_handler(void *arg) @@ -421,7 +421,7 @@ void btc_a2dp_source_on_suspended(tBTA_AV_SUSPEND *p_av) static void btc_a2dp_source_data_post(void) { - osi_thread_post(a2dp_source_local_param.btc_aa_src_task_hdl, btc_a2dp_source_handle_timer, NULL, 1, OSI_THREAD_BLOCKING); + osi_thread_post(a2dp_source_local_param.btc_aa_src_task_hdl, btc_a2dp_source_handle_timer, NULL, 1, OSI_THREAD_MAX_TIMEOUT); } static UINT64 time_now_us() @@ -510,7 +510,7 @@ BT_HDR *btc_a2dp_source_audio_readbuf(void) if (btc_a2dp_source_state != BTC_A2DP_SOURCE_STATE_ON){ return NULL; } - return fixed_queue_try_dequeue(a2dp_source_local_param.btc_aa_src_cb.TxAaQ); + return fixed_queue_dequeue(a2dp_source_local_param.btc_aa_src_cb.TxAaQ, 0); } /******************************************************************************* @@ -1378,7 +1378,7 @@ static void btc_media_aa_prep_sbc_2_send(UINT8 nb_frame) } /* Enqueue the encoded SBC frame in AA Tx Queue */ - fixed_queue_enqueue(a2dp_source_local_param.btc_aa_src_cb.TxAaQ, p_buf); + fixed_queue_enqueue(a2dp_source_local_param.btc_aa_src_cb.TxAaQ, p_buf, FIXED_QUEUE_MAX_TIMEOUT); } else { osi_free(p_buf); } @@ -1407,7 +1407,7 @@ static void btc_a2dp_source_prep_2_send(UINT8 nb_frame) } while (fixed_queue_length(a2dp_source_local_param.btc_aa_src_cb.TxAaQ) > (MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ - nb_frame)) { - osi_free(fixed_queue_try_dequeue(a2dp_source_local_param.btc_aa_src_cb.TxAaQ)); + osi_free(fixed_queue_dequeue(a2dp_source_local_param.btc_aa_src_cb.TxAaQ, 0)); } // Transcode frame @@ -1589,7 +1589,7 @@ static void btc_a2dp_source_aa_stop_tx(void) static void btc_a2dp_source_flush_q(fixed_queue_t *p_q) { while (! fixed_queue_is_empty(p_q)) { - osi_free(fixed_queue_try_dequeue(p_q)); + osi_free(fixed_queue_dequeue(p_q, 0)); } } diff --git a/components/bt/bluedroid/hci/hci_hal_h4.c b/components/bt/bluedroid/hci/hci_hal_h4.c index 5985e32ae2..67bb83438f 100644 --- a/components/bt/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/bluedroid/hci/hci_hal_h4.c @@ -170,9 +170,9 @@ static void hci_hal_h4_rx_handler(void *arg) fixed_queue_process(hci_hal_env.rx_q); } -bool hci_hal_h4_task_post(osi_thread_blocking_t blocking) +bool hci_hal_h4_task_post(uint32_t timeout) { - return osi_thread_post(hci_h4_thread, hci_hal_h4_rx_handler, NULL, 1, blocking); + return osi_thread_post(hci_h4_thread, hci_hal_h4_rx_handler, NULL, 1, timeout); } #if (C2H_FLOW_CONTROL_INCLUDED == TRUE) @@ -314,7 +314,7 @@ static void event_uart_has_bytes(fixed_queue_t *queue) { BT_HDR *packet; while (!fixed_queue_is_empty(queue)) { - packet = fixed_queue_dequeue(queue); + packet = fixed_queue_dequeue(queue, FIXED_QUEUE_MAX_TIMEOUT); hci_hal_h4_hdl_rx_packet(packet); } } @@ -323,7 +323,7 @@ static void host_send_pkt_available_cb(void) { //Controller rx cache buffer is ready for receiving new host packet //Just Call Host main thread task to process pending packets. - hci_host_task_post(OSI_THREAD_BLOCKING); + hci_host_task_post(OSI_THREAD_MAX_TIMEOUT); } static int host_recv_pkt_cb(uint8_t *data, uint16_t len) @@ -347,8 +347,8 @@ static int host_recv_pkt_cb(uint8_t *data, uint16_t len) pkt->len = len; pkt->layer_specific = 0; memcpy(pkt->data, data, len); - fixed_queue_enqueue(hci_hal_env.rx_q, pkt); - hci_hal_h4_task_post(OSI_THREAD_NON_BLOCKING); + fixed_queue_enqueue(hci_hal_env.rx_q, pkt, FIXED_QUEUE_MAX_TIMEOUT); + hci_hal_h4_task_post(0); BTTRC_DUMP_BUFFER("Recv Pkt", pkt->data, len); diff --git a/components/bt/bluedroid/hci/hci_layer.c b/components/bt/bluedroid/hci/hci_layer.c index e426528d45..6c285339cc 100644 --- a/components/bt/bluedroid/hci/hci_layer.c +++ b/components/bt/bluedroid/hci/hci_layer.c @@ -135,9 +135,9 @@ void hci_shut_down(void) } -bool hci_host_task_post(osi_thread_blocking_t blocking) +bool hci_host_task_post(uint32_t timeout) { - return osi_thread_post(hci_host_thread, hci_host_thread_handler, NULL, 0, blocking); + return osi_thread_post(hci_host_thread, hci_host_thread_handler, NULL, 0, timeout); } static int hci_layer_init_env(void) @@ -252,8 +252,8 @@ static void transmit_command( HCI_TRACE_DEBUG("HCI Enqueue Comamnd opcode=0x%x\n", wait_entry->opcode); BTTRC_DUMP_BUFFER(NULL, command->data + command->offset, command->len); - fixed_queue_enqueue(hci_host_env.command_queue, wait_entry); - hci_host_task_post(OSI_THREAD_BLOCKING); + fixed_queue_enqueue(hci_host_env.command_queue, wait_entry, FIXED_QUEUE_MAX_TIMEOUT); + hci_host_task_post(OSI_THREAD_MAX_TIMEOUT); } @@ -273,8 +273,8 @@ static future_t *transmit_command_futured(BT_HDR *command) // in case the upper layer didn't already command->event = MSG_STACK_TO_HC_HCI_CMD; - fixed_queue_enqueue(hci_host_env.command_queue, wait_entry); - hci_host_task_post(OSI_THREAD_BLOCKING); + fixed_queue_enqueue(hci_host_env.command_queue, wait_entry, FIXED_QUEUE_MAX_TIMEOUT); + hci_host_task_post(OSI_THREAD_MAX_TIMEOUT); return future; } @@ -284,10 +284,10 @@ static void transmit_downward(uint16_t type, void *data) transmit_command((BT_HDR *)data, NULL, NULL, NULL); HCI_TRACE_WARNING("%s legacy transmit of command. Use transmit_command instead.\n", __func__); } else { - fixed_queue_enqueue(hci_host_env.packet_queue, data); + fixed_queue_enqueue(hci_host_env.packet_queue, data, FIXED_QUEUE_MAX_TIMEOUT); } - hci_host_task_post(OSI_THREAD_BLOCKING); + hci_host_task_post(OSI_THREAD_MAX_TIMEOUT); } @@ -297,7 +297,7 @@ static void event_command_ready(fixed_queue_t *queue) waiting_command_t *wait_entry = NULL; command_waiting_response_t *cmd_wait_q = &hci_host_env.cmd_waiting_q; - wait_entry = fixed_queue_dequeue(queue); + wait_entry = fixed_queue_dequeue(queue, FIXED_QUEUE_MAX_TIMEOUT); if(wait_entry->opcode == HCI_HOST_NUM_PACKETS_DONE #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) @@ -323,7 +323,7 @@ static void event_command_ready(fixed_queue_t *queue) static void event_packet_ready(fixed_queue_t *queue) { - BT_HDR *packet = (BT_HDR *)fixed_queue_dequeue(queue); + BT_HDR *packet = (BT_HDR *)fixed_queue_dequeue(queue, FIXED_QUEUE_MAX_TIMEOUT); // The queue may be the command queue or the packet queue, we don't care packet_fragmenter->fragment_and_dispatch(packet); @@ -461,7 +461,7 @@ intercepted: /*Tell HCI Host Task to continue TX Pending commands*/ if (hci_host_env.command_credits && !fixed_queue_is_empty(hci_host_env.command_queue)) { - hci_host_task_post(OSI_THREAD_BLOCKING); + hci_host_task_post(OSI_THREAD_MAX_TIMEOUT); } if (wait_entry) { @@ -489,7 +489,7 @@ static void dispatch_reassembled(BT_HDR *packet) { // Events should already have been dispatched before this point //Tell Up-layer received packet. - if (btu_task_post(SIG_BTU_HCI_MSG, packet, OSI_THREAD_BLOCKING) == false) { + if (btu_task_post(SIG_BTU_HCI_MSG, packet, OSI_THREAD_MAX_TIMEOUT) == false) { osi_free(packet); } } diff --git a/components/bt/bluedroid/hci/include/hci/hci_layer.h b/components/bt/bluedroid/hci/include/hci/hci_layer.h index 90f0a8221e..8fa5165e9f 100644 --- a/components/bt/bluedroid/hci/include/hci/hci_layer.h +++ b/components/bt/bluedroid/hci/include/hci/hci_layer.h @@ -97,6 +97,6 @@ const hci_t *hci_layer_get_interface(); int hci_start_up(void); void hci_shut_down(void); -bool hci_host_task_post(osi_thread_blocking_t blocking); +bool hci_host_task_post(uint32_t timeout); #endif /* _HCI_LAYER_H_ */ diff --git a/components/bt/bluedroid/osi/fixed_queue.c b/components/bt/bluedroid/osi/fixed_queue.c index 30290060aa..0b21dd8be1 100644 --- a/components/bt/bluedroid/osi/fixed_queue.c +++ b/components/bt/bluedroid/osi/fixed_queue.c @@ -129,45 +129,12 @@ size_t fixed_queue_capacity(fixed_queue_t *queue) return queue->capacity; } -void fixed_queue_enqueue(fixed_queue_t *queue, void *data) +bool fixed_queue_enqueue(fixed_queue_t *queue, void *data, uint32_t timeout) { assert(queue != NULL); assert(data != NULL); - osi_sem_take(&queue->enqueue_sem, OSI_SEM_MAX_TIMEOUT); - - osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); - - list_append(queue->list, data); - osi_mutex_unlock(&queue->lock); - - osi_sem_give(&queue->dequeue_sem); -} - -void *fixed_queue_dequeue(fixed_queue_t *queue) -{ - void *ret = NULL; - - assert(queue != NULL); - - osi_sem_take(&queue->dequeue_sem, OSI_SEM_MAX_TIMEOUT); - - osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); - ret = list_front(queue->list); - list_remove(queue->list, ret); - osi_mutex_unlock(&queue->lock); - - osi_sem_give(&queue->enqueue_sem); - - return ret; -} - -bool fixed_queue_try_enqueue(fixed_queue_t *queue, void *data) -{ - assert(queue != NULL); - assert(data != NULL); - - if (osi_sem_take(&queue->enqueue_sem, 0) != 0) { + if (osi_sem_take(&queue->enqueue_sem, timeout) != 0) { return false; } @@ -181,15 +148,13 @@ bool fixed_queue_try_enqueue(fixed_queue_t *queue, void *data) return true; } -void *fixed_queue_try_dequeue(fixed_queue_t *queue) +void *fixed_queue_dequeue(fixed_queue_t *queue, uint32_t timeout) { void *ret = NULL; - if (queue == NULL) { - return NULL; - } + assert(queue != NULL); - if (osi_sem_take(queue->dequeue_sem, 0) != 0) { + if (osi_sem_take(queue->dequeue_sem, timeout) != 0) { return NULL; } diff --git a/components/bt/bluedroid/osi/include/osi/fixed_queue.h b/components/bt/bluedroid/osi/include/osi/fixed_queue.h index 5ec0c07498..a25e60393c 100644 --- a/components/bt/bluedroid/osi/include/osi/fixed_queue.h +++ b/components/bt/bluedroid/osi/include/osi/fixed_queue.h @@ -21,11 +21,14 @@ #include #include "osi/list.h" +#include "osi/semaphore.h" #ifndef QUEUE_SIZE_MAX #define QUEUE_SIZE_MAX 254 #endif +#define FIXED_QUEUE_MAX_TIMEOUT OSI_SEM_MAX_TIMEOUT + struct fixed_queue_t; typedef struct fixed_queue_t fixed_queue_t; @@ -56,27 +59,14 @@ size_t fixed_queue_length(fixed_queue_t *queue); // not be NULL. size_t fixed_queue_capacity(fixed_queue_t *queue); -// Enqueues the given |data| into the |queue|. The caller will be blocked -// if nore more space is available in the queue. Neither |queue| nor |data| -// may be NULL. -void fixed_queue_enqueue(fixed_queue_t *queue, void *data); +// Enqueues the given |data| into the |queue|. The caller will be blocked or immediately return or wait for timeout according to the parameter timeout. +// If enqueue failed, it will return false, otherwise return true +bool fixed_queue_enqueue(fixed_queue_t *queue, void *data, uint32_t timeout); // Dequeues the next element from |queue|. If the queue is currently empty, -// this function will block the caller until an item is enqueued. This -// function will never return NULL. |queue| may not be NULL. -void *fixed_queue_dequeue(fixed_queue_t *queue); - -// Tries to enqueue |data| into the |queue|. This function will never block -// the caller. If the queue capacity would be exceeded by adding one more -// element, this function returns false immediately. Otherwise, this function -// returns true. Neither |queue| nor |data| may be NULL. -bool fixed_queue_try_enqueue(fixed_queue_t *queue, void *data); - -// Tries to dequeue an element from |queue|. This function will never block -// the caller. If the queue is empty, this function returns NULL immediately. -// Otherwise, the next element in the queue is returned. |queue| may not be -// NULL. -void *fixed_queue_try_dequeue(fixed_queue_t *queue); +// this function will block the caller until an item is enqueued or immediately return or wait for timeout according to the parameter timeout. +// If dequeue failed, it will return NULL, otherwise return a point. +void *fixed_queue_dequeue(fixed_queue_t *queue, uint32_t timeout); // Returns the first element from |queue|, if present, without dequeuing it. // This function will never block the caller. Returns NULL if there are no diff --git a/components/bt/bluedroid/osi/include/osi/mutex.h b/components/bt/bluedroid/osi/include/osi/mutex.h index 65180a7850..1b9784d62b 100644 --- a/components/bt/bluedroid/osi/include/osi/mutex.h +++ b/components/bt/bluedroid/osi/include/osi/mutex.h @@ -23,9 +23,9 @@ #include "freertos/task.h" #include "freertos/queue.h" #include "freertos/semphr.h" +#include "osi/semaphore.h" - -#define OSI_MUTEX_MAX_TIMEOUT 0xffffffffUL +#define OSI_MUTEX_MAX_TIMEOUT OSI_SEM_MAX_TIMEOUT #define osi_mutex_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE ) #define osi_mutex_set_invalid( x ) ( ( *x ) = NULL ) diff --git a/components/bt/bluedroid/osi/include/osi/thread.h b/components/bt/bluedroid/osi/include/osi/thread.h index b3f77725f9..7f4c46aedf 100644 --- a/components/bt/bluedroid/osi/include/osi/thread.h +++ b/components/bt/bluedroid/osi/include/osi/thread.h @@ -22,9 +22,12 @@ #include "freertos/task.h" #include "esp_task.h" #include "common/bt_defs.h" +#include "osi/semaphore.h" #define portBASE_TYPE int +#define OSI_THREAD_MAX_TIMEOUT OSI_SEM_MAX_TIMEOUT + struct osi_thread; typedef struct osi_thread osi_thread_t; @@ -37,21 +40,53 @@ typedef enum { OSI_THREAD_CORE_AFFINITY, } osi_thread_core_t; -typedef enum { - OSI_THREAD_NON_BLOCKING = 0, - OSI_THREAD_BLOCKING, -} osi_thread_blocking_t; - +/* + * brief: Create a thread or task + * param name: thread name + * param stack_size: thread stack size + * param priority: thread priority + * param core: the CPU core which this thread run, OSI_THREAD_CORE_AFFINITY means unspecific CPU core + * param work_queue_num: speicify queue number, the queue[0] has highest priority, and the priority is decrease by index + * return : if create successfully, return thread handler; otherwise return NULL. + */ osi_thread_t *osi_thread_create(const char *name, size_t stack_size, int priority, osi_thread_core_t core, uint8_t work_queue_num); +/* + * brief: Destroy a thread or task + * param thread: point of thread handler + */ void osi_thread_free(osi_thread_t *thread); -bool osi_thread_post(osi_thread_t *thread, osi_thread_func_t func, void *context, int queue_idx, osi_thread_blocking_t blocking); +/* + * brief: Post an msg to a thread and told the thread call the function + * param thread: point of thread handler + * param func: callback function that called by target thread + * param context: argument of callback function + * param queue_idx: the queue which the msg send to + * param timeout: post timeout, OSI_THREAD_MAX_TIMEOUT means blocking forever, 0 means never blocking, others means block millisecond + * return : if post successfully, return true, otherwise return false + */ +bool osi_thread_post(osi_thread_t *thread, osi_thread_func_t func, void *context, int queue_idx, uint32_t timeout); +/* + * brief: Set the priority of thread + * param thread: point of thread handler + * param priority: priority + * return : if set successfully, return true, otherwise return false + */ bool osi_thread_set_priority(osi_thread_t *thread, int priority); +/* brief: Get thread name + * param thread: point of thread handler + * return: constant point of thread name + */ const char *osi_thread_name(osi_thread_t *thread); +/* brief: Get the size of the specified queue + * param thread: point of thread handler + * param wq_idx: the queue index of the thread + * return: queue size + */ int osi_thread_queue_wait_size(osi_thread_t *thread, int wq_idx); #endif /* __THREAD_H__ */ diff --git a/components/bt/bluedroid/osi/thread.c b/components/bt/bluedroid/osi/thread.c index ceac21bf89..04583061c3 100644 --- a/components/bt/bluedroid/osi/thread.c +++ b/components/bt/bluedroid/osi/thread.c @@ -63,7 +63,7 @@ static void osi_thread_run(void *arg) } while (!thread->stop && idx < thread->work_queue_num) { - work_item_t *item = fixed_queue_try_dequeue(thread->work_queues[idx]); + work_item_t *item = fixed_queue_dequeue(thread->work_queues[idx], 0); if (item) { item->func(item->context); osi_free(item); @@ -227,7 +227,7 @@ void osi_thread_free(osi_thread_t *thread) osi_free(thread); } -bool osi_thread_post(osi_thread_t *thread, osi_thread_func_t func, void *context, int queue_idx, osi_thread_blocking_t blocking) +bool osi_thread_post(osi_thread_t *thread, osi_thread_func_t func, void *context, int queue_idx, uint32_t timeout) { assert(thread != NULL); assert(func != NULL); @@ -243,13 +243,9 @@ bool osi_thread_post(osi_thread_t *thread, osi_thread_func_t func, void *context item->func = func; item->context = context; - if (blocking == OSI_THREAD_BLOCKING) { - fixed_queue_enqueue(thread->work_queues[queue_idx], item); - } else { - if (fixed_queue_try_enqueue(thread->work_queues[queue_idx], item) == false) { - osi_free(item); - return false; - } + if (fixed_queue_enqueue(thread->work_queues[queue_idx], item, timeout) == false) { + osi_free(item); + return false; } osi_sem_give(&thread->work_sem); diff --git a/components/bt/bluedroid/stack/avct/avct_lcb_act.c b/components/bt/bluedroid/stack/avct/avct_lcb_act.c index 02ac96039b..b83219dceb 100644 --- a/components/bt/bluedroid/stack/avct/avct_lcb_act.c +++ b/components/bt/bluedroid/stack/avct/avct_lcb_act.c @@ -449,7 +449,7 @@ void avct_lcb_cong_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data) if (p_lcb->cong == FALSE && !fixed_queue_is_empty(p_lcb->tx_q)) { while (!p_lcb->cong && - (p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_lcb->tx_q)) != NULL) + (p_buf = (BT_HDR *)fixed_queue_dequeue(p_lcb->tx_q, 0)) != NULL) { if (L2CA_DataWrite(p_lcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED) { @@ -569,7 +569,7 @@ void avct_lcb_send_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data) } if (p_lcb->cong == TRUE) { - fixed_queue_enqueue(p_lcb->tx_q, p_buf); + fixed_queue_enqueue(p_lcb->tx_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT); } /* send message to L2CAP */ diff --git a/components/bt/bluedroid/stack/avdt/avdt_ccb_act.c b/components/bt/bluedroid/stack/avdt/avdt_ccb_act.c index 9f7b0ee9d0..7d7e7c6e77 100644 --- a/components/bt/bluedroid/stack/avdt/avdt_ccb_act.c +++ b/components/bt/bluedroid/stack/avdt/avdt_ccb_act.c @@ -68,7 +68,7 @@ static void avdt_ccb_clear_ccb(tAVDT_CCB *p_ccb) } /* clear out response queue */ - while ((p_buf = (BT_HDR *) fixed_queue_try_dequeue(p_ccb->rsp_q)) != NULL) { + while ((p_buf = (BT_HDR *) fixed_queue_dequeue(p_ccb->rsp_q, 0)) != NULL) { osi_free(p_buf); } } @@ -659,7 +659,7 @@ void avdt_ccb_clear_cmds(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT *) &err_code); /* set up next message */ - p_ccb->p_curr_cmd = (BT_HDR *) fixed_queue_try_dequeue(p_ccb->cmd_q); + p_ccb->p_curr_cmd = (BT_HDR *) fixed_queue_dequeue(p_ccb->cmd_q, 0); } while (p_ccb->p_curr_cmd != NULL); @@ -812,7 +812,7 @@ void avdt_ccb_snd_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) ** not congested, not sending fragment, not waiting for response */ if ((!p_ccb->cong) && (p_ccb->p_curr_msg == NULL) && (p_ccb->p_curr_cmd == NULL)) { - if ((p_msg = (BT_HDR *) fixed_queue_try_dequeue(p_ccb->cmd_q)) != NULL) { + if ((p_msg = (BT_HDR *) fixed_queue_dequeue(p_ccb->cmd_q, 0)) != NULL) { /* make a copy of buffer in p_curr_cmd */ if ((p_ccb->p_curr_cmd = (BT_HDR *) osi_malloc(AVDT_CMD_BUF_SIZE)) != NULL) { memcpy(p_ccb->p_curr_cmd, p_msg, (sizeof(BT_HDR) + p_msg->offset + p_msg->len)); @@ -846,7 +846,7 @@ void avdt_ccb_snd_msg(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) } /* do we have responses to send? send them */ else if (!fixed_queue_is_empty(p_ccb->rsp_q)) { - while ((p_msg = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->rsp_q)) != NULL) { + while ((p_msg = (BT_HDR *)fixed_queue_dequeue(p_ccb->rsp_q, 0)) != NULL) { if (avdt_msg_send(p_ccb, p_msg) == TRUE) { /* break out if congested */ break; diff --git a/components/bt/bluedroid/stack/avdt/avdt_msg.c b/components/bt/bluedroid/stack/avdt/avdt_msg.c index 91e993233d..4ebca9a063 100644 --- a/components/bt/bluedroid/stack/avdt/avdt_msg.c +++ b/components/bt/bluedroid/stack/avdt/avdt_msg.c @@ -1440,7 +1440,7 @@ void avdt_msg_send_cmd(tAVDT_CCB *p_ccb, void *p_scb, UINT8 sig_id, tAVDT_MSG *p p_ccb->label = (p_ccb->label + 1) % 16; /* queue message and trigger ccb to send it */ - fixed_queue_enqueue(p_ccb->cmd_q, p_buf); + fixed_queue_enqueue(p_ccb->cmd_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT); avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL); } @@ -1487,7 +1487,7 @@ void avdt_msg_send_rsp(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params) AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_RSP, p_params->hdr.label); /* queue message and trigger ccb to send it */ - fixed_queue_enqueue(p_ccb->rsp_q, p_buf); + fixed_queue_enqueue(p_ccb->rsp_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT); avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL); } @@ -1547,7 +1547,7 @@ void avdt_msg_send_rej(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params) AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_REJ, p_params->hdr.label); /* queue message and trigger ccb to send it */ - fixed_queue_enqueue(p_ccb->rsp_q, p_buf); + fixed_queue_enqueue(p_ccb->rsp_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT); avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL); } @@ -1591,7 +1591,7 @@ void avdt_msg_send_grej(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params) AVDT_TRACE_DEBUG("avdt_msg_send_grej"); /* queue message and trigger ccb to send it */ - fixed_queue_enqueue(p_ccb->rsp_q, p_buf); + fixed_queue_enqueue(p_ccb->rsp_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT); avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL); } diff --git a/components/bt/bluedroid/stack/avdt/avdt_scb_act.c b/components/bt/bluedroid/stack/avdt/avdt_scb_act.c index b4bbcec066..4cdc5a2e36 100644 --- a/components/bt/bluedroid/stack/avdt/avdt_scb_act.c +++ b/components/bt/bluedroid/stack/avdt/avdt_scb_act.c @@ -1232,7 +1232,7 @@ void avdt_scb_hdl_write_req_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) /* this shouldn't be happening */ AVDT_TRACE_WARNING("*** Dropped media packet; congested"); BT_HDR *p_frag; - while ((p_frag = (BT_HDR*)fixed_queue_try_dequeue(p_scb->frag_q)) != NULL) + while ((p_frag = (BT_HDR*)fixed_queue_dequeue(p_scb->frag_q, 0)) != NULL) osi_free(p_frag); } @@ -1397,7 +1397,7 @@ void avdt_scb_snd_stream_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) /* clean fragments queue */ BT_HDR *p_frag; - while ((p_frag = (BT_HDR*)fixed_queue_try_dequeue(p_scb->frag_q)) != NULL) { + while ((p_frag = (BT_HDR*)fixed_queue_dequeue(p_scb->frag_q, 0)) != NULL) { osi_free(p_frag); } p_scb->frag_off = 0; @@ -1824,7 +1824,7 @@ void avdt_scb_free_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) #if AVDT_MULTIPLEXING == TRUE /* clean fragments queue */ BT_HDR *p_frag; - while ((p_frag = (BT_HDR*)fixed_queue_try_dequeue(p_scb->frag_q)) != NULL) { + while ((p_frag = (BT_HDR*)fixed_queue_dequeue(p_scb->frag_q, 0)) != NULL) { osi_free(p_frag); } #endif @@ -1880,7 +1880,7 @@ void avdt_scb_clr_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) AVDT_TRACE_DEBUG("Dropped fragments queue"); /* clean fragments queue */ BT_HDR *p_frag; - while ((p_frag = (BT_HDR*)fixed_queue_try_dequeue(p_scb->frag_q)) != NULL) { + while ((p_frag = (BT_HDR*)fixed_queue_dequeue(p_scb->frag_q, 0)) != NULL) { osi_free(p_frag); } p_scb->frag_off = 0; @@ -1933,7 +1933,7 @@ void avdt_scb_chk_snd_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) L2CA_FlushChannel(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_scb->p_ccb)][avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb)].lcid), L2CAP_FLUSH_CHANS_GET); #endif - while ((p_pkt = (BT_HDR*)fixed_queue_try_dequeue(p_scb->frag_q)) != NULL) { + while ((p_pkt = (BT_HDR*)fixed_queue_dequeue(p_scb->frag_q, 0)) != NULL) { sent = TRUE; AVDT_TRACE_DEBUG("Send fragment len=%d\n", p_pkt->len); /* fragments queue contains fragment to send */ @@ -2096,7 +2096,7 @@ void avdt_scb_queue_frags(tAVDT_SCB *p_scb, UINT8 **pp_data, UINT32 *p_data_len, UINT16_TO_BE_STREAM(p, p_frag->layer_specific ); } /* put fragment into gueue */ - fixed_queue_enqueue(p_scb->frag_q, p_frag); + fixed_queue_enqueue(p_scb->frag_q, p_frag, FIXED_QUEUE_MAX_TIMEOUT); num_frag--; } } diff --git a/components/bt/bluedroid/stack/btm/btm_acl.c b/components/bt/bluedroid/stack/btm/btm_acl.c index 6f7ce092a6..d15fc6c7d6 100644 --- a/components/bt/bluedroid/stack/btm/btm_acl.c +++ b/components/bt/bluedroid/stack/btm/btm_acl.c @@ -2364,7 +2364,7 @@ void btm_acl_resubmit_page (void) BD_ADDR bda; BTM_TRACE_DEBUG ("btm_acl_resubmit_page\n"); /* If there were other page request schedule can start the next one */ - if ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(btm_cb.page_queue)) != NULL) { + if ((p_buf = (BT_HDR *)fixed_queue_dequeue(btm_cb.page_queue, 0)) != NULL) { /* skip 3 (2 bytes opcode and 1 byte len) to get to the bd_addr * for both create_conn and rmt_name */ pp = (UINT8 *)(p_buf + 1) + p_buf->offset + 3; @@ -2395,7 +2395,7 @@ void btm_acl_reset_paging (void) BT_HDR *p; BTM_TRACE_DEBUG ("btm_acl_reset_paging\n"); /* If we sent reset we are definitely not paging any more */ - while ((p = (BT_HDR *)fixed_queue_try_dequeue(btm_cb.page_queue)) != NULL) { + while ((p = (BT_HDR *)fixed_queue_dequeue(btm_cb.page_queue, 0)) != NULL) { osi_free (p); } @@ -2419,7 +2419,7 @@ void btm_acl_paging (BT_HDR *p, BD_ADDR bda) (bda[0] << 16) + (bda[1] << 8) + bda[2], (bda[3] << 16) + (bda[4] << 8) + bda[5]); if (btm_cb.discing) { btm_cb.paging = TRUE; - fixed_queue_enqueue(btm_cb.page_queue, p); + fixed_queue_enqueue(btm_cb.page_queue, p, FIXED_QUEUE_MAX_TIMEOUT); } else { if (!BTM_ACL_IS_CONNECTED (bda)) { BTM_TRACE_DEBUG ("connecting_bda: %06x%06x\n", @@ -2429,7 +2429,7 @@ void btm_acl_paging (BT_HDR *p, BD_ADDR bda) btm_cb.connecting_bda[5]); if (btm_cb.paging && memcmp (bda, btm_cb.connecting_bda, BD_ADDR_LEN) != 0) { - fixed_queue_enqueue(btm_cb.page_queue, p); + fixed_queue_enqueue(btm_cb.page_queue, p, FIXED_QUEUE_MAX_TIMEOUT); } else { p_dev_rec = btm_find_or_alloc_dev (bda); memcpy (btm_cb.connecting_bda, p_dev_rec->bd_addr, BD_ADDR_LEN); diff --git a/components/bt/bluedroid/stack/btm/btm_ble_bgconn.c b/components/bt/bluedroid/stack/btm/btm_ble_bgconn.c index 0766715480..3721471f80 100644 --- a/components/bt/bluedroid/stack/btm/btm_ble_bgconn.c +++ b/components/bt/bluedroid/stack/btm/btm_ble_bgconn.c @@ -785,7 +785,7 @@ void btm_ble_enqueue_direct_conn_req(void *p_param) p->p_param = p_param; - fixed_queue_enqueue(btm_cb.ble_ctr_cb.conn_pending_q, p); + fixed_queue_enqueue(btm_cb.ble_ctr_cb.conn_pending_q, p, FIXED_QUEUE_MAX_TIMEOUT); } /******************************************************************************* ** @@ -801,7 +801,7 @@ BOOLEAN btm_send_pending_direct_conn(void) tBTM_BLE_CONN_REQ *p_req; BOOLEAN rt = FALSE; - p_req = (tBTM_BLE_CONN_REQ*)fixed_queue_try_dequeue(btm_cb.ble_ctr_cb.conn_pending_q); + p_req = (tBTM_BLE_CONN_REQ*)fixed_queue_dequeue(btm_cb.ble_ctr_cb.conn_pending_q, 0); if (p_req != NULL) { rt = l2cble_init_direct_conn((tL2C_LCB *)(p_req->p_param)); diff --git a/components/bt/bluedroid/stack/btm/btm_sco.c b/components/bt/bluedroid/stack/btm/btm_sco.c index 661caba638..25d8c4183c 100644 --- a/components/bt/bluedroid/stack/btm/btm_sco.c +++ b/components/bt/bluedroid/stack/btm/btm_sco.c @@ -86,7 +86,7 @@ void btm_sco_flush_sco_data(UINT16 sco_inx) if (sco_inx < BTM_MAX_SCO_LINKS) { p = &btm_cb.sco_cb.sco_db[sco_inx]; - while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p->xmit_data_q)) != NULL) { + while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p->xmit_data_q, 0)) != NULL) { osi_free(p_buf); } } @@ -292,7 +292,7 @@ void btm_sco_check_send_pkts (UINT16 sco_inx) BT_HDR *p_buf; while (p_cb->xmit_window_size != 0) { - if ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_data_q)) == NULL) { + if ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_ccb->xmit_data_q, 0)) == NULL) { break; } #if BTM_SCO_HCI_DEBUG @@ -441,7 +441,7 @@ tBTM_STATUS BTM_WriteScoData (UINT16 sco_inx, BT_HDR *p_buf) p_buf->len += HCI_SCO_PREAMBLE_SIZE; if (fixed_queue_length(p_ccb->xmit_data_q) < BTM_SCO_XMIT_QUEUE_THRS) { - fixed_queue_enqueue(p_ccb->xmit_data_q, p_buf); + fixed_queue_enqueue(p_ccb->xmit_data_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT); btm_sco_check_send_pkts (sco_inx); } else { BTM_TRACE_WARNING ("SCO xmit Q overflow, pkt dropped"); diff --git a/components/bt/bluedroid/stack/btm/btm_sec.c b/components/bt/bluedroid/stack/btm/btm_sec.c index 1d7b3276c6..fc711d9180 100644 --- a/components/bt/bluedroid/stack/btm/btm_sec.c +++ b/components/bt/bluedroid/stack/btm/btm_sec.c @@ -2791,7 +2791,7 @@ void btm_sec_check_pending_reqs (void) btm_cb.sec_pending_q = fixed_queue_new(QUEUE_SIZE_MAX); - while ((p_e = (tBTM_SEC_QUEUE_ENTRY *)fixed_queue_try_dequeue(bq)) != NULL) { + while ((p_e = (tBTM_SEC_QUEUE_ENTRY *)fixed_queue_dequeue(bq, 0)) != NULL) { /* Check that the ACL is still up before starting security procedures */ if (btm_bda_to_acl(p_e->bd_addr, p_e->transport) != NULL) { if (p_e->psm != 0) { @@ -5784,7 +5784,7 @@ static BOOLEAN btm_sec_queue_mx_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN BTM_TRACE_EVENT ("%s() PSM: 0x%04x Is_Orig: %u mx_proto_id: %u mx_chan_id: %u\n", __func__, psm, is_orig, mx_proto_id, mx_chan_id); - fixed_queue_enqueue(btm_cb.sec_pending_q, p_e); + fixed_queue_enqueue(btm_cb.sec_pending_q, p_e, FIXED_QUEUE_MAX_TIMEOUT); return (TRUE); } @@ -5883,7 +5883,7 @@ static BOOLEAN btm_sec_queue_encrypt_request (BD_ADDR bd_addr, tBT_TRANSPORT tra *(UINT8 *)p_e->p_ref_data = *(UINT8 *)(p_ref_data); p_e->transport = transport; memcpy(p_e->bd_addr, bd_addr, BD_ADDR_LEN); - fixed_queue_enqueue(btm_cb.sec_pending_q, p_e); + fixed_queue_enqueue(btm_cb.sec_pending_q, p_e, FIXED_QUEUE_MAX_TIMEOUT); return TRUE; } diff --git a/components/bt/bluedroid/stack/btu/btu_hcif.c b/components/bt/bluedroid/stack/btu/btu_hcif.c index 5677491c5c..de7693ee84 100644 --- a/components/bt/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/bluedroid/stack/btu/btu_hcif.c @@ -1086,7 +1086,7 @@ static void btu_hcif_command_complete_evt(BT_HDR *response, void *context) event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK; - btu_task_post(SIG_BTU_HCI_MSG, event, OSI_THREAD_BLOCKING); + btu_task_post(SIG_BTU_HCI_MSG, event, OSI_THREAD_MAX_TIMEOUT); } @@ -1291,7 +1291,7 @@ static void btu_hcif_command_status_evt(uint8_t status, BT_HDR *command, void *c event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK; - btu_task_post(SIG_BTU_HCI_MSG, event, OSI_THREAD_BLOCKING); + btu_task_post(SIG_BTU_HCI_MSG, event, OSI_THREAD_MAX_TIMEOUT); } /******************************************************************************* diff --git a/components/bt/bluedroid/stack/btu/btu_init.c b/components/bt/bluedroid/stack/btu/btu_init.c index bf3a55af8c..455cc9fe6a 100644 --- a/components/bt/bluedroid/stack/btu/btu_init.c +++ b/components/bt/bluedroid/stack/btu/btu_init.c @@ -186,7 +186,7 @@ void BTU_StartUp(void) goto error_exit; } - if (btu_task_post(SIG_BTU_START_UP, NULL, OSI_THREAD_BLOCKING) == false) { + if (btu_task_post(SIG_BTU_START_UP, NULL, OSI_THREAD_MAX_TIMEOUT) == false) { goto error_exit; } diff --git a/components/bt/bluedroid/stack/btu/btu_task.c b/components/bt/bluedroid/stack/btu/btu_task.c index 916811df1e..40448357d5 100644 --- a/components/bt/bluedroid/stack/btu/btu_task.c +++ b/components/bt/bluedroid/stack/btu/btu_task.c @@ -246,7 +246,7 @@ void btu_thread_handler(void *arg) osi_free(evt); } -bool btu_task_post(uint32_t sig, void *param, osi_thread_blocking_t blocking) +bool btu_task_post(uint32_t sig, void *param, uint32_t timeout) { btu_thread_evt_t *evt; @@ -258,7 +258,7 @@ bool btu_task_post(uint32_t sig, void *param, osi_thread_blocking_t blocking) evt->sig = sig; evt->param = param; - return osi_thread_post(btu_thread, btu_thread_handler, evt, 0, blocking); + return osi_thread_post(btu_thread, btu_thread_handler, evt, 0, timeout); } void btu_task_start_up(void) @@ -417,7 +417,7 @@ void btu_general_alarm_cb(void *data) assert(data != NULL); TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *)data; - btu_task_post(SIG_BTU_GENERAL_ALARM, p_tle, OSI_THREAD_BLOCKING); + btu_task_post(SIG_BTU_GENERAL_ALARM, p_tle, OSI_THREAD_MAX_TIMEOUT); } void btu_start_timer(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout_sec) @@ -531,7 +531,7 @@ static void btu_l2cap_alarm_cb(void *data) assert(data != NULL); TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *)data; - btu_task_post(SIG_BTU_L2CAP_ALARM, p_tle, OSI_THREAD_BLOCKING); + btu_task_post(SIG_BTU_L2CAP_ALARM, p_tle, OSI_THREAD_MAX_TIMEOUT); } void btu_start_quick_timer(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout_ticks) @@ -614,7 +614,7 @@ void btu_oneshot_alarm_cb(void *data) btu_stop_timer_oneshot(p_tle); - btu_task_post(SIG_BTU_ONESHOT_ALARM, p_tle, OSI_THREAD_BLOCKING); + btu_task_post(SIG_BTU_ONESHOT_ALARM, p_tle, OSI_THREAD_MAX_TIMEOUT); } /* diff --git a/components/bt/bluedroid/stack/gap/gap_ble.c b/components/bt/bluedroid/stack/gap/gap_ble.c index 08f7c195ce..5aab51fc1b 100644 --- a/components/bt/bluedroid/stack/gap/gap_ble.c +++ b/components/bt/bluedroid/stack/gap/gap_ble.c @@ -145,7 +145,7 @@ void gap_ble_dealloc_clcb(tGAP_CLCB *p_clcb) { tGAP_BLE_REQ *p_q; - while ((p_q = (tGAP_BLE_REQ *)fixed_queue_try_dequeue(p_clcb->pending_req_q)) != NULL) { + while ((p_q = (tGAP_BLE_REQ *)fixed_queue_dequeue(p_clcb->pending_req_q, 0)) != NULL) { /* send callback to all pending requests if being removed*/ if (p_q->p_cback != NULL) { (*p_q->p_cback)(FALSE, p_clcb->bda, 0, NULL); @@ -173,7 +173,7 @@ BOOLEAN gap_ble_enqueue_request (tGAP_CLCB *p_clcb, UINT16 uuid, tGAP_BLE_CMPL_C if (p_q != NULL) { p_q->p_cback = p_cback; p_q->uuid = uuid; - fixed_queue_enqueue(p_clcb->pending_req_q, p_q); + fixed_queue_enqueue(p_clcb->pending_req_q, p_q, FIXED_QUEUE_MAX_TIMEOUT); return TRUE; } @@ -190,7 +190,7 @@ BOOLEAN gap_ble_enqueue_request (tGAP_CLCB *p_clcb, UINT16 uuid, tGAP_BLE_CMPL_C *******************************************************************************/ BOOLEAN gap_ble_dequeue_request (tGAP_CLCB *p_clcb, UINT16 *p_uuid, tGAP_BLE_CMPL_CBACK **p_cback) { - tGAP_BLE_REQ *p_q = (tGAP_BLE_REQ *)fixed_queue_try_dequeue(p_clcb->pending_req_q);; + tGAP_BLE_REQ *p_q = (tGAP_BLE_REQ *)fixed_queue_dequeue(p_clcb->pending_req_q, 0);; if (p_q != NULL) { *p_cback = p_q->p_cback; diff --git a/components/bt/bluedroid/stack/gap/gap_conn.c b/components/bt/bluedroid/stack/gap/gap_conn.c index 671ffa7427..db9065de81 100644 --- a/components/bt/bluedroid/stack/gap/gap_conn.c +++ b/components/bt/bluedroid/stack/gap/gap_conn.c @@ -332,7 +332,7 @@ UINT16 GAP_ConnReadData (UINT16 gap_handle, UINT8 *p_data, UINT16 max_len, UINT1 p_buf->len -= copy_len; break; } - osi_free(fixed_queue_try_dequeue(p_ccb->rx_queue)); + osi_free(fixed_queue_dequeue(p_ccb->rx_queue, 0)); } p_ccb->rx_queue_size -= *p_len; @@ -404,7 +404,7 @@ UINT16 GAP_ConnBTRead (UINT16 gap_handle, BT_HDR **pp_buf) return (GAP_ERR_BAD_HANDLE); } - p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->rx_queue); + p_buf = (BT_HDR *)fixed_queue_dequeue(p_ccb->rx_queue, 0); if (p_buf) { *pp_buf = p_buf; @@ -451,7 +451,7 @@ UINT16 GAP_ConnBTWrite (UINT16 gap_handle, BT_HDR *p_buf) return (GAP_ERR_BUF_OFFSET); } - fixed_queue_enqueue(p_ccb->tx_queue, p_buf); + fixed_queue_enqueue(p_ccb->tx_queue, p_buf, FIXED_QUEUE_MAX_TIMEOUT); if (p_ccb->is_congested) { return (BT_PASS); @@ -461,7 +461,7 @@ UINT16 GAP_ConnBTWrite (UINT16 gap_handle, BT_HDR *p_buf) #if (GAP_CONN_POST_EVT_INCLUDED == TRUE) gap_send_event (gap_handle); #else - while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->tx_queue)) != NULL) { + while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_ccb->tx_queue, 0)) != NULL) { UINT8 status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf); if (status == L2CAP_DW_CONGESTED) { @@ -532,7 +532,7 @@ UINT16 GAP_ConnWriteData (UINT16 gap_handle, UINT8 *p_data, UINT16 max_len, UINT GAP_TRACE_EVENT ("GAP_WriteData %d bytes", p_buf->len); - fixed_queue_enqueue(p_ccb->tx_queue, p_buf); + fixed_queue_enqueue(p_ccb->tx_queue, p_buf, FIXED_QUEUE_MAX_TIMEOUT); } if (p_ccb->is_congested) { @@ -543,7 +543,7 @@ UINT16 GAP_ConnWriteData (UINT16 gap_handle, UINT8 *p_data, UINT16 max_len, UINT #if (GAP_CONN_POST_EVT_INCLUDED == TRUE) gap_send_event (gap_handle); #else - while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->tx_queue)) != NULL) + while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_ccb->tx_queue, 0)) != NULL) { UINT8 status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf); @@ -989,7 +989,7 @@ static void gap_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg) } if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED) { - fixed_queue_enqueue(p_ccb->rx_queue, p_msg); + fixed_queue_enqueue(p_ccb->rx_queue, p_msg, FIXED_QUEUE_MAX_TIMEOUT); p_ccb->rx_queue_size += p_msg->len; /* @@ -1033,7 +1033,7 @@ static void gap_congestion_ind (UINT16 lcid, BOOLEAN is_congested) p_ccb->p_callback (p_ccb->gap_handle, event); if (!is_congested) { - while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->tx_queue)) != NULL) { + while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_ccb->tx_queue, 0)) != NULL) { status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf); if (status == L2CAP_DW_CONGESTED) { @@ -1154,13 +1154,13 @@ static void gap_release_ccb (tGAP_CCB *p_ccb) p_ccb->rx_queue_size = 0; while (!fixed_queue_is_empty(p_ccb->rx_queue)) { - osi_free(fixed_queue_try_dequeue(p_ccb->rx_queue)); + osi_free(fixed_queue_dequeue(p_ccb->rx_queue, 0)); } fixed_queue_free(p_ccb->rx_queue, NULL); p_ccb->rx_queue = NULL; while (!fixed_queue_is_empty(p_ccb->tx_queue)) { - osi_free(fixed_queue_try_dequeue(p_ccb->tx_queue)); + osi_free(fixed_queue_dequeue(p_ccb->tx_queue, 0)); } fixed_queue_free(p_ccb->tx_queue, NULL); p_ccb->tx_queue = NULL; diff --git a/components/bt/bluedroid/stack/gatt/gatt_auth.c b/components/bt/bluedroid/stack/gatt/gatt_auth.c index e233ea0cad..b72cb6faee 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_auth.c +++ b/components/bt/bluedroid/stack/gatt/gatt_auth.c @@ -176,7 +176,7 @@ void gatt_enc_cmpl_cback(BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_d return; } tGATT_PENDING_ENC_CLCB *p_buf = - (tGATT_PENDING_ENC_CLCB *)fixed_queue_try_dequeue(p_tcb->pending_enc_clcb); + (tGATT_PENDING_ENC_CLCB *)fixed_queue_dequeue(p_tcb->pending_enc_clcb, 0); if (p_buf != NULL) { if (result == BTM_SUCCESS) { if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENCRYPT_MITM ) { @@ -194,7 +194,7 @@ void gatt_enc_cmpl_cback(BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_d /* start all other pending operation in queue */ for (size_t count = fixed_queue_length(p_tcb->pending_enc_clcb); count > 0; count--) { - p_buf = (tGATT_PENDING_ENC_CLCB *)fixed_queue_try_dequeue(p_tcb->pending_enc_clcb); + p_buf = (tGATT_PENDING_ENC_CLCB *)fixed_queue_dequeue(p_tcb->pending_enc_clcb, 0); if (p_buf != NULL) { gatt_security_check_start(p_buf->p_clcb); osi_free(p_buf); @@ -238,7 +238,7 @@ void gatt_notify_enc_cmpl(BD_ADDR bd_addr) size_t count = fixed_queue_length(p_tcb->pending_enc_clcb); for (; count > 0; count--) { tGATT_PENDING_ENC_CLCB *p_buf = - (tGATT_PENDING_ENC_CLCB *)fixed_queue_try_dequeue(p_tcb->pending_enc_clcb); + (tGATT_PENDING_ENC_CLCB *)fixed_queue_dequeue(p_tcb->pending_enc_clcb, 0); if (p_buf != NULL) { gatt_security_check_start(p_buf->p_clcb); osi_free(p_buf); diff --git a/components/bt/bluedroid/stack/gatt/gatt_db.c b/components/bt/bluedroid/stack/gatt/gatt_db.c index 8a05117482..a860e19e09 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_db.c +++ b/components/bt/bluedroid/stack/gatt/gatt_db.c @@ -1383,7 +1383,7 @@ static BOOLEAN allocate_svc_db_buf(tGATT_SVC_DB *p_db) p_db->p_free_mem = (UINT8 *) p_buf; p_db->mem_free = GATT_DB_BUF_SIZE; - fixed_queue_enqueue(p_db->svc_buffer, p_buf); + fixed_queue_enqueue(p_db->svc_buffer, p_buf, FIXED_QUEUE_MAX_TIMEOUT); return TRUE; diff --git a/components/bt/bluedroid/stack/gatt/gatt_sr.c b/components/bt/bluedroid/stack/gatt/gatt_sr.c index eccc9ec979..6bad33b5c8 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_sr.c +++ b/components/bt/bluedroid/stack/gatt/gatt_sr.c @@ -140,7 +140,7 @@ void gatt_dequeue_sr_cmd (tGATT_TCB *p_tcb) if (p_tcb->sr_cmd.multi_rsp_q) { while (!fixed_queue_is_empty(p_tcb->sr_cmd.multi_rsp_q)) { - osi_free(fixed_queue_try_dequeue(p_tcb->sr_cmd.multi_rsp_q)); + osi_free(fixed_queue_dequeue(p_tcb->sr_cmd.multi_rsp_q, 0)); } fixed_queue_free(p_tcb->sr_cmd.multi_rsp_q, NULL); } @@ -178,7 +178,7 @@ static BOOLEAN process_read_multi_rsp (tGATT_SR_CMD *p_cmd, tGATT_STATUS status, } memcpy((void *)p_buf, (const void *)p_msg, sizeof(tGATTS_RSP)); - fixed_queue_enqueue(p_cmd->multi_rsp_q, p_buf); + fixed_queue_enqueue(p_cmd->multi_rsp_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT); p_cmd->status = status; if (status == GATT_SUCCESS) { @@ -418,7 +418,7 @@ void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U //dequeue prepare write data while(fixed_queue_try_peek_first(prepare_record->queue)) { - queue_data = fixed_queue_dequeue(prepare_record->queue); + queue_data = fixed_queue_dequeue(prepare_record->queue, FIXED_QUEUE_MAX_TIMEOUT); if (is_prepare_write_valid){ if((queue_data->p_attr->p_value != NULL) && (queue_data->p_attr->p_value->attr_val.attr_val != NULL)){ if(is_first) { @@ -1291,7 +1291,7 @@ void gatt_attr_process_prepare_write (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 hand if (prepare_record->queue == NULL) { prepare_record->queue = fixed_queue_new(QUEUE_SIZE_MAX); } - fixed_queue_enqueue(prepare_record->queue, queue_data); + fixed_queue_enqueue(prepare_record->queue, queue_data, FIXED_QUEUE_MAX_TIMEOUT); } } diff --git a/components/bt/bluedroid/stack/gatt/gatt_utils.c b/components/bt/bluedroid/stack/gatt/gatt_utils.c index 2455f746f3..8f9303f0bb 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_utils.c +++ b/components/bt/bluedroid/stack/gatt/gatt_utils.c @@ -97,7 +97,7 @@ void gatt_free_pending_ind(tGATT_TCB *p_tcb) /* release all queued indications */ while (!fixed_queue_is_empty(p_tcb->pending_ind_q)) { - osi_free(fixed_queue_try_dequeue(p_tcb->pending_ind_q)); + osi_free(fixed_queue_dequeue(p_tcb->pending_ind_q, 0)); } fixed_queue_free(p_tcb->pending_ind_q, NULL); p_tcb->pending_ind_q = NULL; @@ -121,7 +121,7 @@ void gatt_free_pending_enc_queue(tGATT_TCB *p_tcb) /* release all queued indications */ while (!fixed_queue_is_empty(p_tcb->pending_enc_clcb)) { - osi_free(fixed_queue_try_dequeue(p_tcb->pending_enc_clcb)); + osi_free(fixed_queue_dequeue(p_tcb->pending_enc_clcb, 0)); } fixed_queue_free(p_tcb->pending_enc_clcb, NULL); p_tcb->pending_enc_clcb = NULL; @@ -143,7 +143,7 @@ void gatt_free_pending_prepare_write_queue(tGATT_TCB *p_tcb) if (p_tcb->prepare_write_record.queue) { /* release all queued prepare write packets */ while (!fixed_queue_is_empty(p_tcb->prepare_write_record.queue)) { - osi_free(fixed_queue_dequeue(p_tcb->prepare_write_record.queue)); + osi_free(fixed_queue_dequeue(p_tcb->prepare_write_record.queue, FIXED_QUEUE_MAX_TIMEOUT)); } fixed_queue_free(p_tcb->prepare_write_record.queue, NULL); p_tcb->prepare_write_record.queue = NULL; @@ -265,7 +265,7 @@ tGATT_VALUE *gatt_add_pending_ind(tGATT_TCB *p_tcb, tGATT_VALUE *p_ind) if ((p_buf = (tGATT_VALUE *)osi_malloc((UINT16)sizeof(tGATT_VALUE))) != NULL) { GATT_TRACE_DEBUG ("enqueue a pending indication"); memcpy(p_buf, p_ind, sizeof(tGATT_VALUE)); - fixed_queue_enqueue(p_tcb->pending_ind_q, p_buf); + fixed_queue_enqueue(p_tcb->pending_ind_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT); } return p_buf; } @@ -288,7 +288,7 @@ tGATTS_PENDING_NEW_SRV_START *gatt_add_pending_new_srv_start(tGATTS_HNDL_RANGE * if ((p_buf = (tGATTS_PENDING_NEW_SRV_START *)osi_malloc((UINT16)sizeof(tGATTS_PENDING_NEW_SRV_START))) != NULL) { GATT_TRACE_DEBUG ("enqueue a new pending new srv start"); p_buf->p_new_srv_start = p_new_srv_start; - fixed_queue_enqueue(gatt_cb.pending_new_srv_start_q, p_buf); + fixed_queue_enqueue(gatt_cb.pending_new_srv_start_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT); } return p_buf; } @@ -310,7 +310,7 @@ tGATTS_SRV_CHG *gatt_add_srv_chg_clt(tGATTS_SRV_CHG *p_srv_chg) if ((p_buf = (tGATTS_SRV_CHG *)osi_malloc((UINT16)sizeof(tGATTS_SRV_CHG))) != NULL) { GATT_TRACE_DEBUG ("enqueue a srv chg client"); memcpy(p_buf, p_srv_chg, sizeof(tGATTS_SRV_CHG)); - fixed_queue_enqueue(gatt_cb.srv_chg_clt_q, p_buf); + fixed_queue_enqueue(gatt_cb.srv_chg_clt_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT); } return p_buf; @@ -469,7 +469,7 @@ void gatt_free_hdl_buffer(tGATT_HDL_LIST_ELEM *p) if (p) { while (!fixed_queue_is_empty(p->svc_db.svc_buffer)) { - osi_free(fixed_queue_try_dequeue(p->svc_db.svc_buffer)); + osi_free(fixed_queue_dequeue(p->svc_db.svc_buffer, 0)); } fixed_queue_free(p->svc_db.svc_buffer, NULL); memset(p, 0, sizeof(tGATT_HDL_LIST_ELEM)); @@ -495,7 +495,7 @@ void gatt_free_srvc_db_buffer_app_id(tBT_UUID *p_app_id) if (memcmp(p_app_id, &p_elem->asgn_range.app_uuid128, sizeof(tBT_UUID)) == 0) { gatt_free_attr_value_buffer(p_elem); while (!fixed_queue_is_empty(p_elem->svc_db.svc_buffer)) { - osi_free(fixed_queue_try_dequeue(p_elem->svc_db.svc_buffer)); + osi_free(fixed_queue_dequeue(p_elem->svc_db.svc_buffer, 0)); } fixed_queue_free(p_elem->svc_db.svc_buffer, NULL); p_elem->svc_db.svc_buffer = NULL; @@ -2733,7 +2733,7 @@ tGATT_PENDING_ENC_CLCB *gatt_add_pending_enc_channel_clcb(tGATT_TCB *p_tcb, tGAT if ((p_buf = (tGATT_PENDING_ENC_CLCB *)osi_malloc((UINT16)sizeof(tGATT_PENDING_ENC_CLCB))) != NULL) { GATT_TRACE_DEBUG ("enqueue a new pending encryption channel clcb"); p_buf->p_clcb = p_clcb; - fixed_queue_enqueue(p_tcb->pending_enc_clcb, p_buf); + fixed_queue_enqueue(p_tcb->pending_enc_clcb, p_buf, FIXED_QUEUE_MAX_TIMEOUT); } return p_buf; } diff --git a/components/bt/bluedroid/stack/include/stack/btu.h b/components/bt/bluedroid/stack/include/stack/btu.h index a038ded1e1..b3269e2ca6 100644 --- a/components/bt/bluedroid/stack/include/stack/btu.h +++ b/components/bt/bluedroid/stack/include/stack/btu.h @@ -288,7 +288,7 @@ void btu_task_shut_down(void); UINT16 BTU_BleAclPktSize(void); -bool btu_task_post(uint32_t sig, void *param, osi_thread_blocking_t blocking); +bool btu_task_post(uint32_t sig, void *param, uint32_t timeout); /* #ifdef __cplusplus diff --git a/components/bt/bluedroid/stack/l2cap/l2c_api.c b/components/bt/bluedroid/stack/l2cap/l2c_api.c index 9a50d4ba72..4074cef841 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_api.c +++ b/components/bt/bluedroid/stack/l2cap/l2c_api.c @@ -2221,7 +2221,7 @@ UINT16 L2CA_FlushChannel (UINT16 lcid, UINT16 num_to_flush) /* If needed, flush buffers in the CCB xmit hold queue */ while ( (num_to_flush != 0) && (!fixed_queue_is_empty(p_ccb->xmit_hold_q))) { - BT_HDR *p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_hold_q); + BT_HDR *p_buf = (BT_HDR *)fixed_queue_dequeue(p_ccb->xmit_hold_q, 0); if (p_buf) { osi_free (p_buf); } diff --git a/components/bt/bluedroid/stack/l2cap/l2c_ble.c b/components/bt/bluedroid/stack/l2cap/l2c_ble.c index b4e347335f..300acefe8a 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_ble.c +++ b/components/bt/bluedroid/stack/l2cap/l2c_ble.c @@ -1361,7 +1361,7 @@ void l2cble_sec_comp(BD_ADDR p_bda, tBT_TRANSPORT transport, void *p_ref_data, if (!fixed_queue_is_empty(p_lcb->le_sec_pending_q)) { - p_buf = (tL2CAP_SEC_DATA*) fixed_queue_dequeue(p_lcb->le_sec_pending_q); + p_buf = (tL2CAP_SEC_DATA*) fixed_queue_dequeue(p_lcb->le_sec_pending_q, FIXED_QUEUE_MAX_TIMEOUT); if (!p_buf) { L2CAP_TRACE_WARNING ("%s Security complete for request not initiated from L2CAP", @@ -1406,7 +1406,7 @@ void l2cble_sec_comp(BD_ADDR p_bda, tBT_TRANSPORT transport, void *p_ref_data, while (!fixed_queue_is_empty(p_lcb->le_sec_pending_q)) { - p_buf = (tL2CAP_SEC_DATA*) fixed_queue_dequeue(p_lcb->le_sec_pending_q); + p_buf = (tL2CAP_SEC_DATA*) fixed_queue_dequeue(p_lcb->le_sec_pending_q, FIXED_QUEUE_MAX_TIMEOUT); if (status != BTM_SUCCESS) { (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data, status); @@ -1462,7 +1462,7 @@ BOOLEAN l2ble_sec_access_req(BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_originator, p_buf->is_originator = is_originator; p_buf->p_callback = p_callback; p_buf->p_ref_data = p_ref_data; - fixed_queue_enqueue(p_lcb->le_sec_pending_q, p_buf); + fixed_queue_enqueue(p_lcb->le_sec_pending_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT); status = btm_ble_start_sec_check(bd_addr, psm, is_originator, &l2cble_sec_comp, p_ref_data); return status; diff --git a/components/bt/bluedroid/stack/l2cap/l2c_csm.c b/components/bt/bluedroid/stack/l2cap/l2c_csm.c index ddfe53dba3..ff7fbb0ec0 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_csm.c +++ b/components/bt/bluedroid/stack/l2cap/l2c_csm.c @@ -1243,7 +1243,7 @@ void l2c_enqueue_peer_data (tL2C_CCB *p_ccb, BT_HDR *p_buf) UINT16_TO_STREAM (p, p_ccb->remote_cid); } - fixed_queue_enqueue(p_ccb->xmit_hold_q, p_buf); + fixed_queue_enqueue(p_ccb->xmit_hold_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT); l2cu_check_channel_congestion (p_ccb); diff --git a/components/bt/bluedroid/stack/l2cap/l2c_fcr.c b/components/bt/bluedroid/stack/l2cap/l2c_fcr.c index 3a7085c803..ecf0bd6c68 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_fcr.c +++ b/components/bt/bluedroid/stack/l2cap/l2c_fcr.c @@ -752,7 +752,7 @@ void l2c_fcr_proc_pdu (tL2C_CCB *p_ccb, BT_HDR *p_buf) fixed_queue_t *temp_q = p_ccb->fcrb.srej_rcv_hold_q; p_ccb->fcrb.srej_rcv_hold_q = fixed_queue_new(QUEUE_SIZE_MAX); - while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(temp_q)) != NULL) { + while ((p_buf = (BT_HDR *)fixed_queue_dequeue(temp_q, 0)) != NULL) { if (p_ccb->in_use && (p_ccb->chnl_state == CST_OPEN)) { /* Get the control word */ p = ((UINT8 *)(p_buf + 1)) + p_buf->offset - L2CAP_FCR_OVERHEAD; @@ -921,7 +921,7 @@ static BOOLEAN process_reqseq (tL2C_CCB *p_ccb, UINT16 ctrl_word) #endif for (xx = 0; xx < num_bufs_acked; xx++) { - BT_HDR *p_tmp = (BT_HDR *)fixed_queue_try_dequeue(p_fcrb->waiting_for_ack_q); + BT_HDR *p_tmp = (BT_HDR *)fixed_queue_dequeue(p_fcrb->waiting_for_ack_q, 0); ls = p_tmp->layer_specific & L2CAP_FCR_SAR_BITS; if ( (ls == L2CAP_FCR_UNSEG_SDU) || (ls == L2CAP_FCR_END_SDU) ) { @@ -1118,7 +1118,7 @@ static void process_i_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, UINT16 ctrl_word, B num_lost, tx_seq, p_fcrb->next_seq_expected, p_fcrb->rej_sent); p_buf->layer_specific = tx_seq; - fixed_queue_enqueue(p_fcrb->srej_rcv_hold_q, p_buf); + fixed_queue_enqueue(p_fcrb->srej_rcv_hold_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT); } else { L2CAP_TRACE_WARNING ("process_i_frame() CID: 0x%04x frame dropped in Srej Sent next_srej:%u hold_q.count:%u win_sz:%u", p_ccb->local_cid, next_srej, fixed_queue_length(p_fcrb->srej_rcv_hold_q), p_ccb->our_cfg.fcr.tx_win_sz); @@ -1147,7 +1147,7 @@ static void process_i_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, UINT16 ctrl_word, B p_ccb->local_cid, tx_seq, fixed_queue_length(p_fcrb->srej_rcv_hold_q)); } p_buf->layer_specific = tx_seq; - fixed_queue_enqueue(p_fcrb->srej_rcv_hold_q, p_buf); + fixed_queue_enqueue(p_fcrb->srej_rcv_hold_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT); p_fcrb->srej_sent = TRUE; l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_SREJ, 0); } @@ -1471,7 +1471,7 @@ static BOOLEAN retransmit_i_frames (tL2C_CCB *p_ccb, UINT8 tx_seq) /* Also flush our retransmission queue */ while (!fixed_queue_is_empty(p_ccb->fcrb.retrans_q)) { - osi_free(fixed_queue_try_dequeue(p_ccb->fcrb.retrans_q)); + osi_free(fixed_queue_dequeue(p_ccb->fcrb.retrans_q, 0)); } if (list_ack != NULL) { @@ -1490,7 +1490,7 @@ static BOOLEAN retransmit_i_frames (tL2C_CCB *p_ccb, UINT8 tx_seq) { p_buf2->layer_specific = p_buf->layer_specific; - fixed_queue_enqueue(p_ccb->fcrb.retrans_q, p_buf2); + fixed_queue_enqueue(p_ccb->fcrb.retrans_q, p_buf2, FIXED_QUEUE_MAX_TIMEOUT); } if ( (tx_seq != L2C_FCR_RETX_ALL_PKTS) || (p_buf2 == NULL) ) { @@ -1534,7 +1534,7 @@ BT_HDR *l2c_fcr_get_next_xmit_sdu_seg (tL2C_CCB *p_ccb, UINT16 max_packet_length /* If there is anything in the retransmit queue, that goes first */ - p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->fcrb.retrans_q); + p_buf = (BT_HDR *)fixed_queue_dequeue(p_ccb->fcrb.retrans_q, 0); if (p_buf != NULL) { /* Update Rx Seq and FCS if we acked some packets while this one was queued */ prepare_I_frame (p_ccb, p_buf, TRUE); @@ -1586,7 +1586,7 @@ BT_HDR *l2c_fcr_get_next_xmit_sdu_seg (tL2C_CCB *p_ccb, UINT16 max_packet_length return (NULL); } } else { /* Use the original buffer if no segmentation, or the last segment */ - p_xmit = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_hold_q); + p_xmit = (BT_HDR *)fixed_queue_dequeue(p_ccb->xmit_hold_q, 0); if (p_xmit->event != 0) { last_seg = TRUE; @@ -1647,7 +1647,7 @@ BT_HDR *l2c_fcr_get_next_xmit_sdu_seg (tL2C_CCB *p_ccb, UINT16 max_packet_length } /* Pretend we sent it and it got lost */ - fixed_queue_enqueue(p_ccb->fcrb.waiting_for_ack_q, p_xmit); + fixed_queue_enqueue(p_ccb->fcrb.waiting_for_ack_q, p_xmit, FIXED_QUEUE_MAX_TIMEOUT); return (NULL); } else { #if (L2CAP_ERTM_STATS == TRUE) @@ -1661,7 +1661,7 @@ BT_HDR *l2c_fcr_get_next_xmit_sdu_seg (tL2C_CCB *p_ccb, UINT16 max_packet_length } p_wack->layer_specific = p_xmit->layer_specific; - fixed_queue_enqueue(p_ccb->fcrb.waiting_for_ack_q, p_wack); + fixed_queue_enqueue(p_ccb->fcrb.waiting_for_ack_q, p_wack, FIXED_QUEUE_MAX_TIMEOUT); } #if (L2CAP_ERTM_STATS == TRUE) diff --git a/components/bt/bluedroid/stack/l2cap/l2c_ucd.c b/components/bt/bluedroid/stack/l2cap/l2c_ucd.c index 8618042c5b..2b130c3490 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_ucd.c +++ b/components/bt/bluedroid/stack/l2cap/l2c_ucd.c @@ -596,13 +596,13 @@ void l2c_ucd_delete_sec_pending_q(tL2C_LCB *p_lcb) { /* clean up any security pending UCD */ while (p_lcb->ucd_out_sec_pending_q.p_first) { - osi_free(fixed_queue_try_dequeue(p_lcb->ucd_out_sec_pending_q)); + osi_free(fixed_queue_dequeue(p_lcb->ucd_out_sec_pending_q, 0)); } fixed_queue_free(p_lcb->ucd_out_sec_pending_q, NULL); p_lcb->ucd_out_sec_pending_q = NULL; while (! fixed_queue_is_empty(p_lcb->ucd_in_sec_pending_q)) { - osi_free(fixed_queue_try_dequeue(p_lcb->ucd_in_sec_pending_q)); + osi_free(fixed_queue_dequeue(p_lcb->ucd_in_sec_pending_q, 0)); } fixed_queue_free(p_lcb->ucd_in_sec_pending_q); p_lcb->ucd_in_sec_pending_q = NULL; @@ -683,7 +683,7 @@ BOOLEAN l2c_ucd_check_pending_info_req(tL2C_CCB *p_ccb) *******************************************************************************/ void l2c_ucd_enqueue_pending_out_sec_q(tL2C_CCB *p_ccb, void *p_data) { - fixed_queue_enqueue(p_ccb->p_lcb->ucd_out_sec_pending_q, p_data); + fixed_queue_enqueue(p_ccb->p_lcb->ucd_out_sec_pending_q, p_data, FIXED_QUEUE_MAX_TIMEOUT); l2cu_check_channel_congestion (p_ccb); } @@ -727,7 +727,7 @@ BOOLEAN l2c_ucd_check_pending_out_sec_q(tL2C_CCB *p_ccb) *******************************************************************************/ void l2c_ucd_send_pending_out_sec_q(tL2C_CCB *p_ccb) { - BT_HDR *p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_out_sec_pending_q); + BT_HDR *p_buf = (BT_HDR*)fixed_queue_dequeue(p_ccb->p_lcb->ucd_out_sec_pending_q, 0); if (p_buf != NULL) { l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_buf); @@ -747,7 +747,7 @@ void l2c_ucd_send_pending_out_sec_q(tL2C_CCB *p_ccb) *******************************************************************************/ void l2c_ucd_discard_pending_out_sec_q(tL2C_CCB *p_ccb) { - BT_HDR *p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_out_sec_pending_q); + BT_HDR *p_buf = (BT_HDR*)fixed_queue_dequeue(p_ccb->p_lcb->ucd_out_sec_pending_q, 0); /* we may need to report to application */ @@ -767,7 +767,7 @@ void l2c_ucd_discard_pending_out_sec_q(tL2C_CCB *p_ccb) *******************************************************************************/ BOOLEAN l2c_ucd_check_pending_in_sec_q(tL2C_CCB *p_ccb) { - BT_HDR *p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_in_sec_pending_q); + BT_HDR *p_buf = (BT_HDR*)fixed_queue_dequeue(p_ccb->p_lcb->ucd_in_sec_pending_q, 0); if (p_buf != NULL) { UINT16 psm; @@ -795,7 +795,7 @@ BOOLEAN l2c_ucd_check_pending_in_sec_q(tL2C_CCB *p_ccb) *******************************************************************************/ void l2c_ucd_send_pending_in_sec_q(tL2C_CCB *p_ccb) { - BT_HDR *p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_in_sec_pending_q) + BT_HDR *p_buf = (BT_HDR*)fixed_queue_dequeue(p_ccb->p_lcb->ucd_in_sec_pending_q, 0) if (p_buf != NULL) { p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Data_Cb(p_ccb->p_lcb->remote_bd_addr, (BT_HDR *)p_buf); @@ -814,7 +814,7 @@ void l2c_ucd_send_pending_in_sec_q(tL2C_CCB *p_ccb) *******************************************************************************/ void l2c_ucd_discard_pending_in_sec_q(tL2C_CCB *p_ccb) { - BT_HDR *p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_in_sec_pending_q); + BT_HDR *p_buf = (BT_HDR*)fixed_queue_dequeue(p_ccb->p_lcb->ucd_in_sec_pending_q, 0); if (p_buf) { osi_free (p_buf); @@ -898,7 +898,7 @@ BOOLEAN l2c_ucd_process_event(tL2C_CCB *p_ccb, UINT16 event, void *p_data) break; case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */ - fixed_queue_enqueue(p_ccb->p_lcb->ucd_in_sec_pending_q, p_data); + fixed_queue_enqueue(p_ccb->p_lcb->ucd_in_sec_pending_q, p_data, FIXED_QUEUE_MAX_TIMEOUT); break; case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */ @@ -958,7 +958,7 @@ BOOLEAN l2c_ucd_process_event(tL2C_CCB *p_ccb, UINT16 event, void *p_data) break; case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */ - fixed_queue_enqueue(p_ccb->p_lcb->ucd_in_sec_pending_q, p_data); + fixed_queue_enqueue(p_ccb->p_lcb->ucd_in_sec_pending_q, p_data, FIXED_QUEUE_MAX_TIMEOUT); break; case L2CEVT_L2CAP_INFO_RSP: @@ -1006,7 +1006,7 @@ BOOLEAN l2c_ucd_process_event(tL2C_CCB *p_ccb, UINT16 event, void *p_data) break; case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */ - fixed_queue_enqueue(p_ccb->p_lcb->ucd_in_sec_pending_q, p_data); + fixed_queue_enqueue(p_ccb->p_lcb->ucd_in_sec_pending_q, p_data, FIXED_QUEUE_MAX_TIMEOUT); break; case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */ @@ -1033,7 +1033,7 @@ BOOLEAN l2c_ucd_process_event(tL2C_CCB *p_ccb, UINT16 event, void *p_data) /* stop idle timer of UCD */ btu_stop_timer (&p_ccb->timer_entry); - fixed_queue_enqueue(p_ccb->p_lcb->ucd_in_sec_pending_q, p_data); + fixed_queue_enqueue(p_ccb->p_lcb->ucd_in_sec_pending_q, p_data, FIXED_QUEUE_MAX_TIMEOUT); l2c_ucd_check_pending_in_sec_q (p_ccb); break; diff --git a/components/bt/bluedroid/stack/l2cap/l2c_utils.c b/components/bt/bluedroid/stack/l2cap/l2c_utils.c index 92e1eede37..841e510a9a 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_utils.c +++ b/components/bt/bluedroid/stack/l2cap/l2c_utils.c @@ -249,7 +249,7 @@ void l2cu_release_lcb (tL2C_LCB *p_lcb) { while (!fixed_queue_is_empty(p_lcb->le_sec_pending_q)) { - tL2CAP_SEC_DATA *p_buf = (tL2CAP_SEC_DATA*) fixed_queue_dequeue(p_lcb->le_sec_pending_q); + tL2CAP_SEC_DATA *p_buf = (tL2CAP_SEC_DATA*) fixed_queue_dequeue(p_lcb->le_sec_pending_q, FIXED_QUEUE_MAX_TIMEOUT); if (p_buf->p_callback) { p_buf->p_callback(p_lcb->remote_bd_addr, p_lcb->transport, p_buf->p_ref_data, BTM_DEV_RESET); } @@ -930,7 +930,7 @@ void l2cu_send_peer_disc_req (tL2C_CCB *p_ccb) layer checks that all buffers are sent before disconnecting. */ if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE) { - while ((p_buf2 = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_hold_q)) != NULL) { + while ((p_buf2 = (BT_HDR *)fixed_queue_dequeue(p_ccb->xmit_hold_q, 0)) != NULL) { l2cu_set_acl_hci_header (p_buf2, p_ccb); l2c_link_check_send_pkts (p_ccb->p_lcb, p_ccb, p_buf2); } @@ -3488,7 +3488,7 @@ BT_HDR *l2cu_get_next_buffer_to_send (tL2C_LCB *p_lcb) } else { if (!fixed_queue_is_empty(p_ccb->xmit_hold_q)) { - p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_hold_q); + p_buf = (BT_HDR *)fixed_queue_dequeue(p_ccb->xmit_hold_q, 0); if (NULL == p_buf) { L2CAP_TRACE_ERROR("l2cu_get_buffer_to_send: No data to be sent"); return (NULL); @@ -3525,7 +3525,7 @@ BT_HDR *l2cu_get_next_buffer_to_send (tL2C_LCB *p_lcb) } } else { - p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_hold_q); + p_buf = (BT_HDR *)fixed_queue_dequeue(p_ccb->xmit_hold_q, 0); if (NULL == p_buf) { L2CAP_TRACE_ERROR("l2cu_get_buffer_to_send() #2: No data to be sent"); return (NULL); diff --git a/components/bt/bluedroid/stack/rfcomm/port_api.c b/components/bt/bluedroid/stack/rfcomm/port_api.c index 64f09149e6..f6e0ed4d4f 100644 --- a/components/bt/bluedroid/stack/rfcomm/port_api.c +++ b/components/bt/bluedroid/stack/rfcomm/port_api.c @@ -1098,7 +1098,7 @@ int PORT_Purge (UINT16 handle, UINT8 purge_flags) count = fixed_queue_length(p_port->rx.queue); - while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->rx.queue)) != NULL) { + while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_port->rx.queue, 0)) != NULL) { osi_free (p_buf); } @@ -1115,7 +1115,7 @@ int PORT_Purge (UINT16 handle, UINT8 purge_flags) if (purge_flags & PORT_PURGE_TXCLEAR) { osi_mutex_global_lock(); /* to prevent tx.queue_size from being negative */ - while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->tx.queue)) != NULL) { + while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_port->tx.queue, 0)) != NULL) { osi_free (p_buf); } @@ -1218,7 +1218,7 @@ int PORT_ReadData (UINT16 handle, char *p_data, UINT16 max_len, UINT16 *p_len) p_data += p_buf->len; } - osi_free(fixed_queue_try_dequeue(p_port->rx.queue)); + osi_free(fixed_queue_dequeue(p_port->rx.queue, 0)); osi_mutex_global_unlock(); @@ -1274,7 +1274,7 @@ int PORT_Read (UINT16 handle, BT_HDR **pp_buf) osi_mutex_global_lock(); - p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->rx.queue); + p_buf = (BT_HDR *)fixed_queue_dequeue(p_port->rx.queue, 0); if (p_buf) { p_port->rx.queue_size -= p_buf->len; @@ -1340,7 +1340,7 @@ static int port_write (tPORT *p_port, BT_HDR *p_buf) p_port->rfc.state, p_port->port_ctrl); - fixed_queue_enqueue(p_port->tx.queue, p_buf); + fixed_queue_enqueue(p_port->tx.queue, p_buf, FIXED_QUEUE_MAX_TIMEOUT); p_port->tx.queue_size += p_buf->len; return (PORT_CMD_PENDING); diff --git a/components/bt/bluedroid/stack/rfcomm/port_rfc.c b/components/bt/bluedroid/stack/rfcomm/port_rfc.c index 46b3e07116..4a47fb46ca 100644 --- a/components/bt/bluedroid/stack/rfcomm/port_rfc.c +++ b/components/bt/bluedroid/stack/rfcomm/port_rfc.c @@ -869,7 +869,7 @@ void PORT_DataInd (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf) osi_mutex_global_lock(); - fixed_queue_enqueue(p_port->rx.queue, p_buf); + fixed_queue_enqueue(p_port->rx.queue, p_buf, FIXED_QUEUE_MAX_TIMEOUT); p_port->rx.queue_size += p_buf->len; osi_mutex_global_unlock(); @@ -976,7 +976,7 @@ UINT32 port_rfc_send_tx_data (tPORT *p_port) /* get data from tx queue and send it */ osi_mutex_global_lock(); - if ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->tx.queue)) != NULL) { + if ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_port->tx.queue, 0)) != NULL) { p_port->tx.queue_size -= p_buf->len; osi_mutex_global_unlock(); diff --git a/components/bt/bluedroid/stack/rfcomm/port_utils.c b/components/bt/bluedroid/stack/rfcomm/port_utils.c index 0da8b3d76b..0b08c0f1f3 100644 --- a/components/bt/bluedroid/stack/rfcomm/port_utils.c +++ b/components/bt/bluedroid/stack/rfcomm/port_utils.c @@ -210,13 +210,13 @@ void port_release_port (tPORT *p_port) osi_mutex_global_lock(); RFCOMM_TRACE_DEBUG("port_release_port, p_port:%p", p_port); - while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->rx.queue)) != NULL) { + while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_port->rx.queue, 0)) != NULL) { osi_free (p_buf); } p_port->rx.queue_size = 0; - while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->tx.queue)) != NULL) { + while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_port->tx.queue, 0)) != NULL) { osi_free (p_buf); } diff --git a/components/bt/bluedroid/stack/rfcomm/rfc_mx_fsm.c b/components/bt/bluedroid/stack/rfcomm/rfc_mx_fsm.c index 6d1bf3c93a..dd2af3b803 100644 --- a/components/bt/bluedroid/stack/rfcomm/rfc_mx_fsm.c +++ b/components/bt/bluedroid/stack/rfcomm/rfc_mx_fsm.c @@ -488,7 +488,7 @@ void rfc_mx_sm_state_disc_wait_ua (tRFC_MCB *p_mcb, UINT16 event, void *p_data) rfc_save_lcid_mcb (p_mcb, p_mcb->lcid); /* clean up before reuse it */ - while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_mcb->cmd_q)) != NULL) { + while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_mcb->cmd_q, 0)) != NULL) { osi_free(p_buf); } diff --git a/components/bt/bluedroid/stack/rfcomm/rfc_utils.c b/components/bt/bluedroid/stack/rfcomm/rfc_utils.c index 8b1e043116..0d1fbdcb39 100644 --- a/components/bt/bluedroid/stack/rfcomm/rfc_utils.c +++ b/components/bt/bluedroid/stack/rfcomm/rfc_utils.c @@ -492,12 +492,12 @@ void rfc_check_send_cmd(tRFC_MCB *p_mcb, BT_HDR *p_buf) __func__, p_mcb, p_mcb->lcid, rfc_find_lcid_mcb(p_mcb->lcid)); } - fixed_queue_enqueue(p_mcb->cmd_q, p_buf); + fixed_queue_enqueue(p_mcb->cmd_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT); } /* handle queue if L2CAP not congested */ while (p_mcb->l2cap_congested == FALSE) { - if ((p = (BT_HDR *)fixed_queue_try_dequeue(p_mcb->cmd_q)) == NULL) { + if ((p = (BT_HDR *)fixed_queue_dequeue(p_mcb->cmd_q, 0)) == NULL) { break; } From 8024fcb296309515cd5169f0be8d93460e11c92f Mon Sep 17 00:00:00 2001 From: baohongde Date: Wed, 24 Apr 2019 15:04:24 +0800 Subject: [PATCH 099/486] components/bt: Add more functions for memory debug. --- components/bt/bluedroid/osi/allocator.c | 83 ++++++++++++++++--- .../bt/bluedroid/osi/include/osi/allocator.h | 5 +- 2 files changed, 76 insertions(+), 12 deletions(-) diff --git a/components/bt/bluedroid/osi/allocator.c b/components/bt/bluedroid/osi/allocator.c index 624a11c176..569bb5f021 100644 --- a/components/bt/bluedroid/osi/allocator.c +++ b/components/bt/bluedroid/osi/allocator.c @@ -36,11 +36,17 @@ typedef struct { } osi_mem_dbg_info_t; static uint32_t mem_dbg_count = 0; -static uint32_t mem_dbg_count2 = 0; static osi_mem_dbg_info_t mem_dbg_info[OSI_MEM_DBG_INFO_MAX]; -static uint32_t mem_dbg_total_size = 0; +static uint32_t mem_dbg_current_size = 0; static uint32_t mem_dbg_max_size = 0; +#define OSI_MEM_DBG_MAX_SECTION_NUM 5 +typedef struct { + bool used; + uint32_t max_size; +} osi_mem_dbg_max_size_section_t; +static osi_mem_dbg_max_size_section_t mem_dbg_max_size_section[OSI_MEM_DBG_MAX_SECTION_NUM]; + void osi_mem_dbg_init(void) { int i; @@ -52,9 +58,13 @@ void osi_mem_dbg_init(void) mem_dbg_info[i].line = 0; } mem_dbg_count = 0; - mem_dbg_count2 = 0; - mem_dbg_total_size = 0; + mem_dbg_current_size = 0; mem_dbg_max_size = 0; + + for (i = 0; i < OSI_MEM_DBG_MAX_SECTION_NUM; i++){ + mem_dbg_max_size_section[i].used = false; + mem_dbg_max_size_section[i].max_size = 0; + } } void osi_mem_dbg_record(void *p, int size, const char *func, int line) @@ -81,9 +91,17 @@ void osi_mem_dbg_record(void *p, int size, const char *func, int line) OSI_TRACE_ERROR("%s full %s %d !!\n", __func__, func, line); } - mem_dbg_total_size += size; - if(mem_dbg_max_size < mem_dbg_total_size) { - mem_dbg_max_size = mem_dbg_total_size; + mem_dbg_current_size += size; + if(mem_dbg_max_size < mem_dbg_current_size) { + mem_dbg_max_size = mem_dbg_current_size; + } + + for (i = 0; i < OSI_MEM_DBG_MAX_SECTION_NUM; i++){ + if (mem_dbg_max_size_section[i].used) { + if(mem_dbg_max_size_section[i].max_size < mem_dbg_current_size) { + mem_dbg_max_size_section[i].max_size = mem_dbg_current_size; + } + } } } @@ -98,7 +116,7 @@ void osi_mem_dbg_clean(void *p, const char *func, int line) for (i = 0; i < OSI_MEM_DBG_INFO_MAX; i++) { if (mem_dbg_info[i].p == p) { - mem_dbg_total_size -= mem_dbg_info[i].size; + mem_dbg_current_size -= mem_dbg_info[i].size; mem_dbg_info[i].p = NULL; mem_dbg_info[i].size = 0; mem_dbg_info[i].func = NULL; @@ -123,7 +141,7 @@ void osi_mem_dbg_show(void) } } OSI_TRACE_ERROR("--> count %d\n", mem_dbg_count); - OSI_TRACE_ERROR("--> size %dB\n--> max size %dB\n", mem_dbg_total_size, mem_dbg_max_size); + OSI_TRACE_ERROR("--> size %dB\n--> max size %dB\n", mem_dbg_current_size, mem_dbg_max_size); } uint32_t osi_mem_dbg_get_max_size(void) @@ -131,9 +149,52 @@ uint32_t osi_mem_dbg_get_max_size(void) return mem_dbg_max_size; } -uint32_t osi_mem_dbg_get_total_size(void) +uint32_t osi_mem_dbg_get_current_size(void) { - return mem_dbg_total_size; + return mem_dbg_current_size; +} + +void osi_men_dbg_set_section_start(uint8_t index) +{ + if (index >= OSI_MEM_DBG_MAX_SECTION_NUM) { + OSI_TRACE_ERROR("Then range of index should be between 0 and %d, current index is %d.\n", + OSI_MEM_DBG_MAX_SECTION_NUM - 1, index); + return; + } + + if (mem_dbg_max_size_section[index].used) { + OSI_TRACE_WARNING("This index(%d) has been started, restart it.\n", index); + } + + mem_dbg_max_size_section[index].used = true; + mem_dbg_max_size_section[index].max_size = mem_dbg_current_size; +} + +void osi_men_dbg_set_section_end(uint8_t index) +{ + if (index >= OSI_MEM_DBG_MAX_SECTION_NUM) { + OSI_TRACE_ERROR("Then range of index should be between 0 and %d, current index is %d.\n", + OSI_MEM_DBG_MAX_SECTION_NUM - 1, index); + return; + } + + if (!mem_dbg_max_size_section[index].used) { + OSI_TRACE_ERROR("This index(%d) has not been started.\n", index); + return; + } + + mem_dbg_max_size_section[index].used = false; +} + +uint32_t osi_mem_dbg_get_max_size_section(uint8_t index) +{ + if (index >= OSI_MEM_DBG_MAX_SECTION_NUM){ + OSI_TRACE_ERROR("Then range of index should be between 0 and %d, current index is %d.\n", + OSI_MEM_DBG_MAX_SECTION_NUM - 1, index); + return 0; + } + + return mem_dbg_max_size_section[index].max_size; } #endif diff --git a/components/bt/bluedroid/osi/include/osi/allocator.h b/components/bt/bluedroid/osi/include/osi/allocator.h index f5e87a473a..579f2b2bb6 100644 --- a/components/bt/bluedroid/osi/include/osi/allocator.h +++ b/components/bt/bluedroid/osi/include/osi/allocator.h @@ -36,7 +36,10 @@ void osi_mem_dbg_record(void *p, int size, const char *func, int line); void osi_mem_dbg_clean(void *p, const char *func, int line); void osi_mem_dbg_show(void); uint32_t osi_mem_dbg_get_max_size(void); -uint32_t osi_mem_dbg_get_total_size(void); +uint32_t osi_mem_dbg_get_current_size(void); +void osi_men_dbg_set_section_start(uint8_t index); +void osi_men_dbg_set_section_end(uint8_t index); +uint32_t osi_mem_dbg_get_max_size_section(uint8_t index); #if HEAP_ALLOCATION_FROM_SPIRAM_FIRST #define osi_malloc(size) \ From f2e6ba8701e0b1d3dd59b01c255df1db7458fdaf Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Thu, 20 Jun 2019 16:25:51 +0800 Subject: [PATCH 100/486] component/bt: clear BT/BLE interrupts after controller_disable to overwrite the default non-zero value of intcntl registers --- components/bt/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/lib b/components/bt/lib index 45df297ff2..471f03c2ca 160000 --- a/components/bt/lib +++ b/components/bt/lib @@ -1 +1 @@ -Subproject commit 45df297ff295c106171d8c3621216e9f48f7d8b4 +Subproject commit 471f03c2ca55225a600d3783dd277a910bfe80ed From 4bd4c7caf3f9ef8402c5a27ab44561537407eb60 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 20 Jun 2019 14:12:15 +0200 Subject: [PATCH 101/486] mdns: fix ignoring mdns packet with some invalid name entries in question field In case of invalid name entry, only this entry is invalidated and parsing continues as other query entries could contain questions to be responded to --- components/mdns/mdns.c | 9 +++++---- components/mdns/private_include/mdns_private.h | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index e88672f82b..fe4a03ba89 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -174,7 +174,7 @@ static const uint8_t * _mdns_read_fqdn(const uint8_t * packet, const uint8_t * s size_t index = 0; while (start[index]) { if (name->parts == 4) { - return NULL; + name->invalid = true; } uint8_t len = start[index++]; if (len < 0xC0) { @@ -195,7 +195,7 @@ static const uint8_t * _mdns_read_fqdn(const uint8_t * packet, const uint8_t * s strlcat(name->host, buf, sizeof(name->host)); } else if (strcasecmp(buf, MDNS_SUB_STR) == 0) { name->sub = 1; - } else { + } else if (!name->invalid) { char* mdns_name_ptrs[]={name->host, name->service, name->proto, name->domain}; memcpy(mdns_name_ptrs[name->parts++], buf, len+1); } @@ -2315,6 +2315,7 @@ static const uint8_t * _mdns_parse_fqdn(const uint8_t * packet, const uint8_t * name->service[0] = 0; name->proto[0] = 0; name->domain[0] = 0; + name->invalid = false; static char buf[MDNS_NAME_BUF_LEN]; @@ -2322,7 +2323,7 @@ static const uint8_t * _mdns_parse_fqdn(const uint8_t * packet, const uint8_t * if (!next_data) { return 0; } - if (!name->parts) { + if (!name->parts || name->invalid) { return next_data; } if (name->parts == 3) { @@ -2620,7 +2621,7 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) clas &= 0x7FFF; content = content + 4; - if (clas != 0x0001) {//bad class + if (clas != 0x0001 || name->invalid) {//bad class or invalid name for this question entry continue; } diff --git a/components/mdns/private_include/mdns_private.h b/components/mdns/private_include/mdns_private.h index e3becf28ff..ed7e89cb8f 100644 --- a/components/mdns/private_include/mdns_private.h +++ b/components/mdns/private_include/mdns_private.h @@ -184,6 +184,7 @@ typedef struct { char domain[MDNS_NAME_BUF_LEN]; uint8_t parts; uint8_t sub; + bool invalid; } mdns_name_t; typedef struct mdns_parsed_question_s { From 813c9dcf223115293de070e327923ee5cb84389a Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Fri, 10 May 2019 13:52:23 +0800 Subject: [PATCH 102/486] ethernet: add eth2ap example This example illustrates how to do Layer2 packet forwarding bussiness between Wi-Fi and Ethernet. --- examples/ethernet/eth2ap/CMakeLists.txt | 4 + examples/ethernet/eth2ap/Makefile | 8 + examples/ethernet/eth2ap/README.md | 114 ++++++++ examples/ethernet/eth2ap/eth2ap.png | Bin 0 -> 88732 bytes examples/ethernet/eth2ap/main/CMakeLists.txt | 6 + .../ethernet/eth2ap/main/Kconfig.projbuild | 111 +++++++ examples/ethernet/eth2ap/main/component.mk | 4 + .../eth2ap/main/eth2ap_example_main.c | 275 ++++++++++++++++++ examples/ethernet/eth2ap/sdkconfig.defaults | 1 + 9 files changed, 523 insertions(+) create mode 100644 examples/ethernet/eth2ap/CMakeLists.txt create mode 100644 examples/ethernet/eth2ap/Makefile create mode 100644 examples/ethernet/eth2ap/README.md create mode 100644 examples/ethernet/eth2ap/eth2ap.png create mode 100644 examples/ethernet/eth2ap/main/CMakeLists.txt create mode 100644 examples/ethernet/eth2ap/main/Kconfig.projbuild create mode 100644 examples/ethernet/eth2ap/main/component.mk create mode 100644 examples/ethernet/eth2ap/main/eth2ap_example_main.c create mode 100644 examples/ethernet/eth2ap/sdkconfig.defaults diff --git a/examples/ethernet/eth2ap/CMakeLists.txt b/examples/ethernet/eth2ap/CMakeLists.txt new file mode 100644 index 0000000000..5a2b416c7f --- /dev/null +++ b/examples/ethernet/eth2ap/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(eth2ap) diff --git a/examples/ethernet/eth2ap/Makefile b/examples/ethernet/eth2ap/Makefile new file mode 100644 index 0000000000..fe024c7f62 --- /dev/null +++ b/examples/ethernet/eth2ap/Makefile @@ -0,0 +1,8 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := eth2ap + +include $(IDF_PATH)/make/project.mk diff --git a/examples/ethernet/eth2ap/README.md b/examples/ethernet/eth2ap/README.md new file mode 100644 index 0000000000..2a4989440d --- /dev/null +++ b/examples/ethernet/eth2ap/README.md @@ -0,0 +1,114 @@ +# eth2ap Example +(See the README.md file in the upper level 'examples' directory for more information about examples. To try a more complex application about Ethernet to WiFi data forwarding, please go to [iot-solution](https://github.com/espressif/esp-iot-solution/tree/master/examples/eth2wifi).) + +## Overview +![eth2ap](eth2ap.png) + +The similarities on MAC layer between Ethernet and Wi-Fi make it easy to forward packets from Ethernet to Wi-Fi and vice versa. This example illustrates how to implement a simple "router" which only supports forwarding packets between Ethernet port and Wi-Fi AP interface. In this case, the Ethernet should play the role of WAN (i.e. it can access outside network) so that a mobile device could get access to the Internet when it gets connected to ESP32 through Wi-Fi. + +**Note:** In this example, ESP32 works like a *bridge* between Ethernet and Wi-Fi, and it won't perform any actions on Layer3 and higher layer, which means there's no need to initialize the TCP/IP stack. + +## How to use this example + +### Hardware Required + +To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports three Ethernet PHY: `TLK110`, `LAN8720` and `IP101`, additional PHY drivers should be implemented by users themselves. + +### Configure the project + +Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you are using CMake based build system. Then go into `Example Configuration` menu. + +* Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board. +* Set PHY address under `Ethernet PHY address`, it should depend on the PHY configuration of your hardware. You'd better consult the schematic of the board. By default, the PHY address of **ESP32-Ethernet-Kit** is *1*. +* Check whether or not to control the power of PHY chip under `Use PHY Power (enable / disable) pin`, (if set true, you also need to give the GPIO number of that pin under `PHY Power GPIO`). +* Set SMI MDC/MDIO GPIO number according to board schematic, by default they are set as below: + + | Default Example GPIO | RMII Signal | Notes | + | -------------------- | ----------- | ------------- | + | GPIO23 | MDC | Output to PHY | + | GPIO18 | MDIO | Bidirectional | + +* Select one kind of RMII clock mode under `Ethernet RMII Clock Mode` option. Possible configurations of the clock are listed as below. By default, ESP32-Ethernet-Kit use the `GPIO0 input` mode, which gives a good performance when enabling Ethernet and Wi-Fi at the same time. + + | Mode | GPIO Pin | Signal name | Notes | + | -------- | -------- | ------------ | ------------------------------------------------------------ | + | external | GPIO0 | EMAC_TX_CLK | Input of 50MHz PHY clock | + | internal | GPIO0 | CLK_OUT1 | Output of 50MHz APLL clock | + | internal | GPIO16 | EMAC_CLK_OUT | Output of 50MHz APLL clock | + | internal | GPIO17 | EMAC_CLK_180 | Inverted output of 50MHz APLL clock (suitable for long clock trace) | + + * External RMII clock must be connected to `GPIO0`. + * ESP32 can generate the RMII clock(50MHz) using its internal APLL. But if the APLL has already been used for other peripheral (e.g. I²S), you'd better choose the external clock. + +* Set the SSID and password for Wi-Fi ap interface under `Wi-Fi SSID` and `Wi-Fi Password`. +* Set the maximum connection number under `Maximum STA connections`. + +### Build and Flash + +To build and flash the example, enter `make -j4 flash monitor` if you are using GNU Make based build system or enter `idf.py build flash monitor` if you are using CMake based build system. + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +### Step 1: Initialize Ethernet and Wi-Fi (AP mode) + +```bash +I (508) example: Power On Ethernet PHY +I (518) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE +I (518) emac: emac reset done +I (518) example: Ethernet Started +...... +I (538) wifi: wifi driver task: 3ffc7fbc, prio:23, stack:3584, core=0 +I (538) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE +I (538) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE +I (568) wifi: wifi firmware version: ec61a20 +I (568) wifi: config NVS flash: enabled +I (568) wifi: config nano formating: disabled +I (568) wifi: Init dynamic tx buffer num: 32 +I (568) wifi: Init data frame dynamic rx buffer num: 32 +I (578) wifi: Init management frame dynamic rx buffer num: 32 +I (588) wifi: Init management short buffer num: 32 +I (588) wifi: Init static rx buffer size: 1600 +I (588) wifi: Init static rx buffer num: 10 +I (598) wifi: Init dynamic rx buffer num: 32 +``` + +### Step 2: Ethernet Connects to Router/Switch/PC (with DHCP server enabled) + +```bash +I (4518) example: Ethernet Link Up +``` + +### Step 3: Start Wi-Fi AP + +```bash +I (4618) phy: phy_version: 4100, 2a5dd04, Jan 23 2019, 21:00:07, 0, 0 +I (4618) wifi: mode : softAP (30:ae:a4:c6:87:5b) +I (4628) wifi: Total power save buffer number: 16 +I (4628) wifi: Init max length of beacon: 752/752 +I (4628) wifi: Init max length of beacon: 752/752 +``` + +### Step 4: Wi-Fi station (e.g. mobile phone) connects to ESP32's Wi-Fi + +```bash +I (10168) wifi: new:<1,0>, old:<1,0>, ap:<1,1>, sta:<255,255>, prof:1 +I (10168) wifi: station: c4:0b:cb:ec:9a:84 join, AID=1, bgn, 20 +I (10258) example: AP got a station connected +``` + +Now your mobile phone should get access to the Internet. + +## Troubleshooting + +* Got error message `emac: emac rx buf err` when running the example. + * This example just forwards the packets on the Layer2 between Wi-Fi and Ethernet, it won't do any Layer3 business. So make sure you have disabled the `CONFIG_ETH_EMAC_L2_TO_L3_RX_BUF_MODE`. By default, this option is false in the `sdkconfig.defaults` file. + +* Got error message `example: WiFi send packet failed: -1` when running the example. + * Ethernet process packets faster than Wi-Fi on ESP32, so have a try to enlarge the value of `FLOW_CONTROL_WIFI_SEND_DELAY_MS`. + +* Wi-Fi station doesn't receive any IP via DHCP. + * All Layer 3 (TCP/IP functions) on the ESP32 are disabled, including the SoftAP DHCP server. This means that devices must be able to access another DHCP server (for example on a Wi-Fi router connected via ethernet) or should use statically assigned IP addresses. diff --git a/examples/ethernet/eth2ap/eth2ap.png b/examples/ethernet/eth2ap/eth2ap.png new file mode 100644 index 0000000000000000000000000000000000000000..39e59aa14fccc872f69dc5d7a752ef6aeded9f6b GIT binary patch literal 88732 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 literal 0 HcmV?d00001 diff --git a/examples/ethernet/eth2ap/main/CMakeLists.txt b/examples/ethernet/eth2ap/main/CMakeLists.txt new file mode 100644 index 0000000000..aaf55bea54 --- /dev/null +++ b/examples/ethernet/eth2ap/main/CMakeLists.txt @@ -0,0 +1,6 @@ + +set(COMPONENT_SRCS "eth2ap_example_main.c") + +set(COMPONENT_ADD_INCLUDEDIRS ".") + +register_component() diff --git a/examples/ethernet/eth2ap/main/Kconfig.projbuild b/examples/ethernet/eth2ap/main/Kconfig.projbuild new file mode 100644 index 0000000000..70dce6b386 --- /dev/null +++ b/examples/ethernet/eth2ap/main/Kconfig.projbuild @@ -0,0 +1,111 @@ +menu "Example Configuration" + + choice EXAMPLE_PHY_MODEL + prompt "Ethernet PHY Device" + default EXAMPLE_PHY_IP101 + help + Select the PHY driver to use for the example. + config EXAMPLE_PHY_IP101 + bool "IP101" + help + IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver. + Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it. + config EXAMPLE_PHY_TLK110 + bool "TLK110" + help + TLK110 is an Industrial 10/100Mbps Ethernet Physical Layer Transceiver. + Goto http://www.ti.com/product/TLK110 for information about it. + config EXAMPLE_PHY_LAN8720 + bool "LAN8720" + help + LAN8720 is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support. + Goto https://www.microchip.com/LAN8720A for more information about it. + endchoice + + config EXAMPLE_PHY_ADDRESS + int "Ethernet PHY Address" + default 1 + range 0 31 + help + PHY Address of your PHY device. It depends on your schematic design. + + choice EXAMPLE_PHY_CLOCK_MODE + prompt "Ethernet RMII Clock Mode" + default EXAMPLE_PHY_CLOCK_GPIO0_IN + help + Select external (input on GPIO0) or internal (output on GPIO0, GPIO16 or GPIO17) RMII clock. + config EXAMPLE_PHY_CLOCK_GPIO0_IN + bool "GPIO0 Input" + help + Input of 50MHz RMII clock on GPIO0. + config EXAMPLE_PHY_CLOCK_GPIO0_OUT + bool "GPIO0 Output" + help + Output the internal 50MHz RMII clock on GPIO0. + config EXAMPLE_PHY_CLOCK_GPIO16_OUT + bool "GPIO16 Output" + help + Output the internal 50MHz RMII clock on GPIO16. + config EXAMPLE_PHY_CLOCK_GPIO17_OUT + bool "GPIO17 Output (inverted)" + help + Output the internal 50MHz RMII clock on GPIO17 (inverted signal). + endchoice + + config EXAMPLE_PHY_CLOCK_MODE + int + default 0 if EXAMPLE_PHY_CLOCK_GPIO0_IN + default 1 if EXAMPLE_PHY_CLOCK_GPIO0_OUT + default 2 if EXAMPLE_PHY_CLOCK_GPIO16_OUT + default 3 if EXAMPLE_PHY_CLOCK_GPIO17_OUT + + config EXAMPLE_PHY_USE_POWER_PIN + bool "Use PHY Power (enable / disable) pin" + default y + help + Use a GPIO "power pin" to power the PHY on/off during operation. + When using GPIO0 to input RMII clock, the reset process will be interfered by this clock. + So we need another GPIO to control the switch on / off of the RMII clock. + + if EXAMPLE_PHY_USE_POWER_PIN + config EXAMPLE_PHY_POWER_PIN + int "PHY power pin" + default 5 + range 0 33 + help + Set the GPIO number used for powering on/off the PHY. + endif + + config EXAMPLE_PHY_SMI_MDC_PIN + int "Ethernet SMI MDC gpio number" + default 23 + range 0 33 + help + GPIO number used for SMI clock signal. + + config EXAMPLE_PHY_SMI_MDIO_PIN + int "Ethernet SMI MDIO gpio number" + default 18 + range 0 33 + help + GPIO number used for SMI data signal. + + config EXAMPLE_WIFI_SSID + string "Wi-Fi SSID" + default "eth2ap" + help + Set the SSID of Wi-Fi ap interface. + + config EXAMPLE_WIFI_PASSWORD + string "Wi-Fi Password" + default "12345678" + help + Set the password of Wi-Fi ap interface. + + config EXAMPLE_MAX_STA_CONN + int "Maximum STA connections" + default 4 + help + Maximum number of the station that allowed to connect to current Wi-Fi hotspot. + +endmenu diff --git a/examples/ethernet/eth2ap/main/component.mk b/examples/ethernet/eth2ap/main/component.mk new file mode 100644 index 0000000000..a98f634eae --- /dev/null +++ b/examples/ethernet/eth2ap/main/component.mk @@ -0,0 +1,4 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/ethernet/eth2ap/main/eth2ap_example_main.c b/examples/ethernet/eth2ap/main/eth2ap_example_main.c new file mode 100644 index 0000000000..ca64cfc7c1 --- /dev/null +++ b/examples/ethernet/eth2ap/main/eth2ap_example_main.c @@ -0,0 +1,275 @@ +/* eth2ap (Ethernet to Wi-Fi AP packet forwarding) Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "esp_event_loop.h" +#include "esp_event.h" +#include "esp_log.h" +#include "esp_eth.h" +#include "esp_wifi.h" +#include "nvs_flash.h" +#include "esp_private/wifi.h" +#include "driver/gpio.h" +#include "sdkconfig.h" + +// Choose the default phy config according to Kconfig +#if CONFIG_EXAMPLE_PHY_LAN8720 +#include "eth_phy/phy_lan8720.h" +#define DEFAULT_ETHERNET_PHY_CONFIG phy_lan8720_default_ethernet_config +#elif CONFIG_EXAMPLE_PHY_TLK110 +#include "eth_phy/phy_tlk110.h" +#define DEFAULT_ETHERNET_PHY_CONFIG phy_tlk110_default_ethernet_config +#elif CONFIG_EXAMPLE_PHY_IP101 +#include "eth_phy/phy_ip101.h" +#define DEFAULT_ETHERNET_PHY_CONFIG phy_ip101_default_ethernet_config +#endif + +#define FLOW_CONTROL_QUEUE_TIMEOUT_MS (100) +#define FLOW_CONTROL_QUEUE_LENGTH (10) +#define FLOW_CONTROL_WIFI_SEND_TIMEOUT_MS (100) + +static const char *TAG = "example"; + +typedef struct { + void *packet; + uint16_t length; +} flow_control_msg_t; + +static xQueueHandle flow_control_queue = NULL; + +static bool s_sta_is_connected = false; +static bool s_ethernet_is_connected = false; +static uint8_t s_eth_mac[6]; + +#ifdef CONFIG_EXAMPLE_PHY_USE_POWER_PIN +/** + * @brief power control function for phy + * + * @param enable: set true to enable PHY power, set false to disable PHY power + * + * @note This function replaces the default PHY power on/off function. + * If this GPIO is not connected on your device (and PHY is always powered), + * you can use the default PHY-specific power on/off function. + */ +static void phy_device_power_enable_via_gpio(bool enable) +{ + assert(DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable); + if (!enable) { + /* call the default PHY-specific power off function */ + DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(false); + } + gpio_pad_select_gpio(CONFIG_EXAMPLE_PHY_POWER_PIN); + gpio_set_direction(CONFIG_EXAMPLE_PHY_POWER_PIN, GPIO_MODE_OUTPUT); + if (enable) { + gpio_set_level(CONFIG_EXAMPLE_PHY_POWER_PIN, 1); + ESP_LOGI(TAG, "Power On Ethernet PHY"); + } else { + gpio_set_level(CONFIG_EXAMPLE_PHY_POWER_PIN, 0); + ESP_LOGI(TAG, "Power Off Ethernet PHY"); + } + vTaskDelay(1); + if (enable) { + /* call the default PHY-specific power on function */ + DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(true); + } +} +#endif + +/** + * @brief gpio specific init + * + * @note RMII data pins are fixed in esp32 as follows: + * TXD0 <=> GPIO19 + * TXD1 <=> GPIO22 + * TX_EN <=> GPIO21 + * RXD0 <=> GPIO25 + * RXD1 <=> GPIO26 + * CLK <=> GPIO0 + * + */ +static void eth_gpio_config_rmii(void) +{ + phy_rmii_configure_data_interface_pins(); + phy_rmii_smi_configure_pins(CONFIG_EXAMPLE_PHY_SMI_MDC_PIN, CONFIG_EXAMPLE_PHY_SMI_MDIO_PIN); +} + +// Forward packets from Wi-Fi to Ethernet +static esp_err_t pkt_wifi2eth(void *buffer, uint16_t len, void *eb) +{ + if (s_ethernet_is_connected) { + if (esp_eth_tx(buffer, len) != ESP_OK) { + ESP_LOGE(TAG, "Ethernet send packet failed"); + } + } + esp_wifi_internal_free_rx_buffer(eb); + return ESP_OK; +} + +// Forward packets from Ethernet to Wi-Fi +// Note that, Ethernet works faster than Wi-Fi on ESP32, +// so we need to add an extra queue to balance their speed difference. +static esp_err_t pkt_eth2wifi(void *buffer, uint16_t len, void *eb) +{ + esp_err_t ret = ESP_OK; + flow_control_msg_t msg = { + .packet = buffer, + .length = len + }; + if (xQueueSend(flow_control_queue, &msg, pdMS_TO_TICKS(FLOW_CONTROL_QUEUE_TIMEOUT_MS)) != pdTRUE) { + ESP_LOGE(TAG, "send flow control message failed or timeout"); + ret = ESP_FAIL; + } + return ret; +} + +// This task will fetch the packet from the queue, and then send out through Wi-Fi. +// Wi-Fi handles packets slower than Ethernet, we might add some delay between each transmitting. +static void eth2wifi_flow_control_task(void *args) +{ + flow_control_msg_t msg; + int res = 0; + uint32_t timeout = 0; + while (1) { + if (xQueueReceive(flow_control_queue, &msg, pdMS_TO_TICKS(FLOW_CONTROL_QUEUE_TIMEOUT_MS)) == pdTRUE) { + timeout = 0; + if (s_sta_is_connected && msg.length > 4) { + do { + vTaskDelay(pdMS_TO_TICKS(timeout)); + timeout += 2; + res = esp_wifi_internal_tx(ESP_IF_WIFI_AP, msg.packet, msg.length - 4); + } while (res == -1 && timeout < FLOW_CONTROL_WIFI_SEND_TIMEOUT_MS); + if (res != ESP_OK) { + ESP_LOGE(TAG, "WiFi send packet failed: %d", res); + } + } + esp_eth_free_rx_buf(msg.packet); + } + } + vTaskDelete(NULL); +} + +// Event handler for Ethernet +static void eth_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + switch (event_id) { + case ETHERNET_EVENT_CONNECTED: + ESP_LOGI(TAG, "Ethernet Link Up"); + s_ethernet_is_connected = true; + esp_eth_get_mac(s_eth_mac); + esp_wifi_set_mac(WIFI_IF_AP, s_eth_mac); + ESP_ERROR_CHECK(esp_wifi_start()); + break; + case ETHERNET_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "Ethernet Link Down"); + s_ethernet_is_connected = false; + ESP_ERROR_CHECK(esp_wifi_stop()); + break; + case ETHERNET_EVENT_START: + ESP_LOGI(TAG, "Ethernet Started"); + break; + case ETHERNET_EVENT_STOP: + ESP_LOGI(TAG, "Ethernet Stopped"); + break; + default: + break; + } +} + +// Event handler for Wi-Fi +static void wifi_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + switch (event_id) { + case WIFI_EVENT_AP_STACONNECTED: + ESP_LOGI(TAG, "Wi-Fi AP got a station connected"); + s_sta_is_connected = true; + esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_AP, pkt_wifi2eth); + break; + case WIFI_EVENT_AP_STADISCONNECTED: + ESP_LOGI(TAG, "Wi-Fi AP got a station disconnected"); + s_sta_is_connected = false; + esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_AP, NULL); + break; + default: + break; + } +} + +static void initialize_ethernet(void) +{ + eth_config_t config = DEFAULT_ETHERNET_PHY_CONFIG; + config.phy_addr = CONFIG_EXAMPLE_PHY_ADDRESS; + config.gpio_config = eth_gpio_config_rmii; + config.clock_mode = CONFIG_EXAMPLE_PHY_CLOCK_MODE; + config.tcpip_input = pkt_eth2wifi; + config.promiscuous_enable = true; +#ifdef CONFIG_EXAMPLE_PHY_USE_POWER_PIN + /* Replace the default 'power enable' function with an example-specific one that toggles a power GPIO. */ + config.phy_power_enable = phy_device_power_enable_via_gpio; +#endif + ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler, NULL)); + ESP_ERROR_CHECK(esp_eth_init_internal(&config)); + ESP_ERROR_CHECK(esp_eth_enable()); +} + +static void initialize_wifi(void) +{ + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler, NULL)); + ESP_ERROR_CHECK(esp_wifi_init_internal(&cfg)); + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); + wifi_config_t wifi_config = { + .ap = { + .ssid = CONFIG_EXAMPLE_WIFI_SSID, + .ssid_len = strlen(CONFIG_EXAMPLE_WIFI_SSID), + .password = CONFIG_EXAMPLE_WIFI_PASSWORD, + .max_connection = CONFIG_EXAMPLE_MAX_STA_CONN, + .authmode = WIFI_AUTH_WPA_WPA2_PSK + }, + }; + if (strlen(CONFIG_EXAMPLE_WIFI_PASSWORD) == 0) { + wifi_config.ap.authmode = WIFI_AUTH_OPEN; + } + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); + ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config)); +} + +static esp_err_t initialize_flow_control(void) +{ + flow_control_queue = xQueueCreate(FLOW_CONTROL_QUEUE_LENGTH, sizeof(flow_control_msg_t)); + if (!flow_control_queue) { + ESP_LOGE(TAG, "create flow control queue failed"); + return ESP_FAIL; + } + BaseType_t ret = xTaskCreate(eth2wifi_flow_control_task, "flow_ctl", 2048, NULL, (tskIDLE_PRIORITY + 2), NULL); + if (ret != pdTRUE) { + ESP_LOGE(TAG, "create flow control task failed"); + return ESP_FAIL; + } + return ESP_OK; +} + +void app_main() +{ + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + ESP_ERROR_CHECK(initialize_flow_control()); + + initialize_ethernet(); + initialize_wifi(); +} diff --git a/examples/ethernet/eth2ap/sdkconfig.defaults b/examples/ethernet/eth2ap/sdkconfig.defaults new file mode 100644 index 0000000000..710208fe53 --- /dev/null +++ b/examples/ethernet/eth2ap/sdkconfig.defaults @@ -0,0 +1 @@ +CONFIG_ETH_EMAC_L2_TO_L3_RX_BUF_MODE=n From 430d9c6fba0ab328d3dd7b39a16ed6d40e48d7d8 Mon Sep 17 00:00:00 2001 From: redchenjs Date: Tue, 18 Jun 2019 13:52:36 +0800 Subject: [PATCH 103/486] i2s: fix a bug when calculating i2s apll parameters Closes https://github.com/espressif/esp-idf/issues/2634 Closes https://github.com/espressif/esp-idf/issues/3380 Fixes https://github.com/espressif/esp-idf/issues/3407 --- components/driver/i2s.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/components/driver/i2s.c b/components/driver/i2s.c index 02322b341a..2056c43f1f 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -253,7 +253,7 @@ static esp_err_t i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, _sdm2, 0); min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, _sdm2, 31); avg = (max_rate + min_rate)/2; - if(abs(avg - rate) < min_diff) { + if (abs(avg - rate) < min_diff) { min_diff = abs(avg - rate); *sdm2 = _sdm2; } @@ -263,11 +263,21 @@ static esp_err_t i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, *sdm2, _odir); min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, *sdm2, _odir); avg = (max_rate + min_rate)/2; - if(abs(avg - rate) < min_diff) { + if (abs(avg - rate) < min_diff) { min_diff = abs(avg - rate); *odir = _odir; } } + min_diff = APLL_MAX_FREQ; + for (_sdm2 = 4; _sdm2 < 9; _sdm2 ++) { + max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, _sdm2, *odir); + min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, _sdm2, *odir); + avg = (max_rate + min_rate)/2; + if (abs(avg - rate) < min_diff) { + min_diff = abs(avg - rate); + *sdm2 = _sdm2; + } + } min_diff = APLL_MAX_FREQ; for (_sdm1 = 0; _sdm1 < 256; _sdm1 ++) { From 070b86eee5cbeac19368d0212c01f56fd376e7b2 Mon Sep 17 00:00:00 2001 From: Ajita Chavan Date: Wed, 19 Jun 2019 16:06:20 +0530 Subject: [PATCH 104/486] i2s: test case for variation in apll clock rate --- components/driver/i2s.c | 9 +++++ components/driver/include/driver/i2s.h | 10 +++++ components/driver/test/test_i2s.c | 53 ++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/components/driver/i2s.c b/components/driver/i2s.c index 2056c43f1f..56c418d153 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -89,6 +89,7 @@ typedef struct { bool use_apll; /*!< I2S use APLL clock */ bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor on underflow */ int fixed_mclk; /*!< I2S fixed MLCK clock */ + double real_rate; #ifdef CONFIG_PM_ENABLE esp_pm_lock_handle_t pm_lock; #endif @@ -178,6 +179,12 @@ esp_err_t i2s_enable_tx_intr(i2s_port_t i2s_num) return ESP_OK; } +float i2s_get_clk(i2s_port_t i2s_num) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + return p_i2s_obj[i2s_num]->real_rate; +} + static esp_err_t i2s_isr_register(i2s_port_t i2s_num, int intr_alloc_flags, void (*fn)(void*), void * arg, i2s_isr_handle_t *handle) { return esp_intr_alloc(ETS_I2S0_INTR_SOURCE + i2s_num, intr_alloc_flags, fn, arg, handle); @@ -465,6 +472,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b I2S[i2s_num]->sample_rate_conf.rx_bck_div_num = m_scale; I2S[i2s_num]->clkm_conf.clka_en = 1; double fi2s_rate = i2s_apll_get_fi2s(bits, sdm0, sdm1, sdm2, odir); + p_i2s_obj[i2s_num]->real_rate = fi2s_rate/bits/channel/m_scale; ESP_LOGI(I2S_TAG, "APLL: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK_M: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d", rate, fi2s_rate/bits/channel/m_scale, bits, 1, m_scale, fi2s_rate, fi2s_rate/8, 1, 0); } else { @@ -475,6 +483,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b I2S[i2s_num]->sample_rate_conf.tx_bck_div_num = bck; I2S[i2s_num]->sample_rate_conf.rx_bck_div_num = bck; double real_rate = (double) (I2S_BASE_CLK / (bck * bits * clkmInteger) / 2); + p_i2s_obj[i2s_num]->real_rate = real_rate; ESP_LOGI(I2S_TAG, "PLL_D2: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d", rate, real_rate, bits, clkmInteger, bck, (double)I2S_BASE_CLK / mclk, real_rate*bits*channel, 64, clkmDecimals); } diff --git a/components/driver/include/driver/i2s.h b/components/driver/include/driver/i2s.h index 59c11978e5..c00be6632f 100644 --- a/components/driver/include/driver/i2s.h +++ b/components/driver/include/driver/i2s.h @@ -501,6 +501,16 @@ esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num); */ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t bits, i2s_channel_t ch); +/** + * @brief get clock set on particular port number. + * + * @param i2s_num I2S_NUM_0, I2S_NUM_1 + * + * @return + * - actual clock set by i2s driver + */ +float i2s_get_clk(i2s_port_t i2s_num); + /** * @brief Set built-in ADC mode for I2S DMA, this function will initialize ADC pad, * and set ADC parameters. diff --git a/components/driver/test/test_i2s.c b/components/driver/test/test_i2s.c index 3afb24412f..813a906cb5 100644 --- a/components/driver/test/test_i2s.c +++ b/components/driver/test/test_i2s.c @@ -9,6 +9,7 @@ #include "freertos/task.h" #include "driver/i2s.h" #include "unity.h" +#include "math.h" #define SAMPLE_RATE (36000) #define SAMPLE_BITS (16) @@ -18,6 +19,7 @@ #define SLAVE_WS_IO 26 #define DATA_IN_IO 21 #define DATA_OUT_IO 22 +#define PERCENT_DIFF 0.0001 /** * i2s initialize test @@ -267,3 +269,54 @@ TEST_CASE("I2S memory leaking test", "[i2s]") vTaskDelay(100 / portTICK_PERIOD_MS); TEST_ASSERT(initial_size == esp_get_free_heap_size()); } + +/* + * The I2S APLL clock variation test used to test the difference between the different sample rates, different bits per sample + * and the APLL clock generate for it. The TEST_CASE passes PERCENT_DIFF variation from the provided sample rate in APLL generated clock + * The percentage difference calculated as (mod((obtained clock rate - desired clock rate)/(desired clock rate))) * 100. + */ +TEST_CASE("I2S APLL clock variation test", "[i2s]") +{ + i2s_pin_config_t pin_config = { + .bck_io_num = MASTER_BCK_IO, + .ws_io_num = MASTER_WS_IO, + .data_out_num = DATA_OUT_IO, + .data_in_num = -1 + }; + + i2s_config_t i2s_config = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = SAMPLE_RATE, + .bits_per_sample = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_I2S, + .dma_buf_count = 6, + .dma_buf_len = 60, + .use_apll = true, + .intr_alloc_flags = 0, + }; + + TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL)); + TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &pin_config)); + TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0)); + int initial_size = esp_get_free_heap_size(); + + uint32_t sample_rate_arr[8] = { 10675, 11025, 16000, 22050, 32000, 44100, 48000, 96000 }; + int bits_per_sample_arr[3] = { 16, 24, 32 }; + + for (int i = 0; i < (sizeof(sample_rate_arr)/sizeof(sample_rate_arr[0])); i++) { + for (int j = 0; j < (sizeof(bits_per_sample_arr)/sizeof(bits_per_sample_arr[0])); j++) { + i2s_config.sample_rate = sample_rate_arr[i]; + i2s_config.bits_per_sample = bits_per_sample_arr[j]; + + TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL)); + TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &pin_config)); + TEST_ASSERT((fabs((i2s_get_clk(I2S_NUM_0) - sample_rate_arr[i]))/(sample_rate_arr[i]))*100 < PERCENT_DIFF); + TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0)); + TEST_ASSERT(initial_size == esp_get_free_heap_size()); + } + } + + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ASSERT(initial_size == esp_get_free_heap_size()); +} From e0a652f164c49a726edbe8d9a2559001e967e86d Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Sun, 5 May 2019 15:42:39 +0800 Subject: [PATCH 105/486] spiffs: add ability to specify dependencies when dirs themselves are generated --- components/spiffs/Makefile.projbuild | 2 +- components/spiffs/project_include.cmake | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/components/spiffs/Makefile.projbuild b/components/spiffs/Makefile.projbuild index 13b2223a9a..645856c497 100644 --- a/components/spiffs/Makefile.projbuild +++ b/components/spiffs/Makefile.projbuild @@ -20,7 +20,7 @@ endif define spiffs_create_partition_image -$(1)_bin: $(PARTITION_TABLE_BIN) | check_python_dependencies +$(1)_bin: $(PARTITION_TABLE_BIN) $(DEPENDS) | check_python_dependencies partition_size=`$(GET_PART_INFO) \ --partition-table-file $(PARTITION_TABLE_BIN) \ get_partition_info --partition-name $(1) --info size`; \ diff --git a/components/spiffs/project_include.cmake b/components/spiffs/project_include.cmake index 19fc96ed7a..31f63b5111 100644 --- a/components/spiffs/project_include.cmake +++ b/components/spiffs/project_include.cmake @@ -4,7 +4,8 @@ # have the created image flashed using `idf.py flash` function(spiffs_create_partition_image partition base_dir) set(options FLASH_IN_PROJECT) - cmake_parse_arguments(arg "${options}" "" "" "${ARGN}") + set(multi DEPENDS) + cmake_parse_arguments(arg "${options}" "" "${multi}" "${ARGN}") idf_build_get_property(idf_path IDF_PATH) set(spiffsgen_py ${PYTHON} ${idf_path}/components/spiffs/spiffsgen.py) @@ -33,6 +34,7 @@ function(spiffs_create_partition_image partition base_dir) --meta-len=${CONFIG_SPIFFS_META_LENGTH} ${use_magic} ${use_magic_len} + DEPENDS ${arg_DEPENDS} ) set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY From c65038fd7414bac3cf3f71a929b090e3b0c15c86 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Fri, 21 Jun 2019 10:58:00 +0800 Subject: [PATCH 106/486] spiffs,make: change spiffsgen build API --- components/spiffs/Makefile.projbuild | 7 +++-- docs/en/api-reference/storage/spiffs.rst | 38 +++++++++++++++++++----- examples/storage/spiffsgen/Makefile | 3 +- 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/components/spiffs/Makefile.projbuild b/components/spiffs/Makefile.projbuild index 645856c497..4d8f39c081 100644 --- a/components/spiffs/Makefile.projbuild +++ b/components/spiffs/Makefile.projbuild @@ -19,8 +19,7 @@ endif # have the created image flashed using `make flash` define spiffs_create_partition_image - -$(1)_bin: $(PARTITION_TABLE_BIN) $(DEPENDS) | check_python_dependencies +$(1)_bin: $(PARTITION_TABLE_BIN) $(SPIFFS_IMAGE_DEPENDS) | check_python_dependencies partition_size=`$(GET_PART_INFO) \ --partition-table-file $(PARTITION_TABLE_BIN) \ get_partition_info --partition-name $(1) --info size`; \ @@ -35,9 +34,11 @@ all_binaries: $(1)_bin print_flash_cmd: $(1)_bin # Append the created binary to esptool_py args if FLASH_IN_PROJECT is set -ifeq ($(3), FLASH_IN_PROJECT) +ifdef SPIFFS_IMAGE_FLASH_IN_PROJECT +ifeq ($(SPIFFS_IMAGE_FLASH_IN_PROJECT),1) SPIFFSGEN_FLASH_IN_PROJECT += $(1) endif +endif endef ESPTOOL_ALL_FLASH_ARGS += $(foreach partition,$(SPIFFSGEN_FLASH_IN_PROJECT), \ diff --git a/docs/en/api-reference/storage/spiffs.rst b/docs/en/api-reference/storage/spiffs.rst index dcd31a022f..5620e83d77 100644 --- a/docs/en/api-reference/storage/spiffs.rst +++ b/docs/en/api-reference/storage/spiffs.rst @@ -44,26 +44,50 @@ Aside from invoking the ``spiffsgen.py`` standalone by manually running it from Make:: - $(eval $(call spiffs_create_partition_image,,,[FLASH_IN_PROJECT])) + SPIFFS_IMAGE_FLASH_IN_PROJECT := ... + SPIFFS_IMAGE_DEPENDS := ... + $(eval $(call spiffs_create_partition_image,,)) CMake:: - spiffs_create_partition_image( [FLASH_IN_PROJECT]) + spiffs_create_partition_image( [FLASH_IN_PROJECT] [DEPENDS dep dep dep...]) This is more convenient as the build configuration is automatically passed to the tool, ensuring that the generated image is valid for that build. An example of this is while the *image_size* is required for the standalone invocation, only the *partition* name is required when using ``spiffs_create_partition_image`` -- the image size is automatically obtained from the project's partition table. -Due to the differences in structure between Make and Cmake, it is important to note that: +Due to the differences in structure between Make and CMake, it is important to note that: - for Make ``spiffs_create_partition_image`` must be called from the project Makefile - for CMake ``spiffs_create_partition_image`` must be called from one of the component CMakeLists.txt files -For both build systems, the image will be created in the build directory with the filename *partition*.bin. +Optionally, user can opt to have the image automatically flashed together with the app binaries, partition tables, etc. on +``idf.py flash`` or ``make flash`` by specifying ``FLASH_IN_PROJECT``. For example, -Optionally, you can opt to have the image automatically flashed together with the app binaries, partition tables, etc., with -``idf.py flash`` or ``make flash`` by specifying ``FLASH_IN_PROJECT``. For example:: +in Make:: + + SPIFFS_IMAGE_FLASH_IN_PROJECT := 1 + $(eval $(call spiffs_create_partition_image,,)) + +in CMake:: spiffs_create_partition_image(my_spiffs_partition my_folder FLASH_IN_PROJECT) -If FLASH_IN_PROJECT is not specified, the image will still be generated, but you will have to flash it manually using ``esptool.py``, ``parttool.py``, or a custom build system target. +If FLASH_IN_PROJECT/SPIFFS_IMAGE_FLASH_IN_PROJECT is not specified, the image will still be generated, but you will have to flash it manually using ``esptool.py``, ``parttool.py``, or a custom build system target. + +There are cases where the contents of the base directory itself is generated at build time. Users can use DEPENDS/SPIFFS_IMAGE_DEPENDS to specify targets +that should be executed before generating the image. + +in Make:: + + dep: + ... + + SPIFFS_IMAGE_DEPENDS := dep + $(eval $(call spiffs_create_partition_image,,)) + +in CMake:: + + add_custom_target(dep COMMAND ...) + + spiffs_create_partition_image(my_spiffs_partition my_folder DEPENDS dep) +For an example, see :example:`examples/storage/spiffsgen>`. diff --git a/examples/storage/spiffsgen/Makefile b/examples/storage/spiffsgen/Makefile index 07cc03d6dd..300abdd6e8 100644 --- a/examples/storage/spiffsgen/Makefile +++ b/examples/storage/spiffsgen/Makefile @@ -12,4 +12,5 @@ include $(IDF_PATH)/make/project.mk # that fits the partition named 'storage'. FLASH_IN_PROJECT indicates that # the generated image should be flashed when the entire project is flashed to # the target with 'make flash'. -$(eval $(call spiffs_create_partition_image,storage,spiffs_image,FLASH_IN_PROJECT)) \ No newline at end of file +SPIFFS_IMAGE_FLASH_IN_PROJECT := 1 +$(eval $(call spiffs_create_partition_image,storage,spiffs_image)) \ No newline at end of file From 149e07911decbeecc917f225ec6721149015887e Mon Sep 17 00:00:00 2001 From: baohongde Date: Fri, 21 Jun 2019 11:55:45 +0800 Subject: [PATCH 107/486] components/bt: Optimization and bugfix of previous commits --- components/bt/bluedroid/bta/dm/bta_dm_act.c | 2 + components/bt/bluedroid/bta/dm/bta_dm_cfg.c | 2 +- components/bt/bluedroid/bta/dm/bta_dm_main.c | 2 + .../bt/bluedroid/bta/dm/include/bta_dm_int.h | 2 + .../bt/bluedroid/bta/gatt/bta_gattc_co.c | 2 +- .../bt/bluedroid/bta/include/bta/bta_sys.h | 2 +- .../bt/bluedroid/bta/sys/bta_sys_main.c | 4 +- components/bt/bluedroid/btc/core/btc_task.c | 116 +++-- .../bluedroid/btc/profile/std/avrc/btc_avrc.c | 2 - .../btc/profile/std/include/btc_avrc.h | 2 +- .../common/include/common/bt_user_config.h | 17 +- components/bt/bluedroid/device/controller.c | 4 +- components/bt/bluedroid/main/bte_init.c | 440 ++++++++++-------- components/bt/bluedroid/stack/a2dp/a2d_api.c | 14 +- components/bt/bluedroid/stack/avrc/avrc_sdp.c | 14 +- .../bt/bluedroid/stack/btm/btm_ble_gap.c | 8 +- .../bt/bluedroid/stack/btm/btm_devctl.c | 2 + components/bt/bluedroid/stack/btm/btm_main.c | 12 +- .../bt/bluedroid/stack/btm/include/btm_int.h | 8 +- components/bt/bluedroid/stack/btu/btu_init.c | 11 +- components/bt/bluedroid/stack/btu/btu_task.c | 61 ++- components/bt/bluedroid/stack/gap/gap_api.c | 15 +- .../bluedroid/stack/include/stack/a2d_api.h | 3 +- .../bluedroid/stack/include/stack/avrc_api.h | 5 +- .../bt/bluedroid/stack/include/stack/btu.h | 2 +- .../bluedroid/stack/include/stack/gap_api.h | 4 +- .../bluedroid/stack/include/stack/port_api.h | 3 +- .../bt/bluedroid/stack/rfcomm/port_api.c | 14 +- components/bt/bluedroid/stack/smp/smp_utils.c | 9 +- 29 files changed, 451 insertions(+), 331 deletions(-) diff --git a/components/bt/bluedroid/bta/dm/bta_dm_act.c b/components/bt/bluedroid/bta/dm/bta_dm_act.c index a6fefeacfe..acb6f6291f 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_act.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_act.c @@ -1298,7 +1298,9 @@ void bta_dm_loc_oob(tBTA_DM_MSG *p_data) *******************************************************************************/ void bta_dm_oob_reply(tBTA_DM_MSG *p_data) { +#if (BLE_INCLUDED) BTM_BleOobDataReply(p_data->oob_reply.bd_addr, BTM_SUCCESS, p_data->oob_reply.len, p_data->oob_reply.value); +#endif } /******************************************************************************* diff --git a/components/bt/bluedroid/bta/dm/bta_dm_cfg.c b/components/bt/bluedroid/bta/dm/bta_dm_cfg.c index 9e018de98d..6769e7141e 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_cfg.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_cfg.c @@ -441,4 +441,4 @@ tBTA_DM_EIR_CONF bta_dm_eir_cfg = { NULL #endif /* #if (BTC_GAP_BT_INCLUDED == TRUE) */ }; -tBTA_DM_EIR_CONF *const p_bta_dm_eir_cfg = (tBTA_DM_EIR_CONF *) &bta_dm_eir_cfg; +tBTA_DM_EIR_CONF *p_bta_dm_eir_cfg = (tBTA_DM_EIR_CONF *) &bta_dm_eir_cfg; diff --git a/components/bt/bluedroid/bta/dm/bta_dm_main.c b/components/bt/bluedroid/bta/dm/bta_dm_main.c index 3b9a7cc4ce..d62974ea2e 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_main.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_main.c @@ -160,7 +160,9 @@ const tBTA_DM_ACTION bta_dm_action[BTA_DM_MAX_EVT] = { bta_dm_update_white_list, /* BTA_DM_API_UPDATE_WHITE_LIST_EVT */ bta_dm_ble_read_adv_tx_power, /* BTA_DM_API_BLE_READ_ADV_TX_POWER_EVT */ bta_dm_ble_read_rssi, /* BTA_DM_API_BLE_READ_RSSI_EVT */ +#if BLE_INCLUDED == TRUE bta_dm_ble_update_duplicate_exceptional_list,/* BTA_DM_API_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_EVT */ +#endif }; diff --git a/components/bt/bluedroid/bta/dm/include/bta_dm_int.h b/components/bt/bluedroid/bta/dm/include/bta_dm_int.h index 4fc8e650ce..c87708e358 100644 --- a/components/bt/bluedroid/bta/dm/include/bta_dm_int.h +++ b/components/bt/bluedroid/bta/dm/include/bta_dm_int.h @@ -157,7 +157,9 @@ enum { BTA_DM_API_UPDATE_WHITE_LIST_EVT, BTA_DM_API_BLE_READ_ADV_TX_POWER_EVT, BTA_DM_API_BLE_READ_RSSI_EVT, +#if BLE_INCLUDED == TRUE BTA_DM_API_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_EVT, +#endif BTA_DM_MAX_EVT }; diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_co.c b/components/bt/bluedroid/bta/gatt/bta_gattc_co.c index 06c51b07e8..a336c23147 100644 --- a/components/bt/bluedroid/bta/gatt/bta_gattc_co.c +++ b/components/bt/bluedroid/bta/gatt/bta_gattc_co.c @@ -269,8 +269,8 @@ tBTA_GATT_STATUS bta_gattc_co_cache_load(tBTA_GATTC_NV_ATTR *attr, UINT8 index) // Read the size of memory space required for blob nvs_get_blob(cache_env->cache_addr[index].cache_fp, cache_key, NULL, &length); // Read previously saved blob if available -#if (!CONFIG_BT_STACK_NO_LOG) esp_err_t err_code = nvs_get_blob(cache_env->cache_addr[index].cache_fp, cache_key, attr, &length); +#if (!CONFIG_BT_STACK_NO_LOG) num_attr = length / sizeof(tBTA_GATTC_NV_ATTR); #endif status = (err_code == ESP_OK && length != 0) ? BTA_GATT_OK : BTA_GATT_ERROR; diff --git a/components/bt/bluedroid/bta/include/bta/bta_sys.h b/components/bt/bluedroid/bta/include/bta/bta_sys.h index a58773de73..a466028b95 100644 --- a/components/bt/bluedroid/bta/include/bta/bta_sys.h +++ b/components/bt/bluedroid/bta/include/bta/bta_sys.h @@ -215,7 +215,7 @@ extern "C" { extern void bta_sys_init(void); extern void bta_sys_free(void); -extern void bta_sys_event(BT_HDR *p_msg); +extern void bta_sys_event(void * param); extern void bta_sys_set_trace_level(UINT8 level); extern void bta_sys_register(UINT8 id, const tBTA_SYS_REG *p_reg); extern void bta_sys_deregister(UINT8 id); diff --git a/components/bt/bluedroid/bta/sys/bta_sys_main.c b/components/bt/bluedroid/bta/sys/bta_sys_main.c index c00abd7394..1ea2ccd702 100644 --- a/components/bt/bluedroid/bta/sys/bta_sys_main.c +++ b/components/bt/bluedroid/bta/sys/bta_sys_main.c @@ -482,8 +482,10 @@ void bta_sys_hw_evt_stack_enabled(tBTA_SYS_HW_MSG *p_sys_hw_msg) ** Returns void ** *******************************************************************************/ -void bta_sys_event(BT_HDR *p_msg) +void bta_sys_event(void * param) { + BT_HDR *p_msg = (BT_HDR *)param; + UINT8 id; BOOLEAN freebuf = TRUE; diff --git a/components/bt/bluedroid/btc/core/btc_task.c b/components/bt/bluedroid/btc/core/btc_task.c index cb8616d9b0..df1e1ddfdc 100644 --- a/components/bt/bluedroid/btc/core/btc_task.c +++ b/components/bt/bluedroid/btc/core/btc_task.c @@ -176,95 +176,121 @@ bt_status_t btc_transfer_context(btc_msg_t *msg, void *arg, int arg_len, btc_arg } #if BTC_DYNAMIC_MENDRY + +static void btc_deinit_mem(void) { + if (btc_dm_cb_ptr) { + osi_free(btc_dm_cb_ptr); + btc_dm_cb_ptr = NULL; + } + + if (btc_profile_cb_tab) { + osi_free(btc_profile_cb_tab); + btc_profile_cb_tab = NULL; + } + +#if (BLE_INCLUDED == TRUE) + if (gl_bta_adv_data_ptr) { + osi_free(gl_bta_adv_data_ptr); + gl_bta_adv_data_ptr = NULL; + } + + if (gl_bta_scan_rsp_data_ptr) { + osi_free(gl_bta_scan_rsp_data_ptr); + gl_bta_scan_rsp_data_ptr = NULL; + } +#endif ///BLE_INCLUDED == TRUE + +#if GATTS_INCLUDED == TRUE && GATT_DYNAMIC_MEMORY == TRUE + if (btc_creat_tab_env_ptr) { + osi_free(btc_creat_tab_env_ptr); + btc_creat_tab_env_ptr = NULL; + } + + if (blufi_env_ptr) { + osi_free(blufi_env_ptr); + blufi_env_ptr = NULL; + } +#endif + +#if BTC_HF_CLIENT_INCLUDED == TRUE && HFP_DYNAMIC_MEMORY == TRUE + if (hf_client_local_param_ptr) { + osi_free(hf_client_local_param_ptr); + hf_client_local_param_ptr = NULL; + } +#endif + +#if BTC_AV_INCLUDED == TRUE && AVRC_DYNAMIC_MEMORY == TRUE + if (btc_rc_cb_ptr) { + osi_free(btc_rc_cb_ptr); + btc_rc_cb_ptr = NULL; + } + if (bta_av_co_cb_ptr) { + osi_free(bta_av_co_cb_ptr); + bta_av_co_cb_ptr = NULL; + } +#endif +} + static bt_status_t btc_init_mem(void) { if ((btc_dm_cb_ptr = (btc_dm_cb_t *)osi_malloc(sizeof(btc_dm_cb_t))) == NULL) { - return BT_STATUS_NOMEM; + goto error_exit; } memset((void *)btc_dm_cb_ptr, 0, sizeof(btc_dm_cb_t)); if ((btc_profile_cb_tab = (void **)osi_malloc(sizeof(void *) * BTC_PID_NUM)) == NULL) { - return BT_STATUS_NOMEM; + goto error_exit; } memset((void *)btc_profile_cb_tab, 0, sizeof(void *) * BTC_PID_NUM); #if (BLE_INCLUDED == TRUE) if ((gl_bta_adv_data_ptr = (tBTA_BLE_ADV_DATA *)osi_malloc(sizeof(tBTA_BLE_ADV_DATA))) == NULL) { - return BT_STATUS_NOMEM; + goto error_exit; } memset((void *)gl_bta_adv_data_ptr, 0, sizeof(tBTA_BLE_ADV_DATA)); if ((gl_bta_scan_rsp_data_ptr = (tBTA_BLE_ADV_DATA *)osi_malloc(sizeof(tBTA_BLE_ADV_DATA))) == NULL) { - return BT_STATUS_NOMEM; + goto error_exit; } memset((void *)gl_bta_scan_rsp_data_ptr, 0, sizeof(tBTA_BLE_ADV_DATA)); #endif ///BLE_INCLUDED == TRUE #if GATTS_INCLUDED == TRUE && GATT_DYNAMIC_MEMORY == TRUE if ((btc_creat_tab_env_ptr = (esp_btc_creat_tab_t *)osi_malloc(sizeof(esp_btc_creat_tab_t))) == NULL) { - return BT_STATUS_NOMEM; + goto error_exit; } memset((void *)btc_creat_tab_env_ptr, 0, sizeof(esp_btc_creat_tab_t)); if ((blufi_env_ptr = (tBLUFI_ENV *)osi_malloc(sizeof(tBLUFI_ENV))) == NULL) { - return BT_STATUS_NOMEM; + goto error_exit; } memset((void *)blufi_env_ptr, 0, sizeof(tBLUFI_ENV)); #endif #if BTC_HF_CLIENT_INCLUDED == TRUE && HFP_DYNAMIC_MEMORY == TRUE if ((hf_client_local_param_ptr = (hf_client_local_param_t *)osi_malloc(sizeof(hf_client_local_param_t))) == NULL) { - return BT_STATUS_NOMEM; + goto error_exit; } memset((void *)hf_client_local_param_ptr, 0, sizeof(hf_client_local_param_t)); #endif #if BTC_AV_INCLUDED == TRUE && AVRC_DYNAMIC_MEMORY == TRUE - if ((btc_rc_vb_ptr = (btc_rc_cb_t *)osi_malloc(sizeof(btc_rc_cb_t))) == NULL) { - return BT_STATUS_NOMEM; + if ((btc_rc_cb_ptr = (btc_rc_cb_t *)osi_malloc(sizeof(btc_rc_cb_t))) == NULL) { + goto error_exit; } - memset((void *)btc_rc_vb_ptr, 0, sizeof(btc_rc_cb_t)); + memset((void *)btc_rc_cb_ptr, 0, sizeof(btc_rc_cb_t)); if ((bta_av_co_cb_ptr = (tBTA_AV_CO_CB *)osi_malloc(sizeof(tBTA_AV_CO_CB))) == NULL) { - return BT_STATUS_NOMEM; + goto error_exit; } memset((void *)bta_av_co_cb_ptr, 0, sizeof(tBTA_AV_CO_CB)); #endif return BT_STATUS_SUCCESS; + +error_exit:; + btc_deinit_mem(); + return BT_STATUS_NOMEM; } - -static void btc_deinit_mem(void) { - osi_free(btc_dm_cb_ptr); - btc_dm_cb_ptr = NULL; - - osi_free(btc_profile_cb_tab); - btc_profile_cb_tab = NULL; - - osi_free(gl_bta_adv_data_ptr); - gl_bta_adv_data_ptr = NULL; - - osi_free(gl_bta_scan_rsp_data_ptr); - gl_bta_scan_rsp_data_ptr = NULL; - -#if GATTS_INCLUDED == TRUE && GATT_DYNAMIC_MEMORY == TRUE - osi_free(btc_creat_tab_env_ptr); - btc_creat_tab_env_ptr = NULL; - osi_free(blufi_env_ptr); - blufi_env_ptr = NULL; -#endif - -#if BTC_HF_CLIENT_INCLUDED == TRUE && HFP_DYNAMIC_MEMORY == TRUE - osi_free(hf_client_local_param_ptr); - hf_client_local_param_ptr = NULL; -#endif - -#if BTC_AV_INCLUDED == TRUE && AVRC_DYNAMIC_MEMORY == TRUE - osi_free(btc_rc_vb_ptr); - btc_rc_vb_ptr = NULL; - osi_free(bta_av_co_cb_ptr); - bta_av_co_cb_ptr = NULL; -#endif -} -#endif +#endif ///BTC_DYNAMIC_MENDRY int btc_init(void) { diff --git a/components/bt/bluedroid/btc/profile/std/avrc/btc_avrc.c b/components/bt/bluedroid/btc/profile/std/avrc/btc_avrc.c index 841d55c360..28ecb85e63 100644 --- a/components/bt/bluedroid/btc/profile/std/avrc/btc_avrc.c +++ b/components/bt/bluedroid/btc/profile/std/avrc/btc_avrc.c @@ -1002,8 +1002,6 @@ static void btc_avrc_ct_init(void) /// initialize CT-TG shared resources if (s_rc_tg_init != BTC_RC_TG_INIT_MAGIC) { memset (&btc_rc_cb, 0, sizeof(btc_rc_cb_t)); - btc_rc_cb.rc_vol_label = MAX_LABEL; - btc_rc_cb.rc_volume = MAX_VOLUME; } } diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_avrc.h b/components/bt/bluedroid/btc/profile/std/include/btc_avrc.h index 7d72393d82..ec98c5ee56 100644 --- a/components/bt/bluedroid/btc/profile/std/include/btc_avrc.h +++ b/components/bt/bluedroid/btc/profile/std/include/btc_avrc.h @@ -98,7 +98,7 @@ typedef enum { #define CHECK_ESP_RC_CONNECTED do { \ BTC_TRACE_DEBUG("## %s ##", __FUNCTION__); \ - if (btc_rc_vb.rc_connected == FALSE) { \ + if (btc_rc_cb.rc_connected == FALSE) { \ BTC_TRACE_WARNING("Function %s() called when RC is not connected", __FUNCTION__); \ return ESP_ERR_INVALID_STATE; \ } \ diff --git a/components/bt/bluedroid/common/include/common/bt_user_config.h b/components/bt/bluedroid/common/include/common/bt_user_config.h index 5fdc1c2183..7fa8ed5c51 100644 --- a/components/bt/bluedroid/common/include/common/bt_user_config.h +++ b/components/bt/bluedroid/common/include/common/bt_user_config.h @@ -15,9 +15,6 @@ #ifndef __BT_USER_CONFIG_H__ #define __BT_USER_CONFIG_H__ - - - /* All the configuration from SDK defined here */ #include "sdkconfig.h" @@ -86,6 +83,7 @@ #define UC_BT_SSP_ENABLED CONFIG_BT_SSP_ENABLED #else #define UC_BT_SSP_ENABLED FALSE +#endif //BLE #ifdef CONFIG_BT_BLE_ENABLED @@ -96,16 +94,16 @@ //GATTS #ifdef CONFIG_BT_GATTS_ENABLE -#define UC_BT_GATTS_ENABLED CONFIG_BT_GATTS_ENABLE +#define UC_BT_GATTS_ENABLE CONFIG_BT_GATTS_ENABLE #else -#define UC_BT_GATTS_ENABLED FALSE +#define UC_BT_GATTS_ENABLE FALSE #endif //GATTC #ifdef CONFIG_BT_GATTC_ENABLE -#define UC_BT_GATTC_ENABLED CONFIG_BT_GATTC_ENABLE +#define UC_BT_GATTC_ENABLE CONFIG_BT_GATTC_ENABLE #else -#define UC_BT_GATTC_ENABLED FALSE +#define UC_BT_GATTC_ENABLE FALSE #endif //GATTC CACHE @@ -117,9 +115,9 @@ //SMP #ifdef CONFIG_BT_SMP_ENABLE -#define UC_BT_SMP_ENABLED CONFIG_BT_SMP_ENABLE +#define UC_BT_SMP_ENABLE CONFIG_BT_SMP_ENABLE #else -#define UC_BT_SMP_ENABLED FALSE +#define UC_BT_SMP_ENABLE FALSE #endif //SMP_SLAVE_CON_PARAMS_UPD_ENABLE @@ -371,7 +369,6 @@ #define UC_BT_LOG_BLUFI_TRACE_LEVEL UC_TRACE_LEVEL_WARNING #endif - #endif /* __BT_USER_CONFIG_H__ */ diff --git a/components/bt/bluedroid/device/controller.c b/components/bt/bluedroid/device/controller.c index df6c5018f6..84d6f59737 100644 --- a/components/bt/bluedroid/device/controller.c +++ b/components/bt/bluedroid/device/controller.c @@ -111,8 +111,8 @@ static void start_up(void) #endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) // Enable adv flow control - response = AWAIT_COMMAND(packet_factory->make_set_adv_report_flow_control(HCI_HOST_FLOW_CTRL_ADV_REPORT_ON, (uint16_t)BLE_ADV_REPORT_FLOW_CONTROL_NUM, (uint16_t)BLE_ADV_REPORT_DISCARD_THRSHOLD)); - packet_parser->parse_generic_command_complete(response); + response = AWAIT_COMMAND(controller_param.packet_factory->make_set_adv_report_flow_control(HCI_HOST_FLOW_CTRL_ADV_REPORT_ON, (uint16_t)BLE_ADV_REPORT_FLOW_CONTROL_NUM, (uint16_t)BLE_ADV_REPORT_DISCARD_THRSHOLD)); + controller_param.packet_parser->parse_generic_command_complete(response); #endif // Tell the controller about our buffer sizes and buffer counts next // TODO(zachoverflow): factor this out. eww l2cap contamination. And why just a hardcoded 10? diff --git a/components/bt/bluedroid/main/bte_init.c b/components/bt/bluedroid/main/bte_init.c index 1d6e994291..7f3723ae55 100644 --- a/components/bt/bluedroid/main/bte_init.c +++ b/components/bt/bluedroid/main/bte_init.c @@ -143,168 +143,6 @@ ** F U N C T I O N S * ******************************************************************************/ -/***************************************************************************** -** -** Function BTE_InitStack -** -** Description Initialize control block memory for each component. -** -** Note: The core stack components must be called -** before creating the BTU Task. The rest of the -** components can be initialized at a later time if desired -** as long as the component's init function is called -** before accessing any of its functions. -** -** Returns void -** -******************************************************************************/ -void BTE_InitStack(void) -{ -#if (defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE) - //Initialize the optional stack components - RFCOMM_Init(); -#endif - - //BNEP and its profiles -#if (defined(BNEP_INCLUDED) && BNEP_INCLUDED == TRUE) - BNEP_Init(); - -#if (defined(PAN_INCLUDED) && PAN_INCLUDED == TRUE) - PAN_Init(); -#endif // PAN -#endif // BNEP Included - - //AVDT and its profiles -#if (defined(A2D_INCLUDED) && A2D_INCLUDED == TRUE) - A2D_Init(); -#endif // AADP - -#if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) - AVRC_Init(); -#endif - -#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE && AVDT_DYNAMIC_MEMORY == TRUE) - if ((avdt_cb_ptr = (tAVDT_CB *)osi_malloc(sizeof(tAVDT_CB))) == NULL) { - return; - } - memset((void *)avdt_cb_ptr, 0, sizeof(tAVDT_CB)); -#endif - -#if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE && AVCT_DYNAMIC_MEMORY == TRUE) - if ((avct_cb_ptr = (tAVCT_CB *)osi_malloc(sizeof(tAVCT_CB))) == NULL) { - return; - } - memset((void *)avct_cb_ptr, 0, sizeof(tAVCT_CB)); -#endif - -#if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE) - GAP_Init(); -#endif - -#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE) - HID_HostInit(); -#endif - -#if (defined(MCA_INCLUDED) && MCA_INCLUDED == TRUE) - MCA_Init(); -#endif - - //BTA Modules -#if (BTA_INCLUDED == TRUE && BTA_DYNAMIC_MEMORY == TRUE) - if ((bta_sys_cb_ptr = (tBTA_SYS_CB *)osi_malloc(sizeof(tBTA_SYS_CB))) == NULL) { - return; - } - if ((bta_dm_cb_ptr = (tBTA_DM_CB *)osi_malloc(sizeof(tBTA_DM_CB))) == NULL) { - return; - } - if ((bta_dm_search_cb_ptr = (tBTA_DM_SEARCH_CB *)osi_malloc(sizeof(tBTA_DM_SEARCH_CB))) == NULL) { - return; - } - if ((bta_dm_di_cb_ptr = (tBTA_DM_DI_CB *)osi_malloc(sizeof(tBTA_DM_DI_CB))) == NULL) { - return; - } - if ((bta_dm_conn_srvcs_ptr = (tBTA_DM_CONNECTED_SRVCS *)osi_malloc(sizeof(tBTA_DM_CONNECTED_SRVCS))) == NULL) { - return; - } - memset((void *)bta_sys_cb_ptr, 0, sizeof(tBTA_SYS_CB)); - memset((void *)bta_dm_cb_ptr, 0, sizeof(tBTA_DM_CB)); - memset((void *)bta_dm_search_cb_ptr, 0, sizeof(tBTA_DM_SEARCH_CB)); - memset((void *)bta_dm_di_cb_ptr, 0, sizeof(tBTA_DM_DI_CB)); - memset((void *)bta_dm_conn_srvcs_ptr, 0, sizeof(tBTA_DM_CONNECTED_SRVCS)); - //memset((void *)bta_prm_cb_ptr, 0, sizeof(tBTA_PRM_CB)); - -#if (defined BTA_HF_INCLUDED && BTA_HF_INCLUDED == TRUE) - if ((bta_hf_client_cb_ptr = (tBTA_HF_CLIENT_CB *)osi_malloc(sizeof(tBTA_HF_CLIENT_CB))) == NULL) { - return; - } - memset((void *)bta_hf_client_cb_ptr, 0, sizeof(tBTA_HF_CLIENT_CB)); -#endif -#if (defined BTA_JV_INCLUDED && BTA_JV_INCLUDED == TRUE) - if ((bta_jv_cb_ptr = (tBTA_JV_CB *)osi_malloc(sizeof(tBTA_JV_CB))) == NULL) { - return; - } - memset((void *)bta_jv_cb_ptr, 0, sizeof(tBTA_JV_CB)); -#endif //JV -#if BTA_HS_INCLUDED == TRUE - memset((void *)bta_hs_cb_ptr, 0, sizeof(tBTA_HS_CB)); -#endif -#if BTA_SDP_INCLUDED == TRUE - if ((bta_sdp_cb_ptr = (tBTA_SDP_CB *)osi_malloc(sizeof(tBTA_SDP_CB))) == NULL) { - return; - } - memset((void *)bta_sdp_cb_ptr, 0, sizeof(tBTA_SDP_CB)); -#endif -#if SDP_INCLUDED == TRUE - if ((g_disc_raw_data_buf = (UINT8 *)osi_malloc(MAX_DISC_RAW_DATA_BUF)) == NULL) { - return; - } - memset((void *)g_disc_raw_data_buf, 0, MAX_DISC_RAW_DATA_BUF); -#endif -#if BTA_AR_INCLUDED==TRUE - if ((bta_ar_cb_ptr = (tBTA_AR_CB *)osi_malloc(sizeof(tBTA_AR_CB))) == NULL) { - return; - } - memset((void *)bta_ar_cb_ptr, 0, sizeof(tBTA_AR_CB)); -#endif -#if BTA_AV_INCLUDED==TRUE - if ((bta_av_cb_ptr = (tBTA_AV_CB *)osi_malloc(sizeof(tBTA_AV_CB))) == NULL) { - return; - } - memset((void *)bta_av_cb_ptr, 0, sizeof(tBTA_AV_CB)); - - if ((bta_av_sbc_ups_cb_ptr = (tBTA_AV_SBC_UPS_CB *)osi_malloc(sizeof(tBTA_AV_SBC_UPS_CB))) == NULL) { - return; - } - memset((void *)bta_av_sbc_ups_cb_ptr, 0, sizeof(tBTA_AV_SBC_UPS_CB)); -#endif -#if BTA_HH_INCLUDED==TRUE - if ((bta_hh_cb_ptr = (tBTA_HH_CB *)osi_malloc(sizeof(tBTA_HH_CB))) == NULL) { - return; - } - memset((void *)bta_hh_cb_ptr, 0, sizeof(tBTA_HH_CB)); -#endif -#if BTA_HL_INCLUDED==TRUE - memset((void *)bta_hl_cb_ptr, 0, sizeof(tBTA_HL_CB)); -#endif -#if GATTC_INCLUDED==TRUE - if ((bta_gattc_cb_ptr = (tBTA_GATTC_CB *)osi_malloc(sizeof(tBTA_GATTC_CB))) == NULL) { - return; - } - memset((void *)bta_gattc_cb_ptr, 0, sizeof(tBTA_GATTC_CB)); -#endif -#if GATTS_INCLUDED == TRUE - if ((bta_gatts_cb_ptr = (tBTA_GATTS_CB *)osi_malloc(sizeof(tBTA_GATTS_CB))) == NULL) { - return; - } - memset((void *)bta_gatts_cb_ptr, 0, sizeof(tBTA_GATTS_CB)); -#endif -#if BTA_PAN_INCLUDED==TRUE - memset((void *)bta_pan_cb_ptr, 0, sizeof(tBTA_PAN_CB)); -#endif - -#endif // BTA_INCLUDED == TRUE -} - /***************************************************************************** ** ** Function BTE_DeinitStack @@ -322,53 +160,83 @@ void BTE_DeinitStack(void) //BTA Modules #if (BTA_INCLUDED == TRUE && BTA_DYNAMIC_MEMORY == TRUE) #if GATTS_INCLUDED == TRUE - osi_free(bta_gatts_cb_ptr); - bta_gatts_cb_ptr = NULL; + if (bta_gatts_cb_ptr){ + osi_free(bta_gatts_cb_ptr); + bta_gatts_cb_ptr = NULL; + } #endif #if GATTC_INCLUDED==TRUE - osi_free(bta_gattc_cb_ptr); - bta_gattc_cb_ptr = NULL; + if (bta_gattc_cb_ptr){ + osi_free(bta_gattc_cb_ptr); + bta_gattc_cb_ptr = NULL; + } #endif #if BTA_HH_INCLUDED==TRUE - osi_free(bta_hh_cb_ptr); - bta_hh_cb_ptr = NULL; + if (bta_hh_cb_ptr){ + osi_free(bta_hh_cb_ptr); + bta_hh_cb_ptr = NULL; + } #endif #if BTA_AV_INCLUDED==TRUE - osi_free(bta_av_cb_ptr); - bta_av_cb_ptr = NULL; - osi_free(bta_av_sbc_ups_cb_ptr); - bta_av_sbc_ups_cb_ptr = NULL; + if (bta_av_cb_ptr){ + osi_free(bta_av_cb_ptr); + bta_av_cb_ptr = NULL; + } + if (bta_av_sbc_ups_cb_ptr){ + osi_free(bta_av_sbc_ups_cb_ptr); + bta_av_sbc_ups_cb_ptr = NULL; + } #endif #if BTA_AR_INCLUDED==TRUE - osi_free(bta_ar_cb_ptr); - bta_ar_cb_ptr = NULL; + if (bta_ar_cb_ptr){ + osi_free(bta_ar_cb_ptr); + bta_ar_cb_ptr = NULL; + } #endif #if SDP_INCLUDED == TRUE - osi_free(g_disc_raw_data_buf); - g_disc_raw_data_buf = NULL; + if (g_disc_raw_data_buf){ + osi_free(g_disc_raw_data_buf); + g_disc_raw_data_buf = NULL; + } #endif #if BTA_SDP_INCLUDED == TRUE - osi_free(bta_sdp_cb_ptr); - bta_sdp_cb_ptr = NULL; + if (bta_sdp_cb_ptr){ + osi_free(bta_sdp_cb_ptr); + bta_sdp_cb_ptr = NULL; + } #endif #if (defined BTA_JV_INCLUDED && BTA_JV_INCLUDED == TRUE) - osi_free(bta_jv_cb_ptr); - bta_jv_cb_ptr = NULL; + if (bta_jv_cb_ptr){ + osi_free(bta_jv_cb_ptr); + bta_jv_cb_ptr = NULL; + } #endif //JV #if (defined BTA_HF_INCLUDED && BTA_HF_INCLUDED == TRUE) - osi_free(bta_hf_client_cb_ptr); - bta_hf_client_cb_ptr = NULL; + if (bta_hf_client_cb_ptr){ + osi_free(bta_hf_client_cb_ptr); + bta_hf_client_cb_ptr = NULL; + } #endif - osi_free(bta_dm_conn_srvcs_ptr); - bta_dm_conn_srvcs_ptr = NULL; - osi_free(bta_dm_di_cb_ptr); - bta_dm_di_cb_ptr = NULL; - osi_free(bta_dm_search_cb_ptr); - bta_dm_search_cb_ptr = NULL; - osi_free(bta_dm_cb_ptr); - bta_dm_cb_ptr = NULL; - osi_free(bta_sys_cb_ptr); - bta_sys_cb_ptr = NULL; + if (bta_dm_conn_srvcs_ptr){ + osi_free(bta_dm_conn_srvcs_ptr); + bta_dm_conn_srvcs_ptr = NULL; + } + if (bta_dm_di_cb_ptr){ + osi_free(bta_dm_di_cb_ptr); + bta_dm_di_cb_ptr = NULL; + } + if (bta_dm_search_cb_ptr){ + osi_free(bta_dm_search_cb_ptr); + bta_dm_search_cb_ptr = NULL; + } + if (bta_dm_cb_ptr){ + osi_free(bta_dm_cb_ptr); + bta_dm_cb_ptr = NULL; + } + if (bta_sys_cb_ptr){ + osi_free(bta_sys_cb_ptr); + bta_sys_cb_ptr = NULL; + } #endif // BTA_INCLUDED == TRUE #if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE) @@ -376,13 +244,17 @@ void BTE_DeinitStack(void) #endif #if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE && AVCT_DYNAMIC_MEMORY == TRUE) - osi_free(avct_cb_ptr); - avct_cb_ptr = NULL; + if (avct_cb_ptr){ + osi_free(avct_cb_ptr); + avct_cb_ptr = NULL; + } #endif #if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE && AVDT_DYNAMIC_MEMORY == TRUE) - osi_free(avdt_cb_ptr); - avdt_cb_ptr = NULL; + if (avdt_cb_ptr){ + osi_free(avdt_cb_ptr); + avdt_cb_ptr = NULL; + } #endif #if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) @@ -397,3 +269,179 @@ void BTE_DeinitStack(void) RFCOMM_Deinit(); #endif } + +/***************************************************************************** +** +** Function BTE_InitStack +** +** Description Initialize control block memory for each component. +** +** Note: The core stack components must be called +** before creating the BTU Task. The rest of the +** components can be initialized at a later time if desired +** as long as the component's init function is called +** before accessing any of its functions. +** +** Returns status +** +******************************************************************************/ +bt_status_t BTE_InitStack(void) +{ +#if (defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE) + //Initialize the optional stack components + if (RFCOMM_Init() != BT_STATUS_SUCCESS) { + goto error_exit; + } +#endif + + //BNEP and its profiles +#if (defined(BNEP_INCLUDED) && BNEP_INCLUDED == TRUE) + BNEP_Init(); + +#if (defined(PAN_INCLUDED) && PAN_INCLUDED == TRUE) + PAN_Init(); +#endif // PAN +#endif // BNEP Included + + //AVDT and its profiles +#if (defined(A2D_INCLUDED) && A2D_INCLUDED == TRUE) + if (A2D_Init() != BT_STATUS_SUCCESS) { + goto error_exit; + } +#endif // AADP + +#if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) + if (AVRC_Init() != BT_STATUS_SUCCESS) { + goto error_exit; + } +#endif + +#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE && AVDT_DYNAMIC_MEMORY == TRUE) + if ((avdt_cb_ptr = (tAVDT_CB *)osi_malloc(sizeof(tAVDT_CB))) == NULL) { + goto error_exit; + } + memset((void *)avdt_cb_ptr, 0, sizeof(tAVDT_CB)); +#endif + +#if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE && AVCT_DYNAMIC_MEMORY == TRUE) + if ((avct_cb_ptr = (tAVCT_CB *)osi_malloc(sizeof(tAVCT_CB))) == NULL) { + goto error_exit; + } + memset((void *)avct_cb_ptr, 0, sizeof(tAVCT_CB)); +#endif + +#if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE) + if (GAP_Init() != BT_STATUS_SUCCESS) { + goto error_exit; + } +#endif + +#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE) + HID_HostInit(); +#endif + +#if (defined(MCA_INCLUDED) && MCA_INCLUDED == TRUE) + MCA_Init(); +#endif + + //BTA Modules +#if (BTA_INCLUDED == TRUE && BTA_DYNAMIC_MEMORY == TRUE) + if ((bta_sys_cb_ptr = (tBTA_SYS_CB *)osi_malloc(sizeof(tBTA_SYS_CB))) == NULL) { + goto error_exit; + } + if ((bta_dm_cb_ptr = (tBTA_DM_CB *)osi_malloc(sizeof(tBTA_DM_CB))) == NULL) { + goto error_exit; + } + if ((bta_dm_search_cb_ptr = (tBTA_DM_SEARCH_CB *)osi_malloc(sizeof(tBTA_DM_SEARCH_CB))) == NULL) { + goto error_exit; + } + if ((bta_dm_di_cb_ptr = (tBTA_DM_DI_CB *)osi_malloc(sizeof(tBTA_DM_DI_CB))) == NULL) { + goto error_exit; + } + if ((bta_dm_conn_srvcs_ptr = (tBTA_DM_CONNECTED_SRVCS *)osi_malloc(sizeof(tBTA_DM_CONNECTED_SRVCS))) == NULL) { + goto error_exit; + } + memset((void *)bta_sys_cb_ptr, 0, sizeof(tBTA_SYS_CB)); + memset((void *)bta_dm_cb_ptr, 0, sizeof(tBTA_DM_CB)); + memset((void *)bta_dm_search_cb_ptr, 0, sizeof(tBTA_DM_SEARCH_CB)); + memset((void *)bta_dm_di_cb_ptr, 0, sizeof(tBTA_DM_DI_CB)); + memset((void *)bta_dm_conn_srvcs_ptr, 0, sizeof(tBTA_DM_CONNECTED_SRVCS)); + //memset((void *)bta_prm_cb_ptr, 0, sizeof(tBTA_PRM_CB)); + +#if (defined BTA_HF_INCLUDED && BTA_HF_INCLUDED == TRUE) + if ((bta_hf_client_cb_ptr = (tBTA_HF_CLIENT_CB *)osi_malloc(sizeof(tBTA_HF_CLIENT_CB))) == NULL) { + goto error_exit; + } + memset((void *)bta_hf_client_cb_ptr, 0, sizeof(tBTA_HF_CLIENT_CB)); +#endif +#if (defined BTA_JV_INCLUDED && BTA_JV_INCLUDED == TRUE) + if ((bta_jv_cb_ptr = (tBTA_JV_CB *)osi_malloc(sizeof(tBTA_JV_CB))) == NULL) { + goto error_exit; + } + memset((void *)bta_jv_cb_ptr, 0, sizeof(tBTA_JV_CB)); +#endif //JV +#if BTA_HS_INCLUDED == TRUE + memset((void *)bta_hs_cb_ptr, 0, sizeof(tBTA_HS_CB)); +#endif +#if BTA_SDP_INCLUDED == TRUE + if ((bta_sdp_cb_ptr = (tBTA_SDP_CB *)osi_malloc(sizeof(tBTA_SDP_CB))) == NULL) { + goto error_exit; + } + memset((void *)bta_sdp_cb_ptr, 0, sizeof(tBTA_SDP_CB)); +#endif +#if SDP_INCLUDED == TRUE + if ((g_disc_raw_data_buf = (UINT8 *)osi_malloc(MAX_DISC_RAW_DATA_BUF)) == NULL) { + goto error_exit; + } + memset((void *)g_disc_raw_data_buf, 0, MAX_DISC_RAW_DATA_BUF); +#endif +#if BTA_AR_INCLUDED==TRUE + if ((bta_ar_cb_ptr = (tBTA_AR_CB *)osi_malloc(sizeof(tBTA_AR_CB))) == NULL) { + goto error_exit; + } + memset((void *)bta_ar_cb_ptr, 0, sizeof(tBTA_AR_CB)); +#endif +#if BTA_AV_INCLUDED==TRUE + if ((bta_av_cb_ptr = (tBTA_AV_CB *)osi_malloc(sizeof(tBTA_AV_CB))) == NULL) { + goto error_exit; + } + memset((void *)bta_av_cb_ptr, 0, sizeof(tBTA_AV_CB)); + + if ((bta_av_sbc_ups_cb_ptr = (tBTA_AV_SBC_UPS_CB *)osi_malloc(sizeof(tBTA_AV_SBC_UPS_CB))) == NULL) { + goto error_exit; + } + memset((void *)bta_av_sbc_ups_cb_ptr, 0, sizeof(tBTA_AV_SBC_UPS_CB)); +#endif +#if BTA_HH_INCLUDED==TRUE + if ((bta_hh_cb_ptr = (tBTA_HH_CB *)osi_malloc(sizeof(tBTA_HH_CB))) == NULL) { + goto error_exit; + } + memset((void *)bta_hh_cb_ptr, 0, sizeof(tBTA_HH_CB)); +#endif +#if BTA_HL_INCLUDED==TRUE + memset((void *)bta_hl_cb_ptr, 0, sizeof(tBTA_HL_CB)); +#endif +#if GATTC_INCLUDED==TRUE + if ((bta_gattc_cb_ptr = (tBTA_GATTC_CB *)osi_malloc(sizeof(tBTA_GATTC_CB))) == NULL) { + goto error_exit; + } + memset((void *)bta_gattc_cb_ptr, 0, sizeof(tBTA_GATTC_CB)); +#endif +#if GATTS_INCLUDED == TRUE + if ((bta_gatts_cb_ptr = (tBTA_GATTS_CB *)osi_malloc(sizeof(tBTA_GATTS_CB))) == NULL) { + goto error_exit; + } + memset((void *)bta_gatts_cb_ptr, 0, sizeof(tBTA_GATTS_CB)); +#endif +#if BTA_PAN_INCLUDED==TRUE + memset((void *)bta_pan_cb_ptr, 0, sizeof(tBTA_PAN_CB)); +#endif + +#endif // BTA_INCLUDED == TRUE + return BT_STATUS_SUCCESS; + +error_exit:; + LOG_ERROR("%s failed due to no memory", __func__); + BTE_DeinitStack(); + return BT_STATUS_NOMEM; +} diff --git a/components/bt/bluedroid/stack/a2dp/a2d_api.c b/components/bt/bluedroid/stack/a2dp/a2d_api.c index 937e46b1e1..8adb200dcd 100644 --- a/components/bt/bluedroid/stack/a2dp/a2d_api.c +++ b/components/bt/bluedroid/stack/a2dp/a2d_api.c @@ -372,13 +372,16 @@ UINT8 A2D_BitsSet(UINT8 num) ** other API functions for this layer. It is typically called ** once during the start up of the stack. ** -** Returns void +** Returns status ** *******************************************************************************/ -void A2D_Init(void) +bt_status_t A2D_Init(void) { #if (A2D_DYNAMIC_MEMORY) a2d_cb_ptr = (tA2D_CB *)osi_malloc(sizeof(tA2D_CB)); + if (!a2d_cb_ptr) { + return BT_STATUS_NOMEM; + } #endif /* #if (A2D_DYNAMIC_MEMORY) */ memset(&a2d_cb, 0, sizeof(tA2D_CB)); @@ -389,6 +392,7 @@ void A2D_Init(void) #else a2d_cb.trace_level = BT_TRACE_LEVEL_NONE; #endif + return BT_STATUS_SUCCESS; } /******************************************************************************* @@ -404,8 +408,10 @@ void A2D_Init(void) void A2D_Deinit(void) { #if (A2D_DYNAMIC_MEMORY) - osi_free(a2d_cb_ptr); - a2d_cb_ptr = NULL; + if (a2d_cb_ptr) { + osi_free(a2d_cb_ptr); + a2d_cb_ptr = NULL; + } #endif /* #if (A2D_DYNAMIC_MEMORY) */ } diff --git a/components/bt/bluedroid/stack/avrc/avrc_sdp.c b/components/bt/bluedroid/stack/avrc/avrc_sdp.c index d3616f3233..11a994d7ac 100644 --- a/components/bt/bluedroid/stack/avrc/avrc_sdp.c +++ b/components/bt/bluedroid/stack/avrc/avrc_sdp.c @@ -340,13 +340,16 @@ UINT8 AVRC_SetTraceLevel (UINT8 new_level) ** control block (if using dynamic memory), and initializes the ** control block and tracing level. ** -** Returns void +** Returns status ** *******************************************************************************/ -void AVRC_Init(void) +bt_status_t AVRC_Init(void) { #if AVRC_DYNAMIC_MEMORY avrc_cb_ptr = (tAVRC_CB *)osi_malloc(sizeof(tAVRC_CB)); + if (!avrc_cb_ptr) { + return BT_STATUS_NOMEM; + } #endif /* #if AVRC_DYNAMIC_MEMORY */ memset(&avrc_cb, 0, sizeof(tAVRC_CB)); @@ -355,6 +358,7 @@ void AVRC_Init(void) #else avrc_cb.trace_level = BT_TRACE_LEVEL_NONE; #endif + return BT_STATUS_SUCCESS; } /******************************************************************************* @@ -371,8 +375,10 @@ void AVRC_Init(void) void AVRC_Deinit(void) { #if AVRC_DYNAMIC_MEMORY - osi_free(avrc_cb_ptr); - avrc_cb_ptr = NULL; + if (avrc_cb_ptr){ + osi_free(avrc_cb_ptr); + avrc_cb_ptr = NULL; + } #endif /* #if AVRC_DYNAMIC_MEMORY */ } diff --git a/components/bt/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/bluedroid/stack/btm/btm_ble_gap.c index e7a4ba955b..5a7f60da94 100644 --- a/components/bt/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/bluedroid/stack/btm/btm_ble_gap.c @@ -246,7 +246,7 @@ uint8_t adv_param_status = 0; uint8_t scan_enable_status = 0; uint8_t scan_param_status = 0; -void btm_lock_init(void) +void btm_ble_lock_init(void) { osi_mutex_new(&adv_enable_lock); osi_mutex_new(&adv_data_lock); @@ -255,7 +255,7 @@ void btm_lock_init(void) osi_mutex_new(&scan_param_lock); } -void btm_lock_free(void) +void btm_ble_lock_free(void) { osi_mutex_free(&adv_enable_lock); osi_mutex_free(&adv_data_lock); @@ -264,7 +264,7 @@ void btm_lock_free(void) osi_mutex_free(&scan_param_lock); } -void btm_sem_init(void) +void btm_ble_sem_init(void) { osi_sem_new(&adv_enable_sem, 1, 0); osi_sem_new(&adv_data_sem, 1, 0); @@ -273,7 +273,7 @@ void btm_sem_init(void) osi_sem_new(&scan_param_sem, 1, 0); } -void btm_sem_free(void) +void btm_ble_sem_free(void) { osi_sem_free(&adv_enable_sem); osi_sem_free(&adv_data_sem); diff --git a/components/bt/bluedroid/stack/btm/btm_devctl.c b/components/bt/bluedroid/stack/btm/btm_devctl.c index 23be3eb303..437a3cd1a3 100644 --- a/components/bt/bluedroid/stack/btm/btm_devctl.c +++ b/components/bt/bluedroid/stack/btm/btm_devctl.c @@ -693,6 +693,7 @@ tBTM_STATUS BTM_VendorSpecificCommand(UINT16 opcode, UINT8 param_len, void btm_vsc_complete (UINT8 *p, UINT16 opcode, UINT16 evt_len, tBTM_CMPL_CB *p_vsc_cplt_cback) { +#if (BLE_INCLUDED == TRUE) tBTM_BLE_CB *ble_cb = &btm_cb.ble_ctr_cb; switch(opcode) { case HCI_VENDOR_BLE_LONG_ADV_DATA: @@ -721,6 +722,7 @@ void btm_vsc_complete (UINT8 *p, UINT16 opcode, UINT16 evt_len, vcs_cplt_params.p_param_buf = p; (*p_vsc_cplt_cback)(&vcs_cplt_params); /* Call the VSC complete callback function */ } +#endif } /******************************************************************************* diff --git a/components/bt/bluedroid/stack/btm/btm_main.c b/components/bt/bluedroid/stack/btm/btm_main.c index b6b853d5c6..cf950f21a9 100644 --- a/components/bt/bluedroid/stack/btm/btm_main.c +++ b/components/bt/bluedroid/stack/btm/btm_main.c @@ -75,8 +75,10 @@ void btm_init (void) #endif btm_dev_init(); /* Device Manager Structures & HCI_Reset */ - btm_lock_init(); - btm_sem_init(); +#if BLE_INCLUDED == TRUE + btm_ble_lock_init(); + btm_ble_sem_init(); +#endif } @@ -96,6 +98,8 @@ void btm_free(void) #if BTM_DYNAMIC_MEMORY FREE_AND_RESET(btm_cb_ptr); #endif - btm_lock_free(); - btm_sem_free(); +#if BLE_INCLUDED == TRUE + btm_ble_lock_free(); + btm_ble_sem_free(); +#endif } diff --git a/components/bt/bluedroid/stack/btm/include/btm_int.h b/components/bt/bluedroid/stack/btm/include/btm_int.h index f575d8958a..4ef7285084 100644 --- a/components/bt/bluedroid/stack/btm/include/btm_int.h +++ b/components/bt/bluedroid/stack/btm/include/btm_int.h @@ -1148,13 +1148,13 @@ void btm_acl_paging (BT_HDR *p, BD_ADDR dest); UINT8 btm_sec_clr_service_by_psm (UINT16 psm); void btm_sec_clr_temp_auth_service (BD_ADDR bda); -void btm_lock_init(void); +void btm_ble_lock_init(void); -void btm_sem_init(void); +void btm_ble_sem_init(void); -void btm_sem_free(void); +void btm_ble_sem_free(void); -void btm_lock_free(void); +void btm_ble_lock_free(void); /* #ifdef __cplusplus diff --git a/components/bt/bluedroid/stack/btu/btu_init.c b/components/bt/bluedroid/stack/btu/btu_init.c index 455cc9fe6a..617bb5de66 100644 --- a/components/bt/bluedroid/stack/btu/btu_init.c +++ b/components/bt/bluedroid/stack/btu/btu_init.c @@ -66,7 +66,7 @@ osi_thread_t *btu_thread = NULL; extern void PLATFORM_DisableHciTransport(UINT8 bDisable); extern void btu_task_thread_handler(void *arg); -void btu_task_start_up(void); +void btu_task_start_up(void * param); void btu_task_shut_down(void); /***************************************************************************** @@ -197,6 +197,15 @@ error_exit:; BTU_ShutDown(); } +/***************************************************************************** +** +** Function BTU_ShutDown +** +** Description Deinitializes the BTU control block. +** +** Returns void +** +******************************************************************************/ void BTU_ShutDown(void) { #if BTU_DYNAMIC_MEMORY diff --git a/components/bt/bluedroid/stack/btu/btu_task.c b/components/bt/bluedroid/stack/btu/btu_task.c index 40448357d5..3e73cbb85c 100644 --- a/components/bt/bluedroid/stack/btu/btu_task.c +++ b/components/bt/bluedroid/stack/btu/btu_task.c @@ -90,7 +90,7 @@ typedef struct { //#include "bt_app_common.h" //#endif -extern void BTE_InitStack(void); +extern bt_status_t BTE_InitStack(void); extern void BTE_DeinitStack(void); /* Define BTU storage area @@ -119,17 +119,19 @@ extern bluedroid_init_done_cb_t bluedroid_init_done_cb; /* Define a function prototype to allow a generic timeout handler */ typedef void (tUSER_TIMEOUT_FUNC) (TIMER_LIST_ENT *p_tle); -static void btu_l2cap_alarm_process(TIMER_LIST_ENT *p_tle); -static void btu_general_alarm_process(TIMER_LIST_ENT *p_tle); -static void btu_hci_msg_process(BT_HDR *p_msg); +static void btu_l2cap_alarm_process(void *param); +static void btu_general_alarm_process(void *param); +static void btu_hci_msg_process(void *param); #if (defined(BTA_INCLUDED) && BTA_INCLUDED == TRUE) -static void btu_bta_alarm_process(TIMER_LIST_ENT *p_tle); +static void btu_bta_alarm_process(void *param); #endif -static void btu_hci_msg_process(BT_HDR *p_msg) +static void btu_hci_msg_process(void *param) { /* Determine the input message type. */ + BT_HDR *p_msg = (BT_HDR *)param; + switch (p_msg->event & BT_EVT_MASK) { case BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK: // TODO(zachoverflow): remove this { @@ -196,8 +198,9 @@ static void btu_hci_msg_process(BT_HDR *p_msg) } #if (defined(BTA_INCLUDED) && BTA_INCLUDED == TRUE) -static void btu_bta_alarm_process(TIMER_LIST_ENT *p_tle) +static void btu_bta_alarm_process(void *param) { + TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *)param; // call timer callback if (p_tle->p_cback) { (*p_tle->p_cback)(p_tle); @@ -213,56 +216,42 @@ static void btu_bta_alarm_process(TIMER_LIST_ENT *p_tle) } #endif -void btu_thread_handler(void *arg) +bool btu_task_post(uint32_t sig, void *param, uint32_t timeout) { - btu_thread_evt_t *evt = (btu_thread_evt_t *)arg; + bool status = false; - switch (evt->sig) { + switch (sig) { case SIG_BTU_START_UP: - btu_task_start_up(); + status = osi_thread_post(btu_thread, btu_task_start_up, param, 0, timeout); break; case SIG_BTU_HCI_MSG: - btu_hci_msg_process((BT_HDR *)evt->param); + status = osi_thread_post(btu_thread, btu_hci_msg_process, param, 0, timeout); break; #if (defined(BTA_INCLUDED) && BTA_INCLUDED == TRUE) case SIG_BTU_BTA_MSG: - bta_sys_event((BT_HDR *)evt->param); + status = osi_thread_post(btu_thread, bta_sys_event, param, 0, timeout); break; case SIG_BTU_BTA_ALARM: - btu_bta_alarm_process((TIMER_LIST_ENT *)evt->param); + status = osi_thread_post(btu_thread, btu_bta_alarm_process, param, 0, timeout); break; #endif case SIG_BTU_GENERAL_ALARM: case SIG_BTU_ONESHOT_ALARM: - btu_general_alarm_process((TIMER_LIST_ENT *)evt->param); + status = osi_thread_post(btu_thread, btu_general_alarm_process, param, 0, timeout); break; case SIG_BTU_L2CAP_ALARM: - btu_l2cap_alarm_process((TIMER_LIST_ENT *)evt->param); + status = osi_thread_post(btu_thread, btu_l2cap_alarm_process, param, 0, timeout); break; default: break; } - osi_free(evt); + return status; } -bool btu_task_post(uint32_t sig, void *param, uint32_t timeout) -{ - btu_thread_evt_t *evt; - - evt = (btu_thread_evt_t *)osi_malloc(sizeof(btu_thread_evt_t)); - if (evt == NULL) { - return false; - } - - evt->sig = sig; - evt->param = param; - - return osi_thread_post(btu_thread, btu_thread_handler, evt, 0, timeout); -} - -void btu_task_start_up(void) +void btu_task_start_up(void *param) { + UNUSED(param); /* Initialize the mandatory core stack control blocks (BTU, BTM, L2CAP, and SDP) */ @@ -305,8 +294,9 @@ void btu_task_shut_down(void) ** Returns void ** *******************************************************************************/ -static void btu_general_alarm_process(TIMER_LIST_ENT *p_tle) +static void btu_general_alarm_process(void *param) { + TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *)param; assert(p_tle != NULL); switch (p_tle->event) { @@ -511,8 +501,9 @@ void btu_free_timer(TIMER_LIST_ENT *p_tle) ** Returns void ** *******************************************************************************/ -static void btu_l2cap_alarm_process(TIMER_LIST_ENT *p_tle) +static void btu_l2cap_alarm_process(void *param) { + TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *)param; assert(p_tle != NULL); switch (p_tle->event) { diff --git a/components/bt/bluedroid/stack/gap/gap_api.c b/components/bt/bluedroid/stack/gap/gap_api.c index 69b5d9629b..b4e7c1b4fb 100644 --- a/components/bt/bluedroid/stack/gap/gap_api.c +++ b/components/bt/bluedroid/stack/gap/gap_api.c @@ -57,13 +57,16 @@ UINT8 GAP_SetTraceLevel (UINT8 new_level) ** This routine should not be called except once per ** stack invocation. ** -** Returns Nothing +** Returns status ** *******************************************************************************/ -void GAP_Init(void) +bt_status_t GAP_Init(void) { #if GAP_DYNAMIC_MEMORY == TRUE gap_cb_ptr = (tGAP_CB *)osi_malloc(sizeof(tGAP_CB)); + if (!gap_cb_ptr) { + return BT_STATUS_NOMEM; + } #endif memset (&gap_cb, 0, sizeof (tGAP_CB)); @@ -81,6 +84,8 @@ void GAP_Init(void) #if BLE_INCLUDED == TRUE && GATTS_INCLUDED == TRUE gap_attr_db_init(); #endif + + return BT_STATUS_SUCCESS; } /******************************************************************************* @@ -96,7 +101,9 @@ void GAP_Init(void) void GAP_Deinit(void) { #if GAP_DYNAMIC_MEMORY == TRUE - osi_free(gap_cb_ptr); - gap_cb_ptr = NULL; + if (gap_cb_ptr) { + osi_free(gap_cb_ptr); + gap_cb_ptr = NULL; + } #endif } \ No newline at end of file diff --git a/components/bt/bluedroid/stack/include/stack/a2d_api.h b/components/bt/bluedroid/stack/include/stack/a2d_api.h index 7509544fb5..466f9fad72 100644 --- a/components/bt/bluedroid/stack/include/stack/a2d_api.h +++ b/components/bt/bluedroid/stack/include/stack/a2d_api.h @@ -23,6 +23,7 @@ ******************************************************************************/ #ifndef A2D_API_H #define A2D_API_H +#include "common/bt_defs.h" #include "stack/sdp_api.h" #if (A2D_INCLUDED == TRUE) /***************************************************************************** @@ -250,7 +251,7 @@ extern UINT8 A2D_BitsSet(UINT8 num); ** Returns void ** *******************************************************************************/ -extern void A2D_Init(void); +extern bt_status_t A2D_Init(void); extern void A2D_Deinit(void); #endif ///A2D_INCLUDED #endif /* A2D_API_H */ diff --git a/components/bt/bluedroid/stack/include/stack/avrc_api.h b/components/bt/bluedroid/stack/include/stack/avrc_api.h index 85e8db1b2e..cbbb4b1c69 100644 --- a/components/bt/bluedroid/stack/include/stack/avrc_api.h +++ b/components/bt/bluedroid/stack/include/stack/avrc_api.h @@ -24,6 +24,7 @@ #ifndef AVRC_API_H #define AVRC_API_H #include "common/bt_target.h" +#include "common/bt_defs.h" #include "stack/avct_api.h" #include "stack/sdp_api.h" #include "stack/avrc_defs.h" @@ -549,10 +550,10 @@ extern UINT8 AVRC_SetTraceLevel (UINT8 new_level); ** control block (if using dynamic memory), and initializes the ** control block and tracing level. ** -** Returns void +** Returns status ** *******************************************************************************/ -extern void AVRC_Init(void); +extern bt_status_t AVRC_Init(void); /******************************************************************************* ** diff --git a/components/bt/bluedroid/stack/include/stack/btu.h b/components/bt/bluedroid/stack/include/stack/btu.h index b3269e2ca6..fd5d1c989d 100644 --- a/components/bt/bluedroid/stack/include/stack/btu.h +++ b/components/bt/bluedroid/stack/include/stack/btu.h @@ -283,7 +283,7 @@ void btu_free_core(void); void BTU_StartUp(void); void BTU_ShutDown(void); -void btu_task_start_up(void); +void btu_task_start_up(void *param); void btu_task_shut_down(void); UINT16 BTU_BleAclPktSize(void); diff --git a/components/bt/bluedroid/stack/include/stack/gap_api.h b/components/bt/bluedroid/stack/include/stack/gap_api.h index 03af2956ce..62062d2f21 100644 --- a/components/bt/bluedroid/stack/include/stack/gap_api.h +++ b/components/bt/bluedroid/stack/include/stack/gap_api.h @@ -320,10 +320,10 @@ extern UINT8 GAP_SetTraceLevel (UINT8 new_level); ** This routine should not be called except once per ** stack invocation. ** -** Returns Nothing +** Returns status ** *******************************************************************************/ -extern void GAP_Init(void); +extern bt_status_t GAP_Init(void); /******************************************************************************* ** diff --git a/components/bt/bluedroid/stack/include/stack/port_api.h b/components/bt/bluedroid/stack/include/stack/port_api.h index 8145a177a0..145ef22889 100644 --- a/components/bt/bluedroid/stack/include/stack/port_api.h +++ b/components/bt/bluedroid/stack/include/stack/port_api.h @@ -25,6 +25,7 @@ #define PORT_API_H #include "common/bt_target.h" +#include "common/bt_defs.h" /***************************************************************************** ** Constants and Types @@ -621,7 +622,7 @@ extern int PORT_Test (UINT16 handle, UINT8 *p_data, UINT16 len); ** Description This function is called to initialize RFCOMM layer ** *******************************************************************************/ -extern void RFCOMM_Init (void); +extern bt_status_t RFCOMM_Init (void); /******************************************************************************* ** diff --git a/components/bt/bluedroid/stack/rfcomm/port_api.c b/components/bt/bluedroid/stack/rfcomm/port_api.c index f6e0ed4d4f..dacf544b9b 100644 --- a/components/bt/bluedroid/stack/rfcomm/port_api.c +++ b/components/bt/bluedroid/stack/rfcomm/port_api.c @@ -1711,11 +1711,16 @@ int PORT_Test (UINT16 handle, UINT8 *p_data, UINT16 len) ** ** Description This function is called to initialize RFCOMM layer ** +** Returns status +** *******************************************************************************/ -void RFCOMM_Init (void) +bt_status_t RFCOMM_Init (void) { #if RFC_DYNAMIC_MEMORY == TRUE rfc_cb_ptr = (tRFC_CB *)osi_malloc(sizeof(tRFC_CB)); + if (rfc_cb_ptr == NULL) { + return BT_STATUS_NOMEM; + } #endif /* #if (RFC_DYNAMIC_MEMORY) */ memset (&rfc_cb, 0, sizeof (tRFC_CB)); /* Init RFCOMM control block */ @@ -1728,6 +1733,7 @@ void RFCOMM_Init (void) #endif rfcomm_l2cap_if_init (); + return BT_STATUS_SUCCESS; } /******************************************************************************* @@ -1743,8 +1749,10 @@ void RFCOMM_Init (void) void RFCOMM_Deinit(void) { #if RFC_DYNAMIC_MEMORY == TRUE - osi_free(rfc_cb_ptr); - rfc_cb_ptr = NULL; + if (rfc_cb_ptr){ + osi_free(rfc_cb_ptr); + rfc_cb_ptr = NULL; + } #endif } diff --git a/components/bt/bluedroid/stack/smp/smp_utils.c b/components/bt/bluedroid/stack/smp/smp_utils.c index 5edf0b8ab2..165b11a2a3 100644 --- a/components/bt/bluedroid/stack/smp/smp_utils.c +++ b/components/bt/bluedroid/stack/smp/smp_utils.c @@ -974,13 +974,14 @@ void smp_proc_pairing_cmpl(tSMP_CB *p_cb) tSMP_EVT_DATA evt_data = {0}; tSMP_CALLBACK *p_callback = p_cb->p_callback; BD_ADDR pairing_bda; - tBTM_SEC_DEV_REC *p_rec = btm_find_dev (p_cb->pairing_bda); SMP_TRACE_DEBUG ("smp_proc_pairing_cmpl \n"); evt_data.cmplt.reason = p_cb->status; evt_data.cmplt.smp_over_br = p_cb->smp_over_br; evt_data.cmplt.auth_mode = 0; +#if (BLE_INCLUDED == TRUE) + tBTM_SEC_DEV_REC *p_rec = btm_find_dev (p_cb->pairing_bda); if (p_cb->status == SMP_SUCCESS) { evt_data.cmplt.sec_level = p_cb->sec_level; if (p_cb->auth_mode) { // the first encryption @@ -992,6 +993,12 @@ void smp_proc_pairing_cmpl(tSMP_CB *p_cb) evt_data.cmplt.auth_mode = p_rec->ble.auth_mode; } } +#else + if (p_cb->status == SMP_SUCCESS) { + evt_data.cmplt.sec_level = p_cb->sec_level; + evt_data.cmplt.auth_mode = p_cb->auth_mode; + } +#endif evt_data.cmplt.is_pair_cancel = FALSE; From 0ed590640eb50c484172d103618bb5533ae4c779 Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Mon, 29 Apr 2019 12:25:50 +0800 Subject: [PATCH 108/486] bootloader: Move some structs to separated file Moved structures which describe the app image to separated file. Closes: IDF-597 --- .../include/esp_app_format.h | 109 ++++++++++++++++++ .../include/esp_image_format.h | 84 +------------- 2 files changed, 110 insertions(+), 83 deletions(-) create mode 100644 components/bootloader_support/include/esp_app_format.h diff --git a/components/bootloader_support/include/esp_app_format.h b/components/bootloader_support/include/esp_app_format.h new file mode 100644 index 0000000000..4917dd0f7b --- /dev/null +++ b/components/bootloader_support/include/esp_app_format.h @@ -0,0 +1,109 @@ +// Copyright 2015-2019 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 + +/** + * @brief SPI flash mode, used in esp_image_header_t + */ +typedef enum { + ESP_IMAGE_SPI_MODE_QIO, /*!< SPI mode QIO */ + ESP_IMAGE_SPI_MODE_QOUT, /*!< SPI mode QOUT */ + ESP_IMAGE_SPI_MODE_DIO, /*!< SPI mode DIO */ + ESP_IMAGE_SPI_MODE_DOUT, /*!< SPI mode DOUT */ + ESP_IMAGE_SPI_MODE_FAST_READ, /*!< SPI mode FAST_READ */ + ESP_IMAGE_SPI_MODE_SLOW_READ /*!< SPI mode SLOW_READ */ +} esp_image_spi_mode_t; + +/** + * @brief SPI flash clock frequency + */ +typedef enum { + ESP_IMAGE_SPI_SPEED_40M, /*!< SPI clock frequency 40 MHz */ + ESP_IMAGE_SPI_SPEED_26M, /*!< SPI clock frequency 26 MHz */ + ESP_IMAGE_SPI_SPEED_20M, /*!< SPI clock frequency 20 MHz */ + ESP_IMAGE_SPI_SPEED_80M = 0xF /*!< SPI clock frequency 80 MHz */ +} esp_image_spi_freq_t; + +/** + * @brief Supported SPI flash sizes + */ +typedef enum { + ESP_IMAGE_FLASH_SIZE_1MB = 0, /*!< SPI flash size 1 MB */ + ESP_IMAGE_FLASH_SIZE_2MB, /*!< SPI flash size 2 MB */ + ESP_IMAGE_FLASH_SIZE_4MB, /*!< SPI flash size 4 MB */ + ESP_IMAGE_FLASH_SIZE_8MB, /*!< SPI flash size 8 MB */ + ESP_IMAGE_FLASH_SIZE_16MB, /*!< SPI flash size 16 MB */ + ESP_IMAGE_FLASH_SIZE_MAX /*!< SPI flash size MAX */ +} esp_image_flash_size_t; + +#define ESP_IMAGE_HEADER_MAGIC 0xE9 /*!< The magic word for the esp_image_header_t structure. */ + +/** + * @brief Main header of binary image + */ +typedef struct { + uint8_t magic; /*!< Magic word ESP_IMAGE_HEADER_MAGIC */ + uint8_t segment_count; /*!< Count of memory segments */ + uint8_t spi_mode; /*!< flash read mode (esp_image_spi_mode_t as uint8_t) */ + uint8_t spi_speed: 4; /*!< flash frequency (esp_image_spi_freq_t as uint8_t) */ + uint8_t spi_size: 4; /*!< flash chip size (esp_image_flash_size_t as uint8_t) */ + uint32_t entry_addr; /*!< Entry address */ + uint8_t wp_pin; /*!< WP pin when SPI pins set via efuse (read by ROM bootloader, + * the IDF bootloader uses software to configure the WP + * pin and sets this field to 0xEE=disabled) */ + uint8_t spi_pin_drv[3]; /*!< Drive settings for the SPI flash pins (read by ROM bootloader) */ + uint8_t reserved[11]; /*!< Reserved bytes in ESP32 additional header space, currently unused */ + uint8_t hash_appended; /*!< If 1, a SHA256 digest "simple hash" (of the entire image) is appended after the checksum. + * Included in image length. This digest + * is separate to secure boot and only used for detecting corruption. + * For secure boot signed images, the signature + * is appended after this (and the simple hash is included in the signed data). */ +} __attribute__((packed)) esp_image_header_t; + +/** @cond */ +_Static_assert(sizeof(esp_image_header_t) == 24, "binary image header should be 24 bytes"); +/** @endcond */ + + +/** + * @brief Header of binary image segment + */ +typedef struct { + uint32_t load_addr; /*!< Address of segment */ + uint32_t data_len; /*!< Length of data */ +} esp_image_segment_header_t; + +#define ESP_IMAGE_MAX_SEGMENTS 16 /*!< Max count of segments in the image. */ + +#define ESP_APP_DESC_MAGIC_WORD 0xABCD5432 /*!< The magic word for the esp_app_desc structure that is in DROM. */ + +/** + * @brief Description about application. + */ +typedef struct { + uint32_t magic_word; /*!< Magic word ESP_APP_DESC_MAGIC_WORD */ + uint32_t secure_version; /*!< Secure version */ + uint32_t reserv1[2]; /*!< reserv1 */ + char version[32]; /*!< Application version */ + char project_name[32]; /*!< Project name */ + char time[16]; /*!< Compile time */ + char date[16]; /*!< Compile date*/ + char idf_ver[32]; /*!< Version IDF */ + uint8_t app_elf_sha256[32]; /*!< sha256 of elf file */ + uint32_t reserv2[20]; /*!< reserv2 */ +} esp_app_desc_t; + +/** @cond */ +_Static_assert(sizeof(esp_app_desc_t) == 256, "esp_app_desc_t should be 256 bytes"); +/** @endcond */ diff --git a/components/bootloader_support/include/esp_image_format.h b/components/bootloader_support/include/esp_image_format.h index 7006cae98d..b66b66f5fd 100644 --- a/components/bootloader_support/include/esp_image_format.h +++ b/components/bootloader_support/include/esp_image_format.h @@ -16,6 +16,7 @@ #include #include #include "esp_flash_partitions.h" +#include "esp_app_format.h" #define ESP_ERR_IMAGE_BASE 0x2000 #define ESP_ERR_IMAGE_FLASH_FAIL (ESP_ERR_IMAGE_BASE + 1) @@ -25,91 +26,8 @@ Can be compiled as part of app or bootloader code. */ -/* SPI flash mode, used in esp_image_header_t */ -typedef enum { - ESP_IMAGE_SPI_MODE_QIO, - ESP_IMAGE_SPI_MODE_QOUT, - ESP_IMAGE_SPI_MODE_DIO, - ESP_IMAGE_SPI_MODE_DOUT, - ESP_IMAGE_SPI_MODE_FAST_READ, - ESP_IMAGE_SPI_MODE_SLOW_READ -} esp_image_spi_mode_t; - -/* SPI flash clock frequency */ -typedef enum { - ESP_IMAGE_SPI_SPEED_40M, - ESP_IMAGE_SPI_SPEED_26M, - ESP_IMAGE_SPI_SPEED_20M, - ESP_IMAGE_SPI_SPEED_80M = 0xF -} esp_image_spi_freq_t; - -/* Supported SPI flash sizes */ -typedef enum { - ESP_IMAGE_FLASH_SIZE_1MB = 0, - ESP_IMAGE_FLASH_SIZE_2MB, - ESP_IMAGE_FLASH_SIZE_4MB, - ESP_IMAGE_FLASH_SIZE_8MB, - ESP_IMAGE_FLASH_SIZE_16MB, - ESP_IMAGE_FLASH_SIZE_MAX -} esp_image_flash_size_t; - -#define ESP_IMAGE_HEADER_MAGIC 0xE9 - -/* Main header of binary image */ -typedef struct { - uint8_t magic; - uint8_t segment_count; - /* flash read mode (esp_image_spi_mode_t as uint8_t) */ - uint8_t spi_mode; - /* flash frequency (esp_image_spi_freq_t as uint8_t) */ - uint8_t spi_speed: 4; - /* flash chip size (esp_image_flash_size_t as uint8_t) */ - uint8_t spi_size: 4; - uint32_t entry_addr; - /* WP pin when SPI pins set via efuse (read by ROM bootloader, the IDF bootloader uses software to configure the WP - * pin and sets this field to 0xEE=disabled) */ - uint8_t wp_pin; - /* Drive settings for the SPI flash pins (read by ROM bootloader) */ - uint8_t spi_pin_drv[3]; - /* Reserved bytes in ESP32 additional header space, currently unused */ - uint8_t reserved[11]; - /* If 1, a SHA256 digest "simple hash" (of the entire image) is appended after the checksum. Included in image length. This digest - * is separate to secure boot and only used for detecting corruption. For secure boot signed images, the signature - * is appended after this (and the simple hash is included in the signed data). */ - uint8_t hash_appended; -} __attribute__((packed)) esp_image_header_t; - -_Static_assert(sizeof(esp_image_header_t) == 24, "binary image header should be 24 bytes"); - #define ESP_IMAGE_HASH_LEN 32 /* Length of the appended SHA-256 digest */ -/* Header of binary image segment */ -typedef struct { - uint32_t load_addr; - uint32_t data_len; -} esp_image_segment_header_t; - -#define ESP_APP_DESC_MAGIC_WORD 0xABCD5432 /*!< The magic word for the esp_app_desc structure that is in DROM. */ - -/** - * @brief Description about application. - */ -typedef struct { - uint32_t magic_word; /*!< Magic word ESP_APP_DESC_MAGIC_WORD */ - uint32_t secure_version; /*!< Secure version */ - uint32_t reserv1[2]; /*!< --- */ - char version[32]; /*!< Application version */ - char project_name[32]; /*!< Project name */ - char time[16]; /*!< Compile time */ - char date[16]; /*!< Compile date*/ - char idf_ver[32]; /*!< Version IDF */ - uint8_t app_elf_sha256[32]; /*!< sha256 of elf file */ - uint32_t reserv2[20]; /*!< --- */ -} esp_app_desc_t; -_Static_assert(sizeof(esp_app_desc_t) == 256, "esp_app_desc_t should be 256 bytes"); - -#define ESP_IMAGE_MAX_SEGMENTS 16 - /* Structure to hold on-flash image metadata */ typedef struct { uint32_t start_addr; /* Start address of image */ From e8582e9aa441c3b2d988c73b582b2985f41042ac Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Fri, 21 Jun 2019 19:48:41 +0800 Subject: [PATCH 109/486] esptool_py: use passed offset and image when template is given esptool_py defines command `esptool_py_flash_project_args` that generates arg file for esptool.py. Two of the arguments are the offset and image, which are not being used when a template file is given. This commit makes variables OFFSET and IMAGE available to the template file, which will holds the value of the offset and image arguments to `esptool_py_flash_project_args`. --- components/bootloader/CMakeLists.txt | 3 +-- components/bootloader/flash_bootloader_args.in | 2 +- components/esptool_py/project_include.cmake | 15 +++++++++++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/components/bootloader/CMakeLists.txt b/components/bootloader/CMakeLists.txt index a9dbf01afe..5e243520e9 100644 --- a/components/bootloader/CMakeLists.txt +++ b/components/bootloader/CMakeLists.txt @@ -7,8 +7,7 @@ endif() # Set values used in flash_bootloader_args.in and generate flash file # for bootloader -set(BOOTLOADER_OFFSET 0x1000) -esptool_py_flash_project_args(bootloader ${BOOTLOADER_OFFSET} +esptool_py_flash_project_args(bootloader 0x1000 ${BOOTLOADER_BUILD_DIR}/bootloader.bin FLASH_IN_PROJECT FLASH_FILE_TEMPLATE flash_bootloader_args.in) \ No newline at end of file diff --git a/components/bootloader/flash_bootloader_args.in b/components/bootloader/flash_bootloader_args.in index 610ba7626b..2867c5aafd 100644 --- a/components/bootloader/flash_bootloader_args.in +++ b/components/bootloader/flash_bootloader_args.in @@ -1,4 +1,4 @@ --flash_mode ${ESPFLASHMODE} --flash_size ${ESPFLASHSIZE} --flash_freq ${ESPFLASHFREQ} -${BOOTLOADER_OFFSET} bootloader/bootloader.bin +${OFFSET} ${IMAGE} diff --git a/components/esptool_py/project_include.cmake b/components/esptool_py/project_include.cmake index b847680c88..544888f054 100644 --- a/components/esptool_py/project_include.cmake +++ b/components/esptool_py/project_include.cmake @@ -148,7 +148,10 @@ add_custom_target(flash_project_args_target) # esptool_py_flash_project_args # -# Add file to the flasher args list, to be flashed at a particular offset +# Add file to the flasher args list, to be flashed at a particular offset. +# +# When a template FLASH_FILE_TEMPLATE is given, the variables OFFSET and IMAGE +# hold the value of arguments offset and image, respectively. function(esptool_py_flash_project_args entry offset image) set(options FLASH_IN_PROJECT) # flash the image when flashing the project set(single_value FLASH_FILE_TEMPLATE) # template file to use to be able to @@ -172,8 +175,16 @@ function(esptool_py_flash_project_args entry offset image) if(NOT __FLASH_FILE_TEMPLATE) file(GENERATE OUTPUT ${entry_flash_args} CONTENT "${offset} ${image}") else() + set(OFFSET ${offset}) + set(IMAGE ${image}) get_filename_component(template "${__FLASH_FILE_TEMPLATE}" ABSOLUTE) - file(GENERATE OUTPUT ${entry_flash_args} INPUT ${template}) + configure_file(${template} ${CMAKE_CURRENT_BINARY_DIR}/${template}.in2) + file(GENERATE OUTPUT ${entry_flash_args} INPUT ${CMAKE_CURRENT_BINARY_DIR}/${template}.in2) + set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + APPEND PROPERTY + ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_CURRENT_BINARY_DIR}/${template}.in2}) + unset(OFFSET) + unset(IMAGE) endif() set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} From 9eccd7c0826d6cc2e9de59304d1e5f76c0063ccf Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Sun, 28 Apr 2019 15:38:23 +0800 Subject: [PATCH 110/486] components: use new component registration api --- components/app_trace/CMakeLists.txt | 19 +- components/app_trace/test/CMakeLists.txt | 9 +- components/app_update/CMakeLists.txt | 10 +- components/app_update/test/CMakeLists.txt | 9 +- components/asio/CMakeLists.txt | 9 +- components/bootloader/CMakeLists.txt | 2 +- .../components/micro-ecc/CMakeLists.txt | 5 +- .../bootloader/subproject/main/CMakeLists.txt | 6 +- components/bootloader_support/CMakeLists.txt | 39 ++-- .../bootloader_support/test/CMakeLists.txt | 9 +- components/bt/CMakeLists.txt | 17 +- components/bt/test/CMakeLists.txt | 10 +- components/coap/CMakeLists.txt | 8 +- components/console/CMakeLists.txt | 13 +- components/cxx/CMakeLists.txt | 5 +- components/cxx/test/CMakeLists.txt | 9 +- components/driver/CMakeLists.txt | 55 +++--- components/driver/test/CMakeLists.txt | 9 +- components/efuse/CMakeLists.txt | 15 +- components/efuse/test/CMakeLists.txt | 9 +- components/esp-tls/CMakeLists.txt | 11 +- components/esp32/CMakeLists.txt | 71 ++++--- components/esp32/test/CMakeLists.txt | 9 +- components/esp_adc_cal/CMakeLists.txt | 9 +- components/esp_common/CMakeLists.txt | 30 ++- components/esp_event/CMakeLists.txt | 26 +-- components/esp_event/test/CMakeLists.txt | 8 +- components/esp_http_client/CMakeLists.txt | 19 +- .../esp_http_client/test/CMakeLists.txt | 9 +- components/esp_http_server/CMakeLists.txt | 23 +-- .../esp_http_server/test/CMakeLists.txt | 9 +- components/esp_https_ota/CMakeLists.txt | 11 +- components/esp_https_server/CMakeLists.txt | 11 +- components/esp_ringbuf/CMakeLists.txt | 10 +- components/esp_ringbuf/test/CMakeLists.txt | 9 +- components/esp_rom/CMakeLists.txt | 11 +- components/esp_wifi/CMakeLists.txt | 13 +- components/esp_wifi/test/CMakeLists.txt | 9 +- components/espcoredump/CMakeLists.txt | 18 +- components/espcoredump/test/CMakeLists.txt | 7 +- components/esptool_py/CMakeLists.txt | 3 +- components/ethernet/CMakeLists.txt | 20 +- components/ethernet/test/CMakeLists.txt | 8 +- components/expat/CMakeLists.txt | 15 +- components/expat/test/CMakeLists.txt | 8 +- components/fatfs/CMakeLists.txt | 29 ++- components/fatfs/test/CMakeLists.txt | 12 +- components/freemodbus/CMakeLists.txt | 74 +++---- components/freertos/CMakeLists.txt | 46 +++-- components/freertos/test/CMakeLists.txt | 9 +- components/heap/CMakeLists.txt | 20 +- components/heap/test/CMakeLists.txt | 9 +- components/idf_test/CMakeLists.txt | 3 +- components/jsmn/CMakeLists.txt | 5 +- components/json/CMakeLists.txt | 9 +- components/libsodium/CMakeLists.txt | 17 +- components/libsodium/test/CMakeLists.txt | 12 +- components/log/CMakeLists.txt | 7 +- components/lwip/CMakeLists.txt | 181 +++++++++--------- components/mbedtls/CMakeLists.txt | 8 +- components/mbedtls/test/CMakeLists.txt | 9 +- components/mdns/CMakeLists.txt | 14 +- components/mdns/test/CMakeLists.txt | 5 +- components/mqtt/CMakeLists.txt | 17 +- components/newlib/CMakeLists.txt | 43 +++-- components/newlib/test/CMakeLists.txt | 9 +- components/nghttp/CMakeLists.txt | 50 ++--- components/nvs_flash/CMakeLists.txt | 23 +-- components/nvs_flash/test/CMakeLists.txt | 9 +- components/openssl/CMakeLists.txt | 25 ++- components/partition_table/CMakeLists.txt | 2 +- .../partition_table/test/CMakeLists.txt | 9 +- components/protobuf-c/CMakeLists.txt | 6 +- components/protocomm/CMakeLists.txt | 35 ++-- components/protocomm/test/CMakeLists.txt | 11 +- components/pthread/CMakeLists.txt | 9 +- components/pthread/test/CMakeLists.txt | 9 +- components/sdmmc/CMakeLists.txt | 19 +- components/sdmmc/test/CMakeLists.txt | 9 +- components/smartconfig_ack/CMakeLists.txt | 9 +- components/soc/CMakeLists.txt | 16 +- components/soc/test/CMakeLists.txt | 11 +- components/spi_flash/CMakeLists.txt | 20 +- components/spi_flash/test/CMakeLists.txt | 9 +- components/spiffs/CMakeLists.txt | 25 ++- components/spiffs/test/CMakeLists.txt | 9 +- components/tcp_transport/CMakeLists.txt | 20 +- components/tcpip_adapter/CMakeLists.txt | 10 +- components/ulp/CMakeLists.txt | 7 +- components/ulp/test/CMakeLists.txt | 9 +- components/unity/CMakeLists.txt | 14 +- components/vfs/CMakeLists.txt | 9 +- components/vfs/test/CMakeLists.txt | 12 +- components/wear_levelling/CMakeLists.txt | 21 +- components/wear_levelling/test/CMakeLists.txt | 12 +- components/wifi_provisioning/CMakeLists.txt | 27 ++- components/wpa_supplicant/CMakeLists.txt | 156 ++++++++------- components/wpa_supplicant/test/CMakeLists.txt | 9 +- components/xtensa/CMakeLists.txt | 15 +- 99 files changed, 810 insertions(+), 1008 deletions(-) diff --git a/components/app_trace/CMakeLists.txt b/components/app_trace/CMakeLists.txt index dc6e8baa7a..5276fa01ed 100644 --- a/components/app_trace/CMakeLists.txt +++ b/components/app_trace/CMakeLists.txt @@ -1,16 +1,16 @@ -set(COMPONENT_SRCS "app_trace.c" +set(srcs "app_trace.c" "app_trace_util.c" "host_file_io.c" "gcov/gcov_rtio.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") +set(include_dirs "include") if(CONFIG_SYSVIEW_ENABLE) - list(APPEND COMPONENT_ADD_INCLUDEDIRS + list(APPEND include_dirs sys_view/Config sys_view/SEGGER sys_view/Sample/OS) - list(APPEND COMPONENT_SRCS "sys_view/SEGGER/SEGGER_SYSVIEW.c" + list(APPEND srcs "sys_view/SEGGER/SEGGER_SYSVIEW.c" "sys_view/Sample/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c" "sys_view/Sample/OS/SEGGER_SYSVIEW_FreeRTOS.c" "sys_view/esp32/SEGGER_RTT_esp32.c" @@ -19,14 +19,13 @@ if(CONFIG_SYSVIEW_ENABLE) endif() if(CONFIG_HEAP_TRACING_TOHOST) - list(APPEND COMPONENT_SRCS "heap_trace_tohost.c") + list(APPEND srcs "heap_trace_tohost.c") endif() -set(COMPONENT_REQUIRES) -set(COMPONENT_PRIV_REQUIRES heap soc) -set(COMPONENT_ADD_LDFRAGMENTS linker.lf) - -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + PRIV_REQUIRES soc + LDFRAGMENTS linker.lf) # disable --coverage for this component, as it is used as transport # for gcov diff --git a/components/app_trace/test/CMakeLists.txt b/components/app_trace/test/CMakeLists.txt index 884ca8b6da..16aca87790 100644 --- a/components/app_trace/test/CMakeLists.txt +++ b/components/app_trace/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity) \ No newline at end of file diff --git a/components/app_update/CMakeLists.txt b/components/app_update/CMakeLists.txt index 68ab01c4f9..acb02accb2 100644 --- a/components/app_update/CMakeLists.txt +++ b/components/app_update/CMakeLists.txt @@ -1,10 +1,6 @@ -set(COMPONENT_SRCS "esp_ota_ops.c" - "esp_app_desc.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") - -set(COMPONENT_REQUIRES spi_flash partition_table bootloader_support) - -register_component() +idf_component_register(SRCS "esp_ota_ops.c" "esp_app_desc.c" + INCLUDE_DIRS "include" + REQUIRES spi_flash partition_table bootloader_support) # esp_app_desc structure is added as an undefined symbol because otherwise the # linker will ignore this structure as it has no other files depending on it. diff --git a/components/app_update/test/CMakeLists.txt b/components/app_update/test/CMakeLists.txt index e42488e75e..e56fd72838 100644 --- a/components/app_update/test/CMakeLists.txt +++ b/components/app_update/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils app_update bootloader_support nvs_flash) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils app_update bootloader_support nvs_flash) \ No newline at end of file diff --git a/components/asio/CMakeLists.txt b/components/asio/CMakeLists.txt index 43d428f8d7..f2038278de 100644 --- a/components/asio/CMakeLists.txt +++ b/components/asio/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_ADD_INCLUDEDIRS asio/asio/include port/include) -set(COMPONENT_SRCS "asio/asio/src/asio.cpp") - -set(COMPONENT_REQUIRES lwip) - -register_component() +idf_component_register(SRCS "asio/asio/src/asio.cpp" + INCLUDE_DIRS "asio/asio/include" "port/include" + REQUIRES lwip) diff --git a/components/bootloader/CMakeLists.txt b/components/bootloader/CMakeLists.txt index 5e243520e9..6d50ca58f5 100644 --- a/components/bootloader/CMakeLists.txt +++ b/components/bootloader/CMakeLists.txt @@ -1,4 +1,4 @@ -register_component() +idf_component_register() # Do not generate flash file when building bootloader or is in early expansion of the build if(BOOTLOADER_BUILD) diff --git a/components/bootloader/subproject/components/micro-ecc/CMakeLists.txt b/components/bootloader/subproject/components/micro-ecc/CMakeLists.txt index d609b61e70..7d4bfc4d19 100644 --- a/components/bootloader/subproject/components/micro-ecc/CMakeLists.txt +++ b/components/bootloader/subproject/components/micro-ecc/CMakeLists.txt @@ -1,4 +1,3 @@ # only compile the "micro-ecc/uECC.c" source file -set(COMPONENT_SRCS "micro-ecc/uECC.c") -set(COMPONENT_ADD_INCLUDEDIRS micro-ecc) -register_component() +idf_component_register(SRCS "micro-ecc/uECC.c" + INCLUDE_DIRS micro-ecc) diff --git a/components/bootloader/subproject/main/CMakeLists.txt b/components/bootloader/subproject/main/CMakeLists.txt index ab3ed94fd0..d73d46debc 100644 --- a/components/bootloader/subproject/main/CMakeLists.txt +++ b/components/bootloader/subproject/main/CMakeLists.txt @@ -1,7 +1,5 @@ -set(COMPONENT_SRCS "bootloader_start.c") -set(COMPONENT_ADD_INCLUDEDIRS "") -set(COMPONENT_REQUIRES bootloader bootloader_support) -register_component() +idf_component_register(SRCS "bootloader_start.c" + REQUIRES bootloader bootloader_support) idf_build_get_property(target IDF_TARGET) set(scripts "${target}.bootloader.ld" diff --git a/components/bootloader_support/CMakeLists.txt b/components/bootloader_support/CMakeLists.txt index 2437829d54..a8db5c4873 100644 --- a/components/bootloader_support/CMakeLists.txt +++ b/components/bootloader_support/CMakeLists.txt @@ -1,4 +1,4 @@ -set(COMPONENT_SRCS "src/bootloader_clock.c" +set(srcs "src/bootloader_clock.c" "src/bootloader_common.c" "src/bootloader_flash.c" "src/bootloader_random.c" @@ -8,14 +8,14 @@ set(COMPONENT_SRCS "src/bootloader_clock.c" "src/flash_qio_mode.c") if(BOOTLOADER_BUILD) - set(COMPONENT_ADD_INCLUDEDIRS "include include_bootloader") - set(COMPONENT_REQUIRES soc) #unfortunately the header directly uses SOC registers - set(COMPONENT_PRIV_REQUIRES micro-ecc spi_flash efuse) - list(APPEND COMPONENT_SRCS "src/bootloader_init.c" - "src/${IDF_TARGET}/bootloader_sha.c" - "src/${IDF_TARGET}/flash_encrypt.c" - "src/${IDF_TARGET}/secure_boot_signatures.c" - "src/${IDF_TARGET}/secure_boot.c") + set(include_dirs "include" "include_bootloader") + set(requires soc) #unfortunately the header directly uses SOC registers + set(priv_requires micro-ecc spi_flash efuse) + list(APPEND srcs "src/bootloader_init.c" + "src/${IDF_TARGET}/bootloader_sha.c" + "src/${IDF_TARGET}/flash_encrypt.c" + "src/${IDF_TARGET}/secure_boot_signatures.c" + "src/${IDF_TARGET}/secure_boot.c") if(CONFIG_SECURE_SIGNED_APPS) get_filename_component(secure_boot_verification_key @@ -45,18 +45,23 @@ if(BOOTLOADER_BUILD) DEPENDS "${orig_secure_boot_verification_key}" VERBATIM) endif() - set(COMPONENT_EMBED_FILES "${secure_boot_verification_key}") + set(embed_files "${secure_boot_verification_key}") set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${secure_boot_verification_key}") endif() else() - list(APPEND COMPONENT_SRCS "src/idf/bootloader_sha.c" - "src/idf/secure_boot_signatures.c") - set(COMPONENT_ADD_INCLUDEDIRS "include") - set(COMPONENT_PRIV_INCLUDEDIRS "include_bootloader") - set(COMPONENT_REQUIRES soc) #unfortunately the header directly uses SOC registers - set(COMPONENT_PRIV_REQUIRES spi_flash mbedtls efuse) + list(APPEND srcs "src/idf/bootloader_sha.c" + "src/idf/secure_boot_signatures.c") + set(include_dirs "include") + set(priv_include_dirs "include_bootloader") + set(requires soc) #unfortunately the header directly uses SOC registers + set(priv_requires spi_flash mbedtls efuse) endif() -register_component() \ No newline at end of file +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + PRIV_INCLUDE_DIRS "${priv_include_dirs}" + REQUIRES "${requires}" + PRIV_REQUIRES "${priv_requires}" + EMBED_FILES "${embed_files}") \ No newline at end of file diff --git a/components/bootloader_support/test/CMakeLists.txt b/components/bootloader_support/test/CMakeLists.txt index 587c81609c..a31c179345 100644 --- a/components/bootloader_support/test/CMakeLists.txt +++ b/components/bootloader_support/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity bootloader_support app_update) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity bootloader_support app_update) diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index e1d1fef01c..2057ea0c75 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -1,11 +1,11 @@ if(CONFIG_BT_ENABLED) - set(COMPONENT_SRCS "bt.c") - set(COMPONENT_ADD_INCLUDEDIRS include) + set(srcs "bt.c") + set(include_dirs include) if(CONFIG_BT_BLUEDROID_ENABLED) - list(APPEND COMPONENT_PRIV_INCLUDEDIRS + list(APPEND priv_include_dirs bluedroid/bta/include bluedroid/bta/ar/include bluedroid/bta/av/include @@ -41,9 +41,9 @@ if(CONFIG_BT_ENABLED) bluedroid/stack/include bluedroid/common/include) - list(APPEND COMPONENT_ADD_INCLUDEDIRS bluedroid/api/include/api) + list(APPEND include_dirs bluedroid/api/include/api) - list(APPEND COMPONENT_SRCS "bluedroid/api/esp_a2dp_api.c" + list(APPEND srcs "bluedroid/api/esp_a2dp_api.c" "bluedroid/api/esp_avrc_api.c" "bluedroid/api/esp_blufi_api.c" "bluedroid/api/esp_bt_device.c" @@ -287,9 +287,10 @@ if(CONFIG_BT_ENABLED) endif() # requirements can't depend on config -set(COMPONENT_PRIV_REQUIRES nvs_flash soc) - -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + PRIV_INCLUDE_DIRS "${priv_include_dirs}" + REQUIRES nvs_flash soc) if(CONFIG_BT_ENABLED) if(GCC_NOT_5_2_0) diff --git a/components/bt/test/CMakeLists.txt b/components/bt/test/CMakeLists.txt index e59c45744a..0012e8bd17 100644 --- a/components/bt/test/CMakeLists.txt +++ b/components/bt/test/CMakeLists.txt @@ -1,7 +1,5 @@ if(CONFIG_BT_ENABLED OR CMAKE_BUILD_EARLY_EXPANSION) - set(COMPONENT_SRCDIRS ".") - set(COMPONENT_ADD_INCLUDEDIRS ".") - set(COMPONENT_REQUIRES unity nvs_flash bt) - - register_component() -endif() + idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity nvs_flash bt) +endif() \ No newline at end of file diff --git a/components/coap/CMakeLists.txt b/components/coap/CMakeLists.txt index 246a0e28e4..78015bb056 100644 --- a/components/coap/CMakeLists.txt +++ b/components/coap/CMakeLists.txt @@ -1,6 +1,6 @@ -set(COMPONENT_ADD_INCLUDEDIRS port/include port/include/coap libcoap/include libcoap/include/coap2) +set(include_dirs port/include port/include/coap libcoap/include libcoap/include/coap2) -set(COMPONENT_SRCS "libcoap/src/address.c" +set(srcs "libcoap/src/address.c" "libcoap/src/async.c" "libcoap/src/block.c" "libcoap/src/coap_event.c" @@ -22,7 +22,9 @@ set(COMPONENT_SRCS "libcoap/src/address.c" set(COMPONENT_REQUIRES lwip) -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + REQUIRES lwip) # Silence format truncation warning, until it is fixed upstream set_source_files_properties(libcoap/src/coap_debug.c PROPERTIES COMPILE_FLAGS -Wno-format-truncation) diff --git a/components/console/CMakeLists.txt b/components/console/CMakeLists.txt index 33dddc81a9..244834c224 100644 --- a/components/console/CMakeLists.txt +++ b/components/console/CMakeLists.txt @@ -1,7 +1,6 @@ -set(COMPONENT_ADD_INCLUDEDIRS .) -set(COMPONENT_SRCS "commands.c" - "split_argv.c" - "argtable3/argtable3.c" - "linenoise/linenoise.c") -register_component() - +idf_component_register(SRCS "commands.c" + "split_argv.c" + "argtable3/argtable3.c" + "linenoise/linenoise.c" + INCLUDE_DIRS "." + REQUIRES vfs) diff --git a/components/cxx/CMakeLists.txt b/components/cxx/CMakeLists.txt index dbfe20dd32..4e81992ad0 100644 --- a/components/cxx/CMakeLists.txt +++ b/components/cxx/CMakeLists.txt @@ -1,6 +1,5 @@ -set(COMPONENT_SRCS "cxx_exception_stubs.cpp" - "cxx_guards.cpp") -register_component() +idf_component_register(SRCS "cxx_exception_stubs.cpp" + "cxx_guards.cpp") target_link_libraries(${COMPONENT_LIB} PUBLIC stdc++ gcc) target_link_libraries(${COMPONENT_LIB} INTERFACE "-u __cxa_guard_dummy") diff --git a/components/cxx/test/CMakeLists.txt b/components/cxx/test/CMakeLists.txt index 884ca8b6da..16aca87790 100644 --- a/components/cxx/test/CMakeLists.txt +++ b/components/cxx/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity) \ No newline at end of file diff --git a/components/driver/CMakeLists.txt b/components/driver/CMakeLists.txt index 9b36ca854b..ddeb98d108 100644 --- a/components/driver/CMakeLists.txt +++ b/components/driver/CMakeLists.txt @@ -1,33 +1,32 @@ -set(COMPONENT_SRCS "can.c" - "gpio.c" - "i2c.c" - "i2s.c" - "ledc.c" - "mcpwm.c" - "pcnt.c" - "periph_ctrl.c" - "rmt.c" - "rtc_module.c" - "sdio_slave.c" - "sdmmc_host.c" - "sdmmc_transaction.c" - "sdspi_crc.c" - "sdspi_host.c" - "sdspi_transaction.c" - "sigmadelta.c" - "spi_common.c" - "spi_master.c" - "spi_slave.c" - "timer.c" - "uart.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_PRIV_INCLUDEDIRS "include/driver") -set(COMPONENT_REQUIRES esp_ringbuf soc) #cannot totally hide soc headers, since there are a lot arguments in the driver are chip-dependent - -register_component() +set(srcs "can.c" + "gpio.c" + "i2c.c" + "i2s.c" + "ledc.c" + "mcpwm.c" + "pcnt.c" + "periph_ctrl.c" + "rmt.c" + "rtc_module.c" + "sdio_slave.c" + "sdmmc_host.c" + "sdmmc_transaction.c" + "sdspi_crc.c" + "sdspi_host.c" + "sdspi_transaction.c" + "sigmadelta.c" + "spi_common.c" + "spi_master.c" + "spi_slave.c" + "timer.c" + "uart.c") +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "include/driver" + REQUIRES esp_ringbuf soc) #cannot totally hide soc headers, since there are a lot arguments in the driver are chip-dependent if(GCC_NOT_5_2_0) # uses C11 atomic feature set_source_files_properties(spi_master.c PROPERTIES COMPILE_FLAGS -std=gnu11) -endif() +endif() \ No newline at end of file diff --git a/components/driver/test/CMakeLists.txt b/components/driver/test/CMakeLists.txt index b48610adcd..7102bae72e 100644 --- a/components/driver/test/CMakeLists.txt +++ b/components/driver/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ". param_test") -set(COMPONENT_ADD_INCLUDEDIRS "include param_test/include") - -set(COMPONENT_REQUIRES unity test_utils driver nvs_flash) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." "param_test" + INCLUDE_DIRS "include" "param_test/include" + REQUIRES unity test_utils driver nvs_flash) \ No newline at end of file diff --git a/components/efuse/CMakeLists.txt b/components/efuse/CMakeLists.txt index f649a242f4..f43a2e6030 100644 --- a/components/efuse/CMakeLists.txt +++ b/components/efuse/CMakeLists.txt @@ -3,16 +3,17 @@ idf_build_get_property(soc_name IDF_TARGET) if(EXISTS "${COMPONENT_DIR}/${soc_name}") include(${COMPONENT_DIR}/${soc_name}/sources.cmake) spaces2list(EFUSE_SOC_SRCS) - add_prefix(COMPONENT_SRCS "${soc_name}/" ${EFUSE_SOC_SRCS}) - set(COMPONENT_ADD_INCLUDEDIRS include ${soc_name}/include) + add_prefix(srcs "${soc_name}/" ${EFUSE_SOC_SRCS}) + set(include_dirs include ${soc_name}/include) endif() -list(APPEND COMPONENT_SRCS "src/esp_efuse_api.c" - "src/esp_efuse_fields.c" - "src/esp_efuse_utility.c") +list(APPEND srcs "src/esp_efuse_api.c" + "src/esp_efuse_fields.c" + "src/esp_efuse_utility.c") -set(COMPONENT_PRIV_REQUIRES bootloader_support soc) -register_component() +idf_component_register(SRCS "${srcs}" + PRIV_REQUIRES bootloader_support soc + INCLUDE_DIRS "${include_dirs}") set(GEN_EFUSE_TABLE_ARG --max_blk_len ${CONFIG_EFUSE_MAX_BLK_LEN}) diff --git a/components/efuse/test/CMakeLists.txt b/components/efuse/test/CMakeLists.txt index 28d0b2e7aa..e239bfe5ce 100644 --- a/components/efuse/test/CMakeLists.txt +++ b/components/efuse/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS "." "include") - -set(COMPONENT_REQUIRES unity test_utils efuse bootloader_support) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." "include" + REQUIRES unity test_utils efuse bootloader_support) \ No newline at end of file diff --git a/components/esp-tls/CMakeLists.txt b/components/esp-tls/CMakeLists.txt index 23f953d940..e08418e5a1 100644 --- a/components/esp-tls/CMakeLists.txt +++ b/components/esp-tls/CMakeLists.txt @@ -1,7 +1,4 @@ -set(COMPONENT_SRCS "esp_tls.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES mbedtls) -set(COMPONENT_PRIV_REQUIRES lwip nghttp) - -register_component() +idf_component_register(SRCS "esp_tls.c" + INCLUDE_DIRS "." + REQUIRES mbedtls + PRIV_REQUIRES lwip nghttp) diff --git a/components/esp32/CMakeLists.txt b/components/esp32/CMakeLists.txt index 9d763b41b9..b69f3747ed 100644 --- a/components/esp32/CMakeLists.txt +++ b/components/esp32/CMakeLists.txt @@ -1,50 +1,49 @@ -require_idf_targets(esp32) - if(BOOTLOADER_BUILD) # For bootloader, all we need from esp32 is headers - set(COMPONENT_ADD_INCLUDEDIRS include) - register_component() + idf_component_register(INCLUDE_DIRS include) target_linker_script(${COMPONENT_LIB} INTERFACE "ld/esp32.peripherals.ld") else() # Regular app build + set(srcs "brownout.c" + "cache_err_int.c" + "cache_sram_mmu.c" + "clk.c" + "cpu_start.c" + "crosscore_int.c" + "dport_access.c" + "dport_panic_highint_hdl.S" + "esp_adapter.c" + "esp_timer_esp32.c" + "esp_himem.c" + "gdbstub.c" + "hw_random.c" + "int_wdt.c" + "intr_alloc.c" + "panic.c" + "pm_esp32.c" + "pm_trace.c" + "reset_reason.c" + "sleep_modes.c" + "spiram.c" + "spiram_psram.c" + "system_api.c" + "task_wdt.c") + set(include_dirs "include") - set(COMPONENT_SRCS "brownout.c" - "cache_err_int.c" - "cache_sram_mmu.c" - "clk.c" - "cpu_start.c" - "crosscore_int.c" - "dport_access.c" - "dport_panic_highint_hdl.S" - "esp_adapter.c" - "esp_timer_esp32.c" - "esp_himem.c" - "gdbstub.c" - "hw_random.c" - "int_wdt.c" - "intr_alloc.c" - "panic.c" - "pm_esp32.c" - "pm_trace.c" - "reset_reason.c" - "sleep_modes.c" - "spiram.c" - "spiram_psram.c" - "system_api.c" - "task_wdt.c") - set(COMPONENT_ADD_INCLUDEDIRS "include") - - set(COMPONENT_REQUIRES driver esp_event efuse soc) #unfortunately rom/uart uses SOC registers directly + set(requires driver esp_event efuse soc) #unfortunately rom/uart uses SOC registers directly # driver is a public requirement because esp_sleep.h uses gpio_num_t & touch_pad_t # app_update is added here because cpu_start.c uses esp_ota_get_app_description() function. - set(COMPONENT_PRIV_REQUIRES - app_trace app_update bootloader_support log mbedtls nvs_flash pthread + set(priv_requires app_trace app_update bootloader_support log mbedtls nvs_flash pthread smartconfig_ack spi_flash vfs wpa_supplicant espcoredump esp_common esp_wifi) + set(fragments linker.lf ld/esp32_fragments.lf) - set(COMPONENT_ADD_LDFRAGMENTS linker.lf ld/esp32_fragments.lf) - - register_component() + idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + LDFRAGMENTS "${fragments}" + REQUIRES "${requires}" + PRIV_REQUIRES "${priv_requires}" + REQUIRED_IDF_TARGETS esp32) target_linker_script(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/esp32_out.ld") diff --git a/components/esp32/test/CMakeLists.txt b/components/esp32/test/CMakeLists.txt index 1ced21ed8a..b36af1bd1d 100644 --- a/components/esp32/test/CMakeLists.txt +++ b/components/esp32/test/CMakeLists.txt @@ -1,9 +1,6 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ". ${CMAKE_CURRENT_BINARY_DIR}") - -set(COMPONENT_REQUIRES unity test_utils nvs_flash ulp esp_common) - -register_component() +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." "${CMAKE_CURRENT_BINARY_DIR}" + REQUIRES unity test_utils nvs_flash ulp esp_common) add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test_tjpgd_logo.h" COMMAND xxd -i "logo.jpg" "${CMAKE_CURRENT_BINARY_DIR}/test_tjpgd_logo.h" diff --git a/components/esp_adc_cal/CMakeLists.txt b/components/esp_adc_cal/CMakeLists.txt index 8bb99092e2..baef0b690e 100644 --- a/components/esp_adc_cal/CMakeLists.txt +++ b/components/esp_adc_cal/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCS "esp_adc_cal.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") - -set(COMPONENT_REQUIRES) - -register_component() +idf_component_register(SRCS "esp_adc_cal.c" + INCLUDE_DIRS "include" + REQUIRES driver) diff --git a/components/esp_common/CMakeLists.txt b/components/esp_common/CMakeLists.txt index 18ffe93678..bb9bd8a7a4 100644 --- a/components/esp_common/CMakeLists.txt +++ b/components/esp_common/CMakeLists.txt @@ -1,27 +1,19 @@ if(BOOTLOADER_BUILD) # For bootloader, all we need from esp_common is headers - set(COMPONENT_ADD_INCLUDEDIRS include) - set(COMPONENT_REQUIRES ${IDF_COMPONENTS}) - set(COMPONENT_SRCS ) - register_component() + idf_component_register(INCLUDE_DIRS include) set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-Wl,--gc-sections") else() # Regular app build - set(COMPONENT_SRCS - "src/dbg_stubs.c" - "src/esp_err_to_name.c" - "src/esp_timer.c" - "src/ets_timer_legacy.c" - "src/freertos_hooks.c" - "src/ipc.c" - "src/pm_locks.c" - "src/stack_check.c") - set(COMPONENT_ADD_INCLUDEDIRS "include") - set(COMPONENT_PRIV_INCLUDEDIRS) - set(COMPONENT_REQUIRES) - set(COMPONENT_PRIV_REQUIRES soc) - - register_component() + idf_component_register(SRCS "src/dbg_stubs.c" + "src/esp_err_to_name.c" + "src/esp_timer.c" + "src/ets_timer_legacy.c" + "src/freertos_hooks.c" + "src/ipc.c" + "src/pm_locks.c" + "src/stack_check.c" + INCLUDE_DIRS include + PRIV_REQUIRES soc) set_source_files_properties( "src/stack_check.c" diff --git a/components/esp_event/CMakeLists.txt b/components/esp_event/CMakeLists.txt index 53aff6b0a2..becd3ba7f6 100644 --- a/components/esp_event/CMakeLists.txt +++ b/components/esp_event/CMakeLists.txt @@ -1,19 +1,13 @@ -set(COMPONENT_SRCS "default_event_loop.c" - "esp_event.c" - "esp_event_private.c" - "event_loop_legacy.c" - "event_send.c") - -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_PRIV_INCLUDEDIRS "private_include") - -set(COMPONENT_REQUIRES log tcpip_adapter) -set(COMPONENT_PRIV_REQUIRES ethernet) -set(COMPONENT_REQUIRES log tcpip_adapter ethernet) - -set(COMPONENT_ADD_LDFRAGMENTS linker.lf) - -register_component() +idf_component_register(SRCS "default_event_loop.c" + "esp_event.c" + "esp_event_private.c" + "event_loop_legacy.c" + "event_send.c" + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "private_include" + REQUIRES log tcpip_adapter + PRIV_REQUIRES ethernet + LDFRAGMENTS linker.lf) if(GCC_NOT_5_2_0 AND CONFIG_ESP_EVENT_LOOP_PROFILING) # uses C11 atomic feature diff --git a/components/esp_event/test/CMakeLists.txt b/components/esp_event/test/CMakeLists.txt index 287a2ba928..8264f10dda 100644 --- a/components/esp_event/test/CMakeLists.txt +++ b/components/esp_event/test/CMakeLists.txt @@ -1,5 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_PRIV_INCLUDEDIRS "../private_include" ".") -set(COMPONENT_PRIV_REQUIRES unity test_utils esp_event driver) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + PRIV_INCLUDE_DIRS "../private_include" "." + REQUIRES unity test_utils esp_event driver) diff --git a/components/esp_http_client/CMakeLists.txt b/components/esp_http_client/CMakeLists.txt index 2bea7ce022..327e90778a 100644 --- a/components/esp_http_client/CMakeLists.txt +++ b/components/esp_http_client/CMakeLists.txt @@ -1,11 +1,8 @@ -set(COMPONENT_SRCS "esp_http_client.c" - "lib/http_auth.c" - "lib/http_header.c" - "lib/http_utils.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_PRIV_INCLUDEDIRS "lib/include") - -set(COMPONENT_REQUIRES "nghttp") -set(COMPONENT_PRIV_REQUIRES "mbedtls" "lwip" "esp-tls" "tcp_transport") - -register_component() +idf_component_register(SRCS "esp_http_client.c" + "lib/http_auth.c" + "lib/http_header.c" + "lib/http_utils.c" + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "lib/include" + REQUIRES nghttp + PRIV_REQUIRES mbedtls lwip esp-tls tcp_transport) diff --git a/components/esp_http_client/test/CMakeLists.txt b/components/esp_http_client/test/CMakeLists.txt index 6b99d7546a..70fc98dcad 100644 --- a/components/esp_http_client/test/CMakeLists.txt +++ b/components/esp_http_client/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils esp_http_client) - -register_component() +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils esp_http_client) \ No newline at end of file diff --git a/components/esp_http_server/CMakeLists.txt b/components/esp_http_server/CMakeLists.txt index 700a0b9cb1..4bf15aa866 100644 --- a/components/esp_http_server/CMakeLists.txt +++ b/components/esp_http_server/CMakeLists.txt @@ -1,13 +1,10 @@ -set(COMPONENT_ADD_INCLUDEDIRS include) -set(COMPONENT_PRIV_INCLUDEDIRS src/port/esp32 src/util) -set(COMPONENT_SRCS "src/httpd_main.c" - "src/httpd_parse.c" - "src/httpd_sess.c" - "src/httpd_txrx.c" - "src/httpd_uri.c" - "src/util/ctrl_sock.c") - -set(COMPONENT_REQUIRES nghttp) # for http_parser.h -set(COMPONENT_PRIV_REQUIRES lwip) - -register_component() +idf_component_register(SRCS "src/httpd_main.c" + "src/httpd_parse.c" + "src/httpd_sess.c" + "src/httpd_txrx.c" + "src/httpd_uri.c" + "src/util/ctrl_sock.c" + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "src/port/esp32" "src/util" + REQUIRES nghttp + PRIV_REQUIRES lwip) # for http_parser.h diff --git a/components/esp_http_server/test/CMakeLists.txt b/components/esp_http_server/test/CMakeLists.txt index de20de38f5..e2ceeb2986 100644 --- a/components/esp_http_server/test/CMakeLists.txt +++ b/components/esp_http_server/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils esp_http_server) - -register_component() +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils esp_http_server) \ No newline at end of file diff --git a/components/esp_https_ota/CMakeLists.txt b/components/esp_https_ota/CMakeLists.txt index 6ef0a5c9e0..8608666fde 100644 --- a/components/esp_https_ota/CMakeLists.txt +++ b/components/esp_https_ota/CMakeLists.txt @@ -1,7 +1,4 @@ -set(COMPONENT_ADD_INCLUDEDIRS include) -set(COMPONENT_SRCS "src/esp_https_ota.c") - -set(COMPONENT_REQUIRES esp_http_client) -set(COMPONENT_PRIV_REQUIRES log app_update) - -register_component() +idf_component_register(SRCS "src/esp_https_ota.c" + INCLUDE_DIRS "include" + REQUIRES esp_http_client + PRIV_REQUIRES log app_update) diff --git a/components/esp_https_server/CMakeLists.txt b/components/esp_https_server/CMakeLists.txt index dfdaa11ecc..c63549b0e2 100644 --- a/components/esp_https_server/CMakeLists.txt +++ b/components/esp_https_server/CMakeLists.txt @@ -1,7 +1,4 @@ -set(COMPONENT_ADD_INCLUDEDIRS include) -set(COMPONENT_SRCS "src/https_server.c") - -set(COMPONENT_REQUIRES esp_http_server openssl) -set(COMPONENT_PRIV_REQUIRES lwip) - -register_component() +idf_component_register(SRCS "src/https_server.c" + INCLUDE_DIRS "include" + REQUIRES esp_http_server openssl + PRIV_REQUIRES lwip) diff --git a/components/esp_ringbuf/CMakeLists.txt b/components/esp_ringbuf/CMakeLists.txt index bba1dfd6d8..4c4b114af9 100644 --- a/components/esp_ringbuf/CMakeLists.txt +++ b/components/esp_ringbuf/CMakeLists.txt @@ -1,7 +1,3 @@ -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_SRCS "ringbuf.c") -set(COMPONENT_ADD_LDFRAGMENTS linker.lf) - -set(COMPONENT_REQUIRES) - -register_component() +idf_component_register(SRCS "ringbuf.c" + INCLUDE_DIRS "include" + LDFRAGMENTS linker.lf) diff --git a/components/esp_ringbuf/test/CMakeLists.txt b/components/esp_ringbuf/test/CMakeLists.txt index 236536c476..b531a14504 100644 --- a/components/esp_ringbuf/test/CMakeLists.txt +++ b/components/esp_ringbuf/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils) - -register_component() +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils) \ No newline at end of file diff --git a/components/esp_rom/CMakeLists.txt b/components/esp_rom/CMakeLists.txt index 188f511eac..2c903a5100 100644 --- a/components/esp_rom/CMakeLists.txt +++ b/components/esp_rom/CMakeLists.txt @@ -1,9 +1,6 @@ if(BOOTLOADER_BUILD) # For bootloader, all we need is headers - set(COMPONENT_ADD_INCLUDEDIRS "include") - set(COMPONENT_REQUIRES ${IDF_COMPONENTS}) - set(COMPONENT_SRCS) - register_component() + idf_component_register(INCLUDE_DIRS include) set(scripts "esp32/ld/esp32.rom.ld" "esp32/ld/esp32.rom.newlib-funcs.ld" @@ -12,10 +9,8 @@ if(BOOTLOADER_BUILD) target_linker_script(${COMPONENT_LIB} INTERFACE "${scripts}") else() # Regular app build - set(COMPONENT_SRCS "esp_rom.c") - set(COMPONENT_ADD_INCLUDEDIRS "include") - - register_component() + idf_component_register(SRCS "esp_rom.c" + INCLUDE_DIRS include) set(scripts "esp32/ld/esp32.rom.ld" diff --git a/components/esp_wifi/CMakeLists.txt b/components/esp_wifi/CMakeLists.txt index 5349e905ac..4cf4723b4a 100644 --- a/components/esp_wifi/CMakeLists.txt +++ b/components/esp_wifi/CMakeLists.txt @@ -1,7 +1,7 @@ idf_build_get_property(idf_target IDF_TARGET) idf_build_get_property(build_dir BUILD_DIR) -set(COMPONENT_SRCS +set(srcs "src/coexist.c" "src/fast_crypto_ops.c" "src/lib_printf.c" @@ -9,15 +9,16 @@ set(COMPONENT_SRCS "src/phy_init.c" "src/restore.c" "src/wifi_init.c") -set(COMPONENT_ADD_INCLUDEDIRS "include" "${idf_target}/include") -set(COMPONENT_PRIV_INCLUDEDIRS) -set(COMPONENT_PRIV_REQUIRES wpa_supplicant nvs_flash) if(NOT CONFIG_ESP32_NO_BLOBS) - set(COMPONENT_ADD_LDFRAGMENTS "linker.lf") + set(ldfragments "linker.lf") endif() -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "include" "${idf_target}/include" + PRIV_REQUIRES wpa_supplicant nvs_flash + LDFRAGMENTS "${ldfragments}") + target_link_libraries(${COMPONENT_LIB} PUBLIC "-L ${CMAKE_CURRENT_SOURCE_DIR}/lib_${idf_target}") if(NOT CONFIG_ESP32_NO_BLOBS) diff --git a/components/esp_wifi/test/CMakeLists.txt b/components/esp_wifi/test/CMakeLists.txt index 6f9211dcc6..a3ff3757c3 100644 --- a/components/esp_wifi/test/CMakeLists.txt +++ b/components/esp_wifi/test/CMakeLists.txt @@ -1,9 +1,6 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ". ${CMAKE_CURRENT_BINARY_DIR}") - -set(COMPONENT_REQUIRES unity test_utils nvs_flash ulp esp_common) - -register_component() +idf_component_register(SRCDIRS "." + INCLUDE_DIRS "." "${CMAKE_CURRENT_BINARY_DIR}" + REQUIRES unity test_utils nvs_flash ulp esp_common) idf_component_get_property(esp_wifi_dir esp_wifi COMPONENT_DIR) diff --git a/components/espcoredump/CMakeLists.txt b/components/espcoredump/CMakeLists.txt index 8ef4c1ce70..f925f93db2 100644 --- a/components/espcoredump/CMakeLists.txt +++ b/components/espcoredump/CMakeLists.txt @@ -1,10 +1,8 @@ -set(COMPONENT_PRIV_INCLUDEDIRS "include_core_dump") -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_PRIV_REQUIRES spi_flash soc) -set(COMPONENT_ADD_LDFRAGMENTS linker.lf) -set(COMPONENT_SRCS "src/core_dump_common.c" - "src/core_dump_flash.c" - "src/core_dump_port.c" - "src/core_dump_uart.c") - -register_component() +idf_component_register(SRCS "src/core_dump_common.c" + "src/core_dump_flash.c" + "src/core_dump_port.c" + "src/core_dump_uart.c" + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "include_core_dump" + LDFRAGMENTS linker.lf + PRIV_REQUIRES spi_flash soc) diff --git a/components/espcoredump/test/CMakeLists.txt b/components/espcoredump/test/CMakeLists.txt index 6704c238b9..c000ba4e57 100644 --- a/components/espcoredump/test/CMakeLists.txt +++ b/components/espcoredump/test/CMakeLists.txt @@ -1,8 +1,7 @@ if(TESTS_ALL EQUAL 1) message("not linking coredump test from CI.") else() - set(COMPONENT_SRCDIRS ".") - set(COMPONENT_ADD_INCLUDEDIRS ".") - set(COMPONENT_REQUIRES unity nvs_flash) - register_component() + idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity nvs_flash) endif() \ No newline at end of file diff --git a/components/esptool_py/CMakeLists.txt b/components/esptool_py/CMakeLists.txt index 09764ccf05..10a0f3457d 100644 --- a/components/esptool_py/CMakeLists.txt +++ b/components/esptool_py/CMakeLists.txt @@ -1,5 +1,4 @@ -set(COMPONENT_PRIV_REQUIRES bootloader) -register_component() +idf_component_register(REQUIRES bootloader) string(REPLACE ";" " " ESPTOOLPY_FLASH_PROJECT_OPTIONS "${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS}") set(ESPTOOLPY_FLASH_PROJECT_OPTIONS diff --git a/components/ethernet/CMakeLists.txt b/components/ethernet/CMakeLists.txt index 704d21a7d7..3951c97c22 100644 --- a/components/ethernet/CMakeLists.txt +++ b/components/ethernet/CMakeLists.txt @@ -1,12 +1,8 @@ -set(COMPONENT_SRCS "emac_dev.c" - "emac_main.c" - "eth_phy/phy_common.c" - "eth_phy/phy_lan8720.c" - "eth_phy/phy_tlk110.c" - "eth_phy/phy_ip101.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") - -set(COMPONENT_REQUIRES) -set(COMPONENT_PRIV_REQUIRES tcpip_adapter esp_event soc) - -register_component() +idf_component_register(SRCS "emac_dev.c" + "emac_main.c" + "eth_phy/phy_common.c" + "eth_phy/phy_lan8720.c" + "eth_phy/phy_tlk110.c" + "eth_phy/phy_ip101.c" + INCLUDE_DIRS "include" + PRIV_REQUIRES tcpip_adapter esp_event soc) diff --git a/components/ethernet/test/CMakeLists.txt b/components/ethernet/test/CMakeLists.txt index d5d44577ae..ae46c13bfd 100644 --- a/components/ethernet/test/CMakeLists.txt +++ b/components/ethernet/test/CMakeLists.txt @@ -1,5 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") -set(COMPONENT_REQUIRES unity ethernet) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity ethernet) \ No newline at end of file diff --git a/components/expat/CMakeLists.txt b/components/expat/CMakeLists.txt index 596aee917c..a6c5882c79 100644 --- a/components/expat/CMakeLists.txt +++ b/components/expat/CMakeLists.txt @@ -1,11 +1,10 @@ -set(COMPONENT_ADD_INCLUDEDIRS expat/expat/lib port/include) -set(COMPONENT_SRCS "expat/expat/lib/loadlibrary.c" - "expat/expat/lib/xmlparse.c" - "expat/expat/lib/xmlrole.c" - "expat/expat/lib/xmltok.c" - "expat/expat/lib/xmltok_impl.c" - "expat/expat/lib/xmltok_ns.c") -register_component() +idf_component_register(SRCS "expat/expat/lib/loadlibrary.c" + "expat/expat/lib/xmlparse.c" + "expat/expat/lib/xmlrole.c" + "expat/expat/lib/xmltok.c" + "expat/expat/lib/xmltok_impl.c" + "expat/expat/lib/xmltok_ns.c" + INCLUDE_DIRS expat/expat/lib port/include) target_compile_definitions(${COMPONENT_LIB} PRIVATE HAVE_EXPAT_CONFIG_H) target_compile_definitions(${COMPONENT_LIB} PRIVATE HAVE_GETRANDOM) diff --git a/components/expat/test/CMakeLists.txt b/components/expat/test/CMakeLists.txt index be2a822177..28d0afb413 100644 --- a/components/expat/test/CMakeLists.txt +++ b/components/expat/test/CMakeLists.txt @@ -1,5 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") -set(COMPONENT_REQUIRES unity expat) - -register_component() +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity expat) \ No newline at end of file diff --git a/components/fatfs/CMakeLists.txt b/components/fatfs/CMakeLists.txt index 4df07d30b9..d46f077252 100644 --- a/components/fatfs/CMakeLists.txt +++ b/components/fatfs/CMakeLists.txt @@ -1,15 +1,14 @@ -set(COMPONENT_SRCS "src/diskio.c" - "src/diskio_rawflash.c" - "src/diskio_sdmmc.c" - "src/diskio_wl.c" - "src/ff.c" - "src/ffsystem.c" - "src/ffunicode.c" - "src/vfs_fat.c" - "src/vfs_fat_sdmmc.c" - "src/vfs_fat_spiflash.c") -set(COMPONENT_ADD_INCLUDEDIRS src) - -set(COMPONENT_REQUIRES wear_levelling sdmmc) - -register_component() +set(srcs "src/diskio.c" + "src/diskio_rawflash.c" + "src/diskio_sdmmc.c" + "src/diskio_wl.c" + "src/ff.c" + "src/ffsystem.c" + "src/ffunicode.c" + "src/vfs_fat.c" + "src/vfs_fat_sdmmc.c" + "src/vfs_fat_spiflash.c") + +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS src + REQUIRES wear_levelling sdmmc) diff --git a/components/fatfs/test/CMakeLists.txt b/components/fatfs/test/CMakeLists.txt index 5e0431c469..2796e95eb4 100644 --- a/components/fatfs/test/CMakeLists.txt +++ b/components/fatfs/test/CMakeLists.txt @@ -1,8 +1,4 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils vfs fatfs) - -set(COMPONENT_EMBED_TXTFILES fatfs.img) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils vfs fatfs + EMBED_TXTFILES fatfs.img) \ No newline at end of file diff --git a/components/freemodbus/CMakeLists.txt b/components/freemodbus/CMakeLists.txt index 4b57c16619..0bf6b6af07 100644 --- a/components/freemodbus/CMakeLists.txt +++ b/components/freemodbus/CMakeLists.txt @@ -1,41 +1,43 @@ # The following five lines of boilerplate have to be in your project's # CMakeLists in this exact order for cmake to work correctly -set(COMPONENT_SRCS "common/esp_modbus_master.c" - "common/esp_modbus_slave.c" - "modbus/mb.c" - "modbus/mb_m.c" - "modbus/ascii/mbascii.c" - "modbus/rtu/mbrtu_m.c" - "modbus/rtu/mbrtu.c" - "modbus/rtu/mbcrc.c" - "modbus/tcp/mbtcp.c" - "port/port.c" - "port/portevent.c" - "port/portevent_m.c" - "port/portother.c" - "port/portother_m.c" - "port/portserial.c" - "port/portserial_m.c" - "port/porttimer.c" - "port/porttimer_m.c" - "modbus/functions/mbfunccoils.c" - "modbus/functions/mbfunccoils_m.c" - "modbus/functions/mbfuncdiag.c" - "modbus/functions/mbfuncdisc.c" - "modbus/functions/mbfuncdisc_m.c" - "modbus/functions/mbfuncholding.c" - "modbus/functions/mbfuncholding_m.c" - "modbus/functions/mbfuncinput.c" - "modbus/functions/mbfuncinput_m.c" - "modbus/functions/mbfuncother.c" - "modbus/functions/mbutils.c" - "serial_slave/modbus_controller/mbc_serial_slave.c" - "serial_master/modbus_controller/mbc_serial_master.c") -set(COMPONENT_ADD_INCLUDEDIRS common/include) -set(COMPONENT_PRIV_INCLUDEDIRS common port modbus modbus/ascii modbus/functions +set(srcs "common/esp_modbus_master.c" + "common/esp_modbus_slave.c" + "modbus/mb.c" + "modbus/mb_m.c" + "modbus/ascii/mbascii.c" + "modbus/rtu/mbrtu_m.c" + "modbus/rtu/mbrtu.c" + "modbus/rtu/mbcrc.c" + "modbus/tcp/mbtcp.c" + "port/port.c" + "port/portevent.c" + "port/portevent_m.c" + "port/portother.c" + "port/portother_m.c" + "port/portserial.c" + "port/portserial_m.c" + "port/porttimer.c" + "port/porttimer_m.c" + "modbus/functions/mbfunccoils.c" + "modbus/functions/mbfunccoils_m.c" + "modbus/functions/mbfuncdiag.c" + "modbus/functions/mbfuncdisc.c" + "modbus/functions/mbfuncdisc_m.c" + "modbus/functions/mbfuncholding.c" + "modbus/functions/mbfuncholding_m.c" + "modbus/functions/mbfuncinput.c" + "modbus/functions/mbfuncinput_m.c" + "modbus/functions/mbfuncother.c" + "modbus/functions/mbutils.c" + "serial_slave/modbus_controller/mbc_serial_slave.c" + "serial_master/modbus_controller/mbc_serial_master.c") +set(include_dirs common/include) +set(priv_include_dirs common port modbus modbus/ascii modbus/functions modbus/rtu modbus/tcp modbus/include) -list(APPEND COMPONENT_PRIV_INCLUDEDIRS serial_slave/port serial_slave/modbus_controller +list(APPEND priv_include_dirs serial_slave/port serial_slave/modbus_controller serial_master/port serial_master/modbus_controller) -set(COMPONENT_REQUIRES "driver") -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + PRIV_INCLUDE_DIRS "${priv_include_dirs}" + REQUIRES driver) diff --git a/components/freertos/CMakeLists.txt b/components/freertos/CMakeLists.txt index a7a83bbebc..0efd886e0d 100644 --- a/components/freertos/CMakeLists.txt +++ b/components/freertos/CMakeLists.txt @@ -1,29 +1,27 @@ -set(COMPONENT_ADD_INCLUDEDIRS include) -set(COMPONENT_PRIV_INCLUDEDIRS include/freertos .) -set(COMPONENT_SRCS "croutine.c" - "event_groups.c" - "FreeRTOS-openocd.c" - "list.c" - "port.c" - "portasm.S" - "queue.c" - "tasks.c" - "timers.c" - "xtensa_context.S" - "xtensa_init.c" - "xtensa_intr.c" - "xtensa_intr_asm.S" - "xtensa_overlay_os_hook.c" - "xtensa_vector_defaults.S" - "xtensa_vectors.S") - +set(srcs "croutine.c" + "event_groups.c" + "FreeRTOS-openocd.c" + "list.c" + "port.c" + "portasm.S" + "queue.c" + "tasks.c" + "timers.c" + "xtensa_context.S" + "xtensa_init.c" + "xtensa_intr.c" + "xtensa_intr_asm.S" + "xtensa_overlay_os_hook.c" + "xtensa_vector_defaults.S" + "xtensa_vectors.S") # app_trace is required by FreeRTOS headers only when CONFIG_SYSVIEW_ENABLE=y, # but requirements can't depend on config options, so always require it. -set(COMPONENT_REQUIRES app_trace) -set(COMPONENT_PRIV_REQUIRES esp_common soc) -set(COMPONENT_ADD_LDFRAGMENTS linker.lf) - -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS include + PRIV_INCLUDE_DIRS include/freertos . + LDFRAGMENTS linker.lf + REQUIRES app_trace + PRIV_REQUIRES soc) target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--undefined=uxTopUsedPriority") diff --git a/components/freertos/test/CMakeLists.txt b/components/freertos/test/CMakeLists.txt index 66a8c82315..b531a14504 100644 --- a/components/freertos/test/CMakeLists.txt +++ b/components/freertos/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils) \ No newline at end of file diff --git a/components/heap/CMakeLists.txt b/components/heap/CMakeLists.txt index 8ed72d2f2f..40fac3710b 100644 --- a/components/heap/CMakeLists.txt +++ b/components/heap/CMakeLists.txt @@ -1,23 +1,23 @@ -set(COMPONENT_SRCS "heap_caps.c" - "heap_caps_init.c" - "multi_heap.c") +set(srcs "heap_caps.c" + "heap_caps_init.c" + "multi_heap.c") if(NOT CONFIG_HEAP_POISONING_DISABLED) - list(APPEND COMPONENT_SRCS "multi_heap_poisoning.c") + list(APPEND srcs "multi_heap_poisoning.c") endif() if(CONFIG_HEAP_TASK_TRACKING) - list(APPEND COMPONENT_SRCS "heap_task_info.c") + list(APPEND srcs "heap_task_info.c") endif() if(CONFIG_HEAP_TRACING_STANDALONE) - list(APPEND COMPONENT_SRCS "heap_trace_standalone.c") + list(APPEND srcs "heap_trace_standalone.c") endif() -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_ADD_LDFRAGMENTS linker.lf) -set(COMPONENT_PRIV_REQUIRES soc) -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS include + LDFRAGMENTS linker.lf + PRIV_REQUIRES soc) if(CONFIG_HEAP_TRACING) set(WRAP_FUNCTIONS diff --git a/components/heap/test/CMakeLists.txt b/components/heap/test/CMakeLists.txt index aed6c9743e..b70637f263 100644 --- a/components/heap/test/CMakeLists.txt +++ b/components/heap/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils heap) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils heap) \ No newline at end of file diff --git a/components/idf_test/CMakeLists.txt b/components/idf_test/CMakeLists.txt index e307838a8b..eafb7ac220 100644 --- a/components/idf_test/CMakeLists.txt +++ b/components/idf_test/CMakeLists.txt @@ -1,2 +1 @@ -set(COMPONENT_ADD_INCLUDEDIRS "include") -register_component() +idf_component_register(INCLUDE_DIRS include) diff --git a/components/jsmn/CMakeLists.txt b/components/jsmn/CMakeLists.txt index 562a2cadcb..0c7a0ab99e 100644 --- a/components/jsmn/CMakeLists.txt +++ b/components/jsmn/CMakeLists.txt @@ -1,3 +1,2 @@ -set(COMPONENT_SRCS "src/jsmn.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") -register_component() +idf_component_register(SRCS "src/jsmn.c" + INCLUDE_DIRS "include") diff --git a/components/json/CMakeLists.txt b/components/json/CMakeLists.txt index 4a85a0b3d1..1ecadb3858 100644 --- a/components/json/CMakeLists.txt +++ b/components/json/CMakeLists.txt @@ -1,5 +1,4 @@ -set(COMPONENT_SRCS "cJSON/cJSON.c" - "cJSON/cJSON_Utils.c" - "cJSON/test.c") -set(COMPONENT_ADD_INCLUDEDIRS cJSON) -register_component() +idf_component_register(SRCS "cJSON/cJSON.c" + "cJSON/cJSON_Utils.c" + "cJSON/test.c" + INCLUDE_DIRS cJSON) diff --git a/components/libsodium/CMakeLists.txt b/components/libsodium/CMakeLists.txt index caef522233..358a840d25 100644 --- a/components/libsodium/CMakeLists.txt +++ b/components/libsodium/CMakeLists.txt @@ -1,7 +1,7 @@ set(SRC libsodium/src/libsodium) # Derived from libsodium/src/libsodium/Makefile.am # (ignoring the !MINIMAL set) -set(COMPONENT_SRCS "${SRC}/crypto_aead/chacha20poly1305/sodium/aead_chacha20poly1305.c" +set(srcs "${SRC}/crypto_aead/chacha20poly1305/sodium/aead_chacha20poly1305.c" "${SRC}/crypto_aead/xchacha20poly1305/sodium/aead_xchacha20poly1305.c" "${SRC}/crypto_auth/crypto_auth.c" "${SRC}/crypto_auth/hmacsha256/auth_hmacsha256.c" @@ -116,18 +116,19 @@ set(COMPONENT_SRCS "${SRC}/crypto_aead/chacha20poly1305/sodium/aead_chacha20poly "port/randombytes_esp32.c") if(CONFIG_LIBSODIUM_USE_MBEDTLS_SHA) - list(APPEND COMPONENT_SRCS "port/crypto_hash_mbedtls/crypto_hash_sha256_mbedtls.c" + list(APPEND srcs "port/crypto_hash_mbedtls/crypto_hash_sha256_mbedtls.c" "port/crypto_hash_mbedtls/crypto_hash_sha512_mbedtls.c") else() - list(APPEND COMPONENT_SRCS "${SRC}/crypto_hash/sha256/cp/hash_sha256_cp.c" + list(APPEND srcs "${SRC}/crypto_hash/sha256/cp/hash_sha256_cp.c" "${SRC}/crypto_hash/sha512/cp/hash_sha512_cp.c") endif() -set(COMPONENT_ADD_INCLUDEDIRS ${SRC}/include port_include) -set(COMPONENT_PRIV_INCLUDEDIRS ${SRC}/include/sodium port_include/sodium port) - -set(COMPONENT_REQUIRES mbedtls) -register_component() +set(include_dirs ${SRC}/include port_include) +set(priv_include_dirs ${SRC}/include/sodium port_include/sodium port) +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + PRIV_INCLUDE_DIRS "${priv_include_dirs}" + REQUIRES mbedtls) target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIGURED diff --git a/components/libsodium/test/CMakeLists.txt b/components/libsodium/test/CMakeLists.txt index 76ac24d2fc..2e3a43bad6 100644 --- a/components/libsodium/test/CMakeLists.txt +++ b/components/libsodium/test/CMakeLists.txt @@ -2,11 +2,7 @@ if(TESTS_ALL EQUAL 1) message("not linking libsodium tests, use '-T libsodium' to test it") else() get_filename_component(LS_TESTDIR "${CMAKE_CURRENT_LIST_DIR}/../libsodium/test/default" ABSOLUTE) - - set(COMPONENT_ADD_INCLUDEDIRS "." "${LS_TESTDIR}/../quirks") - - set(COMPONENT_REQUIRES unity libsodium) - + set(TEST_CASES "chacha20;aead_chacha20poly1305;box;box2;ed25519_convert;sign;hash") foreach(test_case ${TEST_CASES}) @@ -14,9 +10,9 @@ else() list(APPEND TEST_CASES_FILES ${test_case_file}) endforeach() - set(COMPONENT_SRCS "${TEST_CASES_FILES};test_sodium.c") - - register_component() + idf_component_register(SRCS "${TEST_CASES_FILES}" "test_sodium.c" + INCLUDE_DIRS "." "${LS_TESTDIR}/../quirks" + REQUIRES unity libsodium) # The libsodium test suite is designed to be run each test case as an executable on a desktop computer and uses # filesytem to write & then compare contents of each file. diff --git a/components/log/CMakeLists.txt b/components/log/CMakeLists.txt index 505dc93186..4ca3c1a544 100644 --- a/components/log/CMakeLists.txt +++ b/components/log/CMakeLists.txt @@ -1,4 +1,3 @@ -set(COMPONENT_SRCS "log.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_PRIV_REQUIRES soc) -register_component() +idf_component_register(SRCS "log.c" + INCLUDE_DIRS "include" + PRIV_REQUIRES soc) diff --git a/components/lwip/CMakeLists.txt b/components/lwip/CMakeLists.txt index 6a15d6f5c8..6eda8db37e 100644 --- a/components/lwip/CMakeLists.txt +++ b/components/lwip/CMakeLists.txt @@ -1,4 +1,4 @@ -set(COMPONENT_ADD_INCLUDEDIRS +set(include_dirs include/apps include/apps/sntp lwip/src/include @@ -6,92 +6,92 @@ set(COMPONENT_ADD_INCLUDEDIRS port/esp32/include/arch ) -set(COMPONENT_SRCS "apps/dhcpserver/dhcpserver.c" - "apps/ping/esp_ping.c" - "apps/ping/ping.c" - "apps/sntp/sntp.c" - "lwip/src/api/api_lib.c" - "lwip/src/api/api_msg.c" - "lwip/src/api/err.c" - "lwip/src/api/netbuf.c" - "lwip/src/api/netdb.c" - "lwip/src/api/netifapi.c" - "lwip/src/api/sockets.c" - "lwip/src/api/tcpip.c" - "lwip/src/apps/sntp/sntp.c" - "lwip/src/core/def.c" - "lwip/src/core/dns.c" - "lwip/src/core/inet_chksum.c" - "lwip/src/core/init.c" - "lwip/src/core/ip.c" - "lwip/src/core/mem.c" - "lwip/src/core/memp.c" - "lwip/src/core/netif.c" - "lwip/src/core/pbuf.c" - "lwip/src/core/raw.c" - "lwip/src/core/stats.c" - "lwip/src/core/sys.c" - "lwip/src/core/tcp.c" - "lwip/src/core/tcp_in.c" - "lwip/src/core/tcp_out.c" - "lwip/src/core/timeouts.c" - "lwip/src/core/udp.c" - "lwip/src/core/ipv4/autoip.c" - "lwip/src/core/ipv4/dhcp.c" - "lwip/src/core/ipv4/etharp.c" - "lwip/src/core/ipv4/icmp.c" - "lwip/src/core/ipv4/igmp.c" - "lwip/src/core/ipv4/ip4.c" - "lwip/src/core/ipv4/ip4_addr.c" - "lwip/src/core/ipv4/ip4_frag.c" - "lwip/src/core/ipv6/dhcp6.c" - "lwip/src/core/ipv6/ethip6.c" - "lwip/src/core/ipv6/icmp6.c" - "lwip/src/core/ipv6/inet6.c" - "lwip/src/core/ipv6/ip6.c" - "lwip/src/core/ipv6/ip6_addr.c" - "lwip/src/core/ipv6/ip6_frag.c" - "lwip/src/core/ipv6/mld6.c" - "lwip/src/core/ipv6/nd6.c" - "lwip/src/netif/ethernet.c" - "lwip/src/netif/ethernetif.c" - "lwip/src/netif/lowpan6.c" - "lwip/src/netif/slipif.c" - "lwip/src/netif/ppp/auth.c" - "lwip/src/netif/ppp/ccp.c" - "lwip/src/netif/ppp/chap-md5.c" - "lwip/src/netif/ppp/chap-new.c" - "lwip/src/netif/ppp/chap_ms.c" - "lwip/src/netif/ppp/demand.c" - "lwip/src/netif/ppp/eap.c" - "lwip/src/netif/ppp/ecp.c" - "lwip/src/netif/ppp/eui64.c" - "lwip/src/netif/ppp/fsm.c" - "lwip/src/netif/ppp/ipcp.c" - "lwip/src/netif/ppp/ipv6cp.c" - "lwip/src/netif/ppp/lcp.c" - "lwip/src/netif/ppp/magic.c" - "lwip/src/netif/ppp/mppe.c" - "lwip/src/netif/ppp/multilink.c" - "lwip/src/netif/ppp/ppp.c" - "lwip/src/netif/ppp/pppapi.c" - "lwip/src/netif/ppp/pppcrypt.c" - "lwip/src/netif/ppp/pppoe.c" - "lwip/src/netif/ppp/pppol2tp.c" - "lwip/src/netif/ppp/pppos.c" - "lwip/src/netif/ppp/upap.c" - "lwip/src/netif/ppp/utils.c" - "lwip/src/netif/ppp/vj.c" - "port/esp32/vfs_lwip.c" - "port/esp32/debug/lwip_debug.c" - "port/esp32/freertos/sys_arch.c" - "port/esp32/netif/dhcp_state.c" - "port/esp32/netif/ethernetif.c" - "port/esp32/netif/nettestif.c" - "port/esp32/netif/wlanif.c") +set(srcs "apps/dhcpserver/dhcpserver.c" + "apps/ping/esp_ping.c" + "apps/ping/ping.c" + "apps/sntp/sntp.c" + "lwip/src/api/api_lib.c" + "lwip/src/api/api_msg.c" + "lwip/src/api/err.c" + "lwip/src/api/netbuf.c" + "lwip/src/api/netdb.c" + "lwip/src/api/netifapi.c" + "lwip/src/api/sockets.c" + "lwip/src/api/tcpip.c" + "lwip/src/apps/sntp/sntp.c" + "lwip/src/core/def.c" + "lwip/src/core/dns.c" + "lwip/src/core/inet_chksum.c" + "lwip/src/core/init.c" + "lwip/src/core/ip.c" + "lwip/src/core/mem.c" + "lwip/src/core/memp.c" + "lwip/src/core/netif.c" + "lwip/src/core/pbuf.c" + "lwip/src/core/raw.c" + "lwip/src/core/stats.c" + "lwip/src/core/sys.c" + "lwip/src/core/tcp.c" + "lwip/src/core/tcp_in.c" + "lwip/src/core/tcp_out.c" + "lwip/src/core/timeouts.c" + "lwip/src/core/udp.c" + "lwip/src/core/ipv4/autoip.c" + "lwip/src/core/ipv4/dhcp.c" + "lwip/src/core/ipv4/etharp.c" + "lwip/src/core/ipv4/icmp.c" + "lwip/src/core/ipv4/igmp.c" + "lwip/src/core/ipv4/ip4.c" + "lwip/src/core/ipv4/ip4_addr.c" + "lwip/src/core/ipv4/ip4_frag.c" + "lwip/src/core/ipv6/dhcp6.c" + "lwip/src/core/ipv6/ethip6.c" + "lwip/src/core/ipv6/icmp6.c" + "lwip/src/core/ipv6/inet6.c" + "lwip/src/core/ipv6/ip6.c" + "lwip/src/core/ipv6/ip6_addr.c" + "lwip/src/core/ipv6/ip6_frag.c" + "lwip/src/core/ipv6/mld6.c" + "lwip/src/core/ipv6/nd6.c" + "lwip/src/netif/ethernet.c" + "lwip/src/netif/ethernetif.c" + "lwip/src/netif/lowpan6.c" + "lwip/src/netif/slipif.c" + "lwip/src/netif/ppp/auth.c" + "lwip/src/netif/ppp/ccp.c" + "lwip/src/netif/ppp/chap-md5.c" + "lwip/src/netif/ppp/chap-new.c" + "lwip/src/netif/ppp/chap_ms.c" + "lwip/src/netif/ppp/demand.c" + "lwip/src/netif/ppp/eap.c" + "lwip/src/netif/ppp/ecp.c" + "lwip/src/netif/ppp/eui64.c" + "lwip/src/netif/ppp/fsm.c" + "lwip/src/netif/ppp/ipcp.c" + "lwip/src/netif/ppp/ipv6cp.c" + "lwip/src/netif/ppp/lcp.c" + "lwip/src/netif/ppp/magic.c" + "lwip/src/netif/ppp/mppe.c" + "lwip/src/netif/ppp/multilink.c" + "lwip/src/netif/ppp/ppp.c" + "lwip/src/netif/ppp/pppapi.c" + "lwip/src/netif/ppp/pppcrypt.c" + "lwip/src/netif/ppp/pppoe.c" + "lwip/src/netif/ppp/pppol2tp.c" + "lwip/src/netif/ppp/pppos.c" + "lwip/src/netif/ppp/upap.c" + "lwip/src/netif/ppp/utils.c" + "lwip/src/netif/ppp/vj.c" + "port/esp32/vfs_lwip.c" + "port/esp32/debug/lwip_debug.c" + "port/esp32/freertos/sys_arch.c" + "port/esp32/netif/dhcp_state.c" + "port/esp32/netif/ethernetif.c" + "port/esp32/netif/nettestif.c" + "port/esp32/netif/wlanif.c") if(CONFIG_LWIP_PPP_SUPPORT) - list(APPEND COMPONENT_SRCS "lwip/src/netif/ppp/auth.c" + list(APPEND srcs "lwip/src/netif/ppp/auth.c" "lwip/src/netif/ppp/ccp.c" "lwip/src/netif/ppp/chap-md5.c" "lwip/src/netif/ppp/chap-new.c" @@ -123,12 +123,11 @@ if(CONFIG_LWIP_PPP_SUPPORT) "lwip/src/netif/ppp/polarssl/sha1.c") endif() -set(COMPONENT_REQUIRES vfs esp_wifi) -set(COMPONENT_PRIV_REQUIRES ethernet tcpip_adapter nvs_flash) - -set(COMPONENT_ADD_LDFRAGMENTS linker.lf) - -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + LDFRAGMENTS linker.lf + REQUIRES vfs esp_wifi + PRIV_REQUIRES ethernet tcpip_adapter nvs_flash) # lots of LWIP source files evaluate macros that check address of stack variables target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-address) diff --git a/components/mbedtls/CMakeLists.txt b/components/mbedtls/CMakeLists.txt index eaa420ef2e..91ef70234a 100644 --- a/components/mbedtls/CMakeLists.txt +++ b/components/mbedtls/CMakeLists.txt @@ -1,8 +1,6 @@ -set(COMPONENT_ADD_INCLUDEDIRS "port/include" "mbedtls/include") -set(COMPONENT_SRCS "mbedtls.c") -set(COMPONENT_REQUIRES lwip) - -register_component() +idf_component_register(SRCS "mbedtls.c" + INCLUDE_DIRS "port/include" "mbedtls/include" + REQUIRES lwip) # Only build mbedtls libraries set(ENABLE_TESTING CACHE BOOL OFF) diff --git a/components/mbedtls/test/CMakeLists.txt b/components/mbedtls/test/CMakeLists.txt index 5a8cfd8d33..8a083482a6 100644 --- a/components/mbedtls/test/CMakeLists.txt +++ b/components/mbedtls/test/CMakeLists.txt @@ -1,9 +1,6 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils mbedtls) - -register_component() +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils mbedtls) idf_component_get_property(mbedtls mbedtls COMPONENT_LIB) target_compile_definitions(${mbedtls} PUBLIC "-DMBEDTLS_DEPRECATED_WARNING") diff --git a/components/mdns/CMakeLists.txt b/components/mdns/CMakeLists.txt index 0933e30059..7b744dde56 100644 --- a/components/mdns/CMakeLists.txt +++ b/components/mdns/CMakeLists.txt @@ -1,9 +1,7 @@ -set(COMPONENT_SRCS "mdns.c" - "mdns_console.c" - "mdns_networking.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_PRIV_INCLUDEDIRS "private_include") -set(COMPONENT_REQUIRES lwip mbedtls console tcpip_adapter) - -register_component() +idf_component_register(SRCS "mdns.c" + "mdns_console.c" + "mdns_networking.c" + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "private_include" + REQUIRES lwip mbedtls console tcpip_adapter) diff --git a/components/mdns/test/CMakeLists.txt b/components/mdns/test/CMakeLists.txt index 7e694470f6..516ee0097b 100644 --- a/components/mdns/test/CMakeLists.txt +++ b/components/mdns/test/CMakeLists.txt @@ -1,3 +1,2 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_PRIV_REQUIRES unity test_utils mdns) -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + PRIV_REQUIRES unity test_utils mdns) \ No newline at end of file diff --git a/components/mqtt/CMakeLists.txt b/components/mqtt/CMakeLists.txt index 85f63cc9a8..1c30e3a913 100644 --- a/components/mqtt/CMakeLists.txt +++ b/components/mqtt/CMakeLists.txt @@ -1,10 +1,7 @@ -set(COMPONENT_ADD_INCLUDEDIRS esp-mqtt/include) -set(COMPONENT_PRIV_INCLUDEDIRS "esp-mqtt/lib/include") -set(COMPONENT_SRCS "esp-mqtt/mqtt_client.c" - "esp-mqtt/lib/mqtt_msg.c" - "esp-mqtt/lib/mqtt_outbox.c" - "esp-mqtt/lib/platform_esp32_idf.c") - -set(COMPONENT_REQUIRES lwip nghttp mbedtls tcp_transport) - -register_component() +idf_component_register(SRCS "esp-mqtt/mqtt_client.c" + "esp-mqtt/lib/mqtt_msg.c" + "esp-mqtt/lib/mqtt_outbox.c" + "esp-mqtt/lib/platform_esp32_idf.c" + INCLUDE_DIRS esp-mqtt/include + PRIV_INCLUDE_DIRS "esp-mqtt/lib/include" + REQUIRES lwip nghttp mbedtls tcp_transport) diff --git a/components/newlib/CMakeLists.txt b/components/newlib/CMakeLists.txt index 920842a73e..97a6d773b7 100644 --- a/components/newlib/CMakeLists.txt +++ b/components/newlib/CMakeLists.txt @@ -1,20 +1,20 @@ -set(COMPONENT_SRCS "heap.c" - "locks.c" - "poll.c" - "pthread.c" - "random.c" - "reent_init.c" - "select.c" - "syscall_table.c" - "syscalls.c" - "termios.c" - "time.c" - "utime.c") -set(COMPONENT_ADD_INCLUDEDIRS platform_include) +set(srcs "heap.c" + "locks.c" + "poll.c" + "pthread.c" + "random.c" + "reent_init.c" + "select.c" + "syscall_table.c" + "syscalls.c" + "termios.c" + "time.c" + "utime.c") +set(include_dirs platform_include) if(GCC_NOT_5_2_0) if(CONFIG_SPIRAM_CACHE_WORKAROUND) - set(COMPONENT_ADD_LDFRAGMENTS esp32-spiram-rom-functions-c.lf) + set(ldfragments esp32-spiram-rom-functions-c.lf) endif() # Forces the linker to include locks, heap, and syscalls from this component, @@ -27,20 +27,21 @@ else() # Remove this section when GCC 5.2.0 is no longer supported # 'include' and 'lib' directories should also be removed. # An if statement about LIB_PATH below should also be removed. - list(APPEND COMPONENT_ADD_INCLUDEDIRS include) + list(APPEND include_dirs include) set(LIB_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib) if(CONFIG_SPIRAM_CACHE_WORKAROUND) - set(COMPONENT_ADD_LDFRAGMENTS esp32-spiram-rom-functions-psram-workaround.lf) + set(ldfragments esp32-spiram-rom-functions-psram-workaround.lf) endif() endif() -set(COMPONENT_REQUIRES vfs) # for sys/ioctl.h -set(COMPONENT_PRIV_REQUIRES soc) +list(APPEND ldfragments newlib.lf) -list(APPEND COMPONENT_ADD_LDFRAGMENTS newlib.lf) - -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + REQUIRES vfs + PRIV_REQUIRES soc + LDFRAGMENTS "${ldfragments}") if(LIB_PATH) target_link_libraries(${COMPONENT_LIB} INTERFACE "-L ${LIB_PATH}") diff --git a/components/newlib/test/CMakeLists.txt b/components/newlib/test/CMakeLists.txt index 66a8c82315..b531a14504 100644 --- a/components/newlib/test/CMakeLists.txt +++ b/components/newlib/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils) \ No newline at end of file diff --git a/components/nghttp/CMakeLists.txt b/components/nghttp/CMakeLists.txt index c1c4d80942..32bd379eda 100644 --- a/components/nghttp/CMakeLists.txt +++ b/components/nghttp/CMakeLists.txt @@ -1,28 +1,28 @@ -set(COMPONENT_ADD_INCLUDEDIRS port/include nghttp2/lib/includes) -set(COMPONENT_SRCS "nghttp2/lib/nghttp2_buf.c" - "nghttp2/lib/nghttp2_callbacks.c" - "nghttp2/lib/nghttp2_debug.c" - "nghttp2/lib/nghttp2_frame.c" - "nghttp2/lib/nghttp2_hd.c" - "nghttp2/lib/nghttp2_hd_huffman.c" - "nghttp2/lib/nghttp2_hd_huffman_data.c" - "nghttp2/lib/nghttp2_helper.c" - "nghttp2/lib/nghttp2_http.c" - "nghttp2/lib/nghttp2_map.c" - "nghttp2/lib/nghttp2_mem.c" - "nghttp2/lib/nghttp2_npn.c" - "nghttp2/lib/nghttp2_option.c" - "nghttp2/lib/nghttp2_outbound_item.c" - "nghttp2/lib/nghttp2_pq.c" - "nghttp2/lib/nghttp2_priority_spec.c" - "nghttp2/lib/nghttp2_queue.c" - "nghttp2/lib/nghttp2_rcbuf.c" - "nghttp2/lib/nghttp2_session.c" - "nghttp2/lib/nghttp2_stream.c" - "nghttp2/lib/nghttp2_submit.c" - "nghttp2/lib/nghttp2_version.c" - "port/http_parser.c") +set(srcs "nghttp2/lib/nghttp2_buf.c" + "nghttp2/lib/nghttp2_callbacks.c" + "nghttp2/lib/nghttp2_debug.c" + "nghttp2/lib/nghttp2_frame.c" + "nghttp2/lib/nghttp2_hd.c" + "nghttp2/lib/nghttp2_hd_huffman.c" + "nghttp2/lib/nghttp2_hd_huffman_data.c" + "nghttp2/lib/nghttp2_helper.c" + "nghttp2/lib/nghttp2_http.c" + "nghttp2/lib/nghttp2_map.c" + "nghttp2/lib/nghttp2_mem.c" + "nghttp2/lib/nghttp2_npn.c" + "nghttp2/lib/nghttp2_option.c" + "nghttp2/lib/nghttp2_outbound_item.c" + "nghttp2/lib/nghttp2_pq.c" + "nghttp2/lib/nghttp2_priority_spec.c" + "nghttp2/lib/nghttp2_queue.c" + "nghttp2/lib/nghttp2_rcbuf.c" + "nghttp2/lib/nghttp2_session.c" + "nghttp2/lib/nghttp2_stream.c" + "nghttp2/lib/nghttp2_submit.c" + "nghttp2/lib/nghttp2_version.c" + "port/http_parser.c") -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS port/include nghttp2/lib/includes) target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DHAVE_CONFIG_H") diff --git a/components/nvs_flash/CMakeLists.txt b/components/nvs_flash/CMakeLists.txt index 2c815b31ca..1d7e5862dd 100644 --- a/components/nvs_flash/CMakeLists.txt +++ b/components/nvs_flash/CMakeLists.txt @@ -1,13 +1,10 @@ -set(COMPONENT_SRCS "src/nvs_api.cpp" - "src/nvs_encr.cpp" - "src/nvs_item_hash_list.cpp" - "src/nvs_ops.cpp" - "src/nvs_page.cpp" - "src/nvs_pagemanager.cpp" - "src/nvs_storage.cpp" - "src/nvs_types.cpp") -set(COMPONENT_ADD_INCLUDEDIRS include) - -set(COMPONENT_REQUIRES spi_flash mbedtls) - -register_component() +idf_component_register(SRCS "src/nvs_api.cpp" + "src/nvs_encr.cpp" + "src/nvs_item_hash_list.cpp" + "src/nvs_ops.cpp" + "src/nvs_page.cpp" + "src/nvs_pagemanager.cpp" + "src/nvs_storage.cpp" + "src/nvs_types.cpp" + REQUIRES spi_flash mbedtls + INCLUDE_DIRS include) diff --git a/components/nvs_flash/test/CMakeLists.txt b/components/nvs_flash/test/CMakeLists.txt index f473de05af..ede2a57bae 100644 --- a/components/nvs_flash/test/CMakeLists.txt +++ b/components/nvs_flash/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils nvs_flash bootloader_support) - -register_component() +idf_component_register(SRCS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils nvs_flash bootloader_support) \ No newline at end of file diff --git a/components/openssl/CMakeLists.txt b/components/openssl/CMakeLists.txt index 3a96598f01..bba4006f1a 100644 --- a/components/openssl/CMakeLists.txt +++ b/components/openssl/CMakeLists.txt @@ -1,14 +1,11 @@ -set(COMPONENT_ADD_INCLUDEDIRS include) -set(COMPONENT_PRIV_INCLUDEDIRS include/internal include/platform include/openssl) -set(COMPONENT_SRCS "library/ssl_cert.c" - "library/ssl_lib.c" - "library/ssl_methods.c" - "library/ssl_pkey.c" - "library/ssl_stack.c" - "library/ssl_x509.c" - "platform/ssl_pm.c" - "platform/ssl_port.c") - -set(COMPONENT_REQUIRES mbedtls) - -register_component() +idf_component_register(SRCS "library/ssl_cert.c" + "library/ssl_lib.c" + "library/ssl_methods.c" + "library/ssl_pkey.c" + "library/ssl_stack.c" + "library/ssl_x509.c" + "platform/ssl_pm.c" + "platform/ssl_port.c" + REQUIRES mbedtls + INCLUDE_DIRS include + PRIV_INCLUDE_DIRS include/internal include/platform include/openssl) diff --git a/components/partition_table/CMakeLists.txt b/components/partition_table/CMakeLists.txt index d94e3e162f..4fe76cc93e 100644 --- a/components/partition_table/CMakeLists.txt +++ b/components/partition_table/CMakeLists.txt @@ -1,4 +1,4 @@ -register_config_only_component() +idf_component_register() if(BOOTLOADER_BUILD) return() diff --git a/components/partition_table/test/CMakeLists.txt b/components/partition_table/test/CMakeLists.txt index 66a8c82315..b531a14504 100644 --- a/components/partition_table/test/CMakeLists.txt +++ b/components/partition_table/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils) \ No newline at end of file diff --git a/components/protobuf-c/CMakeLists.txt b/components/protobuf-c/CMakeLists.txt index 1c9a3ffc3f..1801093194 100644 --- a/components/protobuf-c/CMakeLists.txt +++ b/components/protobuf-c/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_ADD_INCLUDEDIRS protobuf-c) -set(COMPONENT_SRCS "protobuf-c/protobuf-c/protobuf-c.c") - -register_component() +idf_component_register(SRCS "protobuf-c/protobuf-c/protobuf-c.c" + INCLUDE_DIRS protobuf-c) diff --git a/components/protocomm/CMakeLists.txt b/components/protocomm/CMakeLists.txt index 9f9343815f..22bb08254c 100644 --- a/components/protocomm/CMakeLists.txt +++ b/components/protocomm/CMakeLists.txt @@ -1,25 +1,26 @@ -set(COMPONENT_ADD_INCLUDEDIRS include/common - include/security - include/transports) -set(COMPONENT_PRIV_INCLUDEDIRS proto-c src/common src/simple_ble) -set(COMPONENT_SRCS "src/common/protocomm.c" - "src/security/security0.c" - "src/security/security1.c" - "proto-c/constants.pb-c.c" - "proto-c/sec0.pb-c.c" - "proto-c/sec1.pb-c.c" - "proto-c/session.pb-c.c" - "src/transports/protocomm_console.c" - "src/transports/protocomm_httpd.c") - -set(COMPONENT_PRIV_REQUIRES protobuf-c mbedtls console esp_http_server bt) +set(include_dirs include/common + include/security + include/transports) +set(priv_include_dirs proto-c src/common src/simple_ble) +set(srcs "src/common/protocomm.c" + "src/security/security0.c" + "src/security/security1.c" + "proto-c/constants.pb-c.c" + "proto-c/sec0.pb-c.c" + "proto-c/sec1.pb-c.c" + "proto-c/session.pb-c.c" + "src/transports/protocomm_console.c" + "src/transports/protocomm_httpd.c") if(CONFIG_BT_ENABLED) if(CONFIG_BT_BLUEDROID_ENABLED) - list(APPEND COMPONENT_SRCS + list(APPEND srcs "src/simple_ble/simple_ble.c" "src/transports/protocomm_ble.c") endif() endif() -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + PRIV_INCLUDE_DIRS "${priv_include_dirs}" + PRIV_REQUIRES protobuf-c mbedtls console esp_http_server bt) diff --git a/components/protocomm/test/CMakeLists.txt b/components/protocomm/test/CMakeLists.txt index f25cb01a18..6e04b5332e 100644 --- a/components/protocomm/test/CMakeLists.txt +++ b/components/protocomm/test/CMakeLists.txt @@ -1,7 +1,4 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") -set(COMPONENT_PRIV_INCLUDEDIRS "../proto-c/") - -set(COMPONENT_REQUIRES unity mbedtls protocomm protobuf-c) - -register_component() +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + PRIV_INCLUDE_DIRS "../proto-c/" + REQUIRES unity mbedtls protocomm protobuf-c) \ No newline at end of file diff --git a/components/pthread/CMakeLists.txt b/components/pthread/CMakeLists.txt index 5c8bc04a04..d488c92a9d 100644 --- a/components/pthread/CMakeLists.txt +++ b/components/pthread/CMakeLists.txt @@ -1,8 +1,7 @@ -set(COMPONENT_SRCS "pthread.c" - "pthread_cond_var.c" - "pthread_local_storage.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") -register_component() +idf_component_register(SRCS "pthread.c" + "pthread_cond_var.c" + "pthread_local_storage.c" + INCLUDE_DIRS include) if(CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP) target_link_libraries(${COMPONENT_LIB} "-Wl,--wrap=vPortCleanUpTCB") diff --git a/components/pthread/test/CMakeLists.txt b/components/pthread/test/CMakeLists.txt index f57f843b1b..bb02dc7d41 100644 --- a/components/pthread/test/CMakeLists.txt +++ b/components/pthread/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils pthread) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils pthread) \ No newline at end of file diff --git a/components/sdmmc/CMakeLists.txt b/components/sdmmc/CMakeLists.txt index fdba0cf790..cb7de0e805 100644 --- a/components/sdmmc/CMakeLists.txt +++ b/components/sdmmc/CMakeLists.txt @@ -1,10 +1,9 @@ -set(COMPONENT_SRCS "sdmmc_cmd.c" - "sdmmc_common.c" - "sdmmc_init.c" - "sdmmc_io.c" - "sdmmc_mmc.c" - "sdmmc_sd.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_REQUIRES driver) -set(COMPONENT_PRIV_REQUIRES soc) -register_component() +idf_component_register(SRCS "sdmmc_cmd.c" + "sdmmc_common.c" + "sdmmc_init.c" + "sdmmc_io.c" + "sdmmc_mmc.c" + "sdmmc_sd.c" + INCLUDE_DIRS include + REQUIRES driver + PRIV_REQUIRES soc) \ No newline at end of file diff --git a/components/sdmmc/test/CMakeLists.txt b/components/sdmmc/test/CMakeLists.txt index 885cda77a6..c7c2d52a9b 100644 --- a/components/sdmmc/test/CMakeLists.txt +++ b/components/sdmmc/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity sdmmc) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity sdmmc) \ No newline at end of file diff --git a/components/smartconfig_ack/CMakeLists.txt b/components/smartconfig_ack/CMakeLists.txt index 1518776ce9..eb34b0713c 100644 --- a/components/smartconfig_ack/CMakeLists.txt +++ b/components/smartconfig_ack/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCS "smartconfig_ack.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") - -set(COMPONENT_PRIV_REQUIRES lwip tcpip_adapter) - -register_component() +idf_component_register(SRCS "smartconfig_ack.c" + INCLUDE_DIRS include + PRIV_REQUIRES lwip tcpip_adapter) \ No newline at end of file diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index 572fb38f68..0a2b29b00e 100644 --- a/components/soc/CMakeLists.txt +++ b/components/soc/CMakeLists.txt @@ -4,12 +4,12 @@ if(EXISTS "${COMPONENT_DIR}/${soc_name}") include(${COMPONENT_DIR}/${soc_name}/sources.cmake) spaces2list(SOC_SRCS) - add_prefix(COMPONENT_SRCS "${soc_name}/" ${SOC_SRCS}) - set(COMPONENT_ADD_INCLUDEDIRS ${soc_name}/include) + add_prefix(srcs "${soc_name}/" ${SOC_SRCS}) + set(include_dirs ${soc_name}/include) endif() -list(APPEND COMPONENT_ADD_INCLUDEDIRS include) -list(APPEND COMPONENT_SRCS "src/memory_layout_utils.c" +list(APPEND include_dirs include) +list(APPEND srcs "src/memory_layout_utils.c" "src/lldesc.c" "src/hal/spi_hal.c" "src/hal/spi_hal_iram.c" @@ -20,8 +20,6 @@ list(APPEND COMPONENT_SRCS "src/memory_layout_utils.c" "src/hal/spi_flash_hal_iram.c" ) -set(COMPONENT_ADD_LDFRAGMENTS linker.lf) - -set(COMPONENT_REQUIRES) - -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + LDFRAGMENTS linker.lf) diff --git a/components/soc/test/CMakeLists.txt b/components/soc/test/CMakeLists.txt index 276f56651a..619190b156 100644 --- a/components/soc/test/CMakeLists.txt +++ b/components/soc/test/CMakeLists.txt @@ -1,10 +1,11 @@ idf_build_get_property(soc_name IDF_TARGET) + get_filename_component(soc_test "${CMAKE_CURRENT_SOURCE_DIR}/../${soc_name}/test" ABSOLUTE) if(EXISTS "${soc_test}") - set(COMPONENT_SRCS "${soc_test}") - set(COMPONENT_ADD_INCLUDEDIRS "${soc_test}") + set(srcs "${soc_test}") + set(include_dirs "${soc_test}") endif() -set(COMPONENT_REQUIRES unity test_utils) - -register_component() +idf_component_register(SRC_DIRS "${src_dirs}" + INCLUDE_DIRS "${include_dirs}" + REQUIRES unity test_utils) diff --git a/components/spi_flash/CMakeLists.txt b/components/spi_flash/CMakeLists.txt index eb17b31eef..4a0dd4ecc4 100644 --- a/components/spi_flash/CMakeLists.txt +++ b/components/spi_flash/CMakeLists.txt @@ -1,10 +1,10 @@ +set(priv_requires bootloader_support soc) if(BOOTLOADER_BUILD) # Bootloader needs SPIUnlock from this file, but doesn't # need other parts of this component - set(COMPONENT_SRCS "spi_flash_rom_patch.c") - set(COMPONENT_PRIV_REQUIRES bootloader_support soc) + set(srcs "spi_flash_rom_patch.c") else() - set(COMPONENT_SRCS "cache_utils.c" + set(srcs "cache_utils.c" "flash_mmap.c" "flash_ops.c" "partition.c" @@ -17,13 +17,13 @@ else() "memspi_host_driver.c" ) if(NOT CONFIG_SPI_FLASH_USE_LEGACY_IMPL) - list(APPEND COMPONENT_SRCS "esp_flash_api.c") + list(APPEND srcs "esp_flash_api.c") endif() - set(COMPONENT_PRIV_REQUIRES bootloader_support app_update soc) + set(priv_requires bootloader_support app_update soc) endif() -set(COMPONENT_ADD_INCLUDEDIRS include) -set(COMPONENT_PRIV_INCLUDEDIRS private_include) -set(COMPONENT_ADD_LDFRAGMENTS linker.lf) - -register_component() +idf_component_register(SRCS "${srcs}" + PRIV_REQUIRES "${priv_requires}" + INCLUDE_DIRS include + PRIV_INCLUDE_DIRS private_include + LDFRAGMENTS linker.lf) diff --git a/components/spi_flash/test/CMakeLists.txt b/components/spi_flash/test/CMakeLists.txt index 559473b821..ae23154f2f 100644 --- a/components/spi_flash/test/CMakeLists.txt +++ b/components/spi_flash/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils spi_flash bootloader_support app_update) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils spi_flash bootloader_support app_update) \ No newline at end of file diff --git a/components/spiffs/CMakeLists.txt b/components/spiffs/CMakeLists.txt index 17e5a5587b..dfe4643c0f 100644 --- a/components/spiffs/CMakeLists.txt +++ b/components/spiffs/CMakeLists.txt @@ -1,15 +1,12 @@ -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_PRIV_INCLUDEDIRS "." "spiffs/src") -set(COMPONENT_SRCS "esp_spiffs.c" - "spiffs_api.c" - "spiffs/src/spiffs_cache.c" - "spiffs/src/spiffs_check.c" - "spiffs/src/spiffs_gc.c" - "spiffs/src/spiffs_hydrogen.c" - "spiffs/src/spiffs_nucleus.c") - -set(COMPONENT_REQUIRES spi_flash) -set(COMPONENT_PRIV_REQUIRES bootloader_support) - -register_component() +idf_component_register(SRCS "esp_spiffs.c" + "spiffs_api.c" + "spiffs/src/spiffs_cache.c" + "spiffs/src/spiffs_check.c" + "spiffs/src/spiffs_gc.c" + "spiffs/src/spiffs_hydrogen.c" + "spiffs/src/spiffs_nucleus.c" + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "." "spiffs/src" + REQUIRES spi_flash + PRIV_REQUIRES bootloader_support) diff --git a/components/spiffs/test/CMakeLists.txt b/components/spiffs/test/CMakeLists.txt index dc004f479b..20bfd7a7d4 100644 --- a/components/spiffs/test/CMakeLists.txt +++ b/components/spiffs/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils spiffs) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils spiffs) \ No newline at end of file diff --git a/components/tcp_transport/CMakeLists.txt b/components/tcp_transport/CMakeLists.txt index 9c2ef846b8..f1821db60f 100644 --- a/components/tcp_transport/CMakeLists.txt +++ b/components/tcp_transport/CMakeLists.txt @@ -1,12 +1,8 @@ -set(COMPONENT_SRCS "transport.c" - "transport_ssl.c" - "transport_tcp.c" - "transport_ws.c" - "transport_utils.c" - "transport_strcasestr.c") - -set(COMPONENT_ADD_INCLUDEDIRS "include") - -set(COMPONENT_REQUIRES lwip esp-tls) - -register_component() +idf_component_register(SRCS "transport.c" + "transport_ssl.c" + "transport_tcp.c" + "transport_ws.c" + "transport_utils.c" + "transport_strcasestr.c" + INCLUDE_DIRS include + REQUIRES lwip esp-tls) \ No newline at end of file diff --git a/components/tcpip_adapter/CMakeLists.txt b/components/tcpip_adapter/CMakeLists.txt index b728811ef2..8d35ca61df 100644 --- a/components/tcpip_adapter/CMakeLists.txt +++ b/components/tcpip_adapter/CMakeLists.txt @@ -1,7 +1,3 @@ -set(COMPONENT_SRCS "event_handlers.c" - "tcpip_adapter_lwip.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") - -set(COMPONENT_REQUIRES lwip) - -register_component() +idf_component_register(SRCS "event_handlers.c" "tcpip_adapter_lwip.c" + INCLUDE_DIRS include + REQUIRES lwip ethernet) diff --git a/components/ulp/CMakeLists.txt b/components/ulp/CMakeLists.txt index ca8d115c39..6d47331208 100644 --- a/components/ulp/CMakeLists.txt +++ b/components/ulp/CMakeLists.txt @@ -1,4 +1,3 @@ -set(COMPONENT_SRCS "ulp.c" - "ulp_macro.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") -register_component() +idf_component_register(SRCS "ulp.c" + "ulp_macro.c" + INCLUDE_DIRS include) \ No newline at end of file diff --git a/components/ulp/test/CMakeLists.txt b/components/ulp/test/CMakeLists.txt index 296fda0148..27311f9530 100644 --- a/components/ulp/test/CMakeLists.txt +++ b/components/ulp/test/CMakeLists.txt @@ -1,9 +1,6 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity ulp soc esp_common) - -register_component() +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity ulp soc esp_common) set(ulp_app_name ulp_test_app) set(ulp_s_sources "ulp/test_jumps.S") diff --git a/components/unity/CMakeLists.txt b/components/unity/CMakeLists.txt index 53494ae0f0..a82d037c0c 100644 --- a/components/unity/CMakeLists.txt +++ b/components/unity/CMakeLists.txt @@ -1,22 +1,20 @@ -set(COMPONENT_SRCS "unity/src/unity.c" - "unity_port_esp32.c") - -set(COMPONENT_ADD_INCLUDEDIRS "include" - "unity/src") +set(srcs "unity/src/unity.c" + "unity_port_esp32.c") if(CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL) list(APPEND COMPONENT_PRIV_INCLUDEDIRS "include/priv") endif() if(CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER) - list(APPEND COMPONENT_SRCS "unity_runner.c") + list(APPEND srcs "unity_runner.c") endif() if(CONFIG_UNITY_ENABLE_FIXTURE) - list(APPEND COMPONENT_SRCS "unity/extras/fixture/src/unity_fixture.c") + list(APPEND srcs "unity/extras/fixture/src/unity_fixture.c") endif() -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "include" "unity/src") target_compile_definitions(${COMPONENT_LIB} PUBLIC -DUNITY_INCLUDE_CONFIG_H diff --git a/components/vfs/CMakeLists.txt b/components/vfs/CMakeLists.txt index 0b2f640ca6..d62c9e0393 100644 --- a/components/vfs/CMakeLists.txt +++ b/components/vfs/CMakeLists.txt @@ -1,8 +1,7 @@ -set(COMPONENT_SRCS "vfs.c" - "vfs_uart.c" - "vfs_semihost.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") -register_component() +idf_component_register(SRCS "vfs.c" + "vfs_uart.c" + "vfs_semihost.c" + INCLUDE_DIRS include) # Some newlib syscalls are implemented in vfs.c, make sure these are always # seen by the linker diff --git a/components/vfs/test/CMakeLists.txt b/components/vfs/test/CMakeLists.txt index e67c253d0f..f0a24edd9f 100644 --- a/components/vfs/test/CMakeLists.txt +++ b/components/vfs/test/CMakeLists.txt @@ -1,8 +1,4 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils vfs fatfs spiffs) - -set(COMPONENT_ADD_LDFRAGMENTS linker.lf) - -register_component() +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils vfs fatfs spiffs + LDFRAGMENTS linker.lf) \ No newline at end of file diff --git a/components/wear_levelling/CMakeLists.txt b/components/wear_levelling/CMakeLists.txt index 59b81ccfaa..1a0d775975 100644 --- a/components/wear_levelling/CMakeLists.txt +++ b/components/wear_levelling/CMakeLists.txt @@ -1,11 +1,10 @@ -set(COMPONENT_SRCS "Partition.cpp" - "SPI_Flash.cpp" - "WL_Ext_Perf.cpp" - "WL_Ext_Safe.cpp" - "WL_Flash.cpp" - "crc32.cpp" - "wear_levelling.cpp") -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_PRIV_INCLUDEDIRS private_include) -set(COMPONENT_REQUIRES spi_flash) -register_component() +idf_component_register(SRCS "Partition.cpp" + "SPI_Flash.cpp" + "WL_Ext_Perf.cpp" + "WL_Ext_Safe.cpp" + "WL_Flash.cpp" + "crc32.cpp" + "wear_levelling.cpp" + INCLUDE_DIRS include + PRIV_INCLUDE_DIRS private_include + REQUIRES spi_flash) \ No newline at end of file diff --git a/components/wear_levelling/test/CMakeLists.txt b/components/wear_levelling/test/CMakeLists.txt index 133be91080..a81bf5a8e5 100644 --- a/components/wear_levelling/test/CMakeLists.txt +++ b/components/wear_levelling/test/CMakeLists.txt @@ -1,8 +1,4 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils wear_levelling) - -set(COMPONENT_EMBED_FILES test_partition_v1.bin) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils wear_levelling + EMBED_FILES test_partition_v1.bin) \ No newline at end of file diff --git a/components/wifi_provisioning/CMakeLists.txt b/components/wifi_provisioning/CMakeLists.txt index ec129bce3b..58ddab84f6 100644 --- a/components/wifi_provisioning/CMakeLists.txt +++ b/components/wifi_provisioning/CMakeLists.txt @@ -1,21 +1,20 @@ -set(COMPONENT_ADD_INCLUDEDIRS include) -set(COMPONENT_PRIV_INCLUDEDIRS src proto-c ../protocomm/proto-c) -set(COMPONENT_SRCS "src/wifi_config.c" - "src/manager.c" - "src/handlers.c" - "src/scheme_softap.c" - "src/scheme_console.c" - "proto-c/wifi_config.pb-c.c" - "proto-c/wifi_constants.pb-c.c") - -set(COMPONENT_REQUIRES lwip protocomm) -set(COMPONENT_PRIV_REQUIRES protobuf-c bt mdns json) +set(srcs "src/wifi_config.c" + "src/manager.c" + "src/handlers.c" + "src/scheme_softap.c" + "src/scheme_console.c" + "proto-c/wifi_config.pb-c.c" + "proto-c/wifi_constants.pb-c.c") if(CONFIG_BT_ENABLED) if(CONFIG_BT_BLUEDROID_ENABLED) - list(APPEND COMPONENT_SRCS + list(APPEND srcs "src/scheme_ble.c") endif() endif() -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS include + PRIV_INCLUDE_DIRS src proto-c ../protocomm/proto-c + REQUIRES lwip protocomm + PRIV_REQUIRES protobuf-c bt mdns json) diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index 35bf0bbdb3..78ce6573aa 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -1,83 +1,81 @@ -set(COMPONENT_SRCS "port/os_xtensa.c" - "src/crypto/aes-cbc.c" - "src/crypto/aes-internal-dec.c" - "src/crypto/aes-internal-enc.c" - "src/crypto/aes-internal.c" - "src/crypto/aes-unwrap.c" - "src/crypto/aes-wrap.c" - "src/crypto/bignum.c" - "src/crypto/crypto_mbedtls.c" - "src/crypto/crypto_internal-cipher.c" - "src/crypto/crypto_internal-modexp.c" - "src/crypto/crypto_internal-rsa.c" - "src/crypto/crypto_internal.c" - "src/crypto/des-internal.c" - "src/crypto/dh_group5.c" - "src/crypto/dh_groups.c" - "src/crypto/md4-internal.c" - "src/crypto/md5-internal.c" - "src/crypto/md5.c" - "src/crypto/ms_funcs.c" - "src/crypto/rc4.c" - "src/crypto/sha1-internal.c" - "src/crypto/sha1-pbkdf2.c" - "src/crypto/sha1.c" - "src/crypto/sha256-internal.c" - "src/crypto/sha256.c" - "src/fast_crypto/fast_aes-cbc.c" - "src/fast_crypto/fast_aes-unwrap.c" - "src/fast_crypto/fast_aes-wrap.c" - "src/fast_crypto/fast_crypto_internal-cipher.c" - "src/fast_crypto/fast_crypto_internal-modexp.c" - "src/fast_crypto/fast_crypto_internal.c" - "src/fast_crypto/fast_sha256-internal.c" - "src/fast_crypto/fast_sha256.c" - "src/wpa2/eap_peer/chap.c" - "src/wpa2/eap_peer/eap.c" - "src/wpa2/eap_peer/eap_common.c" - "src/wpa2/eap_peer/eap_mschapv2.c" - "src/wpa2/eap_peer/eap_peap.c" - "src/wpa2/eap_peer/eap_peap_common.c" - "src/wpa2/eap_peer/eap_tls.c" - "src/wpa2/eap_peer/eap_tls_common.c" - "src/wpa2/eap_peer/eap_ttls.c" - "src/wpa2/eap_peer/mschapv2.c" - "src/wpa2/tls/asn1.c" - "src/wpa2/tls/bignum.c" - "src/wpa2/tls/pkcs1.c" - "src/wpa2/tls/pkcs5.c" - "src/wpa2/tls/pkcs8.c" - "src/wpa2/tls/rsa.c" - "src/wpa2/tls/tls_internal.c" - "src/wpa2/tls/tlsv1_client.c" - "src/wpa2/tls/tlsv1_client_read.c" - "src/wpa2/tls/tlsv1_client_write.c" - "src/wpa2/tls/tlsv1_common.c" - "src/wpa2/tls/tlsv1_cred.c" - "src/wpa2/tls/tlsv1_record.c" - "src/wpa2/tls/tlsv1_server.c" - "src/wpa2/tls/tlsv1_server_read.c" - "src/wpa2/tls/tlsv1_server_write.c" - "src/wpa2/tls/x509v3.c" - "src/wpa2/utils/base64.c" - "src/wpa2/utils/ext_password.c" - "src/wps/eap_common.c" - "src/wps/uuid.c" - "src/wps/wps.c" - "src/wps/wps_attr_build.c" - "src/wps/wps_attr_parse.c" - "src/wps/wps_attr_process.c" - "src/wps/wps_common.c" - "src/wps/wps_dev_attr.c" - "src/wps/wps_enrollee.c" - "src/wps/wps_registrar.c" - "src/wps/wps_validate.c") -set(COMPONENT_ADD_INCLUDEDIRS include port/include) +set(srcs "port/os_xtensa.c" + "src/crypto/aes-cbc.c" + "src/crypto/aes-internal-dec.c" + "src/crypto/aes-internal-enc.c" + "src/crypto/aes-internal.c" + "src/crypto/aes-unwrap.c" + "src/crypto/aes-wrap.c" + "src/crypto/bignum.c" + "src/crypto/crypto_mbedtls.c" + "src/crypto/crypto_internal-cipher.c" + "src/crypto/crypto_internal-modexp.c" + "src/crypto/crypto_internal-rsa.c" + "src/crypto/crypto_internal.c" + "src/crypto/des-internal.c" + "src/crypto/dh_group5.c" + "src/crypto/dh_groups.c" + "src/crypto/md4-internal.c" + "src/crypto/md5-internal.c" + "src/crypto/md5.c" + "src/crypto/ms_funcs.c" + "src/crypto/rc4.c" + "src/crypto/sha1-internal.c" + "src/crypto/sha1-pbkdf2.c" + "src/crypto/sha1.c" + "src/crypto/sha256-internal.c" + "src/crypto/sha256.c" + "src/fast_crypto/fast_aes-cbc.c" + "src/fast_crypto/fast_aes-unwrap.c" + "src/fast_crypto/fast_aes-wrap.c" + "src/fast_crypto/fast_crypto_internal-cipher.c" + "src/fast_crypto/fast_crypto_internal-modexp.c" + "src/fast_crypto/fast_crypto_internal.c" + "src/fast_crypto/fast_sha256-internal.c" + "src/fast_crypto/fast_sha256.c" + "src/wpa2/eap_peer/chap.c" + "src/wpa2/eap_peer/eap.c" + "src/wpa2/eap_peer/eap_common.c" + "src/wpa2/eap_peer/eap_mschapv2.c" + "src/wpa2/eap_peer/eap_peap.c" + "src/wpa2/eap_peer/eap_peap_common.c" + "src/wpa2/eap_peer/eap_tls.c" + "src/wpa2/eap_peer/eap_tls_common.c" + "src/wpa2/eap_peer/eap_ttls.c" + "src/wpa2/eap_peer/mschapv2.c" + "src/wpa2/tls/asn1.c" + "src/wpa2/tls/bignum.c" + "src/wpa2/tls/pkcs1.c" + "src/wpa2/tls/pkcs5.c" + "src/wpa2/tls/pkcs8.c" + "src/wpa2/tls/rsa.c" + "src/wpa2/tls/tls_internal.c" + "src/wpa2/tls/tlsv1_client.c" + "src/wpa2/tls/tlsv1_client_read.c" + "src/wpa2/tls/tlsv1_client_write.c" + "src/wpa2/tls/tlsv1_common.c" + "src/wpa2/tls/tlsv1_cred.c" + "src/wpa2/tls/tlsv1_record.c" + "src/wpa2/tls/tlsv1_server.c" + "src/wpa2/tls/tlsv1_server_read.c" + "src/wpa2/tls/tlsv1_server_write.c" + "src/wpa2/tls/x509v3.c" + "src/wpa2/utils/base64.c" + "src/wpa2/utils/ext_password.c" + "src/wps/eap_common.c" + "src/wps/uuid.c" + "src/wps/wps.c" + "src/wps/wps_attr_build.c" + "src/wps/wps_attr_parse.c" + "src/wps/wps_attr_process.c" + "src/wps/wps_common.c" + "src/wps/wps_dev_attr.c" + "src/wps/wps_enrollee.c" + "src/wps/wps_registrar.c" + "src/wps/wps_validate.c") -set(COMPONENT_REQUIRES "") -set(COMPONENT_PRIV_REQUIRES mbedtls) - -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS include port/include + PRIV_REQUIRES mbedtls) target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-strict-aliasing) target_compile_definitions(${COMPONENT_LIB} PRIVATE diff --git a/components/wpa_supplicant/test/CMakeLists.txt b/components/wpa_supplicant/test/CMakeLists.txt index 28ca784c09..1be503f44f 100644 --- a/components/wpa_supplicant/test/CMakeLists.txt +++ b/components/wpa_supplicant/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity wpa_supplicant mbedtls) - -register_component() +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity wpa_supplicant mbedtls) \ No newline at end of file diff --git a/components/xtensa/CMakeLists.txt b/components/xtensa/CMakeLists.txt index 1bb997d673..08a1ccf64c 100644 --- a/components/xtensa/CMakeLists.txt +++ b/components/xtensa/CMakeLists.txt @@ -1,10 +1,7 @@ -set(COMPONENT_SRCS "eri.c" "trax.c" "debug_helpers.c" "debug_helpers_asm.S") +idf_build_get_property(target IDF_TARGET) +idf_component_register(SRCS "eri.c" "trax.c" "debug_helpers.c" "debug_helpers_asm.S" + INCLUDE_DIRS include ${target}/include + LDFRAGMENTS linker.lf + PRIV_REQUIRES soc) -set(COMPONENT_ADD_INCLUDEDIRS "include" "${IDF_TARGET}/include") - -set(COMPONENT_ADD_LDFRAGMENTS linker.lf) -set(COMPONENT_PRIV_REQUIRES soc) - -register_component() - -target_link_libraries(${COMPONENT_LIB} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/${IDF_TARGET}/libhal.a") +target_link_libraries(${COMPONENT_LIB} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/${target}/libhal.a") From 6771eead80534c51efb2033c04769ef5893b4838 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Sun, 28 Apr 2019 15:38:46 +0800 Subject: [PATCH 111/486] examples: use new component registration api --- components/esp_websocket_client/CMakeLists.txt | 7 +++---- components/esp_wifi/test/CMakeLists.txt | 2 +- .../a2dp_gatts_coex/main/CMakeLists.txt | 10 ++++------ .../bluetooth/a2dp_sink/main/CMakeLists.txt | 9 ++++----- .../bluetooth/a2dp_source/main/CMakeLists.txt | 8 +++----- examples/bluetooth/ble_adv/main/CMakeLists.txt | 6 ++---- .../ble_compatibility_test/main/CMakeLists.txt | 6 ++---- .../ble_eddystone/main/CMakeLists.txt | 8 +++----- .../ble_hid_device_demo/main/CMakeLists.txt | 12 +++++------- .../bluetooth/ble_ibeacon/main/CMakeLists.txt | 8 +++----- .../ble_spp_client/main/CMakeLists.txt | 6 ++---- .../ble_spp_server/main/CMakeLists.txt | 6 ++---- .../throughput_client/main/CMakeLists.txt | 6 ++---- .../throughput_server/main/CMakeLists.txt | 6 ++---- examples/bluetooth/blufi/main/CMakeLists.txt | 8 +++----- .../bluetooth/bt_discovery/main/CMakeLists.txt | 6 ++---- .../bt_spp_acceptor/main/CMakeLists.txt | 6 ++---- .../bt_spp_initiator/main/CMakeLists.txt | 6 ++---- .../bt_spp_vfs_acceptor/main/CMakeLists.txt | 8 +++----- .../bt_spp_vfs_initiator/main/CMakeLists.txt | 8 +++----- .../controller_hci_uart/main/CMakeLists.txt | 6 ++---- .../bluetooth/gatt_client/main/CMakeLists.txt | 6 ++---- .../gatt_security_client/main/CMakeLists.txt | 6 ++---- .../gatt_security_server/main/CMakeLists.txt | 6 ++---- .../bluetooth/gatt_server/main/CMakeLists.txt | 6 ++---- .../main/CMakeLists.txt | 6 ++---- .../gattc_multi_connect/main/CMakeLists.txt | 6 ++---- .../cmake/import_lib/main/CMakeLists.txt | 9 +++------ .../protocol_examples_common/CMakeLists.txt | 7 ++----- examples/ethernet/eth2ap/main/CMakeLists.txt | 8 ++------ examples/ethernet/ethernet/main/CMakeLists.txt | 6 ++---- examples/ethernet/iperf/main/CMakeLists.txt | 8 +++----- examples/get-started/blink/main/CMakeLists.txt | 6 ++---- .../hello_world/main/CMakeLists.txt | 6 ++---- .../internal_communication/main/CMakeLists.txt | 8 +++----- .../mesh/manual_networking/main/CMakeLists.txt | 8 +++----- examples/peripherals/adc/main/CMakeLists.txt | 6 ++---- examples/peripherals/adc2/main/CMakeLists.txt | 6 ++---- .../can_alert_and_recovery/main/CMakeLists.txt | 6 ++---- .../main/CMakeLists.txt | 6 ++---- .../can_network_master/main/CMakeLists.txt | 6 ++---- .../can_network_slave/main/CMakeLists.txt | 6 ++---- .../can/can_self_test/main/CMakeLists.txt | 6 ++---- examples/peripherals/gpio/main/CMakeLists.txt | 6 ++---- .../i2c/i2c_self_test/main/CMakeLists.txt | 6 ++---- .../i2c/i2c_tools/main/CMakeLists.txt | 8 +++----- examples/peripherals/i2s/main/CMakeLists.txt | 6 ++---- .../i2s_adc_dac/main/CMakeLists.txt | 6 ++---- examples/peripherals/ledc/main/CMakeLists.txt | 6 ++---- .../mcpwm_basic_config/main/CMakeLists.txt | 6 ++---- .../mcpwm_bldc_control/main/CMakeLists.txt | 6 ++---- .../main/CMakeLists.txt | 6 ++---- .../mcpwm_servo_control/main/CMakeLists.txt | 6 ++---- examples/peripherals/pcnt/main/CMakeLists.txt | 6 ++---- .../rmt_nec_tx_rx/main/CMakeLists.txt | 6 ++---- .../peripherals/rmt_tx/main/CMakeLists.txt | 6 ++---- .../host/components/esp_slave/CMakeLists.txt | 9 +++------ .../peripherals/sdio/host/main/CMakeLists.txt | 6 ++---- .../peripherals/sdio/slave/main/CMakeLists.txt | 6 ++---- .../peripherals/sigmadelta/main/CMakeLists.txt | 6 ++---- .../peripherals/spi_master/main/CMakeLists.txt | 14 +++++--------- .../spi_slave/receiver/main/CMakeLists.txt | 6 ++---- .../spi_slave/sender/main/CMakeLists.txt | 6 ++---- .../timer_group/main/CMakeLists.txt | 6 ++---- .../touch_pad_interrupt/main/CMakeLists.txt | 6 ++---- .../touch_pad_read/main/CMakeLists.txt | 6 ++---- .../uart/nmea0183_parser/main/CMakeLists.txt | 8 +++----- .../uart_async_rxtxtasks/main/CMakeLists.txt | 6 ++---- .../uart/uart_echo/main/CMakeLists.txt | 6 ++---- .../uart/uart_echo_rs485/main/CMakeLists.txt | 6 ++---- .../uart/uart_events/main/CMakeLists.txt | 6 ++---- .../uart/uart_select/main/CMakeLists.txt | 6 ++---- .../asio/chat_client/main/CMakeLists.txt | 6 ++---- .../asio/chat_server/main/CMakeLists.txt | 6 ++---- .../asio/tcp_echo_server/main/CMakeLists.txt | 6 ++---- .../asio/udp_echo_server/main/CMakeLists.txt | 6 ++---- .../protocols/coap_client/main/CMakeLists.txt | 6 ++---- .../protocols/coap_server/main/CMakeLists.txt | 6 ++---- .../esp_http_client/main/CMakeLists.txt | 10 +++------- .../components/sh2lib/CMakeLists.txt | 12 ++++-------- .../http2_request/main/CMakeLists.txt | 6 ++---- .../protocols/http_request/main/CMakeLists.txt | 6 ++---- .../advanced_tests/main/CMakeLists.txt | 8 +++----- .../file_serving/main/CMakeLists.txt | 9 +++------ .../persistent_sockets/main/CMakeLists.txt | 6 ++---- .../restful_server/main/CMakeLists.txt | 7 +++---- .../http_server/simple/main/CMakeLists.txt | 6 ++---- .../https_mbedtls/main/CMakeLists.txt | 10 +++------- .../https_request/main/CMakeLists.txt | 10 +++------- .../protocols/https_server/main/CMakeLists.txt | 12 ++++-------- examples/protocols/mdns/main/CMakeLists.txt | 6 ++---- .../modbus_master/main/CMakeLists.txt | 10 ++++------ .../protocols/modbus_slave/main/CMakeLists.txt | 8 +++----- .../mqtt/publish_test/main/CMakeLists.txt | 6 ++---- .../protocols/mqtt/ssl/main/CMakeLists.txt | 6 ++---- .../mqtt/ssl_mutual_auth/main/CMakeLists.txt | 6 ++---- .../protocols/mqtt/tcp/main/CMakeLists.txt | 6 ++---- examples/protocols/mqtt/ws/main/CMakeLists.txt | 6 ++---- .../protocols/mqtt/wss/main/CMakeLists.txt | 6 ++---- .../openssl_client/main/CMakeLists.txt | 6 ++---- .../openssl_server/main/CMakeLists.txt | 10 +++------- .../components/modem/CMakeLists.txt | 18 +++++++----------- .../protocols/pppos_client/main/CMakeLists.txt | 6 ++---- examples/protocols/sntp/main/CMakeLists.txt | 6 ++---- .../sockets/tcp_client/main/CMakeLists.txt | 6 ++---- .../sockets/tcp_server/main/CMakeLists.txt | 6 ++---- .../sockets/udp_client/main/CMakeLists.txt | 6 ++---- .../sockets/udp_multicast/main/CMakeLists.txt | 6 ++---- .../sockets/udp_server/main/CMakeLists.txt | 6 ++---- .../protocols/websocket/main/CMakeLists.txt | 6 ++---- .../provisioning/ble_prov/main/CMakeLists.txt | 10 ++++------ .../console_prov/main/CMakeLists.txt | 10 ++++------ .../custom_provisioning/CMakeLists.txt | 13 +++++-------- .../custom_config/main/CMakeLists.txt | 10 ++++------ .../provisioning/manager/main/CMakeLists.txt | 6 ++---- .../softap_prov/main/CMakeLists.txt | 10 ++++------ .../storage/nvs_rw_blob/main/CMakeLists.txt | 6 ++---- .../storage/nvs_rw_value/main/CMakeLists.txt | 6 ++---- .../partition_find/main/CMakeLists.txt | 9 +++------ .../partition_mmap/main/CMakeLists.txt | 6 ++---- .../partition_ops/main/CMakeLists.txt | 6 ++---- examples/storage/parttool/main/CMakeLists.txt | 6 ++---- examples/storage/sd_card/main/CMakeLists.txt | 6 ++---- .../storage/semihost_vfs/main/CMakeLists.txt | 5 +++-- examples/storage/spiffs/main/CMakeLists.txt | 6 ++---- examples/storage/spiffsgen/main/CMakeLists.txt | 6 ++---- .../storage/wear_levelling/main/CMakeLists.txt | 6 ++---- .../app_trace_to_host/main/CMakeLists.txt | 6 ++---- .../base_mac_address/main/CMakeLists.txt | 6 ++---- .../console/components/cmd_nvs/CMakeLists.txt | 10 +++------- .../components/cmd_system/CMakeLists.txt | 10 +++------- examples/system/console/main/CMakeLists.txt | 8 +++----- .../system/cpp_exceptions/main/CMakeLists.txt | 6 ++---- .../system/cpp_pthread/main/CMakeLists.txt | 6 ++---- examples/system/deep_sleep/main/CMakeLists.txt | 6 ++---- .../default_event_loop/main/CMakeLists.txt | 6 ++---- .../user_event_loops/main/CMakeLists.txt | 6 ++---- examples/system/esp_timer/main/CMakeLists.txt | 6 ++---- .../real_time_stats/main/CMakeLists.txt | 6 ++---- examples/system/gcov/main/CMakeLists.txt | 8 +++----- examples/system/himem/main/CMakeLists.txt | 6 ++---- .../system/light_sleep/main/CMakeLists.txt | 6 ++---- .../system/network_tests/main/CMakeLists.txt | 6 ++---- .../ota/advanced_https_ota/main/CMakeLists.txt | 13 ++++--------- .../ota/native_ota_example/main/CMakeLists.txt | 9 +++------ .../system/ota/otatool/main/CMakeLists.txt | 6 ++---- .../ota/simple_ota_example/main/CMakeLists.txt | 10 +++------- examples/system/select/main/CMakeLists.txt | 6 ++---- .../system/sysview_tracing/main/CMakeLists.txt | 6 ++---- .../main/CMakeLists.txt | 6 ++---- .../system/task_watchdog/main/CMakeLists.txt | 6 ++---- examples/system/ulp/main/CMakeLists.txt | 10 +++------- examples/system/ulp_adc/main/CMakeLists.txt | 12 ++++-------- .../components/testable/CMakeLists.txt | 6 ++---- .../components/testable/test/CMakeLists.txt | 9 +++------ examples/system/unit_test/main/CMakeLists.txt | 6 ++---- .../system/unit_test/test/main/CMakeLists.txt | 6 ++---- examples/wifi/espnow/main/CMakeLists.txt | 6 ++---- .../getting_started/softAP/main/CMakeLists.txt | 6 ++---- .../station/main/CMakeLists.txt | 6 ++---- .../wifi/iperf/components/iperf/CMakeLists.txt | 10 +++------- examples/wifi/iperf/main/CMakeLists.txt | 8 +++----- examples/wifi/power_save/main/CMakeLists.txt | 6 ++---- examples/wifi/scan/main/CMakeLists.txt | 6 ++---- .../components/pcap/CMakeLists.txt | 7 ++----- .../wifi/simple_sniffer/main/CMakeLists.txt | 13 +++---------- examples/wifi/smart_config/main/CMakeLists.txt | 6 ++---- .../wifi/wpa2_enterprise/main/CMakeLists.txt | 10 +++------- examples/wifi/wps/main/CMakeLists.txt | 6 ++---- 169 files changed, 409 insertions(+), 788 deletions(-) diff --git a/components/esp_websocket_client/CMakeLists.txt b/components/esp_websocket_client/CMakeLists.txt index 723199ce0f..f366a278d3 100644 --- a/components/esp_websocket_client/CMakeLists.txt +++ b/components/esp_websocket_client/CMakeLists.txt @@ -1,4 +1,3 @@ -set(COMPONENT_SRCS "esp_websocket_client.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_REQUIRES lwip esp-tls tcp_transport nghttp) -register_component() +idf_component_register(SRCS "esp_websocket_client.c" + INCLUDE_DIRS "include" + REQUIRES lwip esp-tls tcp_transport nghttp) diff --git a/components/esp_wifi/test/CMakeLists.txt b/components/esp_wifi/test/CMakeLists.txt index a3ff3757c3..cf98dd8137 100644 --- a/components/esp_wifi/test/CMakeLists.txt +++ b/components/esp_wifi/test/CMakeLists.txt @@ -1,4 +1,4 @@ -idf_component_register(SRCDIRS "." +idf_component_register(SRC_DIRS "." INCLUDE_DIRS "." "${CMAKE_CURRENT_BINARY_DIR}" REQUIRES unity test_utils nvs_flash ulp esp_common) diff --git a/examples/bluetooth/a2dp_gatts_coex/main/CMakeLists.txt b/examples/bluetooth/a2dp_gatts_coex/main/CMakeLists.txt index a55538b5fb..55f2d445aa 100644 --- a/examples/bluetooth/a2dp_gatts_coex/main/CMakeLists.txt +++ b/examples/bluetooth/a2dp_gatts_coex/main/CMakeLists.txt @@ -1,6 +1,4 @@ -set(COMPONENT_SRCS "bt_app_av.c" - "bt_app_core.c" - "main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "bt_app_av.c" + "bt_app_core.c" + "main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/a2dp_sink/main/CMakeLists.txt b/examples/bluetooth/a2dp_sink/main/CMakeLists.txt index a55538b5fb..d1d916efbd 100644 --- a/examples/bluetooth/a2dp_sink/main/CMakeLists.txt +++ b/examples/bluetooth/a2dp_sink/main/CMakeLists.txt @@ -1,6 +1,5 @@ -set(COMPONENT_SRCS "bt_app_av.c" - "bt_app_core.c" - "main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") +idf_component_register(SRCS "bt_app_av.c" + "bt_app_core.c" + "main.c" + INCLUDE_DIRS ".") -register_component() diff --git a/examples/bluetooth/a2dp_source/main/CMakeLists.txt b/examples/bluetooth/a2dp_source/main/CMakeLists.txt index 98b05a101b..d0a3885ddb 100644 --- a/examples/bluetooth/a2dp_source/main/CMakeLists.txt +++ b/examples/bluetooth/a2dp_source/main/CMakeLists.txt @@ -1,5 +1,3 @@ -set(COMPONENT_SRCS "bt_app_core.c" - "main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "bt_app_core.c" + "main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/ble_adv/main/CMakeLists.txt b/examples/bluetooth/ble_adv/main/CMakeLists.txt index d005e60123..494d32308b 100644 --- a/examples/bluetooth/ble_adv/main/CMakeLists.txt +++ b/examples/bluetooth/ble_adv/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "app_bt.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "app_bt.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/ble_compatibility_test/main/CMakeLists.txt b/examples/bluetooth/ble_compatibility_test/main/CMakeLists.txt index 3435b4c563..99553fec31 100644 --- a/examples/bluetooth/ble_compatibility_test/main/CMakeLists.txt +++ b/examples/bluetooth/ble_compatibility_test/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "ble_compatibility_test.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "ble_compatibility_test.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/ble_eddystone/main/CMakeLists.txt b/examples/bluetooth/ble_eddystone/main/CMakeLists.txt index 66a4e1aa6c..cdd852c570 100644 --- a/examples/bluetooth/ble_eddystone/main/CMakeLists.txt +++ b/examples/bluetooth/ble_eddystone/main/CMakeLists.txt @@ -1,5 +1,3 @@ -set(COMPONENT_SRCS "esp_eddystone_api.c" - "esp_eddystone_demo.c") -set(COMPONENT_ADD_INCLUDEDIRS "") - -register_component() +idf_component_register(SRCS "esp_eddystone_api.c" + "esp_eddystone_demo.c" + INCLUDE_DIRS "") \ No newline at end of file diff --git a/examples/bluetooth/ble_hid_device_demo/main/CMakeLists.txt b/examples/bluetooth/ble_hid_device_demo/main/CMakeLists.txt index 6445d3c5ef..efba49f6b7 100644 --- a/examples/bluetooth/ble_hid_device_demo/main/CMakeLists.txt +++ b/examples/bluetooth/ble_hid_device_demo/main/CMakeLists.txt @@ -1,10 +1,8 @@ -set(COMPONENT_SRCS "ble_hidd_demo_main.c" - "esp_hidd_prf_api.c" - "hid_dev.c" - "hid_device_le_prf.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "ble_hidd_demo_main.c" + "esp_hidd_prf_api.c" + "hid_dev.c" + "hid_device_le_prf.c" + INCLUDE_DIRS ".") if(GCC_NOT_5_2_0) target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-const-variable) diff --git a/examples/bluetooth/ble_ibeacon/main/CMakeLists.txt b/examples/bluetooth/ble_ibeacon/main/CMakeLists.txt index 1ae1a02e64..50293e2a7b 100644 --- a/examples/bluetooth/ble_ibeacon/main/CMakeLists.txt +++ b/examples/bluetooth/ble_ibeacon/main/CMakeLists.txt @@ -1,5 +1,3 @@ -set(COMPONENT_SRCS "esp_ibeacon_api.c" - "ibeacon_demo.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "esp_ibeacon_api.c" + "ibeacon_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/ble_spp_client/main/CMakeLists.txt b/examples/bluetooth/ble_spp_client/main/CMakeLists.txt index de584f3977..1b83a293fa 100644 --- a/examples/bluetooth/ble_spp_client/main/CMakeLists.txt +++ b/examples/bluetooth/ble_spp_client/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "spp_client_demo.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "spp_client_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/ble_spp_server/main/CMakeLists.txt b/examples/bluetooth/ble_spp_server/main/CMakeLists.txt index 99f35ee072..be4f67ba8d 100644 --- a/examples/bluetooth/ble_spp_server/main/CMakeLists.txt +++ b/examples/bluetooth/ble_spp_server/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "ble_spp_server_demo.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "ble_spp_server_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/ble_throughput/throughput_client/main/CMakeLists.txt b/examples/bluetooth/ble_throughput/throughput_client/main/CMakeLists.txt index 1fe275526d..e4c37ee280 100644 --- a/examples/bluetooth/ble_throughput/throughput_client/main/CMakeLists.txt +++ b/examples/bluetooth/ble_throughput/throughput_client/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "example_ble_client_throughput.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "example_ble_client_throughput.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/ble_throughput/throughput_server/main/CMakeLists.txt b/examples/bluetooth/ble_throughput/throughput_server/main/CMakeLists.txt index 3c1f62ac89..c54e45c928 100644 --- a/examples/bluetooth/ble_throughput/throughput_server/main/CMakeLists.txt +++ b/examples/bluetooth/ble_throughput/throughput_server/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "example_ble_server_throughput.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "example_ble_server_throughput.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/blufi/main/CMakeLists.txt b/examples/bluetooth/blufi/main/CMakeLists.txt index cbb9b24c36..8e40bfbf2f 100644 --- a/examples/bluetooth/blufi/main/CMakeLists.txt +++ b/examples/bluetooth/blufi/main/CMakeLists.txt @@ -1,5 +1,3 @@ -set(COMPONENT_SRCS "blufi_example_main.c" - "blufi_security.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "blufi_example_main.c" + "blufi_security.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/bt_discovery/main/CMakeLists.txt b/examples/bluetooth/bt_discovery/main/CMakeLists.txt index 68ddbfb4c8..4bc23a96f4 100644 --- a/examples/bluetooth/bt_discovery/main/CMakeLists.txt +++ b/examples/bluetooth/bt_discovery/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "bt_discovery.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "bt_discovery.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/bt_spp_acceptor/main/CMakeLists.txt b/examples/bluetooth/bt_spp_acceptor/main/CMakeLists.txt index 0694503f92..a71f85ba7c 100644 --- a/examples/bluetooth/bt_spp_acceptor/main/CMakeLists.txt +++ b/examples/bluetooth/bt_spp_acceptor/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "example_spp_acceptor_demo.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "example_spp_acceptor_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/bt_spp_initiator/main/CMakeLists.txt b/examples/bluetooth/bt_spp_initiator/main/CMakeLists.txt index 1eae1b74c9..09a976ad1c 100644 --- a/examples/bluetooth/bt_spp_initiator/main/CMakeLists.txt +++ b/examples/bluetooth/bt_spp_initiator/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "example_spp_initiator_demo.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "example_spp_initiator_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/main/CMakeLists.txt b/examples/bluetooth/bt_spp_vfs_acceptor/main/CMakeLists.txt index b224db80b6..369e404a15 100644 --- a/examples/bluetooth/bt_spp_vfs_acceptor/main/CMakeLists.txt +++ b/examples/bluetooth/bt_spp_vfs_acceptor/main/CMakeLists.txt @@ -1,5 +1,3 @@ -set(COMPONENT_SRCS "example_spp_vfs_acceptor_demo.c" - "spp_task.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "example_spp_vfs_acceptor_demo.c" + "spp_task.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/bt_spp_vfs_initiator/main/CMakeLists.txt b/examples/bluetooth/bt_spp_vfs_initiator/main/CMakeLists.txt index f3b9111353..03781e4786 100644 --- a/examples/bluetooth/bt_spp_vfs_initiator/main/CMakeLists.txt +++ b/examples/bluetooth/bt_spp_vfs_initiator/main/CMakeLists.txt @@ -1,5 +1,3 @@ -set(COMPONENT_SRCS "example_spp_vfs_initiator_demo.c" - "spp_task.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "example_spp_vfs_initiator_demo.c" + "spp_task.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/controller_hci_uart/main/CMakeLists.txt b/examples/bluetooth/controller_hci_uart/main/CMakeLists.txt index 2f40a64c69..b4eacc768a 100644 --- a/examples/bluetooth/controller_hci_uart/main/CMakeLists.txt +++ b/examples/bluetooth/controller_hci_uart/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "controller_hci_uart_demo.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "controller_hci_uart_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/gatt_client/main/CMakeLists.txt b/examples/bluetooth/gatt_client/main/CMakeLists.txt index 7c79edceaa..82a30b2f71 100644 --- a/examples/bluetooth/gatt_client/main/CMakeLists.txt +++ b/examples/bluetooth/gatt_client/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "gattc_demo.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "gattc_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/gatt_security_client/main/CMakeLists.txt b/examples/bluetooth/gatt_security_client/main/CMakeLists.txt index 32cea7e2e3..691e1edd29 100644 --- a/examples/bluetooth/gatt_security_client/main/CMakeLists.txt +++ b/examples/bluetooth/gatt_security_client/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "example_ble_sec_gattc_demo.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "example_ble_sec_gattc_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/gatt_security_server/main/CMakeLists.txt b/examples/bluetooth/gatt_security_server/main/CMakeLists.txt index 87df03c692..6514591112 100644 --- a/examples/bluetooth/gatt_security_server/main/CMakeLists.txt +++ b/examples/bluetooth/gatt_security_server/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "example_ble_sec_gatts_demo.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "example_ble_sec_gatts_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/gatt_server/main/CMakeLists.txt b/examples/bluetooth/gatt_server/main/CMakeLists.txt index d23e5ffc7d..e950c9ecd0 100644 --- a/examples/bluetooth/gatt_server/main/CMakeLists.txt +++ b/examples/bluetooth/gatt_server/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "gatts_demo.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "gatts_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/gatt_server_service_table/main/CMakeLists.txt b/examples/bluetooth/gatt_server_service_table/main/CMakeLists.txt index 7588b5a7a1..fbe553576b 100644 --- a/examples/bluetooth/gatt_server_service_table/main/CMakeLists.txt +++ b/examples/bluetooth/gatt_server_service_table/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "gatts_table_creat_demo.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "gatts_table_creat_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/gattc_multi_connect/main/CMakeLists.txt b/examples/bluetooth/gattc_multi_connect/main/CMakeLists.txt index 19dcf60d3a..826febe746 100644 --- a/examples/bluetooth/gattc_multi_connect/main/CMakeLists.txt +++ b/examples/bluetooth/gattc_multi_connect/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "gattc_multi_connect.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "gattc_multi_connect.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/build_system/cmake/import_lib/main/CMakeLists.txt b/examples/build_system/cmake/import_lib/main/CMakeLists.txt index fb136b8b97..6c60c8f980 100644 --- a/examples/build_system/cmake/import_lib/main/CMakeLists.txt +++ b/examples/build_system/cmake/import_lib/main/CMakeLists.txt @@ -1,9 +1,6 @@ -set(COMPONENT_SRCS "main.cpp") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_EMBED_TXTFILES "sample.xml") - -register_component() +idf_component_register(SRCS "main.cpp" + INCLUDE_DIRS "." + EMBED_TXTFILES "sample.xml") # Build static library, do not build test executables option(BUILD_SHARED_LIBS OFF) diff --git a/examples/common_components/protocol_examples_common/CMakeLists.txt b/examples/common_components/protocol_examples_common/CMakeLists.txt index 784909da03..0ccb219b4a 100644 --- a/examples/common_components/protocol_examples_common/CMakeLists.txt +++ b/examples/common_components/protocol_examples_common/CMakeLists.txt @@ -1,5 +1,2 @@ -set(COMPONENT_SRCS "connect.c" - "stdin_out.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") - -register_component() +idf_component_register(SRCS "connect.c" "stdin_out.c" + INCLUDE_DIRS "include") diff --git a/examples/ethernet/eth2ap/main/CMakeLists.txt b/examples/ethernet/eth2ap/main/CMakeLists.txt index aaf55bea54..5dbbb14c2d 100644 --- a/examples/ethernet/eth2ap/main/CMakeLists.txt +++ b/examples/ethernet/eth2ap/main/CMakeLists.txt @@ -1,6 +1,2 @@ - -set(COMPONENT_SRCS "eth2ap_example_main.c") - -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "eth2ap_example_main.c" + INCLUDE_DIRS ".") diff --git a/examples/ethernet/ethernet/main/CMakeLists.txt b/examples/ethernet/ethernet/main/CMakeLists.txt index 8c0c9fa0fc..8bc01f1bb4 100644 --- a/examples/ethernet/ethernet/main/CMakeLists.txt +++ b/examples/ethernet/ethernet/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "ethernet_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "ethernet_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/ethernet/iperf/main/CMakeLists.txt b/examples/ethernet/iperf/main/CMakeLists.txt index 16ecc3272c..aa66030901 100644 --- a/examples/ethernet/iperf/main/CMakeLists.txt +++ b/examples/ethernet/iperf/main/CMakeLists.txt @@ -1,5 +1,3 @@ -set(COMPONENT_SRCS "cmd_ethernet.c" - "iperf_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "cmd_ethernet.c" + "iperf_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/get-started/blink/main/CMakeLists.txt b/examples/get-started/blink/main/CMakeLists.txt index 69f12a3847..413c3b5141 100644 --- a/examples/get-started/blink/main/CMakeLists.txt +++ b/examples/get-started/blink/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "blink.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "blink.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/get-started/hello_world/main/CMakeLists.txt b/examples/get-started/hello_world/main/CMakeLists.txt index b79b831950..c299e03782 100644 --- a/examples/get-started/hello_world/main/CMakeLists.txt +++ b/examples/get-started/hello_world/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "hello_world_main.c") -set(COMPONENT_ADD_INCLUDEDIRS "") - -register_component() \ No newline at end of file +idf_component_register(SRCS "hello_world_main.c" + INCLUDE_DIRS "") \ No newline at end of file diff --git a/examples/mesh/internal_communication/main/CMakeLists.txt b/examples/mesh/internal_communication/main/CMakeLists.txt index 451eeceed6..686ab05acf 100644 --- a/examples/mesh/internal_communication/main/CMakeLists.txt +++ b/examples/mesh/internal_communication/main/CMakeLists.txt @@ -1,5 +1,3 @@ -set(COMPONENT_SRCS "mesh_light.c" - "mesh_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ". include") - -register_component() +idf_component_register(SRCS "mesh_light.c" + "mesh_main.c" + INCLUDE_DIRS "." "include") diff --git a/examples/mesh/manual_networking/main/CMakeLists.txt b/examples/mesh/manual_networking/main/CMakeLists.txt index 1ae57b28ac..686ab05acf 100644 --- a/examples/mesh/manual_networking/main/CMakeLists.txt +++ b/examples/mesh/manual_networking/main/CMakeLists.txt @@ -1,5 +1,3 @@ -set(COMPONENT_SRCS "mesh_light.c" - "mesh_main.c") -set(COMPONENT_ADD_INCLUDEDIRS "." "include") - -register_component() +idf_component_register(SRCS "mesh_light.c" + "mesh_main.c" + INCLUDE_DIRS "." "include") diff --git a/examples/peripherals/adc/main/CMakeLists.txt b/examples/peripherals/adc/main/CMakeLists.txt index 9b5d48fc60..035e5bd270 100644 --- a/examples/peripherals/adc/main/CMakeLists.txt +++ b/examples/peripherals/adc/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "adc1_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "adc1_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/adc2/main/CMakeLists.txt b/examples/peripherals/adc2/main/CMakeLists.txt index 1d7776ecf0..5a6c87d577 100644 --- a/examples/peripherals/adc2/main/CMakeLists.txt +++ b/examples/peripherals/adc2/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "adc2_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "adc2_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/can/can_alert_and_recovery/main/CMakeLists.txt b/examples/peripherals/can/can_alert_and_recovery/main/CMakeLists.txt index cf9bf40a99..ab23bf60fb 100644 --- a/examples/peripherals/can/can_alert_and_recovery/main/CMakeLists.txt +++ b/examples/peripherals/can/can_alert_and_recovery/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "can_alert_and_recovery_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "can_alert_and_recovery_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/can/can_network/can_network_listen_only/main/CMakeLists.txt b/examples/peripherals/can/can_network/can_network_listen_only/main/CMakeLists.txt index 5eab299b00..191642e1d1 100644 --- a/examples/peripherals/can/can_network/can_network_listen_only/main/CMakeLists.txt +++ b/examples/peripherals/can/can_network/can_network_listen_only/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "can_network_example_listen_only_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "can_network_example_listen_only_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/can/can_network/can_network_master/main/CMakeLists.txt b/examples/peripherals/can/can_network/can_network_master/main/CMakeLists.txt index f0dc1d6a79..31a67ddcb9 100644 --- a/examples/peripherals/can/can_network/can_network_master/main/CMakeLists.txt +++ b/examples/peripherals/can/can_network/can_network_master/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "can_network_example_master_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "can_network_example_master_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/can/can_network/can_network_slave/main/CMakeLists.txt b/examples/peripherals/can/can_network/can_network_slave/main/CMakeLists.txt index 4a002fbfc3..5ade11d5b5 100644 --- a/examples/peripherals/can/can_network/can_network_slave/main/CMakeLists.txt +++ b/examples/peripherals/can/can_network/can_network_slave/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "can_network_example_slave_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "can_network_example_slave_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/can/can_self_test/main/CMakeLists.txt b/examples/peripherals/can/can_self_test/main/CMakeLists.txt index 21db765a8f..5c3f85e0a5 100644 --- a/examples/peripherals/can/can_self_test/main/CMakeLists.txt +++ b/examples/peripherals/can/can_self_test/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "can_self_test_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "can_self_test_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/gpio/main/CMakeLists.txt b/examples/peripherals/gpio/main/CMakeLists.txt index d768cb8252..d33d5e1716 100644 --- a/examples/peripherals/gpio/main/CMakeLists.txt +++ b/examples/peripherals/gpio/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "gpio_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "gpio_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/i2c/i2c_self_test/main/CMakeLists.txt b/examples/peripherals/i2c/i2c_self_test/main/CMakeLists.txt index 02386f7197..4dc828aacc 100644 --- a/examples/peripherals/i2c/i2c_self_test/main/CMakeLists.txt +++ b/examples/peripherals/i2c/i2c_self_test/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "i2c_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "i2c_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/i2c/i2c_tools/main/CMakeLists.txt b/examples/peripherals/i2c/i2c_tools/main/CMakeLists.txt index 50cdc09826..fed3a94434 100644 --- a/examples/peripherals/i2c/i2c_tools/main/CMakeLists.txt +++ b/examples/peripherals/i2c/i2c_tools/main/CMakeLists.txt @@ -1,5 +1,3 @@ -set(COMPONENT_SRCS "i2ctools_example_main.c" - "cmd_i2ctools.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "i2ctools_example_main.c" + "cmd_i2ctools.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/i2s/main/CMakeLists.txt b/examples/peripherals/i2s/main/CMakeLists.txt index dbb7b172a3..5233689fb2 100644 --- a/examples/peripherals/i2s/main/CMakeLists.txt +++ b/examples/peripherals/i2s/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "i2s_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "i2s_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/i2s_adc_dac/main/CMakeLists.txt b/examples/peripherals/i2s_adc_dac/main/CMakeLists.txt index 6b03500639..e7392559ee 100644 --- a/examples/peripherals/i2s_adc_dac/main/CMakeLists.txt +++ b/examples/peripherals/i2s_adc_dac/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "app_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "app_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/ledc/main/CMakeLists.txt b/examples/peripherals/ledc/main/CMakeLists.txt index 6405eb95ff..f6064011cc 100644 --- a/examples/peripherals/ledc/main/CMakeLists.txt +++ b/examples/peripherals/ledc/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "ledc_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "ledc_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/mcpwm/mcpwm_basic_config/main/CMakeLists.txt b/examples/peripherals/mcpwm/mcpwm_basic_config/main/CMakeLists.txt index d5fdbf5600..ec236fe844 100644 --- a/examples/peripherals/mcpwm/mcpwm_basic_config/main/CMakeLists.txt +++ b/examples/peripherals/mcpwm/mcpwm_basic_config/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "mcpwm_basic_config_example.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "mcpwm_basic_config_example.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/mcpwm/mcpwm_bldc_control/main/CMakeLists.txt b/examples/peripherals/mcpwm/mcpwm_bldc_control/main/CMakeLists.txt index a52ad94513..3f7cedf8d2 100644 --- a/examples/peripherals/mcpwm/mcpwm_bldc_control/main/CMakeLists.txt +++ b/examples/peripherals/mcpwm/mcpwm_bldc_control/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "mcpwm_bldc_control_hall_sensor_example.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "mcpwm_bldc_control_hall_sensor_example.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/mcpwm/mcpwm_brushed_dc_control/main/CMakeLists.txt b/examples/peripherals/mcpwm/mcpwm_brushed_dc_control/main/CMakeLists.txt index 1259035cbf..81ecd07a8f 100644 --- a/examples/peripherals/mcpwm/mcpwm_brushed_dc_control/main/CMakeLists.txt +++ b/examples/peripherals/mcpwm/mcpwm_brushed_dc_control/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "mcpwm_brushed_dc_control_example.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "mcpwm_brushed_dc_control_example.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/mcpwm/mcpwm_servo_control/main/CMakeLists.txt b/examples/peripherals/mcpwm/mcpwm_servo_control/main/CMakeLists.txt index c8fa3d96b9..7a6efda90a 100644 --- a/examples/peripherals/mcpwm/mcpwm_servo_control/main/CMakeLists.txt +++ b/examples/peripherals/mcpwm/mcpwm_servo_control/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "mcpwm_servo_control_example.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "mcpwm_servo_control_example.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/pcnt/main/CMakeLists.txt b/examples/peripherals/pcnt/main/CMakeLists.txt index 2bd2779553..11ace9793f 100644 --- a/examples/peripherals/pcnt/main/CMakeLists.txt +++ b/examples/peripherals/pcnt/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "pcnt_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "pcnt_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/rmt_nec_tx_rx/main/CMakeLists.txt b/examples/peripherals/rmt_nec_tx_rx/main/CMakeLists.txt index 80c75b2285..907a16c057 100644 --- a/examples/peripherals/rmt_nec_tx_rx/main/CMakeLists.txt +++ b/examples/peripherals/rmt_nec_tx_rx/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "infrared_nec_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "infrared_nec_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/rmt_tx/main/CMakeLists.txt b/examples/peripherals/rmt_tx/main/CMakeLists.txt index a0a9147a2a..ad48214028 100644 --- a/examples/peripherals/rmt_tx/main/CMakeLists.txt +++ b/examples/peripherals/rmt_tx/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "rmt_tx_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "rmt_tx_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/sdio/host/components/esp_slave/CMakeLists.txt b/examples/peripherals/sdio/host/components/esp_slave/CMakeLists.txt index 1cda8805cb..9f5c38bbaf 100644 --- a/examples/peripherals/sdio/host/components/esp_slave/CMakeLists.txt +++ b/examples/peripherals/sdio/host/components/esp_slave/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCS "esp_slave.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") - -set(COMPONENT_REQUIRES driver sdmmc) - -register_component() +idf_component_register(SRCS "esp_slave.c" + INCLUDE_DIRS "include" + REQUIRES driver sdmmc) \ No newline at end of file diff --git a/examples/peripherals/sdio/host/main/CMakeLists.txt b/examples/peripherals/sdio/host/main/CMakeLists.txt index 6b03500639..e7392559ee 100644 --- a/examples/peripherals/sdio/host/main/CMakeLists.txt +++ b/examples/peripherals/sdio/host/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "app_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "app_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/sdio/slave/main/CMakeLists.txt b/examples/peripherals/sdio/slave/main/CMakeLists.txt index 6b03500639..e7392559ee 100644 --- a/examples/peripherals/sdio/slave/main/CMakeLists.txt +++ b/examples/peripherals/sdio/slave/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "app_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "app_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/sigmadelta/main/CMakeLists.txt b/examples/peripherals/sigmadelta/main/CMakeLists.txt index 1b0f2299f0..52abe2822d 100644 --- a/examples/peripherals/sigmadelta/main/CMakeLists.txt +++ b/examples/peripherals/sigmadelta/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "sigmadelta_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "sigmadelta_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/spi_master/main/CMakeLists.txt b/examples/peripherals/spi_master/main/CMakeLists.txt index 806ccae2b6..6d1a795b48 100644 --- a/examples/peripherals/spi_master/main/CMakeLists.txt +++ b/examples/peripherals/spi_master/main/CMakeLists.txt @@ -1,9 +1,5 @@ -set(COMPONENT_SRCS "decode_image.c" - "pretty_effect.c" - "spi_master_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - - -set(COMPONENT_EMBED_FILES image.jpg) - -register_component() +idf_component_register(SRCS "decode_image.c" + "pretty_effect.c" + "spi_master_example_main.c" + INCLUDE_DIRS "." + EMBED_FILES image.jpg) \ No newline at end of file diff --git a/examples/peripherals/spi_slave/receiver/main/CMakeLists.txt b/examples/peripherals/spi_slave/receiver/main/CMakeLists.txt index 6b03500639..e7392559ee 100644 --- a/examples/peripherals/spi_slave/receiver/main/CMakeLists.txt +++ b/examples/peripherals/spi_slave/receiver/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "app_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "app_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/spi_slave/sender/main/CMakeLists.txt b/examples/peripherals/spi_slave/sender/main/CMakeLists.txt index 6b03500639..e7392559ee 100644 --- a/examples/peripherals/spi_slave/sender/main/CMakeLists.txt +++ b/examples/peripherals/spi_slave/sender/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "app_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "app_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/timer_group/main/CMakeLists.txt b/examples/peripherals/timer_group/main/CMakeLists.txt index 9a96ce9068..9a07f9eb72 100644 --- a/examples/peripherals/timer_group/main/CMakeLists.txt +++ b/examples/peripherals/timer_group/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "timer_group_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "timer_group_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/touch_pad_interrupt/main/CMakeLists.txt b/examples/peripherals/touch_pad_interrupt/main/CMakeLists.txt index b77bf9c7be..df4240c344 100644 --- a/examples/peripherals/touch_pad_interrupt/main/CMakeLists.txt +++ b/examples/peripherals/touch_pad_interrupt/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "tp_interrupt_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "tp_interrupt_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/touch_pad_read/main/CMakeLists.txt b/examples/peripherals/touch_pad_read/main/CMakeLists.txt index b556e8c0ee..dad0c4905c 100644 --- a/examples/peripherals/touch_pad_read/main/CMakeLists.txt +++ b/examples/peripherals/touch_pad_read/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "tp_read_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "tp_read_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/uart/nmea0183_parser/main/CMakeLists.txt b/examples/peripherals/uart/nmea0183_parser/main/CMakeLists.txt index a8c42b8a71..b06050f468 100644 --- a/examples/peripherals/uart/nmea0183_parser/main/CMakeLists.txt +++ b/examples/peripherals/uart/nmea0183_parser/main/CMakeLists.txt @@ -1,5 +1,3 @@ -set(COMPONENT_SRCS "nmea_parser_example_main.c" - "nmea_parser.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "nmea_parser_example_main.c" + "nmea_parser.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/uart/uart_async_rxtxtasks/main/CMakeLists.txt b/examples/peripherals/uart/uart_async_rxtxtasks/main/CMakeLists.txt index b572323523..7cfd9876ee 100644 --- a/examples/peripherals/uart/uart_async_rxtxtasks/main/CMakeLists.txt +++ b/examples/peripherals/uart/uart_async_rxtxtasks/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "uart_async_rxtxtasks_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "uart_async_rxtxtasks_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/uart/uart_echo/main/CMakeLists.txt b/examples/peripherals/uart/uart_echo/main/CMakeLists.txt index 1ca803f131..b3eac5eff9 100644 --- a/examples/peripherals/uart/uart_echo/main/CMakeLists.txt +++ b/examples/peripherals/uart/uart_echo/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "uart_echo_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "uart_echo_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/uart/uart_echo_rs485/main/CMakeLists.txt b/examples/peripherals/uart/uart_echo_rs485/main/CMakeLists.txt index 8b3393049e..ef96bc63f1 100644 --- a/examples/peripherals/uart/uart_echo_rs485/main/CMakeLists.txt +++ b/examples/peripherals/uart/uart_echo_rs485/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "rs485_example.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "rs485_example.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/uart/uart_events/main/CMakeLists.txt b/examples/peripherals/uart/uart_events/main/CMakeLists.txt index 5a408ef1ef..44d8838503 100644 --- a/examples/peripherals/uart/uart_events/main/CMakeLists.txt +++ b/examples/peripherals/uart/uart_events/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "uart_events_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "uart_events_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/peripherals/uart/uart_select/main/CMakeLists.txt b/examples/peripherals/uart/uart_select/main/CMakeLists.txt index 4e3ae00def..8f1897f23f 100644 --- a/examples/peripherals/uart/uart_select/main/CMakeLists.txt +++ b/examples/peripherals/uart/uart_select/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "uart_select_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "uart_select_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/asio/chat_client/main/CMakeLists.txt b/examples/protocols/asio/chat_client/main/CMakeLists.txt index 25419de4a8..d92c9a8ae9 100644 --- a/examples/protocols/asio/chat_client/main/CMakeLists.txt +++ b/examples/protocols/asio/chat_client/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "chat_client.cpp") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "chat_client.cpp" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/asio/chat_server/main/CMakeLists.txt b/examples/protocols/asio/chat_server/main/CMakeLists.txt index 7e44a9039f..9042b223a6 100644 --- a/examples/protocols/asio/chat_server/main/CMakeLists.txt +++ b/examples/protocols/asio/chat_server/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "chat_server.cpp") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "chat_server.cpp" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/asio/tcp_echo_server/main/CMakeLists.txt b/examples/protocols/asio/tcp_echo_server/main/CMakeLists.txt index 04c3c94d9a..ef518dc723 100644 --- a/examples/protocols/asio/tcp_echo_server/main/CMakeLists.txt +++ b/examples/protocols/asio/tcp_echo_server/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "echo_server.cpp") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "echo_server.cpp" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/asio/udp_echo_server/main/CMakeLists.txt b/examples/protocols/asio/udp_echo_server/main/CMakeLists.txt index cd24937bef..c7a9e3575a 100644 --- a/examples/protocols/asio/udp_echo_server/main/CMakeLists.txt +++ b/examples/protocols/asio/udp_echo_server/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "udp_echo_server.cpp") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "udp_echo_server.cpp" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/coap_client/main/CMakeLists.txt b/examples/protocols/coap_client/main/CMakeLists.txt index eb1a1db15d..90a88c9d3b 100644 --- a/examples/protocols/coap_client/main/CMakeLists.txt +++ b/examples/protocols/coap_client/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "coap_client_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "coap_client_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/coap_server/main/CMakeLists.txt b/examples/protocols/coap_server/main/CMakeLists.txt index 8650fb1147..c28a7be75e 100644 --- a/examples/protocols/coap_server/main/CMakeLists.txt +++ b/examples/protocols/coap_server/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "coap_server_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "coap_server_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/esp_http_client/main/CMakeLists.txt b/examples/protocols/esp_http_client/main/CMakeLists.txt index 77a52e233a..8cc92e71e8 100644 --- a/examples/protocols/esp_http_client/main/CMakeLists.txt +++ b/examples/protocols/esp_http_client/main/CMakeLists.txt @@ -1,10 +1,6 @@ -set(COMPONENT_SRCS "esp_http_client_example.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - - # Embed the server root certificate into the final binary # # (If this was a component, we would set COMPONENT_EMBED_TXTFILES here.) -set(COMPONENT_EMBED_TXTFILES howsmyssl_com_root_cert.pem) - -register_component() +idf_component_register(SRCS "esp_http_client_example.c" + INCLUDE_DIRS "." + EMBED_TXTFILES howsmyssl_com_root_cert.pem) \ No newline at end of file diff --git a/examples/protocols/http2_request/components/sh2lib/CMakeLists.txt b/examples/protocols/http2_request/components/sh2lib/CMakeLists.txt index ec1b5a1e12..030f3f14c2 100644 --- a/examples/protocols/http2_request/components/sh2lib/CMakeLists.txt +++ b/examples/protocols/http2_request/components/sh2lib/CMakeLists.txt @@ -1,8 +1,4 @@ -set(COMPONENT_ADD_INCLUDEDIRS .) - -set(COMPONENT_SRCS "sh2lib.c") - -set(COMPONENT_REQUIRES nghttp) -set(COMPONENT_PRIV_REQUIRES lwip esp-tls) - -register_component() +idf_component_register(SRCS "sh2lib.c" + INCLUDE_DIRS . + REQUIRES nghttp + PRIV_REQUIRES lwip esp-tls) diff --git a/examples/protocols/http2_request/main/CMakeLists.txt b/examples/protocols/http2_request/main/CMakeLists.txt index 6139002258..defbb29583 100644 --- a/examples/protocols/http2_request/main/CMakeLists.txt +++ b/examples/protocols/http2_request/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "http2_request_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "http2_request_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/http_request/main/CMakeLists.txt b/examples/protocols/http_request/main/CMakeLists.txt index 8e346e8bb3..b4b91e9b87 100644 --- a/examples/protocols/http_request/main/CMakeLists.txt +++ b/examples/protocols/http_request/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "http_request_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "http_request_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/http_server/advanced_tests/main/CMakeLists.txt b/examples/protocols/http_server/advanced_tests/main/CMakeLists.txt index 9fd69b1d35..53a3e4d8b9 100644 --- a/examples/protocols/http_server/advanced_tests/main/CMakeLists.txt +++ b/examples/protocols/http_server/advanced_tests/main/CMakeLists.txt @@ -1,5 +1,3 @@ -set(COMPONENT_SRCS "main.c" - "tests.c") -set(COMPONENT_ADD_INCLUDEDIRS ". include") - -register_component() +idf_component_register(SRCS "main.c" + "tests.c" + INCLUDE_DIRS "." "include") \ No newline at end of file diff --git a/examples/protocols/http_server/file_serving/main/CMakeLists.txt b/examples/protocols/http_server/file_serving/main/CMakeLists.txt index a9493f54a8..2354c4b1be 100644 --- a/examples/protocols/http_server/file_serving/main/CMakeLists.txt +++ b/examples/protocols/http_server/file_serving/main/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCS "main.c" "file_server.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_EMBED_FILES "favicon.ico" "upload_script.html") - -register_component() +idf_component_register(SRCS "main.c" "file_server.c" + INCLUDE_DIRS "." + EMBED_FILES "favicon.ico" "upload_script.html") \ No newline at end of file diff --git a/examples/protocols/http_server/persistent_sockets/main/CMakeLists.txt b/examples/protocols/http_server/persistent_sockets/main/CMakeLists.txt index 85970762ab..e0287b7b9e 100644 --- a/examples/protocols/http_server/persistent_sockets/main/CMakeLists.txt +++ b/examples/protocols/http_server/persistent_sockets/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/http_server/restful_server/main/CMakeLists.txt b/examples/protocols/http_server/restful_server/main/CMakeLists.txt index 6df9c7c4da..4e35a40f23 100644 --- a/examples/protocols/http_server/restful_server/main/CMakeLists.txt +++ b/examples/protocols/http_server/restful_server/main/CMakeLists.txt @@ -1,7 +1,6 @@ -set(COMPONENT_SRCS "esp_rest_main.c" "rest_server.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "esp_rest_main.c" + "rest_server.c" + INCLUDE_DIRS ".") if(CONFIG_EXAMPLE_WEB_DEPLOY_SF) set(WEB_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../front/web-demo") diff --git a/examples/protocols/http_server/simple/main/CMakeLists.txt b/examples/protocols/http_server/simple/main/CMakeLists.txt index 85970762ab..e0287b7b9e 100644 --- a/examples/protocols/http_server/simple/main/CMakeLists.txt +++ b/examples/protocols/http_server/simple/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/https_mbedtls/main/CMakeLists.txt b/examples/protocols/https_mbedtls/main/CMakeLists.txt index c9b097c6b9..99d46aba00 100644 --- a/examples/protocols/https_mbedtls/main/CMakeLists.txt +++ b/examples/protocols/https_mbedtls/main/CMakeLists.txt @@ -1,10 +1,6 @@ -set(COMPONENT_SRCS "https_mbedtls_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - - # Embed the server root certificate into the final binary # # (If this was a component, we would set COMPONENT_EMBED_TXTFILES here.) -set(COMPONENT_EMBED_TXTFILES server_root_cert.pem) - -register_component() +idf_component_register(SRCS "https_mbedtls_example_main.c" + INCLUDE_DIRS "." + EMBED_TXTFILES server_root_cert.pem) \ No newline at end of file diff --git a/examples/protocols/https_request/main/CMakeLists.txt b/examples/protocols/https_request/main/CMakeLists.txt index 60a1a0664c..5501a68205 100644 --- a/examples/protocols/https_request/main/CMakeLists.txt +++ b/examples/protocols/https_request/main/CMakeLists.txt @@ -1,10 +1,6 @@ -set(COMPONENT_SRCS "https_request_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - - # Embed the server root certificate into the final binary # # (If this was a component, we would set COMPONENT_EMBED_TXTFILES here.) -set(COMPONENT_EMBED_TXTFILES server_root_cert.pem) - -register_component() +idf_component_register(SRCS "https_request_example_main.c" + INCLUDE_DIRS "." + EMBED_TXTFILES server_root_cert.pem) \ No newline at end of file diff --git a/examples/protocols/https_server/main/CMakeLists.txt b/examples/protocols/https_server/main/CMakeLists.txt index 9e08fb4d71..feca398b8e 100644 --- a/examples/protocols/https_server/main/CMakeLists.txt +++ b/examples/protocols/https_server/main/CMakeLists.txt @@ -1,8 +1,4 @@ -set(COMPONENT_SRCS "main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_EMBED_TXTFILES - "certs/cacert.pem" - "certs/prvtkey.pem") - -register_component() +idf_component_register(SRCS "main.c" + INCLUDE_DIRS "." + EMBED_TXTFILES "certs/cacert.pem" + "certs/prvtkey.pem") \ No newline at end of file diff --git a/examples/protocols/mdns/main/CMakeLists.txt b/examples/protocols/mdns/main/CMakeLists.txt index 814837ea97..141d1e30dc 100644 --- a/examples/protocols/mdns/main/CMakeLists.txt +++ b/examples/protocols/mdns/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "mdns_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "mdns_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/modbus_master/main/CMakeLists.txt b/examples/protocols/modbus_master/main/CMakeLists.txt index 6db1f90987..2555f99e43 100644 --- a/examples/protocols/modbus_master/main/CMakeLists.txt +++ b/examples/protocols/modbus_master/main/CMakeLists.txt @@ -1,6 +1,4 @@ -set(COMPONENT_SRCS "sense_main.c" - "sense_modbus.c" - "device_params.c") -set(COMPONENT_ADD_INCLUDEDIRS "." "include") - -register_component() \ No newline at end of file +idf_component_register(SRCS "sense_main.c" + "sense_modbus.c" + "device_params.c" + INCLUDE_DIRS "." "include") diff --git a/examples/protocols/modbus_slave/main/CMakeLists.txt b/examples/protocols/modbus_slave/main/CMakeLists.txt index 96b08bdc5b..19967e3169 100644 --- a/examples/protocols/modbus_slave/main/CMakeLists.txt +++ b/examples/protocols/modbus_slave/main/CMakeLists.txt @@ -1,5 +1,3 @@ -set(COMPONENT_SRCS "freemodbus.c" - "deviceparams.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() \ No newline at end of file +idf_component_register(SRCS "freemodbus.c" + "deviceparams.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/mqtt/publish_test/main/CMakeLists.txt b/examples/protocols/mqtt/publish_test/main/CMakeLists.txt index c3074a7067..67c4c7b5ad 100644 --- a/examples/protocols/mqtt/publish_test/main/CMakeLists.txt +++ b/examples/protocols/mqtt/publish_test/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "publish_test.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "publish_test.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/mqtt/ssl/main/CMakeLists.txt b/examples/protocols/mqtt/ssl/main/CMakeLists.txt index 6b03500639..e7392559ee 100644 --- a/examples/protocols/mqtt/ssl/main/CMakeLists.txt +++ b/examples/protocols/mqtt/ssl/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "app_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "app_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/mqtt/ssl_mutual_auth/main/CMakeLists.txt b/examples/protocols/mqtt/ssl_mutual_auth/main/CMakeLists.txt index 6b03500639..e7392559ee 100644 --- a/examples/protocols/mqtt/ssl_mutual_auth/main/CMakeLists.txt +++ b/examples/protocols/mqtt/ssl_mutual_auth/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "app_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "app_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/mqtt/tcp/main/CMakeLists.txt b/examples/protocols/mqtt/tcp/main/CMakeLists.txt index 6b03500639..e7392559ee 100644 --- a/examples/protocols/mqtt/tcp/main/CMakeLists.txt +++ b/examples/protocols/mqtt/tcp/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "app_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "app_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/mqtt/ws/main/CMakeLists.txt b/examples/protocols/mqtt/ws/main/CMakeLists.txt index 6b03500639..e7392559ee 100644 --- a/examples/protocols/mqtt/ws/main/CMakeLists.txt +++ b/examples/protocols/mqtt/ws/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "app_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "app_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/mqtt/wss/main/CMakeLists.txt b/examples/protocols/mqtt/wss/main/CMakeLists.txt index 6b03500639..e7392559ee 100644 --- a/examples/protocols/mqtt/wss/main/CMakeLists.txt +++ b/examples/protocols/mqtt/wss/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "app_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "app_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/openssl_client/main/CMakeLists.txt b/examples/protocols/openssl_client/main/CMakeLists.txt index d8e15c98cd..c7a8b33d91 100644 --- a/examples/protocols/openssl_client/main/CMakeLists.txt +++ b/examples/protocols/openssl_client/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "openssl_client_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "openssl_client_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/openssl_server/main/CMakeLists.txt b/examples/protocols/openssl_server/main/CMakeLists.txt index 07b57ef293..713b0cddf2 100644 --- a/examples/protocols/openssl_server/main/CMakeLists.txt +++ b/examples/protocols/openssl_server/main/CMakeLists.txt @@ -1,8 +1,4 @@ -set(COMPONENT_SRCS "openssl_server_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - - # Embed the certificate & key data directly in the built binary -set(COMPONENT_EMBED_TXTFILES cacert.pem prvtkey.pem) - -register_component() +idf_component_register(SRCS "openssl_server_example_main.c" + INCLUDE_DIRS "." + EMBED_TXTFILES cacert.pem prvtkey.pem) \ No newline at end of file diff --git a/examples/protocols/pppos_client/components/modem/CMakeLists.txt b/examples/protocols/pppos_client/components/modem/CMakeLists.txt index 1b1272ec2f..e1bc2c0a97 100644 --- a/examples/protocols/pppos_client/components/modem/CMakeLists.txt +++ b/examples/protocols/pppos_client/components/modem/CMakeLists.txt @@ -1,12 +1,8 @@ -set(COMPONENT_ADD_INCLUDEDIRS .) +set(srcs "src/esp_modem.c" + "src/esp_modem_dce_service" + "src/sim800.c" + "src/bg96.c") -set(COMPONENT_SRCS "src/esp_modem.c" - "src/esp_modem_dce_service" - "src/sim800.c" - "src/bg96.c") - -set(COMPONENT_ADD_INCLUDEDIRS "include") - -set(COMPONENT_REQUIRES driver) - -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS include + REQUIRES driver) \ No newline at end of file diff --git a/examples/protocols/pppos_client/main/CMakeLists.txt b/examples/protocols/pppos_client/main/CMakeLists.txt index e4ef1373fa..048a7246cd 100644 --- a/examples/protocols/pppos_client/main/CMakeLists.txt +++ b/examples/protocols/pppos_client/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "pppos_client_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "pppos_client_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/sntp/main/CMakeLists.txt b/examples/protocols/sntp/main/CMakeLists.txt index c7c035ca03..e06a3359f6 100644 --- a/examples/protocols/sntp/main/CMakeLists.txt +++ b/examples/protocols/sntp/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "sntp_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "sntp_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/sockets/tcp_client/main/CMakeLists.txt b/examples/protocols/sockets/tcp_client/main/CMakeLists.txt index be11f2950f..f1688dcb46 100644 --- a/examples/protocols/sockets/tcp_client/main/CMakeLists.txt +++ b/examples/protocols/sockets/tcp_client/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "tcp_client.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "tcp_client.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/sockets/tcp_server/main/CMakeLists.txt b/examples/protocols/sockets/tcp_server/main/CMakeLists.txt index 844a71574c..1565c7bc30 100644 --- a/examples/protocols/sockets/tcp_server/main/CMakeLists.txt +++ b/examples/protocols/sockets/tcp_server/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "tcp_server.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "tcp_server.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/sockets/udp_client/main/CMakeLists.txt b/examples/protocols/sockets/udp_client/main/CMakeLists.txt index aadad8c208..adc109a104 100644 --- a/examples/protocols/sockets/udp_client/main/CMakeLists.txt +++ b/examples/protocols/sockets/udp_client/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "udp_client.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "udp_client.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/sockets/udp_multicast/main/CMakeLists.txt b/examples/protocols/sockets/udp_multicast/main/CMakeLists.txt index d3caeb6ed7..a8b478a68f 100644 --- a/examples/protocols/sockets/udp_multicast/main/CMakeLists.txt +++ b/examples/protocols/sockets/udp_multicast/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "udp_multicast_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "udp_multicast_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/sockets/udp_server/main/CMakeLists.txt b/examples/protocols/sockets/udp_server/main/CMakeLists.txt index 55a6bebdc2..ceb9d65fa5 100644 --- a/examples/protocols/sockets/udp_server/main/CMakeLists.txt +++ b/examples/protocols/sockets/udp_server/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "udp_server.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "udp_server.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/protocols/websocket/main/CMakeLists.txt b/examples/protocols/websocket/main/CMakeLists.txt index caf642155c..bff26f1088 100644 --- a/examples/protocols/websocket/main/CMakeLists.txt +++ b/examples/protocols/websocket/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "websocket_example.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "websocket_example.c" + INCLUDE_DIRS ".") diff --git a/examples/provisioning/ble_prov/main/CMakeLists.txt b/examples/provisioning/ble_prov/main/CMakeLists.txt index 3c44a1a36a..a483b3871f 100644 --- a/examples/provisioning/ble_prov/main/CMakeLists.txt +++ b/examples/provisioning/ble_prov/main/CMakeLists.txt @@ -1,6 +1,4 @@ -set(COMPONENT_SRCS "app_main.c" - "app_prov.c" - "app_prov_handlers.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "app_main.c" + "app_prov.c" + "app_prov_handlers.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/provisioning/console_prov/main/CMakeLists.txt b/examples/provisioning/console_prov/main/CMakeLists.txt index 3c44a1a36a..a483b3871f 100644 --- a/examples/provisioning/console_prov/main/CMakeLists.txt +++ b/examples/provisioning/console_prov/main/CMakeLists.txt @@ -1,6 +1,4 @@ -set(COMPONENT_SRCS "app_main.c" - "app_prov.c" - "app_prov_handlers.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "app_main.c" + "app_prov.c" + "app_prov_handlers.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/provisioning/custom_config/components/custom_provisioning/CMakeLists.txt b/examples/provisioning/custom_config/components/custom_provisioning/CMakeLists.txt index 4e0f61c125..bcffb88bc6 100644 --- a/examples/provisioning/custom_config/components/custom_provisioning/CMakeLists.txt +++ b/examples/provisioning/custom_config/components/custom_provisioning/CMakeLists.txt @@ -1,8 +1,5 @@ -set(COMPONENT_ADD_INCLUDEDIRS include) -set(COMPONENT_PRIV_INCLUDEDIRS proto-c) -set(COMPONENT_SRCS "src/custom_config.c" - "proto-c/custom_config.pb-c.c") - -set(COMPONENT_PRIV_REQUIRES protobuf-c) - -register_component() +idf_component_register(SRCS "src/custom_config.c" + "proto-c/custom_config.pb-c.c" + INCLUDE_DIRS include + PRIV_INCLUDE_DIRS proto-c + PRIV_REQUIRES protobuf-c) \ No newline at end of file diff --git a/examples/provisioning/custom_config/main/CMakeLists.txt b/examples/provisioning/custom_config/main/CMakeLists.txt index 3c44a1a36a..a483b3871f 100644 --- a/examples/provisioning/custom_config/main/CMakeLists.txt +++ b/examples/provisioning/custom_config/main/CMakeLists.txt @@ -1,6 +1,4 @@ -set(COMPONENT_SRCS "app_main.c" - "app_prov.c" - "app_prov_handlers.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "app_main.c" + "app_prov.c" + "app_prov_handlers.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/provisioning/manager/main/CMakeLists.txt b/examples/provisioning/manager/main/CMakeLists.txt index 6b03500639..61fac40e63 100644 --- a/examples/provisioning/manager/main/CMakeLists.txt +++ b/examples/provisioning/manager/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "app_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "app_main.c" + INCLUDE_DIRS ".") diff --git a/examples/provisioning/softap_prov/main/CMakeLists.txt b/examples/provisioning/softap_prov/main/CMakeLists.txt index 3c44a1a36a..a483b3871f 100644 --- a/examples/provisioning/softap_prov/main/CMakeLists.txt +++ b/examples/provisioning/softap_prov/main/CMakeLists.txt @@ -1,6 +1,4 @@ -set(COMPONENT_SRCS "app_main.c" - "app_prov.c" - "app_prov_handlers.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "app_main.c" + "app_prov.c" + "app_prov_handlers.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/storage/nvs_rw_blob/main/CMakeLists.txt b/examples/storage/nvs_rw_blob/main/CMakeLists.txt index 675c11a0e9..a267ebda53 100644 --- a/examples/storage/nvs_rw_blob/main/CMakeLists.txt +++ b/examples/storage/nvs_rw_blob/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "nvs_blob_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "nvs_blob_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/storage/nvs_rw_value/main/CMakeLists.txt b/examples/storage/nvs_rw_value/main/CMakeLists.txt index 1383460018..6690649ca0 100644 --- a/examples/storage/nvs_rw_value/main/CMakeLists.txt +++ b/examples/storage/nvs_rw_value/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "nvs_value_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "nvs_value_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/storage/partition_api/partition_find/main/CMakeLists.txt b/examples/storage/partition_api/partition_find/main/CMakeLists.txt index 695e65e746..b2d392b5d4 100644 --- a/examples/storage/partition_api/partition_find/main/CMakeLists.txt +++ b/examples/storage/partition_api/partition_find/main/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCS "main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_EMBED_TXTFILES ../partitions_example.csv) - -register_component() +idf_component_register(SRCS "main.c" + INCLUDE_DIRS "." + EMBED_TXTFILES ../partitions_example.csv) \ No newline at end of file diff --git a/examples/storage/partition_api/partition_mmap/main/CMakeLists.txt b/examples/storage/partition_api/partition_mmap/main/CMakeLists.txt index 85970762ab..e0287b7b9e 100644 --- a/examples/storage/partition_api/partition_mmap/main/CMakeLists.txt +++ b/examples/storage/partition_api/partition_mmap/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/storage/partition_api/partition_ops/main/CMakeLists.txt b/examples/storage/partition_api/partition_ops/main/CMakeLists.txt index 85970762ab..e0287b7b9e 100644 --- a/examples/storage/partition_api/partition_ops/main/CMakeLists.txt +++ b/examples/storage/partition_api/partition_ops/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/storage/parttool/main/CMakeLists.txt b/examples/storage/parttool/main/CMakeLists.txt index a574d5ffe6..6056a42f9f 100644 --- a/examples/storage/parttool/main/CMakeLists.txt +++ b/examples/storage/parttool/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "parttool_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() \ No newline at end of file +idf_component_register(SRCS "parttool_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/storage/sd_card/main/CMakeLists.txt b/examples/storage/sd_card/main/CMakeLists.txt index d0a4b53d93..439aa90025 100644 --- a/examples/storage/sd_card/main/CMakeLists.txt +++ b/examples/storage/sd_card/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "sd_card_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "sd_card_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/storage/semihost_vfs/main/CMakeLists.txt b/examples/storage/semihost_vfs/main/CMakeLists.txt index 34d60ad45e..aabc5a454f 100644 --- a/examples/storage/semihost_vfs/main/CMakeLists.txt +++ b/examples/storage/semihost_vfs/main/CMakeLists.txt @@ -1,4 +1,5 @@ -set(COMPONENT_SRCS "semihost_vfs_example_main.c") +set(COMPONENT_SRCS ) set(COMPONENT_ADD_INCLUDEDIRS ".") -register_component() +idf_component_register(SRCS "semihost_vfs_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/storage/spiffs/main/CMakeLists.txt b/examples/storage/spiffs/main/CMakeLists.txt index 8d041d56d1..026db13131 100644 --- a/examples/storage/spiffs/main/CMakeLists.txt +++ b/examples/storage/spiffs/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "spiffs_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "spiffs_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/storage/spiffsgen/main/CMakeLists.txt b/examples/storage/spiffsgen/main/CMakeLists.txt index fdae02e50f..6153893c3c 100644 --- a/examples/storage/spiffsgen/main/CMakeLists.txt +++ b/examples/storage/spiffsgen/main/CMakeLists.txt @@ -1,7 +1,5 @@ -set(COMPONENT_SRCS "spiffsgen_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "spiffsgen_example_main.c" + INCLUDE_DIRS ".") # Create a SPIFFS image from the contents of the 'spiffs_image' directory # that fits the partition named 'storage'. FLASH_IN_PROJECT indicates that diff --git a/examples/storage/wear_levelling/main/CMakeLists.txt b/examples/storage/wear_levelling/main/CMakeLists.txt index e344e9a767..c92569631f 100644 --- a/examples/storage/wear_levelling/main/CMakeLists.txt +++ b/examples/storage/wear_levelling/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "wear_levelling_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "wear_levelling_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/app_trace_to_host/main/CMakeLists.txt b/examples/system/app_trace_to_host/main/CMakeLists.txt index 767689da75..b8adc44f73 100644 --- a/examples/system/app_trace_to_host/main/CMakeLists.txt +++ b/examples/system/app_trace_to_host/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "app_trace_to_host_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "app_trace_to_host_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/base_mac_address/main/CMakeLists.txt b/examples/system/base_mac_address/main/CMakeLists.txt index 364317db42..ab68da3e75 100644 --- a/examples/system/base_mac_address/main/CMakeLists.txt +++ b/examples/system/base_mac_address/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "base_mac_address_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "base_mac_address_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/console/components/cmd_nvs/CMakeLists.txt b/examples/system/console/components/cmd_nvs/CMakeLists.txt index 7c2d3c7d04..ab8257f9ca 100644 --- a/examples/system/console/components/cmd_nvs/CMakeLists.txt +++ b/examples/system/console/components/cmd_nvs/CMakeLists.txt @@ -1,7 +1,3 @@ -set(COMPONENT_ADD_INCLUDEDIRS .) - -set(COMPONENT_SRCS "cmd_nvs.c") - -set(COMPONENT_REQUIRES console nvs_flash) - -register_component() +idf_component_register(SRCS "cmd_nvs.c" + INCLUDE_DIRS . + REQUIRES console nvs_flash) \ No newline at end of file diff --git a/examples/system/console/components/cmd_system/CMakeLists.txt b/examples/system/console/components/cmd_system/CMakeLists.txt index b45a40c31b..ff4612b959 100644 --- a/examples/system/console/components/cmd_system/CMakeLists.txt +++ b/examples/system/console/components/cmd_system/CMakeLists.txt @@ -1,7 +1,3 @@ -set(COMPONENT_ADD_INCLUDEDIRS .) - -set(COMPONENT_SRCS "cmd_system.c") - -set(COMPONENT_REQUIRES console spi_flash) - -register_component() +idf_component_register(SRCS "cmd_system.c" + INCLUDE_DIRS . + REQUIRES console spi_flash) \ No newline at end of file diff --git a/examples/system/console/main/CMakeLists.txt b/examples/system/console/main/CMakeLists.txt index b285886390..5afdb190ad 100644 --- a/examples/system/console/main/CMakeLists.txt +++ b/examples/system/console/main/CMakeLists.txt @@ -1,5 +1,3 @@ -set(COMPONENT_SRCS "cmd_wifi.c" - "console_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "cmd_wifi.c" + "console_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/cpp_exceptions/main/CMakeLists.txt b/examples/system/cpp_exceptions/main/CMakeLists.txt index f735cc5a64..6668d4f291 100644 --- a/examples/system/cpp_exceptions/main/CMakeLists.txt +++ b/examples/system/cpp_exceptions/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "exception_example_main.cpp") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "exception_example_main.cpp" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/cpp_pthread/main/CMakeLists.txt b/examples/system/cpp_pthread/main/CMakeLists.txt index f95c5997c7..f4c4d218e0 100644 --- a/examples/system/cpp_pthread/main/CMakeLists.txt +++ b/examples/system/cpp_pthread/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "cpp_pthread.cpp") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "cpp_pthread.cpp" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/deep_sleep/main/CMakeLists.txt b/examples/system/deep_sleep/main/CMakeLists.txt index e99ca4de9d..c64fc7ac48 100644 --- a/examples/system/deep_sleep/main/CMakeLists.txt +++ b/examples/system/deep_sleep/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "deep_sleep_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "deep_sleep_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/esp_event/default_event_loop/main/CMakeLists.txt b/examples/system/esp_event/default_event_loop/main/CMakeLists.txt index 85970762ab..e0287b7b9e 100644 --- a/examples/system/esp_event/default_event_loop/main/CMakeLists.txt +++ b/examples/system/esp_event/default_event_loop/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/esp_event/user_event_loops/main/CMakeLists.txt b/examples/system/esp_event/user_event_loops/main/CMakeLists.txt index 85970762ab..e0287b7b9e 100644 --- a/examples/system/esp_event/user_event_loops/main/CMakeLists.txt +++ b/examples/system/esp_event/user_event_loops/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/esp_timer/main/CMakeLists.txt b/examples/system/esp_timer/main/CMakeLists.txt index 09db9ec296..eefc6db70d 100644 --- a/examples/system/esp_timer/main/CMakeLists.txt +++ b/examples/system/esp_timer/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "esp_timer_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "esp_timer_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/freertos/real_time_stats/main/CMakeLists.txt b/examples/system/freertos/real_time_stats/main/CMakeLists.txt index 85970762ab..e0287b7b9e 100644 --- a/examples/system/freertos/real_time_stats/main/CMakeLists.txt +++ b/examples/system/freertos/real_time_stats/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/gcov/main/CMakeLists.txt b/examples/system/gcov/main/CMakeLists.txt index 8c9cbd3eaf..0da58c5e1e 100644 --- a/examples/system/gcov/main/CMakeLists.txt +++ b/examples/system/gcov/main/CMakeLists.txt @@ -1,8 +1,6 @@ -set(COMPONENT_SRCS "gcov_example.c" - "gcov_example_func.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "gcov_example.c" + "gcov_example_func.c" + INCLUDE_DIRS ".") set_source_files_properties(gcov_example.c PROPERTIES COMPILE_FLAGS diff --git a/examples/system/himem/main/CMakeLists.txt b/examples/system/himem/main/CMakeLists.txt index a875dec50c..780e49a35c 100644 --- a/examples/system/himem/main/CMakeLists.txt +++ b/examples/system/himem/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "himem_test_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "himem_test_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/light_sleep/main/CMakeLists.txt b/examples/system/light_sleep/main/CMakeLists.txt index fc813fb9ea..36b6c93cc1 100644 --- a/examples/system/light_sleep/main/CMakeLists.txt +++ b/examples/system/light_sleep/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "light_sleep_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "light_sleep_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/network_tests/main/CMakeLists.txt b/examples/system/network_tests/main/CMakeLists.txt index c16f42adb9..f379bf03a2 100644 --- a/examples/system/network_tests/main/CMakeLists.txt +++ b/examples/system/network_tests/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "net_suite.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "net_suite.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/ota/advanced_https_ota/main/CMakeLists.txt b/examples/system/ota/advanced_https_ota/main/CMakeLists.txt index 19abec788c..f24c785feb 100644 --- a/examples/system/ota/advanced_https_ota/main/CMakeLists.txt +++ b/examples/system/ota/advanced_https_ota/main/CMakeLists.txt @@ -1,9 +1,4 @@ -set(COMPONENT_SRCS "advanced_https_ota_example.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - - -# Embed the server root certificate into the final binary -idf_build_get_property(project_dir PROJECT_DIR) -set(COMPONENT_EMBED_TXTFILES ${project_dir}/server_certs/ca_cert.pem) - -register_component() +idf_component_register(SRCS "advanced_https_ota_example.c" + INCLUDE_DIRS "." + # Embed the server root certificate into the final binary + EMBED_TXTFILES ${project_dir}/server_certs/ca_cert.pem) diff --git a/examples/system/ota/native_ota_example/main/CMakeLists.txt b/examples/system/ota/native_ota_example/main/CMakeLists.txt index 1e5d1ed0f5..c09881022c 100644 --- a/examples/system/ota/native_ota_example/main/CMakeLists.txt +++ b/examples/system/ota/native_ota_example/main/CMakeLists.txt @@ -1,8 +1,5 @@ -set(COMPONENT_SRCS "native_ota_example.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - # Embed the server root certificate into the final binary idf_build_get_property(project_dir PROJECT_DIR) -set(COMPONENT_EMBED_TXTFILES ${project_dir}/server_certs/ca_cert.pem) - -register_component() +idf_component_register(SRCS "native_ota_example.c" + INCLUDE_DIRS "." + EMBED_TXTFILES ${project_dir}/server_certs/ca_cert.pem) \ No newline at end of file diff --git a/examples/system/ota/otatool/main/CMakeLists.txt b/examples/system/ota/otatool/main/CMakeLists.txt index 2dc1cb53a0..4c341608ea 100644 --- a/examples/system/ota/otatool/main/CMakeLists.txt +++ b/examples/system/ota/otatool/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "otatool_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "otatool_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/ota/simple_ota_example/main/CMakeLists.txt b/examples/system/ota/simple_ota_example/main/CMakeLists.txt index c5db485eff..f8c5c183cf 100644 --- a/examples/system/ota/simple_ota_example/main/CMakeLists.txt +++ b/examples/system/ota/simple_ota_example/main/CMakeLists.txt @@ -1,9 +1,5 @@ -set(COMPONENT_SRCS "simple_ota_example.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - - # Embed the server root certificate into the final binary idf_build_get_property(project_dir PROJECT_DIR) -set(COMPONENT_EMBED_TXTFILES ${project_dir}/server_certs/ca_cert.pem) - -register_component() +idf_component_register(SRCS "simple_ota_example.c" + INCLUDE_DIRS "." + EMBED_TXTFILES ${project_dir}/server_certs/ca_cert.pem) diff --git a/examples/system/select/main/CMakeLists.txt b/examples/system/select/main/CMakeLists.txt index bf59f84c44..3dd427e874 100644 --- a/examples/system/select/main/CMakeLists.txt +++ b/examples/system/select/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "select_example.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "select_example.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/sysview_tracing/main/CMakeLists.txt b/examples/system/sysview_tracing/main/CMakeLists.txt index dfee658c9a..a23c5937bc 100644 --- a/examples/system/sysview_tracing/main/CMakeLists.txt +++ b/examples/system/sysview_tracing/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "sysview_tracing.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "sysview_tracing.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/sysview_tracing_heap_log/main/CMakeLists.txt b/examples/system/sysview_tracing_heap_log/main/CMakeLists.txt index 58d592c8b2..689bafd3ba 100644 --- a/examples/system/sysview_tracing_heap_log/main/CMakeLists.txt +++ b/examples/system/sysview_tracing_heap_log/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "sysview_heap_log.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "sysview_heap_log.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/task_watchdog/main/CMakeLists.txt b/examples/system/task_watchdog/main/CMakeLists.txt index ef06f3cc55..e805c40ac1 100644 --- a/examples/system/task_watchdog/main/CMakeLists.txt +++ b/examples/system/task_watchdog/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "task_watchdog_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "task_watchdog_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/ulp/main/CMakeLists.txt b/examples/system/ulp/main/CMakeLists.txt index d426857dc6..af7cb3f765 100644 --- a/examples/system/ulp/main/CMakeLists.txt +++ b/examples/system/ulp/main/CMakeLists.txt @@ -1,10 +1,6 @@ -# Set usual component variables -set(COMPONENT_SRCS "ulp_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS "") -set(COMPONENT_REQUIRES soc nvs_flash ulp) - -register_component() - +idf_component_register(SRCS "ulp_example_main.c" + INCLUDE_DIRS "" + REQUIRES soc nvs_flash ulp) # # ULP support additions to component CMakeLists.txt. # diff --git a/examples/system/ulp_adc/main/CMakeLists.txt b/examples/system/ulp_adc/main/CMakeLists.txt index 5f64763179..ef85f9b2fd 100644 --- a/examples/system/ulp_adc/main/CMakeLists.txt +++ b/examples/system/ulp_adc/main/CMakeLists.txt @@ -1,10 +1,6 @@ -# Set usual component variables -set(COMPONENT_SRCS "ulp_adc_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS "") -set(COMPONENT_REQUIRES soc nvs_flash ulp driver) - -register_component() - +idf_component_register(SRCS "ulp_adc_example_main.c" + INCLUDE_DIRS "" + REQUIRES soc nvs_flash ulp driver) # # ULP support additions to component CMakeLists.txt. # @@ -22,4 +18,4 @@ set(ulp_exp_dep_srcs "ulp_adc_example_main.c") # # 4. Call function to build ULP binary and embed in project using the argument # values above. -ulp_embed_binary(${ulp_app_name} ${ulp_s_sources} ${ulp_exp_dep_srcs}) \ No newline at end of file +ulp_embed_binary(${ulp_app_name} ${ulp_s_sources} ${ulp_exp_dep_srcs}) diff --git a/examples/system/unit_test/components/testable/CMakeLists.txt b/examples/system/unit_test/components/testable/CMakeLists.txt index 1df93d6d88..59adfac9d6 100644 --- a/examples/system/unit_test/components/testable/CMakeLists.txt +++ b/examples/system/unit_test/components/testable/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "mean.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") - -register_component() +idf_component_register(SRCS "mean.c" + INCLUDE_DIRS "include") \ No newline at end of file diff --git a/examples/system/unit_test/components/testable/test/CMakeLists.txt b/examples/system/unit_test/components/testable/test/CMakeLists.txt index bbb5b276da..33dded71ae 100644 --- a/examples/system/unit_test/components/testable/test/CMakeLists.txt +++ b/examples/system/unit_test/components/testable/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity testable) - -register_component() +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity testable) \ No newline at end of file diff --git a/examples/system/unit_test/main/CMakeLists.txt b/examples/system/unit_test/main/CMakeLists.txt index f726378150..0631174b7c 100644 --- a/examples/system/unit_test/main/CMakeLists.txt +++ b/examples/system/unit_test/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "example_unit_test_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "example_unit_test_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/unit_test/test/main/CMakeLists.txt b/examples/system/unit_test/test/main/CMakeLists.txt index b849174c77..8a4d168eac 100644 --- a/examples/system/unit_test/test/main/CMakeLists.txt +++ b/examples/system/unit_test/test/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "example_unit_test_test.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "example_unit_test_test.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/wifi/espnow/main/CMakeLists.txt b/examples/wifi/espnow/main/CMakeLists.txt index 151eab724b..c752a271b6 100644 --- a/examples/wifi/espnow/main/CMakeLists.txt +++ b/examples/wifi/espnow/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "espnow_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "espnow_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/wifi/getting_started/softAP/main/CMakeLists.txt b/examples/wifi/getting_started/softAP/main/CMakeLists.txt index 6724060715..a89388299c 100644 --- a/examples/wifi/getting_started/softAP/main/CMakeLists.txt +++ b/examples/wifi/getting_started/softAP/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "softap_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "softap_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/wifi/getting_started/station/main/CMakeLists.txt b/examples/wifi/getting_started/station/main/CMakeLists.txt index 3cd1031283..444b0f59f1 100644 --- a/examples/wifi/getting_started/station/main/CMakeLists.txt +++ b/examples/wifi/getting_started/station/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "station_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "station_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/wifi/iperf/components/iperf/CMakeLists.txt b/examples/wifi/iperf/components/iperf/CMakeLists.txt index 11a8f571e2..29cca1e3ec 100644 --- a/examples/wifi/iperf/components/iperf/CMakeLists.txt +++ b/examples/wifi/iperf/components/iperf/CMakeLists.txt @@ -1,7 +1,3 @@ -set(COMPONENT_ADD_INCLUDEDIRS .) - -set(COMPONENT_SRCS "iperf.c") - -set(COMPONENT_REQUIRES lwip) - -register_component() +idf_component_register(SRCS "iperf.c" + INCLUDE_DIRS . + REQUIRES lwip) \ No newline at end of file diff --git a/examples/wifi/iperf/main/CMakeLists.txt b/examples/wifi/iperf/main/CMakeLists.txt index e94ff94b07..978cc99e0e 100644 --- a/examples/wifi/iperf/main/CMakeLists.txt +++ b/examples/wifi/iperf/main/CMakeLists.txt @@ -1,5 +1,3 @@ -set(COMPONENT_SRCS "cmd_wifi.c" - "iperf_example_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "cmd_wifi.c" + "iperf_example_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/wifi/power_save/main/CMakeLists.txt b/examples/wifi/power_save/main/CMakeLists.txt index f7fc34d94a..e02dc88c90 100644 --- a/examples/wifi/power_save/main/CMakeLists.txt +++ b/examples/wifi/power_save/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "power_save.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "power_save.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/wifi/scan/main/CMakeLists.txt b/examples/wifi/scan/main/CMakeLists.txt index 0b789863af..9719433b43 100644 --- a/examples/wifi/scan/main/CMakeLists.txt +++ b/examples/wifi/scan/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "scan.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "scan.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/wifi/simple_sniffer/components/pcap/CMakeLists.txt b/examples/wifi/simple_sniffer/components/pcap/CMakeLists.txt index 15f5b5da63..ca59591e53 100644 --- a/examples/wifi/simple_sniffer/components/pcap/CMakeLists.txt +++ b/examples/wifi/simple_sniffer/components/pcap/CMakeLists.txt @@ -1,5 +1,2 @@ -set(COMPONENT_ADD_INCLUDEDIRS .) - -set(COMPONENT_SRCS "pcap.c") - -register_component() +idf_component_register(SRCS "pcap.c" + INCLUDE_DIRS .) \ No newline at end of file diff --git a/examples/wifi/simple_sniffer/main/CMakeLists.txt b/examples/wifi/simple_sniffer/main/CMakeLists.txt index 8e95d42fc3..9e14ddef0d 100644 --- a/examples/wifi/simple_sniffer/main/CMakeLists.txt +++ b/examples/wifi/simple_sniffer/main/CMakeLists.txt @@ -1,10 +1,3 @@ - -# The following lines of boilerplate have to be in your project's CMakeLists -# in this exact order for cmake to work correctly -cmake_minimum_required(VERSION 3.5) - -set(COMPONENT_SRCS "simple_sniffer_example_main.c" - "cmd_sniffer.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "simple_sniffer_example_main.c" + "cmd_sniffer.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/wifi/smart_config/main/CMakeLists.txt b/examples/wifi/smart_config/main/CMakeLists.txt index a716681e47..5f956d6660 100644 --- a/examples/wifi/smart_config/main/CMakeLists.txt +++ b/examples/wifi/smart_config/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "smartconfig_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "smartconfig_main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/wifi/wpa2_enterprise/main/CMakeLists.txt b/examples/wifi/wpa2_enterprise/main/CMakeLists.txt index 10640a32db..1c847a1f62 100644 --- a/examples/wifi/wpa2_enterprise/main/CMakeLists.txt +++ b/examples/wifi/wpa2_enterprise/main/CMakeLists.txt @@ -1,8 +1,4 @@ -set(COMPONENT_SRCS "wpa2_enterprise_main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - - # Embed CA, certificate & key directly into binary -set(COMPONENT_EMBED_TXTFILES wpa2_ca.pem wpa2_client.crt wpa2_client.key) - -register_component() +idf_component_register(SRCS "wpa2_enterprise_main.c" + INCLUDE_DIRS "." + EMBED_TXTFILES wpa2_ca.pem wpa2_client.crt wpa2_client.key) \ No newline at end of file diff --git a/examples/wifi/wps/main/CMakeLists.txt b/examples/wifi/wps/main/CMakeLists.txt index c0a1063f66..5ca4a9211f 100644 --- a/examples/wifi/wps/main/CMakeLists.txt +++ b/examples/wifi/wps/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "wps.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +idf_component_register(SRCS "wps.c" + INCLUDE_DIRS ".") \ No newline at end of file From e9bc46db71ce4d85bd8b8413284df2b8fbea57ae Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Sun, 28 Apr 2019 15:39:02 +0800 Subject: [PATCH 112/486] tools: use new component registration api for unit test app --- .../components/test_utils/CMakeLists.txt | 13 +++++-------- tools/unit-test-app/main/CMakeLists.txt | 6 ++---- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/tools/unit-test-app/components/test_utils/CMakeLists.txt b/tools/unit-test-app/components/test_utils/CMakeLists.txt index 50efbdbbb7..7932a10a68 100644 --- a/tools/unit-test-app/components/test_utils/CMakeLists.txt +++ b/tools/unit-test-app/components/test_utils/CMakeLists.txt @@ -1,9 +1,6 @@ -set(COMPONENT_SRCS "ref_clock.c" - "test_runner.c" - "test_utils.c") -set(COMPONENT_ADD_INCLUDEDIRS include) - -set(COMPONENT_REQUIRES spi_flash idf_test unity) - -register_component() +idf_component_register(SRCS "ref_clock.c" + "test_runner.c" + "test_utils.c" + INCLUDE_DIRS include + REQUIRES spi_flash idf_test unity) diff --git a/tools/unit-test-app/main/CMakeLists.txt b/tools/unit-test-app/main/CMakeLists.txt index 47f681d36a..95f9935aa9 100644 --- a/tools/unit-test-app/main/CMakeLists.txt +++ b/tools/unit-test-app/main/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_SRCS "app_main.c") -set(COMPONENT_ADD_INCLUDEDIRS "") - -register_component() +idf_component_register(SRCS "app_main.c" + INCLUDE_DIRS "") \ No newline at end of file From 047cf71c01189115766cb9eba79762a53f36f6d8 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Thu, 30 May 2019 14:17:10 +0800 Subject: [PATCH 113/486] tools: update make converter to use new component registration api --- tools/cmake/convert_to_cmake.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/tools/cmake/convert_to_cmake.py b/tools/cmake/convert_to_cmake.py index 80d9296d62..0ba7fa62f5 100755 --- a/tools/cmake/convert_to_cmake.py +++ b/tools/cmake/convert_to_cmake.py @@ -161,17 +161,14 @@ def convert_component(project_path, component_path): cflags = v.get("CFLAGS", None) with open(cmakelists_path, "w") as f: - f.write("set(COMPONENT_ADD_INCLUDEDIRS %s)\n\n" % component_add_includedirs) - - f.write("# Edit following two lines to set component requirements (see docs)\n") - f.write("set(COMPONENT_REQUIRES "")\n") - f.write("set(COMPONENT_PRIV_REQUIRES "")\n\n") - if component_srcs is not None: - f.write("set(COMPONENT_SRCS %s)\n\n" % component_srcs) - f.write("register_component()\n") + f.write("idf_component_register(SRCS %s)\n" % component_srcs) + f.write(" INCLUDE_DIRS %s" % component_add_includedirs) + f.write(" # Edit following two lines to set component requirements (see docs)\n") + f.write(" REQUIRES "")\n") + f.write(" PRIV_REQUIRES "")\n\n") else: - f.write("register_config_only_component()\n") + f.write("idf_component_register()\n") if cflags is not None: f.write("target_compile_options(${COMPONENT_LIB} PRIVATE %s)\n" % cflags) From 9b350f9eccae7c4d56008317f1b8982f9f492eea Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Fri, 21 Jun 2019 14:29:32 +0800 Subject: [PATCH 114/486] cmake: some formatting fixes Do not include bootloader in flash target when secure boot is enabled. Emit signing warning on all cases where signed apps are enabled (secure boot and signed images) Follow convention of capital letters for SECURE_BOOT_SIGNING_KEY variable, since it is relevant to other components, not just bootloader. Pass signing key and verification key via config, not requiring bootloader to know parent app dir. Misc. variables name corrections --- components/app_trace/CMakeLists.txt | 23 +- components/app_update/CMakeLists.txt | 3 +- components/bootloader_support/CMakeLists.txt | 33 +-- components/coap/CMakeLists.txt | 43 ++-- components/console/CMakeLists.txt | 10 +- components/driver/CMakeLists.txt | 3 +- components/efuse/CMakeLists.txt | 7 +- components/esp32/CMakeLists.txt | 49 ++-- components/esp_http_server/CMakeLists.txt | 4 +- components/esp_wifi/CMakeLists.txt | 19 +- components/espcoredump/CMakeLists.txt | 8 +- components/fatfs/CMakeLists.txt | 22 +- components/freemodbus/CMakeLists.txt | 3 +- components/freertos/CMakeLists.txt | 34 +-- components/heap/CMakeLists.txt | 7 +- components/libsodium/CMakeLists.txt | 237 ++++++++++--------- components/lwip/CMakeLists.txt | 182 +++++++------- components/newlib/CMakeLists.txt | 3 +- components/nghttp/CMakeLists.txt | 47 ++-- components/protocomm/CMakeLists.txt | 19 +- components/soc/CMakeLists.txt | 19 +- components/spi_flash/CMakeLists.txt | 24 +- components/unity/CMakeLists.txt | 5 +- components/wpa_supplicant/CMakeLists.txt | 149 ++++++------ components/xtensa/CMakeLists.txt | 5 +- 25 files changed, 491 insertions(+), 467 deletions(-) diff --git a/components/app_trace/CMakeLists.txt b/components/app_trace/CMakeLists.txt index 5276fa01ed..b9bcdddccc 100644 --- a/components/app_trace/CMakeLists.txt +++ b/components/app_trace/CMakeLists.txt @@ -1,7 +1,9 @@ -set(srcs "app_trace.c" - "app_trace_util.c" - "host_file_io.c" - "gcov/gcov_rtio.c") +set(srcs + "app_trace.c" + "app_trace_util.c" + "host_file_io.c" + "gcov/gcov_rtio.c") + set(include_dirs "include") if(CONFIG_SYSVIEW_ENABLE) @@ -10,12 +12,13 @@ if(CONFIG_SYSVIEW_ENABLE) sys_view/SEGGER sys_view/Sample/OS) - list(APPEND srcs "sys_view/SEGGER/SEGGER_SYSVIEW.c" - "sys_view/Sample/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c" - "sys_view/Sample/OS/SEGGER_SYSVIEW_FreeRTOS.c" - "sys_view/esp32/SEGGER_RTT_esp32.c" - "sys_view/ext/heap_trace_module.c" - "sys_view/ext/logging.c") + list(APPEND srcs + "sys_view/SEGGER/SEGGER_SYSVIEW.c" + "sys_view/Sample/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c" + "sys_view/Sample/OS/SEGGER_SYSVIEW_FreeRTOS.c" + "sys_view/esp32/SEGGER_RTT_esp32.c" + "sys_view/ext/heap_trace_module.c" + "sys_view/ext/logging.c") endif() if(CONFIG_HEAP_TRACING_TOHOST) diff --git a/components/app_update/CMakeLists.txt b/components/app_update/CMakeLists.txt index acb02accb2..af07c24042 100644 --- a/components/app_update/CMakeLists.txt +++ b/components/app_update/CMakeLists.txt @@ -1,4 +1,5 @@ -idf_component_register(SRCS "esp_ota_ops.c" "esp_app_desc.c" +idf_component_register(SRCS "esp_ota_ops.c" + "esp_app_desc.c" INCLUDE_DIRS "include" REQUIRES spi_flash partition_table bootloader_support) diff --git a/components/bootloader_support/CMakeLists.txt b/components/bootloader_support/CMakeLists.txt index a8db5c4873..d40b8d1866 100644 --- a/components/bootloader_support/CMakeLists.txt +++ b/components/bootloader_support/CMakeLists.txt @@ -1,21 +1,23 @@ -set(srcs "src/bootloader_clock.c" - "src/bootloader_common.c" - "src/bootloader_flash.c" - "src/bootloader_random.c" - "src/bootloader_utility.c" - "src/esp_image_format.c" - "src/flash_partitions.c" - "src/flash_qio_mode.c") +set(srcs + "src/bootloader_clock.c" + "src/bootloader_common.c" + "src/bootloader_flash.c" + "src/bootloader_random.c" + "src/bootloader_utility.c" + "src/esp_image_format.c" + "src/flash_partitions.c" + "src/flash_qio_mode.c") if(BOOTLOADER_BUILD) set(include_dirs "include" "include_bootloader") set(requires soc) #unfortunately the header directly uses SOC registers set(priv_requires micro-ecc spi_flash efuse) - list(APPEND srcs "src/bootloader_init.c" - "src/${IDF_TARGET}/bootloader_sha.c" - "src/${IDF_TARGET}/flash_encrypt.c" - "src/${IDF_TARGET}/secure_boot_signatures.c" - "src/${IDF_TARGET}/secure_boot.c") + list(APPEND srcs + "src/bootloader_init.c" + "src/${IDF_TARGET}/bootloader_sha.c" + "src/${IDF_TARGET}/flash_encrypt.c" + "src/${IDF_TARGET}/secure_boot_signatures.c" + "src/${IDF_TARGET}/secure_boot.c") if(CONFIG_SECURE_SIGNED_APPS) get_filename_component(secure_boot_verification_key @@ -51,8 +53,9 @@ if(BOOTLOADER_BUILD) "${secure_boot_verification_key}") endif() else() - list(APPEND srcs "src/idf/bootloader_sha.c" - "src/idf/secure_boot_signatures.c") + list(APPEND srcs + "src/idf/bootloader_sha.c" + "src/idf/secure_boot_signatures.c") set(include_dirs "include") set(priv_include_dirs "include_bootloader") set(requires soc) #unfortunately the header directly uses SOC registers diff --git a/components/coap/CMakeLists.txt b/components/coap/CMakeLists.txt index 78015bb056..aef9d31682 100644 --- a/components/coap/CMakeLists.txt +++ b/components/coap/CMakeLists.txt @@ -1,30 +1,31 @@ set(include_dirs port/include port/include/coap libcoap/include libcoap/include/coap2) -set(srcs "libcoap/src/address.c" - "libcoap/src/async.c" - "libcoap/src/block.c" - "libcoap/src/coap_event.c" - "libcoap/src/coap_hashkey.c" - "libcoap/src/coap_session.c" - "libcoap/src/coap_time.c" - "libcoap/src/coap_debug.c" - "libcoap/src/encode.c" - "libcoap/src/mem.c" - "libcoap/src/net.c" - "libcoap/src/option.c" - "libcoap/src/pdu.c" - "libcoap/src/resource.c" - "libcoap/src/str.c" - "libcoap/src/subscribe.c" - "libcoap/src/uri.c" - "libcoap/src/coap_notls.c" - "port/coap_io.c") +set(srcs + "libcoap/src/address.c" + "libcoap/src/async.c" + "libcoap/src/block.c" + "libcoap/src/coap_event.c" + "libcoap/src/coap_hashkey.c" + "libcoap/src/coap_session.c" + "libcoap/src/coap_time.c" + "libcoap/src/coap_debug.c" + "libcoap/src/encode.c" + "libcoap/src/mem.c" + "libcoap/src/net.c" + "libcoap/src/option.c" + "libcoap/src/pdu.c" + "libcoap/src/resource.c" + "libcoap/src/str.c" + "libcoap/src/subscribe.c" + "libcoap/src/uri.c" + "libcoap/src/coap_notls.c" + "port/coap_io.c") set(COMPONENT_REQUIRES lwip) idf_component_register(SRCS "${srcs}" - INCLUDE_DIRS "${include_dirs}" - REQUIRES lwip) + INCLUDE_DIRS "${include_dirs}" + REQUIRES lwip) # Silence format truncation warning, until it is fixed upstream set_source_files_properties(libcoap/src/coap_debug.c PROPERTIES COMPILE_FLAGS -Wno-format-truncation) diff --git a/components/console/CMakeLists.txt b/components/console/CMakeLists.txt index 244834c224..cb20200cd6 100644 --- a/components/console/CMakeLists.txt +++ b/components/console/CMakeLists.txt @@ -1,6 +1,6 @@ idf_component_register(SRCS "commands.c" - "split_argv.c" - "argtable3/argtable3.c" - "linenoise/linenoise.c" - INCLUDE_DIRS "." - REQUIRES vfs) + "split_argv.c" + "argtable3/argtable3.c" + "linenoise/linenoise.c" + INCLUDE_DIRS "." + REQUIRES vfs) diff --git a/components/driver/CMakeLists.txt b/components/driver/CMakeLists.txt index ddeb98d108..f0509fcf19 100644 --- a/components/driver/CMakeLists.txt +++ b/components/driver/CMakeLists.txt @@ -1,4 +1,5 @@ -set(srcs "can.c" +set(srcs + "can.c" "gpio.c" "i2c.c" "i2s.c" diff --git a/components/efuse/CMakeLists.txt b/components/efuse/CMakeLists.txt index f43a2e6030..9a05e7cc14 100644 --- a/components/efuse/CMakeLists.txt +++ b/components/efuse/CMakeLists.txt @@ -7,9 +7,10 @@ if(EXISTS "${COMPONENT_DIR}/${soc_name}") set(include_dirs include ${soc_name}/include) endif() -list(APPEND srcs "src/esp_efuse_api.c" - "src/esp_efuse_fields.c" - "src/esp_efuse_utility.c") +list(APPEND srcs + "src/esp_efuse_api.c" + "src/esp_efuse_fields.c" + "src/esp_efuse_utility.c") idf_component_register(SRCS "${srcs}" PRIV_REQUIRES bootloader_support soc diff --git a/components/esp32/CMakeLists.txt b/components/esp32/CMakeLists.txt index b69f3747ed..916113b533 100644 --- a/components/esp32/CMakeLists.txt +++ b/components/esp32/CMakeLists.txt @@ -4,30 +4,31 @@ if(BOOTLOADER_BUILD) target_linker_script(${COMPONENT_LIB} INTERFACE "ld/esp32.peripherals.ld") else() # Regular app build - set(srcs "brownout.c" - "cache_err_int.c" - "cache_sram_mmu.c" - "clk.c" - "cpu_start.c" - "crosscore_int.c" - "dport_access.c" - "dport_panic_highint_hdl.S" - "esp_adapter.c" - "esp_timer_esp32.c" - "esp_himem.c" - "gdbstub.c" - "hw_random.c" - "int_wdt.c" - "intr_alloc.c" - "panic.c" - "pm_esp32.c" - "pm_trace.c" - "reset_reason.c" - "sleep_modes.c" - "spiram.c" - "spiram_psram.c" - "system_api.c" - "task_wdt.c") + set(srcs + "brownout.c" + "cache_err_int.c" + "cache_sram_mmu.c" + "clk.c" + "cpu_start.c" + "crosscore_int.c" + "dport_access.c" + "dport_panic_highint_hdl.S" + "esp_adapter.c" + "esp_timer_esp32.c" + "esp_himem.c" + "gdbstub.c" + "hw_random.c" + "int_wdt.c" + "intr_alloc.c" + "panic.c" + "pm_esp32.c" + "pm_trace.c" + "reset_reason.c" + "sleep_modes.c" + "spiram.c" + "spiram_psram.c" + "system_api.c" + "task_wdt.c") set(include_dirs "include") set(requires driver esp_event efuse soc) #unfortunately rom/uart uses SOC registers directly diff --git a/components/esp_http_server/CMakeLists.txt b/components/esp_http_server/CMakeLists.txt index 4bf15aa866..744e6b207f 100644 --- a/components/esp_http_server/CMakeLists.txt +++ b/components/esp_http_server/CMakeLists.txt @@ -6,5 +6,5 @@ idf_component_register(SRCS "src/httpd_main.c" "src/util/ctrl_sock.c" INCLUDE_DIRS "include" PRIV_INCLUDE_DIRS "src/port/esp32" "src/util" - REQUIRES nghttp - PRIV_REQUIRES lwip) # for http_parser.h + REQUIRES nghttp # for http_parser.h + PRIV_REQUIRES lwip) diff --git a/components/esp_wifi/CMakeLists.txt b/components/esp_wifi/CMakeLists.txt index 4cf4723b4a..9c7f29759b 100644 --- a/components/esp_wifi/CMakeLists.txt +++ b/components/esp_wifi/CMakeLists.txt @@ -1,24 +1,21 @@ idf_build_get_property(idf_target IDF_TARGET) -idf_build_get_property(build_dir BUILD_DIR) - -set(srcs - "src/coexist.c" - "src/fast_crypto_ops.c" - "src/lib_printf.c" - "src/mesh_event.c" - "src/phy_init.c" - "src/restore.c" - "src/wifi_init.c") if(NOT CONFIG_ESP32_NO_BLOBS) set(ldfragments "linker.lf") endif() -idf_component_register(SRCS "${srcs}" +idf_component_register(SRCS "src/coexist.c" + "src/fast_crypto_ops.c" + "src/lib_printf.c" + "src/mesh_event.c" + "src/phy_init.c" + "src/restore.c" + "src/wifi_init.c" INCLUDE_DIRS "include" "${idf_target}/include" PRIV_REQUIRES wpa_supplicant nvs_flash LDFRAGMENTS "${ldfragments}") +idf_build_get_property(build_dir BUILD_DIR) target_link_libraries(${COMPONENT_LIB} PUBLIC "-L ${CMAKE_CURRENT_SOURCE_DIR}/lib_${idf_target}") if(NOT CONFIG_ESP32_NO_BLOBS) diff --git a/components/espcoredump/CMakeLists.txt b/components/espcoredump/CMakeLists.txt index f925f93db2..aa3b32eeac 100644 --- a/components/espcoredump/CMakeLists.txt +++ b/components/espcoredump/CMakeLists.txt @@ -2,7 +2,7 @@ idf_component_register(SRCS "src/core_dump_common.c" "src/core_dump_flash.c" "src/core_dump_port.c" "src/core_dump_uart.c" - INCLUDE_DIRS "include" - PRIV_INCLUDE_DIRS "include_core_dump" - LDFRAGMENTS linker.lf - PRIV_REQUIRES spi_flash soc) + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "include_core_dump" + LDFRAGMENTS linker.lf + PRIV_REQUIRES spi_flash soc) diff --git a/components/fatfs/CMakeLists.txt b/components/fatfs/CMakeLists.txt index d46f077252..d12bd175d2 100644 --- a/components/fatfs/CMakeLists.txt +++ b/components/fatfs/CMakeLists.txt @@ -1,14 +1,12 @@ -set(srcs "src/diskio.c" - "src/diskio_rawflash.c" - "src/diskio_sdmmc.c" - "src/diskio_wl.c" - "src/ff.c" - "src/ffsystem.c" - "src/ffunicode.c" - "src/vfs_fat.c" - "src/vfs_fat_sdmmc.c" - "src/vfs_fat_spiflash.c") - -idf_component_register(SRCS "${srcs}" +idf_component_register(SRCS "src/diskio.c" + "src/diskio_rawflash.c" + "src/diskio_sdmmc.c" + "src/diskio_wl.c" + "src/ff.c" + "src/ffsystem.c" + "src/ffunicode.c" + "src/vfs_fat.c" + "src/vfs_fat_sdmmc.c" + "src/vfs_fat_spiflash.c" INCLUDE_DIRS src REQUIRES wear_levelling sdmmc) diff --git a/components/freemodbus/CMakeLists.txt b/components/freemodbus/CMakeLists.txt index 0bf6b6af07..97112a53be 100644 --- a/components/freemodbus/CMakeLists.txt +++ b/components/freemodbus/CMakeLists.txt @@ -1,6 +1,7 @@ # The following five lines of boilerplate have to be in your project's # CMakeLists in this exact order for cmake to work correctly -set(srcs "common/esp_modbus_master.c" +set(srcs + "common/esp_modbus_master.c" "common/esp_modbus_slave.c" "modbus/mb.c" "modbus/mb_m.c" diff --git a/components/freertos/CMakeLists.txt b/components/freertos/CMakeLists.txt index 0efd886e0d..ee6b560392 100644 --- a/components/freertos/CMakeLists.txt +++ b/components/freertos/CMakeLists.txt @@ -1,19 +1,21 @@ -set(srcs "croutine.c" - "event_groups.c" - "FreeRTOS-openocd.c" - "list.c" - "port.c" - "portasm.S" - "queue.c" - "tasks.c" - "timers.c" - "xtensa_context.S" - "xtensa_init.c" - "xtensa_intr.c" - "xtensa_intr_asm.S" - "xtensa_overlay_os_hook.c" - "xtensa_vector_defaults.S" - "xtensa_vectors.S") +set(srcs + "croutine.c" + "event_groups.c" + "FreeRTOS-openocd.c" + "list.c" + "port.c" + "portasm.S" + "queue.c" + "tasks.c" + "timers.c" + "xtensa_context.S" + "xtensa_init.c" + "xtensa_intr.c" + "xtensa_intr_asm.S" + "xtensa_overlay_os_hook.c" + "xtensa_vector_defaults.S" + "xtensa_vectors.S") + # app_trace is required by FreeRTOS headers only when CONFIG_SYSVIEW_ENABLE=y, # but requirements can't depend on config options, so always require it. idf_component_register(SRCS "${srcs}" diff --git a/components/heap/CMakeLists.txt b/components/heap/CMakeLists.txt index 40fac3710b..0bacaf74f9 100644 --- a/components/heap/CMakeLists.txt +++ b/components/heap/CMakeLists.txt @@ -1,6 +1,7 @@ -set(srcs "heap_caps.c" - "heap_caps_init.c" - "multi_heap.c") +set(srcs + "heap_caps.c" + "heap_caps_init.c" + "multi_heap.c") if(NOT CONFIG_HEAP_POISONING_DISABLED) list(APPEND srcs "multi_heap_poisoning.c") diff --git a/components/libsodium/CMakeLists.txt b/components/libsodium/CMakeLists.txt index 358a840d25..103e296612 100644 --- a/components/libsodium/CMakeLists.txt +++ b/components/libsodium/CMakeLists.txt @@ -1,126 +1,129 @@ set(SRC libsodium/src/libsodium) # Derived from libsodium/src/libsodium/Makefile.am # (ignoring the !MINIMAL set) -set(srcs "${SRC}/crypto_aead/chacha20poly1305/sodium/aead_chacha20poly1305.c" - "${SRC}/crypto_aead/xchacha20poly1305/sodium/aead_xchacha20poly1305.c" - "${SRC}/crypto_auth/crypto_auth.c" - "${SRC}/crypto_auth/hmacsha256/auth_hmacsha256.c" - "${SRC}/crypto_auth/hmacsha512/auth_hmacsha512.c" - "${SRC}/crypto_auth/hmacsha512256/auth_hmacsha512256.c" - "${SRC}/crypto_box/crypto_box.c" - "${SRC}/crypto_box/crypto_box_easy.c" - "${SRC}/crypto_box/crypto_box_seal.c" - "${SRC}/crypto_box/curve25519xchacha20poly1305/box_curve25519xchacha20poly1305.c" - "${SRC}/crypto_box/curve25519xsalsa20poly1305/box_curve25519xsalsa20poly1305.c" - "${SRC}/crypto_core/curve25519/ref10/curve25519_ref10.c" - "${SRC}/crypto_core/hchacha20/core_hchacha20.c" - "${SRC}/crypto_core/hsalsa20/core_hsalsa20.c" - "${SRC}/crypto_core/hsalsa20/ref2/core_hsalsa20_ref2.c" - "${SRC}/crypto_core/salsa/ref/core_salsa_ref.c" - "${SRC}/crypto_generichash/crypto_generichash.c" - "${SRC}/crypto_generichash/blake2b/generichash_blake2.c" - "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-avx2.c" - "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-ref.c" - "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-sse41.c" - "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-ssse3.c" - "${SRC}/crypto_generichash/blake2b/ref/blake2b-ref.c" - "${SRC}/crypto_generichash/blake2b/ref/generichash_blake2b.c" - "${SRC}/crypto_hash/crypto_hash.c" - "${SRC}/crypto_hash/sha256/hash_sha256.c" - "${SRC}/crypto_hash/sha256/cp/hash_sha256_cp.c" - "${SRC}/crypto_hash/sha512/hash_sha512.c" - "${SRC}/crypto_hash/sha512/cp/hash_sha512_cp.c" - "${SRC}/crypto_kdf/crypto_kdf.c" - "${SRC}/crypto_kdf/blake2b/kdf_blake2b.c" - "${SRC}/crypto_kx/crypto_kx.c" - "${SRC}/crypto_onetimeauth/crypto_onetimeauth.c" - "${SRC}/crypto_onetimeauth/poly1305/onetimeauth_poly1305.c" - "${SRC}/crypto_onetimeauth/poly1305/donna/poly1305_donna.c" - "${SRC}/crypto_onetimeauth/poly1305/sse2/poly1305_sse2.c" - "${SRC}/crypto_pwhash/crypto_pwhash.c" - "${SRC}/crypto_pwhash/argon2/argon2-core.c" - "${SRC}/crypto_pwhash/argon2/argon2-encoding.c" - "${SRC}/crypto_pwhash/argon2/argon2-fill-block-ref.c" - "${SRC}/crypto_pwhash/argon2/argon2-fill-block-ssse3.c" - "${SRC}/crypto_pwhash/argon2/argon2.c" - "${SRC}/crypto_pwhash/argon2/blake2b-long.c" - "${SRC}/crypto_pwhash/argon2/pwhash_argon2i.c" - "${SRC}/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt-common.c" - "${SRC}/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.c" - "${SRC}/crypto_pwhash/scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c" - "${SRC}/crypto_pwhash/scryptsalsa208sha256/scrypt_platform.c" - "${SRC}/crypto_pwhash/scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c" - "${SRC}/crypto_pwhash/scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c" - "${SRC}/crypto_scalarmult/crypto_scalarmult.c" - "${SRC}/crypto_scalarmult/curve25519/scalarmult_curve25519.c" - "${SRC}/crypto_scalarmult/curve25519/donna_c64/curve25519_donna_c64.c" - "${SRC}/crypto_scalarmult/curve25519/ref10/x25519_ref10.c" - "${SRC}/crypto_scalarmult/curve25519/sandy2x/consts.S" - "${SRC}/crypto_scalarmult/curve25519/sandy2x/curve25519_sandy2x.c" - "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_invert.c" - "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_mul.S" - "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_nsquare.S" - "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_pack.S" - "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe_frombytes_sandy2x.c" - "${SRC}/crypto_scalarmult/curve25519/sandy2x/ladder.S" - "${SRC}/crypto_scalarmult/curve25519/sandy2x/ladder_base.S" - "${SRC}/crypto_scalarmult/curve25519/sandy2x/sandy2x.S" - "${SRC}/crypto_secretbox/crypto_secretbox.c" - "${SRC}/crypto_secretbox/crypto_secretbox_easy.c" - "${SRC}/crypto_secretbox/xchacha20poly1305/secretbox_xchacha20poly1305.c" - "${SRC}/crypto_secretbox/xsalsa20poly1305/secretbox_xsalsa20poly1305.c" - "${SRC}/crypto_shorthash/crypto_shorthash.c" - "${SRC}/crypto_shorthash/siphash24/shorthash_siphash24.c" - "${SRC}/crypto_shorthash/siphash24/shorthash_siphashx24.c" - "${SRC}/crypto_shorthash/siphash24/ref/shorthash_siphash24_ref.c" - "${SRC}/crypto_shorthash/siphash24/ref/shorthash_siphashx24_ref.c" - "${SRC}/crypto_sign/crypto_sign.c" - "${SRC}/crypto_sign/ed25519/sign_ed25519.c" - "${SRC}/crypto_sign/ed25519/ref10/keypair.c" - "${SRC}/crypto_sign/ed25519/ref10/obsolete.c" - "${SRC}/crypto_sign/ed25519/ref10/open.c" - "${SRC}/crypto_sign/ed25519/ref10/sign.c" - "${SRC}/crypto_stream/crypto_stream.c" - "${SRC}/crypto_stream/aes128ctr/stream_aes128ctr.c" - "${SRC}/crypto_stream/aes128ctr/nacl/afternm_aes128ctr.c" - "${SRC}/crypto_stream/aes128ctr/nacl/beforenm_aes128ctr.c" - "${SRC}/crypto_stream/aes128ctr/nacl/consts_aes128ctr.c" - "${SRC}/crypto_stream/aes128ctr/nacl/int128_aes128ctr.c" - "${SRC}/crypto_stream/aes128ctr/nacl/stream_aes128ctr_nacl.c" - "${SRC}/crypto_stream/aes128ctr/nacl/xor_afternm_aes128ctr.c" - "${SRC}/crypto_stream/chacha20/stream_chacha20.c" - "${SRC}/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-avx2.c" - "${SRC}/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-ssse3.c" - "${SRC}/crypto_stream/chacha20/ref/chacha20_ref.c" - "${SRC}/crypto_stream/salsa20/stream_salsa20.c" - "${SRC}/crypto_stream/salsa20/ref/salsa20_ref.c" - "${SRC}/crypto_stream/salsa20/xmm6/salsa20_xmm6-asm.S" - "${SRC}/crypto_stream/salsa20/xmm6/salsa20_xmm6.c" - "${SRC}/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-avx2.c" - "${SRC}/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-sse2.c" - "${SRC}/crypto_stream/salsa2012/stream_salsa2012.c" - "${SRC}/crypto_stream/salsa2012/ref/stream_salsa2012_ref.c" - "${SRC}/crypto_stream/salsa208/stream_salsa208.c" - "${SRC}/crypto_stream/salsa208/ref/stream_salsa208_ref.c" - "${SRC}/crypto_stream/xchacha20/stream_xchacha20.c" - "${SRC}/crypto_stream/xsalsa20/stream_xsalsa20.c" - "${SRC}/crypto_verify/sodium/verify.c" - "${SRC}/randombytes/randombytes.c" - "${SRC}/randombytes/nativeclient/randombytes_nativeclient.c" - "${SRC}/randombytes/salsa20/randombytes_salsa20_random.c" - "${SRC}/randombytes/sysrandom/randombytes_sysrandom.c" - "${SRC}/sodium/core.c" - "${SRC}/sodium/runtime.c" - "${SRC}/sodium/utils.c" - "${SRC}/sodium/version.c" - "port/randombytes_esp32.c") +set(srcs + "${SRC}/crypto_aead/chacha20poly1305/sodium/aead_chacha20poly1305.c" + "${SRC}/crypto_aead/xchacha20poly1305/sodium/aead_xchacha20poly1305.c" + "${SRC}/crypto_auth/crypto_auth.c" + "${SRC}/crypto_auth/hmacsha256/auth_hmacsha256.c" + "${SRC}/crypto_auth/hmacsha512/auth_hmacsha512.c" + "${SRC}/crypto_auth/hmacsha512256/auth_hmacsha512256.c" + "${SRC}/crypto_box/crypto_box.c" + "${SRC}/crypto_box/crypto_box_easy.c" + "${SRC}/crypto_box/crypto_box_seal.c" + "${SRC}/crypto_box/curve25519xchacha20poly1305/box_curve25519xchacha20poly1305.c" + "${SRC}/crypto_box/curve25519xsalsa20poly1305/box_curve25519xsalsa20poly1305.c" + "${SRC}/crypto_core/curve25519/ref10/curve25519_ref10.c" + "${SRC}/crypto_core/hchacha20/core_hchacha20.c" + "${SRC}/crypto_core/hsalsa20/core_hsalsa20.c" + "${SRC}/crypto_core/hsalsa20/ref2/core_hsalsa20_ref2.c" + "${SRC}/crypto_core/salsa/ref/core_salsa_ref.c" + "${SRC}/crypto_generichash/crypto_generichash.c" + "${SRC}/crypto_generichash/blake2b/generichash_blake2.c" + "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-avx2.c" + "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-ref.c" + "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-sse41.c" + "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-ssse3.c" + "${SRC}/crypto_generichash/blake2b/ref/blake2b-ref.c" + "${SRC}/crypto_generichash/blake2b/ref/generichash_blake2b.c" + "${SRC}/crypto_hash/crypto_hash.c" + "${SRC}/crypto_hash/sha256/hash_sha256.c" + "${SRC}/crypto_hash/sha256/cp/hash_sha256_cp.c" + "${SRC}/crypto_hash/sha512/hash_sha512.c" + "${SRC}/crypto_hash/sha512/cp/hash_sha512_cp.c" + "${SRC}/crypto_kdf/crypto_kdf.c" + "${SRC}/crypto_kdf/blake2b/kdf_blake2b.c" + "${SRC}/crypto_kx/crypto_kx.c" + "${SRC}/crypto_onetimeauth/crypto_onetimeauth.c" + "${SRC}/crypto_onetimeauth/poly1305/onetimeauth_poly1305.c" + "${SRC}/crypto_onetimeauth/poly1305/donna/poly1305_donna.c" + "${SRC}/crypto_onetimeauth/poly1305/sse2/poly1305_sse2.c" + "${SRC}/crypto_pwhash/crypto_pwhash.c" + "${SRC}/crypto_pwhash/argon2/argon2-core.c" + "${SRC}/crypto_pwhash/argon2/argon2-encoding.c" + "${SRC}/crypto_pwhash/argon2/argon2-fill-block-ref.c" + "${SRC}/crypto_pwhash/argon2/argon2-fill-block-ssse3.c" + "${SRC}/crypto_pwhash/argon2/argon2.c" + "${SRC}/crypto_pwhash/argon2/blake2b-long.c" + "${SRC}/crypto_pwhash/argon2/pwhash_argon2i.c" + "${SRC}/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt-common.c" + "${SRC}/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.c" + "${SRC}/crypto_pwhash/scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c" + "${SRC}/crypto_pwhash/scryptsalsa208sha256/scrypt_platform.c" + "${SRC}/crypto_pwhash/scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c" + "${SRC}/crypto_pwhash/scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c" + "${SRC}/crypto_scalarmult/crypto_scalarmult.c" + "${SRC}/crypto_scalarmult/curve25519/scalarmult_curve25519.c" + "${SRC}/crypto_scalarmult/curve25519/donna_c64/curve25519_donna_c64.c" + "${SRC}/crypto_scalarmult/curve25519/ref10/x25519_ref10.c" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/consts.S" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/curve25519_sandy2x.c" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_invert.c" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_mul.S" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_nsquare.S" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_pack.S" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe_frombytes_sandy2x.c" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/ladder.S" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/ladder_base.S" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/sandy2x.S" + "${SRC}/crypto_secretbox/crypto_secretbox.c" + "${SRC}/crypto_secretbox/crypto_secretbox_easy.c" + "${SRC}/crypto_secretbox/xchacha20poly1305/secretbox_xchacha20poly1305.c" + "${SRC}/crypto_secretbox/xsalsa20poly1305/secretbox_xsalsa20poly1305.c" + "${SRC}/crypto_shorthash/crypto_shorthash.c" + "${SRC}/crypto_shorthash/siphash24/shorthash_siphash24.c" + "${SRC}/crypto_shorthash/siphash24/shorthash_siphashx24.c" + "${SRC}/crypto_shorthash/siphash24/ref/shorthash_siphash24_ref.c" + "${SRC}/crypto_shorthash/siphash24/ref/shorthash_siphashx24_ref.c" + "${SRC}/crypto_sign/crypto_sign.c" + "${SRC}/crypto_sign/ed25519/sign_ed25519.c" + "${SRC}/crypto_sign/ed25519/ref10/keypair.c" + "${SRC}/crypto_sign/ed25519/ref10/obsolete.c" + "${SRC}/crypto_sign/ed25519/ref10/open.c" + "${SRC}/crypto_sign/ed25519/ref10/sign.c" + "${SRC}/crypto_stream/crypto_stream.c" + "${SRC}/crypto_stream/aes128ctr/stream_aes128ctr.c" + "${SRC}/crypto_stream/aes128ctr/nacl/afternm_aes128ctr.c" + "${SRC}/crypto_stream/aes128ctr/nacl/beforenm_aes128ctr.c" + "${SRC}/crypto_stream/aes128ctr/nacl/consts_aes128ctr.c" + "${SRC}/crypto_stream/aes128ctr/nacl/int128_aes128ctr.c" + "${SRC}/crypto_stream/aes128ctr/nacl/stream_aes128ctr_nacl.c" + "${SRC}/crypto_stream/aes128ctr/nacl/xor_afternm_aes128ctr.c" + "${SRC}/crypto_stream/chacha20/stream_chacha20.c" + "${SRC}/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-avx2.c" + "${SRC}/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-ssse3.c" + "${SRC}/crypto_stream/chacha20/ref/chacha20_ref.c" + "${SRC}/crypto_stream/salsa20/stream_salsa20.c" + "${SRC}/crypto_stream/salsa20/ref/salsa20_ref.c" + "${SRC}/crypto_stream/salsa20/xmm6/salsa20_xmm6-asm.S" + "${SRC}/crypto_stream/salsa20/xmm6/salsa20_xmm6.c" + "${SRC}/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-avx2.c" + "${SRC}/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-sse2.c" + "${SRC}/crypto_stream/salsa2012/stream_salsa2012.c" + "${SRC}/crypto_stream/salsa2012/ref/stream_salsa2012_ref.c" + "${SRC}/crypto_stream/salsa208/stream_salsa208.c" + "${SRC}/crypto_stream/salsa208/ref/stream_salsa208_ref.c" + "${SRC}/crypto_stream/xchacha20/stream_xchacha20.c" + "${SRC}/crypto_stream/xsalsa20/stream_xsalsa20.c" + "${SRC}/crypto_verify/sodium/verify.c" + "${SRC}/randombytes/randombytes.c" + "${SRC}/randombytes/nativeclient/randombytes_nativeclient.c" + "${SRC}/randombytes/salsa20/randombytes_salsa20_random.c" + "${SRC}/randombytes/sysrandom/randombytes_sysrandom.c" + "${SRC}/sodium/core.c" + "${SRC}/sodium/runtime.c" + "${SRC}/sodium/utils.c" + "${SRC}/sodium/version.c" + "port/randombytes_esp32.c") if(CONFIG_LIBSODIUM_USE_MBEDTLS_SHA) - list(APPEND srcs "port/crypto_hash_mbedtls/crypto_hash_sha256_mbedtls.c" - "port/crypto_hash_mbedtls/crypto_hash_sha512_mbedtls.c") + list(APPEND srcs + "port/crypto_hash_mbedtls/crypto_hash_sha256_mbedtls.c" + "port/crypto_hash_mbedtls/crypto_hash_sha512_mbedtls.c") else() - list(APPEND srcs "${SRC}/crypto_hash/sha256/cp/hash_sha256_cp.c" - "${SRC}/crypto_hash/sha512/cp/hash_sha512_cp.c") + list(APPEND srcs + "${SRC}/crypto_hash/sha256/cp/hash_sha256_cp.c" + "${SRC}/crypto_hash/sha512/cp/hash_sha512_cp.c") endif() set(include_dirs ${SRC}/include port_include) diff --git a/components/lwip/CMakeLists.txt b/components/lwip/CMakeLists.txt index 6eda8db37e..cb6a659530 100644 --- a/components/lwip/CMakeLists.txt +++ b/components/lwip/CMakeLists.txt @@ -6,57 +6,93 @@ set(include_dirs port/esp32/include/arch ) -set(srcs "apps/dhcpserver/dhcpserver.c" - "apps/ping/esp_ping.c" - "apps/ping/ping.c" - "apps/sntp/sntp.c" - "lwip/src/api/api_lib.c" - "lwip/src/api/api_msg.c" - "lwip/src/api/err.c" - "lwip/src/api/netbuf.c" - "lwip/src/api/netdb.c" - "lwip/src/api/netifapi.c" - "lwip/src/api/sockets.c" - "lwip/src/api/tcpip.c" - "lwip/src/apps/sntp/sntp.c" - "lwip/src/core/def.c" - "lwip/src/core/dns.c" - "lwip/src/core/inet_chksum.c" - "lwip/src/core/init.c" - "lwip/src/core/ip.c" - "lwip/src/core/mem.c" - "lwip/src/core/memp.c" - "lwip/src/core/netif.c" - "lwip/src/core/pbuf.c" - "lwip/src/core/raw.c" - "lwip/src/core/stats.c" - "lwip/src/core/sys.c" - "lwip/src/core/tcp.c" - "lwip/src/core/tcp_in.c" - "lwip/src/core/tcp_out.c" - "lwip/src/core/timeouts.c" - "lwip/src/core/udp.c" - "lwip/src/core/ipv4/autoip.c" - "lwip/src/core/ipv4/dhcp.c" - "lwip/src/core/ipv4/etharp.c" - "lwip/src/core/ipv4/icmp.c" - "lwip/src/core/ipv4/igmp.c" - "lwip/src/core/ipv4/ip4.c" - "lwip/src/core/ipv4/ip4_addr.c" - "lwip/src/core/ipv4/ip4_frag.c" - "lwip/src/core/ipv6/dhcp6.c" - "lwip/src/core/ipv6/ethip6.c" - "lwip/src/core/ipv6/icmp6.c" - "lwip/src/core/ipv6/inet6.c" - "lwip/src/core/ipv6/ip6.c" - "lwip/src/core/ipv6/ip6_addr.c" - "lwip/src/core/ipv6/ip6_frag.c" - "lwip/src/core/ipv6/mld6.c" - "lwip/src/core/ipv6/nd6.c" - "lwip/src/netif/ethernet.c" - "lwip/src/netif/ethernetif.c" - "lwip/src/netif/lowpan6.c" - "lwip/src/netif/slipif.c" +set(srcs + "apps/dhcpserver/dhcpserver.c" + "apps/ping/esp_ping.c" + "apps/ping/ping.c" + "apps/sntp/sntp.c" + "lwip/src/api/api_lib.c" + "lwip/src/api/api_msg.c" + "lwip/src/api/err.c" + "lwip/src/api/netbuf.c" + "lwip/src/api/netdb.c" + "lwip/src/api/netifapi.c" + "lwip/src/api/sockets.c" + "lwip/src/api/tcpip.c" + "lwip/src/apps/sntp/sntp.c" + "lwip/src/core/def.c" + "lwip/src/core/dns.c" + "lwip/src/core/inet_chksum.c" + "lwip/src/core/init.c" + "lwip/src/core/ip.c" + "lwip/src/core/mem.c" + "lwip/src/core/memp.c" + "lwip/src/core/netif.c" + "lwip/src/core/pbuf.c" + "lwip/src/core/raw.c" + "lwip/src/core/stats.c" + "lwip/src/core/sys.c" + "lwip/src/core/tcp.c" + "lwip/src/core/tcp_in.c" + "lwip/src/core/tcp_out.c" + "lwip/src/core/timeouts.c" + "lwip/src/core/udp.c" + "lwip/src/core/ipv4/autoip.c" + "lwip/src/core/ipv4/dhcp.c" + "lwip/src/core/ipv4/etharp.c" + "lwip/src/core/ipv4/icmp.c" + "lwip/src/core/ipv4/igmp.c" + "lwip/src/core/ipv4/ip4.c" + "lwip/src/core/ipv4/ip4_addr.c" + "lwip/src/core/ipv4/ip4_frag.c" + "lwip/src/core/ipv6/dhcp6.c" + "lwip/src/core/ipv6/ethip6.c" + "lwip/src/core/ipv6/icmp6.c" + "lwip/src/core/ipv6/inet6.c" + "lwip/src/core/ipv6/ip6.c" + "lwip/src/core/ipv6/ip6_addr.c" + "lwip/src/core/ipv6/ip6_frag.c" + "lwip/src/core/ipv6/mld6.c" + "lwip/src/core/ipv6/nd6.c" + "lwip/src/netif/ethernet.c" + "lwip/src/netif/ethernetif.c" + "lwip/src/netif/lowpan6.c" + "lwip/src/netif/slipif.c" + "lwip/src/netif/ppp/auth.c" + "lwip/src/netif/ppp/ccp.c" + "lwip/src/netif/ppp/chap-md5.c" + "lwip/src/netif/ppp/chap-new.c" + "lwip/src/netif/ppp/chap_ms.c" + "lwip/src/netif/ppp/demand.c" + "lwip/src/netif/ppp/eap.c" + "lwip/src/netif/ppp/ecp.c" + "lwip/src/netif/ppp/eui64.c" + "lwip/src/netif/ppp/fsm.c" + "lwip/src/netif/ppp/ipcp.c" + "lwip/src/netif/ppp/ipv6cp.c" + "lwip/src/netif/ppp/lcp.c" + "lwip/src/netif/ppp/magic.c" + "lwip/src/netif/ppp/mppe.c" + "lwip/src/netif/ppp/multilink.c" + "lwip/src/netif/ppp/ppp.c" + "lwip/src/netif/ppp/pppapi.c" + "lwip/src/netif/ppp/pppcrypt.c" + "lwip/src/netif/ppp/pppoe.c" + "lwip/src/netif/ppp/pppol2tp.c" + "lwip/src/netif/ppp/pppos.c" + "lwip/src/netif/ppp/upap.c" + "lwip/src/netif/ppp/utils.c" + "lwip/src/netif/ppp/vj.c" + "port/esp32/vfs_lwip.c" + "port/esp32/debug/lwip_debug.c" + "port/esp32/freertos/sys_arch.c" + "port/esp32/netif/dhcp_state.c" + "port/esp32/netif/ethernetif.c" + "port/esp32/netif/nettestif.c" + "port/esp32/netif/wlanif.c") + +if(CONFIG_LWIP_PPP_SUPPORT) + list(APPEND srcs "lwip/src/netif/ppp/auth.c" "lwip/src/netif/ppp/ccp.c" "lwip/src/netif/ppp/chap-md5.c" @@ -82,45 +118,11 @@ set(srcs "apps/dhcpserver/dhcpserver.c" "lwip/src/netif/ppp/upap.c" "lwip/src/netif/ppp/utils.c" "lwip/src/netif/ppp/vj.c" - "port/esp32/vfs_lwip.c" - "port/esp32/debug/lwip_debug.c" - "port/esp32/freertos/sys_arch.c" - "port/esp32/netif/dhcp_state.c" - "port/esp32/netif/ethernetif.c" - "port/esp32/netif/nettestif.c" - "port/esp32/netif/wlanif.c") - -if(CONFIG_LWIP_PPP_SUPPORT) - list(APPEND srcs "lwip/src/netif/ppp/auth.c" - "lwip/src/netif/ppp/ccp.c" - "lwip/src/netif/ppp/chap-md5.c" - "lwip/src/netif/ppp/chap-new.c" - "lwip/src/netif/ppp/chap_ms.c" - "lwip/src/netif/ppp/demand.c" - "lwip/src/netif/ppp/eap.c" - "lwip/src/netif/ppp/ecp.c" - "lwip/src/netif/ppp/eui64.c" - "lwip/src/netif/ppp/fsm.c" - "lwip/src/netif/ppp/ipcp.c" - "lwip/src/netif/ppp/ipv6cp.c" - "lwip/src/netif/ppp/lcp.c" - "lwip/src/netif/ppp/magic.c" - "lwip/src/netif/ppp/mppe.c" - "lwip/src/netif/ppp/multilink.c" - "lwip/src/netif/ppp/ppp.c" - "lwip/src/netif/ppp/pppapi.c" - "lwip/src/netif/ppp/pppcrypt.c" - "lwip/src/netif/ppp/pppoe.c" - "lwip/src/netif/ppp/pppol2tp.c" - "lwip/src/netif/ppp/pppos.c" - "lwip/src/netif/ppp/upap.c" - "lwip/src/netif/ppp/utils.c" - "lwip/src/netif/ppp/vj.c" - "lwip/src/netif/ppp/polarssl/arc4.c" - "lwip/src/netif/ppp/polarssl/des.c" - "lwip/src/netif/ppp/polarssl/md4.c" - "lwip/src/netif/ppp/polarssl/md5.c" - "lwip/src/netif/ppp/polarssl/sha1.c") + "lwip/src/netif/ppp/polarssl/arc4.c" + "lwip/src/netif/ppp/polarssl/des.c" + "lwip/src/netif/ppp/polarssl/md4.c" + "lwip/src/netif/ppp/polarssl/md5.c" + "lwip/src/netif/ppp/polarssl/sha1.c") endif() idf_component_register(SRCS "${srcs}" diff --git a/components/newlib/CMakeLists.txt b/components/newlib/CMakeLists.txt index 97a6d773b7..47b7c368b3 100644 --- a/components/newlib/CMakeLists.txt +++ b/components/newlib/CMakeLists.txt @@ -1,4 +1,5 @@ -set(srcs "heap.c" +set(srcs + "heap.c" "locks.c" "poll.c" "pthread.c" diff --git a/components/nghttp/CMakeLists.txt b/components/nghttp/CMakeLists.txt index 32bd379eda..1c9ba17a23 100644 --- a/components/nghttp/CMakeLists.txt +++ b/components/nghttp/CMakeLists.txt @@ -1,26 +1,27 @@ -set(srcs "nghttp2/lib/nghttp2_buf.c" - "nghttp2/lib/nghttp2_callbacks.c" - "nghttp2/lib/nghttp2_debug.c" - "nghttp2/lib/nghttp2_frame.c" - "nghttp2/lib/nghttp2_hd.c" - "nghttp2/lib/nghttp2_hd_huffman.c" - "nghttp2/lib/nghttp2_hd_huffman_data.c" - "nghttp2/lib/nghttp2_helper.c" - "nghttp2/lib/nghttp2_http.c" - "nghttp2/lib/nghttp2_map.c" - "nghttp2/lib/nghttp2_mem.c" - "nghttp2/lib/nghttp2_npn.c" - "nghttp2/lib/nghttp2_option.c" - "nghttp2/lib/nghttp2_outbound_item.c" - "nghttp2/lib/nghttp2_pq.c" - "nghttp2/lib/nghttp2_priority_spec.c" - "nghttp2/lib/nghttp2_queue.c" - "nghttp2/lib/nghttp2_rcbuf.c" - "nghttp2/lib/nghttp2_session.c" - "nghttp2/lib/nghttp2_stream.c" - "nghttp2/lib/nghttp2_submit.c" - "nghttp2/lib/nghttp2_version.c" - "port/http_parser.c") +set(srcs + "nghttp2/lib/nghttp2_buf.c" + "nghttp2/lib/nghttp2_callbacks.c" + "nghttp2/lib/nghttp2_debug.c" + "nghttp2/lib/nghttp2_frame.c" + "nghttp2/lib/nghttp2_hd.c" + "nghttp2/lib/nghttp2_hd_huffman.c" + "nghttp2/lib/nghttp2_hd_huffman_data.c" + "nghttp2/lib/nghttp2_helper.c" + "nghttp2/lib/nghttp2_http.c" + "nghttp2/lib/nghttp2_map.c" + "nghttp2/lib/nghttp2_mem.c" + "nghttp2/lib/nghttp2_npn.c" + "nghttp2/lib/nghttp2_option.c" + "nghttp2/lib/nghttp2_outbound_item.c" + "nghttp2/lib/nghttp2_pq.c" + "nghttp2/lib/nghttp2_priority_spec.c" + "nghttp2/lib/nghttp2_queue.c" + "nghttp2/lib/nghttp2_rcbuf.c" + "nghttp2/lib/nghttp2_session.c" + "nghttp2/lib/nghttp2_stream.c" + "nghttp2/lib/nghttp2_submit.c" + "nghttp2/lib/nghttp2_version.c" + "port/http_parser.c") idf_component_register(SRCS "${srcs}" INCLUDE_DIRS port/include nghttp2/lib/includes) diff --git a/components/protocomm/CMakeLists.txt b/components/protocomm/CMakeLists.txt index 22bb08254c..334e279145 100644 --- a/components/protocomm/CMakeLists.txt +++ b/components/protocomm/CMakeLists.txt @@ -2,15 +2,16 @@ set(include_dirs include/common include/security include/transports) set(priv_include_dirs proto-c src/common src/simple_ble) -set(srcs "src/common/protocomm.c" - "src/security/security0.c" - "src/security/security1.c" - "proto-c/constants.pb-c.c" - "proto-c/sec0.pb-c.c" - "proto-c/sec1.pb-c.c" - "proto-c/session.pb-c.c" - "src/transports/protocomm_console.c" - "src/transports/protocomm_httpd.c") +set(srcs + "src/common/protocomm.c" + "src/security/security0.c" + "src/security/security1.c" + "proto-c/constants.pb-c.c" + "proto-c/sec0.pb-c.c" + "proto-c/sec1.pb-c.c" + "proto-c/session.pb-c.c" + "src/transports/protocomm_console.c" + "src/transports/protocomm_httpd.c") if(CONFIG_BT_ENABLED) if(CONFIG_BT_BLUEDROID_ENABLED) diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index 0a2b29b00e..11bbbd0d4c 100644 --- a/components/soc/CMakeLists.txt +++ b/components/soc/CMakeLists.txt @@ -9,15 +9,16 @@ if(EXISTS "${COMPONENT_DIR}/${soc_name}") endif() list(APPEND include_dirs include) -list(APPEND srcs "src/memory_layout_utils.c" - "src/lldesc.c" - "src/hal/spi_hal.c" - "src/hal/spi_hal_iram.c" - "src/hal/spi_slave_hal.c" - "src/hal/spi_slave_hal_iram.c" - "src/soc_include_legacy_warn.c" - "src/hal/spi_flash_hal.c" - "src/hal/spi_flash_hal_iram.c" +list(APPEND srcs + "src/memory_layout_utils.c" + "src/lldesc.c" + "src/hal/spi_hal.c" + "src/hal/spi_hal_iram.c" + "src/hal/spi_slave_hal.c" + "src/hal/spi_slave_hal_iram.c" + "src/soc_include_legacy_warn.c" + "src/hal/spi_flash_hal.c" + "src/hal/spi_flash_hal_iram.c" ) idf_component_register(SRCS "${srcs}" diff --git a/components/spi_flash/CMakeLists.txt b/components/spi_flash/CMakeLists.txt index 4a0dd4ecc4..51bec183a7 100644 --- a/components/spi_flash/CMakeLists.txt +++ b/components/spi_flash/CMakeLists.txt @@ -4,18 +4,18 @@ if(BOOTLOADER_BUILD) # need other parts of this component set(srcs "spi_flash_rom_patch.c") else() - set(srcs "cache_utils.c" - "flash_mmap.c" - "flash_ops.c" - "partition.c" - "spi_flash_rom_patch.c" - "spi_flash_chip_drivers.c" - "spi_flash_chip_generic.c" - "spi_flash_chip_issi.c" - "spi_flash_os_func_app.c" - "spi_flash_os_func_noos.c" - "memspi_host_driver.c" - ) + set(srcs + "cache_utils.c" + "flash_mmap.c" + "flash_ops.c" + "partition.c" + "spi_flash_rom_patch.c" + "spi_flash_chip_drivers.c" + "spi_flash_chip_generic.c" + "spi_flash_chip_issi.c" + "spi_flash_os_func_app.c" + "spi_flash_os_func_noos.c" + "memspi_host_driver.c") if(NOT CONFIG_SPI_FLASH_USE_LEGACY_IMPL) list(APPEND srcs "esp_flash_api.c") endif() diff --git a/components/unity/CMakeLists.txt b/components/unity/CMakeLists.txt index a82d037c0c..d98b05d8df 100644 --- a/components/unity/CMakeLists.txt +++ b/components/unity/CMakeLists.txt @@ -1,5 +1,6 @@ -set(srcs "unity/src/unity.c" - "unity_port_esp32.c") +set(srcs + "unity/src/unity.c" + "unity_port_esp32.c") if(CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL) list(APPEND COMPONENT_PRIV_INCLUDEDIRS "include/priv") diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index 78ce6573aa..7389e1da6c 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -1,77 +1,78 @@ -set(srcs "port/os_xtensa.c" - "src/crypto/aes-cbc.c" - "src/crypto/aes-internal-dec.c" - "src/crypto/aes-internal-enc.c" - "src/crypto/aes-internal.c" - "src/crypto/aes-unwrap.c" - "src/crypto/aes-wrap.c" - "src/crypto/bignum.c" - "src/crypto/crypto_mbedtls.c" - "src/crypto/crypto_internal-cipher.c" - "src/crypto/crypto_internal-modexp.c" - "src/crypto/crypto_internal-rsa.c" - "src/crypto/crypto_internal.c" - "src/crypto/des-internal.c" - "src/crypto/dh_group5.c" - "src/crypto/dh_groups.c" - "src/crypto/md4-internal.c" - "src/crypto/md5-internal.c" - "src/crypto/md5.c" - "src/crypto/ms_funcs.c" - "src/crypto/rc4.c" - "src/crypto/sha1-internal.c" - "src/crypto/sha1-pbkdf2.c" - "src/crypto/sha1.c" - "src/crypto/sha256-internal.c" - "src/crypto/sha256.c" - "src/fast_crypto/fast_aes-cbc.c" - "src/fast_crypto/fast_aes-unwrap.c" - "src/fast_crypto/fast_aes-wrap.c" - "src/fast_crypto/fast_crypto_internal-cipher.c" - "src/fast_crypto/fast_crypto_internal-modexp.c" - "src/fast_crypto/fast_crypto_internal.c" - "src/fast_crypto/fast_sha256-internal.c" - "src/fast_crypto/fast_sha256.c" - "src/wpa2/eap_peer/chap.c" - "src/wpa2/eap_peer/eap.c" - "src/wpa2/eap_peer/eap_common.c" - "src/wpa2/eap_peer/eap_mschapv2.c" - "src/wpa2/eap_peer/eap_peap.c" - "src/wpa2/eap_peer/eap_peap_common.c" - "src/wpa2/eap_peer/eap_tls.c" - "src/wpa2/eap_peer/eap_tls_common.c" - "src/wpa2/eap_peer/eap_ttls.c" - "src/wpa2/eap_peer/mschapv2.c" - "src/wpa2/tls/asn1.c" - "src/wpa2/tls/bignum.c" - "src/wpa2/tls/pkcs1.c" - "src/wpa2/tls/pkcs5.c" - "src/wpa2/tls/pkcs8.c" - "src/wpa2/tls/rsa.c" - "src/wpa2/tls/tls_internal.c" - "src/wpa2/tls/tlsv1_client.c" - "src/wpa2/tls/tlsv1_client_read.c" - "src/wpa2/tls/tlsv1_client_write.c" - "src/wpa2/tls/tlsv1_common.c" - "src/wpa2/tls/tlsv1_cred.c" - "src/wpa2/tls/tlsv1_record.c" - "src/wpa2/tls/tlsv1_server.c" - "src/wpa2/tls/tlsv1_server_read.c" - "src/wpa2/tls/tlsv1_server_write.c" - "src/wpa2/tls/x509v3.c" - "src/wpa2/utils/base64.c" - "src/wpa2/utils/ext_password.c" - "src/wps/eap_common.c" - "src/wps/uuid.c" - "src/wps/wps.c" - "src/wps/wps_attr_build.c" - "src/wps/wps_attr_parse.c" - "src/wps/wps_attr_process.c" - "src/wps/wps_common.c" - "src/wps/wps_dev_attr.c" - "src/wps/wps_enrollee.c" - "src/wps/wps_registrar.c" - "src/wps/wps_validate.c") +set(srcs + "port/os_xtensa.c" + "src/crypto/aes-cbc.c" + "src/crypto/aes-internal-dec.c" + "src/crypto/aes-internal-enc.c" + "src/crypto/aes-internal.c" + "src/crypto/aes-unwrap.c" + "src/crypto/aes-wrap.c" + "src/crypto/bignum.c" + "src/crypto/crypto_mbedtls.c" + "src/crypto/crypto_internal-cipher.c" + "src/crypto/crypto_internal-modexp.c" + "src/crypto/crypto_internal-rsa.c" + "src/crypto/crypto_internal.c" + "src/crypto/des-internal.c" + "src/crypto/dh_group5.c" + "src/crypto/dh_groups.c" + "src/crypto/md4-internal.c" + "src/crypto/md5-internal.c" + "src/crypto/md5.c" + "src/crypto/ms_funcs.c" + "src/crypto/rc4.c" + "src/crypto/sha1-internal.c" + "src/crypto/sha1-pbkdf2.c" + "src/crypto/sha1.c" + "src/crypto/sha256-internal.c" + "src/crypto/sha256.c" + "src/fast_crypto/fast_aes-cbc.c" + "src/fast_crypto/fast_aes-unwrap.c" + "src/fast_crypto/fast_aes-wrap.c" + "src/fast_crypto/fast_crypto_internal-cipher.c" + "src/fast_crypto/fast_crypto_internal-modexp.c" + "src/fast_crypto/fast_crypto_internal.c" + "src/fast_crypto/fast_sha256-internal.c" + "src/fast_crypto/fast_sha256.c" + "src/wpa2/eap_peer/chap.c" + "src/wpa2/eap_peer/eap.c" + "src/wpa2/eap_peer/eap_common.c" + "src/wpa2/eap_peer/eap_mschapv2.c" + "src/wpa2/eap_peer/eap_peap.c" + "src/wpa2/eap_peer/eap_peap_common.c" + "src/wpa2/eap_peer/eap_tls.c" + "src/wpa2/eap_peer/eap_tls_common.c" + "src/wpa2/eap_peer/eap_ttls.c" + "src/wpa2/eap_peer/mschapv2.c" + "src/wpa2/tls/asn1.c" + "src/wpa2/tls/bignum.c" + "src/wpa2/tls/pkcs1.c" + "src/wpa2/tls/pkcs5.c" + "src/wpa2/tls/pkcs8.c" + "src/wpa2/tls/rsa.c" + "src/wpa2/tls/tls_internal.c" + "src/wpa2/tls/tlsv1_client.c" + "src/wpa2/tls/tlsv1_client_read.c" + "src/wpa2/tls/tlsv1_client_write.c" + "src/wpa2/tls/tlsv1_common.c" + "src/wpa2/tls/tlsv1_cred.c" + "src/wpa2/tls/tlsv1_record.c" + "src/wpa2/tls/tlsv1_server.c" + "src/wpa2/tls/tlsv1_server_read.c" + "src/wpa2/tls/tlsv1_server_write.c" + "src/wpa2/tls/x509v3.c" + "src/wpa2/utils/base64.c" + "src/wpa2/utils/ext_password.c" + "src/wps/eap_common.c" + "src/wps/uuid.c" + "src/wps/wps.c" + "src/wps/wps_attr_build.c" + "src/wps/wps_attr_parse.c" + "src/wps/wps_attr_process.c" + "src/wps/wps_common.c" + "src/wps/wps_dev_attr.c" + "src/wps/wps_enrollee.c" + "src/wps/wps_registrar.c" + "src/wps/wps_validate.c") idf_component_register(SRCS "${srcs}" INCLUDE_DIRS include port/include diff --git a/components/xtensa/CMakeLists.txt b/components/xtensa/CMakeLists.txt index 08a1ccf64c..0ab1dd018d 100644 --- a/components/xtensa/CMakeLists.txt +++ b/components/xtensa/CMakeLists.txt @@ -1,5 +1,8 @@ idf_build_get_property(target IDF_TARGET) -idf_component_register(SRCS "eri.c" "trax.c" "debug_helpers.c" "debug_helpers_asm.S" +idf_component_register(SRCS "debug_helpers.c" + "debug_helpers_asm.S" + "eri.c" + "trax.c" INCLUDE_DIRS include ${target}/include LDFRAGMENTS linker.lf PRIV_REQUIRES soc) From 1096ee4b57a8ac0f41241120374119631649a3f7 Mon Sep 17 00:00:00 2001 From: Kirill Chalov Date: Fri, 21 Jun 2019 20:43:17 +0800 Subject: [PATCH 115/486] Review the file api-reference/peripherals/touch_pad.rst --- .../api-reference/peripherals/touch_pad.rst | 74 ++++++++++--------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/docs/en/api-reference/peripherals/touch_pad.rst b/docs/en/api-reference/peripherals/touch_pad.rst index daf15c46f3..6d4c2f8ac6 100644 --- a/docs/en/api-reference/peripherals/touch_pad.rst +++ b/docs/en/api-reference/peripherals/touch_pad.rst @@ -4,19 +4,19 @@ Touch Sensor Introduction ------------ -A touch-sensor system is built on a substrate which carries electrodes and relevant connections under a protective flat surface. When a user touches the surface, the capacitance variation is triggered and a binary signal is generated to indicate whether the touch is valid. +A touch sensor system is built on a substrate which carries electrodes and relevant connections under a protective flat surface. When a user touches the surface, the capacitance variation is used to evaluate if the touch was valid. -ESP32 can provide up to 10 capacitive touch pads / GPIOs. The sensing pads can be arranged in different combinations (e.g. matrix, slider), so that a larger area or more points can be detected. The touch pad sensing process is under the control of a hardware-implemented finite-state machine (FSM) which is initiated by software or a dedicated hardware timer. +ESP32 can handle up to 10 capacitive touch pads / GPIOs. The sensing pads can be arranged in different combinations (e.g., matrix, slider), so that a larger area or more points can be detected. The touch pad sensing process is under the control of a hardware-implemented finite-state machine (FSM) which is initiated by software or a dedicated hardware timer. -Design, operation and control registers of touch sensor are discussed in `ESP32 Technical Reference Manual `_ (PDF). Please refer to it for additional details how this subsystem works. +Design, operation, and control registers of a touch sensor are discussed in `ESP32 Technical Reference Manual `_ (PDF). Please refer to this manual for additional details on how this subsystem works. -In depth details of design of touch sensors and firmware development guidelines for the ESP32 are available in `Touch Sensor Application Note `_. If you would like to test touch sensors in various configurations without building them on your own, check `Guide for ESP32-Sense Development Kit `_. +In-depth design details of touch sensors and firmware development guidelines for ESP32 are available in `Touch Sensor Application Note `_. If you want to test touch sensors in various configurations without building them on your own, check the `Guide for ESP32-Sense Development Kit `_. Functionality Overview ---------------------- -Description of API is broken down into groups of functions to provide quick overview of features like: +Description of API is broken down into groups of functions to provide a quick overview of the following features: - Initialization of touch pad driver - Configuration of touch pad GPIO pins @@ -25,118 +25,120 @@ Description of API is broken down into groups of functions to provide quick over - Filtering measurements - Touch detection methods - Setting up interrupts to report touch detection -- Waking up from sleep mode on interrupt +- Waking up from Sleep mode on interrupt -For detailed description of particular function please go to section :ref:`touch_pad-api-reference`. Practical implementation of this API is covered in section :ref:`touch_pad-api-examples`. +For detailed description of a particular function, please go to Section :ref:`touch_pad-api-reference`. Practical implementation of this API is covered in Section :ref:`touch_pad-api-examples`. Initialization ^^^^^^^^^^^^^^ -Touch pad driver should be initialized before use by calling function :cpp:func:`touch_pad_init`. This function sets several ``.._DEFAULT`` driver parameters listed in :ref:`touch_pad-api-reference` under "Macros". It also clears information what pads have been touched before (if any) and disables interrupts. +Before using a touch pad, you need to initialize the touch pad driver by calling the function :cpp:func:`touch_pad_init`. This function sets several ``.._DEFAULT`` driver parameters listed in :ref:`touch_pad-api-reference` under *Macros*. It also removes the information about which pads have been touched before, if any, and disables interrupts. -If not required anymore, driver can be disabled by calling :cpp:func:`touch_pad_deinit`. +If the driver is not required anymore, deinitialize it by calling :cpp:func:`touch_pad_deinit`. Configuration ^^^^^^^^^^^^^ -Enabling of touch sensor functionality for particular GPIO is done with :cpp:func:`touch_pad_config`. +Enabling the touch sensor functionality for a particular GPIO is done with :cpp:func:`touch_pad_config`. -The function :cpp:func:`touch_pad_set_fsm_mode` is used to select whether touch pad measurement (operated by FSM) is started automatically by hardware timer, or by software. If software mode is selected, then use :cpp:func:`touch_pad_sw_start` to start of the FSM. +Use the function :cpp:func:`touch_pad_set_fsm_mode` to select if touch pad measurement (operated by FSM) should be started automatically by a hardware timer, or by software. If software mode is selected, use :cpp:func:`touch_pad_sw_start` to start the FSM. Touch State Measurements ^^^^^^^^^^^^^^^^^^^^^^^^ -The following two functions come handy to read raw or filtered measurements from the sensor: +The following two functions come in handy to read raw or filtered measurements from the sensor: * :cpp:func:`touch_pad_read` * :cpp:func:`touch_pad_read_filtered` -They may be used to characterize particular touch pad design by checking the range of sensor readings when a pad is touched or released. This information can be then used to establish the touch threshold. +They can also be used, for example, to evaluate a particular touch pad design by checking the range of sensor readings when a pad is touched or released. This information can be then used to establish a touch threshold. .. note:: - Start and configure filter before using :cpp:func:`touch_pad_read_filtered` by calling specific filter functions described down below. + Before using :cpp:func:`touch_pad_read_filtered`, you need to initialize and configure the filter by calling specific filter functions described in Section `Filtering of Measurements`_. -To see how to use both read functions check :example:`peripherals/touch_pad_read` application example. +For the demonstration of how to use both read functions, check the application example :example:`peripherals/touch_pad_read`. Optimization of Measurements ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Touch sensor has several configurable parameters to match characteristics of particular touch pad design. For instance, to sense smaller capacity changes, it is possible to narrow the reference voltage range within which the touch pads are charged / discharged. The high and low reference voltages are set using function :cpp:func:`touch_pad_set_voltage`. A positive side effect, besides ability to discern smaller capacity changes, will be reduction of power consumption for low power applications. A likely negative effect will be increase of measurement noise. If dynamic rage of obtained readings is still satisfactory, then further reduction of power consumption may be done by lowering the measurement time with :cpp:func:`touch_pad_set_meas_time`. +A touch sensor has several configurable parameters to match the characteristics of a particular touch pad design. For instance, to sense smaller capacity changes, it is possible to narrow down the reference voltage range within which the touch pads are charged / discharged. The high and low reference voltages are set using the function :cpp:func:`touch_pad_set_voltage`. -The following summarizes available measurement parameters and corresponding 'set' functions: +Besides the ability to discern smaller capacity changes, a positive side effect is reduction of power consumption for low power applications. A likely negative effect is an increase in measurement noise. If the dynamic range of obtained readings is still satisfactory, then further reduction of power consumption might be done by reducing the measurement time with :cpp:func:`touch_pad_set_meas_time`. + +The following list summarizes available measurement parameters and corresponding 'set' functions: * Touch pad charge / discharge parameters: * voltage range: :cpp:func:`touch_pad_set_voltage` * speed (slope): :cpp:func:`touch_pad_set_cnt_mode` -* Measure time: :cpp:func:`touch_pad_set_meas_time` +* Measurement time: :cpp:func:`touch_pad_set_meas_time` -Relationship between voltage range (high / low reference voltages), speed (slope) and measure time is shown on figure below. +Relationship between the voltage range (high / low reference voltages), speed (slope), and measurement time is shown in the figure below. .. figure:: ../../../_static/touch_pad-measurement-parameters.jpg :align: center :alt: Touch Pad - relationship between measurement parameters :figclass: align-center - Touch Pad - relationship between measurement parameters + Touch pad - relationship between measurement parameters -The last chart "Output" represents the touch sensor reading, i.e. the count of pulses collected within measure time. +The last chart *Output* represents the touch sensor reading, i.e., the count of pulses collected within the measurement time. -All functions are provided in pairs to 'set' specific parameter and to 'get' the current parameter's value, e.g. :cpp:func:`touch_pad_set_voltage` and :cpp:func:`touch_pad_get_voltage`. +All functions are provided in pairs to *set* a specific parameter and to *get* the current parameter's value, e.g., :cpp:func:`touch_pad_set_voltage` and :cpp:func:`touch_pad_get_voltage`. .. _touch_pad-api-filtering-of-measurements: Filtering of Measurements ^^^^^^^^^^^^^^^^^^^^^^^^^ -If measurements are noisy, you may filter them with provided API. The filter should be started before first use by calling :cpp:func:`touch_pad_filter_start`. +If measurements are noisy, you can filter them with provided API functions. Before using the filter, please start it by calling :cpp:func:`touch_pad_filter_start`. -The filter type is IIR (Infinite Impulse Response) and it has configurable period that can be set with function :cpp:func:`touch_pad_set_filter_period`. +The filter type is IIR (infinite impulse response), and it has a configurable period that can be set with the function :cpp:func:`touch_pad_set_filter_period`. -You can stop the filter with :cpp:func:`touch_pad_filter_stop`. If not required anymore, the filter may be deleted by invoking :cpp:func:`touch_pad_filter_delete`. +You can stop the filter with :cpp:func:`touch_pad_filter_stop`. If not required anymore, the filter can be deleted by invoking :cpp:func:`touch_pad_filter_delete`. Touch Detection ^^^^^^^^^^^^^^^ -Touch detection is implemented in ESP32's hardware basing on user configured threshold and raw measurements executed by FSM. Use function :cpp:func:`touch_pad_get_status` to check what pads have been touched and :cpp:func:`touch_pad_clear_status` to clear the touch status information. +Touch detection is implemented in ESP32's hardware based on the user-configured threshold and raw measurements executed by FSM. Use the functions :cpp:func:`touch_pad_get_status` to check which pads have been touched and :cpp:func:`touch_pad_clear_status` to clear the touch status information. -Hardware touch detection may be also wired to interrupts and this is described in next section. +Hardware touch detection can also be wired to interrupts. This is described in the next section. -If measurements are noisy and capacity changes small, then hardware touch detection may be not reliable. To resolve this issue, instead of using hardware detection / provided interrupts, implement measurement filtering and perform touch detection in your own application. See :example:`peripherals/touch_pad_interrupt` for sample implementation of both methods of touch detection. +If measurements are noisy and capacity changes are small, hardware touch detection might be unreliable. To resolve this issue, instead of using hardware detection / provided interrupts, implement measurement filtering and perform touch detection in your own application. For sample implementation of both methods of touch detection, see :example:`peripherals/touch_pad_interrupt`. Touch Triggered Interrupts ^^^^^^^^^^^^^^^^^^^^^^^^^^ -Before enabling an interrupt on touch detection, user should establish touch detection threshold. Use functions described above to read and display sensor measurements when pad is touched and released. Apply a filter when measurements are noisy and relative changes are small. Depending on your application and environmental conditions, test the influence of temperature and power supply voltage changes on measured values. +Before enabling an interrupt on a touch detection, you should establish a touch detection threshold. Use the functions described in `Touch State Measurements`_ to read and display sensor measurements when a pad is touched and released. Apply a filter if measurements are noisy and relative capacity changes are small. Depending on your application and environment conditions, test the influence of temperature and power supply voltage changes on measured values. -Once detection threshold is established, it may be set on initialization with :cpp:func:`touch_pad_config` or at the runtime with :cpp:func:`touch_pad_set_thresh`. +Once a detection threshold is established, it can be set during initialization with :cpp:func:`touch_pad_config` or at the runtime with :cpp:func:`touch_pad_set_thresh`. -In next step configure how interrupts are triggered. They may be triggered below or above threshold and this is set with function :cpp:func:`touch_pad_set_trigger_mode`. +In the next step, configure how interrupts are triggered. They can be triggered below or above the threshold, which is set with the function :cpp:func:`touch_pad_set_trigger_mode`. -Finally configure and manage interrupt calls using the following functions: +Finally, configure and manage interrupt calls using the following functions: * :cpp:func:`touch_pad_isr_register` / :cpp:func:`touch_pad_isr_deregister` * :cpp:func:`touch_pad_intr_enable` / :cpp:func:`touch_pad_intr_disable` -When interrupts are operational, you can obtain information what particular pad triggered interrupt by invoking :cpp:func:`touch_pad_get_status` and clear pad status with :cpp:func:`touch_pad_clear_status`. +When interrupts are operational, you can obtain the information from which particular pad an interrupt came by invoking :cpp:func:`touch_pad_get_status` and clear the pad status with :cpp:func:`touch_pad_clear_status`. .. note:: - Interrupts on touch detection operate on raw / unfiltered measurements checked against user established threshold and are implemented in hardware. Enabling software filtering API (see :ref:`touch_pad-api-filtering-of-measurements`) does not affect this process. + Interrupts on touch detection operate on raw / unfiltered measurements checked against user established threshold and are implemented in hardware. Enabling the software filtering API (see :ref:`touch_pad-api-filtering-of-measurements`) does not affect this process. Wakeup from Sleep Mode ^^^^^^^^^^^^^^^^^^^^^^ -If touch pad interrupts are used to wakeup the chip from a sleep mode, then user can select certain configuration of pads (SET1 or both SET1 and SET2), that should be touched to trigger the interrupt and cause subsequent wakeup. To do so, use function :cpp:func:`touch_pad_set_trigger_source`. +If touch pad interrupts are used to wake up the chip from a sleep mode, you can select a certain configuration of pads (SET1 or both SET1 and SET2) that should be touched to trigger the interrupt and cause the subsequent wakeup. To do so, use the function :cpp:func:`touch_pad_set_trigger_source`. Configuration of required bit patterns of pads may be managed for each 'SET' with: @@ -162,7 +164,7 @@ API Reference GPIO Lookup Macros ^^^^^^^^^^^^^^^^^^ -Some useful macros can be used to specified the GPIO number of a touchpad channel, or vice versa. +Some useful macros can be used to specified the GPIO number of a touch pad channel, or vice versa. e.g. 1. ``TOUCH_PAD_NUM5_GPIO_NUM`` is the GPIO number of channel 5 (12); From 752c7c32d460a92903adb50a60b33db729bfc28a Mon Sep 17 00:00:00 2001 From: Kirill Chalov Date: Mon, 24 Jun 2019 08:22:43 +0800 Subject: [PATCH 116/486] Review the file hw-reference/modules-and-boards.rst --- docs/en/hw-reference/modules-and-boards.rst | 182 +++++++++++++------- 1 file changed, 120 insertions(+), 62 deletions(-) diff --git a/docs/en/hw-reference/modules-and-boards.rst b/docs/en/hw-reference/modules-and-boards.rst index ecc9666c14..ddc41a7353 100644 --- a/docs/en/hw-reference/modules-and-boards.rst +++ b/docs/en/hw-reference/modules-and-boards.rst @@ -4,42 +4,44 @@ ESP32 Modules and Boards ************************ -Espressif designed and manufactured several development modules and boards to help users evaluate functionality of the ESP32 family of chips. Development boards, depending on intended functionality, have exposed GPIO pins headers, provide USB programming interface, JTAG interface as well as peripherals like touch pads, LCD screen, SD card slot, camera module header, etc. +Espressif designs and manufactures different modules and development boards to help users evaluate the potential of the ESP32 family of chips. -For details please refer to documentation below, provided together with description of particular boards. +This document provides description of modules and development boards currently available from Espressif. .. note:: - This section describes the latest versions of boards. Previous versions of boards, including these not produced anymore, are described in section :ref:`esp-modules-and-boards-previous`. + For description of previous versions of modules and development boards as well as for description of discontinued ones, please go to Section :ref:`esp-modules-and-boards-previous`. .. _esp-wroom-solo-wrover-modules: -WROOM, SOLO and WROVER Modules -============================== +WROOM, SOLO, WROVER, and PICO Modules +===================================== -A family of small modules that contain ESP32 chip on board together with some key components including a crystal oscillator and an antenna matching circuit. This makes it easier to provide an ESP32 based solution ready to integrate into final products. Such modules can be also used for evaluation after adding a few extra components like a programming interface, bootstrapping resistors and break out headers. The key characteristics of these modules are summarized in the following table. Some additional details are covered in the following chapters. +This is a family of ESP32-based modules with some integrated key components, including a crystal oscillator and an antenna matching circuit. The modules constitute ready-made solutions for integration into final products. If combined with a few extra components, such as a programming interface, bootstrapping resistors, and pin headers, these modules can also be used for evaluation of ESP32's functionality. -=============== ============ ===== ====== ==== --- Key Components ---------------- --------------------------------- -Module Chip Flash PSRAM Ant. -=============== ============ ===== ====== ==== -ESP32-WROOM-32 ESP32-D0WDQ6 4MB -- MIFA -ESP32-WROOM-32D ESP32-D0WD 4MB -- MIFA -ESP32-WROOM-32U ESP32-D0WD 4MB -- U.FL -ESP32-SOLO-1 ESP32-S0WD 4MB -- MIFA -ESP32-WROVER ESP32-D0WDQ6 4MB 8MB MIFA -ESP32-WROVER-I ESP32-D0WDQ6 4MB 8MB U.FL -ESP32-WROVER-B ESP32-D0WD 4MB 8MB MIFA -ESP32-WROVER-IB ESP32-D0WD 4MB 8MB U.FL -=============== ============ ===== ====== ==== +The key characteristics of these modules are summarized in the table below. Some additional details are covered in the following sections. -* ESP32-**D**.. denotes dual core, ESP32-**S**.. denotes single core chip -* MIFA - Meandered Inverted-F Antenna +=================== ============ =========== ========= ==== =============== + Key Components +------------------- ------------------------------------------ --------------- +Module Chip Flash, MB PSRAM, MB Ant. Dimensions, mm +=================== ============ =========== ========= ==== =============== +ESP32-WROOM-32 ESP32-D0WDQ6 4 -- MIFA 18 × 25.5 × 3.1 +ESP32-WROOM-32D ESP32-D0WD 4, 8, or 16 -- MIFA 18 × 25.5 × 3.1 +ESP32-WROOM-32U ESP32-D0WD 4, 8, or 16 -- U.FL 18 × 19.2 × 3.1 +ESP32-SOLO-1 ESP32-S0WD 4 -- MIFA 18 × 25.5 × 3.1 +ESP32-WROVER (PCB) ESP32-D0WDQ6 4 8 MIFA 18 × 31.4 × 3.3 +ESP32-WROVER (IPEX) ESP32-D0WDQ6 4 8 U.FL 18 × 31.4 × 3.3 +ESP32-WROVER-B ESP32-D0WD 4, 8, or 16 8 MIFA 18 × 31.4 × 3.3 +ESP32-WROVER-IB ESP32-D0WD 4, 8, or 16 8 U.FL 18 × 31.4 × 3.3 +=================== ============ =========== ========= ==== =============== + +* ESP32-**D**.. identifies a dual-core chip, ESP32-**S**.. identifies a single-core chip +* MIFA - Meandered Inverted-F Antenna * U.FL - U.FL / IPEX antenna connector -* ESP32-WROOM-x and ESP32-WROVER-x modules are also available with custom flash sizes of 8MB or 16MB, see `Espressif Products Ordering Information`_ (PDF) +* ESP32-WROOM-32x, ESP32-WROVER-B and ESP32-WROVER-IB modules come with 4 MB flash by default but also available with custom flash sizes of 8 MB and 16 MB, see `Espressif Products Ordering Information`_ (PDF) * `ESP32 Chip Datasheet `__ (PDF) -* Initial release of ESP32-WROVER module had 4MB of PSRAM +* Initial release of the ESP32-WROVER module had 4 MB of PSRAM * *ESP32-WROOM-32* was previously called *ESP-WROOM-32* @@ -48,7 +50,10 @@ ESP32-WROVER-IB ESP32-D0WD 4MB 8MB U.FL ESP32-WROOM-32 -------------- -A basic and commonly adopted ESP32 module with ESP32-D0WDQ6 chip on board. The first one of the WROOM / WROVER family released to the market. By default the module has 4MB flash and may be also ordered with custom flash size of 8 or 16MB, see `Espressif Products Ordering Information`_. +This is a basic and commonly adopted ESP32 module with the ESP32-D0WDQ6 chip on board. It was the first module of the WROOM / WROVER family released to the market. + +For key characteristics, see the table in Section :ref:`esp-wroom-solo-wrover-modules`, `Espressif Products Ordering Information`_. + .. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-wroom-32-front-back.jpg :align: center @@ -61,7 +66,7 @@ Documentation ^^^^^^^^^^^^^ * `ESP32-WROOM-32 Datasheet `__ (PDF) -* `ESP32-WROOM-32 Reference Design `_ containing OrCAD schematic, PCB layout, gerbers and BOM +* `ESP32-WROOM-32 Reference Design `_ containing OrCAD schematic, PCB layout, gerber and BOM files .. _esp-modules-and-boards-esp32-wroom-32d-and-u: @@ -69,7 +74,11 @@ Documentation ESP32-WROOM-32D / ESP32-WROOM-32U --------------------------------- -Both modules have ESP32-D0WD chip on board of a smaller footprint than ESP32-D0WDQ6 installed in :ref:`esp-modules-and-boards-esp32-wroom-32`. By default the module has 4MB flash and may be also ordered with custom flash size of 8 or 16MB, see `Espressif Products Ordering Information`_. Version "D" has a MIFA antenna. Version "U" has just an U.FL / IPEX antenna connector. That makes it 6.3 mm shorter comparing to "D", and also the smallest representative of the whole WROOM / WROVER family of modules. +Both modules integrate the ESP32-D0WD chip which has a smaller footprint than the chip ESP32-D0WDQ6 installed in :ref:`esp-modules-and-boards-esp32-wroom-32`. + +For key characteristics, see the table in Section :ref:`esp-wroom-solo-wrover-modules` and `Espressif Products Ordering Information`_. + +ESP32-WROOM-32U is the smallest representative of the whole WROOM / WROVER family of modules. .. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-wroom-32d-front-back.jpg :align: center @@ -96,7 +105,9 @@ Documentation ESP32-SOLO-1 ------------ -Simplified version of ESP32-WROOM-32D module. It contains a single core ESP32 chip that supports clock frequency of up to 160 MHz. +This is a simplified version of the ESP32-WROOM-32D module. It contains a single-core ESP32 chip that supports a clock frequency of up to 160 MHz. + +For key characteristics, see the table in Section :ref:`esp-wroom-solo-wrover-modules` and `Espressif Products Ordering Information`_. .. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-solo-1-front-back.jpg :align: center @@ -114,19 +125,17 @@ Documentation .. _esp-modules-and-boards-esp32-wrover: -ESP32-WROVER ------------- +ESP32-WROVER series +------------------- -A step upgrade of ESP32-WROOM-32x modules with an additional 8MB SPI PSRAM (Pseudo static RAM). +This series consists of a few modifications of ESP32-WROOM-32x modules, which among other upgrades include additional 8 MB SPI PSRAM (pseudo static RAM). -The module comes in couple of versions listed in section :ref:`esp-wroom-solo-wrover-modules`: +For details, see the table in Section :ref:`esp-wroom-solo-wrover-modules` and `Espressif Products Ordering Information`_. -* **ESP32-WROVER** and **ESP32-WROVER-I** have PSRAM that operates at 1.8V and can support up to 144 MHz clock rate. -* **ESP32-WROVER-B** and **ESP32-WROVER-IB** have PSRAM that operates at 3.3V and can support up to 133 MHz clock rate. +* **ESP32-WROVER (PCB)** and **ESP32-WROVER (IPEX)** have PSRAM that operates at 1.8 V and supports up to 144 MHz clock rate. +* **ESP32-WROVER-B** and **ESP32-WROVER-IB** have PSRAM that operates at 3.3 V and can supports up to 133 MHz clock rate. -By default the module has 4MB flash and may be also ordered with custom flash size of 8 or 16MB, see `Espressif Products Ordering Information`_. - -Depending on version the module has PCB antenna (shown below) or an U.FL / IPEX antenna connector. Because of additional components inside, this module is 5.9 mm longer than :ref:`esp-modules-and-boards-esp32-wroom-32`. +The picture below shows an ESP32-WROVER module with a PCB antenna. .. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-wrover.jpg :align: center @@ -139,16 +148,47 @@ Documentation ^^^^^^^^^^^^^ * `ESP32-WROVER Datasheet `__ (PDF) +* `ESP32-WROVER-B Datasheet `__ (PDF) * `ESP-PSRAM64 & ESP-PSRAM64H Datasheet `__ (PDF) -* `ESP32-WROVER Reference Design `_ containing OrCAD schematic, PCB layout, gerbers and BOM +* `ESP32-WROVER Reference Design `_ containing OrCAD schematic, PCB layout, gerber and BOM files +ESP32-PICO-D4 +------------- + +ESP32-PICO-D4 is a System-in-Package (SiP) module, integrating all peripheral components seamlessly, including the following: + +- 4 MB flash memory +- crystal oscillator +- filter capacitors +- RF matching circuit + +For key characteristics, see `Espressif Products Ordering Information`_. + + +Documentation +^^^^^^^^^^^^^ + +* `ESP32-PICO-D4 Datasheet `__ (PDF) + + +Development Boards +================== + +Depending on the intended functionality, different development boards feature: + +- Access to different ESP32 GPIO pins. +- Different interfaces: USB, JTAG. +- Different peripherals: touchpads, LCD screens, SD card slots, headers for camera modules, etc. + .. _esp-modules-and-boards-esp32-pico-kit: ESP32-PICO-KIT V4.1 -=================== +------------------- -The smallest ESP32 development board with all the components required to connect it directly to a PC USB port, and pin headers to plug into a mini breadboard. It is equipped with ESP32-PICO-D4 module that integrates 4 MB flash memory, a crystal oscillator, filter capacitors and RF matching circuit in one single package. As result, the fully functional development board requires only a few external components that can easy fit on a 20 x 52 mm PCB including antenna, LDO, USB-UART bridge and two buttons to reset it and put into download mode. +This is the smallest available ESP32-based development board. It features all the components for direct connection to a computer's USB port as well as pin headers for plugging into a mini breadboard. + +The board is equipped with the `ESP32-PICO-D4`_ module. With such a module, the creation of a fully functional development board required only a few external components that fit on a PCB as small as 20 x 52 mm. The external components include antenna, LDO, USB-UART bridge, and two buttons for reset and activation of Firmware Download mode. .. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-pico-kit-v4.1.jpg :align: center @@ -157,18 +197,18 @@ The smallest ESP32 development board with all the components required to connect ESP32-PICO-KIT V4.1 board -Comparing to ESP32-PICO-KIT V4, this version contains a more capable CP2102N USB-UART bridge that provides up to 3 Mbps transfers rates. +Comparing to ESP32-PICO-KIT V4, this version features the CP2102N USB-UART bridge that provides faster transfer rates of up to 3 Mbps. Documentation -------------- +^^^^^^^^^^^^^ -* :doc:`../get-started/get-started-pico-kit` +* :doc:`../get-started-cmake/get-started-pico-kit` * `ESP32-PICO-KIT V4.1 Schematic `_ (PDF) -* `ESP32-PICO-KIT Reference Design `_ containing OrCAD schematic, PCB layout, gerbers and BOM +* `ESP32-PICO-KIT Reference Design `_ containing OrCAD schematic, PCB layout, gerber and BOM files * `ESP32-PICO-D4 Datasheet `_ (PDF) Previous Versions ------------------ +^^^^^^^^^^^^^^^^^ * :ref:`esp-modules-and-boards-esp32-pico-kit-v4` * :ref:`esp-modules-and-boards-esp32-pico-kit-v3` @@ -177,9 +217,17 @@ Previous Versions .. _esp-modules-and-boards-esp32-devkitc: ESP32 DevKitC V4 -================ +---------------- -Small and convenient development board with :ref:`esp-modules-and-boards-esp32-wroom-32` module installed, break out pin headers and minimum additional components. Includes USB to serial programming interface, that also provides power supply for the board. Has pushbuttons to reset the board and put it in upload mode. Comparing to the previous :ref:`esp-modules-and-boards-esp32-devkitc-v2`, instead of ESP32-WROOM-32 it can accommodate :ref:`esp-modules-and-boards-esp32-wrover` module and has CP2102N chip that supports faster baud rates. +This is a small and convenient development board that features: + +- :ref:`esp-modules-and-boards-esp32-wroom-32` module +- USB-to-serial programming interface that also provides power supply for the board +- pin headers +- pushbuttons for reset and activation of Firmware Download mode +- a few other components + +Comparing to the previous :ref:`esp-modules-and-boards-esp32-devkitc-v2`, this version can integrate :ref:`esp-modules-and-boards-esp32-wrover` module instead of ESP32-WROOM-32 and has the CP2102N chip that supports faster baud rates. .. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-devkitc-v4-front.jpg :align: center @@ -189,15 +237,15 @@ Small and convenient development board with :ref:`esp-modules-and-boards-esp32-w ESP32 DevKitC V4 board Documentation -------------- +^^^^^^^^^^^^^ -* :doc:`../get-started/get-started-devkitc` +* :doc:`../get-started-cmake/get-started-devkitc` * `ESP32-DevKitC schematic `_ (PDF) -* `ESP32-DevKitC Reference Design `_ containing OrCAD schematic, PCB layout, gerbers and BOM +* `ESP32-DevKitC Reference Design `_ containing OrCAD schematic, PCB layout, gerber and BOM files * `CP210x USB to UART Bridge VCP Drivers `_ Previous Versions ------------------ +^^^^^^^^^^^^^^^^^ * :ref:`esp-modules-and-boards-esp32-devkitc-v2` @@ -205,18 +253,28 @@ Previous Versions .. _esp-modules-and-boards-esp-wrover-kit: ESP-WROVER-KIT V4.1 -=================== +------------------- -The ESP-WROVER-KIT V4.1 development board has dual port USB to serial converter for programming and JTAG interface for debugging. Power supply is provided by USB interface or from standard 5 mm power supply jack. Power supply selection is done with a jumper and may be put on/off with a separate switch. This board has MicroSD card slot, 3.2” SPI LCD screen and dedicated header to connect a camera. It provides RGB diode for diagnostics. Includes 32.768 kHz XTAL for internal RTC to operate it in low power modes. +This board features: -This version of ESP-WROVER-KIT board has ESP-WROVER-B module installed that integrates 64-MBit PSRAM for flexible extended storage and data processing capabilities. The board can accommodate other versions of ESP modules described under :ref:`esp-wroom-solo-wrover-modules`. +- dual port USB-to-serial converter for programming +- JTAG interface for debugging +- MicroSD card slot +- 3.2” SPI LCD screen +- header for a camera module +- RGB diode for diagnostics +- 32.768 kHz XTAL for internal RTC to operate it in low power modes + +Power can be supplied either via USB or via a standard 5 mm power supply jack. A power source can be selected with a jumper and can be turned on/off with a separate switch. + +This version of the ESP-WROVER-KIT board integrates the ESP-WROVER-B module that has 8 MB PSRAM for flexible extended storage and data processing capabilities. The board can accommodate other versions of ESP modules described in :ref:`esp-wroom-solo-wrover-modules`. Comparing to :ref:`esp-modules-and-boards-esp-wrover-kit-v3`, this board has the following design changes: - * JP8, JP11 and JP13 have been combined into a single JP2 - * USB connector has been changed to DIP type and moved to the lower right corner of the board - * R61 has been changed to 0R - * Some other components, e.g. EN and Boot buttons, have been replaced with functional equivalents basing on test results and sourcing options +- JP8, JP11, and JP13 have been combined into a single JP2. +- USB connector has been changed to DIP type and moved to the lower right corner of the board. +- R61 has been changed to a Zero-ohm resistor. +- Some components have been replaced with functional equivalents based on test results and sourcing options, e.g., the EN and Boot buttons. .. figure:: https://dl.espressif.com/dl/schematics/pictures/esp-wrover-kit-v4.1-front.jpg :align: center @@ -225,18 +283,18 @@ Comparing to :ref:`esp-modules-and-boards-esp-wrover-kit-v3`, this board has the ESP-WROVER-KIT V4.1 board -The board on picture above has ESP32-WROVER-B module is installed. +The board in the picture above integrates the ESP32-WROVER-B module. Documentation -------------- +^^^^^^^^^^^^^ -* :doc:`../get-started/get-started-wrover-kit` +* :doc:`../get-started-cmake/get-started-wrover-kit` * `ESP-WROVER-KIT V4.1 Schematic `__ (PDF) * :doc:`../api-guides/jtag-debugging/index` * `FTDI Virtual COM Port Drivers`_ Previous Versions ------------------ +^^^^^^^^^^^^^^^^^ * :ref:`esp-modules-and-boards-esp-wrover-kit-v3` * :ref:`esp-modules-and-boards-esp-wrover-kit-v2` From 32c3730c33bc74fafe5b28d9382bc39083d7da96 Mon Sep 17 00:00:00 2001 From: Kirill Chalov Date: Mon, 24 Jun 2019 08:24:44 +0800 Subject: [PATCH 117/486] Review the file api-guides/external-ram.rst --- docs/en/api-guides/external-ram.rst | 109 +++++++++++++--------------- 1 file changed, 52 insertions(+), 57 deletions(-) diff --git a/docs/en/api-guides/external-ram.rst b/docs/en/api-guides/external-ram.rst index f7c509abcd..2d8d694923 100644 --- a/docs/en/api-guides/external-ram.rst +++ b/docs/en/api-guides/external-ram.rst @@ -7,41 +7,38 @@ Support for external RAM Introduction ============ -The ESP32 has a few hundred KiB of internal RAM, residing on the same die as the rest of the ESP32. For some purposes, this is insufficient, -and therefore the ESP32 incorporates the ability to also use up to 4MiB of external SPI RAM memory as memory. The external memory is incorporated -in the memory map and is, within certain restrictions, usable in the same way internal data RAM is. +ESP32 has a few hundred kilobytes of internal RAM, residing on the same die as the rest of the chip components. It can be insufficient for some purposes, so ESP32 has the ability to also use up to 4 MB of external SPI RAM memory. The external memory is incorporated in the memory map and, with certain restrictions, is usable in the same way as internal data RAM. + Hardware ======== -The ESP32 supports SPI (P)SRAM connected in parallel with the SPI flash chip. While the ESP32 is capable of supporting several types -of RAM chips, the ESP32 SDK at the moment only supports the ESP-PSRAM32 chip. +ESP32 supports SPI PSRAM connected in parallel with the SPI flash chip. While ESP32 is capable of supporting several types of RAM chips, the ESP32 SDK only supports the ESP-PSRAM32 chip at the moment. -The ESP-PSRAM32 chip is an 1.8V device, and can only be used in parallel with an 1.8V flash part. Make sure to either set the MTDI -pin to a high signal level on bootup, or program the fuses in the ESP32 to always use a VDD_SIO level of 1.8V. Not doing this risks -damaging the PSRAM and/or flash chip. +The ESP-PSRAM32 chip is a 1.8 V device which can only be used in parallel with a 1.8 V flash component. Make sure to either set the MTDI pin to a high signal level on bootup, or program ESP32 eFuses to always use the VDD_SIO level of 1.8 V. Not doing this can damage the PSRAM and/or flash chip. -To connect the ESP-PSRAM chip to the ESP32D0W*, connect the following signals: - * PSRAM /CE (pin 1) - ESP32 GPIO 16 - * PSRAM SO (pin 2) - flash DO - * PSRAM SIO[2] (pin 3) - flash WP - * PSRAM SI (pin 5) - flash DI - * PSRAM SCLK (pin 6) - ESP32 GPIO 17 - * PSRAM SIO[3] (pin 7) - flash HOLD - * PSRAM Vcc (pin 8) - ESP32 VCC_SDIO +To connect the ESP-PSRAM32 chip to ESP32D0W*, connect the following signals: -Connections for the ESP32D2W* chips are TBD. + * PSRAM /CE (pin 1) > ESP32 GPIO 16 + * PSRAM SO (pin 2) > flash DO + * PSRAM SIO[2] (pin 3) > flash WP + * PSRAM SI (pin 5) > flash DI + * PSRAM SCLK (pin 6) > ESP32 GPIO 17 + * PSRAM SIO[3] (pin 7) > flash HOLD + * PSRAM Vcc (pin 8) > ESP32 VCC_SDIO + +Connections for ESP32D2W* chips are TBD. .. NOTE:: - Espressif sells an ESP-WROVER module which contains an ESP32, 1.8V flash and the ESP-PSRAM32 integrated in a module, ready for inclusion - on an end product PCB. + Espressif produces the line of ESP32-WROVER modules which contain ESP32, 1.8 V flash, and ESP-PSRAM32. These modules are ready to be mounted on an end product PCB. .. _external_ram_config: + Configuring External RAM ======================== -ESP-IDF fully supports using external memory in applications. ESP-IDF can be configured to handle external RAM in several ways after it is initialized at startup: +ESP-IDF fully supports the use of external memory in applications. Once the external RAM is initialized at startup, ESP-IDF can be configured to handle it in several ways: * :ref:`external_ram_config_memory_map` * :ref:`external_ram_config_capability_allocator` @@ -50,36 +47,39 @@ ESP-IDF fully supports using external memory in applications. ESP-IDF can be con .. _external_ram_config_memory_map: -Integrate RAM into ESP32 memory map ------------------------------------ + +Integrate RAM into the ESP32 memory map +--------------------------------------- Select this option by choosing "Integrate RAM into ESP32 memory map" from :ref:`CONFIG_SPIRAM_USE`. -This is the most basic option for external SPIRAM integration. Most users will want one of the other, more advanced, options. +This is the most basic option for external SPI RAM integration. Most likely, you will need another, more advanced option. -During ESP-IDF startup, external RAM is mapped into the data address space starting at at address 0x3F800000 (byte-accessible). The length of this region is the same as the SPIRAM size (up to the limit of 4MiB). +During the ESP-IDF startup, external RAM is mapped into the data address space, starting at address 0x3F800000 (byte-accessible). The length of this region is the same as the SPI RAM size (up to the limit of 4 MB). -The application can manually place data in external memory by creating pointers to this region. The application is responsible for all management of the external SPIRAM: coordinating buffer usage, preventing corruption, etc. +Applications can manually place data in external memory by creating pointers to this region. So if an application uses external memory, it is responsible for all management of the external SPI RAM: coordinating buffer usage, preventing corruption, etc. .. _external_ram_config_capability_allocator: + Add external RAM to the capability allocator -------------------------------------------- Select this option by choosing "Make RAM allocatable using heap_caps_malloc(..., MALLOC_CAP_SPIRAM)" from :ref:`CONFIG_SPIRAM_USE`. -When enabled, memory is mapped to address 0x3F800000 but also added to the :doc:`capabilities-based heap memory allocator ` using ``MALLOC_CAP_SPIRAM``. +When enabled, memory is mapped to address 0x3F800000 and also added to the :doc:`capabilities-based heap memory allocator ` using ``MALLOC_CAP_SPIRAM``. To allocate memory from external RAM, a program should call ``heap_caps_malloc(size, MALLOC_CAP_SPIRAM)``. After use, this memory can be freed by calling the normal ``free()`` function. .. _external_ram_config_malloc: + Provide external RAM via malloc() --------------------------------- -Select this option by choosing "Make RAM allocatable using malloc() as well" from :ref:`CONFIG_SPIRAM_USE`. This is the default selection. +Select this option by choosing "Make RAM allocatable using malloc() as well" from :ref:`CONFIG_SPIRAM_USE`. This is the default option. -Using this option, memory is added to the capability allocator as described for the previous option. However it is also added to the pool of RAM that can be returned by standard ``malloc()``. +In this case, memory is added to the capability allocator as described for the previous option. However, it is also added to the pool of RAM that can be returned by the standard ``malloc()`` function. This allows any application to use the external RAM without having to rewrite the code to use ``heap_caps_malloc(..., MALLOC_CAP_SPIRAM)``. @@ -88,65 +88,60 @@ An additional configuration item, :ref:`CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL`, ca - When allocating a size less than the threshold, the allocator will try internal memory first. - When allocating a size equal to or larger than the threshold, the allocator will try external memory first. -If a suitable block of preferred internal/external memory is not available, allocation will try the other type of memory. +If a suitable block of preferred internal/external memory is not available, the allocator will try the other type of memory. Because some buffers can only be allocated in internal memory, a second configuration item :ref:`CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL` defines a pool of internal memory which is reserved for *only* explicitly internal allocations (such as memory for DMA use). Regular ``malloc()`` will not allocate from this pool. The :ref:`MALLOC_CAP_DMA ` and ``MALLOC_CAP_INTERNAL`` flags can be used to allocate memory from this pool. .. _external_ram_config_bss: + Allow .bss segment placed in external memory -------------------------------------------- -Enable this option by setting :ref:`CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY`. This configuration setting is independent of the other three. +Enable this option by checking :ref:`CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY`. This configuration setting is independent of the other three. -If enabled, a region of the address space starting from 0x3F800000 will be to used to store zero initialized data (BSS segment) from the lwip, net80211, libpp and bluedroid ESP-IDF libraries. +If enabled, a region of the address space starting from 0x3F800000 will be used to store zero-initialized data (BSS segment) from the lwIP, net80211, libpp, and bluedroid ESP-IDF libraries. -Additional data can be moved from the internal BSS segment to external RAM by applying the ``EXT_RAM_ATTR`` macro to any static declaration (which is not initialized to a non-zero value). +Additional data can be moved from the internal BSS segment to external RAM by applying the macro ``EXT_RAM_ATTR`` to any static declaration (which is not initialized to a non-zero value). This option reduces the internal static memory used by the BSS segment. -Remaining external RAM can also be added to the capability heap allocator, by the method shown above. +Remaining external RAM can also be added to the capability heap allocator using the method shown above. + Restrictions ============ External RAM use has the following restrictions: - * When flash cache is disabled (for example, because the flash is being written to), the external RAM also becomes inaccessible; any reads from or - writes to it will lead to an illegal cache access exception. This is also the reason that ESP-IDF does not by default allocate any task stacks in external RAM (see below). - * External RAM cannot be used as a place to store DMA transaction descriptors or as a buffer for a DMA transfer to read from or write into. Any - buffers that will be used in combination with DMA must be allocated using ``heap_caps_malloc(size, MALLOC_CAP_DMA)`` (and can be freed using a - standard ``free()`` call.) - * External RAM uses the same cache region as the external flash. This means that often accessed variables in external RAM can be read and - modified almost as quickly as in internal ram. However, when accessing large chunks of data (>32K), the cache can be insufficient and speeds - will fall back to the access speed of the external RAM. Moreover, accessing large chunks of data can 'push out' cached flash, possibly making - execution of code afterwards slower. - * External RAM cannot be used as task stack memory. Because of this, :cpp:func:`xTaskCreate` and similar functions will always allocate internal memory - for stack and task TCBs and functions like :cpp:func:`xTaskCreateStatic` will check if the buffers passed are internal. However, for tasks not calling - on code in ROM in any way, directly or indirectly, the menuconfig option :ref:`CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY` will eliminate - the check in xTaskCreateStatic, allowing a task's stack to be in external RAM. Using this is not advised, however. - * By default, failure to initialize external RAM will cause ESP-IDF startup to abort. This can be disabled by enabling config item :ref:`CONFIG_SPIRAM_IGNORE_NOTFOUND`. If :ref:`CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY` is enabled, the option to ignore failure is not available as the linker will have assigned symbols to external memory addresses at link time. - * When used at 80MHz clock speed, external RAM must also occupy either the HSPI or VSPI bus. Select which SPI host will be used by :ref:`CONFIG_SPIRAM_OCCUPY_SPI_HOST`. + * When flash cache is disabled (for example, if the flash is being written to), the external RAM also becomes inaccessible; any reads from or writes to it will lead to an illegal cache access exception. This is also the reason why ESP-IDF does not by default allocate any task stacks in external RAM (see below). + * External RAM cannot be used as a place to store DMA transaction descriptors or as a buffer for a DMA transfer to read from or write into. Any buffers that will be used in combination with DMA must be allocated using ``heap_caps_malloc(size, MALLOC_CAP_DMA)`` and can be freed using a standard ``free()`` call. + * External RAM uses the same cache region as the external flash. This means that frequently accessed variables in external RAM can be read and modified almost as quickly as in internal ram. However, when accessing large chunks of data (>32 KB), the cache can be insufficient, and speeds will fall back to the access speed of the external RAM. Moreover, accessing large chunks of data can "push out" cached flash, possibly making the execution of code slower afterwards. + * External RAM cannot be used as task stack memory. Due to this, :cpp:func:`xTaskCreate` and similar functions will always allocate internal memory for stack and task TCBs, and functions such as :cpp:func:`xTaskCreateStatic` will check if the buffers passed are internal. However, for tasks not calling on code in ROM in any way, directly or indirectly, the menuconfig option :ref:`CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY` will eliminate the check in xTaskCreateStatic, allowing a task's stack to be in external RAM. Using this is not advised, however. + * By default, failure to initialize external RAM will cause the ESP-IDF startup to abort. This can be disabled by enabling the config item :ref:`CONFIG_SPIRAM_IGNORE_NOTFOUND`. If :ref:`CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY` is enabled, the option to ignore failure is not available as the linker will have assigned symbols to external memory addresses at link time. + * When used at 80 MHz clock speed, external RAM must also occupy either the HSPI or VSPI bus. Select which SPI host will be used by :ref:`CONFIG_SPIRAM_OCCUPY_SPI_HOST`. + Chip revisions ============== -There are some issues with certain revisions of the ESP32 that have repercussions for use with external RAM. These are documented in the ESP32 -ECO_ document. In particular, ESP-IDF handles the bugs mentioned in the following ways: +There are some issues with certain revisions of ESP32 that have repercussions for use with external RAM. The issues are documented in the ESP32 ECO_ document. In particular, ESP-IDF handles the bugs mentioned in the following ways: + ESP32 rev v0 ------------ -ESP-IDF has no workaround for the bugs in this revision of silicon, and it cannot be used to map external PSRAM into the ESP32s main memory map. +ESP-IDF has no workaround for the bugs in this revision of silicon, and it cannot be used to map external PSRAM into ESP32's main memory map. + ESP32 rev v1 ------------ -The bugs in this silicon revision introduce a hazard when certain sequences of machine instructions operate on external memory locations (ESP32 ECO 3.2). -To work around this, the gcc compiler to compile ESP-IDF has been expanded with a flag: ``-mfix-esp32-psram-cache-issue``. With this flag passed to gcc -on the command line, the compiler works around these sequences and only outputs code that can safely be executed. +The bugs in this revision of silicon cause issues if certain sequences of machine instructions operate on external memory. (ESP32 ECO 3.2). As a workaround, the GCC compiler received the flag ``-mfix-esp32-psram-cache-issue`` to filter these sequences and only output the code that can safely be executed. Enable this flag by checking :ref:`CONFIG_SPIRAM_CACHE_WORKAROUND`. + +Aside from linking to a recompiled version of Newlib with the additional flag, ESP-IDF also does the following: + +- Avoids using some ROM functions +- Allocates static memory for the WiFi stack -In ESP-IDF, this flag is enabled when you select :ref:`CONFIG_SPIRAM_CACHE_WORKAROUND`. ESP-IDF also takes other measures to make -sure no combination of PSRAM access plus the offending instruction sets are used: it links to a version of Newlib recompiled with the gcc flag, doesn't use -some ROM functions and allocates static memory for the WiFi stack. .. _ECO: https://www.espressif.com/sites/default/files/documentation/eco_and_workarounds_for_bugs_in_esp32_en.pdf From fc3253163e2a6785621fd27e0458b9106c929ddf Mon Sep 17 00:00:00 2001 From: Island Date: Mon, 7 Jan 2019 15:16:47 +0800 Subject: [PATCH 118/486] component/ble_mesh: ESP BLE Mesh release 1. BLE Mesh Core * Provisioning: Node Role * Advertising and GATT bearer * Authentication OOB * Provisioning: Provisioner Role * Advertising and GATT bearer * Authentication OOB * Networking * Relay * Segmentation and Reassembly * Key Refresh * IV Update * Proxy Support * Multiple Client Models Run Simultaneously * Support multiple client models send packets to different nodes simultaneously * No blocking between client model and server * NVS Storage * Store Provisioning Data of BLE Mesh Nodes in Flash 2. BLE Mesh Applications * BLE Mesh Node & Provisioner * Node Example * Provisioner Example * Node + Generic OnOff Client Example * Fast Provisioning * Vendor Fast Prov Server Model * Vendor Fast Prov Client Model * Examples * Wi-Fi & BLE Mesh Coexistence * Example * BLE Mesh Console Commands * Example 3. BLE Mesh Models * Foundation Models * Configuration Server Model * Configuration Client Model * Health Server Model * Health Client Model * Generic Client Models * Generic OnOff Client * Generic Level Client * Generic Location Client * Generic Default Transition Timer Client * Generic Power OnOff Client * Generic Power Level Client * Generic Battery Client * Generic Property Client * Generic Server Models * Generic OnOff Server (Example) * Lighting Client Models * Light Lightness Client * Light CTL Client * Light HSL Client * Light xyL Client * Light LC Client * Sensor Client Model * Sensor Client * Time and Scenes Client Models * Time Client * Scene Client * Scheduler Client --- components/bt/CMakeLists.txt | 69 + components/bt/Kconfig | 811 ++++ .../api/core/esp_ble_mesh_common_api.c | 70 + .../esp_ble_mesh_local_data_operation_api.c | 80 + .../api/core/esp_ble_mesh_low_power_api.c | 26 + .../api/core/esp_ble_mesh_networking_api.c | 338 ++ .../api/core/esp_ble_mesh_provisioning_api.c | 423 ++ .../api/core/esp_ble_mesh_proxy_api.c | 65 + .../core/include/esp_ble_mesh_common_api.h | 37 + .../esp_ble_mesh_local_data_operation_api.h | 113 + .../core/include/esp_ble_mesh_low_power_api.h | 20 + .../include/esp_ble_mesh_networking_api.h | 267 ++ .../include/esp_ble_mesh_provisioning_api.h | 316 ++ .../api/core/include/esp_ble_mesh_proxy_api.h | 59 + .../bt/ble_mesh/api/esp_ble_mesh_defs.h | 1524 +++++++ .../models/esp_ble_mesh_config_model_api.c | 82 + .../models/esp_ble_mesh_generic_model_api.c | 75 + .../models/esp_ble_mesh_health_model_api.c | 98 + .../models/esp_ble_mesh_lighting_model_api.c | 76 + .../models/esp_ble_mesh_sensor_model_api.c | 76 + .../esp_ble_mesh_time_scene_model_api.c | 76 + .../include/esp_ble_mesh_config_model_api.h | 670 +++ .../include/esp_ble_mesh_generic_model_api.h | 478 +++ .../include/esp_ble_mesh_health_model_api.h | 261 ++ .../include/esp_ble_mesh_lighting_model_api.h | 526 +++ .../include/esp_ble_mesh_sensor_model_api.h | 230 ++ .../esp_ble_mesh_time_scene_model_api.h | 292 ++ .../ble_mesh/btc/btc_ble_mesh_config_model.c | 725 ++++ .../ble_mesh/btc/btc_ble_mesh_generic_model.c | 540 +++ .../ble_mesh/btc/btc_ble_mesh_health_model.c | 592 +++ .../btc/btc_ble_mesh_lighting_model.c | 381 ++ .../bt/ble_mesh/btc/btc_ble_mesh_prov.c | 1528 +++++++ .../ble_mesh/btc/btc_ble_mesh_sensor_model.c | 632 +++ .../btc/btc_ble_mesh_time_scene_model.c | 383 ++ .../btc/include/btc_ble_mesh_config_model.h | 64 + .../btc/include/btc_ble_mesh_generic_model.h | 52 + .../btc/include/btc_ble_mesh_health_model.h | 78 + .../btc/include/btc_ble_mesh_lighting_model.h | 53 + .../ble_mesh/btc/include/btc_ble_mesh_prov.h | 210 + .../btc/include/btc_ble_mesh_sensor_model.h | 53 + .../include/btc_ble_mesh_time_scene_model.h | 53 + components/bt/ble_mesh/mesh_core/access.c | 1043 +++++ components/bt/ble_mesh/mesh_core/access.h | 60 + components/bt/ble_mesh/mesh_core/adv.c | 411 ++ components/bt/ble_mesh/mesh_core/adv.h | 86 + components/bt/ble_mesh/mesh_core/beacon.c | 422 ++ components/bt/ble_mesh/mesh_core/beacon.h | 24 + components/bt/ble_mesh/mesh_core/cfg_cli.c | 1657 ++++++++ components/bt/ble_mesh/mesh_core/cfg_srv.c | 3593 +++++++++++++++++ components/bt/ble_mesh/mesh_core/crypto.c | 878 ++++ components/bt/ble_mesh/mesh_core/crypto.h | 166 + components/bt/ble_mesh/mesh_core/foundation.h | 166 + components/bt/ble_mesh/mesh_core/friend.c | 1326 ++++++ components/bt/ble_mesh/mesh_core/friend.h | 49 + components/bt/ble_mesh/mesh_core/health_cli.c | 462 +++ components/bt/ble_mesh/mesh_core/health_srv.c | 529 +++ .../bt/ble_mesh/mesh_core/include/cfg_cli.h | 297 ++ .../bt/ble_mesh/mesh_core/include/cfg_srv.h | 72 + .../ble_mesh/mesh_core/include/health_cli.h | 78 + .../ble_mesh/mesh_core/include/health_srv.h | 93 + .../ble_mesh/mesh_core/include/mesh_access.h | 444 ++ .../mesh_core/include/mesh_aes_encrypt.h | 171 + .../ble_mesh/mesh_core/include/mesh_atomic.h | 305 ++ .../mesh_core/include/mesh_bearer_adapt.h | 733 ++++ .../bt/ble_mesh/mesh_core/include/mesh_buf.h | 1064 +++++ .../ble_mesh/mesh_core/include/mesh_dlist.h | 496 +++ .../bt/ble_mesh/mesh_core/include/mesh_hci.h | 134 + .../ble_mesh/mesh_core/include/mesh_kernel.h | 275 ++ .../bt/ble_mesh/mesh_core/include/mesh_main.h | 584 +++ .../ble_mesh/mesh_core/include/mesh_proxy.h | 37 + .../ble_mesh/mesh_core/include/mesh_slist.h | 468 +++ .../ble_mesh/mesh_core/include/mesh_trace.h | 131 + .../ble_mesh/mesh_core/include/mesh_types.h | 46 + .../bt/ble_mesh/mesh_core/include/mesh_util.h | 440 ++ .../bt/ble_mesh/mesh_core/include/mesh_uuid.h | 530 +++ components/bt/ble_mesh/mesh_core/lpn.c | 1057 +++++ components/bt/ble_mesh/mesh_core/lpn.h | 67 + components/bt/ble_mesh/mesh_core/mesh.h | 22 + .../bt/ble_mesh/mesh_core/mesh_aes_encrypt.c | 409 ++ .../bt/ble_mesh/mesh_core/mesh_atomic.c | 179 + .../bt/ble_mesh/mesh_core/mesh_bearer_adapt.c | 1858 +++++++++ components/bt/ble_mesh/mesh_core/mesh_buf.c | 453 +++ components/bt/ble_mesh/mesh_core/mesh_hci.c | 45 + .../bt/ble_mesh/mesh_core/mesh_kernel.c | 205 + components/bt/ble_mesh/mesh_core/mesh_main.c | 509 +++ components/bt/ble_mesh/mesh_core/mesh_util.c | 86 + components/bt/ble_mesh/mesh_core/net.c | 1517 +++++++ components/bt/ble_mesh/mesh_core/net.h | 388 ++ components/bt/ble_mesh/mesh_core/prov.c | 1774 ++++++++ components/bt/ble_mesh/mesh_core/prov.h | 34 + .../ble_mesh/mesh_core/provisioner_beacon.c | 71 + .../ble_mesh/mesh_core/provisioner_beacon.h | 20 + .../bt/ble_mesh/mesh_core/provisioner_main.c | 1278 ++++++ .../bt/ble_mesh/mesh_core/provisioner_main.h | 122 + .../bt/ble_mesh/mesh_core/provisioner_prov.c | 3287 +++++++++++++++ .../bt/ble_mesh/mesh_core/provisioner_prov.h | 379 ++ .../bt/ble_mesh/mesh_core/provisioner_proxy.c | 608 +++ .../bt/ble_mesh/mesh_core/provisioner_proxy.h | 89 + components/bt/ble_mesh/mesh_core/proxy.c | 1393 +++++++ components/bt/ble_mesh/mesh_core/proxy.h | 51 + components/bt/ble_mesh/mesh_core/settings.c | 1578 ++++++++ components/bt/ble_mesh/mesh_core/settings.h | 39 + .../mesh_core/settings/settings_nvs.c | 374 ++ .../mesh_core/settings/settings_nvs.h | 44 + components/bt/ble_mesh/mesh_core/test.c | 131 + components/bt/ble_mesh/mesh_core/test.h | 43 + components/bt/ble_mesh/mesh_core/transport.c | 1681 ++++++++ components/bt/ble_mesh/mesh_core/transport.h | 102 + .../bt/ble_mesh/mesh_docs/BLE-Mesh_FAQs_EN.md | 9 + .../mesh_docs/BLE-Mesh_Feature_List_EN.md | 89 + .../mesh_docs/BLE-Mesh_Getting_Started_EN.md | 155 + .../mesh_docs/BLE-Mesh_Known_Issues_EN.md | 1 + components/bt/ble_mesh/mesh_docs/README.md | 50 + .../bt/ble_mesh/mesh_models/generic_client.c | 1225 ++++++ .../mesh_models/include/generic_client.h | 491 +++ .../mesh_models/include/lighting_client.h | 492 +++ .../mesh_models/include/mesh_common.h | 46 + .../mesh_models/include/model_common.h | 133 + .../mesh_models/include/model_opcode.h | 276 ++ .../mesh_models/include/sensor_client.h | 167 + .../mesh_models/include/time_scene_client.h | 257 ++ .../bt/ble_mesh/mesh_models/lighting_client.c | 1400 +++++++ .../bt/ble_mesh/mesh_models/mesh_common.c | 46 + .../bt/ble_mesh/mesh_models/model_common.c | 336 ++ .../bt/ble_mesh/mesh_models/sensor_client.c | 616 +++ .../ble_mesh/mesh_models/time_scene_client.c | 694 ++++ components/bt/bluedroid/btc/core/btc_task.c | 21 + .../bt/bluedroid/btc/include/btc/btc_task.h | 12 + components/bt/component.mk | 23 +- docs/en/COPYRIGHT.rst | 2 + .../ble_mesh_client_model/CMakeLists.txt | 6 + .../ble_mesh/ble_mesh_client_model/Makefile | 10 + .../ble_mesh/ble_mesh_client_model/README.md | 14 + .../ble_mesh_client_model/main/CMakeLists.txt | 6 + .../main/Kconfig.projbuild | 22 + .../main/ble_mesh_demo_main.c | 532 +++ .../ble_mesh_client_model/main/board.c | 115 + .../ble_mesh_client_model/main/board.h | 42 + .../ble_mesh_client_model/main/component.mk | 4 + .../ble_mesh_client_model/sdkconfig.defaults | 45 + .../tutorial/ble_mesh_client_model.md | 252 ++ .../tutorial/images/app.png | Bin 0 -> 443575 bytes .../tutorial/images/message.png | Bin 0 -> 67886 bytes .../tutorial/images/picture5.png | Bin 0 -> 26425 bytes .../ble_mesh_node/CMakeLists.txt | 6 + .../ble_mesh_console/ble_mesh_node/Makefile | 10 + .../ble_mesh_console/ble_mesh_node/README.md | 9 + .../ble_mesh_node/main/CMakeLists.txt | 12 + .../ble_mesh_node/main/ble_mesh_adapter.c | 164 + .../ble_mesh_node/main/ble_mesh_adapter.h | 97 + .../main/ble_mesh_cfg_srv_model.c | 208 + .../main/ble_mesh_cfg_srv_model.h | 107 + .../main/ble_mesh_console_decl.h | 28 + .../ble_mesh_node/main/ble_mesh_console_lib.c | 128 + .../ble_mesh_node/main/ble_mesh_console_lib.h | 31 + .../main/ble_mesh_console_main.c | 215 + .../main/ble_mesh_console_system.c | 183 + .../main/ble_mesh_register_node_cmd.c | 547 +++ .../main/ble_mesh_register_server_cmd.c | 83 + .../ble_mesh_node/main/component.mk | 5 + .../ble_mesh_node/main/register_bluetooth.c | 45 + .../ble_mesh_node/sdkconfig.defaults | 46 + .../ble_mesh_provisioner/CMakeLists.txt | 6 + .../ble_mesh_provisioner/Makefile | 10 + .../ble_mesh_provisioner/README.md | 10 + .../ble_mesh_provisioner/main/CMakeLists.txt | 15 + .../main/ble_mesh_adapter.c | 300 ++ .../main/ble_mesh_adapter.h | 123 + .../main/ble_mesh_cfg_srv_model.c | 205 + .../main/ble_mesh_cfg_srv_model.h | 107 + .../main/ble_mesh_console_decl.h | 38 + .../main/ble_mesh_console_lib.c | 124 + .../main/ble_mesh_console_lib.h | 29 + .../main/ble_mesh_console_main.c | 228 ++ .../main/ble_mesh_console_system.c | 179 + .../main/ble_mesh_reg_cfg_client_cmd.c | 390 ++ .../main/ble_mesh_reg_gen_onoff_client_cmd.c | 180 + .../main/ble_mesh_reg_test_perf_client_cmd.c | 219 + .../main/ble_mesh_register_node_cmd.c | 476 +++ .../main/ble_mesh_register_provisioner_cmd.c | 424 ++ .../ble_mesh_provisioner/main/component.mk | 5 + .../main/register_bluetooth.c | 45 + .../ble_mesh_provisioner/sdkconfig.defaults | 40 + .../ble_mesh_fast_prov_client/CMakeLists.txt | 8 + .../ble_mesh_fast_prov_client/Makefile | 12 + .../ble_mesh_fast_prov_client/README.md | 2 + .../main/CMakeLists.txt | 5 + .../main/ble_mesh_demo_main.c | 638 +++ .../main/component.mk | 4 + .../sdkconfig.defaults | 43 + .../ble_mesh_fast_provision_client.md | 218 + .../ble_mesh_fast_prov_server/CMakeLists.txt | 8 + .../ble_mesh_fast_prov_server/Makefile | 12 + .../ble_mesh_fast_prov_server/README.md | 2 + .../main/CMakeLists.txt | 6 + .../main/Kconfig.projbuild | 16 + .../main/ble_mesh_demo_main.c | 842 ++++ .../ble_mesh_fast_prov_server/main/board.c | 72 + .../ble_mesh_fast_prov_server/main/board.h | 47 + .../main/component.mk | 4 + .../sdkconfig.defaults | 51 + .../tutorial/EspBleMesh.md | 93 + .../ble_mesh_fast_provision_server.md | 409 ++ .../tutorial/images/app_ble.png | Bin 0 -> 182199 bytes .../tutorial/images/device.png | Bin 0 -> 356234 bytes .../tutorial/images/picture1.png | Bin 0 -> 73063 bytes .../tutorial/images/picture2.png | Bin 0 -> 69619 bytes .../tutorial/images/time.png | Bin 0 -> 56788 bytes .../ble_mesh/ble_mesh_node/CMakeLists.txt | 6 + .../bluetooth/ble_mesh/ble_mesh_node/Makefile | 10 + .../ble_mesh/ble_mesh_node/README.md | 16 + .../ble_mesh_node/main/CMakeLists.txt | 6 + .../ble_mesh_node/main/Kconfig.projbuild | 22 + .../ble_mesh_node/main/ble_mesh_demo_main.c | 395 ++ .../ble_mesh/ble_mesh_node/main/board.c | 130 + .../ble_mesh/ble_mesh_node/main/board.h | 42 + .../ble_mesh/ble_mesh_node/main/component.mk | 4 + .../ble_mesh/ble_mesh_node/sdkconfig.defaults | 43 + .../Ble_Mesh_Node_Example_Walkthrough.md | 471 +++ .../ble_mesh_provisioner/CMakeLists.txt | 6 + .../ble_mesh/ble_mesh_provisioner/Makefile | 10 + .../ble_mesh/ble_mesh_provisioner/README.md | 6 + .../ble_mesh_provisioner/main/CMakeLists.txt | 5 + .../main/ble_mesh_demo_main.c | 691 ++++ .../ble_mesh_provisioner/main/component.mk | 4 + .../ble_mesh_provisioner/sdkconfig.defaults | 40 + ...le_Mesh_Provisioner_Example_Walkthrough.md | 129 + .../fast_prov_vendor_model/CMakeLists.txt | 6 + .../fast_prov_vendor_model/Makefile | 10 + .../components/CMakeLists.txt | 9 + .../components/component.mk | 6 + .../components/esp_fast_prov_client_model.c | 407 ++ .../components/esp_fast_prov_client_model.h | 36 + .../components/esp_fast_prov_common.h | 121 + .../components/esp_fast_prov_operation.c | 577 +++ .../components/esp_fast_prov_operation.h | 69 + .../components/esp_fast_prov_server_model.c | 640 +++ .../components/esp_fast_prov_server_model.h | 102 + .../main/CMakeLists.txt | 3 + .../fast_prov_vendor_model/main/component.mk | 5 + .../fast_prov_vendor_model/main/main.c | 21 + .../fast_prov_vendor_model/sdkconfig.defaults | 33 + .../ble_mesh_wifi_coexist/CMakeLists.txt | 8 + .../ble_mesh/ble_mesh_wifi_coexist/Makefile | 12 + .../ble_mesh/ble_mesh_wifi_coexist/README.md | 20 + .../components/iperf/CMakeLists.txt | 8 + .../components/iperf/cmd_decl.h | 14 + .../components/iperf/cmd_wifi.c | 477 +++ .../components/iperf/component.mk | 11 + .../components/iperf/iperf.c | 461 +++ .../components/iperf/iperf.h | 61 + .../ble_mesh_wifi_coexist/main/CMakeLists.txt | 6 + .../main/Kconfig.projbuild | 16 + .../main/ble_mesh_demo_main.c | 977 +++++ .../ble_mesh_wifi_coexist/main/board.c | 72 + .../ble_mesh_wifi_coexist/main/board.h | 47 + .../ble_mesh_wifi_coexist/main/component.mk | 5 + .../ble_mesh_wifi_coexist/partitions.csv | 6 + .../ble_mesh_wifi_coexist/sdkconfig.defaults | 82 + .../tutorial/ble_mesh_wifi_coexist.md | 301 ++ 260 files changed, 71487 insertions(+), 1 deletion(-) create mode 100644 components/bt/ble_mesh/api/core/esp_ble_mesh_common_api.c create mode 100644 components/bt/ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c create mode 100644 components/bt/ble_mesh/api/core/esp_ble_mesh_low_power_api.c create mode 100644 components/bt/ble_mesh/api/core/esp_ble_mesh_networking_api.c create mode 100644 components/bt/ble_mesh/api/core/esp_ble_mesh_provisioning_api.c create mode 100644 components/bt/ble_mesh/api/core/esp_ble_mesh_proxy_api.c create mode 100644 components/bt/ble_mesh/api/core/include/esp_ble_mesh_common_api.h create mode 100644 components/bt/ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h create mode 100644 components/bt/ble_mesh/api/core/include/esp_ble_mesh_low_power_api.h create mode 100644 components/bt/ble_mesh/api/core/include/esp_ble_mesh_networking_api.h create mode 100644 components/bt/ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h create mode 100644 components/bt/ble_mesh/api/core/include/esp_ble_mesh_proxy_api.h create mode 100644 components/bt/ble_mesh/api/esp_ble_mesh_defs.h create mode 100644 components/bt/ble_mesh/api/models/esp_ble_mesh_config_model_api.c create mode 100644 components/bt/ble_mesh/api/models/esp_ble_mesh_generic_model_api.c create mode 100644 components/bt/ble_mesh/api/models/esp_ble_mesh_health_model_api.c create mode 100644 components/bt/ble_mesh/api/models/esp_ble_mesh_lighting_model_api.c create mode 100644 components/bt/ble_mesh/api/models/esp_ble_mesh_sensor_model_api.c create mode 100644 components/bt/ble_mesh/api/models/esp_ble_mesh_time_scene_model_api.c create mode 100644 components/bt/ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h create mode 100644 components/bt/ble_mesh/api/models/include/esp_ble_mesh_generic_model_api.h create mode 100644 components/bt/ble_mesh/api/models/include/esp_ble_mesh_health_model_api.h create mode 100644 components/bt/ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h create mode 100644 components/bt/ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h create mode 100644 components/bt/ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h create mode 100644 components/bt/ble_mesh/btc/btc_ble_mesh_config_model.c create mode 100644 components/bt/ble_mesh/btc/btc_ble_mesh_generic_model.c create mode 100644 components/bt/ble_mesh/btc/btc_ble_mesh_health_model.c create mode 100644 components/bt/ble_mesh/btc/btc_ble_mesh_lighting_model.c create mode 100644 components/bt/ble_mesh/btc/btc_ble_mesh_prov.c create mode 100644 components/bt/ble_mesh/btc/btc_ble_mesh_sensor_model.c create mode 100644 components/bt/ble_mesh/btc/btc_ble_mesh_time_scene_model.c create mode 100644 components/bt/ble_mesh/btc/include/btc_ble_mesh_config_model.h create mode 100644 components/bt/ble_mesh/btc/include/btc_ble_mesh_generic_model.h create mode 100644 components/bt/ble_mesh/btc/include/btc_ble_mesh_health_model.h create mode 100644 components/bt/ble_mesh/btc/include/btc_ble_mesh_lighting_model.h create mode 100644 components/bt/ble_mesh/btc/include/btc_ble_mesh_prov.h create mode 100644 components/bt/ble_mesh/btc/include/btc_ble_mesh_sensor_model.h create mode 100644 components/bt/ble_mesh/btc/include/btc_ble_mesh_time_scene_model.h create mode 100644 components/bt/ble_mesh/mesh_core/access.c create mode 100644 components/bt/ble_mesh/mesh_core/access.h create mode 100644 components/bt/ble_mesh/mesh_core/adv.c create mode 100644 components/bt/ble_mesh/mesh_core/adv.h create mode 100644 components/bt/ble_mesh/mesh_core/beacon.c create mode 100644 components/bt/ble_mesh/mesh_core/beacon.h create mode 100644 components/bt/ble_mesh/mesh_core/cfg_cli.c create mode 100644 components/bt/ble_mesh/mesh_core/cfg_srv.c create mode 100644 components/bt/ble_mesh/mesh_core/crypto.c create mode 100644 components/bt/ble_mesh/mesh_core/crypto.h create mode 100644 components/bt/ble_mesh/mesh_core/foundation.h create mode 100644 components/bt/ble_mesh/mesh_core/friend.c create mode 100644 components/bt/ble_mesh/mesh_core/friend.h create mode 100644 components/bt/ble_mesh/mesh_core/health_cli.c create mode 100644 components/bt/ble_mesh/mesh_core/health_srv.c create mode 100644 components/bt/ble_mesh/mesh_core/include/cfg_cli.h create mode 100644 components/bt/ble_mesh/mesh_core/include/cfg_srv.h create mode 100644 components/bt/ble_mesh/mesh_core/include/health_cli.h create mode 100644 components/bt/ble_mesh/mesh_core/include/health_srv.h create mode 100644 components/bt/ble_mesh/mesh_core/include/mesh_access.h create mode 100644 components/bt/ble_mesh/mesh_core/include/mesh_aes_encrypt.h create mode 100644 components/bt/ble_mesh/mesh_core/include/mesh_atomic.h create mode 100644 components/bt/ble_mesh/mesh_core/include/mesh_bearer_adapt.h create mode 100644 components/bt/ble_mesh/mesh_core/include/mesh_buf.h create mode 100644 components/bt/ble_mesh/mesh_core/include/mesh_dlist.h create mode 100644 components/bt/ble_mesh/mesh_core/include/mesh_hci.h create mode 100644 components/bt/ble_mesh/mesh_core/include/mesh_kernel.h create mode 100644 components/bt/ble_mesh/mesh_core/include/mesh_main.h create mode 100644 components/bt/ble_mesh/mesh_core/include/mesh_proxy.h create mode 100644 components/bt/ble_mesh/mesh_core/include/mesh_slist.h create mode 100644 components/bt/ble_mesh/mesh_core/include/mesh_trace.h create mode 100644 components/bt/ble_mesh/mesh_core/include/mesh_types.h create mode 100644 components/bt/ble_mesh/mesh_core/include/mesh_util.h create mode 100644 components/bt/ble_mesh/mesh_core/include/mesh_uuid.h create mode 100644 components/bt/ble_mesh/mesh_core/lpn.c create mode 100644 components/bt/ble_mesh/mesh_core/lpn.h create mode 100644 components/bt/ble_mesh/mesh_core/mesh.h create mode 100644 components/bt/ble_mesh/mesh_core/mesh_aes_encrypt.c create mode 100644 components/bt/ble_mesh/mesh_core/mesh_atomic.c create mode 100644 components/bt/ble_mesh/mesh_core/mesh_bearer_adapt.c create mode 100644 components/bt/ble_mesh/mesh_core/mesh_buf.c create mode 100644 components/bt/ble_mesh/mesh_core/mesh_hci.c create mode 100644 components/bt/ble_mesh/mesh_core/mesh_kernel.c create mode 100644 components/bt/ble_mesh/mesh_core/mesh_main.c create mode 100644 components/bt/ble_mesh/mesh_core/mesh_util.c create mode 100644 components/bt/ble_mesh/mesh_core/net.c create mode 100644 components/bt/ble_mesh/mesh_core/net.h create mode 100644 components/bt/ble_mesh/mesh_core/prov.c create mode 100644 components/bt/ble_mesh/mesh_core/prov.h create mode 100644 components/bt/ble_mesh/mesh_core/provisioner_beacon.c create mode 100644 components/bt/ble_mesh/mesh_core/provisioner_beacon.h create mode 100644 components/bt/ble_mesh/mesh_core/provisioner_main.c create mode 100644 components/bt/ble_mesh/mesh_core/provisioner_main.h create mode 100644 components/bt/ble_mesh/mesh_core/provisioner_prov.c create mode 100644 components/bt/ble_mesh/mesh_core/provisioner_prov.h create mode 100644 components/bt/ble_mesh/mesh_core/provisioner_proxy.c create mode 100644 components/bt/ble_mesh/mesh_core/provisioner_proxy.h create mode 100644 components/bt/ble_mesh/mesh_core/proxy.c create mode 100644 components/bt/ble_mesh/mesh_core/proxy.h create mode 100644 components/bt/ble_mesh/mesh_core/settings.c create mode 100644 components/bt/ble_mesh/mesh_core/settings.h create mode 100644 components/bt/ble_mesh/mesh_core/settings/settings_nvs.c create mode 100644 components/bt/ble_mesh/mesh_core/settings/settings_nvs.h create mode 100644 components/bt/ble_mesh/mesh_core/test.c create mode 100644 components/bt/ble_mesh/mesh_core/test.h create mode 100644 components/bt/ble_mesh/mesh_core/transport.c create mode 100644 components/bt/ble_mesh/mesh_core/transport.h create mode 100644 components/bt/ble_mesh/mesh_docs/BLE-Mesh_FAQs_EN.md create mode 100644 components/bt/ble_mesh/mesh_docs/BLE-Mesh_Feature_List_EN.md create mode 100644 components/bt/ble_mesh/mesh_docs/BLE-Mesh_Getting_Started_EN.md create mode 100644 components/bt/ble_mesh/mesh_docs/BLE-Mesh_Known_Issues_EN.md create mode 100644 components/bt/ble_mesh/mesh_docs/README.md create mode 100644 components/bt/ble_mesh/mesh_models/generic_client.c create mode 100644 components/bt/ble_mesh/mesh_models/include/generic_client.h create mode 100644 components/bt/ble_mesh/mesh_models/include/lighting_client.h create mode 100644 components/bt/ble_mesh/mesh_models/include/mesh_common.h create mode 100644 components/bt/ble_mesh/mesh_models/include/model_common.h create mode 100644 components/bt/ble_mesh/mesh_models/include/model_opcode.h create mode 100644 components/bt/ble_mesh/mesh_models/include/sensor_client.h create mode 100644 components/bt/ble_mesh/mesh_models/include/time_scene_client.h create mode 100644 components/bt/ble_mesh/mesh_models/lighting_client.c create mode 100644 components/bt/ble_mesh/mesh_models/mesh_common.c create mode 100644 components/bt/ble_mesh/mesh_models/model_common.c create mode 100644 components/bt/ble_mesh/mesh_models/sensor_client.c create mode 100644 components/bt/ble_mesh/mesh_models/time_scene_client.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_client_model/CMakeLists.txt create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_client_model/Makefile create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_client_model/README.md create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_client_model/main/CMakeLists.txt create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_client_model/main/Kconfig.projbuild create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_client_model/main/ble_mesh_demo_main.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_client_model/main/board.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_client_model/main/board.h create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_client_model/main/component.mk create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_client_model/sdkconfig.defaults create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/ble_mesh_client_model.md create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/images/app.png create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/images/message.png create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/images/picture5.png create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/CMakeLists.txt create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/Makefile create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/README.md create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/CMakeLists.txt create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.h create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.h create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_decl.h create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.h create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_system.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_server_cmd.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/component.mk create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/sdkconfig.defaults create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/CMakeLists.txt create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/Makefile create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/README.md create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/CMakeLists.txt create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.h create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.h create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_decl.h create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.h create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_system.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_cfg_client_cmd.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_gen_onoff_client_cmd.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_test_perf_client_cmd.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/component.mk create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/register_bluetooth.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/sdkconfig.defaults create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/CMakeLists.txt create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/Makefile create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/README.md create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/CMakeLists.txt create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/ble_mesh_demo_main.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/component.mk create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/sdkconfig.defaults create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/tutorial/ble_mesh_fast_provision_client.md create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/CMakeLists.txt create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/Makefile create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/README.md create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/CMakeLists.txt create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/Kconfig.projbuild create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/ble_mesh_demo_main.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.h create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/component.mk create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/sdkconfig.defaults create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/EspBleMesh.md create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/ble_mesh_fast_provision_server.md create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/app_ble.png create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/device.png create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/picture1.png create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/picture2.png create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/time.png create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_node/CMakeLists.txt create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_node/Makefile create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_node/README.md create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_node/main/CMakeLists.txt create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_node/main/Kconfig.projbuild create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_node/main/ble_mesh_demo_main.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_node/main/board.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_node/main/board.h create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_node/main/component.mk create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_node/sdkconfig.defaults create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_node/tutorial/Ble_Mesh_Node_Example_Walkthrough.md create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_provisioner/CMakeLists.txt create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_provisioner/Makefile create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_provisioner/README.md create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_provisioner/main/CMakeLists.txt create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_provisioner/main/ble_mesh_demo_main.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_provisioner/main/component.mk create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_provisioner/sdkconfig.defaults create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_provisioner/tutorial/Ble_Mesh_Provisioner_Example_Walkthrough.md create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/CMakeLists.txt create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/Makefile create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/CMakeLists.txt create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/component.mk create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.h create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_common.h create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.h create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.h create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/CMakeLists.txt create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/component.mk create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/main.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/sdkconfig.defaults create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/CMakeLists.txt create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/Makefile create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/README.md create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/CMakeLists.txt create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/cmd_decl.h create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/cmd_wifi.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/component.mk create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/iperf.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/iperf.h create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/main/CMakeLists.txt create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/main/Kconfig.projbuild create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/main/ble_mesh_demo_main.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/main/board.c create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/main/board.h create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/main/component.mk create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/partitions.csv create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/sdkconfig.defaults create mode 100644 examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/tutorial/ble_mesh_wifi_coexist.md diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index 73f6879039..58ccb27a82 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -287,6 +287,75 @@ if(CONFIG_BT_ENABLED) endif() endif() +if (CONFIG_BLE_MESH) + list(APPEND COMPONENT_ADD_INCLUDEDIRS + "bluedroid/osi/include" + "ble_mesh/mesh_core" + "ble_mesh/mesh_core/include" + "ble_mesh/mesh_core/settings" + "ble_mesh/btc/include" + "ble_mesh/mesh_models/include" + "ble_mesh/api/core/include" + "ble_mesh/api/models/include" + "ble_mesh/api") + + list(APPEND COMPONENT_SRCS + "ble_mesh/api/core/esp_ble_mesh_common_api.c" + "ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c" + "ble_mesh/api/core/esp_ble_mesh_low_power_api.c" + "ble_mesh/api/core/esp_ble_mesh_networking_api.c" + "ble_mesh/api/core/esp_ble_mesh_provisioning_api.c" + "ble_mesh/api/core/esp_ble_mesh_proxy_api.c" + "ble_mesh/api/models/esp_ble_mesh_config_model_api.c" + "ble_mesh/api/models/esp_ble_mesh_generic_model_api.c" + "ble_mesh/api/models/esp_ble_mesh_health_model_api.c" + "ble_mesh/api/models/esp_ble_mesh_lighting_model_api.c" + "ble_mesh/api/models/esp_ble_mesh_sensor_model_api.c" + "ble_mesh/api/models/esp_ble_mesh_time_scene_model_api.c" + "ble_mesh/btc/btc_ble_mesh_config_model.c" + "ble_mesh/btc/btc_ble_mesh_generic_model.c" + "ble_mesh/btc/btc_ble_mesh_health_model.c" + "ble_mesh/btc/btc_ble_mesh_lighting_model.c" + "ble_mesh/btc/btc_ble_mesh_prov.c" + "ble_mesh/btc/btc_ble_mesh_sensor_model.c" + "ble_mesh/btc/btc_ble_mesh_time_scene_model.c" + "ble_mesh/mesh_core/settings/settings_nvs.c" + "ble_mesh/mesh_core/access.c" + "ble_mesh/mesh_core/adv.c" + "ble_mesh/mesh_core/beacon.c" + "ble_mesh/mesh_core/cfg_cli.c" + "ble_mesh/mesh_core/cfg_srv.c" + "ble_mesh/mesh_core/crypto.c" + "ble_mesh/mesh_core/friend.c" + "ble_mesh/mesh_core/health_cli.c" + "ble_mesh/mesh_core/health_srv.c" + "ble_mesh/mesh_core/lpn.c" + "ble_mesh/mesh_core/mesh_aes_encrypt.c" + "ble_mesh/mesh_core/mesh_atomic.c" + "ble_mesh/mesh_core/mesh_bearer_adapt.c" + "ble_mesh/mesh_core/mesh_buf.c" + "ble_mesh/mesh_core/mesh_hci.c" + "ble_mesh/mesh_core/mesh_kernel.c" + "ble_mesh/mesh_core/mesh_main.c" + "ble_mesh/mesh_core/mesh_util.c" + "ble_mesh/mesh_core/net.c" + "ble_mesh/mesh_core/prov.c" + "ble_mesh/mesh_core/provisioner_beacon.c" + "ble_mesh/mesh_core/provisioner_main.c" + "ble_mesh/mesh_core/provisioner_prov.c" + "ble_mesh/mesh_core/provisioner_proxy.c" + "ble_mesh/mesh_core/proxy.c" + "ble_mesh/mesh_core/settings.c" + "ble_mesh/mesh_core/test.c" + "ble_mesh/mesh_core/transport.c" + "ble_mesh/mesh_models/generic_client.c" + "ble_mesh/mesh_models/lighting_client.c" + "ble_mesh/mesh_models/mesh_common.c" + "ble_mesh/mesh_models/model_common.c" + "ble_mesh/mesh_models/sensor_client.c" + "ble_mesh/mesh_models/time_scene_client.c") +endif() + # requirements can't depend on config set(COMPONENT_PRIV_REQUIRES nvs_flash soc) diff --git a/components/bt/Kconfig b/components/bt/Kconfig index d292e66c20..daf83b1be7 100644 --- a/components/bt/Kconfig +++ b/components/bt/Kconfig @@ -1352,3 +1352,814 @@ menu Bluetooth default 0 endmenu + +menuconfig BLE_MESH + bool "BLE Mesh Support" + help + This option enables BLE Mesh support. The specific features that are + available may depend on other features that have been enabled in the + stack, such as Bluetooth Support, Bluedroid Support & GATT support. + +if BLE_MESH + + config BLE_MESH_HCI_5_0 + bool "Support sending 20ms non-connectable adv packets" + default y + help + It is a temporary solution and needs further modifications. + + config BLE_MESH_USE_DUPLICATE_SCAN + bool "Support Duplicate Scan in BLE Mesh" + select BLE_SCAN_DUPLICATE + select BLE_MESH_SCAN_DUPLICATE_EN + default y + help + Enable this option to allow using specific duplicate scan filter + in BLE Mesh, and Scan Duplicate Type must be set to 0x02. + + config BLE_MESH_FAST_PROV + bool "Enable BLE Mesh Fast Provisioning" + select BLE_MESH_NODE + select BLE_MESH_PROVISIONER + select BLE_MESH_PB_ADV + default n + help + Enable this option to allow BLE Mesh fast provisioning solution to be used. + + config BLE_MESH_NODE + bool "Support for BLE Mesh Node" + help + Enable the device to be provisioned into a node. + + config BLE_MESH_PROVISIONER + bool "Support for BLE Mesh Provisioner" + help + Enable the device to be a provisioner. + + if BLE_MESH_PROVISIONER + + config BLE_MESH_WAIT_FOR_PROV_MAX_DEV_NUM + int "Maximum number of unprovisioned devices that can be added to device queue" + default 20 + range 1 100 + help + This option specifies how may unprovisioned devices can be added to device + queue for provisioning. + + config BLE_MESH_MAX_STORED_NODES + int "Maximum number of nodes whose information can be stored" + default 20 + range 1 1000 + help + This option specifies the maximum number of nodes whose information can be + stored by a provisioner in its upper layer. + + config BLE_MESH_MAX_PROV_NODES + int "Maximum number of devices that can be provisioned by provisioner" + default 20 + range 1 100 + help + This option specifies how many devices can be provisioned by provisioner. + + if BLE_MESH_PB_ADV + config BLE_MESH_PBA_SAME_TIME + int "Maximum number of PB-ADV running at the same time by provisioner" + default 2 + range 1 10 + help + This option specifies how many devices can be provisioned at the same + time using PB-ADV. + endif # BLE_MESH_PB_ADV + + if BLE_MESH_PB_GATT + config BLE_MESH_PBG_SAME_TIME + int "Maximum number of PB-GATT running at the same time by provisioner" + default 1 + range 1 5 + help + This option specifies how many devices can be provisioned at the same + time using PB-GATT. + endif # BLE_MESH_PB_GATT + + config BLE_MESH_PROVISIONER_SUBNET_COUNT + int "Maximum number of mesh subnets that can be created by provisioner" + default 3 + range 1 4096 + help + This option specifies how many subnets per network a provisioner can create. + + config BLE_MESH_PROVISIONER_APP_KEY_COUNT + int "Maximum number of application keys that can be owned by provisioner" + default 9 + range 1 4096 + help + This option specifies how many application keys the provisioner can have. + + endif # BLE_MESH_PROVISIONER + + # Virtual option enabled whenever Generic Provisioning layer is needed + config BLE_MESH_PROV + bool "BLE Mesh Provisioning support" + default y + help + Enable this option to support BLE Mesh Provisioning functionality. For + BLE Mesh, this option should be always enabled. + + config BLE_MESH_PB_ADV + bool "Provisioning support using the advertising bearer (PB-ADV)" + select BLE_MESH_PROV + default y + help + Enable this option to allow the device to be provisioned over the + advertising bearer. + + config BLE_MESH_PB_GATT + bool "Provisioning support using GATT (PB-GATT)" + select BLE_MESH_PROXY + select BLE_MESH_PROV + help + Enable this option to allow the device to be provisioned over GATT. + + # Virtual option enabled whenever any Proxy protocol is needed + config BLE_MESH_PROXY + bool "BLE Mesh Proxy protocol support" + default y + help + Enable this option to support BLE Mesh Proxy protocol used by PB-GATT + and other proxy pdu transmission. + + config BLE_MESH_GATT_PROXY + bool "BLE Mesh GATT Proxy Service" + select BLE_MESH_PROXY + help + This option enables support for Mesh GATT Proxy Service, i.e. the + ability to act as a proxy between a Mesh GATT Client and a Mesh network. + + config BLE_MESH_NODE_ID_TIMEOUT + int "Node Identity advertising timeout" + depends on BLE_MESH_GATT_PROXY + range 1 60 + default 60 + help + This option determines for how long the local node advertises using + Node Identity. The given value is in seconds. The specification limits + this to 60 seconds and lists it as the recommended value as well. + So leaving the default value is the safest option. + + if BLE_MESH_PROXY + + config BLE_MESH_PROXY_FILTER_SIZE + int "Maximum number of filter entries per Proxy Client" + default 1 + default 3 if BLE_MESH_GATT_PROXY + range 1 32767 + help + This option specifies how many Proxy Filter entries the local node supports. + + endif # BLE_MESH_PROXY + + config BLE_MESH_NET_BUF_POOL_USAGE + bool "BLE Mesh net buffer pool usage tracking" + default y + help + Enable BLE Mesh net buffer pool tracking. + + config BLE_MESH_SETTINGS + bool "Store BLE Mesh Node configuration persistently" + default n + help + When selected, the BLE Mesh stack will take care of storing/restoring the + BLE Mesh configuration persistently in flash. Currently this only supports + storing BLE Mesh node configuration. + + if BLE_MESH_SETTINGS + config BLE_MESH_STORE_TIMEOUT + int "Delay (in seconds) before storing anything persistently" + range 0 1000000 + default 0 + help + This value defines in seconds how soon any pending changes are actually + written into persistent storage (flash) after a change occurs. + + config BLE_MESH_SEQ_STORE_RATE + int "How often the sequence number gets updated in storage" + range 0 1000000 + default 128 + help + This value defines how often the local sequence number gets updated in + persistent storage (i.e. flash). e.g. a value of 100 means that the + sequence number will be stored to flash on every 100th increment. + If the node sends messages very frequently a higher value makes more + sense, whereas if the node sends infrequently a value as low as 0 + (update storage for every increment) can make sense. When the stack + gets initialized it will add sequence number to the last stored one, + so that it starts off with a value that's guaranteed to be larger than + the last one used before power off. + + config BLE_MESH_RPL_STORE_TIMEOUT + int "Minimum frequency that the RPL gets updated in storage" + range 0 1000000 + default 5 + help + This value defines in seconds how soon the RPL(Replay Protection List) + gets written to persistent storage after a change occurs. If the node + receives messages frequently, then a large value is recommended. If the + node receives messages rarely, then the value can be as low as 0 (which + means the PRL is written into the storage immediately). + Note that if the node operates in a security-sensitive case, and there is + a risk of sudden power-off, then a value of 0 is strongly recommended. + Otherwise, a power loss before RPL being written into the storage may + introduce message replay attacks and system security will be in a + vulnerable state. + endif # if BLE_MESH_SETTINGS + + config BLE_MESH_SUBNET_COUNT + int "Maximum number of mesh subnets per network" + default 3 + range 1 4096 + help + This option specifies how many subnets a Mesh network can have at the same time. + + config BLE_MESH_APP_KEY_COUNT + int "Maximum number of application keys per network" + default 3 + range 1 4096 + help + This option specifies how many application keys the device can store per network. + + config BLE_MESH_MODEL_KEY_COUNT + int "Maximum number of application keys per model" + default 3 + range 1 4096 + help + This option specifies the maximum number of application keys to which each model + can be bound. + + config BLE_MESH_MODEL_GROUP_COUNT + int "Maximum number of group address subscriptions per model" + default 3 + range 1 4096 + help + This option specifies the maximum number of addresses to which each model can + be subscribed. + + config BLE_MESH_LABEL_COUNT + int "Maximum number of Label UUIDs used for Virtual Addresses" + default 3 + range 0 4096 + help + This option specifies how many Label UUIDs can be stored. + + config BLE_MESH_CRPL + int "Maximum capacity of the replay protection list" + default 10 + range 2 65535 + help + This option specifies the maximum capacity of the replay protection list. + It is similar to Network message cache size, but has a different purpose. + + config BLE_MESH_MSG_CACHE_SIZE + int "Network message cache size" + default 10 + range 2 65535 + help + Number of messages that are cached for the network. This helps prevent + unnecessary decryption operations and unnecessary relays. This option + is similar to Replay protection list, but has a different purpose. + + config BLE_MESH_ADV_BUF_COUNT + int "Number of advertising buffers" + default 60 + range 6 256 + help + Number of advertising buffers available. The transport layer reserves + ADV_BUF_COUNT - 3 buffers for outgoing segments. The maximum outgoing + SDU size is 12 times this value (out of which 4 or 8 bytes are used + for the Transport Layer MIC). For example, 5 segments means the maximum + SDU size is 60 bytes, which leaves 56 bytes for application layer data + using a 4-byte MIC, or 52 bytes using an 8-byte MIC. + + config BLE_MESH_IVU_DIVIDER + int "Divider for IV Update state refresh timer" + default 4 + range 2 96 + help + When the IV Update state enters Normal operation or IV Update + in Progress, we need to keep track of how many hours has passed + in the state, since the specification requires us to remain in + the state at least for 96 hours (Update in Progress has an + additional upper limit of 144 hours). + + In order to fulfill the above requirement, even if the node might + be powered off once in a while, we need to store persistently + how many hours the node has been in the state. This doesn't + necessarily need to happen every hour (thanks to the flexible + duration range). The exact cadence will depend a lot on the + ways that the node will be used and what kind of power source it + has. + + Since there is no single optimal answer, this configuration + option allows specifying a divider, i.e. how many intervals + the 96 hour minimum gets split into. After each interval the + duration that the node has been in the current state gets + stored to flash. E.g. the default value of 4 means that the + state is saved every 24 hours (96 / 4). + + config BLE_MESH_TX_SEG_MSG_COUNT + int "Maximum number of simultaneous outgoing segmented messages" + default 1 + range 1 BLE_MESH_ADV_BUF_COUNT + help + Maximum number of simultaneous outgoing multi-segment and/or reliable messages. + + config BLE_MESH_RX_SEG_MSG_COUNT + int "Maximum number of simultaneous incoming segmented messages" + default 1 + range 1 255 + help + Maximum number of simultaneous incoming multi-segment and/or reliable messages. + + config BLE_MESH_RX_SDU_MAX + int "Maximum incoming Upper Transport Access PDU length" + default 384 + range 36 384 + help + Maximum incoming Upper Transport Access PDU length. Leave this to the default + value, unless you really need to optimize memory usage. + + config BLE_MESH_TX_SEG_MAX + int "Maximum number of segments in outgoing messages" + default 20 + range 2 32 + help + Maximum number of segments supported for outgoing messages. + This value should typically be fine-tuned based on what + models the local node supports, i.e. what's the largest + message payload that the node needs to be able to send. + This value affects memory and call stack consumption, which + is why the default is lower than the maximum that the + specification would allow (32 segments). + + The maximum outgoing SDU size is 12 times this number (out of + which 4 or 8 bytes is used for the Transport Layer MIC). For + example, 5 segments means the maximum SDU size is 60 bytes, + which leaves 56 bytes for application layer data using a + 4-byte MIC and 52 bytes using an 8-byte MIC. + + Be sure to specify a sufficient number of advertising buffers + when setting this option to a higher value. There must be at + least three more advertising buffers (BLE_MESH_ADV_BUF_COUNT) + as there are outgoing segments. + + config BLE_MESH_RELAY + bool "Relay support" + help + Support for acting as a Mesh Relay Node. + + config BLE_MESH_LOW_POWER + bool "Support for Low Power features" + help + Enable this option to operate as a Low Power Node. + + if BLE_MESH_LOW_POWER + + config BLE_MESH_LPN_ESTABLISHMENT + bool "Perform Friendship establishment using low power" + default y + help + Perform the Friendship establishment using low power with the help of a + reduced scan duty cycle. The downside of this is that the node may miss + out on messages intended for it until it has successfully set up Friendship + with a Friend node. + + config BLE_MESH_LPN_AUTO + bool "Automatically start looking for Friend nodes once provisioned" + default y + help + Once provisioned, automatically enable LPN functionality and start looking + for Friend nodes. If this option is disabled LPN mode needs to be manually + enabled by calling bt_mesh_lpn_set(true). + + config BLE_MESH_LPN_AUTO_TIMEOUT + int "Time from last received message before going to LPN mode" + default 15 + range 0 3600 + depends on BLE_MESH_LPN_AUTO + help + Time in seconds from the last received message, that the node waits out + before starting to look for Friend nodes. + + config BLE_MESH_LPN_RETRY_TIMEOUT + int "Retry timeout for Friend requests" + default 8 + range 1 3600 + help + Time in seconds between Friend Requests, if a previous Friend Request did + not yield any acceptable Friend Offers. + + config BLE_MESH_LPN_RSSI_FACTOR + int "RSSIFactor, used in Friend Offer Delay calculation" + range 0 3 + default 0 + help + The contribution of the RSSI, measured by the Friend node, used in Friend + Offer Delay calculations. 0 = 1, 1 = 1.5, 2 = 2, 3 = 2.5. + + config BLE_MESH_LPN_RECV_WIN_FACTOR + int "ReceiveWindowFactor, used in Friend Offer Delay calculation" + range 0 3 + default 0 + help + The contribution of the supported Receive Window used in Friend Offer + Delay calculations. 0 = 1, 1 = 1.5, 2 = 2, 3 = 2.5. + + config BLE_MESH_LPN_MIN_QUEUE_SIZE + int "Minimum size of the acceptable friend queue (MinQueueSizeLog)" + range 1 7 + default 1 + help + The MinQueueSizeLog field is defined as log_2(N), where N is the minimum + number of maximum size Lower Transport PDUs that the Friend node can store + in its Friend Queue. As an example, MinQueueSizeLog value 1 gives N = 2, + and value 7 gives N = 128. + + config BLE_MESH_LPN_RECV_DELAY + int "Receive delay requested by the local node" + range 10 255 + default 100 + help + The ReceiveDelay is the time between the Low Power node sending a + request and listening for a response. This delay allows the Friend + node time to prepare the response. The value is in units of milliseconds. + + config BLE_MESH_LPN_POLL_TIMEOUT + int "The value of the PollTimeout timer" + range 10 244735 + default 300 + help + PollTimeout timer is used to measure time between two consecutive + requests sent by a Low Power node. If no requests are received + the Friend node before the PollTimeout timer expires, then the + friendship is considered terminated. The value is in units of 100 + milliseconds, so e.g. a value of 300 means 30 seconds. + + config BLE_MESH_LPN_INIT_POLL_TIMEOUT + int "The starting value of the PollTimeout timer" + range 10 BLE_MESH_LPN_POLL_TIMEOUT + default BLE_MESH_LPN_POLL_TIMEOUT + help + The initial value of the PollTimeout timer when Friendship is to be + established for the first time. After this, the timeout gradually + grows toward the actual PollTimeout, doubling in value for each iteration. + The value is in units of 100 milliseconds, so e.g. a value of 300 means + 30 seconds. + + config BLE_MESH_LPN_SCAN_LATENCY + int "Latency for enabling scanning" + range 0 50 + default 10 + help + Latency (in milliseconds) is the time it takes to enable scanning. In + practice, it means how much time in advance of the Receive Window, the + request to enable scanning is made. + + config BLE_MESH_LPN_GROUPS + int "Number of groups the LPN can subscribe to" + range 0 16384 + default 8 + help + Maximum number of groups to which the LPN can subscribe. + endif # BLE_MESH_LOW_POWER + + config BLE_MESH_FRIEND + bool "Support for acting as a Friend Node" + help + Enable this option to be able to act as a Friend Node. + + if BLE_MESH_FRIEND + + config BLE_MESH_FRIEND_RECV_WIN + int "Friend Receive Window" + range 1 255 + default 255 + help + Receive Window in milliseconds supported by the Friend node. + + config BLE_MESH_FRIEND_QUEUE_SIZE + int "Minimum number of buffers supported per Friend Queue" + range 2 65536 + default 16 + help + Minimum number of buffers available to be stored for each local Friend Queue. + + config BLE_MESH_FRIEND_SUB_LIST_SIZE + int "Friend Subscription List Size" + range 0 1023 + default 3 + help + Size of the Subscription List that can be supported by a Friend node for a + Low Power node. + + config BLE_MESH_FRIEND_LPN_COUNT + int "Number of supported LPN nodes" + range 1 1000 + default 2 + help + Number of Low Power Nodes with which a Friend can have Friendship simultaneously. + + config BLE_MESH_FRIEND_SEG_RX + int "Number of incomplete segment lists per LPN" + range 1 1000 + default 1 + help + Number of incomplete segment lists tracked for each Friends' LPN. + In other words, this determines from how many elements can segmented + messages destined for the Friend queue be received simultaneously. + + endif # BLE_MESH_FRIEND + + config BLE_MESH_NO_LOG + bool "Disable BLE Mesh debug logs (minimize bin size)" + depends on BLE_MESH + default n + help + Select this to save the BLE Mesh related rodata code size. + + menu "BLE Mesh STACK DEBUG LOG LEVEL" + depends on BLE_MESH && !BLE_MESH_NO_LOG + + choice BLE_MESH_STACK_TRACE_LEVEL + prompt "BLE_MESH_STACK" + default BLE_MESH_TRACE_LEVEL_WARNING + depends on BLE_MESH && !BLE_MESH_NO_LOG + help + Define BLE Mesh trace level for BLE Mesh stack. + + config BLE_MESH_TRACE_LEVEL_NONE + bool "NONE" + config BLE_MESH_TRACE_LEVEL_ERROR + bool "ERROR" + config BLE_MESH_TRACE_LEVEL_WARNING + bool "WARNING" + config BLE_MESH_TRACE_LEVEL_INFO + bool "INFO" + config BLE_MESH_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BLE_MESH_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BLE_MESH_STACK_TRACE_LEVEL + int + depends on BLE_MESH + default 0 if BLE_MESH_TRACE_LEVEL_NONE + default 1 if BLE_MESH_TRACE_LEVEL_ERROR + default 2 if BLE_MESH_TRACE_LEVEL_WARNING + default 3 if BLE_MESH_TRACE_LEVEL_INFO + default 4 if BLE_MESH_TRACE_LEVEL_DEBUG + default 5 if BLE_MESH_TRACE_LEVEL_VERBOSE + default 2 + + endmenu #BLE Mesh DEBUG LOG LEVEL + + menu "BLE Mesh NET BUF DEBUG LOG LEVEL" + depends on BLE_MESH && !BLE_MESH_NO_LOG + + choice BLE_MESH_NET_BUF_TRACE_LEVEL + prompt "BLE_MESH_NET_BUF" + default BLE_MESH_NET_BUF_TRACE_LEVEL_WARNING + depends on BLE_MESH && !BLE_MESH_NO_LOG + help + Define BLE Mesh trace level for BLE Mesh net buffer. + + config BLE_MESH_NET_BUF_TRACE_LEVEL_NONE + bool "NONE" + config BLE_MESH_NET_BUF_TRACE_LEVEL_ERROR + bool "ERROR" + config BLE_MESH_NET_BUF_TRACE_LEVEL_WARNING + bool "WARNING" + config BLE_MESH_NET_BUF_TRACE_LEVEL_INFO + bool "INFO" + config BLE_MESH_NET_BUF_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BLE_MESH_NET_BUF_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BLE_MESH_NET_BUF_TRACE_LEVEL + int + depends on BLE_MESH + default 0 if BLE_MESH_NET_BUF_TRACE_LEVEL_NONE + default 1 if BLE_MESH_NET_BUF_TRACE_LEVEL_ERROR + default 2 if BLE_MESH_NET_BUF_TRACE_LEVEL_WARNING + default 3 if BLE_MESH_NET_BUF_TRACE_LEVEL_INFO + default 4 if BLE_MESH_NET_BUF_TRACE_LEVEL_DEBUG + default 5 if BLE_MESH_NET_BUF_TRACE_LEVEL_VERBOSE + default 2 + + endmenu #BLE Mesh NET BUF DEBUG LOG LEVEL + + config BLE_MESH_IRQ_LOCK + bool "Used the IRQ lock instead of task lock" + help + To improve the real-time requirements of bt controller in BLE Mesh, + task lock is used to replace IRQ lock. + + config BLE_MESH_CLIENT_MSG_TIMEOUT + int "Timeout(ms) for client message response" + range 100 1200000 + default 4000 + help + Timeout value used by the node to get response of the acknowledged + message which is sent by the client model. + + menu "Support for BLE Mesh Client Models" + + config BLE_MESH_CFG_CLI + bool "Configuration Client Model" + help + Enable support for Configuration client model. + + config BLE_MESH_HEALTH_CLI + bool "Health Client Model" + help + Enable support for Health client model. + + config BLE_MESH_GENERIC_ONOFF_CLI + bool "Generic OnOff Client Model" + help + Enable support for Generic OnOff client model. + + config BLE_MESH_GENERIC_LEVEL_CLI + bool "Generic Level Client Model" + help + Enable support for Generic Level client model. + + config BLE_MESH_GENERIC_DEF_TRANS_TIME_CLI + bool "Generic Default Transition Time Client Model" + help + Enable support for Generic Default Transition Time client model. + + config BLE_MESH_GENERIC_POWER_ONOFF_CLI + bool "Generic Power Onoff Client Model" + help + Enable support for Generic Power Onoff client model. + + config BLE_MESH_GENERIC_POWER_LEVEL_CLI + bool "Generic Power Level Client Model" + help + Enable support for Generic Power Level client model. + + config BLE_MESH_GENERIC_BATTERY_CLI + bool "Generic Battery Client Model" + help + Enable support for Generic Battery client model. + + config BLE_MESH_GENERIC_LOCATION_CLI + bool "Generic Location Client Model" + help + Enable support for Generic Location client model. + + config BLE_MESH_GENERIC_PROPERTY_CLI + bool "Generic Property Client Model" + help + Enable support for Generic Property client model. + + config BLE_MESH_SENSOR_CLI + bool "Sensor Client Model" + help + Enable support for Sensor client model. + + config BLE_MESH_TIME_CLI + bool "Time Client Model" + help + Enable support for Time client model. + + config BLE_MESH_SCENE_CLI + bool "Scene Client Model" + help + Enable support for Scene client model. + + config BLE_MESH_SCHEDULER_CLI + bool "Scheduler Client Model" + help + Enable support for Scheduler client model. + + config BLE_MESH_LIGHT_LIGHTNESS_CLI + bool "Light Lightness Client Model" + help + Enable support for Light Lightness client model. + + config BLE_MESH_LIGHT_CTL_CLI + bool "Light CTL Client Model" + help + Enable support for Light CTL client model. + + config BLE_MESH_LIGHT_HSL_CLI + bool "Light HSL Client Model" + help + Enable support for Light HSL client model. + + config BLE_MESH_LIGHT_XYL_CLI + bool "Light XYL Client Model" + help + Enable support for Light XYL client model. + + config BLE_MESH_LIGHT_LC_CLI + bool "Light LC Client Model" + help + Enable support for Light LC client model. + + endmenu + + config BLE_MESH_IV_UPDATE_TEST + bool "Test the IV Update Procedure" + default n + help + This option removes the 96 hour limit of the IV Update Procedure and + lets the state to be changed at any time. + + menu "BLE Mesh specific test option" + + config BLE_MESH_SELF_TEST + bool "Perform BLE Mesh self-tests" + default n + help + This option adds extra self-tests which are run every time BLE Mesh + networking is initialized. + + config BLE_MESH_SHELL + bool "Enable BLE Mesh shell" + default n + help + Activate shell module that provides BLE Mesh commands to the console. + + config BLE_MESH_DEBUG + bool "Enable BLE Mesh debug logs" + default n + help + Enable debug logs for the BLE Mesh functionality. + + if BLE_MESH_DEBUG + + config BLE_MESH_DEBUG_NET + bool "Network layer debug" + help + Enable Network layer debug logs for the BLE Mesh functionality. + + config BLE_MESH_DEBUG_TRANS + bool "Transport layer debug" + help + Enable Transport layer debug logs for the BLE Mesh functionality. + + config BLE_MESH_DEBUG_BEACON + bool "Beacon debug" + help + Enable Beacon-related debug logs for the BLE Mesh functionality. + + config BLE_MESH_DEBUG_CRYPTO + bool "Crypto debug" + help + Enable cryptographic debug logs for the BLE Mesh functionality. + + config BLE_MESH_DEBUG_PROV + bool "Provisioning debug" + help + Enable Provisioning debug logs for the BLE Mesh functionality. + + config BLE_MESH_DEBUG_ACCESS + bool "Access layer debug" + help + Enable Access layer debug logs for the BLE Mesh functionality. + + config BLE_MESH_DEBUG_MODEL + bool "Foundation model debug" + help + Enable Foundation Models debug logs for the BLE Mesh functionality. + + config BLE_MESH_DEBUG_ADV + bool "Advertising debug" + help + Enable advertising debug logs for the BLE Mesh functionality. + + config BLE_MESH_DEBUG_LOW_POWER + bool "Low Power debug" + help + Enable Low Power debug logs for the BLE Mesh functionality. + + config BLE_MESH_DEBUG_FRIEND + bool "Friend debug" + help + Enable Friend debug logs for the BLE Mesh functionality. + + config BLE_MESH_DEBUG_PROXY + bool "Proxy debug" + depends on BLE_MESH_PROXY + help + Enable Proxy protocol debug logs for the BLE Mesh functionality. + + endif # BLE_MESH_DEBUG + + endmenu + +endif # BLE_MESH diff --git a/components/bt/ble_mesh/api/core/esp_ble_mesh_common_api.c b/components/bt/ble_mesh/api/core/esp_ble_mesh_common_api.c new file mode 100644 index 0000000000..4172ef0c7d --- /dev/null +++ b/components/bt/ble_mesh/api/core/esp_ble_mesh_common_api.c @@ -0,0 +1,70 @@ +// Copyright 2017-2018 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 + +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" + +#include "btc/btc_task.h" +#include "btc/btc_manage.h" + +#include "esp_err.h" +#include "esp_bt_defs.h" +#include "esp_bt_main.h" + +#include "btc_ble_mesh_prov.h" +#include "esp_ble_mesh_defs.h" + +esp_err_t esp_ble_mesh_init(esp_ble_mesh_prov_t *prov, esp_ble_mesh_comp_t *comp) +{ + btc_ble_mesh_prov_args_t arg = {0}; + SemaphoreHandle_t semaphore = NULL; + btc_msg_t msg = {0}; + + if (prov == NULL || comp == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + // Create a semaphore + if ((semaphore = xSemaphoreCreateCounting(1, 0)) == NULL) { + LOG_ERROR("%s, Failed to allocate memory for the semaphore", __func__); + return ESP_ERR_NO_MEM; + } + + arg.mesh_init.prov = prov; + arg.mesh_init.comp = comp; + /* Transport semaphore pointer to BTC layer, and will give the semaphore in the BTC task */ + arg.mesh_init.semaphore = semaphore; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_MESH_INIT; + + if (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) != BT_STATUS_SUCCESS) { + vSemaphoreDelete(semaphore); + LOG_ERROR("%s, BLE Mesh initialise failed", __func__); + return ESP_FAIL; + } + + /* Take the Semaphore, wait BLE Mesh initialization to finish. */ + xSemaphoreTake(semaphore, portMAX_DELAY); + /* Don't forget to delete the semaphore at the end. */ + vSemaphoreDelete(semaphore); + + return ESP_OK; +} + diff --git a/components/bt/ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c b/components/bt/ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c new file mode 100644 index 0000000000..6efeaf1765 --- /dev/null +++ b/components/bt/ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c @@ -0,0 +1,80 @@ +// Copyright 2017-2018 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 +#include + +#include "btc/btc_task.h" +#include "btc/btc_manage.h" + +#include "esp_err.h" +#include "esp_bt_defs.h" +#include "esp_bt_main.h" + +#include "btc_ble_mesh_prov.h" +#include "esp_ble_mesh_defs.h" + +int32_t esp_ble_mesh_get_model_publish_period(esp_ble_mesh_model_t *model) +{ + if (model == NULL) { + return 0; + } + return btc_ble_mesh_model_pub_period_get(model); +} + +uint16_t esp_ble_mesh_get_primary_element_address(void) +{ + return btc_ble_mesh_get_primary_addr(); +} + +uint16_t *esp_ble_mesh_is_model_subscribed_to_group(esp_ble_mesh_model_t *model, uint16_t group_addr) +{ + if (model == NULL) { + return NULL; + } + return btc_ble_mesh_model_find_group(model, group_addr); +} + +esp_ble_mesh_elem_t *esp_ble_mesh_find_element(uint16_t element_addr) +{ + return btc_ble_mesh_elem_find(element_addr); +} + +uint8_t esp_ble_mesh_get_element_count(void) +{ + return btc_ble_mesh_elem_count(); +} + +esp_ble_mesh_model_t *esp_ble_mesh_find_vendor_model(const esp_ble_mesh_elem_t *element, + uint16_t company_id, uint16_t model_id) +{ + if (element == NULL) { + return NULL; + } + return btc_ble_mesh_model_find_vnd(element, company_id, model_id); +} + +esp_ble_mesh_model_t *esp_ble_mesh_find_sig_model(const esp_ble_mesh_elem_t *element, uint16_t model_id) +{ + if (element == NULL) { + return NULL; + } + return btc_ble_mesh_model_find(element, model_id); +} + +const esp_ble_mesh_comp_t *esp_ble_mesh_get_composition_data(void) +{ + return btc_ble_mesh_comp_get(); +} + diff --git a/components/bt/ble_mesh/api/core/esp_ble_mesh_low_power_api.c b/components/bt/ble_mesh/api/core/esp_ble_mesh_low_power_api.c new file mode 100644 index 0000000000..6d3745ca6e --- /dev/null +++ b/components/bt/ble_mesh/api/core/esp_ble_mesh_low_power_api.c @@ -0,0 +1,26 @@ +// Copyright 2017-2018 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 + +#include "btc/btc_task.h" +#include "btc/btc_manage.h" + +#include "esp_err.h" +#include "esp_bt_defs.h" +#include "esp_bt_main.h" + +#include "btc_ble_mesh_prov.h" +#include "esp_ble_mesh_defs.h" + diff --git a/components/bt/ble_mesh/api/core/esp_ble_mesh_networking_api.c b/components/bt/ble_mesh/api/core/esp_ble_mesh_networking_api.c new file mode 100644 index 0000000000..9e920dd113 --- /dev/null +++ b/components/bt/ble_mesh/api/core/esp_ble_mesh_networking_api.c @@ -0,0 +1,338 @@ +// Copyright 2017-2018 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 +#include + +#include "btc/btc_task.h" +#include "btc/btc_manage.h" + +#include "esp_err.h" +#include "esp_bt_defs.h" +#include "esp_bt_main.h" + +#include "btc_ble_mesh_prov.h" +#include "esp_ble_mesh_networking_api.h" + +#define ESP_BLE_MESH_TX_SDU_MAX ((CONFIG_BLE_MESH_ADV_BUF_COUNT - 3) * 12) + +static esp_err_t ble_mesh_send_msg(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, + uint32_t opcode, + btc_ble_mesh_model_act_t act, + uint16_t length, uint8_t *data, + int32_t msg_timeout, bool need_rsp, + esp_ble_mesh_dev_role_t device_role) +{ + btc_ble_mesh_model_args_t arg = {0}; + uint8_t op_len = 0, mic_len = 0; + uint8_t *msg_data = NULL; + btc_msg_t msg = {0}; + esp_err_t status; + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + if (device_role > ROLE_FAST_PROV) { + return ESP_ERR_INVALID_ARG; + } + + /* When data is NULL, it is mandatory to set length to 0 to prevent users from misinterpreting parameters. */ + if (data == NULL) { + length = 0; + } + + if (opcode < 0x100) { + op_len = 1; + } else if (opcode < 0x10000) { + op_len = 2; + } else { + op_len = 3; + } + + if (act == BTC_BLE_MESH_ACT_MODEL_PUBLISH) { + if (op_len + length > model->pub->msg->size) { + LOG_ERROR("%s, Model publication msg size %d is too small", __func__, model->pub->msg->size); + return ESP_ERR_INVALID_ARG; + } + } + + if (act == BTC_BLE_MESH_ACT_MODEL_PUBLISH) { + mic_len = 4; + } else { + mic_len = ctx->send_rel ? 8 : 4; + } + + if (op_len + length + mic_len > MIN(ESP_BLE_MESH_SDU_MAX_LEN, ESP_BLE_MESH_TX_SDU_MAX)) { + LOG_ERROR("%s, Data length %d is too large", __func__, length); + return ESP_ERR_INVALID_ARG; + } + + if (act == BTC_BLE_MESH_ACT_MODEL_PUBLISH) { + bt_mesh_model_msg_init(model->pub->msg, opcode); + net_buf_simple_add_mem(model->pub->msg, data, length); + } else { + msg_data = (uint8_t *)osi_malloc(op_len + length); + if (msg_data == NULL) { + return ESP_ERR_NO_MEM; + } + esp_ble_mesh_model_msg_opcode_init(msg_data, opcode); + memcpy(msg_data + op_len, data, length); + } + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_MODEL; + msg.act = act; + + if (act == BTC_BLE_MESH_ACT_MODEL_PUBLISH) { + arg.model_publish.model = model; + arg.model_publish.device_role = device_role; + } else { + arg.model_send.model = model; + arg.model_send.ctx = ctx; + arg.model_send.need_rsp = need_rsp; + arg.model_send.opcode = opcode; + arg.model_send.length = op_len + length; + arg.model_send.data = msg_data; + arg.model_send.device_role = device_role; + arg.model_send.msg_timeout = msg_timeout; + } + + status = (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_model_args_t), btc_ble_mesh_prov_arg_deep_copy) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); + + osi_free(msg_data); + + return status; +} + +esp_err_t esp_ble_mesh_register_custom_model_callback(esp_ble_mesh_model_cb_t callback) +{ + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_MODEL, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_model_msg_opcode_init(uint8_t *data, uint32_t opcode) +{ + uint16_t val; + + if (data == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (opcode < 0x100) { + /* 1-byte OpCode */ + data[0] = opcode & 0xff; + return ESP_OK; + } + + if (opcode < 0x10000) { + /* 2-byte OpCode, big endian */ + val = sys_cpu_to_be16 (opcode); + memcpy(data, &val, 2); + return ESP_OK; + } + + /* 3-byte OpCode, note that little endian for the least 2 bytes(Company ID) of opcode */ + data[0] = (opcode >> 16) & 0xff; + val = sys_cpu_to_le16(opcode & 0xffff); + memcpy(&data[1], &val, 2); + + return ESP_OK; +} + +esp_err_t esp_ble_mesh_client_model_init(esp_ble_mesh_model_t *model) +{ + if (model == NULL) { + return ESP_ERR_INVALID_ARG; + } + return btc_ble_mesh_client_init(model); +} + +esp_err_t esp_ble_mesh_server_model_send_msg(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, uint32_t opcode, + uint16_t length, uint8_t *data) +{ + if (!model || !ctx) { + return ESP_ERR_INVALID_ARG; + } + return ble_mesh_send_msg(model, ctx, opcode, BTC_BLE_MESH_ACT_SERVER_MODEL_SEND, + length, data, 0, false, ROLE_NODE); +} + +esp_err_t esp_ble_mesh_client_model_send_msg(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, uint32_t opcode, + uint16_t length, uint8_t *data, int32_t msg_timeout, + bool need_rsp, esp_ble_mesh_dev_role_t device_role) +{ + if (!model || !ctx) { + return ESP_ERR_INVALID_ARG; + } + return ble_mesh_send_msg(model, ctx, opcode, BTC_BLE_MESH_ACT_CLIENT_MODEL_SEND, + length, data, msg_timeout, need_rsp, device_role); +} + +esp_err_t esp_ble_mesh_model_publish(esp_ble_mesh_model_t *model, uint32_t opcode, + uint16_t length, uint8_t *data, + esp_ble_mesh_dev_role_t device_role) +{ + if (!model || !model->pub || !model->pub->msg) { + return ESP_ERR_INVALID_ARG; + } + return ble_mesh_send_msg(model, NULL, opcode, BTC_BLE_MESH_ACT_MODEL_PUBLISH, + length, data, 0, false, device_role); +} + +esp_err_t esp_ble_mesh_node_local_reset(void) +{ + btc_msg_t msg = {0}; + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_NODE_RESET; + + return (btc_transfer_context(&msg, NULL, 0, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +#if (CONFIG_BLE_MESH_PROVISIONER) + +esp_err_t esp_ble_mesh_provisioner_set_node_name(int index, const char *name) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (!name || (strlen(name) > ESP_BLE_MESH_NODE_NAME_MAX_LEN)) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_PROVISIONER_SET_NODE_NAME; + + arg.set_node_name.index = index; + memset(arg.set_node_name.name, 0, sizeof(arg.set_node_name.name)); + memcpy(arg.set_node_name.name, name, strlen(name)); + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +const char *esp_ble_mesh_provisioner_get_node_name(int index) +{ + return bt_mesh_provisioner_get_node_name(index); +} + +int esp_ble_mesh_provisioner_get_node_index(const char *name) +{ + if (!name || (strlen(name) > ESP_BLE_MESH_NODE_NAME_MAX_LEN)) { + return -EINVAL; + } + + return bt_mesh_provisioner_get_node_index(name); +} + +esp_err_t esp_ble_mesh_provisioner_add_local_app_key(const uint8_t app_key[16], + uint16_t net_idx, uint16_t app_idx) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_PROVISIONER_SET_LOCAL_APP_KEY; + + arg.add_local_app_key.net_idx = net_idx; + arg.add_local_app_key.app_idx = app_idx; + if (app_key) { + memcpy(arg.add_local_app_key.app_key, app_key, 16); + } else { + bzero(arg.add_local_app_key.app_key, 16); + } + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +const uint8_t *esp_ble_mesh_provisioner_get_local_app_key(uint16_t net_idx, uint16_t app_idx) +{ + return bt_mesh_provisioner_local_app_key_get(net_idx, app_idx); +} + +esp_err_t esp_ble_mesh_provisioner_bind_app_key_to_local_model(uint16_t element_addr, uint16_t app_idx, + uint16_t model_id, uint16_t company_id) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (!ESP_BLE_MESH_ADDR_IS_UNICAST(element_addr)) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_PROVISIONER_BIND_LOCAL_MOD_APP; + + arg.local_mod_app_bind.elem_addr = element_addr; + arg.local_mod_app_bind.app_idx = app_idx; + arg.local_mod_app_bind.model_id = model_id; + arg.local_mod_app_bind.cid = company_id; + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_provisioner_add_local_net_key(const uint8_t net_key[16], uint16_t net_idx) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (net_idx == ESP_BLE_MESH_KEY_PRIMARY) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_PROVISIONER_ADD_LOCAL_NET_KEY; + + arg.add_local_net_key.net_idx = net_idx; + if (net_key) { + memcpy(arg.add_local_net_key.net_key, net_key, 16); + } else { + bzero(arg.add_local_net_key.net_key, 16); + } + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +const uint8_t *esp_ble_mesh_provisioner_get_local_net_key(uint16_t net_idx) +{ + return bt_mesh_provisioner_local_net_key_get(net_idx); +} + +#endif /* CONFIG_BLE_MESH_PROVISIONER */ + +#if (CONFIG_BLE_MESH_FAST_PROV) +const uint8_t *esp_ble_mesh_get_fast_prov_app_key(uint16_t net_idx, uint16_t app_idx) +{ + return bt_mesh_get_fast_prov_app_key(net_idx, app_idx); +} +#endif /* CONFIG_BLE_MESH_FAST_PROV */ + diff --git a/components/bt/ble_mesh/api/core/esp_ble_mesh_provisioning_api.c b/components/bt/ble_mesh/api/core/esp_ble_mesh_provisioning_api.c new file mode 100644 index 0000000000..855bcf188f --- /dev/null +++ b/components/bt/ble_mesh/api/core/esp_ble_mesh_provisioning_api.c @@ -0,0 +1,423 @@ +// Copyright 2017-2018 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 + +#include "btc/btc_task.h" +#include "btc/btc_manage.h" + +#include "esp_err.h" +#include "esp_bt_defs.h" +#include "esp_bt_main.h" + +#include "btc_ble_mesh_prov.h" +#include "esp_ble_mesh_provisioning_api.h" + +#define MAX_PROV_LINK_IDX (CONFIG_BLE_MESH_PBA_SAME_TIME + CONFIG_BLE_MESH_PBG_SAME_TIME) +#define MAX_OOB_INPUT_NUM 0x5F5E0FF /* Decimal: 99999999 */ + +esp_err_t esp_ble_mesh_register_prov_callback(esp_ble_mesh_prov_cb_t callback) +{ + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_PROV, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +bool esp_ble_mesh_node_is_provisioned(void) +{ + return bt_mesh_is_provisioned(); +} + +esp_err_t esp_ble_mesh_node_prov_enable(esp_ble_mesh_prov_bearer_t bearers) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_PROV_ENABLE; + arg.node_prov_enable.bearers = bearers; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_node_prov_disable(esp_ble_mesh_prov_bearer_t bearers) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_PROV_DISABLE; + arg.node_prov_disable.bearers = bearers; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_node_set_oob_pub_key(uint8_t pub_key_x[32], uint8_t pub_key_y[32], + uint8_t private_key[32]) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (!pub_key_x || !pub_key_y || !private_key) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_SET_OOB_PUB_KEY; + + memcpy(arg.set_oob_pub_key.pub_key_x, pub_key_x, 32); + memcpy(arg.set_oob_pub_key.pub_key_y, pub_key_y, 32); + memcpy(arg.set_oob_pub_key.private_key, private_key, 32); + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_node_input_number(uint32_t number) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (number > MAX_OOB_INPUT_NUM) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_INPUT_NUMBER; + arg.input_number.number = number; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_node_input_string(const char *string) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (!string) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_INPUT_STRING; + memset(arg.input_string.string, 0, sizeof(arg.input_string.string)); + strncpy(arg.input_string.string, string, strlen(string)); + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_set_unprovisioned_device_name(const char *name) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (!name || strlen(name) > ESP_BLE_MESH_DEVICE_NAME_MAX_LEN) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_SET_DEVICE_NAME; + + memset(arg.set_device_name.name, 0, sizeof(arg.set_device_name.name)); + memcpy(arg.set_device_name.name, name, strlen(name)); + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +#if (CONFIG_BLE_MESH_PROVISIONER) +esp_err_t esp_ble_mesh_provisioner_read_oob_pub_key(uint8_t link_idx, uint8_t pub_key_x[32], + uint8_t pub_key_y[32]) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (!pub_key_x || !pub_key_y || link_idx >= MAX_PROV_LINK_IDX) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_PROVISIONER_READ_OOB_PUB_KEY; + + arg.provisioner_read_oob_pub_key.link_idx = link_idx; + memcpy(arg.provisioner_read_oob_pub_key.pub_key_x, pub_key_x, 32); + memcpy(arg.provisioner_read_oob_pub_key.pub_key_y, pub_key_y, 32); + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_provisioner_input_string(const char *string, uint8_t link_idx) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (!string || link_idx >= MAX_PROV_LINK_IDX) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_PROVISIONER_INPUT_STR; + + memset(arg.provisioner_input_str.string, 0, sizeof(arg.provisioner_input_str.string)); + strncpy(arg.provisioner_input_str.string, string, strlen(string)); + arg.provisioner_input_str.link_idx = link_idx; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_provisioner_input_number(uint32_t number, uint8_t link_idx) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (number > MAX_OOB_INPUT_NUM || link_idx >= MAX_PROV_LINK_IDX) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_PROVISIONER_INPUT_NUM; + + arg.provisioner_input_num.number = number; + arg.provisioner_input_num.link_idx = link_idx; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_provisioner_prov_enable(esp_ble_mesh_prov_bearer_t bearers) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_PROVISIONER_ENABLE; + + arg.provisioner_enable.bearers = bearers; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_provisioner_prov_disable(esp_ble_mesh_prov_bearer_t bearers) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_PROVISIONER_DISABLE; + + arg.provisioner_disable.bearers = bearers; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_provisioner_add_unprov_dev(esp_ble_mesh_unprov_dev_add_t *add_dev, + esp_ble_mesh_dev_add_flag_t flags) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (add_dev == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_PROVISIONER_DEV_ADD; + + arg.provisioner_dev_add.add_dev.addr_type = add_dev->addr_type; + arg.provisioner_dev_add.add_dev.oob_info = add_dev->oob_info; + arg.provisioner_dev_add.add_dev.bearer = add_dev->bearer; + memcpy(arg.provisioner_dev_add.add_dev.addr, add_dev->addr, sizeof(esp_bd_addr_t)); + memcpy(arg.provisioner_dev_add.add_dev.uuid, add_dev->uuid, 16); + arg.provisioner_dev_add.flags = flags; + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_provisioner_delete_dev(esp_ble_mesh_device_delete_t *del_dev) +{ + uint8_t val = DEL_DEV_ADDR_FLAG | DEL_DEV_UUID_FLAG; + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (del_dev == NULL || (__builtin_popcount(del_dev->flag & val) != 1)) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_PROVISIONER_DEV_DEL; + + arg.provisioner_dev_del.del_dev.flag = del_dev->flag; + if (del_dev->flag & DEL_DEV_ADDR_FLAG) { + arg.provisioner_dev_del.del_dev.addr_type = del_dev->addr_type; + memcpy(arg.provisioner_dev_del.del_dev.addr, del_dev->addr, sizeof(esp_bd_addr_t)); + } else if (del_dev->flag & DEL_DEV_UUID_FLAG) { + memcpy(arg.provisioner_dev_del.del_dev.uuid, del_dev->uuid, 16); + } + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_provisioner_set_dev_uuid_match(const uint8_t *match_val, uint8_t match_len, + uint8_t offset, bool prov_after_match) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_PROVISIONER_SET_DEV_UUID_MATCH; + + if (match_len && match_val) { + memcpy(arg.set_dev_uuid_match.match_val, match_val, match_len); + } + arg.set_dev_uuid_match.match_len = match_len; + arg.set_dev_uuid_match.offset = offset; + arg.set_dev_uuid_match.prov_after_match = prov_after_match; + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_provisioner_set_prov_data_info(esp_ble_mesh_prov_data_info_t *prov_data_info) +{ + uint8_t val = PROV_DATA_NET_IDX_FLAG | PROV_DATA_FLAGS_FLAG | PROV_DATA_IV_INDEX_FLAG; + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (prov_data_info == NULL || (__builtin_popcount(prov_data_info->flag & val) != 1)) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_PROVISIONER_SET_PROV_DATA_INFO; + + arg.set_prov_data_info.prov_data.flag = prov_data_info->flag; + if (prov_data_info->flag & PROV_DATA_NET_IDX_FLAG) { + arg.set_prov_data_info.prov_data.net_idx = prov_data_info->net_idx; + } else if (prov_data_info->flag & PROV_DATA_FLAGS_FLAG) { + arg.set_prov_data_info.prov_data.flags = prov_data_info->flags; + } else if (prov_data_info->flag & PROV_DATA_IV_INDEX_FLAG) { + arg.set_prov_data_info.prov_data.iv_index = prov_data_info->iv_index; + } + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +#endif /* CONFIG_BLE_MESH_PROVISIONER */ + +/* The following APIs are for fast provisioning */ + +#if (CONFIG_BLE_MESH_FAST_PROV) + +esp_err_t esp_ble_mesh_set_fast_prov_info(esp_ble_mesh_fast_prov_info_t *fast_prov_info) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (fast_prov_info == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_SET_FAST_PROV_INFO; + + arg.set_fast_prov_info.unicast_min = fast_prov_info->unicast_min; + arg.set_fast_prov_info.unicast_max = fast_prov_info->unicast_max; + arg.set_fast_prov_info.net_idx = fast_prov_info->net_idx; + arg.set_fast_prov_info.flags = fast_prov_info->flags; + arg.set_fast_prov_info.iv_index = fast_prov_info->iv_index; + arg.set_fast_prov_info.offset = fast_prov_info->offset; + arg.set_fast_prov_info.match_len = fast_prov_info->match_len; + if (fast_prov_info->match_len && fast_prov_info->match_val) { + memcpy(arg.set_fast_prov_info.match_val, fast_prov_info->match_val, fast_prov_info->match_len); + } + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_set_fast_prov_action(esp_ble_mesh_fast_prov_action_t action) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (action >= FAST_PROV_ACT_MAX) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_SET_FAST_PROV_ACTION; + + arg.set_fast_prov_action.action = action; + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +#endif /* CONFIG_BLE_MESH_FAST_PROV */ + diff --git a/components/bt/ble_mesh/api/core/esp_ble_mesh_proxy_api.c b/components/bt/ble_mesh/api/core/esp_ble_mesh_proxy_api.c new file mode 100644 index 0000000000..0605e97a6b --- /dev/null +++ b/components/bt/ble_mesh/api/core/esp_ble_mesh_proxy_api.c @@ -0,0 +1,65 @@ +// Copyright 2017-2018 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 + +#include "btc/btc_task.h" +#include "btc/btc_manage.h" + +#include "esp_err.h" +#include "esp_bt_defs.h" +#include "esp_bt_main.h" + +#include "btc_ble_mesh_prov.h" +#include "esp_ble_mesh_defs.h" + +esp_err_t esp_ble_mesh_proxy_identity_enable(void) +{ + btc_msg_t msg = {0}; + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_PROXY_IDENTITY_ENABLE; + + return (btc_transfer_context(&msg, NULL, 0, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_proxy_gatt_enable(void) +{ + btc_msg_t msg = {0}; + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_PROXY_GATT_ENABLE; + + return (btc_transfer_context(&msg, NULL, 0, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_proxy_gatt_disable(void) +{ + btc_msg_t msg = {0}; + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_PROXY_GATT_DISABLE; + + return (btc_transfer_context(&msg, NULL, 0, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + diff --git a/components/bt/ble_mesh/api/core/include/esp_ble_mesh_common_api.h b/components/bt/ble_mesh/api/core/include/esp_ble_mesh_common_api.h new file mode 100644 index 0000000000..a550ad381f --- /dev/null +++ b/components/bt/ble_mesh/api/core/include/esp_ble_mesh_common_api.h @@ -0,0 +1,37 @@ +// Copyright 2017-2018 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. + +#ifndef _ESP_BLE_MESH_COMMON_API_H_ +#define _ESP_BLE_MESH_COMMON_API_H_ + +#include "esp_ble_mesh_defs.h" + +/** + * @brief Initialize BLE Mesh module. + * This API initializes provisioning capabilities and composition data information. + * + * @note After calling this API, the device needs to call esp_ble_mesh_prov_enable() + * to enable provisioning functionality again. + * + * @param[in] prov: Pointer to the device provisioning capabilities. This pointer must + * remain valid during the lifetime of the BLE Mesh device. + * @param[in] comp: Pointer to the device composition data information. This pointer + * must remain valid during the lifetime of the BLE Mesh device. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_init(esp_ble_mesh_prov_t *prov, esp_ble_mesh_comp_t *comp); + +#endif /* _ESP_BLE_MESH_COMMON_API_H_ */ diff --git a/components/bt/ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h b/components/bt/ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h new file mode 100644 index 0000000000..0acb6d73f0 --- /dev/null +++ b/components/bt/ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h @@ -0,0 +1,113 @@ +// Copyright 2017-2018 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. + +#ifndef _ESP_BLE_MESH_LOCAL_DATA_OPERATION_API_H_ +#define _ESP_BLE_MESH_LOCAL_DATA_OPERATION_API_H_ + +#include "esp_ble_mesh_defs.h" + +/** + * @brief Get the model publish period, the unit is ms. + * + * @param[in] model: Model instance pointer. + * + * @return Publish period value on success, 0 or (negative) error code from errno.h on failure. + * + */ +int32_t esp_ble_mesh_get_model_publish_period(esp_ble_mesh_model_t *model); + +/** + * @brief Get the address of the primary element. + * + * @param None. + * + * @return Address of the primary element on success, or + * ESP_BLE_MESH_ADDR_UNASSIGNED on failure which means the device has not been provisioned. + * + */ +uint16_t esp_ble_mesh_get_primary_element_address(void); + +/** + * @brief Check if the model has subscribed to the given group address. + * Note: E.g., once a status message is received and the destination address + * is a group address, the model uses this API to check if it is successfully subscribed + * to the given group address. + * + * @param[in] model: Pointer to the model. + * @param[in] group_addr: Group address. + * + * @return Pointer to the group address within the Subscription List of the model on success, or + * NULL on failure which means the model has not subscribed to the given group address. + * Note: With the pointer to the group address returned, you can reset the group address + * to 0x0000 in order to unsubscribe the model from the group. + * + */ +uint16_t *esp_ble_mesh_is_model_subscribed_to_group(esp_ble_mesh_model_t *model, uint16_t group_addr); + +/** + * @brief Find the BLE Mesh element pointer via the element address. + * + * @param[in] element_addr: Element address. + * + * @return Pointer to the element on success, or NULL on failure. + * + */ +esp_ble_mesh_elem_t *esp_ble_mesh_find_element(uint16_t element_addr); + +/** + * @brief Get the number of elements that have been registered. + * + * @param None. + * + * @return Number of elements. + * + */ +uint8_t esp_ble_mesh_get_element_count(void); + +/** + * @brief Find the Vendor specific model with the given element, + * the company ID and the Vendor Model ID. + * + * @param[in] element: Element to which the model belongs. + * @param[in] company_id: A 16-bit company identifier assigned by the Bluetooth SIG. + * @param[in] model_id: A 16-bit vendor-assigned model identifier. + * + * @return Pointer to the Vendor Model on success, or NULL on failure which means the Vendor Model is not found. + * + */ +esp_ble_mesh_model_t *esp_ble_mesh_find_vendor_model(const esp_ble_mesh_elem_t *element, + uint16_t company_id, uint16_t model_id); + +/** + * @brief Find the SIG model with the given element and Model id. + * + * @param[in] element: Element to which the model belongs. + * @param[in] model_id: SIG model identifier. + * + * @return Pointer to the SIG Model on success, or NULL on failure which means the SIG Model is not found. + * + */ +esp_ble_mesh_model_t *esp_ble_mesh_find_sig_model(const esp_ble_mesh_elem_t *element, uint16_t model_id); + +/** + * @brief Get the Composition data which has been registered. + * + * @param None. + * + * @return Pointer to the Composition data on success, or NULL on failure which means the Composition data is not initialized. + * + */ +const esp_ble_mesh_comp_t *esp_ble_mesh_get_composition_data(void); + +#endif /* _ESP_BLE_MESH_LOCAL_DATA_OPERATION_API_H_ */ diff --git a/components/bt/ble_mesh/api/core/include/esp_ble_mesh_low_power_api.h b/components/bt/ble_mesh/api/core/include/esp_ble_mesh_low_power_api.h new file mode 100644 index 0000000000..7a203d50cc --- /dev/null +++ b/components/bt/ble_mesh/api/core/include/esp_ble_mesh_low_power_api.h @@ -0,0 +1,20 @@ +// Copyright 2017-2018 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. + +#ifndef _ESP_BLE_MESH_LOW_POWER_API_H_ +#define _ESP_BLE_MESH_LOW_POWER_API_H_ + +#include "esp_ble_mesh_defs.h" + +#endif /* _ESP_BLE_MESH_LOW_POWER_API_H_ */ diff --git a/components/bt/ble_mesh/api/core/include/esp_ble_mesh_networking_api.h b/components/bt/ble_mesh/api/core/include/esp_ble_mesh_networking_api.h new file mode 100644 index 0000000000..d3df66879d --- /dev/null +++ b/components/bt/ble_mesh/api/core/include/esp_ble_mesh_networking_api.h @@ -0,0 +1,267 @@ +// Copyright 2017-2018 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. + +#ifndef _ESP_BLE_MESH_NETWORKING_API_H_ +#define _ESP_BLE_MESH_NETWORKING_API_H_ + +#include "esp_ble_mesh_defs.h" + +/** @brief: event, event code of user-defined model events; param, parameters of user-defined model events */ +typedef void (* esp_ble_mesh_model_cb_t)(esp_ble_mesh_model_cb_event_t event, + esp_ble_mesh_model_cb_param_t *param); + +/** + * @brief Register BLE Mesh callback for user-defined models' operations. + * This callback can report the following events generated for the user-defined models: + * - Call back the messages received by user-defined client and server models to the + * application layer; + * - If users call esp_ble_mesh_server/client_model_send, this callback notifies the + * application layer of the send_complete event; + * - If user-defined client model sends a message that requires response, and the response + * message is received after the timer expires, the response message will be reported + * to the application layer as published by a peer device; + * - If the user-defined client model fails to receive the response message during a specified + * period of time, a timeout event will be reported to the application layer. + * + * @note The client models (i.e. Config Client model, Health Client model, Generic + * Client models, Sensor Client model, Scene Client model and Lighting Client models) + * that have been realized internally have their specific register functions. + * For example, esp_ble_mesh_register_config_client_callback is the register + * function for Config Client Model. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_custom_model_callback(esp_ble_mesh_model_cb_t callback); + +/** + * @brief Add the message opcode to the beginning of the model message + * before sending or publishing the model message. + * + * @note This API is only used to set the opcode of the message. + * + * @param[in] data: Pointer to the message data. + * @param[in] opcode: The message opcode. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_model_msg_opcode_init(uint8_t *data, uint32_t opcode); + +/** + * @brief Initialize the user-defined client model. All user-defined client models + * shall call this function to initialize the client model internal data. + * Node: Before calling this API, the op_pair_size and op_pair variabled within + * the user_data(defined using esp_ble_mesh_client_t_) of the client model + * need to be initialized. + * + * @param[in] model: BLE Mesh Client model to which the message belongs. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_client_model_init(esp_ble_mesh_model_t *model); + +/** + * @brief Send server model messages(such as server model status messages). + * + * @param[in] model: BLE Mesh Server Model to which the message belongs. + * @param[in] ctx: Message context, includes keys, TTL, etc. + * @param[in] opcode: Message opcode. + * @param[in] length: Message length (exclude the message opcode). + * @param[in] data: Parameters of Access Payload (exclude the message opcode) to be sent. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_server_model_send_msg(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, uint32_t opcode, + uint16_t length, uint8_t *data); + +/** + * @brief Send client model message (such as model get, set, etc). + * + * @param[in] model: BLE Mesh Client Model to which the message belongs. + * @param[in] ctx: Message context, includes keys, TTL, etc. + * @param[in] opcode: Message opcode. + * @param[in] length: Message length (exclude the message opcode). + * @param[in] data: Parameters of the Access Payload (exclude the message opcode) to be sent. + * @param[in] msg_timeout: Time to get response to the message (in milliseconds). + * @param[in] need_rsp: TRUE if the opcode requires the peer device to reply, FALSE otherwise. + * @param[in] device_role: Role of the device (Node/Provisioner) that sends the message. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_client_model_send_msg(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, uint32_t opcode, + uint16_t length, uint8_t *data, int32_t msg_timeout, + bool need_rsp, esp_ble_mesh_dev_role_t device_role); + +/** + * @brief Send a model publication message. + * + * @note Before calling this function, the user needs to ensure that the model + * publication message (@ref esp_ble_mesh_model_pub_t.msg) contains a valid + * message to be sent. And if users want to update the publishing message, + * this API should be called in ESP_BLE_MESH_MODEL_PUBLISH_UPDATE_EVT + * with the message updated. + * + * + * @param[in] model: Mesh (client) Model publishing the message. + * @param[in] opcode: Message opcode. + * @param[in] length: Message length (exclude the message opcode). + * @param[in] data: Parameters of the Access Payload (exclude the message opcode) to be sent. + * @param[in] device_role: Role of the device (node/provisioner) publishing the message of the type esp_ble_mesh_dev_role_t. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_model_publish(esp_ble_mesh_model_t *model, uint32_t opcode, + uint16_t length, uint8_t *data, + esp_ble_mesh_dev_role_t device_role); + +/** + * @brief Reset the provisioning procedure of the local BLE Mesh node. + * + * @note All provisioning information in this node will be deleted and the node + * needs to be reprovisioned. The API function esp_ble_mesh_node_prov_enable() + * needs to be called to start a new provisioning procedure. + * + * @param None. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_node_local_reset(void); + +/** + * @brief This function is called to set the node (provisioned device) name. + * + * @param[in] index: Index of the node in the node queue. + * @param[in] name: Name (end by '\0') to be set for the node. + * + * @note index is obtained from the parameters of ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_provisioner_set_node_name(int index, const char *name); + +/** + * @brief This function is called to get the node (provisioned device) name. + * + * @param[in] index: Index of the node in the node queue. + * + * @note index is obtained from the parameters of ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT. + * + * @return Node name on success, or NULL on failure. + * + */ +const char *esp_ble_mesh_provisioner_get_node_name(int index); + +/** + * @brief This function is called to get the node (provisioned device) index. + * + * @param[in] name: Name of the node (end by '\0'). + * + * @return Node index on success, or (negative) error code from errno.h on failure. + * + */ +int esp_ble_mesh_provisioner_get_node_index(const char *name); + +/** + * @brief This function is called to set the app key for the local BLE Mesh stack. + * + * @param[in] app_key: The app key to be set for the local BLE Mesh stack. + * @param[in] net_idx: The network key index. + * @param[in] app_idx: The app key index. + * + * @note app_key: If set to NULL, app_key will be generated internally. + * net_idx: Should be an existing one. + * app_idx: If it is going to be generated internally, it should be set to + * 0xFFFF, and the new app_idx will be reported via an event. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_provisioner_add_local_app_key(const uint8_t app_key[16], uint16_t net_idx, uint16_t app_idx); + +/** + * @brief This function is called by Provisioner to get the local app key value. + * + * @param[in] net_idx: Network key index. + * @param[in] app_idx: Application key index. + * + * @return App key on success, or NULL on failure. + * + */ +const uint8_t *esp_ble_mesh_provisioner_get_local_app_key(uint16_t net_idx, uint16_t app_idx); + +/** + * @brief This function is called by Provisioner to bind own model with proper app key. + * + * @param[in] element_addr: Provisioner local element address + * @param[in] app_idx: Provisioner local appkey index + * @param[in] model_id: Provisioner local model id + * @param[in] company_id: Provisioner local company id + * + * @note company_id: If going to bind app_key with local vendor model, company_id + * should be set to 0xFFFF. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_provisioner_bind_app_key_to_local_model(uint16_t element_addr, uint16_t app_idx, + uint16_t model_id, uint16_t company_id); + +/** + * @brief This function is called by Provisioner to add local network key. + * + * @param[in] net_key: The network key to be added to the Provisioner local BLE Mesh stack. + * @param[in] net_idx: The network key index. + * + * @note net_key: If set to NULL, net_key will be generated internally. + * net_idx: If it is going to be generated internally, it should be set to + * 0xFFFF, and the new net_idx will be reported via an event. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_provisioner_add_local_net_key(const uint8_t net_key[16], uint16_t net_idx); + +/** + * @brief This function is called by Provisioner to get the local network key value. + * + * @param[in] net_idx: Network key index. + * + * @return Network key on success, or NULL on failure. + * + */ +const uint8_t *esp_ble_mesh_provisioner_get_local_net_key(uint16_t net_idx); + +/** + * @brief This function is called to get fast provisioning application key. + * + * @param[in] net_idx: Network key index. + * @param[in] app_idx: Application key index. + * + * @return Application key on success, or NULL on failure. + * + */ +const uint8_t *esp_ble_mesh_get_fast_prov_app_key(uint16_t net_idx, uint16_t app_idx); + +#endif /* _ESP_BLE_MESH_NETWORKING_API_H_ */ diff --git a/components/bt/ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h b/components/bt/ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h new file mode 100644 index 0000000000..e03c4d4ef1 --- /dev/null +++ b/components/bt/ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h @@ -0,0 +1,316 @@ +// Copyright 2017-2018 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. + +#ifndef _ESP_BLE_MESH_PROVISIONING_API_H_ +#define _ESP_BLE_MESH_PROVISIONING_API_H_ + +#include "esp_ble_mesh_defs.h" + +/** @brief: event, event code of provisioning events; param, parameters of provisioning events */ +typedef void (* esp_ble_mesh_prov_cb_t)(esp_ble_mesh_prov_cb_event_t event, + esp_ble_mesh_prov_cb_param_t *param); + +/** + * @brief Register BLE Mesh provisioning callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_prov_callback(esp_ble_mesh_prov_cb_t callback); + +/** + * @brief Check if a device has been provisioned. + * + * @param None. + * + * @return TRUE if the device is provisioned, FALSE if the device is unprovisioned. + * + */ +bool esp_ble_mesh_node_is_provisioned(void); + +/** + * @brief Enable specific provisioning bearers to get the device ready for provisioning. + * + * @note PB-ADV: send unprovisioned device beacon. + * PB-GATT: send connectable advertising packets. + * + * @param bearers: Bit-wise OR of provisioning bearers. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_node_prov_enable(esp_ble_mesh_prov_bearer_t bearers); + +/** + * @brief Disable specific provisioning bearers to make a device inaccessible for provisioning. + * + * @param bearers: Bit-wise OR of provisioning bearers. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_node_prov_disable(esp_ble_mesh_prov_bearer_t bearers); + +/** + * @brief Unprovisioned device set own oob public key & private key pair. + * + * @param[in] pub_key_x: Unprovisioned device's Public Key X + * @param[in] pub_key_y: Unprovisioned device's Public Key Y + * @param[in] private_key: Unprovisioned device's Private Key + * + * @return ESP_OK on success or error code otherwise. + */ +esp_err_t esp_ble_mesh_node_set_oob_pub_key(uint8_t pub_key_x[32], uint8_t pub_key_y[32], + uint8_t private_key[32]); + +/** + * @brief Provide provisioning input OOB number. + * + * @note This is intended to be called if the user has received ESP_BLE_MESH_NODE_PROV_INPUT_EVT + * with ESP_BLE_MESH_ENTER_NUMBER as the action. + * + * @param[in] number: Number input by device. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_node_input_number(uint32_t number); + +/** + * @brief Provide provisioning input OOB string. + * + * @note This is intended to be called if the user has received ESP_BLE_MESH_NODE_PROV_INPUT_EVT + * with ESP_BLE_MESH_ENTER_STRING as the action. + * + * @param[in] string: String input by device. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_node_input_string(const char *string); + +/** + * @brief Using this function, an unprovisioned device can set its own device name, + * which will be broadcasted in its advertising data. + * + * @param[in] name: Unprovisioned device name + * + * @note This API applicable to PB-GATT mode only by setting the name to the scan response data, + * it doesn't apply to PB-ADV mode. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_set_unprovisioned_device_name(const char *name); + +/** + * @brief Provisioner inputs unprovisioned device's oob public key. + * + * @param[in] link_idx: The provisioning link index + * @param[in] pub_key_x: Unprovisioned device's Public Key X + * @param[in] pub_key_y: Unprovisioned device's Public Key Y + * + * @return ESP_OK on success or error code otherwise. + */ +esp_err_t esp_ble_mesh_provisioner_read_oob_pub_key(uint8_t link_idx, uint8_t pub_key_x[32], + uint8_t pub_key_y[32]); + +/** + * @brief Provide provisioning input OOB string. + * + * This is intended to be called after the esp_ble_mesh_prov_t prov_input_num + * callback has been called with ESP_BLE_MESH_ENTER_STRING as the action. + * + * @param[in] string: String input by Provisioner. + * @param[in] link_idx: The provisioning link index. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_provisioner_input_string(const char *string, uint8_t link_idx); + +/** + * @brief Provide provisioning input OOB number. + * + * This is intended to be called after the esp_ble_mesh_prov_t prov_input_num + * callback has been called with ESP_BLE_MESH_ENTER_NUMBER as the action. + * + * @param[in] number: Number input by Provisioner. + * @param[in] link_idx: The provisioning link index. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_provisioner_input_number(uint32_t number, uint8_t link_idx); + +/** + * @brief Enable one or more provisioning bearers. + * + * @param[in] bearers: Bit-wise OR of provisioning bearers. + * + * @note PB-ADV: Enable BLE scan. + * PB-GATT: Initialize corresponding BLE Mesh Proxy info. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_provisioner_prov_enable(esp_ble_mesh_prov_bearer_t bearers); + +/** + * @brief Disable one or more provisioning bearers. + * + * @param[in] bearers: Bit-wise OR of provisioning bearers. + * + * @note PB-ADV: Disable BLE scan. + * PB-GATT: Break any existing BLE Mesh Provisioning connections. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_provisioner_prov_disable(esp_ble_mesh_prov_bearer_t bearers); + +/** + * @brief Add unprovisioned device info to the unprov_dev queue. + * + * @param[in] add_dev: Pointer to a struct containing the device information + * @param[in] flags: Flags indicate several operations on the device information + * - Remove device information from queue after device has been provisioned (BIT0) + * - Start provisioning immediately after device is added to queue (BIT1) + * - Device can be removed if device queue is full (BIT2) + * + * @return ESP_OK on success or error code otherwise. + * + * @note: 1. Currently address type only supports public address and static random address. + * 2. If device UUID and/or device address as well as address type already exist in the + * device queue, but the bearer is different from the existing one, add operation + * will also be successful and it will update the provision bearer supported by + * the device. + * 3. For example, if the Provisioner wants to add an unprovisioned device info before + * receiving its unprovisioned device beacon or Mesh Provisioning advertising packets, + * the Provisioner can use this API to add the device info with each one or both of + * device UUID and device address added. When the Provisioner gets the device's + * advertising packets, it will start provisioning the device internally. + * - In this situation, the Provisioner can set bearers with each one or both of + * ESP_BLE_MESH_PROV_ADV and ESP_BLE_MESH_PROV_GATT enabled, and cannot set flags + * with ADD_DEV_START_PROV_NOW_FLAG enabled. + * 4. Another example is when the Provisioner receives the unprovisioned device's beacon or + * Mesh Provisioning advertising packets, the advertising packets will be reported on to + * the application layer using the callback registered by the function + * esp_ble_mesh_register_prov_callback. And in the callback, the Provisioner + * can call this API to start provisioning the device. + * - If the Provisioner uses PB-ADV to provision, either one or both of device UUID and + * device address can be added, bearers shall be set with ESP_BLE_MESH_PROV_ADV + * enabled and the flags shall be set with ADD_DEV_START_PROV_NOW_FLAG enabled. + * - If the Provisioner uses PB-GATT to provision, both the device UUID and device + * address need to be added, bearers shall be set with ESP_BLE_MESH_PROV_GATT enabled, + * and the flags shall be set with ADD_DEV_START_PROV_NOW_FLAG enabled. + * - If the Provisioner just wants to store the unprovisioned device info when receiving + * its advertising packets and start to provision it the next time (e.g. after receiving + * its advertising packets again), then it can add the device info with either one or both + * of device UUID and device address included. Bearers can be set with either one or both + * of ESP_BLE_MESH_PROV_ADV and ESP_BLE_MESH_PROV_GATT enabled (recommend to enable the + * bearer which will receive its advertising packets, because if the other bearer is + * enabled, the Provisioner is not aware if the device supports the bearer), and flags + * cannot be set with ADD_DEV_START_PROV_NOW_FLAG enabled. + * - Note: ESP_BLE_MESH_PROV_ADV, ESP_BLE_MESH_PROV_GATT and ADD_DEV_START_PROV_NOW_FLAG + * can not be enabled at the same time. + * + */ +esp_err_t esp_ble_mesh_provisioner_add_unprov_dev(esp_ble_mesh_unprov_dev_add_t *add_dev, + esp_ble_mesh_dev_add_flag_t flags); + +/** + * @brief Delete device from queue, reset current provisioning link and reset the node. + * + * @note If the device is in the queue, remove it from the queue; if the device is being + * provisioned, terminate the provisioning procedure; if the device has already + * been provisioned, reset the device. And either one of the addr or device UUID + * can be input. + * + * @param[in] del_dev: Pointer to a struct containing the device information. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_provisioner_delete_dev(esp_ble_mesh_device_delete_t *del_dev); + +/** + * @brief Callback for Provisioner that received advertising packets from unprovisioned devices which are + * not in the unprovisioned device queue. + * + * Report on the unprovisioned device beacon and mesh provisioning service adv data to application. + * + * @param[in] addr: Pointer to the unprovisioned device address. + * @param[in] addr_type: Unprovisioned device address type. + * @param[in] adv_type: Adv packet type(ADV_IND or ADV_NONCONN_IND). + * @param[in] dev_uuid: Unprovisioned device UUID pointer. + * @param[in] oob_info: OOB information of the unprovisioned device. + * @param[in] bearer: Adv packet received from PB-GATT or PB-ADV bearer. + * + */ +typedef void (*esp_ble_mesh_prov_adv_cb_t)(const esp_bd_addr_t addr, const esp_ble_addr_type_t addr_type, + const uint8_t adv_type, const uint8_t *dev_uuid, + uint16_t oob_info, esp_ble_mesh_prov_bearer_t bearer); + +/** + * @brief This function is called by Provisioner to set the part of the device UUID + * to be compared before starting to provision. + * + * @param[in] match_val: Value to be compared with the part of the device UUID. + * @param[in] match_len: Length of the compared match value. + * @param[in] offset: Offset of the device UUID to be compared (based on zero). + * @param[in] prov_after_match: Flag used to indicate whether provisioner should start to provision + * the device immediately if the part of the UUID matches. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_provisioner_set_dev_uuid_match(const uint8_t *match_val, uint8_t match_len, + uint8_t offset, bool prov_after_match); + +/** + * @brief This function is called by Provisioner to set provisioning data information + * before starting to provision. + * + * @param[in] prov_data_info: Pointer to a struct containing net_idx or flags or iv_index. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_provisioner_set_prov_data_info(esp_ble_mesh_prov_data_info_t *prov_data_info); + +/** + * @brief This function is called to set provisioning data information before starting + * fast provisioning. + * + * @param[in] fast_prov_info: Pointer to a struct containing unicast address range, net_idx, etc. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_set_fast_prov_info(esp_ble_mesh_fast_prov_info_t *fast_prov_info); + +/** + * @brief This function is called to start/suspend/exit fast provisioning. + * + * @param[in] action: fast provisioning action (i.e. enter, suspend, exit). + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_set_fast_prov_action(esp_ble_mesh_fast_prov_action_t action); + +#endif /* _ESP_BLE_MESH_PROVISIONING_API_H_ */ diff --git a/components/bt/ble_mesh/api/core/include/esp_ble_mesh_proxy_api.h b/components/bt/ble_mesh/api/core/include/esp_ble_mesh_proxy_api.h new file mode 100644 index 0000000000..67a785dda6 --- /dev/null +++ b/components/bt/ble_mesh/api/core/include/esp_ble_mesh_proxy_api.h @@ -0,0 +1,59 @@ +// Copyright 2017-2018 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. + +#ifndef _ESP_BLE_MESH_PROXY_API_H_ +#define _ESP_BLE_MESH_PROXY_API_H_ + +#include "esp_ble_mesh_defs.h" + +/** + * @brief Enable advertising with Node Identity. + * + * @note This API requires that GATT Proxy support be enabled. Once called, + * each subnet starts advertising using Node Identity for the next 60 + * seconds, and after 60s Network ID will be advertised. + * Under normal conditions, the BLE Mesh Proxy Node Identity and + * Network ID advertising will be enabled automatically by BLE Mesh + * stack after the device is provisioned. + * + * @param None. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_proxy_identity_enable(void); + +/** + * @brief Enable BLE Mesh GATT Proxy Service. + * + * @param None. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_proxy_gatt_enable(void); + +/** + * @brief Disconnect the BLE Mesh GATT Proxy connection if there is any, and + * disable the BLE Mesh GATT Proxy Service. + * + * @param None. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_proxy_gatt_disable(void); + +#endif /* _ESP_BLE_MESH_PROXY_API_H_ */ + diff --git a/components/bt/ble_mesh/api/esp_ble_mesh_defs.h b/components/bt/ble_mesh/api/esp_ble_mesh_defs.h new file mode 100644 index 0000000000..6e751bd315 --- /dev/null +++ b/components/bt/ble_mesh/api/esp_ble_mesh_defs.h @@ -0,0 +1,1524 @@ +// Copyright 2017-2018 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. + +#ifndef _ESP_BLE_MESH_DEFS_H_ +#define _ESP_BLE_MESH_DEFS_H_ + +#include + +#include "esp_bt_defs.h" + +#include "mesh_proxy.h" +#include "mesh_access.h" +#include "mesh_main.h" + +#include "mesh.h" +#include "proxy.h" +#include "foundation.h" +#include "provisioner_main.h" + +#include "model_opcode.h" +#include "mesh_common.h" + +#define ESP_BLE_MESH_SDU_MAX_LEN 384 + +/*!< The maximum length of a BLE Mesh provisioned node name */ +#define ESP_BLE_MESH_NODE_NAME_MAX_LEN 31 + +/*!< The maximum length of a BLE Mesh unprovisioned device name */ +#define ESP_BLE_MESH_DEVICE_NAME_MAX_LEN DEVICE_NAME_SIZE + +/*!< Define the BLE Mesh octet 16 bytes size */ +#define ESP_BLE_MESH_OCTET16_LEN 16 +typedef uint8_t esp_ble_mesh_octet16_t[ESP_BLE_MESH_OCTET16_LEN]; + +/*!< Define the BLE Mesh octet 8 bytes size */ +#define ESP_BLE_MESH_OCTET8_LEN 8 +typedef uint8_t esp_ble_mesh_octet8_t[ESP_BLE_MESH_OCTET8_LEN]; + +#define ESP_BLE_MESH_ADDR_UNASSIGNED BLE_MESH_ADDR_UNASSIGNED +#define ESP_BLE_MESH_ADDR_ALL_NODES BLE_MESH_ADDR_ALL_NODES +#define ESP_BLE_MESH_ADDR_PROXIES BLE_MESH_ADDR_PROXIES +#define ESP_BLE_MESH_ADDR_FRIENDS BLE_MESH_ADDR_FRIENDS +#define ESP_BLE_MESH_ADDR_RELAYS BLE_MESH_ADDR_RELAYS + +#define ESP_BLE_MESH_KEY_UNUSED BLE_MESH_KEY_UNUSED +#define ESP_BLE_MESH_KEY_DEV BLE_MESH_KEY_DEV + +#define ESP_BLE_MESH_KEY_PRIMARY BLE_MESH_KEY_PRIMARY +#define ESP_BLE_MESH_KEY_ANY BLE_MESH_KEY_ANY + +/*!< Primary Network Key index */ +#define ESP_BLE_MESH_NET_PRIMARY BLE_MESH_NET_PRIMARY + +/*!< Relay state value */ +#define ESP_BLE_MESH_RELAY_DISABLED BLE_MESH_RELAY_DISABLED +#define ESP_BLE_MESH_RELAY_ENABLED BLE_MESH_RELAY_ENABLED +#define ESP_BLE_MESH_RELAY_NOT_SUPPORTED BLE_MESH_RELAY_NOT_SUPPORTED + +/*!< Beacon state value */ +#define ESP_BLE_MESH_BEACON_DISABLED BLE_MESH_BEACON_DISABLED +#define ESP_BLE_MESH_BEACON_ENABLED BLE_MESH_BEACON_ENABLED + +/*!< GATT Proxy state value */ +#define ESP_BLE_MESH_GATT_PROXY_DISABLED BLE_MESH_GATT_PROXY_DISABLED +#define ESP_BLE_MESH_GATT_PROXY_ENABLED BLE_MESH_GATT_PROXY_ENABLED +#define ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED BLE_MESH_GATT_PROXY_NOT_SUPPORTED + +/*!< Friend state value */ +#define ESP_BLE_MESH_FRIEND_DISABLED BLE_MESH_FRIEND_DISABLED +#define ESP_BLE_MESH_FRIEND_ENABLED BLE_MESH_FRIEND_ENABLED +#define ESP_BLE_MESH_FRIEND_NOT_SUPPORTED BLE_MESH_FRIEND_NOT_SUPPORTED + +/*!< Node identity state value */ +#define ESP_BLE_MESH_NODE_IDENTITY_STOPPED BLE_MESH_NODE_IDENTITY_STOPPED +#define ESP_BLE_MESH_NODE_IDENTITY_RUNNING BLE_MESH_NODE_IDENTITY_RUNNING +#define ESP_BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED + +/*!< Supported features */ +#define ESP_BLE_MESH_FEATURE_RELAY BLE_MESH_FEAT_RELAY +#define ESP_BLE_MESH_FEATURE_PROXY BLE_MESH_FEAT_PROXY +#define ESP_BLE_MESH_FEATURE_FRIEND BLE_MESH_FEAT_FRIEND +#define ESP_BLE_MESH_FEATURE_LOW_POWER BLE_MESH_FEAT_LOW_POWER +#define ESP_BLE_MESH_FEATURE_ALL_SUPPORTED BLE_MESH_FEAT_SUPPORTED + +#define ESP_BLE_MESH_ADDR_IS_UNICAST(addr) BLE_MESH_ADDR_IS_UNICAST(addr) +#define ESP_BLE_MESH_ADDR_IS_GROUP(addr) BLE_MESH_ADDR_IS_GROUP(addr) +#define ESP_BLE_MESH_ADDR_IS_VIRTUAL(addr) BLE_MESH_ADDR_IS_VIRTUAL(addr) +#define ESP_BLE_MESH_ADDR_IS_RFU(addr) BLE_MESH_ADDR_IS_RFU(addr) + +#define ESP_BLE_MESH_INVALID_NODE_INDEX (-1) + +/*!< Foundation Models */ +#define ESP_BLE_MESH_MODEL_ID_CONFIG_SRV BLE_MESH_MODEL_ID_CFG_SRV +#define ESP_BLE_MESH_MODEL_ID_CONFIG_CLI BLE_MESH_MODEL_ID_CFG_CLI +#define ESP_BLE_MESH_MODEL_ID_HEALTH_SRV BLE_MESH_MODEL_ID_HEALTH_SRV +#define ESP_BLE_MESH_MODEL_ID_HEALTH_CLI BLE_MESH_MODEL_ID_HEALTH_CLI + +/*!< Models from the Mesh Model Specification */ +#define ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV BLE_MESH_MODEL_ID_GEN_ONOFF_SRV +#define ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI BLE_MESH_MODEL_ID_GEN_ONOFF_CLI +#define ESP_BLE_MESH_MODEL_ID_GEN_LEVEL_SRV BLE_MESH_MODEL_ID_GEN_LEVEL_SRV +#define ESP_BLE_MESH_MODEL_ID_GEN_LEVEL_CLI BLE_MESH_MODEL_ID_GEN_LEVEL_CLI +#define ESP_BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_SRV BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_SRV +#define ESP_BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_CLI BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_CLI +#define ESP_BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV +#define ESP_BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV +#define ESP_BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_CLI BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_CLI +#define ESP_BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV +#define ESP_BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV +#define ESP_BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_CLI BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_CLI +#define ESP_BLE_MESH_MODEL_ID_GEN_BATTERY_SRV BLE_MESH_MODEL_ID_GEN_BATTERY_SRV +#define ESP_BLE_MESH_MODEL_ID_GEN_BATTERY_CLI BLE_MESH_MODEL_ID_GEN_BATTERY_CLI +#define ESP_BLE_MESH_MODEL_ID_GEN_LOCATION_SRV BLE_MESH_MODEL_ID_GEN_LOCATION_SRV +#define ESP_BLE_MESH_MODEL_ID_GEN_LOCATION_SETUP_SRV BLE_MESH_MODEL_ID_GEN_LOCATION_SETUPSRV +#define ESP_BLE_MESH_MODEL_ID_GEN_LOCATION_CLI BLE_MESH_MODEL_ID_GEN_LOCATION_CLI +#define ESP_BLE_MESH_MODEL_ID_GEN_ADMIN_PROP_SRV BLE_MESH_MODEL_ID_GEN_ADMIN_PROP_SRV +#define ESP_BLE_MESH_MODEL_ID_GEN_MANUFACTURER_PROP_SRV BLE_MESH_MODEL_ID_GEN_MANUFACTURER_PROP_SRV +#define ESP_BLE_MESH_MODEL_ID_GEN_USER_PROP_SRV BLE_MESH_MODEL_ID_GEN_USER_PROP_SRV +#define ESP_BLE_MESH_MODEL_ID_GEN_CLIENT_PROP_SRV BLE_MESH_MODEL_ID_GEN_CLIENT_PROP_SRV +#define ESP_BLE_MESH_MODEL_ID_GEN_PROP_CLI BLE_MESH_MODEL_ID_GEN_PROP_CLI +#define ESP_BLE_MESH_MODEL_ID_SENSOR_SRV BLE_MESH_MODEL_ID_SENSOR_SRV +#define ESP_BLE_MESH_MODEL_ID_SENSOR_SETUP_SRV BLE_MESH_MODEL_ID_SENSOR_SETUP_SRV +#define ESP_BLE_MESH_MODEL_ID_SENSOR_CLI BLE_MESH_MODEL_ID_SENSOR_CLI +#define ESP_BLE_MESH_MODEL_ID_TIME_SRV BLE_MESH_MODEL_ID_TIME_SRV +#define ESP_BLE_MESH_MODEL_ID_TIME_SETUP_SRV BLE_MESH_MODEL_ID_TIME_SETUP_SRV +#define ESP_BLE_MESH_MODEL_ID_TIME_CLI BLE_MESH_MODEL_ID_TIME_CLI +#define ESP_BLE_MESH_MODEL_ID_SCENE_SRV BLE_MESH_MODEL_ID_SCENE_SRV +#define ESP_BLE_MESH_MODEL_ID_SCENE_SETUP_SRV BLE_MESH_MODEL_ID_SCENE_SETUP_SRV +#define ESP_BLE_MESH_MODEL_ID_SCENE_CLI BLE_MESH_MODEL_ID_SCENE_CLI +#define ESP_BLE_MESH_MODEL_ID_SCHEDULER_SRV BLE_MESH_MODEL_ID_SCHEDULER_SRV +#define ESP_BLE_MESH_MODEL_ID_SCHEDULER_SETUP_SRV BLE_MESH_MODEL_ID_SCHEDULER_SETUP_SRV +#define ESP_BLE_MESH_MODEL_ID_SCHEDULER_CLI BLE_MESH_MODEL_ID_SCHEDULER_CLI +#define ESP_BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV +#define ESP_BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SETUP_SRV BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SETUP_SRV +#define ESP_BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_CLI BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_CLI +#define ESP_BLE_MESH_MODEL_ID_LIGHT_CTL_SRV BLE_MESH_MODEL_ID_LIGHT_CTL_SRV +#define ESP_BLE_MESH_MODEL_ID_LIGHT_CTL_SETUP_SRV BLE_MESH_MODEL_ID_LIGHT_CTL_SETUP_SRV +#define ESP_BLE_MESH_MODEL_ID_LIGHT_CTL_CLI BLE_MESH_MODEL_ID_LIGHT_CTL_CLI +#define ESP_BLE_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV BLE_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV +#define ESP_BLE_MESH_MODEL_ID_LIGHT_HSL_SRV BLE_MESH_MODEL_ID_LIGHT_HSL_SRV +#define ESP_BLE_MESH_MODEL_ID_LIGHT_HSL_SETUP_SRV BLE_MESH_MODEL_ID_LIGHT_HSL_SETUP_SRV +#define ESP_BLE_MESH_MODEL_ID_LIGHT_HSL_CLI BLE_MESH_MODEL_ID_LIGHT_HSL_CLI +#define ESP_BLE_MESH_MODEL_ID_LIGHT_HSL_HUE_SRV BLE_MESH_MODEL_ID_LIGHT_HSL_HUE_SRV +#define ESP_BLE_MESH_MODEL_ID_LIGHT_HSL_SAT_SRV BLE_MESH_MODEL_ID_LIGHT_HSL_SAT_SRV +#define ESP_BLE_MESH_MODEL_ID_LIGHT_XYL_SRV BLE_MESH_MODEL_ID_LIGHT_XYL_SRV +#define ESP_BLE_MESH_MODEL_ID_LIGHT_XYL_SETUP_SRV BLE_MESH_MODEL_ID_LIGHT_XYL_SETUP_SRV +#define ESP_BLE_MESH_MODEL_ID_LIGHT_XYL_CLI BLE_MESH_MODEL_ID_LIGHT_XYL_CLI +#define ESP_BLE_MESH_MODEL_ID_LIGHT_LC_SRV BLE_MESH_MODEL_ID_LIGHT_LC_SRV +#define ESP_BLE_MESH_MODEL_ID_LIGHT_LC_SETUP_SRV BLE_MESH_MODEL_ID_LIGHT_LC_SETUPSRV +#define ESP_BLE_MESH_MODEL_ID_LIGHT_LC_CLI BLE_MESH_MODEL_ID_LIGHT_LC_CLI + +/*!< The following opcodes will only be used in the esp_ble_mesh_config_client_get_state function. */ +typedef uint32_t esp_ble_mesh_opcode_config_client_get_t; /*!< esp_ble_mesh_opcode_config_client_get_t belongs to esp_ble_mesh_opcode_t, + this typedef is only used to locate the opcodes used by esp_ble_mesh_config_client_get_state */ +#define ESP_BLE_MESH_MODEL_OP_BEACON_GET OP_BEACON_GET /*!< To determine the Secure Network Beacon state of a Configuration Server */ +#define ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET OP_DEV_COMP_DATA_GET /*!< To determine the Composition Data state of a Configuration Server, a Configuration + Client shall send a Config Composition Data Get message with the Page field value set + to 0xFF. The response is a Config Composition Data Status message that contains the last + page of the Composition Data state. If the Page field of the Config Composition Data Status + message contains a non-zero value, then the Configuration Client shall send another Composition + Data Get message with the Page field value set to one less than the Page field value of the + Config Composition Data Status message. */ +#define ESP_BLE_MESH_MODEL_OP_DEFAULT_TTL_GET OP_DEFAULT_TTL_GET /*!< To determine the Default TTL state of a Configuration Server */ +#define ESP_BLE_MESH_MODEL_OP_GATT_PROXY_GET OP_GATT_PROXY_GET /*!< To determine the GATT Proxy state of a Configuration Server */ +#define ESP_BLE_MESH_MODEL_OP_RELAY_GET OP_RELAY_GET /*!< To determine the Relay and Relay Retransmit states of a Configuration Server */ +#define ESP_BLE_MESH_MODEL_OP_MODEL_PUB_GET OP_MOD_PUB_GET /*!< To determine the Publish Address, Publish AppKey Index, CredentialFlag, + Publish Period, Publish Retransmit Count, Publish Retransmit Interval Steps, + and Publish TTL states of a particular Model within the element */ +#define ESP_BLE_MESH_MODEL_OP_FRIEND_GET OP_FRIEND_GET /*!< To determine the Friend state of a Configuration Server */ +#define ESP_BLE_MESH_MODEL_OP_HEARTBEAT_PUB_GET OP_HEARTBEAT_PUB_GET /*!< To determine the Heartbeat Subscription Source, Heartbeat Subscription Destination, + Heartbeat Subscription Count Log, Heartbeat Subscription Period Log, Heartbeat + Subscription Min Hops, and Heartbeat Subscription Max Hops states of a node */ +#define ESP_BLE_MESH_MODEL_OP_HEARTBEAT_SUB_GET OP_HEARTBEAT_SUB_GET /*!< To determine the Heartbeat Subscription Source, Heartbeat Subscription Destination, + Heartbeat Subscription Count Log, Heartbeat Subscription Period Log, Heartbeat + Subscription Min Hops, and Heartbeat Subscription Max Hops states of a node */ +#define ESP_BLE_MESH_MODEL_OP_NET_KEY_GET OP_NET_KEY_GET /*!< To determine all NetKeys known to the node */ +#define ESP_BLE_MESH_MODEL_OP_APP_KEY_GET OP_APP_KEY_GET /*!< To determine all AppKeys bound to the NetKey */ +#define ESP_BLE_MESH_MODEL_OP_NODE_IDENTITY_GET OP_NODE_IDENTITY_GET /*!< To get the current Node Identity state for a subnet */ +#define ESP_BLE_MESH_MODEL_OP_SIG_MODEL_SUB_GET OP_MOD_SUB_GET /*!< To get the list of subscription addresses of a model within the element */ +#define ESP_BLE_MESH_MODEL_OP_VENDOR_MODEL_SUB_GET OP_MOD_SUB_GET_VND /*!< To get the list of subscription addresses of a model within the element */ +#define ESP_BLE_MESH_MODEL_OP_SIG_MODEL_APP_GET OP_SIG_MOD_APP_GET /*!< To request report of all AppKeys bound to the SIG Model */ +#define ESP_BLE_MESH_MODEL_OP_VENDOR_MODEL_APP_GET OP_VND_MOD_APP_GET /*!< To request report of all AppKeys bound to the Vendor Model */ +#define ESP_BLE_MESH_MODEL_OP_KEY_REFRESH_PHASE_GET OP_KRP_GET /*!< To get the current Key Refresh Phase state of the identified network key */ +#define ESP_BLE_MESH_MODEL_OP_LPN_POLLTIMEOUT_GET OP_LPN_TIMEOUT_GET /*!< To get the current value of PollTimeout timer of the Low Power node within a Friend node */ +#define ESP_BLE_MESH_MODEL_OP_NETWORK_TRANSMIT_GET OP_NET_TRANSMIT_GET /*!< To get the current Network Transmit state of a node */ + +/*!< The following opcodes will only be used in the esp_ble_mesh_config_client_set_state function. */ +typedef uint32_t esp_ble_mesh_opcode_config_client_set_t; /*!< esp_ble_mesh_opcode_config_client_set_t belongs to esp_ble_mesh_opcode_t, + this typedef is only used to locate the opcodes used by esp_ble_mesh_config_client_set_state */ +#define ESP_BLE_MESH_MODEL_OP_BEACON_SET OP_BEACON_SET /*!< Set the Secure Network Beacon state of a Configuration Server with acknowledgment */ +#define ESP_BLE_MESH_MODEL_OP_DEFAULT_TTL_SET OP_DEFAULT_TTL_SET /*!< Set the Default TTL state of a Configuration Server with acknowledgment */ +#define ESP_BLE_MESH_MODEL_OP_GATT_PROXY_SET OP_GATT_PROXY_SET /*!< Determine the GATT Proxy state of a Configuration Server */ +#define ESP_BLE_MESH_MODEL_OP_RELAY_SET OP_RELAY_SET /*!< Set the Relay and Relay Retransmit states of a Configuration Server with acknowledgment */ +#define ESP_BLE_MESH_MODEL_OP_MODEL_PUB_SET OP_MOD_PUB_SET /*!< Set the Publish Address, Publish AppKey Index, CredentialFlag, Publish + Period, Publish Retransmit Count, Publish Retransmit Interval Steps, and + Publish TTL states of a particular model within the element with acknowledgment */ +#define ESP_BLE_MESH_MODEL_OP_MODEL_SUB_ADD OP_MOD_SUB_ADD /*!< Add the address to the Subscription List state of a particular model + within the element with acknowledgment */ +#define ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_ADD OP_MOD_SUB_VA_ADD /*!< Add the Label UUID to the Subscription List state of a particular model + within the element with acknowledgment */ +#define ESP_BLE_MESH_MODEL_OP_MODEL_SUB_DELETE OP_MOD_SUB_DEL /*!< Delete the address from the Subscription List state of a particular + model within the element with acknowledgment */ +#define ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_DELETE OP_MOD_SUB_VA_DEL /*!< Delete the Label UUID from the Subscription List state of a particular + model within the element with acknowledgment */ +#define ESP_BLE_MESH_MODEL_OP_MODEL_SUB_OVERWRITE OP_MOD_SUB_OVERWRITE /*!< Clear the Subscription List and add the address to the Subscription List + state of a particular Model within the element with acknowledgment */ +#define ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_OVERWRITE OP_MOD_SUB_VA_OVERWRITE /*!< Clear the Subscription List and add the Label UUID to the Subscription + List state of a particular model within the element with acknowledgment */ +#define ESP_BLE_MESH_MODEL_OP_NET_KEY_ADD OP_NET_KEY_ADD /*!< Add the NetKey identified by NetKeyIndex to the NetKey List state with acknowledgment */ +#define ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD OP_APP_KEY_ADD /*!< Add the AppKey to the AppKey List and bind it to the NetKey identified + by the NetKeyIndex of a Configuration Server with acknowledgment */ +#define ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND OP_MOD_APP_BIND /*!< Bind the AppKey to a model of a particular element of a Configuration Server with acknowledgment */ +#define ESP_BLE_MESH_MODEL_OP_NODE_RESET OP_NODE_RESET /*!< Reset a node (other than a Provisioner) and remove it from the network */ +#define ESP_BLE_MESH_MODEL_OP_FRIEND_SET OP_FRIEND_SET /*!< Set the Friend state of a Configuration Server with acknowledgment */ +#define ESP_BLE_MESH_MODEL_OP_HEARTBEAT_PUB_SET OP_HEARTBEAT_PUB_SET /*!< Set the Heartbeat Publication Destination, Heartbeat Publication Count, + Heartbeat Publication Period, Heartbeat Publication TTL, Publication Features, + and Publication NetKey Index of a node with acknowledgment */ +#define ESP_BLE_MESH_MODEL_OP_HEARTBEAT_SUB_SET OP_HEARTBEAT_SUB_SET /*!< Determine the Heartbeat Subscription Source, Heartbeat Subscription Destination, + Heartbeat Subscription Count Log, Heartbeat Subscription Period Log, Heartbeat + Subscription Min Hops, and Heartbeat Subscription Max Hops states of a node */ +#define ESP_BLE_MESH_MODEL_OP_NET_KEY_UPDATE OP_NET_KEY_UPDATE /*!< To update a NetKey on a node */ +#define ESP_BLE_MESH_MODEL_OP_NET_KEY_DELETE OP_NET_KEY_DEL /*!< To delete a NetKey on a NetKey List from a node */ +#define ESP_BLE_MESH_MODEL_OP_APP_KEY_UPDATE OP_APP_KEY_UPDATE /*!< To update an AppKey value on the AppKey List on a node */ +#define ESP_BLE_MESH_MODEL_OP_APP_KEY_DELETE OP_APP_KEY_DEL /*!< To delete an AppKey from the AppKey List on a node */ +#define ESP_BLE_MESH_MODEL_OP_NODE_IDENTITY_SET OP_NODE_IDENTITY_SET /*!< To set the current Node Identity state for a subnet */ +#define ESP_BLE_MESH_MODEL_OP_KEY_REFRESH_PHASE_SET OP_KRP_SET /*!< To set the Key Refresh Phase state of the identified network key */ +#define ESP_BLE_MESH_MODEL_OP_MODEL_PUB_VIRTUAL_ADDR_SET OP_MOD_PUB_VA_SET /*!< To set the model Publication state of an outgoing message that originates from a model */ +#define ESP_BLE_MESH_MODEL_OP_MODEL_SUB_DELETE_ALL OP_MOD_SUB_DEL_ALL /*!< To discard the Subscription List of a model */ +#define ESP_BLE_MESH_MODEL_OP_MODEL_APP_UNBIND OP_MOD_APP_UNBIND /*!< To remove the binding between an AppKey and a model */ +#define ESP_BLE_MESH_MODEL_OP_NETWORK_TRANSMIT_SET OP_NET_TRANSMIT_SET /*!< To set the Network Transmit state of a node */ + +/*!< The following opcodes are used by the BLE Mesh Config Server Model internally to respond to the Config Client Model's request messages */ +typedef uint32_t esp_ble_mesh_config_model_status_t; /*!< esp_ble_mesh_config_model_status_t belongs to esp_ble_mesh_opcode_t, this typedef + is only used to locate the opcodes used by the Config Model messages */ +#define ESP_BLE_MESH_MODEL_OP_BEACON_STATUS OP_BEACON_STATUS +#define ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_STATUS OP_DEV_COMP_DATA_STATUS +#define ESP_BLE_MESH_MODEL_OP_DEFAULT_TTL_STATUS OP_DEFAULT_TTL_STATUS +#define ESP_BLE_MESH_MODEL_OP_GATT_PROXY_STATUS OP_GATT_PROXY_STATUS +#define ESP_BLE_MESH_MODEL_OP_RELAY_STATUS OP_RELAY_STATUS +#define ESP_BLE_MESH_MODEL_OP_MODEL_PUB_STATUS OP_MOD_PUB_STATUS +#define ESP_BLE_MESH_MODEL_OP_MODEL_SUB_STATUS OP_MOD_SUB_STATUS +#define ESP_BLE_MESH_MODEL_OP_SIG_MODEL_SUB_LIST OP_MOD_SUB_LIST +#define ESP_BLE_MESH_MODEL_OP_VENDOR_MODEL_SUB_LIST OP_MOD_SUB_LIST_VND +#define ESP_BLE_MESH_MODEL_OP_NET_KEY_STATUS OP_NET_KEY_STATUS +#define ESP_BLE_MESH_MODEL_OP_NET_KEY_LIST OP_NET_KEY_LIST +#define ESP_BLE_MESH_MODEL_OP_APP_KEY_STATUS OP_APP_KEY_STATUS +#define ESP_BLE_MESH_MODEL_OP_APP_KEY_LIST OP_APP_KEY_LIST +#define ESP_BLE_MESH_MODEL_OP_NODE_IDENTITY_STATUS OP_NODE_IDENTITY_STATUS +#define ESP_BLE_MESH_MODEL_OP_MODEL_APP_STATUS OP_MOD_APP_STATUS +#define ESP_BLE_MESH_MODEL_OP_SIG_MODEL_APP_LIST OP_SIG_MOD_APP_LIST +#define ESP_BLE_MESH_MODEL_OP_VENDOR_MODEL_APP_LIST OP_VND_MOD_APP_LIST +#define ESP_BLE_MESH_MODEL_OP_NODE_RESET_STATUS OP_NODE_RESET_STATUS +#define ESP_BLE_MESH_MODEL_OP_FRIEND_STATUS OP_FRIEND_STATUS +#define ESP_BLE_MESH_MODEL_OP_KEY_REFRESH_PHASE_STATUS OP_KRP_STATUS +#define ESP_BLE_MESH_MODEL_OP_HEARTBEAT_PUB_STATUS OP_HEARTBEAT_PUB_STATUS +#define ESP_BLE_MESH_MODEL_OP_HEARTBEAT_SUB_STATUS OP_HEARTBEAT_SUB_STATUS +#define ESP_BLE_MESH_MODEL_OP_LPN_POLLTIMEOUT_STATUS OP_LPN_TIMEOUT_STATUS +#define ESP_BLE_MESH_MODEL_OP_NETWORK_TRANSMIT_STATUS OP_NET_TRANSMIT_STATUS + +/*!< The following opcodes will only be used in the esp_ble_mesh_health_client_get_state function. */ +typedef uint32_t esp_ble_mesh_opcode_health_client_get_t; /*!< esp_ble_mesh_opcode_health_client_get_t belongs to esp_ble_mesh_opcode_t, + this typedef is only used to locate the opcodes used by esp_ble_mesh_health_client_get_state */ +#define ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_GET OP_HEALTH_FAULT_GET /*!< Get the current Registered Fault state */ +#define ESP_BLE_MESH_MODEL_OP_HEALTH_PERIOD_GET OP_HEALTH_PERIOD_GET /*!< Get the current Health Period state */ +#define ESP_BLE_MESH_MODEL_OP_ATTENTION_GET OP_ATTENTION_GET /*!< Get the current Attention Timer state */ + +/*!< The following opcodes will only be used in the esp_ble_mesh_health_client_set_state function. */ +typedef uint32_t esp_ble_mesh_opcode_health_client_set_t; /*!< esp_ble_mesh_opcode_health_client_set_t belongs to esp_ble_mesh_opcode_t, + this typedef is only used to locate the opcodes used by esp_ble_mesh_health_client_set_state */ +#define ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_CLEAR OP_HEALTH_FAULT_CLEAR /*!< Clear Health Fault acknowledged */ +#define ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_CLEAR_UNACK OP_HEALTH_FAULT_CLEAR_UNREL /*!< Clear Health Fault Unacknowledged */ +#define ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_TEST OP_HEALTH_FAULT_TEST /*!< Invoke Health Fault Test acknowledged */ +#define ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_TEST_UNACK OP_HEALTH_FAULT_TEST_UNREL /*!< Invoke Health Fault Test unacknowledged */ +#define ESP_BLE_MESH_MODEL_OP_HEALTH_PERIOD_SET OP_HEALTH_PERIOD_SET /*!< Set Health Period acknowledged */ +#define ESP_BLE_MESH_MODEL_OP_HEALTH_PERIOD_SET_UNACK OP_HEALTH_PERIOD_SET_UNREL /*!< Set Health Period unacknowledged */ +#define ESP_BLE_MESH_MODEL_OP_ATTENTION_SET OP_ATTENTION_SET /*!< Set Health Attention acknowledged of the Health Server */ +#define ESP_BLE_MESH_MODEL_OP_ATTENTION_SET_UNACK OP_ATTENTION_SET_UNREL /*!< Set Health Attention Unacknowledged of the Health Server */ + +/*!< The following opcodes are used by the BLE Mesh Health Server Model internally to respond to the Health Client Model's request messages */ +typedef uint32_t esp_ble_mesh_health_model_status_t; /*!< esp_ble_mesh_health_model_status_t belongs to esp_ble_mesh_opcode_t, this typedef + is only used to locate the opcodes used by the Health Model messages */ +#define ESP_BLE_MESH_MODEL_OP_HEALTH_CURRENT_STATUS OP_HEALTH_CURRENT_STATUS +#define ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_STATUS OP_HEALTH_FAULT_STATUS +#define ESP_BLE_MESH_MODEL_OP_HEALTH_PERIOD_STATUS OP_HEALTH_PERIOD_STATUS +#define ESP_BLE_MESH_MODEL_OP_ATTENTION_STATUS OP_ATTENTION_STATUS + +typedef uint32_t esp_ble_mesh_generic_message_opcode_t; /*!< esp_ble_mesh_generic_message_opcode_t belongs to esp_ble_mesh_opcode_t, + this typedef is only used to locate the opcodes used by functions + esp_ble_mesh_generic_client_get_state & esp_ble_mesh_generic_client_set_state */ +/*!< Generic OnOff Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET BLE_MESH_MODEL_OP_GEN_ONOFF_GET +#define ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET BLE_MESH_MODEL_OP_GEN_ONOFF_SET +#define ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS + +/*!< Generic Level Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_GEN_LEVEL_GET BLE_MESH_MODEL_OP_GEN_LEVEL_GET +#define ESP_BLE_MESH_MODEL_OP_GEN_LEVEL_SET BLE_MESH_MODEL_OP_GEN_LEVEL_SET +#define ESP_BLE_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK BLE_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS +#define ESP_BLE_MESH_MODEL_OP_GEN_DELTA_SET BLE_MESH_MODEL_OP_GEN_DELTA_SET +#define ESP_BLE_MESH_MODEL_OP_GEN_DELTA_SET_UNACK BLE_MESH_MODEL_OP_GEN_DELTA_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_GEN_MOVE_SET BLE_MESH_MODEL_OP_GEN_MOVE_SET +#define ESP_BLE_MESH_MODEL_OP_GEN_MOVE_SET_UNACK BLE_MESH_MODEL_OP_GEN_MOVE_SET_UNACK + +/*!< Generic Default Transition Time Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_GET BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_GET +#define ESP_BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET +#define ESP_BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET_UNACK BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_STATUS BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_STATUS + +/*!< Generic Power OnOff Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_GEN_ONPOWERUP_GET BLE_MESH_MODEL_OP_GEN_ONPOWERUP_GET +#define ESP_BLE_MESH_MODEL_OP_GEN_ONPOWERUP_STATUS BLE_MESH_MODEL_OP_GEN_ONPOWERUP_STATUS + +/*!< Generic Power OnOff Setup Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET +#define ESP_BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET_UNACK BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET_UNACK + +/*!< Generic Power Level Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_GET BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_GET +#define ESP_BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET +#define ESP_BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET_UNACK BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS +#define ESP_BLE_MESH_MODEL_OP_GEN_POWER_LAST_GET BLE_MESH_MODEL_OP_GEN_POWER_LAST_GET +#define ESP_BLE_MESH_MODEL_OP_GEN_POWER_LAST_STATUS BLE_MESH_MODEL_OP_GEN_POWER_LAST_STATUS +#define ESP_BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_GET BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_GET +#define ESP_BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS +#define ESP_BLE_MESH_MODEL_OP_GEN_POWER_RANGE_GET BLE_MESH_MODEL_OP_GEN_POWER_RANGE_GET +#define ESP_BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS + +/*!< Generic Power Level Setup Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET +#define ESP_BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET_UNACK BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET +#define ESP_BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET_UNACK BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET_UNACK + +/*!< Generic Battery Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_GEN_BATTERY_GET BLE_MESH_MODEL_OP_GEN_BATTERY_GET +#define ESP_BLE_MESH_MODEL_OP_GEN_BATTERY_STATUS BLE_MESH_MODEL_OP_GEN_BATTERY_STATUS + +/*!< Generic Location Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_GET BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_GET +#define ESP_BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_STATUS BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_STATUS +#define ESP_BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_GET BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_GET +#define ESP_BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_STATUS BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_STATUS + +/*!< Generic Location Setup Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET +#define ESP_BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET_UNACK BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET +#define ESP_BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET_UNACK BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET_UNACK + +/*!< Generic Manufacturer Property Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTIES_GET BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_GET +#define ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTIES_STATUS BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_STATUS +#define ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTY_GET BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_GET +#define ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTY_SET BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET +#define ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTY_SET_UNACK BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTY_STATUS BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_STATUS + +/*!< Generic Admin Property Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_GET BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_GET +#define ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_STATUS BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_STATUS +#define ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET +#define ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET +#define ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET_UNACK BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_STATUS BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_STATUS + +/*!< Generic User Property Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_GET BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_GET +#define ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS +#define ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET +#define ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET +#define ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET_UNACK BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_STATUS BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_STATUS + +/*!< Generic Client Property Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_GET BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_GET +#define ESP_BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS + +typedef uint32_t esp_ble_mesh_sensor_message_opcode_t; /*!< esp_ble_mesh_sensor_message_opcode_t belongs to esp_ble_mesh_opcode_t, + this typedef is only used to locate the opcodes used by functions + esp_ble_mesh_sensor_client_get_state & esp_ble_mesh_sensor_client_set_state */ +/*!< Sensor Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET +#define ESP_BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS +#define ESP_BLE_MESH_MODEL_OP_SENSOR_GET BLE_MESH_MODEL_OP_SENSOR_GET +#define ESP_BLE_MESH_MODEL_OP_SENSOR_STATUS BLE_MESH_MODEL_OP_SENSOR_STATUS +#define ESP_BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET +#define ESP_BLE_MESH_MODEL_OP_SENSOR_COLUMN_STATUS BLE_MESH_MODEL_OP_SENSOR_COLUMN_STATUS +#define ESP_BLE_MESH_MODEL_OP_SENSOR_SERIES_GET BLE_MESH_MODEL_OP_SENSOR_SERIES_GET +#define ESP_BLE_MESH_MODEL_OP_SENSOR_SERIES_STATUS BLE_MESH_MODEL_OP_SENSOR_SERIES_STATUS + +/*!< Sensor Setup Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET +#define ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET +#define ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS +#define ESP_BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET +#define ESP_BLE_MESH_MODEL_OP_SENSOR_SETTINGS_STATUS BLE_MESH_MODEL_OP_SENSOR_SETTINGS_STATUS +#define ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_GET BLE_MESH_MODEL_OP_SENSOR_SETTING_GET +#define ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET BLE_MESH_MODEL_OP_SENSOR_SETTING_SET +#define ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET_UNACK BLE_MESH_MODEL_OP_SENSOR_SETTING_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_STATUS BLE_MESH_MODEL_OP_SENSOR_SETTING_STATUS + +typedef uint32_t esp_ble_mesh_time_scene_message_opcode_t; /*!< esp_ble_mesh_time_scene_message_opcode_t belongs to esp_ble_mesh_opcode_t, + this typedef is only used to locate the opcodes used by functions + esp_ble_mesh_time_scene_client_get_state & esp_ble_mesh_time_scene_client_set_state */ +/*!< Time Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_TIME_GET BLE_MESH_MODEL_OP_TIME_GET +#define ESP_BLE_MESH_MODEL_OP_TIME_SET BLE_MESH_MODEL_OP_TIME_SET +#define ESP_BLE_MESH_MODEL_OP_TIME_STATUS BLE_MESH_MODEL_OP_TIME_STATUS +#define ESP_BLE_MESH_MODEL_OP_TIME_ROLE_GET BLE_MESH_MODEL_OP_TIME_ROLE_GET +#define ESP_BLE_MESH_MODEL_OP_TIME_ROLE_SET BLE_MESH_MODEL_OP_TIME_ROLE_SET +#define ESP_BLE_MESH_MODEL_OP_TIME_ROLE_STATUS BLE_MESH_MODEL_OP_TIME_ROLE_STATUS +#define ESP_BLE_MESH_MODEL_OP_TIME_ZONE_GET BLE_MESH_MODEL_OP_TIME_ZONE_GET +#define ESP_BLE_MESH_MODEL_OP_TIME_ZONE_SET BLE_MESH_MODEL_OP_TIME_ZONE_SET +#define ESP_BLE_MESH_MODEL_OP_TIME_ZONE_STATUS BLE_MESH_MODEL_OP_TIME_ZONE_STATUS +#define ESP_BLE_MESH_MODEL_OP_TAI_UTC_DELTA_GET BLE_MESH_MODEL_OP_TAI_UTC_DELTA_GET +#define ESP_BLE_MESH_MODEL_OP_TAI_UTC_DELTA_SET BLE_MESH_MODEL_OP_TAI_UTC_DELTA_SET +#define ESP_BLE_MESH_MODEL_OP_TAI_UTC_DELTA_STATUS BLE_MESH_MODEL_OP_TAI_UTC_DELTA_STATUS + +/*!< Scene Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_SCENE_GET BLE_MESH_MODEL_OP_SCENE_GET +#define ESP_BLE_MESH_MODEL_OP_SCENE_RECALL BLE_MESH_MODEL_OP_SCENE_RECALL +#define ESP_BLE_MESH_MODEL_OP_SCENE_RECALL_UNACK BLE_MESH_MODEL_OP_SCENE_RECALL_UNACK +#define ESP_BLE_MESH_MODEL_OP_SCENE_STATUS BLE_MESH_MODEL_OP_SCENE_STATUS +#define ESP_BLE_MESH_MODEL_OP_SCENE_REGISTER_GET BLE_MESH_MODEL_OP_SCENE_REGISTER_GET +#define ESP_BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS + +/*!< Scene Setup Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_SCENE_STORE BLE_MESH_MODEL_OP_SCENE_STORE +#define ESP_BLE_MESH_MODEL_OP_SCENE_STORE_UNACK BLE_MESH_MODEL_OP_SCENE_STORE_UNACK +#define ESP_BLE_MESH_MODEL_OP_SCENE_DELETE BLE_MESH_MODEL_OP_SCENE_DELETE +#define ESP_BLE_MESH_MODEL_OP_SCENE_DELETE_UNACK BLE_MESH_MODEL_OP_SCENE_DELETE_UNACK + +/*!< Scheduler Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_SCHEDULER_ACT_GET BLE_MESH_MODEL_OP_SCHEDULER_ACT_GET +#define ESP_BLE_MESH_MODEL_OP_SCHEDULER_ACT_STATUS BLE_MESH_MODEL_OP_SCHEDULER_ACT_STATUS +#define ESP_BLE_MESH_MODEL_OP_SCHEDULER_GET BLE_MESH_MODEL_OP_SCHEDULER_GET +#define ESP_BLE_MESH_MODEL_OP_SCHEDULER_STATUS BLE_MESH_MODEL_OP_SCHEDULER_STATUS + +/*!< Scheduler Setup Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET +#define ESP_BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET_UNACK BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET_UNACK + +typedef uint32_t esp_ble_mesh_light_message_opcode_t; /*!< esp_ble_mesh_light_message_opcode_t belongs to esp_ble_mesh_opcode_t, + this typedef is only used to locate the opcodes used by functions + esp_ble_mesh_light_client_get_state & esp_ble_mesh_light_client_set_state */ +/*!< Light Lightness Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_GET BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET_UNACK BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_GET BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET_UNACK BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_GET BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_STATUS BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_STATUS +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_GET BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_STATUS BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_STATUS +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_GET BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_STATUS BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_STATUS + +/*!< Light Lightness Setup Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET_UNACK BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET_UNACK BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET_UNACK + +/*!< Light CTL Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_GET BLE_MESH_MODEL_OP_LIGHT_CTL_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_SET BLE_MESH_MODEL_OP_LIGHT_CTL_SET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_SET_UNACK BLE_MESH_MODEL_OP_LIGHT_CTL_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS +#define ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_GET BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_GET BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_STATUS BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_STATUS +#define ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET_UNACK BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS +#define ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_GET BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_STATUS BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_STATUS + +/*!< Light CTL Setup Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET_UNACK BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET_UNACK BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET_UNACK + +/*!< Light HSL Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_GET BLE_MESH_MODEL_OP_LIGHT_HSL_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_GET BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET_UNACK BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_GET BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET_UNACK BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_SET BLE_MESH_MODEL_OP_LIGHT_HSL_SET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_SET_UNACK BLE_MESH_MODEL_OP_LIGHT_HSL_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_GET BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_STATUS BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_STATUS +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_GET BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_STATUS BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_STATUS +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_GET BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_STATUS BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_STATUS + +/*!< Light HSL Setup Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET_UNACK BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET_UNACK BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET_UNACK /* Model spec is wrong */ + +/*!< Light xyL Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_GET BLE_MESH_MODEL_OP_LIGHT_XYL_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_SET BLE_MESH_MODEL_OP_LIGHT_XYL_SET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_SET_UNACK BLE_MESH_MODEL_OP_LIGHT_XYL_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS +#define ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_GET BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_STATUS BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_STATUS +#define ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_GET BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_STATUS BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_STATUS +#define ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_GET BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_STATUS BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_STATUS + +/*!< Light xyL Setup Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET_UNACK BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET_UNACK BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET_UNACK + +/*!< Light Control Message Opcode */ +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LC_MODE_GET BLE_MESH_MODEL_OP_LIGHT_LC_MODE_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET_UNACK BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LC_MODE_STATUS BLE_MESH_MODEL_OP_LIGHT_LC_MODE_STATUS +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LC_OM_GET BLE_MESH_MODEL_OP_LIGHT_LC_OM_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET_UNACK BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LC_OM_STATUS BLE_MESH_MODEL_OP_LIGHT_LC_OM_STATUS +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_GET BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET_UNACK BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_GET BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_GET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET_UNACK BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET_UNACK +#define ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS + +typedef uint32_t esp_ble_mesh_opcode_t; +/*!< End of defines of esp_ble_mesh_opcode_t */ + +#define ESP_BLE_MESH_CFG_STATUS_SUCCESS STATUS_SUCCESS +#define ESP_BLE_MESH_CFG_STATUS_INVALID_ADDRESS STATUS_INVALID_ADDRESS +#define ESP_BLE_MESH_CFG_STATUS_INVALID_MODEL STATUS_INVALID_MODEL +#define ESP_BLE_MESH_CFG_STATUS_INVALID_APPKEY STATUS_INVALID_APPKEY +#define ESP_BLE_MESH_CFG_STATUS_INVALID_NETKEY STATUS_INVALID_NETKEY +#define ESP_BLE_MESH_CFG_STATUS_INSUFFICIENT_RESOURCES STATUS_INSUFF_RESOURCES +#define ESP_BLE_MESH_CFG_STATUS_KEY_INDEX_ALREADY_STORED STATUS_IDX_ALREADY_STORED +#define ESP_BLE_MESH_CFG_STATUS_INVALID_PUBLISH_PARAMETERS STATUS_NVAL_PUB_PARAM +#define ESP_BLE_MESH_CFG_STATUS_NOT_A_SUBSCRIBE_MODEL STATUS_NOT_SUB_MOD +#define ESP_BLE_MESH_CFG_STATUS_STORAGE_FAILURE STATUS_STORAGE_FAIL +#define ESP_BLE_MESH_CFG_STATUS_FEATURE_NOT_SUPPORTED STATUS_FEAT_NOT_SUPP +#define ESP_BLE_MESH_CFG_STATUS_CANNOT_UPDATE STATUS_CANNOT_UPDATE +#define ESP_BLE_MESH_CFG_STATUS_CANNOT_REMOVE STATUS_CANNOT_REMOVE +#define ESP_BLE_MESH_CFG_STATUS_CANNOT_BIND STATUS_CANNOT_BIND +#define ESP_BLE_MESH_CFG_STATUS_TEMP_UNABLE_TO_CHANGE_STATE STATUS_TEMP_STATE_CHG_FAIL +#define ESP_BLE_MESH_CFG_STATUS_CANNOT_SET STATUS_CANNOT_SET +#define ESP_BLE_MESH_CFG_STATUS_UNSPECIFIED_ERROR STATUS_UNSPECIFIED +#define ESP_BLE_MESH_CFG_STATUS_INVALID_BINDING STATUS_INVALID_BINDING +typedef uint8_t esp_ble_mesh_cfg_status_t; /*!< This typedef is only used to indicate the status code + contained in some of the Config Server Model status message */ + +#define ESP_BLE_MESH_MODEL_STATUS_SUCCESS 0x00 +#define ESP_BLE_MESH_MODEL_STATUS_CANNOT_SET_RANGE_MIN 0x01 +#define ESP_BLE_MESH_MODEL_STATUS_CANNOT_SET_RANGE_MAX 0x02 +typedef uint8_t esp_ble_mesh_model_status_t; /*!< This typedef is only used to indicate the status code contained in + some of the server model (e.g. Generic Server Model) status message */ + +/** @def ESP_BLE_MESH_TRANSMIT + * + * @brief Encode transmission count & interval steps. + * + * @note For example, ESP_BLE_MESH_TRANSMIT(2, 20) means that the message + * will be sent about 90ms(count is 3, step is 1, interval is 30 ms + * which includes 10ms of advertising interval random delay). + * + * @param count Number of retransmissions (first transmission is excluded). + * @param int_ms Interval steps in milliseconds. Must be greater than 0 + * and a multiple of 10. + * + * @return BLE Mesh transmit value that can be used e.g. for the default + * values of the Configuration Model data. + */ +#define ESP_BLE_MESH_TRANSMIT(count, int_ms) BLE_MESH_TRANSMIT(count, int_ms) + +/** @def ESP_BLE_MESH_GET_TRANSMIT_COUNT + * + * @brief Decode transmit count from a transmit value. + * + * @param transmit Encoded transmit count & interval value. + * + * @return Transmission count (actual transmissions equal to N + 1). + */ +#define ESP_BLE_MESH_GET_TRANSMIT_COUNT(transmit) BLE_MESH_TRANSMIT_COUNT(transmit) + +/** @def ESP_BLE_MESH_GET_TRANSMIT_INTERVAL + * + * @brief Decode transmit interval from a transmit value. + * + * @param transmit Encoded transmit count & interval value. + * + * @return Transmission interval in milliseconds. + */ +#define ESP_BLE_MESH_GET_TRANSMIT_INTERVAL(transmit) BLE_MESH_TRANSMIT_INT(transmit) + +/** @def ESP_BLE_MESH_PUBLISH_TRANSMIT + * + * @brief Encode Publish Retransmit count & interval steps. + * + * @param count Number of retransmissions (first transmission is excluded). + * @param int_ms Interval steps in milliseconds. Must be greater than 0 + * and a multiple of 50. + * + * @return BLE Mesh transmit value that can be used e.g. for the default + * values of the Configuration Model data. + */ +#define ESP_BLE_MESH_PUBLISH_TRANSMIT(count, int_ms) BLE_MESH_PUB_TRANSMIT(count, int_ms) + +/** @def ESP_BLE_MESH_GET_PUBLISH_TRANSMIT_COUNT + * + * @brief Decode Publish Retransmit count from a given value. + * + * @param transmit Encoded Publish Retransmit count & interval value. + * + * @return Retransmission count (actual transmissions equal to N + 1). + */ +#define ESP_BLE_MESH_GET_PUBLISH_TRANSMIT_COUNT(transmit) BLE_MESH_PUB_TRANSMIT_COUNT(transmit) + +/** @def ESP_BLE_MESH_GET_PUBLISH_TRANSMIT_INTERVAL + * + * @brief Decode Publish Retransmit interval from a given value. + * + * @param transmit Encoded Publish Retransmit count & interval value. + * + * @return Transmission interval in milliseconds. + */ +#define ESP_BLE_MESH_GET_PUBLISH_TRANSMIT_INTERVAL(transmit) BLE_MESH_PUB_TRANSMIT_INT(transmit) + +/* esp_ble_mesh_cb_t is not needed to be initialized by users (set with 0 and will be initialized internally) */ +typedef uint32_t esp_ble_mesh_cb_t; + +typedef enum { + ESP_BLE_MESH_TYPE_PROV_CB, + ESP_BLE_MESH_TYPE_OUTPUT_NUM_CB, + ESP_BLE_MESH_TYPE_OUTPUT_STR_CB, + ESP_BLE_MESH_TYPE_INTPUT_CB, + ESP_BLE_MESH_TYPE_LINK_OPEN_CB, + ESP_BLE_MESH_TYPE_LINK_CLOSE_CB, + ESP_BLE_MESH_TYPE_COMPLETE_CB, + ESP_BLE_MESH_TYPE_RESET_CB, +} esp_ble_mesh_cb_type_t; + +/*!< This enum value is provisioning authentication oob method */ +typedef enum { + ESP_BLE_MESH_NO_OOB, + ESP_BLE_MESH_STATIC_OOB, + ESP_BLE_MESH_OUTPUT_OOB, + ESP_BLE_MESH_INPUT_OOB, +} esp_ble_mesh_oob_method_t; + +/*!< This enum value is associated with bt_mesh_output_action_t in mesh_main.h */ +typedef enum { + ESP_BLE_MESH_NO_OUTPUT = 0, + ESP_BLE_MESH_BLINK = BIT(0), + ESP_BLE_MESH_BEEP = BIT(1), + ESP_BLE_MESH_VIBRATE = BIT(2), + ESP_BLE_MESH_DISPLAY_NUMBER = BIT(3), + ESP_BLE_MESH_DISPLAY_STRING = BIT(4), +} esp_ble_mesh_output_action_t; + +/*!< This enum value is associated with bt_mesh_input_action_t in mesh_main.h */ +typedef enum { + ESP_BLE_MESH_NO_INPUT = 0, + ESP_BLE_MESH_PUSH = BIT(0), + ESP_BLE_MESH_TWIST = BIT(1), + ESP_BLE_MESH_ENTER_NUMBER = BIT(2), + ESP_BLE_MESH_ENTER_STRING = BIT(3), +} esp_ble_mesh_input_action_t; + +/*!< This enum value is associated with bt_mesh_prov_bearer_t in mesh_main.h */ +typedef enum { + ESP_BLE_MESH_PROV_ADV = BIT(0), + ESP_BLE_MESH_PROV_GATT = BIT(1), +} esp_ble_mesh_prov_bearer_t; + +/*!< This enum value is associated with bt_mesh_prov_oob_info_t in mesh_main.h */ +typedef enum { + ESP_BLE_MESH_PROV_OOB_OTHER = BIT(0), + ESP_BLE_MESH_PROV_OOB_URI = BIT(1), + ESP_BLE_MESH_PROV_OOB_2D_CODE = BIT(2), + ESP_BLE_MESH_PROV_OOB_BAR_CODE = BIT(3), + ESP_BLE_MESH_PROV_OOB_NFC = BIT(4), + ESP_BLE_MESH_PROV_OOB_NUMBER = BIT(5), + ESP_BLE_MESH_PROV_OOB_STRING = BIT(6), + /* 7 - 10 are reserved */ + ESP_BLE_MESH_PROV_OOB_ON_BOX = BIT(11), + ESP_BLE_MESH_PROV_OOB_IN_BOX = BIT(12), + ESP_BLE_MESH_PROV_OOB_ON_PAPER = BIT(13), + ESP_BLE_MESH_PROV_OOB_IN_MANUAL = BIT(14), + ESP_BLE_MESH_PROV_OOB_ON_DEV = BIT(15), +} esp_ble_mesh_prov_oob_info_t; + +#define ESP_BLE_MESH_MODEL_OP_1(b0) BLE_MESH_MODEL_OP_1(b0) +#define ESP_BLE_MESH_MODEL_OP_2(b0, b1) BLE_MESH_MODEL_OP_2(b0, b1) +#define ESP_BLE_MESH_MODEL_OP_3(b0, cid) BLE_MESH_MODEL_OP_3(b0, cid) + +/*!< This macro is associated with BLE_MESH_MODEL in mesh_access.h */ +#define ESP_BLE_MESH_SIG_MODEL(_id, _op, _pub, _user_data) \ +{ \ + .model_id = (_id), \ + .op = _op, \ + .keys = { [0 ... (CONFIG_BLE_MESH_MODEL_KEY_COUNT - 1)] = \ + ESP_BLE_MESH_KEY_UNUSED }, \ + .pub = _pub, \ + .groups = { [0 ... (CONFIG_BLE_MESH_MODEL_GROUP_COUNT - 1)] = \ + ESP_BLE_MESH_ADDR_UNASSIGNED }, \ + .user_data = _user_data, \ +} + +/*!< This macro is associated with BLE_MESH_MODEL_VND in mesh_access.h */ +#define ESP_BLE_MESH_VENDOR_MODEL(_company, _id, _op, _pub, _user_data) \ +{ \ + .vnd.company_id = (_company), \ + .vnd.model_id = (_id), \ + .op = _op, \ + .pub = _pub, \ + .keys = { [0 ... (CONFIG_BLE_MESH_MODEL_KEY_COUNT - 1)] = \ + ESP_BLE_MESH_KEY_UNUSED }, \ + .groups = { [0 ... (CONFIG_BLE_MESH_MODEL_GROUP_COUNT - 1)] = \ + ESP_BLE_MESH_ADDR_UNASSIGNED }, \ + .user_data = _user_data, \ +} + +/** @brief Helper to define a BLE Mesh element within an array. + * + * In case the element has no SIG or Vendor models, the helper + * macro ESP_BLE_MESH_MODEL_NONE can be given instead. + * + * @note This macro is associated with BLE_MESH_ELEM in mesh_access.h + * + * @param _loc Location Descriptor. + * @param _mods Array of SIG models. + * @param _vnd_mods Array of vendor models. + */ +#define ESP_BLE_MESH_ELEMENT(_loc, _mods, _vnd_mods) \ +{ \ + .location = (_loc), \ + .sig_model_count = ARRAY_SIZE(_mods), \ + .sig_models = (_mods), \ + .vnd_model_count = ARRAY_SIZE(_vnd_mods), \ + .vnd_models = (_vnd_mods), \ +} + +#define ESP_BLE_MESH_PROV(uuid, sta_val, sta_val_len, out_size, out_act, in_size, in_act) { \ + .uuid = uuid, \ + .static_val = sta_val, \ + .static_val_len = sta_val_len, \ + .output_size = out_size, \ + .output_action = out_act, \ + .input_size = in_size, \ + .input_action = in_act, \ +} + +typedef struct esp_ble_mesh_model esp_ble_mesh_model_t; + +/*!< Abstraction that describes a BLE Mesh Element. + This structure is associated with bt_mesh_elem in mesh_access.h */ +typedef struct { + /* Element Address, assigned during provisioning. */ + uint16_t element_addr; + + /* Location Descriptor (GATT Bluetooth Namespace Descriptors) */ + const uint16_t location; + + /* Model count */ + const uint8_t sig_model_count; + const uint8_t vnd_model_count; + + /* Models */ + esp_ble_mesh_model_t *sig_models; + esp_ble_mesh_model_t *vnd_models; +} esp_ble_mesh_elem_t; + +/*!< Model publication context. + This structure is associated with bt_mesh_model_pub in mesh_access.h */ +typedef struct { + /** The model to which the context belongs. Initialized by the stack. */ + esp_ble_mesh_model_t *model; + + uint16_t publish_addr; /**< Publish Address. */ + uint16_t app_idx; /**< Publish AppKey Index. */ + + uint8_t ttl; /**< Publish Time to Live. */ + uint8_t retransmit; /**< Retransmit Count & Interval Steps. */ + + uint8_t period; /*!< Publish Period. */ + uint16_t period_div: 4, /*!< Divisor for the Period. */ + cred: 1, /*!< Friendship Credentials Flag. */ + fast_period: 1, /**< Use FastPeriodDivisor */ + count: 3; /*!< Retransmissions left. */ + + uint32_t period_start; /**< Start of the current period. */ + + /** @brief Publication buffer, containing the publication message. + * + * This will get correctly created when the publication context + * has been defined using the ESP_BLE_MESH_MODEL_PUB_DEFINE macro. + * + * ESP_BLE_MESH_MODEL_PUB_DEFINE(name, size); + */ + struct net_buf_simple *msg; + + /* The callback is only used for the BLE Mesh stack, not for the app layer. */ + esp_ble_mesh_cb_t update; + + /* Role of the device that is going to publish messages */ + uint8_t dev_role; + + /** Publish Period Timer. Only for stack-internal use. */ + struct k_delayed_work timer; +} esp_ble_mesh_model_pub_t; + +/** @def ESP_BLE_MESH_MODEL_PUB_DEFINE + * + * Define a model publication context. + * + * @param _name Variable name given to the context. + * @param _msg_len Length of the publication message. + * @param _role Role of the device which contains the model. + */ +#define ESP_BLE_MESH_MODEL_PUB_DEFINE(_name, _msg_len, _role) \ + NET_BUF_SIMPLE_DEFINE_STATIC(bt_mesh_pub_msg_##_name, _msg_len); \ + static esp_ble_mesh_model_pub_t _name = { \ + .update = (uint32_t)NULL, \ + .msg = &bt_mesh_pub_msg_##_name, \ + .dev_role = _role, \ + } + +/*!< Model operation context. + This structure is associated with bt_mesh_model_op in mesh_access.h */ +#define ESP_BLE_MESH_MODEL_OP(_opcode, _min_len) \ +{ \ + .opcode = _opcode, \ + .min_len = _min_len, \ + .param_cb = (uint32_t)NULL, \ +} + +typedef struct { + const uint32_t opcode; /* Opcode encoded with the ESP_BLE_MESH_MODEL_OP_* macro */ + const size_t min_len; /* Minimum required message length */ + esp_ble_mesh_cb_t param_cb; /* The callback is only used for BLE Mesh stack, not for the app layer. */ +} esp_ble_mesh_model_op_t; + +/** Define the terminator for the model operation table, each + * model operation struct array must use this terminator as + * the end tag of the operation unit. + */ +#define ESP_BLE_MESH_MODEL_OP_END {0, 0, 0} + +/** Abstraction that describes a Mesh Model instance. + * This structure is associated with bt_mesh_model in mesh_access.h + */ +struct esp_ble_mesh_model { + /* Model ID */ + union { + const uint16_t model_id; + struct { + uint16_t company_id; + uint16_t model_id; + } vnd; + }; + + /* Internal information, mainly for persistent storage */ + uint8_t element_idx; /* Belongs to Nth element */ + uint8_t model_idx; /* Is the Nth model in the element */ + uint16_t flags; /* Information about what has changed */ + + /* The Element to which this Model belongs */ + esp_ble_mesh_elem_t *element; + + /* Model Publication */ + esp_ble_mesh_model_pub_t *const pub; + + /* AppKey List */ + uint16_t keys[CONFIG_BLE_MESH_MODEL_KEY_COUNT]; + + /* Subscription List (group or virtual addresses) */ + uint16_t groups[CONFIG_BLE_MESH_MODEL_GROUP_COUNT]; + + /* Model operation context */ + esp_ble_mesh_model_op_t *op; + + /* Model-specific user data */ + void *user_data; +}; + +/** Helper to define an empty model array. + * This structure is associated with BLE_MESH_MODEL_NONE in mesh_access.h + */ +#define ESP_BLE_MESH_MODEL_NONE ((esp_ble_mesh_model_t []){}) + +/** Message sending context. + * This structure is associated with bt_mesh_msg_ctx in mesh_access.h + */ +typedef struct { + /** NetKey Index of the subnet through which to send the message. */ + uint16_t net_idx; + + /** AppKey Index for message encryption. */ + uint16_t app_idx; + + /** Remote address. */ + uint16_t addr; + + /** Destination address of a received message. Not used for sending. */ + uint16_t recv_dst; + + /** Received TTL value. Not used for sending. */ + uint8_t recv_ttl: 7; + + /** Force sending reliably by using segment acknowledgement */ + uint8_t send_rel: 1; + + /** TTL, or BLE_MESH_TTL_DEFAULT for default TTL. */ + uint8_t send_ttl; + + /** Opcode of a received message. Not used for sending message. */ + uint32_t recv_op; + + /** Model corresponding to the message, no need to be initialized before sending message */ + esp_ble_mesh_model_t *model; + + /** Indicate if the message is sent by a node server model, no need to be initialized before sending message */ + bool srv_send; +} esp_ble_mesh_msg_ctx_t; + +/** Provisioning properties & capabilities. + * This structure is associated with bt_mesh_prov in mesh_access.h + */ +typedef struct { +#if CONFIG_BLE_MESH_NODE + /** The UUID that is used when advertising as an unprovisioned device */ + const uint8_t *uuid; + + /** Optional URI. This will be advertised separately from the + * unprovisioned beacon, however the unprovisioned beacon will + * contain a hash of it so the two can be associated by the + * provisioner. + */ + const char *uri; + + /** Out of Band information field. */ + esp_ble_mesh_prov_oob_info_t oob_info; + + /** Flag indicates whether unprovisioned devices support OOB public key */ + bool oob_pub_key; + + /* This callback is only used for the BLE Mesh stack, not for the app layer */ + esp_ble_mesh_cb_t oob_pub_key_cb; + + /** Static OOB value */ + const uint8_t *static_val; + /** Static OOB value length */ + uint8_t static_val_len; + + /** Maximum size of Output OOB supported */ + uint8_t output_size; + /** Supported Output OOB Actions */ + uint16_t output_actions; + + /** Maximum size of Input OOB supported */ + uint8_t input_size; + /** Supported Input OOB Actions */ + uint16_t input_actions; + + /* These callbacks are only used for the BLE Mesh stack, not for the app layer */ + esp_ble_mesh_cb_t output_num_cb; + esp_ble_mesh_cb_t output_str_cb; + esp_ble_mesh_cb_t input_cb; + esp_ble_mesh_cb_t link_open_cb; + esp_ble_mesh_cb_t link_close_cb; + esp_ble_mesh_cb_t complete_cb; + esp_ble_mesh_cb_t reset_cb; +#endif /* CONFIG_BLE_MESH_NODE */ + +#ifdef CONFIG_BLE_MESH_PROVISIONER + /* Provisioner device UUID */ + const uint8_t *prov_uuid; + + /* Primary element address of the provisioner */ + const uint16_t prov_unicast_addr; + + /* Pre-incremental unicast address value to be assigned to the first device */ + uint16_t prov_start_address; + + /* Attention timer contained in Provisioning Invite PDU */ + uint8_t prov_attention; + + /* Provisioning Algorithm for the Provisioner */ + uint8_t prov_algorithm; + + /* Provisioner public key oob */ + uint8_t prov_pub_key_oob; + + /* The callback is only used for BLE Mesh stack, not for the app layer */ + esp_ble_mesh_cb_t provisioner_prov_read_oob_pub_key; + + /* Provisioner static oob value */ + uint8_t *prov_static_oob_val; + /* Provisioner static oob value length */ + uint8_t prov_static_oob_len; + + /* These callbacks are only used for BLE Mesh stack, not for the app layer */ + esp_ble_mesh_cb_t provisioner_prov_input; + esp_ble_mesh_cb_t provisioner_prov_output; + + /* Key refresh and IV update flag */ + uint8_t flags; + + /* IV index */ + uint32_t iv_index; + + /* These callbacks are only used for BLE Mesh stack, not for the app layer */ + esp_ble_mesh_cb_t provisioner_link_open; + esp_ble_mesh_cb_t provisioner_link_close; + esp_ble_mesh_cb_t provisioner_prov_comp; +#endif /* CONFIG_BLE_MESH_PROVISIONER */ +} esp_ble_mesh_prov_t; + +/** Node Composition + * This structure is associated with bt_mesh_comp in mesh_access.h + */ +typedef struct { + uint16_t cid; + uint16_t pid; + uint16_t vid; + + size_t element_count; + esp_ble_mesh_elem_t *elements; +} esp_ble_mesh_comp_t; + +typedef enum { + ROLE_NODE = 0, + ROLE_PROVISIONER, + ROLE_FAST_PROV, +} esp_ble_mesh_dev_role_t; + +typedef struct { + esp_ble_mesh_opcode_t opcode; /*!< Message opcode */ + esp_ble_mesh_model_t *model; /*!< Pointer to the client model structure */ + esp_ble_mesh_msg_ctx_t ctx; /*!< The context used to send message */ + int32_t msg_timeout; /*!< Timeout value (ms) to get response to the sent message */ + /*!< Note: if using default timeout value in menuconfig, make sure to set this value to 0 */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner, only used for tx */ +} esp_ble_mesh_client_common_param_t; + +typedef uint8_t esp_ble_mesh_dev_add_flag_t; +#define ADD_DEV_RM_AFTER_PROV_FLAG BIT(0) +#define ADD_DEV_START_PROV_NOW_FLAG BIT(1) +#define ADD_DEV_FLUSHABLE_DEV_FLAG BIT(2) +typedef struct { + esp_bd_addr_t addr; + esp_ble_addr_type_t addr_type; + uint8_t uuid[16]; + uint16_t oob_info; + /*!< ADD_DEV_START_PROV_NOW_FLAG shall not be set if the bearer has both PB-ADV and PB-GATT enabled */ + esp_ble_mesh_prov_bearer_t bearer; +} esp_ble_mesh_unprov_dev_add_t; + +#define DEL_DEV_ADDR_FLAG BIT(0) +#define DEL_DEV_UUID_FLAG BIT(1) +typedef struct { + union { + struct { + esp_bd_addr_t addr; + esp_ble_addr_type_t addr_type; + }; + uint8_t uuid[16]; + }; + uint8_t flag; /*!< BIT0: device address; BIT1: device UUID */ +} esp_ble_mesh_device_delete_t; + +#define PROV_DATA_NET_IDX_FLAG BIT(0) +#define PROV_DATA_FLAGS_FLAG BIT(1) +#define PROV_DATA_IV_INDEX_FLAG BIT(2) +typedef struct { + union { + uint16_t net_idx; + uint8_t flags; + uint32_t iv_index; + }; + uint8_t flag; /*!< BIT0: net_idx; BIT1: flags; BIT2: iv_index */ +} esp_ble_mesh_prov_data_info_t; + +typedef struct { + uint16_t unicast_min; /* Minimum unicast address used for fast provisioning */ + uint16_t unicast_max; /* Maximum unicast address used for fast provisioning */ + uint16_t net_idx; /* Netkey index used for fast provisioning */ + uint8_t flags; /* Flags used for fast provisioning */ + uint32_t iv_index; /* IV Index used for fast provisioning */ + uint8_t offset; /* Offset of the UUID to be compared */ + uint8_t match_len; /* Length of the UUID to be compared */ + uint8_t match_val[16]; /* Value of UUID to be compared */ +} esp_ble_mesh_fast_prov_info_t; + +typedef enum { + FAST_PROV_ACT_NONE, + FAST_PROV_ACT_ENTER, + FAST_PROV_ACT_SUSPEND, + FAST_PROV_ACT_EXIT, + FAST_PROV_ACT_MAX, +} esp_ble_mesh_fast_prov_action_t; + +typedef enum { + ESP_BLE_MESH_PROV_REGISTER_COMP_EVT, /*!< Initialize BLE Mesh provisioning capabilities and internal data information completion event */ + ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT, /*!< Set the unprovisioned device name completion event */ + ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT, /*!< Enable node provisioning functionality completion event */ + ESP_BLE_MESH_NODE_PROV_DISABLE_COMP_EVT, /*!< Disable node provisioning functionality completion event */ + ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT, /*!< Establish a BLE Mesh link event */ + ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT, /*!< Close a BLE Mesh link event */ + ESP_BLE_MESH_NODE_PROV_OOB_PUB_KEY_EVT, /*!< Generate Node input OOB public key event */ + ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT, /*!< Generate Node Output Number event */ + ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT, /*!< Generate Node Output String event */ + ESP_BLE_MESH_NODE_PROV_INPUT_EVT, /*!< Event requiring the user to input a number or string */ + ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT, /*!< Provisioning done event */ + ESP_BLE_MESH_NODE_PROV_RESET_EVT, /*!< Provisioning reset event */ + ESP_BLE_MESH_NODE_PROV_SET_OOB_PUB_KEY_COMP_EVT, /*!< Node set oob public key completion event */ + ESP_BLE_MESH_NODE_PROV_INPUT_NUMBER_COMP_EVT, /*!< Node input number completion event */ + ESP_BLE_MESH_NODE_PROV_INPUT_STRING_COMP_EVT, /*!< Node input string completion event */ + ESP_BLE_MESH_NODE_PROXY_IDENTITY_ENABLE_COMP_EVT, /*!< Enable BLE Mesh Proxy Identity advertising completion event */ + ESP_BLE_MESH_NODE_PROXY_GATT_ENABLE_COMP_EVT, /*!< Enable BLE Mesh GATT Proxy Service completion event */ + ESP_BLE_MESH_NODE_PROXY_GATT_DISABLE_COMP_EVT, /*!< Disable BLE Mesh GATT Proxy Service completion event */ + ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT, /*!< Provisioner enable provisioning functionality completion event */ + ESP_BLE_MESH_PROVISIONER_PROV_DISABLE_COMP_EVT, /*!< Provisioner disable provisioning functionality completion event */ + ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT, /*!< Provisioner receives unprovisioned device beacon event */ + ESP_BLE_MESH_PROVISIONER_PROV_READ_OOB_PUB_KEY_EVT, /*!< Provisioner read unprovisioned device OOB public key event */ + ESP_BLE_MESH_PROVISIONER_PROV_INPUT_EVT, /*!< Provisioner input value for provisioning procedure event */ + ESP_BLE_MESH_PROVISIONER_PROV_OUTPUT_EVT, /*!< Provisioner output value for provisioning procedure event */ + ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT, /*!< Provisioner establish a BLE Mesh link event */ + ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT, /*!< Provisioner close a BLE Mesh link event */ + ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT, /*!< Provisioner provisioning done event */ + ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT, /*!< Provisioner add a device to the list which contains devices that are waiting/going to be provisioned completion event */ + ESP_BLE_MESH_PROVISIONER_DELETE_DEV_COMP_EVT, /*!< Provisioner delete a device from the list, close provisioning link with the device if it exists and remove the device from network completion event */ + ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT, /*!< Provisioner set the value to be compared with part of the unprovisioned device UUID completion event */ + ESP_BLE_MESH_PROVISIONER_SET_PROV_DATA_INFO_COMP_EVT, /*!< Provisioner set net_idx/flags/iv_index used for provisioning completion event */ + ESP_BLE_MESH_PROVISIONER_PROV_READ_OOB_PUB_KEY_COMP_EVT, /*!< Provisioner read unprovisioned device OOB public key completion event */ + ESP_BLE_MESH_PROVISIONER_PROV_INPUT_NUMBER_COMP_EVT, /*!< Provisioner input number completion event */ + ESP_BLE_MESH_PROVISIONER_PROV_INPUT_STRING_COMP_EVT, /*!< Provisioner input string completion event */ + ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT, /*!< Provisioner set node name completion event */ + ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT, /*!< Provisioner add local app key completion event */ + ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT, /*!< Provisioner bind local model with local app key completion event */ + ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_NET_KEY_COMP_EVT, /*!< Provisioner add local network key completion event */ + ESP_BLE_MESH_SET_FAST_PROV_INFO_COMP_EVT, /* !< Set fast provisioning information (e.g. unicast address range, net_idx, etc.) completion event */ + ESP_BLE_MESH_SET_FAST_PROV_ACTION_COMP_EVT, /* !< Set fast provisioning action completion event */ + ESP_BLE_MESH_PROV_EVT_MAX, +} esp_ble_mesh_prov_cb_event_t; + +typedef enum { + ESP_BLE_MESH_MODEL_OPERATION_EVT, /*!< User-defined models receive messages from peer devices (e.g. get, set, status, etc) event */ + ESP_BLE_MESH_MODEL_SEND_COMP_EVT, /*!< User-defined models send messages completion event */ + ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT, /*!< User-defined models publish messages completion event */ + ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT, /*!< User-defined client models receive publish messages event */ + ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT, /*!< Timeout event for the user-defined client models that failed to receive response from peer server models */ + ESP_BLE_MESH_MODEL_PUBLISH_UPDATE_EVT, /*!< When a model is configured to publish messages periodically, this event will occur during every publish period */ + ESP_BLE_MESH_MODEL_EVT_MAX, +} esp_ble_mesh_model_cb_event_t; + +typedef union { + /** + * @brief ESP_BLE_MESH_PROV_REGISTER_COMP_EVT + */ + struct ble_mesh_prov_register_comp_param { + int err_code; + } prov_register_comp; + /** + * @brief ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT + */ + struct ble_mesh_set_unprov_dev_name_comp_param { + int err_code; + } node_set_unprov_dev_name_comp; + /** + * @brief ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT + */ + struct ble_mesh_prov_enable_comp_param { + int err_code; + } node_prov_enable_comp; + /** + * @brief ESP_BLE_MESH_NODE_PROV_DISABLE_COMP_EVT + */ + struct ble_mesh_prov_disable_comp_param { + int err_code; + } node_prov_disable_comp; + /** + * @brief ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT + */ + struct ble_mesh_link_open_evt_param { + esp_ble_mesh_prov_bearer_t bearer; + } node_prov_link_open; + /** + * @brief ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT + */ + struct ble_mesh_link_close_evt_param { + esp_ble_mesh_prov_bearer_t bearer; + } node_prov_link_close; + /** + * @brief ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT + */ + struct ble_mesh_output_num_evt_param { + esp_ble_mesh_output_action_t action; + uint32_t number; + } node_prov_output_num; + /** + * @brief ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT + */ + struct ble_mesh_output_str_evt_param { + char string[8]; + } node_prov_output_str; + /** + * @brief ESP_BLE_MESH_NODE_PROV_INPUT_EVT + */ + struct ble_mesh_input_evt_param { + esp_ble_mesh_input_action_t action; + uint8_t size; + } node_prov_input; + /** + * @brief ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT + */ + struct ble_mesh_provision_complete_evt_param { + uint16_t net_idx; + uint16_t addr; + uint8_t flags; + uint32_t iv_index; + } node_prov_complete; + /** + * @brief ESP_BLE_MESH_NODE_PROV_RESET_EVT + */ + struct ble_mesh_provision_reset_param { + + } node_prov_reset; + /** + * @brief ESP_BLE_MESH_NODE_PROV_SET_OOB_PUB_KEY_COMP_EVT + */ + struct ble_mesh_set_oob_pub_key_comp_param { + int err_code; + } node_prov_set_oob_pub_key_comp; + /** + * @brief ESP_BLE_MESH_NODE_PROV_INPUT_NUM_COMP_EVT + */ + struct ble_mesh_input_number_comp_param { + int err_code; + } node_prov_input_num_comp; + /** + * @brief ESP_BLE_MESH_NODE_PROV_INPUT_STR_COMP_EVT + */ + struct ble_mesh_input_string_comp_param { + int err_code; + } node_prov_input_str_comp; + /** + * @brief ESP_BLE_MESH_NODE_PROXY_IDENTITY_ENABLE_COMP_EVT + */ + struct ble_mesh_proxy_identity_enable_comp_param { + int err_code; + } node_proxy_identity_enable_comp; + /** + * @brief ESP_BLE_MESH_NODE_PROXY_GATT_ENABLE_COMP_EVT + */ + struct ble_mesh_proxy_gatt_enable_comp_param { + int err_code; + } node_proxy_gatt_enable_comp; + /** + * @brief ESP_BLE_MESH_NODE_PROXY_GATT_DISABLE_COMP_EVT + */ + struct ble_mesh_proxy_gatt_disable_comp_param { + int err_code; + } node_proxy_gatt_disable_comp; + /** + * @brief ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT + */ + struct ble_mesh_provisioner_recv_unprov_adv_pkt_param { + uint8_t dev_uuid[16]; + uint8_t addr[6]; + esp_ble_addr_type_t addr_type; + uint16_t oob_info; + uint8_t adv_type; + esp_ble_mesh_prov_bearer_t bearer; + } provisioner_recv_unprov_adv_pkt; + /** + * @brief ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT + */ + struct ble_mesh_provisioner_prov_enable_comp_param { + int err_code; + } provisioner_prov_enable_comp; + /** + * @brief ESP_BLE_MESH_PROVISIONER_PROV_DISABLE_COMP_EVT + */ + struct ble_mesh_provisioner_prov_disable_comp_param { + int err_code; + } provisioner_prov_disable_comp; + /** + * @brief ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT + */ + struct ble_mesh_provisioner_link_open_evt_param { + esp_ble_mesh_prov_bearer_t bearer; + } provisioner_prov_link_open; + /** + * @brief ESP_BLE_MESH_PROVISIONER_PROV_READ_OOB_PUB_KEY_EVT + */ + struct ble_mesh_provisioner_prov_read_oob_pub_key_evt_param { + uint8_t link_idx; + } provisioner_prov_read_oob_pub_key; + /** + * @brief ESP_BLE_MESH_PROVISIONER_PROV_INPUT_EVT + */ + struct ble_mesh_provisioner_prov_input_evt_param { + esp_ble_mesh_oob_method_t method; + esp_ble_mesh_output_action_t action; + uint8_t size; + uint8_t link_idx; + } provisioner_prov_input; + /** + * @brief ESP_BLE_MESH_PROVISIONER_PROV_OUTPUT_EVT + */ + struct ble_mesh_provisioner_prov_output_evt_param { + esp_ble_mesh_oob_method_t method; + esp_ble_mesh_input_action_t action; + uint8_t size; + uint8_t link_idx; + union { + char string[8]; + uint32_t number; + }; + } provisioner_prov_output; + /** + * @brief ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT + */ + struct ble_mesh_provisioner_link_close_evt_param { + esp_ble_mesh_prov_bearer_t bearer; + uint8_t reason; + } provisioner_prov_link_close; + /** + * @brief ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT + */ + struct ble_mesh_provisioner_prov_comp_param { + int node_idx; + esp_ble_mesh_octet16_t device_uuid; + uint16_t unicast_addr; + uint8_t element_num; + uint16_t netkey_idx; + } provisioner_prov_complete; + /** + * @brief ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT + */ + struct ble_mesh_provisioner_add_unprov_dev_comp_param { + int err_code; + } provisioner_add_unprov_dev_comp; + /** + * @brief ESP_BLE_MESH_PROVISIONER_DELETE_DEV_COMP_EVT + */ + struct ble_mesh_provisioner_delete_dev_comp_param { + int err_code; + } provisioner_delete_dev_comp; + /** + * @brief ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT + */ + struct ble_mesh_provisioner_set_dev_uuid_match_comp_param { + int err_code; + } provisioner_set_dev_uuid_match_comp; + /** + * @brief ESP_BLE_MESH_PROVISIONER_SET_PROV_DATA_INFO_COMP_EVT + */ + struct ble_mesh_provisioner_set_prov_data_info_comp_param { + int err_code; + } provisioner_set_prov_data_info_comp; + /** + * @brief ESP_BLE_MESH_PROVISIONER_PROV_READ_OOB_PUB_KEY_COMP_EVT + */ + struct ble_mesh_provisioner_prov_read_oob_pub_key_comp_param { + int err_code; + } provisioner_prov_read_oob_pub_key_comp; + /** + * @brief ESP_BLE_MESH_PROVISIONER_PROV_INPUT_NUMBER_COMP_EVT + */ + struct ble_mesh_provisioner_prov_input_num_comp_param { + int err_code; + } provisioner_prov_input_num_comp; + /** + * @brief ESP_BLE_MESH_PROVISIONER_PROV_INPUT_STRING_COMP_EVT + */ + struct ble_mesh_provisioner_prov_input_str_comp_param { + int err_code; + } provisioner_prov_input_str_comp; + /** + * @brief ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT + */ + struct ble_mesh_provisioner_set_node_name_comp_param { + int err_code; + int node_index; + } provisioner_set_node_name_comp; + /** + * @brief ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT + */ + struct ble_mesh_provisioner_add_local_app_key_comp_param { + int err_code; + uint16_t app_idx; + } provisioner_add_app_key_comp; + /** + * @brief ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT + */ + struct ble_mesh_provisioner_bind_local_mod_app_comp_param { + int err_code; + } provisioner_bind_app_key_to_model_comp; + /** + * @brief ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_NET_KEY_COMP_EVT + */ + struct ble_mesh_provisioner_add_local_net_key_comp_param { + int err_code; + uint16_t net_idx; + } provisioner_add_net_key_comp; + struct ble_mesh_set_fast_prov_info_comp_param { + uint8_t status_unicast; + uint8_t status_net_idx; + uint8_t status_match; + } set_fast_prov_info_comp; + struct ble_mesh_set_fast_prov_action_comp_param { + uint8_t status_action; + } set_fast_prov_action_comp; +} esp_ble_mesh_prov_cb_param_t; + +typedef union { + /** + * @brief ESP_BLE_MESH_MODEL_OPERATION_EVT + */ + struct ble_mesh_model_operation_evt_param { + uint32_t opcode; + esp_ble_mesh_model_t *model; + esp_ble_mesh_msg_ctx_t *ctx; + uint16_t length; + uint8_t *msg; + } model_operation; + /** + * @brief ESP_BLE_MESH_MODEL_SEND_COMP_EVT + */ + struct ble_mesh_model_send_comp_param { + int err_code; + uint32_t opcode; + esp_ble_mesh_model_t *model; + esp_ble_mesh_msg_ctx_t *ctx; + } model_send_comp; + /** + * @brief ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT + */ + struct ble_mesh_model_publish_comp_param { + int err_code; + esp_ble_mesh_model_t *model; + } model_publish_comp; + /** + * @brief ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT + */ + struct ble_mesh_mod_recv_publish_msg_param { + uint32_t opcode; + esp_ble_mesh_model_t *model; + esp_ble_mesh_msg_ctx_t *ctx; + uint16_t length; + uint8_t *msg; + } client_recv_publish_msg; + /** + * @brief ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT + */ + struct ble_mesh_client_model_send_timeout_param { + uint32_t opcode; + esp_ble_mesh_model_t *model; + esp_ble_mesh_msg_ctx_t *ctx; + } client_send_timeout; + /** + * @brief ESP_BLE_MESH_MODEL_PUBLISH_UPDATE_EVT + */ + struct ble_mesh_model_publish_update_evt_param { + esp_ble_mesh_model_t *model; + } model_publish_update; +} esp_ble_mesh_model_cb_param_t; + +typedef struct { + uint32_t cli_op; /*!< The client message opcode */ + uint32_t status_op; /*!< The server status opcode corresponding to the client message opcode */ +} esp_ble_mesh_client_op_pair_t; + +/*!< Mesh Client Model Context */ +typedef struct { + esp_ble_mesh_model_t *model; + int op_pair_size; /*!< Size of the op_pair */ + const esp_ble_mesh_client_op_pair_t *op_pair; /*!< Table containing get/set message opcode and corresponding status message opcode */ + uint32_t publish_status; /*!< This variable is reserved for BLE Mesh Stack, does not require initializing on the application layer */ + void *internal_data; /*!< Pointer to the structure of the client model internal data */ + uint8_t msg_role; /*!< Role of the device (Node/Provisioner) that is going to send messages */ +} esp_ble_mesh_client_t; + +#endif /* _ESP_BLE_MESH_DEFS_H_ */ diff --git a/components/bt/ble_mesh/api/models/esp_ble_mesh_config_model_api.c b/components/bt/ble_mesh/api/models/esp_ble_mesh_config_model_api.c new file mode 100644 index 0000000000..67694eef4e --- /dev/null +++ b/components/bt/ble_mesh/api/models/esp_ble_mesh_config_model_api.c @@ -0,0 +1,82 @@ +// Copyright 2017-2018 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 + +#include "btc/btc_task.h" +#include "btc/btc_manage.h" + +#include "esp_bt_defs.h" +#include "esp_bt_main.h" + +#include "btc_ble_mesh_config_model.h" +#include "esp_ble_mesh_config_model_api.h" + +esp_err_t esp_ble_mesh_register_config_client_callback(esp_ble_mesh_cfg_client_cb_t callback) +{ + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_CFG_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_register_config_server_callback(esp_ble_mesh_cfg_server_cb_t callback) +{ + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_CFG_SERVER, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_config_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_cfg_client_get_state_t *get_state) +{ + btc_ble_mesh_cfg_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (!params || !params->model || !params->ctx.addr || !get_state) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_CFG_CLIENT; + msg.act = BTC_BLE_MESH_ACT_CONFIG_CLIENT_GET_STATE; + arg.cfg_client_get_state.params = params; + arg.cfg_client_get_state.get_state = get_state; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_cfg_client_args_t), btc_ble_mesh_cfg_client_arg_deep_copy) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_config_client_set_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_cfg_client_set_state_t *set_state) +{ + btc_ble_mesh_cfg_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (!params || !params->model || !params->ctx.addr || !set_state) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_CFG_CLIENT; + msg.act = BTC_BLE_MESH_ACT_CONFIG_CLIENT_SET_STATE; + arg.cfg_client_set_state.params = params; + arg.cfg_client_set_state.set_state = set_state; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_cfg_client_args_t), btc_ble_mesh_cfg_client_arg_deep_copy) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} diff --git a/components/bt/ble_mesh/api/models/esp_ble_mesh_generic_model_api.c b/components/bt/ble_mesh/api/models/esp_ble_mesh_generic_model_api.c new file mode 100644 index 0000000000..82f6ff5850 --- /dev/null +++ b/components/bt/ble_mesh/api/models/esp_ble_mesh_generic_model_api.c @@ -0,0 +1,75 @@ +// Copyright 2017-2018 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 + +#include "btc/btc_task.h" +#include "btc/btc_manage.h" + +#include "esp_bt_defs.h" +#include "esp_bt_main.h" + +#include "btc_ble_mesh_generic_model.h" +#include "esp_ble_mesh_generic_model_api.h" + +esp_err_t esp_ble_mesh_register_generic_client_callback(esp_ble_mesh_generic_client_cb_t callback) +{ + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_GENERIC_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_generic_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_generic_client_get_state_t *get_state) +{ + btc_ble_mesh_generic_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (!params || !params->model || !params->ctx.addr || !get_state) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_GENERIC_CLIENT; + msg.act = BTC_BLE_MESH_ACT_GENERIC_CLIENT_GET_STATE; + arg.generic_client_get_state.params = params; + arg.generic_client_get_state.get_state = get_state; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_generic_client_args_t), btc_ble_mesh_generic_client_arg_deep_copy) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_generic_client_set_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_generic_client_set_state_t *set_state) +{ + btc_ble_mesh_generic_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (!params || !params->model || !params->ctx.addr || !set_state) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_GENERIC_CLIENT; + msg.act = BTC_BLE_MESH_ACT_GENERIC_CLIENT_SET_STATE; + arg.generic_client_set_state.params = params; + arg.generic_client_set_state.set_state = set_state; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_generic_client_args_t), btc_ble_mesh_generic_client_arg_deep_copy) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} diff --git a/components/bt/ble_mesh/api/models/esp_ble_mesh_health_model_api.c b/components/bt/ble_mesh/api/models/esp_ble_mesh_health_model_api.c new file mode 100644 index 0000000000..e7df777dc0 --- /dev/null +++ b/components/bt/ble_mesh/api/models/esp_ble_mesh_health_model_api.c @@ -0,0 +1,98 @@ +// Copyright 2017-2018 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 + +#include "btc/btc_task.h" +#include "btc/btc_manage.h" + +#include "esp_bt_defs.h" +#include "esp_bt_main.h" + +#include "btc_ble_mesh_health_model.h" +#include "esp_ble_mesh_health_model_api.h" + +esp_err_t esp_ble_mesh_register_health_client_callback(esp_ble_mesh_health_client_cb_t callback) +{ + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_HEALTH_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_register_health_server_callback(esp_ble_mesh_health_server_cb_t callback) +{ + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_HEALTH_SERVER, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_health_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_health_client_get_state_t *get_state) +{ + btc_ble_mesh_health_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (!params || !params->model || !params->ctx.addr || !get_state) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HEALTH_CLIENT; + msg.act = BTC_BLE_MESH_ACT_HEALTH_CLIENT_GET_STATE; + arg.health_client_get_state.params = params; + arg.health_client_get_state.get_state = get_state; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_health_client_args_t), btc_ble_mesh_health_client_arg_deep_copy) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_health_client_set_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_health_client_set_state_t *set_state) +{ + btc_ble_mesh_health_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (!params || !params->model || !params->ctx.addr || !set_state) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HEALTH_CLIENT; + msg.act = BTC_BLE_MESH_ACT_HEALTH_CLIENT_SET_STATE; + arg.health_client_set_state.params = params; + arg.health_client_set_state.set_state = set_state; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_health_client_args_t), btc_ble_mesh_health_client_arg_deep_copy) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_health_server_fault_update(esp_ble_mesh_elem_t *element) +{ + btc_ble_mesh_health_server_args_t arg = {0}; + btc_msg_t msg = {0}; + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HEALTH_SERVER; + msg.act = BTC_BLE_MESH_ACT_HEALTH_SERVER_FAULT_UPDATE; + arg.fault_update.element = element; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_health_server_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} diff --git a/components/bt/ble_mesh/api/models/esp_ble_mesh_lighting_model_api.c b/components/bt/ble_mesh/api/models/esp_ble_mesh_lighting_model_api.c new file mode 100644 index 0000000000..eea415d618 --- /dev/null +++ b/components/bt/ble_mesh/api/models/esp_ble_mesh_lighting_model_api.c @@ -0,0 +1,76 @@ +// Copyright 2017-2018 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 + +#include "btc/btc_task.h" +#include "btc/btc_manage.h" + +#include "esp_bt_defs.h" +#include "esp_bt_main.h" + +#include "btc_ble_mesh_lighting_model.h" +#include "esp_ble_mesh_lighting_model_api.h" + +esp_err_t esp_ble_mesh_register_light_client_callback(esp_ble_mesh_light_client_cb_t callback) +{ + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_LIGHT_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_light_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_light_client_get_state_t *get_state) +{ + btc_ble_mesh_light_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (!params || !params->model || !params->ctx.addr || !get_state) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_LIGHT_CLIENT; + msg.act = BTC_BLE_MESH_ACT_LIGHT_CLIENT_GET_STATE; + arg.light_client_get_state.params = params; + arg.light_client_get_state.get_state = get_state; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_light_client_args_t), btc_ble_mesh_light_client_arg_deep_copy) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_light_client_set_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_light_client_set_state_t *set_state) +{ + btc_ble_mesh_light_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (!params || !params->model || !params->ctx.addr || !set_state) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_LIGHT_CLIENT; + msg.act = BTC_BLE_MESH_ACT_LIGHT_CLIENT_SET_STATE; + arg.light_client_set_state.params = params; + arg.light_client_set_state.set_state = set_state; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_light_client_args_t), btc_ble_mesh_light_client_arg_deep_copy) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + diff --git a/components/bt/ble_mesh/api/models/esp_ble_mesh_sensor_model_api.c b/components/bt/ble_mesh/api/models/esp_ble_mesh_sensor_model_api.c new file mode 100644 index 0000000000..41072d227f --- /dev/null +++ b/components/bt/ble_mesh/api/models/esp_ble_mesh_sensor_model_api.c @@ -0,0 +1,76 @@ +// Copyright 2017-2018 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 + +#include "btc/btc_task.h" +#include "btc/btc_manage.h" + +#include "esp_bt_defs.h" +#include "esp_bt_main.h" + +#include "btc_ble_mesh_sensor_model.h" +#include "esp_ble_mesh_sensor_model_api.h" + +esp_err_t esp_ble_mesh_register_sensor_client_callback(esp_ble_mesh_sensor_client_cb_t callback) +{ + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_SENSOR_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_sensor_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_sensor_client_get_state_t *get_state) +{ + btc_ble_mesh_sensor_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (!params || !params->model || !params->ctx.addr || !get_state) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_SENSOR_CLIENT; + msg.act = BTC_BLE_MESH_ACT_SENSOR_CLIENT_GET_STATE; + arg.sensor_client_get_state.params = params; + arg.sensor_client_get_state.get_state = get_state; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_sensor_client_args_t), btc_ble_mesh_sensor_client_arg_deep_copy) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_sensor_client_set_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_sensor_client_set_state_t *set_state) +{ + btc_ble_mesh_sensor_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (!params || !params->model || !params->ctx.addr || !set_state) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_SENSOR_CLIENT; + msg.act = BTC_BLE_MESH_ACT_SENSOR_CLIENT_SET_STATE; + arg.sensor_client_set_state.params = params; + arg.sensor_client_set_state.set_state = set_state; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_sensor_client_args_t), btc_ble_mesh_sensor_client_arg_deep_copy) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + diff --git a/components/bt/ble_mesh/api/models/esp_ble_mesh_time_scene_model_api.c b/components/bt/ble_mesh/api/models/esp_ble_mesh_time_scene_model_api.c new file mode 100644 index 0000000000..13823b9787 --- /dev/null +++ b/components/bt/ble_mesh/api/models/esp_ble_mesh_time_scene_model_api.c @@ -0,0 +1,76 @@ +// Copyright 2017-2018 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 + +#include "btc/btc_task.h" +#include "btc/btc_manage.h" + +#include "esp_bt_defs.h" +#include "esp_bt_main.h" + +#include "btc_ble_mesh_time_scene_model.h" +#include "esp_ble_mesh_time_scene_model_api.h" + +esp_err_t esp_ble_mesh_register_time_scene_client_callback(esp_ble_mesh_time_scene_client_cb_t callback) +{ + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_TIME_SCENE_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_time_scene_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_time_scene_client_get_state_t *get_state) +{ + btc_ble_mesh_time_scene_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (!params || !params->model || !params->ctx.addr || !get_state) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_TIME_SCENE_CLIENT; + msg.act = BTC_BLE_MESH_ACT_TIME_SCENE_CLIENT_GET_STATE; + arg.time_scene_client_get_state.params = params; + arg.time_scene_client_get_state.get_state = get_state; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_time_scene_client_args_t), btc_ble_mesh_time_scene_client_arg_deep_copy) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_time_scene_client_set_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_time_scene_client_set_state_t *set_state) +{ + btc_ble_mesh_time_scene_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (!params || !params->model || !params->ctx.addr || !set_state) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_TIME_SCENE_CLIENT; + msg.act = BTC_BLE_MESH_ACT_TIME_SCENE_CLIENT_SET_STATE; + arg.time_scene_client_set_state.params = params; + arg.time_scene_client_set_state.set_state = set_state; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_time_scene_client_args_t), btc_ble_mesh_time_scene_client_arg_deep_copy) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + diff --git a/components/bt/ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h b/components/bt/ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h new file mode 100644 index 0000000000..755e0671b2 --- /dev/null +++ b/components/bt/ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h @@ -0,0 +1,670 @@ +// Copyright 2017-2018 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. + +#ifndef _ESP_BLE_MESH_CONFIG_MODEL_API_H_ +#define _ESP_BLE_MESH_CONFIG_MODEL_API_H_ + +#include "esp_ble_mesh_defs.h" + +/** @def ESP_BLE_MESH_MODEL_CFG_SRV + * + * @brief Define a new Config Server Model. + * + * @note The Config Server Model can only be included by a Primary Element. + * + * @param srv_data Pointer to a unique Config Server Model user_data. + * + * @return New Config Server Model instance. + */ +#define ESP_BLE_MESH_MODEL_CFG_SRV(srv_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_CONFIG_SRV, \ + NULL, NULL, srv_data) + +/** @def ESP_BLE_MESH_MODEL_CFG_CLI + * + * @brief Define a new Config Client Model. + * + * @note The Config Client Model can only be included by a Primary Element. + * + * @param cli_data Pointer to a unique struct esp_ble_mesh_client_t. + * + * @return New Config Client Model instance. + */ +#define ESP_BLE_MESH_MODEL_CFG_CLI(cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_CONFIG_CLI, \ + NULL, NULL, cli_data) + +typedef struct esp_ble_mesh_cfg_srv { + esp_ble_mesh_model_t *model; + + uint8_t net_transmit; /*!< Network Transmit state */ + uint8_t relay; /*!< Relay Mode state */ + uint8_t relay_retransmit; /*!< Relay Retransmit state */ + uint8_t beacon; /*!< Secure Network Beacon state */ + uint8_t gatt_proxy; /*!< GATT Proxy state */ + uint8_t friend_state; /*!< Friend state */ + uint8_t default_ttl; /*!< Default TTL */ + + /** Heartbeat Publication */ + struct { + struct k_delayed_work timer; + + uint16_t dst; + uint16_t count; + uint8_t period; + uint8_t ttl; + uint16_t feature; + uint16_t net_idx; + } heartbeat_pub; + + /** Heartbeat Subscription */ + struct { + int64_t expiry; + + uint16_t src; + uint16_t dst; + uint16_t count; + uint8_t min_hops; + uint8_t max_hops; + + /** Optional subscription tracking function */ + void (*func)(uint8_t hops, uint16_t feature); + } heartbeat_sub; +} esp_ble_mesh_cfg_srv_t; + +/** Parameters of Composition Data Get. */ +typedef struct { + uint8_t page; /*!< Page number of the Composition Data. */ +} esp_ble_mesh_cfg_composition_data_get_t; + +/** Parameters of Model Publication Get. */ +typedef struct { + uint16_t element_addr; /*!< The element address */ + uint16_t model_id; /*!< The model id */ + uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ +} esp_ble_mesh_cfg_model_pub_get_t; + +/** Parameters of SIG Model Subscription Get. */ +typedef struct { + uint16_t element_addr; /*!< The element address */ + uint16_t model_id; /*!< The model id */ +} esp_ble_mesh_cfg_sig_model_sub_get_t; + +/** Parameters of Vendor Model Subscription Get. */ +typedef struct { + uint16_t element_addr; /*!< The element address */ + uint16_t model_id; /*!< The model id */ + uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ +} esp_ble_mesh_cfg_vnd_model_sub_get_t; + +/** Parameters of Application Key Get. */ +typedef struct { + uint16_t net_idx; /*!< The network key index */ +} esp_ble_mesh_cfg_app_key_get_t; + +/** Parameters of Node Identity Get. */ +typedef struct { + uint16_t net_idx; /*!< The network key index */ +} esp_ble_mesh_cfg_node_identity_get_t; + +/** Parameters of SIG Model App Get. */ +typedef struct { + uint16_t element_addr; /*!< The element address */ + uint16_t model_id; /*!< The model id */ +} esp_ble_mesh_cfg_sig_model_app_get_t; + +/** Parameters of Vendor Model App Get. */ +typedef struct { + uint16_t element_addr; /*!< The element address */ + uint16_t model_id; /*!< The model id */ + uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ +} esp_ble_mesh_cfg_vnd_model_app_get_t; + +/** Parameters of Key Refresh Phase Get. */ +typedef struct { + uint16_t net_idx; /*!< The network key index */ +} esp_ble_mesh_cfg_kr_phase_get_t; + +/** Parameters of Low Power Node PollTimeout Get. */ +typedef struct { + uint16_t lpn_addr; /*!< The unicast address of the Low Power node */ +} esp_ble_mesh_cfg_lpn_polltimeout_get_t; + +/** Parameters of Beacon Set. */ +typedef struct { + uint8_t beacon; +} esp_ble_mesh_cfg_beacon_set_t; + +/** Parameters of Default TTL Set. */ +typedef struct { + uint8_t ttl; /*!< The default TTL state value */ +} esp_ble_mesh_cfg_default_ttl_set_t; + +/** Parameters of Friend Set. */ +typedef struct { + uint8_t friend_state; /*!< The friend state value */ +} esp_ble_mesh_cfg_friend_set_t; + +/** Parameters of GATT Proxy Set. */ +typedef struct { + uint8_t gatt_proxy; /*!< The GATT Proxy state value */ +} esp_ble_mesh_cfg_gatt_proxy_set_t; + +/** Parameters of Relay Set. */ +typedef struct { + uint8_t relay; /*!< The relay value */ + uint8_t relay_retransmit; /*!< The relay retransmit value */ +} esp_ble_mesh_cfg_relay_set_t; + +/** Parameters of Network Key Add. */ +typedef struct { + uint16_t net_idx; /*!< The network key index */ + uint8_t net_key[16]; /*!< The network key value */ +} esp_ble_mesh_cfg_net_key_add_t; + +/** Parameters of Application Key Add. */ +typedef struct { + uint16_t net_idx; /*!< The network key index */ + uint16_t app_idx; /*!< The app key index */ + uint8_t app_key[16]; /*!< The app key value */ +} esp_ble_mesh_cfg_app_key_add_t; + +/** Parameters of Model Application Key Bind. */ +typedef struct { + uint16_t element_addr; /*!< The element address */ + uint16_t model_app_idx; /*!< Index of the app key to bind with the model */ + uint16_t model_id; /*!< The model id */ + uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ +} esp_ble_mesh_cfg_model_app_bind_t; + +/** Parameters of Model Publication Set. */ +typedef struct { + uint16_t element_addr; /*!< The element address */ + uint16_t publish_addr; /*!< Value of the publish address */ + uint16_t publish_app_idx; /*!< Index of the application key */ + bool cred_flag; /*!< Value of the Friendship Credential Flag */ + uint8_t publish_ttl; /*!< Default TTL value for the publishing messages */ + uint8_t publish_period; /*!< Period for periodic status publishing */ + uint8_t publish_retransmit; /*!< Number of retransmissions and number of 50-millisecond steps between retransmissions */ + uint16_t model_id; /*!< The model id */ + uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ +} esp_ble_mesh_cfg_model_pub_set_t; + +/** Parameters of Model Subscription Add. */ +typedef struct { + uint16_t element_addr; /*!< The element address */ + uint16_t sub_addr; /*!< The address to be added to the Subscription List */ + uint16_t model_id; /*!< The model id */ + uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ +} esp_ble_mesh_cfg_model_sub_add_t; + +/** Parameters of Model Subscription Delete. */ +typedef struct { + uint16_t element_addr; /*!< The element address */ + uint16_t sub_addr; /*!< The address to be removed from the Subscription List */ + uint16_t model_id; /*!< The model id */ + uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ +} esp_ble_mesh_cfg_model_sub_delete_t; + +/** Parameters of Model Subscription Overwrite. */ +typedef struct { + uint16_t element_addr; /*!< The element address */ + uint16_t sub_addr; /*!< The address to be added to the Subscription List */ + uint16_t model_id; /*!< The model id */ + uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ +} esp_ble_mesh_cfg_model_sub_overwrite_t; + +/** Parameters of Model Subscription Virtual Address Add. */ +typedef struct { + uint16_t element_addr; /*!< The element address */ + uint8_t label_uuid[16]; /*!< The Label UUID of the virtual address to be added to the Subscription List */ + uint16_t model_id; /*!< The model id */ + uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ +} esp_ble_mesh_cfg_model_sub_va_add_t; + +/** Parameters of Model Subscription Virtual Address Delete. */ +typedef struct { + uint16_t element_addr; /*!< The element address */ + uint8_t label_uuid[16]; /*!< The Label UUID of the virtual address to be removed from the Subscription List */ + uint16_t model_id; /*!< The model id */ + uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ +} esp_ble_mesh_cfg_model_sub_va_delete_t; + +/** Parameters of Model Subscription Virtual Address Overwrite. */ +typedef struct { + uint16_t element_addr; /*!< The element address */ + uint8_t label_uuid[16]; /*!< The Label UUID of the virtual address to be added to the Subscription List */ + uint16_t model_id; /*!< The model id */ + uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ +} esp_ble_mesh_cfg_model_sub_va_overwrite_t; + +/** Parameters of Model Publication Virtual Address Set. */ +typedef struct { + uint16_t element_addr; /*!< The element address */ + uint8_t label_uuid[16]; /*!< Value of the Label UUID publish address */ + uint16_t publish_app_idx; /*!< Index of the application key */ + bool cred_flag; /*!< Value of the Friendship Credential Flag */ + uint8_t publish_ttl; /*!< Default TTL value for the publishing messages */ + uint8_t publish_period; /*!< Period for periodic status publishing */ + uint8_t publish_retransmit; /*!< Number of retransmissions and number of 50-millisecond steps between retransmissions */ + uint16_t model_id; /*!< The model id */ + uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ +} esp_ble_mesh_cfg_model_pub_va_set_t; + +/** Parameters of Model Subscription Delete All. */ +typedef struct { + uint16_t element_addr; /*!< The element address */ + uint16_t model_id; /*!< The model id */ + uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ +} esp_ble_mesh_cfg_model_sub_delete_all_t; + +/** Parameters of Network Key Update. */ +typedef struct { + uint16_t net_idx; /*!< The network key index */ + uint8_t net_key[16]; /*!< The network key value */ +} esp_ble_mesh_cfg_net_key_update_t; + +/** Parameters of Network Key Delete. */ +typedef struct { + uint16_t net_idx; /*!< The network key index */ +} esp_ble_mesh_cfg_net_key_delete_t; + +/** Parameters of Application Key Update. */ +typedef struct { + uint16_t net_idx; /*!< The network key index */ + uint16_t app_idx; /*!< The app key index */ + uint8_t app_key[16]; /*!< The app key value */ +} esp_ble_mesh_cfg_app_key_update_t; + +/** Parameters of Application Key Delete. */ +typedef struct { + uint16_t net_idx; /*!< The network key index */ + uint16_t app_idx; /*!< The app key index */ +} esp_ble_mesh_cfg_app_key_delete_t; + +/** Parameters of Node Identity Set. */ +typedef struct { + uint16_t net_idx; /*!< The network key index */ + uint8_t identity; /*!< New Node Identity state */ +} esp_ble_mesh_cfg_node_identity_set_t; + +/** Parameters of Model Application Key Unbind. */ +typedef struct { + uint16_t element_addr; /*!< The element address */ + uint16_t model_app_idx; /*!< Index of the app key to bind with the model */ + uint16_t model_id; /*!< The model id */ + uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ +} esp_ble_mesh_cfg_model_app_unbind_t; + +/** Parameters of Key Refresh Phase Set. */ +typedef struct { + uint16_t net_idx; /*!< The network key index */ + uint8_t transition; /*!< New Key Refresh Phase Transition */ +} esp_ble_mesh_cfg_kr_phase_set_t; + +/** Parameters of Network Transmit Set. */ +typedef struct { + uint8_t net_transmit; /*!< Network Transmit State */ +} esp_ble_mesh_cfg_net_transmit_set_t; + +/** Parameters of Model Heartbeat Publication Set. */ +typedef struct { + uint16_t dst; + uint8_t count; + uint8_t period; + uint8_t ttl; + uint16_t feature; + uint16_t net_idx; +} esp_ble_mesh_cfg_heartbeat_pub_set_t; + +/** Parameters of Model Heartbeat Subscription Set. */ +typedef struct { + uint16_t src; + uint16_t dst; + uint8_t period; +} esp_ble_mesh_cfg_heartbeat_sub_set_t; + +/** + * @brief For ESP_BLE_MESH_MODEL_OP_BEACON_GET + * ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET + * ESP_BLE_MESH_MODEL_OP_DEFAULT_TTL_GET + * ESP_BLE_MESH_MODEL_OP_GATT_PROXY_GET + * ESP_BLE_MESH_MODEL_OP_RELAY_GET + * ESP_BLE_MESH_MODEL_OP_MODEL_PUB_GET + * ESP_BLE_MESH_MODEL_OP_FRIEND_GET + * ESP_BLE_MESH_MODEL_OP_HEARTBEAT_PUB_GET + * ESP_BLE_MESH_MODEL_OP_HEARTBEAT_SUB_GET + * the get_state parameter in the esp_ble_mesh_config_client_get_state function should not be set to NULL. + */ +typedef union { + esp_ble_mesh_cfg_model_pub_get_t model_pub_get; /*!< For ESP_BLE_MESH_MODEL_OP_MODEL_PUB_GET. */ + esp_ble_mesh_cfg_composition_data_get_t comp_data_get; /*!< For ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET. */ + esp_ble_mesh_cfg_sig_model_sub_get_t sig_model_sub_get; /*!< For ESP_BLE_MESH_MODEL_OP_SIG_MODEL_SUB_GET */ + esp_ble_mesh_cfg_vnd_model_sub_get_t vnd_model_sub_get; /*!< For ESP_BLE_MESH_MODEL_OP_VENDOR_MODEL_SUB_GET */ + esp_ble_mesh_cfg_app_key_get_t app_key_get; /*!< For ESP_BLE_MESH_MODEL_OP_APP_KEY_GET. */ + esp_ble_mesh_cfg_node_identity_get_t node_identity_get; /*!< For ESP_BLE_MESH_MODEL_OP_NODE_IDENTITY_GET. */ + esp_ble_mesh_cfg_sig_model_app_get_t sig_model_app_get; /*!< For ESP_BLE_MESH_MODEL_OP_SIG_MODEL_APP_GET */ + esp_ble_mesh_cfg_vnd_model_app_get_t vnd_model_app_get; /*!< For ESP_BLE_MESH_MODEL_OP_VENDOR_MODEL_APP_GET */ + esp_ble_mesh_cfg_kr_phase_get_t kr_phase_get; /*!< For ESP_BLE_MESH_MODEL_OP_KEY_REFRESH_PHASE_GET */ + esp_ble_mesh_cfg_lpn_polltimeout_get_t lpn_pollto_get; /*!< For ESP_BLE_MESH_MODEL_OP_LPN_POLLTIMEOUT_GET */ +} esp_ble_mesh_cfg_client_get_state_t; + +/** + * @brief For ESP_BLE_MESH_MODEL_OP_BEACON_SET + * ESP_BLE_MESH_MODEL_OP_DEFAULT_TTL_SET + * ESP_BLE_MESH_MODEL_OP_GATT_PROXY_SET + * ESP_BLE_MESH_MODEL_OP_RELAY_SET + * ESP_BLE_MESH_MODEL_OP_MODEL_PUB_SET + * ESP_BLE_MESH_MODEL_OP_MODEL_SUB_ADD + * ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_ADD + * ESP_BLE_MESH_MODEL_OP_MODEL_SUB_DELETE + * ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_DELETE + * ESP_BLE_MESH_MODEL_OP_MODEL_SUB_OVERWRITE + * ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_OVERWRITE + * ESP_BLE_MESH_MODEL_OP_NET_KEY_ADD + * ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD + * ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND + * ESP_BLE_MESH_MODEL_OP_NODE_RESET + * ESP_BLE_MESH_MODEL_OP_FRIEND_SET + * ESP_BLE_MESH_MODEL_OP_HEARTBEAT_PUB_SET + * ESP_BLE_MESH_MODEL_OP_HEARTBEAT_SUB_SET + * the set_state parameter in the esp_ble_mesh_config_client_set_state function should not be set to NULL. + */ +typedef union { + esp_ble_mesh_cfg_beacon_set_t beacon_set; /*!< For ESP_BLE_MESH_MODEL_OP_BEACON_SET */ + esp_ble_mesh_cfg_default_ttl_set_t default_ttl_set; /*!< For ESP_BLE_MESH_MODEL_OP_DEFAULT_TTL_SET */ + esp_ble_mesh_cfg_friend_set_t friend_set; /*!< For ESP_BLE_MESH_MODEL_OP_FRIEND_SET */ + esp_ble_mesh_cfg_gatt_proxy_set_t gatt_proxy_set; /*!< For ESP_BLE_MESH_MODEL_OP_GATT_PROXY_SET */ + esp_ble_mesh_cfg_relay_set_t relay_set; /*!< For ESP_BLE_MESH_MODEL_OP_RELAY_SET */ + esp_ble_mesh_cfg_net_key_add_t net_key_add; /*!< For ESP_BLE_MESH_MODEL_OP_NET_KEY_ADD */ + esp_ble_mesh_cfg_app_key_add_t app_key_add; /*!< For ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD */ + esp_ble_mesh_cfg_model_app_bind_t model_app_bind; /*!< For ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND */ + esp_ble_mesh_cfg_model_pub_set_t model_pub_set; /*!< For ESP_BLE_MESH_MODEL_OP_MODEL_PUB_SET */ + esp_ble_mesh_cfg_model_sub_add_t model_sub_add; /*!< For ESP_BLE_MESH_MODEL_OP_MODEL_SUB_ADD */ + esp_ble_mesh_cfg_model_sub_delete_t model_sub_delete; /*!< For ESP_BLE_MESH_MODEL_OP_MODEL_SUB_DELETE */ + esp_ble_mesh_cfg_model_sub_overwrite_t model_sub_overwrite; /*!< For ESP_BLE_MESH_MODEL_OP_MODEL_SUB_OVERWRITE */ + esp_ble_mesh_cfg_model_sub_va_add_t model_sub_va_add; /*!< For ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_ADD */ + esp_ble_mesh_cfg_model_sub_va_delete_t model_sub_va_delete; /*!< For ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_DELETE */ + esp_ble_mesh_cfg_model_sub_va_overwrite_t model_sub_va_overwrite; /*!< For ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_OVERWRITE */ + esp_ble_mesh_cfg_heartbeat_pub_set_t heartbeat_pub_set; /*!< For ESP_BLE_MESH_MODEL_OP_HEARTBEAT_PUB_SET */ + esp_ble_mesh_cfg_heartbeat_sub_set_t heartbeat_sub_set; /*!< For ESP_BLE_MESH_MODEL_OP_HEARTBEAT_SUB_SET */ + esp_ble_mesh_cfg_model_pub_va_set_t model_pub_va_set; /*!< For ESP_BLE_MESH_MODEL_OP_MODEL_PUB_VIRTUAL_ADDR_SET */ + esp_ble_mesh_cfg_model_sub_delete_all_t model_sub_delete_all; /*!< For ESP_BLE_MESH_MODEL_OP_MODEL_SUB_DELETE_ALL */ + esp_ble_mesh_cfg_net_key_update_t net_key_update; /*!< For ESP_BLE_MESH_MODEL_OP_NET_KEY_UPDATE */ + esp_ble_mesh_cfg_net_key_delete_t net_key_delete; /*!< For ESP_BLE_MESH_MODEL_OP_NET_KEY_DELETE */ + esp_ble_mesh_cfg_app_key_update_t app_key_update; /*!< For ESP_BLE_MESH_MODEL_OP_APP_KEY_UPDATE */ + esp_ble_mesh_cfg_app_key_delete_t app_key_delete; /*!< For ESP_BLE_MESH_MODEL_OP_APP_KEY_DELETE */ + esp_ble_mesh_cfg_node_identity_set_t node_identity_set; /*!< For ESP_BLE_MESH_MODEL_OP_NODE_IDENTITY_SET */ + esp_ble_mesh_cfg_model_app_unbind_t model_app_unbind; /*!< For ESP_BLE_MESH_MODEL_OP_MODEL_APP_UNBIND */ + esp_ble_mesh_cfg_kr_phase_set_t kr_phase_set; /*!< For ESP_BLE_MESH_MODEL_OP_KEY_REFRESH_PHASE_SET */ + esp_ble_mesh_cfg_net_transmit_set_t net_transmit_set; /*!< For ESP_BLE_MESH_MODEL_OP_NETWORK_TRANSMIT_SET */ +} esp_ble_mesh_cfg_client_set_state_t; + +typedef struct { + uint8_t beacon; /*!< Secure Network Beacon state value */ +} esp_ble_mesh_cfg_beacon_status_cb_t; + +typedef struct { + uint8_t page; /*!< Page number of the Composition Data */ + struct net_buf_simple *composition_data; /*!< Pointer to Composition Data for the identified page */ +} esp_ble_mesh_cfg_comp_data_status_cb_t; + +typedef struct { + uint8_t default_ttl; /*!< Default TTL state value */ +} esp_ble_mesh_cfg_default_ttl_status_cb_t; + +typedef struct { + uint8_t gatt_proxy; /*!< GATT Proxy state value */ +} esp_ble_mesh_cfg_gatt_proxy_status_cb_t; + +typedef struct { + uint8_t relay; /*!< Relay state value */ + uint8_t retransmit; /*!< Relay retransmit value(number of retransmissions and number of 10-millisecond steps between retransmissions) */ +} esp_ble_mesh_cfg_relay_status_cb_t; + +typedef struct { + uint8_t status; /*!< Status Code for the request message */ + uint16_t element_addr; /*!< Address of the element */ + uint16_t publish_addr; /*!< Value of the publish address */ + uint16_t app_idx; /*!< Index of the application key */ + bool cred_flag; /*!< Value of the Friendship Credential Flag */ + uint8_t ttl; /*!< Default TTL value for the outgoing messages */ + uint8_t period; /*!< Period for periodic status publishing */ + uint8_t transmit; /*!< Number of retransmissions and number of 50-millisecond steps between retransmissions */ + uint16_t company_id; /*!< Company ID */ + uint16_t model_id; /*!< Model ID */ +} esp_ble_mesh_cfg_model_pub_status_cb_t; + +typedef struct { + uint8_t status; /*!< Status Code for the request message */ + uint16_t element_addr; /*!< Address of the element */ + uint16_t sub_addr; /*!< Value of the address */ + uint16_t company_id; /*!< Company ID */ + uint16_t model_id; /*!< Model ID */ +} esp_ble_mesh_cfg_model_sub_status_cb_t; + +typedef struct { + uint8_t status; /*!< Status Code for the request message */ + uint16_t net_idx; /*!< Index of the NetKey */ +} esp_ble_mesh_cfg_net_key_status_cb_t; + +typedef struct { + uint8_t status; /*!< Status Code for the request message */ + uint16_t net_idx; /*!< Index of the NetKey */ + uint16_t app_idx; /*!< Index of the application key */ +} esp_ble_mesh_cfg_app_key_status_cb_t; + +typedef struct { + uint8_t status; /*!< Status Code for the request message */ + uint16_t element_addr; /*!< Address of the element */ + uint16_t app_idx; /*!< Index of the application key */ + uint16_t company_id; /*!< Company ID */ + uint16_t model_id; /*!< Model ID */ +} esp_ble_mesh_cfg_mod_app_status_cb_t; + +typedef struct { + uint8_t friend_state; /*!< Friend state value */ +} esp_ble_mesh_cfg_friend_status_cb_t; + +typedef struct { + uint8_t status; /*!< Status Code for the request message */ + uint16_t dst; /*!< Destination address for Heartbeat messages */ + uint8_t count; /*!< Number of Heartbeat messages remaining to be sent */ + uint8_t period; /*!< Period for sending Heartbeat messages */ + uint8_t ttl; /*!< TTL to be used when sending Heartbeat messages */ + uint16_t features; /*!< Features that trigger Heartbeat messages when changed */ + uint16_t net_idx; /*!< Index of the NetKey */ +} esp_ble_mesh_cfg_hb_pub_status_cb_t; + +typedef struct { + uint8_t status; /*!< Status Code for the request message */ + uint16_t src; /*!< Source address for Heartbeat messages */ + uint16_t dst; /*!< Destination address for Heartbeat messages */ + uint8_t period; /*!< Remaining Period for processing Heartbeat messages */ + uint8_t count; /*!< Number of Heartbeat messages received */ + uint8_t min_hops; /*!< Minimum hops when receiving Heartbeat messages */ + uint8_t max_hops; /*!< Maximum hops when receiving Heartbeat messages */ +} esp_ble_mesh_cfg_hb_sub_status_cb_t; + +typedef struct { + uint8_t net_trans_count:3; /*!< Number of transmissions for each Network PDU originating from the node */ + uint8_t net_trans_step :5; /*!< Maximum hops when receiving Heartbeat messages */ +} esp_ble_mesh_cfg_net_trans_status_cb_t; + +typedef struct { + uint8_t status; /*!< Status Code for the request message */ + uint16_t element_addr; /*!< Address of the element */ + uint16_t company_id; /*!< Company ID */ + uint16_t model_id; /*!< Model ID */ + struct net_buf_simple *sub_addr; /*!< A block of all addresses from the Subscription List */ +} esp_ble_mesh_cfg_model_sub_list_cb_t; + +typedef struct { + struct net_buf_simple *net_idx; /*!< A list of NetKey Indexes known to the node */ +} esp_ble_mesh_cfg_net_key_list_cb_t; + +typedef struct { + uint8_t status; /*!< Status Code for the request message */ + uint16_t net_idx; /*!< NetKey Index of the NetKey that the AppKeys are bound to */ + struct net_buf_simple *app_idx; /*!< A list of AppKey indexes that are bound to the NetKey identified by NetKeyIndex */ +} esp_ble_mesh_cfg_app_key_list_cb_t; + +typedef struct { + uint8_t status; /*!< Status Code for the request message */ + uint16_t net_idx; /*!< Index of the NetKey */ + uint8_t identity; /*!< Node Identity state */ +} esp_ble_mesh_cfg_node_id_status_cb_t; + +typedef struct { + uint8_t status; /*!< Status Code for the request message */ + uint16_t element_addr; /*!< Address of the element */ + uint16_t company_id; /*!< Company ID */ + uint16_t model_id; /*!< Model ID */ + struct net_buf_simple *app_idx; /*!< All AppKey indexes bound to the Model */ +} esp_ble_mesh_cfg_model_app_list_cb_t; + +typedef struct { + uint8_t status; /*!< Status Code for the request message */ + uint16_t net_idx; /*!< Index of the NetKey */ + uint8_t phase; /*!< Key Refresh Phase state */ +} esp_ble_mesh_cfg_kr_phase_status_cb_t; + +typedef struct { + uint16_t lpn_addr; /*!< The unicast address of the Low Power node */ + int32_t poll_timeout; /*!< The current value of the PollTimeout timer of the Low Power node */ +} esp_ble_mesh_cfg_lpn_pollto_status_cb_t; + +typedef union { + esp_ble_mesh_cfg_beacon_status_cb_t beacon_status; /*!< The beacon status value */ + esp_ble_mesh_cfg_comp_data_status_cb_t comp_data_status; /*!< The composition data status value */ + esp_ble_mesh_cfg_default_ttl_status_cb_t default_ttl_status; /*!< The default_ttl status value */ + esp_ble_mesh_cfg_gatt_proxy_status_cb_t gatt_proxy_status; /*!< The gatt_proxy status value */ + esp_ble_mesh_cfg_relay_status_cb_t relay_status; /*!< The relay status value */ + esp_ble_mesh_cfg_model_pub_status_cb_t model_pub_status; /*!< The model publication status value */ + esp_ble_mesh_cfg_model_sub_status_cb_t model_sub_status; /*!< The model subscription status value */ + esp_ble_mesh_cfg_net_key_status_cb_t netkey_status; /*!< The netkey status value */ + esp_ble_mesh_cfg_app_key_status_cb_t appkey_status; /*!< The appkey status value */ + esp_ble_mesh_cfg_mod_app_status_cb_t model_app_status; /*!< The model app status value */ + esp_ble_mesh_cfg_friend_status_cb_t friend_status; /*!< The friend status value */ + esp_ble_mesh_cfg_hb_pub_status_cb_t heartbeat_pub_status; /*!< The heartbeat publication status value */ + esp_ble_mesh_cfg_hb_sub_status_cb_t heartbeat_sub_status; /*!< The heartbeat subscription status value */ + esp_ble_mesh_cfg_net_trans_status_cb_t net_transmit_status; /*!< The network transmit status value */ + esp_ble_mesh_cfg_model_sub_list_cb_t model_sub_list; /*!< The model subscription list value */ + esp_ble_mesh_cfg_net_key_list_cb_t netkey_list; /*!< The network key index list value */ + esp_ble_mesh_cfg_app_key_list_cb_t appkey_list; /*!< The application key index list value */ + esp_ble_mesh_cfg_node_id_status_cb_t node_identity_status; /*!< The node identity status value */ + esp_ble_mesh_cfg_model_app_list_cb_t model_app_list; /*!< The model application key index list value */ + esp_ble_mesh_cfg_kr_phase_status_cb_t kr_phase_status; /*!< The key refresh phase status value */ + esp_ble_mesh_cfg_lpn_pollto_status_cb_t lpn_timeout_status; /*!< The low power node poll timeout status value */ +} esp_ble_mesh_cfg_client_common_cb_param_t; + +typedef struct { + int error_code; /*!< Appropriate error code */ + esp_ble_mesh_client_common_param_t *params; /*!< The client common parameters */ + esp_ble_mesh_cfg_client_common_cb_param_t status_cb; /*!< The config status message callback values */ +} esp_ble_mesh_cfg_client_cb_param_t; + +typedef enum { + ESP_BLE_MESH_CFG_CLIENT_GET_STATE_EVT, + ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT, + ESP_BLE_MESH_CFG_CLIENT_PUBLISH_EVT, + ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT, + ESP_BLE_MESH_CFG_CLIENT_EVT_MAX, +} esp_ble_mesh_cfg_client_cb_event_t; + +typedef struct { + uint16_t app_idx; /* AppKey Index of the Config AppKey Add */ +} esp_ble_mesh_cfg_srv_app_key_add_cb_t; + +typedef union { + esp_ble_mesh_cfg_srv_app_key_add_cb_t app_key_add; /* !< The Config AppKey Add event value */ +} esp_ble_mesh_cfg_server_common_cb_param_t; + +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the server model structure */ + esp_ble_mesh_msg_ctx_t ctx; /*!< The context of the received message */ + esp_ble_mesh_cfg_server_common_cb_param_t status_cb; /*!< The received configuration message callback values */ +} esp_ble_mesh_cfg_server_cb_param_t; + +typedef enum { + ESP_BLE_MESH_CFG_SERVER_RECV_MSG_EVT, + ESP_BLE_MESH_CFG_SERVER_EVT_MAX, +} esp_ble_mesh_cfg_server_cb_event_t; + +/** + * @brief Bluetooth Mesh Config Client and Server Model functions. + */ + +/** @brief: event, event code of Config Client Model events; param, parameters of Config Client Model events */ +typedef void (* esp_ble_mesh_cfg_client_cb_t)(esp_ble_mesh_cfg_client_cb_event_t event, + esp_ble_mesh_cfg_client_cb_param_t *param); + +/** @brief: event, event code of Config Client Model events; param, parameters of Config Client Model events */ +typedef void (* esp_ble_mesh_cfg_server_cb_t)(esp_ble_mesh_cfg_server_cb_event_t event, + esp_ble_mesh_cfg_server_cb_param_t *param); + +/** + * @brief Register BLE Mesh Config Client Model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_config_client_callback(esp_ble_mesh_cfg_client_cb_t callback); + +/** + * @brief Register BLE Mesh Config Server Model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_config_server_callback(esp_ble_mesh_cfg_server_cb_t callback); + +/** + * @brief Get the value of Config Server Model states using the Config Client Model get messages. + * + * @note If you want to find the opcodes and corresponding meanings accepted by this API, + * please refer to (@ref esp_ble_mesh_opcode_config_client_get_t). + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] get_state: Pointer to a union, each kind of opcode corresponds to one structure inside. + * Shall not be set to NULL. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_config_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_cfg_client_get_state_t *get_state); + +/** + * @brief Set the value of the Configuration Server Model states using the Config Client Model set messages. + * + * @note If you want to find the opcodes and corresponding meanings accepted by this API, + * please refer to (@ref esp_ble_mesh_opcode_config_client_set_t). + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] set_state: Pointer to a union, each kind of opcode corresponds to one structure inside. + * Shall not be set to NULL. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_config_client_set_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_cfg_client_set_state_t *set_state); + +#endif /** _ESP_BLE_MESH_CONFIG_MODEL_API_H_ */ + diff --git a/components/bt/ble_mesh/api/models/include/esp_ble_mesh_generic_model_api.h b/components/bt/ble_mesh/api/models/include/esp_ble_mesh_generic_model_api.h new file mode 100644 index 0000000000..a8db2852f7 --- /dev/null +++ b/components/bt/ble_mesh/api/models/include/esp_ble_mesh_generic_model_api.h @@ -0,0 +1,478 @@ +// Copyright 2017-2018 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. + +/** @file + * @brief Bluetooth Mesh Generic Client Model APIs. + */ + +#ifndef _ESP_BLE_MESH_GENERIC_MODEL_API_H_ +#define _ESP_BLE_MESH_GENERIC_MODEL_API_H_ + +#include "generic_client.h" +#include "esp_ble_mesh_defs.h" + +/** @def ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI + * + * @brief Define a new Generic OnOff Client Model. + * + * @note This API needs to be called for each element on which + * the application needs to have a Generic OnOff Client Model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New Generic OnOff Client Model instance. + */ +#define ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, \ + NULL, cli_pub, cli_data) + +/** @def ESP_BLE_MESH_MODEL_GEN_LEVEL_CLI + * + * @brief Define a new Generic Level Client Model. + * + * @note This API needs to be called for each element on which + * the application needs to have a Generic Level Client Model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New Generic Level Client Model instance. + */ + +#define ESP_BLE_MESH_MODEL_GEN_LEVEL_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_LEVEL_CLI, \ + NULL, cli_pub, cli_data) + +/** @def ESP_BLE_MESH_MODEL_GEN_DEF_TRANS_TIME_CLI + * + * @brief Define a new Generic Default Transition Time Client Model. + * + * @note This API needs to be called for each element on which + * the application needs to have a Generic Default Transition + * Time Client Model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New Generic Default Transition Time Client Model instance. + */ +#define ESP_BLE_MESH_MODEL_GEN_DEF_TRANS_TIME_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_CLI, \ + NULL, cli_pub, cli_data) + +/** @def ESP_BLE_MESH_MODEL_GEN_POWER_ONOFF_CLI + * + * @brief Define a new Generic Power OnOff Client Model. + * + * @note This API needs to be called for each element on which + * the application needs to have a Generic Power OnOff Client Model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New Generic Power OnOff Client Model instance. + */ +#define ESP_BLE_MESH_MODEL_GEN_POWER_ONOFF_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_CLI, \ + NULL, cli_pub, cli_data) + +/** @def ESP_BLE_MESH_MODEL_GEN_POWER_LEVEL_CLI + * + * @brief Define a new Generic Power Level Client Model. + * + * @note This API needs to be called for each element on which + * the application needs to have a Generic Power Level Client Model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New Generic Power Level Client Model instance. + */ +#define ESP_BLE_MESH_MODEL_GEN_POWER_LEVEL_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_CLI, \ + NULL, cli_pub, cli_data) + +/** @def ESP_BLE_MESH_MODEL_GEN_BATTERY_CLI + * + * @brief Define a new Generic Battery Client Model. + * + * @note This API needs to be called for each element on which + * the application needs to have a Generic Battery Client Model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New Generic Battery Client Model instance. + */ +#define ESP_BLE_MESH_MODEL_GEN_BATTERY_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_BATTERY_CLI, \ + NULL, cli_pub, cli_data) + +/** @def ESP_BLE_MESH_MODEL_GEN_LOCATION_CLI + * + * @brief Define a new Generic Location Client Model. + * + * @note This API needs to be called for each element on which + * the application needs to have a Generic Location Client Model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New Generic Location Client Model instance. + */ +#define ESP_BLE_MESH_MODEL_GEN_LOCATION_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_LOCATION_CLI, \ + NULL, cli_pub, cli_data) + +/** @def ESP_BLE_MESH_MODEL_GEN_PROPERTY_CLI + * + * @brief Define a new Generic Property Client Model. + * + * @note This API needs to be called for each element on which + * the application needs to have a Generic Property Client Model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New Generic Location Client Model instance. + */ +#define ESP_BLE_MESH_MODEL_GEN_PROPERTY_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_PROP_CLI, \ + NULL, cli_pub, cli_data) + +/** + * @brief Bluetooth Mesh Generic Client Model Get and Set parameters structure. + */ + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + uint8_t onoff; /* Target value of Generic OnOff state */ + uint8_t tid; /* Transaction ID */ + uint8_t trans_time; /* Time to complete state transition (optional) */ + uint8_t delay; /* Indicate message execution delay (C.1) */ +} esp_ble_mesh_gen_onoff_set_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + int16_t level; /* Target value of Generic Level state */ + uint8_t tid; /* Transaction ID */ + uint8_t trans_time; /* Time to complete state transition (optional) */ + uint8_t delay; /* Indicate message execution delay (C.1) */ +} esp_ble_mesh_gen_level_set_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + int32_t level; /* Delta change of Generic Level state */ + uint8_t tid; /* Transaction ID */ + uint8_t trans_time; /* Time to complete state transition (optional) */ + uint8_t delay; /* Indicate message execution delay (C.1) */ +} esp_ble_mesh_gen_delta_set_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + int16_t delta_level;/* Delta Level step to calculate Move speed for Generic Level state */ + uint8_t tid; /* Transaction ID */ + uint8_t trans_time; /* Time to complete state transition (optional) */ + uint8_t delay; /* Indicate message execution delay (C.1) */ +} esp_ble_mesh_gen_move_set_t; + +typedef struct { + uint8_t trans_time; /* The value of the Generic Default Transition Time state */ +} esp_ble_mesh_gen_def_trans_time_set_t; + +typedef struct { + uint8_t onpowerup; /* The value of the Generic OnPowerUp state */ +} esp_ble_mesh_gen_onpowerup_set_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + uint16_t power; /* Target value of Generic Power Actual state */ + uint8_t tid; /* Transaction ID */ + uint8_t trans_time; /* Time to complete state transition (optional) */ + uint8_t delay; /* Indicate message execution delay (C.1) */ +} esp_ble_mesh_gen_power_level_set_t; + +typedef struct { + uint16_t power; /* The value of the Generic Power Default state */ +} esp_ble_mesh_gen_power_default_set_t; + +typedef struct { + uint16_t range_min; /* Value of Range Min field of Generic Power Range state */ + uint16_t range_max; /* Value of Range Max field of Generic Power Range state */ +} esp_ble_mesh_gen_power_range_set_t; + +typedef struct { + int32_t global_latitude; /* Global Coordinates (Latitude) */ + int32_t global_longitude; /* Global Coordinates (Longitude) */ + int16_t global_altitude; /* Global Altitude */ +} esp_ble_mesh_gen_loc_global_set_t; + +typedef struct { + int16_t local_north; /* Local Coordinates (North) */ + int16_t local_east; /* Local Coordinates (East) */ + int16_t local_altitude; /* Local Altitude */ + uint8_t floor_number; /* Floor Number */ + uint16_t uncertainty; /* Uncertainty */ +} esp_ble_mesh_gen_loc_local_set_t; + +typedef struct { + uint16_t property_id; /* Property ID identifying a Generic User Property */ +} esp_ble_mesh_gen_user_property_get_t; + +typedef struct { + uint16_t property_id; /* Property ID identifying a Generic User Property */ + struct net_buf_simple *property_value; /* Raw value for the User Property */ +} esp_ble_mesh_gen_user_property_set_t; + +typedef struct { + uint16_t property_id; /* Property ID identifying a Generic Admin Property */ +} esp_ble_mesh_gen_admin_property_get_t; + +typedef struct { + uint16_t property_id; /* Property ID identifying a Generic Admin Property */ + uint8_t user_access; /* Enumeration indicating user access */ + struct net_buf_simple *property_value; /* Raw value for the Admin Property */ +} esp_ble_mesh_gen_admin_property_set_t; + +typedef struct { + uint16_t property_id; /* Property ID identifying a Generic Manufacturer Property */ +} esp_ble_mesh_gen_manufacturer_property_get_t; + +typedef struct { + uint16_t property_id; /* Property ID identifying a Generic Manufacturer Property */ + uint8_t user_access; /* Enumeration indicating user access */ +} esp_ble_mesh_gen_manufacturer_property_set_t; + +typedef struct { + uint16_t property_id; /* A starting Client Property ID present within an element */ +} esp_ble_mesh_gen_client_properties_get_t; + +typedef union { + esp_ble_mesh_gen_user_property_get_t user_property_get; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET */ + esp_ble_mesh_gen_admin_property_get_t admin_property_get; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET*/ + esp_ble_mesh_gen_manufacturer_property_get_t manufacturer_property_get; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTY_SET */ + esp_ble_mesh_gen_client_properties_get_t client_properties_get; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_GET */ +} esp_ble_mesh_generic_client_get_state_t; + +typedef union { + esp_ble_mesh_gen_onoff_set_t onoff_set; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET & ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK */ + esp_ble_mesh_gen_level_set_t level_set; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_LEVEL_SET & ESP_BLE_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK */ + esp_ble_mesh_gen_delta_set_t delta_set; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_DELTA_SET & ESP_BLE_MESH_MODEL_OP_GEN_DELTA_SET_UNACK */ + esp_ble_mesh_gen_move_set_t move_set; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_MOVE_SET & ESP_BLE_MESH_MODEL_OP_GEN_MOVE_SET_UNACK */ + esp_ble_mesh_gen_def_trans_time_set_t def_trans_time_set; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET & ESP_BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET_UNACK */ + esp_ble_mesh_gen_onpowerup_set_t power_set; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET & ESP_BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET_UNACK */ + esp_ble_mesh_gen_power_level_set_t power_level_set; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET & ESP_BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET_UNACK */ + esp_ble_mesh_gen_power_default_set_t power_default_set; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET & ESP_BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET_UNACK */ + esp_ble_mesh_gen_power_range_set_t power_range_set; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET & ESP_BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET_UNACK */ + esp_ble_mesh_gen_loc_global_set_t loc_global_set; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET & ESP_BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET_UNACK */ + esp_ble_mesh_gen_loc_local_set_t loc_local_set; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET & ESP_BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET_UNACK */ + esp_ble_mesh_gen_user_property_set_t user_property_set; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET & ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET_UNACK */ + esp_ble_mesh_gen_admin_property_set_t admin_property_set; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET & ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET_UNACK */ + esp_ble_mesh_gen_manufacturer_property_set_t manufacturer_property_set; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTY_SET & ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTY_SET_UNACK */ +} esp_ble_mesh_generic_client_set_state_t; + +/** + * @brief Bluetooth Mesh Generic Client Model Get and Set callback parameters structure. + */ + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + uint8_t present_onoff; /* Current value of Generic OnOff state */ + uint8_t target_onoff; /* Target value of Generic OnOff state (optional) */ + uint8_t remain_time; /* Time to complete state transition (C.1) */ +} esp_ble_mesh_gen_onoff_status_cb_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + int16_t present_level; /* Current value of Generic Level state */ + int16_t target_level; /* Target value of the Generic Level state (optional) */ + uint8_t remain_time; /* Time to complete state transition (C.1) */ +} esp_ble_mesh_gen_level_status_cb_t; + +typedef struct { + uint8_t trans_time; /* The value of the Generic Default Transition Time state */ +} esp_ble_mesh_gen_def_trans_time_status_cb_t; + +typedef struct { + uint8_t onpowerup; /* The value of the Generic OnPowerUp state */ +} esp_ble_mesh_gen_onpowerup_status_cb_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + uint16_t present_power; /* Current value of Generic Power Actual state */ + uint16_t target_power; /* Target value of Generic Power Actual state (optional) */ + uint8_t remain_time; /* Time to complete state transition (C.1) */ +} esp_ble_mesh_gen_power_level_status_cb_t; + +typedef struct { + uint16_t power; /* The value of the Generic Power Last state */ +} esp_ble_mesh_gen_power_last_status_cb_t; + +typedef struct { + uint16_t power; /* The value of the Generic Default Last state */ +} esp_ble_mesh_gen_power_default_status_cb_t; + +typedef struct { + uint8_t status_code; /* Status Code for the request message */ + uint16_t range_min; /* Value of Range Min field of Generic Power Range state */ + uint16_t range_max; /* Value of Range Max field of Generic Power Range state */ +} esp_ble_mesh_gen_power_range_status_cb_t; + +typedef struct { + u32_t battery_level : 8; /* Value of Generic Battery Level state */ + u32_t time_to_discharge : 24; /* Value of Generic Battery Time to Discharge state */ + u32_t time_to_charge : 24; /* Value of Generic Battery Time to Charge state */ + u32_t flags : 8; /* Value of Generic Battery Flags state */ +} esp_ble_mesh_gen_battery_status_cb_t; + +typedef struct { + int32_t global_latitude; /* Global Coordinates (Latitude) */ + int32_t global_longitude; /* Global Coordinates (Longitude) */ + int16_t global_altitude; /* Global Altitude */ +} esp_ble_mesh_gen_loc_global_status_cb_t; + +typedef struct { + int16_t local_north; /* Local Coordinates (North) */ + int16_t local_east; /* Local Coordinates (East) */ + int16_t local_altitude; /* Local Altitude */ + uint8_t floor_number; /* Floor Number */ + uint16_t uncertainty; /* Uncertainty */ +} esp_ble_mesh_gen_loc_local_status_cb_t; + +typedef struct { + struct net_buf_simple *property_ids; /* Buffer contains a sequence of N User Property IDs */ +} esp_ble_mesh_gen_user_properties_status_cb_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + uint16_t property_id; /* Property ID identifying a Generic User Property */ + uint8_t user_access; /* Enumeration indicating user access (optional) */ + struct net_buf_simple *property_value; /* Raw value for the User Property (C.1) */ +} esp_ble_mesh_gen_user_property_status_cb_t; + +typedef struct { + struct net_buf_simple *property_ids; /* Buffer contains a sequence of N Admin Property IDs */ +} esp_ble_mesh_gen_admin_properties_status_cb_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + uint16_t property_id; /* Property ID identifying a Generic Admin Property */ + uint8_t user_access; /* Enumeration indicating user access (optional) */ + struct net_buf_simple *property_value; /* Raw value for the Admin Property (C.1) */ +} esp_ble_mesh_gen_admin_property_status_cb_t; + +typedef struct { + struct net_buf_simple *property_ids; /* Buffer contains a sequence of N Manufacturer Property IDs */ +} esp_ble_mesh_gen_manufacturer_properties_status_cb_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + uint16_t property_id; /* Property ID identifying a Generic Manufacturer Property */ + uint8_t user_access; /* Enumeration indicating user access (optional) */ + struct net_buf_simple *property_value; /* Raw value for the Manufacturer Property (C.1) */ +} esp_ble_mesh_gen_manufacturer_property_status_cb_t; + +typedef struct { + struct net_buf_simple *property_ids; /* Buffer contains a sequence of N Client Property IDs */ +} esp_ble_mesh_gen_client_properties_status_cb_t; + +typedef union { + esp_ble_mesh_gen_onoff_status_cb_t onoff_status; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS */ + esp_ble_mesh_gen_level_status_cb_t level_status; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS */ + esp_ble_mesh_gen_def_trans_time_status_cb_t def_trans_time_status; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_STATUS */ + esp_ble_mesh_gen_onpowerup_status_cb_t onpowerup_status; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_ONPOWERUP_STATUS */ + esp_ble_mesh_gen_power_level_status_cb_t power_level_status; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS */ + esp_ble_mesh_gen_power_last_status_cb_t power_last_status; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_POWER_LAST_STATUS */ + esp_ble_mesh_gen_power_default_status_cb_t power_default_status; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS */ + esp_ble_mesh_gen_power_range_status_cb_t power_range_status; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS */ + esp_ble_mesh_gen_battery_status_cb_t battery_status; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_BATTERY_STATUS */ + esp_ble_mesh_gen_loc_global_status_cb_t location_global_status; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_STATUS */ + esp_ble_mesh_gen_loc_local_status_cb_t location_local_status; /*!< ESP_BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_STATUS */ + esp_ble_mesh_gen_user_properties_status_cb_t user_properties_status; /*!< ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS */ + esp_ble_mesh_gen_user_property_status_cb_t user_property_status; /*!< ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_STATUS */ + esp_ble_mesh_gen_admin_properties_status_cb_t admin_properties_status; /*!< ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_STATUS */ + esp_ble_mesh_gen_admin_property_status_cb_t admin_property_status; /*!< ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_STATUS */ + esp_ble_mesh_gen_manufacturer_properties_status_cb_t manufacturer_properties_status; /*!< ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTIES_STATUS */ + esp_ble_mesh_gen_manufacturer_property_status_cb_t manufacturer_property_status; /*!< ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTY_STATUS */ + esp_ble_mesh_gen_client_properties_status_cb_t client_properties_status; /*!< ESP_BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS */ +} esp_ble_mesh_gen_client_status_cb_t; + +typedef struct { + int error_code; /*!< Appropriate error code */ + esp_ble_mesh_client_common_param_t *params; /*!< The client common parameters. */ + esp_ble_mesh_gen_client_status_cb_t status_cb; /*!< The generic status message callback values */ +} esp_ble_mesh_generic_client_cb_param_t; + +typedef enum { + ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT, + ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT, + ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT, + ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT, + ESP_BLE_MESH_GENERIC_CLIENT_EVT_MAX, +} esp_ble_mesh_generic_client_cb_event_t; + +/** + * @brief Bluetooth Mesh Generic Client Model function. + */ + +/** @brief: event, event code of Generic Client Model events; param, parameters of Generic Client Model events */ +typedef void (* esp_ble_mesh_generic_client_cb_t)(esp_ble_mesh_generic_client_cb_event_t event, + esp_ble_mesh_generic_client_cb_param_t *param); + +/** + * @brief Register BLE Mesh Generic Client Model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_generic_client_callback(esp_ble_mesh_generic_client_cb_t callback); + +/** + * @brief Get the value of Generic Server Model states using the Generic Client Model get messages. + * + * @note If you want to find the opcodes and corresponding meanings accepted by this API, + * please refer to (@ref esp_ble_mesh_generic_message_opcode_t). + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] get_state: Pointer to generic get message value. + * Shall not be set to NULL. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_generic_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_generic_client_get_state_t *get_state); + +/** + * @brief Set the value of Generic Server Model states using the Generic Client Model set messages. + * + * @note If you want to find the opcodes and corresponding meanings accepted by this API, + * please refer to (@ref esp_ble_mesh_generic_message_opcode_t). + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] set_state: Pointer to generic set message value. + * Shall not be set to NULL. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_generic_client_set_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_generic_client_set_state_t *set_state); + + +#endif /* _ESP_BLE_MESH_GENERIC_MODEL_API_H_ */ + diff --git a/components/bt/ble_mesh/api/models/include/esp_ble_mesh_health_model_api.h b/components/bt/ble_mesh/api/models/include/esp_ble_mesh_health_model_api.h new file mode 100644 index 0000000000..687bdc604e --- /dev/null +++ b/components/bt/ble_mesh/api/models/include/esp_ble_mesh_health_model_api.h @@ -0,0 +1,261 @@ +// Copyright 2017-2018 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. + +#ifndef _ESP_BLE_MESH_HEALTH_MODEL_API_H_ +#define _ESP_BLE_MESH_HEALTH_MODEL_API_H_ + +#include "esp_ble_mesh_defs.h" + +/** @def ESP_BLE_MESH_MODEL_HEALTH_SRV + * + * @brief Define a new Health Server Model. + * + * @note The Health Server Model can only be included by a Primary Element. + * + * @param srv Pointer to the unique struct esp_ble_mesh_health_srv_t. + * @param pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * + * @return New Health Server Model instance. + */ +#define ESP_BLE_MESH_MODEL_HEALTH_SRV(srv, pub) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_HEALTH_SRV, \ + NULL, pub, srv) + +/** @def ESP_BLE_MESH_MODEL_HEALTH_CLI + * + * @brief Define a new Health Client Model. + * + * @note This API needs to be called for each element on which + * the application needs to have a Health Client Model. + * + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New Health Client Model instance. + */ +#define ESP_BLE_MESH_MODEL_HEALTH_CLI(cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_HEALTH_CLI, \ + NULL, NULL, cli_data) + +typedef struct { + /* Fetch current faults */ + int (*fault_get_cur)(esp_ble_mesh_model_t *model, uint8_t *test_id, + uint16_t *company_id, uint8_t *faults, uint8_t *fault_count); + + /* Fetch registered faults */ + int (*fault_get_reg)(esp_ble_mesh_model_t *model, uint16_t company_id, + uint8_t *test_id, uint8_t *faults, uint8_t *fault_count); + + /* Clear registered faults */ + int (*fault_clear)(esp_ble_mesh_model_t *model, uint16_t company_id); + + /* Run a specific test */ + int (*fault_test)(esp_ble_mesh_model_t *model, uint8_t test_id, uint16_t company_id); + + /* Attention on */ + void (*attn_on)(esp_ble_mesh_model_t *model); + + /* Attention off */ + void (*attn_off)(esp_ble_mesh_model_t *model); +} esp_ble_mesh_health_srv_cb_t; + +/** ESP BLE Mesh Health Server Model Context */ +typedef struct { + esp_ble_mesh_model_t *model; + + /* Optional callback struct */ + const esp_ble_mesh_health_srv_cb_t *cb; + + /* Attention Timer state */ + struct k_delayed_work attn_timer; +} esp_ble_mesh_health_srv_t; + +/** BLE Mesh Health Client Model fault get Context */ +typedef struct { + uint16_t company_id; /*!< Bluetooth assigned 16-bit Company ID */ +} esp_ble_mesh_health_fault_get_t; + +/** Mesh Health Client Model attention set Context */ +typedef struct { + uint8_t attention; /*!< Value of the Attention Timer state */ +} esp_ble_mesh_health_attention_set_t; + +/** Mesh Health client Model period set Context */ +typedef struct { + uint8_t fast_period_divisor; /*!< Divider for the Publish Period */ +} esp_ble_mesh_health_period_set_t; + +/** BLE Mesh Health Client Model fault test Context */ +typedef struct { + uint16_t company_id; /*!< Bluetooth assigned 16-bit Company ID */ + uint8_t test_id; /*!< ID of a specific test to be performed */ +} esp_ble_mesh_health_fault_test_t; + +/** BLE Mesh Health Client Model fault clear Context */ +typedef struct { + uint16_t company_id; /*!< Bluetooth assigned 16-bit Company ID */ +} esp_ble_mesh_health_fault_clear_t; + +/** + * @brief For ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_GET + * ESP_BLE_MESH_MODEL_OP_ATTENTION_GET + * ESP_BLE_MESH_MODEL_OP_HEALTH_PERIOD_GET + * the get_state parameter in the esp_ble_mesh_health_client_get_state function should not be set to NULL. + */ +typedef union { + esp_ble_mesh_health_fault_get_t fault_get; /*!< For ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_GET. */ +} esp_ble_mesh_health_client_get_state_t; + +/** + * @brief For ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_CLEAR + * ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_CLEAR_UNACK + * ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_TEST + * ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_TEST_UNACK + * ESP_BLE_MESH_MODEL_OP_HEALTH_PERIOD_SET + * ESP_BLE_MESH_MODEL_OP_HEALTH_PERIOD_SET_UNACK + * ESP_BLE_MESH_MODEL_OP_ATTENTION_SET + * ESP_BLE_MESH_MODEL_OP_ATTENTION_SET_UNACK + * the set_state parameter in the esp_ble_mesh_health_client_set_state function should not be set to NULL. + */ +typedef union { + esp_ble_mesh_health_attention_set_t attention_set; /*!< For ESP_BLE_MESH_MODEL_OP_ATTENTION_SET or ESP_BLE_MESH_MODEL_OP_ATTENTION_SET_UNACK. */ + esp_ble_mesh_health_period_set_t period_set; /*!< For ESP_BLE_MESH_MODEL_OP_HEALTH_PERIOD_SET or ESP_BLE_MESH_MODEL_OP_HEALTH_PERIOD_SET_UNACK. */ + esp_ble_mesh_health_fault_test_t fault_test; /*!< For ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_TEST or ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_TEST_UNACK. */ + esp_ble_mesh_health_fault_clear_t fault_clear; /*!< For ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_CLEAR or ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_CLEAR_UNACK. */ +} esp_ble_mesh_health_client_set_state_t; + +typedef struct { + uint8_t test_id; /*!< ID of a most recently performed test */ + uint16_t company_id; /*!< Bluetooth assigned 16-bit Company ID */ + struct net_buf_simple *fault_array; /*!< FaultArray field contains a sequence of 1-octet fault values */ +} esp_ble_mesh_health_current_status_cb_t; + +typedef struct { + uint8_t test_id; /*!< ID of a most recently performed test */ + uint16_t company_id; /*!< Bluetooth assigned 16-bit Company ID */ + struct net_buf_simple *fault_array; /*!< FaultArray field contains a sequence of 1-octet fault values */ +} esp_ble_mesh_health_fault_status_cb_t; + +typedef struct { + uint8_t fast_period_divisor; /*!< Divider for the Publish Period */ +} esp_ble_mesh_health_period_status_cb_t; + +typedef struct { + uint8_t attention; /*!< Value of the Attention Timer state */ +} esp_ble_mesh_health_attention_status_cb_t; + +typedef union { + esp_ble_mesh_health_current_status_cb_t current_status; /*!< The health current status value */ + esp_ble_mesh_health_fault_status_cb_t fault_status; /*!< The health fault status value */ + esp_ble_mesh_health_period_status_cb_t period_status; /*!< The health period status value */ + esp_ble_mesh_health_attention_status_cb_t attention_status; /*!< The health attention status value */ +} esp_ble_mesh_health_client_common_cb_param_t; + +typedef struct { + int error_code; /*!< Appropriate error code */ + esp_ble_mesh_client_common_param_t *params; /*!< The client common parameters. */ + esp_ble_mesh_health_client_common_cb_param_t status_cb; /*!< The health message status callback values */ +} esp_ble_mesh_health_client_cb_param_t; + +typedef enum { + ESP_BLE_MESH_HEALTH_CLIENT_GET_STATE_EVT, + ESP_BLE_MESH_HEALTH_CLIENT_SET_STATE_EVT, + ESP_BLE_MESH_HEALTH_CLIENT_PUBLISH_EVT, + ESP_BLE_MESH_HEALTH_CLIENT_TIMEOUT_EVT, + ESP_BLE_MESH_HEALTH_CLIENT_EVT_MAX, +} esp_ble_mesh_health_client_cb_event_t; + +typedef struct { + int error_code; /*!< Appropriate error code */ +} esp_ble_mesh_health_server_cb_param_t; + +typedef enum { + ESP_BLE_MESH_HEALTH_SERVER_FAULT_UPDATE_COMPLETE_EVT, + ESP_BLE_MESH_HEALTH_SERVER_EVT_MAX, +} esp_ble_mesh_health_server_cb_event_t; + +/** + * @brief Bluetooth Mesh Health Client and Server Model function. + */ + +/** @brief: event, event code of Health Client Model event; param, parameters of Health Client Model event) */ +typedef void (* esp_ble_mesh_health_client_cb_t)(esp_ble_mesh_health_client_cb_event_t event, + esp_ble_mesh_health_client_cb_param_t *param); + +/** @brief: event, event code of Health Server Model event; param, parameters of Health Server Model event) */ +typedef void (* esp_ble_mesh_health_server_cb_t)(esp_ble_mesh_health_server_cb_event_t event, + esp_ble_mesh_health_server_cb_param_t *param); + +/** + * @brief Register BLE Mesh Health Model callback, the callback will report Health Client & Server Model events. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_health_client_callback(esp_ble_mesh_health_client_cb_t callback); + +/** + * @brief Register BLE Mesh Health Server Model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_health_server_callback(esp_ble_mesh_health_server_cb_t callback); + +/** + * @brief This function is called to get the Health Server states using the Health Client Model get messages. + * + * @note If you want to find the opcodes and corresponding meanings accepted by this API, + * please refer to (@ref esp_ble_mesh_opcode_health_client_get_t). + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] get_state: Pointer to a union, each kind of opcode corresponds to one structure inside. + * Shall not be set to NULL. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_health_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_health_client_get_state_t *get_state); + +/** + * @brief This function is called to set the Health Server states using the Health Client Model set messages. + * + * @note If you want to find the opcodes and corresponding meanings accepted by this API, + * please refer to (@ref esp_ble_mesh_opcode_health_client_set_t). + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] set_state: Pointer to a union, each kind of opcode corresponds to one structure inside. + * Shall not be set to NULL. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_health_client_set_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_health_client_set_state_t *set_state); + +/** + * @brief This function is called by the Health Server Model to start to publish its Current Health Fault. + * + * @param[in] element: The element to which the Health Server Model belongs. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_health_server_fault_update(esp_ble_mesh_elem_t *element); + +#endif /** _ESP_BLE_MESH_HEALTH_MODEL_API_H_ */ diff --git a/components/bt/ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h b/components/bt/ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h new file mode 100644 index 0000000000..ab119a48bc --- /dev/null +++ b/components/bt/ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h @@ -0,0 +1,526 @@ +// Copyright 2017-2018 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. + +/** @file + * @brief Bluetooth Mesh Light Client Model APIs. + */ + +#ifndef _ESP_BLE_MESH_LIGHTING_MODEL_API_H_ +#define _ESP_BLE_MESH_LIGHTING_MODEL_API_H_ + +#include "lighting_client.h" +#include "esp_ble_mesh_defs.h" + +/** @def ESP_BLE_MESH_MODEL_LIGHT_LIGHTNESS_CLI + * + * @brief Define a new Light Lightness Client Model. + * + * @note This API needs to be called for each element on which + * the application needs to have a Light Lightness Client Model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New Light Lightness Client Model instance. + */ +#define ESP_BLE_MESH_MODEL_LIGHT_LIGHTNESS_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_CLI, \ + NULL, cli_pub, cli_data) + +/** @def ESP_BLE_MESH_MODEL_LIGHT_CTL_CLI + * + * @brief Define a new Light CTL Client Model. + * + * @note This API needs to be called for each element on which + * the application needs to have a Light CTL Client Model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New Light CTL Client Model instance. + */ +#define ESP_BLE_MESH_MODEL_LIGHT_CTL_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_LIGHT_CTL_CLI, \ + NULL, cli_pub, cli_data) + +/** @def ESP_BLE_MESH_MODEL_LIGHT_HSL_CLI + * + * @brief Define a new Light HSL Client Model. + * + * @note This API needs to be called for each element on which + * the application needs to have a Light HSL Client Model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New Light HSL Client Model instance. + */ +#define ESP_BLE_MESH_MODEL_LIGHT_HSL_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_LIGHT_HSL_CLI, \ + NULL, cli_pub, cli_data) + +/** @def ESP_BLE_MESH_MODEL_LIGHT_XYL_CLI + * + * @brief Define a new Light xyL Client Model. + * + * @note This API needs to be called for each element on which + * the application needs to have a Light xyL Client Model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New Light xyL Client Model instance. + */ +#define ESP_BLE_MESH_MODEL_LIGHT_XYL_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_LIGHT_XYL_CLI, \ + NULL, cli_pub, cli_data) + +/** @def ESP_BLE_MESH_MODEL_LIGHT_LC_CLI + * + * @brief Define a new Light LC Client Model. + * + * @note This API needs to be called for each element on which + * the application needs to have a Light LC Client Model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New Light LC Client Model instance. + */ +#define ESP_BLE_MESH_MODEL_LIGHT_LC_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_LIGHT_LC_CLI, \ + NULL, cli_pub, cli_data) + +/** + * @brief Bluetooth Mesh Light Lightness Client Model Get and Set parameters structure. + */ + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + u16_t lightness; /* Target value of light lightness actual state */ + u8_t tid; /* Transaction ID */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +} esp_ble_mesh_light_lightness_set_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + u16_t lightness; /* Target value of light lightness linear state */ + u8_t tid; /* Transaction ID */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +} esp_ble_mesh_light_lightness_linear_set_t; + +typedef struct { + u16_t lightness; /* The value of the Light Lightness Default state */ +} esp_ble_mesh_light_lightness_default_set_t; + +typedef struct { + u16_t range_min; /* Value of range min field of light lightness range state */ + u16_t range_max; /* Value of range max field of light lightness range state */ +} esp_ble_mesh_light_lightness_range_set_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + u16_t ctl_lightness; /* Target value of light ctl lightness state */ + u16_t ctl_temperatrue; /* Target value of light ctl temperature state */ + s16_t ctl_delta_uv; /* Target value of light ctl delta UV state */ + u8_t tid; /* Transaction ID */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +} esp_ble_mesh_light_ctl_set_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + u16_t ctl_temperatrue; /* Target value of light ctl temperature state */ + s16_t ctl_delta_uv; /* Target value of light ctl delta UV state */ + u8_t tid; /* Transaction ID */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +} esp_ble_mesh_light_ctl_temperature_set_t; + +typedef struct { + u16_t range_min; /* Value of temperature range min field of light ctl temperature range state */ + u16_t range_max; /* Value of temperature range max field of light ctl temperature range state */ +} esp_ble_mesh_light_ctl_temperature_range_set_t; + +typedef struct { + u16_t lightness; /* Value of light lightness default state */ + u16_t temperature; /* Value of light temperature default state */ + s16_t delta_uv; /* Value of light delta UV default state */ +} esp_ble_mesh_light_ctl_default_set_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + u16_t hsl_lightness; /* Target value of light hsl lightness state */ + u16_t hsl_hue; /* Target value of light hsl hue state */ + u16_t hsl_saturation; /* Target value of light hsl saturation state */ + u8_t tid; /* Transaction ID */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +} esp_ble_mesh_light_hsl_set_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + u16_t hue; /* Target value of light hsl hue state */ + u8_t tid; /* Transaction ID */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +} esp_ble_mesh_light_hsl_hue_set_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + u16_t saturation; /* Target value of light hsl hue state */ + u8_t tid; /* Transaction ID */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +} esp_ble_mesh_light_hsl_saturation_set_t; + +typedef struct { + u16_t lightness; /* Value of light lightness default state */ + u16_t hue; /* Value of light hue default state */ + u16_t saturation; /* Value of light saturation default state */ +} esp_ble_mesh_light_hsl_default_set_t; + +typedef struct { + u16_t hue_range_min; /* Value of hue range min field of light hsl hue range state */ + u16_t hue_range_max; /* Value of hue range max field of light hsl hue range state */ + u16_t saturation_range_min; /* Value of saturation range min field of light hsl saturation range state */ + u16_t saturation_range_max; /* Value of saturation range max field of light hsl saturation range state */ +} esp_ble_mesh_light_hsl_range_set_t; + +typedef struct { + bool op_en; /* Indicate whether optional parameters included */ + u16_t xyl_lightness; /* The target value of the Light xyL Lightness state */ + u16_t xyl_x; /* The target value of the Light xyL x state */ + u16_t xyl_y; /* The target value of the Light xyL y state */ + u8_t tid; /* Transaction Identifier */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +} esp_ble_mesh_light_xyl_set_t; + +typedef struct { + u16_t lightness; /* The value of the Light Lightness Default state */ + u16_t xyl_x; /* The value of the Light xyL x Default state */ + u16_t xyl_y; /* The value of the Light xyL y Default state */ +} esp_ble_mesh_light_xyl_default_set_t; + +typedef struct { + u16_t xyl_x_range_min; /* The value of the xyL x Range Min field of the Light xyL x Range state */ + u16_t xyl_x_range_max; /* The value of the xyL x Range Max field of the Light xyL x Range state */ + u16_t xyl_y_range_min; /* The value of the xyL y Range Min field of the Light xyL y Range state */ + u16_t xyl_y_range_max; /* The value of the xyL y Range Max field of the Light xyL y Range state */ +} esp_ble_mesh_light_xyl_range_set_t; + +typedef struct { + u8_t mode; /* The target value of the Light LC Mode state */ +} esp_ble_mesh_light_lc_mode_set_t; + +typedef struct { + u8_t mode; /* The target value of the Light LC Occupancy Mode state */ +} esp_ble_mesh_light_lc_om_set_t; + +typedef struct { + bool op_en; /* Indicate whether optional parameters included */ + u8_t light_onoff; /* The target value of the Light LC Light OnOff state */ + u8_t tid; /* Transaction Identifier */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +} esp_ble_mesh_light_lc_light_onoff_set_t; + +typedef struct { + u16_t property_id; /* Property ID identifying a Light LC Property */ +} esp_ble_mesh_light_lc_property_get_t; + +typedef struct { + u16_t property_id; /* Property ID identifying a Light LC Property */ + struct net_buf_simple *property_value; /* Raw value for the Light LC Property */ +} esp_ble_mesh_light_lc_property_set_t; + +typedef union { + esp_ble_mesh_light_lc_property_get_t lc_property_get; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_GET */ +} esp_ble_mesh_light_client_get_state_t; + +typedef union { + esp_ble_mesh_light_lightness_set_t lightness_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET_UNACK */ + esp_ble_mesh_light_lightness_linear_set_t lightness_linear_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET_UNACK */ + esp_ble_mesh_light_lightness_default_set_t lightness_default_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET_UNACK */ + esp_ble_mesh_light_lightness_range_set_t lightness_range_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET_UNACK */ + esp_ble_mesh_light_ctl_set_t ctl_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_SET_UNACK */ + esp_ble_mesh_light_ctl_temperature_set_t ctl_temperature_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET_UNACK */ + esp_ble_mesh_light_ctl_temperature_range_set_t ctl_temperature_range_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET_UNACK */ + esp_ble_mesh_light_ctl_default_set_t ctl_default_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET_UNACK */ + esp_ble_mesh_light_hsl_set_t hsl_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_SET_UNACK */ + esp_ble_mesh_light_hsl_hue_set_t hsl_hue_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET_UNACK */ + esp_ble_mesh_light_hsl_saturation_set_t hsl_saturation_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET_UNACK */ + esp_ble_mesh_light_hsl_default_set_t hsl_default_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET_UNACK */ + esp_ble_mesh_light_hsl_range_set_t hsl_range_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET_UNACK */ + esp_ble_mesh_light_xyl_set_t xyl_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_SET_UNACK */ + esp_ble_mesh_light_xyl_default_set_t xyl_default_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET_UNACK */ + esp_ble_mesh_light_xyl_range_set_t xyl_range_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET_UNACK */ + esp_ble_mesh_light_lc_mode_set_t lc_mode_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET_UNACK */ + esp_ble_mesh_light_lc_om_set_t lc_om_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET_UNACK */ + esp_ble_mesh_light_lc_light_onoff_set_t lc_light_onoff_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET_UNACK */ + esp_ble_mesh_light_lc_property_set_t lc_property_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET_UNACK */ +} esp_ble_mesh_light_client_set_state_t; + +/** + * @brief Bluetooth Mesh Light Lightness Client Model Get and Set callback parameters structure. + */ + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + u16_t present_lightness; /* Current value of light lightness actual state */ + u16_t target_lightness; /* Target value of light lightness actual state (optional) */ + u8_t remain_time; /* Time to complete state transition (C.1) */ +} esp_ble_mesh_light_lightness_status_cb_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + u16_t present_lightness; /* Current value of light lightness linear state */ + u16_t target_lightness; /* Target value of light lightness linear state (optional) */ + u8_t remain_time; /* Time to complete state transition (C.1) */ +} esp_ble_mesh_light_lightness_linear_status_cb_t; + +typedef struct { + u16_t lightness; /* The value of the Light Lightness Last state */ +} esp_ble_mesh_light_lightness_last_status_cb_t; + +typedef struct { + u16_t lightness; /* The value of the Light Lightness default State */ +} esp_ble_mesh_light_lightness_default_status_cb_t; + +typedef struct { + u8_t status_code; /* Status Code for the request message */ + u16_t range_min; /* Value of range min field of light lightness range state */ + u16_t range_max; /* Value of range max field of light lightness range state */ +} esp_ble_mesh_light_lightness_range_status_cb_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + u16_t present_ctl_lightness; /* Current value of light ctl lightness state */ + u16_t present_ctl_temperature; /* Current value of light ctl temperature state */ + u16_t target_ctl_lightness; /* Target value of light ctl lightness state (optional) */ + u16_t target_ctl_temperature; /* Target value of light ctl temperature state (C.1) */ + u8_t remain_time; /* Time to complete state transition (C.1) */ +} esp_ble_mesh_light_ctl_status_cb_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + u16_t present_ctl_temperature; /* Current value of light ctl temperature state */ + u16_t present_ctl_delta_uv; /* Current value of light ctl delta UV state */ + u16_t target_ctl_temperature; /* Target value of light ctl temperature state (optional) */ + u16_t target_ctl_delta_uv; /* Target value of light ctl delta UV state (C.1) */ + u8_t remain_time; /* Time to complete state transition (C.1) */ +} esp_ble_mesh_light_ctl_temperature_status_cb_t; + +typedef struct { + u8_t status_code; /* Status code for the request message */ + u16_t range_min; /* Value of temperature range min field of light ctl temperature range state */ + u16_t range_max; /* Value of temperature range max field of light ctl temperature range state */ +} esp_ble_mesh_light_ctl_temperature_range_status_cb_t; + +typedef struct { + u16_t lightness; /* Value of light lightness default state */ + u16_t temperature; /* Value of light temperature default state */ + s16_t delta_uv; /* Value of light delta UV default state */ +} esp_ble_mesh_light_ctl_default_status_cb_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + u16_t hsl_lightness; /* Current value of light hsl lightness state */ + u16_t hsl_hue; /* Current value of light hsl hue state */ + u16_t hsl_saturation; /* Current value of light hsl saturation state */ + u8_t remain_time; /* Time to complete state transition (optional) */ +} esp_ble_mesh_light_hsl_status_cb_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + u16_t hsl_lightness_target; /* Target value of light hsl lightness state */ + u16_t hsl_hue_target; /* Target value of light hsl hue state */ + u16_t hsl_saturation_target; /* Target value of light hsl saturation state */ + u8_t remain_time; /* Time to complete state transition (optional) */ +} esp_ble_mesh_light_hsl_target_status_cb_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + u16_t present_hue; /* Current value of light hsl hue state */ + u16_t target_hue; /* Target value of light hsl hue state (optional) */ + u8_t remain_time; /* Time to complete state transition (C.1) */ +} esp_ble_mesh_light_hsl_hue_status_cb_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + u16_t present_saturation; /* Current value of light hsl saturation state */ + u16_t target_saturation; /* Target value of light hsl saturation state (optional) */ + u8_t remain_time; /* Time to complete state transition (C.1) */ +} esp_ble_mesh_light_hsl_saturation_status_cb_t; + +typedef struct { + u16_t lightness; /* Value of light lightness default state */ + u16_t hue; /* Value of light hue default state */ + u16_t saturation; /* Value of light saturation default state */ +} esp_ble_mesh_light_hsl_default_status_cb_t; + +typedef struct { + u8_t status_code; /* Status code for the request message */ + u16_t hue_range_min; /* Value of hue range min field of light hsl hue range state */ + u16_t hue_range_max; /* Value of hue range max field of light hsl hue range state */ + u16_t saturation_range_min; /* Value of saturation range min field of light hsl saturation range state */ + u16_t saturation_range_max; /* Value of saturation range max field of light hsl saturation range state */ +} esp_ble_mesh_light_hsl_range_status_cb_t; + +typedef struct { + bool op_en; /* Indicate whether optional parameters included */ + u16_t xyl_lightness; /* The present value of the Light xyL Lightness state */ + u16_t xyl_x; /* The present value of the Light xyL x state */ + u16_t xyl_y; /* The present value of the Light xyL y state */ + u8_t remain_time; /* Time to complete state transition (optional) */ +} esp_ble_mesh_light_xyl_status_cb_t; + +typedef struct { + bool op_en; /* Indicate whether optional parameters included */ + u16_t target_xyl_lightness; /* The target value of the Light xyL Lightness state */ + u16_t target_xyl_x; /* The target value of the Light xyL x state */ + u16_t target_xyl_y; /* The target value of the Light xyL y state */ + u8_t remain_time; /* Time to complete state transition (optional) */ +} esp_ble_mesh_light_xyl_target_status_cb_t; + +typedef struct { + u16_t lightness; /* The value of the Light Lightness Default state */ + u16_t xyl_x; /* The value of the Light xyL x Default state */ + u16_t xyl_y; /* The value of the Light xyL y Default state */ +} esp_ble_mesh_light_xyl_default_status_cb_t; + +typedef struct { + u8_t status_code; /* Status Code for the requesting message */ + u16_t xyl_x_range_min; /* The value of the xyL x Range Min field of the Light xyL x Range state */ + u16_t xyl_x_range_max; /* The value of the xyL x Range Max field of the Light xyL x Range state */ + u16_t xyl_y_range_min; /* The value of the xyL y Range Min field of the Light xyL y Range state */ + u16_t xyl_y_range_max; /* The value of the xyL y Range Max field of the Light xyL y Range state */ +} esp_ble_mesh_light_xyl_range_status_cb_t; + +typedef struct { + u8_t mode; /* The present value of the Light LC Mode state */ +} esp_ble_mesh_light_lc_mode_status_cb_t; + +typedef struct { + u8_t mode; /* The present value of the Light LC Occupancy Mode state */ +} esp_ble_mesh_light_lc_om_status_cb_t; + +typedef struct { + bool op_en; /* Indicate whether optional parameters included */ + u8_t present_light_onoff; /* The present value of the Light LC Light OnOff state */ + u8_t target_light_onoff; /* The target value of the Light LC Light OnOff state (Optional) */ + u8_t remain_time; /* Time to complete state transition (C.1) */ +} esp_ble_mesh_light_lc_light_onoff_status_cb_t; + +typedef struct { + u16_t property_id; /* Property ID identifying a Light LC Property */ + struct net_buf_simple *property_value; /* Raw value for the Light LC Property */ +} esp_ble_mesh_light_lc_property_status_cb_t; + +typedef union { + esp_ble_mesh_light_lightness_status_cb_t lightness_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS */ + esp_ble_mesh_light_lightness_linear_status_cb_t lightness_linear_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS */ + esp_ble_mesh_light_lightness_last_status_cb_t lightness_last_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_STATUS */ + esp_ble_mesh_light_lightness_default_status_cb_t lightness_default_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_STATUS */ + esp_ble_mesh_light_lightness_range_status_cb_t lightness_range_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_STATUS */ + esp_ble_mesh_light_ctl_status_cb_t ctl_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS */ + esp_ble_mesh_light_ctl_temperature_status_cb_t ctl_temperature_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS */ + esp_ble_mesh_light_ctl_temperature_range_status_cb_t ctl_temperature_range_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_STATUS */ + esp_ble_mesh_light_ctl_default_status_cb_t ctl_default_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_STATUS */ + esp_ble_mesh_light_hsl_status_cb_t hsl_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS */ + esp_ble_mesh_light_hsl_target_status_cb_t hsl_target_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_STATUS */ + esp_ble_mesh_light_hsl_hue_status_cb_t hsl_hue_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS */ + esp_ble_mesh_light_hsl_saturation_status_cb_t hsl_saturation_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS */ + esp_ble_mesh_light_hsl_default_status_cb_t hsl_default_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_STATUS */ + esp_ble_mesh_light_hsl_range_status_cb_t hsl_range_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_STATUS */ + esp_ble_mesh_light_xyl_status_cb_t xyl_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS */ + esp_ble_mesh_light_xyl_target_status_cb_t xyl_target_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_STATUS */ + esp_ble_mesh_light_xyl_default_status_cb_t xyl_default_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_STATUS */ + esp_ble_mesh_light_xyl_range_status_cb_t xyl_range_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_STATUS */ + esp_ble_mesh_light_lc_mode_status_cb_t lc_mode_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LC_MODE_STATUS */ + esp_ble_mesh_light_lc_om_status_cb_t lc_om_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LC_OM_STATUS */ + esp_ble_mesh_light_lc_light_onoff_status_cb_t lc_light_onoff_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS */ + esp_ble_mesh_light_lc_property_status_cb_t lc_property_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS */ +} esp_ble_mesh_light_client_status_cb_t; + +typedef struct { + int error_code; /*!< Appropriate error code */ + esp_ble_mesh_client_common_param_t *params; /*!< The client common parameters. */ + esp_ble_mesh_light_client_status_cb_t status_cb; /*!< The light status message callback values */ +} esp_ble_mesh_light_client_cb_param_t; + +typedef enum { + ESP_BLE_MESH_LIGHT_CLIENT_GET_STATE_EVT, + ESP_BLE_MESH_LIGHT_CLIENT_SET_STATE_EVT, + ESP_BLE_MESH_LIGHT_CLIENT_PUBLISH_EVT, + ESP_BLE_MESH_LIGHT_CLIENT_TIMEOUT_EVT, + ESP_BLE_MESH_LIGHT_CLIENT_EVT_MAX, +} esp_ble_mesh_light_client_cb_event_t; + +/** + * @brief Bluetooth Mesh Light Client Model function. + */ + +/** @brief: event, event code of Light Client Model events; param, parameters of Light Client Model events */ +typedef void (* esp_ble_mesh_light_client_cb_t)(esp_ble_mesh_light_client_cb_event_t event, + esp_ble_mesh_light_client_cb_param_t *param); + +/** + * @brief Register BLE Mesh Light Client Model callback. + * + * @param[in] callback: pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_light_client_callback(esp_ble_mesh_light_client_cb_t callback); + +/** + * @brief Get the value of Light Server Model states using the Light Client Model get messages. + * + * @note If you want to know the opcodes and corresponding meanings accepted by this API, + * please refer to (@ref esp_ble_mesh_light_message_opcode_t). + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] get_state: Pointer of light get message value. + * Shall not be set to NULL. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_light_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_light_client_get_state_t *get_state); + +/** + * @brief Set the value of Light Server Model states using the Light Client Model set messages. + * + * @note If you want to know the opcodes and corresponding meanings accepted by this API, + * please refer to (@ref esp_ble_mesh_light_message_opcode_t). + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] set_state: Pointer of generic set message value. + * Shall not be set to NULL. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_light_client_set_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_light_client_set_state_t *set_state); + + +#endif /* _ESP_BLE_MESH_LIGHTING_MODEL_API_H_ */ + diff --git a/components/bt/ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h b/components/bt/ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h new file mode 100644 index 0000000000..553845cad8 --- /dev/null +++ b/components/bt/ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h @@ -0,0 +1,230 @@ +// Copyright 2017-2018 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. + +/** @file + * @brief Bluetooth Mesh Sensor Client Model APIs. + */ + +#ifndef _ESP_BLE_MESH_SENSOR_MODEL_API_H_ +#define _ESP_BLE_MESH_SENSOR_MODEL_API_H_ + +#include "sensor_client.h" +#include "esp_ble_mesh_defs.h" + +/** @def ESP_BLE_MESH_MODEL_SENSOR_CLI + * + * @brief Define a new Sensor Client Model. + * + * @note This API needs to be called for each element on which + * the application needs to have a Sensor Client Model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New Sensor Client Model instance. + */ +#define ESP_BLE_MESH_MODEL_SENSOR_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_SENSOR_CLI, \ + NULL, cli_pub, cli_data) + +/** + * @brief Bluetooth Mesh Sensor Client Model Get and Set parameters structure. + */ +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + u16_t property_id; /* Property ID of a sensor (optional) */ +} esp_ble_mesh_sensor_descriptor_get_t; + +typedef struct { + u16_t property_id; /* Property ID of a sensor */ +} esp_ble_mesh_sensor_cadence_get_t; + +typedef struct { + u16_t property_id; /* Property ID for the sensor */ + u8_t fast_cadence_period_divisor : 7, /* Divisor for the publish period */ + status_trigger_type : 1; /* The unit and format of the Status Trigger Delta fields */ + struct net_buf_simple *status_trigger_delta_down; /* Delta down value that triggers a status message */ + struct net_buf_simple *status_trigger_delta_up; /* Delta up value that triggers a status message */ + u8_t status_min_interval; /* Minimum interval between two consecutive Status messages */ + struct net_buf_simple *fast_cadence_low; /* Low value for the fast cadence range */ + struct net_buf_simple *fast_cadence_high; /* Fast value for the fast cadence range */ +} esp_ble_mesh_sensor_cadence_set_t; + +typedef struct { + u16_t sensor_property_id; /* Property ID of a sensor */ +} esp_ble_mesh_sensor_settings_get_t; + +typedef struct { + u16_t sensor_property_id; /* Property ID of a sensor */ + u16_t sensor_setting_property_id; /* Setting ID identifying a setting within a sensor */ +} esp_ble_mesh_sensor_setting_get_t; + +typedef struct { + u16_t sensor_property_id; /* Property ID identifying a sensor */ + u16_t sensor_setting_property_id; /* Setting ID identifying a setting within a sensor */ + struct net_buf_simple *sensor_setting_raw; /* Raw value for the setting */ +} esp_ble_mesh_sensor_setting_set_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + u16_t property_id; /* Property ID for the sensor (optional) */ +} esp_ble_mesh_sensor_get_t; + +typedef struct { + u16_t property_id; /* Property identifying a sensor */ + struct net_buf_simple *raw_value_x; /* Raw value identifying a column */ +} esp_ble_mesh_sensor_column_get_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + u16_t property_id; /* Property identifying a sensor */ + struct net_buf_simple *raw_value_x1; /* Raw value identifying a starting column (optional) */ + struct net_buf_simple *raw_value_x2; /* Raw value identifying an ending column (C.1) */ +} esp_ble_mesh_sensor_series_get_t; + +typedef union { + esp_ble_mesh_sensor_descriptor_get_t descriptor_get; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET */ + esp_ble_mesh_sensor_cadence_get_t cadence_get; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET */ + esp_ble_mesh_sensor_settings_get_t settings_get; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET */ + esp_ble_mesh_sensor_setting_get_t setting_get; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_GET */ + esp_ble_mesh_sensor_get_t sensor_get; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_GET */ + esp_ble_mesh_sensor_column_get_t column_get; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET */ + esp_ble_mesh_sensor_series_get_t series_get; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_SERIES_GET */ +} esp_ble_mesh_sensor_client_get_state_t; + +typedef union { + esp_ble_mesh_sensor_cadence_set_t cadence_set; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET & ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK */ + esp_ble_mesh_sensor_setting_set_t setting_set; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET & ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET_UNACK */ +} esp_ble_mesh_sensor_client_set_state_t; + +/** + * @brief Bluetooth Mesh Sensor Client Model Get and Set callback parameters structure. + */ + +typedef struct { + struct net_buf_simple *descriptor; /* Sequence of 8-octet sensor descriptors (optional) */ +} esp_ble_mesh_sensor_descriptor_status_cb_t; + +typedef struct { + u16_t property_id; /* Property for the sensor */ + struct net_buf_simple *sensor_cadence_value; /* Value of sensor cadence state */ +} esp_ble_mesh_sensor_cadence_status_cb_t; + +typedef struct { + u16_t sensor_property_id; /* Property ID identifying a sensor */ + struct net_buf_simple *sensor_setting_property_ids; /* A sequence of N sensor setting property IDs (optional) */ +} esp_ble_mesh_sensor_settings_status_cb_t; + +typedef struct { + bool op_en; /* Indicate id optional parameters are included */ + u16_t sensor_property_id; /* Property ID identifying a sensor */ + u16_t sensor_setting_property_id; /* Setting ID identifying a setting within a sensor */ + u8_t sensor_setting_access; /* Read/Write access rights for the setting (optional) */ + struct net_buf_simple *sensor_setting_raw; /* Raw value for the setting */ +} esp_ble_mesh_sensor_setting_status_cb_t; + +typedef struct { + struct net_buf_simple *marshalled_sensor_data; /* Value of sensor data state (optional) */ +} esp_ble_mesh_sensor_status_cb_t; + +typedef struct { + u16_t property_id; /* Property identifying a sensor and the Y axis */ + struct net_buf_simple *sensor_column_value; /* Left values of sensor column status */ +} esp_ble_mesh_sensor_column_status_cb_t; + +typedef struct { + u16_t property_id; /* Property identifying a sensor and the Y axis */ + struct net_buf_simple *sensor_series_value; /* Left values of sensor series status */ +} esp_ble_mesh_sensor_series_status_cb_t; + + +typedef union { + esp_ble_mesh_sensor_descriptor_status_cb_t descriptor_status; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS */ + esp_ble_mesh_sensor_cadence_status_cb_t cadence_status; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS */ + esp_ble_mesh_sensor_settings_status_cb_t settings_status; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_SETTINGS_STATUS */ + esp_ble_mesh_sensor_setting_status_cb_t setting_status; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_STATUS */ + esp_ble_mesh_sensor_status_cb_t sensor_status; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_STATUS */ + esp_ble_mesh_sensor_column_status_cb_t column_status; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_COLUMN_STATUS */ + esp_ble_mesh_sensor_series_status_cb_t series_status; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_SERIES_STATUS */ +} esp_ble_mesh_sensor_client_status_cb_t; + +typedef struct { + int error_code; /*!< 0: success, + * otherwise failure. For the error code values please refer to errno.h file. + * A negative sign is added to the standard error codes in errno.h. */ + esp_ble_mesh_client_common_param_t *params; /*!< The client common parameters. */ + esp_ble_mesh_sensor_client_status_cb_t status_cb; /*!< The sensor status message callback values */ +} esp_ble_mesh_sensor_client_cb_param_t; + +typedef enum { + ESP_BLE_MESH_SENSOR_CLIENT_GET_STATE_EVT, + ESP_BLE_MESH_SENSOR_CLIENT_SET_STATE_EVT, + ESP_BLE_MESH_SENSOR_CLIENT_PUBLISH_EVT, + ESP_BLE_MESH_SENSOR_CLIENT_TIMEOUT_EVT, + ESP_BLE_MESH_SENSOR_CLIENT_EVT_MAX, +} esp_ble_mesh_sensor_client_cb_event_t; + +/** + * @brief Bluetooth Mesh Sensor Client Model function. + */ + +/** @brief: event, event code of Sensor Client Model events; param, parameters of Sensor Client Model events */ +typedef void (* esp_ble_mesh_sensor_client_cb_t)(esp_ble_mesh_sensor_client_cb_event_t event, + esp_ble_mesh_sensor_client_cb_param_t *param); + +/** + * @brief Register BLE Mesh Sensor Client Model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_sensor_client_callback(esp_ble_mesh_sensor_client_cb_t callback); + +/** + * @brief Get the value of Sensor Server Model states using the Sensor Client Model get messages. + * + * @note If you want to know the opcodes and corresponding meanings accepted by this API, + * please refer to (@ref esp_ble_mesh_sensor_message_opcode_t). + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] get_state: Pointer to sensor get message value. + * Shall not be set to NULL. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_sensor_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_sensor_client_get_state_t *get_state); + +/** + * @brief Set the value of Sensor Server Model states using the Sensor Client Model set messages. + * + * @note If you want to know the opcodes and corresponding meanings accepted by this API, + * please refer to (@ref esp_ble_mesh_sensor_message_opcode_t). + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] set_state: Pointer to sensor set message value. + * Shall not be set to NULL. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_sensor_client_set_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_sensor_client_set_state_t *set_state); + +#endif /* _ESP_BLE_MESH_SENSOR_MODEL_API_H_ */ + + diff --git a/components/bt/ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h b/components/bt/ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h new file mode 100644 index 0000000000..cdf55ef170 --- /dev/null +++ b/components/bt/ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h @@ -0,0 +1,292 @@ +// Copyright 2017-2018 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. + +/** @file + * @brief Bluetooth Mesh Time and Scene Client Model APIs. + */ + +#ifndef _ESP_BLE_MESH_TIME_SCENE_MODEL_API_H_ +#define _ESP_BLE_MESH_TIME_SCENE_MODEL_API_H_ + +#include "time_scene_client.h" +#include "esp_ble_mesh_defs.h" + +/** @def ESP_BLE_MESH_MODEL_TIME_CLI + * + * @brief Define a new Time Client Model. + * + * @note This API needs to be called for each element on which + * the application needs to have a Time Client Model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New Time Client Model instance. + */ +#define ESP_BLE_MESH_MODEL_TIME_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_TIME_CLI, \ + NULL, cli_pub, cli_data) + +/** @def ESP_BLE_MESH_MODEL_SCENE_CLI + * + * @brief Define a new Scene Client Model. + * + * @note This API needs to be called for each element on which + * the application needs to have a Scene Client Model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New Scene Client Model instance. + */ +#define ESP_BLE_MESH_MODEL_SCENE_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_SCENE_CLI, \ + NULL, cli_pub, cli_data) + +/** @def ESP_BLE_MESH_MODEL_SCHEDULER_CLI + * + * @brief Define a new Scheduler Client Model. + * + * @note This API needs to be called for each element on which + * the application needs to have a Scheduler Client Model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New Scheduler Client Model instance. + */ +#define ESP_BLE_MESH_MODEL_SCHEDULER_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_SCHEDULER_CLI, \ + NULL, cli_pub, cli_data) + +/** + * @brief Bluetooth Mesh Time Scene Client Model Get and Set parameters structure. + */ + +typedef struct { + u8_t tai_seconds[5]; /* The current TAI time in seconds */ + u8_t sub_second; /* The sub-second time in units of 1/256 second */ + u8_t uncertainty; /* The estimated uncertainty in 10-millisecond steps */ + u16_t time_authority : 1; /* 0 = No Time Authority, 1 = Time Authority */ + u16_t tai_utc_delta : 15; /* Current difference between TAI and UTC in seconds */ + u8_t time_zone_offset; /* The local time zone offset in 15-minute increments */ +} esp_ble_mesh_time_set_t; + +typedef struct { + u8_t time_zone_offset_new; /* Upcoming local time zone offset */ + u8_t tai_zone_change[5]; /* TAI Seconds time of the upcoming Time Zone Offset change */ +} esp_ble_mesh_time_zone_set_t; + +typedef struct { + u16_t tai_utc_delta_new : 15; /* Upcoming difference between TAI and UTC in seconds */ + u16_t padding : 1; /* Always 0b0. Other values are Prohibited. */ + u8_t tai_delta_change[5]; /* TAI Seconds time of the upcoming TAI-UTC Delta change */ +} esp_ble_mesh_tai_utc_delta_set_t; + +typedef struct { + u8_t time_role; /* The Time Role for the element */ +} esp_ble_mesh_time_role_set_t; + +typedef struct { + u16_t scene_number; /* The number of scenes to be stored */ +} esp_ble_mesh_scene_store_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + u16_t scene_number; /* The number of scenes to be recalled */ + u8_t tid; /* Transaction ID */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +} esp_ble_mesh_scene_recall_t; + +typedef struct { + u16_t scene_number; /* The number of scenes to be deleted */ +} esp_ble_mesh_scene_delete_t; + +typedef struct { + u8_t index; /* Index of the Schedule Register entry to get */ +} esp_ble_mesh_scheduler_act_get_t; + +typedef struct { + u64_t index : 4; /* Index of the Schedule Register entry to set */ + u64_t year : 7; /* Scheduled year for the action */ + u64_t month : 12; /* Scheduled month for the action */ + u64_t day : 5; /* Scheduled day of the month for the action */ + u64_t hour : 5; /* Scheduled hour for the action */ + u64_t minute : 6; /* Scheduled minute for the action */ + u64_t second : 6; /* Scheduled second for the action */ + u64_t day_of_week : 7; /* Schedule days of the week for the action */ + u64_t action : 4; /* Action to be performed at the scheduled time */ + u64_t trans_time : 8; /* Transition time for this action */ + u16_t scene_number; /* Transition time for this action */ +} esp_ble_mesh_scheduler_act_set_t; + +/** + * @brief For + * + * the get_state parameter in the esp_ble_mesh_time_scene_client_get_state function should be set to NULL. + */ +typedef union { + esp_ble_mesh_scheduler_act_get_t scheduler_act_get; /*!< For ESP_BLE_MESH_MODEL_OP_SCHEDULER_ACT_GET */ +} esp_ble_mesh_time_scene_client_get_state_t; + +typedef union { + esp_ble_mesh_time_set_t time_set; /*!< For ESP_BLE_MESH_MODEL_OP_TIME_SET */ + esp_ble_mesh_time_zone_set_t time_zone_set; /*!< For ESP_BLE_MESH_MODEL_OP_TIME_ZONE_SET */ + esp_ble_mesh_tai_utc_delta_set_t tai_utc_delta_set; /*!< For ESP_BLE_MESH_MODEL_OP_TAI_UTC_DELTA_SET */ + esp_ble_mesh_time_role_set_t time_role_set; /*!< For ESP_BLE_MESH_MODEL_OP_TIME_ROLE_SET */ + esp_ble_mesh_scene_store_t scene_store; /*!< For ESP_BLE_MESH_MODEL_OP_SCENE_STORE & ESP_BLE_MESH_MODEL_OP_SCENE_STORE_UNACK */ + esp_ble_mesh_scene_recall_t scene_recall; /*!< For ESP_BLE_MESH_MODEL_OP_SCENE_RECALL & ESP_BLE_MESH_MODEL_OP_SCENE_RECALL_UNACK */ + esp_ble_mesh_scene_delete_t scene_delete; /*!< For ESP_BLE_MESH_MODEL_OP_SCENE_DELETE & ESP_BLE_MESH_MODEL_OP_SCENE_DELETE_UNACK */ + esp_ble_mesh_scheduler_act_set_t scheduler_act_set; /*!< For ESP_BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET & ESP_BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET_UNACK */ +} esp_ble_mesh_time_scene_client_set_state_t; + +/** + * @brief Bluetooth Mesh Time Scene Client Model Get and Set callback parameters structure. + */ + +typedef struct { + u8_t tai_seconds[5]; /* The current TAI time in seconds */ + u8_t sub_second; /* The sub-second time in units of 1/256 second */ + u8_t uncertainty; /* The estimated uncertainty in 10-millisecond steps */ + u16_t time_authority : 1; /* 0 = No Time Authority, 1 = Time Authority */ + u16_t tai_utc_delta : 15; /* Current difference between TAI and UTC in seconds */ + u8_t time_zone_offset; /* The local time zone offset in 15-minute increments */ +} esp_ble_mesh_time_status_cb_t; + +typedef struct { + u8_t time_zone_offset_curr; /* Current local time zone offset */ + u8_t time_zone_offset_new; /* Upcoming local time zone offset */ + u8_t tai_zone_change[5]; /* TAI Seconds time of the upcoming Time Zone Offset change */ +} esp_ble_mesh_time_zone_status_cb_t; + +typedef struct { + u16_t tai_utc_delta_curr : 15; /* Current difference between TAI and UTC in seconds */ + u16_t padding_1 : 1; /* Always 0b0. Other values are Prohibited. */ + u16_t tai_utc_delta_new : 15; /* Upcoming difference between TAI and UTC in seconds */ + u16_t padding_2 : 1; /* Always 0b0. Other values are Prohibited. */ + u8_t tai_delta_change[5]; /* TAI Seconds time of the upcoming TAI-UTC Delta change */ +} esp_ble_mesh_tai_utc_delta_status_cb_t; + +typedef struct { + u8_t time_role; /* The Time Role for the element */ +} esp_ble_mesh_time_role_status_cb_t; + +typedef struct { + bool op_en; /* Indicate if optional parameters are included */ + u8_t status_code; /* Status code of the last operation */ + u16_t current_scene; /* Scene Number of the current scene */ + u16_t target_scene; /* Scene Number of the target scene (optional) */ + u8_t remain_time; /* Time to complete state transition (C.1) */ +} esp_ble_mesh_scene_status_cb_t; + +typedef struct { + u8_t status_code; /* Status code for the previous operation */ + u16_t current_scene; /* Scene Number of the current scene */ + struct net_buf_simple *scenes; /* A list of scenes stored within an element */ +} esp_ble_mesh_scene_register_status_cb_t; + +typedef struct { + u16_t schedules; /* Bit field indicating defined Actions in the Schedule Register */ +} esp_ble_mesh_scheduler_status_cb_t; + +typedef struct { + u64_t index : 4; /* Enumerates (selects) a Schedule Register entry */ + u64_t year : 7; /* Scheduled year for the action */ + u64_t month : 12; /* Scheduled month for the action */ + u64_t day : 5; /* Scheduled day of the month for the action */ + u64_t hour : 5; /* Scheduled hour for the action */ + u64_t minute : 6; /* Scheduled minute for the action */ + u64_t second : 6; /* Scheduled second for the action */ + u64_t day_of_week : 7; /* Schedule days of the week for the action */ + u64_t action : 4; /* Action to be performed at the scheduled time */ + u64_t trans_time : 8; /* Transition time for this action */ + u16_t scene_number; /* Transition time for this action */ +} esp_ble_mesh_scheduler_act_status_cb_t; + +typedef union { + esp_ble_mesh_time_status_cb_t time_status; /*!< For ESP_BLE_MESH_MODEL_OP_TIME_STATUS */ + esp_ble_mesh_time_zone_status_cb_t time_zone_status; /*!< For ESP_BLE_MESH_MODEL_OP_TIME_ZONE_STATUS */ + esp_ble_mesh_tai_utc_delta_status_cb_t tai_utc_delta_status; /*!< For ESP_BLE_MESH_MODEL_OP_TAI_UTC_DELTA_STATUS */ + esp_ble_mesh_time_role_status_cb_t time_role_status; /*!< For ESP_BLE_MESH_MODEL_OP_TIME_ROLE_STATUS */ + esp_ble_mesh_scene_status_cb_t scene_status; /*!< For ESP_BLE_MESH_MODEL_OP_SCENE_STATUS */ + esp_ble_mesh_scene_register_status_cb_t scene_register_status; /*!< For ESP_BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS */ + esp_ble_mesh_scheduler_status_cb_t scheduler_status; /*!< For ESP_BLE_MESH_MODEL_OP_SCHEDULER_STATUS */ + esp_ble_mesh_scheduler_act_status_cb_t scheduler_act_status; /*!< For ESP_BLE_MESH_MODEL_OP_SCHEDULER_ACT_STATUS */ +} esp_ble_mesh_time_scene_client_status_cb_t; + +typedef struct { + int error_code; /*!< Appropriate error code */ + esp_ble_mesh_client_common_param_t *params; /*!< The client common parameters. */ + esp_ble_mesh_time_scene_client_status_cb_t status_cb; /*!< The scene status message callback values */ +} esp_ble_mesh_time_scene_client_cb_param_t; + +typedef enum { + ESP_BLE_MESH_TIME_SCENE_CLIENT_GET_STATE_EVT, + ESP_BLE_MESH_TIME_SCENE_CLIENT_SET_STATE_EVT, + ESP_BLE_MESH_TIME_SCENE_CLIENT_PUBLISH_EVT, + ESP_BLE_MESH_TIME_SCENE_CLIENT_TIMEOUT_EVT, + ESP_BLE_MESH_TIME_SCENE_CLIENT_EVT_MAX, +} esp_ble_mesh_time_scene_client_cb_event_t; + +/** + * @brief Bluetooth Mesh Time Scene Client Model function. + */ + +/** @brief: event, event code of Time Scene Client Model events; param, parameters of Time Scene Client Model events */ +typedef void (* esp_ble_mesh_time_scene_client_cb_t)(esp_ble_mesh_time_scene_client_cb_event_t event, + esp_ble_mesh_time_scene_client_cb_param_t *param); + +/** + * @brief Register BLE Mesh Time Scene Client Model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_time_scene_client_callback(esp_ble_mesh_time_scene_client_cb_t callback); + +/** + * @brief Get the value of Time Scene Server Model states using the Time Scene Client Model get messages. + * + * @note If you want to know the opcodes and corresponding meanings accepted by this API, + * please refer to (@ref esp_ble_mesh_time_scene_message_opcode_t). + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] get_state: Pointer to time scene get message value. + * Shall not be set to NULL. + * + * @return ESP_OK on success or error code otherwise. + */ +esp_err_t esp_ble_mesh_time_scene_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_time_scene_client_get_state_t *get_state); + +/** + * @brief Set the value of Time Scene Server Model states using the Time Scene Client Model set messages. + * + * @note If you want to know the opcodes and corresponding meanings accepted by this API, + * please refer to (@ref esp_ble_mesh_time_scene_message_opcode_t). + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] set_state: Pointer to time scene set message value. + * Shall not be set to NULL. + * + * @return ESP_OK on success or error code otherwise. + */ +esp_err_t esp_ble_mesh_time_scene_client_set_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_time_scene_client_set_state_t *set_state); + +#endif /* _ESP_BLE_MESH_TIME_SCENE_MODEL_API_H_ */ + diff --git a/components/bt/ble_mesh/btc/btc_ble_mesh_config_model.c b/components/bt/ble_mesh/btc/btc_ble_mesh_config_model.c new file mode 100644 index 0000000000..7fe0e0595d --- /dev/null +++ b/components/bt/ble_mesh/btc/btc_ble_mesh_config_model.c @@ -0,0 +1,725 @@ +// Copyright 2017-2018 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 +#include + +#include "btc/btc_manage.h" +#include "osi/allocator.h" + +#include "cfg_cli.h" +#include "mesh_common.h" +#include "btc_ble_mesh_config_model.h" +#include "esp_ble_mesh_config_model_api.h" + +#define CID_NVAL 0xffff + +extern s32_t config_msg_timeout; + +static inline void btc_ble_mesh_cfg_client_cb_to_app(esp_ble_mesh_cfg_client_cb_event_t event, + esp_ble_mesh_cfg_client_cb_param_t *param) +{ + esp_ble_mesh_cfg_client_cb_t btc_mesh_cb = (esp_ble_mesh_cfg_client_cb_t)btc_profile_cb_get(BTC_PID_CFG_CLIENT); + if (btc_mesh_cb) { + btc_mesh_cb(event, param); + } +} + +static inline void btc_ble_mesh_cfg_server_cb_to_app(esp_ble_mesh_cfg_server_cb_event_t event, + esp_ble_mesh_cfg_server_cb_param_t *param) +{ + esp_ble_mesh_cfg_server_cb_t btc_mesh_cb = (esp_ble_mesh_cfg_server_cb_t)btc_profile_cb_get(BTC_PID_CFG_SERVER); + if (btc_mesh_cb) { + btc_mesh_cb(event, param); + } +} + +void btc_ble_mesh_cfg_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_cfg_client_args_t *dst = (btc_ble_mesh_cfg_client_args_t *)p_dest; + btc_ble_mesh_cfg_client_args_t *src = (btc_ble_mesh_cfg_client_args_t *)p_src; + + if (!msg || !dst || !src) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_CONFIG_CLIENT_GET_STATE: { + dst->cfg_client_get_state.params = (esp_ble_mesh_client_common_param_t *)osi_malloc(sizeof(esp_ble_mesh_client_common_param_t)); + dst->cfg_client_get_state.get_state = (esp_ble_mesh_cfg_client_get_state_t *)osi_malloc(sizeof(esp_ble_mesh_cfg_client_get_state_t)); + if (dst->cfg_client_get_state.params && dst->cfg_client_get_state.get_state) { + memcpy(dst->cfg_client_get_state.params, src->cfg_client_get_state.params, + sizeof(esp_ble_mesh_client_common_param_t)); + memcpy(dst->cfg_client_get_state.get_state, src->cfg_client_get_state.get_state, + sizeof(esp_ble_mesh_cfg_client_get_state_t)); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + break; + } + case BTC_BLE_MESH_ACT_CONFIG_CLIENT_SET_STATE: { + dst->cfg_client_set_state.params = (esp_ble_mesh_client_common_param_t *)osi_malloc(sizeof(esp_ble_mesh_client_common_param_t)); + dst->cfg_client_set_state.set_state = (esp_ble_mesh_cfg_client_set_state_t *)osi_malloc(sizeof(esp_ble_mesh_cfg_client_set_state_t)); + if (dst->cfg_client_set_state.params && dst->cfg_client_set_state.set_state) { + memcpy(dst->cfg_client_set_state.params, src->cfg_client_set_state.params, + sizeof(esp_ble_mesh_client_common_param_t)); + memcpy(dst->cfg_client_set_state.set_state, src->cfg_client_set_state.set_state, + sizeof(esp_ble_mesh_cfg_client_set_state_t)); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + break; + } + default: + LOG_DEBUG("%s, Unknown deep copy act %d", __func__, msg->act); + break; + } +} + +static void btc_ble_mesh_cfg_client_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_cfg_client_cb_param_t *p_dest_data = (esp_ble_mesh_cfg_client_cb_param_t *)p_dest; + esp_ble_mesh_cfg_client_cb_param_t *p_src_data = (esp_ble_mesh_cfg_client_cb_param_t *)p_src; + u32_t opcode; + u16_t length; + + if (!msg || !p_src_data || !p_dest_data) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case ESP_BLE_MESH_CFG_CLIENT_GET_STATE_EVT: + case ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT: + case ESP_BLE_MESH_CFG_CLIENT_PUBLISH_EVT: + if (p_src_data->params) { + opcode = p_src_data->params->opcode; + switch (opcode) { + case OP_DEV_COMP_DATA_GET: + case OP_DEV_COMP_DATA_STATUS: + if (p_src_data->status_cb.comp_data_status.composition_data) { + length = p_src_data->status_cb.comp_data_status.composition_data->len; + p_dest_data->status_cb.comp_data_status.composition_data = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.comp_data_status.composition_data) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.comp_data_status.composition_data, + p_src_data->status_cb.comp_data_status.composition_data->data, + p_src_data->status_cb.comp_data_status.composition_data->len); + } + break; + case OP_MOD_SUB_GET: + case OP_MOD_SUB_GET_VND: + case OP_MOD_SUB_LIST: + case OP_MOD_SUB_LIST_VND: + if (p_src_data->status_cb.model_sub_list.sub_addr) { + length = p_src_data->status_cb.model_sub_list.sub_addr->len; + p_dest_data->status_cb.model_sub_list.sub_addr = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.model_sub_list.sub_addr) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.model_sub_list.sub_addr, + p_src_data->status_cb.model_sub_list.sub_addr->data, + p_src_data->status_cb.model_sub_list.sub_addr->len); + } + break; + case OP_NET_KEY_GET: + case OP_NET_KEY_LIST: + if (p_src_data->status_cb.netkey_list.net_idx) { + length = p_src_data->status_cb.netkey_list.net_idx->len; + p_dest_data->status_cb.netkey_list.net_idx = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.netkey_list.net_idx) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.netkey_list.net_idx, + p_src_data->status_cb.netkey_list.net_idx->data, + p_src_data->status_cb.netkey_list.net_idx->len); + } + break; + case OP_APP_KEY_GET: + case OP_APP_KEY_LIST: + if (p_src_data->status_cb.appkey_list.app_idx) { + length = p_src_data->status_cb.appkey_list.app_idx->len; + p_dest_data->status_cb.appkey_list.app_idx = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.appkey_list.app_idx) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.appkey_list.app_idx, + p_src_data->status_cb.appkey_list.app_idx->data, + p_src_data->status_cb.appkey_list.app_idx->len); + } + break; + case OP_SIG_MOD_APP_GET: + case OP_VND_MOD_APP_GET: + case OP_SIG_MOD_APP_LIST: + case OP_VND_MOD_APP_LIST: + if (p_src_data->status_cb.model_app_list.app_idx) { + length = p_src_data->status_cb.model_app_list.app_idx->len; + p_dest_data->status_cb.model_app_list.app_idx = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.model_app_list.app_idx) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.model_app_list.app_idx, + p_src_data->status_cb.model_app_list.app_idx->data, + p_src_data->status_cb.model_app_list.app_idx->len); + } + break; + default: + break; + } + } + case ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT: + if (p_src_data->params) { + p_dest_data->params = osi_malloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (p_dest_data->params) { + memcpy(p_dest_data->params, p_src_data->params, sizeof(esp_ble_mesh_client_common_param_t)); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + } + break; + default: + break; + } +} + +static void btc_ble_mesh_cfg_client_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_cfg_client_cb_param_t *arg = NULL; + u32_t opcode; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_cfg_client_cb_param_t *)(msg->arg); + + switch (msg->act) { + case ESP_BLE_MESH_CFG_CLIENT_GET_STATE_EVT: + case ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT: + case ESP_BLE_MESH_CFG_CLIENT_PUBLISH_EVT: + if (arg->params) { + opcode = arg->params->opcode; + switch (opcode) { + case OP_DEV_COMP_DATA_GET: + case OP_DEV_COMP_DATA_STATUS: + bt_mesh_free_buf(arg->status_cb.comp_data_status.composition_data); + break; + case OP_MOD_SUB_GET: + case OP_MOD_SUB_GET_VND: + case OP_MOD_SUB_LIST: + case OP_MOD_SUB_LIST_VND: + bt_mesh_free_buf(arg->status_cb.model_sub_list.sub_addr); + break; + case OP_NET_KEY_GET: + case OP_NET_KEY_LIST: + bt_mesh_free_buf(arg->status_cb.netkey_list.net_idx); + break; + case OP_APP_KEY_GET: + case OP_APP_KEY_LIST: + bt_mesh_free_buf(arg->status_cb.appkey_list.app_idx); + break; + case OP_SIG_MOD_APP_GET: + case OP_VND_MOD_APP_GET: + case OP_SIG_MOD_APP_LIST: + case OP_VND_MOD_APP_LIST: + bt_mesh_free_buf(arg->status_cb.model_app_list.app_idx); + break; + default: + break; + } + } + case ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT: + if (arg->params) { + osi_free(arg->params); + } + break; + default: + break; + } +} + +void btc_ble_mesh_cfg_client_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_cfg_client_args_t *arg = NULL; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_cfg_client_args_t *)(msg->arg); + + switch (msg->act) { + case BTC_BLE_MESH_ACT_CONFIG_CLIENT_GET_STATE: + if (arg->cfg_client_get_state.params) { + osi_free(arg->cfg_client_get_state.params); + } + if (arg->cfg_client_get_state.get_state) { + osi_free(arg->cfg_client_get_state.get_state); + } + break; + case BTC_BLE_MESH_ACT_CONFIG_CLIENT_SET_STATE: + if (arg->cfg_client_set_state.params) { + osi_free(arg->cfg_client_set_state.params); + } + if (arg->cfg_client_set_state.set_state) { + osi_free(arg->cfg_client_set_state.set_state); + } + break; + default: + break; + } + + return; +} + +static void btc_mesh_cfg_client_callback(esp_ble_mesh_cfg_client_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + LOG_DEBUG("%s", __func__); + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_CFG_CLIENT; + msg.act = act; + + btc_transfer_context(&msg, cb_params, + sizeof(esp_ble_mesh_cfg_client_cb_param_t), btc_ble_mesh_cfg_client_copy_req_data); +} + +void bt_mesh_callback_config_status_to_btc(u32_t opcode, u8_t evt_type, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const u8_t *val, size_t len) +{ + esp_ble_mesh_cfg_client_cb_param_t cb_params = {0}; + esp_ble_mesh_client_common_param_t params = {0}; + size_t length; + uint8_t act; + + if (!model || !ctx) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (evt_type) { + case 0x00: + act = ESP_BLE_MESH_CFG_CLIENT_GET_STATE_EVT; + break; + case 0x01: + act = ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT; + break; + case 0x02: + act = ESP_BLE_MESH_CFG_CLIENT_PUBLISH_EVT; + break; + case 0x03: + act = ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT; + break; + default: + LOG_ERROR("%s, Unknown config client event type %d", __func__, evt_type); + return; + } + + params.opcode = opcode; + params.model = (esp_ble_mesh_model_t *)model; + params.ctx.net_idx = ctx->net_idx; + params.ctx.app_idx = ctx->app_idx; + params.ctx.addr = ctx->addr; + params.ctx.recv_ttl = ctx->recv_ttl; + params.ctx.recv_op = ctx->recv_op; + params.ctx.recv_dst = ctx->recv_dst; + + cb_params.error_code = 0; + cb_params.params = ¶ms; + + if (val && len) { + length = (len <= sizeof(cb_params.status_cb)) ? len : sizeof(cb_params.status_cb); + memcpy(&cb_params.status_cb, val, length); + } + + btc_mesh_cfg_client_callback(&cb_params, act); +} + + +void btc_mesh_cfg_client_publish_callback(u32_t opcode, struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) +{ + if (!model || !ctx || !buf) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + bt_mesh_callback_config_status_to_btc(opcode, 0x02, model, ctx, buf->data, buf->len); +} + +void btc_mesh_cfg_client_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_cfg_client_cb_param_t cfg_client_cb = {0}; + btc_ble_mesh_cfg_client_args_t *arg = NULL; + bt_mesh_role_param_t role_param = {0}; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_cfg_client_args_t *)(msg->arg); + + switch (msg->act) { + case BTC_BLE_MESH_ACT_CONFIG_CLIENT_GET_STATE: { + cfg_client_cb.params = arg->cfg_client_get_state.params; + role_param.model = (struct bt_mesh_model *)cfg_client_cb.params->model; + role_param.role = cfg_client_cb.params->msg_role; + if (bt_mesh_set_model_role(&role_param)) { + LOG_ERROR("%s, Failed to set model role", __func__); + return; + } + btc_ble_mesh_config_client_get_state(arg->cfg_client_get_state.params, + arg->cfg_client_get_state.get_state, + &cfg_client_cb); + if (cfg_client_cb.error_code) { + btc_mesh_cfg_client_callback(&cfg_client_cb, ESP_BLE_MESH_CFG_CLIENT_GET_STATE_EVT); + } + break; + } + case BTC_BLE_MESH_ACT_CONFIG_CLIENT_SET_STATE: { + cfg_client_cb.params = arg->cfg_client_set_state.params; + role_param.model = (struct bt_mesh_model *)cfg_client_cb.params->model; + role_param.role = cfg_client_cb.params->msg_role; + if (bt_mesh_set_model_role(&role_param)) { + LOG_ERROR("%s, Failed to set model role", __func__); + return; + } + btc_ble_mesh_config_client_set_state(arg->cfg_client_set_state.params, + arg->cfg_client_set_state.set_state, + &cfg_client_cb); + if (cfg_client_cb.error_code) { + btc_mesh_cfg_client_callback(&cfg_client_cb, ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT); + } + break; + } + default: + break; + } + + btc_ble_mesh_cfg_client_arg_deep_free(msg); +} + +void btc_mesh_cfg_client_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_cfg_client_cb_param_t *param = NULL; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + param = (esp_ble_mesh_cfg_client_cb_param_t *)(msg->arg); + + if (msg->act < ESP_BLE_MESH_CFG_CLIENT_EVT_MAX) { + btc_ble_mesh_cfg_client_cb_to_app(msg->act, param); + } else { + LOG_ERROR("%s, Unknown msg->act = %d", __func__, msg->act); + } + + btc_ble_mesh_cfg_client_free_req_data(msg); +} + +int btc_ble_mesh_config_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_cfg_client_get_state_t *get_state, + esp_ble_mesh_cfg_client_cb_param_t *cfg_client_cb) +{ + struct bt_mesh_msg_ctx ctx = {0}; + + if (!params || !cfg_client_cb) { + LOG_ERROR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + ctx.net_idx = params->ctx.net_idx; + ctx.app_idx = BLE_MESH_KEY_DEV; + ctx.addr = params->ctx.addr; + ctx.send_rel = params->ctx.send_rel; + ctx.send_ttl = params->ctx.send_ttl; + + config_msg_timeout = params->msg_timeout; + + switch (params->opcode) { + case ESP_BLE_MESH_MODEL_OP_BEACON_GET: + return (cfg_client_cb->error_code = bt_mesh_cfg_beacon_get(&ctx)); + case ESP_BLE_MESH_MODEL_OP_DEFAULT_TTL_GET: + return (cfg_client_cb->error_code = bt_mesh_cfg_ttl_get(&ctx)); + case ESP_BLE_MESH_MODEL_OP_FRIEND_GET: + return (cfg_client_cb->error_code = bt_mesh_cfg_friend_get(&ctx)); + case ESP_BLE_MESH_MODEL_OP_GATT_PROXY_GET: + return (cfg_client_cb->error_code = bt_mesh_cfg_gatt_proxy_get(&ctx)); + case ESP_BLE_MESH_MODEL_OP_RELAY_GET: + return (cfg_client_cb->error_code = bt_mesh_cfg_relay_get(&ctx)); + case ESP_BLE_MESH_MODEL_OP_MODEL_PUB_GET: + return (cfg_client_cb->error_code = + bt_mesh_cfg_mod_pub_get(&ctx, get_state->model_pub_get.element_addr, get_state->model_pub_get.model_id, + get_state->model_pub_get.company_id)); + case ESP_BLE_MESH_MODEL_OP_HEARTBEAT_PUB_GET: + return (cfg_client_cb->error_code = bt_mesh_cfg_hb_pub_get(&ctx)); + case ESP_BLE_MESH_MODEL_OP_HEARTBEAT_SUB_GET: + return (cfg_client_cb->error_code = bt_mesh_cfg_hb_sub_get(&ctx)); + case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET: + return (cfg_client_cb->error_code = bt_mesh_cfg_comp_data_get(&ctx, get_state->comp_data_get.page)); + case ESP_BLE_MESH_MODEL_OP_SIG_MODEL_SUB_GET: + return (cfg_client_cb->error_code = + bt_mesh_cfg_mod_sub_get(&ctx, get_state->sig_model_sub_get.element_addr, get_state->sig_model_sub_get.model_id)); + case ESP_BLE_MESH_MODEL_OP_VENDOR_MODEL_SUB_GET: + return (cfg_client_cb->error_code = + bt_mesh_cfg_mod_sub_get_vnd(&ctx, get_state->vnd_model_sub_get.element_addr, + get_state->vnd_model_sub_get.model_id, get_state->vnd_model_sub_get.company_id)); + case ESP_BLE_MESH_MODEL_OP_NET_KEY_GET: + return (cfg_client_cb->error_code = bt_mesh_cfg_net_key_get(&ctx)); + case ESP_BLE_MESH_MODEL_OP_APP_KEY_GET: + return (cfg_client_cb->error_code = bt_mesh_cfg_app_key_get(&ctx, get_state->app_key_get.net_idx)); + case ESP_BLE_MESH_MODEL_OP_NODE_IDENTITY_GET: + return (cfg_client_cb->error_code = bt_mesh_cfg_node_identity_get(&ctx, get_state->node_identity_get.net_idx)); + case ESP_BLE_MESH_MODEL_OP_SIG_MODEL_APP_GET: + return (cfg_client_cb->error_code = + bt_mesh_cfg_mod_app_get(&ctx, get_state->sig_model_app_get.element_addr, get_state->sig_model_app_get.model_id)); + case ESP_BLE_MESH_MODEL_OP_VENDOR_MODEL_APP_GET: + return (cfg_client_cb->error_code = + bt_mesh_cfg_mod_app_get_vnd(&ctx, get_state->vnd_model_app_get.element_addr, + get_state->vnd_model_app_get.model_id, get_state->vnd_model_app_get.company_id)); + case ESP_BLE_MESH_MODEL_OP_KEY_REFRESH_PHASE_GET: + return (cfg_client_cb->error_code = bt_mesh_cfg_kr_phase_get(&ctx, get_state->kr_phase_get.net_idx)); + case ESP_BLE_MESH_MODEL_OP_LPN_POLLTIMEOUT_GET: + return (cfg_client_cb->error_code = bt_mesh_cfg_lpn_timeout_get(&ctx, get_state->lpn_pollto_get.lpn_addr)); + case ESP_BLE_MESH_MODEL_OP_NETWORK_TRANSMIT_GET: + return (cfg_client_cb->error_code = bt_mesh_cfg_net_transmit_get(&ctx)); + default: + BT_WARN("%s, Invalid opcode 0x%x", __func__, params->opcode); + return (cfg_client_cb->error_code = -EINVAL); + } + + return 0; +} + +int btc_ble_mesh_config_client_set_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_cfg_client_set_state_t *set_state, + esp_ble_mesh_cfg_client_cb_param_t *cfg_client_cb) +{ + struct bt_mesh_msg_ctx ctx = {0}; + + if (!params || !set_state || !cfg_client_cb) { + LOG_ERROR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + ctx.net_idx = params->ctx.net_idx; + ctx.app_idx = BLE_MESH_KEY_DEV; + ctx.addr = params->ctx.addr; + ctx.send_rel = params->ctx.send_rel; + ctx.send_ttl = params->ctx.send_ttl; + + config_msg_timeout = params->msg_timeout; + + switch (params->opcode) { + case ESP_BLE_MESH_MODEL_OP_BEACON_SET: + return (cfg_client_cb->error_code = bt_mesh_cfg_beacon_set(&ctx, set_state->beacon_set.beacon)); + case ESP_BLE_MESH_MODEL_OP_DEFAULT_TTL_SET: + return (cfg_client_cb->error_code = bt_mesh_cfg_ttl_set(&ctx, set_state->default_ttl_set.ttl)); + case ESP_BLE_MESH_MODEL_OP_FRIEND_SET: + return (cfg_client_cb->error_code = bt_mesh_cfg_friend_set(&ctx, set_state->friend_set.friend_state)); + case ESP_BLE_MESH_MODEL_OP_GATT_PROXY_SET: + return (cfg_client_cb->error_code = bt_mesh_cfg_gatt_proxy_set(&ctx, set_state->gatt_proxy_set.gatt_proxy)); + case ESP_BLE_MESH_MODEL_OP_RELAY_SET: + return (cfg_client_cb->error_code = + bt_mesh_cfg_relay_set(&ctx, set_state->relay_set.relay, set_state->relay_set.relay_retransmit)); + case ESP_BLE_MESH_MODEL_OP_NET_KEY_ADD: + return (cfg_client_cb->error_code = + bt_mesh_cfg_net_key_add(&ctx, set_state->net_key_add.net_idx, &set_state->net_key_add.net_key[0])); + case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: + return (cfg_client_cb->error_code = + bt_mesh_cfg_app_key_add(&ctx, set_state->app_key_add.net_idx, + set_state->app_key_add.app_idx, &set_state->app_key_add.app_key[0])); + case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND: + return (cfg_client_cb->error_code = + bt_mesh_cfg_mod_app_bind(&ctx, set_state->model_app_bind.element_addr, set_state->model_app_bind.model_app_idx, + set_state->model_app_bind.model_id, set_state->model_app_bind.company_id)); + case ESP_BLE_MESH_MODEL_OP_MODEL_PUB_SET: { + struct bt_mesh_cfg_mod_pub model_pub = { + .addr = set_state->model_pub_set.publish_addr, + .app_idx = set_state->model_pub_set.publish_app_idx, + .cred_flag = set_state->model_pub_set.cred_flag, + .ttl = set_state->model_pub_set.publish_ttl, + .period = set_state->model_pub_set.publish_period, + .transmit = set_state->model_pub_set.publish_retransmit, + }; + return (cfg_client_cb->error_code = + bt_mesh_cfg_mod_pub_set(&ctx, set_state->model_pub_set.element_addr, set_state->model_pub_set.model_id, + set_state->model_pub_set.company_id, &model_pub)); + } + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_ADD: + return (cfg_client_cb->error_code = + bt_mesh_cfg_mod_sub_add(&ctx, set_state->model_sub_add.element_addr, set_state->model_sub_add.sub_addr, + set_state->model_sub_add.model_id, set_state->model_sub_add.company_id)); + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_DELETE: + return (cfg_client_cb->error_code = + bt_mesh_cfg_mod_sub_del(&ctx, set_state->model_sub_delete.element_addr, set_state->model_sub_delete.sub_addr, + set_state->model_sub_delete.model_id, set_state->model_sub_delete.company_id)); + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_OVERWRITE: + return (cfg_client_cb->error_code = + bt_mesh_cfg_mod_sub_overwrite(&ctx, set_state->model_sub_overwrite.element_addr, set_state->model_sub_overwrite.sub_addr, + set_state->model_sub_overwrite.model_id, set_state->model_sub_overwrite.company_id)); + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_ADD: + return (cfg_client_cb->error_code = + bt_mesh_cfg_mod_sub_va_add(&ctx, set_state->model_sub_va_add.element_addr, &set_state->model_sub_va_add.label_uuid[0], + set_state->model_sub_va_add.model_id, set_state->model_sub_va_add.company_id)); + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_OVERWRITE: + return (cfg_client_cb->error_code = + bt_mesh_cfg_mod_sub_va_overwrite(&ctx, set_state->model_sub_va_overwrite.element_addr, &set_state->model_sub_va_overwrite.label_uuid[0], + set_state->model_sub_va_overwrite.model_id, set_state->model_sub_va_overwrite.company_id)); + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_DELETE: + return (cfg_client_cb->error_code = + bt_mesh_cfg_mod_sub_va_del(&ctx, set_state->model_sub_va_delete.element_addr, &set_state->model_sub_va_delete.label_uuid[0], + set_state->model_sub_va_delete.model_id, set_state->model_sub_va_delete.company_id)); + case ESP_BLE_MESH_MODEL_OP_HEARTBEAT_SUB_SET: + return (cfg_client_cb->error_code = + bt_mesh_cfg_hb_sub_set(&ctx, (struct bt_mesh_cfg_hb_sub *)&set_state->heartbeat_sub_set)); + case ESP_BLE_MESH_MODEL_OP_HEARTBEAT_PUB_SET: + return (cfg_client_cb->error_code = + bt_mesh_cfg_hb_pub_set(&ctx, (const struct bt_mesh_cfg_hb_pub *)&set_state->heartbeat_pub_set)); + case ESP_BLE_MESH_MODEL_OP_NODE_RESET: + return (cfg_client_cb->error_code = bt_mesh_cfg_node_reset(&ctx)); + case ESP_BLE_MESH_MODEL_OP_MODEL_PUB_VIRTUAL_ADDR_SET: { + struct bt_mesh_cfg_mod_pub model_pub = { + .app_idx = set_state->model_pub_va_set.publish_app_idx, + .cred_flag = set_state->model_pub_va_set.cred_flag, + .ttl = set_state->model_pub_va_set.publish_ttl, + .period = set_state->model_pub_va_set.publish_period, + .transmit = set_state->model_pub_va_set.publish_retransmit, + }; + return (cfg_client_cb->error_code = + bt_mesh_cfg_mod_pub_va_set(&ctx, set_state->model_pub_va_set.element_addr, set_state->model_pub_va_set.model_id, + set_state->model_pub_va_set.company_id, set_state->model_pub_va_set.label_uuid, &model_pub)); + } + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_DELETE_ALL: + return (cfg_client_cb->error_code = + bt_mesh_cfg_mod_sub_del_all(&ctx, set_state->model_sub_delete_all.element_addr, + set_state->model_sub_delete_all.model_id, set_state->model_sub_delete_all.company_id)); + case ESP_BLE_MESH_MODEL_OP_NET_KEY_UPDATE: + return (cfg_client_cb->error_code = + bt_mesh_cfg_net_key_update(&ctx, set_state->net_key_update.net_idx, set_state->net_key_update.net_key)); + case ESP_BLE_MESH_MODEL_OP_NET_KEY_DELETE: + return (cfg_client_cb->error_code = + bt_mesh_cfg_net_key_delete(&ctx, set_state->net_key_delete.net_idx)); + case ESP_BLE_MESH_MODEL_OP_APP_KEY_UPDATE: + return (cfg_client_cb->error_code = + bt_mesh_cfg_app_key_update(&ctx, set_state->app_key_update.net_idx, set_state->app_key_update.app_idx, + set_state->app_key_update.app_key)); + case ESP_BLE_MESH_MODEL_OP_APP_KEY_DELETE: + return (cfg_client_cb->error_code = + bt_mesh_cfg_app_key_delete(&ctx, set_state->app_key_delete.net_idx, set_state->app_key_delete.app_idx)); + case ESP_BLE_MESH_MODEL_OP_NODE_IDENTITY_SET: + return (cfg_client_cb->error_code = + bt_mesh_cfg_node_identity_set(&ctx, set_state->node_identity_set.net_idx, set_state->node_identity_set.identity)); + case ESP_BLE_MESH_MODEL_OP_MODEL_APP_UNBIND: + return (cfg_client_cb->error_code = + bt_mesh_cfg_mod_app_unbind(&ctx, set_state->model_app_unbind.element_addr, set_state->model_app_unbind.model_app_idx, + set_state->model_app_unbind.model_id, set_state->model_app_unbind.company_id)); + case ESP_BLE_MESH_MODEL_OP_KEY_REFRESH_PHASE_SET: + return (cfg_client_cb->error_code = + bt_mesh_cfg_kr_phase_set(&ctx, set_state->kr_phase_set.net_idx, set_state->kr_phase_set.transition)); + case ESP_BLE_MESH_MODEL_OP_NETWORK_TRANSMIT_SET: + return (cfg_client_cb->error_code = + bt_mesh_cfg_net_transmit_set(&ctx, set_state->net_transmit_set.net_transmit)); + default: + BT_WARN("%s, Invalid opcode 0x%x", __func__, params->opcode); + return (cfg_client_cb->error_code = -EINVAL); + } + + return 0; +} + +static void btc_mesh_cfg_server_callback(esp_ble_mesh_cfg_server_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + LOG_DEBUG("%s", __func__); + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_CFG_SERVER; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_cfg_server_cb_param_t), NULL); +} + +void bt_mesh_callback_cfg_server_event_to_btc(u8_t evt_type, struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const u8_t *val, size_t len) +{ + esp_ble_mesh_cfg_server_cb_param_t cb_params = {0}; + size_t length; + uint8_t act; + + if (!model || !ctx) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (evt_type) { + case 0x00: + act = ESP_BLE_MESH_CFG_SERVER_RECV_MSG_EVT; + break; + default: + LOG_ERROR("%s, Unknown config server event type %d", __func__, evt_type); + return; + } + + cb_params.model = (esp_ble_mesh_model_t *)model; + cb_params.ctx.net_idx = ctx->net_idx; + cb_params.ctx.app_idx = ctx->app_idx; + cb_params.ctx.addr = ctx->addr; + cb_params.ctx.recv_ttl = ctx->recv_ttl; + cb_params.ctx.recv_op = ctx->recv_op; + cb_params.ctx.recv_dst = ctx->recv_dst; + + if (val && len) { + length = (len <= sizeof(cb_params.status_cb)) ? len : sizeof(cb_params.status_cb); + memcpy(&cb_params.status_cb, val, length); + } + + btc_mesh_cfg_server_callback(&cb_params, act); +} + +void btc_mesh_cfg_server_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_cfg_server_cb_param_t *param = NULL; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + param = (esp_ble_mesh_cfg_server_cb_param_t *)(msg->arg); + + if (msg->act < ESP_BLE_MESH_CFG_SERVER_EVT_MAX) { + btc_ble_mesh_cfg_server_cb_to_app(msg->act, param); + } else { + LOG_ERROR("%s, Unknown msg->act = %d", __func__, msg->act); + } +} diff --git a/components/bt/ble_mesh/btc/btc_ble_mesh_generic_model.c b/components/bt/ble_mesh/btc/btc_ble_mesh_generic_model.c new file mode 100644 index 0000000000..b8fc338169 --- /dev/null +++ b/components/bt/ble_mesh/btc/btc_ble_mesh_generic_model.c @@ -0,0 +1,540 @@ +// Copyright 2017-2018 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 +#include + +#include "btc/btc_manage.h" +#include "osi/allocator.h" + +#include "cfg_cli.h" +#include "btc_ble_mesh_generic_model.h" +#include "esp_ble_mesh_generic_model_api.h" + +static inline void btc_ble_mesh_cb_to_app(esp_ble_mesh_generic_client_cb_event_t event, + esp_ble_mesh_generic_client_cb_param_t *param) +{ + esp_ble_mesh_generic_client_cb_t btc_mesh_cb = (esp_ble_mesh_generic_client_cb_t)btc_profile_cb_get(BTC_PID_GENERIC_CLIENT); + if (btc_mesh_cb) { + btc_mesh_cb(event, param); + } +} + +void btc_ble_mesh_generic_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_generic_client_args_t *dst = (btc_ble_mesh_generic_client_args_t *)p_dest; + btc_ble_mesh_generic_client_args_t *src = (btc_ble_mesh_generic_client_args_t *)p_src; + u32_t opcode; + u16_t length; + + if (!msg || !dst || !src) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_GENERIC_CLIENT_GET_STATE: { + dst->generic_client_get_state.params = (esp_ble_mesh_client_common_param_t *)osi_malloc(sizeof(esp_ble_mesh_client_common_param_t)); + dst->generic_client_get_state.get_state = (esp_ble_mesh_generic_client_get_state_t *)osi_malloc(sizeof(esp_ble_mesh_generic_client_get_state_t)); + if (dst->generic_client_get_state.params && dst->generic_client_get_state.get_state) { + memcpy(dst->generic_client_get_state.params, src->generic_client_get_state.params, + sizeof(esp_ble_mesh_client_common_param_t)); + memcpy(dst->generic_client_get_state.get_state, src->generic_client_get_state.get_state, + sizeof(esp_ble_mesh_generic_client_get_state_t)); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + break; + } + case BTC_BLE_MESH_ACT_GENERIC_CLIENT_SET_STATE: { + dst->generic_client_set_state.params = (esp_ble_mesh_client_common_param_t *)osi_malloc(sizeof(esp_ble_mesh_client_common_param_t)); + dst->generic_client_set_state.set_state = (esp_ble_mesh_generic_client_set_state_t *)osi_malloc(sizeof(esp_ble_mesh_generic_client_set_state_t)); + if (dst->generic_client_set_state.params && dst->generic_client_set_state.set_state) { + memcpy(dst->generic_client_set_state.params, src->generic_client_set_state.params, + sizeof(esp_ble_mesh_client_common_param_t)); + memcpy(dst->generic_client_set_state.set_state, src->generic_client_set_state.set_state, + sizeof(esp_ble_mesh_generic_client_set_state_t)); + + opcode = src->generic_client_set_state.params->opcode; + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET: + if (src->generic_client_set_state.set_state->user_property_set.property_value) { + length = src->generic_client_set_state.set_state->user_property_set.property_value->len; + dst->generic_client_set_state.set_state->user_property_set.property_value = bt_mesh_alloc_buf(length); + if (!dst->generic_client_set_state.set_state->user_property_set.property_value) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(dst->generic_client_set_state.set_state->user_property_set.property_value, + src->generic_client_set_state.set_state->user_property_set.property_value->data, + src->generic_client_set_state.set_state->user_property_set.property_value->len); + } + break; + case ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET: + if (src->generic_client_set_state.set_state->admin_property_set.property_value) { + length = src->generic_client_set_state.set_state->admin_property_set.property_value->len; + dst->generic_client_set_state.set_state->admin_property_set.property_value = bt_mesh_alloc_buf(length); + if (!dst->generic_client_set_state.set_state->admin_property_set.property_value) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(dst->generic_client_set_state.set_state->admin_property_set.property_value, + src->generic_client_set_state.set_state->admin_property_set.property_value->data, + src->generic_client_set_state.set_state->admin_property_set.property_value->len); + } + break; + default: + break; + } + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + break; + } + default: + LOG_DEBUG("%s, Unknown deep copy act %d", __func__, msg->act); + break; + } +} + +static void btc_ble_mesh_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_generic_client_cb_param_t *p_dest_data = (esp_ble_mesh_generic_client_cb_param_t *)p_dest; + esp_ble_mesh_generic_client_cb_param_t *p_src_data = (esp_ble_mesh_generic_client_cb_param_t *)p_src; + u32_t opcode; + u16_t length; + + if (!msg || !p_src_data || !p_dest_data) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT: + case ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT: + case ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT: + if (p_src_data->params) { + opcode = p_src_data->params->opcode; + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_GET: + case ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS: + if (p_src_data->status_cb.user_properties_status.property_ids) { + length = p_src_data->status_cb.user_properties_status.property_ids->len; + p_dest_data->status_cb.user_properties_status.property_ids = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.user_properties_status.property_ids) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.user_properties_status.property_ids, + p_src_data->status_cb.user_properties_status.property_ids->data, + p_src_data->status_cb.user_properties_status.property_ids->len); + } + break; + case ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET: + case ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET: + case ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_STATUS: + if (p_src_data->status_cb.user_property_status.property_value) { + length = p_src_data->status_cb.user_property_status.property_value->len; + p_dest_data->status_cb.user_property_status.property_value = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.user_property_status.property_value) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.user_property_status.property_value, + p_src_data->status_cb.user_property_status.property_value->data, + p_src_data->status_cb.user_property_status.property_value->len); + } + break; + case ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_GET: + case ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_STATUS: + if (p_src_data->status_cb.admin_properties_status.property_ids) { + length = p_src_data->status_cb.admin_properties_status.property_ids->len; + p_dest_data->status_cb.admin_properties_status.property_ids = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.admin_properties_status.property_ids) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.admin_properties_status.property_ids, + p_src_data->status_cb.admin_properties_status.property_ids->data, + p_src_data->status_cb.admin_properties_status.property_ids->len); + } + break; + case ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET: + case ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET: + case ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_STATUS: + if (p_src_data->status_cb.admin_property_status.property_value) { + length = p_src_data->status_cb.admin_property_status.property_value->len; + p_dest_data->status_cb.admin_property_status.property_value = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.admin_property_status.property_value) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.admin_property_status.property_value, + p_src_data->status_cb.admin_property_status.property_value->data, + p_src_data->status_cb.admin_property_status.property_value->len); + } + break; + case ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTIES_GET: + case ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTIES_STATUS: + if (p_src_data->status_cb.manufacturer_properties_status.property_ids) { + length = p_src_data->status_cb.manufacturer_properties_status.property_ids->len; + p_dest_data->status_cb.manufacturer_properties_status.property_ids = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.manufacturer_properties_status.property_ids) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.manufacturer_properties_status.property_ids, + p_src_data->status_cb.manufacturer_properties_status.property_ids->data, + p_src_data->status_cb.manufacturer_properties_status.property_ids->len); + } + break; + case ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTY_GET: + case ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTY_SET: + case ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTY_STATUS: + if (p_src_data->status_cb.manufacturer_property_status.property_value) { + length = p_src_data->status_cb.manufacturer_property_status.property_value->len; + p_dest_data->status_cb.manufacturer_property_status.property_value = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.manufacturer_property_status.property_value) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.manufacturer_property_status.property_value, + p_src_data->status_cb.manufacturer_property_status.property_value->data, + p_src_data->status_cb.manufacturer_property_status.property_value->len); + } + break; + case ESP_BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_GET: + case ESP_BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS: + if (p_src_data->status_cb.client_properties_status.property_ids) { + length = p_src_data->status_cb.client_properties_status.property_ids->len; + p_dest_data->status_cb.client_properties_status.property_ids = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.client_properties_status.property_ids) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.client_properties_status.property_ids, + p_src_data->status_cb.client_properties_status.property_ids->data, + p_src_data->status_cb.client_properties_status.property_ids->len); + } + break; + default: + break; + } + } + case ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT: + if (p_src_data->params) { + p_dest_data->params = osi_malloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (p_dest_data->params) { + memcpy(p_dest_data->params, p_src_data->params, sizeof(esp_ble_mesh_client_common_param_t)); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + } + break; + default: + break; + } +} + +static void btc_ble_mesh_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_generic_client_cb_param_t *arg = NULL; + u32_t opcode; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_generic_client_cb_param_t *)(msg->arg); + + switch (msg->act) { + case ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT: + case ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT: + case ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT: + if (arg->params) { + opcode = arg->params->opcode; + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_GET: + case ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS: + bt_mesh_free_buf(arg->status_cb.user_properties_status.property_ids); + break; + case ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET: + case ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET: + case ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_STATUS: + bt_mesh_free_buf(arg->status_cb.user_property_status.property_value); + break; + case ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_GET: + case ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_STATUS: + bt_mesh_free_buf(arg->status_cb.admin_properties_status.property_ids); + break; + case ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET: + case ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET: + case ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_STATUS: + bt_mesh_free_buf(arg->status_cb.admin_property_status.property_value); + break; + case ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTIES_GET: + case ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTIES_STATUS: + bt_mesh_free_buf(arg->status_cb.manufacturer_properties_status.property_ids); + break; + case ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTY_GET: + case ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTY_SET: + case ESP_BLE_MESH_MODEL_OP_GEN_MANUFACTURER_PROPERTY_STATUS: + bt_mesh_free_buf(arg->status_cb.manufacturer_property_status.property_value); + break; + case ESP_BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_GET: + case ESP_BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS: + bt_mesh_free_buf(arg->status_cb.client_properties_status.property_ids); + break; + default: + break; + } + } + case ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT: + if (arg->params) { + osi_free(arg->params); + } + break; + default: + break; + } +} + +void btc_ble_mesh_generic_client_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_generic_client_args_t *arg = NULL; + u32_t opcode = 0; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_generic_client_args_t *)(msg->arg); + + switch (msg->act) { + case BTC_BLE_MESH_ACT_GENERIC_CLIENT_GET_STATE: + if (arg->generic_client_get_state.params) { + osi_free(arg->generic_client_get_state.params); + } + if (arg->generic_client_get_state.get_state) { + osi_free(arg->generic_client_get_state.get_state); + } + break; + case BTC_BLE_MESH_ACT_GENERIC_CLIENT_SET_STATE: + if (arg->generic_client_set_state.params) { + opcode = arg->generic_client_set_state.params->opcode; + osi_free(arg->generic_client_set_state.params); + } + if (arg->generic_client_set_state.set_state) { + if (opcode) { + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET: + bt_mesh_free_buf(arg->generic_client_set_state.set_state->user_property_set.property_value); + break; + case ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET: + bt_mesh_free_buf(arg->generic_client_set_state.set_state->admin_property_set.property_value); + break; + default: + break; + } + } + osi_free(arg->generic_client_set_state.set_state); + } + break; + default: + break; + } + + return; +} + +static void btc_mesh_generic_client_callback(esp_ble_mesh_generic_client_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + LOG_DEBUG("%s", __func__); + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_GENERIC_CLIENT; + msg.act = act; + + btc_transfer_context(&msg, cb_params, + sizeof(esp_ble_mesh_generic_client_cb_param_t), btc_ble_mesh_copy_req_data); +} + +void bt_mesh_callback_generic_status_to_btc(u32_t opcode, u8_t evt_type, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const u8_t *val, size_t len) +{ + esp_ble_mesh_generic_client_cb_param_t cb_params = {0}; + esp_ble_mesh_client_common_param_t params = {0}; + size_t length; + uint8_t act; + + if (!model || !ctx) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (evt_type) { + case 0x00: + act = ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT; + break; + case 0x01: + act = ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT; + break; + case 0x02: + act = ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT; + break; + case 0x03: + act = ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT; + break; + default: + LOG_ERROR("%s, Unknown generic client event type %d", __func__, evt_type); + return; + } + + params.opcode = opcode; + params.model = (esp_ble_mesh_model_t *)model; + params.ctx.net_idx = ctx->net_idx; + params.ctx.app_idx = ctx->app_idx; + params.ctx.addr = ctx->addr; + params.ctx.recv_ttl = ctx->recv_ttl; + params.ctx.recv_op = ctx->recv_op; + params.ctx.recv_dst = ctx->recv_dst; + + cb_params.error_code = 0; + cb_params.params = ¶ms; + + if (val && len) { + length = (len <= sizeof(cb_params.status_cb)) ? len : sizeof(cb_params.status_cb); + memcpy(&cb_params.status_cb, val, length); + } + + btc_mesh_generic_client_callback(&cb_params, act); +} + +void btc_mesh_generic_client_publish_callback(u32_t opcode, struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) +{ + if (!model || !ctx || !buf) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + bt_mesh_callback_generic_status_to_btc(opcode, 0x02, model, ctx, buf->data, buf->len); +} + +void btc_mesh_generic_client_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_generic_client_cb_param_t generic_client_cb = {0}; + esp_ble_mesh_client_common_param_t *params = NULL; + btc_ble_mesh_generic_client_args_t *arg = NULL; + struct bt_mesh_common_param common = {0}; + bt_mesh_role_param_t role_param = {0}; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_generic_client_args_t *)(msg->arg); + + switch (msg->act) { + case BTC_BLE_MESH_ACT_GENERIC_CLIENT_GET_STATE: { + params = arg->generic_client_get_state.params; + role_param.model = (struct bt_mesh_model *)params->model; + role_param.role = params->msg_role; + if (bt_mesh_set_model_role(&role_param)) { + LOG_ERROR("%s, Failed to set model role", __func__); + return; + } + common.opcode = params->opcode; + common.model = (struct bt_mesh_model *)params->model; + common.ctx.net_idx = params->ctx.net_idx; + common.ctx.app_idx = params->ctx.app_idx; + common.ctx.addr = params->ctx.addr; + common.ctx.send_rel = params->ctx.send_rel; + common.ctx.send_ttl = params->ctx.send_ttl; + common.msg_timeout = params->msg_timeout; + + generic_client_cb.params = arg->generic_client_get_state.params; + generic_client_cb.error_code = + bt_mesh_generic_client_get_state(&common, + (void *)arg->generic_client_get_state.get_state, + (void *)&generic_client_cb.status_cb); + if (generic_client_cb.error_code) { + /* If send failed, callback error_code to app layer immediately */ + btc_mesh_generic_client_callback(&generic_client_cb, + ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT); + } + break; + } + case BTC_BLE_MESH_ACT_GENERIC_CLIENT_SET_STATE: { + params = arg->generic_client_set_state.params; + role_param.model = (struct bt_mesh_model *)params->model; + role_param.role = params->msg_role; + if (bt_mesh_set_model_role(&role_param)) { + LOG_ERROR("%s, Failed to set model role", __func__); + return; + } + common.opcode = params->opcode; + common.model = (struct bt_mesh_model *)params->model; + common.ctx.net_idx = params->ctx.net_idx; + common.ctx.app_idx = params->ctx.app_idx; + common.ctx.addr = params->ctx.addr; + common.ctx.send_rel = params->ctx.send_rel; + common.ctx.send_ttl = params->ctx.send_ttl; + common.msg_timeout = params->msg_timeout; + + generic_client_cb.params = arg->generic_client_set_state.params; + generic_client_cb.error_code = + bt_mesh_generic_client_set_state(&common, + (void *)arg->generic_client_set_state.set_state, + (void *)&generic_client_cb.status_cb); + if (generic_client_cb.error_code) { + /* If send failed, callback error_code to app layer immediately */ + btc_mesh_generic_client_callback(&generic_client_cb, + ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT); + } + break; + } + default: + break; + } + + btc_ble_mesh_generic_client_arg_deep_free(msg); +} + +void btc_mesh_generic_client_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_generic_client_cb_param_t *param = NULL; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + param = (esp_ble_mesh_generic_client_cb_param_t *)(msg->arg); + + if (msg->act < ESP_BLE_MESH_GENERIC_CLIENT_EVT_MAX) { + btc_ble_mesh_cb_to_app(msg->act, param); + } else { + LOG_ERROR("%s, Unknown msg->act = %d", __func__, msg->act); + } + + btc_ble_mesh_free_req_data(msg); +} diff --git a/components/bt/ble_mesh/btc/btc_ble_mesh_health_model.c b/components/bt/ble_mesh/btc/btc_ble_mesh_health_model.c new file mode 100644 index 0000000000..6651f59936 --- /dev/null +++ b/components/bt/ble_mesh/btc/btc_ble_mesh_health_model.c @@ -0,0 +1,592 @@ +// Copyright 2017-2018 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 +#include + +#include "btc/btc_manage.h" +#include "btc/btc_task.h" +#include "osi/allocator.h" + +#include "health_srv.h" +#include "health_cli.h" +#include "mesh_common.h" + +#include "btc_ble_mesh_health_model.h" +#include "esp_ble_mesh_defs.h" + +extern s32_t health_msg_timeout; + +static inline void btc_ble_mesh_health_client_cb_to_app(esp_ble_mesh_health_client_cb_event_t event, + esp_ble_mesh_health_client_cb_param_t *param) +{ + esp_ble_mesh_health_client_cb_t btc_mesh_cb = (esp_ble_mesh_health_client_cb_t)btc_profile_cb_get(BTC_PID_HEALTH_CLIENT); + if (btc_mesh_cb) { + btc_mesh_cb(event, param); + } +} + +static inline void btc_ble_mesh_health_server_cb_to_app(esp_ble_mesh_health_server_cb_event_t event, + esp_ble_mesh_health_server_cb_param_t *param) +{ + esp_ble_mesh_health_server_cb_t btc_mesh_cb = (esp_ble_mesh_health_server_cb_t)btc_profile_cb_get(BTC_PID_HEALTH_SERVER); + if (btc_mesh_cb) { + btc_mesh_cb(event, param); + } +} + +void btc_ble_mesh_health_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_health_client_args_t *dst = (btc_ble_mesh_health_client_args_t *)p_dest; + btc_ble_mesh_health_client_args_t *src = (btc_ble_mesh_health_client_args_t *)p_src; + + if (!msg || !dst || !src) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_HEALTH_CLIENT_GET_STATE: { + dst->health_client_get_state.params = (esp_ble_mesh_client_common_param_t *)osi_malloc(sizeof(esp_ble_mesh_client_common_param_t)); + dst->health_client_get_state.get_state = (esp_ble_mesh_health_client_get_state_t *)osi_malloc(sizeof(esp_ble_mesh_health_client_get_state_t)); + if (dst->health_client_get_state.params && dst->health_client_get_state.get_state) { + memcpy(dst->health_client_get_state.params, src->health_client_get_state.params, + sizeof(esp_ble_mesh_client_common_param_t)); + memcpy(dst->health_client_get_state.get_state, src->health_client_get_state.get_state, + sizeof(esp_ble_mesh_health_client_get_state_t)); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + break; + } + case BTC_BLE_MESH_ACT_HEALTH_CLIENT_SET_STATE: { + dst->health_client_set_state.params = (esp_ble_mesh_client_common_param_t *)osi_malloc(sizeof(esp_ble_mesh_client_common_param_t)); + dst->health_client_set_state.set_state = (esp_ble_mesh_health_client_set_state_t *)osi_malloc(sizeof(esp_ble_mesh_health_client_set_state_t)); + if (dst->health_client_set_state.params && dst->health_client_set_state.set_state) { + memcpy(dst->health_client_set_state.params, src->health_client_set_state.params, + sizeof(esp_ble_mesh_client_common_param_t)); + memcpy(dst->health_client_set_state.set_state, src->health_client_set_state.set_state, + sizeof(esp_ble_mesh_health_client_set_state_t)); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + break; + } + default: + LOG_DEBUG("%s, Unknown deep copy act %d", __func__, msg->act); + break; + } +} + +static void btc_ble_mesh_health_client_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_health_client_args_t *arg = NULL; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_health_client_args_t *)(msg->arg); + + switch (msg->act) { + case BTC_BLE_MESH_ACT_HEALTH_CLIENT_GET_STATE: + if (arg->health_client_get_state.params) { + osi_free(arg->health_client_get_state.params); + } + if (arg->health_client_get_state.get_state) { + osi_free(arg->health_client_get_state.get_state); + } + break; + case BTC_BLE_MESH_ACT_HEALTH_CLIENT_SET_STATE: + if (arg->health_client_set_state.params) { + osi_free(arg->health_client_set_state.params); + } + if (arg->health_client_set_state.set_state) { + osi_free(arg->health_client_set_state.set_state); + } + break; + default: + break; + } + + return; +} + +void btc_ble_mesh_health_server_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + if (!msg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_HEALTH_SERVER_FAULT_UPDATE: + break; + default: + break; + } +} + +static void btc_ble_mesh_health_server_arg_deep_free(btc_msg_t *msg) +{ + if (!msg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_HEALTH_SERVER_FAULT_UPDATE: + break; + default: + break; + } +} + +static void btc_ble_mesh_health_client_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_health_client_cb_param_t *p_dest_data = (esp_ble_mesh_health_client_cb_param_t *)p_dest; + esp_ble_mesh_health_client_cb_param_t *p_src_data = (esp_ble_mesh_health_client_cb_param_t *)p_src; + u32_t opcode; + u16_t length; + + if (!msg || !p_src_data || !p_dest_data) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case ESP_BLE_MESH_HEALTH_CLIENT_GET_STATE_EVT: + case ESP_BLE_MESH_HEALTH_CLIENT_SET_STATE_EVT: + case ESP_BLE_MESH_HEALTH_CLIENT_PUBLISH_EVT: + if (p_src_data->params) { + opcode = p_src_data->params->opcode; + switch (opcode) { + case OP_HEALTH_CURRENT_STATUS: + if (p_src_data->status_cb.current_status.fault_array) { + length = p_src_data->status_cb.current_status.fault_array->len; + p_dest_data->status_cb.current_status.fault_array = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.current_status.fault_array) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.current_status.fault_array, + p_src_data->status_cb.current_status.fault_array->data, + p_src_data->status_cb.current_status.fault_array->len); + } + break; + case OP_HEALTH_FAULT_GET: + case OP_HEALTH_FAULT_CLEAR: + case OP_HEALTH_FAULT_TEST: + case OP_HEALTH_FAULT_STATUS: + if (p_src_data->status_cb.fault_status.fault_array) { + length = p_src_data->status_cb.fault_status.fault_array->len; + p_dest_data->status_cb.fault_status.fault_array = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.fault_status.fault_array) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.fault_status.fault_array, + p_src_data->status_cb.fault_status.fault_array->data, + p_src_data->status_cb.fault_status.fault_array->len); + } + break; + default: + break; + } + } + case ESP_BLE_MESH_HEALTH_CLIENT_TIMEOUT_EVT: + if (p_src_data->params) { + p_dest_data->params = osi_malloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (p_dest_data->params) { + memcpy(p_dest_data->params, p_src_data->params, sizeof(esp_ble_mesh_client_common_param_t)); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + } + break; + default: + break; + } +} + +static void btc_ble_mesh_health_client_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_health_client_cb_param_t *arg = NULL; + u32_t opcode; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_health_client_cb_param_t *)(msg->arg); + + switch (msg->act) { + case ESP_BLE_MESH_HEALTH_CLIENT_GET_STATE_EVT: + case ESP_BLE_MESH_HEALTH_CLIENT_SET_STATE_EVT: + case ESP_BLE_MESH_HEALTH_CLIENT_PUBLISH_EVT: + if (arg->params) { + opcode = arg->params->opcode; + switch (opcode) { + case OP_HEALTH_CURRENT_STATUS: + bt_mesh_free_buf(arg->status_cb.current_status.fault_array); + break; + case OP_HEALTH_FAULT_GET: + case OP_HEALTH_FAULT_CLEAR: + case OP_HEALTH_FAULT_TEST: + case OP_HEALTH_FAULT_STATUS: + bt_mesh_free_buf(arg->status_cb.fault_status.fault_array); + break; + default: + break; + } + } + case ESP_BLE_MESH_HEALTH_CLIENT_TIMEOUT_EVT: + if (arg->params) { + osi_free(arg->params); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_health_server_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + if (!msg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case ESP_BLE_MESH_HEALTH_SERVER_FAULT_UPDATE_COMPLETE_EVT: + break; + default: + break; + } +} + +static void btc_ble_mesh_health_server_free_req_data(btc_msg_t *msg) +{ + if (!msg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case ESP_BLE_MESH_HEALTH_SERVER_FAULT_UPDATE_COMPLETE_EVT: + break; + default: + break; + } +} + +static void btc_mesh_health_client_callback(esp_ble_mesh_health_client_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + LOG_DEBUG("%s", __func__); + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_HEALTH_CLIENT; + msg.act = act; + + btc_transfer_context(&msg, cb_params, + sizeof(esp_ble_mesh_health_client_cb_param_t), btc_ble_mesh_health_client_copy_req_data); +} + +static void btc_mesh_health_server_callback(esp_ble_mesh_health_server_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + LOG_DEBUG("%s", __func__); + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_HEALTH_SERVER; + msg.act = act; + + btc_transfer_context(&msg, cb_params, + sizeof(esp_ble_mesh_health_server_cb_param_t), btc_ble_mesh_health_server_copy_req_data); +} + +int btc_ble_mesh_health_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_health_client_get_state_t *get_state, + esp_ble_mesh_health_client_cb_param_t *client_cb) +{ + struct bt_mesh_msg_ctx ctx = {0}; + + if (!params || !client_cb) { + LOG_ERROR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + ctx.net_idx = params->ctx.net_idx; + ctx.app_idx = params->ctx.app_idx; + ctx.addr = params->ctx.addr; + ctx.send_rel = params->ctx.send_rel; + ctx.send_ttl = params->ctx.send_ttl; + + health_msg_timeout = params->msg_timeout; + + switch (params->opcode) { + case ESP_BLE_MESH_MODEL_OP_ATTENTION_GET: + return (client_cb->error_code = bt_mesh_health_attention_get(&ctx)); + case ESP_BLE_MESH_MODEL_OP_HEALTH_PERIOD_GET: + return (client_cb->error_code = bt_mesh_health_period_get(&ctx)); + case ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_GET: + return (client_cb->error_code = bt_mesh_health_fault_get(&ctx, get_state->fault_get.company_id)); + default: + BT_WARN("%s, invalid opcode 0x%x", __func__, params->opcode); + return (client_cb->error_code = -EINVAL); + } + + return 0; +} + +int btc_ble_mesh_health_client_set_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_health_client_set_state_t *set_state, + esp_ble_mesh_health_client_cb_param_t *client_cb) +{ + struct bt_mesh_msg_ctx ctx = {0}; + + if (!params || !set_state || !client_cb) { + LOG_ERROR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + ctx.net_idx = params->ctx.net_idx; + ctx.app_idx = params->ctx.app_idx; + ctx.addr = params->ctx.addr; + ctx.send_rel = params->ctx.send_rel; + ctx.send_ttl = params->ctx.send_ttl; + + health_msg_timeout = params->msg_timeout; + + switch (params->opcode) { + case ESP_BLE_MESH_MODEL_OP_ATTENTION_SET: + return (client_cb->error_code = + bt_mesh_health_attention_set(&ctx, set_state->attention_set.attention, true)); + case ESP_BLE_MESH_MODEL_OP_ATTENTION_SET_UNACK: + return (client_cb->error_code = + bt_mesh_health_attention_set(&ctx, set_state->attention_set.attention, false)); + case ESP_BLE_MESH_MODEL_OP_HEALTH_PERIOD_SET: + return (client_cb->error_code = + bt_mesh_health_period_set(&ctx, set_state->period_set.fast_period_divisor, true)); + case ESP_BLE_MESH_MODEL_OP_HEALTH_PERIOD_SET_UNACK: + return (client_cb->error_code = + bt_mesh_health_period_set(&ctx, set_state->period_set.fast_period_divisor, false)); + case ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_TEST: + return (client_cb->error_code = + bt_mesh_health_fault_test(&ctx, set_state->fault_test.company_id, set_state->fault_test.test_id, true)); + case ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_TEST_UNACK: + return (client_cb->error_code = + bt_mesh_health_fault_test(&ctx, set_state->fault_test.company_id, set_state->fault_test.test_id, false)); + case ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_CLEAR: + return (client_cb->error_code = + bt_mesh_health_fault_clear(&ctx, set_state->fault_clear.company_id, true)); + case ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_CLEAR_UNACK: + return (client_cb->error_code = + bt_mesh_health_fault_clear(&ctx, set_state->fault_clear.company_id, false)); + default: + BT_WARN("%s, Invalid opcode 0x%x", __func__, params->opcode); + return (client_cb->error_code = -EINVAL); + } + + return 0; +} + +void bt_mesh_callback_health_status_to_btc(u32_t opcode, u8_t evt_type, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const u8_t *val, u16_t len) +{ + esp_ble_mesh_health_client_cb_param_t cb_params = {0}; + esp_ble_mesh_client_common_param_t params = {0}; + size_t length; + uint8_t act; + + if (!model || !ctx) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (evt_type) { + case 0x00: + act = ESP_BLE_MESH_HEALTH_CLIENT_GET_STATE_EVT; + break; + case 0x01: + act = ESP_BLE_MESH_HEALTH_CLIENT_SET_STATE_EVT; + break; + case 0x02: + act = ESP_BLE_MESH_HEALTH_CLIENT_PUBLISH_EVT; + break; + case 0x03: + act = ESP_BLE_MESH_HEALTH_CLIENT_TIMEOUT_EVT; + break; + default: + LOG_ERROR("%s, Unknown health client event type %d", __func__, evt_type); + return; + } + + params.opcode = opcode; + params.model = (esp_ble_mesh_model_t *)model; + params.ctx.net_idx = ctx->net_idx; + params.ctx.app_idx = ctx->app_idx; + params.ctx.addr = ctx->addr; + params.ctx.recv_ttl = ctx->recv_ttl; + params.ctx.recv_op = ctx->recv_op; + params.ctx.recv_dst = ctx->recv_dst; + + cb_params.error_code = 0; + cb_params.params = ¶ms; + + if (val && len) { + length = (len <= sizeof(cb_params.status_cb)) ? len : sizeof(cb_params.status_cb); + memcpy(&cb_params.status_cb, val, length); + } + + btc_mesh_health_client_callback(&cb_params, act); +} + +void btc_mesh_health_publish_callback(u32_t opcode, struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) +{ + if (!model || !ctx || !buf) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + bt_mesh_callback_health_status_to_btc(opcode, 0x02, model, ctx, buf->data, buf->len); +} + +void btc_mesh_health_client_call_handler(btc_msg_t *msg) +{ + btc_ble_mesh_health_client_args_t *arg = NULL; + esp_ble_mesh_health_client_cb_param_t health_client_cb = {0}; + bt_mesh_role_param_t role_param = {0}; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_health_client_args_t *)(msg->arg); + + switch (msg->act) { + case BTC_BLE_MESH_ACT_HEALTH_CLIENT_GET_STATE: { + health_client_cb.params = arg->health_client_get_state.params; + role_param.model = (struct bt_mesh_model *)health_client_cb.params->model; + role_param.role = health_client_cb.params->msg_role; + if (bt_mesh_set_model_role(&role_param)) { + LOG_ERROR("%s, Failed to set model role", __func__); + return; + } + btc_ble_mesh_health_client_get_state(arg->health_client_get_state.params, + arg->health_client_get_state.get_state, + &health_client_cb); + if (health_client_cb.error_code) { + /* If send failed, callback error_code to app layer immediately */ + btc_mesh_health_client_callback(&health_client_cb, ESP_BLE_MESH_HEALTH_CLIENT_GET_STATE_EVT); + } + break; + } + case BTC_BLE_MESH_ACT_HEALTH_CLIENT_SET_STATE: { + health_client_cb.params = arg->health_client_set_state.params; + role_param.model = (struct bt_mesh_model *)health_client_cb.params->model; + role_param.role = health_client_cb.params->msg_role; + if (bt_mesh_set_model_role(&role_param)) { + LOG_ERROR("%s, Failed to set model role", __func__); + return; + } + btc_ble_mesh_health_client_set_state(arg->health_client_set_state.params, + arg->health_client_set_state.set_state, + &health_client_cb); + if (health_client_cb.error_code) { + /* If send failed, callback error_code to app layer immediately */ + btc_mesh_health_client_callback(&health_client_cb, ESP_BLE_MESH_HEALTH_CLIENT_SET_STATE_EVT); + } + break; + } + default: + break; + } + + btc_ble_mesh_health_client_arg_deep_free(msg); + return; +} + +void btc_mesh_health_client_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_health_client_cb_param_t *param = NULL; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + param = (esp_ble_mesh_health_client_cb_param_t *)(msg->arg); + + if (msg->act < ESP_BLE_MESH_HEALTH_CLIENT_EVT_MAX) { + btc_ble_mesh_health_client_cb_to_app(msg->act, param); + } else { + LOG_ERROR("%s, Unknown msg->act = %d", __func__, msg->act); + } + + btc_ble_mesh_health_client_free_req_data(msg); +} + +void btc_mesh_health_server_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_health_server_cb_param_t health_server_cb = {0}; + btc_ble_mesh_health_server_args_t *arg = NULL; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_health_server_args_t *)(msg->arg); + + switch (msg->act) { + case BTC_BLE_MESH_ACT_HEALTH_SERVER_FAULT_UPDATE: { + health_server_cb.error_code = bt_mesh_fault_update((struct bt_mesh_elem *)arg->fault_update.element); + btc_mesh_health_server_callback(&health_server_cb, ESP_BLE_MESH_HEALTH_SERVER_FAULT_UPDATE_COMPLETE_EVT); + } + default: + break; + } + + btc_ble_mesh_health_server_arg_deep_free(msg); +} + +void btc_mesh_health_server_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_health_server_cb_param_t *param = NULL; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + param = (esp_ble_mesh_health_server_cb_param_t *)(msg->arg); + + if (msg->act < ESP_BLE_MESH_HEALTH_SERVER_EVT_MAX) { + btc_ble_mesh_health_server_cb_to_app(msg->act, param); + } else { + LOG_ERROR("%s, Unknown msg->act = %d", __func__, msg->act); + } + + btc_ble_mesh_health_server_free_req_data(msg); +} diff --git a/components/bt/ble_mesh/btc/btc_ble_mesh_lighting_model.c b/components/bt/ble_mesh/btc/btc_ble_mesh_lighting_model.c new file mode 100644 index 0000000000..1b89c51713 --- /dev/null +++ b/components/bt/ble_mesh/btc/btc_ble_mesh_lighting_model.c @@ -0,0 +1,381 @@ +// Copyright 2017-2018 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 +#include + +#include "btc/btc_manage.h" +#include "osi/allocator.h" + +#include "lighting_client.h" +#include "btc_ble_mesh_lighting_model.h" +#include "esp_ble_mesh_lighting_model_api.h" + +static inline void btc_ble_mesh_cb_to_app(esp_ble_mesh_light_client_cb_event_t event, + esp_ble_mesh_light_client_cb_param_t *param) +{ + esp_ble_mesh_light_client_cb_t btc_mesh_cb = (esp_ble_mesh_light_client_cb_t)btc_profile_cb_get(BTC_PID_LIGHT_CLIENT); + if (btc_mesh_cb) { + btc_mesh_cb(event, param); + } +} + +void btc_ble_mesh_light_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_light_client_args_t *dst = (btc_ble_mesh_light_client_args_t *)p_dest; + btc_ble_mesh_light_client_args_t *src = (btc_ble_mesh_light_client_args_t *)p_src; + + if (!msg || !dst || !src) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_LIGHT_CLIENT_GET_STATE: { + dst->light_client_get_state.params = (esp_ble_mesh_client_common_param_t *)osi_malloc(sizeof(esp_ble_mesh_client_common_param_t)); + dst->light_client_get_state.get_state = (esp_ble_mesh_light_client_get_state_t *)osi_malloc(sizeof(esp_ble_mesh_light_client_get_state_t)); + if (dst->light_client_get_state.params && dst->light_client_get_state.get_state) { + memcpy(dst->light_client_get_state.params, src->light_client_get_state.params, + sizeof(esp_ble_mesh_client_common_param_t)); + memcpy(dst->light_client_get_state.get_state, src->light_client_get_state.get_state, + sizeof(esp_ble_mesh_light_client_get_state_t)); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + break; + } + case BTC_BLE_MESH_ACT_LIGHT_CLIENT_SET_STATE: { + dst->light_client_set_state.params = (esp_ble_mesh_client_common_param_t *)osi_malloc(sizeof(esp_ble_mesh_client_common_param_t)); + dst->light_client_set_state.set_state = (esp_ble_mesh_light_client_set_state_t *)osi_malloc(sizeof(esp_ble_mesh_light_client_set_state_t)); + if (dst->light_client_set_state.params && dst->light_client_set_state.set_state) { + memcpy(dst->light_client_set_state.params, src->light_client_set_state.params, + sizeof(esp_ble_mesh_client_common_param_t)); + memcpy(dst->light_client_set_state.set_state, src->light_client_set_state.set_state, + sizeof(esp_ble_mesh_light_client_set_state_t)); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + break; + } + default: + LOG_DEBUG("%s, Unknown deep copy act %d", __func__, msg->act); + break; + } +} + +static void btc_ble_mesh_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_light_client_cb_param_t *p_dest_data = (esp_ble_mesh_light_client_cb_param_t *)p_dest; + esp_ble_mesh_light_client_cb_param_t *p_src_data = (esp_ble_mesh_light_client_cb_param_t *)p_src; + u32_t opcode; + u16_t length; + + if (!msg || !p_src_data || !p_dest_data) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case ESP_BLE_MESH_LIGHT_CLIENT_GET_STATE_EVT: + case ESP_BLE_MESH_LIGHT_CLIENT_SET_STATE_EVT: + case ESP_BLE_MESH_LIGHT_CLIENT_PUBLISH_EVT: + if (p_src_data->params) { + opcode = p_src_data->params->opcode; + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_GET: + case ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET: + case ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS: + if (p_src_data->status_cb.lc_property_status.property_value) { + length = p_src_data->status_cb.lc_property_status.property_value->len; + p_dest_data->status_cb.lc_property_status.property_value = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.lc_property_status.property_value) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.lc_property_status.property_value, + p_src_data->status_cb.lc_property_status.property_value->data, + p_src_data->status_cb.lc_property_status.property_value->len); + } + break; + default: + break; + } + } + case ESP_BLE_MESH_LIGHT_CLIENT_TIMEOUT_EVT: + if (p_src_data->params) { + p_dest_data->params = osi_malloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (p_dest_data->params) { + memcpy(p_dest_data->params, p_src_data->params, sizeof(esp_ble_mesh_client_common_param_t)); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + } + break; + default: + break; + } +} + +static void btc_ble_mesh_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_light_client_cb_param_t *arg = NULL; + u32_t opcode; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_light_client_cb_param_t *)(msg->arg); + + switch (msg->act) { + case ESP_BLE_MESH_LIGHT_CLIENT_GET_STATE_EVT: + case ESP_BLE_MESH_LIGHT_CLIENT_SET_STATE_EVT: + case ESP_BLE_MESH_LIGHT_CLIENT_PUBLISH_EVT: + if (arg->params) { + opcode = arg->params->opcode; + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_GET: + case ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET: + case ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS: + bt_mesh_free_buf(arg->status_cb.lc_property_status.property_value); + break; + default: + break; + } + } + case ESP_BLE_MESH_LIGHT_CLIENT_TIMEOUT_EVT: + if (arg->params) { + osi_free(arg->params); + } + break; + default: + break; + } +} + +void btc_ble_mesh_light_client_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_light_client_args_t *arg = NULL; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_light_client_args_t *)(msg->arg); + + switch (msg->act) { + case BTC_BLE_MESH_ACT_LIGHT_CLIENT_GET_STATE: + if (arg->light_client_get_state.params) { + osi_free(arg->light_client_get_state.params); + } + if (arg->light_client_get_state.get_state) { + osi_free(arg->light_client_get_state.get_state); + } + break; + case BTC_BLE_MESH_ACT_LIGHT_CLIENT_SET_STATE: + if (arg->light_client_set_state.params) { + osi_free(arg->light_client_set_state.params); + } + if (arg->light_client_set_state.set_state) { + osi_free(arg->light_client_set_state.set_state); + } + break; + default: + break; + } + + return; +} + +static void btc_mesh_light_client_callback(esp_ble_mesh_light_client_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + LOG_DEBUG("%s", __func__); + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_LIGHT_CLIENT; + msg.act = act; + + btc_transfer_context(&msg, cb_params, + sizeof(esp_ble_mesh_light_client_cb_param_t), btc_ble_mesh_copy_req_data); +} + +void bt_mesh_callback_light_status_to_btc(u32_t opcode, u8_t evt_type, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const u8_t *val, size_t len) +{ + esp_ble_mesh_light_client_cb_param_t cb_params = {0}; + esp_ble_mesh_client_common_param_t params = {0}; + size_t length; + uint8_t act; + + if (!model || !ctx) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (evt_type) { + case 0x00: + act = ESP_BLE_MESH_LIGHT_CLIENT_GET_STATE_EVT; + break; + case 0x01: + act = ESP_BLE_MESH_LIGHT_CLIENT_SET_STATE_EVT; + break; + case 0x02: + act = ESP_BLE_MESH_LIGHT_CLIENT_PUBLISH_EVT; + break; + case 0x03: + act = ESP_BLE_MESH_LIGHT_CLIENT_TIMEOUT_EVT; + break; + default: + LOG_ERROR("%s, Unknown lighting client event type", __func__); + return; + } + + params.opcode = opcode; + params.model = (esp_ble_mesh_model_t *)model; + params.ctx.net_idx = ctx->net_idx; + params.ctx.app_idx = ctx->app_idx; + params.ctx.addr = ctx->addr; + params.ctx.recv_ttl = ctx->recv_ttl; + params.ctx.recv_op = ctx->recv_op; + params.ctx.recv_dst = ctx->recv_dst; + + cb_params.error_code = 0; + cb_params.params = ¶ms; + + if (val && len) { + length = (len <= sizeof(cb_params.status_cb)) ? len : sizeof(cb_params.status_cb); + memcpy(&cb_params.status_cb, val, length); + } + + btc_mesh_light_client_callback(&cb_params, act); +} + +void btc_mesh_light_client_publish_callback(u32_t opcode, struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) +{ + if (!model || !ctx || !buf) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + bt_mesh_callback_light_status_to_btc(opcode, 0x02, model, ctx, buf->data, buf->len); +} + +void btc_mesh_light_client_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_light_client_cb_param_t light_client_cb = {0}; + esp_ble_mesh_client_common_param_t *params = NULL; + btc_ble_mesh_light_client_args_t *arg = NULL; + struct bt_mesh_common_param common = {0}; + bt_mesh_role_param_t role_param = {0}; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_light_client_args_t *)(msg->arg); + + switch (msg->act) { + case BTC_BLE_MESH_ACT_LIGHT_CLIENT_GET_STATE: { + params = arg->light_client_get_state.params; + role_param.model = (struct bt_mesh_model *)params->model; + role_param.role = params->msg_role; + if (bt_mesh_set_model_role(&role_param)) { + LOG_ERROR("%s, Failed to set model role", __func__); + return; + } + common.opcode = params->opcode; + common.model = (struct bt_mesh_model *)params->model; + common.ctx.net_idx = params->ctx.net_idx; + common.ctx.app_idx = params->ctx.app_idx; + common.ctx.addr = params->ctx.addr; + common.ctx.send_rel = params->ctx.send_rel; + common.ctx.send_ttl = params->ctx.send_ttl; + common.msg_timeout = params->msg_timeout; + + light_client_cb.params = arg->light_client_get_state.params; + light_client_cb.error_code = + bt_mesh_light_client_get_state(&common, + (void *)arg->light_client_get_state.get_state, + (void *)&light_client_cb.status_cb); + if (light_client_cb.error_code) { + /* If send failed, callback error_code to app layer immediately */ + btc_mesh_light_client_callback(&light_client_cb, + ESP_BLE_MESH_LIGHT_CLIENT_GET_STATE_EVT); + } + break; + } + case BTC_BLE_MESH_ACT_LIGHT_CLIENT_SET_STATE: { + params = arg->light_client_set_state.params; + role_param.model = (struct bt_mesh_model *)params->model; + role_param.role = params->msg_role; + if (bt_mesh_set_model_role(&role_param)) { + LOG_ERROR("%s, Failed to set model role", __func__); + return; + } + common.opcode = params->opcode; + common.model = (struct bt_mesh_model *)params->model; + common.ctx.net_idx = params->ctx.net_idx; + common.ctx.app_idx = params->ctx.app_idx; + common.ctx.addr = params->ctx.addr; + common.ctx.send_rel = params->ctx.send_rel; + common.ctx.send_ttl = params->ctx.send_ttl; + common.msg_timeout = params->msg_timeout; + + light_client_cb.params = arg->light_client_set_state.params; + light_client_cb.error_code = + bt_mesh_light_client_set_state(&common, + (void *)arg->light_client_set_state.set_state, + (void *)&light_client_cb.status_cb); + if (light_client_cb.error_code) { + /* If send failed, callback error_code to app layer immediately */ + btc_mesh_light_client_callback(&light_client_cb, + ESP_BLE_MESH_LIGHT_CLIENT_SET_STATE_EVT); + } + break; + } + default: + break; + } + + btc_ble_mesh_light_client_arg_deep_free(msg); +} + +void btc_mesh_light_client_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_light_client_cb_param_t *param = NULL; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + param = (esp_ble_mesh_light_client_cb_param_t *)(msg->arg); + + if (msg->act < ESP_BLE_MESH_LIGHT_CLIENT_EVT_MAX) { + btc_ble_mesh_cb_to_app(msg->act, param); + } else { + LOG_ERROR("%s, Unknown msg->act = %d", __func__, msg->act); + } + + btc_ble_mesh_free_req_data(msg); +} + diff --git a/components/bt/ble_mesh/btc/btc_ble_mesh_prov.c b/components/bt/ble_mesh/btc/btc_ble_mesh_prov.c new file mode 100644 index 0000000000..d53b0d8cb4 --- /dev/null +++ b/components/bt/ble_mesh/btc/btc_ble_mesh_prov.c @@ -0,0 +1,1528 @@ +// Copyright 2017-2018 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 +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" + +#include "btc/btc_manage.h" +#include "osi/allocator.h" + +#include "sdkconfig.h" + +#include "mesh_util.h" +#include "mesh_main.h" +#include "mesh_access.h" +#include "mesh_proxy.h" +#include "cfg_cli.h" +#include "health_cli.h" + +#include "mesh.h" +#include "access.h" +#include "transport.h" +#include "proxy.h" +#include "prov.h" +#include "provisioner_prov.h" +#include "provisioner_main.h" + +#include "generic_client.h" +#include "lighting_client.h" +#include "sensor_client.h" +#include "time_scene_client.h" +#include "model_common.h" + +#include "btc_ble_mesh_prov.h" +#include "btc_ble_mesh_config_model.h" +#include "btc_ble_mesh_health_model.h" +#include "btc_ble_mesh_generic_model.h" +#include "btc_ble_mesh_time_scene_model.h" +#include "btc_ble_mesh_sensor_model.h" +#include "btc_ble_mesh_lighting_model.h" + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_common_api.h" +#include "esp_ble_mesh_provisioning_api.h" +#include "esp_ble_mesh_networking_api.h" + +#define BLE_MESH_MAX_DATA_SIZE 379 + +void btc_ble_mesh_prov_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_model_args_t *dst = (btc_ble_mesh_model_args_t *)p_dest; + btc_ble_mesh_model_args_t *src = (btc_ble_mesh_model_args_t *)p_src; + + if (!msg || !dst || !src) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_SERVER_MODEL_SEND: + case BTC_BLE_MESH_ACT_CLIENT_MODEL_SEND: { + LOG_DEBUG("%s, BTC_BLE_MESH_ACT_MODEL_SEND, src->model_send.length = %d", __func__, src->model_send.length); + dst->model_send.data = src->model_send.length ? (uint8_t *)osi_malloc(src->model_send.length) : NULL; + dst->model_send.ctx = osi_malloc(sizeof(esp_ble_mesh_msg_ctx_t)); + if (src->model_send.length) { + if (dst->model_send.data) { + memcpy(dst->model_send.data, src->model_send.data, src->model_send.length); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + } + if (dst->model_send.ctx) { + memcpy(dst->model_send.ctx, src->model_send.ctx, sizeof(esp_ble_mesh_msg_ctx_t)); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + break; + } + default: + LOG_DEBUG("%s, Unknown deep copy act %d", __func__, msg->act); + break; + } +} + +void btc_ble_mesh_prov_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_model_args_t *arg = NULL; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_model_args_t *)(msg->arg); + + switch (msg->act) { + case BTC_BLE_MESH_ACT_SERVER_MODEL_SEND: + case BTC_BLE_MESH_ACT_CLIENT_MODEL_SEND: + if (arg->model_send.data) { + osi_free(arg->model_send.data); + } + if (arg->model_send.ctx) { + osi_free(arg->model_send.ctx); + } + break; + default: + break; + } + + return; +} + +static void btc_ble_mesh_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_model_cb_param_t *p_dest_data = (esp_ble_mesh_model_cb_param_t *)p_dest; + esp_ble_mesh_model_cb_param_t *p_src_data = (esp_ble_mesh_model_cb_param_t *)p_src; + + if (!msg || !p_src_data || !p_dest_data) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case ESP_BLE_MESH_MODEL_OPERATION_EVT: { + if (p_src_data->model_operation.ctx && p_src_data->model_operation.msg) { + p_dest_data->model_operation.ctx = osi_malloc(sizeof(esp_ble_mesh_msg_ctx_t)); + p_dest_data->model_operation.msg = p_src_data->model_operation.length ? (uint8_t *)osi_malloc(p_src_data->model_operation.length) : NULL; + if (p_dest_data->model_operation.ctx) { + memcpy(p_dest_data->model_operation.ctx, p_src_data->model_operation.ctx, sizeof(esp_ble_mesh_msg_ctx_t)); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + if (p_src_data->model_operation.length) { + if (p_dest_data->model_operation.msg) { + memcpy(p_dest_data->model_operation.msg, p_src_data->model_operation.msg, p_src_data->model_operation.length); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + } + } + break; + } + case ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT: { + if (p_src_data->client_recv_publish_msg.ctx && p_src_data->client_recv_publish_msg.msg) { + p_dest_data->client_recv_publish_msg.ctx = osi_malloc(sizeof(esp_ble_mesh_msg_ctx_t)); + p_dest_data->client_recv_publish_msg.msg = p_src_data->client_recv_publish_msg.length ? (uint8_t *)osi_malloc(p_src_data->client_recv_publish_msg.length) : NULL; + if (p_dest_data->client_recv_publish_msg.ctx) { + memcpy(p_dest_data->client_recv_publish_msg.ctx, p_src_data->client_recv_publish_msg.ctx, sizeof(esp_ble_mesh_msg_ctx_t)); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + if (p_src_data->client_recv_publish_msg.length) { + if (p_dest_data->client_recv_publish_msg.msg) { + memcpy(p_dest_data->client_recv_publish_msg.msg, p_src_data->client_recv_publish_msg.msg, p_src_data->client_recv_publish_msg.length); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + } + } + break; + } + case ESP_BLE_MESH_MODEL_SEND_COMP_EVT: { + if (p_src_data->model_send_comp.ctx) { + p_dest_data->model_send_comp.ctx = osi_malloc(sizeof(esp_ble_mesh_msg_ctx_t)); + if (p_dest_data->model_send_comp.ctx) { + memcpy(p_dest_data->model_send_comp.ctx, p_src_data->model_send_comp.ctx, sizeof(esp_ble_mesh_msg_ctx_t)); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + } + break; + } + case ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT: { + if (p_src_data->client_send_timeout.ctx) { + p_dest_data->client_send_timeout.ctx = osi_malloc(sizeof(esp_ble_mesh_msg_ctx_t)); + if (p_dest_data->client_send_timeout.ctx) { + memcpy(p_dest_data->client_send_timeout.ctx, p_src_data->client_send_timeout.ctx, sizeof(esp_ble_mesh_msg_ctx_t)); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + } + break; + } + default: + break; + } +} + +static void btc_ble_mesh_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_model_cb_param_t *arg = NULL; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_model_cb_param_t *)(msg->arg); + + switch (msg->act) { + case ESP_BLE_MESH_MODEL_OPERATION_EVT: { + if (arg->model_operation.msg) { + osi_free(arg->model_operation.msg); + } + if (arg->model_operation.ctx) { + osi_free(arg->model_operation.ctx); + } + break; + } + case ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT: { + if (arg->client_recv_publish_msg.msg) { + osi_free(arg->client_recv_publish_msg.msg); + } + if (arg->client_recv_publish_msg.ctx) { + osi_free(arg->client_recv_publish_msg.ctx); + } + break; + } + case ESP_BLE_MESH_MODEL_SEND_COMP_EVT: { + if (arg->model_send_comp.ctx) { + osi_free(arg->model_send_comp.ctx); + } + break; + } + case ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT: { + if (arg->client_send_timeout.ctx) { + osi_free(arg->client_send_timeout.ctx); + } + break; + } + default: + break; + } +} + +static inline void btc_ble_mesh_cb_to_app(esp_ble_mesh_prov_cb_event_t event, + esp_ble_mesh_prov_cb_param_t *param) +{ + esp_ble_mesh_prov_cb_t btc_mesh_cb = (esp_ble_mesh_prov_cb_t)btc_profile_cb_get(BTC_PID_PROV); + if (btc_mesh_cb) { + btc_mesh_cb(event, param); + } +} + +static inline void btc_ble_mesh_model_cb_to_app(esp_ble_mesh_model_cb_event_t event, + esp_ble_mesh_model_cb_param_t *param) +{ + esp_ble_mesh_model_cb_t btc_mesh_cb = (esp_ble_mesh_model_cb_t)btc_profile_cb_get(BTC_PID_MODEL); + if (btc_mesh_cb) { + btc_mesh_cb(event, param); + } +} + +extern u32_t mesh_opcode; + +static void btc_ble_mesh_server_model_op_cb(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + esp_ble_mesh_model_cb_param_t mesh_param = {0}; + btc_msg_t msg = {0}; + bt_status_t ret; + + mesh_param.model_operation.opcode = mesh_opcode; + mesh_param.model_operation.model = (esp_ble_mesh_model_t *)model; + mesh_param.model_operation.ctx = (esp_ble_mesh_msg_ctx_t *)ctx; + mesh_param.model_operation.length = buf->len; + mesh_param.model_operation.msg = buf->data; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_MODEL; + msg.act = ESP_BLE_MESH_MODEL_OPERATION_EVT; + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_model_cb_param_t), btc_ble_mesh_copy_req_data); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + } + return; +} + +static void btc_ble_mesh_client_model_op_cb(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + esp_ble_mesh_model_cb_param_t mesh_param = {0}; + bt_mesh_client_common_t *client_param = NULL; + bt_mesh_internal_data_t *data = NULL; + bt_mesh_client_node_t *node = NULL; + btc_msg_t msg = {0}; + bt_status_t ret; + + if (!model || !model->user_data || !ctx || !buf) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + client_param = (bt_mesh_client_common_t *)model->user_data; + data = (bt_mesh_internal_data_t *)client_param->internal_data; + if (!data) { + LOG_ERROR("%s, Client internal_data is NULL", __func__); + return; + } + + node = bt_mesh_is_model_message_publish(model, ctx, buf, false); + if (node == NULL) { + msg.act = ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT; + mesh_param.client_recv_publish_msg.opcode = mesh_opcode; + mesh_param.client_recv_publish_msg.model = (esp_ble_mesh_model_t *)model; + mesh_param.client_recv_publish_msg.ctx = (esp_ble_mesh_msg_ctx_t *)ctx; + mesh_param.client_recv_publish_msg.length = buf->len; + mesh_param.client_recv_publish_msg.msg = buf->data; + } else { + msg.act = ESP_BLE_MESH_MODEL_OPERATION_EVT; + mesh_param.model_operation.opcode = mesh_opcode; + mesh_param.model_operation.model = (esp_ble_mesh_model_t *)model; + mesh_param.model_operation.ctx = (esp_ble_mesh_msg_ctx_t *)ctx; + mesh_param.model_operation.length = buf->len; + mesh_param.model_operation.msg = buf->data; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_MODEL; + if (msg.act != ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT) { + // Don't forget to release the node at the end. + bt_mesh_client_free_node(&data->queue, node); + } + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_model_cb_param_t), btc_ble_mesh_copy_req_data); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s, btc_transfer_context failed", __func__); + } + return; +} + +static void btc_ble_mesh_model_send_comp_cb(esp_ble_mesh_model_t *model, esp_ble_mesh_msg_ctx_t *ctx, u32_t opcode, int err) +{ + esp_ble_mesh_model_cb_param_t mesh_param = {0}; + btc_msg_t msg = {0}; + bt_status_t ret; + + mesh_param.model_send_comp.err_code = err; + mesh_param.model_send_comp.opcode = opcode; + mesh_param.model_send_comp.model = model; + mesh_param.model_send_comp.ctx = ctx; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_MODEL; + msg.act = ESP_BLE_MESH_MODEL_SEND_COMP_EVT; + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_model_cb_param_t), btc_ble_mesh_copy_req_data); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + } + return; +} + +static void btc_ble_mesh_model_publish_comp_cb(esp_ble_mesh_model_t *model, int err) +{ + esp_ble_mesh_model_cb_param_t mesh_param = {0}; + btc_msg_t msg = {0}; + bt_status_t ret; + + mesh_param.model_publish_comp.err_code = err; + mesh_param.model_publish_comp.model = model; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_MODEL; + msg.act = ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT; + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_model_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + } + return; +} + +#if defined(CONFIG_BLE_MESH_NODE) +static void btc_oob_pub_key_cb(void) +{ + btc_msg_t msg = {0}; + + LOG_DEBUG("%s", __func__); + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_PROV; + msg.act = ESP_BLE_MESH_NODE_PROV_OOB_PUB_KEY_EVT; + + if (btc_transfer_context(&msg, NULL, 0, NULL) != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + } + return; +} + +static int btc_output_number_cb(bt_mesh_output_action_t act, u32_t num) +{ + esp_ble_mesh_prov_cb_param_t mesh_param = {0}; + btc_msg_t msg = {0}; + bt_status_t ret; + + LOG_DEBUG("%s", __func__); + + mesh_param.node_prov_output_num.action = (esp_ble_mesh_output_action_t)act; + mesh_param.node_prov_output_num.number = num; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_PROV; + msg.act = ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT; + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_prov_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + return -1; + } + return 0; +} + +static int btc_output_string_cb(const char *str) +{ + esp_ble_mesh_prov_cb_param_t mesh_param = {0}; + btc_msg_t msg = {0}; + bt_status_t ret; + + LOG_DEBUG("%s", __func__); + + strncpy(mesh_param.node_prov_output_str.string, str, strlen(str)); + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_PROV; + msg.act = ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT; + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_prov_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + return -1; + } + return 0; +} + +static int btc_input_cb(bt_mesh_input_action_t act, u8_t size) +{ + esp_ble_mesh_prov_cb_param_t mesh_param = {0}; + btc_msg_t msg = {0}; + bt_status_t ret; + + LOG_DEBUG("%s", __func__); + + mesh_param.node_prov_input.action = (esp_ble_mesh_input_action_t)act; + mesh_param.node_prov_input.size = size; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_PROV; + msg.act = ESP_BLE_MESH_NODE_PROV_INPUT_EVT; + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_prov_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + return -1; + } + return 0; +} + +static void btc_link_open_cb(bt_mesh_prov_bearer_t bearer) +{ + esp_ble_mesh_prov_cb_param_t mesh_param = {0}; + btc_msg_t msg = {0}; + bt_status_t ret; + + LOG_DEBUG("%s", __func__); + + mesh_param.node_prov_link_open.bearer = (esp_ble_mesh_prov_bearer_t)bearer; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_PROV; + msg.act = ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT; + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_prov_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + } + return; +} + +static void btc_link_close_cb(bt_mesh_prov_bearer_t bearer) +{ + esp_ble_mesh_prov_cb_param_t mesh_param = {0}; + btc_msg_t msg = {0}; + bt_status_t ret; + + LOG_DEBUG("%s", __func__); + + mesh_param.node_prov_link_close.bearer = (esp_ble_mesh_prov_bearer_t)bearer; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_PROV; + msg.act = ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT; + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_prov_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + } + return; +} + +static void btc_complete_cb(u16_t net_idx, u16_t addr, u8_t flags, u32_t iv_index) +{ + esp_ble_mesh_prov_cb_param_t mesh_param = {0}; + btc_msg_t msg = {0}; + bt_status_t ret; + + LOG_DEBUG("%s", __func__); + + mesh_param.node_prov_complete.net_idx = net_idx; + mesh_param.node_prov_complete.addr = addr; + mesh_param.node_prov_complete.flags = flags; + mesh_param.node_prov_complete.iv_index = iv_index; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_PROV; + msg.act = ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT; + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_prov_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + } + return; +} + +static void btc_reset_cb(void) +{ + btc_msg_t msg = {0}; + bt_status_t ret; + + LOG_DEBUG("%s", __func__); + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_PROV; + msg.act = ESP_BLE_MESH_NODE_PROV_RESET_EVT; + ret = btc_transfer_context(&msg, NULL, 0, NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + } + return; +} +#endif /* defined(CONFIG_BLE_MESH_NODE) */ + +static void btc_prov_register_complete_cb(int err_code) +{ + esp_ble_mesh_prov_cb_param_t mesh_param = {0}; + btc_msg_t msg = {0}; + bt_status_t ret; + + LOG_DEBUG("%s", __func__); + + mesh_param.prov_register_comp.err_code = err_code; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_PROV; + msg.act = ESP_BLE_MESH_PROV_REGISTER_COMP_EVT; + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_prov_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + } + return; +} + +static void btc_client_model_timeout_cb(struct k_work *work) +{ + esp_ble_mesh_model_cb_param_t mesh_param = {0}; + bt_mesh_client_common_t *client_param = NULL; + bt_mesh_internal_data_t *data = NULL; + bt_mesh_client_node_t *node = NULL; + btc_msg_t msg = {0}; + bt_status_t ret; + + node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work); + if (!node || !node->ctx.model || !node->ctx.model->user_data) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + client_param = (bt_mesh_client_common_t *)node->ctx.model->user_data; + data = (bt_mesh_internal_data_t *)client_param->internal_data; + if (!data) { + LOG_ERROR("%s, Client internal_data is NULL", __func__); + return; + } + + mesh_param.client_send_timeout.opcode = node->opcode; + mesh_param.client_send_timeout.model = (esp_ble_mesh_model_t *)node->ctx.model; + mesh_param.client_send_timeout.ctx = (esp_ble_mesh_msg_ctx_t *)&node->ctx; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_MODEL; + msg.act = ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT; + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_model_cb_param_t), btc_ble_mesh_copy_req_data); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + } + // Don't forget to release the node at the end. + bt_mesh_client_free_node(&data->queue, node); + return; +} + +static int btc_model_publish_update(struct bt_mesh_model *mod) +{ + esp_ble_mesh_model_cb_param_t mesh_param = {0}; + btc_msg_t msg = {0}; + bt_status_t ret; + + LOG_DEBUG("%s", __func__); + + mesh_param.model_publish_update.model = (esp_ble_mesh_model_t *)mod; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_MODEL; + msg.act = ESP_BLE_MESH_MODEL_PUBLISH_UPDATE_EVT; + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_model_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + return -1; + } + return 0; +} + +static void btc_prov_set_complete_cb(esp_ble_mesh_prov_cb_param_t *param, uint8_t act) +{ + btc_msg_t msg = {0}; + bt_status_t ret; + + LOG_DEBUG("%s", __func__); + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_PROV; + msg.act = act; + ret = btc_transfer_context(&msg, param, + sizeof(esp_ble_mesh_prov_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + } + return; +} + +#if (CONFIG_BLE_MESH_PROVISIONER) +static void btc_provisioner_recv_unprov_adv_pkt_cb(const u8_t addr[6], const u8_t addr_type, + const u8_t adv_type, const u8_t dev_uuid[16], + u16_t oob_info, bt_mesh_prov_bearer_t bearer) +{ + esp_ble_mesh_prov_cb_param_t mesh_param = {0}; + btc_msg_t msg = {0}; + bt_status_t ret; + + LOG_DEBUG("%s", __func__); + + if (addr == NULL || dev_uuid == NULL || + (bearer != BLE_MESH_PROV_ADV && bearer != BLE_MESH_PROV_GATT)) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + memcpy(mesh_param.provisioner_recv_unprov_adv_pkt.dev_uuid, dev_uuid, 16); + memcpy(mesh_param.provisioner_recv_unprov_adv_pkt.addr, addr, ESP_BD_ADDR_LEN); + mesh_param.provisioner_recv_unprov_adv_pkt.addr_type = addr_type; + mesh_param.provisioner_recv_unprov_adv_pkt.oob_info = oob_info; + mesh_param.provisioner_recv_unprov_adv_pkt.adv_type = adv_type; + mesh_param.provisioner_recv_unprov_adv_pkt.bearer = bearer; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_PROV; + msg.act = ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT; + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_prov_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + } + return; +} + +static int btc_provisioner_prov_read_oob_pub_key_cb(u8_t link_idx) +{ + esp_ble_mesh_prov_cb_param_t mesh_param = {0}; + btc_msg_t msg = {0}; + bt_status_t ret; + + LOG_DEBUG("%s", __func__); + + mesh_param.provisioner_prov_read_oob_pub_key.link_idx = link_idx; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_PROV; + msg.act = ESP_BLE_MESH_PROVISIONER_PROV_READ_OOB_PUB_KEY_EVT; + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_prov_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + return -1; + } + return 0; +} + +static int btc_provisioner_prov_input_cb(u8_t method, bt_mesh_output_action_t act, u8_t size, u8_t link_idx) +{ + esp_ble_mesh_prov_cb_param_t mesh_param = {0}; + btc_msg_t msg = {0}; + bt_status_t ret; + + LOG_DEBUG("%s", __func__); + + mesh_param.provisioner_prov_input.method = (esp_ble_mesh_oob_method_t)method; + mesh_param.provisioner_prov_input.action = (esp_ble_mesh_output_action_t)act; + mesh_param.provisioner_prov_input.size = size; + mesh_param.provisioner_prov_input.link_idx = link_idx; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_PROV; + msg.act = ESP_BLE_MESH_PROVISIONER_PROV_INPUT_EVT; + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_prov_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + return -1; + } + return 0; +} + +static int btc_provisioner_prov_output_cb(u8_t method, bt_mesh_input_action_t act, void *data, u8_t size, u8_t link_idx) +{ + esp_ble_mesh_prov_cb_param_t mesh_param = {0}; + btc_msg_t msg = {0}; + bt_status_t ret; + + LOG_DEBUG("%s", __func__); + + mesh_param.provisioner_prov_output.method = (esp_ble_mesh_oob_method_t)method; + mesh_param.provisioner_prov_output.action = (esp_ble_mesh_input_action_t)act; + mesh_param.provisioner_prov_output.size = size; + mesh_param.provisioner_prov_output.link_idx = link_idx; + if (act == BLE_MESH_ENTER_STRING) { + strncpy(mesh_param.provisioner_prov_output.string, (char *)data, size); + } else { + mesh_param.provisioner_prov_output.number = sys_get_le32((u8_t *)data); + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_PROV; + msg.act = ESP_BLE_MESH_PROVISIONER_PROV_OUTPUT_EVT; + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_prov_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + return -1; + } + return 0; +} + +static void btc_provisioner_link_open_cb(bt_mesh_prov_bearer_t bearer) +{ + esp_ble_mesh_prov_cb_param_t mesh_param = {0}; + btc_msg_t msg = {0}; + bt_status_t ret; + + LOG_DEBUG("%s", __func__); + + mesh_param.provisioner_prov_link_open.bearer = (esp_ble_mesh_prov_bearer_t)bearer; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_PROV; + msg.act = ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT; + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_prov_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + } + return; +} + +static void btc_provisioner_link_close_cb(bt_mesh_prov_bearer_t bearer, u8_t reason) +{ + esp_ble_mesh_prov_cb_param_t mesh_param = {0}; + btc_msg_t msg = {0}; + bt_status_t ret; + + LOG_DEBUG("%s", __func__); + + mesh_param.provisioner_prov_link_close.bearer = (esp_ble_mesh_prov_bearer_t)bearer; + mesh_param.provisioner_prov_link_close.reason = reason; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_PROV; + msg.act = ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT; + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_prov_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + } + return; +} + +static void btc_provisioner_prov_complete_cb(int node_idx, const u8_t device_uuid[16], + u16_t unicast_addr, u8_t element_num, + u16_t netkey_idx) +{ + esp_ble_mesh_prov_cb_param_t mesh_param = {0}; + btc_msg_t msg = {0}; + bt_status_t ret; + + LOG_DEBUG("%s", __func__); + + mesh_param.provisioner_prov_complete.node_idx = node_idx; + mesh_param.provisioner_prov_complete.unicast_addr = unicast_addr; + mesh_param.provisioner_prov_complete.element_num = element_num; + mesh_param.provisioner_prov_complete.netkey_idx = netkey_idx; + memcpy(mesh_param.provisioner_prov_complete.device_uuid, device_uuid, sizeof(esp_ble_mesh_octet16_t)); + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_PROV; + msg.act = ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT; + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_prov_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + } + return; +} +#endif /* CONFIG_BLE_MESH_PROVISIONER */ + +int btc_ble_mesh_client_init(esp_ble_mesh_model_t *model) +{ + __ASSERT(model && model->op, "%s, Invalid parameter", __func__); + esp_ble_mesh_model_op_t *op = model->op; + while (op != NULL && op->opcode != 0) { + op->param_cb = (esp_ble_mesh_cb_t)btc_ble_mesh_client_model_op_cb; + op++; + } + return bt_mesh_client_init((struct bt_mesh_model *)model); +} + +int32_t btc_ble_mesh_model_pub_period_get(esp_ble_mesh_model_t *mod) +{ + return bt_mesh_model_pub_period_get((struct bt_mesh_model *)mod); +} + +uint16_t btc_ble_mesh_get_primary_addr(void) +{ + return bt_mesh_primary_addr(); +} + +uint16_t *btc_ble_mesh_model_find_group(esp_ble_mesh_model_t *mod, uint16_t addr) +{ + return bt_mesh_model_find_group((struct bt_mesh_model *)mod, addr); +} + +esp_ble_mesh_elem_t *btc_ble_mesh_elem_find(u16_t addr) +{ + return (esp_ble_mesh_elem_t *)bt_mesh_elem_find(addr); +} + +uint8_t btc_ble_mesh_elem_count(void) +{ + return bt_mesh_elem_count(); +} + +esp_ble_mesh_model_t *btc_ble_mesh_model_find_vnd(const esp_ble_mesh_elem_t *elem, + uint16_t company, uint16_t id) +{ + return (esp_ble_mesh_model_t *)bt_mesh_model_find_vnd((struct bt_mesh_elem *)elem, company, id); +} + +esp_ble_mesh_model_t *btc_ble_mesh_model_find(const esp_ble_mesh_elem_t *elem, uint16_t id) +{ + return (esp_ble_mesh_model_t *)bt_mesh_model_find((struct bt_mesh_elem *)elem, id); +} + +const esp_ble_mesh_comp_t *btc_ble_mesh_comp_get(void) +{ + return (const esp_ble_mesh_comp_t *)bt_mesh_comp_get(); +} + +/* Configuration Models */ +extern const struct bt_mesh_model_op bt_mesh_cfg_srv_op[]; +extern const struct bt_mesh_model_op bt_mesh_cfg_cli_op[]; +/* Health Models */ +extern const struct bt_mesh_model_op bt_mesh_health_srv_op[]; +extern const struct bt_mesh_model_op bt_mesh_health_cli_op[]; +/* Generic Client Models */ +extern const struct bt_mesh_model_op gen_onoff_cli_op[]; +extern const struct bt_mesh_model_op gen_level_cli_op[]; +extern const struct bt_mesh_model_op gen_def_trans_time_cli_op[]; +extern const struct bt_mesh_model_op gen_power_onoff_cli_op[]; +extern const struct bt_mesh_model_op gen_power_level_cli_op[]; +extern const struct bt_mesh_model_op gen_battery_cli_op[]; +extern const struct bt_mesh_model_op gen_location_cli_op[]; +extern const struct bt_mesh_model_op gen_property_cli_op[]; +/* Lighting Client Models */ +extern const struct bt_mesh_model_op light_lightness_cli_op[]; +extern const struct bt_mesh_model_op light_ctl_cli_op[]; +extern const struct bt_mesh_model_op light_hsl_cli_op[]; +extern const struct bt_mesh_model_op light_xyl_cli_op[]; +extern const struct bt_mesh_model_op light_lc_cli_op[]; +/* Sensor Client Models */ +extern const struct bt_mesh_model_op sensor_cli_op[]; +/* Time and Scenes Client Models */ +extern const struct bt_mesh_model_op time_cli_op[]; +extern const struct bt_mesh_model_op scene_cli_op[]; +extern const struct bt_mesh_model_op scheduler_cli_op[]; + +static void btc_mesh_model_op_add(esp_ble_mesh_model_t *model) +{ + esp_ble_mesh_model_op_t *op = NULL; + + if (!model) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + /* 1. For SIG client models, model->op will be NULL and initialized here. + * 2. The vendor model opcode is 3 bytes. + */ + if ((model->op != NULL) && (model->op->opcode >= 0x10000)) { + goto add_model_op; + } + + switch (model->model_id) { + case BLE_MESH_MODEL_ID_CFG_SRV: { + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_cfg_srv_op; + break; + } + case BLE_MESH_MODEL_ID_CFG_CLI: { + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_cfg_cli_op; + bt_mesh_config_client_t *cli = (bt_mesh_config_client_t *)model->user_data; + if (cli != NULL) { + cli->publish_status = btc_mesh_cfg_client_publish_callback; + } + break; + } + case BLE_MESH_MODEL_ID_HEALTH_SRV: { + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_health_srv_op; + break; + } + case BLE_MESH_MODEL_ID_HEALTH_CLI: { + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_health_cli_op; + bt_mesh_health_client_t *cli = (bt_mesh_health_client_t *)model->user_data; + if (cli != NULL) { + cli->publish_status = btc_mesh_health_publish_callback; + } + break; + } + case BLE_MESH_MODEL_ID_GEN_ONOFF_CLI: { + model->op = ((esp_ble_mesh_model_op_t *)gen_onoff_cli_op); + bt_mesh_gen_onoff_cli_t *cli = (bt_mesh_gen_onoff_cli_t *)model->user_data; + if (cli != NULL) { + cli->publish_status = btc_mesh_generic_client_publish_callback; + } + break; + } + case BLE_MESH_MODEL_ID_GEN_LEVEL_CLI: { + model->op = ((esp_ble_mesh_model_op_t *)gen_level_cli_op); + bt_mesh_gen_level_cli_t *cli = (bt_mesh_gen_level_cli_t *)model->user_data; + if (cli != NULL) { + cli->publish_status = btc_mesh_generic_client_publish_callback; + } + break; + } + case BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_CLI: { + model->op = ((esp_ble_mesh_model_op_t *)gen_def_trans_time_cli_op); + bt_mesh_gen_def_trans_time_cli_t *cli = (bt_mesh_gen_def_trans_time_cli_t *)model->user_data; + if (cli != NULL) { + cli->publish_status = btc_mesh_generic_client_publish_callback; + } + break; + } + case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_CLI: { + model->op = ((esp_ble_mesh_model_op_t *)gen_power_onoff_cli_op); + bt_mesh_gen_power_onoff_cli_t *cli = (bt_mesh_gen_power_onoff_cli_t *)model->user_data; + if (cli != NULL) { + cli->publish_status = btc_mesh_generic_client_publish_callback; + } + break; + } + case BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_CLI: { + model->op = ((esp_ble_mesh_model_op_t *)gen_power_level_cli_op); + bt_mesh_gen_power_level_cli_t *cli = (bt_mesh_gen_power_level_cli_t *)model->user_data; + if (cli != NULL) { + cli->publish_status = btc_mesh_generic_client_publish_callback; + } + break; + } + case BLE_MESH_MODEL_ID_GEN_BATTERY_CLI: { + model->op = ((esp_ble_mesh_model_op_t *)gen_battery_cli_op); + bt_mesh_gen_battery_cli_t *cli = (bt_mesh_gen_battery_cli_t *)model->user_data; + if (cli != NULL) { + cli->publish_status = btc_mesh_generic_client_publish_callback; + } + break; + } + case BLE_MESH_MODEL_ID_GEN_LOCATION_CLI: { + model->op = ((esp_ble_mesh_model_op_t *)gen_location_cli_op); + bt_mesh_gen_location_cli_t *cli = (bt_mesh_gen_location_cli_t *)model->user_data; + if (cli != NULL) { + cli->publish_status = btc_mesh_generic_client_publish_callback; + } + break; + } + case BLE_MESH_MODEL_ID_GEN_PROP_CLI: { + model->op = ((esp_ble_mesh_model_op_t *)gen_property_cli_op); + bt_mesh_gen_property_cli_t *cli = (bt_mesh_gen_property_cli_t *)model->user_data; + if (cli != NULL) { + cli->publish_status = btc_mesh_generic_client_publish_callback; + } + break; + } + case BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_CLI: { + model->op = ((esp_ble_mesh_model_op_t *)light_lightness_cli_op); + bt_mesh_light_lightness_cli_t *cli = (bt_mesh_light_lightness_cli_t *)model->user_data; + if (cli != NULL) { + cli->publish_status = btc_mesh_light_client_publish_callback; + } + break; + } + case BLE_MESH_MODEL_ID_LIGHT_CTL_CLI: { + model->op = ((esp_ble_mesh_model_op_t *)light_ctl_cli_op); + bt_mesh_light_ctl_cli_t *cli = (bt_mesh_light_ctl_cli_t *)model->user_data; + if (cli != NULL) { + cli->publish_status = btc_mesh_light_client_publish_callback; + } + break; + } + case BLE_MESH_MODEL_ID_LIGHT_HSL_CLI: { + model->op = ((esp_ble_mesh_model_op_t *)light_hsl_cli_op); + bt_mesh_light_hsl_cli_t *cli = (bt_mesh_light_hsl_cli_t *)model->user_data; + if (cli != NULL) { + cli->publish_status = btc_mesh_light_client_publish_callback; + } + break; + } + case BLE_MESH_MODEL_ID_LIGHT_XYL_CLI: { + model->op = ((esp_ble_mesh_model_op_t *)light_xyl_cli_op); + bt_mesh_light_xyl_cli_t *cli = (bt_mesh_light_xyl_cli_t *)model->user_data; + if (cli != NULL) { + cli->publish_status = btc_mesh_light_client_publish_callback; + } + break; + } + case BLE_MESH_MODEL_ID_LIGHT_LC_CLI: { + model->op = ((esp_ble_mesh_model_op_t *)light_lc_cli_op); + bt_mesh_light_lc_cli_t *cli = (bt_mesh_light_lc_cli_t *)model->user_data; + if (cli != NULL) { + cli->publish_status = btc_mesh_light_client_publish_callback; + } + break; + } + case BLE_MESH_MODEL_ID_SENSOR_CLI: { + model->op = ((esp_ble_mesh_model_op_t *)sensor_cli_op); + bt_mesh_sensor_client_t *cli = (bt_mesh_sensor_client_t *)model->user_data; + if (cli != NULL) { + cli->publish_status = btc_mesh_sensor_client_publish_callback; + } + break; + } + case BLE_MESH_MODEL_ID_TIME_CLI: { + model->op = ((esp_ble_mesh_model_op_t *)time_cli_op); + bt_mesh_time_scene_client_t *cli = (bt_mesh_time_scene_client_t *)model->user_data; + if (cli != NULL) { + cli->publish_status = btc_mesh_time_scene_client_publish_callback; + } + break; + } + case BLE_MESH_MODEL_ID_SCENE_CLI: { + model->op = ((esp_ble_mesh_model_op_t *)scene_cli_op); + bt_mesh_time_scene_client_t *cli = (bt_mesh_time_scene_client_t *)model->user_data; + if (cli != NULL) { + cli->publish_status = btc_mesh_time_scene_client_publish_callback; + } + break; + } + case BLE_MESH_MODEL_ID_SCHEDULER_CLI: { + model->op = ((esp_ble_mesh_model_op_t *)scheduler_cli_op); + bt_mesh_time_scene_client_t *cli = (bt_mesh_time_scene_client_t *)model->user_data; + if (cli != NULL) { + cli->publish_status = btc_mesh_time_scene_client_publish_callback; + } + break; + } + default: { + goto add_model_op; + } + } + return; + +add_model_op: + if (model->pub) { + model->pub->update = (esp_ble_mesh_cb_t)btc_model_publish_update; + } + op = model->op; + while (op != NULL && op->opcode != 0) { + op->param_cb = (esp_ble_mesh_cb_t)btc_ble_mesh_server_model_op_cb; + op++; + } + return; +} + +void btc_mesh_prov_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_prov_cb_param_t param = {0}; + btc_ble_mesh_prov_args_t *arg = NULL; + uint8_t act; + + if (!msg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + arg = (btc_ble_mesh_prov_args_t *)(msg->arg); + + switch (msg->act) { + case BTC_BLE_MESH_ACT_MESH_INIT: { + int err_code; + for (int i = 0; i < arg->mesh_init.comp->element_count; i++) { + esp_ble_mesh_elem_t *elem = &arg->mesh_init.comp->elements[i]; + /* For SIG models */ + for (int j = 0; j < elem->sig_model_count; j++) { + esp_ble_mesh_model_t *sig_model = &elem->sig_models[j]; + /* The opcode of sig model should be 1 or 2 bytes. */ + if (sig_model && sig_model->op && (sig_model->op->opcode >= 0x10000)) { + err_code = -EINVAL; + btc_prov_register_complete_cb(err_code); + return; + } + btc_mesh_model_op_add(sig_model); + } + /* For vendor models */ + for (int k = 0; k < elem->vnd_model_count; k++) { + esp_ble_mesh_model_t *vnd_model = &elem->vnd_models[k]; + /* The opcode of vendor model should be 3 bytes. */ + if (vnd_model && vnd_model->op && vnd_model->op->opcode < 0x10000) { + err_code = -EINVAL; + btc_prov_register_complete_cb(err_code); + return; + } + btc_mesh_model_op_add(vnd_model); + } + } +#if CONFIG_BLE_MESH_NODE + arg->mesh_init.prov->oob_pub_key_cb = (esp_ble_mesh_cb_t)btc_oob_pub_key_cb; + arg->mesh_init.prov->output_num_cb = (esp_ble_mesh_cb_t)btc_output_number_cb; + arg->mesh_init.prov->output_str_cb = (esp_ble_mesh_cb_t)btc_output_string_cb; + arg->mesh_init.prov->input_cb = (esp_ble_mesh_cb_t)btc_input_cb; + arg->mesh_init.prov->link_open_cb = (esp_ble_mesh_cb_t)btc_link_open_cb; + arg->mesh_init.prov->link_close_cb = (esp_ble_mesh_cb_t)btc_link_close_cb; + arg->mesh_init.prov->complete_cb = (esp_ble_mesh_cb_t)btc_complete_cb; + arg->mesh_init.prov->reset_cb = (esp_ble_mesh_cb_t)btc_reset_cb; +#endif /* CONFIG_BLE_MESH_NODE */ +#if (CONFIG_BLE_MESH_PROVISIONER) + arg->mesh_init.prov->provisioner_prov_read_oob_pub_key = (esp_ble_mesh_cb_t)btc_provisioner_prov_read_oob_pub_key_cb; + arg->mesh_init.prov->provisioner_prov_input = (esp_ble_mesh_cb_t)btc_provisioner_prov_input_cb; + arg->mesh_init.prov->provisioner_prov_output = (esp_ble_mesh_cb_t)btc_provisioner_prov_output_cb; + arg->mesh_init.prov->provisioner_link_open = (esp_ble_mesh_cb_t)btc_provisioner_link_open_cb; + arg->mesh_init.prov->provisioner_link_close = (esp_ble_mesh_cb_t)btc_provisioner_link_close_cb; + arg->mesh_init.prov->provisioner_prov_comp = (esp_ble_mesh_cb_t)btc_provisioner_prov_complete_cb; + bt_mesh_prov_adv_pkt_cb_register(btc_provisioner_recv_unprov_adv_pkt_cb); +#endif /* CONFIG_BLE_MESH_PROVISIONER */ + err_code = bt_mesh_init((struct bt_mesh_prov *)arg->mesh_init.prov, + (struct bt_mesh_comp *)arg->mesh_init.comp); + /* Give the semaphore when BLE Mesh initialization is finished. */ + xSemaphoreGive(arg->mesh_init.semaphore); + btc_prov_register_complete_cb(err_code); + return; + } +#if CONFIG_BLE_MESH_NODE + case BTC_BLE_MESH_ACT_PROV_ENABLE: + LOG_DEBUG("%s, BTC_BLE_MESH_ACT_PROV_ENABLE, bearers = %d", __func__, arg->node_prov_enable.bearers); + act = ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT; + param.node_prov_enable_comp.err_code = bt_mesh_prov_enable(arg->node_prov_enable.bearers); + break; + case BTC_BLE_MESH_ACT_PROV_DISABLE: + LOG_DEBUG("%s, BTC_BLE_MESH_ACT_PROV_DISABLE, bearers = %d", __func__, arg->node_prov_disable.bearers); + act = ESP_BLE_MESH_NODE_PROV_DISABLE_COMP_EVT; + param.node_prov_disable_comp.err_code = bt_mesh_prov_disable(arg->node_prov_disable.bearers); + break; + case BTC_BLE_MESH_ACT_NODE_RESET: + LOG_DEBUG("%s, BTC_BLE_MESH_ACT_NODE_RESET", __func__); + bt_mesh_reset(); + return; + case BTC_BLE_MESH_ACT_SET_OOB_PUB_KEY: + act = ESP_BLE_MESH_NODE_PROV_SET_OOB_PUB_KEY_COMP_EVT; + param.node_prov_set_oob_pub_key_comp.err_code = + bt_mesh_set_oob_pub_key(arg->set_oob_pub_key.pub_key_x, + arg->set_oob_pub_key.pub_key_y, + arg->set_oob_pub_key.private_key); + break; + case BTC_BLE_MESH_ACT_INPUT_NUMBER: + act = ESP_BLE_MESH_NODE_PROV_INPUT_NUMBER_COMP_EVT; + param.node_prov_input_num_comp.err_code = bt_mesh_input_number(arg->input_number.number); + break; + case BTC_BLE_MESH_ACT_INPUT_STRING: + act = ESP_BLE_MESH_NODE_PROV_INPUT_STRING_COMP_EVT; + param.node_prov_input_str_comp.err_code = bt_mesh_input_string(arg->input_string.string); + break; + case BTC_BLE_MESH_ACT_SET_DEVICE_NAME: + act = ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT; + param.node_set_unprov_dev_name_comp.err_code = bt_mesh_set_device_name(arg->set_device_name.name); + break; +#if defined(CONFIG_BLE_MESH_GATT_PROXY) + case BTC_BLE_MESH_ACT_PROXY_IDENTITY_ENABLE: + act = ESP_BLE_MESH_NODE_PROXY_IDENTITY_ENABLE_COMP_EVT; + param.node_proxy_identity_enable_comp.err_code = bt_mesh_proxy_identity_enable(); + break; + case BTC_BLE_MESH_ACT_PROXY_GATT_ENABLE: + act = ESP_BLE_MESH_NODE_PROXY_GATT_ENABLE_COMP_EVT; + param.node_proxy_gatt_enable_comp.err_code = bt_mesh_proxy_gatt_enable(); + break; + case BTC_BLE_MESH_ACT_PROXY_GATT_DISABLE: + act = ESP_BLE_MESH_NODE_PROXY_GATT_DISABLE_COMP_EVT; + param.node_proxy_gatt_disable_comp.err_code = bt_mesh_proxy_gatt_disable(); + break; +#endif /* CONFIG_BLE_MESH_GATT_PROXY */ +#endif /* CONFIG_BLE_MESH_NODE */ +#if (CONFIG_BLE_MESH_PROVISIONER) + case BTC_BLE_MESH_ACT_PROVISIONER_READ_OOB_PUB_KEY: + act = ESP_BLE_MESH_PROVISIONER_PROV_READ_OOB_PUB_KEY_COMP_EVT; + param.provisioner_prov_read_oob_pub_key_comp.err_code = + bt_mesh_prov_read_oob_pub_key(arg->provisioner_read_oob_pub_key.link_idx, + arg->provisioner_read_oob_pub_key.pub_key_x, + arg->provisioner_read_oob_pub_key.pub_key_y); + break; + case BTC_BLE_MESH_ACT_PROVISIONER_INPUT_STR: + act = ESP_BLE_MESH_PROVISIONER_PROV_INPUT_STRING_COMP_EVT; + param.provisioner_prov_input_str_comp.err_code = + bt_mesh_prov_set_oob_input_data(arg->provisioner_input_str.link_idx, + (const u8_t *)&arg->provisioner_input_str.string, false); + break; + case BTC_BLE_MESH_ACT_PROVISIONER_INPUT_NUM: + act = ESP_BLE_MESH_PROVISIONER_PROV_INPUT_NUMBER_COMP_EVT; + param.provisioner_prov_input_num_comp.err_code = + bt_mesh_prov_set_oob_input_data(arg->provisioner_input_num.link_idx, + (const u8_t *)&arg->provisioner_input_num.number, true); + break; + case BTC_BLE_MESH_ACT_PROVISIONER_ENABLE: + act = ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT; + param.provisioner_prov_enable_comp.err_code = + bt_mesh_provisioner_enable(arg->provisioner_enable.bearers); + break; + case BTC_BLE_MESH_ACT_PROVISIONER_DISABLE: + act = ESP_BLE_MESH_PROVISIONER_PROV_DISABLE_COMP_EVT; + param.provisioner_prov_disable_comp.err_code = + bt_mesh_provisioner_disable(arg->provisioner_disable.bearers); + break; + case BTC_BLE_MESH_ACT_PROVISIONER_DEV_ADD: { + struct bt_mesh_unprov_dev_add add_dev = {0}; + add_dev.addr_type = arg->provisioner_dev_add.add_dev.addr_type; + add_dev.oob_info = arg->provisioner_dev_add.add_dev.oob_info; + add_dev.bearer = arg->provisioner_dev_add.add_dev.bearer; + memcpy(add_dev.addr, arg->provisioner_dev_add.add_dev.addr, 6); + memcpy(add_dev.uuid, arg->provisioner_dev_add.add_dev.uuid, 16); + act = ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT; + param.provisioner_add_unprov_dev_comp.err_code = + bt_mesh_provisioner_add_unprov_dev(&add_dev, arg->provisioner_dev_add.flags); + break; + } + case BTC_BLE_MESH_ACT_PROVISIONER_DEV_DEL: { + struct bt_mesh_device_delete del_dev = {0}; + if (arg->provisioner_dev_del.del_dev.flag & DEL_DEV_ADDR_FLAG) { + del_dev.addr_type = arg->provisioner_dev_del.del_dev.addr_type; + memcpy(del_dev.addr, arg->provisioner_dev_del.del_dev.addr, 6); + } else if (arg->provisioner_dev_del.del_dev.flag & DEL_DEV_UUID_FLAG) { + memcpy(del_dev.uuid, arg->provisioner_dev_del.del_dev.uuid, 16); + } + act = ESP_BLE_MESH_PROVISIONER_DELETE_DEV_COMP_EVT; + param.provisioner_delete_dev_comp.err_code = bt_mesh_provisioner_delete_device(&del_dev); + break; + } + case BTC_BLE_MESH_ACT_PROVISIONER_SET_DEV_UUID_MATCH: + act = ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT; + param.provisioner_set_dev_uuid_match_comp.err_code = + bt_mesh_provisioner_set_dev_uuid_match(arg->set_dev_uuid_match.offset, + arg->set_dev_uuid_match.match_len, + arg->set_dev_uuid_match.match_val, + arg->set_dev_uuid_match.prov_after_match); + break; + case BTC_BLE_MESH_ACT_PROVISIONER_SET_PROV_DATA_INFO: { + struct bt_mesh_prov_data_info info = {0}; + info.flag = arg->set_prov_data_info.prov_data.flag; + if (arg->set_prov_data_info.prov_data.flag & PROV_DATA_NET_IDX_FLAG) { + info.net_idx = arg->set_prov_data_info.prov_data.net_idx; + } else if (arg->set_prov_data_info.prov_data.flag & PROV_DATA_FLAGS_FLAG) { + info.flags = arg->set_prov_data_info.prov_data.flags; + } else if (arg->set_prov_data_info.prov_data.flag & PROV_DATA_IV_INDEX_FLAG) { + info.iv_index = arg->set_prov_data_info.prov_data.iv_index; + } + act = ESP_BLE_MESH_PROVISIONER_SET_PROV_DATA_INFO_COMP_EVT; + param.provisioner_set_prov_data_info_comp.err_code = + bt_mesh_provisioner_set_prov_data_info(&info); + break; + } + case BTC_BLE_MESH_ACT_PROVISIONER_SET_NODE_NAME: + act = ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT; + param.provisioner_set_node_name_comp.err_code = + bt_mesh_provisioner_set_node_name(arg->set_node_name.index, arg->set_node_name.name); + if (param.provisioner_set_node_name_comp.err_code) { + param.provisioner_set_node_name_comp.node_index = ESP_BLE_MESH_INVALID_NODE_INDEX; + } else { + param.provisioner_set_node_name_comp.node_index = arg->set_node_name.index; + } + break; + case BTC_BLE_MESH_ACT_PROVISIONER_SET_LOCAL_APP_KEY: { + const u8_t *app_key = NULL; + const u8_t zero[16] = {0}; + if (memcmp(arg->add_local_app_key.app_key, zero, 16)) { + app_key = arg->add_local_app_key.app_key; + } + act = ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT; + param.provisioner_add_app_key_comp.err_code = + bt_mesh_provisioner_local_app_key_add(app_key, arg->add_local_app_key.net_idx, + &arg->add_local_app_key.app_idx); + if (param.provisioner_add_app_key_comp.err_code) { + param.provisioner_add_app_key_comp.app_idx = ESP_BLE_MESH_KEY_UNUSED; + } else { + param.provisioner_add_app_key_comp.app_idx = arg->add_local_app_key.app_idx; + } + break; + } + case BTC_BLE_MESH_ACT_PROVISIONER_BIND_LOCAL_MOD_APP: + act = ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT; + param.provisioner_bind_app_key_to_model_comp.err_code = + bt_mesh_provisioner_bind_local_model_app_idx(arg->local_mod_app_bind.elem_addr, + arg->local_mod_app_bind.model_id, + arg->local_mod_app_bind.cid, + arg->local_mod_app_bind.app_idx); + break; + case BTC_BLE_MESH_ACT_PROVISIONER_ADD_LOCAL_NET_KEY: { + const u8_t *net_key = NULL; + const u8_t zero[16] = {0}; + if (memcmp(arg->add_local_net_key.net_key, zero, 16)) { + net_key = arg->add_local_net_key.net_key; + } + act = ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_NET_KEY_COMP_EVT; + param.provisioner_add_net_key_comp.err_code = + bt_mesh_provisioner_local_net_key_add(net_key, &arg->add_local_net_key.net_idx); + if (param.provisioner_add_net_key_comp.err_code) { + param.provisioner_add_net_key_comp.net_idx = ESP_BLE_MESH_KEY_UNUSED; + } else { + param.provisioner_add_net_key_comp.net_idx = arg->add_local_net_key.net_idx; + } + break; + } +#endif /* CONFIG_BLE_MESH_PROVISIONER */ +#if (CONFIG_BLE_MESH_FAST_PROV) + case BTC_BLE_MESH_ACT_SET_FAST_PROV_INFO: + act = ESP_BLE_MESH_SET_FAST_PROV_INFO_COMP_EVT; + param.set_fast_prov_info_comp.status_unicast = + bt_mesh_set_fast_prov_unicast_addr_range(arg->set_fast_prov_info.unicast_min, + arg->set_fast_prov_info.unicast_max); + param.set_fast_prov_info_comp.status_net_idx = + bt_mesh_set_fast_prov_net_idx(arg->set_fast_prov_info.net_idx); + bt_mesh_set_fast_prov_flags_iv_index(arg->set_fast_prov_info.flags, + arg->set_fast_prov_info.iv_index); + param.set_fast_prov_info_comp.status_match = + bt_mesh_provisioner_set_dev_uuid_match(arg->set_fast_prov_info.offset, + arg->set_fast_prov_info.match_len, + arg->set_fast_prov_info.match_val, false); + break; + case BTC_BLE_MESH_ACT_SET_FAST_PROV_ACTION: + act = ESP_BLE_MESH_SET_FAST_PROV_ACTION_COMP_EVT; + param.set_fast_prov_action_comp.status_action = + bt_mesh_set_fast_prov_action(arg->set_fast_prov_action.action); + break; +#endif /* (CONFIG_BLE_MESH_FAST_PROV) */ + default: + LOG_WARN("%s, Invalid msg->act %d", __func__, msg->act); + return; + } + + btc_prov_set_complete_cb(¶m, act); + return; +} + +void btc_mesh_model_call_handler(btc_msg_t *msg) +{ + btc_ble_mesh_model_args_t *arg = NULL; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_model_args_t *)(msg->arg); + + switch (msg->act) { + case BTC_BLE_MESH_ACT_MODEL_PUBLISH: { + if (arg->model_publish.device_role == PROVISIONER) { + bt_mesh_role_param_t common = {0}; + common.model = (struct bt_mesh_model *)(arg->model_publish.model); + common.role = arg->model_publish.device_role; + if (bt_mesh_set_model_role(&common)) { + LOG_ERROR("%s, Failed to set model role", __func__); + return; + } + } + int err = bt_mesh_model_publish((struct bt_mesh_model *)arg->model_publish.model); + btc_ble_mesh_model_publish_comp_cb(arg->model_publish.model, err); + break; + } + case BTC_BLE_MESH_ACT_SERVER_MODEL_SEND: { + /* arg->model_send.length contains opcode & message, 8 is used for TransMIC */ + struct net_buf_simple *buf = bt_mesh_alloc_buf(arg->model_send.length + 8); + if (!buf) { + LOG_ERROR("%s, Failed to allocate memory", __func__); + return; + } + net_buf_simple_add_mem(buf, arg->model_send.data, arg->model_send.length); + arg->model_send.ctx->srv_send = true; + int err = bt_mesh_model_send((struct bt_mesh_model *)arg->model_send.model, + (struct bt_mesh_msg_ctx *)arg->model_send.ctx, + buf, NULL, NULL); + bt_mesh_free_buf(buf); + btc_ble_mesh_model_send_comp_cb(arg->model_send.model, arg->model_send.ctx, + arg->model_send.opcode, err); + break; + } + case BTC_BLE_MESH_ACT_CLIENT_MODEL_SEND: { + bt_mesh_role_param_t common = {0}; + /* arg->model_send.length contains opcode & message, 8 is used for TransMIC */ + struct net_buf_simple *buf = bt_mesh_alloc_buf(arg->model_send.length + 8); + if (!buf) { + LOG_ERROR("%s, Failed to allocate memory", __func__); + return; + } + net_buf_simple_add_mem(buf, arg->model_send.data, arg->model_send.length); + arg->model_send.ctx->srv_send = false; + common.model = (struct bt_mesh_model *)(arg->model_send.model); + common.role = arg->model_send.device_role; + if (bt_mesh_set_model_role(&common)) { + LOG_ERROR("%s, Failed to set model role", __func__); + return; + } + int err = bt_mesh_client_send_msg((struct bt_mesh_model *)arg->model_send.model, + arg->model_send.opcode, + (struct bt_mesh_msg_ctx *)arg->model_send.ctx, buf, + btc_client_model_timeout_cb, arg->model_send.msg_timeout, + arg->model_send.need_rsp, NULL, NULL); + bt_mesh_free_buf(buf); + btc_ble_mesh_model_send_comp_cb(arg->model_send.model, arg->model_send.ctx, + arg->model_send.opcode, err); + break; + } + default: + LOG_WARN("%s, Unknown msg->act %d", __func__, msg->act); + break; + } + + btc_ble_mesh_prov_arg_deep_free(msg); +} + +void btc_mesh_model_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_model_cb_param_t *param = NULL; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + param = (esp_ble_mesh_model_cb_param_t *)(msg->arg); + + if (msg->act < ESP_BLE_MESH_MODEL_EVT_MAX) { + btc_ble_mesh_model_cb_to_app(msg->act, param); + } else { + LOG_ERROR("%s, Unknown msg->act = %d", __func__, msg->act); + } + + btc_ble_mesh_free_req_data(msg); +} + +void btc_mesh_prov_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_prov_cb_param_t *param = NULL; + + if (!msg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + param = (esp_ble_mesh_prov_cb_param_t *)(msg->arg); + + if (msg->act < ESP_BLE_MESH_PROV_EVT_MAX) { + btc_ble_mesh_cb_to_app(msg->act, param); + } else { + LOG_ERROR("%s, Unknown msg->act = %d", __func__, msg->act); + } +} diff --git a/components/bt/ble_mesh/btc/btc_ble_mesh_sensor_model.c b/components/bt/ble_mesh/btc/btc_ble_mesh_sensor_model.c new file mode 100644 index 0000000000..53d773842f --- /dev/null +++ b/components/bt/ble_mesh/btc/btc_ble_mesh_sensor_model.c @@ -0,0 +1,632 @@ +// Copyright 2017-2018 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 +#include + +#include "btc/btc_manage.h" +#include "osi/allocator.h" + +#include "sensor_client.h" +#include "btc_ble_mesh_sensor_model.h" +#include "esp_ble_mesh_sensor_model_api.h" + +static inline void btc_ble_mesh_cb_to_app(esp_ble_mesh_sensor_client_cb_event_t event, + esp_ble_mesh_sensor_client_cb_param_t *param) +{ + esp_ble_mesh_sensor_client_cb_t btc_mesh_cb = (esp_ble_mesh_sensor_client_cb_t)btc_profile_cb_get(BTC_PID_SENSOR_CLIENT); + if (btc_mesh_cb) { + btc_mesh_cb(event, param); + } +} + +void btc_ble_mesh_sensor_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_sensor_client_args_t *dst = (btc_ble_mesh_sensor_client_args_t *)p_dest; + btc_ble_mesh_sensor_client_args_t *src = (btc_ble_mesh_sensor_client_args_t *)p_src; + u32_t opcode; + u16_t length; + + if (!msg || !dst || !src) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_SENSOR_CLIENT_GET_STATE: { + dst->sensor_client_get_state.params = (esp_ble_mesh_client_common_param_t *)osi_malloc(sizeof(esp_ble_mesh_client_common_param_t)); + dst->sensor_client_get_state.get_state = (esp_ble_mesh_sensor_client_get_state_t *)osi_malloc(sizeof(esp_ble_mesh_sensor_client_get_state_t)); + if (dst->sensor_client_get_state.params && dst->sensor_client_get_state.get_state) { + memcpy(dst->sensor_client_get_state.params, src->sensor_client_get_state.params, + sizeof(esp_ble_mesh_client_common_param_t)); + memcpy(dst->sensor_client_get_state.get_state, src->sensor_client_get_state.get_state, + sizeof(esp_ble_mesh_sensor_client_get_state_t)); + + opcode = src->sensor_client_get_state.params->opcode; + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET: + if (src->sensor_client_get_state.get_state->column_get.raw_value_x) { + length = src->sensor_client_get_state.get_state->column_get.raw_value_x->len; + dst->sensor_client_get_state.get_state->column_get.raw_value_x = bt_mesh_alloc_buf(length); + if (!dst->sensor_client_get_state.get_state->column_get.raw_value_x) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(dst->sensor_client_get_state.get_state->column_get.raw_value_x, + src->sensor_client_get_state.get_state->column_get.raw_value_x->data, + src->sensor_client_get_state.get_state->column_get.raw_value_x->len); + } + break; + case ESP_BLE_MESH_MODEL_OP_SENSOR_SERIES_GET: + if (src->sensor_client_get_state.get_state->series_get.raw_value_x1) { + length = src->sensor_client_get_state.get_state->series_get.raw_value_x1->len; + dst->sensor_client_get_state.get_state->series_get.raw_value_x1 = bt_mesh_alloc_buf(length); + if (!dst->sensor_client_get_state.get_state->series_get.raw_value_x1) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(dst->sensor_client_get_state.get_state->series_get.raw_value_x1, + src->sensor_client_get_state.get_state->series_get.raw_value_x1->data, + src->sensor_client_get_state.get_state->series_get.raw_value_x1->len); + } + if (src->sensor_client_get_state.get_state->series_get.raw_value_x2) { + length = src->sensor_client_get_state.get_state->series_get.raw_value_x2->len; + dst->sensor_client_get_state.get_state->series_get.raw_value_x2 = bt_mesh_alloc_buf(length); + if (!dst->sensor_client_get_state.get_state->series_get.raw_value_x2) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(dst->sensor_client_get_state.get_state->series_get.raw_value_x2, + src->sensor_client_get_state.get_state->series_get.raw_value_x2->data, + src->sensor_client_get_state.get_state->series_get.raw_value_x2->len); + } + break; + default: + break; + } + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + break; + } + case BTC_BLE_MESH_ACT_SENSOR_CLIENT_SET_STATE: { + dst->sensor_client_set_state.params = (esp_ble_mesh_client_common_param_t *)osi_malloc(sizeof(esp_ble_mesh_client_common_param_t)); + dst->sensor_client_set_state.set_state = (esp_ble_mesh_sensor_client_set_state_t *)osi_malloc(sizeof(esp_ble_mesh_sensor_client_set_state_t)); + if (dst->sensor_client_set_state.params && dst->sensor_client_set_state.set_state) { + memcpy(dst->sensor_client_set_state.params, src->sensor_client_set_state.params, + sizeof(esp_ble_mesh_client_common_param_t)); + memcpy(dst->sensor_client_set_state.set_state, src->sensor_client_set_state.set_state, + sizeof(esp_ble_mesh_sensor_client_set_state_t)); + + opcode = src->sensor_client_set_state.params->opcode; + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET: + if (src->sensor_client_set_state.set_state->cadence_set.status_trigger_delta_down) { + length = src->sensor_client_set_state.set_state->cadence_set.status_trigger_delta_down->len; + dst->sensor_client_set_state.set_state->cadence_set.status_trigger_delta_down = bt_mesh_alloc_buf(length); + if (!dst->sensor_client_set_state.set_state->cadence_set.status_trigger_delta_down) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(dst->sensor_client_set_state.set_state->cadence_set.status_trigger_delta_down, + src->sensor_client_set_state.set_state->cadence_set.status_trigger_delta_down->data, + src->sensor_client_set_state.set_state->cadence_set.status_trigger_delta_down->len); + } + if (src->sensor_client_set_state.set_state->cadence_set.status_trigger_delta_up) { + length = src->sensor_client_set_state.set_state->cadence_set.status_trigger_delta_up->len; + dst->sensor_client_set_state.set_state->cadence_set.status_trigger_delta_up = bt_mesh_alloc_buf(length); + if (!dst->sensor_client_set_state.set_state->cadence_set.status_trigger_delta_up) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(dst->sensor_client_set_state.set_state->cadence_set.status_trigger_delta_up, + src->sensor_client_set_state.set_state->cadence_set.status_trigger_delta_up->data, + src->sensor_client_set_state.set_state->cadence_set.status_trigger_delta_up->len); + } + if (src->sensor_client_set_state.set_state->cadence_set.fast_cadence_low) { + length = src->sensor_client_set_state.set_state->cadence_set.fast_cadence_low->len; + dst->sensor_client_set_state.set_state->cadence_set.fast_cadence_low = bt_mesh_alloc_buf(length); + if (!dst->sensor_client_set_state.set_state->cadence_set.fast_cadence_low) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(dst->sensor_client_set_state.set_state->cadence_set.fast_cadence_low, + src->sensor_client_set_state.set_state->cadence_set.fast_cadence_low->data, + src->sensor_client_set_state.set_state->cadence_set.fast_cadence_low->len); + } + if (src->sensor_client_set_state.set_state->cadence_set.fast_cadence_high) { + length = src->sensor_client_set_state.set_state->cadence_set.fast_cadence_high->len; + dst->sensor_client_set_state.set_state->cadence_set.fast_cadence_high = bt_mesh_alloc_buf(length); + if (!dst->sensor_client_set_state.set_state->cadence_set.fast_cadence_high) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(dst->sensor_client_set_state.set_state->cadence_set.fast_cadence_high, + src->sensor_client_set_state.set_state->cadence_set.fast_cadence_high->data, + src->sensor_client_set_state.set_state->cadence_set.fast_cadence_high->len); + } + break; + case ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET: + if (src->sensor_client_set_state.set_state->setting_set.sensor_setting_raw) { + length = src->sensor_client_set_state.set_state->setting_set.sensor_setting_raw->len; + dst->sensor_client_set_state.set_state->setting_set.sensor_setting_raw = bt_mesh_alloc_buf(length); + if (!dst->sensor_client_set_state.set_state->setting_set.sensor_setting_raw) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(dst->sensor_client_set_state.set_state->setting_set.sensor_setting_raw, + src->sensor_client_set_state.set_state->setting_set.sensor_setting_raw->data, + src->sensor_client_set_state.set_state->setting_set.sensor_setting_raw->len); + } + break; + default: + break; + } + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + break; + } + default: + LOG_DEBUG("%s, Unknown deep copy act %d", __func__, msg->act); + break; + } +} + +static void btc_ble_mesh_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_sensor_client_cb_param_t *p_dest_data = (esp_ble_mesh_sensor_client_cb_param_t *)p_dest; + esp_ble_mesh_sensor_client_cb_param_t *p_src_data = (esp_ble_mesh_sensor_client_cb_param_t *)p_src; + u32_t opcode; + u16_t length; + + if (!msg || !p_src_data || !p_dest_data) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case ESP_BLE_MESH_SENSOR_CLIENT_GET_STATE_EVT: + case ESP_BLE_MESH_SENSOR_CLIENT_SET_STATE_EVT: + case ESP_BLE_MESH_SENSOR_CLIENT_PUBLISH_EVT: + if (p_src_data->params) { + opcode = p_src_data->params->opcode; + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET: + case ESP_BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS: + if (p_src_data->status_cb.descriptor_status.descriptor) { + length = p_src_data->status_cb.descriptor_status.descriptor->len; + p_dest_data->status_cb.descriptor_status.descriptor = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.descriptor_status.descriptor) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.descriptor_status.descriptor, + p_src_data->status_cb.descriptor_status.descriptor->data, + p_src_data->status_cb.descriptor_status.descriptor->len); + } + break; + case ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET: + case ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET: + case ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS: + if (p_src_data->status_cb.cadence_status.sensor_cadence_value) { + length = p_src_data->status_cb.cadence_status.sensor_cadence_value->len; + p_dest_data->status_cb.cadence_status.sensor_cadence_value = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.cadence_status.sensor_cadence_value) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.cadence_status.sensor_cadence_value, + p_src_data->status_cb.cadence_status.sensor_cadence_value->data, + p_src_data->status_cb.cadence_status.sensor_cadence_value->len); + } + break; + case ESP_BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET: + case ESP_BLE_MESH_MODEL_OP_SENSOR_SETTINGS_STATUS: + if (p_src_data->status_cb.settings_status.sensor_setting_property_ids) { + length = p_src_data->status_cb.settings_status.sensor_setting_property_ids->len; + p_dest_data->status_cb.settings_status.sensor_setting_property_ids = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.settings_status.sensor_setting_property_ids) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.settings_status.sensor_setting_property_ids, + p_src_data->status_cb.settings_status.sensor_setting_property_ids->data, + p_src_data->status_cb.settings_status.sensor_setting_property_ids->len); + } + break; + case ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_GET: + case ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET: + case ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_STATUS: + if (p_src_data->status_cb.setting_status.sensor_setting_raw) { + length = p_src_data->status_cb.setting_status.sensor_setting_raw->len; + p_dest_data->status_cb.setting_status.sensor_setting_raw = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.setting_status.sensor_setting_raw) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.setting_status.sensor_setting_raw, + p_src_data->status_cb.setting_status.sensor_setting_raw->data, + p_src_data->status_cb.setting_status.sensor_setting_raw->len); + } + break; + case ESP_BLE_MESH_MODEL_OP_SENSOR_GET: + case ESP_BLE_MESH_MODEL_OP_SENSOR_STATUS: + if (p_src_data->status_cb.sensor_status.marshalled_sensor_data) { + length = p_src_data->status_cb.sensor_status.marshalled_sensor_data->len; + p_dest_data->status_cb.sensor_status.marshalled_sensor_data = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.sensor_status.marshalled_sensor_data) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.sensor_status.marshalled_sensor_data, + p_src_data->status_cb.sensor_status.marshalled_sensor_data->data, + p_src_data->status_cb.sensor_status.marshalled_sensor_data->len); + } + break; + case ESP_BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET: + case ESP_BLE_MESH_MODEL_OP_SENSOR_COLUMN_STATUS: + if (p_src_data->status_cb.column_status.sensor_column_value) { + length = p_src_data->status_cb.column_status.sensor_column_value->len; + p_dest_data->status_cb.column_status.sensor_column_value = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.column_status.sensor_column_value) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.column_status.sensor_column_value, + p_src_data->status_cb.column_status.sensor_column_value->data, + p_src_data->status_cb.column_status.sensor_column_value->len); + } + break; + case ESP_BLE_MESH_MODEL_OP_SENSOR_SERIES_GET: + case ESP_BLE_MESH_MODEL_OP_SENSOR_SERIES_STATUS: + if (p_src_data->status_cb.series_status.sensor_series_value) { + length = p_src_data->status_cb.series_status.sensor_series_value->len; + p_dest_data->status_cb.series_status.sensor_series_value = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.series_status.sensor_series_value) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.series_status.sensor_series_value, + p_src_data->status_cb.series_status.sensor_series_value->data, + p_src_data->status_cb.series_status.sensor_series_value->len); + } + break; + default: + break; + } + } + case ESP_BLE_MESH_SENSOR_CLIENT_TIMEOUT_EVT: + if (p_src_data->params) { + p_dest_data->params = osi_malloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (p_dest_data->params) { + memcpy(p_dest_data->params, p_src_data->params, sizeof(esp_ble_mesh_client_common_param_t)); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + } + break; + default: + break; + } +} + +static void btc_ble_mesh_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_sensor_client_cb_param_t *arg = NULL; + u32_t opcode; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_sensor_client_cb_param_t *)(msg->arg); + + switch (msg->act) { + case ESP_BLE_MESH_SENSOR_CLIENT_GET_STATE_EVT: + case ESP_BLE_MESH_SENSOR_CLIENT_SET_STATE_EVT: + case ESP_BLE_MESH_SENSOR_CLIENT_PUBLISH_EVT: + if (arg->params) { + opcode = arg->params->opcode; + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET: + case ESP_BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS: + bt_mesh_free_buf(arg->status_cb.descriptor_status.descriptor); + break; + case ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET: + case ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET: + case ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS: + bt_mesh_free_buf(arg->status_cb.cadence_status.sensor_cadence_value); + break; + case ESP_BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET: + case ESP_BLE_MESH_MODEL_OP_SENSOR_SETTINGS_STATUS: + bt_mesh_free_buf(arg->status_cb.settings_status.sensor_setting_property_ids); + break; + case ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_GET: + case ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET: + case ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_STATUS: + bt_mesh_free_buf(arg->status_cb.setting_status.sensor_setting_raw); + break; + case ESP_BLE_MESH_MODEL_OP_SENSOR_GET: + case ESP_BLE_MESH_MODEL_OP_SENSOR_STATUS: + bt_mesh_free_buf(arg->status_cb.sensor_status.marshalled_sensor_data); + break; + case ESP_BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET: + case ESP_BLE_MESH_MODEL_OP_SENSOR_COLUMN_STATUS: + bt_mesh_free_buf(arg->status_cb.column_status.sensor_column_value); + break; + case ESP_BLE_MESH_MODEL_OP_SENSOR_SERIES_GET: + case ESP_BLE_MESH_MODEL_OP_SENSOR_SERIES_STATUS: + bt_mesh_free_buf(arg->status_cb.series_status.sensor_series_value); + break; + default: + break; + } + } + case ESP_BLE_MESH_SENSOR_CLIENT_TIMEOUT_EVT: + if (arg->params) { + osi_free(arg->params); + } + break; + default: + break; + } +} + +void btc_ble_mesh_sensor_client_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_sensor_client_args_t *arg = NULL; + u32_t opcode = 0; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_sensor_client_args_t *)(msg->arg); + + switch (msg->act) { + case BTC_BLE_MESH_ACT_SENSOR_CLIENT_GET_STATE: + if (arg->sensor_client_get_state.params) { + opcode = arg->sensor_client_get_state.params->opcode; + osi_free(arg->sensor_client_get_state.params); + } + if (arg->sensor_client_get_state.get_state) { + if (opcode) { + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET: + bt_mesh_free_buf(arg->sensor_client_get_state.get_state->column_get.raw_value_x); + break; + case ESP_BLE_MESH_MODEL_OP_SENSOR_SERIES_GET: + bt_mesh_free_buf(arg->sensor_client_get_state.get_state->series_get.raw_value_x1); + bt_mesh_free_buf(arg->sensor_client_get_state.get_state->series_get.raw_value_x2); + break; + default: + break; + } + } + osi_free(arg->sensor_client_get_state.get_state); + } + break; + case BTC_BLE_MESH_ACT_SENSOR_CLIENT_SET_STATE: + if (arg->sensor_client_set_state.params) { + opcode = arg->sensor_client_set_state.params->opcode; + osi_free(arg->sensor_client_set_state.params); + } + if (arg->sensor_client_set_state.set_state) { + if (opcode) { + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET: + bt_mesh_free_buf(arg->sensor_client_set_state.set_state->cadence_set.status_trigger_delta_down); + bt_mesh_free_buf(arg->sensor_client_set_state.set_state->cadence_set.status_trigger_delta_up); + bt_mesh_free_buf(arg->sensor_client_set_state.set_state->cadence_set.fast_cadence_low); + bt_mesh_free_buf(arg->sensor_client_set_state.set_state->cadence_set.fast_cadence_high); + break; + case ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET: + bt_mesh_free_buf(arg->sensor_client_set_state.set_state->setting_set.sensor_setting_raw); + break; + default: + break; + } + } + osi_free(arg->sensor_client_set_state.set_state); + } + break; + default: + break; + } + + return; +} + +static void btc_mesh_sensor_client_callback(esp_ble_mesh_sensor_client_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + LOG_DEBUG("%s", __func__); + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_SENSOR_CLIENT; + msg.act = act; + + btc_transfer_context(&msg, cb_params, + sizeof(esp_ble_mesh_sensor_client_cb_param_t), btc_ble_mesh_copy_req_data); +} + +void bt_mesh_callback_sensor_status_to_btc(u32_t opcode, u8_t evt_type, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const u8_t *val, size_t len) +{ + esp_ble_mesh_sensor_client_cb_param_t cb_params = {0}; + esp_ble_mesh_client_common_param_t params = {0}; + size_t length; + uint8_t act; + + if (!model || !ctx) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (evt_type) { + case 0x00: + act = ESP_BLE_MESH_SENSOR_CLIENT_GET_STATE_EVT; + break; + case 0x01: + act = ESP_BLE_MESH_SENSOR_CLIENT_SET_STATE_EVT; + break; + case 0x02: + act = ESP_BLE_MESH_SENSOR_CLIENT_PUBLISH_EVT; + break; + case 0x03: + act = ESP_BLE_MESH_SENSOR_CLIENT_TIMEOUT_EVT; + break; + default: + LOG_ERROR("%s, Unknown sensor client event type %d", __func__, evt_type); + return; + } + + params.opcode = opcode; + params.model = (esp_ble_mesh_model_t *)model; + params.ctx.net_idx = ctx->net_idx; + params.ctx.app_idx = ctx->app_idx; + params.ctx.addr = ctx->addr; + params.ctx.recv_ttl = ctx->recv_ttl; + params.ctx.recv_op = ctx->recv_op; + params.ctx.recv_dst = ctx->recv_dst; + + cb_params.error_code = 0; + cb_params.params = ¶ms; + + if (val && len) { + length = (len <= sizeof(cb_params.status_cb)) ? len : sizeof(cb_params.status_cb); + memcpy(&cb_params.status_cb, val, length); + } + + btc_mesh_sensor_client_callback(&cb_params, act); +} + +void btc_mesh_sensor_client_publish_callback(u32_t opcode, struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) +{ + if (!model || !ctx || !buf) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + bt_mesh_callback_sensor_status_to_btc(opcode, 0x02, model, ctx, buf->data, buf->len); +} + +void btc_mesh_sensor_client_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_sensor_client_cb_param_t sensor_client_cb = {0}; + esp_ble_mesh_client_common_param_t *params = NULL; + btc_ble_mesh_sensor_client_args_t *arg = NULL; + struct bt_mesh_common_param common = {0}; + bt_mesh_role_param_t role_param = {0}; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_sensor_client_args_t *)(msg->arg); + + switch (msg->act) { + case BTC_BLE_MESH_ACT_SENSOR_CLIENT_GET_STATE: { + params = arg->sensor_client_get_state.params; + role_param.model = (struct bt_mesh_model *)params->model; + role_param.role = params->msg_role; + if (bt_mesh_set_model_role(&role_param)) { + LOG_ERROR("%s, Failed to set model role", __func__); + return; + } + common.opcode = params->opcode; + common.model = (struct bt_mesh_model *)params->model; + common.ctx.net_idx = params->ctx.net_idx; + common.ctx.app_idx = params->ctx.app_idx; + common.ctx.addr = params->ctx.addr; + common.ctx.send_rel = params->ctx.send_rel; + common.ctx.send_ttl = params->ctx.send_ttl; + common.msg_timeout = params->msg_timeout; + + sensor_client_cb.params = arg->sensor_client_get_state.params; + sensor_client_cb.error_code = + bt_mesh_sensor_client_get_state(&common, + (void *)arg->sensor_client_get_state.get_state, + (void *)&sensor_client_cb.status_cb); + if (sensor_client_cb.error_code) { + /* If send failed, callback error_code to app layer immediately */ + btc_mesh_sensor_client_callback(&sensor_client_cb, + ESP_BLE_MESH_SENSOR_CLIENT_GET_STATE_EVT); + } + break; + } + case BTC_BLE_MESH_ACT_SENSOR_CLIENT_SET_STATE: { + params = arg->sensor_client_set_state.params; + role_param.model = (struct bt_mesh_model *)params->model; + role_param.role = params->msg_role; + if (bt_mesh_set_model_role(&role_param)) { + LOG_ERROR("%s, Failed to set model role", __func__); + return; + } + common.opcode = params->opcode; + common.model = (struct bt_mesh_model *)params->model; + common.ctx.net_idx = params->ctx.net_idx; + common.ctx.app_idx = params->ctx.app_idx; + common.ctx.addr = params->ctx.addr; + common.ctx.send_rel = params->ctx.send_rel; + common.ctx.send_ttl = params->ctx.send_ttl; + common.msg_timeout = params->msg_timeout; + + sensor_client_cb.params = arg->sensor_client_set_state.params; + sensor_client_cb.error_code = + bt_mesh_sensor_client_set_state(&common, + (void *)arg->sensor_client_set_state.set_state, + (void *)&sensor_client_cb.status_cb); + if (sensor_client_cb.error_code) { + /* If send failed, callback error_code to app layer immediately */ + btc_mesh_sensor_client_callback(&sensor_client_cb, + ESP_BLE_MESH_SENSOR_CLIENT_SET_STATE_EVT); + } + break; + } + default: + break; + } + + btc_ble_mesh_sensor_client_arg_deep_free(msg); +} + +void btc_mesh_sensor_client_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_sensor_client_cb_param_t *param = NULL; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + param = (esp_ble_mesh_sensor_client_cb_param_t *)(msg->arg); + + if (msg->act < ESP_BLE_MESH_SENSOR_CLIENT_EVT_MAX) { + btc_ble_mesh_cb_to_app(msg->act, param); + } else { + LOG_ERROR("%s, Unknown msg->act = %d", __func__, msg->act); + } + + btc_ble_mesh_free_req_data(msg); +} + diff --git a/components/bt/ble_mesh/btc/btc_ble_mesh_time_scene_model.c b/components/bt/ble_mesh/btc/btc_ble_mesh_time_scene_model.c new file mode 100644 index 0000000000..4c1a36905e --- /dev/null +++ b/components/bt/ble_mesh/btc/btc_ble_mesh_time_scene_model.c @@ -0,0 +1,383 @@ +// Copyright 2017-2018 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 +#include + +#include "btc/btc_manage.h" +#include "osi/allocator.h" + +#include "time_scene_client.h" +#include "btc_ble_mesh_time_scene_model.h" +#include "esp_ble_mesh_time_scene_model_api.h" + +static inline void btc_ble_mesh_cb_to_app(esp_ble_mesh_time_scene_client_cb_event_t event, + esp_ble_mesh_time_scene_client_cb_param_t *param) +{ + esp_ble_mesh_time_scene_client_cb_t btc_mesh_cb = (esp_ble_mesh_time_scene_client_cb_t)btc_profile_cb_get(BTC_PID_TIME_SCENE_CLIENT); + if (btc_mesh_cb) { + btc_mesh_cb(event, param); + } +} + +void btc_ble_mesh_time_scene_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_time_scene_client_args_t *dst = (btc_ble_mesh_time_scene_client_args_t *)p_dest; + btc_ble_mesh_time_scene_client_args_t *src = (btc_ble_mesh_time_scene_client_args_t *)p_src; + + if (!msg || !dst || !src) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_TIME_SCENE_CLIENT_GET_STATE: { + dst->time_scene_client_get_state.params = (esp_ble_mesh_client_common_param_t *)osi_malloc(sizeof(esp_ble_mesh_client_common_param_t)); + dst->time_scene_client_get_state.get_state = (esp_ble_mesh_time_scene_client_get_state_t *)osi_malloc(sizeof(esp_ble_mesh_time_scene_client_get_state_t)); + if (dst->time_scene_client_get_state.params && dst->time_scene_client_get_state.get_state) { + memcpy(dst->time_scene_client_get_state.params, src->time_scene_client_get_state.params, + sizeof(esp_ble_mesh_client_common_param_t)); + memcpy(dst->time_scene_client_get_state.get_state, src->time_scene_client_get_state.get_state, + sizeof(esp_ble_mesh_time_scene_client_get_state_t)); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + break; + } + case BTC_BLE_MESH_ACT_TIME_SCENE_CLIENT_SET_STATE: { + dst->time_scene_client_set_state.params = (esp_ble_mesh_client_common_param_t *)osi_malloc(sizeof(esp_ble_mesh_client_common_param_t)); + dst->time_scene_client_set_state.set_state = (esp_ble_mesh_time_scene_client_set_state_t *)osi_malloc(sizeof(esp_ble_mesh_time_scene_client_set_state_t)); + if (dst->time_scene_client_set_state.params && dst->time_scene_client_set_state.set_state) { + memcpy(dst->time_scene_client_set_state.params, src->time_scene_client_set_state.params, + sizeof(esp_ble_mesh_client_common_param_t)); + memcpy(dst->time_scene_client_set_state.set_state, src->time_scene_client_set_state.set_state, + sizeof(esp_ble_mesh_time_scene_client_set_state_t)); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + break; + } + default: + LOG_DEBUG("%s, Unknown deep copy act %d", __func__, msg->act); + break; + } +} + +static void btc_ble_mesh_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_time_scene_client_cb_param_t *p_dest_data = (esp_ble_mesh_time_scene_client_cb_param_t *)p_dest; + esp_ble_mesh_time_scene_client_cb_param_t *p_src_data = (esp_ble_mesh_time_scene_client_cb_param_t *)p_src; + u32_t opcode; + u16_t length; + + if (!msg || !p_src_data || !p_dest_data) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case ESP_BLE_MESH_TIME_SCENE_CLIENT_GET_STATE_EVT: + case ESP_BLE_MESH_TIME_SCENE_CLIENT_SET_STATE_EVT: + case ESP_BLE_MESH_TIME_SCENE_CLIENT_PUBLISH_EVT: + if (p_src_data->params) { + opcode = p_src_data->params->opcode; + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_SCENE_STORE: + case ESP_BLE_MESH_MODEL_OP_SCENE_REGISTER_GET: + case ESP_BLE_MESH_MODEL_OP_SCENE_DELETE: + case ESP_BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS: + if (p_src_data->status_cb.scene_register_status.scenes) { + length = p_src_data->status_cb.scene_register_status.scenes->len; + p_dest_data->status_cb.scene_register_status.scenes = bt_mesh_alloc_buf(length); + if (!p_dest_data->status_cb.scene_register_status.scenes) { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + return; + } + net_buf_simple_add_mem(p_dest_data->status_cb.scene_register_status.scenes, + p_src_data->status_cb.scene_register_status.scenes->data, + p_src_data->status_cb.scene_register_status.scenes->len); + } + break; + default: + break; + } + } + case ESP_BLE_MESH_TIME_SCENE_CLIENT_TIMEOUT_EVT: + if (p_src_data->params) { + p_dest_data->params = osi_malloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (p_dest_data->params) { + memcpy(p_dest_data->params, p_src_data->params, sizeof(esp_ble_mesh_client_common_param_t)); + } else { + LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act); + } + } + break; + default: + break; + } +} + +static void btc_ble_mesh_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_time_scene_client_cb_param_t *arg = NULL; + u32_t opcode; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_time_scene_client_cb_param_t *)(msg->arg); + + switch (msg->act) { + case ESP_BLE_MESH_TIME_SCENE_CLIENT_GET_STATE_EVT: + case ESP_BLE_MESH_TIME_SCENE_CLIENT_SET_STATE_EVT: + case ESP_BLE_MESH_TIME_SCENE_CLIENT_PUBLISH_EVT: + if (arg->params) { + opcode = arg->params->opcode; + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_SCENE_STORE: + case ESP_BLE_MESH_MODEL_OP_SCENE_REGISTER_GET: + case ESP_BLE_MESH_MODEL_OP_SCENE_DELETE: + case ESP_BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS: + bt_mesh_free_buf(arg->status_cb.scene_register_status.scenes); + break; + default: + break; + } + } + case ESP_BLE_MESH_TIME_SCENE_CLIENT_TIMEOUT_EVT: + if (arg->params) { + osi_free(arg->params); + } + break; + default: + break; + } +} + +void btc_ble_mesh_time_scene_client_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_time_scene_client_args_t *arg = NULL; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_time_scene_client_args_t *)(msg->arg); + + switch (msg->act) { + case BTC_BLE_MESH_ACT_TIME_SCENE_CLIENT_GET_STATE: + if (arg->time_scene_client_get_state.params) { + osi_free(arg->time_scene_client_get_state.params); + } + if (arg->time_scene_client_get_state.get_state) { + osi_free(arg->time_scene_client_get_state.get_state); + } + break; + case BTC_BLE_MESH_ACT_TIME_SCENE_CLIENT_SET_STATE: + if (arg->time_scene_client_set_state.params) { + osi_free(arg->time_scene_client_set_state.params); + } + if (arg->time_scene_client_set_state.set_state) { + osi_free(arg->time_scene_client_set_state.set_state); + } + break; + default: + break; + } + + return; +} + +static void btc_mesh_time_scene_client_callback(esp_ble_mesh_time_scene_client_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + LOG_DEBUG("%s", __func__); + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_TIME_SCENE_CLIENT; + msg.act = act; + + btc_transfer_context(&msg, cb_params, + sizeof(esp_ble_mesh_time_scene_client_cb_param_t), btc_ble_mesh_copy_req_data); +} + +void bt_mesh_callback_time_scene_status_to_btc(u32_t opcode, u8_t evt_type, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const u8_t *val, size_t len) +{ + esp_ble_mesh_time_scene_client_cb_param_t cb_params = {0}; + esp_ble_mesh_client_common_param_t params = {0}; + size_t length; + uint8_t act; + + if (!model || !ctx) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + switch (evt_type) { + case 0x00: + act = ESP_BLE_MESH_TIME_SCENE_CLIENT_GET_STATE_EVT; + break; + case 0x01: + act = ESP_BLE_MESH_TIME_SCENE_CLIENT_SET_STATE_EVT; + break; + case 0x02: + act = ESP_BLE_MESH_TIME_SCENE_CLIENT_PUBLISH_EVT; + break; + case 0x03: + act = ESP_BLE_MESH_TIME_SCENE_CLIENT_TIMEOUT_EVT; + break; + default: + LOG_ERROR("%s, Unknown time scene client event type %d", __func__, evt_type); + return; + } + + params.opcode = opcode; + params.model = (esp_ble_mesh_model_t *)model; + params.ctx.net_idx = ctx->net_idx; + params.ctx.app_idx = ctx->app_idx; + params.ctx.addr = ctx->addr; + params.ctx.recv_ttl = ctx->recv_ttl; + params.ctx.recv_op = ctx->recv_op; + params.ctx.recv_dst = ctx->recv_dst; + + cb_params.error_code = 0; + cb_params.params = ¶ms; + + if (val && len) { + length = (len <= sizeof(cb_params.status_cb)) ? len : sizeof(cb_params.status_cb); + memcpy(&cb_params.status_cb, val, length); + } + + btc_mesh_time_scene_client_callback(&cb_params, act); +} + +void btc_mesh_time_scene_client_publish_callback(u32_t opcode, struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) +{ + if (!model || !ctx || !buf) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + bt_mesh_callback_time_scene_status_to_btc(opcode, 0x02, model, ctx, buf->data, buf->len); +} + +void btc_mesh_time_scene_client_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_time_scene_client_cb_param_t time_scene_client_cb = {0}; + btc_ble_mesh_time_scene_client_args_t *arg = NULL; + esp_ble_mesh_client_common_param_t *params = NULL; + struct bt_mesh_common_param common = {0}; + bt_mesh_role_param_t role_param = {0}; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_time_scene_client_args_t *)(msg->arg); + + switch (msg->act) { + case BTC_BLE_MESH_ACT_TIME_SCENE_CLIENT_GET_STATE: { + params = arg->time_scene_client_get_state.params; + role_param.model = (struct bt_mesh_model *)params->model; + role_param.role = params->msg_role; + if (bt_mesh_set_model_role(&role_param)) { + LOG_ERROR("%s, Failed to set model role", __func__); + return; + } + common.opcode = params->opcode; + common.model = (struct bt_mesh_model *)params->model; + common.ctx.net_idx = params->ctx.net_idx; + common.ctx.app_idx = params->ctx.app_idx; + common.ctx.addr = params->ctx.addr; + common.ctx.send_rel = params->ctx.send_rel; + common.ctx.send_ttl = params->ctx.send_ttl; + common.msg_timeout = params->msg_timeout; + + time_scene_client_cb.params = arg->time_scene_client_get_state.params; + time_scene_client_cb.error_code = + bt_mesh_time_scene_client_get_state(&common, + (void *)arg->time_scene_client_get_state.get_state, + (void *)&time_scene_client_cb.status_cb); + if (time_scene_client_cb.error_code) { + /* If send failed, callback error_code to app layer immediately */ + btc_mesh_time_scene_client_callback(&time_scene_client_cb, + ESP_BLE_MESH_TIME_SCENE_CLIENT_GET_STATE_EVT); + } + break; + } + case BTC_BLE_MESH_ACT_TIME_SCENE_CLIENT_SET_STATE: { + params = arg->time_scene_client_set_state.params; + role_param.model = (struct bt_mesh_model *)params->model; + role_param.role = params->msg_role; + if (bt_mesh_set_model_role(&role_param)) { + LOG_ERROR("%s, Failed to set model role", __func__); + return; + } + common.opcode = params->opcode; + common.model = (struct bt_mesh_model *)params->model; + common.ctx.net_idx = params->ctx.net_idx; + common.ctx.app_idx = params->ctx.app_idx; + common.ctx.addr = params->ctx.addr; + common.ctx.send_rel = params->ctx.send_rel; + common.ctx.send_ttl = params->ctx.send_ttl; + common.msg_timeout = params->msg_timeout; + + time_scene_client_cb.params = arg->time_scene_client_set_state.params; + time_scene_client_cb.error_code = + bt_mesh_time_scene_client_set_state(&common, + (void *)arg->time_scene_client_set_state.set_state, + (void *)&time_scene_client_cb.status_cb); + if (time_scene_client_cb.error_code) { + /* If send failed, callback error_code to app layer immediately */ + btc_mesh_time_scene_client_callback(&time_scene_client_cb, + ESP_BLE_MESH_TIME_SCENE_CLIENT_SET_STATE_EVT); + } + break; + } + default: + break; + } + + btc_ble_mesh_time_scene_client_arg_deep_free(msg); +} + +void btc_mesh_time_scene_client_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_time_scene_client_cb_param_t *param = NULL; + + if (!msg || !msg->arg) { + LOG_ERROR("%s, Invalid parameter", __func__); + return; + } + + param = (esp_ble_mesh_time_scene_client_cb_param_t *)(msg->arg); + + if (msg->act < ESP_BLE_MESH_TIME_SCENE_CLIENT_EVT_MAX) { + btc_ble_mesh_cb_to_app(msg->act, param); + } else { + LOG_ERROR("%s, Unknown msg->act = %d", __func__, msg->act); + } + + btc_ble_mesh_free_req_data(msg); +} + diff --git a/components/bt/ble_mesh/btc/include/btc_ble_mesh_config_model.h b/components/bt/ble_mesh/btc/include/btc_ble_mesh_config_model.h new file mode 100644 index 0000000000..6744b96120 --- /dev/null +++ b/components/bt/ble_mesh/btc/include/btc_ble_mesh_config_model.h @@ -0,0 +1,64 @@ +// Copyright 2017-2018 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. + +#ifndef _BTC_BLE_MESH_CONFIG_MODEL_H_ +#define _BTC_BLE_MESH_CONFIG_MODEL_H_ + +#include +#include "btc/btc_task.h" +#include "esp_ble_mesh_config_model_api.h" + +typedef enum { + BTC_BLE_MESH_ACT_CONFIG_CLIENT_GET_STATE, + BTC_BLE_MESH_ACT_CONFIG_CLIENT_SET_STATE, +} btc_ble_mesh_cfg_client_act_t; + +typedef union { + struct ble_mesh_clg_client_get_state_reg_args { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_cfg_client_get_state_t *get_state; + } cfg_client_get_state; + struct ble_mesh_clg_client_set_state_reg_args { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_cfg_client_set_state_t *set_state; + } cfg_client_set_state; +} btc_ble_mesh_cfg_client_args_t; + +void btc_mesh_cfg_client_call_handler(btc_msg_t *msg); + +void btc_mesh_cfg_client_cb_handler(btc_msg_t *msg); + +void btc_ble_mesh_cfg_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); + +int btc_ble_mesh_config_client_get_state(esp_ble_mesh_client_common_param_t *params, esp_ble_mesh_cfg_client_get_state_t *get_state, + esp_ble_mesh_cfg_client_cb_param_t *cfg_client_cb); + +int btc_ble_mesh_config_client_set_state(esp_ble_mesh_client_common_param_t *params, esp_ble_mesh_cfg_client_set_state_t *set_state, + esp_ble_mesh_cfg_client_cb_param_t *cfg_client_cb); + +void btc_mesh_cfg_client_publish_callback(u32_t opcode, struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); + +void bt_mesh_callback_config_status_to_btc(u32_t opcode, u8_t evt_type, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const u8_t *val, size_t len); + +void btc_mesh_cfg_server_cb_handler(btc_msg_t *msg); + +void bt_mesh_callback_cfg_server_event_to_btc(u8_t evt_type, struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const u8_t *val, size_t len); + +#endif /* _BTC_BLE_MESH_CONFIG_MODEL_H_ */ diff --git a/components/bt/ble_mesh/btc/include/btc_ble_mesh_generic_model.h b/components/bt/ble_mesh/btc/include/btc_ble_mesh_generic_model.h new file mode 100644 index 0000000000..480003141d --- /dev/null +++ b/components/bt/ble_mesh/btc/include/btc_ble_mesh_generic_model.h @@ -0,0 +1,52 @@ +// Copyright 2017-2018 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. + +#ifndef _BTC_BLE_MESH_GENERIC_MODEL_H_ +#define _BTC_BLE_MESH_GENERIC_MODEL_H_ + +#include +#include "btc/btc_task.h" +#include "esp_ble_mesh_generic_model_api.h" + +typedef enum { + BTC_BLE_MESH_ACT_GENERIC_CLIENT_GET_STATE, + BTC_BLE_MESH_ACT_GENERIC_CLIENT_SET_STATE, +} btc_ble_mesh_generic_client_act_t; + +typedef union { + struct ble_mesh_generic_client_get_state_reg_args { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_generic_client_get_state_t *get_state; + } generic_client_get_state; + struct ble_mesh_generic_client_set_state_reg_args { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_generic_client_set_state_t *set_state; + } generic_client_set_state; +} btc_ble_mesh_generic_client_args_t; + +void btc_mesh_generic_client_call_handler(btc_msg_t *msg); + +void btc_mesh_generic_client_cb_handler(btc_msg_t *msg); + +void btc_ble_mesh_generic_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); + +void btc_mesh_generic_client_publish_callback(u32_t opcode, struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); + +void bt_mesh_callback_generic_status_to_btc(u32_t opcode, u8_t evt_type, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const u8_t *val, size_t len); + +#endif /* _BTC_BLE_MESH_GENERIC_MODEL_H_ */ diff --git a/components/bt/ble_mesh/btc/include/btc_ble_mesh_health_model.h b/components/bt/ble_mesh/btc/include/btc_ble_mesh_health_model.h new file mode 100644 index 0000000000..859624dba2 --- /dev/null +++ b/components/bt/ble_mesh/btc/include/btc_ble_mesh_health_model.h @@ -0,0 +1,78 @@ +// Copyright 2017-2018 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. + +#ifndef _BTC_BLE_MESH_HEALTH_MODEL_H_ +#define _BTC_BLE_MESH_HEALTH_MODEL_H_ + +#include +#include "btc/btc_task.h" +#include "esp_ble_mesh_health_model_api.h" + +typedef enum { + BTC_BLE_MESH_ACT_HEALTH_CLIENT_GET_STATE, + BTC_BLE_MESH_ACT_HEALTH_CLIENT_SET_STATE, + BTC_BLE_MESH_ACT_HEALTH_CLIENT_MAX, +} btc_ble_mesh_health_client_act_t; + +typedef enum { + BTC_BLE_MESH_ACT_HEALTH_SERVER_FAULT_UPDATE, + BTC_BLE_MESH_ACT_HEALTH_SERVER_MAX, +} btc_ble_mesh_health_server_act_t; + +typedef union { + struct ble_mesh_health_client_get_state_reg_args { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_health_client_get_state_t *get_state; + } health_client_get_state; + struct ble_mesh_health_client_set_state_reg_args { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_health_client_set_state_t *set_state; + } health_client_set_state; +} btc_ble_mesh_health_client_args_t; + +typedef union { + struct ble_mesh_health_server_fault_update_args { + esp_ble_mesh_elem_t *element; + } fault_update; +} btc_ble_mesh_health_server_args_t; + +void btc_mesh_health_client_call_handler(btc_msg_t *msg); + +void btc_mesh_health_client_cb_handler(btc_msg_t *msg); + +void btc_mesh_health_server_call_handler(btc_msg_t *msg); + +void btc_mesh_health_server_cb_handler(btc_msg_t *msg); + +void btc_ble_mesh_health_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); + +void btc_ble_mesh_health_server_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); + +int btc_ble_mesh_health_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_health_client_get_state_t *get_state, + esp_ble_mesh_health_client_cb_param_t *client_cb); + +int btc_ble_mesh_health_client_set_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_health_client_set_state_t *set_state, + esp_ble_mesh_health_client_cb_param_t *client_cb); + +void btc_mesh_health_publish_callback(u32_t opcode, struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); + +void bt_mesh_callback_health_status_to_btc(u32_t opcode, u8_t evt_type, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const u8_t *val, u16_t len); + +#endif /* _BTC_BLE_MESH_HEALTH_MODEL_H_ */ diff --git a/components/bt/ble_mesh/btc/include/btc_ble_mesh_lighting_model.h b/components/bt/ble_mesh/btc/include/btc_ble_mesh_lighting_model.h new file mode 100644 index 0000000000..8a3088f32d --- /dev/null +++ b/components/bt/ble_mesh/btc/include/btc_ble_mesh_lighting_model.h @@ -0,0 +1,53 @@ +// Copyright 2017-2018 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. + +#ifndef _BTC_BLE_MESH_LIGHTING_MODEL_H_ +#define _BTC_BLE_MESH_LIGHTING_MODEL_H_ + +#include +#include "btc/btc_task.h" +#include "esp_ble_mesh_lighting_model_api.h" + +typedef enum { + BTC_BLE_MESH_ACT_LIGHT_CLIENT_GET_STATE, + BTC_BLE_MESH_ACT_LIGHT_CLIENT_SET_STATE, +} btc_ble_mesh_light_client_act_t; + +typedef union { + struct ble_mesh_light_client_get_state_reg_args { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_light_client_get_state_t *get_state; + } light_client_get_state; + struct ble_mesh_light_client_set_state_reg_args { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_light_client_set_state_t *set_state; + } light_client_set_state; +} btc_ble_mesh_light_client_args_t; + +void btc_mesh_light_client_call_handler(btc_msg_t *msg); + +void btc_mesh_light_client_cb_handler(btc_msg_t *msg); + +void btc_ble_mesh_light_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); + +void btc_mesh_light_client_publish_callback(u32_t opcode, struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); + +void bt_mesh_callback_light_status_to_btc(u32_t opcode, u8_t evt_type, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const u8_t *val, size_t len); + +#endif /* _BTC_BLE_MESH_LIGHTING_MODEL_H_ */ + diff --git a/components/bt/ble_mesh/btc/include/btc_ble_mesh_prov.h b/components/bt/ble_mesh/btc/include/btc_ble_mesh_prov.h new file mode 100644 index 0000000000..9ce21e4865 --- /dev/null +++ b/components/bt/ble_mesh/btc/include/btc_ble_mesh_prov.h @@ -0,0 +1,210 @@ +// Copyright 2017-2018 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. + +#ifndef _BTC_BLE_MESH_PROV_H_ +#define _BTC_BLE_MESH_PROV_H_ + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" + +#include "btc/btc_task.h" +#include "esp_bt_defs.h" + +#include "mesh_access.h" +#include "mesh_buf.h" +#include "mesh_main.h" +#include "provisioner_prov.h" +#include "esp_ble_mesh_defs.h" + +typedef enum { + BTC_BLE_MESH_ACT_MESH_INIT = 0, + BTC_BLE_MESH_ACT_PROV_ENABLE, + BTC_BLE_MESH_ACT_PROV_DISABLE, + BTC_BLE_MESH_ACT_NODE_RESET, + BTC_BLE_MESH_ACT_SET_OOB_PUB_KEY, + BTC_BLE_MESH_ACT_INPUT_NUMBER, + BTC_BLE_MESH_ACT_INPUT_STRING, + BTC_BLE_MESH_ACT_SET_DEVICE_NAME, + BTC_BLE_MESH_ACT_PROXY_IDENTITY_ENABLE, + BTC_BLE_MESH_ACT_PROXY_GATT_ENABLE, + BTC_BLE_MESH_ACT_PROXY_GATT_DISABLE, + BTC_BLE_MESH_ACT_PROVISIONER_READ_OOB_PUB_KEY, + BTC_BLE_MESH_ACT_PROVISIONER_INPUT_STR, + BTC_BLE_MESH_ACT_PROVISIONER_INPUT_NUM, + BTC_BLE_MESH_ACT_PROVISIONER_ENABLE, + BTC_BLE_MESH_ACT_PROVISIONER_DISABLE, + BTC_BLE_MESH_ACT_PROVISIONER_DEV_ADD, + BTC_BLE_MESH_ACT_PROVISIONER_DEV_DEL, + BTC_BLE_MESH_ACT_PROVISIONER_SET_DEV_UUID_MATCH, + BTC_BLE_MESH_ACT_PROVISIONER_SET_PROV_DATA_INFO, + BTC_BLE_MESH_ACT_PROVISIONER_SET_NODE_NAME, + BTC_BLE_MESH_ACT_PROVISIONER_SET_LOCAL_APP_KEY, + BTC_BLE_MESH_ACT_PROVISIONER_BIND_LOCAL_MOD_APP, + BTC_BLE_MESH_ACT_PROVISIONER_ADD_LOCAL_NET_KEY, + BTC_BLE_MESH_ACT_SET_FAST_PROV_INFO, + BTC_BLE_MESH_ACT_SET_FAST_PROV_ACTION, +} btc_ble_mesh_prov_act_t; + +typedef enum { + BTC_BLE_MESH_ACT_MODEL_PUBLISH, + BTC_BLE_MESH_ACT_SERVER_MODEL_SEND, + BTC_BLE_MESH_ACT_CLIENT_MODEL_SEND +} btc_ble_mesh_model_act_t; + +typedef union { + struct ble_mesh_init_args { + esp_ble_mesh_prov_t *prov; + esp_ble_mesh_comp_t *comp; + SemaphoreHandle_t semaphore; + } mesh_init; + struct ble_mesh_node_prov_enable_args { + esp_ble_mesh_prov_bearer_t bearers; + } node_prov_enable; + struct ble_mesh_node_prov_disable_args { + esp_ble_mesh_prov_bearer_t bearers; + } node_prov_disable; + struct ble_mesh_set_oob_pub_key_args { + uint8_t pub_key_x[32]; + uint8_t pub_key_y[32]; + uint8_t private_key[32]; + } set_oob_pub_key; + struct ble_mesh_node_input_num_args { + uint32_t number; + } input_number; + struct ble_mesh_node_input_str_args { + char string[8]; + } input_string; + struct ble_mesh_set_device_name_args { + char name[ESP_BLE_MESH_DEVICE_NAME_MAX_LEN]; + } set_device_name; + struct ble_mesh_provisioner_read_oob_pub_key_args { + uint8_t link_idx; + uint8_t pub_key_x[32]; + uint8_t pub_key_y[32]; + } provisioner_read_oob_pub_key; + struct ble_mesh_provisioner_input_str_args { + char string[8]; + uint8_t link_idx; + } provisioner_input_str; + struct ble_mesh_provisioner_input_num_args { + uint32_t number; + uint8_t link_idx; + } provisioner_input_num; + struct ble_mesh_provisioner_enable_args { + esp_ble_mesh_prov_bearer_t bearers; + } provisioner_enable; + struct ble_mesh_provisioner_disable_args { + esp_ble_mesh_prov_bearer_t bearers; + } provisioner_disable; + struct ble_mesh_provisioner_dev_add_args { + esp_ble_mesh_unprov_dev_add_t add_dev; + esp_ble_mesh_dev_add_flag_t flags; + } provisioner_dev_add; + struct ble_mesh_provisioner_dev_del_args { + esp_ble_mesh_device_delete_t del_dev; + } provisioner_dev_del; + struct ble_mesh_provisioner_set_dev_uuid_match_args { + uint8_t offset; + uint8_t match_len; + uint8_t match_val[16]; + bool prov_after_match; + } set_dev_uuid_match; + struct ble_mesh_provisioner_set_prov_net_idx_args { + esp_ble_mesh_prov_data_info_t prov_data; + } set_prov_data_info; + struct ble_mesh_provisioner_set_node_name_args { + int index; + char name[ESP_BLE_MESH_NODE_NAME_MAX_LEN]; + } set_node_name; + struct ble_mesh_provisioner_add_local_app_key_args { + uint8_t app_key[16]; + uint16_t net_idx; + uint16_t app_idx; + } add_local_app_key; + struct ble_mesh_provisioner_bind_local_mod_app_args { + uint16_t elem_addr; + uint16_t model_id; + uint16_t cid; + uint16_t app_idx; + } local_mod_app_bind; + struct ble_mesh_provisioner_add_local_net_key_args { + uint8_t net_key[16]; + uint16_t net_idx; + } add_local_net_key; + struct ble_mesh_set_fast_prov_info_args { + uint16_t unicast_min; + uint16_t unicast_max; + uint16_t net_idx; + uint8_t flags; + uint32_t iv_index; + uint8_t offset; + uint8_t match_len; + uint8_t match_val[16]; + } set_fast_prov_info; + struct ble_mesh_set_fast_prov_action_args { + uint8_t action; + } set_fast_prov_action; +} btc_ble_mesh_prov_args_t; + +typedef union { + struct ble_mesh_model_publish_args { + esp_ble_mesh_model_t *model; + uint8_t device_role; + } model_publish; + struct ble_mesh_model_send_args { + esp_ble_mesh_model_t *model; + esp_ble_mesh_msg_ctx_t *ctx; + uint32_t opcode; + bool need_rsp; + uint16_t length; + uint8_t *data; + uint8_t device_role; + int32_t msg_timeout; + } model_send; +} btc_ble_mesh_model_args_t; + +void btc_ble_mesh_prov_arg_deep_free(btc_msg_t *msg); + +void btc_ble_mesh_prov_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); + +int btc_ble_mesh_client_init(esp_ble_mesh_model_t *model); + +int32_t btc_ble_mesh_model_pub_period_get(esp_ble_mesh_model_t *mod); + +uint16_t btc_ble_mesh_get_primary_addr(void); + +uint16_t *btc_ble_mesh_model_find_group(esp_ble_mesh_model_t *mod, uint16_t addr); + +esp_ble_mesh_elem_t *btc_ble_mesh_elem_find(u16_t addr); + +uint8_t btc_ble_mesh_elem_count(void); + +esp_ble_mesh_model_t *btc_ble_mesh_model_find_vnd(const esp_ble_mesh_elem_t *elem, + uint16_t company, uint16_t id); + +esp_ble_mesh_model_t *btc_ble_mesh_model_find(const esp_ble_mesh_elem_t *elem, + uint16_t id); + +const esp_ble_mesh_comp_t *btc_ble_mesh_comp_get(void); + +void btc_mesh_model_call_handler(btc_msg_t *msg); +void btc_mesh_model_cb_handler(btc_msg_t *msg); + +void btc_mesh_prov_call_handler(btc_msg_t *msg); + +void btc_mesh_prov_cb_handler(btc_msg_t *msg); + +#endif /* _BTC_BLE_MESH_PROV_H_ */ diff --git a/components/bt/ble_mesh/btc/include/btc_ble_mesh_sensor_model.h b/components/bt/ble_mesh/btc/include/btc_ble_mesh_sensor_model.h new file mode 100644 index 0000000000..6bd97355e8 --- /dev/null +++ b/components/bt/ble_mesh/btc/include/btc_ble_mesh_sensor_model.h @@ -0,0 +1,53 @@ +// Copyright 2017-2018 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. + +#ifndef _BTC_BLE_MESH_SENSOR_MODEL_H_ +#define _BTC_BLE_MESH_SENSOR_MODEL_H_ + +#include +#include "btc/btc_task.h" +#include "esp_ble_mesh_sensor_model_api.h" + +typedef enum { + BTC_BLE_MESH_ACT_SENSOR_CLIENT_GET_STATE, + BTC_BLE_MESH_ACT_SENSOR_CLIENT_SET_STATE, +} btc_ble_mesh_sensor_client_act_t; + +typedef union { + struct ble_mesh_sensor_client_get_state_reg_args { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_sensor_client_get_state_t *get_state; + } sensor_client_get_state; + struct ble_mesh_sensor_client_set_state_reg_args { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_sensor_client_set_state_t *set_state; + } sensor_client_set_state; +} btc_ble_mesh_sensor_client_args_t; + +void btc_mesh_sensor_client_call_handler(btc_msg_t *msg); + +void btc_mesh_sensor_client_cb_handler(btc_msg_t *msg); + +void btc_ble_mesh_sensor_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); + +void btc_mesh_sensor_client_publish_callback(u32_t opcode, struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); + +void bt_mesh_callback_sensor_status_to_btc(u32_t opcode, u8_t evt_type, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const u8_t *val, size_t len); + +#endif /* _BTC_BLE_MESH_SENSOR_MODEL_H_ */ + diff --git a/components/bt/ble_mesh/btc/include/btc_ble_mesh_time_scene_model.h b/components/bt/ble_mesh/btc/include/btc_ble_mesh_time_scene_model.h new file mode 100644 index 0000000000..1778fa2347 --- /dev/null +++ b/components/bt/ble_mesh/btc/include/btc_ble_mesh_time_scene_model.h @@ -0,0 +1,53 @@ +// Copyright 2017-2018 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. + +#ifndef _BTC_BLE_MESH_TIME_SCENE_MODEL_H_ +#define _BTC_BLE_MESH_TIME_SCENE_MODEL_H_ + +#include +#include "btc/btc_task.h" +#include "esp_ble_mesh_time_scene_model_api.h" + +typedef enum { + BTC_BLE_MESH_ACT_TIME_SCENE_CLIENT_GET_STATE, + BTC_BLE_MESH_ACT_TIME_SCENE_CLIENT_SET_STATE, +} btc_ble_mesh_time_scene_client_act_t; + +typedef union { + struct ble_mesh_time_scene_client_get_state_reg_args { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_time_scene_client_get_state_t *get_state; + } time_scene_client_get_state; + struct ble_mesh_time_scene_client_set_state_reg_args { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_time_scene_client_set_state_t *set_state; + } time_scene_client_set_state; +} btc_ble_mesh_time_scene_client_args_t; + +void btc_mesh_time_scene_client_call_handler(btc_msg_t *msg); + +void btc_mesh_time_scene_client_cb_handler(btc_msg_t *msg); + +void btc_ble_mesh_time_scene_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); + +void btc_mesh_time_scene_client_publish_callback(u32_t opcode, struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); + +void bt_mesh_callback_time_scene_status_to_btc(u32_t opcode, u8_t evt_type, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const u8_t *val, size_t len); + +#endif /* _BTC_BLE_MESH_TIME_SCENE_MODEL_H_ */ + diff --git a/components/bt/ble_mesh/mesh_core/access.c b/components/bt/ble_mesh/mesh_core/access.c new file mode 100644 index 0000000000..6184d30091 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/access.c @@ -0,0 +1,1043 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +#include "sdkconfig.h" +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BLE_MESH_DEBUG_ACCESS) + +#include "mesh_util.h" +#include "mesh_buf.h" +#include "mesh_trace.h" +#include "mesh_kernel.h" +#include "mesh_access.h" +#include "mesh_main.h" + +#include "mesh.h" +#include "adv.h" +#include "net.h" +#include "lpn.h" +#include "transport.h" +#include "access.h" +#include "foundation.h" + +#include "mesh_common.h" +#include "generic_client.h" +#include "sensor_client.h" +#include "time_scene_client.h" +#include "lighting_client.h" +#include "provisioner_main.h" + +#define BLE_MESH_SDU_MAX_LEN 384 + +static const struct bt_mesh_comp *dev_comp; +static u16_t dev_primary_addr; + +static const struct { + const u16_t id; + int (*const init)(struct bt_mesh_model *model, bool primary); +} model_init[] = { + { BLE_MESH_MODEL_ID_CFG_SRV, bt_mesh_cfg_srv_init }, + { BLE_MESH_MODEL_ID_HEALTH_SRV, bt_mesh_health_srv_init }, +#if defined(CONFIG_BLE_MESH_CFG_CLI) + { BLE_MESH_MODEL_ID_CFG_CLI, bt_mesh_cfg_cli_init }, +#endif +#if defined(CONFIG_BLE_MESH_HEALTH_CLI) + { BLE_MESH_MODEL_ID_HEALTH_CLI, bt_mesh_health_cli_init }, +#endif +#if defined(CONFIG_BLE_MESH_GENERIC_ONOFF_CLI) + { BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, bt_mesh_gen_onoff_cli_init }, +#endif +#if defined(CONFIG_BLE_MESH_GENERIC_LEVEL_CLI) + { BLE_MESH_MODEL_ID_GEN_LEVEL_CLI, bt_mesh_gen_level_cli_init }, +#endif +#if defined(CONFIG_BLE_MESH_GENERIC_DEF_TRANS_TIME_CLI) + { BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_CLI, bt_mesh_gen_def_trans_time_cli_init }, +#endif +#if defined(CONFIG_BLE_MESH_GENERIC_POWER_ONOFF_CLI) + { BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_CLI, bt_mesh_gen_pwr_onoff_cli_init }, +#endif +#if defined(CONFIG_BLE_MESH_GENERIC_POWER_LEVEL_CLI) + { BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_CLI, bt_mesh_gen_pwr_level_cli_init }, +#endif +#if defined(CONFIG_BLE_MESH_GENERIC_BATTERY_CLI) + { BLE_MESH_MODEL_ID_GEN_BATTERY_CLI, bt_mesh_gen_battery_cli_init }, +#endif +#if defined(CONFIG_BLE_MESH_GENERIC_LOCATION_CLI) + { BLE_MESH_MODEL_ID_GEN_LOCATION_CLI, bt_mesh_gen_location_cli_init }, +#endif +#if defined(CONFIG_BLE_MESH_GENERIC_PROPERTY_CLI) + { BLE_MESH_MODEL_ID_GEN_PROP_CLI, bt_mesh_gen_property_cli_init }, +#endif +#if defined(CONFIG_BLE_MESH_SENSOR_CLI) + { BLE_MESH_MODEL_ID_SENSOR_CLI, bt_mesh_sensor_cli_init }, +#endif +#if defined(CONFIG_BLE_MESH_TIME_CLI) + { BLE_MESH_MODEL_ID_TIME_CLI, bt_mesh_time_cli_init }, +#endif +#if defined(CONFIG_BLE_MESH_SCENE_CLI) + { BLE_MESH_MODEL_ID_SCENE_CLI, bt_mesh_scene_cli_init }, +#endif +#if defined(CONFIG_BLE_MESH_SCHEDULER_CLI) + { BLE_MESH_MODEL_ID_SCHEDULER_CLI, bt_mesh_scheduler_cli_init }, +#endif +#if defined(CONFIG_BLE_MESH_LIGHT_LIGHTNESS_CLI) + { BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_CLI, bt_mesh_light_lightness_cli_init }, +#endif +#if defined(CONFIG_BLE_MESH_LIGHT_CTL_CLI) + { BLE_MESH_MODEL_ID_LIGHT_CTL_CLI, bt_mesh_light_ctl_cli_init }, +#endif +#if defined(CONFIG_BLE_MESH_LIGHT_HSL_CLI) + { BLE_MESH_MODEL_ID_LIGHT_HSL_CLI, bt_mesh_light_hsl_cli_init }, +#endif +#if defined(CONFIG_BLE_MESH_LIGHT_XYL_CLI) + { BLE_MESH_MODEL_ID_LIGHT_XYL_CLI, bt_mesh_light_xyl_cli_init }, +#endif +#if defined(CONFIG_BLE_MESH_LIGHT_LC_CLI) + { BLE_MESH_MODEL_ID_LIGHT_LC_CLI, bt_mesh_light_lc_cli_init }, +#endif +}; + +void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, + struct bt_mesh_elem *elem, + bool vnd, bool primary, + void *user_data), + void *user_data) +{ + int i, j; + + for (i = 0; i < dev_comp->elem_count; i++) { + struct bt_mesh_elem *elem = &dev_comp->elem[i]; + + for (j = 0; j < elem->model_count; j++) { + struct bt_mesh_model *model = &elem->models[j]; + + func(model, elem, false, i == 0, user_data); + } + + for (j = 0; j < elem->vnd_model_count; j++) { + struct bt_mesh_model *model = &elem->vnd_models[j]; + + func(model, elem, true, i == 0, user_data); + } + } +} + +s32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod) +{ + int period = 0; + + if (!mod->pub) { + BT_ERR("%s, Model has no publication support", __func__); + return 0; + } + + switch (mod->pub->period >> 6) { + case 0x00: + /* 1 step is 100 ms */ + period = K_MSEC((mod->pub->period & BIT_MASK(6)) * 100U); + break; + case 0x01: + /* 1 step is 1 second */ + period = K_SECONDS(mod->pub->period & BIT_MASK(6)); + break; + case 0x02: + /* 1 step is 10 seconds */ + period = K_SECONDS((mod->pub->period & BIT_MASK(6)) * 10U); + break; + case 0x03: + /* 1 step is 10 minutes */ + period = K_MINUTES((mod->pub->period & BIT_MASK(6)) * 10U); + break; + default: + BT_ERR("%s, Unknown model publication period", __func__); + return 0; + } + + if (mod->pub->fast_period) { + return period >> mod->pub->period_div; + } else { + return period; + } +} + +static s32_t next_period(struct bt_mesh_model *mod) +{ + struct bt_mesh_model_pub *pub = mod->pub; + u32_t elapsed, period; + + if (!pub) { + BT_ERR("%s, Model has no publication support", __func__); + return -ENOTSUP; + } + + period = bt_mesh_model_pub_period_get(mod); + if (!period) { + return 0; + } + + elapsed = k_uptime_get_32() - pub->period_start; + + BT_DBG("Publishing took %ums", elapsed); + + if (elapsed > period) { + BT_WARN("Publication sending took longer than the period"); + /* Return smallest positive number since 0 means disabled */ + return K_MSEC(1); + } + + return period - elapsed; +} + +static void publish_sent(int err, void *user_data) +{ + struct bt_mesh_model *mod = user_data; + s32_t delay; + + BT_DBG("err %d", err); + + if (!mod->pub) { + BT_ERR("%s, Model has no publication support", __func__); + return; + } + + if (mod->pub->count) { + delay = BLE_MESH_PUB_TRANSMIT_INT(mod->pub->retransmit); + } else { + delay = next_period(mod); + } + + if (delay) { + BT_DBG("Publishing next time in %dms", delay); + k_delayed_work_submit(&mod->pub->timer, delay); + } +} + +static const struct bt_mesh_send_cb pub_sent_cb = { + .end = publish_sent, +}; + +static int publish_retransmit(struct bt_mesh_model *mod) +{ + struct bt_mesh_model_pub *pub = mod->pub; + if (!pub) { + BT_ERR("%s, Model has no publication support", __func__); + return -ENOTSUP; + } + + struct bt_mesh_app_key *key = NULL; + struct net_buf_simple *sdu = NULL; + struct bt_mesh_msg_ctx ctx = { + .addr = pub->addr, + .send_ttl = pub->ttl, + .model = mod, + .srv_send = (pub->dev_role == NODE ? true : false), + }; + struct bt_mesh_net_tx tx = { + .ctx = &ctx, + .src = bt_mesh_model_elem(mod)->addr, + .xmit = bt_mesh_net_transmit_get(), + .friend_cred = pub->cred, + }; + int err; + + key = bt_mesh_app_key_find(pub->key); + if (!key) { + BT_ERR("%s, Failed to find AppKey", __func__); + return -EADDRNOTAVAIL; + } + + tx.sub = bt_mesh_subnet_get(key->net_idx); + + ctx.net_idx = key->net_idx; + ctx.app_idx = key->app_idx; + + sdu = bt_mesh_alloc_buf(pub->msg->len + 4); + if (!sdu) { + BT_ERR("%s, Failed to allocate memory", __func__); + return -ENOMEM; + } + + net_buf_simple_add_mem(sdu, pub->msg->data, pub->msg->len); + + pub->count--; + + err = bt_mesh_trans_send(&tx, sdu, &pub_sent_cb, mod); + + bt_mesh_free_buf(sdu); + return err; +} + +static void mod_publish(struct k_work *work) +{ + struct bt_mesh_model_pub *pub = CONTAINER_OF(work, + struct bt_mesh_model_pub, + timer.work); + s32_t period_ms; + int err; + + BT_DBG("%s", __func__); + + period_ms = bt_mesh_model_pub_period_get(pub->mod); + BT_DBG("period %u ms", period_ms); + + if (pub->count) { + err = publish_retransmit(pub->mod); + if (err) { + BT_ERR("%s, Failed to retransmit (err %d)", __func__, err); + + pub->count = 0U; + + /* Continue with normal publication */ + if (period_ms) { + k_delayed_work_submit(&pub->timer, period_ms); + } + } + + return; + } + + if (!period_ms) { + return; + } + + __ASSERT_NO_MSG(pub->update != NULL); + + pub->period_start = k_uptime_get_32(); + + /* Callback the model publish update event to the application layer. + * In the event, users can update the context of the publish message + * which will be published in the next period. + */ + err = pub->update(pub->mod); + if (err) { + BT_ERR("%s, Failed to update publication message", __func__); + return; + } + + err = bt_mesh_model_publish(pub->mod); + if (err) { + BT_ERR("%s, Publishing failed (err %d)", __func__, err); + } + + if (pub->count) { + /* Retransmissions also control the timer */ + k_delayed_work_cancel(&pub->timer); + } +} + +struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod) +{ + return &dev_comp->elem[mod->elem_idx]; +} + +struct bt_mesh_model *bt_mesh_model_get(bool vnd, u8_t elem_idx, u8_t mod_idx) +{ + struct bt_mesh_elem *elem; + + if (!dev_comp) { + BT_ERR("%s, dev_comp is not initialized", __func__); + return NULL; + } + + if (elem_idx >= dev_comp->elem_count) { + BT_ERR("%s, Invalid element index %u", __func__, elem_idx); + return NULL; + } + + elem = &dev_comp->elem[elem_idx]; + + if (vnd) { + if (mod_idx >= elem->vnd_model_count) { + BT_ERR("%s, Invalid vendor model index %u", __func__, mod_idx); + return NULL; + } + + return &elem->vnd_models[mod_idx]; + } else { + if (mod_idx >= elem->model_count) { + BT_ERR("%s, Invalid SIG model index %u", __func__, mod_idx); + return NULL; + } + + return &elem->models[mod_idx]; + } +} + +static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, + bool vnd, bool primary, void *user_data) +{ + int i; + + mod->elem = elem; + + if (mod->pub) { + mod->pub->mod = mod; + k_delayed_work_init(&mod->pub->timer, mod_publish); + } + + for (i = 0; i < ARRAY_SIZE(mod->keys); i++) { + mod->keys[i] = BLE_MESH_KEY_UNUSED; + } + + mod->flags = 0; + mod->elem_idx = elem - dev_comp->elem; + if (vnd) { + mod->model_idx = mod - elem->vnd_models; + } else { + mod->model_idx = mod - elem->models; + } + + if (vnd) { + return; + } + + for (i = 0; i < ARRAY_SIZE(model_init); i++) { + if (model_init[i].id == mod->id) { + model_init[i].init(mod, primary); + } + } +} + +int bt_mesh_comp_register(const struct bt_mesh_comp *comp) +{ + /* There must be at least one element */ + if (!comp->elem_count) { + return -EINVAL; + } + + dev_comp = comp; + + bt_mesh_model_foreach(mod_init, NULL); + + return 0; +} + +void bt_mesh_comp_provision(u16_t addr) +{ + int i; + + dev_primary_addr = addr; + + BT_DBG("addr 0x%04x elem_count %u", addr, dev_comp->elem_count); + + for (i = 0; i < dev_comp->elem_count; i++) { + struct bt_mesh_elem *elem = &dev_comp->elem[i]; + + elem->addr = addr++; + + BT_DBG("addr 0x%04x mod_count %u vnd_mod_count %u", + elem->addr, elem->model_count, elem->vnd_model_count); + } +} + +void bt_mesh_comp_unprovision(void) +{ + BT_DBG("%s", __func__); + + dev_primary_addr = BLE_MESH_ADDR_UNASSIGNED; + + bt_mesh_model_foreach(mod_init, NULL); +} + +u16_t bt_mesh_primary_addr(void) +{ + return dev_primary_addr; +} + +u16_t *bt_mesh_model_find_group(struct bt_mesh_model *mod, u16_t addr) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mod->groups); i++) { + if (mod->groups[i] == addr) { + return &mod->groups[i]; + } + } + + return NULL; +} + +static struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem, + u16_t group_addr) +{ + struct bt_mesh_model *model; + u16_t *match; + int i; + + for (i = 0; i < elem->model_count; i++) { + model = &elem->models[i]; + + match = bt_mesh_model_find_group(model, group_addr); + if (match) { + return model; + } + } + + for (i = 0; i < elem->vnd_model_count; i++) { + model = &elem->vnd_models[i]; + + match = bt_mesh_model_find_group(model, group_addr); + if (match) { + return model; + } + } + + return NULL; +} + +struct bt_mesh_elem *bt_mesh_elem_find(u16_t addr) +{ + int i; + + for (i = 0; i < dev_comp->elem_count; i++) { + struct bt_mesh_elem *elem = &dev_comp->elem[i]; + + if (BLE_MESH_ADDR_IS_GROUP(addr) || + BLE_MESH_ADDR_IS_VIRTUAL(addr)) { + if (bt_mesh_elem_find_group(elem, addr)) { + return elem; + } + } else if (elem->addr == addr) { + return elem; + } + } + + return NULL; +} + +u8_t bt_mesh_elem_count(void) +{ + return dev_comp->elem_count; +} + +static bool model_has_key(struct bt_mesh_model *mod, u16_t key) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mod->keys); i++) { + if (mod->keys[i] == key) { + return true; + } + } + + return false; +} + +static const struct bt_mesh_model_op *find_op(struct bt_mesh_model *models, + u8_t model_count, u16_t dst, + u16_t app_idx, u32_t opcode, + struct bt_mesh_model **model) +{ + u8_t i; + + for (i = 0U; i < model_count; i++) { + const struct bt_mesh_model_op *op; + + *model = &models[i]; + + if (BLE_MESH_ADDR_IS_GROUP(dst) || + BLE_MESH_ADDR_IS_VIRTUAL(dst)) { + if (!bt_mesh_model_find_group(*model, dst)) { + continue; + } + } + + if (!model_has_key(*model, app_idx)) { + continue; + } + + for (op = (*model)->op; op->func; op++) { + if (op->opcode == opcode) { + return op; + } + } + } + + *model = NULL; + return NULL; +} + +static int get_opcode(struct net_buf_simple *buf, u32_t *opcode) +{ + switch (buf->data[0] >> 6) { + case 0x00: + case 0x01: + if (buf->data[0] == 0x7f) { + BT_ERR("%s, Ignoring RFU OpCode", __func__); + return -EINVAL; + } + + *opcode = net_buf_simple_pull_u8(buf); + return 0; + case 0x02: + if (buf->len < 2) { + BT_ERR("%s, Too short payload for 2-octet OpCode", __func__); + return -EINVAL; + } + + *opcode = net_buf_simple_pull_be16(buf); + return 0; + case 0x03: + if (buf->len < 3) { + BT_ERR("%s, Too short payload for 3-octet OpCode", __func__); + return -EINVAL; + } + + *opcode = net_buf_simple_pull_u8(buf) << 16; + *opcode |= net_buf_simple_pull_le16(buf); + return 0; + } + + return -EINVAL; +} + +bool bt_mesh_fixed_group_match(u16_t addr) +{ + /* Check for fixed group addresses */ + switch (addr) { + case BLE_MESH_ADDR_ALL_NODES: + return true; + case BLE_MESH_ADDR_PROXIES: + return (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED); + case BLE_MESH_ADDR_FRIENDS: + return (bt_mesh_friend_get() == BLE_MESH_FRIEND_ENABLED); + case BLE_MESH_ADDR_RELAYS: + return (bt_mesh_relay_get() == BLE_MESH_RELAY_ENABLED); + default: + return false; + } +} + +u32_t mesh_opcode; + +void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) +{ + struct bt_mesh_model *models, *model; + const struct bt_mesh_model_op *op; + u32_t opcode; + u8_t count; + int i; + + BT_DBG("app_idx 0x%04x src 0x%04x dst 0x%04x", rx->ctx.app_idx, + rx->ctx.addr, rx->ctx.recv_dst); + BT_DBG("len %u: %s", buf->len, bt_hex(buf->data, buf->len)); + + if (get_opcode(buf, &opcode) < 0) { + BT_WARN("%s, Unable to decode OpCode", __func__); + return; + } + + BT_DBG("OpCode 0x%08x", opcode); + + mesh_opcode = opcode; + + for (i = 0; i < dev_comp->elem_count; i++) { + struct bt_mesh_elem *elem = &dev_comp->elem[i]; + + if (BLE_MESH_ADDR_IS_UNICAST(rx->ctx.recv_dst)) { + if (elem->addr != rx->ctx.recv_dst) { + continue; + } + } else if (BLE_MESH_ADDR_IS_GROUP(rx->ctx.recv_dst) || + BLE_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) { + /* find_op() will do proper model/group matching */ + } else if (i != 0 || + !bt_mesh_fixed_group_match(rx->ctx.recv_dst)) { + continue; + } + + /* SIG models cannot contain 3-byte (vendor) OpCodes, and + * vendor models cannot contain SIG (1- or 2-byte) OpCodes, so + * we only need to do the lookup in one of the model lists. + */ + if (opcode < 0x10000) { + models = elem->models; + count = elem->model_count; + } else { + models = elem->vnd_models; + count = elem->vnd_model_count; + } + + op = find_op(models, count, rx->ctx.recv_dst, rx->ctx.app_idx, + opcode, &model); + if (op) { + struct net_buf_simple_state state; + + if (buf->len < op->min_len) { + BT_ERR("%s, Too short message for OpCode 0x%08x", + __func__, opcode); + continue; + } + + /* The callback will likely parse the buffer, so + * store the parsing state in case multiple models + * receive the message. + */ + net_buf_simple_save(buf, &state); + + /** Changed by Espressif, here we update recv_op with the + * value opcode got from the buf. + */ + rx->ctx.recv_op = opcode; + /** Changed by Espressif, we update the model pointer to the + * found model when we received a message. + */ + rx->ctx.model = model; + /** Changed by Espressif, we update the srv_send flag to be + * true when we received a message. This flag will be used + * when a server model sends a status message and will + * have no impact on the client sent messages. + */ + rx->ctx.srv_send = true; + + op->func(model, &rx->ctx, buf); + net_buf_simple_restore(buf, &state); + + } else { + BT_DBG("No OpCode 0x%08x for elem %d", opcode, i); + } + } +} + +void bt_mesh_model_msg_init(struct net_buf_simple *msg, u32_t opcode) +{ + net_buf_simple_init(msg, 0); + + if (opcode < 0x100) { + /* 1-byte OpCode */ + net_buf_simple_add_u8(msg, opcode); + return; + } + + if (opcode < 0x10000) { + /* 2-byte OpCode */ + net_buf_simple_add_be16(msg, opcode); + return; + } + + /* 3-byte OpCode */ + net_buf_simple_add_u8(msg, ((opcode >> 16) & 0xff)); + net_buf_simple_add_le16(msg, opcode & 0xffff); +} + +static int model_send(struct bt_mesh_model *model, + struct bt_mesh_net_tx *tx, bool implicit_bind, + struct net_buf_simple *msg, + const struct bt_mesh_send_cb *cb, void *cb_data) +{ + bool check = false; + u8_t role; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx->ctx->net_idx, + tx->ctx->app_idx, tx->ctx->addr); + BT_DBG("len %u: %s", msg->len, bt_hex(msg->data, msg->len)); + + role = bt_mesh_get_model_role(model, tx->ctx->srv_send); + if (role == ROLE_NVAL) { + BT_ERR("%s, Failed to get model role", __func__); + return -EINVAL; + } + +#if CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER + if (role == NODE) { + if (!bt_mesh_is_provisioned()) { + BT_ERR("%s, Local node is not yet provisioned", __func__); + return -EAGAIN; + } + if (!bt_mesh_is_provisioner_en()) { + check = true; + } + } +#endif + +#if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (role == PROVISIONER) { + if (!provisioner_check_msg_dst_addr(tx->ctx->addr)) { + BT_ERR("%s, Failed to check DST", __func__); + return -EINVAL; + } + if (bt_mesh_is_provisioner_en()) { + check = true; + } + } +#endif + +#if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (role == PROVISIONER) { + if (!provisioner_check_msg_dst_addr(tx->ctx->addr)) { + BT_ERR("%s, Failed to check DST", __func__); + return -EINVAL; + } + if (bt_mesh_is_provisioner_en()) { + check = true; + } + } else { + if (!bt_mesh_is_provisioned()) { + BT_ERR("%s, Local node is not yet provisioned", __func__); + return -EAGAIN; + } + check = true; + } +#endif + + if (!check) { + BT_ERR("%s, fail", __func__); + return -EINVAL; + } + + if (net_buf_simple_tailroom(msg) < 4) { + BT_ERR("%s, Not enough tailroom for TransMIC", __func__); + return -EINVAL; + } + + if (msg->len > MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SDU_MAX_LEN) - 4) { + BT_ERR("%s, Too big message", __func__); + return -EMSGSIZE; + } + + if (!implicit_bind && !model_has_key(model, tx->ctx->app_idx)) { + BT_ERR("%s, Model not bound to AppKey 0x%04x", __func__, tx->ctx->app_idx); + return -EINVAL; + } + + return bt_mesh_trans_send(tx, msg, cb, cb_data); +} + +int bt_mesh_model_send(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *msg, + const struct bt_mesh_send_cb *cb, void *cb_data) +{ + struct bt_mesh_subnet *sub = NULL; + u8_t role; + + role = bt_mesh_get_model_role(model, ctx->srv_send); + if (role == ROLE_NVAL) { + BT_ERR("%s, Failed to get model role", __func__); + return -EINVAL; + } + +#if CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER + if (role == NODE) { + if (!bt_mesh_is_provisioner_en()) { + sub = bt_mesh_subnet_get(ctx->net_idx); + } + } +#endif + +#if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (role == PROVISIONER) { + if (bt_mesh_is_provisioner_en()) { + sub = provisioner_subnet_get(ctx->net_idx); + } + } +#endif + +#if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (role == NODE) { + sub = bt_mesh_subnet_get(ctx->net_idx); + } else if (role == PROVISIONER) { + if (bt_mesh_is_provisioner_en()) { + sub = provisioner_subnet_get(ctx->net_idx); + } + } else if (role == FAST_PROV) { +#if CONFIG_BLE_MESH_FAST_PROV + sub = get_fast_prov_subnet(ctx->net_idx); +#endif + } +#endif + + if (!sub) { + BT_ERR("%s, Failed to get subnet", __func__); + return -EINVAL; + } + + ctx->model = model; + + struct bt_mesh_net_tx tx = { + .sub = sub, + .ctx = ctx, + .src = bt_mesh_model_elem(model)->addr, + .xmit = bt_mesh_net_transmit_get(), + .friend_cred = 0, + }; + + return model_send(model, &tx, false, msg, cb, cb_data); +} + +int bt_mesh_model_publish(struct bt_mesh_model *model) +{ + struct bt_mesh_model_pub *pub = model->pub; + struct bt_mesh_app_key *key = NULL; + struct net_buf_simple *sdu = NULL; + struct bt_mesh_msg_ctx ctx = {0}; + struct bt_mesh_net_tx tx = { + .sub = NULL, + .ctx = &ctx, + .src = bt_mesh_model_elem(model)->addr, + .xmit = bt_mesh_net_transmit_get(), + }; + int err; + + BT_DBG("%s", __func__); + + if (!pub) { + BT_ERR("%s, Model has no publication support", __func__); + return -ENOTSUP; + } + + if (pub->addr == BLE_MESH_ADDR_UNASSIGNED) { + BT_WARN("%s, Unassigned model publish address", __func__); + return -EADDRNOTAVAIL; + } + +#if CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER + if (pub->dev_role == NODE) { + if (bt_mesh_is_provisioned()) { + key = bt_mesh_app_key_find(pub->key); + } + } +#endif + +#if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (pub->dev_role == PROVISIONER) { + if (bt_mesh_is_provisioner_en()) { + key = provisioner_app_key_find(pub->key); + } + } +#endif + +#if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (pub->dev_role == NODE) { + if (bt_mesh_is_provisioned()) { + key = bt_mesh_app_key_find(pub->key); + } + } else if (pub->dev_role == PROVISIONER) { + if (bt_mesh_is_provisioner_en()) { + key = provisioner_app_key_find(pub->key); + } + } +#endif + + if (!key) { + BT_ERR("%s, Failed to get AppKey", __func__); + return -EADDRNOTAVAIL; + } + + if (pub->msg->len + 4 > MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SDU_MAX_LEN)) { + BT_ERR("%s, Message does not fit maximum SDU size", __func__); + return -EMSGSIZE; + } + + if (pub->count) { + BT_WARN("%s, Clearing publish retransmit timer", __func__); + k_delayed_work_cancel(&pub->timer); + } + + ctx.addr = pub->addr; + ctx.send_ttl = pub->ttl; + ctx.net_idx = key->net_idx; + ctx.app_idx = key->app_idx; + ctx.srv_send = pub->dev_role == NODE ? true : false; + + tx.friend_cred = pub->cred; + +#if CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER + if (pub->dev_role == NODE) { + if (bt_mesh_is_provisioned()) { + tx.sub = bt_mesh_subnet_get(ctx.net_idx); + } + } +#endif + +#if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (pub->dev_role == PROVISIONER) { + if (bt_mesh_is_provisioner_en()) { + tx.sub = provisioner_subnet_get(ctx.net_idx); + } + } +#endif + +#if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (pub->dev_role == NODE) { + if (bt_mesh_is_provisioned()) { + tx.sub = bt_mesh_subnet_get(ctx.net_idx); + } + } else if (pub->dev_role == PROVISIONER) { + if (bt_mesh_is_provisioner_en()) { + tx.sub = provisioner_subnet_get(ctx.net_idx); + } + } +#endif + + if (!tx.sub) { + BT_ERR("%s, Failed to get subnet", __func__); + return -EADDRNOTAVAIL; + } + + pub->count = BLE_MESH_PUB_TRANSMIT_COUNT(pub->retransmit); + + BT_DBG("Publish Retransmit Count %u Interval %ums", pub->count, + BLE_MESH_PUB_TRANSMIT_INT(pub->retransmit)); + + sdu = bt_mesh_alloc_buf(pub->msg->len + 4); + if (!sdu) { + BT_ERR("%s, Failed to allocate memory", __func__); + return -ENOMEM; + } + + net_buf_simple_add_mem(sdu, pub->msg->data, pub->msg->len); + + err = model_send(model, &tx, true, sdu, &pub_sent_cb, model); + if (err) { + /* Don't try retransmissions for this publish attempt */ + pub->count = 0U; + /* Make sure the publish timer gets reset */ + publish_sent(err, model); + } + + bt_mesh_free_buf(sdu); + return err; +} + +struct bt_mesh_model *bt_mesh_model_find_vnd(struct bt_mesh_elem *elem, + u16_t company, u16_t id) +{ + u8_t i; + + for (i = 0U; i < elem->vnd_model_count; i++) { + if (elem->vnd_models[i].vnd.company == company && + elem->vnd_models[i].vnd.id == id) { + return &elem->vnd_models[i]; + } + } + + return NULL; +} + +struct bt_mesh_model *bt_mesh_model_find(struct bt_mesh_elem *elem, + u16_t id) +{ + u8_t i; + + for (i = 0U; i < elem->model_count; i++) { + if (elem->models[i].id == id) { + return &elem->models[i]; + } + } + + return NULL; +} + +const struct bt_mesh_comp *bt_mesh_comp_get(void) +{ + return dev_comp; +} diff --git a/components/bt/ble_mesh/mesh_core/access.h b/components/bt/ble_mesh/mesh_core/access.h new file mode 100644 index 0000000000..114c1662be --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/access.h @@ -0,0 +1,60 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ACCESS_H_ +#define _ACCESS_H_ + +#include "mesh_access.h" +#include "mesh_buf.h" +#include "net.h" + +/* bt_mesh_model.flags */ +enum { + BLE_MESH_MOD_BIND_PENDING = BIT(0), + BLE_MESH_MOD_SUB_PENDING = BIT(1), + BLE_MESH_MOD_PUB_PENDING = BIT(2), +}; + +void bt_mesh_elem_register(struct bt_mesh_elem *elem, u8_t count); + +u8_t bt_mesh_elem_count(void); + +/* Find local element based on unicast or group address */ +struct bt_mesh_elem *bt_mesh_elem_find(u16_t addr); + +struct bt_mesh_model *bt_mesh_model_find_vnd(struct bt_mesh_elem *elem, + u16_t company, u16_t id); +struct bt_mesh_model *bt_mesh_model_find(struct bt_mesh_elem *elem, + u16_t id); + +u16_t *bt_mesh_model_find_group(struct bt_mesh_model *mod, u16_t addr); + +bool bt_mesh_fixed_group_match(u16_t addr); + +void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, + struct bt_mesh_elem *elem, + bool vnd, bool primary, + void *user_data), + void *user_data); + +s32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod); + +void bt_mesh_comp_provision(u16_t addr); +void bt_mesh_comp_unprovision(void); + +u16_t bt_mesh_primary_addr(void); + +const struct bt_mesh_comp *bt_mesh_comp_get(void); + +struct bt_mesh_model *bt_mesh_model_get(bool vnd, u8_t elem_idx, u8_t mod_idx); + +void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf); + +int bt_mesh_comp_register(const struct bt_mesh_comp *comp); + +#endif /* _ACCESS_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/adv.c b/components/bt/ble_mesh/mesh_core/adv.c new file mode 100644 index 0000000000..87ef363061 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/adv.c @@ -0,0 +1,411 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" + +#include "osi/thread.h" +#include "sdkconfig.h" +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BLE_MESH_DEBUG_ADV) + +#include "mesh_util.h" +#include "mesh_buf.h" +#include "mesh_bearer_adapt.h" +#include "mesh_trace.h" +#include "mesh_hci.h" + +#include "mesh.h" +#include "adv.h" +#include "net.h" +#include "foundation.h" +#include "beacon.h" +#include "prov.h" +#include "proxy.h" + +#include "provisioner_prov.h" +#include "provisioner_proxy.h" +#include "provisioner_beacon.h" + +/* Convert from ms to 0.625ms units */ +#define ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5) + +/* Window and Interval are equal for continuous scanning */ +#define MESH_SCAN_INTERVAL 0x20 +#define MESH_SCAN_WINDOW 0x20 + +/* Pre-5.0 controllers enforce a minimum interval of 100ms + * whereas 5.0+ controllers can go down to 20ms. + */ +#define ADV_INT_DEFAULT_MS 100 +#define ADV_INT_FAST_MS 20 + +#if defined(CONFIG_BT_HOST_CRYPTO) +#define ADV_STACK_SIZE 1024 +#else +#define ADV_STACK_SIZE 768 +#endif + +static xQueueHandle xBleMeshQueue; +static const bt_mesh_addr_t *dev_addr; + +static const u8_t adv_type[] = { + [BLE_MESH_ADV_PROV] = BLE_MESH_DATA_MESH_PROV, + [BLE_MESH_ADV_DATA] = BLE_MESH_DATA_MESH_MESSAGE, + [BLE_MESH_ADV_BEACON] = BLE_MESH_DATA_MESH_BEACON, + [BLE_MESH_ADV_URI] = BLE_MESH_DATA_URI, +}; + +NET_BUF_POOL_DEFINE(adv_buf_pool, CONFIG_BLE_MESH_ADV_BUF_COUNT + 3 * CONFIG_BLE_MESH_PBA_SAME_TIME, + BLE_MESH_ADV_DATA_SIZE, BLE_MESH_ADV_USER_DATA_SIZE, NULL); + +static struct bt_mesh_adv adv_pool[CONFIG_BLE_MESH_ADV_BUF_COUNT + 3 * CONFIG_BLE_MESH_PBA_SAME_TIME]; + +static struct bt_mesh_adv *adv_alloc(int id) +{ + return &adv_pool[id]; +} + +static inline void adv_send_start(u16_t duration, int err, + const struct bt_mesh_send_cb *cb, + void *cb_data) +{ + if (cb && cb->start) { + cb->start(duration, err, cb_data); + } +} + +static inline void adv_send_end(int err, const struct bt_mesh_send_cb *cb, + void *cb_data) +{ + if (cb && cb->end) { + cb->end(err, cb_data); + } +} + +static inline int adv_send(struct net_buf *buf) +{ + const s32_t adv_int_min = ((bt_mesh_dev.hci_version >= BLE_MESH_HCI_VERSION_5_0) ? + ADV_INT_FAST_MS : ADV_INT_DEFAULT_MS); + const struct bt_mesh_send_cb *cb = BLE_MESH_ADV(buf)->cb; + void *cb_data = BLE_MESH_ADV(buf)->cb_data; + struct bt_mesh_adv_param param = {0}; + u16_t duration, adv_int; + struct bt_mesh_adv_data ad = {0}; + int err; + + adv_int = MAX(adv_int_min, + BLE_MESH_TRANSMIT_INT(BLE_MESH_ADV(buf)->xmit)); + duration = (BLE_MESH_TRANSMIT_COUNT(BLE_MESH_ADV(buf)->xmit) + 1) * + (adv_int + 10); + + BT_DBG("type %u len %u: %s", BLE_MESH_ADV(buf)->type, + buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("count %u interval %ums duration %ums", + BLE_MESH_TRANSMIT_COUNT(BLE_MESH_ADV(buf)->xmit) + 1, adv_int, + duration); + + ad.type = adv_type[BLE_MESH_ADV(buf)->type]; + ad.data_len = buf->len; + ad.data = buf->data; + + param.options = 0U; + param.interval_min = ADV_SCAN_UNIT(adv_int); + param.interval_max = param.interval_min; + + err = bt_le_adv_start(¶m, &ad, 1, NULL, 0); + net_buf_unref(buf); + adv_send_start(duration, err, cb, cb_data); + if (err) { + BT_ERR("%s, Advertising failed: err %d", __func__, err); + return err; + } + + BT_DBG("Advertising started. Sleeping %u ms", duration); + + k_sleep(K_MSEC(duration)); + + err = bt_le_adv_stop(); + adv_send_end(err, cb, cb_data); + if (err) { + BT_ERR("%s, Stop advertising failed: err %d", __func__, err); + return 0; + } + + BT_DBG("Advertising stopped"); + return 0; +} + +static void adv_thread(void *p) +{ + struct net_buf **buf = NULL; + bt_mesh_msg_t msg = {0}; + int status; + + BT_DBG("started"); + + buf = (struct net_buf **)(&msg.arg); + + while (1) { + *buf = NULL; +#if CONFIG_BLE_MESH_NODE + if (IS_ENABLED(CONFIG_BLE_MESH_PROXY)) { + xQueueReceive(xBleMeshQueue, &msg, K_NO_WAIT); + while (!(*buf)) { + s32_t timeout; + BT_DBG("Proxy advertising start"); + timeout = bt_mesh_proxy_adv_start(); + BT_DBG("Proxy Advertising up to %d ms", timeout); + xQueueReceive(xBleMeshQueue, &msg, timeout); + BT_DBG("Proxy advertising stop"); + bt_mesh_proxy_adv_stop(); + } + } else { + xQueueReceive(xBleMeshQueue, &msg, (portTickType)portMAX_DELAY); + } +#else + xQueueReceive(xBleMeshQueue, &msg, (portTickType)portMAX_DELAY); +#endif + + if (!(*buf)) { + continue; + } + + /* busy == 0 means this was canceled */ + if (BLE_MESH_ADV(*buf)->busy) { + BLE_MESH_ADV(*buf)->busy = 0U; + status = adv_send(*buf); + if (status) { + if (xQueueSendToFront(xBleMeshQueue, &msg, K_NO_WAIT) != pdTRUE) { + BT_ERR("%s, xQueueSendToFront failed", __func__); + } + } + } + + /* Give other threads a chance to run */ + taskYIELD(); + } +} + +void bt_mesh_adv_update(void) +{ + BT_DBG("%s", __func__); + bt_mesh_msg_t msg = {0}; + bt_mesh_task_post(&msg, 0); +} + +struct net_buf *bt_mesh_adv_create_from_pool(struct net_buf_pool *pool, + bt_mesh_adv_alloc_t get_id, + enum bt_mesh_adv_type type, + u8_t xmit, s32_t timeout) +{ + struct bt_mesh_adv *adv; + struct net_buf *buf; + + if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_SUSPENDED)) { + BT_WARN("Refusing to allocate buffer while suspended"); + return NULL; + } + + buf = net_buf_alloc(pool, timeout); + if (!buf) { + return NULL; + } + + BT_DBG("%s, pool = %p, buf_count = %d, uinit_count = %d", __func__, + buf->pool, pool->buf_count, pool->uninit_count); + + adv = get_id(net_buf_id(buf)); + BLE_MESH_ADV(buf) = adv; + + (void)memset(adv, 0, sizeof(*adv)); + + adv->type = type; + adv->xmit = xmit; + + return buf; +} + +struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, u8_t xmit, + s32_t timeout) +{ + return bt_mesh_adv_create_from_pool(&adv_buf_pool, adv_alloc, type, + xmit, timeout); +} + +void bt_mesh_task_post(bt_mesh_msg_t *msg, uint32_t timeout) +{ + BT_DBG("%s", __func__); + if (xQueueSend(xBleMeshQueue, msg, timeout) != pdTRUE) { + BT_ERR("%s, Failed to post msg to queue", __func__); + } +} + +void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, + void *cb_data) +{ + BT_DBG("type 0x%02x len %u: %s", BLE_MESH_ADV(buf)->type, buf->len, + bt_hex(buf->data, buf->len)); + + BLE_MESH_ADV(buf)->cb = cb; + BLE_MESH_ADV(buf)->cb_data = cb_data; + BLE_MESH_ADV(buf)->busy = 1U; + + bt_mesh_msg_t msg = {0}; + msg.arg = (void *)net_buf_ref(buf); + bt_mesh_task_post(&msg, portMAX_DELAY); +} + +const bt_mesh_addr_t *bt_mesh_pba_get_addr(void) +{ + return dev_addr; +} + +static void bt_mesh_scan_cb(const bt_mesh_addr_t *addr, s8_t rssi, + u8_t adv_type, struct net_buf_simple *buf) +{ +#if CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT + u16_t uuid = 0; +#endif + + if (adv_type != BLE_MESH_ADV_NONCONN_IND && adv_type != BLE_MESH_ADV_IND) { + return; + } + + BT_DBG("%s, len %u: %s", __func__, buf->len, bt_hex(buf->data, buf->len)); + + dev_addr = addr; + + while (buf->len > 1) { + struct net_buf_simple_state state; + u8_t len, type; + + len = net_buf_simple_pull_u8(buf); + /* Check for early termination */ + if (len == 0U) { + return; + } + + if (len > buf->len) { + BT_WARN("AD malformed"); + return; + } + + net_buf_simple_save(buf, &state); + + type = net_buf_simple_pull_u8(buf); + + buf->len = len - 1; + +#if 0 + /* TODO: Check with BLE Mesh BQB test cases */ + if ((type == BLE_MESH_DATA_MESH_PROV || type == BLE_MESH_DATA_MESH_MESSAGE || + type == BLE_MESH_DATA_MESH_BEACON) && (adv_type != BLE_MESH_ADV_NONCONN_IND)) { + BT_DBG("%s, ignore BLE Mesh packet (type 0x%02x) with adv_type 0x%02x", + __func__, type, adv_type); + return; + } +#endif + + switch (type) { + case BLE_MESH_DATA_MESH_MESSAGE: + bt_mesh_net_recv(buf, rssi, BLE_MESH_NET_IF_ADV); + break; +#if CONFIG_BLE_MESH_PB_ADV + case BLE_MESH_DATA_MESH_PROV: +#if CONFIG_BLE_MESH_NODE + if (!bt_mesh_is_provisioner_en()) { + bt_mesh_pb_adv_recv(buf); + } +#endif +#if CONFIG_BLE_MESH_PROVISIONER + if (bt_mesh_is_provisioner_en()) { + provisioner_pb_adv_recv(buf); + } +#endif + break; +#endif /* CONFIG_BLE_MESH_PB_ADV */ + case BLE_MESH_DATA_MESH_BEACON: +#if CONFIG_BLE_MESH_NODE + if (!bt_mesh_is_provisioner_en()) { + bt_mesh_beacon_recv(buf); + } +#endif +#if CONFIG_BLE_MESH_PROVISIONER + if (bt_mesh_is_provisioner_en()) { + provisioner_beacon_recv(buf); + } +#endif + break; +#if CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT + case BLE_MESH_DATA_FLAGS: + if (bt_mesh_is_provisioner_en()) { + if (!provisioner_flags_match(buf)) { + BT_DBG("Flags mismatch, ignore this adv pkt"); + return; + } + } + break; + case BLE_MESH_DATA_UUID16_ALL: + if (bt_mesh_is_provisioner_en()) { + uuid = provisioner_srv_uuid_recv(buf); + if (!uuid) { + BT_DBG("Service UUID mismatch, ignore this adv pkt"); + return; + } + } + break; + case BLE_MESH_DATA_SVC_DATA16: + if (bt_mesh_is_provisioner_en()) { + provisioner_srv_data_recv(buf, addr, uuid); + } + break; +#endif /* CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT */ + default: + break; + } + + net_buf_simple_restore(buf, &state); + net_buf_simple_pull(buf, len); + } + + return; +} + +void bt_mesh_adv_init(void) +{ + xBleMeshQueue = xQueueCreate(150, sizeof(bt_mesh_msg_t)); + xTaskCreatePinnedToCore(adv_thread, "BLE_Mesh_ADV_Task", 3072, NULL, + configMAX_PRIORITIES - 7, NULL, TASK_PINNED_TO_CORE); +} + +int bt_mesh_scan_enable(void) +{ + struct bt_mesh_scan_param scan_param = { + .type = BLE_MESH_SCAN_PASSIVE, +#if defined(CONFIG_BLE_MESH_USE_DUPLICATE_SCAN) + .filter_dup = BLE_MESH_SCAN_FILTER_DUP_ENABLE, +#else + .filter_dup = BLE_MESH_SCAN_FILTER_DUP_DISABLE, +#endif + .interval = MESH_SCAN_INTERVAL, + .window = MESH_SCAN_WINDOW + }; + + BT_DBG("%s", __func__); + + return bt_le_scan_start(&scan_param, bt_mesh_scan_cb); +} + +int bt_mesh_scan_disable(void) +{ + BT_DBG("%s", __func__); + + return bt_le_scan_stop(); +} diff --git a/components/bt/ble_mesh/mesh_core/adv.h b/components/bt/ble_mesh/mesh_core/adv.h new file mode 100644 index 0000000000..b827af59ea --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/adv.h @@ -0,0 +1,86 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ADV_H_ +#define _ADV_H_ + +#include "mesh_bearer_adapt.h" + +/* Maximum advertising data payload for a single data type */ +#define BLE_MESH_ADV_DATA_SIZE 29 + +/* The user data is a pointer (4 bytes) to struct bt_mesh_adv */ +#define BLE_MESH_ADV_USER_DATA_SIZE 4 + +#define BLE_MESH_ADV(buf) (*(struct bt_mesh_adv **)net_buf_user_data(buf)) + +typedef struct bt_mesh_msg { + uint8_t sig; //event signal + uint8_t aid; //application id + uint8_t pid; //profile id + uint8_t act; //profile action, defined in seprerate header files + void *arg; //param for btc function or function param +} bt_mesh_msg_t; + +enum bt_mesh_adv_type { + BLE_MESH_ADV_PROV, + BLE_MESH_ADV_DATA, + BLE_MESH_ADV_BEACON, + BLE_MESH_ADV_URI, +}; + +typedef void (*bt_mesh_adv_func_t)(struct net_buf *buf, u16_t duration, + int err, void *user_data); + +struct bt_mesh_adv { + const struct bt_mesh_send_cb *cb; + void *cb_data; + + u8_t type: 2, + busy: 1; + u8_t xmit; + + union { + /* Address, used e.g. for Friend Queue messages */ + u16_t addr; + + /* For transport layer segment sending */ + struct { + u8_t attempts; + } seg; + }; +}; + +typedef struct bt_mesh_adv *(*bt_mesh_adv_alloc_t)(int id); + +/* xmit_count: Number of retransmissions, i.e. 0 == 1 transmission */ +struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, u8_t xmit, + s32_t timeout); + +struct net_buf *bt_mesh_adv_create_from_pool(struct net_buf_pool *pool, + bt_mesh_adv_alloc_t get_id, + enum bt_mesh_adv_type type, + u8_t xmit, s32_t timeout); + +void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, + void *cb_data); + +const bt_mesh_addr_t *bt_mesh_pba_get_addr(void); + +void bt_mesh_adv_update(void); + +void bt_mesh_adv_init(void); + +int bt_mesh_scan_enable(void); + +int bt_mesh_scan_disable(void); + +void bt_mesh_task_post(bt_mesh_msg_t *msg, uint32_t timeout); + +#endif /* _ADV_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/beacon.c b/components/bt/ble_mesh/mesh_core/beacon.c new file mode 100644 index 0000000000..a62cf073ad --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/beacon.c @@ -0,0 +1,422 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "sdkconfig.h" +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BLE_MESH_DEBUG_BEACON) + +#include "mesh_util.h" +#include "mesh_buf.h" +#include "mesh_main.h" +#include "mesh_trace.h" + +#include "adv.h" +#include "mesh.h" +#include "net.h" +#include "prov.h" +#include "crypto.h" +#include "beacon.h" +#include "foundation.h" + +#if CONFIG_BLE_MESH_NODE + +#if defined(CONFIG_BLE_MESH_FAST_PROV) +#define UNPROVISIONED_INTERVAL K_SECONDS(3) +#else +#define UNPROVISIONED_INTERVAL K_SECONDS(5) +#endif /* CONFIG_BLE_MESH_FAST_PROV */ +#define PROVISIONED_INTERVAL K_SECONDS(10) + +#define BEACON_TYPE_UNPROVISIONED 0x00 +#define BEACON_TYPE_SECURE 0x01 + +/* 3 transmissions, 20ms interval */ +#define UNPROV_XMIT BLE_MESH_TRANSMIT(2, 20) + +/* 1 transmission, 20ms interval */ +#define PROV_XMIT BLE_MESH_TRANSMIT(0, 20) + +static struct k_delayed_work beacon_timer; + +static struct bt_mesh_subnet *cache_check(u8_t data[21]) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; + + if (sub->net_idx == BLE_MESH_KEY_UNUSED) { + continue; + } + + if (!memcmp(sub->beacon_cache, data, 21)) { + return sub; + } + } + + return NULL; +} + +static void cache_add(u8_t data[21], struct bt_mesh_subnet *sub) +{ + memcpy(sub->beacon_cache, data, 21); +} + +static void beacon_complete(int err, void *user_data) +{ + struct bt_mesh_subnet *sub = user_data; + + BT_DBG("err %d", err); + + sub->beacon_sent = k_uptime_get_32(); +} + +void bt_mesh_beacon_create(struct bt_mesh_subnet *sub, + struct net_buf_simple *buf) +{ + u8_t flags = bt_mesh_net_flags(sub); + struct bt_mesh_subnet_keys *keys; + + net_buf_simple_add_u8(buf, BEACON_TYPE_SECURE); + + if (sub->kr_flag) { + keys = &sub->keys[1]; + } else { + keys = &sub->keys[0]; + } + + net_buf_simple_add_u8(buf, flags); + + /* Network ID */ + net_buf_simple_add_mem(buf, keys->net_id, 8); + + /* IV Index */ + net_buf_simple_add_be32(buf, bt_mesh.iv_index); + + net_buf_simple_add_mem(buf, sub->auth, 8); + + BT_DBG("net_idx 0x%04x flags 0x%02x NetID %s", sub->net_idx, + flags, bt_hex(keys->net_id, 8)); + BT_DBG("IV Index 0x%08x Auth %s", bt_mesh.iv_index, + bt_hex(sub->auth, 8)); +} + +/* If the interval has passed or is within 5 seconds from now send a beacon */ +#define BEACON_THRESHOLD(sub) (K_SECONDS(10 * ((sub)->beacons_last + 1)) - \ + K_SECONDS(5)) + +static int secure_beacon_send(void) +{ + static const struct bt_mesh_send_cb send_cb = { + .end = beacon_complete, + }; + u32_t now = k_uptime_get_32(); + int i; + + BT_DBG("%s", __func__); + + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; + struct net_buf *buf; + u32_t time_diff; + + if (sub->net_idx == BLE_MESH_KEY_UNUSED) { + continue; + } + + time_diff = now - sub->beacon_sent; + if (time_diff < K_SECONDS(600) && + time_diff < BEACON_THRESHOLD(sub)) { + continue; + } + + buf = bt_mesh_adv_create(BLE_MESH_ADV_BEACON, PROV_XMIT, + K_NO_WAIT); + if (!buf) { + BT_ERR("%s, Unable to allocate beacon buffer", __func__); + return -ENOBUFS; + } + + bt_mesh_beacon_create(sub, &buf->b); + + bt_mesh_adv_send(buf, &send_cb, sub); + net_buf_unref(buf); + } + + return 0; +} + +static int unprovisioned_beacon_send(void) +{ +#if defined(CONFIG_BLE_MESH_PB_ADV) + const struct bt_mesh_prov *prov; + u8_t uri_hash[16] = { 0 }; + struct net_buf *buf; + u16_t oob_info; + + BT_DBG("%s", __func__); + + buf = bt_mesh_adv_create(BLE_MESH_ADV_BEACON, UNPROV_XMIT, K_NO_WAIT); + if (!buf) { + BT_ERR("%s, Unable to allocate beacon buffer", __func__); + return -ENOBUFS; + } + + prov = bt_mesh_prov_get(); + + net_buf_add_u8(buf, BEACON_TYPE_UNPROVISIONED); + net_buf_add_mem(buf, prov->uuid, 16); + + if (prov->uri && bt_mesh_s1(prov->uri, uri_hash) == 0) { + oob_info = prov->oob_info | BLE_MESH_PROV_OOB_URI; + } else { + oob_info = prov->oob_info; + } + + net_buf_add_be16(buf, oob_info); + net_buf_add_mem(buf, uri_hash, 4); + + bt_mesh_adv_send(buf, NULL, NULL); + net_buf_unref(buf); + + if (prov->uri) { + size_t len; + + buf = bt_mesh_adv_create(BLE_MESH_ADV_URI, UNPROV_XMIT, + K_NO_WAIT); + if (!buf) { + BT_ERR("Unable to allocate URI buffer"); + return -ENOBUFS; + } + + len = strlen(prov->uri); + if (net_buf_tailroom(buf) < len) { + BT_WARN("Too long URI to fit advertising data"); + } else { + net_buf_add_mem(buf, prov->uri, len); + bt_mesh_adv_send(buf, NULL, NULL); + } + + net_buf_unref(buf); + } + +#endif /* CONFIG_BLE_MESH_PB_ADV */ + return 0; +} + +static void update_beacon_observation(void) +{ + static bool first_half; + int i; + + /* Observation period is 20 seconds, whereas the beacon timer + * runs every 10 seconds. We process what's happened during the + * window only after the second half. + */ + first_half = !first_half; + if (first_half) { + return; + } + + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; + + if (sub->net_idx == BLE_MESH_KEY_UNUSED) { + continue; + } + + sub->beacons_last = sub->beacons_cur; + sub->beacons_cur = 0U; + } +} + +static void beacon_send(struct k_work *work) +{ + /* Don't send anything if we have an active provisioning link */ + if (IS_ENABLED(CONFIG_BLE_MESH_PROV) && bt_prov_active()) { + k_delayed_work_submit(&beacon_timer, UNPROVISIONED_INTERVAL); + return; + } + + BT_DBG("%s", __func__); + + if (bt_mesh_is_provisioned()) { + update_beacon_observation(); + secure_beacon_send(); + + /* Only resubmit if beaconing is still enabled */ + if (bt_mesh_beacon_get() == BLE_MESH_BEACON_ENABLED || + bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_INITIATOR)) { + k_delayed_work_submit(&beacon_timer, + PROVISIONED_INTERVAL); + } + } else { + unprovisioned_beacon_send(); + k_delayed_work_submit(&beacon_timer, UNPROVISIONED_INTERVAL); + } + +} + +static void secure_beacon_recv(struct net_buf_simple *buf) +{ + u8_t *data, *net_id, *auth; + struct bt_mesh_subnet *sub; + u32_t iv_index; + bool new_key, kr_change, iv_change; + u8_t flags; + + if (buf->len < 21) { + BT_ERR("%s, Too short secure beacon (len %u)", __func__, buf->len); + return; + } + + sub = cache_check(buf->data); + if (sub) { + /* We've seen this beacon before - just update the stats */ + goto update_stats; + } + + /* So we can add to the cache if auth matches */ + data = buf->data; + + flags = net_buf_simple_pull_u8(buf); + net_id = net_buf_simple_pull_mem(buf, 8); + iv_index = net_buf_simple_pull_be32(buf); + auth = buf->data; + + BT_DBG("flags 0x%02x id %s iv_index 0x%08x", + flags, bt_hex(net_id, 8), iv_index); + + sub = bt_mesh_subnet_find(net_id, flags, iv_index, auth, &new_key); + if (!sub) { + BT_DBG("No subnet that matched beacon"); + return; + } + + if (sub->kr_phase == BLE_MESH_KR_PHASE_2 && !new_key) { + BT_WARN("Ignoring Phase 2 KR Update secured using old key"); + return; + } + + cache_add(data, sub); + + /* If we have NetKey0 accept initiation only from it */ + if (bt_mesh_subnet_get(BLE_MESH_KEY_PRIMARY) && + sub->net_idx != BLE_MESH_KEY_PRIMARY) { + BT_WARN("Ignoring secure beacon on non-primary subnet"); + goto update_stats; + } + + BT_DBG("net_idx 0x%04x iv_index 0x%08x, current iv_index 0x%08x", + sub->net_idx, iv_index, bt_mesh.iv_index); + + if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_INITIATOR) && + (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS) == + BLE_MESH_IV_UPDATE(flags))) { + bt_mesh_beacon_ivu_initiator(false); + } + + iv_change = bt_mesh_net_iv_update(iv_index, BLE_MESH_IV_UPDATE(flags)); + + kr_change = bt_mesh_kr_update(sub, BLE_MESH_KEY_REFRESH(flags), new_key); + if (kr_change) { + bt_mesh_net_beacon_update(sub); + } + + if (iv_change) { + /* Update all subnets */ + bt_mesh_net_sec_update(NULL); + } else if (kr_change) { + /* Key Refresh without IV Update only impacts one subnet */ + bt_mesh_net_sec_update(sub); + } + +update_stats: + if (bt_mesh_beacon_get() == BLE_MESH_BEACON_ENABLED && + sub->beacons_cur < 0xff) { + sub->beacons_cur++; + } +} + +void bt_mesh_beacon_recv(struct net_buf_simple *buf) +{ + u8_t type; + + BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); + + if (buf->len < 1) { + BT_ERR("%s, Too short beacon", __func__); + return; + } + + type = net_buf_simple_pull_u8(buf); + switch (type) { + case BEACON_TYPE_UNPROVISIONED: + BT_DBG("Ignoring unprovisioned device beacon"); + break; + case BEACON_TYPE_SECURE: + secure_beacon_recv(buf); + break; + default: + BT_DBG("Unknown beacon type 0x%02x", type); + break; + } +} + +void bt_mesh_beacon_init(void) +{ + k_delayed_work_init(&beacon_timer, beacon_send); +} + +void bt_mesh_beacon_ivu_initiator(bool enable) +{ + bt_mesh_atomic_set_bit_to(bt_mesh.flags, BLE_MESH_IVU_INITIATOR, enable); + + if (enable) { + k_work_submit(&beacon_timer.work); + } else if (bt_mesh_beacon_get() == BLE_MESH_BEACON_DISABLED) { + k_delayed_work_cancel(&beacon_timer); + } +} + +void bt_mesh_beacon_enable(void) +{ + int i; + + if (!bt_mesh_is_provisioned()) { + k_work_submit(&beacon_timer.work); + return; + } + + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; + + if (sub->net_idx == BLE_MESH_KEY_UNUSED) { + continue; + } + + sub->beacons_last = 0U; + sub->beacons_cur = 0U; + + bt_mesh_net_beacon_update(sub); + } + + k_work_submit(&beacon_timer.work); +} + +void bt_mesh_beacon_disable(void) +{ + if (!bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_INITIATOR)) { + k_delayed_work_cancel(&beacon_timer); + } +} + +#endif /* CONFIG_BLE_MESH_NODE */ diff --git a/components/bt/ble_mesh/mesh_core/beacon.h b/components/bt/ble_mesh/mesh_core/beacon.h new file mode 100644 index 0000000000..f410fa5d59 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/beacon.h @@ -0,0 +1,24 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BEACON_H_ +#define _BEACON_H_ + +void bt_mesh_beacon_enable(void); +void bt_mesh_beacon_disable(void); + +void bt_mesh_beacon_ivu_initiator(bool enable); + +void bt_mesh_beacon_recv(struct net_buf_simple *buf); + +void bt_mesh_beacon_create(struct bt_mesh_subnet *sub, + struct net_buf_simple *buf); + +void bt_mesh_beacon_init(void); + +#endif /* _BEACON_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/cfg_cli.c b/components/bt/ble_mesh/mesh_core/cfg_cli.c new file mode 100644 index 0000000000..aa2daf0da8 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/cfg_cli.c @@ -0,0 +1,1657 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "osi/allocator.h" +#include "sdkconfig.h" +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BLE_MESH_DEBUG_MODEL) + +#include "mesh_types.h" +#include "mesh_util.h" +#include "mesh_kernel.h" +#include "mesh_trace.h" +#include "cfg_cli.h" + +#include "mesh.h" +#include "foundation.h" +#include "mesh_common.h" +#include "btc_ble_mesh_config_model.h" + +#define CID_NVAL 0xffff + +s32_t config_msg_timeout; + +static bt_mesh_config_client_t *cli; + +static const bt_mesh_client_op_pair_t cfg_op_pair[] = { + { OP_BEACON_GET, OP_BEACON_STATUS }, + { OP_BEACON_SET, OP_BEACON_STATUS }, + { OP_DEV_COMP_DATA_GET, OP_DEV_COMP_DATA_STATUS }, + { OP_DEFAULT_TTL_GET, OP_DEFAULT_TTL_STATUS }, + { OP_DEFAULT_TTL_SET, OP_DEFAULT_TTL_STATUS }, + { OP_GATT_PROXY_GET, OP_GATT_PROXY_STATUS }, + { OP_GATT_PROXY_SET, OP_GATT_PROXY_STATUS }, + { OP_RELAY_GET, OP_RELAY_STATUS }, + { OP_RELAY_SET, OP_RELAY_STATUS }, + { OP_MOD_PUB_GET, OP_MOD_PUB_STATUS }, + { OP_MOD_PUB_SET, OP_MOD_PUB_STATUS }, + { OP_MOD_PUB_VA_SET, OP_MOD_PUB_STATUS }, + { OP_MOD_SUB_ADD, OP_MOD_SUB_STATUS }, + { OP_MOD_SUB_VA_ADD, OP_MOD_SUB_STATUS }, + { OP_MOD_SUB_DEL, OP_MOD_SUB_STATUS }, + { OP_MOD_SUB_VA_DEL, OP_MOD_SUB_STATUS }, + { OP_MOD_SUB_OVERWRITE, OP_MOD_SUB_STATUS }, + { OP_MOD_SUB_VA_OVERWRITE, OP_MOD_SUB_STATUS }, + { OP_MOD_SUB_DEL_ALL, OP_MOD_SUB_STATUS }, + { OP_MOD_SUB_GET, OP_MOD_SUB_LIST }, + { OP_MOD_SUB_GET_VND, OP_MOD_SUB_LIST_VND }, + { OP_NET_KEY_ADD, OP_NET_KEY_STATUS }, + { OP_NET_KEY_UPDATE, OP_NET_KEY_STATUS }, + { OP_NET_KEY_DEL, OP_NET_KEY_STATUS }, + { OP_NET_KEY_GET, OP_NET_KEY_LIST }, + { OP_APP_KEY_ADD, OP_APP_KEY_STATUS }, + { OP_APP_KEY_UPDATE, OP_APP_KEY_STATUS }, + { OP_APP_KEY_DEL, OP_APP_KEY_STATUS }, + { OP_APP_KEY_GET, OP_APP_KEY_LIST }, + { OP_NODE_IDENTITY_GET, OP_NODE_IDENTITY_STATUS }, + { OP_NODE_IDENTITY_SET, OP_NODE_IDENTITY_STATUS }, + { OP_MOD_APP_BIND, OP_MOD_APP_STATUS }, + { OP_MOD_APP_UNBIND, OP_MOD_APP_STATUS }, + { OP_SIG_MOD_APP_GET, OP_SIG_MOD_APP_LIST }, + { OP_VND_MOD_APP_GET, OP_VND_MOD_APP_LIST }, + { OP_NODE_RESET, OP_NODE_RESET_STATUS }, + { OP_FRIEND_GET, OP_FRIEND_STATUS }, + { OP_FRIEND_SET, OP_FRIEND_STATUS }, + { OP_KRP_GET, OP_KRP_STATUS }, + { OP_KRP_SET, OP_KRP_STATUS }, + { OP_HEARTBEAT_PUB_GET, OP_HEARTBEAT_PUB_STATUS }, + { OP_HEARTBEAT_PUB_SET, OP_HEARTBEAT_PUB_STATUS }, + { OP_HEARTBEAT_SUB_GET, OP_HEARTBEAT_SUB_STATUS }, + { OP_HEARTBEAT_SUB_SET, OP_HEARTBEAT_SUB_STATUS }, + { OP_LPN_TIMEOUT_GET, OP_LPN_TIMEOUT_STATUS }, + { OP_NET_TRANSMIT_GET, OP_NET_TRANSMIT_STATUS }, + { OP_NET_TRANSMIT_SET, OP_NET_TRANSMIT_STATUS }, +}; + +static void timeout_handler(struct k_work *work) +{ + config_internal_data_t *internal = NULL; + bt_mesh_config_client_t *client = NULL; + bt_mesh_client_node_t *node = NULL; + + BT_WARN("Receive configuration status message timeout"); + + node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work); + if (!node || !node->ctx.model) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + client = (bt_mesh_config_client_t *)node->ctx.model->user_data; + if (!client) { + BT_ERR("%s, Config Client user_data is NULL", __func__); + return; + } + + internal = (config_internal_data_t *)client->internal_data; + if (!internal) { + BT_ERR("%s, Config Client internal_data is NULL", __func__); + return; + } + + bt_mesh_callback_config_status_to_btc(node->opcode, 0x03, node->ctx.model, + &node->ctx, NULL, 0); + + bt_mesh_client_free_node(&internal->queue, node); + + return; +} + +static void cfg_client_cancel(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + void *status, size_t len) +{ + config_internal_data_t *data = NULL; + bt_mesh_client_node_t *node = NULL; + struct net_buf_simple buf = {0}; + u8_t evt_type = 0xFF; + + if (!model || !ctx) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + data = (config_internal_data_t *)cli->internal_data; + if (!data) { + BT_ERR("%s, Config Client internal_data is NULL", __func__); + return; + } + + /* If it is a publish message, sent to the user directly. */ + buf.data = (u8_t *)status; + buf.len = (u16_t)len; + node = bt_mesh_is_model_message_publish(model, ctx, &buf, true); + if (!node) { + BT_DBG("Unexpected config status message 0x%x", ctx->recv_op); + } else { + switch (node->opcode) { + case OP_BEACON_GET: + case OP_DEV_COMP_DATA_GET: + case OP_DEFAULT_TTL_GET: + case OP_GATT_PROXY_GET: + case OP_RELAY_GET: + case OP_MOD_PUB_GET: + case OP_MOD_SUB_GET: + case OP_MOD_SUB_GET_VND: + case OP_NET_KEY_GET: + case OP_APP_KEY_GET: + case OP_NODE_IDENTITY_GET: + case OP_SIG_MOD_APP_GET: + case OP_VND_MOD_APP_GET: + case OP_FRIEND_GET: + case OP_KRP_GET: + case OP_HEARTBEAT_PUB_GET: + case OP_HEARTBEAT_SUB_GET: + case OP_LPN_TIMEOUT_GET: + case OP_NET_TRANSMIT_GET: + evt_type = 0x00; + break; + case OP_BEACON_SET: + case OP_DEFAULT_TTL_SET: + case OP_GATT_PROXY_SET: + case OP_RELAY_SET: + case OP_MOD_PUB_SET: + case OP_MOD_PUB_VA_SET: + case OP_MOD_SUB_ADD: + case OP_MOD_SUB_VA_ADD: + case OP_MOD_SUB_DEL: + case OP_MOD_SUB_VA_DEL: + case OP_MOD_SUB_OVERWRITE: + case OP_MOD_SUB_VA_OVERWRITE: + case OP_MOD_SUB_DEL_ALL: + case OP_NET_KEY_ADD: + case OP_NET_KEY_UPDATE: + case OP_NET_KEY_DEL: + case OP_APP_KEY_ADD: + case OP_APP_KEY_UPDATE: + case OP_APP_KEY_DEL: + case OP_NODE_IDENTITY_SET: + case OP_MOD_APP_BIND: + case OP_MOD_APP_UNBIND: + case OP_NODE_RESET: + case OP_FRIEND_SET: + case OP_KRP_SET: + case OP_HEARTBEAT_PUB_SET: + case OP_HEARTBEAT_SUB_SET: + case OP_NET_TRANSMIT_SET: + evt_type = 0x01; + break; + default: + break; + } + + bt_mesh_callback_config_status_to_btc(node->opcode, evt_type, model, + ctx, (const u8_t *)status, len); + // Don't forget to release the node at the end. + bt_mesh_client_free_node(&data->queue, node); + } + + switch (ctx->recv_op) { + case OP_DEV_COMP_DATA_STATUS: { + struct bt_mesh_cfg_comp_data_status *val; + val = (struct bt_mesh_cfg_comp_data_status *)status; + bt_mesh_free_buf(val->comp_data); + break; + } + case OP_MOD_SUB_LIST: + case OP_MOD_SUB_LIST_VND: { + struct bt_mesh_cfg_mod_sub_list *val = status; + bt_mesh_free_buf(val->addr); + break; + } + case OP_NET_KEY_LIST: { + struct bt_mesh_cfg_net_key_list *val = status; + bt_mesh_free_buf(val->net_idx); + break; + } + case OP_APP_KEY_LIST: { + struct bt_mesh_cfg_app_key_list *val = status; + bt_mesh_free_buf(val->app_idx); + break; + } + case OP_SIG_MOD_APP_LIST: + case OP_VND_MOD_APP_LIST: { + struct bt_mesh_cfg_mod_app_list *val = status; + bt_mesh_free_buf(val->app_idx); + break; + } + default: + break; + } +} + +static void comp_data_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_cfg_comp_data_status status = {0}; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + status.page = net_buf_simple_pull_u8(buf); + status.comp_data = bt_mesh_alloc_buf(buf->len); + if (!status.comp_data) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + + net_buf_simple_add_mem(status.comp_data, buf->data, buf->len); + + cfg_client_cancel(model, ctx, &status, sizeof(struct bt_mesh_cfg_comp_data_status)); +} + +static void state_status_u8(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + u8_t status = 0; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + status = net_buf_simple_pull_u8(buf); + + cfg_client_cancel(model, ctx, &status, sizeof(u8_t)); +} + +static void beacon_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + state_status_u8(model, ctx, buf); +} + +static void ttl_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + state_status_u8(model, ctx, buf); +} + +static void friend_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + state_status_u8(model, ctx, buf); +} + +static void gatt_proxy_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + state_status_u8(model, ctx, buf); +} + +static void relay_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_cfg_relay_status status = {0}; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + status.relay = net_buf_simple_pull_u8(buf); + status.retransmit = net_buf_simple_pull_u8(buf); + + cfg_client_cancel(model, ctx, &status, sizeof(struct bt_mesh_cfg_relay_status)); +} + +static void net_key_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_cfg_netkey_status status = {0}; + u16_t app_idx; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + status.status = net_buf_simple_pull_u8(buf); + key_idx_unpack(buf, &status.net_idx, &app_idx); + + cfg_client_cancel(model, ctx, &status, sizeof(struct bt_mesh_cfg_netkey_status)); +} + +static void app_key_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_cfg_appkey_status status = {0}; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + status.status = net_buf_simple_pull_u8(buf); + key_idx_unpack(buf, &status.net_idx, &status.app_idx); + + cfg_client_cancel(model, ctx, &status, sizeof(struct bt_mesh_cfg_appkey_status)); +} + +static void mod_app_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_cfg_mod_app_status status = {0}; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + status.status = net_buf_simple_pull_u8(buf); + status.elem_addr = net_buf_simple_pull_le16(buf); + status.app_idx = net_buf_simple_pull_le16(buf); + if (buf->len >= 4) { + status.cid = net_buf_simple_pull_le16(buf); + } else { + status.cid = CID_NVAL; + } + status.mod_id = net_buf_simple_pull_le16(buf); + + cfg_client_cancel(model, ctx, &status, sizeof(struct bt_mesh_cfg_mod_app_status)); +} + +static void mod_pub_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_cfg_mod_pub_status status = {0}; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + status.status = net_buf_simple_pull_u8(buf); + status.elem_addr = net_buf_simple_pull_le16(buf); + status.addr = net_buf_simple_pull_le16(buf); + status.app_idx = net_buf_simple_pull_le16(buf); + status.cred_flag = (status.app_idx & BIT(12)); + status.app_idx &= BIT_MASK(12); + status.ttl = net_buf_simple_pull_u8(buf); + status.period = net_buf_simple_pull_u8(buf); + status.transmit = net_buf_simple_pull_u8(buf); + if (buf->len >= 4) { + status.cid = net_buf_simple_pull_le16(buf); + } else { + status.cid = CID_NVAL; + } + status.mod_id = net_buf_simple_pull_le16(buf); + + cfg_client_cancel(model, ctx, &status, sizeof(struct bt_mesh_cfg_mod_pub_status)); +} + +static void mod_sub_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_cfg_mod_sub_status status = {0}; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + status.status = net_buf_simple_pull_u8(buf); + status.elem_addr = net_buf_simple_pull_le16(buf); + status.sub_addr = net_buf_simple_pull_le16(buf); + if (buf->len >= 4) { + status.cid = net_buf_simple_pull_le16(buf); + } else { + status.cid = CID_NVAL; + } + status.mod_id = net_buf_simple_pull_le16(buf); + + cfg_client_cancel(model, ctx, &status, sizeof(struct bt_mesh_cfg_mod_sub_status)); +} + +static void hb_sub_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_cfg_hb_sub_status status = {0}; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + status.status = net_buf_simple_pull_u8(buf); + status.src = net_buf_simple_pull_le16(buf); + status.dst = net_buf_simple_pull_le16(buf); + status.period = net_buf_simple_pull_u8(buf); + status.count = net_buf_simple_pull_u8(buf); + status.min = net_buf_simple_pull_u8(buf); + status.max = net_buf_simple_pull_u8(buf); + + cfg_client_cancel(model, ctx, &status, sizeof(struct bt_mesh_cfg_hb_sub_status)); +} + +static void hb_pub_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_cfg_hb_pub_status status = {0}; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + status.status = net_buf_simple_pull_u8(buf); + status.dst = net_buf_simple_pull_le16(buf); + status.count = net_buf_simple_pull_u8(buf); + status.period = net_buf_simple_pull_u8(buf); + status.ttl = net_buf_simple_pull_u8(buf); + status.feat = net_buf_simple_pull_u8(buf); + status.net_idx = net_buf_simple_pull_u8(buf); + + cfg_client_cancel(model, ctx, &status, sizeof(struct bt_mesh_cfg_hb_sub_status)); +} + +static void node_reset_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + cfg_client_cancel(model, ctx, NULL, 0); +} + +static void mod_sub_list(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_cfg_mod_sub_list list = {0}; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + list.status = net_buf_simple_pull_u8(buf); + list.elem_addr = net_buf_simple_pull_le16(buf); + if (ctx->recv_op == OP_MOD_SUB_LIST_VND) { + list.cid = net_buf_simple_pull_le16(buf); + } else { + list.cid = CID_NVAL; + } + list.mod_id = net_buf_simple_pull_le16(buf); + + list.addr = bt_mesh_alloc_buf(buf->len); + if (!list.addr) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + net_buf_simple_add_mem(list.addr, buf->data, buf->len); + + cfg_client_cancel(model, ctx, &list, sizeof(struct bt_mesh_cfg_mod_sub_list)); +} + +static void net_key_list(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_cfg_net_key_list list = {0}; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + list.net_idx = bt_mesh_alloc_buf(buf->len); + if (!list.net_idx) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + net_buf_simple_add_mem(list.net_idx, buf->data, buf->len); + + cfg_client_cancel(model, ctx, &list, sizeof(struct bt_mesh_cfg_net_key_list)); +} + +static void app_key_list(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_cfg_app_key_list list = {0}; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + list.status = net_buf_simple_pull_u8(buf); + list.net_idx = net_buf_simple_pull_le16(buf); + list.app_idx = bt_mesh_alloc_buf(buf->len); + if (!list.app_idx) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + net_buf_simple_add_mem(list.app_idx, buf->data, buf->len); + + cfg_client_cancel(model, ctx, &list, sizeof(struct bt_mesh_cfg_app_key_list)); +} + +static void node_id_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_cfg_node_id_status status = {0}; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + status.status = net_buf_simple_pull_u8(buf); + status.net_idx = net_buf_simple_pull_le16(buf); + status.identity = net_buf_simple_pull_u8(buf); + + cfg_client_cancel(model, ctx, &status, sizeof(struct bt_mesh_cfg_node_id_status)); +} + +static void mod_app_list(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_cfg_mod_app_list list = {0}; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + list.status = net_buf_simple_pull_u8(buf); + list.elem_addr = net_buf_simple_pull_le16(buf); + if (ctx->recv_op == OP_VND_MOD_APP_LIST) { + list.cid = net_buf_simple_pull_le16(buf); + } else { + list.cid = CID_NVAL; + } + list.mod_id = net_buf_simple_pull_le16(buf); + + list.app_idx = bt_mesh_alloc_buf(buf->len); + if (!list.app_idx) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + net_buf_simple_add_mem(list.app_idx, buf->data, buf->len); + + cfg_client_cancel(model, ctx, &list, sizeof(struct bt_mesh_cfg_mod_app_list)); +} + +static void kr_phase_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_cfg_key_refresh_status status = {0}; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + status.status = net_buf_simple_pull_u8(buf); + status.net_idx = net_buf_simple_pull_le16(buf); + status.phase = net_buf_simple_pull_u8(buf); + + cfg_client_cancel(model, ctx, &status, sizeof(struct bt_mesh_cfg_key_refresh_status)); +} + +static void lpn_pollto_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_cfg_lpn_pollto_status status = {0}; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + status.lpn_addr = net_buf_simple_pull_le16(buf); + status.timeout = net_buf_simple_pull_u8(buf); + status.timeout |= net_buf_simple_pull_u8(buf) << 8; + status.timeout |= net_buf_simple_pull_u8(buf) << 16; + + cfg_client_cancel(model, ctx, &status, sizeof(struct bt_mesh_cfg_lpn_pollto_status)); +} + +static void net_trans_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + state_status_u8(model, ctx, buf); +} + +const struct bt_mesh_model_op bt_mesh_cfg_cli_op[] = { + { OP_DEV_COMP_DATA_STATUS, 15, comp_data_status }, + { OP_BEACON_STATUS, 1, beacon_status }, + { OP_DEFAULT_TTL_STATUS, 1, ttl_status }, + { OP_FRIEND_STATUS, 1, friend_status }, + { OP_GATT_PROXY_STATUS, 1, gatt_proxy_status }, + { OP_RELAY_STATUS, 2, relay_status }, + { OP_NET_KEY_STATUS, 3, net_key_status }, + { OP_APP_KEY_STATUS, 4, app_key_status }, + { OP_MOD_APP_STATUS, 7, mod_app_status }, + { OP_MOD_PUB_STATUS, 12, mod_pub_status }, + { OP_MOD_SUB_STATUS, 7, mod_sub_status }, + { OP_HEARTBEAT_SUB_STATUS, 9, hb_sub_status }, + { OP_HEARTBEAT_PUB_STATUS, 10, hb_pub_status }, + { OP_NODE_RESET_STATUS, 0, node_reset_status }, + { OP_MOD_SUB_LIST, 5, mod_sub_list }, + { OP_MOD_SUB_LIST_VND, 7, mod_sub_list }, + { OP_NET_KEY_LIST, 2, net_key_list }, + { OP_APP_KEY_LIST, 3, app_key_list }, + { OP_NODE_IDENTITY_STATUS, 4, node_id_status }, + { OP_SIG_MOD_APP_LIST, 5, mod_app_list }, + { OP_VND_MOD_APP_LIST, 7, mod_app_list }, + { OP_KRP_STATUS, 4, kr_phase_status }, + { OP_LPN_TIMEOUT_STATUS, 5, lpn_pollto_status }, + { OP_NET_TRANSMIT_STATUS, 1, net_trans_status }, + BLE_MESH_MODEL_OP_END, +}; + +int bt_mesh_cfg_comp_data_get(struct bt_mesh_msg_ctx *ctx, u8_t page) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_DEV_COMP_DATA_GET); + net_buf_simple_add_u8(&msg, page); + + err = bt_mesh_client_send_msg(cli->model, OP_DEV_COMP_DATA_GET, ctx, + &msg, timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +static int get_state_u8(struct bt_mesh_msg_ctx *ctx, u32_t op) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 0 + 4); + int err; + + bt_mesh_model_msg_init(&msg, op); + + err = bt_mesh_client_send_msg(cli->model, op, ctx, &msg, timeout_handler, + config_msg_timeout, true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +static int set_state_u8(struct bt_mesh_msg_ctx *ctx, u32_t op, u8_t new_val) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); + int err; + + bt_mesh_model_msg_init(&msg, op); + net_buf_simple_add_u8(&msg, new_val); + + err = bt_mesh_client_send_msg(cli->model, op, ctx, &msg, timeout_handler, + config_msg_timeout, true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_beacon_get(struct bt_mesh_msg_ctx *ctx) +{ + if (!ctx || !ctx->addr) { + return -EINVAL; + } + return get_state_u8(ctx, OP_BEACON_GET); +} + +int bt_mesh_cfg_beacon_set(struct bt_mesh_msg_ctx *ctx, u8_t val) +{ + if (!ctx || !ctx->addr) { + return -EINVAL; + } + return set_state_u8(ctx, OP_BEACON_SET, val); +} + +int bt_mesh_cfg_ttl_get(struct bt_mesh_msg_ctx *ctx) +{ + if (!ctx || !ctx->addr) { + return -EINVAL; + } + return get_state_u8(ctx, OP_DEFAULT_TTL_GET); +} + +int bt_mesh_cfg_ttl_set(struct bt_mesh_msg_ctx *ctx, u8_t val) +{ + if (!ctx || !ctx->addr) { + return -EINVAL; + } + return set_state_u8(ctx, OP_DEFAULT_TTL_SET, val); +} + +int bt_mesh_cfg_friend_get(struct bt_mesh_msg_ctx *ctx) +{ + if (!ctx || !ctx->addr) { + return -EINVAL; + } + return get_state_u8(ctx, OP_FRIEND_GET); +} + +int bt_mesh_cfg_friend_set(struct bt_mesh_msg_ctx *ctx, u8_t val) +{ + if (!ctx || !ctx->addr) { + return -EINVAL; + } + return set_state_u8(ctx, OP_FRIEND_SET, val); +} + +int bt_mesh_cfg_gatt_proxy_get(struct bt_mesh_msg_ctx *ctx) +{ + if (!ctx || !ctx->addr) { + return -EINVAL; + } + return get_state_u8(ctx, OP_GATT_PROXY_GET); +} + +int bt_mesh_cfg_gatt_proxy_set(struct bt_mesh_msg_ctx *ctx, u8_t val) +{ + if (!ctx || !ctx->addr) { + return -EINVAL; + } + return set_state_u8(ctx, OP_GATT_PROXY_SET, val); +} + +int bt_mesh_cfg_relay_get(struct bt_mesh_msg_ctx *ctx) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 0 + 4); + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_RELAY_GET); + + err = bt_mesh_client_send_msg(cli->model, OP_RELAY_GET, ctx, &msg, + timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_relay_set(struct bt_mesh_msg_ctx *ctx, u8_t new_relay, + u8_t new_transmit) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 2 + 4); + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_RELAY_SET); + net_buf_simple_add_u8(&msg, new_relay); + net_buf_simple_add_u8(&msg, new_transmit); + + err = bt_mesh_client_send_msg(cli->model, OP_RELAY_SET, ctx, &msg, + timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_net_key_add(struct bt_mesh_msg_ctx *ctx, u16_t key_net_idx, + const u8_t net_key[16]) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 18 + 4); + int err; + + if (!ctx || !ctx->addr || !net_key) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_NET_KEY_ADD); + net_buf_simple_add_le16(&msg, key_net_idx); + net_buf_simple_add_mem(&msg, net_key, 16); + + err = bt_mesh_client_send_msg(cli->model, OP_NET_KEY_ADD, ctx, &msg, + timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_app_key_add(struct bt_mesh_msg_ctx *ctx, u16_t key_net_idx, + u16_t key_app_idx, const u8_t app_key[16]) +{ + NET_BUF_SIMPLE_DEFINE(msg, 1 + 19 + 4); + int err; + + if (!ctx || !ctx->addr || !app_key) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_APP_KEY_ADD); + key_idx_pack(&msg, key_net_idx, key_app_idx); + net_buf_simple_add_mem(&msg, app_key, 16); + + err = bt_mesh_client_send_msg(cli->model, OP_APP_KEY_ADD, ctx, &msg, + timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_mod_app_bind(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t mod_app_idx, u16_t mod_id, u16_t cid) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 8 + 4); + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_MOD_APP_BIND); + net_buf_simple_add_le16(&msg, elem_addr); + net_buf_simple_add_le16(&msg, mod_app_idx); + if (cid != CID_NVAL) { + net_buf_simple_add_le16(&msg, cid); + } + net_buf_simple_add_le16(&msg, mod_id); + + err = bt_mesh_client_send_msg(cli->model, OP_MOD_APP_BIND, ctx, &msg, + timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +static int mod_sub(u32_t op, struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t sub_addr, u16_t mod_id, u16_t cid) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 8 + 4); + int err; + + bt_mesh_model_msg_init(&msg, op); + net_buf_simple_add_le16(&msg, elem_addr); + net_buf_simple_add_le16(&msg, sub_addr); + if (cid != CID_NVAL) { + net_buf_simple_add_le16(&msg, cid); + } + net_buf_simple_add_le16(&msg, mod_id); + + err = bt_mesh_client_send_msg(cli->model, op, ctx, &msg, timeout_handler, + config_msg_timeout, true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_mod_sub_add(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t sub_addr, u16_t mod_id, u16_t cid) +{ + if (!ctx || !ctx->addr) { + return -EINVAL; + } + return mod_sub(OP_MOD_SUB_ADD, ctx, elem_addr, sub_addr, mod_id, cid); +} + +int bt_mesh_cfg_mod_sub_del(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t sub_addr, u16_t mod_id, u16_t cid) +{ + if (!ctx || !ctx->addr) { + return -EINVAL; + } + return mod_sub(OP_MOD_SUB_DEL, ctx, elem_addr, sub_addr, mod_id, cid); +} + +int bt_mesh_cfg_mod_sub_overwrite(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t sub_addr, u16_t mod_id, u16_t cid) +{ + if (!ctx || !ctx->addr) { + return -EINVAL; + } + return mod_sub(OP_MOD_SUB_OVERWRITE, ctx, elem_addr, sub_addr, mod_id, cid); +} + +static int mod_sub_va(u32_t op, struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + const u8_t label[16], u16_t mod_id, u16_t cid) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 22 + 4); + int err; + + BT_DBG("net_idx 0x%04x addr 0x%04x elem_addr 0x%04x label %s", + ctx->net_idx, ctx->addr, elem_addr, label); + BT_DBG("mod_id 0x%04x cid 0x%04x", mod_id, cid); + + bt_mesh_model_msg_init(&msg, op); + net_buf_simple_add_le16(&msg, elem_addr); + net_buf_simple_add_mem(&msg, label, 16); + if (cid != CID_NVAL) { + net_buf_simple_add_le16(&msg, cid); + } + net_buf_simple_add_le16(&msg, mod_id); + + err = bt_mesh_client_send_msg(cli->model, op, ctx, &msg, timeout_handler, + config_msg_timeout, true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_mod_sub_va_add(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + const u8_t label[16], u16_t mod_id, u16_t cid) +{ + if (!ctx || !ctx->addr || !label) { + return -EINVAL; + } + return mod_sub_va(OP_MOD_SUB_VA_ADD, ctx, elem_addr, label, mod_id, cid); +} + +int bt_mesh_cfg_mod_sub_va_del(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + const u8_t label[16], u16_t mod_id, u16_t cid) +{ + if (!ctx || !ctx->addr || !label) { + return -EINVAL; + } + return mod_sub_va(OP_MOD_SUB_VA_DEL, ctx, elem_addr, label, mod_id, cid); +} + +int bt_mesh_cfg_mod_sub_va_overwrite(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + const u8_t label[16], u16_t mod_id, u16_t cid) +{ + if (!ctx || !ctx->addr || !label) { + return -EINVAL; + } + return mod_sub_va(OP_MOD_SUB_VA_OVERWRITE, ctx, elem_addr, label, mod_id, cid); +} + +int bt_mesh_cfg_mod_pub_get(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t mod_id, u16_t cid) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 6 + 4); + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_MOD_PUB_GET); + net_buf_simple_add_le16(&msg, elem_addr); + if (cid != CID_NVAL) { + net_buf_simple_add_le16(&msg, cid); + } + net_buf_simple_add_le16(&msg, mod_id); + + err = bt_mesh_client_send_msg(cli->model, OP_MOD_PUB_GET, ctx, &msg, + timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_mod_pub_set(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t mod_id, u16_t cid, + struct bt_mesh_cfg_mod_pub *pub) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 13 + 4); + int err; + + if (!ctx || !ctx->addr || !pub) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_MOD_PUB_SET); + net_buf_simple_add_le16(&msg, elem_addr); + net_buf_simple_add_le16(&msg, pub->addr); + net_buf_simple_add_le16(&msg, (pub->app_idx | (pub->cred_flag << 12))); + net_buf_simple_add_u8(&msg, pub->ttl); + net_buf_simple_add_u8(&msg, pub->period); + net_buf_simple_add_u8(&msg, pub->transmit); + if (cid != CID_NVAL) { + net_buf_simple_add_le16(&msg, cid); + } + net_buf_simple_add_le16(&msg, mod_id); + + err = bt_mesh_client_send_msg(cli->model, OP_MOD_PUB_SET, ctx, &msg, + timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_hb_sub_set(struct bt_mesh_msg_ctx *ctx, + struct bt_mesh_cfg_hb_sub *sub) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 5 + 4); + int err; + + if (!ctx || !ctx->addr || !sub) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_HEARTBEAT_SUB_SET); + net_buf_simple_add_le16(&msg, sub->src); + net_buf_simple_add_le16(&msg, sub->dst); + net_buf_simple_add_u8(&msg, sub->period); + + err = bt_mesh_client_send_msg(cli->model, OP_HEARTBEAT_SUB_SET, ctx, + &msg, timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_hb_sub_get(struct bt_mesh_msg_ctx *ctx) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 0 + 4); + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_HEARTBEAT_SUB_GET); + + err = bt_mesh_client_send_msg(cli->model, OP_HEARTBEAT_SUB_GET, ctx, + &msg, timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_hb_pub_set(struct bt_mesh_msg_ctx *ctx, + const struct bt_mesh_cfg_hb_pub *pub) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 9 + 4); + int err; + + if (!ctx || !ctx->addr || !pub) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_HEARTBEAT_PUB_SET); + net_buf_simple_add_le16(&msg, pub->dst); + net_buf_simple_add_u8(&msg, pub->count); + net_buf_simple_add_u8(&msg, pub->period); + net_buf_simple_add_u8(&msg, pub->ttl); + net_buf_simple_add_le16(&msg, pub->feat); + net_buf_simple_add_le16(&msg, pub->net_idx); + + err = bt_mesh_client_send_msg(cli->model, OP_HEARTBEAT_PUB_SET, ctx, + &msg, timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_hb_pub_get(struct bt_mesh_msg_ctx *ctx) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 0 + 4); + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_HEARTBEAT_PUB_GET); + + err = bt_mesh_client_send_msg(cli->model, OP_HEARTBEAT_PUB_GET, ctx, + &msg, timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_node_reset(struct bt_mesh_msg_ctx *ctx) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 0 + 4); + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_NODE_RESET); + + err = bt_mesh_client_send_msg(cli->model, OP_NODE_RESET, ctx, &msg, + timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_mod_pub_va_set(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t mod_id, u16_t cid, const u8_t label[16], + struct bt_mesh_cfg_mod_pub *pub) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 27 + 4); + int err; + + if (!ctx || !ctx->addr || !label || !pub) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_MOD_PUB_VA_SET); + net_buf_simple_add_le16(&msg, elem_addr); + net_buf_simple_add_mem(&msg, label, 16); + net_buf_simple_add_le16(&msg, (pub->app_idx | (pub->cred_flag << 12))); + net_buf_simple_add_u8(&msg, pub->ttl); + net_buf_simple_add_u8(&msg, pub->period); + net_buf_simple_add_u8(&msg, pub->transmit); + if (cid != CID_NVAL) { + net_buf_simple_add_le16(&msg, cid); + } + net_buf_simple_add_le16(&msg, mod_id); + + err = bt_mesh_client_send_msg(cli->model, OP_MOD_PUB_VA_SET, ctx, &msg, + timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_mod_sub_del_all(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t mod_id, u16_t cid) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 6 + 4); + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_MOD_SUB_DEL_ALL); + net_buf_simple_add_le16(&msg, elem_addr); + if (cid != CID_NVAL) { + net_buf_simple_add_le16(&msg, cid); + } + net_buf_simple_add_le16(&msg, mod_id); + + err = bt_mesh_client_send_msg(cli->model, OP_MOD_SUB_DEL_ALL, ctx, &msg, + timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +static int mod_sub_get(u32_t op, struct bt_mesh_msg_ctx *ctx, + u16_t elem_addr, u16_t mod_id, u16_t cid) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 6 + 4); + int err; + + bt_mesh_model_msg_init(&msg, op); + net_buf_simple_add_le16(&msg, elem_addr); + if (cid != CID_NVAL) { + net_buf_simple_add_le16(&msg, cid); + } + net_buf_simple_add_le16(&msg, mod_id); + + err = bt_mesh_client_send_msg(cli->model, op, ctx, &msg, timeout_handler, + config_msg_timeout, true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_mod_sub_get(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, u16_t mod_id) +{ + if (!ctx || !ctx->addr) { + return -EINVAL; + } + return mod_sub_get(OP_MOD_SUB_GET, ctx, elem_addr, mod_id, CID_NVAL); +} + +int bt_mesh_cfg_mod_sub_get_vnd(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t mod_id, u16_t cid) +{ + if (!ctx || !ctx->addr || cid == CID_NVAL) { + return -EINVAL; + } + return mod_sub_get(OP_MOD_SUB_GET_VND, ctx, elem_addr, mod_id, cid); +} + +int bt_mesh_cfg_net_key_update(struct bt_mesh_msg_ctx *ctx, u16_t net_idx, + const u8_t net_key[16]) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 18 + 4); + int err; + + if (!ctx || !ctx->addr || !net_key) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_NET_KEY_UPDATE); + net_buf_simple_add_le16(&msg, net_idx); + net_buf_simple_add_mem(&msg, net_key, 16); + + err = bt_mesh_client_send_msg(cli->model, OP_NET_KEY_UPDATE, ctx, &msg, + timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_net_key_delete(struct bt_mesh_msg_ctx *ctx, u16_t net_idx) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 2 + 4); + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_NET_KEY_DEL); + net_buf_simple_add_le16(&msg, net_idx); + + err = bt_mesh_client_send_msg(cli->model, OP_NET_KEY_DEL, ctx, &msg, + timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_net_key_get(struct bt_mesh_msg_ctx *ctx) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 0 + 4); + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_NET_KEY_GET); + + err = bt_mesh_client_send_msg(cli->model, OP_NET_KEY_GET, ctx, &msg, + timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_app_key_update(struct bt_mesh_msg_ctx *ctx, u16_t net_idx, + u16_t app_idx, const u8_t app_key[16]) +{ + NET_BUF_SIMPLE_DEFINE(msg, 1 + 19 + 4); + int err; + + if (!ctx || !ctx->addr || !app_key) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_APP_KEY_UPDATE); + key_idx_pack(&msg, net_idx, app_idx); + net_buf_simple_add_mem(&msg, app_key, 16); + + err = bt_mesh_client_send_msg(cli->model, OP_APP_KEY_UPDATE, ctx, &msg, + timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_app_key_delete(struct bt_mesh_msg_ctx *ctx, u16_t net_idx, u16_t app_idx) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 3 + 4); + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_APP_KEY_DEL); + key_idx_pack(&msg, net_idx, app_idx); + + err = bt_mesh_client_send_msg(cli->model, OP_APP_KEY_DEL, ctx, &msg, + timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_app_key_get(struct bt_mesh_msg_ctx *ctx, u16_t net_idx) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 2 + 4); + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_APP_KEY_GET); + net_buf_simple_add_le16(&msg, net_idx); + + err = bt_mesh_client_send_msg(cli->model, OP_APP_KEY_GET, ctx, &msg, + timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +static int node_identity_op(u32_t op, struct bt_mesh_msg_ctx *ctx, + u16_t net_idx, u8_t identity) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 3 + 4); + int err; + + bt_mesh_model_msg_init(&msg, op); + net_buf_simple_add_le16(&msg, net_idx); + if (op == OP_NODE_IDENTITY_SET) { + net_buf_simple_add_u8(&msg, identity); + } + + err = bt_mesh_client_send_msg(cli->model, op, ctx, &msg, timeout_handler, + config_msg_timeout, true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_node_identity_get(struct bt_mesh_msg_ctx *ctx, u16_t net_idx) +{ + if (!ctx || !ctx->addr) { + return -EINVAL; + } + return node_identity_op(OP_NODE_IDENTITY_GET, ctx, net_idx, 0xFF); +} + +int bt_mesh_cfg_node_identity_set(struct bt_mesh_msg_ctx *ctx, u16_t net_idx, u8_t identity) +{ + if (!ctx || !ctx->addr || identity > 0x01) { + return -EINVAL; + } + return node_identity_op(OP_NODE_IDENTITY_SET, ctx, net_idx, identity); +} + +int bt_mesh_cfg_mod_app_unbind(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t app_idx, u16_t mod_id, u16_t cid) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 8 + 4); + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_MOD_APP_UNBIND); + net_buf_simple_add_le16(&msg, elem_addr); + net_buf_simple_add_le16(&msg, app_idx); + if (cid != CID_NVAL) { + net_buf_simple_add_le16(&msg, cid); + } + net_buf_simple_add_le16(&msg, mod_id); + + err = bt_mesh_client_send_msg(cli->model, OP_MOD_APP_UNBIND, ctx, &msg, + timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +static int mod_app_get(u32_t op, struct bt_mesh_msg_ctx *ctx, + u16_t elem_addr, u16_t mod_id, u16_t cid) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 6 + 4); + int err; + + bt_mesh_model_msg_init(&msg, op); + net_buf_simple_add_le16(&msg, elem_addr); + if (cid != CID_NVAL) { + net_buf_simple_add_le16(&msg, cid); + } + net_buf_simple_add_le16(&msg, mod_id); + + err = bt_mesh_client_send_msg(cli->model, op, ctx, &msg, timeout_handler, + config_msg_timeout, true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_mod_app_get(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, u16_t mod_id) +{ + if (!ctx || !ctx->addr) { + return -EINVAL; + } + return mod_app_get(OP_SIG_MOD_APP_GET, ctx, elem_addr, mod_id, CID_NVAL); +} + +int bt_mesh_cfg_mod_app_get_vnd(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t mod_id, u16_t cid) +{ + if (!ctx || !ctx->addr || cid == CID_NVAL) { + return -EINVAL; + } + return mod_app_get(OP_VND_MOD_APP_GET, ctx, elem_addr, mod_id, cid); +} + +static int kr_phase_op(u32_t op, struct bt_mesh_msg_ctx *ctx, + u16_t net_idx, u8_t transition) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 3 + 4); + int err; + + bt_mesh_model_msg_init(&msg, op); + net_buf_simple_add_le16(&msg, net_idx); + if (op == OP_KRP_SET) { + net_buf_simple_add_u8(&msg, transition); + } + + err = bt_mesh_client_send_msg(cli->model, op, ctx, &msg, timeout_handler, + config_msg_timeout, true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_kr_phase_get(struct bt_mesh_msg_ctx *ctx, u16_t net_idx) +{ + if (!ctx || !ctx->addr) { + return -EINVAL; + } + return kr_phase_op(OP_KRP_GET, ctx, net_idx, 0xFF); +} + +int bt_mesh_cfg_kr_phase_set(struct bt_mesh_msg_ctx *ctx, u16_t net_idx, u8_t transition) +{ + if (!ctx || !ctx->addr || transition > 0x03) { + return -EINVAL; + } + return kr_phase_op(OP_KRP_SET, ctx, net_idx, transition);; +} + +int bt_mesh_cfg_lpn_timeout_get(struct bt_mesh_msg_ctx *ctx, u16_t lpn_addr) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 2 + 4); + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_LPN_TIMEOUT_GET); + net_buf_simple_add_le16(&msg, lpn_addr); + + err = bt_mesh_client_send_msg(cli->model, OP_LPN_TIMEOUT_GET, ctx, &msg, + timeout_handler, config_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_cfg_net_transmit_get(struct bt_mesh_msg_ctx *ctx) +{ + if (!ctx || !ctx->addr) { + return -EINVAL; + } + return get_state_u8(ctx, OP_NET_TRANSMIT_GET); +} + +int bt_mesh_cfg_net_transmit_set(struct bt_mesh_msg_ctx *ctx, u8_t transmit) +{ + if (!ctx || !ctx->addr) { + return -EINVAL; + } + return set_state_u8(ctx, OP_NET_TRANSMIT_SET, transmit); +} + +s32_t bt_mesh_cfg_cli_timeout_get(void) +{ + return config_msg_timeout; +} + +void bt_mesh_cfg_cli_timeout_set(s32_t timeout) +{ + config_msg_timeout = timeout; +} + +int bt_mesh_cfg_cli_init(struct bt_mesh_model *model, bool primary) +{ + config_internal_data_t *internal = NULL; + bt_mesh_config_client_t *client = NULL; + + BT_DBG("primary %u", primary); + + if (!primary) { + BT_ERR("Configuration Client only allowed in primary element"); + return -EINVAL; + } + + if (!model) { + BT_ERR("Configuration Client model is NULL"); + return -EINVAL; + } + + client = (bt_mesh_config_client_t *)model->user_data; + if (!client) { + BT_ERR("No Configuration Client context provided"); + return -EINVAL; + } + + /* TODO: call osi_free() when deinit function is invoked*/ + internal = osi_calloc(sizeof(config_internal_data_t)); + if (!internal) { + BT_ERR("Allocate memory for Configuration Client internal data fail"); + return -ENOMEM; + } + + sys_slist_init(&internal->queue); + + client->model = model; + client->op_pair_size = ARRAY_SIZE(cfg_op_pair); + client->op_pair = cfg_op_pair; + client->internal_data = internal; + + cli = client; + + /* Configuration Model security is device-key based */ + model->keys[0] = BLE_MESH_KEY_DEV; + + return 0; +} diff --git a/components/bt/ble_mesh/mesh_core/cfg_srv.c b/components/bt/ble_mesh/mesh_core/cfg_srv.c new file mode 100644 index 0000000000..4e330e61a0 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/cfg_srv.c @@ -0,0 +1,3593 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "sdkconfig.h" +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BLE_MESH_DEBUG_MODEL) + +#include "mesh_types.h" +#include "mesh_util.h" +#include "mesh_main.h" +#include "mesh_trace.h" +#include "cfg_srv.h" +#include "settings.h" + +#include "mesh.h" +#include "adv.h" +#include "net.h" +#include "lpn.h" +#include "transport.h" +#include "crypto.h" +#include "access.h" +#include "beacon.h" +#include "proxy.h" +#include "foundation.h" +#include "friend.h" +#include "settings.h" + +#include "mesh_common.h" +#include "btc_ble_mesh_config_model.h" + +#define DEFAULT_TTL 7 + +/* Maximum message length is 384 in BLE Mesh. Here for composition data, + * due to 1 octet opcode and 4 octets TransMIC, 379 octets can be used to + * store device composition data. + */ +#define COMP_DATA_MAX_LEN 379 + +static struct bt_mesh_cfg_srv *conf; + +static struct label { + u16_t ref; + u16_t addr; + u8_t uuid[16]; +} labels[CONFIG_BLE_MESH_LABEL_COUNT]; + +static void hb_send(struct bt_mesh_model *model) +{ + struct bt_mesh_cfg_srv *cfg = model->user_data; + u16_t feat = 0U; + struct __packed { + u8_t init_ttl; + u16_t feat; + } hb; + struct bt_mesh_msg_ctx ctx = { + .net_idx = cfg->hb_pub.net_idx, + .app_idx = BLE_MESH_KEY_UNUSED, + .addr = cfg->hb_pub.dst, + .send_ttl = cfg->hb_pub.ttl, + }; + struct bt_mesh_net_tx tx = { + .sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx), + .ctx = &ctx, + .src = bt_mesh_model_elem(model)->addr, + .xmit = bt_mesh_net_transmit_get(), + }; + + hb.init_ttl = cfg->hb_pub.ttl; + + if (bt_mesh_relay_get() == BLE_MESH_RELAY_ENABLED) { + feat |= BLE_MESH_FEAT_RELAY; + } + + if (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED) { + feat |= BLE_MESH_FEAT_PROXY; + } + + if (bt_mesh_friend_get() == BLE_MESH_FRIEND_ENABLED) { + feat |= BLE_MESH_FEAT_FRIEND; + } + +#if defined(CONFIG_BLE_MESH_LOW_POWER) + if (bt_mesh.lpn.state != BLE_MESH_LPN_DISABLED) { + feat |= BLE_MESH_FEAT_LOW_POWER; + } +#endif + + hb.feat = sys_cpu_to_be16(feat); + + BT_DBG("InitTTL %u feat 0x%04x", cfg->hb_pub.ttl, feat); + + bt_mesh_ctl_send(&tx, TRANS_CTL_OP_HEARTBEAT, &hb, sizeof(hb), + NULL, NULL, NULL); +} + +static int comp_add_elem(struct net_buf_simple *buf, struct bt_mesh_elem *elem, + bool primary) +{ + struct bt_mesh_model *mod; + int i; + + if (net_buf_simple_tailroom(buf) < + 4 + (elem->model_count * 2U) + (elem->vnd_model_count * 2U)) { + BT_ERR("%s, Too large device composition", __func__); + return -E2BIG; + } + + net_buf_simple_add_le16(buf, elem->loc); + + net_buf_simple_add_u8(buf, elem->model_count); + net_buf_simple_add_u8(buf, elem->vnd_model_count); + + for (i = 0; i < elem->model_count; i++) { + mod = &elem->models[i]; + net_buf_simple_add_le16(buf, mod->id); + } + + for (i = 0; i < elem->vnd_model_count; i++) { + mod = &elem->vnd_models[i]; + net_buf_simple_add_le16(buf, mod->vnd.company); + net_buf_simple_add_le16(buf, mod->vnd.id); + } + + return 0; +} + +static int comp_get_page_0(struct net_buf_simple *buf) +{ + u16_t feat = 0U; + const struct bt_mesh_comp *comp; + int i; + + comp = bt_mesh_comp_get(); + + if (IS_ENABLED(CONFIG_BLE_MESH_RELAY)) { + feat |= BLE_MESH_FEAT_RELAY; + } + + if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY)) { + feat |= BLE_MESH_FEAT_PROXY; + } + + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { + feat |= BLE_MESH_FEAT_FRIEND; + } + + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) { + feat |= BLE_MESH_FEAT_LOW_POWER; + } + + net_buf_simple_add_le16(buf, comp->cid); + net_buf_simple_add_le16(buf, comp->pid); + net_buf_simple_add_le16(buf, comp->vid); + net_buf_simple_add_le16(buf, CONFIG_BLE_MESH_CRPL); + net_buf_simple_add_le16(buf, feat); + + for (i = 0; i < comp->elem_count; i++) { + int err; + + err = comp_add_elem(buf, &comp->elem[i], i == 0); + if (err) { + return err; + } + } + + return 0; +} + +static void dev_comp_data_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct net_buf_simple *sdu = NULL; + u8_t page; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + page = net_buf_simple_pull_u8(buf); + if (page != 0U) { + BT_WARN("Composition page %u not available", page); + page = 0U; + } + + sdu = bt_mesh_alloc_buf(MIN(BLE_MESH_TX_SDU_MAX, COMP_DATA_MAX_LEN)); + if (!sdu) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + + bt_mesh_model_msg_init(sdu, OP_DEV_COMP_DATA_STATUS); + + net_buf_simple_add_u8(sdu, page); + if (comp_get_page_0(sdu) < 0) { + BT_ERR("%s, Unable to get composition page 0", __func__); + bt_mesh_free_buf(sdu); + return; + } + + if (bt_mesh_model_send(model, ctx, sdu, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Composition Data Status", __func__); + } + + bt_mesh_free_buf(sdu); + return; +} + +static struct bt_mesh_model *get_model(struct bt_mesh_elem *elem, + struct net_buf_simple *buf, bool *vnd) +{ + if (buf->len < 4) { + u16_t id; + + id = net_buf_simple_pull_le16(buf); + + BT_DBG("ID 0x%04x addr 0x%04x", id, elem->addr); + + *vnd = false; + + return bt_mesh_model_find(elem, id); + } else { + u16_t company, id; + + company = net_buf_simple_pull_le16(buf); + id = net_buf_simple_pull_le16(buf); + + BT_DBG("Company 0x%04x ID 0x%04x addr 0x%04x", company, id, + elem->addr); + + *vnd = true; + + return bt_mesh_model_find_vnd(elem, company, id); + } +} + +static bool app_key_is_valid(u16_t app_idx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { + struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; + + if (key->net_idx != BLE_MESH_KEY_UNUSED && + key->app_idx == app_idx) { + return true; + } + } + + return false; +} + +static u8_t _mod_pub_set(struct bt_mesh_model *model, u16_t pub_addr, + u16_t app_idx, u8_t cred_flag, u8_t ttl, u8_t period, + u8_t retransmit, bool store) +{ + if (!model->pub) { + return STATUS_NVAL_PUB_PARAM; + } + + if (!IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && cred_flag) { + return STATUS_FEAT_NOT_SUPP; + } + + if (!model->pub->update && period) { + return STATUS_NVAL_PUB_PARAM; + } + + if (pub_addr == BLE_MESH_ADDR_UNASSIGNED) { + if (model->pub->addr == BLE_MESH_ADDR_UNASSIGNED) { + return STATUS_SUCCESS; + } + + model->pub->addr = BLE_MESH_ADDR_UNASSIGNED; + model->pub->key = 0U; + model->pub->cred = 0U; + model->pub->ttl = 0U; + model->pub->period = 0U; + model->pub->retransmit = 0U; + model->pub->count = 0U; + + if (model->pub->update) { + k_delayed_work_cancel(&model->pub->timer); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS) && store) { + bt_mesh_store_mod_pub(model); + } + + return STATUS_SUCCESS; + } + + if (!bt_mesh_app_key_find(app_idx)) { + return STATUS_INVALID_APPKEY; + } + + model->pub->addr = pub_addr; + model->pub->key = app_idx; + model->pub->cred = cred_flag; + model->pub->ttl = ttl; + model->pub->period = period; + model->pub->retransmit = retransmit; + + if (model->pub->update) { + s32_t period_ms; + + period_ms = bt_mesh_model_pub_period_get(model); + BT_DBG("period %u ms", period_ms); + + if (period_ms) { + k_delayed_work_submit(&model->pub->timer, period_ms); + } else { + k_delayed_work_cancel(&model->pub->timer); + } + } + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS) && store) { + bt_mesh_store_mod_pub(model); + } + + return STATUS_SUCCESS; +} + +static u8_t mod_bind(struct bt_mesh_model *model, u16_t key_idx) +{ + int i; + + BT_DBG("model %p key_idx 0x%03x", model, key_idx); + + if (!app_key_is_valid(key_idx)) { + return STATUS_INVALID_APPKEY; + } + + for (i = 0; i < ARRAY_SIZE(model->keys); i++) { + /* Treat existing binding as success */ + if (model->keys[i] == key_idx) { + return STATUS_SUCCESS; + } + } + + for (i = 0; i < ARRAY_SIZE(model->keys); i++) { + if (model->keys[i] == BLE_MESH_KEY_UNUSED) { + model->keys[i] = key_idx; + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_mod_bind(model); + } + + return STATUS_SUCCESS; + } + } + + return STATUS_INSUFF_RESOURCES; +} + +static u8_t mod_unbind(struct bt_mesh_model *model, u16_t key_idx, bool store) +{ + int i; + + BT_DBG("model %p key_idx 0x%03x store %u", model, key_idx, store); + + if (!app_key_is_valid(key_idx)) { + return STATUS_INVALID_APPKEY; + } + + for (i = 0; i < ARRAY_SIZE(model->keys); i++) { + if (model->keys[i] != key_idx) { + continue; + } + + model->keys[i] = BLE_MESH_KEY_UNUSED; + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS) && store) { + bt_mesh_store_mod_bind(model); + } + + if (model->pub && model->pub->key == key_idx) { + _mod_pub_set(model, BLE_MESH_ADDR_UNASSIGNED, + 0, 0, 0, 0, 0, store); + } + } + + return STATUS_SUCCESS; +} + +struct bt_mesh_app_key *bt_mesh_app_key_alloc(u16_t app_idx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { + struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; + + if (key->net_idx == BLE_MESH_KEY_UNUSED) { + return key; + } + } + + return NULL; +} + +static u8_t app_key_set(u16_t net_idx, u16_t app_idx, const u8_t val[16], + bool update) +{ + struct bt_mesh_app_keys *keys; + struct bt_mesh_app_key *key; + struct bt_mesh_subnet *sub; + + BT_DBG("net_idx 0x%04x app_idx %04x update %u val %s", + net_idx, app_idx, update, bt_hex(val, 16)); + + sub = bt_mesh_subnet_get(net_idx); + if (!sub) { + return STATUS_INVALID_NETKEY; + } + + key = bt_mesh_app_key_find(app_idx); + if (update) { + if (!key) { + return STATUS_INVALID_APPKEY; + } + + if (key->net_idx != net_idx) { + return STATUS_INVALID_BINDING; + } + + keys = &key->keys[1]; + + /* The AppKey Update message shall generate an error when node + * is in normal operation, Phase 2, or Phase 3 or in Phase 1 + * when the AppKey Update message on a valid AppKeyIndex when + * the AppKey value is different. + */ + if (sub->kr_phase != BLE_MESH_KR_PHASE_1) { + return STATUS_CANNOT_UPDATE; + } + + if (key->updated) { + if (memcmp(keys->val, val, 16)) { + return STATUS_CANNOT_UPDATE; + } else { + return STATUS_SUCCESS; + } + } + + key->updated = true; + } else { + if (key) { + if (key->net_idx == net_idx && + !memcmp(key->keys[0].val, val, 16)) { + return STATUS_SUCCESS; + } + + if (key->net_idx == net_idx) { + return STATUS_IDX_ALREADY_STORED; + } else { + return STATUS_INVALID_NETKEY; + } + } + + key = bt_mesh_app_key_alloc(app_idx); + if (!key) { + return STATUS_INSUFF_RESOURCES; + } + + keys = &key->keys[0]; + } + + if (bt_mesh_app_id(val, &keys->id)) { + if (update) { + key->updated = false; + } + + return STATUS_STORAGE_FAIL; + } + + BT_DBG("app_idx 0x%04x AID 0x%02x", app_idx, keys->id); + + key->net_idx = net_idx; + key->app_idx = app_idx; + memcpy(keys->val, val, 16); + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + BT_DBG("Storing AppKey persistently"); + bt_mesh_store_app_key(key); + } + + return STATUS_SUCCESS; +} + +static void app_key_add(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 4 + 4); + u16_t key_net_idx, key_app_idx; + u8_t status; + + key_idx_unpack(buf, &key_net_idx, &key_app_idx); + + BT_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx); + + bt_mesh_model_msg_init(&msg, OP_APP_KEY_STATUS); + + status = app_key_set(key_net_idx, key_app_idx, buf->data, false); + BT_DBG("status 0x%02x", status); + net_buf_simple_add_u8(&msg, status); + + key_idx_pack(&msg, key_net_idx, key_app_idx); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config AppKey Status", __func__); + return; + } + +#if defined(CONFIG_BLE_MESH_FAST_PROV) + bt_mesh_callback_cfg_server_event_to_btc(0x0, model, ctx, + (u8_t *)&key_app_idx, sizeof(u16_t)); +#endif +} + +static void app_key_update(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 4 + 4); + u16_t key_net_idx, key_app_idx; + u8_t status; + + key_idx_unpack(buf, &key_net_idx, &key_app_idx); + + BT_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx); + + bt_mesh_model_msg_init(&msg, OP_APP_KEY_STATUS); + + status = app_key_set(key_net_idx, key_app_idx, buf->data, true); + BT_DBG("status 0x%02x", status); + net_buf_simple_add_u8(&msg, status); + + key_idx_pack(&msg, key_net_idx, key_app_idx); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config AppKey Status", __func__); + } +} + +struct unbind_data { + u16_t app_idx; + bool store; +}; + +static void _mod_unbind(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, + bool vnd, bool primary, void *user_data) +{ + struct unbind_data *data = user_data; + + mod_unbind(mod, data->app_idx, data->store); +} + +void bt_mesh_app_key_del(struct bt_mesh_app_key *key, bool store) +{ + struct unbind_data data = { .app_idx = key->app_idx, .store = store }; + + BT_DBG("AppIdx 0x%03x store %u", key->app_idx, store); + + bt_mesh_model_foreach(_mod_unbind, &data); + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS) && store) { + bt_mesh_clear_app_key(key); + } + + key->net_idx = BLE_MESH_KEY_UNUSED; + (void)memset(key->keys, 0, sizeof(key->keys)); +} + +static void app_key_del(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 4 + 4); + u16_t key_net_idx, key_app_idx; + struct bt_mesh_app_key *key; + u8_t status; + + key_idx_unpack(buf, &key_net_idx, &key_app_idx); + + BT_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx); + + if (!bt_mesh_subnet_get(key_net_idx)) { + status = STATUS_INVALID_NETKEY; + goto send_status; + } + + key = bt_mesh_app_key_find(key_app_idx); + if (!key) { + /* Treat as success since the client might have missed a + * previous response and is resending the request. + */ + status = STATUS_SUCCESS; + goto send_status; + } + + if (key->net_idx != key_net_idx) { + status = STATUS_INVALID_BINDING; + goto send_status; + } + + bt_mesh_app_key_del(key, true); + status = STATUS_SUCCESS; + +send_status: + bt_mesh_model_msg_init(&msg, OP_APP_KEY_STATUS); + + net_buf_simple_add_u8(&msg, status); + + key_idx_pack(&msg, key_net_idx, key_app_idx); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config AppKey Status", __func__); + } +} + +/* Index list length: 3 bytes for every pair and 2 bytes for an odd idx */ +#define IDX_LEN(num) (((num) / 2) * 3 + ((num) % 2) * 2) + +static void app_key_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 3 + 4 + + IDX_LEN(CONFIG_BLE_MESH_APP_KEY_COUNT)); + u16_t get_idx, i, prev; + u8_t status; + + get_idx = net_buf_simple_pull_le16(buf); + if (get_idx > 0xfff) { + BT_ERR("%s, Invalid NetKeyIndex 0x%04x", __func__, get_idx); + return; + } + + BT_DBG("idx 0x%04x", get_idx); + + bt_mesh_model_msg_init(&msg, OP_APP_KEY_LIST); + + if (!bt_mesh_subnet_get(get_idx)) { + status = STATUS_INVALID_NETKEY; + } else { + status = STATUS_SUCCESS; + } + + net_buf_simple_add_u8(&msg, status); + net_buf_simple_add_le16(&msg, get_idx); + + if (status != STATUS_SUCCESS) { + goto send_status; + } + + prev = BLE_MESH_KEY_UNUSED; + for (i = 0U; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { + struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; + + if (key->net_idx != get_idx) { + continue; + } + + if (prev == BLE_MESH_KEY_UNUSED) { + prev = key->app_idx; + continue; + } + + key_idx_pack(&msg, prev, key->app_idx); + prev = BLE_MESH_KEY_UNUSED; + } + + if (prev != BLE_MESH_KEY_UNUSED) { + net_buf_simple_add_le16(&msg, prev); + } + +send_status: + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config AppKey List", __func__); + } +} + +static void beacon_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + bt_mesh_model_msg_init(&msg, OP_BEACON_STATUS); + net_buf_simple_add_u8(&msg, bt_mesh_beacon_get()); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Beacon Status", __func__); + } +} + +static void beacon_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); + struct bt_mesh_cfg_srv *cfg = model->user_data; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + if (!cfg) { + BT_WARN("No Configuration Server context available"); + } else if (buf->data[0] == 0x00 || buf->data[0] == 0x01) { + if (buf->data[0] != cfg->beacon) { + cfg->beacon = buf->data[0]; + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_cfg(); + } + +#if CONFIG_BLE_MESH_NODE + if (cfg->beacon) { + bt_mesh_beacon_enable(); + } else { + bt_mesh_beacon_disable(); + } +#endif + } + } else { + BT_WARN("Invalid Config Beacon value 0x%02x", buf->data[0]); + return; + } + + bt_mesh_model_msg_init(&msg, OP_BEACON_STATUS); + net_buf_simple_add_u8(&msg, bt_mesh_beacon_get()); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Beacon Status", __func__); + } +} + +static void default_ttl_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + bt_mesh_model_msg_init(&msg, OP_DEFAULT_TTL_STATUS); + net_buf_simple_add_u8(&msg, bt_mesh_default_ttl_get()); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Default TTL Status", __func__); + } +} + +static void default_ttl_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); + struct bt_mesh_cfg_srv *cfg = model->user_data; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + if (!cfg) { + BT_WARN("No Configuration Server context available"); + } else if (buf->data[0] <= BLE_MESH_TTL_MAX && buf->data[0] != 0x01) { + if (cfg->default_ttl != buf->data[0]) { + cfg->default_ttl = buf->data[0]; + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_cfg(); + } + } + } else { + BT_WARN("Prohibited Default TTL value 0x%02x", buf->data[0]); + return; + } + + bt_mesh_model_msg_init(&msg, OP_DEFAULT_TTL_STATUS); + net_buf_simple_add_u8(&msg, bt_mesh_default_ttl_get()); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Default TTL Status", __func__); + } +} + +static void send_gatt_proxy_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); + + bt_mesh_model_msg_init(&msg, OP_GATT_PROXY_STATUS); + net_buf_simple_add_u8(&msg, bt_mesh_gatt_proxy_get()); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config GATT Proxy Status", __func__); + } +} + +static void gatt_proxy_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + send_gatt_proxy_status(model, ctx); +} + +static void gatt_proxy_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_cfg_srv *cfg = model->user_data; + struct bt_mesh_subnet *sub; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + if (buf->data[0] != 0x00 && buf->data[0] != 0x01) { + BT_WARN("Invalid GATT Proxy value 0x%02x", buf->data[0]); + return; + } + + if (!IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY) || + bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_NOT_SUPPORTED) { + goto send_status; + } + + if (!cfg) { + BT_WARN("No Configuration Server context available"); + goto send_status; + } + + BT_DBG("GATT Proxy 0x%02x -> 0x%02x", cfg->gatt_proxy, buf->data[0]); + + if (cfg->gatt_proxy == buf->data[0]) { + goto send_status; + } + + cfg->gatt_proxy = buf->data[0]; + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_cfg(); + } + +#if CONFIG_BLE_MESH_NODE + if (cfg->gatt_proxy == BLE_MESH_GATT_PROXY_DISABLED) { + int i; + + /* Section 4.2.11.1: "When the GATT Proxy state is set to + * 0x00, the Node Identity state for all subnets shall be set + * to 0x00 and shall not be changed." + */ + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; + + if (sub->net_idx != BLE_MESH_KEY_UNUSED) { + bt_mesh_proxy_identity_stop(sub); + } + } + + /* Section 4.2.11: "Upon transition from GATT Proxy state 0x01 + * to GATT Proxy state 0x00 the GATT Bearer Server shall + * disconnect all GATT Bearer Clients. + */ + bt_mesh_proxy_gatt_disconnect(); + } + + bt_mesh_adv_update(); +#endif + + sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx); + if ((cfg->hb_pub.feat & BLE_MESH_FEAT_PROXY) && sub) { + hb_send(model); + } + +send_status: + send_gatt_proxy_status(model, ctx); +} + +static void net_transmit_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + bt_mesh_model_msg_init(&msg, OP_NET_TRANSMIT_STATUS); + net_buf_simple_add_u8(&msg, bt_mesh_net_transmit_get()); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Network Transmit Status", __func__); + } +} + +static void net_transmit_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); + struct bt_mesh_cfg_srv *cfg = model->user_data; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + BT_DBG("Transmit 0x%02x (count %u interval %ums)", buf->data[0], + BLE_MESH_TRANSMIT_COUNT(buf->data[0]), + BLE_MESH_TRANSMIT_INT(buf->data[0])); + + if (!cfg) { + BT_WARN("No Configuration Server context available"); + } else { + cfg->net_transmit = buf->data[0]; + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_cfg(); + } + } + + bt_mesh_model_msg_init(&msg, OP_NET_TRANSMIT_STATUS); + net_buf_simple_add_u8(&msg, bt_mesh_net_transmit_get()); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Network Transmit Status", __func__); + } +} + +static void relay_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 2 + 4); + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + bt_mesh_model_msg_init(&msg, OP_RELAY_STATUS); + net_buf_simple_add_u8(&msg, bt_mesh_relay_get()); + net_buf_simple_add_u8(&msg, bt_mesh_relay_retransmit_get()); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Relay Status", __func__); + } +} + +static void relay_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 2 + 4); + struct bt_mesh_cfg_srv *cfg = model->user_data; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + if (!cfg) { + BT_WARN("No Configuration Server context available"); + } else if (buf->data[0] == 0x00 || buf->data[0] == 0x01) { + struct bt_mesh_subnet *sub; + bool change; + + if (cfg->relay == BLE_MESH_RELAY_NOT_SUPPORTED) { + change = false; + } else { + change = (cfg->relay != buf->data[0]); + cfg->relay = buf->data[0]; + cfg->relay_retransmit = buf->data[1]; + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_cfg(); + } + } + + BT_DBG("Relay 0x%02x (%s) xmit 0x%02x (count %u interval %u)", + cfg->relay, change ? "changed" : "not changed", + cfg->relay_retransmit, + BLE_MESH_TRANSMIT_COUNT(cfg->relay_retransmit), + BLE_MESH_TRANSMIT_INT(cfg->relay_retransmit)); + + sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx); + if ((cfg->hb_pub.feat & BLE_MESH_FEAT_RELAY) && sub && change) { + hb_send(model); + } + } else { + BT_WARN("Invalid Relay value 0x%02x", buf->data[0]); + return; + } + + bt_mesh_model_msg_init(&msg, OP_RELAY_STATUS); + net_buf_simple_add_u8(&msg, bt_mesh_relay_get()); + net_buf_simple_add_u8(&msg, bt_mesh_relay_retransmit_get()); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Relay Status", __func__); + } +} + +static void send_mod_pub_status(struct bt_mesh_model *cfg_mod, + struct bt_mesh_msg_ctx *ctx, + u16_t elem_addr, u16_t pub_addr, + bool vnd, struct bt_mesh_model *mod, + u8_t status, u8_t *mod_id) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 14 + 4); + + bt_mesh_model_msg_init(&msg, OP_MOD_PUB_STATUS); + + net_buf_simple_add_u8(&msg, status); + net_buf_simple_add_le16(&msg, elem_addr); + + if (status != STATUS_SUCCESS) { + (void)memset(net_buf_simple_add(&msg, 7), 0, 7); + } else { + u16_t idx_cred; + + net_buf_simple_add_le16(&msg, pub_addr); + + idx_cred = mod->pub->key | (u16_t)mod->pub->cred << 12; + net_buf_simple_add_le16(&msg, idx_cred); + net_buf_simple_add_u8(&msg, mod->pub->ttl); + net_buf_simple_add_u8(&msg, mod->pub->period); + net_buf_simple_add_u8(&msg, mod->pub->retransmit); + } + + if (vnd) { + memcpy(net_buf_simple_add(&msg, 4), mod_id, 4); + } else { + memcpy(net_buf_simple_add(&msg, 2), mod_id, 2); + } + + if (bt_mesh_model_send(cfg_mod, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Model Publication Status", __func__); + } +} + +static void mod_pub_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + u16_t elem_addr, pub_addr = 0U; + struct bt_mesh_model *mod; + struct bt_mesh_elem *elem; + u8_t *mod_id, status; + bool vnd; + + elem_addr = net_buf_simple_pull_le16(buf); + if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { + BT_ERR("%s, Prohibited element address 0x%04x", __func__, elem_addr); + return; + } + + mod_id = buf->data; + + BT_DBG("elem_addr 0x%04x", elem_addr); + + elem = bt_mesh_elem_find(elem_addr); + if (!elem) { + mod = NULL; + vnd = (buf->len == 4U); + status = STATUS_INVALID_ADDRESS; + goto send_status; + } + + mod = get_model(elem, buf, &vnd); + if (!mod) { + status = STATUS_INVALID_MODEL; + goto send_status; + } + + if (!mod->pub) { + status = STATUS_NVAL_PUB_PARAM; + goto send_status; + } + + pub_addr = mod->pub->addr; + status = STATUS_SUCCESS; + +send_status: + send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, + status, mod_id); +} + +static void mod_pub_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + u8_t retransmit, status, pub_ttl, pub_period, cred_flag; + u16_t elem_addr, pub_addr, pub_app_idx; + struct bt_mesh_model *mod; + struct bt_mesh_elem *elem; + u8_t *mod_id; + bool vnd; + + elem_addr = net_buf_simple_pull_le16(buf); + if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { + BT_ERR("%s, Prohibited element address 0x%04x", __func__, elem_addr); + return; + } + + pub_addr = net_buf_simple_pull_le16(buf); + pub_app_idx = net_buf_simple_pull_le16(buf); + cred_flag = ((pub_app_idx >> 12) & BIT_MASK(1)); + pub_app_idx &= BIT_MASK(12); + + pub_ttl = net_buf_simple_pull_u8(buf); + if (pub_ttl > BLE_MESH_TTL_MAX && pub_ttl != BLE_MESH_TTL_DEFAULT) { + BT_ERR("%s, Invalid TTL value 0x%02x", __func__, pub_ttl); + return; + } + + pub_period = net_buf_simple_pull_u8(buf); + retransmit = net_buf_simple_pull_u8(buf); + mod_id = buf->data; + + BT_DBG("elem_addr 0x%04x pub_addr 0x%04x cred_flag %u", + elem_addr, pub_addr, cred_flag); + BT_DBG("pub_app_idx 0x%03x, pub_ttl %u pub_period 0x%02x", + pub_app_idx, pub_ttl, pub_period); + BT_DBG("retransmit 0x%02x (count %u interval %ums)", retransmit, + BLE_MESH_PUB_TRANSMIT_COUNT(retransmit), + BLE_MESH_PUB_TRANSMIT_INT(retransmit)); + + elem = bt_mesh_elem_find(elem_addr); + if (!elem) { + mod = NULL; + vnd = (buf->len == 4U); + status = STATUS_INVALID_ADDRESS; + goto send_status; + } + + mod = get_model(elem, buf, &vnd); + if (!mod) { + status = STATUS_INVALID_MODEL; + goto send_status; + } + + status = _mod_pub_set(mod, pub_addr, pub_app_idx, cred_flag, pub_ttl, + pub_period, retransmit, true); + +send_status: + send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, + status, mod_id); +} + +#if CONFIG_BLE_MESH_LABEL_COUNT > 0 +static u8_t va_add(u8_t *label_uuid, u16_t *addr) +{ + struct label *free_slot = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(labels); i++) { + if (!labels[i].ref) { + free_slot = &labels[i]; + continue; + } + + if (!memcmp(labels[i].uuid, label_uuid, 16)) { + *addr = labels[i].addr; + labels[i].ref++; + return STATUS_SUCCESS; + } + } + + if (!free_slot) { + return STATUS_INSUFF_RESOURCES; + } + + if (bt_mesh_virtual_addr(label_uuid, addr) < 0) { + return STATUS_UNSPECIFIED; + } + + free_slot->ref = 1U; + free_slot->addr = *addr; + memcpy(free_slot->uuid, label_uuid, 16); + + return STATUS_SUCCESS; +} + +static u8_t va_del(u8_t *label_uuid, u16_t *addr) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(labels); i++) { + if (!memcmp(labels[i].uuid, label_uuid, 16)) { + if (addr) { + *addr = labels[i].addr; + } + + labels[i].ref--; + return STATUS_SUCCESS; + } + } + + if (addr) { + *addr = BLE_MESH_ADDR_UNASSIGNED; + } + + return STATUS_CANNOT_REMOVE; +} + +static size_t mod_sub_list_clear(struct bt_mesh_model *mod) +{ + u8_t *label_uuid; + size_t clear_count; + int i; + + /* Unref stored labels related to this model */ + for (i = 0, clear_count = 0; i < ARRAY_SIZE(mod->groups); i++) { + if (!BLE_MESH_ADDR_IS_VIRTUAL(mod->groups[i])) { + if (mod->groups[i] != BLE_MESH_ADDR_UNASSIGNED) { + mod->groups[i] = BLE_MESH_ADDR_UNASSIGNED; + clear_count++; + } + + continue; + } + + label_uuid = bt_mesh_label_uuid_get(mod->groups[i]); + + mod->groups[i] = BLE_MESH_ADDR_UNASSIGNED; + clear_count++; + + if (label_uuid) { + va_del(label_uuid, NULL); + } else { + BT_ERR("%s, Label UUID not found", __func__); + } + } + + return clear_count; +} + +static void mod_pub_va_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + u8_t retransmit, status, pub_ttl, pub_period, cred_flag; + u16_t elem_addr, pub_addr, pub_app_idx; + struct bt_mesh_model *mod; + struct bt_mesh_elem *elem; + u8_t *label_uuid; + u8_t *mod_id; + bool vnd; + + elem_addr = net_buf_simple_pull_le16(buf); + if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { + BT_ERR("%s, Prohibited element address 0x%04x", __func__, elem_addr); + return; + } + + label_uuid = net_buf_simple_pull_mem(buf, 16); + pub_app_idx = net_buf_simple_pull_le16(buf); + cred_flag = ((pub_app_idx >> 12) & BIT_MASK(1)); + pub_app_idx &= BIT_MASK(12); + pub_ttl = net_buf_simple_pull_u8(buf); + if (pub_ttl > BLE_MESH_TTL_MAX && pub_ttl != BLE_MESH_TTL_DEFAULT) { + BT_ERR("%s, Invalid TTL value 0x%02x", __func__, pub_ttl); + return; + } + + pub_period = net_buf_simple_pull_u8(buf); + retransmit = net_buf_simple_pull_u8(buf); + mod_id = buf->data; + + BT_DBG("elem_addr 0x%04x cred_flag %u", elem_addr, cred_flag); + BT_DBG("pub_app_idx 0x%03x, pub_ttl %u pub_period 0x%02x", + pub_app_idx, pub_ttl, pub_period); + BT_DBG("retransmit 0x%02x (count %u interval %ums)", retransmit, + BLE_MESH_PUB_TRANSMIT_COUNT(retransmit), + BLE_MESH_PUB_TRANSMIT_INT(retransmit)); + + elem = bt_mesh_elem_find(elem_addr); + if (!elem) { + mod = NULL; + vnd = (buf->len == 4U); + pub_addr = 0U; + status = STATUS_INVALID_ADDRESS; + goto send_status; + } + + mod = get_model(elem, buf, &vnd); + if (!mod) { + pub_addr = 0U; + status = STATUS_INVALID_MODEL; + goto send_status; + } + + status = va_add(label_uuid, &pub_addr); + if (status == STATUS_SUCCESS) { + status = _mod_pub_set(mod, pub_addr, pub_app_idx, cred_flag, + pub_ttl, pub_period, retransmit, true); + } + +send_status: + send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, + status, mod_id); +} +#else +static size_t mod_sub_list_clear(struct bt_mesh_model *mod) +{ + size_t clear_count; + int i; + + /* Unref stored labels related to this model */ + for (i = 0, clear_count = 0; i < ARRAY_SIZE(mod->groups); i++) { + if (mod->groups[i] != BLE_MESH_ADDR_UNASSIGNED) { + mod->groups[i] = BLE_MESH_ADDR_UNASSIGNED; + clear_count++; + } + } + + return clear_count; +} + +static void mod_pub_va_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + u8_t *mod_id, status; + struct bt_mesh_model *mod; + struct bt_mesh_elem *elem; + u16_t elem_addr, pub_addr = 0U; + bool vnd; + + elem_addr = net_buf_simple_pull_le16(buf); + if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { + BT_ERR("%s, Prohibited element address 0x%04x", __func__, elem_addr); + return; + } + + net_buf_simple_pull(buf, 16); + mod_id = net_buf_simple_pull(buf, 4); + + BT_DBG("elem_addr 0x%04x", elem_addr); + + elem = bt_mesh_elem_find(elem_addr); + if (!elem) { + mod = NULL; + vnd = (buf->len == 4U); + status = STATUS_INVALID_ADDRESS; + goto send_status; + } + + mod = get_model(elem, buf, &vnd); + if (!mod) { + status = STATUS_INVALID_MODEL; + goto send_status; + } + + if (!mod->pub) { + status = STATUS_NVAL_PUB_PARAM; + goto send_status; + } + + pub_addr = mod->pub->addr; + status = STATUS_INSUFF_RESOURCES; + +send_status: + send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, + status, mod_id); +} +#endif /* CONFIG_BLE_MESH_LABEL_COUNT > 0 */ + +static void send_mod_sub_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, u8_t status, + u16_t elem_addr, u16_t sub_addr, u8_t *mod_id, + bool vnd) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 9 + 4); + + BT_DBG("status 0x%02x elem_addr 0x%04x sub_addr 0x%04x", status, + elem_addr, sub_addr); + + bt_mesh_model_msg_init(&msg, OP_MOD_SUB_STATUS); + + net_buf_simple_add_u8(&msg, status); + net_buf_simple_add_le16(&msg, elem_addr); + net_buf_simple_add_le16(&msg, sub_addr); + + if (vnd) { + memcpy(net_buf_simple_add(&msg, 4), mod_id, 4); + } else { + memcpy(net_buf_simple_add(&msg, 2), mod_id, 2); + } + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Model Subscription Status", __func__); + } +} + +static void mod_sub_add(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + u16_t elem_addr, sub_addr; + struct bt_mesh_model *mod; + struct bt_mesh_elem *elem; + u8_t *mod_id; + u8_t status; + bool vnd; + int i; + + elem_addr = net_buf_simple_pull_le16(buf); + if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { + BT_ERR("%s, Prohibited element address 0x%04x", __func__, elem_addr); + return; + } + + sub_addr = net_buf_simple_pull_le16(buf); + + BT_DBG("elem_addr 0x%04x, sub_addr 0x%04x", elem_addr, sub_addr); + + mod_id = buf->data; + + elem = bt_mesh_elem_find(elem_addr); + if (!elem) { + mod = NULL; + vnd = (buf->len == 4U); + status = STATUS_INVALID_ADDRESS; + goto send_status; + } + + mod = get_model(elem, buf, &vnd); + if (!mod) { + status = STATUS_INVALID_MODEL; + goto send_status; + } + + if (!BLE_MESH_ADDR_IS_GROUP(sub_addr)) { + status = STATUS_INVALID_ADDRESS; + goto send_status; + } + + if (bt_mesh_model_find_group(mod, sub_addr)) { + /* Tried to add existing subscription */ + BT_DBG("found existing subscription"); + status = STATUS_SUCCESS; + goto send_status; + } + + for (i = 0; i < ARRAY_SIZE(mod->groups); i++) { + if (mod->groups[i] == BLE_MESH_ADDR_UNASSIGNED) { + mod->groups[i] = sub_addr; + break; + } + } + + if (i == ARRAY_SIZE(mod->groups)) { + status = STATUS_INSUFF_RESOURCES; + } else { + status = STATUS_SUCCESS; + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_mod_sub(mod); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) { + bt_mesh_lpn_group_add(sub_addr); + } + } + +send_status: + send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, + mod_id, vnd); +} + +static void mod_sub_del(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + u16_t elem_addr, sub_addr; + struct bt_mesh_model *mod; + struct bt_mesh_elem *elem; + u8_t *mod_id; + u16_t *match; + u8_t status; + bool vnd; + + elem_addr = net_buf_simple_pull_le16(buf); + if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { + BT_ERR("%s, Prohibited element address 0x%04x", __func__, elem_addr); + return; + } + + sub_addr = net_buf_simple_pull_le16(buf); + + BT_DBG("elem_addr 0x%04x sub_addr 0x%04x", elem_addr, sub_addr); + + mod_id = buf->data; + + elem = bt_mesh_elem_find(elem_addr); + if (!elem) { + mod = NULL; + vnd = (buf->len == 4U); + status = STATUS_INVALID_ADDRESS; + goto send_status; + } + + mod = get_model(elem, buf, &vnd); + if (!mod) { + status = STATUS_INVALID_MODEL; + goto send_status; + } + + if (!BLE_MESH_ADDR_IS_GROUP(sub_addr)) { + status = STATUS_INVALID_ADDRESS; + goto send_status; + } + + /* An attempt to remove a non-existing address shall be treated + * as a success. + */ + status = STATUS_SUCCESS; + + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) { + bt_mesh_lpn_group_del(&sub_addr, 1); + } + + match = bt_mesh_model_find_group(mod, sub_addr); + if (match) { + *match = BLE_MESH_ADDR_UNASSIGNED; + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_mod_sub(mod); + } + } + +send_status: + send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, + mod_id, vnd); +} + +static void mod_sub_overwrite(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + u16_t elem_addr, sub_addr; + struct bt_mesh_model *mod; + struct bt_mesh_elem *elem; + u8_t *mod_id; + u8_t status; + bool vnd; + + elem_addr = net_buf_simple_pull_le16(buf); + if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { + BT_ERR("%s, Prohibited element address 0x%04x", __func__, elem_addr); + return; + } + + sub_addr = net_buf_simple_pull_le16(buf); + + BT_DBG("elem_addr 0x%04x sub_addr 0x%04x", elem_addr, sub_addr); + + mod_id = buf->data; + + elem = bt_mesh_elem_find(elem_addr); + if (!elem) { + mod = NULL; + vnd = (buf->len == 4U); + status = STATUS_INVALID_ADDRESS; + goto send_status; + } + + mod = get_model(elem, buf, &vnd); + if (!mod) { + status = STATUS_INVALID_MODEL; + goto send_status; + } + + if (!BLE_MESH_ADDR_IS_GROUP(sub_addr)) { + status = STATUS_INVALID_ADDRESS; + goto send_status; + } + + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) { + bt_mesh_lpn_group_del(mod->groups, ARRAY_SIZE(mod->groups)); + } + + mod_sub_list_clear(mod); + + if (ARRAY_SIZE(mod->groups) > 0) { + mod->groups[0] = sub_addr; + status = STATUS_SUCCESS; + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_mod_sub(mod); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) { + bt_mesh_lpn_group_add(sub_addr); + } + } else { + status = STATUS_INSUFF_RESOURCES; + } + + +send_status: + send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, + mod_id, vnd); +} + +static void mod_sub_del_all(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_model *mod; + struct bt_mesh_elem *elem; + u16_t elem_addr; + u8_t *mod_id; + u8_t status; + bool vnd; + + elem_addr = net_buf_simple_pull_le16(buf); + if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { + BT_ERR("%s, Prohibited element address 0x%04x", __func__, elem_addr); + return; + } + + BT_DBG("elem_addr 0x%04x", elem_addr); + + mod_id = buf->data; + + elem = bt_mesh_elem_find(elem_addr); + if (!elem) { + mod = NULL; + vnd = (buf->len == 4U); + status = STATUS_INVALID_ADDRESS; + goto send_status; + } + + mod = get_model(elem, buf, &vnd); + if (!mod) { + status = STATUS_INVALID_MODEL; + goto send_status; + } + + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) { + bt_mesh_lpn_group_del(mod->groups, ARRAY_SIZE(mod->groups)); + } + + mod_sub_list_clear(mod); + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_mod_sub(mod); + } + + status = STATUS_SUCCESS; + +send_status: + send_mod_sub_status(model, ctx, status, elem_addr, + BLE_MESH_ADDR_UNASSIGNED, mod_id, vnd); +} + +static void mod_sub_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 5 + 4 + + CONFIG_BLE_MESH_MODEL_GROUP_COUNT * 2); + struct bt_mesh_model *mod; + struct bt_mesh_elem *elem; + u16_t addr, id; + int i; + + addr = net_buf_simple_pull_le16(buf); + if (!BLE_MESH_ADDR_IS_UNICAST(addr)) { + BT_ERR("%s, Prohibited element address 0x%04x", __func__, addr); + return; + } + + id = net_buf_simple_pull_le16(buf); + + BT_DBG("addr 0x%04x id 0x%04x", addr, id); + + bt_mesh_model_msg_init(&msg, OP_MOD_SUB_LIST); + + elem = bt_mesh_elem_find(addr); + if (!elem) { + net_buf_simple_add_u8(&msg, STATUS_INVALID_ADDRESS); + net_buf_simple_add_le16(&msg, addr); + net_buf_simple_add_le16(&msg, id); + goto send_list; + } + + mod = bt_mesh_model_find(elem, id); + if (!mod) { + net_buf_simple_add_u8(&msg, STATUS_INVALID_MODEL); + net_buf_simple_add_le16(&msg, addr); + net_buf_simple_add_le16(&msg, id); + goto send_list; + } + + net_buf_simple_add_u8(&msg, STATUS_SUCCESS); + + net_buf_simple_add_le16(&msg, addr); + net_buf_simple_add_le16(&msg, id); + + for (i = 0; i < ARRAY_SIZE(mod->groups); i++) { + if (mod->groups[i] != BLE_MESH_ADDR_UNASSIGNED) { + net_buf_simple_add_le16(&msg, mod->groups[i]); + } + } + +send_list: + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Model Subscription List", __func__); + } +} + +static void mod_sub_get_vnd(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 7 + 4 + + CONFIG_BLE_MESH_MODEL_GROUP_COUNT * 2); + struct bt_mesh_model *mod; + struct bt_mesh_elem *elem; + u16_t company, addr, id; + int i; + + addr = net_buf_simple_pull_le16(buf); + if (!BLE_MESH_ADDR_IS_UNICAST(addr)) { + BT_ERR("%s, Prohibited element address 0x%04x", __func__, addr); + return; + } + + company = net_buf_simple_pull_le16(buf); + id = net_buf_simple_pull_le16(buf); + + BT_DBG("addr 0x%04x company 0x%04x id 0x%04x", addr, company, id); + + bt_mesh_model_msg_init(&msg, OP_MOD_SUB_LIST_VND); + + elem = bt_mesh_elem_find(addr); + if (!elem) { + net_buf_simple_add_u8(&msg, STATUS_INVALID_ADDRESS); + net_buf_simple_add_le16(&msg, addr); + net_buf_simple_add_le16(&msg, company); + net_buf_simple_add_le16(&msg, id); + goto send_list; + } + + mod = bt_mesh_model_find_vnd(elem, company, id); + if (!mod) { + net_buf_simple_add_u8(&msg, STATUS_INVALID_MODEL); + net_buf_simple_add_le16(&msg, addr); + net_buf_simple_add_le16(&msg, company); + net_buf_simple_add_le16(&msg, id); + goto send_list; + } + + net_buf_simple_add_u8(&msg, STATUS_SUCCESS); + + net_buf_simple_add_le16(&msg, addr); + net_buf_simple_add_le16(&msg, company); + net_buf_simple_add_le16(&msg, id); + + for (i = 0; i < ARRAY_SIZE(mod->groups); i++) { + if (mod->groups[i] != BLE_MESH_ADDR_UNASSIGNED) { + net_buf_simple_add_le16(&msg, mod->groups[i]); + } + } + +send_list: + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Vendor Model Subscription List", __func__); + } +} + +#if CONFIG_BLE_MESH_LABEL_COUNT > 0 +static void mod_sub_va_add(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + u16_t elem_addr, sub_addr; + struct bt_mesh_model *mod; + struct bt_mesh_elem *elem; + u8_t *label_uuid; + u8_t *mod_id; + u8_t status; + bool vnd; + int i; + + elem_addr = net_buf_simple_pull_le16(buf); + if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { + BT_ERR("%s, Prohibited element address 0x%04x", __func__, elem_addr); + return; + } + + label_uuid = net_buf_simple_pull_mem(buf, 16); + + BT_DBG("elem_addr 0x%04x", elem_addr); + + mod_id = buf->data; + elem = bt_mesh_elem_find(elem_addr); + if (!elem) { + mod = NULL; + vnd = (buf->len == 4U); + sub_addr = BLE_MESH_ADDR_UNASSIGNED; + status = STATUS_INVALID_ADDRESS; + goto send_status; + } + + mod = get_model(elem, buf, &vnd); + if (!mod) { + sub_addr = BLE_MESH_ADDR_UNASSIGNED; + status = STATUS_INVALID_MODEL; + goto send_status; + } + + status = va_add(label_uuid, &sub_addr); + if (status != STATUS_SUCCESS) { + goto send_status; + } + + if (bt_mesh_model_find_group(mod, sub_addr)) { + /* Tried to add existing subscription */ + status = STATUS_SUCCESS; + goto send_status; + } + + for (i = 0; i < ARRAY_SIZE(mod->groups); i++) { + if (mod->groups[i] == BLE_MESH_ADDR_UNASSIGNED) { + mod->groups[i] = sub_addr; + break; + } + } + + if (i == ARRAY_SIZE(mod->groups)) { + status = STATUS_INSUFF_RESOURCES; + } else { + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) { + bt_mesh_lpn_group_add(sub_addr); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_mod_sub(mod); + } + + status = STATUS_SUCCESS; + } + +send_status: + send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, + mod_id, vnd); +} + +static void mod_sub_va_del(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + u16_t elem_addr, sub_addr; + struct bt_mesh_model *mod; + struct bt_mesh_elem *elem; + u8_t *label_uuid; + u8_t *mod_id; + u16_t *match; + u8_t status; + bool vnd; + + elem_addr = net_buf_simple_pull_le16(buf); + if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { + BT_ERR("%s, Prohibited element address 0x%04x", __func__, elem_addr); + return; + } + + label_uuid = net_buf_simple_pull_mem(buf, 16); + + BT_DBG("elem_addr 0x%04x", elem_addr); + + mod_id = buf->data; + + elem = bt_mesh_elem_find(elem_addr); + if (!elem) { + mod = NULL; + vnd = (buf->len == 4U); + sub_addr = BLE_MESH_ADDR_UNASSIGNED; + status = STATUS_INVALID_ADDRESS; + goto send_status; + } + + mod = get_model(elem, buf, &vnd); + if (!mod) { + sub_addr = BLE_MESH_ADDR_UNASSIGNED; + status = STATUS_INVALID_MODEL; + goto send_status; + } + + status = va_del(label_uuid, &sub_addr); + if (sub_addr == BLE_MESH_ADDR_UNASSIGNED) { + goto send_status; + } + + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) { + bt_mesh_lpn_group_del(&sub_addr, 1); + } + + match = bt_mesh_model_find_group(mod, sub_addr); + if (match) { + *match = BLE_MESH_ADDR_UNASSIGNED; + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_mod_sub(mod); + } + + status = STATUS_SUCCESS; + } else { + status = STATUS_CANNOT_REMOVE; + } + +send_status: + send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, + mod_id, vnd); +} + +static void mod_sub_va_overwrite(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + u16_t elem_addr, sub_addr = BLE_MESH_ADDR_UNASSIGNED; + struct bt_mesh_model *mod; + struct bt_mesh_elem *elem; + u8_t *label_uuid; + u8_t *mod_id; + u8_t status; + bool vnd; + + elem_addr = net_buf_simple_pull_le16(buf); + if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { + BT_ERR("%s, Prohibited element address 0x%04x", __func__, elem_addr); + return; + } + + label_uuid = net_buf_simple_pull_mem(buf, 16); + + BT_DBG("elem_addr 0x%04x", elem_addr); + + mod_id = buf->data; + + elem = bt_mesh_elem_find(elem_addr); + if (!elem) { + mod = NULL; + vnd = (buf->len == 4U); + status = STATUS_INVALID_ADDRESS; + goto send_status; + } + + mod = get_model(elem, buf, &vnd); + if (!mod) { + status = STATUS_INVALID_MODEL; + goto send_status; + } + + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) { + bt_mesh_lpn_group_del(mod->groups, ARRAY_SIZE(mod->groups)); + } + + mod_sub_list_clear(mod); + + if (ARRAY_SIZE(mod->groups) > 0) { + status = va_add(label_uuid, &sub_addr); + if (status == STATUS_SUCCESS) { + mod->groups[0] = sub_addr; + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_mod_sub(mod); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) { + bt_mesh_lpn_group_add(sub_addr); + } + } + } else { + status = STATUS_INSUFF_RESOURCES; + } + +send_status: + send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, + mod_id, vnd); +} +#else +static void mod_sub_va_add(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_model *mod; + struct bt_mesh_elem *elem; + u16_t elem_addr; + u8_t *mod_id; + u8_t status; + bool vnd; + + elem_addr = net_buf_simple_pull_le16(buf); + if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { + BT_ERR("%s, Prohibited element address 0x%04x", __func__, elem_addr); + return; + } + + net_buf_simple_pull(buf, 16); + + mod_id = buf->data; + + elem = bt_mesh_elem_find(elem_addr); + if (!elem) { + mod = NULL; + vnd = (buf->len == 4U); + status = STATUS_INVALID_ADDRESS; + goto send_status; + } + + mod = get_model(elem, buf, &vnd); + if (!mod) { + status = STATUS_INVALID_MODEL; + goto send_status; + } + + status = STATUS_INSUFF_RESOURCES; + +send_status: + send_mod_sub_status(model, ctx, status, elem_addr, + BLE_MESH_ADDR_UNASSIGNED, mod_id, vnd); +} + +static void mod_sub_va_del(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_elem *elem; + u16_t elem_addr; + u8_t *mod_id; + u8_t status; + bool vnd; + + elem_addr = net_buf_simple_pull_le16(buf); + if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { + BT_ERR("%s, Prohibited element address 0x%04x", __func__, elem_addr); + return; + } + + net_buf_simple_pull(buf, 16); + + mod_id = buf->data; + + elem = bt_mesh_elem_find(elem_addr); + if (!elem) { + vnd = (buf->len == 4U); + status = STATUS_INVALID_ADDRESS; + goto send_status; + } + + if (!get_model(elem, buf, &vnd)) { + status = STATUS_INVALID_MODEL; + goto send_status; + } + + status = STATUS_INSUFF_RESOURCES; + +send_status: + send_mod_sub_status(model, ctx, status, elem_addr, + BLE_MESH_ADDR_UNASSIGNED, mod_id, vnd); +} + +static void mod_sub_va_overwrite(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_elem *elem; + u16_t elem_addr; + u8_t *mod_id; + u8_t status; + bool vnd; + + elem_addr = net_buf_simple_pull_le16(buf); + if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { + BT_ERR("%s, Prohibited element address 0x%04x", __func__, elem_addr); + return; + } + + net_buf_simple_pull(buf, 18); + + mod_id = buf->data; + + elem = bt_mesh_elem_find(elem_addr); + if (!elem) { + vnd = (buf->len == 4U); + status = STATUS_INVALID_ADDRESS; + goto send_status; + } + + if (!get_model(elem, buf, &vnd)) { + status = STATUS_INVALID_MODEL; + goto send_status; + } + + status = STATUS_INSUFF_RESOURCES; + +send_status: + send_mod_sub_status(model, ctx, status, elem_addr, + BLE_MESH_ADDR_UNASSIGNED, mod_id, vnd); +} +#endif /* CONFIG_BLE_MESH_LABEL_COUNT > 0 */ + +static void send_net_key_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + u16_t idx, u8_t status) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 3 + 4); + + bt_mesh_model_msg_init(&msg, OP_NET_KEY_STATUS); + + net_buf_simple_add_u8(&msg, status); + net_buf_simple_add_le16(&msg, idx); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config NetKey Status", __func__); + } +} + +static void net_key_add(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_subnet *sub; + u16_t idx; + int err; + + idx = net_buf_simple_pull_le16(buf); + if (idx > 0xfff) { + BT_ERR("%s, Invalid NetKeyIndex 0x%04x", __func__, idx); + return; + } + + BT_DBG("idx 0x%04x", idx); + + sub = bt_mesh_subnet_get(idx); + if (!sub) { + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + if (bt_mesh.sub[i].net_idx == BLE_MESH_KEY_UNUSED) { + sub = &bt_mesh.sub[i]; + break; + } + } + + if (!sub) { + send_net_key_status(model, ctx, idx, + STATUS_INSUFF_RESOURCES); + return; + } + } + + /* Check for already existing subnet */ + if (sub->net_idx == idx) { + u8_t status; + + if (memcmp(buf->data, sub->keys[0].net, 16)) { + status = STATUS_IDX_ALREADY_STORED; + } else { + status = STATUS_SUCCESS; + } + + send_net_key_status(model, ctx, idx, status); + return; + } + + err = bt_mesh_net_keys_create(&sub->keys[0], buf->data); + if (err) { + send_net_key_status(model, ctx, idx, STATUS_UNSPECIFIED); + return; + } + + sub->net_idx = idx; + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + BT_DBG("Storing NetKey persistently"); + bt_mesh_store_subnet(sub); + } + + /* Make sure we have valid beacon data to be sent */ + bt_mesh_net_beacon_update(sub); + + if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY)) { + sub->node_id = BLE_MESH_NODE_IDENTITY_STOPPED; +#if CONFIG_BLE_MESH_NODE + bt_mesh_proxy_beacon_send(sub); + bt_mesh_adv_update(); +#endif + } else { + sub->node_id = BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED; + } + + send_net_key_status(model, ctx, idx, STATUS_SUCCESS); +} + +static void net_key_update(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_subnet *sub; + u16_t idx; + int err; + + idx = net_buf_simple_pull_le16(buf); + if (idx > 0xfff) { + BT_ERR("%s, Invalid NetKeyIndex 0x%04x", __func__, idx); + return; + } + + BT_DBG("idx 0x%04x", idx); + + sub = bt_mesh_subnet_get(idx); + if (!sub) { + send_net_key_status(model, ctx, idx, STATUS_INVALID_NETKEY); + return; + } + + /* The node shall successfully process a NetKey Update message on a + * valid NetKeyIndex when the NetKey value is different and the Key + * Refresh procedure has not been started, or when the NetKey value is + * the same in Phase 1. The NetKey Update message shall generate an + * error when the node is in Phase 2, or Phase 3. + */ + switch (sub->kr_phase) { + case BLE_MESH_KR_NORMAL: + if (!memcmp(buf->data, sub->keys[0].net, 16)) { + return; + } + break; + case BLE_MESH_KR_PHASE_1: + if (!memcmp(buf->data, sub->keys[1].net, 16)) { + send_net_key_status(model, ctx, idx, STATUS_SUCCESS); + return; + } + /* fall through */ + case BLE_MESH_KR_PHASE_2: + case BLE_MESH_KR_PHASE_3: + send_net_key_status(model, ctx, idx, STATUS_CANNOT_UPDATE); + return; + } + + err = bt_mesh_net_keys_create(&sub->keys[1], buf->data); + if (!err && (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) || + IS_ENABLED(CONFIG_BLE_MESH_FRIEND))) { + err = friend_cred_update(sub); + } + + if (err) { + send_net_key_status(model, ctx, idx, STATUS_UNSPECIFIED); + return; + } + + sub->kr_phase = BLE_MESH_KR_PHASE_1; + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + BT_DBG("Storing NetKey persistently"); + bt_mesh_store_subnet(sub); + } + + bt_mesh_net_beacon_update(sub); + + send_net_key_status(model, ctx, idx, STATUS_SUCCESS); +} + +static void hb_pub_disable(struct bt_mesh_cfg_srv *cfg) +{ + BT_DBG("%s", __func__); + + cfg->hb_pub.dst = BLE_MESH_ADDR_UNASSIGNED; + cfg->hb_pub.count = 0U; + cfg->hb_pub.ttl = 0U; + cfg->hb_pub.period = 0U; + + k_delayed_work_cancel(&cfg->hb_pub.timer); +} + +static void net_key_del(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_subnet *sub; + u16_t del_idx; + u8_t status; + + del_idx = net_buf_simple_pull_le16(buf); + if (del_idx > 0xfff) { + BT_ERR("%s, Invalid NetKeyIndex 0x%04x", __func__, del_idx); + return; + } + + BT_DBG("idx 0x%04x", del_idx); + + sub = bt_mesh_subnet_get(del_idx); + if (!sub) { + /* This could be a retry of a previous attempt that had its + * response lost, so pretend that it was a success. + */ + status = STATUS_SUCCESS; + goto send_status; + } + + /* The key that the message was encrypted with cannot be removed. + * The NetKey List must contain a minimum of one NetKey. + */ + if (ctx->net_idx == del_idx) { + status = STATUS_CANNOT_REMOVE; + goto send_status; + } + + bt_mesh_subnet_del(sub, true); + status = STATUS_SUCCESS; + +send_status: + send_net_key_status(model, ctx, del_idx, status); +} + +static void net_key_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + NET_BUF_SIMPLE_DEFINE(msg, + 2 + 4 + IDX_LEN(CONFIG_BLE_MESH_SUBNET_COUNT)); + u16_t prev, i; + + bt_mesh_model_msg_init(&msg, OP_NET_KEY_LIST); + + prev = BLE_MESH_KEY_UNUSED; + for (i = 0U; i < ARRAY_SIZE(bt_mesh.sub); i++) { + struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; + + if (sub->net_idx == BLE_MESH_KEY_UNUSED) { + continue; + } + + if (prev == BLE_MESH_KEY_UNUSED) { + prev = sub->net_idx; + continue; + } + + key_idx_pack(&msg, prev, sub->net_idx); + prev = BLE_MESH_KEY_UNUSED; + } + + if (prev != BLE_MESH_KEY_UNUSED) { + net_buf_simple_add_le16(&msg, prev); + } + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config NetKey List", __func__); + } +} + +static void node_identity_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 4 + 4); + struct bt_mesh_subnet *sub; + u8_t node_id; + u16_t idx; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + idx = net_buf_simple_pull_le16(buf); + if (idx > 0xfff) { + BT_ERR("%s, Invalid NetKeyIndex 0x%04x", __func__, idx); + return; + } + + bt_mesh_model_msg_init(&msg, OP_NODE_IDENTITY_STATUS); + + sub = bt_mesh_subnet_get(idx); + if (!sub) { + net_buf_simple_add_u8(&msg, STATUS_INVALID_NETKEY); + node_id = 0x00; + } else { + net_buf_simple_add_u8(&msg, STATUS_SUCCESS); + node_id = sub->node_id; + } + + net_buf_simple_add_le16(&msg, idx); + net_buf_simple_add_u8(&msg, node_id); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Node Identity Status", __func__); + } +} + +static void node_identity_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 4 + 4); + struct bt_mesh_subnet *sub; + u8_t node_id; + u16_t idx; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + idx = net_buf_simple_pull_le16(buf); + if (idx > 0xfff) { + BT_WARN("%s, Invalid NetKeyIndex 0x%04x", __func__, idx); + return; + } + + node_id = net_buf_simple_pull_u8(buf); + if (node_id != 0x00 && node_id != 0x01) { + BT_WARN("%s, Invalid Node ID value 0x%02x", __func__, node_id); + return; + } + + bt_mesh_model_msg_init(&msg, OP_NODE_IDENTITY_STATUS); + + sub = bt_mesh_subnet_get(idx); + if (!sub) { + net_buf_simple_add_u8(&msg, STATUS_INVALID_NETKEY); + net_buf_simple_add_le16(&msg, idx); + net_buf_simple_add_u8(&msg, node_id); + } else { + net_buf_simple_add_u8(&msg, STATUS_SUCCESS); + net_buf_simple_add_le16(&msg, idx); +#if CONFIG_BLE_MESH_NODE + /* Section 4.2.11.1: "When the GATT Proxy state is set to + * 0x00, the Node Identity state for all subnets shall be set + * to 0x00 and shall not be changed." + */ + if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY) && + bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED) { + if (node_id) { + bt_mesh_proxy_identity_start(sub); + } else { + bt_mesh_proxy_identity_stop(sub); + } + bt_mesh_adv_update(); + } +#endif + net_buf_simple_add_u8(&msg, sub->node_id); + } + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Node Identity Status", __func__); + } +} + +static void create_mod_app_status(struct net_buf_simple *msg, + struct bt_mesh_model *mod, bool vnd, + u16_t elem_addr, u16_t app_idx, + u8_t status, u8_t *mod_id) +{ + bt_mesh_model_msg_init(msg, OP_MOD_APP_STATUS); + + net_buf_simple_add_u8(msg, status); + net_buf_simple_add_le16(msg, elem_addr); + net_buf_simple_add_le16(msg, app_idx); + + if (vnd) { + memcpy(net_buf_simple_add(msg, 4), mod_id, 4); + } else { + memcpy(net_buf_simple_add(msg, 2), mod_id, 2); + } +} + +static void mod_app_bind(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 9 + 4); + u16_t elem_addr, key_app_idx; + struct bt_mesh_model *mod; + struct bt_mesh_elem *elem; + u8_t *mod_id, status; + bool vnd; + + elem_addr = net_buf_simple_pull_le16(buf); + if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { + BT_ERR("%s, Prohibited element address 0x%04x", __func__, elem_addr); + return; + } + + key_app_idx = net_buf_simple_pull_le16(buf); + mod_id = buf->data; + + elem = bt_mesh_elem_find(elem_addr); + if (!elem) { + mod = NULL; + vnd = (buf->len == 4U); + status = STATUS_INVALID_ADDRESS; + goto send_status; + } + + mod = get_model(elem, buf, &vnd); + if (!mod) { + status = STATUS_INVALID_MODEL; + goto send_status; + } + + /* Configuration Server only allows device key based access */ + if (model == mod) { + BT_ERR("%s, Client tried to bind AppKey to Configuration Model", __func__); + status = STATUS_CANNOT_BIND; + goto send_status; + } + + status = mod_bind(mod, key_app_idx); + +send_status: + BT_DBG("status 0x%02x", status); + create_mod_app_status(&msg, mod, vnd, elem_addr, key_app_idx, status, + mod_id); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Model App Bind Status", __func__); + } +} + +static void mod_app_unbind(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 9 + 4); + u16_t elem_addr, key_app_idx; + struct bt_mesh_model *mod; + struct bt_mesh_elem *elem; + u8_t *mod_id, status; + bool vnd; + + elem_addr = net_buf_simple_pull_le16(buf); + if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { + BT_ERR("%s, Prohibited element address 0x%04x", __func__, elem_addr); + return; + } + + key_app_idx = net_buf_simple_pull_le16(buf); + mod_id = buf->data; + + elem = bt_mesh_elem_find(elem_addr); + if (!elem) { + mod = NULL; + vnd = (buf->len == 4U); + status = STATUS_INVALID_ADDRESS; + goto send_status; + } + + mod = get_model(elem, buf, &vnd); + if (!mod) { + status = STATUS_INVALID_MODEL; + goto send_status; + } + + status = mod_unbind(mod, key_app_idx, true); + +send_status: + BT_DBG("status 0x%02x", status); + create_mod_app_status(&msg, mod, vnd, elem_addr, key_app_idx, status, + mod_id); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Model App Unbind Status", __func__); + } +} + +#define KEY_LIST_LEN (CONFIG_BLE_MESH_MODEL_KEY_COUNT * 2) + +static void mod_app_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 9 + KEY_LIST_LEN + 4); + struct bt_mesh_model *mod; + struct bt_mesh_elem *elem; + u8_t *mod_id, status; + u16_t elem_addr; + bool vnd; + + elem_addr = net_buf_simple_pull_le16(buf); + if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { + BT_ERR("%s, Prohibited element address 0x%04x", __func__, elem_addr); + return; + } + + mod_id = buf->data; + + BT_DBG("elem_addr 0x%04x", elem_addr); + + elem = bt_mesh_elem_find(elem_addr); + if (!elem) { + mod = NULL; + vnd = (buf->len == 4U); + status = STATUS_INVALID_ADDRESS; + goto send_list; + } + + mod = get_model(elem, buf, &vnd); + if (!mod) { + status = STATUS_INVALID_MODEL; + goto send_list; + } + + status = STATUS_SUCCESS; + +send_list: + if (vnd) { + bt_mesh_model_msg_init(&msg, OP_VND_MOD_APP_LIST); + } else { + bt_mesh_model_msg_init(&msg, OP_SIG_MOD_APP_LIST); + } + + net_buf_simple_add_u8(&msg, status); + net_buf_simple_add_le16(&msg, elem_addr); + + if (vnd) { + net_buf_simple_add_mem(&msg, mod_id, 4); + } else { + net_buf_simple_add_mem(&msg, mod_id, 2); + } + + if (mod) { + int i; + + for (i = 0; i < ARRAY_SIZE(mod->keys); i++) { + if (mod->keys[i] != BLE_MESH_KEY_UNUSED) { + net_buf_simple_add_le16(&msg, mod->keys[i]); + } + } + } + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Model Application List", __func__); + } +} + +static void node_reset(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 0 + 4); + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + + bt_mesh_model_msg_init(&msg, OP_NODE_RESET_STATUS); + + /* Send the response first since we wont have any keys left to + * send it later. + */ + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Node Reset Status", __func__); + } + +#if CONFIG_BLE_MESH_NODE + bt_mesh_reset(); +#endif +} + +static void send_friend_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); + struct bt_mesh_cfg_srv *cfg = model->user_data; + + bt_mesh_model_msg_init(&msg, OP_FRIEND_STATUS); + net_buf_simple_add_u8(&msg, cfg->frnd); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Friend Status", __func__); + } +} + +static void friend_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + send_friend_status(model, ctx); +} + +static void friend_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_cfg_srv *cfg = model->user_data; + struct bt_mesh_subnet *sub; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + if (buf->data[0] != 0x00 && buf->data[0] != 0x01) { + BT_WARN("Invalid Friend value 0x%02x", buf->data[0]); + return; + } + + if (!cfg) { + BT_WARN("No Configuration Server context available"); + goto send_status; + } + + BT_DBG("Friend 0x%02x -> 0x%02x", cfg->frnd, buf->data[0]); + + if (cfg->frnd == buf->data[0]) { + goto send_status; + } + + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { + cfg->frnd = buf->data[0]; + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_cfg(); + } + + if (cfg->frnd == BLE_MESH_FRIEND_DISABLED) { + bt_mesh_friend_clear_net_idx(BLE_MESH_KEY_ANY); + } + } + + sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx); + if ((cfg->hb_pub.feat & BLE_MESH_FEAT_FRIEND) && sub) { + hb_send(model); + } + +send_status: + send_friend_status(model, ctx); +} + +static void lpn_timeout_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 5 + 4); + struct bt_mesh_friend *frnd; + u16_t lpn_addr; + s32_t timeout; + + lpn_addr = net_buf_simple_pull_le16(buf); + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x lpn_addr 0x%02x", + ctx->net_idx, ctx->app_idx, ctx->addr, lpn_addr); + + if (!BLE_MESH_ADDR_IS_UNICAST(lpn_addr)) { + BT_WARN("Invalid LPNAddress; ignoring msg"); + return; + } + + bt_mesh_model_msg_init(&msg, OP_LPN_TIMEOUT_STATUS); + net_buf_simple_add_le16(&msg, lpn_addr); + + if (!IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { + timeout = 0; + goto send_rsp; + } + + frnd = bt_mesh_friend_find(BLE_MESH_KEY_ANY, lpn_addr, true, true); + if (!frnd) { + timeout = 0; + goto send_rsp; + } + + timeout = k_delayed_work_remaining_get(&frnd->timer) / 100; + +send_rsp: + net_buf_simple_add_u8(&msg, timeout); + net_buf_simple_add_u8(&msg, timeout >> 8); + net_buf_simple_add_u8(&msg, timeout >> 16); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config LPN PollTimeout Status", __func__); + } +} + +static void send_krp_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + u16_t idx, u8_t phase, u8_t status) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 4 + 4); + + bt_mesh_model_msg_init(&msg, OP_KRP_STATUS); + + net_buf_simple_add_u8(&msg, status); + net_buf_simple_add_le16(&msg, idx); + net_buf_simple_add_u8(&msg, phase); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Key Refresh Phase Status", __func__); + } +} + +static void krp_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_subnet *sub; + u16_t idx; + + idx = net_buf_simple_pull_le16(buf); + if (idx > 0xfff) { + BT_ERR("%s, Invalid NetKeyIndex 0x%04x", __func__, idx); + return; + } + + BT_DBG("idx 0x%04x", idx); + + sub = bt_mesh_subnet_get(idx); + if (!sub) { + send_krp_status(model, ctx, idx, 0x00, STATUS_INVALID_NETKEY); + } else { + send_krp_status(model, ctx, idx, sub->kr_phase, + STATUS_SUCCESS); + } +} + +static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_subnet *sub; + u8_t phase; + u16_t idx; + + idx = net_buf_simple_pull_le16(buf); + phase = net_buf_simple_pull_u8(buf); + + if (idx > 0xfff) { + BT_ERR("%s, Invalid NetKeyIndex 0x%04x", __func__, idx); + return; + } + + BT_DBG("idx 0x%04x transition 0x%02x", idx, phase); + + sub = bt_mesh_subnet_get(idx); + if (!sub) { + send_krp_status(model, ctx, idx, 0x00, STATUS_INVALID_NETKEY); + return; + } + + BT_DBG("%u -> %u", sub->kr_phase, phase); + + if (phase < BLE_MESH_KR_PHASE_2 || phase > BLE_MESH_KR_PHASE_3 || + (sub->kr_phase == BLE_MESH_KR_NORMAL && + phase == BLE_MESH_KR_PHASE_2)) { + BT_WARN("%s, Prohibited transition %u -> %u", __func__, sub->kr_phase, phase); + return; + } + + if (sub->kr_phase == BLE_MESH_KR_PHASE_1 && + phase == BLE_MESH_KR_PHASE_2) { + sub->kr_phase = BLE_MESH_KR_PHASE_2; + sub->kr_flag = 1; + bt_mesh_net_beacon_update(sub); + } else if ((sub->kr_phase == BLE_MESH_KR_PHASE_1 || + sub->kr_phase == BLE_MESH_KR_PHASE_2) && + phase == BLE_MESH_KR_PHASE_3) { + bt_mesh_net_revoke_keys(sub); + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) || + IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { + friend_cred_refresh(ctx->net_idx); + } + sub->kr_phase = BLE_MESH_KR_NORMAL; + sub->kr_flag = 0; + bt_mesh_net_beacon_update(sub); + } + + send_krp_status(model, ctx, idx, sub->kr_phase, STATUS_SUCCESS); +} + +static u8_t hb_log(u16_t val) +{ + if (!val) { + return 0x00; + } else if (val == 0xffff) { + return 0xff; + } else { + return 32 - __builtin_clz(val); + } +} + +static u8_t hb_pub_count_log(u16_t val) +{ + if (!val) { + return 0x00; + } else if (val == 0x01) { + return 0x01; + } else if (val == 0xffff) { + return 0xff; + } else { + return 32 - __builtin_clz(val - 1) + 1; + } +} + +static u16_t hb_pwr2(u8_t val, u8_t sub) +{ + if (!val) { + return 0x0000; + } else if (val == 0xff || val == 0x11) { + return 0xffff; + } else { + return (1 << (val - sub)); + } +} + +struct hb_pub_param { + u16_t dst; + u8_t count_log; + u8_t period_log; + u8_t ttl; + u16_t feat; + u16_t net_idx; +} __packed; + +static void hb_pub_send_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, u8_t status, + struct hb_pub_param *orig_msg) +{ + /* Needed size: opcode (1 byte) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 1 + 10 + 4); + struct bt_mesh_cfg_srv *cfg = model->user_data; + + BT_DBG("src 0x%04x status 0x%02x", ctx->addr, status); + + bt_mesh_model_msg_init(&msg, OP_HEARTBEAT_PUB_STATUS); + + net_buf_simple_add_u8(&msg, status); + + if (orig_msg) { + memcpy(net_buf_simple_add(&msg, sizeof(*orig_msg)), orig_msg, + sizeof(*orig_msg)); + goto send; + } + + net_buf_simple_add_le16(&msg, cfg->hb_pub.dst); + net_buf_simple_add_u8(&msg, hb_pub_count_log(cfg->hb_pub.count)); + net_buf_simple_add_u8(&msg, cfg->hb_pub.period); + net_buf_simple_add_u8(&msg, cfg->hb_pub.ttl); + net_buf_simple_add_le16(&msg, cfg->hb_pub.feat); + net_buf_simple_add_le16(&msg, cfg->hb_pub.net_idx); + +send: + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Heartbeat Publication Status", __func__); + } +} + +static void heartbeat_pub_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + BT_DBG("src 0x%04x", ctx->addr); + + hb_pub_send_status(model, ctx, STATUS_SUCCESS, NULL); +} + +static void heartbeat_pub_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct hb_pub_param *param = (void *)buf->data; + struct bt_mesh_cfg_srv *cfg = model->user_data; + u16_t dst, feat, idx; + u8_t status; + + BT_DBG("src 0x%04x", ctx->addr); + + dst = sys_le16_to_cpu(param->dst); + /* All other address types but virtual are valid */ + if (BLE_MESH_ADDR_IS_VIRTUAL(dst)) { + status = STATUS_INVALID_ADDRESS; + goto failed; + } + + if (param->count_log > 0x11 && param->count_log != 0xff) { + status = STATUS_CANNOT_SET; + goto failed; + } + + if (param->period_log > 0x10) { + status = STATUS_CANNOT_SET; + goto failed; + } + + if (param->ttl > BLE_MESH_TTL_MAX && param->ttl != BLE_MESH_TTL_DEFAULT) { + BT_ERR("%s, Invalid TTL value 0x%02x", __func__, param->ttl); + return; + } + + feat = sys_le16_to_cpu(param->feat); + + idx = sys_le16_to_cpu(param->net_idx); + if (idx > 0xfff) { + BT_ERR("%s, Invalid NetKeyIndex 0x%04x", __func__, idx); + return; + } + + if (!bt_mesh_subnet_get(idx)) { + status = STATUS_INVALID_NETKEY; + goto failed; + } + + cfg->hb_pub.dst = dst; + cfg->hb_pub.period = param->period_log; + cfg->hb_pub.feat = feat & BLE_MESH_FEAT_SUPPORTED; + cfg->hb_pub.net_idx = idx; + + if (dst == BLE_MESH_ADDR_UNASSIGNED) { + hb_pub_disable(cfg); + } else { + /* 2^(n-1) */ + cfg->hb_pub.count = hb_pwr2(param->count_log, 1); + cfg->hb_pub.ttl = param->ttl; + + BT_DBG("period %u ms", hb_pwr2(param->period_log, 1) * 1000U); + + /* Note: Send heartbeat message here will cause wrong heartbeat status message */ +#if 0 + /* The first Heartbeat message shall be published as soon + * as possible after the Heartbeat Publication Period state + * has been configured for periodic publishing. + */ + if (param->period_log && param->count_log) { + k_work_submit(&cfg->hb_pub.timer.work); + } else { + k_delayed_work_cancel(&cfg->hb_pub.timer); + } +#endif + } + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_hb_pub(); + } + + hb_pub_send_status(model, ctx, STATUS_SUCCESS, NULL); + + /* The first Heartbeat message shall be published as soon + * as possible after the Heartbeat Publication Period state + * has been configured for periodic publishing. + */ + if (dst != BLE_MESH_ADDR_UNASSIGNED) { + if (param->period_log && param->count_log) { + k_work_submit(&cfg->hb_pub.timer.work); + } else { + k_delayed_work_cancel(&cfg->hb_pub.timer); + } + } + + return; + +failed: + hb_pub_send_status(model, ctx, status, param); +} + +static void hb_sub_send_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, u8_t status) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 9 + 4); + struct bt_mesh_cfg_srv *cfg = model->user_data; + u16_t period; + s64_t uptime; + + BT_DBG("src 0x%04x status 0x%02x", ctx->addr, status); + + uptime = k_uptime_get(); + if (uptime > cfg->hb_sub.expiry) { + period = 0U; + } else { + period = (cfg->hb_sub.expiry - uptime) / 1000; + } + + bt_mesh_model_msg_init(&msg, OP_HEARTBEAT_SUB_STATUS); + + net_buf_simple_add_u8(&msg, status); + net_buf_simple_add_le16(&msg, cfg->hb_sub.src); + net_buf_simple_add_le16(&msg, cfg->hb_sub.dst); + if (cfg->hb_sub.src == BLE_MESH_ADDR_UNASSIGNED || + cfg->hb_sub.dst == BLE_MESH_ADDR_UNASSIGNED) { + memset(net_buf_simple_add(&msg, 4), 0, 4); + } else { + net_buf_simple_add_u8(&msg, hb_log(period)); + net_buf_simple_add_u8(&msg, hb_log(cfg->hb_sub.count)); + net_buf_simple_add_u8(&msg, cfg->hb_sub.min_hops); + net_buf_simple_add_u8(&msg, cfg->hb_sub.max_hops); + } + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Config Heartbeat Subscription Status", __func__); + } +} + +static void heartbeat_sub_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + BT_DBG("src 0x%04x", ctx->addr); + + hb_sub_send_status(model, ctx, STATUS_SUCCESS); +} + +static void heartbeat_sub_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_cfg_srv *cfg = model->user_data; + u16_t sub_src, sub_dst; + u8_t sub_period; + s32_t period_ms; + + BT_DBG("src 0x%04x", ctx->addr); + + sub_src = net_buf_simple_pull_le16(buf); + sub_dst = net_buf_simple_pull_le16(buf); + sub_period = net_buf_simple_pull_u8(buf); + + BT_DBG("sub_src 0x%04x sub_dst 0x%04x period 0x%02x", + sub_src, sub_dst, sub_period); + + if (sub_src != BLE_MESH_ADDR_UNASSIGNED && + !BLE_MESH_ADDR_IS_UNICAST(sub_src)) { + BT_WARN("Prohibited source address"); + return; + } + + if (BLE_MESH_ADDR_IS_VIRTUAL(sub_dst) || BLE_MESH_ADDR_IS_RFU(sub_dst) || + (BLE_MESH_ADDR_IS_UNICAST(sub_dst) && + sub_dst != bt_mesh_primary_addr())) { + BT_WARN("Prohibited destination address"); + return; + } + + if (sub_period > 0x11) { + BT_WARN("Prohibited subscription period 0x%02x", sub_period); + return; + } + + if (sub_src == BLE_MESH_ADDR_UNASSIGNED || + sub_dst == BLE_MESH_ADDR_UNASSIGNED || + sub_period == 0x00) { + /* Only an explicit address change to unassigned should + * trigger clearing of the values according to + * MESH/NODE/CFG/HBS/BV-02-C. + */ + if (cfg->hb_sub.src != sub_src || cfg->hb_sub.dst != sub_dst) { + cfg->hb_sub.src = BLE_MESH_ADDR_UNASSIGNED; + cfg->hb_sub.dst = BLE_MESH_ADDR_UNASSIGNED; + } + + period_ms = 0; + } else { + cfg->hb_sub.src = sub_src; + cfg->hb_sub.dst = sub_dst; + cfg->hb_sub.min_hops = BLE_MESH_TTL_MAX; + cfg->hb_sub.max_hops = 0U; + cfg->hb_sub.count = 0U; + period_ms = hb_pwr2(sub_period, 1) * 1000U; + } + + /* Let the transport layer know it needs to handle this address */ + bt_mesh_set_hb_sub_dst(cfg->hb_sub.dst); + + BT_DBG("period_ms %u", period_ms); + + if (period_ms) { + cfg->hb_sub.expiry = k_uptime_get() + period_ms; + } else { + cfg->hb_sub.expiry = 0; + } + + hb_sub_send_status(model, ctx, STATUS_SUCCESS); + + /* MESH/NODE/CFG/HBS/BV-01-C expects the MinHops to be 0x7f after + * disabling subscription, but 0x00 for subsequent Get requests. + */ + if (!period_ms) { + cfg->hb_sub.min_hops = 0U; + } +} + +const struct bt_mesh_model_op bt_mesh_cfg_srv_op[] = { + { OP_DEV_COMP_DATA_GET, 1, dev_comp_data_get }, + { OP_APP_KEY_ADD, 19, app_key_add }, + { OP_APP_KEY_UPDATE, 19, app_key_update }, + { OP_APP_KEY_DEL, 3, app_key_del }, + { OP_APP_KEY_GET, 2, app_key_get }, + { OP_BEACON_GET, 0, beacon_get }, + { OP_BEACON_SET, 1, beacon_set }, + { OP_DEFAULT_TTL_GET, 0, default_ttl_get }, + { OP_DEFAULT_TTL_SET, 1, default_ttl_set }, + { OP_GATT_PROXY_GET, 0, gatt_proxy_get }, + { OP_GATT_PROXY_SET, 1, gatt_proxy_set }, + { OP_NET_TRANSMIT_GET, 0, net_transmit_get }, + { OP_NET_TRANSMIT_SET, 1, net_transmit_set }, + { OP_RELAY_GET, 0, relay_get }, + { OP_RELAY_SET, 2, relay_set }, + { OP_MOD_PUB_GET, 4, mod_pub_get }, + { OP_MOD_PUB_SET, 11, mod_pub_set }, + { OP_MOD_PUB_VA_SET, 24, mod_pub_va_set }, + { OP_MOD_SUB_ADD, 6, mod_sub_add }, + { OP_MOD_SUB_VA_ADD, 20, mod_sub_va_add }, + { OP_MOD_SUB_DEL, 6, mod_sub_del }, + { OP_MOD_SUB_VA_DEL, 20, mod_sub_va_del }, + { OP_MOD_SUB_OVERWRITE, 6, mod_sub_overwrite }, + { OP_MOD_SUB_VA_OVERWRITE, 20, mod_sub_va_overwrite }, + { OP_MOD_SUB_DEL_ALL, 4, mod_sub_del_all }, + { OP_MOD_SUB_GET, 4, mod_sub_get }, + { OP_MOD_SUB_GET_VND, 6, mod_sub_get_vnd }, + { OP_NET_KEY_ADD, 18, net_key_add }, + { OP_NET_KEY_UPDATE, 18, net_key_update }, + { OP_NET_KEY_DEL, 2, net_key_del }, + { OP_NET_KEY_GET, 0, net_key_get }, + { OP_NODE_IDENTITY_GET, 2, node_identity_get }, + { OP_NODE_IDENTITY_SET, 3, node_identity_set }, + { OP_MOD_APP_BIND, 6, mod_app_bind }, + { OP_MOD_APP_UNBIND, 6, mod_app_unbind }, + { OP_SIG_MOD_APP_GET, 4, mod_app_get }, + { OP_VND_MOD_APP_GET, 6, mod_app_get }, + { OP_NODE_RESET, 0, node_reset }, + { OP_FRIEND_GET, 0, friend_get }, + { OP_FRIEND_SET, 1, friend_set }, + { OP_LPN_TIMEOUT_GET, 2, lpn_timeout_get }, + { OP_KRP_GET, 2, krp_get }, + { OP_KRP_SET, 3, krp_set }, + { OP_HEARTBEAT_PUB_GET, 0, heartbeat_pub_get }, + { OP_HEARTBEAT_PUB_SET, 9, heartbeat_pub_set }, + { OP_HEARTBEAT_SUB_GET, 0, heartbeat_sub_get }, + { OP_HEARTBEAT_SUB_SET, 5, heartbeat_sub_set }, + BLE_MESH_MODEL_OP_END, +}; + +static void hb_publish(struct k_work *work) +{ + struct bt_mesh_cfg_srv *cfg = CONTAINER_OF(work, + struct bt_mesh_cfg_srv, + hb_pub.timer.work); + struct bt_mesh_model *model = cfg->model; + struct bt_mesh_subnet *sub; + u16_t period_ms; + + BT_DBG("hb_pub.count: %u", cfg->hb_pub.count); + + sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx); + if (!sub) { + BT_ERR("%s, No matching subnet for idx 0x%02x", + __func__, cfg->hb_pub.net_idx); + cfg->hb_pub.dst = BLE_MESH_ADDR_UNASSIGNED; + return; + } + + if (cfg->hb_pub.count == 0U) { + return; + } + + period_ms = hb_pwr2(cfg->hb_pub.period, 1) * 1000U; + if (period_ms && cfg->hb_pub.count > 1) { + k_delayed_work_submit(&cfg->hb_pub.timer, period_ms); + } + + hb_send(model); + + if (cfg->hb_pub.count != 0xffff) { + cfg->hb_pub.count--; + } +} + +static bool conf_is_valid(struct bt_mesh_cfg_srv *cfg) +{ + if (cfg->relay > 0x02) { + return false; + } + + if (cfg->beacon > 0x01) { + return false; + } + + if (cfg->default_ttl > BLE_MESH_TTL_MAX) { + return false; + } + + return true; +} + +int bt_mesh_cfg_srv_init(struct bt_mesh_model *model, bool primary) +{ + struct bt_mesh_cfg_srv *cfg = model->user_data; + + if (!cfg) { + BT_ERR("%s, No Configuration Server context provided", __func__); + return -EINVAL; + } + + if (!conf_is_valid(cfg)) { + BT_ERR("%s, Invalid values in configuration", __func__); + return -EINVAL; + } + + /* Configuration Model security is device-key based */ + model->keys[0] = BLE_MESH_KEY_DEV; + + if (!IS_ENABLED(CONFIG_BLE_MESH_RELAY)) { + cfg->relay = BLE_MESH_RELAY_NOT_SUPPORTED; + } + + if (!IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { + cfg->frnd = BLE_MESH_FRIEND_NOT_SUPPORTED; + } + + if (!IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY)) { + cfg->gatt_proxy = BLE_MESH_GATT_PROXY_NOT_SUPPORTED; + } + + k_delayed_work_init(&cfg->hb_pub.timer, hb_publish); + cfg->hb_pub.net_idx = BLE_MESH_KEY_UNUSED; + cfg->hb_sub.expiry = 0; + + cfg->model = model; + + conf = cfg; + + return 0; +} + +static void mod_reset(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, + bool vnd, bool primary, void *user_data) +{ + size_t clear_count; + + /* Clear model state that isn't otherwise cleared. E.g. AppKey + * binding and model publication is cleared as a consequence + * of removing all app keys, however model subscription clearing + * must be taken care of here. + */ + + clear_count = mod_sub_list_clear(mod); + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS) && clear_count) { + bt_mesh_store_mod_sub(mod); + } +} + +void bt_mesh_cfg_reset(void) +{ + struct bt_mesh_cfg_srv *cfg = conf; + int i; + + BT_DBG("%s", __func__); + + if (!cfg) { + return; + } + + bt_mesh_set_hb_sub_dst(BLE_MESH_ADDR_UNASSIGNED); + + cfg->hb_sub.src = BLE_MESH_ADDR_UNASSIGNED; + cfg->hb_sub.dst = BLE_MESH_ADDR_UNASSIGNED; + cfg->hb_sub.expiry = 0; + + /* Delete all net keys, which also takes care of all app keys which + * are associated with each net key. + */ + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; + + if (sub->net_idx != BLE_MESH_KEY_UNUSED) { + bt_mesh_subnet_del(sub, true); + } + } + + bt_mesh_model_foreach(mod_reset, NULL); + + (void)memset(labels, 0, sizeof(labels)); +} + +void bt_mesh_heartbeat(u16_t src, u16_t dst, u8_t hops, u16_t feat) +{ + struct bt_mesh_cfg_srv *cfg = conf; + + if (!cfg) { + BT_WARN("No configuaration server context available"); + return; + } + + if (src != cfg->hb_sub.src || dst != cfg->hb_sub.dst) { + BT_WARN("No subscription for received heartbeat"); + return; + } + + if (k_uptime_get() > cfg->hb_sub.expiry) { + BT_WARN("Heartbeat subscription period expired"); + return; + } + + cfg->hb_sub.min_hops = MIN(cfg->hb_sub.min_hops, hops); + cfg->hb_sub.max_hops = MAX(cfg->hb_sub.max_hops, hops); + + if (cfg->hb_sub.count < 0xffff) { + cfg->hb_sub.count++; + } + + BT_DBG("src 0x%04x dst 0x%04x hops %u min %u max %u count %u", src, + dst, hops, cfg->hb_sub.min_hops, cfg->hb_sub.max_hops, + cfg->hb_sub.count); + + if (cfg->hb_sub.func) { + cfg->hb_sub.func(hops, feat); + } +} + +u8_t bt_mesh_net_transmit_get(void) +{ + if (conf) { + return conf->net_transmit; + } + + return 0; +} + +u8_t bt_mesh_relay_get(void) +{ + if (conf) { + return conf->relay; + } + + return BLE_MESH_RELAY_NOT_SUPPORTED; +} + +u8_t bt_mesh_friend_get(void) +{ + if (conf) { + BT_DBG("conf %p conf->frnd 0x%02x", conf, conf->frnd); + return conf->frnd; + } + + return BLE_MESH_FRIEND_NOT_SUPPORTED; +} + +u8_t bt_mesh_relay_retransmit_get(void) +{ + if (conf) { + return conf->relay_retransmit; + } + + return 0; +} + +u8_t bt_mesh_beacon_get(void) +{ + if (conf) { + return conf->beacon; + } + + return BLE_MESH_BEACON_DISABLED; +} + +u8_t bt_mesh_gatt_proxy_get(void) +{ + if (conf) { + return conf->gatt_proxy; + } + + return BLE_MESH_GATT_PROXY_NOT_SUPPORTED; +} + +u8_t bt_mesh_default_ttl_get(void) +{ + if (conf) { + return conf->default_ttl; + } + + return DEFAULT_TTL; +} + +u8_t *bt_mesh_label_uuid_get(u16_t addr) +{ + int i; + + BT_DBG("addr 0x%04x", addr); + + for (i = 0; i < ARRAY_SIZE(labels); i++) { + if (labels[i].addr == addr) { + BT_DBG("Found Label UUID for 0x%04x: %s", addr, + bt_hex(labels[i].uuid, 16)); + return labels[i].uuid; + } + } + + BT_WARN("No matching Label UUID for 0x%04x", addr); + + return NULL; +} + +struct bt_mesh_hb_pub *bt_mesh_hb_pub_get(void) +{ + if (!conf) { + return NULL; + } + + return &conf->hb_pub; +} + +void bt_mesh_hb_pub_disable(void) +{ + if (conf) { + hb_pub_disable(conf); + } +} + +struct bt_mesh_cfg_srv *bt_mesh_cfg_get(void) +{ + return conf; +} + +void bt_mesh_subnet_del(struct bt_mesh_subnet *sub, bool store) +{ + int i; + + BT_DBG("NetIdx 0x%03x store %u", sub->net_idx, store); + + if (conf && conf->hb_pub.net_idx == sub->net_idx) { + hb_pub_disable(conf); + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS) && store) { + bt_mesh_store_hb_pub(); + } + } + + /* Delete any app keys bound to this NetKey index */ + for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { + struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; + + if (key->net_idx == sub->net_idx) { + bt_mesh_app_key_del(key, store); + } + } + + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { + bt_mesh_friend_clear_net_idx(sub->net_idx); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS) && store) { + bt_mesh_clear_subnet(sub); + } + + (void)memset(sub, 0, sizeof(*sub)); + sub->net_idx = BLE_MESH_KEY_UNUSED; +} diff --git a/components/bt/ble_mesh/mesh_core/crypto.c b/components/bt/ble_mesh/mesh_core/crypto.c new file mode 100644 index 0000000000..d2e6507882 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/crypto.c @@ -0,0 +1,878 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "sdkconfig.h" +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BLE_MESH_DEBUG_CRYPTO) + +#include "mesh_types.h" +#include "mesh_util.h" +#include "mesh_buf.h" +#include "mesh_trace.h" +#include "mesh_bearer_adapt.h" +#include "mesh_aes_encrypt.h" + +#include "mesh.h" +#include "crypto.h" + +#define NET_MIC_LEN(pdu) (((pdu)[1] & 0x80) ? 8 : 4) +#define APP_MIC_LEN(aszmic) ((aszmic) ? 8 : 4) + +int bt_mesh_aes_cmac(const u8_t key[16], struct bt_mesh_sg *sg, + size_t sg_len, u8_t mac[16]) +{ + struct tc_aes_key_sched_struct sched; + struct tc_cmac_struct state; + + if (tc_cmac_setup(&state, key, &sched) == TC_CRYPTO_FAIL) { + return -EIO; + } + + for (; sg_len; sg_len--, sg++) { + if (tc_cmac_update(&state, sg->data, + sg->len) == TC_CRYPTO_FAIL) { + return -EIO; + } + } + + if (tc_cmac_final(mac, &state) == TC_CRYPTO_FAIL) { + return -EIO; + } + + return 0; +} + +int bt_mesh_k1(const u8_t *ikm, size_t ikm_len, const u8_t salt[16], + const char *info, u8_t okm[16]) +{ + int err; + + err = bt_mesh_aes_cmac_one(salt, ikm, ikm_len, okm); + if (err < 0) { + return err; + } + + return bt_mesh_aes_cmac_one(okm, info, strlen(info), okm); +} + +int bt_mesh_k2(const u8_t n[16], const u8_t *p, size_t p_len, + u8_t net_id[1], u8_t enc_key[16], u8_t priv_key[16]) +{ + struct bt_mesh_sg sg[3]; + u8_t salt[16]; + u8_t out[16]; + u8_t t[16]; + u8_t pad; + int err; + + BT_DBG("n %s", bt_hex(n, 16)); + BT_DBG("p %s", bt_hex(p, p_len)); + + err = bt_mesh_s1("smk2", salt); + if (err) { + return err; + } + + err = bt_mesh_aes_cmac_one(salt, n, 16, t); + if (err) { + return err; + } + + pad = 0x01; + + sg[0].data = NULL; + sg[0].len = 0; + sg[1].data = p; + sg[1].len = p_len; + sg[2].data = &pad; + sg[2].len = sizeof(pad); + + err = bt_mesh_aes_cmac(t, sg, ARRAY_SIZE(sg), out); + if (err) { + return err; + } + + net_id[0] = out[15] & 0x7f; + + sg[0].data = out; + sg[0].len = sizeof(out); + pad = 0x02; + + err = bt_mesh_aes_cmac(t, sg, ARRAY_SIZE(sg), out); + if (err) { + return err; + } + + memcpy(enc_key, out, 16); + + pad = 0x03; + + err = bt_mesh_aes_cmac(t, sg, ARRAY_SIZE(sg), out); + if (err) { + return err; + } + + memcpy(priv_key, out, 16); + + BT_DBG("NID 0x%02x enc_key %s", net_id[0], bt_hex(enc_key, 16)); + BT_DBG("priv_key %s", bt_hex(priv_key, 16)); + + return 0; +} + +int bt_mesh_k3(const u8_t n[16], u8_t out[8]) +{ + u8_t id64[] = { 'i', 'd', '6', '4', 0x01 }; + u8_t tmp[16]; + u8_t t[16]; + int err; + + err = bt_mesh_s1("smk3", tmp); + if (err) { + return err; + } + + err = bt_mesh_aes_cmac_one(tmp, n, 16, t); + if (err) { + return err; + } + + err = bt_mesh_aes_cmac_one(t, id64, sizeof(id64), tmp); + if (err) { + return err; + } + + memcpy(out, tmp + 8, 8); + + return 0; +} + +int bt_mesh_k4(const u8_t n[16], u8_t out[1]) +{ + u8_t id6[] = { 'i', 'd', '6', 0x01 }; + u8_t tmp[16]; + u8_t t[16]; + int err; + + err = bt_mesh_s1("smk4", tmp); + if (err) { + return err; + } + + err = bt_mesh_aes_cmac_one(tmp, n, 16, t); + if (err) { + return err; + } + + err = bt_mesh_aes_cmac_one(t, id6, sizeof(id6), tmp); + if (err) { + return err; + } + + out[0] = tmp[15] & BIT_MASK(6); + + return 0; +} + +int bt_mesh_id128(const u8_t n[16], const char *s, u8_t out[16]) +{ + const char *id128 = "id128\x01"; + u8_t salt[16]; + int err; + + err = bt_mesh_s1(s, salt); + if (err) { + return err; + } + + return bt_mesh_k1(n, 16, salt, id128, out); +} + +static int bt_mesh_ccm_decrypt(const u8_t key[16], u8_t nonce[13], + const u8_t *enc_msg, size_t msg_len, + const u8_t *aad, size_t aad_len, + u8_t *out_msg, size_t mic_size) +{ + u8_t msg[16], pmsg[16], cmic[16], cmsg[16], Xn[16], mic[16]; + u16_t last_blk, blk_cnt; + size_t i, j; + int err; + + if (msg_len < 1 || aad_len >= 0xff00) { + return -EINVAL; + } + + /* C_mic = e(AppKey, 0x01 || nonce || 0x0000) */ + pmsg[0] = 0x01; + memcpy(pmsg + 1, nonce, 13); + sys_put_be16(0x0000, pmsg + 14); + + err = bt_mesh_encrypt_be(key, pmsg, cmic); + if (err) { + return err; + } + + /* X_0 = e(AppKey, 0x09 || nonce || length) */ + if (mic_size == sizeof(u64_t)) { + pmsg[0] = 0x19 | (aad_len ? 0x40 : 0x00); + } else { + pmsg[0] = 0x09 | (aad_len ? 0x40 : 0x00); + } + + memcpy(pmsg + 1, nonce, 13); + sys_put_be16(msg_len, pmsg + 14); + + err = bt_mesh_encrypt_be(key, pmsg, Xn); + if (err) { + return err; + } + + /* If AAD is being used to authenticate, include it here */ + if (aad_len) { + sys_put_be16(aad_len, pmsg); + + for (i = 0; i < sizeof(u16_t); i++) { + pmsg[i] = Xn[i] ^ pmsg[i]; + } + + j = 0; + aad_len += sizeof(u16_t); + while (aad_len > 16) { + do { + pmsg[i] = Xn[i] ^ aad[j]; + i++, j++; + } while (i < 16); + + aad_len -= 16; + i = 0; + + err = bt_mesh_encrypt_be(key, pmsg, Xn); + if (err) { + return err; + } + } + + for (i = 0; i < aad_len; i++, j++) { + pmsg[i] = Xn[i] ^ aad[j]; + } + + for (i = aad_len; i < 16; i++) { + pmsg[i] = Xn[i]; + } + + err = bt_mesh_encrypt_be(key, pmsg, Xn); + if (err) { + return err; + } + } + + last_blk = msg_len % 16; + blk_cnt = (msg_len + 15) / 16; + if (!last_blk) { + last_blk = 16U; + } + + for (j = 0; j < blk_cnt; j++) { + if (j + 1 == blk_cnt) { + /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */ + pmsg[0] = 0x01; + memcpy(pmsg + 1, nonce, 13); + sys_put_be16(j + 1, pmsg + 14); + + err = bt_mesh_encrypt_be(key, pmsg, cmsg); + if (err) { + return err; + } + + /* Encrypted = Payload[0-15] ^ C_1 */ + for (i = 0; i < last_blk; i++) { + msg[i] = enc_msg[(j * 16) + i] ^ cmsg[i]; + } + + memcpy(out_msg + (j * 16), msg, last_blk); + + /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */ + for (i = 0; i < last_blk; i++) { + pmsg[i] = Xn[i] ^ msg[i]; + } + + for (i = last_blk; i < 16; i++) { + pmsg[i] = Xn[i] ^ 0x00; + } + + err = bt_mesh_encrypt_be(key, pmsg, Xn); + if (err) { + return err; + } + + /* MIC = C_mic ^ X_1 */ + for (i = 0; i < sizeof(mic); i++) { + mic[i] = cmic[i] ^ Xn[i]; + } + } else { + /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */ + pmsg[0] = 0x01; + memcpy(pmsg + 1, nonce, 13); + sys_put_be16(j + 1, pmsg + 14); + + err = bt_mesh_encrypt_be(key, pmsg, cmsg); + if (err) { + return err; + } + + /* Encrypted = Payload[0-15] ^ C_1 */ + for (i = 0; i < 16; i++) { + msg[i] = enc_msg[(j * 16) + i] ^ cmsg[i]; + } + + memcpy(out_msg + (j * 16), msg, 16); + + /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */ + for (i = 0; i < 16; i++) { + pmsg[i] = Xn[i] ^ msg[i]; + } + + err = bt_mesh_encrypt_be(key, pmsg, Xn); + if (err) { + return err; + } + } + } + + if (memcmp(mic, enc_msg + msg_len, mic_size)) { + return -EBADMSG; + } + + return 0; +} + +static int bt_mesh_ccm_encrypt(const u8_t key[16], u8_t nonce[13], + const u8_t *msg, size_t msg_len, + const u8_t *aad, size_t aad_len, + u8_t *out_msg, size_t mic_size) +{ + u8_t pmsg[16], cmic[16], cmsg[16], mic[16], Xn[16]; + u16_t blk_cnt, last_blk; + size_t i, j; + int err; + + BT_DBG("key %s", bt_hex(key, 16)); + BT_DBG("nonce %s", bt_hex(nonce, 13)); + BT_DBG("msg (len %u) %s", msg_len, bt_hex(msg, msg_len)); + BT_DBG("aad_len %u mic_size %u", aad_len, mic_size); + + /* Unsupported AAD size */ + if (aad_len >= 0xff00) { + return -EINVAL; + } + + /* C_mic = e(AppKey, 0x01 || nonce || 0x0000) */ + pmsg[0] = 0x01; + memcpy(pmsg + 1, nonce, 13); + sys_put_be16(0x0000, pmsg + 14); + + err = bt_mesh_encrypt_be(key, pmsg, cmic); + if (err) { + return err; + } + + /* X_0 = e(AppKey, 0x09 || nonce || length) */ + if (mic_size == sizeof(u64_t)) { + pmsg[0] = 0x19 | (aad_len ? 0x40 : 0x00); + } else { + pmsg[0] = 0x09 | (aad_len ? 0x40 : 0x00); + } + + memcpy(pmsg + 1, nonce, 13); + sys_put_be16(msg_len, pmsg + 14); + + err = bt_mesh_encrypt_be(key, pmsg, Xn); + if (err) { + return err; + } + + /* If AAD is being used to authenticate, include it here */ + if (aad_len) { + sys_put_be16(aad_len, pmsg); + + for (i = 0; i < sizeof(u16_t); i++) { + pmsg[i] = Xn[i] ^ pmsg[i]; + } + + j = 0; + aad_len += sizeof(u16_t); + while (aad_len > 16) { + do { + pmsg[i] = Xn[i] ^ aad[j]; + i++, j++; + } while (i < 16); + + aad_len -= 16; + i = 0; + + err = bt_mesh_encrypt_be(key, pmsg, Xn); + if (err) { + return err; + } + } + + for (i = 0; i < aad_len; i++, j++) { + pmsg[i] = Xn[i] ^ aad[j]; + } + + for (i = aad_len; i < 16; i++) { + pmsg[i] = Xn[i]; + } + + err = bt_mesh_encrypt_be(key, pmsg, Xn); + if (err) { + return err; + } + } + + last_blk = msg_len % 16; + blk_cnt = (msg_len + 15) / 16; + if (!last_blk) { + last_blk = 16U; + } + + for (j = 0; j < blk_cnt; j++) { + if (j + 1 == blk_cnt) { + /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */ + for (i = 0; i < last_blk; i++) { + pmsg[i] = Xn[i] ^ msg[(j * 16) + i]; + } + for (i = last_blk; i < 16; i++) { + pmsg[i] = Xn[i] ^ 0x00; + } + + err = bt_mesh_encrypt_be(key, pmsg, Xn); + if (err) { + return err; + } + + /* MIC = C_mic ^ X_1 */ + for (i = 0; i < sizeof(mic); i++) { + mic[i] = cmic[i] ^ Xn[i]; + } + + /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */ + pmsg[0] = 0x01; + memcpy(pmsg + 1, nonce, 13); + sys_put_be16(j + 1, pmsg + 14); + + err = bt_mesh_encrypt_be(key, pmsg, cmsg); + if (err) { + return err; + } + + /* Encrypted = Payload[0-15] ^ C_1 */ + for (i = 0; i < last_blk; i++) { + out_msg[(j * 16) + i] = + msg[(j * 16) + i] ^ cmsg[i]; + } + } else { + /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */ + for (i = 0; i < 16; i++) { + pmsg[i] = Xn[i] ^ msg[(j * 16) + i]; + } + + err = bt_mesh_encrypt_be(key, pmsg, Xn); + if (err) { + return err; + } + + /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */ + pmsg[0] = 0x01; + memcpy(pmsg + 1, nonce, 13); + sys_put_be16(j + 1, pmsg + 14); + + err = bt_mesh_encrypt_be(key, pmsg, cmsg); + if (err) { + return err; + } + + /* Encrypted = Payload[0-15] ^ C_N */ + for (i = 0; i < 16; i++) { + out_msg[(j * 16) + i] = + msg[(j * 16) + i] ^ cmsg[i]; + } + + } + } + + memcpy(out_msg + msg_len, mic, mic_size); + + return 0; +} + +#if defined(CONFIG_BLE_MESH_PROXY) +static void create_proxy_nonce(u8_t nonce[13], const u8_t *pdu, + u32_t iv_index) +{ + /* Nonce Type */ + nonce[0] = 0x03; + + /* Pad */ + nonce[1] = 0x00; + + /* Sequence Number */ + nonce[2] = pdu[2]; + nonce[3] = pdu[3]; + nonce[4] = pdu[4]; + + /* Source Address */ + nonce[5] = pdu[5]; + nonce[6] = pdu[6]; + + /* Pad */ + nonce[7] = 0U; + nonce[8] = 0U; + + /* IV Index */ + sys_put_be32(iv_index, &nonce[9]); +} +#endif /* PROXY */ + +static void create_net_nonce(u8_t nonce[13], const u8_t *pdu, + u32_t iv_index) +{ + /* Nonce Type */ + nonce[0] = 0x00; + + /* FRND + TTL */ + nonce[1] = pdu[1]; + + /* Sequence Number */ + nonce[2] = pdu[2]; + nonce[3] = pdu[3]; + nonce[4] = pdu[4]; + + /* Source Address */ + nonce[5] = pdu[5]; + nonce[6] = pdu[6]; + + /* Pad */ + nonce[7] = 0U; + nonce[8] = 0U; + + /* IV Index */ + sys_put_be32(iv_index, &nonce[9]); +} + +int bt_mesh_net_obfuscate(u8_t *pdu, u32_t iv_index, + const u8_t privacy_key[16]) +{ + u8_t priv_rand[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, }; + u8_t tmp[16]; + int err, i; + + BT_DBG("IVIndex %u, PrivacyKey %s", iv_index, bt_hex(privacy_key, 16)); + + sys_put_be32(iv_index, &priv_rand[5]); + memcpy(&priv_rand[9], &pdu[7], 7); + + BT_DBG("PrivacyRandom %s", bt_hex(priv_rand, 16)); + + err = bt_mesh_encrypt_be(privacy_key, priv_rand, tmp); + if (err) { + return err; + } + + for (i = 0; i < 6; i++) { + pdu[1 + i] ^= tmp[i]; + } + + return 0; +} + +int bt_mesh_net_encrypt(const u8_t key[16], struct net_buf_simple *buf, + u32_t iv_index, bool proxy) +{ + u8_t mic_len = NET_MIC_LEN(buf->data); + u8_t nonce[13]; + int err; + + BT_DBG("IVIndex %u EncKey %s mic_len %u", iv_index, bt_hex(key, 16), + mic_len); + BT_DBG("PDU (len %u) %s", buf->len, bt_hex(buf->data, buf->len)); + +#if defined(CONFIG_BLE_MESH_PROXY) + if (proxy) { + create_proxy_nonce(nonce, buf->data, iv_index); + } else { + create_net_nonce(nonce, buf->data, iv_index); + } +#else + create_net_nonce(nonce, buf->data, iv_index); +#endif + + BT_DBG("Nonce %s", bt_hex(nonce, 13)); + + err = bt_mesh_ccm_encrypt(key, nonce, &buf->data[7], buf->len - 7, + NULL, 0, &buf->data[7], mic_len); + if (!err) { + net_buf_simple_add(buf, mic_len); + } + + return err; +} + +int bt_mesh_net_decrypt(const u8_t key[16], struct net_buf_simple *buf, + u32_t iv_index, bool proxy) +{ + u8_t mic_len = NET_MIC_LEN(buf->data); + u8_t nonce[13]; + + BT_DBG("PDU (%u bytes) %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("iv_index %u, key %s mic_len %u", iv_index, bt_hex(key, 16), + mic_len); + +#if defined(CONFIG_BLE_MESH_PROXY) + if (proxy) { + create_proxy_nonce(nonce, buf->data, iv_index); + } else { + create_net_nonce(nonce, buf->data, iv_index); + } +#else + create_net_nonce(nonce, buf->data, iv_index); +#endif + + BT_DBG("Nonce %s", bt_hex(nonce, 13)); + + buf->len -= mic_len; + + return bt_mesh_ccm_decrypt(key, nonce, &buf->data[7], buf->len - 7, + NULL, 0, &buf->data[7], mic_len); +} + +static void create_app_nonce(u8_t nonce[13], bool dev_key, u8_t aszmic, + u16_t src, u16_t dst, u32_t seq_num, + u32_t iv_index) +{ + if (dev_key) { + nonce[0] = 0x02; + } else { + nonce[0] = 0x01; + } + + sys_put_be32((seq_num | ((u32_t)aszmic << 31)), &nonce[1]); + + sys_put_be16(src, &nonce[5]); + sys_put_be16(dst, &nonce[7]); + + sys_put_be32(iv_index, &nonce[9]); +} + +int bt_mesh_app_encrypt(const u8_t key[16], bool dev_key, u8_t aszmic, + struct net_buf_simple *buf, const u8_t *ad, + u16_t src, u16_t dst, u32_t seq_num, u32_t iv_index) +{ + u8_t nonce[13]; + int err; + + BT_DBG("AppKey %s", bt_hex(key, 16)); + BT_DBG("dev_key %u src 0x%04x dst 0x%04x", dev_key, src, dst); + BT_DBG("seq_num 0x%08x iv_index 0x%08x", seq_num, iv_index); + BT_DBG("Clear: %s", bt_hex(buf->data, buf->len)); + + create_app_nonce(nonce, dev_key, aszmic, src, dst, seq_num, iv_index); + + BT_DBG("Nonce %s", bt_hex(nonce, 13)); + + err = bt_mesh_ccm_encrypt(key, nonce, buf->data, buf->len, ad, + ad ? 16 : 0, buf->data, APP_MIC_LEN(aszmic)); + if (!err) { + net_buf_simple_add(buf, APP_MIC_LEN(aszmic)); + BT_DBG("Encr: %s", bt_hex(buf->data, buf->len)); + } + + return err; +} + +int bt_mesh_app_decrypt(const u8_t key[16], bool dev_key, u8_t aszmic, + struct net_buf_simple *buf, struct net_buf_simple *out, + const u8_t *ad, u16_t src, u16_t dst, u32_t seq_num, + u32_t iv_index) +{ + u8_t nonce[13]; + int err; + + BT_DBG("EncData (len %u) %s", buf->len, bt_hex(buf->data, buf->len)); + + create_app_nonce(nonce, dev_key, aszmic, src, dst, seq_num, iv_index); + + BT_DBG("AppKey %s", bt_hex(key, 16)); + BT_DBG("Nonce %s", bt_hex(nonce, 13)); + + err = bt_mesh_ccm_decrypt(key, nonce, buf->data, buf->len, ad, + ad ? 16 : 0, out->data, APP_MIC_LEN(aszmic)); + if (!err) { + net_buf_simple_add(out, buf->len); + } + + return err; +} + +/* reversed, 8-bit, poly=0x07 */ +static const u8_t crc_table[256] = { + 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75, + 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b, + 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69, + 0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67, + + 0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d, + 0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43, + 0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51, + 0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f, + + 0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05, + 0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b, + 0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19, + 0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17, + + 0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d, + 0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33, + 0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21, + 0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f, + + 0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95, + 0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b, + 0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89, + 0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87, + + 0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad, + 0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3, + 0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1, + 0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf, + + 0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5, + 0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb, + 0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9, + 0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7, + + 0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd, + 0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3, + 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1, + 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf +}; + +u8_t bt_mesh_fcs_calc(const u8_t *data, u8_t data_len) +{ + u8_t fcs = 0xff; + + while (data_len--) { + fcs = crc_table[fcs ^ *data++]; + } + + BT_DBG("fcs 0x%02x", 0xff - fcs); + + return 0xff - fcs; +} + +bool bt_mesh_fcs_check(struct net_buf_simple *buf, u8_t received_fcs) +{ + const u8_t *data = buf->data; + u16_t data_len = buf->len; + u8_t fcs = 0xff; + + while (data_len--) { + fcs = crc_table[fcs ^ *data++]; + } + + return crc_table[fcs ^ received_fcs] == 0xcf; +} + +int bt_mesh_virtual_addr(const u8_t virtual_label[16], u16_t *addr) +{ + u8_t salt[16]; + u8_t tmp[16]; + int err; + + err = bt_mesh_s1("vtad", salt); + if (err) { + return err; + } + + err = bt_mesh_aes_cmac_one(salt, virtual_label, 16, tmp); + if (err) { + return err; + } + + *addr = (sys_get_be16(&tmp[14]) & 0x3fff) | 0x8000; + + return 0; +} + +int bt_mesh_prov_conf_salt(const u8_t conf_inputs[145], u8_t salt[16]) +{ + const u8_t conf_salt_key[16] = { 0 }; + + return bt_mesh_aes_cmac_one(conf_salt_key, conf_inputs, 145, salt); +} + +int bt_mesh_prov_conf_key(const u8_t dhkey[32], const u8_t conf_salt[16], + u8_t conf_key[16]) +{ + return bt_mesh_k1(dhkey, 32, conf_salt, "prck", conf_key); +} + +int bt_mesh_prov_conf(const u8_t conf_key[16], const u8_t rand[16], + const u8_t auth[16], u8_t conf[16]) +{ + struct bt_mesh_sg sg[] = { { rand, 16 }, { auth, 16 } }; + + BT_DBG("ConfirmationKey %s", bt_hex(conf_key, 16)); + BT_DBG("RandomDevice %s", bt_hex(rand, 16)); + BT_DBG("AuthValue %s", bt_hex(auth, 16)); + + return bt_mesh_aes_cmac(conf_key, sg, ARRAY_SIZE(sg), conf); +} + +int bt_mesh_prov_decrypt(const u8_t key[16], u8_t nonce[13], + const u8_t data[25 + 8], u8_t out[25]) +{ + return bt_mesh_ccm_decrypt(key, nonce, data, 25, NULL, 0, out, 8); +} + +#if CONFIG_BLE_MESH_PROVISIONER +int bt_mesh_prov_encrypt(const u8_t key[16], u8_t nonce[13], + const u8_t data[25], u8_t out[33]) +{ + return bt_mesh_ccm_encrypt(key, nonce, data, 25, NULL, 0, out, 8); +} +#endif + +int bt_mesh_beacon_auth(const u8_t beacon_key[16], u8_t flags, + const u8_t net_id[8], u32_t iv_index, + u8_t auth[8]) +{ + u8_t msg[13], tmp[16]; + int err; + + BT_DBG("BeaconKey %s", bt_hex(beacon_key, 16)); + BT_DBG("NetId %s", bt_hex(net_id, 8)); + BT_DBG("IV Index 0x%08x", iv_index); + + msg[0] = flags; + memcpy(&msg[1], net_id, 8); + sys_put_be32(iv_index, &msg[9]); + + BT_DBG("BeaconMsg %s", bt_hex(msg, sizeof(msg))); + + err = bt_mesh_aes_cmac_one(beacon_key, msg, sizeof(msg), tmp); + if (!err) { + memcpy(auth, tmp, 8); + } + + return err; +} diff --git a/components/bt/ble_mesh/mesh_core/crypto.h b/components/bt/ble_mesh/mesh_core/crypto.h new file mode 100644 index 0000000000..d8e9b1452e --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/crypto.h @@ -0,0 +1,166 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _CRYPTO_H_ +#define _CRYPTO_H_ + +#include "mesh_types.h" +#include + +struct bt_mesh_sg { + const void *data; + size_t len; +}; + +int bt_mesh_aes_cmac(const u8_t key[16], struct bt_mesh_sg *sg, + size_t sg_len, u8_t mac[16]); + +static inline int bt_mesh_aes_cmac_one(const u8_t key[16], const void *m, + size_t len, u8_t mac[16]) +{ + struct bt_mesh_sg sg = { m, len }; + + return bt_mesh_aes_cmac(key, &sg, 1, mac); +} + +static inline bool bt_mesh_s1(const char *m, u8_t salt[16]) +{ + const u8_t zero[16] = { 0 }; + + return bt_mesh_aes_cmac_one(zero, m, strlen(m), salt); +} + +int bt_mesh_k1(const u8_t *ikm, size_t ikm_len, const u8_t salt[16], + const char *info, u8_t okm[16]); + +#define bt_mesh_k1_str(ikm, ikm_len, salt_str, info, okm) \ +({ \ + const u8_t salt[16] = salt_str; \ + bt_mesh_k1(ikm, ikm_len, salt, info, okm); \ +}) + +int bt_mesh_k2(const u8_t n[16], const u8_t *p, size_t p_len, + u8_t net_id[1], u8_t enc_key[16], u8_t priv_key[16]); + +int bt_mesh_k3(const u8_t n[16], u8_t out[8]); + +int bt_mesh_k4(const u8_t n[16], u8_t out[1]); + +int bt_mesh_id128(const u8_t n[16], const char *s, u8_t out[16]); + +static inline int bt_mesh_id_resolving_key(const u8_t net_key[16], + u8_t resolving_key[16]) +{ + return bt_mesh_k1_str(net_key, 16, "smbt", "smbi", resolving_key); +} + +static inline int bt_mesh_identity_key(const u8_t net_key[16], + u8_t identity_key[16]) +{ + return bt_mesh_id128(net_key, "nkik", identity_key); +} + +static inline int bt_mesh_beacon_key(const u8_t net_key[16], + u8_t beacon_key[16]) +{ + return bt_mesh_id128(net_key, "nkbk", beacon_key); +} + +int bt_mesh_beacon_auth(const u8_t beacon_key[16], u8_t flags, + const u8_t net_id[16], u32_t iv_index, + u8_t auth[8]); + +static inline int bt_mesh_app_id(const u8_t app_key[16], u8_t app_id[1]) +{ + return bt_mesh_k4(app_key, app_id); +} + +static inline int bt_mesh_session_key(const u8_t dhkey[32], + const u8_t prov_salt[16], + u8_t session_key[16]) +{ + return bt_mesh_k1(dhkey, 32, prov_salt, "prsk", session_key); +} + +static inline int bt_mesh_prov_nonce(const u8_t dhkey[32], + const u8_t prov_salt[16], + u8_t nonce[13]) +{ + u8_t tmp[16]; + int err; + + err = bt_mesh_k1(dhkey, 32, prov_salt, "prsn", tmp); + if (!err) { + memcpy(nonce, tmp + 3, 13); + } + + return err; +} + +static inline int bt_mesh_dev_key(const u8_t dhkey[32], + const u8_t prov_salt[16], + u8_t dev_key[16]) +{ + return bt_mesh_k1(dhkey, 32, prov_salt, "prdk", dev_key); +} + +static inline int bt_mesh_prov_salt(const u8_t conf_salt[16], + const u8_t prov_rand[16], + const u8_t dev_rand[16], + u8_t prov_salt[16]) +{ + const u8_t prov_salt_key[16] = { 0 }; + struct bt_mesh_sg sg[] = { + { conf_salt, 16 }, + { prov_rand, 16 }, + { dev_rand, 16 }, + }; + + return bt_mesh_aes_cmac(prov_salt_key, sg, ARRAY_SIZE(sg), prov_salt); +} + +int bt_mesh_net_obfuscate(u8_t *pdu, u32_t iv_index, + const u8_t privacy_key[16]); + +int bt_mesh_net_encrypt(const u8_t key[16], struct net_buf_simple *buf, + u32_t iv_index, bool proxy); + +int bt_mesh_net_decrypt(const u8_t key[16], struct net_buf_simple *buf, + u32_t iv_index, bool proxy); + +int bt_mesh_app_encrypt(const u8_t key[16], bool dev_key, u8_t aszmic, + struct net_buf_simple *buf, const u8_t *ad, + u16_t src, u16_t dst, u32_t seq_num, u32_t iv_index); + +int bt_mesh_app_decrypt(const u8_t key[16], bool dev_key, u8_t aszmic, + struct net_buf_simple *buf, struct net_buf_simple *out, + const u8_t *ad, u16_t src, u16_t dst, u32_t seq_num, + u32_t iv_index); + +u8_t bt_mesh_fcs_calc(const u8_t *data, u8_t data_len); + +bool bt_mesh_fcs_check(struct net_buf_simple *buf, u8_t received_fcs); + +int bt_mesh_virtual_addr(const u8_t virtual_label[16], u16_t *addr); + +int bt_mesh_prov_conf_salt(const u8_t conf_inputs[145], u8_t salt[16]); + +int bt_mesh_prov_conf_key(const u8_t dhkey[32], const u8_t conf_salt[16], + u8_t conf_key[16]); + +int bt_mesh_prov_conf(const u8_t conf_key[16], const u8_t rand[16], + const u8_t auth[16], u8_t conf[16]); + +int bt_mesh_prov_decrypt(const u8_t key[16], u8_t nonce[13], + const u8_t data[25 + 8], u8_t out[25]); + +int bt_mesh_prov_encrypt(const u8_t key[16], u8_t nonce[13], + const u8_t data[25], u8_t out[33]); + +#endif /* _CRYPTO_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/foundation.h b/components/bt/ble_mesh/mesh_core/foundation.h new file mode 100644 index 0000000000..d1ccd31ae4 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/foundation.h @@ -0,0 +1,166 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _FOUNDATION_H_ +#define _FOUNDATION_H_ + +#include "mesh_access.h" +#include "net.h" + +#define OP_APP_KEY_ADD BLE_MESH_MODEL_OP_1(0x00) +#define OP_APP_KEY_UPDATE BLE_MESH_MODEL_OP_1(0x01) +#define OP_DEV_COMP_DATA_STATUS BLE_MESH_MODEL_OP_1(0x02) +#define OP_MOD_PUB_SET BLE_MESH_MODEL_OP_1(0x03) +#define OP_HEALTH_CURRENT_STATUS BLE_MESH_MODEL_OP_1(0x04) +#define OP_HEALTH_FAULT_STATUS BLE_MESH_MODEL_OP_1(0x05) +#define OP_HEARTBEAT_PUB_STATUS BLE_MESH_MODEL_OP_1(0x06) +#define OP_APP_KEY_DEL BLE_MESH_MODEL_OP_2(0x80, 0x00) +#define OP_APP_KEY_GET BLE_MESH_MODEL_OP_2(0x80, 0x01) +#define OP_APP_KEY_LIST BLE_MESH_MODEL_OP_2(0x80, 0x02) +#define OP_APP_KEY_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x03) +#define OP_ATTENTION_GET BLE_MESH_MODEL_OP_2(0x80, 0x04) +#define OP_ATTENTION_SET BLE_MESH_MODEL_OP_2(0x80, 0x05) +#define OP_ATTENTION_SET_UNREL BLE_MESH_MODEL_OP_2(0x80, 0x06) +#define OP_ATTENTION_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x07) +#define OP_DEV_COMP_DATA_GET BLE_MESH_MODEL_OP_2(0x80, 0x08) +#define OP_BEACON_GET BLE_MESH_MODEL_OP_2(0x80, 0x09) +#define OP_BEACON_SET BLE_MESH_MODEL_OP_2(0x80, 0x0a) +#define OP_BEACON_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x0b) +#define OP_DEFAULT_TTL_GET BLE_MESH_MODEL_OP_2(0x80, 0x0c) +#define OP_DEFAULT_TTL_SET BLE_MESH_MODEL_OP_2(0x80, 0x0d) +#define OP_DEFAULT_TTL_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x0e) +#define OP_FRIEND_GET BLE_MESH_MODEL_OP_2(0x80, 0x0f) +#define OP_FRIEND_SET BLE_MESH_MODEL_OP_2(0x80, 0x10) +#define OP_FRIEND_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x11) +#define OP_GATT_PROXY_GET BLE_MESH_MODEL_OP_2(0x80, 0x12) +#define OP_GATT_PROXY_SET BLE_MESH_MODEL_OP_2(0x80, 0x13) +#define OP_GATT_PROXY_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x14) +#define OP_KRP_GET BLE_MESH_MODEL_OP_2(0x80, 0x15) +#define OP_KRP_SET BLE_MESH_MODEL_OP_2(0x80, 0x16) +#define OP_KRP_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x17) +#define OP_MOD_PUB_GET BLE_MESH_MODEL_OP_2(0x80, 0x18) +#define OP_MOD_PUB_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x19) +#define OP_MOD_PUB_VA_SET BLE_MESH_MODEL_OP_2(0x80, 0x1a) +#define OP_MOD_SUB_ADD BLE_MESH_MODEL_OP_2(0x80, 0x1b) +#define OP_MOD_SUB_DEL BLE_MESH_MODEL_OP_2(0x80, 0x1c) +#define OP_MOD_SUB_DEL_ALL BLE_MESH_MODEL_OP_2(0x80, 0x1d) +#define OP_MOD_SUB_OVERWRITE BLE_MESH_MODEL_OP_2(0x80, 0x1e) +#define OP_MOD_SUB_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x1f) +#define OP_MOD_SUB_VA_ADD BLE_MESH_MODEL_OP_2(0x80, 0x20) +#define OP_MOD_SUB_VA_DEL BLE_MESH_MODEL_OP_2(0x80, 0x21) +#define OP_MOD_SUB_VA_OVERWRITE BLE_MESH_MODEL_OP_2(0x80, 0x22) +#define OP_NET_TRANSMIT_GET BLE_MESH_MODEL_OP_2(0x80, 0x23) +#define OP_NET_TRANSMIT_SET BLE_MESH_MODEL_OP_2(0x80, 0x24) +#define OP_NET_TRANSMIT_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x25) +#define OP_RELAY_GET BLE_MESH_MODEL_OP_2(0x80, 0x26) +#define OP_RELAY_SET BLE_MESH_MODEL_OP_2(0x80, 0x27) +#define OP_RELAY_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x28) +#define OP_MOD_SUB_GET BLE_MESH_MODEL_OP_2(0x80, 0x29) +#define OP_MOD_SUB_LIST BLE_MESH_MODEL_OP_2(0x80, 0x2a) +#define OP_MOD_SUB_GET_VND BLE_MESH_MODEL_OP_2(0x80, 0x2b) +#define OP_MOD_SUB_LIST_VND BLE_MESH_MODEL_OP_2(0x80, 0x2c) +#define OP_LPN_TIMEOUT_GET BLE_MESH_MODEL_OP_2(0x80, 0x2d) +#define OP_LPN_TIMEOUT_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x2e) +#define OP_HEALTH_FAULT_CLEAR BLE_MESH_MODEL_OP_2(0x80, 0x2f) +#define OP_HEALTH_FAULT_CLEAR_UNREL BLE_MESH_MODEL_OP_2(0x80, 0x30) +#define OP_HEALTH_FAULT_GET BLE_MESH_MODEL_OP_2(0x80, 0x31) +#define OP_HEALTH_FAULT_TEST BLE_MESH_MODEL_OP_2(0x80, 0x32) +#define OP_HEALTH_FAULT_TEST_UNREL BLE_MESH_MODEL_OP_2(0x80, 0x33) +#define OP_HEALTH_PERIOD_GET BLE_MESH_MODEL_OP_2(0x80, 0x34) +#define OP_HEALTH_PERIOD_SET BLE_MESH_MODEL_OP_2(0x80, 0x35) +#define OP_HEALTH_PERIOD_SET_UNREL BLE_MESH_MODEL_OP_2(0x80, 0x36) +#define OP_HEALTH_PERIOD_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x37) +#define OP_HEARTBEAT_PUB_GET BLE_MESH_MODEL_OP_2(0x80, 0x38) +#define OP_HEARTBEAT_PUB_SET BLE_MESH_MODEL_OP_2(0x80, 0x39) +#define OP_HEARTBEAT_SUB_GET BLE_MESH_MODEL_OP_2(0x80, 0x3a) +#define OP_HEARTBEAT_SUB_SET BLE_MESH_MODEL_OP_2(0x80, 0x3b) +#define OP_HEARTBEAT_SUB_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x3c) +#define OP_MOD_APP_BIND BLE_MESH_MODEL_OP_2(0x80, 0x3d) +#define OP_MOD_APP_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x3e) +#define OP_MOD_APP_UNBIND BLE_MESH_MODEL_OP_2(0x80, 0x3f) +#define OP_NET_KEY_ADD BLE_MESH_MODEL_OP_2(0x80, 0x40) +#define OP_NET_KEY_DEL BLE_MESH_MODEL_OP_2(0x80, 0x41) +#define OP_NET_KEY_GET BLE_MESH_MODEL_OP_2(0x80, 0x42) +#define OP_NET_KEY_LIST BLE_MESH_MODEL_OP_2(0x80, 0x43) +#define OP_NET_KEY_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x44) +#define OP_NET_KEY_UPDATE BLE_MESH_MODEL_OP_2(0x80, 0x45) +#define OP_NODE_IDENTITY_GET BLE_MESH_MODEL_OP_2(0x80, 0x46) +#define OP_NODE_IDENTITY_SET BLE_MESH_MODEL_OP_2(0x80, 0x47) +#define OP_NODE_IDENTITY_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x48) +#define OP_NODE_RESET BLE_MESH_MODEL_OP_2(0x80, 0x49) +#define OP_NODE_RESET_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x4a) +#define OP_SIG_MOD_APP_GET BLE_MESH_MODEL_OP_2(0x80, 0x4b) +#define OP_SIG_MOD_APP_LIST BLE_MESH_MODEL_OP_2(0x80, 0x4c) +#define OP_VND_MOD_APP_GET BLE_MESH_MODEL_OP_2(0x80, 0x4d) +#define OP_VND_MOD_APP_LIST BLE_MESH_MODEL_OP_2(0x80, 0x4e) + +#define STATUS_SUCCESS 0x00 +#define STATUS_INVALID_ADDRESS 0x01 +#define STATUS_INVALID_MODEL 0x02 +#define STATUS_INVALID_APPKEY 0x03 +#define STATUS_INVALID_NETKEY 0x04 +#define STATUS_INSUFF_RESOURCES 0x05 +#define STATUS_IDX_ALREADY_STORED 0x06 +#define STATUS_NVAL_PUB_PARAM 0x07 +#define STATUS_NOT_SUB_MOD 0x08 +#define STATUS_STORAGE_FAIL 0x09 +#define STATUS_FEAT_NOT_SUPP 0x0a +#define STATUS_CANNOT_UPDATE 0x0b +#define STATUS_CANNOT_REMOVE 0x0c +#define STATUS_CANNOT_BIND 0x0d +#define STATUS_TEMP_STATE_CHG_FAIL 0x0e +#define STATUS_CANNOT_SET 0x0f +#define STATUS_UNSPECIFIED 0x10 +#define STATUS_INVALID_BINDING 0x11 + +int bt_mesh_cfg_srv_init(struct bt_mesh_model *model, bool primary); +int bt_mesh_health_srv_init(struct bt_mesh_model *model, bool primary); + +int bt_mesh_cfg_cli_init(struct bt_mesh_model *model, bool primary); +int bt_mesh_health_cli_init(struct bt_mesh_model *model, bool primary); + +void bt_mesh_cfg_reset(void); + +void bt_mesh_heartbeat(u16_t src, u16_t dst, u8_t hops, u16_t feat); + +void bt_mesh_attention(struct bt_mesh_model *model, u8_t time); + +u8_t *bt_mesh_label_uuid_get(u16_t addr); + +struct bt_mesh_hb_pub *bt_mesh_hb_pub_get(void); +void bt_mesh_hb_pub_disable(void); +struct bt_mesh_cfg_srv *bt_mesh_cfg_get(void); + +u8_t bt_mesh_net_transmit_get(void); +u8_t bt_mesh_relay_get(void); +u8_t bt_mesh_friend_get(void); +u8_t bt_mesh_relay_retransmit_get(void); +u8_t bt_mesh_beacon_get(void); +u8_t bt_mesh_gatt_proxy_get(void); +u8_t bt_mesh_default_ttl_get(void); + +void bt_mesh_subnet_del(struct bt_mesh_subnet *sub, bool store); + +struct bt_mesh_app_key *bt_mesh_app_key_alloc(u16_t app_idx); +void bt_mesh_app_key_del(struct bt_mesh_app_key *key, bool store); + +static inline void key_idx_pack(struct net_buf_simple *buf, + u16_t idx1, u16_t idx2) +{ + net_buf_simple_add_le16(buf, idx1 | ((idx2 & 0x00f) << 12)); + net_buf_simple_add_u8(buf, idx2 >> 4); +} + +static inline void key_idx_unpack(struct net_buf_simple *buf, + u16_t *idx1, u16_t *idx2) +{ + *idx1 = sys_get_le16(&buf->data[0]) & 0xfff; + *idx2 = sys_get_le16(&buf->data[1]) >> 4; + net_buf_simple_pull(buf, 3); +} + +#endif /* _FOUNDATION_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/friend.c b/components/bt/ble_mesh/mesh_core/friend.c new file mode 100644 index 0000000000..b47e86fe81 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/friend.c @@ -0,0 +1,1326 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "sdkconfig.h" +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BLE_MESH_DEBUG_FRIEND) + +#include "mesh_buf.h" +#include "mesh_util.h" +#include "mesh_main.h" +#include "mesh_trace.h" + +#include "crypto.h" +#include "adv.h" +#include "mesh.h" +#include "net.h" +#include "transport.h" +#include "access.h" +#include "foundation.h" +#include "friend.h" + +#ifdef CONFIG_BLE_MESH_FRIEND + +#define FRIEND_BUF_SIZE (BLE_MESH_ADV_DATA_SIZE - BLE_MESH_NET_HDR_LEN) + +/* We reserve one extra buffer for each friendship, since we need to be able + * to resend the last sent PDU, which sits separately outside of the queue. + */ +#define FRIEND_BUF_COUNT ((CONFIG_BLE_MESH_FRIEND_QUEUE_SIZE + 1) * \ + CONFIG_BLE_MESH_FRIEND_LPN_COUNT) + +#define FRIEND_ADV(buf) CONTAINER_OF(BLE_MESH_ADV(buf), \ + struct friend_adv, adv) + +/* PDUs from Friend to the LPN should only be transmitted once with the + * smallest possible interval (20ms). + */ +#define FRIEND_XMIT BLE_MESH_TRANSMIT(0, 20) + +struct friend_pdu_info { + u16_t src; + u16_t dst; + + u8_t seq[3]; + + u8_t ttl: 7, + ctl: 1; + + u32_t iv_index; +}; + +NET_BUF_POOL_FIXED_DEFINE(friend_buf_pool, FRIEND_BUF_COUNT, + BLE_MESH_ADV_DATA_SIZE, NULL); + +static struct friend_adv { + struct bt_mesh_adv adv; + u64_t seq_auth; +} adv_pool[FRIEND_BUF_COUNT]; + +static struct bt_mesh_adv *adv_alloc(int id) +{ + return &adv_pool[id].adv; +} + +static void discard_buffer(void) +{ + struct bt_mesh_friend *frnd = &bt_mesh.frnd[0]; + struct net_buf *buf; + int i; + + /* Find the Friend context with the most queued buffers */ + for (i = 1; i < ARRAY_SIZE(bt_mesh.frnd); i++) { + if (bt_mesh.frnd[i].queue_size > frnd->queue_size) { + frnd = &bt_mesh.frnd[i]; + } + } + + buf = net_buf_slist_get(&frnd->queue); + __ASSERT_NO_MSG(buf != NULL); + BT_WARN("Discarding buffer %p for LPN 0x%04x", buf, frnd->lpn); + net_buf_unref(buf); +} + +static struct net_buf *friend_buf_alloc(u16_t src) +{ + struct net_buf *buf; + + BT_DBG("src 0x%04x", src); + + do { + buf = bt_mesh_adv_create_from_pool(&friend_buf_pool, adv_alloc, + BLE_MESH_ADV_DATA, + FRIEND_XMIT, K_NO_WAIT); + if (!buf) { + discard_buffer(); + } + } while (!buf); + + BLE_MESH_ADV(buf)->addr = src; + FRIEND_ADV(buf)->seq_auth = TRANS_SEQ_AUTH_NVAL; + + BT_DBG("allocated buf %p", buf); + + return buf; +} + +static bool is_lpn_unicast(struct bt_mesh_friend *frnd, u16_t addr) +{ + if (frnd->lpn == BLE_MESH_ADDR_UNASSIGNED) { + return false; + } + + return (addr >= frnd->lpn && addr < (frnd->lpn + frnd->num_elem)); +} + +struct bt_mesh_friend *bt_mesh_friend_find(u16_t net_idx, u16_t lpn_addr, + bool valid, bool established) +{ + int i; + + BT_DBG("net_idx 0x%04x lpn_addr 0x%04x", net_idx, lpn_addr); + + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { + struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; + + if (valid && !frnd->valid) { + continue; + } + + if (established && !frnd->established) { + continue; + } + + if (net_idx != BLE_MESH_KEY_ANY && frnd->net_idx != net_idx) { + continue; + } + + if (is_lpn_unicast(frnd, lpn_addr)) { + return frnd; + } + } + + return NULL; +} + +/* Intentionally start a little bit late into the ReceiveWindow when + * it's large enough. This may improve reliability with some platforms, + * like the PTS, where the receiver might not have sufficiently compensated + * for internal latencies required to start scanning. + */ +static s32_t recv_delay(struct bt_mesh_friend *frnd) +{ +#if CONFIG_BLE_MESH_FRIEND_RECV_WIN > 50 + return (s32_t)frnd->recv_delay + (CONFIG_BLE_MESH_FRIEND_RECV_WIN / 5); +#else + return frnd->recv_delay; +#endif +} + +static void friend_clear(struct bt_mesh_friend *frnd) +{ + int i; + + BT_DBG("LPN 0x%04x", frnd->lpn); + + k_delayed_work_cancel(&frnd->timer); + + friend_cred_del(frnd->net_idx, frnd->lpn); + + if (frnd->last) { + /* Cancel the sending if necessary */ + if (frnd->pending_buf) { + BLE_MESH_ADV(frnd->last)->busy = 0U; + } + + net_buf_unref(frnd->last); + frnd->last = NULL; + } + + while (!sys_slist_is_empty(&frnd->queue)) { + net_buf_unref(net_buf_slist_get(&frnd->queue)); + } + + for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) { + struct bt_mesh_friend_seg *seg = &frnd->seg[i]; + + while (!sys_slist_is_empty(&seg->queue)) { + net_buf_unref(net_buf_slist_get(&seg->queue)); + } + } + + frnd->valid = 0U; + frnd->established = 0U; + frnd->pending_buf = 0U; + frnd->fsn = 0U; + frnd->queue_size = 0U; + frnd->pending_req = 0U; + (void)memset(frnd->sub_list, 0, sizeof(frnd->sub_list)); +} + +void bt_mesh_friend_clear_net_idx(u16_t net_idx) +{ + int i; + + BT_DBG("net_idx 0x%04x", net_idx); + + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { + struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; + + if (frnd->net_idx == BLE_MESH_KEY_UNUSED) { + continue; + } + + if (net_idx == BLE_MESH_KEY_ANY || frnd->net_idx == net_idx) { + friend_clear(frnd); + } + } +} + +void bt_mesh_friend_sec_update(u16_t net_idx) +{ + int i; + + BT_DBG("net_idx 0x%04x", net_idx); + + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { + struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; + + if (frnd->net_idx == BLE_MESH_KEY_UNUSED) { + continue; + } + + if (net_idx == BLE_MESH_KEY_ANY || frnd->net_idx == net_idx) { + frnd->sec_update = 1U; + } + } +} + +int bt_mesh_friend_clear(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) +{ + struct bt_mesh_ctl_friend_clear *msg = (void *)buf->data; + struct bt_mesh_friend *frnd; + u16_t lpn_addr, lpn_counter; + struct bt_mesh_net_tx tx = { + .sub = rx->sub, + .ctx = &rx->ctx, + .src = bt_mesh_primary_addr(), + .xmit = bt_mesh_net_transmit_get(), + }; + struct bt_mesh_ctl_friend_clear_confirm cfm; + + if (buf->len < sizeof(*msg)) { + BT_WARN("%s, Too short Friend Clear", __func__); + return -EINVAL; + } + + lpn_addr = sys_be16_to_cpu(msg->lpn_addr); + lpn_counter = sys_be16_to_cpu(msg->lpn_counter); + + BT_DBG("LPN addr 0x%04x counter 0x%04x", lpn_addr, lpn_counter); + + frnd = bt_mesh_friend_find(rx->sub->net_idx, lpn_addr, false, false); + if (!frnd) { + BT_WARN("%s, No matching LPN addr 0x%04x", __func__, lpn_addr); + return 0; + } + + /* A Friend Clear message is considered valid if the result of the + * subtraction of the value of the LPNCounter field of the Friend + * Request message (the one that initiated the friendship) from the + * value of the LPNCounter field of the Friend Clear message, modulo + * 65536, is in the range 0 to 255 inclusive. + */ + if (lpn_counter - frnd->lpn_counter > 255) { + BT_WARN("%s, LPN Counter out of range (old %u new %u)", + __func__, frnd->lpn_counter, lpn_counter); + return 0; + } + + tx.ctx->send_ttl = BLE_MESH_TTL_MAX; + + cfm.lpn_addr = msg->lpn_addr; + cfm.lpn_counter = msg->lpn_counter; + + bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_CLEAR_CFM, &cfm, + sizeof(cfm), NULL, NULL, NULL); + + friend_clear(frnd); + + return 0; +} + +static void friend_sub_add(struct bt_mesh_friend *frnd, u16_t addr) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) { + if (frnd->sub_list[i] == BLE_MESH_ADDR_UNASSIGNED) { + frnd->sub_list[i] = addr; + return; + } + } + + BT_WARN("%s, No space in friend subscription list", __func__); +} + +static void friend_sub_rem(struct bt_mesh_friend *frnd, u16_t addr) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) { + if (frnd->sub_list[i] == addr) { + frnd->sub_list[i] = BLE_MESH_ADDR_UNASSIGNED; + return; + } + } +} + +static struct net_buf *create_friend_pdu(struct bt_mesh_friend *frnd, + struct friend_pdu_info *info, + struct net_buf_simple *sdu) +{ + struct bt_mesh_subnet *sub; + const u8_t *enc, *priv; + struct net_buf *buf; + u8_t nid; + + sub = bt_mesh_subnet_get(frnd->net_idx); + __ASSERT_NO_MSG(sub != NULL); + + buf = friend_buf_alloc(info->src); + + /* Friend Offer needs master security credentials */ + if (info->ctl && TRANS_CTL_OP(sdu->data) == TRANS_CTL_OP_FRIEND_OFFER) { + enc = sub->keys[sub->kr_flag].enc; + priv = sub->keys[sub->kr_flag].privacy; + nid = sub->keys[sub->kr_flag].nid; + } else { + if (friend_cred_get(sub, frnd->lpn, &nid, &enc, &priv)) { + BT_ERR("%s, friend_cred_get failed", __func__); + goto failed; + } + } + + net_buf_add_u8(buf, (nid | (info->iv_index & 1) << 7)); + + if (info->ctl) { + net_buf_add_u8(buf, info->ttl | 0x80); + } else { + net_buf_add_u8(buf, info->ttl); + } + + net_buf_add_mem(buf, info->seq, sizeof(info->seq)); + + net_buf_add_be16(buf, info->src); + net_buf_add_be16(buf, info->dst); + + net_buf_add_mem(buf, sdu->data, sdu->len); + + /* We re-encrypt and obfuscate using the received IVI rather than + * the normal TX IVI (which may be different) since the transport + * layer nonce includes the IVI. + */ + if (bt_mesh_net_encrypt(enc, &buf->b, info->iv_index, false)) { + BT_ERR("%s, Re-encrypting failed", __func__); + goto failed; + } + + if (bt_mesh_net_obfuscate(buf->data, info->iv_index, priv)) { + BT_ERR("%s, Re-obfuscating failed", __func__); + goto failed; + } + + return buf; + +failed: + net_buf_unref(buf); + return NULL; +} + +static struct net_buf *encode_friend_ctl(struct bt_mesh_friend *frnd, + u8_t ctl_op, + struct net_buf_simple *sdu) +{ + struct friend_pdu_info info; + u32_t seq; + + BT_DBG("LPN 0x%04x", frnd->lpn); + + net_buf_simple_push_u8(sdu, TRANS_CTL_HDR(ctl_op, 0)); + + info.src = bt_mesh_primary_addr(); + info.dst = frnd->lpn; + + info.ctl = 1U; + info.ttl = 0U; + + seq = bt_mesh_next_seq(); + info.seq[0] = seq >> 16; + info.seq[1] = seq >> 8; + info.seq[2] = seq; + + info.iv_index = BLE_MESH_NET_IVI_TX; + + return create_friend_pdu(frnd, &info, sdu); +} + +static struct net_buf *encode_update(struct bt_mesh_friend *frnd, u8_t md) +{ + struct bt_mesh_ctl_friend_update *upd; + NET_BUF_SIMPLE_DEFINE(sdu, 1 + sizeof(*upd)); + struct bt_mesh_subnet *sub = bt_mesh_subnet_get(frnd->net_idx); + + __ASSERT_NO_MSG(sub != NULL); + + BT_DBG("lpn 0x%04x md 0x%02x", frnd->lpn, md); + + net_buf_simple_reserve(&sdu, 1); + + upd = net_buf_simple_add(&sdu, sizeof(*upd)); + upd->flags = bt_mesh_net_flags(sub); + upd->iv_index = sys_cpu_to_be32(bt_mesh.iv_index); + upd->md = md; + + return encode_friend_ctl(frnd, TRANS_CTL_OP_FRIEND_UPDATE, &sdu); +} + +static void enqueue_sub_cfm(struct bt_mesh_friend *frnd, u8_t xact) +{ + struct bt_mesh_ctl_friend_sub_confirm *cfm; + NET_BUF_SIMPLE_DEFINE(sdu, 1 + sizeof(*cfm)); + struct net_buf *buf; + + BT_DBG("lpn 0x%04x xact 0x%02x", frnd->lpn, xact); + + net_buf_simple_reserve(&sdu, 1); + + cfm = net_buf_simple_add(&sdu, sizeof(*cfm)); + cfm->xact = xact; + + buf = encode_friend_ctl(frnd, TRANS_CTL_OP_FRIEND_SUB_CFM, &sdu); + if (!buf) { + BT_ERR("%s, Unable to encode Subscription List Confirmation", __func__); + return; + } + + if (frnd->last) { + BT_DBG("Discarding last PDU"); + net_buf_unref(frnd->last); + } + + frnd->last = buf; + frnd->send_last = 1U; +} + +static void friend_recv_delay(struct bt_mesh_friend *frnd) +{ + frnd->pending_req = 1U; + k_delayed_work_submit(&frnd->timer, recv_delay(frnd)); + BT_DBG("Waiting RecvDelay of %d ms", recv_delay(frnd)); +} + +int bt_mesh_friend_sub_add(struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf) +{ + struct bt_mesh_friend *frnd; + u8_t xact; + + if (buf->len < BLE_MESH_FRIEND_SUB_MIN_LEN) { + BT_WARN("%s, Too short Friend Subscription Add", __func__); + return -EINVAL; + } + + frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, true); + if (!frnd) { + BT_WARN("%s, No matching LPN addr 0x%04x", __func__, rx->ctx.addr); + return 0; + } + + if (frnd->pending_buf) { + BT_WARN("%s, Previous buffer not yet sent!", __func__); + return 0; + } + + friend_recv_delay(frnd); + + xact = net_buf_simple_pull_u8(buf); + + while (buf->len >= 2U) { + friend_sub_add(frnd, net_buf_simple_pull_be16(buf)); + } + + enqueue_sub_cfm(frnd, xact); + + return 0; +} + +int bt_mesh_friend_sub_rem(struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf) +{ + struct bt_mesh_friend *frnd; + u8_t xact; + + if (buf->len < BLE_MESH_FRIEND_SUB_MIN_LEN) { + BT_WARN("%s, Too short Friend Subscription Remove", __func__); + return -EINVAL; + } + + frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, true); + if (!frnd) { + BT_WARN("%s, No matching LPN addr 0x%04x", __func__, rx->ctx.addr); + return 0; + } + + if (frnd->pending_buf) { + BT_WARN("%s, Previous buffer not yet sent!", __func__); + return 0; + } + + friend_recv_delay(frnd); + + xact = net_buf_simple_pull_u8(buf); + + while (buf->len >= 2U) { + friend_sub_rem(frnd, net_buf_simple_pull_be16(buf)); + } + + enqueue_sub_cfm(frnd, xact); + + return 0; +} + +static void enqueue_buf(struct bt_mesh_friend *frnd, struct net_buf *buf) +{ + net_buf_slist_put(&frnd->queue, buf); + frnd->queue_size++; +} + +static void enqueue_update(struct bt_mesh_friend *frnd, u8_t md) +{ + struct net_buf *buf; + + buf = encode_update(frnd, md); + if (!buf) { + BT_ERR("%s, Unable to encode Friend Update", __func__); + return; + } + + frnd->sec_update = 0U; + enqueue_buf(frnd, buf); +} + +int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) +{ + struct bt_mesh_ctl_friend_poll *msg = (void *)buf->data; + struct bt_mesh_friend *frnd; + + if (buf->len < sizeof(*msg)) { + BT_WARN("%s, Too short Friend Poll", __func__); + return -EINVAL; + } + + frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, false); + if (!frnd) { + BT_WARN("%s, No matching LPN addr 0x%04x", __func__, rx->ctx.addr); + return 0; + } + + if (msg->fsn & ~1) { + BT_WARN("%s, Prohibited (non-zero) padding bits", __func__); + return -EINVAL; + } + + if (frnd->pending_buf) { + BT_WARN("%s, Previous buffer not yet sent!", __func__); + return 0; + } + + BT_DBG("msg->fsn %u frnd->fsn %u", (msg->fsn & 1), frnd->fsn); + + friend_recv_delay(frnd); + + if (!frnd->established) { + BT_DBG("Friendship established with 0x%04x", frnd->lpn); + frnd->established = 1U; + } + + if (msg->fsn == frnd->fsn && frnd->last) { + BT_DBG("Re-sending last PDU"); + frnd->send_last = 1U; + } else { + if (frnd->last) { + net_buf_unref(frnd->last); + frnd->last = NULL; + } + + frnd->fsn = msg->fsn; + + if (sys_slist_is_empty(&frnd->queue)) { + enqueue_update(frnd, 0); + BT_DBG("Enqueued Friend Update to empty queue"); + } + } + + return 0; +} + +static struct bt_mesh_friend *find_clear(u16_t prev_friend) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { + struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; + + if (frnd->clear.frnd == prev_friend) { + return frnd; + } + } + + return NULL; +} + +static void friend_clear_sent(int err, void *user_data) +{ + struct bt_mesh_friend *frnd = user_data; + + k_delayed_work_submit(&frnd->clear.timer, + K_SECONDS(frnd->clear.repeat_sec)); + frnd->clear.repeat_sec *= 2U; +} + +static const struct bt_mesh_send_cb clear_sent_cb = { + .end = friend_clear_sent, +}; + +static void send_friend_clear(struct bt_mesh_friend *frnd) +{ + struct bt_mesh_msg_ctx ctx = { + .net_idx = frnd->net_idx, + .app_idx = BLE_MESH_KEY_UNUSED, + .addr = frnd->clear.frnd, + .send_ttl = BLE_MESH_TTL_MAX, + }; + struct bt_mesh_net_tx tx = { + .sub = &bt_mesh.sub[0], + .ctx = &ctx, + .src = bt_mesh_primary_addr(), + .xmit = bt_mesh_net_transmit_get(), + }; + struct bt_mesh_ctl_friend_clear req = { + .lpn_addr = sys_cpu_to_be16(frnd->lpn), + .lpn_counter = sys_cpu_to_be16(frnd->lpn_counter), + }; + + BT_DBG("%s", __func__); + + bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_CLEAR, &req, + sizeof(req), NULL, &clear_sent_cb, frnd); +} + +static void clear_timeout(struct k_work *work) +{ + struct bt_mesh_friend *frnd = CONTAINER_OF(work, struct bt_mesh_friend, + clear.timer.work); + u32_t duration; + + BT_DBG("LPN 0x%04x (old) Friend 0x%04x", frnd->lpn, frnd->clear.frnd); + + duration = k_uptime_get_32() - frnd->clear.start; + if (duration > 2 * frnd->poll_to) { + BT_DBG("Clear Procedure timer expired"); + frnd->clear.frnd = BLE_MESH_ADDR_UNASSIGNED; + return; + } + + send_friend_clear(frnd); +} + +static void clear_procedure_start(struct bt_mesh_friend *frnd) +{ + BT_DBG("LPN 0x%04x (old) Friend 0x%04x", frnd->lpn, frnd->clear.frnd); + + frnd->clear.start = k_uptime_get_32() + (2 * frnd->poll_to); + frnd->clear.repeat_sec = 1U; + + send_friend_clear(frnd); +} + +int bt_mesh_friend_clear_cfm(struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf) +{ + struct bt_mesh_ctl_friend_clear_confirm *msg = (void *)buf->data; + struct bt_mesh_friend *frnd; + u16_t lpn_addr, lpn_counter; + + BT_DBG("%s", __func__); + + if (buf->len < sizeof(*msg)) { + BT_WARN("%s, Too short Friend Clear Confirm", __func__); + return -EINVAL; + } + + frnd = find_clear(rx->ctx.addr); + if (!frnd) { + BT_WARN("%s, No pending clear procedure for 0x%02x", __func__, rx->ctx.addr); + return 0; + } + + lpn_addr = sys_be16_to_cpu(msg->lpn_addr); + if (lpn_addr != frnd->lpn) { + BT_WARN("%s, LPN address mismatch (0x%04x != 0x%04x)", + __func__, lpn_addr, frnd->lpn); + return 0; + } + + lpn_counter = sys_be16_to_cpu(msg->lpn_counter); + if (lpn_counter != frnd->lpn_counter) { + BT_WARN("%s, LPN counter mismatch (0x%04x != 0x%04x)", + __func__, lpn_counter, frnd->lpn_counter); + return 0; + } + + k_delayed_work_cancel(&frnd->clear.timer); + frnd->clear.frnd = BLE_MESH_ADDR_UNASSIGNED; + + return 0; +} + +static void enqueue_offer(struct bt_mesh_friend *frnd, s8_t rssi) +{ + struct bt_mesh_ctl_friend_offer *off; + NET_BUF_SIMPLE_DEFINE(sdu, 1 + sizeof(*off)); + struct net_buf *buf; + + BT_DBG("%s", __func__); + + net_buf_simple_reserve(&sdu, 1); + + off = net_buf_simple_add(&sdu, sizeof(*off)); + + off->recv_win = CONFIG_BLE_MESH_FRIEND_RECV_WIN, + off->queue_size = CONFIG_BLE_MESH_FRIEND_QUEUE_SIZE, + off->sub_list_size = ARRAY_SIZE(frnd->sub_list), + off->rssi = rssi, + off->frnd_counter = sys_cpu_to_be16(frnd->counter); + + buf = encode_friend_ctl(frnd, TRANS_CTL_OP_FRIEND_OFFER, &sdu); + if (!buf) { + BT_ERR("%s, Unable to encode Friend Offer", __func__); + return; + } + + frnd->counter++; + + if (frnd->last) { + net_buf_unref(frnd->last); + } + + frnd->last = buf; + frnd->send_last = 1U; +} + +#define RECV_WIN CONFIG_BLE_MESH_FRIEND_RECV_WIN +#define RSSI_FACT(crit) (((crit) >> 5) & (u8_t)BIT_MASK(2)) +#define RECV_WIN_FACT(crit) (((crit) >> 3) & (u8_t)BIT_MASK(2)) +#define MIN_QUEUE_SIZE_LOG(crit) ((crit) & (u8_t)BIT_MASK(3)) +#define MIN_QUEUE_SIZE(crit) ((u32_t)BIT(MIN_QUEUE_SIZE_LOG(crit))) + +static s32_t offer_delay(struct bt_mesh_friend *frnd, s8_t rssi, u8_t crit) +{ + /* Scaling factors. The actual values are 1, 1.5, 2 & 2.5, but we + * want to avoid floating-point arithmetic. + */ + static const u8_t fact[] = { 10, 15, 20, 25 }; + s32_t delay; + + BT_DBG("ReceiveWindowFactor %u ReceiveWindow %u RSSIFactor %u RSSI %d", + fact[RECV_WIN_FACT(crit)], RECV_WIN, + fact[RSSI_FACT(crit)], rssi); + + /* Delay = ReceiveWindowFactor * ReceiveWindow - RSSIFactor * RSSI */ + delay = (s32_t)fact[RECV_WIN_FACT(crit)] * RECV_WIN; + delay -= (s32_t)fact[RSSI_FACT(crit)] * rssi; + delay /= 10; + + BT_DBG("Local Delay calculated as %d ms", delay); + + if (delay < 100) { + return K_MSEC(100); + } + + return K_MSEC(delay); +} + +int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) +{ + struct bt_mesh_ctl_friend_req *msg = (void *)buf->data; + struct bt_mesh_friend *frnd = NULL; + u32_t poll_to; + int i; + + if (buf->len < sizeof(*msg)) { + BT_WARN("%s, Too short Friend Request", __func__); + return -EINVAL; + } + + if (msg->recv_delay <= 0x09) { + BT_WARN("%s, Prohibited ReceiveDelay (0x%02x)", __func__, msg->recv_delay); + return -EINVAL; + } + + poll_to = (((u32_t)msg->poll_to[0] << 16) | + ((u32_t)msg->poll_to[1] << 8) | + ((u32_t)msg->poll_to[2])); + + if (poll_to <= 0x000009 || poll_to >= 0x34bc00) { + BT_WARN("%s, Prohibited PollTimeout (0x%06x)", __func__, poll_to); + return -EINVAL; + } + + if (msg->num_elem == 0x00) { + BT_WARN("%s, Prohibited NumElements value (0x00)", __func__); + return -EINVAL; + } + + if (!BLE_MESH_ADDR_IS_UNICAST(rx->ctx.addr + msg->num_elem - 1)) { + BT_WARN("%s, LPN elements stretch outside of unicast range", __func__); + return -EINVAL; + } + + if (!MIN_QUEUE_SIZE_LOG(msg->criteria)) { + BT_WARN("%s, Prohibited Minimum Queue Size in Friend Request", __func__); + return -EINVAL; + } + + if (CONFIG_BLE_MESH_FRIEND_QUEUE_SIZE < MIN_QUEUE_SIZE(msg->criteria)) { + BT_WARN("%s, We have a too small Friend Queue size (%u < %u)", + __func__, CONFIG_BLE_MESH_FRIEND_QUEUE_SIZE, + MIN_QUEUE_SIZE(msg->criteria)); + return 0; + } + + frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, false); + if (frnd) { + BT_WARN("%s, Existing LPN re-requesting Friendship", __func__); + friend_clear(frnd); + goto init_friend; + } + + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { + if (!bt_mesh.frnd[i].valid) { + frnd = &bt_mesh.frnd[i]; + frnd->valid = 1U; + break; + } + } + + if (!frnd) { + BT_WARN("%s, No free Friend contexts for new LPN", __func__); + return -ENOMEM; + } + +init_friend: + frnd->lpn = rx->ctx.addr; + frnd->num_elem = msg->num_elem; + frnd->net_idx = rx->sub->net_idx; + frnd->recv_delay = msg->recv_delay; + frnd->poll_to = poll_to * 100U; + frnd->lpn_counter = sys_be16_to_cpu(msg->lpn_counter); + frnd->clear.frnd = sys_be16_to_cpu(msg->prev_addr); + + BT_DBG("LPN 0x%04x rssi %d recv_delay %u poll_to %ums", + frnd->lpn, rx->rssi, frnd->recv_delay, frnd->poll_to); + + if (BLE_MESH_ADDR_IS_UNICAST(frnd->clear.frnd) && + !bt_mesh_elem_find(frnd->clear.frnd)) { + clear_procedure_start(frnd); + } + + k_delayed_work_submit(&frnd->timer, + offer_delay(frnd, rx->rssi, msg->criteria)); + + friend_cred_create(rx->sub, frnd->lpn, frnd->lpn_counter, + frnd->counter); + + enqueue_offer(frnd, rx->rssi); + + return 0; +} + +static struct bt_mesh_friend_seg *get_seg(struct bt_mesh_friend *frnd, + u16_t src, u64_t *seq_auth) +{ + struct bt_mesh_friend_seg *unassigned = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) { + struct bt_mesh_friend_seg *seg = &frnd->seg[i]; + struct net_buf *buf = (void *)sys_slist_peek_head(&seg->queue); + + if (buf && BLE_MESH_ADV(buf)->addr == src && + FRIEND_ADV(buf)->seq_auth == *seq_auth) { + return seg; + } + + if (!unassigned && !buf) { + unassigned = seg; + } + } + + return unassigned; +} + +static void enqueue_friend_pdu(struct bt_mesh_friend *frnd, + enum bt_mesh_friend_pdu_type type, + struct net_buf *buf) +{ + struct bt_mesh_friend_seg *seg; + struct friend_adv *adv; + + BT_DBG("type %u", type); + + if (type == BLE_MESH_FRIEND_PDU_SINGLE) { + if (frnd->sec_update) { + enqueue_update(frnd, 1); + } + + enqueue_buf(frnd, buf); + return; + } + + adv = FRIEND_ADV(buf); + seg = get_seg(frnd, BLE_MESH_ADV(buf)->addr, &adv->seq_auth); + if (!seg) { + BT_ERR("%s, No free friend segment RX contexts for 0x%04x", + __func__, BLE_MESH_ADV(buf)->addr); + net_buf_unref(buf); + return; + } + + net_buf_slist_put(&seg->queue, buf); + + if (type == BLE_MESH_FRIEND_PDU_COMPLETE) { + if (frnd->sec_update) { + enqueue_update(frnd, 1); + } + + /* Only acks should have a valid SeqAuth in the Friend queue + * (otherwise we can't easily detect them there), so clear + * the SeqAuth information from the segments before merging. + */ + SYS_SLIST_FOR_EACH_CONTAINER(&seg->queue, buf, node) { + FRIEND_ADV(buf)->seq_auth = TRANS_SEQ_AUTH_NVAL; + frnd->queue_size++; + } + + sys_slist_merge_slist(&frnd->queue, &seg->queue); + } +} + +static void buf_send_start(u16_t duration, int err, void *user_data) +{ + struct bt_mesh_friend *frnd = user_data; + + BT_DBG("err %d", err); + + frnd->pending_buf = 0U; + + /* Friend Offer doesn't follow the re-sending semantics */ + if (!frnd->established) { + net_buf_unref(frnd->last); + frnd->last = NULL; + } +} + +static void buf_send_end(int err, void *user_data) +{ + struct bt_mesh_friend *frnd = user_data; + + BT_DBG("err %d", err); + + if (frnd->pending_req) { + BT_WARN("Another request before previous completed sending"); + return; + } + + if (frnd->established) { + k_delayed_work_submit(&frnd->timer, frnd->poll_to); + BT_DBG("Waiting %u ms for next poll", frnd->poll_to); + } else { + /* Friend offer timeout is 1 second */ + k_delayed_work_submit(&frnd->timer, K_SECONDS(1)); + BT_DBG("Waiting for first poll"); + } +} + +static void friend_timeout(struct k_work *work) +{ + struct bt_mesh_friend *frnd = CONTAINER_OF(work, struct bt_mesh_friend, + timer.work); + static const struct bt_mesh_send_cb buf_sent_cb = { + .start = buf_send_start, + .end = buf_send_end, + }; + + __ASSERT_NO_MSG(frnd->pending_buf == 0U); + + BT_DBG("lpn 0x%04x send_last %u last %p", frnd->lpn, + frnd->send_last, frnd->last); + + if (frnd->send_last && frnd->last) { + BT_DBG("Sending frnd->last %p", frnd->last); + frnd->send_last = 0U; + goto send_last; + } + + if (frnd->established && !frnd->pending_req) { + BT_WARN("%s, Friendship lost with 0x%04x", __func__, frnd->lpn); + friend_clear(frnd); + return; + } + + frnd->last = net_buf_slist_get(&frnd->queue); + if (!frnd->last) { + BT_WARN("%s, Friendship not established with 0x%04x", __func__, frnd->lpn); + friend_clear(frnd); + return; + } + + BT_DBG("Sending buf %p from Friend Queue of LPN 0x%04x", + frnd->last, frnd->lpn); + frnd->queue_size--; + +send_last: + frnd->pending_req = 0U; + frnd->pending_buf = 1U; + bt_mesh_adv_send(frnd->last, &buf_sent_cb, frnd); +} + +int bt_mesh_friend_init(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { + struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; + int j; + + frnd->net_idx = BLE_MESH_KEY_UNUSED; + + sys_slist_init(&frnd->queue); + + k_delayed_work_init(&frnd->timer, friend_timeout); + k_delayed_work_init(&frnd->clear.timer, clear_timeout); + + for (j = 0; j < ARRAY_SIZE(frnd->seg); j++) { + sys_slist_init(&frnd->seg[j].queue); + } + } + + return 0; +} + +static void friend_purge_old_ack(struct bt_mesh_friend *frnd, u64_t *seq_auth, + u16_t src) +{ + sys_snode_t *cur, *prev = NULL; + + BT_DBG("SeqAuth %llx src 0x%04x", *seq_auth, src); + + for (cur = sys_slist_peek_head(&frnd->queue); + cur != NULL; prev = cur, cur = sys_slist_peek_next(cur)) { + struct net_buf *buf = (void *)cur; + + if (BLE_MESH_ADV(buf)->addr == src && + FRIEND_ADV(buf)->seq_auth == *seq_auth) { + BT_DBG("Removing old ack from Friend Queue"); + + sys_slist_remove(&frnd->queue, prev, cur); + frnd->queue_size--; + /* Make sure old slist entry state doesn't remain */ + buf->frags = NULL; + + net_buf_unref(buf); + break; + } + } +} + +static void friend_lpn_enqueue_rx(struct bt_mesh_friend *frnd, + struct bt_mesh_net_rx *rx, + enum bt_mesh_friend_pdu_type type, + u64_t *seq_auth, struct net_buf_simple *sbuf) +{ + struct friend_pdu_info info; + struct net_buf *buf; + + BT_DBG("LPN 0x%04x queue_size %u", frnd->lpn, frnd->queue_size); + + if (type == BLE_MESH_FRIEND_PDU_SINGLE && seq_auth) { + friend_purge_old_ack(frnd, seq_auth, rx->ctx.addr); + } + + info.src = rx->ctx.addr; + info.dst = rx->ctx.recv_dst; + + if (rx->net_if == BLE_MESH_NET_IF_LOCAL) { + info.ttl = rx->ctx.recv_ttl; + } else { + info.ttl = rx->ctx.recv_ttl - 1U; + } + + info.ctl = rx->ctl; + + info.seq[0] = (rx->seq >> 16); + info.seq[1] = (rx->seq >> 8); + info.seq[2] = rx->seq; + + info.iv_index = BLE_MESH_NET_IVI_RX(rx); + + buf = create_friend_pdu(frnd, &info, sbuf); + if (!buf) { + BT_ERR("%s, Failed to encode Friend buffer", __func__); + return; + } + + if (seq_auth) { + FRIEND_ADV(buf)->seq_auth = *seq_auth; + } + + enqueue_friend_pdu(frnd, type, buf); + + BT_DBG("Queued message for LPN 0x%04x, queue_size %u", + frnd->lpn, frnd->queue_size); +} + +static void friend_lpn_enqueue_tx(struct bt_mesh_friend *frnd, + struct bt_mesh_net_tx *tx, + enum bt_mesh_friend_pdu_type type, + u64_t *seq_auth, struct net_buf_simple *sbuf) +{ + struct friend_pdu_info info; + struct net_buf *buf; + u32_t seq; + + BT_DBG("LPN 0x%04x", frnd->lpn); + + if (type == BLE_MESH_FRIEND_PDU_SINGLE && seq_auth) { + friend_purge_old_ack(frnd, seq_auth, tx->src); + } + + info.src = tx->src; + info.dst = tx->ctx->addr; + + info.ttl = tx->ctx->send_ttl; + info.ctl = (tx->ctx->app_idx == BLE_MESH_KEY_UNUSED); + + seq = bt_mesh_next_seq(); + info.seq[0] = seq >> 16; + info.seq[1] = seq >> 8; + info.seq[2] = seq; + + info.iv_index = BLE_MESH_NET_IVI_TX; + + buf = create_friend_pdu(frnd, &info, sbuf); + if (!buf) { + BT_ERR("%s, Failed to encode Friend buffer", __func__); + return; + } + + if (seq_auth) { + FRIEND_ADV(buf)->seq_auth = *seq_auth; + } + + enqueue_friend_pdu(frnd, type, buf); + + BT_DBG("Queued message for LPN 0x%04x", frnd->lpn); +} + +static bool friend_lpn_matches(struct bt_mesh_friend *frnd, u16_t net_idx, + u16_t addr) +{ + int i; + + if (!frnd->established) { + return false; + } + + if (net_idx != frnd->net_idx) { + return false; + } + + if (BLE_MESH_ADDR_IS_UNICAST(addr)) { + return is_lpn_unicast(frnd, addr); + } + + for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) { + if (frnd->sub_list[i] == addr) { + return true; + } + } + + return false; +} + +bool bt_mesh_friend_match(u16_t net_idx, u16_t addr) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { + struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; + + if (friend_lpn_matches(frnd, net_idx, addr)) { + BT_DBG("LPN 0x%04x matched address 0x%04x", + frnd->lpn, addr); + return true; + } + } + + BT_DBG("No matching LPN for address 0x%04x", addr); + + return false; +} + +void bt_mesh_friend_enqueue_rx(struct bt_mesh_net_rx *rx, + enum bt_mesh_friend_pdu_type type, + u64_t *seq_auth, struct net_buf_simple *sbuf) +{ + int i; + + if (!rx->friend_match || + (rx->ctx.recv_ttl <= 1U && rx->net_if != BLE_MESH_NET_IF_LOCAL) || + bt_mesh_friend_get() != BLE_MESH_FRIEND_ENABLED) { + return; + } + + BT_DBG("recv_ttl %u net_idx 0x%04x src 0x%04x dst 0x%04x", + rx->ctx.recv_ttl, rx->sub->net_idx, rx->ctx.addr, + rx->ctx.recv_dst); + + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { + struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; + + if (friend_lpn_matches(frnd, rx->sub->net_idx, + rx->ctx.recv_dst)) { + friend_lpn_enqueue_rx(frnd, rx, type, seq_auth, sbuf); + } + } +} + +bool bt_mesh_friend_enqueue_tx(struct bt_mesh_net_tx *tx, + enum bt_mesh_friend_pdu_type type, + u64_t *seq_auth, struct net_buf_simple *sbuf) +{ + bool matched = false; + int i; + + if (!bt_mesh_friend_match(tx->sub->net_idx, tx->ctx->addr) || + bt_mesh_friend_get() != BLE_MESH_FRIEND_ENABLED) { + return matched; + } + + BT_DBG("net_idx 0x%04x dst 0x%04x src 0x%04x", tx->sub->net_idx, + tx->ctx->addr, tx->src); + + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { + struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; + + if (friend_lpn_matches(frnd, tx->sub->net_idx, tx->ctx->addr)) { + friend_lpn_enqueue_tx(frnd, tx, type, seq_auth, sbuf); + matched = true; + } + } + + return matched; +} + +void bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, u16_t src, + u16_t dst, u64_t *seq_auth) +{ + int i; + + BT_DBG("%s", __func__); + + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { + struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; + int j; + + if (!friend_lpn_matches(frnd, sub->net_idx, dst)) { + continue; + } + + for (j = 0; j < ARRAY_SIZE(frnd->seg); j++) { + struct bt_mesh_friend_seg *seg = &frnd->seg[j]; + struct net_buf *buf; + + buf = (void *)sys_slist_peek_head(&seg->queue); + if (!buf) { + continue; + } + + if (BLE_MESH_ADV(buf)->addr != src) { + continue; + } + + if (FRIEND_ADV(buf)->seq_auth != *seq_auth) { + continue; + } + + BT_WARN("%s, Clearing incomplete segments for 0x%04x", __func__, src); + + while (!sys_slist_is_empty(&seg->queue)) { + net_buf_unref(net_buf_slist_get(&seg->queue)); + } + } + } +} + +#endif /* CONFIG_BLE_MESH_FRIEND */ diff --git a/components/bt/ble_mesh/mesh_core/friend.h b/components/bt/ble_mesh/mesh_core/friend.h new file mode 100644 index 0000000000..008a342c9b --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/friend.h @@ -0,0 +1,49 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _FRIEND_H_ +#define _FRIEND_H_ + +enum bt_mesh_friend_pdu_type { + BLE_MESH_FRIEND_PDU_SINGLE, + BLE_MESH_FRIEND_PDU_PARTIAL, + BLE_MESH_FRIEND_PDU_COMPLETE, +}; + +bool bt_mesh_friend_match(u16_t net_idx, u16_t addr); + +struct bt_mesh_friend *bt_mesh_friend_find(u16_t net_idx, u16_t lpn_addr, + bool valid, bool established); + +void bt_mesh_friend_enqueue_rx(struct bt_mesh_net_rx *rx, + enum bt_mesh_friend_pdu_type type, + u64_t *seq_auth, struct net_buf_simple *sbuf); +bool bt_mesh_friend_enqueue_tx(struct bt_mesh_net_tx *tx, + enum bt_mesh_friend_pdu_type type, + u64_t *seq_auth, struct net_buf_simple *sbuf); + +void bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, u16_t src, + u16_t dst, u64_t *seq_auth); + +void bt_mesh_friend_sec_update(u16_t net_idx); + +void bt_mesh_friend_clear_net_idx(u16_t net_idx); + +int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf); +int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf); +int bt_mesh_friend_clear(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf); +int bt_mesh_friend_clear_cfm(struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf); +int bt_mesh_friend_sub_add(struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf); +int bt_mesh_friend_sub_rem(struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf); + +int bt_mesh_friend_init(void); + +#endif /* _FRIEND_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/health_cli.c b/components/bt/ble_mesh/mesh_core/health_cli.c new file mode 100644 index 0000000000..c66e42afcd --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/health_cli.c @@ -0,0 +1,462 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "osi/allocator.h" +#include "sdkconfig.h" +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BLE_MESH_DEBUG_MODEL) + +#include "mesh_types.h" +#include "mesh_util.h" +#include "mesh_trace.h" +#include "health_cli.h" + +#include "foundation.h" +#include "mesh_common.h" +#include "btc_ble_mesh_health_model.h" + +s32_t health_msg_timeout; + +static bt_mesh_health_client_t *health_cli; + +static const bt_mesh_client_op_pair_t health_op_pair[] = { + { OP_HEALTH_FAULT_GET, OP_HEALTH_FAULT_STATUS }, + { OP_HEALTH_FAULT_CLEAR, OP_HEALTH_FAULT_STATUS }, + { OP_HEALTH_FAULT_TEST, OP_HEALTH_FAULT_STATUS }, + { OP_HEALTH_PERIOD_GET, OP_HEALTH_PERIOD_STATUS }, + { OP_HEALTH_PERIOD_SET, OP_HEALTH_PERIOD_STATUS }, + { OP_ATTENTION_GET, OP_ATTENTION_STATUS }, + { OP_ATTENTION_SET, OP_ATTENTION_STATUS }, +}; + +static void timeout_handler(struct k_work *work) +{ + health_internal_data_t *internal = NULL; + bt_mesh_health_client_t *client = NULL; + bt_mesh_client_node_t *node = NULL; + + BT_WARN("Receive health status message timeout"); + + node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work); + if (!node || !node->ctx.model) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + client = (bt_mesh_health_client_t *)node->ctx.model->user_data; + if (!client) { + BT_ERR("%s, Health Client user_data is NULL", __func__); + return; + } + + internal = (health_internal_data_t *)client->internal_data; + if (!internal) { + BT_ERR("%s, Health Client internal_data is NULL", __func__); + return; + } + + bt_mesh_callback_health_status_to_btc(node->opcode, 0x03, node->ctx.model, + &node->ctx, NULL, 0); + + bt_mesh_client_free_node(&internal->queue, node); + + return; +} + +static void health_client_cancel(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + void *status, size_t len) +{ + health_internal_data_t *data = NULL; + bt_mesh_client_node_t *node = NULL; + struct net_buf_simple buf = {0}; + u8_t evt_type = 0xFF; + + if (!model || !ctx || !status || !len) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + data = (health_internal_data_t *)health_cli->internal_data; + if (!data) { + BT_ERR("%s, Health Client internal_data is NULL", __func__); + return; + } + + /* If it is a publish message, sent to the user directly. */ + buf.data = (u8_t *)status; + buf.len = (u16_t)len; + node = bt_mesh_is_model_message_publish(model, ctx, &buf, true); + if (!node) { + BT_DBG("Unexpected health status message 0x%x", ctx->recv_op); + } else { + switch (node->opcode) { + case OP_HEALTH_FAULT_GET: + case OP_HEALTH_PERIOD_GET: + case OP_ATTENTION_GET: + evt_type = 0x00; + break; + case OP_HEALTH_FAULT_CLEAR: + case OP_HEALTH_FAULT_TEST: + case OP_HEALTH_PERIOD_SET: + case OP_ATTENTION_SET: + evt_type = 0x01; + break; + default: + break; + } + + bt_mesh_callback_health_status_to_btc(node->opcode, evt_type, model, + ctx, (const u8_t *)status, len); + // Don't forget to release the node at the end. + bt_mesh_client_free_node(&data->queue, node); + } + + switch (ctx->recv_op) { + case OP_HEALTH_FAULT_STATUS: { + struct bt_mesh_health_fault_status *val; + val = (struct bt_mesh_health_fault_status *)status; + bt_mesh_free_buf(val->fault_array); + break; + } + default: + break; + } +} + +static void health_fault_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_health_fault_status status = {0}; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + status.test_id = net_buf_simple_pull_u8(buf); + status.cid = net_buf_simple_pull_le16(buf); + status.fault_array = bt_mesh_alloc_buf(buf->len); + if (!status.fault_array) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + + net_buf_simple_add_mem(status.fault_array, buf->data, buf->len); + + health_client_cancel(model, ctx, &status, sizeof(struct bt_mesh_health_fault_status)); +} + +static void health_current_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + bt_mesh_client_node_t *node = NULL; + u8_t test_id; + u16_t cid; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + /* Health current status is a publish message, sent to the user directly. */ + if (!(node = bt_mesh_is_model_message_publish(model, ctx, buf, true))) { + return; + } + + test_id = net_buf_simple_pull_u8(buf); + cid = net_buf_simple_pull_le16(buf); + + BT_DBG("Test ID 0x%02x Company ID 0x%04x Fault Count %u", + test_id, cid, buf->len); +} + +static void health_period_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + u8_t status = 0; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + status = net_buf_simple_pull_u8(buf); + + health_client_cancel(model, ctx, &status, sizeof(u8_t)); +} + +static void health_attention_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + u8_t status = 0; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, + bt_hex(buf->data, buf->len)); + + status = net_buf_simple_pull_u8(buf); + + health_client_cancel(model, ctx, &status, sizeof(u8_t)); +} + +const struct bt_mesh_model_op bt_mesh_health_cli_op[] = { + { OP_HEALTH_FAULT_STATUS, 3, health_fault_status }, + { OP_HEALTH_CURRENT_STATUS, 3, health_current_status }, + { OP_HEALTH_PERIOD_STATUS, 1, health_period_status }, + { OP_ATTENTION_STATUS, 1, health_attention_status }, + BLE_MESH_MODEL_OP_END, +}; + +int bt_mesh_health_attention_get(struct bt_mesh_msg_ctx *ctx) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 0 + 4); + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_ATTENTION_GET); + + err = bt_mesh_client_send_msg(health_cli->model, OP_ATTENTION_GET, ctx, + &msg, timeout_handler, health_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_health_attention_set(struct bt_mesh_msg_ctx *ctx, + u8_t attention, bool need_ack) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); + u32_t opcode; + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + if (need_ack) { + opcode = OP_ATTENTION_SET; + } else { + opcode = OP_ATTENTION_SET_UNREL; + } + bt_mesh_model_msg_init(&msg, opcode); + net_buf_simple_add_u8(&msg, attention); + + err = bt_mesh_client_send_msg(health_cli->model, opcode, ctx, &msg, + timeout_handler, health_msg_timeout, + need_ack, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_health_period_get(struct bt_mesh_msg_ctx *ctx) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 0 + 4); + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_HEALTH_PERIOD_GET); + + err = bt_mesh_client_send_msg(health_cli->model, OP_HEALTH_PERIOD_GET, + ctx, &msg, timeout_handler, health_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_health_period_set(struct bt_mesh_msg_ctx *ctx, + u8_t divisor, bool need_ack) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); + u32_t opcode; + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + if (need_ack) { + opcode = OP_HEALTH_PERIOD_SET; + } else { + opcode = OP_HEALTH_PERIOD_SET_UNREL; + } + bt_mesh_model_msg_init(&msg, opcode); + net_buf_simple_add_u8(&msg, divisor); + + err = bt_mesh_client_send_msg(health_cli->model, opcode, ctx, &msg, + timeout_handler, health_msg_timeout, + need_ack, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_health_fault_test(struct bt_mesh_msg_ctx *ctx, + u16_t cid, u8_t test_id, bool need_ack) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 3 + 4); + u32_t opcode; + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + if (need_ack) { + opcode = OP_HEALTH_FAULT_TEST; + } else { + opcode = OP_HEALTH_FAULT_TEST_UNREL; + } + bt_mesh_model_msg_init(&msg, opcode); + net_buf_simple_add_u8(&msg, test_id); + net_buf_simple_add_le16(&msg, cid); + + err = bt_mesh_client_send_msg(health_cli->model, opcode, ctx, &msg, + timeout_handler, health_msg_timeout, + need_ack, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_health_fault_clear(struct bt_mesh_msg_ctx *ctx, + u16_t cid, bool need_ack) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 2 + 4); + u32_t opcode; + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + if (need_ack) { + opcode = OP_HEALTH_FAULT_CLEAR; + } else { + opcode = OP_HEALTH_FAULT_CLEAR_UNREL; + } + bt_mesh_model_msg_init(&msg, opcode); + net_buf_simple_add_le16(&msg, cid); + + err = bt_mesh_client_send_msg(health_cli->model, opcode, ctx, &msg, + timeout_handler, health_msg_timeout, + need_ack, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +int bt_mesh_health_fault_get(struct bt_mesh_msg_ctx *ctx, u16_t cid) +{ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 2 + 4); + int err; + + if (!ctx || !ctx->addr) { + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, OP_HEALTH_FAULT_GET); + net_buf_simple_add_le16(&msg, cid); + + err = bt_mesh_client_send_msg(health_cli->model, OP_HEALTH_FAULT_GET, ctx, + &msg, timeout_handler, health_msg_timeout, + true, NULL, NULL); + if (err) { + BT_ERR("%s, send failed (err %d)", __func__, err); + } + + return err; +} + +s32_t bt_mesh_health_cli_timeout_get(void) +{ + return health_msg_timeout; +} + +void bt_mesh_health_cli_timeout_set(s32_t timeout) +{ + health_msg_timeout = timeout; +} + +int bt_mesh_health_cli_set(struct bt_mesh_model *model) +{ + if (!model || !model->user_data) { + BT_ERR("%s, No Health Client context for given model", __func__); + return -EINVAL; + } + + health_cli = model->user_data; + + return 0; +} + +int bt_mesh_health_cli_init(struct bt_mesh_model *model, bool primary) +{ + health_internal_data_t *internal = NULL; + bt_mesh_health_client_t *client = NULL; + + BT_DBG("primary %u", primary); + + if (!model) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_health_client_t *)model->user_data; + if (!client) { + BT_ERR("%s, No Health Client context provided", __func__); + return -EINVAL; + } + + /* TODO: call osi_free() when deinit function is invoked*/ + internal = osi_calloc(sizeof(health_internal_data_t)); + if (!internal) { + BT_ERR("%s, Failed to allocate memory", __func__); + return -ENOMEM; + } + + sys_slist_init(&internal->queue); + + client->model = model; + client->op_pair_size = ARRAY_SIZE(health_op_pair); + client->op_pair = health_op_pair; + client->internal_data = internal; + + /* Set the default health client pointer */ + if (!health_cli) { + health_cli = client; + } + + return 0; +} diff --git a/components/bt/ble_mesh/mesh_core/health_srv.c b/components/bt/ble_mesh/mesh_core/health_srv.c new file mode 100644 index 0000000000..96e16692dd --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/health_srv.c @@ -0,0 +1,529 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "sdkconfig.h" +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BLE_MESH_DEBUG_MODEL) + +#include "mesh_types.h" +#include "mesh_util.h" +#include "mesh_trace.h" +#include "health_srv.h" + +#include "mesh.h" +#include "adv.h" +#include "net.h" +#include "transport.h" +#include "access.h" +#include "foundation.h" +#include "mesh_common.h" + +#define HEALTH_TEST_STANDARD 0x00 + +/* Maximum message length is 384 in BLE Mesh. Here for health fault status, + * due to 1 octet opcode and 4 octets TransMIC, 379 octets can be used to + * store health fault status. + */ +#define HEALTH_FAULT_MAX_LEN 379 + +/* Health Server context of the primary element */ +struct bt_mesh_health_srv *health_srv; + +static void health_get_registered(struct bt_mesh_model *mod, + u16_t company_id, + struct net_buf_simple *msg) +{ + struct bt_mesh_health_srv *srv = mod->user_data; + u8_t *test_id; + + BT_DBG("Company ID 0x%04x", company_id); + + if (!srv) { + BT_ERR("%s, No Health Server context provided", __func__); + return; + } + + bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_STATUS); + + test_id = net_buf_simple_add(msg, 1); + net_buf_simple_add_le16(msg, company_id); + + if (srv->cb && srv->cb->fault_get_reg) { + u8_t fault_count = net_buf_simple_tailroom(msg) - 4; + int err; + + err = srv->cb->fault_get_reg(mod, company_id, test_id, + net_buf_simple_tail(msg), + &fault_count); + if (err) { + BT_ERR("%s, Failed to get faults (err %d)", __func__, err); + *test_id = HEALTH_TEST_STANDARD; + } else { + net_buf_simple_add(msg, fault_count); + } + } else { + BT_WARN("No callback for getting faults"); + *test_id = HEALTH_TEST_STANDARD; + } +} + +static size_t health_get_current(struct bt_mesh_model *mod, + struct net_buf_simple *msg) +{ + struct bt_mesh_health_srv *srv = mod->user_data; + const struct bt_mesh_comp *comp; + u8_t *test_id, *company_ptr; + u16_t company_id; + u8_t fault_count; + int err; + + if (!srv) { + BT_ERR("%s, No Health Server context provided", __func__); + return 0; + } + + bt_mesh_model_msg_init(msg, OP_HEALTH_CURRENT_STATUS); + + test_id = net_buf_simple_add(msg, 1); + company_ptr = net_buf_simple_add(msg, sizeof(company_id)); + comp = bt_mesh_comp_get(); + + if (srv->cb && srv->cb->fault_get_cur) { + fault_count = net_buf_simple_tailroom(msg); + err = srv->cb->fault_get_cur(mod, test_id, &company_id, + net_buf_simple_tail(msg), + &fault_count); + if (err) { + BT_ERR("%s, Failed to get faults (err %d)", __func__, err); + sys_put_le16(comp->cid, company_ptr); + *test_id = HEALTH_TEST_STANDARD; + fault_count = 0U; + } else { + sys_put_le16(company_id, company_ptr); + net_buf_simple_add(msg, fault_count); + } + } else { + BT_WARN("No callback for getting faults"); + sys_put_le16(comp->cid, company_ptr); + *test_id = HEALTH_TEST_STANDARD; + fault_count = 0U; + } + + return fault_count; +} + +static void health_fault_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct net_buf_simple *sdu = NULL; + u16_t company_id; + + company_id = net_buf_simple_pull_le16(buf); + + BT_DBG("company_id 0x%04x", company_id); + + sdu = bt_mesh_alloc_buf(MIN(BLE_MESH_TX_SDU_MAX, HEALTH_FAULT_MAX_LEN)); + if (!sdu) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + + health_get_registered(model, company_id, sdu); + + if (bt_mesh_model_send(model, ctx, sdu, NULL, NULL)) { + BT_ERR("%s, Unable to send Health Current Status", __func__); + } + + bt_mesh_free_buf(sdu); + return; +} + +static void health_fault_clear_unrel(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_health_srv *srv = model->user_data; + u16_t company_id; + + if (!srv) { + BT_ERR("%s, No Health Server context provided", __func__); + return; + } + + company_id = net_buf_simple_pull_le16(buf); + + BT_DBG("company_id 0x%04x", company_id); + + if (srv->cb && srv->cb->fault_clear) { + srv->cb->fault_clear(model, company_id); + } +} + +static void health_fault_clear(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_health_srv *srv = model->user_data; + struct net_buf_simple *sdu = NULL; + u16_t company_id; + + if (!srv) { + BT_ERR("%s, No Health Server context provided", __func__); + return; + } + + company_id = net_buf_simple_pull_le16(buf); + + BT_DBG("company_id 0x%04x", company_id); + + if (srv->cb && srv->cb->fault_clear) { + srv->cb->fault_clear(model, company_id); + } + + sdu = bt_mesh_alloc_buf(MIN(BLE_MESH_TX_SDU_MAX, HEALTH_FAULT_MAX_LEN)); + if (!sdu) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + + health_get_registered(model, company_id, sdu); + + if (bt_mesh_model_send(model, ctx, sdu, NULL, NULL)) { + BT_ERR("%s, Unable to send Health Current Status", __func__); + } + + bt_mesh_free_buf(sdu); + return; +} + +static void health_fault_test_unrel(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_health_srv *srv = model->user_data; + u16_t company_id; + u8_t test_id; + + if (!srv) { + BT_ERR("%s, No Health Server context provided", __func__); + return; + } + + test_id = net_buf_simple_pull_u8(buf); + company_id = net_buf_simple_pull_le16(buf); + + BT_DBG("test 0x%02x company 0x%04x", test_id, company_id); + + if (srv->cb && srv->cb->fault_test) { + srv->cb->fault_test(model, test_id, company_id); + } +} + +static void health_fault_test(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_health_srv *srv = model->user_data; + struct net_buf_simple *sdu = NULL; + u16_t company_id; + u8_t test_id; + + BT_DBG("%s", __func__); + + if (!srv) { + BT_ERR("%s, No Health Server context provided", __func__); + return; + } + + test_id = net_buf_simple_pull_u8(buf); + company_id = net_buf_simple_pull_le16(buf); + + BT_DBG("test 0x%02x company 0x%04x", test_id, company_id); + + if (srv->cb && srv->cb->fault_test) { + int err; + + err = srv->cb->fault_test(model, test_id, company_id); + if (err) { + BT_WARN("Running fault test failed with err %d", err); + return; + } + } + + sdu = bt_mesh_alloc_buf(MIN(BLE_MESH_TX_SDU_MAX, HEALTH_FAULT_MAX_LEN)); + if (!sdu) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + + health_get_registered(model, company_id, sdu); + + if (bt_mesh_model_send(model, ctx, sdu, NULL, NULL)) { + BT_ERR("%s, Unable to send Health Current Status", __func__); + } + + bt_mesh_free_buf(sdu); + return; +} + +static void send_attention_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); + struct bt_mesh_health_srv *srv = model->user_data; + u8_t time; + + if (!srv) { + BT_ERR("%s, No Health Server context provided", __func__); + return; + } + + time = k_delayed_work_remaining_get(&srv->attn_timer) / 1000; + BT_DBG("%u second%s", time, (time == 1U) ? "" : "s"); + + bt_mesh_model_msg_init(&msg, OP_ATTENTION_STATUS); + + net_buf_simple_add_u8(&msg, time); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Health Attention Status", __func__); + } +} + +static void attention_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + BT_DBG("%s", __func__); + + send_attention_status(model, ctx); +} + +static void attention_set_unrel(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + u8_t time; + + time = net_buf_simple_pull_u8(buf); + + BT_DBG("%u second%s", time, (time == 1U) ? "" : "s"); + + bt_mesh_attention(model, time); +} + +static void attention_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + BT_DBG("%s", __func__); + + attention_set_unrel(model, ctx, buf); + + send_attention_status(model, ctx); +} + +static void send_health_period_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx) +{ + /* Needed size: opcode (2 bytes) + msg + MIC */ + NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); + + bt_mesh_model_msg_init(&msg, OP_HEALTH_PERIOD_STATUS); + + net_buf_simple_add_u8(&msg, model->pub->period_div); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("%s, Unable to send Health Period Status", __func__); + } +} + +static void health_period_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + BT_DBG("%s", __func__); + + send_health_period_status(model, ctx); +} + +static void health_period_set_unrel(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + u8_t period; + + period = net_buf_simple_pull_u8(buf); + if (period > 15) { + BT_WARN("%s, Prohibited period value %u", __func__, period); + return; + } + + BT_DBG("period %u", period); + + model->pub->period_div = period; +} + +static void health_period_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + BT_DBG("%s", __func__); + + health_period_set_unrel(model, ctx, buf); + + send_health_period_status(model, ctx); +} + +const struct bt_mesh_model_op bt_mesh_health_srv_op[] = { + { OP_HEALTH_FAULT_GET, 2, health_fault_get }, + { OP_HEALTH_FAULT_CLEAR, 2, health_fault_clear }, + { OP_HEALTH_FAULT_CLEAR_UNREL, 2, health_fault_clear_unrel }, + { OP_HEALTH_FAULT_TEST, 3, health_fault_test }, + { OP_HEALTH_FAULT_TEST_UNREL, 3, health_fault_test_unrel }, + { OP_HEALTH_PERIOD_GET, 0, health_period_get }, + { OP_HEALTH_PERIOD_SET, 1, health_period_set }, + { OP_HEALTH_PERIOD_SET_UNREL, 1, health_period_set_unrel }, + { OP_ATTENTION_GET, 0, attention_get }, + { OP_ATTENTION_SET, 1, attention_set }, + { OP_ATTENTION_SET_UNREL, 1, attention_set_unrel }, + BLE_MESH_MODEL_OP_END, +}; + +static int health_pub_update(struct bt_mesh_model *mod) +{ + struct bt_mesh_model_pub *pub = mod->pub; + size_t count; + + BT_DBG("%s", __func__); + + count = health_get_current(mod, pub->msg); + if (count) { + pub->fast_period = 1U; + } else { + pub->fast_period = 0U; + } + + return 0; +} + +int bt_mesh_fault_update(struct bt_mesh_elem *elem) +{ + struct bt_mesh_model *mod; + + mod = bt_mesh_model_find(elem, BLE_MESH_MODEL_ID_HEALTH_SRV); + if (!mod) { + BT_ERR("%s, Health Server does not exist", __func__); + return -EINVAL; + } + + if (!mod->pub) { + BT_ERR("%s, Health Server has no publication support", __func__); + return -EIO; + } + + /* Let periodic publishing, if enabled, take care of sending the + * Health Current Status. + */ + if (bt_mesh_model_pub_period_get(mod)) { + return 0; + } + + health_pub_update(mod); + + return bt_mesh_model_publish(mod); +} + +static void attention_off(struct k_work *work) +{ + struct bt_mesh_health_srv *srv = CONTAINER_OF(work, + struct bt_mesh_health_srv, + attn_timer.work); + BT_DBG("%s", __func__); + + if (!srv) { + BT_ERR("%s, No Health Server context provided", __func__); + return; + } + + if (srv->cb && srv->cb->attn_off) { + srv->cb->attn_off(srv->model); + } +} + +int bt_mesh_health_srv_init(struct bt_mesh_model *model, bool primary) +{ + struct bt_mesh_health_srv *srv = model->user_data; + + if (!srv) { + if (!primary) { + return 0; + } + + BT_ERR("%s, No Health Server context provided", __func__); + return -EINVAL; + } + + if (!model->pub) { + BT_ERR("%s, Health Server has no publication support", __func__); + return -EINVAL; + } + + model->pub->update = health_pub_update; + + k_delayed_work_init(&srv->attn_timer, attention_off); + + srv->model = model; + + if (primary) { + health_srv = srv; + } + + return 0; +} + +void bt_mesh_attention(struct bt_mesh_model *model, u8_t time) +{ + struct bt_mesh_health_srv *srv; + + if (!model) { + srv = health_srv; + if (!srv) { + BT_WARN("%s, No Health Server context provided", __func__); + return; + } + + model = srv->model; + } else { + srv = model->user_data; + if (!srv) { + BT_WARN("%s, No Health Server context provided", __func__); + return; + } + } + + if (time) { + if (srv->cb && srv->cb->attn_on) { + srv->cb->attn_on(model); + } + + k_delayed_work_submit(&srv->attn_timer, time * 1000U); + } else { + k_delayed_work_cancel(&srv->attn_timer); + + if (srv->cb && srv->cb->attn_off) { + srv->cb->attn_off(model); + } + } +} diff --git a/components/bt/ble_mesh/mesh_core/include/cfg_cli.h b/components/bt/ble_mesh/mesh_core/include/cfg_cli.h new file mode 100644 index 0000000000..b001d84b8a --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/include/cfg_cli.h @@ -0,0 +1,297 @@ +/** @file + * @brief Bluetooth Mesh Configuration Client Model APIs. + */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _BLE_MESH_CFG_CLI_H_ +#define _BLE_MESH_CFG_CLI_H_ + +#include "mesh_access.h" +#include "mesh_kernel.h" +#include "model_common.h" + +/** + * @brief Bluetooth Mesh + * @defgroup bt_mesh_cfg_cli Bluetooth Mesh Configuration Client Model + * @ingroup bt_mesh + * @{ + */ + +/* Config client model common structure */ +typedef bt_mesh_client_common_t bt_mesh_config_client_t; +typedef bt_mesh_internal_data_t config_internal_data_t; + +extern const struct bt_mesh_model_op bt_mesh_cfg_cli_op[]; + +#define BLE_MESH_MODEL_CFG_CLI(cli_data) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_CFG_CLI, \ + bt_mesh_cfg_cli_op, NULL, cli_data) + +int bt_mesh_cfg_comp_data_get(struct bt_mesh_msg_ctx *ctx, u8_t page); + +int bt_mesh_cfg_beacon_get(struct bt_mesh_msg_ctx *ctx); + +int bt_mesh_cfg_beacon_set(struct bt_mesh_msg_ctx *ctx, u8_t val); + +int bt_mesh_cfg_ttl_get(struct bt_mesh_msg_ctx *ctx); + +int bt_mesh_cfg_ttl_set(struct bt_mesh_msg_ctx *ctx, u8_t val); + +int bt_mesh_cfg_friend_get(struct bt_mesh_msg_ctx *ctx); + +int bt_mesh_cfg_friend_set(struct bt_mesh_msg_ctx *ctx, u8_t val); + +int bt_mesh_cfg_gatt_proxy_get(struct bt_mesh_msg_ctx *ctx); + +int bt_mesh_cfg_gatt_proxy_set(struct bt_mesh_msg_ctx *ctx, u8_t val); + +int bt_mesh_cfg_relay_get(struct bt_mesh_msg_ctx *ctx); + +int bt_mesh_cfg_relay_set(struct bt_mesh_msg_ctx *ctx, u8_t new_relay, u8_t new_transmit); + +int bt_mesh_cfg_net_key_add(struct bt_mesh_msg_ctx *ctx, u16_t key_net_idx, + const u8_t net_key[16]); + +int bt_mesh_cfg_app_key_add(struct bt_mesh_msg_ctx *ctx, u16_t key_net_idx, + u16_t key_app_idx, const u8_t app_key[16]); + +int bt_mesh_cfg_mod_app_bind(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t mod_app_idx, u16_t mod_id, u16_t cid); + +struct bt_mesh_cfg_mod_pub { + u16_t addr; + u16_t app_idx; + bool cred_flag; + u8_t ttl; + u8_t period; + u8_t transmit; +}; + +int bt_mesh_cfg_mod_pub_get(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t mod_id, u16_t cid); + +int bt_mesh_cfg_mod_pub_set(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t mod_id, u16_t cid, + struct bt_mesh_cfg_mod_pub *pub); + +int bt_mesh_cfg_mod_sub_add(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t sub_addr, u16_t mod_id, u16_t cid); + +int bt_mesh_cfg_mod_sub_del(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t sub_addr, u16_t mod_id, u16_t cid); + +int bt_mesh_cfg_mod_sub_overwrite(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t sub_addr, u16_t mod_id, u16_t cid); + +int bt_mesh_cfg_mod_sub_va_add(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + const u8_t label[16], u16_t mod_id, u16_t cid); + +int bt_mesh_cfg_mod_sub_va_del(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + const u8_t label[16], u16_t mod_id, u16_t cid); + +int bt_mesh_cfg_mod_sub_va_overwrite(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + const u8_t label[16], u16_t mod_id, u16_t cid); + +struct bt_mesh_cfg_hb_sub { + u16_t src; + u16_t dst; + u8_t period; +}; + +int bt_mesh_cfg_hb_sub_set(struct bt_mesh_msg_ctx *ctx, + struct bt_mesh_cfg_hb_sub *sub); + +int bt_mesh_cfg_hb_sub_get(struct bt_mesh_msg_ctx *ctx); + +struct bt_mesh_cfg_hb_pub { + u16_t dst; + u8_t count; + u8_t period; + u8_t ttl; + u16_t feat; + u16_t net_idx; +}; + +int bt_mesh_cfg_hb_pub_set(struct bt_mesh_msg_ctx *ctx, + const struct bt_mesh_cfg_hb_pub *pub); + +int bt_mesh_cfg_hb_pub_get(struct bt_mesh_msg_ctx *ctx); + +int bt_mesh_cfg_node_reset(struct bt_mesh_msg_ctx *ctx); + +s32_t bt_mesh_cfg_cli_timeout_get(void); +void bt_mesh_cfg_cli_timeout_set(s32_t timeout); + +/* Configuration Client Status Message Context */ + +struct bt_mesh_cfg_comp_data_status { + u8_t page; + struct net_buf_simple *comp_data; +}; + +struct bt_mesh_cfg_relay_status { + u8_t relay; + u8_t retransmit; +}; + +struct bt_mesh_cfg_netkey_status { + u8_t status; + u16_t net_idx; +}; + +struct bt_mesh_cfg_appkey_status { + u8_t status; + u16_t net_idx; + u16_t app_idx; +}; + +struct bt_mesh_cfg_mod_app_status { + u8_t status; + u16_t elem_addr; + u16_t app_idx; + u16_t cid; + u16_t mod_id; +}; + +struct bt_mesh_cfg_mod_pub_status { + u8_t status; + u16_t elem_addr; + u16_t addr; + u16_t app_idx; + bool cred_flag; + u8_t ttl; + u8_t period; + u8_t transmit; + u16_t cid; + u16_t mod_id; +}; + +struct bt_mesh_cfg_mod_sub_status { + u8_t status; + u16_t elem_addr; + u16_t sub_addr; + u16_t cid; + u16_t mod_id; +}; + +struct bt_mesh_cfg_hb_sub_status { + u8_t status; + u16_t src; + u16_t dst; + u8_t period; + u8_t count; + u8_t min; + u8_t max; +}; + +struct bt_mesh_cfg_hb_pub_status { + u8_t status; + u16_t dst; + u8_t count; + u8_t period; + u8_t ttl; + u16_t feat; + u16_t net_idx; +}; + +struct bt_mesh_cfg_mod_sub_list { + u8_t status; + u16_t elem_addr; + u16_t cid; + u16_t mod_id; + struct net_buf_simple *addr; +}; + +struct bt_mesh_cfg_net_key_list { + struct net_buf_simple *net_idx; +}; + +struct bt_mesh_cfg_app_key_list { + u8_t status; + u16_t net_idx; + struct net_buf_simple *app_idx; +}; + +struct bt_mesh_cfg_node_id_status { + u8_t status; + u16_t net_idx; + u8_t identity; +}; + +struct bt_mesh_cfg_mod_app_list { + u8_t status; + u16_t elem_addr; + u16_t cid; + u16_t mod_id; + struct net_buf_simple *app_idx; +}; + +struct bt_mesh_cfg_key_refresh_status { + u8_t status; + u16_t net_idx; + u8_t phase; +}; + +struct bt_mesh_cfg_lpn_pollto_status { + u16_t lpn_addr; + s32_t timeout; +}; + +int bt_mesh_cfg_mod_pub_va_set(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t mod_id, u16_t cid, const u8_t label[16], + struct bt_mesh_cfg_mod_pub *pub); + +int bt_mesh_cfg_mod_sub_del_all(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t mod_id, u16_t cid); + +int bt_mesh_cfg_mod_sub_get(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, u16_t mod_id); + +int bt_mesh_cfg_mod_sub_get_vnd(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t mod_id, u16_t cid); + +int bt_mesh_cfg_net_key_update(struct bt_mesh_msg_ctx *ctx, u16_t net_idx, + const u8_t net_key[16]); + +int bt_mesh_cfg_net_key_delete(struct bt_mesh_msg_ctx *ctx, u16_t net_idx); + +int bt_mesh_cfg_net_key_get(struct bt_mesh_msg_ctx *ctx); + +int bt_mesh_cfg_app_key_update(struct bt_mesh_msg_ctx *ctx, u16_t net_idx, + u16_t app_idx, const u8_t app_key[16]); + +int bt_mesh_cfg_app_key_delete(struct bt_mesh_msg_ctx *ctx, u16_t net_idx, u16_t app_idx); + +int bt_mesh_cfg_app_key_get(struct bt_mesh_msg_ctx *ctx, u16_t net_idx); + +int bt_mesh_cfg_node_identity_get(struct bt_mesh_msg_ctx *ctx, u16_t net_idx); + +int bt_mesh_cfg_node_identity_set(struct bt_mesh_msg_ctx *ctx, u16_t net_idx, u8_t identity); + +int bt_mesh_cfg_mod_app_unbind(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t app_idx, u16_t mod_id, u16_t cid); + +int bt_mesh_cfg_mod_app_get(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, u16_t mod_id); + +int bt_mesh_cfg_mod_app_get_vnd(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, + u16_t mod_id, u16_t cid); + +int bt_mesh_cfg_kr_phase_get(struct bt_mesh_msg_ctx *ctx, u16_t net_idx); + +int bt_mesh_cfg_kr_phase_set(struct bt_mesh_msg_ctx *ctx, u16_t net_idx, u8_t transition); + +int bt_mesh_cfg_lpn_timeout_get(struct bt_mesh_msg_ctx *ctx, u16_t lpn_addr); + +int bt_mesh_cfg_net_transmit_get(struct bt_mesh_msg_ctx *ctx); + +int bt_mesh_cfg_net_transmit_set(struct bt_mesh_msg_ctx *ctx, u8_t transmit); + +/** + * @} + */ + +#endif /* __BLE_MESH_CFG_CLI_H */ diff --git a/components/bt/ble_mesh/mesh_core/include/cfg_srv.h b/components/bt/ble_mesh/mesh_core/include/cfg_srv.h new file mode 100644 index 0000000000..d5f77e7b01 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/include/cfg_srv.h @@ -0,0 +1,72 @@ +/** @file + * @brief Bluetooth Mesh Configuration Server Model APIs. + */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _BLE_MESH_CFG_SRV_H_ +#define _BLE_MESH_CFG_SRV_H_ + +#include "mesh_access.h" +#include "mesh_kernel.h" + +/** + * @brief Bluetooth Mesh + * @defgroup bt_mesh_cfg_srv Bluetooth Mesh Configuration Server Model + * @ingroup bt_mesh + * @{ + */ + +/** Mesh Configuration Server Model Context */ +struct bt_mesh_cfg_srv { + struct bt_mesh_model *model; + + u8_t net_transmit; /* Network Transmit state */ + u8_t relay; /* Relay Mode state */ + u8_t relay_retransmit; /* Relay Retransmit state */ + u8_t beacon; /* Secure Network Beacon state */ + u8_t gatt_proxy; /* GATT Proxy state */ + u8_t frnd; /* Friend state */ + u8_t default_ttl; /* Default TTL */ + + /* Heartbeat Publication */ + struct bt_mesh_hb_pub { + struct k_delayed_work timer; + + u16_t dst; + u16_t count; + u8_t period; + u8_t ttl; + u16_t feat; + u16_t net_idx; + } hb_pub; + + /* Heartbeat Subscription */ + struct bt_mesh_hb_sub { + s64_t expiry; + + u16_t src; + u16_t dst; + u16_t count; + u8_t min_hops; + u8_t max_hops; + + /* Optional subscription tracking function */ + void (*func)(u8_t hops, u16_t feat); + } hb_sub; +}; + +extern const struct bt_mesh_model_op bt_mesh_cfg_srv_op[]; + +#define BLE_MESH_MODEL_CFG_SRV(srv_data) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_CFG_SRV, \ + bt_mesh_cfg_srv_op, NULL, srv_data) + +/** + * @} + */ + +#endif /* __BLE_MESH_CFG_SRV_H */ diff --git a/components/bt/ble_mesh/mesh_core/include/health_cli.h b/components/bt/ble_mesh/mesh_core/include/health_cli.h new file mode 100644 index 0000000000..9d7230ebac --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/include/health_cli.h @@ -0,0 +1,78 @@ +/** @file + * @brief Bluetooth Mesh Health Client Model APIs. + */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _BLE_MESH_HEALTH_CLI_H_ +#define _BLE_MESH_HEALTH_CLI_H_ + +#include "mesh_access.h" +#include "mesh_kernel.h" +#include "model_common.h" + +/** + * @brief Bluetooth Mesh + * @defgroup bt_mesh_health_cli Bluetooth Mesh Health Client Model + * @ingroup bt_mesh + * @{ + */ + +/* Health client model common structure */ +typedef bt_mesh_client_common_t bt_mesh_health_client_t; +typedef bt_mesh_internal_data_t health_internal_data_t; + +typedef bt_mesh_internal_data_t health_client_internal_data_t; + +extern const struct bt_mesh_model_op bt_mesh_health_cli_op[]; + +#define BLE_MESH_MODEL_HEALTH_CLI(cli_data) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_HEALTH_CLI, \ + bt_mesh_health_cli_op, NULL, cli_data) + +int bt_mesh_health_cli_set(struct bt_mesh_model *model); + +int bt_mesh_health_fault_get(struct bt_mesh_msg_ctx *ctx, u16_t cid); + +int bt_mesh_health_fault_clear(struct bt_mesh_msg_ctx *ctx, u16_t cid, + bool need_ack); + +int bt_mesh_health_fault_test(struct bt_mesh_msg_ctx *ctx, + u16_t cid, u8_t test_id, bool need_ack); + +int bt_mesh_health_period_get(struct bt_mesh_msg_ctx *ctx); + +int bt_mesh_health_period_set(struct bt_mesh_msg_ctx *ctx, + u8_t divisor, bool need_ack); + +int bt_mesh_health_attention_get(struct bt_mesh_msg_ctx *ctx); + +int bt_mesh_health_attention_set(struct bt_mesh_msg_ctx *ctx, + u8_t attention, bool need_ack); + +s32_t bt_mesh_health_cli_timeout_get(void); +void bt_mesh_health_cli_timeout_set(s32_t timeout); + +/* Health Client Status Message Context */ + +struct bt_mesh_health_current_status { + u8_t test_id; + u16_t cid; + struct net_buf_simple *fault_array; +}; + +struct bt_mesh_health_fault_status { + u8_t test_id; + u16_t cid; + struct net_buf_simple *fault_array; +}; + +/** + * @} + */ + +#endif /* __BLE_MESH_HEALTH_CLI_H */ diff --git a/components/bt/ble_mesh/mesh_core/include/health_srv.h b/components/bt/ble_mesh/mesh_core/include/health_srv.h new file mode 100644 index 0000000000..4e9b840776 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/include/health_srv.h @@ -0,0 +1,93 @@ +/** @file + * @brief Bluetooth Mesh Health Server Model APIs. + */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _BLE_MESH_HEALTH_SRV_H_ +#define _BLE_MESH_HEALTH_SRV_H_ + +#include "mesh_access.h" +#include "mesh_kernel.h" + +/** + * @brief Bluetooth Mesh Health Server Model + * @defgroup bt_mesh_health_srv Bluetooth Mesh Health Server Model + * @ingroup bt_mesh + * @{ + */ + +struct bt_mesh_health_srv_cb { + /* Fetch current faults */ + int (*fault_get_cur)(struct bt_mesh_model *model, u8_t *test_id, + u16_t *company_id, u8_t *faults, + u8_t *fault_count); + + /* Fetch registered faults */ + int (*fault_get_reg)(struct bt_mesh_model *model, u16_t company_id, + u8_t *test_id, u8_t *faults, + u8_t *fault_count); + + /* Clear registered faults */ + int (*fault_clear)(struct bt_mesh_model *model, u16_t company_id); + + /* Run a specific test */ + int (*fault_test)(struct bt_mesh_model *model, u8_t test_id, + u16_t company_id); + + /* Attention on */ + void (*attn_on)(struct bt_mesh_model *model); + + /* Attention off */ + void (*attn_off)(struct bt_mesh_model *model); +}; + +/** @def BLE_MESH_HEALTH_PUB_DEFINE + * + * A helper to define a health publication context + * + * @param _name Name given to the publication context variable. + * @param _max_faults Maximum number of faults the element can have. + */ +#define BLE_MESH_HEALTH_PUB_DEFINE(_name, _max_faults) \ + BLE_MESH_MODEL_PUB_DEFINE(_name, NULL, (1 + 3 + (_max_faults))) + +/** Mesh Health Server Model Context */ +struct bt_mesh_health_srv { + struct bt_mesh_model *model; + + /* Optional callback struct */ + const struct bt_mesh_health_srv_cb *cb; + + /* Attention Timer state */ + struct k_delayed_work attn_timer; +}; + +extern const struct bt_mesh_model_op bt_mesh_health_srv_op[]; + +/** @def BLE_MESH_MODEL_HEALTH_SRV + * + * Define a new health server model. Note that this API needs to be + * repeated for each element which the application wants to have a + * health server model on. Each instance also needs a unique + * bt_mesh_health_srv and bt_mesh_model_pub context. + * + * @param srv Pointer to a unique struct bt_mesh_health_srv. + * @param pub Pointer to a unique struct bt_mesh_model_pub. + * + * @return New mesh model instance. + */ +#define BLE_MESH_MODEL_HEALTH_SRV(srv, pub) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_HEALTH_SRV, \ + bt_mesh_health_srv_op, pub, srv) + +int bt_mesh_fault_update(struct bt_mesh_elem *elem); + +/** + * @} + */ + +#endif /* __BLE_MESH_HEALTH_SRV_H */ diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_access.h b/components/bt/ble_mesh/mesh_core/include/mesh_access.h new file mode 100644 index 0000000000..bdabab15ca --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/include/mesh_access.h @@ -0,0 +1,444 @@ +/** @file + * @brief Bluetooth Mesh Access Layer APIs. + */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _BLE_MESH_ACCESS_H_ +#define _BLE_MESH_ACCESS_H_ + +#include +#include "mesh_types.h" +#include "mesh_util.h" +#include "mesh_buf.h" +#include "sdkconfig.h" + +/** + * @brief Bluetooth Mesh Access Layer + * @defgroup bt_mesh_access Bluetooth Mesh Access Layer + * @ingroup bt_mesh + * @{ + */ + +#define BLE_MESH_ADDR_UNASSIGNED 0x0000 +#define BLE_MESH_ADDR_ALL_NODES 0xffff +#define BLE_MESH_ADDR_PROXIES 0xfffc +#define BLE_MESH_ADDR_FRIENDS 0xfffd +#define BLE_MESH_ADDR_RELAYS 0xfffe + +#define BLE_MESH_KEY_UNUSED 0xffff +#define BLE_MESH_KEY_DEV 0xfffe + +/** Helper to define a mesh element within an array. + * + * In case the element has no SIG or Vendor models the helper + * macro BLE_MESH_MODEL_NONE can be given instead. + * + * @param _loc Location Descriptor. + * @param _mods Array of models. + * @param _vnd_mods Array of vendor models. + */ +#define BLE_MESH_ELEM(_loc, _mods, _vnd_mods) \ +{ \ + .loc = (_loc), \ + .model_count = ARRAY_SIZE(_mods), \ + .models = (_mods), \ + .vnd_model_count = ARRAY_SIZE(_vnd_mods), \ + .vnd_models = (_vnd_mods), \ +} + +/** Abstraction that describes a Mesh Element */ +struct bt_mesh_elem { + /* Unicast Address. Set at runtime during provisioning. */ + u16_t addr; + + /* Location Descriptor (GATT Bluetooth Namespace Descriptors) */ + const u16_t loc; + + const u8_t model_count; + const u8_t vnd_model_count; + + struct bt_mesh_model *const models; + struct bt_mesh_model *const vnd_models; +}; + +/* Foundation Models */ +#define BLE_MESH_MODEL_ID_CFG_SRV 0x0000 +#define BLE_MESH_MODEL_ID_CFG_CLI 0x0001 +#define BLE_MESH_MODEL_ID_HEALTH_SRV 0x0002 +#define BLE_MESH_MODEL_ID_HEALTH_CLI 0x0003 + +/* Models from the Mesh Model Specification */ +#define BLE_MESH_MODEL_ID_GEN_ONOFF_SRV 0x1000 +#define BLE_MESH_MODEL_ID_GEN_ONOFF_CLI 0x1001 +#define BLE_MESH_MODEL_ID_GEN_LEVEL_SRV 0x1002 +#define BLE_MESH_MODEL_ID_GEN_LEVEL_CLI 0x1003 +#define BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_SRV 0x1004 +#define BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_CLI 0x1005 +#define BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV 0x1006 +#define BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV 0x1007 +#define BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_CLI 0x1008 +#define BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV 0x1009 +#define BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV 0x100a +#define BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_CLI 0x100b +#define BLE_MESH_MODEL_ID_GEN_BATTERY_SRV 0x100c +#define BLE_MESH_MODEL_ID_GEN_BATTERY_CLI 0x100d +#define BLE_MESH_MODEL_ID_GEN_LOCATION_SRV 0x100e +#define BLE_MESH_MODEL_ID_GEN_LOCATION_SETUPSRV 0x100f +#define BLE_MESH_MODEL_ID_GEN_LOCATION_CLI 0x1010 +#define BLE_MESH_MODEL_ID_GEN_ADMIN_PROP_SRV 0x1011 +#define BLE_MESH_MODEL_ID_GEN_MANUFACTURER_PROP_SRV 0x1012 +#define BLE_MESH_MODEL_ID_GEN_USER_PROP_SRV 0x1013 +#define BLE_MESH_MODEL_ID_GEN_CLIENT_PROP_SRV 0x1014 +#define BLE_MESH_MODEL_ID_GEN_PROP_CLI 0x1015 +#define BLE_MESH_MODEL_ID_SENSOR_SRV 0x1100 +#define BLE_MESH_MODEL_ID_SENSOR_SETUP_SRV 0x1101 +#define BLE_MESH_MODEL_ID_SENSOR_CLI 0x1102 +#define BLE_MESH_MODEL_ID_TIME_SRV 0x1200 +#define BLE_MESH_MODEL_ID_TIME_SETUP_SRV 0x1201 +#define BLE_MESH_MODEL_ID_TIME_CLI 0x1202 +#define BLE_MESH_MODEL_ID_SCENE_SRV 0x1203 +#define BLE_MESH_MODEL_ID_SCENE_SETUP_SRV 0x1204 +#define BLE_MESH_MODEL_ID_SCENE_CLI 0x1205 +#define BLE_MESH_MODEL_ID_SCHEDULER_SRV 0x1206 +#define BLE_MESH_MODEL_ID_SCHEDULER_SETUP_SRV 0x1207 +#define BLE_MESH_MODEL_ID_SCHEDULER_CLI 0x1208 +#define BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV 0x1300 +#define BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SETUP_SRV 0x1301 +#define BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_CLI 0x1302 +#define BLE_MESH_MODEL_ID_LIGHT_CTL_SRV 0x1303 +#define BLE_MESH_MODEL_ID_LIGHT_CTL_SETUP_SRV 0x1304 +#define BLE_MESH_MODEL_ID_LIGHT_CTL_CLI 0x1305 +#define BLE_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV 0x1306 +#define BLE_MESH_MODEL_ID_LIGHT_HSL_SRV 0x1307 +#define BLE_MESH_MODEL_ID_LIGHT_HSL_SETUP_SRV 0x1308 +#define BLE_MESH_MODEL_ID_LIGHT_HSL_CLI 0x1309 +#define BLE_MESH_MODEL_ID_LIGHT_HSL_HUE_SRV 0x130a +#define BLE_MESH_MODEL_ID_LIGHT_HSL_SAT_SRV 0x130b +#define BLE_MESH_MODEL_ID_LIGHT_XYL_SRV 0x130c +#define BLE_MESH_MODEL_ID_LIGHT_XYL_SETUP_SRV 0x130d +#define BLE_MESH_MODEL_ID_LIGHT_XYL_CLI 0x130e +#define BLE_MESH_MODEL_ID_LIGHT_LC_SRV 0x130f +#define BLE_MESH_MODEL_ID_LIGHT_LC_SETUPSRV 0x1310 +#define BLE_MESH_MODEL_ID_LIGHT_LC_CLI 0x1311 + +/** Message sending context. */ +struct bt_mesh_msg_ctx { + /** NetKey Index of the subnet to send the message on. */ + u16_t net_idx; + + /** AppKey Index to encrypt the message with. */ + u16_t app_idx; + + /** Remote address. */ + u16_t addr; + + /** Destination address of a received message. Not used for sending. */ + u16_t recv_dst; + + /** Received TTL value. Not used for sending. */ + u8_t recv_ttl: 7; + + /** Force sending reliably by using segment acknowledgement */ + u8_t send_rel: 1; + + /** TTL, or BLE_MESH_TTL_DEFAULT for default TTL. */ + u8_t send_ttl; + + /** Change by Espressif, opcode of a received message. + * Not used for sending message. */ + u32_t recv_op; + + /** Change by Espressif, model corresponds to the message */ + struct bt_mesh_model *model; + + /** Change by Espressif, if the message is sent by a server + * model. Not used for receiving message. */ + bool srv_send; +}; + +struct bt_mesh_model_op { + /* OpCode encoded using the BLE_MESH_MODEL_OP_* macros */ + const u32_t opcode; + + /* Minimum required message length */ + const size_t min_len; + + /* Message handler for the opcode */ + void (*const func)(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf); +}; + +#define BLE_MESH_MODEL_OP_1(b0) (b0) +#define BLE_MESH_MODEL_OP_2(b0, b1) (((b0) << 8) | (b1)) +#define BLE_MESH_MODEL_OP_3(b0, cid) ((((b0) << 16) | 0xc00000) | (cid)) + +#define BLE_MESH_MODEL_OP_END { 0, 0, NULL } +#define BLE_MESH_MODEL_NO_OPS ((struct bt_mesh_model_op []) \ + { BLE_MESH_MODEL_OP_END }) + +/** Helper to define an empty model array */ +#define BLE_MESH_MODEL_NONE ((struct bt_mesh_model []){}) + +#define BLE_MESH_MODEL(_id, _op, _pub, _user_data) \ +{ \ + .id = (_id), \ + .op = _op, \ + .keys = { [0 ... (CONFIG_BLE_MESH_MODEL_KEY_COUNT - 1)] = \ + BLE_MESH_KEY_UNUSED }, \ + .pub = _pub, \ + .groups = { [0 ... (CONFIG_BLE_MESH_MODEL_GROUP_COUNT - 1)] = \ + BLE_MESH_ADDR_UNASSIGNED }, \ + .user_data = _user_data, \ +} + +#define BLE_MESH_MODEL_VND(_company, _id, _op, _pub, _user_data) \ +{ \ + .vnd.company = (_company), \ + .vnd.id = (_id), \ + .op = _op, \ + .pub = _pub, \ + .keys = { [0 ... (CONFIG_BLE_MESH_MODEL_KEY_COUNT - 1)] = \ + BLE_MESH_KEY_UNUSED }, \ + .groups = { [0 ... (CONFIG_BLE_MESH_MODEL_GROUP_COUNT - 1)] = \ + BLE_MESH_ADDR_UNASSIGNED }, \ + .user_data = _user_data, \ +} + +/** @def BLE_MESH_TRANSMIT + * + * @brief Encode transmission count & interval steps. + * + * @param count Number of retransmissions (first transmission is excluded). + * @param int_ms Interval steps in milliseconds. Must be greater than 0 + * and a multiple of 10. + * + * @return Mesh transmit value that can be used e.g. for the default + * values of the configuration model data. + */ +#define BLE_MESH_TRANSMIT(count, int_ms) ((count) | (((int_ms / 10) - 1) << 3)) + +/** @def BLE_MESH_TRANSMIT_COUNT + * + * @brief Decode transmit count from a transmit value. + * + * @param transmit Encoded transmit count & interval value. + * + * @return Transmission count (actual transmissions is N + 1). + */ +#define BLE_MESH_TRANSMIT_COUNT(transmit) (((transmit) & (u8_t)BIT_MASK(3))) + +/** @def BLE_MESH_TRANSMIT_INT + * + * @brief Decode transmit interval from a transmit value. + * + * @param transmit Encoded transmit count & interval value. + * + * @return Transmission interval in milliseconds. + */ +#define BLE_MESH_TRANSMIT_INT(transmit) ((((transmit) >> 3) + 1) * 10) + +/** @def BLE_MESH_PUB_TRANSMIT + * + * @brief Encode Publish Retransmit count & interval steps. + * + * @param count Number of retransmissions (first transmission is excluded). + * @param int_ms Interval steps in milliseconds. Must be greater than 0 + * and a multiple of 50. + * + * @return Mesh transmit value that can be used e.g. for the default + * values of the configuration model data. + */ +#define BLE_MESH_PUB_TRANSMIT(count, int_ms) BLE_MESH_TRANSMIT(count, (int_ms) / 5) + +/** @def BLE_MESH_PUB_TRANSMIT_COUNT + * + * @brief Decode Pubhlish Retransmit count from a given value. + * + * @param transmit Encoded Publish Retransmit count & interval value. + * + * @return Retransmission count (actual transmissions is N + 1). + */ +#define BLE_MESH_PUB_TRANSMIT_COUNT(transmit) BLE_MESH_TRANSMIT_COUNT(transmit) + +/** @def BLE_MESH_PUB_TRANSMIT_INT + * + * @brief Decode Publish Retransmit interval from a given value. + * + * @param transmit Encoded Publish Retransmit count & interval value. + * + * @return Transmission interval in milliseconds. + */ +#define BLE_MESH_PUB_TRANSMIT_INT(transmit) ((((transmit) >> 3) + 1) * 50) + +/** Model publication context. */ +struct bt_mesh_model_pub { + /** The model the context belongs to. Initialized by the stack. */ + struct bt_mesh_model *mod; + + u16_t addr; /**< Publish Address. */ + u16_t key; /**< Publish AppKey Index. */ + + u8_t ttl; /**< Publish Time to Live. */ + u8_t retransmit; /**< Retransmit Count & Interval Steps. */ + u8_t period; /**< Publish Period. */ + u16_t period_div: 4, /**< Divisor for the Period. */ + cred: 1, /**< Friendship Credentials Flag. */ + fast_period: 1, /**< Use FastPeriodDivisor */ + count: 3; /**< Retransmissions left. */ + + u32_t period_start; /**< Start of the current period. */ + + /** @brief Publication buffer, containing the publication message. + * + * This will get correctly created when the publication context + * has been defined using the BLE_MESH_MODEL_PUB_DEFINE macro. + * + * BLE_MESH_MODEL_PUB_DEFINE(name, update, size); + */ + struct net_buf_simple *msg; + + /** @brief Callback for updating the publication buffer. + * + * When set to NULL, the model is assumed not to support + * periodic publishing. When set to non-NULL the callback + * will be called periodically and is expected to update + * @ref bt_mesh_model_pub.msg with a valid publication + * message. + * + * @param mod The Model the Publication Context belogs to. + * + * @return Zero on success or (negative) error code otherwise. + */ + int (*update)(struct bt_mesh_model *mod); + + /* Change by Espressif, role of the device going to publish messages */ + u8_t dev_role; + + /** Publish Period Timer. Only for stack-internal use. */ + struct k_delayed_work timer; +}; + +/** @def BLE_MESH_MODEL_PUB_DEFINE + * + * Define a model publication context. + * + * @param _name Variable name given to the context. + * @param _update Optional message update callback (may be NULL). + * @param _msg_len Length of the publication message. + */ +#define BLE_MESH_MODEL_PUB_DEFINE(_name, _update, _msg_len) \ + NET_BUF_SIMPLE_DEFINE_STATIC(bt_mesh_pub_msg_##_name, _msg_len); \ + static struct bt_mesh_model_pub _name = { \ + .update = _update, \ + .msg = &bt_mesh_pub_msg_##_name, \ + } + +/** Abstraction that describes a Mesh Model instance */ +struct bt_mesh_model { + union { + const u16_t id; + struct { + u16_t company; + u16_t id; + } vnd; + }; + + /* Internal information, mainly for persistent storage */ + u8_t elem_idx; /* Belongs to Nth element */ + u8_t model_idx; /* Is the Nth model in the element */ + u16_t flags; /* Information about what has changed */ + + /* The Element this Model belongs to */ + struct bt_mesh_elem *elem; + + /* Model Publication */ + struct bt_mesh_model_pub *const pub; + + /* AppKey List */ + u16_t keys[CONFIG_BLE_MESH_MODEL_KEY_COUNT]; + + /* Subscription List (group or virtual addresses) */ + u16_t groups[CONFIG_BLE_MESH_MODEL_GROUP_COUNT]; + + const struct bt_mesh_model_op *const op; + + /* Model-specific user data */ + void *user_data; +}; + +struct bt_mesh_send_cb { + void (*start)(u16_t duration, int err, void *cb_data); + void (*end)(int err, void *cb_data); +}; + +void bt_mesh_model_msg_init(struct net_buf_simple *msg, u32_t opcode); + +/** Special TTL value to request using configured default TTL */ +#define BLE_MESH_TTL_DEFAULT 0xff + +/** Maximum allowed TTL value */ +#define BLE_MESH_TTL_MAX 0x7f + +/** + * @brief Send an Access Layer message. + * + * @param model Mesh (client) Model that the message belongs to. + * @param ctx Message context, includes keys, TTL, etc. + * @param msg Access Layer payload (the actual message to be sent). + * @param cb Optional "message sent" callback. + * @param cb_data User data to be passed to the callback. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_model_send(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *msg, + const struct bt_mesh_send_cb *cb, + void *cb_data); + +/** + * @brief Send a model publication message. + * + * Before calling this function, the user needs to ensure that the model + * publication message (@ref bt_mesh_model_pub.msg) contains a valid + * message to be sent. Note that this API is only to be used for + * non-period publishing. For periodic publishing the app only needs + * to make sure that @ref bt_mesh_model_pub.msg contains a valid message + * whenever the @ref bt_mesh_model_pub.update callback is called. + * + * @param model Mesh (client) Model that's publishing the message. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_model_publish(struct bt_mesh_model *model); + +/** + * @brief Get the element that a model belongs to. + * + * @param mod Mesh model. + * + * @return Pointer to the element that the given model belongs to. + */ +struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod); + +/** Node Composition */ +struct bt_mesh_comp { + u16_t cid; + u16_t pid; + u16_t vid; + + size_t elem_count; + struct bt_mesh_elem *elem; +}; + +/** + * @} + */ + +#endif /* __BLE_MESH_ACCESS_H */ diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_aes_encrypt.h b/components/bt/ble_mesh/mesh_core/include/mesh_aes_encrypt.h new file mode 100644 index 0000000000..afaa6b27dd --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/include/mesh_aes_encrypt.h @@ -0,0 +1,171 @@ +/* aes.h - TinyCrypt interface to an AES-128 implementation */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * @brief -- Interface to an AES-128 implementation. + * + * Overview: AES-128 is a NIST approved block cipher specified in + * FIPS 197. Block ciphers are deterministic algorithms that + * perform a transformation specified by a symmetric key in fixed- + * length data sets, also called blocks. + * + * Security: AES-128 provides approximately 128 bits of security. + * + * Usage: 1) call tc_aes128_set_encrypt/decrypt_key to set the key. + * + * 2) call tc_aes_encrypt/decrypt to process the data. + */ + +#ifndef _BLE_MESH_AES_ENCRYPT_H_ +#define _BLE_MESH_AES_ENCRYPT_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define Nb (4) /* number of columns (32-bit words) comprising the state */ +#define Nk (4) /* number of 32-bit words comprising the key */ +#define Nr (10) /* number of rounds */ +#define TC_AES_BLOCK_SIZE (Nb*Nk) +#define TC_AES_KEY_SIZE (Nb*Nk) + +#define TC_CRYPTO_SUCCESS 1 +#define TC_CRYPTO_FAIL 0 + +#define TC_ZERO_BYTE 0x00 + +/* padding for last message block */ +#define TC_CMAC_PADDING 0x80 + +typedef struct tc_aes_key_sched_struct { + unsigned int words[Nb * (Nr + 1)]; +} *TCAesKeySched_t; + +/* struct tc_cmac_struct represents the state of a CMAC computation */ +typedef struct tc_cmac_struct { + /* initialization vector */ + uint8_t iv[TC_AES_BLOCK_SIZE]; + /* used if message length is a multiple of block_size bytes */ + uint8_t K1[TC_AES_BLOCK_SIZE]; + /* used if message length isn't a multiple block_size bytes */ + uint8_t K2[TC_AES_BLOCK_SIZE]; + /* where to put bytes that didn't fill a block */ + uint8_t leftover[TC_AES_BLOCK_SIZE]; + /* identifies the encryption key */ + unsigned int keyid; + /* next available leftover location */ + unsigned int leftover_offset; + /* AES key schedule */ + TCAesKeySched_t sched; + /* calls to tc_cmac_update left before re-key */ + uint64_t countdown; +} *TCCmacState_t; + +/** + * @brief Set AES-128 encryption key + * Uses key k to initialize s + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: s == NULL or k == NULL + * @note This implementation skips the additional steps required for keys + * larger than 128 bits, and must not be used for AES-192 or + * AES-256 key schedule -- see FIPS 197 for details + * @param s IN/OUT -- initialized struct tc_aes_key_sched_struct + * @param k IN -- points to the AES key + */ +int tc_aes128_set_encrypt_key(TCAesKeySched_t s, const uint8_t *k); + +/** + * @brief AES-128 Encryption procedure + * Encrypts contents of in buffer into out buffer under key; + * schedule s + * @note Assumes s was initialized by aes_set_encrypt_key; + * out and in point to 16 byte buffers + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: out == NULL or in == NULL or s == NULL + * @param out IN/OUT -- buffer to receive ciphertext block + * @param in IN -- a plaintext block to encrypt + * @param s IN -- initialized AES key schedule + */ +int tc_aes_encrypt(uint8_t *out, const uint8_t *in, + const TCAesKeySched_t s); + +/** + * @brief Set the AES-128 decryption key + * Uses key k to initialize s + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: s == NULL or k == NULL + * @note This is the implementation of the straightforward inverse cipher + * using the cipher documented in FIPS-197 figure 12, not the + * equivalent inverse cipher presented in Figure 15 + * @warning This routine skips the additional steps required for keys larger + * than 128, and must not be used for AES-192 or AES-256 key + * schedule -- see FIPS 197 for details + * @param s IN/OUT -- initialized struct tc_aes_key_sched_struct + * @param k IN -- points to the AES key + */ +int tc_aes128_set_decrypt_key(TCAesKeySched_t s, const uint8_t *k); + +/** + * @brief AES-128 Encryption procedure + * Decrypts in buffer into out buffer under key schedule s + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: out is NULL or in is NULL or s is NULL + * @note Assumes s was initialized by aes_set_encrypt_key + * out and in point to 16 byte buffers + * @param out IN/OUT -- buffer to receive ciphertext block + * @param in IN -- a plaintext block to encrypt + * @param s IN -- initialized AES key schedule + */ +int tc_aes_decrypt(uint8_t *out, const uint8_t *in, + const TCAesKeySched_t s); + +int tc_cmac_setup(TCCmacState_t s, const uint8_t *key, TCAesKeySched_t sched); + +void gf_double(uint8_t *out, uint8_t *in); + +int tc_cmac_init(TCCmacState_t s); + +int tc_cmac_update(TCCmacState_t s, const uint8_t *data, size_t data_length); + +int tc_cmac_final(uint8_t *tag, TCCmacState_t s); + +int tc_cmac_erase(TCCmacState_t s); + +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_AES_ENCRYPT_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_atomic.h b/components/bt/ble_mesh/mesh_core/include/mesh_atomic.h new file mode 100644 index 0000000000..5c8bf17b89 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/include/mesh_atomic.h @@ -0,0 +1,305 @@ +/* atomic operations */ + +/* + * Copyright (c) 1997-2015, Wind River Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BLE_MESH_ATOMIC_H_ +#define _BLE_MESH_ATOMIC_H_ + +#include "mesh_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef bt_mesh_atomic_t bt_mesh_atomic_val_t; + +/** + * @defgroup atomic_apis Atomic Services APIs + * @ingroup kernel_apis + * @{ + */ + +/** + * + * @brief Atomic increment. + * + * This routine performs an atomic increment by 1 on @a target. + * + * @param target Address of atomic variable. + * + * @return Previous value of @a target. + */ +#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN +static inline bt_mesh_atomic_val_t bt_mesh_atomic_inc(bt_mesh_atomic_t *target) +{ + return bt_mesh_atomic_add(target, 1); +} +#else +extern bt_mesh_atomic_val_t bt_mesh_atomic_inc(bt_mesh_atomic_t *target); +#endif + +/** + * + * @brief Atomic decrement. + * + * This routine performs an atomic decrement by 1 on @a target. + * + * @param target Address of atomic variable. + * + * @return Previous value of @a target. + */ +#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN +static inline bt_mesh_atomic_val_t bt_mesh_atomic_dec(bt_mesh_atomic_t *target) +{ + return bt_mesh_atomic_sub(target, 1); +} +#else +extern bt_mesh_atomic_val_t bt_mesh_atomic_dec(bt_mesh_atomic_t *target); +#endif + +/** + * + * @brief Atomic get. + * + * This routine performs an atomic read on @a target. + * + * @param target Address of atomic variable. + * + * @return Value of @a target. + */ +#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN +static inline bt_mesh_atomic_val_t bt_mesh_atomic_get(const bt_mesh_atomic_t *target) +{ + return __atomic_load_n(target, __ATOMIC_SEQ_CST); +} +#else +extern bt_mesh_atomic_val_t bt_mesh_atomic_get(const bt_mesh_atomic_t *target); +#endif + +/** + * + * @brief Atomic get-and-set. + * + * This routine atomically sets @a target to @a value and returns + * the previous value of @a target. + * + * @param target Address of atomic variable. + * @param value Value to write to @a target. + * + * @return Previous value of @a target. + */ +#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN +static inline bt_mesh_atomic_val_t bt_mesh_atomic_set(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t value) +{ + /* This builtin, as described by Intel, is not a traditional + * test-and-set operation, but rather an atomic exchange operation. It + * writes value into *ptr, and returns the previous contents of *ptr. + */ + return __atomic_exchange_n(target, value, __ATOMIC_SEQ_CST); +} +#else +extern bt_mesh_atomic_val_t bt_mesh_atomic_set(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t value); +#endif + +/** + * + * @brief Atomic bitwise inclusive OR. + * + * This routine atomically sets @a target to the bitwise inclusive OR of + * @a target and @a value. + * + * @param target Address of atomic variable. + * @param value Value to OR. + * + * @return Previous value of @a target. + */ +#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN +static inline bt_mesh_atomic_val_t bt_mesh_atomic_or(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t value) +{ + return __atomic_fetch_or(target, value, __ATOMIC_SEQ_CST); +} +#else +extern bt_mesh_atomic_val_t bt_mesh_atomic_or(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t value); +#endif + +/** + * + * @brief Atomic bitwise AND. + * + * This routine atomically sets @a target to the bitwise AND of @a target + * and @a value. + * + * @param target Address of atomic variable. + * @param value Value to AND. + * + * @return Previous value of @a target. + */ +#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN +static inline bt_mesh_atomic_val_t bt_mesh_atomic_and(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t value) +{ + return __atomic_fetch_and(target, value, __ATOMIC_SEQ_CST); +} +#else +extern bt_mesh_atomic_val_t bt_mesh_atomic_and(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t value); +#endif + +/** + * @cond INTERNAL_HIDDEN + */ + +#define BLE_MESH_ATOMIC_BITS (sizeof(bt_mesh_atomic_val_t) * 8) +#define BLE_MESH_ATOMIC_MASK(bit) (1 << ((bit) & (BLE_MESH_ATOMIC_BITS - 1))) +#define BLE_MESH_ATOMIC_ELEM(addr, bit) ((addr) + ((bit) / BLE_MESH_ATOMIC_BITS)) + +/** + * INTERNAL_HIDDEN @endcond + */ + +/** + * @brief Define an array of atomic variables. + * + * This macro defines an array of atomic variables containing at least + * @a num_bits bits. + * + * @note + * If used from file scope, the bits of the array are initialized to zero; + * if used from within a function, the bits are left uninitialized. + * + * @param name Name of array of atomic variables. + * @param num_bits Number of bits needed. + */ +#define BLE_MESH_ATOMIC_DEFINE(name, num_bits) \ + bt_mesh_atomic_t name[1 + ((num_bits) - 1) / BLE_MESH_ATOMIC_BITS] + +/** + * @brief Atomically test a bit. + * + * This routine tests whether bit number @a bit of @a target is set or not. + * The target may be a single atomic variable or an array of them. + * + * @param target Address of atomic variable or array. + * @param bit Bit number (starting from 0). + * + * @return 1 if the bit was set, 0 if it wasn't. + */ +static inline int bt_mesh_atomic_test_bit(const bt_mesh_atomic_t *target, int bit) +{ + bt_mesh_atomic_val_t val = bt_mesh_atomic_get(BLE_MESH_ATOMIC_ELEM(target, bit)); + + return (1 & (val >> (bit & (BLE_MESH_ATOMIC_BITS - 1)))); +} + +/** + * @brief Atomically test and clear a bit. + * + * Atomically clear bit number @a bit of @a target and return its old value. + * The target may be a single atomic variable or an array of them. + * + * @param target Address of atomic variable or array. + * @param bit Bit number (starting from 0). + * + * @return 1 if the bit was set, 0 if it wasn't. + */ +static inline int bt_mesh_atomic_test_and_clear_bit(bt_mesh_atomic_t *target, int bit) +{ + bt_mesh_atomic_val_t mask = BLE_MESH_ATOMIC_MASK(bit); + bt_mesh_atomic_val_t old; + + old = bt_mesh_atomic_and(BLE_MESH_ATOMIC_ELEM(target, bit), ~mask); + + return (old & mask) != 0; +} + +/** + * @brief Atomically set a bit. + * + * Atomically set bit number @a bit of @a target and return its old value. + * The target may be a single atomic variable or an array of them. + * + * @param target Address of atomic variable or array. + * @param bit Bit number (starting from 0). + * + * @return 1 if the bit was set, 0 if it wasn't. + */ +static inline int bt_mesh_atomic_test_and_set_bit(bt_mesh_atomic_t *target, int bit) +{ + bt_mesh_atomic_val_t mask = BLE_MESH_ATOMIC_MASK(bit); + bt_mesh_atomic_val_t old; + + old = bt_mesh_atomic_or(BLE_MESH_ATOMIC_ELEM(target, bit), mask); + + return (old & mask) != 0; +} + +/** + * @brief Atomically clear a bit. + * + * Atomically clear bit number @a bit of @a target. + * The target may be a single atomic variable or an array of them. + * + * @param target Address of atomic variable or array. + * @param bit Bit number (starting from 0). + * + * @return N/A + */ +static inline void bt_mesh_atomic_clear_bit(bt_mesh_atomic_t *target, int bit) +{ + bt_mesh_atomic_val_t mask = BLE_MESH_ATOMIC_MASK(bit); + + (void)bt_mesh_atomic_and(BLE_MESH_ATOMIC_ELEM(target, bit), ~mask); +} + +/** + * @brief Atomically set a bit. + * + * Atomically set bit number @a bit of @a target. + * The target may be a single atomic variable or an array of them. + * + * @param target Address of atomic variable or array. + * @param bit Bit number (starting from 0). + * + * @return N/A + */ +static inline void bt_mesh_atomic_set_bit(bt_mesh_atomic_t *target, int bit) +{ + bt_mesh_atomic_val_t mask = BLE_MESH_ATOMIC_MASK(bit); + + (void)bt_mesh_atomic_or(BLE_MESH_ATOMIC_ELEM(target, bit), mask); +} + +/** + * @brief Atomically set a bit to a given value. + * + * Atomically set bit number @a bit of @a target to value @a val. + * The target may be a single atomic variable or an array of them. + * + * @param target Address of atomic variable or array. + * @param bit Bit number (starting from 0). + * @param val true for 1, false for 0. + * + * @return N/A + */ +static inline void bt_mesh_atomic_set_bit_to(bt_mesh_atomic_t *target, int bit, bool val) +{ + bt_mesh_atomic_val_t mask = BLE_MESH_ATOMIC_MASK(bit); + + if (val) { + (void)bt_mesh_atomic_or(BLE_MESH_ATOMIC_ELEM(target, bit), mask); + } else { + (void)bt_mesh_atomic_and(BLE_MESH_ATOMIC_ELEM(target, bit), ~mask); + } +} + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_ATOMIC_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_bearer_adapt.h b/components/bt/ble_mesh/mesh_core/include/mesh_bearer_adapt.h new file mode 100644 index 0000000000..1382031878 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/include/mesh_bearer_adapt.h @@ -0,0 +1,733 @@ +/* + * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2015-2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BLE_MESH_BEARER_ADRPT_H_ +#define _BLE_MESH_BEARER_ADRPT_H_ + +#include +#include "mesh_types.h" +#include "mesh_util.h" +#include "mesh_buf.h" +#include "mesh_uuid.h" + +/* BLE Mesh Max Connection Count */ +#define BLE_MESH_MAX_CONN CONFIG_BT_ACL_CONNECTIONS + +/* BD ADDR types */ +#define BLE_MESH_ADDR_PUBLIC 0x00 +#define BLE_MESH_ADDR_RANDOM 0x01 +#define BLE_MESH_ADDR_PUBLIC_ID 0x02 +#define BLE_MESH_ADDR_RANDOM_ID 0x03 + +/* BD ADDR length */ +#define BLE_MESH_ADDR_LEN 0x06 + +/* Advertising types */ +#define BLE_MESH_ADV_IND 0x00 +#define BLE_MESH_ADV_DIRECT_IND 0x01 +#define BLE_MESH_ADV_SCAN_IND 0x02 +#define BLE_MESH_ADV_NONCONN_IND 0x03 +#define BLE_MESH_ADV_DIRECT_IND_LOW_DUTY 0x04 + +/* advertising channel map */ +#define BLE_MESH_ADV_CHNL_37 BIT(0) +#define BLE_MESH_ADV_CHNL_38 BIT(1) +#define BLE_MESH_ADV_CHNL_39 BIT(2) + +/* Advertising filter policy */ +#define BLE_MESH_AP_SCAN_CONN_ALL 0x00 +#define BLE_MESH_AP_SCAN_WL_CONN_ALL 0x01 +#define BLE_MESH_AP_SCAN_ALL_CONN_WL 0x02 +#define BLE_MESH_AP_SCAN_CONN_WL 0x03 + +/* Scan types */ +#define BLE_MESH_SCAN_PASSIVE 0x00 +#define BLE_MESH_SCAN_ACTIVE 0x01 + +/* Scan operation */ +#define BLE_MESH_SCAN_DISABLE 0x00 +#define BLE_MESH_SCAN_ENABLE 0x01 + +/* Scan duplicate operation */ +#define BLE_MESH_SCAN_FILTER_DUP_DISABLE 0x00 +#define BLE_MESH_SCAN_FILTER_DUP_ENABLE 0x01 + +/* Scan filter policy */ +#define BLE_MESH_SP_ADV_ALL 0x00 +#define BLE_MESH_SP_ADV_WL 0x01 +#define BLE_MESH_SP_ADV_ALL_RPA_DIR_ADV 0x02 +#define BLE_MESH_SP_ADV_WL_RPA_DIR_ADV 0x03 + +/* Error codes for Error response PDU */ +#define BLE_MESH_ATT_ERR_INVALID_HANDLE 0x01 +#define BLE_MESH_ATT_ERR_READ_NOT_PERMITTED 0x02 +#define BLE_MESH_ATT_ERR_WRITE_NOT_PERMITTED 0x03 +#define BLE_MESH_ATT_ERR_INVALID_PDU 0x04 +#define BLE_MESH_ATT_ERR_AUTHENTICATION 0x05 +#define BLE_MESH_ATT_ERR_NOT_SUPPORTED 0x06 +#define BLE_MESH_ATT_ERR_INVALID_OFFSET 0x07 +#define BLE_MESH_ATT_ERR_AUTHORIZATION 0x08 +#define BLE_MESH_ATT_ERR_PREPARE_QUEUE_FULL 0x09 +#define BLE_MESH_ATT_ERR_ATTRIBUTE_NOT_FOUND 0x0a +#define BLE_MESH_ATT_ERR_ATTRIBUTE_NOT_LONG 0x0b +#define BLE_MESH_ATT_ERR_ENCRYPTION_KEY_SIZE 0x0c +#define BLE_MESH_ATT_ERR_INVALID_ATTRIBUTE_LEN 0x0d +#define BLE_MESH_ATT_ERR_UNLIKELY 0x0e +#define BLE_MESH_ATT_ERR_INSUFFICIENT_ENCRYPTION 0x0f +#define BLE_MESH_ATT_ERR_UNSUPPORTED_GROUP_TYPE 0x10 +#define BLE_MESH_ATT_ERR_INSUFFICIENT_RESOURCES 0x11 + +/* Common Profile Error Codes (from CSS) */ +#define BLE_MESH_ATT_ERR_WRITE_REQ_REJECTED 0xfc +#define BLE_MESH_ATT_ERR_CCC_IMPROPER_CONF 0xfd +#define BLE_MESH_ATT_ERR_PROCEDURE_IN_PROGRESS 0xfe +#define BLE_MESH_ATT_ERR_OUT_OF_RANGE 0xff + +/* EIR/AD data type definitions */ +#define BLE_MESH_DATA_FLAGS 0x01 /* AD flags */ +#define BLE_MESH_DATA_UUID16_SOME 0x02 /* 16-bit UUID, more available */ +#define BLE_MESH_DATA_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ +#define BLE_MESH_DATA_UUID32_SOME 0x04 /* 32-bit UUID, more available */ +#define BLE_MESH_DATA_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ +#define BLE_MESH_DATA_UUID128_SOME 0x06 /* 128-bit UUID, more available */ +#define BLE_MESH_DATA_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ +#define BLE_MESH_DATA_NAME_SHORTENED 0x08 /* Shortened name */ +#define BLE_MESH_DATA_NAME_COMPLETE 0x09 /* Complete name */ +#define BLE_MESH_DATA_TX_POWER 0x0a /* Tx Power */ +#define BLE_MESH_DATA_SOLICIT16 0x14 /* Solicit UUIDs, 16-bit */ +#define BLE_MESH_DATA_SOLICIT128 0x15 /* Solicit UUIDs, 128-bit */ +#define BLE_MESH_DATA_SVC_DATA16 0x16 /* Service data, 16-bit UUID */ +#define BLE_MESH_DATA_GAP_APPEARANCE 0x19 /* GAP appearance */ +#define BLE_MESH_DATA_SOLICIT32 0x1f /* Solicit UUIDs, 32-bit */ +#define BLE_MESH_DATA_SVC_DATA32 0x20 /* Service data, 32-bit UUID */ +#define BLE_MESH_DATA_SVC_DATA128 0x21 /* Service data, 128-bit UUID */ +#define BLE_MESH_DATA_URI 0x24 /* URI */ +#define BLE_MESH_DATA_MESH_PROV 0x29 /* Mesh Provisioning PDU */ +#define BLE_MESH_DATA_MESH_MESSAGE 0x2a /* Mesh Networking PDU */ +#define BLE_MESH_DATA_MESH_BEACON 0x2b /* Mesh Beacon */ + +#define BLE_MESH_DATA_MANUFACTURER_DATA 0xff /* Manufacturer Specific Data */ + +#define BLE_MESH_AD_LIMITED 0x01 /* Limited Discoverable */ +#define BLE_MESH_AD_GENERAL 0x02 /* General Discoverable */ +#define BLE_MESH_AD_NO_BREDR 0x04 /* BR/EDR not supported */ + +/* Client Characteristic Configuration Values */ + +/** @def BLE_MESH_GATT_CCC_NOTIFY + * @brief Client Characteristic Configuration Notification. + * + * If set, changes to Characteristic Value shall be notified. + */ +#define BLE_MESH_GATT_CCC_NOTIFY 0x0001 + +/** @def BLE_MESH_GATT_CCC_INDICATE + * @brief Client Characteristic Configuration Indication. + * + * If set, changes to Characteristic Value shall be indicated. + */ +#define BLE_MESH_GATT_CCC_INDICATE 0x0002 + +/** @def BLE_MESH_GATT_ERR + * @brief Construct error return value for attribute read and write callbacks. + * + * @param _att_err ATT error code + * + * @return Appropriate error code for the attribute callbacks. + * + */ +#define BLE_MESH_GATT_ERR(_att_err) (-(_att_err)) + +enum { + BLE_MESH_GATT_ITER_STOP = 0, + BLE_MESH_GATT_ITER_CONTINUE, +}; + +/* GATT attribute permission bit field values */ +enum { + /** No operations supported, e.g. for notify-only */ + BLE_MESH_GATT_PERM_NONE = 0, + + /** Attribute read permission. */ + BLE_MESH_GATT_PERM_READ = BIT(0), + + /** Attribute write permission. */ + BLE_MESH_GATT_PERM_WRITE = BIT(1), + + /** Attribute read permission with encryption. + * + * If set, requires encryption for read access. + */ + BLE_MESH_GATT_PERM_READ_ENCRYPT = BIT(2), + + /** Attribute write permission with encryption. + * + * If set, requires encryption for write access. + */ + BLE_MESH_GATT_PERM_WRITE_ENCRYPT = BIT(3), + + /** Attribute read permission with authentication. + * + * If set, requires encryption using authenticated link-key for read + * access. + */ + BLE_MESH_GATT_PERM_READ_AUTHEN = BIT(4), + + /** Attribute write permission with authentication. + * + * If set, requires encryption using authenticated link-key for write + * access. + */ + BLE_MESH_GATT_PERM_WRITE_AUTHEN = BIT(5), + + /** Attribute prepare write permission. + * + * If set, allows prepare writes with use of BT_GATT_WRITE_FLAG_PREPARE + * passed to write callback. + */ + BLE_MESH_GATT_PERM_PREPARE_WRITE = BIT(6), +}; + +/** Advertising options */ +enum { + /** Convenience value when no options are specified. */ + BLE_MESH_ADV_OPT_NONE = 0, + + /** Advertise as connectable. Type of advertising is determined by + * providing SCAN_RSP data and/or enabling local privacy support. + */ + BLE_MESH_ADV_OPT_CONNECTABLE = BIT(0), + + /** Don't try to resume connectable advertising after a connection. + * This option is only meaningful when used together with + * BLE_MESH_ADV_OPT_CONNECTABLE. If set the advertising will be stopped + * when bt_le_adv_stop() is called or when an incoming (slave) + * connection happens. If this option is not set the stack will + * take care of keeping advertising enabled even as connections + * occur. + */ + BLE_MESH_ADV_OPT_ONE_TIME = BIT(1), +}; + +/* Defined GAP timers */ +#define BLE_MESH_GAP_SCAN_FAST_INTERVAL 0x0060 /* 60 ms */ +#define BLE_MESH_GAP_SCAN_FAST_WINDOW 0x0030 /* 30 ms */ +#define BLE_MESH_GAP_SCAN_SLOW_INTERVAL_1 0x0800 /* 1.28 s */ +#define BLE_MESH_GAP_SCAN_SLOW_WINDOW_1 0x0012 /* 11.25 ms */ +#define BLE_MESH_GAP_SCAN_SLOW_INTERVAL_2 0x1000 /* 2.56 s */ +#define BLE_MESH_GAP_SCAN_SLOW_WINDOW_2 0x0012 /* 11.25 ms */ +#define BLE_MESH_GAP_ADV_FAST_INT_MIN_0 0x0020 /* 20 ms */ +#define BLE_MESH_GAP_ADV_FAST_INT_MAX_0 0x0020 /* 20 ms */ +#define BLE_MESH_GAP_ADV_FAST_INT_MIN_1 0x0030 /* 30 ms */ +#define BLE_MESH_GAP_ADV_FAST_INT_MAX_1 0x0060 /* 60 ms */ +#define BLE_MESH_GAP_ADV_FAST_INT_MIN_2 0x00a0 /* 100 ms */ +#define BLE_MESH_GAP_ADV_FAST_INT_MAX_2 0x00f0 /* 150 ms */ +#define BLE_MESH_GAP_ADV_SLOW_INT_MIN 0x0320 /* 500 ms */ +#define BLE_MESH_GAP_ADV_SLOW_INT_MAX 0x0320 /* 500 ms */ +#define BLE_MESH_GAP_INIT_CONN_INT_MIN 0x0018 /* 30 ms */ +#define BLE_MESH_GAP_INIT_CONN_INT_MAX 0x0028 /* 50 ms */ + +/* Characteristic Properties Bit field values */ + +/** @def BLE_MESH_GATT_CHRC_BROADCAST + * @brief Characteristic broadcast property. + * + * If set, permits broadcasts of the Characteristic Value using Server + * Characteristic Configuration Descriptor. + */ +#define BLE_MESH_GATT_CHRC_BROADCAST 0x01 + +/** @def BLE_MESH_GATT_CHRC_READ + * @brief Characteristic read property. + * + * If set, permits reads of the Characteristic Value. + */ +#define BLE_MESH_GATT_CHRC_READ 0x02 + +/** @def BLE_MESH_GATT_CHRC_WRITE_WITHOUT_RESP + * @brief Characteristic write without response property. + * + * If set, permits write of the Characteristic Value without response. + */ +#define BLE_MESH_GATT_CHRC_WRITE_WITHOUT_RESP 0x04 + +/** @def BLE_MESH_GATT_CHRC_WRITE + * @brief Characteristic write with response property. + * + * If set, permits write of the Characteristic Value with response. + */ +#define BLE_MESH_GATT_CHRC_WRITE 0x08 + +/** @def BLE_MESH_GATT_CHRC_NOTIFY + * @brief Characteristic notify property. + * + * If set, permits notifications of a Characteristic Value without + * acknowledgment. + */ +#define BLE_MESH_GATT_CHRC_NOTIFY 0x10 + +/** @def BLE_MESH_GATT_CHRC_INDICATE + * @brief Characteristic indicate property. + * + * If set, permits indications of a Characteristic Value with acknowledgment. + */ +#define BLE_MESH_GATT_CHRC_INDICATE 0x20 + +/** @def BLE_MESH_GATT_CHRC_AUTH + * @brief Characteristic Authenticated Signed Writes property. + * + * If set, permits signed writes to the Characteristic Value. + */ +#define BLE_MESH_GATT_CHRC_AUTH 0x40 + +/** @def BLE_MESH_GATT_CHRC_EXT_PROP + * @brief Characteristic Extended Properties property. + * + * If set, additional characteristic properties are defined in the + * Characteristic Extended Properties Descriptor. + */ +#define BLE_MESH_GATT_CHRC_EXT_PROP 0x80 + +/** @brief Characteristic Attribute Value. */ +struct bt_mesh_gatt_char { + /** Characteristic UUID. */ + const struct bt_mesh_uuid *uuid; + /** Characteristic properties. */ + u8_t properties; +}; + +/** @brief GATT Service structure */ +struct bt_mesh_gatt_service { + /** Service Attributes */ + struct bt_mesh_gatt_attr *attrs; + /** Service Attribute count */ + u16_t attr_count; + sys_snode_t node; +}; + +struct bt_mesh_ecb_param { + u8_t key[16]; + u8_t clear_text[16]; + u8_t cipher_text[16]; +} __packed; + +typedef struct { + u8_t type; + u8_t val[6]; +} bt_mesh_addr_t; + +/** Description of different data types that can be encoded into + * advertising data. Used to form arrays that are passed to the + * bt_le_adv_start() function. + */ +struct bt_mesh_adv_data { + u8_t type; + u8_t data_len; + const u8_t *data; +}; + +/** @brief Helper to declare elements of bt_data arrays + * + * This macro is mainly for creating an array of struct + * bt_mesh_adv_data elements which is then passed to + * bt_le_adv_start(). + * + * @param _type Type of advertising data field + * @param _data Pointer to the data field payload + * @param _data_len Number of bytes behind the _data pointer + */ +#define BLE_MESH_ADV_DATA(_type, _data, _data_len) \ + { \ + .type = (_type), \ + .data_len = (_data_len), \ + .data = (const u8_t *)(_data), \ + } + +/** @brief Helper to declare elements of bt_data arrays + * + * This macro is mainly for creating an array of struct bt_mesh_adv_data + * elements which is then passed to bt_le_adv_start(). + * + * @param _type Type of advertising data field + * @param _bytes Variable number of single-byte parameters + */ +#define BLE_MESH_ADV_DATA_BYTES(_type, _bytes...) \ + BLE_MESH_ADV_DATA(_type, ((u8_t []) { _bytes }), \ + sizeof((u8_t []) { _bytes })) + +/* BLE Mesh Advertising Parameters */ +struct bt_mesh_adv_param { + /** Bit-field of advertising options */ + u8_t options; + + /** Minimum Advertising Interval (N * 0.625) */ + u16_t interval_min; + + /** Maximum Advertising Interval (N * 0.625) */ + u16_t interval_max; +}; + +/* BLE Mesh scan parameters */ +struct bt_mesh_scan_param { + /** Scan type (BLE_MESH_SCAN_ACTIVE or BLE_MESH_SCAN_PASSIVE) */ + u8_t type; + + /** Duplicate filtering (BLE_MESH_SCAN_FILTER_DUP_ENABLE or + * BLE_MESH_SCAN_FILTER_DUP_DISABLE) + */ + u8_t filter_dup; + + /** Scan interval (N * 0.625 ms) */ + u16_t interval; + + /** Scan window (N * 0.625 ms) */ + u16_t window; +}; + +struct bt_mesh_conn { + u16_t handle; + bt_mesh_atomic_t ref; +}; + +/** @typedef bt_mesh_scan_cb_t + * @brief Callback type for reporting LE scan results. + * + * A function of this type is given to the bt_le_scan_start() function + * and will be called for any discovered LE device. + * + * @param addr Advertiser LE address and type. + * @param rssi Strength of advertiser signal. + * @param adv_type Type of advertising response from advertiser. + * @param data Buffer containing advertiser data. + */ +typedef void bt_mesh_scan_cb_t(const bt_mesh_addr_t *addr, s8_t rssi, + u8_t adv_type, struct net_buf_simple *buf); + +/* @typedef bt_mesh_dh_key_cb_t + * @brief Callback type for DH Key calculation. + * + * Used to notify of the calculated DH Key. + * + * @param key Public key. + * @param idx Provisioning link index, only used by Provisioner. + * + * @return The DH Key, or NULL in case of failure. + */ +typedef void (*bt_mesh_dh_key_cb_t)(const u8_t key[32], const u8_t idx); + +/** @typedef bt_mesh_gatt_attr_func_t + * @brief Attribute iterator callback. + * + * @param attr Attribute found. + * @param user_data Data given. + * + * @return BLE_MESH_GATT_ITER_CONTINUE if should continue to the next attribute + * or BLE_MESH_GATT_ITER_STOP to stop. + */ +typedef u8_t (*bt_mesh_gatt_attr_func_t)(const struct bt_mesh_gatt_attr *attr, + void *user_data); + +/** @brief Connection callback structure. + * + * This structure is used for tracking the state of a connection. + * It is registered with the help of the bt_mesh_gatts_conn_cb_register() API. + * It's permissible to register multiple instances of this @ref bt_conn_cb + * type, in case different modules of an application are interested in + * tracking the connection state. If a callback is not of interest for + * an instance, it may be set to NULL and will as a consequence not be + * used for that instance. + */ +struct bt_mesh_conn_cb { + /** @brief A new connection has been established. + * + * This callback notifies the application of a new connection. + * In case the err parameter is non-zero it means that the + * connection establishment failed. + * + * @param conn New connection object. + * @param err HCI error. Zero for success, non-zero otherwise. + */ + void (*connected)(struct bt_mesh_conn *conn, u8_t err); + + /** @brief A connection has been disconnected. + * + * This callback notifies the application that a connection + * has been disconnected. + * + * @param conn Connection object. + * @param reason HCI reason for the disconnection. + */ + void (*disconnected)(struct bt_mesh_conn *conn, u8_t reason); +}; + +struct bt_mesh_prov_conn_cb { + void (*connected)(const u8_t addr[6], struct bt_mesh_conn *conn, int id); + + void (*disconnected)(struct bt_mesh_conn *conn, u8_t reason); + + ssize_t (*prov_write_descr)(struct bt_mesh_conn *conn, u8_t *addr); + + ssize_t (*prov_notify)(struct bt_mesh_conn *conn, u8_t *data, u16_t len); + + ssize_t (*proxy_write_descr)(struct bt_mesh_conn *conn); + + ssize_t (*proxy_notify)(struct bt_mesh_conn *conn, u8_t *data, u16_t len); +}; + +/** @brief GATT Attribute structure. */ +struct bt_mesh_gatt_attr { + /** Attribute UUID */ + const struct bt_mesh_uuid *uuid; + + /** Attribute read callback + * + * @param conn The connection that is requesting to read + * @param attr The attribute that's being read + * @param buf Buffer to place the read result in + * @param len Length of data to read + * @param offset Offset to start reading from + * + * @return Number fo bytes read, or in case of an error + * BLE_MESH_GATT_ERR() with a specific ATT error code. + */ + ssize_t (*read)(struct bt_mesh_conn *conn, + const struct bt_mesh_gatt_attr *attr, + void *buf, u16_t len, + u16_t offset); + + /** Attribute write callback + * + * @param conn The connection that is requesting to write + * @param attr The attribute that's being written + * @param buf Buffer with the data to write + * @param len Number of bytes in the buffer + * @param offset Offset to start writing from + * @param flags Flags (BT_GATT_WRITE_*) + * + * @return Number of bytes written, or in case of an error + * BLE_MESH_GATT_ERR() with a specific ATT error code. + */ + ssize_t (*write)(struct bt_mesh_conn *conn, + const struct bt_mesh_gatt_attr *attr, + const void *buf, u16_t len, + u16_t offset, u8_t flags); + + /** Attribute user data */ + void *user_data; + /** Attribute handle */ + u16_t handle; + /** Attribute permissions */ + u8_t perm; +}; + +/** @def BLE_MESH_GATT_PRIMARY_SERVICE + * @brief Primary Service Declaration Macro. + * + * Helper macro to declare a primary service attribute. + * + * @param _service Service attribute value. + */ +#define BLE_MESH_GATT_PRIMARY_SERVICE(_service) \ +{ \ + .uuid = BLE_MESH_UUID_GATT_PRIMARY, \ + .perm = BLE_MESH_GATT_PERM_READ, \ + .read = bt_mesh_gatts_attr_read_service, \ + .user_data = _service, \ +} + +/** @def BLE_MESH_GATT_SECONDARY_SERVICE + * @brief Secondary Service Declaration Macro. + * + * Helper macro to declare a secondary service attribute. + * + * @param _service Service attribute value. + */ +#define BLE_MESH_GATT_SECONDARY_SERVICE(_service) \ +{ \ + .uuid = BLE_MESH_UUID_GATT_SECONDARY, \ + .perm = BLE_MESH_GATT_PERM_READ, \ + .read = bt_mesh_gatts_attr_read_service, \ + .user_data = _service, \ +} + +/** @def BLE_MESH_GATT_INCLUDE_SERVICE + * @brief Include Service Declaration Macro. + * + * Helper macro to declare database internal include service attribute. + * + * @param _service_incl the first service attribute of service to include + */ +#define BLE_MESH_GATT_INCLUDE_SERVICE(_service_incl) \ +{ \ + .uuid = BLE_MESH_UUID_GATT_INCLUDE, \ + .perm = BLE_MESH_GATT_PERM_READ, \ + .read = bt_mesh_gatts_attr_read_included, \ + .user_data = _service_incl, \ +} + +/** @def BLE_MESH_GATT_CHARACTERISTIC + * @brief Characteristic Declaration Macro. + * + * Helper macro to declare a characteristic attribute. + * + * @param _uuid Characteristic attribute uuid. + * @param _props Characteristic attribute properties. + */ +#define BLE_MESH_GATT_CHARACTERISTIC(_uuid, _props) \ +{ \ + .uuid = BLE_MESH_UUID_GATT_CHRC, \ + .perm = BLE_MESH_GATT_PERM_READ, \ + .read = bt_mesh_gatts_attr_read_chrc, \ + .user_data = (&(struct bt_mesh_gatt_char) { .uuid = _uuid, \ + .properties = _props, }), \ +} + +/** @def BLE_MESH_GATT_DESCRIPTOR + * @brief Descriptor Declaration Macro. + * + * Helper macro to declare a descriptor attribute. + * + * @param _uuid Descriptor attribute uuid. + * @param _perm Descriptor attribute access permissions. + * @param _read Descriptor attribute read callback. + * @param _write Descriptor attribute write callback. + * @param _value Descriptor attribute value. + */ +#define BLE_MESH_GATT_DESCRIPTOR(_uuid, _perm, _read, _write, _value) \ +{ \ + .uuid = _uuid, \ + .perm = _perm, \ + .read = _read, \ + .write = _write, \ + .user_data = _value, \ +} + +/** @def BLE_MESH_GATT_SERVICE + * @brief Service Structure Declaration Macro. + * + * Helper macro to declare a service structure. + * + * @param _attrs Service attributes. + */ +#define BLE_MESH_GATT_SERVICE(_attrs) \ +{ \ + .attrs = _attrs, \ + .attr_count = ARRAY_SIZE(_attrs), \ +} + +int bt_le_adv_start(const struct bt_mesh_adv_param *param, + const struct bt_mesh_adv_data *ad, size_t ad_len, + const struct bt_mesh_adv_data *sd, size_t sd_len); + +int bt_le_adv_stop(void); + +int bt_le_scan_start(const struct bt_mesh_scan_param *param, bt_mesh_scan_cb_t cb); + +int bt_le_scan_stop(void); + +void bt_mesh_gatts_conn_cb_register(struct bt_mesh_conn_cb *cb); + +int bt_mesh_gatts_disconnect(struct bt_mesh_conn *conn, u8_t reason); + +int bt_mesh_gatts_service_register(struct bt_mesh_gatt_service *svc); + +int bt_mesh_gatts_service_unregister(struct bt_mesh_gatt_service *svc); + +ssize_t bt_mesh_gatts_attr_read_included(struct bt_mesh_conn *conn, + const struct bt_mesh_gatt_attr *attr, + void *buf, u16_t len, u16_t offset); + +ssize_t bt_mesh_gatts_attr_read(struct bt_mesh_conn *conn, const struct bt_mesh_gatt_attr *attr, + void *buf, u16_t buf_len, u16_t offset, + const void *value, u16_t value_len); + +ssize_t bt_mesh_gatts_attr_read_service(struct bt_mesh_conn *conn, + const struct bt_mesh_gatt_attr *attr, + void *buf, u16_t len, u16_t offset); + +ssize_t bt_mesh_gatts_attr_read_chrc(struct bt_mesh_conn *conn, + const struct bt_mesh_gatt_attr *attr, void *buf, + u16_t len, u16_t offset); + +int bt_mesh_gatts_notify(struct bt_mesh_conn *conn, const struct bt_mesh_gatt_attr *attr, + const void *data, u16_t len); + +u16_t bt_mesh_gatt_get_mtu(struct bt_mesh_conn *conn); + +/** APIs added by Espressif */ +int bt_mesh_gatts_service_stop(struct bt_mesh_gatt_service *svc); +int bt_mesh_gatts_service_start(struct bt_mesh_gatt_service *svc); + +void bt_mesh_gattc_conn_cb_register(struct bt_mesh_prov_conn_cb *cb); + +u16_t bt_mesh_gattc_get_service_uuid(struct bt_mesh_conn *conn); + +int bt_mesh_gattc_conn_create(const bt_mesh_addr_t *addr, u16_t service_uuid); + +void bt_gattc_conn_close(struct bt_mesh_conn *conn); + +void bt_mesh_gattc_exchange_mtu(u8_t index); + +u16_t bt_mesh_gattc_get_mtu_info(struct bt_mesh_conn *conn); + +int bt_mesh_gattc_write_no_rsp(struct bt_mesh_conn *conn, const struct bt_mesh_gatt_attr *attr, + const void *data, u16_t len); + +void bt_mesh_gattc_disconnect(struct bt_mesh_conn *conn); + +struct bt_mesh_conn *bt_mesh_conn_ref(struct bt_mesh_conn *conn); + +void bt_mesh_conn_unref(struct bt_mesh_conn *conn); + +void bt_mesh_gatt_init(void); + +void bt_mesh_adapt_init(void); + +int bt_mesh_rand(void *buf, size_t len); + +void bt_mesh_set_private_key(const u8_t pri_key[32]); + +const u8_t *bt_mesh_pub_key_get(void); + +bool bt_mesh_check_public_key(const uint8_t key[64]); + +int bt_mesh_dh_key_gen(const u8_t remote_pk[64], bt_mesh_dh_key_cb_t cb, const u8_t idx); + +int bt_mesh_encrypt_le(const u8_t key[16], const u8_t plaintext[16], + u8_t enc_data[16]); + +int bt_mesh_encrypt_be(const u8_t key[16], const u8_t plaintext[16], + u8_t enc_data[16]); + +enum { + BLE_MESH_EXCEP_LIST_ADD = 0, + BLE_MESH_EXCEP_LIST_REMOVE, + BLE_MESH_EXCEP_LIST_CLEAN, +}; + +enum { + BLE_MESH_EXCEP_INFO_ADV_ADDR = 0, + BLE_MESH_EXCEP_INFO_MESH_LINK_ID, + BLE_MESH_EXCEP_INFO_MESH_BEACON, + BLE_MESH_EXCEP_INFO_MESH_PROV_ADV, + BLE_MESH_EXCEP_INFO_MESH_PROXY_ADV, +}; + +enum { + BLE_MESH_EXCEP_CLEAN_ADDR_LIST = BIT(0), + BLE_MESH_EXCEP_CLEAN_MESH_LINK_ID_LIST = BIT(1), + BLE_MESH_EXCEP_CLEAN_MESH_BEACON_LIST = BIT(2), + BLE_MESH_EXCEP_CLEAN_MESH_PROV_ADV_LIST = BIT(3), + BLE_MESH_EXCEP_CLEAN_MESH_PROXY_ADV_LIST = BIT(4), + BLE_MESH_EXCEP_CLEAN_ALL_LIST = 0xFFFF, +}; + +int bt_mesh_update_exceptional_list(u8_t sub_code, u8_t type, void *info); + +#endif /* _BLE_MESH_BEARER_ADRPT_H_ */ + diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_buf.h b/components/bt/ble_mesh/mesh_core/include/mesh_buf.h new file mode 100644 index 0000000000..e6c62877ea --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/include/mesh_buf.h @@ -0,0 +1,1064 @@ +/** @file + * @brief Buffer management. + */ + +/* + * Copyright (c) 2015 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _BLE_MESH_BUF_H_ +#define _BLE_MESH_BUF_H_ + +#include +#include "sys/cdefs.h" +#include "mesh_types.h" +#include "mesh_slist.h" +#include "mesh_kernel.h" +#include "mesh_util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Unaligned access */ +#define UNALIGNED_GET(p) \ +__extension__ ({ \ + struct __attribute__((__packed__)) { \ + __typeof__(*(p)) __v; \ + } *__p = (__typeof__(__p)) (p); \ + __p->__v; \ +}) + +#define BLE_MESH_NET_BUF_USER_DATA_SIZE 4 + +/** + * @brief Network buffer library + * @defgroup net_buf Network Buffer Library + * @ingroup networking + * @{ + */ + +/* Alignment needed for various parts of the buffer definition */ +#define __net_buf_align __aligned(sizeof(int)) + +/** + * @def NET_BUF_SIMPLE_DEFINE + * @brief Define a net_buf_simple stack variable. + * + * This is a helper macro which is used to define a net_buf_simple object + * on the stack. + * + * @param _name Name of the net_buf_simple object. + * @param _size Maximum data storage for the buffer. + */ +#define NET_BUF_SIMPLE_DEFINE(_name, _size) \ + u8_t net_buf_data_##_name[_size]; \ + struct net_buf_simple _name = { \ + .data = net_buf_data_##_name, \ + .len = 0, \ + .size = _size, \ + .__buf = net_buf_data_##_name, \ + } + +/** + * @def NET_BUF_SIMPLE_DEFINE_STATIC + * @brief Define a static net_buf_simple variable. + * + * This is a helper macro which is used to define a static net_buf_simple + * object. + * + * @param _name Name of the net_buf_simple object. + * @param _size Maximum data storage for the buffer. + */ +#define NET_BUF_SIMPLE_DEFINE_STATIC(_name, _size) \ + static u8_t net_buf_data_##_name[_size]; \ + static struct net_buf_simple _name = { \ + .data = net_buf_data_##_name, \ + .len = 0, \ + .size = _size, \ + .__buf = net_buf_data_##_name, \ + } + +/** + * @brief Simple network buffer representation. + * + * This is a simpler variant of the net_buf object (in fact net_buf uses + * net_buf_simple internally). It doesn't provide any kind of reference + * counting, user data, dynamic allocation, or in general the ability to + * pass through kernel objects such as FIFOs. + * + * The main use of this is for scenarios where the meta-data of the normal + * net_buf isn't needed and causes too much overhead. This could be e.g. + * when the buffer only needs to be allocated on the stack or when the + * access to and lifetime of the buffer is well controlled and constrained. + */ +struct net_buf_simple { + /** Pointer to the start of data in the buffer. */ + u8_t *data; + + /** Length of the data behind the data pointer. */ + u16_t len; + + /** Amount of data that this buffer can store. */ + u16_t size; + + /** Start of the data storage. Not to be accessed directly + * (the data pointer should be used instead). + */ + u8_t *__buf; +}; + +/** + * @def NET_BUF_SIMPLE + * @brief Define a net_buf_simple stack variable and get a pointer to it. + * + * This is a helper macro which is used to define a net_buf_simple object on + * the stack and the get a pointer to it as follows: + * + * struct net_buf_simple *my_buf = NET_BUF_SIMPLE(10); + * + * After creating the object it needs to be initialized by calling + * net_buf_simple_init(). + * + * @param _size Maximum data storage for the buffer. + * + * @return Pointer to stack-allocated net_buf_simple object. + */ +#define NET_BUF_SIMPLE(_size) \ + ((struct net_buf_simple *)(&(struct { \ + struct net_buf_simple buf; \ + u8_t data[_size] __net_buf_align; \ + }) { \ + .buf.size = _size, \ + .buf.__buf = NULL, \ + })) + +/** + * @brief Initialize a net_buf_simple object. + * + * This needs to be called after creating a net_buf_simple object using + * the NET_BUF_SIMPLE macro. + * + * @param buf Buffer to initialize. + * @param reserve_head Headroom to reserve. + */ +static inline void net_buf_simple_init(struct net_buf_simple *buf, + size_t reserve_head) +{ + if (!buf->__buf) { + buf->__buf = (u8_t *)buf + sizeof(*buf); + } + + buf->data = buf->__buf + reserve_head; + buf->len = 0; +} + +/** + * @brief Reset buffer + * + * Reset buffer data so it can be reused for other purposes. + * + * @param buf Buffer to reset. + */ +static inline void net_buf_simple_reset(struct net_buf_simple *buf) +{ + buf->len = 0; + buf->data = buf->__buf; +} + +/** + * @brief Prepare data to be added at the end of the buffer + * + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param len Number of bytes to increment the length with. + * + * @return The original tail of the buffer. + */ +void *net_buf_simple_add(struct net_buf_simple *buf, size_t len); + +/** + * @brief Copy given number of bytes from memory to the end of the buffer + * + * Increments the data length of the buffer to account for more data at the + * end. + * + * @param buf Buffer to update. + * @param mem Location of data to be added. + * @param len Length of data to be added + * + * @return The original tail of the buffer. + */ +void *net_buf_simple_add_mem(struct net_buf_simple *buf, const void *mem, + size_t len); + +/** + * @brief Add (8-bit) byte at the end of the buffer + * + * Increments the data length of the buffer to account for more data at the + * end. + * + * @param buf Buffer to update. + * @param val byte value to be added. + * + * @return Pointer to the value added + */ +u8_t *net_buf_simple_add_u8(struct net_buf_simple *buf, u8_t val); + +/** + * @brief Add 16-bit value at the end of the buffer + * + * Adds 16-bit value in little endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 16-bit value to be added. + */ +void net_buf_simple_add_le16(struct net_buf_simple *buf, u16_t val); + +/** + * @brief Add 16-bit value at the end of the buffer + * + * Adds 16-bit value in big endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 16-bit value to be added. + */ +void net_buf_simple_add_be16(struct net_buf_simple *buf, u16_t val); + +/** + * @brief Add 32-bit value at the end of the buffer + * + * Adds 32-bit value in little endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 32-bit value to be added. + */ +void net_buf_simple_add_le32(struct net_buf_simple *buf, u32_t val); + +/** + * @brief Add 32-bit value at the end of the buffer + * + * Adds 32-bit value in big endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 32-bit value to be added. + */ +void net_buf_simple_add_be32(struct net_buf_simple *buf, u32_t val); + +/** + * @brief Push data to the beginning of the buffer. + * + * Modifies the data pointer and buffer length to account for more data + * in the beginning of the buffer. + * + * @param buf Buffer to update. + * @param len Number of bytes to add to the beginning. + * + * @return The new beginning of the buffer data. + */ +void *net_buf_simple_push(struct net_buf_simple *buf, size_t len); + +/** + * @brief Push 16-bit value to the beginning of the buffer + * + * Adds 16-bit value in little endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 16-bit value to be pushed to the buffer. + */ +void net_buf_simple_push_le16(struct net_buf_simple *buf, u16_t val); + +/** + * @brief Push 16-bit value to the beginning of the buffer + * + * Adds 16-bit value in big endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 16-bit value to be pushed to the buffer. + */ +void net_buf_simple_push_be16(struct net_buf_simple *buf, u16_t val); + +/** + * @brief Push 8-bit value to the beginning of the buffer + * + * Adds 8-bit value the beginning of the buffer. + * + * @param buf Buffer to update. + * @param val 8-bit value to be pushed to the buffer. + */ +void net_buf_simple_push_u8(struct net_buf_simple *buf, u8_t val); + +/** + * @brief Remove data from the beginning of the buffer. + * + * Removes data from the beginning of the buffer by modifying the data + * pointer and buffer length. + * + * @param buf Buffer to update. + * @param len Number of bytes to remove. + * + * @return New beginning of the buffer data. + */ +void *net_buf_simple_pull(struct net_buf_simple *buf, size_t len); + +/** + * @brief Remove data from the beginning of the buffer. + * + * Removes data from the beginning of the buffer by modifying the data + * pointer and buffer length. + * + * @param buf Buffer to update. + * @param len Number of bytes to remove. + * + * @return Pointer to the old location of the buffer data. + */ +void *net_buf_simple_pull_mem(struct net_buf_simple *buf, size_t len); + +/** + * @brief Remove a 8-bit value from the beginning of the buffer + * + * Same idea as with net_buf_simple_pull(), but a helper for operating + * on 8-bit values. + * + * @param buf A valid pointer on a buffer. + * + * @return The 8-bit removed value + */ +u8_t net_buf_simple_pull_u8(struct net_buf_simple *buf); + +/** + * @brief Remove and convert 16 bits from the beginning of the buffer. + * + * Same idea as with net_buf_simple_pull(), but a helper for operating + * on 16-bit little endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 16-bit value converted from little endian to host endian. + */ +u16_t net_buf_simple_pull_le16(struct net_buf_simple *buf); + +/** + * @brief Remove and convert 16 bits from the beginning of the buffer. + * + * Same idea as with net_buf_simple_pull(), but a helper for operating + * on 16-bit big endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 16-bit value converted from big endian to host endian. + */ +u16_t net_buf_simple_pull_be16(struct net_buf_simple *buf); + +/** + * @brief Remove and convert 32 bits from the beginning of the buffer. + * + * Same idea as with net_buf_simple_pull(), but a helper for operating + * on 32-bit little endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 32-bit value converted from little endian to host endian. + */ +u32_t net_buf_simple_pull_le32(struct net_buf_simple *buf); + +/** + * @brief Remove and convert 32 bits from the beginning of the buffer. + * + * Same idea as with net_buf_simple_pull(), but a helper for operating + * on 32-bit big endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 32-bit value converted from big endian to host endian. + */ +u32_t net_buf_simple_pull_be32(struct net_buf_simple *buf); + +/** + * @brief Get the tail pointer for a buffer. + * + * Get a pointer to the end of the data in a buffer. + * + * @param buf Buffer. + * + * @return Tail pointer for the buffer. + */ +static inline u8_t *net_buf_simple_tail(struct net_buf_simple *buf) +{ + return buf->data + buf->len; +} + +/** + * @brief Check buffer headroom. + * + * Check how much free space there is in the beginning of the buffer. + * + * buf A valid pointer on a buffer + * + * @return Number of bytes available in the beginning of the buffer. + */ +size_t net_buf_simple_headroom(struct net_buf_simple *buf); + +/** + * @brief Check buffer tailroom. + * + * Check how much free space there is at the end of the buffer. + * + * @param buf A valid pointer on a buffer + * + * @return Number of bytes available at the end of the buffer. + */ +size_t net_buf_simple_tailroom(struct net_buf_simple *buf); + +/** + * @brief Parsing state of a buffer. + * + * This is used for temporarily storing the parsing state of a buffer + * while giving control of the parsing to a routine which we don't + * control. + */ +struct net_buf_simple_state { + /** Offset of the data pointer from the beginning of the storage */ + u16_t offset; + /** Length of data */ + u16_t len; +}; + +/** + * @brief Save the parsing state of a buffer. + * + * Saves the parsing state of a buffer so it can be restored later. + * + * @param buf Buffer from which the state should be saved. + * @param state Storage for the state. + */ +static inline void net_buf_simple_save(struct net_buf_simple *buf, + struct net_buf_simple_state *state) +{ + state->offset = net_buf_simple_headroom(buf); + state->len = buf->len; +} + +/** + * @brief Restore the parsing state of a buffer. + * + * Restores the parsing state of a buffer from a state previously stored + * by net_buf_simple_save(). + * + * @param buf Buffer to which the state should be restored. + * @param state Stored state. + */ +static inline void net_buf_simple_restore(struct net_buf_simple *buf, + struct net_buf_simple_state *state) +{ + buf->data = buf->__buf + state->offset; + buf->len = state->len; +} + +/** + * @brief Initialize buffer with the given headroom. + * + * The buffer is not expected to contain any data when this API is called. + * + * @param buf Buffer to initialize. + * @param reserve How much headroom to reserve. + */ +void net_buf_simple_reserve(struct net_buf_simple *buf, size_t reserve); + +/** + * Flag indicating that the buffer has associated fragments. Only used + * internally by the buffer handling code while the buffer is inside a + * FIFO, meaning this never needs to be explicitly set or unset by the + * net_buf API user. As long as the buffer is outside of a FIFO, i.e. + * in practice always for the user for this API, the buf->frags pointer + * should be used instead. + */ +#define NET_BUF_FRAGS BIT(0) + +/** + * @brief Network buffer representation. + * + * This struct is used to represent network buffers. Such buffers are + * normally defined through the NET_BUF_POOL_*_DEFINE() APIs and allocated + * using the net_buf_alloc() API. + */ +struct net_buf { + union { + /** Allow placing the buffer into sys_slist_t */ + sys_snode_t node; + + /** Fragments associated with this buffer. */ + struct net_buf *frags; + }; + + /** Reference count. */ + u8_t ref; + + /** Bit-field of buffer flags. */ + u8_t flags; + + /** Where the buffer should go when freed up. */ + struct net_buf_pool *pool; + + /* Union for convenience access to the net_buf_simple members, also + * preserving the old API. + */ + union { + /* The ABI of this struct must match net_buf_simple */ + struct { + /** Pointer to the start of data in the buffer. */ + u8_t *data; + + /** Length of the data behind the data pointer. */ + u16_t len; + + /** Amount of data that this buffer can store. */ + u16_t size; + + /** Start of the data storage. Not to be accessed + * directly (the data pointer should be used + * instead). + */ + u8_t *__buf; + }; + + struct net_buf_simple b; + }; + + /** System metadata for this buffer. */ + u8_t user_data[BLE_MESH_NET_BUF_USER_DATA_SIZE] __net_buf_align; +}; + +struct net_buf_data_cb { + u8_t * (*alloc)(struct net_buf *buf, size_t *size, s32_t timeout); + u8_t * (*ref)(struct net_buf *buf, u8_t *data); + void (*unref)(struct net_buf *buf, u8_t *data); +}; + +struct net_buf_data_alloc { + const struct net_buf_data_cb *cb; + void *alloc_data; +}; + +struct net_buf_pool { + /** Number of buffers in pool */ + const u16_t buf_count; + + /** Number of uninitialized buffers */ + u16_t uninit_count; + +#if defined(CONFIG_BLE_MESH_NET_BUF_POOL_USAGE) + /** Amount of available buffers in the pool. */ + s16_t avail_count; + + /** Total size of the pool. */ + const u16_t pool_size; + + /** Name of the pool. Used when printing pool information. */ + const char *name; +#endif /* CONFIG_BLE_MESH_NET_BUF_POOL_USAGE */ + + /** Optional destroy callback when buffer is freed. */ + void (*const destroy)(struct net_buf *buf); + + /** Data allocation handlers. */ + const struct net_buf_data_alloc *alloc; + + /** Helper to access the start of storage (for net_buf_pool_init) */ + struct net_buf *const __bufs; +}; + +#if defined(CONFIG_BLE_MESH_NET_BUF_POOL_USAGE) +#define NET_BUF_POOL_INITIALIZER(_pool, _alloc, _bufs, _count, _destroy) \ + { \ + .alloc = _alloc, \ + .__bufs = (struct net_buf *)_bufs, \ + .buf_count = _count, \ + .uninit_count = _count, \ + .avail_count = _count, \ + .destroy = _destroy, \ + .name = STRINGIFY(_pool), \ + } +#else +#define NET_BUF_POOL_INITIALIZER(_pool, _alloc, _bufs, _count, _destroy) \ + { \ + .alloc = _alloc, \ + .__bufs = (struct net_buf *)_bufs, \ + .buf_count = _count, \ + .uninit_count = _count, \ + .destroy = _destroy, \ + } +#endif /* CONFIG_BLE_MESH_NET_BUF_POOL_USAGE */ + +struct net_buf_pool_fixed { + size_t data_size; + u8_t *data_pool; +}; + +/** @cond INTERNAL_HIDDEN */ +extern const struct net_buf_data_cb net_buf_fixed_cb; + +/** + * @def NET_BUF_POOL_FIXED_DEFINE + * @brief Define a new pool for buffers based on fixed-size data + * + * Defines a net_buf_pool struct and the necessary memory storage (array of + * structs) for the needed amount of buffers. After this, the buffers can be + * accessed from the pool through net_buf_alloc. The pool is defined as a + * static variable, so if it needs to be exported outside the current module + * this needs to happen with the help of a separate pointer rather than an + * extern declaration. + * + * The data payload of the buffers will be allocated from a byte array + * of fixed sized chunks. This kind of pool does not support blocking on + * the data allocation, so the timeout passed to net_buf_alloc will be + * always treated as K_NO_WAIT when trying to allocate the data. This means + * that allocation failures, i.e. NULL returns, must always be handled + * cleanly. + * + * If provided with a custom destroy callback, this callback is + * responsible for eventually calling net_buf_destroy() to complete the + * process of returning the buffer to the pool. + * + * @param _name Name of the pool variable. + * @param _count Number of buffers in the pool. + * @param _data_size Maximum data payload per buffer. + * @param _destroy Optional destroy callback when buffer is freed. + */ +#define NET_BUF_POOL_FIXED_DEFINE(_name, _count, _data_size, _destroy) \ + static struct net_buf net_buf_##_name[_count]; \ + static u8_t net_buf_data_##_name[_count][_data_size]; \ + static const struct net_buf_pool_fixed net_buf_fixed_##_name = { \ + .data_size = _data_size, \ + .data_pool = (u8_t *)net_buf_data_##_name, \ + }; \ + static const struct net_buf_data_alloc net_buf_fixed_alloc_##_name = { \ + .cb = &net_buf_fixed_cb, \ + .alloc_data = (void *)&net_buf_fixed_##_name, \ + }; \ + struct net_buf_pool _name __net_buf_align \ + __in_section(_net_buf_pool, static, _name) = \ + NET_BUF_POOL_INITIALIZER(_name, &net_buf_fixed_alloc_##_name, \ + net_buf_##_name, _count, _destroy) + +/** + * @def NET_BUF_POOL_DEFINE + * @brief Define a new pool for buffers + * + * Defines a net_buf_pool struct and the necessary memory storage (array of + * structs) for the needed amount of buffers. After this,the buffers can be + * accessed from the pool through net_buf_alloc. The pool is defined as a + * static variable, so if it needs to be exported outside the current module + * this needs to happen with the help of a separate pointer rather than an + * extern declaration. + * + * If provided with a custom destroy callback this callback is + * responsible for eventually calling net_buf_destroy() to complete the + * process of returning the buffer to the pool. + * + * @param _name Name of the pool variable. + * @param _count Number of buffers in the pool. + * @param _size Maximum data size for each buffer. + * @param _ud_size Amount of user data space to reserve. + * @param _destroy Optional destroy callback when buffer is freed. + */ +#define NET_BUF_POOL_DEFINE(_name, _count, _size, _ud_size, _destroy) \ + NET_BUF_POOL_FIXED_DEFINE(_name, _count, _size, _destroy) + +/** + * @brief Get a zero-based index for a buffer. + * + * This function will translate a buffer into a zero-based index, + * based on its placement in its buffer pool. This can be useful if you + * want to associate an external array of meta-data contexts with the + * buffers of a pool. + * + * @param buf Network buffer. + * + * @return Zero-based index for the buffer. + */ +int net_buf_id(struct net_buf *buf); + +/** + * @brief Allocate a new fixed buffer from a pool. + * + * @param pool Which pool to allocate the buffer from. + * @param timeout Affects the action taken should the pool be empty. + * If K_NO_WAIT, then return immediately. If K_FOREVER, then + * wait as long as necessary. Otherwise, wait up to the specified + * number of milliseconds before timing out. Note that some types + * of data allocators do not support blocking (such as the HEAP + * type). In this case it's still possible for net_buf_alloc() to + * fail (return NULL) even if it was given K_FOREVER. + * + * @return New buffer or NULL if out of buffers. + */ +#if defined(CONFIG_BLE_MESH_NET_BUF_LOG) +struct net_buf *net_buf_alloc_fixed_debug(struct net_buf_pool *pool, s32_t timeout, + const char *func, int line); +#define net_buf_alloc_fixed(_pool, _timeout) \ + net_buf_alloc_fixed_debug(_pool, _timeout, __func__, __LINE__) +#else +struct net_buf *net_buf_alloc_fixed(struct net_buf_pool *pool, s32_t timeout); +#endif + +/** + * @def net_buf_alloc + * + * @copydetails net_buf_alloc_fixed + */ +#define net_buf_alloc(pool, timeout) net_buf_alloc_fixed(pool, timeout) + +/** + * @brief Reset buffer + * + * Reset buffer data and flags so it can be reused for other purposes. + * + * @param buf Buffer to reset. + */ +void net_buf_reset(struct net_buf *buf); + +/** + * @def net_buf_reserve + * @brief Initialize buffer with the given headroom. + * + * The buffer is not expected to contain any data when this API is called. + * + * @param buf Buffer to initialize. + * @param reserve How much headroom to reserve. + */ +#define net_buf_reserve(buf, reserve) net_buf_simple_reserve(&(buf)->b, reserve) + +/** + * @brief Put a buffer into a list + * + * Put a buffer to the end of a list. If the buffer contains follow-up + * fragments this function will take care of inserting them as well + * into the list. + * + * @param list Which list to append the buffer to. + * @param buf Buffer. + */ +void net_buf_slist_put(sys_slist_t *list, struct net_buf *buf); + +/** + * @brief Get a buffer from a list. + * + * Get buffer from a list. If the buffer had any fragments, these will + * automatically be recovered from the list as well and be placed to + * the buffer's fragment list. + * + * @param list Which list to take the buffer from. + * + * @return New buffer or NULL if the FIFO is empty. + */ +struct net_buf *net_buf_slist_get(sys_slist_t *list); + +/** + * @brief Decrements the reference count of a buffer. + * + * Decrements the reference count of a buffer and puts it back into the + * pool if the count reaches zero. + * + * @param buf A valid pointer on a buffer + */ +#if defined(CONFIG_BLE_MESH_NET_BUF_LOG) +void net_buf_unref_debug(struct net_buf *buf, const char *func, int line); +#define net_buf_unref(_buf) \ + net_buf_unref_debug(_buf, __func__, __LINE__) +#else +void net_buf_unref(struct net_buf *buf); +#endif + +/** + * @brief Increment the reference count of a buffer. + * + * @param buf A valid pointer on a buffer + * + * @return the buffer newly referenced + */ +struct net_buf *net_buf_ref(struct net_buf *buf); + +/** + * @brief Get a pointer to the user data of a buffer. + * + * @param buf A valid pointer on a buffer + * + * @return Pointer to the user data of the buffer. + */ +static inline void *net_buf_user_data(struct net_buf *buf) +{ + return (void *)buf->user_data; +} + +/** + * @def net_buf_add + * @brief Prepare data to be added at the end of the buffer + * + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param len Number of bytes to increment the length with. + * + * @return The original tail of the buffer. + */ +#define net_buf_add(buf, len) net_buf_simple_add(&(buf)->b, len) + +/** + * @def net_buf_add_mem + * @brief Copy bytes from memory to the end of the buffer + * + * Copies the given number of bytes to the end of the buffer. Increments the + * data length of the buffer to account for more data at the end. + * + * @param buf Buffer to update. + * @param mem Location of data to be added. + * @param len Length of data to be added + * + * @return The original tail of the buffer. + */ +#define net_buf_add_mem(buf, mem, len) net_buf_simple_add_mem(&(buf)->b, mem, len) + +/** + * @def net_buf_add_u8 + * @brief Add (8-bit) byte at the end of the buffer + * + * Adds a byte at the end of the buffer. Increments the data length of + * the buffer to account for more data at the end. + * + * @param buf Buffer to update. + * @param val byte value to be added. + * + * @return Pointer to the value added + */ +#define net_buf_add_u8(buf, val) net_buf_simple_add_u8(&(buf)->b, val) + +/** + * @def net_buf_add_le16 + * @brief Add 16-bit value at the end of the buffer + * + * Adds 16-bit value in little endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 16-bit value to be added. + */ +#define net_buf_add_le16(buf, val) net_buf_simple_add_le16(&(buf)->b, val) + +/** + * @def net_buf_add_be16 + * @brief Add 16-bit value at the end of the buffer + * + * Adds 16-bit value in big endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 16-bit value to be added. + */ +#define net_buf_add_be16(buf, val) net_buf_simple_add_be16(&(buf)->b, val) + +/** + * @def net_buf_add_le32 + * @brief Add 32-bit value at the end of the buffer + * + * Adds 32-bit value in little endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 32-bit value to be added. + */ +#define net_buf_add_le32(buf, val) net_buf_simple_add_le32(&(buf)->b, val) + +/** + * @def net_buf_add_be32 + * @brief Add 32-bit value at the end of the buffer + * + * Adds 32-bit value in big endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 32-bit value to be added. + */ +#define net_buf_add_be32(buf, val) net_buf_simple_add_be32(&(buf)->b, val) + +/** + * @def net_buf_push + * @brief Push data to the beginning of the buffer. + * + * Modifies the data pointer and buffer length to account for more data + * in the beginning of the buffer. + * + * @param buf Buffer to update. + * @param len Number of bytes to add to the beginning. + * + * @return The new beginning of the buffer data. + */ +#define net_buf_push(buf, len) net_buf_simple_push(&(buf)->b, len) + +/** + * @def net_buf_push_le16 + * @brief Push 16-bit value to the beginning of the buffer + * + * Adds 16-bit value in little endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 16-bit value to be pushed to the buffer. + */ +#define net_buf_push_le16(buf, val) net_buf_simple_push_le16(&(buf)->b, val) + +/** + * @def net_buf_push_be16 + * @brief Push 16-bit value to the beginning of the buffer + * + * Adds 16-bit value in little endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 16-bit value to be pushed to the buffer. + */ +#define net_buf_push_be16(buf, val) net_buf_simple_push_be16(&(buf)->b, val) + +/** + * @def net_buf_push_u8 + * @brief Push 8-bit value to the beginning of the buffer + * + * Adds 8-bit value the beginning of the buffer. + * + * @param buf Buffer to update. + * @param val 8-bit value to be pushed to the buffer. + */ +#define net_buf_push_u8(buf, val) net_buf_simple_push_u8(&(buf)->b, val) + +/** + * @def net_buf_pull + * @brief Remove data from the beginning of the buffer. + * + * Removes data from the beginning of the buffer by modifying the data + * pointer and buffer length. + * + * @param buf Buffer to update. + * @param len Number of bytes to remove. + * + * @return New beginning of the buffer data. + */ +#define net_buf_pull(buf, len) net_buf_simple_pull(&(buf)->b, len) + +/** + * @def net_buf_pull_u8 + * @brief Remove a 8-bit value from the beginning of the buffer + * + * Same idea as with net_buf_pull(), but a helper for operating on + * 8-bit values. + * + * @param buf A valid pointer on a buffer. + * + * @return The 8-bit removed value + */ +#define net_buf_pull_u8(buf) net_buf_simple_pull_u8(&(buf)->b) + +/** + * @def net_buf_pull_le16 + * @brief Remove and convert 16 bits from the beginning of the buffer. + * + * Same idea as with net_buf_pull(), but a helper for operating on + * 16-bit little endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 16-bit value converted from little endian to host endian. + */ +#define net_buf_pull_le16(buf) net_buf_simple_pull_le16(&(buf)->b) + +/** + * @def net_buf_pull_be16 + * @brief Remove and convert 16 bits from the beginning of the buffer. + * + * Same idea as with net_buf_pull(), but a helper for operating on + * 16-bit big endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 16-bit value converted from big endian to host endian. + */ +#define net_buf_pull_be16(buf) net_buf_simple_pull_be16(&(buf)->b) + +/** + * @def net_buf_pull_le32 + * @brief Remove and convert 32 bits from the beginning of the buffer. + * + * Same idea as with net_buf_pull(), but a helper for operating on + * 32-bit little endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 32-bit value converted from little endian to host endian. + */ +#define net_buf_pull_le32(buf) net_buf_simple_pull_le32(&(buf)->b) + +/** + * @def net_buf_pull_be32 + * @brief Remove and convert 32 bits from the beginning of the buffer. + * + * Same idea as with net_buf_pull(), but a helper for operating on + * 32-bit big endian data. + * + * @param buf A valid pointer on a buffer + * + * @return 32-bit value converted from big endian to host endian. + */ +#define net_buf_pull_be32(buf) net_buf_simple_pull_be32(&(buf)->b) + +/** + * @def net_buf_tailroom + * @brief Check buffer tailroom. + * + * Check how much free space there is at the end of the buffer. + * + * @param buf A valid pointer on a buffer + * + * @return Number of bytes available at the end of the buffer. + */ +#define net_buf_tailroom(buf) net_buf_simple_tailroom(&(buf)->b) + +/** + * @def net_buf_headroom + * @brief Check buffer headroom. + * + * Check how much free space there is in the beginning of the buffer. + * + * buf A valid pointer on a buffer + * + * @return Number of bytes available in the beginning of the buffer. + */ +#define net_buf_headroom(buf) net_buf_simple_headroom(&(buf)->b) + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_BUF_H_ */ + diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_dlist.h b/components/bt/ble_mesh/mesh_core/include/mesh_dlist.h new file mode 100644 index 0000000000..31eef746ec --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/include/mesh_dlist.h @@ -0,0 +1,496 @@ +/* + * Copyright (c) 2013-2015 Wind River Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Doubly-linked list implementation + * + * Doubly-linked list implementation using inline macros/functions. + * This API is not thread safe, and thus if a list is used across threads, + * calls to functions must be protected with synchronization primitives. + * + * The lists are expected to be initialized such that both the head and tail + * pointers point to the list itself. Initializing the lists in such a fashion + * simplifies the adding and removing of nodes to/from the list. + */ + +#ifndef _BLE_MESH_DLIST_H_ +#define _BLE_MESH_DLIST_H_ + +#include +#include "mesh_util.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +struct _dnode { + union { + struct _dnode *head; /* ptr to head of list (sys_dlist_t) */ + struct _dnode *next; /* ptr to next node (sys_dnode_t) */ + }; + union { + struct _dnode *tail; /* ptr to tail of list (sys_dlist_t) */ + struct _dnode *prev; /* ptr to previous node (sys_dnode_t) */ + }; +}; + +typedef struct _dnode sys_dlist_t; +typedef struct _dnode sys_dnode_t; + +/** + * @brief Provide the primitive to iterate on a list + * Note: the loop is unsafe and thus __dn should not be removed + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_DLIST_FOR_EACH_NODE(l, n) { + * + * } + * + * This and other SYS_DLIST_*() macros are not thread safe. + * + * @param __dl A pointer on a sys_dlist_t to iterate on + * @param __dn A sys_dnode_t pointer to peek each node of the list + */ +#define SYS_DLIST_FOR_EACH_NODE(__dl, __dn) \ + for (__dn = sys_dlist_peek_head(__dl); __dn; \ + __dn = sys_dlist_peek_next(__dl, __dn)) + +/** + * @brief Provide the primitive to iterate on a list, from a node in the list + * Note: the loop is unsafe and thus __dn should not be removed + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_DLIST_ITERATE_FROM_NODE(l, n) { + * + * } + * + * Like SYS_DLIST_FOR_EACH_NODE(), but __dn already contains a node in the list + * where to start searching for the next entry from. If NULL, it starts from + * the head. + * + * This and other SYS_DLIST_*() macros are not thread safe. + * + * @param __dl A pointer on a sys_dlist_t to iterate on + * @param __dn A sys_dnode_t pointer to peek each node of the list; + * it contains the starting node, or NULL to start from the head + */ +#define SYS_DLIST_ITERATE_FROM_NODE(__dl, __dn) \ + for (__dn = __dn ? sys_dlist_peek_next_no_check(__dl, __dn) \ + : sys_dlist_peek_head(__dl); \ + __dn; \ + __dn = sys_dlist_peek_next(__dl, __dn)) + +/** + * @brief Provide the primitive to safely iterate on a list + * Note: __dn can be removed, it will not break the loop. + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_DLIST_FOR_EACH_NODE_SAFE(l, n, s) { + * + * } + * + * This and other SYS_DLIST_*() macros are not thread safe. + * + * @param __dl A pointer on a sys_dlist_t to iterate on + * @param __dn A sys_dnode_t pointer to peek each node of the list + * @param __dns A sys_dnode_t pointer for the loop to run safely + */ +#define SYS_DLIST_FOR_EACH_NODE_SAFE(__dl, __dn, __dns) \ + for (__dn = sys_dlist_peek_head(__dl), \ + __dns = sys_dlist_peek_next(__dl, __dn); \ + __dn; __dn = __dns, \ + __dns = sys_dlist_peek_next(__dl, __dn)) + +/* + * @brief Provide the primitive to resolve the container of a list node + * Note: it is safe to use with NULL pointer nodes + * + * @param __dn A pointer on a sys_dnode_t to get its container + * @param __cn Container struct type pointer + * @param __n The field name of sys_dnode_t within the container struct + */ +#define SYS_DLIST_CONTAINER(__dn, __cn, __n) \ + (__dn ? CONTAINER_OF(__dn, __typeof__(*__cn), __n) : NULL) +/* + * @brief Provide the primitive to peek container of the list head + * + * @param __dl A pointer on a sys_dlist_t to peek + * @param __cn Container struct type pointer + * @param __n The field name of sys_dnode_t within the container struct + */ +#define SYS_DLIST_PEEK_HEAD_CONTAINER(__dl, __cn, __n) \ + SYS_DLIST_CONTAINER(sys_dlist_peek_head(__dl), __cn, __n) + +/* + * @brief Provide the primitive to peek the next container + * + * @param __dl A pointer on a sys_dlist_t to peek + * @param __cn Container struct type pointer + * @param __n The field name of sys_dnode_t within the container struct + */ +#define SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n) \ + ((__cn) ? SYS_DLIST_CONTAINER(sys_dlist_peek_next(__dl, &(__cn->__n)), \ + __cn, __n) : NULL) + +/** + * @brief Provide the primitive to iterate on a list under a container + * Note: the loop is unsafe and thus __cn should not be detached + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_DLIST_FOR_EACH_CONTAINER(l, c, n) { + * + * } + * + * @param __dl A pointer on a sys_dlist_t to iterate on + * @param __cn A pointer to peek each entry of the list + * @param __n The field name of sys_dnode_t within the container struct + */ +#define SYS_DLIST_FOR_EACH_CONTAINER(__dl, __cn, __n) \ + for (__cn = SYS_DLIST_PEEK_HEAD_CONTAINER(__dl, __cn, __n); __cn; \ + __cn = SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n)) + +/** + * @brief Provide the primitive to safely iterate on a list under a container + * Note: __cn can be detached, it will not break the loop. + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_DLIST_FOR_EACH_CONTAINER_SAFE(l, c, cn, n) { + * + * } + * + * @param __dl A pointer on a sys_dlist_t to iterate on + * @param __cn A pointer to peek each entry of the list + * @param __cns A pointer for the loop to run safely + * @param __n The field name of sys_dnode_t within the container struct + */ +#define SYS_DLIST_FOR_EACH_CONTAINER_SAFE(__dl, __cn, __cns, __n) \ + for (__cn = SYS_DLIST_PEEK_HEAD_CONTAINER(__dl, __cn, __n), \ + __cns = SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n); __cn; \ + __cn = __cns, \ + __cns = SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n)) + +/** + * @brief initialize list + * + * @param list the doubly-linked list + * + * @return N/A + */ + +static inline void sys_dlist_init(sys_dlist_t *list) +{ + list->head = (sys_dnode_t *)list; + list->tail = (sys_dnode_t *)list; +} + +#define SYS_DLIST_STATIC_INIT(ptr_to_list) {{(ptr_to_list)}, {(ptr_to_list)}} + +/** + * @brief check if a node is the list's head + * + * @param list the doubly-linked list to operate on + * @param node the node to check + * + * @return 1 if node is the head, 0 otherwise + */ + +static inline int sys_dlist_is_head(sys_dlist_t *list, sys_dnode_t *node) +{ + return list->head == node; +} + +/** + * @brief check if a node is the list's tail + * + * @param list the doubly-linked list to operate on + * @param node the node to check + * + * @return 1 if node is the tail, 0 otherwise + */ + +static inline int sys_dlist_is_tail(sys_dlist_t *list, sys_dnode_t *node) +{ + return list->tail == node; +} + +/** + * @brief check if the list is empty + * + * @param list the doubly-linked list to operate on + * + * @return 1 if empty, 0 otherwise + */ + +static inline int sys_dlist_is_empty(sys_dlist_t *list) +{ + return list->head == list; +} + +/** + * @brief check if more than one node present + * + * This and other sys_dlist_*() functions are not thread safe. + * + * @param list the doubly-linked list to operate on + * + * @return 1 if multiple nodes, 0 otherwise + */ + +static inline int sys_dlist_has_multiple_nodes(sys_dlist_t *list) +{ + return list->head != list->tail; +} + +/** + * @brief get a reference to the head item in the list + * + * @param list the doubly-linked list to operate on + * + * @return a pointer to the head element, NULL if list is empty + */ + +static inline sys_dnode_t *sys_dlist_peek_head(sys_dlist_t *list) +{ + return sys_dlist_is_empty(list) ? NULL : list->head; +} + +/** + * @brief get a reference to the head item in the list + * + * The list must be known to be non-empty. + * + * @param list the doubly-linked list to operate on + * + * @return a pointer to the head element + */ + +static inline sys_dnode_t *sys_dlist_peek_head_not_empty(sys_dlist_t *list) +{ + return list->head; +} + +/** + * @brief get a reference to the next item in the list, node is not NULL + * + * Faster than sys_dlist_peek_next() if node is known not to be NULL. + * + * @param list the doubly-linked list to operate on + * @param node the node from which to get the next element in the list + * + * @return a pointer to the next element from a node, NULL if node is the tail + */ + +static inline sys_dnode_t *sys_dlist_peek_next_no_check(sys_dlist_t *list, + sys_dnode_t *node) +{ + return (node == list->tail) ? NULL : node->next; +} + +/** + * @brief get a reference to the next item in the list + * + * @param list the doubly-linked list to operate on + * @param node the node from which to get the next element in the list + * + * @return a pointer to the next element from a node, NULL if node is the tail + * or NULL (when node comes from reading the head of an empty list). + */ + +static inline sys_dnode_t *sys_dlist_peek_next(sys_dlist_t *list, + sys_dnode_t *node) +{ + return node ? sys_dlist_peek_next_no_check(list, node) : NULL; +} + +/** + * @brief get a reference to the tail item in the list + * + * @param list the doubly-linked list to operate on + * + * @return a pointer to the tail element, NULL if list is empty + */ + +static inline sys_dnode_t *sys_dlist_peek_tail(sys_dlist_t *list) +{ + return sys_dlist_is_empty(list) ? NULL : list->tail; +} + +/** + * @brief add node to tail of list + * + * This and other sys_dlist_*() functions are not thread safe. + * + * @param list the doubly-linked list to operate on + * @param node the element to append + * + * @return N/A + */ + +static inline void sys_dlist_append(sys_dlist_t *list, sys_dnode_t *node) +{ + node->next = list; + node->prev = list->tail; + + list->tail->next = node; + list->tail = node; +} + +/** + * @brief add node to head of list + * + * This and other sys_dlist_*() functions are not thread safe. + * + * @param list the doubly-linked list to operate on + * @param node the element to append + * + * @return N/A + */ + +static inline void sys_dlist_prepend(sys_dlist_t *list, sys_dnode_t *node) +{ + node->next = list->head; + node->prev = list; + + list->head->prev = node; + list->head = node; +} + +/** + * @brief insert node after a node + * + * Insert a node after a specified node in a list. + * This and other sys_dlist_*() functions are not thread safe. + * + * @param list the doubly-linked list to operate on + * @param insert_point the insert point in the list: if NULL, insert at head + * @param node the element to append + * + * @return N/A + */ + +static inline void sys_dlist_insert_after(sys_dlist_t *list, + sys_dnode_t *insert_point, sys_dnode_t *node) +{ + if (!insert_point) { + sys_dlist_prepend(list, node); + } else { + node->next = insert_point->next; + node->prev = insert_point; + insert_point->next->prev = node; + insert_point->next = node; + } +} + +/** + * @brief insert node before a node + * + * Insert a node before a specified node in a list. + * This and other sys_dlist_*() functions are not thread safe. + * + * @param list the doubly-linked list to operate on + * @param insert_point the insert point in the list: if NULL, insert at tail + * @param node the element to insert + * + * @return N/A + */ + +static inline void sys_dlist_insert_before(sys_dlist_t *list, + sys_dnode_t *insert_point, sys_dnode_t *node) +{ + if (!insert_point) { + sys_dlist_append(list, node); + } else { + node->prev = insert_point->prev; + node->next = insert_point; + insert_point->prev->next = node; + insert_point->prev = node; + } +} + +/** + * @brief insert node at position + * + * Insert a node in a location depending on a external condition. The cond() + * function checks if the node is to be inserted _before_ the current node + * against which it is checked. + * This and other sys_dlist_*() functions are not thread safe. + * + * @param list the doubly-linked list to operate on + * @param node the element to insert + * @param cond a function that determines if the current node is the correct + * insert point + * @param data parameter to cond() + * + * @return N/A + */ + +static inline void sys_dlist_insert_at(sys_dlist_t *list, sys_dnode_t *node, + int (*cond)(sys_dnode_t *, void *), void *data) +{ + if (sys_dlist_is_empty(list)) { + sys_dlist_append(list, node); + } else { + sys_dnode_t *pos = sys_dlist_peek_head(list); + + while (pos && !cond(pos, data)) { + pos = sys_dlist_peek_next(list, pos); + } + sys_dlist_insert_before(list, pos, node); + } +} + +/** + * @brief remove a specific node from a list + * + * The list is implicit from the node. The node must be part of a list. + * This and other sys_dlist_*() functions are not thread safe. + * + * @param node the node to remove + * + * @return N/A + */ + +static inline void sys_dlist_remove(sys_dnode_t *node) +{ + node->prev->next = node->next; + node->next->prev = node->prev; +} + +/** + * @brief get the first node in a list + * + * This and other sys_dlist_*() functions are not thread safe. + * + * @param list the doubly-linked list to operate on + * + * @return the first node in the list, NULL if list is empty + */ + +static inline sys_dnode_t *sys_dlist_get(sys_dlist_t *list) +{ + sys_dnode_t *node; + + if (sys_dlist_is_empty(list)) { + return NULL; + } + + node = list->head; + sys_dlist_remove(node); + return node; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_DLIST_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_hci.h b/components/bt/ble_mesh/mesh_core/include/mesh_hci.h new file mode 100644 index 0000000000..1c3e093e0b --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/include/mesh_hci.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2015-2016 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _BLE_MESH_HCI_H_ +#define _BLE_MESH_HCI_H_ + +#include "mesh_kernel.h" +#include "mesh_bearer_adapt.h" +#include "mesh_atomic.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Porting form zephyr/subsys/bluetooth/host/hci_core.h */ + +#define BLE_MESH_LMP_FEAT_PAGES_COUNT 1 + +/* bt_mesh_dev flags: the flags defined here represent BT controller state */ +enum { + BLE_MESH_DEV_ENABLE, + BLE_MESH_DEV_READY, + BLE_MESH_DEV_ID_STATIC_RANDOM, + BLE_MESH_DEV_HAS_PUB_KEY, + BLE_MESH_DEV_PUB_KEY_BUSY, + + BLE_MESH_DEV_ADVERTISING, + BLE_MESH_DEV_KEEP_ADVERTISING, + BLE_MESH_DEV_SCANNING, + BLE_MESH_DEV_EXPLICIT_SCAN, + BLE_MESH_DEV_ACTIVE_SCAN, + BLE_MESH_DEV_SCAN_FILTER_DUP, + + BLE_MESH_DEV_RPA_VALID, + + BLE_MESH_DEV_ID_PENDING, + + /* Total number of flags - must be at the end of the enum */ + BLE_MESH_DEV_NUM_FLAGS, +}; + +struct bt_mesh_dev_le { + /* LE features */ + u8_t features[8]; + + /* LE states */ + u64_t states; +}; + +/* State tracking for the local Bluetooth controller */ +struct bt_mesh_dev { + /* Flags indicate which functionality is enabled */ + BLE_MESH_ATOMIC_DEFINE(flags, BLE_MESH_DEV_NUM_FLAGS); + + /* Controller version & manufacturer information */ + u8_t hci_version; + u8_t lmp_version; + u16_t hci_revision; + u16_t lmp_subversion; + u16_t manufacturer; + + /* LMP features (pages 0, 1, 2) */ + u8_t features[BLE_MESH_LMP_FEAT_PAGES_COUNT][8]; + + /* LE controller specific features */ + struct bt_mesh_dev_le le; +}; + +/*Porting from zephyr/subsys/bluetooth/host/hci_core.h */ +/* HCI version from Assigned Numbers */ +#define BLE_MESH_HCI_VERSION_1_0B 0 +#define BLE_MESH_HCI_VERSION_1_1 1 +#define BLE_MESH_HCI_VERSION_1_2 2 +#define BLE_MESH_HCI_VERSION_2_0 3 +#define BLE_MESH_HCI_VERSION_2_1 4 +#define BLE_MESH_HCI_VERSION_3_0 5 +#define BLE_MESH_HCI_VERSION_4_0 6 +#define BLE_MESH_HCI_VERSION_4_1 7 +#define BLE_MESH_HCI_VERSION_4_2 8 +#define BLE_MESH_HCI_VERSION_5_0 9 + +/* OpCode Group Fields */ +#define BLE_MESH_OGF_LINK_CTRL 0x01 +#define BLE_MESH_OGF_BASEBAND 0x03 +#define BLE_MESH_OGF_INFO 0x04 +#define BLE_MESH_OGF_STATUS 0x05 +#define BLE_MESH_OGF_LE 0x08 +#define BLE_MESH_OGF_VS 0x3f + +/* Construct OpCode from OGF and OCF */ +#define BLE_MESH_OP(ogf, ocf) ((ocf) | ((ogf) << 10)) + +/* Obtain OGF from OpCode */ +#define BLE_MESH_OGF(opcode) (((opcode) >> 10) & BIT_MASK(6)) + +/* Obtain OCF from OpCode */ +#define BLE_MESH_OCF(opcode) ((opcode) & BIT_MASK(10)) + +#define BLE_MESH_HCI_OP_SET_ADV_PARAM BLE_MESH_OP(BLE_MESH_OGF_LE, 0x0006) +struct bt_mesh_hci_cp_set_adv_param { + u16_t min_interval; + u16_t max_interval; + u8_t type; + u8_t own_addr_type; + bt_mesh_addr_t direct_addr; + u8_t channel_map; + u8_t filter_policy; +} __packed; + +#define BLE_MESH_HCI_OP_SET_ADV_DATA BLE_MESH_OP(BLE_MESH_OGF_LE, 0x0008) +struct bt_mesh_hci_cp_set_adv_data { + u8_t len; + u8_t data[31]; +} __packed; + +#define BLE_MESH_HCI_OP_SET_SCAN_RSP_DATA BLE_MESH_OP(BLE_MESH_OGF_LE, 0x0009) +struct bt_mesh_hci_cp_set_scan_rsp_data { + u8_t len; + u8_t data[31]; +} __packed; + +/* Added by Espressif */ +extern struct bt_mesh_dev bt_mesh_dev; + +void bt_mesh_hci_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_HCI_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_kernel.h b/components/bt/ble_mesh/mesh_core/include/mesh_kernel.h new file mode 100644 index 0000000000..785b8b8dfb --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/include/mesh_kernel.h @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2016, Wind River Systems, Inc. + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BLE_MESH_KERNEL_H_ +#define _BLE_MESH_KERNEL_H_ + +#include "osi/mutex.h" +#include "mesh_types.h" +#include "mesh_slist.h" +#include "mesh_atomic.h" +#include "mesh_dlist.h" + +/* number of nsec per usec */ +#define NSEC_PER_USEC 1000 + +/* number of microseconds per millisecond */ +#define USEC_PER_MSEC 1000 + +/* number of milliseconds per second */ +#define MSEC_PER_SEC 1000 + +/* number of microseconds per second */ +#define USEC_PER_SEC ((USEC_PER_MSEC) * (MSEC_PER_SEC)) + +/* number of nanoseconds per second */ +#define NSEC_PER_SEC ((NSEC_PER_USEC) * (USEC_PER_MSEC) * (MSEC_PER_SEC)) + +/* timeout is not in use */ +#define _INACTIVE (-1) + +struct k_work; + +/** + * @typedef k_work_handler_t + * @brief Work item handler function type. + * + * A work item's handler function is executed by a workqueue's thread + * when the work item is processed by the workqueue. + * + * @param work Address of the work item. + * + * @return N/A + */ +typedef void (*k_work_handler_t)(struct k_work *work); + +typedef sys_dlist_t _wait_q_t; + +struct k_work { + void *_reserved; + k_work_handler_t handler; + int index; +}; + +#define _K_WORK_INITIALIZER(work_handler) \ +{ \ + ._reserved = NULL, \ + .handler = work_handler, \ +} + +/** + * @brief Generate null timeout delay. + * + * This macro generates a timeout delay that that instructs a kernel API + * not to wait if the requested operation cannot be performed immediately. + * + * @return Timeout delay value. + */ +#define K_NO_WAIT 0 + +/** + * @brief Generate timeout delay from milliseconds. + * + * This macro generates a timeout delay that that instructs a kernel API + * to wait up to @a ms milliseconds to perform the requested operation. + * + * @param ms Duration in milliseconds. + * + * @return Timeout delay value. + */ +#define K_MSEC(ms) (ms) + +/** + * @brief Generate timeout delay from seconds. + * + * This macro generates a timeout delay that that instructs a kernel API + * to wait up to @a s seconds to perform the requested operation. + * + * @param s Duration in seconds. + * + * @return Timeout delay value. + */ +#define K_SECONDS(s) K_MSEC((s) * MSEC_PER_SEC) + +/** + * @brief Generate timeout delay from minutes. + * + * This macro generates a timeout delay that that instructs a kernel API + * to wait up to @a m minutes to perform the requested operation. + * + * @param m Duration in minutes. + * + * @return Timeout delay value. + */ +#define K_MINUTES(m) K_SECONDS((m) * 60) + +/** + * @brief Generate timeout delay from hours. + * + * This macro generates a timeout delay that that instructs a kernel API + * to wait up to @a h hours to perform the requested operation. + * + * @param h Duration in hours. + * + * @return Timeout delay value. + */ +#define K_HOURS(h) K_MINUTES((h) * 60) + +/** + * @brief Generate infinite timeout delay. + * + * This macro generates a timeout delay that that instructs a kernel API + * to wait as long as necessary to perform the requested operation. + * + * @return Timeout delay value. + */ +#define K_FOREVER (-1) + +/** + * @brief Get system uptime (32-bit version). + * + * This routine returns the lower 32-bits of the elapsed time since the system + * booted, in milliseconds. + * + * This routine can be more efficient than k_uptime_get(), as it reduces the + * need for interrupt locking and 64-bit math. However, the 32-bit result + * cannot hold a system uptime time larger than approximately 50 days, so the + * caller must handle possible rollovers. + * + * @return Current uptime. + */ +u32_t k_uptime_get_32(void); + +struct k_delayed_work { + struct k_work work; +}; + +/** + * @brief Submit a delayed work item to the system workqueue. + * + * This routine schedules work item @a work to be processed by the system + * workqueue after a delay of @a delay milliseconds. The routine initiates + * an asynchronous countdown for the work item and then returns to the caller. + * Only when the countdown completes is the work item actually submitted to + * the workqueue and becomes pending. + * + * Submitting a previously submitted delayed work item that is still + * counting down cancels the existing submission and restarts the countdown + * using the new delay. If the work item is currently pending on the + * workqueue's queue because the countdown has completed it is too late to + * resubmit the item, and resubmission fails without impacting the work item. + * If the work item has already been processed, or is currently being processed, + * its work is considered complete and the work item can be resubmitted. + * + * @warning + * Work items submitted to the system workqueue should avoid using handlers + * that block or yield since this may prevent the system workqueue from + * processing other work items in a timely manner. + * + * @note Can be called by ISRs. + * + * @param work Address of delayed work item. + * @param delay Delay before submitting the work item (in milliseconds). + * + * @retval 0 Work item countdown started. + * @retval -EINPROGRESS Work item is already pending. + * @retval -EINVAL Work item is being processed or has completed its work. + * @retval -EADDRINUSE Work item is pending on a different workqueue. + */ +int k_delayed_work_submit(struct k_delayed_work *work, s32_t delay); + +/** + * @brief Get time remaining before a delayed work gets scheduled. + * + * This routine computes the (approximate) time remaining before a + * delayed work gets executed. If the delayed work is not waiting to be + * scheduled, it returns zero. + * + * @param work Delayed work item. + * + * @return Remaining time (in milliseconds). + */ +s32_t k_delayed_work_remaining_get(struct k_delayed_work *work); + +/** + * @brief Submit a work item to the system workqueue. + * + * This routine submits work item @a work to be processed by the system + * workqueue. If the work item is already pending in the workqueue's queue + * as a result of an earlier submission, this routine has no effect on the + * work item. If the work item has already been processed, or is currently + * being processed, its work is considered complete and the work item can be + * resubmitted. + * + * @warning + * Work items submitted to the system workqueue should avoid using handlers + * that block or yield since this may prevent the system workqueue from + * processing other work items in a timely manner. + * + * @note Can be called by ISRs. + * + * @param work Address of work item. + * + * @return N/A + */ +static inline void k_work_submit(struct k_work *work) +{ + if (work && work->handler) { + work->handler(work); + } +} + +/** + * @brief Initialize a work item. + * + * This routine initializes a workqueue work item, prior to its first use. + * + * @param work Address of work item. + * @param handler Function to invoke each time work item is processed. + * + * @return N/A + */ +static inline void k_work_init(struct k_work *work, k_work_handler_t handler) +{ + work->handler = handler; +} + +int k_delayed_work_cancel(struct k_delayed_work *work); + +int k_delayed_work_free(struct k_delayed_work *work); + +void k_delayed_work_init(struct k_delayed_work *work, k_work_handler_t handler); + +/** + * @brief Get system uptime. + * + * This routine returns the elapsed time since the system booted, + * in milliseconds. + * + * @return Current uptime. + */ +s64_t k_uptime_get(void); + +/** + * @brief Put the current thread to sleep. + * + * This routine puts the current thread to sleep for @a duration + * milliseconds. + * + * @param duration Number of milliseconds to sleep. + * + * @return N/A + */ +void k_sleep(s32_t duration); + +unsigned int bt_mesh_irq_lock(void); +void bt_mesh_irq_unlock(unsigned int key); + +void bt_mesh_k_init(void); + +#endif /* _BLE_MESH_KERNEL_H_ */ + diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_main.h b/components/bt/ble_mesh/mesh_core/include/mesh_main.h new file mode 100644 index 0000000000..374c6a0770 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/include/mesh_main.h @@ -0,0 +1,584 @@ +/** @file + * @brief Bluetooth Mesh Profile APIs. + */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _BLE_MESH_MAIN_H_ +#define _BLE_MESH_MAIN_H_ + +#include "mesh_util.h" +#include "mesh_access.h" + +/** + * @brief Bluetooth Mesh Provisioning + * @defgroup bt_mesh_prov Bluetooth Mesh Provisioning + * @ingroup bt_mesh + * @{ + */ + +typedef enum { + BLE_MESH_NO_OUTPUT = 0, + BLE_MESH_BLINK = BIT(0), + BLE_MESH_BEEP = BIT(1), + BLE_MESH_VIBRATE = BIT(2), + BLE_MESH_DISPLAY_NUMBER = BIT(3), + BLE_MESH_DISPLAY_STRING = BIT(4), +} bt_mesh_output_action_t; + +typedef enum { + BLE_MESH_NO_INPUT = 0, + BLE_MESH_PUSH = BIT(0), + BLE_MESH_TWIST = BIT(1), + BLE_MESH_ENTER_NUMBER = BIT(2), + BLE_MESH_ENTER_STRING = BIT(3), +} bt_mesh_input_action_t; + +typedef enum { + BLE_MESH_PROV_ADV = BIT(0), + BLE_MESH_PROV_GATT = BIT(1), +} bt_mesh_prov_bearer_t; + +typedef enum { + BLE_MESH_PROV_OOB_OTHER = BIT(0), + BLE_MESH_PROV_OOB_URI = BIT(1), + BLE_MESH_PROV_OOB_2D_CODE = BIT(2), + BLE_MESH_PROV_OOB_BAR_CODE = BIT(3), + BLE_MESH_PROV_OOB_NFC = BIT(4), + BLE_MESH_PROV_OOB_NUMBER = BIT(5), + BLE_MESH_PROV_OOB_STRING = BIT(6), + /* 7 - 10 are reserved */ + BLE_MESH_PROV_OOB_ON_BOX = BIT(11), + BLE_MESH_PROV_OOB_IN_BOX = BIT(12), + BLE_MESH_PROV_OOB_ON_PAPER = BIT(13), + BLE_MESH_PROV_OOB_IN_MANUAL = BIT(14), + BLE_MESH_PROV_OOB_ON_DEV = BIT(15), +} bt_mesh_prov_oob_info_t; + +/** Provisioning properties & capabilities. */ +struct bt_mesh_prov { +#if CONFIG_BLE_MESH_NODE + /** The UUID that's used when advertising as unprovisioned */ + const u8_t *uuid; + + /** Optional URI. This will be advertised separately from the + * unprovisioned beacon, however the unprovisioned beacon will + * contain a hash of it so the two can be associated by the + * provisioner. + */ + const char *uri; + + /** Out of Band information field. */ + bt_mesh_prov_oob_info_t oob_info; + + /** Flag indicates whether unprovisioned devices support OOB public key */ + bool oob_pub_key; + + /** @brief Set device OOB public key. + * + * This callback notifies the application to + * set OOB public key & private key pair. + */ + void (*oob_pub_key_cb)(void); + + /** Static OOB value */ + const u8_t *static_val; + /** Static OOB value length */ + u8_t static_val_len; + + /** Maximum size of Output OOB supported */ + u8_t output_size; + /** Supported Output OOB Actions */ + u16_t output_actions; + + /* Maximum size of Input OOB supported */ + u8_t input_size; + /** Supported Input OOB Actions */ + u16_t input_actions; + + /** @brief Output of a number is requested. + * + * This callback notifies the application to + * output the given number using the given action. + * + * @param act Action for outputting the number. + * @param num Number to be out-put. + * + * @return Zero on success or negative error code otherwise + */ + int (*output_number)(bt_mesh_output_action_t act, u32_t num); + + /** @brief Output of a string is requested. + * + * This callback notifies the application to + * display the given string to the user. + * + * @param str String to be displayed. + * + * @return Zero on success or negative error code otherwise + */ + int (*output_string)(const char *str); + + /** @brief Input is requested. + * + * This callback notifies the application to request + * input from the user using the given action. The + * requested input will either be a string or a number, and + * the application needs to consequently call the + * bt_mesh_input_string() or bt_mesh_input_number() functions + * once the data has been acquired from the user. + * + * @param act Action for inputting data. + * @param num Maximum size of the in-put data. + * + * @return Zero on success or negative error code otherwise + */ + int (*input)(bt_mesh_input_action_t act, u8_t size); + + /** @brief Provisioning link has been opened. + * + * This callback notifies the application that a provisioning + * link has been opened on the given provisioning bearer. + * + * @param bearer Provisioning bearer. + */ + void (*link_open)(bt_mesh_prov_bearer_t bearer); + + /** @brief Provisioning link has been closed. + * + * This callback notifies the application that a provisioning + * link has been closed on the given provisioning bearer. + * + * @param bearer Provisioning bearer. + */ + void (*link_close)(bt_mesh_prov_bearer_t bearer); + + /** @brief Provisioning is complete. + * + * This callback notifies the application that provisioning has + * been successfully completed, and that the local node has been + * assigned the specified NetKeyIndex and primary element address. + * + * @param net_idx NetKeyIndex given during provisioning. + * @param addr Primary element address. + * @param flags Key Refresh & IV Update flags + * @param iv_index IV Index. + */ + void (*complete)(u16_t net_idx, u16_t addr, u8_t flags, u32_t iv_index); + + /** @brief Node has been reset. + * + * This callback notifies the application that the local node + * has been reset and needs to be reprovisioned. The node will + * not automatically advertise as unprovisioned, rather the + * bt_mesh_prov_enable() API needs to be called to enable + * unprovisioned advertising on one or more provisioning bearers. + */ + void (*reset)(void); +#endif /* CONFIG_BLE_MESH_NODE */ + +#if CONFIG_BLE_MESH_PROVISIONER + /* Provisioner device uuid */ + const u8_t *prov_uuid; + + /* + * Primary element address of the provisioner. + * No need to initialize it for fast provisioning. + */ + const u16_t prov_unicast_addr; + + /* + * Starting unicast address going to assigned. + * No need to initialize it for fast provisioning. + */ + u16_t prov_start_address; + + /* Attention timer contained in Provisioning Invite */ + u8_t prov_attention; + + /* Provisioner provisioning Algorithm */ + u8_t prov_algorithm; + + /* Provisioner public key oob */ + u8_t prov_pub_key_oob; + + /** @brief Input is requested. + * + * This callback notifies the application that it should + * read device's public key with OOB + * + * @param link_idx: The provisioning link index + * + * @return Zero on success or negative error code otherwise + */ + int (*prov_pub_key_oob_cb)(u8_t link_idx); + + /* Provisioner static oob value */ + u8_t *prov_static_oob_val; + + /* Provisioner static oob value length */ + u8_t prov_static_oob_len; + + /** @brief Provisioner input a number read from device output + * + * This callback notifies the application that it should + * input the number given by the device. + * + * @param method: The OOB authentication method + * @param act: The output action of the device + * @param size: The output size of the device + * @param link_idx: The provisioning link index + * + * @return Zero on success or negative error code otherwise + */ + int (*prov_input_num)(u8_t method, bt_mesh_output_action_t act, u8_t size, u8_t link_idx); + + /** @brief Provisioner output a number to the device + * + * This callback notifies the application that it should + * output the number to the device. + * + * @param method: The OOB authentication method + * @param act: The input action of the device + * @param data: The input number/string of the device + * @param size: The input size of the device + * @param link_idx: The provisioning link index + * + * @return Zero on success or negative error code otherwise + */ + int (*prov_output_num)(u8_t method, bt_mesh_input_action_t act, void *data, u8_t size, u8_t link_idx); + + /* + * Key refresh and IV update flag. + * No need to initialize it for fast provisioning. + */ + u8_t flags; + + /* + * IV index. No need to initialize it for fast provisioning. + */ + u32_t iv_index; + + /** @brief Provisioner has opened a provisioning link. + * + * This callback notifies the application that a provisioning + * link has been opened on the given provisioning bearer. + * + * @param bearer Provisioning bearer. + */ + void (*prov_link_open)(bt_mesh_prov_bearer_t bearer); + + /** @brief Provisioner has closed a provisioning link. + * + * This callback notifies the application that a provisioning + * link has been closed on the given provisioning bearer. + * + * @param bearer Provisioning bearer. + * @param reason Provisioning link close reason(disconnect reason) + * 0xFF: disconnect due to provisioner_pb_gatt_disable() + */ + void (*prov_link_close)(bt_mesh_prov_bearer_t bearer, u8_t reason); + + /** @brief Provision one device is complete. + * + * This callback notifies the application that provisioner has + * successfully provisioned a device, and the node has been assigned + * the specified NetKeyIndex and primary element address. + * + * @param node_idx Node index within the node(provisioned device) queue. + * @param device_uuid Provisioned device uuid pointer. + * @param unicast_addr Provisioned device assigned unicast address. + * @param element_num Provisioned device element number. + * @param netkey_idx Provisioned device assigned netkey index. + */ + void (*prov_complete)(int node_idx, const u8_t device_uuid[16], + u16_t unicast_addr, u8_t element_num, + u16_t netkey_idx); +#endif /* CONFIG_BLE_MESH_PROVISIONER */ +}; + +/* The following APIs are for BLE Mesh Node */ + +/** @brief Provide provisioning input OOB string. + * + * This is intended to be called after the bt_mesh_prov input callback + * has been called with BLE_MESH_ENTER_STRING as the action. + * + * @param str String. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_mesh_input_string(const char *str); + +/** @brief Provide provisioning input OOB number. + * + * This is intended to be called after the bt_mesh_prov input callback + * has been called with BLE_MESH_ENTER_NUMBER as the action. + * + * @param num Number. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_mesh_input_number(u32_t num); + +/** @brief Enable specific provisioning bearers + * + * Enable one or more provisioning bearers. + * + * @param Bit-wise OR of provisioning bearers. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers); + +/** @brief Disable specific provisioning bearers + * + * Disable one or more provisioning bearers. + * + * @param Bit-wise OR of provisioning bearers. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers); + +/** @brief Indicate whether provisioner is enabled + * + * @return true - enabled, false - disabled. + */ +bool bt_mesh_is_provisioner_en(void); + +/* The following API is for BLE Mesh Fast Provisioning */ + +/** @brief Change the device action + * + * @param[IN] action: role of device to be set + * 0x01 - enter, 0x02 - suspend, 0x03 - exit + * + * @return status + */ +u8_t bt_mesh_set_fast_prov_action(u8_t action); + +/* The following APIs are for BLE Mesh Provisioner */ + +/** @brief Provide provisioning input OOB string. + * + * This is intended to be called after the bt_mesh_prov input callback + * has been called with BLE_MESH_ENTER_STRING as the action. + * + * @param str String. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_mesh_prov_input_string(const char *str); + +/** @brief Provide provisioning input OOB number. + * + * This is intended to be called after the bt_mesh_prov input callback + * has been called with BLE_MESH_ENTER_NUMBER as the action. + * + * @param num Number. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_mesh_prov_input_number(u32_t num); + +/** @brief Enable specific provisioning bearers + * + * Enable one or more provisioning bearers. + * + * @param bearers Bit-wise OR of provisioning bearers. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_mesh_provisioner_enable(bt_mesh_prov_bearer_t bearers); + +/** @brief Disable specific provisioning bearers + * + * Disable one or more provisioning bearers. + * + * @param bearers Bit-wise OR of provisioning bearers. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_mesh_provisioner_disable(bt_mesh_prov_bearer_t bearers); + +/** + * @} + */ + +/** + * @brief Bluetooth Mesh + * @defgroup bt_mesh Bluetooth Mesh + * @ingroup bluetooth + * @{ + */ + +/* Primary Network Key index */ +#define BLE_MESH_NET_PRIMARY 0x000 + +#define BLE_MESH_RELAY_DISABLED 0x00 +#define BLE_MESH_RELAY_ENABLED 0x01 +#define BLE_MESH_RELAY_NOT_SUPPORTED 0x02 + +#define BLE_MESH_BEACON_DISABLED 0x00 +#define BLE_MESH_BEACON_ENABLED 0x01 + +#define BLE_MESH_GATT_PROXY_DISABLED 0x00 +#define BLE_MESH_GATT_PROXY_ENABLED 0x01 +#define BLE_MESH_GATT_PROXY_NOT_SUPPORTED 0x02 + +#define BLE_MESH_FRIEND_DISABLED 0x00 +#define BLE_MESH_FRIEND_ENABLED 0x01 +#define BLE_MESH_FRIEND_NOT_SUPPORTED 0x02 + +#define BLE_MESH_NODE_IDENTITY_STOPPED 0x00 +#define BLE_MESH_NODE_IDENTITY_RUNNING 0x01 +#define BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED 0x02 + +/* Features */ +#define BLE_MESH_FEAT_RELAY BIT(0) +#define BLE_MESH_FEAT_PROXY BIT(1) +#define BLE_MESH_FEAT_FRIEND BIT(2) +#define BLE_MESH_FEAT_LOW_POWER BIT(3) +#define BLE_MESH_FEAT_SUPPORTED (BLE_MESH_FEAT_RELAY | \ + BLE_MESH_FEAT_PROXY | \ + BLE_MESH_FEAT_FRIEND | \ + BLE_MESH_FEAT_LOW_POWER) + +/** @brief Initialize Mesh support + * + * After calling this API, the node will not automatically advertise as + * unprovisioned, rather the bt_mesh_prov_enable() API needs to be called + * to enable unprovisioned advertising on one or more provisioning bearers. + * + * @param prov Node provisioning information. + * @param comp Node Composition. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_mesh_init(const struct bt_mesh_prov *prov, + const struct bt_mesh_comp *comp); + +/** @brief Reset the state of the local Mesh node. + * + * Resets the state of the node, which means that it needs to be + * reprovisioned to become an active node in a Mesh network again. + * + * After calling this API, the node will not automatically advertise as + * unprovisioned, rather the bt_mesh_prov_enable() API needs to be called + * to enable unprovisioned advertising on one or more provisioning bearers. + * + */ +void bt_mesh_reset(void); + +/** @brief Suspend the Mesh network temporarily. + * + * This API can be used for power saving purposes, but the user should be + * aware that leaving the local node suspended for a long period of time + * may cause it to become permanently disconnected from the Mesh network. + * If at all possible, the Friendship feature should be used instead, to + * make the node into a Low Power Node. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_suspend(void); + +/** @brief Resume a suspended Mesh network. + * + * This API resumes the local node, after it has been suspended using the + * bt_mesh_suspend() API. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_resume(void); + +/** @brief Provision the local Mesh Node. + * + * This API should normally not be used directly by the application. The + * only exception is for testing purposes where manual provisioning is + * desired without an actual external provisioner. + * + * @param net_key Network Key + * @param net_idx Network Key Index + * @param flags Provisioning Flags + * @param iv_index IV Index + * @param addr Primary element address + * @param dev_key Device Key + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_mesh_provision(const u8_t net_key[16], u16_t net_idx, + u8_t flags, u32_t iv_index, u16_t addr, + const u8_t dev_key[16]); + +/** @brief Check if the local node has been provisioned. + * + * This API can be used to check if the local node has been provisioned + * or not. It can e.g. be helpful to determine if there was a stored + * network in flash, i.e. if the network was restored after calling + * settings_load(). + * + * @return True if the node is provisioned. False otherwise. + */ +bool bt_mesh_is_provisioned(void); + +/** @brief Toggle the IV Update test mode + * + * This API is only available if the IV Update test mode has been enabled + * in Kconfig. It is needed for passing most of the IV Update qualification + * test cases. + * + * @param enable true to enable IV Update test mode, false to disable it. + */ +void bt_mesh_iv_update_test(bool enable); + +/** @brief Toggle the IV Update state + * + * This API is only available if the IV Update test mode has been enabled + * in Kconfig. It is needed for passing most of the IV Update qualification + * test cases. + * + * @return true if IV Update In Progress state was entered, false otherwise. + */ +bool bt_mesh_iv_update(void); + +/** @brief Toggle the Low Power feature of the local device + * + * Enables or disables the Low Power feature of the local device. This is + * exposed as a run-time feature, since the device might want to change + * this e.g. based on being plugged into a stable power source or running + * from a battery power source. + * + * @param enable true to enable LPN functionality, false to disable it. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_mesh_lpn_set(bool enable); + +/** @brief Send out a Friend Poll message. + * + * Send a Friend Poll message to the Friend of this node. If there is no + * established Friendship the function will return an error. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_mesh_lpn_poll(void); + +/** @brief Register a callback for Friendship changes. + * + * Registers a callback that will be called whenever Friendship gets + * established or is lost. + * + * @param cb Function to call when the Friendship status changes. + */ +void bt_mesh_lpn_set_cb(void (*cb)(u16_t friend_addr, bool established)); + +/** + * @} + */ + +#endif /* _BLE_MESH_MAIN_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_proxy.h b/components/bt/ble_mesh/mesh_core/include/mesh_proxy.h new file mode 100644 index 0000000000..0b14d9e184 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/include/mesh_proxy.h @@ -0,0 +1,37 @@ +/** @file + * @brief Bluetooth Mesh Proxy APIs. + */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BLE_MESH_PROXY_H_ +#define _BLE_MESH_PROXY_H_ + +#include +/** + * @brief Bluetooth Mesh Proxy + * @defgroup bt_mesh_proxy Bluetooth Mesh Proxy + * @ingroup bt_mesh + * @{ + */ + +/** + * @brief Enable advertising with Node Identity. + * + * This API requires that GATT Proxy support has been enabled. Once called + * each subnet will start advertising using Node Identity for the next + * 60 seconds. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_proxy_identity_enable(void); + +/** + * @} + */ + +#endif /* _BLE_MESH_PROXY_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_slist.h b/components/bt/ble_mesh/mesh_core/include/mesh_slist.h new file mode 100644 index 0000000000..4ddf427e6a --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/include/mesh_slist.h @@ -0,0 +1,468 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * + * @brief Single-linked list implementation + * + * Single-linked list implementation using inline macros/functions. + * This API is not thread safe, and thus if a list is used across threads, + * calls to functions must be protected with synchronization primitives. + */ + +#ifndef _BLE_MESH_SLIST_H_ +#define _BLE_MESH_SLIST_H_ + +#include +#include +#include "mesh_util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct _snode { + struct _snode *next; +}; + +typedef struct _snode sys_snode_t; + +struct _slist { + sys_snode_t *head; + sys_snode_t *tail; +}; + +typedef struct _slist sys_slist_t; + +/** + * @brief Provide the primitive to iterate on a list + * Note: the loop is unsafe and thus __sn should not be removed + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_SLIST_FOR_EACH_NODE(l, n) { + * + * } + * + * This and other SYS_SLIST_*() macros are not thread safe. + * + * @param __sl A pointer on a sys_slist_t to iterate on + * @param __sn A sys_snode_t pointer to peek each node of the list + */ +#define SYS_SLIST_FOR_EACH_NODE(__sl, __sn) \ + for (__sn = sys_slist_peek_head(__sl); __sn; \ + __sn = sys_slist_peek_next(__sn)) + +/** + * @brief Provide the primitive to iterate on a list, from a node in the list + * Note: the loop is unsafe and thus __sn should not be removed + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_SLIST_ITERATE_FROM_NODE(l, n) { + * + * } + * + * Like SYS_SLIST_FOR_EACH_NODE(), but __dn already contains a node in the list + * where to start searching for the next entry from. If NULL, it starts from + * the head. + * + * This and other SYS_SLIST_*() macros are not thread safe. + * + * @param __sl A pointer on a sys_slist_t to iterate on + * @param __sn A sys_snode_t pointer to peek each node of the list + * it contains the starting node, or NULL to start from the head + */ +#define SYS_SLIST_ITERATE_FROM_NODE(__sl, __sn) \ + for (__sn = __sn ? sys_slist_peek_next_no_check(__sn) \ + : sys_slist_peek_head(__sl); \ + __sn; \ + __sn = sys_slist_peek_next(__sn)) + +/** + * @brief Provide the primitive to safely iterate on a list + * Note: __sn can be removed, it will not break the loop. + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_SLIST_FOR_EACH_NODE_SAFE(l, n, s) { + * + * } + * + * This and other SYS_SLIST_*() macros are not thread safe. + * + * @param __sl A pointer on a sys_slist_t to iterate on + * @param __sn A sys_snode_t pointer to peek each node of the list + * @param __sns A sys_snode_t pointer for the loop to run safely + */ +#define SYS_SLIST_FOR_EACH_NODE_SAFE(__sl, __sn, __sns) \ + for (__sn = sys_slist_peek_head(__sl), \ + __sns = sys_slist_peek_next(__sn); \ + __sn; __sn = __sns, \ + __sns = sys_slist_peek_next(__sn)) + +/* + * @brief Provide the primitive to resolve the container of a list node + * Note: it is safe to use with NULL pointer nodes + * + * @param __ln A pointer on a sys_node_t to get its container + * @param __cn Container struct type pointer + * @param __n The field name of sys_node_t within the container struct + */ +#define SYS_SLIST_CONTAINER(__ln, __cn, __n) \ + ((__ln) ? CONTAINER_OF((__ln), __typeof__(*(__cn)), __n) : NULL) +/* + * @brief Provide the primitive to peek container of the list head + * + * @param __sl A pointer on a sys_slist_t to peek + * @param __cn Container struct type pointer + * @param __n The field name of sys_node_t within the container struct + */ +#define SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n) \ + SYS_SLIST_CONTAINER(sys_slist_peek_head(__sl), __cn, __n) + +/* + * @brief Provide the primitive to peek container of the list tail + * + * @param __sl A pointer on a sys_slist_t to peek + * @param __cn Container struct type pointer + * @param __n The field name of sys_node_t within the container struct + */ +#define SYS_SLIST_PEEK_TAIL_CONTAINER(__sl, __cn, __n) \ + SYS_SLIST_CONTAINER(sys_slist_peek_tail(__sl), __cn, __n) + +/* + * @brief Provide the primitive to peek the next container + * + * @param __cn Container struct type pointer + * @param __n The field name of sys_node_t within the container struct + */ + +#define SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n) \ + ((__cn) ? SYS_SLIST_CONTAINER(sys_slist_peek_next(&((__cn)->__n)), \ + __cn, __n) : NULL) + +/** + * @brief Provide the primitive to iterate on a list under a container + * Note: the loop is unsafe and thus __cn should not be detached + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_SLIST_FOR_EACH_CONTAINER(l, c, n) { + * + * } + * + * @param __sl A pointer on a sys_slist_t to iterate on + * @param __cn A pointer to peek each entry of the list + * @param __n The field name of sys_node_t within the container struct + */ +#define SYS_SLIST_FOR_EACH_CONTAINER(__sl, __cn, __n) \ + for (__cn = SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n); __cn; \ + __cn = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n)) + +/** + * @brief Provide the primitive to safely iterate on a list under a container + * Note: __cn can be detached, it will not break the loop. + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_SLIST_FOR_EACH_NODE_SAFE(l, c, cn, n) { + * + * } + * + * @param __sl A pointer on a sys_slist_t to iterate on + * @param __cn A pointer to peek each entry of the list + * @param __cns A pointer for the loop to run safely + * @param __n The field name of sys_node_t within the container struct + */ +#define SYS_SLIST_FOR_EACH_CONTAINER_SAFE(__sl, __cn, __cns, __n) \ + for (__cn = SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n), \ + __cns = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n); __cn; \ + __cn = __cns, __cns = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n)) + +/** + * @brief Initialize a list + * + * @param list A pointer on the list to initialize + */ +static inline void sys_slist_init(sys_slist_t *list) +{ + list->head = NULL; + list->tail = NULL; +} + +#define SYS_SLIST_STATIC_INIT(ptr_to_list) {NULL, NULL} + +/** + * @brief Test if the given list is empty + * + * @param list A pointer on the list to test + * + * @return a boolean, true if it's empty, false otherwise + */ +static inline bool sys_slist_is_empty(sys_slist_t *list) +{ + return (!list->head); +} + +/** + * @brief Peek the first node from the list + * + * @param list A point on the list to peek the first node from + * + * @return A pointer on the first node of the list (or NULL if none) + */ +static inline sys_snode_t *sys_slist_peek_head(sys_slist_t *list) +{ + return list->head; +} + +/** + * @brief Peek the last node from the list + * + * @param list A point on the list to peek the last node from + * + * @return A pointer on the last node of the list (or NULL if none) + */ +static inline sys_snode_t *sys_slist_peek_tail(sys_slist_t *list) +{ + return list->tail; +} + +/** + * @brief Peek the next node from current node, node is not NULL + * + * Faster then sys_slist_peek_next() if node is known not to be NULL. + * + * @param node A pointer on the node where to peek the next node + * + * @return a pointer on the next node (or NULL if none) + */ +static inline sys_snode_t *sys_slist_peek_next_no_check(sys_snode_t *node) +{ + return node->next; +} + +/** + * @brief Peek the next node from current node + * + * @param node A pointer on the node where to peek the next node + * + * @return a pointer on the next node (or NULL if none) + */ +static inline sys_snode_t *sys_slist_peek_next(sys_snode_t *node) +{ + return node ? sys_slist_peek_next_no_check(node) : NULL; +} + +/** + * @brief Prepend a node to the given list + * + * This and other sys_slist_*() functions are not thread safe. + * + * @param list A pointer on the list to affect + * @param node A pointer on the node to prepend + */ +static inline void sys_slist_prepend(sys_slist_t *list, + sys_snode_t *node) +{ + node->next = list->head; + list->head = node; + + if (!list->tail) { + list->tail = list->head; + } +} + +/** + * @brief Append a node to the given list + * + * This and other sys_slist_*() functions are not thread safe. + * + * @param list A pointer on the list to affect + * @param node A pointer on the node to append + */ +static inline void sys_slist_append(sys_slist_t *list, + sys_snode_t *node) +{ + node->next = NULL; + + if (!list->tail) { + list->tail = node; + list->head = node; + } else { + list->tail->next = node; + list->tail = node; + } +} + +/** + * @brief Append a list to the given list + * + * Append a singly-linked, NULL-terminated list consisting of nodes containing + * the pointer to the next node as the first element of a node, to @a list. + * This and other sys_slist_*() functions are not thread safe. + * + * @param list A pointer on the list to affect + * @param head A pointer to the first element of the list to append + * @param tail A pointer to the last element of the list to append + */ +static inline void sys_slist_append_list(sys_slist_t *list, + void *head, void *tail) +{ + if (!list->tail) { + list->head = (sys_snode_t *)head; + list->tail = (sys_snode_t *)tail; + } else { + list->tail->next = (sys_snode_t *)head; + list->tail = (sys_snode_t *)tail; + } +} + +/** + * @brief merge two slists, appending the second one to the first + * + * When the operation is completed, the appending list is empty. + * This and other sys_slist_*() functions are not thread safe. + * + * @param list A pointer on the list to affect + * @param list_to_append A pointer to the list to append. + */ +static inline void sys_slist_merge_slist(sys_slist_t *list, + sys_slist_t *list_to_append) +{ + sys_slist_append_list(list, list_to_append->head, + list_to_append->tail); + sys_slist_init(list_to_append); +} + +/** + * @brief Insert a node to the given list + * + * This and other sys_slist_*() functions are not thread safe. + * + * @param list A pointer on the list to affect + * @param prev A pointer on the previous node + * @param node A pointer on the node to insert + */ +static inline void sys_slist_insert(sys_slist_t *list, + sys_snode_t *prev, + sys_snode_t *node) +{ + if (!prev) { + sys_slist_prepend(list, node); + } else if (!prev->next) { + sys_slist_append(list, node); + } else { + node->next = prev->next; + prev->next = node; + } +} + +/** + * @brief Fetch and remove the first node of the given list + * + * List must be known to be non-empty. + * This and other sys_slist_*() functions are not thread safe. + * + * @param list A pointer on the list to affect + * + * @return A pointer to the first node of the list + */ +static inline sys_snode_t *sys_slist_get_not_empty(sys_slist_t *list) +{ + sys_snode_t *node = list->head; + + list->head = node->next; + if (list->tail == node) { + list->tail = list->head; + } + + return node; +} + +/** + * @brief Fetch and remove the first node of the given list + * + * This and other sys_slist_*() functions are not thread safe. + * + * @param list A pointer on the list to affect + * + * @return A pointer to the first node of the list (or NULL if empty) + */ +static inline sys_snode_t *sys_slist_get(sys_slist_t *list) +{ + return sys_slist_is_empty(list) ? NULL : sys_slist_get_not_empty(list); +} + +/** + * @brief Remove a node + * + * This and other sys_slist_*() functions are not thread safe. + * + * @param list A pointer on the list to affect + * @param prev_node A pointer on the previous node + * (can be NULL, which means the node is the list's head) + * @param node A pointer on the node to remove + */ +static inline void sys_slist_remove(sys_slist_t *list, + sys_snode_t *prev_node, + sys_snode_t *node) +{ + if (!prev_node) { + list->head = node->next; + + /* Was node also the tail? */ + if (list->tail == node) { + list->tail = list->head; + } + } else { + prev_node->next = node->next; + + /* Was node the tail? */ + if (list->tail == node) { + list->tail = prev_node; + } + } + + node->next = NULL; +} + +/** + * @brief Find and remove a node from a list + * + * This and other sys_slist_*() functions are not thread safe. + * + * @param list A pointer on the list to affect + * @param node A pointer on the node to remove from the list + * + * @return true if node was removed + */ +static inline bool sys_slist_find_and_remove(sys_slist_t *list, + sys_snode_t *node) +{ + sys_snode_t *prev = NULL; + sys_snode_t *test; + + SYS_SLIST_FOR_EACH_NODE(list, test) { + if (test == node) { + sys_slist_remove(list, prev, node); + return true; + } + + prev = test; + } + + return false; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_SLIST_H_ */ + diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_trace.h b/components/bt/ble_mesh/mesh_core/include/mesh_trace.h new file mode 100644 index 0000000000..325c807f93 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/include/mesh_trace.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2015-2016 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BLE_MESH_TRACE_H_ +#define _BLE_MESH_TRACE_H_ + +#include "esp_log.h" +#include "sdkconfig.h" + +/* Define common tracing for all */ +#ifndef LOG_LEVEL_ERROR +#define LOG_LEVEL_ERROR 1 +#endif /* LOG_LEVEL_ERROR */ + +#ifndef LOG_LEVEL_WARN +#define LOG_LEVEL_WARN 2 +#endif /* LOG_LEVEL_WARN */ + +#ifndef LOG_LEVEL_INFO +#define LOG_LEVEL_INFO 3 +#endif /* LOG_LEVEL_INFO */ + +#ifndef LOG_LEVEL_DEBUG +#define LOG_LEVEL_DEBUG 4 +#endif /* LOG_LEVEL_DEBUG */ + +#ifndef LOG_LEVEL_VERBOSE +#define LOG_LEVEL_VERBOSE 5 +#endif /*LOG_LEVEL_VERBOSE */ + +#ifdef CONFIG_BLE_MESH_STACK_TRACE_LEVEL +#define MESH_LOG_LEVEL CONFIG_BLE_MESH_STACK_TRACE_LEVEL +#else +#define MESH_LOG_LEVEL LOG_LEVEL_WARN +#endif + +#ifdef CONFIG_BLE_MESH_NET_BUF_TRACE_LEVEL +#define NET_BUF_LOG_LEVEL CONFIG_BLE_MESH_NET_BUF_TRACE_LEVEL +#else +#define NET_BUF_LOG_LEVEL LOG_LEVEL_WARN +#endif + +#define MESH_TRACE_TAG "BLE_MESH" + +#if (LOG_LOCAL_LEVEL >= 4) +#define BLE_MESH_LOG_LOCAL_LEVEL_MAPPING (LOG_LOCAL_LEVEL + 1) +#else +#define BLE_MESH_LOG_LOCAL_LEVEL_MAPPING LOG_LOCAL_LEVEL +#endif + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif /* MAX(a, b) */ + +#define BLE_MESH_LOG_LEVEL_CHECK(LAYER, LEVEL) (MAX(LAYER##_LOG_LEVEL, BLE_MESH_LOG_LOCAL_LEVEL_MAPPING) >= LOG_LEVEL_##LEVEL) + +#define BLE_MESH_PRINT_E(tag, format, ...) {esp_log_write(ESP_LOG_ERROR, tag, LOG_FORMAT(E, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } +#define BLE_MESH_PRINT_W(tag, format, ...) {esp_log_write(ESP_LOG_WARN, tag, LOG_FORMAT(W, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } +#define BLE_MESH_PRINT_I(tag, format, ...) {esp_log_write(ESP_LOG_INFO, tag, LOG_FORMAT(I, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } +#define BLE_MESH_PRINT_D(tag, format, ...) {esp_log_write(ESP_LOG_DEBUG, tag, LOG_FORMAT(D, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } +#define BLE_MESH_PRINT_V(tag, format, ...) {esp_log_write(ESP_LOG_VERBOSE, tag, LOG_FORMAT(V, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } + +#define printk ets_printf + +#define _STRINGIFY(x) #x +#define STRINGIFY(s) _STRINGIFY(s) + +#ifndef __ASSERT +#define __ASSERT(test, fmt, ...) \ + do { \ + if (!(test)) { \ + printk("ASSERTION FAIL [%s] @ %s:%d:\n\t", \ + _STRINGIFY(test), \ + __FILE__, \ + __LINE__); \ + printk(fmt, ##__VA_ARGS__); \ + for (;;); \ + } \ + } while ((0)) +#endif + +#ifndef __ASSERT_NO_MSG +#define __ASSERT_NO_MSG(x) do { if (!(x)) BLE_MESH_PRINT_E(MESH_TRACE_TAG, "error %s %u", __FILE__, __LINE__); } while (0) +#endif + +#if !CONFIG_BLE_MESH_NO_LOG +#define BT_ERR(fmt, args...) do {if ((MESH_LOG_LEVEL >= LOG_LEVEL_ERROR) && BLE_MESH_LOG_LEVEL_CHECK(MESH, ERROR)) BLE_MESH_PRINT_E(MESH_TRACE_TAG, fmt, ## args);} while(0) +#define BT_WARN(fmt, args...) do {if ((MESH_LOG_LEVEL >= LOG_LEVEL_WARN) && BLE_MESH_LOG_LEVEL_CHECK(MESH, WARN)) BLE_MESH_PRINT_W(MESH_TRACE_TAG, fmt, ## args);} while(0) +#define BT_INFO(fmt, args...) do {if ((MESH_LOG_LEVEL >= LOG_LEVEL_INFO) && BLE_MESH_LOG_LEVEL_CHECK(MESH, INFO)) BLE_MESH_PRINT_I(MESH_TRACE_TAG, fmt, ## args);} while(0) +#define BT_DBG(fmt, args...) do {if ((MESH_LOG_LEVEL >= LOG_LEVEL_DEBUG) && BLE_MESH_LOG_LEVEL_CHECK(MESH, DEBUG)) BLE_MESH_PRINT_D(MESH_TRACE_TAG, fmt, ## args);} while(0) +#else +#define BT_ERR(fmt, args...) +#define BT_WARN(fmt, args...) +#define BT_INFO(fmt, args...) +#define BT_DBG(fmt, args...) +#endif + +#if defined(CONFIG_BLE_MESH_NET_BUF_LOG) && (!CONFIG_BLE_MESH_NO_LOG) +#define NET_BUF_ERR(fmt, args...) do {if ((NET_BUF_LOG_LEVEL >= LOG_LEVEL_ERROR) && BLE_MESH_LOG_LEVEL_CHECK(NET_BUF, ERROR)) BLE_MESH_PRINT_E(MESH_TRACE_TAG, fmt, ## args);} while(0) +#define NET_BUF_WARN(fmt, args...) do {if ((NET_BUF_LOG_LEVEL >= LOG_LEVEL_WARN) && BLE_MESH_LOG_LEVEL_CHECK(NET_BUF, WARN)) BLE_MESH_PRINT_W(MESH_TRACE_TAG, fmt, ## args);} while(0) +#define NET_BUF_INFO(fmt, args...) do {if ((NET_BUF_LOG_LEVEL >= LOG_LEVEL_INFO) && BLE_MESH_LOG_LEVEL_CHECK(NET_BUF, INFO)) BLE_MESH_PRINT_I(MESH_TRACE_TAG, fmt, ## args);} while(0) +#define NET_BUF_DBG(fmt, args...) do {if ((NET_BUF_LOG_LEVEL >= LOG_LEVEL_DEBUG) && BLE_MESH_LOG_LEVEL_CHECK(NET_BUF, DEBUG)) BLE_MESH_PRINT_D(MESH_TRACE_TAG, fmt, ## args);} while(0) +#define NET_BUF_ASSERT(cond) __ASSERT_NO_MSG(cond) +#else +#define NET_BUF_ERR(fmt, args...) +#define NET_BUF_WARN(fmt, args...) +#define NET_BUF_INFO(fmt, args...) +#define NET_BUF_DBG(fmt, args...) +#define NET_BUF_ASSERT(cond) +#endif + +#if defined(CONFIG_BLE_MESH_NET_BUF_SIMPLE_LOG) && (!CONFIG_BLE_MESH_NO_LOG) +#define NET_BUF_SIMPLE_ERR(fmt, args...) do {if ((NET_BUF_LOG_LEVEL >= LOG_LEVEL_ERROR) && BLE_MESH_LOG_LEVEL_CHECK(NET_BUF, ERROR)) BLE_MESH_PRINT_E(MESH_TRACE_TAG, fmt, ## args);} while(0) +#define NET_BUF_SIMPLE_WARN(fmt, args...) do {if ((NET_BUF_LOG_LEVEL >= LOG_LEVEL_WARN) && BLE_MESH_LOG_LEVEL_CHECK(NET_BUF, WARN)) BLE_MESH_PRINT_W(MESH_TRACE_TAG, fmt, ## args);} while(0) +#define NET_BUF_SIMPLE_INFO(fmt, args...) do {if ((NET_BUF_LOG_LEVEL >= LOG_LEVEL_INFO) && BLE_MESH_LOG_LEVEL_CHECK(NET_BUF, INFO)) BLE_MESH_PRINT_I(MESH_TRACE_TAG, fmt, ## args);} while(0) +#define NET_BUF_SIMPLE_DBG(fmt, args...) do {if ((NET_BUF_LOG_LEVEL >= LOG_LEVEL_DEBUG) && BLE_MESH_LOG_LEVEL_CHECK(NET_BUF, DEBUG)) BLE_MESH_PRINT_D(MESH_TRACE_TAG, fmt, ## args);} while(0) +#define NET_BUF_SIMPLE_ASSERT(cond) __ASSERT_NO_MSG(cond) +#else +#define NET_BUF_SIMPLE_ERR(fmt, args...) +#define NET_BUF_SIMPLE_WARN(fmt, args...) +#define NET_BUF_SIMPLE_INFO(fmt, args...) +#define NET_BUF_SIMPLE_DBG(fmt, args...) +#define NET_BUF_SIMPLE_ASSERT(cond) +#endif + +#endif /* _BLE_MESH_TRACE_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_types.h b/components/bt/ble_mesh/mesh_core/include/mesh_types.h new file mode 100644 index 0000000000..66df1ec75e --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/include/mesh_types.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017 Linaro Limited + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BLE_MESH_TYPES_H_ +#define _BLE_MESH_TYPES_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef signed char s8_t; +typedef signed short s16_t; +typedef signed int s32_t; +typedef signed long long s64_t; + +typedef unsigned char u8_t; +typedef unsigned short u16_t; +typedef unsigned int u32_t; +typedef unsigned long long u64_t; + +typedef int bt_mesh_atomic_t; + +#ifndef bool +#define bool int8_t +#endif + +#ifndef false +#define false 0 +#endif + +#ifndef true +#define true 1 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_TYPES_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_util.h b/components/bt/ble_mesh/mesh_core/include/mesh_util.h new file mode 100644 index 0000000000..8258e2c691 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/include/mesh_util.h @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2011-2014, Wind River Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Misc utilities + * + * Misc utilities usable by the kernel and application code. + */ + +#ifndef _BLE_MESH_UTIL_H_ +#define _BLE_MESH_UTIL_H_ + +#include +#include "mesh_types.h" +#include "mesh_trace.h" +#include "soc/soc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Helper to pass a int as a pointer or vice-versa. + * Those are available for 32 bits architectures: + */ +#define POINTER_TO_UINT(x) ((u32_t) (x)) +#define UINT_TO_POINTER(x) ((void *) (x)) +#define POINTER_TO_INT(x) ((s32_t) (x)) +#define INT_TO_POINTER(x) ((void *) (x)) + +/* Evaluates to 0 if cond is true-ish; compile error otherwise */ +#define ZERO_OR_COMPILE_ERROR(cond) ((int) sizeof(char[1 - 2 * !(cond)]) - 1) + +/* Evaluates to 0 if array is an array; compile error if not array (e.g. + * pointer) + */ +#define IS_ARRAY(array) \ + ZERO_OR_COMPILE_ERROR( \ + !__builtin_types_compatible_p(__typeof__(array), \ + __typeof__(&(array)[0]))) + +/* Evaluates to number of elements in an array; compile error if not + * an array (e.g. pointer) + */ +#define ARRAY_SIZE(array) \ + ((unsigned long) (IS_ARRAY(array) + \ + (sizeof(array) / sizeof((array)[0])))) + +/* Evaluates to 1 if ptr is part of array, 0 otherwise; compile error if + * "array" argument is not an array (e.g. "ptr" and "array" mixed up) + */ +#define PART_OF_ARRAY(array, ptr) \ + ((ptr) && ((ptr) >= &array[0] && (ptr) < &array[ARRAY_SIZE(array)])) + +#define CONTAINER_OF(ptr, type, field) \ + ((type *)(((char *)(ptr)) - offsetof(type, field))) + +/* round "x" up/down to next multiple of "align" (which must be a power of 2) */ +#define ROUND_UP(x, align) \ + (((unsigned long)(x) + ((unsigned long)align - 1)) & \ + ~((unsigned long)align - 1)) +#define ROUND_DOWN(x, align) ((unsigned long)(x) & ~((unsigned long)align - 1)) + +#define ceiling_fraction(numerator, divider) \ + (((numerator) + ((divider) - 1)) / (divider)) + +/* Internal helpers only used by the sys_* APIs further below */ +#ifndef __bswap_16 +#define __bswap_16(x) ((u16_t) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))) +#endif + +#ifndef __bswap_32 +#define __bswap_32(x) ((u32_t) ((((x) >> 24) & 0xff) | \ + (((x) >> 8) & 0xff00) | \ + (((x) & 0xff00) << 8) | \ + (((x) & 0xff) << 24))) +#endif + +#ifndef __bswap_64 +#define __bswap_64(x) ((u64_t) ((((x) >> 56) & 0xff) | \ + (((x) >> 40) & 0xff00) | \ + (((x) >> 24) & 0xff0000) | \ + (((x) >> 8) & 0xff000000) | \ + (((x) & 0xff000000) << 8) | \ + (((x) & 0xff0000) << 24) | \ + (((x) & 0xff00) << 40) | \ + (((x) & 0xff) << 56))) +#endif + +#define sys_le16_to_cpu(val) (val) +#define sys_cpu_to_le16(val) (val) +#define sys_be16_to_cpu(val) __bswap_16(val) +#define sys_cpu_to_be16(val) __bswap_16(val) +#define sys_le32_to_cpu(val) (val) +#define sys_cpu_to_le32(val) (val) +#define sys_le64_to_cpu(val) (val) +#define sys_cpu_to_le64(val) (val) +#define sys_be32_to_cpu(val) __bswap_32(val) +#define sys_cpu_to_be32(val) __bswap_32(val) +#define sys_be64_to_cpu(val) __bswap_64(val) +#define sys_cpu_to_be64(val) __bswap_64(val) + +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef BIT +#define BIT(n) (1UL << (n)) +#endif + +#ifndef BIT_MASK +#define BIT_MASK(n) (BIT(n) - 1) +#endif + +/** + * @brief Check for macro definition in compiler-visible expressions + * + * This trick was pioneered in Linux as the config_enabled() macro. + * The madness has the effect of taking a macro value that may be + * defined to "1" (e.g. CONFIG_MYFEATURE), or may not be defined at + * all and turning it into a literal expression that can be used at + * "runtime". That is, it works similarly to + * "defined(CONFIG_MYFEATURE)" does except that it is an expansion + * that can exist in a standard expression and be seen by the compiler + * and optimizer. Thus much ifdef usage can be replaced with cleaner + * expressions like: + * + * if (IS_ENABLED(CONFIG_MYFEATURE)) + * myfeature_enable(); + * + * INTERNAL + * First pass just to expand any existing macros, we need the macro + * value to be e.g. a literal "1" at expansion time in the next macro, + * not "(1)", etc... Standard recursive expansion does not work. + */ +#define IS_ENABLED(config_macro) _IS_ENABLED1(config_macro) + +/* Now stick on a "_XXXX" prefix, it will now be "_XXXX1" if config_macro + * is "1", or just "_XXXX" if it's undefined. + * ENABLED: _IS_ENABLED2(_XXXX1) + * DISABLED _IS_ENABLED2(_XXXX) + */ +#define _IS_ENABLED1(config_macro) _IS_ENABLED2(_XXXX##config_macro) + +/* Here's the core trick, we map "_XXXX1" to "_YYYY," (i.e. a string + * with a trailing comma), so it has the effect of making this a + * two-argument tuple to the preprocessor only in the case where the + * value is defined to "1" + * ENABLED: _YYYY, <--- note comma! + * DISABLED: _XXXX + */ +#define _XXXX1 _YYYY, + +/* Then we append an extra argument to fool the gcc preprocessor into + * accepting it as a varargs macro. + * arg1 arg2 arg3 + * ENABLED: _IS_ENABLED3(_YYYY, 1, 0) + * DISABLED _IS_ENABLED3(_XXXX 1, 0) + */ +#define _IS_ENABLED2(one_or_two_args) _IS_ENABLED3(one_or_two_args 1, 0) + +/* And our second argument is thus now cooked to be 1 in the case + * where the value is defined to 1, and 0 if not: + */ +#define _IS_ENABLED3(ignore_this, val, ...) val + +/* ESP Toolchain doesn't support section */ +#define ___in_section(a, b, c) +#define __in_section(a, b, c) ___in_section(a, b, c) + +#define __in_section_unique(seg) ___in_section(seg, __FILE__, __COUNTER__) + +#define popcount(x) __builtin_popcount(x) + +/** + * + * @brief find most significant bit set in a 32-bit word + * + * This routine finds the first bit set starting from the most significant bit + * in the argument passed in and returns the index of that bit. Bits are + * numbered starting at 1 from the least significant bit. A return value of + * zero indicates that the value passed is zero. + * + * @return most significant bit set, 0 if @a op is 0 + */ + +#if defined(__GNUC__) +static inline unsigned int find_msb_set(u32_t op) +{ + if (!op) { + return 0; + } + return 32 - __builtin_clz(op); +} +#endif + +/** + * + * @brief find least significant bit set in a 32-bit word + * + * This routine finds the first bit set starting from the least significant bit + * in the argument passed in and returns the index of that bit. Bits are + * numbered starting at 1 from the least significant bit. A return value of + * zero indicates that the value passed is zero. + * + * @return least significant bit set, 0 if @a op is 0 + */ + +#if defined(__GNUC__) +static inline unsigned int find_lsb_set(u32_t op) +{ + return __builtin_ffs(op); +} +#endif + +/** + * @brief Put a 16-bit integer as big-endian to arbitrary location. + * + * Put a 16-bit integer, originally in host endianness, to a + * potentially unaligned memory location in big-endian format. + * + * @param val 16-bit integer in host endianness. + * @param dst Destination memory address to store the result. + */ +static inline void sys_put_be16(u16_t val, u8_t dst[2]) +{ + dst[0] = val >> 8; + dst[1] = val; +} + +/** + * @brief Put a 32-bit integer as big-endian to arbitrary location. + * + * Put a 32-bit integer, originally in host endianness, to a + * potentially unaligned memory location in big-endian format. + * + * @param val 32-bit integer in host endianness. + * @param dst Destination memory address to store the result. + */ +static inline void sys_put_be32(u32_t val, u8_t dst[4]) +{ + sys_put_be16(val >> 16, dst); + sys_put_be16(val, &dst[2]); +} + +/** + * @brief Put a 16-bit integer as little-endian to arbitrary location. + * + * Put a 16-bit integer, originally in host endianness, to a + * potentially unaligned memory location in little-endian format. + * + * @param val 16-bit integer in host endianness. + * @param dst Destination memory address to store the result. + */ +static inline void sys_put_le16(u16_t val, u8_t dst[2]) +{ + dst[0] = val; + dst[1] = val >> 8; +} + +/** + * @brief Put a 32-bit integer as little-endian to arbitrary location. + * + * Put a 32-bit integer, originally in host endianness, to a + * potentially unaligned memory location in little-endian format. + * + * @param val 32-bit integer in host endianness. + * @param dst Destination memory address to store the result. + */ +static inline void sys_put_le32(u32_t val, u8_t dst[4]) +{ + sys_put_le16(val, dst); + sys_put_le16(val >> 16, &dst[2]); +} + +/** + * @brief Put a 64-bit integer as little-endian to arbitrary location. + * + * Put a 64-bit integer, originally in host endianness, to a + * potentially unaligned memory location in little-endian format. + * + * @param val 64-bit integer in host endianness. + * @param dst Destination memory address to store the result. + */ +static inline void sys_put_le64(u64_t val, u8_t dst[8]) +{ + sys_put_le32(val, dst); + sys_put_le32(val >> 32, &dst[4]); +} + +/** + * @brief Get a 16-bit integer stored in big-endian format. + * + * Get a 16-bit integer, stored in big-endian format in a potentially + * unaligned memory location, and convert it to the host endianness. + * + * @param src Location of the big-endian 16-bit integer to get. + * + * @return 16-bit integer in host endianness. + */ +static inline u16_t sys_get_be16(const u8_t src[2]) +{ + return ((u16_t)src[0] << 8) | src[1]; +} + +/** + * @brief Get a 32-bit integer stored in big-endian format. + * + * Get a 32-bit integer, stored in big-endian format in a potentially + * unaligned memory location, and convert it to the host endianness. + * + * @param src Location of the big-endian 32-bit integer to get. + * + * @return 32-bit integer in host endianness. + */ +static inline u32_t sys_get_be32(const u8_t src[4]) +{ + return ((u32_t)sys_get_be16(&src[0]) << 16) | sys_get_be16(&src[2]); +} + +/** + * @brief Get a 16-bit integer stored in little-endian format. + * + * Get a 16-bit integer, stored in little-endian format in a potentially + * unaligned memory location, and convert it to the host endianness. + * + * @param src Location of the little-endian 16-bit integer to get. + * + * @return 16-bit integer in host endianness. + */ +static inline u16_t sys_get_le16(const u8_t src[2]) +{ + return ((u16_t)src[1] << 8) | src[0]; +} + +/** + * @brief Get a 32-bit integer stored in little-endian format. + * + * Get a 32-bit integer, stored in little-endian format in a potentially + * unaligned memory location, and convert it to the host endianness. + * + * @param src Location of the little-endian 32-bit integer to get. + * + * @return 32-bit integer in host endianness. + */ +static inline u32_t sys_get_le32(const u8_t src[4]) +{ + return ((u32_t)sys_get_le16(&src[2]) << 16) | sys_get_le16(&src[0]); +} + +/** + * @brief Get a 64-bit integer stored in little-endian format. + * + * Get a 64-bit integer, stored in little-endian format in a potentially + * unaligned memory location, and convert it to the host endianness. + * + * @param src Location of the little-endian 64-bit integer to get. + * + * @return 64-bit integer in host endianness. + */ +static inline u64_t sys_get_le64(const u8_t src[8]) +{ + return ((u64_t)sys_get_le32(&src[4]) << 32) | sys_get_le32(&src[0]); +} + +const char *bt_hex(const void *buf, size_t len); + +void mem_rcopy(u8_t *dst, u8_t const *src, u16_t len); + +void _set(void *to, uint8_t val, unsigned int len); + +unsigned int _copy(uint8_t *to, unsigned int to_len, + const uint8_t *from, unsigned int from_len); + +void _set(void *to, uint8_t val, unsigned int len); + +uint8_t _double_byte(uint8_t a); + +int _compare(const uint8_t *a, const uint8_t *b, size_t size); + +/** + * @brief Swap one buffer content into another + * + * Copy the content of src buffer into dst buffer in reversed order, + * i.e.: src[n] will be put in dst[end-n] + * Where n is an index and 'end' the last index in both arrays. + * The 2 memory pointers must be pointing to different areas, and have + * a minimum size of given length. + * + * @param dst A valid pointer on a memory area where to copy the data in + * @param src A valid pointer on a memory area where to copy the data from + * @param length Size of both dst and src memory areas + */ +static inline void sys_memcpy_swap(void *dst, const void *src, size_t length) +{ + __ASSERT(((src < dst && (src + length) <= dst) || + (src > dst && (dst + length) <= src)), + "Source and destination buffers must not overlap"); + + src += length - 1; + + for (; length > 0; length--) { + *((u8_t *)dst++) = *((u8_t *)src--); + } +} + +/** + * @brief Swap buffer content + * + * In-place memory swap, where final content will be reversed. + * I.e.: buf[n] will be put in buf[end-n] + * Where n is an index and 'end' the last index of buf. + * + * @param buf A valid pointer on a memory area to swap + * @param length Size of buf memory area + */ +static inline void sys_mem_swap(void *buf, size_t length) +{ + size_t i; + + for (i = 0; i < (length / 2); i++) { + u8_t tmp = ((u8_t *)buf)[i]; + + ((u8_t *)buf)[i] = ((u8_t *)buf)[length - 1 - i]; + ((u8_t *)buf)[length - 1 - i] = tmp; + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_UTIL_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_uuid.h b/components/bt/ble_mesh/mesh_core/include/mesh_uuid.h new file mode 100644 index 0000000000..de03df5c32 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/include/mesh_uuid.h @@ -0,0 +1,530 @@ +/** @file + * @brief Bluetooth UUID handling + */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _BLE_MESH_UUID_H_ +#define _BLE_MESH_UUID_H_ + +/** + * @brief UUIDs + * @defgroup bt_uuid UUIDs + * @ingroup bluetooth + * @{ + */ + +#include "mesh_util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Bluetooth UUID types */ +enum { + BLE_MESH_UUID_TYPE_16, + BLE_MESH_UUID_TYPE_32, + BLE_MESH_UUID_TYPE_128, +}; + +/** @brief This is a 'tentative' type and should be used as a pointer only */ +struct bt_mesh_uuid { + u8_t type; +}; + +struct bt_mesh_uuid_16 { + struct bt_mesh_uuid uuid; + u16_t val; +}; + +struct bt_mesh_uuid_32 { + struct bt_mesh_uuid uuid; + u32_t val; +}; + +struct bt_mesh_uuid_128 { + struct bt_mesh_uuid uuid; + u8_t val[16]; +}; + +#define BLE_MESH_UUID_INIT_16(value) \ +{ \ + .uuid.type = BLE_MESH_UUID_TYPE_16, \ + .val = (value), \ +} + +#define BLE_MESH_UUID_INIT_32(value) \ +{ \ + .uuid.type = BLE_MESH_UUID_TYPE_32, \ + .val = (value), \ +} + +#define BLE_MESH_UUID_INIT_128(value...) \ +{ \ + .uuid.type = BLE_MESH_UUID_TYPE_128, \ + .val = { value }, \ +} + +#define BLE_MESH_UUID_DECLARE_16(value) \ + ((struct bt_mesh_uuid *) (&(struct bt_mesh_uuid_16) BLE_MESH_UUID_INIT_16(value))) + +#define BLE_MESH_UUID_DECLARE_32(value) \ + ((struct bt_mesh_uuid *) (&(struct bt_mesh_uuid_32) BLE_MESH_UUID_INIT_32(value))) + +#define BLE_MESH_UUID_DECLARE_128(value...) \ + ((struct bt_mesh_uuid *) (&(struct bt_mesh_uuid_128) BLE_MESH_UUID_INIT_128(value))) + +#define BLE_MESH_UUID_16(__u) CONTAINER_OF(__u, struct bt_mesh_uuid_16, uuid) +#define BLE_MESH_UUID_32(__u) CONTAINER_OF(__u, struct bt_mesh_uuid_32, uuid) +#define BLE_MESH_UUID_128(__u) CONTAINER_OF(__u, struct bt_mesh_uuid_128, uuid) + +/** @def BLE_MESH_UUID_GAP + * @brief Generic Access + */ +#define BLE_MESH_UUID_GAP BLE_MESH_UUID_DECLARE_16(0x1800) +#define BLE_MESH_UUID_GAP_VAL 0x1800 +/** @def BLE_MESH_UUID_GATT + * @brief Generic Attribute + */ +#define BLE_MESH_UUID_GATT BLE_MESH_UUID_DECLARE_16(0x1801) +#define BLE_MESH_UUID_GATT_VAL 0x1801 +/** @def BLE_MESH_UUID_CTS + * @brief Current Time Service + */ +#define BLE_MESH_UUID_CTS BLE_MESH_UUID_DECLARE_16(0x1805) +#define BLE_MESH_UUID_CTS_VAL 0x1805 +/** @def BLE_MESH_UUID_DIS + * @brief Device Information Service + */ +#define BLE_MESH_UUID_DIS BLE_MESH_UUID_DECLARE_16(0x180a) +#define BLE_MESH_UUID_DIS_VAL 0x180a +/** @def BLE_MESH_UUID_HRS + * @brief Heart Rate Service + */ +#define BLE_MESH_UUID_HRS BLE_MESH_UUID_DECLARE_16(0x180d) +#define BLE_MESH_UUID_HRS_VAL 0x180d +/** @def BLE_MESH_UUID_BAS + * @brief Battery Service + */ +#define BLE_MESH_UUID_BAS BLE_MESH_UUID_DECLARE_16(0x180f) +#define BLE_MESH_UUID_BAS_VAL 0x180f +/** @def BLE_MESH_UUID_HIDS + * @brief HID Service + */ +#define BLE_MESH_UUID_HIDS BLE_MESH_UUID_DECLARE_16(0x1812) +#define BLE_MESH_UUID_HIDS_VAL 0x1812 +/** @def BLE_MESH_UUID_CSC + * @brief Cycling Speed and Cadence Service + */ +#define BLE_MESH_UUID_CSC BLE_MESH_UUID_DECLARE_16(0x1816) +#define BLE_MESH_UUID_CSC_VAL 0x1816 +/** @def BLE_MESH_UUID_ESS + * @brief Environmental Sensing Service + */ +#define BLE_MESH_UUID_ESS BLE_MESH_UUID_DECLARE_16(0x181a) +#define BLE_MESH_UUID_ESS_VAL 0x181a +/** @def BLE_MESH_UUID_IPSS + * @brief IP Support Service + */ +#define BLE_MESH_UUID_IPSS BLE_MESH_UUID_DECLARE_16(0x1820) +#define BLE_MESH_UUID_IPSS_VAL 0x1820 +/** @def BLE_MESH_UUID_MESH_PROV + * @brief Mesh Provisioning Service + */ +#define BLE_MESH_UUID_MESH_PROV BLE_MESH_UUID_DECLARE_16(0x1827) +#define BLE_MESH_UUID_MESH_PROV_VAL 0x1827 +/** @def BLE_MESH_UUID_MESH_PROXY + * @brief Mesh Proxy Service + */ +#define BLE_MESH_UUID_MESH_PROXY BLE_MESH_UUID_DECLARE_16(0x1828) +#define BLE_MESH_UUID_MESH_PROXY_VAL 0x1828 +/** @def BLE_MESH_UUID_GATT_PRIMARY + * @brief GATT Primary Service + */ +#define BLE_MESH_UUID_GATT_PRIMARY BLE_MESH_UUID_DECLARE_16(0x2800) +#define BLE_MESH_UUID_GATT_PRIMARY_VAL 0x2800 +/** @def BLE_MESH_UUID_GATT_SECONDARY + * @brief GATT Secondary Service + */ +#define BLE_MESH_UUID_GATT_SECONDARY BLE_MESH_UUID_DECLARE_16(0x2801) +#define BLE_MESH_UUID_GATT_SECONDARY_VAL 0x2801 +/** @def BLE_MESH_UUID_GATT_INCLUDE + * @brief GATT Include Service + */ +#define BLE_MESH_UUID_GATT_INCLUDE BLE_MESH_UUID_DECLARE_16(0x2802) +#define BLE_MESH_UUID_GATT_INCLUDE_VAL 0x2802 +/** @def BLE_MESH_UUID_GATT_CHRC + * @brief GATT Characteristic + */ +#define BLE_MESH_UUID_GATT_CHRC BLE_MESH_UUID_DECLARE_16(0x2803) +#define BLE_MESH_UUID_GATT_CHRC_VAL 0x2803 +/** @def BLE_MESH_UUID_GATT_CEP + * @brief GATT Characteristic Extended Properties + */ +#define BLE_MESH_UUID_GATT_CEP BLE_MESH_UUID_DECLARE_16(0x2900) +#define BLE_MESH_UUID_GATT_CEP_VAL 0x2900 +/** @def BLE_MESH_UUID_GATT_CUD + * @brief GATT Characteristic User Description + */ +#define BLE_MESH_UUID_GATT_CUD BLE_MESH_UUID_DECLARE_16(0x2901) +#define BLE_MESH_UUID_GATT_CUD_VAL 0x2901 +/** @def BLE_MESH_UUID_GATT_CCC + * @brief GATT Client Characteristic Configuration + */ +#define BLE_MESH_UUID_GATT_CCC BLE_MESH_UUID_DECLARE_16(0x2902) +#define BLE_MESH_UUID_GATT_CCC_VAL 0x2902 +/** @def BLE_MESH_UUID_GATT_SCC + * @brief GATT Server Characteristic Configuration + */ +#define BLE_MESH_UUID_GATT_SCC BLE_MESH_UUID_DECLARE_16(0x2903) +#define BLE_MESH_UUID_GATT_SCC_VAL 0x2903 +/** @def BLE_MESH_UUID_GATT_CPF + * @brief GATT Characteristic Presentation Format + */ +#define BLE_MESH_UUID_GATT_CPF BLE_MESH_UUID_DECLARE_16(0x2904) +#define BLE_MESH_UUID_GATT_CPF_VAL 0x2904 +/** @def BLE_MESH_UUID_VALID_RANGE + * @brief Valid Range Descriptor + */ +#define BLE_MESH_UUID_VALID_RANGE BLE_MESH_UUID_DECLARE_16(0x2906) +#define BLE_MESH_UUID_VALID_RANGE_VAL 0x2906 +/** @def BLE_MESH_UUID_HIDS_EXT_REPORT + * @brief HID External Report Descriptor + */ +#define BLE_MESH_UUID_HIDS_EXT_REPORT BLE_MESH_UUID_DECLARE_16(0x2907) +#define BLE_MESH_UUID_HIDS_EXT_REPORT_VAL 0x2907 +/** @def BLE_MESH_UUID_HIDS_REPORT_REF + * @brief HID Report Reference Descriptor + */ +#define BLE_MESH_UUID_HIDS_REPORT_REF BLE_MESH_UUID_DECLARE_16(0x2908) +#define BLE_MESH_UUID_HIDS_REPORT_REF_VAL 0x2908 +/** @def BLE_MESH_UUID_ES_CONFIGURATION + * @brief Environmental Sensing Configuration Descriptor + */ +#define BLE_MESH_UUID_ES_CONFIGURATION BLE_MESH_UUID_DECLARE_16(0x290b) +#define BLE_MESH_UUID_ES_CONFIGURATION_VAL 0x290b +/** @def BLE_MESH_UUID_ES_MEASUREMENT + * @brief Environmental Sensing Measurement Descriptor + */ +#define BLE_MESH_UUID_ES_MEASUREMENT BLE_MESH_UUID_DECLARE_16(0x290c) +#define BLE_MESH_UUID_ES_MEASUREMENT_VAL 0x290c +/** @def BLE_MESH_UUID_ES_TRIGGER_SETTING + * @brief Environmental Sensing Trigger Setting Descriptor + */ +#define BLE_MESH_UUID_ES_TRIGGER_SETTING BLE_MESH_UUID_DECLARE_16(0x290d) +#define BLE_MESH_UUID_ES_TRIGGER_SETTING_VAL 0x290d +/** @def BLE_MESH_UUID_GAP_DEVICE_NAME + * @brief GAP Characteristic Device Name + */ +#define BLE_MESH_UUID_GAP_DEVICE_NAME BLE_MESH_UUID_DECLARE_16(0x2a00) +#define BLE_MESH_UUID_GAP_DEVICE_NAME_VAL 0x2a00 +/** @def BLE_MESH_UUID_GAP_APPEARANCE + * @brief GAP Characteristic Appearance + */ +#define BLE_MESH_UUID_GAP_APPEARANCE BLE_MESH_UUID_DECLARE_16(0x2a01) +#define BLE_MESH_UUID_GAP_APPEARANCE_VAL 0x2a01 +/** @def BLE_MESH_UUID_GAP_PPCP + * @brief GAP Characteristic Peripheral Preferred Connection Parameters + */ +#define BLE_MESH_UUID_GAP_PPCP BLE_MESH_UUID_DECLARE_16(0x2a04) +#define BLE_MESH_UUID_GAP_PPCP_VAL 0x2a04 +/** @def BLE_MESH_UUID_GATT_SC + * @brief GATT Characteristic Service Changed + */ +#define BLE_MESH_UUID_GATT_SC BLE_MESH_UUID_DECLARE_16(0x2a05) +#define BLE_MESH_UUID_GATT_SC_VAL 0x2a05 +/** @def BLE_MESH_UUID_BAS_BATTERY_LEVEL + * @brief BAS Characteristic Battery Level + */ +#define BLE_MESH_UUID_BAS_BATTERY_LEVEL BLE_MESH_UUID_DECLARE_16(0x2a19) +#define BLE_MESH_UUID_BAS_BATTERY_LEVEL_VAL 0x2a19 +/** @def BLE_MESH_UUID_DIS_SYSTEM_ID + * @brief DIS Characteristic System ID + */ +#define BLE_MESH_UUID_DIS_SYSTEM_ID BLE_MESH_UUID_DECLARE_16(0x2a23) +#define BLE_MESH_UUID_DIS_SYSTEM_ID_VAL 0x2a23 +/** @def BLE_MESH_UUID_DIS_MODEL_NUMBER + * @brief DIS Characteristic Model Number String + */ +#define BLE_MESH_UUID_DIS_MODEL_NUMBER BLE_MESH_UUID_DECLARE_16(0x2a24) +#define BLE_MESH_UUID_DIS_MODEL_NUMBER_VAL 0x2a24 +/** @def BLE_MESH_UUID_DIS_SERIAL_NUMBER + * @brief DIS Characteristic Serial Number String + */ +#define BLE_MESH_UUID_DIS_SERIAL_NUMBER BLE_MESH_UUID_DECLARE_16(0x2a25) +#define BLE_MESH_UUID_DIS_SERIAL_NUMBER_VAL 0x2a25 +/** @def BLE_MESH_UUID_DIS_FIRMWARE_REVISION + * @brief DIS Characteristic Firmware Revision String + */ +#define BLE_MESH_UUID_DIS_FIRMWARE_REVISION BLE_MESH_UUID_DECLARE_16(0x2a26) +#define BLE_MESH_UUID_DIS_FIRMWARE_REVISION_VAL 0x2a26 +/** @def BLE_MESH_UUID_DIS_HARDWARE_REVISION + * @brief DIS Characteristic Hardware Revision String + */ +#define BLE_MESH_UUID_DIS_HARDWARE_REVISION BLE_MESH_UUID_DECLARE_16(0x2a27) +#define BLE_MESH_UUID_DIS_HARDWARE_REVISION_VAL 0x2a27 +/** @def BLE_MESH_UUID_DIS_SOFTWARE_REVISION + * @brief DIS Characteristic Software Revision String + */ +#define BLE_MESH_UUID_DIS_SOFTWARE_REVISION BLE_MESH_UUID_DECLARE_16(0x2a28) +#define BLE_MESH_UUID_DIS_SOFTWARE_REVISION_VAL 0x2a28 +/** @def BLE_MESH_UUID_DIS_MANUFACTURER_NAME + * @brief DIS Characteristic Manufacturer Name String + */ +#define BLE_MESH_UUID_DIS_MANUFACTURER_NAME BLE_MESH_UUID_DECLARE_16(0x2a29) +#define BLE_MESH_UUID_DIS_MANUFACTURER_NAME_VAL 0x2a29 +/** @def BLE_MESH_UUID_DIS_PNP_ID + * @brief DIS Characteristic PnP ID + */ +#define BLE_MESH_UUID_DIS_PNP_ID BLE_MESH_UUID_DECLARE_16(0x2a50) +#define BLE_MESH_UUID_DIS_PNP_ID_VAL 0x2a50 +/** @def BLE_MESH_UUID_CTS_CURRENT_TIME + * @brief CTS Characteristic Current Time + */ +#define BLE_MESH_UUID_CTS_CURRENT_TIME BLE_MESH_UUID_DECLARE_16(0x2a2b) +#define BLE_MESH_UUID_CTS_CURRENT_TIME_VAL 0x2a2b +/** @def BLE_MESH_UUID_MAGN_DECLINATION + * @brief Magnetic Declination Characteristic + */ +#define BLE_MESH_UUID_MAGN_DECLINATION BLE_MESH_UUID_DECLARE_16(0x2a2c) +#define BLE_MESH_UUID_MAGN_DECLINATION_VAL 0x2a2c +/** @def BLE_MESH_UUID_HRS_MEASUREMENT + * @brief HRS Characteristic Measurement Interval + */ +#define BLE_MESH_UUID_HRS_MEASUREMENT BLE_MESH_UUID_DECLARE_16(0x2a37) +#define BLE_MESH_UUID_HRS_MEASUREMENT_VAL 0x2a37 +/** @def BLE_MESH_UUID_HRS_BODY_SENSOR + * @brief HRS Characteristic Body Sensor Location + */ +#define BLE_MESH_UUID_HRS_BODY_SENSOR BLE_MESH_UUID_DECLARE_16(0x2a38) +#define BLE_MESH_UUID_HRS_BODY_SENSOR_VAL 0x2a38 +/** @def BLE_MESH_UUID_HRS_CONTROL_POINT + * @brief HRS Characteristic Control Point + */ +#define BLE_MESH_UUID_HRS_CONTROL_POINT BLE_MESH_UUID_DECLARE_16(0x2a39) +#define BLE_MESH_UUID_HRS_CONTROL_POINT_VAL 0x2a39 +/** @def BLE_MESH_UUID_HIDS_INFO + * @brief HID Information Characteristic + */ +#define BLE_MESH_UUID_HIDS_INFO BLE_MESH_UUID_DECLARE_16(0x2a4a) +#define BLE_MESH_UUID_HIDS_INFO_VAL 0x2a4a +/** @def BLE_MESH_UUID_HIDS_REPORT_MAP + * @brief HID Report Map Characteristic + */ +#define BLE_MESH_UUID_HIDS_REPORT_MAP BLE_MESH_UUID_DECLARE_16(0x2a4b) +#define BLE_MESH_UUID_HIDS_REPORT_MAP_VAL 0x2a4b +/** @def BLE_MESH_UUID_HIDS_CTRL_POINT + * @brief HID Control Point Characteristic + */ +#define BLE_MESH_UUID_HIDS_CTRL_POINT BLE_MESH_UUID_DECLARE_16(0x2a4c) +#define BLE_MESH_UUID_HIDS_CTRL_POINT_VAL 0x2a4c +/** @def BLE_MESH_UUID_HIDS_REPORT + * @brief HID Report Characteristic + */ +#define BLE_MESH_UUID_HIDS_REPORT BLE_MESH_UUID_DECLARE_16(0x2a4d) +#define BLE_MESH_UUID_HIDS_REPORT_VAL 0x2a4d +/** @def BLE_MESH_UUID_CSC_MEASUREMENT + * @brief CSC Measurement Characteristic + */ +#define BLE_MESH_UUID_CSC_MEASUREMENT BLE_MESH_UUID_DECLARE_16(0x2a5b) +#define BLE_MESH_UUID_CSC_MEASUREMENT_VAL 0x2a5b +/** @def BLE_MESH_UUID_CSC_FEATURE + * @brief CSC Feature Characteristic + */ +#define BLE_MESH_UUID_CSC_FEATURE BLE_MESH_UUID_DECLARE_16(0x2a5c) +#define BLE_MESH_UUID_CSC_FEATURE_VAL 0x2a5c +/** @def BLE_MESH_UUID_SENSOR_LOCATION + * @brief Sensor Location Characteristic + */ +#define BLE_MESH_UUID_SENSOR_LOCATION BLE_MESH_UUID_DECLARE_16(0x2a5d) +#define BLE_MESH_UUID_SENSOR_LOCATION_VAL 0x2a5d +/** @def BLE_MESH_UUID_SC_CONTROL_POINT + * @brief SC Control Point Characteristic + */ +#define BLE_MESH_UUID_SC_CONTROL_POINT BLE_MESH_UUID_DECLARE_16(0x2a55) +#define BLE_MESH_UUID_SC_CONTROL_POINT_VAl 0x2a55 +/** @def BLE_MESH_UUID_ELEVATION + * @brief Elevation Characteristic + */ +#define BLE_MESH_UUID_ELEVATION BLE_MESH_UUID_DECLARE_16(0x2a6c) +#define BLE_MESH_UUID_ELEVATION_VAL 0x2a6c +/** @def BLE_MESH_UUID_PRESSURE + * @brief Pressure Characteristic + */ +#define BLE_MESH_UUID_PRESSURE BLE_MESH_UUID_DECLARE_16(0x2a6d) +#define BLE_MESH_UUID_PRESSURE_VAL 0x2a6d +/** @def BLE_MESH_UUID_TEMPERATURE + * @brief Temperature Characteristic + */ +#define BLE_MESH_UUID_TEMPERATURE BLE_MESH_UUID_DECLARE_16(0x2a6e) +#define BLE_MESH_UUID_TEMPERATURE_VAL 0x2a6e +/** @def BLE_MESH_UUID_HUMIDITY + * @brief Humidity Characteristic + */ +#define BLE_MESH_UUID_HUMIDITY BLE_MESH_UUID_DECLARE_16(0x2a6f) +#define BLE_MESH_UUID_HUMIDITY_VAL 0x2a6f +/** @def BLE_MESH_UUID_TRUE_WIND_SPEED + * @brief True Wind Speed Characteristic + */ +#define BLE_MESH_UUID_TRUE_WIND_SPEED BLE_MESH_UUID_DECLARE_16(0x2a70) +#define BLE_MESH_UUID_TRUE_WIND_SPEED_VAL 0x2a70 +/** @def BLE_MESH_UUID_TRUE_WIND_DIR + * @brief True Wind Direction Characteristic + */ +#define BLE_MESH_UUID_TRUE_WIND_DIR BLE_MESH_UUID_DECLARE_16(0x2a71) +#define BLE_MESH_UUID_TRUE_WIND_DIR_VAL 0x2a71 +/** @def BLE_MESH_UUID_APPARENT_WIND_SPEED + * @brief Apparent Wind Speed Characteristic + */ +#define BLE_MESH_UUID_APPARENT_WIND_SPEED BLE_MESH_UUID_DECLARE_16(0x2a72) +#define BLE_MESH_UUID_APPARENT_WIND_SPEED_VAL 0x2a72 +/** @def BLE_MESH_UUID_APPARENT_WIND_DIR + * @brief Apparent Wind Direction Characteristic + */ +#define BLE_MESH_UUID_APPARENT_WIND_DIR BLE_MESH_UUID_DECLARE_16(0x2a73) +#define BLE_MESH_UUID_APPARENT_WIND_DIR_VAL 0x2a73 +/** @def BLE_MESH_UUID_GUST_FACTOR + * @brief Gust Factor Characteristic + */ +#define BLE_MESH_UUID_GUST_FACTOR BLE_MESH_UUID_DECLARE_16(0x2a74) +#define BLE_MESH_UUID_GUST_FACTOR_VAL 0x2a74 +/** @def BLE_MESH_UUID_POLLEN_CONCENTRATION + * @brief Pollen Concentration Characteristic + */ +#define BLE_MESH_UUID_POLLEN_CONCENTRATION BLE_MESH_UUID_DECLARE_16(0x2a75) +#define BLE_MESH_UUID_POLLEN_CONCENTRATION_VAL 0x2a75 +/** @def BLE_MESH_UUID_UV_INDEX + * @brief UV Index Characteristic + */ +#define BLE_MESH_UUID_UV_INDEX BLE_MESH_UUID_DECLARE_16(0x2a76) +#define BLE_MESH_UUID_UV_INDEX_VAL 0x2a76 +/** @def BLE_MESH_UUID_IRRADIANCE + * @brief Irradiance Characteristic + */ +#define BLE_MESH_UUID_IRRADIANCE BLE_MESH_UUID_DECLARE_16(0x2a77) +#define BLE_MESH_UUID_IRRADIANCE_VAL 0x2a77 +/** @def BLE_MESH_UUID_RAINFALL + * @brief Rainfall Characteristic + */ +#define BLE_MESH_UUID_RAINFALL BLE_MESH_UUID_DECLARE_16(0x2a78) +#define BLE_MESH_UUID_RAINFALL_VAL 0x2a78 +/** @def BLE_MESH_UUID_WIND_CHILL + * @brief Wind Chill Characteristic + */ +#define BLE_MESH_UUID_WIND_CHILL BLE_MESH_UUID_DECLARE_16(0x2a79) +#define BLE_MESH_UUID_WIND_CHILL_VAL 0x2a79 +/** @def BLE_MESH_UUID_HEAT_INDEX + * @brief Heat Index Characteristic + */ +#define BLE_MESH_UUID_HEAT_INDEX BLE_MESH_UUID_DECLARE_16(0x2a7a) +#define BLE_MESH_UUID_HEAT_INDEX_VAL 0x2a7a +/** @def BLE_MESH_UUID_DEW_POINT + * @brief Dew Point Characteristic + */ +#define BLE_MESH_UUID_DEW_POINT BLE_MESH_UUID_DECLARE_16(0x2a7b) +#define BLE_MESH_UUID_DEW_POINT_VAL 0x2a7b +/** @def BLE_MESH_UUID_DESC_VALUE_CHANGED + * @brief Descriptor Value Changed Characteristic + */ +#define BLE_MESH_UUID_DESC_VALUE_CHANGED BLE_MESH_UUID_DECLARE_16(0x2a7d) +#define BLE_MESH_UUID_DESC_VALUE_CHANGED_VAL 0x2a7d +/** @def BLE_MESH_UUID_MAGN_FLUX_DENSITY_2D + * @brief Magnetic Flux Density - 2D Characteristic + */ +#define BLE_MESH_UUID_MAGN_FLUX_DENSITY_2D BLE_MESH_UUID_DECLARE_16(0x2aa0) +#define BLE_MESH_UUID_MAGN_FLUX_DENSITY_2D_VAL 0x2aa0 +/** @def BLE_MESH_UUID_MAGN_FLUX_DENSITY_3D + * @brief Magnetic Flux Density - 3D Characteristic + */ +#define BLE_MESH_UUID_MAGN_FLUX_DENSITY_3D BLE_MESH_UUID_DECLARE_16(0x2aa1) +#define BLE_MESH_UUID_MAGN_FLUX_DENSITY_3D_VAL 0x2aa1 +/** @def BLE_MESH_UUID_BAR_PRESSURE_TREND + * @brief Barometric Pressure Trend Characteristic + */ +#define BLE_MESH_UUID_BAR_PRESSURE_TREND BLE_MESH_UUID_DECLARE_16(0x2aa3) +#define BLE_MESH_UUID_BAR_PRESSURE_TREND_VAL 0x2aa3 +/** @def BLE_MESH_UUID_MESH_PROV_DATA_IN + * @brief Mesh Provisioning Data In + */ +#define BLE_MESH_UUID_MESH_PROV_DATA_IN BLE_MESH_UUID_DECLARE_16(0x2adb) +#define BLE_MESH_UUID_MESH_PROV_DATA_IN_VAL 0x2adb +/** @def BLE_MESH_UUID_MESH_PROV_DATA_OUT + * @brief Mesh Provisioning Data Out + */ +#define BLE_MESH_UUID_MESH_PROV_DATA_OUT BLE_MESH_UUID_DECLARE_16(0x2adc) +#define BLE_MESH_UUID_MESH_PROV_DATA_OUT_VAL 0x2adc +/** @def BLE_MESH_UUID_MESH_PROXY_DATA_IN + * @brief Mesh Proxy Data In + */ +#define BLE_MESH_UUID_MESH_PROXY_DATA_IN BLE_MESH_UUID_DECLARE_16(0x2add) +#define BLE_MESH_UUID_MESH_PROXY_DATA_IN_VAL 0x2add +/** @def BLE_MESH_UUID_MESH_PROXY_DATA_OUT + * @brief Mesh Proxy Data Out + */ +#define BLE_MESH_UUID_MESH_PROXY_DATA_OUT BLE_MESH_UUID_DECLARE_16(0x2ade) +#define BLE_MESH_UUID_MESH_PROXY_DATA_OUT_VAL 0x2ade + +/* + * Protocol UUIDs + */ +#define BLE_MESH_UUID_SDP BLE_MESH_UUID_DECLARE_16(0x0001) +#define BLE_MESH_UUID_SDP_VAL 0x0001 +#define BLE_MESH_UUID_UDP BLE_MESH_UUID_DECLARE_16(0x0002) +#define BLE_MESH_UUID_UDP_VAL 0x0002 +#define BLE_MESH_UUID_RFCOMM BLE_MESH_UUID_DECLARE_16(0x0003) +#define BLE_MESH_UUID_RFCOMM_VAL 0x0003 +#define BLE_MESH_UUID_TCP BLE_MESH_UUID_DECLARE_16(0x0004) +#define BLE_MESH_UUID_TCP_VAL 0x0004 +#define BLE_MESH_UUID_TCS_BIN BLE_MESH_UUID_DECLARE_16(0x0005) +#define BLE_MESH_UUID_TCS_BIN_VAL 0x0005 +#define BLE_MESH_UUID_TCS_AT BLE_MESH_UUID_DECLARE_16(0x0006) +#define BLE_MESH_UUID_TCS_AT_VAL 0x0006 +#define BLE_MESH_UUID_ATT BLE_MESH_UUID_DECLARE_16(0x0007) +#define BLE_MESH_UUID_ATT_VAL 0x0007 +#define BLE_MESH_UUID_OBEX BLE_MESH_UUID_DECLARE_16(0x0008) +#define BLE_MESH_UUID_OBEX_VAL 0x0008 +#define BLE_MESH_UUID_IP BLE_MESH_UUID_DECLARE_16(0x0009) +#define BLE_MESH_UUID_IP_VAL 0x0009 +#define BLE_MESH_UUID_FTP BLE_MESH_UUID_DECLARE_16(0x000a) +#define BLE_MESH_UUID_FTP_VAL 0x000a +#define BLE_MESH_UUID_HTTP BLE_MESH_UUID_DECLARE_16(0x000c) +#define BLE_MESH_UUID_HTTP_VAL 0x000c +#define BLE_MESH_UUID_BNEP BLE_MESH_UUID_DECLARE_16(0x000f) +#define BLE_MESH_UUID_BNEP_VAL 0x000f +#define BLE_MESH_UUID_UPNP BLE_MESH_UUID_DECLARE_16(0x0010) +#define BLE_MESH_UUID_UPNP_VAL 0x0010 +#define BLE_MESH_UUID_HIDP BLE_MESH_UUID_DECLARE_16(0x0011) +#define BLE_MESH_UUID_HIDP_VAL 0x0011 +#define BLE_MESH_UUID_HCRP_CTRL BLE_MESH_UUID_DECLARE_16(0x0012) +#define BLE_MESH_UUID_HCRP_CTRL_VAL 0x0012 +#define BLE_MESH_UUID_HCRP_DATA BLE_MESH_UUID_DECLARE_16(0x0014) +#define BLE_MESH_UUID_HCRP_DATA_VAL 0x0014 +#define BLE_MESH_UUID_HCRP_NOTE BLE_MESH_UUID_DECLARE_16(0x0016) +#define BLE_MESH_UUID_HCRP_NOTE_VAL 0x0016 +#define BLE_MESH_UUID_AVCTP BLE_MESH_UUID_DECLARE_16(0x0017) +#define BLE_MESH_UUID_AVCTP_VAL 0x0017 +#define BLE_MESH_UUID_AVDTP BLE_MESH_UUID_DECLARE_16(0x0019) +#define BLE_MESH_UUID_AVDTP_VAL 0x0019 +#define BLE_MESH_UUID_CMTP BLE_MESH_UUID_DECLARE_16(0x001b) +#define BLE_MESH_UUID_CMTP_VAL 0x001b +#define BLE_MESH_UUID_UDI BLE_MESH_UUID_DECLARE_16(0x001d) +#define BLE_MESH_UUID_UDI_VAL 0x001d +#define BLE_MESH_UUID_MCAP_CTRL BLE_MESH_UUID_DECLARE_16(0x001e) +#define BLE_MESH_UUID_MCAP_CTRL_VAL 0x001e +#define BLE_MESH_UUID_MCAP_DATA BLE_MESH_UUID_DECLARE_16(0x001f) +#define BLE_MESH_UUID_MCAP_DATA_VAL 0x001f +#define BLE_MESH_UUID_L2CAP BLE_MESH_UUID_DECLARE_16(0x0100) +#define BLE_MESH_UUID_L2CAP_VAL 0x0100 + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* _BLE_MESH_UUID_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/lpn.c b/components/bt/ble_mesh/mesh_core/lpn.c new file mode 100644 index 0000000000..8adf2a24bb --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/lpn.c @@ -0,0 +1,1057 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "sdkconfig.h" +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BLE_MESH_DEBUG_LOW_POWER) + +#include "mesh_buf.h" +#include "mesh_kernel.h" +#include "mesh_trace.h" +#include "mesh_main.h" + +#include "crypto.h" +#include "adv.h" +#include "mesh.h" +#include "net.h" +#include "transport.h" +#include "access.h" +#include "beacon.h" +#include "foundation.h" +#include "lpn.h" + +#ifdef CONFIG_BLE_MESH_LOW_POWER + +#if defined(CONFIG_BLE_MESH_LPN_AUTO) +#define LPN_AUTO_TIMEOUT K_SECONDS(CONFIG_BLE_MESH_LPN_AUTO_TIMEOUT) +#else +#define LPN_AUTO_TIMEOUT 0 +#endif + +#define LPN_RECV_DELAY CONFIG_BLE_MESH_LPN_RECV_DELAY +#define SCAN_LATENCY MIN(CONFIG_BLE_MESH_LPN_SCAN_LATENCY, \ + LPN_RECV_DELAY) + +#define FRIEND_REQ_RETRY_TIMEOUT K_SECONDS(CONFIG_BLE_MESH_LPN_RETRY_TIMEOUT) + +#define FRIEND_REQ_WAIT K_MSEC(100) +#define FRIEND_REQ_SCAN K_SECONDS(1) +#define FRIEND_REQ_TIMEOUT (FRIEND_REQ_WAIT + FRIEND_REQ_SCAN) + +#define POLL_RETRY_TIMEOUT K_MSEC(100) + +#define REQ_RETRY_DURATION(lpn) (4 * (LPN_RECV_DELAY + (lpn)->adv_duration + \ + (lpn)->recv_win + POLL_RETRY_TIMEOUT)) + +#define POLL_TIMEOUT_INIT (CONFIG_BLE_MESH_LPN_INIT_POLL_TIMEOUT * 100) +#define POLL_TIMEOUT_MAX(lpn) ((CONFIG_BLE_MESH_LPN_POLL_TIMEOUT * 100) - \ + REQ_RETRY_DURATION(lpn)) + +/* Update 4 to 20 for BQB test case MESH/NODE/FRND/LPM/BI-02-C */ +#define REQ_ATTEMPTS(lpn) (POLL_TIMEOUT_MAX(lpn) < K_SECONDS(3) ? 2 : 4) + +#define CLEAR_ATTEMPTS 2 + +#define LPN_CRITERIA ((CONFIG_BLE_MESH_LPN_MIN_QUEUE_SIZE) | \ + (CONFIG_BLE_MESH_LPN_RSSI_FACTOR << 3) | \ + (CONFIG_BLE_MESH_LPN_RECV_WIN_FACTOR << 5)) + +#define POLL_TO(to) { (u8_t)((to) >> 16), (u8_t)((to) >> 8), (u8_t)(to) } +#define LPN_POLL_TO POLL_TO(CONFIG_BLE_MESH_LPN_POLL_TIMEOUT) + +/* 2 transmissions, 20ms interval */ +#define POLL_XMIT BLE_MESH_TRANSMIT(1, 20) + +static void (*lpn_cb)(u16_t friend_addr, bool established); + +#if defined(CONFIG_BLE_MESH_DEBUG_LOW_POWER) +static const char *state2str(int state) +{ + switch (state) { + case BLE_MESH_LPN_DISABLED: + return "disabled"; + case BLE_MESH_LPN_CLEAR: + return "clear"; + case BLE_MESH_LPN_TIMER: + return "timer"; + case BLE_MESH_LPN_ENABLED: + return "enabled"; + case BLE_MESH_LPN_REQ_WAIT: + return "req wait"; + case BLE_MESH_LPN_WAIT_OFFER: + return "wait offer"; + case BLE_MESH_LPN_ESTABLISHED: + return "established"; + case BLE_MESH_LPN_RECV_DELAY: + return "recv delay"; + case BLE_MESH_LPN_WAIT_UPDATE: + return "wait update"; + default: + return "(unknown)"; + } +} +#endif /* CONFIG_BLE_MESH_DEBUG_LOW_POWER */ + +static inline void lpn_set_state(int state) +{ +#if defined(CONFIG_BLE_MESH_DEBUG_LOW_POWER) + BT_DBG("%s -> %s", state2str(bt_mesh.lpn.state), state2str(state)); +#endif + bt_mesh.lpn.state = state; +} + +static inline void group_zero(bt_mesh_atomic_t *target) +{ +#if CONFIG_BLE_MESH_LPN_GROUPS > 32 + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) { + bt_mesh_atomic_set(&target[i], 0); + } +#else + bt_mesh_atomic_set(target, 0); +#endif +} + +static inline void group_set(bt_mesh_atomic_t *target, bt_mesh_atomic_t *source) +{ +#if CONFIG_BLE_MESH_LPN_GROUPS > 32 + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) { + (void)bt_mesh_atomic_or(&target[i], bt_mesh_atomic_get(&source[i])); + } +#else + (void)bt_mesh_atomic_or(target, bt_mesh_atomic_get(source)); +#endif +} + +static inline void group_clear(bt_mesh_atomic_t *target, bt_mesh_atomic_t *source) +{ +#if CONFIG_BLE_MESH_LPN_GROUPS > 32 + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) { + (void)bt_mesh_atomic_and(&target[i], ~bt_mesh_atomic_get(&source[i])); + } +#else + (void)bt_mesh_atomic_and(target, ~bt_mesh_atomic_get(source)); +#endif +} + +static void clear_friendship(bool force, bool disable); + +static void friend_clear_sent(int err, void *user_data) +{ + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + + /* We're switching away from Low Power behavior, so permanently + * enable scanning. + */ + bt_mesh_scan_enable(); + + lpn->req_attempts++; + + if (err) { + BT_ERR("%s, Sending Friend Request failed (err %d)", __func__, err); + lpn_set_state(BLE_MESH_LPN_ENABLED); + clear_friendship(false, lpn->disable); + return; + } + + lpn_set_state(BLE_MESH_LPN_CLEAR); + k_delayed_work_submit(&lpn->timer, FRIEND_REQ_TIMEOUT); +} + +static const struct bt_mesh_send_cb clear_sent_cb = { + .end = friend_clear_sent, +}; + +static int send_friend_clear(void) +{ + struct bt_mesh_msg_ctx ctx = { + .net_idx = bt_mesh.sub[0].net_idx, + .app_idx = BLE_MESH_KEY_UNUSED, + .addr = bt_mesh.lpn.frnd, + .send_ttl = 0, + }; + struct bt_mesh_net_tx tx = { + .sub = &bt_mesh.sub[0], + .ctx = &ctx, + .src = bt_mesh_primary_addr(), + .xmit = bt_mesh_net_transmit_get(), + }; + struct bt_mesh_ctl_friend_clear req = { + .lpn_addr = sys_cpu_to_be16(tx.src), + .lpn_counter = sys_cpu_to_be16(bt_mesh.lpn.counter), + }; + + BT_DBG("%s", __func__); + + return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_CLEAR, &req, + sizeof(req), NULL, &clear_sent_cb, NULL); +} + +static void clear_friendship(bool force, bool disable) +{ + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + + BT_DBG("force %u disable %u", force, disable); + + if (!force && lpn->established && !lpn->clear_success && + lpn->req_attempts < CLEAR_ATTEMPTS) { + send_friend_clear(); + lpn->disable = disable; + return; + } + + bt_mesh_rx_reset(); + + k_delayed_work_cancel(&lpn->timer); + + friend_cred_del(bt_mesh.sub[0].net_idx, lpn->frnd); + + if (lpn->clear_success) { + lpn->old_friend = BLE_MESH_ADDR_UNASSIGNED; + } else { + lpn->old_friend = lpn->frnd; + } + + if (lpn_cb && lpn->frnd != BLE_MESH_ADDR_UNASSIGNED) { + lpn_cb(lpn->frnd, false); + } + + lpn->frnd = BLE_MESH_ADDR_UNASSIGNED; + lpn->fsn = 0U; + lpn->req_attempts = 0U; + lpn->recv_win = 0U; + lpn->queue_size = 0U; + lpn->disable = 0U; + lpn->sent_req = 0U; + lpn->established = 0U; + lpn->clear_success = 0U; + + group_zero(lpn->added); + group_zero(lpn->pending); + group_zero(lpn->to_remove); + + /* Set this to 1 to force group subscription when the next + * Friendship is created, in case lpn->groups doesn't get + * modified meanwhile. + */ + lpn->groups_changed = 1U; + + if (disable) { + lpn_set_state(BLE_MESH_LPN_DISABLED); + return; + } + + lpn_set_state(BLE_MESH_LPN_ENABLED); + k_delayed_work_submit(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT); +} + +static void friend_req_sent(u16_t duration, int err, void *user_data) +{ + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + + if (err) { + BT_ERR("%s, Sending Friend Request failed (err %d)", __func__, err); + return; + } + + lpn->adv_duration = duration; + + if (IS_ENABLED(CONFIG_BLE_MESH_LPN_ESTABLISHMENT)) { + k_delayed_work_submit(&lpn->timer, FRIEND_REQ_WAIT); + lpn_set_state(BLE_MESH_LPN_REQ_WAIT); + } else { + k_delayed_work_submit(&lpn->timer, + duration + FRIEND_REQ_TIMEOUT); + lpn_set_state(BLE_MESH_LPN_WAIT_OFFER); + } +} + +static const struct bt_mesh_send_cb friend_req_sent_cb = { + .start = friend_req_sent, +}; + +static int send_friend_req(struct bt_mesh_lpn *lpn) +{ + const struct bt_mesh_comp *comp = bt_mesh_comp_get(); + struct bt_mesh_msg_ctx ctx = { + .net_idx = bt_mesh.sub[0].net_idx, + .app_idx = BLE_MESH_KEY_UNUSED, + .addr = BLE_MESH_ADDR_FRIENDS, + .send_ttl = 0, + }; + struct bt_mesh_net_tx tx = { + .sub = &bt_mesh.sub[0], + .ctx = &ctx, + .src = bt_mesh_primary_addr(), + .xmit = POLL_XMIT, + }; + struct bt_mesh_ctl_friend_req req = { + .criteria = LPN_CRITERIA, + .recv_delay = LPN_RECV_DELAY, + .poll_to = LPN_POLL_TO, + .prev_addr = lpn->old_friend, + .num_elem = comp->elem_count, + .lpn_counter = sys_cpu_to_be16(lpn->counter), + }; + + BT_DBG("%s", __func__); + + return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_REQ, &req, + sizeof(req), NULL, &friend_req_sent_cb, NULL); +} + +static void req_sent(u16_t duration, int err, void *user_data) +{ + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + +#if defined(CONFIG_BLE_MESH_DEBUG_LOW_POWER) + BT_DBG("req 0x%02x duration %u err %d state %s", + lpn->sent_req, duration, err, state2str(lpn->state)); +#endif + + if (err) { + BT_ERR("%s, Sending request failed (err %d)", __func__, err); + lpn->sent_req = 0U; + group_zero(lpn->pending); + return; + } + + lpn->req_attempts++; + lpn->adv_duration = duration; + + if (lpn->established || IS_ENABLED(CONFIG_BLE_MESH_LPN_ESTABLISHMENT)) { + lpn_set_state(BLE_MESH_LPN_RECV_DELAY); + /* We start scanning a bit early to elimitate risk of missing + * response data due to HCI and other latencies. + */ + k_delayed_work_submit(&lpn->timer, + LPN_RECV_DELAY - SCAN_LATENCY); + } else { + lpn_set_state(BLE_MESH_LPN_OFFER_RECV); + k_delayed_work_submit(&lpn->timer, + LPN_RECV_DELAY + duration + + lpn->recv_win); + } +} + +static const struct bt_mesh_send_cb req_sent_cb = { + .start = req_sent, +}; + +static int send_friend_poll(void) +{ + struct bt_mesh_msg_ctx ctx = { + .net_idx = bt_mesh.sub[0].net_idx, + .app_idx = BLE_MESH_KEY_UNUSED, + .addr = bt_mesh.lpn.frnd, + .send_ttl = 0, + }; + struct bt_mesh_net_tx tx = { + .sub = &bt_mesh.sub[0], + .ctx = &ctx, + .src = bt_mesh_primary_addr(), + .xmit = POLL_XMIT, + .friend_cred = true, + }; + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + u8_t fsn = lpn->fsn; + int err; + + BT_DBG("lpn->sent_req 0x%02x", lpn->sent_req); + + if (lpn->sent_req) { + if (lpn->sent_req != TRANS_CTL_OP_FRIEND_POLL) { + lpn->pending_poll = 1U; + } + + return 0; + } + + err = bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_POLL, &fsn, 1, + NULL, &req_sent_cb, NULL); + if (err == 0) { + lpn->pending_poll = 0U; + lpn->sent_req = TRANS_CTL_OP_FRIEND_POLL; + } + + return err; +} + +void bt_mesh_lpn_disable(bool force) +{ + if (bt_mesh.lpn.state == BLE_MESH_LPN_DISABLED) { + return; + } + + clear_friendship(force, true); +} + +int bt_mesh_lpn_set(bool enable) +{ + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + + if (enable) { + if (lpn->state != BLE_MESH_LPN_DISABLED) { + return 0; + } + } else { + if (lpn->state == BLE_MESH_LPN_DISABLED) { + return 0; + } + } + + if (!bt_mesh_is_provisioned()) { + if (enable) { + lpn_set_state(BLE_MESH_LPN_ENABLED); + } else { + lpn_set_state(BLE_MESH_LPN_DISABLED); + } + + return 0; + } + + if (enable) { + lpn_set_state(BLE_MESH_LPN_ENABLED); + + if (IS_ENABLED(CONFIG_BLE_MESH_LPN_ESTABLISHMENT)) { + bt_mesh_scan_disable(); + } + + send_friend_req(lpn); + } else { + if (IS_ENABLED(CONFIG_BLE_MESH_LPN_AUTO) && + lpn->state == BLE_MESH_LPN_TIMER) { + k_delayed_work_cancel(&lpn->timer); + lpn_set_state(BLE_MESH_LPN_DISABLED); + } else { + bt_mesh_lpn_disable(false); + } + } + + return 0; +} + +static void friend_response_received(struct bt_mesh_lpn *lpn) +{ + BT_DBG("lpn->sent_req 0x%02x", lpn->sent_req); + + if (lpn->sent_req == TRANS_CTL_OP_FRIEND_POLL) { + lpn->fsn++; + } + + k_delayed_work_cancel(&lpn->timer); + bt_mesh_scan_disable(); + lpn_set_state(BLE_MESH_LPN_ESTABLISHED); + lpn->req_attempts = 0U; + lpn->sent_req = 0U; +} + +void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx) +{ + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + + if (lpn->state == BLE_MESH_LPN_TIMER) { + BT_DBG("Restarting establishment timer"); + k_delayed_work_submit(&lpn->timer, LPN_AUTO_TIMEOUT); + return; + } + + if (lpn->sent_req != TRANS_CTL_OP_FRIEND_POLL) { + BT_WARN("Unexpected message withouth a preceding Poll"); + return; + } + + friend_response_received(lpn); + + BT_DBG("Requesting more messages from Friend"); + + send_friend_poll(); +} + +int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf) +{ + struct bt_mesh_ctl_friend_offer *msg = (void *)buf->data; + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + struct bt_mesh_subnet *sub = rx->sub; + struct friend_cred *cred; + u16_t frnd_counter; + int err; + + if (buf->len < sizeof(*msg)) { + BT_WARN("Too short Friend Offer"); + return -EINVAL; + } + + if (lpn->state != BLE_MESH_LPN_WAIT_OFFER) { + BT_WARN("Ignoring unexpected Friend Offer"); + return 0; + } + + if (!msg->recv_win) { + BT_WARN("Prohibited ReceiveWindow value"); + return -EINVAL; + } + + frnd_counter = sys_be16_to_cpu(msg->frnd_counter); + + BT_DBG("recv_win %u queue_size %u sub_list_size %u rssi %d counter %u", + msg->recv_win, msg->queue_size, msg->sub_list_size, msg->rssi, + frnd_counter); + + lpn->frnd = rx->ctx.addr; + + cred = friend_cred_create(sub, lpn->frnd, lpn->counter, frnd_counter); + if (!cred) { + lpn->frnd = BLE_MESH_ADDR_UNASSIGNED; + return -ENOMEM; + } + + /* TODO: Add offer acceptance criteria check */ + + k_delayed_work_cancel(&lpn->timer); + + lpn->recv_win = msg->recv_win; + lpn->queue_size = msg->queue_size; + + err = send_friend_poll(); + if (err) { + friend_cred_clear(cred); + lpn->frnd = BLE_MESH_ADDR_UNASSIGNED; + lpn->recv_win = 0U; + lpn->queue_size = 0U; + return err; + } + + lpn->counter++; + + return 0; +} + +int bt_mesh_lpn_friend_clear_cfm(struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf) +{ + struct bt_mesh_ctl_friend_clear_confirm *msg = (void *)buf->data; + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + u16_t addr, counter; + + if (buf->len < sizeof(*msg)) { + BT_WARN("Too short Friend Clear Confirm"); + return -EINVAL; + } + + if (lpn->state != BLE_MESH_LPN_CLEAR) { + BT_WARN("Ignoring unexpected Friend Clear Confirm"); + return 0; + } + + addr = sys_be16_to_cpu(msg->lpn_addr); + counter = sys_be16_to_cpu(msg->lpn_counter); + + BT_DBG("LPNAddress 0x%04x LPNCounter 0x%04x", addr, counter); + + if (addr != bt_mesh_primary_addr() || counter != lpn->counter) { + BT_WARN("Invalid parameters in Friend Clear Confirm"); + return 0; + } + + lpn->clear_success = 1U; + clear_friendship(false, lpn->disable); + + return 0; +} + +static void lpn_group_add(u16_t group) +{ + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + u16_t *free_slot = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(lpn->groups); i++) { + if (lpn->groups[i] == group) { + bt_mesh_atomic_clear_bit(lpn->to_remove, i); + return; + } + + if (!free_slot && lpn->groups[i] == BLE_MESH_ADDR_UNASSIGNED) { + free_slot = &lpn->groups[i]; + } + } + + if (!free_slot) { + BT_WARN("Friend Subscription List exceeded!"); + return; + } + + *free_slot = group; + lpn->groups_changed = 1U; +} + +static void lpn_group_del(u16_t group) +{ + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + int i; + + for (i = 0; i < ARRAY_SIZE(lpn->groups); i++) { + if (lpn->groups[i] == group) { + if (bt_mesh_atomic_test_bit(lpn->added, i) || + bt_mesh_atomic_test_bit(lpn->pending, i)) { + bt_mesh_atomic_set_bit(lpn->to_remove, i); + lpn->groups_changed = 1U; + } else { + lpn->groups[i] = BLE_MESH_ADDR_UNASSIGNED; + } + } + } +} + +static inline int group_popcount(bt_mesh_atomic_t *target) +{ +#if CONFIG_BLE_MESH_LPN_GROUPS > 32 + int i, count = 0; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) { + count += popcount(bt_mesh_atomic_get(&target[i])); + } +#else + return popcount(bt_mesh_atomic_get(target)); +#endif +} + +static bool sub_update(u8_t op) +{ + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + int added_count = group_popcount(lpn->added); + struct bt_mesh_msg_ctx ctx = { + .net_idx = bt_mesh.sub[0].net_idx, + .app_idx = BLE_MESH_KEY_UNUSED, + .addr = lpn->frnd, + .send_ttl = 0, + }; + struct bt_mesh_net_tx tx = { + .sub = &bt_mesh.sub[0], + .ctx = &ctx, + .src = bt_mesh_primary_addr(), + .xmit = POLL_XMIT, + .friend_cred = true, + }; + struct bt_mesh_ctl_friend_sub req; + size_t i, g; + + BT_DBG("op 0x%02x sent_req 0x%02x", op, lpn->sent_req); + + if (lpn->sent_req) { + return false; + } + + for (i = 0, g = 0; i < ARRAY_SIZE(lpn->groups); i++) { + if (lpn->groups[i] == BLE_MESH_ADDR_UNASSIGNED) { + continue; + } + + if (op == TRANS_CTL_OP_FRIEND_SUB_ADD) { + if (bt_mesh_atomic_test_bit(lpn->added, i)) { + continue; + } + } else { + if (!bt_mesh_atomic_test_bit(lpn->to_remove, i)) { + continue; + } + } + + if (added_count + g >= lpn->queue_size) { + BT_WARN("%s, Friend Queue Size exceeded", __func__); + break; + } + + req.addr_list[g++] = sys_cpu_to_be16(lpn->groups[i]); + bt_mesh_atomic_set_bit(lpn->pending, i); + + if (g == ARRAY_SIZE(req.addr_list)) { + break; + } + } + + if (g == 0) { + group_zero(lpn->pending); + return false; + } + + req.xact = lpn->xact_next++; + + if (bt_mesh_ctl_send(&tx, op, &req, 1 + g * 2, NULL, + &req_sent_cb, NULL) < 0) { + group_zero(lpn->pending); + return false; + } + + lpn->xact_pending = req.xact; + lpn->sent_req = op; + return true; +} + +static void update_timeout(struct bt_mesh_lpn *lpn) +{ + if (lpn->established) { + BT_WARN("No response from Friend during ReceiveWindow"); + bt_mesh_scan_disable(); + lpn_set_state(BLE_MESH_LPN_ESTABLISHED); + k_delayed_work_submit(&lpn->timer, POLL_RETRY_TIMEOUT); + } else { + if (IS_ENABLED(CONFIG_BLE_MESH_LPN_ESTABLISHMENT)) { + bt_mesh_scan_disable(); + } + + if (lpn->req_attempts < 6) { + BT_WARN("Retrying first Friend Poll"); + lpn->sent_req = 0U; + if (send_friend_poll() == 0) { + return; + } + } + + BT_ERR("Timed out waiting for first Friend Update"); + clear_friendship(false, false); + } +} + +static void lpn_timeout(struct k_work *work) +{ + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + +#if defined(CONFIG_BLE_MESH_DEBUG_LOW_POWER) + BT_DBG("state: %s", state2str(lpn->state)); +#endif + + switch (lpn->state) { + case BLE_MESH_LPN_DISABLED: + break; + case BLE_MESH_LPN_CLEAR: + clear_friendship(false, bt_mesh.lpn.disable); + break; + case BLE_MESH_LPN_TIMER: + BT_DBG("Starting to look for Friend nodes"); + lpn_set_state(BLE_MESH_LPN_ENABLED); + if (IS_ENABLED(CONFIG_BLE_MESH_LPN_ESTABLISHMENT)) { + bt_mesh_scan_disable(); + } + /* fall through */ + case BLE_MESH_LPN_ENABLED: + send_friend_req(lpn); + break; + case BLE_MESH_LPN_REQ_WAIT: + bt_mesh_scan_enable(); + k_delayed_work_submit(&lpn->timer, + lpn->adv_duration + FRIEND_REQ_SCAN); + lpn_set_state(BLE_MESH_LPN_WAIT_OFFER); + break; + case BLE_MESH_LPN_WAIT_OFFER: + BT_WARN("No acceptable Friend Offers received"); + if (IS_ENABLED(CONFIG_BLE_MESH_LPN_ESTABLISHMENT)) { + bt_mesh_scan_disable(); + } + lpn->counter++; + lpn_set_state(BLE_MESH_LPN_ENABLED); + k_delayed_work_submit(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT); + break; + case BLE_MESH_LPN_OFFER_RECV: + BT_WARN("No Friend Update received after the first Friend Poll"); + lpn->sent_req = 0U; + send_friend_poll(); + break; + case BLE_MESH_LPN_ESTABLISHED: + if (lpn->req_attempts < REQ_ATTEMPTS(lpn)) { + u8_t req = lpn->sent_req; + + lpn->sent_req = 0U; + + if (!req || req == TRANS_CTL_OP_FRIEND_POLL) { + send_friend_poll(); + } else { + sub_update(req); + } + + break; + } + + BT_ERR("No response from Friend after %u retries", + lpn->req_attempts); + lpn->req_attempts = 0U; + clear_friendship(false, false); + break; + case BLE_MESH_LPN_RECV_DELAY: + k_delayed_work_submit(&lpn->timer, + lpn->adv_duration + SCAN_LATENCY + + lpn->recv_win); + bt_mesh_scan_enable(); + lpn_set_state(BLE_MESH_LPN_WAIT_UPDATE); + break; + case BLE_MESH_LPN_WAIT_UPDATE: + update_timeout(lpn); + break; + default: + __ASSERT(0, "Unhandled LPN state"); + break; + } +} + +void bt_mesh_lpn_group_add(u16_t group) +{ + BT_DBG("group 0x%04x", group); + + lpn_group_add(group); + + if (!bt_mesh_lpn_established() || bt_mesh.lpn.sent_req) { + return; + } + + sub_update(TRANS_CTL_OP_FRIEND_SUB_ADD); +} + +void bt_mesh_lpn_group_del(u16_t *groups, size_t group_count) +{ + int i; + + for (i = 0; i < group_count; i++) { + if (groups[i] != BLE_MESH_ADDR_UNASSIGNED) { + BT_DBG("group 0x%04x", groups[i]); + lpn_group_del(groups[i]); + } + } + + if (!bt_mesh_lpn_established() || bt_mesh.lpn.sent_req) { + return; + } + + sub_update(TRANS_CTL_OP_FRIEND_SUB_REM); +} + +static s32_t poll_timeout(struct bt_mesh_lpn *lpn) +{ + /* If we're waiting for segment acks keep polling at high freq */ + if (bt_mesh_tx_in_progress()) { + return MIN(POLL_TIMEOUT_MAX(lpn), K_SECONDS(1)); + } + + if (lpn->poll_timeout < POLL_TIMEOUT_MAX(lpn)) { + lpn->poll_timeout *= 2; + lpn->poll_timeout = MIN(lpn->poll_timeout, + POLL_TIMEOUT_MAX(lpn)); + } + + BT_DBG("Poll Timeout is %ums", lpn->poll_timeout); + + return lpn->poll_timeout; +} + +int bt_mesh_lpn_friend_sub_cfm(struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf) +{ + struct bt_mesh_ctl_friend_sub_confirm *msg = (void *)buf->data; + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + + if (buf->len < sizeof(*msg)) { + BT_WARN("Too short Friend Subscription Confirm"); + return -EINVAL; + } + + BT_DBG("xact 0x%02x", msg->xact); + + if (!lpn->sent_req) { + BT_WARN("No pending subscription list message"); + return 0; + } + + if (msg->xact != lpn->xact_pending) { + BT_WARN("Transaction mismatch (0x%02x != 0x%02x)", + msg->xact, lpn->xact_pending); + return 0; + } + + if (lpn->sent_req == TRANS_CTL_OP_FRIEND_SUB_ADD) { + group_set(lpn->added, lpn->pending); + group_zero(lpn->pending); + } else if (lpn->sent_req == TRANS_CTL_OP_FRIEND_SUB_REM) { + int i; + + group_clear(lpn->added, lpn->pending); + + for (i = 0; i < ARRAY_SIZE(lpn->groups); i++) { + if (bt_mesh_atomic_test_and_clear_bit(lpn->pending, i) && + bt_mesh_atomic_test_and_clear_bit(lpn->to_remove, i)) { + lpn->groups[i] = BLE_MESH_ADDR_UNASSIGNED; + } + } + } else { + BT_WARN("Unexpected Friend Subscription Confirm"); + return 0; + } + + friend_response_received(lpn); + + if (lpn->groups_changed) { + sub_update(TRANS_CTL_OP_FRIEND_SUB_ADD); + sub_update(TRANS_CTL_OP_FRIEND_SUB_REM); + + if (!lpn->sent_req) { + lpn->groups_changed = 0U; + } + } + + if (lpn->pending_poll) { + send_friend_poll(); + } + + if (!lpn->sent_req) { + k_delayed_work_submit(&lpn->timer, poll_timeout(lpn)); + } + + return 0; +} + +int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf) +{ + struct bt_mesh_ctl_friend_update *msg = (void *)buf->data; + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + struct bt_mesh_subnet *sub = rx->sub; + u32_t iv_index; + + if (buf->len < sizeof(*msg)) { + BT_WARN("Too short Friend Update"); + return -EINVAL; + } + + if (lpn->sent_req != TRANS_CTL_OP_FRIEND_POLL) { + BT_WARN("Unexpected friend update"); + return 0; + } + + if (sub->kr_phase == BLE_MESH_KR_PHASE_2 && !rx->new_key) { + BT_WARN("Ignoring Phase 2 KR Update secured using old key"); + return 0; + } + + if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_INITIATOR) && + (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS) == + BLE_MESH_IV_UPDATE(msg->flags))) { + bt_mesh_beacon_ivu_initiator(false); + } + + if (!lpn->established) { + /* This is normally checked on the transport layer, however + * in this state we're also still accepting master + * credentials so we need to ensure the right ones (Friend + * Credentials) were used for this message. + */ + if (!rx->friend_cred) { + BT_WARN("Friend Update with wrong credentials"); + return -EINVAL; + } + + lpn->established = 1U; + + BT_INFO("Friendship established with 0x%04x", lpn->frnd); + + if (lpn_cb) { + lpn_cb(lpn->frnd, true); + } + + /* Set initial poll timeout */ + lpn->poll_timeout = MIN(POLL_TIMEOUT_MAX(lpn), + POLL_TIMEOUT_INIT); + } + + friend_response_received(lpn); + + iv_index = sys_be32_to_cpu(msg->iv_index); + + BT_DBG("flags 0x%02x iv_index 0x%08x md %u", msg->flags, iv_index, + msg->md); + + if (bt_mesh_kr_update(sub, BLE_MESH_KEY_REFRESH(msg->flags), + rx->new_key)) { + bt_mesh_net_beacon_update(sub); + } + + bt_mesh_net_iv_update(iv_index, BLE_MESH_IV_UPDATE(msg->flags)); + + if (lpn->groups_changed) { + sub_update(TRANS_CTL_OP_FRIEND_SUB_ADD); + sub_update(TRANS_CTL_OP_FRIEND_SUB_REM); + + if (!lpn->sent_req) { + lpn->groups_changed = 0U; + } + } + + if (msg->md) { + BT_DBG("Requesting for more messages"); + send_friend_poll(); + } + + if (!lpn->sent_req) { + k_delayed_work_submit(&lpn->timer, poll_timeout(lpn)); + } + + return 0; +} + +int bt_mesh_lpn_poll(void) +{ + if (!bt_mesh.lpn.established) { + return -EAGAIN; + } + + BT_DBG("Requesting more messages"); + + return send_friend_poll(); +} + +void bt_mesh_lpn_set_cb(void (*cb)(u16_t friend_addr, bool established)) +{ + lpn_cb = cb; +} + +int bt_mesh_lpn_init(void) +{ + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + + BT_DBG("%s", __func__); + + k_delayed_work_init(&lpn->timer, lpn_timeout); + + if (lpn->state == BLE_MESH_LPN_ENABLED) { + if (IS_ENABLED(CONFIG_BLE_MESH_LPN_ESTABLISHMENT)) { + bt_mesh_scan_disable(); + } else { + bt_mesh_scan_enable(); + } + + send_friend_req(lpn); + } else { + bt_mesh_scan_enable(); + + if (IS_ENABLED(CONFIG_BLE_MESH_LPN_AUTO)) { + BT_DBG("Waiting %u ms for messages", LPN_AUTO_TIMEOUT); + lpn_set_state(BLE_MESH_LPN_TIMER); + k_delayed_work_submit(&lpn->timer, LPN_AUTO_TIMEOUT); + } + } + + return 0; +} + +#endif /* CONFIG_BLE_MESH_LOW_POWER */ diff --git a/components/bt/ble_mesh/mesh_core/lpn.h b/components/bt/ble_mesh/mesh_core/lpn.h new file mode 100644 index 0000000000..ad870e99e1 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/lpn.h @@ -0,0 +1,67 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _LPN_H_ +#define _LPN_H_ + +int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf); +int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf); +int bt_mesh_lpn_friend_clear_cfm(struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf); +int bt_mesh_lpn_friend_sub_cfm(struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf); + +static inline bool bt_mesh_lpn_established(void) +{ +#if defined(CONFIG_BLE_MESH_LOW_POWER) + return bt_mesh.lpn.established; +#else + return false; +#endif +} + +static inline bool bt_mesh_lpn_match(u16_t addr) +{ +#if defined(CONFIG_BLE_MESH_LOW_POWER) + if (bt_mesh_lpn_established()) { + return (addr == bt_mesh.lpn.frnd); + } +#endif + return false; +} + +static inline bool bt_mesh_lpn_waiting_update(void) +{ +#if defined(CONFIG_BLE_MESH_LOW_POWER) + return (bt_mesh.lpn.state == BLE_MESH_LPN_WAIT_UPDATE); +#else + return false; +#endif +} + +static inline bool bt_mesh_lpn_timer(void) +{ +#if defined(CONFIG_BLE_MESH_LPN_AUTO) + return (bt_mesh.lpn.state == BLE_MESH_LPN_TIMER); +#else + return false; +#endif +} + +void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx); + +void bt_mesh_lpn_group_add(u16_t group); +void bt_mesh_lpn_group_del(u16_t *groups, size_t group_count); + +void bt_mesh_lpn_disable(bool force); + +int bt_mesh_lpn_init(void); + +#endif /* _LPN_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/mesh.h b/components/bt/ble_mesh/mesh_core/mesh.h new file mode 100644 index 0000000000..c536184aa9 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/mesh.h @@ -0,0 +1,22 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _MESH_H_ +#define _MESH_H_ + +#define BLE_MESH_KEY_PRIMARY 0x0000 +#define BLE_MESH_KEY_ANY 0xffff + +#define BLE_MESH_ADDR_IS_UNICAST(addr) ((addr) && (addr) < 0x8000) +#define BLE_MESH_ADDR_IS_GROUP(addr) ((addr) >= 0xc000 && (addr) <= 0xff00) +#define BLE_MESH_ADDR_IS_VIRTUAL(addr) ((addr) >= 0x8000 && (addr) < 0xc000) +#define BLE_MESH_ADDR_IS_RFU(addr) ((addr) >= 0xff00 && (addr) <= 0xfffb) + +struct bt_mesh_net; + +#endif /* _MESH_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/mesh_aes_encrypt.c b/components/bt/ble_mesh/mesh_core/mesh_aes_encrypt.c new file mode 100644 index 0000000000..2d1842cc4b --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/mesh_aes_encrypt.c @@ -0,0 +1,409 @@ +/* aes_encrypt.c - TinyCrypt implementation of AES encryption procedure */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mesh_aes_encrypt.h" +#include "mesh_util.h" +#include "sdkconfig.h" + +/* max number of calls until change the key (2^48).*/ +const static uint64_t MAX_CALLS = ((uint64_t)1 << 48); + +/* + * gf_wrap -- In our implementation, GF(2^128) is represented as a 16 byte + * array with byte 0 the most significant and byte 15 the least significant. + * High bit carry reduction is based on the primitive polynomial + * + * X^128 + X^7 + X^2 + X + 1, + * + * which leads to the reduction formula X^128 = X^7 + X^2 + X + 1. Indeed, + * since 0 = (X^128 + X^7 + X^2 + 1) mod (X^128 + X^7 + X^2 + X + 1) and since + * addition of polynomials with coefficients in Z/Z(2) is just XOR, we can + * add X^128 to both sides to get + * + * X^128 = (X^7 + X^2 + X + 1) mod (X^128 + X^7 + X^2 + X + 1) + * + * and the coefficients of the polynomial on the right hand side form the + * string 1000 0111 = 0x87, which is the value of gf_wrap. + * + * This gets used in the following way. Doubling in GF(2^128) is just a left + * shift by 1 bit, except when the most significant bit is 1. In the latter + * case, the relation X^128 = X^7 + X^2 + X + 1 says that the high order bit + * that overflows beyond 128 bits can be replaced by addition of + * X^7 + X^2 + X + 1 <--> 0x87 to the low order 128 bits. Since addition + * in GF(2^128) is represented by XOR, we therefore only have to XOR 0x87 + * into the low order byte after a left shift when the starting high order + * bit is 1. + */ +const unsigned char gf_wrap = 0x87; + +static const uint8_t sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, + 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, + 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, + 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, + 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, + 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, + 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, + 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, + 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, + 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, + 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, + 0xb0, 0x54, 0xbb, 0x16 +}; + +static inline unsigned int rotword(unsigned int a) +{ + return (((a) >> 24) | ((a) << 8)); +} + +#define subbyte(a, o) (sbox[((a) >> (o))&0xff] << (o)) +#define subword(a) (subbyte(a, 24)|subbyte(a, 16)|subbyte(a, 8)|subbyte(a, 0)) + +int tc_aes128_set_encrypt_key(TCAesKeySched_t s, const uint8_t *k) +{ + const unsigned int rconst[11] = { + 0x00000000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, + 0x20000000, 0x40000000, 0x80000000, 0x1b000000, 0x36000000 + }; + unsigned int i; + unsigned int t; + + if (s == (TCAesKeySched_t) 0) { + return TC_CRYPTO_FAIL; + } else if (k == (const uint8_t *) 0) { + return TC_CRYPTO_FAIL; + } + + for (i = 0; i < Nk; ++i) { + s->words[i] = (k[Nb * i] << 24) | (k[Nb * i + 1] << 16) | + (k[Nb * i + 2] << 8) | (k[Nb * i + 3]); + } + + for (; i < (Nb * (Nr + 1)); ++i) { + t = s->words[i - 1]; + if ((i % Nk) == 0) { + t = subword(rotword(t)) ^ rconst[i / Nk]; + } + s->words[i] = s->words[i - Nk] ^ t; + } + + return TC_CRYPTO_SUCCESS; +} + +static inline void add_round_key(uint8_t *s, const unsigned int *k) +{ + s[0] ^= (uint8_t)(k[0] >> 24); s[1] ^= (uint8_t)(k[0] >> 16); + s[2] ^= (uint8_t)(k[0] >> 8); s[3] ^= (uint8_t)(k[0]); + s[4] ^= (uint8_t)(k[1] >> 24); s[5] ^= (uint8_t)(k[1] >> 16); + s[6] ^= (uint8_t)(k[1] >> 8); s[7] ^= (uint8_t)(k[1]); + s[8] ^= (uint8_t)(k[2] >> 24); s[9] ^= (uint8_t)(k[2] >> 16); + s[10] ^= (uint8_t)(k[2] >> 8); s[11] ^= (uint8_t)(k[2]); + s[12] ^= (uint8_t)(k[3] >> 24); s[13] ^= (uint8_t)(k[3] >> 16); + s[14] ^= (uint8_t)(k[3] >> 8); s[15] ^= (uint8_t)(k[3]); +} + +static inline void sub_bytes(uint8_t *s) +{ + unsigned int i; + + for (i = 0; i < (Nb * Nk); ++i) { + s[i] = sbox[s[i]]; + } +} + +#define triple(a)(_double_byte(a)^(a)) + +static inline void mult_row_column(uint8_t *out, const uint8_t *in) +{ + out[0] = _double_byte(in[0]) ^ triple(in[1]) ^ in[2] ^ in[3]; + out[1] = in[0] ^ _double_byte(in[1]) ^ triple(in[2]) ^ in[3]; + out[2] = in[0] ^ in[1] ^ _double_byte(in[2]) ^ triple(in[3]); + out[3] = triple(in[0]) ^ in[1] ^ in[2] ^ _double_byte(in[3]); +} + +static inline void mix_columns(uint8_t *s) +{ + uint8_t t[Nb * Nk]; + + mult_row_column(t, s); + mult_row_column(&t[Nb], s + Nb); + mult_row_column(&t[2 * Nb], s + (2 * Nb)); + mult_row_column(&t[3 * Nb], s + (3 * Nb)); + (void) _copy(s, sizeof(t), t, sizeof(t)); +} + +/* + * This shift_rows also implements the matrix flip required for mix_columns, but + * performs it here to reduce the number of memory operations. + */ +static inline void shift_rows(uint8_t *s) +{ + uint8_t t[Nb * Nk]; + + t[0] = s[0]; t[1] = s[5]; t[2] = s[10]; t[3] = s[15]; + t[4] = s[4]; t[5] = s[9]; t[6] = s[14]; t[7] = s[3]; + t[8] = s[8]; t[9] = s[13]; t[10] = s[2]; t[11] = s[7]; + t[12] = s[12]; t[13] = s[1]; t[14] = s[6]; t[15] = s[11]; + (void) _copy(s, sizeof(t), t, sizeof(t)); +} + +int tc_aes_encrypt(uint8_t *out, const uint8_t *in, const TCAesKeySched_t s) +{ + uint8_t state[Nk * Nb]; + unsigned int i; + + if (out == (uint8_t *) 0) { + return TC_CRYPTO_FAIL; + } else if (in == (const uint8_t *) 0) { + return TC_CRYPTO_FAIL; + } else if (s == (TCAesKeySched_t) 0) { + return TC_CRYPTO_FAIL; + } + + (void)_copy(state, sizeof(state), in, sizeof(state)); + add_round_key(state, s->words); + + for (i = 0; i < (Nr - 1); ++i) { + sub_bytes(state); + shift_rows(state); + mix_columns(state); + add_round_key(state, s->words + Nb * (i + 1)); + } + + sub_bytes(state); + shift_rows(state); + add_round_key(state, s->words + Nb * (i + 1)); + + (void)_copy(out, sizeof(state), state, sizeof(state)); + + /* zeroing out the state buffer */ + _set(state, TC_ZERO_BYTE, sizeof(state)); + + return TC_CRYPTO_SUCCESS; +} + +int tc_cmac_setup(TCCmacState_t s, const uint8_t *key, TCAesKeySched_t sched) +{ + + /* input sanity check: */ + if (s == (TCCmacState_t) 0 || + key == (const uint8_t *) 0) { + return TC_CRYPTO_FAIL; + } + + /* put s into a known state */ + _set(s, 0, sizeof(*s)); + s->sched = sched; + + /* configure the encryption key used by the underlying block cipher */ + tc_aes128_set_encrypt_key(s->sched, key); + + /* compute s->K1 and s->K2 from s->iv using s->keyid */ + _set(s->iv, 0, TC_AES_BLOCK_SIZE); + tc_aes_encrypt(s->iv, s->iv, s->sched); + gf_double (s->K1, s->iv); + gf_double (s->K2, s->K1); + + /* reset s->iv to 0 in case someone wants to compute now */ + tc_cmac_init(s); + + return TC_CRYPTO_SUCCESS; +} + +/* + * assumes: out != NULL and points to a GF(2^n) value to receive the + * doubled value; + * in != NULL and points to a 16 byte GF(2^n) value + * to double; + * the in and out buffers do not overlap. + * effects: doubles the GF(2^n) value pointed to by "in" and places + * the result in the GF(2^n) value pointed to by "out." + */ +void gf_double(uint8_t *out, uint8_t *in) +{ + + /* start with low order byte */ + uint8_t *x = in + (TC_AES_BLOCK_SIZE - 1); + + /* if msb == 1, we need to add the gf_wrap value, otherwise add 0 */ + uint8_t carry = (in[0] >> 7) ? gf_wrap : 0; + + out += (TC_AES_BLOCK_SIZE - 1); + for (;;) { + *out-- = (*x << 1) ^ carry; + if (x == in) { + break; + } + carry = *x-- >> 7; + } +} + +int tc_cmac_init(TCCmacState_t s) +{ + /* input sanity check: */ + if (s == (TCCmacState_t) 0) { + return TC_CRYPTO_FAIL; + } + + /* CMAC starts with an all zero initialization vector */ + _set(s->iv, 0, TC_AES_BLOCK_SIZE); + + /* and the leftover buffer is empty */ + _set(s->leftover, 0, TC_AES_BLOCK_SIZE); + s->leftover_offset = 0; + + /* Set countdown to max number of calls allowed before re-keying: */ + s->countdown = MAX_CALLS; + + return TC_CRYPTO_SUCCESS; +} + +int tc_cmac_update(TCCmacState_t s, const uint8_t *data, size_t data_length) +{ + unsigned int i; + + /* input sanity check: */ + if (s == (TCCmacState_t) 0) { + return TC_CRYPTO_FAIL; + } + if (data_length == 0) { + return TC_CRYPTO_SUCCESS; + } + if (data == (const uint8_t *) 0) { + return TC_CRYPTO_FAIL; + } + + if (s->countdown == 0) { + return TC_CRYPTO_FAIL; + } + + s->countdown--; + + if (s->leftover_offset > 0) { + /* last data added to s didn't end on a TC_AES_BLOCK_SIZE byte boundary */ + size_t remaining_space = TC_AES_BLOCK_SIZE - s->leftover_offset; + + if (data_length < remaining_space) { + /* still not enough data to encrypt this time either */ + _copy(&s->leftover[s->leftover_offset], data_length, data, data_length); + s->leftover_offset += data_length; + return TC_CRYPTO_SUCCESS; + } + /* leftover block is now full; encrypt it first */ + _copy(&s->leftover[s->leftover_offset], + remaining_space, + data, + remaining_space); + data_length -= remaining_space; + data += remaining_space; + s->leftover_offset = 0; + + for (i = 0; i < TC_AES_BLOCK_SIZE; ++i) { + s->iv[i] ^= s->leftover[i]; + } + tc_aes_encrypt(s->iv, s->iv, s->sched); + } + + /* CBC encrypt each (except the last) of the data blocks */ + while (data_length > TC_AES_BLOCK_SIZE) { + for (i = 0; i < TC_AES_BLOCK_SIZE; ++i) { + s->iv[i] ^= data[i]; + } + tc_aes_encrypt(s->iv, s->iv, s->sched); + data += TC_AES_BLOCK_SIZE; + data_length -= TC_AES_BLOCK_SIZE; + } + + if (data_length > 0) { + /* save leftover data for next time */ + _copy(s->leftover, data_length, data, data_length); + s->leftover_offset = data_length; + } + + return TC_CRYPTO_SUCCESS; +} + +int tc_cmac_final(uint8_t *tag, TCCmacState_t s) +{ + uint8_t *k; + unsigned int i; + + /* input sanity check: */ + if (tag == (uint8_t *) 0 || + s == (TCCmacState_t) 0) { + return TC_CRYPTO_FAIL; + } + + if (s->leftover_offset == TC_AES_BLOCK_SIZE) { + /* the last message block is a full-sized block */ + k = (uint8_t *) s->K1; + } else { + /* the final message block is not a full-sized block */ + size_t remaining = TC_AES_BLOCK_SIZE - s->leftover_offset; + + _set(&s->leftover[s->leftover_offset], 0, remaining); + s->leftover[s->leftover_offset] = TC_CMAC_PADDING; + k = (uint8_t *) s->K2; + } + for (i = 0; i < TC_AES_BLOCK_SIZE; ++i) { + s->iv[i] ^= s->leftover[i] ^ k[i]; + } + + tc_aes_encrypt(tag, s->iv, s->sched); + + /* erasing state: */ + tc_cmac_erase(s); + + return TC_CRYPTO_SUCCESS; +} + +int tc_cmac_erase(TCCmacState_t s) +{ + if (s == (TCCmacState_t) 0) { + return TC_CRYPTO_FAIL; + } + + /* destroy the current state */ + _set(s, 0, sizeof(*s)); + + return TC_CRYPTO_SUCCESS; +} diff --git a/components/bt/ble_mesh/mesh_core/mesh_atomic.c b/components/bt/ble_mesh/mesh_core/mesh_atomic.c new file mode 100644 index 0000000000..ce73638053 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/mesh_atomic.c @@ -0,0 +1,179 @@ +/** + * @brief Atomically set a bit. + * + * Atomically set bit number @a bit of @a target. + * The target may be a single atomic variable or an array of them. + * + * @param target Address of atomic variable or array. + * @param bit Bit number (starting from 0). + * + * @return N/A + */ + +/* + * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2011-2014 Wind River Systems, Inc. + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "mesh_atomic.h" +#include "mesh_kernel.h" +#include "sdkconfig.h" + +#ifndef CONFIG_ATOMIC_OPERATIONS_BUILTIN + +/** +* +* @brief Atomic get primitive +* +* @param target memory location to read from +* +* This routine provides the atomic get primitive to atomically read +* a value from . It simply does an ordinary load. Note that +* is expected to be aligned to a 4-byte boundary. +* +* @return The value read from +*/ +bt_mesh_atomic_val_t bt_mesh_atomic_get(const bt_mesh_atomic_t *target) +{ + return *target; +} + +/** + * + * @brief Atomic get-and-set primitive + * + * This routine provides the atomic set operator. The is atomically + * written at and the previous value at is returned. + * + * @param target the memory location to write to + * @param value the value to write + * + * @return The previous value from + */ +bt_mesh_atomic_val_t bt_mesh_atomic_set(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t value) +{ + unsigned int key; + bt_mesh_atomic_val_t ret; + + key = bt_mesh_irq_lock(); + + ret = *target; + *target = value; + + bt_mesh_irq_unlock(key); + + return ret; +} + +/** + * + * @brief Atomic bitwise inclusive OR primitive + * + * This routine provides the atomic bitwise inclusive OR operator. The + * is atomically bitwise OR'ed with the value at , placing the result + * at , and the previous value at is returned. + * + * @param target the memory location to be modified + * @param value the value to OR + * + * @return The previous value from + */ +bt_mesh_atomic_val_t bt_mesh_atomic_or(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t value) +{ + unsigned int key; + bt_mesh_atomic_val_t ret; + + key = bt_mesh_irq_lock(); + + ret = *target; + *target |= value; + + bt_mesh_irq_unlock(key); + + return ret; +} + +/** + * + * @brief Atomic bitwise AND primitive + * + * This routine provides the atomic bitwise AND operator. The is + * atomically bitwise AND'ed with the value at , placing the result + * at , and the previous value at is returned. + * + * @param target the memory location to be modified + * @param value the value to AND + * + * @return The previous value from + */ +bt_mesh_atomic_val_t bt_mesh_atomic_and(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t value) +{ + unsigned int key; + bt_mesh_atomic_val_t ret; + + key = bt_mesh_irq_lock(); + + ret = *target; + *target &= value; + + bt_mesh_irq_unlock(key); + + return ret; +} + +/** + * + * @brief Atomic decrement primitive + * + * @param target memory location to decrement + * + * This routine provides the atomic decrement operator. The value at + * is atomically decremented by 1, and the old value from is returned. + * + * @return The value from prior to the decrement + */ +bt_mesh_atomic_val_t bt_mesh_atomic_dec(bt_mesh_atomic_t *target) +{ + unsigned int key; + bt_mesh_atomic_val_t ret; + + key = bt_mesh_irq_lock(); + + ret = *target; + (*target)--; + + bt_mesh_irq_unlock(key); + + return ret; +} + +/** + * + * @brief Atomic increment primitive + * + * @param target memory location to increment + * + * This routine provides the atomic increment operator. The value at + * is atomically incremented by 1, and the old value from is returned. + * + * @return The value from before the increment + */ +bt_mesh_atomic_val_t bt_mesh_atomic_inc(bt_mesh_atomic_t *target) +{ + unsigned int key; + bt_mesh_atomic_val_t ret; + + key = bt_mesh_irq_lock(); + + ret = *target; + (*target)++; + + bt_mesh_irq_unlock(key); + + return ret; +} + +#endif /* #ifndef CONFIG_ATOMIC_OPERATIONS_BUILTIN */ diff --git a/components/bt/ble_mesh/mesh_core/mesh_bearer_adapt.c b/components/bt/ble_mesh/mesh_core/mesh_bearer_adapt.c new file mode 100644 index 0000000000..67bea67e03 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/mesh_bearer_adapt.c @@ -0,0 +1,1858 @@ +/* + * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2015-2016 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "sdkconfig.h" + +#include "bta/bta_api.h" +#include "bta/bta_gatt_api.h" +#include "bta/bta_gatt_common.h" +#include "bta_gattc_int.h" +#include "stack/btm_ble_api.h" +#include "p_256_ecc_pp.h" +#include "stack/hcimsgs.h" +#include "osi/future.h" +#include "osi/allocator.h" + +#include "mbedtls/aes.h" + +#include "mesh_hci.h" +#include "mesh_aes_encrypt.h" +#include "mesh_bearer_adapt.h" +#include "mesh_trace.h" +#include "mesh_buf.h" +#include "mesh_atomic.h" + +#include "provisioner_prov.h" +#include "mesh_common.h" + +#define BLE_MESH_BTM_CHECK_STATUS(func) do { \ + tBTM_STATUS __status = (func); \ + if ((__status != BTM_SUCCESS) && (__status != BTM_CMD_STARTED)) { \ + BT_ERR("%s, Invalid status %d", __func__, __status); \ + return -1; \ + } \ + } while(0); + +#define BLE_MESH_GATT_GET_CONN_ID(conn_id) (((u16_t)(conn_id)) >> 8) +#define BLE_MESH_GATT_CREATE_CONN_ID(gatt_if, conn_id) ((u16_t)((((u8_t)(conn_id)) << 8) | ((u8_t)(gatt_if)))) + +/* We don't need to manage the BLE_MESH_DEV_ADVERTISING flags in the version of bluedriod, + * it will manage it in the BTM layer. + */ +#define BLE_MESH_DEV 0 + +/* P-256 Variables */ +static u8_t bt_mesh_public_key[64]; +static BT_OCTET32 bt_mesh_private_key = { + 0x3f, 0x49, 0xf6, 0xd4, 0xa3, 0xc5, 0x5f, 0x38, + 0x74, 0xc9, 0xb3, 0xe3, 0xd2, 0x10, 0x3f, 0x50, + 0x4a, 0xff, 0x60, 0x7b, 0xeb, 0x40, 0xb7, 0x99, + 0x58, 0x99, 0xb8, 0xa6, 0xcd, 0x3c, 0x1a, 0xbd +}; + +/* Scan related functions */ +static bt_mesh_scan_cb_t *bt_mesh_scan_dev_found_cb; +static void bt_mesh_scan_result_callback(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data); + +#if defined(CONFIG_BLE_MESH_NODE) && CONFIG_BLE_MESH_NODE +/* the gatt database list to save the attribute table */ +static sys_slist_t bt_mesh_gatts_db; + +/* Static Variables */ +static struct bt_mesh_conn bt_mesh_gatts_conn[BLE_MESH_MAX_CONN]; +static struct bt_mesh_conn_cb *bt_mesh_gatts_conn_cb; +static tBTA_GATTS_IF bt_mesh_gatts_if; +static BD_ADDR bt_mesh_gatts_addr; +static u16_t svc_handle, char_handle; +static future_t *future_mesh; + +/* Static Functions */ +static struct bt_mesh_gatt_attr *bt_mesh_gatts_find_attr_by_handle(u16_t handle); +#endif /* defined(CONFIG_BLE_MESH_NODE) && CONFIG_BLE_MESH_NODE */ + +#if defined(CONFIG_BLE_MESH_PROVISIONER) && CONFIG_BLE_MESH_PROVISIONER +#define BLE_MESH_GATTC_APP_UUID_BYTE 0x97 +static struct gattc_prov_info { + /* Service to be found depends on the type of adv pkt received */ + struct bt_mesh_conn conn; + BD_ADDR addr; + u8_t addr_type; + u16_t service_uuid; + u16_t mtu; + bool wr_desc_done; /* Indicate if write char descriptor event is received */ + u16_t start_handle; /* Service attribute start handle */ + u16_t end_handle; /* Service attribute end handle */ + u16_t data_in_handle; /* Data In Characteristic attribute handle */ + u16_t data_out_handle; /* Data Out Characteristic attribute handle */ + u16_t ccc_handle; /* Data Out Characteristic CCC attribute handle */ +} bt_mesh_gattc_info[BLE_MESH_MAX_CONN]; +static struct bt_mesh_prov_conn_cb *bt_mesh_gattc_conn_cb; +static tBTA_GATTC_IF bt_mesh_gattc_if; +#endif /* defined(CONFIG_BLE_MESH_PROVISIONER) && CONFIG_BLE_MESH_PROVISIONER */ + +static void bt_mesh_scan_results_change_2_bta(tBTM_INQ_RESULTS *p_inq, u8_t *p_eir, + tBTA_DM_SEARCH_CBACK *p_scan_cback) +{ + tBTM_INQ_INFO *p_inq_info; + tBTA_DM_SEARCH result; + + bdcpy(result.inq_res.bd_addr, p_inq->remote_bd_addr); + result.inq_res.rssi = p_inq->rssi; + result.inq_res.ble_addr_type = p_inq->ble_addr_type; + result.inq_res.inq_result_type = p_inq->inq_result_type; + result.inq_res.device_type = p_inq->device_type; + result.inq_res.flag = p_inq->flag; + result.inq_res.adv_data_len = p_inq->adv_data_len; + result.inq_res.scan_rsp_len = p_inq->scan_rsp_len; + memcpy(result.inq_res.dev_class, p_inq->dev_class, sizeof(DEV_CLASS)); + result.inq_res.ble_evt_type = p_inq->ble_evt_type; + + /* application will parse EIR to find out remote device name */ + result.inq_res.p_eir = p_eir; + + if ((p_inq_info = BTM_InqDbRead(p_inq->remote_bd_addr)) != NULL) { + /* initialize remt_name_not_required to FALSE so that we get the name by default */ + result.inq_res.remt_name_not_required = FALSE; + } + + if (p_scan_cback) { + p_scan_cback(BTA_DM_INQ_RES_EVT, &result); + } + + if (p_inq_info) { + /* application indicates if it knows the remote name, inside the callback + copy that to the inquiry data base*/ + if (result.inq_res.remt_name_not_required) { + p_inq_info->appl_knows_rem_name = TRUE; + } + } +} + +static void bt_mesh_scan_results_cb(tBTM_INQ_RESULTS *p_inq, u8_t *p_eir) +{ + bt_mesh_scan_results_change_2_bta(p_inq, p_eir, bt_mesh_scan_result_callback); +} + +static bool valid_adv_param(const struct bt_mesh_adv_param *param) +{ + if (!(param->options & BLE_MESH_ADV_OPT_CONNECTABLE)) { +#if BLE_MESH_DEV + if (bt_mesh_dev.hci_version < BLE_MESH_HCI_VERSION_5_0 && + param->interval_min < 0x00a0) { + return false; + } +#endif + } + + if (param->interval_min > param->interval_max || + param->interval_min < 0x0020 || param->interval_max > 0x4000) { + return false; + } + + return true; +} + +static int set_adv_data(u16_t hci_op, const struct bt_mesh_adv_data *ad, size_t ad_len) +{ + struct bt_mesh_hci_cp_set_adv_data param = {0}; + int i; + + if (ad == NULL || ad_len == 0) { + return 0; + } + + for (i = 0; i < ad_len; i++) { + /* Check if ad fit in the remaining buffer */ + if (param.len + ad[i].data_len + 2 > 31) { + return -EINVAL; + } + + param.data[param.len++] = ad[i].data_len + 1; + param.data[param.len++] = ad[i].type; + + memcpy(¶m.data[param.len], ad[i].data, ad[i].data_len); + param.len += ad[i].data_len; + } + + /* Set adv data and scan rsp data. */ + if (hci_op == BLE_MESH_HCI_OP_SET_ADV_DATA) { + BLE_MESH_BTM_CHECK_STATUS(BTM_BleWriteAdvDataRaw(param.data, param.len)); + } else if (hci_op == BLE_MESH_HCI_OP_SET_SCAN_RSP_DATA) { + BLE_MESH_BTM_CHECK_STATUS(BTM_BleWriteScanRspRaw(param.data, param.len)); + } + + return 0; +} + +static void start_adv_completed_cb(u8_t status) +{ +#if BLE_MESH_DEV + if (!status) { + bt_mesh_atomic_set_bit(bt_mesh_dev.flags, BLE_MESH_DEV_ADVERTISING); + } +#endif +} + +static bool valid_scan_param(const struct bt_mesh_scan_param *param) +{ + if (param->type != BLE_MESH_SCAN_PASSIVE && + param->type != BLE_MESH_SCAN_ACTIVE) { + return false; + } + + if (param->filter_dup != BLE_MESH_SCAN_FILTER_DUP_DISABLE && + param->filter_dup != BLE_MESH_SCAN_FILTER_DUP_ENABLE) { + return false; + } + + if (param->interval < 0x0004 || param->interval > 0x4000) { + return false; + } + + if (param->window < 0x0004 || param->window > 0x4000) { + return false; + } + + if (param->window > param->interval) { + return false; + } + + return true; +} + +static int start_le_scan(u8_t scan_type, u16_t interval, u16_t window, u8_t filter_dup) +{ + UINT8 scan_fil_policy = BLE_MESH_SP_ADV_ALL; /* No whitelist for BLE Mesh */ + UINT8 addr_type_own = BLE_MESH_ADDR_PUBLIC; /* Currently only support Public Address */ + tGATT_IF client_if = 0xFF; /* Default GATT interface id */ + + BLE_MESH_BTM_CHECK_STATUS( + BTM_BleSetScanFilterParams(client_if, interval, window, scan_type, addr_type_own, + filter_dup, scan_fil_policy, NULL)); + + /* BLE Mesh scan permanently, so no duration of scan here */ + BLE_MESH_BTM_CHECK_STATUS(BTM_BleScan(true, 0, bt_mesh_scan_results_cb, NULL, NULL)); + +#if BLE_MESH_DEV + if (scan_type == BLE_MESH_SCAN_ACTIVE) { + bt_mesh_atomic_set_bit(bt_mesh_dev.flags, BLE_MESH_DEV_ACTIVE_SCAN); + } else { + bt_mesh_atomic_clear_bit(bt_mesh_dev.flags, BLE_MESH_DEV_ACTIVE_SCAN); + } +#endif + + return 0; +} + +static void bt_mesh_scan_result_callback(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data) +{ + bt_mesh_addr_t addr = {0}; + UINT8 adv_type; + UINT8 rssi; + + BT_DBG("%s, event = %d", __func__, event); + + if (event == BTA_DM_INQ_RES_EVT) { + /* TODO: How to process scan response here? */ + addr.type = p_data->inq_res.ble_addr_type; + memcpy(addr.val, p_data->inq_res.bd_addr, BLE_MESH_ADDR_LEN); + rssi = p_data->inq_res.rssi; + adv_type = p_data->inq_res.ble_evt_type; + + /* scan rsp len: p_data->inq_res.scan_rsp_len */ + struct net_buf_simple *buf = bt_mesh_alloc_buf(p_data->inq_res.adv_data_len); + if (!buf) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + net_buf_simple_add_mem(buf, p_data->inq_res.p_eir, p_data->inq_res.adv_data_len); + + if (bt_mesh_scan_dev_found_cb != NULL) { + bt_mesh_scan_dev_found_cb(&addr, rssi, adv_type, buf); + } + osi_free(buf); + } else if (event == BTA_DM_INQ_CMPL_EVT) { + BT_INFO("%s, Scan completed, number of scan response %d", __func__, p_data->inq_cmpl.num_resps); + } else { + BT_WARN("%s, Unexpected event 0x%x", __func__, event); + } +} + +/* APIs functions */ +int bt_le_adv_start(const struct bt_mesh_adv_param *param, + const struct bt_mesh_adv_data *ad, size_t ad_len, + const struct bt_mesh_adv_data *sd, size_t sd_len) +{ + tBTA_START_ADV_CMPL_CBACK *p_start_adv_cb; + tBTM_BLE_ADV_CHNL_MAP channel_map; + tBLE_ADDR_TYPE addr_type_own; + tBLE_BD_ADDR p_dir_bda = {0}; + tBTM_BLE_AFP adv_fil_pol; + UINT8 adv_type; + int err; + +#if BLE_MESH_DEV + if (bt_mesh_atomic_test_bit(bt_mesh_dev.flags, BLE_MESH_DEV_ADVERTISING)) { + return -EALREADY; + } +#endif + + if (!valid_adv_param(param)) { + BT_ERR("%s, Invalid adv parameters", __func__); + return -EINVAL; + } + + err = set_adv_data(BLE_MESH_HCI_OP_SET_ADV_DATA, ad, ad_len); + if (err) { + BT_ERR("%s, Failed to set adv data", __func__); + return err; + } + + /* + * We need to set SCAN_RSP when enabling advertising type that allows + * for Scan Requests. + * + * If sd was not provided but we enable connectable undirected + * advertising sd needs to be cleared from values set by previous calls. + * Clearing sd is done by calling set_adv_data() with NULL data and zero len. + * So following condition check is unusual but correct. + */ + if (sd && (param->options & BLE_MESH_ADV_OPT_CONNECTABLE)) { + err = set_adv_data(BLE_MESH_HCI_OP_SET_SCAN_RSP_DATA, sd, sd_len); + if (err) { + BT_ERR("%s, Failed to set scan rsp data", __func__); + return err; + } + } + + if (param->options & BLE_MESH_ADV_OPT_CONNECTABLE) { + adv_type = BLE_MESH_ADV_IND; + } else if (sd != NULL) { + adv_type = BLE_MESH_ADV_SCAN_IND; + } else { + adv_type = BLE_MESH_ADV_NONCONN_IND; + } + addr_type_own = BLE_MESH_ADDR_PUBLIC; /* Currently only support Public Address */ + channel_map = BLE_MESH_ADV_CHNL_37 | BLE_MESH_ADV_CHNL_38 | BLE_MESH_ADV_CHNL_39; + adv_fil_pol = BLE_MESH_AP_SCAN_CONN_ALL; + p_start_adv_cb = start_adv_completed_cb; + + /* Check if we can start adv using BTM_BleSetAdvParamsStartAdvCheck */ + BLE_MESH_BTM_CHECK_STATUS( + BTM_BleSetAdvParamsAll(param->interval_min, param->interval_max, adv_type, + addr_type_own, &p_dir_bda, + channel_map, adv_fil_pol, p_start_adv_cb)); + BLE_MESH_BTM_CHECK_STATUS(BTM_BleStartAdv()); + +#if BLE_MESH_DEV + bt_mesh_atomic_set_bit(bt_mesh_dev.flags, BLE_MESH_DEV_ADVERTISING); + + if (!(param->options & BLE_MESH_ADV_OPT_ONE_TIME)) { + bt_mesh_atomic_set_bit(bt_mesh_dev.flags, BLE_MESH_DEV_KEEP_ADVERTISING); + } +#endif + + return 0; +} + +int bt_le_adv_stop(void) +{ +#if BLE_MESH_DEV + bt_mesh_atomic_clear_bit(bt_mesh_dev.flags, BLE_MESH_DEV_KEEP_ADVERTISING); + if (!bt_mesh_atomic_test_bit(bt_mesh_dev.flags, BLE_MESH_DEV_ADVERTISING)) { + return 0; + } +#endif + + BLE_MESH_BTM_CHECK_STATUS(BTM_BleBroadcast(false, NULL)); + +#if BLE_MESH_DEV + bt_mesh_atomic_clear_bit(bt_mesh_dev.flags, BLE_MESH_DEV_ADVERTISING); +#endif + + return 0; +} + +int bt_le_scan_start(const struct bt_mesh_scan_param *param, bt_mesh_scan_cb_t cb) +{ + int err; + +#if BLE_MESH_DEV + if (bt_mesh_atomic_test_bit(bt_mesh_dev.flags, BLE_MESH_DEV_SCANNING)) { + return -EALREADY; + } +#endif + + if (!valid_scan_param(param)) { + return -EINVAL; + } + +#if BLE_MESH_DEV + if (param->filter_dup) { + bt_mesh_atomic_set_bit(bt_mesh_dev.flags, BLE_MESH_DEV_SCAN_FILTER_DUP); + } else { + bt_mesh_atomic_clear_bit(bt_mesh_dev.flags, BLE_MESH_DEV_SCAN_FILTER_DUP); + } +#endif + + err = start_le_scan(param->type, param->interval, param->window, param->filter_dup); + if (err) { + return err; + } + +#if BLE_MESH_DEV + bt_mesh_atomic_set_bit(bt_mesh_dev.flags, BLE_MESH_DEV_SCANNING); +#endif + + bt_mesh_scan_dev_found_cb = cb; + return err; +} + +int bt_le_scan_stop(void) +{ +#if BLE_MESH_DEV + if (bt_mesh_atomic_test_bit(bt_mesh_dev.flags, BLE_MESH_DEV_SCANNING)) { + bt_mesh_atomic_clear_bit(bt_mesh_dev.flags, BLE_MESH_DEV_SCANNING); + BLE_MESH_BTM_CHECK_STATUS(BTM_BleScan(false, 0, NULL, NULL, NULL)); + } +#else + BLE_MESH_BTM_CHECK_STATUS(BTM_BleScan(false, 0, NULL, NULL, NULL)); +#endif + + bt_mesh_scan_dev_found_cb = NULL; + return 0; +} + +#if defined(CONFIG_BLE_MESH_NODE) && CONFIG_BLE_MESH_NODE +static void bt_mesh_bta_gatts_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) +{ + switch (event) { + case BTA_GATTS_REG_EVT: + if (p_data->reg_oper.status == BTA_GATT_OK) { + bt_mesh_gatts_if = p_data->reg_oper.server_if; + } + break; + case BTA_GATTS_READ_EVT: { + struct bt_mesh_gatt_attr *attr = bt_mesh_gatts_find_attr_by_handle(p_data->req_data.p_data->read_req.handle); + u8_t index = BLE_MESH_GATT_GET_CONN_ID(p_data->req_data.conn_id); + tBTA_GATTS_RSP rsp; + u8_t buf[100] = {0}; + u16_t len = 0; + + BT_DBG("%s, read: handle = %d", __func__, p_data->req_data.p_data->read_req.handle); + + if (attr != NULL && attr->read != NULL) { + if ((len = attr->read(&bt_mesh_gatts_conn[index], attr, buf, 100, + p_data->req_data.p_data->read_req.offset)) > 0) { + rsp.attr_value.handle = p_data->req_data.p_data->read_req.handle; + rsp.attr_value.len = len; + memcpy(&rsp.attr_value.value[0], buf, len); + BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id, + p_data->req_data.status, &rsp); + BT_DBG("%s, Send gatts read response, handle = %x", __func__, attr->handle); + } else { + BT_WARN("%s, BLE Mesh gatts read failed", __func__); + } + } + break; + } + case BTA_GATTS_WRITE_EVT: { + struct bt_mesh_gatt_attr *attr = bt_mesh_gatts_find_attr_by_handle(p_data->req_data.p_data->write_req.handle); + u8_t index = BLE_MESH_GATT_GET_CONN_ID(p_data->req_data.conn_id); + u16_t len = 0; + + BT_DBG("%s, write: handle = %d, len = %d, data = %s", __func__, p_data->req_data.p_data->write_req.handle, + p_data->req_data.p_data->write_req.len, + bt_hex(p_data->req_data.p_data->write_req.value, p_data->req_data.p_data->write_req.len)); + + if (attr != NULL && attr->write != NULL) { + if ((len = attr->write(&bt_mesh_gatts_conn[index], attr, + p_data->req_data.p_data->write_req.value, + p_data->req_data.p_data->write_req.len, + p_data->req_data.p_data->write_req.offset, 0)) > 0) { + if (p_data->req_data.p_data->write_req.need_rsp) { + BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id, + p_data->req_data.status, NULL); + BT_DBG("%s, send mesh write rsp, handle = %x", __func__, attr->handle); + } + } + } + break; + } + case BTA_GATTS_EXEC_WRITE_EVT: + break; + case BTA_GATTS_MTU_EVT: + break; + case BTA_GATTS_CONF_EVT: + break; + case BTA_GATTS_CREATE_EVT: + svc_handle = p_data->create.service_id; + BT_DBG("%s, svc_handle = %d, future_mesh = %p", __func__, svc_handle, future_mesh); + if (future_mesh != NULL) { + future_ready(future_mesh, FUTURE_SUCCESS); + } + break; + case BTA_GATTS_ADD_INCL_SRVC_EVT: + svc_handle = p_data->add_result.attr_id; + if (future_mesh != NULL) { + future_ready(future_mesh, FUTURE_SUCCESS); + } + break; + case BTA_GATTS_ADD_CHAR_EVT: + char_handle = p_data->add_result.attr_id; + if (future_mesh != NULL) { + future_ready(future_mesh, FUTURE_SUCCESS); + } + break; + case BTA_GATTS_ADD_CHAR_DESCR_EVT: + char_handle = p_data->add_result.attr_id; + if (future_mesh != NULL) { + future_ready(future_mesh, FUTURE_SUCCESS); + } + break; + case BTA_GATTS_DELELTE_EVT: + break; + case BTA_GATTS_START_EVT: + break; + case BTA_GATTS_STOP_EVT: + break; + case BTA_GATTS_CONNECT_EVT: +#if BLE_MESH_DEV + /* When connection is created, advertising will be stopped automatically. */ + bt_mesh_atomic_test_and_clear_bit(bt_mesh_dev.flags, BLE_MESH_DEV_ADVERTISING); +#endif + if (bt_mesh_gatts_conn_cb != NULL && bt_mesh_gatts_conn_cb->connected != NULL) { + u8_t index = BLE_MESH_GATT_GET_CONN_ID(p_data->conn.conn_id); + if (index < BLE_MESH_MAX_CONN) { + bt_mesh_gatts_conn[index].handle = BLE_MESH_GATT_GET_CONN_ID(p_data->conn.conn_id); + (bt_mesh_gatts_conn_cb->connected)(&bt_mesh_gatts_conn[index], 0); + } + memcpy(bt_mesh_gatts_addr, p_data->conn.remote_bda, BLE_MESH_ADDR_LEN); + /* This is for EspBleMesh Android app. When it tries to connect with the + * device at the first time and it fails due to some reason. And after + * the second connection, the device needs to send GATT service change + * indication to the phone manually to notify it dicovering service again. + */ + BTA_GATTS_SendServiceChangeIndication(bt_mesh_gatts_if, bt_mesh_gatts_addr); + } + break; + case BTA_GATTS_DISCONNECT_EVT: +#if BLE_MESH_DEV + bt_mesh_atomic_test_and_clear_bit(bt_mesh_dev.flags, BLE_MESH_DEV_ADVERTISING); +#endif + if (bt_mesh_gatts_conn_cb != NULL && bt_mesh_gatts_conn_cb->disconnected != NULL) { + u8_t index = BLE_MESH_GATT_GET_CONN_ID(p_data->conn.conn_id); + if (index < BLE_MESH_MAX_CONN) { + bt_mesh_gatts_conn[index].handle = BLE_MESH_GATT_GET_CONN_ID(p_data->conn.conn_id); + (bt_mesh_gatts_conn_cb->disconnected)(&bt_mesh_gatts_conn[index], p_data->conn.reason); + } + memset(bt_mesh_gatts_addr, 0x0, BLE_MESH_ADDR_LEN); + } + break; + case BTA_GATTS_CLOSE_EVT: + break; + default: + break; + } +} + +void bt_mesh_gatts_conn_cb_register(struct bt_mesh_conn_cb *cb) +{ + bt_mesh_gatts_conn_cb = cb; +} + +static struct bt_mesh_gatt_attr *bt_mesh_gatts_find_attr_by_handle(u16_t handle) +{ + struct bt_mesh_gatt_service *svc = NULL; + struct bt_mesh_gatt_attr *attr = NULL; + + SYS_SLIST_FOR_EACH_CONTAINER(&bt_mesh_gatts_db, svc, node) { + int i; + + for (i = 0; i < svc->attr_count; i++) { + attr = &svc->attrs[i]; + /* Check the attrs handle is equal to the handle or not */ + if (attr->handle == handle) { + return attr; + } + } + } + + return NULL; +} + +static void bt_mesh_gatts_foreach_attr(u16_t start_handle, u16_t end_handle, + bt_mesh_gatt_attr_func_t func, void *user_data) +{ + struct bt_mesh_gatt_service *svc = NULL; + + SYS_SLIST_FOR_EACH_CONTAINER(&bt_mesh_gatts_db, svc, node) { + int i; + + for (i = 0; i < svc->attr_count; i++) { + struct bt_mesh_gatt_attr *attr = &svc->attrs[i]; + + /* Check if attribute handle is within range */ + if (attr->handle < start_handle || + attr->handle > end_handle) { + continue; + } + + if (func(attr, user_data) == BLE_MESH_GATT_ITER_STOP) { + return; + } + } + } +} + +static u8_t find_next(const struct bt_mesh_gatt_attr *attr, void *user_data) +{ + struct bt_mesh_gatt_attr **next = user_data; + + *next = (struct bt_mesh_gatt_attr *)attr; + + return BLE_MESH_GATT_ITER_STOP; +} + +static struct bt_mesh_gatt_attr *bt_mesh_gatts_attr_next(const struct bt_mesh_gatt_attr *attr) +{ + struct bt_mesh_gatt_attr *next = NULL; + + bt_mesh_gatts_foreach_attr(attr->handle + 1, attr->handle + 1, find_next, &next); + + return next; +} + +ssize_t bt_mesh_gatts_attr_read(struct bt_mesh_conn *conn, const struct bt_mesh_gatt_attr *attr, + void *buf, u16_t buf_len, u16_t offset, + const void *value, u16_t value_len) +{ + u16_t len; + + if (offset > value_len) { + return BLE_MESH_GATT_ERR(BLE_MESH_ATT_ERR_INVALID_OFFSET); + } + + len = MIN(buf_len, value_len - offset); + + BT_DBG("handle 0x%04x offset %u length %u", attr->handle, offset, len); + + memcpy(buf, value + offset, len); + + return len; +} + +struct gatts_incl { + u16_t start_handle; + u16_t end_handle; + u16_t uuid16; +} __packed; + +ssize_t bt_mesh_gatts_attr_read_included(struct bt_mesh_conn *conn, + const struct bt_mesh_gatt_attr *attr, + void *buf, u16_t len, u16_t offset) +{ + struct bt_mesh_gatt_attr *incl = attr->user_data; + struct bt_mesh_uuid *uuid = incl->user_data; + struct gatts_incl pdu = {0}; + u8_t value_len; + + /* First attr points to the start handle */ + pdu.start_handle = sys_cpu_to_le16(incl->handle); + value_len = sizeof(pdu.start_handle) + sizeof(pdu.end_handle); + + /* + * Core 4.2, Vol 3, Part G, 3.2, + * The Service UUID shall only be present when the UUID is a 16-bit Bluetooth UUID. + */ + if (uuid->type == BLE_MESH_UUID_TYPE_16) { + pdu.uuid16 = sys_cpu_to_le16(BLE_MESH_UUID_16(uuid)->val); + value_len += sizeof(pdu.uuid16); + } + + return bt_mesh_gatts_attr_read(conn, attr, buf, len, offset, &pdu, value_len); +} + +ssize_t bt_mesh_gatts_attr_read_service(struct bt_mesh_conn *conn, + const struct bt_mesh_gatt_attr *attr, + void *buf, u16_t len, u16_t offset) +{ + struct bt_mesh_uuid *uuid = attr->user_data; + + if (uuid->type == BLE_MESH_UUID_TYPE_16) { + u16_t uuid16 = sys_cpu_to_le16(BLE_MESH_UUID_16(uuid)->val); + + return bt_mesh_gatts_attr_read(conn, attr, buf, len, offset, &uuid16, 2); + } + + return bt_mesh_gatts_attr_read(conn, attr, buf, len, offset, + BLE_MESH_UUID_128(uuid)->val, 16); +} + +struct gatts_chrc { + u8_t properties; + u16_t value_handle; + union { + u16_t uuid16; + u8_t uuid[16]; + }; +} __packed; + +ssize_t bt_mesh_gatts_attr_read_chrc(struct bt_mesh_conn *conn, + const struct bt_mesh_gatt_attr *attr, void *buf, + u16_t len, u16_t offset) +{ + struct bt_mesh_gatt_char *chrc = attr->user_data; + const struct bt_mesh_gatt_attr *next = NULL; + struct gatts_chrc pdu = {0}; + u8_t value_len; + + pdu.properties = chrc->properties; + /* BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part G] page 534: + * 3.3.2 Characteristic Value Declaration + * The Characteristic Value declaration contains the value of the + * characteristic. It is the first Attribute after the characteristic + * declaration. All characteristic definitions shall have a + * Characteristic Value declaration. + */ + next = bt_mesh_gatts_attr_next(attr); + if (!next) { + BT_WARN("%s, No value for characteristic at 0x%04x", __func__, attr->handle); + pdu.value_handle = 0x0000; + } else { + pdu.value_handle = sys_cpu_to_le16(next->handle); + } + value_len = sizeof(pdu.properties) + sizeof(pdu.value_handle); + + if (chrc->uuid->type == BLE_MESH_UUID_TYPE_16) { + pdu.uuid16 = sys_cpu_to_le16(BLE_MESH_UUID_16(chrc->uuid)->val); + value_len += 2; + } else { + memcpy(pdu.uuid, BLE_MESH_UUID_128(chrc->uuid)->val, 16); + value_len += 16; + } + + return bt_mesh_gatts_attr_read(conn, attr, buf, len, offset, &pdu, value_len); +} + +static void bta_uuid_to_bt_mesh_uuid(tBT_UUID *bta_uuid, const struct bt_mesh_uuid *uuid) +{ + assert(uuid != NULL && bta_uuid != NULL); + + if (uuid->type == BLE_MESH_UUID_TYPE_16) { + bta_uuid->len = LEN_UUID_16; + bta_uuid->uu.uuid16 = BLE_MESH_UUID_16(uuid)->val; + } else if (uuid->type == BLE_MESH_UUID_TYPE_32) { + bta_uuid->len = LEN_UUID_32; + bta_uuid->uu.uuid32 = BLE_MESH_UUID_32(uuid)->val; + } else if (uuid->type == BLE_MESH_UUID_TYPE_128) { + bta_uuid->len = LEN_UUID_128; + memcpy(bta_uuid->uu.uuid128, BLE_MESH_UUID_128(uuid)->val, LEN_UUID_128); + } else { + BT_ERR("%s, Invalid mesh uuid type = %d", __func__, uuid->type); + } + + return; +} + +static int gatts_register(struct bt_mesh_gatt_service *svc) +{ + struct bt_mesh_gatt_service *last; + u16_t handle; + + if (sys_slist_is_empty(&bt_mesh_gatts_db)) { + handle = 0; + goto populate; + } + + last = SYS_SLIST_PEEK_TAIL_CONTAINER(&bt_mesh_gatts_db, last, node); + handle = last->attrs[last->attr_count - 1].handle; + BT_DBG("%s, handle = %d", __func__, handle); + +populate: + sys_slist_append(&bt_mesh_gatts_db, &svc->node); + return 0; +} + +static tBTA_GATT_PERM bt_mesh_perm_to_bta_perm(u8_t perm) +{ + tBTA_GATT_PERM bta_perm = 0; + + if ((perm & BLE_MESH_GATT_PERM_READ) == BLE_MESH_GATT_PERM_READ) { + bta_perm |= BTA_GATT_PERM_READ; + } + + if ((perm & BLE_MESH_GATT_PERM_WRITE) == BLE_MESH_GATT_PERM_WRITE) { + bta_perm |= BTA_GATT_PERM_WRITE; + } + + if ((perm & BLE_MESH_GATT_PERM_READ_ENCRYPT) == BLE_MESH_GATT_PERM_READ_ENCRYPT) { + bta_perm |= BTA_GATT_PERM_READ_ENCRYPTED; + } + + if ((perm & BLE_MESH_GATT_PERM_WRITE_ENCRYPT) == BLE_MESH_GATT_PERM_WRITE_ENCRYPT) { + bta_perm |= BTA_GATT_PERM_WRITE_ENCRYPTED; + } + + if ((perm & BLE_MESH_GATT_PERM_READ_AUTHEN) == BLE_MESH_GATT_PERM_READ_AUTHEN) { + bta_perm |= BTA_GATT_PERM_READ_ENC_MITM; + } + + if ((perm & BLE_MESH_GATT_PERM_WRITE_AUTHEN) == BLE_MESH_GATT_PERM_WRITE_AUTHEN) { + bta_perm |= BTA_GATT_PERM_WRITE_ENC_MITM; + } + + return bta_perm; +} + +int bt_mesh_gatts_service_register(struct bt_mesh_gatt_service *svc) +{ + tBT_UUID bta_uuid = {0}; + + assert(svc != NULL); + + for (int i = 0; i < svc->attr_count; i++) { + if (svc->attrs[i].uuid->type == BLE_MESH_UUID_TYPE_16) { + switch (BLE_MESH_UUID_16(svc->attrs[i].uuid)->val) { + case BLE_MESH_UUID_GATT_PRIMARY_VAL: { + future_mesh = future_new(); + bta_uuid_to_bt_mesh_uuid(&bta_uuid, (struct bt_mesh_uuid *)svc->attrs[i].user_data); + BTA_GATTS_CreateService(bt_mesh_gatts_if, + &bta_uuid, 0, svc->attr_count, true); + if (future_await(future_mesh) == FUTURE_FAIL) { + BT_ERR("%s, Failed to add primary service", __func__); + return ESP_FAIL; + } + svc->attrs[i].handle = svc_handle; + BT_DBG("Add primary service: svc_uuid = %x, perm = %d, svc_handle = %d", bta_uuid.uu.uuid16, svc->attrs[i].perm, svc_handle); + break; + } + case BLE_MESH_UUID_GATT_SECONDARY_VAL: { + future_mesh = future_new(); + bta_uuid_to_bt_mesh_uuid(&bta_uuid, (struct bt_mesh_uuid *)svc->attrs[i].user_data); + BTA_GATTS_CreateService(bt_mesh_gatts_if, + &bta_uuid, 0, svc->attr_count, false); + if (future_await(future_mesh) == FUTURE_FAIL) { + BT_ERR("%s, Failed to add secondary service", __func__); + return ESP_FAIL; + } + svc->attrs[i].handle = svc_handle; + BT_DBG("Add secondary service: svc_uuid = %x, perm = %d, svc_handle = %d", bta_uuid.uu.uuid16, svc->attrs[i].perm, svc_handle); + break; + } + case BLE_MESH_UUID_GATT_INCLUDE_VAL: { + break; + } + case BLE_MESH_UUID_GATT_CHRC_VAL: { + future_mesh = future_new(); + struct bt_mesh_gatt_char *gatts_chrc = (struct bt_mesh_gatt_char *)svc->attrs[i].user_data; + bta_uuid_to_bt_mesh_uuid(&bta_uuid, gatts_chrc->uuid); + BTA_GATTS_AddCharacteristic(svc_handle, &bta_uuid, bt_mesh_perm_to_bta_perm(svc->attrs[i + 1].perm), gatts_chrc->properties, NULL, NULL); + if (future_await(future_mesh) == FUTURE_FAIL) { + BT_ERR("%s, Failed to add characristic", __func__); + return ESP_FAIL; + } + /* All the characristic should have two handle: the declaration handle and the value handle */ + svc->attrs[i].handle = char_handle - 1; + svc->attrs[i + 1].handle = char_handle; + BT_DBG("Add characteristic: char_uuid = %x, char_handle = %d, perm = %d, char_pro = %d", BLE_MESH_UUID_16(gatts_chrc->uuid)->val, char_handle, svc->attrs[i + 1].perm, gatts_chrc->properties); + break; + } + case BLE_MESH_UUID_GATT_CEP_VAL: + case BLE_MESH_UUID_GATT_CUD_VAL: + case BLE_MESH_UUID_GATT_CCC_VAL: + case BLE_MESH_UUID_GATT_SCC_VAL: + case BLE_MESH_UUID_GATT_CPF_VAL: + case BLE_MESH_UUID_VALID_RANGE_VAL: + case BLE_MESH_UUID_HIDS_EXT_REPORT_VAL: + case BLE_MESH_UUID_HIDS_REPORT_REF_VAL: + case BLE_MESH_UUID_ES_CONFIGURATION_VAL: + case BLE_MESH_UUID_ES_MEASUREMENT_VAL: + case BLE_MESH_UUID_ES_TRIGGER_SETTING_VAL: { + future_mesh = future_new(); + bta_uuid_to_bt_mesh_uuid(&bta_uuid, svc->attrs[i].uuid); + BTA_GATTS_AddCharDescriptor(svc_handle, bt_mesh_perm_to_bta_perm(svc->attrs[i].perm), &bta_uuid, NULL, NULL); + if (future_await(future_mesh) == FUTURE_FAIL) { + BT_ERR("%s, Failed to add descriptor", __func__); + return ESP_FAIL; + } + svc->attrs[i].handle = char_handle; + BT_DBG("Add descriptor: descr_uuid = %x, perm= %d, descr_handle = %d", BLE_MESH_UUID_16(svc->attrs[i].uuid)->val, svc->attrs[i].perm, char_handle); + break; + } + default: + break; + } + } + } + + if (svc_handle != 0) { + svc_handle = 0; + } + + gatts_register(svc); + return 0; +} + +int bt_mesh_gatts_disconnect(struct bt_mesh_conn *conn, u8_t reason) +{ + UNUSED(reason); + u16_t conn_id = BLE_MESH_GATT_CREATE_CONN_ID(bt_mesh_gatts_if, conn->handle); + BTA_GATTS_Close(conn_id); + return 0; +} + +int bt_mesh_gatts_service_unregister(struct bt_mesh_gatt_service *svc) +{ + assert(svc != NULL); + + BTA_GATTS_DeleteService(svc->attrs[0].handle); + return 0; +} + +int bt_mesh_gatts_notify(struct bt_mesh_conn *conn, const struct bt_mesh_gatt_attr *attr, + const void *data, u16_t len) +{ + u16_t conn_id = BLE_MESH_GATT_CREATE_CONN_ID(bt_mesh_gatts_if, conn->handle); + BTA_GATTS_HandleValueIndication(conn_id, attr->handle, len, (u8_t *)data, false); + return 0; +} + +u16_t bt_mesh_gatt_get_mtu(struct bt_mesh_conn *conn) +{ + return BTA_GATT_GetLocalMTU(); +} + +/* APIs added by Espressif */ +int bt_mesh_gatts_service_stop(struct bt_mesh_gatt_service *svc) +{ + if (!svc) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + BT_DBG("Stop service:%d", svc->attrs[0].handle); + + BTA_GATTS_StopService(svc->attrs[0].handle); + return 0; +} + +int bt_mesh_gatts_service_start(struct bt_mesh_gatt_service *svc) +{ + struct bt_mesh_uuid_16 *uuid_16 = NULL; + struct bt_mesh_uuid *uuid = NULL; + + if (!svc) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + BT_DBG("Start service:%d", svc->attrs[0].handle); + + BTA_GATTS_StartService(svc->attrs[0].handle, BTA_GATT_TRANSPORT_LE); + + /* For EspBleMesh Android app, it does not disconnect after provisioning + * is done, and hence we send GATT service change indication manually + * when Mesh Proxy Service is started after provisioning. + */ + uuid = (struct bt_mesh_uuid *)svc->attrs[0].user_data; + if (uuid && uuid->type == BLE_MESH_UUID_TYPE_16) { + uuid_16 = (struct bt_mesh_uuid_16 *)uuid; + BT_DBG("%s, type 0x%02x, val 0x%04x", __func__, uuid_16->uuid.type, uuid_16->val); + if (uuid_16->val == BLE_MESH_UUID_MESH_PROXY_VAL) { + BTA_GATTS_SendServiceChangeIndication(bt_mesh_gatts_if, bt_mesh_gatts_addr); + } + } + + return 0; +} +#endif /* defined(CONFIG_BLE_MESH_NODE) && CONFIG_BLE_MESH_NODE */ + +#if defined(CONFIG_BLE_MESH_PROVISIONER) && CONFIG_BLE_MESH_PROVISIONER +void bt_mesh_gattc_conn_cb_register(struct bt_mesh_prov_conn_cb *cb) +{ + bt_mesh_gattc_conn_cb = cb; +} + +u16_t bt_mesh_gattc_get_service_uuid(struct bt_mesh_conn *conn) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { + if (conn == &bt_mesh_gattc_info[i].conn) { + break; + } + } + + if (i == ARRAY_SIZE(bt_mesh_gattc_info)) { + return 0; + } + + return bt_mesh_gattc_info[i].service_uuid; +} + +/** For provisioner acting as a GATT client, it may follow the procedures + * listed below. + * 1. Create connection with the unprovisioned device + * 2. Exchange MTU size + * 3. Find Mesh Prov Service in the device's service database + * 4. Find Mesh Prov Data In/Out characteristic within the service + * 5. Get CCC of Mesh Prov Data Out Characteristic + * 6. Set the Notification bit of CCC + */ + +int bt_mesh_gattc_conn_create(const bt_mesh_addr_t *addr, u16_t service_uuid) +{ + u8_t zero[6] = {0}; + int i; + + if (!addr || !memcmp(addr->val, zero, BLE_MESH_ADDR_LEN) || + (addr->type > BLE_ADDR_RANDOM)) { + BT_ERR("%s, Invalid remote address", __func__); + return -EINVAL; + } + + if (service_uuid != BLE_MESH_UUID_MESH_PROV_VAL && + service_uuid != BLE_MESH_UUID_MESH_PROXY_VAL) { + BT_ERR("%s, Invalid service uuid 0x%04x", __func__, service_uuid); + return -EINVAL; + } + + /* Check if already creating connection with the device */ + for (i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { + if (!memcmp(bt_mesh_gattc_info[i].addr, addr->val, BLE_MESH_ADDR_LEN)) { + BT_WARN("%s, Already create connection with %s", + __func__, bt_hex(addr->val, BLE_MESH_ADDR_LEN)); + return -EALREADY; + } + } + + /* Find empty element in queue to store device info */ + for (i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { + if ((bt_mesh_gattc_info[i].conn.handle == 0xFFFF) && + (bt_mesh_gattc_info[i].service_uuid == 0x0000)) { + memcpy(bt_mesh_gattc_info[i].addr, addr->val, BLE_MESH_ADDR_LEN); + bt_mesh_gattc_info[i].addr_type = addr->type; + /* Service to be found after exhanging mtu size */ + bt_mesh_gattc_info[i].service_uuid = service_uuid; + break; + } + } + + if (i == ARRAY_SIZE(bt_mesh_gattc_info)) { + BT_WARN("%s, gattc info is full", __func__); + return -ENOMEM; + } + +#if BLE_MESH_DEV + if (bt_mesh_atomic_test_and_clear_bit(bt_mesh_dev.flags, BLE_MESH_DEV_SCANNING)) { + BLE_MESH_BTM_CHECK_STATUS(BTM_BleScan(false, 0, NULL, NULL, NULL)); + } +#else + BLE_MESH_BTM_CHECK_STATUS(BTM_BleScan(false, 0, NULL, NULL, NULL)); +#endif /* BLE_MESH_DEV */ + + BT_DBG("%s, create conn with %s", __func__, bt_hex(addr->val, BLE_MESH_ADDR_LEN)); + + /* Min_interval: 250ms + * Max_interval: 250ms + * Slave_latency: 0x0 + * Supervision_timeout: 32 sec + */ + BTA_DmSetBlePrefConnParams(bt_mesh_gattc_info[i].addr, 0xC8, 0xC8, 0x00, 0xC80); + + BTA_GATTC_Open(bt_mesh_gattc_if, bt_mesh_gattc_info[i].addr, + bt_mesh_gattc_info[i].addr_type, true, BTA_GATT_TRANSPORT_LE); + + /* Increment pbg_count */ + provisioner_pbg_count_inc(); + + return 0; +} + +void bt_mesh_gattc_exchange_mtu(u8_t index) +{ + /** Set local MTU and exchange with GATT server. + * ATT_MTU >= 69 for Mesh GATT Prov Service + * ATT_NTU >= 33 for Mesh GATT Proxy Service + */ + u16_t conn_id; + + conn_id = BLE_MESH_GATT_CREATE_CONN_ID(bt_mesh_gattc_if, bt_mesh_gattc_info[index].conn.handle); + + BTA_GATTC_ConfigureMTU(conn_id); +} + +u16_t bt_mesh_gattc_get_mtu_info(struct bt_mesh_conn *conn) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { + if (conn == &bt_mesh_gattc_info[i].conn) { + return bt_mesh_gattc_info[i].mtu; + } + } + + return 0; +} + +int bt_mesh_gattc_write_no_rsp(struct bt_mesh_conn *conn, const struct bt_mesh_gatt_attr *attr, + const void *data, u16_t len) +{ + u16_t conn_id; + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { + if (conn == &bt_mesh_gattc_info[i].conn) { + break; + } + } + + if (i == ARRAY_SIZE(bt_mesh_gattc_info)) { + BT_ERR("%s, Conn is not found", __func__); + /** Here we return 0 for prov_send() return value check in provisioner.c + */ + return 0; + } + + conn_id = BLE_MESH_GATT_CREATE_CONN_ID(bt_mesh_gattc_if, bt_mesh_gattc_info[i].conn.handle); + + BTA_GATTC_WriteCharValue(conn_id, bt_mesh_gattc_info[i].data_in_handle, + BTA_GATTC_TYPE_WRITE_NO_RSP, len, + (u8_t *)data, BTA_GATT_AUTH_REQ_NONE); + + return 0; +} + +void bt_mesh_gattc_disconnect(struct bt_mesh_conn *conn) +{ + /** Disconnect + * Clear proper proxy server information + * Clear proper prov_link information + * Clear proper bt_mesh_gattc_info information + * Here in adapter, we just clear proper bt_mesh_gattc_info, and + * when proxy_disconnected callback comes, the proxy server + * information and prov_link information should be cleared. + */ + u16_t conn_id; + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { + if (conn == &bt_mesh_gattc_info[i].conn) { + break; + } + } + + if (i == ARRAY_SIZE(bt_mesh_gattc_info)) { + BT_ERR("%s, Conn is not found", __func__); + return; + } + + conn_id = BLE_MESH_GATT_CREATE_CONN_ID(bt_mesh_gattc_if, bt_mesh_gattc_info[i].conn.handle); + + BTA_GATTC_Close(conn_id); +} + +/** Mesh Provisioning Service: 0x1827 + * Mesh Provisioning Data In: 0x2ADB + * Mesh Provisioning Data Out: 0x2ADC + * Mesh Proxy Service: 0x1828 + * Mesh Proxy Data In: 0x2ADD + * Mesh PROXY Data Out: 0x2ADE + */ +static void bt_mesh_bta_gattc_cb(tBTA_GATTC_EVT event, tBTA_GATTC *p_data) +{ + struct bt_mesh_conn *conn = NULL; + u16_t handle = 0; + ssize_t len = 0; + int i = 0; + + switch (event) { + case BTA_GATTC_REG_EVT: + if (p_data->reg_oper.status == BTA_GATT_OK) { + u8_t uuid[16] = { [0 ... 15] = BLE_MESH_GATTC_APP_UUID_BYTE }; + + BT_DBG("BTA_GATTC_REG_EVT"); + + if (p_data->reg_oper.app_uuid.len == LEN_UUID_128 && + !memcmp(p_data->reg_oper.app_uuid.uu.uuid128, uuid, 16)) { + bt_mesh_gattc_if = p_data->reg_oper.client_if; + BT_DBG("bt_mesh_gattc_if is %d", bt_mesh_gattc_if); + } + } + break; + case BTA_GATTC_CFG_MTU_EVT: { + if (p_data->cfg_mtu.status == BTA_GATT_OK) { + BT_DBG("BTA_GATTC_CFG_MTU_EVT, cfg_mtu is %d", p_data->cfg_mtu.mtu); + + handle = BLE_MESH_GATT_GET_CONN_ID(p_data->cfg_mtu.conn_id); + + for (i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { + if (bt_mesh_gattc_info[i].conn.handle == handle) { + bt_mesh_gattc_info[i].mtu = p_data->cfg_mtu.mtu; + break; + } + } + + /** Once mtu exchanged accomplished, start to find services, and here + * need a flag to indicate which service to find(Mesh Prov Service or + * Mesh Proxy Service) + */ + if (i != ARRAY_SIZE(bt_mesh_gattc_info)) { + tBT_UUID service_uuid; + u16_t conn_id; + + conn_id = BLE_MESH_GATT_CREATE_CONN_ID(bt_mesh_gattc_if, bt_mesh_gattc_info[i].conn.handle); + service_uuid.len = sizeof(bt_mesh_gattc_info[i].service_uuid); + service_uuid.uu.uuid16 = bt_mesh_gattc_info[i].service_uuid; + + /* Search Mesh Provisioning Service or Mesh Proxy Service */ + BTA_GATTC_ServiceSearchRequest(conn_id, &service_uuid); + } + } + break; + } + case BTA_GATTC_SEARCH_RES_EVT: { + BT_DBG("BTA_GATTC_SEARCH_RES_EVT"); + + handle = BLE_MESH_GATT_GET_CONN_ID(p_data->srvc_res.conn_id); + + for (i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { + if (bt_mesh_gattc_info[i].conn.handle == handle) { + break; + } + } + + if (i != ARRAY_SIZE(bt_mesh_gattc_info)) { + if (p_data->srvc_res.service_uuid.uuid.len == 2 && + p_data->srvc_res.service_uuid.uuid.uu.uuid16 == bt_mesh_gattc_info[i].service_uuid) { + bt_mesh_gattc_info[i].start_handle = p_data->srvc_res.start_handle; + bt_mesh_gattc_info[i].end_handle = p_data->srvc_res.end_handle; + } + } + break; + } + case BTA_GATTC_SEARCH_CMPL_EVT: { + if (p_data->search_cmpl.status == BTA_GATT_OK) { + BT_DBG("BTA_GATTC_SEARCH_CMPL_EVT"); + + handle = BLE_MESH_GATT_GET_CONN_ID(p_data->search_cmpl.conn_id); + + for (i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { + if (bt_mesh_gattc_info[i].conn.handle == handle) { + break; + } + } + + if (i == ARRAY_SIZE(bt_mesh_gattc_info)) { + BT_ERR("%s, Conn handle is not found", __func__); + return; + } + + conn = &bt_mesh_gattc_info[i].conn; + + if (bt_mesh_gattc_info[i].start_handle == 0x00 || + bt_mesh_gattc_info[i].end_handle == 0x00 || + (bt_mesh_gattc_info[i].start_handle > bt_mesh_gattc_info[i].end_handle)) { + bt_mesh_gattc_disconnect(conn); + return; + } + + int count = 0; + int num = 0; + u16_t conn_id; + tBT_UUID char_uuid; + btgatt_db_element_t *result = NULL; + tBTA_GATT_STATUS status; + u16_t notify_en = BLE_MESH_GATT_CCC_NOTIFY; + tBTA_GATT_UNFMT write; + + /* Get the characteristic num within Mesh Provisioning/Proxy Service */ + conn_id = BLE_MESH_GATT_CREATE_CONN_ID(bt_mesh_gattc_if, bt_mesh_gattc_info[i].conn.handle); + BTA_GATTC_GetDBSizeByType(conn_id, BTGATT_DB_CHARACTERISTIC, bt_mesh_gattc_info[i].start_handle, + bt_mesh_gattc_info[i].end_handle, BTA_GATTC_INVALID_HANDLE, &count); + if (count != 2) { + bt_mesh_gattc_disconnect(conn); + return; + } + + /* Get Mesh Provisioning/Proxy Data In/Out Characteristic */ + for (int j = 0; j != 2; j++) { + /** First: find Mesh Provisioning/Proxy Data In Characteristic + * Second: find Mesh Provisioning/Proxy Data Out Characteristic + */ + char_uuid.len = 2; + if (bt_mesh_gattc_info[i].service_uuid == BLE_MESH_UUID_MESH_PROV_VAL) { + char_uuid.uu.uuid16 = BLE_MESH_UUID_MESH_PROV_DATA_IN_VAL + j; + } else if (bt_mesh_gattc_info[i].service_uuid == BLE_MESH_UUID_MESH_PROXY_VAL) { + char_uuid.uu.uuid16 = BLE_MESH_UUID_MESH_PROXY_DATA_IN_VAL + j; + } + + BTA_GATTC_GetCharByUUID(conn_id, bt_mesh_gattc_info[i].start_handle, + bt_mesh_gattc_info[i].end_handle, char_uuid, &result, &num); + + if (!result) { + bt_mesh_gattc_disconnect(conn); + return; + } + + if (num != 1) { + osi_free(result); + bt_mesh_gattc_disconnect(conn); + return; + } + + if (!j) { + if (!(result[0].properties & BLE_MESH_GATT_CHRC_WRITE_WITHOUT_RESP)) { + osi_free(result); + bt_mesh_gattc_disconnect(conn); + return; + } + bt_mesh_gattc_info[i].data_in_handle = result[0].attribute_handle; + } else { + if (!(result[0].properties & BLE_MESH_GATT_CHRC_NOTIFY)) { + osi_free(result); + bt_mesh_gattc_disconnect(conn); + return; + } + bt_mesh_gattc_info[i].data_out_handle = result[0].attribute_handle; + } + osi_free(result); + result = NULL; + } + + /* Register Notification fot Mesh Provisioning/Proxy Data Out Characteristic */ + status = BTA_GATTC_RegisterForNotifications(bt_mesh_gattc_if, bt_mesh_gattc_info[i].addr, + bt_mesh_gattc_info[i].data_out_handle); + if (status != BTA_GATT_OK) { + bt_mesh_gattc_disconnect(conn); + return; + } + + /** After notification is registered, get descriptor number of the + * Mesh Provisioning/Proxy Data Out Characteristic + */ + BTA_GATTC_GetDBSizeByType(conn_id, BTGATT_DB_DESCRIPTOR, bt_mesh_gattc_info[i].start_handle, + bt_mesh_gattc_info[i].end_handle, bt_mesh_gattc_info[i].data_out_handle, &num); + if (!num) { + bt_mesh_gattc_disconnect(conn); + return; + } + + /* Get CCC of Mesh Provisioning/Proxy Data Out Characteristic */ + char_uuid.len = 2; + char_uuid.uu.uuid16 = BLE_MESH_UUID_GATT_CCC_VAL; + BTA_GATTC_GetDescrByCharHandle(conn_id, bt_mesh_gattc_info[i].data_out_handle, + char_uuid, &result, &num); + + if (!result) { + bt_mesh_gattc_disconnect(conn); + return; + } + + if (num != 1) { + osi_free(result); + bt_mesh_gattc_disconnect(conn); + return; + } + + bt_mesh_gattc_info[i].ccc_handle = result[0].attribute_handle; + + /** Enable Notification of Mesh Provisioning/Proxy Data Out + * Characteristic Descriptor. + */ + write.len = sizeof(notify_en); + write.p_value = (u8_t *)¬ify_en; + BTA_GATTC_WriteCharDescr(conn_id, result[0].attribute_handle, + BTA_GATTC_TYPE_WRITE, &write, BTA_GATT_AUTH_REQ_NONE); + + osi_free(result); + result = NULL; + } + break; + } + case BTA_GATTC_READ_DESCR_EVT: + break; + case BTA_GATTC_WRITE_DESCR_EVT: { + if (p_data->write.status == BTA_GATT_OK) { + BT_DBG("BTA_GATTC_WRITE_DESCR_EVT"); + + handle = BLE_MESH_GATT_GET_CONN_ID(p_data->write.conn_id); + + for (i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { + if (bt_mesh_gattc_info[i].conn.handle == handle) { + break; + } + } + + if (i == ARRAY_SIZE(bt_mesh_gattc_info)) { + BT_ERR("%s, Conn handle is not found", __func__); + return; + } + + conn = &bt_mesh_gattc_info[i].conn; + + if (bt_mesh_gattc_info[i].ccc_handle != p_data->write.handle) { + BT_WARN("%s, gattc ccc_handle is not matched", __func__); + bt_mesh_gattc_disconnect(conn); + return; + } + + if (bt_mesh_gattc_info[i].service_uuid == BLE_MESH_UUID_MESH_PROV_VAL) { + if (bt_mesh_gattc_conn_cb != NULL && bt_mesh_gattc_conn_cb->prov_write_descr != NULL) { + len = bt_mesh_gattc_conn_cb->prov_write_descr(&bt_mesh_gattc_info[i].conn, bt_mesh_gattc_info[i].addr); + if (len < 0) { + BT_ERR("%s, prov_write_descr failed", __func__); + bt_mesh_gattc_disconnect(conn); + return; + } + bt_mesh_gattc_info[i].wr_desc_done = true; + } + } else if (bt_mesh_gattc_info[i].service_uuid == BLE_MESH_UUID_MESH_PROXY_VAL) { + if (bt_mesh_gattc_conn_cb != NULL && bt_mesh_gattc_conn_cb->proxy_write_descr != NULL) { + len = bt_mesh_gattc_conn_cb->proxy_write_descr(&bt_mesh_gattc_info[i].conn); + if (len < 0) { + BT_ERR("%s, proxy_write_descr failed", __func__); + bt_mesh_gattc_disconnect(conn); + return; + } + } + } + } + break; + } + case BTA_GATTC_NOTIF_EVT: { + BT_DBG("BTA_GATTC_NOTIF_EVT"); + + handle = BLE_MESH_GATT_GET_CONN_ID(p_data->notify.conn_id); + + for (i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { + if (bt_mesh_gattc_info[i].conn.handle == handle) { + break; + } + } + + if (i == ARRAY_SIZE(bt_mesh_gattc_info)) { + BT_ERR("%s, Conn handle is not found", __func__); + return; + } + + conn = &bt_mesh_gattc_info[i].conn; + + if (memcmp(bt_mesh_gattc_info[i].addr, p_data->notify.bda, BLE_MESH_ADDR_LEN) || + bt_mesh_gattc_info[i].data_out_handle != p_data->notify.handle || + p_data->notify.is_notify == false) { + BT_ERR("%s, Notification error", __func__); + bt_mesh_gattc_disconnect(conn); + return; + } + + if (bt_mesh_gattc_info[i].service_uuid == BLE_MESH_UUID_MESH_PROV_VAL) { + if (bt_mesh_gattc_conn_cb != NULL && bt_mesh_gattc_conn_cb->prov_notify != NULL) { + len = bt_mesh_gattc_conn_cb->prov_notify(&bt_mesh_gattc_info[i].conn, + p_data->notify.value, p_data->notify.len); + if (len < 0) { + BT_ERR("%s, prov_notify failed", __func__); + bt_mesh_gattc_disconnect(conn); + return; + } + } + } else if (bt_mesh_gattc_info[i].service_uuid == BLE_MESH_UUID_MESH_PROXY_VAL) { + if (bt_mesh_gattc_conn_cb != NULL && bt_mesh_gattc_conn_cb->proxy_notify != NULL) { + len = bt_mesh_gattc_conn_cb->proxy_notify(&bt_mesh_gattc_info[i].conn, + p_data->notify.value, p_data->notify.len); + if (len < 0) { + BT_ERR("%s, proxy_notify failed", __func__); + bt_mesh_gattc_disconnect(conn); + return; + } + } + } + break; + } + case BTA_GATTC_READ_CHAR_EVT: + break; + case BTA_GATTC_WRITE_CHAR_EVT: + break; + case BTA_GATTC_PREP_WRITE_EVT: + break; + case BTA_GATTC_EXEC_EVT: + break; + case BTA_GATTC_OPEN_EVT: { + BT_DBG("BTA_GATTC_OPEN_EVT"); + /** After current connection is established, provisioner can + * use BTA_DmBleScan() to re-enable scan. + */ + tBTM_STATUS status; +#if BLE_MESH_DEV + if (!bt_mesh_atomic_test_bit(bt_mesh_dev.flags, BLE_MESH_DEV_SCANNING)) { + status = BTM_BleScan(true, 0, bt_mesh_scan_results_cb, NULL, NULL); + if (status != BTM_SUCCESS && status != BTM_CMD_STARTED) { + BT_ERR("%s, Invalid status %d", __func__, status); + break; + } + bt_mesh_atomic_set_bit(bt_mesh_dev.flags, BLE_MESH_DEV_SCANNING); + } +#else + status = BTM_BleScan(true, 0, bt_mesh_scan_results_cb, NULL, NULL); + if (status != BTM_SUCCESS && status != BTM_CMD_STARTED) { + BT_ERR("%s, Invalid status %d", __func__, status); + break; + } +#endif /* BLE_MESH_DEV */ + break; + } + case BTA_GATTC_CLOSE_EVT: + BT_DBG("BTA_GATTC_CLOSE_EVT"); + break; + case BTA_GATTC_CONNECT_EVT: { + BT_DBG("BTA_GATTC_CONNECT_EVT"); + + if (bt_mesh_gattc_if != p_data->connect.client_if) { + BT_ERR("%s, gattc_if & connect_if don't match", __func__); + return; + } + + if (bt_mesh_gattc_conn_cb != NULL && bt_mesh_gattc_conn_cb->connected != NULL) { + for (i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { + if (!memcmp(bt_mesh_gattc_info[i].addr, p_data->connect.remote_bda, BLE_MESH_ADDR_LEN)) { + bt_mesh_gattc_info[i].conn.handle = BLE_MESH_GATT_GET_CONN_ID(p_data->connect.conn_id); + (bt_mesh_gattc_conn_cb->connected)(bt_mesh_gattc_info[i].addr, &bt_mesh_gattc_info[i].conn, i); + break; + } + } + } + break; + } + case BTA_GATTC_DISCONNECT_EVT: { + BT_DBG("BTA_GATTC_DISCONNECT_EVT"); + + if (bt_mesh_gattc_if != p_data->disconnect.client_if) { + BT_ERR("%s, gattc_if & disconnect_if don't match", __func__); + return; + } + + handle = BLE_MESH_GATT_GET_CONN_ID(p_data->disconnect.conn_id); + + if (bt_mesh_gattc_conn_cb != NULL && bt_mesh_gattc_conn_cb->disconnected != NULL) { + for (i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { + if (!memcmp(bt_mesh_gattc_info[i].addr, p_data->disconnect.remote_bda, BLE_MESH_ADDR_LEN)) { + if (bt_mesh_gattc_info[i].conn.handle == handle) { + (bt_mesh_gattc_conn_cb->disconnected)(&bt_mesh_gattc_info[i].conn, p_data->disconnect.reason); + if (!bt_mesh_gattc_info[i].wr_desc_done) { + /* Add this in case connection is established, connected event comes, but + * connection is terminated before server->filter_type is set to PROV. + */ + provisioner_clear_link_conn_info(bt_mesh_gattc_info[i].addr); + } + } else { + /* Add this in case connection is failed to be established, and here we + * need to clear some provision link info, like connecting flag, device + * uuid, address info, etc. + */ + provisioner_clear_link_conn_info(bt_mesh_gattc_info[i].addr); + } + /* Decrease prov pbg_count */ + provisioner_pbg_count_dec(); + /* Reset corresponding gattc info */ + memset(&bt_mesh_gattc_info[i], 0, sizeof(bt_mesh_gattc_info[i])); + bt_mesh_gattc_info[i].conn.handle = 0xFFFF; + bt_mesh_gattc_info[i].mtu = GATT_DEF_BLE_MTU_SIZE; + bt_mesh_gattc_info[i].wr_desc_done = false; + break; + } + } + } + break; + } + case BTA_GATTC_CONGEST_EVT: + break; + case BTA_GATTC_SRVC_CHG_EVT: + break; + default: + break; + } +} +#endif /* defined(CONFIG_BLE_MESH_PROVISIONER) && CONFIG_BLE_MESH_PROVISIONER */ + +struct bt_mesh_conn *bt_mesh_conn_ref(struct bt_mesh_conn *conn) +{ + bt_mesh_atomic_inc(&conn->ref); + + BT_DBG("handle %u ref %u", conn->handle, bt_mesh_atomic_get(&conn->ref)); + + return conn; +} + +void bt_mesh_conn_unref(struct bt_mesh_conn *conn) +{ + bt_mesh_atomic_dec(&conn->ref); + + BT_DBG("handle %u ref %u", conn->handle, bt_mesh_atomic_get(&conn->ref)); +} + +void bt_mesh_gatt_init(void) +{ + tBT_UUID app_uuid = {LEN_UUID_128, {0}}; + + BTA_GATT_SetLocalMTU(GATT_DEF_BLE_MTU_SIZE); + +#if CONFIG_BLE_MESH_NODE + /* Fill our internal UUID with a fixed pattern 0x96 for the ble mesh */ + memset(&app_uuid.uu.uuid128, 0x96, LEN_UUID_128); + BTA_GATTS_AppRegister(&app_uuid, bt_mesh_bta_gatts_cb); +#endif + +#if CONFIG_BLE_MESH_PROVISIONER + for (int i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { + bt_mesh_gattc_info[i].conn.handle = 0xFFFF; + bt_mesh_gattc_info[i].mtu = GATT_DEF_BLE_MTU_SIZE; /* Default MTU_SIZE 23 */ + bt_mesh_gattc_info[i].wr_desc_done = false; + } + memset(&app_uuid.uu.uuid128, BLE_MESH_GATTC_APP_UUID_BYTE, LEN_UUID_128); + BTA_GATTC_AppRegister(&app_uuid, bt_mesh_bta_gattc_cb); +#endif +} + +void bt_mesh_adapt_init(void) +{ + BT_DBG("%s", __func__); + /* initialization of P-256 parameters */ + p_256_init_curve(KEY_LENGTH_DWORDS_P256); +} + +int bt_mesh_rand(void *buf, size_t len) +{ + int i; + + if (buf == NULL || len == 0) { + BT_ERR("%s, Invalid parameter", __func__); + return -EAGAIN; + } + + for (i = 0; i < (int)(len / sizeof(u32_t)); i++) { + u32_t rand = esp_random(); + memcpy(buf + i * sizeof(u32_t), &rand, sizeof(u32_t)); + } + + BT_DBG("%s, rand: %s", __func__, bt_hex(buf, len)); + return 0; +} + +void bt_mesh_set_private_key(const u8_t pri_key[32]) +{ + memcpy(bt_mesh_private_key, pri_key, 32); +} + +const u8_t *bt_mesh_pub_key_get(void) +{ + Point public_key; + BT_OCTET32 pri_key; +#if 1 + if (bt_mesh_atomic_test_bit(bt_mesh_dev.flags, BLE_MESH_DEV_HAS_PUB_KEY)) { + return bt_mesh_public_key; + } +#else + /* BLE Mesh BQB test case MESH/NODE/PROV/UPD/BV-12-C requires + * different public key for each provisioning procedure. + * Note: if enabled, when Provisioner provision multiple devices + * at the same time, this may cause invalid confirmation value. + */ + if (bt_mesh_rand(bt_mesh_private_key, 32)) { + BT_ERR("%s, Unable to generate bt_mesh_private_key", __func__); + return NULL; + } +#endif + mem_rcopy(pri_key, bt_mesh_private_key, 32); + ECC_PointMult(&public_key, &(curve_p256.G), (DWORD *)pri_key, KEY_LENGTH_DWORDS_P256); + + memcpy(bt_mesh_public_key, public_key.x, BT_OCTET32_LEN); + memcpy(bt_mesh_public_key + BT_OCTET32_LEN, public_key.y, BT_OCTET32_LEN); + + bt_mesh_atomic_set_bit(bt_mesh_dev.flags, BLE_MESH_DEV_HAS_PUB_KEY); + BT_DBG("gen the bt_mesh_public_key:%s", bt_hex(bt_mesh_public_key, sizeof(bt_mesh_public_key))); + + return bt_mesh_public_key; +} + +bool bt_mesh_check_public_key(const u8_t key[64]) +{ + struct p256_pub_key { + u8_t x[32]; + u8_t y[32]; + } check = {0}; + + sys_memcpy_swap(check.x, key, 32); + sys_memcpy_swap(check.y, key + 32, 32); + + return ECC_CheckPointIsInElliCur_P256((Point *)&check); +} + +int bt_mesh_dh_key_gen(const u8_t remote_pk[64], bt_mesh_dh_key_cb_t cb, const u8_t idx) +{ + BT_OCTET32 private_key; + Point peer_publ_key; + Point new_publ_key; + BT_OCTET32 dhkey; + + BT_DBG("private key = %s", bt_hex(bt_mesh_private_key, BT_OCTET32_LEN)); + + mem_rcopy(private_key, bt_mesh_private_key, BT_OCTET32_LEN); + memcpy(peer_publ_key.x, remote_pk, BT_OCTET32_LEN); + memcpy(peer_publ_key.y, &remote_pk[BT_OCTET32_LEN], BT_OCTET32_LEN); + + BT_DBG("remote public key x = %s", bt_hex(peer_publ_key.x, BT_OCTET32_LEN)); + BT_DBG("remote public key y = %s", bt_hex(peer_publ_key.y, BT_OCTET32_LEN)); + + ECC_PointMult(&new_publ_key, &peer_publ_key, (DWORD *) private_key, KEY_LENGTH_DWORDS_P256); + + memcpy(dhkey, new_publ_key.x, BT_OCTET32_LEN); + + BT_DBG("new public key x = %s", bt_hex(new_publ_key.x, 32)); + BT_DBG("new public key y = %s", bt_hex(new_publ_key.y, 32)); + + if (cb != NULL) { + cb((const u8_t *)dhkey, idx); + } + + return 0; +} + +#if CONFIG_MBEDTLS_HARDWARE_AES +static void ecb_encrypt(u8_t const *const key_le, u8_t const *const clear_text_le, + u8_t *const cipher_text_le, u8_t *const cipher_text_be) +{ + struct bt_mesh_ecb_param ecb; + mbedtls_aes_context aes_ctx = {0}; + + aes_ctx.key_bytes = 16; + mem_rcopy(&aes_ctx.key[0], key_le, 16); + mem_rcopy(&ecb.clear_text[0], clear_text_le, sizeof(ecb.clear_text)); + mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, &ecb.clear_text[0], &ecb.cipher_text[0]); + + if (cipher_text_le) { + mem_rcopy(cipher_text_le, &ecb.cipher_text[0], + sizeof(ecb.cipher_text)); + } + + if (cipher_text_be) { + memcpy(cipher_text_be, &ecb.cipher_text[0], + sizeof(ecb.cipher_text)); + } +} + +static void ecb_encrypt_be(u8_t const *const key_be, u8_t const *const clear_text_be, + u8_t *const cipher_text_be) +{ + struct bt_mesh_ecb_param ecb; + mbedtls_aes_context aes_ctx = {0}; + + aes_ctx.key_bytes = 16; + memcpy(&aes_ctx.key[0], key_be, 16); + memcpy(&ecb.clear_text[0], clear_text_be, sizeof(ecb.clear_text)); + mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, &ecb.clear_text[0], &ecb.cipher_text[0]); + + memcpy(cipher_text_be, &ecb.cipher_text[0], sizeof(ecb.cipher_text)); +} +#endif /* CONFIG_MBEDTLS_HARDWARE_AES */ + +int bt_mesh_encrypt_le(const u8_t key[16], const u8_t plaintext[16], + u8_t enc_data[16]) +{ +#if CONFIG_MBEDTLS_HARDWARE_AES + BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); + + ecb_encrypt(key, plaintext, enc_data, NULL); + + BT_DBG("enc_data %s", bt_hex(enc_data, 16)); + return 0; +#else /* CONFIG_MBEDTLS_HARDWARE_AES */ + struct tc_aes_key_sched_struct s; + u8_t tmp[16]; + + BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); + + sys_memcpy_swap(tmp, key, 16); + + if (tc_aes128_set_encrypt_key(&s, tmp) == TC_CRYPTO_FAIL) { + return -EINVAL; + } + + sys_memcpy_swap(tmp, plaintext, 16); + + if (tc_aes_encrypt(enc_data, tmp, &s) == TC_CRYPTO_FAIL) { + return -EINVAL; + } + + sys_mem_swap(enc_data, 16); + + BT_DBG("enc_data %s", bt_hex(enc_data, 16)); + + return 0; +#endif /* CONFIG_MBEDTLS_HARDWARE_AES */ +} + +int bt_mesh_encrypt_be(const u8_t key[16], const u8_t plaintext[16], + u8_t enc_data[16]) +{ +#if CONFIG_MBEDTLS_HARDWARE_AES + BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); + + ecb_encrypt_be(key, plaintext, enc_data); + + BT_DBG("enc_data %s", bt_hex(enc_data, 16)); + + return 0; +#else /* CONFIG_MBEDTLS_HARDWARE_AES */ + struct tc_aes_key_sched_struct s; + + BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); + + if (tc_aes128_set_encrypt_key(&s, key) == TC_CRYPTO_FAIL) { + return -EINVAL; + } + + if (tc_aes_encrypt(enc_data, plaintext, &s) == TC_CRYPTO_FAIL) { + return -EINVAL; + } + + BT_DBG("enc_data %s", bt_hex(enc_data, 16)); + + return 0; +#endif /* CONFIG_MBEDTLS_HARDWARE_AES */ +} + +#if defined(CONFIG_BLE_MESH_USE_DUPLICATE_SCAN) +int bt_mesh_update_exceptional_list(u8_t sub_code, u8_t type, void *info) +{ + BD_ADDR value = {0}; + + if ((sub_code > BLE_MESH_EXCEP_LIST_CLEAN) || + (type > BLE_MESH_EXCEP_INFO_MESH_PROXY_ADV)) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + if (type == BLE_MESH_EXCEP_INFO_MESH_LINK_ID) { + if (!info) { + BT_ERR("%s, NULL Provisioning Link ID", __func__); + return -EINVAL; + } + memcpy(value, info, sizeof(u32_t)); + } + + BT_DBG("%s, %s type 0x%x", __func__, sub_code ? "Remove" : "Add", type); + + /* The parameter "device_info" can't be NULL in the API */ + BLE_MESH_BTM_CHECK_STATUS(BTM_UpdateBleDuplicateExceptionalList(sub_code, type, value, NULL)); + + return 0; +} +#endif diff --git a/components/bt/ble_mesh/mesh_core/mesh_buf.c b/components/bt/ble_mesh/mesh_core/mesh_buf.c new file mode 100644 index 0000000000..d6e0cd710e --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/mesh_buf.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2015 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "sdkconfig.h" + +#include "mesh_buf.h" +#include "mesh_trace.h" + +int net_buf_id(struct net_buf *buf) +{ + struct net_buf_pool *pool = buf->pool; + + return buf - pool->__bufs; +} + +static inline struct net_buf *pool_get_uninit(struct net_buf_pool *pool, + u16_t uninit_count) +{ + struct net_buf *buf; + + buf = &pool->__bufs[pool->buf_count - uninit_count]; + + buf->pool = pool; + + return buf; +} + +void *net_buf_simple_add(struct net_buf_simple *buf, size_t len) +{ + u8_t *tail = net_buf_simple_tail(buf); + + NET_BUF_SIMPLE_DBG("buf %p len %u", buf, len); + + NET_BUF_SIMPLE_ASSERT(net_buf_simple_tailroom(buf) >= len); + + buf->len += len; + return tail; +} + +void *net_buf_simple_add_mem(struct net_buf_simple *buf, const void *mem, + size_t len) +{ + NET_BUF_SIMPLE_DBG("buf %p len %u", buf, len); + + return memcpy(net_buf_simple_add(buf, len), mem, len); +} + +u8_t *net_buf_simple_add_u8(struct net_buf_simple *buf, u8_t val) +{ + u8_t *u8; + + NET_BUF_SIMPLE_DBG("buf %p val 0x%02x", buf, val); + + u8 = net_buf_simple_add(buf, 1); + *u8 = val; + + return u8; +} + +void net_buf_simple_add_le16(struct net_buf_simple *buf, u16_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %u", buf, val); + + val = sys_cpu_to_le16(val); + memcpy(net_buf_simple_add(buf, sizeof(val)), &val, sizeof(val)); +} + +void net_buf_simple_add_be16(struct net_buf_simple *buf, u16_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %u", buf, val); + + val = sys_cpu_to_be16(val); + memcpy(net_buf_simple_add(buf, sizeof(val)), &val, sizeof(val)); +} + +void net_buf_simple_add_le32(struct net_buf_simple *buf, u32_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %u", buf, val); + + val = sys_cpu_to_le32(val); + memcpy(net_buf_simple_add(buf, sizeof(val)), &val, sizeof(val)); +} + +void net_buf_simple_add_be32(struct net_buf_simple *buf, u32_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %u", buf, val); + + val = sys_cpu_to_be32(val); + memcpy(net_buf_simple_add(buf, sizeof(val)), &val, sizeof(val)); +} + +void *net_buf_simple_push(struct net_buf_simple *buf, size_t len) +{ + NET_BUF_SIMPLE_DBG("buf %p len %u", buf, len); + + NET_BUF_SIMPLE_ASSERT(net_buf_simple_headroom(buf) >= len); + + buf->data -= len; + buf->len += len; + return buf->data; +} + +void net_buf_simple_push_le16(struct net_buf_simple *buf, u16_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %u", buf, val); + + val = sys_cpu_to_le16(val); + memcpy(net_buf_simple_push(buf, sizeof(val)), &val, sizeof(val)); +} + +void net_buf_simple_push_be16(struct net_buf_simple *buf, u16_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %u", buf, val); + + val = sys_cpu_to_be16(val); + memcpy(net_buf_simple_push(buf, sizeof(val)), &val, sizeof(val)); +} + +void net_buf_simple_push_u8(struct net_buf_simple *buf, u8_t val) +{ + u8_t *data = net_buf_simple_push(buf, 1); + + *data = val; +} + +void *net_buf_simple_pull(struct net_buf_simple *buf, size_t len) +{ + NET_BUF_SIMPLE_DBG("buf %p len %u", buf, len); + + NET_BUF_SIMPLE_ASSERT(buf->len >= len); + + buf->len -= len; + return buf->data += len; +} + +void *net_buf_simple_pull_mem(struct net_buf_simple *buf, size_t len) +{ + void *data = buf->data; + + NET_BUF_SIMPLE_DBG("buf %p len %zu", buf, len); + + NET_BUF_SIMPLE_ASSERT(buf->len >= len); + + buf->len -= len; + buf->data += len; + + return data; +} + +u8_t net_buf_simple_pull_u8(struct net_buf_simple *buf) +{ + u8_t val; + + val = buf->data[0]; + net_buf_simple_pull(buf, 1); + + return val; +} + +u16_t net_buf_simple_pull_le16(struct net_buf_simple *buf) +{ + u16_t val; + + val = UNALIGNED_GET((u16_t *)buf->data); + net_buf_simple_pull(buf, sizeof(val)); + + return sys_le16_to_cpu(val); +} + +u16_t net_buf_simple_pull_be16(struct net_buf_simple *buf) +{ + u16_t val; + + val = UNALIGNED_GET((u16_t *)buf->data); + net_buf_simple_pull(buf, sizeof(val)); + + return sys_be16_to_cpu(val); +} + +u32_t net_buf_simple_pull_le32(struct net_buf_simple *buf) +{ + u32_t val; + + val = UNALIGNED_GET((u32_t *)buf->data); + net_buf_simple_pull(buf, sizeof(val)); + + return sys_le32_to_cpu(val); +} + +u32_t net_buf_simple_pull_be32(struct net_buf_simple *buf) +{ + u32_t val; + + val = UNALIGNED_GET((u32_t *)buf->data); + net_buf_simple_pull(buf, sizeof(val)); + + return sys_be32_to_cpu(val); +} + +size_t net_buf_simple_headroom(struct net_buf_simple *buf) +{ + return buf->data - buf->__buf; +} + +size_t net_buf_simple_tailroom(struct net_buf_simple *buf) +{ + return buf->size - net_buf_simple_headroom(buf) - buf->len; +} + +void net_buf_reset(struct net_buf *buf) +{ + NET_BUF_ASSERT(buf->flags == 0); + NET_BUF_ASSERT(buf->frags == NULL); + + net_buf_simple_reset(&buf->b); +} + +void net_buf_simple_reserve(struct net_buf_simple *buf, size_t reserve) +{ + NET_BUF_ASSERT(buf); + NET_BUF_ASSERT(buf->len == 0U); + NET_BUF_DBG("buf %p reserve %zu", buf, reserve); + + buf->data = buf->__buf + reserve; +} + +void net_buf_slist_put(sys_slist_t *list, struct net_buf *buf) +{ + struct net_buf *tail; + unsigned int key; + + NET_BUF_ASSERT(list); + NET_BUF_ASSERT(buf); + + for (tail = buf; tail->frags; tail = tail->frags) { + tail->flags |= NET_BUF_FRAGS; + } + + key = bt_mesh_irq_lock(); + sys_slist_append_list(list, &buf->node, &tail->node); + bt_mesh_irq_unlock(key); +} + +struct net_buf *net_buf_slist_get(sys_slist_t *list) +{ + struct net_buf *buf, *frag; + unsigned int key; + + NET_BUF_ASSERT(list); + + key = bt_mesh_irq_lock(); + buf = (void *)sys_slist_get(list); + bt_mesh_irq_unlock(key); + + if (!buf) { + return NULL; + } + + /* Get any fragments belonging to this buffer */ + for (frag = buf; (frag->flags & NET_BUF_FRAGS); frag = frag->frags) { + key = bt_mesh_irq_lock(); + frag->frags = (void *)sys_slist_get(list); + bt_mesh_irq_unlock(key); + + NET_BUF_ASSERT(frag->frags); + + /* The fragments flag is only for list-internal usage */ + frag->flags &= ~NET_BUF_FRAGS; + } + + /* Mark the end of the fragment list */ + frag->frags = NULL; + + return buf; +} + +struct net_buf *net_buf_ref(struct net_buf *buf) +{ + NET_BUF_ASSERT(buf); + + NET_BUF_DBG("buf %p (old) ref %u pool %p", buf, buf->ref, buf->pool); + + buf->ref++; + return buf; +} + +#if defined(CONFIG_BLE_MESH_NET_BUF_LOG) +void net_buf_unref_debug(struct net_buf *buf, const char *func, int line) +#else +void net_buf_unref(struct net_buf *buf) +#endif +{ + NET_BUF_ASSERT(buf); + + while (buf) { + struct net_buf *frags = buf->frags; + struct net_buf_pool *pool; + +#if defined(CONFIG_BLE_MESH_NET_BUF_LOG) + if (!buf->ref) { + NET_BUF_ERR("%s():%d: buf %p double free", func, line, + buf); + return; + } +#endif + NET_BUF_DBG("buf %p ref %u pool %p frags %p", buf, buf->ref, + buf->pool, buf->frags); + + /* Changed by Espressif. Add !buf->ref to avoid minus 0 */ + if (!buf->ref || --buf->ref > 0) { + return; + } + + buf->frags = NULL; + + pool = buf->pool; + + pool->uninit_count++; +#if defined(CONFIG_BLE_MESH_NET_BUF_POOL_USAGE) + pool->avail_count++; + NET_BUF_DBG("%s, pool %p, avail_count %d, uninit_count %d", __func__, + pool, pool->avail_count, pool->uninit_count); + NET_BUF_ASSERT(pool->avail_count <= pool->buf_count); +#endif + + if (pool->destroy) { + pool->destroy(buf); + } + + buf = frags; + } +} + +static u8_t *fixed_data_alloc(struct net_buf *buf, size_t *size, s32_t timeout) +{ + struct net_buf_pool *pool = buf->pool; + const struct net_buf_pool_fixed *fixed = pool->alloc->alloc_data; + + *size = MIN(fixed->data_size, *size); + + return fixed->data_pool + fixed->data_size * net_buf_id(buf); +} + +static void fixed_data_unref(struct net_buf *buf, u8_t *data) +{ + /* Nothing needed for fixed-size data pools */ +} + +const struct net_buf_data_cb net_buf_fixed_cb = { + .alloc = fixed_data_alloc, + .unref = fixed_data_unref, +}; + +static u8_t *data_alloc(struct net_buf *buf, size_t *size, s32_t timeout) +{ + struct net_buf_pool *pool = buf->pool; + + return pool->alloc->cb->alloc(buf, size, timeout); +} + +#if defined(CONFIG_BLE_MESH_NET_BUF_LOG) +struct net_buf *net_buf_alloc_len_debug(struct net_buf_pool *pool, size_t size, + s32_t timeout, const char *func, int line) +#else +struct net_buf *net_buf_alloc_len(struct net_buf_pool *pool, size_t size, + s32_t timeout) +#endif +{ + struct net_buf *buf = NULL; + unsigned int key; + int i; + + NET_BUF_ASSERT(pool); + + NET_BUF_DBG("%s, pool %p, uninit_count %d, buf_count %d", __func__, + pool, pool->uninit_count, pool->buf_count); + + /* We need to lock interrupts temporarily to prevent race conditions + * when accessing pool->uninit_count. + */ + key = bt_mesh_irq_lock(); + + /* If there are uninitialized buffers we're guaranteed to succeed + * with the allocation one way or another. + */ + if (pool->uninit_count) { + /* Changed by Espressif. Use buf when buf->ref is 0 */ + for (i = pool->buf_count; i > 0; i--) { + buf = pool_get_uninit(pool, i); + if (!buf->ref) { + bt_mesh_irq_unlock(key); + goto success; + } + } + } + + bt_mesh_irq_unlock(key); + + NET_BUF_ERR("%s, Failed to get free buffer", __func__); + return NULL; + +success: + NET_BUF_DBG("allocated buf %p", buf); + + if (size) { + buf->__buf = data_alloc(buf, &size, timeout); + if (!buf->__buf) { + NET_BUF_ERR("%s, Failed to allocate data", __func__); + return NULL; + } + } else { + NET_BUF_WARN("%s, Zero data size", __func__); + buf->__buf = NULL; + } + + buf->ref = 1; + buf->flags = 0; + buf->frags = NULL; + buf->size = size; + net_buf_reset(buf); + + pool->uninit_count--; +#if defined(CONFIG_BLE_MESH_NET_BUF_POOL_USAGE) + pool->avail_count--; + NET_BUF_ASSERT(pool->avail_count >= 0); +#endif + + return buf; +} + +#if defined(CONFIG_BLE_MESH_NET_BUF_LOG) +struct net_buf *net_buf_alloc_fixed_debug(struct net_buf_pool *pool, + s32_t timeout, const char *func, + int line) +{ + const struct net_buf_pool_fixed *fixed = pool->alloc->alloc_data; + + return net_buf_alloc_len_debug(pool, fixed->data_size, timeout, func, line); +} +#else +struct net_buf *net_buf_alloc_fixed(struct net_buf_pool *pool, s32_t timeout) +{ + const struct net_buf_pool_fixed *fixed = pool->alloc->alloc_data; + + return net_buf_alloc_len(pool, fixed->data_size, timeout); +} +#endif \ No newline at end of file diff --git a/components/bt/ble_mesh/mesh_core/mesh_hci.c b/components/bt/ble_mesh/mesh_core/mesh_hci.c new file mode 100644 index 0000000000..72da73a389 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/mesh_hci.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2015-2016 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sdkconfig.h" + +#include "stack/bt_types.h" +#include "device/controller.h" + +#include "mesh_hci.h" + +struct bt_mesh_dev bt_mesh_dev; + +void bt_mesh_hci_init(void) +{ + const uint8_t *features = controller_get_interface()->get_features_ble()->as_array; + if (features != NULL) { + memcpy(bt_mesh_dev.features[0], features, 8); + memcpy(bt_mesh_dev.le.features, features, 8); + } + + /** + * Currently 20ms non-connectable adv interval is supported, and we need to add + * a flag to indicate this support. + */ +#ifdef CONFIG_BLE_MESH_HCI_5_0 + bt_mesh_dev.hci_version = BLE_MESH_HCI_VERSION_5_0; +#else + bt_mesh_dev.hci_version = controller_get_interface()->get_bt_version()->hci_version; +#endif + bt_mesh_dev.lmp_version = controller_get_interface()->get_bt_version()->lmp_version; + bt_mesh_dev.hci_revision = controller_get_interface()->get_bt_version()->hci_revision; + bt_mesh_dev.lmp_subversion = controller_get_interface()->get_bt_version()->lmp_subversion; + bt_mesh_dev.manufacturer = controller_get_interface()->get_bt_version()->manufacturer; + + const uint8_t *p = controller_get_interface()->get_ble_supported_states(); + uint64_t states_fh = 0, states_sh = 0; + STREAM_TO_UINT32(states_fh, p); + STREAM_TO_UINT32(states_sh, p); + bt_mesh_dev.le.states = (states_sh << 32) | states_fh; +} diff --git a/components/bt/ble_mesh/mesh_core/mesh_kernel.c b/components/bt/ble_mesh/mesh_core/mesh_kernel.c new file mode 100644 index 0000000000..d1d1ca6670 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/mesh_kernel.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2016 Wind River Systems, Inc. + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "sdkconfig.h" + +#include "osi/hash_map.h" +#include "osi/alarm.h" +#include "osi/hash_functions.h" + +#include "common/bt_trace.h" +#include "common/bt_defs.h" + +#include "esp_timer.h" + +#include "mesh_kernel.h" +#include "mesh_trace.h" + +#include "provisioner_prov.h" + +static osi_mutex_t bm_alarm_lock; +static osi_mutex_t bm_irq_lock; +static hash_map_t *bm_alarm_hash_map; +static const size_t BLE_MESH_GENERAL_ALARM_HASH_MAP_SIZE = 20 + CONFIG_BLE_MESH_PBA_SAME_TIME + \ + CONFIG_BLE_MESH_PBG_SAME_TIME; + +typedef struct alarm_t { + /* timer id point to here */ + esp_timer_handle_t alarm_hdl; + osi_alarm_callback_t cb; + void *cb_data; + int64_t deadline_us; +} osi_alarm_t; + +static void bt_mesh_alarm_cb(void *data) +{ + assert(data != NULL); + struct k_delayed_work *work = (struct k_delayed_work *)data; + work->work.handler(&work->work); + return; +} + +unsigned int bt_mesh_irq_lock(void) +{ +#if defined(CONFIG_BLE_MESH_IRQ_LOCK) && CONFIG_BLE_MESH_IRQ_LOCK + unsigned int key = XTOS_SET_INTLEVEL(XCHAL_EXCM_LEVEL); + return key; +#else + /* Change by Espressif. In BLE Mesh, in order to improve the real-time + * requirements of bt controller, we use task lock to replace IRQ lock. + */ + osi_mutex_lock(&bm_irq_lock, OSI_MUTEX_MAX_TIMEOUT); + return 0; +#endif +} + +void bt_mesh_irq_unlock(unsigned int key) +{ +#if defined(CONFIG_BLE_MESH_IRQ_LOCK) && CONFIG_BLE_MESH_IRQ_LOCK + XTOS_RESTORE_INTLEVEL(key); +#else + osi_mutex_unlock(&bm_irq_lock); +#endif +} + +s64_t k_uptime_get(void) +{ + /** k_uptime_get_32 is in in milliseconds, + * but esp_timer_get_time is in microseconds + */ + return (esp_timer_get_time() / 1000); +} + +u32_t k_uptime_get_32(void) +{ + /** k_uptime_get_32 is in in milliseconds, + * but esp_timer_get_time is in microseconds + */ + return (u32_t)(esp_timer_get_time() / 1000); +} + +void k_sleep(s32_t duration) +{ + vTaskDelay(duration / portTICK_PERIOD_MS); + return; +} + +void bt_mesh_k_init(void) +{ + osi_mutex_new(&bm_alarm_lock); + osi_mutex_new(&bm_irq_lock); + bm_alarm_hash_map = hash_map_new(BLE_MESH_GENERAL_ALARM_HASH_MAP_SIZE, + hash_function_pointer, NULL, + (data_free_fn)osi_alarm_free, NULL); + assert(bm_alarm_hash_map != NULL); +} + +void k_delayed_work_init(struct k_delayed_work *work, k_work_handler_t handler) +{ + osi_alarm_t *alarm = NULL; + + assert(work != NULL && bm_alarm_hash_map != NULL); + + k_work_init(&work->work, handler); + + osi_mutex_lock(&bm_alarm_lock, OSI_MUTEX_MAX_TIMEOUT); + if (!hash_map_has_key(bm_alarm_hash_map, (void *)work)) { + alarm = osi_alarm_new("bt_mesh", bt_mesh_alarm_cb, (void *)work, 0); + if (alarm == NULL) { + BT_ERR("%s, Unable to create alarm", __func__); + return; + } + if (!hash_map_set(bm_alarm_hash_map, work, (void *)alarm)) { + BT_ERR("%s Unable to add the timer to hash map.", __func__); + } + } + osi_mutex_unlock(&bm_alarm_lock); + + alarm = hash_map_get(bm_alarm_hash_map, work); + if (alarm == NULL) { + BT_WARN("%s, Unable to find expected alarm in hash map", __func__); + return; + } + + // Just init the work timer only, don't start it. + osi_alarm_cancel(alarm); + return; +} + +int k_delayed_work_submit(struct k_delayed_work *work, + s32_t delay) +{ + assert(work != NULL && bm_alarm_hash_map != NULL); + + osi_alarm_t *alarm = hash_map_get(bm_alarm_hash_map, (void *)work); + if (alarm == NULL) { + BT_WARN("%s, Unable to find expected alarm in hash map", __func__); + return -EINVAL; + } + + // Cancel the alarm first, before start the alarm. + osi_alarm_cancel(alarm); + osi_alarm_set(alarm, delay); + return 0; +} + +int k_delayed_work_cancel(struct k_delayed_work *work) +{ + assert(work != NULL && bm_alarm_hash_map != NULL); + + osi_alarm_t *alarm = hash_map_get(bm_alarm_hash_map, (void *)work); + if (alarm == NULL) { + BT_WARN("%s, Unable to find expected alarm in hash map", __func__); + return -EINVAL; + } + + osi_alarm_cancel(alarm); + alarm->deadline_us = 0; + return 0; +} + +int k_delayed_work_free(struct k_delayed_work *work) +{ + assert(work != NULL && bm_alarm_hash_map != NULL); + + osi_alarm_t *alarm = hash_map_get(bm_alarm_hash_map, work); + if (alarm == NULL) { + BT_WARN("%s Unable to find expected alarm in hash map", __func__); + return -EINVAL; + } + + hash_map_erase(bm_alarm_hash_map, work); + return 0; +} + +s32_t k_delayed_work_remaining_get(struct k_delayed_work *work) +{ + assert(work != NULL && bm_alarm_hash_map != NULL); + + osi_alarm_t *alarm = hash_map_get(bm_alarm_hash_map, (void *)work); + if (alarm == NULL) { + BT_WARN("%s Unable to find expected alarm in hash map", __func__); + return 0; + } + + if (!alarm->deadline_us) { + return 0; + } + + s32_t remain_time = 0; + int64_t now = esp_timer_get_time(); + if ((alarm->deadline_us - now) < 0x1FFFFFFFFFF) { + remain_time = (alarm->deadline_us - now) / 1000; + } else { + return 0; + } + + return remain_time; +} diff --git a/components/bt/ble_mesh/mesh_core/mesh_main.c b/components/bt/ble_mesh/mesh_core/mesh_main.c new file mode 100644 index 0000000000..03760d957c --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/mesh_main.c @@ -0,0 +1,509 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "sdkconfig.h" +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BLE_MESH_DEBUG) + +#include "mesh_buf.h" +#include "mesh_trace.h" +#include "mesh_main.h" +#include "mesh_hci.h" + +#include "adv.h" +#include "prov.h" +#include "net.h" +#include "beacon.h" +#include "lpn.h" +#include "friend.h" +#include "transport.h" +#include "access.h" +#include "foundation.h" +#include "proxy.h" +#include "settings.h" +#include "mesh.h" +#include "provisioner_prov.h" +#include "provisioner_proxy.h" +#include "provisioner_main.h" + +static volatile bool provisioner_en = false; + +#define ACTION_ENTER 0x01 +#define ACTION_SUSPEND 0x02 +#define ACTION_EXIT 0x03 + +#if CONFIG_BLE_MESH_NODE + +int bt_mesh_provision(const u8_t net_key[16], u16_t net_idx, + u8_t flags, u32_t iv_index, u16_t addr, + const u8_t dev_key[16]) +{ + bool pb_gatt_enabled; + int err; + + BT_INFO("Primary Element: 0x%04x", addr); + BT_DBG("net_idx 0x%04x flags 0x%02x iv_index 0x%04x", + net_idx, flags, iv_index); + + if (bt_mesh_atomic_test_and_set_bit(bt_mesh.flags, BLE_MESH_VALID)) { + return -EALREADY; + } + + if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT)) { + if (bt_mesh_proxy_prov_disable(false) == 0) { + pb_gatt_enabled = true; + } else { + pb_gatt_enabled = false; + } + } else { + pb_gatt_enabled = false; + } + + err = bt_mesh_net_create(net_idx, flags, net_key, iv_index); + if (err) { + bt_mesh_atomic_clear_bit(bt_mesh.flags, BLE_MESH_VALID); + + if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && pb_gatt_enabled) { + bt_mesh_proxy_prov_enable(); + } + + return err; + } + + bt_mesh.seq = 0U; + + bt_mesh_comp_provision(addr); + + memcpy(bt_mesh.dev_key, dev_key, 16); + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + BT_DBG("Storing network information persistently"); + bt_mesh_store_net(); + bt_mesh_store_subnet(&bt_mesh.sub[0]); + bt_mesh_store_iv(false); + } + + /* Add this to avoid "already active status" for bt_mesh_scan_enable() */ + bt_mesh_scan_disable(); + + bt_mesh_net_start(); + + return 0; +} + +void bt_mesh_reset(void) +{ + if (!bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID)) { + BT_WARN("%s, Not provisioned", __func__); + return; + } + + bt_mesh.iv_index = 0U; + bt_mesh.seq = 0U; + + memset(bt_mesh.flags, 0, sizeof(bt_mesh.flags)); + + k_delayed_work_cancel(&bt_mesh.ivu_timer); + + bt_mesh_cfg_reset(); + + bt_mesh_rx_reset(); + bt_mesh_tx_reset(); + + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) { + bt_mesh_lpn_disable(true); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { + bt_mesh_friend_clear_net_idx(BLE_MESH_KEY_ANY); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY)) { + bt_mesh_proxy_gatt_disable(); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_clear_net(); + } + + (void)memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key)); + + bt_mesh_scan_disable(); + bt_mesh_beacon_disable(); + + bt_mesh_comp_unprovision(); + + if (IS_ENABLED(CONFIG_BLE_MESH_PROV)) { + bt_mesh_prov_reset(); + } +} + +bool bt_mesh_is_provisioned(void) +{ + return bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID); +} + +int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers) +{ + if (bt_mesh_is_provisioned()) { + return -EALREADY; + } + + if (IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) && + (bearers & BLE_MESH_PROV_ADV)) { + /* Make sure we're scanning for provisioning inviations */ + bt_mesh_scan_enable(); + /* Enable unprovisioned beacon sending */ + bt_mesh_beacon_enable(); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && + (bearers & BLE_MESH_PROV_GATT)) { + bt_mesh_proxy_prov_enable(); + bt_mesh_adv_update(); + } + + return 0; +} + +int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers) +{ + if (bt_mesh_is_provisioned()) { + return -EALREADY; + } + + if (IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) && + (bearers & BLE_MESH_PROV_ADV)) { + bt_mesh_beacon_disable(); + bt_mesh_scan_disable(); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && + (bearers & BLE_MESH_PROV_GATT)) { + bt_mesh_proxy_prov_disable(true); + } + + return 0; +} + +#endif /* CONFIG_BLE_MESH_NODE */ + +static void model_suspend(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, + bool vnd, bool primary, void *user_data) +{ + if (mod->pub && mod->pub->update) { + mod->pub->count = 0U; + k_delayed_work_cancel(&mod->pub->timer); + } +} + +int bt_mesh_suspend(void) +{ + int err; + + if (!bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID)) { + return -EINVAL; + } + + if (bt_mesh_atomic_test_and_set_bit(bt_mesh.flags, BLE_MESH_SUSPENDED)) { + return -EALREADY; + } + + err = bt_mesh_scan_disable(); + if (err) { + bt_mesh_atomic_clear_bit(bt_mesh.flags, BLE_MESH_SUSPENDED); + BT_WARN("%s, Disabling scanning failed (err %d)", __func__, err); + return err; + } + + bt_mesh_hb_pub_disable(); + + if (bt_mesh_beacon_get() == BLE_MESH_BEACON_ENABLED) { + bt_mesh_beacon_disable(); + } + + bt_mesh_model_foreach(model_suspend, NULL); + + return 0; +} + +static void model_resume(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, + bool vnd, bool primary, void *user_data) +{ + if (mod->pub && mod->pub->update) { + s32_t period_ms = bt_mesh_model_pub_period_get(mod); + + if (period_ms) { + k_delayed_work_submit(&mod->pub->timer, period_ms); + } + } +} + +int bt_mesh_resume(void) +{ + int err; + + if (!bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID)) { + return -EINVAL; + } + + if (!bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_SUSPENDED)) { + return -EALREADY; + } + + err = bt_mesh_scan_enable(); + if (err) { + BT_WARN("%s, Re-enabling scanning failed (err %d)", __func__, err); + bt_mesh_atomic_set_bit(bt_mesh.flags, BLE_MESH_SUSPENDED); + return err; + } + + if (bt_mesh_beacon_get() == BLE_MESH_BEACON_ENABLED) { + bt_mesh_beacon_enable(); + } + + bt_mesh_model_foreach(model_resume, NULL); + + return err; +} + +int bt_mesh_init(const struct bt_mesh_prov *prov, + const struct bt_mesh_comp *comp) +{ + int err; + + bt_mesh_k_init(); + + bt_mesh_hci_init(); + + bt_mesh_adapt_init(); + + err = bt_mesh_comp_register(comp); + if (err) { + return err; + } + + bt_mesh_gatt_init(); + +#if CONFIG_BLE_MESH_NODE + extern struct bt_mesh_gatt_service proxy_svc; + if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY)) { + bt_mesh_gatts_service_register(&proxy_svc); + } + + extern struct bt_mesh_gatt_service prov_svc; + if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT)) { + bt_mesh_gatts_service_register(&prov_svc); + } +#endif + + if (IS_ENABLED(CONFIG_BLE_MESH_PROV)) { +#if CONFIG_BLE_MESH_NODE + err = bt_mesh_prov_init(prov); + if (err) { + return err; + } +#endif +#if CONFIG_BLE_MESH_PROVISIONER + err = provisioner_prov_init(prov); + if (err) { + return err; + } +#endif + } + + bt_mesh_net_init(); + bt_mesh_trans_init(); + +#if CONFIG_BLE_MESH_NODE + /* Changed by Espressif, add random delay (0 ~ 3s) */ +#if defined(CONFIG_BLE_MESH_FAST_PROV) + u32_t delay = 0; + bt_mesh_rand(&delay, sizeof(u32_t)); + vTaskDelay((delay % 3000) / portTICK_PERIOD_MS); +#endif + bt_mesh_beacon_init(); +#endif + + bt_mesh_adv_init(); + + if (IS_ENABLED(CONFIG_BLE_MESH_PROXY)) { +#if CONFIG_BLE_MESH_NODE + bt_mesh_proxy_init(); +#endif +#if CONFIG_BLE_MESH_PROVISIONER + provisioner_proxy_init(); +#endif + } + +#if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + /* If node & provisioner are both enabled and the + * device starts as a node, it must finish provisioning */ + err = provisioner_upper_init(); + if (err) { + return err; + } +#endif + +#if defined(CONFIG_BLE_MESH_SETTINGS) + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_settings_init(); + } +#endif + + return 0; +} + +bool bt_mesh_is_provisioner_en(void) +{ + return provisioner_en; +} + +/* The following APIs are for fast provisioning */ + +#if CONFIG_BLE_MESH_PROVISIONER +int bt_mesh_provisioner_enable(bt_mesh_prov_bearer_t bearers) +{ + int err; + + if (bt_mesh_is_provisioner_en()) { + BT_WARN("%s, Provisioner is already enabled", __func__); + return -EALREADY; + } + + err = provisioner_upper_init(); + if (err) { + BT_ERR("%s, provisioner_upper_init fail", __func__); + return err; + } + +#if defined(CONFIG_BLE_MESH_USE_DUPLICATE_SCAN) + if (IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) && + (bearers & BLE_MESH_PROV_ADV)) { + bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_ADD, + BLE_MESH_EXCEP_INFO_MESH_BEACON, NULL); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && + (bearers & BLE_MESH_PROV_GATT)) { + bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_ADD, + BLE_MESH_EXCEP_INFO_MESH_PROV_ADV, NULL); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_PROXY)) { + bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_ADD, + BLE_MESH_EXCEP_INFO_MESH_PROXY_ADV, NULL); + } +#endif + + if ((IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) && + (bearers & BLE_MESH_PROV_ADV)) || + (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && + (bearers & BLE_MESH_PROV_GATT))) { + bt_mesh_scan_enable(); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && + (bearers & BLE_MESH_PROV_GATT)) { + provisioner_pb_gatt_enable(); + } + + provisioner_en = true; + + return 0; +} + +int bt_mesh_provisioner_disable(bt_mesh_prov_bearer_t bearers) +{ + if (!bt_mesh_is_provisioner_en()) { + BT_WARN("%s, Provisioner is already disabled", __func__); + return -EALREADY; + } + + if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && + (bearers & BLE_MESH_PROV_GATT)) { + provisioner_pb_gatt_disable(); + } + + if ((IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) && + (bearers & BLE_MESH_PROV_ADV)) && + (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && + (bearers & BLE_MESH_PROV_GATT))) { + bt_mesh_scan_disable(); + } + + provisioner_en = false; + + return 0; +} +#endif /* CONFIG_BLE_MESH_PROVISIONER */ + +/* The following API is for fast provisioning */ + +#if CONFIG_BLE_MESH_FAST_PROV +u8_t bt_mesh_set_fast_prov_action(u8_t action) +{ + if (!action || action > ACTION_EXIT) { + return 0x01; + } + + if ((!provisioner_en && (action == ACTION_SUSPEND || action == ACTION_EXIT)) || + (provisioner_en && (action == ACTION_ENTER))) { + BT_WARN("%s, Action is already done", __func__); + return 0x0; + } + + if (action == ACTION_ENTER) { +#if 0 + /* If the device is provisioned using PB-GATT and connected to + * the phone with proxy service, proxy_gatt shall not be disabled + * here. The node needs to send some status messages to the phone + * while it is connected. + */ + if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY)) { + bt_mesh_proxy_gatt_disable(); + } +#endif + if (bt_mesh_beacon_get() == BLE_MESH_BEACON_ENABLED) { + bt_mesh_beacon_disable(); + } + if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT)) { + provisioner_pb_gatt_enable(); + } + provisioner_set_fast_prov_flag(true); + provisioner_en = true; + } else { + if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT)) { + provisioner_pb_gatt_disable(); + } + if (bt_mesh_beacon_get() == BLE_MESH_BEACON_ENABLED) { + bt_mesh_beacon_enable(); + } +#if 0 + /* Mesh Proxy GATT will be re-enabled on application layer */ + if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY) && + bt_mesh_gatt_proxy_get() != BLE_MESH_GATT_PROXY_NOT_SUPPORTED) { + bt_mesh_proxy_gatt_enable(); + bt_mesh_adv_update(); + } +#endif + provisioner_set_fast_prov_flag(false); + provisioner_en = false; + if (action == ACTION_EXIT) { + provisioner_upper_reset_all_nodes(); + provisioner_prov_reset_all_nodes(); + } + } + + return 0x0; +} +#endif /* CONFIG_BLE_MESH_FAST_PROV */ diff --git a/components/bt/ble_mesh/mesh_core/mesh_util.c b/components/bt/ble_mesh/mesh_core/mesh_util.c new file mode 100644 index 0000000000..4650bb2603 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/mesh_util.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2016 Vinayak Kariappa Chettimada + * Copyright (c) 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "mesh_util.h" +#include "mesh_kernel.h" +#include "mesh_aes_encrypt.h" + +#define MASK_TWENTY_SEVEN 0x1b + +const char *bt_hex(const void *buf, size_t len) +{ + static const char hex[] = "0123456789abcdef"; + static char hexbufs[4][129]; + static u8_t curbuf; + const u8_t *b = buf; + unsigned int mask; + char *str; + int i; + + mask = bt_mesh_irq_lock(); + str = hexbufs[curbuf++]; + curbuf %= ARRAY_SIZE(hexbufs); + bt_mesh_irq_unlock(mask); + + len = MIN(len, (sizeof(hexbufs[0]) - 1) / 2); + + for (i = 0; i < len; i++) { + str[i * 2] = hex[b[i] >> 4]; + str[i * 2 + 1] = hex[b[i] & 0xf]; + } + + str[i * 2] = '\0'; + + return str; +} + +void mem_rcopy(u8_t *dst, u8_t const *src, u16_t len) +{ + src += len; + while (len--) { + *dst++ = *--src; + } +} + +unsigned int _copy(uint8_t *to, unsigned int to_len, + const uint8_t *from, unsigned int from_len) +{ + if (from_len <= to_len) { + (void)memcpy(to, from, from_len); + return from_len; + } else { + return TC_CRYPTO_FAIL; + } +} + +void _set(void *to, uint8_t val, unsigned int len) +{ + (void)memset(to, val, len); +} + +/* + * Doubles the value of a byte for values up to 127. + */ +uint8_t _double_byte(uint8_t a) +{ + return ((a << 1) ^ ((a >> 7) * MASK_TWENTY_SEVEN)); +} + +int _compare(const uint8_t *a, const uint8_t *b, size_t size) +{ + const uint8_t *tempa = a; + const uint8_t *tempb = b; + uint8_t result = 0; + + for (unsigned int i = 0; i < size; i++) { + result |= tempa[i] ^ tempb[i]; + } + return result; +} diff --git a/components/bt/ble_mesh/mesh_core/net.c b/components/bt/ble_mesh/mesh_core/net.c new file mode 100644 index 0000000000..020ea02707 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/net.c @@ -0,0 +1,1517 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "sdkconfig.h" +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BLE_MESH_DEBUG_NET) + +#include "mesh_util.h" +#include "mesh_buf.h" +#include "mesh_main.h" +#include "mesh_trace.h" +#include "mesh.h" + +#include "crypto.h" +#include "adv.h" +#include "mesh.h" +#include "net.h" +#include "lpn.h" +#include "friend.h" +#include "proxy.h" +#include "transport.h" +#include "access.h" +#include "foundation.h" +#include "beacon.h" +#include "settings.h" +#include "prov.h" +#include "provisioner_main.h" + +/* Minimum valid Mesh Network PDU length. The Network headers + * themselves take up 9 bytes. After that there is a minumum of 1 byte + * payload for both CTL=1 and CTL=0 PDUs (smallest OpCode is 1 byte). CTL=1 + * PDUs must use a 64-bit (8 byte) NetMIC, whereas CTL=0 PDUs have at least + * a 32-bit (4 byte) NetMIC and AppMIC giving again a total of 8 bytes. + */ +#define BLE_MESH_NET_MIN_PDU_LEN (BLE_MESH_NET_HDR_LEN + 1 + 8) + +/* Seq limit after IV Update is triggered */ +#define IV_UPDATE_SEQ_LIMIT 8000000 + +#define IVI(pdu) ((pdu)[0] >> 7) +#define NID(pdu) ((pdu)[0] & 0x7f) +#define CTL(pdu) ((pdu)[1] >> 7) +#define TTL(pdu) ((pdu)[1] & 0x7f) +#define SEQ(pdu) (((u32_t)(pdu)[2] << 16) | \ + ((u32_t)(pdu)[3] << 8) | (u32_t)(pdu)[4]); +#define SRC(pdu) (sys_get_be16(&(pdu)[5])) +#define DST(pdu) (sys_get_be16(&(pdu)[7])) + +/* Determine how many friendship credentials we need */ +#if defined(CONFIG_BLE_MESH_FRIEND) +#define FRIEND_CRED_COUNT CONFIG_BLE_MESH_FRIEND_LPN_COUNT +#elif defined(CONFIG_BLE_MESH_LOW_POWER) +#define FRIEND_CRED_COUNT CONFIG_BLE_MESH_SUBNET_COUNT +#else +#define FRIEND_CRED_COUNT 0 +#endif + +#if FRIEND_CRED_COUNT > 0 +static struct friend_cred friend_cred[FRIEND_CRED_COUNT]; +#endif + +static u64_t msg_cache[CONFIG_BLE_MESH_MSG_CACHE_SIZE]; +static u16_t msg_cache_next; + +/* Singleton network context (the implementation only supports one) */ +struct bt_mesh_net bt_mesh = { + .local_queue = SYS_SLIST_STATIC_INIT(&bt_mesh.local_queue), + .sub = { + [0 ... (CONFIG_BLE_MESH_SUBNET_COUNT - 1)] = { + .net_idx = BLE_MESH_KEY_UNUSED, + } + }, + .app_keys = { + [0 ... (CONFIG_BLE_MESH_APP_KEY_COUNT - 1)] = { + .net_idx = BLE_MESH_KEY_UNUSED, + } + }, +}; + +static u32_t dup_cache[4]; +static int dup_cache_next; + +static bool check_dup(struct net_buf_simple *data) +{ + const u8_t *tail = net_buf_simple_tail(data); + u32_t val; + int i; + + val = sys_get_be32(tail - 4) ^ sys_get_be32(tail - 8); + + for (i = 0; i < ARRAY_SIZE(dup_cache); i++) { + if (dup_cache[i] == val) { + return true; + } + } + + dup_cache[dup_cache_next++] = val; + dup_cache_next %= ARRAY_SIZE(dup_cache); + + return false; +} + +static u64_t msg_hash(struct bt_mesh_net_rx *rx, struct net_buf_simple *pdu) +{ + u32_t hash1, hash2; + + /* Three least significant bytes of IVI + first byte of SEQ */ + hash1 = (BLE_MESH_NET_IVI_RX(rx) << 8) | pdu->data[2]; + + /* Two last bytes of SEQ + SRC */ + memcpy(&hash2, &pdu->data[3], 4); + + return (u64_t)hash1 << 32 | (u64_t)hash2; +} + +static bool msg_cache_match(struct bt_mesh_net_rx *rx, + struct net_buf_simple *pdu) +{ + u64_t hash = msg_hash(rx, pdu); + u16_t i; + + for (i = 0U; i < ARRAY_SIZE(msg_cache); i++) { + if (msg_cache[i] == hash) { + return true; + } + } + + /* Add to the cache */ + msg_cache[msg_cache_next++] = hash; + msg_cache_next %= ARRAY_SIZE(msg_cache); + + return false; +} + +struct bt_mesh_subnet *bt_mesh_subnet_get(u16_t net_idx) +{ + int i; + + if (net_idx == BLE_MESH_KEY_ANY) { + return &bt_mesh.sub[0]; + } + + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + if (bt_mesh.sub[i].net_idx == net_idx) { + return &bt_mesh.sub[i]; + } + } + + return NULL; +} + +int bt_mesh_net_keys_create(struct bt_mesh_subnet_keys *keys, + const u8_t key[16]) +{ + u8_t p[] = { 0 }; + u8_t nid; + int err; + + err = bt_mesh_k2(key, p, sizeof(p), &nid, keys->enc, keys->privacy); + if (err) { + BT_ERR("%s, Unable to generate NID, EncKey & PrivacyKey", __func__); + return err; + } + + memcpy(keys->net, key, 16); + + keys->nid = nid; + + BT_DBG("NID 0x%02x EncKey %s", keys->nid, bt_hex(keys->enc, 16)); + BT_DBG("PrivacyKey %s", bt_hex(keys->privacy, 16)); + + err = bt_mesh_k3(key, keys->net_id); + if (err) { + BT_ERR("%s, Unable to generate Net ID", __func__); + return err; + } + + BT_DBG("NetID %s", bt_hex(keys->net_id, 8)); + +#if defined(CONFIG_BLE_MESH_GATT_PROXY) + err = bt_mesh_identity_key(key, keys->identity); + if (err) { + BT_ERR("%s, Unable to generate IdentityKey", __func__); + return err; + } + + BT_DBG("IdentityKey %s", bt_hex(keys->identity, 16)); +#endif /* GATT_PROXY */ + + err = bt_mesh_beacon_key(key, keys->beacon); + if (err) { + BT_ERR("%s, Unable to generate beacon key", __func__); + return err; + } + + BT_DBG("BeaconKey %s", bt_hex(keys->beacon, 16)); + + return 0; +} + +#if (defined(CONFIG_BLE_MESH_LOW_POWER) || \ + defined(CONFIG_BLE_MESH_FRIEND)) +int friend_cred_set(struct friend_cred *cred, u8_t idx, const u8_t net_key[16]) +{ + u16_t lpn_addr, frnd_addr; + int err; + u8_t p[9]; + +#if defined(CONFIG_BLE_MESH_LOW_POWER) + if (cred->addr == bt_mesh.lpn.frnd) { + lpn_addr = bt_mesh_primary_addr(); + frnd_addr = cred->addr; + } else { + lpn_addr = cred->addr; + frnd_addr = bt_mesh_primary_addr(); + } +#else + lpn_addr = cred->addr; + frnd_addr = bt_mesh_primary_addr(); +#endif + + BT_DBG("LPNAddress 0x%04x FriendAddress 0x%04x", lpn_addr, frnd_addr); + BT_DBG("LPNCounter 0x%04x FriendCounter 0x%04x", cred->lpn_counter, + cred->frnd_counter); + + p[0] = 0x01; + sys_put_be16(lpn_addr, p + 1); + sys_put_be16(frnd_addr, p + 3); + sys_put_be16(cred->lpn_counter, p + 5); + sys_put_be16(cred->frnd_counter, p + 7); + + err = bt_mesh_k2(net_key, p, sizeof(p), &cred->cred[idx].nid, + cred->cred[idx].enc, cred->cred[idx].privacy); + if (err) { + BT_ERR("%s, Unable to generate NID, EncKey & PrivacyKey", __func__); + return err; + } + + BT_DBG("Friend NID 0x%02x EncKey %s", cred->cred[idx].nid, + bt_hex(cred->cred[idx].enc, 16)); + BT_DBG("Friend PrivacyKey %s", bt_hex(cred->cred[idx].privacy, 16)); + + return 0; +} + +void friend_cred_refresh(u16_t net_idx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { + struct friend_cred *cred = &friend_cred[i]; + + if (cred->addr != BLE_MESH_ADDR_UNASSIGNED && + cred->net_idx == net_idx) { + memcpy(&cred->cred[0], &cred->cred[1], + sizeof(cred->cred[0])); + } + } +} + +int friend_cred_update(struct bt_mesh_subnet *sub) +{ + int err, i; + + BT_DBG("net_idx 0x%04x", sub->net_idx); + + for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { + struct friend_cred *cred = &friend_cred[i]; + + if (cred->addr == BLE_MESH_ADDR_UNASSIGNED || + cred->net_idx != sub->net_idx) { + continue; + } + + err = friend_cred_set(cred, 1, sub->keys[1].net); + if (err) { + return err; + } + } + + return 0; +} + +struct friend_cred *friend_cred_create(struct bt_mesh_subnet *sub, u16_t addr, + u16_t lpn_counter, u16_t frnd_counter) +{ + struct friend_cred *cred; + int i, err; + + BT_DBG("net_idx 0x%04x addr 0x%04x", sub->net_idx, addr); + + for (cred = NULL, i = 0; i < ARRAY_SIZE(friend_cred); i++) { + if ((friend_cred[i].addr == BLE_MESH_ADDR_UNASSIGNED) || + (friend_cred[i].addr == addr && + friend_cred[i].net_idx == sub->net_idx)) { + cred = &friend_cred[i]; + break; + } + } + + if (!cred) { + BT_WARN("No free friend credential slots"); + return NULL; + } + + cred->net_idx = sub->net_idx; + cred->addr = addr; + cred->lpn_counter = lpn_counter; + cred->frnd_counter = frnd_counter; + + err = friend_cred_set(cred, 0, sub->keys[0].net); + if (err) { + friend_cred_clear(cred); + return NULL; + } + + if (sub->kr_flag) { + err = friend_cred_set(cred, 1, sub->keys[1].net); + if (err) { + friend_cred_clear(cred); + return NULL; + } + } + + return cred; +} + +void friend_cred_clear(struct friend_cred *cred) +{ + cred->net_idx = BLE_MESH_KEY_UNUSED; + cred->addr = BLE_MESH_ADDR_UNASSIGNED; + cred->lpn_counter = 0U; + cred->frnd_counter = 0U; + (void)memset(cred->cred, 0, sizeof(cred->cred)); +} + +int friend_cred_del(u16_t net_idx, u16_t addr) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { + struct friend_cred *cred = &friend_cred[i]; + + if (cred->addr == addr && cred->net_idx == net_idx) { + friend_cred_clear(cred); + return 0; + } + } + + return -ENOENT; +} + +int friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid, + const u8_t **enc, const u8_t **priv) +{ + int i; + + BT_DBG("net_idx 0x%04x addr 0x%04x", sub->net_idx, addr); + + for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { + struct friend_cred *cred = &friend_cred[i]; + + if (cred->net_idx != sub->net_idx) { + continue; + } + + if (addr != BLE_MESH_ADDR_UNASSIGNED && cred->addr != addr) { + continue; + } + + if (nid) { + *nid = cred->cred[sub->kr_flag].nid; + } + + if (enc) { + *enc = cred->cred[sub->kr_flag].enc; + } + + if (priv) { + *priv = cred->cred[sub->kr_flag].privacy; + } + + return 0; + } + + return -ENOENT; +} +#else +int friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid, + const u8_t **enc, const u8_t **priv) +{ + return -ENOENT; +} +#endif /* FRIEND || LOW_POWER */ + +u8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub) +{ + u8_t flags = 0x00; + + if (sub && sub->kr_flag) { + flags |= BLE_MESH_NET_FLAG_KR; + } + + if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS)) { + flags |= BLE_MESH_NET_FLAG_IVU; + } + + return flags; +} + +int bt_mesh_net_beacon_update(struct bt_mesh_subnet *sub) +{ + u8_t flags = bt_mesh_net_flags(sub); + struct bt_mesh_subnet_keys *keys; + + if (sub->kr_flag) { + BT_DBG("NetIndex %u Using new key", sub->net_idx); + keys = &sub->keys[1]; + } else { + BT_DBG("NetIndex %u Using current key", sub->net_idx); + keys = &sub->keys[0]; + } + + BT_DBG("flags 0x%02x, IVI 0x%08x", flags, bt_mesh.iv_index); + + return bt_mesh_beacon_auth(keys->beacon, flags, keys->net_id, + bt_mesh.iv_index, sub->auth); +} + +int bt_mesh_net_create(u16_t idx, u8_t flags, const u8_t key[16], + u32_t iv_index) +{ + struct bt_mesh_subnet *sub; + int err; + + BT_DBG("idx %u flags 0x%02x iv_index %u", idx, flags, iv_index); + + BT_DBG("NetKey %s", bt_hex(key, 16)); + + (void)memset(msg_cache, 0, sizeof(msg_cache)); + msg_cache_next = 0U; + + sub = &bt_mesh.sub[0]; + + sub->kr_flag = BLE_MESH_KEY_REFRESH(flags); + if (sub->kr_flag) { + err = bt_mesh_net_keys_create(&sub->keys[1], key); + if (err) { + return -EIO; + } + + sub->kr_phase = BLE_MESH_KR_PHASE_2; + } else { + err = bt_mesh_net_keys_create(&sub->keys[0], key); + if (err) { + return -EIO; + } + } + + sub->net_idx = idx; + + if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY)) { + sub->node_id = BLE_MESH_NODE_IDENTITY_STOPPED; + } else { + sub->node_id = BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED; + } + + bt_mesh.iv_index = iv_index; + bt_mesh_atomic_set_bit_to(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS, + BLE_MESH_IV_UPDATE(flags)); + + /* Set minimum required hours, since the 96-hour minimum requirement + * doesn't apply straight after provisioning (since we can't know how + * long has actually passed since the network changed its state). + */ + bt_mesh.ivu_duration = BLE_MESH_IVU_MIN_HOURS; + + /* Make sure we have valid beacon data to be sent */ + bt_mesh_net_beacon_update(sub); + + return 0; +} + +void bt_mesh_net_revoke_keys(struct bt_mesh_subnet *sub) +{ + int i; + + BT_DBG("idx 0x%04x", sub->net_idx); + + memcpy(&sub->keys[0], &sub->keys[1], sizeof(sub->keys[0])); + + for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { + struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; + + if (key->net_idx != sub->net_idx || !key->updated) { + continue; + } + + memcpy(&key->keys[0], &key->keys[1], sizeof(key->keys[0])); + key->updated = false; + } +} + +bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, u8_t new_kr, bool new_key) +{ + if (new_kr != sub->kr_flag && sub->kr_phase == BLE_MESH_KR_NORMAL) { + BT_WARN("KR change in normal operation. Are we blacklisted?"); + return false; + } + + sub->kr_flag = new_kr; + + if (sub->kr_flag) { + if (sub->kr_phase == BLE_MESH_KR_PHASE_1) { + BT_DBG("Phase 1 -> Phase 2"); + sub->kr_phase = BLE_MESH_KR_PHASE_2; + return true; + } + } else { + switch (sub->kr_phase) { + case BLE_MESH_KR_PHASE_1: + if (!new_key) { + /* Ignore */ + break; + } + /* Upon receiving a Secure Network beacon with the KR flag set + * to 0 using the new NetKey in Phase 1, the node shall + * immediately transition to Phase 3, which effectively skips + * Phase 2. + * + * Intentional fall-through. + */ + case BLE_MESH_KR_PHASE_2: + BT_DBG("KR Phase 0x%02x -> Normal", sub->kr_phase); + bt_mesh_net_revoke_keys(sub); + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) || + IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { + friend_cred_refresh(sub->net_idx); + } + sub->kr_phase = BLE_MESH_KR_NORMAL; + return true; + } + } + + return false; +} + +void bt_mesh_rpl_reset(void) +{ + int i; + + /* Discard "old old" IV Index entries from RPL and flag + * any other ones (which are valid) as old. + */ + for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { + struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; + + if (rpl->src) { + if (rpl->old_iv) { + (void)memset(rpl, 0, sizeof(*rpl)); + } else { + rpl->old_iv = true; + } + } + } +} + +#if defined(CONFIG_BLE_MESH_IV_UPDATE_TEST) +void bt_mesh_iv_update_test(bool enable) +{ + bt_mesh_atomic_set_bit_to(bt_mesh.flags, BLE_MESH_IVU_TEST, enable); + /* Reset the duration variable - needed for some PTS tests */ + bt_mesh.ivu_duration = 0U; +} + +bool bt_mesh_iv_update(void) +{ + if (!bt_mesh_is_provisioned()) { + BT_ERR("%s, Not yet provisioned", __func__); + return false; + } + + if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS)) { + bt_mesh_net_iv_update(bt_mesh.iv_index, false); + } else { + bt_mesh_net_iv_update(bt_mesh.iv_index + 1, true); + } + + bt_mesh_net_sec_update(NULL); + + return bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS); +} +#endif /* CONFIG_BLE_MESH_IV_UPDATE_TEST */ + +/* Used for sending immediate beacons to Friend queues and GATT clients */ +void bt_mesh_net_sec_update(struct bt_mesh_subnet *sub) +{ + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { + bt_mesh_friend_sec_update(sub ? sub->net_idx : BLE_MESH_KEY_ANY); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY) && + bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED) { +#if CONFIG_BLE_MESH_NODE + bt_mesh_proxy_beacon_send(sub); +#endif + } +} + +bool bt_mesh_net_iv_update(u32_t iv_index, bool iv_update) +{ + int i; + + if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS)) { + /* We're currently in IV Update mode */ + + if (iv_index != bt_mesh.iv_index) { + BT_WARN("IV Index mismatch: 0x%08x != 0x%08x", + iv_index, bt_mesh.iv_index); + return false; + } + + if (iv_update) { + /* Nothing to do */ + BT_DBG("Already in IV Update in Progress state"); + return false; + } + } else { + /* We're currently in Normal mode */ + + if (iv_index == bt_mesh.iv_index) { + BT_DBG("Same IV Index in normal mode"); + return false; + } + + if (iv_index < bt_mesh.iv_index || + iv_index > bt_mesh.iv_index + 42) { + BT_ERR("IV Index out of sync: 0x%08x != 0x%08x", + iv_index, bt_mesh.iv_index); + return false; + } + + if (iv_index > bt_mesh.iv_index + 1) { + BT_WARN("Performing IV Index Recovery"); + (void)memset(bt_mesh.rpl, 0, sizeof(bt_mesh.rpl)); + bt_mesh.iv_index = iv_index; + bt_mesh.seq = 0U; + goto do_update; + } + + if (iv_index == bt_mesh.iv_index + 1 && !iv_update) { + BT_WARN("Ignoring new index in normal mode"); + return false; + } + + if (!iv_update) { + /* Nothing to do */ + BT_DBG("Already in Normal state"); + return false; + } + } + + if (!(IS_ENABLED(CONFIG_BLE_MESH_IV_UPDATE_TEST) && + bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_TEST))) { + if (bt_mesh.ivu_duration < BLE_MESH_IVU_MIN_HOURS) { + BT_WARN("IV Update before minimum duration"); + return false; + } + } + + /* Defer change to Normal Operation if there are pending acks */ + if (!iv_update && bt_mesh_tx_in_progress()) { + BT_WARN("IV Update deferred because of pending transfer"); + bt_mesh_atomic_set_bit(bt_mesh.flags, BLE_MESH_IVU_PENDING); + return false; + } + +do_update: + bt_mesh_atomic_set_bit_to(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS, iv_update); + bt_mesh.ivu_duration = 0U; + + if (iv_update) { + bt_mesh.iv_index = iv_index; + BT_DBG("IV Update state entered. New index 0x%08x", + bt_mesh.iv_index); + + bt_mesh_rpl_reset(); + } else { + BT_DBG("Normal mode entered"); + bt_mesh.seq = 0U; + } + + k_delayed_work_submit(&bt_mesh.ivu_timer, BLE_MESH_IVU_TIMEOUT); + + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + if (bt_mesh.sub[i].net_idx != BLE_MESH_KEY_UNUSED) { + bt_mesh_net_beacon_update(&bt_mesh.sub[i]); + } + } + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_iv(false); + } + + return true; +} + +u32_t bt_mesh_next_seq(void) +{ + u32_t seq = bt_mesh.seq++; + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_seq(); + } + + return seq; +} + +int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf, + bool new_key, const struct bt_mesh_send_cb *cb, + void *cb_data) +{ + const u8_t *enc, *priv; + u32_t seq; + int err; + + BT_DBG("net_idx 0x%04x new_key %u len %u", sub->net_idx, new_key, + buf->len); + + enc = sub->keys[new_key].enc; + priv = sub->keys[new_key].privacy; + + err = bt_mesh_net_obfuscate(buf->data, BLE_MESH_NET_IVI_TX, priv); + if (err) { + BT_ERR("%s, Deobfuscate failed (err %d)", __func__, err); + return err; + } + + err = bt_mesh_net_decrypt(enc, &buf->b, BLE_MESH_NET_IVI_TX, false); + if (err) { + BT_ERR("%s, Decrypt failed (err %d)", __func__, err); + return err; + } + + /* Update with a new sequence number */ + seq = bt_mesh_next_seq(); + buf->data[2] = seq >> 16; + buf->data[3] = seq >> 8; + buf->data[4] = seq; + + err = bt_mesh_net_encrypt(enc, &buf->b, BLE_MESH_NET_IVI_TX, false); + if (err) { + BT_ERR("%s, Encrypt failed (err %d)", __func__, err); + return err; + } + + err = bt_mesh_net_obfuscate(buf->data, BLE_MESH_NET_IVI_TX, priv); + if (err) { + BT_ERR("%s, Obfuscate failed (err %d)", __func__, err); + return err; + } + + bt_mesh_adv_send(buf, cb, cb_data); + + if (!bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS) && + bt_mesh.seq > IV_UPDATE_SEQ_LIMIT) { +#if CONFIG_BLE_MESH_NODE + bt_mesh_beacon_ivu_initiator(true); +#endif + bt_mesh_net_iv_update(bt_mesh.iv_index + 1, true); + bt_mesh_net_sec_update(NULL); + } + + return 0; +} + +static void bt_mesh_net_local(struct k_work *work) +{ + struct net_buf *buf; + + while ((buf = net_buf_slist_get(&bt_mesh.local_queue))) { + BT_DBG("len %u: %s", buf->len, bt_hex(buf->data, buf->len)); + bt_mesh_net_recv(&buf->b, 0, BLE_MESH_NET_IF_LOCAL); + net_buf_unref(buf); + } +} + +int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf, + bool proxy) +{ + const bool ctl = (tx->ctx->app_idx == BLE_MESH_KEY_UNUSED); + u32_t seq_val; + u8_t nid; + const u8_t *enc, *priv; + u8_t *seq; + int err; + + if (ctl && net_buf_simple_tailroom(buf) < 8) { + BT_ERR("%s, Insufficient MIC space for CTL PDU", __func__); + return -EINVAL; + } else if (net_buf_simple_tailroom(buf) < 4) { + BT_ERR("%s, Insufficient MIC space for PDU", __func__); + return -EINVAL; + } + + BT_DBG("src 0x%04x dst 0x%04x ctl %u seq 0x%06x", + tx->src, tx->ctx->addr, ctl, bt_mesh.seq); + + net_buf_simple_push_be16(buf, tx->ctx->addr); + net_buf_simple_push_be16(buf, tx->src); + + seq = net_buf_simple_push(buf, 3); + seq_val = bt_mesh_next_seq(); + seq[0] = seq_val >> 16; + seq[1] = seq_val >> 8; + seq[2] = seq_val; + + if (ctl) { + net_buf_simple_push_u8(buf, tx->ctx->send_ttl | 0x80); + } else { + net_buf_simple_push_u8(buf, tx->ctx->send_ttl); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && tx->friend_cred) { + if (friend_cred_get(tx->sub, BLE_MESH_ADDR_UNASSIGNED, + &nid, &enc, &priv)) { + BT_WARN("Falling back to master credentials"); + + tx->friend_cred = 0U; + + nid = tx->sub->keys[tx->sub->kr_flag].nid; + enc = tx->sub->keys[tx->sub->kr_flag].enc; + priv = tx->sub->keys[tx->sub->kr_flag].privacy; + } + } else { + tx->friend_cred = 0U; + nid = tx->sub->keys[tx->sub->kr_flag].nid; + enc = tx->sub->keys[tx->sub->kr_flag].enc; + priv = tx->sub->keys[tx->sub->kr_flag].privacy; + } + + net_buf_simple_push_u8(buf, (nid | (BLE_MESH_NET_IVI_TX & 1) << 7)); + + err = bt_mesh_net_encrypt(enc, buf, BLE_MESH_NET_IVI_TX, proxy); + if (err) { + return err; + } + + return bt_mesh_net_obfuscate(buf->data, BLE_MESH_NET_IVI_TX, priv); +} + +int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, + const struct bt_mesh_send_cb *cb, void *cb_data) +{ + int err; + + BT_DBG("src 0x%04x dst 0x%04x len %u headroom %u tailroom %u", + tx->src, tx->ctx->addr, buf->len, net_buf_headroom(buf), + net_buf_tailroom(buf)); + BT_DBG("Payload len %u: %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("Seq 0x%06x", bt_mesh.seq); + + if (tx->ctx->send_ttl == BLE_MESH_TTL_DEFAULT) { + tx->ctx->send_ttl = bt_mesh_default_ttl_get(); + } + + err = bt_mesh_net_encode(tx, &buf->b, false); + if (err) { + goto done; + } + + /* Deliver to GATT Proxy Clients if necessary. Mesh spec 3.4.5.2: + * "The output filter of the interface connected to advertising or + * GATT bearers shall drop all messages with TTL value set to 1." + */ +#if CONFIG_BLE_MESH_NODE + if (bt_mesh_is_provisioned()) { + if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY) && + tx->ctx->send_ttl != 1U) { + if (bt_mesh_proxy_relay(&buf->b, tx->ctx->addr) && + BLE_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { + /* Notify completion if this only went + * through the Mesh Proxy. + */ + if (cb) { + if (cb->start) { + cb->start(0, 0, cb_data); + } + + if (cb->end) { + cb->end(0, cb_data); + } + } + + err = 0; + goto done; + } + } + } +#endif + + /* Deliver to local network interface if necessary */ + if (bt_mesh_fixed_group_match(tx->ctx->addr) || + bt_mesh_elem_find(tx->ctx->addr)) { + if (cb && cb->start) { + cb->start(0, 0, cb_data); + } + net_buf_slist_put(&bt_mesh.local_queue, net_buf_ref(buf)); + if (cb && cb->end) { + cb->end(0, cb_data); + } + k_work_submit(&bt_mesh.local_work); + } else if (tx->ctx->send_ttl != 1U) { + /* Deliver to the advertising network interface. Mesh spec + * 3.4.5.2: "The output filter of the interface connected to + * advertising or GATT bearers shall drop all messages with + * TTL value set to 1." + */ + bt_mesh_adv_send(buf, cb, cb_data); + } + +done: + net_buf_unref(buf); + return err; +} + +static bool auth_match(struct bt_mesh_subnet_keys *keys, + const u8_t net_id[8], u8_t flags, + u32_t iv_index, const u8_t auth[8]) +{ + u8_t net_auth[8]; + + if (memcmp(net_id, keys->net_id, 8)) { + return false; + } + + bt_mesh_beacon_auth(keys->beacon, flags, keys->net_id, iv_index, + net_auth); + + if (memcmp(auth, net_auth, 8)) { + BT_WARN("Authentication Value %s != %s", + bt_hex(auth, 8), bt_hex(net_auth, 8)); + return false; + } + + return true; +} + +struct bt_mesh_subnet *bt_mesh_subnet_find(const u8_t net_id[8], u8_t flags, + u32_t iv_index, const u8_t auth[8], + bool *new_key) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; + + if (sub->net_idx == BLE_MESH_KEY_UNUSED) { + continue; + } + + if (auth_match(&sub->keys[0], net_id, flags, iv_index, auth)) { + *new_key = false; + return sub; + } + + if (sub->kr_phase == BLE_MESH_KR_NORMAL) { + continue; + } + + if (auth_match(&sub->keys[1], net_id, flags, iv_index, auth)) { + *new_key = true; + return sub; + } + } + + return NULL; +} + +static int net_decrypt(struct bt_mesh_subnet *sub, const u8_t *enc, + const u8_t *priv, const u8_t *data, + size_t data_len, struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf) +{ + BT_DBG("NID 0x%02x net_idx 0x%04x", NID(data), sub->net_idx); + BT_DBG("IVI %u net->iv_index 0x%08x", IVI(data), bt_mesh.iv_index); + + rx->old_iv = (IVI(data) != (bt_mesh.iv_index & 0x01)); + + net_buf_simple_reset(buf); + memcpy(net_buf_simple_add(buf, data_len), data, data_len); + + if (bt_mesh_net_obfuscate(buf->data, BLE_MESH_NET_IVI_RX(rx), priv)) { + return -ENOENT; + } + + /* TODO: For provisioner, when a device is re-provisioned and start to + * send the same message(e.g. cfg_appkey_add), the status message is easy + * to be filtered here. So when a device is re-provisioned, the related + * msg_cache should be cleared. Will do it later. + */ + if (rx->net_if == BLE_MESH_NET_IF_ADV && msg_cache_match(rx, buf)) { + BT_WARN("Duplicate found in Network Message Cache"); + return -EALREADY; + } + + rx->ctx.addr = SRC(buf->data); + if (!BLE_MESH_ADDR_IS_UNICAST(rx->ctx.addr)) { + BT_WARN("Ignoring non-unicast src addr 0x%04x", rx->ctx.addr); + return -EINVAL; + } + + BT_DBG("src 0x%04x", rx->ctx.addr); + +#if CONFIG_BLE_MESH_NODE + if (bt_mesh_is_provisioned()) { + if (IS_ENABLED(CONFIG_BLE_MESH_PROXY) && + rx->net_if == BLE_MESH_NET_IF_PROXY_CFG) { + return bt_mesh_net_decrypt(enc, buf, BLE_MESH_NET_IVI_RX(rx), + true); + } + } +#endif + + return bt_mesh_net_decrypt(enc, buf, BLE_MESH_NET_IVI_RX(rx), false); +} + +#if (defined(CONFIG_BLE_MESH_LOW_POWER) || \ + defined(CONFIG_BLE_MESH_FRIEND)) +static int friend_decrypt(struct bt_mesh_subnet *sub, const u8_t *data, + size_t data_len, struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf) +{ + int i; + + BT_DBG("NID 0x%02x net_idx 0x%04x", NID(data), sub->net_idx); + + for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { + struct friend_cred *cred = &friend_cred[i]; + + if (cred->net_idx != sub->net_idx) { + continue; + } + + if (NID(data) == cred->cred[0].nid && + !net_decrypt(sub, cred->cred[0].enc, cred->cred[0].privacy, + data, data_len, rx, buf)) { + return 0; + } + + if (sub->kr_phase == BLE_MESH_KR_NORMAL) { + continue; + } + + if (NID(data) == cred->cred[1].nid && + !net_decrypt(sub, cred->cred[1].enc, cred->cred[1].privacy, + data, data_len, rx, buf)) { + rx->new_key = 1U; + return 0; + } + } + + return -ENOENT; +} +#endif + +static bool net_find_and_decrypt(const u8_t *data, size_t data_len, + struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf) +{ + struct bt_mesh_subnet *sub = NULL; + u32_t array_size = 0; + int i; + + BT_DBG("%s", __func__); + +#if CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER + if (!bt_mesh_is_provisioner_en()) { + array_size = ARRAY_SIZE(bt_mesh.sub); + } +#endif + +#if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (bt_mesh_is_provisioner_en()) { + array_size = ARRAY_SIZE(bt_mesh.p_sub); + } +#endif + +#if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + array_size = ARRAY_SIZE(bt_mesh.sub); + if (bt_mesh_is_provisioner_en()) { + array_size += ARRAY_SIZE(bt_mesh.p_sub); + } +#endif + + if (!array_size) { + BT_ERR("%s, Unable to get subnet size", __func__); + return false; + } + + for (i = 0; i < array_size; i++) { +#if CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER + if (!bt_mesh_is_provisioner_en()) { + sub = &bt_mesh.sub[i]; + } +#endif + +#if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (bt_mesh_is_provisioner_en()) { + sub = bt_mesh.p_sub[i]; + } +#endif + +#if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (i < ARRAY_SIZE(bt_mesh.sub)) { + sub = &bt_mesh.sub[i]; + } else { + sub = bt_mesh.p_sub[i - ARRAY_SIZE(bt_mesh.sub)]; + } +#endif + + if (!sub) { + BT_DBG("%s, NULL subnet", __func__); + continue; + } + + if (sub->net_idx == BLE_MESH_KEY_UNUSED) { + continue; + } + +#if CONFIG_BLE_MESH_NODE + if (bt_mesh_is_provisioned()) { +#if (defined(CONFIG_BLE_MESH_LOW_POWER) || defined(CONFIG_BLE_MESH_FRIEND)) + if (!friend_decrypt(sub, data, data_len, rx, buf)) { + rx->friend_cred = 1; + rx->ctx.net_idx = sub->net_idx; + rx->sub = sub; + return true; + } +#endif + } +#endif /* CONFIG_BLE_MESH_NODE */ + + if (NID(data) == sub->keys[0].nid && + !net_decrypt(sub, sub->keys[0].enc, sub->keys[0].privacy, + data, data_len, rx, buf)) { + rx->ctx.net_idx = sub->net_idx; + rx->sub = sub; + return true; + } + + if (sub->kr_phase == BLE_MESH_KR_NORMAL) { + continue; + } + + if (NID(data) == sub->keys[1].nid && + !net_decrypt(sub, sub->keys[1].enc, sub->keys[1].privacy, + data, data_len, rx, buf)) { + rx->new_key = 1U; + rx->ctx.net_idx = sub->net_idx; + rx->sub = sub; + return true; + } + } + + return false; +} + +/* Relaying from advertising to the advertising bearer should only happen + * if the Relay state is set to enabled. Locally originated packets always + * get sent to the advertising bearer. If the packet came in through GATT, + * then we should only relay it if the GATT Proxy state is enabled. + */ +#if CONFIG_BLE_MESH_NODE + +static bool relay_to_adv(enum bt_mesh_net_if net_if) +{ + switch (net_if) { + case BLE_MESH_NET_IF_LOCAL: + return true; + case BLE_MESH_NET_IF_ADV: + return (bt_mesh_relay_get() == BLE_MESH_RELAY_ENABLED); + case BLE_MESH_NET_IF_PROXY: + return (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED); + default: + return false; + } +} + +static void bt_mesh_net_relay(struct net_buf_simple *sbuf, + struct bt_mesh_net_rx *rx) +{ + const u8_t *enc, *priv; + struct net_buf *buf; + u8_t nid, transmit; + + if (rx->net_if == BLE_MESH_NET_IF_LOCAL) { + /* Locally originated PDUs with TTL=1 will only be delivered + * to local elements as per Mesh Profile 1.0 section 3.4.5.2: + * "The output filter of the interface connected to + * advertising or GATT bearers shall drop all messages with + * TTL value set to 1." + */ + if (rx->ctx.recv_ttl == 1U) { + return; + } + } else { + if (rx->ctx.recv_ttl <= 1U) { + return; + } + } + + if (rx->net_if == BLE_MESH_NET_IF_ADV && + bt_mesh_relay_get() != BLE_MESH_RELAY_ENABLED && + bt_mesh_gatt_proxy_get() != BLE_MESH_GATT_PROXY_ENABLED) { + return; + } + + BT_DBG("TTL %u CTL %u dst 0x%04x", rx->ctx.recv_ttl, rx->ctl, + rx->ctx.recv_dst); + + /* The Relay Retransmit state is only applied to adv-adv relaying. + * Anything else (like GATT to adv, or locally originated packets) + * use the Network Transmit state. + */ + if (rx->net_if == BLE_MESH_NET_IF_ADV) { + transmit = bt_mesh_relay_retransmit_get(); + } else { + transmit = bt_mesh_net_transmit_get(); + if (rx->net_if == BLE_MESH_NET_IF_PROXY && + transmit < BLE_MESH_TRANSMIT(5, 20)) { + /** + * Add this in case EspBleMesh APP just send a message once, and + * the Proxy Node will send this message using advertising bearer + * with duration not less than 180ms. + */ + transmit = BLE_MESH_TRANSMIT(5, 20); + } + } + + buf = bt_mesh_adv_create(BLE_MESH_ADV_DATA, transmit, K_NO_WAIT); + if (!buf) { + BT_ERR("%s, Out of relay buffers", __func__); + return; + } + + /* Only decrement TTL for non-locally originated packets */ + if (rx->net_if != BLE_MESH_NET_IF_LOCAL) { + /* Leave CTL bit intact */ + sbuf->data[1] &= 0x80; + sbuf->data[1] |= rx->ctx.recv_ttl - 1U; + } + + net_buf_add_mem(buf, sbuf->data, sbuf->len); + + enc = rx->sub->keys[rx->sub->kr_flag].enc; + priv = rx->sub->keys[rx->sub->kr_flag].privacy; + nid = rx->sub->keys[rx->sub->kr_flag].nid; + + BT_DBG("Relaying packet. TTL is now %u", TTL(buf->data)); + + /* Update NID if RX or RX was with friend credentials */ + if (rx->friend_cred) { + buf->data[0] &= 0x80; /* Clear everything except IVI */ + buf->data[0] |= nid; + } + + /* We re-encrypt and obfuscate using the received IVI rather than + * the normal TX IVI (which may be different) since the transport + * layer nonce includes the IVI. + */ + if (bt_mesh_net_encrypt(enc, &buf->b, BLE_MESH_NET_IVI_RX(rx), false)) { + BT_ERR("%s, Re-encrypting failed", __func__); + goto done; + } + + if (bt_mesh_net_obfuscate(buf->data, BLE_MESH_NET_IVI_RX(rx), priv)) { + BT_ERR("%s, Re-obfuscating failed", __func__); + goto done; + } + + /* Sending to the GATT bearer should only happen if GATT Proxy + * is enabled or the message originates from the local node. + */ + if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY) && + (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED || + rx->net_if == BLE_MESH_NET_IF_LOCAL)) { + if (bt_mesh_proxy_relay(&buf->b, rx->ctx.recv_dst) && + BLE_MESH_ADDR_IS_UNICAST(rx->ctx.recv_dst)) { + goto done; + } + } + + if (relay_to_adv(rx->net_if)) { + bt_mesh_adv_send(buf, NULL, NULL); + } + +done: + net_buf_unref(buf); +} + +#endif /* CONFIG_BLE_MESH_NODE */ + +int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, + struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) +{ + if (data->len < BLE_MESH_NET_MIN_PDU_LEN) { + BT_WARN("Dropping too short mesh packet (len %u)", data->len); + BT_WARN("%s", bt_hex(data->data, data->len)); + return -EINVAL; + } + + if (net_if == BLE_MESH_NET_IF_ADV && check_dup(data)) { + return -EINVAL; + } + + BT_DBG("%u bytes: %s", data->len, bt_hex(data->data, data->len)); + + rx->net_if = net_if; + + if (!net_find_and_decrypt(data->data, data->len, rx, buf)) { + BT_DBG("Unable to find matching net for packet"); + return -ENOENT; + } + + /* Initialize AppIdx to a sane value */ + rx->ctx.app_idx = BLE_MESH_KEY_UNUSED; + + rx->ctx.recv_ttl = TTL(buf->data); + + /* Default to responding with TTL 0 for non-routed messages */ + if (rx->ctx.recv_ttl == 0U) { + rx->ctx.send_ttl = 0U; + } else { + rx->ctx.send_ttl = BLE_MESH_TTL_DEFAULT; + } + + rx->ctl = CTL(buf->data); + rx->seq = SEQ(buf->data); + rx->ctx.recv_dst = DST(buf->data); + + BT_DBG("Decryption successful. Payload len %u", buf->len); + + if (net_if != BLE_MESH_NET_IF_PROXY_CFG && + rx->ctx.recv_dst == BLE_MESH_ADDR_UNASSIGNED) { + BT_ERR("%s, Destination address is unassigned; dropping packet", __func__); + return -EBADMSG; + } + + if (BLE_MESH_ADDR_IS_RFU(rx->ctx.recv_dst)) { + BT_ERR("%s, Destination address is RFU; dropping packet", __func__); + return -EBADMSG; + } + + if (net_if != BLE_MESH_NET_IF_LOCAL && bt_mesh_elem_find(rx->ctx.addr)) { + BT_DBG("Dropping locally originated packet"); + return -EBADMSG; + } + + BT_DBG("src 0x%04x dst 0x%04x ttl %u", rx->ctx.addr, rx->ctx.recv_dst, + rx->ctx.recv_ttl); + BT_DBG("PDU: %s", bt_hex(buf->data, buf->len)); + + return 0; +} + +void bt_mesh_net_recv(struct net_buf_simple *data, s8_t rssi, + enum bt_mesh_net_if net_if) +{ + NET_BUF_SIMPLE_DEFINE(buf, 29); + struct bt_mesh_net_rx rx = { .rssi = rssi }; + struct net_buf_simple_state state; + + BT_DBG("rssi %d net_if %u", rssi, net_if); + +#if CONFIG_BLE_MESH_NODE + if (!bt_mesh_is_provisioner_en()) { + if (!bt_mesh_is_provisioned()) { + return; + } + } +#endif + +#if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (!bt_mesh_is_provisioner_en()) { + BT_WARN("%s, Provisioner is disabled", __func__); + return; + } + if (!provisioner_get_prov_node_count()) { + return; + } +#endif + + if (bt_mesh_net_decode(data, net_if, &rx, &buf)) { + return; + } + + /* Save the state so the buffer can later be relayed */ + net_buf_simple_save(&buf, &state); + +#if CONFIG_BLE_MESH_NODE + if (bt_mesh_is_provisioned()) { + if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY) && + net_if == BLE_MESH_NET_IF_PROXY) { + bt_mesh_proxy_addr_add(data, rx.ctx.addr); + } + } +#endif + + rx.local_match = (bt_mesh_fixed_group_match(rx.ctx.recv_dst) || + bt_mesh_elem_find(rx.ctx.recv_dst)); + + bt_mesh_trans_recv(&buf, &rx); + + /* Relay if this was a group/virtual address, or if the destination + * was neither a local element nor an LPN we're Friends for. + */ +#if CONFIG_BLE_MESH_NODE + if (bt_mesh_is_provisioned()) { + if (!BLE_MESH_ADDR_IS_UNICAST(rx.ctx.recv_dst) || + (!rx.local_match && !rx.friend_match)) { + net_buf_simple_restore(&buf, &state); + bt_mesh_net_relay(&buf, &rx); + } + } +#endif +} + +static void ivu_refresh(struct k_work *work) +{ + bt_mesh.ivu_duration += BLE_MESH_IVU_HOURS; + + BT_DBG("%s for %u hour%s", + bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS) ? + "IVU in Progress" : "IVU Normal mode", + bt_mesh.ivu_duration, bt_mesh.ivu_duration == 1U ? "" : "s"); + + if (bt_mesh.ivu_duration < BLE_MESH_IVU_MIN_HOURS) { + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_iv(true); + } + + k_delayed_work_submit(&bt_mesh.ivu_timer, BLE_MESH_IVU_TIMEOUT); + return; + } + + if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS)) { +#if CONFIG_BLE_MESH_NODE + bt_mesh_beacon_ivu_initiator(true); +#endif + bt_mesh_net_iv_update(bt_mesh.iv_index, false); + } else if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_iv(true); + } +} + +#if defined(CONFIG_BLE_MESH_NODE) +void bt_mesh_net_start(void) +{ + if (bt_mesh_beacon_get() == BLE_MESH_BEACON_ENABLED) { + bt_mesh_beacon_enable(); + } else { + bt_mesh_beacon_disable(); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY) && + bt_mesh_gatt_proxy_get() != BLE_MESH_GATT_PROXY_NOT_SUPPORTED) { + bt_mesh_proxy_gatt_enable(); + bt_mesh_adv_update(); + } + +#if defined(CONFIG_BLE_MESH_USE_DUPLICATE_SCAN) + /* Add Mesh beacon type (Secure Network Beacon) to the exceptional list */ + bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_ADD, + BLE_MESH_EXCEP_INFO_MESH_BEACON, NULL); +#endif + + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) { + /* TODO: Enable duplicate scan in Low Power Mode */ + bt_mesh_lpn_init(); + } else { + bt_mesh_scan_enable(); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { + bt_mesh_friend_init(); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_PROV)) { + u16_t net_idx = bt_mesh.sub[0].net_idx; + u16_t addr = bt_mesh_primary_addr(); + u32_t iv_index = bt_mesh.iv_index; + u8_t flags = (u8_t)bt_mesh.sub[0].kr_flag; + if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS)) { + flags |= BLE_MESH_NET_FLAG_IVU; + } + + bt_mesh_prov_complete(net_idx, addr, flags, iv_index); + } +} +#endif + +void bt_mesh_net_init(void) +{ + k_delayed_work_init(&bt_mesh.ivu_timer, ivu_refresh); + + k_work_init(&bt_mesh.local_work, bt_mesh_net_local); +} diff --git a/components/bt/ble_mesh/mesh_core/net.h b/components/bt/ble_mesh/mesh_core/net.h new file mode 100644 index 0000000000..90515fd2ca --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/net.h @@ -0,0 +1,388 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _NET_H_ +#define _NET_H_ + +#include "mesh_util.h" +#include "mesh_kernel.h" +#include "mesh_access.h" + +#define BLE_MESH_NET_FLAG_KR BIT(0) +#define BLE_MESH_NET_FLAG_IVU BIT(1) + +#define BLE_MESH_KR_NORMAL 0x00 +#define BLE_MESH_KR_PHASE_1 0x01 +#define BLE_MESH_KR_PHASE_2 0x02 +#define BLE_MESH_KR_PHASE_3 0x03 + +#define BLE_MESH_IV_UPDATE(flags) ((flags >> 1) & 0x01) +#define BLE_MESH_KEY_REFRESH(flags) (flags & 0x01) + +/* How many hours in between updating IVU duration */ +#define BLE_MESH_IVU_MIN_HOURS 96 +#define BLE_MESH_IVU_HOURS (BLE_MESH_IVU_MIN_HOURS / \ + CONFIG_BLE_MESH_IVU_DIVIDER) +#define BLE_MESH_IVU_TIMEOUT K_HOURS(BLE_MESH_IVU_HOURS) + +struct bt_mesh_app_key { + u16_t net_idx; + u16_t app_idx; + bool updated; + struct bt_mesh_app_keys { + u8_t id; + u8_t val[16]; + } keys[2]; +}; + +struct bt_mesh_subnet { + u32_t beacon_sent; /* Timestamp of last sent beacon */ + u8_t beacons_last; /* Number of beacons during last + * observation window + */ + u8_t beacons_cur; /* Number of beaconds observed during + * currently ongoing window. + */ + + u8_t beacon_cache[21]; /* Cached last authenticated beacon */ + + u16_t net_idx; /* NetKeyIndex */ + + bool kr_flag; /* Key Refresh Flag */ + u8_t kr_phase; /* Key Refresh Phase */ + + u8_t node_id; /* Node Identity State */ + u32_t node_id_start; /* Node Identity started timestamp */ + + u8_t auth[8]; /* Beacon Authentication Value */ + + struct bt_mesh_subnet_keys { + u8_t net[16]; /* NetKey */ + u8_t nid; /* NID */ + u8_t enc[16]; /* EncKey */ + u8_t net_id[8]; /* Network ID */ +#if defined(CONFIG_BLE_MESH_GATT_PROXY) + u8_t identity[16]; /* IdentityKey */ +#endif + u8_t privacy[16]; /* PrivacyKey */ + u8_t beacon[16]; /* BeaconKey */ + } keys[2]; +}; + +struct bt_mesh_rpl { + u16_t src; + bool old_iv; +#if defined(CONFIG_BLE_MESH_SETTINGS) + bool store; +#endif + u32_t seq; +}; + +#if defined(CONFIG_BLE_MESH_FRIEND) +#define FRIEND_SEG_RX CONFIG_BLE_MESH_FRIEND_SEG_RX +#define FRIEND_SUB_LIST_SIZE CONFIG_BLE_MESH_FRIEND_SUB_LIST_SIZE +#else +#define FRIEND_SEG_RX 0 +#define FRIEND_SUB_LIST_SIZE 0 +#endif + +struct bt_mesh_friend { + u16_t lpn; + u8_t recv_delay; + u8_t fsn: 1, + send_last: 1, + pending_req: 1, + sec_update: 1, + pending_buf: 1, + valid: 1, + established: 1; + s32_t poll_to; + u8_t num_elem; + u16_t lpn_counter; + u16_t counter; + + u16_t net_idx; + + u16_t sub_list[FRIEND_SUB_LIST_SIZE]; + + struct k_delayed_work timer; + + struct bt_mesh_friend_seg { + sys_slist_t queue; + } seg[FRIEND_SEG_RX]; + + struct net_buf *last; + + sys_slist_t queue; + u32_t queue_size; + + /* Friend Clear Procedure */ + struct { + u32_t start; /* Clear Procedure start */ + u16_t frnd; /* Previous Friend's address */ + u16_t repeat_sec; /* Repeat timeout in seconds */ + struct k_delayed_work timer; /* Repeat timer */ + } clear; +}; + +#if defined(CONFIG_BLE_MESH_LOW_POWER) +#define LPN_GROUPS CONFIG_BLE_MESH_LPN_GROUPS +#else +#define LPN_GROUPS 0 +#endif + +/* Low Power Node state */ +struct bt_mesh_lpn { + enum __packed { + BLE_MESH_LPN_DISABLED, /* LPN feature is disabled */ + BLE_MESH_LPN_CLEAR, /* Clear in progress */ + BLE_MESH_LPN_TIMER, /* Waiting for auto timer expiry */ + BLE_MESH_LPN_ENABLED, /* LPN enabled, but no Friend */ + BLE_MESH_LPN_REQ_WAIT, /* Wait before scanning for offers */ + BLE_MESH_LPN_WAIT_OFFER, /* Friend Req sent */ + BLE_MESH_LPN_ESTABLISHED, /* Friendship established */ + BLE_MESH_LPN_RECV_DELAY, /* Poll sent, waiting ReceiveDelay */ + BLE_MESH_LPN_WAIT_UPDATE, /* Waiting for Update or message */ + BLE_MESH_LPN_OFFER_RECV, /* Friend offer received */ + } state; + + /* Transaction Number (used for subscription list) */ + u8_t xact_next; + u8_t xact_pending; + u8_t sent_req; + + /* Address of our Friend when we're a LPN. Unassigned if we don't + * have a friend yet. + */ + u16_t frnd; + + /* Value from the friend offer */ + u8_t recv_win; + + u8_t req_attempts; /* Number of Request attempts */ + + s32_t poll_timeout; + + u8_t groups_changed: 1, /* Friend Subscription List needs updating */ + pending_poll: 1, /* Poll to be sent after subscription */ + disable: 1, /* Disable LPN after clearing */ + fsn: 1, /* Friend Sequence Number */ + established: 1, /* Friendship established */ + clear_success: 1; /* Friend Clear Confirm received */ + + /* Friend Queue Size */ + u8_t queue_size; + + /* LPNCounter */ + u16_t counter; + + /* Previous Friend of this LPN */ + u16_t old_friend; + + /* Duration reported for last advertising packet */ + u16_t adv_duration; + + /* Next LPN related action timer */ + struct k_delayed_work timer; + + /* Subscribed groups */ + u16_t groups[LPN_GROUPS]; + + /* Bit fields for tracking which groups the Friend knows about */ + BLE_MESH_ATOMIC_DEFINE(added, LPN_GROUPS); + BLE_MESH_ATOMIC_DEFINE(pending, LPN_GROUPS); + BLE_MESH_ATOMIC_DEFINE(to_remove, LPN_GROUPS); +}; + +/* bt_mesh_net.flags */ +enum { + BLE_MESH_VALID, /* We have been provisioned */ + BLE_MESH_SUSPENDED, /* Network is temporarily suspended */ + BLE_MESH_IVU_IN_PROGRESS, /* IV Update in Progress */ + BLE_MESH_IVU_INITIATOR, /* IV Update initiated by us */ + BLE_MESH_IVU_TEST, /* IV Update test mode */ + BLE_MESH_IVU_PENDING, /* Update blocked by SDU in progress */ + + /* pending storage actions */ + BLE_MESH_RPL_PENDING, + BLE_MESH_KEYS_PENDING, + BLE_MESH_NET_PENDING, + BLE_MESH_IV_PENDING, + BLE_MESH_SEQ_PENDING, + BLE_MESH_HB_PUB_PENDING, + BLE_MESH_CFG_PENDING, + BLE_MESH_MOD_PENDING, + + /* Don't touch - intentionally last */ + BLE_MESH_FLAG_COUNT, +}; + +struct bt_mesh_net { + u32_t iv_index; /* Current IV Index */ + u32_t seq; /* Next outgoing sequence number (24 bits) */ + + BLE_MESH_ATOMIC_DEFINE(flags, BLE_MESH_FLAG_COUNT); + + /* Local network interface */ + struct k_work local_work; + sys_slist_t local_queue; + +#if defined(CONFIG_BLE_MESH_FRIEND) + /* Friend state, unique for each LPN that we're Friends for */ + struct bt_mesh_friend frnd[CONFIG_BLE_MESH_FRIEND_LPN_COUNT]; +#endif + +#if defined(CONFIG_BLE_MESH_LOW_POWER) + struct bt_mesh_lpn lpn; /* Low Power Node state */ +#endif + + /* Number of hours in current IV Update state */ + u8_t ivu_duration; + + /* Timer to track duration in current IV Update state */ + struct k_delayed_work ivu_timer; + + u8_t dev_key[16]; + + struct bt_mesh_app_key app_keys[CONFIG_BLE_MESH_APP_KEY_COUNT]; + + struct bt_mesh_subnet sub[CONFIG_BLE_MESH_SUBNET_COUNT]; + + struct bt_mesh_rpl rpl[CONFIG_BLE_MESH_CRPL]; + +#if defined(CONFIG_BLE_MESH_PROVISIONER) + /* Application keys stored by provisioner */ + struct bt_mesh_app_key *p_app_keys[CONFIG_BLE_MESH_PROVISIONER_APP_KEY_COUNT]; + /* Next app_idx can be assigned */ + u16_t p_app_idx_next; + + /* Network keys stored by provisioner */ + struct bt_mesh_subnet *p_sub[CONFIG_BLE_MESH_PROVISIONER_SUBNET_COUNT]; + /* Next net_idx can be assigned */ + u16_t p_net_idx_next; +#endif +}; + +/* Network interface */ +enum bt_mesh_net_if { + BLE_MESH_NET_IF_ADV, + BLE_MESH_NET_IF_LOCAL, + BLE_MESH_NET_IF_PROXY, + BLE_MESH_NET_IF_PROXY_CFG, +}; + +/* Decoding context for Network/Transport data */ +struct bt_mesh_net_rx { + struct bt_mesh_subnet *sub; + struct bt_mesh_msg_ctx ctx; + u32_t seq; /* Sequence Number */ + u8_t old_iv: 1, /* iv_index - 1 was used */ + new_key: 1, /* Data was encrypted with updated key */ + friend_cred: 1, /* Data was encrypted with friend cred */ + ctl: 1, /* Network Control */ + net_if: 2, /* Network interface */ + local_match: 1, /* Matched a local element */ + friend_match: 1; /* Matched an LPN we're friends for */ + s8_t rssi; +}; + +/* Encoding context for Network/Transport data */ +struct bt_mesh_net_tx { + struct bt_mesh_subnet *sub; + struct bt_mesh_msg_ctx *ctx; + u16_t src; + u8_t xmit; + u8_t friend_cred: 1, + aszmic: 1, + aid: 6; +}; + +extern struct bt_mesh_net bt_mesh; + +#define BLE_MESH_NET_IVI_TX (bt_mesh.iv_index - \ + bt_mesh_atomic_test_bit(bt_mesh.flags, \ + BLE_MESH_IVU_IN_PROGRESS)) +#define BLE_MESH_NET_IVI_RX(rx) (bt_mesh.iv_index - (rx)->old_iv) + +#define BLE_MESH_NET_HDR_LEN 9 + +int bt_mesh_net_keys_create(struct bt_mesh_subnet_keys *keys, + const u8_t key[16]); + +int bt_mesh_net_create(u16_t idx, u8_t flags, const u8_t key[16], + u32_t iv_index); + +u8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub); + +bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, u8_t new_kr, bool new_key); + +void bt_mesh_net_revoke_keys(struct bt_mesh_subnet *sub); + +int bt_mesh_net_beacon_update(struct bt_mesh_subnet *sub); + +void bt_mesh_rpl_reset(void); + +bool bt_mesh_net_iv_update(u32_t iv_index, bool iv_update); + +void bt_mesh_net_sec_update(struct bt_mesh_subnet *sub); + +struct bt_mesh_subnet *bt_mesh_subnet_get(u16_t net_idx); + +struct bt_mesh_subnet *bt_mesh_subnet_find(const u8_t net_id[8], u8_t flags, + u32_t iv_index, const u8_t auth[8], + bool *new_key); + +int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf, + bool proxy); + +int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, + const struct bt_mesh_send_cb *cb, void *cb_data); + +int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf, + bool new_key, const struct bt_mesh_send_cb *cb, + void *cb_data); + +int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, + struct bt_mesh_net_rx *rx, struct net_buf_simple *buf); + +void bt_mesh_net_recv(struct net_buf_simple *data, s8_t rssi, + enum bt_mesh_net_if net_if); + +u32_t bt_mesh_next_seq(void); + +void bt_mesh_net_start(void); + +void bt_mesh_net_init(void); + +/* Friendship Credential Management */ +struct friend_cred { + u16_t net_idx; + u16_t addr; + + u16_t lpn_counter; + u16_t frnd_counter; + + struct { + u8_t nid; /* NID */ + u8_t enc[16]; /* EncKey */ + u8_t privacy[16]; /* PrivacyKey */ + } cred[2]; +}; + +int friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid, + const u8_t **enc, const u8_t **priv); +int friend_cred_set(struct friend_cred *cred, u8_t idx, const u8_t net_key[16]); +void friend_cred_refresh(u16_t net_idx); +int friend_cred_update(struct bt_mesh_subnet *sub); +struct friend_cred *friend_cred_create(struct bt_mesh_subnet *sub, u16_t addr, + u16_t lpn_counter, u16_t frnd_counter); +void friend_cred_clear(struct friend_cred *cred); +int friend_cred_del(u16_t net_idx, u16_t addr); + +#endif /* _NET_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/prov.c b/components/bt/ble_mesh/mesh_core/prov.c new file mode 100644 index 0000000000..0a3329ff65 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/prov.c @@ -0,0 +1,1774 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +#include "sdkconfig.h" +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BLE_MESH_DEBUG_PROV) + +#include "mesh_util.h" +#include "mesh_main.h" +#include "mesh_uuid.h" +#include "mesh_trace.h" +#include "mesh_proxy.h" + +#include "crypto.h" +#include "adv.h" +#include "mesh.h" +#include "net.h" +#include "access.h" +#include "foundation.h" +#include "proxy.h" +#include "prov.h" + +#if CONFIG_BLE_MESH_NODE + +/* 3 transmissions, 20ms interval */ +#define PROV_XMIT BLE_MESH_TRANSMIT(2, 20) + +#define AUTH_METHOD_NO_OOB 0x00 +#define AUTH_METHOD_STATIC 0x01 +#define AUTH_METHOD_OUTPUT 0x02 +#define AUTH_METHOD_INPUT 0x03 + +#define OUTPUT_OOB_BLINK 0x00 +#define OUTPUT_OOB_BEEP 0x01 +#define OUTPUT_OOB_VIBRATE 0x02 +#define OUTPUT_OOB_NUMBER 0x03 +#define OUTPUT_OOB_STRING 0x04 + +#define INPUT_OOB_PUSH 0x00 +#define INPUT_OOB_TWIST 0x01 +#define INPUT_OOB_NUMBER 0x02 +#define INPUT_OOB_STRING 0x03 + +#define PROV_ERR_NONE 0x00 +#define PROV_ERR_NVAL_PDU 0x01 +#define PROV_ERR_NVAL_FMT 0x02 +#define PROV_ERR_UNEXP_PDU 0x03 +#define PROV_ERR_CFM_FAILED 0x04 +#define PROV_ERR_RESOURCES 0x05 +#define PROV_ERR_DECRYPT 0x06 +#define PROV_ERR_UNEXP_ERR 0x07 +#define PROV_ERR_ADDR 0x08 + +#define PROV_INVITE 0x00 +#define PROV_CAPABILITIES 0x01 +#define PROV_START 0x02 +#define PROV_PUB_KEY 0x03 +#define PROV_INPUT_COMPLETE 0x04 +#define PROV_CONFIRM 0x05 +#define PROV_RANDOM 0x06 +#define PROV_DATA 0x07 +#define PROV_COMPLETE 0x08 +#define PROV_FAILED 0x09 + +#define PROV_ALG_P256 0x00 + +#define GPCF(gpc) (gpc & 0x03) +#define GPC_START(last_seg) (((last_seg) << 2) | 0x00) +#define GPC_ACK 0x01 +#define GPC_CONT(seg_id) (((seg_id) << 2) | 0x02) +#define GPC_CTL(op) (((op) << 2) | 0x03) + +#define START_PAYLOAD_MAX 20 +#define CONT_PAYLOAD_MAX 23 + +#define START_LAST_SEG(gpc) (gpc >> 2) +#define CONT_SEG_INDEX(gpc) (gpc >> 2) + +#define BEARER_CTL(gpc) (gpc >> 2) +#define LINK_OPEN 0x00 +#define LINK_ACK 0x01 +#define LINK_CLOSE 0x02 + +#define CLOSE_REASON_SUCCESS 0x00 +#define CLOSE_REASON_TIMEOUT 0x01 +#define CLOSE_REASON_FAILED 0x02 + +#define XACT_SEG_DATA(_seg) (&link.rx.buf->data[20 + ((_seg - 1) * 23)]) +#define XACT_SEG_RECV(_seg) (link.rx.seg &= ~(1 << (_seg))) + +#define XACT_NVAL 0xff + +enum { + REMOTE_PUB_KEY, /* Remote key has been received */ + OOB_PUB_KEY, /* OOB public key is available */ + LINK_ACTIVE, /* Link has been opened */ + HAVE_DHKEY, /* DHKey has been calcualted */ + SEND_CONFIRM, /* Waiting to send Confirm value */ + WAIT_NUMBER, /* Waiting for number input from user */ + WAIT_STRING, /* Waiting for string input from user */ + TIMEOUT_START, /* Provision timeout timer has started */ + + NUM_FLAGS, +}; + +struct prov_link { + BLE_MESH_ATOMIC_DEFINE(flags, NUM_FLAGS); +#if defined(CONFIG_BLE_MESH_PB_GATT) + struct bt_mesh_conn *conn; /* GATT connection */ +#endif + u8_t dhkey[32]; /* Calculated DHKey */ + u8_t expect; /* Next expected PDU */ + + bool oob_pk_flag; /* Flag indicates whether using OOB public key */ + + u8_t oob_method; + u8_t oob_action; + u8_t oob_size; + + u8_t conf[16]; /* Remote Confirmation */ + u8_t rand[16]; /* Local Random */ + u8_t auth[16]; /* Authentication Value */ + + u8_t conf_salt[16]; /* ConfirmationSalt */ + u8_t conf_key[16]; /* ConfirmationKey */ + u8_t conf_inputs[145]; /* ConfirmationInputs */ + u8_t prov_salt[16]; /* Provisioning Salt */ + +#if defined(CONFIG_BLE_MESH_PB_ADV) + u32_t id; /* Link ID */ + u8_t tx_pdu_type; /* The previously transmitted Provisioning PDU type */ + + struct { + u8_t id; /* Transaction ID */ + u8_t prev_id; /* Previous Transaction ID */ + u8_t seg; /* Bit-field of unreceived segments */ + u8_t last_seg; /* Last segment (to check length) */ + u8_t fcs; /* Expected FCS value */ + struct net_buf_simple *buf; + } rx; + + struct { + /* Start timestamp of the transaction */ + s64_t start; + + /* Transaction id*/ + u8_t id; + + /* Pending outgoing buffer(s) */ + struct net_buf *buf[3]; + + /* Retransmit timer */ + struct k_delayed_work retransmit; + } tx; +#endif + + /* Provision timeout timer */ + struct k_delayed_work timeout; +}; + +struct prov_rx { + u32_t link_id; + u8_t xact_id; + u8_t gpc; +}; + +#define BUF_TIMEOUT K_MSEC(400) + +#if defined(CONFIG_BLE_MESH_FAST_PROV) +#define RETRANSMIT_TIMEOUT K_MSEC(360) +#define TRANSACTION_TIMEOUT K_SECONDS(3) +#define PROVISION_TIMEOUT K_SECONDS(6) +#else +#define RETRANSMIT_TIMEOUT K_MSEC(500) +#define TRANSACTION_TIMEOUT K_SECONDS(30) +#define PROVISION_TIMEOUT K_SECONDS(60) +#endif /* CONFIG_BLE_MESH_FAST_PROV */ + +#if defined(CONFIG_BLE_MESH_PB_GATT) +#define PROV_BUF_HEADROOM 5 +#else +#define PROV_BUF_HEADROOM 0 +NET_BUF_SIMPLE_DEFINE_STATIC(rx_buf, 65); +#endif + +#define PROV_BUF(name, len) \ + NET_BUF_SIMPLE_DEFINE(name, PROV_BUF_HEADROOM + len) + +static struct prov_link link; + +static const struct bt_mesh_prov *prov; + +static void close_link(u8_t err, u8_t reason); + +static void reset_state(void) +{ + /* Disable Attention Timer if it was set */ + if (link.conf_inputs[0]) { + bt_mesh_attention(NULL, 0); + } + +#if defined(CONFIG_BLE_MESH_PB_GATT) + if (link.conn) { + bt_mesh_conn_unref(link.conn); + } +#endif + +#if defined(CONFIG_BLE_MESH_PB_ADV) + /* Clear everything except the retransmit delayed work config */ + (void)memset(&link, 0, offsetof(struct prov_link, tx.retransmit)); + link.rx.prev_id = XACT_NVAL; + +#if defined(CONFIG_BLE_MESH_PB_GATT) + link.rx.buf = bt_mesh_proxy_get_buf(); +#else + net_buf_simple_reset(&rx_buf); + link.rx.buf = &rx_buf; +#endif /* PB_GATT */ + +#else + (void)memset(&link, 0, offsetof(struct prov_link, timeout)); +#endif /* PB_ADV */ +} + +#if defined(CONFIG_BLE_MESH_PB_ADV) +static void buf_sent(int err, void *user_data) +{ + if (!link.tx.buf[0]) { + return; + } + + k_delayed_work_submit(&link.tx.retransmit, RETRANSMIT_TIMEOUT); +} + +static struct bt_mesh_send_cb buf_sent_cb = { + .end = buf_sent, +}; + +static void free_segments(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) { + struct net_buf *buf = link.tx.buf[i]; + + if (!buf) { + break; + } + + link.tx.buf[i] = NULL; + /* Mark as canceled */ + BLE_MESH_ADV(buf)->busy = 0U; + /** Changed by Espressif. Add this to avoid buf->ref is 2 which will + * cause lack of buf. + */ + if (buf->ref > 1) { + buf->ref = 1; + } + net_buf_unref(buf); + } +} + +static void prov_clear_tx(void) +{ + BT_DBG("%s", __func__); + + k_delayed_work_cancel(&link.tx.retransmit); + + free_segments(); +} + +static void reset_link(void) +{ + prov_clear_tx(); + + if (bt_mesh_atomic_test_and_clear_bit(link.flags, TIMEOUT_START)) { + k_delayed_work_cancel(&link.timeout); + } + + if (prov->link_close) { + prov->link_close(BLE_MESH_PROV_ADV); + } + +#if defined(CONFIG_BLE_MESH_USE_DUPLICATE_SCAN) + /* Remove the link id from exceptional list */ + bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_REMOVE, + BLE_MESH_EXCEP_INFO_MESH_LINK_ID, &link.id); +#endif + + reset_state(); +} + +static struct net_buf *adv_buf_create(void) +{ + struct net_buf *buf; + + buf = bt_mesh_adv_create(BLE_MESH_ADV_PROV, PROV_XMIT, BUF_TIMEOUT); + if (!buf) { + BT_ERR("%s, Out of provisioning buffers", __func__); + return NULL; + } + + return buf; +} + +static u8_t pending_ack = XACT_NVAL; + +static void ack_complete(u16_t duration, int err, void *user_data) +{ + BT_DBG("xact %u complete", (u8_t)pending_ack); + pending_ack = XACT_NVAL; +} + +static void gen_prov_ack_send(u8_t xact_id) +{ + static const struct bt_mesh_send_cb cb = { + .start = ack_complete, + }; + const struct bt_mesh_send_cb *complete; + struct net_buf *buf; + + BT_DBG("xact_id %u", xact_id); + + if (pending_ack == xact_id) { + BT_DBG("Not sending duplicate ack"); + return; + } + + buf = adv_buf_create(); + if (!buf) { + return; + } + + if (pending_ack == XACT_NVAL) { + pending_ack = xact_id; + complete = &cb; + } else { + complete = NULL; + } + + net_buf_add_be32(buf, link.id); + net_buf_add_u8(buf, xact_id); + net_buf_add_u8(buf, GPC_ACK); + + bt_mesh_adv_send(buf, complete, NULL); + net_buf_unref(buf); +} + +static void send_reliable(void) +{ + int i; + + link.tx.start = k_uptime_get(); + + for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) { + struct net_buf *buf = link.tx.buf[i]; + + if (!buf) { + break; + } + + if (i + 1 < ARRAY_SIZE(link.tx.buf) && link.tx.buf[i + 1]) { + bt_mesh_adv_send(buf, NULL, NULL); + } else { + bt_mesh_adv_send(buf, &buf_sent_cb, NULL); + } + } +} + +static int bearer_ctl_send(u8_t op, void *data, u8_t data_len) +{ + struct net_buf *buf; + + BT_DBG("op 0x%02x data_len %u", op, data_len); + + prov_clear_tx(); + + buf = adv_buf_create(); + if (!buf) { + return -ENOBUFS; + } + + net_buf_add_be32(buf, link.id); + /* Transaction ID, always 0 for Bearer messages */ + net_buf_add_u8(buf, 0x00); + net_buf_add_u8(buf, GPC_CTL(op)); + net_buf_add_mem(buf, data, data_len); + + link.tx.buf[0] = buf; + send_reliable(); + + return 0; +} + +static u8_t last_seg(u8_t len) +{ + if (len <= START_PAYLOAD_MAX) { + return 0; + } + + len -= START_PAYLOAD_MAX; + + return 1 + (len / CONT_PAYLOAD_MAX); +} + +static inline u8_t next_transaction_id(void) +{ + if (link.tx.id != 0U && link.tx.id != 0xFF) { + return ++link.tx.id; + } + + link.tx.id = 0x80; + return link.tx.id; +} + +static int prov_send_adv(struct net_buf_simple *msg) +{ + struct net_buf *start, *buf; + u8_t seg_len, seg_id; + u8_t xact_id; + s32_t timeout = PROVISION_TIMEOUT; + + BT_DBG("%s, len %u: %s", __func__, msg->len, bt_hex(msg->data, msg->len)); + + prov_clear_tx(); + + start = adv_buf_create(); + if (!start) { + return -ENOBUFS; + } + + xact_id = next_transaction_id(); + net_buf_add_be32(start, link.id); + net_buf_add_u8(start, xact_id); + + net_buf_add_u8(start, GPC_START(last_seg(msg->len))); + net_buf_add_be16(start, msg->len); + net_buf_add_u8(start, bt_mesh_fcs_calc(msg->data, msg->len)); + + link.tx.buf[0] = start; + /* Changed by Espressif, get message type */ + link.tx_pdu_type = msg->data[0]; + + seg_len = MIN(msg->len, START_PAYLOAD_MAX); + BT_DBG("seg 0 len %u: %s", seg_len, bt_hex(msg->data, seg_len)); + net_buf_add_mem(start, msg->data, seg_len); + net_buf_simple_pull(msg, seg_len); + + buf = start; + for (seg_id = 1U; msg->len > 0; seg_id++) { + if (seg_id >= ARRAY_SIZE(link.tx.buf)) { + BT_ERR("%s, Too big message", __func__); + free_segments(); + return -E2BIG; + } + + buf = adv_buf_create(); + if (!buf) { + free_segments(); + return -ENOBUFS; + } + + link.tx.buf[seg_id] = buf; + + seg_len = MIN(msg->len, CONT_PAYLOAD_MAX); + + BT_DBG("seg_id %u len %u: %s", seg_id, seg_len, + bt_hex(msg->data, seg_len)); + + net_buf_add_be32(buf, link.id); + net_buf_add_u8(buf, xact_id); + net_buf_add_u8(buf, GPC_CONT(seg_id)); + net_buf_add_mem(buf, msg->data, seg_len); + net_buf_simple_pull(msg, seg_len); + } + + send_reliable(); + + /* Changed by Espressif, add provisioning timeout timer operations. + * When sending a provisioning PDU successfully, restart the 60s timer. + */ + if (bt_mesh_atomic_test_and_clear_bit(link.flags, TIMEOUT_START)) { + k_delayed_work_cancel(&link.timeout); + } +#if defined(CONFIG_BLE_MESH_FAST_PROV) + if (link.tx_pdu_type >= PROV_COMPLETE) { + timeout = K_SECONDS(60); + } +#endif + if (!bt_mesh_atomic_test_and_set_bit(link.flags, TIMEOUT_START)) { + k_delayed_work_submit(&link.timeout, timeout); + } + + return 0; +} + +#endif /* CONFIG_BLE_MESH_PB_ADV */ + +#if defined(CONFIG_BLE_MESH_PB_GATT) +static int prov_send_gatt(struct net_buf_simple *msg) +{ + int err = 0; + + if (!link.conn) { + return -ENOTCONN; + } + + /* Changed by Espressif, add provisioning timeout timer operations. + * When sending a provisioning PDU successfully, restart the 60s timer. + */ + err = bt_mesh_proxy_send(link.conn, BLE_MESH_PROXY_PROV, msg); + if (err) { + BT_ERR("%s, Failed to send provisioning PDU", __func__); + return err; + } + + if (bt_mesh_atomic_test_and_clear_bit(link.flags, TIMEOUT_START)) { + k_delayed_work_cancel(&link.timeout); + } + if (msg->data[1] != PROV_COMPLETE && msg->data[1] != PROV_FAILED) { + if (!bt_mesh_atomic_test_and_set_bit(link.flags, TIMEOUT_START)) { + k_delayed_work_submit(&link.timeout, PROVISION_TIMEOUT); + } + } + + return 0; +} +#endif /* CONFIG_BLE_MESH_PB_GATT */ + +static inline int prov_send(struct net_buf_simple *buf) +{ +#if defined(CONFIG_BLE_MESH_PB_GATT) + if (link.conn) { + return prov_send_gatt(buf); + } +#endif +#if defined(CONFIG_BLE_MESH_PB_ADV) + return prov_send_adv(buf); +#else + return 0; +#endif +} + +static void prov_buf_init(struct net_buf_simple *buf, u8_t type) +{ + net_buf_simple_reserve(buf, PROV_BUF_HEADROOM); + net_buf_simple_add_u8(buf, type); +} + +static void prov_send_fail_msg(u8_t err) +{ + PROV_BUF(buf, 2); + + prov_buf_init(&buf, PROV_FAILED); + net_buf_simple_add_u8(&buf, err); + prov_send(&buf); +} + +static void prov_invite(const u8_t *data) +{ + PROV_BUF(buf, 12); + + BT_DBG("Attention Duration: %u seconds", data[0]); + + if (data[0]) { + bt_mesh_attention(NULL, data[0]); + } + + link.conf_inputs[0] = data[0]; + + prov_buf_init(&buf, PROV_CAPABILITIES); + + /* Number of Elements supported */ + net_buf_simple_add_u8(&buf, bt_mesh_elem_count()); + + /* Supported algorithms - FIPS P-256 Eliptic Curve */ + net_buf_simple_add_be16(&buf, BIT(PROV_ALG_P256)); + + /* Public Key Type */ + net_buf_simple_add_u8(&buf, prov->oob_pub_key); + + /* Static OOB Type */ + net_buf_simple_add_u8(&buf, prov->static_val ? BIT(0) : 0x00); + + /* Output OOB Size */ + net_buf_simple_add_u8(&buf, prov->output_size); + + /* Output OOB Action */ + net_buf_simple_add_be16(&buf, prov->output_actions); + + /* Input OOB Size */ + net_buf_simple_add_u8(&buf, prov->input_size); + + /* Input OOB Action */ + net_buf_simple_add_be16(&buf, prov->input_actions); + + memcpy(&link.conf_inputs[1], &buf.data[1], 11); + + if (prov_send(&buf)) { + BT_ERR("%s, Failed to send capabilities", __func__); + close_link(PROV_ERR_RESOURCES, CLOSE_REASON_FAILED); + return; + } + + link.expect = PROV_START; +} + +static void prov_capabilities(const u8_t *data) +{ + u16_t algorithms, output_action, input_action; + + BT_DBG("Elements: %u", data[0]); + + algorithms = sys_get_be16(&data[1]); + BT_DBG("Algorithms: %u", algorithms); + + BT_DBG("Public Key Type: 0x%02x", data[3]); + BT_DBG("Static OOB Type: 0x%02x", data[4]); + BT_DBG("Output OOB Size: %u", data[5]); + + output_action = sys_get_be16(&data[6]); + BT_DBG("Output OOB Action: 0x%04x", output_action); + + BT_DBG("Input OOB Size: %u", data[8]); + + input_action = sys_get_be16(&data[9]); + BT_DBG("Input OOB Action: 0x%04x", input_action); +} + +static bt_mesh_output_action_t output_action(u8_t action) +{ + switch (action) { + case OUTPUT_OOB_BLINK: + return BLE_MESH_BLINK; + case OUTPUT_OOB_BEEP: + return BLE_MESH_BEEP; + case OUTPUT_OOB_VIBRATE: + return BLE_MESH_VIBRATE; + case OUTPUT_OOB_NUMBER: + return BLE_MESH_DISPLAY_NUMBER; + case OUTPUT_OOB_STRING: + return BLE_MESH_DISPLAY_STRING; + default: + return BLE_MESH_NO_OUTPUT; + } +} + +static bt_mesh_input_action_t input_action(u8_t action) +{ + switch (action) { + case INPUT_OOB_PUSH: + return BLE_MESH_PUSH; + case INPUT_OOB_TWIST: + return BLE_MESH_TWIST; + case INPUT_OOB_NUMBER: + return BLE_MESH_ENTER_NUMBER; + case INPUT_OOB_STRING: + return BLE_MESH_ENTER_STRING; + default: + return BLE_MESH_NO_INPUT; + } +} + +static int prov_auth(u8_t method, u8_t action, u8_t size) +{ + bt_mesh_output_action_t output; + bt_mesh_input_action_t input; + + switch (method) { + case AUTH_METHOD_NO_OOB: + if (action || size) { + return -EINVAL; + } + + (void)memset(link.auth, 0, sizeof(link.auth)); + return 0; + case AUTH_METHOD_STATIC: + if (action || size) { + return -EINVAL; + } + + memcpy(link.auth + 16 - prov->static_val_len, + prov->static_val, prov->static_val_len); + (void)memset(link.auth, 0, + sizeof(link.auth) - prov->static_val_len); + return 0; + + case AUTH_METHOD_OUTPUT: + output = output_action(action); + if (!output) { + return -EINVAL; + } + + if (!(prov->output_actions & output)) { + return -EINVAL; + } + + if (size > prov->output_size) { + return -EINVAL; + } + + if (output == BLE_MESH_DISPLAY_STRING) { + unsigned char str[9]; + u8_t i; + + bt_mesh_rand(str, size); + + /* Normalize to '0' .. '9' & 'A' .. 'Z' */ + for (i = 0U; i < size; i++) { + str[i] %= 36; + if (str[i] < 10) { + str[i] += '0'; + } else { + str[i] += 'A' - 10; + } + } + str[size] = '\0'; + + memcpy(link.auth, str, size); + (void)memset(link.auth + size, 0, + sizeof(link.auth) - size); + + return prov->output_string((char *)str); + } else { + u32_t div[8] = { 10, 100, 1000, 10000, 100000, + 1000000, 10000000, 100000000 + }; + u32_t num; + + bt_mesh_rand(&num, sizeof(num)); + num %= div[size - 1]; + + sys_put_be32(num, &link.auth[12]); + (void)memset(link.auth, 0, 12); + + return prov->output_number(output, num); + } + + case AUTH_METHOD_INPUT: + input = input_action(action); + if (!input) { + return -EINVAL; + } + + if (!(prov->input_actions & input)) { + return -EINVAL; + } + + if (size > prov->input_size) { + return -EINVAL; + } + + if (input == BLE_MESH_ENTER_STRING) { + bt_mesh_atomic_set_bit(link.flags, WAIT_STRING); + } else { + bt_mesh_atomic_set_bit(link.flags, WAIT_NUMBER); + } + + return prov->input(input, size); + + default: + return -EINVAL; + } +} + +static void prov_start(const u8_t *data) +{ + BT_DBG("Algorithm: 0x%02x", data[0]); + BT_DBG("Public Key: 0x%02x", data[1]); + BT_DBG("Auth Method: 0x%02x", data[2]); + BT_DBG("Auth Action: 0x%02x", data[3]); + BT_DBG("Auth Size: 0x%02x", data[4]); + + if (data[0] != PROV_ALG_P256) { + BT_ERR("%s, Unknown algorithm 0x%02x", __func__, data[0]); + prov_send_fail_msg(PROV_ERR_NVAL_FMT); + return; + } + + if (data[1] > 0x01) { + BT_ERR("%s, Invalid public key value: 0x%02x", __func__, data[1]); + prov_send_fail_msg(PROV_ERR_NVAL_FMT); + return; + } + + memcpy(&link.conf_inputs[12], data, 5); + + link.expect = PROV_PUB_KEY; + + /* If Provisioning Start PDU indicates that provisioner chooses + * OOB public key, then callback to the application layer to let + * users input public & private key pair. + */ + link.oob_pk_flag = data[1] ? true : false; + if (link.oob_pk_flag) { + prov->oob_pub_key_cb(); + } + + if (prov_auth(data[2], data[3], data[4]) < 0) { + BT_ERR("%s, Invalid authentication method: 0x%02x; " + "action: 0x%02x; size: 0x%02x", + __func__, data[2], data[3], data[4]); + prov_send_fail_msg(PROV_ERR_NVAL_FMT); + } +} + +static void send_confirm(void) +{ + PROV_BUF(cfm, 17); + + BT_DBG("ConfInputs[0] %s", bt_hex(link.conf_inputs, 64)); + BT_DBG("ConfInputs[64] %s", bt_hex(&link.conf_inputs[64], 64)); + BT_DBG("ConfInputs[128] %s", bt_hex(&link.conf_inputs[128], 17)); + + if (bt_mesh_prov_conf_salt(link.conf_inputs, link.conf_salt)) { + BT_ERR("%s, Unable to generate confirmation salt", __func__); + close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + return; + } + + BT_DBG("ConfirmationSalt: %s", bt_hex(link.conf_salt, 16)); + + if (bt_mesh_prov_conf_key(link.dhkey, link.conf_salt, link.conf_key)) { + BT_ERR("%s, Unable to generate confirmation key", __func__); + close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + return; + } + + BT_DBG("ConfirmationKey: %s", bt_hex(link.conf_key, 16)); + + if (bt_mesh_rand(link.rand, 16)) { + BT_ERR("%s, Unable to generate random number", __func__); + close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + return; + } + + BT_DBG("LocalRandom: %s", bt_hex(link.rand, 16)); + + prov_buf_init(&cfm, PROV_CONFIRM); + + if (bt_mesh_prov_conf(link.conf_key, link.rand, link.auth, + net_buf_simple_add(&cfm, 16))) { + BT_ERR("%s, Unable to generate confirmation value", __func__); + close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + return; + } + + if (prov_send(&cfm)) { + BT_ERR("%s, Unable to send Provisioning Confirm", __func__); + close_link(PROV_ERR_RESOURCES, CLOSE_REASON_FAILED); + return; + } + + link.expect = PROV_RANDOM; +} + +static void send_input_complete(void) +{ + PROV_BUF(buf, 1); + + prov_buf_init(&buf, PROV_INPUT_COMPLETE); + prov_send(&buf); +} + +int bt_mesh_input_number(u32_t num) +{ + BT_DBG("%u", num); + + if (!bt_mesh_atomic_test_and_clear_bit(link.flags, WAIT_NUMBER)) { + return -EINVAL; + } + + sys_put_be32(num, &link.auth[12]); + + send_input_complete(); + + if (!bt_mesh_atomic_test_bit(link.flags, HAVE_DHKEY)) { + return 0; + } + + if (bt_mesh_atomic_test_and_clear_bit(link.flags, SEND_CONFIRM)) { + send_confirm(); + } + + return 0; +} + +int bt_mesh_input_string(const char *str) +{ + BT_DBG("%s", str); + + if (!bt_mesh_atomic_test_and_clear_bit(link.flags, WAIT_STRING)) { + return -EINVAL; + } + + (void)memcpy(link.auth, str, prov->input_size); + + send_input_complete(); + + if (!bt_mesh_atomic_test_bit(link.flags, HAVE_DHKEY)) { + return 0; + } + + if (bt_mesh_atomic_test_and_clear_bit(link.flags, SEND_CONFIRM)) { + send_confirm(); + } + + return 0; +} + +static void prov_dh_key_cb(const u8_t key[32], const u8_t idx) +{ + BT_DBG("%p", key); + + if (!key) { + BT_ERR("%s, DHKey generation failed", __func__); + close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + return; + } + + sys_memcpy_swap(link.dhkey, key, 32); + + BT_DBG("DHkey: %s", bt_hex(link.dhkey, 32)); + + bt_mesh_atomic_set_bit(link.flags, HAVE_DHKEY); + + if (bt_mesh_atomic_test_bit(link.flags, WAIT_NUMBER) || + bt_mesh_atomic_test_bit(link.flags, WAIT_STRING)) { + return; + } + + if (bt_mesh_atomic_test_and_clear_bit(link.flags, SEND_CONFIRM)) { + send_confirm(); + } +} + +static void send_pub_key(void) +{ + PROV_BUF(buf, 65); + const u8_t *key; + + key = bt_mesh_pub_key_get(); + if (!key) { + BT_ERR("%s, No public key available", __func__); + close_link(PROV_ERR_RESOURCES, CLOSE_REASON_FAILED); + return; + } + + BT_DBG("Local Public Key: %s", bt_hex(key, 64)); + + prov_buf_init(&buf, PROV_PUB_KEY); + + /* Swap X and Y halves independently to big-endian */ + sys_memcpy_swap(net_buf_simple_add(&buf, 32), key, 32); + sys_memcpy_swap(net_buf_simple_add(&buf, 32), &key[32], 32); + + memcpy(&link.conf_inputs[81], &buf.data[1], 64); + + prov_send(&buf); + + /* Copy remote key in little-endian for bt_mesh_dh_key_gen(). + * X and Y halves are swapped independently. + */ + net_buf_simple_reset(&buf); + sys_memcpy_swap(buf.data, &link.conf_inputs[17], 32); + sys_memcpy_swap(&buf.data[32], &link.conf_inputs[49], 32); + + if (bt_mesh_dh_key_gen(buf.data, prov_dh_key_cb, 0)) { + BT_ERR("%s, Unable to generate DHKey", __func__); + close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + return; + } + + link.expect = PROV_CONFIRM; +} + +static int bt_mesh_calc_dh_key(void) +{ + NET_BUF_SIMPLE_DEFINE(buf, 64); + + /* Copy remote key in little-endian for bt_mesh_dh_key_gen(). + * X and Y halves are swapped independently. + */ + net_buf_simple_reset(&buf); + sys_memcpy_swap(buf.data, &link.conf_inputs[17], 32); + sys_memcpy_swap(&buf.data[32], &link.conf_inputs[49], 32); + + if (bt_mesh_dh_key_gen(buf.data, prov_dh_key_cb, 0)) { + BT_ERR("%s, Unable to generate DHKey", __func__); + close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + return -EIO; + } + + return 0; +} + +int bt_mesh_set_oob_pub_key(const u8_t pub_key_x[32], const u8_t pub_key_y[32], + const u8_t pri_key[32]) +{ + if (!pub_key_x || !pub_key_y || !pri_key) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + /* Copy OOB public key in big-endian to Provisioning ConfirmationInputs, + * X and Y halves are swapped independently. + * And set input private key to mesh_bearer_adapt.c + */ + sys_memcpy_swap(&link.conf_inputs[81], pub_key_x, 32); + sys_memcpy_swap(&link.conf_inputs[81] + 32, pub_key_y, 32); + bt_mesh_set_private_key(pri_key); + + bt_mesh_atomic_set_bit(link.flags, OOB_PUB_KEY); + + /* If remote public key is not got, just return */ + if (!bt_mesh_atomic_test_bit(link.flags, REMOTE_PUB_KEY)) { + return 0; + } + + return bt_mesh_calc_dh_key(); +} + +static void prov_pub_key(const u8_t *data) +{ + BT_DBG("Remote Public Key: %s", bt_hex(data, 64)); + + /* BLE Mesh BQB test case MESH/NODE/PROV/UPD/BI-13-C needs to + * check the public key using the following rules: + * (1) X > 0, Y > 0 + * (2) X > 0, Y = 0 + * (3) X = 0, Y = 0 + */ + if (!bt_mesh_check_public_key(data)) { + BT_ERR("%s, Invalid public key", __func__); + prov_send_fail_msg(PROV_ERR_UNEXP_PDU); + return; + } + + memcpy(&link.conf_inputs[17], data, 64); + bt_mesh_atomic_set_bit(link.flags, REMOTE_PUB_KEY); + + if (!bt_mesh_pub_key_get()) { + /* Clear retransmit timer */ +#if defined(CONFIG_BLE_MESH_PB_ADV) + prov_clear_tx(); +#endif + BT_WARN("Waiting for a local public key"); + return; + } + + if (!link.oob_pk_flag) { + send_pub_key(); + } else { + link.expect = PROV_CONFIRM; + } +} + +static void prov_input_complete(const u8_t *data) +{ + BT_DBG("%s", __func__); +} + +static void prov_confirm(const u8_t *data) +{ + BT_DBG("Remote Confirm: %s", bt_hex(data, 16)); + + memcpy(link.conf, data, 16); + + if (!bt_mesh_atomic_test_bit(link.flags, HAVE_DHKEY)) { +#if defined(CONFIG_BLE_MESH_PB_ADV) + prov_clear_tx(); +#endif + bt_mesh_atomic_set_bit(link.flags, SEND_CONFIRM); + /* If using OOB public key and it has already got, calculates dhkey */ + if (link.oob_pk_flag && bt_mesh_atomic_test_bit(link.flags, OOB_PUB_KEY)) { + bt_mesh_calc_dh_key(); + } + } else { + send_confirm(); + } +} + +static void prov_random(const u8_t *data) +{ + PROV_BUF(rnd, 17); + u8_t conf_verify[16]; + + BT_DBG("Remote Random: %s", bt_hex(data, 16)); + + if (bt_mesh_prov_conf(link.conf_key, data, link.auth, conf_verify)) { + BT_ERR("%s, Unable to calculate confirmation verification", __func__); + close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + return; + } + + if (memcmp(conf_verify, link.conf, 16)) { + BT_ERR("%s, Invalid confirmation value", __func__); + BT_DBG("Received: %s", bt_hex(link.conf, 16)); + BT_DBG("Calculated: %s", bt_hex(conf_verify, 16)); + close_link(PROV_ERR_CFM_FAILED, CLOSE_REASON_FAILED); + return; + } + + prov_buf_init(&rnd, PROV_RANDOM); + net_buf_simple_add_mem(&rnd, link.rand, 16); + + if (prov_send(&rnd)) { + BT_ERR("%s, Failed to send Provisioning Random", __func__); + close_link(PROV_ERR_RESOURCES, CLOSE_REASON_FAILED); + return; + } + + if (bt_mesh_prov_salt(link.conf_salt, data, link.rand, + link.prov_salt)) { + BT_ERR("%s, Failed to generate provisioning salt", __func__); + close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + return; + } + + BT_DBG("ProvisioningSalt: %s", bt_hex(link.prov_salt, 16)); + + link.expect = PROV_DATA; +} + +static inline bool is_pb_gatt(void) +{ +#if defined(CONFIG_BLE_MESH_PB_GATT) + return !!link.conn; +#else + return false; +#endif +} + +static void prov_data(const u8_t *data) +{ + PROV_BUF(msg, 1); + u8_t session_key[16]; + u8_t nonce[13]; + u8_t dev_key[16]; + u8_t pdu[25]; + u8_t flags; + u32_t iv_index; + u16_t addr; + u16_t net_idx; + int err; + bool identity_enable; + + BT_DBG("%s", __func__); + + err = bt_mesh_session_key(link.dhkey, link.prov_salt, session_key); + if (err) { + BT_ERR("%s, Unable to generate session key", __func__); + close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + return; + } + + BT_DBG("SessionKey: %s", bt_hex(session_key, 16)); + + err = bt_mesh_prov_nonce(link.dhkey, link.prov_salt, nonce); + if (err) { + BT_ERR("%s, Unable to generate session nonce", __func__); + close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + return; + } + + BT_DBG("Nonce: %s", bt_hex(nonce, 13)); + + err = bt_mesh_prov_decrypt(session_key, nonce, data, pdu); + if (err) { + BT_ERR("%s, Unable to decrypt provisioning data", __func__); + close_link(PROV_ERR_DECRYPT, CLOSE_REASON_FAILED); + return; + } + + err = bt_mesh_dev_key(link.dhkey, link.prov_salt, dev_key); + if (err) { + BT_ERR("%s, Unable to generate device key", __func__); + close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + return; + } + + BT_DBG("DevKey: %s", bt_hex(dev_key, 16)); + + net_idx = sys_get_be16(&pdu[16]); + flags = pdu[18]; + iv_index = sys_get_be32(&pdu[19]); + addr = sys_get_be16(&pdu[23]); + + BT_DBG("net_idx %u iv_index 0x%08x, addr 0x%04x", + net_idx, iv_index, addr); + + prov_buf_init(&msg, PROV_COMPLETE); + prov_send(&msg); + + /* Ignore any further PDUs on this link */ + link.expect = 0U; + + /* Store info, since bt_mesh_provision() will end up clearing it */ + if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY)) { + identity_enable = is_pb_gatt(); + } else { + identity_enable = false; + } + + err = bt_mesh_provision(pdu, net_idx, flags, iv_index, addr, dev_key); + if (err) { + BT_ERR("Failed to provision (err %d)", err); + return; + } + + /* After PB-GATT provisioning we should start advertising + * using Node Identity. + */ + if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY) && identity_enable) { + bt_mesh_proxy_identity_enable(); + } +} + +static void prov_complete(const u8_t *data) +{ + BT_DBG("%s", __func__); +} + +static void prov_failed(const u8_t *data) +{ + BT_WARN("Error: 0x%02x", data[0]); +} + +static const struct { + void (*func)(const u8_t *data); + u16_t len; +} prov_handlers[] = { + { prov_invite, 1 }, + { prov_capabilities, 11 }, + { prov_start, 5, }, + { prov_pub_key, 64 }, + { prov_input_complete, 0 }, + { prov_confirm, 16 }, + { prov_random, 16 }, + { prov_data, 33 }, + { prov_complete, 0 }, + { prov_failed, 1 }, +}; + +static void close_link(u8_t err, u8_t reason) +{ +#if defined(CONFIG_BLE_MESH_PB_GATT) + if (link.conn) { + bt_mesh_pb_gatt_close(link.conn); + return; + } +#endif + +#if defined(CONFIG_BLE_MESH_PB_ADV) + if (err) { + prov_send_fail_msg(err); + } + + link.rx.seg = 0U; + bearer_ctl_send(LINK_CLOSE, &reason, sizeof(reason)); +#endif + + reset_state(); +} + +/* Changed by Espressif, add provisioning timeout timer callback */ +static void prov_timeout(struct k_work *work) +{ + BT_DBG("%s", __func__); + + close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_TIMEOUT); +} + +#if defined(CONFIG_BLE_MESH_PB_ADV) +static void prov_retransmit(struct k_work *work) +{ + s64_t timeout = TRANSACTION_TIMEOUT; + int i; + + BT_DBG("%s", __func__); + + if (!bt_mesh_atomic_test_bit(link.flags, LINK_ACTIVE)) { + BT_WARN("Link not active"); + return; + } + +#if defined(CONFIG_BLE_MESH_FAST_PROV) + /* When Provisioning Failed PDU is sent, 3s may be used here. */ + if (link.tx_pdu_type >= PROV_COMPLETE) { + timeout = K_SECONDS(30); + } +#endif + if (k_uptime_get() - link.tx.start > timeout) { + BT_WARN("Node timeout, giving up transaction"); + reset_link(); + return; + } + + for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) { + struct net_buf *buf = link.tx.buf[i]; + + if (!buf) { + break; + } + + if (BLE_MESH_ADV(buf)->busy) { + continue; + } + + BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); + + if (i + 1 < ARRAY_SIZE(link.tx.buf) && link.tx.buf[i + 1]) { + bt_mesh_adv_send(buf, NULL, NULL); + } else { + bt_mesh_adv_send(buf, &buf_sent_cb, NULL); + } + + } +} + +static void link_open(struct prov_rx *rx, struct net_buf_simple *buf) +{ + BT_DBG("len %u", buf->len); + + if (buf->len < 16) { + BT_ERR("%s, Too short bearer open message (len %u)", __func__, buf->len); + return; + } + + if (bt_mesh_atomic_test_bit(link.flags, LINK_ACTIVE)) { + /* Send another link ack if the provisioner missed the last */ + if (link.id == rx->link_id && link.expect == PROV_INVITE) { + BT_DBG("Resending link ack"); + bearer_ctl_send(LINK_ACK, NULL, 0); + } else { + BT_WARN("Ignoring bearer open: link already active"); + } + + return; + } + + if (memcmp(buf->data, prov->uuid, 16)) { + BT_DBG("Bearer open message not for us"); + return; + } + + if (prov->link_open) { + prov->link_open(BLE_MESH_PROV_ADV); + } + + link.id = rx->link_id; + bt_mesh_atomic_set_bit(link.flags, LINK_ACTIVE); + net_buf_simple_reset(link.rx.buf); + +#if defined(CONFIG_BLE_MESH_USE_DUPLICATE_SCAN) + /* Add the link id into exceptional list */ + bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_ADD, + BLE_MESH_EXCEP_INFO_MESH_LINK_ID, &link.id); +#endif + + bearer_ctl_send(LINK_ACK, NULL, 0); + + link.expect = PROV_INVITE; +} + +static void link_ack(struct prov_rx *rx, struct net_buf_simple *buf) +{ + BT_DBG("len %u", buf->len); +} + +static void link_close(struct prov_rx *rx, struct net_buf_simple *buf) +{ + BT_DBG("len %u", buf->len); + + reset_link(); +} + +static void gen_prov_ctl(struct prov_rx *rx, struct net_buf_simple *buf) +{ + BT_DBG("op 0x%02x len %u", BEARER_CTL(rx->gpc), buf->len); + + switch (BEARER_CTL(rx->gpc)) { + case LINK_OPEN: + link_open(rx, buf); + break; + case LINK_ACK: + if (!bt_mesh_atomic_test_bit(link.flags, LINK_ACTIVE)) { + return; + } + + link_ack(rx, buf); + break; + case LINK_CLOSE: + if (!bt_mesh_atomic_test_bit(link.flags, LINK_ACTIVE)) { + return; + } + + link_close(rx, buf); + break; + default: + BT_ERR("%s, Unknown bearer opcode: 0x%02x", __func__, BEARER_CTL(rx->gpc)); + return; + } +} + +static void prov_msg_recv(void) +{ + u8_t type = link.rx.buf->data[0]; + + BT_DBG("type 0x%02x len %u", type, link.rx.buf->len); + + if (!bt_mesh_fcs_check(link.rx.buf, link.rx.fcs)) { + BT_ERR("%s, Incorrect FCS", __func__); + return; + } + + gen_prov_ack_send(link.rx.id); + link.rx.prev_id = link.rx.id; + link.rx.id = 0U; + + if (type != PROV_FAILED && type != link.expect) { + BT_WARN("Unexpected msg 0x%02x != 0x%02x", type, link.expect); + prov_send_fail_msg(PROV_ERR_UNEXP_PDU); + return; + } + + if (type >= ARRAY_SIZE(prov_handlers)) { + BT_ERR("%s, Unknown provisioning PDU type 0x%02x", __func__, type); + close_link(PROV_ERR_NVAL_PDU, CLOSE_REASON_FAILED); + return; + } + + if (1 + prov_handlers[type].len != link.rx.buf->len) { + BT_ERR("%s, Invalid length %u for type 0x%02x", + __func__, link.rx.buf->len, type); + close_link(PROV_ERR_NVAL_FMT, CLOSE_REASON_FAILED); + return; + } + + /* Changed by Espressif, add provisioning timeout timer operations. + * When received a provisioning PDU, restart the 60s timer. + */ + if (bt_mesh_atomic_test_and_clear_bit(link.flags, TIMEOUT_START)) { + k_delayed_work_cancel(&link.timeout); + } + if (!bt_mesh_atomic_test_and_set_bit(link.flags, TIMEOUT_START)) { + k_delayed_work_submit(&link.timeout, PROVISION_TIMEOUT); + } + + prov_handlers[type].func(&link.rx.buf->data[1]); +} + +static void gen_prov_cont(struct prov_rx *rx, struct net_buf_simple *buf) +{ + u8_t seg = CONT_SEG_INDEX(rx->gpc); + + BT_DBG("len %u, seg_index %u", buf->len, seg); + + if (!link.rx.seg && link.rx.prev_id == rx->xact_id) { + BT_WARN("Resending ack"); + gen_prov_ack_send(rx->xact_id); + return; + } + + /* An issue here: + * If the Transaction Start PDU is lost and the device receives corresponding + * Transaction Continuation PDU fist, this will trigger the following error - + * handling code to be executed and the device must wait for the timeout of + * PB-ADV provisioning procedure. Then another provisioning procedure can be + * started (link.rx.id will be reset after each provisioning PDU is received + * completely). This issue also exists in Provisioner. + */ + if (rx->xact_id != link.rx.id) { + BT_WARN("Data for unknown transaction (%u != %u)", + rx->xact_id, link.rx.id); + return; + } + + if (seg > link.rx.last_seg) { + BT_ERR("%s, Invalid segment index %u", __func__, seg); + close_link(PROV_ERR_NVAL_FMT, CLOSE_REASON_FAILED); + return; + } else if (seg == link.rx.last_seg) { + u8_t expect_len; + + expect_len = (link.rx.buf->len - 20U - + ((link.rx.last_seg - 1) * 23U)); + if (expect_len != buf->len) { + BT_ERR("%s, Incorrect last seg len: %u != %u", + __func__, expect_len, buf->len); + close_link(PROV_ERR_NVAL_FMT, CLOSE_REASON_FAILED); + return; + } + } + + if (!(link.rx.seg & BIT(seg))) { + BT_WARN("Ignoring already received segment"); + return; + } + + memcpy(XACT_SEG_DATA(seg), buf->data, buf->len); + XACT_SEG_RECV(seg); + + if (!link.rx.seg) { + prov_msg_recv(); + } +} + +static void gen_prov_ack(struct prov_rx *rx, struct net_buf_simple *buf) +{ + BT_DBG("len %u", buf->len); + + if (!link.tx.buf[0]) { + return; + } + + if (rx->xact_id == link.tx.id) { + prov_clear_tx(); + } +} + +static void gen_prov_start(struct prov_rx *rx, struct net_buf_simple *buf) +{ + if (link.rx.seg) { + BT_WARN("Got Start while there are unreceived segments"); + return; + } + + if (link.rx.prev_id == rx->xact_id) { + BT_WARN("Resending ack"); + gen_prov_ack_send(rx->xact_id); + return; + } + + link.rx.buf->len = net_buf_simple_pull_be16(buf); + link.rx.id = rx->xact_id; + link.rx.fcs = net_buf_simple_pull_u8(buf); + + BT_DBG("len %u last_seg %u total_len %u fcs 0x%02x", buf->len, + START_LAST_SEG(rx->gpc), link.rx.buf->len, link.rx.fcs); + + if (link.rx.buf->len < 1) { + BT_ERR("%s, Ignoring zero-length provisioning PDU", __func__); + close_link(PROV_ERR_NVAL_FMT, CLOSE_REASON_FAILED); + return; + } + + if (link.rx.buf->len > link.rx.buf->size) { + BT_ERR("%s, Too large provisioning PDU (%u bytes)", + __func__, link.rx.buf->len); + // close_link(PROV_ERR_NVAL_FMT, CLOSE_REASON_FAILED); + return; + } + + if (START_LAST_SEG(rx->gpc) > 0 && link.rx.buf->len <= 20U) { + BT_ERR("%s, Too small total length for multi-segment PDU", __func__); + close_link(PROV_ERR_NVAL_FMT, CLOSE_REASON_FAILED); + return; + } + + link.rx.seg = (1 << (START_LAST_SEG(rx->gpc) + 1)) - 1; + link.rx.last_seg = START_LAST_SEG(rx->gpc); + memcpy(link.rx.buf->data, buf->data, buf->len); + XACT_SEG_RECV(0); + + if (!link.rx.seg) { + prov_msg_recv(); + } +} + +static const struct { + void (*func)(struct prov_rx *rx, struct net_buf_simple *buf); + bool require_link; + u8_t min_len; +} gen_prov[] = { + { gen_prov_start, true, 3 }, + { gen_prov_ack, true, 0 }, + { gen_prov_cont, true, 0 }, + { gen_prov_ctl, false, 0 }, +}; + +static void gen_prov_recv(struct prov_rx *rx, struct net_buf_simple *buf) +{ + if (buf->len < gen_prov[GPCF(rx->gpc)].min_len) { + BT_ERR("%s, Too short GPC message type %u", __func__, GPCF(rx->gpc)); + return; + } + + if (!bt_mesh_atomic_test_bit(link.flags, LINK_ACTIVE) && + gen_prov[GPCF(rx->gpc)].require_link) { + BT_DBG("Ignoring message that requires active link"); + return; + } + + gen_prov[GPCF(rx->gpc)].func(rx, buf); +} + +void bt_mesh_pb_adv_recv(struct net_buf_simple *buf) +{ + struct prov_rx rx; + + if (!bt_prov_active() && bt_mesh_is_provisioned()) { + BT_DBG("Ignoring provisioning PDU - already provisioned"); + return; + } + + if (buf->len < 6) { + BT_WARN("Too short provisioning packet (len %u)", buf->len); + return; + } + + rx.link_id = net_buf_simple_pull_be32(buf); + rx.xact_id = net_buf_simple_pull_u8(buf); + rx.gpc = net_buf_simple_pull_u8(buf); + + BT_DBG("link_id 0x%08x xact_id %u", rx.link_id, rx.xact_id); + + if (bt_mesh_atomic_test_bit(link.flags, LINK_ACTIVE) && link.id != rx.link_id) { + BT_DBG("Ignoring mesh beacon for unknown link"); + return; + } + + gen_prov_recv(&rx, buf); +} +#endif /* CONFIG_BLE_MESH_PB_ADV */ + +#if defined(CONFIG_BLE_MESH_PB_GATT) +int bt_mesh_pb_gatt_recv(struct bt_mesh_conn *conn, struct net_buf_simple *buf) +{ + u8_t type; + + BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); + + if (link.conn != conn) { + BT_WARN("Data for unexpected connection"); + return -ENOTCONN; + } + + if (buf->len < 1) { + BT_WARN("Too short provisioning packet (len %u)", buf->len); + return -EINVAL; + } + + type = net_buf_simple_pull_u8(buf); + if (type != PROV_FAILED && type != link.expect) { + BT_WARN("Unexpected msg 0x%02x != 0x%02x", type, link.expect); + prov_send_fail_msg(PROV_ERR_UNEXP_PDU); + return -EINVAL; + } + + if (type >= ARRAY_SIZE(prov_handlers)) { + BT_ERR("%s, Unknown provisioning PDU type 0x%02x", __func__, type); + return -EINVAL; + } + + if (prov_handlers[type].len != buf->len) { + BT_ERR("%s, Invalid length %u for type 0x%02x", __func__, buf->len, type); + return -EINVAL; + } + + /* Changed by Espressif, add provisioning timeout timer operations. + * When received a provisioning PDU, restart the 60s timer. + */ + if (bt_mesh_atomic_test_and_clear_bit(link.flags, TIMEOUT_START)) { + k_delayed_work_cancel(&link.timeout); + } + if (!bt_mesh_atomic_test_and_set_bit(link.flags, TIMEOUT_START)) { + k_delayed_work_submit(&link.timeout, PROVISION_TIMEOUT); + } + + prov_handlers[type].func(buf->data); + + return 0; +} + +int bt_mesh_pb_gatt_open(struct bt_mesh_conn *conn) +{ + BT_DBG("conn %p", conn); + + if (bt_mesh_atomic_test_and_set_bit(link.flags, LINK_ACTIVE)) { + return -EBUSY; + } + + link.conn = bt_mesh_conn_ref(conn); + link.expect = PROV_INVITE; + + if (prov->link_open) { + prov->link_open(BLE_MESH_PROV_GATT); + } + + return 0; +} + +int bt_mesh_pb_gatt_close(struct bt_mesh_conn *conn) +{ + BT_DBG("conn %p", conn); + + if (link.conn != conn) { + BT_ERR("%s, Not connected", __func__); + return -ENOTCONN; + } + + if (prov->link_close) { + prov->link_close(BLE_MESH_PROV_GATT); + } + + reset_state(); + + return 0; +} +#endif /* CONFIG_BLE_MESH_PB_GATT */ + +const struct bt_mesh_prov *bt_mesh_prov_get(void) +{ + return prov; +} + +bool bt_prov_active(void) +{ + return bt_mesh_atomic_test_bit(link.flags, LINK_ACTIVE); +} + +int bt_mesh_prov_init(const struct bt_mesh_prov *prov_info) +{ + const u8_t *key = NULL; + + if (!prov_info) { + BT_ERR("%s, No provisioning context provided", __func__); + return -EINVAL; + } + + /* Changed by Espressif. Use micro-ecc to generate public key now. */ + key = bt_mesh_pub_key_get(); + if (!key) { + BT_ERR("%s, Failed to generate public key", __func__); + return -EIO; + } + + prov = prov_info; + +#if defined(CONFIG_BLE_MESH_PB_ADV) + k_delayed_work_init(&link.tx.retransmit, prov_retransmit); +#endif + + /* Changed by Espressif, add provisioning timeout timer init */ + k_delayed_work_init(&link.timeout, prov_timeout); + + reset_state(); + + return 0; +} + +void bt_mesh_prov_complete(u16_t net_idx, u16_t addr, u8_t flags, u32_t iv_index) +{ + if (prov->complete) { + prov->complete(net_idx, addr, flags, iv_index); + } +} + +void bt_mesh_prov_reset(void) +{ + if (prov->reset) { + prov->reset(); + } +} + +#endif /* CONFIG_BLE_MESH_NODE */ diff --git a/components/bt/ble_mesh/mesh_core/prov.h b/components/bt/ble_mesh/mesh_core/prov.h new file mode 100644 index 0000000000..f96ed7707f --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/prov.h @@ -0,0 +1,34 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _PROV_H_ +#define _PROV_H_ + +#include "mesh_main.h" +#include "mesh_buf.h" +#include "mesh_bearer_adapt.h" + +void bt_mesh_pb_adv_recv(struct net_buf_simple *buf); + +bool bt_prov_active(void); + +int bt_mesh_pb_gatt_open(struct bt_mesh_conn *conn); +int bt_mesh_pb_gatt_close(struct bt_mesh_conn *conn); +int bt_mesh_pb_gatt_recv(struct bt_mesh_conn *conn, struct net_buf_simple *buf); + +int bt_mesh_set_oob_pub_key(const u8_t pub_key_x[32], const u8_t pub_key_y[32], + const u8_t pri_key[32]); + +const struct bt_mesh_prov *bt_mesh_prov_get(void); + +int bt_mesh_prov_init(const struct bt_mesh_prov *prov); + +void bt_mesh_prov_complete(u16_t net_idx, u16_t addr, u8_t flags, u32_t iv_index); +void bt_mesh_prov_reset(void); + +#endif /* _PROV_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/provisioner_beacon.c b/components/bt/ble_mesh/mesh_core/provisioner_beacon.c new file mode 100644 index 0000000000..dfe4e39fa0 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/provisioner_beacon.c @@ -0,0 +1,71 @@ +// Copyright 2017-2018 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 +#include + +#include "sdkconfig.h" +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BLE_MESH_DEBUG_BEACON) + +#include "mesh_util.h" +#include "mesh_buf.h" +#include "mesh_main.h" +#include "mesh_trace.h" + +#include "adv.h" +#include "mesh.h" +#include "net.h" +#include "prov.h" +#include "crypto.h" +#include "beacon.h" +#include "foundation.h" +#include "provisioner_prov.h" + +#define BEACON_TYPE_UNPROVISIONED 0x00 +#define BEACON_TYPE_SECURE 0x01 + +#if CONFIG_BLE_MESH_PROVISIONER + +static void provisioner_secure_beacon_recv(struct net_buf_simple *buf) +{ + // TODO: Provisioner receive and handle Secure Network Beacon +} + +void provisioner_beacon_recv(struct net_buf_simple *buf) +{ + u8_t type; + + BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); + + if (buf->len < 1) { + BT_ERR("%s, Too short beacon", __func__); + return; + } + + type = net_buf_simple_pull_u8(buf); + switch (type) { + case BEACON_TYPE_UNPROVISIONED: + BT_DBG("Unprovisioned device beacon received"); + provisioner_unprov_beacon_recv(buf); + break; + case BEACON_TYPE_SECURE: + provisioner_secure_beacon_recv(buf); + break; + default: + BT_DBG("%s, Unknown beacon type 0x%02x", __func__, type); + break; + } +} + +#endif /* CONFIG_BLE_MESH_PROVISIONER */ diff --git a/components/bt/ble_mesh/mesh_core/provisioner_beacon.h b/components/bt/ble_mesh/mesh_core/provisioner_beacon.h new file mode 100644 index 0000000000..0b3cfae6e6 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/provisioner_beacon.h @@ -0,0 +1,20 @@ +// Copyright 2017-2018 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. + +#ifndef _PROVISIONER_BEACON_H_ +#define _PROVISIONER_BEACON_H_ + +void provisioner_beacon_recv(struct net_buf_simple *buf); + +#endif /* _PROVISIONER_BEACON_H_ */ \ No newline at end of file diff --git a/components/bt/ble_mesh/mesh_core/provisioner_main.c b/components/bt/ble_mesh/mesh_core/provisioner_main.c new file mode 100644 index 0000000000..d78cc1484a --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/provisioner_main.c @@ -0,0 +1,1278 @@ +// Copyright 2017-2018 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 +#include + +#include "sdkconfig.h" +#include "osi/allocator.h" + +#include "mesh_util.h" +#include "mesh_main.h" +#include "mesh_trace.h" +#include "mesh_bearer_adapt.h" + +#include "mesh.h" +#include "crypto.h" +#include "adv.h" +#include "net.h" +#include "access.h" + +#include "provisioner_prov.h" +#include "provisioner_proxy.h" +#include "provisioner_main.h" + +#if CONFIG_BLE_MESH_PROVISIONER + +static const struct bt_mesh_prov *prov; +static const struct bt_mesh_comp *comp; + +static struct bt_mesh_node_t *mesh_nodes[CONFIG_BLE_MESH_MAX_STORED_NODES]; +static u32_t mesh_node_count; + +static bool prov_upper_init = false; + +static int provisioner_index_check(int node_index) +{ + struct bt_mesh_node_t *node = NULL; + + BT_DBG("%s", __func__); + + if (node_index < 0) { + BT_ERR("%s, Invalid node index %d", __func__, node_index); + return -EINVAL; + } + + if (node_index >= ARRAY_SIZE(mesh_nodes)) { + BT_ERR("%s, Too big node index", __func__); + return -EINVAL; + } + + node = mesh_nodes[node_index]; + if (!node) { + BT_ERR("%s, Node is not found", __func__); + return -EINVAL; + } + + return 0; +} + +int provisioner_node_provision(int node_index, const u8_t uuid[16], u16_t oob_info, + u16_t unicast_addr, u8_t element_num, u16_t net_idx, + u8_t flags, u32_t iv_index, const u8_t dev_key[16]) +{ + struct bt_mesh_node_t *node = NULL; + + BT_DBG("%s", __func__); + + if (mesh_node_count >= ARRAY_SIZE(mesh_nodes)) { + BT_ERR("%s, Node queue is full", __func__); + return -ENOMEM; + } + + if (node_index >= ARRAY_SIZE(mesh_nodes) || !uuid || !dev_key) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + node = osi_calloc(sizeof(struct bt_mesh_node_t)); + if (!node) { + BT_ERR("%s, Failed to allocate memory", __func__); + return -ENOMEM; + } + + BT_DBG("node_index: 0x%x, unicast_addr: 0x%x, element_num: 0x%x, net_idx: 0x%x", + node_index, unicast_addr, element_num, net_idx); + BT_DBG("dev_uuid: %s", bt_hex(uuid, 16)); + BT_DBG("dev_key: %s", bt_hex(dev_key, 16)); + + mesh_nodes[node_index] = node; + + memcpy(node->dev_uuid, uuid, 16); + node->oob_info = oob_info; + node->unicast_addr = unicast_addr; + node->element_num = element_num; + node->net_idx = net_idx; + node->flags = flags; + node->iv_index = iv_index; + memcpy(node->dev_key, dev_key, 16); + + mesh_node_count++; + + return 0; +} + +int provisioner_node_reset(int node_index) +{ + struct bt_mesh_node_t *node = NULL; + struct bt_mesh_rpl *rpl = NULL; + int i; + + BT_DBG("%s, reset node %d", __func__, node_index); + + if (!mesh_node_count) { + BT_ERR("%s, Node queue is empty", __func__); + return -ENODEV; + } + + if (provisioner_index_check(node_index)) { + BT_ERR("%s, Failed to check node index", __func__); + return -EINVAL; + } + + node = mesh_nodes[node_index]; + + /* Reset corresponding rpl when reset the node */ + for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { + rpl = &bt_mesh.rpl[i]; + if (rpl->src >= node->unicast_addr && + rpl->src < node->unicast_addr + node->element_num) { + memset(rpl, 0, sizeof(struct bt_mesh_rpl)); + } + } + + osi_free(mesh_nodes[node_index]); + mesh_nodes[node_index] = NULL; + + mesh_node_count--; + + return 0; +} + +int provisioner_upper_reset_all_nodes(void) +{ + int i, err; + + BT_DBG("%s", __func__); + + for (i = 0; i < ARRAY_SIZE(mesh_nodes); i++) { + err = provisioner_node_reset(i); + if (err == -ENODEV) { + return 0; + } + } + + return 0; +} + +/** For Provisioner, we use the same data structure + * (like, struct bt_mesh_subnet, etc.) for netkey + * & appkey because if not we need to change a lot + * of APIs. + */ +int provisioner_upper_init(void) +{ + struct bt_mesh_subnet *sub = NULL; + u8_t p_key[16] = {0}; + + BT_DBG("%s", __func__); + + if (prov_upper_init) { + return 0; + } + + comp = bt_mesh_comp_get(); + if (!comp) { + BT_ERR("%s, NULL composition data", __func__); + return -EINVAL; + } + + prov = provisioner_get_prov_info(); + if (!prov) { + BT_ERR("%s, NULL provisioning context", __func__); + return -EINVAL; + } + + /* If the device only acts as a Provisioner, need to initialize + each element's address. */ + bt_mesh_comp_provision(prov->prov_unicast_addr); + + /* Generate the primary netkey */ + if (bt_mesh_rand(p_key, 16)) { + BT_ERR("%s, Failed to generate Primary NetKey", __func__); + return -EIO; + } + + sub = osi_calloc(sizeof(struct bt_mesh_subnet)); + if (!sub) { + BT_ERR("%s, Failed to allocate memory", __func__); + return -ENOMEM; + } + + sub->kr_flag = BLE_MESH_KEY_REFRESH(prov->flags); + if (sub->kr_flag) { + if (bt_mesh_net_keys_create(&sub->keys[1], p_key)) { + BT_ERR("%s, Failed to generate net-related keys", __func__); + osi_free(sub); + return -EIO; + } + sub->kr_phase = BLE_MESH_KR_PHASE_2; + } else { + /* Currently provisioner only use keys[0] */ + if (bt_mesh_net_keys_create(&sub->keys[0], p_key)) { + BT_ERR("%s, Failed to create net-related keys", __func__); + osi_free(sub); + return -EIO; + } + sub->kr_phase = BLE_MESH_KR_NORMAL; + } + sub->net_idx = BLE_MESH_KEY_PRIMARY; + sub->node_id = BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED; + + bt_mesh.p_sub[0] = sub; + + /* Dynamically added appkey & netkey will use these key_idx */ + bt_mesh.p_app_idx_next = 0x0000; + bt_mesh.p_net_idx_next = 0x0001; + + /* In this function, we use the values of struct bt_mesh_prov + which has been initialized in the application layer */ + bt_mesh.iv_index = prov->iv_index; + bt_mesh_atomic_set_bit_to(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS, + BLE_MESH_IV_UPDATE(prov->flags)); + + /* Set minimum required hours, since the 96-hour minimum requirement + * doesn't apply straight after provisioning (since we can't know how + * long has actually passed since the network changed its state). + * This operation is the same with node initialization. + */ + bt_mesh.ivu_duration = BLE_MESH_IVU_MIN_HOURS; + + prov_upper_init = true; + + BT_DBG("kr_flag: %d, kr_phase: %d, net_idx: 0x%02x, node_id %d", + sub->kr_flag, sub->kr_phase, sub->net_idx, sub->node_id); + BT_DBG("netkey: %s, nid: 0x%x", bt_hex(sub->keys[0].net, 16), sub->keys[0].nid); + BT_DBG("enckey: %s", bt_hex(sub->keys[0].enc, 16)); + BT_DBG("network id: %s", bt_hex(sub->keys[0].net_id, 8)); + BT_DBG("identity: %s", bt_hex(sub->keys[0].identity, 16)); + BT_DBG("privacy: %s", bt_hex(sub->keys[0].privacy, 16)); + BT_DBG("beacon: %s", bt_hex(sub->keys[0].beacon, 16)); + + return 0; +} + +/* The following APIs are for provisioner upper layers internal use */ + +const u8_t *provisioner_net_key_get(u16_t net_idx) +{ + struct bt_mesh_subnet *sub = NULL; + int i; + + BT_DBG("%s", __func__); + + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { + sub = bt_mesh.p_sub[i]; + if (!sub || (sub->net_idx != net_idx)) { + continue; + } + if (sub->kr_flag) { + return sub->keys[1].net; + } + return sub->keys[0].net; + } + + return NULL; +} + +struct bt_mesh_subnet *provisioner_subnet_get(u16_t net_idx) +{ + struct bt_mesh_subnet *sub = NULL; + int i; + + BT_DBG("%s", __func__); + + if (net_idx == BLE_MESH_KEY_ANY) { + return bt_mesh.p_sub[0]; + } + + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { + sub = bt_mesh.p_sub[i]; + if (!sub || (sub->net_idx != net_idx)) { + continue; + } + return sub; + } + + return NULL; +} + +bool provisioner_check_msg_dst_addr(u16_t dst_addr) +{ + struct bt_mesh_node_t *node = NULL; + int i; + + BT_DBG("%s", __func__); + + if (!BLE_MESH_ADDR_IS_UNICAST(dst_addr)) { + return true; + } + + for (i = 0; i < ARRAY_SIZE(mesh_nodes); i++) { + node = mesh_nodes[i]; + if (node && dst_addr >= node->unicast_addr && + dst_addr < node->unicast_addr + node->element_num) { + return true; + } + } + + return false; +} + +const u8_t *provisioner_get_device_key(u16_t dst_addr) +{ + /* Device key is only used to encrypt configuration messages. + * Configuration model shall only be supported by the primary + * element which uses the primary unicast address. + */ + struct bt_mesh_node_t *node = NULL; + int i; + + BT_DBG("%s", __func__); + + if (!BLE_MESH_ADDR_IS_UNICAST(dst_addr)) { + BT_ERR("%s, Not a unicast address 0x%04x", __func__, dst_addr); + return NULL; + } + + for (i = 0; i < ARRAY_SIZE(mesh_nodes); i++) { + node = mesh_nodes[i]; + if (node && node->unicast_addr == dst_addr) { + return node->dev_key; + } + } + + return NULL; +} + +struct bt_mesh_app_key *provisioner_app_key_find(u16_t app_idx) +{ + struct bt_mesh_app_key *key = NULL; + int i; + + BT_DBG("%s", __func__); + + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { + key = bt_mesh.p_app_keys[i]; + if (!key) { + continue; + } + if (key->net_idx != BLE_MESH_KEY_UNUSED && + key->app_idx == app_idx) { + return key; + } + } + + return NULL; +} + +u32_t provisioner_get_prov_node_count(void) +{ + return mesh_node_count; +} + +/* The following APIs are for provisioner application use */ + +#if 0 +static int bt_mesh_provisioner_set_kr_flag(u16_t net_idx, bool kr_flag) +{ + struct bt_mesh_subnet *sub = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { + sub = bt_mesh.p_sub[i]; + if (!sub || (sub->net_idx != net_idx)) { + continue; + } + sub->kr_flag = kr_flag; + break; + } + if (i == ARRAY_SIZE(bt_mesh.p_sub)) { + return -ENODEV; + } + + /* TODO: When kr_flag is changed, provisioner may need + * to change the netkey of the subnet and update + * corresponding appkey. + */ + + return 0; +} + +static void bt_mesh_provisioner_set_iv_index(u32_t iv_index) +{ + bt_mesh.iv_index = iv_index; + + /* TODO: When iv_index is changed, provisioner may need to + * start iv update procedure. And the ivu_initiator + * & iv_update flags may also need to be set. + */ +} +#endif + +int bt_mesh_provisioner_store_node_info(struct bt_mesh_node_t *node_info) +{ + struct bt_mesh_node_t *node = NULL; + int i; + + if (!node_info) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + /* Check if the device uuid already exists */ + for (i = 0; i < ARRAY_SIZE(mesh_nodes); i++) { + node = mesh_nodes[i]; + if (node && !memcmp(node->dev_uuid, node_info->dev_uuid, 16)) { + BT_WARN("%s, Node info already exists", __func__); + return -EEXIST; + } + } + + /* 0 ~ (CONFIG_BLE_MESH_MAX_PROV_NODES-1) are left for self-provisioned nodes */ + for (i = CONFIG_BLE_MESH_MAX_PROV_NODES; i < ARRAY_SIZE(mesh_nodes); i++) { + node = mesh_nodes[i]; + if (!node) { + node = osi_calloc(sizeof(struct bt_mesh_node_t)); + if (!node) { + BT_ERR("%s, Failed to allocate memory", __func__); + return -ENOMEM; + } + memcpy(node, node_info, sizeof(struct bt_mesh_node_t)); + mesh_nodes[i] = node; + mesh_node_count++; + return 0; + } + } + + BT_ERR("%s, Node info is full", __func__); + return -ENOMEM; +} + +int bt_mesh_provisioner_get_all_node_unicast_addr(struct net_buf_simple *buf) +{ + struct bt_mesh_node_t *node = NULL; + int i; + + if (!buf) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(mesh_nodes); i++) { + node = mesh_nodes[i]; + if (!node || !BLE_MESH_ADDR_IS_UNICAST(node->unicast_addr)) { + continue; + } + net_buf_simple_add_le16(buf, node->unicast_addr); + } + + return 0; +} + +int bt_mesh_provisioner_set_node_name(int node_index, const char *name) +{ + size_t length, name_len; + int i; + + BT_DBG("%s", __func__); + + if (!name) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + if (provisioner_index_check(node_index)) { + BT_ERR("%s, Failed to check node index", __func__); + return -EINVAL; + } + + BT_DBG("name len is %d, name is %s", strlen(name), name); + + length = (strlen(name) <= MESH_NAME_SIZE) ? strlen(name) : MESH_NAME_SIZE; + for (i = 0; i < ARRAY_SIZE(mesh_nodes); i++) { + if (!mesh_nodes[i] || !mesh_nodes[i]->node_name) { + continue; + } + name_len = strlen(mesh_nodes[i]->node_name); + if (length != name_len) { + continue; + } + if (!strncmp(mesh_nodes[i]->node_name, name, length)) { + BT_WARN("%s, Name %s already exists", __func__, name); + return -EEXIST; + } + } + + strncpy(mesh_nodes[node_index]->node_name, name, length); + + return 0; +} + +const char *bt_mesh_provisioner_get_node_name(int node_index) +{ + BT_DBG("%s", __func__); + + if (provisioner_index_check(node_index)) { + BT_ERR("%s, Failed to check node index", __func__); + return NULL; + } + + return mesh_nodes[node_index]->node_name; +} + +int bt_mesh_provisioner_get_node_index(const char *name) +{ + size_t length, name_len; + int i; + + BT_DBG("%s", __func__); + + if (!name) { + return -EINVAL; + } + + length = (strlen(name) <= MESH_NAME_SIZE) ? strlen(name) : MESH_NAME_SIZE; + for (i = 0; i < ARRAY_SIZE(mesh_nodes); i++) { + if (!mesh_nodes[i] || !mesh_nodes[i]->node_name) { + continue; + } + name_len = strlen(mesh_nodes[i]->node_name); + if (length != name_len) { + continue; + } + if (!strncmp(mesh_nodes[i]->node_name, name, length)) { + return i; + } + } + + return -ENODEV; +} + +struct bt_mesh_node_t *bt_mesh_provisioner_get_node_info(u16_t unicast_addr) +{ + struct bt_mesh_node_t *node = NULL; + int i; + + BT_DBG("%s", __func__); + + if (!BLE_MESH_ADDR_IS_UNICAST(unicast_addr)) { + BT_ERR("%s, Not a unicast address 0x%04x", __func__, unicast_addr); + return NULL; + } + + for (i = 0; i < ARRAY_SIZE(mesh_nodes); i++) { + node = mesh_nodes[i]; + if (!node) { + continue; + } + if (unicast_addr >= node->unicast_addr && + unicast_addr < (node->unicast_addr + node->element_num)) { + return node; + } + } + + return NULL; +} + +u32_t bt_mesh_provisioner_get_net_key_count(void) +{ + return ARRAY_SIZE(bt_mesh.p_sub); +} + +u32_t bt_mesh_provisioner_get_app_key_count(void) +{ + return ARRAY_SIZE(bt_mesh.p_app_keys); +} + +static int provisioner_check_app_key(const u8_t app_key[16], u16_t *app_idx) +{ + struct bt_mesh_app_key *key = NULL; + int i; + + if (!app_key) { + return 0; + } + + /* Check if app_key is already existed */ + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { + key = bt_mesh.p_app_keys[i]; + if (key && (!memcmp(key->keys[0].val, app_key, 16) || + !memcmp(key->keys[1].val, app_key, 16))) { + *app_idx = key->app_idx; + return -EEXIST; + } + } + + return 0; +} + +static int provisioner_check_app_idx(u16_t app_idx, bool exist) +{ + struct bt_mesh_app_key *key = NULL; + int i; + + if (exist) { + /* Check if app_idx is already existed */ + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { + key = bt_mesh.p_app_keys[i]; + if (key && (key->app_idx == app_idx)) { + return -EEXIST; + } + } + return 0; + } + + /* Check if app_idx is not existed */ + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { + key = bt_mesh.p_app_keys[i]; + if (key && (key->app_idx == app_idx)) { + return 0; + } + } + + return -ENODEV; +} + +static int provisioner_check_app_key_full(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { + if (!bt_mesh.p_app_keys[i]) { + return i; + } + } + + return -ENOMEM; +} + +static int provisioner_check_net_key(const u8_t net_key[16], u16_t *net_idx) +{ + struct bt_mesh_subnet *sub = NULL; + int i; + + if (!net_key) { + return 0; + } + + /* Check if net_key is already existed */ + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { + sub = bt_mesh.p_sub[i]; + if (sub && (!memcmp(sub->keys[0].net, net_key, 16) || + !memcmp(sub->keys[1].net, net_key, 16))) { + *net_idx = sub->net_idx; + return -EEXIST; + } + } + + return 0; +} + +static int provisioner_check_net_idx(u16_t net_idx, bool exist) +{ + struct bt_mesh_subnet *sub = NULL; + int i; + + if (exist) { + /* Check if net_idx is already existed */ + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { + sub = bt_mesh.p_sub[i]; + if (sub && (sub->net_idx == net_idx)) { + return -EEXIST; + } + } + return 0; + } + + /* Check if net_idx is not existed */ + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { + sub = bt_mesh.p_sub[i]; + if (sub && (sub->net_idx == net_idx)) { + return 0; + } + } + + return -ENODEV; +} + +static int provisioner_check_net_key_full(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { + if (!bt_mesh.p_sub[i]) { + return i; + } + } + + return -ENOMEM; +} + +int bt_mesh_provisioner_local_app_key_add(const u8_t app_key[16], u16_t net_idx, u16_t *app_idx) +{ + struct bt_mesh_app_key *key = NULL; + struct bt_mesh_app_keys *keys = NULL; + u8_t p_key[16] = {0}; + int add = -1; + + if (bt_mesh.p_app_idx_next >= 0x1000) { + BT_ERR("%s, No AppKey Index available", __func__); + return -EIO; + } + + if (!app_idx || (*app_idx != 0xFFFF && *app_idx >= 0x1000)) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + /* Check if the same application key already exists */ + if (provisioner_check_app_key(app_key, app_idx)) { + BT_WARN("%s, AppKey already exists, AppKey Index updated", __func__); + return 0; + } + + /* Check if the net_idx exists */ + if (provisioner_check_net_idx(net_idx, false)) { + BT_ERR("%s, NetKey Index does not exist", __func__); + return -ENODEV; + } + + /* Check if the same app_idx already exists */ + if (provisioner_check_app_idx(*app_idx, true)) { + BT_ERR("%s, AppKey Index already exists", __func__); + return -EEXIST; + } + + add = provisioner_check_app_key_full(); + if (add < 0) { + BT_ERR("%s, AppKey queue is full", __func__); + return -ENOMEM; + } + + if (!app_key) { + if (bt_mesh_rand(p_key, 16)) { + BT_ERR("%s, Failed to generate AppKey", __func__); + return -EIO; + } + } else { + memcpy(p_key, app_key, 16); + } + + key = osi_calloc(sizeof(struct bt_mesh_app_key)); + if (!key) { + BT_ERR("%s, Failed to allocate memory", __func__); + return -ENOMEM; + } + + keys = &key->keys[0]; + if (bt_mesh_app_id(p_key, &keys->id)) { + BT_ERR("%s, Failed to generate AID", __func__); + osi_free(key); + return -EIO; + } + + memcpy(keys->val, p_key, 16); + key->net_idx = net_idx; + if (*app_idx != 0xFFFF) { + key->app_idx = *app_idx; + } else { + key->app_idx = bt_mesh.p_app_idx_next; + while (1) { + if (provisioner_check_app_idx(key->app_idx, true)) { + key->app_idx = (++bt_mesh.p_app_idx_next); + if (key->app_idx >= 0x1000) { + BT_ERR("%s, No AppKey Index available", __func__); + osi_free(key); + return -EIO; + } + } else { + break; + } + } + *app_idx = key->app_idx; + } + key->updated = false; + + bt_mesh.p_app_keys[add] = key; + + return 0; +} + +const u8_t *bt_mesh_provisioner_local_app_key_get(u16_t net_idx, u16_t app_idx) +{ + struct bt_mesh_app_key *key = NULL; + int i; + + BT_DBG("%s", __func__); + + if (provisioner_check_net_idx(net_idx, false)) { + BT_ERR("%s, NetKey Index does not exist", __func__); + return NULL; + } + + if (provisioner_check_app_idx(app_idx, false)) { + BT_ERR("%s, AppKey Index does not exist", __func__); + return NULL; + } + + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { + key = bt_mesh.p_app_keys[i]; + if (key && key->net_idx == net_idx && + key->app_idx == app_idx) { + if (key->updated) { + return key->keys[1].val; + } + return key->keys[0].val; + } + } + + return NULL; +} + +int bt_mesh_provisioner_local_app_key_delete(u16_t net_idx, u16_t app_idx) +{ + struct bt_mesh_app_key *key = NULL; + int i; + + BT_DBG("%s", __func__); + + if (provisioner_check_net_idx(net_idx, false)) { + BT_ERR("%s, NetKey Index does not exist", __func__); + return -ENODEV; + } + + if (provisioner_check_app_idx(app_idx, false)) { + BT_ERR("%s, AppKey Index does not exist", __func__); + return -ENODEV; + } + + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { + key = bt_mesh.p_app_keys[i]; + if (key && key->net_idx == net_idx && + key->app_idx == app_idx) { + osi_free(bt_mesh.p_app_keys[i]); + bt_mesh.p_app_keys[i] = NULL; + return 0; + } + } + + /* Shall never reach here */ + return -ENODEV; +} + +int bt_mesh_provisioner_local_net_key_add(const u8_t net_key[16], u16_t *net_idx) +{ + struct bt_mesh_subnet *sub = NULL; + u8_t p_key[16] = {0}; + int add = -1; + + if (bt_mesh.p_net_idx_next >= 0x1000) { + BT_ERR("%s, No NetKey Index available", __func__); + return -EIO; + } + + if (!net_idx || (*net_idx != 0xFFFF && *net_idx >= 0x1000)) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + /* Check if the same network key already exists */ + if (provisioner_check_net_key(net_key, net_idx)) { + BT_WARN("%s, NetKey already exists, NetKey Index updated", __func__); + return 0; + } + + /* Check if the same net_idx already exists */ + if (provisioner_check_net_idx(*net_idx, true)) { + BT_ERR("%s, NetKey Index already exists", __func__); + return -EEXIST; + } + + add = provisioner_check_net_key_full(); + if (add < 0) { + BT_ERR("%s, NetKey queue is full", __func__); + return -ENOMEM; + } + + if (!net_key) { + if (bt_mesh_rand(p_key, 16)) { + BT_ERR("%s, Failed to generate NetKey", __func__); + return -EIO; + } + } else { + memcpy(p_key, net_key, 16); + } + + sub = osi_calloc(sizeof(struct bt_mesh_subnet)); + if (!sub) { + BT_ERR("%s, Failed to allocate memory", __func__); + return -ENOMEM; + } + + if (bt_mesh_net_keys_create(&sub->keys[0], p_key)) { + BT_ERR("%s, Failed to generate NID", __func__); + osi_free(sub); + return -EIO; + } + + if (*net_idx != 0xFFFF) { + sub->net_idx = *net_idx; + } else { + sub->net_idx = bt_mesh.p_net_idx_next; + while (1) { + if (provisioner_check_net_idx(sub->net_idx, true)) { + sub->net_idx = (++bt_mesh.p_net_idx_next); + if (sub->net_idx >= 0x1000) { + BT_ERR("%s, No NetKey Index available", __func__); + osi_free(sub); + return -EIO; + } + } else { + break; + } + } + *net_idx = sub->net_idx; + } + sub->kr_phase = BLE_MESH_KR_NORMAL; + sub->kr_flag = false; + sub->node_id = BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED; + + bt_mesh.p_sub[add] = sub; + + return 0; +} + +const u8_t *bt_mesh_provisioner_local_net_key_get(u16_t net_idx) +{ + struct bt_mesh_subnet *sub = NULL; + int i; + + BT_DBG("%s", __func__); + + if (provisioner_check_net_idx(net_idx, false)) { + BT_ERR("%s, NetKey Index does not exist", __func__); + return NULL; + } + + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { + sub = bt_mesh.p_sub[i]; + if (sub && sub->net_idx == net_idx) { + if (sub->kr_flag) { + return sub->keys[1].net; + } + return sub->keys[0].net; + } + } + + return NULL; +} + +int bt_mesh_provisioner_local_net_key_delete(u16_t net_idx) +{ + struct bt_mesh_subnet *sub = NULL; + int i; + + BT_DBG("%s", __func__); + + if (provisioner_check_net_idx(net_idx, false)) { + BT_ERR("%s, NetKey Index does not exist", __func__); + return -ENODEV; + } + + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { + sub = bt_mesh.p_sub[i]; + if (sub && sub->net_idx == net_idx) { + osi_free(bt_mesh.p_sub[i]); + bt_mesh.p_sub[i] = NULL; + return 0; + } + } + + /* Shall never reach here */ + return -ENODEV; +} + +int bt_mesh_provisioner_get_own_unicast_addr(u16_t *addr, u8_t *elem_num) +{ + if (!addr || !elem_num || !prov || !comp) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + *addr = prov->prov_unicast_addr; + *elem_num = comp->elem_count; + + return 0; +} + +int bt_mesh_provisioner_bind_local_model_app_idx(u16_t elem_addr, u16_t mod_id, + u16_t cid, u16_t app_idx) +{ + struct bt_mesh_elem *elem = NULL; + struct bt_mesh_model *model = NULL; + int i; + + if (!comp) { + BT_ERR("%s, NULL composition data", __func__); + return -EINVAL; + } + + for (i = 0; i < comp->elem_count; i++) { + elem = &comp->elem[i]; + if (elem->addr == elem_addr) { + break; + } + } + if (i == comp->elem_count) { + BT_ERR("%s, No element is found", __func__); + return -ENODEV; + } + + if (cid == 0xFFFF) { + model = bt_mesh_model_find(elem, mod_id); + } else { + model = bt_mesh_model_find_vnd(elem, cid, mod_id); + } + if (!model) { + BT_ERR("%s, No model is found", __func__); + return -ENODEV; + } + + if (provisioner_check_app_idx(app_idx, false)) { + BT_ERR("%s, AppKey Index does not exist", __func__); + return -ENODEV; + } + + for (i = 0; i < ARRAY_SIZE(model->keys); i++) { + if (model->keys[i] == app_idx) { + BT_WARN("%s, AppKey Index is already binded with model", __func__); + return 0; + } + } + + for (i = 0; i < ARRAY_SIZE(model->keys); i++) { + if (model->keys[i] == BLE_MESH_KEY_UNUSED) { + model->keys[i] = app_idx; + return 0; + } + } + + BT_ERR("%s, Model AppKey queue is full", __func__); + return -ENOMEM; +} + +int bt_mesh_provisioner_bind_local_app_net_idx(u16_t net_idx, u16_t app_idx) +{ + struct bt_mesh_app_key *key = NULL; + int i; + + BT_DBG("%s", __func__); + + if (provisioner_check_net_idx(net_idx, false)) { + BT_ERR("%s, NetKey Index does not exist", __func__); + return -ENODEV; + } + + if (provisioner_check_app_idx(app_idx, false)) { + BT_ERR("%s, AppKey Index does not exist", __func__); + return -ENODEV; + } + + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { + key = bt_mesh.p_app_keys[i]; + if (!key || (key->app_idx != app_idx)) { + continue; + } + key->net_idx = net_idx; + return 0; + } + + return -ENODEV; +} + +int bt_mesh_provisioner_print_local_element_info(void) +{ + struct bt_mesh_elem *elem = NULL; + struct bt_mesh_model *model = NULL; + int i, j; + + if (!comp) { + BT_ERR("%s, NULL composition data", __func__); + return -EINVAL; + } + + BT_WARN("************************************************"); + BT_WARN("* cid: 0x%04x pid: 0x%04x vid: 0x%04x *", comp->cid, comp->pid, comp->vid); + BT_WARN("* Element Number: 0x%02x *", comp->elem_count); + for (i = 0; i < comp->elem_count; i++) { + elem = &comp->elem[i]; + BT_WARN("* Element %d: 0x%04x *", i, elem->addr); + BT_WARN("* Loc: 0x%04x NumS: 0x%02x NumV: 0x%02x *", elem->loc, elem->model_count, elem->vnd_model_count); + for (j = 0; j < elem->model_count; j++) { + model = &elem->models[j]; + BT_WARN("* sig_model %d: id - 0x%04x *", j, model->id); + } + for (j = 0; j < elem->vnd_model_count; j++) { + model = &elem->vnd_models[j]; + BT_WARN("* vnd_model %d: id - 0x%04x, cid - 0x%04x *", j, model->vnd.id, model->vnd.company); + } + } + BT_WARN("************************************************"); + + return 0; +} + +#endif /* CONFIG_BLE_MESH_PROVISIONER */ + +/* The following APIs are for fast provisioning */ + +#if CONFIG_BLE_MESH_FAST_PROV + +const u8_t *get_fast_prov_device_key(u16_t addr) +{ + struct bt_mesh_node_t *node = NULL; + + BT_DBG("%s", __func__); + + if (!BLE_MESH_ADDR_IS_UNICAST(addr)) { + BT_ERR("%s, Not a unicast address 0x%04x", __func__, addr); + return NULL; + } + + if (addr == bt_mesh_primary_addr()) { + return bt_mesh.dev_key; + } + + for (int i = 0; i < ARRAY_SIZE(mesh_nodes); i++) { + node = mesh_nodes[i]; + if (node && node->unicast_addr == addr) { + return node->dev_key; + } + } + + return NULL; +} + +struct bt_mesh_subnet *get_fast_prov_subnet(u16_t net_idx) +{ + struct bt_mesh_subnet *sub = NULL; + + BT_DBG("%s", __func__); + + for (int i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + sub = &bt_mesh.sub[i]; + if (sub->net_idx == net_idx) { + return sub; + } + } + + for (int i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { + sub = bt_mesh.p_sub[i]; + if (sub && sub->net_idx == net_idx) { + return sub; + } + } + + return NULL; +} + +struct bt_mesh_app_key *get_fast_prov_app_key(u16_t net_idx, u16_t app_idx) +{ + struct bt_mesh_app_key *key = NULL; + + BT_DBG("%s", __func__); + + for (int i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { + key = &bt_mesh.app_keys[i]; + if (key->net_idx == net_idx && key->app_idx == app_idx) { + return key; + } + } + + for (int i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { + key = bt_mesh.p_app_keys[i]; + if (key && key->net_idx == net_idx && key->app_idx == app_idx) { + return key; + } + } + + return NULL; +} + +u8_t bt_mesh_set_fast_prov_net_idx(u16_t net_idx) +{ + struct bt_mesh_subnet *sub = NULL; + struct bt_mesh_subnet_keys *key = NULL; + + sub = get_fast_prov_subnet(net_idx); + if (sub) { + key = BLE_MESH_KEY_REFRESH(sub->kr_flag) ? &sub->keys[1] : &sub->keys[0]; + return provisioner_set_fast_prov_net_idx(key->net, net_idx); + } + + /* If net_idx is not found, set net_idx to fast_prov first, + * and wait for primary provisioner to add net_key */ + return provisioner_set_fast_prov_net_idx(NULL, net_idx); +} + +u8_t bt_mesh_add_fast_prov_net_key(const u8_t net_key[16]) +{ + const u8_t *keys = NULL; + u16_t net_idx; + int err; + + net_idx = provisioner_get_fast_prov_net_idx(); + bt_mesh.p_net_idx_next = net_idx; + + err = bt_mesh_provisioner_local_net_key_add(net_key, &net_idx); + if (err) { + return 0x01; /* status: add net_key fail */ + }; + + keys = bt_mesh_provisioner_local_net_key_get(net_idx); + if (!keys) { + return 0x01; /* status: add net_key fail */ + } + + return provisioner_set_fast_prov_net_idx(keys, net_idx); +} + +const u8_t *bt_mesh_get_fast_prov_net_key(u16_t net_idx) +{ + struct bt_mesh_subnet *sub = NULL; + + sub = get_fast_prov_subnet(net_idx); + if (!sub) { + BT_ERR("%s, Failed to get subnet", __func__); + return NULL; + } + + return (sub->kr_flag ? sub->keys[1].net : sub->keys[0].net); +} + +const u8_t *bt_mesh_get_fast_prov_app_key(u16_t net_idx, u16_t app_idx) +{ + struct bt_mesh_app_key *key = NULL; + + key = get_fast_prov_app_key(net_idx, app_idx); + if (!key) { + BT_ERR("%s, Failed to get AppKey", __func__); + return NULL; + } + + return (key->updated ? key->keys[1].val : key->keys[0].val); +} + +#endif /* CONFIG_BLE_MESH_FAST_PROV */ diff --git a/components/bt/ble_mesh/mesh_core/provisioner_main.h b/components/bt/ble_mesh/mesh_core/provisioner_main.h new file mode 100644 index 0000000000..a4585d4009 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/provisioner_main.h @@ -0,0 +1,122 @@ +// Copyright 2017-2018 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. + +#ifndef _PROVISIONER_MAIN_H_ +#define _PROVISIONER_MAIN_H_ + +#include "mesh_util.h" +#include "mesh_kernel.h" +#include "mesh_access.h" +#include "net.h" + +#define MESH_NAME_SIZE 31 + +/* Each node information stored by provisioner */ +struct bt_mesh_node_t { + char node_name[MESH_NAME_SIZE]; /* Node name */ + u8_t dev_uuid[16]; /* Device UUID pointer, stored in provisioner_prov.c */ + u16_t oob_info; /* Node OOB information */ + u16_t unicast_addr; /* Node unicast address */ + u8_t element_num; /* Node element number */ + u16_t net_idx; /* Node provision net_idx */ + u8_t flags; /* Node key refresh flag and iv update flag */ + u32_t iv_index; /* Node IV Index */ + u8_t dev_key[16]; /* Node device key */ +} __packed; + +/* The following APIs are for key init, node provision & node reset. */ + +int provisioner_node_provision(int node_index, const u8_t uuid[16], u16_t oob_info, + u16_t unicast_addr, u8_t element_num, u16_t net_idx, + u8_t flags, u32_t iv_index, const u8_t dev_key[16]); + +int provisioner_node_reset(int node_index); + +int provisioner_upper_reset_all_nodes(void); + +int provisioner_upper_init(void); + +/* The following APIs are for provisioner upper layers internal usage. */ + +const u8_t *provisioner_net_key_get(u16_t net_idx); + +struct bt_mesh_subnet *provisioner_subnet_get(u16_t net_idx); + +bool provisioner_check_msg_dst_addr(u16_t dst_addr); + +const u8_t *provisioner_get_device_key(u16_t dst_addr); + +struct bt_mesh_app_key *provisioner_app_key_find(u16_t app_idx); + +u32_t provisioner_get_prov_node_count(void); + +/* The following APIs are for provisioner application use. */ + +int bt_mesh_provisioner_store_node_info(struct bt_mesh_node_t *node_info); + +int bt_mesh_provisioner_get_all_node_unicast_addr(struct net_buf_simple *buf); + +int bt_mesh_provisioner_set_node_name(int node_index, const char *name); + +const char *bt_mesh_provisioner_get_node_name(int node_index); + +int bt_mesh_provisioner_get_node_index(const char *name); + +struct bt_mesh_node_t *bt_mesh_provisioner_get_node_info(u16_t unicast_addr); + +u32_t bt_mesh_provisioner_get_net_key_count(void); + +u32_t bt_mesh_provisioner_get_app_key_count(void); + +int bt_mesh_provisioner_local_app_key_add(const u8_t app_key[16], u16_t net_idx, u16_t *app_idx); + +const u8_t *bt_mesh_provisioner_local_app_key_get(u16_t net_idx, u16_t app_idx); + +int bt_mesh_provisioner_local_app_key_delete(u16_t net_idx, u16_t app_idx); + +int bt_mesh_provisioner_local_net_key_add(const u8_t net_key[16], u16_t *net_idx); + +const u8_t *bt_mesh_provisioner_local_net_key_get(u16_t net_idx); + +int bt_mesh_provisioner_local_net_key_delete(u16_t net_idx); + +int bt_mesh_provisioner_get_own_unicast_addr(u16_t *addr, u8_t *elem_num); + +/* Provisioner bind local client model with proper appkey index */ +int bt_mesh_provisioner_bind_local_model_app_idx(u16_t elem_addr, u16_t mod_id, + u16_t cid, u16_t app_idx); + +/* This API can be used to change the net_idx binded with the app_idx. */ +int bt_mesh_provisioner_bind_local_app_net_idx(u16_t net_idx, u16_t app_idx); + +/* Provisioner print own element information */ +int bt_mesh_provisioner_print_local_element_info(void); + +/* The following APIs are for fast provisioning */ + +const u8_t *get_fast_prov_device_key(u16_t dst_addr); + +struct bt_mesh_subnet *get_fast_prov_subnet(u16_t net_idx); + +struct bt_mesh_app_key *get_fast_prov_app_key(u16_t net_idx, u16_t app_idx); + +u8_t bt_mesh_set_fast_prov_net_idx(u16_t net_idx); + +u8_t bt_mesh_add_fast_prov_net_key(const u8_t net_key[16]); + +const u8_t *bt_mesh_get_fast_prov_net_key(u16_t net_idx); + +const u8_t *bt_mesh_get_fast_prov_app_key(u16_t net_idx, u16_t app_idx); + +#endif /* _PROVISIONER_MAIN_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/provisioner_prov.c b/components/bt/ble_mesh/mesh_core/provisioner_prov.c new file mode 100644 index 0000000000..a07c8cec87 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/provisioner_prov.c @@ -0,0 +1,3287 @@ +// Copyright 2017-2018 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 +#include + +#include "sdkconfig.h" +#include "osi/allocator.h" +#include "osi/mutex.h" + +#include "mesh_main.h" +#include "mesh_trace.h" +#include "mesh_bearer_adapt.h" + +#include "crypto.h" +#include "adv.h" +#include "mesh.h" +#include "provisioner_prov.h" +#include "provisioner_proxy.h" +#include "provisioner_main.h" + +#if CONFIG_BLE_MESH_PROVISIONER + +/* Service data length has minus 1 type length & 2 uuid length*/ +#define BLE_MESH_PROV_SRV_DATA_LEN 0x12 +#define BLE_MESH_PROXY_SRV_DATA_LEN1 0x09 +#define BLE_MESH_PROXY_SRV_DATA_LEN2 0x11 + +/* 3 transmissions, 20ms interval */ +#define PROV_XMIT BLE_MESH_TRANSMIT(2, 20) + +#define AUTH_METHOD_NO_OOB 0x00 +#define AUTH_METHOD_STATIC 0x01 +#define AUTH_METHOD_OUTPUT 0x02 +#define AUTH_METHOD_INPUT 0x03 + +#define OUTPUT_OOB_BLINK 0x00 +#define OUTPUT_OOB_BEEP 0x01 +#define OUTPUT_OOB_VIBRATE 0x02 +#define OUTPUT_OOB_NUMBER 0x03 +#define OUTPUT_OOB_STRING 0x04 + +#define INPUT_OOB_PUSH 0x00 +#define INPUT_OOB_TWIST 0x01 +#define INPUT_OOB_NUMBER 0x02 +#define INPUT_OOB_STRING 0x03 + +#define PROV_ERR_NONE 0x00 +#define PROV_ERR_NVAL_PDU 0x01 +#define PROV_ERR_NVAL_FMT 0x02 +#define PROV_ERR_UNEXP_PDU 0x03 +#define PROV_ERR_CFM_FAILED 0x04 +#define PROV_ERR_RESOURCES 0x05 +#define PROV_ERR_DECRYPT 0x06 +#define PROV_ERR_UNEXP_ERR 0x07 +#define PROV_ERR_ADDR 0x08 + +#define PROV_INVITE 0x00 +#define PROV_CAPABILITIES 0x01 +#define PROV_START 0x02 +#define PROV_PUB_KEY 0x03 +#define PROV_INPUT_COMPLETE 0x04 +#define PROV_CONFIRM 0x05 +#define PROV_RANDOM 0x06 +#define PROV_DATA 0x07 +#define PROV_COMPLETE 0x08 +#define PROV_FAILED 0x09 + +#define PROV_ALG_P256 0x00 + +#define GPCF(gpc) (gpc & 0x03) +#define GPC_START(last_seg) (((last_seg) << 2) | 0x00) +#define GPC_ACK 0x01 +#define GPC_CONT(seg_id) (((seg_id) << 2) | 0x02) +#define GPC_CTL(op) (((op) << 2) | 0x03) + +#define START_PAYLOAD_MAX 20 +#define CONT_PAYLOAD_MAX 23 + +#define START_LAST_SEG(gpc) (gpc >> 2) +#define CONT_SEG_INDEX(gpc) (gpc >> 2) + +#define BEARER_CTL(gpc) (gpc >> 2) +#define LINK_OPEN 0x00 +#define LINK_ACK 0x01 +#define LINK_CLOSE 0x02 + +#define CLOSE_REASON_SUCCESS 0x00 +#define CLOSE_REASON_TIMEOUT 0x01 +#define CLOSE_REASON_FAILED 0x02 + +#define PROV_AUTH_VAL_SIZE 0x10 +#define PROV_CONF_SALT_SIZE 0x10 +#define PROV_CONF_KEY_SIZE 0x10 +#define PROV_DH_KEY_SIZE 0x20 +#define PROV_CONFIRM_SIZE 0x10 +#define PROV_PROV_SALT_SIZE 0x10 +#define PROV_CONF_INPUTS_SIZE 0x91 + +#define XACT_SEG_DATA(_idx, _seg) (&link[_idx].rx.buf->data[20 + ((_seg - 1) * 23)]) +#define XACT_SEG_RECV(_idx, _seg) (link[_idx].rx.seg &= ~(1 << (_seg))) + +#define XACT_NVAL 0xff + +enum { + REMOTE_PUB_KEY, /* Remote key has been received */ + LOCAL_PUB_KEY, /* Local public key is available */ + LINK_ACTIVE, /* Link has been opened */ + WAIT_GEN_DHKEY, /* Waiting for remote public key to generate DHKey */ + HAVE_DHKEY, /* DHKey has been calcualted */ + SEND_CONFIRM, /* Waiting to send Confirm value */ + WAIT_NUMBER, /* Waiting for number input from user */ + WAIT_STRING, /* Waiting for string input from user */ + TIMEOUT_START, /* Provision timeout timer has started */ + NUM_FLAGS, +}; + +/** Provisioner link structure allocation + * |--------------------------------------------------------| + * | Link(PB-ADV) | Link(PB-GATT) | + * |--------------------------------------------------------| + * |<----------------------Total Link---------------------->| + */ +struct prov_link { + BLE_MESH_ATOMIC_DEFINE(flags, NUM_FLAGS); + u8_t uuid[16]; /* check if device is being provisioned*/ + u16_t oob_info; /* oob info of this device */ + u8_t element_num; /* element num of device */ + u8_t ki_flags; /* Key refresh flag and iv update flag */ + u32_t iv_index; /* IV Index */ + u8_t auth_method; /* choosed authentication method */ + u8_t auth_action; /* choosed authentication action */ + u8_t auth_size; /* choosed authentication size */ + u16_t unicast_addr; /* unicast address assigned for device */ + bt_mesh_addr_t addr; /* Device address */ +#if defined(CONFIG_BLE_MESH_PB_GATT) + bool connecting; /* start connecting with device */ + struct bt_mesh_conn *conn; /* GATT connection */ +#endif + u8_t expect; /* Next expected PDU */ + + u8_t *dhkey; /* Calculated DHKey */ + u8_t *auth; /* Authentication Value */ + + u8_t *conf_salt; /* ConfirmationSalt */ + u8_t *conf_key; /* ConfirmationKey */ + u8_t *conf_inputs; /* ConfirmationInputs */ + + u8_t *rand; /* Local Random */ + u8_t *conf; /* Remote Confirmation */ + + u8_t *prov_salt; /* Provisioning Salt */ + +#if defined(CONFIG_BLE_MESH_PB_ADV) + bool linking; /* Linking is being establishing */ + u16_t send_link_close; /* Link close is being sent flag */ + u32_t link_id; /* Link ID */ + u8_t pending_ack; /* Decide which transaction id ack is pending */ + u8_t expect_ack_for; /* Transaction ACK expected for provisioning pdu */ + u8_t tx_pdu_type; /* The current transmitted Provisioning PDU type */ + + struct { + u8_t trans_id; /* Transaction ID */ + u8_t prev_id; /* Previous Transaction ID */ + u8_t seg; /* Bit-field of unreceived segments */ + u8_t last_seg; /* Last segment (to check length) */ + u8_t fcs; /* Expected FCS value */ + u8_t adv_buf_id; /* index of buf allocated in adv_buf_data */ + struct net_buf_simple *buf; + } rx; + + struct { + /* Start timestamp of the transaction */ + s64_t start; + + /* Transaction id*/ + u8_t trans_id; + + /* Pending outgoing buffer(s) */ + struct net_buf *buf[3]; + + /* Retransmit timer */ + struct k_delayed_work retransmit; + } tx; +#endif + + /** Provision timeout timer. Spec P259 says: The provisioning protocol + * shall have a minimum timeout of 60 seconds that is reset each time + * a provisioning protocol PDU is sent or received. + */ + struct k_delayed_work timeout; +}; + +/* Number of devices can be provisioned at the same time equals to PB-ADV + PB-GATT */ +#define BLE_MESH_PROV_SAME_TIME \ + (CONFIG_BLE_MESH_PBA_SAME_TIME + CONFIG_BLE_MESH_PBG_SAME_TIME) + +static struct prov_link link[BLE_MESH_PROV_SAME_TIME]; + +struct prov_rx { + u32_t link_id; + u8_t xact_id; + u8_t gpc; +}; + +#define BLE_MESH_ALREADY_PROV_NUM (CONFIG_BLE_MESH_MAX_PROV_NODES + 10) + +struct prov_ctx_t { + /* If provisioning random have been generated, set BIT0 to 1 */ + u8_t rand_gen_done; + + /* Provisioner random */ + u8_t random[16]; + + /* Number of provisioned devices */ + u16_t node_count; + + /* Current number of PB-ADV provisioned devices simultaneously */ + u8_t pba_count; + + /* Current number of PB-GATT provisioned devices simultaneously */ + u8_t pbg_count; + + /* Current unicast address going to assigned */ + u16_t current_addr; + + /* Current net_idx going to be used in provisioning data */ + u16_t curr_net_idx; + + /* Current flags going to be used in provisioning data */ + u16_t curr_flags; + + /* Current iv_index going to be used in provisioning data */ + u16_t curr_iv_index; + + /* Offset of the device uuid to be matched, based on zero */ + u8_t match_offset; + + /* Length of the device uuid to be matched (start from the match_offset) */ + u8_t match_length; + + /* Value of the device uuid to be matched */ + u8_t *match_value; + + /* Indicate when received uuid_match adv_pkts, can provision it at once */ + bool prov_after_match; + + /* Mutex used to protect the PB-ADV procedure */ + osi_mutex_t pb_adv_lock; + + /* Mutex used to protect the PB-GATT procedure */ + osi_mutex_t pb_gatt_lock; + + /** This structure is used to store the information of the device which + * provisioner has successfully sent provisioning data to. In this + * structure, we don't care if the device is currently in the mesh + * network, or has been removed, or failed to send provisioning + * complete pdu after receiving the provisioning data pdu. + */ + struct already_prov_info { + u8_t uuid[16]; /* device uuid */ + u8_t element_num; /* element number of the deleted node */ + u16_t unicast_addr; /* Primary unicast address of the deleted node */ + } already_prov[BLE_MESH_ALREADY_PROV_NUM]; +}; + +static struct prov_ctx_t prov_ctx; + +struct prov_node_info { + bool provisioned; /* device provisioned flag */ + bt_mesh_addr_t addr; /* device address */ + u8_t uuid[16]; /* node uuid */ + u16_t oob_info; /* oob info contained in adv pkt */ + u8_t element_num; /* element contained in this node */ + u16_t unicast_addr; /* primary unicast address of this node */ + u16_t net_idx; /* Netkey index got during provisioning */ + u8_t flags; /* Key refresh flag and iv update flag */ + u32_t iv_index; /* IV Index */ +}; + +static struct prov_node_info prov_nodes[CONFIG_BLE_MESH_MAX_PROV_NODES]; + +struct unprov_dev_queue { + bt_mesh_addr_t addr; + u8_t uuid[16]; + u16_t oob_info; + u8_t bearer; + u8_t flags; +} __packed unprov_dev[CONFIG_BLE_MESH_WAIT_FOR_PROV_MAX_DEV_NUM] = { + [0 ... (CONFIG_BLE_MESH_WAIT_FOR_PROV_MAX_DEV_NUM - 1)] = { + .addr.type = 0xff, + .bearer = 0, + .flags = false, + }, +}; + +static unprov_adv_pkt_cb_t notify_unprov_adv_pkt_cb; + +#define BUF_TIMEOUT K_MSEC(400) + +#if defined(CONFIG_BLE_MESH_FAST_PROV) +#define RETRANSMIT_TIMEOUT K_MSEC(360) +#define TRANSACTION_TIMEOUT K_SECONDS(3) +#define PROVISION_TIMEOUT K_SECONDS(6) +#else +#define RETRANSMIT_TIMEOUT K_MSEC(500) +#define TRANSACTION_TIMEOUT K_SECONDS(30) +#define PROVISION_TIMEOUT K_SECONDS(60) +#endif /* CONFIG_BLE_MESH_FAST_PROV */ + +#if defined(CONFIG_BLE_MESH_PB_GATT) +#define PROV_BUF_HEADROOM 5 +#else +#define PROV_BUF_HEADROOM 0 +#endif + +#define PROV_BUF(name, len) \ + NET_BUF_SIMPLE_DEFINE(name, PROV_BUF_HEADROOM + len) + +static const struct bt_mesh_prov *prov; + +#if defined(CONFIG_BLE_MESH_PB_ADV) +static void send_link_open(const u8_t idx); +#endif + +static void prov_gen_dh_key(const u8_t idx); + +static void send_pub_key(const u8_t idx, u8_t oob); + +static void close_link(const u8_t idx, u8_t reason); + +#if defined(CONFIG_BLE_MESH_PB_ADV) +#define ADV_BUF_SIZE 65 + +static struct prov_adv_buf { + struct net_buf_simple buf; +} adv_buf[CONFIG_BLE_MESH_PBA_SAME_TIME]; + +static u8_t adv_buf_data[ADV_BUF_SIZE * CONFIG_BLE_MESH_PBA_SAME_TIME]; +#endif + +#define PROV_FREE_MEM(_idx, member) \ +{ \ + if (link[_idx].member) { \ + osi_free(link[_idx].member); \ + } \ +} + +/* Fast provisioning uses this structure for provisioning data */ +static struct bt_mesh_fast_prov_info { + u16_t net_idx; + const u8_t *net_key; + u8_t flags; + u32_t iv_index; + u16_t unicast_addr_min; + u16_t unicast_addr_max; +} fast_prov_info; + +static bool fast_prov_flag; + +#define FAST_PROV_FLAG_GET() fast_prov_flag + +void provisioner_pbg_count_dec(void) +{ + if (prov_ctx.pbg_count) { + prov_ctx.pbg_count--; + } +} + +void provisioner_pbg_count_inc(void) +{ + prov_ctx.pbg_count++; +} + +void provisioner_clear_link_conn_info(const u8_t addr[6]) +{ +#if defined(CONFIG_BLE_MESH_PB_GATT) + u8_t i; + + if (!addr) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + BT_DBG("%s, Clear device %s info", __func__, bt_hex(addr, BLE_MESH_ADDR_LEN)); + + for (i = CONFIG_BLE_MESH_PBA_SAME_TIME; i < BLE_MESH_PROV_SAME_TIME; i++) { + if (!memcmp(link[i].addr.val, addr, BLE_MESH_ADDR_LEN)) { + link[i].connecting = false; + link[i].conn = NULL; + link[i].oob_info = 0x0; + memset(link[i].uuid, 0, 16); + memset(&link[i].addr, 0, sizeof(bt_mesh_addr_t)); + bt_mesh_atomic_test_and_clear_bit(link[i].flags, LINK_ACTIVE); + if (bt_mesh_atomic_test_and_clear_bit(link[i].flags, TIMEOUT_START)) { + k_delayed_work_cancel(&link[i].timeout); + } + return; + } + } + + BT_WARN("%s, Address %s is not found", __func__, bt_hex(addr, BLE_MESH_ADDR_LEN)); +#endif + return; +} + +const struct bt_mesh_prov *provisioner_get_prov_info(void) +{ + return prov; +} + +int provisioner_prov_reset_all_nodes(void) +{ + u16_t i; + + BT_DBG("%s", __func__); + + for (i = 0U; i < ARRAY_SIZE(prov_nodes); i++) { + if (prov_nodes[i].provisioned) { + memset(&prov_nodes[i], 0, sizeof(struct prov_node_info)); + } + } + + prov_ctx.node_count = 0; + + return 0; +} + +static int provisioner_dev_find(const bt_mesh_addr_t *addr, const u8_t uuid[16], u16_t *index) +{ + bool uuid_match = false; + bool addr_match = false; + u8_t zero[16] = {0}; + u16_t i = 0, j = 0; + int comp = 0; + + if (addr) { + comp = memcmp(addr->val, zero, BLE_MESH_ADDR_LEN); + } + + if ((!uuid && (!addr || (comp == 0) || (addr->type > BLE_MESH_ADDR_RANDOM))) || !index) { + return -EINVAL; + } + + /** Note: user may add a device into two unprov_dev array elements, + * one with device address, address type and another only + * with device UUID. We need to take this into consideration. + */ + if (uuid && memcmp(uuid, zero, 16)) { + for (i = 0; i < ARRAY_SIZE(unprov_dev); i++) { + if (!memcmp(unprov_dev[i].uuid, uuid, 16)) { + uuid_match = true; + break; + } + } + } + + if (addr && comp && (addr->type <= BLE_MESH_ADDR_RANDOM)) { + for (j = 0; j < ARRAY_SIZE(unprov_dev); j++) { + if (!memcmp(unprov_dev[j].addr.val, addr->val, BLE_MESH_ADDR_LEN) && + unprov_dev[j].addr.type == addr->type) { + addr_match = true; + break; + } + } + } + + if (!uuid_match && !addr_match) { + BT_DBG("%s, Device does not exist in queue", __func__); + return -ENODEV; + } + + if (uuid_match && addr_match && (i != j)) { + /** + * In this situation, copy address & type into device uuid + * array element, reset another element, rm_flag will be + * decided by uuid element. + */ + unprov_dev[i].addr.type = unprov_dev[j].addr.type; + memcpy(unprov_dev[i].addr.val, unprov_dev[j].addr.val, BLE_MESH_ADDR_LEN); + unprov_dev[i].bearer |= unprov_dev[j].bearer; + memset(&unprov_dev[j], 0x0, sizeof(struct unprov_dev_queue)); + } + + *index = uuid_match ? i : j; + return 0; +} + +static bool is_unprov_dev_being_provision(const u8_t uuid[16]) +{ + u16_t i; + +#if defined(CONFIG_BLE_MESH_FAST_PROV) + /** + * During Fast Provisioning test, we found that if a device has already being + * provisioned, there is still a chance that the Provisioner can receive the + * Unprovisioned Device Beacon from the device (because the device will stop + * Unprovisioned Device Beacon when Transaction ACK for Provisioning Complete + * is received). So in Fast Provisioning the Provisioner should ignore this. + */ + for (i = 0U; i < ARRAY_SIZE(prov_nodes); i++) { + if (prov_nodes[i].provisioned) { + if (!memcmp(prov_nodes[i].uuid, uuid, 16)) { + BT_WARN("Device has already been provisioned"); + return -EALREADY; + } + } + } +#endif + + for (i = 0U; i < BLE_MESH_PROV_SAME_TIME; i++) { +#if defined(CONFIG_BLE_MESH_PB_ADV) && defined(CONFIG_BLE_MESH_PB_GATT) + if (link[i].linking || link[i].connecting || + bt_mesh_atomic_test_bit(link[i].flags, LINK_ACTIVE)) { +#elif defined(CONFIG_BLE_MESH_PB_ADV) && !defined(CONFIG_BLE_MESH_PB_GATT) + if (link[i].linking || bt_mesh_atomic_test_bit(link[i].flags, LINK_ACTIVE)) { +#else + if (link[i].connecting || bt_mesh_atomic_test_bit(link[i].flags, LINK_ACTIVE)) { +#endif + if (!memcmp(link[i].uuid, uuid, 16)) { + BT_DBG("%s, Device is being provisioned", __func__); + return true; + } + } + } + + return false; +} + +static bool is_unprov_dev_uuid_match(const u8_t uuid[16]) +{ + if (prov_ctx.match_length && prov_ctx.match_value) { + if (memcmp(uuid + prov_ctx.match_offset, + prov_ctx.match_value, prov_ctx.match_length)) { + return false; + } + } + + return true; +} + +static int provisioner_check_unprov_dev_info(const u8_t uuid[16]) +{ + u16_t i; + + if (!uuid) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + /* Check if the device uuid matches configured value */ + if (is_unprov_dev_uuid_match(uuid) == false) { + BT_DBG("%s, Device uuid is not matched", __func__); + return -EIO; + } + + /* Check if this device is currently being provisioned. + * According to Zephyr's device code, if we connect with + * one device and start to provision it, we may still can + * receive the connectable prov adv pkt from this device. + * Here we check both PB-GATT and PB-ADV link status. + */ + if (is_unprov_dev_being_provision(uuid)) { + return -EALREADY; + } + + /* Check if this device is currently being provisioned. + * According to Zephyr's device code, if we connect with + * one device and start to provision it, we may still can + * receive the connectable prov adv pkt from this device. + * Here we check both PB-GATT and PB-ADV link status. + */ + if (is_unprov_dev_being_provision(uuid)) { + return -EALREADY; + } + + /* Check if the device has already been provisioned */ + for (i = 0U; i < ARRAY_SIZE(prov_nodes); i++) { + if (prov_nodes[i].provisioned) { + if (!memcmp(prov_nodes[i].uuid, uuid, 16)) { + BT_WARN("Provisioned before, start to provision again"); + provisioner_node_reset(i); + memset(&prov_nodes[i], 0, sizeof(struct prov_node_info)); + if (prov_ctx.node_count) { + prov_ctx.node_count--; + } + return 0; + } + } + } + + /* Check if the prov_nodes queue is full */ + if (prov_ctx.node_count == ARRAY_SIZE(prov_nodes)) { + BT_WARN("Current provisioned devices reach max limit"); + return -ENOMEM; + } + + return 0; +} + +#if defined(CONFIG_BLE_MESH_PB_ADV) +static int provisioner_start_prov_pb_adv(const u8_t uuid[16], + const bt_mesh_addr_t *addr, u16_t oob_info) +{ + u8_t zero[6] = {0}; + int addr_cmp; + u8_t i; + + if (!uuid || !addr) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + osi_mutex_lock(&prov_ctx.pb_adv_lock, OSI_MUTEX_MAX_TIMEOUT); + + if (is_unprov_dev_being_provision(uuid)) { + osi_mutex_unlock(&prov_ctx.pb_adv_lock); + return -EALREADY; + } + + addr_cmp = memcmp(addr->val, zero, BLE_MESH_ADDR_LEN); + + for (i = 0U; i < CONFIG_BLE_MESH_PBA_SAME_TIME; i++) { + if (!bt_mesh_atomic_test_bit(link[i].flags, LINK_ACTIVE) && !link[i].linking) { + memcpy(link[i].uuid, uuid, 16); + link[i].oob_info = oob_info; + if (addr_cmp && (addr->type <= BLE_MESH_ADDR_RANDOM)) { + link[i].addr.type = addr->type; + memcpy(link[i].addr.val, addr->val, BLE_MESH_ADDR_LEN); + } + send_link_open(i); + osi_mutex_unlock(&prov_ctx.pb_adv_lock); + return 0; + } + } + + BT_ERR("%s, No PB-ADV link is available", __func__); + osi_mutex_unlock(&prov_ctx.pb_adv_lock); + return -ENOMEM; +} +#endif /* CONFIG_BLE_MESH_PB_ADV */ + +#if defined(CONFIG_BLE_MESH_PB_GATT) +static int provisioner_start_prov_pb_gatt(const u8_t uuid[16], + const bt_mesh_addr_t *addr, u16_t oob_info) +{ + u8_t zero[6] = {0}; + int addr_cmp; + u8_t i; + + if (!uuid || !addr) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + osi_mutex_lock(&prov_ctx.pb_gatt_lock, OSI_MUTEX_MAX_TIMEOUT); + + if (is_unprov_dev_being_provision(uuid)) { + osi_mutex_unlock(&prov_ctx.pb_gatt_lock); + return -EALREADY; + } + + addr_cmp = memcmp(addr->val, zero, BLE_MESH_ADDR_LEN); + + for (i = CONFIG_BLE_MESH_PBA_SAME_TIME; i < BLE_MESH_PROV_SAME_TIME; i++) { + if (!link[i].connecting && !bt_mesh_atomic_test_bit(link[i].flags, LINK_ACTIVE)) { + memcpy(link[i].uuid, uuid, 16); + link[i].oob_info = oob_info; + if (addr_cmp && (addr->type <= BLE_MESH_ADDR_RANDOM)) { + link[i].addr.type = addr->type; + memcpy(link[i].addr.val, addr->val, BLE_MESH_ADDR_LEN); + } + if (bt_mesh_gattc_conn_create(&link[i].addr, BLE_MESH_UUID_MESH_PROV_VAL)) { + memset(link[i].uuid, 0, 16); + link[i].oob_info = 0x0; + memset(&link[i].addr, 0, sizeof(bt_mesh_addr_t)); + osi_mutex_unlock(&prov_ctx.pb_gatt_lock); + return -EIO; + } + /* If creating connection successfully, set connecting flag to 1 */ + link[i].connecting = true; + osi_mutex_unlock(&prov_ctx.pb_gatt_lock); + return 0; + } + } + + BT_ERR("%s, No PB-GATT link is available", __func__); + osi_mutex_unlock(&prov_ctx.pb_gatt_lock); + return -ENOMEM; +} +#endif /* CONFIG_BLE_MESH_PB_GATT */ + +int bt_mesh_provisioner_add_unprov_dev(struct bt_mesh_unprov_dev_add *add_dev, u8_t flags) +{ + bt_mesh_addr_t add_addr = {0}; + u8_t zero[16] = {0}; + int addr_cmp = 0; + int uuid_cmp = 0; + u16_t i; + int err; + + if (!add_dev) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + addr_cmp = memcmp(add_dev->addr, zero, BLE_MESH_ADDR_LEN); + uuid_cmp = memcmp(add_dev->uuid, zero, 16); + + if (add_dev->bearer == 0x0 || ((uuid_cmp == 0) && + ((addr_cmp == 0) || add_dev->addr_type > BLE_MESH_ADDR_RANDOM))) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + if ((add_dev->bearer & BLE_MESH_PROV_ADV) && (add_dev->bearer & BLE_MESH_PROV_GATT) && + (flags & START_PROV_NOW)) { + BT_ERR("%s, Can not start PB-ADV & PB-GATT simultaneouly", __func__); + return -EINVAL; + } + + if ((uuid_cmp == 0) && (flags & START_PROV_NOW)) { + BT_ERR("%s, Can not start provisioning with zero uuid", __func__); + return -EINVAL; + } + + if ((add_dev->bearer & BLE_MESH_PROV_GATT) && (flags & START_PROV_NOW) && + ((addr_cmp == 0) || add_dev->addr_type > BLE_MESH_ADDR_RANDOM)) { + BT_ERR("%s, Invalid device address for PB-GATT", __func__); + return -EINVAL; + } + + if (add_dev->bearer & BLE_MESH_PROV_GATT) { +#if !CONFIG_BLE_MESH_PB_GATT + BT_ERR("%s, Not support PB-GATT", __func__); + return -EINVAL; +#endif + } + + if (add_dev->bearer & BLE_MESH_PROV_ADV) { +#if !CONFIG_BLE_MESH_PB_ADV + BT_ERR("%s, Not support PB-ADV", __func__); + return -EINVAL; +#endif + } + + add_addr.type = add_dev->addr_type; + memcpy(add_addr.val, add_dev->addr, BLE_MESH_ADDR_LEN); + + err = provisioner_dev_find(&add_addr, add_dev->uuid, &i); + if (err == -EINVAL) { + BT_ERR("%s, Invalid parameter", __func__); + return err; + } else if (err == 0) { + if (!(add_dev->bearer & unprov_dev[i].bearer)) { + BT_WARN("Add device with only bearer updated"); + unprov_dev[i].bearer |= add_dev->bearer; + } else { + BT_WARN("Device already exists in queue"); + } + goto start; + } + + for (i = 0U; i < ARRAY_SIZE(unprov_dev); i++) { + if (unprov_dev[i].bearer) { + continue; + } + if (addr_cmp && (add_dev->addr_type <= BLE_MESH_ADDR_RANDOM)) { + unprov_dev[i].addr.type = add_dev->addr_type; + memcpy(unprov_dev[i].addr.val, add_dev->addr, BLE_MESH_ADDR_LEN); + } + if (uuid_cmp) { + memcpy(unprov_dev[i].uuid, add_dev->uuid, 16); + } + unprov_dev[i].bearer = add_dev->bearer & BIT_MASK(2); + unprov_dev[i].flags = flags & BIT_MASK(3); + goto start; + } + + /* If queue is full, find flushable device and replace it */ + for (i = 0U; i < ARRAY_SIZE(unprov_dev); i++) { + if (unprov_dev[i].flags & FLUSHABLE_DEV) { + memset(&unprov_dev[i], 0, sizeof(struct unprov_dev_queue)); + if (addr_cmp && (add_dev->addr_type <= BLE_MESH_ADDR_RANDOM)) { + unprov_dev[i].addr.type = add_dev->addr_type; + memcpy(unprov_dev[i].addr.val, add_dev->addr, BLE_MESH_ADDR_LEN); + } + if (uuid_cmp) { + memcpy(unprov_dev[i].uuid, add_dev->uuid, 16); + } + unprov_dev[i].bearer = add_dev->bearer & BIT_MASK(2); + unprov_dev[i].flags = flags & BIT_MASK(3); + goto start; + } + } + + BT_ERR("%s, Unprovisioned device queue is full", __func__); + return -ENOMEM; + +start: + if (!(flags & START_PROV_NOW)) { + return 0; + } + + /* Check if current provisioned node count + active link reach max limit */ + if (prov_ctx.node_count + prov_ctx.pba_count + \ + prov_ctx.pbg_count >= ARRAY_SIZE(prov_nodes)) { + BT_WARN("%s, Node count + active link count reach max limit", __func__); + return -EIO; + } + + if ((err = provisioner_check_unprov_dev_info(add_dev->uuid))) { + return err; + } + + if (add_dev->bearer & BLE_MESH_PROV_ADV) { +#if defined(CONFIG_BLE_MESH_PB_ADV) + if (prov_ctx.pba_count == CONFIG_BLE_MESH_PBA_SAME_TIME) { + BT_WARN("%s, Current PB-ADV links reach max limit", __func__); + return -EIO; + } + if ((err = provisioner_start_prov_pb_adv( + add_dev->uuid, &add_addr, add_dev->oob_info))) { + return err; + } +#endif + } else if (add_dev->bearer & BLE_MESH_PROV_GATT) { +#if defined(CONFIG_BLE_MESH_PB_GATT) + if (prov_ctx.pbg_count == CONFIG_BLE_MESH_PBG_SAME_TIME) { + BT_WARN("%s, Current PB-GATT links reach max limit", __func__); + return -EIO; + } + if ((err = provisioner_start_prov_pb_gatt( + add_dev->uuid, &add_addr, add_dev->oob_info))) { + return err; + } +#endif + } + + return 0; +} + +int bt_mesh_provisioner_delete_device(struct bt_mesh_device_delete *del_dev) +{ + /** + * Three Situations: + * 1. device is not being/been provisioned, just remove from device queue. + * 2. device is being provisioned, need to close link & remove from device queue. + * 3. device is been provisioned, need to send config_node_reset and may need to + * remove from device queue. config _node_reset can be added in function + * provisioner_node_reset() in provisioner_main.c. + */ + bt_mesh_addr_t del_addr = {0}; + u8_t zero[16] = {0}; + bool addr_match = false; + bool uuid_match = false; + int addr_cmp = 0; + int uuid_cmp = 0; + u16_t i; + int err; + + if (!del_dev) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + addr_cmp = memcmp(del_dev->addr, zero, BLE_MESH_ADDR_LEN); + uuid_cmp = memcmp(del_dev->uuid, zero, 16); + + if ((uuid_cmp == 0) && ((addr_cmp == 0) || del_dev->addr_type > BLE_MESH_ADDR_RANDOM)) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + del_addr.type = del_dev->addr_type; + memcpy(del_addr.val, del_dev->addr, BLE_MESH_ADDR_LEN); + + /* First: find if the device is in the device queue */ + err = provisioner_dev_find(&del_addr, del_dev->uuid, &i); + if (err) { + BT_DBG("%s, Device is not in the queue", __func__); + } else { + memset(&unprov_dev[i], 0x0, sizeof(struct unprov_dev_queue)); + } + + /* Second: find if the device is being provisioned */ + for (i = 0U; i < ARRAY_SIZE(link); i++) { + if (addr_cmp && (del_dev->addr_type <= BLE_MESH_ADDR_RANDOM)) { + if (!memcmp(link[i].addr.val, del_dev->addr, BLE_MESH_ADDR_LEN) && + link[i].addr.type == del_dev->addr_type) { + addr_match = true; + } + } + if (uuid_cmp) { + if (!memcmp(link[i].uuid, del_dev->uuid, 16)) { + uuid_match = true; + } + } + if (addr_match || uuid_match) { + close_link(i, CLOSE_REASON_FAILED); + break; + } + } + + /* Third: find if the device is been provisioned */ + for (i = 0U; i < ARRAY_SIZE(prov_nodes); i++) { + if (addr_cmp && (del_dev->addr_type <= BLE_MESH_ADDR_RANDOM)) { + if (!memcmp(prov_nodes[i].addr.val, del_dev->addr, BLE_MESH_ADDR_LEN) && + prov_nodes[i].addr.type == del_dev->addr_type) { + addr_match = true; + } + } + if (uuid_cmp) { + if (!memcmp(prov_nodes[i].uuid, del_dev->uuid, 16)) { + uuid_match = true; + } + } + if (addr_match || uuid_match) { + memset(&prov_nodes[i], 0, sizeof(struct prov_node_info)); + provisioner_node_reset(i); + if (prov_ctx.node_count) { + prov_ctx.node_count--; + } + break; + } + } + + return 0; +} + +int bt_mesh_provisioner_set_dev_uuid_match(u8_t offset, u8_t length, + const u8_t *match, bool prov_flag) +{ + if (length && (!match || (offset + length > 16))) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + if (length && !prov_ctx.match_value) { + prov_ctx.match_value = osi_calloc(16); + if (!prov_ctx.match_value) { + BT_ERR("%s, Failed to allocate memory", __func__); + return -ENOMEM; + } + } + + prov_ctx.match_offset = offset; + prov_ctx.match_length = length; + if (length) { + memcpy(prov_ctx.match_value, match, length); + } + prov_ctx.prov_after_match = prov_flag; + + return 0; +} + +int bt_mesh_prov_adv_pkt_cb_register(unprov_adv_pkt_cb_t cb) +{ + if (!cb) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + notify_unprov_adv_pkt_cb = cb; + return 0; +} + +int bt_mesh_provisioner_set_prov_data_info(struct bt_mesh_prov_data_info *info) +{ + const u8_t *key = NULL; + + if (!info || info->flag == 0) { + return -EINVAL; + } + + if (info->flag & NET_IDX_FLAG) { + key = provisioner_net_key_get(info->net_idx); + if (!key) { + BT_ERR("%s, Failed to get NetKey", __func__); + return -EINVAL; + } + prov_ctx.curr_net_idx = info->net_idx; + } else if (info->flag & FLAGS_FLAG) { + prov_ctx.curr_flags = info->flags; + } else if (info->flag & IV_INDEX_FLAG) { + prov_ctx.curr_iv_index = info->iv_index; + } + + return 0; +} + +/* The following APIs are for fast provisioning */ + +void provisioner_set_fast_prov_flag(bool flag) +{ + fast_prov_flag = flag; +} + +u8_t provisioner_set_fast_prov_net_idx(const u8_t *net_key, u16_t net_idx) +{ + fast_prov_info.net_idx = net_idx; + fast_prov_info.net_key = net_key; + + if (!net_key) { + BT_WARN("%s, Wait for NetKey for fast provisioning", __func__); + return 0x01; /*status: wait for net_key */ + } + + return 0x0; /* status: success */ +} + +u16_t provisioner_get_fast_prov_net_idx(void) +{ + return fast_prov_info.net_idx; +} + +u8_t bt_mesh_set_fast_prov_unicast_addr_range(u16_t min, u16_t max) +{ + if (!BLE_MESH_ADDR_IS_UNICAST(min) || !BLE_MESH_ADDR_IS_UNICAST(max)) { + BT_ERR("%s, Not a unicast address", __func__); + return 0x01; /* status: not a unicast address */ + } + + if (min > max) { + BT_ERR("%s, Min bigger than max", __func__); + return 0x02; /* status: min is bigger than max */ + } + + if (min <= fast_prov_info.unicast_addr_max) { + BT_ERR("%s, Address overlap", __func__); + return 0x03; /* status: address overlaps with current value */ + } + + fast_prov_info.unicast_addr_min = min; + fast_prov_info.unicast_addr_max = max; + + prov_ctx.current_addr = fast_prov_info.unicast_addr_min; + + return 0x0; /* status: success */ +} + +void bt_mesh_set_fast_prov_flags_iv_index(u8_t flags, u32_t iv_index) +{ + /* BIT0: Key Refreash flag, BIT1: IV Update flag */ + fast_prov_info.flags = flags & BIT_MASK(2); + fast_prov_info.iv_index = iv_index; +} + +#if defined(CONFIG_BLE_MESH_PB_ADV) +static struct net_buf_simple *bt_mesh_pba_get_buf(const u8_t idx) +{ + struct net_buf_simple *buf = &(adv_buf[idx].buf); + + net_buf_simple_reset(buf); + + return buf; +} +#endif /* CONFIG_BLE_MESH_PB_ADV */ + +static void prov_memory_free(const u8_t idx) +{ + PROV_FREE_MEM(idx, dhkey); + PROV_FREE_MEM(idx, auth); + PROV_FREE_MEM(idx, conf); + PROV_FREE_MEM(idx, conf_salt); + PROV_FREE_MEM(idx, conf_key); + PROV_FREE_MEM(idx, conf_inputs); + PROV_FREE_MEM(idx, prov_salt); +} + +#if defined(CONFIG_BLE_MESH_PB_ADV) +static void buf_sent(int err, void *user_data) +{ + u8_t idx = (int)user_data; + + if (!link[idx].tx.buf[0]) { + return; + } + + k_delayed_work_submit(&link[idx].tx.retransmit, RETRANSMIT_TIMEOUT); +} + +static struct bt_mesh_send_cb buf_sent_cb = { + .end = buf_sent, +}; + +static void free_segments(const u8_t idx) +{ + u8_t i; + + for (i = 0U; i < ARRAY_SIZE(link[idx].tx.buf); i++) { + struct net_buf *buf = link[idx].tx.buf[i]; + + if (!buf) { + break; + } + + link[idx].tx.buf[i] = NULL; + /* Mark as canceled */ + BLE_MESH_ADV(buf)->busy = 0; + /** Change by Espressif. Add this to avoid buf->ref is 2 which will + * cause lack of buf. + */ + if (buf->ref > 1) { + buf->ref = 1; + } + net_buf_unref(buf); + } +} + +static void prov_clear_tx(const u8_t idx) +{ + BT_DBG("%s", __func__); + + k_delayed_work_cancel(&link[idx].tx.retransmit); + + free_segments(idx); +} + +static void reset_link(const u8_t idx, u8_t reason) +{ + prov_clear_tx(idx); + + if (bt_mesh_atomic_test_and_clear_bit(link[idx].flags, TIMEOUT_START)) { + k_delayed_work_cancel(&link[idx].timeout); + } + + if (prov->prov_link_close) { + prov->prov_link_close(BLE_MESH_PROV_ADV, reason); + } + + prov_memory_free(idx); + +#if defined(CONFIG_BLE_MESH_USE_DUPLICATE_SCAN) + /* Remove the link id from exceptional list */ + bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_REMOVE, + BLE_MESH_EXCEP_INFO_MESH_LINK_ID, &link[idx].link_id); +#endif + + /* Clear everything except the retransmit delayed work config */ + memset(&link[idx], 0, offsetof(struct prov_link, tx.retransmit)); + + link[idx].pending_ack = XACT_NVAL; + link[idx].rx.prev_id = XACT_NVAL; + + if (bt_mesh_pub_key_get()) { + bt_mesh_atomic_set_bit(link[idx].flags, LOCAL_PUB_KEY); + } + + link[idx].rx.buf = bt_mesh_pba_get_buf(idx); + + if (prov_ctx.pba_count) { + prov_ctx.pba_count--; + } +} + +static struct net_buf *adv_buf_create(void) +{ + struct net_buf *buf; + + buf = bt_mesh_adv_create(BLE_MESH_ADV_PROV, PROV_XMIT, BUF_TIMEOUT); + if (!buf) { + BT_ERR("Out of provisioning buffers"); + return NULL; + } + + return buf; +} + +static void ack_complete(u16_t duration, int err, void *user_data) +{ + u8_t idx = (int)user_data; + + BT_DBG("xact %u complete", link[idx].pending_ack); + + link[idx].pending_ack = XACT_NVAL; +} + +static void gen_prov_ack_send(const u8_t idx, u8_t xact_id) +{ + static const struct bt_mesh_send_cb cb = { + .start = ack_complete, + }; + const struct bt_mesh_send_cb *complete; + struct net_buf *buf; + + BT_DBG("xact_id %u", xact_id); + + if (link[idx].pending_ack == xact_id) { + BT_DBG("Not sending duplicate ack"); + return; + } + + buf = adv_buf_create(); + if (!buf) { + return; + } + + if (link[idx].pending_ack == XACT_NVAL) { + link[idx].pending_ack = xact_id; + complete = &cb; + } else { + complete = NULL; + } + + net_buf_add_be32(buf, link[idx].link_id); + net_buf_add_u8(buf, xact_id); + net_buf_add_u8(buf, GPC_ACK); + + bt_mesh_adv_send(buf, complete, (void *)(int)idx); + net_buf_unref(buf); +} + +static void send_reliable(const u8_t idx) +{ + u8_t i; + + link[idx].tx.start = k_uptime_get(); + + for (i = 0U; i < ARRAY_SIZE(link[idx].tx.buf); i++) { + struct net_buf *buf = link[idx].tx.buf[i]; + + if (!buf) { + break; + } + + if (i + 1 < ARRAY_SIZE(link[idx].tx.buf) && link[idx].tx.buf[i + 1]) { + bt_mesh_adv_send(buf, NULL, NULL); + } else { + bt_mesh_adv_send(buf, &buf_sent_cb, (void *)(int)idx); + } + } +} + +static int bearer_ctl_send(const u8_t idx, u8_t op, void *data, u8_t data_len) +{ + struct net_buf *buf; + + BT_DBG("op 0x%02x data_len %u", op, data_len); + + prov_clear_tx(idx); + + buf = adv_buf_create(); + if (!buf) { + return -ENOBUFS; + } + + net_buf_add_be32(buf, link[idx].link_id); + /* Transaction ID, always 0 for Bearer messages */ + net_buf_add_u8(buf, 0x00); + net_buf_add_u8(buf, GPC_CTL(op)); + net_buf_add_mem(buf, data, data_len); + + link[idx].tx.buf[0] = buf; + send_reliable(idx); + + /** We can also use buf->ref and a flag to decide that + * link close has been sent 3 times. + * Here we use another way: use retransmit timer and need + * to make sure the timer is not cancelled during sending + * link close pdu, so we add link[i].tx.id = 0 + */ + if (op == LINK_CLOSE) { + u8_t reason = *(u8_t *)data; + link[idx].send_link_close = ((reason & BIT_MASK(2)) << 1) | BIT(0); + link[idx].tx.trans_id = 0; + } + + return 0; +} + +static void send_link_open(const u8_t idx) +{ + u8_t j; + + /** Generate link ID, and may need to check if this id is + * currently being used, which may will not happen ever. + */ + bt_mesh_rand(&link[idx].link_id, sizeof(u32_t)); + while (1) { + for (j = 0U; j < CONFIG_BLE_MESH_PBA_SAME_TIME; j++) { + if (bt_mesh_atomic_test_bit(link[j].flags, LINK_ACTIVE) || link[j].linking) { + if (link[idx].link_id == link[j].link_id) { + bt_mesh_rand(&link[idx].link_id, sizeof(u32_t)); + break; + } + } + } + if (j == CONFIG_BLE_MESH_PBA_SAME_TIME) { + break; + } + } + +#if defined(CONFIG_BLE_MESH_USE_DUPLICATE_SCAN) + /* Add the link id into exceptional list */ + bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_ADD, + BLE_MESH_EXCEP_INFO_MESH_LINK_ID, &link[idx].link_id); +#endif + + bearer_ctl_send(idx, LINK_OPEN, link[idx].uuid, 16); + + /* If Provisioner sets LINK_ACTIVE flag once Link Open is sent, we have + * no need to use linking flag (like PB-GATT connecting) to prevent the + * stored device info (UUID, oob_info) being replaced by other received + * unprovisioned device beacons. + * But if Provisioner sets LINK_ACTIVE flag after Link ACK is received, + * we need to use linking flag to prevent device info being replaced. + * Currently we set LINK_ACTIVE flag after sending Link Open. + */ + link[idx].linking = true; + + /* Set LINK_ACTIVE just to be in compatibility with current Zephyr code */ + bt_mesh_atomic_set_bit(link[idx].flags, LINK_ACTIVE); + + if (prov->prov_link_open) { + prov->prov_link_open(BLE_MESH_PROV_ADV); + } + + prov_ctx.pba_count++; +} + +static u8_t last_seg(u8_t len) +{ + if (len <= START_PAYLOAD_MAX) { + return 0; + } + + len -= START_PAYLOAD_MAX; + + return 1 + (len / CONT_PAYLOAD_MAX); +} + +static inline u8_t next_transaction_id(const u8_t idx) +{ + if (link[idx].tx.trans_id > 0x7F) { + link[idx].tx.trans_id = 0x0; + } + return link[idx].tx.trans_id++; +} + +static int prov_send_adv(const u8_t idx, struct net_buf_simple *msg) +{ + struct net_buf *start, *buf; + u8_t seg_len, seg_id; + u8_t xact_id; + s32_t timeout = PROVISION_TIMEOUT; + + BT_DBG("%s, len %u: %s", __func__, msg->len, bt_hex(msg->data, msg->len)); + + prov_clear_tx(idx); + + start = adv_buf_create(); + if (!start) { + return -ENOBUFS; + } + + xact_id = next_transaction_id(idx); + net_buf_add_be32(start, link[idx].link_id); + net_buf_add_u8(start, xact_id); + + net_buf_add_u8(start, GPC_START(last_seg(msg->len))); + net_buf_add_be16(start, msg->len); + net_buf_add_u8(start, bt_mesh_fcs_calc(msg->data, msg->len)); + + link[idx].tx.buf[0] = start; + /* Changed by Espressif, get message type */ + link[idx].tx_pdu_type = msg->data[0]; + + seg_len = MIN(msg->len, START_PAYLOAD_MAX); + BT_DBG("seg 0 len %u: %s", seg_len, bt_hex(msg->data, seg_len)); + net_buf_add_mem(start, msg->data, seg_len); + net_buf_simple_pull(msg, seg_len); + + buf = start; + for (seg_id = 1; msg->len > 0; seg_id++) { + if (seg_id >= ARRAY_SIZE(link[idx].tx.buf)) { + BT_ERR("%s, Too big message", __func__); + free_segments(idx); + return -E2BIG; + } + + buf = adv_buf_create(); + if (!buf) { + free_segments(idx); + return -ENOBUFS; + } + + link[idx].tx.buf[seg_id] = buf; + + seg_len = MIN(msg->len, CONT_PAYLOAD_MAX); + + BT_DBG("seg_id %u len %u: %s", seg_id, seg_len, + bt_hex(msg->data, seg_len)); + + net_buf_add_be32(buf, link[idx].link_id); + net_buf_add_u8(buf, xact_id); + net_buf_add_u8(buf, GPC_CONT(seg_id)); + net_buf_add_mem(buf, msg->data, seg_len); + net_buf_simple_pull(msg, seg_len); + } + + send_reliable(idx); + +#if defined(CONFIG_BLE_MESH_FAST_PROV) + if (link[idx].tx_pdu_type >= PROV_DATA) { + timeout = K_SECONDS(60); + } +#endif + if (!bt_mesh_atomic_test_and_set_bit(link[idx].flags, TIMEOUT_START)) { + k_delayed_work_submit(&link[idx].timeout, timeout); + } + + return 0; +} +#endif /* CONFIG_BLE_MESH_PB_ADV */ + +#if defined(CONFIG_BLE_MESH_PB_GATT) +static int prov_send_gatt(const u8_t idx, struct net_buf_simple *msg) +{ + int err; + + if (!link[idx].conn) { + return -ENOTCONN; + } + + err = provisioner_proxy_send(link[idx].conn, BLE_MESH_PROXY_PROV, msg); + if (err) { + BT_ERR("%s, Failed to send PB-GATT pdu", __func__); + return err; + } + + if (!bt_mesh_atomic_test_and_set_bit(link[idx].flags, TIMEOUT_START)) { + k_delayed_work_submit(&link[idx].timeout, PROVISION_TIMEOUT); + } + + return 0; +} +#endif /* CONFIG_BLE_MESH_PB_GATT */ + +static inline int prov_send(const u8_t idx, struct net_buf_simple *buf) +{ +#if defined(CONFIG_BLE_MESH_PB_ADV) + if (idx < CONFIG_BLE_MESH_PBA_SAME_TIME) { + return prov_send_adv(idx, buf); + } +#endif + +#if defined(CONFIG_BLE_MESH_PB_GATT) + if (idx < BLE_MESH_PROV_SAME_TIME +#if defined(CONFIG_BLE_MESH_PB_ADV) + && idx >= CONFIG_BLE_MESH_PBA_SAME_TIME +#endif + ) { + return prov_send_gatt(idx, buf); + } +#endif + + BT_ERR("%s, Invalid link index %d", __func__, idx); + return -EINVAL; +} + +static void prov_buf_init(struct net_buf_simple *buf, u8_t type) +{ + net_buf_simple_reserve(buf, PROV_BUF_HEADROOM); + net_buf_simple_add_u8(buf, type); +} + +static void prov_invite(const u8_t idx, const u8_t *data) +{ + BT_DBG("%s", __func__); +} + +static void prov_start(const u8_t idx, const u8_t *data) +{ + BT_DBG("%s", __func__); +} + +static void prov_data(const u8_t idx, const u8_t *data) +{ + BT_DBG("%s", __func__); +} + +static void send_invite(const u8_t idx) +{ + PROV_BUF(buf, 2); + + prov_buf_init(&buf, PROV_INVITE); + + net_buf_simple_add_u8(&buf, prov->prov_attention); + + link[idx].conf_inputs[0] = prov->prov_attention; + + if (prov_send(idx, &buf)) { + BT_ERR("%s, Failed to send Provisioning Invite", __func__); + close_link(idx, CLOSE_REASON_FAILED); + return; + } + + link[idx].expect = PROV_CAPABILITIES; +} + +static void prov_capabilities(const u8_t idx, const u8_t *data) +{ + PROV_BUF(buf, 6); + u16_t algorithms, output_action, input_action; + u8_t element_num, pub_key_oob, static_oob, + output_size, input_size; + u8_t auth_method, auth_action, auth_size; + + element_num = data[0]; + BT_DBG("Elements: %u", element_num); + if (!element_num) { + BT_ERR("%s, Invalid element number", __func__); + goto fail; + } + link[idx].element_num = element_num; + + algorithms = sys_get_be16(&data[1]); + BT_DBG("Algorithms: %u", algorithms); + if (algorithms != BIT(PROV_ALG_P256)) { + BT_ERR("%s, Invalid algorithms", __func__); + goto fail; + } + + pub_key_oob = data[3]; + BT_DBG("Public Key Type: 0x%02x", pub_key_oob); + if (pub_key_oob > 0x01) { + BT_ERR("%s, Invalid public key type", __func__); + goto fail; + } + pub_key_oob = ((prov->prov_pub_key_oob && + prov->prov_pub_key_oob_cb) ? pub_key_oob : 0x00); + + static_oob = data[4]; + BT_DBG("Static OOB Type: 0x%02x", static_oob); + if (static_oob > 0x01) { + BT_ERR("%s, Invalid Static OOB type", __func__); + goto fail; + } + static_oob = (prov->prov_static_oob_val ? static_oob : 0x00); + + output_size = data[5]; + BT_DBG("Output OOB Size: %u", output_size); + if (output_size > 0x08) { + BT_ERR("%s, Invalid Output OOB size", __func__); + goto fail; + } + + output_action = sys_get_be16(&data[6]); + BT_DBG("Output OOB Action: 0x%04x", output_action); + if (output_action > 0x1f) { + BT_ERR("%s, Invalid Output OOB action", __func__); + goto fail; + } + + /* Provisioner select output action */ + if (prov->prov_input_num && output_size) { + output_action = __builtin_ctz(output_action); + } else { + output_size = 0x0; + output_action = 0x0; + } + + input_size = data[8]; + BT_DBG("Input OOB Size: %u", input_size); + if (input_size > 0x08) { + BT_ERR("%s, Invalid Input OOB size", __func__); + goto fail; + } + + input_action = sys_get_be16(&data[9]); + BT_DBG("Input OOB Action: 0x%04x", input_action); + if (input_action > 0x0f) { + BT_ERR("%s, Invalid Input OOB action", __func__); + goto fail; + } + + /* Make sure received pdu is ok and cancel the timeout timer */ + if (bt_mesh_atomic_test_and_clear_bit(link[idx].flags, TIMEOUT_START)) { + k_delayed_work_cancel(&link[idx].timeout); + } + + /* Provisioner select input action */ + if (prov->prov_output_num && input_size) { + input_action = __builtin_ctz(input_action); + } else { + input_size = 0x0; + input_action = 0x0; + } + + if (static_oob) { + /* if static oob is valid, just use static oob */ + auth_method = AUTH_METHOD_STATIC; + auth_action = 0x00; + auth_size = 0x00; + } else { + if (!output_size && !input_size) { + auth_method = AUTH_METHOD_NO_OOB; + auth_action = 0x00; + auth_size = 0x00; + } else if (!output_size && input_size) { + auth_method = AUTH_METHOD_INPUT; + auth_action = (u8_t)input_action; + auth_size = input_size; + } else { + auth_method = AUTH_METHOD_OUTPUT; + auth_action = (u8_t)output_action; + auth_size = output_size; + } + } + + /* Store provisioning capbilities value in conf_inputs */ + memcpy(&link[idx].conf_inputs[1], data, 11); + + prov_buf_init(&buf, PROV_START); + net_buf_simple_add_u8(&buf, prov->prov_algorithm); + net_buf_simple_add_u8(&buf, pub_key_oob); + net_buf_simple_add_u8(&buf, auth_method); + net_buf_simple_add_u8(&buf, auth_action); + net_buf_simple_add_u8(&buf, auth_size); + + memcpy(&link[idx].conf_inputs[12], &buf.data[1], 5); + + if (prov_send(idx, &buf)) { + BT_ERR("%s, Failed to send Provisioning Start", __func__); + goto fail; + } + + link[idx].auth_method = auth_method; + link[idx].auth_action = auth_action; + link[idx].auth_size = auth_size; + + /** After prov start sent, use OOB to get remote public key. + * And we just follow the procedure in Figure 5.15 of Section + * 5.4.2.3 of Mesh Profile Spec. + */ + if (pub_key_oob) { + if (prov->prov_pub_key_oob_cb(idx)) { + BT_ERR("%s, Failed to notify input OOB Public Key", __func__); + goto fail; + } + } + + /** If using PB-ADV, need to listen for transaction ack, + * after ack is received, provisioner can send public key. + */ +#if defined(CONFIG_BLE_MESH_PB_ADV) + if (idx < CONFIG_BLE_MESH_PBA_SAME_TIME) { + link[idx].expect_ack_for = PROV_START; + return; + } +#endif /* CONFIG_BLE_MESH_PB_ADV */ + + send_pub_key(idx, pub_key_oob); + return; + +fail: + close_link(idx, CLOSE_REASON_FAILED); + return; +} + +static bt_mesh_output_action_t output_action(u8_t action) +{ + switch (action) { + case OUTPUT_OOB_BLINK: + return BLE_MESH_BLINK; + case OUTPUT_OOB_BEEP: + return BLE_MESH_BEEP; + case OUTPUT_OOB_VIBRATE: + return BLE_MESH_VIBRATE; + case OUTPUT_OOB_NUMBER: + return BLE_MESH_DISPLAY_NUMBER; + case OUTPUT_OOB_STRING: + return BLE_MESH_DISPLAY_STRING; + default: + return BLE_MESH_NO_OUTPUT; + } +} + +static bt_mesh_input_action_t input_action(u8_t action) +{ + switch (action) { + case INPUT_OOB_PUSH: + return BLE_MESH_PUSH; + case INPUT_OOB_TWIST: + return BLE_MESH_TWIST; + case INPUT_OOB_NUMBER: + return BLE_MESH_ENTER_NUMBER; + case INPUT_OOB_STRING: + return BLE_MESH_ENTER_STRING; + default: + return BLE_MESH_NO_INPUT; + } +} + +static int prov_auth(const u8_t idx, u8_t method, u8_t action, u8_t size) +{ + bt_mesh_output_action_t output; + bt_mesh_input_action_t input; + + link[idx].auth = (u8_t *)osi_calloc(PROV_AUTH_VAL_SIZE); + if (!link[idx].auth) { + BT_ERR("%s, Failed to allocate memory", __func__); + close_link(idx, CLOSE_REASON_FAILED); + return -ENOMEM; + } + + switch (method) { + case AUTH_METHOD_NO_OOB: + if (action || size) { + return -EINVAL; + } + memset(link[idx].auth, 0, 16); + return 0; + + case AUTH_METHOD_STATIC: + if (action || size) { + return -EINVAL; + } + memcpy(link[idx].auth + 16 - prov->prov_static_oob_len, + prov->prov_static_oob_val, prov->prov_static_oob_len); + memset(link[idx].auth, 0, 16 - prov->prov_static_oob_len); + return 0; + + case AUTH_METHOD_OUTPUT: + /* Use auth_action to get device output action */ + output = output_action(action); + if (!output) { + return -EINVAL; + } + return prov->prov_input_num(AUTH_METHOD_OUTPUT, output, size, idx); + + case AUTH_METHOD_INPUT: + /* Use auth_action to get device input action */ + input = input_action(action); + if (!input) { + return -EINVAL; + } + + /* Provisioner ouputs number/string and wait for device's Provisioning Input Complete PDU */ + link[idx].expect = PROV_INPUT_COMPLETE; + + if (input == BLE_MESH_ENTER_STRING) { + unsigned char str[9]; + u8_t j; + + bt_mesh_rand(str, size); + /* Normalize to '0' .. '9' & 'A' .. 'Z' */ + for (j = 0; j < size; j++) { + str[j] %= 36; + if (str[j] < 10) { + str[j] += '0'; + } else { + str[j] += 'A' - 10; + } + } + str[size] = '\0'; + + memcpy(link[idx].auth, str, size); + memset(link[idx].auth + size, 0, sizeof(link[idx].auth) - size); + + return prov->prov_output_num(AUTH_METHOD_INPUT, input, str, size, idx); + } else { + u32_t div[8] = { 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 }; + u32_t num; + + bt_mesh_rand(&num, sizeof(num)); + num %= div[size - 1]; + + sys_put_be32(num, &link[idx].auth[12]); + memset(link[idx].auth, 0, 12); + + return prov->prov_output_num(AUTH_METHOD_INPUT, input, &num, size, idx); + } + + default: + return -EINVAL; + } +} + +static void send_confirm(const u8_t idx) +{ + PROV_BUF(buf, 17); + + BT_DBG("ConfInputs[0] %s", bt_hex(link[idx].conf_inputs, 64)); + BT_DBG("ConfInputs[64] %s", bt_hex(link[idx].conf_inputs + 64, 64)); + BT_DBG("ConfInputs[128] %s", bt_hex(link[idx].conf_inputs + 128, 17)); + + link[idx].conf_salt = (u8_t *)osi_calloc(PROV_CONF_SALT_SIZE); + if (!link[idx].conf_salt) { + BT_ERR("%s, Failed to allocate memory", __func__); + goto fail; + } + + link[idx].conf_key = (u8_t *)osi_calloc(PROV_CONF_KEY_SIZE); + if (!link[idx].conf_key) { + BT_ERR("%s, Failed to allocate memory", __func__); + goto fail; + } + + if (bt_mesh_prov_conf_salt(link[idx].conf_inputs, link[idx].conf_salt)) { + BT_ERR("%s, Failed to generate confirmation salt", __func__); + goto fail; + } + + BT_DBG("ConfirmationSalt: %s", bt_hex(link[idx].conf_salt, 16)); + + if (bt_mesh_prov_conf_key(link[idx].dhkey, link[idx].conf_salt, link[idx].conf_key)) { + BT_ERR("%s, Failed to generate confirmation key", __func__); + goto fail; + } + + BT_DBG("ConfirmationKey: %s", bt_hex(link[idx].conf_key, 16)); + + /** Provisioner use the same random number for each provisioning + * device, if different random need to be used, here provisioner + * should allocate memory for rand and call bt_mesh_rand() every time. + */ + if (!(prov_ctx.rand_gen_done & BIT(0))) { + if (bt_mesh_rand(prov_ctx.random, 16)) { + BT_ERR("%s, Failed to generate random number", __func__); + goto fail; + } + link[idx].rand = prov_ctx.random; + prov_ctx.rand_gen_done |= BIT(0); + } else { + /* Provisioner random has already been generated. */ + link[idx].rand = prov_ctx.random; + } + + BT_DBG("LocalRandom: %s", bt_hex(link[idx].rand, 16)); + + prov_buf_init(&buf, PROV_CONFIRM); + + if (bt_mesh_prov_conf(link[idx].conf_key, link[idx].rand, link[idx].auth, + net_buf_simple_add(&buf, 16))) { + BT_ERR("%s, Failed to generate confirmation value", __func__); + goto fail; + } + + if (prov_send(idx, &buf)) { + BT_ERR("%s, Failed to send Provisioning Confirm", __func__); + goto fail; + } + + link[idx].expect = PROV_CONFIRM; + return; + +fail: + close_link(idx, CLOSE_REASON_FAILED); + return; +} + +int bt_mesh_prov_set_oob_input_data(const u8_t idx, const u8_t *val, bool num_flag) +{ + /** This function should be called in the prov_input_num + * callback, after the data output by device has been + * input by provisioner. + * Paramter size is used to indicate the length of data + * indicated by Pointer val, for example, if device output + * data is 12345678(decimal), the data in auth value will + * be 0xBC614E. + * Parameter num_flag is used to indicate whether the value + * input by provisioner is number or string. + */ + if (!link[idx].auth) { + BT_ERR("%s, Link auth is NULL", __func__); + return -EINVAL; + } + + memset(link[idx].auth, 0, 16); + if (num_flag) { + /* Provisioner inputs number */ + memcpy(link[idx].auth + 12, val, sizeof(u32_t)); + } else { + /* Provisioner inputs string */ + memcpy(link[idx].auth, val, link[idx].auth_size); + } + + send_confirm(idx); + return 0; +} + +#if 0 +int bt_mesh_prov_set_oob_output_data(const u8_t idx, u8_t *num, u8_t size, bool num_flag) +{ + /** This function should be called in the prov_output_num + * callback, after the data has been output by provisioner. + * Parameter size is used to indicate the length of data + * indicated by Pointer num, for example, if provisioner + * output data is 12345678(decimal), the data in auth value + * will be 0xBC614E. + * Parameter num_flag is used to indicate whether the value + * output by provisioner is number or string. + */ + if (!link[idx].auth) { + BT_ERR("%s, link auth is NULL", __func__); + return -EINVAL; + } + + if (num_flag) { + /* Provisioner output number */ + memset(link[idx].auth, 0, 16); + memcpy(link[idx].auth + 16 - size, num, size); + } else { + /* Provisioner output string */ + memset(link[idx].auth, 0, 16); + memcpy(link[idx].auth, num, size); + } + + link[idx].expect = PROV_INPUT_COMPLETE; + + return 0; +} +#endif + +int bt_mesh_prov_read_oob_pub_key(const u8_t idx, const u8_t pub_key_x[32], const u8_t pub_key_y[32]) +{ + if (!link[idx].conf_inputs) { + BT_ERR("%s, Link conf_inputs is NULL", __func__); + return -EINVAL; + } + + /* Swap X and Y halves independently to big-endian */ + sys_memcpy_swap(&link[idx].conf_inputs[81], pub_key_x, 32); + sys_memcpy_swap(&link[idx].conf_inputs[81] + 32, pub_key_y, 32); + + bt_mesh_atomic_set_bit(link[idx].flags, REMOTE_PUB_KEY); + + if (bt_mesh_atomic_test_and_clear_bit(link[idx].flags, WAIT_GEN_DHKEY)) { + prov_gen_dh_key(idx); + } + + return 0; +} + +static void prov_dh_key_cb(const u8_t key[32], const u8_t idx) +{ + BT_DBG("%p", key); + + if (!key) { + BT_ERR("%s, Failed to generate DHKey", __func__); + goto fail; + } + + link[idx].dhkey = (u8_t *)osi_calloc(PROV_DH_KEY_SIZE); + if (!link[idx].dhkey) { + BT_ERR("%s, Failed to allocate memory", __func__); + goto fail; + } + sys_memcpy_swap(link[idx].dhkey, key, 32); + + BT_DBG("DHkey: %s", bt_hex(link[idx].dhkey, 32)); + + bt_mesh_atomic_set_bit(link[idx].flags, HAVE_DHKEY); + + /** After dhkey is generated, if auth_method is No OOB or + * Static OOB, provisioner can start to send confirmation. + * If output OOB is used by the device, provisioner need + * to watch out the output number and input it as auth_val. + * If input OOB is used by the device, provisioner need + * to output a value, and wait for prov input complete pdu. + */ + if (prov_auth(idx, link[idx].auth_method, + link[idx].auth_action, link[idx].auth_size) < 0) { + BT_ERR("%s, Failed to authenticate", __func__); + goto fail; + } + if (link[idx].auth_method == AUTH_METHOD_OUTPUT || + link[idx].auth_method == AUTH_METHOD_INPUT) { + return; + } + + if (link[idx].expect != PROV_INPUT_COMPLETE) { + send_confirm(idx); + } + return; + +fail: + close_link(idx, CLOSE_REASON_FAILED); + return; +} + +static void prov_gen_dh_key(const u8_t idx) +{ + u8_t pub_key[64]; + + /* Copy device public key in little-endian for bt_mesh_dh_key_gen(). + * X and Y halves are swapped independently. + */ + sys_memcpy_swap(&pub_key[0], &link[idx].conf_inputs[81], 32); + sys_memcpy_swap(&pub_key[32], &link[idx].conf_inputs[113], 32); + + if (bt_mesh_dh_key_gen(pub_key, prov_dh_key_cb, idx)) { + BT_ERR("%s, Failed to generate DHKey", __func__); + close_link(idx, CLOSE_REASON_FAILED); + return; + } +} + +static void send_pub_key(const u8_t idx, u8_t oob) +{ + PROV_BUF(buf, 65); + const u8_t *key = NULL; + + key = bt_mesh_pub_key_get(); + if (!key) { + BT_ERR("%s, No public key available", __func__); + close_link(idx, CLOSE_REASON_FAILED); + return; + } + + BT_DBG("Local Public Key: %s", bt_hex(key, 64)); + + bt_mesh_atomic_set_bit(link[idx].flags, LOCAL_PUB_KEY); + + prov_buf_init(&buf, PROV_PUB_KEY); + + /* Swap X and Y halves independently to big-endian */ + sys_memcpy_swap(net_buf_simple_add(&buf, 32), key, 32); + sys_memcpy_swap(net_buf_simple_add(&buf, 32), &key[32], 32); + + /* Store provisioner public key value in conf_inputs */ + memcpy(&link[idx].conf_inputs[17], &buf.data[1], 64); + + if (prov_send(idx, &buf)) { + BT_ERR("%s, Failed to send Provisioning Public Key", __func__); + close_link(idx, CLOSE_REASON_FAILED); + return; + } + + if (!oob) { + link[idx].expect = PROV_PUB_KEY; + } else { + /** Have already got device public key. If next is to + * send confirm(not wait for input complete), need to + * wait for transactiona ack for public key then send + * provisioning confirm pdu. + */ +#if defined(CONFIG_BLE_MESH_PB_ADV) + if (idx < CONFIG_BLE_MESH_PBA_SAME_TIME) { + link[idx].expect_ack_for = PROV_PUB_KEY; + return; + } +#endif /* CONFIG_BLE_MESH_PB_ADV */ + + /* If remote public key has been read, then start to generate DHkey, + * otherwise wait for device oob public key. + */ + if (bt_mesh_atomic_test_bit(link[idx].flags, REMOTE_PUB_KEY)) { + prov_gen_dh_key(idx); + } else { + bt_mesh_atomic_set_bit(link[idx].flags, WAIT_GEN_DHKEY); + } + } +} + +static void prov_pub_key(const u8_t idx, const u8_t *data) +{ + BT_DBG("Remote Public Key: %s", bt_hex(data, 64)); + + /* Make sure received pdu is ok and cancel the timeout timer */ + if (bt_mesh_atomic_test_and_clear_bit(link[idx].flags, TIMEOUT_START)) { + k_delayed_work_cancel(&link[idx].timeout); + } + + memcpy(&link[idx].conf_inputs[81], data, 64); + + if (!bt_mesh_atomic_test_bit(link[idx].flags, LOCAL_PUB_KEY)) { + /* Clear retransmit timer */ +#if defined(CONFIG_BLE_MESH_PB_ADV) + prov_clear_tx(idx); +#endif + bt_mesh_atomic_set_bit(link[idx].flags, REMOTE_PUB_KEY); + BT_WARN("%s, Waiting for local public key", __func__); + return; + } + + prov_gen_dh_key(idx); +} + +static void prov_input_complete(const u8_t idx, const u8_t *data) +{ + /* Make sure received pdu is ok and cancel the timeout timer */ + if (bt_mesh_atomic_test_and_clear_bit(link[idx].flags, TIMEOUT_START)) { + k_delayed_work_cancel(&link[idx].timeout); + } + + /* Provisioner receives input complete and send confirm */ + send_confirm(idx); +} + +static void prov_confirm(const u8_t idx, const u8_t *data) +{ + /** + * Zephyr uses PROV_BUF(16). Currently test with PROV_BUF(16) + * and PROV_BUF(17) on branch feature/btdm_ble_mesh_debug both + * work fine. + */ + PROV_BUF(buf, 17); + + BT_DBG("Remote Confirm: %s", bt_hex(data, 16)); + + /* Make sure received pdu is ok and cancel the timeout timer */ + if (bt_mesh_atomic_test_and_clear_bit(link[idx].flags, TIMEOUT_START)) { + k_delayed_work_cancel(&link[idx].timeout); + } + + link[idx].conf = (u8_t *)osi_calloc(PROV_CONFIRM_SIZE); + if (!link[idx].conf) { + BT_ERR("%s, Failed to allocate memory", __func__); + close_link(idx, CLOSE_REASON_FAILED); + return; + } + + memcpy(link[idx].conf, data, 16); + + if (!bt_mesh_atomic_test_bit(link[idx].flags, HAVE_DHKEY)) { +#if defined(CONFIG_BLE_MESH_PB_ADV) + prov_clear_tx(idx); +#endif + bt_mesh_atomic_set_bit(link[idx].flags, SEND_CONFIRM); + } + + prov_buf_init(&buf, PROV_RANDOM); + + net_buf_simple_add_mem(&buf, link[idx].rand, 16); + + if (prov_send(idx, &buf)) { + BT_ERR("%s, Failed to send Provisioning Random", __func__); + close_link(idx, CLOSE_REASON_FAILED); + return; + } + + link[idx].expect = PROV_RANDOM; +} + +static void send_prov_data(const u8_t idx) +{ + PROV_BUF(buf, 34); + const u8_t *netkey = NULL; + bool already_flag = false; + u8_t session_key[16]; + u8_t nonce[13]; + u8_t pdu[25]; + u16_t max_addr; + u16_t j; + int err; + + err = bt_mesh_session_key(link[idx].dhkey, link[idx].prov_salt, session_key); + if (err) { + BT_ERR("%s, Failed to generate session key", __func__); + goto fail; + } + BT_DBG("SessionKey: %s", bt_hex(session_key, 16)); + + err = bt_mesh_prov_nonce(link[idx].dhkey, link[idx].prov_salt, nonce); + if (err) { + BT_ERR("%s, Failed to generate session nonce", __func__); + goto fail; + } + BT_DBG("Nonce: %s", bt_hex(nonce, 13)); + + /* Assign provisioning data for the device. Currently all provisioned devices + * will be added to the primary subnet, and may add an API to choose to which + * subnet will the device be provisioned later. + */ + if (FAST_PROV_FLAG_GET()) { + netkey = fast_prov_info.net_key; + if (!netkey) { + BT_ERR("%s, Failed to get NetKey for fast provisioning", __func__); + goto fail; + } + memcpy(pdu, netkey, 16); + sys_put_be16(fast_prov_info.net_idx, &pdu[16]); + pdu[18] = fast_prov_info.flags; + sys_put_be32(fast_prov_info.iv_index, &pdu[19]); + } else { + netkey = provisioner_net_key_get(prov_ctx.curr_net_idx); + if (!netkey) { + BT_ERR("%s, Failed to get NetKey for provisioning data", __func__); + goto fail; + } + memcpy(pdu, netkey, 16); + sys_put_be16(prov_ctx.curr_net_idx, &pdu[16]); + pdu[18] = prov_ctx.curr_flags; + sys_put_be32(prov_ctx.curr_iv_index, &pdu[19]); + } + + /* 1. The Provisioner must not reuse unicast addresses that have been + * allocated to a device and sent in a Provisioning Data PDU until + * the Provisioner receives an Unprovisioned Device beacon or + * Service Data for the Mesh Provisioning Service from that same + * device, identified using the Device UUID of the device. + * 2. Once the provisioning data for the device has been sent, we will + * add the data sent to this device into the already_prov_info. + * 3. Another situation here is: + * If the device is a re-provisioned one, but the element num has + * changed and is larger than the previous number, here we will + * assign new address for the device. + */ + + /* Check if this device is a re-provisioned device */ + for (j = 0U; j < ARRAY_SIZE(prov_ctx.already_prov); j++) { + if (!memcmp(link[idx].uuid, prov_ctx.already_prov[j].uuid, 16)) { + if (link[idx].element_num <= prov_ctx.already_prov[j].element_num) { + already_flag = true; + sys_put_be16(prov_ctx.already_prov[j].unicast_addr, &pdu[23]); + link[idx].unicast_addr = prov_ctx.already_prov[j].unicast_addr; + break; + } else { + /* TODO: If the device has a larger element number during the + * second provisioning, then if the device is provisioned the + * third time later, already_prov struct will have two elements + * containing the same device UUID but with different element + * number. So we may add a flag to indicate the unicast address + * in the smaller element can be reused by other devices when + * unicast address is exhausted. + */ + } + } + } + + max_addr = FAST_PROV_FLAG_GET() ? fast_prov_info.unicast_addr_max : 0x7FFF; + + if (!already_flag) { + /* If this device to be provisioned is a new device */ + if (!prov_ctx.current_addr) { + BT_ERR("%s, No unicast address can be assigned", __func__); + goto fail; + } + + if (prov_ctx.current_addr + link[idx].element_num - 1 > max_addr) { + BT_ERR("%s, Not enough unicast address for the device", __func__); + goto fail; + } + + sys_put_be16(prov_ctx.current_addr, &pdu[23]); + link[idx].unicast_addr = prov_ctx.current_addr; + } + + prov_buf_init(&buf, PROV_DATA); + + err = bt_mesh_prov_encrypt(session_key, nonce, pdu, net_buf_simple_add(&buf, 33)); + if (err) { + BT_ERR("%s, Failed to encrypt provisioning data", __func__); + goto fail; + } + + if (prov_send(idx, &buf)) { + BT_ERR("%s, Failed to send Provisioning Data", __func__); + goto fail; + } + + /* If provisioning data is sent successfully, add the assigned information + * into the already_prov_info struct if this device is a new one. And if + * sent successfully, update the current_addr in prov_ctx struct. + */ + if (!already_flag) { + for (j = 0U; j < ARRAY_SIZE(prov_ctx.already_prov); j++) { + if (!prov_ctx.already_prov[j].element_num) { + memcpy(prov_ctx.already_prov[j].uuid, link[idx].uuid, 16); + prov_ctx.already_prov[j].element_num = link[idx].element_num; + prov_ctx.already_prov[j].unicast_addr = link[idx].unicast_addr; + break; + } + } + + /* We update the next unicast address to be assigned here because + * if provisioner is provisioning two devices at the same time, we + * need to assign the unicast address for them correctly. Hence we + * should not update the prov_ctx.current_addr after the proper + * provisioning complete pdu is received. + */ + prov_ctx.current_addr += link[idx].element_num; + if (prov_ctx.current_addr > max_addr) { + /* No unicast address will be used for further provisioning */ + prov_ctx.current_addr = 0x0000; + } + } + + if (FAST_PROV_FLAG_GET()) { + link[idx].ki_flags = fast_prov_info.flags; + link[idx].iv_index = fast_prov_info.iv_index; + } else { + link[idx].ki_flags = prov_ctx.curr_flags; + link[idx].iv_index = prov_ctx.curr_iv_index; + } + + link[idx].expect = PROV_COMPLETE; + return; + +fail: + close_link(idx, CLOSE_REASON_FAILED); + return; +} + +static void prov_random(const u8_t idx, const u8_t *data) +{ + u8_t conf_verify[16]; + + BT_DBG("Remote Random: %s", bt_hex(data, 16)); + + if (bt_mesh_prov_conf(link[idx].conf_key, data, link[idx].auth, conf_verify)) { + BT_ERR("%s, Failed to calculate confirmation verification", __func__); + goto fail; + } + + if (memcmp(conf_verify, link[idx].conf, 16)) { + BT_ERR("%s, Invalid confirmation value", __func__); + BT_DBG("Received: %s", bt_hex(link[idx].conf, 16)); + BT_DBG("Calculated: %s", bt_hex(conf_verify, 16)); + goto fail; + } + + /*Verify received confirm is ok and cancel the timeout timer */ + if (bt_mesh_atomic_test_and_clear_bit(link[idx].flags, TIMEOUT_START)) { + k_delayed_work_cancel(&link[idx].timeout); + } + + /** After provisioner receives provisioning random from device, + * and successfully check the confirmation, the following + * should be done: + * 1. osi_calloc memory for prov_salt + * 2. calculate prov_salt + * 3. prepare provisioning data and send + */ + link[idx].prov_salt = (u8_t *)osi_calloc(PROV_PROV_SALT_SIZE); + if (!link[idx].prov_salt) { + BT_ERR("%s, Failed to allocate memory", __func__); + goto fail; + } + + if (bt_mesh_prov_salt(link[idx].conf_salt, link[idx].rand, data, + link[idx].prov_salt)) { + BT_ERR("%s, Failed to generate ProvisioningSalt", __func__); + goto fail; + } + + BT_DBG("ProvisioningSalt: %s", bt_hex(link[idx].prov_salt, 16)); + + send_prov_data(idx); + return; + +fail: + close_link(idx, CLOSE_REASON_FAILED); + return; +} + +static void prov_complete(const u8_t idx, const u8_t *data) +{ + u8_t device_key[16]; + u16_t rm = 0; + u16_t j; + int err; + + /* Make sure received pdu is ok and cancel the timeout timer */ + if (bt_mesh_atomic_test_and_clear_bit(link[idx].flags, TIMEOUT_START)) { + k_delayed_work_cancel(&link[idx].timeout); + } + + /* If provisioning complete is received, the provisioning device + * will be stored into the prov_node_info structure and become a + * node within the mesh network + */ + err = bt_mesh_dev_key(link[idx].dhkey, link[idx].prov_salt, device_key); + if (err) { + BT_ERR("%s, Failed to generate device key", __func__); + close_link(idx, CLOSE_REASON_FAILED); + return; + } + + for (j = 0U; j < ARRAY_SIZE(prov_nodes); j++) { + if (!prov_nodes[j].provisioned) { + prov_nodes[j].provisioned = true; + prov_nodes[j].oob_info = link[idx].oob_info; + prov_nodes[j].element_num = link[idx].element_num; + prov_nodes[j].unicast_addr = link[idx].unicast_addr; + if (FAST_PROV_FLAG_GET()) { + prov_nodes[j].net_idx = fast_prov_info.net_idx; + } else { + prov_nodes[j].net_idx = prov_ctx.curr_net_idx; + } + prov_nodes[j].flags = link[idx].ki_flags; + prov_nodes[j].iv_index = link[idx].iv_index; + prov_nodes[j].addr.type = link[idx].addr.type; + memcpy(prov_nodes[j].addr.val, link[idx].addr.val, BLE_MESH_ADDR_LEN); + memcpy(prov_nodes[j].uuid, link[idx].uuid, 16); + break; + } + } + + if (j == ARRAY_SIZE(prov_nodes)) { + BT_ERR("%s, Provisioned node queue is full", __func__); + close_link(idx, CLOSE_REASON_FAILED); + return; + } + + prov_ctx.node_count++; + + err = provisioner_node_provision(j, prov_nodes[j].uuid, prov_nodes[j].oob_info, + prov_nodes[j].unicast_addr, prov_nodes[j].element_num, + prov_nodes[j].net_idx, prov_nodes[j].flags, + prov_nodes[j].iv_index, device_key); + if (err) { + BT_ERR("%s, Failed to store node info", __func__); + close_link(idx, CLOSE_REASON_FAILED); + return; + } + + if (prov->prov_complete) { + prov->prov_complete(j, prov_nodes[j].uuid, prov_nodes[j].unicast_addr, + prov_nodes[j].element_num, prov_nodes[j].net_idx); + } + + err = provisioner_dev_find(&link[idx].addr, link[idx].uuid, &rm); + if (!err) { + if (unprov_dev[rm].flags & RM_AFTER_PROV) { + memset(&unprov_dev[rm], 0, sizeof(struct unprov_dev_queue)); + } + } else if (err == -ENODEV) { + BT_DBG("%s, Device is not found in queue", __func__); + } else { + BT_WARN("%s, Failed to remove device from queue", __func__); + } + + close_link(idx, CLOSE_REASON_SUCCESS); +} + +static void prov_failed(const u8_t idx, const u8_t *data) +{ + BT_WARN("%s, Error 0x%02x", __func__, data[0]); + + close_link(idx, CLOSE_REASON_FAILED); +} + +static const struct { + void (*func)(const u8_t idx, const u8_t *data); + u16_t len; +} prov_handlers[] = { + { prov_invite, 1 }, + { prov_capabilities, 11 }, + { prov_start, 5 }, + { prov_pub_key, 64 }, + { prov_input_complete, 0 }, + { prov_confirm, 16 }, + { prov_random, 16 }, + { prov_data, 33 }, + { prov_complete, 0 }, + { prov_failed, 1 }, +}; + +static void close_link(const u8_t idx, u8_t reason) +{ +#if defined(CONFIG_BLE_MESH_PB_ADV) + if (idx < CONFIG_BLE_MESH_PBA_SAME_TIME) { + bearer_ctl_send(idx, LINK_CLOSE, &reason, sizeof(reason)); + return; + } +#endif + +#if defined(CONFIG_BLE_MESH_PB_GATT) + if (idx < BLE_MESH_PROV_SAME_TIME +#if defined(CONFIG_BLE_MESH_PB_ADV) + && idx >= CONFIG_BLE_MESH_PBA_SAME_TIME +#endif + ) { + if (link[idx].conn) { + bt_mesh_gattc_disconnect(link[idx].conn); + } + return; + } +#endif + + BT_ERR("%s, Invalid link index %d", __func__, idx); + return; +} + +static void prov_timeout(struct k_work *work) +{ + u8_t idx = (u8_t)work->index; + + BT_DBG("%s", __func__); + + close_link(idx, CLOSE_REASON_TIMEOUT); +} + +#if defined(CONFIG_BLE_MESH_PB_ADV) +static void prov_retransmit(struct k_work *work) +{ + s64_t timeout = TRANSACTION_TIMEOUT; + u8_t idx = (u8_t)work->index; + u8_t i; + + BT_DBG("%s", __func__); + + if (!bt_mesh_atomic_test_bit(link[idx].flags, LINK_ACTIVE)) { + BT_WARN("%s, Link is not active", __func__); + return; + } + +#if defined(CONFIG_BLE_MESH_FAST_PROV) + if (link[idx].tx_pdu_type >= PROV_DATA) { + timeout = K_SECONDS(30); + } +#endif + if (k_uptime_get() - link[idx].tx.start > timeout) { + BT_WARN("Provisioner timeout, giving up transaction"); + reset_link(idx, CLOSE_REASON_TIMEOUT); + return; + } + + if (link[idx].send_link_close & BIT(0)) { + u8_t reason = (link[idx].send_link_close >> 1) & BIT_MASK(2); + u16_t count = (link[idx].send_link_close >> 3); + if (count >= 2) { + reset_link(idx, reason); + return; + } + link[idx].send_link_close += BIT(3); + } + + for (i = 0U; i < ARRAY_SIZE(link[idx].tx.buf); i++) { + struct net_buf *buf = link[idx].tx.buf[i]; + + if (!buf) { + break; + } + + if (BLE_MESH_ADV(buf)->busy) { + continue; + } + + BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); + + if (i + 1 < ARRAY_SIZE(link[idx].tx.buf) && link[idx].tx.buf[i + 1]) { + bt_mesh_adv_send(buf, NULL, NULL); + } else { + bt_mesh_adv_send(buf, &buf_sent_cb, (void *)(int)idx); + } + } +} + +static void link_ack(const u8_t idx, struct prov_rx *rx, struct net_buf_simple *buf) +{ + BT_DBG("len %u", buf->len); + + if (buf->len) { + BT_ERR("%s, Invalid Link ACK length", __func__); + close_link(idx, CLOSE_REASON_FAILED); + return; + } + + if (link[idx].expect == PROV_CAPABILITIES) { + BT_WARN("%s, Link ACK is already received", __func__); + return; + } + + link[idx].conf_inputs = (u8_t *)osi_calloc(PROV_CONF_INPUTS_SIZE); + if (!link[idx].conf_inputs) { + BT_ERR("%s, Failed to allocate memory", __func__); + close_link(idx, CLOSE_REASON_FAILED); + return; + } + + send_invite(idx); +} + +static void link_close(const u8_t idx, struct prov_rx *rx, struct net_buf_simple *buf) +{ + u8_t reason; + + BT_DBG("len %u", buf->len); + + reason = net_buf_simple_pull_u8(buf); + + reset_link(idx, reason); +} + +static void gen_prov_ctl(const u8_t idx, struct prov_rx *rx, struct net_buf_simple *buf) +{ + BT_DBG("op 0x%02x len %u", BEARER_CTL(rx->gpc), buf->len); + + switch (BEARER_CTL(rx->gpc)) { + case LINK_OPEN: + break; + + case LINK_ACK: + if (!bt_mesh_atomic_test_bit(link[idx].flags, LINK_ACTIVE)) { + return; + } + link_ack(idx, rx, buf); + break; + + case LINK_CLOSE: + if (!bt_mesh_atomic_test_bit(link[idx].flags, LINK_ACTIVE)) { + return; + } + link_close(idx, rx, buf); + break; + + default: + BT_ERR("%s, Unknown bearer opcode 0x%02x", __func__, BEARER_CTL(rx->gpc)); + return; + } +} + +static void prov_msg_recv(const u8_t idx) +{ + u8_t type = link[idx].rx.buf->data[0]; + + BT_DBG("type 0x%02x len %u", type, link[idx].rx.buf->len); + + /** + * Provisioner first checks information within the received + * Provisioning PDU. If the check succeeds then check fcs. + */ + if (type != PROV_FAILED && type != link[idx].expect) { + BT_ERR("%s, Unexpected msg 0x%02x != 0x%02x", __func__, type, link[idx].expect); + goto fail; + } + + if (type >= 0x0A) { + BT_ERR("%s, Unknown provisioning PDU type 0x%02x", __func__, type); + goto fail; + } + + if (1 + prov_handlers[type].len != link[idx].rx.buf->len) { + BT_ERR("%s, Invalid length %u for type 0x%02x", __func__, link[idx].rx.buf->len, type); + goto fail; + } + + if (!bt_mesh_fcs_check(link[idx].rx.buf, link[idx].rx.fcs)) { + BT_ERR("%s, Incorrect FCS", __func__); + goto fail; + } + + gen_prov_ack_send(idx, link[idx].rx.trans_id); + link[idx].rx.prev_id = link[idx].rx.trans_id; + link[idx].rx.trans_id = 0; + + prov_handlers[type].func(idx, &link[idx].rx.buf->data[1]); + return; + +fail: + close_link(idx, CLOSE_REASON_FAILED); + return; +} + +static void gen_prov_cont(const u8_t idx, struct prov_rx *rx, struct net_buf_simple *buf) +{ + u8_t seg = CONT_SEG_INDEX(rx->gpc); + + BT_DBG("len %u, seg_index %u", buf->len, seg); + + if (!link[idx].rx.seg && link[idx].rx.prev_id == rx->xact_id) { + BT_WARN("%s, Resending ack", __func__); + gen_prov_ack_send(idx, rx->xact_id); + return; + } + + if (rx->xact_id != link[idx].rx.trans_id) { + BT_WARN("%s, Data for unknown transaction (%u != %u)", + __func__, rx->xact_id, link[idx].rx.trans_id); + /** + * If Provisioner receives a Provisioning PDU with a mismatch + * transaction number, it just ignore it. + */ + return; + } + + if (seg > link[idx].rx.last_seg) { + BT_ERR("%s, Invalid segment index %u", __func__, seg); + goto fail; + } else if (seg == link[idx].rx.last_seg) { + u8_t expect_len; + + expect_len = (link[idx].rx.buf->len - 20 - + (23 * (link[idx].rx.last_seg - 1))); + if (expect_len != buf->len) { + BT_ERR("%s, Incorrect last seg len: %u != %u", + __func__, expect_len, buf->len); + goto fail; + } + } + + if (!(link[idx].rx.seg & BIT(seg))) { + BT_WARN("%s, Ignore already received segment", __func__); + return; + } + + memcpy(XACT_SEG_DATA(idx, seg), buf->data, buf->len); + XACT_SEG_RECV(idx, seg); + + if (!link[idx].rx.seg) { + prov_msg_recv(idx); + } + return; + +fail: + close_link(idx, CLOSE_REASON_FAILED); + return; +} + +static void gen_prov_ack(const u8_t idx, struct prov_rx *rx, struct net_buf_simple *buf) +{ + u8_t ack_type, pub_key_oob; + + BT_DBG("len %u", buf->len); + + if (!link[idx].tx.buf[0]) { + return; + } + + if (!link[idx].tx.trans_id) { + return; + } + + if (rx->xact_id == (link[idx].tx.trans_id - 1)) { + prov_clear_tx(idx); + + ack_type = link[idx].expect_ack_for; + switch (ack_type) { + case PROV_START: + pub_key_oob = link[idx].conf_inputs[13]; + send_pub_key(idx, pub_key_oob); + break; + case PROV_PUB_KEY: + prov_gen_dh_key(idx); + break; + default: + break; + } + link[idx].expect_ack_for = 0x00; + } +} + +static void gen_prov_start(const u8_t idx, struct prov_rx *rx, struct net_buf_simple *buf) +{ + if (link[idx].rx.seg) { + BT_WARN("%s, Get Start while there are unreceived segments", __func__); + return; + } + + if (link[idx].rx.prev_id == rx->xact_id) { + BT_WARN("%s, Resending ack", __func__); + gen_prov_ack_send(idx, rx->xact_id); + return; + } + + link[idx].rx.buf->len = net_buf_simple_pull_be16(buf); + link[idx].rx.trans_id = rx->xact_id; + link[idx].rx.fcs = net_buf_simple_pull_u8(buf); + + BT_DBG("len %u last_seg %u total_len %u fcs 0x%02x", buf->len, + START_LAST_SEG(rx->gpc), link[idx].rx.buf->len, link[idx].rx.fcs); + + /* Provisioner can not receive zero-length provisioning pdu */ + if (link[idx].rx.buf->len < 1) { + BT_ERR("%s, Ignoring zero-length provisioning PDU", __func__); + close_link(idx, CLOSE_REASON_FAILED); + return; + } + + if (link[idx].rx.buf->len > link[idx].rx.buf->size) { + BT_ERR("%s, Too large provisioning PDU (%u bytes)", + __func__, link[idx].rx.buf->len); + // close_link(i, CLOSE_REASON_FAILED); + return; + } + + if (START_LAST_SEG(rx->gpc) > 0 && link[idx].rx.buf->len <= 20) { + BT_ERR("%s, Too small total length for multi-segment PDU", __func__); + close_link(idx, CLOSE_REASON_FAILED); + return; + } + + link[idx].rx.seg = (1 << (START_LAST_SEG(rx->gpc) + 1)) - 1; + link[idx].rx.last_seg = START_LAST_SEG(rx->gpc); + memcpy(link[idx].rx.buf->data, buf->data, buf->len); + XACT_SEG_RECV(idx, 0); + + if (!link[idx].rx.seg) { + prov_msg_recv(idx); + } +} + +static const struct { + void (*const func)(const u8_t idx, struct prov_rx *rx, struct net_buf_simple *buf); + const u8_t require_link; + const u8_t min_len; +} gen_prov[] = { + { gen_prov_start, true, 3 }, + { gen_prov_ack, true, 0 }, + { gen_prov_cont, true, 0 }, + { gen_prov_ctl, true, 0 }, +}; + +static void gen_prov_recv(const u8_t idx, struct prov_rx *rx, struct net_buf_simple *buf) +{ + if (buf->len < gen_prov[GPCF(rx->gpc)].min_len) { + BT_ERR("%s, Too short GPC message type %u", __func__, GPCF(rx->gpc)); + close_link(idx, CLOSE_REASON_FAILED); + return; + } + + /** + * require_link can be used combining with link[].linking flag to + * set LINK_ACTIVE status after Link ACK is received. In this case + * there is no need to check LINK_ACTIVE status in find_link(). + */ + if (!bt_mesh_atomic_test_bit(link[idx].flags, LINK_ACTIVE) && + gen_prov[GPCF(rx->gpc)].require_link) { + BT_DBG("Ignoring message that requires active link"); + return; + } + + gen_prov[GPCF(rx->gpc)].func(idx, rx, buf); +} + +static int find_link(u32_t link_id, u8_t *idx) +{ + u8_t i; + + /* link for PB-ADV is from 0 to CONFIG_BLE_MESH_PBA_SAME_TIME */ + for (i = 0U; i < CONFIG_BLE_MESH_PBA_SAME_TIME; i++) { + if (bt_mesh_atomic_test_bit(link[i].flags, LINK_ACTIVE)) { + if (link[i].link_id == link_id) { + if (idx) { + *idx = i; + } + return 0; + } + } + } + + return -1; +} + +void provisioner_pb_adv_recv(struct net_buf_simple *buf) +{ + struct prov_rx rx = {0}; + u8_t idx; + + rx.link_id = net_buf_simple_pull_be32(buf); + if (find_link(rx.link_id, &idx) < 0) { + BT_DBG("%s, Data for unexpected link", __func__); + return; + } + + if (buf->len < 2) { + BT_ERR("%s, Too short provisioning packet (len %u)", __func__, buf->len); + close_link(idx, CLOSE_REASON_FAILED); + return; + } + + rx.xact_id = net_buf_simple_pull_u8(buf); + rx.gpc = net_buf_simple_pull_u8(buf); + + BT_DBG("link_id 0x%08x xact_id %u", rx.link_id, rx.xact_id); + + gen_prov_recv(idx, &rx, buf); +} +#endif /* CONFIG_BLE_MESH_PB_ADV */ + +#if defined(CONFIG_BLE_MESH_PB_GATT) +static struct bt_mesh_conn *find_conn(struct bt_mesh_conn *conn, u8_t *idx) +{ + u8_t i; + + /* link for PB-GATT is from CONFIG_BLE_MESH_PBA_SAME_TIME to BLE_MESH_PROV_SAME_TIME */ + for (i = CONFIG_BLE_MESH_PBA_SAME_TIME; i < BLE_MESH_PROV_SAME_TIME; i++) { + if (bt_mesh_atomic_test_bit(link[i].flags, LINK_ACTIVE)) { + if (link[i].conn == conn) { + if (idx) { + *idx = i; + } + return conn; + } + } + } + + return NULL; +} + +int provisioner_pb_gatt_recv(struct bt_mesh_conn *conn, struct net_buf_simple *buf) +{ + u8_t type; + u8_t idx; + + BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); + + if (!find_conn(conn, &idx)) { + BT_ERR("%s, Data for unexpected connection", __func__); + return -ENOTCONN; + } + + if (buf->len < 1) { + BT_ERR("%s, Too short provisioning packet (len %u)", __func__, buf->len); + goto fail; + } + + type = net_buf_simple_pull_u8(buf); + if (type != PROV_FAILED && type != link[idx].expect) { + BT_ERR("%s, Unexpected msg 0x%02x != 0x%02x", __func__, type, link[idx].expect); + goto fail; + } + + if (type >= 0x0A) { + BT_ERR("%s, Unknown provisioning PDU type 0x%02x", __func__, type); + goto fail; + } + + if (prov_handlers[type].len != buf->len) { + BT_ERR("%s, Invalid length %u for type 0x%02x", __func__, buf->len, type); + goto fail; + } + + prov_handlers[type].func(idx, buf->data); + + return 0; + +fail: + /* Mesh Spec Section 5.4.4 Provisioning errors */ + close_link(idx, CLOSE_REASON_FAILED); + return -EINVAL; +} + +int provisioner_set_prov_conn(const u8_t addr[6], struct bt_mesh_conn *conn) +{ + u8_t i; + + if (!addr || !conn) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + for (i = CONFIG_BLE_MESH_PBA_SAME_TIME; i < BLE_MESH_PROV_SAME_TIME; i++) { + if (!memcmp(link[i].addr.val, addr, BLE_MESH_ADDR_LEN)) { + link[i].conn = bt_mesh_conn_ref(conn); + return 0; + } + } + + BT_ERR("%s, Address %s is not found", __func__, bt_hex(addr, BLE_MESH_ADDR_LEN)); + return -ENOMEM; +} + +int provisioner_pb_gatt_open(struct bt_mesh_conn *conn, u8_t *addr) +{ + u8_t idx = 0, i; + + BT_DBG("conn %p", conn); + + /** + * Double check if the device is currently being provisioned using PB-ADV. + * Provisioner binds conn with proper device when proxy_prov_connected() + * is invoked, and here after proper GATT procedures are completed, we just + * check if this conn already exists in the proxy servers array. + */ + for (i = CONFIG_BLE_MESH_PBA_SAME_TIME; i < BLE_MESH_PROV_SAME_TIME; i++) { + if (link[i].conn == conn) { + idx = i; + break; + } + } + + if (i == BLE_MESH_PROV_SAME_TIME) { + BT_ERR("%s, Link is not found", __func__); + return -ENOTCONN; + } + +#if defined(CONFIG_BLE_MESH_PB_ADV) + for (i = 0U; i < CONFIG_BLE_MESH_PBA_SAME_TIME; i++) { + if (bt_mesh_atomic_test_bit(link[i].flags, LINK_ACTIVE)) { + if (!memcmp(link[i].uuid, link[idx].uuid, 16)) { + BT_WARN("%s, Provision using PB-GATT & PB-ADV same time", __func__); + close_link(idx, CLOSE_REASON_FAILED); + return -EALREADY; + } + } + } +#endif + + bt_mesh_atomic_set_bit(link[idx].flags, LINK_ACTIVE); + link[idx].conn = bt_mesh_conn_ref(conn); + + /* May use lcd to indicate starting provisioning each device */ + if (prov->prov_link_open) { + prov->prov_link_open(BLE_MESH_PROV_GATT); + } + + link[idx].conf_inputs = (u8_t *)osi_calloc(PROV_CONF_INPUTS_SIZE); + if (!link[idx].conf_inputs) { + /* Disconnect this connection, clear corresponding informations */ + BT_ERR("%s, Failed to allocate memory", __func__); + close_link(idx, CLOSE_REASON_FAILED); + return -ENOMEM; + } + + send_invite(idx); + return 0; +} + +int provisioner_pb_gatt_close(struct bt_mesh_conn *conn, u8_t reason) +{ + u8_t idx; + + BT_DBG("conn %p", conn); + + if (!find_conn(conn, &idx)) { + BT_ERR("%s, Conn %p is not found", __func__, conn); + return -ENOTCONN; + } + + if (bt_mesh_atomic_test_and_clear_bit(link[idx].flags, TIMEOUT_START)) { + k_delayed_work_cancel(&link[idx].timeout); + } + + if (prov->prov_link_close) { + prov->prov_link_close(BLE_MESH_PROV_GATT, reason); + } + + prov_memory_free(idx); + + memset(&link[idx], 0, offsetof(struct prov_link, timeout)); + + if (bt_mesh_pub_key_get()) { + bt_mesh_atomic_set_bit(link[idx].flags, LOCAL_PUB_KEY); + } + + return 0; +} +#endif /* CONFIG_BLE_MESH_PB_GATT */ + +int provisioner_prov_init(const struct bt_mesh_prov *prov_info) +{ + const u8_t *key = NULL; + u8_t i; + + if (!prov_info) { + BT_ERR("%s, No provisioning context provided", __func__); + return -EINVAL; + } + + if (CONFIG_BLE_MESH_PBG_SAME_TIME > BLE_MESH_MAX_CONN) { + BT_ERR("%s, PB-GATT same time exceeds max connection", __func__); + return -EINVAL; + } + + key = bt_mesh_pub_key_get(); + if (!key) { + BT_ERR("%s, Failed to generate Public Key", __func__); + return -EIO; + } + + prov = prov_info; + +#if defined(CONFIG_BLE_MESH_PB_ADV) + for (i = 0U; i < CONFIG_BLE_MESH_PBA_SAME_TIME; i++) { + struct prov_adv_buf *adv = &adv_buf[i]; + adv->buf.size = ADV_BUF_SIZE; + adv->buf.__buf = adv_buf_data + (i * ADV_BUF_SIZE); + + link[i].pending_ack = XACT_NVAL; + k_delayed_work_init(&link[i].tx.retransmit, prov_retransmit); + link[i].tx.retransmit.work.index = (int)i; + link[i].rx.prev_id = XACT_NVAL; + link[i].rx.buf = bt_mesh_pba_get_buf(i); + } +#endif + + for (i = 0U; i < BLE_MESH_PROV_SAME_TIME; i++) { + k_delayed_work_init(&link[i].timeout, prov_timeout); + link[i].timeout.work.index = (int)i; + } + + /* for PB-GATT, use servers[] array in proxy_provisioner.c */ + + prov_ctx.current_addr = prov->prov_start_address; + prov_ctx.curr_net_idx = BLE_MESH_KEY_PRIMARY; + prov_ctx.curr_flags = prov->flags; + prov_ctx.curr_iv_index = prov->iv_index; + + osi_mutex_new(&prov_ctx.pb_adv_lock); + osi_mutex_new(&prov_ctx.pb_gatt_lock); + + return 0; +} + +static bool is_unprov_dev_info_callback_to_app(bt_mesh_prov_bearer_t bearer, + const u8_t uuid[16], const bt_mesh_addr_t *addr, u16_t oob_info) +{ + u16_t index; + + if (prov_ctx.prov_after_match == false) { + u8_t adv_type = (bearer == BLE_MESH_PROV_ADV) ? + BLE_MESH_ADV_NONCONN_IND : BLE_MESH_ADV_IND; + + if (provisioner_dev_find(addr, uuid, &index)) { + BT_DBG("%s, Device is not in queue, notify to upper layer", __func__); + if (notify_unprov_adv_pkt_cb) { + notify_unprov_adv_pkt_cb(addr->val, addr->type, adv_type, uuid, oob_info, bearer); + } + return true; + } + + if (!(unprov_dev[index].bearer & bearer)) { + BT_WARN("Device in queue not support PB-%s", + (bearer == BLE_MESH_PROV_ADV) ? "ADV" : "GATT"); + if (notify_unprov_adv_pkt_cb) { + notify_unprov_adv_pkt_cb(addr->val, addr->type, adv_type, uuid, oob_info, bearer); + } + return true; + } + } + + return false; +} + +void provisioner_unprov_beacon_recv(struct net_buf_simple *buf) +{ +#if defined(CONFIG_BLE_MESH_PB_ADV) + const bt_mesh_addr_t *addr = NULL; + const u8_t *uuid = NULL; + u16_t oob_info; + + if (buf->len != 0x12 && buf->len != 0x16) { + BT_ERR("%s, Invalid Unprovisioned Device Beacon length", __func__); + return; + } + + if (prov_ctx.pba_count == CONFIG_BLE_MESH_PBA_SAME_TIME) { + BT_DBG("Current PB-ADV devices reach max limit"); + return; + } + + addr = bt_mesh_pba_get_addr(); + uuid = buf->data; + net_buf_simple_pull(buf, 16); + /* Mesh beacon uses big-endian to send beacon data */ + oob_info = net_buf_simple_pull_be16(buf); + + if (provisioner_check_unprov_dev_info(uuid)) { + return; + } + + if (is_unprov_dev_info_callback_to_app( + BLE_MESH_PROV_ADV, uuid, addr, oob_info)) { + return; + } + + provisioner_start_prov_pb_adv(uuid, addr, oob_info); +#endif /* CONFIG_BLE_MESH_PB_ADV */ +} + +bool provisioner_flags_match(struct net_buf_simple *buf) +{ + u8_t flags; + + if (buf->len != 1) { + BT_DBG("%s, Unexpected flags length", __func__); + return false; + } + + flags = net_buf_simple_pull_u8(buf); + + BT_DBG("Received adv pkt with flags: 0x%02x", flags); + + /* Flags context will not be checked curently */ + + return true; +} + +u16_t provisioner_srv_uuid_recv(struct net_buf_simple *buf) +{ + u16_t uuid; + + if (buf->len != 2) { + BT_DBG("Length not match mesh service uuid"); + return false; + } + + uuid = net_buf_simple_pull_le16(buf); + + BT_DBG("Received adv pkt with service UUID: %d", uuid); + + if ((uuid != BLE_MESH_UUID_MESH_PROV_VAL) && (uuid != BLE_MESH_UUID_MESH_PROXY_VAL)) { + return false; + } + + return uuid; +} + +static void provisioner_prov_srv_data_recv(struct net_buf_simple *buf, const bt_mesh_addr_t *addr); + +void provisioner_srv_data_recv(struct net_buf_simple *buf, const bt_mesh_addr_t *addr, u16_t uuid) +{ + u16_t uuid_type; + + if (!buf || !addr) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + uuid_type = net_buf_simple_pull_le16(buf); + if (uuid_type != uuid) { + BT_DBG("%s, Invalid Mesh Service Data UUID 0x%04x", __func__, uuid_type); + return; + } + + switch (uuid) { + case BLE_MESH_UUID_MESH_PROV_VAL: + if (buf->len != BLE_MESH_PROV_SRV_DATA_LEN) { + BT_WARN("%s, Invalid Mesh Prov Service Data length %d", __func__, buf->len); + return; + } + BT_DBG("Start to deal with Mesh Prov Service Data"); + provisioner_prov_srv_data_recv(buf, addr); + break; + case BLE_MESH_UUID_MESH_PROXY_VAL: + if (buf->len != BLE_MESH_PROXY_SRV_DATA_LEN1 && + buf->len != BLE_MESH_PROXY_SRV_DATA_LEN2) { + BT_ERR("%s, Invalid Mesh Proxy Service Data length %d", __func__, buf->len); + return; + } + BT_DBG("Start to deal with Mesh Proxy Service Data"); + provisioner_proxy_srv_data_recv(buf); + break; + default: + break; + } +} + +static void provisioner_prov_srv_data_recv(struct net_buf_simple *buf, const bt_mesh_addr_t *addr) +{ +#if defined(CONFIG_BLE_MESH_PB_GATT) + const u8_t *uuid = NULL; + u16_t oob_info; + + if (prov_ctx.pbg_count == CONFIG_BLE_MESH_PBG_SAME_TIME) { + BT_DBG("Current PB-GATT devices reach max limit"); + return; + } + + uuid = buf->data; + net_buf_simple_pull(buf, 16); + /* Mesh beacon uses big-endian to send beacon data */ + oob_info = net_buf_simple_pull_be16(buf); + + if (provisioner_check_unprov_dev_info(uuid)) { + return; + } + + if (is_unprov_dev_info_callback_to_app( + BLE_MESH_PROV_GATT, uuid, addr, oob_info)) { + return; + } + + /* Provisioner will copy the device uuid, oob info, etc. into an unused link + * struct, and at this moment the link has not been activated. Even if we + * receive an Unprovisioned Device Beacon and a Connectable Provisioning adv + * pkt from the same device, and store the device info received within each + * adv pkt into two link structs which will has no impact on the provisioning + * of this device, because no matter which link among PB-GATT and PB-ADV is + * activated first, the other one will be dropped finally and the link struct + * occupied by the dropped link will be used by other devices (because the link + * is not activated). + * Use connecting flag to prevent if two devices's adv pkts are both received, + * the previous one info will be replaced by the second one. + */ + provisioner_start_prov_pb_gatt(uuid, addr, oob_info); +#endif /* CONFIG_BLE_MESH_PB_GATT */ +} + +#endif /* CONFIG_BLE_MESH_PROVISIONER */ diff --git a/components/bt/ble_mesh/mesh_core/provisioner_prov.h b/components/bt/ble_mesh/mesh_core/provisioner_prov.h new file mode 100644 index 0000000000..30a2f94d76 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/provisioner_prov.h @@ -0,0 +1,379 @@ +// Copyright 2017-2018 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. + +#ifndef _PROVISIONER_PROV_H_ +#define _PROVISIONER_PROV_H_ + +#include "mesh_bearer_adapt.h" +#include "mesh_main.h" + +#if !CONFIG_BLE_MESH_PROVISIONER + +#define CONFIG_BLE_MESH_PBA_SAME_TIME 0 +#define CONFIG_BLE_MESH_PBG_SAME_TIME 0 + +#else + +#if !defined(CONFIG_BLE_MESH_PB_ADV) +#define CONFIG_BLE_MESH_PBA_SAME_TIME 0 +#endif /* !CONFIG_BLE_MESH_PB_ADV */ + +#if !defined(CONFIG_BLE_MESH_PB_GATT) +#define CONFIG_BLE_MESH_PBG_SAME_TIME 0 +#endif /* !CONFIG_BLE_MESH_PB_GATT */ + +#endif /* !CONFIG_BLE_MESH_PROVISIONER */ + +#define RM_AFTER_PROV BIT(0) +#define START_PROV_NOW BIT(1) +#define FLUSHABLE_DEV BIT(2) + +struct bt_mesh_unprov_dev_add { + u8_t addr[6]; + u8_t addr_type; + u8_t uuid[16]; + u16_t oob_info; + u8_t bearer; +}; + +struct bt_mesh_device_delete { + u8_t addr[6]; + u8_t addr_type; + u8_t uuid[16]; +}; + +#define NET_IDX_FLAG BIT(0) +#define FLAGS_FLAG BIT(1) +#define IV_INDEX_FLAG BIT(2) + +struct bt_mesh_prov_data_info { + union { + u16_t net_idx; + u8_t flags; + u32_t iv_index; + }; + u8_t flag; +}; + +/* The following APIs are for primary provisioner internal use */ + +/** + * @brief This function decrements the current PB-GATT count. + * + * @return None + */ +void provisioner_pbg_count_dec(void); + +/** + * @brief This function increments the current PB-GATT count. + * + * @return None + */ +void provisioner_pbg_count_inc(void); + +/** + * @brief This function clears the part of the link info of the proper device. + * + * @param[in] addr: Remote device address + * + * @return None + */ +void provisioner_clear_link_conn_info(const u8_t addr[6]); + +/** + * @brief This function handles the received PB-ADV PDUs. + * + * @param[in] buf: Pointer to the buffer containing generic provisioning PDUs + * + * @return Zero - success, otherwise - fail + */ +void provisioner_pb_adv_recv(struct net_buf_simple *buf); + +/** + * @brief This function sends provisioning invite to start + * provisioning this unprovisioned device. + * + * @param[in] addr: Remote device address + * @param[in] conn: Pointer to the bt_conn structure + * + * @return Zero - success, otherwise - fail + */ +int provisioner_set_prov_conn(const u8_t addr[6], struct bt_mesh_conn *conn); + +/** + * @brief This function sends provisioning invite to start + * provisioning this unprovisioned device. + * + * @param[in] conn: Pointer to the bt_conn structure + * @param[in] addr: Address of the connected device + * + * @return Zero - success, otherwise - fail + */ +int provisioner_pb_gatt_open(struct bt_mesh_conn *conn, u8_t *addr); + +/** + * @brief This function resets the used information when + * related connection is terminated. + * + * @param[in] conn: Pointer to the bt_conn structure + * @param[in] reason: Connection terminated reason + * + * @return Zero - success, otherwise - fail + */ +int provisioner_pb_gatt_close(struct bt_mesh_conn *conn, u8_t reason); + +/** + * @brief This function handles the received PB-GATT provision + * PDUs. + * + * @param[in] conn: Pointer to the bt_conn structure + * @param[in] buf: Pointer to the buffer containing provision PDUs + * + * @return Zero - success, otherwise - fail + */ +int provisioner_pb_gatt_recv(struct bt_mesh_conn *conn, struct net_buf_simple *buf); + +/** + * @brief This function initializes provisioner's PB-GATT and PB-ADV + * related information. + * + * @param[in] prov_info: Pointer to the application-initialized provisioner info. + * + * @return Zero - success, otherwise - fail + */ +int provisioner_prov_init(const struct bt_mesh_prov *prov_info); + +/** + * @brief This function parses the received unprovisioned device + * beacon advertising packets, and if checked, starts to provision this device + * using PB-ADV bearer. + * + * @param[in] buf: Pointer to the buffer containing unprovisioned device beacon + * + * @return None + */ +void provisioner_unprov_beacon_recv(struct net_buf_simple *buf); + +/** + * @brief This function parses the flags part of the + * received connectable mesh provisioning advertising packets. + * + * @param[in] buf: Pointer to the buffer containing advertising flags part + * + * @return True - success, False - fail + */ +bool provisioner_flags_match(struct net_buf_simple *buf); + +/** + * @brief This function parses the service UUID part of the + * received connectable mesh provisioning advertising packets. + * + * @param[in] buf: Pointer to the buffer containing service UUID part + * + * @return Zero - fail, otherwise - Service UUID(0x1827 or 0x1828) + */ +u16_t provisioner_srv_uuid_recv(struct net_buf_simple *buf); + +/** + * @brief This function parses the service data part of the + * received connectable mesh provisioning advertising packets. + * + * @param[in] buf: Pointer to the buffer containing the remianing service data part + * @param[in] addr: Pointer to the received device address + * @param[in] uuid: Service UUID contained in the service UUID part + * + * @return None + */ +void provisioner_srv_data_recv(struct net_buf_simple *buf, const bt_mesh_addr_t *addr, u16_t uuid); + +/** + * @brief This function gets the bt_mesh_prov pointer. + * + * @return bt_mesh_prov pointer(prov) + */ +const struct bt_mesh_prov *provisioner_get_prov_info(void); + +/** + * @brief This function resets all nodes information in provisioner_prov.c. + * + * @return Zero + */ +int provisioner_prov_reset_all_nodes(void); + +/* The following APIs are for primary provisioner application use */ + +/** @brief Add unprovisioned device info to unprov_dev queue + * + * @param[in] add_dev: Pointer to the structure containing the device information + * @param[in] flags: Flags indicate several operations of the device information + * - Remove device information from queue after it is provisioned (BIT0) + * - Start provisioning as soon as device is added to queue (BIT1) + * - Device can be flushed when device queue is full (BIT2) + * + * @return Zero on success or (negative) error code otherwise. + * + * @Note: 1. Currently address type only supports public address and static random address. + * 2. If device UUID and/or device address and address type already exist in the + * device queue, but the bearer differs from the existing one, add operation + * will also be successful and it will update the provision bearer supported by + * the device. + */ +int bt_mesh_provisioner_add_unprov_dev(struct bt_mesh_unprov_dev_add *add_dev, u8_t flags); + +/** @brief Delete device from queue, reset current provisioning link and reset the node + * + * @param[in] del_dev: Pointer to the structure containing the device information + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_mesh_provisioner_delete_device(struct bt_mesh_device_delete *del_dev); + +/** + * @brief This function sets a part of the device UUID for comparison before + * starting to provision the device. + * + * @param[in] offset: offset of the device UUID to be compared + * @param[in] length: length of the device UUID to be compared + * @param[in] match: value to be compared + * @param[in] prov_flag: flags indicate if uuid_match advertising packets are received, after that + * the device will be provisioned at once or reported to the application layer + * + * @return Zero - success, otherwise - fail + */ +int bt_mesh_provisioner_set_dev_uuid_match(u8_t offset, u8_t length, + const u8_t *match, bool prov_flag); + +/** @brief Callback for provisioner receiving advertising packet from unprovisioned devices which are + * not in the unprovisioned device queue. + * + * Report on the unprovisioned device beacon and mesh provisioning service advertising data to application layer + * + * @param addr Unprovisioned device address pointer + * @param addr_type Unprovisioned device address type + * @param dev_uuid Unprovisioned device device UUID pointer + * @param bearer Advertising packet received from PB-GATT or PB-ADV bearer + * @param adv_type Adv packet type, currently this is not used and we can use bearer to device + * the adv_type(ADV_IND or ADV_NONCONN_IND). This parameter will be used, when + * scan response data will be supported. + * + */ +typedef void (*unprov_adv_pkt_cb_t)(const u8_t addr[6], const u8_t addr_type, + const u8_t adv_type, const u8_t dev_uuid[16], + u16_t oob_info, bt_mesh_prov_bearer_t bearer); + +/** + * @brief This function registers the callback which notifies the application + * layer of the received mesh provisioning or unprovisioned device + * beacon advertizing packets (from devices not in the unprov device queue). + * + * @param[in] cb: Callback of the notifying adv pkts function + * + * @return Zero - success, otherwise - fail + */ +int bt_mesh_prov_adv_pkt_cb_register(unprov_adv_pkt_cb_t cb); + +/** + * @brief This function changes net_idx or flags or iv_index used in provisioning data. + * + * @param[in] info: Pointer of structure containing net_idx or flags or iv_index + * + * @return Zero - success, otherwise - fail + */ +int bt_mesh_provisioner_set_prov_data_info(struct bt_mesh_prov_data_info *info); + +/** + * @brief This function is called to input number/string out-put by unprovisioned device. + * + * @param[in] idx The provisioning link index + * @param[in] val Pointer of the input number/string + * @param[in] num_flag Flag indicates if it is a number or string + * + * @return Zero - success, otherwise - fail + */ +int bt_mesh_prov_set_oob_input_data(const u8_t idx, const u8_t *val, bool num_flag); + +/** + * @brief This function is called to output number/string which will be input by unprovisioned device. + * + * @param[in] idx The provisioning link index + * @param[in] num Pointer of the output number/string + * @param[in] size Size of the output number/string + * @param[in] num_flag Flag indicates if it is a number or string + * + * @return Zero - success, otherwise - fail + */ +#if 0 +int bt_mesh_prov_set_oob_output_data(const u8_t idx, u8_t *num, u8_t size, bool num_flag); +#endif + +/** + * @brief This function is called to read unprovisioned device's oob public key. + * + * @param[in] idx The provisioning link index + * @param[in] pub_key_x Unprovisioned device's Public Key X + * @param[in] pub_key_y Unprovisioned device's Public Key Y + * + * @return Zero - success, otherwise - fail + */ +int bt_mesh_prov_read_oob_pub_key(const u8_t idx, const u8_t pub_key_x[32], const u8_t pub_key_y[32]); + +/* The following APIs are for fast provisioning */ + +/** + * @brief This function is called to set fast_prov_flag. + * + * @param[in] flag: Flag set to fast_prov_flag + * + * @return None + */ +void provisioner_set_fast_prov_flag(bool flag); + +/** + * @brief This function is called to set netkey index used for fast provisioning. + * + * @param[in] net_key: Netkey value + * @param[in] net_idx: Netkey index + * + * @return status for set netkey index msg + */ +u8_t provisioner_set_fast_prov_net_idx(const u8_t *net_key, u16_t net_idx); + +/** + * @brief This function is called to get netkey index used for fast provisioning. + * + * @return net_idx of fast provisioning + */ +u16_t provisioner_get_fast_prov_net_idx(void); + +/** + * @brief This function is called to set unicast address range used for fast provisioning. + * + * @param[in] min: Minimum unicast address + * @param[in] max: Maximum unicast address + * + * @return status for set unicast address range message + */ +u8_t bt_mesh_set_fast_prov_unicast_addr_range(u16_t min, u16_t max); + +/** + * @brief This function is called to set flags & iv_index used for fast provisioning. + * + * @param[in] flags: Key refresh flag and iv update flag + * @param[in] iv_index: IV index + * + * @return None + */ +void bt_mesh_set_fast_prov_flags_iv_index(u8_t flags, u32_t iv_index); + +#endif /* _PROVISIONER_PROV_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/provisioner_proxy.c b/components/bt/ble_mesh/mesh_core/provisioner_proxy.c new file mode 100644 index 0000000000..2961af3c42 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/provisioner_proxy.c @@ -0,0 +1,608 @@ +// Copyright 2017-2018 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 +#include + +#include "sdkconfig.h" + +#include "mesh_bearer_adapt.h" +#include "mesh_trace.h" + +#include "net.h" +#include "beacon.h" +#include "foundation.h" +#include "provisioner_prov.h" +#include "provisioner_proxy.h" +#include "provisioner_beacon.h" + +#if CONFIG_BLE_MESH_PROVISIONER + +#define PDU_TYPE(data) (data[0] & BIT_MASK(6)) +#define PDU_SAR(data) (data[0] >> 6) + +#define SAR_COMPLETE 0x00 +#define SAR_FIRST 0x01 +#define SAR_CONT 0x02 +#define SAR_LAST 0x03 + +#define CFG_FILTER_SET 0x00 +#define CFG_FILTER_ADD 0x01 +#define CFG_FILTER_REMOVE 0x02 +#define CFG_FILTER_STATUS 0x03 + +#define PDU_HDR(sar, type) (sar << 6 | (type & BIT_MASK(6))) + +#define SERVER_BUF_SIZE 68 + +#define ID_TYPE_NET 0x00 +#define ID_TYPE_NODE 0x01 + +#define NODE_ID_LEN 19 +#define NET_ID_LEN 11 + +#define CLOSE_REASON_PROXY 0xFF + +static int conn_count; + +static struct bt_mesh_proxy_server { + struct bt_mesh_conn *conn; + /* Provisioner can use filter to double check the dst within mesh messages */ + u16_t filter[CONFIG_BLE_MESH_PROXY_FILTER_SIZE]; + enum __packed { + NONE, + WHITELIST, + BLACKLIST, + PROV, + } filter_type; + u8_t msg_type; + struct net_buf_simple buf; +} servers[BLE_MESH_MAX_CONN]; + +static u8_t server_buf_data[SERVER_BUF_SIZE * BLE_MESH_MAX_CONN]; + +static struct bt_mesh_proxy_server *find_server(struct bt_mesh_conn *conn) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(servers); i++) { + if (servers[i].conn == conn) { + return &servers[i]; + } + } + + return NULL; +} + +static int filter_status(struct bt_mesh_proxy_server *server, + struct net_buf_simple *buf) +{ + /* TODO: Deal with received proxy configuration status messages */ + return 0; +} + +#if 0 +static void send_filter_set(struct bt_mesh_proxy_server *server, + struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf) +{ + /* TODO: Act as proxy client, send proxy configuration set messages */ +} + +static void send_filter_add(struct bt_mesh_proxy_server *server, + struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf) +{ + /* TODO: Act as proxy client, send proxy configuration add messages */ +} + +static void send_filter_remove(struct bt_mesh_proxy_server *server, + struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf) +{ + /* TODO: Act as proxy client, send proxy configuration remove messages */ +} +#endif + +static void proxy_cfg(struct bt_mesh_proxy_server *server) +{ + NET_BUF_SIMPLE_DEFINE(buf, 29); + struct bt_mesh_net_rx rx; + u8_t opcode; + int err; + + /** In order to deal with proxy configuration messages, provisioner should + * do sth. like create mesh network after each device is provisioned. + */ + err = bt_mesh_net_decode(&server->buf, BLE_MESH_NET_IF_PROXY_CFG, + &rx, &buf); + if (err) { + BT_ERR("%s, Failed to decode Proxy Configuration (err %d)", __func__, err); + return; + } + + /* Remove network headers */ + net_buf_simple_pull(&buf, BLE_MESH_NET_HDR_LEN); + + BT_DBG("%u bytes: %s", buf.len, bt_hex(buf.data, buf.len)); + + if (buf.len < 1) { + BT_WARN("Too short proxy configuration PDU"); + return; + } + + opcode = net_buf_simple_pull_u8(&buf); + switch (opcode) { + case CFG_FILTER_STATUS: + filter_status(server, &buf); + break; + default: + BT_WARN("Unhandled configuration OpCode 0x%02x", opcode); + break; + } +} + +static void proxy_complete_pdu(struct bt_mesh_proxy_server *server) +{ + switch (server->msg_type) { +#if defined(CONFIG_BLE_MESH_GATT_PROXY) + case BLE_MESH_PROXY_NET_PDU: + BT_DBG("Mesh Network PDU"); + bt_mesh_net_recv(&server->buf, 0, BLE_MESH_NET_IF_PROXY); + break; + case BLE_MESH_PROXY_BEACON: + BT_DBG("Mesh Beacon PDU"); + provisioner_beacon_recv(&server->buf); + break; + case BLE_MESH_PROXY_CONFIG: + BT_DBG("Mesh Configuration PDU"); + proxy_cfg(server); + break; +#endif +#if defined(CONFIG_BLE_MESH_PB_GATT) + case BLE_MESH_PROXY_PROV: + BT_DBG("Mesh Provisioning PDU"); + provisioner_pb_gatt_recv(server->conn, &server->buf); + break; +#endif + default: + BT_WARN("Unhandled Message Type 0x%02x", server->msg_type); + break; + } + + net_buf_simple_reset(&server->buf); +} + +#define ATTR_IS_PROV(uuid) (uuid == BLE_MESH_UUID_MESH_PROV_VAL) + +static ssize_t proxy_recv(struct bt_mesh_conn *conn, + const struct bt_mesh_gatt_attr *attr, const void *buf, + u16_t len, u16_t offset, u8_t flags) +{ + struct bt_mesh_proxy_server *server = find_server(conn); + const u8_t *data = buf; + u16_t srvc_uuid = 0; + + if (!server) { + return -ENOTCONN; + } + + if (len < 1) { + BT_WARN("Too small Proxy PDU"); + return -EINVAL; + } + + srvc_uuid = bt_mesh_gattc_get_service_uuid(conn); + if (!srvc_uuid) { + BT_ERR("%s, No service uuid found", __func__); + return -ENOTCONN; + } + + if (ATTR_IS_PROV(srvc_uuid) != (PDU_TYPE(data) == BLE_MESH_PROXY_PROV)) { + BT_WARN("Proxy PDU type doesn't match GATT service uuid"); + return -EINVAL; + } + + if (len - 1 > net_buf_simple_tailroom(&server->buf)) { + BT_WARN("Too big proxy PDU"); + return -EINVAL; + } + + switch (PDU_SAR(data)) { + case SAR_COMPLETE: + if (server->buf.len) { + BT_WARN("Complete PDU while a pending incomplete one"); + return -EINVAL; + } + + server->msg_type = PDU_TYPE(data); + net_buf_simple_add_mem(&server->buf, data + 1, len - 1); + proxy_complete_pdu(server); + break; + + case SAR_FIRST: + if (server->buf.len) { + BT_WARN("First PDU while a pending incomplete one"); + return -EINVAL; + } + + server->msg_type = PDU_TYPE(data); + net_buf_simple_add_mem(&server->buf, data + 1, len - 1); + break; + + case SAR_CONT: + if (!server->buf.len) { + BT_WARN("Continuation with no prior data"); + return -EINVAL; + } + + if (server->msg_type != PDU_TYPE(data)) { + BT_WARN("Unexpected message type in continuation"); + return -EINVAL; + } + + net_buf_simple_add_mem(&server->buf, data + 1, len - 1); + break; + + case SAR_LAST: + if (!server->buf.len) { + BT_WARN("Last SAR PDU with no prior data"); + return -EINVAL; + } + + if (server->msg_type != PDU_TYPE(data)) { + BT_WARN("Unexpected message type in last SAR PDU"); + return -EINVAL; + } + + net_buf_simple_add_mem(&server->buf, data + 1, len - 1); + proxy_complete_pdu(server); + break; + } + + return len; +} + +static void proxy_prov_connected(const u8_t addr[6], struct bt_mesh_conn *conn, int id) +{ + struct bt_mesh_proxy_server *server = NULL; + + conn_count++; + + if (!servers[id].conn) { + server = &servers[id]; + } + + if (!server) { + BT_ERR("%s, No matching Proxy Client objects", __func__); + /** Disconnect current connection, clear part of prov_link + * information, like uuid, dev_addr, linking flag, etc. + */ + + return; + } + + server->conn = bt_mesh_conn_ref(conn); + server->filter_type = NONE; + memset(server->filter, 0, sizeof(server->filter)); + net_buf_simple_reset(&server->buf); + +#if defined(CONFIG_BLE_MESH_PB_GATT) + if (provisioner_set_prov_conn(addr, server->conn)) { + BT_ERR("%s, provisioner_set_prov_conn failed", __func__); + bt_mesh_gattc_disconnect(server->conn); + return; + } +#endif + + bt_mesh_gattc_exchange_mtu(id); +} + +static void proxy_prov_disconnected(struct bt_mesh_conn *conn, u8_t reason) +{ + struct bt_mesh_proxy_server *server = NULL; + int i; + + BT_DBG("conn %p, handle is %d, reason 0x%02x", conn, conn->handle, reason); + + if (conn_count) { + conn_count--; + } + + for (i = 0; i < ARRAY_SIZE(servers); i++) { + server = &servers[i]; + if (server->conn == conn) { + if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && + server->filter_type == PROV) { + provisioner_pb_gatt_close(conn, reason); + } + server->conn = NULL; + break; + } + } +} + +#if defined(CONFIG_BLE_MESH_PB_GATT) +static ssize_t prov_write_ccc_descr(struct bt_mesh_conn *conn, u8_t *addr) +{ + struct bt_mesh_proxy_server *server; + + server = find_server(conn); + + if (!server) { + BT_ERR("%s, No Proxy Server found", __func__); + return -ENOTCONN; + } + + if (server->filter_type == NONE) { + server->filter_type = PROV; + return provisioner_pb_gatt_open(conn, addr); + } + + return -EINVAL; +} + +static ssize_t prov_notification(struct bt_mesh_conn *conn, u8_t *data, u16_t len) +{ + struct bt_mesh_proxy_server *server; + + server = find_server(conn); + + if (!server) { + BT_ERR("%s, No Proxy Server found", __func__); + return -ENOTCONN; + } + + if (server->filter_type == PROV) { + return proxy_recv(conn, NULL, data, len, 0, 0); + } + + return -EINVAL; +} + +int provisioner_pb_gatt_enable(void) +{ + int i; + + BT_DBG("%s", __func__); + + for (i = 0; i < ARRAY_SIZE(servers); i++) { + if (servers[i].conn) { + servers[i].filter_type = PROV; + } + } + + return 0; +} + +int provisioner_pb_gatt_disable(void) +{ + int i; + + BT_DBG("%s", __func__); + + for (i = 0; i < ARRAY_SIZE(servers); i++) { + struct bt_mesh_proxy_server *server = &servers[i]; + + if (server->conn && server->filter_type == PROV) { + bt_mesh_gattc_disconnect(server->conn); + server->filter_type = NONE; + } + } + + return 0; +} + +#endif /* CONFIG_BLE_MESH_PB_GATT */ + +#if defined(CONFIG_BLE_MESH_GATT_PROXY) +static ssize_t proxy_write_ccc_descr(struct bt_mesh_conn *conn) +{ + struct bt_mesh_proxy_server *server; + + server = find_server(conn); + + if (!server) { + BT_ERR("%s, No Proxy Server found", __func__); + return -ENOTCONN; + } + + if (server->filter_type == NONE) { + server->filter_type = WHITELIST; + return 0; + } + + return -EINVAL; +} + +static ssize_t proxy_notification(struct bt_mesh_conn *conn, u8_t *data, u16_t len) +{ + return proxy_recv(conn, NULL, data, len, 0, 0); +} + +/** Currently provisioner does't need bt_mesh_provisioner_proxy_enable() + * and bt_mesh_provisioner_proxy_disable() functions, and once they are + * used, provisioner can be enabled to parse node_id_adv and net_id_adv + * in order to support proxy client role. + * And if gatt_proxy is disabled, provisioner can stop dealing with + * these two kinds of connectable advertising packets. + */ +int bt_mesh_provisioner_proxy_enable(void) +{ + int i; + + BT_DBG("%s", __func__); + + for (i = 0; i < ARRAY_SIZE(servers); i++) { + if (servers[i].conn) { + servers[i].filter_type = WHITELIST; + } + } + + /** TODO: Once at leat one device has been provisioned, provisioner + * can be set to allow receiving and parsing node_id & net_id adv + * packets, and we may use a global flag to indicate this. + */ + + return 0; +} + +static void bt_mesh_proxy_gatt_proxy_disconnect(void) +{ + int i; + + BT_DBG("%s", __func__); + + for (i = 0; i < ARRAY_SIZE(servers); i++) { + struct bt_mesh_proxy_server *server = &servers[i]; + + if (server->conn && (server->filter_type == WHITELIST || + server->filter_type == BLACKLIST)) { + server->filter_type = NONE; + bt_mesh_gattc_disconnect(server->conn); + } + } +} + +int bt_mesh_provisioner_proxy_disable(void) +{ + BT_DBG("%s", __func__); + + /** TODO: Once this function is invoked, provisioner shall stop + * receiving and parsing node_id & net_id adv packets, and if + * proxy connection exists, we should disconnect it. + */ + + bt_mesh_proxy_gatt_proxy_disconnect(); + + return 0; +} + +#endif /* CONFIG_BLE_MESH_GATT_PROXY */ + +static int proxy_send(struct bt_mesh_conn *conn, const void *data, u16_t len) +{ + BT_DBG("%u bytes: %s", len, bt_hex(data, len)); + +#if defined(CONFIG_BLE_MESH_GATT_PROXY) || defined(CONFIG_BLE_MESH_PB_GATT) + return bt_mesh_gattc_write_no_rsp(conn, NULL, data, len); +#endif + + return 0; +} + +static int proxy_prov_segment_and_send(struct bt_mesh_conn *conn, u8_t type, + struct net_buf_simple *msg) +{ + u16_t mtu; + + if (conn == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + BT_DBG("conn %p type 0x%02x len %u: %s", conn, type, msg->len, + bt_hex(msg->data, msg->len)); + + mtu = bt_mesh_gattc_get_mtu_info(conn); + if (!mtu) { + BT_ERR("%s, Conn used to get mtu does not exist", __func__); + return -ENOTCONN; + } + + /* ATT_MTU - OpCode (1 byte) - Handle (2 bytes) */ + mtu -= 3; + if (mtu > msg->len) { + net_buf_simple_push_u8(msg, PDU_HDR(SAR_COMPLETE, type)); + return proxy_send(conn, msg->data, msg->len); + } + + net_buf_simple_push_u8(msg, PDU_HDR(SAR_FIRST, type)); + proxy_send(conn, msg->data, mtu); + net_buf_simple_pull(msg, mtu); + + while (msg->len) { + if (msg->len + 1 < mtu) { + net_buf_simple_push_u8(msg, PDU_HDR(SAR_LAST, type)); + proxy_send(conn, msg->data, msg->len); + break; + } + + net_buf_simple_push_u8(msg, PDU_HDR(SAR_CONT, type)); + proxy_send(conn, msg->data, mtu); + net_buf_simple_pull(msg, mtu); + } + + return 0; +} + +int provisioner_proxy_send(struct bt_mesh_conn *conn, u8_t type, + struct net_buf_simple *msg) +{ + struct bt_mesh_proxy_server *server = find_server(conn); + + if (!server) { + BT_ERR("$%s, No Proxy Server found", __func__); + return -ENOTCONN; + } + + if ((server->filter_type == PROV) != (type == BLE_MESH_PROXY_PROV)) { + BT_ERR("%s, Invalid PDU type for Proxy Client", __func__); + return -EINVAL; + } + + return proxy_prov_segment_and_send(conn, type, msg); +} + +static struct bt_mesh_prov_conn_cb conn_callbacks = { + .connected = proxy_prov_connected, + .disconnected = proxy_prov_disconnected, +#if defined(CONFIG_BLE_MESH_PB_GATT) + .prov_write_descr = prov_write_ccc_descr, + .prov_notify = prov_notification, +#endif /* CONFIG_BLE_MESH_PB_GATT */ +#if defined(CONFIG_BLE_MESH_GATT_PROXY) + .proxy_write_descr = proxy_write_ccc_descr, + .proxy_notify = proxy_notification, +#endif /* CONFIG_BLE_MESH_GATT_PROXY */ +}; + +void provisioner_proxy_srv_data_recv(struct net_buf_simple *buf) +{ + /** TODO: Parse node_id_adv or net_id_adv pkts. Currently we + * don't support this function, and if realized later, proxy + * client need to check if there is server structure left + * before create connection with a server. + * check conn_count & CONFIG_BLE_MESH_PBG_SAME_TIME + */ +} + +int provisioner_proxy_init(void) +{ + int i; + + /* Initialize the server receive buffers */ + for (i = 0; i < ARRAY_SIZE(servers); i++) { + struct bt_mesh_proxy_server *server = &servers[i]; + + server->buf.size = SERVER_BUF_SIZE; + server->buf.__buf = server_buf_data + (i * SERVER_BUF_SIZE); + } + + bt_mesh_gattc_conn_cb_register(&conn_callbacks); + + return 0; +} + +#endif /* CONFIG_BLE_MESH_PROVISIONER */ diff --git a/components/bt/ble_mesh/mesh_core/provisioner_proxy.h b/components/bt/ble_mesh/mesh_core/provisioner_proxy.h new file mode 100644 index 0000000000..5da92f433b --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/provisioner_proxy.h @@ -0,0 +1,89 @@ +// Copyright 2017-2018 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. + +#ifndef _PROVISIONER_PROXY_H_ +#define _PROVISIONER_PROXY_H_ + +#include "mesh_buf.h" + +#define BLE_MESH_PROXY_NET_PDU 0x00 +#define BLE_MESH_PROXY_BEACON 0x01 +#define BLE_MESH_PROXY_CONFIG 0x02 +#define BLE_MESH_PROXY_PROV 0x03 + +/** + * @brief This function is called to send proxy protocol messages. + * + * @param[in] conn: Pointer to bt_conn structure + * @param[in] type: Proxy protocol message type + * @param[in] msg: Pointer to the buffer contains sending message. + * + * @return Zero-success, other-fail + */ +int provisioner_proxy_send(struct bt_mesh_conn *conn, u8_t type, struct net_buf_simple *msg); + +/** + * @brief This function is called to parse received node identity and net + * id adv pkts and create connection if deceided to. + * + * @param[in] buf: Pointer to the buffer contains received message. + * + * @return None + */ +void provisioner_proxy_srv_data_recv(struct net_buf_simple *buf); + +/** + * @brief This function is called to initialize proxy provisioner structure + * and register proxy connection related callbacks. + * + * @return Zero-success, other-fail + */ +int provisioner_proxy_init(void); + +/** + * @brief This function is called to enable dealing with proxy provisioning + * messages. + * + * @return Zero-success, other-fail + */ +int provisioner_pb_gatt_enable(void); + +/** + * @brief This function is called to disable dealing with proxy provisioning + * messages and if proxy provisioning connections exist, the connections + * will be disconnected. + * + * @return Zero-success, other-fail + */ +int provisioner_pb_gatt_disable(void); + +/* The following APIs are for application use */ +/** + * @brief This function is called to enable receiving node identity and net + * id adv pkts. + * + * @return Zero-success, other-fail + */ +int bt_mesh_provisioner_proxy_enable(void); + +/** + * @brief This function is called to disable receiving node identity and net + * id adv pkts, and if proxy connections exist, these connections will + * be disconnected. + * + * @return Zero-success, other-fail + */ +int bt_mesh_provisioner_proxy_disable(void); + +#endif /* _PROVISIONER_PROXY_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/proxy.c b/components/bt/ble_mesh/mesh_core/proxy.c new file mode 100644 index 0000000000..fd9807f54b --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/proxy.c @@ -0,0 +1,1393 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +#include "sdkconfig.h" +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BLE_MESH_DEBUG_PROXY) + +#include "mesh_buf.h" +#include "mesh_util.h" +#include "mesh_bearer_adapt.h" +#include "mesh_trace.h" + +#include "mesh.h" +#include "adv.h" +#include "net.h" +#include "prov.h" +#include "beacon.h" +#include "foundation.h" +#include "access.h" +#include "proxy.h" + +#if CONFIG_BLE_MESH_NODE + +#define PDU_TYPE(data) (data[0] & BIT_MASK(6)) +#define PDU_SAR(data) (data[0] >> 6) + +#define SAR_COMPLETE 0x00 +#define SAR_FIRST 0x01 +#define SAR_CONT 0x02 +#define SAR_LAST 0x03 + +#define CFG_FILTER_SET 0x00 +#define CFG_FILTER_ADD 0x01 +#define CFG_FILTER_REMOVE 0x02 +#define CFG_FILTER_STATUS 0x03 + +#define PDU_HDR(sar, type) (sar << 6 | (type & BIT_MASK(6))) + +#define CLIENT_BUF_SIZE 68 + +#define ADV_OPT (BLE_MESH_ADV_OPT_CONNECTABLE | BLE_MESH_ADV_OPT_ONE_TIME) + +static const struct bt_mesh_adv_param slow_adv_param = { + .options = ADV_OPT, + .interval_min = BLE_MESH_GAP_ADV_SLOW_INT_MIN, + .interval_max = BLE_MESH_GAP_ADV_SLOW_INT_MAX, +}; + +static const struct bt_mesh_adv_param fast_adv_param = { + .options = ADV_OPT, + .interval_min = BLE_MESH_GAP_ADV_FAST_INT_MIN_0, + .interval_max = BLE_MESH_GAP_ADV_FAST_INT_MAX_0, +}; + +static bool proxy_adv_enabled; + +#if defined(CONFIG_BLE_MESH_GATT_PROXY) +static void proxy_send_beacons(struct k_work *work); +static u16_t proxy_ccc_val; +#endif + +#if defined(CONFIG_BLE_MESH_PB_GATT) +static u16_t prov_ccc_val; +static bool prov_fast_adv; +#endif + +enum { + SAR_TIMER_START, /* Timer for SAR transfer has been started */ + NUM_FLAGS, +}; + +#define PROXY_SAR_TRANS_TIMEOUT K_SECONDS(20) + +static struct bt_mesh_proxy_client { + struct bt_mesh_conn *conn; + u16_t filter[CONFIG_BLE_MESH_PROXY_FILTER_SIZE]; + enum __packed { + NONE, + WHITELIST, + BLACKLIST, + PROV, + } filter_type; + u8_t msg_type; +#if defined(CONFIG_BLE_MESH_GATT_PROXY) + struct k_work send_beacons; +#endif + struct net_buf_simple buf; + /* Proxy Server: 20s timeout for each segmented proxy pdu */ + BLE_MESH_ATOMIC_DEFINE(flags, NUM_FLAGS); + struct k_delayed_work sar_timer; +} clients[BLE_MESH_MAX_CONN] = { + [0 ... (BLE_MESH_MAX_CONN - 1)] = { +#if defined(CONFIG_BLE_MESH_GATT_PROXY) + .send_beacons = _K_WORK_INITIALIZER(proxy_send_beacons), +#endif + }, +}; + +static u8_t client_buf_data[CLIENT_BUF_SIZE * BLE_MESH_MAX_CONN]; + +/* Track which service is enabled */ +static enum { + MESH_GATT_NONE, + MESH_GATT_PROV, + MESH_GATT_PROXY, +} gatt_svc = MESH_GATT_NONE; + +static char device_name[DEVICE_NAME_SIZE] = "ESP-BLE-MESH"; + +int bt_mesh_set_device_name(const char *name) +{ + if (!name) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + if (strlen(name) > DEVICE_NAME_SIZE) { + BT_ERR("%s, Too long device name", __func__); + return -EINVAL; + } + + memset(device_name, 0x0, sizeof(device_name)); + memcpy(device_name, name, strlen(name)); + + return 0; +} + +static struct bt_mesh_proxy_client *find_client(struct bt_mesh_conn *conn) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(clients); i++) { + if (clients[i].conn == conn) { + return &clients[i]; + } + } + + return NULL; +} + +#if defined(CONFIG_BLE_MESH_GATT_PROXY) +/* Next subnet in queue to be advertised */ +static int next_idx; + +static int proxy_segment_and_send(struct bt_mesh_conn *conn, u8_t type, + struct net_buf_simple *msg); + +static int filter_set(struct bt_mesh_proxy_client *client, + struct net_buf_simple *buf) +{ + u8_t type; + + if (buf->len < 1) { + BT_WARN("Too short Filter Set message"); + return -EINVAL; + } + + type = net_buf_simple_pull_u8(buf); + BT_DBG("type 0x%02x", type); + + switch (type) { + case 0x00: + (void)memset(client->filter, 0, sizeof(client->filter)); + client->filter_type = WHITELIST; + break; + case 0x01: + (void)memset(client->filter, 0, sizeof(client->filter)); + client->filter_type = BLACKLIST; + break; + default: + BT_WARN("Prohibited Filter Type 0x%02x", type); + return -EINVAL; + } + + return 0; +} + +static void filter_add(struct bt_mesh_proxy_client *client, u16_t addr) +{ + int i; + + BT_DBG("addr 0x%04x", addr); + + if (addr == BLE_MESH_ADDR_UNASSIGNED) { + return; + } + + for (i = 0; i < ARRAY_SIZE(client->filter); i++) { + if (client->filter[i] == addr) { + return; + } + } + + for (i = 0; i < ARRAY_SIZE(client->filter); i++) { + if (client->filter[i] == BLE_MESH_ADDR_UNASSIGNED) { + client->filter[i] = addr; + return; + } + } +} + +static void filter_remove(struct bt_mesh_proxy_client *client, u16_t addr) +{ + int i; + + BT_DBG("addr 0x%04x", addr); + + if (addr == BLE_MESH_ADDR_UNASSIGNED) { + return; + } + + for (i = 0; i < ARRAY_SIZE(client->filter); i++) { + if (client->filter[i] == addr) { + client->filter[i] = BLE_MESH_ADDR_UNASSIGNED; + return; + } + } +} + +static void send_filter_status(struct bt_mesh_proxy_client *client, + struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf) +{ + struct bt_mesh_net_tx tx = { + .sub = rx->sub, + .ctx = &rx->ctx, + .src = bt_mesh_primary_addr(), + }; + u16_t filter_size; + int i, err; + + /* Configuration messages always have dst unassigned */ + tx.ctx->addr = BLE_MESH_ADDR_UNASSIGNED; + + net_buf_simple_reset(buf); + net_buf_simple_reserve(buf, 10); + + net_buf_simple_add_u8(buf, CFG_FILTER_STATUS); + + if (client->filter_type == WHITELIST) { + net_buf_simple_add_u8(buf, 0x00); + } else { + net_buf_simple_add_u8(buf, 0x01); + } + + for (filter_size = 0U, i = 0; i < ARRAY_SIZE(client->filter); i++) { + if (client->filter[i] != BLE_MESH_ADDR_UNASSIGNED) { + filter_size++; + } + } + + net_buf_simple_add_be16(buf, filter_size); + + BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); + + err = bt_mesh_net_encode(&tx, buf, true); + if (err) { + BT_ERR("%s, Encoding Proxy cfg message failed (err %d)", __func__, err); + return; + } + + err = proxy_segment_and_send(client->conn, BLE_MESH_PROXY_CONFIG, buf); + if (err) { + BT_ERR("%s, Failed to send proxy cfg message (err %d)", __func__, err); + } +} + +static void proxy_cfg(struct bt_mesh_proxy_client *client) +{ + NET_BUF_SIMPLE_DEFINE(buf, 29); + struct bt_mesh_net_rx rx; + u8_t opcode; + int err; + + err = bt_mesh_net_decode(&client->buf, BLE_MESH_NET_IF_PROXY_CFG, + &rx, &buf); + if (err) { + BT_ERR("%s, Failed to decode Proxy Configuration (err %d)", __func__, err); + return; + } + + /* Remove network headers */ + net_buf_simple_pull(&buf, BLE_MESH_NET_HDR_LEN); + + BT_DBG("%u bytes: %s", buf.len, bt_hex(buf.data, buf.len)); + + if (buf.len < 1) { + BT_WARN("Too short proxy configuration PDU"); + return; + } + + opcode = net_buf_simple_pull_u8(&buf); + switch (opcode) { + case CFG_FILTER_SET: + filter_set(client, &buf); + send_filter_status(client, &rx, &buf); + break; + case CFG_FILTER_ADD: + while (buf.len >= 2) { + u16_t addr; + + addr = net_buf_simple_pull_be16(&buf); + filter_add(client, addr); + } + send_filter_status(client, &rx, &buf); + break; + case CFG_FILTER_REMOVE: + while (buf.len >= 2) { + u16_t addr; + + addr = net_buf_simple_pull_be16(&buf); + filter_remove(client, addr); + } + send_filter_status(client, &rx, &buf); + break; + default: + BT_WARN("Unhandled configuration OpCode 0x%02x", opcode); + break; + } +} + +static int beacon_send(struct bt_mesh_conn *conn, struct bt_mesh_subnet *sub) +{ + NET_BUF_SIMPLE_DEFINE(buf, 23); + + net_buf_simple_reserve(&buf, 1); + bt_mesh_beacon_create(sub, &buf); + + return proxy_segment_and_send(conn, BLE_MESH_PROXY_BEACON, &buf); +} + +static void proxy_send_beacons(struct k_work *work) +{ + struct bt_mesh_proxy_client *client; + int i; + + client = CONTAINER_OF(work, struct bt_mesh_proxy_client, send_beacons); + + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; + + if (sub->net_idx != BLE_MESH_KEY_UNUSED) { + beacon_send(client->conn, sub); + } + } +} + +void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub) +{ + int i; + + if (!sub) { + /* NULL means we send on all subnets */ + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + if (bt_mesh.sub[i].net_idx != BLE_MESH_KEY_UNUSED) { + bt_mesh_proxy_beacon_send(&bt_mesh.sub[i]); + } + } + + return; + } + + for (i = 0; i < ARRAY_SIZE(clients); i++) { + if (clients[i].conn) { + beacon_send(clients[i].conn, sub); + } + } +} + +void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub) +{ + sub->node_id = BLE_MESH_NODE_IDENTITY_RUNNING; + sub->node_id_start = k_uptime_get_32(); + + /* Prioritize the recently enabled subnet */ + next_idx = sub - bt_mesh.sub; +} + +void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub) +{ + sub->node_id = BLE_MESH_NODE_IDENTITY_STOPPED; + sub->node_id_start = 0U; +} + +int bt_mesh_proxy_identity_enable(void) +{ + int i, count = 0; + + BT_DBG("%s", __func__); + + if (!bt_mesh_is_provisioned()) { + return -EAGAIN; + } + + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; + + if (sub->net_idx == BLE_MESH_KEY_UNUSED) { + continue; + } + + if (sub->node_id == BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED) { + continue; + } + + bt_mesh_proxy_identity_start(sub); + count++; + } + + if (count) { + bt_mesh_adv_update(); + } + + return 0; +} + +#endif /* GATT_PROXY */ + +static void proxy_complete_pdu(struct bt_mesh_proxy_client *client) +{ + switch (client->msg_type) { +#if defined(CONFIG_BLE_MESH_GATT_PROXY) + case BLE_MESH_PROXY_NET_PDU: + BT_DBG("Mesh Network PDU"); + bt_mesh_net_recv(&client->buf, 0, BLE_MESH_NET_IF_PROXY); + break; + case BLE_MESH_PROXY_BEACON: + BT_DBG("Mesh Beacon PDU"); + bt_mesh_beacon_recv(&client->buf); + break; + case BLE_MESH_PROXY_CONFIG: + BT_DBG("Mesh Configuration PDU"); + proxy_cfg(client); + break; +#endif +#if defined(CONFIG_BLE_MESH_PB_GATT) + case BLE_MESH_PROXY_PROV: + BT_DBG("Mesh Provisioning PDU"); + bt_mesh_pb_gatt_recv(client->conn, &client->buf); + break; +#endif + default: + BT_WARN("Unhandled Message Type 0x%02x", client->msg_type); + break; + } + + net_buf_simple_reset(&client->buf); +} + +#define ATTR_IS_PROV(attr) (attr->user_data != NULL) + +static ssize_t proxy_recv(struct bt_mesh_conn *conn, + const struct bt_mesh_gatt_attr *attr, const void *buf, + u16_t len, u16_t offset, u8_t flags) +{ + struct bt_mesh_proxy_client *client = find_client(conn); + const u8_t *data = buf; + + if (!client) { + return -ENOTCONN; + } + + if (len < 1) { + BT_WARN("Too small Proxy PDU"); + return -EINVAL; + } + + if (ATTR_IS_PROV(attr) != (PDU_TYPE(data) == BLE_MESH_PROXY_PROV)) { + BT_WARN("Proxy PDU type doesn't match GATT service"); + return -EINVAL; + } + + if (len - 1 > net_buf_simple_tailroom(&client->buf)) { + BT_WARN("Too big proxy PDU"); + return -EINVAL; + } + + switch (PDU_SAR(data)) { + case SAR_COMPLETE: + if (client->buf.len) { + BT_WARN("Complete PDU while a pending incomplete one"); + return -EINVAL; + } + + client->msg_type = PDU_TYPE(data); + net_buf_simple_add_mem(&client->buf, data + 1, len - 1); + proxy_complete_pdu(client); + break; + + case SAR_FIRST: + if (client->buf.len) { + BT_WARN("First PDU while a pending incomplete one"); + return -EINVAL; + } + + if (!bt_mesh_atomic_test_and_set_bit(client->flags, SAR_TIMER_START)) { + k_delayed_work_submit(&client->sar_timer, PROXY_SAR_TRANS_TIMEOUT); + } + + client->msg_type = PDU_TYPE(data); + net_buf_simple_add_mem(&client->buf, data + 1, len - 1); + break; + + case SAR_CONT: + if (!client->buf.len) { + BT_WARN("Continuation with no prior data"); + return -EINVAL; + } + + if (client->msg_type != PDU_TYPE(data)) { + BT_WARN("Unexpected message type in continuation"); + return -EINVAL; + } + + net_buf_simple_add_mem(&client->buf, data + 1, len - 1); + break; + + case SAR_LAST: + if (!client->buf.len) { + BT_WARN("Last SAR PDU with no prior data"); + return -EINVAL; + } + + if (client->msg_type != PDU_TYPE(data)) { + BT_WARN("Unexpected message type in last SAR PDU"); + return -EINVAL; + } + + if (bt_mesh_atomic_test_and_clear_bit(client->flags, SAR_TIMER_START)) { + k_delayed_work_cancel(&client->sar_timer); + } + + net_buf_simple_add_mem(&client->buf, data + 1, len - 1); + proxy_complete_pdu(client); + break; + } + + return len; +} + +static int conn_count; + +static void proxy_connected(struct bt_mesh_conn *conn, u8_t err) +{ + struct bt_mesh_proxy_client *client; + int i; + + BT_DBG("conn %p err 0x%02x", conn, err); + + conn_count++; + + /* Since we use ADV_OPT_ONE_TIME */ + proxy_adv_enabled = false; + + /* Try to re-enable advertising in case it's possible */ + if (conn_count < BLE_MESH_MAX_CONN) { + bt_mesh_adv_update(); + } + + for (client = NULL, i = 0; i < ARRAY_SIZE(clients); i++) { + if (!clients[i].conn) { + client = &clients[i]; + break; + } + } + + if (!client) { + BT_ERR("%s, No free Proxy Client objects", __func__); + return; + } + + client->conn = bt_mesh_conn_ref(conn); + client->filter_type = NONE; + (void)memset(client->filter, 0, sizeof(client->filter)); + net_buf_simple_reset(&client->buf); +} + +static void proxy_disconnected(struct bt_mesh_conn *conn, u8_t reason) +{ + int i; + + BT_DBG("conn %p reason 0x%02x", conn, reason); + + conn_count--; + + for (i = 0; i < ARRAY_SIZE(clients); i++) { + struct bt_mesh_proxy_client *client = &clients[i]; + + if (client->conn == conn) { + if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && + client->filter_type == PROV) { + bt_mesh_pb_gatt_close(conn); + } + + if (bt_mesh_atomic_test_and_clear_bit(client->flags, SAR_TIMER_START)) { + k_delayed_work_cancel(&client->sar_timer); + } + + bt_mesh_conn_unref(client->conn); + client->conn = NULL; + break; + } + } + + bt_mesh_adv_update(); +} + +struct net_buf_simple *bt_mesh_proxy_get_buf(void) +{ + struct net_buf_simple *buf = &clients[0].buf; + + net_buf_simple_reset(buf); + + return buf; +} + +#if defined(CONFIG_BLE_MESH_PB_GATT) +static ssize_t prov_ccc_write(struct bt_mesh_conn *conn, + const struct bt_mesh_gatt_attr *attr, + const void *buf, u16_t len, + u16_t offset, u8_t flags) +{ + struct bt_mesh_proxy_client *client; + u16_t *value = attr->user_data; + + BT_DBG("len %u: %s", len, bt_hex(buf, len)); + + if (len != sizeof(*value)) { + return BLE_MESH_GATT_ERR(BLE_MESH_ATT_ERR_INVALID_ATTRIBUTE_LEN); + } + + *value = sys_get_le16(buf); + if (*value != BLE_MESH_GATT_CCC_NOTIFY) { + BT_WARN("Client wrote 0x%04x instead enabling notify", *value); + return len; + } + + /* If a connection exists there must be a client */ + client = find_client(conn); + __ASSERT(client, "No client for connection"); + + if (client->filter_type == NONE) { + client->filter_type = PROV; + bt_mesh_pb_gatt_open(conn); + } + + return len; +} + +static ssize_t prov_ccc_read(struct bt_mesh_conn *conn, + const struct bt_mesh_gatt_attr *attr, + void *buf, u16_t len, u16_t offset) +{ + u16_t *value = attr->user_data; + + return bt_mesh_gatts_attr_read(conn, attr, buf, len, offset, value, + sizeof(*value)); +} + +/* Mesh Provisioning Service Declaration */ +static struct bt_mesh_gatt_attr prov_attrs[] = { + BLE_MESH_GATT_PRIMARY_SERVICE(BLE_MESH_UUID_MESH_PROV), + + BLE_MESH_GATT_CHARACTERISTIC(BLE_MESH_UUID_MESH_PROV_DATA_IN, + BLE_MESH_GATT_CHRC_WRITE_WITHOUT_RESP), + BLE_MESH_GATT_DESCRIPTOR(BLE_MESH_UUID_MESH_PROV_DATA_IN, BLE_MESH_GATT_PERM_WRITE, + NULL, proxy_recv, (void *)1), + + BLE_MESH_GATT_CHARACTERISTIC(BLE_MESH_UUID_MESH_PROV_DATA_OUT, + BLE_MESH_GATT_CHRC_NOTIFY), + BLE_MESH_GATT_DESCRIPTOR(BLE_MESH_UUID_MESH_PROV_DATA_OUT, BLE_MESH_GATT_PERM_NONE, + NULL, NULL, NULL), + /* Add custom CCC as clients need to be tracked individually */ + BLE_MESH_GATT_DESCRIPTOR(BLE_MESH_UUID_GATT_CCC, + BLE_MESH_GATT_PERM_WRITE | BLE_MESH_GATT_PERM_READ, + prov_ccc_read, prov_ccc_write, &prov_ccc_val), +}; + +struct bt_mesh_gatt_service prov_svc = BLE_MESH_GATT_SERVICE(prov_attrs); + +int bt_mesh_proxy_prov_enable(void) +{ + int i; + + BT_DBG("%s", __func__); + + if (gatt_svc == MESH_GATT_PROV) { + BT_WARN("%s, Already", __func__); + return -EALREADY; + } + + if (gatt_svc != MESH_GATT_NONE) { + BT_WARN("%s, Busy", __func__); + return -EBUSY; + } + + bt_mesh_gatts_service_start(&prov_svc); + gatt_svc = MESH_GATT_PROV; + prov_fast_adv = true; + + for (i = 0; i < ARRAY_SIZE(clients); i++) { + if (clients[i].conn) { + clients[i].filter_type = PROV; + } + } + + + return 0; +} + +int bt_mesh_proxy_prov_disable(bool disconnect) +{ + int i; + + BT_DBG("%s", __func__); + + if (gatt_svc == MESH_GATT_NONE) { + BT_WARN("%s, Already", __func__); + return -EALREADY; + } + + if (gatt_svc != MESH_GATT_PROV) { + BT_WARN("%s, Busy", __func__); + return -EBUSY; + } + + bt_mesh_gatts_service_stop(&prov_svc); + gatt_svc = MESH_GATT_NONE; + + for (i = 0; i < ARRAY_SIZE(clients); i++) { + struct bt_mesh_proxy_client *client = &clients[i]; + + if (!client->conn || client->filter_type != PROV) { + continue; + } + + if (disconnect) { + bt_mesh_gatts_disconnect(client->conn, 0x13); + } else { + bt_mesh_pb_gatt_close(client->conn); + client->filter_type = NONE; + } + } + + bt_mesh_adv_update(); + + return 0; +} + +#endif /* CONFIG_BLE_MESH_PB_GATT */ + +#if defined(CONFIG_BLE_MESH_GATT_PROXY) +static ssize_t proxy_ccc_write(struct bt_mesh_conn *conn, + const struct bt_mesh_gatt_attr *attr, + const void *buf, u16_t len, + u16_t offset, u8_t flags) +{ + struct bt_mesh_proxy_client *client; + u16_t value; + + BT_DBG("len %u: %s", len, bt_hex(buf, len)); + + if (len != sizeof(value)) { + return BLE_MESH_GATT_ERR(BLE_MESH_ATT_ERR_INVALID_ATTRIBUTE_LEN); + } + + value = sys_get_le16(buf); + if (value != BLE_MESH_GATT_CCC_NOTIFY) { + BT_WARN("Client wrote 0x%04x instead enabling notify", value); + return len; + } + + /* If a connection exists there must be a client */ + client = find_client(conn); + __ASSERT(client, "No client for connection"); + + if (client->filter_type == NONE) { + client->filter_type = WHITELIST; + k_work_submit(&client->send_beacons); + } + + return len; +} + +static ssize_t proxy_ccc_read(struct bt_mesh_conn *conn, + const struct bt_mesh_gatt_attr *attr, + void *buf, u16_t len, u16_t offset) +{ + u16_t *value = attr->user_data; + + return bt_mesh_gatts_attr_read(conn, attr, buf, len, offset, value, + sizeof(*value)); +} + +/* Mesh Proxy Service Declaration */ +static struct bt_mesh_gatt_attr proxy_attrs[] = { + BLE_MESH_GATT_PRIMARY_SERVICE(BLE_MESH_UUID_MESH_PROXY), + + BLE_MESH_GATT_CHARACTERISTIC(BLE_MESH_UUID_MESH_PROXY_DATA_IN, + BLE_MESH_GATT_CHRC_WRITE_WITHOUT_RESP), + BLE_MESH_GATT_DESCRIPTOR(BLE_MESH_UUID_MESH_PROXY_DATA_IN, BLE_MESH_GATT_PERM_WRITE, + NULL, proxy_recv, NULL), + + BLE_MESH_GATT_CHARACTERISTIC(BLE_MESH_UUID_MESH_PROXY_DATA_OUT, + BLE_MESH_GATT_CHRC_NOTIFY), + BLE_MESH_GATT_DESCRIPTOR(BLE_MESH_UUID_MESH_PROXY_DATA_OUT, BLE_MESH_GATT_PERM_NONE, + NULL, NULL, NULL), + /* Add custom CCC as clients need to be tracked individually */ + BLE_MESH_GATT_DESCRIPTOR(BLE_MESH_UUID_GATT_CCC, + BLE_MESH_GATT_PERM_READ | BLE_MESH_GATT_PERM_WRITE, + proxy_ccc_read, proxy_ccc_write, &proxy_ccc_val), +}; + +struct bt_mesh_gatt_service proxy_svc = BLE_MESH_GATT_SERVICE(proxy_attrs); + +int bt_mesh_proxy_gatt_enable(void) +{ + int i; + + BT_DBG("%s", __func__); + + if (gatt_svc == MESH_GATT_PROXY) { + BT_WARN("%s, Already", __func__); + return -EALREADY; + } + + if (gatt_svc != MESH_GATT_NONE) { + BT_WARN("%s, Busy", __func__); + return -EBUSY; + } + + bt_mesh_gatts_service_start(&proxy_svc); + gatt_svc = MESH_GATT_PROXY; + + for (i = 0; i < ARRAY_SIZE(clients); i++) { + if (clients[i].conn) { + clients[i].filter_type = WHITELIST; + } + } + + return 0; +} + +void bt_mesh_proxy_gatt_disconnect(void) +{ + int i; + + BT_DBG("%s", __func__); + + for (i = 0; i < ARRAY_SIZE(clients); i++) { + struct bt_mesh_proxy_client *client = &clients[i]; + + if (client->conn && (client->filter_type == WHITELIST || + client->filter_type == BLACKLIST)) { + client->filter_type = NONE; + bt_mesh_gatts_disconnect(client->conn, 0x13); + } + } +} + +int bt_mesh_proxy_gatt_disable(void) +{ + BT_DBG("%s", __func__); + + if (gatt_svc == MESH_GATT_NONE) { + BT_WARN("%s, Already", __func__); + return -EALREADY; + } + + if (gatt_svc != MESH_GATT_PROXY) { + BT_WARN("%s, Busy", __func__); + return -EBUSY; + } + + bt_mesh_proxy_gatt_disconnect(); + + bt_mesh_gatts_service_stop(&proxy_svc); + gatt_svc = MESH_GATT_NONE; + + return 0; +} + +void bt_mesh_proxy_addr_add(struct net_buf_simple *buf, u16_t addr) +{ + struct bt_mesh_proxy_client *client = + CONTAINER_OF(buf, struct bt_mesh_proxy_client, buf); + + BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr); + + if (client->filter_type == WHITELIST) { + filter_add(client, addr); + } else if (client->filter_type == BLACKLIST) { + filter_remove(client, addr); + } +} + +static bool client_filter_match(struct bt_mesh_proxy_client *client, + u16_t addr) +{ + int i; + + BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr); + + if (client->filter_type == WHITELIST) { + for (i = 0; i < ARRAY_SIZE(client->filter); i++) { + if (client->filter[i] == addr) { + return true; + } + } + + return false; + } + + if (client->filter_type == BLACKLIST) { + for (i = 0; i < ARRAY_SIZE(client->filter); i++) { + if (client->filter[i] == addr) { + return false; + } + } + + return true; + } + + return false; +} + +bool bt_mesh_proxy_relay(struct net_buf_simple *buf, u16_t dst) +{ + bool relayed = false; + int i; + + BT_DBG("%u bytes to dst 0x%04x", buf->len, dst); + + for (i = 0; i < ARRAY_SIZE(clients); i++) { + struct bt_mesh_proxy_client *client = &clients[i]; + NET_BUF_SIMPLE_DEFINE(msg, 32); + + if (!client->conn) { + continue; + } + + if (!client_filter_match(client, dst)) { + continue; + } + + /* Proxy PDU sending modifies the original buffer, + * so we need to make a copy. + */ + net_buf_simple_reserve(&msg, 1); + net_buf_simple_add_mem(&msg, buf->data, buf->len); + + bt_mesh_proxy_send(client->conn, BLE_MESH_PROXY_NET_PDU, &msg); + relayed = true; + } + + return relayed; +} + +#endif /* CONFIG_BLE_MESH_GATT_PROXY */ + +static int proxy_send(struct bt_mesh_conn *conn, const void *data, u16_t len) +{ + BT_DBG("%u bytes: %s", len, bt_hex(data, len)); + +#if defined(CONFIG_BLE_MESH_GATT_PROXY) + if (gatt_svc == MESH_GATT_PROXY) { + return bt_mesh_gatts_notify(conn, &proxy_attrs[4], data, len); + } +#endif + +#if defined(CONFIG_BLE_MESH_PB_GATT) + if (gatt_svc == MESH_GATT_PROV) { + return bt_mesh_gatts_notify(conn, &prov_attrs[4], data, len); + } +#endif + + return 0; +} + +static int proxy_segment_and_send(struct bt_mesh_conn *conn, u8_t type, + struct net_buf_simple *msg) +{ + u16_t mtu; + + BT_DBG("conn %p type 0x%02x len %u: %s", conn, type, msg->len, + bt_hex(msg->data, msg->len)); + + /* ATT_MTU - OpCode (1 byte) - Handle (2 bytes) */ + mtu = bt_mesh_gatt_get_mtu(conn) - 3; + if (mtu > msg->len) { + net_buf_simple_push_u8(msg, PDU_HDR(SAR_COMPLETE, type)); + return proxy_send(conn, msg->data, msg->len); + } + + net_buf_simple_push_u8(msg, PDU_HDR(SAR_FIRST, type)); + proxy_send(conn, msg->data, mtu); + net_buf_simple_pull(msg, mtu); + + while (msg->len) { + if (msg->len + 1 < mtu) { + net_buf_simple_push_u8(msg, PDU_HDR(SAR_LAST, type)); + proxy_send(conn, msg->data, msg->len); + break; + } + + net_buf_simple_push_u8(msg, PDU_HDR(SAR_CONT, type)); + proxy_send(conn, msg->data, mtu); + net_buf_simple_pull(msg, mtu); + } + + return 0; +} + +int bt_mesh_proxy_send(struct bt_mesh_conn *conn, u8_t type, + struct net_buf_simple *msg) +{ + struct bt_mesh_proxy_client *client = find_client(conn); + + if (!client) { + BT_ERR("%s, No Proxy Client found", __func__); + return -ENOTCONN; + } + + if ((client->filter_type == PROV) != (type == BLE_MESH_PROXY_PROV)) { + BT_ERR("%s, Invalid PDU type for Proxy Client", __func__); + return -EINVAL; + } + + return proxy_segment_and_send(conn, type, msg); +} + +#if defined(CONFIG_BLE_MESH_PB_GATT) +static u8_t prov_svc_data[20] = { 0x27, 0x18, }; + +static const struct bt_mesh_adv_data prov_ad[] = { + BLE_MESH_ADV_DATA_BYTES(BLE_MESH_DATA_FLAGS, (BLE_MESH_AD_GENERAL | BLE_MESH_AD_NO_BREDR)), + BLE_MESH_ADV_DATA_BYTES(BLE_MESH_DATA_UUID16_ALL, 0x27, 0x18), + BLE_MESH_ADV_DATA(BLE_MESH_DATA_SVC_DATA16, prov_svc_data, sizeof(prov_svc_data)), +}; +#endif /* PB_GATT */ + +#if defined(CONFIG_BLE_MESH_GATT_PROXY) + +#define ID_TYPE_NET 0x00 +#define ID_TYPE_NODE 0x01 + +#define NODE_ID_LEN 19 +#define NET_ID_LEN 11 + +#define NODE_ID_TIMEOUT K_SECONDS(CONFIG_BLE_MESH_NODE_ID_TIMEOUT) + +static u8_t proxy_svc_data[NODE_ID_LEN] = { 0x28, 0x18, }; + +static const struct bt_mesh_adv_data node_id_ad[] = { + BLE_MESH_ADV_DATA_BYTES(BLE_MESH_DATA_FLAGS, (BLE_MESH_AD_GENERAL | BLE_MESH_AD_NO_BREDR)), + BLE_MESH_ADV_DATA_BYTES(BLE_MESH_DATA_UUID16_ALL, 0x28, 0x18), + BLE_MESH_ADV_DATA(BLE_MESH_DATA_SVC_DATA16, proxy_svc_data, NODE_ID_LEN), +}; + +static const struct bt_mesh_adv_data net_id_ad[] = { + BLE_MESH_ADV_DATA_BYTES(BLE_MESH_DATA_FLAGS, (BLE_MESH_AD_GENERAL | BLE_MESH_AD_NO_BREDR)), + BLE_MESH_ADV_DATA_BYTES(BLE_MESH_DATA_UUID16_ALL, 0x28, 0x18), + BLE_MESH_ADV_DATA(BLE_MESH_DATA_SVC_DATA16, proxy_svc_data, NET_ID_LEN), +}; + +static int node_id_adv(struct bt_mesh_subnet *sub) +{ + u8_t tmp[16]; + int err; + + BT_DBG("%s", __func__); + + proxy_svc_data[2] = ID_TYPE_NODE; + + err = bt_mesh_rand(proxy_svc_data + 11, 8); + if (err) { + return err; + } + + (void)memset(tmp, 0, 6); + memcpy(tmp + 6, proxy_svc_data + 11, 8); + sys_put_be16(bt_mesh_primary_addr(), tmp + 14); + + err = bt_mesh_encrypt_be(sub->keys[sub->kr_flag].identity, tmp, tmp); + if (err) { + return err; + } + + memcpy(proxy_svc_data + 3, tmp + 8, 8); + + err = bt_le_adv_start(&fast_adv_param, node_id_ad, + ARRAY_SIZE(node_id_ad), NULL, 0); + if (err) { + BT_WARN("Failed to advertise using Node ID (err %d)", err); + return err; + } + + proxy_adv_enabled = true; + + return 0; +} + +static int net_id_adv(struct bt_mesh_subnet *sub) +{ + int err; + + BT_DBG("%s", __func__); + + proxy_svc_data[2] = ID_TYPE_NET; + + BT_DBG("Advertising with NetId %s", + bt_hex(sub->keys[sub->kr_flag].net_id, 8)); + + memcpy(proxy_svc_data + 3, sub->keys[sub->kr_flag].net_id, 8); + + err = bt_le_adv_start(&slow_adv_param, net_id_ad, + ARRAY_SIZE(net_id_ad), NULL, 0); + if (err) { + BT_WARN("Failed to advertise using Network ID (err %d)", err); + return err; + } + + proxy_adv_enabled = true; + + return 0; +} + +static bool advertise_subnet(struct bt_mesh_subnet *sub) +{ + if (sub->net_idx == BLE_MESH_KEY_UNUSED) { + return false; + } + + return (sub->node_id == BLE_MESH_NODE_IDENTITY_RUNNING || + bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED); +} + +static struct bt_mesh_subnet *next_sub(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + struct bt_mesh_subnet *sub; + + sub = &bt_mesh.sub[(i + next_idx) % ARRAY_SIZE(bt_mesh.sub)]; + if (advertise_subnet(sub)) { + next_idx = (next_idx + 1) % ARRAY_SIZE(bt_mesh.sub); + return sub; + } + } + + return NULL; +} + +static int sub_count(void) +{ + int i, count = 0; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; + + if (advertise_subnet(sub)) { + count++; + } + } + + return count; +} + +static s32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) +{ + s32_t remaining = K_FOREVER; + int subnet_count; + + BT_DBG("%s", __func__); + + if (conn_count == BLE_MESH_MAX_CONN) { + BT_WARN("Connectable advertising deferred (max connections)"); + return remaining; + } + + if (!sub) { + BT_WARN("No subnets to advertise on"); + return remaining; + } + + if (sub->node_id == BLE_MESH_NODE_IDENTITY_RUNNING) { + u32_t active = k_uptime_get_32() - sub->node_id_start; + + if (active < NODE_ID_TIMEOUT) { + remaining = NODE_ID_TIMEOUT - active; + BT_DBG("Node ID active for %u ms, %d ms remaining", + active, remaining); + node_id_adv(sub); + } else { + bt_mesh_proxy_identity_stop(sub); + BT_DBG("Node ID stopped"); + } + } + + if (sub->node_id == BLE_MESH_NODE_IDENTITY_STOPPED) { + if (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED) { + net_id_adv(sub); + } else { + return gatt_proxy_advertise(next_sub()); + } + } + + subnet_count = sub_count(); + BT_DBG("sub_count %u", subnet_count); + if (subnet_count > 1) { + s32_t max_timeout; + + /* We use NODE_ID_TIMEOUT as a starting point since it may + * be less than 60 seconds. Divide this period into at least + * 6 slices, but make sure that a slice is at least one + * second long (to avoid excessive rotation). + */ + max_timeout = NODE_ID_TIMEOUT / MAX(subnet_count, 6); + max_timeout = MAX(max_timeout, K_SECONDS(1)); + + if (remaining > max_timeout || remaining < 0) { + remaining = max_timeout; + } + } + + BT_DBG("Advertising %d ms for net_idx 0x%04x", remaining, sub->net_idx); + + return remaining; +} +#endif /* GATT_PROXY */ + +#if defined(CONFIG_BLE_MESH_PB_GATT) +static size_t gatt_prov_adv_create(struct bt_mesh_adv_data prov_sd[2]) +{ + const struct bt_mesh_prov *prov = bt_mesh_prov_get(); + const char *name = device_name; + size_t name_len = strlen(name); + size_t prov_sd_len = 0; + size_t sd_space = 31; + + memcpy(prov_svc_data + 2, prov->uuid, 16); + sys_put_be16(prov->oob_info, prov_svc_data + 18); + + if (prov->uri) { + size_t uri_len = strlen(prov->uri); + + if (uri_len > 29) { + /* There's no way to shorten an URI */ + BT_WARN("Too long URI to fit advertising packet"); + } else { + prov_sd[0].type = BLE_MESH_DATA_URI; + prov_sd[0].data_len = uri_len; + prov_sd[0].data = (const u8_t *)prov->uri; + sd_space -= 2 + uri_len; + prov_sd_len++; + } + } + + if (sd_space > 2 && name_len > 0) { + sd_space -= 2; + + if (sd_space < name_len) { + prov_sd[prov_sd_len].type = BLE_MESH_DATA_NAME_SHORTENED; + prov_sd[prov_sd_len].data_len = sd_space; + } else { + prov_sd[prov_sd_len].type = BLE_MESH_DATA_NAME_COMPLETE; + prov_sd[prov_sd_len].data_len = name_len; + } + + prov_sd[prov_sd_len].data = (const u8_t *)name; + prov_sd_len++; + } + + return prov_sd_len; +} +#endif /* CONFIG_BLE_MESH_PB_GATT */ + +s32_t bt_mesh_proxy_adv_start(void) +{ + BT_DBG("%s", __func__); + + if (gatt_svc == MESH_GATT_NONE) { + return K_FOREVER; + } + +#if defined(CONFIG_BLE_MESH_PB_GATT) + if (!bt_mesh_is_provisioned()) { + const struct bt_mesh_adv_param *param; + struct bt_mesh_adv_data prov_sd[2]; + size_t prov_sd_len; + + if (prov_fast_adv) { + param = &fast_adv_param; + } else { + param = &slow_adv_param; + } + + prov_sd_len = gatt_prov_adv_create(prov_sd); + + if (bt_le_adv_start(param, prov_ad, ARRAY_SIZE(prov_ad), + prov_sd, prov_sd_len) == 0) { + proxy_adv_enabled = true; + + /* Advertise 60 seconds using fast interval */ + if (prov_fast_adv) { + prov_fast_adv = false; + return K_SECONDS(60); + } + } + } +#endif /* PB_GATT */ + +#if defined(CONFIG_BLE_MESH_GATT_PROXY) + if (bt_mesh_is_provisioned()) { + return gatt_proxy_advertise(next_sub()); + } +#endif /* GATT_PROXY */ + + return K_FOREVER; +} + +void bt_mesh_proxy_adv_stop(void) +{ + int err; + + BT_DBG("adv_enabled %u", proxy_adv_enabled); + + if (!proxy_adv_enabled) { + return; + } + + err = bt_le_adv_stop(); + if (err) { + BT_ERR("%s, Failed to stop advertising (err %d)", __func__, err); + } else { + proxy_adv_enabled = false; + } +} + +static struct bt_mesh_conn_cb conn_callbacks = { + .connected = proxy_connected, + .disconnected = proxy_disconnected, +}; + +static void proxy_recv_timeout(struct k_work *work) +{ + struct bt_mesh_proxy_client *client = NULL; + + BT_DBG("%s", __func__); + + client = CONTAINER_OF(work, struct bt_mesh_proxy_client, sar_timer.work); + if (!client || !client->conn) { + BT_ERR("%s, Invalid proxy client parameter", __func__); + return; + } + + bt_mesh_atomic_clear_bit(client->flags, SAR_TIMER_START); + net_buf_simple_reset(&client->buf); + bt_mesh_gatts_disconnect(client->conn, 0x13); +} + +int bt_mesh_proxy_init(void) +{ + int i; + + /* Initialize the client receive buffers */ + for (i = 0; i < ARRAY_SIZE(clients); i++) { + struct bt_mesh_proxy_client *client = &clients[i]; + + client->buf.size = CLIENT_BUF_SIZE; + client->buf.__buf = client_buf_data + (i * CLIENT_BUF_SIZE); + k_delayed_work_init(&client->sar_timer, proxy_recv_timeout); + } + + bt_mesh_gatts_conn_cb_register(&conn_callbacks); + +#if defined(CONFIG_BLE_MESH_PB_GATT) + const struct bt_mesh_prov *prov = bt_mesh_prov_get(); + __ASSERT(prov && prov->uuid, "%s, Device UUID is not initialized", __func__); +#endif + + return 0; +} + +#endif /* CONFIG_BLE_MESH_NODE */ diff --git a/components/bt/ble_mesh/mesh_core/proxy.h b/components/bt/ble_mesh/mesh_core/proxy.h new file mode 100644 index 0000000000..07120e0950 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/proxy.h @@ -0,0 +1,51 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _PROXY_H_ +#define _PROXY_H_ + +#include "net.h" +#include "mesh_buf.h" +#include "mesh_bearer_adapt.h" + +#define BLE_MESH_PROXY_NET_PDU 0x00 +#define BLE_MESH_PROXY_BEACON 0x01 +#define BLE_MESH_PROXY_CONFIG 0x02 +#define BLE_MESH_PROXY_PROV 0x03 + +#define DEVICE_NAME_SIZE 29 + +int bt_mesh_set_device_name(const char *name); + +int bt_mesh_proxy_send(struct bt_mesh_conn *conn, u8_t type, + struct net_buf_simple *msg); + +int bt_mesh_proxy_prov_enable(void); +int bt_mesh_proxy_prov_disable(bool disconnect); + +int bt_mesh_proxy_gatt_enable(void); +int bt_mesh_proxy_gatt_disable(void); +void bt_mesh_proxy_gatt_disconnect(void); + +void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub); + +struct net_buf_simple *bt_mesh_proxy_get_buf(void); + +s32_t bt_mesh_proxy_adv_start(void); +void bt_mesh_proxy_adv_stop(void); + +void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub); +void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub); + +bool bt_mesh_proxy_relay(struct net_buf_simple *buf, u16_t dst); +void bt_mesh_proxy_addr_add(struct net_buf_simple *buf, u16_t addr); + +int bt_mesh_proxy_init(void); + +#endif /* _PROXY_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/settings.c b/components/bt/ble_mesh/mesh_core/settings.c new file mode 100644 index 0000000000..6606142c2b --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/settings.c @@ -0,0 +1,1578 @@ +/* + * Copyright (c) 2018 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "sdkconfig.h" +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BLE_MESH_DEBUG_SETTINGS) + +#include "mesh_types.h" +#include "mesh_util.h" +#include "mesh_access.h" +#include "mesh_main.h" +#include "mesh_buf.h" +#include "mesh_kernel.h" +#include "mesh_trace.h" +#include "mesh_common.h" + +#include "mesh.h" +#include "net.h" +#include "crypto.h" +#include "transport.h" +#include "access.h" +#include "foundation.h" +#include "proxy.h" +#include "cfg_srv.h" + +#include "settings_nvs.h" + +/* BLE Mesh NVS Key and corresponding data struct. + * Note: The length of nvs key must be <= 15. + * "xxxx" (2 octet) means the rpl_src, net_idx, app_idx, model_key, etc. + * Model model_key is a combination "elem_idx << 8 | model_idx". + * key: "mesh/net" -> write/read to set/get NET data + * key: "mesh/iv" -> write/read to set/get IV data + * key: "mesh/seq" -> write/read to set/get SEQ data + * key: "mesh/hb_pub" -> write/read to set/get CFG HB_PUB data + * key: "mesh/cfg" -> write/read to set/get CFG data + * key: "mesh/rpl" -> write/read to set/get all RPL src. + * key: "mesh/rpl/xxxx" -> write/read to set/get the "xxxx" RPL data + * key: "mesh/netkey" -> write/read to set/get all NetKey Indexes + * key: "mesh/nk/xxxx" -> write/read to set/get the "xxxx" NetKey data + * key: "mesh/appkey" -> write/read to set/get all AppKey Indexes + * key: "mesh/ak/xxxx" -> write/read to set/get the "xxxx" AppKey data + * key: "mesh/sig" -> write/read to set/get all SIG MODEL model_keys. + * key: "mesh/s/xxxx/b" -> write/read to set/get SIG MODEL Bind AppKey List + * key: "mesh/s/xxxx/s" -> write/read to set/get SIG MODEL Subscription List + * key: "mesh/s/xxxx/p" -> write/read to set/get SIG MODEL Publication + * key: "mesh/vnd" -> write/read to set/get all VENDOR MODEL model_keys. + * key: "mesh/v/xxxx/b" -> write/read to set/get VENDOR MODEL Bind AppKey List + * key: "mesh/v/xxxx/s" -> write/read to set/get VENDOR MODEL Subscription List + * key: "mesh/v/xxxx/p" -> write/read to set/get VENDOR MODEL Publication + */ + +#if CONFIG_BLE_MESH_SETTINGS + +#define GET_ELEMENT_IDX(x) ((u8_t)((x) >> 8)) +#define GET_MODEL_IDX(x) ((u8_t)(x)) +#define GET_MODEL_KEY(a, b) ((u16_t)(((u16_t)((a) << 8)) | b)) + +/* Tracking of what storage changes are pending for App and Net Keys. We + * track this in a separate array here instead of within the respective + * bt_mesh_app_key and bt_mesh_subnet structs themselves, since once a key + * gets deleted its struct becomes invalid and may be reused for other keys. + */ +static struct key_update { + u16_t key_idx: 12, /* AppKey or NetKey Index */ + valid: 1, /* 1 if this entry is valid, 0 if not */ + app_key: 1, /* 1 if this is an AppKey, 0 if a NetKey */ + clear: 1; /* 1 if key needs clearing, 0 if storing */ +} key_updates[CONFIG_BLE_MESH_APP_KEY_COUNT + CONFIG_BLE_MESH_SUBNET_COUNT]; + +static struct k_delayed_work pending_store; + +/* Mesh network storage information */ +struct net_val { + u16_t primary_addr; + u8_t dev_key[16]; +} __packed; + +/* Sequence number storage */ +struct seq_val { + u8_t val[3]; +} __packed; + +/* Heartbeat Publication storage */ +struct hb_pub_val { + u16_t dst; + u8_t period; + u8_t ttl; + u16_t feat; + u16_t net_idx: 12, + indefinite: 1; +}; + +/* Miscelaneous configuration server model states */ +struct cfg_val { + u8_t net_transmit; + u8_t relay; + u8_t relay_retransmit; + u8_t beacon; + u8_t gatt_proxy; + u8_t frnd; + u8_t default_ttl; +}; + +/* IV Index & IV Update storage */ +struct iv_val { + u32_t iv_index; + u8_t iv_update: 1, + iv_duration: 7; +} __packed; + +/* Replay Protection List storage */ +struct rpl_val { + u32_t seq: 24, + old_iv: 1; +}; + +/* NetKey storage information */ +struct net_key_val { + u8_t kr_flag: 1, + kr_phase: 7; + u8_t val[2][16]; +} __packed; + +/* AppKey storage information */ +struct app_key_val { + u16_t net_idx; + bool updated; + u8_t val[2][16]; +} __packed; + +struct mod_pub_val { + u16_t addr; + u16_t key; + u8_t ttl; + u8_t retransmit; + u8_t period; + u8_t period_div: 4, + cred: 1; +}; + +/* We need this so we don't overwrite app-hardcoded values in case FCB + * contains a history of changes but then has a NULL at the end. + */ +static struct { + bool valid; + struct cfg_val cfg; +} stored_cfg; + +static int net_set(const char *name) +{ + struct net_val net = {0}; + bool exist; + int err; + + BT_DBG("%s", __func__); + + err = bt_mesh_load_core_settings(name, (u8_t *)&net, sizeof(net), &exist); + if (err) { + BT_WARN("%s, Clear NET", __func__); + memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key)); + bt_mesh_comp_unprovision(); + return 0; + } + + if (exist == false) { + return 0; + } + + memcpy(bt_mesh.dev_key, net.dev_key, sizeof(bt_mesh.dev_key)); + bt_mesh_comp_provision(net.primary_addr); + + BT_DBG("Provisioned with primary address 0x%04x", net.primary_addr); + BT_DBG("Recovered DevKey %s", bt_hex(bt_mesh.dev_key, 16)); + + return 0; +} + +static int iv_set(const char *name) +{ + struct iv_val iv = {0}; + bool exist; + int err; + + BT_DBG("%s", __func__); + + err = bt_mesh_load_core_settings(name, (u8_t *)&iv, sizeof(iv), &exist); + if (err) { + BT_WARN("%s, Clear IV", __func__); + bt_mesh.iv_index = 0U; + bt_mesh_atomic_clear_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS); + return 0; + } + + if (exist == false) { + return 0; + } + + bt_mesh.iv_index = iv.iv_index; + bt_mesh_atomic_set_bit_to(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS, iv.iv_update); + bt_mesh.ivu_duration = iv.iv_duration; + + BT_DBG("IV Index 0x%04x (IV Update Flag %u) duration %u hours", + iv.iv_index, iv.iv_update, iv.iv_duration); + + return 0; +} + +static int seq_set(const char *name) +{ + struct seq_val seq = {0}; + bool exist; + int err; + + BT_DBG("%s", __func__); + + err = bt_mesh_load_core_settings(name, (u8_t *)&seq, sizeof(seq), &exist); + if (err) { + BT_WARN("%s, Clear SEQ", __func__); + bt_mesh.seq = 0U; + return 0; + } + + if (exist == false) { + return 0; + } + + bt_mesh.seq = ((u32_t)seq.val[0] | ((u32_t)seq.val[1] << 8) | + ((u32_t)seq.val[2] << 16)); + + if (CONFIG_BLE_MESH_SEQ_STORE_RATE > 0) { + /* Make sure we have a large enough sequence number. We + * subtract 1 so that the first transmission causes a write + * to the settings storage. + */ + bt_mesh.seq += (CONFIG_BLE_MESH_SEQ_STORE_RATE - + (bt_mesh.seq % CONFIG_BLE_MESH_SEQ_STORE_RATE)); + bt_mesh.seq--; + } + + BT_DBG("Sequence Number 0x%06x", bt_mesh.seq); + + return 0; +} + +static struct bt_mesh_rpl *rpl_find(u16_t src) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { + if (bt_mesh.rpl[i].src == src) { + return &bt_mesh.rpl[i]; + } + } + + return NULL; +} + +static struct bt_mesh_rpl *rpl_alloc(u16_t src) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { + if (bt_mesh.rpl[i].src == BLE_MESH_ADDR_UNASSIGNED) { + bt_mesh.rpl[i].src = src; + return &bt_mesh.rpl[i]; + } + } + + return NULL; +} + +static int rpl_set(const char *name) +{ + struct net_buf_simple *buf = NULL; + struct bt_mesh_rpl *entry = NULL; + struct rpl_val rpl = {0}; + char get[16] = {'\0'}; + size_t length; + bool exist; + int err = 0; + int i; + + BT_DBG("%s", __func__); + + buf = bt_mesh_get_core_settings_item(name); + if (!buf) { + return 0; + } + + length = buf->len; + + for (i = 0; i < length / SETTINGS_ITEM_SIZE; i++) { + u16_t src = net_buf_simple_pull_le16(buf); + sprintf(get, "mesh/rpl/%04x", src); + + err = bt_mesh_load_core_settings(get, (u8_t *)&rpl, sizeof(rpl), &exist); + if (err) { + BT_ERR("%s, Failed to load RPL %s, reset RPL", __func__, get); + bt_mesh_rpl_reset(); + goto free; + } + + if (exist == false) { + continue; + } + + entry = rpl_find(src); + if (!entry) { + entry = rpl_alloc(src); + if (!entry) { + BT_ERR("%s, No space for a new RPL 0x%04x", __func__, src); + err = -ENOMEM; + goto free; + } + } + + BT_DBG("RPL 0x%04x: Seq 0x%06x, old_iv %u", src, rpl.seq, rpl.old_iv); + entry->src = src; + entry->seq = rpl.seq; + entry->old_iv = rpl.old_iv; + } + +free: + bt_mesh_free_buf(buf); + return err; +} + +static struct bt_mesh_subnet *subnet_alloc(u16_t net_idx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + if (bt_mesh.sub[i].net_idx == BLE_MESH_KEY_UNUSED) { + bt_mesh.sub[i].net_idx = net_idx; + return &bt_mesh.sub[i]; + } + } + + return NULL; +} + +static int net_key_set(const char *name) +{ + struct net_buf_simple *buf = NULL; + struct bt_mesh_subnet *sub = NULL; + struct net_key_val key = {0}; + char get[16] = {'\0'}; + size_t length; + bool exist; + int err = 0; + int i; + + BT_DBG("%s", __func__); + + buf = bt_mesh_get_core_settings_item(name); + if (!buf) { + return 0; + } + + length = buf->len; + + for (i = 0; i < length / SETTINGS_ITEM_SIZE; i++) { + u16_t net_idx = net_buf_simple_pull_le16(buf); + sprintf(get, "mesh/nk/%04x", net_idx); + + err = bt_mesh_load_core_settings(get, (u8_t *)&key, sizeof(key), &exist); + if (err) { + BT_ERR("%s, Failed to load NetKey %s", __func__, get); + goto free; + } + + if (exist == false) { + continue; + } + + sub = bt_mesh_subnet_get(net_idx); + if (!sub) { + sub = subnet_alloc(net_idx); + if (!sub) { + BT_ERR("%s, No space for a new subnet 0x%03x", __func__, net_idx); + err = -ENOMEM; + goto free; + } + } + + BT_DBG("NetKeyIndex 0x%03x recovered from storage", net_idx); + sub->net_idx = net_idx; + sub->kr_flag = key.kr_flag; + sub->kr_phase = key.kr_phase; + memcpy(sub->keys[0].net, &key.val[0], 16); + memcpy(sub->keys[1].net, &key.val[1], 16); + } + +free: + bt_mesh_free_buf(buf); + return err; +} + +static int app_key_set(const char *name) +{ + struct bt_mesh_app_key *app = NULL; + struct bt_mesh_subnet *sub = NULL; + struct net_buf_simple *buf = NULL; + struct app_key_val key = {0}; + char get[16] = {'\0'}; + size_t length; + bool exist; + int err = 0; + int i; + + BT_DBG("%s", __func__); + + buf = bt_mesh_get_core_settings_item(name); + if (!buf) { + return 0; + } + + length = buf->len; + + for (i = 0; i < length / SETTINGS_ITEM_SIZE; i++) { + u16_t app_idx = net_buf_simple_pull_le16(buf); + sprintf(get, "mesh/ak/%04x", app_idx); + + err = bt_mesh_load_core_settings(get, (u8_t *)&key, sizeof(key), &exist); + if (err) { + BT_ERR("%s, Failed to load AppKey %s", __func__, get); + goto free; + } + + if (exist == false) { + continue; + } + + sub = bt_mesh_subnet_get(key.net_idx); + if (!sub) { + BT_ERR("%s, Failed to find subnet 0x%03x", __func__, key.net_idx); + err = -ENOENT; + goto free; + } + + app = bt_mesh_app_key_find(app_idx); + if (!app) { + app = bt_mesh_app_key_alloc(app_idx); + if (!app) { + BT_ERR("%s, No space for a new app key 0x%03x", __func__, app_idx); + err = -ENOMEM; + goto free; + } + } + + BT_DBG("AppKeyIndex 0x%03x recovered from storage", app_idx); + app->net_idx = key.net_idx; + app->app_idx = app_idx; + app->updated = key.updated; + memcpy(app->keys[0].val, key.val[0], 16); + memcpy(app->keys[1].val, key.val[1], 16); + bt_mesh_app_id(app->keys[0].val, &app->keys[0].id); + bt_mesh_app_id(app->keys[1].val, &app->keys[1].id); + } + +free: + bt_mesh_free_buf(buf); + return err; +} + +static int hb_pub_set(const char *name) +{ + struct bt_mesh_hb_pub *hb_pub = bt_mesh_hb_pub_get(); + struct hb_pub_val hb_val = {0}; + bool exist; + int err; + + BT_DBG("%s", __func__); + + if (!hb_pub) { + BT_ERR("%s, NULL cfg hb pub", __func__); + return -EINVAL; + } + + err = bt_mesh_load_core_settings(name, (u8_t *)&hb_val, sizeof(hb_val), &exist); + if (err) { + BT_WARN("%s, Cleared heartbeat publication", __func__); + hb_pub->dst = BLE_MESH_ADDR_UNASSIGNED; + hb_pub->count = 0U; + hb_pub->ttl = 0U; + hb_pub->period = 0U; + hb_pub->feat = 0U; + return 0; + } + + if (exist == false) { + return 0; + } + + hb_pub->dst = hb_val.dst; + hb_pub->period = hb_val.period; + hb_pub->ttl = hb_val.ttl; + hb_pub->feat = hb_val.feat; + hb_pub->net_idx = hb_val.net_idx; + if (hb_val.indefinite) { + hb_pub->count = 0xffff; + } else { + hb_pub->count = 0U; + } + + BT_DBG("Restore Heartbeat Publication"); + + return 0; +} + +static int cfg_set(const char *name) +{ + struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get(); + struct cfg_val val = {0}; + bool exist; + int err; + + BT_DBG("%s", __func__); + + if (!cfg) { + BT_ERR("%s, NULL cfg", __func__); + stored_cfg.valid = false; + return -EINVAL; + } + + err = bt_mesh_load_core_settings(name, (u8_t *)&val, sizeof(val), &exist); + if (err) { + BT_WARN("%s, Cleared configuration", __func__); + stored_cfg.valid = false; + return 0; + } + + if (exist == false) { + return 0; + } + + stored_cfg.valid = true; + BT_DBG("Restore configuration state"); + return 0; +} + +static int model_set_bind(bool vnd, struct bt_mesh_model *model, u16_t model_key) +{ + char name[16] = {'\0'}; + bool exist; + int i, err; + + /* Start with empty array regardless of cleared or set value */ + for (i = 0; i < ARRAY_SIZE(model->keys); i++) { + model->keys[i] = BLE_MESH_KEY_UNUSED; + } + + sprintf(name, "mesh/%s/%04x/b", vnd ? "v" : "s", model_key); + err = bt_mesh_load_core_settings(name, (u8_t *)model->keys, sizeof(model->keys), &exist); + if (err) { + BT_ERR("%s, Failed to get model bind keys", __func__); + return -EIO; + } + + return 0; +} + +static int model_set_sub(bool vnd, struct bt_mesh_model *model, u16_t model_key) +{ + char name[16] = {'\0'}; + bool exist; + int i, err; + + /* Start with empty array regardless of cleared or set value */ + for (i = 0; i < ARRAY_SIZE(model->groups); i++) { + model->groups[i] = BLE_MESH_ADDR_UNASSIGNED; + } + + sprintf(name, "mesh/%s/%04x/s", vnd ? "v" : "s", model_key); + err = bt_mesh_load_core_settings(name, (u8_t *)model->groups, sizeof(model->groups), &exist); + if (err) { + BT_ERR("%s, Failed to get model subscriptions", __func__); + return -EIO; + } + + return 0; +} + +static int model_set_pub(bool vnd, struct bt_mesh_model *model, u16_t model_key) +{ + struct mod_pub_val pub = {0}; + char name[16] = {'\0'}; + bool exist; + int err; + + if (!model->pub) { + BT_WARN("%s, Model has no publication context", __func__); + return 0; + } + + sprintf(name, "mesh/%s/%04x/p", vnd ? "v" : "s", model_key); + err = bt_mesh_load_core_settings(name, (u8_t *)&pub, sizeof(pub), &exist); + if (err) { + BT_WARN("%s, Cleared model publication", __func__); + model->pub->addr = BLE_MESH_ADDR_UNASSIGNED; + model->pub->key = 0U; + model->pub->cred = 0U; + model->pub->ttl = 0U; + model->pub->period = 0U; + model->pub->retransmit = 0U; + model->pub->count = 0U; + return 0; + } + + if (exist == false) { + return 0; + } + + model->pub->addr = pub.addr; + model->pub->key = pub.key; + model->pub->cred = pub.cred; + model->pub->ttl = pub.ttl; + model->pub->period = pub.period; + model->pub->retransmit = pub.retransmit; + model->pub->count = 0U; + + BT_DBG("Restore model publication, pub_addr 0x%04x app_idx 0x%03x", + pub.addr, pub.key); + + return 0; +} + +static int model_set(bool vnd, const char *name) +{ + struct bt_mesh_model *model = NULL; + struct net_buf_simple *buf = NULL; + u8_t elem_idx, model_idx; + size_t length; + int err = 0; + int i; + + BT_DBG("%s", __func__); + + buf = bt_mesh_get_core_settings_item(name); + if (!buf) { + return 0; + } + + length = buf->len; + + for (i = 0; i < length / SETTINGS_ITEM_SIZE; i++) { + u16_t model_key = net_buf_simple_pull_le16(buf); + elem_idx = GET_ELEMENT_IDX(model_key); + model_idx = GET_MODEL_IDX(model_key); + + model = bt_mesh_model_get(vnd, elem_idx, model_idx); + if (!model) { + BT_ERR("%s, Failed to get %s model, elem_idx %u model_idx %u", + __func__, vnd ? "vnd" : "sig", elem_idx, model_idx); + err = -ENOENT; + goto free; + } + + err = model_set_bind(vnd, model, model_key); + if (err) { + BT_ERR("%s, model_set_bind fail", __func__); + goto free; + } + + err = model_set_sub(vnd, model, model_key); + if (err) { + BT_ERR("%s, model_set_sub fail", __func__); + goto free; + } + + err = model_set_pub(vnd, model, model_key); + if (err) { + BT_ERR("%s, model_set_pub fail", __func__); + goto free; + } + } + +free: + bt_mesh_free_buf(buf); + return err; +} + +static int sig_mod_set(const char *name) +{ + return model_set(false, name); +} + +static int vnd_mod_set(const char *name) +{ + return model_set(true, name); +} + +const struct bt_mesh_setting { + const char *name; + int (*func)(const char *name); +} settings[] = { + { "mesh/net", net_set }, + { "mesh/iv", iv_set }, + { "mesh/seq", seq_set }, + { "mesh/rpl", rpl_set }, + { "mesh/netkey", net_key_set }, + { "mesh/appkey", app_key_set }, + { "mesh/hb_pub", hb_pub_set }, + { "mesh/cfg", cfg_set }, + { "mesh/sig", sig_mod_set }, + { "mesh/vnd", vnd_mod_set }, +}; + +int settings_core_load(void) +{ + int i; + + BT_DBG("%s", __func__); + + for (i = 0; i < ARRAY_SIZE(settings); i++) { + settings[i].func(settings[i].name); + } + + return 0; +} + +static int subnet_init(struct bt_mesh_subnet *sub) +{ + int err; + + err = bt_mesh_net_keys_create(&sub->keys[0], sub->keys[0].net); + if (err) { + BT_ERR("%s, Unable to generate keys for subnet", __func__); + return -EIO; + } + + if (sub->kr_phase != BLE_MESH_KR_NORMAL) { + err = bt_mesh_net_keys_create(&sub->keys[1], sub->keys[1].net); + if (err) { + BT_ERR("%s, Unable to generate keys for subnet", __func__); + (void)memset(&sub->keys[0], 0, sizeof(sub->keys[0])); + return -EIO; + } + } + + if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY)) { + sub->node_id = BLE_MESH_NODE_IDENTITY_STOPPED; + } else { + sub->node_id = BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED; + } + + /* Make sure we have valid beacon data to be sent */ + bt_mesh_net_beacon_update(sub); + + return 0; +} + +static void commit_model(struct bt_mesh_model *model, struct bt_mesh_elem *elem, + bool vnd, bool primary, void *user_data) +{ + if (model->pub && model->pub->update && + model->pub->addr != BLE_MESH_ADDR_UNASSIGNED) { + s32_t ms = bt_mesh_model_pub_period_get(model); + if (ms) { + BT_DBG("Starting publish timer (period %u ms)", ms); + k_delayed_work_submit(&model->pub->timer, ms); + } + } +} + +int settings_core_commit(void) +{ + struct bt_mesh_hb_pub *hb_pub = NULL; + struct bt_mesh_cfg_srv *cfg = NULL; + int i; + + BT_DBG("sub[0].net_idx 0x%03x", bt_mesh.sub[0].net_idx); + + if (bt_mesh.sub[0].net_idx == BLE_MESH_KEY_UNUSED) { + /* Nothing to do since we're not yet provisioned */ + return 0; + } + + if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT)) { +#if defined(CONFIG_BLE_MESH_NODE) + bt_mesh_proxy_prov_disable(true); +#endif + } + + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; + int err; + + if (sub->net_idx == BLE_MESH_KEY_UNUSED) { + continue; + } + + err = subnet_init(sub); + if (err) { + BT_ERR("%s, Failed to init subnet 0x%03x", __func__, sub->net_idx); + } + } + + if (bt_mesh.ivu_duration < BLE_MESH_IVU_MIN_HOURS) { + k_delayed_work_submit(&bt_mesh.ivu_timer, BLE_MESH_IVU_TIMEOUT); + } + + bt_mesh_model_foreach(commit_model, NULL); + + hb_pub = bt_mesh_hb_pub_get(); + if (hb_pub && hb_pub->dst != BLE_MESH_ADDR_UNASSIGNED && + hb_pub->count && hb_pub->period) { + BT_DBG("Starting heartbeat publication"); + k_work_submit(&hb_pub->timer.work); + } + + cfg = bt_mesh_cfg_get(); + if (cfg && stored_cfg.valid) { + cfg->net_transmit = stored_cfg.cfg.net_transmit; + cfg->relay = stored_cfg.cfg.relay; + cfg->relay_retransmit = stored_cfg.cfg.relay_retransmit; + cfg->beacon = stored_cfg.cfg.beacon; + cfg->gatt_proxy = stored_cfg.cfg.gatt_proxy; + cfg->frnd = stored_cfg.cfg.frnd; + cfg->default_ttl = stored_cfg.cfg.default_ttl; + } + + bt_mesh_atomic_set_bit(bt_mesh.flags, BLE_MESH_VALID); + +#if defined(CONFIG_BLE_MESH_NODE) + bt_mesh_net_start(); +#endif + + return 0; +} + +static void schedule_store(int flag) +{ + s32_t timeout; + + bt_mesh_atomic_set_bit(bt_mesh.flags, flag); + + if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_NET_PENDING) || + bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IV_PENDING) || + bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_SEQ_PENDING)) { + timeout = K_NO_WAIT; + } else if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_RPL_PENDING) && + (CONFIG_BLE_MESH_RPL_STORE_TIMEOUT < + CONFIG_BLE_MESH_STORE_TIMEOUT)) { + timeout = K_SECONDS(CONFIG_BLE_MESH_RPL_STORE_TIMEOUT); + } else { + timeout = K_SECONDS(CONFIG_BLE_MESH_STORE_TIMEOUT); + } + + BT_DBG("Waiting %d seconds", timeout / MSEC_PER_SEC); + + if (timeout) { + k_delayed_work_submit(&pending_store, timeout); + } else { + k_work_submit(&pending_store.work); + } +} + +static void clear_iv(void) +{ + BT_DBG("Clearing IV"); + bt_mesh_save_core_settings("mesh/iv", NULL, 0); +} + +static void clear_net(void) +{ + BT_DBG("Clearing Network"); + bt_mesh_save_core_settings("mesh/net", NULL, 0); +} + +static void store_pending_net(void) +{ + struct net_val net = {0}; + + BT_DBG("addr 0x%04x DevKey %s", bt_mesh_primary_addr(), + bt_hex(bt_mesh.dev_key, 16)); + + net.primary_addr = bt_mesh_primary_addr(); + memcpy(net.dev_key, bt_mesh.dev_key, 16); + + bt_mesh_save_core_settings("mesh/net", (const u8_t *)&net, sizeof(net)); +} + +void bt_mesh_store_net(void) +{ + schedule_store(BLE_MESH_NET_PENDING); +} + +static void store_pending_iv(void) +{ + struct iv_val iv = {0}; + + iv.iv_index = bt_mesh.iv_index; + iv.iv_update = bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS); + iv.iv_duration = bt_mesh.ivu_duration; + + bt_mesh_save_core_settings("mesh/iv", (const u8_t *)&iv, sizeof(iv)); +} + +void bt_mesh_store_iv(bool only_duration) +{ + schedule_store(BLE_MESH_IV_PENDING); + + if (!only_duration) { + /* Always update Seq whenever IV changes */ + schedule_store(BLE_MESH_SEQ_PENDING); + } +} + +static void store_pending_seq(void) +{ + struct seq_val seq = {0}; + + seq.val[0] = bt_mesh.seq; + seq.val[1] = bt_mesh.seq >> 8; + seq.val[2] = bt_mesh.seq >> 16; + + bt_mesh_save_core_settings("mesh/seq", (const u8_t *)&seq, sizeof(seq)); +} + +void bt_mesh_store_seq(void) +{ + if (CONFIG_BLE_MESH_SEQ_STORE_RATE && + (bt_mesh.seq % CONFIG_BLE_MESH_SEQ_STORE_RATE)) { + return; + } + + schedule_store(BLE_MESH_SEQ_PENDING); +} + +static void store_rpl(struct bt_mesh_rpl *entry) +{ + struct rpl_val rpl = {0}; + char name[16] = {'\0'}; + int err; + + BT_DBG("src 0x%04x seq 0x%06x old_iv %u", entry->src, entry->seq, entry->old_iv); + + rpl.seq = entry->seq; + rpl.old_iv = entry->old_iv; + + sprintf(name, "mesh/rpl/%04x", entry->src); + err = bt_mesh_save_core_settings(name, (const u8_t *)&rpl, sizeof(rpl)); + if (err) { + BT_ERR("%s, Failed to save RPL %s", __func__, name); + return; + } + + err = bt_mesh_add_core_settings_item("mesh/rpl", entry->src); + if (err) { + BT_ERR("%s, Failed to add 0x%04x to mesh/rpl", __func__, entry->src); + } + + return; +} + +static void clear_rpl(void) +{ + struct net_buf_simple *buf = NULL; + char name[16] = {'\0'}; + size_t length; + u16_t src; + int i; + + BT_DBG("%s", __func__); + + bt_mesh_rpl_clear(); + + buf = bt_mesh_get_core_settings_item("mesh/rpl"); + if (!buf) { + BT_WARN("%s, Erase RPL", __func__); + bt_mesh_save_core_settings("mesh/rpl", NULL, 0); + return; + } + + length = buf->len; + + for (i = 0; i < length / SETTINGS_ITEM_SIZE; i++) { + src = net_buf_simple_pull_le16(buf); + sprintf(name, "mesh/rpl/%04x", src); + bt_mesh_save_core_settings(name, NULL, 0); + } + + bt_mesh_save_core_settings("mesh/rpl", NULL, 0); + + bt_mesh_free_buf(buf); + return; +} + +static void store_pending_rpl(void) +{ + int i; + + BT_DBG("%s", __func__); + + for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { + struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; + + if (rpl->store) { + rpl->store = false; + store_rpl(rpl); + } + } +} + +static void store_pending_hb_pub(void) +{ + struct bt_mesh_hb_pub *hb_pub = bt_mesh_hb_pub_get(); + struct hb_pub_val val = {0}; + + if (!hb_pub) { + BT_WARN("%s, NULL hb_pub", __func__); + return; + } + + val.indefinite = (hb_pub->count = 0xffff); + val.dst = hb_pub->dst; + val.period = hb_pub->period; + val.ttl = hb_pub->ttl; + val.feat = hb_pub->feat; + val.net_idx = hb_pub->net_idx; + + bt_mesh_save_core_settings("mesh/hb_pub", (const u8_t *)&val, sizeof(val)); +} + +static void store_pending_cfg(void) +{ + struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get(); + struct cfg_val val = {0}; + + if (!cfg) { + BT_WARN("%s, NULL cfg", __func__); + return; + } + + val.net_transmit = cfg->net_transmit; + val.relay = cfg->relay; + val.relay_retransmit = cfg->relay_retransmit; + val.beacon = cfg->beacon; + val.gatt_proxy = cfg->gatt_proxy; + val.frnd = cfg->frnd; + val.default_ttl = cfg->default_ttl; + + bt_mesh_save_core_settings("mesh/cfg", (const u8_t *)&val, sizeof(val)); +} + +static void clear_cfg(void) +{ + BT_DBG("Clearing configuration"); + bt_mesh_save_core_settings("mesh/cfg", NULL, 0); +} + +static void clear_app_key(u16_t app_idx) +{ + char name[16] = {'\0'}; + int err; + + BT_DBG("AppKeyIndex 0x%03x", app_idx); + + sprintf(name, "mesh/ak/%04x", app_idx); + bt_mesh_save_core_settings(name, NULL, 0); + + err = bt_mesh_remove_core_settings_item("mesh/appkey", app_idx); + if (err) { + BT_ERR("%s, Failed to remove 0x%04x from mesh/appkey", __func__, app_idx); + } + + return; +} + +static void clear_net_key(u16_t net_idx) +{ + char name[16] = {'\0'}; + int err; + + BT_DBG("NetKeyIndex 0x%03x", net_idx); + + sprintf(name, "mesh/nk/%04x", net_idx); + bt_mesh_save_core_settings(name, NULL, 0); + + err = bt_mesh_remove_core_settings_item("mesh/netkey", net_idx); + if (err) { + BT_ERR("%s, Failed to remove 0x%04x from mesh/netkey", __func__, net_idx); + } + + return; +} + +static void store_net_key(struct bt_mesh_subnet *sub) +{ + struct net_key_val key = {0}; + char name[16] = {'\0'}; + int err; + + BT_DBG("NetKeyIndex 0x%03x NetKey %s", sub->net_idx, + bt_hex(sub->keys[0].net, 16)); + + memcpy(&key.val[0], sub->keys[0].net, 16); + memcpy(&key.val[1], sub->keys[1].net, 16); + key.kr_flag = sub->kr_flag; + key.kr_phase = sub->kr_phase; + + sprintf(name, "mesh/nk/%04x", sub->net_idx); + err = bt_mesh_save_core_settings(name, (const u8_t *)&key, sizeof(key)); + if (err) { + BT_ERR("%s, Failed to save NetKey %s", __func__, name); + return; + } + + err = bt_mesh_add_core_settings_item("mesh/netkey", sub->net_idx); + if (err) { + BT_ERR("%s, Failed to add 0x%04x to mesh/netkey", __func__, sub->net_idx); + } + + return; +} + +static void store_app_key(struct bt_mesh_app_key *app) +{ + struct app_key_val key = {0}; + char name[16] = {'\0'}; + int err; + + key.net_idx = app->net_idx; + key.updated = app->updated; + memcpy(key.val[0], app->keys[0].val, 16); + memcpy(key.val[1], app->keys[1].val, 16); + + sprintf(name, "mesh/ak/%04x", app->app_idx); + err = bt_mesh_save_core_settings(name, (const u8_t *)&key, sizeof(key)); + if (err) { + BT_ERR("%s, Failed to save AppKey %s", __func__, name); + return; + } + + err = bt_mesh_add_core_settings_item("mesh/appkey", app->app_idx); + if (err) { + BT_ERR("%s, Failed to add 0x%04x to mesh/appkey", __func__, app->app_idx); + } + + return; +} + +static void store_pending_keys(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(key_updates); i++) { + struct key_update *update = &key_updates[i]; + + if (!update->valid) { + continue; + } + + if (update->clear) { + if (update->app_key) { + clear_app_key(update->key_idx); + } else { + clear_net_key(update->key_idx); + } + } else { + if (update->app_key) { + struct bt_mesh_app_key *key = NULL; + key = bt_mesh_app_key_find(update->key_idx); + if (key) { + store_app_key(key); + } else { + BT_WARN("AppKeyIndex 0x%03x not found", update->key_idx); + } + } else { + struct bt_mesh_subnet *sub = NULL; + sub = bt_mesh_subnet_get(update->key_idx); + if (sub) { + store_net_key(sub); + } else { + BT_WARN("NetKeyIndex 0x%03x not found", update->key_idx); + } + } + } + + update->valid = 0U; + } +} + +static void store_pending_mod_bind(struct bt_mesh_model *model, bool vnd) +{ + char name[16] = {'\0'}; + u16_t model_key; + int err; + + model_key = GET_MODEL_KEY(model->elem_idx, model->model_idx); + + sprintf(name, "mesh/%s/%04x/b", vnd ? "v" : "s", model_key); + + if (!bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID)) { + bt_mesh_save_core_settings(name, NULL, 0); + return; + } + + err = bt_mesh_save_core_settings(name, (const u8_t *)model->keys, sizeof(model->keys)); + if (err) { + BT_ERR("%s, Failed to save %s", __func__, name); + return; + } + + err = bt_mesh_add_core_settings_item(vnd ? "mesh/vnd" : "mesh/sig", model_key); + if (err) { + BT_ERR("%s, Failed to add 0x%04x to %s", __func__, model_key, + vnd ? "mesh/vnd" : "mesh/sig"); + } + + return; +} + +static void store_pending_mod_sub(struct bt_mesh_model *model, bool vnd) +{ + char name[16] = {'\0'}; + u16_t model_key; + int err; + + model_key = GET_MODEL_KEY(model->elem_idx, model->model_idx); + + sprintf(name, "mesh/%s/%04x/s", vnd ? "v" : "s", model_key); + + if (!bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID)) { + bt_mesh_save_core_settings(name, NULL, 0); + return; + } + + err = bt_mesh_save_core_settings(name, (const u8_t *)model->groups, sizeof(model->groups)); + if (err) { + BT_ERR("%s, Failed to save %s", __func__, name); + return; + } + + err = bt_mesh_add_core_settings_item(vnd ? "mesh/vnd" : "mesh/sig", model_key); + if (err) { + BT_ERR("%s, Failed to add 0x%04x to %s", __func__, model_key, + vnd ? "mesh/vnd" : "mesh/sig"); + } + + return; +} + +static void store_pending_mod_pub(struct bt_mesh_model *model, bool vnd) +{ + struct mod_pub_val pub = {0}; + char name[16] = {'\0'}; + u16_t model_key; + int err; + + if (!model->pub) { + BT_WARN("%s, No model publication to store", __func__); + return; + } + + pub.addr = model->pub->addr; + pub.key = model->pub->key; + pub.ttl = model->pub->ttl; + pub.retransmit = model->pub->retransmit; + pub.period = model->pub->period; + pub.period_div = model->pub->period_div; + pub.cred = model->pub->cred; + + model_key = GET_MODEL_KEY(model->elem_idx, model->model_idx); + + sprintf(name, "mesh/%s/%04x/p", vnd ? "v" : "s", model_key); + + if (!bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID)) { + bt_mesh_save_core_settings(name, NULL, 0); + return; + } + + err = bt_mesh_save_core_settings(name, (const u8_t *)&pub, sizeof(pub)); + if (err) { + BT_ERR("%s, Failed to save %s", __func__, name); + return; + } + + err = bt_mesh_add_core_settings_item(vnd ? "mesh/vnd" : "mesh/sig", model_key); + if (err) { + BT_ERR("%s, Failed to add 0x%04x to %s", __func__, model_key, + vnd ? "mesh/vnd" : "mesh/sig"); + } + + return; +} + +static void store_pending_mod(struct bt_mesh_model *model, + struct bt_mesh_elem *elem, bool vnd, + bool primary, void *user_data) +{ + if (!model->flags) { + return; + } + + if (model->flags & BLE_MESH_MOD_BIND_PENDING) { + model->flags &= ~BLE_MESH_MOD_BIND_PENDING; + store_pending_mod_bind(model, vnd); + } + + if (model->flags & BLE_MESH_MOD_SUB_PENDING) { + model->flags &= ~BLE_MESH_MOD_SUB_PENDING; + store_pending_mod_sub(model, vnd); + } + + if (model->flags & BLE_MESH_MOD_PUB_PENDING) { + model->flags &= ~BLE_MESH_MOD_PUB_PENDING; + store_pending_mod_pub(model, vnd); + } +} + +static void store_pending(struct k_work *work) +{ + BT_DBG("%s", __func__); + + if (bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_RPL_PENDING)) { + if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID)) { + store_pending_rpl(); + } else { + clear_rpl(); + } + } + + if (bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_KEYS_PENDING)) { + store_pending_keys(); + } + + if (bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_NET_PENDING)) { + if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID)) { + store_pending_net(); + } else { + clear_net(); + } + } + + if (bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_IV_PENDING)) { + if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID)) { + store_pending_iv(); + } else { + clear_iv(); + } + } + + if (bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_SEQ_PENDING)) { + store_pending_seq(); + } + + if (bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_HB_PUB_PENDING)) { + store_pending_hb_pub(); + } + + if (bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_CFG_PENDING)) { + if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID)) { + store_pending_cfg(); + } else { + clear_cfg(); + } + } + + if (bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_MOD_PENDING)) { + bt_mesh_model_foreach(store_pending_mod, NULL); + if (!bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID)) { + bt_mesh_save_core_settings("mesh/sig", NULL, 0); + bt_mesh_save_core_settings("mesh/vnd", NULL, 0); + } + } +} + +void bt_mesh_store_rpl(struct bt_mesh_rpl *entry) +{ + entry->store = true; + schedule_store(BLE_MESH_RPL_PENDING); +} + +static struct key_update *key_update_find(bool app_key, u16_t key_idx, + struct key_update **free_slot) +{ + struct key_update *match = NULL; + int i; + + *free_slot = NULL; + + for (i = 0; i < ARRAY_SIZE(key_updates); i++) { + struct key_update *update = &key_updates[i]; + + if (!update->valid) { + *free_slot = update; + continue; + } + + if (update->app_key != app_key) { + continue; + } + + if (update->key_idx == key_idx) { + match = update; + } + } + + return match; +} + +void bt_mesh_store_subnet(struct bt_mesh_subnet *sub) +{ + struct key_update *free_slot = NULL; + struct key_update *update = NULL; + + BT_DBG("NetKeyIndex 0x%03x", sub->net_idx); + + update = key_update_find(false, sub->net_idx, &free_slot); + if (update) { + update->clear = 0U; + schedule_store(BLE_MESH_KEYS_PENDING); + return; + } + + if (!free_slot) { + store_net_key(sub); + return; + } + + free_slot->valid = 1U; + free_slot->key_idx = sub->net_idx; + free_slot->app_key = 0U; + free_slot->clear = 0U; + + schedule_store(BLE_MESH_KEYS_PENDING); +} + +void bt_mesh_store_app_key(struct bt_mesh_app_key *key) +{ + struct key_update *free_slot = NULL; + struct key_update *update = NULL; + + BT_DBG("AppKeyIndex 0x%03x", key->app_idx); + + update = key_update_find(true, key->app_idx, &free_slot); + if (update) { + update->clear = 0U; + schedule_store(BLE_MESH_KEYS_PENDING); + return; + } + + if (!free_slot) { + store_app_key(key); + return; + } + + free_slot->valid = 1U; + free_slot->key_idx = key->app_idx; + free_slot->app_key = 1U; + free_slot->clear = 0U; + + schedule_store(BLE_MESH_KEYS_PENDING); +} + +void bt_mesh_store_hb_pub(void) +{ + schedule_store(BLE_MESH_HB_PUB_PENDING); +} + +void bt_mesh_store_cfg(void) +{ + schedule_store(BLE_MESH_CFG_PENDING); +} + +void bt_mesh_clear_net(void) +{ + schedule_store(BLE_MESH_NET_PENDING); + schedule_store(BLE_MESH_IV_PENDING); + schedule_store(BLE_MESH_CFG_PENDING); +} + +void bt_mesh_clear_subnet(struct bt_mesh_subnet *sub) +{ + struct key_update *free_slot = NULL; + struct key_update *update = NULL; + + BT_DBG("NetKeyIndex 0x%03x", sub->net_idx); + + update = key_update_find(false, sub->net_idx, &free_slot); + if (update) { + update->clear = 1U; + schedule_store(BLE_MESH_KEYS_PENDING); + return; + } + + if (!free_slot) { + clear_net_key(sub->net_idx); + return; + } + + free_slot->valid = 1U; + free_slot->key_idx = sub->net_idx; + free_slot->app_key = 0U; + free_slot->clear = 1U; + + schedule_store(BLE_MESH_KEYS_PENDING); +} + +void bt_mesh_clear_app_key(struct bt_mesh_app_key *key) +{ + struct key_update *free_slot = NULL; + struct key_update *update = NULL; + + BT_DBG("AppKeyIndex 0x%03x", key->app_idx); + + update = key_update_find(true, key->app_idx, &free_slot); + if (update) { + update->clear = 1U; + schedule_store(BLE_MESH_KEYS_PENDING); + return; + } + + if (!free_slot) { + clear_app_key(key->app_idx); + return; + } + + free_slot->valid = 1U; + free_slot->key_idx = key->app_idx; + free_slot->app_key = 1U; + free_slot->clear = 1U; + + schedule_store(BLE_MESH_KEYS_PENDING); +} + +void bt_mesh_clear_rpl(void) +{ + schedule_store(BLE_MESH_RPL_PENDING); +} + +void bt_mesh_store_mod_bind(struct bt_mesh_model *model) +{ + model->flags |= BLE_MESH_MOD_BIND_PENDING; + schedule_store(BLE_MESH_MOD_PENDING); +} + +void bt_mesh_store_mod_sub(struct bt_mesh_model *model) +{ + model->flags |= BLE_MESH_MOD_SUB_PENDING; + schedule_store(BLE_MESH_MOD_PENDING); +} + +void bt_mesh_store_mod_pub(struct bt_mesh_model *model) +{ + model->flags |= BLE_MESH_MOD_PUB_PENDING; + schedule_store(BLE_MESH_MOD_PENDING); +} + +int settings_core_init(void) +{ + BT_DBG("%s", __func__); + + k_delayed_work_init(&pending_store, store_pending); + + return 0; +} + +int bt_mesh_settings_init(void) +{ + BT_DBG("%s", __func__); + + bt_mesh_settings_foreach(); + + return 0; +} + +#endif /* CONFIG_BLE_MESH_SETTINGS */ diff --git a/components/bt/ble_mesh/mesh_core/settings.h b/components/bt/ble_mesh/mesh_core/settings.h new file mode 100644 index 0000000000..84b5e182b4 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/settings.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _SETTINGS_H_ +#define _SETTINGS_H_ + +#include "sdkconfig.h" + +#include "net.h" +#include "mesh_access.h" +#include "mesh_bearer_adapt.h" + +int settings_core_init(void); +int settings_core_load(void); +int settings_core_commit(void); + +void bt_mesh_store_net(void); +void bt_mesh_store_iv(bool only_duration); +void bt_mesh_store_seq(void); +void bt_mesh_store_rpl(struct bt_mesh_rpl *rpl); +void bt_mesh_store_subnet(struct bt_mesh_subnet *sub); +void bt_mesh_store_app_key(struct bt_mesh_app_key *key); +void bt_mesh_store_hb_pub(void); +void bt_mesh_store_cfg(void); +void bt_mesh_store_mod_bind(struct bt_mesh_model *mod); +void bt_mesh_store_mod_sub(struct bt_mesh_model *mod); +void bt_mesh_store_mod_pub(struct bt_mesh_model *mod); + +void bt_mesh_clear_net(void); +void bt_mesh_clear_subnet(struct bt_mesh_subnet *sub); +void bt_mesh_clear_app_key(struct bt_mesh_app_key *key); +void bt_mesh_clear_rpl(void); + +int bt_mesh_settings_init(void); + +#endif /* _SETTINGS_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/settings/settings_nvs.c b/components/bt/ble_mesh/mesh_core/settings/settings_nvs.c new file mode 100644 index 0000000000..1a19bee297 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/settings/settings_nvs.c @@ -0,0 +1,374 @@ +// Copyright 2017-2018 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 +#include +#include +#include + +#include "nvs.h" +#include "sdkconfig.h" + +#include "mesh_util.h" +#include "mesh_types.h" +#include "mesh_common.h" + +#include "settings_nvs.h" +#include "settings.h" + +#if CONFIG_BLE_MESH_SETTINGS + +enum settings_type { + SETTINGS_CORE, + SETTINGS_SERVER, +}; + +struct settings_context { + char *nvs_name; + nvs_handle handle; + + int (*settings_init)(void); + int (*settings_load)(void); + int (*settings_commit)(void); +}; + +static struct settings_context settings_ctx[] = { + [SETTINGS_CORE] = { + .nvs_name = "mesh_core", + .settings_init = settings_core_init, + .settings_load = settings_core_load, + .settings_commit = settings_core_commit, + }, + [SETTINGS_SERVER] = { + .nvs_name = "mesh_server", + .settings_init = NULL, + .settings_load = NULL, + .settings_commit = NULL, + }, +}; + +/* API used to initialize, load and commit BLE Mesh related settings */ + +void bt_mesh_settings_foreach(void) +{ + int i, err; + + for (i = 0; i < ARRAY_SIZE(settings_ctx); i++) { + struct settings_context *ctx = &settings_ctx[i]; + + err = nvs_open(ctx->nvs_name, NVS_READWRITE, &ctx->handle); + if (err != ESP_OK) { + BT_ERR("%s, Open nvs failed, name %s, err %d", __func__, ctx->nvs_name, err); + continue; + } + + if (ctx->settings_init && ctx->settings_init()) { + BT_ERR("%s, Init settings failed, name %s", __func__, ctx->nvs_name); + continue; + } + + if (ctx->settings_load && ctx->settings_load()) { + BT_ERR("%s, Load settings failed, name %s", __func__, ctx->nvs_name); + continue; + } + + if (ctx->settings_commit && ctx->settings_commit()) { + BT_ERR("%s, Commit settings failed, name %s", __func__, ctx->nvs_name); + continue; + } + } +} + +/* API used to get BLE Mesh related nvs handle */ + +static inline nvs_handle settings_get_nvs_handle(enum settings_type type) +{ + return settings_ctx[type].handle; +} + +/* API used to store/erase BLE Mesh related settings */ + +static int settings_save(nvs_handle handle, const char *key, const u8_t *val, size_t len) +{ + int err; + + if (key == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + BT_DBG("%s, nvs %s, key %s", __func__, val ? "set" : "erase", key); + + if (val) { + err = nvs_set_blob(handle, key, val, len); + } else { + err = nvs_erase_key(handle, key); + if (err == ESP_ERR_NVS_NOT_FOUND) { + BT_DBG("%s, %s does not exist", __func__, key); + return 0; + } + } + if (err != ESP_OK) { + BT_ERR("%s, Failed to %s %s data (err %d)", __func__, + val ? "set" : "erase", key, err); + return -EIO; + } + + err = nvs_commit(handle); + if (err != ESP_OK) { + BT_ERR("%s, Failed to commit settings (err %d)", __func__, err); + return -EIO; + } + + return 0; +} + +int bt_mesh_save_core_settings(const char *key, const u8_t *val, size_t len) +{ + nvs_handle handle = settings_get_nvs_handle(SETTINGS_CORE); + return settings_save(handle, key, val, len); +} + +/* API used to load BLE Mesh related settings */ + +static int settings_load(nvs_handle handle, const char *key, + u8_t *buf, size_t buf_len, bool *exist) +{ + int err; + + if (key == NULL || buf == NULL || exist == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + err = nvs_get_blob(handle, key, buf, &buf_len); + if (err != ESP_OK) { + if (err == ESP_ERR_NVS_NOT_FOUND) { + BT_DBG("%s, Settings %s is not found", __func__, key); + *exist = false; + return 0; + } + + BT_ERR("%s, Failed to get %s data (err %d)", __func__, key, err); + return -EIO; + } + + *exist = true; + return 0; +} + +int bt_mesh_load_core_settings(const char *key, u8_t *buf, size_t buf_len, bool *exist) +{ + nvs_handle handle = settings_get_nvs_handle(SETTINGS_CORE); + return settings_load(handle, key, buf, buf_len, exist); +} + +/* API used to get length of BLE Mesh related settings */ + +static size_t settings_get_length(nvs_handle handle, const char *key) +{ + size_t len = 0; + int err; + + if (key == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return 0; + } + + err = nvs_get_blob(handle, key, NULL, &len); + if (err != ESP_OK) { + if (err != ESP_ERR_NVS_NOT_FOUND) { + BT_ERR("%s, Failed to get %s length (err %d)", __func__, key, err); + } + return 0; + } + + return len; +} + +/* API used to get BLE Mesh related items. Here items mean model key, NetKey/AppKey + * Index, etc. which are going to be used as the prefix of the nvs keys of the BLE + * Mesh settings. + */ + +static struct net_buf_simple *settings_get_item(nvs_handle handle, const char *key) +{ + struct net_buf_simple *buf = NULL; + size_t length; + bool exist; + int err; + + length = settings_get_length(handle, key); + if (!length) { + BT_DBG("%s, Empty %s", __func__, key); + return NULL; + } + + buf = bt_mesh_alloc_buf(length); + if (!buf) { + BT_ERR("%s, Failed to allocate memory", __func__); + /* TODO: in this case, erase all related settings? */ + return NULL; + } + + err = settings_load(handle, key, buf->data, length, &exist); + if (err) { + BT_ERR("%s, Failed to load %s", __func__, key); + /* TODO: in this case, erase all related settings? */ + bt_mesh_free_buf(buf); + return NULL; + } + + if (exist == false) { + bt_mesh_free_buf(buf); + return NULL; + } + + buf->len = length; + return buf; +} + +struct net_buf_simple *bt_mesh_get_core_settings_item(const char *key) +{ + nvs_handle handle = settings_get_nvs_handle(SETTINGS_CORE); + return settings_get_item(handle, key); +} + +/* API used to check if the settings item exists */ + +static bool is_settings_item_exist(struct net_buf_simple *buf, const u16_t val) +{ + struct net_buf_simple_state state = {0}; + size_t length; + int i; + + if (!buf) { + return false; + } + + net_buf_simple_save(buf, &state); + + length = buf->len; + for (i = 0; i < length / SETTINGS_ITEM_SIZE; i++) { + u16_t item = net_buf_simple_pull_le16(buf); + if (item == val) { + net_buf_simple_restore(buf, &state); + return true; + } + } + + net_buf_simple_restore(buf, &state); + return false; +} + +/* API used to add the settings item */ + +static int settings_add_item(nvs_handle handle, const char *key, const u16_t val) +{ + struct net_buf_simple *store = NULL; + struct net_buf_simple *buf = NULL; + size_t length = 0; + int err; + + buf = settings_get_item(handle, key); + + /* Check if val already exists */ + if (is_settings_item_exist(buf, val) == true) { + BT_DBG("%s, 0x%04x already exists", __func__, val); + bt_mesh_free_buf(buf); + return 0; + } + + length = (buf ? buf->len : 0) + sizeof(val); + + store = bt_mesh_alloc_buf(length); + if (!store) { + BT_ERR("%s, Failed to allocate memory", __func__); + bt_mesh_free_buf(buf); + return -ENOMEM; + } + + if (buf) { + net_buf_simple_add_mem(store, buf->data, buf->len); + } + net_buf_simple_add_mem(store, &val, sizeof(val)); + + err = settings_save(handle, key, store->data, store->len); + + bt_mesh_free_buf(store); + bt_mesh_free_buf(buf); + return err; +} + +int bt_mesh_add_core_settings_item(const char *key, const u16_t val) +{ + nvs_handle handle = settings_get_nvs_handle(SETTINGS_CORE); + return settings_add_item(handle, key, val); +} + +/* API used to remove the settings item */ + +static int settings_remove_item(nvs_handle handle, const char *key, const u16_t val) +{ + struct net_buf_simple *store = NULL; + struct net_buf_simple *buf = NULL; + size_t length = 0; + size_t buf_len; + int i, err; + + buf = settings_get_item(handle, key); + + /* Check if val does exist */ + if (is_settings_item_exist(buf, val) == false) { + BT_DBG("%s, 0x%04x does not exist", __func__, val); + bt_mesh_free_buf(buf); + return 0; + } + + length = buf->len - sizeof(val); + if (!length) { + settings_save(handle, key, NULL, 0); + bt_mesh_free_buf(buf); + return 0; + } + + store = bt_mesh_alloc_buf(length); + if (!store) { + BT_ERR("%s, Failed to allocate memory", __func__); + bt_mesh_free_buf(buf); + return -ENOMEM; + } + + buf_len = buf->len; + for (i = 0; i < buf_len / SETTINGS_ITEM_SIZE; i++) { + u16_t item = net_buf_simple_pull_le16(buf); + if (item != val) { + net_buf_simple_add_le16(store, item); + } + } + + err = settings_save(handle, key, store->data, store->len); + + bt_mesh_free_buf(store); + bt_mesh_free_buf(buf); + return err; +} + +int bt_mesh_remove_core_settings_item(const char *key, const u16_t val) +{ + nvs_handle handle = settings_get_nvs_handle(SETTINGS_CORE); + return settings_remove_item(handle, key, val); +} + +#endif /* CONFIG_BLE_MESH_SETTINGS */ diff --git a/components/bt/ble_mesh/mesh_core/settings/settings_nvs.h b/components/bt/ble_mesh/mesh_core/settings/settings_nvs.h new file mode 100644 index 0000000000..b1e929adf8 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/settings/settings_nvs.h @@ -0,0 +1,44 @@ +// Copyright 2017-2018 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. + +#ifndef _BLE_MESH_SETTINGS_NVS_H_ +#define _BLE_MESH_SETTINGS_NVS_H_ + +#include +#include "mesh_types.h" +#include "mesh_buf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SETTINGS_ITEM_SIZE sizeof(u16_t) + +void bt_mesh_settings_foreach(void); + +int bt_mesh_save_core_settings(const char *key, const u8_t *val, size_t len); + +int bt_mesh_load_core_settings(const char *key, u8_t *buf, size_t buf_len, bool *exist); + +struct net_buf_simple *bt_mesh_get_core_settings_item(const char *key); + +int bt_mesh_add_core_settings_item(const char *key, const u16_t val); + +int bt_mesh_remove_core_settings_item(const char *key, const u16_t val); + +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_SETTINGS_NVS_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/test.c b/components/bt/ble_mesh/mesh_core/test.c new file mode 100644 index 0000000000..f61beb8720 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/test.c @@ -0,0 +1,131 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "mesh_trace.h" +#include "mesh_main.h" +#include "mesh_access.h" + +#include "mesh.h" +#include "test.h" +#include "crypto.h" +#include "net.h" +#include "foundation.h" +#include "access.h" + +#if defined(CONFIG_BLE_MESH_SELF_TEST) + +int bt_mesh_test(void) +{ + return 0; +} +#endif /* #if defined(CONFIG_BLE_MESH_SELF_TEST) */ + +int bt_mesh_device_auto_enter_network(struct bt_mesh_device_network_info *info) +{ + const struct bt_mesh_comp *comp = NULL; + struct bt_mesh_model *model = NULL; + struct bt_mesh_elem *elem = NULL; + struct bt_mesh_app_keys *keys = NULL; + struct bt_mesh_app_key *key = NULL; + struct bt_mesh_subnet *sub = NULL; + int i, j, k; + int err; + + if (info == NULL || !BLE_MESH_ADDR_IS_UNICAST(info->unicast_addr) || + !BLE_MESH_ADDR_IS_GROUP(info->group_addr)) { + return -EINVAL; + } + + /* The device becomes a node and enters the network */ + err = bt_mesh_provision(info->net_key, info->net_idx, info->flags, info->iv_index, + info->unicast_addr, info->dev_key); + if (err) { + BT_ERR("%s, bt_mesh_provision() failed (err %d)", __func__, err); + return err; + } + + /* Adds application key to device */ + sub = bt_mesh_subnet_get(info->net_idx); + if (!sub) { + BT_ERR("%s, Failed to find subnet 0x%04x", __func__, info->net_idx); + return -ENODEV; + } + + for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { + key = &bt_mesh.app_keys[i]; + if (key->net_idx == BLE_MESH_KEY_UNUSED) { + break; + } + } + if (i == ARRAY_SIZE(bt_mesh.app_keys)) { + BT_ERR("%s, Failed to allocate memory, AppKeyIndex 0x%04x", __func__, info->app_idx); + return -ENOMEM; + } + + keys = sub->kr_flag ? &key->keys[1] : &key->keys[0]; + + if (bt_mesh_app_id(info->app_key, &keys->id)) { + BT_ERR("%s, Failed to calculate AID, AppKeyIndex 0x%04x", __func__, info->app_idx); + return -EIO; + } + + key->net_idx = info->net_idx; + key->app_idx = info->app_idx; + memcpy(keys->val, info->app_key, 16); + + /* Binds AppKey with all non-config models, adds group address to all these models */ + comp = bt_mesh_comp_get(); + if (!comp) { + BT_ERR("%s, Composition data is NULL", __func__); + return -ENODEV; + } + + for (i = 0; i < comp->elem_count; i++) { + elem = &comp->elem[i]; + for (j = 0; j < elem->model_count; j++) { + model = &elem->models[j]; + if (model->id == BLE_MESH_MODEL_ID_CFG_SRV || + model->id == BLE_MESH_MODEL_ID_CFG_CLI) { + continue; + } + for (k = 0; k < ARRAY_SIZE(model->keys); k++) { + if (model->keys[k] == BLE_MESH_KEY_UNUSED) { + model->keys[k] = info->app_idx; + break; + } + } + for (k = 0; k < ARRAY_SIZE(model->groups); k++) { + if (model->groups[k] == BLE_MESH_ADDR_UNASSIGNED) { + model->groups[k] = info->group_addr; + break; + } + } + } + for (j = 0; j < elem->vnd_model_count; j++) { + model = &elem->vnd_models[j]; + for (k = 0; k < ARRAY_SIZE(model->keys); k++) { + if (model->keys[k] == BLE_MESH_KEY_UNUSED) { + model->keys[k] = info->app_idx; + break; + } + } + for (k = 0; k < ARRAY_SIZE(model->groups); k++) { + if (model->groups[k] == BLE_MESH_ADDR_UNASSIGNED) { + model->groups[k] = info->group_addr; + break; + } + } + } + } + + return 0; +} diff --git a/components/bt/ble_mesh/mesh_core/test.h b/components/bt/ble_mesh/mesh_core/test.h new file mode 100644 index 0000000000..60e3d0d8f1 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/test.h @@ -0,0 +1,43 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BLE_MESH_TEST_H_ +#define _BLE_MESH_TEST_H_ + +#include +#include +#include + +#include "mesh_buf.h" +#include "sdkconfig.h" + +#if defined(CONFIG_BLE_MESH_SELF_TEST) +int bt_mesh_test(void); +#else +static inline int bt_mesh_test(void) +{ + return 0; +} +#endif + +struct bt_mesh_device_network_info { + u8_t net_key[16]; + u16_t net_idx; + u8_t flags; + u32_t iv_index; + u16_t unicast_addr; + u8_t dev_key[16]; + u8_t app_key[16]; + u16_t app_idx; + u16_t group_addr; +}; + +int bt_mesh_device_auto_enter_network(struct bt_mesh_device_network_info *info); + +#endif /* _BLE_MESH_TEST_H_ */ diff --git a/components/bt/ble_mesh/mesh_core/transport.c b/components/bt/ble_mesh/mesh_core/transport.c new file mode 100644 index 0000000000..a456ebbfc8 --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/transport.c @@ -0,0 +1,1681 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "sdkconfig.h" +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BLE_MESH_DEBUG_TRANS) + +#include "mesh_types.h" +#include "mesh_util.h" +#include "mesh_buf.h" +#include "mesh_trace.h" +#include "mesh_main.h" +#include "settings.h" + +#include "crypto.h" +#include "adv.h" +#include "mesh.h" +#include "net.h" +#include "lpn.h" +#include "friend.h" +#include "access.h" +#include "foundation.h" +#include "settings.h" +#include "transport.h" +#include "mesh_common.h" +#include "model_common.h" +#include "provisioner_main.h" + +/* The transport layer needs at least three buffers for itself to avoid + * deadlocks. Ensure that there are a sufficient number of advertising + * buffers available compared to the maximum supported outgoing segment + * count. + */ +_Static_assert(CONFIG_BLE_MESH_ADV_BUF_COUNT >= (CONFIG_BLE_MESH_TX_SEG_MAX + 3), + "Too small BLE Mesh adv buffer count"); + +#define AID_MASK ((u8_t)(BIT_MASK(6))) + +#define SEG(data) ((data)[0] >> 7) +#define AKF(data) (((data)[0] >> 6) & 0x01) +#define AID(data) ((data)[0] & AID_MASK) +#define ASZMIC(data) (((data)[1] >> 7) & 1) + +#define APP_MIC_LEN(aszmic) ((aszmic) ? 8 : 4) + +#define UNSEG_HDR(akf, aid) ((akf << 6) | (aid & AID_MASK)) +#define SEG_HDR(akf, aid) (UNSEG_HDR(akf, aid) | 0x80) + +#define BLOCK_COMPLETE(seg_n) (u32_t)(((u64_t)1 << (seg_n + 1)) - 1) + +#define SEQ_AUTH(iv_index, seq) (((u64_t)iv_index) << 24 | (u64_t)seq) + +/* Number of retransmit attempts (after the initial transmit) per segment */ +#define SEG_RETRANSMIT_ATTEMPTS 4 + +/* "This timer shall be set to a minimum of 200 + 50 * TTL milliseconds.". + * We use 400 since 300 is a common send duration for standard HCI, and we + * need to have a timeout that's bigger than that. + */ +#define SEG_RETRANSMIT_TIMEOUT(tx) (K_MSEC(400) + 50 * (tx)->ttl) + +/* How long to wait for available buffers before giving up */ +#define BUF_TIMEOUT K_NO_WAIT + +static struct seg_tx { + struct bt_mesh_subnet *sub; + struct net_buf *seg[CONFIG_BLE_MESH_TX_SEG_MAX]; + u64_t seq_auth; + u16_t dst; + u8_t seg_n: 5, /* Last segment index */ + new_key: 1; /* New/old key */ + u8_t nack_count; /* Number of unacked segs */ + u8_t ttl; + const struct bt_mesh_send_cb *cb; + void *cb_data; + struct k_delayed_work retransmit; /* Retransmit timer */ +} seg_tx[CONFIG_BLE_MESH_TX_SEG_MSG_COUNT]; + +static struct seg_rx { + struct bt_mesh_subnet *sub; + u64_t seq_auth; + u8_t seg_n: 5, + ctl: 1, + in_use: 1, + obo: 1; + u8_t hdr; + u8_t ttl; + u16_t src; + u16_t dst; + u32_t block; + u32_t last; + struct k_delayed_work ack; + struct net_buf_simple buf; +} seg_rx[CONFIG_BLE_MESH_RX_SEG_MSG_COUNT] = { + [0 ... (CONFIG_BLE_MESH_RX_SEG_MSG_COUNT - 1)] = { + .buf.size = CONFIG_BLE_MESH_RX_SDU_MAX, + }, +}; + +static u8_t seg_rx_buf_data[(CONFIG_BLE_MESH_RX_SEG_MSG_COUNT * + CONFIG_BLE_MESH_RX_SDU_MAX)]; + +static u16_t hb_sub_dst = BLE_MESH_ADDR_UNASSIGNED; + +void bt_mesh_set_hb_sub_dst(u16_t addr) +{ + hb_sub_dst = addr; +} + +static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, + const struct bt_mesh_send_cb *cb, void *cb_data) +{ + struct net_buf *buf; + + BT_DBG("src 0x%04x dst 0x%04x app_idx 0x%04x sdu_len %u", + tx->src, tx->ctx->addr, tx->ctx->app_idx, sdu->len); + + buf = bt_mesh_adv_create(BLE_MESH_ADV_DATA, tx->xmit, BUF_TIMEOUT); + if (!buf) { + BT_ERR("%s, Out of network buffers", __func__); + return -ENOBUFS; + } + + net_buf_reserve(buf, BLE_MESH_NET_HDR_LEN); + + if (tx->ctx->app_idx == BLE_MESH_KEY_DEV) { + net_buf_add_u8(buf, UNSEG_HDR(0, 0)); + } else { + net_buf_add_u8(buf, UNSEG_HDR(1, tx->aid)); + } + + net_buf_add_mem(buf, sdu->data, sdu->len); + + if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { + if (bt_mesh_friend_enqueue_tx(tx, BLE_MESH_FRIEND_PDU_SINGLE, + NULL, &buf->b) && + BLE_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { + /* PDUs for a specific Friend should only go + * out through the Friend Queue. + */ + net_buf_unref(buf); + return 0; + } + } + } + + return bt_mesh_net_send(tx, buf, cb, cb_data); +} + +bool bt_mesh_tx_in_progress(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { + if (seg_tx[i].nack_count) { + return true; + } + } + + return false; +} + +static void seg_tx_reset(struct seg_tx *tx) +{ + int i; + + k_delayed_work_cancel(&tx->retransmit); + + tx->cb = NULL; + tx->cb_data = NULL; + tx->seq_auth = 0U; + tx->sub = NULL; + tx->dst = BLE_MESH_ADDR_UNASSIGNED; + + if (!tx->nack_count) { + return; + } + + for (i = 0; i <= tx->seg_n; i++) { + if (!tx->seg[i]) { + continue; + } + + /** Change by Espressif. Add this to avoid buf->ref is 2 which will + * cause lack of buf. + */ + if (tx->seg[i]->ref > 1) { + tx->seg[i]->ref = 1; + } + net_buf_unref(tx->seg[i]); + tx->seg[i] = NULL; + } + + tx->nack_count = 0U; + + if (bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_IVU_PENDING)) { + BT_DBG("Proceding with pending IV Update"); + /* bt_mesh_net_iv_update() will re-enable the flag if this + * wasn't the only transfer. + */ + if (bt_mesh_net_iv_update(bt_mesh.iv_index, false)) { + bt_mesh_net_sec_update(NULL); + } + } +} + +static inline void seg_tx_complete(struct seg_tx *tx, int err) +{ + if (tx->cb && tx->cb->end) { + tx->cb->end(err, tx->cb_data); + } + + seg_tx_reset(tx); +} + +static void seg_first_send_start(u16_t duration, int err, void *user_data) +{ + struct seg_tx *tx = user_data; + + if (tx->cb && tx->cb->start) { + tx->cb->start(duration, err, tx->cb_data); + } +} + +static void seg_send_start(u16_t duration, int err, void *user_data) +{ + struct seg_tx *tx = user_data; + + /* If there's an error in transmitting the 'sent' callback will never + * be called. Make sure that we kick the retransmit timer also in this + * case since otherwise we risk the transmission of becoming stale. + */ + if (err) { + k_delayed_work_submit(&tx->retransmit, + SEG_RETRANSMIT_TIMEOUT(tx)); + } +} + +static void seg_sent(int err, void *user_data) +{ + struct seg_tx *tx = user_data; + + k_delayed_work_submit(&tx->retransmit, + SEG_RETRANSMIT_TIMEOUT(tx)); +} + +static const struct bt_mesh_send_cb first_sent_cb = { + .start = seg_first_send_start, + .end = seg_sent, +}; + +static const struct bt_mesh_send_cb seg_sent_cb = { + .start = seg_send_start, + .end = seg_sent, +}; + +static void seg_tx_send_unacked(struct seg_tx *tx) +{ + int i, err; + + for (i = 0; i <= tx->seg_n; i++) { + struct net_buf *seg = tx->seg[i]; + + if (!seg) { + continue; + } + + if (BLE_MESH_ADV(seg)->busy) { + BT_DBG("Skipping segment that's still advertising"); + continue; + } + + if (!(BLE_MESH_ADV(seg)->seg.attempts--)) { + BT_WARN("Ran out of retransmit attempts"); + seg_tx_complete(tx, -ETIMEDOUT); + return; + } + + BT_DBG("resending %u/%u", i, tx->seg_n); + + err = bt_mesh_net_resend(tx->sub, seg, tx->new_key, + &seg_sent_cb, tx); + if (err) { + BT_ERR("%s, Sending segment failed", __func__); + seg_tx_complete(tx, -EIO); + return; + } + } +} + +static void seg_retransmit(struct k_work *work) +{ + struct seg_tx *tx = CONTAINER_OF(work, struct seg_tx, retransmit); + + seg_tx_send_unacked(tx); +} + +static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, + const struct bt_mesh_send_cb *cb, void *cb_data) +{ + u8_t seg_hdr, seg_o; + u16_t seq_zero; + struct seg_tx *tx; + int i; + + BT_DBG("src 0x%04x dst 0x%04x app_idx 0x%04x aszmic %u sdu_len %u", + net_tx->src, net_tx->ctx->addr, net_tx->ctx->app_idx, + net_tx->aszmic, sdu->len); + + if (sdu->len < 1) { + BT_ERR("%s, Zero-length SDU not allowed", __func__); + return -EINVAL; + } + + if (sdu->len > BLE_MESH_TX_SDU_MAX) { + BT_ERR("%s, Not enough segment buffers for length %u", __func__, sdu->len); + return -EMSGSIZE; + } + + for (tx = NULL, i = 0; i < ARRAY_SIZE(seg_tx); i++) { + if (!seg_tx[i].nack_count) { + tx = &seg_tx[i]; + break; + } + } + + if (!tx) { + BT_ERR("%s, No multi-segment message contexts available", __func__); + return -EBUSY; + } + + if (net_tx->ctx->app_idx == BLE_MESH_KEY_DEV) { + seg_hdr = SEG_HDR(0, 0); + } else { + seg_hdr = SEG_HDR(1, net_tx->aid); + } + + seg_o = 0U; + tx->dst = net_tx->ctx->addr; + tx->seg_n = (sdu->len - 1) / 12U; + tx->nack_count = tx->seg_n + 1; + tx->seq_auth = SEQ_AUTH(BLE_MESH_NET_IVI_TX, bt_mesh.seq); + tx->sub = net_tx->sub; + tx->new_key = net_tx->sub->kr_flag; + tx->cb = cb; + tx->cb_data = cb_data; + + if (net_tx->ctx->send_ttl == BLE_MESH_TTL_DEFAULT) { + tx->ttl = bt_mesh_default_ttl_get(); + } else { + tx->ttl = net_tx->ctx->send_ttl; + } + + seq_zero = tx->seq_auth & 0x1fff; + + BT_DBG("SeqZero 0x%04x", seq_zero); + + for (seg_o = 0U; sdu->len; seg_o++) { + struct net_buf *seg; + u16_t len; + int err; + + seg = bt_mesh_adv_create(BLE_MESH_ADV_DATA, net_tx->xmit, + BUF_TIMEOUT); + if (!seg) { + BT_ERR("%s, Out of segment buffers", __func__); + seg_tx_reset(tx); + return -ENOBUFS; + } + + BLE_MESH_ADV(seg)->seg.attempts = SEG_RETRANSMIT_ATTEMPTS; + + net_buf_reserve(seg, BLE_MESH_NET_HDR_LEN); + + net_buf_add_u8(seg, seg_hdr); + net_buf_add_u8(seg, (net_tx->aszmic << 7) | seq_zero >> 6); + net_buf_add_u8(seg, (((seq_zero & 0x3f) << 2) | + (seg_o >> 3))); + net_buf_add_u8(seg, ((seg_o & 0x07) << 5) | tx->seg_n); + + len = MIN(sdu->len, 12); + net_buf_add_mem(seg, sdu->data, len); + net_buf_simple_pull(sdu, len); + + tx->seg[seg_o] = net_buf_ref(seg); + + if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { + enum bt_mesh_friend_pdu_type type; + + if (seg_o == tx->seg_n) { + type = BLE_MESH_FRIEND_PDU_COMPLETE; + } else { + type = BLE_MESH_FRIEND_PDU_PARTIAL; + } + + if (bt_mesh_friend_enqueue_tx(net_tx, type, + &tx->seq_auth, + &seg->b) && + BLE_MESH_ADDR_IS_UNICAST(net_tx->ctx->addr)) { + /* PDUs for a specific Friend should only go + * out through the Friend Queue. + */ + net_buf_unref(seg); + return 0; + } + } + } + + BT_DBG("Sending %u/%u", seg_o, tx->seg_n); + + err = bt_mesh_net_send(net_tx, seg, + seg_o ? &seg_sent_cb : &first_sent_cb, + tx); + if (err) { + BT_ERR("%s, Sending segment failed", __func__); + seg_tx_reset(tx); + return err; + } + } + + if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && + bt_mesh_lpn_established()) { + bt_mesh_lpn_poll(); + } + } + + return 0; +} + +struct bt_mesh_app_key *bt_mesh_app_key_find(u16_t app_idx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { + struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; + + if (key->net_idx != BLE_MESH_KEY_UNUSED && + key->app_idx == app_idx) { + return key; + } + } + + return NULL; +} + +int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, + const struct bt_mesh_send_cb *cb, void *cb_data) +{ + const u8_t *key = NULL; + u8_t *ad, role; + int err; + + if (net_buf_simple_tailroom(msg) < 4) { + BT_ERR("%s, Insufficient tailroom for Transport MIC", __func__); + return -EINVAL; + } + + if (msg->len > 11) { + tx->ctx->send_rel = 1U; + } + + BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx->sub->net_idx, + tx->ctx->app_idx, tx->ctx->addr); + BT_DBG("len %u: %s", msg->len, bt_hex(msg->data, msg->len)); + + role = bt_mesh_get_model_role(tx->ctx->model, tx->ctx->srv_send); + if (role == ROLE_NVAL) { + BT_ERR("%s, Failed to get model role", __func__); + return -EINVAL; + } + + if (tx->ctx->app_idx == BLE_MESH_KEY_DEV) { +#if CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER + if (role == NODE) { + if (!bt_mesh_is_provisioner_en()) { + key = bt_mesh.dev_key; + } + } +#endif + +#if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (role == PROVISIONER) { + if (bt_mesh_is_provisioner_en()) { + key = provisioner_get_device_key(tx->ctx->addr); + } + } +#endif + +#if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (role == NODE) { + key = bt_mesh.dev_key; + } else if (role == PROVISIONER) { + if (bt_mesh_is_provisioner_en()) { + key = provisioner_get_device_key(tx->ctx->addr); + } + } else if (role == FAST_PROV) { +#if CONFIG_BLE_MESH_FAST_PROV + key = get_fast_prov_device_key(tx->ctx->addr); +#endif + } +#endif + + if (!key) { + BT_ERR("%s, Failed to get Device Key", __func__); + return -EINVAL; + } + + tx->aid = 0U; + } else { + struct bt_mesh_app_key *app_key = NULL; + +#if CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER + if (role == NODE) { + if (!bt_mesh_is_provisioner_en()) { + app_key = bt_mesh_app_key_find(tx->ctx->app_idx); + } + } +#endif + +#if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (role == PROVISIONER) { + if (bt_mesh_is_provisioner_en()) { + app_key = provisioner_app_key_find(tx->ctx->app_idx); + } + } +#endif + +#if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (role == NODE) { + app_key = bt_mesh_app_key_find(tx->ctx->app_idx); + } else if (role == PROVISIONER) { + if (bt_mesh_is_provisioner_en()) { + app_key = provisioner_app_key_find(tx->ctx->app_idx); + } + } else if (role == FAST_PROV) { +#if CONFIG_BLE_MESH_FAST_PROV + app_key = get_fast_prov_app_key(tx->ctx->net_idx, tx->ctx->app_idx); +#endif + } +#endif + + if (!app_key) { + BT_ERR("%s, Failed to get AppKey", __func__); + return -EINVAL; + } + + if (tx->sub->kr_phase == BLE_MESH_KR_PHASE_2 && + app_key->updated) { + key = app_key->keys[1].val; + tx->aid = app_key->keys[1].id; + } else { + key = app_key->keys[0].val; + tx->aid = app_key->keys[0].id; + } + } + + if (!tx->ctx->send_rel || net_buf_simple_tailroom(msg) < 8) { + tx->aszmic = 0U; + } else { + tx->aszmic = 1U; + } + + if (BLE_MESH_ADDR_IS_VIRTUAL(tx->ctx->addr)) { + ad = bt_mesh_label_uuid_get(tx->ctx->addr); + } else { + ad = NULL; + } + + err = bt_mesh_app_encrypt(key, tx->ctx->app_idx == BLE_MESH_KEY_DEV, + tx->aszmic, msg, ad, tx->src, + tx->ctx->addr, bt_mesh.seq, + BLE_MESH_NET_IVI_TX); + if (err) { + return err; + } + + if (tx->ctx->send_rel) { + err = send_seg(tx, msg, cb, cb_data); + } else { + err = send_unseg(tx, msg, cb, cb_data); + } + + return err; +} + +int bt_mesh_trans_resend(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, + const struct bt_mesh_send_cb *cb, void *cb_data) +{ + struct net_buf_simple_state state; + int err; + + net_buf_simple_save(msg, &state); + + if (tx->ctx->send_rel || msg->len > 15) { + err = send_seg(tx, msg, cb, cb_data); + } else { + err = send_unseg(tx, msg, cb, cb_data); + } + + net_buf_simple_restore(msg, &state); + + return err; +} + +static bool is_replay(struct bt_mesh_net_rx *rx) +{ + int i; + + /* Don't bother checking messages from ourselves */ + if (rx->net_if == BLE_MESH_NET_IF_LOCAL) { + return false; + } + + for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { + struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; + + /* Empty slot */ + if (!rpl->src) { + rpl->src = rx->ctx.addr; + rpl->seq = rx->seq; + rpl->old_iv = rx->old_iv; + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_rpl(rpl); + } + + return false; + } + + /* Existing slot for given address */ + if (rpl->src == rx->ctx.addr) { + if (rx->old_iv && !rpl->old_iv) { + return true; + } + +#if !CONFIG_BLE_MESH_PATCH_FOR_SLAB_APP_1_1_0 + if ((!rx->old_iv && rpl->old_iv) || + rpl->seq < rx->seq) { +#else /* CONFIG_BLE_MESH_PATCH_FOR_SLAB_APP_1_1_0 */ + /** + * Added 10 here to fix the bug of Silicon Lab Android App 1.1.0 when + * reconnection will cause its sequence number recounting from 0. + */ + if ((!rx->old_iv && rpl->old_iv) || + (rpl->seq < rx->seq) || (rpl->seq > rx->seq + 10)) { +#endif /* #if !CONFIG_BLE_MESH_PATCH_FOR_SLAB_APP_1_1_0 */ + rpl->seq = rx->seq; + rpl->old_iv = rx->old_iv; + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_rpl(rpl); + } + + return false; + } else { + return true; + } + } + } + + BT_ERR("%s, RPL is full!", __func__); + return true; +} + +static int sdu_recv(struct bt_mesh_net_rx *rx, u32_t seq, u8_t hdr, + u8_t aszmic, struct net_buf_simple *buf) +{ + struct net_buf_simple *sdu = NULL; + u32_t array_size = 0; + u8_t *ad; + u16_t i; + int err; + + BT_DBG("ASZMIC %u AKF %u AID 0x%02x", aszmic, AKF(&hdr), AID(&hdr)); + BT_DBG("len %u: %s", buf->len, bt_hex(buf->data, buf->len)); + + if (buf->len < 1 + APP_MIC_LEN(aszmic)) { + BT_ERR("%s, Too short SDU + MIC", __func__); + return -EINVAL; + } + + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && !rx->local_match) { + BT_DBG("Ignoring PDU for LPN 0x%04x of this Friend", + rx->ctx.recv_dst); + return 0; + } + + if (BLE_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) { + ad = bt_mesh_label_uuid_get(rx->ctx.recv_dst); + } else { + ad = NULL; + } + + /* Adjust the length to not contain the MIC at the end */ + buf->len -= APP_MIC_LEN(aszmic); + + /* Use bt_mesh_alloc_buf() instead of NET_BUF_SIMPLE_DEFINE to avoid + * causing btu task stackoverflow. + */ + sdu = bt_mesh_alloc_buf(CONFIG_BLE_MESH_RX_SDU_MAX - 4); + if (!sdu) { + BT_ERR("%s, Failed to allocate memory", __func__); + return -ENOMEM; + } + + if (!AKF(&hdr)) { +#if CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER + if (!bt_mesh_is_provisioner_en()) { + array_size = 1; + } +#endif + +#if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (bt_mesh_is_provisioner_en()) { + array_size = 1; + } +#endif + +#if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + array_size = 1; + if (bt_mesh_is_provisioner_en()) { + array_size += 1; + } +#endif + + for (i = 0; i < array_size; i++) { + const u8_t *dev_key = NULL; + +#if CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER + if (!bt_mesh_is_provisioner_en()) { + dev_key = bt_mesh.dev_key; + } +#endif + +#if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (bt_mesh_is_provisioner_en()) { + dev_key = provisioner_get_device_key(rx->ctx.addr); + } +#endif + +#if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (i < 1) { + dev_key = bt_mesh.dev_key; + } else { + dev_key = provisioner_get_device_key(rx->ctx.addr); + } +#endif + + if (!dev_key) { + BT_DBG("%s, NULL Device Key", __func__); + continue; + } + + net_buf_simple_reset(sdu); + err = bt_mesh_app_decrypt(dev_key, true, aszmic, buf, + sdu, ad, rx->ctx.addr, + rx->ctx.recv_dst, seq, + BLE_MESH_NET_IVI_RX(rx)); + if (err) { + continue; + } + + rx->ctx.app_idx = BLE_MESH_KEY_DEV; + bt_mesh_model_recv(rx, sdu); + + bt_mesh_free_buf(sdu); + return 0; + } + + BT_WARN("%s, Unable to decrypt with DevKey", __func__); + bt_mesh_free_buf(sdu); + return -ENODEV; + } + +#if CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER + if (!bt_mesh_is_provisioner_en()) { + array_size = ARRAY_SIZE(bt_mesh.app_keys); + } +#endif + +#if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (bt_mesh_is_provisioner_en()) { + array_size = ARRAY_SIZE(bt_mesh.p_app_keys); + } +#endif + +#if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + array_size = ARRAY_SIZE(bt_mesh.app_keys); + if (bt_mesh_is_provisioner_en()) { + array_size += ARRAY_SIZE(bt_mesh.p_app_keys); + } +#endif + + for (i = 0; i < array_size; i++) { + struct bt_mesh_app_key *key = NULL; + struct bt_mesh_app_keys *keys = NULL; + +#if CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER + if (!bt_mesh_is_provisioner_en()) { + key = &bt_mesh.app_keys[i]; + } +#endif + +#if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (bt_mesh_is_provisioner_en()) { + key = bt_mesh.p_app_keys[i]; + } +#endif + +#if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER + if (i < ARRAY_SIZE(bt_mesh.app_keys)) { + key = &bt_mesh.app_keys[i]; + } else { + key = bt_mesh.p_app_keys[i - ARRAY_SIZE(bt_mesh.app_keys)]; + } +#endif + + if (!key) { + BT_DBG("%s, NULL AppKey", __func__); + continue; + } + + /* Make sure that this AppKey matches received net_idx */ + if (key->net_idx != rx->sub->net_idx) { + continue; + } + + if (rx->new_key && key->updated) { + keys = &key->keys[1]; + } else { + keys = &key->keys[0]; + } + + /* Check that the AppKey ID matches */ + if (AID(&hdr) != keys->id) { + continue; + } + + net_buf_simple_reset(sdu); + err = bt_mesh_app_decrypt(keys->val, false, aszmic, buf, + sdu, ad, rx->ctx.addr, + rx->ctx.recv_dst, seq, + BLE_MESH_NET_IVI_RX(rx)); + if (err) { + BT_DBG("Unable to decrypt with AppKey 0x%03x", + key->app_idx); + continue; + } + + rx->ctx.app_idx = key->app_idx; + bt_mesh_model_recv(rx, sdu); + + bt_mesh_free_buf(sdu); + return 0; + } + + BT_WARN("%s, No matching AppKey", __func__); + bt_mesh_free_buf(sdu); + return -EINVAL; +} + +static struct seg_tx *seg_tx_lookup(u16_t seq_zero, u8_t obo, u16_t addr) +{ + struct seg_tx *tx; + int i; + + for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { + tx = &seg_tx[i]; + + if ((tx->seq_auth & 0x1fff) != seq_zero) { + continue; + } + + if (tx->dst == addr) { + return tx; + } + + /* If the expected remote address doesn't match, + * but the OBO flag is set and this is the first + * acknowledgement, assume it's a Friend that's + * responding and therefore accept the message. + */ + if (obo && tx->nack_count == tx->seg_n + 1) { + tx->dst = addr; + return tx; + } + } + + return NULL; +} + +static int trans_ack(struct bt_mesh_net_rx *rx, u8_t hdr, + struct net_buf_simple *buf, u64_t *seq_auth) +{ + struct seg_tx *tx; + unsigned int bit; + u32_t ack; + u16_t seq_zero; + u8_t obo; + + if (buf->len < 6) { + BT_ERR("%s, Too short ack message", __func__); + return -EINVAL; + } + + seq_zero = net_buf_simple_pull_be16(buf); + obo = seq_zero >> 15; + seq_zero = (seq_zero >> 2) & 0x1fff; + + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && rx->friend_match) { + BT_DBG("Ack for LPN 0x%04x of this Friend", rx->ctx.recv_dst); + /* Best effort - we don't have enough info for true SeqAuth */ + *seq_auth = SEQ_AUTH(BLE_MESH_NET_IVI_RX(rx), seq_zero); + return 0; + } + + ack = net_buf_simple_pull_be32(buf); + + BT_DBG("OBO %u seq_zero 0x%04x ack 0x%08x", obo, seq_zero, ack); + + tx = seg_tx_lookup(seq_zero, obo, rx->ctx.addr); + if (!tx) { + BT_WARN("No matching TX context for ack"); + return -EINVAL; + } + + *seq_auth = tx->seq_auth; + + if (!ack) { + BT_WARN("SDU canceled"); + seg_tx_complete(tx, -ECANCELED); + return 0; + } + + if (find_msb_set(ack) - 1 > tx->seg_n) { + BT_ERR("%s, Too large segment number in ack", __func__); + return -EINVAL; + } + + k_delayed_work_cancel(&tx->retransmit); + + while ((bit = find_lsb_set(ack))) { + if (tx->seg[bit - 1]) { + BT_DBG("seg %u/%u acked", bit - 1, tx->seg_n); + net_buf_unref(tx->seg[bit - 1]); + tx->seg[bit - 1] = NULL; + tx->nack_count--; + } + + ack &= ~BIT(bit - 1); + } + + if (tx->nack_count) { + seg_tx_send_unacked(tx); + } else { + BT_DBG("SDU TX complete"); + seg_tx_complete(tx, 0); + } + + return 0; +} + +static int trans_heartbeat(struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf) +{ + u8_t init_ttl, hops; + u16_t feat; + + if (buf->len < 3) { + BT_ERR("%s, Too short heartbeat message", __func__); + return -EINVAL; + } + + if (rx->ctx.recv_dst != hb_sub_dst) { + BT_WARN("Ignoring heartbeat to non-subscribed destination"); + return 0; + } + + init_ttl = (net_buf_simple_pull_u8(buf) & 0x7f); + feat = net_buf_simple_pull_be16(buf); + + hops = (init_ttl - rx->ctx.recv_ttl + 1); + + BT_DBG("src 0x%04x TTL %u InitTTL %u (%u hop%s) feat 0x%04x", + rx->ctx.addr, rx->ctx.recv_ttl, init_ttl, hops, + (hops == 1U) ? "" : "s", feat); + + bt_mesh_heartbeat(rx->ctx.addr, rx->ctx.recv_dst, hops, feat); + + return 0; +} + +static int ctl_recv(struct bt_mesh_net_rx *rx, u8_t hdr, + struct net_buf_simple *buf, u64_t *seq_auth) +{ + u8_t ctl_op = TRANS_CTL_OP(&hdr); + + BT_DBG("OpCode 0x%02x len %u", ctl_op, buf->len); + + switch (ctl_op) { + case TRANS_CTL_OP_ACK: + return trans_ack(rx, hdr, buf, seq_auth); + case TRANS_CTL_OP_HEARTBEAT: + return trans_heartbeat(rx, buf); + } + + /* Only acks and heartbeats may need processing without local_match */ + if (!rx->local_match) { + return 0; + } + + if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && !bt_mesh_lpn_established()) { + switch (ctl_op) { + case TRANS_CTL_OP_FRIEND_POLL: + return bt_mesh_friend_poll(rx, buf); + case TRANS_CTL_OP_FRIEND_REQ: + return bt_mesh_friend_req(rx, buf); + case TRANS_CTL_OP_FRIEND_CLEAR: + return bt_mesh_friend_clear(rx, buf); + case TRANS_CTL_OP_FRIEND_CLEAR_CFM: + return bt_mesh_friend_clear_cfm(rx, buf); + case TRANS_CTL_OP_FRIEND_SUB_ADD: + return bt_mesh_friend_sub_add(rx, buf); + case TRANS_CTL_OP_FRIEND_SUB_REM: + return bt_mesh_friend_sub_rem(rx, buf); + } + } + +#if defined(CONFIG_BLE_MESH_LOW_POWER) + if (ctl_op == TRANS_CTL_OP_FRIEND_OFFER) { + return bt_mesh_lpn_friend_offer(rx, buf); + } + + if (rx->ctx.addr == bt_mesh.lpn.frnd) { + if (ctl_op == TRANS_CTL_OP_FRIEND_CLEAR_CFM) { + return bt_mesh_lpn_friend_clear_cfm(rx, buf); + } + + if (!rx->friend_cred) { + BT_WARN("Message from friend with wrong credentials"); + return -EINVAL; + } + + switch (ctl_op) { + case TRANS_CTL_OP_FRIEND_UPDATE: + return bt_mesh_lpn_friend_update(rx, buf); + case TRANS_CTL_OP_FRIEND_SUB_CFM: + return bt_mesh_lpn_friend_sub_cfm(rx, buf); + } + } +#endif /* CONFIG_BLE_MESH_LOW_POWER */ + } + + BT_WARN("Unhandled TransOpCode 0x%02x", ctl_op); + + return -ENOENT; +} + +static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx, + u64_t *seq_auth) +{ + u8_t hdr; + + BT_DBG("AFK %u AID 0x%02x", AKF(buf->data), AID(buf->data)); + + if (buf->len < 1) { + BT_ERR("%s, Too small unsegmented PDU", __func__); + return -EINVAL; + } + + if (rx->local_match && is_replay(rx)) { + BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", + rx->ctx.addr, rx->ctx.recv_dst, rx->seq); + return -EINVAL; + } + + hdr = net_buf_simple_pull_u8(buf); + + if (rx->ctl) { + return ctl_recv(rx, hdr, buf, seq_auth); + } else { + /* SDUs must match a local element or an LPN of this Friend. */ + if (!rx->local_match && !rx->friend_match) { + return 0; + } + + return sdu_recv(rx, rx->seq, hdr, 0, buf); + } +} + +static inline s32_t ack_timeout(struct seg_rx *rx) +{ + s32_t to; + u8_t ttl; + + if (rx->ttl == BLE_MESH_TTL_DEFAULT) { + ttl = bt_mesh_default_ttl_get(); + } else { + ttl = rx->ttl; + } + + /* The acknowledgment timer shall be set to a minimum of + * 150 + 50 * TTL milliseconds. + */ + to = K_MSEC(150 + (ttl * 50U)); + + /* 100 ms for every not yet received segment */ + to += K_MSEC(((rx->seg_n + 1) - popcount(rx->block)) * 100U); + + /* Make sure we don't send more frequently than the duration for + * each packet (default is 300ms). + */ + return MAX(to, K_MSEC(400)); +} + +int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, u8_t ctl_op, void *data, + size_t data_len, u64_t *seq_auth, + const struct bt_mesh_send_cb *cb, void *cb_data) +{ + struct net_buf *buf; + + BT_DBG("src 0x%04x dst 0x%04x ttl 0x%02x ctl 0x%02x", tx->src, + tx->ctx->addr, tx->ctx->send_ttl, ctl_op); + BT_DBG("len %u: %s", data_len, bt_hex(data, data_len)); + + buf = bt_mesh_adv_create(BLE_MESH_ADV_DATA, tx->xmit, BUF_TIMEOUT); + if (!buf) { + BT_ERR("%s, Out of transport buffers", __func__); + return -ENOBUFS; + } + + net_buf_reserve(buf, BLE_MESH_NET_HDR_LEN); + + net_buf_add_u8(buf, TRANS_CTL_HDR(ctl_op, 0)); + + net_buf_add_mem(buf, data, data_len); + + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { + if (bt_mesh_friend_enqueue_tx(tx, BLE_MESH_FRIEND_PDU_SINGLE, + seq_auth, &buf->b) && + BLE_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { + /* PDUs for a specific Friend should only go + * out through the Friend Queue. + */ + net_buf_unref(buf); + return 0; + } + } + + return bt_mesh_net_send(tx, buf, cb, cb_data); +} + +static int send_ack(struct bt_mesh_subnet *sub, u16_t src, u16_t dst, + u8_t ttl, u64_t *seq_auth, u32_t block, u8_t obo) +{ + struct bt_mesh_msg_ctx ctx = { + .net_idx = sub->net_idx, + .app_idx = BLE_MESH_KEY_UNUSED, + .addr = dst, + .send_ttl = ttl, + }; + struct bt_mesh_net_tx tx = { + .sub = sub, + .ctx = &ctx, + .src = obo ? bt_mesh_primary_addr() : src, + .xmit = bt_mesh_net_transmit_get(), + }; + u16_t seq_zero = *seq_auth & 0x1fff; + u8_t buf[6]; + + BT_DBG("SeqZero 0x%04x Block 0x%08x OBO %u", seq_zero, block, obo); + + if (bt_mesh_lpn_established()) { + BT_WARN("Not sending ack when LPN is enabled"); + return 0; + } + + /* This can happen if the segmented message was destined for a group + * or virtual address. + */ + if (!BLE_MESH_ADDR_IS_UNICAST(src)) { + BT_WARN("Not sending ack for non-unicast address"); + return 0; + } + + sys_put_be16(((seq_zero << 2) & 0x7ffc) | (obo << 15), buf); + sys_put_be32(block, &buf[2]); + + return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_ACK, buf, sizeof(buf), + NULL, NULL, NULL); +} + +static void seg_rx_reset(struct seg_rx *rx, bool full_reset) +{ + BT_DBG("rx %p", rx); + + k_delayed_work_cancel(&rx->ack); + + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && rx->obo && + rx->block != BLOCK_COMPLETE(rx->seg_n)) { + BT_WARN("Clearing incomplete buffers from Friend queue"); + bt_mesh_friend_clear_incomplete(rx->sub, rx->src, rx->dst, + &rx->seq_auth); + } + + rx->in_use = 0U; + + /* We don't always reset these values since we need to be able to + * send an ack if we receive a segment after we've already received + * the full SDU. + */ + if (full_reset) { + rx->seq_auth = 0U; + rx->sub = NULL; + rx->src = BLE_MESH_ADDR_UNASSIGNED; + rx->dst = BLE_MESH_ADDR_UNASSIGNED; + } +} + +static void seg_ack(struct k_work *work) +{ + struct seg_rx *rx = CONTAINER_OF(work, struct seg_rx, ack); + + BT_DBG("rx %p", rx); + + if (k_uptime_get_32() - rx->last > K_SECONDS(60)) { + BT_WARN("Incomplete timer expired"); + seg_rx_reset(rx, false); + return; + } + + send_ack(rx->sub, rx->dst, rx->src, rx->ttl, &rx->seq_auth, + rx->block, rx->obo); + + k_delayed_work_submit(&rx->ack, ack_timeout(rx)); +} + +static inline u8_t seg_len(bool ctl) +{ + if (ctl) { + return 8; + } else { + return 12; + } +} + +static inline bool sdu_len_is_ok(bool ctl, u8_t seg_n) +{ + return ((seg_n * seg_len(ctl) + 1) <= CONFIG_BLE_MESH_RX_SDU_MAX); +} + +static struct seg_rx *seg_rx_find(struct bt_mesh_net_rx *net_rx, + const u64_t *seq_auth) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(seg_rx); i++) { + struct seg_rx *rx = &seg_rx[i]; + + if (rx->src != net_rx->ctx.addr || + rx->dst != net_rx->ctx.recv_dst) { + continue; + } + + /* Return newer RX context in addition to an exact match, so + * the calling function can properly discard an old SeqAuth. + * Note: in Zephyr v1.14.0, ">=" is used here which does not + * seem to be a right operation, hence we still use the original + * "==" here. + */ + if (rx->seq_auth == *seq_auth) { + return rx; + } + + if (rx->in_use) { + BT_WARN("Duplicate SDU from src 0x%04x", + net_rx->ctx.addr); + + /* Clear out the old context since the sender + * has apparently started sending a new SDU. + */ + seg_rx_reset(rx, true); + + /* Return non-match so caller can re-allocate */ + return NULL; + } + } + + return NULL; +} + +static bool seg_rx_is_valid(struct seg_rx *rx, struct bt_mesh_net_rx *net_rx, + const u8_t *hdr, u8_t seg_n) +{ + if (rx->hdr != *hdr || rx->seg_n != seg_n) { + BT_ERR("%s, Invalid segment for ongoing session", __func__); + return false; + } + + if (rx->src != net_rx->ctx.addr || rx->dst != net_rx->ctx.recv_dst) { + BT_ERR("%s, Invalid source or destination for segment", __func__); + return false; + } + + if (rx->ctl != net_rx->ctl) { + BT_ERR("%s, Inconsistent CTL in segment", __func__); + return false; + } + + return true; +} + +static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, + const u8_t *hdr, const u64_t *seq_auth, + u8_t seg_n) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(seg_rx); i++) { + struct seg_rx *rx = &seg_rx[i]; + + if (rx->in_use) { + continue; + } + + rx->in_use = 1U; + net_buf_simple_reset(&rx->buf); + rx->sub = net_rx->sub; + rx->ctl = net_rx->ctl; + rx->seq_auth = *seq_auth; + rx->seg_n = seg_n; + rx->hdr = *hdr; + rx->ttl = net_rx->ctx.send_ttl; + rx->src = net_rx->ctx.addr; + rx->dst = net_rx->ctx.recv_dst; + rx->block = 0U; + + BT_DBG("New RX context. Block Complete 0x%08x", + BLOCK_COMPLETE(seg_n)); + + return rx; + } + + return NULL; +} + +static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, + enum bt_mesh_friend_pdu_type *pdu_type, u64_t *seq_auth) +{ + struct seg_rx *rx; + u8_t *hdr = buf->data; + u16_t seq_zero; + u8_t seg_n; + u8_t seg_o; + int err; + + if (buf->len < 5) { + BT_ERR("%s, Too short segmented message (len %u)", __func__, buf->len); + return -EINVAL; + } + + BT_DBG("ASZMIC %u AKF %u AID 0x%02x", ASZMIC(hdr), AKF(hdr), AID(hdr)); + + net_buf_simple_pull(buf, 1); + + seq_zero = net_buf_simple_pull_be16(buf); + seg_o = (seq_zero & 0x03) << 3; + seq_zero = (seq_zero >> 2) & 0x1fff; + seg_n = net_buf_simple_pull_u8(buf); + seg_o |= seg_n >> 5; + seg_n &= 0x1f; + + BT_DBG("SeqZero 0x%04x SegO %u SegN %u", seq_zero, seg_o, seg_n); + + if (seg_o > seg_n) { + BT_ERR("%s, SegO greater than SegN (%u > %u)", __func__, seg_o, seg_n); + return -EINVAL; + } + + /* According to Mesh 1.0 specification: + * "The SeqAuth is composed of the IV Index and the sequence number + * (SEQ) of the first segment" + * + * Therefore we need to calculate very first SEQ in order to find + * seqAuth. We can calculate as below: + * + * SEQ(0) = SEQ(n) - (delta between seqZero and SEQ(n) by looking into + * 14 least significant bits of SEQ(n)) + * + * Mentioned delta shall be >= 0, if it is not then seq_auth will + * be broken and it will be verified by the code below. + */ + *seq_auth = SEQ_AUTH(BLE_MESH_NET_IVI_RX(net_rx), + (net_rx->seq - + ((((net_rx->seq & BIT_MASK(14)) - seq_zero)) & + BIT_MASK(13)))); + + /* Look for old RX sessions */ + rx = seg_rx_find(net_rx, seq_auth); + if (rx) { + /* Discard old SeqAuth packet */ + if (rx->seq_auth > *seq_auth) { + BT_WARN("Ignoring old SeqAuth"); + return -EINVAL; + } + + if (!seg_rx_is_valid(rx, net_rx, hdr, seg_n)) { + return -EINVAL; + } + + if (rx->in_use) { + BT_DBG("Existing RX context. Block 0x%08x", rx->block); + goto found_rx; + } + + if (rx->block == BLOCK_COMPLETE(rx->seg_n)) { + BT_WARN("Got segment for already complete SDU"); + send_ack(net_rx->sub, net_rx->ctx.recv_dst, + net_rx->ctx.addr, net_rx->ctx.send_ttl, + seq_auth, rx->block, rx->obo); + return -EALREADY; + } + + /* We ignore instead of sending block ack 0 since the + * ack timer is always smaller than the incomplete + * timer, i.e. the sender is misbehaving. + */ + BT_WARN("Got segment for canceled SDU"); + return -EINVAL; + } + + /* Bail out early if we're not ready to receive such a large SDU */ + if (!sdu_len_is_ok(net_rx->ctl, seg_n)) { + BT_ERR("%s, Too big incoming SDU length", __func__); + send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, + net_rx->ctx.send_ttl, seq_auth, 0, + net_rx->friend_match); + return -EMSGSIZE; + } + + /* Look for free slot for a new RX session */ + rx = seg_rx_alloc(net_rx, hdr, seq_auth, seg_n); + if (!rx) { + /* Warn but don't cancel since the existing slots willl + * eventually be freed up and we'll be able to process + * this one. + */ + BT_WARN("No free slots for new incoming segmented messages"); + return -ENOMEM; + } + + rx->obo = net_rx->friend_match; + +found_rx: + if (BIT(seg_o) & rx->block) { + BT_WARN("Received already received fragment"); + return -EALREADY; + } + + /* All segments, except the last one, must either have 8 bytes of + * payload (for 64bit Net MIC) or 12 bytes of payload (for 32bit + * Net MIC). + */ + if (seg_o == seg_n) { + /* Set the expected final buffer length */ + rx->buf.len = seg_n * seg_len(rx->ctl) + buf->len; + BT_DBG("Target len %u * %u + %u = %u", seg_n, seg_len(rx->ctl), + buf->len, rx->buf.len); + + if (rx->buf.len > CONFIG_BLE_MESH_RX_SDU_MAX) { + BT_ERR("Too large SDU len"); + send_ack(net_rx->sub, net_rx->ctx.recv_dst, + net_rx->ctx.addr, net_rx->ctx.send_ttl, + seq_auth, 0, rx->obo); + seg_rx_reset(rx, true); + return -EMSGSIZE; + } + } else { + if (buf->len != seg_len(rx->ctl)) { + BT_ERR("%s, Incorrect segment size for message type", __func__); + return -EINVAL; + } + } + + /* Reset the Incomplete Timer */ + rx->last = k_uptime_get_32(); + + if (!k_delayed_work_remaining_get(&rx->ack) && + !bt_mesh_lpn_established()) { + k_delayed_work_submit(&rx->ack, ack_timeout(rx)); + } + + /* Location in buffer can be calculated based on seg_o & rx->ctl */ + memcpy(rx->buf.data + (seg_o * seg_len(rx->ctl)), buf->data, buf->len); + + BT_DBG("Received %u/%u", seg_o, seg_n); + + /* Mark segment as received */ + rx->block |= BIT(seg_o); + + if (rx->block != BLOCK_COMPLETE(seg_n)) { + *pdu_type = BLE_MESH_FRIEND_PDU_PARTIAL; + return 0; + } + + BT_DBG("Complete SDU"); + + if (net_rx->local_match && is_replay(net_rx)) { + BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", + net_rx->ctx.addr, net_rx->ctx.recv_dst, net_rx->seq); + /* Clear the segment's bit */ + rx->block &= ~BIT(seg_o); + return -EINVAL; + } + + *pdu_type = BLE_MESH_FRIEND_PDU_COMPLETE; + + k_delayed_work_cancel(&rx->ack); + send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, + net_rx->ctx.send_ttl, seq_auth, rx->block, rx->obo); + + if (net_rx->ctl) { + err = ctl_recv(net_rx, *hdr, &rx->buf, seq_auth); + } else { + err = sdu_recv(net_rx, (rx->seq_auth & 0xffffff), *hdr, + ASZMIC(hdr), &rx->buf); + } + + seg_rx_reset(rx, false); + + return err; +} + +int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) +{ + u64_t seq_auth = TRANS_SEQ_AUTH_NVAL; + enum bt_mesh_friend_pdu_type pdu_type = BLE_MESH_FRIEND_PDU_SINGLE; + struct net_buf_simple_state state; + int err; + + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { + rx->friend_match = bt_mesh_friend_match(rx->sub->net_idx, + rx->ctx.recv_dst); + } else { + rx->friend_match = false; + } + + BT_DBG("src 0x%04x dst 0x%04x seq 0x%08x friend_match %u", + rx->ctx.addr, rx->ctx.recv_dst, rx->seq, rx->friend_match); + + /* Remove network headers */ + net_buf_simple_pull(buf, BLE_MESH_NET_HDR_LEN); + + BT_DBG("Payload %s", bt_hex(buf->data, buf->len)); + + /* If LPN mode is enabled messages are only accepted when we've + * requested the Friend to send them. The messages must also + * be encrypted using the Friend Credentials. + */ + if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && + bt_mesh_lpn_established() && rx->net_if == BLE_MESH_NET_IF_ADV && + (!bt_mesh_lpn_waiting_update() || !rx->friend_cred)) { + BT_WARN("Ignoring unexpected message in Low Power mode"); + return -EAGAIN; + } + } + + /* Save the app-level state so the buffer can later be placed in + * the Friend Queue. + */ + net_buf_simple_save(buf, &state); + + if (SEG(buf->data)) { + /* Segmented messages must match a local element or an + * LPN of this Friend. + */ + if (!rx->local_match && !rx->friend_match) { + return 0; + } + + err = trans_seg(buf, rx, &pdu_type, &seq_auth); + } else { + err = trans_unseg(buf, rx, &seq_auth); + } + + /* Notify LPN state machine so a Friend Poll will be sent. If the + * message was a Friend Update it's possible that a Poll was already + * queued for sending, however that's fine since then the + * bt_mesh_lpn_waiting_update() function will return false: + * we still need to go through the actual sending to the bearer and + * wait for ReceiveDelay before transitioning to WAIT_UPDATE state. + * Another situation where we want to notify the LPN state machine + * is if it's configured to use an automatic Friendship establishment + * timer, in which case we want to reset the timer at this point. + * + */ + if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && + (bt_mesh_lpn_timer() || + (bt_mesh_lpn_established() && bt_mesh_lpn_waiting_update()))) { + bt_mesh_lpn_msg_received(rx); + } + } + + net_buf_simple_restore(buf, &state); + + if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && rx->friend_match && !err) { + if (seq_auth == TRANS_SEQ_AUTH_NVAL) { + bt_mesh_friend_enqueue_rx(rx, pdu_type, NULL, buf); + } else { + bt_mesh_friend_enqueue_rx(rx, pdu_type, &seq_auth, buf); + } + } + } + + return err; +} + +void bt_mesh_rx_reset(void) +{ + int i; + + BT_DBG("%s", __func__); + + for (i = 0; i < ARRAY_SIZE(seg_rx); i++) { + seg_rx_reset(&seg_rx[i], true); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_clear_rpl(); + } else { + (void)memset(bt_mesh.rpl, 0, sizeof(bt_mesh.rpl)); + } +} + +void bt_mesh_tx_reset(void) +{ + int i; + + BT_DBG("%s", __func__); + + for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { + seg_tx_reset(&seg_tx[i]); + } +} + +void bt_mesh_trans_init(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { + k_delayed_work_init(&seg_tx[i].retransmit, seg_retransmit); + } + + for (i = 0; i < ARRAY_SIZE(seg_rx); i++) { + k_delayed_work_init(&seg_rx[i].ack, seg_ack); + seg_rx[i].buf.__buf = (seg_rx_buf_data + + (i * CONFIG_BLE_MESH_RX_SDU_MAX)); + seg_rx[i].buf.data = seg_rx[i].buf.__buf; + } +} + +void bt_mesh_rpl_clear(void) +{ + BT_DBG("%s", __func__); + (void)memset(bt_mesh.rpl, 0, sizeof(bt_mesh.rpl)); +} diff --git a/components/bt/ble_mesh/mesh_core/transport.h b/components/bt/ble_mesh/mesh_core/transport.h new file mode 100644 index 0000000000..13845f345c --- /dev/null +++ b/components/bt/ble_mesh/mesh_core/transport.h @@ -0,0 +1,102 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _TRANSPORT_H_ +#define _TRANSPORT_H_ + +#define TRANS_SEQ_AUTH_NVAL 0xffffffffffffffff + +#define BLE_MESH_TX_SDU_MAX (CONFIG_BLE_MESH_TX_SEG_MAX * 12) + +#define TRANS_CTL_OP_MASK ((u8_t)BIT_MASK(7)) +#define TRANS_CTL_OP(data) ((data)[0] & TRANS_CTL_OP_MASK) +#define TRANS_CTL_HDR(op, seg) ((op & TRANS_CTL_OP_MASK) | (seg << 7)) + +#define TRANS_CTL_OP_ACK 0x00 +#define TRANS_CTL_OP_FRIEND_POLL 0x01 +#define TRANS_CTL_OP_FRIEND_UPDATE 0x02 +#define TRANS_CTL_OP_FRIEND_REQ 0x03 +#define TRANS_CTL_OP_FRIEND_OFFER 0x04 +#define TRANS_CTL_OP_FRIEND_CLEAR 0x05 +#define TRANS_CTL_OP_FRIEND_CLEAR_CFM 0x06 +#define TRANS_CTL_OP_FRIEND_SUB_ADD 0x07 +#define TRANS_CTL_OP_FRIEND_SUB_REM 0x08 +#define TRANS_CTL_OP_FRIEND_SUB_CFM 0x09 +#define TRANS_CTL_OP_HEARTBEAT 0x0a + +struct bt_mesh_ctl_friend_poll { + u8_t fsn; +} __packed; + +struct bt_mesh_ctl_friend_update { + u8_t flags; + u32_t iv_index; + u8_t md; +} __packed; + +struct bt_mesh_ctl_friend_req { + u8_t criteria; + u8_t recv_delay; + u8_t poll_to[3]; + u16_t prev_addr; + u8_t num_elem; + u16_t lpn_counter; +} __packed; + +struct bt_mesh_ctl_friend_offer { + u8_t recv_win; + u8_t queue_size; + u8_t sub_list_size; + s8_t rssi; + u16_t frnd_counter; +} __packed; + +struct bt_mesh_ctl_friend_clear { + u16_t lpn_addr; + u16_t lpn_counter; +} __packed; + +struct bt_mesh_ctl_friend_clear_confirm { + u16_t lpn_addr; + u16_t lpn_counter; +} __packed; + +#define BLE_MESH_FRIEND_SUB_MIN_LEN (1 + 2) +struct bt_mesh_ctl_friend_sub { + u8_t xact; + u16_t addr_list[5]; +} __packed; + +struct bt_mesh_ctl_friend_sub_confirm { + u8_t xact; +} __packed; + +void bt_mesh_set_hb_sub_dst(u16_t addr); + +struct bt_mesh_app_key *bt_mesh_app_key_find(u16_t app_idx); + +bool bt_mesh_tx_in_progress(void); + +void bt_mesh_rx_reset(void); +void bt_mesh_tx_reset(void); + +int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, u8_t ctl_op, void *data, + size_t data_len, u64_t *seq_auth, + const struct bt_mesh_send_cb *cb, void *cb_data); + +int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, + const struct bt_mesh_send_cb *cb, void *cb_data); + +int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx); + +void bt_mesh_trans_init(void); + +void bt_mesh_rpl_clear(void); + +#endif /* _TRANSPORT_H_ */ diff --git a/components/bt/ble_mesh/mesh_docs/BLE-Mesh_FAQs_EN.md b/components/bt/ble_mesh/mesh_docs/BLE-Mesh_FAQs_EN.md new file mode 100644 index 0000000000..3e3ba69684 --- /dev/null +++ b/components/bt/ble_mesh/mesh_docs/BLE-Mesh_FAQs_EN.md @@ -0,0 +1,9 @@ +# Frequently Asked Questions + +## General Questions + +### Why I do not get a reply from the remote device when I perform get operation immediately after set operation has been performed? +* Any Client Model operation needs to wait for the completion event of an ongoing operation. Once the completion event is received the next command can be executed. If a command is executed before the completion event is received, a timeout error will occur. + +### When I use the API `esp_ble_mesh_client_model_send_msg`, why does it crash with the log messages *Invalid client value when sent client msg* or *Invalid client value when sent client msg*? +* You should initialize a structure of the type `esp_ble_mesh_client_t` and set its value as the user data of client model. diff --git a/components/bt/ble_mesh/mesh_docs/BLE-Mesh_Feature_List_EN.md b/components/bt/ble_mesh/mesh_docs/BLE-Mesh_Feature_List_EN.md new file mode 100644 index 0000000000..cf54f7985e --- /dev/null +++ b/components/bt/ble_mesh/mesh_docs/BLE-Mesh_Feature_List_EN.md @@ -0,0 +1,89 @@ +# Espressif BLE Mesh Feature List + +## Currently Supported Features + +### Mesh Core + +* Provisioning: Node Role + * Advertising and GATT bearer + * Authentication OOB + +* Provisioning: Provisioner Role + * Advertising and GATT bearer + * Authentication OOB + +* Networking + * Relay + * Segmentation and Reassembly + * Key Refresh + * IV Update + +* Proxy Support + +* Multiple Client Models Run Simultaneously + * Support multiple client models send packets to different nodes simultaneously + * No blocking between client model and server + +* NVS Storing + * Store Provisioning Data of The Node Device + +### Mesh Applications + +* Fast Provisioning + * Fast Provisioning Server Model + * Fast Provisioning Client Model + * Example & Demo Video + +* Wi-Fi & BLE Mesh Coexistence + * Example & Demo Video(coming soon) + +* Mesh Console Commands + * Example + + +### Mesh Models + +* Foundation Models + * Configuration Server Model + * Configuration Client Model + * Health Server Model + * Health Client Model + +* Generic Client Models + * Generic OnOff Client + * Generic Level Client + * Generic Location Client + * Generic Default Transition Timer Client + * Generic Power OnOff Client + * Generic Power Level Client + * Generic Battery Client + * Generic Property Client + +* Generic Server Models + * Generic OnOff Server (Simple) + +* Lighting Client Models + * Light Lightness Client + * Light CTL Client + * Light HSL Client + +* Sensor Client Models + * Sensor Client + +* Time and Scenes Client Models + * Scene Client + + +## Future Release Features + +### Mesh Core + +* BLE Mesh BQB Certification +* Friend Feature +* Low Power Node Feature + +### Mesh Applications + +* Fast OTA + +### Mesh Models diff --git a/components/bt/ble_mesh/mesh_docs/BLE-Mesh_Getting_Started_EN.md b/components/bt/ble_mesh/mesh_docs/BLE-Mesh_Getting_Started_EN.md new file mode 100644 index 0000000000..5ac15427a7 --- /dev/null +++ b/components/bt/ble_mesh/mesh_docs/BLE-Mesh_Getting_Started_EN.md @@ -0,0 +1,155 @@ +# Introduction + +Bluetooth mesh networking enables many-to-many (m:m) device communications and is optimized for creating large-scale device networks. + +Devices may relay data to other devices not in direct radio range of the originating device. In this way, mesh networks can span very large physical areas and contain large numbers of devices. It is ideally suited for building automation, sensor networks, and other IoT solutions where tens, hundreds, or thousands of devices need to reliably and securely communicate with one another. + +Bluetooth mesh is not a wireless communications technology, but a networking technology. This technology is dependent upon Bluetooth Low Energy (BLE) - a wireless communications protocol stack. + + +# Specifications + +The official specifications for Bluetooth mesh can be found [here](https://www.bluetooth.com/specifications/mesh-specifications) + + +# Getting Started with BLE Mesh on ESP32 + +If you are new to ESP32, you may first need to go through the [Getting Started guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html). + +Built on top of Zephyr BLE Mesh stack, the ESP BLE Mesh implementation supports device provisioning and node control. It also supports such node features as Proxy, Relay, Low power and Friend. + + +## Access to ESP BLE Mesh +Since you are on this page, you should already have access to Espressif BLE Mesh SDK. If you do not have access, please get in touch with your point of contact. + +## Documentation + +The ESP BLE Mesh code in the SDK is organized as below. Each folder contains source files related to it as well as a subfolder with header files for the exposed functionality. + +``` +$tree components/bt/ble_mesh/ + +├── api /* BLE Mesh functionality exposed through esp_ble_mesh_* APIs for the applications */ +│   ├── core /* BLE Mesh Core APIs */ +│   │   └── include +│   └── models /* Foundation Models and other Client Models APIs */ +│   └── include +├── btc +│   └── include +├── mesh_core /* BLE mesh core based on Zephyr BLE stack with miscellaneous modifications and +│ │ an adaptation layer to make it work with ESP32 */ +│   └── include +├── mesh_docs /* BLE Mesh docs */ +└── mesh_models /* Foundation Models and other Client Models implementations */ + └── include +``` + +To demonstrate the features supported by BLE Mesh SDK, a few sample examples have been added. Each example has a README.md file for quick start as well as a walkthrough file that explains the functionality in detail. + +Below is a snapshot of the BLE Mesh examples directory + +``` +$ tree examples/bluetooth/ble_mesh/ +├── ble_mesh_client_model +│   ├── main +│   │   ├── ble_mesh_client_model_main.c +│   │   ├── board.c +│   │   ├── board.h +│   │   ├── component.mk +│   │   └── Kconfig.projbuild +│   ├── Makefile +│   ├── README.md +│   └── sdkconfig.defaults +├── ble_mesh_node +│   ├── main +│   │   ├── ble_mesh_demo_main.c +│   │   ├── board.c +│   │   ├── board.h +│   │   ├── component.mk +│   │   └── Kconfig.projbuild +│   ├── Makefile +│   ├── README.md +│   ├── sdkconfig.defaults +│   └── tutorial +│   └── Ble_Mesh_Node_Example_Walkthrough.md +├── ble_mesh_provisioner +│ ├── main +│ │   ├── ble_mesh_demo_main.c +│ │   ├── board.c +│ │   ├── board.h +│ │   ├── component.mk +│ │   └── Kconfig.projbuild +│ ├── Makefile +│ ├── README.md +│ ├── sdkconfig.defaults +│ └── tutorial +│ └── Ble_Mesh_Provisioner_Example_Walkthrough.md +├──ble_mesh_console +│ ├── ble_mesh_node +│ └── ble_mesh_provisioner +├──ble_mesh_fast_provision +│ ├── ble_mesh_fast_prov_client +│ └── ble_mesh_fast_prov_server +├──ble_mesh_vendor_models +│ ├── fast_prov_vendor_model +└──ble_mesh_wifi_coexist + ├── main + ├── components + └── tutorial + └── ble_mesh_wifi_coexist.md +8 directories, 26 files +``` + + +## Hardware and Setup + +At present ESP32-DevKitC and ESP-WROVER-KIT are supported for BLE Mesh implementation. You can find the details about the modules [here](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/modules-and-boards.html) + +You can choose the board through menuconfig: `make menuconfig -> Example Configuration -> Board selection for BLE Mesh` + +Note that if you plan to use ESP32-DevKitC, you need to connect an RGB LED to GPIO pins 25, 26 and 27. + + +## Sample Examples + +* BLE Mesh Node + +This example shows the use of BLE Mesh as a node device having a Configuration Server model and a Generic OnOff Server model. A BLE Mesh provisioner can then provision the node and control a RGB LED representing on/off state. + +* BLE Mesh Client Model + +This example shows how a Generic OnOff Client model within a node works. The node has a Configuration Server model, a Generic OnOff Server model and a Generic OnOff Client model. + +* BLE Mesh Provisioner + +This example shows how a device can act as a BLE Mesh provisioner to provision devices. The provisioner has a Configuration Server model, a Configuration Client model and a Generic OnOff Client model. + + +## Mobile Apps + +ESP BLE Mesh implementation is compatible with a few phone apps, including Silicon Labs BLE Mesh and nRF Mesh. These apps are available on Google Play and App Store. In addition, Espressif offers its own Android app which is currently being actively developed. You can find the latest APK file [here](http://download.espressif.com/BLE_MESH/BLE_Mesh_Tools/BLE_Mesh_App/EspBleMesh-0.9.4.apk). + +Note: The most recent tested version 1.1.0 of Silicon Labs App has a bug, which has been fixed by a workaround on the SDK side. The fix is implemented through a configuration option enabled by default. For other Android/iOS apps, this option needs to be disabled from menuconfig: +`make menuconfig -> Example Configuration -> This option fixes the bug of Silicon Lab Android App 1.1.0 when reconnection will cause the sequence number to recount from 0` + +## Building and Flashing + +If you build the application for the first time, the menuconfig screen will pop up. You can choose the board from the Example Configuration option. Additionally, you can modify the serial settings in the Serial flasher config option in accordance with your port configuration. + +BLE Mesh specific configuration options can also be modified through: `make menuconfig -> Component config -> Bluetooth Mesh support` + +You can still change options at any other time using `make menuconfig`. + +``` +$ export IDF_PATH=/path/to/esp-ble-mesh-sdk-v0.x + +$ cd examples/bluetooth/ble_mesh/ + +$ make -j8 flash monitor +``` + + +# Reporting Issues + +* If you find a bug or have a feature request, go to [the Issues section on GitHub](https://github.com/espressif/esp-idf/issues). Before reporting a new issue, please check the existing issues at the provided link and the FAQs document in the `mesh_docs` folder. +* When you submit an issue or a feature request on GitHub, please add the tag "BLE Mesh" in the issue title for our faster reaction. diff --git a/components/bt/ble_mesh/mesh_docs/BLE-Mesh_Known_Issues_EN.md b/components/bt/ble_mesh/mesh_docs/BLE-Mesh_Known_Issues_EN.md new file mode 100644 index 0000000000..034d2388d3 --- /dev/null +++ b/components/bt/ble_mesh/mesh_docs/BLE-Mesh_Known_Issues_EN.md @@ -0,0 +1 @@ +To be added. diff --git a/components/bt/ble_mesh/mesh_docs/README.md b/components/bt/ble_mesh/mesh_docs/README.md new file mode 100644 index 0000000000..65775ebf98 --- /dev/null +++ b/components/bt/ble_mesh/mesh_docs/README.md @@ -0,0 +1,50 @@ +# ESP BLE Mesh Framework + +This folder contains all the documents of ESP BLE Mesh. +* Note: breaking changes might be introduced into ESP BLE Mesh on [minor IDF versions](https://docs.espressif.com/projects/esp-idf/en/latest/versions.html) + + +## Demos + +* [Provisioning of BLE Mesh nodes using Smartphone App](http://download.espressif.com/BLE_MESH/Docs4Customers/esp-ble-mesh-demo.mp4) +* [Espressif Fast Provisioning using ESP BLE Mesh App](http://download.espressif.com/BLE_MESH/BLE_Mesh_Demo/V0.4_Demo_Fast_Provision/ESP32_BLE_Mesh_Fast_Provision.mp4) +* [Espressif BLE Mesh and Wi-Fi Coexistence](http://download.espressif.com/BLE_MESH/BLE_Mesh_Demo/V0.5_Demo_Coexistence/ESP_BLE_MESH_%26_WIFI_Coexistence.mp4) + +## Examples + +* [BLE Mesh Node Example Code](../../../../examples/bluetooth/ble_mesh/ble_mesh_node) +* [BLE_Mesh_Node_Example_Walkthrough](../../../../examples/bluetooth/ble_mesh/ble_mesh_node/tutorial/Ble_Mesh_Node_Example_Walkthrough.md) +* [BLE Mesh Provisioner Example Code](../../../../examples/bluetooth/ble_mesh/ble_mesh_provisioner) +* [BLE_Mesh_Provisioner_Example_Walkthrough](../../../../examples/bluetooth/ble_mesh/ble_mesh_provisioner/tutorial/Ble_Mesh_Provisioner_Example_Walkthrough.md) +* [BLE Mesh Client Model Example Code](../../../../examples/bluetooth/ble_mesh/ble_mesh_client_model) +* [BLE_Mesh_Client_Model_Example_Walkthrough](../../../../examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/ble_mesh_client_model.md) +* [BLE Mesh Console Example Code](../../../../examples/bluetooth/ble_mesh/ble_mesh_console) +* [BLE Mesh Fast Prov Client Example Code](../../../../examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client) +* [BLE_Mesh_Fast_Prov_Client_Example_Walkthrough](../../../../examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/tutorial/ble_mesh_fast_provision_client.md) +* [BLE Mesh Fast Prov Server Example Code](../../../../examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server) +* [BLE_Mesh_Fast_Prov_Server_Example_Walkthrough](../../../../examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/ble_mesh_fast_provision_server.md) +* [BLE Mesh Wifi Coexist Example Code](../../../../examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist) +* [BLE_Mesh_Wifi_Coexist_Example_Walkthrough](../../../../examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/tutorial%20%20%20%20%20%20/ble_mesh_wifi_coexist.md) +## Documentation + +### ESP BLE Mesh Development Documentation + +* [Getting started with ESP BLE Mesh](BLE-Mesh_Getting_Started_EN.md) +* [ESP BLE Mesh Feature List](BLE-Mesh_Feature_List_EN.md) +* [FAQs](BLE-Mesh_FAQs_EN.md) +* [Known Issues](BLE-Mesh_Known_Issues_EN.md) + +### BLE Mesh Protocol Documentation + +* [BLE Mesh Core Specification](https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=429633) +* [BLE Mesh Model Specification](https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=429634) +* [An Intro to Bluetooth Mesh Part 1](http://blog.bluetooth.com/an-intro-to-bluetooth-mesh-part1) +* [An Intro to Bluetooth Mesh Part 2](http://blog.bluetooth.com/an-intro-to-bluetooth-mesh-part2) +* [The Fundamental Concepts of Bluetooth Mesh Networking Part 1](http://blog.bluetooth.com/the-fundamental-concepts-of-bluetooth-mesh-networking-part-1) +* [The Fundamental Concepts of Bluetooth Mesh Networking, Part 2](http://blog.bluetooth.com/the-fundamental-concepts-of-bluetooth-mesh-networking-part-2) +* [Bluetooth Mesh Networking: Friendship](http://blog.bluetooth.com/bluetooth-mesh-networking-series-friendship) +* [Management of Devices in a Bluetooth Mesh Network](http://blog.bluetooth.com/management-of-devices-bluetooth-mesh-network) +* [Bluetooth Mesh Security Overview](http://blog.bluetooth.com/bluetooth-mesh-security-overview) +* [Provisioning a Bluetooth Mesh Network Part 1](http://blog.bluetooth.com/provisioning-a-bluetooth-mesh-network-part-1) +* [Provisioning a Bluetooth Mesh Network Part 2](http://blog.bluetooth.com/provisioning-a-bluetooth-mesh-network-part-2) + diff --git a/components/bt/ble_mesh/mesh_models/generic_client.c b/components/bt/ble_mesh/mesh_models/generic_client.c new file mode 100644 index 0000000000..7aeb5d00d3 --- /dev/null +++ b/components/bt/ble_mesh/mesh_models/generic_client.c @@ -0,0 +1,1225 @@ +// Copyright 2017-2018 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 +#include +#include + +#include "osi/allocator.h" +#include "sdkconfig.h" + +#include "mesh_types.h" +#include "mesh_kernel.h" +#include "mesh_trace.h" + +#include "mesh.h" +#include "model_opcode.h" +#include "mesh_common.h" +#include "generic_client.h" + +#include "btc_ble_mesh_generic_model.h" + +/** The following are the macro definitions of generic client + * model messages length, and a message is composed of three + * parts: Opcode + msg_value + MIC + */ +/* Generic onoff client messages length */ +#define BLE_MESH_GEN_ONOFF_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_ONOFF_SET_MSG_LEN (2 + 4 + 4) + +/* Generic level client messages length */ +#define BLE_MESH_GEN_LEVEL_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_LEVEL_SET_MSG_LEN (2 + 5 + 4) +#define BLE_MESH_GEN_DELTA_SET_MSG_LEN (2 + 7 + 4) +#define BLE_MESH_GEN_MOVE_SET_MSG_LEN (2 + 5 + 4) + +/* Generic default transition time client messages length */ +#define BLE_MESH_GEN_DEF_TRANS_TIME_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_DEF_TRANS_TIME_SET_MSG_LEN (2 + 1 + 4) + +/* Generic power onoff client messages length */ +#define BLE_MESH_GEN_ONPOWERUP_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_ONPOWERUP_SET_MSG_LEN (2 + 1 + 4) + +/* Generic power level client messages length */ +#define BLE_MESH_GEN_POWER_LEVEL_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_POWER_LEVEL_SET_MSG_LEN (2 + 5 + 4) +#define BLE_MESH_GEN_POWER_LAST_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_POWER_DEFAULT_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_POWER_DEFAULT_SET_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_GEN_POWER_RANGE_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_POWER_RANGE_SET_MSG_LEN (2 + 4 + 4) + +/* Generic battery client messages length */ +#define BLE_MESH_GEN_BATTERY_GET_MSG_LEN (2 + 0 + 4) + +/* Generic location client messages length */ +#define BLE_MESH_GEN_LOC_GLOBAL_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_LOC_GLOBAL_SET_MSG_LEN (1 + 10 + 4) +#define BLE_MESH_GEN_LOC_LOCAL_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_LOC_LOCAL_SET_MSG_LEN (2 + 9 + 4) + +/* Generic property client messages length */ +#define BLE_MESH_GEN_USER_PROPERTIES_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_USER_PROPERTY_GET_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_GEN_USER_PROPERTY_SET_MSG_LEN /* variable */ +#define BLE_MESH_GEN_ADMIN_PROPERTIES_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_ADMIN_PROPERTY_GET_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_GEN_ADMIN_PROPERTY_SET_MSG_LEN /* variable */ +#define BLE_MESH_GEN_MANU_PROPERTIES_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_MANU_PROPERTY_GET_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_GEN_MANU_PROPERTY_SET_MSG_LEN (1 + 3 + 4) +#define BLE_MESH_GEN_CLINET_PROPERTIES_GET_MSG_LEN (1 + 2 + 4) + +#define BLE_MESH_GEN_GET_STATE_MSG_LEN (2 + 2 + 4) + +static const bt_mesh_client_op_pair_t gen_op_pair[] = { + { BLE_MESH_MODEL_OP_GEN_ONOFF_GET, BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS }, + { BLE_MESH_MODEL_OP_GEN_ONOFF_SET, BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS }, + { BLE_MESH_MODEL_OP_GEN_LEVEL_GET, BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS }, + { BLE_MESH_MODEL_OP_GEN_LEVEL_SET, BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS }, + { BLE_MESH_MODEL_OP_GEN_DELTA_SET, BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS }, + { BLE_MESH_MODEL_OP_GEN_MOVE_SET, BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS }, + { BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_GET, BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_STATUS }, + { BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET, BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_STATUS }, + { BLE_MESH_MODEL_OP_GEN_ONPOWERUP_GET, BLE_MESH_MODEL_OP_GEN_ONPOWERUP_STATUS }, + { BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET, BLE_MESH_MODEL_OP_GEN_ONPOWERUP_STATUS }, + { BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_GET, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS }, + { BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS }, + { BLE_MESH_MODEL_OP_GEN_POWER_LAST_GET, BLE_MESH_MODEL_OP_GEN_POWER_LAST_STATUS }, + { BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_GET, BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS }, + { BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET, BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS }, + { BLE_MESH_MODEL_OP_GEN_POWER_RANGE_GET, BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS }, + { BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET, BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS }, + { BLE_MESH_MODEL_OP_GEN_BATTERY_GET, BLE_MESH_MODEL_OP_GEN_BATTERY_STATUS }, + { BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_GET, BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_STATUS }, + { BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET, BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_STATUS }, + { BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_GET, BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_STATUS }, + { BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET, BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_STATUS }, + { BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_GET, BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS }, + { BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET, BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_STATUS }, + { BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET, BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_STATUS }, + { BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_GET, BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_STATUS }, + { BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET, BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_STATUS }, + { BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET, BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_STATUS }, + { BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_GET, BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_STATUS }, + { BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_GET, BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_STATUS }, + { BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET, BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_STATUS }, + { BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_GET, BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS }, +}; + +static void timeout_handler(struct k_work *work) +{ + generic_internal_data_t *internal = NULL; + bt_mesh_generic_client_t *client = NULL; + bt_mesh_client_node_t *node = NULL; + + BT_WARN("Receive generic status message timeout"); + + node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work); + if (!node || !node->ctx.model) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + client = (bt_mesh_generic_client_t *)node->ctx.model->user_data; + if (!client) { + BT_ERR("%s, Generic Client user_data is NULL", __func__); + return; + } + + internal = (generic_internal_data_t *)client->internal_data; + if (!internal) { + BT_ERR("%s, Generic Client internal_data is NULL", __func__); + return; + } + + bt_mesh_callback_generic_status_to_btc(node->opcode, 0x03, node->ctx.model, + &node->ctx, NULL, 0); + + bt_mesh_client_free_node(&internal->queue, node); + + return; +} + +static void generic_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + generic_internal_data_t *internal = NULL; + bt_mesh_generic_client_t *client = NULL; + bt_mesh_client_node_t *node = NULL; + u8_t *val = NULL; + u8_t evt = 0xFF; + u32_t rsp = 0; + size_t len = 0; + + BT_DBG("%s, len %d, bytes %s", __func__, buf->len, bt_hex(buf->data, buf->len)); + + client = (bt_mesh_generic_client_t *)model->user_data; + if (!client) { + BT_ERR("%s, Generic Client user_data is NULL", __func__); + return; + } + + internal = (generic_internal_data_t *)client->internal_data; + if (!internal) { + BT_ERR("%s, Generic Client internal_data is NULL", __func__); + return; + } + + rsp = ctx->recv_op; + + switch (rsp) { + case BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS: { + struct bt_mesh_gen_onoff_status *status = NULL; + if (buf->len != 1 && buf->len != 3) { + BT_ERR("Invalid Generic OnOff Status length %d", buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_gen_onoff_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->present_onoff = net_buf_simple_pull_u8(buf); + if (buf->len) { + status->op_en = true; + status->target_onoff = net_buf_simple_pull_u8(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (u8_t *)status; + len = sizeof(struct bt_mesh_gen_onoff_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS: { + struct bt_mesh_gen_level_status *status = NULL; + if (buf->len != 2 && buf->len != 5) { + BT_ERR("Invalid Generic Level Status length %d", buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_gen_level_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->present_level = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->target_level = net_buf_simple_pull_le16(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (u8_t *)status; + len = sizeof(struct bt_mesh_gen_level_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_STATUS: { + struct bt_mesh_gen_def_trans_time_status *status = NULL; + if (buf->len != 1) { + BT_ERR("Invalid Generic Default Trans Time Status length %d", buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_gen_def_trans_time_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->trans_time = net_buf_simple_pull_u8(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_gen_def_trans_time_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_ONPOWERUP_STATUS: { + struct bt_mesh_gen_onpowerup_status *status = NULL; + if (buf->len != 1) { + BT_ERR("Invalid Generic OnPowerUp Status length %d", buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_gen_onpowerup_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->onpowerup = net_buf_simple_pull_u8(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_gen_onpowerup_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS: { + struct bt_mesh_gen_power_level_status *status = NULL; + if (buf->len != 2 && buf->len != 5) { + BT_ERR("Invalid Generic Power Level Status length %d", buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_gen_power_level_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->present_power = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->target_power = net_buf_simple_pull_le16(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (u8_t *)status; + len = sizeof(struct bt_mesh_gen_power_level_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_POWER_LAST_STATUS: { + struct bt_mesh_gen_power_last_status *status = NULL; + if (buf->len != 2) { + BT_ERR("Invalid Generic Power Last Status length %d", buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_gen_power_last_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->power = net_buf_simple_pull_le16(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_gen_power_last_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS: { + struct bt_mesh_gen_power_default_status *status = NULL; + if (buf->len != 2) { + BT_ERR("Invalid Generic Power Default Status length %d", buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_gen_power_default_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->power = net_buf_simple_pull_le16(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_gen_power_default_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS: { + struct bt_mesh_gen_power_range_status *status = NULL; + if (buf->len != 5) { + BT_ERR("Invalid Generic Power Range Status length %d", buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_gen_power_range_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->status_code = net_buf_simple_pull_u8(buf); + status->range_min = net_buf_simple_pull_le16(buf); + status->range_max = net_buf_simple_pull_le16(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_gen_power_range_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_BATTERY_STATUS: { + struct bt_mesh_gen_battery_status *status = NULL; + if (buf->len != 8) { + BT_ERR("Invalid Generic Battery Status length %d", buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_gen_battery_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + u32_t value = 0; + value = net_buf_simple_pull_le32(buf); + status->battery_level = (u8_t)value; + status->time_to_discharge = (value >> 8); + value = net_buf_simple_pull_le32(buf); + status->time_to_charge = (value & 0xffffff); + status->flags = (u8_t)(value >> 24); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_gen_battery_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_STATUS: { + struct bt_mesh_gen_loc_global_status *status = NULL; + if (buf->len != 10) { + BT_ERR("Invalid Generic Location Global Status length %d", buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_gen_loc_global_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->global_latitude = net_buf_simple_pull_le32(buf); + status->global_longitude = net_buf_simple_pull_le32(buf); + status->global_altitude = net_buf_simple_pull_le16(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_gen_loc_global_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_STATUS: { + struct bt_mesh_gen_loc_local_status *status = NULL; + if (buf->len != 9) { + BT_ERR("Invalid Generic Location Local Status length %d", buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_gen_loc_local_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->local_north = net_buf_simple_pull_le16(buf); + status->local_east = net_buf_simple_pull_le16(buf); + status->local_altitude = net_buf_simple_pull_le16(buf); + status->floor_number = net_buf_simple_pull_u8(buf); + status->uncertainty = net_buf_simple_pull_le16(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_gen_loc_local_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS: { + struct bt_mesh_gen_user_properties_status *status = NULL; + status = osi_calloc(sizeof(struct bt_mesh_gen_user_properties_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->user_property_ids = bt_mesh_alloc_buf(buf->len); + if (!status->user_property_ids) { + BT_ERR("%s, Failed to allocate memory", __func__); + osi_free(status); + return; + } + net_buf_simple_add_mem(status->user_property_ids, buf->data, buf->len); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_gen_user_properties_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_STATUS: { + struct bt_mesh_gen_user_property_status *status = NULL; + status = osi_calloc(sizeof(struct bt_mesh_gen_user_property_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->user_property_id = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->user_access = net_buf_simple_pull_u8(buf); + status->user_property_value = bt_mesh_alloc_buf(buf->len); + if (!status->user_property_value) { + BT_ERR("%s, Failed to allocate memory", __func__); + osi_free(status); + return; + } + net_buf_simple_add_mem(status->user_property_value, buf->data, buf->len); + } + val = (u8_t *)status; + len = sizeof(struct bt_mesh_gen_user_property_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_STATUS: { + struct bt_mesh_gen_admin_properties_status *status = NULL; + status = osi_calloc(sizeof(struct bt_mesh_gen_admin_properties_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->admin_property_ids = bt_mesh_alloc_buf(buf->len); + if (!status->admin_property_ids) { + BT_ERR("%s, Failed to allocate memory", __func__); + osi_free(status); + return; + } + net_buf_simple_add_mem(status->admin_property_ids, buf->data, buf->len); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_gen_admin_properties_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_STATUS: { + struct bt_mesh_gen_admin_property_status *status = NULL; + status = osi_calloc(sizeof(struct bt_mesh_gen_admin_property_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->admin_property_id = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->admin_user_access = net_buf_simple_pull_u8(buf); + status->admin_property_value = bt_mesh_alloc_buf(buf->len); + if (!status->admin_property_value) { + BT_ERR("%s, Failed to allocate memory", __func__); + osi_free(status); + return; + } + net_buf_simple_add_mem(status->admin_property_value, buf->data, buf->len); + } + val = (u8_t *)status; + len = sizeof(struct bt_mesh_gen_admin_property_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_STATUS: { + struct bt_mesh_gen_manu_properties_status *status = NULL; + status = osi_calloc(sizeof(struct bt_mesh_gen_manu_properties_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->manu_property_ids = bt_mesh_alloc_buf(buf->len); + if (!status->manu_property_ids) { + BT_ERR("%s, Failed to allocate memory", __func__); + osi_free(status); + return; + } + net_buf_simple_add_mem(status->manu_property_ids, buf->data, buf->len); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_gen_manu_properties_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_STATUS: { + struct bt_mesh_gen_manu_property_status *status = NULL; + status = osi_calloc(sizeof(struct bt_mesh_gen_manu_property_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->manu_property_id = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->manu_user_access = net_buf_simple_pull_u8(buf); + status->manu_property_value = bt_mesh_alloc_buf(buf->len); + if (!status->manu_property_value) { + BT_ERR("%s, Failed to allocate memory", __func__); + osi_free(status); + return; + } + net_buf_simple_add_mem(status->manu_property_value, buf->data, buf->len); + } + val = (u8_t *)status; + len = sizeof(struct bt_mesh_gen_manu_property_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS: { + struct bt_mesh_gen_client_properties_status *status = NULL; + status = osi_calloc(sizeof(struct bt_mesh_gen_client_properties_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->client_property_ids = bt_mesh_alloc_buf(buf->len); + if (!status->client_property_ids) { + BT_ERR("%s, Failed to allocate memory", __func__); + osi_free(status); + return; + } + net_buf_simple_add_mem(status->client_property_ids, buf->data, buf->len); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_gen_client_properties_status); + break; + } + default: + BT_ERR("%s, Not a Generic Status message opcode", __func__); + return; + } + + buf->data = val; + buf->len = len; + node = bt_mesh_is_model_message_publish(model, ctx, buf, true); + if (!node) { + BT_DBG("Unexpected generic status message 0x%x", rsp); + } else { + switch (node->opcode) { + case BLE_MESH_MODEL_OP_GEN_ONOFF_GET: + case BLE_MESH_MODEL_OP_GEN_LEVEL_GET: + case BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_GET: + case BLE_MESH_MODEL_OP_GEN_ONPOWERUP_GET: + case BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_GET: + case BLE_MESH_MODEL_OP_GEN_POWER_LAST_GET: + case BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_GET: + case BLE_MESH_MODEL_OP_GEN_POWER_RANGE_GET: + case BLE_MESH_MODEL_OP_GEN_BATTERY_GET: + case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_GET: + case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_GET: + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_GET: + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET: + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_GET: + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET: + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_GET: + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_GET: + case BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_GET: + evt = 0x00; + break; + case BLE_MESH_MODEL_OP_GEN_ONOFF_SET: + case BLE_MESH_MODEL_OP_GEN_LEVEL_SET: + case BLE_MESH_MODEL_OP_GEN_DELTA_SET: + case BLE_MESH_MODEL_OP_GEN_MOVE_SET: + case BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET: + case BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET: + case BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET: + case BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET: + case BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET: + case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET: + case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET: + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET: + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET: + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET: + evt = 0x01; + break; + default: + break; + } + + bt_mesh_callback_generic_status_to_btc(node->opcode, evt, model, ctx, val, len); + // Don't forget to release the node at the end. + bt_mesh_client_free_node(&internal->queue, node); + } + + switch (rsp) { + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS: { + struct bt_mesh_gen_user_properties_status *status; + status = (struct bt_mesh_gen_user_properties_status *)val; + bt_mesh_free_buf(status->user_property_ids); + break; + } + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_STATUS: { + struct bt_mesh_gen_user_property_status *status; + status = (struct bt_mesh_gen_user_property_status *)val; + bt_mesh_free_buf(status->user_property_value); + break; + } + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_STATUS: { + struct bt_mesh_gen_admin_properties_status *status; + status = (struct bt_mesh_gen_admin_properties_status *)val; + bt_mesh_free_buf(status->admin_property_ids); + break; + } + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_STATUS: { + struct bt_mesh_gen_admin_property_status *status; + status = (struct bt_mesh_gen_admin_property_status *)val; + bt_mesh_free_buf(status->admin_property_value); + break; + } + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_STATUS: { + struct bt_mesh_gen_manu_properties_status *status; + status = (struct bt_mesh_gen_manu_properties_status *)val; + bt_mesh_free_buf(status->manu_property_ids); + break; + } + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_STATUS: { + struct bt_mesh_gen_manu_property_status *status; + status = (struct bt_mesh_gen_manu_property_status *)val; + bt_mesh_free_buf(status->manu_property_value); + break; + } + case BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS: { + struct bt_mesh_gen_client_properties_status *status; + status = (struct bt_mesh_gen_client_properties_status *)val; + bt_mesh_free_buf(status->client_property_ids); + break; + } + default: + break; + } + + osi_free(val); + + return; +} + +const struct bt_mesh_model_op gen_onoff_cli_op[] = { + { BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, 1, generic_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op gen_level_cli_op[] = { + { BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS, 2, generic_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op gen_def_trans_time_cli_op[] = { + { BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_STATUS, 1, generic_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op gen_power_onoff_cli_op[] = { + { BLE_MESH_MODEL_OP_GEN_ONPOWERUP_STATUS, 1, generic_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op gen_power_level_cli_op[] = { + { BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS, 2, generic_status }, + { BLE_MESH_MODEL_OP_GEN_POWER_LAST_STATUS, 2, generic_status }, + { BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS, 2, generic_status }, + { BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS, 5, generic_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op gen_battery_cli_op[] = { + { BLE_MESH_MODEL_OP_GEN_BATTERY_STATUS, 8, generic_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op gen_location_cli_op[] = { + { BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_STATUS, 10, generic_status }, + { BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_STATUS, 9, generic_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op gen_property_cli_op[] = { + { BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS, 2, generic_status }, + { BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_STATUS, 2, generic_status }, + { BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_STATUS, 2, generic_status }, + { BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_STATUS, 2, generic_status }, + { BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_STATUS, 2, generic_status }, + { BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_STATUS, 2, generic_status }, + { BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS, 2, generic_status }, + BLE_MESH_MODEL_OP_END, +}; + +static int gen_get_state(struct bt_mesh_common_param *common, void *value) +{ + NET_BUF_SIMPLE_DEFINE(msg, BLE_MESH_GEN_GET_STATE_MSG_LEN); + int err; + + bt_mesh_model_msg_init(&msg, common->opcode); + + if (value) { + switch (common->opcode) { + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET: { + struct bt_mesh_gen_user_property_get *get; + get = (struct bt_mesh_gen_user_property_get *)value; + net_buf_simple_add_le16(&msg, get->user_property_id); + break; + } + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET: { + struct bt_mesh_gen_admin_property_get *get; + get = (struct bt_mesh_gen_admin_property_get *)value; + net_buf_simple_add_le16(&msg, get->admin_property_id); + break; + } + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_GET: { + struct bt_mesh_gen_manu_property_get *get; + get = (struct bt_mesh_gen_manu_property_get *)value; + net_buf_simple_add_le16(&msg, get->manu_property_id); + break; + } + case BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_GET: { + struct bt_mesh_gen_client_properties_get *get; + get = (struct bt_mesh_gen_client_properties_get *)value; + net_buf_simple_add_le16(&msg, get->client_property_id); + break; + } + default: + BT_DBG("This generic message should be sent with NULL get pointer"); + break; + } + } + + err = bt_mesh_client_send_msg(common->model, common->opcode, &common->ctx, &msg, + timeout_handler, common->msg_timeout, true, + common->cb, common->cb_data); + if (err) { + BT_ERR("%s, Failed to send Generic Get message (err %d)", __func__, err); + } + + return err; +} + +static int gen_set_state(struct bt_mesh_common_param *common, + void *value, u16_t value_len, bool need_ack) +{ + struct net_buf_simple *msg = NULL; + int err; + + msg = bt_mesh_alloc_buf(value_len); + if (!msg) { + BT_ERR("%s, Failed to allocate memory", __func__); + return -ENOMEM; + } + + bt_mesh_model_msg_init(msg, common->opcode); + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_GEN_ONOFF_SET: + case BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK: { + struct bt_mesh_gen_onoff_set *set; + set = (struct bt_mesh_gen_onoff_set *)value; + net_buf_simple_add_u8(msg, set->onoff); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + + case BLE_MESH_MODEL_OP_GEN_LEVEL_SET: + case BLE_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK: { + struct bt_mesh_gen_level_set *set; + set = (struct bt_mesh_gen_level_set *)value; + net_buf_simple_add_le16(msg, set->level); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + + case BLE_MESH_MODEL_OP_GEN_DELTA_SET: + case BLE_MESH_MODEL_OP_GEN_DELTA_SET_UNACK: { + struct bt_mesh_gen_delta_set *set; + set = (struct bt_mesh_gen_delta_set *)value; + net_buf_simple_add_le32(msg, set->level); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + + case BLE_MESH_MODEL_OP_GEN_MOVE_SET: + case BLE_MESH_MODEL_OP_GEN_MOVE_SET_UNACK: { + struct bt_mesh_gen_move_set *set; + set = (struct bt_mesh_gen_move_set *)value; + net_buf_simple_add_le16(msg, set->delta_level); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + + case BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET: + case BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET_UNACK: { + struct bt_mesh_gen_def_trans_time_set *set; + set = (struct bt_mesh_gen_def_trans_time_set *)value; + net_buf_simple_add_u8(msg, set->trans_time); + break; + } + + case BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET: + case BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET_UNACK: { + struct bt_mesh_gen_onpowerup_set *set; + set = (struct bt_mesh_gen_onpowerup_set *)value; + net_buf_simple_add_u8(msg, set->onpowerup); + break; + } + + case BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET: + case BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET_UNACK: { + struct bt_mesh_gen_power_level_set *set; + set = (struct bt_mesh_gen_power_level_set *)value; + net_buf_simple_add_le16(msg, set->power); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + + case BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET: + case BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET_UNACK: { + struct bt_mesh_gen_power_default_set *set; + set = (struct bt_mesh_gen_power_default_set *)value; + net_buf_simple_add_le16(msg, set->power); + break; + } + + case BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET: + case BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET_UNACK: { + struct bt_mesh_gen_power_range_set *set; + set = (struct bt_mesh_gen_power_range_set *)value; + net_buf_simple_add_le16(msg, set->range_min); + net_buf_simple_add_le16(msg, set->range_max); + break; + } + + case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET: + case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET_UNACK: { + struct bt_mesh_gen_loc_global_set *set; + set = (struct bt_mesh_gen_loc_global_set *)value; + net_buf_simple_add_le32(msg, set->global_latitude); + net_buf_simple_add_le32(msg, set->global_longitude); + net_buf_simple_add_le16(msg, set->global_altitude); + break; + } + + case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET: + case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET_UNACK: { + struct bt_mesh_gen_loc_local_set *set; + set = (struct bt_mesh_gen_loc_local_set *)value; + net_buf_simple_add_le16(msg, set->local_north); + net_buf_simple_add_le16(msg, set->local_east); + net_buf_simple_add_le16(msg, set->local_altitude); + net_buf_simple_add_u8(msg, set->floor_number); + net_buf_simple_add_le16(msg, set->uncertainty); + break; + } + + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET: + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET_UNACK: { + struct bt_mesh_gen_user_property_set *set; + set = (struct bt_mesh_gen_user_property_set *)value; + net_buf_simple_add_le16(msg, set->user_property_id); + net_buf_simple_add_mem(msg, set->user_property_value->data, set->user_property_value->len); + break; + } + + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET: + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET_UNACK: { + struct bt_mesh_gen_admin_property_set *set; + set = (struct bt_mesh_gen_admin_property_set *)value; + net_buf_simple_add_le16(msg, set->admin_property_id); + net_buf_simple_add_u8(msg, set->admin_user_access); + net_buf_simple_add_mem(msg, set->admin_property_value->data, set->admin_property_value->len); + break; + } + + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET: + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET_UNACK: { + struct bt_mesh_gen_manu_property_set *set; + set = (struct bt_mesh_gen_manu_property_set *)value; + net_buf_simple_add_le16(msg, set->manu_property_id); + net_buf_simple_add_u8(msg, set->manu_user_access); + break; + } + + default: + BT_ERR("%s, Not a Generic Client Set message opcode", __func__); + err = -EINVAL; + goto end; + } + + err = bt_mesh_client_send_msg(common->model, common->opcode, &common->ctx, msg, + timeout_handler, common->msg_timeout, need_ack, + common->cb, common->cb_data); + if (err) { + BT_ERR("%s, Failed to send Generic Set message (err %d)", __func__, err); + } + +end: + bt_mesh_free_buf(msg); + + return err; +} + +int bt_mesh_generic_client_get_state(struct bt_mesh_common_param *common, void *get, void *status) +{ + bt_mesh_generic_client_t *client = NULL; + + if (!common || !common->model) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_generic_client_t *)common->model->user_data; + if (!client || !client->internal_data) { + BT_ERR("%s, Generic Client user data is NULL", __func__); + return -EINVAL; + } + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_GEN_ONOFF_GET: + case BLE_MESH_MODEL_OP_GEN_LEVEL_GET: + case BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_GET: + case BLE_MESH_MODEL_OP_GEN_ONPOWERUP_GET: + case BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_GET: + case BLE_MESH_MODEL_OP_GEN_POWER_LAST_GET: + case BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_GET: + case BLE_MESH_MODEL_OP_GEN_POWER_RANGE_GET: + case BLE_MESH_MODEL_OP_GEN_BATTERY_GET: + case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_GET: + case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_GET: + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_GET: + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_GET: + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_GET: + break; + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET: + if (!get) { + BT_ERR("%s, Generic user_property_get is NULL", __func__); + return -EINVAL; + } + break; + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET: + if (!get) { + BT_ERR("%s, Generic admin_property_get is NULL", __func__); + return -EINVAL; + } + break; + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_GET: + if (!get) { + BT_ERR("%s, Generic manu_property_get is NULL", __func__); + return -EINVAL; + } + break; + case BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_GET: + if (!get) { + BT_ERR("%s, Generic client_properties_get is NULL", __func__); + return -EINVAL; + } + break; + default: + BT_ERR("%s, Not a Generic Client Get message opcode", __func__); + return -EINVAL; + } + + return gen_get_state(common, get); +} + +int bt_mesh_generic_client_set_state(struct bt_mesh_common_param *common, void *set, void *status) +{ + bt_mesh_generic_client_t *client = NULL; + u16_t length = 0; + bool need_ack = false; + + if (!common || !common->model || !set) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_generic_client_t *)common->model->user_data; + if (!client || !client->internal_data) { + BT_ERR("%s, Generic Client user data is NULL", __func__); + return -EINVAL; + } + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_GEN_ONOFF_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK: { + struct bt_mesh_gen_onoff_set *value; + value = (struct bt_mesh_gen_onoff_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("%s, Invalid Generic OnOff Set transition time", __func__); + return -EINVAL; + } + } + length = BLE_MESH_GEN_ONOFF_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_GEN_LEVEL_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK: { + struct bt_mesh_gen_level_set *value; + value = (struct bt_mesh_gen_level_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("%s, Invalid Generic Level Set transition time", __func__); + return -EINVAL; + } + } + length = BLE_MESH_GEN_LEVEL_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_GEN_DELTA_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_DELTA_SET_UNACK: { + struct bt_mesh_gen_delta_set *value; + value = (struct bt_mesh_gen_delta_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("%s, Invalid Generic Delta Set transition time", __func__); + return -EINVAL; + } + } + length = BLE_MESH_GEN_DELTA_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_GEN_MOVE_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_MOVE_SET_UNACK: { + struct bt_mesh_gen_move_set *value; + value = (struct bt_mesh_gen_move_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("%s, Invalid Generic Move Set transition time", __func__); + return -EINVAL; + } + } + length = BLE_MESH_GEN_MOVE_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET_UNACK: { + u8_t value = *(u8_t *)set; + if ((value & 0x3F) > 0x3E) { + BT_ERR("%s, Invalid Generic Default Trans Time Set transition time", __func__); + return -EINVAL; + } + length = BLE_MESH_GEN_DEF_TRANS_TIME_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET_UNACK: + length = BLE_MESH_GEN_ONPOWERUP_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET_UNACK: { + struct bt_mesh_gen_power_level_set *value; + value = (struct bt_mesh_gen_power_level_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("%s, Invalid Generic Power Level Set transition time", __func__); + return -EINVAL; + } + } + length = BLE_MESH_GEN_POWER_LEVEL_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET_UNACK: + length = BLE_MESH_GEN_POWER_DEFAULT_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET_UNACK: { + struct bt_mesh_gen_power_range_set *value; + value = (struct bt_mesh_gen_power_range_set *)set; + if (value->range_min > value->range_max) { + BT_ERR("%s, Generic Power Level Set range min is greater than range max", __func__); + return -EINVAL; + } + length = BLE_MESH_GEN_POWER_RANGE_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET_UNACK: + length = BLE_MESH_GEN_LOC_GLOBAL_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET_UNACK: + length = BLE_MESH_GEN_LOC_LOCAL_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET_UNACK: { + struct bt_mesh_gen_user_property_set *value; + value = (struct bt_mesh_gen_user_property_set *)set; + if (!value->user_property_value) { + BT_ERR("%s, Generic user_property_value is NULL", __func__); + return -EINVAL; + } + length = (1 + 2 + value->user_property_value->len + 4); + break; + } + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET_UNACK: { + struct bt_mesh_gen_admin_property_set *value; + value = (struct bt_mesh_gen_admin_property_set *)set; + if (!value->admin_property_value) { + BT_ERR("%s, Generic admin_property_value is NULL", __func__); + return -EINVAL; + } + length = (1 + 2 + 1 + value->admin_property_value->len + 4); + break; + } + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET_UNACK: + length = BLE_MESH_GEN_MANU_PROPERTY_SET_MSG_LEN; + break; + default: + BT_ERR("%s, Not a Generic Client Set message opcode", __func__); + return -EINVAL; + } + + return gen_set_state(common, set, length, need_ack); +} + +static int generic_client_init(struct bt_mesh_model *model, bool primary) +{ + generic_internal_data_t *internal = NULL; + bt_mesh_generic_client_t *client = NULL; + + BT_DBG("primary %u", primary); + + if (!model) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_generic_client_t *)model->user_data; + if (!client) { + BT_ERR("%s, Generic Client user_data is NULL", __func__); + return -EINVAL; + } + + /* TODO: call osi_free() when deinit function is invoked*/ + internal = osi_calloc(sizeof(generic_internal_data_t)); + if (!internal) { + BT_ERR("%s, Failed to allocate memory", __func__); + return -ENOMEM; + } + + sys_slist_init(&internal->queue); + + client->model = model; + client->op_pair_size = ARRAY_SIZE(gen_op_pair); + client->op_pair = gen_op_pair; + client->internal_data = internal; + + return 0; +} + +int bt_mesh_gen_onoff_cli_init(struct bt_mesh_model *model, bool primary) +{ + return generic_client_init(model, primary); +} + +int bt_mesh_gen_level_cli_init(struct bt_mesh_model *model, bool primary) +{ + return generic_client_init(model, primary); +} + +int bt_mesh_gen_def_trans_time_cli_init(struct bt_mesh_model *model, bool primary) +{ + return generic_client_init(model, primary); +} + +int bt_mesh_gen_pwr_onoff_cli_init(struct bt_mesh_model *model, bool primary) +{ + return generic_client_init(model, primary); +} + +int bt_mesh_gen_pwr_level_cli_init(struct bt_mesh_model *model, bool primary) +{ + return generic_client_init(model, primary); +} + +int bt_mesh_gen_battery_cli_init(struct bt_mesh_model *model, bool primary) +{ + return generic_client_init(model, primary); +} + +int bt_mesh_gen_location_cli_init(struct bt_mesh_model *model, bool primary) +{ + return generic_client_init(model, primary); +} + +int bt_mesh_gen_property_cli_init(struct bt_mesh_model *model, bool primary) +{ + return generic_client_init(model, primary); +} diff --git a/components/bt/ble_mesh/mesh_models/include/generic_client.h b/components/bt/ble_mesh/mesh_models/include/generic_client.h new file mode 100644 index 0000000000..3f272cb952 --- /dev/null +++ b/components/bt/ble_mesh/mesh_models/include/generic_client.h @@ -0,0 +1,491 @@ +// Copyright 2017-2018 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. + +/** @file + * @brief Bluetooth Mesh Generic Client Model APIs. + */ + +#ifndef _GENERIC_CLIENT_H_ +#define _GENERIC_CLIENT_H_ + +#include "mesh_access.h" +#include "mesh_kernel.h" + +#include "model_common.h" + +/* Generic client model common structure */ +typedef bt_mesh_client_common_t bt_mesh_generic_client_t; +typedef bt_mesh_internal_data_t generic_internal_data_t; + +/* Generic OnOff Client Model Context */ +extern const struct bt_mesh_model_op gen_onoff_cli_op[]; + +/** @def BLE_MESH_MODEL_GEN_ONOFF_CLI + * + * Define a new generic onoff client model. Note that this API + * needs to be repeated for each element which the application + * wants to have a generic onoff client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_gen_onoff_cli. + * + * @return New generic onoff client model instance. + */ +#define BLE_MESH_MODEL_GEN_ONOFF_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, \ + gen_onoff_cli_op, cli_pub, cli_data) + +typedef bt_mesh_client_common_t bt_mesh_gen_onoff_cli_t; + +struct bt_mesh_gen_onoff_status { + bool op_en; /* Indicate whether optional parameters included */ + u8_t present_onoff; /* Present value of Generic OnOff state */ + u8_t target_onoff; /* Target value of Generic OnOff state (optional) */ + u8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_gen_onoff_set { + bool op_en; /* Indicate whether optional parameters included */ + u8_t onoff; /* Target value of Generic OnOff state */ + u8_t tid; /* Transaction Identifier */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +}; + +/* Generic Level Client Model Context */ +extern const struct bt_mesh_model_op gen_level_cli_op[]; + +/** @def BLE_MESH_MODEL_GEN_LEVEL_CLI + * + * Define a new generic level client model. Note that this API + * needs to be repeated for each element which the application + * wants to have a generic level client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_gen_level_cli. + * + * @return New generic level client model instance. + */ +#define BLE_MESH_MODEL_GEN_LEVEL_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_GEN_LEVEL_CLI, \ + gen_level_cli_op, cli_pub, cli_data) + +typedef bt_mesh_client_common_t bt_mesh_gen_level_cli_t; + +struct bt_mesh_gen_level_status { + bool op_en; /* Indicate whether optional parameters included */ + s16_t present_level; /* Present value of Generic Level state */ + s16_t target_level; /* Target value of the Generic Level state (optional) */ + u8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_gen_level_set { + bool op_en; /* Indicate whether optional parameters included */ + s16_t level; /* Target value of Generic Level state */ + u8_t tid; /* Transaction Identifier */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_gen_delta_set { + bool op_en; /* Indicate whether optional parameters included */ + s32_t level; /* Delta change of Generic Level state */ + u8_t tid; /* Transaction Identifier */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_gen_move_set { + bool op_en; /* Indicate whether optional parameters included */ + s16_t delta_level; /* Delta Level step to calculate Move speed for Generic Level state */ + u8_t tid; /* Transaction Identifier */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +}; + +/* Generic Default Transition Time Client Model Context */ +extern const struct bt_mesh_model_op gen_def_trans_time_cli_op[]; + +/** @def BLE_MESH_MODEL_GEN_DEF_TRANS_TIME_CLI + * + * Define a new generic default transition time client model. Note + * that this API needs to be repeated for each element that the + * application wants to have a generic default transition client + * model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_gen_def_trans_time_cli. + * + * @return New generic default transition time client model instance. + */ +#define BLE_MESH_MODEL_GEN_DEF_TRANS_TIME_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_CLI, \ + gen_def_trans_time_cli_op, cli_pub, cli_data) + +typedef bt_mesh_client_common_t bt_mesh_gen_def_trans_time_cli_t; + +struct bt_mesh_gen_def_trans_time_set { + u8_t trans_time; /* The value of the Generic Default Transition Time state */ +}; + +struct bt_mesh_gen_def_trans_time_status { + u8_t trans_time; /* The value of the Generic Default Transition Time state */ +}; + +/* Generic Power OnOff Client Model Context */ +extern const struct bt_mesh_model_op gen_power_onoff_cli_op[]; + +/** @def BLE_MESH_MODEL_GEN_POWER_ONOFF_CLI + * + * Define a new generic power onoff client model. Note that this API + * needs to be repeated for each element which the application wants + * to have a generic power onoff client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_gen_power_onoff_cli. + * + * @return New generic power onoff client model instance. + */ +#define BLE_MESH_MODEL_GEN_POWER_ONOFF_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_CLI, \ + gen_power_onoff_cli_op, cli_pub, cli_data) + +typedef bt_mesh_client_common_t bt_mesh_gen_power_onoff_cli_t; + +struct bt_mesh_gen_onpowerup_set { + u8_t onpowerup; /* The value of the Generic OnPowerUp state */ +}; + +struct bt_mesh_gen_onpowerup_status { + u8_t onpowerup; /* The value of the Generic OnPowerUp state */ +}; + +/* Generic Power Level Client Model Context */ +extern const struct bt_mesh_model_op gen_power_level_cli_op[]; + +/** @def BLE_MESH_MODEL_GEN_POWER_LEVEL_CLI + * + * Define a new generic power level client model. Note that this API + * needs to be repeated for each element which the application wants + * to have a generic power level client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_gen_power_level_cli. + * + * @return New generic power level client model instance. + */ +#define BLE_MESH_MODEL_GEN_POWER_LEVEL_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_CLI, \ + gen_power_level_cli_op, cli_pub, cli_data) + +typedef bt_mesh_client_common_t bt_mesh_gen_power_level_cli_t; + +struct bt_mesh_gen_power_level_status { + bool op_en; /* Indicate whether optional parameters included */ + u16_t present_power; /* Present value of Generic Power Actual state */ + u16_t target_power; /* Target value of Generic Power Actual state (optional) */ + u8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_gen_power_last_status { + u16_t power; /* The value of the Generic Power Last state */ +}; + +struct bt_mesh_gen_power_default_status { + u16_t power; /* The value of the Generic Default Last state */ +}; + +struct bt_mesh_gen_power_range_status { + u8_t status_code; /* Status Code for the requesting message */ + u16_t range_min; /* Value of Range Min field of Generic Power Range state */ + u16_t range_max; /* Value of Range Max field of Generic Power Range state */ +}; + +struct bt_mesh_gen_power_level_set { + bool op_en; /* Indicate whether optional parameters included */ + u16_t power; /* Target value of Generic Power Actual state */ + u8_t tid; /* Transaction Identifier */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_gen_power_default_set { + u16_t power; /* The value of the Generic Power Default state */ +}; + +struct bt_mesh_gen_power_range_set { + u16_t range_min; /* Value of Range Min field of Generic Power Range state */ + u16_t range_max; /* Value of Range Max field of Generic Power Range state */ +}; + +/* Generic Battery Client Model Context */ +extern const struct bt_mesh_model_op gen_battery_cli_op[]; + +/** @def BLE_MESH_MODEL_GEN_BATTERY_CLI + * + * Define a new generic battery client model. Note that this API + * needs to be repeated for each element which the application + * wants to have a generic battery client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_gen_battery_cli. + * + * @return New generic battery client model instance. + */ +#define BLE_MESH_MODEL_GEN_BATTERY_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_GEN_BATTERY_CLI, \ + gen_battery_cli_op, cli_pub, cli_data) + +typedef bt_mesh_client_common_t bt_mesh_gen_battery_cli_t; + +struct bt_mesh_gen_battery_status { + u32_t battery_level : 8; /* Value of Generic Battery Level state */ + u32_t time_to_discharge : 24; /* Value of Generic Battery Time to Discharge state */ + u32_t time_to_charge : 24; /* Value of Generic Battery Time to Charge state */ + u32_t flags : 8; /* Value of Generic Battery Flags state */ +}; + +/* Generic Location Client Model Context */ +extern const struct bt_mesh_model_op gen_location_cli_op[]; + +/** @def BLE_MESH_MODEL_GEN_LOCATION_CLI + * + * Define a new generic location client model. Note that this API + * needs to be repeated for each element which the application + * wants to have a generic location client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_gen_location_cli. + * + * @return New generic location client model instance. + */ +#define BLE_MESH_MODEL_GEN_LOCATION_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_GEN_LOCATION_CLI, \ + gen_location_cli_op, cli_pub, cli_data) + +typedef bt_mesh_client_common_t bt_mesh_gen_location_cli_t; + +struct bt_mesh_gen_loc_global_status { + s32_t global_latitude; /* Global Coordinates (Latitude) */ + s32_t global_longitude; /* Global Coordinates (Longitude) */ + s16_t global_altitude; /* Global Altitude */ +}; + +struct bt_mesh_gen_loc_local_status { + s16_t local_north; /* Local Coordinates (North) */ + s16_t local_east; /* Local Coordinates (East) */ + s16_t local_altitude; /* Local Altitude */ + u8_t floor_number; /* Floor Number */ + u16_t uncertainty; /* Uncertainty */ +}; + +struct bt_mesh_gen_loc_global_set { + s32_t global_latitude; /* Global Coordinates (Latitude) */ + s32_t global_longitude; /* Global Coordinates (Longitude) */ + s16_t global_altitude; /* Global Altitude */ +}; + +struct bt_mesh_gen_loc_local_set { + s16_t local_north; /* Local Coordinates (North) */ + s16_t local_east; /* Local Coordinates (East) */ + s16_t local_altitude; /* Local Altitude */ + u8_t floor_number; /* Floor Number */ + u16_t uncertainty; /* Uncertainty */ +}; + +/* Generic Property Client Model Context */ +extern const struct bt_mesh_model_op gen_property_cli_op[]; + +/** @def BLE_MESH_MODEL_GEN_LOCATION_CLI + * + * Define a new generic location client model. Note that this API + * needs to be repeated for each element which the application + * wants to have a generic location client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_gen_location_cli. + * + * @return New generic location client model instance. + */ +#define BLE_MESH_MODEL_GEN_PROPERTY_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_GEN_PROP_CLI, \ + gen_property_cli_op, cli_pub, cli_data) + +typedef bt_mesh_client_common_t bt_mesh_gen_property_cli_t; + +struct bt_mesh_gen_user_properties_status { + struct net_buf_simple *user_property_ids; /* Buffer contains a sequence of N User Property IDs */ +}; + +struct bt_mesh_gen_user_property_status { + bool op_en; /* Indicate whether optional parameters included */ + u16_t user_property_id; /* Property ID identifying a Generic User Property */ + u8_t user_access; /* Enumeration indicating user access (optional) */ + struct net_buf_simple *user_property_value; /* Raw value for the User Property (C.1) */ +}; + +struct bt_mesh_gen_admin_properties_status { + struct net_buf_simple *admin_property_ids; /* Buffer contains a sequence of N Admin Property IDs */ +}; + +struct bt_mesh_gen_admin_property_status { + bool op_en; /* Indicate whether optional parameters included */ + u16_t admin_property_id; /* Property ID identifying a Generic Admin Property */ + u8_t admin_user_access; /* Enumeration indicating user access (optional) */ + struct net_buf_simple *admin_property_value; /* Raw value for the Admin Property (C.1) */ +}; + +struct bt_mesh_gen_manu_properties_status { + struct net_buf_simple *manu_property_ids; /* Buffer contains a sequence of N Manufacturer Property IDs */ +}; + +struct bt_mesh_gen_manu_property_status { + bool op_en; /* Indicate whether optional parameters included */ + u16_t manu_property_id; /* Property ID identifying a Generic Manufacturer Property */ + u8_t manu_user_access; /* Enumeration indicating user access (optional) */ + struct net_buf_simple *manu_property_value; /* Raw value for the Manufacturer Property (C.1) */ +}; + +struct bt_mesh_gen_client_properties_status { + struct net_buf_simple *client_property_ids; /* Buffer contains a sequence of N Client Property IDs */ +}; + +struct bt_mesh_gen_user_property_get { + u16_t user_property_id; /* Property ID identifying a Generic User Property */ +}; + +struct bt_mesh_gen_user_property_set { + u16_t user_property_id; /* Property ID identifying a Generic User Property */ + struct net_buf_simple *user_property_value; /* Raw value for the User Property */ +}; + +struct bt_mesh_gen_admin_property_get { + u16_t admin_property_id; /* Property ID identifying a Generic Admin Property */ +}; + +struct bt_mesh_gen_admin_property_set { + u16_t admin_property_id; /* Property ID identifying a Generic Admin Property */ + u8_t admin_user_access; /* Enumeration indicating user access */ + struct net_buf_simple *admin_property_value; /* Raw value for the Admin Property */ +}; + +struct bt_mesh_gen_manu_property_get { + u16_t manu_property_id; /* Property ID identifying a Generic Manufacturer Property */ +}; + +struct bt_mesh_gen_manu_property_set { + u16_t manu_property_id; /* Property ID identifying a Generic Manufacturer Property */ + u8_t manu_user_access; /* Enumeration indicating user access */ +}; + +struct bt_mesh_gen_client_properties_get { + u16_t client_property_id; /* A starting Client Property ID present within an element */ +}; + +/** + * @brief This function is called to initialize generic onoff client model user_data. + * + * @param[in] model: Pointer to generic onoff client model + * @param[in] primary: Whether belongs to primary element + * + * @return Zero-success, other-fail + */ +int bt_mesh_gen_onoff_cli_init(struct bt_mesh_model *model, bool primary); + +/** + * @brief This function is called to initialize generic level client model user_data. + * + * @param[in] model: Pointer to generic level client model + * @param[in] primary: Whether belongs to primary element + * + * @return Zero-success, other-fail + */ +int bt_mesh_gen_level_cli_init(struct bt_mesh_model *model, bool primary); + +/** + * @brief This function is called to initialize generic default transition time + * client model user_data. + * + * @param[in] model: Pointer to generic default transition time client model + * @param[in] primary: Whether belongs to primary element + * + * @return Zero-success, other-fail + */ +int bt_mesh_gen_def_trans_time_cli_init(struct bt_mesh_model *model, bool primary); + +/** + * @brief This function is called to initialize generic power onoff client model user_data. + * + * @param[in] model: Pointer to generic power onoff client model + * @param[in] primary: Whether belongs to primary element + * + * @return Zero-success, other-fail + */ +int bt_mesh_gen_pwr_onoff_cli_init(struct bt_mesh_model *model, bool primary); + +/** + * @brief This function is called to initialize generic power level client model user_data. + * + * @param[in] model: Pointer to generic power level client model + * @param[in] primary: Whether belongs to primary element + * + * @return Zero-success, other-fail + */ +int bt_mesh_gen_pwr_level_cli_init(struct bt_mesh_model *model, bool primary); + +/** + * @brief This function is called to initialize generic battery client model user_data. + * + * @param[in] model: Pointer to generic battery client model + * @param[in] primary: Whether belongs to primary element + * + * @return Zero-success, other-fail + */ +int bt_mesh_gen_battery_cli_init(struct bt_mesh_model *model, bool primary); + +/** + * @brief This function is called to initialize generic location client model user_data. + * + * @param[in] model: Pointer to generic location client model + * @param[in] primary: Whether belongs to primary element + * + * @return Zero-success, other-fail + */ +int bt_mesh_gen_location_cli_init(struct bt_mesh_model *model, bool primary); + +/** + * @brief This function is called to initialize generic property client model user_data. + * + * @param[in] model: Pointer to generic property client model + * @param[in] primary: Whether belongs to primary element + * + * @return Zero-success, other-fail + */ +int bt_mesh_gen_property_cli_init(struct bt_mesh_model *model, bool primary); + +/** + * @brief This function is called to get generic states. + * + * @param[in] common: Message common information structure + * @param[in] get: Pointer of generic get message value + * @param[out] status: Pointer of generic status message value + * + * @return Zero-success, other-fail + */ +int bt_mesh_generic_client_get_state(struct bt_mesh_common_param *common, void *get, void *status); + +/** + * @brief This function is called to set generic states. + * + * @param[in] common: Message common information structure + * @param[in] set: Pointer of generic set message value + * @param[out] status: Pointer of generic status message value + * + * @return Zero-success, other-fail + */ +int bt_mesh_generic_client_set_state(struct bt_mesh_common_param *common, void *set, void *status); + +#endif /* _GENERIC_CLIENT_H_ */ diff --git a/components/bt/ble_mesh/mesh_models/include/lighting_client.h b/components/bt/ble_mesh/mesh_models/include/lighting_client.h new file mode 100644 index 0000000000..5b6b92a5ae --- /dev/null +++ b/components/bt/ble_mesh/mesh_models/include/lighting_client.h @@ -0,0 +1,492 @@ +// Copyright 2017-2018 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. + +/** @file + * @brief Bluetooth Mesh Lighting Client Model APIs. + */ + +#ifndef _LIGHTING_CLIENT_H_ +#define _LIGHTING_CLIENT_H_ + +#include "mesh_access.h" +#include "mesh_kernel.h" + +#include "model_common.h" + +/* Light client model common structure */ +typedef bt_mesh_client_common_t bt_mesh_light_client_t; +typedef bt_mesh_internal_data_t light_internal_data_t; + +/* Light Lightness Client Model Context */ +extern const struct bt_mesh_model_op light_lightness_cli_op[]; + +/** @def BLE_MESH_MODEL_LIGHT_LIGHTNESS_CLI + * + * Define a new light lightness client model. Note that this API + * needs to be repeated for each element which the application + * wants to have a light lightness client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_light_lightness_cli. + * + * @return New light lightness client model instance. + */ +#define BLE_MESH_MODEL_LIGHT_LIGHTNESS_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_CLI, \ + light_lightness_cli_op, cli_pub, cli_data) + +typedef bt_mesh_client_common_t bt_mesh_light_lightness_cli_t; + +struct bt_mesh_light_lightness_status { + bool op_en; /* Indicate whether optional parameters included */ + u16_t present_lightness; /* Present value of light lightness actual state */ + u16_t target_lightness; /* Target value of light lightness actual state (optional) */ + u8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_light_lightness_linear_status { + bool op_en; /* Indicate whether optional parameters included */ + u16_t present_lightness; /* Present value of light lightness linear state */ + u16_t target_lightness; /* Target value of light lightness linear state (optional) */ + u8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_light_lightness_last_status { + u16_t lightness; /* The value of the Light Lightness Last state */ +}; + +struct bt_mesh_light_lightness_default_status { + u16_t lightness; /* The value of the Light Lightness default state */ +}; + +struct bt_mesh_light_lightness_range_status { + u8_t status_code; /* Status Code for the requesting message */ + u16_t range_min; /* Value of range min field of light lightness range state */ + u16_t range_max; /* Value of range max field of light lightness range state */ +}; + +struct bt_mesh_light_lightness_set { + bool op_en; /* Indicate whether optional parameters included */ + u16_t lightness; /* Target value of light lightness actual state */ + u8_t tid; /* Transaction Identifier */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_light_lightness_linear_set { + bool op_en; /* Indicate whether optional parameters included */ + u16_t lightness; /* Target value of light lightness linear state */ + u8_t tid; /* Transaction Identifier */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_light_lightness_default_set { + u16_t lightness; /* The value of the Light Lightness Default state */ +}; + +struct bt_mesh_light_lightness_range_set { + u16_t range_min; /* Value of range min field of light lightness range state */ + u16_t range_max; /* Value of range max field of light lightness range state */ +}; + +/* Light CTL Client Model Context */ +extern const struct bt_mesh_model_op light_ctl_cli_op[]; + +/** @def BLE_MESH_MODEL_LIGHT_CTL_CLI + * + * Define a new light CTL client model. Note that this API needs + * to be repeated for each element which the application wants to + * have a light CTL client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_light_ctl_cli. + * + * @return New light CTL client model instance. + */ +#define BLE_MESH_MODEL_LIGHT_CTL_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_LIGHT_CTL_CLI, \ + light_ctl_cli_op, cli_pub, cli_data) + +typedef bt_mesh_client_common_t bt_mesh_light_ctl_cli_t; + +struct bt_mesh_light_ctl_status { + bool op_en; /* Indicate whether optional parameters included */ + u16_t present_ctl_lightness; /* Present value of light ctl lightness state */ + u16_t present_ctl_temperature; /* Present value of light ctl temperature state */ + u16_t target_ctl_lightness; /* Target value of light ctl lightness state (optional) */ + u16_t target_ctl_temperature; /* Target value of light ctl temperature state (C.1) */ + u8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_light_ctl_temperature_status { + bool op_en; /* Indicate whether optional parameters included */ + u16_t present_ctl_temperature; /* Present value of light ctl temperature state */ + u16_t present_ctl_delta_uv; /* Present value of light ctl delta UV state */ + u16_t target_ctl_temperature; /* Target value of light ctl temperature state (optional) */ + u16_t target_ctl_delta_uv; /* Target value of light ctl delta UV state (C.1) */ + u8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_light_ctl_temperature_range_status { + u8_t status_code; /* Status code for the requesting message */ + u16_t range_min; /* Value of temperature range min field of light ctl temperature range state */ + u16_t range_max; /* Value of temperature range max field of light ctl temperature range state */ +}; + +struct bt_mesh_light_ctl_default_status { + u16_t lightness; /* Value of light lightness default state */ + u16_t temperature; /* Value of light temperature default state */ + s16_t delta_uv; /* Value of light delta UV default state */ +}; + +struct bt_mesh_light_ctl_set { + bool op_en; /* Indicate whether optional parameters included */ + u16_t ctl_lightness; /* Target value of light ctl lightness state */ + u16_t ctl_temperature; /* Target value of light ctl temperature state */ + s16_t ctl_delta_uv; /* Target value of light ctl delta UV state */ + u8_t tid; /* Transaction Identifier */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_light_ctl_temperature_set { + bool op_en; /* Indicate whether optional parameters included */ + u16_t ctl_temperature; /* Target value of light ctl temperature state */ + s16_t ctl_delta_uv; /* Target value of light ctl delta UV state */ + u8_t tid; /* Transaction Identifier */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_light_ctl_temperature_range_set { + u16_t range_min; /* Value of temperature range min field of light ctl temperature range state */ + u16_t range_max; /* Value of temperature range max field of light ctl temperature range state */ +}; + +struct bt_mesh_light_ctl_default_set { + u16_t lightness; /* Value of light lightness default state */ + u16_t temperature; /* Value of light temperature default state */ + s16_t delta_uv; /* Value of light delta UV default state */ +}; + +/* Light HSL Client Model Context */ +extern const struct bt_mesh_model_op light_hsl_cli_op[]; + +/** @def BLE_MESH_MODEL_LIGHT_HSL_CLI + * + * Define a new light HSL client model. Note that this API needs + * to be repeated for each element which the application wants to + * have a light HSL client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_light_hsl_cli. + * + * @return New light HSL client model instance. + */ +#define BLE_MESH_MODEL_LIGHT_HSL_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_LIGHT_HSL_CLI, \ + light_hsl_cli_op, cli_pub, cli_data) + +typedef bt_mesh_client_common_t bt_mesh_light_hsl_cli_t; + +struct bt_mesh_light_hsl_status { + bool op_en; /* Indicate whether optional parameters included */ + u16_t hsl_lightness; /* Present value of light hsl lightness state */ + u16_t hsl_hue; /* Present value of light hsl hue state */ + u16_t hsl_saturation; /* Present value of light hsl saturation state */ + u8_t remain_time; /* Time to complete state transition (optional) */ +}; + +struct bt_mesh_light_hsl_target_status { + bool op_en; /* Indicate whether optional parameters included */ + u16_t hsl_lightness_target; /* Target value of light hsl lightness state */ + u16_t hsl_hue_target; /* Target value of light hsl hue state */ + u16_t hsl_saturation_target; /* Target value of light hsl saturation state */ + u8_t remain_time; /* Time to complete state transition (optional) */ +}; + +struct bt_mesh_light_hsl_hue_status { + bool op_en; /* Indicate whether optional parameters included */ + u16_t present_hue; /* Present value of light hsl hue state */ + u16_t target_hue; /* Target value of light hsl hue state (optional) */ + u8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_light_hsl_saturation_status { + bool op_en; /* Indicate whether optional parameters included */ + u16_t present_saturation; /* Present value of light hsl saturation state */ + u16_t target_saturation; /* Target value of light hsl saturation state (optional) */ + u8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_light_hsl_default_status { + u16_t lightness; /* Value of light lightness default state */ + u16_t hue; /* Value of light hue default state */ + u16_t saturation; /* Value of light saturation default state */ +}; + +struct bt_mesh_light_hsl_range_status { + u8_t status_code; /* Status code for the requesting message */ + u16_t hue_range_min; /* Value of hue range min field of light hsl hue range state */ + u16_t hue_range_max; /* Value of hue range max field of light hsl hue range state */ + u16_t saturation_range_min; /* Value of saturation range min field of light hsl saturation range state */ + u16_t saturation_range_max; /* Value of saturation range max field of light hsl saturation range state */ +}; + +struct bt_mesh_light_hsl_set { + bool op_en; /* Indicate whether optional parameters included */ + u16_t hsl_lightness; /* Target value of light hsl lightness state */ + u16_t hsl_hue; /* Target value of light hsl hue state */ + u16_t hsl_saturation; /* Target value of light hsl saturation state */ + u8_t tid; /* Transaction Identifier */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_light_hsl_hue_set { + bool op_en; /* Indicate whether optional parameters included */ + u16_t hue; /* Target value of light hsl hue state */ + u8_t tid; /* Transaction Identifier */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_light_hsl_saturation_set { + bool op_en; /* Indicate whether optional parameters included */ + u16_t saturation; /* Target value of light hsl hue state */ + u8_t tid; /* Transaction Identifier */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_light_hsl_default_set { + u16_t lightness; /* Value of light lightness default state */ + u16_t hue; /* Value of light hue default state */ + u16_t saturation; /* Value of light saturation default state */ +}; + +struct bt_mesh_light_hsl_range_set { + u16_t hue_range_min; /* Value of hue range min field of light hsl hue range state */ + u16_t hue_range_max; /* Value of hue range max field of light hsl hue range state */ + u16_t saturation_range_min; /* Value of saturation range min field of light hsl saturation range state */ + u16_t saturation_range_max; /* Value of saturation range max field of light hsl saturation range state */ +}; + +/* Light xyL Client Model Context */ +extern const struct bt_mesh_model_op light_xyl_cli_op[]; + +/** @def BLE_MESH_MODEL_LIGHT_XYL_CLI + * + * Define a new light xyL client model. Note that this API needs + * to be repeated for each element which the application wants + * to have a light xyL client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_light_xyl_cli. + * + * @return New light xyL client model instance. + */ +#define BLE_MESH_MODEL_LIGHT_XYL_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_LIGHT_XYL_CLI, \ + light_xyl_cli_op, cli_pub, cli_data) + +typedef bt_mesh_client_common_t bt_mesh_light_xyl_cli_t; + +struct bt_mesh_light_xyl_status { + bool op_en; /* Indicate whether optional parameters included */ + u16_t xyl_lightness; /* The present value of the Light xyL Lightness state */ + u16_t xyl_x; /* The present value of the Light xyL x state */ + u16_t xyl_y; /* The present value of the Light xyL y state */ + u8_t remain_time; /* Time to complete state transition (optional) */ +}; + +struct bt_mesh_light_xyl_target_status { + bool op_en; /* Indicate whether optional parameters included */ + u16_t target_xyl_lightness; /* The target value of the Light xyL Lightness state */ + u16_t target_xyl_x; /* The target value of the Light xyL x state */ + u16_t target_xyl_y; /* The target value of the Light xyL y state */ + u8_t remain_time; /* Time to complete state transition (optional) */ +}; + +struct bt_mesh_light_xyl_default_status { + u16_t lightness; /* The value of the Light Lightness Default state */ + u16_t xyl_x; /* The value of the Light xyL x Default state */ + u16_t xyl_y; /* The value of the Light xyL y Default state */ +}; + +struct bt_mesh_light_xyl_range_status { + u8_t status_code; /* Status Code for the requesting message */ + u16_t xyl_x_range_min; /* The value of the xyL x Range Min field of the Light xyL x Range state */ + u16_t xyl_x_range_max; /* The value of the xyL x Range Max field of the Light xyL x Range state */ + u16_t xyl_y_range_min; /* The value of the xyL y Range Min field of the Light xyL y Range state */ + u16_t xyl_y_range_max; /* The value of the xyL y Range Max field of the Light xyL y Range state */ +}; + +struct bt_mesh_light_xyl_set { + bool op_en; /* Indicate whether optional parameters included */ + u16_t xyl_lightness; /* The target value of the Light xyL Lightness state */ + u16_t xyl_x; /* The target value of the Light xyL x state */ + u16_t xyl_y; /* The target value of the Light xyL y state */ + u8_t tid; /* Transaction Identifier */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_light_xyl_default_set { + u16_t lightness; /* The value of the Light Lightness Default state */ + u16_t xyl_x; /* The value of the Light xyL x Default state */ + u16_t xyl_y; /* The value of the Light xyL y Default state */ +}; + +struct bt_mesh_light_xyl_range_set { + u16_t xyl_x_range_min; /* The value of the xyL x Range Min field of the Light xyL x Range state */ + u16_t xyl_x_range_max; /* The value of the xyL x Range Max field of the Light xyL x Range state */ + u16_t xyl_y_range_min; /* The value of the xyL y Range Min field of the Light xyL y Range state */ + u16_t xyl_y_range_max; /* The value of the xyL y Range Max field of the Light xyL y Range state */ +}; + +/* Light LC Client Model Context */ +extern const struct bt_mesh_model_op light_lc_cli_op[]; + +/** @def BLE_MESH_MODEL_LIGHT_LC_CLI + * + * Define a new light lc client model. Note that this API needs + * to be repeated for each element which the application wants + * to have a light lc client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_light_lc_cli. + * + * @return New light lc client model instance. + */ +#define BLE_MESH_MODEL_LIGHT_LC_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_LIGHT_LC_CLI, \ + light_lc_cli_op, cli_pub, cli_data) + +typedef bt_mesh_client_common_t bt_mesh_light_lc_cli_t; + +struct bt_mesh_light_lc_mode_status { + u8_t mode; /* The present value of the Light LC Mode state */ +}; + +struct bt_mesh_light_lc_om_status { + u8_t mode; /* The present value of the Light LC Occupancy Mode state */ +}; + +struct bt_mesh_light_lc_light_onoff_status { + bool op_en; /* Indicate whether optional parameters included */ + u8_t present_light_onoff; /* The present value of the Light LC Light OnOff state */ + u8_t target_light_onoff; /* The target value of the Light LC Light OnOff state (Optional) */ + u8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_light_lc_property_status { + u16_t light_lc_property_id; /* Property ID identifying a Light LC Property */ + struct net_buf_simple *light_lc_property_value; /* Raw value for the Light LC Property */ +}; + +struct bt_mesh_light_lc_mode_set { + u8_t mode; /* The target value of the Light LC Mode state */ +}; + +struct bt_mesh_light_lc_om_set { + u8_t mode; /* The target value of the Light LC Occupancy Mode state */ +}; + +struct bt_mesh_light_lc_light_onoff_set { + bool op_en; /* Indicate whether optional parameters included */ + u8_t light_onoff; /* The target value of the Light LC Light OnOff state */ + u8_t tid; /* Transaction Identifier */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_light_lc_property_get { + u16_t light_lc_property_id; /* Property ID identifying a Light LC Property */ +}; + +struct bt_mesh_light_lc_property_set { + u16_t light_lc_property_id; /* Property ID identifying a Light LC Property */ + struct net_buf_simple *light_lc_property_value; /* Raw value for the Light LC Property */ +}; + +/** + * @brief This function is called to initialize light lightness client model user_data. + * + * @param[in] model: Pointer to light lightness client model + * @param[in] primary: Whether belongs to primary element + * + * @return Zero-success, other-fail + */ +int bt_mesh_light_lightness_cli_init(struct bt_mesh_model *model, bool primary); + +/** + * @brief This function is called to initialize light ctl client model user_data. + * + * @param[in] model: Pointer to light ctl client model + * @param[in] primary: Whether belongs to primary element + * + * @return Zero-success, other-fail + */ +int bt_mesh_light_ctl_cli_init(struct bt_mesh_model *model, bool primary); + +/** + * @brief This function is called to initialize light hsl client model user_data. + * + * @param[in] model: Pointer to light hsl client model + * @param[in] primary: Whether belongs to primary element + * + * @return Zero-success, other-fail + */ +int bt_mesh_light_hsl_cli_init(struct bt_mesh_model *model, bool primary); + +/** + * @brief This function is called to initialize light xyl client model user_data. + * + * @param[in] model: Pointer to light xyl client model + * @param[in] primary: Whether belongs to primary element + * + * @return Zero-success, other-fail + */ +int bt_mesh_light_xyl_cli_init(struct bt_mesh_model *model, bool primary); + +/** + * @brief This function is called to initialize light lc client model user_data. + * + * @param[in] model: Pointer to light lc client model + * @param[in] primary: Whether belongs to primary element + * + * @return Zero-success, other-fail + */ +int bt_mesh_light_lc_cli_init(struct bt_mesh_model *model, bool primary); + +/** + * @brief This function is called to get light states. + * + * @param[in] common: Message common information structure + * @param[in] get: Pointer of light get message value + * @param[out] status: Pointer of light status message value + * + * @return Zero-success, other-fail + */ +int bt_mesh_light_client_get_state(struct bt_mesh_common_param *common, void *get, void *status); + +/** + * @brief This function is called to set light states. + * + * @param[in] common: Message common information structure + * @param[in] set: Pointer of light set message value + * @param[out] status: Pointer of light status message value + * + * @return Zero-success, other-fail + */ +int bt_mesh_light_client_set_state(struct bt_mesh_common_param *common, void *set, void *status); + +#endif /* _LIGHTING_CLIENT_H_ */ diff --git a/components/bt/ble_mesh/mesh_models/include/mesh_common.h b/components/bt/ble_mesh/mesh_models/include/mesh_common.h new file mode 100644 index 0000000000..2a116be01e --- /dev/null +++ b/components/bt/ble_mesh/mesh_models/include/mesh_common.h @@ -0,0 +1,46 @@ +// Copyright 2017-2018 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. + +/** @file + * @brief Bluetooth Mesh Model Common APIs. + */ + +#ifndef _MESH_COMMON_H_ +#define _MESH_COMMON_H_ + +#include "osi/allocator.h" + +#include "mesh_types.h" +#include "mesh_buf.h" +#include "mesh_trace.h" + +/** + * @brief This function allocates memory to store outgoing message. + * + * @param[in] size: Length of memory allocated to store message value + * + * @return NULL-fail, pointer of a net_buf_simple structure-success + */ +struct net_buf_simple *bt_mesh_alloc_buf(u16_t size); + +/** + * @brief This function releases the memory allocated for the outgoing message. + * + * @param[in] buf: Pointer to the net_buf_simple structure to be freed + * + * @return none + */ +void bt_mesh_free_buf(struct net_buf_simple *buf); + +#endif /* _MESH_COMMON_H_ */ \ No newline at end of file diff --git a/components/bt/ble_mesh/mesh_models/include/model_common.h b/components/bt/ble_mesh/mesh_models/include/model_common.h new file mode 100644 index 0000000000..fd9cc6dfda --- /dev/null +++ b/components/bt/ble_mesh/mesh_models/include/model_common.h @@ -0,0 +1,133 @@ +// Copyright 2017-2018 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. + +#ifndef _MODEL_COMMON_H_ +#define _MODEL_COMMON_H_ + +#include "mesh_access.h" + +/** Mesh Client Model Context */ +typedef struct { + u32_t cli_op; /* The client opcode */ + u32_t status_op; /* The server status opcode corresponding to the client opcode */ +} bt_mesh_client_op_pair_t; + +/** Mesh Client Model Context */ +typedef struct { + struct bt_mesh_model *model; + int op_pair_size; /* the size of op_pair */ + const bt_mesh_client_op_pair_t *op_pair; + /** + * @brief This function is a callback function used to push the received unsolicited + * messages to the application layer. + * + * @param[in] opcode: Opcode of received status message + * @param[in] model: Model associated with the status message + * @param[in] ctx: Context information of the status message + * @param[in] buf: Buffer contains the status message value + * + * @return None + */ + void (*publish_status)(u32_t opcode, struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); + void *internal_data; /* Pointer of the structure of internal data */ + u8_t msg_role; /* device role of the tx message */ +} bt_mesh_client_common_t; + +typedef struct { + sys_slist_t queue; +} bt_mesh_internal_data_t; + +typedef struct { + sys_snode_t client_node; + struct bt_mesh_msg_ctx ctx; + u32_t opcode; /* Indicate the opcode of the message sending */ + u32_t op_pending; /* Indicate the status message waiting for */ + struct k_delayed_work timer; /* Message send Timer. Only for stack-internal use. */ +} bt_mesh_client_node_t; + +int bt_mesh_client_init(struct bt_mesh_model *model); + +/** + * @brief Check the msg is a publish msg or not + * + * @param model Mesh (client) Model that the message belongs to. + * @param ctx Message context, includes keys, TTL, etc. + * @param buf The message buffer + * @param need_pub Indicate if the msg sent to app layer as a publish msg + * @return 0 on success, or (negative) error code on failure. + */ +bt_mesh_client_node_t *bt_mesh_is_model_message_publish(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf, + bool need_pub); + +bool bt_mesh_client_find_opcode_in_list(sys_slist_t *list, u32_t opcode); + +bool bt_mesh_client_check_node_in_list(sys_slist_t *list, uint16_t tx_dst); + +bt_mesh_client_node_t *bt_mesh_client_pick_node(sys_slist_t *list, u16_t tx_dst); + +int bt_mesh_client_send_msg(struct bt_mesh_model *model, + u32_t opcode, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *msg, + k_work_handler_t timer_handler, + s32_t timeout, bool need_ack, + const struct bt_mesh_send_cb *cb, void *cb_data); + +int bt_mesh_client_free_node(sys_slist_t *queue, bt_mesh_client_node_t *node); + +enum { + NODE = 0, + PROVISIONER, + FAST_PROV, +}; + +#define ROLE_NVAL 0xFF + +struct bt_mesh_common_param { + u32_t opcode; /* Message opcode */ + struct bt_mesh_model *model; /* Pointer to cli structure */ + struct bt_mesh_msg_ctx ctx; /* Message context */ + s32_t msg_timeout; /* Time to get response messages */ + const struct bt_mesh_send_cb *cb; /* User defined callback function */ + void *cb_data; /* Data as parameter of the cb function */ +}; + +typedef struct bt_mesh_role_param { + struct bt_mesh_model *model; /* The client model structure */ + u8_t role; /* Role of the device - Node/Provisioner */ +} bt_mesh_role_param_t; + +/** + * @brief This function copies node_index for stack internal use. + * + * @param[in] common: Pointer to the struct bt_mesh_role_param structure + * + * @return Zero - success, otherwise - fail + */ +int bt_mesh_set_model_role(bt_mesh_role_param_t *common); + +/** + * @brief This function gets msg role for stack internal use. + * + * @param[in] model: Pointer to the model structure + * @param[in] srv_send: Indicate if the message is sent by a server model + * + * @return 0 - Node, 1 - Provisioner + */ +u8_t bt_mesh_get_model_role(struct bt_mesh_model *model, bool srv_send); + +#endif /* _MODEL_COMMON_H_ */ + diff --git a/components/bt/ble_mesh/mesh_models/include/model_opcode.h b/components/bt/ble_mesh/mesh_models/include/model_opcode.h new file mode 100644 index 0000000000..01929d5cfe --- /dev/null +++ b/components/bt/ble_mesh/mesh_models/include/model_opcode.h @@ -0,0 +1,276 @@ +// Copyright 2017-2018 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. + +#ifndef _MODEL_OPCODE_H_ +#define _MODEL_OPCODE_H_ + +#include "mesh_main.h" + +/* Generic OnOff Message Opcode */ +#define BLE_MESH_MODEL_OP_GEN_ONOFF_GET BLE_MESH_MODEL_OP_2(0x82, 0x01) +#define BLE_MESH_MODEL_OP_GEN_ONOFF_SET BLE_MESH_MODEL_OP_2(0x82, 0x02) +#define BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x03) +#define BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x04) + +/* Generic Level Message Opcode */ +#define BLE_MESH_MODEL_OP_GEN_LEVEL_GET BLE_MESH_MODEL_OP_2(0x82, 0x05) +#define BLE_MESH_MODEL_OP_GEN_LEVEL_SET BLE_MESH_MODEL_OP_2(0x82, 0x06) +#define BLE_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x07) +#define BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x08) +#define BLE_MESH_MODEL_OP_GEN_DELTA_SET BLE_MESH_MODEL_OP_2(0x82, 0x09) +#define BLE_MESH_MODEL_OP_GEN_DELTA_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x0A) +#define BLE_MESH_MODEL_OP_GEN_MOVE_SET BLE_MESH_MODEL_OP_2(0x82, 0x0B) +#define BLE_MESH_MODEL_OP_GEN_MOVE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x0C) + +/* Generic Default Transition Time Message Opcode*/ +#define BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_GET BLE_MESH_MODEL_OP_2(0x82, 0x0D) +#define BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET BLE_MESH_MODEL_OP_2(0x82, 0x0E) +#define BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x0F) +#define BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x10) + +/* Generic Power OnOff Message Opcode*/ +#define BLE_MESH_MODEL_OP_GEN_ONPOWERUP_GET BLE_MESH_MODEL_OP_2(0x82, 0x11) +#define BLE_MESH_MODEL_OP_GEN_ONPOWERUP_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x12) + +/* Generic Power OnOff Setup Message Opcode */ +#define BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET BLE_MESH_MODEL_OP_2(0x82, 0x13) +#define BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x14) + +/* Generic Power Level Message Opcode */ +#define BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_GET BLE_MESH_MODEL_OP_2(0x82, 0x15) +#define BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET BLE_MESH_MODEL_OP_2(0x82, 0x16) +#define BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x17) +#define BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x18) +#define BLE_MESH_MODEL_OP_GEN_POWER_LAST_GET BLE_MESH_MODEL_OP_2(0x82, 0x19) +#define BLE_MESH_MODEL_OP_GEN_POWER_LAST_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x1A) +#define BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_GET BLE_MESH_MODEL_OP_2(0x82, 0x1B) +#define BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x1C) +#define BLE_MESH_MODEL_OP_GEN_POWER_RANGE_GET BLE_MESH_MODEL_OP_2(0x82, 0x1D) +#define BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x1E) + +/* Generic Power Level Setup Message Opcode */ +#define BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET BLE_MESH_MODEL_OP_2(0x82, 0x1F) +#define BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x20) +#define BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET BLE_MESH_MODEL_OP_2(0x82, 0x21) +#define BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x22) + +/* Generic Battery Message Opcode */ +#define BLE_MESH_MODEL_OP_GEN_BATTERY_GET BLE_MESH_MODEL_OP_2(0x82, 0x23) +#define BLE_MESH_MODEL_OP_GEN_BATTERY_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x24) + +/* Generic Location Message Opcode */ +#define BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_GET BLE_MESH_MODEL_OP_2(0x82, 0x25) +#define BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_STATUS BLE_MESH_MODEL_OP_1(0x40) +#define BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_GET BLE_MESH_MODEL_OP_2(0x82, 0x26) +#define BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x27) + +/* Generic Location Setup Message Opcode */ +#define BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET BLE_MESH_MODEL_OP_1(0x41) +#define BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET_UNACK BLE_MESH_MODEL_OP_1(0x42) +#define BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET BLE_MESH_MODEL_OP_2(0x82, 0x28) +#define BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x29) + +/* Generic Manufacturer Property Message Opcode */ +#define BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_GET BLE_MESH_MODEL_OP_2(0x82, 0x2A) +#define BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_STATUS BLE_MESH_MODEL_OP_1(0x43) +#define BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_GET BLE_MESH_MODEL_OP_2(0x82, 0x2B) +#define BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET BLE_MESH_MODEL_OP_1(0x44) +#define BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET_UNACK BLE_MESH_MODEL_OP_1(0x45) +#define BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_STATUS BLE_MESH_MODEL_OP_1(0x46) + +/* Generic Admin Property Message Opcode */ +#define BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_GET BLE_MESH_MODEL_OP_2(0x82, 0x2C) +#define BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_STATUS BLE_MESH_MODEL_OP_1(0x47) +#define BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET BLE_MESH_MODEL_OP_2(0x82, 0x2D) +#define BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET BLE_MESH_MODEL_OP_1(0x48) +#define BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET_UNACK BLE_MESH_MODEL_OP_1(0x49) +#define BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_STATUS BLE_MESH_MODEL_OP_1(0x4A) + +/* Generic User Property Message Opcode */ +#define BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_GET BLE_MESH_MODEL_OP_2(0x82, 0x2E) +#define BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS BLE_MESH_MODEL_OP_1(0x4B) +#define BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET BLE_MESH_MODEL_OP_2(0x82, 0x2F) +#define BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET BLE_MESH_MODEL_OP_1(0x4C) +#define BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET_UNACK BLE_MESH_MODEL_OP_1(0x4D) +#define BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_STATUS BLE_MESH_MODEL_OP_1(0x4E) + +/* Generic Client Property Message Opcode */ +#define BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_GET BLE_MESH_MODEL_OP_1(0x4F) +#define BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS BLE_MESH_MODEL_OP_1(0x50) + +/* Sensor Message Opcode */ +#define BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET BLE_MESH_MODEL_OP_2(0x82, 0x30) +#define BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS BLE_MESH_MODEL_OP_1(0x51) +#define BLE_MESH_MODEL_OP_SENSOR_GET BLE_MESH_MODEL_OP_2(0x82, 0x31) +#define BLE_MESH_MODEL_OP_SENSOR_STATUS BLE_MESH_MODEL_OP_1(0x52) +#define BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET BLE_MESH_MODEL_OP_2(0x82, 0x32) +#define BLE_MESH_MODEL_OP_SENSOR_COLUMN_STATUS BLE_MESH_MODEL_OP_1(0x53) +#define BLE_MESH_MODEL_OP_SENSOR_SERIES_GET BLE_MESH_MODEL_OP_2(0x82, 0x33) +#define BLE_MESH_MODEL_OP_SENSOR_SERIES_STATUS BLE_MESH_MODEL_OP_1(0x54) + +/* Sensor Setup Message Opcode */ +#define BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET BLE_MESH_MODEL_OP_2(0x82, 0x34) +#define BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET BLE_MESH_MODEL_OP_1(0x55) +#define BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK BLE_MESH_MODEL_OP_1(0x56) +#define BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS BLE_MESH_MODEL_OP_1(0x57) +#define BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET BLE_MESH_MODEL_OP_2(0x82, 0x35) +#define BLE_MESH_MODEL_OP_SENSOR_SETTINGS_STATUS BLE_MESH_MODEL_OP_1(0x58) +#define BLE_MESH_MODEL_OP_SENSOR_SETTING_GET BLE_MESH_MODEL_OP_2(0x82, 0x36) +#define BLE_MESH_MODEL_OP_SENSOR_SETTING_SET BLE_MESH_MODEL_OP_1(0x59) +#define BLE_MESH_MODEL_OP_SENSOR_SETTING_SET_UNACK BLE_MESH_MODEL_OP_1(0x5A) +#define BLE_MESH_MODEL_OP_SENSOR_SETTING_STATUS BLE_MESH_MODEL_OP_1(0x5B) + +/* Time Message Opcode */ +#define BLE_MESH_MODEL_OP_TIME_GET BLE_MESH_MODEL_OP_2(0x82, 0x37) +#define BLE_MESH_MODEL_OP_TIME_SET BLE_MESH_MODEL_OP_1(0x5C) +#define BLE_MESH_MODEL_OP_TIME_STATUS BLE_MESH_MODEL_OP_1(0x5D) +#define BLE_MESH_MODEL_OP_TIME_ROLE_GET BLE_MESH_MODEL_OP_2(0x82, 0x38) +#define BLE_MESH_MODEL_OP_TIME_ROLE_SET BLE_MESH_MODEL_OP_2(0x82, 0x39) +#define BLE_MESH_MODEL_OP_TIME_ROLE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x3A) +#define BLE_MESH_MODEL_OP_TIME_ZONE_GET BLE_MESH_MODEL_OP_2(0x82, 0x3B) +#define BLE_MESH_MODEL_OP_TIME_ZONE_SET BLE_MESH_MODEL_OP_2(0x82, 0x3C) +#define BLE_MESH_MODEL_OP_TIME_ZONE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x3D) +#define BLE_MESH_MODEL_OP_TAI_UTC_DELTA_GET BLE_MESH_MODEL_OP_2(0x82, 0x3E) +#define BLE_MESH_MODEL_OP_TAI_UTC_DELTA_SET BLE_MESH_MODEL_OP_2(0x82, 0x3F) +#define BLE_MESH_MODEL_OP_TAI_UTC_DELTA_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x40) + +/* Scene Message Opcode */ +#define BLE_MESH_MODEL_OP_SCENE_GET BLE_MESH_MODEL_OP_2(0x82, 0x41) +#define BLE_MESH_MODEL_OP_SCENE_RECALL BLE_MESH_MODEL_OP_2(0x82, 0x42) +#define BLE_MESH_MODEL_OP_SCENE_RECALL_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x43) +#define BLE_MESH_MODEL_OP_SCENE_STATUS BLE_MESH_MODEL_OP_1(0x5E) +#define BLE_MESH_MODEL_OP_SCENE_REGISTER_GET BLE_MESH_MODEL_OP_2(0x82, 0x44) +#define BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x45) + +/* Scene Setup Message Opcode */ +#define BLE_MESH_MODEL_OP_SCENE_STORE BLE_MESH_MODEL_OP_2(0x82, 0x46) +#define BLE_MESH_MODEL_OP_SCENE_STORE_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x47) +#define BLE_MESH_MODEL_OP_SCENE_DELETE BLE_MESH_MODEL_OP_2(0x82, 0x9E) +#define BLE_MESH_MODEL_OP_SCENE_DELETE_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x9F) + +/* Scheduler Message Opcode */ +#define BLE_MESH_MODEL_OP_SCHEDULER_ACT_GET BLE_MESH_MODEL_OP_2(0x82, 0x48) +#define BLE_MESH_MODEL_OP_SCHEDULER_ACT_STATUS BLE_MESH_MODEL_OP_1(0x5F) +#define BLE_MESH_MODEL_OP_SCHEDULER_GET BLE_MESH_MODEL_OP_2(0x82, 0x49) +#define BLE_MESH_MODEL_OP_SCHEDULER_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x4A) + +/* Scheduler Setup Message Opcode */ +#define BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET BLE_MESH_MODEL_OP_1(0x60) +#define BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET_UNACK BLE_MESH_MODEL_OP_1(0x61) + +/* Light Lightness Message Opcode */ +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_GET BLE_MESH_MODEL_OP_2(0x82, 0x4B) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET BLE_MESH_MODEL_OP_2(0x82, 0x4C) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x4D) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x4E) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_GET BLE_MESH_MODEL_OP_2(0x82, 0x4F) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET BLE_MESH_MODEL_OP_2(0x82, 0x50) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x51) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x52) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_GET BLE_MESH_MODEL_OP_2(0x82, 0x53) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x54) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_GET BLE_MESH_MODEL_OP_2(0x82, 0x55) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x56) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_GET BLE_MESH_MODEL_OP_2(0x82, 0x57) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x58) + +/* Light Lightness Setup Message Opcode */ +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET BLE_MESH_MODEL_OP_2(0x82, 0x59) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x5A) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET BLE_MESH_MODEL_OP_2(0x82, 0x5B) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x5C) + +/* Light CTL Message Opcode */ +#define BLE_MESH_MODEL_OP_LIGHT_CTL_GET BLE_MESH_MODEL_OP_2(0x82, 0x5D) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_SET BLE_MESH_MODEL_OP_2(0x82, 0x5E) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x5F) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x60) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_GET BLE_MESH_MODEL_OP_2(0x82, 0x61) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_GET BLE_MESH_MODEL_OP_2(0x82, 0x62) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x63) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET BLE_MESH_MODEL_OP_2(0x82, 0x64) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x65) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x66) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_GET BLE_MESH_MODEL_OP_2(0x82, 0x67) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x68) + +/* Light CTL Setup Message Opcode */ +#define BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET BLE_MESH_MODEL_OP_2(0x82, 0x69) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x6A) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET BLE_MESH_MODEL_OP_2(0x82, 0x6B) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x6C) + +/* Light HSL Message Opcode */ +#define BLE_MESH_MODEL_OP_LIGHT_HSL_GET BLE_MESH_MODEL_OP_2(0x82, 0x6D) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_GET BLE_MESH_MODEL_OP_2(0x82, 0x6E) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET BLE_MESH_MODEL_OP_2(0x82, 0x6F) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x70) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x71) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_GET BLE_MESH_MODEL_OP_2(0x82, 0x72) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET BLE_MESH_MODEL_OP_2(0x82, 0x73) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x74) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x75) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_SET BLE_MESH_MODEL_OP_2(0x82, 0x76) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x77) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x78) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_GET BLE_MESH_MODEL_OP_2(0x82, 0x79) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x7A) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_GET BLE_MESH_MODEL_OP_2(0x82, 0x7B) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x7C) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_GET BLE_MESH_MODEL_OP_2(0x82, 0x7D) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x7E) + +/* Light HSL Setup Message Opcode */ +#define BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET BLE_MESH_MODEL_OP_2(0x82, 0x7F) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x80) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET BLE_MESH_MODEL_OP_2(0x82, 0x81) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x82) /* Model spec is wrong */ + +/* Light xyL Message Opcode */ +#define BLE_MESH_MODEL_OP_LIGHT_XYL_GET BLE_MESH_MODEL_OP_2(0x82, 0x83) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_SET BLE_MESH_MODEL_OP_2(0x82, 0x84) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x85) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x86) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_GET BLE_MESH_MODEL_OP_2(0x82, 0x87) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x88) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_GET BLE_MESH_MODEL_OP_2(0x82, 0x89) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x8A) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_GET BLE_MESH_MODEL_OP_2(0x82, 0x8B) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x8C) + +/* Light xyL Setup Message Opcode */ +#define BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET BLE_MESH_MODEL_OP_2(0x82, 0x8D) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x8E) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET BLE_MESH_MODEL_OP_2(0x82, 0x8F) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x90) + +/* Light Control Message Opcode */ +#define BLE_MESH_MODEL_OP_LIGHT_LC_MODE_GET BLE_MESH_MODEL_OP_2(0x82, 0x91) +#define BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET BLE_MESH_MODEL_OP_2(0x82, 0x92) +#define BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x93) +#define BLE_MESH_MODEL_OP_LIGHT_LC_MODE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x94) +#define BLE_MESH_MODEL_OP_LIGHT_LC_OM_GET BLE_MESH_MODEL_OP_2(0x82, 0x95) +#define BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET BLE_MESH_MODEL_OP_2(0x82, 0x96) +#define BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x97) +#define BLE_MESH_MODEL_OP_LIGHT_LC_OM_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x98) +#define BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_GET BLE_MESH_MODEL_OP_2(0x82, 0x99) +#define BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET BLE_MESH_MODEL_OP_2(0x82, 0x9A) +#define BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x9B) +#define BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x9C) +#define BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_GET BLE_MESH_MODEL_OP_2(0x82, 0x9D) +#define BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET BLE_MESH_MODEL_OP_1(0x62) +#define BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET_UNACK BLE_MESH_MODEL_OP_1(0x63) +#define BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS BLE_MESH_MODEL_OP_1(0x64) + +#endif /* _MODEL_OPCODE_H_ */ diff --git a/components/bt/ble_mesh/mesh_models/include/sensor_client.h b/components/bt/ble_mesh/mesh_models/include/sensor_client.h new file mode 100644 index 0000000000..2b259a8953 --- /dev/null +++ b/components/bt/ble_mesh/mesh_models/include/sensor_client.h @@ -0,0 +1,167 @@ +// Copyright 2017-2018 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. + +/** @file + * @brief Bluetooth Mesh Sensor Client Model APIs. + */ + +#ifndef _SENSOR_CLIENT_H_ +#define _SENSOR_CLIENT_H_ + +#include "mesh_access.h" +#include "mesh_kernel.h" + +#include "model_common.h" + +/* Sensor Client Model Context */ +extern const struct bt_mesh_model_op sensor_cli_op[]; + +/** @def BLE_MESH_MODEL_SENSOR_CLI + * + * Define a new sensor client model. Note that this API needs to + * be repeated for each element which the application wants to + * have a sensor client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_sensor_cli. + * + * @return New sensor client model instance. + */ +#define BLE_MESH_MODEL_SENSOR_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_SENSOR_CLI, \ + sensor_cli_op, cli_pub, cli_data) + +typedef bt_mesh_client_common_t bt_mesh_sensor_client_t; +typedef bt_mesh_internal_data_t sensor_internal_data_t; + +struct bt_mesh_sensor_descriptor_status { + struct net_buf_simple *descriptor; /* Sequence of 8-octet sensor descriptors (optional) */ +}; + +struct bt_mesh_sensor_cadence_status { + u16_t property_id; /* Property for the sensor */ + struct net_buf_simple *sensor_cadence_value; /* Value of sensor cadence state */ +}; + +struct bt_mesh_sensor_settings_status { + u16_t sensor_property_id; /* Property ID identifying a sensor */ + struct net_buf_simple *sensor_setting_property_ids; /* A sequence of N sensor setting property IDs (optional) */ +}; + +struct bt_mesh_sensor_setting_status { + bool op_en; /* Indicate whether optional parameters included */ + u16_t sensor_property_id; /* Property ID identifying a sensor */ + u16_t sensor_setting_property_id; /* Setting ID identifying a setting within a sensor */ + u8_t sensor_setting_access; /* Read/Write access rights for the setting (optional) */ + struct net_buf_simple *sensor_setting_raw; /* Raw value for the setting */ +}; + +struct bt_mesh_sensor_status { + struct net_buf_simple *marshalled_sensor_data; /* Value of sensor data state (optional) */ +}; + +struct bt_mesh_sensor_column_status { + u16_t property_id; /* Property identifying a sensor and the Y axis */ + struct net_buf_simple *sensor_column_value; /* Left values of sensor column status */ +}; + +struct bt_mesh_sensor_series_status { + u16_t property_id; /* Property identifying a sensor and the Y axis */ + struct net_buf_simple *sensor_series_value; /* Left values of sensor series status */ +}; + +struct bt_mesh_sensor_descriptor_get { + bool op_en; /* Indicate whether optional parameters included */ + u16_t property_id; /* Property ID for the sensor (optional) */ +}; + +struct bt_mesh_sensor_cadence_get { + u16_t property_id; /* Property ID for the sensor */ +}; + +struct bt_mesh_sensor_cadence_set { + u16_t property_id; /* Property ID for the sensor */ + u8_t fast_cadence_period_divisor : 7, /* Divisor for the publish period */ + status_trigger_type : 1; /* The unit and format of the Status Trigger Delta fields */ + struct net_buf_simple *status_trigger_delta_down; /* Delta down value that triggers a status message */ + struct net_buf_simple *status_trigger_delta_up; /* Delta up value that triggers a status message */ + u8_t status_min_interval; /* Minimum interval between two consecutive Status messages */ + struct net_buf_simple *fast_cadence_low; /* Low value for the fast cadence range */ + struct net_buf_simple *fast_cadence_high; /* Fast value for the fast cadence range */ +}; + +struct bt_mesh_sensor_settings_get { + u16_t sensor_property_id; /* Property ID for the sensor */ +}; + +struct bt_mesh_sensor_setting_get { + u16_t sensor_property_id; /* Property ID identifying a sensor */ + u16_t sensor_setting_property_id; /* Setting ID identifying a setting within a sensor */ +}; + +struct bt_mesh_sensor_setting_set { + u16_t sensor_property_id; /* Property ID identifying a sensor */ + u16_t sensor_setting_property_id; /* Setting ID identifying a setting within a sensor */ + struct net_buf_simple *sensor_setting_raw; /* Raw value for the setting */ +}; + +struct bt_mesh_sensor_get { + bool op_en; /* Indicate whether optional parameters included */ + u16_t property_id; /* Property ID for the sensor (optional) */ +}; + +struct bt_mesh_sensor_column_get { + u16_t property_id; /* Property identifying a sensor */ + struct net_buf_simple *raw_value_x; /* Raw value identifying a column */ +}; + +struct bt_mesh_sensor_series_get { + bool op_en; /* Indicate whether optional parameters included */ + u16_t property_id; /* Property identifying a sensor */ + struct net_buf_simple *raw_value_x1; /* Raw value identifying a starting column (optional) */ + struct net_buf_simple *raw_value_x2; /* Raw value identifying a ending column (C.1) */ +}; + +/** + * @brief This function is called to initialize sensor client model user_data. + * + * @param[in] model: Pointer to sensor client model + * @param[in] primary: Whether belongs to primary element + * + * @return Zero-success, other-fail + */ +int bt_mesh_sensor_cli_init(struct bt_mesh_model *model, bool primary); + +/** + * @brief This function is called to get sensor states. + * + * @param[in] common: Message common information structure + * @param[in] get: Pointer of sensor get message value + * @param[out] status: Pointer of sensor status message value + * + * @return Zero-success, other-fail + */ +int bt_mesh_sensor_client_get_state(struct bt_mesh_common_param *common, void *get, void *status); + +/** + * @brief This function is called to set sensor states. + * + * @param[in] common: Message common information structure + * @param[in] set: Pointer of sensor set message value + * @param[out] status: Pointer of sensor status message value + * + * @return Zero-success, other-fail + */ +int bt_mesh_sensor_client_set_state(struct bt_mesh_common_param *common, void *set, void *status); + +#endif /* _SENSOR_CLIENT_H_ */ diff --git a/components/bt/ble_mesh/mesh_models/include/time_scene_client.h b/components/bt/ble_mesh/mesh_models/include/time_scene_client.h new file mode 100644 index 0000000000..baa0d4abc0 --- /dev/null +++ b/components/bt/ble_mesh/mesh_models/include/time_scene_client.h @@ -0,0 +1,257 @@ +// Copyright 2017-2018 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. + +/** @file + * @brief Bluetooth Mesh Time and Scene Client Model APIs. + */ + +#ifndef _TIME_SCENE_CLIENT_H_ +#define _TIME_SCENE_CLIENT_H_ + +#include "mesh_access.h" +#include "mesh_kernel.h" + +#include "model_common.h" + +/* Time scene client model common structure */ +typedef bt_mesh_client_common_t bt_mesh_time_scene_client_t; +typedef bt_mesh_internal_data_t time_scene_internal_data_t; + +/* Time Client Model Context */ +extern const struct bt_mesh_model_op time_cli_op[]; + +/** @def BLE_MESH_MODEL_TIME_CLI + * + * Define a new time client model. Note that this API needs to + * be repeated for each element which the application wants to + * have a time model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_time_cli. + * + * @return New time client model instance. + */ +#define BLE_MESH_MODEL_TIME_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_TIME_CLI, \ + time_cli_op, cli_pub, cli_data) + +typedef bt_mesh_client_common_t bt_mesh_time_cli_t; + +struct bt_mesh_time_status { + u8_t tai_seconds[5]; /* The current TAI time in seconds */ + u8_t sub_second; /* The sub-second time in units of 1/256 second */ + u8_t uncertainty; /* The estimated uncertainty in 10-millisecond steps */ + u16_t time_authority : 1; /* 0 = No Time Authority, 1 = Time Authority */ + u16_t tai_utc_delta : 15; /* Current difference between TAI and UTC in seconds */ + u8_t time_zone_offset; /* The local time zone offset in 15-minute increments */ +}; + +struct bt_mesh_time_zone_status { + u8_t time_zone_offset_curr; /* Current local time zone offset */ + u8_t time_zone_offset_new; /* Upcoming local time zone offset */ + u8_t tai_zone_change[5]; /* TAI Seconds time of the upcoming Time Zone Offset change */ +}; + +struct bt_mesh_tai_utc_delta_status { + u16_t tai_utc_delta_curr : 15; /* Current difference between TAI and UTC in seconds */ + u16_t padding_1 : 1; /* Always 0b0. Other values are Prohibited. */ + u16_t tai_utc_delta_new : 15; /* Upcoming difference between TAI and UTC in seconds */ + u16_t padding_2 : 1; /* Always 0b0. Other values are Prohibited. */ + u8_t tai_delta_change[5]; /* TAI Seconds time of the upcoming TAI-UTC Delta change */ +}; + +struct bt_mesh_time_role_status { + u8_t time_role; /* The Time Role for the element */ +}; + +struct bt_mesh_time_set { + u8_t tai_seconds[5]; /* The current TAI time in seconds */ + u8_t sub_second; /* The sub-second time in units of 1/256 second */ + u8_t uncertainty; /* The estimated uncertainty in 10-millisecond steps */ + u16_t time_authority : 1; /* 0 = No Time Authority, 1 = Time Authority */ + u16_t tai_utc_delta : 15; /* Current difference between TAI and UTC in seconds */ + u8_t time_zone_offset; /* The local time zone offset in 15-minute increments */ +}; + +struct bt_mesh_time_zone_set { + u8_t time_zone_offset_new; /* Upcoming local time zone offset */ + u8_t tai_zone_change[5]; /* TAI Seconds time of the upcoming Time Zone Offset change */ +}; + +struct bt_mesh_tai_utc_delta_set { + u16_t tai_utc_delta_new : 15; /* Upcoming difference between TAI and UTC in seconds */ + u16_t padding : 1; /* Always 0b0. Other values are Prohibited. */ + u8_t tai_delta_change[5]; /* TAI Seconds time of the upcoming TAI-UTC Delta change */ +}; + +struct bt_mesh_time_role_set { + u8_t time_role; /* The Time Role for the element */ +}; + +/* Scene Client Model Context */ +extern const struct bt_mesh_model_op scene_cli_op[]; + +/** @def BLE_MESH_MODEL_SCENE_CLI + * + * Define a new scene client model. Note that this API needs to + * be repeated for each element which the application wants to + * have a scene model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_scene_cli. + * + * @return New scene client model instance. + */ +#define BLE_MESH_MODEL_SCENE_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_SCENE_CLI, \ + scene_cli_op, cli_pub, cli_data) + +typedef bt_mesh_client_common_t bt_mesh_scene_cli_t; + +struct bt_mesh_scene_status { + bool op_en; /* Indicate whether optional parameters included */ + u8_t status_code; /* Status code for the last operation */ + u16_t current_scene; /* Scene Number of a current scene */ + u16_t target_scene; /* Scene Number of a target scene (optional) */ + u8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_scene_register_status { + u8_t status_code; /* Status code for the previous operation */ + u16_t current_scene; /* Scene Number of a current scene */ + struct net_buf_simple *scenes; /* A list of scenes stored within an element */ +}; + +struct bt_mesh_scene_store { + u16_t scene_number; /* The number of the scene to be stored */ +}; + +struct bt_mesh_scene_recall { + bool op_en; /* Indicate whether optional parameters included */ + u16_t scene_number; /* The number of the scene to be recalled */ + u8_t tid; /* Transaction Identifier */ + u8_t trans_time; /* Time to complete state transition (optional) */ + u8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_scene_delete { + u16_t scene_number; /* The number of the scene to be deleted */ +}; + +/* Scheduler Client Model Context */ +extern const struct bt_mesh_model_op scheduler_cli_op[]; + +/** @def BLE_MESH_MODEL_SCHEDULER_CLI + * + * Define a new scheduler client model. Note that this API needs to + * be repeated for each element which the application wants to + * have a scheduler model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_scheduler_cli. + * + * @return New scheduler client model instance. + */ +#define BLE_MESH_MODEL_SCHEDULER_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL(BLE_MESH_MODEL_ID_SCHEDULER_CLI, \ + scheduler_cli_op, cli_pub, cli_data) + +typedef bt_mesh_client_common_t bt_mesh_scheduler_cli_t; + +struct bt_mesh_scheduler_status { + u16_t schedules; /* Bit field indicating defined Actions in the Schedule Register */ +}; + +struct bt_mesh_scheduler_act_status { + u64_t index : 4; /* Enumerates (selects) a Schedule Register entry */ + u64_t year : 7; /* Scheduled year for the action */ + u64_t month : 12; /* Scheduled month for the action */ + u64_t day : 5; /* Scheduled day of the month for the action */ + u64_t hour : 5; /* Scheduled hour for the action */ + u64_t minute : 6; /* Scheduled minute for the action */ + u64_t second : 6; /* Scheduled second for the action */ + u64_t day_of_week : 7; /* Schedule days of the week for the action */ + u64_t action : 4; /* Action to be performed at the scheduled time */ + u64_t trans_time : 8; /* Transition time for this action */ + u16_t scene_number; /* Transition time for this action */ +}; + +struct bt_mesh_scheduler_act_get { + u8_t index; /* Index of the Schedule Register entry to get */ +}; + +struct bt_mesh_scheduler_act_set { + u64_t index : 4; /* Index of the Schedule Register entry to set */ + u64_t year : 7; /* Scheduled year for the action */ + u64_t month : 12; /* Scheduled month for the action */ + u64_t day : 5; /* Scheduled day of the month for the action */ + u64_t hour : 5; /* Scheduled hour for the action */ + u64_t minute : 6; /* Scheduled minute for the action */ + u64_t second : 6; /* Scheduled second for the action */ + u64_t day_of_week : 7; /* Schedule days of the week for the action */ + u64_t action : 4; /* Action to be performed at the scheduled time */ + u64_t trans_time : 8; /* Transition time for this action */ + u16_t scene_number; /* Transition time for this action */ +}; + +/** + * @brief This function is called to initialize time client model user_data. + * + * @param[in] model: Pointer to time client model + * @param[in] primary: Whether belongs to primary element + * + * @return Zero-success, other-fail + */ +int bt_mesh_time_cli_init(struct bt_mesh_model *model, bool primary); + +/** + * @brief This function is called to initialize scene client model user_data. + * + * @param[in] model: Pointer to scene client model + * @param[in] primary: Whether belongs to primary element + * + * @return Zero-success, other-fail + */ +int bt_mesh_scene_cli_init(struct bt_mesh_model *model, bool primary); + +/** + * @brief This function is called to initialize scheduler client model user_data. + * + * @param[in] model: Pointer to scheduler client model + * @param[in] primary: Whether belongs to primary element + * + * @return Zero-success, other-fail + */ +int bt_mesh_scheduler_cli_init(struct bt_mesh_model *model, bool primary); + +/** + * @brief This function is called to get scene states. + * + * @param[in] common: Message common information structure + * @param[in] get: Pointer of time scene get message value + * @param[out] status: Pointer of time scene status message value + * + * @return Zero-success, other-fail + */ +int bt_mesh_time_scene_client_get_state(struct bt_mesh_common_param *common, void *get, void *status); + +/** + * @brief This function is called to set scene states. + * + * @param[in] common: Message common information structure + * @param[in] set: Pointer of time scene set message value + * @param[out] status: Pointer of time scene status message value + * + * @return Zero-success, other-fail + */ +int bt_mesh_time_scene_client_set_state(struct bt_mesh_common_param *common, void *set, void *status); + +#endif /* _TIME_SCENE_CLIENT_H_ */ diff --git a/components/bt/ble_mesh/mesh_models/lighting_client.c b/components/bt/ble_mesh/mesh_models/lighting_client.c new file mode 100644 index 0000000000..3aea99a8a4 --- /dev/null +++ b/components/bt/ble_mesh/mesh_models/lighting_client.c @@ -0,0 +1,1400 @@ +// Copyright 2017-2018 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 +#include +#include + +#include "osi/allocator.h" +#include "sdkconfig.h" + +#include "mesh_types.h" +#include "mesh_kernel.h" +#include "mesh_trace.h" + +#include "mesh.h" +#include "model_opcode.h" +#include "mesh_common.h" +#include "lighting_client.h" + +#include "btc_ble_mesh_lighting_model.h" + +/** The following are the macro definitions of lighting client + * model messages length, and a message is composed of three + * parts: Opcode + msg_value + MIC + */ +/* Light lightness client messages length */ +#define BLE_MESH_LIGHT_LIGHTNESS_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_LIGHTNESS_SET_MSG_LEN (2 + 5 + 4) +#define BLE_MESH_LIGHT_LIGHTNESS_LINEAR_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_LIGHTNESS_LINEAR_SET_MSG_LEN (2 + 5 + 4) +#define BLE_MESH_LIGHT_LIGHTNESS_LAST_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_LIGHTNESS_DEFAULT_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_LIGHTNESS_DEFAULT_SET_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_LIGHT_LIGHTNESS_RANGE_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_LIGHTNESS_RANGE_SET_MSG_LEN (2 + 4 + 4) + +/* Light CTL client messages length */ +#define BLE_MESH_LIGHT_CTL_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_CTL_SET_MSG_LEN (2 + 9 + 4) +#define BLE_MESH_LIGHT_CTL_TEMPERATURE_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_CTL_TEMPERATURE_SET_MSG_LEN (2 + 7 + 4) +#define BLE_MESH_LIGHT_CTL_TEMPERATURE_RANGE_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_CTL_TEMPERATURE_RANGE_SET_MSG_LEN (2 + 4 + 4) +#define BLE_MESH_LIGHT_CTL_DEFAULT_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_CTL_DEFAULT_SET_MSG_LEN (2 + 6 + 4) + +/* Light HSL client messages length */ +#define BLE_MESH_LIGHT_HSL_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_HSL_SET_MSG_LEN (2 + 9 + 4) +#define BLE_MESH_LIGHT_HSL_TARGET_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_HSL_HUE_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_HSL_HUE_SET_MSG_LEN (2 + 5 + 4) +#define BLE_MESH_LIGHT_HSL_SATURATION_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_HSL_SATURATION_SET_MSG_LEN (2 + 5 + 4) +#define BLE_MESH_LIGHT_HSL_DEFAULT_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_HSL_DEFAULT_SET_MSG_LEN (2 + 6 + 4) +#define BLE_MESH_LIGHT_HSL_RANGE_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_HSL_RANGE_SET_MSG_LEN (2 + 8 + 4) + +/* Light xyL client messages length */ +#define BLE_MESH_LIGHT_XYL_SET_MSG_LEN (2 + 9 + 4) +#define BLE_MESH_LIGHT_XYL_DEFAULT_SET_MSG_LEN (2 + 6 + 4) +#define BLE_MESH_LIGHT_XYL_RANGE_SET_MSG_LEN (2 + 8 + 4) + +/* Light LC client messages length */ +#define BLE_MESH_LIGHT_LC_MODE_SET_MSG_LEN (2 + 1 + 4) +#define BLE_MESH_LIGHT_LC_OM_SET_MSG_LEN (2 + 1 + 4) +#define BLE_MESH_LIGHT_LC_LIGHT_ONOFF_SET_MSG_LEN (2 + 4 + 4) +#define BLE_MESH_LIGHT_LC_PROPERTY_GET_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_LIGHT_LC_PROPERTY_SET_MSG_LEN /* variable */ + +#define BLE_MESH_LIGHT_GET_STATE_MSG_LEN (2 + 2 + 4) + +static const bt_mesh_client_op_pair_t light_op_pair[] = { + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_GET, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_GET, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_GET, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_GET, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_GET, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_GET, BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_SET, BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_GET, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_GET, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_GET, BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET, BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_GET, BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_SET, BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_GET, BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_GET, BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET, BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_GET, BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET, BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_GET, BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET, BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_GET, BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET, BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_XYL_GET, BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_XYL_SET, BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_GET, BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_GET, BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET, BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_GET, BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET, BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LC_MODE_GET, BLE_MESH_MODEL_OP_LIGHT_LC_MODE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET, BLE_MESH_MODEL_OP_LIGHT_LC_MODE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LC_OM_GET, BLE_MESH_MODEL_OP_LIGHT_LC_OM_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET, BLE_MESH_MODEL_OP_LIGHT_LC_OM_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_GET, BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET, BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_GET, BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET, BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS }, +}; + +static void timeout_handler(struct k_work *work) +{ + light_internal_data_t *internal = NULL; + bt_mesh_light_client_t *client = NULL; + bt_mesh_client_node_t *node = NULL; + + BT_WARN("Receive light status message timeout"); + + node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work); + if (!node || !node->ctx.model) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + client = (bt_mesh_light_client_t *)node->ctx.model->user_data; + if (!client) { + BT_ERR("%s, Lighting Client user_data is NULL", __func__); + return; + } + + internal = (light_internal_data_t *)client->internal_data; + if (!internal) { + BT_ERR("%s, Lighting Client internal_data is NULL", __func__); + return; + } + + bt_mesh_callback_light_status_to_btc(node->opcode, 0x03, node->ctx.model, + &node->ctx, NULL, 0); + + bt_mesh_client_free_node(&internal->queue, node); + + return; +} + +static void light_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + light_internal_data_t *internal = NULL; + bt_mesh_light_client_t *client = NULL; + bt_mesh_client_node_t *node = NULL; + u8_t *val = NULL; + u8_t evt = 0xFF; + u32_t rsp = 0; + size_t len = 0; + + BT_DBG("%s, len %d, bytes %s", __func__, buf->len, bt_hex(buf->data, buf->len)); + + client = (bt_mesh_light_client_t *)model->user_data; + if (!client) { + BT_ERR("%s, Lighting Client user_data is NULL", __func__); + return; + } + + internal = (light_internal_data_t *)client->internal_data; + if (!internal) { + BT_ERR("%s, Lighting Client internal_data is NULL", __func__); + return; + } + + rsp = ctx->recv_op; + + switch (rsp) { + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS: { + struct bt_mesh_light_lightness_status *status = NULL; + if (buf->len != 2 && buf->len != 5) { + BT_ERR("%s, Invalid Light Lightness Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_lightness_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->present_lightness = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->target_lightness = net_buf_simple_pull_le16(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_lightness_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS: { + struct bt_mesh_light_lightness_linear_status *status = NULL; + if (buf->len != 2 && buf->len != 5) { + BT_ERR("%s, Invalid Light Lightness Linear Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_lightness_linear_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->present_lightness = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->target_lightness = net_buf_simple_pull_le16(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_lightness_linear_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_STATUS: { + struct bt_mesh_light_lightness_last_status *status = NULL; + if (buf->len != 2) { + BT_ERR("%s, Invalid Light Lightness Last Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_lightness_last_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->lightness = net_buf_simple_pull_le16(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_lightness_last_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_STATUS: { + struct bt_mesh_light_lightness_default_status *status = NULL; + if (buf->len != 2) { + BT_ERR("%s, Invalid Light Lightness Default Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_lightness_default_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->lightness = net_buf_simple_pull_le16(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_lightness_default_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_STATUS: { + struct bt_mesh_light_lightness_range_status *status = NULL; + if (buf->len != 5) { + BT_ERR("%s, Invalid Light Lightness Range Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_lightness_range_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->status_code = net_buf_simple_pull_u8(buf); + status->range_min = net_buf_simple_pull_le16(buf); + status->range_max = net_buf_simple_pull_le16(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_lightness_range_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS: { + struct bt_mesh_light_ctl_status *status = NULL; + if (buf->len != 4 && buf->len != 9) { + BT_ERR("%s, Invalid Light CTL Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_ctl_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->present_ctl_lightness = net_buf_simple_pull_le16(buf); + status->present_ctl_temperature = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->target_ctl_lightness = net_buf_simple_pull_le16(buf); + status->target_ctl_temperature = net_buf_simple_pull_le16(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_ctl_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS: { + struct bt_mesh_light_ctl_temperature_status *status = NULL; + if (buf->len != 4 && buf->len != 9) { + BT_ERR("%s, Invalid Light CTL Temperature Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_ctl_temperature_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->present_ctl_temperature = net_buf_simple_pull_le16(buf); + status->present_ctl_delta_uv = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->target_ctl_temperature = net_buf_simple_pull_le16(buf); + status->target_ctl_delta_uv = net_buf_simple_pull_le16(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_ctl_temperature_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_STATUS: { + struct bt_mesh_light_ctl_temperature_range_status *status = NULL; + if (buf->len != 5) { + BT_ERR("%s, Invalid Light CTL Temperature Range Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_ctl_temperature_range_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->status_code = net_buf_simple_pull_u8(buf); + status->range_min = net_buf_simple_pull_le16(buf); + status->range_max = net_buf_simple_pull_le16(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_ctl_temperature_range_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_STATUS: { + struct bt_mesh_light_ctl_default_status *status = NULL; + if (buf->len != 6) { + BT_ERR("%s, Invalid Light CTL Default Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_ctl_default_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->lightness = net_buf_simple_pull_le16(buf); + status->temperature = net_buf_simple_pull_le16(buf); + status->delta_uv = net_buf_simple_pull_le16(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_ctl_default_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS: { + struct bt_mesh_light_hsl_status *status = NULL; + if (buf->len != 6 && buf->len != 7) { + BT_ERR("%s, Invalid Light HSL Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_hsl_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->hsl_lightness = net_buf_simple_pull_le16(buf); + status->hsl_hue = net_buf_simple_pull_le16(buf); + status->hsl_saturation = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_hsl_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_STATUS: { + struct bt_mesh_light_hsl_target_status *status = NULL; + if (buf->len != 6 && buf->len != 7) { + BT_ERR("%s, Invalid Light HSL Target Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_hsl_target_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->hsl_lightness_target = net_buf_simple_pull_le16(buf); + status->hsl_hue_target = net_buf_simple_pull_le16(buf); + status->hsl_saturation_target = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_hsl_target_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS: { + struct bt_mesh_light_hsl_hue_status *status = NULL; + if (buf->len != 2 && buf->len != 5) { + BT_ERR("%s, Invalid Light HSL Hue Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_hsl_hue_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->present_hue = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->target_hue = net_buf_simple_pull_le16(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_hsl_hue_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS: { + struct bt_mesh_light_hsl_saturation_status *status = NULL; + if (buf->len != 2 && buf->len != 5) { + BT_ERR("%s, Invalid Light HSL Saturation Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_hsl_saturation_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->present_saturation = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->target_saturation = net_buf_simple_pull_le16(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_hsl_saturation_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_STATUS: { + struct bt_mesh_light_hsl_default_status *status = NULL; + if (buf->len != 6) { + BT_ERR("%s, Invalid Light HSL Default Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_hsl_default_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->lightness = net_buf_simple_pull_le16(buf); + status->hue = net_buf_simple_pull_le16(buf); + status->saturation = net_buf_simple_pull_le16(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_hsl_default_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_STATUS: { + struct bt_mesh_light_hsl_range_status *status = NULL; + if (buf->len != 9) { + BT_ERR("%s, Invalid Light HSL Range Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_hsl_range_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->status_code = net_buf_simple_pull_u8(buf); + status->hue_range_min = net_buf_simple_pull_le16(buf); + status->hue_range_max = net_buf_simple_pull_le16(buf); + status->saturation_range_min = net_buf_simple_pull_le16(buf); + status->saturation_range_max = net_buf_simple_pull_le16(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_hsl_range_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS: { + struct bt_mesh_light_xyl_status *status = NULL; + if (buf->len != 6 && buf->len != 7) { + BT_ERR("%s, Invalid Light xyL Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_xyl_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->xyl_lightness = net_buf_simple_pull_le16(buf); + status->xyl_x = net_buf_simple_pull_le16(buf); + status->xyl_y = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_xyl_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_STATUS: { + struct bt_mesh_light_xyl_target_status *status = NULL; + if (buf->len != 6 && buf->len != 7) { + BT_ERR("%s, Invalid Light xyL Target Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_xyl_target_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->target_xyl_lightness = net_buf_simple_pull_le16(buf); + status->target_xyl_x = net_buf_simple_pull_le16(buf); + status->target_xyl_y = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_xyl_target_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_STATUS: { + struct bt_mesh_light_xyl_default_status *status = NULL; + if (buf->len != 6) { + BT_ERR("%s, Invalid Light xyL Default Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_xyl_default_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->lightness = net_buf_simple_pull_le16(buf); + status->xyl_x = net_buf_simple_pull_le16(buf); + status->xyl_y = net_buf_simple_pull_le16(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_xyl_default_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_STATUS: { + struct bt_mesh_light_xyl_range_status *status = NULL; + if (buf->len != 9) { + BT_ERR("%s, Invalid Light xyL Range Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_xyl_range_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->status_code = net_buf_simple_pull_u8(buf); + status->xyl_x_range_min = net_buf_simple_pull_le16(buf); + status->xyl_x_range_max = net_buf_simple_pull_le16(buf); + status->xyl_y_range_min = net_buf_simple_pull_le16(buf); + status->xyl_y_range_max = net_buf_simple_pull_le16(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_xyl_range_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LC_MODE_STATUS: { + struct bt_mesh_light_lc_mode_status *status = NULL; + if (buf->len != 1) { + BT_ERR("%s, Invalid Light LC Mode Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_lc_mode_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->mode = net_buf_simple_pull_u8(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_lc_mode_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LC_OM_STATUS: { + struct bt_mesh_light_lc_om_status *status = NULL; + if (buf->len != 1) { + BT_ERR("%s, Invalid Light LC OM Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_lc_om_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->mode = net_buf_simple_pull_u8(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_lc_om_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS: { + struct bt_mesh_light_lc_light_onoff_status *status = NULL; + if (buf->len != 1 && buf->len != 3) { + BT_ERR("%s, Invalid Light LC Light OnOff Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_light_lc_light_onoff_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->present_light_onoff = net_buf_simple_pull_u8(buf); + if (buf->len) { + status->op_en = true; + status->target_light_onoff = net_buf_simple_pull_u8(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_lc_light_onoff_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS: { + struct bt_mesh_light_lc_property_status *status = NULL; + status = osi_calloc(sizeof(struct bt_mesh_light_lc_property_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->light_lc_property_id = net_buf_simple_pull_le16(buf); + status->light_lc_property_value = bt_mesh_alloc_buf(buf->len); + if (!status->light_lc_property_value) { + BT_ERR("%s, Failed to allocate memory", __func__); + osi_free(status); + return; + } + net_buf_simple_add_mem(status->light_lc_property_value, buf->data, buf->len); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_light_lc_property_status); + break; + } + default: + BT_ERR("%s, Not a Lighting Status message opcode", __func__); + return; + } + + buf->data = val; + buf->len = len; + node = bt_mesh_is_model_message_publish(model, ctx, buf, true); + if (!node) { + BT_DBG("Unexpected light status message 0x%x", rsp); + } else { + switch (node->opcode) { + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_GET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_GET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_GET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_GET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_GET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_GET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_GET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_GET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_GET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_GET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_GET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_GET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_GET: + case BLE_MESH_MODEL_OP_LIGHT_LC_MODE_GET: + case BLE_MESH_MODEL_OP_LIGHT_LC_OM_GET: + case BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_GET: + case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_GET: + evt = 0x00; + break; + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_SET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_SET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_SET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET: + case BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET: + case BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET: + case BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET: + case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET: + evt = 0x01; + break; + default: + break; + } + + bt_mesh_callback_light_status_to_btc(node->opcode, evt, model, ctx, val, len); + // Don't forget to release the node at the end. + bt_mesh_client_free_node(&internal->queue, node); + } + + switch (rsp) { + case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS: { + struct bt_mesh_light_lc_property_status *status; + status = (struct bt_mesh_light_lc_property_status *)val; + bt_mesh_free_buf(status->light_lc_property_value); + break; + } + default: + break; + } + + osi_free(val); + + return; +} + +const struct bt_mesh_model_op light_lightness_cli_op[] = { + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS, 2, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS, 2, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_STATUS, 2, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_STATUS, 2, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_STATUS, 5, light_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op light_ctl_cli_op[] = { + { BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS, 4, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS, 4, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_STATUS, 5, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_STATUS, 6, light_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op light_hsl_cli_op[] = { + { BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS, 6, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_STATUS, 6, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS, 2, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS, 2, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_STATUS, 6, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_STATUS, 9, light_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op light_xyl_cli_op[] = { + { BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS, 6, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_STATUS, 6, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_STATUS, 6, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_STATUS, 9, light_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op light_lc_cli_op[] = { + { BLE_MESH_MODEL_OP_LIGHT_LC_MODE_STATUS, 1, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_LC_OM_STATUS, 1, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS, 1, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS, 2, light_status }, + BLE_MESH_MODEL_OP_END, +}; + +static int light_get_state(struct bt_mesh_common_param *common, void *value) +{ + NET_BUF_SIMPLE_DEFINE(msg, BLE_MESH_LIGHT_GET_STATE_MSG_LEN); + int err; + + bt_mesh_model_msg_init(&msg, common->opcode); + + if (value) { + switch (common->opcode) { + case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_GET: { + struct bt_mesh_light_lc_property_get *get; + get = (struct bt_mesh_light_lc_property_get *)value; + net_buf_simple_add_le16(&msg, get->light_lc_property_id); + break; + } + default: + BT_DBG("This lighting message should be sent with NULL get pointer"); + break; + } + } + + err = bt_mesh_client_send_msg(common->model, common->opcode, &common->ctx, &msg, + timeout_handler, common->msg_timeout, true, + common->cb, common->cb_data); + if (err) { + BT_ERR("%s, Failed to send Lighting Client Get message (err %d)", __func__, err); + } + + return err; +} + +static int light_set_state(struct bt_mesh_common_param *common, + void *value, u16_t value_len, bool need_ack) +{ + struct net_buf_simple *msg = NULL; + int err; + + msg = bt_mesh_alloc_buf(value_len); + if (!msg) { + BT_ERR("%s, Failed to allocate memory", __func__); + return -ENOMEM; + } + + bt_mesh_model_msg_init(msg, common->opcode); + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET_UNACK: { + struct bt_mesh_light_lightness_set *set; + set = (struct bt_mesh_light_lightness_set *)value; + net_buf_simple_add_le16(msg, set->lightness); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET_UNACK: { + struct bt_mesh_light_lightness_linear_set *set; + set = (struct bt_mesh_light_lightness_linear_set *)value; + net_buf_simple_add_le16(msg, set->lightness); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET_UNACK: { + struct bt_mesh_light_lightness_default_set *set; + set = (struct bt_mesh_light_lightness_default_set *)value; + net_buf_simple_add_le16(msg, set->lightness); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET_UNACK: { + struct bt_mesh_light_lightness_range_set *set; + set = (struct bt_mesh_light_lightness_range_set *)value; + net_buf_simple_add_le16(msg, set->range_min); + net_buf_simple_add_le16(msg, set->range_max); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_SET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_SET_UNACK: { + struct bt_mesh_light_ctl_set *set; + set = (struct bt_mesh_light_ctl_set *)value; + net_buf_simple_add_le16(msg, set->ctl_lightness); + net_buf_simple_add_le16(msg, set->ctl_temperature); + net_buf_simple_add_le16(msg, set->ctl_delta_uv); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET_UNACK: { + struct bt_mesh_light_ctl_temperature_set *set; + set = (struct bt_mesh_light_ctl_temperature_set *)value; + net_buf_simple_add_le16(msg, set->ctl_temperature); + net_buf_simple_add_le16(msg, set->ctl_delta_uv); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET_UNACK: { + struct bt_mesh_light_ctl_temperature_range_set *set; + set = (struct bt_mesh_light_ctl_temperature_range_set *)value; + net_buf_simple_add_le16(msg, set->range_min); + net_buf_simple_add_le16(msg, set->range_max); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET_UNACK: { + struct bt_mesh_light_ctl_default_set *set; + set = (struct bt_mesh_light_ctl_default_set *)value; + net_buf_simple_add_le16(msg, set->lightness); + net_buf_simple_add_le16(msg, set->temperature); + net_buf_simple_add_le16(msg, set->delta_uv); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_SET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_SET_UNACK: { + struct bt_mesh_light_hsl_set *set; + set = (struct bt_mesh_light_hsl_set *)value; + net_buf_simple_add_le16(msg, set->hsl_lightness); + net_buf_simple_add_le16(msg, set->hsl_hue); + net_buf_simple_add_le16(msg, set->hsl_saturation); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET_UNACK: { + struct bt_mesh_light_hsl_hue_set *set; + set = (struct bt_mesh_light_hsl_hue_set *)value; + net_buf_simple_add_le16(msg, set->hue); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET_UNACK: { + struct bt_mesh_light_hsl_saturation_set *set; + set = (struct bt_mesh_light_hsl_saturation_set *)value; + net_buf_simple_add_le16(msg, set->saturation); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET_UNACK: { + struct bt_mesh_light_hsl_default_set *set; + set = (struct bt_mesh_light_hsl_default_set *)value; + net_buf_simple_add_le16(msg, set->lightness); + net_buf_simple_add_le16(msg, set->hue); + net_buf_simple_add_le16(msg, set->saturation); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET_UNACK: { + struct bt_mesh_light_hsl_range_set *set; + set = (struct bt_mesh_light_hsl_range_set *)value; + net_buf_simple_add_le16(msg, set->hue_range_min); + net_buf_simple_add_le16(msg, set->hue_range_max); + net_buf_simple_add_le16(msg, set->saturation_range_min); + net_buf_simple_add_le16(msg, set->saturation_range_max); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_XYL_SET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_SET_UNACK: { + struct bt_mesh_light_xyl_set *set; + set = (struct bt_mesh_light_xyl_set *)value; + net_buf_simple_add_le16(msg, set->xyl_lightness); + net_buf_simple_add_le16(msg, set->xyl_x); + net_buf_simple_add_le16(msg, set->xyl_y); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + case BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET_UNACK: { + struct bt_mesh_light_xyl_default_set *set; + set = (struct bt_mesh_light_xyl_default_set *)value; + net_buf_simple_add_le16(msg, set->lightness); + net_buf_simple_add_le16(msg, set->xyl_x); + net_buf_simple_add_le16(msg, set->xyl_y); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET_UNACK: { + struct bt_mesh_light_xyl_range_set *set; + set = (struct bt_mesh_light_xyl_range_set *)value; + net_buf_simple_add_le16(msg, set->xyl_x_range_min); + net_buf_simple_add_le16(msg, set->xyl_x_range_max); + net_buf_simple_add_le16(msg, set->xyl_y_range_min); + net_buf_simple_add_le16(msg, set->xyl_y_range_max); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET: + case BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET_UNACK: { + struct bt_mesh_light_lc_mode_set *set; + set = (struct bt_mesh_light_lc_mode_set *)value; + net_buf_simple_add_u8(msg, set->mode); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET: + case BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET_UNACK: { + struct bt_mesh_light_lc_om_set *set; + set = (struct bt_mesh_light_lc_om_set *)value; + net_buf_simple_add_u8(msg, set->mode); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET: + case BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET_UNACK: { + struct bt_mesh_light_lc_light_onoff_set *set; + set = (struct bt_mesh_light_lc_light_onoff_set *)value; + net_buf_simple_add_u8(msg, set->light_onoff); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET: + case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET_UNACK: { + struct bt_mesh_light_lc_property_set *set; + set = (struct bt_mesh_light_lc_property_set *)value; + net_buf_simple_add_le16(msg, set->light_lc_property_id); + net_buf_simple_add_mem(msg, set->light_lc_property_value->data, set->light_lc_property_value->len); + break; + } + default: + BT_ERR("%s, Not a Lighting Client Set message opcode", __func__); + err = -EINVAL; + goto end; + } + + err = bt_mesh_client_send_msg(common->model, common->opcode, &common->ctx, msg, + timeout_handler, common->msg_timeout, need_ack, + common->cb, common->cb_data); + if (err) { + BT_ERR("%s, Failed to send Lighting Client Set message (err %d)", __func__, err); + } + +end: + bt_mesh_free_buf(msg); + + return err; +} + +int bt_mesh_light_client_get_state(struct bt_mesh_common_param *common, void *get, void *status) +{ + bt_mesh_light_client_t *client = NULL; + + if (!common || !common->model) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_light_client_t *)common->model->user_data; + if (!client || !client->internal_data) { + BT_ERR("%s, Lighting Client user data is NULL", __func__); + return -EINVAL; + } + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_GET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_GET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_GET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_GET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_GET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_GET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_GET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_GET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_GET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_GET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_GET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_GET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_GET: + case BLE_MESH_MODEL_OP_LIGHT_LC_MODE_GET: + case BLE_MESH_MODEL_OP_LIGHT_LC_OM_GET: + case BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_GET: + break; + case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_GET: + if (!get) { + BT_ERR("%s, Lighting lc_property_get is NULL", __func__); + return -EINVAL; + } + break; + default: + BT_ERR("%s, Not a Lighting Client Get message opcode", __func__); + return -EINVAL; + } + + return light_get_state(common, get); +} + +int bt_mesh_light_client_set_state(struct bt_mesh_common_param *common, void *set, void *status) +{ + bt_mesh_light_client_t *client = NULL; + u16_t length = 0; + bool need_ack = false; + + if (!common || !common->model || !set) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_light_client_t *)common->model->user_data; + if (!client || !client->internal_data) { + BT_ERR("%s, Lighting Client user data is NULL", __func__); + return -EINVAL; + } + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET_UNACK: { + struct bt_mesh_light_lightness_set *value; + value = (struct bt_mesh_light_lightness_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("%s, Invalid Light Lightness Set transition time", __func__); + return -EINVAL; + } + } + length = BLE_MESH_LIGHT_LIGHTNESS_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET_UNACK: { + struct bt_mesh_light_lightness_linear_set *value; + value = (struct bt_mesh_light_lightness_linear_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("%s, Invalid Light Lightness Linear Set transition time", __func__); + return -EINVAL; + } + } + length = BLE_MESH_LIGHT_LIGHTNESS_LINEAR_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET_UNACK: + length = BLE_MESH_LIGHT_LIGHTNESS_DEFAULT_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET_UNACK: { + struct bt_mesh_light_lightness_range_set *value; + value = (struct bt_mesh_light_lightness_range_set *)set; + if (value->range_min > value->range_max) { + BT_ERR("%s, Light Lightness Range Set range min is greater than range max", __func__); + return -EINVAL; + } + length = BLE_MESH_LIGHT_LIGHTNESS_RANGE_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_CTL_SET_UNACK: { + struct bt_mesh_light_ctl_set *value; + value = (struct bt_mesh_light_ctl_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("%s, Invalid Light CTL Set transition time", __func__); + return -EINVAL; + } + } + length = BLE_MESH_LIGHT_CTL_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET_UNACK: { + struct bt_mesh_light_ctl_temperature_set *value; + value = (struct bt_mesh_light_ctl_temperature_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("%s, Invalid Light CTL Temperature Set transition time", __func__); + return -EINVAL; + } + } + length = BLE_MESH_LIGHT_CTL_TEMPERATURE_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET_UNACK: { + struct bt_mesh_light_ctl_temperature_range_set *value; + value = (struct bt_mesh_light_ctl_temperature_range_set *)set; + if (value->range_min > value->range_max) { + BT_ERR("%s, Light CTL Temperature Range Set range min is greater than range max", __func__); + return -EINVAL; + } + length = BLE_MESH_LIGHT_CTL_TEMPERATURE_RANGE_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET_UNACK: + length = BLE_MESH_LIGHT_CTL_DEFAULT_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_LIGHT_HSL_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_HSL_SET_UNACK: { + struct bt_mesh_light_hsl_set *value; + value = (struct bt_mesh_light_hsl_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("%s, Invalid Light HSL Set transition time", __func__); + return -EINVAL; + } + } + length = BLE_MESH_LIGHT_HSL_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET_UNACK: { + struct bt_mesh_light_hsl_hue_set *value; + value = (struct bt_mesh_light_hsl_hue_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("%s, Invalid Light HSL Hue Set transition time", __func__); + return -EINVAL; + } + } + length = BLE_MESH_LIGHT_HSL_HUE_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET_UNACK: { + struct bt_mesh_light_hsl_saturation_set *value; + value = (struct bt_mesh_light_hsl_saturation_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("%s, Invalid Light HSL Saturation Set transition time", __func__); + return -EINVAL; + } + } + length = BLE_MESH_LIGHT_HSL_SATURATION_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET_UNACK: + length = BLE_MESH_LIGHT_HSL_DEFAULT_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET_UNACK: { + struct bt_mesh_light_hsl_range_set *value; + value = (struct bt_mesh_light_hsl_range_set *)set; + if (value->hue_range_min > value->hue_range_max || + value->saturation_range_min > value->saturation_range_max) { + BT_ERR("%s, Light HSL Range Set range min is greater than range max", __func__); + return -EINVAL; + } + length = BLE_MESH_LIGHT_HSL_RANGE_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_XYL_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_XYL_SET_UNACK: { + struct bt_mesh_light_xyl_set *value; + value = (struct bt_mesh_light_xyl_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("%s, Invalid Light xyL Set transition time", __func__); + return -EINVAL; + } + } + length = BLE_MESH_LIGHT_XYL_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET_UNACK: + length = BLE_MESH_LIGHT_XYL_DEFAULT_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET_UNACK: { + struct bt_mesh_light_xyl_range_set *value; + value = (struct bt_mesh_light_xyl_range_set *)set; + if (value->xyl_x_range_min > value->xyl_x_range_max || + value->xyl_y_range_min > value->xyl_y_range_max) { + BT_ERR("%s, Light xyL Range Set range min is greater than range max", __func__); + return -EINVAL; + } + length = BLE_MESH_LIGHT_XYL_RANGE_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET_UNACK: + length = BLE_MESH_LIGHT_LC_MODE_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET_UNACK: + length = BLE_MESH_LIGHT_LC_OM_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET_UNACK: { + struct bt_mesh_light_lc_light_onoff_set *value; + value = (struct bt_mesh_light_lc_light_onoff_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("%s, Invalid Light LC Light OnOff Set transition time", __func__); + return -EINVAL; + } + } + length = BLE_MESH_LIGHT_LC_LIGHT_ONOFF_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET_UNACK: { + struct bt_mesh_light_lc_property_set *value; + value = (struct bt_mesh_light_lc_property_set *)set; + if (!value->light_lc_property_value) { + BT_ERR("%s, Lighting light_lc_property_value is NULL", __func__); + return -EINVAL; + } + length = (1 + 2 + value->light_lc_property_value->len + 4); + break; + } + default: + BT_ERR("%s, Not a Lighting Client Set message opcode", __func__); + return -EINVAL; + } + + return light_set_state(common, set, length, need_ack); +} + +static int light_client_init(struct bt_mesh_model *model, bool primary) +{ + light_internal_data_t *internal = NULL; + bt_mesh_light_client_t *client = NULL; + + BT_DBG("primary %u", primary); + + if (!model) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_light_client_t *)model->user_data; + if (!client) { + BT_ERR("%s, Lighting Client user_data is NULL", __func__); + return -EINVAL; + } + + /* TODO: call osi_free() when deinit function is invoked*/ + internal = osi_calloc(sizeof(light_internal_data_t)); + if (!internal) { + BT_ERR("%s, Failed to allocate memory", __func__); + return -ENOMEM; + } + + sys_slist_init(&internal->queue); + + client->model = model; + client->op_pair_size = ARRAY_SIZE(light_op_pair); + client->op_pair = light_op_pair; + client->internal_data = internal; + + return 0; +} + +int bt_mesh_light_lightness_cli_init(struct bt_mesh_model *model, bool primary) +{ + return light_client_init(model, primary); +} + +int bt_mesh_light_ctl_cli_init(struct bt_mesh_model *model, bool primary) +{ + return light_client_init(model, primary); +} + +int bt_mesh_light_hsl_cli_init(struct bt_mesh_model *model, bool primary) +{ + return light_client_init(model, primary); +} + +int bt_mesh_light_xyl_cli_init(struct bt_mesh_model *model, bool primary) +{ + return light_client_init(model, primary); +} + +int bt_mesh_light_lc_cli_init(struct bt_mesh_model *model, bool primary) +{ + return light_client_init(model, primary); +} \ No newline at end of file diff --git a/components/bt/ble_mesh/mesh_models/mesh_common.c b/components/bt/ble_mesh/mesh_models/mesh_common.c new file mode 100644 index 0000000000..801644ace1 --- /dev/null +++ b/components/bt/ble_mesh/mesh_models/mesh_common.c @@ -0,0 +1,46 @@ +// Copyright 2017-2018 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 +#include + +#include "mesh_common.h" + +struct net_buf_simple *bt_mesh_alloc_buf(u16_t size) +{ + struct net_buf_simple *buf = NULL; + u8_t *data = NULL; + + buf = (struct net_buf_simple *)osi_calloc(sizeof(struct net_buf_simple) + size); + if (!buf) { + BT_ERR("%s, Failed to allocate memory", __func__); + return NULL; + } + + data = (u8_t *)buf + sizeof(struct net_buf_simple); + + buf->data = data; + buf->len = 0; + buf->size = size; + buf->__buf = data; + + return buf; +} + +void bt_mesh_free_buf(struct net_buf_simple *buf) +{ + if (buf) { + osi_free(buf); + } +} diff --git a/components/bt/ble_mesh/mesh_models/model_common.c b/components/bt/ble_mesh/mesh_models/model_common.c new file mode 100644 index 0000000000..c904543de5 --- /dev/null +++ b/components/bt/ble_mesh/mesh_models/model_common.c @@ -0,0 +1,336 @@ +// Copyright 2017-2018 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 +#include + +#include "osi/allocator.h" + +#include "mesh_access.h" +#include "mesh_buf.h" +#include "mesh_slist.h" +#include "mesh_main.h" + +#include "mesh.h" +#include "model_common.h" + +bt_mesh_client_node_t *bt_mesh_is_model_message_publish(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf, + bool need_pub) +{ + bt_mesh_internal_data_t *data = NULL; + bt_mesh_client_common_t *cli = NULL; + bt_mesh_client_node_t *node = NULL; + u32_t rsp; + + if (!model || !ctx || !buf) { + BT_ERR("%s, Invalid parameter", __func__); + return NULL; + } + + cli = (bt_mesh_client_common_t *)model->user_data; + if (!cli) { + BT_ERR("%s, Clinet user_data is NULL", __func__); + return NULL; + } + + rsp = ctx->recv_op; + + /** If the received message address is not a unicast address, + * the address may be a group/virtual address, and we push + * this message to the application layer. + */ + if (!BLE_MESH_ADDR_IS_UNICAST(ctx->recv_dst)) { + BT_DBG("Unexpected status message 0x%x", rsp); + if (cli->publish_status && need_pub) { + cli->publish_status(rsp, model, ctx, buf); + } + return NULL; + } + + /** If the source address of the received status message is + * different with the destination address of the sending + * message, then the message is from another element and + * push it to application layer. + */ + data = (bt_mesh_internal_data_t *)cli->internal_data; + if (!data) { + BT_ERR("%s, Client internal_data is NULL", __func__); + return NULL; + } + + if ((node = bt_mesh_client_pick_node(&data->queue, ctx->addr)) == NULL) { + BT_DBG("Unexpected status message 0x%x", rsp); + if (cli->publish_status && need_pub) { + cli->publish_status(rsp, model, ctx, buf); + } + return NULL; + } + + if (node->op_pending != rsp) { + BT_DBG("Unexpected status message 0x%x", rsp); + if (cli->publish_status && need_pub) { + cli->publish_status(rsp, model, ctx, buf); + } + return NULL; + } + + return node; +} + +bool bt_mesh_client_find_opcode_in_list(sys_slist_t *list, u32_t opcode) +{ + if (sys_slist_is_empty(list)) { + return false; + } + + sys_snode_t *cur = NULL; bt_mesh_client_node_t *node = NULL; + for (cur = sys_slist_peek_head(list); + cur != NULL; cur = sys_slist_peek_next(cur)) { + node = (bt_mesh_client_node_t *)cur; + if (node->op_pending == opcode) { + return true; + } + return NULL; + } + + return node; +} + +bool bt_mesh_client_check_node_in_list(sys_slist_t *list, u16_t tx_dst) +{ + if (sys_slist_is_empty(list)) { + return false; + } + + sys_snode_t *cur = NULL; bt_mesh_client_node_t *node = NULL; + for (cur = sys_slist_peek_head(list); + cur != NULL; cur = sys_slist_peek_next(cur)) { + node = (bt_mesh_client_node_t *)cur; + if (node->ctx.addr == tx_dst) { + return true; + } + } + + return false; +} + +bt_mesh_client_node_t *bt_mesh_client_pick_node(sys_slist_t *list, u16_t tx_dst) +{ + if (sys_slist_is_empty(list)) { + return NULL; + } + + sys_snode_t *cur = NULL; bt_mesh_client_node_t *node = NULL; + for (cur = sys_slist_peek_head(list); + cur != NULL; cur = sys_slist_peek_next(cur)) { + node = (bt_mesh_client_node_t *)cur; + if (node->ctx.addr == tx_dst) { + return node; + } + } + + return NULL; +} + +static u32_t bt_mesh_client_get_status_op(const bt_mesh_client_op_pair_t *op_pair, + int size, u32_t opcode) +{ + if (!op_pair || size == 0) { + return 0; + } + + const bt_mesh_client_op_pair_t *op = op_pair; + for (int i = 0; i < size; i++) { + if (op->cli_op == opcode) { + return op->status_op; + } + op++; + } + + return 0; +} + +int bt_mesh_client_send_msg(struct bt_mesh_model *model, + u32_t opcode, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *msg, + k_work_handler_t timer_handler, + s32_t timeout, bool need_ack, + const struct bt_mesh_send_cb *cb, + void *cb_data) +{ + bt_mesh_internal_data_t *internal = NULL; + bt_mesh_client_common_t *cli = NULL; + bt_mesh_client_node_t *node = NULL; + int err; + + if (!model || !ctx || !msg) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + cli = (bt_mesh_client_common_t *)model->user_data; + __ASSERT(cli, "Invalid client value when sent client msg."); + internal = (bt_mesh_internal_data_t *)cli->internal_data; + __ASSERT(internal, "Invalid internal value when sent client msg."); + + if (!need_ack) { + /* If this is an unack message, send it directly. */ + return bt_mesh_model_send(model, ctx, msg, cb, cb_data); + } + + if (bt_mesh_client_check_node_in_list(&internal->queue, ctx->addr)) { + BT_ERR("%s, Busy sending message to DST 0x%04x", __func__, ctx->addr); + err = -EBUSY; + } else { + /* Don't forget to free the node in the timeout (timer_handler) function. */ + node = (bt_mesh_client_node_t *)osi_calloc(sizeof(bt_mesh_client_node_t)); + if (!node) { + BT_ERR("%s, Failed to allocate memory", __func__); + return -ENOMEM; + } + memcpy(&node->ctx, ctx, sizeof(struct bt_mesh_msg_ctx)); + node->ctx.model = model; + node->opcode = opcode; + if ((node->op_pending = bt_mesh_client_get_status_op(cli->op_pair, cli->op_pair_size, opcode)) == 0) { + BT_ERR("%s, Not found the status opcode in the op_pair list", __func__); + osi_free(node); + return -EINVAL; + } + if ((err = bt_mesh_model_send(model, ctx, msg, cb, cb_data)) != 0) { + osi_free(node); + } else { + sys_slist_append(&internal->queue, &node->client_node); + k_delayed_work_init(&node->timer, timer_handler); + k_delayed_work_submit(&node->timer, timeout ? timeout : CONFIG_BLE_MESH_CLIENT_MSG_TIMEOUT); + } + } + + return err; +} + +int bt_mesh_client_init(struct bt_mesh_model *model) +{ + bt_mesh_internal_data_t *data = NULL; + bt_mesh_client_common_t *cli = NULL; + + if (!model) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + if (!model->op) { + BT_ERR("%s, Client model op is NULL", __func__); + return -EINVAL; + } + + cli = model->user_data; + if (!cli) { + BT_ERR("%s, Client user_data is NULL", __func__); + return -EINVAL; + } + + /* TODO: call osi_free() when deinit function is invoked */ + data = osi_calloc(sizeof(bt_mesh_internal_data_t)); + if (!data) { + BT_ERR("%s, Failed to allocate memory", __func__); + return -ENOMEM; + } + + /* Init the client data queue */ + sys_slist_init(&data->queue); + + cli->model = model; + cli->internal_data = data; + + return 0; +} + +int bt_mesh_client_free_node(sys_slist_t *queue, bt_mesh_client_node_t *node) +{ + if (!queue || !node) { + return -EINVAL; + } + + // Free the node timer + k_delayed_work_free(&node->timer); + // Release the client node from the queue + sys_slist_find_and_remove(queue, &node->client_node); + // Free the node + osi_free(node); + + return 0; +} + +int bt_mesh_set_model_role(bt_mesh_role_param_t *common) +{ + bt_mesh_client_common_t *client = NULL; + + if (!common || !common->model || !common->model->user_data) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_client_common_t *)common->model->user_data; + + switch (common->role) { +#if CONFIG_BLE_MESH_NODE + case NODE: + /* no matter if provisioner is enabled/disabled , node role can be used to send messages */ + client->msg_role = NODE; + break; +#endif +#if CONFIG_BLE_MESH_PROVISIONER + case PROVISIONER: + /* if provisioner is not enabled, provisioner role can't be used to send messages */ + if (!bt_mesh_is_provisioner_en()) { + BT_ERR("%s, Provisioner is disabled", __func__); + return -EINVAL; + } + client->msg_role = PROVISIONER; + break; +#endif +#if CONFIG_BLE_MESH_FAST_PROV + case FAST_PROV: + client->msg_role = FAST_PROV; + break; +#endif + default: + BT_WARN("%s, Unknown model role %x", __func__, common->role); + return -EINVAL; + } + + return 0; +} + +u8_t bt_mesh_get_model_role(struct bt_mesh_model *model, bool srv_send) +{ + bt_mesh_client_common_t *client = NULL; + + if (srv_send) { + BT_DBG("%s, Message is sent by a server model", __func__); + return NODE; + } + + if (!model || !model->user_data) { + BT_ERR("%s, Invalid parameter", __func__); + return ROLE_NVAL; + } + + client = (bt_mesh_client_common_t *)model->user_data; + + return client->msg_role; +} diff --git a/components/bt/ble_mesh/mesh_models/sensor_client.c b/components/bt/ble_mesh/mesh_models/sensor_client.c new file mode 100644 index 0000000000..1933d1027a --- /dev/null +++ b/components/bt/ble_mesh/mesh_models/sensor_client.c @@ -0,0 +1,616 @@ +// Copyright 2017-2018 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 +#include +#include + +#include "osi/allocator.h" +#include "sdkconfig.h" + +#include "mesh_types.h" +#include "mesh_kernel.h" +#include "mesh_trace.h" + +#include "mesh.h" +#include "model_opcode.h" +#include "mesh_common.h" +#include "sensor_client.h" + +#include "btc_ble_mesh_sensor_model.h" + +/** The following are the macro definitions of sensor client + * model messages length, and a message is composed of three + * parts: Opcode + msg_value + MIC + */ +/* Sensor client messages length */ +#define BLE_MESH_SENSOR_DESCRIPTOR_GET_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_SENSOR_CADENCE_GET_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_SENSOR_CADENCE_SET_MSG_LEN /* variable */ +#define BLE_MESH_SENSOR_SETTINGS_GET_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_SENSOR_SETTING_GET_MSG_LEN (2 + 4 + 4) +#define BLE_MESH_SENSOR_SETTING_SET_MSG_LEN /* variable */ +#define BLE_MESH_SENSOR_GET_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_SENSOR_COLUMN_GET_MSG_LEN /* variable */ +#define BLE_MESH_SENSOR_SERIES_GET_MSG_LEN /* variable */ + +static const bt_mesh_client_op_pair_t sensor_op_pair[] = { + { BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET, BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS }, + { BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET, BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS }, + { BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET, BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS }, + { BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET, BLE_MESH_MODEL_OP_SENSOR_SETTINGS_STATUS }, + { BLE_MESH_MODEL_OP_SENSOR_SETTING_GET, BLE_MESH_MODEL_OP_SENSOR_SETTING_STATUS }, + { BLE_MESH_MODEL_OP_SENSOR_SETTING_SET, BLE_MESH_MODEL_OP_SENSOR_SETTING_STATUS }, + { BLE_MESH_MODEL_OP_SENSOR_GET, BLE_MESH_MODEL_OP_SENSOR_STATUS }, + { BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET, BLE_MESH_MODEL_OP_SENSOR_COLUMN_STATUS }, + { BLE_MESH_MODEL_OP_SENSOR_SERIES_GET, BLE_MESH_MODEL_OP_SENSOR_SERIES_STATUS }, +}; + +static void timeout_handler(struct k_work *work) +{ + sensor_internal_data_t *internal = NULL; + bt_mesh_sensor_client_t *client = NULL; + bt_mesh_client_node_t *node = NULL; + + BT_WARN("Receive sensor status message timeout"); + + node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work); + if (!node || !node->ctx.model) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + client = (bt_mesh_sensor_client_t *)node->ctx.model->user_data; + if (!client) { + BT_ERR("%s, Sensor Client user_data is NULL", __func__); + return; + } + + internal = (sensor_internal_data_t *)client->internal_data; + if (!internal) { + BT_ERR("%s, Sensor Client internal_data is NULL", __func__); + return; + } + + bt_mesh_callback_sensor_status_to_btc(node->opcode, 0x03, node->ctx.model, + &node->ctx, NULL, 0); + + bt_mesh_client_free_node(&internal->queue, node); + + return; +} + +static void sensor_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + sensor_internal_data_t *internal = NULL; + bt_mesh_sensor_client_t *client = NULL; + bt_mesh_client_node_t *node = NULL; + u8_t *val = NULL; + u8_t evt = 0xFF; + u32_t rsp = 0; + size_t len = 0; + + BT_DBG("%s, len %d, bytes %s", __func__, buf->len, bt_hex(buf->data, buf->len)); + + client = (bt_mesh_sensor_client_t *)model->user_data; + if (!client) { + BT_ERR("%s, Sensor Client user_data is NULL", __func__); + return; + } + + internal = (sensor_internal_data_t *)client->internal_data; + if (!internal) { + BT_ERR("%s, Sensor Client internal_data is NULL", __func__); + return; + } + + rsp = ctx->recv_op; + switch (rsp) { + case BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS: { + struct bt_mesh_sensor_descriptor_status *status = NULL; + status = osi_calloc(sizeof(struct bt_mesh_sensor_descriptor_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->descriptor = bt_mesh_alloc_buf(buf->len); + if (!status->descriptor) { + BT_ERR("%s, Failed to allocate memory", __func__); + osi_free(status); + return; + } + net_buf_simple_add_mem(status->descriptor, buf->data, buf->len); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_sensor_descriptor_status); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS: { + struct bt_mesh_sensor_cadence_status *status = NULL; + status = osi_calloc(sizeof(struct bt_mesh_sensor_cadence_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->property_id = net_buf_simple_pull_le16(buf); + status->sensor_cadence_value = bt_mesh_alloc_buf(buf->len); + if (!status->sensor_cadence_value) { + BT_ERR("%s, Failed to allocate memory", __func__); + osi_free(status); + return; + } + net_buf_simple_add_mem(status->sensor_cadence_value, buf->data, buf->len); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_sensor_cadence_status); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SETTINGS_STATUS: { + struct bt_mesh_sensor_settings_status *status = NULL; + status = osi_calloc(sizeof(struct bt_mesh_sensor_settings_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->sensor_property_id = net_buf_simple_pull_le16(buf); + status->sensor_setting_property_ids = bt_mesh_alloc_buf(buf->len); + if (!status->sensor_setting_property_ids) { + BT_ERR("%s, Failed to allocate memory", __func__); + osi_free(status); + return; + } + net_buf_simple_add_mem(status->sensor_setting_property_ids, buf->data, buf->len); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_sensor_settings_status); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SETTING_STATUS: { + struct bt_mesh_sensor_setting_status *status = NULL; + status = osi_calloc(sizeof(struct bt_mesh_sensor_setting_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->sensor_property_id = net_buf_simple_pull_le16(buf); + status->sensor_setting_property_id = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->sensor_setting_access = net_buf_simple_pull_u8(buf); + status->sensor_setting_raw = bt_mesh_alloc_buf(buf->len); + if (!status->sensor_setting_raw) { + BT_ERR("%s, Failed to allocate memory", __func__); + osi_free(status); + return; + } + net_buf_simple_add_mem(status->sensor_setting_raw, buf->data, buf->len); + } + val = (u8_t *)status; + len = sizeof(struct bt_mesh_sensor_setting_status); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_STATUS: { + struct bt_mesh_sensor_status *status = NULL; + status = osi_calloc(sizeof(struct bt_mesh_sensor_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->marshalled_sensor_data = bt_mesh_alloc_buf(buf->len); + if (!status->marshalled_sensor_data) { + BT_ERR("%s, Failed to allocate memory", __func__); + osi_free(status); + return; + } + net_buf_simple_add_mem(status->marshalled_sensor_data, buf->data, buf->len); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_sensor_status); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_COLUMN_STATUS: { + struct bt_mesh_sensor_column_status *status = NULL; + status = osi_calloc(sizeof(struct bt_mesh_sensor_column_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->property_id = net_buf_simple_pull_le16(buf); + status->sensor_column_value = bt_mesh_alloc_buf(buf->len); + if (!status->sensor_column_value) { + BT_ERR("%s, Failed to allocate memory", __func__); + osi_free(status); + return; + } + net_buf_simple_add_mem(status->sensor_column_value, buf->data, buf->len); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_sensor_column_status); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SERIES_STATUS: { + struct bt_mesh_sensor_series_status *status = NULL; + status = osi_calloc(sizeof(struct bt_mesh_sensor_series_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->property_id = net_buf_simple_pull_le16(buf); + status->sensor_series_value = bt_mesh_alloc_buf(buf->len); + if (!status->sensor_series_value) { + BT_ERR("%s, Failed to allocate memory", __func__); + osi_free(status); + return; + } + net_buf_simple_add_mem(status->sensor_series_value, buf->data, buf->len); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_sensor_series_status); + break; + } + default: + BT_ERR("%s, Not a Sensor Status message opcode", __func__); + return; + } + + buf->data = val; + buf->len = len; + node = bt_mesh_is_model_message_publish(model, ctx, buf, true); + if (!node) { + BT_DBG("Unexpected sensor status message 0x%x", rsp); + } else { + switch (node->opcode) { + case BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET: + case BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET: + case BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET: + case BLE_MESH_MODEL_OP_SENSOR_SETTING_GET: + case BLE_MESH_MODEL_OP_SENSOR_GET: + case BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET: + case BLE_MESH_MODEL_OP_SENSOR_SERIES_GET: + evt = 0x00; + break; + case BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET: + case BLE_MESH_MODEL_OP_SENSOR_SETTING_SET: + evt = 0x01; + break; + default: + break; + } + + bt_mesh_callback_sensor_status_to_btc(node->opcode, evt, model, ctx, val, len); + // Don't forget to release the node at the end. + bt_mesh_client_free_node(&internal->queue, node); + } + + switch (rsp) { + case BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS: { + struct bt_mesh_sensor_descriptor_status *status; + status = (struct bt_mesh_sensor_descriptor_status *)val; + bt_mesh_free_buf(status->descriptor); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS: { + struct bt_mesh_sensor_cadence_status *status; + status = (struct bt_mesh_sensor_cadence_status *)val; + bt_mesh_free_buf(status->sensor_cadence_value); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SETTINGS_STATUS: { + struct bt_mesh_sensor_settings_status *status; + status = (struct bt_mesh_sensor_settings_status *)val; + bt_mesh_free_buf(status->sensor_setting_property_ids); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SETTING_STATUS: { + struct bt_mesh_sensor_setting_status *status; + status = (struct bt_mesh_sensor_setting_status *)val; + bt_mesh_free_buf(status->sensor_setting_raw); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_STATUS: { + struct bt_mesh_sensor_status *status; + status = (struct bt_mesh_sensor_status *)val; + bt_mesh_free_buf(status->marshalled_sensor_data); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_COLUMN_STATUS: { + struct bt_mesh_sensor_column_status *status; + status = (struct bt_mesh_sensor_column_status *)val; + bt_mesh_free_buf(status->sensor_column_value); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SERIES_STATUS: { + struct bt_mesh_sensor_series_status *status; + status = (struct bt_mesh_sensor_series_status *)val; + bt_mesh_free_buf(status->sensor_series_value); + break; + } + default: + break; + } + + osi_free(val); + + return; +} + +const struct bt_mesh_model_op sensor_cli_op[] = { + { BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS, 0, sensor_status }, + { BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS, 2, sensor_status }, + { BLE_MESH_MODEL_OP_SENSOR_SETTINGS_STATUS, 2, sensor_status }, + { BLE_MESH_MODEL_OP_SENSOR_SETTING_STATUS, 4, sensor_status }, + { BLE_MESH_MODEL_OP_SENSOR_STATUS, 0, sensor_status }, + { BLE_MESH_MODEL_OP_SENSOR_COLUMN_STATUS, 2, sensor_status }, + { BLE_MESH_MODEL_OP_SENSOR_SERIES_STATUS, 2, sensor_status }, + BLE_MESH_MODEL_OP_END, +}; + +static int sensor_act_state(struct bt_mesh_common_param *common, + void *value, u16_t value_len, bool need_ack) +{ + struct net_buf_simple *msg = NULL; + int err; + + msg = bt_mesh_alloc_buf(value_len); + if (!msg) { + BT_ERR("%s, Failed to allocate memory", __func__); + return -ENOMEM; + } + + bt_mesh_model_msg_init(msg, common->opcode); + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET: { + struct bt_mesh_sensor_descriptor_get *act; + act = (struct bt_mesh_sensor_descriptor_get *)value; + if (act->op_en) { + net_buf_simple_add_le16(msg, act->property_id); + } + break; + } + case BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET: { + struct bt_mesh_sensor_cadence_get *act; + act = (struct bt_mesh_sensor_cadence_get *)value; + net_buf_simple_add_le16(msg, act->property_id); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET: + case BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK: { + struct bt_mesh_sensor_cadence_set *act; + act = (struct bt_mesh_sensor_cadence_set *)value; + net_buf_simple_add_le16(msg, act->property_id); + net_buf_simple_add_u8(msg, act->status_trigger_type << 7 | act->fast_cadence_period_divisor); + net_buf_simple_add_mem(msg, act->status_trigger_delta_down->data, act->status_trigger_delta_down->len); + net_buf_simple_add_mem(msg, act->status_trigger_delta_up->data, act->status_trigger_delta_up->len); + net_buf_simple_add_u8(msg, act->status_min_interval); + net_buf_simple_add_mem(msg, act->fast_cadence_low->data, act->fast_cadence_low->len); + net_buf_simple_add_mem(msg, act->fast_cadence_high->data, act->fast_cadence_high->len); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET: { + struct bt_mesh_sensor_settings_get *act; + act = (struct bt_mesh_sensor_settings_get *)value; + net_buf_simple_add_le16(msg, act->sensor_property_id); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SETTING_GET: { + struct bt_mesh_sensor_setting_get *act; + act = (struct bt_mesh_sensor_setting_get *)value; + net_buf_simple_add_le16(msg, act->sensor_property_id); + net_buf_simple_add_le16(msg, act->sensor_setting_property_id); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SETTING_SET: + case BLE_MESH_MODEL_OP_SENSOR_SETTING_SET_UNACK: { + struct bt_mesh_sensor_setting_set *act; + act = (struct bt_mesh_sensor_setting_set *)value; + net_buf_simple_add_le16(msg, act->sensor_property_id); + net_buf_simple_add_le16(msg, act->sensor_setting_property_id); + net_buf_simple_add_mem(msg, act->sensor_setting_raw->data, act->sensor_setting_raw->len); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_GET: { + struct bt_mesh_sensor_get *act; + act = (struct bt_mesh_sensor_get *)value; + if (act->op_en) { + net_buf_simple_add_le16(msg, act->property_id); + } + break; + } + case BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET: { + struct bt_mesh_sensor_column_get *act; + act = (struct bt_mesh_sensor_column_get *)value; + net_buf_simple_add_le16(msg, act->property_id); + net_buf_simple_add_mem(msg, act->raw_value_x->data, act->raw_value_x->len); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SERIES_GET: { + struct bt_mesh_sensor_series_get *act; + act = (struct bt_mesh_sensor_series_get *)value; + net_buf_simple_add_le16(msg, act->property_id); + if (act->op_en) { + net_buf_simple_add_mem(msg, act->raw_value_x1->data, act->raw_value_x1->len); + net_buf_simple_add_mem(msg, act->raw_value_x2->data, act->raw_value_x2->len); + } + break; + } + default: + BT_ERR("%s, Not a Sensor Client message opcode", __func__); + err = -EINVAL; + goto end; + } + + err = bt_mesh_client_send_msg(common->model, common->opcode, &common->ctx, msg, + timeout_handler, common->msg_timeout, need_ack, + common->cb, common->cb_data); + if (err) { + BT_ERR("%s, Failed to send Sensor Client message (err %d)", __func__, err); + } + +end: + bt_mesh_free_buf(msg); + + return err; +} + +int bt_mesh_sensor_client_get_state(struct bt_mesh_common_param *common, void *get, void *status) +{ + bt_mesh_sensor_client_t *client = NULL; + u16_t length = 0; + + if (!common || !common->model || !get) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_sensor_client_t *)common->model->user_data; + if (!client || !client->internal_data) { + BT_ERR("%s, Sensor Client user data is NULL", __func__); + return -EINVAL; + } + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET: + length = BLE_MESH_SENSOR_DESCRIPTOR_GET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET: + length = BLE_MESH_SENSOR_CADENCE_GET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET: + length = BLE_MESH_SENSOR_SETTINGS_GET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_SENSOR_SETTING_GET: + length = BLE_MESH_SENSOR_SETTING_GET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_SENSOR_GET: + length = BLE_MESH_SENSOR_GET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET: { + struct bt_mesh_sensor_column_get *value; + value = (struct bt_mesh_sensor_column_get *)get; + if (!value->raw_value_x) { + BT_ERR("%s, Sensor column_get is NULL", __func__); + return -EINVAL; + } + length = (2 + 2 + value->raw_value_x->len + 4); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SERIES_GET: { + struct bt_mesh_sensor_series_get *value; + value = (struct bt_mesh_sensor_series_get *)get; + if (value->op_en) { + if (!value->raw_value_x1 || !value->raw_value_x2) { + BT_ERR("%s, Sensor series_get is NULL", __func__); + return -EINVAL; + } + } + if (value->op_en) { + length = value->raw_value_x1->len + value->raw_value_x2->len; + } + length += (2 + 2 + 4); + break; + } + default: + BT_ERR("%s, Not a Sensor Client Get message opcode", __func__); + return -EINVAL; + } + + return sensor_act_state(common, get, length, true); +} + +int bt_mesh_sensor_client_set_state(struct bt_mesh_common_param *common, void *set, void *status) +{ + bt_mesh_sensor_client_t *client = NULL; + u16_t length = 0; + bool need_ack = false; + + if (!common || !common->model || !set) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_sensor_client_t *)common->model->user_data; + if (!client || !client->internal_data) { + BT_ERR("%s, Sensor Client user data is NULL", __func__); + return -EINVAL; + } + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK: { + struct bt_mesh_sensor_cadence_set *value; + value = (struct bt_mesh_sensor_cadence_set *)set; + if (!value->status_trigger_delta_down || !value->status_trigger_delta_up || + !value->fast_cadence_low || !value->fast_cadence_high) { + BT_ERR("%s, Sensor cadence_set is NULL", __func__); + return -EINVAL; + } + length = value->status_trigger_delta_down->len + \ + value->status_trigger_delta_up->len + \ + value->fast_cadence_low->len + \ + value->fast_cadence_high->len; + length += (1 + 2 + 1 + 1 + 4); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SETTING_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_SENSOR_SETTING_SET_UNACK: { + struct bt_mesh_sensor_setting_set *value; + value = (struct bt_mesh_sensor_setting_set *)set; + if (!value->sensor_setting_raw) { + BT_ERR("%s, Sensor setting_raw is NULL", __func__); + return -EINVAL; + } + length = (1 + 2 + 2 + value->sensor_setting_raw->len + 4); + break; + } + default: + BT_ERR("%s, Not a Sensor Client Set message opcode", __func__); + return -EINVAL; + } + + return sensor_act_state(common, set, length, need_ack); +} + +int bt_mesh_sensor_cli_init(struct bt_mesh_model *model, bool primary) +{ + sensor_internal_data_t *internal = NULL; + bt_mesh_sensor_client_t *client = NULL; + + BT_DBG("primary %u", primary); + + if (!model) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_sensor_client_t *)model->user_data; + if (!client) { + BT_ERR("%s, Sensor Client user_data is NULL", __func__); + return -EINVAL; + } + + /* TODO: call osi_free() when deinit function is invoked*/ + internal = osi_calloc(sizeof(sensor_internal_data_t)); + if (!internal) { + BT_ERR("%s, Failed to allocate memory", __func__); + return -ENOMEM; + } + + sys_slist_init(&internal->queue); + + client->model = model; + client->op_pair_size = ARRAY_SIZE(sensor_op_pair); + client->op_pair = sensor_op_pair; + client->internal_data = internal; + + return 0; +} \ No newline at end of file diff --git a/components/bt/ble_mesh/mesh_models/time_scene_client.c b/components/bt/ble_mesh/mesh_models/time_scene_client.c new file mode 100644 index 0000000000..3296edf925 --- /dev/null +++ b/components/bt/ble_mesh/mesh_models/time_scene_client.c @@ -0,0 +1,694 @@ +// Copyright 2017-2018 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 +#include +#include + +#include "osi/allocator.h" +#include "sdkconfig.h" + +#include "mesh_types.h" +#include "mesh_kernel.h" +#include "mesh_trace.h" + +#include "mesh.h" +#include "model_opcode.h" +#include "mesh_common.h" +#include "time_scene_client.h" + +#include "btc_ble_mesh_time_scene_model.h" + +/** The following are the macro definitions of time and client + * scene model messages length, and a message is composed of + * three parts: Opcode + msg_value + MIC + */ +/* Time client messages length */ +#define BLE_MESH_TIME_SET_MSG_LEN (1 + 10 + 4) +#define BLE_MESH_TIME_ZONE_SET_MSG_LEN (2 + 6 + 4) +#define BLE_MESH_TAI_UTC_DELTA_SET_MSG_LEN (2 + 7 + 4) +#define BLE_MESH_TIME_ROLE_SET_MSG_LEN (2 + 1 + 4) + +/* Scene client messages length */ +#define BLE_MESH_SCENE_STORE_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_SCENE_RECALL_MSG_LEN (2 + 5 + 4) +#define BLE_MESH_SCENE_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_SCENE_REGISTER_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_SCENE_DELETE_MSG_LEN (2 + 2 + 4) + +/* Scheduler client messages length */ +#define BLE_MESH_SCHEDULER_ACT_GET_MSG_LEN (2 + 1 + 4) +#define BLE_MESH_SCHEDULER_ACT_SET_MSG_LEN (1 + 10 + 4) + +#define BLE_MESH_SCENE_GET_STATE_MSG_LEN (2 + 1 + 4) +#define BLE_MESH_SCENE_ACT_STATE_MSG_LEN (2 + 2 + 4) + +static const bt_mesh_client_op_pair_t time_scene_op_pair[] = { + { BLE_MESH_MODEL_OP_TIME_GET, BLE_MESH_MODEL_OP_TIME_STATUS }, + { BLE_MESH_MODEL_OP_TIME_SET, BLE_MESH_MODEL_OP_TIME_STATUS }, + { BLE_MESH_MODEL_OP_TIME_ZONE_GET, BLE_MESH_MODEL_OP_TIME_ZONE_STATUS }, + { BLE_MESH_MODEL_OP_TIME_ZONE_SET, BLE_MESH_MODEL_OP_TIME_ZONE_STATUS }, + { BLE_MESH_MODEL_OP_TAI_UTC_DELTA_GET, BLE_MESH_MODEL_OP_TAI_UTC_DELTA_STATUS }, + { BLE_MESH_MODEL_OP_TAI_UTC_DELTA_SET, BLE_MESH_MODEL_OP_TAI_UTC_DELTA_STATUS }, + { BLE_MESH_MODEL_OP_TIME_ROLE_GET, BLE_MESH_MODEL_OP_TIME_ROLE_STATUS }, + { BLE_MESH_MODEL_OP_TIME_ROLE_SET, BLE_MESH_MODEL_OP_TIME_ROLE_STATUS }, + { BLE_MESH_MODEL_OP_SCENE_STORE, BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS }, + { BLE_MESH_MODEL_OP_SCENE_RECALL, BLE_MESH_MODEL_OP_SCENE_STATUS }, + { BLE_MESH_MODEL_OP_SCENE_GET, BLE_MESH_MODEL_OP_SCENE_STATUS }, + { BLE_MESH_MODEL_OP_SCENE_REGISTER_GET, BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS }, + { BLE_MESH_MODEL_OP_SCENE_DELETE, BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS }, + { BLE_MESH_MODEL_OP_SCHEDULER_GET, BLE_MESH_MODEL_OP_SCHEDULER_STATUS }, + { BLE_MESH_MODEL_OP_SCHEDULER_ACT_GET, BLE_MESH_MODEL_OP_SCHEDULER_ACT_STATUS }, + { BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET, BLE_MESH_MODEL_OP_SCHEDULER_ACT_STATUS }, +}; + +static void timeout_handler(struct k_work *work) +{ + time_scene_internal_data_t *internal = NULL; + bt_mesh_time_scene_client_t *client = NULL; + bt_mesh_client_node_t *node = NULL; + + BT_WARN("Receive time scene status message timeout"); + + node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work); + if (!node || !node->ctx.model) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + client = (bt_mesh_time_scene_client_t *)node->ctx.model->user_data; + if (!client) { + BT_ERR("%s, Time Scene Client user_data is NULL", __func__); + return; + } + + internal = (time_scene_internal_data_t *)client->internal_data; + if (!internal) { + BT_ERR("%s, Time Scene Client internal_data is NULL", __func__); + return; + } + + bt_mesh_callback_time_scene_status_to_btc(node->opcode, 0x03, node->ctx.model, + &node->ctx, NULL, 0); + + bt_mesh_client_free_node(&internal->queue, node); + + return; +} + +static void time_scene_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + time_scene_internal_data_t *internal = NULL; + bt_mesh_time_scene_client_t *client = NULL; + bt_mesh_client_node_t *node = NULL; + u8_t *val = NULL; + u8_t evt = 0xFF; + u32_t rsp = 0; + size_t len = 0; + + BT_DBG("%s, len %d, bytes %s", __func__, buf->len, bt_hex(buf->data, buf->len)); + + client = (bt_mesh_time_scene_client_t *)model->user_data; + if (!client) { + BT_ERR("%s, Time Scene Client user_data is NULL", __func__); + return; + } + + internal = (time_scene_internal_data_t *)client->internal_data; + if (!internal) { + BT_ERR("%s, Time Scene Client internal_data is NULL", __func__); + return; + } + + rsp = ctx->recv_op; + switch (rsp) { + case BLE_MESH_MODEL_OP_TIME_STATUS: { + struct bt_mesh_time_status *status = NULL; + if (buf->len != 5 && buf->len != 10) { + BT_ERR("%s, Invalid Time Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_time_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + memcpy(status->tai_seconds, buf->data, 5); + net_buf_simple_pull(buf, 5); + status->sub_second = net_buf_simple_pull_u8(buf); + status->uncertainty = net_buf_simple_pull_u8(buf); + u16_t temp = net_buf_simple_pull_le16(buf); + status->time_authority = temp & BIT(0); + status->tai_utc_delta = temp >> 15; + status->time_zone_offset = net_buf_simple_pull_u8(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_time_status); + break; + } + case BLE_MESH_MODEL_OP_TIME_ZONE_STATUS: { + struct bt_mesh_time_zone_status *status = NULL; + if (buf->len != 7) { + BT_ERR("%s, Invalid Time Zone Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_time_zone_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->time_zone_offset_curr = net_buf_simple_pull_u8(buf); + status->time_zone_offset_new = net_buf_simple_pull_u8(buf); + memcpy(status->tai_zone_change, buf->data, 5); + net_buf_simple_pull(buf, 5); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_time_zone_status); + break; + } + case BLE_MESH_MODEL_OP_TAI_UTC_DELTA_STATUS: { + struct bt_mesh_tai_utc_delta_status *status = NULL; + if (buf->len != 9) { + BT_ERR("%s, Invalid TAI UTC Delta Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_tai_utc_delta_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + u16_t temp = net_buf_simple_pull_le16(buf); + status->tai_utc_delta_curr = temp & BIT_MASK(15); + status->padding_1 = (temp >> 15) & BIT(0); + temp = net_buf_simple_pull_le16(buf); + status->tai_utc_delta_new = temp & BIT_MASK(15); + status->padding_2 = (temp >> 15) & BIT(0); + memcpy(status->tai_delta_change, buf->data, 5); + net_buf_simple_pull(buf, 5); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_tai_utc_delta_status); + break; + } + case BLE_MESH_MODEL_OP_TIME_ROLE_STATUS: { + struct bt_mesh_time_role_status *status = NULL; + if (buf->len != 1) { + BT_ERR("%s, Invalid Time Role Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_time_role_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->time_role = net_buf_simple_pull_u8(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_time_role_status); + break; + } + case BLE_MESH_MODEL_OP_SCENE_STATUS: { + struct bt_mesh_scene_status *status = NULL; + if (buf->len != 3 && buf->len != 6) { + BT_ERR("%s, Invalid Scene Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_scene_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->status_code = net_buf_simple_pull_u8(buf); + status->current_scene = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->target_scene = net_buf_simple_pull_le16(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (u8_t *)status; + len = sizeof(struct bt_mesh_scene_status); + break; + } + case BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS: { + struct bt_mesh_scene_register_status *status = NULL; + status = osi_calloc(sizeof(struct bt_mesh_scene_register_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->status_code = net_buf_simple_pull_u8(buf); + status->current_scene = net_buf_simple_pull_le16(buf); + status->scenes = bt_mesh_alloc_buf(buf->len); + if (!status->scenes) { + BT_ERR("%s, Failed to allocate memory", __func__); + osi_free(status); + return; + } + net_buf_simple_add_mem(status->scenes, buf->data, buf->len); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_scene_register_status); + break; + } + case BLE_MESH_MODEL_OP_SCHEDULER_STATUS: { + struct bt_mesh_scheduler_status *status = NULL; + if (buf->len != 2) { + BT_ERR("%s, Invalid Scheduler Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_scheduler_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + status->schedules = net_buf_simple_pull_le16(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_scheduler_status); + break; + } + case BLE_MESH_MODEL_OP_SCHEDULER_ACT_STATUS: { + struct bt_mesh_scheduler_act_status *status = NULL; + if (buf->len != 10) { + BT_ERR("%s, Invalid Scheduler Action Status length %d", __func__, buf->len); + return; + } + status = osi_calloc(sizeof(struct bt_mesh_scheduler_act_status)); + if (!status) { + BT_ERR("%s, Failed to allocate memory", __func__); + return; + } + memcpy(status, buf->data, offsetof(struct bt_mesh_scheduler_act_status, scene_number)); + net_buf_simple_pull(buf, offsetof(struct bt_mesh_scheduler_act_status, scene_number)); + status->scene_number = net_buf_simple_pull_le16(buf); + val = (u8_t *)status; + len = sizeof(struct bt_mesh_scheduler_act_status); + break; + } + default: + BT_ERR("%s, Not a Time Scene Status message opcode", __func__); + return; + } + + buf->data = val; + buf->len = len; + node = bt_mesh_is_model_message_publish(model, ctx, buf, true); + if (!node) { + BT_DBG("Unexpected time scene status message 0x%x", rsp); + } else { + switch (node->opcode) { + case BLE_MESH_MODEL_OP_TIME_GET: + case BLE_MESH_MODEL_OP_TIME_ZONE_GET: + case BLE_MESH_MODEL_OP_TAI_UTC_DELTA_GET: + case BLE_MESH_MODEL_OP_TIME_ROLE_GET: + case BLE_MESH_MODEL_OP_SCENE_GET: + case BLE_MESH_MODEL_OP_SCENE_REGISTER_GET: + case BLE_MESH_MODEL_OP_SCHEDULER_GET: + case BLE_MESH_MODEL_OP_SCHEDULER_ACT_GET: + evt = 0x00; + break; + case BLE_MESH_MODEL_OP_TIME_SET: + case BLE_MESH_MODEL_OP_TIME_ZONE_SET: + case BLE_MESH_MODEL_OP_TAI_UTC_DELTA_SET: + case BLE_MESH_MODEL_OP_TIME_ROLE_SET: + case BLE_MESH_MODEL_OP_SCENE_STORE: + case BLE_MESH_MODEL_OP_SCENE_RECALL: + case BLE_MESH_MODEL_OP_SCENE_DELETE: + case BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET: + evt = 0x01; + break; + default: + break; + } + + bt_mesh_callback_time_scene_status_to_btc(node->opcode, evt, model, ctx, val, len); + // Don't forget to release the node at the end. + bt_mesh_client_free_node(&internal->queue, node); + } + + switch (rsp) { + case BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS: { + struct bt_mesh_scene_register_status *status; + status = (struct bt_mesh_scene_register_status *)val; + bt_mesh_free_buf(status->scenes); + break; + } + default: + break; + } + + osi_free(val); + + return; +} + +const struct bt_mesh_model_op time_cli_op[] = { + { BLE_MESH_MODEL_OP_TIME_STATUS, 5, time_scene_status }, + { BLE_MESH_MODEL_OP_TIME_ZONE_STATUS, 7, time_scene_status }, + { BLE_MESH_MODEL_OP_TAI_UTC_DELTA_STATUS, 9, time_scene_status }, + { BLE_MESH_MODEL_OP_TIME_ROLE_STATUS, 1, time_scene_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op scene_cli_op[] = { + { BLE_MESH_MODEL_OP_SCENE_STATUS, 3, time_scene_status }, + { BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS, 3, time_scene_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op scheduler_cli_op[] = { + { BLE_MESH_MODEL_OP_SCHEDULER_STATUS, 2, time_scene_status }, + { BLE_MESH_MODEL_OP_SCHEDULER_ACT_STATUS, 10, time_scene_status }, + BLE_MESH_MODEL_OP_END, +}; + +static int time_scene_get_state(struct bt_mesh_common_param *common, void *value) +{ + NET_BUF_SIMPLE_DEFINE(msg, BLE_MESH_SCENE_GET_STATE_MSG_LEN); + int err; + + bt_mesh_model_msg_init(&msg, common->opcode); + + if (value) { + switch (common->opcode) { + case BLE_MESH_MODEL_OP_SCHEDULER_ACT_GET: { + struct bt_mesh_scheduler_act_get *get; + get = (struct bt_mesh_scheduler_act_get *)value; + net_buf_simple_add_u8(&msg, get->index); + break; + } + default: + BT_DBG("This time scene message should be sent with NULL get pointer"); + break; + } + } + + err = bt_mesh_client_send_msg(common->model, common->opcode, &common->ctx, &msg, + timeout_handler, common->msg_timeout, true, + common->cb, common->cb_data); + if (err) { + BT_ERR("%s, Failed to send Time Scene Get message (err %d)", __func__, err); + } + + return err; +} + +static int time_scene_set_state(struct bt_mesh_common_param *common, + void *value, u16_t value_len, bool need_ack) +{ + struct net_buf_simple *msg = NULL; + int err; + + msg = bt_mesh_alloc_buf(value_len); + if (!msg) { + BT_ERR("%s, Failed to allocate memory", __func__); + return -ENOMEM; + } + + bt_mesh_model_msg_init(msg, common->opcode); + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_TIME_SET: { + struct bt_mesh_time_set *set; + set = (struct bt_mesh_time_set *)value; + net_buf_simple_add_mem(msg, set->tai_seconds, 5); + net_buf_simple_add_u8(msg, set->sub_second); + net_buf_simple_add_u8(msg, set->uncertainty); + net_buf_simple_add_le16(msg, set->tai_utc_delta << 1 | set->time_authority); + net_buf_simple_add_u8(msg, set->time_zone_offset); + break; + } + case BLE_MESH_MODEL_OP_TIME_ZONE_SET: { + struct bt_mesh_time_zone_set *set; + set = (struct bt_mesh_time_zone_set *)value; + net_buf_simple_add_u8(msg, set->time_zone_offset_new); + net_buf_simple_add_mem(msg, set->tai_zone_change, 5); + break; + } + case BLE_MESH_MODEL_OP_TAI_UTC_DELTA_SET: { + struct bt_mesh_tai_utc_delta_set *set; + set = (struct bt_mesh_tai_utc_delta_set *)value; + net_buf_simple_add_le16(msg, set->padding << 15 | set->tai_utc_delta_new); + net_buf_simple_add_mem(msg, set->tai_delta_change, 5); + break; + } + case BLE_MESH_MODEL_OP_TIME_ROLE_SET: { + struct bt_mesh_time_role_set *set; + set = (struct bt_mesh_time_role_set *)value; + net_buf_simple_add_u8(msg, set->time_role); + break; + } + case BLE_MESH_MODEL_OP_SCENE_STORE: + case BLE_MESH_MODEL_OP_SCENE_STORE_UNACK: { + struct bt_mesh_scene_store *set; + set = (struct bt_mesh_scene_store *)value; + net_buf_simple_add_le16(msg, set->scene_number); + break; + } + case BLE_MESH_MODEL_OP_SCENE_RECALL: + case BLE_MESH_MODEL_OP_SCENE_RECALL_UNACK: { + struct bt_mesh_scene_recall *set; + set = (struct bt_mesh_scene_recall *)value; + net_buf_simple_add_le16(msg, set->scene_number); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + case BLE_MESH_MODEL_OP_SCENE_DELETE: + case BLE_MESH_MODEL_OP_SCENE_DELETE_UNACK: { + struct bt_mesh_scene_delete *set; + set = (struct bt_mesh_scene_delete *)value; + net_buf_simple_add_le16(msg, set->scene_number); + break; + } + case BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET: + case BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET_UNACK: { + struct bt_mesh_scheduler_act_set *set; + set = (struct bt_mesh_scheduler_act_set *)value; + net_buf_simple_add_mem(msg, set, offsetof(struct bt_mesh_scheduler_act_set, scene_number)); + net_buf_simple_add_le16(msg, set->scene_number); + break; + } + default: + BT_ERR("%s, Not a Time Scene Client set message opcode", __func__); + err = -EINVAL; + goto end; + } + + err = bt_mesh_client_send_msg(common->model, common->opcode, &common->ctx, msg, + timeout_handler, common->msg_timeout, need_ack, + common->cb, common->cb_data); + if (err) { + BT_ERR("%s, Failed to send Time Scene Set message (err %d)", __func__, err); + } + +end: + bt_mesh_free_buf(msg); + return err; +} + +int bt_mesh_time_scene_client_get_state(struct bt_mesh_common_param *common, void *get, void *status) +{ + bt_mesh_time_scene_client_t *client = NULL; + + if (!common || !common->model) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_time_scene_client_t *)common->model->user_data; + if (!client || !client->internal_data) { + BT_ERR("%s, Time Scene Client user data is NULL", __func__); + return -EINVAL; + } + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_TIME_GET: + case BLE_MESH_MODEL_OP_TIME_ZONE_GET: + case BLE_MESH_MODEL_OP_TAI_UTC_DELTA_GET: + case BLE_MESH_MODEL_OP_TIME_ROLE_GET: + case BLE_MESH_MODEL_OP_SCENE_GET: + case BLE_MESH_MODEL_OP_SCENE_REGISTER_GET: + case BLE_MESH_MODEL_OP_SCHEDULER_GET: + break; + case BLE_MESH_MODEL_OP_SCHEDULER_ACT_GET: + if (!get) { + BT_ERR("%s, Scheduler action index is NULL", __func__); + return -EINVAL; + } + break; + default: + BT_ERR("%s, Not a Time Scene Client Get message opcode", __func__); + return -EINVAL; + } + + return time_scene_get_state(common, get); +} + +int bt_mesh_time_scene_client_set_state(struct bt_mesh_common_param *common, void *set, void *status) +{ + bt_mesh_time_scene_client_t *client = NULL; + u16_t length = 0; + bool need_ack = false; + + if (!common || !common->model || !set) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_time_scene_client_t *)common->model->user_data; + if (!client || !client->internal_data) { + BT_ERR("%s, Time Scene Client user data is NULL", __func__); + return -EINVAL; + } + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_TIME_SET: + need_ack = true; + length = BLE_MESH_TIME_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_TIME_ZONE_SET: + need_ack = true; + length = BLE_MESH_TIME_ZONE_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_TAI_UTC_DELTA_SET: { + struct bt_mesh_tai_utc_delta_set *value; + value = (struct bt_mesh_tai_utc_delta_set *)set; + if (value->padding) { + BT_ERR("%s, Non-zero padding value is prohibited", __func__); + return -EINVAL; + } + need_ack = true; + length = BLE_MESH_TAI_UTC_DELTA_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_TIME_ROLE_SET: { + struct bt_mesh_time_role_set *value; + value = (struct bt_mesh_time_role_set *)set; + if (value->time_role > 0x03) { + BT_ERR("%s, Time role value is prohibited", __func__); + return -EINVAL; + } + need_ack = true; + length = BLE_MESH_TIME_ROLE_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_SCENE_STORE: + need_ack = true; + case BLE_MESH_MODEL_OP_SCENE_STORE_UNACK: { + struct bt_mesh_scene_store *value; + value = (struct bt_mesh_scene_store *)set; + if (!value->scene_number) { + BT_ERR("%s, Scene store scene_number 0x0000 is prohibited", __func__); + return -EINVAL; + } + length = BLE_MESH_SCENE_STORE_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_SCENE_RECALL: + need_ack = true; + case BLE_MESH_MODEL_OP_SCENE_RECALL_UNACK: { + struct bt_mesh_scene_recall *value; + value = (struct bt_mesh_scene_recall *)set; + if (!value->scene_number) { + BT_ERR("%s, Scene recall scene_number 0x0000 is prohibited", __func__); + return -EINVAL; + } + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("%s, Invalid Scene Recall transition time", __func__); + return -EINVAL; + } + } + length = BLE_MESH_SCENE_RECALL_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_SCENE_DELETE: + need_ack = true; + case BLE_MESH_MODEL_OP_SCENE_DELETE_UNACK: { + length = BLE_MESH_SCENE_DELETE_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET_UNACK: { + struct bt_mesh_scheduler_act_set *value; + value = (struct bt_mesh_scheduler_act_set *)set; + if (value->year > 0x64) { + BT_ERR("%s, Scheduler register year value is prohibited", __func__); + return -EINVAL; + } + if (value->hour > 0x19) { + BT_ERR("%s, Scheduler register hour value is prohibited", __func__); + return -EINVAL; + } + length = BLE_MESH_SCHEDULER_ACT_SET_MSG_LEN; + break; + } + default: + BT_ERR("%s, Not a Time Scene Set message opcode", __func__); + return -EINVAL; + } + + return time_scene_set_state(common, set, length, need_ack); +} + +static int time_scene_client_init(struct bt_mesh_model *model, bool primary) +{ + time_scene_internal_data_t *internal = NULL; + bt_mesh_time_scene_client_t *client = NULL; + + BT_DBG("primary %u", primary); + + if (!model) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_time_scene_client_t *)model->user_data; + if (!client) { + BT_ERR("%s, Time Scene Client user_data is NULL", __func__); + return -EINVAL; + } + + /* TODO: call osi_free() when deinit function is invoked*/ + internal = osi_calloc(sizeof(time_scene_internal_data_t)); + if (!internal) { + BT_ERR("%s, Failed to allocate memory", __func__); + return -ENOMEM; + } + + sys_slist_init(&internal->queue); + + client->model = model; + client->op_pair_size = ARRAY_SIZE(time_scene_op_pair); + client->op_pair = time_scene_op_pair; + client->internal_data = internal; + + return 0; +} + +int bt_mesh_time_cli_init(struct bt_mesh_model *model, bool primary) +{ + return time_scene_client_init(model, primary); +} + +int bt_mesh_scene_cli_init(struct bt_mesh_model *model, bool primary) +{ + return time_scene_client_init(model, primary); +} + +int bt_mesh_scheduler_cli_init(struct bt_mesh_model *model, bool primary) +{ + return time_scene_client_init(model, primary); +} \ No newline at end of file diff --git a/components/bt/bluedroid/btc/core/btc_task.c b/components/bt/bluedroid/btc/core/btc_task.c index df1e1ddfdc..edfc4a63f1 100644 --- a/components/bt/bluedroid/btc/core/btc_task.c +++ b/components/bt/bluedroid/btc/core/btc_task.c @@ -49,6 +49,15 @@ #include "btc_hf_client.h" #endif /* #if BTC_HF_CLIENT_INCLUDED */ #endif /* #if CLASSIC_BT_INCLUDED */ +#if CONFIG_BLE_MESH +#include "btc_ble_mesh_prov.h" +#include "btc_ble_mesh_health_model.h" +#include "btc_ble_mesh_config_model.h" +#include "btc_ble_mesh_generic_model.h" +#include "btc_ble_mesh_lighting_model.h" +#include "btc_ble_mesh_sensor_model.h" +#include "btc_ble_mesh_time_scene_model.h" +#endif /* #if CONFIG_BLE_MESH */ #define BTC_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) #define BTC_TASK_STACK_SIZE (BT_BTC_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) //by menuconfig @@ -98,6 +107,18 @@ static const btc_func_t profile_tab[BTC_PID_NUM] = { [BTC_PID_HF_CLIENT] = {btc_hf_client_call_handler, btc_hf_client_cb_handler}, #endif /* #if BTC_HF_CLIENT_INCLUDED */ #endif /* #if CLASSIC_BT_INCLUDED */ +#if CONFIG_BLE_MESH + [BTC_PID_PROV] = {btc_mesh_prov_call_handler, btc_mesh_prov_cb_handler}, + [BTC_PID_MODEL] = {btc_mesh_model_call_handler, btc_mesh_model_cb_handler}, + [BTC_PID_HEALTH_CLIENT] = {btc_mesh_health_client_call_handler, btc_mesh_health_client_cb_handler}, + [BTC_PID_HEALTH_SERVER] = {btc_mesh_health_server_call_handler, btc_mesh_health_server_cb_handler}, + [BTC_PID_CFG_CLIENT] = {btc_mesh_cfg_client_call_handler, btc_mesh_cfg_client_cb_handler}, + [BTC_PID_CFG_SERVER] = {NULL , btc_mesh_cfg_server_cb_handler}, + [BTC_PID_GENERIC_CLIENT] = {btc_mesh_generic_client_call_handler, btc_mesh_generic_client_cb_handler}, + [BTC_PID_LIGHT_CLIENT] = {btc_mesh_light_client_call_handler, btc_mesh_light_client_cb_handler}, + [BTC_PID_SENSOR_CLIENT] = {btc_mesh_sensor_client_call_handler, btc_mesh_sensor_client_cb_handler}, + [BTC_PID_TIME_SCENE_CLIENT] = {btc_mesh_time_scene_client_call_handler, btc_mesh_time_scene_client_cb_handler}, +#endif /* #if CONFIG_BLE_MESH */ }; /***************************************************************************** diff --git a/components/bt/bluedroid/btc/include/btc/btc_task.h b/components/bt/bluedroid/btc/include/btc/btc_task.h index 0ed02d911a..7c5ec80072 100644 --- a/components/bt/bluedroid/btc/include/btc/btc_task.h +++ b/components/bt/bluedroid/btc/include/btc/btc_task.h @@ -64,6 +64,18 @@ typedef enum { BTC_PID_HF_CLIENT, #endif /* BTC_HF_CLIENT_INCLUDED */ #endif /* CLASSIC_BT_INCLUDED */ +#if CONFIG_BLE_MESH + BTC_PID_PROV, + BTC_PID_MODEL, + BTC_PID_HEALTH_CLIENT, + BTC_PID_HEALTH_SERVER, + BTC_PID_CFG_CLIENT, + BTC_PID_CFG_SERVER, + BTC_PID_GENERIC_CLIENT, + BTC_PID_LIGHT_CLIENT, + BTC_PID_SENSOR_CLIENT, + BTC_PID_TIME_SCENE_CLIENT, +#endif /* CONFIG_BLE_MESH */ BTC_PID_NUM, } btc_pid_t; //btc profile id diff --git a/components/bt/component.mk b/components/bt/component.mk index b77e8f6640..529da89139 100644 --- a/components/bt/component.mk +++ b/components/bt/component.mk @@ -72,7 +72,19 @@ COMPONENT_PRIV_INCLUDEDIRS += bluedroid/bta/include \ bluedroid/utils/include \ bluedroid/common/include -COMPONENT_ADD_INCLUDEDIRS += bluedroid/api/include/api +COMPONENT_ADD_INCLUDEDIRS += bluedroid/api/include/api \ + bluedroid/osi/include \ + +ifdef CONFIG_BLE_MESH + COMPONENT_ADD_INCLUDEDIRS += ble_mesh/mesh_core \ + ble_mesh/mesh_core/include \ + ble_mesh/mesh_core/settings \ + ble_mesh/btc/include \ + ble_mesh/mesh_models/include \ + ble_mesh/api/core/include \ + ble_mesh/api/models/include \ + ble_mesh/api +endif COMPONENT_SRCDIRS += bluedroid/bta/dm \ bluedroid/bta/gatt \ @@ -122,6 +134,15 @@ COMPONENT_SRCDIRS += bluedroid/bta/dm \ bluedroid/api \ bluedroid +ifdef CONFIG_BLE_MESH + COMPONENT_SRCDIRS += ble_mesh/mesh_core \ + ble_mesh/mesh_core/settings \ + ble_mesh/btc \ + ble_mesh/mesh_models \ + ble_mesh/api/core \ + ble_mesh/api/models +endif + ifeq ($(GCC_NOT_5_2_0), 1) bluedroid/bta/sdp/bta_sdp_act.o: CFLAGS += -Wno-unused-const-variable bluedroid/btc/core/btc_config.o: CFLAGS += -Wno-unused-const-variable diff --git a/docs/en/COPYRIGHT.rst b/docs/en/COPYRIGHT.rst index e9aa5a4ed8..cb4272af64 100644 --- a/docs/en/COPYRIGHT.rst +++ b/docs/en/COPYRIGHT.rst @@ -56,6 +56,7 @@ These third party libraries can be included into the application (firmware) prod * :component:`Asio `, Copyright (c) 2003-2018 Christopher M. Kohlhoff is licensed under the Boost Software License. * :component:`ESP-MQTT ` MQTT Package (contiki-mqtt) - Copyright (c) 2014, Stephen Robinson, MQTT-ESP - Tuan PM is licensed under Apache License 2.0. +* :component:`BLE Mesh ` is adapted from Zephyr Project, Copyright (c) 2017-2018 Intel Corporation and licensed under Apache License 2.0 Build Tools ----------- @@ -158,3 +159,4 @@ Copyright (C) 2011, ChaN, all right reserved. .. _spiffs: https://github.com/pellepl/spiffs .. _asio: https://github.com/chriskohlhoff/asio .. _mqtt: https://github.com/espressif/esp-mqtt +.. _zephyr: https://github.com/zephyrproject-rtos/zephyr diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/CMakeLists.txt b/examples/bluetooth/ble_mesh/ble_mesh_client_model/CMakeLists.txt new file mode 100644 index 0000000000..f384288f31 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_client_model/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(ble_mesh_client_model) diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/Makefile b/examples/bluetooth/ble_mesh/ble_mesh_client_model/Makefile new file mode 100644 index 0000000000..384ad8ed5e --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_client_model/Makefile @@ -0,0 +1,10 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := ble_mesh_client_model + +COMPONENT_ADD_INCLUDEDIRS := components/include + +include $(IDF_PATH)/make/project.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/README.md b/examples/bluetooth/ble_mesh/ble_mesh_client_model/README.md new file mode 100644 index 0000000000..38aa2caee1 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_client_model/README.md @@ -0,0 +1,14 @@ +ESP BLE Mesh Client Model Demo +======================== + +This demo shows how to use the Generic OnOff Client Model to get/set the generic on/off state. The basic procedures are as follows: + +1. Download and run this demo. +2. Use any app for BLE Mesh to provision this device as well as the device running the Generic OnOff Server demo. +3. After both onoff client and server devices are provisioned, use UART1 to input the unicast address of the element within the server device. +4. The Generic OnOff Client will start to get and set Generic OnOff states periodically. + +>**Notes:** +> +>1. The NetKey index and AppKey index are fixed to 0x0000 in this demo. +>2. If the client device is re-provisioned, but the server device is not, the first few get/set messages from the client will be treated as replay attacks. To avoid this, both devices should be re-provisioned prior to transmitting messages. \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/CMakeLists.txt b/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/CMakeLists.txt new file mode 100644 index 0000000000..1eb2d87ed2 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/CMakeLists.txt @@ -0,0 +1,6 @@ +set(COMPONENT_SRCS "ble_mesh_demo_main.c" + "board.c") + +set(COMPONENT_ADD_INCLUDEDIRS ".") + +register_component() diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/Kconfig.projbuild b/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/Kconfig.projbuild new file mode 100644 index 0000000000..3bde11ff6d --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/Kconfig.projbuild @@ -0,0 +1,22 @@ +menu "Example Configuration" + + choice BLE_MESH_EXAMPLE_BOARD + prompt "Board selection for BLE Mesh" + default BLE_MESH_ESP_WROOM_32 + help + Select this option to choose the board for BLE Mesh. The default is ESP32-WROOM-32 + + config BLE_MESH_ESP_WROOM_32 + bool "ESP32-WROOM-32" + + config BLE_MESH_ESP_WROVER + bool "ESP32-WROVER" + endchoice + + config BLE_MESH_PATCH_FOR_SLAB_APP_1_1_0 + bool "Fix bug of Silicon Lab Android App v1.1.0 when reconnection will cause sequence number to recount from 0" + default y + help + It is an ad hoc solution and needs further modifications. + +endmenu diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/ble_mesh_demo_main.c b/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/ble_mesh_demo_main.c new file mode 100644 index 0000000000..3dde33207d --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/ble_mesh_demo_main.c @@ -0,0 +1,532 @@ +/* main.c - Application main entry point */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "esp_log.h" +#include "nvs_flash.h" + +#include "esp_bt.h" +#include "esp_bt_main.h" +#include "esp_bt_device.h" +#include "esp_ble_mesh_common_api.h" +#include "esp_ble_mesh_provisioning_api.h" +#include "esp_ble_mesh_networking_api.h" +#include "esp_ble_mesh_config_model_api.h" +#include "esp_ble_mesh_generic_model_api.h" + +#include "board.h" + +#define TAG "ble_mesh_client" + +#define CID_ESP 0x02E5 + +#define MSG_SEND_TTL 3 +#define MSG_SEND_REL false +#define MSG_TIMEOUT 0 /* 0 indicates that timeout value from menuconfig will be used */ +#define MSG_ROLE ROLE_NODE + +extern struct _led_state led_state[3]; + +static uint8_t dev_uuid[16] = { 0xdd, 0xdd }; +static uint16_t node_net_idx = ESP_BLE_MESH_KEY_UNUSED; +static uint16_t node_app_idx = ESP_BLE_MESH_KEY_UNUSED; +static uint8_t remote_onoff = LED_OFF; + +/* The remote node address shall be input through UART1, see board.c */ +uint16_t remote_addr = ESP_BLE_MESH_ADDR_UNASSIGNED; + +static esp_ble_mesh_client_t onoff_client; + +static esp_ble_mesh_cfg_srv_t config_server = { + .relay = ESP_BLE_MESH_RELAY_DISABLED, + .beacon = ESP_BLE_MESH_BEACON_ENABLED, +#if defined(CONFIG_BLE_MESH_FRIEND) + .friend_state = ESP_BLE_MESH_FRIEND_ENABLED, +#else + .friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED, +#endif +#if defined(CONFIG_BLE_MESH_GATT_PROXY) + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED, +#else + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED, +#endif + .default_ttl = 7, + + /* 3 transmissions with 20ms interval */ + .net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20), + .relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20), +}; + +ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_srv_pub, 2 + 1, MSG_ROLE); +ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_cli_pub, 2 + 1, MSG_ROLE); + +static esp_ble_mesh_model_op_t onoff_op[] = { + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET, 0), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, 2), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2), + /* Each model operation struct array must use this terminator + * as the end tag of the operation uint. */ + ESP_BLE_MESH_MODEL_OP_END, +}; + +static esp_ble_mesh_model_t root_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&config_server), + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, onoff_op, + &onoff_srv_pub, &led_state[0]), + ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(&onoff_cli_pub, &onoff_client), +}; + +static esp_ble_mesh_elem_t elements[] = { + ESP_BLE_MESH_ELEMENT(0, root_models, ESP_BLE_MESH_MODEL_NONE), +}; + +static esp_ble_mesh_comp_t composition = { + .cid = CID_ESP, + .elements = elements, + .element_count = ARRAY_SIZE(elements), +}; + +/* Disable OOB security for SILabs Android app */ +static esp_ble_mesh_prov_t provision = { + .uuid = dev_uuid, +#if 0 + .output_size = 4, + .output_actions = ESP_BLE_MESH_DISPLAY_NUMBER, + .input_actions = ESP_BLE_MESH_PUSH, + .input_size = 4, +#else + .output_size = 0, + .output_actions = 0, +#endif +}; + +static int output_number(esp_ble_mesh_output_action_t action, uint32_t number) +{ + board_output_number(action, number); + return 0; +} + +static void prov_complete(uint16_t net_idx, uint16_t addr, uint8_t flags, uint32_t iv_index) +{ + ESP_LOGI(TAG, "net_idx: 0x%04x, addr: 0x%04x", net_idx, addr); + ESP_LOGI(TAG, "flags: 0x%02x, iv_index: 0x%08x", flags, iv_index); + board_prov_complete(); + node_net_idx = net_idx; +} + +static void gen_onoff_get_handler(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, + uint16_t length, uint8_t *data) +{ + struct _led_state *led = (struct _led_state *)model->user_data; + uint8_t send_data; + esp_err_t err; + + ESP_LOGI(TAG, "%s, addr 0x%04x onoff 0x%02x", __func__, model->element->element_addr, led->current); + + send_data = led->current; + /* Send Generic OnOff Status as a response to Generic OnOff Get */ + err = esp_ble_mesh_server_model_send_msg(model, ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, + sizeof(send_data), &send_data); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Generic OnOff Status failed", __func__); + return; + } +} + +static void gen_onoff_set_unack_handler(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, + uint16_t length, uint8_t *data) +{ + struct _led_state *led = (struct _led_state *)model->user_data; + uint8_t prev_onoff; + esp_err_t err; + + ESP_LOGI(TAG, "%s, addr 0x%02x onoff 0x%02x", __func__, model->element->element_addr, led->current); + + prev_onoff = led->previous; + led->current = data[0]; + remote_onoff = led->current; + + board_led_operation(led->pin, led->current); + + /* If Generic OnOff state is changed, and the publish address of Generic OnOff Server + * model is valid, Generic OnOff Status will be published. + */ + if (prev_onoff != led->current && model->pub->publish_addr != ESP_BLE_MESH_ADDR_UNASSIGNED) { + ESP_LOGI(TAG, "Publish previous 0x%02x current 0x%02x", prev_onoff, led->current); + err = esp_ble_mesh_model_publish(model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, + sizeof(led->current), &led->current, ROLE_NODE); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Publish Generic OnOff Status failed", __func__); + return; + } + } +} + +static void gen_onoff_set_handler(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, + uint16_t length, uint8_t *data) +{ + struct net_buf_simple *msg = model->pub->msg; + struct _led_state *led = (struct _led_state *)model->user_data; + uint8_t prev_onoff, send_data; + esp_err_t err; + + ESP_LOGI(TAG, "%s, addr 0x%02x onoff 0x%02x", __func__, model->element->element_addr, led->current); + + prev_onoff = led->previous; + led->current = data[0]; + remote_onoff = led->current; + + board_led_operation(led->pin, led->current); + + send_data = led->current; + /* Send Generic OnOff Status as a response to Generic OnOff Get */ + err = esp_ble_mesh_server_model_send_msg(model, ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, + sizeof(send_data), &send_data); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Generic OnOff Status failed", __func__); + return; + } + + /* If Generic OnOff state is changed, and the publish address of Generic OnOff Server + * model is valid, Generic OnOff Status will be published. + */ + if (prev_onoff != led->current && model->pub->publish_addr != ESP_BLE_MESH_ADDR_UNASSIGNED) { + ESP_LOGI(TAG, "Publish previous 0x%02x current 0x%02x", prev_onoff, led->current); + bt_mesh_model_msg_init(msg, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS); + err = esp_ble_mesh_model_publish(model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, + sizeof(send_data), &send_data, ROLE_NODE); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Publish Generic OnOff Status failed", __func__); + return; + } + } +} + +static char *esp_ble_mesh_prov_event_to_str(esp_ble_mesh_prov_cb_event_t event) +{ + switch (event) { + case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT: + return "ESP_BLE_MESH_PROV_REGISTER_COMP_EVT"; + case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT: + return "ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT"; + case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT: + return "ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT"; + case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT: + return "ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT"; + case ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT: + return "ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT"; + case ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT: + return "ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT"; + case ESP_BLE_MESH_NODE_PROV_INPUT_EVT: + return "ESP_BLE_MESH_NODE_PROV_INPUT_EVT"; + case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT: + return "ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT"; + case ESP_BLE_MESH_NODE_PROV_RESET_EVT: + return "ESP_BLE_MESH_NODE_PROV_RESET_EVT"; + default: + return "Invalid BLE Mesh provision event"; + } + + return NULL; +} + +static void esp_ble_mesh_prov_cb(esp_ble_mesh_prov_cb_event_t event, + esp_ble_mesh_prov_cb_param_t *param) +{ + ESP_LOGI(TAG, "%s, event = %s", __func__, esp_ble_mesh_prov_event_to_str(event)); + + switch (event) { + case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROV_REGISTER_COMP_EVT, err_code %d", param->prov_register_comp.err_code); + break; + case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT, err_code %d", param->node_prov_enable_comp.err_code); + break; + case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT, bearer %s", + param->node_prov_link_open.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT"); + break; + case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT, bearer %s", + param->node_prov_link_close.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT"); + break; + case ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT: + output_number(param->node_prov_output_num.action, param->node_prov_output_num.number); + break; + case ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT: + break; + case ESP_BLE_MESH_NODE_PROV_INPUT_EVT: + break; + case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT: + prov_complete(param->node_prov_complete.net_idx, param->node_prov_complete.addr, + param->node_prov_complete.flags, param->node_prov_complete.iv_index); + break; + case ESP_BLE_MESH_NODE_PROV_RESET_EVT: + break; + case ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT, err_code %d", param->node_set_unprov_dev_name_comp.err_code); + break; + default: + break; + } + + return; +} + +static esp_err_t esp_ble_mesh_set_msg_common(esp_ble_mesh_client_common_param_t *common, + esp_ble_mesh_generic_client_set_state_t *set, + esp_ble_mesh_model_t *model, uint32_t opcode, + uint8_t onoff) +{ + if (!common || !set || !model) { + return ESP_ERR_INVALID_ARG; + } + + common->opcode = opcode; + common->model = model; + common->ctx.net_idx = node_net_idx; + common->ctx.app_idx = node_app_idx; + common->ctx.addr = remote_addr; + common->ctx.send_ttl = MSG_SEND_TTL; + common->ctx.send_rel = MSG_SEND_REL; + common->msg_timeout = MSG_TIMEOUT; + common->msg_role = MSG_ROLE; + set->onoff_set.op_en = false; + set->onoff_set.onoff = onoff; + set->onoff_set.tid = 0x0; + + return ESP_OK; +} + + +static void esp_ble_mesh_model_cb(esp_ble_mesh_model_cb_event_t event, + esp_ble_mesh_model_cb_param_t *param) +{ + esp_ble_mesh_client_common_param_t common = {0}; + int err; + + switch (event) { + case ESP_BLE_MESH_MODEL_OPERATION_EVT: { + if (!param->model_operation.model || !param->model_operation.model->op || !param->model_operation.ctx) { + ESP_LOGE(TAG, "ESP_BLE_MESH_MODEL_OPERATION_EVT parameter is NULL"); + return; + } + if (node_app_idx == ESP_BLE_MESH_KEY_UNUSED) { + /* Generic OnOff Server/Client Models need to bind with the same app key */ + node_app_idx = param->model_operation.ctx->app_idx; + } + switch (param->model_operation.opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET: + gen_onoff_get_handler(param->model_operation.model, param->model_operation.ctx, + param->model_operation.length, param->model_operation.msg); + break; + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: { + esp_ble_mesh_generic_client_set_state_t set_state = {0}; + gen_onoff_set_handler(param->model_operation.model, param->model_operation.ctx, + param->model_operation.length, param->model_operation.msg); + /* This node has a Generic OnOff Client and Server Model. + * When Generic OnOff Server Model receives a Generic OnOff Set message, after + * this message is been handled, the Generic OnOff Client Model will send the + * Generic OnOff Set message to another node(contains Generic OnOff Server Model) + * identified by the remote_addr. + */ + esp_ble_mesh_set_msg_common(&common, &set_state, onoff_client.model, + ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, remote_onoff); + err = esp_ble_mesh_generic_client_set_state(&common, &set_state); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Generic OnOff Set failed", __func__); + return; + } + break; + } + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK: { + esp_ble_mesh_generic_client_set_state_t set_state = {0}; + gen_onoff_set_unack_handler(param->model_operation.model, param->model_operation.ctx, + param->model_operation.length, param->model_operation.msg); + /* This node has a Generic OnOff Client and Server Model. + * When Generic OnOff Client Model receives a Generic OnOff Set Unack message, + * after this message is been handled, the Generic OnOff Client Model will send + * the Generic OnOff Set Unack message to another node(contains Generic OnOff + * Server Model) identified by the remote_addr. + */ + esp_ble_mesh_set_msg_common(&common, &set_state, onoff_client.model, + ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, remote_onoff); + err = esp_ble_mesh_generic_client_set_state(&common, &set_state); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Generic OnOff Set Unack failed", __func__); + return; + } + break; + } + default: + break; + } + break; + } + case ESP_BLE_MESH_MODEL_SEND_COMP_EVT: + break; + case ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT: + break; + default: + break; + } + return; +} + +static void esp_ble_mesh_generic_cb(esp_ble_mesh_generic_client_cb_event_t event, + esp_ble_mesh_generic_client_cb_param_t *param) +{ + uint32_t opcode; + int err; + + ESP_LOGI(TAG, "%s: event is %d, error code is %d, opcode is 0x%x", + __func__, event, param->error_code, param->params->opcode); + + opcode = param->params->opcode; + + switch (event) { + case ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT"); + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET: + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET: onoff %d", param->status_cb.onoff_status.present_onoff); + break; + default: + break; + } + break; + case ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT"); + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: onoff %d", param->status_cb.onoff_status.present_onoff); + break; + default: + break; + } + break; + case ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT"); + break; + case ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT: { + ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT"); + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: { + esp_ble_mesh_client_common_param_t common = {0}; + esp_ble_mesh_generic_client_set_state_t set_state = {0}; + /* If failed to get the response of Generic OnOff Set, resend Generic OnOff Set */ + esp_ble_mesh_set_msg_common(&common, &set_state, onoff_client.model, + ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, remote_onoff); + err = esp_ble_mesh_generic_client_set_state(&common, &set_state); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Generic OnOff Set failed", __func__); + return; + } + break; + } + default: + break; + } + break; + } + default: + break; + } + return; +} + +static int ble_mesh_init(void) +{ + int err = 0; + + memcpy(dev_uuid + 2, esp_bt_dev_get_address(), ESP_BD_ADDR_LEN); + + esp_ble_mesh_register_prov_callback(esp_ble_mesh_prov_cb); + esp_ble_mesh_register_custom_model_callback(esp_ble_mesh_model_cb); + esp_ble_mesh_register_generic_client_callback(esp_ble_mesh_generic_cb); + + err = esp_ble_mesh_init(&provision, &composition); + if (err) { + ESP_LOGE(TAG, "Initializing mesh failed (err %d)", err); + return err; + } + + esp_ble_mesh_node_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT); + + ESP_LOGI(TAG, "BLE Mesh Node initialized"); + + board_led_operation(LED_G, LED_ON); + + return err; +} + +static esp_err_t bluetooth_init(void) +{ + esp_err_t ret; + + ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)); + + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + ret = esp_bt_controller_init(&bt_cfg); + if (ret) { + ESP_LOGE(TAG, "%s initialize controller failed", __func__); + return ret; + } + + ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); + if (ret) { + ESP_LOGE(TAG, "%s enable controller failed", __func__); + return ret; + } + ret = esp_bluedroid_init(); + if (ret) { + ESP_LOGE(TAG, "%s init bluetooth failed", __func__); + return ret; + } + ret = esp_bluedroid_enable(); + if (ret) { + ESP_LOGE(TAG, "%s enable bluetooth failed", __func__); + return ret; + } + + return ret; +} + +void app_main(void) +{ + int err; + + ESP_LOGI(TAG, "Initializing..."); + + board_init(); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "esp32_bluetooth_init failed (err %d)", err); + return; + } + + /* Initialize the Bluetooth Mesh Subsystem */ + err = ble_mesh_init(); + if (err) { + ESP_LOGE(TAG, "Bluetooth mesh init failed (err %d)", err); + } +} diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/board.c b/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/board.c new file mode 100644 index 0000000000..d81bc58815 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/board.c @@ -0,0 +1,115 @@ +/* board.c - Board-specific hooks */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" + +#include "driver/uart.h" +#include "esp_log.h" + +#include "esp_ble_mesh_provisioning_api.h" +#include "board.h" + +#define TAG "BOARD" + +#define MESH_UART_NUM UART_NUM_1 +#define MESH_UART (&UART1) + +#define UART_BUF_SIZE 128 + +#define UART1_TX_PIN GPIO_NUM_16 +#define UART1_RX_PIN GPIO_NUM_17 + +extern uint16_t remote_addr; + +struct _led_state led_state[3] = { + { LED_OFF, LED_OFF, LED_R, "red" }, + { LED_OFF, LED_OFF, LED_G, "green" }, + { LED_OFF, LED_OFF, LED_B, "blue" }, +}; + +void board_output_number(esp_ble_mesh_output_action_t action, uint32_t number) +{ + ESP_LOGI(TAG, "Board output number %d", number); +} + +void board_prov_complete(void) +{ + board_led_operation(LED_G, LED_OFF); +} + +void board_led_operation(uint8_t pin, uint8_t onoff) +{ + for (int i = 0; i < ARRAY_SIZE(led_state); i++) { + if (led_state[i].pin != pin) { + continue; + } + if (onoff == led_state[i].previous) { + ESP_LOGW(TAG, "led %s is already %s", + led_state[i].name, (onoff ? "on" : "off")); + return; + } + gpio_set_level(pin, onoff); + led_state[i].previous = onoff; + return; + } + ESP_LOGE(TAG, "LED is not found!"); +} + +static void board_uart_task(void *p) +{ + uint8_t *data = calloc(1, UART_BUF_SIZE); + uint32_t input; + + while (1) { + int len = uart_read_bytes(MESH_UART_NUM, data, UART_BUF_SIZE, 100 / portTICK_RATE_MS); + if (len > 0) { + input = strtoul((const char *)data, NULL, 16); + remote_addr = input & 0xFFFF; + ESP_LOGI(TAG, "%s: input 0x%08x, remote_addr 0x%04x", __func__, input, remote_addr); + memset(data, 0, UART_BUF_SIZE); + } + } + + vTaskDelete(NULL); +} + +static void board_led_init(void) +{ + for (int i = 0; i < ARRAY_SIZE(led_state); i++) { + gpio_pad_select_gpio(led_state[i].pin); + gpio_set_direction(led_state[i].pin, GPIO_MODE_OUTPUT); + gpio_set_level(led_state[i].pin, LED_OFF); + led_state[i].previous = LED_OFF; + } +} + +static void board_uart_init(void) +{ + uart_config_t uart_config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE + }; + uart_param_config(MESH_UART_NUM, &uart_config); + uart_set_pin(MESH_UART_NUM, UART1_TX_PIN, UART1_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + uart_driver_install(MESH_UART_NUM, UART_BUF_SIZE * 2, 0, 0, NULL, 0); +} + +void board_init(void) +{ + board_led_init(); + board_uart_init(); + xTaskCreate(board_uart_task, "board_uart_task", 2048, NULL, 5, NULL); +} diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/board.h b/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/board.h new file mode 100644 index 0000000000..4ae04b2ed4 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/board.h @@ -0,0 +1,42 @@ +/* board.h - Board-specific hooks */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _BOARD_H_ +#define _BOARD_H_ + +#include "driver/gpio.h" +#include "esp_ble_mesh_defs.h" + +#if defined(CONFIG_BLE_MESH_ESP_WROOM_32) +#define LED_R GPIO_NUM_25 +#define LED_G GPIO_NUM_26 +#define LED_B GPIO_NUM_27 +#elif defined(CONFIG_BLE_MESH_ESP_WROVER) +#define LED_R GPIO_NUM_0 +#define LED_G GPIO_NUM_2 +#define LED_B GPIO_NUM_4 +#endif + +#define LED_ON 1 +#define LED_OFF 0 + +struct _led_state { + uint8_t current; + uint8_t previous; + uint8_t pin; + char *name; +}; + +void board_output_number(esp_ble_mesh_output_action_t action, uint32_t number); + +void board_prov_complete(void); + +void board_led_operation(uint8_t pin, uint8_t onoff); + +void board_init(void); + +#endif diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/component.mk b/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/component.mk new file mode 100644 index 0000000000..a98f634eae --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/component.mk @@ -0,0 +1,4 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/sdkconfig.defaults b/examples/bluetooth/ble_mesh/ble_mesh_client_model/sdkconfig.defaults new file mode 100644 index 0000000000..e1aee38f72 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_client_model/sdkconfig.defaults @@ -0,0 +1,45 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y +CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY= +CONFIG_BTDM_CONTROLLER_MODE_BTDM= +CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n +CONFIG_BLE_SCAN_DUPLICATE=y +CONFIG_SCAN_DUPLICATE_TYPE=2 +CONFIG_DUPLICATE_SCAN_CACHE_SIZE=200 +CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y +CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE=200 +CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y +CONFIG_GATTS_ENABLE=y +CONFIG_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_HCI_5_0=y +CONFIG_BLE_MESH_USE_DUPLICATE_SCAN=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PROV=y +CONFIG_BLE_MESH_NET_BUF_POOL_USAGE=y +CONFIG_BLE_MESH_PROXY=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_GATT_PROXY=y +CONFIG_BLE_MESH_NODE_ID_TIMEOUT=60 +CONFIG_BLE_MESH_PROXY_FILTER_SIZE=1 +CONFIG_BLE_MESH_IV_UPDATE_TEST= +CONFIG_BLE_MESH_SUBNET_COUNT=1 +CONFIG_BLE_MESH_APP_KEY_COUNT=1 +CONFIG_BLE_MESH_MODEL_KEY_COUNT=1 +CONFIG_BLE_MESH_MODEL_GROUP_COUNT=1 +CONFIG_BLE_MESH_LABEL_COUNT=1 +CONFIG_BLE_MESH_CRPL=10 +CONFIG_BLE_MESH_MSG_CACHE_SIZE=10 +CONFIG_BLE_MESH_ADV_BUF_COUNT=60 +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=6 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=1 +CONFIG_BLE_MESH_RX_SDU_MAX=384 +CONFIG_BLE_MESH_TX_SEG_MAX=32 +CONFIG_BLE_MESH_RELAY=y +CONFIG_BLE_MESH_LOW_POWER= +CONFIG_BLE_MESH_FRIEND= +CONFIG_BLE_MESH_CFG_CLI= +CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y +CONFIG_BTU_TASK_STACK_SIZE=4512 \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/ble_mesh_client_model.md b/examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/ble_mesh_client_model.md new file mode 100644 index 0000000000..49697c2ab0 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/ble_mesh_client_model.md @@ -0,0 +1,252 @@ +# 1. Introduction +## 1.1 Demo Function + +1. This demo forwards the message sent by the nRF Mesh app. +2. The user enters the address of the destination node and use it to forwarded packet. +3. The types of the forwarded message include: + * `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET`, + * `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET`, + * `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK`. +4. The destination node reports its Onoff state with the `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS` message. + +Example: The nRF Mesh app sends a `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET` message to the node that runs the `ble_mesh_client_model` project. Then this node sends a `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET` message to the destination node that runs the `ble_mesh_node` project. The address of the destination node is entered by the user via the serial port. + +## 1.1.1 What You Need + +* 1 x Device that runs the `ble_mesh_client_model` project. +* 1 x Device that runs the `ble_mesh_node` project. +* 1 x Phone that installs the nRF Mesh app for controlling these two devices + +## 1.2 Node Composition + +This demo has only one element, in which the following three Models are implemented: + +- **Configuration Server Model** is mainly to represent a mesh network configuration, such as its AppKey, Relay State, TTL State, Subscription List State, etc. +- **Generic OnOff Client Model** controls a Generic OnOff Server via messages defined by the Generic OnOff Model, that is, turning on and off the lights. +- **Generic OnOff Server Model** implements the nodes' Onoff state. + +## 1.3 Message Sequence + +You can choose from the 4 message sequences described below: + +1. Acknowledged Get +2. Acknowledged Set +3. Unacknowledged Set +4. Acknowledged Set with Periodic Publishing + +![Packet interaction](images/message.png) + +## 2. Code Analysis + +Code initialization part reference [Initializing the Bluetooth and Initializing the BLE Mesh](../../ble_mesh_wifi_coexist/tutorial%20%20%20%20%20%20/ble_mesh_wifi_coexist.md) + +### 2.1 Model Definition + +#### 2.1.1 Generic OnOff Server Model + +```c +//Allocating memory for publishing messages. +ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_srv_pub, 2 + 1, MSG_ROLE); +//Registering the minimum length of messages. For example, the minimum length of the ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET message is registered as 2 octets. +static esp_ble_mesh_model_op_t onoff_op[] = { + { ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET, 0, 0}, + { ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, 2, 0}, + { ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2, 0}, + ESP_BLE_MESH_MODEL_OP_END, +}; +//Registering the Generic Onoff Server Model. +static esp_ble_mesh_model_t root_models[] = { + //onoff server's onoff state init + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, onoff_op, + &onoff_srv_pub, &led_state[0]), +}; +``` +#### 2.1.2 Generic OnOff Client Model + +```c +//Allocating memory for publishing messages. +ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_cli_pub, 2 + 1, MSG_ROLE); +//Registering the Generic Onoff Client Model. +static esp_ble_mesh_model_t root_models[] = { + ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(&onoff_cli_pub, &onoff_client), +}; +``` + +### 2.2 Model Callback Function + +#### 2.2.1 The Callback function for the Generic Onoff Client Model + +```c +esp_ble_mesh_register_generic_client_callback(esp_ble_mesh_generic_cb); + +``` +1. The callback function will be triggered when the Client Model: + + * Receives a message that indicates the Onoff state of the Sever Model; Or + * Calls any APIs that the Server Model send messages. + +2. The events that the callback function handle: + +| Event name | Opcode |Description | +| ------------- | ------------|------------------------------------------- | +| ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET |The event triggered when the Generic Onoff Client Model receives acknowledgment after sending the `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET` message | +| ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET | The event triggered when the Generic Onoff Client Model receives acknowledgment after sending the `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET` message | +| ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT | NA | The event triggered when the Generic Onoff Client Model receives publishing messages. | +| ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET | The event triggered when API (that send messages) calling times out | + + +#### 2.2.2 The Callback function for the Generic Onoff Server Model + +```c +esp_ble_mesh_register_custom_model_callback(esp_ble_mesh_model_cb); + +``` +1. The callback function will be triggered when the Server Model: + + * Receives a message that indicates operating the Onoff state of the Server Model from the Generic Onoff Client Model; Or + * Calls any APIs that the Server Model send messages. + +2. The events of the callback function: + +| Event Name | Opcode | Description | +|-------------------------------------|-------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET | The event triggered when the Generic Onoff Server Model receives the ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET message that **gets** the Onoff state of the server from the Client Model | +| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET | The event triggered when the Generic Onoff Server Model receives the ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET message that **sets** the Onoff state of the server from the Client Model | +| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK | The event triggered when the Generic Onoff Server Model receives the ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK message that **sets** the Onoff state of the server from the Client Model | +| ESP_BLE_MESH_MODEL_SEND_COMP_EVT | NA | The event triggered when the `esp_ble_mesh_server_model_send_msg` API calling completes | +| ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT | NA | The event triggered when the `esp_ble_mesh_model_publish` API calling completes | + + +### 2.3 Model that Sends Message +#### 2.3.1 Message Control + +The `esp_ble_mesh_set_msg_common` function is used to set the message controlling parameters. + +| Parameter Name |Description | +| ----------------------|------------------------- | +| `opcode` | The message opcode | +| `model` | The pointer to the client Model struct | +| `ctx.net_idx` | The NetKey Index of the subnet through which the message is sent | +| `ctx.app_idx` | The AppKey Index for message encryption | +| `ctx.addr` | The address of the destination nodes | +| `ctx.send_ttl`| The TTL State, which determines how many times a message will be relayed | +| `ctx.send_rel`| This parameter determines if the Model will wait for an acknowledgement after sending a message | +| `msg_timeout` | The maximum time the Model will wait for an acknowledgement | +| `msg_role` | The role of message (node/provisioner) | + +> Note: +> +> Please check the `ESP_BLE_MESH_MODEL_SEND_COMP_EVT` event to see if the message is sent successfully. +> This event is just for sending sig Model and vendor Model messages, not for all Models. + +#### 2.3.2 The Generic Onoff Client sends message + +The Generic Onoff Client Model calls the `esp_ble_mesh_generic_client_get_state` API to get the state of the server Model, such as the Onoff state. + +```c +esp_ble_mesh_generic_client_get_state_t get_state = {0}; +esp_ble_mesh_set_msg_common(&common, node, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET); +err = esp_ble_mesh_generic_client_get_state(&common, &get_state); +if (err) { + ESP_LOGE(TAG, "%s: Generic OnOff Get failed", __func__); + return; +} +``` + +The Generic Onoff Client Model calls the `esp_ble_mesh_generic_client_set_state` API to set the state of the server Model, such as the Onoff state. + +```c +esp_ble_mesh_generic_client_set_state_t set_state = {0}; +esp_ble_mesh_set_msg_common(&common, &set_state, onoff_client.model, + ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, remote_onoff); +err = esp_ble_mesh_generic_client_set_state(&common, &set_state); +if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Generic OnOff Set failed", __func__); + return; +} +``` + +#### 2.3.3 The Generic Onoff Server sends message + +The Generic Onoff Server Model has to bind its Appkey before calling the `esp_ble_mesh_server_model_send_msg` API to send a message. + +```c +err = esp_ble_mesh_server_model_send_msg(model, ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, + sizeof(send_data), &send_data); +``` +The Generic Onoff Server Model calls the `esp_ble_mesh_model_publish` API to publish messages. Only the Models that have subscribed to this destination address receive the published messages. + +```c +err = esp_ble_mesh_model_publish(model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, + sizeof(led->current), &led->current, ROLE_NODE); +``` + +### 2.4 Users Enter the Address of the Destination Node via Serial Port + +Please connect your devices and enters the address of the destination node via the serial port. + +Users can adjust the address of the destination node. + + +> Note: +> Please connect the pin 16 and pin 17 of the device that runs the `ble_mesh_client_model` project to the USB-to-UART tool. + +```c +#define UART1_TX_PIN GPIO_NUM_16 +#define UART1_RX_PIN GPIO_NUM_17 +``` + +The `board_uart_task` task is used to receive commands sent via the serial port, among which, the`remote_addr` represents the address of destination node that the message is forwarded to. Please enters hexadecimal string, such as 5, for this parameter. The address will be converted to 0x05 automatically. + +```c +static void board_uart_task(void *p) +{ + uint8_t *data = calloc(1, UART_BUF_SIZE); + uint32_t input; + + while (1) { + int len = uart_read_bytes(MESH_UART_NUM, data, UART_BUF_SIZE, 100 / portTICK_RATE_MS); + if (len > 0) { + input = strtoul((const char *)data, NULL, 16); + remote_addr = input & 0xFFFF; + ESP_LOGI(TAG, "%s: input 0x%08x, remote_addr 0x%04x", __func__, input, remote_addr); + memset(data, 0, UART_BUF_SIZE); + } + } + + vTaskDelete(NULL); +} +``` + + +# 3. Timing Sequence Diagram + +The steps for this demo: + +1. The nRF Mesh App provisionings the unprovisioned devices into nodes; +2. The nRF Mesh App adds a Appkey to these nodes, and bind the Models of these nodes to this Appkey. +3. The nRF Mesh App sends a controlling message to the Generic Onoff Client Model. Then the Client Model forwards this message to the server Model of the other node. + +The timing sequence diagram of this demo is shown below: + +![Packet interaction](images/picture5.png)

+ +>Note: +> +>The node **only forwards the message after it receives the controlling message sent by the app**. That is said, the node will **not** forwards messages to the other nodes every time the user enters the address of the destination node through the serial port. + + +# 4. The nRF Mesh App + +![Packet interaction](images/app.png) + +1. Scan the unprovisioned devices. +2. Identity the the capability of the unprovisioned devices. +3. Provisioning the unprovisioned devices. +4. Check if the Mesh node has been configured successful. +5. Configure the Models of the nodes. +6. Click on the Generic On Off Client option. +7. Bind the Generic On Off Client Model to the Appkey. +8. Check if the binding is successfully. +9. Bind the Generic On Off Server Model to the Appkey. +10. Send controlling messages. diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/images/app.png b/examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/images/app.png new file mode 100644 index 0000000000000000000000000000000000000000..9701c13ac91fcd87be1a2fac5f38255b0c79d33b GIT binary patch literal 443575 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%0AK# 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%0AY1Em=Dk5t-zahVEeaUwnH8BNE!<)x~W`F~h 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

DGM?{E} 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�em)V30cc|Zvw0xy)>77ol;zD_xE8f>&A_)~d0-g~evSLz z<{vNuhtwq!fMdE(N`^1vtj0)7n}Sm{C=L5r925$C%NJ+WZM2t&Si{NDetOcpkP{3I zCiOnt*9&;{tdp;{WK8zE@lNq_JSIBDgoItS>b1lBzLE3ss5``gXA95=UrZ_O*y=!zA{1DzO|PV( z&lE_pAmxIERabe~4iZVoo{I!XM-r5okBGYpWa3cZGQ}XH3dK{<i*_ker1YC7693jVgT!=TJryomxy*6crB+I z$%FE4B;($Z%PC!gE!&K1sh_rQirQZMS;zR9_eKf9!=;`v7J({FIiEg}%dTLkzGI%7 zYmS(9I(s4(mV&9+m@FGifih~T%?w;c`VBi0@FYt!cwU%_yngg_WR5xUHubSYYBLSM zxGRzNTEH7l;H(;pfAu=m7vo9JyT%vn)?>fjhpQqx&Qmmkzd#G|(R9xVZt4H~Y!9=e zZJ$_L{Kv-7&?_ff9z>%l+&TaJRpH?N_1d$0dn#n_)xSm-O0~2&%l_;{&sbA=a-wW! zBGEUOxr$*dc=p!cOe+A-_77gMfj90X!eh%eZmurZanW+I@oc-pdt_6)R!}2=7}ozE zu-u=(zPfa7^b?k`O=r>uPm@OPP5D#b{rC1up`Z(Pm4<(9aP}&(d}E|XQkQUPt2Afx z{wv!ub*M7@dTq~=F4`hoC8omF_7FvMp`AP422^x5bUXU7sa$%rtNH8ahc6r=h+EUp zz~E$?!-aY+_U;a-Yr^4;$45om#b>o%sHZc~EZaYC@rHPkI9IymsxAonJe&v%M^ z&+}FOmXilLJ-fdw8LxL5Kzm~WF>r1D(+QP~%lQJj!v))mXZMMfDaQK2tD&C+@?ZY` z?7V^GgqSUR9NFx&d}cwWkJf{stwO_D{inxi@xLc&U1>k|pKa$k@xWUy(nJb(nx9p? z8Poi(TCvo4<$2SW1pqMzgmAZT#a1W>EWdZfl10@VIPvUKj|*x}->}y7S4aiIeT$MU zR42yA$CfmvjSqf&CUOe`K0D7=5AfHiH$sgC?xNW`SCjM%E;(N*ivXCXYW1$M9-9mA zZ&T5m26TV1J=o9f?=o`aNs;j>_K7{LjM+}=DwO#U5Da_tT>fF!Z@2yi7R0mWB?cSY z|18=5hEf?6LD#-Dy8{t)C<$@A-gOk-prRN+iBYh6!=j!-{LR}ID{FmWs?3@I`T(cN z|BW;D%glw|qJW>Cg}+~_Ct-9D&7}mWvm%8^hVh?@vjswqj`c`I|64r(OrZ^iSVhg< zXvm8HhUEeiP358+Q-N>XVDgqqYdNWqSD-}X(nR0tPyqS>b@l&hQ2_p+oqhZy7TG~j zQr>_76!^ol@U!>^>}3y!Dla*rdt=KUAS)QhU~*z0bWo5ID+K{4b$~Gq$vf&ptWHr+ zCG8_q5`0*^GszFeLuU~86uXc3V^;+;6l&^x$*EtW+PNCTIzeV&~)%^dn>UZsXDKpu6Pbv-I(6A|6-6NjaIe@}}A8-tg z2#D&u|yRcsR1Fu40g`H1~%}xNW9MF=Pl*NNC;T!|g;YSsx6j@!1I7S`2 z0SXSjuTq^yH|R~XsUiP|gYBDnQKG!uBQlwIApR>|vQ$ZJGFb|JeHxKi$9i}`tZ?g{ zbKbQe{a*LC4Jn!cx5J*o-Nk)eYW4oOgv|!%0c#OpL%V+nGNkA z5zo0p6Azb4t7;|lqG~l*l@3IR^u$a_XnXVf-@sYgOBtj1>HuR8aF%)k1Sn{Q>V1lx z1d$sR;U;3%986ygU94`8ro>}awK(6;k;-XCC=nMXm!--ZFS5N=;b_DodsD4y{lqBm z!gvdkPqB2Nz!d3b!B$b)(tc3HsBxt%XS~^HJ<}MwiV@h@h@3R)HTBAhS)z{%kG7SUcp`?_1&$3Jn+YN!KD=sNKpnD^9-|Vbx=(hAs zMQNCui+*TX;Kl0PFfm`*OI0Od8y|y2tsyjaAbL|>kTKqER9AtG<)MKUeUxYR+nx~F zTVB@jpwWfA5jf}i@&*1}2Zo}Y5IogHGj~x>+)^D=zYlGEfqOf5Tpys&Rb3i(yP8tf z0CxJs&(n_&LMo>2czXy~^Xr z3gvT)bVv79XoLXu>h#9JD5) zqMOlhuh`qqu>J!2K^N_!Z&1C~&nu5(~w<0O7AqT-Z zBJ=IaJH9m1#$;s`1-}JXDG_J%DE$ZE4hNLTirOM?>2KXhR~q-qA)2W>K7vKf4d3uH zilsG(H6Hd~x%EM(A^$NJ_LM1ZG5kFvIaa7s-XzjlIM7FRTl{rm zI=V(-7zy%_lY#nFcJQ08_r*CI`pb;Ms?V7(-ddh3_yr#s=ABKeNf)phAs8)n-{o4K z5Pz}yzz0`Bfe#GEjp><*gid%0lEi_lpxm1RRGThRKs&3Bov5A2@QKxM4J3KoZT7wA zUYf$I2lMl9emWbX25=m0$U;xE9+LK}?-gTe9khDRIj!J#V z#*2%dxK?oR3h;%bS+gh*_cs;*lC-_{CV?9?p~;nvnog{8EC5~wz{7gs^Lx=JRQXpK zRm7}eip~^7p5Xd=!(7IZU1k6=-Cd9C7;Jc^BQLG7W@_`6OZoJk#LMqTc>URcirUKl4pc!Na^jwS3W}@5OX3Bk^MmtFioPhk^B!EC)%@ z$GyjeGAzQG6PKinK{YFV{k*GHF1ekhf1`3Sc%5k8ME*!Fh1U*u;_NSf@_$g;9XFRZ zkcrYom~SU-&BKz=B5mWlR0~!)_Ii{jI9qAt`SnGAqRJ>nKE>4 zfCtXdD4cs3*#H&BkhGZ8C8oExVdR%bw=`CSkM- zHYesTQIw^%r>Wkr|IbK5>T@z_z0l>web==*Ygv@Szk`%%`laIi+hH1#MQe)x_8kz{hX@|tA`GW zB&`bM7tSVdoKF?X!gf2&GAtpdV&Sm0rz)jy15&<%WIQG5f}Xk@$1a)kOCa zeXcY6Zi5E^zx>YjyF8$*zqz}XpMXKrp53F4{RqAHAbBVnRW0s|+Itpeb5qzrQO(%J zUb{gQl_9Y37_ho1=kK)KDc{NVK9*v2IURt{Z?@^V>)O? z+?LH<`t|H(bYMl4k;`bQs`aq56*-TKcYT8816Zu)=ZiNXf3B2}MLs9PN2o@jE+ma2 ze`%IYN41f}Bp;ZoRq1+hy|Dy!IbTb~s_mwu(u*{c&#k93`uk+)j$X)k)=V1bkTQK^ z0Gz`8?`D$ZwB%XEct_H}BVHmYuDh}w)sbEI5};B;p@YbVtEC?bNpBG{02;cbk^46w zzPHjTq3wS5K7x0m5?u!4r#A)jI9Pt#n4|aKxI)qd5B3c|u4YmJnG{4;*@1%t^NNGA zz}gc9_(zC~d3@e&p?B}sum69Hy?H#8@7p(S7ljHbvb5WkH9M)4ecuOJvxm?aV=Wa~ zD*G<$*tf9_gGxkRkgQaRDTz@ySF`enOi{DO4*_LIWh z6DA8*zTJZ|#upfzg@(S$E~9cQAF^OsU&s}GFSTJlz*4`&>T9I8`1!eWL3ht`slq1b z!f4&NEJ`2DM6?qHO-z4_7-D~(Ev&?34Gp>$1tX}Fjk1Rs*CZR+A8D^(v$e6=cR4ug z(jv5dAvpSpT|u`X*1Cop&#kDY+U0%?v2714UZ`qNS%G(Mool=jp2l6pI45CRITbKm z#yhN2K-UFl%Ury$zD>Ld8*mtQ(tL>-v-m1A!iV#k(0bSRuf|3RW-~+l;-jv*ZxmZ& z8Z(=YfSL3bxugZUzRBx(#^f{?K{C|Q&fxj7ywMq$mW_n!Yix82oEK8p^0Q<~I;UH} zNIaEMu_~nCKPJQ+chQ>&K3>uIXllZ{GqA>uIK;s4Z05 zt3@$IU>vEXe_4@K*GO5KwoyC%{;qa;!%mB$WjikgvT-Y_MgKFm=sjR{*t&))|8DvD zUZFSh+P(X_Vku*kMJNhtSHPO_5xMq-pgn8JxaPW&)jA@wb(NS$^&*_U6@ul%lxRH~ ztbE=!hLEf4FmvGkT4y4W-&ioNWL&Rp?q)o^x$2ykY})BNZz#i;lAs983tl`iBsJsN z3#gh03+)A~)Amjn0xxK|4&GxW=WeBP?3`xu8G@=Ynt{zQQMpOJ&NJJZ`Ky*1k@VQW znbvJ0i;7kjc_sy~?A2U9g?Yu1_v>Y~)`22z83OjQ0&{HcN#V$j6%{;q;nhTo{#^N) zQP2m?gfYA!$Lf$Hv?t*!g_vn_2idZCc5d80D?=b@^|n&SVyN};+`=6wOX6C!w(dJ- zRpaaeQ?|$M+#2t;~ZnMsCm?zc|A4il(E8K53cHNw4k}OR>aFJ^T>MgjkTh zVZ)*Y^{1+Wa^q`GBu~rfmP45NpMQAb6u26=@Qx(MFCsCb2;5}ZjgpmXZ;zxU?Xnq$ z@~($Q%y`0*qEOyrLD}i6A-S;FkEnh3O`DE(yImj49yS1hm7KD^V>m7bO+_;qu zEV0?ZW_QKMs61dfk{RCmp52~QpYM1f{}?zsz+I|zNsg5L2m9(_t1a`BjkEfxe?07drt4W3`irEIsdHZf90{KG+EL zbU-`o^YR{O`w5u3rzhQp5_y(arsy7R;&aK@B_w}Bij@B10s)p{RSRPO!Wl@*hfRE2 z0DuKV(9gMx?RMli|5M-^3A}`H>X>WOl#tIo$3C4da;;?R-(FP#pxNHNZrNkM>J{#9 zF@SeBzuwYrmL`WE*M{%!$6e|4{dPq0npv_OCRj$ZlYw%r zyM04Hnn}tXbo*|+i5Au}@cImPfw*&37|yv||7s;V2d@GXgi!05nOw!<7u<5U(uc;e zWJkn>@g(DIPzz3+dGx0@-dLu9$2QBohR~RY98J&a!)2At9;UCi1#FTqA-dicDCpu^ zup6;^EKRKIPWFX^nckXf$wl+N&}l%5AvgV`jd^7Gr{uxnvx{g}4q7;g4Q*QQ)ZF&tYKUYq<;&2G^1D>`i+wKM5>#amDq{j8q z48xp@;aper7~}c7iKM)t_XC-78|LvSeTh7(7(KV5S@b6CYdKZ#Qqbb`uYLHxw^q7EN*(!~Hq91Zb#u!XW*s(_6Mt5+DKQTa(y?AkuZFL_kC>2U+=j;u^{< zaR$VY=s5jZkVD1ZgtlNlXWFzI=aM2`R@z9x14!F>4?D;qN&`W?6tZt}3YCu9%eXF( z1`)#c!1l4iRH$haXW?j~+Dx=Jaw(6+lr&UUkw9?Ln=(VcibDA-k4l0nO7xT3T$YK9ouYgZhXsQ zEFy7XEAD_NyNmbNyMrR{N2J{+VircolGq0k?|*M7RsJe!!AX*_f+DXy!t0ONX?VqN zo~Pj%ZFjLW`rBXbd}a;foT;ET=02;vl+CE&%sy(64EQoRT1odnjI;CIXVy6=gDZZv z2kF1w8?}|Yf;6~U?}9SRFn1%rk+3Rxh`B=swE?8f@To~n%-*y!h~^Fbzk&t70a!4N zSgciqxQ+Upqbg@yQ>ze(XA$+$==t5ooS=Eou>N>0aLRC zUw_@0+O8_RgDh#Pw-jafH*^Fkxm_Sz1 zR2fO_DIr7t>h<5N1MOi*o}dzpK4NcmF`3(RyP&5fjjDorZh+IF0bXD@X59RRsi%=Q z28L>SF)!j4FGj5@fl5vgDzb;s$g{VAyc#qf~o+32!cIi7%4bf`#rG=`CeVijEftK|*gvJk9ij=IcO+ zQfG4^=F|quN!6TJDuc4!iGF_ByXu~82e`4;%+p80OsIZun1tKUT~Qec2I!Oj=u&2E z?WI>a98`X;RvH2uN`r>}MNBOwl=-DqI=RmNOg@jOD^JF{GSzX1-U`3tEOCu>V0_6_ zcuTUUhVe}w8*aGHWqXnBnUYekb71*T*Y9GPr&uXj6;{ z%nDwq$4q5-lxygo^Z6(`97s{{@QT}iVG7nibqwu~#Ivk;u}#xck^*^yua8HiWoE_I z&wpA28~QgM;5E?vA5T?~UYU!nCIhL4Hul?+Q4n%u*WB=Lh`hGL>k3@m`w!{+XFoYp z*+|5U_v1VY*;6#mPId+&1(IZFp&LzSRPG3LyIE$q%<#yhr?xhYsVN*4vs!jp&PB{k z<4R*j&$|YHJBe7W-LvvE^EpAK4XmyncT65D%(U*ytGjYL6dfFg4ht{adjXQ*ek#N} zk+Te?D(JDaz`}L1vE-@A(1h*KX7d>3WZcr-*Y?f;Ek3GOn7KOH#9v_vp1&ugw)7rN zH{%uX0+O6>TyDJ`~Dxv7%J@-N0ocm`rW4A?(Iqv5aaQH

zWpBSDCrn8qk<)a7z|ut(nXpR)+W`cY<&3UV22+k==QK$iJP=$BWSQ&dvDz)Y{)a$#qNn zptr4v*opf*<2aqH^F8Up`uP0C5UgLne@e>&T>ro=P!}tOZQ3pGG2ImQ&^YjD2=FWw zn5dijIUqeYzvEFO+rNVKPjCC~VKq8Y&(EdEdtKT*I1S!VXE|?-PTexz^;nnO);i!v ze)b|v+MEp$g?G|)Z62&io>^7ToAwZOXej3k@l@*RuNyq-=brZJBG}sM^!J!*HrM;w zCNu)&<++pfI3;2#hn|F=oVJV=3%{i-JjW*{b|m8lhq)o7M6~2Nba&-Ipi(pT+oaIcJ!ZhVu?C4bU1pxes~r8EWP-h#dI^DvtZD|+f@&Q z>*PD!0cSG#GEX^WvM{Tj*NAy2V(9urT)6vo&XT)Xb?d$w&5+Z|`|n=461Cgb+0J#7 zL(VTr2TIOdS1b=+)7K=oJcP74A{?I+Y(9S9Hs3s3CYJZU=2GA1`JItx-#H$iG+yy- zJH7I{==AW+im|zqvCT~19Y&HgxC^&$;H6N}MeXv>xV-Y~r@+R;(HY~~x98t#?;Rj= z)?LEC30#LhTVD{j79p1);h*%((#SF5#kzFA;-dHh1aOM9OH$C8HWth#NqngyIU6XZ#!k*AYCjGUGwQ18eJ5Vu;B-G8Y39Z;ZQt(rXEMg`Qq>ufU4Wf1PuE0 zt6E#>%dJRq9*KH4rhNX3A9x4AETLuY&r2t=&X-fW zus?$-pGeOLJSd@n>c{(0$orm%I6^5J{vz*_j-R}0E3s)oU|pMgVUnv4>L0g~D z>KE#UTQ9t!JDBU2bCxkjgUUqtXToNm7`NX3l8i}7F@tBXVlEv8kI92dGlfFA^Hw)X zc7~>J-O8pKvV|G{Zd{u5uy^hifw ze9@WWD!haQvk{k8mEtuv597*m#|8KY(Glov(>vh!t;|mkX-NF-$a6=NKPHt<%2TUt zYRq+2Jzz8VibumCu6JbtKK$ZKCj5I?#W8mUKYjXcpH>&S?BMtbL)EOsGk(T&t8!P5 z(oV$+S}4QE_~(RZ%}Y9hDLlQaBZh7@1qTgrP9<=M`S*D+@2KiTWQW^2bD|0!>Qa^* z>AwP_6*6yA*zYyB=h2I2RWOyH&sZD~JYrplFQtGo7BnQJrY}@(Cv0w1T8A3d%TxMS zkK6%I93K5=VmUhjS~r__pmjS07Do8QviOaMM<|nyM0Zk;N+z0D?m)_QlX9nBV=5AL z)9(#^(L1;UHyO(QbX#Y5tcpu1#ga>_DugscO(B;^aE=lvaHdsj==4_C- zx#vtj5;(qD$2>|?8yW4~l~1aGw-t9B)wR47e8(}c-&vPcW>T14_G{jw)a@NjV;c;I zdXx@B6`i>(9RTuG!E2R#o34`p$giB5j9Vo$gkrI+R5NMWac;OXD4 z6yFC2pEKYBz%KonAG9~TYhJC7tX(I0KxTA7wlas!)s?#JU?{I96{F8^-KIzW5Bx-9 zOwv)>Gqg>0m^b1{uQ^#9}CrYa>C)t z{ff!&IUU&MzU)Iw?7oX!N+p(bpULjSiAH<(YQs+MC@PU59&0hYM>$j2v#g zF@#&*yK?uO?UAd+YBqJ5e0Yh(vt|^zlo>i5tk`?yn7~&Q zjSh+z-jF&pA_27Z)-CVq2D4y-^}{F4q>mb=hiFHwDQ`S5ZLx=W6yy_tj=ILbtIt_I z@nKIb&z;w}FL+jJ>o&n>S;70oYDBy3;4%vT8N+kG8R*-trA=Rs{q{^{+aRowXjrC@ z{75u=L3n0CKe4-dAU4>g zB=oUXJs9;uWIl1+W%P05vbmQC#)@>oT|Nq0A%fU1@~}`$SbQpZhQCz1Iltx;z6YGp zi2KPmA;j%&U}72)fI94T*C^2i!Xv z%)S7l9bKFP-GhAvLM+7aI3FSE^;@*cY}w9djD z@II8AVJkvT{AyN_nOh>XYl*)^jY_L}B<#!K7tsg42(0=P!<5;v`&wMC&;8n7iwlJ$ zi&?7f3(=D%wQClFm#z zLr-Y9;!{BdWI270$p-^rpKxUu)ufxA{vbZ6cEzyF?Im+^7KJ(L7ywHGFfcyj!QyP+ z1B15_!@ zK_xvuwDhG_aVKfSI%=oCj@MmI(hWhEhM!HjtvGQBzaE=mv6AJ1i__ZamvgbFqMD1D z?e^ykGbE@NA=9E@=RqK1l8jzFY$=T`(0#|HZ&yuMigfJ^zMS&_pGsO8Ca?jHO375w)zrA_Pp6 z!Q3>Q%Xp;}64#>xs%PaB`y8dWRZXhM?FTa;W)|bv)+LwP7ousp6=BR1uOj3^7~&Vt zT_L+2&??}?b(bC+?f8MlrSgJu!3}W6Eti3YLAk%DPhv^-$!4}}>#P9Pyt)2|2J(+n z(M&gE(81Y1!`cOCmcur(F?|6f2c|Uvc)W%#AGkaviNRRB(?S)%g#k*IVF_)$d0!n4 zUbg9iPNP$&Prbz}84=8}f${q|Q=llehpzD;Sx&f2EbMx^%dC8M?Dr6KFY=lZY^&F8 z^%`?qUSAooN|s)%@ADA%D2E%b7q;-Pq-#J*nh+j% zUv|0}g|@4`c%ew;HXQ0FLiMMX|9lR(#DCnaG%^&cMJO8wL>0tltSZ3&9GA=h=lu2F(V z8hcaq<}ka(FJ8FOZ*Mg^T#Vs#z&~qblcnt)^Ow}F9B|r#Oeg2>_r3B zs}a0#(y>wvDu+U|L0ym`C)*tx{-VTRM<##7i`Dk(kBRpfL>zhDbSlPW#zyPMB*k~c zeO8EUAJAXzn2=&uXQKMj0W+wR_L*_DZmNfEOGNPtazCLSs_;Mi2@2zt zUFPSsGv^+3%XWV|!VYCh)wbgaIXdyGk4RF;BPYua9S|3}pPa`Wl@fzY6V`Ohh3XfC zgy3$1U_JR{L}aYopwTBINC3fYM57S%K!j}AMH~XgFP&V)u8JF4?y|4iSLN#u3{`Q1 zG@XXWNyl*sP8Ry{gbj7NDgWcB1R!!UtF0iMU<#cvyvlQ+Fp^ci9s7IDS+325bc;?o zAQ;3rPw&wD2`~LOPfQ!|#Gu}t=SnPOvOXL?G8&<}lNGVM4}YXu#(cU{pPx7PcrV|| zrC6@iIKJ&X>FH++wN#_zb^&HCNca*9;^HXG5tHZqV1m5{B}Fs1z!|{WG9S-Q=d++) zoR0fgH2kYcsoYw*uRW~N$xRftVNB(qeG;5@1*41C$<#g?uERP3WVwJkLHpfGnBT9* z0R(#+f79V+Z;42i_DfYnpK!mN66zjhK@}6jN+hHEkmDJ?%5WQ@8CStN_Nqc9O}UAq z4-4S^y)>JtJQBlRrQR$B`jY34{HFje`SSe!6Lmh&x-b3DNL7ltMxG65r|~ngyr(#Rg=;&v4V^GG~JgHK4?X7$`sD5x=RuBo#s)g2I94<|0%U`J7dq05igX5I>6YX0s4g?yH(MGRS)F^Dpit4X@{cfK$<_T<@5SB%#jsVik?hNNL>4H~sXNnj$Vcsv|Tc@a6{WSlFM z0!k)Y{$Vl706u8FRc@i#3@oq4Gw^ccS&dNc36{h*j9ldUj9d7$^*$THMY6Dn8ICGPz;c<3Q2|d!=lu6^4~?NGUFOBQ}%`| zZ0~nc9id^UvfuHOi#!&d{q4o#Kr{upnk^z!i1&AaolKou+Z9poxQ@tN=o|a)*@VEH zzqsqjaWK}^u(-C{N379nSm-^~B0$;k;j+7f+{^ZK#S=RDy2Gr1Sy*tPiY_(!n<$O{ zOg>(8R?fYMA>6T@4|{e(Y=lpU6Pz1_MpVfQJ6xc%cB|~pUV+iENlPLLA5+OR+~0zP$R#=g%OAo^?VUnQT~Ar~Lqb>ams0M%4VCcP zu-rsb-;Z))$rMte>d!Fp7pic3#kGa^`uV_%)6d%!9q`~;iS(Vy&QDHMK2aO_8PBAM zK6>{D<1%G_!rE|yV|*^D-}^dwnZZFrJp$pZgYKIm4Y$9+)Ud4=9iI>*r6 zkz=OUxr4n2CRSp)Y;(JCSM|heJUB$IHx`q`gkLtlywA!|bS~q>z4XT~#I7XpMXK2VQ=%X>b z)gM5#eUs9v3fS$H-@#j92W6T*QXP#v9|kC21e9{ToMC)WTp!*0FrNKt;z>-cNMv&(YUu(HiIc*PGOhWKp5GsbsA%PVABRWt%HiJ9|IyA~|nA zg9)xB&rM^lR(bmn0m|*GS7bWA`FW6=hW%S$c=6Ea1DXAO-2ITJ4wxtZl)4?9bHSub zNoO?y1S>patpPCSEI#x#%f#gVD?eS1F+bwsh@yG`5tC@Vrl$%rQQee4Br zUEaG5*)_8C$$Fi=+thl&>u*{Bs0Vt;RS{4J0-*thoJt1m`1n}{ zkGAcQO!mwj*^DI`w9&fwyNH&-5Fw{43F`&3OiRowk}Cv zTVy_O%TgBY!A@v(VZn>DEIG1GaD%}~fT-+yK5$xL0EPWAdt3YTLj*Wc1=#V2E z#|(SUjVL;pp9v$bNG=6jy9?_V3NZ~SC2qv=uS*@Ehoq7#2h*DK2$=b$wFRH#w#1b; z)>F*JCM2&SZIi%6OrLT?ui(sr6msm_kd8+T>+3w0aE+QTgggEX3)QEZxd<-pVE8o zGH6tFbwGHWyHGa>@MWP~y9;^g+I9zQe4EE`JLAKOcS?-?W@_;J%a8)e9S!x+$z4IkEh3jQhpe$ogTlznUy$$M26^e|0LkBq> z@^reTG+v*-#A7{Y{+4Br7#EcC8GPZxGm!jjk6QOvo0=0i|I<5NyEaOvdzo%NLb9gp zG&4w-?YomUt{+%p@j=?LV_i5{)H0rnKB8iN0?9iCv)HmOUxmuWTTj)lz}{pYl>J_k zza3npMQl7tCX;%BFuudl*bFnid52ReJK_`P+>U?vYs=|;zJroX(P$n$9Z%d;iL>iG zn#WlLhgKj8my-whimks|Yg`ZMwMYNZYk#gBf?eZ=esyLg87V5Pn*X}hTcTeo z8kIBQgd`99%iUf_4sUVO$`b6ui~sdirfxhS!^CTazVZ43Fz@fD{0tntAyqJ700`H?kY6@s&>DSIQYOZ9hWCUlN7=(Ebm^OrR#-HG(=FndZ#fsMe1!ctVPn$RD>mS<0@ez0S z*E&Dbj~Xz3DiZaDkb}Q1_m!^fEMy;KWzQqDl1=wA>ZNQd@GZ(>-f^UDg5y|9ukT}# ziQbH5j;IN1RS>d@+r{9XvTl`xFHiABtM}AwPo@`hm!zw;>ngk)g_^PiG<9?YQU3u zC&lsViM$Pp&+ILJtxZ(;uE+T=Rgz`&;ah+ms`;;~<|hT=zl&MO(r17${8z~43% zM$3g)=?_#oF>_^2i9|xuK@a#9uO$(>0xMF{6Xzqm5g5RMIB{wuyM&-eaIU~|s3(nu z3f>{EFXC>lLtL{Mkb#OJ0Xu(*J9KSNFKoZ9Pw7~B#H9sMZmWOrJB9AjtCiPImnU*8 z#c4@9#lY!IVR>aiJaPi)5PL$5q{>`r4l0#z6p9YGJoajCdKTT&R9&K9Otc9x`rK1g zo+-NA9Rs+m%O3>2!tZusSVGIvt*ppg13Vk3 z-$=k5){302;S4_&@#4adY1CAn*_=p zbk{9^X=XC zUY;CHc+$g{92YB$w0&p#x1c36r!>!R+ffY|?UGW55yr~Y71^>9+c(WhvvS?WZJmTt z`9}B`3tyO}%35mems8i`rI)4gUoDcw%eOC6f-WC$X0b13pWdb@k~)guD%G2OwH@17 zZ6UMK$ZH@IHsHMfkVig-A){3+(cEKFn!VT$vLLfFd&F;;O#Q{b#6M_1wOYH-`^ef$ za>G!*JQ>rJRiBi)dQJ+>K-Udg#?*qB84RqcE9ZqaczHV2Ub9Lr(IYls2zr)-uOD0? z%lD)tqR$l#J>FGXX_&>_zRKA1`)45??WDQN4VN_cU#lUiqW2CC>98J;VPB@DSJ`i_ zcyP=kSx4RcRTKsiBLshq1>Y_j)#0_Q?4b{cb=|%#33f2`OsrkeFdv{N%G{@2#8yTMc7^l+WiZ{BW9rmCu!)=t^}cJ3ibPnBv%)W$nrhDQl}d~VjdOJ7dFOCmyWTR z>=+Om**VH}IF6YNO@0T2Q4aP$`q9m`6_T83$Bg8ICBkc4q3$rLdS4|bKkl1ib%xpO z+wad*rK9h@b9-Kku|Lsq9yB@GuI{DdNrK#gP7gWRKjMyQS)O_2(GABe(4?k_ENq*u zcGMEs+??vzHXfYhR+)vN%9KIfGLvGNy*h6HYQlav+&3p9^&SzN$P(Q{iGZqV^q z?7~W%vLW=9)DTUqdD7b>us2H)Xx+*+?J&P@JRIpY`{`{@jL5{xqimg*$>17l+n+t? zNz%*vTBM!#Spwp^^vuHZ-9p{SbTjjr^g{G@`JJ2}G+!3bu0q|_6oaS4lY(-0$~hkm zVH#d5dJm5*K4@mrOqKFDUQ&^zm|zm`OIi1;e1>iVZEjuPdp<@nz?yfnr}L*FLy)Gb zb$R8{a*V{_!Sd7fxrEzr{naKqsEOlA8GA(o&Y;m3l);{`Um%!sm9WO8R}`+Lc~g@0JY0Fe@i?J z0>^)%sTsQAE3$*}o({-NORO z-!HdBBT-)3545`4Q2Q$B&#CRaX^l<=f@L?;cOE zZu`2L)qt*ED9Th4YW1qL)K7nm=<3|iwqw_OggQ%#`dpJ6%h2x2SW`UGbT2XHjY&DC zG~c&t&e%1P#%L1TYA($GV@h)kHyjHSGyff!5W-0$Qd0sklnz28#FWholAuu6e$iUYwgPQUrm zNG6Lj3OjyQWVScRNT=xi4VDg-c%3#fqKCKAuwpeB3i7_>kAP6t zvcn21>|d3BFV}vS&OPh4&2i}78imWOH<)C`*~6SZg6c2TKh{7-VQ0hW&+P%i^6;T} zjpN9FQT354SrN0!c*l59?AH^X-k)j!);Clip1e3~_-h$UY3yp;*4LQtNUpU*?iN!^ zmh=FflX={mQ3o;&kKAjxaaCYHq_;w|&g)4>iATs`{r8TP*8+8}!guw=KB)^^#t6E%v!*&3rml*fp;XHsFewl0WzyaNa*6Op`sq_h8aO#x^Lc<>q1B+-f+nY6Zf%4|O=H=HN~5 z{%A)7d0qS3oGtlFGgJ-*1GaytdSOLF+ms9;>90Ar+8WS5cgq!@I8FAl^~zrWL)!kc zHLqpCccf!%-FzBU=+pnJLO;~czqQ6U@i#}my`P}6-@xv*<-W>dU`!0j7^AW9=2-IK z=SwE~gE$#7)p<&0vXdm&uZhgpfHcv+Dl~ap%P^ChYB{_&vinpz_H7;@(vvlUcQX>x zoh9!xhR3LK2YAL_ZDR-TIG`n}z;^L$GKu5;WA=C5LUv{`EFtmI1<5AwUk$*gZ z$Qs&OBZl~YxN2}F=aF}ZS`G7v$>=LpWKSLnnpm=}P|@EOmTC_0TWwH_wTCUNmmGal z^6kII3@UuUz*lw##00H@@ks~sJQx{$aAM_~8QpG`A)?k;KX0w3_z=xo~8$&UM*hn3VLNqZM5Nh`-@X@onzq6F`E<{WY3w<_Ltyq>kt2Q zYpS6NCAb$;1dO3DD|BD6lAB=TJQXpMuihn7jR<1~O5vmu5z zs(toB`=^N1>I{B;>t$F137SCnkZjBeSfHSl?cM*wr34Q8z6OU=&(!Z=){(fs-|~JB zk84YIv=`O=ic5QE_&e?u*5Rq%F#5zrR=(s%kN>K=#h(1R(~smkWd>g(d289Ea{tt& z&8+Q_rL{Sq(nD)QyKNnk5O{{s+%TJVuK*9*jiGJ7QJxvTGfuIs$izH^(n@p8j_`hpKl8J$wHdb!b4Od&*6GRxrr_3_C2ivxgtrAUB5H z`)-*REd|jGyPL`$Tyr^DR&-twIeq5+o$)s!X;hnOIe`<7?_MN%Om-uA$s8W5skl9j z!i#@wXH@9P&p=1z5dP^jrJ6H7UP|3_*F(~<(vQLe(Tk_R_TcE<{o4V5bdg_d0D{Ps zt74%U(5W`u3!|h|&St)2+Cwr*Vf4u>sb%)Z8s@a}%^)uHlh*aA*?i%#J(V6Gbwo_( zd0Tl%TyXy({25dmK$EvMa}acg%efzLzcXA;8`wP2 zK(%OvwzM?-wN@|)UO~)0&+%hVNS<4#(vT=WbX5o(#>o9hfKm?*sYOs<4taqr_L72F z(s%2|T=aC{)03MJ*!VqhF;Ng*#^6hHj4F=!(pC3==%a z_6U1&+Jnd1Yz>jk%T=caCkmeI2Rcpp2V_2af65R$*Gtf@4&K}QkYt+(kDP1Z1FPd7 zpLBcj>cIV79r9>xfr4r0z`QbntCqC!fib1XCR30EPj)`IiliH7-daX{HDTy?vb+4O zZg}br8p??TG6kK1+{`>gLyb__hXv;SiQeM1FewLM&JWgdcw6Wc$-uCGv_u???8eG=#IMAK%gm6&4OC-2cbj zz(CL&2}nFyEoq|eMbF*8Y_Rn#xRQLYX6t+QNxI5sH+(j+P4j!mfgc9?@A&pAY3gIs zp5HcaJH#p1bCxCe!fLBGB$vwNgRsP<%8jwW!ESF>vN<}d`rx5qas%*7&hXol89_M3 z@O50HF|!FihOJBpoR#f1-sI|pqAY9-r!0x)P3y8`GCEjHY|BQBhvqOg0N~D`kNH#B z0IlwltbK!lXWaB@p<9as>nYUigU;%N+V6m@t$=26p**xe$|u_l?a)*D{KKgRI=2_6 zfU>WiHDe0kiM5IiMOpklM zy>qy`M#(3zZY)^Zw<8K|;oAT&Y#b}J>Bp%=tBkcIQKW)_D1mND8Uu6$6IjJ&DYkci zz2hvwP2mu^qjO~K0CW7zx9*(e(Zxq3o8|Yy%IW(vU*RaN4b%WFu6d5|O?{|fI=Kzs zhMVD-aECc@`N`QIEbSS=>O>5u>LG=m_loS3t0zcSV|8;fi<$m`i`w!`ZpOs7LHkx% z=hFzuQ_6i6TYC=H*{J(F?hPb&MAwcb3A5GlJ3aDX1yZ}Bl6pquAIZRJ$F_K97skU! zr$w{n+3Qb3HAmJa{uraowS7#S%!`@*%)tWcSz^6J%RF$8o_-=pelJkaoFp%-De6C_ zNBtJM>H>8MR@2y?8vSS6GsRP52aYqh_~w6u z;we#w9!@qIs=>Q(oiP1A&3UL!7f<(0U);g0=!{IIo}&2GO6?21>%HQeLv`m8OzJ=K z2=iCVI_N&<&TV!-RX8~St8Y67J5V$a?kg=@>A~ibR&tcaK*ML4(!y=+fdY2a zowOX2IiopP`G!w3OGCSqsW4$lSO=cYeqZK3W3s^dD9iU;`bRT7^4gzF*dGqjZU@^$ z2`pN=i!K)7eXt%s6Z_+{PZ>`!Z;|6>A&Gd>1BB3gcFK%BRAU_dq?YjxL`ll8(=2iH zO+|yB3O?B-{C+^yTnVv^nSJAy<0>9^b_G|t3(9s?&RRQZ?6zs(J6c>u52(;~RQ zH@*QF9EJ*y$frF0nc;exk@+p7#~oS24lgZ{qqJ1W%uD&p9!Oc!02e;H2BB$x_6K9a zZqT9nsrrKV9}?ss-v&kCLtA`o@uYnLmxzysz5Wnv;D<Ch~kVk3eb?eYtND}TXo5y~jul~SaKQ>v zK$+bqJ?-Czn|U*iT`P9oQD&b_rF`l0BxHqHM{=PGDKKmJbiA7uS-9(1btPE4Vf>`s z3d>0?7aHe@)d$DjlVlr9&}Xz55k0{(83gubwABm~oCg(>O4KCS@9$|Lm0NUg;1z3; z6(Sk8dn14o%;`VH@!wI^vC%2A-hA?~N3%R8Y<|UTO|Mm}SF3VoqgR|ISE`A@ zRlA9OSP}8!XS0S3M6geH?i^ZjRttH}b0Ju{(HFm_?R4*4)BW`_yE8}*5^_UT zdU-|l@wieF*UfI^Fwdxghtb}Mr`NL50&_(A!5~ zd}&%l!UVc=19xjIsV}liJ~kF_+ke$@RJomD`$E9i$D~`uZSRL%zwe05zo!NQe+;s; zZaHn=@U^s22>*fH1IrNs&3b~1ghFzcE2JTd#Dj{p6JGYQ+ZXzJ_GsM-QIk}=6tI+) zkhYeEa*nL1y$TCpcsc_nlA5QPl7U75FaBq~2O5$?*E?XB>IF74C%P!yYVA1WO?(f% zi?Yh*dSbEZrTF0?9i(dVZkti7I192@ZCCEPn0_ie(Iq=asztL3QzfNRGl8CFl2fE^ zr(s#OeO%cnmhPXpWk7p!k^7altef%<{^h#}k>Kr1`+|23zo7LdG)QIwuTOFSHW- zdDi;$sZR(t9?P6xu6)8m?^y2tgbwAiSsXful&yD3#zzNbB?Llz`bMz`#Dwu{4z3%F zejlYweag!QAIpeF_kF1{>8Ug~!QX^M7fE=pVVJ@UB z#+tUstA$ogZeOiBz4o=rVx&s)%jLGi-ay+84Q23Dg0H7(K5Sl-s6X#Y^>S45;}{xh zI_IZ?(y?djy_9mzB?&p!`&-M>TWCdI$yq+z#?&RX`r$1m^ za+t#%M`otE@?MvTh@86Yj7(?s??P<_kg2$8(~jy zLT_Qm^lbe41(_dZuxt3-SPlg7$}E33@9i<-6|Lvws)zaVapp)o9X+%3ugP!Qp1o^V zp7osPlu=z-rjYIC4;MOPtF3C{qLTa%r8g(J_GQ^x@IGrgtpBbbbeQtnNKn)2FVNh= zf8dlslCO+)&(m~jhrUe#Qvcex$-;>tE=dc2^sl`kADEGjxDS15tA1cuj5K^;!xbB)=psF@xeh&u zaxT0xfm${#2o@8!{$p@R?SISm?!${=iWpU;FFHMuWXDR%BktsCz4OB#i-}?e>1iKm z6l=FRxhF0tA)YLmE}PufZ?+}#|8mfdp=b5=46~nfa7p>@EgB`23-jz9~z|5dZ{(07wMFemP-f;6>Sx18&{W}JfDICx7yVS<-Z|QF`#0s zr2rOx?)NVKh*IfW4t}#KM_O<=znwjTW z>t1W!>#o1wUYr*h&Z!Q z??N@?VzvG{$M56N1$8gKd@4dOM4X?$(h{J0o6c}OKSR00Z2?_DzyN6C{}&7Z9IoIr zz!h}-BCJ}k9Z0&tu+qRcfS@ugQ!JlE43U>RA4L`MH<}rL*NYvyPVmc z8qr1Gc+Y^P%i78psvD#dcUgd5Pr6@>>y`rQig?`KnzC1#_bA4W|!3C`(x^Fc)0Y}2X|$b z_qKO04?1_{i{I!^CNG^2Ywx zZkCz!hzqDko5Q5yH{CJR)=x3t)ST*s1TUL=Z&?kxeXSY_f&^{egI&S&2;;QN0FkV} zZ>cbrs;s-)94bf%&DRA4&wH$a;=iOZgy@x`q20)$4T@HmPK7LE)F=>26S&_ zW^XIk%SEP+6s!^=g)PgTNx6ZnmR1!_f;nZN3NtIuOszlQG$0W%zgwqsI|au zaQxk{e$N&QWQw`|ee?QEhW3cI+wGR2*()O714TIF=lClgCtG zQ7#&tHaQ_6VKmHp39-`e0FNnPQHLzsR0;bh6c1lDb`B{w8d&$(A@f=QCF zDBMumVB~!o^;Y%XM{4ea6q}z_!z9A?!ZuCY0l%@F5hCusRNRxr;uhNzJANU<;nG<4 z+zv#cL)Clx$!cL*0Cmkm@Wz&iFud=WJYP*r@wz$syh5RV>e=m@9OR?mz1QoJHq)ym zENcvcGm$ed>+hZKSmmknMC}>P#VrcieA{!8(n`#>=0*+WExFs>T#gwzeIOAv{`)sX z)IN56u;RtYl2hEG`^M0>Srm4Q84`hDx67QnG3C-x&^*`T3pFkm>B2Vj32k4??bgHM z5hhfhl+ly8;p0Wyz)19%C?R?AJuuuu&Zy^wsCbD$X2!vYe~L-cp_B1CzoEL$d~B!Y z9^CCxdKx$S76boMc8fxDPg!GDG-AvvYn?mJo@~8U9r~6@H%D!joKAb0=W)##?V0*K zt(Azv*GPwaVfdopGA)^J$+(tpg%!)tfolOgpki% zy!k!uYHPRw+CKIB zrrp57!89gzrif4(0U`bSbx6b36{Bvz_o08lG_5vqPGL@J>4m%HR=+NU|0LEZ>`K~t z5Ze+fr%+{F3DvrDyOlCO>w>Ls&^{jd=w%fe)ygH0~ zOHck#Sn;I7ZnXSVAuT-ez(X6Pw06~4t@N4&<%-z+xD}^Xb?Eea9dF1VU$zWgg$TzZ z!p@M1y^bLg`@8MyC+JH5m~^k)2efm}HjA~Lb;nY6-qx3)pEd z{=%Uz5t;Gkk&B|?>e+#*q2}kWp?vF~n`KcWa{5NthQ~wI%WEA~F(I; z>zzPUF9^LB;649T?^w1VT0#>}^_d|_ol`usFQ{^G-4!{@E~8!l+O?LwfTU8>_ay90 z+(T2i*iCw_*30Qk%t?_u7g_k{GS~L}eV3%7Y6@oy5?F%Sq(JMY*HNMukBbjQCX7hD zlk&m^E33ik824$QrCGeP;u)sDczhM;AJ%ESv+#RYvi$2CR_U~!b2ZC1&6))YzeFt2 z)uxBbdG(D z?sn1arE@R$ROO8pMs(dQZ%js7Aka)>!t7MeXRd(D?XP+TBom)|Y1D!s@ZynVU5-1a zs7fB%>=SWsPB40LRAh3u_BFdQtx5BUJXzO*Y=pv<jaX&A zF1J7aXd#eJs|)XoEb_jbL^Ys>Qp)n#vl zWV&TbPh?-Y9bY=kfi+VYX<`4^lJ-mAh_z}G^|iqh)>oVuVB_qC^v#j7T6s2et`Kci==HTFoel7*fsX{{LR zI6HF7Podmr_ln1N_y*jkwrTec)Dg3YpebV;&<}i>kPU5I^7}Jgi_!wg)rUvPRWzxB zRYza+hzt!V4W+02GYbrAA@DKa)ojqJ%(e9EwO^rJ(7|}ePbZ@%oUlSqiy80IE62zZtRtehvx`{40QasTOJ0i zJ%X6K&Na7&rf_^cIe*U{G<`En8%y}J;`uwA zaFe+X@}9T|ARe#8peb69wh$?pJb4923<7w42*e;bK=7`qdxYRTFcsV5Zv%;Q}r> zE@_7~Ne_3BRjoa7pNe4HtKf`d)+Ry&e2x{x<47lMu}o=sQc;y;1`d3$Z}zJT%0dK` z!owB@^^^gXMp%BpuC~9WE8^+uvqPy*_Nyf(=j&I^Xso=>k*az9mf;xjd(aos z%ZXoYz#Rj;(G|d!fg>$=>xlBjN_SD+d~xS`|HvSSJN)I$KmOly=0!_gMhdV()O4Cz zZRMqGL3QE+wK@cMUc$4SzUIgqjKihZiV5kpPdw7bWX0mQV*4OMX#L!VsOnl8r+jZ8 zHGstrpeGvY2#f>=qEqGBJ_h~orh6Nw6!hT7hO-v(NX*=;OWJNxq*eQ5(&Rs4-mB{# zwdo*^gL$PVAQl_~_HC%@j7#mvZ{882xMSIF{Ndb=?yp>gM)d&zuzTleWbQskAQ2j^ z8vaP2ji$SL30Sf-U-YVQ?KD|y_7dM26`ov_yD8Ii>?>(oM|&@f@sUP26-}h4jVhVW zf-V1JBeEGzOf8Y4`bacj8_Eh%BwP&Nr;Wno;Key(gbwNMe_}d&)dTTxT&E%@L4wgN5Vu z{HEKQRN%aj5Z#Bh(LVR~Ox?lF;Z9i48#*~U)3eZO0^NvV9B`Kh>Phhs?pYi5|0SB= zZw1zJk|H^}c{?tvWBLYTZ^@F}I4Y+Nl;fh7`xfn^yEpYG`&&%-RKryZ7qr`-J+jDE zCj)5ld6{i-6R5=dlKThc!(8Q47Xku=kASfGG z;*!Vd|8U~T;r~-7UfVm9XgINjEmmO#h8TI7@AF`7LF)EG^Q*Bjpp#YxgwGKOgK-?& zT^4^Mn$bv{y+t7=g03ckZVNSL{ctTMp$y&LAmX&Y43xtumSKX5ro<)AM2`|@Rur2* z#nRLGa_q;ty6Vb4wYsWrN^44O^SyC0CfxM~Qc<_YY{x@&}3M6bMGU9ateE)sJe*xtKZ3)lg_)p{YcLh$} zhFJ^_{jHd7nw0C~yWgMjFBzp%LX3Nk?Jw#eT2CB9UBUGS=FhXC;C@U;6i_%~zpf^N zvVOtJQQ!Pf_J#lqedHgRr)JIjV&Fa~mC}8O%n$V)&c?lmz3T z7Idcxtaf8GJu(v0y)8;hP{lvWtZfx{Hgr9knhrrMmyjQLKXU47S*mdc6{!Fv)98z5bgojTnD#h2nCtt89eJ-D$v6oa&Q0 zjs1&=`pLEY1CIX5)?_iyI+f6Af{HG6{0&7c$L z2_pd1{lP-?CsWg($;7&{c;U8xz3;Q$;8Y>U(76FuxNy9b*WZ0!{+xJO6hXipE}`*P zs2-0^XN9kv!$D9~G3%I8;^%S1ro_SX`tecK-ioalY^xw~HDe4!d~aRY|MAxBFPms6 z5G+UH#s8G={5OUsRlMc$9aLxHYwSQ_<nd zFzUUHgT;}Vy`@>`i-0sl6dE$p`RFO1+2B?vHq&#utzs)4hvNs}4844&^bk=)Gzs zo!UpTYN0pgwV4RqPO)GZ>lzdf)zKe)o?qlYlxjc~`WB`vA*X)^TT7Kyx zEX1s2@^oK9mz^53zm~*QTe$}{K67DrAq(4AZ=&!5or86Ah<=>91g?n$lSaTzTNTJp zi`Ob6lq_i+aU40Fm3y;3?B}M-aJ(0=I#2J8wYTQqW}&Uy<(F(tK?haVib)2pfAXrt zR-ymtBdv1fG@!&3(a2M^8yV7Kzv*-#rHrR7AJgilgc_J)z9DUuX-F;3(uPw{L+TX@KqoZR06AVA(h6ESXCNB^CWc zbB-%G40-3vXhILn8mUchA=YrvHMHNMy!7amsjG(xHPmEPE)-^L_?O%~1*T<1?Hq1E z(>YqLQZ9U$^0vlfawmw$V_Ffk|5`kwCG$85G2J7Ct5XiEk++VdJ~&zbTrcK!C){RDOE=8jIkjQ(zppzlyT(mi{LdeG8UB1A zmiy})ZLF_W(LTfN*bEbl_bNp2BQ=FMXzxQKAcfqwRLE4sAM;ZGc2QRH;bZf(oG>}> z1kZWnirJ8&5*0{tG(p8S25|+)CsuWdX2yBN6KmC62;LjHzoxNX%0@=Mbn zl~xvF^HNaP2dhuD!Ja>SpwQe+qn+;^yP-(lcB=d`pt4XNiAt-^&s46qakdT1ecrX8 z^=UbLIqIhr);Nm_kWdR_TG#RyOrE%+&_4u~jWJsncIR%we0DvQN~tuF>;pJT_rd6x z8c<8ar8Cf$q{ICo7wQH()FWS=mVB_ILo?oqxei(I>iy=>fo(|oYTAC&603(g5sru@ zXDRQ@eV%bR0{ihTv{ zx4ph15qilx{W}?X@Ha6zJm1$T5b=J3X?#$Vy=|@^B=Ir)^ws&>fkfMFb^M~eRxs)j zO9QNXY_SDkZkK+55{)cjn-q+k9D{G7Jnk7k%2z*VU5bk?0;?14bm=XDT$S=@y)JON zQ)zScUpU}6(+wvT%?@tb474Enm>>4VQ&UZ#=ap;{#`Z&<_K0e|dO%;_*H09x9peM8 zIl`Fj?R+ZP%m8E9doatBDWh_Tkw9G|a)my!WfxW^O+12-{-=T#g zMFeH9wA|AUQ=b+}C{V!EJ5#LG+5?)>zjZLv@u$fgxu%UUx^P;1tB~^4b|vQiUpBef z-b}BtPQStxU}w_wOXT1A+&W2~-$*1TjQ!!oF<_sR;hsbHkgScY{nJ>Yc4RTn;R?b? zza-ZY7K~h+2p6LGW*5xq5yQv{17?@9Q-R z8if@NEfQu)_l8_#P=L29ZLbur!gHI;DI&nIlzcc($e4_FK)gQqIF;*!pyZMz<3OEO zi)DC$+^x%Y>b9ECMl62G80M;6Aah33w>p3lvI8SM`p2vKDNXyK4&eQicN}_lmpQfN`1!WwK~jt@vUj;=rwFCfO7JB`k!L)-&79x4 z2sz6hBi!2I?DzZLvh2va9W{JQ(9ekl`Q(1zuzby&V;Tz)hrkhdyCfrn z_)u!Y11>0kX51xR05E4|moi1FToY`e2O7-2Ywc@qX($fs&@0=V)icevo8fVA{Wv2B z>Bw~x-Z;MI1XB z;Bd$4hgjmT7b1UZ9A!O#0c$*O(%yr=!lPq7I&6Pa1F8*H_8DKg)f5iepI5&<$LD$p z0V(ENI=SsbvA(8H$Ku{OjuK%odrRZi=PK!*EtXH+*dK6*n^HTY4jRSr8{_dMu+_np zEmF@CQzQJ+w$t|!a>ZB#vBvP|$v$1-6UriTkCP^#`uUHo1W;qHRheyon;{<)OeX3# zxzlnYRIfu^y0Dz_k*ma6aEZGE@Pav-&k}@pTqL}M3(gWtSUFi{_l?hMxLHJl8iUr~ zYyg91@=6|I8u_@mS{Sp434R*7P9*2vIhKV3uo=JcYLO=~=A9#J1*|UvM$5hUY4BGb z6K*vCgyd@dYPVt@$}-oB>hsf#zqn%jDd4yw1&4RE+Gv%Lw# zFOAioTL9#QG2+;u4*=S@B3$t2iUTDm{(N2NkzUoZ{l)) z$oEZn0%CfVvr|1$`=lhB12({<2%+n79?`Ui#`&_N5i?hy1PE2sI#+sbtb54pH#LRh#niM)oZTJi{&p| zLJQ|K^a-@MXZ!;h9-YHikpN*hN#X)`A5(u<8lSK^g||IN@g72cO3yR=e(`J2!okq= zmzJHtuP+Wa<0&cOBO+1-05^=o4{((X*m9o5X=e&u^Oq9yktk~!1ut+r{v1xkxJDA9b?9`v;eNbPgdjr8-geK3h4LwP#PcVnpJ^6Au%; zgsr!o5shZpO#=1I$sUVM?lf`UkHcs7{1y33RyNdP9`w&3FD`lNRN z`qs!~P#5~HR?&WyVHG8E+tbdv5$9vJ9+~#R1{UNaX5f+KpEJXhSDd*ej$RZDG_P1r z0p&F-Bl!i(u{z2~4Oh%^mf1&WQ`BAxim%`IjMN&cX?uJK4UJA+(A@9zo9k&EM66+1 zR!;1pa-q8vHhaJm94&M#I(ejAm1u)=iK-4{;6L8XE^RfLxtK+gwN)qG>0iRQa9W)vW8~RU#bdK*{>C9=;l* zstP0tL%GCH%bIQW@GiEKx=7u*ZNnOd;N|T`H8s{LjnBMa8djm%(o&kOo@z3k7fVcd zPudoe_0Zl2mk)oi86RGf4D_M2cUP0xuVBwKr&WFqJe_D$npZQ&J#ZQm;~hm*q5M`b zBs$hSzrBRyi(1iHTQ6OsH`lra+`RbTl08_IcFVs$Fu<-ZEE}C_M---MzKtAm`K>{Ea_15?kuYx zzDBN+-#;{f#j{dqA*s%)%TyqVn^Q}&EiU-UHnEaq+bmn(^13?o)3W$}u&lw8ugY^< zi@C0FTe$vN=90n5RHR9m2%JqoJ81c=#(g_+r-Efp1ZDaf7BN%}OQ>1PRu5H%=ra^P zE2^SNgU$4>ZftGtSB_K~nHiE(59B0JEiBr1p^=6hR>(&MnU^(S`OHzmGATBxg}V2V zEB!Mnyzj_H%z`?EixX)a+Ib(^ZPYd)&>J%u3yO%XyjQw)+y|338&n^7Zq=apAm(jUqD$z5jdNQ#I%_{^0snb3Ii*N_kze`{yCAmO z&mqtCO!C+yv|=WMzYodk+Ofv7I>k^V2%`D1p$m|rue;c4XMSaVvnBa#2cG;+>lh|b z1@xW7Dhm-N9OI+sBgX04-1D5AQz0WPLs!*5K>Pj7Aua1oUVkHRY{qi$Y2nU?SMN!t zY(8`F8OE0PS2R49rRzSlo%?6MpInp<>ciz(zZrHxkIhuxiFn^(fP z+#y8}6LO}X%kmkJTsK6*kX%8Y*6X^EuiU+f8=RxS^2IH!e zUPyI}9qJ=jw?3p}5fJQNNA>F5s(^6Cz-YH7WJ9#LOx0W0>dSNTK*imbEE^Uwy>}%W z0XP$en9}e?L)z(QaZfS!C&-#owmK+Yg>~krhseLWc)sL{l|^+yg>Z3@e_j)M=}LbI+yQ(+-wzmPQ2FZLfv7EjNlu zNk7bZS|j7*qvN(G#ZZ$W`$pke+2)fPl|y$6Yi>vStk?-L?*wG&b@RNA6>B%TI<}WX zb6yrZ)|3p>lSXnR_$!>_j!I)7Rs^$6e-7!{^+u}2a7Py2 zca?KZb|w>JMVW#cha&!FOd(z=fQ?fWW#Pwzur@G{;M2)(S9 z!?8z;5V-eKkAF-geW9hVTNBHrswAl-S+=L~tKurx?1i4baD9WApY#^CNOn)Z4uRKe zYl|J&`~Xz#C#~v=vaKFXs*>3D+=1E_k@M|I+;*xud`23-N@+27MzrZKGiA6Xs(aaD zzHa&qbHex@O;s0O?^S^=@hrO>2-6in=C=2l=A-<+)5>AF*SOPf4_JQ=G+I;sYCiLP z1!^$lh_+W!=9^!flB5p{I0uK>zt2MEbj&*3%7{>@sb%WQ zU@MI)JRZ?RLcUeq@LP#w_{zT2l%N1}S5=Ej~Ut6UkV-6%|}21Nf(Cd5-Sh?o;be5{6^zc+t5hQ8~1NWctb`u&*dZzrkYiTj?NJ)R1^%_Ft7 zCKVeVHZYVz^iLLb_Ik^+=%oh@T0I-R>)W{=MPX{86fWmx30j|#*z0m7&!tyKMmJq0 zD=-O>Rq^CF+p_XJ_$N**p732FQYOkFDu6pD>UWu7lyAy|*fVUGEceKKmOKso(f7uU zT=;1Wz4n78P8wUP)8HowjJ(0iprCnh^IASZ4T1WP7zDwh1@{j(c$d0*8o|jr1-yp$ zzl80M`Viv5S1~LreS{uj6zEFW=k4huA=sPel7PLrBb7#m7ZTkSzW}AxBO_ZnIRfN} zxVd}q#$>}sU<+pdC)@&S#tExwEdD0V+k>|xUI>LxM%6rLs>@(WubCdldEL|jBX^M?x~M#_R4 zaMzP#<@l}9;132&`&{wI(STnArvvd()`qZ}x4?(tIS@_hwl<<3lkqq5K-)5A`YZ| zlOamm_YgPwwq?I=*I=aJ2hqg^9OwKlytqcMI;A2K*n?Y$4MC literal 0 HcmV?d00001 diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/images/picture5.png b/examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/images/picture5.png new file mode 100644 index 0000000000000000000000000000000000000000..ff9329eb146acb2b117c1f23aefc6faecfc7cff4 GIT binary patch literal 26425 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 Z=re;BL7JjV;OA~msVHd3m)count != 0) {\ + ESP_LOGD(TAG, "\n%s, %s\n", __func__, message);\ + dst_msg = src_msg->ival[0];\ + } \ +} while(0) \ + +#define ble_mesh_node_get_value(index, key, value) do { \ + uint16_t _index = 0; \ + xSemaphoreTake(ble_mesh_node_sema, portMAX_DELAY); \ + for (_index = 0; _index < NODE_MAX_GROUP_CONFIG; _index) { \ + if (node_set_prestore_params[_index].key == value) { \ + break; \ + } \ + } \ + index = _index; \ + xSemaphoreGive(ble_mesh_node_sema); \ +} while(0) \ + +#define ble_mesh_node_set_state(status) do { \ + xSemaphoreTake(ble_mesh_node_sema, portMAX_DELAY); \ + node_status.previous = node_status.current; \ + node_status.current = status; \ + xSemaphoreGive(ble_mesh_node_sema); \ +}while(0) \ + +#define ble_mesh_node_get_state(status) do { \ + xSemaphoreTake(ble_mesh_node_sema, portMAX_DELAY); \ + status = node_status.current; \ + xSemaphoreGive(ble_mesh_node_sema); \ +}while(0) \ + +#define ble_mesh_callback_check_err_code(err_code, message) do { \ + if (err_code == ESP_OK) { \ + ESP_LOGI(TAG, "%s,OK\n", message); \ + } else { \ + ESP_LOGE(TAG, "%s,Fail,%d\n", message, err_code); \ + } \ +}while(0) \ + +void ble_mesh_node_init(); +void ble_mesh_set_node_prestore_params(uint16_t netkey_index, uint16_t unicast_addr); +esp_ble_mesh_model_t *ble_mesh_get_model(uint16_t model_id); +esp_ble_mesh_comp_t *ble_mesh_get_component(uint16_t model_id); +void ble_mesh_node_statistics_get(); +int ble_mesh_node_statistics_accumultate(uint8_t *data, uint32_t value, uint16_t type); +int ble_mesh_node_statistics_init(uint16_t package_num); +void ble_mesh_node_statistics_destroy(); + +#endif //_BLE_MESH_ADAOTER_H_ diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.c b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.c new file mode 100644 index 0000000000..2e7c938460 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.c @@ -0,0 +1,208 @@ +// Copyright 2017-2018 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 "ble_mesh_cfg_srv_model.h" + +uint8_t dev_uuid[16] = {0xdd, 0xdd}; + +#if CONFIG_BLE_MESH_NODE +esp_ble_mesh_prov_t prov = { + .uuid = dev_uuid, +}; +#endif //CONFIG_BLE_MESH_NODE + +#if CONFIG_BLE_MESH_PROVISIONER +esp_ble_mesh_prov_t prov = { + .prov_uuid = dev_uuid, + .prov_unicast_addr = 0x0001, + .prov_start_address = 0x0005, + .prov_attention = 0x00, + .prov_algorithm = 0x00, + .prov_pub_key_oob = 0x00, + .prov_pub_key_oob_cb = NULL, + .prov_static_oob_val = NULL, + .prov_static_oob_len = 0x00, + .prov_input_num = NULL, + .prov_output_num = NULL, + .flags = 0x00, + .iv_index = 0x00, +}; +#endif //CONFIG_BLE_MESH_PROVISIONER + +ESP_BLE_MESH_MODEL_PUB_DEFINE(model_pub_config, 2 + 1, ROLE_NODE); + +esp_ble_mesh_model_pub_t vendor_model_pub_config; + +// configure server module +esp_ble_mesh_cfg_srv_t cfg_srv = { + .relay = ESP_BLE_MESH_RELAY_ENABLED, + .beacon = ESP_BLE_MESH_BEACON_ENABLED, +#if defined(CONFIG_BLE_MESH_FRIEND) + .friend_state = ESP_BLE_MESH_FRIEND_ENABLED, +#else + .friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED, +#endif +#if defined(CONFIG_BLE_MESH_GATT_PROXY) + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED, +#else + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED, +#endif + .default_ttl = 7, + + /* 3 transmissions with 20ms interval */ + .net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20), + .relay_retransmit = ESP_BLE_MESH_TRANSMIT(0, 20), +}; + +esp_ble_mesh_model_t config_server_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv), +}; + +esp_ble_mesh_elem_t config_server_elements[] = { + ESP_BLE_MESH_ELEMENT(0, config_server_models, ESP_BLE_MESH_MODEL_NONE), +}; + +esp_ble_mesh_comp_t config_server_comp = { + .cid = CID_ESP, + .elements = config_server_elements, + .element_count = ARRAY_SIZE(config_server_elements), +}; + +// config client model +esp_ble_mesh_model_t config_client_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv), + ESP_BLE_MESH_MODEL_CFG_CLI(&cfg_cli), +}; + +esp_ble_mesh_elem_t config_client_elements[] = { + ESP_BLE_MESH_ELEMENT(0, config_client_models, ESP_BLE_MESH_MODEL_NONE), +}; + +esp_ble_mesh_comp_t config_client_comp = { + .cid = CID_ESP, + .elements = config_client_elements, + .element_count = ARRAY_SIZE(config_client_elements), +}; + +// configure special module +esp_ble_mesh_model_op_t gen_onoff_srv_model_op_config[] = { + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET, 0), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, 2), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2), + ESP_BLE_MESH_MODEL_OP_END, +}; + +esp_ble_mesh_model_t gen_onoff_srv_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv), + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_model_op_config, &model_pub_config, NULL), +}; + +esp_ble_mesh_elem_t gen_onoff_srv_elements[] = { + ESP_BLE_MESH_ELEMENT(0, gen_onoff_srv_models, ESP_BLE_MESH_MODEL_NONE), +}; + +esp_ble_mesh_comp_t gen_onoff_srv_comp = { + .cid = CID_ESP, + .elements = gen_onoff_srv_elements, + .element_count = ARRAY_SIZE(gen_onoff_srv_elements), +}; + +// config generic onoff client +#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI) + +esp_ble_mesh_client_t gen_onoff_cli; + +esp_ble_mesh_model_t gen_onoff_cli_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv), + ESP_BLE_MESH_MODEL_CFG_CLI(&cfg_cli), + ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(&model_pub_config, &gen_onoff_cli), +}; + +esp_ble_mesh_elem_t gen_onoff_cli_elements[] = { + ESP_BLE_MESH_ELEMENT(0, gen_onoff_cli_models, ESP_BLE_MESH_MODEL_NONE), +}; + +esp_ble_mesh_comp_t gen_onoff_cli_comp = { + .cid = CID_ESP, + .elements = gen_onoff_cli_elements, + .element_count = ARRAY_SIZE(gen_onoff_cli_elements), +}; +#endif //CONFIG_BLE_MESH_GENERIC_ONOFF_CLI + +//CONFIG VENDOR MODEL TEST PERFORMANCE +#define ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_SRV 0x2000 +#define ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_CLI 0x2001 + +#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_GET ESP_BLE_MESH_MODEL_OP_3(0x01, CID_ESP) +#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET ESP_BLE_MESH_MODEL_OP_3(0x02, CID_ESP) +#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK ESP_BLE_MESH_MODEL_OP_3(0x03, CID_ESP) +#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS ESP_BLE_MESH_MODEL_OP_3(0x04, CID_ESP) + +esp_ble_mesh_client_op_pair_t test_perf_cli_op_pair[] = { + {ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_GET, ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS}, + {ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET, ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS}, + {ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK, ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS}, +}; + +esp_ble_mesh_client_t test_perf_cli = { + .op_pair_size = ARRAY_SIZE(test_perf_cli_op_pair), + .op_pair = test_perf_cli_op_pair, +}; + +esp_ble_mesh_model_op_t test_perf_srv_op[] = { + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_GET, 1), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET, 1), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK, 1), + ESP_BLE_MESH_MODEL_OP_END, +}; + +esp_ble_mesh_model_op_t test_perf_cli_op[] = { + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS, 1), + ESP_BLE_MESH_MODEL_OP_END, +}; + +esp_ble_mesh_model_t config_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv), + ESP_BLE_MESH_MODEL_CFG_CLI(&cfg_cli), +}; + +esp_ble_mesh_model_t test_perf_cli_models[] = { + ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_CLI, + test_perf_cli_op, &vendor_model_pub_config, &test_perf_cli), +}; + +esp_ble_mesh_elem_t test_perf_cli_elements[] = { + ESP_BLE_MESH_ELEMENT(0, config_models, test_perf_cli_models), +}; + +esp_ble_mesh_comp_t test_perf_cli_comp = { + .cid = CID_ESP, + .elements = test_perf_cli_elements, + .element_count = ARRAY_SIZE(test_perf_cli_elements), +}; + +esp_ble_mesh_model_t test_perf_srv_models[] = { + ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_SRV, + test_perf_srv_op, NULL, NULL), +}; + +esp_ble_mesh_elem_t test_perf_srv_elements[] = { + ESP_BLE_MESH_ELEMENT(0, config_models, test_perf_srv_models), +}; + +esp_ble_mesh_comp_t test_perf_srv_comp = { + .cid = CID_ESP, + .elements = test_perf_srv_elements, + .element_count = ARRAY_SIZE(test_perf_srv_elements), +}; diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.h b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.h new file mode 100644 index 0000000000..9e43333eb9 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.h @@ -0,0 +1,107 @@ +// Copyright 2017-2018 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. + +#ifndef _BLE_MESH_CFG_SRV_MODEL_H_ +#define _BLE_MESH_CFG_SRV_MODEL_H_ + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_config_model_api.h" + +#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI) +#include "esp_ble_mesh_generic_model_api.h" +#endif //CONFIG_BLE_MESH_GENERIC_ONOFF_CLI + +#define NODE_MAX_GROUP_CONFIG 3 +#define CID_ESP 0x02C4 + +extern uint8_t dev_uuid[16]; + +typedef struct { + uint16_t net_idx; + uint16_t unicast_addr; +} ble_mesh_node_config_params; +ble_mesh_node_config_params ble_mesh_node_prestore_params[NODE_MAX_GROUP_CONFIG]; + +extern esp_ble_mesh_prov_t prov; + +extern esp_ble_mesh_model_pub_t vendor_model_pub_config; + +// configure server module +extern esp_ble_mesh_cfg_srv_t cfg_srv; + +extern esp_ble_mesh_model_t config_server_models[]; + +extern esp_ble_mesh_elem_t config_server_elements[]; + +extern esp_ble_mesh_comp_t config_server_comp; + +// config client model +esp_ble_mesh_client_t cfg_cli; +extern esp_ble_mesh_model_t config_client_models[]; + +extern esp_ble_mesh_elem_t config_client_elements[]; + +extern esp_ble_mesh_comp_t config_client_comp; + +// configure special module +extern esp_ble_mesh_model_op_t gen_onoff_srv_model_op_config[]; + +extern esp_ble_mesh_model_t gen_onoff_srv_models[]; + +extern esp_ble_mesh_elem_t gen_onoff_srv_elements[]; + +extern esp_ble_mesh_comp_t gen_onoff_srv_comp; + +// config generic onoff client +#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI) + +extern esp_ble_mesh_client_t gen_onoff_cli; + +extern esp_ble_mesh_model_t gen_onoff_cli_models[]; + +extern esp_ble_mesh_elem_t gen_onoff_cli_elements[]; + +extern esp_ble_mesh_comp_t gen_onoff_cli_comp; +#endif //CONFIG_BLE_MESH_GENERIC_ONOFF_CLI + +//CONFIG VENDOR MODEL TEST PERFORMANCE +#define ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_SRV 0x2000 +#define ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_CLI 0x2001 + +#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_GET ESP_BLE_MESH_MODEL_OP_3(0x01, CID_ESP) +#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET ESP_BLE_MESH_MODEL_OP_3(0x02, CID_ESP) +#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK ESP_BLE_MESH_MODEL_OP_3(0x03, CID_ESP) +#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS ESP_BLE_MESH_MODEL_OP_3(0x04, CID_ESP) + +extern esp_ble_mesh_client_t test_perf_cli; + +extern esp_ble_mesh_model_op_t test_perf_srv_op[]; + +extern esp_ble_mesh_model_op_t test_perf_cli_op[]; + +extern esp_ble_mesh_model_t config_models[]; + +extern esp_ble_mesh_model_t test_perf_cli_models[]; + +extern esp_ble_mesh_elem_t test_perf_cli_elements[]; + +extern esp_ble_mesh_comp_t test_perf_cli_comp; + +extern esp_ble_mesh_model_t test_perf_srv_models[]; + +extern esp_ble_mesh_elem_t test_perf_srv_elements[]; + +extern esp_ble_mesh_comp_t test_perf_srv_comp; + +#endif //_BLE_MESH_CFG_SRV_MODEL_H_ diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_decl.h b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_decl.h new file mode 100644 index 0000000000..22ab3a7f59 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_decl.h @@ -0,0 +1,28 @@ +/* Console example — declarations of command registration functions. + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#pragma once + +#include "esp_ble_mesh_defs.h" + +// Register system functions +void register_system(); + +// Register blutooth +void register_bluetooth(); + +// Register mesh node cmd +void ble_mesh_register_mesh_node(); + +// Register mesh config server and generic server operation cmd +void ble_mesh_register_server(); + +#if (CONFIG_BLE_MESH_CFG_CLI) +// Register mesh config client operation cmd +void ble_mesh_register_configuration_client_model(); +#endif diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.c b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.c new file mode 100644 index 0000000000..88b728bbab --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.c @@ -0,0 +1,128 @@ +// Copyright 2017-2018 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 "ble_mesh_console_lib.h" + +static int hex2num(char c); +static int hex2byte(const char *hex); + +static int hex2num(char c) +{ + if (c >= '0' && c <= '9') { + return c - '0'; + } + if (c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } + if (c >= 'A' && c <= 'F') { + return c - 'A' + 10; + } + return -1; +} + +static int hex2byte(const char *hex) +{ + int a, b; + a = hex2num(*hex++); + if (a < 0) { + return -1; + } + b = hex2num(*hex++); + if (b < 0) { + return -1; + } + return (a << 4) | b; +} + +int hexstr_2_bin(const char *hex, uint8_t *buf, uint32_t len) +{ + uint32_t i; + int a; + const char *ipos = hex; + uint8_t *opos = buf; + + for (i = 0; i < len; i++) { + a = hex2byte(ipos); + if (a < 0) { + return -1; + } + *opos ++ = a; + ipos += 2; + } + return 0; +} + +int get_value_string(char *value_in, char *buf) +{ + int result = -1; + + uint16_t length = strlen(value_in); + for(int i = 0; i 2) { + if (value_in[0] == '0' && value_in[1] == 'x') { + buf[(length - 2) / 2] = 0; + result = hexstr_2_bin(&value_in[2], (uint8_t *)buf, (length - 2) / 2); + length = (length - 2) / 2; + } else { + strcpy(buf, value_in); + result = 0; + } + } else { + strcpy(buf, value_in); + result = 0; + } + + return result; +} + +bool str_2_mac(uint8_t *str, uint8_t *dest) +{ + uint8_t loop = 0; + uint8_t tmp = 0; + uint8_t *src_p = str; + + if (strlen((char *)src_p) != 17) { // must be like 12:34:56:78:90:AB + return false; + } + + for (loop = 0; loop < 17 ; loop++) { + if (loop % 3 == 2) { + if (src_p[loop] != ':') { + return false; + } + + continue; + } + + if ((src_p[loop] >= '0') && (src_p[loop] <= '9')) { + tmp = tmp * 16 + src_p[loop] - '0'; + } else if ((src_p[loop] >= 'A') && (src_p[loop] <= 'F')) { + tmp = tmp * 16 + src_p[loop] - 'A' + 10; + } else if ((src_p[loop] >= 'a') && (src_p[loop] <= 'f')) { + tmp = tmp * 16 + src_p[loop] - 'a' + 10; + } else { + return false; + } + + if (loop % 3 == 1) { + *dest++ = tmp; + tmp = 0; + } + } + + return true; +} \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.h b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.h new file mode 100644 index 0000000000..8f8449eca4 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.h @@ -0,0 +1,31 @@ +// Copyright 2017-2018 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. + +#ifndef _BLE_MESH_CONSOLE_LIB_H_ +#define _BLE_MESH_CONSOLE_LIB_H_ + +#include +#include + +#include "esp_system.h" +#include "esp_log.h" +#include "nvs_flash.h" +#include "esp_console.h" +#include "argtable3/argtable3.h" + +bool str_2_mac(uint8_t *str, uint8_t *dest); +int hexstr_2_bin(const char *hex, uint8_t *buf, uint32_t len); +int get_value_string(char *value_in, char *buf); + +#endif //_BLE_MESH_CONSOLE_LIB_H_ \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c new file mode 100644 index 0000000000..e629cf3054 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c @@ -0,0 +1,215 @@ +// Copyright 2017-2018 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 +#include + +#include "esp_system.h" +#include "esp_log.h" +#include "esp_vfs_dev.h" +#include "driver/uart.h" +#include "nvs.h" +#include "nvs_flash.h" + +#include "esp_bt.h" +#include "esp_bt_main.h" + +#include "esp_console.h" +#include "linenoise/linenoise.h" +#include "argtable3/argtable3.h" + +#include "ble_mesh_console_decl.h" + +#if CONFIG_STORE_HISTORY + +#define MOUNT_PATH "/data" +#define HISTORY_PATH MOUNT_PATH "/history.txt" + +static void initialize_filesystem() +{ + static wl_handle_t wl_handle; + const esp_vfs_fat_mount_config_t mount_config = { + .max_files = 4, + .format_if_mount_failed = true + }; + esp_err_t err = esp_vfs_fat_spiflash_mount(MOUNT_PATH, "storage", &mount_config, &wl_handle); + if (err != ESP_OK) { + printf("Failed to mount FATFS (0x%x)", err); + return; + } +} +#endif // CONFIG_STORE_HISTORY + +static void initialize_console() +{ + /* Disable buffering on stdin and stdout */ + setvbuf(stdin, NULL, _IONBF, 0); + setvbuf(stdout, NULL, _IONBF, 0); + + /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */ + esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR); + /* Move the caret to the beginning of the next line on '\n' */ + esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF); + + /* Install UART driver for interrupt-driven reads and writes */ + ESP_ERROR_CHECK( uart_driver_install(CONFIG_CONSOLE_UART_NUM, + 256, 0, 0, NULL, 0) ); + + /* Tell VFS to use UART driver */ + esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM); + + /* Initialize the console */ + esp_console_config_t console_config = { + .max_cmdline_args = 20, + .max_cmdline_length = 256, +#if CONFIG_LOG_COLORS + .hint_color = atoi(LOG_COLOR_CYAN) +#endif + }; + ESP_ERROR_CHECK( esp_console_init(&console_config) ); + + /* Configure linenoise line completion library */ + /* Enable multiline editing. If not set, long commands will scroll within + * single line. + */ + linenoiseSetMultiLine(1); + + /* Tell linenoise where to get command completions and hints */ + linenoiseSetCompletionCallback(&esp_console_get_completion); + linenoiseSetHintsCallback((linenoiseHintsCallback *) &esp_console_get_hint); + + /* Set command history size */ + linenoiseHistorySetMaxLen(100); + +#if CONFIG_STORE_HISTORY + /* Load command history from filesystem */ + linenoiseHistoryLoad(HISTORY_PATH); +#endif +} + + +esp_err_t bluetooth_init(void) +{ + esp_err_t ret; + + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + ret = esp_bt_controller_init(&bt_cfg); + if (ret) { + printf("%s initialize controller failed\n", __func__); + return ret; + } + + ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); + if (ret) { + printf("%s enable controller failed\n", __func__); + return ret; + } + ret = esp_bluedroid_init(); + if (ret) { + printf("%s init bluetooth failed\n", __func__); + return ret; + } + ret = esp_bluedroid_enable(); + if (ret) { + printf("%s enable bluetooth failed\n", __func__); + return ret; + } + + return ret; +} + +void app_main(void) +{ + esp_err_t res; + + nvs_flash_init(); + + // init and enable bluetooth + res = bluetooth_init(); + if (res) { + printf("esp32_bluetooth_init failed (ret %d)", res); + } + +#if CONFIG_STORE_HISTORY + initialize_filesystem(); +#endif + + initialize_console(); + + /* Register commands */ + esp_console_register_help_command(); + register_system(); + register_bluetooth(); + ble_mesh_register_mesh_node(); + ble_mesh_register_server(); + + /* Prompt to be printed before each line. + * This can be customized, made dynamic, etc. + */ + const char *prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR; + + printf("\n" + "This is an example of ESP-IDF console component.\n" + "Type 'help' to get the list of commands.\n" + "Use UP/DOWN arrows to navigate through command history.\n" + "Press TAB when typing command name to auto-complete.\n"); + + /* Figure out if the terminal supports escape sequences */ + int probe_status = linenoiseProbe(); + if (probe_status) { /* zero indicates success */ + printf("\n" + "Your terminal application does not support escape sequences.\n" + "Line editing and history features are disabled.\n" + "On Windows, try using Putty instead.\n"); + linenoiseSetDumbMode(1); +#if CONFIG_LOG_COLORS + /* Since the terminal doesn't support escape sequences, + * don't use color codes in the prompt. + */ + prompt = "esp32> "; +#endif //CONFIG_LOG_COLORS + } + + /* Main loop */ + while (true) { + /* Get a line using linenoise. + * The line is returned when ENTER is pressed. + */ + char *line = linenoise(prompt); + if (line == NULL) { /* Ignore empty lines */ + continue; + } + /* Add the command to the history */ + linenoiseHistoryAdd(line); +#if CONFIG_STORE_HISTORY + /* Save command history to filesystem */ + linenoiseHistorySave(HISTORY_PATH); +#endif + + /* Try to run the command */ + int ret; + esp_err_t err = esp_console_run(line, &ret); + if (err == ESP_ERR_NOT_FOUND) { + printf("Unrecognized command\n"); + } else if (err == ESP_ERR_INVALID_ARG) { + // command was empty + } else if (err == ESP_OK && ret != ESP_OK) { + printf("\nCommand returned non-zero error code: 0x%x\n", ret); + } else if (err != ESP_OK) { + printf("Internal error: 0x%x\n", err); + } + /* linenoise allocates line buffer on the heap, so need to free it */ + linenoiseFree(line); + } +} diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_system.c b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_system.c new file mode 100644 index 0000000000..cc8805dbf2 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_system.c @@ -0,0 +1,183 @@ +/* Console example — various system commands + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include + +#include "esp_log.h" +#include "esp_console.h" +#include "esp_system.h" +#include "esp_sleep.h" +#include "driver/rtc_io.h" +#include "soc/rtc_cntl_reg.h" +#include "argtable3/argtable3.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "ble_mesh_console_decl.h" + +#if CONFIG_IDF_CMAKE +#define CONFIG_ESPTOOLPY_PORT "Which is choosen by Users for CMake" +#endif + +static void register_free(); +static void register_restart(); +static void register_make(); + +void register_system() +{ + register_free(); + register_restart(); + register_make(); +} + +/** 'restart' command restarts the program */ + +static int restart(int argc, char **argv) +{ + printf("%s, %s", __func__, "Restarting"); + esp_restart(); +} + +static void register_restart() +{ + const esp_console_cmd_t cmd = { + .command = "restart", + .help = "Restart the program", + .hint = NULL, + .func = &restart, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); +} + +/** 'free' command prints available heap memory */ + +static int free_mem(int argc, char **argv) +{ + printf("%d\n", esp_get_free_heap_size()); + return 0; +} + +static void register_free() +{ + const esp_console_cmd_t cmd = { + .command = "free", + .help = "Get the total size of heap memory available", + .hint = NULL, + .func = &free_mem, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); +} + +static int make(int argc, char **argv) +{ + int count = REG_READ(RTC_CNTL_STORE0_REG); + if (++count >= 3) { + printf("This is not the console you are looking for.\n"); + return 0; + } + REG_WRITE(RTC_CNTL_STORE0_REG, count); + + const char *make_output = + R"(LD build/console.elf +esptool.py v2.1-beta1 +)"; + + const char* flash_output[] = { +R"(Flashing binaries to serial port )" CONFIG_ESPTOOLPY_PORT R"( (app at offset 0x10000)... +esptool.py v2.1-beta1 +Connecting.... +)", +R"(Chip is ESP32D0WDQ6 (revision 0) +Uploading stub... +Running stub... +Stub running... +Changing baud rate to 921600 +Changed. +Configuring flash size... +Auto-detected Flash size: 4MB +Flash params set to 0x0220 +Compressed 15712 bytes to 9345... +)", +R"(Wrote 15712 bytes (9345 compressed) at 0x00001000 in 0.1 seconds (effective 1126.9 kbit/s)... +Hash of data verified. +Compressed 333776 bytes to 197830... +)", +R"(Wrote 333776 bytes (197830 compressed) at 0x00010000 in 3.3 seconds (effective 810.3 kbit/s)... +Hash of data verified. +Compressed 3072 bytes to 82... +)", +R"(Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 1588.4 kbit/s)... +Hash of data verified. +Leaving... +Hard resetting... +)" + }; + + const char* monitor_output = +R"(MONITOR +)" LOG_COLOR_W R"(--- idf_monitor on )" CONFIG_ESPTOOLPY_PORT R"( 115200 --- +--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H -- +)" LOG_RESET_COLOR; + + bool need_make = false; + bool need_flash = false; + bool need_monitor = false; + for (int i = 1; i < argc; ++i) { + if (strcmp(argv[i], "all") == 0) { + need_make = true; + } else if (strcmp(argv[i], "flash") == 0) { + need_make = true; + need_flash = true; + } else if (strcmp(argv[i], "monitor") == 0) { + need_monitor = true; + } else if (argv[i][0] == '-') { + /* probably -j option */ + } else if (isdigit((int) argv[i][0])) { + /* might be an argument to -j */ + } else { + printf("make: *** No rule to make target `%s'. Stop.\n", argv[i]); + /* Technically this is an error, but let's not spoil the output */ + return 0; + } + } + if (argc == 1) { + need_make = true; + } + if (need_make) { + printf("%s", make_output); + } + if (need_flash) { + size_t n_items = sizeof(flash_output) / sizeof(flash_output[0]); + for (int i = 0; i < n_items; ++i) { + printf("%s", flash_output[i]); + vTaskDelay(200/portTICK_PERIOD_MS); + } + } + if (need_monitor) { + printf("%s", monitor_output); + esp_restart(); + } + return 0; +} + +static void register_make() +{ + const esp_console_cmd_t cmd = { + .command = "make", + .help = NULL, /* Do not include in 'help' output */ + .hint = "all | flash | monitor", + .func = &make, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); +} + + diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c new file mode 100644 index 0000000000..da08884e35 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c @@ -0,0 +1,547 @@ +// Copyright 2017-2018 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 "esp_bt.h" +#include "soc/soc.h" + +#include "esp_bt_device.h" + +#include "test.h" +#include "esp_ble_mesh_networking_api.h" +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_common_api.h" +#include "esp_ble_mesh_provisioning_api.h" + +#include "ble_mesh_console_lib.h" +#include "ble_mesh_adapter.h" + +typedef struct { + struct arg_str *static_val; + struct arg_int *static_val_len; + struct arg_int *output_size; + struct arg_int *output_actions; + struct arg_int *input_size; + struct arg_int *input_actions; + struct arg_end *end; +} ble_mesh_prov_t; +static ble_mesh_prov_t oob; + +typedef struct { + struct arg_int *model_type; + struct arg_int *config_index; + struct arg_str *dev_uuid; + struct arg_int *pub_config; + struct arg_end *end; +} ble_mesh_comp_t; +static ble_mesh_comp_t component; + +typedef struct { + struct arg_int *bearer; + struct arg_int *enable; + struct arg_end *end; +} ble_mesh_bearer_t; +static ble_mesh_bearer_t bearer; + +typedef struct { + struct arg_str *action_type; + struct arg_int *package_num; + struct arg_end *end; +} ble_mesh_node_statistices_t; +ble_mesh_node_statistices_t node_statistices; + +typedef struct { + struct arg_str *action_type; + struct arg_int *tx_sense_power; + struct arg_end *end; +} ble_mesh_tx_sense_power; +static ble_mesh_tx_sense_power power_set; + +typedef struct { + struct arg_str *net_key; + struct arg_int *net_idx; + struct arg_int *unicast_addr; + struct arg_str *dev_key; + struct arg_str *app_key; + struct arg_int *app_idx; + struct arg_int *group_addr; + struct arg_end *end; +} ble_mesh_node_network_info_t; +ble_mesh_node_network_info_t node_network_info; + +ble_mesh_node_status node_status = { + .previous = 0x0, + .current = 0x0, +}; + +SemaphoreHandle_t ble_mesh_node_sema; + +void ble_mesh_register_node_cmd(); +// Register callback function +void ble_mesh_prov_cb(esp_ble_mesh_prov_cb_event_t event, esp_ble_mesh_prov_cb_param_t *param); +void ble_mesh_model_cb(esp_ble_mesh_model_cb_event_t event, esp_ble_mesh_model_cb_param_t *param); + + +void ble_mesh_register_mesh_node() +{ + ble_mesh_register_node_cmd(); +} + +int ble_mesh_register_node_cb() +{ + ESP_LOGD(TAG, "enter %s\n", __func__); + ble_mesh_node_init(); + esp_ble_mesh_register_prov_callback(ble_mesh_prov_cb); + esp_ble_mesh_register_custom_model_callback(ble_mesh_model_cb); + ESP_LOGI(TAG, "Node:Reg,OK"); + ESP_LOGD(TAG, "exit %s\n", __func__); + return 0; +} + +void ble_mesh_prov_cb(esp_ble_mesh_prov_cb_event_t event, esp_ble_mesh_prov_cb_param_t *param) +{ + ESP_LOGD(TAG, "enter %s, event = %d", __func__, event); + switch (event) { + case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT: + ble_mesh_callback_check_err_code(param->prov_register_comp.err_code, "Provisioning:Register"); + break; + case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_prov_enable_comp.err_code, "Node:EnBearer"); + break; + case ESP_BLE_MESH_NODE_PROV_DISABLE_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_prov_disable_comp.err_code, "Node:DisBearer"); + break; + case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT: + ESP_LOGI(TAG, "Node:LinkOpen,OK,%d", param->node_prov_link_open.bearer); + break; + case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT: + ESP_LOGI(TAG, "Node:LinkClose,OK,%d", param->node_prov_link_close.bearer); + break; + case ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT: + ESP_LOGI(TAG, "Node:OutPut,%d,%d", param->node_prov_output_num.action, param->node_prov_output_num.number); + break; + case ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT: + ESP_LOGI(TAG, "Node:OutPutStr,%s", param->node_prov_output_str.string); + break; + case ESP_BLE_MESH_NODE_PROV_INPUT_EVT: + ESP_LOGI(TAG, "Node:InPut,%d,%d", param->node_prov_input.action, param->node_prov_input.size); + break; + case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT: + ESP_LOGI(TAG, "Provisioning:Success,%d", param->node_prov_complete.addr); + ble_mesh_set_node_prestore_params(param->node_prov_complete.net_idx, param->node_prov_complete.addr); + break; + case ESP_BLE_MESH_NODE_PROV_RESET_EVT: + ESP_LOGI(TAG, "Node:Reset"); + break; + case ESP_BLE_MESH_NODE_PROV_INPUT_NUMBER_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_prov_input_num_comp.err_code, "Node:InputNum"); + break; + case ESP_BLE_MESH_NODE_PROV_INPUT_STRING_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_prov_input_str_comp.err_code, "Node:InputStr"); + break; + case ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_set_unprov_dev_name_comp.err_code, "Node:SetName"); + break; + case ESP_BLE_MESH_NODE_PROXY_IDENTITY_ENABLE_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_proxy_identity_enable_comp.err_code, "Node:ProxyIndentity"); + break; + case ESP_BLE_MESH_NODE_PROXY_GATT_ENABLE_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_proxy_gatt_enable_comp.err_code, "Node:EnProxyGatt"); + break; + case ESP_BLE_MESH_NODE_PROXY_GATT_DISABLE_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_proxy_gatt_disable_comp.err_code, "Node:DisProxyGatt"); + break; + default: + break; + } + ESP_LOGD(TAG, "exit %s", __func__); +} + +void ble_mesh_model_cb(esp_ble_mesh_model_cb_event_t event, esp_ble_mesh_model_cb_param_t *param) +{ + uint8_t status; + uint16_t result; + uint8_t data[4]; + + ESP_LOGD(TAG, "enter %s, event=%x\n", __func__, event); + printf("enter %s, event=%x\n", __func__, event); + switch (event) { + case ESP_BLE_MESH_MODEL_OPERATION_EVT: + if (param->model_operation.model != NULL && param->model_operation.model->op != NULL) { + if (param->model_operation.opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET) { + ESP_LOGI(TAG, "Node:GetStatus,Success"); + ble_mesh_node_get_state(status); + esp_ble_mesh_server_model_send_msg(param->model_operation.model, param->model_operation.ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, + sizeof(status), &status); + } else if (param->model_operation.opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) { + ESP_LOGI(TAG, "Node:SetAck,Success,%d,%d,%d", param->model_operation.msg[0], param->model_operation.ctx->recv_ttl, param->model_operation.length); + ble_mesh_node_set_state(param->model_operation.msg[0]); + ble_mesh_node_get_state(status); + esp_ble_mesh_server_model_send_msg(param->model_operation.model, param->model_operation.ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, + sizeof(status), &status); + } else if (param->model_operation.opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK) { + ble_mesh_node_set_state(param->model_operation.msg[0]); + ESP_LOGI(TAG, "Node:SetUnAck,Success,%d,%d", param->model_operation.msg[0], param->model_operation.ctx->recv_ttl); + } else if (param->model_operation.opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS) { + ESP_LOGI(TAG, "Node:Status,Success,%d", param->model_operation.length); + } else if (param->model_operation.opcode == ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET) { + ESP_LOGI(TAG, "VendorModel:SetAck,Success,%d", param->model_operation.ctx->recv_ttl); + data[0] = param->model_operation.msg[0]; + data[1] = param->model_operation.msg[1]; + data[2] = param->model_operation.msg[2]; + data[3] = param->model_operation.ctx->recv_ttl; + result = ble_mesh_node_statistics_accumultate(param->model_operation.msg, param->model_operation.length, VENDOR_MODEL_PERF_OPERATION_TYPE_SET); + if (result == 0) { + esp_ble_mesh_server_model_send_msg(param->model_operation.model, param->model_operation.ctx, + ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS, sizeof(data), data); + } + } else if (param->model_operation.opcode == ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK) { + ESP_LOGI(TAG, "VendorModel:SetUnAck,Success,%d,%d", param->model_operation.ctx->recv_ttl, param->model_operation.length); + result = ble_mesh_node_statistics_accumultate(param->model_operation.msg, param->model_operation.length, VENDOR_MODEL_PERF_OPERATION_TYPE_SET_UNACK); + if (result == 0) { + esp_ble_mesh_server_model_send_msg(param->model_operation.model, param->model_operation.ctx, + ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS, param->model_operation.length, param->model_operation.msg); + } + } + } + break; + case ESP_BLE_MESH_MODEL_SEND_COMP_EVT: + if (param->model_send_comp.err_code == ESP_OK) { + ESP_LOGI(TAG, "Node:ModelSend,OK"); + } else { + ESP_LOGE(TAG, "Node:ModelSend,Fail"); + } + break; + case ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT: + ESP_LOGI(TAG, "PublishSend,OK,0x%x,%d,", param->model_publish_comp.model->model_id, param->model_publish_comp.model->pub->msg->len); + break; + case ESP_BLE_MESH_MODEL_PUBLISH_UPDATE_EVT: + ESP_LOGI(TAG, "PublishUpdate,OK"); + break; + case ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT: + ESP_LOGI(TAG, "Node:TimeOut"); + break; + case ESP_BLE_MESH_MODEL_EVT_MAX: + ESP_LOGI(TAG, "Node:MaxEvt"); + break; + default: + break; + } + + ESP_LOGD(TAG, "exit %s\n", __func__); +} + +int ble_mesh_power_set(int argc, char **argv) +{ + esp_err_t result = ESP_OK; + ESP_LOGD(TAG, "enter %s\n", __func__); + int nerrors = arg_parse(argc, argv, (void **) &power_set); + if (nerrors != 0) { + arg_print_errors(stderr, power_set.end, argv[0]); + return 1; + } + + if (strcmp(power_set.action_type->sval[0], "tx") == 0) { + result = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, power_set.tx_sense_power->ival[0]); + } else if (strcmp(power_set.action_type->sval[0], "sense") == 0) { + uint32_t *reg = (uint32_t *)(0x6001c07c); + int reg_addr = 0x6001c07c; + uint32_t flag = 0x00FF0000; + uint32_t sense_new = power_set.tx_sense_power->ival[0]; + uint32_t reg_to_write = ((*reg) &= ~flag) | ((256 - sense_new) << 16); + REG_WRITE(reg_addr, reg_to_write); + + } + + if (result == ESP_OK) { + ESP_LOGI(TAG, "Node:SetPower,OK\n"); + } + ESP_LOGD(TAG, "exit %s\n", __func__); + return result; +} + +static int ble_mesh_load_oob(int argc, char **argv) +{ + uint8_t *static_val; + int nerrors = arg_parse(argc, argv, (void **) &oob); + + ESP_LOGD(TAG, "enter %s \n", __func__); + + if (nerrors != 0) { + arg_print_errors(stderr, oob.end, argv[0]); + return 1; + } + + //parsing prov + if (oob.static_val->count != 0) { + static_val = malloc(oob.static_val_len->ival[0] + 1); + get_value_string((char *)oob.static_val->sval[0], (char *)static_val); + prov.static_val = static_val; + } + + arg_int_to_value(oob.static_val_len, prov.static_val_len, "static_val_len"); + arg_int_to_value(oob.output_size, prov.output_size, "output_size"); + arg_int_to_value(oob.output_actions, prov.output_actions, "output_actions"); + arg_int_to_value(oob.input_size, prov.input_size, "input_size"); + arg_int_to_value(oob.input_actions, prov.input_actions, "input_action"); + + ESP_LOGI(TAG, "OOB:Load,OK\n"); + ESP_LOGD(TAG, "exit %s\n", __func__); + return 0; +} + +int ble_mesh_init(int argc, char **argv) +{ + int err; + esp_ble_mesh_comp_t *local_component = NULL; + uint8_t *device_uuid =NULL; + + int nerrors = arg_parse(argc, argv, (void **) &component); + if (nerrors != 0) { + arg_print_errors(stderr, component.end, argv[0]); + return 1; + } + + ESP_LOGD(TAG, "enter %s, module %x\n", __func__, component.model_type->ival[0]); + local_component = ble_mesh_get_component(component.model_type->ival[0]); + + if (component.dev_uuid->count != 0) { + device_uuid = malloc((16 + 1) * sizeof(uint8_t)); + if (device_uuid == NULL) { + ESP_LOGE(TAG, "ble mesh malloc failed, %d\n", __LINE__); + } + get_value_string((char *)component.dev_uuid->sval[0], (char *) device_uuid); + memcpy(dev_uuid, device_uuid, 16); + } else { + memcpy(dev_uuid, esp_bt_dev_get_address(), 6); + } + + err = esp_ble_mesh_init(&prov, local_component); + if (err) { + ESP_LOGE(TAG, "Initializing mesh failed (err %d)\n", err); + return err; + } + + free(device_uuid); + ESP_LOGD(TAG, "exit %s\n", __func__); + return err; +} + +int ble_mesh_node_enable_bearer(int argc, char **argv) +{ + esp_err_t err = 0; + + ESP_LOGD(TAG, "enter %s \n", __func__); + + int nerrors = arg_parse(argc, argv, (void **) &bearer); + if (nerrors != 0) { + arg_print_errors(stderr, bearer.end, argv[0]); + return 1; + } + + if (bearer.enable->count != 0) { + if (bearer.enable->ival[0]) { + //err = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, ESP_PWR_LVL_N12); + err = esp_ble_mesh_node_prov_enable(bearer.bearer->ival[0]); + } else { + err = esp_ble_mesh_node_prov_disable(bearer.bearer->ival[0]); + } + } else { + return 1; + } + + ESP_LOGD(TAG, "exit %s\n", __func__); + return err; +} + +int ble_mesh_node_reset() +{ + esp_err_t err; + ESP_LOGD(TAG, "enter %s\n", __func__); + + err = esp_ble_mesh_node_local_reset(); + + ESP_LOGD(TAG, "exit %s\n", __func__); + return err; +} + +int ble_mesh_node_statistics_regist(int argc, char **argv) +{ + int result = ESP_OK; + + int nerrors = arg_parse(argc, argv, (void **) &node_statistices); + if (nerrors != 0) { + arg_print_errors(stderr, node_statistices.end, argv[0]); + return 1; + } + + ESP_LOGD(TAG, "enter %s\n", __func__); + + if (strcmp(node_statistices.action_type->sval[0], "init") == 0) { + result = ble_mesh_node_statistics_init(node_statistices.package_num->ival[0]); + ESP_LOGI(TAG, "Node:InitStatistics,OK\n"); + } else if (strcmp(node_statistices.action_type->sval[0], "get") == 0) { + ble_mesh_node_statistics_get(); + ESP_LOGI(TAG, "Node:GetStatistics,OK\n"); + } else if (strcmp(node_statistices.action_type->sval[0], "destroy") == 0) { + ble_mesh_node_statistics_destroy(); + ESP_LOGI(TAG, "Node:DestroyStatistics\n"); + } + + ESP_LOGD(TAG, "exit %s\n", __func__); + return result; +} + +int ble_mesh_node_enter_network_auto(int argc, char **argv) +{ + esp_err_t err = ESP_OK; + struct bt_mesh_device_network_info info = { + .flags = 0, + .iv_index = 0, + }; + + int nerrors = arg_parse(argc, argv, (void **) &node_network_info); + if (nerrors != 0) { + arg_print_errors(stderr, node_network_info.end, argv[0]); + return 1; + } + + ESP_LOGD(TAG, "enter %s\n", __func__); + + arg_int_to_value(node_network_info.net_idx, info.net_idx, "network key index"); + arg_int_to_value(node_network_info.unicast_addr, info.unicast_addr, "unicast address"); + arg_int_to_value(node_network_info.app_idx, info.app_idx, "appkey index"); + arg_int_to_value(node_network_info.group_addr, info.group_addr, "group address"); + err = get_value_string((char *)node_network_info.net_key->sval[0], (char *)info.net_key); + err = get_value_string((char *)node_network_info.dev_key->sval[0], (char *)info.dev_key); + err = get_value_string((char *)node_network_info.app_key->sval[0], (char *)info.app_key); + + err = bt_mesh_device_auto_enter_network(&info); + if (err == ESP_OK) { + ESP_LOGD(TAG, "NODE:EnNetwork,OK"); + } else { + ESP_LOGE(TAG, "NODE:EnNetwork,FAIL,%d", err); + } + + ESP_LOGD(TAG, "exit %s\n", __func__); + return err; +} + +void ble_mesh_register_node_cmd() +{ + const esp_console_cmd_t register_cmd = { + .command = "bmreg", + .help = "ble mesh: provisioner/node register callback", + .hint = NULL, + .func = &ble_mesh_register_node_cb, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(®ister_cmd)); + + oob.static_val = arg_str0("s", NULL, "", "Static OOB value"); + oob.static_val_len = arg_int0("l", NULL, "", "Static OOB value length"); + oob.output_size = arg_int0("x", NULL, "", "Maximum size of Output OOB"); + oob.output_actions = arg_int0("o", NULL, "", "Supported Output OOB Actions"); + oob.input_size = arg_int0("y", NULL, "", "Maximum size of Input OOB"); + oob.input_actions = arg_int0("i", NULL, "", "Supported Input OOB Actions"); + oob.end = arg_end(1); + + const esp_console_cmd_t oob_cmd = { + .command = "bmoob", + .help = "ble mesh: provisioner/node config OOB parameters", + .hint = NULL, + .func = &ble_mesh_load_oob, + .argtable = &oob, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&oob_cmd) ); + + component.model_type = arg_int0("m", NULL, "", "mesh model"); + component.config_index = arg_int0("c", NULL, "", "mesh model op"); + component.config_index->ival[0] = 0; // set default value + component.pub_config = arg_int0("p", NULL, "", "publish message buffer"); + component.dev_uuid = arg_str0("d", NULL, "", "device uuid"); + component.end = arg_end(1); + + const esp_console_cmd_t model_cmd = { + .command = "bminit", + .help = "ble mesh: provisioner/node init", + .hint = NULL, + .func = &ble_mesh_init, + .argtable = &component, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&model_cmd) ); + + bearer.bearer = arg_int0("b", NULL, "", "supported bearer"); + bearer.enable = arg_int0("e", NULL, "", "bearers node supported"); + bearer.end = arg_end(1); + + const esp_console_cmd_t bearer_cmd = { + .command = "bmnbearer", + .help = "ble mesh node: enable/disable different bearer", + .hint = NULL, + .func = &ble_mesh_node_enable_bearer, + .argtable = &bearer, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&bearer_cmd)); + + const esp_console_cmd_t reset_cmd = { + .command = "bmnreset", + .help = "ble mesh node: reset", + .hint = NULL, + .func = &ble_mesh_node_reset, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&reset_cmd)); + + node_statistices.action_type = arg_str1("z", NULL, "", "action type"); + node_statistices.package_num = arg_int0("p", NULL, "", "package number"); + node_statistices.end = arg_end(1); + + const esp_console_cmd_t node_statistices_cmd = { + .command = "bmsperf", + .help = "ble mesh server: performance statistics", + .hint = NULL, + .func = &ble_mesh_node_statistics_regist, + .argtable = &node_statistices, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&node_statistices_cmd)); + + power_set.action_type = arg_str1("z", NULL, "", "action type"); + power_set.tx_sense_power = arg_int0("t", NULL, "", "tx power or sense"); + power_set.end = arg_end(1); + + const esp_console_cmd_t power_set_cmd = { + .command = "bmtxpower", + .help = "ble mesh: set tx power or sense", + .hint = NULL, + .func = &ble_mesh_power_set, + .argtable = &power_set, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&power_set_cmd)); + + node_network_info.net_key = arg_str1("k", NULL, "", "network key"); + node_network_info.net_idx = arg_int1("n", NULL, "", "network key index"); + node_network_info.unicast_addr = arg_int1("u", NULL, "", "unicast address"); + node_network_info.dev_key = arg_str1("d", NULL, "", "device key"); + node_network_info.app_key = arg_str1("a", NULL, "", "app key"); + node_network_info.app_idx = arg_int1("i", NULL, "", "appkey index"); + node_network_info.group_addr = arg_int1("g", NULL, "", "group address"); + node_network_info.end = arg_end(1); + + const esp_console_cmd_t node_network_info_cmd = { + .command = "bmnnwk", + .help = "ble mesh node: auto join network", + .hint = NULL, + .func = &ble_mesh_node_enter_network_auto, + .argtable = &node_network_info, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&node_network_info_cmd)); +} diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_server_cmd.c b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_server_cmd.c new file mode 100644 index 0000000000..3abe85dc01 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_server_cmd.c @@ -0,0 +1,83 @@ +// Copyright 2017-2018 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 "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_networking_api.h" + +#include "ble_mesh_console_lib.h" +#include "ble_mesh_adapter.h" + +void ble_mesh_register_server_operation(); + +typedef struct { + struct arg_str *data; + struct arg_int *opcode; + struct arg_int *model; + struct arg_int *role; + struct arg_end *end; +} ble_mesh_publish_message; +ble_mesh_publish_message msg_publish; + +void ble_mesh_register_server() +{ + ble_mesh_register_server_operation(); +} + +int ble_mesh_module_publish_message(int argc, char **argv) +{ + esp_err_t err; + esp_ble_mesh_model_t *model = NULL; + uint8_t *data = NULL; + uint8_t device_role = ROLE_NODE; + uint16_t length = 0; + + ESP_LOGD(TAG, "enter %s \n", __func__); + + int nerrors = arg_parse(argc, argv, (void **) &msg_publish); + if (nerrors != 0) { + arg_print_errors(stderr, msg_publish.end, argv[0]); + return 1; + } + + data = malloc(strlen(msg_publish.data->sval[0])); + get_value_string((char *)msg_publish.data->sval[0], (char *) data); + + arg_int_to_value(msg_publish.role, device_role, "device role"); + model = ble_mesh_get_model(msg_publish.model->ival[0]); + + err = esp_ble_mesh_model_publish(model, msg_publish.opcode->ival[0], length, data, device_role); + + ESP_LOGD(TAG, "exit %s \n", __func__); + free(data); + return err; +} + +void ble_mesh_register_server_operation() +{ + msg_publish.data = arg_str1("d", NULL, "", "message data"); + msg_publish.opcode = arg_int1("o", NULL, "", "operation opcode"); + msg_publish.model = arg_int1("m", NULL, "", "module published to"); + msg_publish.role = arg_int1("r", NULL, "", "device role"); + msg_publish.end = arg_end(1); + + const esp_console_cmd_t msg_publish_cmd = { + .command = "bmpublish", + .help = "ble mesh: publish message", + .hint = NULL, + .func = &ble_mesh_module_publish_message, + .argtable = &msg_publish, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&msg_publish_cmd)); +} + diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/component.mk b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/component.mk new file mode 100644 index 0000000000..0b9d7585e7 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/component.mk @@ -0,0 +1,5 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) + diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c new file mode 100644 index 0000000000..5afaca813b --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c @@ -0,0 +1,45 @@ +// Copyright 2017-2018 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 "esp_bt_device.h" +#include "esp_console.h" + +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + +void register_ble_address(); + +void register_bluetooth() +{ + register_ble_address(); +} + +int bt_mac() +{ + const uint8_t *mac = esp_bt_dev_get_address(); + printf("+BTMAC:"MACSTR"\n", MAC2STR(mac)); + return 0; +} + +void register_ble_address() +{ + const esp_console_cmd_t cmd = { + .command = "btmac", + .help = "get BT mac address", + .hint = NULL, + .func = (esp_console_cmd_func_t)&bt_mac, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&cmd)); +} + diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/sdkconfig.defaults b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/sdkconfig.defaults new file mode 100644 index 0000000000..732947bb16 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/sdkconfig.defaults @@ -0,0 +1,46 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_CONSOLE_UART_BAUDRATE=921600 +CONFIG_ESPTOOLPY_BAUD_921600B=y +CONFIG_MONITOR_BAUD_921600B=y +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y +CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY= +CONFIG_BTDM_CONTROLLER_MODE_BTDM= +CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n +CONFIG_BLE_SCAN_DUPLICATE=y +CONFIG_SCAN_DUPLICATE_TYPE=2 +CONFIG_DUPLICATE_SCAN_CACHE_SIZE=200 +CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y +CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE=200 +CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y +CONFIG_GATTS_ENABLE=y +CONFIG_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_HCI_5_0=y +CONFIG_BLE_MESH_USE_DUPLICATE_SCAN=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PROV=y +CONFIG_BLE_MESH_NET_BUF_POOL_USAGE=y +CONFIG_BLE_MESH_PROXY=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_GATT_PROXY=y +CONFIG_BLE_MESH_NODE_ID_TIMEOUT=60 +CONFIG_BLE_MESH_PROXY_FILTER_SIZE=1 +CONFIG_BLE_MESH_SUBNET_COUNT=1 +CONFIG_BLE_MESH_APP_KEY_COUNT=1 +CONFIG_BLE_MESH_MODEL_KEY_COUNT=1 +CONFIG_BLE_MESH_MODEL_GROUP_COUNT=1 +CONFIG_BLE_MESH_LABEL_COUNT=1 +CONFIG_BLE_MESH_CRPL=10 +CONFIG_BLE_MESH_MSG_CACHE_SIZE=10 +CONFIG_BLE_MESH_ADV_BUF_COUNT=60 +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=6 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=1 +CONFIG_BLE_MESH_RX_SDU_MAX=384 +CONFIG_BLE_MESH_TX_SEG_MAX=32 +CONFIG_BLE_MESH_RELAY=y +CONFIG_BLE_MESH_LOW_POWER= +CONFIG_BLE_MESH_FRIEND= +CONFIG_BLE_MESH_CFG_CLI=y +CONFIG_BTU_TASK_STACK_SIZE=4512 \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/CMakeLists.txt b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/CMakeLists.txt new file mode 100644 index 0000000000..6ce28d7d57 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(ble_mesh_console_provisioner) diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/Makefile b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/Makefile new file mode 100644 index 0000000000..6c7b6101fa --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/Makefile @@ -0,0 +1,10 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := ble_mesh_console_provisioner + +COMPONENT_ADD_INCLUDEDIRS := components/include + +include $(IDF_PATH)/make/project.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/README.md b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/README.md new file mode 100644 index 0000000000..3925d93cf4 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/README.md @@ -0,0 +1,10 @@ +# ble mesh provisioner demo +## Introduction +This demo implements ble mesh provisioner basic features.Based on this demo, provisioner can scan and prove unprovisioned device, send set/get message. Also can define new model. + +Demo steps: +1. Build the ble mesh provisioner demo with sdkconfig.default +2. register provisioner and set oob info, load model to init ble mesh provisioner +3. enable bearer, so that it can scan and prove unprovisioned devices +4. config appkey and other config info use config client model +5. send set/get message to nodes \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/CMakeLists.txt b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/CMakeLists.txt new file mode 100644 index 0000000000..339b93fc95 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/CMakeLists.txt @@ -0,0 +1,15 @@ +set(COMPONENT_SRCS "ble_mesh_adapter.c" + "ble_mesh_cfg_srv_model.c" + "ble_mesh_console_lib.c" + "ble_mesh_console_main.c" + "ble_mesh_console_system.c" + "ble_mesh_reg_cfg_client_cmd.c" + "ble_mesh_reg_gen_onoff_client_cmd.c" + "ble_mesh_reg_test_perf_client_cmd.c" + "ble_mesh_register_node_cmd.c" + "ble_mesh_register_provisioner_cmd.c" + "register_bluetooth.c") + +set(COMPONENT_ADD_INCLUDEDIRS ".") + +register_component() diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.c b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.c new file mode 100644 index 0000000000..5f668718f3 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.c @@ -0,0 +1,300 @@ +// Copyright 2017-2018 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 "esp_ble_mesh_networking_api.h" +#include "ble_mesh_adapter.h" + +esp_ble_mesh_model_t *ble_mesh_get_model(uint16_t model_id) +{ + esp_ble_mesh_model_t *model = NULL; + + switch (model_id) { + case ESP_BLE_MESH_MODEL_ID_CONFIG_SRV: + model = config_server_models; + break; +#if (CONFIG_BLE_MESH_CFG_CLI) + case ESP_BLE_MESH_MODEL_ID_CONFIG_CLI: + model = &gen_onoff_cli_models[1]; + break; +#endif + case ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV: + model = &gen_onoff_srv_models[1]; + break; +#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI) + case ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI: + model = &gen_onoff_cli_models[2]; + break; +#endif + case ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_CLI: + model = &test_perf_cli_models[0]; + break; + case ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_SRV: + model = &test_perf_srv_models[0]; + break; + } + + return model; +} + +esp_ble_mesh_comp_t *ble_mesh_get_component(uint16_t model_id) +{ + esp_ble_mesh_comp_t *comp = NULL; + + switch (model_id) { + case ESP_BLE_MESH_MODEL_ID_CONFIG_SRV: + comp = &config_server_comp; + break; + case ESP_BLE_MESH_MODEL_ID_CONFIG_CLI: + comp = &config_client_comp; + break; + case ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV: + comp = &gen_onoff_srv_comp; + break; +#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI) + case ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI: + comp = &gen_onoff_cli_comp; + break; +#endif + case ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_CLI: + comp = &test_perf_cli_comp; + break; + case ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_SRV: + comp = &test_perf_srv_comp; + break; + } + + return comp; +} + +void ble_mesh_node_init() +{ + uint16_t i; + + for (i = 0; i < NODE_MAX_GROUP_CONFIG; i++) { + ble_mesh_node_prestore_params[i].net_idx = 0xFFFF; + ble_mesh_node_prestore_params[i].unicast_addr = 0xFFFF; + } + + ble_mesh_node_sema = xSemaphoreCreateMutex(); + if (!ble_mesh_node_sema) { + ESP_LOGE(TAG, "%s failed to init, failed to create mesh node semaphore", __func__); + } +} + +void ble_mesh_set_node_prestore_params(uint16_t netkey_index, uint16_t unicast_addr) +{ + uint16_t i; + xSemaphoreTake(ble_mesh_node_sema, portMAX_DELAY); + for (i = 0; i < NODE_MAX_GROUP_CONFIG; i++) { + if (ble_mesh_node_prestore_params[i].net_idx != 0xFFFF && ble_mesh_node_prestore_params[i].unicast_addr != 0xFFFF) { + ble_mesh_node_prestore_params[i].net_idx = netkey_index; + ble_mesh_node_prestore_params[i].unicast_addr = unicast_addr; + } + } + xSemaphoreGive(ble_mesh_node_sema); +} + +void ble_mesh_create_send_data(char *data, uint16_t byte_num, uint16_t sequence_num, uint32_t opcode) +{ + uint16_t i; + + // first two bytes are sequence num, third is type + data[0] = sequence_num >> 8; + data[1] = sequence_num & 0xFF; + switch (opcode) { + case ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_GET: + data[2] = VENDOR_MODEL_PERF_OPERATION_TYPE_GET; + break; + case ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET: + data[2] = VENDOR_MODEL_PERF_OPERATION_TYPE_SET; + break; + case ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK: + data[2] = VENDOR_MODEL_PERF_OPERATION_TYPE_SET_UNACK; + break; + } + + for (i = 3; i < byte_num; i++) { + data[i] = i; + } +} + +void ble_mesh_test_performance_client_model_get() +{ + uint32_t i, j; + uint32_t sum_time = 0; + + xSemaphoreTake(ble_mesh_test_perf_sema, portMAX_DELAY); + + for (i = 0, j = 0; i < test_perf_statistics.test_num; i++) { + if (test_perf_statistics.time[i] != 0) { + sum_time += test_perf_statistics.time[i]; + j += 1; + } else { + continue; + } + + if (j == test_perf_statistics.test_num - 1) { + break; + } + } + + ESP_LOGI(TAG, "VendorModel:Statistics,%d,%d\n", + test_perf_statistics.statistics, (sum_time / (j + 1))); + + xSemaphoreGive(ble_mesh_test_perf_sema); +} + +void ble_mesh_test_performance_client_model_get_received_percent() +{ + uint32_t i, j; + uint32_t max_time = 1400; + uint32_t min_time = 0; + uint32_t time_level_num = 0; + typedef struct { + uint16_t time_level; + uint16_t time_num; + } statistics_time_performance; + statistics_time_performance *statistics_time_percent; + + xSemaphoreTake(ble_mesh_test_perf_sema, portMAX_DELAY); + + time_level_num = ((max_time - min_time) / 50 + 1); + statistics_time_percent = malloc(sizeof(statistics_time_performance) * time_level_num); + + for (j = 0; j < time_level_num; j++) { + statistics_time_percent[j].time_level = min_time + 50 * j; + statistics_time_percent[j].time_num = 0; + } + + for (i = 0; i < test_perf_statistics.test_num; i++) { + for (j = 0; j < time_level_num; j++) { + if (test_perf_statistics.time[i] > max_time) { + j -= 1; + break; + } + if (test_perf_statistics.time[i] >= min_time + 50 * j + && test_perf_statistics.time[i] < min_time + 50 * (j + 1)) { + statistics_time_percent[j].time_num += 1; + break; + } + } + } + + // for script match + ESP_LOGI(TAG, "VendorModel:Statistics"); + for (j = 0; j < time_level_num; j++) { + printf(",%d:%d", statistics_time_percent[j].time_level, statistics_time_percent[j].time_num); + } + printf("\n"); + + free(statistics_time_percent); + xSemaphoreGive(ble_mesh_test_perf_sema); +} + +void ble_mesh_test_performance_client_model_accumulate_statistics(uint32_t value) +{ + xSemaphoreTake(ble_mesh_test_perf_sema, portMAX_DELAY); + test_perf_statistics.statistics += value; + xSemaphoreGive(ble_mesh_test_perf_sema); +} + +int ble_mesh_test_performance_client_model_accumulate_time(uint16_t time, uint8_t *data, uint8_t ack_ttl, uint16_t length) +{ + uint16_t i; + uint16_t sequence_num = 0; + uint16_t node_received_ttl = 0; + xSemaphoreTake(ble_mesh_test_perf_sema, portMAX_DELAY); + + // received fail + if (length != test_perf_statistics.test_length) { + xSemaphoreGive(ble_mesh_test_perf_sema); + return 1; + } + + if (data != NULL) { + sequence_num = (data[0] << 8) | data[1]; + if (data[2] == VENDOR_MODEL_PERF_OPERATION_TYPE_SET) { + node_received_ttl = data[3]; + } + } + + for (i = 0; i < test_perf_statistics.test_num; i++) { + if (test_perf_statistics.package_index[i] == sequence_num) { + xSemaphoreGive(ble_mesh_test_perf_sema); + return 1; + } + } + + for (i = 0; i < test_perf_statistics.test_num; i++) { + if (test_perf_statistics.package_index[i] == 0) { + test_perf_statistics.package_index[i] = sequence_num; + if (data[2] == VENDOR_MODEL_PERF_OPERATION_TYPE_SET) { + if (node_received_ttl == test_perf_statistics.ttl && ack_ttl == test_perf_statistics.ttl) { + test_perf_statistics.time[i] = time; + } else { + test_perf_statistics.time[i] = 0; + } + } else if (data[2] == VENDOR_MODEL_PERF_OPERATION_TYPE_SET_UNACK) { + test_perf_statistics.time[i] = time; + } + break; + } + } + + xSemaphoreGive(ble_mesh_test_perf_sema); + return 0; +} + +int ble_mesh_test_performance_client_model_init(uint16_t node_num, uint32_t test_num, uint8_t ttl) +{ + uint16_t i; + + // malloc time + test_perf_statistics.time = malloc(test_num * sizeof(uint16_t)); + if (test_perf_statistics.time == NULL) { + ESP_LOGE(TAG, " %s %d, malloc fail\n", __func__, __LINE__); + return 1; + } + + test_perf_statistics.package_index = malloc(test_num * sizeof(uint16_t)); + if (test_perf_statistics.package_index == NULL) { + ESP_LOGE(TAG, " %s %d, malloc fail\n", __func__, __LINE__); + } + for (i = 0; i < test_num; i++) { + test_perf_statistics.time[i] = 0; + test_perf_statistics.package_index[i] = 0; + } + + test_perf_statistics.test_num = test_num; + test_perf_statistics.node_num = node_num; + test_perf_statistics.ttl = ttl; + test_perf_statistics.statistics = 0; + return 0; +} + +void ble_mesh_test_performance_client_model_destroy() +{ + if (test_perf_statistics.time != NULL) { + free(test_perf_statistics.time); + } + + if (test_perf_statistics.package_index != NULL) { + free(test_perf_statistics.package_index); + } + + test_perf_statistics.test_num = 0; + test_perf_statistics.ttl = 0; + test_perf_statistics.node_num = 0; + test_perf_statistics.statistics = 0; +} diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.h b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.h new file mode 100644 index 0000000000..87bc7399a4 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.h @@ -0,0 +1,123 @@ +// Copyright 2017-2018 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. + +#ifndef _BLE_MESH_ADAPTER_H_ +#define _BLE_MESH_ADAPTER_H_ + +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" + +#include "ble_mesh_console_lib.h" +#include "ble_mesh_cfg_srv_model.h" + +#define TAG "ble_mesh_prov_console" + +uint64_t start_time; +typedef enum { + VENDOR_MODEL_PERF_OPERATION_TYPE_GET = 1, + VENDOR_MODEL_PERF_OPERATION_TYPE_SET, + VENDOR_MODEL_PERF_OPERATION_TYPE_SET_UNACK +} ble_mesh_perf_operation_type; + +typedef struct { + uint8_t current; + uint8_t previous; + char *name; +} ble_mesh_node_status; + +typedef struct { + bool need_ack; + uint8_t ttl; + uint16_t length; + uint16_t test_num; + uint16_t address; + uint16_t app_idx; + uint16_t net_idx; + uint32_t opcode; + esp_ble_mesh_model_t *model; + esp_ble_mesh_dev_role_t device_role; +} ble_mesh_test_perf_throughput_data; + +typedef struct { + uint32_t statistics; + uint32_t test_num; + uint16_t test_length; + uint16_t node_num; + uint16_t *time; + uint16_t *package_index; + uint8_t ttl; +} ble_mesh_performance_statistics_t; +ble_mesh_performance_statistics_t test_perf_statistics; + +#define SEND_MESSAGE_TIMEOUT (30000/portTICK_RATE_MS) + +extern SemaphoreHandle_t ble_mesh_node_sema; +extern SemaphoreHandle_t ble_mesh_test_perf_send_sema; +extern SemaphoreHandle_t ble_mesh_test_perf_sema; + +#define arg_int_to_value(src_msg, dst_msg, message) do { \ + if (src_msg->count != 0) {\ + ESP_LOGD(TAG, " %s, %s\n", __func__, message);\ + dst_msg = src_msg->ival[0];\ + } \ +} while(0) \ + +#define ble_mesh_node_get_value(index, key, value) do { \ + uint16_t _index = 0; \ + xSemaphoreTake(ble_mesh_node_sema, portMAX_DELAY); \ + for (_index = 0; _index < NODE_MAX_GROUP_CONFIG; _index) { \ + if (node_set_prestore_params[_index].key == value) { \ + break; \ + } \ + } \ + index = _index; \ + xSemaphoreGive(ble_mesh_node_sema); \ +} while(0) \ + +#define ble_mesh_node_set_state(status) do { \ + xSemaphoreTake(ble_mesh_node_sema, portMAX_DELAY); \ + node_status.previous = node_status.current; \ + node_status.current = status; \ + xSemaphoreGive(ble_mesh_node_sema); \ +}while(0) \ + +#define ble_mesh_node_get_state(status) do { \ + xSemaphoreTake(ble_mesh_node_sema, portMAX_DELAY); \ + status = node_status.previous; \ + xSemaphoreGive(ble_mesh_node_sema); \ +}while(0) \ + +#define ble_mesh_callback_check_err_code(err_code, message) do { \ + if (err_code == ESP_OK) { \ + ESP_LOGI(TAG, "%s,OK\n", message); \ + } else { \ + ESP_LOGI(TAG, "%s,Fail,%d\n", message, err_code); \ + } \ +}while(0) \ + +void ble_mesh_node_init(); +void ble_mesh_set_node_prestore_params(uint16_t netkey_index, uint16_t unicast_addr); + +esp_ble_mesh_model_t *ble_mesh_get_model(uint16_t model_id); +esp_ble_mesh_comp_t *ble_mesh_get_component(uint16_t model_id); +void ble_mesh_create_send_data(char *data, uint16_t byte_num, uint16_t sequence_num, uint32_t opcode); + +void ble_mesh_test_performance_client_model_get(); +void ble_mesh_test_performance_client_model_get_received_percent(); +void ble_mesh_test_performance_client_model_accumulate_statistics(uint32_t value); +int ble_mesh_test_performance_client_model_accumulate_time(uint16_t time, uint8_t *data, uint8_t ack_ttl, uint16_t length); +int ble_mesh_test_performance_client_model_init(uint16_t node_num, uint32_t test_num, uint8_t ttl); +void ble_mesh_test_performance_client_model_destroy(); + +#endif //_BLE_MESH_ADAPTER_H_ \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.c b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.c new file mode 100644 index 0000000000..9518e74b42 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.c @@ -0,0 +1,205 @@ +// Copyright 2017-2018 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 "ble_mesh_cfg_srv_model.h" + +uint8_t dev_uuid[16] = {0xdd, 0xdd}; + +#if CONFIG_BLE_MESH_NODE +esp_ble_mesh_prov_t prov = { + .uuid = dev_uuid, +}; +#endif //CONFIG_BLE_MESH_NODE + +#if CONFIG_BLE_MESH_PROVISIONER +esp_ble_mesh_prov_t prov = { + .prov_uuid = dev_uuid, + .prov_unicast_addr = 0x0001, + .prov_start_address = 0x0005, + .prov_attention = 0x00, + .prov_algorithm = 0x00, + .prov_pub_key_oob = 0x00, + .prov_static_oob_val = NULL, + .prov_static_oob_len = 0x00, + .flags = 0x00, + .iv_index = 0x00, +}; +#endif //CONFIG_BLE_MESH_PROVISIONER + +ESP_BLE_MESH_MODEL_PUB_DEFINE(model_pub_config, 2 + 1, ROLE_PROVISIONER); + +esp_ble_mesh_model_pub_t vendor_model_pub_config; + +// configure server module +esp_ble_mesh_cfg_srv_t cfg_srv = { + .relay = ESP_BLE_MESH_RELAY_ENABLED, + .beacon = ESP_BLE_MESH_BEACON_ENABLED, +#if defined(CONFIG_BLE_MESH_FRIEND) + .friend_state = ESP_BLE_MESH_FRIEND_ENABLED, +#else + .friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED, +#endif +#if defined(CONFIG_BLE_MESH_GATT_PROXY) + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED, +#else + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED, +#endif + .default_ttl = 7, + + /* 3 transmissions with 20ms interval */ + .net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20), + .relay_retransmit = ESP_BLE_MESH_TRANSMIT(0, 20), +}; + +esp_ble_mesh_model_t config_server_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv), +}; + +esp_ble_mesh_elem_t config_server_elements[] = { + ESP_BLE_MESH_ELEMENT(0, config_server_models, ESP_BLE_MESH_MODEL_NONE), +}; + +esp_ble_mesh_comp_t config_server_comp = { + .cid = CID_ESP, + .elements = config_server_elements, + .element_count = ARRAY_SIZE(config_server_elements), +}; + +// config client model +esp_ble_mesh_model_t config_client_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv), + ESP_BLE_MESH_MODEL_CFG_CLI(&cfg_cli), +}; + +esp_ble_mesh_elem_t config_client_elements[] = { + ESP_BLE_MESH_ELEMENT(0, config_client_models, ESP_BLE_MESH_MODEL_NONE), +}; + +esp_ble_mesh_comp_t config_client_comp = { + .cid = CID_ESP, + .elements = config_client_elements, + .element_count = ARRAY_SIZE(config_client_elements), +}; + +// configure special module +esp_ble_mesh_model_op_t gen_onoff_srv_model_op_config[] = { + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET, 0), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, 2), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2), + ESP_BLE_MESH_MODEL_OP_END, +}; + +esp_ble_mesh_model_t gen_onoff_srv_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv), + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_model_op_config, &model_pub_config, NULL), +}; + +esp_ble_mesh_elem_t gen_onoff_srv_elements[] = { + ESP_BLE_MESH_ELEMENT(0, gen_onoff_srv_models, ESP_BLE_MESH_MODEL_NONE), +}; + +esp_ble_mesh_comp_t gen_onoff_srv_comp = { + .cid = CID_ESP, + .elements = gen_onoff_srv_elements, + .element_count = ARRAY_SIZE(gen_onoff_srv_elements), +}; + +// config generic onoff client +#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI) + +esp_ble_mesh_client_t gen_onoff_cli; + +esp_ble_mesh_model_t gen_onoff_cli_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv), + ESP_BLE_MESH_MODEL_CFG_CLI(&cfg_cli), + ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(&model_pub_config, &gen_onoff_cli), +}; + +esp_ble_mesh_elem_t gen_onoff_cli_elements[] = { + ESP_BLE_MESH_ELEMENT(0, gen_onoff_cli_models, ESP_BLE_MESH_MODEL_NONE), +}; + +esp_ble_mesh_comp_t gen_onoff_cli_comp = { + .cid = CID_ESP, + .elements = gen_onoff_cli_elements, + .element_count = ARRAY_SIZE(gen_onoff_cli_elements), +}; +#endif //CONFIG_BLE_MESH_GENERIC_ONOFF_CLI + +//CONFIG VENDOR MODEL TEST PERFORMANCE +#define ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_SRV 0x2000 +#define ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_CLI 0x2001 + +#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_GET ESP_BLE_MESH_MODEL_OP_3(0x01, CID_ESP) +#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET ESP_BLE_MESH_MODEL_OP_3(0x02, CID_ESP) +#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK ESP_BLE_MESH_MODEL_OP_3(0x03, CID_ESP) +#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS ESP_BLE_MESH_MODEL_OP_3(0x04, CID_ESP) + +esp_ble_mesh_client_op_pair_t test_perf_cli_op_pair[] = { + {ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_GET, ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS}, + {ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET, ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS}, + {ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK, ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS}, +}; + +esp_ble_mesh_client_t test_perf_cli = { + .op_pair_size = ARRAY_SIZE(test_perf_cli_op_pair), + .op_pair = test_perf_cli_op_pair, +}; + +esp_ble_mesh_model_op_t test_perf_srv_op[] = { + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_GET, 1), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET, 1), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK, 1), + ESP_BLE_MESH_MODEL_OP_END, +}; + +esp_ble_mesh_model_op_t test_perf_cli_op[] = { + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS, 1), + ESP_BLE_MESH_MODEL_OP_END, +}; + +esp_ble_mesh_model_t config_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv), + ESP_BLE_MESH_MODEL_CFG_CLI(&cfg_cli), +}; + +esp_ble_mesh_model_t test_perf_cli_models[] = { + ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_CLI, + test_perf_cli_op, &vendor_model_pub_config, &test_perf_cli), +}; + +esp_ble_mesh_elem_t test_perf_cli_elements[] = { + ESP_BLE_MESH_ELEMENT(0, config_models, test_perf_cli_models), +}; + +esp_ble_mesh_comp_t test_perf_cli_comp = { + .cid = CID_ESP, + .elements = test_perf_cli_elements, + .element_count = ARRAY_SIZE(test_perf_cli_elements), +}; + +esp_ble_mesh_model_t test_perf_srv_models[] = { + ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_SRV, + test_perf_srv_op, NULL, NULL), +}; + +esp_ble_mesh_elem_t test_perf_srv_elements[] = { + ESP_BLE_MESH_ELEMENT(0, config_models, test_perf_srv_models), +}; + +esp_ble_mesh_comp_t test_perf_srv_comp = { + .cid = CID_ESP, + .elements = test_perf_srv_elements, + .element_count = ARRAY_SIZE(test_perf_srv_elements), +}; diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.h b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.h new file mode 100644 index 0000000000..9e43333eb9 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.h @@ -0,0 +1,107 @@ +// Copyright 2017-2018 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. + +#ifndef _BLE_MESH_CFG_SRV_MODEL_H_ +#define _BLE_MESH_CFG_SRV_MODEL_H_ + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_config_model_api.h" + +#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI) +#include "esp_ble_mesh_generic_model_api.h" +#endif //CONFIG_BLE_MESH_GENERIC_ONOFF_CLI + +#define NODE_MAX_GROUP_CONFIG 3 +#define CID_ESP 0x02C4 + +extern uint8_t dev_uuid[16]; + +typedef struct { + uint16_t net_idx; + uint16_t unicast_addr; +} ble_mesh_node_config_params; +ble_mesh_node_config_params ble_mesh_node_prestore_params[NODE_MAX_GROUP_CONFIG]; + +extern esp_ble_mesh_prov_t prov; + +extern esp_ble_mesh_model_pub_t vendor_model_pub_config; + +// configure server module +extern esp_ble_mesh_cfg_srv_t cfg_srv; + +extern esp_ble_mesh_model_t config_server_models[]; + +extern esp_ble_mesh_elem_t config_server_elements[]; + +extern esp_ble_mesh_comp_t config_server_comp; + +// config client model +esp_ble_mesh_client_t cfg_cli; +extern esp_ble_mesh_model_t config_client_models[]; + +extern esp_ble_mesh_elem_t config_client_elements[]; + +extern esp_ble_mesh_comp_t config_client_comp; + +// configure special module +extern esp_ble_mesh_model_op_t gen_onoff_srv_model_op_config[]; + +extern esp_ble_mesh_model_t gen_onoff_srv_models[]; + +extern esp_ble_mesh_elem_t gen_onoff_srv_elements[]; + +extern esp_ble_mesh_comp_t gen_onoff_srv_comp; + +// config generic onoff client +#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI) + +extern esp_ble_mesh_client_t gen_onoff_cli; + +extern esp_ble_mesh_model_t gen_onoff_cli_models[]; + +extern esp_ble_mesh_elem_t gen_onoff_cli_elements[]; + +extern esp_ble_mesh_comp_t gen_onoff_cli_comp; +#endif //CONFIG_BLE_MESH_GENERIC_ONOFF_CLI + +//CONFIG VENDOR MODEL TEST PERFORMANCE +#define ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_SRV 0x2000 +#define ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_CLI 0x2001 + +#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_GET ESP_BLE_MESH_MODEL_OP_3(0x01, CID_ESP) +#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET ESP_BLE_MESH_MODEL_OP_3(0x02, CID_ESP) +#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK ESP_BLE_MESH_MODEL_OP_3(0x03, CID_ESP) +#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS ESP_BLE_MESH_MODEL_OP_3(0x04, CID_ESP) + +extern esp_ble_mesh_client_t test_perf_cli; + +extern esp_ble_mesh_model_op_t test_perf_srv_op[]; + +extern esp_ble_mesh_model_op_t test_perf_cli_op[]; + +extern esp_ble_mesh_model_t config_models[]; + +extern esp_ble_mesh_model_t test_perf_cli_models[]; + +extern esp_ble_mesh_elem_t test_perf_cli_elements[]; + +extern esp_ble_mesh_comp_t test_perf_cli_comp; + +extern esp_ble_mesh_model_t test_perf_srv_models[]; + +extern esp_ble_mesh_elem_t test_perf_srv_elements[]; + +extern esp_ble_mesh_comp_t test_perf_srv_comp; + +#endif //_BLE_MESH_CFG_SRV_MODEL_H_ diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_decl.h b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_decl.h new file mode 100644 index 0000000000..90e52a61d9 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_decl.h @@ -0,0 +1,38 @@ +/* Console example — declarations of command registration functions. + + This example code is in the Public Domain (or CC0 licensed, at your option). + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#pragma once + +#include "esp_ble_mesh_defs.h" + +// Register system functions +void register_system(); + +// Register bluetooth +void register_bluetooth(); + +// Register mesh node cmd +void ble_mesh_register_mesh_node(); + +// Register Test Perf client cmd +void ble_mesh_register_mesh_test_performance_client(); + +#if (CONFIG_BLE_MESH_CFG_CLI) +// Register mesh config client operation cmd +void ble_mesh_register_configuration_client_model(); +#endif + +#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI) +// Register mesh client operation cmd +void ble_mesh_register_gen_onoff_client(); +#endif + +#if CONFIG_BLE_MESH_PROVISIONER +// Regitster mesh provisioner cmd +void ble_mesh_register_mesh_provisioner(); +#endif diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.c b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.c new file mode 100644 index 0000000000..d15ee3adc1 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.c @@ -0,0 +1,124 @@ +// Copyright 2017-2018 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 "ble_mesh_console_lib.h" + +static int hex2num(char c); +static int hex2byte(const char *hex); + +static int hex2num(char c) +{ + if (c >= '0' && c <= '9') { + return c - '0'; + } + if (c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } + if (c >= 'A' && c <= 'F') { + return c - 'A' + 10; + } + return -1; +} + +static int hex2byte(const char *hex) +{ + int a, b; + a = hex2num(*hex++); + if (a < 0) { + return -1; + } + b = hex2num(*hex++); + if (b < 0) { + return -1; + } + return (a << 4) | b; +} + +int hexstr_2_bin(const char *hex, uint8_t *buf, uint32_t len) +{ + uint32_t i; + int a; + const char *ipos = hex; + uint8_t *opos = buf; + + for (i = 0; i < len; i++) { + a = hex2byte(ipos); + if (a < 0) { + return -1; + } + *opos ++ = a; + ipos += 2; + } + return 0; +} + +int get_value_string(char *value_in, char *buf) +{ + int result = -1; + + uint16_t length = strlen(value_in); + + if (length > 2) { + if (value_in[0] == '0' && value_in[1] == 'x') { + buf[(length - 2) / 2] = 0; + result = hexstr_2_bin(&value_in[2], (uint8_t *)buf, (length - 2) / 2); + length = (length - 2) / 2; + } else { + strcpy(buf, value_in); + result = 0; + } + } else { + strcpy(buf, value_in); + result = 0; + } + return result; +} + +bool str_2_mac(uint8_t *str, uint8_t *dest) +{ + uint8_t loop = 0; + uint8_t tmp = 0; + uint8_t *src_p = str; + + if (strlen((char *)src_p) != 17) { // must be like 12:34:56:78:90:AB + return false; + } + + for (loop = 0; loop < 17 ; loop++) { + if (loop % 3 == 2) { + if (src_p[loop] != ':') { + return false; + } + + continue; + } + + if ((src_p[loop] >= '0') && (src_p[loop] <= '9')) { + tmp = tmp * 16 + src_p[loop] - '0'; + } else if ((src_p[loop] >= 'A') && (src_p[loop] <= 'F')) { + tmp = tmp * 16 + src_p[loop] - 'A' + 10; + } else if ((src_p[loop] >= 'a') && (src_p[loop] <= 'f')) { + tmp = tmp * 16 + src_p[loop] - 'a' + 10; + } else { + return false; + } + + if (loop % 3 == 1) { + *dest++ = tmp; + tmp = 0; + } + } + + return true; +} diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.h b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.h new file mode 100644 index 0000000000..11dd05cb37 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.h @@ -0,0 +1,29 @@ +// Copyright 2017-2018 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. + +#ifndef _BLE_MESH_CONSOLE_LIB_H_ +#define _BLE_MESH_CONSOLE_LIB_H_ + +#include +#include + +#include "esp_system.h" +#include "esp_console.h" +#include "argtable3/argtable3.h" + +bool str_2_mac(uint8_t *str, uint8_t *dest); +int hexstr_2_bin(const char *hex, uint8_t *buf, uint32_t len); +int get_value_string(char *value_in, char *buf); + +#endif //_BLE_MESH_CONSOLE_LIB_H_ \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c new file mode 100644 index 0000000000..f7c4eacf6b --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c @@ -0,0 +1,228 @@ +// Copyright 2017-2018 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 +#include + +#include "esp_system.h" +#include "esp_log.h" +#include "esp_console.h" +#include "esp_vfs_dev.h" +#include "driver/uart.h" +#include "linenoise/linenoise.h" +#include "argtable3/argtable3.h" + +#include "esp_vfs_fat.h" +#include "nvs.h" +#include "nvs_flash.h" + +#include "esp_bt.h" +#include "esp_bt_main.h" + +#include "ble_mesh_console_decl.h" + +#define TAG "ble_mesh_test" + +#if CONFIG_STORE_HISTORY + +#define MOUNT_PATH "/data" +#define HISTORY_PATH MOUNT_PATH "/history.txt" + +static void initialize_filesystem() +{ + static wl_handle_t wl_handle; + const esp_vfs_fat_mount_config_t mount_config = { + .max_files = 4, + .format_if_mount_failed = true + }; + esp_err_t err = esp_vfs_fat_spiflash_mount(MOUNT_PATH, "storage", &mount_config, &wl_handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to mount FATFS (0x%x)", err); + return; + } +} +#endif // CONFIG_STORE_HISTORY + +static void initialize_console() +{ + /* Disable buffering on stdin and stdout */ + setvbuf(stdin, NULL, _IONBF, 0); + setvbuf(stdout, NULL, _IONBF, 0); + + /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */ + esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR); + /* Move the caret to the beginning of the next line on '\n' */ + esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF); + + /* Install UART driver for interrupt-driven reads and writes */ + ESP_ERROR_CHECK( uart_driver_install(CONFIG_CONSOLE_UART_NUM, + 256, 0, 0, NULL, 0) ); + + /* Tell VFS to use UART driver */ + esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM); + + /* Initialize the console */ + esp_console_config_t console_config = { + .max_cmdline_args = 20, + .max_cmdline_length = 256, +#if CONFIG_LOG_COLORS + .hint_color = atoi(LOG_COLOR_CYAN) +#endif + }; + ESP_ERROR_CHECK( esp_console_init(&console_config) ); + + /* Configure linenoise line completion library */ + /* Enable multiline editing. If not set, long commands will scroll within + * a single line. + */ + linenoiseSetMultiLine(1); + + /* Tell linenoise where to get command completions and hints */ + linenoiseSetCompletionCallback(&esp_console_get_completion); + linenoiseSetHintsCallback((linenoiseHintsCallback *) &esp_console_get_hint); + + /* Set command history size */ + linenoiseHistorySetMaxLen(100); + +#if CONFIG_STORE_HISTORY + /* Load command history from filesystem */ + linenoiseHistoryLoad(HISTORY_PATH); +#endif +} + + +esp_err_t bluetooth_init(void) +{ + esp_err_t ret; + + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + ret = esp_bt_controller_init(&bt_cfg); + if (ret) { + ESP_LOGE(TAG, "%s failed to initialize controller\n", __func__); + return ret; + } + + ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); + if (ret) { + ESP_LOGE(TAG, "%s failed to enable controller\n", __func__); + return ret; + } + ret = esp_bluedroid_init(); + if (ret) { + ESP_LOGE(TAG, "%s failed to initialize bluetooth\n", __func__); + return ret; + } + ret = esp_bluedroid_enable(); + if (ret) { + ESP_LOGE(TAG, "%s failed to enable bluetooth\n", __func__); + return ret; + } + + return ret; +} + +void app_main(void) +{ + esp_err_t res; + + nvs_flash_init(); + + // init and enable bluetooth + res = bluetooth_init(); + if (res) { + printf("esp32_bluetooth_init failed (ret %d)", res); + } + +#if CONFIG_STORE_HISTORY + initialize_filesystem(); +#endif + + initialize_console(); + + /* Register commands */ + esp_console_register_help_command(); + register_system(); + register_bluetooth(); + ble_mesh_register_mesh_node(); + ble_mesh_register_mesh_test_performance_client(); +#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI) + ble_mesh_register_gen_onoff_client(); +#endif +#if (CONFIG_BLE_MESH_PROVISIONER) + ble_mesh_register_mesh_provisioner(); +#endif +#if (CONFIG_BLE_MESH_CFG_CLI) + ble_mesh_register_configuration_client_model(); +#endif + + + /* Prompt to be printed before each line. + * This can be customized, made dynamic, etc. + */ + const char *prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR; + + printf("\n" + "This is an example of an ESP-IDF console component.\n" + "Type 'help' to get the list of commands.\n" + "Use UP/DOWN arrows to navigate through the command history.\n" + "Press TAB when typing a command name to auto-complete.\n"); + + /* Figure out if the terminal supports escape sequences */ + int probe_status = linenoiseProbe(); + if (probe_status) { /* zero indicates OK */ + printf("\n" + "Your terminal application does not support escape sequences.\n" + "Line editing and history features are disabled.\n" + "On Windows, try using Putty instead.\n"); + linenoiseSetDumbMode(1); +#if CONFIG_LOG_COLORS + /* Since the terminal doesn't support escape sequences, + * don't use color codes in the prompt. + */ + prompt = "esp32> "; +#endif //CONFIG_LOG_COLORS + } + + /* Main loop */ + while (true) { + /* Get a line using linenoise. + * The line is returned when ENTER is pressed. + */ + char *line = linenoise(prompt); + if (line == NULL) { /* Ignore empty lines */ + continue; + } + /* Add the command to the history */ + linenoiseHistoryAdd(line); +#if CONFIG_STORE_HISTORY + /* Save command history to filesystem */ + linenoiseHistorySave(HISTORY_PATH); +#endif + + /* Try to run the command */ + int ret; + esp_err_t err = esp_console_run(line, &ret); + if (err == ESP_ERR_NOT_FOUND) { + printf("Unrecognized command\n"); + } else if (err == ESP_ERR_INVALID_ARG) { + // command was empty + } else if (err == ESP_OK && ret != ESP_OK) { + printf("\nCommand returned non-zero error code: 0x%x\n", ret); + } else if (err != ESP_OK) { + printf("Internal error: 0x%x\n", err); + } + /* linenoise allocates line buffer on the heap, so need to free it */ + linenoiseFree(line); + } +} diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_system.c b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_system.c new file mode 100644 index 0000000000..d3dc6c12f9 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_system.c @@ -0,0 +1,179 @@ +/* Console example — various system commands + + This example code is in the Public Domain (or CC0 licensed, at your option). + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include + +#include "esp_log.h" +#include "esp_console.h" +#include "esp_system.h" +#include "esp_sleep.h" +#include "driver/rtc_io.h" +#include "argtable3/argtable3.h" + +#include "ble_mesh_console_decl.h" + +#if CONFIG_IDF_CMAKE +#define CONFIG_ESPTOOLPY_PORT "Which is choosen by Users for CMake" +#endif + +static void register_free(); +static void register_restart(); +static void register_make(); + +void register_system() +{ + register_free(); + register_restart(); + register_make(); +} + +/** 'restart' command restarts the program */ + +static int restart(int argc, char **argv) +{ + printf("%s, %s", __func__, "Restarting"); + esp_restart(); +} + +static void register_restart() +{ + const esp_console_cmd_t cmd = { + .command = "restart", + .help = "Restart the program", + .hint = NULL, + .func = &restart, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); +} + +/** 'free' command prints available heap memory */ + +static int free_mem(int argc, char **argv) +{ + printf("%d\n", esp_get_free_heap_size()); + return 0; +} + +static void register_free() +{ + const esp_console_cmd_t cmd = { + .command = "free", + .help = "Get the total size of heap memory available", + .hint = NULL, + .func = &free_mem, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); +} + +static int make(int argc, char **argv) +{ + int count = REG_READ(RTC_CNTL_STORE0_REG); + if (++count >= 3) { + printf("This is not the console you are looking for.\n"); + return 0; + } + REG_WRITE(RTC_CNTL_STORE0_REG, count); + + const char *make_output = + R"(LD build/console.elf +esptool.py v2.1-beta1 +)"; + + const char* flash_output[] = { +R"(Flashing binaries to serial port )" CONFIG_ESPTOOLPY_PORT R"( (app at offset 0x10000)... +esptool.py v2.1-beta1 +Connecting.... +)", +R"(Chip is ESP32D0WDQ6 (revision 0) +Uploading stub... +Running stub... +Stub running... +Changing baud rate to 921600 +Changed. +Configuring flash size... +Auto-detected Flash size: 4MB +Flash params set to 0x0220 +Compressed 15712 bytes to 9345... +)", +R"(Wrote 15712 bytes (9345 compressed) at 0x00001000 in 0.1 seconds (effective 1126.9 kbit/s)... +Hash of data verified. +Compressed 333776 bytes to 197830... +)", +R"(Wrote 333776 bytes (197830 compressed) at 0x00010000 in 3.3 seconds (effective 810.3 kbit/s)... +Hash of data verified. +Compressed 3072 bytes to 82... +)", +R"(Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 1588.4 kbit/s)... +Hash of data verified. +Leaving... +Hard resetting... +)" + }; + + const char* monitor_output = +R"(MONITOR +)" LOG_COLOR_W R"(--- idf_monitor on )" CONFIG_ESPTOOLPY_PORT R"( 115200 --- +--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H -- +)" LOG_RESET_COLOR; + + bool need_make = false; + bool need_flash = false; + bool need_monitor = false; + for (int i = 1; i < argc; ++i) { + if (strcmp(argv[i], "all") == 0) { + need_make = true; + } else if (strcmp(argv[i], "flash") == 0) { + need_make = true; + need_flash = true; + } else if (strcmp(argv[i], "monitor") == 0) { + need_monitor = true; + } else if (argv[i][0] == '-') { + /* probably -j option */ + } else if (isdigit((int) argv[i][0])) { + /* might be an argument to -j */ + } else { + printf("make: *** No rule to make target `%s'. Stop.\n", argv[i]); + /* Technically this is an error, but let's not spoil the output */ + return 0; + } + } + if (argc == 1) { + need_make = true; + } + if (need_make) { + printf("%s", make_output); + } + if (need_flash) { + size_t n_items = sizeof(flash_output) / sizeof(flash_output[0]); + for (int i = 0; i < n_items; ++i) { + printf("%s", flash_output[i]); + vTaskDelay(200/portTICK_PERIOD_MS); + } + } + if (need_monitor) { + printf("%s", monitor_output); + esp_restart(); + } + return 0; +} + +static void register_make() +{ + const esp_console_cmd_t cmd = { + .command = "make", + .help = NULL, /* Do not include in 'help' output */ + .hint = "all | flash | monitor", + .func = &make, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); +} + + diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_cfg_client_cmd.c b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_cfg_client_cmd.c new file mode 100644 index 0000000000..fd2852de82 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_cfg_client_cmd.c @@ -0,0 +1,390 @@ +// Copyright 2017-2018 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 "esp_ble_mesh_networking_api.h" +#include "ble_mesh_adapter.h" + +#if (CONFIG_BLE_MESH_CFG_CLI) +typedef struct { + struct arg_str *action_type; + struct arg_str *set_state; + struct arg_int *opcode; + struct arg_int *unicast_address; + struct arg_int *appkey_index; + struct arg_int *mod_id; + struct arg_int *addr; + struct arg_int *cid; + struct arg_int *value; + struct arg_int *relay_statue; + struct arg_int *relay_transmit; + struct arg_int *net_idx; + struct arg_end *end; +} ble_mesh_client_get_set_state_t; +ble_mesh_client_get_set_state_t configuration_client_model_operation; + +void ble_mesh_register_configuration_client_model_command(); +void ble_mesh_configuration_client_model_cb(esp_ble_mesh_cfg_client_cb_event_t event, + esp_ble_mesh_cfg_client_cb_param_t *param); + +void ble_mesh_register_configuration_client_model() +{ + ble_mesh_register_configuration_client_model_command(); +} + +void ble_mesh_configuration_client_model_cb(esp_ble_mesh_cfg_client_cb_event_t event, + esp_ble_mesh_cfg_client_cb_param_t *param) +{ + uint32_t opcode; + ESP_LOGD(TAG, "enter %s, event = %x\n, error_code = %x\n", __func__, event, param->error_code); + + if (!param->error_code) { + opcode = param->params->opcode; + switch (event) { + case ESP_BLE_MESH_CFG_CLIENT_GET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_BEACON_GET: + ESP_LOGI(TAG, "CfgClient:beacon,0x%x", param->status_cb.beacon_status.beacon); + break; + case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET: + ESP_LOGI(TAG, "CfgClient:page,0x%x,len,0x%x", param->status_cb.comp_data_status.page, param->status_cb.comp_data_status.composition_data->len); + break; + case ESP_BLE_MESH_MODEL_OP_DEFAULT_TTL_GET: + ESP_LOGI(TAG, "CfgClient:ttl,0x%x", param->status_cb.default_ttl_status.default_ttl); + break; + case ESP_BLE_MESH_MODEL_OP_GATT_PROXY_GET: + ESP_LOGI(TAG, "CfgClient:proxy,0x%x", param->status_cb.gatt_proxy_status.gatt_proxy); + break; + case ESP_BLE_MESH_MODEL_OP_RELAY_GET: + ESP_LOGI(TAG, "CfgClient:relay,0x%x,retransmit,0x%x", param->status_cb.relay_status.relay, param->status_cb.relay_status.retransmit); + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_PUB_GET: + if (param->status_cb.model_pub_status.status == ESP_OK) { + ESP_LOGI(TAG, "CfgClient:PublishGet,OK,0x%x", param->status_cb.model_pub_status.publish_addr); + } else { + ESP_LOGI(TAG, "CfgClient:PublishGet,Fail"); + } + + break; + case ESP_BLE_MESH_MODEL_OP_FRIEND_GET: + ESP_LOGI(TAG, "CfgClient:friend,0x%x", param->status_cb.friend_status.friend_state); + break; + case ESP_BLE_MESH_MODEL_OP_HEARTBEAT_PUB_GET: + if (param->status_cb.heartbeat_pub_status.status == ESP_OK) { + ESP_LOGI(TAG, "CfgClient:HeartBeatPubGet,OK,destination:0x%x,countlog:0x%x,periodlog:0x%x,ttl:0x%x,features:0x%x,net_idx:0x%x", + param->status_cb.heartbeat_pub_status.dst, param->status_cb.heartbeat_pub_status.count, param->status_cb.heartbeat_pub_status.period, + param->status_cb.heartbeat_pub_status.ttl, param->status_cb.heartbeat_pub_status.features, param->status_cb.heartbeat_pub_status.net_idx); + } else { + ESP_LOGI(TAG, "CfgClient:HeartBeatGet,Fail,%d", param->status_cb.heartbeat_pub_status.status); + } + break; + case ESP_BLE_MESH_MODEL_OP_HEARTBEAT_SUB_GET: + if (param->status_cb.heartbeat_sub_status.status == ESP_OK) { + ESP_LOGI(TAG, "CfgClient:HeartBeatSubGet,OK,source:0x%x,destination:0x%x, periodlog:0x%x,countlog:0x%x,minhops:0x%x,maxhops:0x%x", + param->status_cb.heartbeat_sub_status.src, param->status_cb.heartbeat_sub_status.dst, param->status_cb.heartbeat_sub_status.period, + param->status_cb.heartbeat_sub_status.count, param->status_cb.heartbeat_sub_status.min_hops, param->status_cb.heartbeat_sub_status.max_hops); + } else { + ESP_LOGI(TAG, "CfgClient:HeartBeatSubGet,Fail,%d", param->status_cb.heartbeat_sub_status.status); + } + break; + default: + ESP_LOGI(TAG, "Not supported config client get message opcode"); + break; + } + break; + case ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_BEACON_SET: + ESP_LOGI(TAG, "CfgClient:beacon,0x%x", param->status_cb.beacon_status.beacon); + break; + case ESP_BLE_MESH_MODEL_OP_DEFAULT_TTL_SET: + ESP_LOGI(TAG, "CfgClient:ttl,0x%x", param->status_cb.default_ttl_status.default_ttl); + break; + case ESP_BLE_MESH_MODEL_OP_GATT_PROXY_SET: + ESP_LOGI(TAG, "CfgClient:proxy,0x%x", param->status_cb.gatt_proxy_status.gatt_proxy); + break; + case ESP_BLE_MESH_MODEL_OP_RELAY_SET: + ESP_LOGI(TAG, "CfgClient:relay,0x%x, retransmit: 0x%x", param->status_cb.relay_status.relay, param->status_cb.relay_status.retransmit); + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_PUB_SET: + if (param->status_cb.model_pub_status.status == ESP_OK) { + ESP_LOGI(TAG, "CfgClient:PublishSet,OK,0x%x", param->status_cb.model_pub_status.publish_addr); + } else { + ESP_LOGI(TAG, "CfgClient:PublishSet,Fail"); + } + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_ADD: + if (param->status_cb.model_sub_status.status == ESP_OK) { + ESP_LOGI(TAG, "CnfClient:SubAdd,OK,%x,%x", param->status_cb.model_sub_status.element_addr, param->status_cb.model_sub_status.sub_addr); + } else { + ESP_LOGI(TAG, "CnfClient:SubAdd,Fail,%x", param->status_cb.model_sub_status.status); + } + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_DELETE: + if (param->status_cb.model_sub_status.status == ESP_OK) { + ESP_LOGI(TAG, "CnfClient:SubDel,OK,%x,%x", param->status_cb.model_sub_status.element_addr, param->status_cb.model_sub_status.sub_addr); + } else { + ESP_LOGI(TAG, "CnfClient:SubDel,Fail,%x", param->status_cb.model_sub_status.status); + } + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_OVERWRITE: + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_ADD: + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_DELETE: + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_OVERWRITE: + break; + case ESP_BLE_MESH_MODEL_OP_NET_KEY_ADD: + if (param->status_cb.netkey_status.status == ESP_OK) { + ESP_LOGI(TAG, "CfgClient:NetKeyAdd,OK"); + } else { + ESP_LOGI(TAG, "CfgClient:NetKeyAdd,Fail,%d", param->status_cb.netkey_status.status); + } + break; + case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: + if (param->status_cb.appkey_status.status == ESP_OK) { + ESP_LOGI(TAG, "CnfClient:AddAppkey,OK,%x,%x,%x", param->status_cb.appkey_status.net_idx, param->status_cb.appkey_status.app_idx, param->params->ctx.addr); + } else { + ESP_LOGI(TAG, "CnfClient:AddAppkey,Fail,%x", param->status_cb.appkey_status.status); + } + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND: + if (param->status_cb.model_app_status.status == ESP_OK) { + ESP_LOGI(TAG, "CnfClient:AppkeyBind,OK,%x,%x,%x", param->status_cb.model_app_status.app_idx, param->status_cb.model_app_status.model_id, param->params->ctx.addr); + } else { + ESP_LOGI(TAG, "CnfClient:AppkeyBind,Fail,%x", param->status_cb.model_app_status.status); + } + break; + case ESP_BLE_MESH_MODEL_OP_FRIEND_SET: + ESP_LOGI(TAG, "CfgClient:friend: 0x%x", param->status_cb.friend_status.friend_state); + break; + case ESP_BLE_MESH_MODEL_OP_HEARTBEAT_PUB_SET: + if (param->status_cb.heartbeat_pub_status.status == ESP_OK) { + ESP_LOGI(TAG, "CfgClient:HeartBeatPubSet,OK,destination:0x%x,countlog:0x%x, periodlog:0x%x,ttl:0x%x,features:0x%x,net_idx: 0x%x", + param->status_cb.heartbeat_pub_status.dst, param->status_cb.heartbeat_pub_status.count, param->status_cb.heartbeat_pub_status.period, + param->status_cb.heartbeat_pub_status.ttl, param->status_cb.heartbeat_pub_status.features, param->status_cb.heartbeat_pub_status.net_idx); + } else { + ESP_LOGI(TAG, "CfgClient:HeartBeatSet,Fail,%d", param->status_cb.heartbeat_pub_status.status); + } + break; + case ESP_BLE_MESH_MODEL_OP_HEARTBEAT_SUB_SET: + if (param->status_cb.heartbeat_sub_status.status == ESP_OK) { + ESP_LOGI(TAG, "CfgClient:HeartBeatSubSet,OK,source:0x%x,destination:0x%x, periodlog:0x%x,countlog:0x%x,minhops:0x%x,maxhops:0x%x", + param->status_cb.heartbeat_sub_status.src, param->status_cb.heartbeat_sub_status.dst, param->status_cb.heartbeat_sub_status.period, + param->status_cb.heartbeat_sub_status.count, param->status_cb.heartbeat_sub_status.min_hops, param->status_cb.heartbeat_sub_status.max_hops); + } else { + ESP_LOGI(TAG, "CfgClient:HeartBeatSubSet,Fail,%d", param->status_cb.heartbeat_sub_status.status); + } + break; + default: + ESP_LOGI(TAG, "Not supported config client set message opcode"); + break; + } + break; + case ESP_BLE_MESH_CFG_CLIENT_PUBLISH_EVT: + ESP_LOGI(TAG, "CnfClient:Publish,OK"); + break; + case ESP_BLE_MESH_CFG_CLIENT_EVT_MAX: + ESP_LOGI(TAG, "CnfClient:MaxEvt"); + break; + case ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT: + ESP_LOGI(TAG, "CfgClient:TimeOut"); + break; + default: + ESP_LOGI(TAG, "CfgClient:InvalidEvent"); + break; + } + } else { + ESP_LOGI(TAG, "CnfClient:Fail,%d", param->error_code); + } + ESP_LOGD(TAG, "exit %s \n", __func__); +} + +int ble_mesh_configuration_client_model_operation(int argc, char **argv) +{ + int err = ESP_OK; + const uint8_t *app_key = NULL; + esp_ble_mesh_cfg_default_ttl_set_t ttl_set; + esp_ble_mesh_cfg_gatt_proxy_set_t proxy_set; + esp_ble_mesh_cfg_app_key_add_t app_key_add; + esp_ble_mesh_cfg_model_pub_set_t mod_pub_set = { + .company_id = 0xFFFF, + .cred_flag = false, + .publish_period = 0, + .publish_retransmit = 0, + }; + esp_ble_mesh_cfg_model_sub_add_t mod_sub_add = { + .company_id = 0xFFFF, + }; + esp_ble_mesh_cfg_model_sub_delete_t mod_sub_del = { + .company_id = 0xFFFF, + }; + esp_ble_mesh_cfg_relay_set_t relay_set; + esp_ble_mesh_client_common_param_t client_common = { + .msg_role = ROLE_PROVISIONER, + .msg_timeout = 0, + .ctx.send_ttl = 7, + }; + esp_ble_mesh_cfg_client_get_state_t get_state = { + .comp_data_get.page = 0, + .model_pub_get.company_id = 0xFFFF, + }; + esp_ble_mesh_cfg_model_app_bind_t mod_app_bind = { + .company_id = 0xFFFF, + }; + + client_common.model = ble_mesh_get_model(ESP_BLE_MESH_MODEL_ID_CONFIG_CLI); + + ESP_LOGD(TAG, "enter %s \n", __func__); + + int nerrors = arg_parse(argc, argv, (void **) &configuration_client_model_operation); + if (nerrors != 0) { + arg_print_errors(stderr, configuration_client_model_operation.end, argv[0]); + return 1; + } + + if (configuration_client_model_operation.opcode->count != 0) { + client_common.opcode = configuration_client_model_operation.opcode->ival[0]; + } + + if (configuration_client_model_operation.net_idx->count != 0) { + client_common.ctx.net_idx = configuration_client_model_operation.net_idx->ival[0]; + app_key_add.net_idx = configuration_client_model_operation.net_idx->ival[0]; + } + + if (configuration_client_model_operation.unicast_address->count != 0) { + client_common.ctx.addr = configuration_client_model_operation.unicast_address->ival[0]; + get_state.model_pub_get.element_addr = configuration_client_model_operation.unicast_address->ival[0]; + mod_app_bind.element_addr = configuration_client_model_operation.unicast_address->ival[0]; + mod_sub_add.element_addr = configuration_client_model_operation.unicast_address->ival[0]; + mod_sub_del.element_addr = configuration_client_model_operation.unicast_address->ival[0]; + mod_pub_set.element_addr = configuration_client_model_operation.unicast_address->ival[0]; + } + + if (configuration_client_model_operation.appkey_index->count != 0) { + client_common.ctx.app_idx = configuration_client_model_operation.appkey_index->ival[0]; + mod_app_bind.model_app_idx = configuration_client_model_operation.appkey_index->ival[0]; + app_key_add.app_idx = configuration_client_model_operation.appkey_index->ival[0]; + mod_pub_set.publish_app_idx = configuration_client_model_operation.appkey_index->ival[0]; + } + + if (configuration_client_model_operation.value->count != 0) { + ttl_set.ttl = configuration_client_model_operation.value->ival[0]; + proxy_set.gatt_proxy = configuration_client_model_operation.value->ival[0]; + mod_pub_set.publish_ttl = configuration_client_model_operation.value->ival[0]; + } + + if (configuration_client_model_operation.addr->count != 0) { + mod_sub_del.sub_addr = configuration_client_model_operation.addr->ival[0]; + mod_sub_add.sub_addr = configuration_client_model_operation.addr->ival[0]; + mod_pub_set.publish_addr = configuration_client_model_operation.addr->ival[0]; + } + + if (configuration_client_model_operation.mod_id->count != 0) { + mod_app_bind.model_id = configuration_client_model_operation.mod_id->ival[0]; + mod_sub_add.model_id = configuration_client_model_operation.mod_id->ival[0]; + mod_sub_del.model_id = configuration_client_model_operation.mod_id->ival[0]; + get_state.model_pub_get.model_id = configuration_client_model_operation.mod_id->ival[0];; + mod_pub_set.model_id = configuration_client_model_operation.mod_id->ival[0]; + } + + if (configuration_client_model_operation.relay_statue->count != 0) { + relay_set.relay = configuration_client_model_operation.relay_statue->ival[0]; + mod_pub_set.publish_period = configuration_client_model_operation.relay_statue->ival[0]; + } + + if (configuration_client_model_operation.relay_transmit->count != 0) { + relay_set.relay_retransmit = configuration_client_model_operation.relay_transmit->ival[0]; + mod_pub_set.publish_retransmit = configuration_client_model_operation.relay_transmit->ival[0]; + } + + if (configuration_client_model_operation.cid->count != 0) { + mod_app_bind.company_id = configuration_client_model_operation.cid->ival[0]; + mod_sub_del.company_id = configuration_client_model_operation.cid->ival[0]; + mod_sub_add.company_id = configuration_client_model_operation.cid->ival[0]; + mod_pub_set.company_id = configuration_client_model_operation.cid->ival[0]; + } + + if (configuration_client_model_operation.action_type->count != 0) { + if (strcmp(configuration_client_model_operation.action_type->sval[0], "get") == 0) { + err = esp_ble_mesh_config_client_get_state(&client_common, &get_state); + } else if (strcmp(configuration_client_model_operation.action_type->sval[0], "set") == 0) { + if (configuration_client_model_operation.set_state->count != 0) { + if (strcmp(configuration_client_model_operation.set_state->sval[0], "appkey") == 0) { + app_key = esp_ble_mesh_provisioner_get_local_app_key(app_key_add.net_idx, app_key_add.app_idx); + if (app_key == NULL) { + ESP_LOGE(TAG, "CnfClient:AddAppkey,Fail,app key or network key NULL"); + return ESP_FAIL; + } else { + memcpy(app_key_add.app_key, app_key, 16); + } + err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&app_key_add); + } else if (strcmp(configuration_client_model_operation.set_state->sval[0], "appbind") == 0) { + err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&mod_app_bind); + } else if (strcmp(configuration_client_model_operation.set_state->sval[0], "ttl") == 0) { + err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&ttl_set); + } else if (strcmp(configuration_client_model_operation.set_state->sval[0], "proxy") == 0) { + err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&proxy_set); + } else if (strcmp(configuration_client_model_operation.set_state->sval[0], "subadd") == 0) { + err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&mod_sub_add); + } else if (strcmp(configuration_client_model_operation.set_state->sval[0], "subdel") == 0) { + err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&mod_sub_del); + } else if (strcmp(configuration_client_model_operation.set_state->sval[0], "relay") == 0) { + err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&relay_set); + } else if (strcmp(configuration_client_model_operation.set_state->sval[0], "pubset") == 0) { + err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&mod_pub_set); + } + } + } else if (strcmp(configuration_client_model_operation.action_type->sval[0], "reg") == 0) { + err = esp_ble_mesh_register_config_client_callback(ble_mesh_configuration_client_model_cb); + } + } + + if (err == ESP_OK) { + ESP_LOGI(TAG, "ConfigClient:OK"); + } else { + ESP_LOGI(TAG, "ConfigClient:Fail"); + } + + ESP_LOGD(TAG, "exit %s %d\n", __func__, err); + return err; +} + + +void ble_mesh_register_configuration_client_model_command() +{ + configuration_client_model_operation.action_type = arg_str1("z", NULL, "", "action type"); + configuration_client_model_operation.set_state = arg_str0("x", NULL, "", "set state"); + configuration_client_model_operation.opcode = arg_int0("o", NULL, "", "message opcode"); + configuration_client_model_operation.unicast_address = arg_int0("u", NULL, "

", "unicast address"); + configuration_client_model_operation.net_idx = arg_int0("n", NULL, "", "net work index"); + configuration_client_model_operation.appkey_index = arg_int0("i", NULL, "", "appkey index"); + configuration_client_model_operation.relay_statue = arg_int0("r", NULL, "", "relay statue"); + configuration_client_model_operation.relay_transmit = arg_int0("t", NULL, "", "relay transmit"); + configuration_client_model_operation.cid = arg_int0("c", NULL, "", "company id"); + configuration_client_model_operation.value = arg_int0("v", NULL, "", "value"); + configuration_client_model_operation.addr = arg_int0("a", NULL, "
", "address"); + configuration_client_model_operation.mod_id = arg_int0("m", NULL, "", "model id"); + configuration_client_model_operation.end = arg_end(1); + + const esp_console_cmd_t client_stconfiguration_client_model_operationate_cmd = { + .command = "bmccm", + .help = "ble mesh configuration client model", + .hint = NULL, + .func = &ble_mesh_configuration_client_model_operation, + .argtable = &configuration_client_model_operation, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&client_stconfiguration_client_model_operationate_cmd)); +} +#endif diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_gen_onoff_client_cmd.c b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_gen_onoff_client_cmd.c new file mode 100644 index 0000000000..70a28162f7 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_gen_onoff_client_cmd.c @@ -0,0 +1,180 @@ +// Copyright 2017-2018 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 "esp_timer.h" +#include "ble_mesh_adapter.h" + +#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI) +typedef struct { + struct arg_str *action_type; + struct arg_int *op_en; + struct arg_int *unicast_address; + struct arg_int *onoff_state; + struct arg_int *trans_id; + struct arg_int *trans_time; + struct arg_int *delay; + struct arg_int *opcode; + struct arg_int *appkey_idx; + struct arg_int *role; + struct arg_int *net_idx; + struct arg_end *end; +} ble_mesh_gen_onoff_state_t; +ble_mesh_gen_onoff_state_t gen_onoff_state; + +void ble_mesh_register_gen_onoff_client_command(); +void ble_mesh_generic_onoff_client_model_cb(esp_ble_mesh_generic_client_cb_event_t event, + esp_ble_mesh_generic_client_cb_param_t *param); + +void ble_mesh_register_gen_onoff_client() +{ + ble_mesh_register_gen_onoff_client_command(); +} + +void ble_mesh_generic_onoff_client_model_cb(esp_ble_mesh_generic_client_cb_event_t event, + esp_ble_mesh_generic_client_cb_param_t *param) +{ + uint32_t opcode = param->params->opcode; + + ESP_LOGD(TAG, "enter %s: event is %d, error code is %d, opcode is 0x%x\n", + __func__, event, param->error_code, opcode); + + switch (event) { + case ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT: { + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET: + if (param->error_code == ESP_OK) { + ESP_LOGI(TAG, "GenOnOffClient:GetStatus,OK,%d", param->status_cb.onoff_status.present_onoff); + } else { + ESP_LOGE(TAG, "GenOnOffClient:GetStatus,Fail,%d", param->error_code); + } + break; + default: + break; + } + break; + } + case ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT: { + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: + if (param->error_code == ESP_OK) { + ESP_LOGI(TAG, "GenOnOffClient:SetStatus,OK,%d", param->status_cb.onoff_status.present_onoff); + } else { + ESP_LOGE(TAG, "GenOnOffClient:SetStatus,Fail,%d", param->error_code); + } + break; + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK: + if (param->error_code == ESP_OK) { + ESP_LOGI(TAG, "GenOnOffClient:SetUNACK,OK"); + } else { + ESP_LOGE(TAG, "GenOnOffClient:SetUNACK,Fail,%d", param->error_code); + } + break; + default: + break; + } + break; + } + case ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT: { + if (param->error_code == ESP_OK) { + ESP_LOGI(TAG, "GenOnOffClient:Publish,OK"); + } else { + ESP_LOGE(TAG, "GenOnOffClient:Publish,Fail,%d", param->error_code); + } + break; + } + case ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT: + ESP_LOGE(TAG, "GenOnOffClient:TimeOut,%d", param->error_code); + break; + case ESP_BLE_MESH_GENERIC_CLIENT_EVT_MAX: + ESP_LOGE(TAG, "GenONOFFClient:InvalidEvt,%d", param->error_code); + break; + default: + break; + } + ESP_LOGD(TAG, "exit %s \n", __func__); +} + +int ble_mesh_generic_onoff_client_model(int argc, char **argv) +{ + int err = ESP_OK; + esp_ble_mesh_generic_client_set_state_t gen_client_set; + esp_ble_mesh_generic_client_get_state_t gen_client_get; + esp_ble_mesh_client_common_param_t onoff_common = { + .msg_timeout = 0, + .ctx.send_ttl = 7, + }; + + ESP_LOGD(TAG, "enter %s\n", __func__); + + int nerrors = arg_parse(argc, argv, (void **) &gen_onoff_state); + if (nerrors != 0) { + arg_print_errors(stderr, gen_onoff_state.end, argv[0]); + return 1; + } + + onoff_common.model = ble_mesh_get_model(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI); + + arg_int_to_value(gen_onoff_state.appkey_idx, onoff_common.ctx.app_idx, "appkey_index"); + arg_int_to_value(gen_onoff_state.opcode, onoff_common.opcode, "opcode"); + arg_int_to_value(gen_onoff_state.role, onoff_common.msg_role, "role"); + arg_int_to_value(gen_onoff_state.unicast_address, onoff_common.ctx.addr, "address"); + arg_int_to_value(gen_onoff_state.net_idx, onoff_common.ctx.net_idx, "network key index"); + arg_int_to_value(gen_onoff_state.op_en, gen_client_set.onoff_set.op_en, "op_en"); + arg_int_to_value(gen_onoff_state.onoff_state, gen_client_set.onoff_set.onoff, "onoff"); + arg_int_to_value(gen_onoff_state.trans_id, gen_client_set.onoff_set.tid, "tid"); + arg_int_to_value(gen_onoff_state.trans_time, gen_client_set.onoff_set.trans_time, "trans_time"); + arg_int_to_value(gen_onoff_state.delay, gen_client_set.onoff_set.delay, "delay"); + + if (gen_onoff_state.action_type->count != 0) { + if (strcmp(gen_onoff_state.action_type->sval[0], "get") == 0) { + err = esp_ble_mesh_generic_client_get_state(&onoff_common, &gen_client_get); + } else if (strcmp(gen_onoff_state.action_type->sval[0], "set") == 0) { + err = esp_ble_mesh_generic_client_set_state(&onoff_common, &gen_client_set); + } else if (strcmp(gen_onoff_state.action_type->sval[0], "reg") == 0) { + err = esp_ble_mesh_register_generic_client_callback(ble_mesh_generic_onoff_client_model_cb); + if (err == ESP_OK) { + ESP_LOGI(TAG, "GenONOFFClient:Reg,OK"); + } + } + } + ESP_LOGD(TAG, "exit %s\n", __func__); + return err; +} + +void ble_mesh_register_gen_onoff_client_command() +{ + gen_onoff_state.action_type = arg_str1("z", NULL, "", "action type"); + gen_onoff_state.opcode = arg_int0("o", NULL, "", "message opcode"); + gen_onoff_state.appkey_idx = arg_int0("a", NULL, "", "appkey index"); + gen_onoff_state.role = arg_int0("r", NULL, "", "role"); + gen_onoff_state.unicast_address = arg_int0("u", NULL, "
", "unicast address"); + gen_onoff_state.net_idx = arg_int0("n", NULL, "", "network key index"); + gen_onoff_state.op_en = arg_int0("e", NULL, "", "whether optional parameters included"); + gen_onoff_state.onoff_state = arg_int0("s", NULL, "", "present onoff state"); + gen_onoff_state.trans_id = arg_int0("i", NULL, "", "transaction identifier"); + gen_onoff_state.trans_time = arg_int0("t", NULL, "
", "unicast address"); + test_perf_client_model.ttl = arg_int0("t", NULL, "", "ttl"); + test_perf_client_model.app_idx = arg_int0("a", NULL, "", "appkey index"); + test_perf_client_model.net_idx = arg_int0("i", NULL, "", "network key index"); + test_perf_client_model.dev_role = arg_int0("d", NULL, "", "device role"); + test_perf_client_model.dev_role->ival[0] = ROLE_PROVISIONER; + test_perf_client_model.end = arg_end(1); + + const esp_console_cmd_t test_perf_client_model_cmd = { + .command = "bmtpcvm", + .help = "ble mesh test performance client vendor model", + .hint = NULL, + .func = &ble_mesh_test_performance_client_model, + .argtable = &test_perf_client_model, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&test_perf_client_model_cmd)); + + test_perf_client_model_statistics.action_type = arg_str1("z", NULL, "", "action type"); + test_perf_client_model_statistics.test_size = arg_int0("s", NULL, "", "test size"); + test_perf_client_model_statistics.node_num = arg_int0("n", NULL, "", "node number"); + test_perf_client_model_statistics.ttl = arg_int0("l", NULL, "", "ttl"); + test_perf_client_model_statistics.end = arg_end(1); + + const esp_console_cmd_t test_perf_client_model_performance_cmd = { + .command = "bmcperf", + .help = "ble mesh client: test performance", + .hint = NULL, + .func = &ble_mesh_test_performance_client_model_performance, + .argtable = &test_perf_client_model_statistics, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&test_perf_client_model_performance_cmd)); +} diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c new file mode 100644 index 0000000000..57e89605c9 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c @@ -0,0 +1,476 @@ +// Copyright 2017-2018 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 "soc/soc.h" +#include "esp_bt.h" +#include "esp_bt_device.h" + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_common_api.h" +#include "esp_ble_mesh_provisioning_api.h" +#include "esp_ble_mesh_networking_api.h" +#include "esp_ble_mesh_config_model_api.h" + +#include "ble_mesh_adapter.h" + +typedef struct { + struct arg_str *static_val; + struct arg_int *static_val_len; + struct arg_int *output_size; + struct arg_int *output_actions; + struct arg_int *input_size; + struct arg_int *input_actions; + struct arg_int *prov_start_address; + struct arg_end *end; +} ble_mesh_prov_t; +static ble_mesh_prov_t oob; + +typedef struct { + struct arg_int *model_type; + struct arg_int *config_index; + struct arg_int *pub_config; + struct arg_end *end; +} ble_mesh_comp_t; +static ble_mesh_comp_t component; + +typedef struct { + struct arg_int *bearer; + struct arg_int *enable; + struct arg_end *end; +} ble_mesh_bearer_t; +static ble_mesh_bearer_t bearer; + +typedef struct { + struct arg_str *action_type; + struct arg_int *tx_sense_power; + struct arg_end *end; +} ble_mesh_tx_sense_power; +static ble_mesh_tx_sense_power power_set; + +ble_mesh_node_status node_status = { + .previous = 0x0, + .current = 0x0, +}; + +SemaphoreHandle_t ble_mesh_node_sema; + +void ble_mesh_register_node_cmd(); +// Register callback function +void ble_mesh_prov_cb(esp_ble_mesh_prov_cb_event_t event, esp_ble_mesh_prov_cb_param_t *param); +void ble_mesh_model_cb(esp_ble_mesh_model_cb_event_t event, esp_ble_mesh_model_cb_param_t *param); + + +void ble_mesh_register_mesh_node() +{ + ble_mesh_register_node_cmd(); +} + +int ble_mesh_register_node_cb() +{ + ESP_LOGD(TAG, "enter %s\n", __func__); + ble_mesh_node_init(); + esp_ble_mesh_register_prov_callback(ble_mesh_prov_cb); + esp_ble_mesh_register_custom_model_callback(ble_mesh_model_cb); + ESP_LOGI(TAG, "Node:Reg,OK"); + ESP_LOGD(TAG, "exit %s\n", __func__); + return 0; +} + +void ble_mesh_prov_cb(esp_ble_mesh_prov_cb_event_t event, esp_ble_mesh_prov_cb_param_t *param) +{ + ESP_LOGD(TAG, "enter %s, event = %d", __func__, event); + switch (event) { + case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT: + ble_mesh_callback_check_err_code(param->prov_register_comp.err_code, "Provisioning:Register"); + break; + case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_prov_enable_comp.err_code, "Node:EnBearer"); + break; + case ESP_BLE_MESH_NODE_PROV_DISABLE_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_prov_disable_comp.err_code, "Node:DisBearer"); + break; + case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT: + ESP_LOGI(TAG, "Node:LinkOpen,OK,%d", param->node_prov_link_open.bearer); + break; + case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT: + ESP_LOGI(TAG, "Node:LinkClose,OK,%d", param->node_prov_link_close.bearer); + break; + case ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT: + ESP_LOGI(TAG, "Node:OutPut,%d,%d", param->node_prov_output_num.action, param->node_prov_output_num.number); + break; + case ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT: + ESP_LOGI(TAG, "Node:OutPutStr,%s", param->node_prov_output_str.string); + break; + case ESP_BLE_MESH_NODE_PROV_INPUT_EVT: + ESP_LOGI(TAG, "Node:InPut,%d,%d", param->node_prov_input.action, param->node_prov_input.size); + break; + case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT: + ESP_LOGI(TAG, "Node:OK,%d,%d", param->node_prov_complete.net_idx, param->node_prov_complete.addr); + ble_mesh_set_node_prestore_params(param->node_prov_complete.net_idx, param->node_prov_complete.addr); + break; + case ESP_BLE_MESH_NODE_PROV_RESET_EVT: + ESP_LOGI(TAG, "Node:Reset"); + break; + case ESP_BLE_MESH_NODE_PROV_INPUT_NUMBER_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_prov_input_num_comp.err_code, "Node:InputNum"); + break; + case ESP_BLE_MESH_NODE_PROV_INPUT_STRING_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_prov_input_str_comp.err_code, "Node:InputStr"); + break; + case ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_set_unprov_dev_name_comp.err_code, "Node:SetName"); + break; + case ESP_BLE_MESH_NODE_PROXY_IDENTITY_ENABLE_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_proxy_identity_enable_comp.err_code, "Node:ProxyIndentity"); + break; + case ESP_BLE_MESH_NODE_PROXY_GATT_ENABLE_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_proxy_gatt_enable_comp.err_code, "Node:EnProxyGatt"); + break; + case ESP_BLE_MESH_NODE_PROXY_GATT_DISABLE_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_proxy_gatt_disable_comp.err_code, "Node:DisProxyGatt"); + break; +#if (CONFIG_BLE_MESH_PROVISIONER) + case ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT: + ESP_LOGI(TAG, "Provisioner recv unprovisioned device beacon:"); + ESP_LOG_BUFFER_HEX("Device UUID %s", param->provisioner_recv_unprov_adv_pkt.dev_uuid, 16); + ESP_LOG_BUFFER_HEX("Address %s", param->provisioner_recv_unprov_adv_pkt.addr, 6); + ESP_LOGI(TAG, "Address type 0x%x, oob_info 0x%04x, adv_type 0x%x, bearer 0x%x", + param->provisioner_recv_unprov_adv_pkt.addr_type, param->provisioner_recv_unprov_adv_pkt.oob_info, + param->provisioner_recv_unprov_adv_pkt.adv_type, param->provisioner_recv_unprov_adv_pkt.bearer); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT: + ESP_LOGI(TAG, "Provisioner:LinkOpen,OK,%d", param->provisioner_prov_link_open.bearer); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT: + ESP_LOGI(TAG, "Provisioner:LinkClose,OK,%d,%d", + param->provisioner_prov_link_close.bearer, param->provisioner_prov_link_close.reason); + break; + case ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT: + ble_mesh_callback_check_err_code(param->provisioner_add_unprov_dev_comp.err_code, "Provisioner:DevAdd"); + break; + case ESP_BLE_MESH_PROVISIONER_DELETE_DEV_COMP_EVT: + ble_mesh_callback_check_err_code(param->provisioner_delete_dev_comp.err_code, "Provisioner:DevDel"); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT: + ESP_LOGI(TAG, "Provisioner:OK,%d,%d", param->provisioner_prov_complete.netkey_idx, param->provisioner_prov_complete.unicast_addr); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT: + ble_mesh_callback_check_err_code(param->provisioner_prov_enable_comp.err_code, "Provisioner:EnBearer"); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_DISABLE_COMP_EVT: + ble_mesh_callback_check_err_code(param->provisioner_prov_disable_comp.err_code, "Provisioner:DisBearer"); + break; + case ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT: + ble_mesh_callback_check_err_code(param->provisioner_set_dev_uuid_match_comp.err_code, "Provisioner:UuidMatch"); + break; + case ESP_BLE_MESH_PROVISIONER_SET_PROV_DATA_INFO_COMP_EVT: + ble_mesh_callback_check_err_code(param->provisioner_set_prov_data_info_comp.err_code, "Provisioner:DataInfo"); + break; + case ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT: + ble_mesh_callback_check_err_code(param->provisioner_set_node_name_comp.err_code, "Provisioner:NodeName"); + break; + case ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT: + ble_mesh_callback_check_err_code(param->provisioner_add_app_key_comp.err_code, "Provisioner:AppKeyAdd"); + break; + case ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT: + ble_mesh_callback_check_err_code(param->provisioner_bind_app_key_to_model_comp.err_code, "Provisioner:AppKeyBind"); + break; + case ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_NET_KEY_COMP_EVT: + ble_mesh_callback_check_err_code(param->provisioner_add_net_key_comp.err_code, "Provisioner:NetKeyAdd"); + break; +#endif + default: + break; + } + ESP_LOGD(TAG, "exit %s\n", __func__); +} + +void ble_mesh_model_cb(esp_ble_mesh_model_cb_event_t event, esp_ble_mesh_model_cb_param_t *param) +{ + esp_err_t result = ESP_OK; + uint8_t status; + + ESP_LOGD(TAG, "enter %s, event=%x\n", __func__, event); + + switch (event) { + case ESP_BLE_MESH_MODEL_OPERATION_EVT: + if (param->model_operation.model != NULL && param->model_operation.model->op != NULL) { + if (param->model_operation.opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET) { + ESP_LOGI(TAG, "Node:GetStatus,OK"); + ble_mesh_node_get_state(status); + result = esp_ble_mesh_server_model_send_msg(param->model_operation.model, param->model_operation.ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, + sizeof(status), &status); + } else if (param->model_operation.opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) { + ble_mesh_node_set_state(param->model_operation.msg[0]); + ESP_LOGI(TAG, "Node:SetAck,OK,%d,%d", param->model_operation.msg[0], param->model_operation.ctx->recv_ttl); + result = esp_ble_mesh_server_model_send_msg(param->model_operation.model, param->model_operation.ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, + sizeof(status), param->model_operation.msg); + } else if (param->model_operation.opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK) { + ble_mesh_node_set_state(param->model_operation.msg[0]); + ESP_LOGI(TAG, "Node:SetUnAck,OK,%d,%d", param->model_operation.msg[0], param->model_operation.ctx->recv_ttl); + } else if (param->model_operation.opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS) { + ESP_LOGI(TAG, "Node:Status,Success,%d", param->model_operation.length); + } else if (param->model_operation.opcode == ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET) { + ESP_LOGI(TAG, "VendorModel:SetAck,OK,%d", param->model_operation.ctx->recv_ttl); + } else if (param->model_operation.opcode == ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS) { + uint64_t current_time = esp_timer_get_time(); + result = ble_mesh_test_performance_client_model_accumulate_time(((uint32_t)(current_time - start_time) / 1000), param->model_operation.msg, param->model_operation.ctx->recv_ttl, param->model_operation.length); + ESP_LOGI(TAG, "VendorModel:Status,OK,%d", param->model_operation.ctx->recv_ttl); + if (ble_mesh_test_perf_send_sema != NULL && result == ESP_OK) { + xSemaphoreGive(ble_mesh_test_perf_send_sema); + } + } + } + break; + case ESP_BLE_MESH_MODEL_SEND_COMP_EVT: + if (param->model_send_comp.err_code == ESP_OK) { + ESP_LOGI(TAG, "Node:ModelSend,OK"); + } else { + ESP_LOGE(TAG, "Node:ModelSend,Fail,%d,0x%X,0x%04X", param->model_send_comp.err_code, param->model_send_comp.model->model_id, param->model_send_comp.model->op->opcode); + } + break; + case ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT: + ESP_LOGI(TAG, "Node:PublishSend,OK,0x%X,%d", param->model_publish_comp.model->model_id, param->model_publish_comp.model->pub->msg->len); + break; + case ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT: + ESP_LOGI(TAG, "Node:PublishReceive,OK,0x%04X,%d,%d", param->client_recv_publish_msg.opcode, param->client_recv_publish_msg.length, param->client_recv_publish_msg.msg[1]); + uint64_t current_time = esp_timer_get_time(); + result = ble_mesh_test_performance_client_model_accumulate_time(((uint32_t)(current_time - start_time) / 2000), param->client_recv_publish_msg.msg, param->client_recv_publish_msg.ctx->recv_ttl, param->client_recv_publish_msg.length); + if (ble_mesh_test_perf_send_sema != NULL && param->client_recv_publish_msg.msg[2] == VENDOR_MODEL_PERF_OPERATION_TYPE_SET_UNACK && result == ESP_OK) { + xSemaphoreGive(ble_mesh_test_perf_send_sema); + } + break; + case ESP_BLE_MESH_MODEL_PUBLISH_UPDATE_EVT: + ESP_LOGI(TAG, "Node:PublishUpdate,OK"); + break; + case ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT: + ESP_LOGI(TAG, "Node:TimeOut, 0x%04X", param->client_send_timeout.opcode); + if (ble_mesh_test_perf_send_sema != NULL) { + xSemaphoreGive(ble_mesh_test_perf_send_sema); + } + break; + case ESP_BLE_MESH_MODEL_EVT_MAX: + ESP_LOGI(TAG, "Node:MaxEvt"); + break; + default: + break; + } + + ESP_LOGD(TAG, "exit %s\n", __func__); +} + +int ble_mesh_power_set(int argc, char **argv) +{ + esp_err_t result = ESP_OK; + int nerrors = arg_parse(argc, argv, (void **) &power_set); + + ESP_LOGD(TAG, "enter %s\n", __func__); + + if (nerrors != 0) { + arg_print_errors(stderr, power_set.end, argv[0]); + return 1; + } + + if (strcmp(power_set.action_type->sval[0], "tx") == 0) { + result = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, power_set.tx_sense_power->ival[0]); + } else if (strcmp(power_set.action_type->sval[0], "sense") == 0) { + uint32_t *reg = (uint32_t *)(0x6001c07c); + int reg_addr = 0x6001c07c; + uint32_t flag = 0x00FF0000; + uint32_t sense_new = power_set.tx_sense_power->ival[0]; + uint32_t reg_to_write = ((*reg) &= ~flag) | ((256 - sense_new) << 16); + REG_WRITE(reg_addr, reg_to_write); + + } + + if (result == ESP_OK) { + ESP_LOGI(TAG, "Node:SetPower,OK\n"); + } + + ESP_LOGD(TAG, "exit %s\n", __func__); + return result; +} + +static int ble_mesh_load_oob(int argc, char **argv) +{ + uint8_t *static_val; + + ESP_LOGD(TAG, "enter %s \n", __func__); + + int nerrors = arg_parse(argc, argv, (void **) &oob); + if (nerrors != 0) { + arg_print_errors(stderr, oob.end, argv[0]); + return 1; + } + + //parsing prov +#if CONFIG_BLE_MESH_NODE + prov.uuid = dev_uuid; + memcpy(dev_uuid, esp_bt_dev_get_address(), 6); + if (oob.static_val->count != 0) { + static_val = malloc(oob.static_val_len->ival[0] + 1); + if (static_val == NULL) { + ESP_LOGE(TAG, "malloc fail,%s,%d\n", __func__, __LINE__); + } + get_value_string((char *)oob.static_val->sval[0], (char *)static_val); + prov.static_val = static_val; + } + + arg_int_to_value(oob.static_val_len, prov.static_val_len, "static value length"); + arg_int_to_value(oob.output_size, prov.output_size, "output size"); + arg_int_to_value(oob.output_actions, prov.output_actions, "output actions"); + arg_int_to_value(oob.input_size, prov.input_size, "input size"); + arg_int_to_value(oob.input_actions, prov.input_actions, "input actions"); +#endif + +#if CONFIG_BLE_MESH_PROVISIONER + if (oob.static_val->count != 0) { + static_val = malloc(oob.static_val_len->ival[0] + 1); + if (static_val == NULL) { + ESP_LOGE(TAG, "malloc fail,%s,%d\n", __func__, __LINE__); + } + get_value_string((char *)oob.static_val->sval[0], (char *)static_val); + prov.prov_static_oob_val = static_val; + } + arg_int_to_value(oob.prov_start_address, prov.prov_start_address, "provisioner start address"); + arg_int_to_value(oob.static_val_len, prov.prov_static_oob_len, "provisioner static value length"); +#endif + + ESP_LOGI(TAG, "OOB:Load,OK\n"); + + ESP_LOGD(TAG, "exit %s\n", __func__); + return 0; +} + + +int ble_mesh_init(int argc, char **argv) +{ + int err; + esp_ble_mesh_comp_t *local_component = NULL; + + int nerrors = arg_parse(argc, argv, (void **) &component); + if (nerrors != 0) { + arg_print_errors(stderr, component.end, argv[0]); + return 1; + } + + ESP_LOGD(TAG, "enter %s, module %x\n", __func__, component.model_type->ival[0]); + local_component = ble_mesh_get_component(component.model_type->ival[0]); + + + err = esp_ble_mesh_init(&prov, local_component); + if (err) { + ESP_LOGE(TAG, "Initializing mesh failed (err %d)\n", err); + return err; + } + + ESP_LOGD(TAG, "exit %s\n", __func__); + return err; +} + +int ble_mesh_provisioner_enable_bearer(int argc, char **argv) +{ + esp_err_t err = 0; + + ESP_LOGD(TAG, "enter %s \n", __func__); + + int nerrors = arg_parse(argc, argv, (void **) &bearer); + if (nerrors != 0) { + arg_print_errors(stderr, bearer.end, argv[0]); + return 1; + } + + if (bearer.enable->count != 0) { + if (bearer.enable->ival[0]) { + err = esp_ble_mesh_provisioner_prov_enable(bearer.bearer->ival[0]); + } else { + err = esp_ble_mesh_provisioner_prov_disable(bearer.bearer->ival[0]); + } + } else { + return 1; + } + + ESP_LOGD(TAG, "exit %s\n", __func__); + return err; +} + +void ble_mesh_register_node_cmd() +{ + const esp_console_cmd_t register_cmd = { + .command = "bmreg", + .help = "ble mesh: provisioner/node register callback", + .hint = NULL, + .func = &ble_mesh_register_node_cb, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(®ister_cmd)); + oob.static_val = arg_str0("s", NULL, "", "Static OOB value"); + oob.static_val_len = arg_int0("l", NULL, "", "Static OOB value length"); + oob.output_size = arg_int0("x", NULL, "", "Maximum size of Output OOB"); + oob.output_actions = arg_int0("o", NULL, "", "Supported Output OOB Actions"); + oob.input_size = arg_int0("y", NULL, "", "Maximum size of Input OOB"); + oob.input_actions = arg_int0("i", NULL, "", "Supported Input OOB Actions"); + oob.prov_start_address = arg_int0("p", NULL, "
", "start address assigned by provisioner"); + oob.prov_start_address->ival[0] = 0x0005; + oob.end = arg_end(1); + + const esp_console_cmd_t oob_cmd = { + .command = "bmoob", + .help = "ble mesh: provisioner/node config OOB parameters", + .hint = NULL, + .func = &ble_mesh_load_oob, + .argtable = &oob, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&oob_cmd) ); + + component.model_type = arg_int0("m", NULL, "", "mesh model"); + component.config_index = arg_int0("c", NULL, "", "mesh model op"); + component.config_index->ival[0] = 0; // set default value + component.pub_config = arg_int0("p", NULL, "", "publish message buffer"); + component.end = arg_end(1); + + const esp_console_cmd_t model_cmd = { + .command = "bminit", + .help = "ble mesh: provisioner/node init", + .hint = NULL, + .func = &ble_mesh_init, + .argtable = &component, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&model_cmd) ); + + bearer.bearer = arg_int0("b", NULL, "", "supported bearer"); + bearer.enable = arg_int0("e", NULL, "", "bearers node supported"); + bearer.end = arg_end(1); + + const esp_console_cmd_t bearer_cmd = { + .command = "bmpbearer", + .help = "ble mesh provisioner: enable/disable different bearers", + .hint = NULL, + .func = &ble_mesh_provisioner_enable_bearer, + .argtable = &bearer, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&bearer_cmd)); + + power_set.tx_sense_power = arg_int0("t", NULL, "", "tx power or sense"); + power_set.action_type = arg_str1("z", NULL, "", "action type"); + power_set.end = arg_end(1); + + const esp_console_cmd_t power_set_cmd = { + .command = "bmtxpower", + .help = "ble mesh: set tx power or sense", + .hint = NULL, + .func = &ble_mesh_power_set, + .argtable = &power_set, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&power_set_cmd)); +} diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c new file mode 100644 index 0000000000..c5a2d3ad1b --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c @@ -0,0 +1,424 @@ +// Copyright 2017-2018 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 "esp_bt_defs.h" + +#include "provisioner_prov.h" +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_networking_api.h" +#include "esp_ble_mesh_provisioning_api.h" +#include "esp_ble_mesh_config_model_api.h" + +#include "ble_mesh_adapter.h" +#include "ble_mesh_console_decl.h" + +#if CONFIG_BLE_MESH_PROVISIONER + +typedef struct { + struct arg_int *bearer; + struct arg_int *enable; + struct arg_end *end; +} ble_mesh_provisioner_bearer_t; +ble_mesh_provisioner_bearer_t provisioner_bearer; + +typedef struct { + struct arg_str *add_del; + struct arg_str *device_addr; + struct arg_str *device_uuid; + struct arg_int *addr_type; + struct arg_int *bearer; + struct arg_int *oob_info; + struct arg_int *flag; + struct arg_end *end; +} ble_mesh_provisioner_addr_t; +ble_mesh_provisioner_addr_t provisioner_addr; + +typedef struct { + struct arg_int *unicast_addr; + struct arg_end *end; +} ble_mesh_provisioner_get_node_t; +ble_mesh_provisioner_get_node_t provisioner_get_node; + +typedef struct { + struct arg_int *oob_info; + struct arg_int *unicast_addr; + struct arg_int *element_num; + struct arg_int *net_idx; + struct arg_str *dev_key; + struct arg_str *uuid; + struct arg_end *end; +} ble_mesh_provisioner_add_node_t; +ble_mesh_provisioner_add_node_t provisioner_add_node; + +typedef struct { + struct arg_int *appkey_index; + struct arg_int *element_address; + struct arg_int *network_index; + struct arg_int *mod_id; + struct arg_int *cid; + struct arg_end *end; +} ble_mesh_provisioner_bind_model_t; +ble_mesh_provisioner_bind_model_t provisioner_local_bind; + +typedef struct { + struct arg_str *action_type; + struct arg_int *net_idx; + struct arg_int *app_idx; + struct arg_str *key; + struct arg_end *end; +} ble_mesh_provisioner_add_key_t; +ble_mesh_provisioner_add_key_t provisioner_add_key; + +void ble_mesh_regist_provisioner_cmd(); + +void ble_mesh_prov_adv_cb(const esp_bd_addr_t addr, const esp_ble_addr_type_t addr_type, const uint8_t adv_type, + const uint8_t *dev_uuid, uint16_t oob_info, esp_ble_mesh_prov_bearer_t bearer); + +void ble_mesh_register_mesh_provisioner() +{ + ble_mesh_regist_provisioner_cmd(); +} + +void ble_mesh_prov_adv_cb(const esp_bd_addr_t addr, const esp_ble_addr_type_t addr_type, const uint8_t adv_type, + const uint8_t *dev_uuid, uint16_t oob_info, esp_ble_mesh_prov_bearer_t bearer) +{ + ESP_LOGD(TAG, "enter %s\n", __func__); + ESP_LOGI(TAG, "scan device address:"); + esp_log_buffer_hex(TAG, addr, sizeof(esp_bd_addr_t)); + ESP_LOGI(TAG, "scan device uuid:"); + esp_log_buffer_hex(TAG, dev_uuid, 16); + ESP_LOGD(TAG, "exit %s\n", __func__); +} + +int ble_mesh_provisioner_register() +{ + ESP_LOGD(TAG, "enter %s \n", __func__); + // esp_ble_mesh_register_unprov_adv_pkt_callback(ble_mesh_prov_adv_cb); + ESP_LOGI(TAG, "Provisioner:Reg,OK"); + ESP_LOGD(TAG, "exit %s \n", __func__); + return 0; +} + +int ble_mesh_provision_address(int argc, char **argv) +{ + esp_err_t err = ESP_OK; + esp_ble_mesh_unprov_dev_add_t device_addr = {0}; + uint8_t preset_addr_uuid[16] = {0x01, 0x02}; + esp_ble_mesh_device_delete_t del_dev = { + .flag = BIT(0), + }; + + ESP_LOGD(TAG, "enter %s \n", __func__); + + int nerrors = arg_parse(argc, argv, (void **) &provisioner_addr); + if (nerrors != 0) { + arg_print_errors(stderr, provisioner_addr.end, argv[0]); + return 1; + } + + if (provisioner_addr.device_addr->count != 0) { + if (provisioner_addr.device_uuid->count != 0) { + del_dev.flag = BIT(0) | BIT(1); + str_2_mac((uint8_t *)provisioner_addr.device_addr->sval[0], device_addr.uuid); + str_2_mac((uint8_t *)provisioner_addr.device_addr->sval[0], del_dev.uuid); + } else { + del_dev.flag = BIT(0); + memcpy(device_addr.uuid, preset_addr_uuid, 16); + memcpy(del_dev.uuid, preset_addr_uuid, 16); + } + str_2_mac((uint8_t *)provisioner_addr.device_addr->sval[0], device_addr.addr); + str_2_mac((uint8_t *)provisioner_addr.device_addr->sval[0], del_dev.addr); + arg_int_to_value(provisioner_addr.addr_type, device_addr.addr_type, "address type"); + arg_int_to_value(provisioner_addr.addr_type, del_dev.addr_type, "address type"); + } else if (provisioner_addr.device_uuid->count != 0) { + del_dev.flag = BIT(1); + memcpy(device_addr.addr, preset_addr_uuid, 6); + memcpy(del_dev.addr, preset_addr_uuid, 6); + str_2_mac((uint8_t *)provisioner_addr.device_addr->sval[0], device_addr.uuid); + str_2_mac((uint8_t *)provisioner_addr.device_addr->sval[0], del_dev.uuid); + } + + if (strcmp(provisioner_addr.add_del->sval[0], "add") == 0) { + arg_int_to_value(provisioner_addr.bearer, device_addr.bearer, "bearer"); + arg_int_to_value(provisioner_addr.oob_info, device_addr.oob_info, "oob information"); + err = esp_ble_mesh_provisioner_add_unprov_dev(&device_addr, provisioner_addr.flag->ival[0]); + } else if (strcmp(provisioner_addr.add_del->sval[0], "del") == 0) { + err = esp_ble_mesh_provisioner_delete_dev(&del_dev); + } + + ESP_LOGD(TAG, "exit %s \n", __func__); + return err; +} + +int ble_mesh_provisioner_bearer(int argc, char **argv) +{ + esp_err_t err; + + ESP_LOGD(TAG, "enter %s \n", __func__); + + int nerrors = arg_parse(argc, argv, (void **) &provisioner_bearer); + if (nerrors != 0) { + arg_print_errors(stderr, provisioner_bearer.end, argv[0]); + return 1; + } + + if (provisioner_bearer.enable->count != 0) { + if (provisioner_bearer.enable->ival[0]) { + err = esp_ble_mesh_provisioner_prov_enable(provisioner_bearer.bearer->ival[0]); + } else { + err = esp_ble_mesh_provisioner_prov_disable(provisioner_bearer.bearer->ival[0]); + } + } else { + return 1; + } + + ESP_LOGD(TAG, "exit %s \n", __func__); + return err; +} + +int ble_mesh_provisioner_get_node(int argc, char **argv) +{ + uint16_t unicast_addr = 0; + uint16_t i = 0; + struct bt_mesh_node_t *node_info; + + ESP_LOGD(TAG, "enter %s\n", __func__); + int nerrors = arg_parse(argc, argv, (void **) &provisioner_get_node); + if (nerrors != 0) { + arg_print_errors(stderr, provisioner_get_node.end, argv[0]); + return 1; + } + + arg_int_to_value(provisioner_get_node.unicast_addr, unicast_addr, "unicast address"); + node_info = bt_mesh_provisioner_get_node_info(unicast_addr); + + if (node_info == NULL) { + return ESP_FAIL; + } else { + printf("OobInfo:0x%x,Address:0x%x,EleNum:0x%x,NetIdx:0x%x,DevKey:", + node_info->oob_info, node_info->unicast_addr, node_info->element_num, node_info->net_idx); + for (i = 0; i < 16; i++) { + printf("%02x", node_info->dev_key[i]); + } + printf(",DevUuid:"); + for (i = 0; i < 16; i++) { + printf("%02x", node_info->dev_uuid[i]); + } + printf("\n"); + } + + ESP_LOGD(TAG, "exit %s\n", __func__); + return ESP_OK; +} + +int ble_mesh_provisioner_add_node(int argc, char **argv) +{ + struct bt_mesh_node_t node_info; + esp_err_t result; + ESP_LOGD(TAG, " enter %s\n", __func__); + + int nerrors = arg_parse(argc, argv, (void **) &provisioner_add_node); + if (nerrors != 0) { + arg_print_errors(stderr, provisioner_add_node.end, argv[0]); + return 1; + } + + arg_int_to_value(provisioner_add_node.oob_info, node_info.oob_info, "oob information"); + arg_int_to_value(provisioner_add_node.unicast_addr, node_info.unicast_addr, "unicast address"); + arg_int_to_value(provisioner_add_node.element_num, node_info.element_num, "element number"); + arg_int_to_value(provisioner_add_node.net_idx, node_info.net_idx, "network index"); + if (provisioner_add_node.dev_key->count != 0) { + get_value_string((char *)provisioner_add_node.dev_key->sval[0], (char *)node_info.dev_key); + } + if (provisioner_add_node.uuid->count != 0) { + get_value_string((char *)provisioner_add_node.uuid->sval[0], (char *)node_info.dev_uuid); + get_value_string((char *)provisioner_add_node.uuid->sval[0], (char *)node_info.dev_uuid); + } + + result = bt_mesh_provisioner_store_node_info(&node_info); + if (result == ESP_OK) { + ESP_LOGI(TAG, "Provisioner:AddNodeInfo,OK\n"); + } + + ESP_LOGD(TAG, "exit %s\n", __func__); + return result; +} + +int ble_mesh_provisioner_add_key(int argc, char **argv) +{ + esp_err_t err = ESP_OK; + uint8_t key[16] = {0}; + esp_ble_mesh_prov_data_info_t info = { + .net_idx = 1, + .flag = NET_IDX_FLAG, + }; + ESP_LOGD(TAG, " enter %s\n", __func__); + + int nerrors = arg_parse(argc, argv, (void **) &provisioner_add_key); + if (nerrors != 0) { + arg_print_errors(stderr, provisioner_add_key.end, argv[0]); + return 1; + } + + err = get_value_string((char *)provisioner_add_key.key->sval[0], (char *) key); + if (strcmp(provisioner_add_key.action_type->sval[0], "appkey") == 0) { + err = esp_ble_mesh_provisioner_add_local_app_key(key, provisioner_add_key.net_idx->ival[0], provisioner_add_key.app_idx->ival[0]); + } else if (strcmp(provisioner_add_key.action_type->sval[0], "netkey") == 0) { + // choose network key + info.net_idx = provisioner_add_key.net_idx->ival[0]; + err = esp_ble_mesh_provisioner_add_local_net_key(key, provisioner_add_key.net_idx->ival[0]); + err = err | esp_ble_mesh_provisioner_set_prov_data_info(&info); + } + + if (err != ESP_OK) { + ESP_LOGI(TAG, "Provisioner:KeyAction,Fail"); + } else { + ESP_LOGI(TAG, "Provisioner:KeyAction,OK"); + } + + ESP_LOGD(TAG, "exit %s\n", __func__); + return err; +} + +int ble_mesh_provision_bind_local_model(int argc, char **argv) +{ + esp_err_t err; + uint16_t element_addr = 0; + uint16_t app_idx = 0; + uint16_t model_id = 0; + uint16_t company_id = 0xFFFF; + + ESP_LOGD(TAG, " enter %s\n", __func__); + + int nerrors = arg_parse(argc, argv, (void **) &provisioner_local_bind); + if (nerrors != 0) { + arg_print_errors(stderr, provisioner_local_bind.end, argv[0]); + return 1; + } + + arg_int_to_value(provisioner_local_bind.element_address, element_addr, "element address"); + arg_int_to_value(provisioner_local_bind.appkey_index, app_idx, "appkey index"); + arg_int_to_value(provisioner_local_bind.mod_id, model_id, "model id"); + arg_int_to_value(provisioner_local_bind.cid, company_id, "company id"); + err = esp_ble_mesh_provisioner_bind_app_key_to_local_model(element_addr, app_idx, model_id, company_id); + + if (err != ESP_OK) { + ESP_LOGE(TAG, "Provisioner:BindModel,Fail,%x\n", err); + } else { + ESP_LOGI(TAG, "Provisioner:BindModel,OK\n"); + } + ESP_LOGD(TAG, "exit %s\n", __func__); + return err; +} + +void ble_mesh_regist_provisioner_cmd() +{ + const esp_console_cmd_t prov_register = { + .command = "bmpreg", + .help = "ble mesh provisioner: register callback", + .hint = NULL, + .func = &ble_mesh_provisioner_register, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&prov_register)); + + provisioner_addr.add_del = arg_str1("z", NULL, "", "action type"); + provisioner_addr.device_addr = arg_str0("d", NULL, "
", "device address"); + provisioner_addr.device_uuid = arg_str0("u", NULL, "", "device uuid"); + provisioner_addr.addr_type = arg_int0("a", NULL, "", "address type"); + provisioner_addr.flag = arg_int0("f", NULL, "", "address flag"); + provisioner_addr.flag->ival[0] = ADD_DEV_RM_AFTER_PROV_FLAG | ADD_DEV_FLUSHABLE_DEV_FLAG; + provisioner_addr.bearer = arg_int0("b", NULL, "", "used bearer"); + provisioner_addr.oob_info = arg_int0("o", NULL, "", "oob information"); + provisioner_addr.end = arg_end(1); + + const esp_console_cmd_t provisioner_addr_cmd = { + .command = "bmpdev", + .help = "ble mesh provisioner: add/delete unprovisioned device", + .hint = NULL, + .func = &ble_mesh_provision_address, + .argtable = &provisioner_addr, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&provisioner_addr_cmd)); + + provisioner_bearer.bearer = arg_int0("b", NULL, "", "bearer supported provisioner"); + provisioner_bearer.enable = arg_int0("e", NULL, "", "enable or disable bearer"); + provisioner_bearer.end = arg_end(1); + + const esp_console_cmd_t provisioner_bearer_cmd = { + .command = "bmpbearer", + .help = "ble mesh provisioner: enable/disable provisioner different bearer", + .hint = NULL, + .func = &ble_mesh_provisioner_bearer, + .argtable = &provisioner_bearer, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&provisioner_bearer_cmd)); + + provisioner_get_node.unicast_addr = arg_int1("u", NULL, "
", "get node by unicast address"); + provisioner_get_node.end = arg_end(1); + + const esp_console_cmd_t provisioner_get_node_cmd = { + .command = "bmpgetn", + .help = "ble mesh provisioner: get node", + .func = &ble_mesh_provisioner_get_node, + .argtable = &provisioner_get_node, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&provisioner_get_node_cmd)); + + provisioner_add_node.oob_info = arg_int0("o", NULL, "", "oob information"); + provisioner_add_node.unicast_addr = arg_int0("a", NULL, "", "unicast address"); + provisioner_add_node.element_num = arg_int0("e", NULL, "", "element num"); + provisioner_add_node.net_idx = arg_int0("n", NULL, "", "net index"); + provisioner_add_node.dev_key = arg_str0("d", NULL, "", "device key"); + provisioner_add_node.uuid = arg_str0("u", NULL, "", "device uuid"); + provisioner_add_node.end = arg_end(1); + + const esp_console_cmd_t provisioner_add_node_cmd = { + .command = "bmpaddn", + .help = "ble mesh provisioner: add node", + .func = &ble_mesh_provisioner_add_node, + .argtable = &provisioner_add_node, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&provisioner_add_node_cmd)); + + provisioner_local_bind.appkey_index = arg_int1("a", NULL, "", "appkey index"); + provisioner_local_bind.element_address = arg_int1("e", NULL, "", "element address"); + provisioner_local_bind.network_index = arg_int1("n", NULL, "", "network index"); + provisioner_local_bind.mod_id = arg_int1("m", NULL, "", "model id"); + provisioner_local_bind.cid = arg_int0("c", NULL, "", "company id"); + provisioner_local_bind.end = arg_end(1); + + const esp_console_cmd_t provisioner_local_bind_cmd = { + .command = "bmpbind", + .help = "ble mesh provisioner: bind local model", + .func = &ble_mesh_provision_bind_local_model, + .argtable = &provisioner_local_bind, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&provisioner_local_bind_cmd)); + + provisioner_add_key.action_type = arg_str1("z", NULL, "", "add appkey or network key"); + provisioner_add_key.net_idx = arg_int1("n", NULL, "", "network key index"); + provisioner_add_key.key = arg_str1("k", NULL, "", "appkey or network"); + provisioner_add_key.app_idx = arg_int0("a", NULL, "", "appkey index"); + provisioner_add_key.end = arg_end(1); + + const esp_console_cmd_t provisioner_add_key_cmd = { + .command = "bmpkey", + .help = "ble mesh provisioner: key", + .func = &ble_mesh_provisioner_add_key, + .argtable = &provisioner_add_key, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&provisioner_add_key_cmd)); +} +#endif + diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/component.mk b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/component.mk new file mode 100644 index 0000000000..0b9d7585e7 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/component.mk @@ -0,0 +1,5 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) + diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/register_bluetooth.c b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/register_bluetooth.c new file mode 100644 index 0000000000..bcb548520f --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/register_bluetooth.c @@ -0,0 +1,45 @@ +// Copyright 2017-2018 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 "esp_bt_device.h" +#include "esp_console.h" + +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + +void register_ble_address(); + +void register_bluetooth() +{ + register_ble_address(); +} + +int bt_mac(int argc, char** argv) +{ + const uint8_t *mac = esp_bt_dev_get_address(); + printf("+BTMAC:"MACSTR"\n", MAC2STR(mac)); + return 0; +} + +void register_ble_address() +{ + const esp_console_cmd_t cmd = { + .command = "btmac", + .help = "BLE address", + .hint = NULL, + .func = (esp_console_cmd_func_t)&bt_mac, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&cmd)); +} + diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/sdkconfig.defaults b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/sdkconfig.defaults new file mode 100644 index 0000000000..9c0ad1b87c --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/sdkconfig.defaults @@ -0,0 +1,40 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y +CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY= +CONFIG_BTDM_CONTROLLER_MODE_BTDM= +CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n +CONFIG_BLE_SCAN_DUPLICATE=y +CONFIG_SCAN_DUPLICATE_TYPE=2 +CONFIG_DUPLICATE_SCAN_CACHE_SIZE=200 +CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y +CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE=200 +CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_HCI_5_0=y +CONFIG_BLE_MESH_USE_DUPLICATE_SCAN=y +CONFIG_BLE_MESH_PROV=y +CONFIG_BLE_MESH_PROVISIONER=y +CONFIG_BLE_MESH_WAIT_FOR_PROV_MAX_DEV_NUM=20 +CONFIG_BLE_MESH_MAX_PROV_NODES=20 +CONFIG_BLE_MESH_PBA_SAME_TIME=10 +CONFIG_BLE_MESH_PBG_SAME_TIME=4 +CONFIG_BLE_MESH_PROVISIONER_SUBNET_COUNT=3 +CONFIG_BLE_MESH_PROVISIONER_APP_KEY_COUNT=9 +CONFIG_BLE_MESH_PB_ADV=y +CONFIG_BLE_MESH_NET_BUF_POOL_USAGE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_GATT_PROXY=y +CONFIG_BLE_MESH_RELAY=y +CONFIG_BLE_MESH_LOW_POWER= +CONFIG_BLE_MESH_FRIEND= +CONFIG_BLE_MESH_MSG_CACHE_SIZE=10 +CONFIG_BLE_MESH_ADV_BUF_COUNT=60 +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=6 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=1 +CONFIG_BLE_MESH_RX_SDU_MAX=384 +CONFIG_BLE_MESH_TX_SEG_MAX=32 +CONFIG_BTU_TASK_STACK_SIZE=4512 +CONFIG_BLE_MESH_CFG_CLI=y +CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/CMakeLists.txt b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/CMakeLists.txt new file mode 100644 index 0000000000..df96eec280 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(ble_mesh_fast_prov_client) diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/Makefile b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/Makefile new file mode 100644 index 0000000000..06bba88878 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/Makefile @@ -0,0 +1,12 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := ble_mesh_fast_prov_client + +COMPONENT_ADD_INCLUDEDIRS := components/include + +EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components + +include $(IDF_PATH)/make/project.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/README.md b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/README.md new file mode 100644 index 0000000000..9e45f4f31b --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/README.md @@ -0,0 +1,2 @@ +ESP BLE Mesh Fast Provisioning Client Demo +======================== \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/CMakeLists.txt b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/CMakeLists.txt new file mode 100644 index 0000000000..3d3bc6f9a5 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/CMakeLists.txt @@ -0,0 +1,5 @@ +set(COMPONENT_SRCS "ble_mesh_demo_main.c") + +set(COMPONENT_ADD_INCLUDEDIRS ".") + +register_component() diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/ble_mesh_demo_main.c b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/ble_mesh_demo_main.c new file mode 100644 index 0000000000..3337277340 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/ble_mesh_demo_main.c @@ -0,0 +1,638 @@ +// Copyright 2017-2018 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 +#include + +#include "esp_system.h" +#include "esp_log.h" +#include "nvs_flash.h" + +#include "esp_bt.h" +#include "esp_bt_main.h" +#include "esp_bt_device.h" +#include "esp_gap_ble_api.h" +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_common_api.h" +#include "esp_ble_mesh_provisioning_api.h" +#include "esp_ble_mesh_networking_api.h" +#include "esp_ble_mesh_config_model_api.h" +#include "esp_ble_mesh_generic_model_api.h" + +#include "esp_fast_prov_common.h" +#include "esp_fast_prov_operation.h" +#include "esp_fast_prov_client_model.h" + +#define TAG "FAST_PROV_CLIENT_DEMO" + +#define PROV_OWN_ADDR 0x0001 +#define APP_KEY_OCTET 0x12 +#define GROUP_ADDRESS 0xC000 + +static uint8_t dev_uuid[16] = { 0xdd, 0xdd }; +static uint8_t match[] = { 0xdd, 0xdd }; + +static const esp_ble_mesh_client_op_pair_t fast_prov_cli_op_pair[] = { + { ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS }, + { ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS }, + { ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS }, +}; + +static esp_ble_mesh_cfg_srv_t config_server = { + .relay = ESP_BLE_MESH_RELAY_DISABLED, + .beacon = ESP_BLE_MESH_BEACON_ENABLED, +#if defined(CONFIG_BLE_MESH_FRIEND) + .friend_state = ESP_BLE_MESH_FRIEND_ENABLED, +#else + .friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED, +#endif +#if defined(CONFIG_BLE_MESH_GATT_PROXY) + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED, +#else + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED, +#endif + .default_ttl = 7, + /* 3 transmissions with a 20ms interval */ + .net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20), + .relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20), +}; +esp_ble_mesh_client_t config_client; +esp_ble_mesh_client_t gen_onoff_client; +esp_ble_mesh_client_t fast_prov_client = { + .op_pair_size = ARRAY_SIZE(fast_prov_cli_op_pair), + .op_pair = fast_prov_cli_op_pair, +}; + +static esp_ble_mesh_model_op_t fast_prov_cli_op[] = { + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS, 1), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS, 2), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS, 2), + ESP_BLE_MESH_MODEL_OP_END, +}; + +static esp_ble_mesh_model_t root_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&config_server), + ESP_BLE_MESH_MODEL_CFG_CLI(&config_client), + ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(NULL, &gen_onoff_client), +}; + +static esp_ble_mesh_model_t vnd_models[] = { + ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_CLI, + fast_prov_cli_op, NULL, &fast_prov_client), +}; + +static esp_ble_mesh_elem_t elements[] = { + ESP_BLE_MESH_ELEMENT(0, root_models, vnd_models), +}; + +static esp_ble_mesh_comp_t comp = { + .cid = CID_ESP, + .elements = elements, + .element_count = ARRAY_SIZE(elements), +}; + +static esp_ble_mesh_prov_t prov = { + .prov_uuid = dev_uuid, + .prov_unicast_addr = PROV_OWN_ADDR, + .prov_start_address = 0x0005, + .prov_attention = 0x00, + .prov_algorithm = 0x00, + .prov_pub_key_oob = 0x00, + .prov_static_oob_val = NULL, + .prov_static_oob_len = 0x00, + .flags = 0x00, + .iv_index = 0x00, +}; + +example_prov_info_t prov_info = { + .net_idx = ESP_BLE_MESH_KEY_PRIMARY, + .app_idx = ESP_BLE_MESH_KEY_PRIMARY, + .node_addr_cnt = 100, + .unicast_max = 0x7FFF, + .group_addr = GROUP_ADDRESS, + .max_node_num = 0x01, +}; + +static void provisioner_prov_link_open(esp_ble_mesh_prov_bearer_t bearer) +{ + ESP_LOGI(TAG, "%s link open", bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT"); +} + +static void provisioner_prov_link_close(esp_ble_mesh_prov_bearer_t bearer, uint8_t reason) +{ + ESP_LOGI(TAG, "%s link close, reason 0x%02x", + bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT", reason); + + if (bearer == ESP_BLE_MESH_PROV_ADV && reason != 0x00) { + prov_info.max_node_num++; + } +} + +static void provisioner_prov_complete(int node_index, const uint8_t uuid[16], uint16_t unicast_addr, + uint8_t elem_num, uint16_t net_idx) +{ + example_node_info_t *node = NULL; + char name[10]; + esp_err_t err; + + ESP_LOGI(TAG, "Node index: 0x%x, unicast address: 0x%02x, element num: %d, netkey index: 0x%02x", + node_index, unicast_addr, elem_num, net_idx); + ESP_LOGI(TAG, "Node uuid: %s", bt_hex(uuid, 16)); + + sprintf(name, "%s%d", "NODE-", node_index); + if (esp_ble_mesh_provisioner_set_node_name(node_index, name)) { + ESP_LOGE(TAG, "%s: Failed to set node name", __func__); + return; + } + + /* Sets node info */ + err = example_store_node_info(uuid, unicast_addr, elem_num, prov_info.net_idx, + prov_info.app_idx, LED_OFF); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to set node info", __func__); + return; + } + + /* Gets node info */ + node = example_get_node_info(unicast_addr); + if (!node) { + ESP_LOGE(TAG, "%s: Failed to get node info", __func__); + return; + } + + /* The Provisioner will send Config AppKey Add to the node. */ + example_msg_common_info_t info = { + .net_idx = node->net_idx, + .app_idx = node->app_idx, + .dst = node->unicast_addr, + .timeout = 0, + .role = ROLE_PROVISIONER, + }; + esp_ble_mesh_cfg_app_key_add_t add_key = { + .net_idx = prov_info.net_idx, + .app_idx = prov_info.app_idx, + }; + memcpy(add_key.app_key, prov_info.app_key, 16); + err = example_send_config_appkey_add(config_client.model, &info, &add_key); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to send Config AppKey Add message", __func__); + return; + } +} + +static void example_recv_unprov_adv_pkt(uint8_t dev_uuid[16], uint8_t addr[ESP_BD_ADDR_LEN], + esp_ble_addr_type_t addr_type, uint16_t oob_info, + uint8_t adv_type, esp_ble_mesh_prov_bearer_t bearer) +{ + esp_ble_mesh_unprov_dev_add_t add_dev = {0}; + esp_ble_mesh_dev_add_flag_t flag; + esp_err_t err; + bool reprov; + + if (bearer & ESP_BLE_MESH_PROV_ADV) { + /* Checks if the device has been provisioned previously. If the device + * is a re-provisioned one, we will ignore the 'max_node_num' count and + * start to provision it directly. + */ + reprov = example_is_node_exist(dev_uuid); + if (reprov) { + goto add; + } + + if (prov_info.max_node_num == 0) { + return; + } + + ESP_LOGI(TAG, "address: %s, address type: %d, adv type: %d", bt_hex(addr, 6), addr_type, adv_type); + ESP_LOGI(TAG, "dev uuid: %s", bt_hex(dev_uuid, 16)); + ESP_LOGI(TAG, "oob info: %d, bearer: %s", oob_info, (bearer & ESP_BLE_MESH_PROV_ADV) ? "PB-ADV" : "PB-GATT"); + +add: + memcpy(add_dev.addr, addr, 6); + add_dev.addr_type = (uint8_t)addr_type; + memcpy(add_dev.uuid, dev_uuid, 16); + add_dev.oob_info = oob_info; + add_dev.bearer = (uint8_t)bearer; + flag = ADD_DEV_RM_AFTER_PROV_FLAG | ADD_DEV_START_PROV_NOW_FLAG | ADD_DEV_FLUSHABLE_DEV_FLAG; + err = esp_ble_mesh_provisioner_add_unprov_dev(&add_dev, flag); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to start provisioning a device", __func__); + return; + } + + if (!reprov) { + if (prov_info.max_node_num) { + prov_info.max_node_num--; + } + } + } +} + +static void example_provisioning_callback(esp_ble_mesh_prov_cb_event_t event, + esp_ble_mesh_prov_cb_param_t *param) +{ + switch (event) { + case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROV_REGISTER_COMP_EVT, err_code: %d", + param->prov_register_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT"); + break; + case ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT: + example_recv_unprov_adv_pkt(param->provisioner_recv_unprov_adv_pkt.dev_uuid, param->provisioner_recv_unprov_adv_pkt.addr, + param->provisioner_recv_unprov_adv_pkt.addr_type, param->provisioner_recv_unprov_adv_pkt.oob_info, + param->provisioner_recv_unprov_adv_pkt.adv_type, param->provisioner_recv_unprov_adv_pkt.bearer); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT, bearer %s", + param->provisioner_prov_link_open.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT"); + provisioner_prov_link_open(param->provisioner_prov_link_open.bearer); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT, bearer %s reason 0x%02x", + param->provisioner_prov_link_close.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT", + param->provisioner_prov_link_close.reason); + provisioner_prov_link_close(param->provisioner_prov_link_close.bearer, + param->provisioner_prov_link_close.reason); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT"); + provisioner_prov_complete(param->provisioner_prov_complete.node_idx, + param->provisioner_prov_complete.device_uuid, + param->provisioner_prov_complete.unicast_addr, + param->provisioner_prov_complete.element_num, + param->provisioner_prov_complete.netkey_idx); + break; + case ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT, err_code: %d", + param->provisioner_add_unprov_dev_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT, err_code: %d", + param->provisioner_set_dev_uuid_match_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT, err_code: %d", + param->provisioner_set_node_name_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT: { + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT, err_code %d", param->provisioner_add_app_key_comp.err_code); + if (param->provisioner_add_app_key_comp.err_code == ESP_OK) { + esp_err_t err; + prov_info.app_idx = param->provisioner_add_app_key_comp.app_idx; + err = esp_ble_mesh_provisioner_bind_app_key_to_local_model(PROV_OWN_ADDR, prov_info.app_idx, + ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, CID_NVAL); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to bind AppKey with OnOff Client Model", __func__); + return; + } + err = esp_ble_mesh_provisioner_bind_app_key_to_local_model(PROV_OWN_ADDR, prov_info.app_idx, + ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_CLI, CID_ESP); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to bind AppKey with Fast Prov Client Model", __func__); + return; + } + } + break; + } + case ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT, err_code %d", param->provisioner_bind_app_key_to_model_comp.err_code); + break; + default: + break; + } + return; +} + +static void example_custom_model_callback(esp_ble_mesh_model_cb_event_t event, + esp_ble_mesh_model_cb_param_t *param) +{ + uint32_t opcode; + esp_err_t err; + + switch (event) { + case ESP_BLE_MESH_MODEL_OPERATION_EVT: { + if (!param->model_operation.model || !param->model_operation.model->op || + !param->model_operation.ctx) { + ESP_LOGE(TAG, "%s: model_operation parameter is NULL", __func__); + return; + } + opcode = param->model_operation.opcode; + switch (opcode) { + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS: + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS: + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS: { + ESP_LOGI(TAG, "%s: Fast Prov Client Model receives status, opcode 0x%04x", __func__, opcode); + err = example_fast_prov_client_recv_status(param->model_operation.model, + param->model_operation.ctx, + param->model_operation.length, + param->model_operation.msg); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to handle fast prov status message", __func__); + return; + } + break; + } + default: + ESP_LOGI(TAG, "%s: opcode 0x%04x", __func__, param->model_operation.opcode); + break; + } + break; + } + case ESP_BLE_MESH_MODEL_SEND_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_SEND_COMP_EVT, err_code %d", + param->model_send_comp.err_code); + break; + case ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT, err_code %d", + param->model_publish_comp.err_code); + break; + case ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_CLIENT_RECV_PUBLISH_MSG_EVT, opcode 0x%04x", + param->client_recv_publish_msg.opcode); + break; + case ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT, opcode 0x%04x, dst 0x%04x", + param->client_send_timeout.opcode, param->client_send_timeout.ctx->addr); + err = example_fast_prov_client_recv_timeout(param->client_send_timeout.opcode, + param->client_send_timeout.model, + param->client_send_timeout.ctx); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to resend fast prov client message", __func__); + return; + } + break; + default: + break; + } +} + +static void example_config_client_callback(esp_ble_mesh_cfg_client_cb_event_t event, + esp_ble_mesh_cfg_client_cb_param_t *param) +{ + example_node_info_t *node = NULL; + uint32_t opcode; + uint16_t address; + esp_err_t err; + + ESP_LOGI(TAG, "%s, error_code = 0x%02x, event = 0x%02x, addr: 0x%04x", + __func__, param->error_code, event, param->params->ctx.addr); + + opcode = param->params->opcode; + address = param->params->ctx.addr; + + node = example_get_node_info(address); + if (!node) { + ESP_LOGE(TAG, "%s: Failed to get node info", __func__); + return; + } + + if (param->error_code) { + ESP_LOGE(TAG, "Failed to send config client message, opcode: 0x%04x", opcode); + return; + } + + switch (event) { + case ESP_BLE_MESH_CFG_CLIENT_GET_STATE_EVT: + break; + case ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: { + example_fast_prov_info_set_t set = {0}; + if (!node->reprov || !ESP_BLE_MESH_ADDR_IS_UNICAST(node->unicast_min)) { + /* If the node is a new one or the node is re-provisioned but the information of the node + * has not been set before, here we will set the Fast Prov Info Set info to the node. + */ + node->node_addr_cnt = prov_info.node_addr_cnt; + node->unicast_min = prov_info.unicast_min; + node->unicast_max = prov_info.unicast_max; + node->flags = prov.flags; + node->iv_index = prov.iv_index; + node->fp_net_idx = prov_info.net_idx; + node->group_addr = prov_info.group_addr; + node->match_len = prov_info.match_len; + memcpy(node->match_val, prov_info.match_val, prov_info.match_len); + node->action = 0x81; + } + set.ctx_flags = 0x037F; + memcpy(&set.node_addr_cnt, &node->node_addr_cnt, + sizeof(example_node_info_t) - offsetof(example_node_info_t, node_addr_cnt)); + example_msg_common_info_t info = { + .net_idx = node->net_idx, + .app_idx = node->app_idx, + .dst = node->unicast_addr, + .timeout = 0, + .role = ROLE_PROVISIONER, + }; + err = example_send_fast_prov_info_set(fast_prov_client.model, &info, &set); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to set Fast Prov Info Set message", __func__); + return; + } + break; + } + default: + break; + } + break; + case ESP_BLE_MESH_CFG_CLIENT_PUBLISH_EVT: + break; + case ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: { + example_msg_common_info_t info = { + .net_idx = node->net_idx, + .app_idx = node->app_idx, + .dst = node->unicast_addr, + .timeout = 0, + .role = ROLE_PROVISIONER, + }; + esp_ble_mesh_cfg_app_key_add_t add_key = { + .net_idx = prov_info.net_idx, + .app_idx = prov_info.app_idx, + }; + memcpy(add_key.app_key, prov_info.app_key, 16); + err = example_send_config_appkey_add(config_client.model, &info, &add_key); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to send Config AppKey Add message", __func__); + return; + } + break; + } + default: + break; + } + break; + default: + ESP_LOGE(TAG, "Not a config client status message event"); + break; + } +} + +static void example_generic_client_callback(esp_ble_mesh_generic_client_cb_event_t event, + esp_ble_mesh_generic_client_cb_param_t *param) +{ + example_node_info_t *node = NULL; + uint32_t opcode; + uint16_t address; + + ESP_LOGI(TAG, "%s, error_code = 0x%02x, event = 0x%02x, addr: 0x%04x", + __func__, param->error_code, event, param->params->ctx.addr); + + opcode = param->params->opcode; + address = param->params->ctx.addr; + + node = example_get_node_info(address); + if (!node) { + ESP_LOGE(TAG, "%s: Failed to get node info", __func__); + return; + } + + if (param->error_code) { + ESP_LOGE(TAG, "Failed to send generic client message, opcode: 0x%04x", opcode); + return; + } + + switch (event) { + case ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT: + break; + case ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: + node->onoff = param->status_cb.onoff_status.present_onoff; + ESP_LOGI(TAG, "node->onoff: 0x%02x", node->onoff); + break; + default: + break; + } + break; + case ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT: + break; + case ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT: + break; + default: + ESP_LOGE(TAG, "Not a generic client status message event"); + break; + } +} + +static esp_err_t ble_mesh_init(void) +{ + esp_err_t err; + + memcpy(dev_uuid, esp_bt_dev_get_address(), 6); + + prov_info.unicast_min = prov.prov_start_address + prov_info.max_node_num; + prov_info.match_len = sizeof(match); + memcpy(prov_info.match_val, match, sizeof(match)); + memset(prov_info.app_key, APP_KEY_OCTET, sizeof(prov_info.app_key)); + + esp_ble_mesh_register_prov_callback(example_provisioning_callback); + esp_ble_mesh_register_custom_model_callback(example_custom_model_callback); + esp_ble_mesh_register_config_client_callback(example_config_client_callback); + esp_ble_mesh_register_generic_client_callback(example_generic_client_callback); + + err = esp_ble_mesh_provisioner_set_dev_uuid_match(match, 0x02, 0x00, false); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to set matching device UUID", __func__); + return ESP_FAIL; + } + + err = esp_ble_mesh_init(&prov, &comp); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to initialize BLE Mesh", __func__); + return ESP_FAIL; + } + + err = esp_ble_mesh_client_model_init(&vnd_models[0]); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to initialize fast prov client model", __func__); + return ESP_FAIL; + } + + err = esp_ble_mesh_provisioner_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to enable provisioning", __func__); + return ESP_FAIL; + } + + err = esp_ble_mesh_provisioner_add_local_app_key(prov_info.app_key, prov_info.net_idx, prov_info.app_idx); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to add local application key", __func__); + return ESP_FAIL; + } + + ESP_LOGI(TAG, "BLE Mesh Provisioner initialized"); + + return err; +} + +esp_err_t bluetooth_init(void) +{ + esp_err_t ret; + + ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)); + + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + ret = esp_bt_controller_init(&bt_cfg); + if (ret) { + ESP_LOGE(TAG, "%s initialize controller failed", __func__); + return ret; + } + + ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); + if (ret) { + ESP_LOGE(TAG, "%s enable controller failed", __func__); + return ret; + } + ret = esp_bluedroid_init(); + if (ret) { + ESP_LOGE(TAG, "%s init bluetooth failed", __func__); + return ret; + } + ret = esp_bluedroid_enable(); + if (ret) { + ESP_LOGE(TAG, "%s enable bluetooth failed", __func__); + return ret; + } + + return ret; +} + +void app_main(void) +{ + int err; + + ESP_LOGI(TAG, "Initializing..."); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "esp32_bluetooth_init failed (err %d)", err); + return; + } + + /* Initialize the Bluetooth Mesh Subsystem */ + err = ble_mesh_init(); + if (err) { + ESP_LOGE(TAG, "Failed to initialize BLE Mesh (err %d)", err); + } +} diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/component.mk b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/component.mk new file mode 100644 index 0000000000..a98f634eae --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/component.mk @@ -0,0 +1,4 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/sdkconfig.defaults b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/sdkconfig.defaults new file mode 100644 index 0000000000..a5c4750931 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/sdkconfig.defaults @@ -0,0 +1,43 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y +CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY= +CONFIG_BTDM_CONTROLLER_MODE_BTDM= +CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n +CONFIG_BLE_SCAN_DUPLICATE=y +CONFIG_SCAN_DUPLICATE_TYPE=2 +CONFIG_DUPLICATE_SCAN_CACHE_SIZE=200 +CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y +CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE=200 +CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_HCI_5_0=y +CONFIG_BLE_MESH_USE_DUPLICATE_SCAN=y +CONFIG_BLE_MESH_PROV=y +CONFIG_BLE_MESH_PROVISIONER=y +CONFIG_BLE_MESH_WAIT_FOR_PROV_MAX_DEV_NUM=10 +CONFIG_BLE_MESH_MAX_PROV_NODES=10 +CONFIG_BLE_MESH_MAX_STORED_NODES=10 +CONFIG_BLE_MESH_PBA_SAME_TIME=1 +CONFIG_BLE_MESH_PBG_SAME_TIME=1 +CONFIG_BLE_MESH_PROVISIONER_SUBNET_COUNT=3 +CONFIG_BLE_MESH_PROVISIONER_APP_KEY_COUNT=3 +CONFIG_BLE_MESH_PB_ADV=y +CONFIG_BLE_MESH_NET_BUF_POOL_USAGE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_GATT_PROXY=y +CONFIG_BLE_MESH_RELAY=y +CONFIG_BLE_MESH_LOW_POWER= +CONFIG_BLE_MESH_FRIEND= +CONFIG_BTU_TASK_STACK_SIZE=4512 +CONFIG_BLE_MESH_CFG_CLI=y +CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y +CONFIG_BLE_MESH_ADV_BUF_COUNT=100 +CONFIG_BLE_MESH_CRPL=10 +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SDU_MAX=384 +CONFIG_BLE_MESH_TX_SEG_MAX=32 +CONFIG_BLE_MESH_NO_LOG=n +CONFIG_BLE_MESH_STACK_TRACE_LEVEL=1 \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/tutorial/ble_mesh_fast_provision_client.md b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/tutorial/ble_mesh_fast_provision_client.md new file mode 100644 index 0000000000..60d27304ee --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/tutorial/ble_mesh_fast_provision_client.md @@ -0,0 +1,218 @@ +# 1. Introduction +## 1.1 Demo Function + +This demo completes the following functions: + +1. Provisioning an unprovisioned device and change it to a node. +2. Binding the provisioner's Appkey to its own models. +3. Sending messages to the node about the Appkey and the fast provisioning information. +4. Getting the addresses of all the nodes in the fast provisioning network. +5. Controlling the nodes by their group address. + +**Note: The demo's functionality is similar to that of the EspBleMesh app.** + +## 1.2 Node Composition + +This demo has only one element, in which the following four models are implemented: + +- The **Configuration Server** model is used to represent a mesh network configuration of a device. +- The **Configuration Client** model is used to represent an element that can control and monitor the configuration of a node. +- The **Generic OnOff Client** model controls a Generic OnOff Server via messages defined by the **Generic OnOff** model (turning on and off the lights in this demo). +- The **Vendor Client** model is used to control the `fast_prov_server` state, which defines the fast provisioning behavior of a node. + +**Note: For detailed information about these models, please refer to other BLE Mesh demos.** + +## 2. Code Analysis + +Code initialization part reference [Initializing the Bluetooth and Initializing the BLE Mesh](../../../ble_mesh_wifi_coexist/tutorial%20%20%20%20%20%20/ble_mesh_wifi_coexist.md) + +### 2.1 Data Structure + +`example_prov_info_t` is used to define the keys, the address range can be assigned by a node, and the maximum number of nodes supported by the mesh network. + +| Name |Description | +| ----------------------|------------------------- | +| `net_idx` | Netkey index value | +| `app_idx` | AppKey index value | +| `app_key[16]` | Appkey, which is used throughout the network | +| `node_addr_cnt`| The maximum number of nodes supported in the mesh network,which serves the same purpose of the `Fast provisioning count` parameter in the EspBleMesh app| +| `unicast_min` | Minimum unicast address to be assigned to the nodes in the mesh network | +| `unicast_max` | Maximum unicast address to be assigned to the nodes in the mesh network | +| `group_addr`| The group address, which is used to control the on/off state of all nodes in the mesh network, that is said, turning on and off the lights in this demo| +| `match_val[16]`| The value used by the Fast Provisioning Provisioner to filter the devices to be provisioned | +| `match_len` | The maximum length of `match_val[16]` | +| `max_node_num` | The maximum number of nodes can be provisioned by the client | + +### 2.2 Code Flow + +The events and APIs in this section are presented in the same order with code execution. + +### 2.2.1 Initialization + +#### 2.2.1.1 Set the UUID Filter + +The `esp_ble_mesh_provisioner_set_dev_uuid_match` API is called by the provisioner to set the part of the device UUID to be compared before starting to provision. + +``` +/** + * @brief This function is called by Provisioner to set the part of the device UUID + * to be compared before starting to provision. + * + * @param[in] match_val: Value to be compared with the part of the device UUID. + * @param[in] match_len: Length of the compared match value. + * @param[in] offset: Offset of the device UUID to be compared (based on zero). + * @param[in] prov_after_match: Flag used to indicate whether provisioner should start to provision + * the device immediately if the part of the UUID matches. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_provisioner_set_dev_uuid_match(const uint8_t *match_val, uint8_t match_len, + uint8_t offset, bool prov_after_match); +``` + +```c +err = esp_ble_mesh_provisioner_set_dev_uuid_match(match, 0x02, 0x00, false); +if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to set matching device UUID", __func__); + return ESP_FAIL; +} +``` + + + +#### 2.2.1.2 Add local Appkey + +The provisioner has no Appkey right after it has been initialized. Therefore, you have to add a local Appkey for the provisioner by calling the `esp_ble_mesh_provisioner_add_local_app_key`. + +```c +err = esp_ble_mesh_provisioner_add_local_app_key(prov_info.app_key, prov_info.net_idx, prov_info.app_idx); +if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to add local application key", __func__); + return ESP_FAIL; +} +``` +Please check the return value of the API calling and the return value of `ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT`, and make sure that the Appkey has been added to this provisioner. + +#### 2.2.1.3 Bind Appkey to local model + +To control the server model, the client model uses messages to control the server model and these message must be encrypted by the Appkey. To that end, users must bind the Appkey of the provisioner to its local models, which are the **Generic OnOff Client** model and the **Vendor Client** model, by calling the `esp_ble_mesh_provisioner_add_local_app_key` api. + +```c +prov_info.app_idx = param->provisioner_add_app_key_comp.app_idx; +err = esp_ble_mesh_provisioner_bind_app_key_to_local_model(PROV_OWN_ADDR, prov_info.app_idx, + ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, CID_NVAL); +if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to bind AppKey with OnOff Client Model", __func__); + return; +} +err = esp_ble_mesh_provisioner_bind_app_key_to_local_model(PROV_OWN_ADDR, prov_info.app_idx, + ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_CLI, CID_ESP); +if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to bind AppKey with Fast Prov Client Model", __func__); + return; +} +``` +Please check the return value of the API calling and the return value of the `ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT` event, and make sure that the Appkey has been binded to the local models. + + +### 2.2.2 Provisioning a device + +The unprovisioned devices continuously send the **Unprovisioned Device** beacon, which contains the value of its UUID. + +* If the UUID matched, a `ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT` event will be triggered, which will add the unprovisioned device information to the queue of to-be-provisioned devices. + + ```c + err = esp_ble_mesh_provisioner_add_unprov_dev(&add_dev, flag); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to start provisioning a device", __func__); + return; + } + + if (!reprov) { + if (prov_info.max_node_num) { + prov_info.max_node_num--; + } + } + ``` +* If not, this device will be ignored. + +After that, all the devices in the queue will be provisioned automatically. + +### 2.2.3 Sending cache data + +Appkey is among the cache required for this node to become a provisioner. + +When the provisioning completes, an `ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT` event will be triggered, which will add the Appkey to the node's **Config Server** model by calling the `esp_ble_mesh_config_client_set_state` API: + +```c +common.opcode = ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD; +common.model = model; +common.ctx.net_idx = info->net_idx; +common.ctx.app_idx = 0x0000; /* not used for config messages */ +common.ctx.addr = info->dst; +common.ctx.send_rel = false; +common.ctx.send_ttl = 0; +common.msg_timeout = info->timeout; +common.msg_role = info->role; + +return esp_ble_mesh_config_client_set_state(&common, &set); +``` + +* If API calling succeeds, an `ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT` event will be triggered, which sends other cache information (`example_fast_prov_info_set_t`) to the node's **Vendor Server** model by calling the `example_send_fast_prov_info_set` function; + * If API calling (`example_send_fast_prov_info_set`) succeeded, a message with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET` will be sent, whose acknowledgement (with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS`) will further trigger an `ESP_BLE_MESH_MODEL_OPERATION_EVT` event + ```c + err = example_send_fast_prov_info_set(fast_prov_client.model, &info, &set); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to set Fast Prov Info Set message", __func__); + return; + } + ``` + * If API calling (`example_send_fast_prov_info_set`) times out, an `ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT` event will be triggered. +* If API calling times out, an `ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT` event is triggered. + +After that, this node has the ability to provisioning other nodes as a provisioner, and further controls other nodes. + +**Note: The message with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET` contains the group address of all the nodes. When a node receives this message, it will automatically subscribe the Onoff Server model of this address.** + +### 2.2.4 Controlling the node + +When the `ESP_BLE_MESH_MODEL_OPERATION_EVT` event is triggered, the provisioner starts a timer. + +```c + ESP_LOG_BUFFER_HEX("fast prov info status", data, len); +#if !defined(CONFIG_BLE_MESH_FAST_PROV) + prim_prov_addr = ctx->addr; + k_delayed_work_init(&get_all_node_addr_timer, example_get_all_node_addr); + k_delayed_work_submit(&get_all_node_addr_timer, GET_ALL_NODE_ADDR_TIMEOUT); +#endif + break; +``` +After the timers times out, the provisioner starts to get the addresses of all nodes in the mesh network by calling the `example_send_fast_prov_all_node_addr_get` function, which sends a message with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET`. + +```c +err = example_send_fast_prov_all_node_addr_get(model, &info); +if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to send Fast Prov Node Address Get message", __func__); + return; +} +``` + +After that, the provisioner will receive an acknowledgement, which is a message with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS`, which triggers the `ESP_BLE_MESH_MODEL_OPERATION_EVT` event. + +Then, the provisioner is able to turn on all the nodes (which are lights in this demo) by calling the `example_send_generic_onoff_set` function using the group address. + +```c +example_msg_common_info_t info = { + .net_idx = node->net_idx, + .app_idx = node->app_idx, + .dst = node->group_addr, + .timeout = 0, + .role = ROLE_PROVISIONER, +}; +err = example_send_generic_onoff_set(cli_model, &info, LED_ON, 0x00, false); +if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to send Generic OnOff Set Unack message", __func__); + return ESP_FAIL; +} +``` diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/CMakeLists.txt b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/CMakeLists.txt new file mode 100644 index 0000000000..594effdbb8 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(ble_mesh_fast_prov_server) diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/Makefile b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/Makefile new file mode 100644 index 0000000000..f6ece484ac --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/Makefile @@ -0,0 +1,12 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := ble_mesh_fast_prov_server + +COMPONENT_ADD_INCLUDEDIRS := components/include + +EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components + +include $(IDF_PATH)/make/project.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/README.md b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/README.md new file mode 100644 index 0000000000..2746ed629a --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/README.md @@ -0,0 +1,2 @@ +ESP BLE Mesh Fast Provisioning Server Demo +======================== \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/CMakeLists.txt b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/CMakeLists.txt new file mode 100644 index 0000000000..1eb2d87ed2 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/CMakeLists.txt @@ -0,0 +1,6 @@ +set(COMPONENT_SRCS "ble_mesh_demo_main.c" + "board.c") + +set(COMPONENT_ADD_INCLUDEDIRS ".") + +register_component() diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/Kconfig.projbuild b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/Kconfig.projbuild new file mode 100644 index 0000000000..e48a853e0b --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/Kconfig.projbuild @@ -0,0 +1,16 @@ +menu "Example Configuration" + + choice BLE_MESH_EXAMPLE_BOARD + prompt "Board selection for BLE Mesh" + default BLE_MESH_ESP_WROOM_32 + help + Select this option to choose the board for BLE Mesh. The default is ESP32-WROOM-32 + + config BLE_MESH_ESP_WROOM_32 + bool "ESP32-WROOM-32" + + config BLE_MESH_ESP_WROVER + bool "ESP32-WROVER" + endchoice + +endmenu diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/ble_mesh_demo_main.c b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/ble_mesh_demo_main.c new file mode 100644 index 0000000000..87bc00e1d0 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/ble_mesh_demo_main.c @@ -0,0 +1,842 @@ +// Copyright 2017-2018 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 +#include + +#include "esp_log.h" +#include "nvs_flash.h" + +#include "esp_bt.h" +#include "esp_bt_main.h" +#include "esp_bt_device.h" + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_common_api.h" +#include "esp_ble_mesh_networking_api.h" +#include "esp_ble_mesh_provisioning_api.h" +#include "esp_ble_mesh_config_model_api.h" +#include "esp_ble_mesh_generic_model_api.h" + +#include "board.h" +#include "esp_fast_prov_operation.h" +#include "esp_fast_prov_client_model.h" +#include "esp_fast_prov_server_model.h" + +#define TAG "FAST_PROV_SERVER_DEMO" + +extern struct _led_state led_state[3]; +extern struct k_delayed_work send_self_prov_node_addr_timer; +extern bt_mesh_atomic_t fast_prov_cli_flags; + +static uint8_t dev_uuid[16] = { 0xdd, 0xdd }; +static uint8_t prov_start_num = 0; +static bool prov_start = false; + +static const esp_ble_mesh_client_op_pair_t fast_prov_cli_op_pair[] = { + { ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS }, + { ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS }, + { ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK }, + { ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS }, +}; + +/* Configuration Client Model user_data */ +esp_ble_mesh_client_t config_client; + +/* Configuration Server Model user_data */ +esp_ble_mesh_cfg_srv_t config_server = { + .relay = ESP_BLE_MESH_RELAY_ENABLED, + .beacon = ESP_BLE_MESH_BEACON_DISABLED, +#if defined(CONFIG_BLE_MESH_FRIEND) + .friend_state = ESP_BLE_MESH_FRIEND_ENABLED, +#else + .friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED, +#endif +#if defined(CONFIG_BLE_MESH_GATT_PROXY) + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED, +#else + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED, +#endif + .default_ttl = 7, + /* 3 transmissions with 20ms interval */ + .net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20), + .relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20), +}; + +/* Fast Prov Client Model user_data */ +esp_ble_mesh_client_t fast_prov_client = { + .op_pair_size = ARRAY_SIZE(fast_prov_cli_op_pair), + .op_pair = fast_prov_cli_op_pair, +}; + +/* Fast Prov Server Model user_data */ +example_fast_prov_server_t fast_prov_server = { + .primary_role = false, + .max_node_num = 6, + .prov_node_cnt = 0x0, + .unicast_min = ESP_BLE_MESH_ADDR_UNASSIGNED, + .unicast_max = ESP_BLE_MESH_ADDR_UNASSIGNED, + .unicast_cur = ESP_BLE_MESH_ADDR_UNASSIGNED, + .unicast_step = 0x0, + .flags = 0x0, + .iv_index = 0x0, + .net_idx = ESP_BLE_MESH_KEY_UNUSED, + .app_idx = ESP_BLE_MESH_KEY_UNUSED, + .group_addr = ESP_BLE_MESH_ADDR_UNASSIGNED, + .prim_prov_addr = ESP_BLE_MESH_ADDR_UNASSIGNED, + .match_len = 0x0, + .pend_act = FAST_PROV_ACT_NONE, + .state = STATE_IDLE, +}; + +static esp_ble_mesh_model_op_t onoff_op[] = { + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET, 0), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, 2), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2), + ESP_BLE_MESH_MODEL_OP_END, +}; + +ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub, 2 + 1, ROLE_FAST_PROV); + +static esp_ble_mesh_model_op_t fast_prov_srv_op[] = { + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET, 3), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD, 16), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR, 2), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET, 0), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_GROUP_ADD, 2), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_GROUP_DELETE, 2), + ESP_BLE_MESH_MODEL_OP_END, +}; + +static esp_ble_mesh_model_op_t fast_prov_cli_op[] = { + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS, 1), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS, 2), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK, 0), + ESP_BLE_MESH_MODEL_OP_END, +}; + +static esp_ble_mesh_model_t root_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&config_server), + ESP_BLE_MESH_MODEL_CFG_CLI(&config_client), + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, onoff_op, + &onoff_pub, &led_state[1]), +}; + +static esp_ble_mesh_model_t vnd_models[] = { + ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_SRV, + fast_prov_srv_op, NULL, &fast_prov_server), + ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_CLI, + fast_prov_cli_op, NULL, &fast_prov_client), +}; + +static esp_ble_mesh_elem_t elements[] = { + ESP_BLE_MESH_ELEMENT(0, root_models, vnd_models), +}; + +static esp_ble_mesh_comp_t comp = { + .cid = CID_ESP, + .elements = elements, + .element_count = ARRAY_SIZE(elements), +}; + +static esp_ble_mesh_prov_t prov = { + .uuid = dev_uuid, + .output_size = 0, + .output_actions = 0, + .prov_attention = 0x00, + .prov_algorithm = 0x00, + .prov_pub_key_oob = 0x00, + .prov_static_oob_val = NULL, + .prov_static_oob_len = 0x00, + .flags = 0x00, + .iv_index = 0x00, +}; + +static void gen_onoff_get_handler(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, + uint16_t len, uint8_t *data) +{ + struct _led_state *led = NULL; + uint8_t send_data; + esp_err_t err; + + led = (struct _led_state *)model->user_data; + if (!led) { + ESP_LOGE(TAG, "%s: Failed to get generic onoff server model user_data", __func__); + return; + } + + send_data = led->current; + + /* Sends Generic OnOff Status as a reponse to Generic OnOff Get */ + err = esp_ble_mesh_server_model_send_msg(model, ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, + sizeof(send_data), &send_data); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to send Generic OnOff Status message", __func__); + return; + } + + /* When the node receives the first Generic OnOff Get/Set/Set Unack message, it will + * start the timer used to disable fast provisioning functionality. + */ + if (!bt_mesh_atomic_test_and_set_bit(fast_prov_server.srv_flags, DISABLE_FAST_PROV_START)) { + k_delayed_work_submit(&fast_prov_server.disable_fast_prov_timer, DISABLE_FAST_PROV_TIMEOUT); + } +} + +static void gen_onoff_set_unack_handler(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, + uint16_t len, uint8_t *data) +{ + struct _led_state *led = NULL; + + led = (struct _led_state *)model->user_data; + if (!led) { + ESP_LOGE(TAG, "%s: Failed to get generic onoff server model user_data", __func__); + return; + } + + led->current = data[0]; + gpio_set_level(led->pin, led->current); + + /* When the node receives the first Generic OnOff Get/Set/Set Unack message, it will + * start the timer used to disable fast provisioning functionality. + */ + if (!bt_mesh_atomic_test_and_set_bit(fast_prov_server.srv_flags, DISABLE_FAST_PROV_START)) { + k_delayed_work_submit(&fast_prov_server.disable_fast_prov_timer, DISABLE_FAST_PROV_TIMEOUT); + } +} + +static void gen_onoff_set_handler(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, + uint16_t len, uint8_t *data) +{ + gen_onoff_set_unack_handler(model, ctx, len, data); + gen_onoff_get_handler(model, ctx, len, data); +} + +static void node_prov_complete(uint16_t net_idx, uint16_t addr, uint8_t flags, uint32_t iv_index) +{ + ESP_LOGI(TAG, "net_idx: 0x%04x, unicast_addr: 0x%04x", net_idx, addr); + ESP_LOGI(TAG, "flags: 0x%02x, iv_index: 0x%08x", flags, iv_index); + board_prov_complete(); + /* Updates the net_idx used by Fast Prov Server model, and it can also + * be updated if the Fast Prov Info Set message contains a valid one. + */ + fast_prov_server.net_idx = net_idx; +} + +static void provisioner_prov_link_open(esp_ble_mesh_prov_bearer_t bearer) +{ + ESP_LOGI(TAG, "%s: bearer %s", __func__, bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT"); +} + +static void provisioner_prov_link_close(esp_ble_mesh_prov_bearer_t bearer, uint8_t reason) +{ + ESP_LOGI(TAG, "%s: bearer %s, reason 0x%02x", __func__, + bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT", reason); + if (prov_start_num) { + prov_start_num--; + } +} + +static void provisioner_prov_complete(int node_idx, const uint8_t uuid[16], uint16_t unicast_addr, + uint8_t element_num, uint16_t net_idx) +{ + example_node_info_t *node = NULL; + esp_err_t err; + + if (example_is_node_exist(uuid) == false) { + fast_prov_server.prov_node_cnt++; + } + + ESP_LOG_BUFFER_HEX("Device uuid", uuid + 2, 6); + ESP_LOGI(TAG, "Unicast address 0x%04x", unicast_addr); + + /* Sets node info */ + err = example_store_node_info(uuid, unicast_addr, element_num, net_idx, + fast_prov_server.app_idx, LED_OFF); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to set node info", __func__); + return; + } + + /* Gets node info */ + node = example_get_node_info(unicast_addr); + if (!node) { + ESP_LOGE(TAG, "%s: Failed to get node info", __func__); + return; + } + + if (fast_prov_server.primary_role == true) { + /* If the Provisioner is the primary one (i.e. provisioned by the phone), it shall + * store self-provisioned node addresses; + * If the node_addr_cnt configured by the phone is small than or equal to the + * maximum number of nodes it can provision, it shall reset the timer which is used + * to send all node addresses to the phone. + */ + err = example_store_remote_node_address(unicast_addr); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to store node address 0x%04x", __func__, unicast_addr); + return; + } + if (fast_prov_server.node_addr_cnt != FAST_PROV_NODE_COUNT_MIN && + fast_prov_server.node_addr_cnt <= fast_prov_server.max_node_num) { + if (bt_mesh_atomic_test_and_clear_bit(fast_prov_server.srv_flags, GATT_PROXY_ENABLE_START)) { + k_delayed_work_cancel(&fast_prov_server.gatt_proxy_enable_timer); + } + if (!bt_mesh_atomic_test_and_set_bit(fast_prov_server.srv_flags, GATT_PROXY_ENABLE_START)) { + k_delayed_work_submit(&fast_prov_server.gatt_proxy_enable_timer, GATT_PROXY_ENABLE_TIMEOUT); + } + } + } else { + /* When a device is provisioned, the non-primary Provisioner shall reset the timer + * which is used to send node addresses to the primary Provisioner. + */ + if (bt_mesh_atomic_test_and_clear_bit(&fast_prov_cli_flags, SEND_SELF_PROV_NODE_ADDR_START)) { + k_delayed_work_cancel(&send_self_prov_node_addr_timer); + } + if (!bt_mesh_atomic_test_and_set_bit(&fast_prov_cli_flags, SEND_SELF_PROV_NODE_ADDR_START)) { + k_delayed_work_submit(&send_self_prov_node_addr_timer, SEND_SELF_PROV_NODE_ADDR_TIMEOUT); + } + } + + if (bt_mesh_atomic_test_bit(fast_prov_server.srv_flags, DISABLE_FAST_PROV_START)) { + /* When a device is provisioned, and the stop_prov flag of the Provisioner has been + * set, the Provisioner shall reset the timer which is used to stop the provisioner + * functionality. + */ + k_delayed_work_cancel(&fast_prov_server.disable_fast_prov_timer); + k_delayed_work_submit(&fast_prov_server.disable_fast_prov_timer, DISABLE_FAST_PROV_TIMEOUT); + } + + /* The Provisioner will send Config AppKey Add to the node. */ + example_msg_common_info_t info = { + .net_idx = node->net_idx, + .app_idx = node->app_idx, + .dst = node->unicast_addr, + .timeout = 0, + .role = ROLE_FAST_PROV, + }; + err = example_send_config_appkey_add(config_client.model, &info, NULL); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to send Config AppKey Add message", __func__); + return; + } +} + +static void example_recv_unprov_adv_pkt(uint8_t dev_uuid[16], uint8_t addr[ESP_BD_ADDR_LEN], + esp_ble_addr_type_t addr_type, uint16_t oob_info, + uint8_t adv_type, esp_ble_mesh_prov_bearer_t bearer) +{ + esp_ble_mesh_unprov_dev_add_t add_dev = {0}; + esp_ble_mesh_dev_add_flag_t flag; + esp_err_t err; + + /* In Fast Provisioning, the Provisioner should only use PB-ADV to provision devices. */ + if (prov_start && (bearer & ESP_BLE_MESH_PROV_ADV)) { + /* Checks if the device is a reprovisioned one. */ + if (example_is_node_exist(dev_uuid) == false) { + if ((prov_start_num >= fast_prov_server.max_node_num) || + (fast_prov_server.prov_node_cnt >= fast_prov_server.max_node_num)) { + return; + } + } + + add_dev.addr_type = (uint8_t)addr_type; + add_dev.oob_info = oob_info; + add_dev.bearer = (uint8_t)bearer; + memcpy(add_dev.uuid, dev_uuid, 16); + memcpy(add_dev.addr, addr, ESP_BD_ADDR_LEN); + flag = ADD_DEV_RM_AFTER_PROV_FLAG | ADD_DEV_START_PROV_NOW_FLAG | ADD_DEV_FLUSHABLE_DEV_FLAG; + err = esp_ble_mesh_provisioner_add_unprov_dev(&add_dev, flag); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to start provisioning device", __func__); + return; + } + + /* If adding unprovisioned device successfully, increase prov_start_num */ + prov_start_num++; + } + + return; +} + +static void example_ble_mesh_provisioning_cb(esp_ble_mesh_prov_cb_event_t event, + esp_ble_mesh_prov_cb_param_t *param) +{ + esp_err_t err; + + switch (event) { + case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROV_REGISTER_COMP_EVT, err_code: %d", + param->prov_register_comp.err_code); + break; + case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT, err_code: %d", + param->node_prov_enable_comp.err_code); + break; + case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT, bearer: %s", + param->node_prov_link_open.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT"); + break; + case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT, bearer: %s", + param->node_prov_link_close.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT"); + break; + case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT"); + node_prov_complete(param->node_prov_complete.net_idx, param->node_prov_complete.addr, + param->node_prov_complete.flags, param->node_prov_complete.iv_index); + break; + case ESP_BLE_MESH_NODE_PROXY_GATT_DISABLE_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROXY_GATT_DISABLE_COMP_EVT"); + if (fast_prov_server.primary_role == true) { + config_server.relay = ESP_BLE_MESH_RELAY_DISABLED; + } + prov_start = true; + break; + case ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT: + example_recv_unprov_adv_pkt(param->provisioner_recv_unprov_adv_pkt.dev_uuid, param->provisioner_recv_unprov_adv_pkt.addr, + param->provisioner_recv_unprov_adv_pkt.addr_type, param->provisioner_recv_unprov_adv_pkt.oob_info, + param->provisioner_recv_unprov_adv_pkt.adv_type, param->provisioner_recv_unprov_adv_pkt.bearer); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT"); + provisioner_prov_link_open(param->provisioner_prov_link_open.bearer); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT"); + provisioner_prov_link_close(param->provisioner_prov_link_close.bearer, + param->provisioner_prov_link_close.reason); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT"); + provisioner_prov_complete(param->provisioner_prov_complete.node_idx, + param->provisioner_prov_complete.device_uuid, + param->provisioner_prov_complete.unicast_addr, + param->provisioner_prov_complete.element_num, + param->provisioner_prov_complete.netkey_idx); + break; + case ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT, err_code: %d", + param->provisioner_add_unprov_dev_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT, err_code: %d", + param->provisioner_set_dev_uuid_match_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT, err_code: %d", + param->provisioner_set_node_name_comp.err_code); + break; + case ESP_BLE_MESH_SET_FAST_PROV_INFO_COMP_EVT: { + ESP_LOGI(TAG, "ESP_BLE_MESH_SET_FAST_PROV_INFO_COMP_EVT"); + ESP_LOGI(TAG, "status_unicast: 0x%02x, status_net_idx: 0x%02x, status_match 0x%02x", + param->set_fast_prov_info_comp.status_unicast, + param->set_fast_prov_info_comp.status_net_idx, + param->set_fast_prov_info_comp.status_match); + err = example_handle_fast_prov_info_set_comp_evt(fast_prov_server.model, + param->set_fast_prov_info_comp.status_unicast, + param->set_fast_prov_info_comp.status_net_idx, + param->set_fast_prov_info_comp.status_match); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to handle Fast Prov Info Set complete event", __func__); + return; + } + break; + } + case ESP_BLE_MESH_SET_FAST_PROV_ACTION_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_SET_FAST_PROV_ACTION_COMP_EVT, status_action 0x%02x", + param->set_fast_prov_action_comp.status_action); + err = example_handle_fast_prov_action_set_comp_evt(fast_prov_server.model, + param->set_fast_prov_action_comp.status_action); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to handle Fast Prov Action Set complete event", __func__); + return; + } + break; + default: + break; + } + + return; +} + +static void example_ble_mesh_custom_model_cb(esp_ble_mesh_model_cb_event_t event, + esp_ble_mesh_model_cb_param_t *param) +{ + uint32_t opcode; + esp_err_t err; + + switch (event) { + case ESP_BLE_MESH_MODEL_OPERATION_EVT: { + if (!param->model_operation.model || !param->model_operation.model->op || + !param->model_operation.ctx) { + ESP_LOGE(TAG, "%s: model_operation parameter is NULL", __func__); + return; + } + opcode = param->model_operation.opcode; + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: + gen_onoff_set_handler(param->model_operation.model, param->model_operation.ctx, + param->model_operation.length, param->model_operation.msg); + break; + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK: + gen_onoff_set_unack_handler(param->model_operation.model, param->model_operation.ctx, + param->model_operation.length, param->model_operation.msg); + break; + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET: + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD: + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR: + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET: + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_GROUP_ADD: + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_GROUP_DELETE: { + ESP_LOGI(TAG, "%s: Fast prov server receives msg, opcode 0x%04x", __func__, opcode); + struct net_buf_simple buf = { + .len = param->model_operation.length, + .data = param->model_operation.msg, + }; + err = example_fast_prov_server_recv_msg(param->model_operation.model, + param->model_operation.ctx, &buf); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to handle fast prov client message", __func__); + return; + } + break; + } + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS: + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS: + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK: { + ESP_LOGI(TAG, "%s: Fast prov client receives msg, opcode 0x%04x", __func__, opcode); + err = example_fast_prov_client_recv_status(param->model_operation.model, + param->model_operation.ctx, + param->model_operation.length, + param->model_operation.msg); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to handle fast prov server message", __func__); + return; + } + break; + } + default: + ESP_LOGI(TAG, "%s: opcode 0x%04x", __func__, param->model_operation.opcode); + break; + } + break; + } + case ESP_BLE_MESH_MODEL_SEND_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_SEND_COMP_EVT, err_code %d", param->model_send_comp.err_code); + switch (param->model_send_comp.opcode) { + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS: + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS: + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK: + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS: + err = example_handle_fast_prov_status_send_comp_evt(param->model_send_comp.err_code, + param->model_send_comp.opcode, + param->model_send_comp.model, + param->model_send_comp.ctx); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to handle fast prov status send complete event", __func__); + return; + } + break; + default: + break; + } + break; + case ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT, err_code %d", + param->model_publish_comp.err_code); + break; + case ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_CLIENT_RECV_PUBLISH_MSG_EVT, opcode 0x%04x", + param->client_recv_publish_msg.opcode); + break; + case ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT, opcode 0x%04x, dst 0x%04x", + param->client_send_timeout.opcode, param->client_send_timeout.ctx->addr); + err = example_fast_prov_client_recv_timeout(param->client_send_timeout.opcode, + param->client_send_timeout.model, + param->client_send_timeout.ctx); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Faield to resend fast prov client message", __func__); + return; + } + break; + default: + break; + } +} + +static void example_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t event, + esp_ble_mesh_cfg_client_cb_param_t *param) +{ + example_node_info_t *node = NULL; + uint32_t opcode; + uint16_t address; + esp_err_t err; + + ESP_LOGI(TAG, "%s, error_code = 0x%02x, event = 0x%02x, addr: 0x%04x", + __func__, param->error_code, event, param->params->ctx.addr); + + opcode = param->params->opcode; + address = param->params->ctx.addr; + + node = example_get_node_info(address); + if (!node) { + ESP_LOGE(TAG, "%s: Failed to get node info", __func__); + return; + } + + if (param->error_code) { + ESP_LOGE(TAG, "Failed to send config client message, opcode: 0x%04x", opcode); + return; + } + + switch (event) { + case ESP_BLE_MESH_CFG_CLIENT_GET_STATE_EVT: + break; + case ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: { + example_fast_prov_info_set_t set = {0}; + if (node->reprov == false) { + /* After sending Config AppKey Add successfully, start to send Fast Prov Info Set */ + if (fast_prov_server.unicast_cur >= fast_prov_server.unicast_max) { + /* TODO: + * 1. If unicast_cur is >= unicast_max, we can also send the message to enable + * the Provisioner functionality on the node, and need to add another vendor + * message used by the node to require a new unicast address range from primary + * Provisioner, and before get the correct response, the node should pend + * the fast provisioning functionality. + * 2. Currently if address is not enough, the Provisioner will only add the group + * address to the node. + */ + ESP_LOGW(TAG, "%s: Not enough address to be assigned", __func__); + node->lack_of_addr = true; + } else { + /* Send fast_prov_info_set message to node */ + node->lack_of_addr = false; + node->unicast_min = fast_prov_server.unicast_cur; + if (fast_prov_server.unicast_cur + fast_prov_server.unicast_step >= fast_prov_server.unicast_max) { + node->unicast_max = fast_prov_server.unicast_max; + } else { + node->unicast_max = fast_prov_server.unicast_cur + fast_prov_server.unicast_step; + } + node->flags = fast_prov_server.flags; + node->iv_index = fast_prov_server.iv_index; + node->fp_net_idx = fast_prov_server.net_idx; + node->group_addr = fast_prov_server.group_addr; + node->prov_addr = fast_prov_server.prim_prov_addr; + node->match_len = fast_prov_server.match_len; + memcpy(node->match_val, fast_prov_server.match_val, fast_prov_server.match_len); + node->action = FAST_PROV_ACT_ENTER; + fast_prov_server.unicast_cur = node->unicast_max + 1; + } + } + if (node->lack_of_addr == false) { + set.ctx_flags = 0x03FE; + memcpy(&set.unicast_min, &node->unicast_min, + sizeof(example_node_info_t) - offsetof(example_node_info_t, unicast_min)); + } else { + set.ctx_flags = BIT(6); + set.group_addr = fast_prov_server.group_addr; + } + example_msg_common_info_t info = { + .net_idx = node->net_idx, + .app_idx = node->app_idx, + .dst = node->unicast_addr, + .timeout = 0, + .role = ROLE_FAST_PROV, + }; + err = example_send_fast_prov_info_set(fast_prov_client.model, &info, &set); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to send Fast Prov Info Set message", __func__); + return; + } + break; + } + default: + break; + } + break; + case ESP_BLE_MESH_CFG_CLIENT_PUBLISH_EVT: + break; + case ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: { + example_msg_common_info_t info = { + .net_idx = node->net_idx, + .app_idx = node->app_idx, + .dst = node->unicast_addr, + .timeout = 0, + .role = ROLE_FAST_PROV, + }; + err = example_send_config_appkey_add(config_client.model, &info, NULL); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to send Config AppKey Add message", __func__); + return; + } + break; + } + default: + break; + } + break; + default: + return; + } +} + +static void example_ble_mesh_config_server_cb(esp_ble_mesh_cfg_server_cb_event_t event, + esp_ble_mesh_cfg_server_cb_param_t *param) +{ + esp_err_t err; + + ESP_LOGI(TAG, "%s, event = 0x%02x, opcode = 0x%04x, addr: 0x%04x", + __func__, event, param->ctx.recv_op, param->ctx.addr); + + switch (event) { + case ESP_BLE_MESH_CFG_SERVER_RECV_MSG_EVT: + switch (param->ctx.recv_op) { + case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: + ESP_LOGI(TAG, "Config Server get Config AppKey Add"); + err = example_handle_config_app_key_add_evt(param->status_cb.app_key_add.app_idx); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to bind app_idx 0x%04x with non-config models", + __func__, param->status_cb.app_key_add.app_idx); + return; + } + break; + default: + break; + } + break; + default: + return; + } +} + +static esp_err_t ble_mesh_init(void) +{ + esp_err_t err; + + /* First two bytes of device uuid is compared with match value by Provisioner */ + memcpy(dev_uuid + 2, esp_bt_dev_get_address(), 6); + + esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb); + esp_ble_mesh_register_custom_model_callback(example_ble_mesh_custom_model_cb); + esp_ble_mesh_register_config_client_callback(example_ble_mesh_config_client_cb); + esp_ble_mesh_register_config_server_callback(example_ble_mesh_config_server_cb); + + err = esp_ble_mesh_init(&prov, &comp); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to initialize BLE Mesh", __func__); + return err; + } + + err = example_fast_prov_server_init(&vnd_models[0]); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to initialize fast prov server model", __func__); + return err; + } + + err = esp_ble_mesh_client_model_init(&vnd_models[1]); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to initialize fast prov client model", __func__); + return err; + } + + k_delayed_work_init(&send_self_prov_node_addr_timer, example_send_self_prov_node_addr); + + err = esp_ble_mesh_node_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to enable node provisioning", __func__); + return err; + } + + ESP_LOGI(TAG, "BLE Mesh Fast Prov Node initialized"); + + board_led_operation(LED_B, LED_ON); + + return ESP_OK; +} + +static esp_err_t bluetooth_init(void) +{ + esp_err_t ret; + + ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)); + + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + ret = esp_bt_controller_init(&bt_cfg); + if (ret) { + ESP_LOGE(TAG, "%s initialize controller failed", __func__); + return ret; + } + + ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); + if (ret) { + ESP_LOGE(TAG, "%s enable controller failed", __func__); + return ret; + } + + ret = esp_bluedroid_init(); + if (ret) { + ESP_LOGE(TAG, "%s init bluetooth failed", __func__); + return ret; + } + + ret = esp_bluedroid_enable(); + if (ret) { + ESP_LOGE(TAG, "%s enable bluetooth failed", __func__); + return ret; + } + + return ret; +} + +void app_main(void) +{ + esp_err_t err; + + ESP_LOGI(TAG, "Initializing..."); + + err = board_init(); + if (err) { + ESP_LOGE(TAG, "board_init failed (err %d)", err); + return; + } + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "esp32_bluetooth_init failed (err %d)", err); + return; + } + + /* Initialize the Bluetooth Mesh Subsystem */ + err = ble_mesh_init(); + if (err) { + ESP_LOGE(TAG, "Bluetooth mesh init failed (err %d)", err); + return; + } +} diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.c b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.c new file mode 100644 index 0000000000..4c51d04af7 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.c @@ -0,0 +1,72 @@ +// Copyright 2017-2018 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 + +#include "driver/gpio.h" +#include "board.h" +#include "esp_fast_prov_common.h" + +#define TAG "BOARD" + +struct _led_state led_state[3] = { + { LED_OFF, LED_OFF, LED_R, "red" }, + { LED_OFF, LED_OFF, LED_G, "green" }, + { LED_OFF, LED_OFF, LED_B, "blue" }, +}; + +void board_output_number(esp_ble_mesh_output_action_t action, uint32_t number) +{ + ESP_LOGI(TAG, "Board output number %d", number); +} + +void board_prov_complete(void) +{ + board_led_operation(LED_B, LED_OFF); +} + +void board_led_operation(uint8_t pin, uint8_t onoff) +{ + for (int i = 0; i < 3; i++) { + if (led_state[i].pin != pin) { + continue; + } + if (onoff == led_state[i].previous) { + ESP_LOGW(TAG, "led %s is already %s", + led_state[i].name, (onoff ? "on" : "off")); + return; + } + gpio_set_level(pin, onoff); + led_state[i].previous = onoff; + return; + } + + ESP_LOGE(TAG, "LED is not found!"); +} + +static void board_led_init(void) +{ + for (int i = 0; i < 3; i++) { + gpio_pad_select_gpio(led_state[i].pin); + gpio_set_direction(led_state[i].pin, GPIO_MODE_OUTPUT); + gpio_set_level(led_state[i].pin, LED_OFF); + led_state[i].previous = LED_OFF; + } +} + +esp_err_t board_init(void) +{ + board_led_init(); + return ESP_OK; +} diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.h b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.h new file mode 100644 index 0000000000..b00fc1e04b --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.h @@ -0,0 +1,47 @@ +// Copyright 2017-2018 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. + +#ifndef _BOARD_H_ +#define _BOARD_H_ + +#include "sdkconfig.h" +#include "driver/gpio.h" +#include "esp_ble_mesh_defs.h" + +#ifdef CONFIG_BLE_MESH_ESP_WROOM_32 +#define LED_R GPIO_NUM_25 +#define LED_G GPIO_NUM_26 +#define LED_B GPIO_NUM_27 +#elif defined(CONFIG_BLE_MESH_ESP_WROVER) +#define LED_R GPIO_NUM_0 +#define LED_G GPIO_NUM_2 +#define LED_B GPIO_NUM_4 +#endif + +struct _led_state { + uint8_t current; + uint8_t previous; + uint8_t pin; + char *name; +}; + +void board_output_number(esp_ble_mesh_output_action_t action, uint32_t number); + +void board_prov_complete(void); + +void board_led_operation(uint8_t pin, uint8_t onoff); + +esp_err_t board_init(void); + +#endif diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/component.mk b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/component.mk new file mode 100644 index 0000000000..a98f634eae --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/component.mk @@ -0,0 +1,4 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/sdkconfig.defaults b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/sdkconfig.defaults new file mode 100644 index 0000000000..4f6ca5787a --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/sdkconfig.defaults @@ -0,0 +1,51 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y +CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY= +CONFIG_BTDM_CONTROLLER_MODE_BTDM= +CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n +CONFIG_BLE_SCAN_DUPLICATE=y +CONFIG_SCAN_DUPLICATE_TYPE=2 +CONFIG_DUPLICATE_SCAN_CACHE_SIZE=200 +CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y +CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE=200 +CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y +CONFIG_GATTS_ENABLE=y +CONFIG_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_HCI_5_0=y +CONFIG_BLE_MESH_USE_DUPLICATE_SCAN=y +CONFIG_BLE_MESH_FAST_PROV=y +CONFIG_BLE_MESH_PROV=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PROVISIONER=y +CONFIG_BLE_MESH_WAIT_FOR_PROV_MAX_DEV_NUM=20 +CONFIG_BLE_MESH_MAX_STORED_NODES=10 +CONFIG_BLE_MESH_MAX_PROV_NODES=6 +CONFIG_BLE_MESH_PBA_SAME_TIME=3 +CONFIG_BLE_MESH_PBG_SAME_TIME=3 +CONFIG_BLE_MESH_PROVISIONER_SUBNET_COUNT=3 +CONFIG_BLE_MESH_PROVISIONER_APP_KEY_COUNT=9 +CONFIG_BLE_MESH_PB_ADV=y +CONFIG_BLE_MESH_NET_BUF_POOL_USAGE=y +CONFIG_BLE_MESH_SUBNET_COUNT=2 +CONFIG_BLE_MESH_APP_KEY_COUNT=3 +CONFIG_BLE_MESH_MODEL_KEY_COUNT=3 +CONFIG_BLE_MESH_MODEL_GROUP_COUNT=3 +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_GATT_PROXY=y +CONFIG_BLE_MESH_RELAY=y +CONFIG_BLE_MESH_LOW_POWER= +CONFIG_BLE_MESH_FRIEND= +CONFIG_BTU_TASK_STACK_SIZE=4512 +CONFIG_BLE_MESH_CFG_CLI=y +CONFIG_BLE_MESH_CRPL=60 +CONFIG_BLE_MESH_MSG_CACHE_SIZE=60 +CONFIG_BLE_MESH_ADV_BUF_COUNT=200 +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SDU_MAX=384 +CONFIG_BLE_MESH_TX_SEG_MAX=32 +CONFIG_BLE_MESH_NO_LOG=n +CONFIG_BLE_MESH_STACK_TRACE_LEVEL=0 \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/EspBleMesh.md b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/EspBleMesh.md new file mode 100644 index 0000000000..274ecf581d --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/EspBleMesh.md @@ -0,0 +1,93 @@ +# Demo Function + +This demo demonstrates the fast provisioning of ESP BLE Mesh network and how to use the EspBleMesh app to control an individual provisioned node or all the provisioned nodes. + +A video of this demo can be seen +[here](http://download.espressif.com/BLE_MESH/BLE_Mesh_Demo/V0.4_Demo_Fast_Provision/ESP32_BLE_Mesh_Fast_Provision.mp4) + +# What You Need + +* [EspBleMesh App for Android](http://download.espressif.com/BLE_MESH/BLE_Mesh_Tools/BLE_Mesh_App/EspBleMesh-0.9.4.apk) +* [ESP BLE Mesh SDK v0.6(Beta Version)](https://glab.espressif.cn/ble_mesh/esp-ble-mesh-v0.6) +* ESP32 Development Boards + +> Note: +> +> 1. Please flash the [`ble_mesh_fast_prov_server`](https://glab.espressif.cn/ble_mesh/esp-ble-mesh-v0.6/tree/ble_mesh_release/esp-ble-mesh-v0.6/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server) to your boards first; +> 2. To have a better understanding of the performance of the BLE Mesh network, we recommend that at least 3 devices should be added in your network. +> 3. We recommend that you solder LED indicators if your development board does not come with lights. +> 4. Please check the type of board and LED pin definition enabled in `Example BLE Mesh Config` by running `make menuconfig` + +![Board](images/device.png) + + +# Flash and Monitor + +1. Enter the directory: +examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server +2. Make sure that the `IDF_PATH` environment variable was set in accordance with your current IDF path +3. Check the version of your toolchain. Version 4.1 or newer should be used. + +![Checkenvironment](images/picture1.png) + +4. Run `make -j4 flash` to compile codes and flash the codes to the device. + +![compiledcode](images/picture2.png) + +> Note: +> +> Please click on the Exit button if you see the following windows. + + +5. Please establish a connection between your device and PC, using the correct serial number, if you want to monitor the operation of this device on PC. + +# How to Use the App + +Please launch the `EspBleMesh` app, and follow the steps described below to establish a BLE Mesh network and control any individual node or all the nodes. + +![App steps](images/app_ble.png) +1. Click on the upper left corner to see more options; +2. Click on **Provisioning** to scan nearby unprovisioned devices; +3. Choose any unprovisioned devices in the scanned list; +4. Enter the number of devices you want to add in your mesh network; +> Note: +> +> If you only want to use the normal provisioning feature,You don't check the option for fast provisioning. +5. Wait until all the devices are provisioned; +6. Click on the upper left corner to see more options; +7. Click on **Fast Provisioned** to see all the provisioned devices; +8. Control your devices. + +> Note: +> +> Please disable your Bluetooth function on your phone, enable it and try again, if you have encountered any connection issues. + + +# Procedure + +## Role + +* Phone - Top Provisioner +* The device that has been provisioned by Phone - Primary Provisioner +* Devices that have been provisioned and changed to the role of a provisioner - Temporary Provisioner +* Devices that have been provisioned but not changed to the role of a provisioner - Node + +## Interaction + +![Interaction](images/time.png) +1. The Top Provisioner configures the first device to access the network with the GATT bearer. +2. The Top Provisioner sends the `send_config_appkey_add` message to allocate the Appkey to this device. +3. The Top Provisioner sends the `send_fast_prov_info_set` message to provide the necessary information so the device can be changed to a Primary Provisioner. +4. The device calls the `esp_ble_mesh_set_fast_prov_action` API to change itself into the role of a Primary Provisioner and disconnects with the Top Provisioner. +5. The Primary Provisioner sends the `send_config_appkey_add` message to allocate the Appkey to an other device. +6. The Primary Provisioner sends the `send_fast_prov_info_set` message to provide the necessary information so the device can be changed to a Temporary Provisioner. +7. The device calls the `esp_ble_mesh_set_fast_prov_action` API to change itself into the role of a Temporary Provisioner and starts its address timer. +8. The Temporary Provisioner collects the addresses of nodes that it has provisioned and sends these addresses to the Primary Provisioner, when its address timer times out, which indicates the Temporary Provisioner hasn't provisioned any devices for 10s. +9. The Primary Provisioner reconnects to the Top Provisioner when its address timer times out, which indicates the Primary Provisioner hasn't received any messages from the Temporary Provisioners for 10s. +10. The Top Provisioner sends the `node_adress_Get` message automatically after reconnecting with the Primary Provisioner. +11. At this point, the Top Provisioner is able to control any nodes in the BLE Mesh Network. + +> Note: +> +> The nodes in the BLE Mesh Network only disable its provisioner functionality after it has been controlled by the Top Provisioner for at least one time. + diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/ble_mesh_fast_provision_server.md b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/ble_mesh_fast_provision_server.md new file mode 100644 index 0000000000..d1e597cda6 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/ble_mesh_fast_provision_server.md @@ -0,0 +1,409 @@ +# 1. Introduction +## 1.1 Demo Function + +This demo is used for fast provisioning networks. It takes no more than 60 seconds to provisioning 100 devices in this demo. + +This demo must be used with the EspBleMesh app. For details about how to use the EspBleMesh app, please click [here](EspBleMesh.md). + +## 1.2 Node Composition + +This demo has only one element, where the following five Models are implemented: + +- The **Configuration Server** Model is used to represent a mesh network configuration of a device. +- The **Configuration Client** Model is used to represent an element that can control and monitor the configuration of a node. +- The **Generic OnOff Server** Model implements the node's Onoff state. +- The **Vendor Server** Model implements the node's `fast_prov_server` state. +- The **Vendor Client** Model is used to control the `fast_prov_server` state, which defines the fast provisioning behavior of a node. + + +## 2. Code Analysis + +Code initialization part reference [Initializing the Bluetooth and Initializing the BLE Mesh](../../../ble_mesh_wifi_coexist/tutorial%20%20%20%20%20%20/ble_mesh_wifi_coexist.md) + +### 2.1 Data Structure + +This section introduces the `example_fast_prov_server_t` strut for this demo, and its variables in groups. + +``` +typedef struct { + esp_ble_mesh_model_t *model; /* Fast Prov Server Model pointer */ + ATOMIC_DEFINE(srv_flags, SRV_MAX_FLAGS); + + bool primary_role; /* Indicate if the device is a Primary Provisioner */ + uint8_t max_node_num; /* The maximum number of devices can be provisioned by the Provisioner */ + uint8_t prov_node_cnt; /* Number of self-provisioned nodes */ + uint16_t app_idx; /* AppKey index of the application key added by other Provisioner */ + uint16_t top_address; /* Address of the device(e.g. phone) which triggers fast provisioning */ + + esp_ble_mesh_msg_ctx_t ctx; /* the context stored for sending fast prov status message */ + struct fast_prov_info_set *set_info; /* Used to store received fast prov info set context */ + + uint16_t node_addr_cnt; /* Number of node address shall be received */ + uint16_t unicast_min; /* Minimum unicast address can be send to other nodes */ + uint16_t unicast_max; /* Maximum unicast address can be send to other nodes */ + uint16_t unicast_cur; /* Current unicast address can be assigned */ + uint16_t unicast_step; /* Unicast address change step */ + uint8_t flags; /* Flags state */ + uint32_t iv_index; /* Iv_index state */ + uint16_t net_idx; /* Netkey index state */ + uint16_t group_addr; /* Subscribed group address */ + uint16_t prim_prov_addr; /* Unicast address of Primary Provisioner */ + uint8_t match_val[16]; /* Match value to be compared with unprovisioned device UUID */ + uint8_t match_len; /* Length of match value to be compared */ + + uint8_t pend_act; /* Pending action to be performed */ + uint8_t state; /* Fast prov state -> 0: idle, 1: pend, 2: active */ + + struct k_delayed_work disable_fast_prov_timer; /* Used to disable fast provisioning */ + struct k_delayed_work gatt_proxy_enable_timer; /* Used to Mesh GATT Proxy functionality */ +} __attribute__((packed)) example_fast_prov_server_t; +``` + + +#### 2.1.1 Provisioner Role and State + +Different provisioners have different behaviors and it’s helpful to understand the concepts of different roles so you can better understand the codes. + +In the struct, there are three variables that are related to roles and states, which are described in the following table: + +| Variable Name |Description | +| ---------------------|------------------------- | +| `primary_role` | Provisioner identity | +| `state` | Fast provisioner state (0: idle, 1: pend, 2: active) | +| `srv_flags` | Flags (`DISABLE_FAST_PROV_START`,`GATT_PROXY_ENABLE_START`,`RELAY_PROXY_DISABLED`,`SRV_MAX_FLAGS`) | + +Among which, there are four roles in this demo (`primary_role`): + +* Phone - Top Provisioner +* The device that has been provisioned by Phone - Primary Provisioner +* Devices that have been provisioned and changed to the role of a provisioner - Temporary Provisioner +* Devices that have been provisioned but not changed to the role of a provisioner - Node + + +#### 2.1.2 Provisioner Address Management + +The provisioner address management is used to assign a unicast address to each node, so as to prevent address conflicts by allocating address in an equally manner. Each provisioner has its own address range and a maximum number of the nodes it can provisioned. The provisioner will allocate a subset of its address range to the nodes it has provisioned. + +Example: A top provisioner's address range is 0 to 100 and the maximum number of nodes it can provisioned is 5. The provisioner address management will assign subsets of address range to these 5 nodes, which are 1 to 20, 21 to 40, 41 to 60, 61 to 80 and 81 to 100. + +The variables that are related to the address management are described in the following table: + +| Variable Name |Description | +| ----------------------|------------------------- | +| `unicast_min` | Minimum unicast address can be allocated to other nodes | +| `unicast_max` | Maximum unicast address can be allocated to other nodes | +| `unicast_cur` | Current unicast address | +| `unicast_step` | Unicast address change step Offset| + +#### 2.1.3 Provisioner Cache Data + +The cache data is required, so a node can change its role to become a provisioner. During this process, the `esp_ble_mesh_set_fast_prov_info` and `esp_ble_mesh_set_fast_prov_action` APIs are called. + +The node's cache data, which are described in the following table, is sent by the provisioner. + +| Variable Name |Description | +| ----------------------|------------------------- | +| `flags` |Flags state| +| `iv_index` |Iv_index state| +| `net_idx` |Netkey index state | +| `group_addr` |Subscribed group address | +| `prim_prov_addr` |Unicast address of Primary Provisioner | +| `match_val[16]` |Match value to be compared with unprovisioned device UUID | +| `match_len` | Length of match value to be compared | +| `max_node_num` | The maximum number of devices can be provisioned by the Provisioner | +| `prov_node_cnt` | Number of self-provisioned nodes | +| `app_idx` | AppKey index of the application key added by other Provisioner | +| `top_address` | Address of the device(e.g. phone) which triggers fast provisioning | + + +#### 2.1.4 Provisioner Timer + +There are two timers in this demo, which are: + +1. `gatt_proxy_enable_timer` is used to enable Mesh GATT Proxy functionality. + * The timer starts or resets and starts when a Temporary Provisioner provisions an unprovisioned device. + * The Temporary Provisioner will send a message (Address information) to the Primary Provisioner. +2. `disable_fast_prov_timer` is used to disable the provisioning capabilities. + * The node starts the timer when it receives a **Generic OnOff Get/Set/Set Unack** message sent by the EspBleMesh app. The group address should be used if you want to disable the provisioning capabilities of all nodes. + +The variables that are related to these two timers are described below: + +| Variable Name |Description | +| ----------------------|------------------------- | +| `disable_fast_prov_timer` |Used to disable fast provisioning| +| `gatt_proxy_enable_timer` |Used to enable Mesh GATT Proxy functionality| + +### 2.2 Model Definition + +#### 2.2.1 Vendor Server Model + +The **Vendor Server** Model implements the node's `fast_prov_server` state, which has been covered in the previous section. + +```c +example_fast_prov_server_t fast_prov_server = { + .primary_role = false, + .max_node_num = 6, + .prov_node_cnt = 0x0, + .unicast_min = ESP_BLE_MESH_ADDR_UNASSIGNED, + .unicast_max = ESP_BLE_MESH_ADDR_UNASSIGNED, + .unicast_cur = ESP_BLE_MESH_ADDR_UNASSIGNED, + .unicast_step = 0x0, + .flags = 0x0, + .iv_index = 0x0, + .net_idx = ESP_BLE_MESH_KEY_UNUSED, + .app_idx = ESP_BLE_MESH_KEY_UNUSED, + .group_addr = ESP_BLE_MESH_ADDR_UNASSIGNED, + .prim_prov_addr = ESP_BLE_MESH_ADDR_UNASSIGNED, + .match_len = 0x0, + .pend_act = FAST_PROV_ACT_NONE, + .state = STATE_IDLE, +}; +``` + +The `fast_prov_srv_op` is used to register the minimum length of messages. For example, the minimum length of the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET` message is registered as 3 octets. + +```c +static esp_ble_mesh_model_op_t fast_prov_srv_op[] = { + { ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET, 3, NULL }, + { ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD, 16, NULL }, + { ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR, 2, NULL }, + { ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET, 0, NULL }, + ESP_BLE_MESH_MODEL_OP_END, +}; + +``` +The `example_fast_prov_server_init` function is used to register the callback function triggered when the timers timeout, and initializes the Model-related variables in the data struct. + +```c +err = example_fast_prov_server_init(&vnd_models[0]); +if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to initialize fast prov server model", __func__); + return err; +} +``` + +The `fast_prov_server` struct represents the Vendor server's states. The `CID_ESP` and `ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_SRV` constants, which consist of the vendor server Model's Model id `ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_SRV`, are used to identity the Vendor server Model. + + +```c +static esp_ble_mesh_model_t vnd_models[] = { + ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_SRV, + fast_prov_srv_op, NULL, &fast_prov_server), +}; +static esp_ble_mesh_elem_t elements[] = { + ESP_BLE_MESH_ELEMENT(0, root_models, vnd_models), +}; +``` + + +#### 2.2.2 Vendor Client Model + +The **Vendor Client** Model is used to control the `fast_prov_server` state, which defines the fast provisioning behavior of a node. + +The `fast_prov_cli_op_pair` struct is used to register the corresponding message acknowledgements. + +```c +static const esp_ble_mesh_client_op_pair_t fast_prov_cli_op_pair[] = { + { ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS }, + { ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS }, + { ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK }, + { ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS }, +}; +``` + +Example: The **Vendor Client** Model sends message with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET`, which requires the **Vendor Server** Model to respond with a message with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS`. After that, the **Vendor Client** Model times out if it receives no corresponding acknowledgement. + +```c +static const esp_ble_mesh_client_op_pair_t fast_prov_cli_op_pair[] = { + { ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS }, +}; +``` +Note that you can also use the code below if you don't want the **Vendor Client** Model to wait for acknowledgement from the server Model, which means the client Model will never time out. + +```c +static const esp_ble_mesh_client_op_pair_t fast_prov_cli_op_pair[] = { + { ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET, NULL }, +}; +``` + +The `esp_ble_mesh_client_model_init` API is used to register the callback function triggered when the timers timeout, and initializes the Model-related variables in the data struct. + +```c +err = esp_ble_mesh_client_model_init(&vnd_models[1]); +if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to initialize fast prov client Model", __func__); + return err; +} +``` + +The `CID_ESP` and `ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_CLI` constants, which consist of the vendor client Model's Model id `ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_CLI`, are used to identity the Vendor client Model. + +```c + +esp_ble_mesh_client_t fast_prov_client = { + .op_pair_size = ARRAY_SIZE(fast_prov_cli_op_pair), + .op_pair = fast_prov_cli_op_pair, +}; + +static esp_ble_mesh_model_op_t fast_prov_cli_op[] = { + { ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS, 1, NULL }, + { ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS, 2, NULL }, + { ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK, 0, NULL }, + ESP_BLE_MESH_MODEL_OP_END, +}; + +static esp_ble_mesh_model_t vnd_models[] = { + ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_CLI, + fast_prov_cli_op, NULL, &fast_prov_client), +}; +static esp_ble_mesh_elem_t elements[] = { + ESP_BLE_MESH_ELEMENT(0, root_models, vnd_models), +}; + +``` + +## 2.3 Message Opcode + +"Opcode-send" represents the message that the client sends to the server. + +"Opcode-ack" represents the message that the server sends to the client. + +* INFO_SET + +|Meaning | Opcode-send | Opcode-ack | +| -----| ------------- | -------------| +|Opcode| `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET` | `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS` | +|Function| This message contains all the information as a Provisioner |Checks each field of the Provisioner information and set the corresponding flag bit. The returned status is variable.| +|Parameter|structfast_prov_info_set|status_bit_mask, status_ctx_flag, status_unicast, status_net_idx, status_group, status_pri_prov, status_match, status_action| + + +* NODE_ADDR + +|Meaning | Opcode-send | Opcode-ack | +| -----| ------------- | -------------| +|Opcode| `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR` | `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK` | +|Function| Temporary Provisioner reports the address of the node it has provisioned. |Used to check if the message was sent successfully. | +|Parameter| Address array |NA | + +* ADDR_GET + +|Meaning | Opcode-send | Opcode-ack | +| -----| ------------- | -------------| +|Opcode| `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET` | `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS` | +|Function|Top Provisioner gets the address of all nodes obtained from Primary Provisioner. | Returns the address of all nodes, but does not contain its own. | +|Parameter|NA |Address array | + +* NET_KEY_ADD + +|Meaning | Opcode-send | Opcode-ack | +| -----| ------------- | -------------| +|Opcode | `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD` | `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS` | +|Function| Reserved for later use | Reserved for later use | +|Parameter| NA | NA | + + +### 2.4 Callback Function +#### 2.4.1 The Callback function for the Vendor Server Model + +```c + esp_ble_mesh_register_custom_model_callback(example_ble_mesh_custom_model_cb); + esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb); +``` + +1. The callback function will be triggered when the **Vendor Server** Model: + * Receives a message that indicates the Onoff state of the client Model; or + * Calls any APIs that send messages. + +2. The events that this callback function handle: + +* Generic Onoff Server Model + +| Event Name | Opcode |Description | +| ------------- | ------------|------------------------------------------- | +| ESP_BLE_MESH_MODEL_OPERATION_EVT|ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET | This event is triggered when the **Generic Onoff Server** model receives the `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET` message | +| ESP_BLE_MESH_MODEL_OPERATION_EVT|ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK| This event is triggered when the **Generic Onoff Server** model receives the `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK` message. | + +* Vendor Server Model + +| Event Name | Opcode |Description | +| ------------- | ------------|------------------------------------------- | +| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET | This event is triggered when the **Vendor Server** model receives the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET` message.| +| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR | This event is triggered when the **Vendor Server** model receives the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR` message.| +| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET | This event is triggered when the **Vendor Server** model receives the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET` message.| + +* The **Configuration Client** Model + +| Event Name | Opcode |Description | +| ------------- | ------------|------------------------------------------- | +|ESP_BLE_MESH_SET_FAST_PROV_INFO_COMP_EVT| NA| This event is triggered when the `esp_ble_mesh_set_fast_prov_info` API is called. | +|ESP_BLE_MESH_SET_FAST_PROV_ACTION_COMP_EVT| NA| This event is triggered when the `esp_ble_mesh_set_fast_prov_action` API is called. | +|ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT|ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD|This event is triggered when the **Configuration Server** model receives and further triggers an API calling to send `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET` message. | +|ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT|ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD|This event is triggered when the API `example_send_config_appkey_add` times out.| + +#### 2.4.2 The Vendor Client Model + +```c + esp_ble_mesh_register_custom_model_callback(example_ble_mesh_custom_model_cb); +``` + +1. The callback function will be triggered when the **Vendor Client** model: + * Receives any message sent by the vendor server Model; or + * Calls any APIs that send messages. + +2. The events that this callback function handle: + +| Event Name | Opcode |Description | +| ------------- | ------------|------------------------------------------- | +| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS | This event is triggered when the **Vendor Client** model receives the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS` message.| +| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS | This event is triggered when the **Vendor Client** model receives the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS` message.| +| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK | This event is triggered when the **Vendor Client** model receives the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK` message | +| ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT | client_send_timeout.opcode | This event is triggered when the API `esp_ble_mesh_client_model_send_msg` times out.| + +### 2.5 Message Sending +#### 2.5.1 The Vendor Client sends messages + +The Vendor Client Model calls the `esp_ble_mesh_client_model_send_msg` API to send messages to the Vendor Server Model. + +| Parameter Name |Description | +| ----------------------|------------------------- | +| `model` | The pointer to the client Model struct | +| `ctx.net_idx` | The NetKey Index of the subnet through which the message is sent | +| `ctx.app_idx` | The AppKey Index for the message encryption | +| `ctx.addr` | The address of the destination nodes | +| `ctx.send_ttl`| The TTL State, which determines how many times a message can be relayed| +| `ctx.send_rel`| This parameter determines whether the Model will wait for an acknowledgment after sending a message | +| `opcode` | The message opcode | +| `msg->len` | The length of the `msg->data`| +| `msg->data` | The pointer to sent data| +| `msg_timeout` | The maximum duration (4000 ms by default) that the Model waits for an acknowledgment. | +|`true` | True: an acknowledgement is required; False: no acknowledgement is required | +| `msg_role` | The role of a message (node/provisioner) | + +```c +esp_ble_mesh_msg_ctx_t ctx = { + .net_idx = info->net_idx, + .app_idx = info->app_idx, + .addr = info->dst, + .send_rel = false, + .send_ttl = 0, + }; + err = esp_ble_mesh_client_model_send_msg(model, &ctx, + ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET, + msg->len, msg->data, info->timeout, true, info->role); +``` + +#### 2.5.2 The Vendor Server sends messages + +The **Vendor Server** Model has to bind its Appkey before calling the `esp_ble_mesh_server_model_send_msg` API to send a message. + +```c +esp_ble_mesh_server_model_send_msg(model, ctx, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS, + msg->len ,msg->data ); +``` +The **Vendor Server** Model calls the `esp_ble_mesh_model_publish` API to publish messages. Only the Models that have subscribed to this destination address receive the published messages. + +```c +esp_err_t esp_ble_mesh_model_publish(esp_ble_mesh_model_t *model, uint32_t opcode, + uint16_t length, uint8_t *data, + esp_ble_mesh_dev_role_t device_role); +``` diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/app_ble.png b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/app_ble.png new file mode 100644 index 0000000000000000000000000000000000000000..e62b7577899d5a1f3e205a3bce80af5e3f55617f GIT binary patch literal 182199 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 z

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 z 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 literal 0 HcmV?d00001 diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/device.png b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/device.png new file mode 100644 index 0000000000000000000000000000000000000000..5caaa973acb18ce1e9f0f9b633435e454fcc2669 GIT binary patch literal 356234 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�U7~=`OM%DHy(gd8T|M4`3E2C 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%0A|kJEd_g@=Irpn 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

sG{6n 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 z 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 lR5bR})a^n@&mK~dDs~iRzp6nSx*d|*p`saH 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 literal 0 HcmV?d00001 diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/time.png b/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/time.png new file mode 100644 index 0000000000000000000000000000000000000000..5f11ae49b41ee95f25fd42309209e5054744a709 GIT binary patch literal 56788 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%0AyH;JiAc495) zqZbX9I`3@GEzsE*$syH}Jjxrjn;5THjHWky^&Yuq$45FiHrAfnpJDsLcOyf75;9~l|Z(bWxHPKMO9^)3j#CU&+l>9)wMlxxME zu#Nk@jmiB;uboLv;Z)(S>I{~0cb`vGSmA z7B}j>zZ0{w+uK)YxMi_Khg%+#cYZ8bak~a z^H2sHSB|uQWF#~uCPqh3F9cCy7pf+E*Q|4CVRY2s)m08|ZmQnXCol7~!n!tf>yexM z;e*B|d={G+_glGDKHG!U@3fUer9^ar`Nmqw!9dOUt4vyE^WyiaXJFHq(RYxY^XZW{ z6dtl@TV5zpBFovSt$6Tv(ZD(n!hqyb{s(+9?9ry=5jtkL8i_|wb(Y=a?<#{2Xuvwt u;7}YftA2i;o2dV;`hSUQ_}}PqYJ8*oI56 Example Configuration --> This option facilitates sending with 20ms non-connectable interval...` + +For a better demonstration effect, an RGB LED can be soldered onto the ESP32-DevKitC board, by connecting their corresponding GPIO pins are GPIO\_NUM\_25, GPIO\_NUM\_26, GPIO\_NUM\_27. Then you need to select the following option in menuconfig: + `make menuconfig --> Example Configuration --> Board selection for BLE Mesh --> ESP-WROOM-32` + +Please check the [tutorial](tutorial/Ble_Mesh_Node_Example_Walkthrough.md) for more information about this example. diff --git a/examples/bluetooth/ble_mesh/ble_mesh_node/main/CMakeLists.txt b/examples/bluetooth/ble_mesh/ble_mesh_node/main/CMakeLists.txt new file mode 100644 index 0000000000..1eb2d87ed2 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_node/main/CMakeLists.txt @@ -0,0 +1,6 @@ +set(COMPONENT_SRCS "ble_mesh_demo_main.c" + "board.c") + +set(COMPONENT_ADD_INCLUDEDIRS ".") + +register_component() diff --git a/examples/bluetooth/ble_mesh/ble_mesh_node/main/Kconfig.projbuild b/examples/bluetooth/ble_mesh/ble_mesh_node/main/Kconfig.projbuild new file mode 100644 index 0000000000..18776a7a39 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_node/main/Kconfig.projbuild @@ -0,0 +1,22 @@ +menu "Example Configuration" + + choice BLE_MESH_EXAMPLE_BOARD + prompt "Board selection for BLE Mesh" + default BLE_MESH_ESP_WROOM_32 + help + Select this option to choose the board for BLE Mesh. The default is ESP32-WROOM-32 + + config BLE_MESH_ESP_WROOM_32 + bool "ESP32-WROOM-32" + + config BLE_MESH_ESP_WROVER + bool "ESP32-WROVER" + endchoice + + config BLE_MESH_PATCH_FOR_SLAB_APP_1_1_0 + bool "Fix bug of Silicon Lab Android App v1.1.0 when reconnection will cause sequence number to recount from 0" + default y + help + It is an ad hoc solution and needs further modifications + +endmenu diff --git a/examples/bluetooth/ble_mesh/ble_mesh_node/main/ble_mesh_demo_main.c b/examples/bluetooth/ble_mesh/ble_mesh_node/main/ble_mesh_demo_main.c new file mode 100644 index 0000000000..0e0aeaf845 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_node/main/ble_mesh_demo_main.c @@ -0,0 +1,395 @@ +/* main.c - Application main entry point */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "esp_log.h" +#include "nvs_flash.h" + +#include "esp_bt.h" +#include "esp_bt_main.h" +#include "esp_bt_device.h" + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_common_api.h" +#include "esp_ble_mesh_networking_api.h" +#include "esp_ble_mesh_provisioning_api.h" +#include "esp_ble_mesh_config_model_api.h" + +#include "board.h" + +#define TAG "ble_mesh_node" + +#define CID_ESP 0x02E5 + +extern struct _led_state led_state[3]; + +static uint8_t dev_uuid[16] = { 0xdd, 0xdd }; + +static esp_ble_mesh_cfg_srv_t config_server = { + .relay = ESP_BLE_MESH_RELAY_DISABLED, + .beacon = ESP_BLE_MESH_BEACON_ENABLED, +#if defined(CONFIG_BLE_MESH_FRIEND) + .friend_state = ESP_BLE_MESH_FRIEND_ENABLED, +#else + .friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED, +#endif +#if defined(CONFIG_BLE_MESH_GATT_PROXY) + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED, +#else + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED, +#endif + .default_ttl = 7, + /* 3 transmissions with 20ms interval */ + .net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20), + .relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20), +}; + +ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub, 2 + 1, ROLE_NODE); + +static esp_ble_mesh_model_op_t onoff_op[] = { + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET, 0), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, 2), + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2), + /* Each model operation struct array must use this terminator + * as the end tag of the operation uint. */ + ESP_BLE_MESH_MODEL_OP_END, +}; + +static esp_ble_mesh_model_t root_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&config_server), + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, onoff_op, + &onoff_pub, &led_state[0]), +}; + +static esp_ble_mesh_model_t extend_model_0[] = { + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, onoff_op, + &onoff_pub, &led_state[1]), +}; + +static esp_ble_mesh_model_t extend_model_1[] = { + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, onoff_op, + &onoff_pub, &led_state[2]), +}; + +static esp_ble_mesh_elem_t elements[] = { + ESP_BLE_MESH_ELEMENT(0, root_models, ESP_BLE_MESH_MODEL_NONE), + ESP_BLE_MESH_ELEMENT(0, extend_model_0, ESP_BLE_MESH_MODEL_NONE), + ESP_BLE_MESH_ELEMENT(0, extend_model_1, ESP_BLE_MESH_MODEL_NONE), +}; + +static esp_ble_mesh_comp_t composition = { + .cid = CID_ESP, + .elements = elements, + .element_count = ARRAY_SIZE(elements), +}; + +/* Disable OOB security for SILabs Android app */ +static esp_ble_mesh_prov_t provision = { + .uuid = dev_uuid, +#if 0 + .output_size = 4, + .output_actions = ESP_BLE_MESH_DISPLAY_NUMBER, + .input_actions = ESP_BLE_MESH_PUSH, + .input_size = 4, +#else + .output_size = 0, + .output_actions = 0, +#endif +}; + +static int output_number(esp_ble_mesh_output_action_t action, uint32_t number) +{ + board_output_number(action, number); + return 0; +} + +static void prov_complete(uint16_t net_idx, uint16_t addr, uint8_t flags, uint32_t iv_index) +{ + ESP_LOGI(TAG, "net_idx: 0x%04x, addr: 0x%04x", net_idx, addr); + ESP_LOGI(TAG, "flags: 0x%02x, iv_index: 0x%08x", flags, iv_index); + board_prov_complete(); +} + +static void gen_onoff_get_handler(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, + uint16_t length, uint8_t *data) +{ + struct _led_state *led = (struct _led_state *)model->user_data; + uint8_t send_data; + esp_err_t err; + + ESP_LOGI(TAG, "%s, addr 0x%04x onoff 0x%02x", __func__, model->element->element_addr, led->current); + + send_data = led->current; + /* Send Generic OnOff Status as a response to Generic OnOff Get */ + err = esp_ble_mesh_server_model_send_msg(model, ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, + sizeof(send_data), &send_data); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Generic OnOff Status failed", __func__); + return; + } +} + +static void gen_onoff_set_unack_handler(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, + uint16_t length, uint8_t *data) +{ + struct _led_state *led = (struct _led_state *)model->user_data; + uint8_t prev_onoff; + esp_err_t err; + + ESP_LOGI(TAG, "%s, addr 0x%02x onoff 0x%02x", __func__, model->element->element_addr, led->current); + + prev_onoff = led->previous; + led->current = data[0]; + + board_led_operation(led->pin, led->current); + + /* If Generic OnOff state is changed, and the publish address of Generic OnOff Server + * model is valid, Generic OnOff Status will be published. + */ + if (prev_onoff != led->current && model->pub->publish_addr != ESP_BLE_MESH_ADDR_UNASSIGNED) { + ESP_LOGI(TAG, "Publish previous 0x%02x current 0x%02x", prev_onoff, led->current); + err = esp_ble_mesh_model_publish(model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, + sizeof(led->current), &led->current, ROLE_NODE); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Publish Generic OnOff Status failed", __func__); + return; + } + } +} + +static void gen_onoff_set_handler(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, + uint16_t length, uint8_t *data) +{ + struct _led_state *led = (struct _led_state *)model->user_data; + uint8_t prev_onoff, send_data; + esp_err_t err; + + ESP_LOGI(TAG, "%s, addr 0x%02x onoff 0x%02x", __func__, model->element->element_addr, led->current); + + prev_onoff = led->previous; + led->current = data[0]; + + board_led_operation(led->pin, led->current); + + send_data = led->current; + /* Send Generic OnOff Status as a response to Generic OnOff Get */ + err = esp_ble_mesh_server_model_send_msg(model, ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, + sizeof(send_data), &send_data); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Generic OnOff Status failed", __func__); + return; + } + + /* If Generic OnOff state is changed, and the publish address of Generic OnOff Server + * model is valid, Generic OnOff Status will be published. + */ + if (prev_onoff != led->current && model->pub->publish_addr != ESP_BLE_MESH_ADDR_UNASSIGNED) { + ESP_LOGI(TAG, "Publish previous 0x%02x current 0x%02x", prev_onoff, led->current); + err = esp_ble_mesh_model_publish(model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, + sizeof(send_data), &send_data, ROLE_NODE); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Publish Generic OnOff Status failed", __func__); + return; + } + } +} + +static char *esp_ble_mesh_prov_event_to_str(esp_ble_mesh_prov_cb_event_t event) +{ + switch (event) { + case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT: + return "ESP_BLE_MESH_PROV_REGISTER_COMP_EVT"; + case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT: + return "ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT"; + case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT: + return "ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT"; + case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT: + return "ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT"; + case ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT: + return "ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT"; + case ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT: + return "ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT"; + case ESP_BLE_MESH_NODE_PROV_INPUT_EVT: + return "ESP_BLE_MESH_NODE_PROV_INPUT_EVT"; + case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT: + return "ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT"; + case ESP_BLE_MESH_NODE_PROV_RESET_EVT: + return "ESP_BLE_MESH_NODE_PROV_RESET_EVT"; + default: + return "Invalid BLE Mesh provision event"; + } + + return NULL; +} + +static void esp_ble_mesh_prov_cb(esp_ble_mesh_prov_cb_event_t event, + esp_ble_mesh_prov_cb_param_t *param) +{ + ESP_LOGI(TAG, "%s, event = %s", __func__, esp_ble_mesh_prov_event_to_str(event)); + switch (event) { + case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROV_REGISTER_COMP_EVT, err_code %d", param->prov_register_comp.err_code); + break; + case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT, err_code %d", param->node_prov_enable_comp.err_code); + break; + case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT, bearer %s", + param->node_prov_link_open.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT"); + break; + case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT, bearer %s", + param->node_prov_link_close.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT"); + break; + case ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT: + output_number(param->node_prov_output_num.action, param->node_prov_output_num.number); + break; + case ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT: + break; + case ESP_BLE_MESH_NODE_PROV_INPUT_EVT: + break; + case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT: + prov_complete(param->node_prov_complete.net_idx, param->node_prov_complete.addr, + param->node_prov_complete.flags, param->node_prov_complete.iv_index); + break; + case ESP_BLE_MESH_NODE_PROV_RESET_EVT: + break; + case ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT, err_code %d", param->node_set_unprov_dev_name_comp.err_code); + break; + default: + break; + } + return; +} + +static void esp_ble_mesh_model_cb(esp_ble_mesh_model_cb_event_t event, + esp_ble_mesh_model_cb_param_t *param) +{ + switch (event) { + case ESP_BLE_MESH_MODEL_OPERATION_EVT: { + if (!param->model_operation.model || !param->model_operation.model->op || !param->model_operation.ctx) { + ESP_LOGE(TAG, "ESP_BLE_MESH_MODEL_OPERATION_EVT parameter is NULL"); + return; + } + switch (param->model_operation.opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET: + gen_onoff_get_handler(param->model_operation.model, param->model_operation.ctx, + param->model_operation.length, param->model_operation.msg); + break; + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: + gen_onoff_set_handler(param->model_operation.model, param->model_operation.ctx, + param->model_operation.length, param->model_operation.msg); + break; + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK: + gen_onoff_set_unack_handler(param->model_operation.model, param->model_operation.ctx, + param->model_operation.length, param->model_operation.msg); + break; + default: + break; + } + break; + } + case ESP_BLE_MESH_MODEL_SEND_COMP_EVT: + break; + case ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT: + break; + default: + break; + } +} + +static esp_err_t ble_mesh_init(void) +{ + int err = 0; + + memcpy(dev_uuid + 2, esp_bt_dev_get_address(), ESP_BD_ADDR_LEN); + + esp_ble_mesh_register_prov_callback(esp_ble_mesh_prov_cb); + esp_ble_mesh_register_custom_model_callback(esp_ble_mesh_model_cb); + + err = esp_ble_mesh_init(&provision, &composition); + if (err) { + ESP_LOGE(TAG, "Initializing mesh failed (err %d)", err); + return err; + } + + esp_ble_mesh_node_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT); + + ESP_LOGI(TAG, "BLE Mesh Node initialized"); + + board_led_operation(LED_G, LED_ON); + + return err; +} + +static esp_err_t bluetooth_init(void) +{ + esp_err_t ret; + + ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)); + + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + ret = esp_bt_controller_init(&bt_cfg); + if (ret) { + ESP_LOGE(TAG, "%s initialize controller failed", __func__); + return ret; + } + + ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); + if (ret) { + ESP_LOGE(TAG, "%s enable controller failed", __func__); + return ret; + } + ret = esp_bluedroid_init(); + if (ret) { + ESP_LOGE(TAG, "%s init bluetooth failed", __func__); + return ret; + } + ret = esp_bluedroid_enable(); + if (ret) { + ESP_LOGE(TAG, "%s enable bluetooth failed", __func__); + return ret; + } + + return ret; +} + +void app_main(void) +{ + int err; + + ESP_LOGI(TAG, "Initializing..."); + + board_init(); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "esp32_bluetooth_init failed (err %d)", err); + return; + } + + /* Initialize the Bluetooth Mesh Subsystem */ + err = ble_mesh_init(); + if (err) { + ESP_LOGE(TAG, "Bluetooth mesh init failed (err %d)", err); + } +} diff --git a/examples/bluetooth/ble_mesh/ble_mesh_node/main/board.c b/examples/bluetooth/ble_mesh/ble_mesh_node/main/board.c new file mode 100644 index 0000000000..50035a7ddd --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_node/main/board.c @@ -0,0 +1,130 @@ +/* board.c - Board-specific hooks */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" + +#include "driver/gpio.h" +#include "esp_log.h" +#include "board.h" +#include "esp_ble_mesh_provisioning_api.h" + +#define TAG "BOARD" + +#define INTR_FLAG_DEFAULT 0 + +static xQueueHandle s_evt_queue; + +struct _led_state led_state[3] = { + { LED_OFF, LED_OFF, LED_R, "red" }, + { LED_OFF, LED_OFF, LED_G, "green" }, + { LED_OFF, LED_OFF, LED_B, "blue" }, +}; + +void board_output_number(esp_ble_mesh_output_action_t action, uint32_t number) +{ + ESP_LOGI(TAG, "Board output number %d", number); +} + +void board_prov_complete(void) +{ + board_led_operation(LED_G, LED_OFF); +} + +void board_led_operation(uint8_t pin, uint8_t onoff) +{ + for (int i = 0; i < 3; i++) { + if (led_state[i].pin != pin) { + continue; + } + if (onoff == led_state[i].previous) { + ESP_LOGW(TAG, "led %s is already %s", + led_state[i].name, (onoff ? "on" : "off")); + return; + } + gpio_set_level(pin, onoff); + led_state[i].previous = onoff; + return; + } + + ESP_LOGE(TAG, "LED is not found!"); +} + +static void board_led_init(void) +{ + for (int i = 0; i < 3; i++) { + gpio_pad_select_gpio(led_state[i].pin); + gpio_set_direction(led_state[i].pin, GPIO_MODE_OUTPUT); + gpio_set_level(led_state[i].pin, LED_OFF); + led_state[i].previous = LED_OFF; + } +} + +static void IRAM_ATTR switch_isr_handler(void *arg) +{ + uint32_t gpio_num = (uint32_t) arg; + xQueueSendFromISR(s_evt_queue, &gpio_num, NULL); +} + +static void switch_key_init(uint32_t key) +{ + gpio_config_t io_conf; + io_conf.intr_type = GPIO_INTR_NEGEDGE; + io_conf.pin_bit_mask = 1 << key; + io_conf.mode = GPIO_MODE_INPUT; + io_conf.pull_up_en = 1; + io_conf.pull_down_en = 0; + gpio_config(&io_conf); + + gpio_set_intr_type(key, GPIO_INTR_NEGEDGE); + gpio_install_isr_service(INTR_FLAG_DEFAULT); + gpio_isr_handler_add(key, switch_isr_handler, (void *)key); +} + +static void switch_task_entry(void *arg) +{ + while (1) { + uint32_t io_num; + if (xQueueReceive(s_evt_queue, &io_num, portMAX_DELAY) == pdTRUE) { + uint8_t onoff = led_state[0].previous; + ESP_LOGI(TAG, "GPIO[%d] intr, val: %d", io_num, gpio_get_level(io_num)); + board_led_operation(LED_R, !onoff); + led_state[0].previous = !onoff; + //TODO: publish state change message + } + } +} + +static void switch_init(gpio_num_t gpio_num) +{ + s_evt_queue = xQueueCreate(3, sizeof(uint32_t)); + if (!s_evt_queue) { + return; + } + + BaseType_t ret = xTaskCreate(switch_task_entry, "switch", 4096, NULL, 4, NULL); + if (ret == pdFAIL) { + goto fail; + } + + switch_key_init(gpio_num); + return; + +fail: + vQueueDelete(s_evt_queue); +} + +void board_init(void) +{ + board_led_init(); + switch_init(GPIO_NUM_18); +} diff --git a/examples/bluetooth/ble_mesh/ble_mesh_node/main/board.h b/examples/bluetooth/ble_mesh/ble_mesh_node/main/board.h new file mode 100644 index 0000000000..4ae04b2ed4 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_node/main/board.h @@ -0,0 +1,42 @@ +/* board.h - Board-specific hooks */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _BOARD_H_ +#define _BOARD_H_ + +#include "driver/gpio.h" +#include "esp_ble_mesh_defs.h" + +#if defined(CONFIG_BLE_MESH_ESP_WROOM_32) +#define LED_R GPIO_NUM_25 +#define LED_G GPIO_NUM_26 +#define LED_B GPIO_NUM_27 +#elif defined(CONFIG_BLE_MESH_ESP_WROVER) +#define LED_R GPIO_NUM_0 +#define LED_G GPIO_NUM_2 +#define LED_B GPIO_NUM_4 +#endif + +#define LED_ON 1 +#define LED_OFF 0 + +struct _led_state { + uint8_t current; + uint8_t previous; + uint8_t pin; + char *name; +}; + +void board_output_number(esp_ble_mesh_output_action_t action, uint32_t number); + +void board_prov_complete(void); + +void board_led_operation(uint8_t pin, uint8_t onoff); + +void board_init(void); + +#endif diff --git a/examples/bluetooth/ble_mesh/ble_mesh_node/main/component.mk b/examples/bluetooth/ble_mesh/ble_mesh_node/main/component.mk new file mode 100644 index 0000000000..a98f634eae --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_node/main/component.mk @@ -0,0 +1,4 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/bluetooth/ble_mesh/ble_mesh_node/sdkconfig.defaults b/examples/bluetooth/ble_mesh/ble_mesh_node/sdkconfig.defaults new file mode 100644 index 0000000000..565e251ebd --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_node/sdkconfig.defaults @@ -0,0 +1,43 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y +CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY= +CONFIG_BTDM_CONTROLLER_MODE_BTDM= +CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n +CONFIG_BLE_SCAN_DUPLICATE=y +CONFIG_SCAN_DUPLICATE_TYPE=2 +CONFIG_DUPLICATE_SCAN_CACHE_SIZE=200 +CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y +CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE=200 +CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y +CONFIG_GATTS_ENABLE=y +CONFIG_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_HCI_5_0=y +CONFIG_BLE_MESH_USE_DUPLICATE_SCAN=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PROV=y +CONFIG_BLE_MESH_NET_BUF_POOL_USAGE=y +CONFIG_BLE_MESH_PROXY=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_GATT_PROXY=y +CONFIG_BLE_MESH_NODE_ID_TIMEOUT=60 +CONFIG_BLE_MESH_PROXY_FILTER_SIZE=1 +CONFIG_BLE_MESH_SUBNET_COUNT=1 +CONFIG_BLE_MESH_APP_KEY_COUNT=1 +CONFIG_BLE_MESH_MODEL_KEY_COUNT=1 +CONFIG_BLE_MESH_MODEL_GROUP_COUNT=1 +CONFIG_BLE_MESH_LABEL_COUNT=1 +CONFIG_BLE_MESH_CRPL=10 +CONFIG_BLE_MESH_MSG_CACHE_SIZE=10 +CONFIG_BLE_MESH_ADV_BUF_COUNT=60 +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=6 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=1 +CONFIG_BLE_MESH_RX_SDU_MAX=384 +CONFIG_BLE_MESH_TX_SEG_MAX=32 +CONFIG_BLE_MESH_RELAY=y +CONFIG_BLE_MESH_LOW_POWER= +CONFIG_BLE_MESH_FRIEND= +CONFIG_BLE_MESH_CFG_CLI=y +CONFIG_BTU_TASK_STACK_SIZE=4512 \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_node/tutorial/Ble_Mesh_Node_Example_Walkthrough.md b/examples/bluetooth/ble_mesh/ble_mesh_node/tutorial/Ble_Mesh_Node_Example_Walkthrough.md new file mode 100644 index 0000000000..639d10de3f --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_node/tutorial/Ble_Mesh_Node_Example_Walkthrough.md @@ -0,0 +1,471 @@ + +# ESP BLE Mesh Node demo + +## 1. Introduction + +ESP BLE Mesh is built on top of Zephyr BLE Mesh stack. ESP BLE Mesh nodes support: + +* Network provisioning +* Node control, including the use of PB\_GATT and PB\_ADV bearers +* Encryption +* Node features of Proxy, Relay, Low power and Friend + +This demo has only one element, in which the following two models are implemented: + +- **Configuration Server model**: The role of this model is mainly to configure Provisioner device’s AppKey and set up its relay function, TTL size, subscription, etc. +- **Generic OnOff Server model**: This model implements the most basic function of turning the lights on and off. + +## 2. Code Analysis + +### 2.1 Foler Structure + +The folder `ble_mesh_node` contains the following files and subfolders: + +``` +$ tree examples/bluetooth/ble_mesh/ble_mesh/ble_mesh_node +├── Makefile /* Compiling parameters for the demo */ +├── README.md /* Quick start guide */ +├── build +├── main /* Stores the `.c` and `.h` application code files for this demo */ +├── sdkconfig /* Current parameters of `make menuconfig` */ +├── sdkconfig.defaults /* Default parameters of `make menuconfig` */ +├── sdkconfig.old /* Previously saved parameters of `make menuconfig` */ +└── tutorial /* More in-depth information about the demo */ +``` + +The contents of the `main` subfolder are as follows: + +``` +main +├── Kconfig.projbuild +├── ble_mesh_demo_main.c /* main application codes, more info below */ +├── board.c /* Codes for implementation +├── board.h of the RGB LED driver */ +└── component.mk +``` + +- `ble_mesh_demo_main.c`: contains the following main application codes, which are needed to implement the BLE Mesh demo + - Initialize Bluetooth Controller stack and Host stack (bluedroid) + - Initialize BLE Mesh stack + - Register the callback function of BLE Mesh provision and BLE Mesh model + - Implement and initialize BLE Mesh element + - Implement and initialize BLE Mesh Configuration Server model and Generic OnOff Server model + - Function as BLE Mesh Configuration Server Model Get Opcode and BLE Mesh Configuration Server Model Set Opcode + - Declare and define the RGB LED structure. + +### 2.2 Code Analysis of BLE Mesh Node demo + +For better understanding of the demo implementation, this section provides a detailed analysis of the codes in the file `ble_mesh_demo_main.c`. + +#### 2.2.1 Initializing and Enabling BLE Mesh + +When ESP32 system initialization is completed, `app_main` is called. The code block below demonstrates the implementation of the functions in `app_main`. + +```c +void app_main(void) +{ + int err; + + ESP_LOGI(TAG, "Initializing..."); + + board_init(); + + err = bluetooth_init(); + + if (err) { + ESP_LOGE(TAG, "esp32_bluetooth_init failed (err %d)", err); + return; + } + + /* Initializes the Bluetooth Mesh Subsystem */ + err = ble_mesh_init(); + if (err) { + ESP_LOGE(TAG, "Bluetooth mesh init failed (err %d)", err); + } +} +``` + +In particular, the code includes: + +- `err = bluetooth_init()`: initialization related to the Bluetooth protocol stack (including Controller and Host) +- `err = ble_mesh_init()`: initialization related to BLE Mesh + +Further, the code for initialization of the BLE Mesh protocol stack is introduced, together with the description of the required actions to initialize BLE Mesh. + +```c +static esp_err_t ble_mesh_init(void) +{ + int err = 0; + + memcpy(dev_uuid + 2, esp_bt_dev_get_address(), ESP_BD_ADDR_LEN); + + // See comment 1 + esp_ble_mesh_register_prov_callback(esp_ble_mesh_prov_cb); + esp_ble_mesh_register_custom_model_callback(esp_ble_mesh_model_cb); + + err = esp_ble_mesh_init(&provision, &composition); + if (err) { + ESP_LOGE(TAG, "Initializing mesh failed (err %d)", err); + return err; + } + + esp_ble_mesh_node_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT); + + ESP_LOGI(TAG, "BLE Mesh Node initialized"); + + board_led_operation(LED_G, LED_ON); + + return err; +} +``` + +The code includes the following: + +- `esp_ble_mesh_register_prov_callback(esp_ble_mesh_prov_cb)`: registers the provisioning callback function in the BLE Mesh stack. This callback function gets executed during the BLE Mesh network configuration process. It allows the BLE Mesh stack to generate events and notify the application layer about important network configuration processes. This callback function mainly implements the following events: + - `ESP_BLE_MESH_PROVISION_REG_EVT`: Generated when the BLE Mesh initialization process is completed after calling the API function `esp_ble_mesh_init`. It returns the initialization status of the BLE Mesh application. + - `ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT`: Generated when a Provisioner and an unprovisioned device establish a link. + - `ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT`: Generated to notify the application layer that a link has been broken after BLE Mesh bottom-layer protocol sends or receives the message `The Link Broken`. + - `ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT`: Received by the application layer if during the configuration process `output_actions` is set as `ESP_BLE_MESH_DISPLAY_NUMBER`, and the target peer `input_actions` is set as `ESP_BLE_MESH_ENTER_NUMBER`. + - `ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT`: Received by the application layer if during the configuration process `output_actions` is set as `ESP_BLE_MESH_DISPLAY_STRING`, and the target peer `input_actions` is set as `ESP_BLE_MESH_ENTER_STRING`. + - `ESP_BLE_MESH_NODE_PROV_INPUT_EVT`: Received by the application layer if during the configuration process `input_actions` is set as anything but `ESP_BLE_MESH_NO_INPUT`. + - `ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT`: Received by the application layer when the provisioning is completed. + - `ESP_BLE_MESH_NODE_PROV_RESET_EVT`: Received by the application layer when the network reset is completed. + +- `esp_ble_mesh_register_custom_model_callback(esp_ble_mesh_model_cb)`: registers the model operation callback function. This callback function is used when the target peer operates the model state of the source peer after BLE Mesh has completed network configuration. This callback function mainly implements the following events: + - `ESP_BLE_MESH_MODEL_OPERATION_EVT`: Can be triggered by the two scenarios below: + - Server model receives `Get Status` or `Set Status` from Client model. + - Client model receives `Status state` from Server model. + - `ESP_BLE_MESH_MODEL_SEND_COMP_EVT`: Generated after the Server model sends `Status state` by calling the API function `esp_ble_mesh_server_model_send_msg`. + - `ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT`: Generated after the application has completed calling the API `esp_ble_mesh_model_publish_msg` to publish messages + - `ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT`: Generated when the Client model calls the API function `esp_ble_mesh_client_model_send_msg`, but fails to receive ACK from the target peer due to timeout + - `ESP_BLE_MESH_MODEL_PUBLISH_UPDATE_EVT`: Generated after the application sets up the publish function to regularly send messages to the target peer. + +- `esp_ble_mesh_node_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT)`: enables the Advertising and Scan functions when the BLE Mesh initialization is completed. It makes the devices visible to Provisioners for network provisioning. +- `board_led_operation(LED_G, LED_ON)`: initializes the RGB LED. + +At this point, initialization and enabling of BLE Mesh as a node port is completed, which means a Provisioner can identify devices for network provisioning and data transmission. + +#### 2.2.2 Implementation of BLE Mesh Element Structure + +The section above shows how to initialize BLE Mesh as a node port. You may still have the following questions: + +- What else needs to be done before initialization? +- How to add an element and a model to ESP BLE Mesh stack? +- How to choose a different encryption approach? +- How to declare the features of Proxy, Relay, Low Power and Friend? + +This section provides the answers to these questions. + +First of all, before calling the API `esp_ble_mesh_init` to initialize BLE Mesh, an element and a model need to be declared and defined. + +The code block below shows the declaration of an element structure. + +```c + +/*!< Abstraction that describes a BLE Mesh Element. + This structure is associated with bt_mesh_elem in mesh_access.h */ +typedef struct { + /* Element Address, it is assigned during provisioning. */ + uint16_t element_addr; + + /* Location Descriptor (GATT Bluetooth Namespace Descriptors) */ + const uint16_t location; + + /* Model count */ + const uint8_t sig_model_count; + const uint8_t vnd_model_count; + + /* Models */ + esp_ble_mesh_model_t *sig_models; + esp_ble_mesh_model_t *vnd_models; +} esp_ble_mesh_elem_t; +``` + +The next code block shows the definition of an element structure, which only requires to call the macro `ESP_BLE_MESH_ELEMENT`. + +```c +static esp_ble_mesh_elem_t elements[] = { + ESP_BLE_MESH_ELEMENT(0, root_models, ESP_BLE_MESH_MODEL_NONE), +}; +``` +Another code block provides the codes needed to implement the macro `ESP_BLE_MESH_ELEMENT`. + +```c +#define ESP_BLE_MESH_ELEMENT(_loc, _mods, _vnd_mods) \ +{ \ + .location = (_loc), \ + .sig_model_count = ARRAY_SIZE(_mods), \ + .sig_models = (_mods), \ + .vnd_model_count = ARRAY_SIZE(_vnd_mods), \ + .vnd_models = (_vnd_mods), \ +} + +``` + +The variables of the element structure are as follows: + +- `addr`: stores the element primary address, used by Mesh Stack during the configuration process. It can be ignored for the higher level applications. +- `loc`: location descriptor defined by SIG. For this demo, set its value to `0`. +- `model_count`: number of SIG models supported in this element. +- `vnd_model_count`: number of the Vendor model supported in this element. +- `models`: pointer to the SIG Models that have already been defined. +- `vnd_models`: pointer to the Vendor Model that has already been defined. + +
Note: the SIG Model count and the Vendor Model count work separately. For example, if two SIG Models and one Vendor model are supported in an element, the variables would be model_count = 2, vnd_model_count = 1.
+ + +If a defined element does not support the Vendor model, the third parameter (the last one) of the macro `ESP_BLE_MESH_ELEMENT` should be set to `ESP_BLE_MESH_MODEL_NODE`. Likewise, if the SIG Model is not supported, the second parameter should be set to `ESP_BLE_MESH_MODEL_NODE`. + +#### 2.2.3 Implementation of BLE Mesh Model Structure + +The preceding section has introduced the specific ways to implement and define an element by passing specific model pointers to it. This section explains how to implement and define a Model structure, which is shown in the code blocks below. + +```c +/** Abstraction that describes a Mesh Model instance. + * This structure is associated with bt_mesh_model in mesh_access.h + */ +struct esp_ble_mesh_model { + /* Model ID */ + union { + const uint16_t model_id; + struct { + uint16_t company_id; + uint16_t model_id; + } vnd; + }; + + /* The Element to which this Model belongs */ + esp_ble_mesh_elem_t *element; + + /* Model Publication */ + esp_ble_mesh_model_pub_t *const pub; + + /* AppKey List */ + uint16_t keys[CONFIG_BLE_MESH_MODEL_KEY_COUNT]; + + /* Subscription List (group or virtual addresses) */ + uint16_t groups[CONFIG_BLE_MESH_MODEL_GROUP_COUNT]; + + /* Model operation context */ + esp_ble_mesh_model_op_t *op; + + /* Model-specific user data */ + void *user_data; +}; +``` + +The block above shows a specific implementation of the model structure. Although this structure has many variables, only the following four ones are used for applications: + +- `id` and `vnd`: union variables, defining the SIG Model and the Vendor Model respectively. +- `op`: structure with a set of variables for the Model Operation, declaring the opcode that corresponds to Get, Set, or Status State, as well as the minimum value lengths that are supported in this module. +- `pub`: structure that needs to be defined if the Model structure supports the Publish function. +- `user_data`: optional variable for storing the application layer data. + +The other structures and variables (keys, group, element) get their values through the BLE Mesh stack during the initialization or configuration stages. You are not reqiured to initialize them. + +The next code block presents the definition of the model structure, and the `root_models[]` array. This array is used for indicating the number of the existing model structures. A model is implemented by using a macro. + +```c + +static esp_ble_mesh_model_t root_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&config_server), + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, onoff_op, + &onoff_pub, &led_state[0]), +}; +``` + +Different models require different macros. The exisitng types of models and their respective macros needed for implementation are given in the table below. + +| | Model Name | Macro Required for its Definition | +| --------------- | ---- | ----------------------------- | +| **SIG Models Implemented in ESP32 BLE Mesh Stack** | Configuration Server Model | `ESP_BLE_MESH_MODEL_CFG_SRV` | +| | Configuration Client Model | `ESP_BLE_MESH_MODEL_CFG_CLI` | +| | Generic OnOff Client Model | `ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI` | +| | Generic Level Client Model | `ESP_BLE_MESH_MODEL_GEN_LEVEL_CLI` | +| | Generic Default Transition Time Client Model | `ESP_BLE_MESH_MODEL_GEN_DEF_TRANS_TIME_CLI` | +| | Generic Power OnOff Client Model | `ESP_BLE_MESH_MODEL_GEN_POWER_ONOFF_CLI` | +| | Generic Power Level Client Model | `ESP_BLE_MESH_MODEL_GEN_POWER_LEVEL_CLI` | +| | Generic Battery Client Model | `ESP_BLE_MESH_MODEL_GEN_BATTERY_CLI` | +| | Generic Location Client Model | `ESP_BLE_MESH_MODEL_GEN_LOCATION_CLI` | +| | Generic Property Client Model | `ESP_BLE_MESH_MODEL_GEN_PROPERTY_CLI` | +| | Light Lightness Client Model | `ESP_BLE_MESH_MODEL_LIGHT_LIGHTNESS_CLI` | +| | Light CTL Client Model | `ESP_BLE_MESH_MODEL_LIGHT_CTL_CLI` | +| | Light HSL Client Model | `ESP_BLE_MESH_MODEL_LIGHT_HSL_CLI` | +| | Sensor Client Model | `ESP_BLE_MESH_MODEL_SENSOR_CLI` | +| | Scene Client Model | `ESP_BLE_MESH_MODEL_SCENE_CLI` | +| **SIG Models Not Implemented in ESP32 BLE Mesh Stack** | - | `ESP_BLE_MESH_SIG_MODEL` | +| **Vendor Models** | - | `ESP_BLE_MESH_VENDOR_MODEL` | + +Another important structure in a model is `esp_ble_mesh_model_op_t *op` pointers. These structures point to the operation structure that defines the Model state. Generally, there are two types of models in BLE Mesh: + +- Server Model: + - Consists of one or multiple states that can exist across different elements + - Defines the messages sent/received by the model, along with the element's behavior. + - Example:On/Off switch --- Indicates the On/Off status. +- Client Model: + - Defines the messages used by the client to request, change or use the relevant state of the server. + - Example:On/Off switch --- Indicates the On or Off message sent by the Client. + +Operation structure defines the state value supported by a model. A specific operation structure is given below. + +The following code block shows the declaration of the Model operation structure. + +```c +/*!< Model operation context. + This structure is associated with bt_mesh_model_op in mesh_access.h */ +typedef struct { + const uint32_t opcode; /* Opcode encoded with the ESP_BLE_MESH_MODEL_OP_* macro */ + const size_t min_len; /* Minimum required message length */ + esp_ble_mesh_cb_t param_cb; /* The callback is only used for the BLE Mesh stack, not for the app layer. */ +} esp_ble_mesh_model_op_t; +``` + +There are three variables in the declaration of the operation structure: + +- `opcode`: opcode corresponding to a state. As specified in BLE Mesh, the SIG Model opcode should be 1~2 bytes, and the Vendor Model opcode should be 3 bytes. +- `min_len`: min length of the messages received by the state. For example, OnOff Get state is 0 bytes, and OnOff Set State is 2 bytes. +- `param_cb`: used for the BLE Mesh protocol only. Applications need to set its value to `0`. + +The block below shows the operation structure array defined by the OnOff Server in this demo. + +```c +static esp_ble_mesh_model_op_t onoff_op[] = { + { ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET, 0, 0}, + { ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, 2, 0}, + { ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2, 0}, + /* Each model operation struct array must use this terminator + * as the end tag of the operation uint. */ + ESP_BLE_MESH_MODEL_OP_END, +}; +``` + +It presents the opcodes, corresponding to the three states, defined in this demo: OnOff Get, OnOff Set, and OnOff Set Unack. + +
Note: for the Server Model, the corresponding request state of the Client Model needs to be written in the operation definition. For example, if the Generic OnOff Server Model is to be implemented in this demo, the following three states requested by the Generic OnOff Client Model need to be written in the operation definition: OnOff Get, OnOff Set, and OnOff Set Unack. Likewise, for the Client Model, the corresponding State of the messages received by the Server needs to be written in the operation definition.
+ +#### 2.2.4. Encryption and Authentication of BLE Mesh + +In the project developing process, different security levels are required. BLE Mesh offers various kinds of encryption and authentication features which can be split into two categories - Input and Output. + +The classification of the Input features is given in the table below. + +| Feature Name | Action Supported | +| ------------ | ------------------ | +| `ESP_BLE_MESH_NO_INPUT` | Input is not supported by device's IO | +| `ESP_BLE_MESH_PUSH` | PUSH | +| `ESP_BLE_MESH_TWIST` | TWIST | +| `ESP_BLE_MESH_ENTER_NUMBER` | ENTER NUMBER | +| `ESP_BLE_MESH_ENTER_STRING` | ENTER STRING | + +The classification of the Output features is given in the table below. + +| Feature Name | Action Supported | +| ------------ | ------------------ | +| `ESP_BLE_MESH_NO_OUTPUT ` | Output is not supported by device's IO | +| `ESP_BLE_MESH_BLINK ` | BLINK | +| `ESP_BLE_MESH_BEEP ` | BEEP | +| `ESP_BLE_MESH_VIBRATE ` | VIBRATE | +| `ESP_BLE_MESH_DISPLAY_NUMBER ` | DISPLAY NUMBER | +| `ESP_BLE_MESH_DISPLAY_STRING ` | DISPLAY STRING | + +The above Input and Output categories in the declaration of the structure `esp_ble_mesh_prov_t` can be defined by the following four variables: + +- `output_size` +- `output_actions` +- `input_actions` +- `input_size` + +These variables should be set to `0` for this demo, as it uses the most basic authentication features. + +## 3. Configuration of BLE Mesh Menuconfig + +To be functional across different applications, the BLE Mesh menuconfig is specifically designed to offer a variety of configuration options, which can be helpful in tailoring your own configuration. + +The list of configuration options in BLE Mesh menuconfig is stored in `Component config` ---> `[]Bluetooth Mesh support` and can be accessed with the command `make menuconfig`. This configuration option list is shown below. + +``` +—— Bluetooth Mesh support +[*] Suppoft for BLE Mesh Node +[ ] Support for BLE lqesh Provisioner +[*] Provisiosing support using the advertising bearer (PB-ADV) +[*] net buffer pool usage +[*] Provisioning support using GATT (PB-GATT) +[*] GATT Proxy Service +(60) Node Identity advertising timeout +(1) Maximum number of filter entries per Proxy Client +[*] Perform self-tests +[*] Test the IV Update Procedure +(1) Maximum number of mesh subnets per network +(1) Maximum number of application keys per network +(1) Maximum number of application keys per model +(1) Maximum number of group address subscriptions per model +(1) Maximum number of Label UUIDs used for virtual Addresses +(10) Maximum capacity of the replay protection list +(10) Network message cache size +(20) Number of advertising buffers +(6) Maximum number of simultaneous outgoing segmented messages +(1) Maximum number of simultaneous incoming segmented messages +(384) Maximum incoming Upper Transport Access PDU length +[*] Relay support +[ ] Support for Low Power features +[ ] Support for acting as a Friend Node +[*] Support for Configuration Client Model +[*] Support for Health Client Model +[ ] Support for Generic OnOff Client Model +[ ] Support for Generic Level Client Model +[ ] Support for Generic Default Transition Time Client Model +[ ] Support for Generic Power OnOff Client Model +[ ] Support for Generic Power Level Client Model +[ ] Support for Generic Battery Client Model +[ ] Support for Generic Location Client Model +[ ] Support for Generic Property Client Model +[ ] Support for Sensor Client Model +[ ] Support for Scene Client Model +[ ] Support for Light Lightness Client Model +[ ] Support for Light CTL Client Model +[ ] Support for Light HSL Client Model +[ ] Enable Bluetooth Mesh shell +``` + +The detailed information about the roles and functions of these options is presented below. + +- **Support for BLE Mesh Node**: Indicates if the role of a node is supported. There are two roles in BLE Mesh: a Provisioner and a node. In this demo only a node is supported. +- **Support for BLE Mesh Provisioner**: Indicates if the role of a Provisioner is supported. +- **Provisioning support using the advertising bearer (PB-ADV)**: Indicates if the bearer PB-ADV is supported for network provisioning. In BLE Mesh,the bearers PB-ADV and PB-GATT are supported for network provisioning. This demo supports both of them. +- **net buffer pool usage**: When enabled, BLE Mesh monitors the usage of the Adv buffer. +- **Provisioning support using GATT (PB-GATT)**: Indicates if the PB-GATT bearer is supported for network provisioning. +- **GATT Proxy Service**: Indicates if the GATT proxy service is supported. + - **Node Identity advertising timeout**: Indicates the time (in seconds) after which advertising stops. This value gets assigned by BLE Mesh protocol stack when using the GATT proxy service. +- **Maximum number of filter entries per Proxy Client**: Used to configure the maximum number of filtered addresses. To reduce the number of Network PDUs exchanges between a Proxy Client and a Proxy Server, a proxy filter can be used. The output filter of the network interface instantiated by the Proxy Server can be configured by the Proxy Client. This allows the Proxy Client to explicitly request to receive only mesh messages with certain destination addresses. For example, a Proxy Client that is subscribed to a group address may want to only receive packets addressed to the unicast address of one of its elements and to that group address. Thus, the Proxy Client has full control over the packets it receives using the Proxy protocol. +- **Perform self-tests**: +- **Test the IV Update Procedure**: +- **Maximum number of mesh subnets per network**: Indicates the maximum number of the subnets supported in a BLE Mesh network. +- **Maximum number of application keys per network**: Indicates the maximum number of AppKeys supported in a BLE Mesh network. +- **Maximum number of application keys per model**: Indicates the maximum number of AppKeys bound in each Model. +- **Maximum number of group address subscriptions per model**: Indicates the maximum number of group address subscriptions supported in each model in BLE Mesh. +- **Maximum number of Label UUIDs used for Virtual Addresses**: Indicates the maximum number of Label UUIDs supported in BLE Mesh. +- **Maximum capacity of the replay protection list**: Indicates what the name suggests. +- **Network message cache size**: Configures the size of the cache, which is used to store the forwarded messages to avoid multiple forwarding in BLE Mesh. +- **Number of advertising buffers**: Indicates what the name suggests. +- **Maximum number of simultaneous outgoing segmented messages**: Indicates what the name suggests. +- **Maximum number of simultaneous incoming segmented messages**: Indicates what the name suggests. +- **Maximum incoming Upper Transport Access PDU length**: Indicates that the access layer can receive the maximum length of a complete packet. +- **Relay support**: Indicates if the Relay feature is supported. +- **Support for Low Power features**: Indicates if the Low Power features are supported. +- **Support for acting as a Friend Node**: Indicates if the Friend feature is supported. +- **Support for Configuration Client Model**: Indicates if the Configuration Client model is supported. +- **Support for Health Client Model**: Indicates if the given model is supported. +- **Support for Generic OnOff Client Model**: Indicates if the given model is supported. +- **Support for Generic Level Client Model**: Indicates if the given model is supported. +- **Support for Generic Default Transition Time Client Model**: Indicates if the given model is supported. +- **Support for Generic Power Onoff Client Model**: Indicates if the given model is supported. +- **Support for Generic Power Level Client Model**: Indicates if the given model is supported. +- **Support for Generic Battery Client Model**: Indicates if the given model is supported. +- **Support for Generic Location Client Model**: Indicates if the given model is supported. +- **Support for Generic Property Client Model**: Indicates if the given model is supported. +- **Support for Sensor Client Model**: Indicates if the given model is supported. +- **Support for Scene Client Model**: Indicates if the given model is supported. +- **Support for Light Lightness Client Model**: Indicates if the given model is supported. +- **Support for Light CTL Client Model**: Indicates if the given model is supported. +- **Support for Light HSL Client Model**: Indicates if the given model is supported. +- **Enable Bluetooth Mesh shell**: \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_provisioner/CMakeLists.txt b/examples/bluetooth/ble_mesh/ble_mesh_provisioner/CMakeLists.txt new file mode 100644 index 0000000000..dfffbf786f --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_provisioner/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(ble_mesh_provisioner) diff --git a/examples/bluetooth/ble_mesh/ble_mesh_provisioner/Makefile b/examples/bluetooth/ble_mesh/ble_mesh_provisioner/Makefile new file mode 100644 index 0000000000..bceab36a3e --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_provisioner/Makefile @@ -0,0 +1,10 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := ble_mesh_provisioner + +COMPONENT_ADD_INCLUDEDIRS := components/include + +include $(IDF_PATH)/make/project.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_provisioner/README.md b/examples/bluetooth/ble_mesh/ble_mesh_provisioner/README.md new file mode 100644 index 0000000000..2ccf84fd30 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_provisioner/README.md @@ -0,0 +1,6 @@ +ESP BLE Mesh Provisioner demo +================================ + +This demo shows how a BLE Mesh device can function as a provisioner. + +Please check the [tutorial](tutorial/Ble_Mesh_Provisioner_Example_Walkthrough.md) for more information about this example. \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_provisioner/main/CMakeLists.txt b/examples/bluetooth/ble_mesh/ble_mesh_provisioner/main/CMakeLists.txt new file mode 100644 index 0000000000..3d3bc6f9a5 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_provisioner/main/CMakeLists.txt @@ -0,0 +1,5 @@ +set(COMPONENT_SRCS "ble_mesh_demo_main.c") + +set(COMPONENT_ADD_INCLUDEDIRS ".") + +register_component() diff --git a/examples/bluetooth/ble_mesh/ble_mesh_provisioner/main/ble_mesh_demo_main.c b/examples/bluetooth/ble_mesh/ble_mesh_provisioner/main/ble_mesh_demo_main.c new file mode 100644 index 0000000000..7f3ddeb405 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_provisioner/main/ble_mesh_demo_main.c @@ -0,0 +1,691 @@ +/* main.c - Application main entry point */ + +/* + * Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "esp_log.h" +#include "nvs_flash.h" + +#include "esp_bt.h" +#include "esp_bt_main.h" +#include "esp_bt_device.h" + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_common_api.h" +#include "esp_ble_mesh_provisioning_api.h" +#include "esp_ble_mesh_networking_api.h" +#include "esp_ble_mesh_config_model_api.h" +#include "esp_ble_mesh_generic_model_api.h" + +#define TAG "ble_mesh_provisioner" + +#define LED_OFF 0x0 +#define LED_ON 0x1 + +#define CID_ESP 0x02E5 +#define CID_NVAL 0xFFFF + +#define PROV_OWN_ADDR 0x0001 + +#define MSG_SEND_TTL 3 +#define MSG_SEND_REL false +#define MSG_TIMEOUT 0 +#define MSG_ROLE ROLE_PROVISIONER + +#define COMP_DATA_PAGE_0 0x00 + +#define APP_KEY_IDX 0x0000 +#define APP_KEY_OCTET 0x12 + +static uint8_t dev_uuid[16]; + +typedef struct { + uint8_t uuid[16]; + uint16_t unicast; + uint8_t elem_num; + uint8_t onoff; +} esp_ble_mesh_node_info_t; + +static esp_ble_mesh_node_info_t nodes[CONFIG_BLE_MESH_MAX_PROV_NODES] = { + [0 ... (CONFIG_BLE_MESH_MAX_PROV_NODES - 1)] = { + .unicast = ESP_BLE_MESH_ADDR_UNASSIGNED, + .elem_num = 0, + .onoff = LED_OFF, + } +}; + +static struct esp_ble_mesh_key { + uint16_t net_idx; + uint16_t app_idx; + uint8_t app_key[16]; +} prov_key; + +static esp_ble_mesh_client_t config_client; +static esp_ble_mesh_client_t onoff_client; + +static esp_ble_mesh_cfg_srv_t config_server = { + .relay = ESP_BLE_MESH_RELAY_DISABLED, + .beacon = ESP_BLE_MESH_BEACON_ENABLED, +#if defined(CONFIG_BLE_MESH_FRIEND) + .friend_state = ESP_BLE_MESH_FRIEND_ENABLED, +#else + .friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED, +#endif +#if defined(CONFIG_BLE_MESH_GATT_PROXY) + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED, +#else + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED, +#endif + .default_ttl = 7, + /* 3 transmissions with 20ms interval */ + .net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20), + .relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20), +}; + +static esp_ble_mesh_model_t root_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&config_server), + ESP_BLE_MESH_MODEL_CFG_CLI(&config_client), + ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(NULL, &onoff_client), +}; + +static esp_ble_mesh_elem_t elements[] = { + ESP_BLE_MESH_ELEMENT(0, root_models, ESP_BLE_MESH_MODEL_NONE), +}; + +static esp_ble_mesh_comp_t composition = { + .cid = CID_ESP, + .elements = elements, + .element_count = ARRAY_SIZE(elements), +}; + +static esp_ble_mesh_prov_t provision = { + .prov_uuid = dev_uuid, + .prov_unicast_addr = PROV_OWN_ADDR, + .prov_start_address = 0x0005, + .prov_attention = 0x00, + .prov_algorithm = 0x00, + .prov_pub_key_oob = 0x00, + .prov_static_oob_val = NULL, + .prov_static_oob_len = 0x00, + .flags = 0x00, + .iv_index = 0x00, +}; + +static esp_err_t esp_ble_mesh_store_node_info(const uint8_t uuid[16], uint16_t unicast, + uint8_t elem_num, uint8_t onoff_state) +{ + int i; + + if (!uuid || !ESP_BLE_MESH_ADDR_IS_UNICAST(unicast)) { + return ESP_ERR_INVALID_ARG; + } + + /* Judge if the device has been provisioned before */ + for (i = 0; i < ARRAY_SIZE(nodes); i++) { + if (!memcmp(nodes[i].uuid, uuid, 16)) { + ESP_LOGW(TAG, "%s: reprovisioned device 0x%04x", __func__, unicast); + nodes[i].unicast = unicast; + nodes[i].elem_num = elem_num; + nodes[i].onoff = onoff_state; + return ESP_OK; + } + } + + for (i = 0; i < ARRAY_SIZE(nodes); i++) { + if (nodes[i].unicast == ESP_BLE_MESH_ADDR_UNASSIGNED) { + memcpy(nodes[i].uuid, uuid, 16); + nodes[i].unicast = unicast; + nodes[i].elem_num = elem_num; + nodes[i].onoff = onoff_state; + return ESP_OK; + } + } + + return ESP_FAIL; +} + +static esp_ble_mesh_node_info_t *esp_ble_mesh_get_node_info(uint16_t unicast) +{ + int i; + + if (!ESP_BLE_MESH_ADDR_IS_UNICAST(unicast)) { + return NULL; + } + + for (i = 0; i < ARRAY_SIZE(nodes); i++) { + if (nodes[i].unicast <= unicast && + nodes[i].unicast + nodes[i].elem_num > unicast) { + return &nodes[i]; + } + } + + return NULL; +} + +static esp_err_t esp_ble_mesh_set_msg_common(esp_ble_mesh_client_common_param_t *common, + esp_ble_mesh_node_info_t *node, + esp_ble_mesh_model_t *model, uint32_t opcode) +{ + if (!common || !node || !model) { + return ESP_ERR_INVALID_ARG; + } + + common->opcode = opcode; + common->model = model; + common->ctx.net_idx = prov_key.net_idx; + common->ctx.app_idx = prov_key.app_idx; + common->ctx.addr = node->unicast; + common->ctx.send_ttl = MSG_SEND_TTL; + common->ctx.send_rel = MSG_SEND_REL; + common->msg_timeout = MSG_TIMEOUT; + common->msg_role = MSG_ROLE; + + return ESP_OK; +} + +static esp_err_t prov_complete(int node_idx, const esp_ble_mesh_octet16_t uuid, + uint16_t unicast, uint8_t elem_num, uint16_t net_idx) +{ + esp_ble_mesh_client_common_param_t common = {0}; + esp_ble_mesh_cfg_client_get_state_t get_state = {0}; + esp_ble_mesh_node_info_t *node = NULL; + char name[10]; + int err; + + ESP_LOGI(TAG, "node index: 0x%x, unicast address: 0x%02x, element num: %d, netkey index: 0x%02x", + node_idx, unicast, elem_num, net_idx); + ESP_LOGI(TAG, "device uuid: %s", bt_hex(uuid, 16)); + + sprintf(name, "%s%d", "NODE-", node_idx); + err = esp_ble_mesh_provisioner_set_node_name(node_idx, name); + if (err) { + ESP_LOGE(TAG, "%s: Set node name failed", __func__); + return ESP_FAIL; + } + + err = esp_ble_mesh_store_node_info(uuid, unicast, elem_num, LED_OFF); + if (err) { + ESP_LOGE(TAG, "%s: Store node info failed", __func__); + return ESP_FAIL; + } + + node = esp_ble_mesh_get_node_info(unicast); + if (!node) { + ESP_LOGE(TAG, "%s: Get node info failed", __func__); + return ESP_FAIL; + } + + esp_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET); + get_state.comp_data_get.page = COMP_DATA_PAGE_0; + err = esp_ble_mesh_config_client_get_state(&common, &get_state); + if (err) { + ESP_LOGE(TAG, "%s: Send config comp data get failed", __func__); + return ESP_FAIL; + } + + return ESP_OK; +} + +static void prov_link_open(esp_ble_mesh_prov_bearer_t bearer) +{ + ESP_LOGI(TAG, "%s link open", bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT"); +} + +static void prov_link_close(esp_ble_mesh_prov_bearer_t bearer, uint8_t reason) +{ + ESP_LOGI(TAG, "%s link close, reason 0x%02x", + bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT", reason); +} + +static void recv_unprov_adv_pkt(uint8_t dev_uuid[16], uint8_t addr[ESP_BD_ADDR_LEN], + esp_ble_addr_type_t addr_type, uint16_t oob_info, + uint8_t adv_type, esp_ble_mesh_prov_bearer_t bearer) +{ + esp_ble_mesh_unprov_dev_add_t add_dev = {0}; + int err; + + /* Due to the API esp_ble_mesh_provisioner_set_dev_uuid_match, Provisioner will only + * use this callback to report the devices, whose device UUID starts with 0xdd & 0xdd, + * to the application layer. + */ + + ESP_LOGI(TAG, "address: %s, address type: %d, adv type: %d", bt_hex(addr, ESP_BD_ADDR_LEN), addr_type, adv_type); + ESP_LOGI(TAG, "device uuid: %s", bt_hex(dev_uuid, 16)); + ESP_LOGI(TAG, "oob info: %d, bearer: %s", oob_info, (bearer & ESP_BLE_MESH_PROV_ADV) ? "PB-ADV" : "PB-GATT"); + + memcpy(add_dev.addr, addr, ESP_BD_ADDR_LEN); + add_dev.addr_type = (uint8_t)addr_type; + memcpy(add_dev.uuid, dev_uuid, 16); + add_dev.oob_info = oob_info; + add_dev.bearer = (uint8_t)bearer; + /* Note: If unprovisioned device adv packets have not been received, we should not add + device with ADD_DEV_START_PROV_NOW_FLAG set. */ + err = esp_ble_mesh_provisioner_add_unprov_dev(&add_dev, + ADD_DEV_RM_AFTER_PROV_FLAG | ADD_DEV_START_PROV_NOW_FLAG | ADD_DEV_FLUSHABLE_DEV_FLAG); + if (err) { + ESP_LOGE(TAG, "%s: Add unprovisioned device into queue failed", __func__); + } + + return; +} + +static void esp_ble_mesh_prov_cb(esp_ble_mesh_prov_cb_event_t event, + esp_ble_mesh_prov_cb_param_t *param) +{ + switch (event) { + case ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT, err_code %d", param->provisioner_prov_enable_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_DISABLE_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_DISABLE_COMP_EVT, err_code %d", param->provisioner_prov_disable_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT"); + recv_unprov_adv_pkt(param->provisioner_recv_unprov_adv_pkt.dev_uuid, param->provisioner_recv_unprov_adv_pkt.addr, + param->provisioner_recv_unprov_adv_pkt.addr_type, param->provisioner_recv_unprov_adv_pkt.oob_info, + param->provisioner_recv_unprov_adv_pkt.adv_type, param->provisioner_recv_unprov_adv_pkt.bearer); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT: + prov_link_open(param->provisioner_prov_link_open.bearer); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT: + prov_link_close(param->provisioner_prov_link_close.bearer, param->provisioner_prov_link_close.reason); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT: + prov_complete(param->provisioner_prov_complete.node_idx, param->provisioner_prov_complete.device_uuid, + param->provisioner_prov_complete.unicast_addr, param->provisioner_prov_complete.element_num, + param->provisioner_prov_complete.netkey_idx); + break; + case ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT, err_code %d", param->provisioner_add_unprov_dev_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT, err_code %d", param->provisioner_set_dev_uuid_match_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT: { + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT, err_code %d", param->provisioner_set_node_name_comp.err_code); + if (param->provisioner_set_node_name_comp.err_code == ESP_OK) { + const char *name = NULL; + name = esp_ble_mesh_provisioner_get_node_name(param->provisioner_set_node_name_comp.node_index); + if (!name) { + ESP_LOGE(TAG, "Get node name failed"); + return; + } + ESP_LOGI(TAG, "Node %d name is: %s", param->provisioner_set_node_name_comp.node_index, name); + } + break; + } + case ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT: { + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT, err_code %d", param->provisioner_add_app_key_comp.err_code); + if (param->provisioner_add_app_key_comp.err_code == ESP_OK) { + esp_err_t err = 0; + prov_key.app_idx = param->provisioner_add_app_key_comp.app_idx; + err = esp_ble_mesh_provisioner_bind_app_key_to_local_model(PROV_OWN_ADDR, prov_key.app_idx, + ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, CID_NVAL); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Provisioner bind local model appkey failed"); + return; + } + } + break; + } + case ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT, err_code %d", param->provisioner_bind_app_key_to_model_comp.err_code); + break; + default: + break; + } + + return; +} + +static void esp_ble_mesh_model_cb(esp_ble_mesh_model_cb_event_t event, + esp_ble_mesh_model_cb_param_t *param) +{ + switch (event) { + case ESP_BLE_MESH_MODEL_OPERATION_EVT: + break; + case ESP_BLE_MESH_MODEL_SEND_COMP_EVT: + break; + case ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT: + break; + default: + break; + } +} + +static void esp_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t event, + esp_ble_mesh_cfg_client_cb_param_t *param) +{ + esp_ble_mesh_client_common_param_t common = {0}; + esp_ble_mesh_node_info_t *node = NULL; + uint32_t opcode; + uint16_t addr; + int err; + + opcode = param->params->opcode; + addr = param->params->ctx.addr; + + ESP_LOGI(TAG, "%s, error_code = 0x%02x, event = 0x%02x, addr: 0x%04x, opcode: 0x%04x", + __func__, param->error_code, event, param->params->ctx.addr, opcode); + + if (param->error_code) { + ESP_LOGE(TAG, "Send config client message failed, opcode 0x%04x", opcode); + return; + } + + node = esp_ble_mesh_get_node_info(addr); + if (!node) { + ESP_LOGE(TAG, "%s: Get node info failed", __func__); + return; + } + + switch (event) { + case ESP_BLE_MESH_CFG_CLIENT_GET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET: { + ESP_LOGI(TAG, "composition data %s", bt_hex(param->status_cb.comp_data_status.composition_data->data, + param->status_cb.comp_data_status.composition_data->len)); + esp_ble_mesh_cfg_client_set_state_t set_state = {0}; + esp_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD); + set_state.app_key_add.net_idx = prov_key.net_idx; + set_state.app_key_add.app_idx = prov_key.app_idx; + memcpy(set_state.app_key_add.app_key, prov_key.app_key, 16); + err = esp_ble_mesh_config_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Config AppKey Add failed", __func__); + return; + } + break; + } + default: + break; + } + break; + case ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: { + esp_ble_mesh_cfg_client_set_state_t set_state = {0}; + esp_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND); + set_state.model_app_bind.element_addr = node->unicast; + set_state.model_app_bind.model_app_idx = prov_key.app_idx; + set_state.model_app_bind.model_id = ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV; + set_state.model_app_bind.company_id = CID_NVAL; + err = esp_ble_mesh_config_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Config Model App Bind failed", __func__); + return; + } + break; + } + case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND: { + esp_ble_mesh_generic_client_get_state_t get_state = {0}; + esp_ble_mesh_set_msg_common(&common, node, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET); + err = esp_ble_mesh_generic_client_get_state(&common, &get_state); + if (err) { + ESP_LOGE(TAG, "%s: Generic OnOff Get failed", __func__); + return; + } + break; + } + default: + break; + } + break; + case ESP_BLE_MESH_CFG_CLIENT_PUBLISH_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_STATUS: + ESP_LOG_BUFFER_HEX("composition data %s", param->status_cb.comp_data_status.composition_data->data, + param->status_cb.comp_data_status.composition_data->len); + break; + case ESP_BLE_MESH_MODEL_OP_APP_KEY_STATUS: + break; + default: + break; + } + break; + case ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET: { + esp_ble_mesh_cfg_client_get_state_t get_state = {0}; + esp_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET); + get_state.comp_data_get.page = COMP_DATA_PAGE_0; + err = esp_ble_mesh_config_client_get_state(&common, &get_state); + if (err) { + ESP_LOGE(TAG, "%s: Config Composition Data Get failed", __func__); + return; + } + break; + } + case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: { + esp_ble_mesh_cfg_client_set_state_t set_state = {0}; + esp_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD); + set_state.app_key_add.net_idx = prov_key.net_idx; + set_state.app_key_add.app_idx = prov_key.app_idx; + memcpy(set_state.app_key_add.app_key, prov_key.app_key, 16); + err = esp_ble_mesh_config_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Config AppKey Add failed", __func__); + return; + } + break; + } + case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND: { + esp_ble_mesh_cfg_client_set_state_t set_state = {0}; + esp_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND); + set_state.model_app_bind.element_addr = node->unicast; + set_state.model_app_bind.model_app_idx = prov_key.app_idx; + set_state.model_app_bind.model_id = ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV; + set_state.model_app_bind.company_id = CID_NVAL; + err = esp_ble_mesh_config_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Config Model App Bind failed", __func__); + return; + } + break; + } + default: + break; + } + break; + default: + ESP_LOGE(TAG, "Not a config client status message event"); + break; + } +} + +static void esp_ble_mesh_generic_client_cb(esp_ble_mesh_generic_client_cb_event_t event, + esp_ble_mesh_generic_client_cb_param_t *param) +{ + esp_ble_mesh_client_common_param_t common = {0}; + esp_ble_mesh_node_info_t *node = NULL; + uint32_t opcode; + uint16_t addr; + int err; + + opcode = param->params->opcode; + addr = param->params->ctx.addr; + + ESP_LOGI(TAG, "%s, error_code = 0x%02x, event = 0x%02x, addr: 0x%04x, opcode: 0x%04x", + __func__, param->error_code, event, param->params->ctx.addr, opcode); + + if (param->error_code) { + ESP_LOGE(TAG, "Send generic client message failed, opcode 0x%04x", opcode); + return; + } + + node = esp_ble_mesh_get_node_info(addr); + if (!node) { + ESP_LOGE(TAG, "%s: Get node info failed", __func__); + return; + } + + switch (event) { + case ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET: { + esp_ble_mesh_generic_client_set_state_t set_state = {0}; + node->onoff = param->status_cb.onoff_status.present_onoff; + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET onoff: 0x%02x", node->onoff); + /* After Generic OnOff Status for Generic OnOff Get is received, Generic OnOff Set will be sent */ + esp_ble_mesh_set_msg_common(&common, node, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET); + set_state.onoff_set.op_en = false; + set_state.onoff_set.onoff = !node->onoff; + set_state.onoff_set.tid = 0; + err = esp_ble_mesh_generic_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Generic OnOff Set failed", __func__); + return; + } + break; + } + default: + break; + } + break; + case ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: + node->onoff = param->status_cb.onoff_status.present_onoff; + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET onoff: 0x%02x", node->onoff); + break; + default: + break; + } + break; + case ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT: + break; + case ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT: + /* If failed to receive the responses, these messages will be resend */ + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET: { + esp_ble_mesh_generic_client_get_state_t get_state = {0}; + esp_ble_mesh_set_msg_common(&common, node, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET); + err = esp_ble_mesh_generic_client_get_state(&common, &get_state); + if (err) { + ESP_LOGE(TAG, "%s: Generic OnOff Get failed", __func__); + return; + } + break; + } + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: { + esp_ble_mesh_generic_client_set_state_t set_state = {0}; + node->onoff = param->status_cb.onoff_status.present_onoff; + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET onoff: 0x%02x", node->onoff); + esp_ble_mesh_set_msg_common(&common, node, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET); + set_state.onoff_set.op_en = false; + set_state.onoff_set.onoff = !node->onoff; + set_state.onoff_set.tid = 0; + err = esp_ble_mesh_generic_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Generic OnOff Set failed", __func__); + return; + } + break; + } + default: + break; + } + break; + default: + ESP_LOGE(TAG, "Not a generic client status message event"); + break; + } +} + +static int ble_mesh_init(void) +{ + uint8_t match[2] = {0xdd, 0xdd}; + int err = 0; + + prov_key.net_idx = ESP_BLE_MESH_KEY_PRIMARY; + prov_key.app_idx = APP_KEY_IDX; + memset(prov_key.app_key, APP_KEY_OCTET, sizeof(prov_key.app_key)); + + memcpy(dev_uuid, esp_bt_dev_get_address(), ESP_BD_ADDR_LEN); + + esp_ble_mesh_register_prov_callback(esp_ble_mesh_prov_cb); + esp_ble_mesh_register_custom_model_callback(esp_ble_mesh_model_cb); + esp_ble_mesh_register_config_client_callback(esp_ble_mesh_config_client_cb); + esp_ble_mesh_register_generic_client_callback(esp_ble_mesh_generic_client_cb); + + esp_ble_mesh_provisioner_set_dev_uuid_match(match, sizeof(match), 0x0, false); + + err = esp_ble_mesh_init(&provision, &composition); + if (err) { + ESP_LOGE(TAG, "Initializing mesh failed (err %d)", err); + return err; + } + + esp_ble_mesh_provisioner_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT); + + esp_ble_mesh_provisioner_add_local_app_key(prov_key.app_key, prov_key.net_idx, prov_key.app_idx); + + ESP_LOGI(TAG, "BLE Mesh Provisioner initialized"); + + return err; +} + +static esp_err_t bluetooth_init(void) +{ + esp_err_t ret; + + ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)); + + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + ret = esp_bt_controller_init(&bt_cfg); + if (ret) { + ESP_LOGE(TAG, "%s initialize controller failed", __func__); + return ret; + } + + ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); + if (ret) { + ESP_LOGE(TAG, "%s enable controller failed", __func__); + return ret; + } + ret = esp_bluedroid_init(); + if (ret) { + ESP_LOGE(TAG, "%s init bluetooth failed", __func__); + return ret; + } + ret = esp_bluedroid_enable(); + if (ret) { + ESP_LOGE(TAG, "%s enable bluetooth failed", __func__); + return ret; + } + + return ret; +} + +void app_main(void) +{ + int err; + + ESP_LOGI(TAG, "Initializing..."); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "esp32_bluetooth_init failed (err %d)", err); + return; + } + + /* Initialize the Bluetooth Mesh Subsystem */ + err = ble_mesh_init(); + if (err) { + ESP_LOGE(TAG, "Bluetooth mesh init failed (err %d)", err); + } +} diff --git a/examples/bluetooth/ble_mesh/ble_mesh_provisioner/main/component.mk b/examples/bluetooth/ble_mesh/ble_mesh_provisioner/main/component.mk new file mode 100644 index 0000000000..a98f634eae --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_provisioner/main/component.mk @@ -0,0 +1,4 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/bluetooth/ble_mesh/ble_mesh_provisioner/sdkconfig.defaults b/examples/bluetooth/ble_mesh/ble_mesh_provisioner/sdkconfig.defaults new file mode 100644 index 0000000000..12c5be5d12 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_provisioner/sdkconfig.defaults @@ -0,0 +1,40 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y +CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY= +CONFIG_BTDM_CONTROLLER_MODE_BTDM= +CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n +CONFIG_BLE_SCAN_DUPLICATE=y +CONFIG_SCAN_DUPLICATE_TYPE=2 +CONFIG_DUPLICATE_SCAN_CACHE_SIZE=200 +CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y +CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE=200 +CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_HCI_5_0=y +CONFIG_BLE_MESH_USE_DUPLICATE_SCAN=y +CONFIG_BLE_MESH_PROV=y +CONFIG_BLE_MESH_PROVISIONER=y +CONFIG_BLE_MESH_WAIT_FOR_PROV_MAX_DEV_NUM=10 +CONFIG_BLE_MESH_MAX_STORED_NODES=10 +CONFIG_BLE_MESH_MAX_PROV_NODES=10 +CONFIG_BLE_MESH_PBA_SAME_TIME=3 +CONFIG_BLE_MESH_PBG_SAME_TIME=2 +CONFIG_BLE_MESH_PROVISIONER_SUBNET_COUNT=3 +CONFIG_BLE_MESH_PROVISIONER_APP_KEY_COUNT=3 +CONFIG_BLE_MESH_PB_ADV=y +CONFIG_BLE_MESH_NET_BUF_POOL_USAGE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_GATT_PROXY=y +CONFIG_BLE_MESH_RELAY=y +CONFIG_BLE_MESH_LOW_POWER= +CONFIG_BLE_MESH_FRIEND= +CONFIG_BLE_MESH_ADV_BUF_COUNT=60 +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=6 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=6 +CONFIG_BLE_MESH_RX_SDU_MAX=384 +CONFIG_BLE_MESH_TX_SEG_MAX=32 +CONFIG_BTU_TASK_STACK_SIZE=4512 +CONFIG_BLE_MESH_CFG_CLI=y +CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_provisioner/tutorial/Ble_Mesh_Provisioner_Example_Walkthrough.md b/examples/bluetooth/ble_mesh/ble_mesh_provisioner/tutorial/Ble_Mesh_Provisioner_Example_Walkthrough.md new file mode 100644 index 0000000000..53d0f9d04e --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_provisioner/tutorial/Ble_Mesh_Provisioner_Example_Walkthrough.md @@ -0,0 +1,129 @@ + +# Demo for ESP BLE Mesh Provisioner + +## 1. Introduction + +This demo shows how a BLE Mesh device can function as a Provisioner. If you are new to BLE Mesh, please start by checking [Demo for ESP BLE Mesh Node](../../ble_mesh_node/README.md). + +## 2. Code Flow + +### 2.1 Initialization + +The code block below shows the initialization of BLE Mesh. + +```c +static int ble_mesh_init(void) +{ + uint8_t match[2] = {0xdd, 0xdd}; + int err = 0; + + prov_key.net_idx = ESP_BLE_MESH_KEY_PRIMARY; + prov_key.app_idx = ESP_BLE_MESH_APP_IDX; + memset(prov_key.app_key, APP_KEY_OCTET, sizeof(prov_key.app_key)); + + memcpy(dev_uuid, esp_bt_dev_get_address(), ESP_BD_ADDR_LEN); + + esp_ble_mesh_register_prov_callback(esp_ble_mesh_prov_cb); + esp_ble_mesh_register_custom_model_callback(esp_ble_mesh_model_cb); + esp_ble_mesh_register_config_client_callback(esp_ble_mesh_config_client_cb); + esp_ble_mesh_register_generic_client_callback(esp_ble_mesh_generic_client_cb); + + esp_ble_mesh_provisioner_set_dev_uuid_match(match, sizeof(match), 0x0, false); + + err = esp_ble_mesh_init(&provision, &composition); + if (err) { + ESP_LOGE(TAG, "Initializing mesh failed (err %d)", err); + return err; + } + + esp_ble_mesh_provisioner_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT); + + esp_ble_mesh_provisioner_add_local_app_key(prov_key.app_key, prov_key.net_idx, prov_key.app_idx); + + ESP_LOGI(TAG, "Provisioner initialized"); + + return err; +} +``` + +The following procedures are needed for the initialization with `ble_mesh_init`. + +1. `???`: adds the device to the list of devices for provisioning. Once a device is added, BLE Mesh protocol stack automatically provisions this device. +2. `esp_ble_mesh_provisioner_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT)`: call this API function to scan for the unprovisioned devices in the surrounding environment. + +### 2.2 Set and Bind AppKey + +While working as a Provisioner, a BLE Mesh device also needs to configure such parameters as AppKey, TTL, and Proxy after provisioning is finished. It is not required if a BLE Mesh device works as a node. + +Please note that successful configuring of AppKeys is of vital importance. App can only send/receive data (set a state, get a state and publish) after an AppKey has been set and bound. + +```c +static esp_err_t prov_complete(int node_idx, const esp_ble_mesh_octet16_t uuid, + uint16_t unicast, uint8_t elem_num, uint16_t net_idx) +{ + esp_ble_mesh_client_common_param_t common = {0}; + esp_ble_mesh_cfg_client_get_state_t get_state = {0}; + esp_ble_mesh_node_info_t *node = NULL; + char name[10]; + int err; + + ESP_LOGI(TAG, "node index: 0x%x, unicast address: 0x%02x, element num: %d, netkey index: 0x%02x", + node_idx, unicast, elem_num, net_idx); + ESP_LOGI(TAG, "device uuid: %s", bt_hex(uuid, 16)); + + sprintf(name, "%s%d", "NODE-", node_idx); + err = esp_ble_mesh_provisioner_set_node_name(node_idx, name); + if (err) { + ESP_LOGE(TAG, "%s: Set node name failed", __func__); + return ESP_FAIL; + } + + err = esp_ble_mesh_store_node_info(uuid, unicast, elem_num, LED_OFF); + if (err) { + ESP_LOGE(TAG, "%s: Store node info failed", __func__); + return ESP_FAIL; + } + + node = esp_ble_mesh_get_node_info(unicast); + if (!node) { + ESP_LOGE(TAG, "%s: Get node info failed", __func__); + return ESP_FAIL; + } + + esp_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET); + get_state.comp_data_get.page = COMPOSITION_DATA_PAGE_0; + err = esp_ble_mesh_config_client_get_state(&common, &get_state); + if (err) { + ESP_LOGE(TAG, "%s: Send config comp data get failed", __func__); + return ESP_FAIL; + } + + return ESP_OK; +} +``` + +After provisioning is completed, the API function `esp_ble_mesh_provisioner_add_local_app_key` must be called to set and bind an AppKey. After that, the device can exchange model messages with peer devices. + +
Note: Set and bind AppKey is used to configure and bind an AppKey through the Configuration Client model. For this reason, a Provisioner must also register the Configuration Client model.
+ +### 2.3 Register the Configuration Client Model + +The process of registering the Configuration Client model is similar to registering other models, as can be seen below. + +```c +static esp_ble_mesh_client_t config_client; +``` +```c +static esp_ble_mesh_model_t root_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&config_server), + ESP_BLE_MESH_MODEL_CFG_CLI(&config_client), + ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(NULL, &onoff_client), +}; +``` + +The procedures to register the Configuration Client model include: + +1. `static esp_ble_mesh_client_t config_client`: defines a variable `config_client` of the type `esp_ble_mesh_client_t` +2. `ESP_BLE_MESH_MODEL_CFG_CLI(&config_client)`: use the macro `ESP_BLE_MESH_MODEL_CFG_CLI` to add the Configuration Client model to the `root_models` array. + +After the definition is completed, the Configuration Client model can be registered simply by passing the pointer of `element` to the BLE Mesh protocol stack. diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/CMakeLists.txt b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/CMakeLists.txt new file mode 100644 index 0000000000..cb92f4b374 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(fast_prov_vendor_model) diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/Makefile b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/Makefile new file mode 100644 index 0000000000..274dd33494 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/Makefile @@ -0,0 +1,10 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := fast_prov_vendor_model + +COMPONENT_ADD_INCLUDEDIRS := components/include + +include $(IDF_PATH)/make/project.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/CMakeLists.txt b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/CMakeLists.txt new file mode 100644 index 0000000000..44699eb00e --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/CMakeLists.txt @@ -0,0 +1,9 @@ +set(COMPONENT_SRCS "esp_fast_prov_client_model.c" + "esp_fast_prov_server_model.c" + "esp_fast_prov_operation.c") + +set(COMPONENT_ADD_INCLUDEDIRS ".") + +set(COMPONENT_REQUIRES bt) + +register_component() diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/component.mk b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/component.mk new file mode 100644 index 0000000000..646c890db8 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/component.mk @@ -0,0 +1,6 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) +# +COMPONENT_ADD_INCLUDEDIRS := . \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.c b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.c new file mode 100644 index 0000000000..a9d3d8bc8b --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.c @@ -0,0 +1,407 @@ +// Copyright 2017-2018 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 +#include + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_local_data_operation_api.h" + +#include "esp_fast_prov_operation.h" +#include "esp_fast_prov_client_model.h" +#include "esp_fast_prov_server_model.h" + +#define TAG "FAST_PROV_CLIENT" + +/* Note: these variables are used by ble_mesh_fast_prov_client demo */ + +#define GET_ALL_NODE_ADDR_TIMEOUT K_SECONDS(60) + +/* Timer used to send Fast Prov All Node Addr Get message */ +#if !defined(CONFIG_BLE_MESH_FAST_PROV) +static struct k_delayed_work get_all_node_addr_timer; +#endif + +/* Unicast address of the Primary Provisioner */ +static uint16_t prim_prov_addr; + +/* Note: these variables are used by ble_mesh_fast_prov_server demo */ + +/* Send 4 node addresses (8 octets) most each time to prevent segmentation */ +#define NODE_ADDR_SEND_MAX_LEN 8 + +/* Timer used to send self-provisioned node addresses to Primary Provisioner */ +struct k_delayed_work send_self_prov_node_addr_timer; +bt_mesh_atomic_t fast_prov_cli_flags; + +/* Self-provisioned node addresses that are being sent */ +typedef struct { + struct net_buf_simple *addr; /* Unicast addresses of self-provisioned nodes being sent */ + bool send_succeed; /* Indicate if sent operation is successful */ + bool ack_received; /* Indicate if sent address has been acked */ +} example_send_prov_node_addr_t; + +NET_BUF_SIMPLE_DEFINE_STATIC(send_addr, NODE_ADDR_SEND_MAX_LEN); +static example_send_prov_node_addr_t node_addr_send = { + .addr = &send_addr, + .send_succeed = true, + .ack_received = true, +}; + +/* Self-provisioned node addresses that have been sent successfully */ +uint16_t addr_already_sent[CONFIG_BLE_MESH_MAX_PROV_NODES]; + +static example_fast_prov_server_t *get_fast_prov_srv_user_data(void) +{ + esp_ble_mesh_model_t *model = NULL; + + model = example_find_model(esp_ble_mesh_get_primary_element_address(), + ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_SRV, CID_ESP); + if (!model) { + ESP_LOGE(TAG, "%s: Failed to get config server model", __func__); + return NULL; + } + + return (example_fast_prov_server_t *)(model->user_data); +} + +/* Timeout handler for send_self_prov_node_addr_timer */ +void example_send_self_prov_node_addr(struct k_work *work) +{ + example_fast_prov_server_t *fast_prov_srv = NULL; + esp_ble_mesh_model_t *model = NULL; + int i, j, err; + + bt_mesh_atomic_test_and_clear_bit(&fast_prov_cli_flags, SEND_SELF_PROV_NODE_ADDR_START); + + fast_prov_srv = get_fast_prov_srv_user_data(); + if (!fast_prov_srv) { + ESP_LOGE(TAG, "%s: Failed to get fast prov server model user_data", __func__); + return; + } + + model = example_find_model(esp_ble_mesh_get_primary_element_address(), + ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_CLI, CID_ESP); + if (!model) { + ESP_LOGE(TAG, "%s: Failed to get fast prov client model", __func__); + return; + } + + if (node_addr_send.send_succeed == true && node_addr_send.ack_received == false) { + ESP_LOGW(TAG, "%s: Previous node address message is being sent", __func__); + return; + } + + if (node_addr_send.send_succeed == true) { + /* If the previous node address message has been sent successfully, and when + * timeout event comes, we will update the send buffer (node_addr_send). + */ + net_buf_simple_reset(node_addr_send.addr); + for (i = 0; i < CONFIG_BLE_MESH_MAX_PROV_NODES; i++) { + uint16_t addr = example_get_node_address(i); + if (!ESP_BLE_MESH_ADDR_IS_UNICAST(addr)) { + continue; + } + for (j = 0; j < ARRAY_SIZE(addr_already_sent); j++) { + if (addr == addr_already_sent[j]) { + ESP_LOGW(TAG, "%s: node addr 0x%04x has already been sent", __func__, addr); + break; + } + } + if (j != ARRAY_SIZE(addr_already_sent)) { + continue; + } + net_buf_simple_add_le16(node_addr_send.addr, addr); + if (node_addr_send.addr->len == NODE_ADDR_SEND_MAX_LEN) { + break; + } + } + } + + if (node_addr_send.addr->len) { + example_msg_common_info_t info = { + .net_idx = fast_prov_srv->net_idx, + .app_idx = fast_prov_srv->app_idx, + .dst = fast_prov_srv->prim_prov_addr, + .timeout = 0, + .role = ROLE_FAST_PROV, + }; + err = example_send_fast_prov_self_prov_node_addr(model, &info, node_addr_send.addr); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to send node address", __func__); + node_addr_send.send_succeed = false; + } else { + node_addr_send.send_succeed = true; + } + node_addr_send.ack_received = false; + } + + /* If sending node addresses failed, the Provisioner will start the timer in case + * no other devices will be provisioned and the timer will never start. + */ + if (node_addr_send.send_succeed == false && node_addr_send.ack_received == false) { + if (!bt_mesh_atomic_test_and_set_bit(&fast_prov_cli_flags, SEND_SELF_PROV_NODE_ADDR_START)) { + k_delayed_work_submit(&send_self_prov_node_addr_timer, SEND_SELF_PROV_NODE_ADDR_TIMEOUT); + } + } + + return; +} + +#if !defined(CONFIG_BLE_MESH_FAST_PROV) +/* Timeout handler for get_all_node_addr_timer */ +static void example_get_all_node_addr(struct k_work *work) +{ + esp_ble_mesh_model_t *model = NULL; + example_node_info_t *node = NULL; + esp_err_t err; + + node = example_get_node_info(prim_prov_addr); + if (!node) { + ESP_LOGE(TAG, "%s: Failed to get node info", __func__); + return; + } + + model = example_find_model(esp_ble_mesh_get_primary_element_address(), + ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_CLI, CID_ESP); + if (!model) { + ESP_LOGE(TAG, "%s: Failed to get model info", __func__); + return; + } + + example_msg_common_info_t info = { + .net_idx = node->net_idx, + .app_idx = node->app_idx, + .dst = node->unicast_addr, + .timeout = 10000, + .role = ROLE_PROVISIONER, + }; + err = example_send_fast_prov_all_node_addr_get(model, &info); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to send Fast Prov Node Address Get message", __func__); + return; + } +} +#endif + +esp_err_t example_fast_prov_client_recv_timeout(uint32_t opcode, esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx) +{ +#if defined(CONFIG_BLE_MESH_FAST_PROV) + example_fast_prov_server_t *fast_prov_srv = NULL; +#endif + example_node_info_t *node = NULL; + esp_err_t err; + + ESP_LOGW(TAG, "%s: Receive fast prov server status timeout", __func__); + + if (!model || !ctx) { + return ESP_ERR_INVALID_ARG; + } + +#if defined(CONFIG_BLE_MESH_FAST_PROV) + fast_prov_srv = get_fast_prov_srv_user_data(); + if (!fast_prov_srv) { + ESP_LOGE(TAG, "%s: Failed to get fast prov server model user_data", __func__); + return ESP_FAIL; + } +#endif + + switch (opcode) { + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET: { + example_fast_prov_info_set_t set = {0}; + node = example_get_node_info(ctx->addr); + if (!node) { + return ESP_FAIL; + } + example_msg_common_info_t info = { + .net_idx = node->net_idx, + .app_idx = node->app_idx, + .dst = node->unicast_addr, + .timeout = 0, + }; +#if defined(CONFIG_BLE_MESH_FAST_PROV) + if (node->lack_of_addr == false) { + set.ctx_flags = 0x03FE; + memcpy(&set.unicast_min, &node->unicast_min, + sizeof(example_node_info_t) - offsetof(example_node_info_t, unicast_min)); + } else { + set.ctx_flags = BIT(6); + set.group_addr = fast_prov_srv->group_addr; + } + info.role = ROLE_FAST_PROV; +#else + set.ctx_flags = 0x037F; + memcpy(&set.node_addr_cnt, &node->node_addr_cnt, + sizeof(example_node_info_t) - offsetof(example_node_info_t, node_addr_cnt)); + info.role = ROLE_PROVISIONER; +#endif + err = example_send_fast_prov_info_set(model, &info, &set); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to send Fast Prov Info Set message", __func__); + return ESP_FAIL; + } + break; + } + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD: + break; +#if defined(CONFIG_BLE_MESH_FAST_PROV) + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR: + if (node_addr_send.addr->len) { + example_msg_common_info_t info = { + .net_idx = fast_prov_srv->net_idx, + .app_idx = fast_prov_srv->app_idx, + .dst = fast_prov_srv->prim_prov_addr, + .timeout = 0, + .role = ROLE_FAST_PROV, + }; + err = example_send_fast_prov_self_prov_node_addr(model, &info, node_addr_send.addr); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to send Fast Prov Node Addr message", __func__); + node_addr_send.send_succeed = false; + } else { + node_addr_send.send_succeed = true; + } + node_addr_send.ack_received = false; + } + if (node_addr_send.send_succeed == false && node_addr_send.ack_received == false) { + if (!bt_mesh_atomic_test_and_set_bit(&fast_prov_cli_flags, SEND_SELF_PROV_NODE_ADDR_START)) { + k_delayed_work_submit(&send_self_prov_node_addr_timer, SEND_SELF_PROV_NODE_ADDR_TIMEOUT); + } + } + break; +#endif + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET: { + node = example_get_node_info(ctx->addr); + if (!node) { + return ESP_FAIL; + } + example_msg_common_info_t info = { + .net_idx = node->net_idx, + .app_idx = node->app_idx, + .dst = node->unicast_addr, + .timeout = 10000, + .role = ROLE_PROVISIONER, + }; + err = example_send_fast_prov_all_node_addr_get(model, &info); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to send Fast Prov Node Address message", __func__); + return ESP_FAIL; + } + break; + } + default: + break; + } + + return ESP_OK; +} + +esp_err_t example_fast_prov_client_recv_status(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, + uint16_t len, const uint8_t *data) +{ + if (!model || !ctx) { + return ESP_ERR_INVALID_ARG; + } + + ESP_LOG_BUFFER_HEX("fast prov client receives", data, len); + + switch (ctx->recv_op) { + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS: + ESP_LOG_BUFFER_HEX("fast prov info status", data, len); +#if !defined(CONFIG_BLE_MESH_FAST_PROV) + prim_prov_addr = ctx->addr; + k_delayed_work_init(&get_all_node_addr_timer, example_get_all_node_addr); + k_delayed_work_submit(&get_all_node_addr_timer, GET_ALL_NODE_ADDR_TIMEOUT); +#endif + break; + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS: + ESP_LOGI(TAG, "status_key: 0x%02x, status_act: 0x%02x", data[0], data[1]); + break; + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK: { + /* node address message has been acked */ + int i, j; + uint8_t length = node_addr_send.addr->len; + node_addr_send.send_succeed = true; + node_addr_send.ack_received = true; + for (i = 0; i < (length >> 1); i++) { + uint16_t addr = net_buf_simple_pull_le16(node_addr_send.addr); + if (ESP_BLE_MESH_ADDR_IS_UNICAST(addr)) { + for (j = 0; j < ARRAY_SIZE(addr_already_sent); j++) { + if (addr_already_sent[j] == addr) { + break; + } + } + if (j != ARRAY_SIZE(addr_already_sent)) { + continue; + } + for (j = 0; j < ARRAY_SIZE(addr_already_sent); j++) { + if (addr_already_sent[j] == ESP_BLE_MESH_ADDR_UNASSIGNED) { + addr_already_sent[j] = addr; + break; + } + } + if (j == ARRAY_SIZE(addr_already_sent)) { + ESP_LOGE(TAG, "%s: No place to store the sent node address", __func__); + return ESP_FAIL; + } + } + } + /* In case spending too much time on the first node address message(i.e. failed + * to receive ack), and the timer for the second or further messages is timeout, + * thus the Provisioner will never be able to send other addresses. + */ + if (!bt_mesh_atomic_test_and_set_bit(&fast_prov_cli_flags, SEND_SELF_PROV_NODE_ADDR_START)) { + k_delayed_work_submit(&send_self_prov_node_addr_timer, SEND_SELF_PROV_NODE_ADDR_TIMEOUT); + } + break; + } + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS: { + ESP_LOG_BUFFER_HEX("Node address", data, len); + esp_ble_mesh_model_t *cli_model = NULL; + example_node_info_t *node = NULL; + esp_err_t err; + node = example_get_node_info(prim_prov_addr); + if (!node) { + ESP_LOGE(TAG, "%s: Failed to get node info", __func__); + return ESP_FAIL; + } + cli_model = example_find_model(esp_ble_mesh_get_primary_element_address(), + ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, CID_NVAL); + if (!cli_model) { + ESP_LOGE(TAG, "%s: Failed to get Generic OnOff Client Model info", __func__); + return ESP_FAIL; + } + example_msg_common_info_t info = { + .net_idx = node->net_idx, + .app_idx = node->app_idx, + .dst = node->group_addr, + .timeout = 0, + .role = ROLE_PROVISIONER, + }; + err = example_send_generic_onoff_set(cli_model, &info, LED_ON, 0x00, false); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to send Generic OnOff Set Unack message", __func__); + return ESP_FAIL; + } + break; + } + default: + ESP_LOGE(TAG, "%s: Invalid fast prov status opcode", __func__); + return ESP_FAIL; + } + + return ESP_OK; +} \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.h b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.h new file mode 100644 index 0000000000..9dac3c241c --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.h @@ -0,0 +1,36 @@ +// Copyright 2017-2018 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. + +#ifndef _ESP_FAST_PROV_CLIENT_MODEL_H +#define _ESP_FAST_PROV_CLIENT_MODEL_H + +#include "esp_ble_mesh_defs.h" + +enum { + SEND_SELF_PROV_NODE_ADDR_START, /* Flag indicates the timer used to send self-provisioned node addresses has been started */ + CLI_MAX_FLAGS, +}; + +#define SEND_SELF_PROV_NODE_ADDR_TIMEOUT K_SECONDS(5) + +void example_send_self_prov_node_addr(struct k_work *work); + +esp_err_t example_fast_prov_client_recv_timeout(uint32_t opcode, esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx); + +esp_err_t example_fast_prov_client_recv_status(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, + uint16_t len, const uint8_t *data); + +#endif /* _ESP_FAST_PROV_CLIENT_MODEL_H */ \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_common.h b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_common.h new file mode 100644 index 0000000000..6f4771239f --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_common.h @@ -0,0 +1,121 @@ +// Copyright 2017-2018 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. + +#ifndef _ESP_FAST_PROV_COMMON_H +#define _ESP_FAST_PROV_COMMON_H + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_config_model_api.h" + +#define LED_OFF 0x00 +#define LED_ON 0x01 + +#define CID_ESP 0x02E5 +#define CID_NVAL 0xFFFF + +/* Fast Prov Model ID */ +#define ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_CLI 0x0000 +#define ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_SRV 0x0001 + +/* Fast Prov Message Opcode */ +#define ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET ESP_BLE_MESH_MODEL_OP_3(0x00, CID_ESP) +#define ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS ESP_BLE_MESH_MODEL_OP_3(0x01, CID_ESP) + +#define ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD ESP_BLE_MESH_MODEL_OP_3(0x02, CID_ESP) +#define ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS ESP_BLE_MESH_MODEL_OP_3(0x03, CID_ESP) + +#define ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR ESP_BLE_MESH_MODEL_OP_3(0x04, CID_ESP) +#define ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK ESP_BLE_MESH_MODEL_OP_3(0x05, CID_ESP) + +#define ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET ESP_BLE_MESH_MODEL_OP_3(0x06, CID_ESP) +#define ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS ESP_BLE_MESH_MODEL_OP_3(0x07, CID_ESP) + +#define ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_GROUP_ADD ESP_BLE_MESH_MODEL_OP_3(0x08, CID_ESP) + +#define ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_GROUP_DELETE ESP_BLE_MESH_MODEL_OP_3(0x09, CID_ESP) + +typedef struct { + uint16_t net_idx; + uint16_t app_idx; + uint16_t dst; + int32_t timeout; + esp_ble_mesh_dev_role_t role; +} example_msg_common_info_t; + +typedef struct { + uint16_t net_idx; + uint16_t app_idx; + uint8_t app_key[16]; + + uint16_t node_addr_cnt; /* Number of BLE Mesh nodes in the network */ + uint16_t unicast_min; /* Minimum unicast address to be assigned to the nodes in the network */ + uint16_t unicast_max; /* Maximum unicast address to be assigned to the nodes in the network */ + uint16_t group_addr; /* Group address which will be subscribed by the nodes in the network */ + uint8_t match_val[16]; /* Match value used by Fast Provisoning Provisioner */ + uint8_t match_len; + + uint8_t max_node_num; /* Maximum number of nodes can be provisioned by the client */ +} __attribute__((packed)) example_prov_info_t; + +/* Fast Prov Info Set Message Context */ +typedef struct { + uint16_t ctx_flags; /* Flags indicate which part of context exists */ + uint16_t node_addr_cnt; /* Number of the nodes going to be provisioned */ + uint16_t unicast_min; /* Assigned minimum unicast address */ + uint16_t unicast_max; /* Assigned maximum unicast address */ + uint8_t flags; /* Flags used for provisioning data */ + uint32_t iv_index; /* IV_index used for provisioning data */ + uint16_t net_idx; /* Netkey index used for provisioning data */ + uint16_t group_addr; /* Group address going to be added to model */ + uint16_t prov_addr; /* Primary Provisioner address */ + uint8_t match_val[16]; /* Match value used for provisioning */ + uint8_t match_len; + uint8_t action; /* Action used to enbale/disable Provisioner functionality */ +} __attribute__((packed)) example_fast_prov_info_set_t; + +typedef struct { + /* The following is the basic information of a node */ + bool reprov; + uint8_t uuid[16]; + uint16_t unicast_addr; + uint8_t element_num; + uint16_t net_idx; + uint16_t app_idx; + uint8_t onoff; + + /* The following is the information which will be/has been sent to the node */ + bool lack_of_addr; + uint16_t node_addr_cnt; + uint16_t unicast_min; + uint16_t unicast_max; + uint8_t flags; + uint32_t iv_index; + uint16_t fp_net_idx; + uint16_t group_addr; + uint16_t prov_addr; + uint8_t match_val[16]; + uint8_t match_len; + uint8_t action; +} __attribute__((packed)) example_node_info_t; + +typedef struct { + uint8_t net_key[16]; /* Network key going to be added */ +} example_fast_prov_net_key_add_t; + +typedef struct { + uint8_t status_key; /* Indicate the result of adding network key */ + uint8_t status_act; /* Indicate the result of action */ +} example_fast_prov_net_key_status_t; + +#endif /* _ESP_FAST_PROV_COMMON_H */ \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.c b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.c new file mode 100644 index 0000000000..c9a2bb795b --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.c @@ -0,0 +1,577 @@ +// Copyright 2017-2018 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 +#include + +#include "esp_ble_mesh_networking_api.h" +#include "esp_ble_mesh_provisioning_api.h" +#include "esp_ble_mesh_config_model_api.h" +#include "esp_ble_mesh_generic_model_api.h" +#include "esp_ble_mesh_local_data_operation_api.h" + +#include "esp_fast_prov_common.h" +#include "esp_fast_prov_operation.h" +#include "esp_fast_prov_client_model.h" +#include "esp_fast_prov_server_model.h" + +#define TAG "FAST_PROV_OP" + +/* Provisioned node information context */ +static example_node_info_t nodes_info[CONFIG_BLE_MESH_MAX_PROV_NODES] = { + [0 ... (CONFIG_BLE_MESH_MAX_PROV_NODES - 1)] = { + .reprov = false, + .unicast_addr = ESP_BLE_MESH_ADDR_UNASSIGNED, + .element_num = 0x0, + .net_idx = ESP_BLE_MESH_KEY_UNUSED, + .app_idx = ESP_BLE_MESH_KEY_UNUSED, + .onoff = LED_OFF, + .lack_of_addr = false, + .unicast_min = ESP_BLE_MESH_ADDR_UNASSIGNED, + .unicast_max = ESP_BLE_MESH_ADDR_UNASSIGNED, + .flags = 0x0, + .iv_index = 0x0, + .group_addr = ESP_BLE_MESH_ADDR_UNASSIGNED, + .prov_addr = ESP_BLE_MESH_ADDR_UNASSIGNED, + .match_len = 0, + .action = FAST_PROV_ACT_NONE, + } +}; + +esp_err_t example_store_node_info(const uint8_t uuid[16], uint16_t node_addr, + uint8_t elem_num, uint16_t net_idx, + uint16_t app_idx, uint8_t onoff) +{ + example_node_info_t *node = NULL; + + if (!uuid || !ESP_BLE_MESH_ADDR_IS_UNICAST(node_addr) || !elem_num) { + return ESP_ERR_INVALID_ARG; + } + + for (int i = 0; i < ARRAY_SIZE(nodes_info); i++) { + node = &nodes_info[i]; + if (!memcmp(node->uuid, uuid, 16)) { + ESP_LOGW(TAG, "%s: reprovisioned node", __func__); + node->reprov = true; + node->unicast_addr = node_addr; + node->element_num = elem_num; + node->net_idx = net_idx; + node->app_idx = app_idx; + node->onoff = onoff; + return ESP_OK; + } + } + + for (int i = 0; i < ARRAY_SIZE(nodes_info); i++) { + node = &nodes_info[i]; + if (node->unicast_addr == ESP_BLE_MESH_ADDR_UNASSIGNED) { + memcpy(node->uuid, uuid, 16); + node->reprov = false; + node->unicast_addr = node_addr; + node->element_num = elem_num; + node->net_idx = net_idx; + node->app_idx = app_idx; + node->onoff = onoff; + node->lack_of_addr = false; + return ESP_OK; + } + } + + ESP_LOGE(TAG, "%s: nodes_info is full", __func__); + return ESP_FAIL; +} + +example_node_info_t *example_get_node_info(uint16_t node_addr) +{ + example_node_info_t *node = NULL; + + if (!ESP_BLE_MESH_ADDR_IS_UNICAST(node_addr)) { + return NULL; + } + + for (int i = 0; i < ARRAY_SIZE(nodes_info); i++) { + node = &nodes_info[i]; + if (node_addr >= node->unicast_addr && + node_addr < node->unicast_addr + node->element_num) { + return node; + } + } + + return NULL; +} + +bool example_is_node_exist(const uint8_t uuid[16]) +{ + example_node_info_t *node = NULL; + + if (!uuid) { + return false; + } + + for (int i = 0; i < ARRAY_SIZE(nodes_info); i++) { + node = &nodes_info[i]; + if (ESP_BLE_MESH_ADDR_IS_UNICAST(node->unicast_addr)) { + if (!memcmp(node->uuid, uuid, 16)) { + return true; + } + } + } + + return false; +} + +uint16_t example_get_node_address(int node_idx) +{ + return nodes_info[node_idx].unicast_addr; +} + +esp_ble_mesh_model_t *example_find_model(uint16_t element_addr, uint16_t model_id, + uint16_t company_id) +{ + esp_ble_mesh_elem_t *element = NULL; + + if (!ESP_BLE_MESH_ADDR_IS_UNICAST(element_addr)) { + return NULL; + } + + element = esp_ble_mesh_find_element(element_addr); + if (!element) { + return NULL; + } + + if (company_id == CID_NVAL) { + return esp_ble_mesh_find_sig_model(element, model_id); + } else { + return esp_ble_mesh_find_vendor_model(element, company_id, model_id); + } +} + +static esp_err_t example_set_app_idx_to_user_data(uint16_t app_idx) +{ + example_fast_prov_server_t *srv_data = NULL; + esp_ble_mesh_model_t *srv_model = NULL; + + srv_model = example_find_model(esp_ble_mesh_get_primary_element_address(), + ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_SRV, CID_ESP); + if (!srv_model) { + return ESP_FAIL; + } + + srv_data = (example_fast_prov_server_t *)(srv_model->user_data); + if (!srv_data) { + return ESP_FAIL; + } + + srv_data->app_idx = app_idx; + return ESP_OK; +} + +esp_err_t example_handle_config_app_key_add_evt(uint16_t app_idx) +{ + const esp_ble_mesh_comp_t *comp = NULL; + esp_ble_mesh_elem_t *element = NULL; + esp_ble_mesh_model_t *model = NULL; + int i, j, k; + + comp = esp_ble_mesh_get_composition_data(); + if (!comp) { + return ESP_FAIL; + } + + for (i = 0; i < comp->element_count; i++) { + element = &comp->elements[i]; + /* Bind app_idx with SIG models except the Config Client & Server models */ + for (j = 0; j < element->sig_model_count; j++) { + model = &element->sig_models[j]; + if (model->model_id == ESP_BLE_MESH_MODEL_ID_CONFIG_SRV || + model->model_id == ESP_BLE_MESH_MODEL_ID_CONFIG_CLI) { + continue; + } + for (k = 0; k < ARRAY_SIZE(model->keys); k++) { + if (model->keys[k] == app_idx) { + break; + } + } + if (k != ARRAY_SIZE(model->keys)) { + continue; + } + for (k = 0; k < ARRAY_SIZE(model->keys); k++) { + if (model->keys[k] == ESP_BLE_MESH_KEY_UNUSED) { + model->keys[k] = app_idx; + break; + } + } + if (k == ARRAY_SIZE(model->keys)) { + ESP_LOGE(TAG, "%s: SIG model (model_id 0x%04x) is full of AppKey", + __func__, model->model_id); + } + } + /* Bind app_idx with Vendor models */ + for (j = 0; j < element->vnd_model_count; j++) { + model = &element->vnd_models[j]; + for (k = 0; k < ARRAY_SIZE(model->keys); k++) { + if (model->keys[k] == app_idx) { + break; + } + } + if (k != ARRAY_SIZE(model->keys)) { + continue; + } + for (k = 0; k < ARRAY_SIZE(model->keys); k++) { + if (model->keys[k] == ESP_BLE_MESH_KEY_UNUSED) { + model->keys[k] = app_idx; + break; + } + } + if (k == ARRAY_SIZE(model->keys)) { + ESP_LOGE(TAG, "%s: Vendor model (model_id 0x%04x, cid: 0x%04x) is full of AppKey", + __func__, model->vnd.model_id, model->vnd.company_id); + } + } + } + + return example_set_app_idx_to_user_data(app_idx); +} + +esp_err_t example_add_fast_prov_group_address(uint16_t model_id, uint16_t group_addr) +{ + const esp_ble_mesh_comp_t *comp = NULL; + esp_ble_mesh_elem_t *element = NULL; + esp_ble_mesh_model_t *model = NULL; + int i, j; + + if (!ESP_BLE_MESH_ADDR_IS_GROUP(group_addr)) { + return ESP_ERR_INVALID_ARG; + } + + comp = esp_ble_mesh_get_composition_data(); + if (!comp) { + return ESP_FAIL; + } + + for (i = 0; i < comp->element_count; i++) { + element = &comp->elements[i]; + model = esp_ble_mesh_find_sig_model(element, model_id); + if (!model) { + continue; + } + for (j = 0; j < ARRAY_SIZE(model->groups); j++) { + if (model->groups[j] == group_addr) { + break; + } + } + if (j != ARRAY_SIZE(model->groups)) { + ESP_LOGW(TAG, "%s: Group address already exists, element index: %d", __func__, i); + continue; + } + for (j = 0; j < ARRAY_SIZE(model->groups); j++) { + if (model->groups[j] == ESP_BLE_MESH_ADDR_UNASSIGNED) { + model->groups[j] = group_addr; + break; + } + } + if (j == ARRAY_SIZE(model->groups)) { + ESP_LOGE(TAG, "%s: Model is full of group address, element index: %d", __func__, i); + } + } + + return ESP_OK; +} + +esp_err_t example_delete_fast_prov_group_address(uint16_t model_id, uint16_t group_addr) +{ + const esp_ble_mesh_comp_t *comp = NULL; + esp_ble_mesh_elem_t *element = NULL; + esp_ble_mesh_model_t *model = NULL; + int i, j; + + if (!ESP_BLE_MESH_ADDR_IS_GROUP(group_addr)) { + return ESP_ERR_INVALID_ARG; + } + + comp = esp_ble_mesh_get_composition_data(); + if (comp == NULL) { + return ESP_FAIL; + } + + for (i = 0; i < comp->element_count; i++) { + element = &comp->elements[i]; + + model = esp_ble_mesh_find_sig_model(element, model_id); + if (model == NULL) { + continue; + } + for (j = 0; j < ARRAY_SIZE(model->groups); j++) { + if (model->groups[j] == group_addr) { + model->groups[j] = ESP_BLE_MESH_ADDR_UNASSIGNED; + break; + } + } + } + + return ESP_OK; +} + +esp_err_t example_send_config_appkey_add(esp_ble_mesh_model_t *model, + example_msg_common_info_t *info, + esp_ble_mesh_cfg_app_key_add_t *add_key) +{ + esp_ble_mesh_client_common_param_t common = {0}; + esp_ble_mesh_cfg_client_set_state_t set = {0}; + const uint8_t *key = NULL; + + if (!model || !info) { + return ESP_ERR_INVALID_ARG; + } + + if (add_key) { + set.app_key_add.net_idx = add_key->net_idx; + set.app_key_add.app_idx = add_key->app_idx; + memcpy(set.app_key_add.app_key, add_key->app_key, 16); + } else { +#if defined(CONFIG_BLE_MESH_FAST_PROV) + key = esp_ble_mesh_get_fast_prov_app_key(info->net_idx, info->app_idx); +#endif + if (!key) { + return ESP_FAIL; + } + set.app_key_add.net_idx = info->net_idx; + set.app_key_add.app_idx = info->app_idx; + memcpy(set.app_key_add.app_key, key, 16); + } + + common.opcode = ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD; + common.model = model; + common.ctx.net_idx = info->net_idx; + common.ctx.app_idx = 0x0000; /* not used for config messages */ + common.ctx.addr = info->dst; + common.ctx.send_rel = false; + common.ctx.send_ttl = 0; + common.msg_timeout = info->timeout; + common.msg_role = info->role; + + return esp_ble_mesh_config_client_set_state(&common, &set); +} + +esp_err_t example_send_generic_onoff_get(esp_ble_mesh_model_t *model, + example_msg_common_info_t *info) +{ + esp_ble_mesh_generic_client_get_state_t get = {0}; + esp_ble_mesh_client_common_param_t common = {0}; + + if (!model || !info) { + return ESP_ERR_INVALID_ARG; + } + + common.opcode = ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET; + common.model = model; + common.ctx.net_idx = info->net_idx; + common.ctx.app_idx = info->app_idx; + common.ctx.addr = info->dst; + common.ctx.send_rel = false; + common.ctx.send_ttl = 0; + common.msg_timeout = info->timeout; + common.msg_role = info->role; + + return esp_ble_mesh_generic_client_get_state(&common, &get); +} + +esp_err_t example_send_generic_onoff_set(esp_ble_mesh_model_t *model, + example_msg_common_info_t *info, + uint8_t onoff, uint8_t tid, bool need_ack) +{ + esp_ble_mesh_generic_client_set_state_t set = {0}; + esp_ble_mesh_client_common_param_t common = {0}; + + if (!model || !info) { + return ESP_ERR_INVALID_ARG; + } + + set.onoff_set.onoff = onoff; + set.onoff_set.tid = tid; + set.onoff_set.op_en = false; + + if (need_ack) { + common.opcode = ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET; + } else { + common.opcode = ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK; + } + common.model = model; + common.ctx.net_idx = info->net_idx; + common.ctx.app_idx = info->app_idx; + common.ctx.addr = info->dst; + common.ctx.send_rel = false; + common.ctx.send_ttl = 0; + common.msg_timeout = info->timeout; + common.msg_role = info->role; + + return esp_ble_mesh_generic_client_set_state(&common, &set); +} + +esp_err_t example_send_fast_prov_info_set(esp_ble_mesh_model_t *model, + example_msg_common_info_t *info, + example_fast_prov_info_set_t *set) +{ + struct net_buf_simple *msg = NULL; + esp_err_t err; + + if (!model || !set || !set->ctx_flags || !info) { + return ESP_ERR_INVALID_ARG; + } + + ESP_LOGI(TAG, "min: 0x%04x, max: 0x%04x", set->unicast_min, set->unicast_max); + ESP_LOGI(TAG, "flags: 0x%02x, iv_index: 0x%08x", set->flags, set->iv_index); + ESP_LOGI(TAG, "net_idx: 0x%04x, group_addr: 0x%04x", set->net_idx, set->group_addr); + ESP_LOGI(TAG, "action: 0x%02x", set->action); + ESP_LOG_BUFFER_HEX("FAST_PROV_OP: match_val", set->match_val, set->match_len); + + msg = bt_mesh_alloc_buf(18 + set->match_len); + if (!msg) { + return ESP_FAIL; + } + + net_buf_simple_add_le16(msg, set->ctx_flags); + if (set->ctx_flags & BIT(0)) { + net_buf_simple_add_le16(msg, set->node_addr_cnt); + } + if (set->ctx_flags & BIT(1)) { + net_buf_simple_add_le16(msg, set->unicast_min); + } + if (set->ctx_flags & BIT(2)) { + net_buf_simple_add_le16(msg, set->unicast_max); + } + if (set->ctx_flags & BIT(3)) { + net_buf_simple_add_u8(msg, set->flags); + } + if (set->ctx_flags & BIT(4)) { + net_buf_simple_add_le32(msg, set->iv_index); + } + if (set->ctx_flags & BIT(5)) { + net_buf_simple_add_le16(msg, set->net_idx); + } + if (set->ctx_flags & BIT(6)) { + net_buf_simple_add_le16(msg, set->group_addr); + } + if (set->ctx_flags & BIT(7)) { + net_buf_simple_add_le16(msg, set->prov_addr); + } + if (set->ctx_flags & BIT(8)) { + net_buf_simple_add_mem(msg, set->match_val, set->match_len); + } + if (set->ctx_flags & BIT(9)) { + net_buf_simple_add_u8(msg, set->action); + } + + esp_ble_mesh_msg_ctx_t ctx = { + .net_idx = info->net_idx, + .app_idx = info->app_idx, + .addr = info->dst, + .send_rel = false, + .send_ttl = 0, + }; + err = esp_ble_mesh_client_model_send_msg(model, &ctx, + ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET, + msg->len, msg->data, info->timeout, true, info->role); + + bt_mesh_free_buf(msg); + return err; +} + +esp_err_t example_send_fast_prov_net_key_add(esp_ble_mesh_model_t *model, + example_msg_common_info_t *info, + uint8_t net_key[16]) +{ + if (!model || !info || !net_key) { + return ESP_ERR_INVALID_ARG; + } + + esp_ble_mesh_msg_ctx_t ctx = { + .net_idx = info->net_idx, + .app_idx = info->app_idx, + .addr = info->dst, + .send_rel = false, + .send_ttl = 0, + }; + + return esp_ble_mesh_client_model_send_msg(model, &ctx, + ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD, + 16, net_key, info->timeout, true, info->role); +} + +esp_err_t example_send_fast_prov_self_prov_node_addr(esp_ble_mesh_model_t *model, + example_msg_common_info_t *info, + struct net_buf_simple *node_addr) +{ + if (!model || !info || !node_addr || (node_addr->len % 2)) { + return ESP_ERR_INVALID_ARG; + } + + ESP_LOG_BUFFER_HEX("Send node address", node_addr->data, node_addr->len); + + esp_ble_mesh_msg_ctx_t ctx = { + .net_idx = info->net_idx, + .app_idx = info->app_idx, + .addr = info->dst, + .send_rel = false, + .send_ttl = 0, + }; + + return esp_ble_mesh_client_model_send_msg(model, &ctx, + ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR, + node_addr->len, node_addr->data, info->timeout, true, info->role); +} + +esp_err_t example_send_fast_prov_all_node_addr_get(esp_ble_mesh_model_t *model, + example_msg_common_info_t *info) +{ + if (!model || !info) { + return ESP_ERR_INVALID_ARG; + } + + esp_ble_mesh_msg_ctx_t ctx = { + .net_idx = info->net_idx, + .app_idx = info->app_idx, + .addr = info->dst, + .send_rel = false, + .send_ttl = 0, + }; + + return esp_ble_mesh_client_model_send_msg(model, &ctx, + ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET, + 0, NULL, info->timeout, true, info->role); +} + +esp_err_t example_send_fast_prov_status_msg(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, + uint32_t opcode, struct net_buf_simple *msg) +{ + if (!model || !ctx) { + return ESP_ERR_INVALID_ARG; + } + + switch (opcode) { + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS: + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS: + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK: + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS: + ctx->send_ttl = 0; + ctx->send_rel = false; + break; + default: + ESP_LOGW(TAG, "%s: Invalid fast prov status opcode 0x%04x", __func__, opcode); + return ESP_FAIL; + } + + return esp_ble_mesh_server_model_send_msg(model, ctx, opcode, msg ? msg->len : 0, msg ? msg->data : NULL); +} \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.h b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.h new file mode 100644 index 0000000000..3a3135062e --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.h @@ -0,0 +1,69 @@ +// Copyright 2017-2018 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. + +#ifndef _ESP_FAST_PROV_OPERATION_H +#define _ESP_FAST_PROV_OPERATION_H + +#include "esp_fast_prov_common.h" + +esp_err_t example_store_node_info(const uint8_t uuid[16], uint16_t node_addr, + uint8_t elem_num, uint16_t net_idx, + uint16_t app_idx, uint8_t onoff); + +example_node_info_t *example_get_node_info(uint16_t node_addr); + +bool example_is_node_exist(const uint8_t uuid[16]); + +uint16_t example_get_node_address(int node_idx); + +esp_ble_mesh_model_t *example_find_model(uint16_t element_addr, uint16_t model_id, + uint16_t company_id); + +esp_err_t example_handle_config_app_key_add_evt(uint16_t app_idx); + +esp_err_t example_add_fast_prov_group_address(uint16_t model_id, uint16_t group_addr); + +esp_err_t example_delete_fast_prov_group_address(uint16_t model_id, uint16_t group_addr); + +esp_err_t example_send_config_appkey_add(esp_ble_mesh_model_t *model, + example_msg_common_info_t *info, + esp_ble_mesh_cfg_app_key_add_t *add_key); + +esp_err_t example_send_generic_onoff_get(esp_ble_mesh_model_t *model, + example_msg_common_info_t *info); + +esp_err_t example_send_generic_onoff_set(esp_ble_mesh_model_t *model, + example_msg_common_info_t *info, + uint8_t onoff, uint8_t tid, bool need_ack); + +esp_err_t example_send_fast_prov_info_set(esp_ble_mesh_model_t *model, + example_msg_common_info_t *info, + example_fast_prov_info_set_t *set); + +esp_err_t example_send_fast_prov_net_key_add(esp_ble_mesh_model_t *model, + example_msg_common_info_t *info, + uint8_t net_key[16]); + +esp_err_t example_send_fast_prov_self_prov_node_addr(esp_ble_mesh_model_t *model, + example_msg_common_info_t *info, + struct net_buf_simple *node_addr); + +esp_err_t example_send_fast_prov_all_node_addr_get(esp_ble_mesh_model_t *model, + example_msg_common_info_t *info); + +esp_err_t example_send_fast_prov_status_msg(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, + uint32_t opcode, struct net_buf_simple *msg); + +#endif /* _ESP_FAST_PROV_OPERATION_H */ \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.c b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.c new file mode 100644 index 0000000000..99f4facff5 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.c @@ -0,0 +1,640 @@ +// Copyright 2017-2018 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 +#include + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_local_data_operation_api.h" +#include "esp_ble_mesh_provisioning_api.h" +#include "esp_ble_mesh_networking_api.h" +#include "esp_ble_mesh_proxy_api.h" +#include "esp_ble_mesh_config_model_api.h" + +#include "esp_fast_prov_operation.h" +#include "esp_fast_prov_server_model.h" + +#define TAG "FAST_PROV_SERVER" + +/* Array used to store all node addresses */ +static uint16_t all_node_addr[120]; +static uint16_t all_node_addr_cnt; + +esp_err_t example_store_remote_node_address(uint16_t node_addr) +{ + if (!ESP_BLE_MESH_ADDR_IS_UNICAST(node_addr)) { + ESP_LOGE(TAG, "%s: Not a unicast address", __func__); + return ESP_ERR_INVALID_ARG; + } + + for (int i = 0; i < ARRAY_SIZE(all_node_addr); i++) { + if (all_node_addr[i] == node_addr) { + ESP_LOGW(TAG, "%s: Node address 0x%04x already exists", __func__, node_addr); + return ESP_OK; + } + } + + for (int i = 0; i < ARRAY_SIZE(all_node_addr); i++) { + if (all_node_addr[i] == ESP_BLE_MESH_ADDR_UNASSIGNED) { + all_node_addr[i] = node_addr; + all_node_addr_cnt++; + return ESP_OK; + } + } + + ESP_LOGE(TAG, "%s: remote node address queue is full", __func__); + return ESP_FAIL; +} + +esp_ble_mesh_cfg_srv_t *get_cfg_srv_user_data(void) +{ + esp_ble_mesh_model_t *model = NULL; + + model = example_find_model(esp_ble_mesh_get_primary_element_address(), + ESP_BLE_MESH_MODEL_ID_CONFIG_SRV, CID_NVAL); + if (!model) { + ESP_LOGE(TAG, "%s: Failed to get config server model", __func__); + return NULL; + } + + return (esp_ble_mesh_cfg_srv_t *)(model->user_data); +} + +/* Timeout handler for disable_fast_prov_timer */ +static void disable_fast_prov_cb(struct k_work *work) +{ + example_fast_prov_server_t *srv = NULL; + + srv = CONTAINER_OF(work, example_fast_prov_server_t, disable_fast_prov_timer.work); + if (!srv) { + ESP_LOGE(TAG, "%s: Failed to get fast prov server model user_data", __func__); + return; + } + + if (esp_ble_mesh_set_fast_prov_action(FAST_PROV_ACT_SUSPEND)) { + ESP_LOGE(TAG, "%s: Failed to disable fast provisioning", __func__); + return; + } +} + +/* Timeout handler for gatt_proxy_enable_timer */ +static void enable_gatt_proxy_cb(struct k_work *work) +{ + example_fast_prov_server_t *srv = NULL; + + srv = CONTAINER_OF(work, example_fast_prov_server_t, gatt_proxy_enable_timer.work); + if (!srv) { + ESP_LOGE(TAG, "%s: Failed to get fast prov server model user_data", __func__); + return; + } + + if (bt_mesh_atomic_test_and_clear_bit(srv->srv_flags, RELAY_PROXY_DISABLED)) { + ESP_LOGI(TAG, "%s: Enable BLE Mesh Relay & GATT Proxy", __func__); + /* For Primary Provisioner, Relay will not be enabled */ + esp_ble_mesh_proxy_gatt_enable(); + esp_ble_mesh_proxy_identity_enable(); + } + + return; +} + +static void example_free_set_info(example_fast_prov_server_t *srv) +{ + if (srv && srv->set_info) { + osi_free(srv->set_info); + srv->set_info = NULL; + } +} + +esp_err_t example_fast_prov_server_recv_msg(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, struct net_buf_simple *buf) +{ + example_fast_prov_server_t *srv = NULL; + struct net_buf_simple *msg = NULL; + uint32_t opcode = 0; + esp_err_t err; + + if (!model || !model->user_data || !ctx || !buf) { + return ESP_ERR_INVALID_ARG; + } + + srv = (example_fast_prov_server_t *)model->user_data; + + ESP_LOG_BUFFER_HEX("fast prov server recv", buf->data, buf->len); + + switch (ctx->recv_op) { + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET: { + /* fast prov info status (maximum 9 octets): + * status_bit_mask (2) + status_ctx_flag (1) + status_unicast (1) + status_net_idx (1) + + * status_group (1) + status_pri_prov (1) + status_match (1) + status_action (1). + */ + uint8_t match_len = 0, match_val[16]; + uint8_t status_unicast = 0; + uint8_t flags = 0; + + msg = bt_mesh_alloc_buf(9); + opcode = ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS; + + if (srv->set_info) { + ESP_LOGW(TAG, "%s: Set fast prov info is already in progress", __func__); + net_buf_simple_add_le16(msg, 0xFFFF); + break; + } + + /* If fast prov server state is pending, can not set fast prov info, + * and send response message with all status set to 0x01 (i.e. fail). + */ + if (srv->state == STATE_PEND) { + uint8_t val[7] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; + net_buf_simple_add_le16(msg, 0x7f); + net_buf_simple_add_mem(msg, val, sizeof(val)); + break; + } + + uint16_t ctx_flags = net_buf_simple_pull_le16(buf); + if (ctx_flags == 0) { + net_buf_simple_add_le16(msg, BIT(0)); + net_buf_simple_add_u8(msg, 0x01); /* invalid ctx_flags */ + break; + } + + uint16_t node_addr_cnt = (ctx_flags & BIT(0)) ? net_buf_simple_pull_le16(buf) : 0x0; + uint16_t unicast_min = (ctx_flags & BIT(1)) ? net_buf_simple_pull_le16(buf) : (esp_ble_mesh_get_primary_element_address() + esp_ble_mesh_get_element_count()); + uint16_t unicast_max = (ctx_flags & BIT(2)) ? net_buf_simple_pull_le16(buf) : 0x7FFF; + if (ctx_flags & BIT(3)) { + flags = net_buf_simple_pull_u8(buf); + } else { + flags = (uint8_t)bt_mesh.sub[0].kr_flag; + if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS)) { + flags |= BLE_MESH_NET_FLAG_IVU; + } + } + uint32_t iv_index = (ctx_flags & BIT(4)) ? net_buf_simple_pull_le32(buf) : bt_mesh.iv_index; + uint16_t net_idx = (ctx_flags & BIT(5)) ? net_buf_simple_pull_le16(buf) : srv->net_idx; + uint16_t group_addr = (ctx_flags & BIT(6)) ? net_buf_simple_pull_le16(buf) : ESP_BLE_MESH_ADDR_UNASSIGNED; + uint16_t pri_prov_addr = (ctx_flags & BIT(7)) ? net_buf_simple_pull_le16(buf) : ESP_BLE_MESH_ADDR_UNASSIGNED; + if (ctx_flags & BIT(8)) { + match_len = buf->len - ((ctx_flags & BIT(9)) ? 1 : 0); + memcpy(match_val, buf->data, match_len); + net_buf_simple_pull(buf, match_len); + } + uint8_t action = (ctx_flags & BIT(9)) ? net_buf_simple_pull_u8(buf) : FAST_PROV_ACT_NONE; + + /* If fast prov server state is active, the device can only suspend or exit fast provisioning */ + if (srv->state == STATE_ACTIVE) { + net_buf_simple_add_le16(msg, BIT(6)); + switch (action & BIT_MASK(2)) { + case FAST_PROV_ACT_SUSPEND: + case FAST_PROV_ACT_EXIT: + srv->pend_act = action & BIT_MASK(2); + if (!bt_mesh_atomic_test_and_set_bit(srv->srv_flags, DISABLE_FAST_PROV_START)) { + k_delayed_work_submit(&srv->disable_fast_prov_timer, DISABLE_FAST_PROV_TIMEOUT); + } + net_buf_simple_add_u8(msg, 0x00); /* action succeed */ + break; + default: + net_buf_simple_add_u8(msg, 0x04); /* action already in progress */ + break; + } + break; + } + + if ((ctx_flags & BIT(1)) || (ctx_flags & BIT(2))) { + if (!ESP_BLE_MESH_ADDR_IS_UNICAST(unicast_min) || !ESP_BLE_MESH_ADDR_IS_UNICAST(unicast_max)) { + status_unicast = 0x01; /* not a unicast address */ + } else if (unicast_min > unicast_max) { + status_unicast = 0x02; /* min bigger than max */ + } else if (unicast_min < (esp_ble_mesh_get_primary_element_address() + esp_ble_mesh_get_element_count())) { + status_unicast = 0x04; /* overlap with own element address */ + } + if (status_unicast) { + net_buf_simple_add_le16(msg, BIT(1)); + net_buf_simple_add_u8(msg, status_unicast); + break; + } + } + + if (ctx_flags & BIT(6)) { + if (!ESP_BLE_MESH_ADDR_IS_GROUP(group_addr)) { + net_buf_simple_add_le16(msg, BIT(3)); + net_buf_simple_add_u8(msg, 0x01); /* not a group address */ + break; + } + err = example_add_fast_prov_group_address(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, group_addr); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to add group address 0x%04x", __func__, group_addr); + net_buf_simple_add_le16(msg, BIT(3)); + net_buf_simple_add_u8(msg, 0x02); /* add group address failed */ + break; + } + srv->group_addr = group_addr; + } + + if (ctx_flags & BIT(7)) { + if (!ESP_BLE_MESH_ADDR_IS_UNICAST(pri_prov_addr)) { + net_buf_simple_add_le16(msg, BIT(4)); + net_buf_simple_add_u8(msg, 0x01); /* not a unicast address */ + break; + } + } + + if (ctx_flags & BIT(8)) { + if (match_len > 16) { + net_buf_simple_add_le16(msg, BIT(5)); + net_buf_simple_add_u8(msg, 0x01); /* too large match value length */ + break; + } + } + + if (ctx_flags & BIT(9)) { + if ((action & BIT_MASK(2)) != FAST_PROV_ACT_ENTER) { + net_buf_simple_add_le16(msg, BIT(6)); + net_buf_simple_add_u8(msg, 0x01); /* action failed */ + break; + } + } else { + net_buf_simple_add_le16(msg, BIT(6)); + net_buf_simple_add_u8(msg, 0x03); /* none action */ + break; + } + + memcpy(&srv->ctx, ctx, sizeof(esp_ble_mesh_msg_ctx_t)); + srv->set_info = osi_calloc(sizeof(struct fast_prov_info_set)); + if (!srv->set_info) { + ESP_LOGE(TAG, "%s: Failed to allocate memory", __func__); + bt_mesh_free_buf(msg); + return ESP_FAIL; + } + + if (unicast_max < unicast_min + srv->max_node_num - 1) { + srv->max_node_num = unicast_max - unicast_min + 1; + } + + srv->set_info->set_succeed = false; + srv->set_info->node_addr_cnt = node_addr_cnt; + srv->set_info->unicast_min = unicast_min; + srv->set_info->unicast_max = unicast_max; + srv->set_info->flags = flags; + srv->set_info->iv_index = iv_index; + srv->set_info->net_idx = net_idx; + srv->set_info->pri_prov_addr = pri_prov_addr; + srv->set_info->match_len = match_len; + memcpy(srv->set_info->match_val, match_val, match_len); + srv->set_info->action = action; + + esp_ble_mesh_fast_prov_info_t info_set = { + .unicast_min = unicast_min, + .unicast_max = unicast_min + srv->max_node_num - 1, + .flags = flags, + .iv_index = iv_index, + .net_idx = net_idx, + .offset = 0x00, + .match_len = match_len, + }; + memcpy(info_set.match_val, match_val, match_len); + err = esp_ble_mesh_set_fast_prov_info(&info_set); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to set fast prov info", __func__); + net_buf_simple_add_le16(msg, BIT(5) | BIT(2) | BIT(1)); + net_buf_simple_add_u8(msg, 0x01); /* set unicast failed */ + net_buf_simple_add_u8(msg, 0x01); /* set net_idx failed */ + net_buf_simple_add_u8(msg, 0x01); /* set UUID match failed */ + break; + } + /* If setting fast prov info successfully, wait for the event callback */ + bt_mesh_free_buf(msg); + return ESP_OK; + } + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD: { + uint8_t status_net_key, status_action; + + msg = bt_mesh_alloc_buf(2); + + if (srv->state == STATE_PEND) { + /* Add fast prov net_key, wait for event callback and call esp_ble_mesh_set_fast_prov_act() to set action */ + } else { + /* If state is not pending, can not add net_key */ + status_net_key = 0x01; /* status_net_key: fail */ + status_action = 0x01; /* status_action: fail */ + } + + opcode = ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS; + net_buf_simple_add_u8(msg, status_net_key); + net_buf_simple_add_u8(msg, status_action); + break; + } + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR: { + if (buf->len % 2) { + ESP_LOGE(TAG, "%s: Invalid Fast Prov Node Addr message length", __func__); + return ESP_FAIL; + } + + if (bt_mesh_atomic_test_and_clear_bit(srv->srv_flags, GATT_PROXY_ENABLE_START)) { + k_delayed_work_cancel(&srv->gatt_proxy_enable_timer); + } + + for (; buf->len; ) { + uint16_t node_addr = net_buf_simple_pull_le16(buf); + ESP_LOGI(TAG, "Node address: 0x%04x", node_addr); + err = example_store_remote_node_address(node_addr); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to store node address 0x%04x", __func__, node_addr); + } + } + + opcode = ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK; + break; + } + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET: { + /* Top device (e.g. phone) tries to get all node addresses */ + msg = bt_mesh_alloc_buf(all_node_addr_cnt * 2); + if (!msg) { + ESP_LOGE(TAG, "%s: Failed to allocate memory", __func__); + return ESP_FAIL; + } + + for (int i = 0; i < all_node_addr_cnt; i++) { + net_buf_simple_add_le16(msg, all_node_addr[i]); + } + ESP_LOG_BUFFER_HEX("All node address", msg->data, msg->len); + + opcode = ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS; + break; + } + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_GROUP_ADD: { + uint16_t own_addr = esp_ble_mesh_get_primary_element_address(); + uint16_t group_addr = net_buf_simple_pull_le16(buf); + ESP_LOGI(TAG, "%s, group address 0x%04x", __func__, group_addr); + if (!ESP_BLE_MESH_ADDR_IS_GROUP(group_addr)) { + return ESP_FAIL; + } + for (; buf->len; ) { + uint16_t dst = net_buf_simple_pull_le16(buf); + ESP_LOGI(TAG, "%s, dst 0x%04x, own address 0x%04x", __func__, dst, own_addr); + if (dst == own_addr) { + err = example_add_fast_prov_group_address(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, group_addr); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to add group address 0x%04x", __func__, group_addr); + } + return err; + } + } + return ESP_OK; + } + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_GROUP_DELETE: { + uint16_t own_addr = esp_ble_mesh_get_primary_element_address(); + uint16_t group_addr = net_buf_simple_pull_le16(buf); + ESP_LOGI(TAG, "%s, group address 0x%04x", __func__, group_addr); + if (!ESP_BLE_MESH_ADDR_IS_GROUP(group_addr)) { + return ESP_FAIL; + } + for (; buf->len; ) { + uint16_t dst = net_buf_simple_pull_le16(buf); + ESP_LOGI(TAG, "%s, dst 0x%04x, own address 0x%04x", __func__, dst, own_addr); + if (dst == own_addr) { + err = example_delete_fast_prov_group_address(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, group_addr); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to delete group address 0x%04x", __func__, group_addr); + } + return err; + } + } + return ESP_OK; + } + default: + ESP_LOGW(TAG, "%s: Not a Fast Prov Client message opcode", __func__); + return ESP_FAIL; + } + + err = example_send_fast_prov_status_msg(model, ctx, opcode, msg); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to send Fast Prov Status message", __func__); + example_free_set_info(srv); + } + + bt_mesh_free_buf(msg); + return err; +} + +esp_err_t example_handle_fast_prov_info_set_comp_evt(esp_ble_mesh_model_t *model, uint8_t status_unicast, + uint8_t status_net_idx, uint8_t status_match) +{ + example_fast_prov_server_t *srv = NULL; + struct net_buf_simple *msg = NULL; + esp_err_t err; + + if (!model || !model->user_data) { + return ESP_ERR_INVALID_ARG; + } + + srv = (example_fast_prov_server_t *)model->user_data; + if (!srv->set_info) { + return ESP_FAIL; + } + + msg = bt_mesh_alloc_buf(9); + + if (status_unicast || status_match) { + net_buf_simple_add_le16(msg, BIT(5) | BIT(1)); + net_buf_simple_add_u8(msg, status_unicast); + net_buf_simple_add_u8(msg, status_match); + goto send; + } + + /* Update Fast Prov Server Model user_data */ + srv->unicast_min = srv->set_info->unicast_min + srv->max_node_num; + srv->unicast_max = srv->set_info->unicast_max; + srv->unicast_cur = srv->set_info->unicast_min + srv->max_node_num; + if (srv->unicast_max <= srv->unicast_min) { + srv->unicast_step = 0; + } else { + srv->unicast_step = (srv->unicast_max - srv->unicast_min) / srv->max_node_num; + } + srv->flags = srv->set_info->flags; + srv->iv_index = srv->set_info->iv_index; + srv->net_idx = srv->set_info->net_idx; + if (srv->set_info->action & BIT(7)) { + srv->primary_role = true; + srv->node_addr_cnt = srv->set_info->node_addr_cnt; + srv->prim_prov_addr = esp_ble_mesh_get_primary_element_address(); + srv->top_address = srv->ctx.addr; + } else { + srv->primary_role = false; + srv->prim_prov_addr = srv->set_info->pri_prov_addr; + } + srv->match_len = srv->set_info->match_len; + memcpy(srv->match_val, srv->set_info->match_val, srv->set_info->match_len); + + if (status_net_idx) { + ESP_LOGW(TAG, "%s: Wait for fast prov netkey to be added", __func__); + srv->pend_act = FAST_PROV_ACT_ENTER; + srv->state = STATE_PEND; + net_buf_simple_add_le16(msg, BIT(6) | BIT(2)); + net_buf_simple_add_u8(msg, status_net_idx); /* wait for net_key */ + net_buf_simple_add_u8(msg, 0x02); /* pending action */ + goto send; + } + + /* Sets fast prov action */ + err = esp_ble_mesh_set_fast_prov_action(FAST_PROV_ACT_ENTER); + if (err == ESP_OK) { + bt_mesh_free_buf(msg); + return ESP_OK; + } + + ESP_LOGE(TAG, "%s: Failed to set fast prov action", __func__); + net_buf_simple_add_le16(msg, BIT(6)); + net_buf_simple_add_u8(msg, 0x01); /* action failed */ + +send: + err = example_send_fast_prov_status_msg(model, &srv->ctx, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS, msg); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to send Fast Prov Status message", __func__); + example_free_set_info(srv); + } + + bt_mesh_free_buf(msg); + return err; +} + +esp_err_t example_handle_fast_prov_action_set_comp_evt(esp_ble_mesh_model_t *model, uint8_t status_action) +{ + example_fast_prov_server_t *srv = NULL; + struct net_buf_simple *msg = NULL; + uint32_t opcode; + esp_err_t err; + + if (!model || !model->user_data) { + return ESP_ERR_INVALID_ARG; + } + + srv = (example_fast_prov_server_t *)model->user_data; + + msg = bt_mesh_alloc_buf(9); + + switch (srv->state) { + case STATE_IDLE: { /* fast prov info set (enter) */ + const uint8_t zero[6] = {0}; + net_buf_simple_add_le16(msg, 0x7f); + net_buf_simple_add_mem(msg, zero, 6); + net_buf_simple_add_u8(msg, status_action); + opcode = ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS; + /** + * Disable relay should not have a impact on Mesh Proxy PDU, and + * we can also move "disabling relay" in the event of "disabling + * gatt proxy" here. + */ + if (srv->node_addr_cnt == FAST_PROV_NODE_COUNT_MIN) { + if (bt_mesh_atomic_test_and_clear_bit(srv->srv_flags, GATT_PROXY_ENABLE_START)) { + k_delayed_work_cancel(&srv->gatt_proxy_enable_timer); + } + if (!bt_mesh_atomic_test_and_set_bit(srv->srv_flags, GATT_PROXY_ENABLE_START)) { + k_delayed_work_submit(&srv->gatt_proxy_enable_timer, K_SECONDS(3)); + } + } + break; + } + case STATE_ACTIVE: /* fast prov info set (suspend/exit) */ + /* Currently we only support suspend/exit fast prov after Generic + * OnOff Set/Set Unack is received. So no fast prov status message + * will be sent. + */ + case STATE_PEND: /* fast prov net_key add */ + /* In this case, we should send fast prov net_key status */ + default: + bt_mesh_free_buf(msg); + return ESP_OK; + } + + err = example_send_fast_prov_status_msg(model, &srv->ctx, opcode, msg); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: Failed to send Fast Prov Status message", __func__); + example_free_set_info(srv); + bt_mesh_free_buf(msg); + return ESP_FAIL; + } + + if (status_action == 0x00) { + if (srv->state == STATE_IDLE || srv->state == STATE_PEND) { + srv->state = STATE_ACTIVE; + } else if (srv->state == STATE_ACTIVE) { + srv->state = STATE_IDLE; + } + if (srv->set_info) { + srv->set_info->set_succeed = true; + } + } + + bt_mesh_free_buf(msg); + return ESP_OK; +} + +esp_err_t example_handle_fast_prov_status_send_comp_evt(int err_code, uint32_t opcode, + esp_ble_mesh_model_t *model, esp_ble_mesh_msg_ctx_t *ctx) +{ + example_fast_prov_server_t *srv = NULL; + + if (!model || !model->user_data) { + return ESP_ERR_INVALID_ARG; + } + + srv = (example_fast_prov_server_t *)model->user_data; + + ESP_LOGI(TAG, "%s: opcode 0x%06x", __func__, opcode); + + switch (opcode) { + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS: + if (err_code == 0 && srv->set_info && srv->set_info->set_succeed == true) { + if (!bt_mesh_atomic_test_and_set_bit(srv->srv_flags, RELAY_PROXY_DISABLED)) { + /* For Primary Provisioner: disable Relay and GATT Proxy; + * For other Provisioners: only disable GATT Proxy + */ + ESP_LOGW(TAG, "%s: Disable BLE Mesh Relay & GATT Proxy", __func__); + esp_ble_mesh_proxy_gatt_disable(); + } + } + example_free_set_info(srv); + break; + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS: + break; + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK: + if (!bt_mesh_atomic_test_and_set_bit(srv->srv_flags, GATT_PROXY_ENABLE_START)) { + k_delayed_work_submit(&srv->gatt_proxy_enable_timer, GATT_PROXY_ENABLE_TIMEOUT); + } + break; + case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS: + break; + default: + break; + } + + return ESP_OK; +} + +esp_err_t example_fast_prov_server_init(esp_ble_mesh_model_t *model) +{ + example_fast_prov_server_t *srv = NULL; + + if (!model || !model->user_data) { + return ESP_ERR_INVALID_ARG; + } + + srv = (example_fast_prov_server_t *)model->user_data; + srv->model = model; + + k_delayed_work_init(&srv->disable_fast_prov_timer, disable_fast_prov_cb); + k_delayed_work_init(&srv->gatt_proxy_enable_timer, enable_gatt_proxy_cb); + + return ESP_OK; +} diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.h b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.h new file mode 100644 index 0000000000..b4dec616a6 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.h @@ -0,0 +1,102 @@ +// Copyright 2017-2018 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. + +#ifndef _ESP_FAST_PROV_SERVER_MODEL_H +#define _ESP_FAST_PROV_SERVER_MODEL_H + +#include "esp_fast_prov_common.h" + +#define DISABLE_FAST_PROV_TIMEOUT K_SECONDS(10) +#define GATT_PROXY_ENABLE_TIMEOUT K_SECONDS(10) + +#define FAST_PROV_NODE_COUNT_MIN 0x01 + +enum { + DISABLE_FAST_PROV_START, /* Flag indicates the timer used to disable fast provisioning has been started */ + GATT_PROXY_ENABLE_START, /* Flag indicates the timer used to enable Mesh GATT Proxy has been started */ + RELAY_PROXY_DISABLED, /* Flag indicates if relay & proxy_adv are enabled or disabled */ + SRV_MAX_FLAGS, +}; + +enum { + STATE_IDLE, + STATE_PEND, + STATE_ACTIVE, + STATE_MAX, +}; + +struct fast_prov_info_set { + bool set_succeed; + uint16_t node_addr_cnt; + uint16_t unicast_min; + uint16_t unicast_max; + uint8_t flags; + uint32_t iv_index; + uint16_t net_idx; + uint16_t group_addr; + uint16_t pri_prov_addr; + uint8_t match_val[16]; + uint8_t match_len; + uint8_t action; +}; + +typedef struct { + esp_ble_mesh_model_t *model; /* Fast Prov Server model pointer */ + BLE_MESH_ATOMIC_DEFINE(srv_flags, SRV_MAX_FLAGS); + + bool primary_role; /* Indicate if the device is a Primary Provisioner */ + uint8_t max_node_num; /* The maximum number of devices can be provisioned by the Provisioner */ + uint8_t prov_node_cnt; /* Number of self-provisioned nodes */ + uint16_t app_idx; /* AppKey index of the application key added by other Provisioner */ + uint16_t top_address; /* Address of the device(e.g. phone) which triggers fast provisioning */ + + esp_ble_mesh_msg_ctx_t ctx; /* the context stored for sending fast prov status message */ + struct fast_prov_info_set *set_info; /* Used to store received fast prov info set context */ + + uint16_t node_addr_cnt; /* Number of node address shall be received */ + uint16_t unicast_min; /* Minimum unicast address can be send to other nodes */ + uint16_t unicast_max; /* Maximum unicast address can be send to other nodes */ + uint16_t unicast_cur; /* Current unicast address can be assigned */ + uint16_t unicast_step; /* Unicast address change step */ + uint8_t flags; /* Flags state */ + uint32_t iv_index; /* Iv_index state */ + uint16_t net_idx; /* Netkey index state */ + uint16_t group_addr; /* Subscribed group address */ + uint16_t prim_prov_addr; /* Unicast address of Primary Provisioner */ + uint8_t match_val[16]; /* Match value to be compared with unprovisioned device UUID */ + uint8_t match_len; /* Length of match value to be compared */ + + uint8_t pend_act; /* Pending action to be performed */ + uint8_t state; /* Fast prov state -> 0: idle, 1: pend, 2: active */ + + struct k_delayed_work disable_fast_prov_timer; /* Used to disable fast provisioning */ + struct k_delayed_work gatt_proxy_enable_timer; /* Used to enable Mesh GATT Proxy functionality */ +} __attribute__((packed)) example_fast_prov_server_t; + +esp_err_t example_store_remote_node_address(uint16_t node_addr); + +esp_err_t example_fast_prov_server_recv_msg(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, struct net_buf_simple *buf); + +esp_err_t example_handle_fast_prov_info_set_comp_evt(esp_ble_mesh_model_t *model, uint8_t status_unicast, + uint8_t status_net_idx, uint8_t status_match); + +esp_err_t example_handle_fast_prov_action_set_comp_evt(esp_ble_mesh_model_t *model, uint8_t status_action); + +esp_err_t example_handle_fast_prov_status_send_comp_evt(int err_code, uint32_t opcode, + esp_ble_mesh_model_t *model, esp_ble_mesh_msg_ctx_t *ctx); + +esp_err_t example_fast_prov_server_init(esp_ble_mesh_model_t *model); + +#endif /* _ESP_FAST_PROV_SERVER_MODEL_H */ \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/CMakeLists.txt b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/CMakeLists.txt new file mode 100644 index 0000000000..f475ba4612 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/CMakeLists.txt @@ -0,0 +1,3 @@ +set(COMPONENT_SRCS "main.c") + +register_component() diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/component.mk b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/component.mk new file mode 100644 index 0000000000..d68c5375e9 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/component.mk @@ -0,0 +1,5 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) +# \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/main.c b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/main.c new file mode 100644 index 0000000000..889f706f78 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/main.c @@ -0,0 +1,21 @@ +// Copyright 2017-2018 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. + +void app_main(void) +{ + /* This main.c is for CI. The fast_prov_vendor_model shall be + * included by other ble mesh examples which need vendor fast + * provisioning client/server models. + */ +} diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/sdkconfig.defaults b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/sdkconfig.defaults new file mode 100644 index 0000000000..da5392232d --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/sdkconfig.defaults @@ -0,0 +1,33 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_FAST_PROV=y +CONFIG_BLE_MESH_PROV=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PROVISIONER=y +CONFIG_BLE_MESH_WAIT_FOR_PROV_MAX_DEV_NUM=20 +CONFIG_BLE_MESH_MAX_STORED_NODES=10 +CONFIG_BLE_MESH_MAX_PROV_NODES=6 +CONFIG_BLE_MESH_PBA_SAME_TIME=3 +CONFIG_BLE_MESH_PBG_SAME_TIME=3 +CONFIG_BLE_MESH_PROVISIONER_SUBNET_COUNT=3 +CONFIG_BLE_MESH_PROVISIONER_APP_KEY_COUNT=9 +CONFIG_BLE_MESH_PB_ADV=y +CONFIG_BLE_MESH_NET_BUF_POOL_USAGE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_GATT_PROXY=y +CONFIG_BLE_MESH_RELAY=y +CONFIG_BLE_MESH_LOW_POWER= +CONFIG_BLE_MESH_FRIEND= +CONFIG_BTU_TASK_STACK_SIZE=4512 +CONFIG_BLE_MESH_CFG_CLI=y +CONFIG_BLE_MESH_CRPL=60 +CONFIG_BLE_MESH_MSG_CACHE_SIZE=60 +CONFIG_BLE_MESH_ADV_BUF_COUNT=200 +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SDU_MAX=384 +CONFIG_BLE_MESH_TX_SEG_MAX=32 +CONFIG_BLE_MESH_NO_LOG=n +CONFIG_BLE_MESH_STACK_TRACE_LEVEL=0 \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/CMakeLists.txt b/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/CMakeLists.txt new file mode 100644 index 0000000000..8f5e74e32f --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(ble_mesh_wifi_coexist) diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/Makefile b/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/Makefile new file mode 100644 index 0000000000..2db430c14f --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/Makefile @@ -0,0 +1,12 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := ble_mesh_wifi_coexist + +COMPONENT_ADD_INCLUDEDIRS := components/include + +EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components + +include $(IDF_PATH)/make/project.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/README.md b/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/README.md new file mode 100644 index 0000000000..8173486ffa --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/README.md @@ -0,0 +1,20 @@ +ESP BLE Mesh and WiFi Coexist example +======================== + +此demo是用来测试当BLE Mesh实现正常的配网和收发消息的正常功能时,WiFi 所能达到的最大throughput值。用户可以根据此demo中的throughput值来实现自己需要的应用场景。如果用户对ESP32 BLE Mesh使用方法还不熟悉的话, 可以参考[BLE Mesh brief introduction](../ble_mesh_node/README.md) + +此demo主要分为两个部分: + +- WiFi Iperf协议 +- BLE Mesh fast provision Server + +WiFi的Iperf协议使用方法请参考[WiFi Iperf README](../../../wifi/iperf/README.md) + +当WiFi的Iperf开起来之后,BLE Mesh就可以使用fast provsion 进行配网了,此demo只实现了fast provsion 的server功能。此demo 的BLE Mesh模块实现了一个Element和以下几个Model: + +- Config Server Model: 此Model是当对方需要配置APP Key, Dev Key,等信息时,需要使用此Model +- Config Client Model: 此Model是当需要配置APP Key, Dev Key,等信息时,需要使用此Model +- Generic OnOff Server Model:此Model通过暴露自己的OnOff State,从而实现LED 灯的开关功能 +- Generic OnOff Client Model: 使用此Model可以实现开关功能,控制别的node 的LED灯的开关 +- Fast Provision Server Model: 此Model是为了进行快速配网而实现的自定义Model,通过此Model当节点作为临时provisioner进行配网成功后,需要将生成的Element地址通过此Model进行传给provisioner +- Fast Provision Client Model:此Model和Fast Provision Server Model是配合使用的 \ No newline at end of file diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/CMakeLists.txt b/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/CMakeLists.txt new file mode 100644 index 0000000000..5073db6d0f --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/CMakeLists.txt @@ -0,0 +1,8 @@ +set(COMPONENT_SRCS "cmd_wifi.c" + "iperf.c") + +set(COMPONENT_ADD_INCLUDEDIRS .) + +set(COMPONENT_REQUIRES lwip console) + +register_component() diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/cmd_decl.h b/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/cmd_decl.h new file mode 100644 index 0000000000..78707eabd5 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/cmd_decl.h @@ -0,0 +1,14 @@ +/* Iperf example — declarations of command registration functions. + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#pragma once + +// Register WiFi functions +void register_wifi(void); +void initialise_wifi(void); + diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/cmd_wifi.c b/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/cmd_wifi.c new file mode 100644 index 0000000000..8d258dc923 --- /dev/null +++ b/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/cmd_wifi.c @@ -0,0 +1,477 @@ +/* Iperf Example - wifi commands + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include "esp_log.h" +#include "esp_console.h" +#include "argtable3/argtable3.h" +#include "cmd_decl.h" +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_wifi.h" +#include "tcpip_adapter.h" +#include "esp_event_loop.h" +#include "iperf.h" + +typedef struct { + struct arg_str *ip; + struct arg_lit *server; + struct arg_lit *udp; + struct arg_int *port; + struct arg_int *interval; + struct arg_int *time; + struct arg_lit *abort; + struct arg_end *end; +} wifi_iperf_t; +static wifi_iperf_t iperf_args; + +typedef struct { + struct arg_str *ssid; + struct arg_str *password; + struct arg_end *end; +} wifi_args_t; + +typedef struct { + struct arg_str *ssid; + struct arg_end *end; +} wifi_scan_arg_t; + +static wifi_args_t sta_args; +static wifi_scan_arg_t scan_args; +static wifi_args_t ap_args; +static bool reconnect = true; +static const char *TAG = "iperf"; + +static EventGroupHandle_t wifi_event_group; +const int CONNECTED_BIT = BIT0; +const int DISCONNECTED_BIT = BIT1; + +static void scan_done_handler(void) +{ + uint16_t sta_number = 0; + uint8_t i; + wifi_ap_record_t *ap_list_buffer; + + esp_wifi_scan_get_ap_num(&sta_number); + ap_list_buffer = malloc(sta_number * sizeof(wifi_ap_record_t)); + if (ap_list_buffer == NULL) { + ESP_LOGE(TAG, "Failed to malloc buffer to print scan results"); + return; + } + + if (esp_wifi_scan_get_ap_records(&sta_number, (wifi_ap_record_t *)ap_list_buffer) == ESP_OK) { + for (i = 0; i < sta_number; i++) { + ESP_LOGI(TAG, "[%s][rssi=%d]", ap_list_buffer[i].ssid, ap_list_buffer[i].rssi); + } + } + free(ap_list_buffer); +} + +static esp_err_t event_handler(void *ctx, system_event_t *event) +{ + switch (event->event_id) { + case SYSTEM_EVENT_STA_GOT_IP: + xEventGroupClearBits(wifi_event_group, DISCONNECTED_BIT); + xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); + ESP_LOGI(TAG, "got ip"); + break; + case SYSTEM_EVENT_SCAN_DONE: + scan_done_handler(); + ESP_LOGI(TAG, "sta scan done"); + break; + case SYSTEM_EVENT_STA_CONNECTED: + ESP_LOGI(TAG, "L2 connected"); + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + if (reconnect) { + ESP_LOGI(TAG, "sta disconnect, reconnect..."); + esp_wifi_connect(); + } else { + ESP_LOGI(TAG, "sta disconnect"); + } + xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); + xEventGroupSetBits(wifi_event_group, DISCONNECTED_BIT); + break; + default: + break; + } + return ESP_OK; +} + +void initialise_wifi(void) +{ + esp_log_level_set("wifi", ESP_LOG_WARN); + static bool initialized = false; + + if (initialized) { + return; + } + + 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_ps(WIFI_PS_MIN_MODEM) ); //must call this + ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); + ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); + ESP_ERROR_CHECK( esp_wifi_start() ); + initialized = true; +} + +static bool wifi_cmd_sta_join(const char *ssid, const char *pass) +{ + int bits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, 0, 1, 0); + + wifi_config_t wifi_config = { 0 }; + + strlcpy((char *) wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid)); + if (pass) { + strncpy((char *) wifi_config.sta.password, pass, sizeof(wifi_config.sta.password)); + } + + if (bits & CONNECTED_BIT) { + reconnect = false; + xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); + ESP_ERROR_CHECK( esp_wifi_disconnect() ); + xEventGroupWaitBits(wifi_event_group, DISCONNECTED_BIT, 0, 1, portTICK_RATE_MS); + } + + reconnect = true; + esp_wifi_disconnect(); + //ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); //by snake + ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) ); + ESP_ERROR_CHECK( esp_wifi_connect() ); + + xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, 0, 1, 5000 / portTICK_RATE_MS); + + return true; +} + +static int wifi_cmd_sta(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &sta_args); + + if (nerrors != 0) { + arg_print_errors(stderr, sta_args.end, argv[0]); + return 1; + } + + ESP_LOGI(TAG, "sta connecting to '%s'", sta_args.ssid->sval[0]); + wifi_cmd_sta_join(sta_args.ssid->sval[0], sta_args.password->sval[0]); + return 0; +} + +static bool wifi_cmd_sta_scan(const char *ssid) +{ + wifi_scan_config_t scan_config = { 0 }; + scan_config.ssid = (uint8_t *) ssid; + + ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); + ESP_ERROR_CHECK( esp_wifi_scan_start(&scan_config, false) ); + + return true; +} + +static int wifi_cmd_scan(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &scan_args); + + if (nerrors != 0) { + arg_print_errors(stderr, scan_args.end, argv[0]); + return 1; + } + + ESP_LOGI(TAG, "sta start to scan"); + if ( scan_args.ssid->count == 1 ) { + wifi_cmd_sta_scan(scan_args.ssid->sval[0]); + } else { + wifi_cmd_sta_scan(NULL); + } + return 0; +} + + +static bool wifi_cmd_ap_set(const char *ssid, const char *pass) +{ + wifi_config_t wifi_config = { + .ap = { + .ssid = "", + .ssid_len = 0, + .max_connection = 4, + .password = "", + .authmode = WIFI_AUTH_WPA_WPA2_PSK + }, + }; + + reconnect = false; + strncpy((char *) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid)); + if (pass) { + if (strlen(pass) != 0 && strlen(pass) < 8) { + reconnect = true; + ESP_LOGE(TAG, "password less than 8"); + return false; + } + strncpy((char *) wifi_config.ap.password, pass, sizeof(wifi_config.ap.password)); + } + + if (strlen(pass) == 0) { + wifi_config.ap.authmode = WIFI_AUTH_OPEN; + } + + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); + ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config)); + return true; +} + +static int wifi_cmd_ap(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &ap_args); + + if (nerrors != 0) { + arg_print_errors(stderr, ap_args.end, argv[0]); + return 1; + } + + wifi_cmd_ap_set(ap_args.ssid->sval[0], ap_args.password->sval[0]); + ESP_LOGI(TAG, "AP mode, %s %s", ap_args.ssid->sval[0], ap_args.password->sval[0]); + return 0; +} + +static int wifi_cmd_query(int argc, char **argv) +{ + wifi_config_t cfg; + wifi_mode_t mode; + + esp_wifi_get_mode(&mode); + if (WIFI_MODE_AP == mode) { + esp_wifi_get_config(WIFI_IF_AP, &cfg); + ESP_LOGI(TAG, "AP mode, %s %s", cfg.ap.ssid, cfg.ap.password); + } else if (WIFI_MODE_STA == mode) { + int bits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, 0, 1, 0); + if (bits & CONNECTED_BIT) { + esp_wifi_get_config(WIFI_IF_STA, &cfg); + ESP_LOGI(TAG, "sta mode, connected %s", cfg.ap.ssid); + } else { + ESP_LOGI(TAG, "sta mode, disconnected"); + } + } else { + ESP_LOGI(TAG, "NULL mode"); + return 0; + } + + return 0; +} + +static uint32_t wifi_get_local_ip(void) +{ + int bits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, 0, 1, 0); + tcpip_adapter_if_t ifx = TCPIP_ADAPTER_IF_AP; + tcpip_adapter_ip_info_t ip_info; + wifi_mode_t mode; + + esp_wifi_get_mode(&mode); + if (WIFI_MODE_STA == mode) { + bits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, 0, 1, 0); + if (bits & CONNECTED_BIT) { + ifx = TCPIP_ADAPTER_IF_STA; + } else { + ESP_LOGE(TAG, "sta has no IP"); + return 0; + } + } + + tcpip_adapter_get_ip_info(ifx, &ip_info); + return ip_info.ip.addr; +} + +static int wifi_cmd_iperf(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &iperf_args); + iperf_cfg_t cfg; + + if (nerrors != 0) { + arg_print_errors(stderr, iperf_args.end, argv[0]); + return 0; + } + + memset(&cfg, 0, sizeof(cfg)); + + if ( iperf_args.abort->count != 0) { + iperf_stop(); + return 0; + } + + if ( ((iperf_args.ip->count == 0) && (iperf_args.server->count == 0)) || + ((iperf_args.ip->count != 0) && (iperf_args.server->count != 0)) ) { + ESP_LOGE(TAG, "should specific client/server mode"); + return 0; + } + + if (iperf_args.ip->count == 0) { + cfg.flag |= IPERF_FLAG_SERVER; + } else { + cfg.dip = ipaddr_addr(iperf_args.ip->sval[0]); + cfg.flag |= IPERF_FLAG_CLIENT; + } + + cfg.sip = wifi_get_local_ip(); + if (cfg.sip == 0) { + return 0; + } + + if (iperf_args.udp->count == 0) { + cfg.flag |= IPERF_FLAG_TCP; + } else { + cfg.flag |= IPERF_FLAG_UDP; + } + + if (iperf_args.port->count == 0) { + cfg.sport = IPERF_DEFAULT_PORT; + cfg.dport = IPERF_DEFAULT_PORT; + } else { + if (cfg.flag & IPERF_FLAG_SERVER) { + cfg.sport = iperf_args.port->ival[0]; + cfg.dport = IPERF_DEFAULT_PORT; + } else { + cfg.sport = IPERF_DEFAULT_PORT; + cfg.dport = iperf_args.port->ival[0]; + } + } + + if (iperf_args.interval->count == 0) { + cfg.interval = IPERF_DEFAULT_INTERVAL; + } else { + cfg.interval = iperf_args.interval->ival[0]; + if (cfg.interval <= 0) { + cfg.interval = IPERF_DEFAULT_INTERVAL; + } + } + + if (iperf_args.time->count == 0) { + cfg.time = IPERF_DEFAULT_TIME; + } else { + cfg.time = iperf_args.time->ival[0]; + if (cfg.time <= cfg.interval) { + cfg.time = cfg.interval; + } + } + + ESP_LOGI(TAG, "mode=%s-%s sip=%d.%d.%d.%d:%d, dip=%d.%d.%d.%d:%d, interval=%d, time=%d", + cfg.flag & IPERF_FLAG_TCP ? "tcp" : "udp", + cfg.flag & IPERF_FLAG_SERVER ? "server" : "client", + cfg.sip & 0xFF, (cfg.sip >> 8) & 0xFF, (cfg.sip >> 16) & 0xFF, (cfg.sip >> 24) & 0xFF, cfg.sport, + cfg.dip & 0xFF, (cfg.dip >> 8) & 0xFF, (cfg.dip >> 16) & 0xFF, (cfg.dip >> 24) & 0xFF, cfg.dport, + cfg.interval, cfg.time); + + iperf_start(&cfg); + + return 0; +} + +static int restart(int argc, char **argv) +{ + ESP_LOGI(TAG, "Restarting"); + esp_restart(); +} + +static int heap_size(int argc, char **argv) +{ + uint32_t heap_size = heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT); + ESP_LOGI(TAG, "min heap size: %u", heap_size); + return 0; +} + +void register_wifi() +{ + sta_args.ssid = arg_str1(NULL, NULL, "", "SSID of AP"); + sta_args.password = arg_str0(NULL, NULL, "", "password of AP"); + sta_args.end = arg_end(2); + + const esp_console_cmd_t sta_cmd = { + .command = "sta", + .help = "WiFi is station mode, join specified soft-AP", + .hint = NULL, + .func = &wifi_cmd_sta, + .argtable = &sta_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&sta_cmd) ); + + scan_args.ssid = arg_str0(NULL, NULL, "", "SSID of AP want to be scanned"); + scan_args.end = arg_end(1); + + const esp_console_cmd_t scan_cmd = { + .command = "scan", + .help = "WiFi is station mode, start scan ap", + .hint = NULL, + .func = &wifi_cmd_scan, + .argtable = &scan_args + }; + + ap_args.ssid = arg_str1(NULL, NULL, "", "SSID of AP"); + ap_args.password = arg_str0(NULL, NULL, "", "password of AP"); + ap_args.end = arg_end(2); + + + ESP_ERROR_CHECK( esp_console_cmd_register(&scan_cmd) ); + + const esp_console_cmd_t ap_cmd = { + .command = "ap", + .help = "AP mode, configure ssid and password", + .hint = NULL, + .func = &wifi_cmd_ap, + .argtable = &ap_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&ap_cmd) ); + + const esp_console_cmd_t query_cmd = { + .command = "query", + .help = "query WiFi info", + .hint = NULL, + .func = &wifi_cmd_query, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&query_cmd) ); + + const esp_console_cmd_t restart_cmd = { + .command = "restart", + .help = "Restart the program", + .hint = NULL, + .func = &restart, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&restart_cmd) ); + + iperf_args.ip = arg_str0("c", "client", "", "run in client mode, connecting to "); + iperf_args.server = arg_lit0("s", "server", "run in server mode"); + iperf_args.udp = arg_lit0("u", "udp", "use UDP rather than TCP"); + iperf_args.port = arg_int0("p", "port", "", "server port to listen on/connect to"); + iperf_args.interval = arg_int0("i", "interval", "", "seconds between periodic bandwidth reports"); + iperf_args.time = arg_int0("t", "time", "

*/ +#define P2P_EVENT_SERV_DISC_REQ "P2P-SERV-DISC-REQ " +/* parameters: */ +#define P2P_EVENT_SERV_DISC_RESP "P2P-SERV-DISC-RESP " +#define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED " +#define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT " +#define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED " +#define P2P_EVENT_PERSISTENT_PSK_FAIL "P2P-PERSISTENT-PSK-FAIL id=" + +/* parameters: */ +#define ESS_DISASSOC_IMMINENT "ESS-DISASSOC-IMMINENT " + +#define INTERWORKING_AP "INTERWORKING-AP " +#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH " + +#define GAS_RESPONSE_INFO "GAS-RESPONSE-INFO " + +/* hostapd control interface - fixed message prefixes */ +#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED " +#define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS " +#define WPS_EVENT_REG_SUCCESS "WPS-REG-SUCCESS " +#define WPS_EVENT_AP_SETUP_LOCKED "WPS-AP-SETUP-LOCKED " +#define WPS_EVENT_AP_SETUP_UNLOCKED "WPS-AP-SETUP-UNLOCKED " +#define WPS_EVENT_AP_PIN_ENABLED "WPS-AP-PIN-ENABLED " +#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED " +#define AP_STA_CONNECTED "AP-STA-CONNECTED " +#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED " + +#define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA " +#define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA " + +/* BSS command information masks */ + +#define WPA_BSS_MASK_ALL 0xFFFDFFFF +#define WPA_BSS_MASK_ID BIT(0) +#define WPA_BSS_MASK_BSSID BIT(1) +#define WPA_BSS_MASK_FREQ BIT(2) +#define WPA_BSS_MASK_BEACON_INT BIT(3) +#define WPA_BSS_MASK_CAPABILITIES BIT(4) +#define WPA_BSS_MASK_QUAL BIT(5) +#define WPA_BSS_MASK_NOISE BIT(6) +#define WPA_BSS_MASK_LEVEL BIT(7) +#define WPA_BSS_MASK_TSF BIT(8) +#define WPA_BSS_MASK_AGE BIT(9) +#define WPA_BSS_MASK_IE BIT(10) +#define WPA_BSS_MASK_FLAGS BIT(11) +#define WPA_BSS_MASK_SSID BIT(12) +#define WPA_BSS_MASK_WPS_SCAN BIT(13) +#define WPA_BSS_MASK_P2P_SCAN BIT(14) +#define WPA_BSS_MASK_INTERNETW BIT(15) +#define WPA_BSS_MASK_WIFI_DISPLAY BIT(16) +#define WPA_BSS_MASK_DELIM BIT(17) + + +#ifdef __cplusplus +} +#endif + +#endif /* WPA_CTRL_H */ diff --git a/components/wpa_supplicant/src/crypto/aes-cbc.c b/components/wpa_supplicant/src/crypto/aes-cbc.c index 016207795e..b592279098 100644 --- a/components/wpa_supplicant/src/crypto/aes-cbc.c +++ b/components/wpa_supplicant/src/crypto/aes-cbc.c @@ -13,9 +13,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/aes.h" #include "crypto/aes_wrap.h" diff --git a/components/wpa_supplicant/src/crypto/aes-internal-dec.c b/components/wpa_supplicant/src/crypto/aes-internal-dec.c index 46371c5557..5cea5f745f 100644 --- a/components/wpa_supplicant/src/crypto/aes-internal-dec.c +++ b/components/wpa_supplicant/src/crypto/aes-internal-dec.c @@ -21,9 +21,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/crypto.h" #include "crypto/aes_i.h" diff --git a/components/wpa_supplicant/src/crypto/aes-internal-enc.c b/components/wpa_supplicant/src/crypto/aes-internal-enc.c index 7b1080c450..5b714fedba 100644 --- a/components/wpa_supplicant/src/crypto/aes-internal-enc.c +++ b/components/wpa_supplicant/src/crypto/aes-internal-enc.c @@ -21,8 +21,8 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" -#include "crypto/common.h" +#include "utils/includes.h" +#include "utils/common.h" #include "crypto/crypto.h" #include "crypto/aes_i.h" diff --git a/components/wpa_supplicant/src/crypto/aes-internal.c b/components/wpa_supplicant/src/crypto/aes-internal.c index 9618239f93..537d4034a7 100644 --- a/components/wpa_supplicant/src/crypto/aes-internal.c +++ b/components/wpa_supplicant/src/crypto/aes-internal.c @@ -21,10 +21,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -//#include "wpa/common.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/crypto.h" #include "crypto/aes_i.h" diff --git a/components/wpa_supplicant/src/crypto/aes-unwrap.c b/components/wpa_supplicant/src/crypto/aes-unwrap.c index 4a92f1cd31..2e5a0a1c5f 100644 --- a/components/wpa_supplicant/src/crypto/aes-unwrap.c +++ b/components/wpa_supplicant/src/crypto/aes-unwrap.c @@ -13,9 +13,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/aes.h" #include "crypto/aes_wrap.h" diff --git a/components/wpa_supplicant/src/crypto/aes-wrap.c b/components/wpa_supplicant/src/crypto/aes-wrap.c index 388dd97a82..40eb98c546 100644 --- a/components/wpa_supplicant/src/crypto/aes-wrap.c +++ b/components/wpa_supplicant/src/crypto/aes-wrap.c @@ -7,9 +7,9 @@ * See README for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/aes.h" #include "crypto/aes_wrap.h" diff --git a/components/wpa_supplicant/include/crypto/aes_i.h b/components/wpa_supplicant/src/crypto/aes_i.h similarity index 99% rename from components/wpa_supplicant/include/crypto/aes_i.h rename to components/wpa_supplicant/src/crypto/aes_i.h index 1063422a81..290ac423bd 100644 --- a/components/wpa_supplicant/include/crypto/aes_i.h +++ b/components/wpa_supplicant/src/crypto/aes_i.h @@ -15,7 +15,7 @@ #ifndef AES_I_H #define AES_I_H -#include "aes.h" +#include "crypto/aes.h" /* #define FULL_UNROLL */ #define AES_SMALL_TABLES diff --git a/components/wpa_supplicant/src/crypto/bignum.c b/components/wpa_supplicant/src/crypto/bignum.c index 7b8446c3ba..12a273e5ff 100644 --- a/components/wpa_supplicant/src/crypto/bignum.c +++ b/components/wpa_supplicant/src/crypto/bignum.c @@ -12,10 +12,10 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" -#include "crypto/common.h" -#include "wpa/wpabuf.h" -#include "wpa/wpa_debug.h" +#include "utils/includes.h" +#include "utils/common.h" +#include "utils/wpabuf.h" +#include "utils/wpa_debug.h" #include "bignum.h" #define CONFIG_INTERNAL_LIBTOMMATH diff --git a/components/wpa_supplicant/src/crypto/crypto_internal-cipher.c b/components/wpa_supplicant/src/crypto/crypto_internal-cipher.c index 7d89795797..f197aa35e2 100644 --- a/components/wpa_supplicant/src/crypto/crypto_internal-cipher.c +++ b/components/wpa_supplicant/src/crypto/crypto_internal-cipher.c @@ -6,21 +6,13 @@ * See README for more details. */ -//#include "wpa/includes.h" - -//#include "wpa/common.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/crypto.h" #include "crypto/aes.h" #if defined(CONFIG_DES) || defined(CONFIG_DES3) #include "crypto/des_i.h" #endif -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - - struct crypto_cipher { enum crypto_cipher_alg alg; union { diff --git a/components/wpa_supplicant/src/crypto/crypto_internal-modexp.c b/components/wpa_supplicant/src/crypto/crypto_internal-modexp.c index ea97857005..2bf67df34c 100644 --- a/components/wpa_supplicant/src/crypto/crypto_internal-modexp.c +++ b/components/wpa_supplicant/src/crypto/crypto_internal-modexp.c @@ -12,9 +12,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "bignum.h" #include "crypto/crypto.h" diff --git a/components/wpa_supplicant/src/crypto/crypto_internal-rsa.c b/components/wpa_supplicant/src/crypto/crypto_internal-rsa.c index 19934f063b..de7c8091e9 100644 --- a/components/wpa_supplicant/src/crypto/crypto_internal-rsa.c +++ b/components/wpa_supplicant/src/crypto/crypto_internal-rsa.c @@ -6,16 +6,16 @@ * See README for more details. */ -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/crypto.h" -#include "wpa/includes.h" -#include "wpa/common.h" -#include "wpa/wpa_debug.h" +#include "utils/includes.h" +#include "utils/common.h" +#include "utils/wpa_debug.h" -#include "wpa2/tls/rsa.h" -#include "wpa2/tls/pkcs1.h" -#include "wpa2/tls/pkcs8.h" +#include "tls/rsa.h" +#include "tls/pkcs1.h" +#include "tls/pkcs8.h" /* Dummy structures; these are just typecast to struct crypto_rsa_key */ struct crypto_public_key; diff --git a/components/wpa_supplicant/src/crypto/crypto_internal.c b/components/wpa_supplicant/src/crypto/crypto_internal.c index d8d59dfb9d..5a1d5951ce 100644 --- a/components/wpa_supplicant/src/crypto/crypto_internal.c +++ b/components/wpa_supplicant/src/crypto/crypto_internal.c @@ -6,19 +6,12 @@ * See README for more details. */ -#include "crypto/includes.h" -#include "crypto/common.h" -//#include "wpa/common.h" +#include "utils/includes.h" +#include "utils/common.h" #include "crypto/crypto.h" -//#include "crypto/sha256_i.h" #include "crypto/sha1_i.h" #include "crypto/md5_i.h" -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - - struct crypto_hash { enum crypto_hash_alg alg; union { diff --git a/components/wpa_supplicant/src/crypto/crypto_mbedtls.c b/components/wpa_supplicant/src/crypto/crypto_mbedtls.c index 7bbee6d253..315a6834ff 100644 --- a/components/wpa_supplicant/src/crypto/crypto_mbedtls.c +++ b/components/wpa_supplicant/src/crypto/crypto_mbedtls.c @@ -17,8 +17,8 @@ #include "mbedtls/bignum.h" #endif -#include "crypto/includes.h" -#include "crypto/common.h" +#include "utils/includes.h" +#include "utils/common.h" #include "crypto/crypto.h" #include "mbedtls/ecp.h" diff --git a/components/wpa_supplicant/src/crypto/des-internal.c b/components/wpa_supplicant/src/crypto/des-internal.c index a29c21a1bb..7c66412286 100644 --- a/components/wpa_supplicant/src/crypto/des-internal.c +++ b/components/wpa_supplicant/src/crypto/des-internal.c @@ -9,9 +9,9 @@ */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/crypto.h" //#include "des_i.h" diff --git a/components/wpa_supplicant/src/crypto/des_i.h b/components/wpa_supplicant/src/crypto/des_i.h new file mode 100644 index 0000000000..c9563d2204 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/des_i.h @@ -0,0 +1,25 @@ +/* + * DES and 3DES-EDE ciphers + * Copyright (c) 2006-2009, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef DES_I_H +#define DES_I_H + +struct des3_key_s { + u32 ek[3][32]; + u32 dk[3][32]; +}; + +void des_key_setup(const u8 *key, u32 *ek, u32 *dk); +void des_block_encrypt(const u8 *plain, const u32 *ek, u8 *crypt); +void des_block_decrypt(const u8 *crypt, const u32 *dk, u8 *plain); + +void des3_key_setup(const u8 *key, struct des3_key_s *dkey); +void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt); +void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain); + +#endif /* DES_I_H */ diff --git a/components/wpa_supplicant/src/crypto/dh_group5.c b/components/wpa_supplicant/src/crypto/dh_group5.c index 710f5c7d02..5ae75da2e1 100644 --- a/components/wpa_supplicant/src/crypto/dh_group5.c +++ b/components/wpa_supplicant/src/crypto/dh_group5.c @@ -12,9 +12,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/dh_groups.h" #include "crypto/dh_group5.h" diff --git a/components/wpa_supplicant/src/crypto/dh_groups.c b/components/wpa_supplicant/src/crypto/dh_groups.c index c08f8f29df..9f85846034 100644 --- a/components/wpa_supplicant/src/crypto/dh_groups.c +++ b/components/wpa_supplicant/src/crypto/dh_groups.c @@ -12,18 +12,16 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/crypto.h" #include "crypto/random.h" #include "crypto/dh_groups.h" -#include "wpa/wpabuf.h" -#include "wpa/wpa_debug.h" +#include "utils/wpabuf.h" +#include "utils/wpa_debug.h" #include "esp_wifi_crypto_types.h" -extern wps_crypto_funcs_t wps_crypto_funcs; - #ifdef ALL_DH_GROUPS /* RFC 4306, B.1. Group 1 - 768 Bit MODP @@ -588,16 +586,10 @@ dh_init(const struct dh_group *dh, struct wpabuf **priv) if (pv == NULL) return NULL; - if (wps_crypto_funcs.crypto_mod_exp) { - if (wps_crypto_funcs.crypto_mod_exp(dh->generator, dh->generator_len, - wpabuf_head(*priv), wpabuf_len(*priv), - dh->prime, dh->prime_len, wpabuf_mhead(pv), - &pv_len)) { - wpabuf_free(pv); - wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed"); - return NULL; - } - } else { + if (fast_crypto_mod_exp(dh->generator, dh->generator_len, + wpabuf_head(*priv), wpabuf_len(*priv), + dh->prime, dh->prime_len, wpabuf_mhead(pv), + &pv_len)) { wpabuf_free(pv); wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed"); return NULL; @@ -632,16 +624,10 @@ dh_derive_shared(const struct wpabuf *peer_public, if (shared == NULL) return NULL; - if (wps_crypto_funcs.crypto_mod_exp) { - if (wps_crypto_funcs.crypto_mod_exp(wpabuf_head(peer_public), wpabuf_len(peer_public), - wpabuf_head(own_private), wpabuf_len(own_private), - dh->prime, dh->prime_len, - wpabuf_mhead(shared), &shared_len)) { - wpabuf_free(shared); - wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed"); - return NULL; - } - } else { + if (fast_crypto_mod_exp(wpabuf_head(peer_public), wpabuf_len(peer_public), + wpabuf_head(own_private), wpabuf_len(own_private), + dh->prime, dh->prime_len, + wpabuf_mhead(shared), &shared_len)) { wpabuf_free(shared); wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed"); return NULL; diff --git a/components/wpa_supplicant/src/crypto/md4-internal.c b/components/wpa_supplicant/src/crypto/md4-internal.c index a3ad58129a..cc988492d3 100644 --- a/components/wpa_supplicant/src/crypto/md4-internal.c +++ b/components/wpa_supplicant/src/crypto/md4-internal.c @@ -4,8 +4,8 @@ * This software may be distributed under the terms of BSD license. */ -#include "crypto/includes.h" -#include "crypto/common.h" +#include "utils/includes.h" +#include "utils/common.h" #include "crypto/crypto.h" #define MD4_BLOCK_LENGTH 64 diff --git a/components/wpa_supplicant/src/crypto/md5-internal.c b/components/wpa_supplicant/src/crypto/md5-internal.c index a430e297a5..3a98b36d49 100644 --- a/components/wpa_supplicant/src/crypto/md5-internal.c +++ b/components/wpa_supplicant/src/crypto/md5-internal.c @@ -12,9 +12,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/md5.h" #include "crypto/md5_i.h" #include "crypto/crypto.h" diff --git a/components/wpa_supplicant/src/crypto/md5.c b/components/wpa_supplicant/src/crypto/md5.c index 3125c98311..3a05742961 100644 --- a/components/wpa_supplicant/src/crypto/md5.c +++ b/components/wpa_supplicant/src/crypto/md5.c @@ -12,9 +12,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/md5.h" #include "crypto/crypto.h" diff --git a/components/wpa_supplicant/include/crypto/md5_i.h b/components/wpa_supplicant/src/crypto/md5_i.h similarity index 100% rename from components/wpa_supplicant/include/crypto/md5_i.h rename to components/wpa_supplicant/src/crypto/md5_i.h diff --git a/components/wpa_supplicant/src/crypto/ms_funcs.c b/components/wpa_supplicant/src/crypto/ms_funcs.c index 038f5af950..191aa2bcf2 100644 --- a/components/wpa_supplicant/src/crypto/ms_funcs.c +++ b/components/wpa_supplicant/src/crypto/ms_funcs.c @@ -7,9 +7,9 @@ */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/sha1.h" #include "crypto/ms_funcs.h" #include "crypto/crypto.h" diff --git a/components/wpa_supplicant/src/crypto/rc4.c b/components/wpa_supplicant/src/crypto/rc4.c index 678632297f..aa914dcc72 100644 --- a/components/wpa_supplicant/src/crypto/rc4.c +++ b/components/wpa_supplicant/src/crypto/rc4.c @@ -12,9 +12,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/crypto.h" #define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0) diff --git a/components/wpa_supplicant/src/crypto/sha1-internal.c b/components/wpa_supplicant/src/crypto/sha1-internal.c index a1c255e416..9eb190039e 100644 --- a/components/wpa_supplicant/src/crypto/sha1-internal.c +++ b/components/wpa_supplicant/src/crypto/sha1-internal.c @@ -12,9 +12,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/sha1.h" #include "crypto/sha1_i.h" #include "crypto/md5.h" diff --git a/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c b/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c index 915a23aa78..ec7100142c 100644 --- a/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c +++ b/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c @@ -12,8 +12,8 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" -#include "crypto/common.h" +#include "utils/includes.h" +#include "utils/common.h" #include "crypto/sha1.h" #include "crypto/md5.h" #include "crypto/crypto.h" diff --git a/components/wpa_supplicant/src/crypto/sha1.c b/components/wpa_supplicant/src/crypto/sha1.c index 3d6da417ac..5b228292b2 100644 --- a/components/wpa_supplicant/src/crypto/sha1.c +++ b/components/wpa_supplicant/src/crypto/sha1.c @@ -12,9 +12,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/sha1.h" #include "crypto/crypto.h" diff --git a/components/wpa_supplicant/include/crypto/sha1_i.h b/components/wpa_supplicant/src/crypto/sha1_i.h similarity index 100% rename from components/wpa_supplicant/include/crypto/sha1_i.h rename to components/wpa_supplicant/src/crypto/sha1_i.h diff --git a/components/wpa_supplicant/src/crypto/sha256-internal.c b/components/wpa_supplicant/src/crypto/sha256-internal.c index 9a1fca1c17..376dbd98f2 100644 --- a/components/wpa_supplicant/src/crypto/sha256-internal.c +++ b/components/wpa_supplicant/src/crypto/sha256-internal.c @@ -12,9 +12,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/sha256.h" #include "crypto/crypto.h" diff --git a/components/wpa_supplicant/src/crypto/sha256.c b/components/wpa_supplicant/src/crypto/sha256.c index f62cc11827..49f248c334 100644 --- a/components/wpa_supplicant/src/crypto/sha256.c +++ b/components/wpa_supplicant/src/crypto/sha256.c @@ -12,9 +12,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/sha256.h" #include "crypto/crypto.h" diff --git a/components/wpa_supplicant/src/wpa2/eap_peer/chap.c b/components/wpa_supplicant/src/eap_peer/chap.c similarity index 89% rename from components/wpa_supplicant/src/wpa2/eap_peer/chap.c rename to components/wpa_supplicant/src/eap_peer/chap.c index eb613ca4c1..f48db98193 100644 --- a/components/wpa_supplicant/src/wpa2/eap_peer/chap.c +++ b/components/wpa_supplicant/src/eap_peer/chap.c @@ -4,8 +4,8 @@ */ #ifdef CHAP_MD5 -#include "wpa/includes.h" -#include "wpa/common.h" +#include "utils/includes.h" +#include "utils/common.h" #include "crypto/crypto.h" #include "wpa2/eap_peer/chap.h" diff --git a/components/wpa_supplicant/src/wpa2/eap_peer/eap.c b/components/wpa_supplicant/src/eap_peer/eap.c similarity index 73% rename from components/wpa_supplicant/src/wpa2/eap_peer/eap.c rename to components/wpa_supplicant/src/eap_peer/eap.c index 3ddd294274..114985c9e5 100644 --- a/components/wpa_supplicant/src/wpa2/eap_peer/eap.c +++ b/components/wpa_supplicant/src/eap_peer/eap.c @@ -18,34 +18,34 @@ #include "esp_err.h" -#include "wpa/includes.h" -#include "wpa/common.h" -#include "wpa/wpa_debug.h" -#include "wpa/eapol_common.h" -#include "wpa/ieee802_11_defs.h" -#include "wpa/state_machine.h" -#include "wpa/wpa.h" +#include "utils/includes.h" +#include "utils/common.h" +#include "utils/wpa_debug.h" +#include "common/eapol_common.h" +#include "common/ieee802_11_defs.h" +#include "utils/state_machine.h" +#include "rsn_supp/wpa.h" #include "crypto/crypto.h" -#include "wpa2/utils/ext_password.h" -#include "wpa2/tls/tls.h" -#include "wpa2/eap_peer/eap_i.h" -#include "wpa2/eap_peer/eap_config.h" -#include "wpa2/eap_peer/eap.h" -#include "wpa2/eap_peer/eap_tls.h" +#include "utils/ext_password.h" +#include "tls/tls.h" +#include "eap_peer/eap_i.h" +#include "eap_peer/eap_config.h" +#include "eap_peer/eap.h" +#include "eap_peer/eap_tls.h" +#include "esp_supplicant/esp_wifi_driver.h" #ifdef EAP_PEER_METHOD -#include "wpa2/eap_peer/eap_methods.h" +#include "eap_peer/eap_methods.h" #endif +#include "supplicant_opt.h" + -static bool gl_disable_time_check = true; void eap_peer_config_deinit(struct eap_sm *sm); void eap_peer_blob_deinit(struct eap_sm *sm); void eap_deinit_prev_method(struct eap_sm *sm, const char *txt); -extern bool ieee80211_unregister_wpa2_cb(void); - #ifdef EAP_PEER_METHOD static struct eap_method *eap_methods = NULL; @@ -333,7 +333,7 @@ struct wpabuf * eap_sm_build_nak(struct eap_sm *sm, EapType type, u8 id) #endif int eap_peer_config_init( - struct eap_sm *sm, u8 *private_key_passwd, + struct eap_sm *sm, const u8 *private_key_passwd, int private_key_passwd_len) { if (!sm) @@ -478,8 +478,6 @@ void eap_sm_abort(struct eap_sm *sm) { wpabuf_free(sm->lastRespData); sm->lastRespData = NULL; - //os_free(sm->eapKeyData); - //sm->eapKeyData = NULL; } /** @@ -559,184 +557,3 @@ const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm, return NULL; } -esp_err_t esp_wifi_sta_wpa2_ent_set_cert_key(const unsigned char *client_cert, int client_cert_len, const unsigned char *private_key, int private_key_len, const unsigned char *private_key_passwd, int private_key_passwd_len) -{ - if (client_cert && client_cert_len > 0) { - g_wpa_client_cert = client_cert; - g_wpa_client_cert_len = client_cert_len; - } - if (private_key && private_key_len > 0) { - g_wpa_private_key = private_key; - g_wpa_private_key_len = private_key_len; - } - if (private_key_passwd && private_key_passwd_len > 0) { - g_wpa_private_key_passwd = private_key_passwd; - g_wpa_private_key_passwd_len = private_key_passwd_len; - } - - return ESP_OK; -} - -void esp_wifi_sta_wpa2_ent_clear_cert_key(void) -{ - ieee80211_unregister_wpa2_cb(); - - g_wpa_client_cert = NULL; - g_wpa_client_cert_len = 0; - g_wpa_private_key = NULL; - g_wpa_private_key_len = 0; - g_wpa_private_key_passwd = NULL; - g_wpa_private_key_passwd_len = 0; -} - -esp_err_t esp_wifi_sta_wpa2_ent_set_ca_cert(const unsigned char *ca_cert, int ca_cert_len) -{ - if (ca_cert && ca_cert_len > 0) { - g_wpa_ca_cert = ca_cert; - g_wpa_ca_cert_len = ca_cert_len; - } - - return ESP_OK; -} - -void esp_wifi_sta_wpa2_ent_clear_ca_cert(void) -{ - g_wpa_ca_cert = NULL; - g_wpa_ca_cert_len = 0; -} - -#define ANONYMOUS_ID_LEN_MAX 128 -esp_err_t esp_wifi_sta_wpa2_ent_set_identity(const unsigned char *identity, int len) -{ - if (len <= 0 || len > ANONYMOUS_ID_LEN_MAX) { - return ESP_ERR_INVALID_ARG; - } - - if (g_wpa_anonymous_identity) { - os_free(g_wpa_anonymous_identity); - g_wpa_anonymous_identity = NULL; - } - - g_wpa_anonymous_identity = (u8 *)os_zalloc(len); - if (g_wpa_anonymous_identity == NULL) { - return ESP_ERR_NO_MEM; - } - - os_memcpy(g_wpa_anonymous_identity, identity, len); - g_wpa_anonymous_identity_len = len; - - return ESP_OK; -} - -void esp_wifi_sta_wpa2_ent_clear_identity(void) -{ - if (g_wpa_anonymous_identity) - os_free(g_wpa_anonymous_identity); - - g_wpa_anonymous_identity = NULL; - g_wpa_anonymous_identity_len = 0; -} - -#define USERNAME_LEN_MAX 128 -esp_err_t esp_wifi_sta_wpa2_ent_set_username(const unsigned char *username, int len) -{ - if (len <= 0 || len > USERNAME_LEN_MAX) - return ESP_ERR_INVALID_ARG; - - if (g_wpa_username) { - os_free(g_wpa_username); - g_wpa_username = NULL; - } - - g_wpa_username = (u8 *)os_zalloc(len); - if (g_wpa_username == NULL) - return ESP_ERR_NO_MEM; - - os_memcpy(g_wpa_username, username, len); - g_wpa_username_len = len; - - return ESP_OK; -} - -void esp_wifi_sta_wpa2_ent_clear_username(void) -{ - if (g_wpa_username) - os_free(g_wpa_username); - - g_wpa_username = NULL; - g_wpa_username_len = 0; -} - -esp_err_t esp_wifi_sta_wpa2_ent_set_password(const unsigned char *password, int len) -{ - if (len <= 0) - return ESP_ERR_INVALID_ARG; - - if (g_wpa_password) { - os_free(g_wpa_password); - g_wpa_password = NULL; - } - - g_wpa_password = (u8 *)os_zalloc(len); - if (g_wpa_password == NULL) - return ESP_ERR_NO_MEM; - - os_memcpy(g_wpa_password, password, len); - g_wpa_password_len = len; - - return ESP_OK; -} - -void esp_wifi_sta_wpa2_ent_clear_password(void) -{ - if (g_wpa_password) - os_free(g_wpa_password); - g_wpa_password = NULL; - g_wpa_password_len = 0; -} - -esp_err_t esp_wifi_sta_wpa2_ent_set_new_password(const unsigned char *new_password, int len) -{ - if (len <= 0) - return ESP_ERR_INVALID_ARG; - - if (g_wpa_new_password) { - os_free(g_wpa_new_password); - g_wpa_new_password = NULL; - } - - g_wpa_new_password = (u8 *)os_zalloc(len); - if (g_wpa_new_password == NULL) - return ESP_ERR_NO_MEM; - - os_memcpy(g_wpa_new_password, new_password, len); - g_wpa_password_len = len; - - return ESP_OK; -} - -void esp_wifi_sta_wpa2_ent_clear_new_password(void) -{ - if (g_wpa_new_password) - os_free(g_wpa_new_password); - g_wpa_new_password = NULL; - g_wpa_new_password_len = 0; -} - -esp_err_t esp_wifi_sta_wpa2_ent_set_disable_time_check(bool disable) -{ - gl_disable_time_check = disable; - return ESP_OK; -} - -bool wifi_sta_get_enterprise_disable_time_check(void) -{ - return gl_disable_time_check; -} - -esp_err_t esp_wifi_sta_wpa2_ent_get_disable_time_check(bool *disable) -{ - *disable = wifi_sta_get_enterprise_disable_time_check(); - return ESP_OK; -} - diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap.h b/components/wpa_supplicant/src/eap_peer/eap.h similarity index 92% rename from components/wpa_supplicant/include/wpa2/eap_peer/eap.h rename to components/wpa_supplicant/src/eap_peer/eap.h index 9e1c3efa94..4e84ea7fc7 100644 --- a/components/wpa_supplicant/include/wpa2/eap_peer/eap.h +++ b/components/wpa_supplicant/src/eap_peer/eap.h @@ -9,8 +9,8 @@ #ifndef EAP_H #define EAP_H -#include "wpa/defs.h" -#include "wpa2/eap_peer/eap_defs.h" +#include "common/defs.h" +#include "eap_peer/eap_defs.h" struct eap_sm; @@ -45,7 +45,7 @@ struct wpabuf * eap_sm_build_nak(struct eap_sm *sm, EapType type, u8 id); int eap_peer_blob_init(struct eap_sm *sm); void eap_peer_blob_deinit(struct eap_sm *sm); int eap_peer_config_init( - struct eap_sm *sm, u8 *private_key_passwd, + struct eap_sm *sm, const u8 *private_key_passwd, int private_key_passwd_len); void eap_peer_config_deinit(struct eap_sm *sm); void eap_sm_abort(struct eap_sm *sm); diff --git a/components/wpa_supplicant/src/wpa2/eap_peer/eap_common.c b/components/wpa_supplicant/src/eap_peer/eap_common.c similarity index 97% rename from components/wpa_supplicant/src/wpa2/eap_peer/eap_common.c rename to components/wpa_supplicant/src/eap_peer/eap_common.c index a1748b140f..e6973fac6e 100644 --- a/components/wpa_supplicant/src/wpa2/eap_peer/eap_common.c +++ b/components/wpa_supplicant/src/eap_peer/eap_common.c @@ -6,11 +6,11 @@ * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" -#include "wpa2/eap_peer/eap_defs.h" -#include "wpa2/eap_peer/eap_common.h" +#include "utils/common.h" +#include "eap_peer/eap_defs.h" +#include "eap_peer/eap_common.h" /** * eap_hdr_len_valid - Validate EAP header length field diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_common.h b/components/wpa_supplicant/src/eap_peer/eap_common.h similarity index 96% rename from components/wpa_supplicant/include/wpa2/eap_peer/eap_common.h rename to components/wpa_supplicant/src/eap_peer/eap_common.h index 38c5710058..b7b8afcc50 100644 --- a/components/wpa_supplicant/include/wpa2/eap_peer/eap_common.h +++ b/components/wpa_supplicant/src/eap_peer/eap_common.h @@ -9,7 +9,7 @@ #ifndef EAP_COMMON_H #define EAP_COMMON_H -#include "wpa/wpabuf.h" +#include "utils/wpabuf.h" int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload); const u8 * eap_hdr_validate(int vendor, EapType eap_type, diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_config.h b/components/wpa_supplicant/src/eap_peer/eap_config.h similarity index 99% rename from components/wpa_supplicant/include/wpa2/eap_peer/eap_config.h rename to components/wpa_supplicant/src/eap_peer/eap_config.h index f95dcda3a1..3698e73252 100644 --- a/components/wpa_supplicant/include/wpa2/eap_peer/eap_config.h +++ b/components/wpa_supplicant/src/eap_peer/eap_config.h @@ -141,7 +141,7 @@ struct eap_peer_config { * * If left out, this will be asked through control interface. */ - u8 *private_key_passwd; + const u8 *private_key_passwd; /** * Phase 2 diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_defs.h b/components/wpa_supplicant/src/eap_peer/eap_defs.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/eap_peer/eap_defs.h rename to components/wpa_supplicant/src/eap_peer/eap_defs.h diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_i.h b/components/wpa_supplicant/src/eap_peer/eap_i.h similarity index 97% rename from components/wpa_supplicant/include/wpa2/eap_peer/eap_i.h rename to components/wpa_supplicant/src/eap_peer/eap_i.h index 401d3687a9..a55a8ae388 100644 --- a/components/wpa_supplicant/include/wpa2/eap_peer/eap_i.h +++ b/components/wpa_supplicant/src/eap_peer/eap_i.h @@ -9,7 +9,7 @@ #ifndef EAP_I_H #define EAP_I_H -#include "wpa/wpabuf.h" +#include "utils/wpabuf.h" #include "eap.h" #include "eap_common.h" #include "eap_config.h" @@ -134,7 +134,10 @@ struct eap_sm { const struct eap_method *m; }; -wpa2_crypto_funcs_t wpa2_crypto_funcs; +typedef enum { + WPA2_STATE_ENABLED = 0, + WPA2_STATE_DISABLED, +} wpa2_state_t; const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len); const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len); diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_methods.h b/components/wpa_supplicant/src/eap_peer/eap_methods.h similarity index 96% rename from components/wpa_supplicant/include/wpa2/eap_peer/eap_methods.h rename to components/wpa_supplicant/src/eap_peer/eap_methods.h index 7d518dec2c..80a09677a4 100644 --- a/components/wpa_supplicant/include/wpa2/eap_peer/eap_methods.h +++ b/components/wpa_supplicant/src/eap_peer/eap_methods.h @@ -27,7 +27,6 @@ int eap_peer_method_register(struct eap_method *method); void eap_peer_unregister_methods(void); -//int eap_peer_md5_register(void); int eap_peer_tls_register(void); int eap_peer_peap_register(void); int eap_peer_ttls_register(void); diff --git a/components/wpa_supplicant/src/wpa2/eap_peer/eap_mschapv2.c b/components/wpa_supplicant/src/eap_peer/eap_mschapv2.c similarity index 95% rename from components/wpa_supplicant/src/wpa2/eap_peer/eap_mschapv2.c rename to components/wpa_supplicant/src/eap_peer/eap_mschapv2.c index b28c1eabc7..dff5aeec5c 100644 --- a/components/wpa_supplicant/src/wpa2/eap_peer/eap_mschapv2.c +++ b/components/wpa_supplicant/src/eap_peer/eap_mschapv2.c @@ -9,18 +9,18 @@ #ifdef EAP_MSCHAPv2 -#include "wpa/wpa.h" -#include "wpa/includes.h" -#include "wpa/common.h" +#include "rsn_supp/wpa.h" +#include "utils/includes.h" +#include "utils/common.h" #include "crypto/random.h" #include "crypto/ms_funcs.h" -#include "wpa2/tls/tls.h" -#include "wpa2/eap_peer/eap_i.h" -#include "wpa2/eap_peer/eap_defs.h" -#include "wpa2/eap_peer/eap_tls_common.h" -#include "wpa2/eap_peer/eap_config.h" -#include "wpa2/eap_peer/mschapv2.h" -#include "wpa2/eap_peer/eap_methods.h" +#include "tls/tls.h" +#include "eap_peer/eap_i.h" +#include "eap_peer/eap_defs.h" +#include "eap_peer/eap_tls_common.h" +#include "eap_peer/eap_config.h" +#include "eap_peer/mschapv2.h" +#include "eap_peer/eap_methods.h" #define MSCHAPV2_OP_CHALLENGE 1 #define MSCHAPV2_OP_RESPONSE 2 @@ -296,7 +296,6 @@ eap_mschapv2_failure_txt(struct eap_sm *sm, struct eap_mschapv2_data *data, char *txt) { char *pos; - //char *msg = ""; int retry = 1; struct eap_peer_config *config = eap_get_config(sm); @@ -345,23 +344,15 @@ eap_mschapv2_failure_txt(struct eap_sm *sm, if (pos && os_strncmp(pos, "M=", 2) == 0) { pos += 2; - //msg = pos; } - #if 0 - wpa_printf(MSG_WARNING, "EAP-MSCHAPV2: failure message: '%s' (retry %sallowed, error %d)", - msg, retry == 1? "" : "not ", data->prev_error); - #endif if (data->prev_error == ERROR_PASSWD_EXPIRED && data->passwd_change_version == 3 && config) { if (config->new_password == NULL) { wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Password expired - " "password change reqired\n"); - //eap_sm_request_new_password(sm); } } else if (retry == 1 && config) { if (!config->mschapv2_retry) - //eap_sm_request_identity(sm); - //eap_sm_request_password(sm); config->mschapv2_retry = 1; } else if (config) { config->mschapv2_retry = 0; @@ -493,8 +484,6 @@ eap_mschapv2_failure(struct eap_sm *sm, if (config && config->new_password) return eap_mschapv2_change_password(sm, data, ret, req, id); - //if (config && config->pending_req_new_password) - // return NULL; } else if (retry && data->prev_error == ERROR_AUTHENTICATION_FAILURE) { return NULL; } diff --git a/components/wpa_supplicant/src/wpa2/eap_peer/eap_peap.c b/components/wpa_supplicant/src/eap_peer/eap_peap.c similarity index 98% rename from components/wpa_supplicant/src/wpa2/eap_peer/eap_peap.c rename to components/wpa_supplicant/src/eap_peer/eap_peap.c index 931e2d2bf9..dad73ae2cb 100644 --- a/components/wpa_supplicant/src/wpa2/eap_peer/eap_peap.c +++ b/components/wpa_supplicant/src/eap_peer/eap_peap.c @@ -5,20 +5,18 @@ * This software may be distributed under the terms of the BSD license. * See README for more details. */ +#include "utils/includes.h" + #ifdef EAP_PEAP - -#include "wpa/includes.h" - -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/sha1.h" -#include "wpa2/tls/tls.h" -#include "wpa2/eap_peer/eap_tlv_common.h" -#include "wpa2/eap_peer/eap_peap_common.h" -#include "wpa2/eap_peer/eap_i.h" -#include "wpa2/eap_peer/eap_tls_common.h" -#include "wpa2/eap_peer/eap_config.h" -#include "wpa2/eap_peer/eap_methods.h" -//#include "tncc.h" +#include "tls/tls.h" +#include "eap_peer/eap_tlv_common.h" +#include "eap_peer/eap_peap_common.h" +#include "eap_peer/eap_i.h" +#include "eap_peer/eap_tls_common.h" +#include "eap_peer/eap_config.h" +#include "eap_peer/eap_methods.h" /* Maximum supported PEAP version * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt @@ -629,7 +627,6 @@ static int eap_peap_phase2_request(struct eap_sm *sm, size_t len = be_to_host16(hdr->length); u8 *pos; struct eap_method_ret iret; - //struct eap_peer_config *config = eap_get_config(sm); if (len <= sizeof(struct eap_hdr)) { wpa_printf(MSG_INFO, "EAP-PEAP: too short " @@ -1111,10 +1108,8 @@ eap_peap_process(struct eap_sm *sm, void *priv, * label by default, but allow it to be configured with * phase1 parameter peaplabel=1. */ if (data->peap_version > 1 || data->force_new_label) - //label = "client PEAP encryption"; strcpy(label, "client PEAP encryption"); else - //label = "client EAP encryption"; strcpy(label, "client EAP encryption"); wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in " "key derivation", label); diff --git a/components/wpa_supplicant/src/wpa2/eap_peer/eap_peap_common.c b/components/wpa_supplicant/src/eap_peer/eap_peap_common.c similarity index 94% rename from components/wpa_supplicant/src/wpa2/eap_peer/eap_peap_common.c rename to components/wpa_supplicant/src/eap_peer/eap_peap_common.c index 9b7e7cc4b9..2cafe71975 100644 --- a/components/wpa_supplicant/src/wpa2/eap_peer/eap_peap_common.c +++ b/components/wpa_supplicant/src/eap_peer/eap_peap_common.c @@ -6,13 +6,13 @@ * See README for more details. */ +#include "utils/includes.h" + #ifdef EAP_PEAP -#include "wpa/includes.h" - -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/sha1.h" -#include "wpa2/eap_peer/eap_peap_common.h" +#include "eap_peer/eap_peap_common.h" int peap_prfplus(int version, const u8 *key, size_t key_len, diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_peap_common.h b/components/wpa_supplicant/src/eap_peer/eap_peap_common.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/eap_peer/eap_peap_common.h rename to components/wpa_supplicant/src/eap_peer/eap_peap_common.h diff --git a/components/wpa_supplicant/src/wpa2/eap_peer/eap_tls.c b/components/wpa_supplicant/src/eap_peer/eap_tls.c similarity index 95% rename from components/wpa_supplicant/src/wpa2/eap_peer/eap_tls.c rename to components/wpa_supplicant/src/eap_peer/eap_tls.c index 00dabfe40a..c6d0bd0598 100644 --- a/components/wpa_supplicant/src/wpa2/eap_peer/eap_tls.c +++ b/components/wpa_supplicant/src/eap_peer/eap_tls.c @@ -5,17 +5,16 @@ * This software may be distributed under the terms of the BSD license. * See README for more details. */ +#include "utils/includes.h" + #ifdef EAP_TLS - -#include "wpa/includes.h" - -#include "wpa/common.h" -#include "wpa2/tls/tls.h" -#include "wpa2/eap_peer/eap_i.h" -#include "wpa2/eap_peer/eap_defs.h" -#include "wpa2/eap_peer/eap_tls_common.h" -#include "wpa2/eap_peer/eap_config.h" -#include "wpa2/eap_peer/eap_methods.h" +#include "utils/common.h" +#include "tls/tls.h" +#include "eap_peer/eap_i.h" +#include "eap_peer/eap_defs.h" +#include "eap_peer/eap_tls_common.h" +#include "eap_peer/eap_config.h" +#include "eap_peer/eap_methods.h" struct eap_tls_data { struct eap_ssl_data ssl; diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_tls.h b/components/wpa_supplicant/src/eap_peer/eap_tls.h similarity index 96% rename from components/wpa_supplicant/include/wpa2/eap_peer/eap_tls.h rename to components/wpa_supplicant/src/eap_peer/eap_tls.h index a8a386f22c..ca9f55d4cc 100644 --- a/components/wpa_supplicant/include/wpa2/eap_peer/eap_tls.h +++ b/components/wpa_supplicant/src/eap_peer/eap_tls.h @@ -12,7 +12,7 @@ #include "eap_i.h" #include "eap_common.h" #include "eap.h" -#include "wpa/wpabuf.h" +#include "utils/wpabuf.h" void * eap_tls_init(struct eap_sm *sm); void eap_tls_deinit(struct eap_sm *sm, void *priv); diff --git a/components/wpa_supplicant/src/wpa2/eap_peer/eap_tls_common.c b/components/wpa_supplicant/src/eap_peer/eap_tls_common.c similarity index 99% rename from components/wpa_supplicant/src/wpa2/eap_peer/eap_tls_common.c rename to components/wpa_supplicant/src/eap_peer/eap_tls_common.c index 2c97e6c0f0..213cafa13f 100644 --- a/components/wpa_supplicant/src/wpa2/eap_peer/eap_tls_common.c +++ b/components/wpa_supplicant/src/eap_peer/eap_tls_common.c @@ -6,15 +6,15 @@ * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/sha1.h" -#include "wpa2/tls/tls.h" -#include "wpa2/eap_peer/eap_i.h" -#include "wpa2/eap_peer/eap_tls_common.h" -#include "wpa2/eap_peer/eap_config.h" -#include "wpa2/eap_peer/eap_methods.h" +#include "tls/tls.h" +#include "eap_peer/eap_i.h" +#include "eap_peer/eap_tls_common.h" +#include "eap_peer/eap_config.h" +#include "eap_peer/eap_methods.h" static struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len, u8 code, u8 identifier) diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_tls_common.h b/components/wpa_supplicant/src/eap_peer/eap_tls_common.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/eap_peer/eap_tls_common.h rename to components/wpa_supplicant/src/eap_peer/eap_tls_common.h diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_tlv_common.h b/components/wpa_supplicant/src/eap_peer/eap_tlv_common.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/eap_peer/eap_tlv_common.h rename to components/wpa_supplicant/src/eap_peer/eap_tlv_common.h diff --git a/components/wpa_supplicant/src/wpa2/eap_peer/eap_ttls.c b/components/wpa_supplicant/src/eap_peer/eap_ttls.c similarity index 71% rename from components/wpa_supplicant/src/wpa2/eap_peer/eap_ttls.c rename to components/wpa_supplicant/src/eap_peer/eap_ttls.c index cc0460d337..fb5515913e 100644 --- a/components/wpa_supplicant/src/wpa2/eap_peer/eap_ttls.c +++ b/components/wpa_supplicant/src/eap_peer/eap_ttls.c @@ -6,23 +6,20 @@ * See README for more details. */ +#include "utils/includes.h" + #ifdef EAP_TTLS - -#include "wpa/includes.h" - -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/ms_funcs.h" #include "crypto/sha1.h" -#include "wpa2/tls/tls.h" -//#include "eap_common/chap.h" -#include "wpa2/eap_peer/eap.h" -#include "wpa2/eap_peer/eap_ttls.h" -#include "wpa2/eap_peer/mschapv2.h" -//#include "wpa2/eap_peer/chap.h" -#include "wpa2/eap_peer/eap_i.h" -#include "wpa2/eap_peer/eap_tls_common.h" -#include "wpa2/eap_peer/eap_config.h" -#include "wpa2/eap_peer/eap_methods.h" +#include "tls/tls.h" +#include "eap_peer/eap.h" +#include "eap_peer/eap_ttls.h" +#include "eap_peer/mschapv2.h" +#include "eap_peer/eap_i.h" +#include "eap_peer/eap_tls_common.h" +#include "eap_peer/eap_config.h" +#include "eap_peer/eap_methods.h" #define EAP_TTLS_VERSION 0 @@ -73,7 +70,6 @@ static void * eap_ttls_init(struct eap_sm *sm) { struct eap_ttls_data *data; struct eap_peer_config *config = eap_get_config(sm); - //char *selected; data = (struct eap_ttls_data *)os_zalloc(sizeof(*data)); if (data == NULL) @@ -83,7 +79,6 @@ static void * eap_ttls_init(struct eap_sm *sm) /* selected = "MSCHAPV2"; - //TODO: Now only support EAP-TTLS/MSCHAPV2 if (config && config->phase2) { if (os_strstr(config->phase2, "autheap=")) { selected = "EAP"; @@ -187,32 +182,6 @@ static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code, return pos; } -#if 0 -static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code, - int mandatory) -{ - struct wpabuf *msg; - u8 *avp, *pos; - - msg = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(*resp) + 4); - if (msg == NULL) { - wpabuf_free(*resp); - *resp = NULL; - return -1; - } - - avp = wpabuf_mhead(msg); - pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, wpabuf_len(*resp)); - os_memcpy(pos, wpabuf_head(*resp), wpabuf_len(*resp)); - pos += wpabuf_len(*resp); - AVP_PAD(avp, pos); - wpabuf_free(*resp); - wpabuf_put(msg, pos - avp); - *resp = msg; - return 0; -} -#endif - static int eap_ttls_v0_derive_key(struct eap_sm *sm, struct eap_ttls_data *data) { @@ -244,170 +213,6 @@ static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len); } -#if 0 -static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data, - u8 method) -{ - size_t i; - for (i = 0; i < data->num_phase2_eap_types; i++) { - if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF || - data->phase2_eap_types[i].method != method) - continue; - - data->phase2_eap_type.vendor = - data->phase2_eap_types[i].vendor; - data->phase2_eap_type.method = - data->phase2_eap_types[i].method; - wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " - "Phase 2 EAP vendor %d method %d\n", - data->phase2_eap_type.vendor, - data->phase2_eap_type.method); - break; - } -} - -static int eap_ttls_phase2_eap_process(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct eap_hdr *hdr, size_t len, - struct wpabuf **resp) -{ - struct wpabuf msg; - struct eap_method_ret iret; - - os_memset(&iret, 0, sizeof(iret)); - wpabuf_set(&msg, hdr, len); - *resp = data->phase2_method->process(sm, data->phase2_priv, &iret, - &msg); - if ((iret.methodState == METHOD_DONE || - iret.methodState == METHOD_MAY_CONT) && - (iret.decision == DECISION_UNCOND_SUCC || - iret.decision == DECISION_COND_SUCC || - iret.decision == DECISION_FAIL)) { - ret->methodState = iret.methodState; - ret->decision = iret.decision; - } - - return 0; -} - - -static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct eap_hdr *hdr, size_t len, - u8 method, struct wpabuf **resp) -{ -#ifdef EAP_TNC - if (data->tnc_started && data->phase2_method && - data->phase2_priv && method == EAP_TYPE_TNC && - data->phase2_eap_type.method == EAP_TYPE_TNC) - return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, - resp); - - if (data->ready_for_tnc && !data->tnc_started && - method == EAP_TYPE_TNC) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed " - "EAP method\n"); - data->tnc_started = 1; - } - - if (data->tnc_started) { - if (data->phase2_eap_type.vendor != EAP_VENDOR_IETF || - data->phase2_eap_type.method == EAP_TYPE_TNC) { - wpa_printf(MSG_ERROR, "EAP-TTLS: Unexpected EAP " - "type %d for TNC\n", method); - return -1; - } - - data->phase2_eap_type.vendor = EAP_VENDOR_IETF; - data->phase2_eap_type.method = method; - wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " - "Phase 2 EAP vendor %d method %d (TNC)\n", - data->phase2_eap_type.vendor, - data->phase2_eap_type.method); - - if (data->phase2_type == EAP_TTLS_PHASE2_EAP) - eap_ttls_phase2_eap_deinit(sm, data); - } -#endif /* EAP_TNC */ - - if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF && - data->phase2_eap_type.method == EAP_TYPE_NONE) - eap_ttls_phase2_select_eap_method(data, method); - - if (method != data->phase2_eap_type.method || method == EAP_TYPE_NONE) - { - return -1; - if (eap_peer_tls_phase2_nak(data->phase2_eap_types, - data->num_phase2_eap_types, - hdr, resp)) - return -1; - return 0; - - } - - if (data->phase2_priv == NULL) { - data->phase2_method = eap_peer_get_eap_method( - EAP_VENDOR_IETF, method); - if (data->phase2_method) { - sm->init_phase2 = 1; - data->phase2_priv = data->phase2_method->init(sm); - sm->init_phase2 = 0; - } - } - if (data->phase2_priv == NULL || data->phase2_method == NULL) { - wpa_printf(MSG_ERROR, "EAP-TTLS: failed to initialize " - "Phase 2 EAP method %d\n", method); - return -1; - } - - return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, resp); -} - -#if 0 -static int eap_ttls_phase2_request_eap(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct eap_hdr *hdr, - struct wpabuf **resp) -{ - size_t len = be_to_host16(hdr->length); - u8 *pos; - struct eap_peer_config *config = eap_get_config(sm); - - if (len <= sizeof(struct eap_hdr)) { - wpa_printf(MSG_ERROR, "EAP-TTLS: too short " - "Phase 2 request (len=%lu)\n", (unsigned long) len); - return -1; - } - pos = (u8 *) (hdr + 1); - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP Request: type=%d\n", *pos); - switch (*pos) { - case EAP_TYPE_IDENTITY: - *resp = eap_sm_build_identity_resp(sm, hdr->identifier, 1); - break; - default: - if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len, - *pos, resp) < 0) - return -1; - break; - } - - if (*resp == NULL && - (config->pending_req_identity || config->pending_req_password || - config->pending_req_otp)) { - return 0; - } - - if (*resp == NULL) - return -1; - - return eap_ttls_avp_encapsulate(resp, RADIUS_ATTR_EAP_MESSAGE, 1); -} -#endif -#endif - static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, @@ -507,202 +312,6 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, #endif /* EAP_MSCHAPv2 */ } -#if 0 -//only support MSCHAPv2 -static int eap_ttls_phase2_request_mschap(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct wpabuf **resp) -{ - struct wpabuf *msg; - u8 *buf, *pos, *challenge; - const u8 *identity, *password; - size_t identity_len, password_len; - int pwhash; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request\n"); - - identity = eap_get_config_identity(sm, &identity_len); - password = eap_get_config_password2(sm, &password_len, &pwhash); - if (identity == NULL || password == NULL) - return -1; - - msg = wpabuf_alloc(identity_len + 1000); - if (msg == NULL) { - wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to allocate memory\n"); - return -1; - } - pos = buf = wpabuf_mhead(msg); - - // User-Name - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, - identity, identity_len); - - // MS-CHAP-Challenge - challenge = eap_ttls_implicit_challenge( - sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1); - if (challenge == NULL) { - wpabuf_free(msg); - wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive " - "implicit challenge\n"); - return -1; - } - - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, - RADIUS_VENDOR_ID_MICROSOFT, 1, - challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); - - // MS-CHAP-Response - pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_RESPONSE, - RADIUS_VENDOR_ID_MICROSOFT, 1, - EAP_TTLS_MSCHAP_RESPONSE_LEN); - data->ident = challenge[EAP_TTLS_MSCHAP_CHALLENGE_LEN]; - *pos++ = data->ident; - *pos++ = 1; // Flags: Use NT style passwords - os_memset(pos, 0, 24); // LM-Response - pos += 24; - if (pwhash) { - challenge_response(challenge, password, pos); // NT-Response - } else { - nt_challenge_response(challenge, password, password_len, - pos); // NT-Response - } - pos += 24; - os_free(challenge); - AVP_PAD(buf, pos); - - wpabuf_put(msg, pos - buf); - *resp = msg; - - // EAP-TTLS/MSCHAP does not provide tunneled success - // notification, so assume that Phase2 succeeds. - ret->methodState = METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - - return 0; -} - - -static int eap_ttls_phase2_request_pap(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct wpabuf **resp) -{ - struct wpabuf *msg; - u8 *buf, *pos; - size_t pad; - const u8 *identity, *password; - size_t identity_len, password_len; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request\n"); - - identity = eap_get_config_identity(sm, &identity_len); - password = eap_get_config_password(sm, &password_len); - if (identity == NULL || password == NULL) - return -1; - - msg = wpabuf_alloc(identity_len + password_len + 100); - if (msg == NULL) { - wpa_printf(MSG_ERROR, "EAP-TTLS/PAP: Failed to allocate memory\n"); - return -1; - } - pos = buf = wpabuf_mhead(msg); - - // User-Name - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, - identity, identity_len); - - // User-Password; in RADIUS, this is encrypted, but EAP-TTLS encrypts - // the data, so no separate encryption is used in the AVP itself. - // However, the password is padded to obfuscate its length. - pad = password_len == 0 ? 16 : (16 - (password_len & 15)) & 15; - pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1, - password_len + pad); - os_memcpy(pos, password, password_len); - pos += password_len; - os_memset(pos, 0, pad); - pos += pad; - AVP_PAD(buf, pos); - - wpabuf_put(msg, pos - buf); - *resp = msg; - - // EAP-TTLS/PAP does not provide tunneled success notification, - // so assume that Phase2 succeeds. - ret->methodState = METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - - return 0; -} - - -static int eap_ttls_phase2_request_chap(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct wpabuf **resp) -{ - struct wpabuf *msg; - u8 *buf, *pos, *challenge; - const u8 *identity, *password; - size_t identity_len, password_len; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request\n"); - - identity = eap_get_config_identity(sm, &identity_len); - password = eap_get_config_password(sm, &password_len); - if (identity == NULL || password == NULL) - return -1; - - msg = wpabuf_alloc(identity_len + 1000); - if (msg == NULL) { - wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to allocate memory\n"); - return -1; - } - pos = buf = wpabuf_mhead(msg); - - // User-Name - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, - identity, identity_len); - - // CHAP-Challenge - challenge = eap_ttls_implicit_challenge( - sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1); - if (challenge == NULL) { - wpabuf_free(msg); - wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive " - "implicit challenge\n"); - return -1; - } - - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_CHAP_CHALLENGE, 0, 1, - challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); - - // CHAP-Password - pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_CHAP_PASSWORD, 0, 1, - 1 + EAP_TTLS_CHAP_PASSWORD_LEN); - data->ident = challenge[EAP_TTLS_CHAP_CHALLENGE_LEN]; - *pos++ = data->ident; - - // MD5(Ident + Password + Challenge) - chap_md5(data->ident, password, password_len, challenge, - EAP_TTLS_CHAP_CHALLENGE_LEN, pos); - - pos += EAP_TTLS_CHAP_PASSWORD_LEN; - os_free(challenge); - AVP_PAD(buf, pos); - - wpabuf_put(msg, pos - buf); - *resp = msg; - - // EAP-TTLS/CHAP does not provide tunneled success - // notification, so assume that Phase2 succeeds. - ret->methodState = METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - - return 0; -} -#endif - static int eap_ttls_phase2_request(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, @@ -745,9 +354,7 @@ static int eap_ttls_phase2_request(struct eap_sm *sm, phase2_type == EAP_TTLS_PHASE2_CHAP) { if (eap_get_config_identity(sm, &len) == NULL) { wpa_printf(MSG_ERROR, "EAP-TTLS: Identity not configured\n"); - //eap_sm_request_identity(sm); if (eap_get_config_password(sm, &len) == NULL); - // eap_sm_request_password(sm); printf("[Debug] Return because no identity EAP_TTLS_PHASE2_MSCHAPV2 EAP_TTLS_PHASE2_MSCHAP\n"); return 0; } @@ -755,7 +362,6 @@ static int eap_ttls_phase2_request(struct eap_sm *sm, if (eap_get_config_password(sm, &len) == NULL) { wpa_printf(MSG_ERROR, "EAP-TTLS: Password not configured\n"); printf("[Debug] Return because no password EAP_TTLS_PHASE2_MSCHAPV2 EAP_TTLS_PHASE2_MSCHAP\n"); - //eap_sm_request_password(sm); return 0; } } @@ -992,61 +598,6 @@ static int eap_ttls_encrypt_response(struct eap_sm *sm, return 0; } -#if 0 -static int eap_ttls_process_phase2_eap(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct ttls_parse_avp *parse, - struct wpabuf **resp) -{ - struct eap_hdr *hdr; - size_t len; - - if (parse->eapdata == NULL) { - wpa_printf(MSG_ERROR, "EAP-TTLS: No EAP Message in the " - "packet - dropped\n"); - return -1; - } - - hdr = (struct eap_hdr *) parse->eapdata; - - if (parse->eap_len < sizeof(*hdr)) { - wpa_printf(MSG_ERROR, "EAP-TTLS: Too short Phase 2 EAP " - "frame (len=%lu, expected %lu or more) - dropped\n", - (unsigned long) parse->eap_len, - (unsigned long) sizeof(*hdr)); - return -1; - } - len = be_to_host16(hdr->length); - if (len > parse->eap_len) { - wpa_printf(MSG_ERROR, "EAP-TTLS: Length mismatch in Phase 2 " - "EAP frame (EAP hdr len=%lu, EAP data len in " - "AVP=%lu)\n", - (unsigned long) len, - (unsigned long) parse->eap_len); - return -1; - } - wpa_printf(MSG_DEBUG, "EAP-TTLS: received Phase 2: code=%d " - "identifier=%d length=%lu\n", - hdr->code, hdr->identifier, (unsigned long) len); - switch (hdr->code) { - case EAP_CODE_REQUEST: - if (eap_ttls_phase2_request(sm, data, ret, hdr, resp)) { - wpa_printf(MSG_ERROR, "EAP-TTLS: Phase2 Request " - "processing failed\n"); - return -1; - } - break; - default: - wpa_printf(MSG_ERROR, "EAP-TTLS: Unexpected code=%d in " - "Phase 2 EAP header\n", hdr->code); - return -1; - } - - return 0; -} -#endif - static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, @@ -1149,7 +700,6 @@ static int eap_ttls_process_decrypted(struct eap_sm *sm, struct wpabuf **out_data) { struct wpabuf *resp = NULL; - //struct eap_peer_config *config = eap_get_config(sm); int res; enum phase2_types phase2_type = data->phase2_type; @@ -1242,7 +792,6 @@ static int eap_ttls_implicit_identity_request(struct eap_sm *sm, "processing failed\n"); retval = -1; } else { - //struct eap_peer_config *config = eap_get_config(sm); if (resp == NULL) {/* && (config->pending_req_identity || config->pending_req_password || diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_ttls.h b/components/wpa_supplicant/src/eap_peer/eap_ttls.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/eap_peer/eap_ttls.h rename to components/wpa_supplicant/src/eap_peer/eap_ttls.h diff --git a/components/wpa_supplicant/src/wpa2/eap_peer/mschapv2.c b/components/wpa_supplicant/src/eap_peer/mschapv2.c similarity index 96% rename from components/wpa_supplicant/src/wpa2/eap_peer/mschapv2.c rename to components/wpa_supplicant/src/eap_peer/mschapv2.c index 33351989b5..84859111ec 100644 --- a/components/wpa_supplicant/src/wpa2/eap_peer/mschapv2.c +++ b/components/wpa_supplicant/src/eap_peer/mschapv2.c @@ -4,10 +4,10 @@ #ifdef EAP_MSCHAPv2 -#include "wpa/includes.h" -#include "wpa/common.h" +#include "utils/includes.h" +#include "utils/common.h" #include "crypto/ms_funcs.h" -#include "wpa2/eap_peer/mschapv2.h" +#include "eap_peer/mschapv2.h" const u8 * mschapv2_remove_domain(const u8 *username, size_t *len) { diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/mschapv2.h b/components/wpa_supplicant/src/eap_peer/mschapv2.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/eap_peer/mschapv2.h rename to components/wpa_supplicant/src/eap_peer/mschapv2.h diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_hostap.c b/components/wpa_supplicant/src/esp_supplicant/esp_hostap.c new file mode 100644 index 0000000000..e1eca8b195 --- /dev/null +++ b/components/wpa_supplicant/src/esp_supplicant/esp_hostap.c @@ -0,0 +1,134 @@ +// Copyright 2019 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 "utils/includes.h" + +#include "utils/common.h" +#include "crypto/sha1.h" +#include "common/ieee802_11_defs.h" +#include "common/eapol_common.h" +#include "ap/wpa_auth.h" +#include "ap/ap_config.h" +#include "utils/wpa_debug.h" +#include "ap/hostapd.h" +#include "ap/wpa_auth_i.h" +#include "esp_wifi_driver.h" +#include "esp_wifi_types.h" + +void *hostap_init(void) +{ + struct wifi_ssid *ssid = esp_wifi_ap_get_prof_ap_ssid_internal(); + struct hostapd_data *hapd = NULL; + struct wpa_auth_config *auth_conf; + u8 mac[6]; + + hapd = (struct hostapd_data *)os_zalloc(sizeof(struct hostapd_data)); + + if (hapd == NULL) { + return NULL; + } + + hapd->conf = (struct hostapd_bss_config *)os_zalloc(sizeof(struct hostapd_bss_config)); + + if (hapd->conf == NULL) { + os_free(hapd); + return NULL; + } + + auth_conf = (struct wpa_auth_config *)os_zalloc(sizeof(struct wpa_auth_config)); + + if (auth_conf == NULL) { + os_free(hapd->conf); + os_free(hapd); + hapd = NULL; + return NULL; + } + if (esp_wifi_ap_get_prof_authmode_internal() == WIFI_AUTH_WPA_PSK) { + auth_conf->wpa = WPA_PROTO_WPA; + } + if (esp_wifi_ap_get_prof_authmode_internal() == WIFI_AUTH_WPA2_PSK) { + auth_conf->wpa = WPA_PROTO_RSN; + } + if (esp_wifi_ap_get_prof_authmode_internal() == WIFI_AUTH_WPA_WPA2_PSK) { + auth_conf->wpa = WPA_PROTO_RSN | WPA_PROTO_WPA; + } + + auth_conf->wpa_group = WPA_CIPHER_TKIP; + auth_conf->wpa_pairwise = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP; + auth_conf->rsn_pairwise = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP; + auth_conf->wpa_key_mgmt = WPA_KEY_MGMT_PSK; + auth_conf->eapol_version = EAPOL_VERSION; + + memcpy(hapd->conf->ssid.ssid, ssid->ssid, ssid->len); + hapd->conf->ssid.ssid_len = ssid->len; + hapd->conf->ssid.wpa_passphrase = (char *)os_zalloc(64); + if (hapd->conf->ssid.wpa_passphrase == NULL) { + os_free(auth_conf); + os_free(hapd->conf); + os_free(hapd); + hapd = NULL; + return NULL; + } + memcpy(hapd->conf->ssid.wpa_passphrase, esp_wifi_ap_get_prof_password_internal(), strlen((char *)esp_wifi_ap_get_prof_password_internal())); + + hapd->conf->ap_max_inactivity = 5 * 60; + hostapd_setup_wpa_psk(hapd->conf); + + esp_wifi_get_macaddr_internal(WIFI_IF_AP, mac); + + hapd->wpa_auth = wpa_init(mac, auth_conf, NULL); + esp_wifi_set_appie_internal(WIFI_APPIE_WPA, hapd->wpa_auth->wpa_ie, (uint16_t)hapd->wpa_auth->wpa_ie_len, 0); //michael ML + os_free(auth_conf); + + return (void *)hapd; +} + +bool hostap_deinit(void *data) +{ + struct hostapd_data *hapd = (struct hostapd_data *)data; + + if (hapd == NULL) { + return true; + } + + if (hapd->wpa_auth->wpa_ie != NULL) { + os_free(hapd->wpa_auth->wpa_ie); + } + + if (hapd->wpa_auth->group != NULL) { + os_free(hapd->wpa_auth->group); + } + + if (hapd->wpa_auth != NULL) { + os_free(hapd->wpa_auth); + } + + if (hapd->conf->ssid.wpa_psk != NULL) { + os_free(hapd->conf->ssid.wpa_psk); + } + + if (hapd->conf->ssid.wpa_passphrase != NULL) { + os_free(hapd->conf->ssid.wpa_passphrase); + } + + if (hapd->conf != NULL) { + os_free(hapd->conf); + } + + if (hapd != NULL) { + os_free(hapd); + } + + return true; +} diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_hostap.h b/components/wpa_supplicant/src/esp_supplicant/esp_hostap.h new file mode 100644 index 0000000000..59a183f21e --- /dev/null +++ b/components/wpa_supplicant/src/esp_supplicant/esp_hostap.h @@ -0,0 +1,21 @@ +// Copyright 2019 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. + +#ifndef ESP_HOSTAP_H +#define ESP_HOSTAP_H + +void *hostap_init(void); +bool hostap_deinit(void *data); + +#endif /* ESP_HOSTAP_H */ diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h new file mode 100644 index 0000000000..fdef1d350b --- /dev/null +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h @@ -0,0 +1,220 @@ +// Copyright 2019 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. + +#ifndef _ESP_WIFI_DRIVER_H_ +#define _ESP_WIFI_DRIVER_H_ + +#include "esp_err.h" +#include "esp_wifi.h" + +#if CONFIG_NEWLIB_NANO_FORMAT +#define TASK_STACK_SIZE_ADD 0 +#else +#define TASK_STACK_SIZE_ADD 512 +#endif + +#define WPA2_TASK_STACK_SIZE (6144 + TASK_STACK_SIZE_ADD) +#define WPS_TASK_STACK_SIZE (12288 + TASK_STACK_SIZE_ADD) + +enum { + WIFI_WPA_ALG_NONE = 0, + WIFI_WPA_ALG_WEP40 = 1, + WIFI_WPA_ALG_TKIP = 2, + WIFI_WPA_ALG_CCMP = 3, + WIFI_WPA_ALG_WAPI = 4, + WIFI_WPA_ALG_WEP104 = 5, + WIFI_WPA_ALG_WEP, + WIFI_WPA_ALG_IGTK, + WIFI_WPA_ALG_PMK, + WIFI_WPA_ALG_GCMP +}; + +enum { + WIFI_APPIE_PROBEREQ = 0, + WIFI_APPIE_ASSOC_REQ, + WIFI_APPIE_ASSOC_RESP, + WIFI_APPIE_WPA, + WIFI_APPIE_RSN, + WIFI_APPIE_WPS_PR, + WIFI_APPIE_WPS_AR, + WIFI_APPIE_MESH_QUICK, + WIFI_APPIE_FREQ_ERROR, + WIFI_APPIE_ESP_MANUFACTOR, + WIFI_APPIE_COUNTRY, + WIFI_APPIE_MAX, +}; + +enum { + NONE_AUTH = 0x01, + WPA_AUTH_UNSPEC = 0x02, + WPA_AUTH_PSK = 0x03, + WPA2_AUTH_ENT = 0x04, + WPA2_AUTH_PSK = 0x05, + WPA_AUTH_CCKM = 0x06, + WPA2_AUTH_CCKM = 0x07, + WPA2_AUTH_INVALID = 0x08, +}; + +typedef enum { + WPA2_ENT_EAP_STATE_NOT_START, + WPA2_ENT_EAP_STATE_IN_PROGRESS, + WPA2_ENT_EAP_STATE_SUCCESS, + WPA2_ENT_EAP_STATE_FAIL, +} wpa2_ent_eap_state_t; + +struct wifi_appie { + uint16_t ie_len; + uint8_t ie_data[]; +}; + +struct wifi_ssid { + int len; + uint8_t ssid[32]; +}; + +struct wps_scan_ie { + uint8_t *bssid; + uint8_t chan; + uint16_t capinfo; + uint8_t *ssid; + uint8_t *wpa; + uint8_t *rsn; + uint8_t *wps; +}; + +typedef struct { + int proto; + int pairwise_cipher; + int group_cipher; + int key_mgmt; + int capabilities; + size_t num_pmkid; + const u8 *pmkid; + int mgmt_group_cipher; +} wifi_wpa_ie_t; + +struct wpa_funcs { + void (*wpa_sta_init)(void); + bool (*wpa_sta_deinit)(void); + void (*wpa_sta_connect)(uint8_t *bssid); + int (*wpa_sta_rx_eapol)(u8 *src_addr, u8 *buf, u32 len); + bool (*wpa_sta_in_4way_handshake)(void); + void *(*wpa_ap_init)(void); + bool (*wpa_ap_deinit)(void *data); + bool (*wpa_ap_join)(void **sm, u8 *bssid, u8 *wpa_ie, u8 wpa_ie_len); + bool (*wpa_ap_remove)(void *sm); + uint8_t *(*wpa_ap_get_wpa_ie)(uint8_t *len); + bool (*wpa_ap_rx_eapol)(void *hapd_data, void *sm, u8 *data, size_t data_len); + char *(*wpa_config_parse_string)(const char *value, size_t *len); + int (*wpa_parse_wpa_ie)(const u8 *wpa_ie, size_t wpa_ie_len, wifi_wpa_ie_t *data); + int (*wpa_config_bss)(u8 *bssid); + int (*wpa_michael_mic_failure)(u16 is_unicast); +}; + +struct wpa2_funcs { + int (*wpa2_sm_rx_eapol)(u8 *src_addr, u8 *buf, u32 len, u8 *bssid); + int (*wpa2_start)(void); + u8 (*wpa2_get_state)(void); + int (*wpa2_init)(void); + void (*wpa2_deinit)(void); +}; + +struct wps_funcs { + bool (*wps_parse_scan_result)(struct wps_scan_ie *scan); + int (*wifi_station_wps_start)(void); + int (*wps_sm_rx_eapol)(u8 *src_addr, u8 *buf, u32 len); + int (*wps_start_pending)(void); +}; + +typedef esp_err_t (*wifi_wpa2_fn_t)(void *); +typedef struct { + wifi_wpa2_fn_t fn; + void *param; +} wifi_wpa2_param_t; + +#define IS_WPS_REGISTRAR(type) (((type)>WPS_TYPE_MAX)?(((type)WPS_TYPE_DISABLE)?(((type) + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" + +#include "esp_err.h" + +#include "utils/includes.h" +#include "utils/common.h" +#include "utils/wpa_debug.h" +#include "common/wpa_ctrl.h" +#include "common/eapol_common.h" +#include "common/ieee802_11_defs.h" +#include "utils/state_machine.h" +#include "rsn_supp/wpa.h" + +#include "crypto/crypto.h" + +#include "utils/ext_password.h" +#include "tls/tls.h" +#include "eap_peer/eap_i.h" +#include "eap_peer/eap_config.h" +#include "eap_peer/eap.h" +#include "eap_peer/eap_tls.h" +#ifdef EAP_PEER_METHOD +#include "eap_peer/eap_methods.h" +#endif + +#include "esp_wifi_driver.h" +#include "esp_private/wifi.h" +#include "esp_wpa_err.h" + +#define WPA2_VERSION "v2.0" + +static struct eap_sm *gEapSm = NULL; + +static int eap_peer_sm_init(void); +static void eap_peer_sm_deinit(void); + +static int wpa2_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid); +static int wpa2_start_eapol_internal(void); +int wpa2_post(uint32_t sig, uint32_t par); + +#ifdef USE_WPA2_TASK +static void *s_wpa2_task_hdl = NULL; +static void *s_wpa2_queue = NULL; +static wpa2_state_t s_wpa2_state = WPA2_STATE_DISABLED; +static void *s_wpa2_api_lock = NULL; +static void *s_wifi_wpa2_sync_sem = NULL; +static bool s_disable_time_check = true; + +static void wpa2_api_lock(void) +{ + if (s_wpa2_api_lock == NULL) { + s_wpa2_api_lock = xSemaphoreCreateRecursiveMutex(); + if (!s_wpa2_api_lock) { + wpa_printf(MSG_ERROR, "WPA2: failed to create wpa2 api lock"); + return; + } + } + + xSemaphoreTakeRecursive(s_wpa2_api_lock, portMAX_DELAY); +} + +static void wpa2_api_unlock(void) +{ + if (s_wpa2_api_lock) { + xSemaphoreGiveRecursive(s_wpa2_api_lock); + } +} + +static bool inline wpa2_is_enabled(void) +{ + return (s_wpa2_state == WPA2_STATE_ENABLED); +} + +static bool inline wpa2_is_disabled(void) +{ + return (s_wpa2_state == WPA2_STATE_DISABLED); +} + +static void inline wpa2_set_state(wpa2_state_t state) +{ + s_wpa2_state = state; +} + +static void wpa2_set_eap_state(wpa2_ent_eap_state_t state) +{ + if (!gEapSm) { + return; + } + + gEapSm->finish_state = state; + esp_wifi_set_wpa2_ent_state_internal(state); +} + +static inline void wpa2_task_delete(void *arg) +{ + void *my_task_hdl = xTaskGetCurrentTaskHandle(); + int ret = ESP_OK; + + if (my_task_hdl == s_wpa2_task_hdl) { + wpa_printf(MSG_ERROR, "WPA2: should never call task delete api in wpa2 task context"); + return; + } + + ret = wpa2_post(SIG_WPA2_TASK_DEL, 0); + + if (ESP_OK != ret) { + wpa_printf(MSG_ERROR, "WPA2: failed to post task delete event, ret=%d", ret); + return; + } +} + +#define WPA_ADDR_LEN 6 +struct wpa2_rx_param { + uint8_t *bssid; + u8 sa[WPA_ADDR_LEN]; + u8 *buf; + int len; +}; + +void wpa2_task(void *pvParameters ) +{ + ETSEvent *e; + struct eap_sm *sm = gEapSm; + bool task_del = false; + uint32_t sig = 0; + + if (!sm) { + return; + } + + for (;;) { + if ( pdPASS == xQueueReceive(s_wpa2_queue, &e, portMAX_DELAY) ) { + sig = e->sig; + switch (e->sig) { + case SIG_WPA2_TASK_DEL: + task_del = true; + break; + case SIG_WPA2_START: + sm->wpa2_sig_cnt[e->sig]--; + wpa2_start_eapol_internal(); + break; + case SIG_WPA2_RX: { + struct wpa2_rx_param *param; + + sm->wpa2_sig_cnt[e->sig]--; + param = (struct wpa2_rx_param *)(e->par); + if (param) { + wpa2_sm_rx_eapol_internal(param->sa, param->buf, param->len, param->bssid); + os_free(param->buf); + os_free(param); + } + break; + } + default: + break; + } + os_free(e); + } + + if (task_del) { + break; + } else { + if (s_wifi_wpa2_sync_sem) { + wpa_printf(MSG_DEBUG, "WPA2: wifi->wpa2 api completed sig(%d)", sig); + xSemaphoreGive(s_wifi_wpa2_sync_sem); + } else { + wpa_printf(MSG_ERROR, "WPA2: null wifi->wpa2 sync sem"); + } + } + } + + wpa_printf(MSG_DEBUG, "WPA2: queue deleted"); + vQueueDelete(s_wpa2_queue); + wpa_printf(MSG_DEBUG, "WPA2: task deleted"); + s_wpa2_queue = NULL; + if (s_wifi_wpa2_sync_sem) { + wpa_printf(MSG_DEBUG, "WPA2: wifi->wpa2 api completed sig(%d)", sig); + xSemaphoreGive(s_wifi_wpa2_sync_sem); + } else { + wpa_printf(MSG_ERROR, "WPA2: null wifi->wpa2 sync sem"); + } + + /* At this point, we completed */ + vTaskDelete(NULL); +} + +int wpa2_post(uint32_t sig, uint32_t par) +{ + struct eap_sm *sm = gEapSm; + + if (!sm) { + return ESP_FAIL; + } + + if (sm->wpa2_sig_cnt[sig]) { + return ESP_OK; + } else { + ETSEvent *evt = (ETSEvent *)os_malloc(sizeof(ETSEvent)); + if (evt == NULL) { + wpa_printf(MSG_ERROR, "WPA2: E N M\n"); + return ESP_FAIL; + } + sm->wpa2_sig_cnt[sig]++; + evt->sig = sig; + evt->par = par; + if ( xQueueSend(s_wpa2_queue, &evt, 10 / portTICK_PERIOD_MS ) != pdPASS) { + wpa_printf(MSG_ERROR, "WPA2: Q S E"); + return ESP_FAIL; + } else { + if (s_wifi_wpa2_sync_sem) { + xSemaphoreTake(s_wifi_wpa2_sync_sem, portMAX_DELAY); + wpa_printf(MSG_DEBUG, "WPA2: wpa2 api return, sm->state(%d)", sm->finish_state); + } else { + wpa_printf(MSG_ERROR, "WPA2: null wifi->wpa2 sync sem"); + } + } + } + return ESP_OK; +} + +#endif /* USE_WPA2_TASK */ + +static void wpa2_sendto_wrapper(void *buffer, uint16_t len) +{ + esp_wifi_internal_tx(WIFI_IF_STA, buffer, len); +} + +static inline int wpa2_sm_ether_send(struct eap_sm *sm, const u8 *dest, u16 proto, + const u8 *data, size_t data_len) +{ + void *buffer = (void *)(data - sizeof(struct l2_ethhdr)); + struct l2_ethhdr *eth = NULL; + + if (!buffer) { + wpa_printf(MSG_ERROR, "wpa2: invalid data"); + return ESP_FAIL; + } else { + eth = (struct l2_ethhdr *)buffer; + memcpy(eth->h_dest, dest, ETH_ALEN); + memcpy(eth->h_source, sm->ownaddr, ETH_ALEN); + eth->h_proto = host_to_be16(proto); + wpa2_sendto_wrapper(buffer, sizeof(struct l2_ethhdr) + data_len); + } + + return ESP_OK; +} + +u8 *wpa2_sm_alloc_eapol(struct eap_sm *sm, u8 type, + const void *data, u16 data_len, + size_t *msg_len, void **data_pos) +{ + void *buffer; + struct ieee802_1x_hdr *hdr; + + *msg_len = sizeof(struct ieee802_1x_hdr) + data_len; + /* XXX: reserve l2_ethhdr is enough */ + buffer = os_malloc(*msg_len + sizeof(struct l2_ethhdr)); + + if (buffer == NULL) { + return NULL; + } + + hdr = (struct ieee802_1x_hdr *)((char *)buffer + sizeof(struct l2_ethhdr)); + hdr->version = 0x01; + hdr->type = type; + hdr->length = host_to_be16(data_len); + + if (data) { + memcpy(hdr + 1, data, data_len); + } else { + memset(hdr + 1, 0, data_len); + } + + if (data_pos) { + *data_pos = hdr + 1; + } + + return (u8 *) hdr; +} + + +void wpa2_sm_free_eapol(u8 *buffer) +{ + if (buffer != NULL) { + buffer = buffer - sizeof(struct l2_ethhdr); + } + os_free(buffer); + +} + +int eap_sm_send_eapol(struct eap_sm *sm, struct wpabuf *resp) +{ + size_t outlen; + int ret; + u8 *outbuf = NULL; + + u8 bssid[6]; + ret = esp_wifi_get_assoc_bssid_internal(bssid); + + if (ret != 0) { + wpa_printf(MSG_DEBUG, "bssid is empty \n"); + return WPA_ERR_INVALID_BSSID; + } + + outbuf = wpa2_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAP_PACKET, + wpabuf_head_u8(resp), wpabuf_len(resp), + &outlen, NULL); + if (!outbuf) { + return ESP_ERR_NO_MEM; + } + + ret = wpa2_sm_ether_send(sm, bssid, ETH_P_EAPOL, outbuf, outlen); + wpa2_sm_free_eapol(outbuf); + if (ret) { + return ESP_FAIL; + } + + return ESP_OK; +} + +int eap_sm_process_request(struct eap_sm *sm, struct wpabuf *reqData) +{ + size_t plen; + u32 reqVendor, reqVendorMethod; + u8 type, *pos; + struct eap_hdr *ehdr; + const struct eap_method *m = NULL; + struct wpabuf *resp = NULL; + struct eap_method_ret m_res; + int ret = 0; + + if (reqData == NULL || wpabuf_len(reqData) < sizeof(*ehdr)) { + return ESP_ERR_INVALID_ARG; + } + + ehdr = (struct eap_hdr *)wpabuf_head(reqData); + plen = be_to_host16(ehdr->length); + if (plen > wpabuf_len(reqData)) { + return ESP_FAIL; + } + + if (ehdr->identifier == sm->current_identifier) { + /*Retransmit*/ + resp = sm->lastRespData; + goto send_resp; + } + + sm->current_identifier = ehdr->identifier; + + pos = (u8 *)(ehdr + 1); + type = *pos++; + if (type == EAP_TYPE_IDENTITY) { + resp = (struct wpabuf *)eap_sm_build_identity_resp(sm, ehdr->identifier, 0); + goto send_resp; + } else if (type == EAP_TYPE_NOTIFICATION) { + /*Ignore*/ + goto out; + } else if (type == EAP_TYPE_EXPANDED) { + if (plen < sizeof(*ehdr) + 8) { + return ESP_FAIL; + } + reqVendor = WPA_GET_BE24(pos); + pos += 3; + reqVendorMethod = WPA_GET_BE32(pos); + } else { + reqVendor = EAP_VENDOR_IETF; + reqVendorMethod = type; + } + + if (sm->m && sm->m->process && sm->eap_method_priv && + reqVendor == sm->m->vendor && + reqVendorMethod == sm->m->method) { + resp = sm->m->process(sm, sm->eap_method_priv, + &m_res, reqData); + } else { + m = eap_peer_get_eap_method(reqVendor, reqVendorMethod); + if (m == NULL) { + goto build_nak; + } + if (sm->m) { + eap_deinit_prev_method(sm, "GET_METHOD"); + } + sm->m = m; + sm->eap_method_priv = sm->m->init(sm); + if (sm->eap_method_priv == NULL) { + wpa_printf(MSG_ERROR, "Method private structure allocated failure\n"); + sm->m = NULL; + goto build_nak; + } + + if (sm->m->process) { + resp = sm->m->process(sm, sm->eap_method_priv, &m_res, reqData); + } + } + + if (sm->m->isKeyAvailable && sm->m->getKey && + sm->m->isKeyAvailable(sm, sm->eap_method_priv)) { + if (sm->eapKeyData) { + os_free(sm->eapKeyData); + } + sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv, + &sm->eapKeyDataLen); + } + goto send_resp; + +build_nak: + resp = (struct wpabuf *)eap_sm_build_nak(sm, type, ehdr->identifier); + if (resp == NULL) { + return ESP_FAIL; + } + ret = ESP_FAIL; + +send_resp: + if (resp == NULL) { + wpa_printf(MSG_ERROR, "Response build fail, return."); + return ESP_FAIL; + } + ret = eap_sm_send_eapol(sm, resp); + if (ret == ESP_OK) { + if (resp != sm->lastRespData) { + wpabuf_free(sm->lastRespData); + sm->lastRespData = resp; + } + } else { + wpabuf_free(sm->lastRespData); + sm->lastRespData = NULL; + wpabuf_free(resp); + resp = NULL; + + if (ret == WPA_ERR_INVALID_BSSID) { + ret = WPA2_ENT_EAP_STATE_FAIL; + wpa2_set_eap_state(WPA2_ENT_EAP_STATE_FAIL); + } + } +out: + return ret; +} + +static int wpa2_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid) +{ + struct eap_sm *sm = gEapSm; + + if (!sm) { + return ESP_FAIL; + } +#ifdef USE_WPA2_TASK + { + struct wpa2_rx_param *param = (struct wpa2_rx_param *)os_zalloc(sizeof(struct wpa2_rx_param)); /* free in task */ + + if (!param) { + return ESP_ERR_NO_MEM; + } + + param->buf = (u8 *)os_zalloc(len); /* free in task */ + if (!param->buf) { + os_free(param); + return ESP_ERR_NO_MEM; + } + param->bssid = bssid; + memcpy(param->buf, buf, len); + param->len = len; + memcpy(param->sa, src_addr, WPA_ADDR_LEN); + + return wpa2_post(SIG_WPA2_RX, (uint32_t)param); + } +#else + + return wpa2_sm_rx_eapol_internal(src_addr, buf, len, bssid); +#endif +} + + +static int wpa2_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid) +{ + struct eap_sm *sm = gEapSm; + u32 plen, data_len; + struct ieee802_1x_hdr *hdr; + struct eap_hdr *ehdr; + struct wpabuf *req = NULL; + u8 *tmp; + int ret = ESP_FAIL; + + if (!sm) { + return ESP_FAIL; + } + + if (len < sizeof(*hdr) + sizeof(*ehdr)) { +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: EAPOL frame too short to be a WPA " + "EAPOL-Key (len %lu, expecting at least %lu)", + (unsigned long) len, + (unsigned long) sizeof(*hdr) + sizeof(*ehdr)); +#endif + return ESP_FAIL; + } + + tmp = buf; + + hdr = (struct ieee802_1x_hdr *) tmp; + ehdr = (struct eap_hdr *) (hdr + 1); + plen = be_to_host16(hdr->length); + data_len = plen + sizeof(*hdr); + +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "IEEE 802.1X RX: version=%d type=%d length=%d\n", + hdr->version, hdr->type, plen); +#endif + if (hdr->version < EAPOL_VERSION) { + /* TODO: backwards compatibility */ + } + if (hdr->type != IEEE802_1X_TYPE_EAP_PACKET) { +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA2: EAP frame (type %u) discarded, " + "not a EAP PACKET frame", hdr->type); +#endif + ret = -2; + goto _out; + } + if (plen > len - sizeof(*hdr) || plen < sizeof(*ehdr)) { +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA2: EAPOL frame payload size %lu " + "invalid (frame size %lu)", + (unsigned long) plen, (unsigned long) len); +#endif + ret = -2; + goto _out; + } + + wpa_hexdump(MSG_MSGDUMP, "WPA2: RX EAPOL-EAP PACKET", tmp, len); + + if (data_len < len) { +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: ignoring %lu bytes after the IEEE " + "802.1X data\n", (unsigned long) len - data_len); +#endif + } + +#ifdef EAP_PEER_METHOD + switch (ehdr->code) { + case EAP_CODE_REQUEST: + req = wpabuf_alloc_copy((u8 *)ehdr, len - sizeof(*hdr)); + ret = eap_sm_process_request(sm, req); + break; + case EAP_CODE_RESPONSE: + /*Ignore*/ + break; + case EAP_CODE_SUCCESS: + if (sm->eapKeyData) { + wpa_set_pmk(sm->eapKeyData); + os_free(sm->eapKeyData); + sm->eapKeyData = NULL; + wpa_printf(MSG_INFO, ">>>>>wpa2 FINISH\n"); + ret = WPA2_ENT_EAP_STATE_SUCCESS; + wpa2_set_eap_state(WPA2_ENT_EAP_STATE_SUCCESS); + } else { + wpa_printf(MSG_INFO, ">>>>>wpa2 FAILED, receive EAP_SUCCESS but pmk is empty, potential attack!\n"); + ret = WPA2_ENT_EAP_STATE_FAIL; + wpa2_set_eap_state(WPA2_ENT_EAP_STATE_FAIL); + } + break; + case EAP_CODE_FAILURE: + wpa_printf(MSG_INFO, ">>>>>wpa2 FAILED\n"); + ret = WPA2_ENT_EAP_STATE_FAIL; + wpa2_set_eap_state(WPA2_ENT_EAP_STATE_FAIL); + break; + } +_out: + wpabuf_free(req); +#endif + return ret; +} + +static int wpa2_start_eapol(void) +{ +#ifdef USE_WPA2_TASK + return wpa2_post(SIG_WPA2_START, 0); +#else + return wpa2_start_eapol_internal(); +#endif +} + +static int wpa2_start_eapol_internal(void) +{ + struct eap_sm *sm = gEapSm; + int ret = 0; + u8 bssid[6]; + u8 *buf; + size_t len; + + if (!sm) { + return ESP_FAIL; + } + + ret = esp_wifi_get_assoc_bssid_internal(bssid); + if (ret != 0) { + wpa_printf(MSG_ERROR, "bssid is empty!"); + return WPA_ERR_INVALID_BSSID; + } + + buf = wpa2_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_START, (u8 *)"", 0, &len, NULL); + if (!buf) { + return ESP_FAIL; + } + + wpa2_set_eap_state(WPA2_ENT_EAP_STATE_IN_PROGRESS); + wpa2_sm_ether_send(sm, bssid, ETH_P_EAPOL, buf, len); + wpa2_sm_free_eapol(buf); + return ESP_OK; +} + +/** + * eap_peer_sm_init - Allocate and initialize EAP peer state machine + * @eapol_ctx: Context data to be used with eapol_cb calls + * @eapol_cb: Pointer to EAPOL callback functions + * @msg_ctx: Context data for wpa_msg() calls + * @conf: EAP configuration + * Returns: Pointer to the allocated EAP state machine or %NULL on failure + * + * This function allocates and initializes an EAP state machine. In addition, + * this initializes TLS library for the new EAP state machine. eapol_cb pointer + * will be in use until eap_peer_sm_deinit() is used to deinitialize this EAP + * state machine. Consequently, the caller must make sure that this data + * structure remains alive while the EAP state machine is active. + */ +static int eap_peer_sm_init(void) +{ + int ret = 0; + struct eap_sm *sm; + + if (gEapSm) { + wpa_printf(MSG_ERROR, "WPA2: wpa2 sm not null, deinit it"); + eap_peer_sm_deinit(); + } + + sm = (struct eap_sm *)os_zalloc(sizeof(*sm)); + if (sm == NULL) { + return ESP_ERR_NO_MEM; + } + + wpa2_set_eap_state(WPA2_ENT_EAP_STATE_NOT_START); + sm->current_identifier = 0xff; + esp_wifi_get_macaddr_internal(WIFI_IF_STA, sm->ownaddr); + ret = eap_peer_blob_init(sm); + if (ret) { + wpa_printf(MSG_ERROR, "eap_peer_blob_init failed\n"); + os_free(sm); + return ESP_FAIL; + } + + ret = eap_peer_config_init(sm, g_wpa_private_key_passwd, g_wpa_private_key_passwd_len); + if (ret) { + wpa_printf(MSG_ERROR, "eap_peer_config_init failed\n"); + eap_peer_blob_deinit(sm); + os_free(sm); + return ESP_FAIL; + } + + sm->ssl_ctx = tls_init(); + if (sm->ssl_ctx == NULL) { + wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS " + "context."); + eap_peer_blob_deinit(sm); + eap_peer_config_deinit(sm); + os_free(sm); + return ESP_FAIL; + } + + + gEapSm = sm; +#ifdef USE_WPA2_TASK + s_wpa2_queue = xQueueCreate(SIG_WPA2_MAX, sizeof( void * ) ); + xTaskCreate(wpa2_task, "wpa2T", WPA2_TASK_STACK_SIZE, NULL, 2, s_wpa2_task_hdl); + s_wifi_wpa2_sync_sem = xSemaphoreCreateCounting(1, 0); + if (!s_wifi_wpa2_sync_sem) { + wpa_printf(MSG_ERROR, "WPA2: failed create wifi wpa2 task sync sem"); + return ESP_FAIL; + } + + wpa_printf(MSG_INFO, "wpa2_task prio:%d, stack:%d\n", 2, WPA2_TASK_STACK_SIZE); + +#endif + return ESP_OK; +} + +/** + * eap_peer_sm_deinit - Deinitialize and free an EAP peer state machine + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * + * This function deinitializes EAP state machine and frees all allocated + * resources. + */ +static void eap_peer_sm_deinit(void) +{ + struct eap_sm *sm = gEapSm; + + if (sm == NULL) { + return; + } + + eap_peer_config_deinit(sm); + eap_peer_blob_deinit(sm); + eap_deinit_prev_method(sm, "EAP deinit"); + eap_sm_abort(sm); + tls_deinit(sm->ssl_ctx); +#ifdef USE_WPA2_TASK + wpa2_task_delete(0); +#endif + if (s_wifi_wpa2_sync_sem) { + vSemaphoreDelete(s_wifi_wpa2_sync_sem); + } + s_wifi_wpa2_sync_sem = NULL; + + os_free(sm); + gEapSm = NULL; +} + +uint8_t wpa2_machine_start = 0; + +esp_err_t esp_wifi_sta_wpa2_ent_enable_fn(void *arg) +{ + struct wpa2_funcs *wpa2_cb; + + wpa_printf(MSG_INFO, "WPA2 ENTERPRISE VERSION: [%s] enable\n", + WPA2_VERSION); + + wpa2_cb = (struct wpa2_funcs *)os_zalloc(sizeof(struct wpa2_funcs)); + if (wpa2_cb == NULL) { + wpa_printf(MSG_ERROR, "WPA2: no mem for wpa2 cb\n"); + return ESP_ERR_NO_MEM; + } + + wpa2_cb->wpa2_sm_rx_eapol = wpa2_sm_rx_eapol; + wpa2_cb->wpa2_start = wpa2_start_eapol; + wpa2_cb->wpa2_init = eap_peer_sm_init; + wpa2_cb->wpa2_deinit = eap_peer_sm_deinit; + + esp_wifi_register_wpa2_cb_internal(wpa2_cb); + + wpa_printf(MSG_DEBUG, "WPA2 ENTERPRISE CRYPTO INIT.\r\n"); + +#ifdef EAP_PEER_METHOD + if (eap_peer_register_methods()) { + wpa_printf(MSG_ERROR, "Register EAP Peer methods Failure\n"); + } +#endif + wpa2_machine_start = 1; + return ESP_OK; +} + +esp_err_t esp_wifi_sta_wpa2_ent_enable(void) +{ + wifi_wpa2_param_t param; + esp_err_t ret; + + wpa2_api_lock(); + + if (wpa2_is_enabled()) { + wpa_printf(MSG_INFO, "WPA2: already enabled"); + wpa2_api_unlock(); + return ESP_OK; + } + + param.fn = (wifi_wpa2_fn_t)esp_wifi_sta_wpa2_ent_enable_fn; + param.param = NULL; + + ret = esp_wifi_sta_wpa2_ent_enable_internal(¶m); + + if (ESP_OK == ret) { + wpa2_set_state(WPA2_STATE_ENABLED); + } else { + wpa_printf(MSG_ERROR, "failed to enable wpa2 ret=%d", ret); + } + + wpa2_api_unlock(); + + return ret; +} + +esp_err_t esp_wifi_sta_wpa2_ent_disable_fn(void *param) +{ + wpa_printf(MSG_INFO, "WPA2 ENTERPRISE VERSION: [%s] disable\n", WPA2_VERSION); + esp_wifi_unregister_wpa2_cb_internal(); + + if (gEapSm) { + eap_peer_sm_deinit(); + } + +#ifdef USE_WPA2_TASK +#endif + +#ifdef EAP_PEER_METHOD + eap_peer_unregister_methods(); +#endif + + wpa2_machine_start = 0; + return ESP_OK; +} + +esp_err_t esp_wifi_sta_wpa2_ent_disable(void) +{ + wifi_wpa2_param_t param; + esp_err_t ret; + + wpa2_api_lock(); + + if (wpa2_is_disabled()) { + wpa_printf(MSG_INFO, "WPA2: already disabled"); + wpa2_api_unlock(); + return ESP_OK; + } + + param.fn = (wifi_wpa2_fn_t)esp_wifi_sta_wpa2_ent_disable_fn; + param.param = 0; + ret = esp_wifi_sta_wpa2_ent_disable_internal(¶m); + + if (ESP_OK == ret) { + wpa2_set_state(WPA2_STATE_DISABLED); + } else { + wpa_printf(MSG_ERROR, "failed to disable wpa2 ret=%d", ret); + } + + wpa2_api_unlock(); + + return ret; +} + +esp_err_t esp_wifi_sta_wpa2_ent_set_cert_key(const unsigned char *client_cert, int client_cert_len, const unsigned char *private_key, int private_key_len, const unsigned char *private_key_passwd, int private_key_passwd_len) +{ + if (client_cert && client_cert_len > 0) { + g_wpa_client_cert = client_cert; + g_wpa_client_cert_len = client_cert_len; + } + if (private_key && private_key_len > 0) { + g_wpa_private_key = private_key; + g_wpa_private_key_len = private_key_len; + } + if (private_key_passwd && private_key_passwd_len > 0) { + g_wpa_private_key_passwd = private_key_passwd; + g_wpa_private_key_passwd_len = private_key_passwd_len; + } + + return ESP_OK; +} + +void esp_wifi_sta_wpa2_ent_clear_cert_key(void) +{ + esp_wifi_unregister_wpa2_cb_internal(); + + g_wpa_client_cert = NULL; + g_wpa_client_cert_len = 0; + g_wpa_private_key = NULL; + g_wpa_private_key_len = 0; + g_wpa_private_key_passwd = NULL; + g_wpa_private_key_passwd_len = 0; +} + +esp_err_t esp_wifi_sta_wpa2_ent_set_ca_cert(const unsigned char *ca_cert, int ca_cert_len) +{ + if (ca_cert && ca_cert_len > 0) { + g_wpa_ca_cert = ca_cert; + g_wpa_ca_cert_len = ca_cert_len; + } + + return ESP_OK; +} + +void esp_wifi_sta_wpa2_ent_clear_ca_cert(void) +{ + g_wpa_ca_cert = NULL; + g_wpa_ca_cert_len = 0; +} + +#define ANONYMOUS_ID_LEN_MAX 128 +esp_err_t esp_wifi_sta_wpa2_ent_set_identity(const unsigned char *identity, int len) +{ + if (len <= 0 || len > ANONYMOUS_ID_LEN_MAX) { + return ESP_ERR_INVALID_ARG; + } + + if (g_wpa_anonymous_identity) { + os_free(g_wpa_anonymous_identity); + g_wpa_anonymous_identity = NULL; + } + + g_wpa_anonymous_identity = (u8 *)os_zalloc(len); + if (g_wpa_anonymous_identity == NULL) { + return ESP_ERR_NO_MEM; + } + + os_memcpy(g_wpa_anonymous_identity, identity, len); + g_wpa_anonymous_identity_len = len; + + return ESP_OK; +} + +void esp_wifi_sta_wpa2_ent_clear_identity(void) +{ + if (g_wpa_anonymous_identity) { + os_free(g_wpa_anonymous_identity); + } + + g_wpa_anonymous_identity = NULL; + g_wpa_anonymous_identity_len = 0; +} + +#define USERNAME_LEN_MAX 128 +esp_err_t esp_wifi_sta_wpa2_ent_set_username(const unsigned char *username, int len) +{ + if (len <= 0 || len > USERNAME_LEN_MAX) { + return ESP_ERR_INVALID_ARG; + } + + if (g_wpa_username) { + os_free(g_wpa_username); + g_wpa_username = NULL; + } + + g_wpa_username = (u8 *)os_zalloc(len); + if (g_wpa_username == NULL) { + return ESP_ERR_NO_MEM; + } + + os_memcpy(g_wpa_username, username, len); + g_wpa_username_len = len; + + return ESP_OK; +} + +void esp_wifi_sta_wpa2_ent_clear_username(void) +{ + if (g_wpa_username) { + os_free(g_wpa_username); + } + + g_wpa_username = NULL; + g_wpa_username_len = 0; +} + +esp_err_t esp_wifi_sta_wpa2_ent_set_password(const unsigned char *password, int len) +{ + if (len <= 0) { + return ESP_ERR_INVALID_ARG; + } + + if (g_wpa_password) { + os_free(g_wpa_password); + g_wpa_password = NULL; + } + + g_wpa_password = (u8 *)os_zalloc(len); + if (g_wpa_password == NULL) { + return ESP_ERR_NO_MEM; + } + + os_memcpy(g_wpa_password, password, len); + g_wpa_password_len = len; + + return ESP_OK; +} + +void esp_wifi_sta_wpa2_ent_clear_password(void) +{ + if (g_wpa_password) { + os_free(g_wpa_password); + } + g_wpa_password = NULL; + g_wpa_password_len = 0; +} + +esp_err_t esp_wifi_sta_wpa2_ent_set_new_password(const unsigned char *new_password, int len) +{ + if (len <= 0) { + return ESP_ERR_INVALID_ARG; + } + + if (g_wpa_new_password) { + os_free(g_wpa_new_password); + g_wpa_new_password = NULL; + } + + g_wpa_new_password = (u8 *)os_zalloc(len); + if (g_wpa_new_password == NULL) { + return ESP_ERR_NO_MEM; + } + + os_memcpy(g_wpa_new_password, new_password, len); + g_wpa_password_len = len; + + return ESP_OK; +} + +void esp_wifi_sta_wpa2_ent_clear_new_password(void) +{ + if (g_wpa_new_password) { + os_free(g_wpa_new_password); + } + g_wpa_new_password = NULL; + g_wpa_new_password_len = 0; +} + +esp_err_t esp_wifi_sta_wpa2_ent_set_disable_time_check(bool disable) +{ + s_disable_time_check = disable; + return ESP_OK; +} + +bool wifi_sta_get_enterprise_disable_time_check(void) +{ + return s_disable_time_check; +} + +esp_err_t esp_wifi_sta_wpa2_ent_get_disable_time_check(bool *disable) +{ + *disable = wifi_sta_get_enterprise_disable_time_check(); + return ESP_OK; +} + diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_err.h b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_err.h new file mode 100644 index 0000000000..9704c7f3ac --- /dev/null +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_err.h @@ -0,0 +1,19 @@ +// Copyright 2019 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. + +/* + * This file define the ESP supplicant internal error code + */ + +#define WPA_ERR_INVALID_BSSID -2 diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c new file mode 100644 index 0000000000..d565cd1cba --- /dev/null +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c @@ -0,0 +1,239 @@ +// Copyright 2019 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 "utils/includes.h" +#include "utils/common.h" +#include "rsn_supp/wpa.h" +#include "rsn_supp/wpa_i.h" +#include "common/eapol_common.h" +#include "common/ieee802_11_defs.h" +#include "rsn_supp/wpa_ie.h" +#include "ap/wpa_auth.h" +#include "ap/wpa_auth_i.h" +#include "ap/ap_config.h" +#include "ap/hostapd.h" +#include "esp_wpas_glue.h" +#include "esp_hostap.h" + +#include "crypto/crypto.h" +#include "crypto/sha1.h" +#include "crypto/aes_wrap.h" +#include "crypto/wepkey.h" + +#include "esp_wifi_driver.h" +#include "esp_private/wifi.h" + +void wpa_install_key(enum wpa_alg alg, u8 *addr, int key_idx, int set_tx, + u8 *seq, size_t seq_len, u8 *key, size_t key_len, int key_entry_valid) +{ + esp_wifi_set_sta_key_internal(alg, addr, key_idx, set_tx, seq, seq_len, key, key_len, key_entry_valid); +} + +int wpa_get_key(uint8_t *ifx, int *alg, u8 *addr, int *key_idx, + u8 *key, size_t key_len, int key_entry_valid) +{ + return esp_wifi_get_sta_key_internal(ifx, alg, addr, key_idx, key, key_len, key_entry_valid); +} + +/** + * eapol_sm_notify_eap_success - Notification of external EAP success trigger + * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() + * @success: %TRUE = set success, %FALSE = clear success + * + * Notify the EAPOL state machine that external event has forced EAP state to + * success (success = %TRUE). This can be cleared by setting success = %FALSE. + * + * This function is called to update EAP state when WPA-PSK key handshake has + * been completed successfully since WPA-PSK does not use EAP state machine. + */ + +/* fix buf for tx for now */ +#define WPA_TX_MSG_BUFF_MAXLEN 200 + +void wpa_sendto_wrapper(void *buffer, u16 len) +{ + esp_wifi_internal_tx(0, buffer, len); +} + +void wpa_deauthenticate(u8 reason_code) +{ + esp_wifi_deauthenticate_internal(reason_code); +} + +void wpa_config_profile() +{ + if (esp_wifi_sta_prof_is_wpa_internal()) { + wpa_set_profile(WPA_PROTO_WPA, esp_wifi_sta_get_prof_authmode_internal()); + } else if (esp_wifi_sta_prof_is_wpa2_internal()) { + wpa_set_profile(WPA_PROTO_RSN, esp_wifi_sta_get_prof_authmode_internal()); + } else { + WPA_ASSERT(0); + } +} + +int wpa_config_bss(uint8_t *bssid) +{ + struct wifi_ssid *ssid = esp_wifi_sta_get_prof_ssid_internal(); + u8 mac[6]; + + esp_wifi_get_macaddr_internal(0, mac); + wpa_set_bss((char *)mac, (char *)bssid, esp_wifi_sta_get_pairwise_cipher_internal(), esp_wifi_sta_get_group_cipher_internal(), + (char *)esp_wifi_sta_get_prof_password_internal(), ssid->ssid, ssid->len); + return ESP_OK; +} + +void wpa_config_assoc_ie(u8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len) +{ + if (proto == BIT(0)) { + esp_wifi_set_appie_internal(WIFI_APPIE_WPA, assoc_buf, assoc_wpa_ie_len, 1); + } else { + esp_wifi_set_appie_internal(WIFI_APPIE_RSN, assoc_buf, assoc_wpa_ie_len, 1); + } +} + +void wpa_neg_complete() +{ + esp_wifi_auth_done_internal(); +} + +void wpa_attach(void) +{ +#ifndef IOT_SIP_MODE + wpa_register(NULL, wpa_sendto_wrapper, + wpa_config_assoc_ie, wpa_install_key, wpa_get_key, wpa_deauthenticate, wpa_neg_complete); +#else + u8 *payload = (u8 *)os_malloc(WPA_TX_MSG_BUFF_MAXLEN); + wpa_register(payload, wpa_sendto_wrapper, + wpa_config_assoc_ie, wpa_install_key, wpa_get_key, wpa_deauthenticate, wpa_neg_complete); +#endif + + esp_wifi_register_tx_cb_internal(eapol_txcb, WIFI_TXCB_EAPOL_ID); +} + +uint8_t *wpa_ap_get_wpa_ie(uint8_t *ie_len) +{ + struct hostapd_data *hapd = (struct hostapd_data *)esp_wifi_get_hostap_private_internal(); + + if (!hapd || !hapd->wpa_auth || !hapd->wpa_auth->wpa_ie) { + return NULL; + } + + *ie_len = hapd->wpa_auth->wpa_ie_len; + return hapd->wpa_auth->wpa_ie; +} + +bool wpa_ap_rx_eapol(void *hapd_data, void *sm_data, u8 *data, size_t data_len) +{ + struct hostapd_data *hapd = (struct hostapd_data *)hapd_data; + struct wpa_state_machine *sm = (struct wpa_state_machine *)sm_data; + + if (!hapd || !sm) { + return false; + } + + wpa_receive(hapd->wpa_auth, sm, data, data_len); + + return true; +} + +bool wpa_deattach(void) +{ + return true; +} + +void wpa_sta_connect(uint8_t *bssid) +{ + wpa_config_profile(); + wpa_config_bss(bssid); +} + +int cipher_type_map(int wpa_cipher) +{ + switch (wpa_cipher) { + case WPA_CIPHER_NONE: + return WIFI_CIPHER_TYPE_NONE; + + case WPA_CIPHER_WEP40: + return WIFI_CIPHER_TYPE_WEP40; + + case WPA_CIPHER_WEP104: + return WIFI_CIPHER_TYPE_WEP104; + + case WPA_CIPHER_TKIP: + return WIFI_CIPHER_TYPE_TKIP; + + case WPA_CIPHER_CCMP: + return WIFI_CIPHER_TYPE_CCMP; + + case WPA_CIPHER_CCMP|WPA_CIPHER_TKIP: + return WIFI_CIPHER_TYPE_TKIP_CCMP; + + default: + return WIFI_CIPHER_TYPE_UNKNOWN; + } +} + +int wpa_parse_wpa_ie_wrapper(const u8 *wpa_ie, size_t wpa_ie_len, wifi_wpa_ie_t *data) +{ + struct wpa_ie_data ie; + int ret = 0; + + ret = wpa_parse_wpa_ie(wpa_ie, wpa_ie_len, &ie); + data->proto = ie.proto; + data->pairwise_cipher = cipher_type_map(ie.pairwise_cipher); + data->group_cipher = cipher_type_map(ie.group_cipher); + data->key_mgmt = ie.key_mgmt; + data->capabilities = ie.capabilities; + data->pmkid = ie.pmkid; + data->mgmt_group_cipher = cipher_type_map(ie.mgmt_group_cipher); + + return ret; +} + +int esp_supplicant_init(void) +{ + struct wpa_funcs *wpa_cb; + + wpa_cb = (struct wpa_funcs *)os_malloc(sizeof(struct wpa_funcs)); + if (!wpa_cb) { + return ESP_ERR_NO_MEM; + } + + wpa_cb->wpa_sta_init = wpa_attach; + wpa_cb->wpa_sta_deinit = wpa_deattach; + wpa_cb->wpa_sta_rx_eapol = wpa_sm_rx_eapol; + wpa_cb->wpa_sta_connect = wpa_sta_connect; + wpa_cb->wpa_sta_in_4way_handshake = wpa_sta_in_4way_handshake; + + wpa_cb->wpa_ap_join = wpa_ap_join; + wpa_cb->wpa_ap_remove = wpa_ap_remove; + wpa_cb->wpa_ap_get_wpa_ie = wpa_ap_get_wpa_ie; + wpa_cb->wpa_ap_rx_eapol = wpa_ap_rx_eapol; + wpa_cb->wpa_ap_init = hostap_init; + wpa_cb->wpa_ap_deinit = hostap_deinit; + + wpa_cb->wpa_config_parse_string = wpa_config_parse_string; + wpa_cb->wpa_parse_wpa_ie = wpa_parse_wpa_ie_wrapper; + wpa_cb->wpa_config_bss = wpa_config_bss; + wpa_cb->wpa_michael_mic_failure = wpa_michael_mic_failure; + + esp_wifi_register_wpa_cb_internal(wpa_cb); + + return ESP_OK; +} + +bool wpa_hook_deinit(void) +{ + return esp_wifi_unregister_wpa_cb_internal(); +} diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpas_glue.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpas_glue.c new file mode 100644 index 0000000000..89c901f802 --- /dev/null +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpas_glue.c @@ -0,0 +1,114 @@ +// Copyright 2019 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. + +#ifdef ESP_SUPPLICANT + +#include "utils/includes.h" +#include "utils/common.h" +#include "common/eapol_common.h" +#include "rsn_supp/wpa.h" + +u8 *wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type, + const void *data, u16 data_len, + size_t *msg_len, void **data_pos) +{ + void *buffer; + struct ieee802_1x_hdr *hdr; + + *msg_len = sizeof(struct ieee802_1x_hdr) + data_len; + + buffer = os_malloc(*msg_len + sizeof(struct l2_ethhdr)); + + if (buffer == NULL) { + return NULL; + } + + /* XXX: reserve l2_ethhdr is enough */ + hdr = (struct ieee802_1x_hdr *)((char *)buffer + sizeof(struct l2_ethhdr)); + + hdr->version = sm->eapol_version; + hdr->type = type; + hdr->length = host_to_be16(data_len); + + if (data) { + memcpy(hdr + 1, data, data_len); + } else { + memset(hdr + 1, 0, data_len); + } + + if (data_pos) { + *data_pos = hdr + 1; + } + + return (u8 *) hdr; +} + +void wpa_sm_free_eapol(u8 *buffer) +{ + buffer = buffer - sizeof(struct l2_ethhdr); + os_free(buffer); +} + +void wpa_sm_deauthenticate(struct wpa_sm *sm, u8 reason_code) +{ + + /*only need send deauth frame when associated*/ + if (WPA_SM_STATE(sm) >= WPA_ASSOCIATED) { + sm->wpa_deauthenticate(reason_code); + } +} + +/** + * mlme_setprotection - MLME-SETPROTECTION.request primitive + * @priv: Private driver interface data + * @addr: Address of the station for which to set protection (may be + * %NULL for group keys) + * @protect_type: MLME_SETPROTECTION_PROTECT_TYPE_* + * @key_type: MLME_SETPROTECTION_KEY_TYPE_* + * Returns: 0 on success, -1 on failure + * + * This is an optional function that can be used to set the driver to + * require protection for Tx and/or Rx frames. This uses the layer + * interface defined in IEEE 802.11i-2004 clause 10.3.22.1 + * (MLME-SETPROTECTION.request). Many drivers do not use explicit + * set protection operation; instead, they set protection implicitly + * based on configured keys. + */ +int wpa_sm_mlme_setprotection(struct wpa_sm *sm, const u8 *addr, + int protect_type, int key_type) +{ + return 0; +} + +/* + *use above two functions to get wpa_ie and rsn_ie, then don't need wpa_sm_get_beacon_ie function +*/ +int wpa_sm_get_beacon_ie(struct wpa_sm *sm) +{ + return 0; +} + +/** + * wpa_supplicant_disassociate - Disassociate the current connection + * @wpa_s: Pointer to wpa_supplicant data + * @reason_code: IEEE 802.11 reason code for the disassociate frame + * + * This function is used to request %wpa_supplicant to disassociate with the + * current AP. + */ +void wpa_sm_disassociate(struct wpa_sm *sm, int reason_code) +{ + /*check if need clear internal state and data value*/ +} +#endif diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpas_glue.h b/components/wpa_supplicant/src/esp_supplicant/esp_wpas_glue.h new file mode 100644 index 0000000000..4d867962e7 --- /dev/null +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpas_glue.h @@ -0,0 +1,33 @@ +// Copyright 2019 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. + +#ifndef WPAS_GLUE_H +#define WPAS_GLUE_H + +u8 *wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type, + const void *data, u16 data_len, + size_t *msg_len, void **data_pos); + +int wpa_sm_mlme_setprotection(struct wpa_sm *sm, const u8 *addr, + int protect_type, int key_type); + +void wpa_sm_deauthenticate(struct wpa_sm *sm, u8 reason_code); + +void wpa_sm_disassociate(struct wpa_sm *sm, int reason_code); + +int wpa_sm_get_beacon_ie(struct wpa_sm *sm); + +void wpa_sm_free_eapol(u8 *buffer); + +#endif /* WPAS_GLUE_H */ diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wps.c b/components/wpa_supplicant/src/esp_supplicant/esp_wps.c new file mode 100644 index 0000000000..03ed6e8587 --- /dev/null +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wps.c @@ -0,0 +1,2138 @@ +// Copyright 2019 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 + +#include "utils/includes.h" +#include "rsn_supp/wpa.h" +#include "utils/common.h" +#include "common/eapol_common.h" +#include "utils/wpa_debug.h" +#include "common/ieee802_11_defs.h" +#include "crypto/dh_group5.h" +#include "wps/wps_i.h" +#include "wps/wps_dev_attr.h" +#include "eap_peer/eap_defs.h" +#include "eap_peer/eap_common.h" +#include "esp_wifi_driver.h" +#include "esp_event.h" +#include "esp_wifi.h" +#include "esp_err.h" +#include "esp_private/wifi.h" + +#define API_MUTEX_TAKE() do {\ + if (!s_wps_api_lock) {\ + s_wps_api_lock = xSemaphoreCreateRecursiveMutex();\ + if (!s_wps_api_lock) {\ + wpa_printf(MSG_ERROR, "wps api lock create failed");\ + return ESP_ERR_NO_MEM;\ + }\ + }\ + xSemaphoreTakeRecursive(s_wps_api_lock, portMAX_DELAY);\ +} while(0) + +#define API_MUTEX_GIVE() xSemaphoreGiveRecursive(s_wps_api_lock) +#define DATA_MUTEX_TAKE() xSemaphoreTakeRecursive(s_wps_data_lock, portMAX_DELAY) +#define DATA_MUTEX_GIVE() xSemaphoreGiveRecursive(s_wps_data_lock) + +#define WPS_ADDR_LEN 6 +#ifdef USE_WPS_TASK +struct wps_rx_param { + u8 sa[WPS_ADDR_LEN]; + u8 *buf; + int len; +}; + +typedef struct { + void *arg; + int ret; /* return value */ +} wps_ioctl_param_t; + +static void *s_wps_task_hdl = NULL; +static void *s_wps_queue = NULL; +static void *s_wps_api_lock = NULL; /* Used in WPS public API only, never be freed */ +static void *s_wps_api_sem = NULL; /* Sync semaphore used between WPS publi API caller task and WPS task */ +static void *s_wps_data_lock = NULL; +static void *s_wps_task_create_sem = NULL; +static bool s_wps_enabled = false; +static uint8_t s_wps_sig_cnt[SIG_WPS_NUM] = {0}; + +#endif + +void wifi_wps_scan_done(void *arg, STATUS status); +void wifi_wps_scan(void); +int wifi_station_wps_start(void); +int wps_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len); +void wifi_wps_start_internal(void); +int wifi_wps_enable_internal(const esp_wps_config_t *config); +int wifi_wps_disable_internal(void); +void wifi_station_wps_timeout_internal(void); +void wifi_station_wps_msg_timeout_internal(void); +void wifi_station_wps_success_internal(void); +void wifi_wps_scan_internal(void); +void wifi_station_wps_eapol_start_handle_internal(void); + +struct wps_sm *gWpsSm = NULL; +static wps_factory_information_t *s_factory_info = NULL; + +#ifdef CONFIG_WPS_TESTING +int wps_version_number = 0x20; +int wps_testing_dummy_cred = 0; +#endif /* CONFIG_WPS_TESTING */ + +int wps_get_type(void) +{ + return esp_wifi_get_wps_type_internal(); +} + +int wps_set_type(uint32_t type) +{ + return esp_wifi_set_wps_type_internal(type); +} + +int wps_get_status(void) +{ + return esp_wifi_get_wps_status_internal(); +} + +int wps_set_status(uint32_t status) +{ + return esp_wifi_set_wps_status_internal(status); +} + +#ifdef USE_WPS_TASK +void wps_task(void *pvParameters ) +{ + ETSEvent *e; + wps_ioctl_param_t *param; + bool del_task = false; + + xSemaphoreGive(s_wps_task_create_sem); + + wpa_printf(MSG_DEBUG, "wps_Task enter"); + for (;;) { + if ( pdPASS == xQueueReceive(s_wps_queue, &e, portMAX_DELAY) ) { + + if ( (e->sig >= SIG_WPS_ENABLE) && (e->sig < SIG_WPS_NUM) ) { + DATA_MUTEX_TAKE(); + if (s_wps_sig_cnt[e->sig]) { + s_wps_sig_cnt[e->sig]--; + } else { + wpa_printf(MSG_ERROR, "wpsT: invalid sig cnt, sig=%d cnt=%d", e->sig, s_wps_sig_cnt[e->sig]); + } + DATA_MUTEX_GIVE(); + } + + wpa_printf(MSG_DEBUG, "wpsT: rx sig=%d", e->sig); + + switch (e->sig) { + case SIG_WPS_ENABLE: + case SIG_WPS_DISABLE: + case SIG_WPS_START: + param = (wps_ioctl_param_t *)e->par; + if (!param) { + wpa_printf(MSG_ERROR, "wpsT: invalid param sig=%d", e->sig); + xSemaphoreGive(s_wps_api_sem); + break; + } + + if (e->sig == SIG_WPS_ENABLE) { + param->ret = wifi_wps_enable_internal((esp_wps_config_t *)(param->arg)); + } else if (e->sig == SIG_WPS_DISABLE) { + param->ret = wifi_wps_disable_internal(); + del_task = true; + s_wps_task_hdl = NULL; + } else { + param->ret = wifi_station_wps_start(); + } + + xSemaphoreGive(s_wps_api_sem); + break; + + case SIG_WPS_RX: { + struct wps_rx_param *param; + + param = (struct wps_rx_param *)(e->par); + if (param) { + wps_sm_rx_eapol_internal(param->sa, param->buf, param->len); + os_free(param->buf); + os_free(param); + } + break; + } + + case SIG_WPS_TIMER_TIMEOUT: + wifi_station_wps_timeout_internal(); + break; + + case SIG_WPS_TIMER_MSG_TIMEOUT: + wifi_station_wps_msg_timeout_internal(); + break; + + case SIG_WPS_TIMER_SUCCESS_CB: + wifi_station_wps_success_internal(); + break; + + case SIG_WPS_TIMER_SCAN: + wifi_wps_scan_internal(); + break; + + case SIG_WPS_TIMER_EAPOL_START: + wifi_station_wps_eapol_start_handle_internal(); + break; + + default: + wpa_printf(MSG_ERROR, "wpsT: invalid sig=%d", e->sig); + break; + } + os_free(e); + + if (del_task) { + wpa_printf(MSG_DEBUG, "wpsT: delete task"); + break; + } + } + } + vTaskDelete(NULL); +} + +/* wps_post() is thread-safe + * + */ +int wps_post(uint32_t sig, uint32_t par) +{ + wpa_printf(MSG_DEBUG, "wps post: sig=%d cnt=%d", sig, s_wps_sig_cnt[sig]); + + DATA_MUTEX_TAKE(); + if (s_wps_sig_cnt[sig]) { + wpa_printf(MSG_DEBUG, "wps post: sig=%d processing", sig); + DATA_MUTEX_GIVE(); + return ESP_OK; + } else { + ETSEvent *evt = (ETSEvent *)os_malloc(sizeof(ETSEvent)); + + if (evt == NULL) { + wpa_printf(MSG_ERROR, "WPS: E N M"); + DATA_MUTEX_GIVE(); + return ESP_FAIL; + } + + s_wps_sig_cnt[sig]++; + evt->sig = sig; + evt->par = par; + DATA_MUTEX_GIVE(); + + if ( xQueueSend(s_wps_queue, &evt, 10 / portTICK_PERIOD_MS) != pdPASS) { + wpa_printf(MSG_ERROR, "WPS: Q S E"); + DATA_MUTEX_TAKE(); + s_wps_sig_cnt[sig]--; + DATA_MUTEX_GIVE(); + return ESP_FAIL; + } + } + return ESP_OK; +} +#endif + +static void wps_sendto_wrapper(void *buffer, uint16_t len) +{ + esp_wifi_internal_tx(WIFI_IF_STA, buffer, len); +} + +/* +* wps_sm_ether_send - Send Ethernet frame +* @wpa_s: Pointer to wpa_supplicant data +* @dest: Destination MAC address +* @proto: Ethertype in host byte order +* @buf: Frame payload starting from IEEE 802.1X header +* @len: Frame payload length +* Returns: >=0 on success, <0 on failure +*/ +static inline int wps_sm_ether_send(struct wps_sm *sm, const u8 *dest, u16 proto, + const u8 *data, size_t data_len) +{ + void *buffer = (void *)(data - sizeof(struct l2_ethhdr)); + struct l2_ethhdr *eth = (struct l2_ethhdr *)buffer; + + memcpy(eth->h_dest, dest, ETH_ALEN); + memcpy(eth->h_source, sm->ownaddr, ETH_ALEN); + eth->h_proto = host_to_be16(proto); + + wps_sendto_wrapper(buffer, sizeof(struct l2_ethhdr) + data_len); + + return ESP_OK; +} + + +u8 *wps_sm_alloc_eapol(struct wps_sm *sm, u8 type, + const void *data, u16 data_len, + size_t *msg_len, void **data_pos) +{ + void *buffer; + struct ieee802_1x_hdr *hdr; + + *msg_len = sizeof(struct ieee802_1x_hdr) + data_len; + /* XXX: reserve l2_ethhdr is enough */ + buffer = os_malloc(*msg_len + sizeof(struct l2_ethhdr)); + + if (buffer == NULL) { + return NULL; + } + hdr = (struct ieee802_1x_hdr *)((char *)buffer + sizeof(struct l2_ethhdr)); + + hdr->version = sm->eapol_version; + hdr->type = type; + hdr->length = host_to_be16(data_len); + + if (data) { + memcpy(hdr + 1, data, data_len); + } else { + memset(hdr + 1, 0, data_len); + } + + if (data_pos) { + *data_pos = hdr + 1; + } + + return (u8 *) hdr; +} + + +void wps_sm_free_eapol(u8 *buffer) +{ + buffer = buffer - sizeof(struct l2_ethhdr); + os_free(buffer); + +} + + +/** + * wps_init - Initialize WPS Registration protocol data + * @cfg: WPS configuration + * Returns: Pointer to allocated data or %NULL on failure + * + * This function is used to initialize WPS data for a registration protocol + * instance (i.e., each run of registration protocol as a Registrar of + * Enrollee. The caller is responsible for freeing this data after the + * registration run has been completed by calling wps_deinit(). + */ +struct wps_data *wps_init(void) +{ + struct wps_sm *sm = gWpsSm; + struct wps_data *data = (struct wps_data *)os_zalloc(sizeof(*data)); + const char *all_zero_pin = "00000000"; + + if (data == NULL) { + return NULL; + } + + data->wps = sm->wps_ctx; + + if (IS_WPS_REGISTRAR(wps_get_type())) { + data->registrar = 1; + } else { + data->registrar = 0; + } + + data->registrar = 0; /* currently, we force to support enrollee only */ + + if (data->registrar) { + memcpy(data->uuid_r, sm->uuid, WPS_UUID_LEN); + } else { + memcpy(data->mac_addr_e, sm->dev->mac_addr, ETH_ALEN); + memcpy(data->uuid_e, sm->uuid, WPS_UUID_LEN); + } + + if (wps_get_type() == WPS_TYPE_PIN) { + u32 spin = 0; + data->dev_pw_id = DEV_PW_DEFAULT; + data->dev_password_len = 8; + data->dev_password = (u8 *) os_zalloc(data->dev_password_len + 1); + if (data->dev_password == NULL) { + os_free(data); + return NULL; + } + + spin = wps_generate_pin(); + sprintf((char *)data->dev_password, "%08d", spin); + wpa_hexdump_key(MSG_DEBUG, "WPS: AP PIN dev_password", + data->dev_password, data->dev_password_len); + do { + char tmpp[9]; + os_bzero(tmpp, 9); + memcpy(tmpp, data->dev_password, 8); + wpa_printf(MSG_DEBUG, "WPS PIN [%s]", tmpp); + system_event_t evt; + evt.event_id = SYSTEM_EVENT_STA_WPS_ER_PIN; + memcpy(evt.event_info.sta_er_pin.pin_code, data->dev_password, 8); + esp_wifi_send_event_internal(&evt); + } while (0); + } else if (wps_get_type() == WPS_TYPE_PBC) { + data->pbc = 1; + /* Use special PIN '00000000' for PBC */ + data->dev_pw_id = DEV_PW_PUSHBUTTON; + if (data->dev_password) { + os_free(data->dev_password); + } + data->dev_password = (u8 *) os_zalloc(9); + if (data->dev_password == NULL) { + os_free(data); + return NULL; + } else { + strncpy((char *)data->dev_password, all_zero_pin, 9); + } + data->dev_password_len = 8; + } + +#ifdef CONFIG_WPS_NFC + if (cfg->wps->ap && !cfg->registrar && cfg->wps->ap_nfc_dev_pw_id) { + data->dev_pw_id = cfg->wps->ap_nfc_dev_pw_id; + os_free(data->dev_password); + data->dev_password = + os_malloc(wpabuf_len(cfg->wps->ap_nfc_dev_pw)); + if (data->dev_password == NULL) { + os_free(data); + return NULL; + } + memcpy(data->dev_password, + wpabuf_head(cfg->wps->ap_nfc_dev_pw), + wpabuf_len(cfg->wps->ap_nfc_dev_pw)); + data->dev_password_len = wpabuf_len(cfg->wps->ap_nfc_dev_pw); + } +#endif /* CONFIG_WPS_NFC */ + data->wps->config_methods = WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_DISPLAY; +#ifdef CONFIG_WPS2 + data->wps->config_methods |= (WPS_CONFIG_VIRT_PUSHBUTTON | WPS_CONFIG_PHY_DISPLAY); +#endif + + data->state = data->registrar ? RECV_M1 : SEND_M1; + + return data; +} + + +/** + * wps_deinit - Deinitialize WPS Registration protocol data + * @data: WPS Registration protocol data from wps_init() + */ +void wps_deinit(void) +{ + struct wps_data *data = gWpsSm->wps; + +#ifdef CONFIG_WPS_NFC + if (data->registrar && data->nfc_pw_token) + wps_registrar_remove_nfc_pw_token(data->wps->registrar, + data->nfc_pw_token); +#endif /* CONFIG_WPS_NFC */ + + if (data->wps_pin_revealed) { + wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and " + "negotiation failed"); + } else if (data->registrar) + wpa_printf(MSG_DEBUG, "WPS: register information revealed and " + "negotiation failed"); + wpabuf_free(data->dh_privkey); + +#ifdef DESP32_WORKAROUND + /* + * due to the public key calculated when wps start, it will not calculate anymore even when we build M1 message, also calculate the key need take a long time + * which would cause WPS fail, so we clean the key after WPS finished . + */ + data->dh_privkey = NULL; +#endif //DESP32_WORKAROUND + + wpabuf_free(data->dh_pubkey_e); + wpabuf_free(data->dh_pubkey_r); + wpabuf_free(data->last_msg); + os_free(data->dev_password); + dh5_free(data->dh_ctx); + wps_dev_deinit(&data->peer_dev); +#ifdef CONFIG_WPS_NFC + os_free(data->nfc_pw_token); +#endif + os_free(data); +} + +static void +wps_build_ic_appie_wps_pr(void) +{ + struct wpabuf *extra_ie = NULL; + struct wpabuf *wps_ie; + struct wps_sm *sm = gWpsSm; + + wpa_printf(MSG_DEBUG, "wps build: wps pr"); + + if (wps_get_type() == WPS_TYPE_PBC) { + wps_ie = (struct wpabuf *)wps_build_probe_req_ie(DEV_PW_PUSHBUTTON, + sm->dev, + sm->uuid, WPS_REQ_ENROLLEE, + 0, NULL); + } else { + wps_ie = (struct wpabuf *)wps_build_probe_req_ie(DEV_PW_DEFAULT, + sm->dev, + sm->uuid, WPS_REQ_ENROLLEE, + 0, NULL); + } + + if (wps_ie) { + if (wpabuf_resize(&extra_ie, wpabuf_len(wps_ie)) == 0) { + wpabuf_put_buf(extra_ie, wps_ie); + } else { + wpabuf_free(wps_ie); + return; + } + wpabuf_free(wps_ie); + } + + esp_wifi_set_appie_internal(WIFI_APPIE_WPS_PR, (uint8_t *)wpabuf_head(extra_ie), extra_ie->used, 0); + wpabuf_free(extra_ie); +} + +static void +wps_build_ic_appie_wps_ar(void) +{ + struct wpabuf *buf = (struct wpabuf *)wps_build_assoc_req_ie(WPS_REQ_ENROLLEE); + + wpa_printf(MSG_DEBUG, "wps build: wps ar"); + + if (buf) { + esp_wifi_set_appie_internal(WIFI_APPIE_WPS_AR, (uint8_t *)wpabuf_head(buf), buf->used, 0); + wpabuf_free(buf); + } +} + +static bool +wps_parse_scan_result(struct wps_scan_ie *scan) +{ + struct wps_sm *sm = gWpsSm; + wifi_mode_t op_mode = 0; +#ifdef WPS_DEBUG + char tmp[32]; + + os_bzero(tmp, 32); + strncpy(tmp, (char *)&scan->ssid[2], (int)scan->ssid[1]); + wpa_printf(MSG_DEBUG, "wps parse scan: %s", tmp); +#endif + + if (wps_get_type() == WPS_TYPE_DISABLE + || (wps_get_status() != WPS_STATUS_DISABLE + && wps_get_status() != WPS_STATUS_SCANNING) + ) { + return false; + } + + esp_wifi_get_mode(&op_mode); + if ((op_mode == WIFI_MODE_STA || op_mode == WIFI_MODE_APSTA) && scan->wps) { + struct wpabuf *buf = wpabuf_alloc_copy(scan->wps + 6, scan->wps[1] - 4); + + if (wps_is_selected_pbc_registrar(buf, scan->bssid) + || wps_is_selected_pin_registrar(buf, scan->bssid)) { + wpabuf_free(buf); + + if (sm->is_wps_scan == false) { + return false; + } + if (memcmp(sm->config.bssid, scan->bssid, ETH_ALEN) != 0 ) { + sm->discover_ssid_cnt++; + } + + if (!scan->rsn && !scan->wpa && (scan->capinfo & WIFI_CAPINFO_PRIVACY)) { + wpa_printf(MSG_ERROR, "WEP not suppported in WPS"); + + return false; + } + + esp_wifi_enable_sta_privacy_internal(); + os_bzero(sm->ssid, sizeof(sm->ssid)); + strncpy((char *)sm->ssid, (char *)&scan->ssid[2], (int)scan->ssid[1]); + sm->ssid_len = scan->ssid[1]; + if (scan->bssid) { + memcpy(gWpsSm->bssid, scan->bssid, ETH_ALEN); + memcpy(sm->config.bssid, scan->bssid, ETH_ALEN); + sm->config.bssid_set = 1; + } else { + } + wpa_printf(MSG_DEBUG, "wps discover [%s]", sm->ssid); + sm->scan_cnt = 0; + + memcpy(sm->config.ssid, sm->ssid, sm->ssid_len); + sm->channel = scan->chan; + + return true; + } + wpabuf_free(buf); + } + + return false; +} + +int wps_send_eap_identity_rsp(u8 id) +{ + struct wps_sm *sm = gWpsSm; + struct wpabuf *eap_buf = NULL; + u8 bssid[6]; + u8 *buf = NULL; + int len; + int ret = ESP_OK; + + wpa_printf(MSG_DEBUG, "wps send eapol id rsp"); + eap_buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, sm->identity_len, + EAP_CODE_RESPONSE, id); + if (!eap_buf) { + ret = ESP_FAIL; + goto _err; + } + + ret = esp_wifi_get_assoc_bssid_internal(bssid); + if (ret != 0) { + wpa_printf(MSG_ERROR, "bssid is empty!"); + return ESP_FAIL; + } + + wpabuf_put_data(eap_buf, sm->identity, sm->identity_len); + + buf = wps_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head_u8(eap_buf), wpabuf_len(eap_buf), (size_t *)&len, NULL); + if (!buf) { + ret = ESP_ERR_NO_MEM; + goto _err; + } + + ret = wps_sm_ether_send(sm, bssid, ETH_P_EAPOL, buf, len); + if (ret) { + ret = ESP_FAIL; + goto _err; + } + +_err: + wps_sm_free_eapol(buf); + wpabuf_free(eap_buf); + return ret; +} + +int wps_send_frag_ack(u8 id) +{ + struct wps_sm *sm = gWpsSm; + struct wpabuf *eap_buf = NULL; + u8 bssid[6]; + u8 *buf; + int len; + int ret = 0; + enum wsc_op_code opcode = WSC_FRAG_ACK; + + wpa_printf(MSG_DEBUG, "send frag ack id:%d", id); + + if (!sm) { + return ESP_FAIL; + } + + ret = esp_wifi_get_assoc_bssid_internal(bssid); + if (ret != 0) { + wpa_printf(MSG_ERROR, "bssid is empty!"); + return ret; + } + + eap_buf = eap_msg_alloc(EAP_VENDOR_WFA, 0x00000001, 2, EAP_CODE_RESPONSE, id); + if (!eap_buf) { + ret = ESP_ERR_NO_MEM; + goto _err; + } + + wpabuf_put_u8(eap_buf, opcode); + wpabuf_put_u8(eap_buf, 0x00); /* flags */ + + buf = wps_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head_u8(eap_buf), wpabuf_len(eap_buf), (size_t *)&len, NULL); + if (!buf) { + ret = ESP_ERR_NO_MEM; + goto _err; + } + + ret = wps_sm_ether_send(sm, bssid, ETH_P_EAPOL, buf, len); + if (ret) { + ret = ESP_ERR_NO_MEM; + goto _err; + } + +_err: + wpabuf_free(eap_buf); + return ret; +} + +int wps_enrollee_process_msg_frag(struct wpabuf **buf, int tot_len, u8 *frag_data, int frag_len, u8 flag) +{ + struct wps_sm *sm = gWpsSm; + u8 identifier; + + if (!sm) { + return ESP_FAIL; + } + + identifier = sm->current_identifier; + + if (buf == NULL || frag_data == NULL) { + wpa_printf(MSG_ERROR, "fun:%s. line:%d, frag buf or frag data is null", __FUNCTION__, __LINE__); + return ESP_FAIL; + } + + if (*buf == NULL) { + if (0 == (flag & WPS_MSG_FLAG_LEN) || tot_len < frag_len) { + wpa_printf(MSG_ERROR, "fun:%s. line:%d, flag error:%02x", __FUNCTION__, __LINE__, flag); + return ESP_FAIL; + } + + *buf = wpabuf_alloc(tot_len); + if (*buf == NULL) { + return ESP_ERR_NO_MEM; + } + + wpabuf_put_data(*buf, frag_data, frag_len); + return wps_send_frag_ack(identifier); + } + + if (flag & WPS_MSG_FLAG_LEN) { + wpa_printf(MSG_ERROR, "fun:%s. line:%d, flag error:%02x", __FUNCTION__, __LINE__, flag); + return ESP_FAIL; + } + + wpabuf_put_data(*buf, frag_data, frag_len); + + if (flag & WPS_MSG_FLAG_MORE) { + return wps_send_frag_ack(identifier); + } + + return ESP_OK; +} + +int wps_process_wps_mX_req(u8 *ubuf, int len, enum wps_process_res *res) +{ + struct wps_sm *sm = gWpsSm; + static struct wpabuf *wps_buf = NULL; + struct eap_expand *expd; + int tlen = 0; + u8 *tbuf; + u8 flag; + int frag_len; + u16 be_tot_len = 0; + + if (!sm) { + return ESP_FAIL; + } + + expd = (struct eap_expand *) ubuf; + wpa_printf(MSG_DEBUG, "wps process mX req: len %d, tlen %d", len, tlen); + + flag = *(u8 *)(ubuf + sizeof(struct eap_expand)); + if (flag & WPS_MSG_FLAG_LEN) { + tbuf = ubuf + sizeof(struct eap_expand) + 1 + 2;//two bytes total length + frag_len = len - (sizeof(struct eap_expand) + 1 + 2); + be_tot_len = *(u16 *)(ubuf + sizeof(struct eap_expand) + 1); + tlen = ((be_tot_len & 0xff) << 8) | ((be_tot_len >> 8) & 0xff); + } else { + tbuf = ubuf + sizeof(struct eap_expand) + 1; + frag_len = len - (sizeof(struct eap_expand) + 1); + tlen = frag_len; + } + + if ((flag & WPS_MSG_FLAG_MORE) || wps_buf != NULL) {//frag msg + wpa_printf(MSG_DEBUG, "rx frag msg id:%d, flag:%d, frag_len: %d, tot_len: %d, be_tot_len:%d", sm->current_identifier, flag, frag_len, tlen, be_tot_len); + if (ESP_OK != wps_enrollee_process_msg_frag(&wps_buf, tlen, tbuf, frag_len, flag)) { + if (wps_buf) { + wpabuf_free(wps_buf); + wps_buf = NULL; + } + return ESP_FAIL; + } + if (flag & WPS_MSG_FLAG_MORE) { + if (res) { + *res = WPS_FRAGMENT; + } + return ESP_OK; + } + } else { //not frag msg + if (wps_buf) {//if something wrong, frag msg buf is not freed, free first + wpa_printf(MSG_ERROR, "something is wrong, frag buf is not freed"); + wpabuf_free(wps_buf); + wps_buf = NULL; + } + wps_buf = wpabuf_alloc_copy(tbuf, tlen); + } + + if (!wps_buf) { + return ESP_FAIL; + } + + ets_timer_disarm(&sm->wps_msg_timeout_timer); + + if (res) { + *res = wps_enrollee_process_msg(sm->wps, expd->opcode, wps_buf); + } else { + wps_enrollee_process_msg(sm->wps, expd->opcode, wps_buf); + } + + if (wps_buf) { + wpabuf_free(wps_buf); + wps_buf = NULL; + } + return ESP_OK; +} + +int wps_send_wps_mX_rsp(u8 id) +{ + struct wps_sm *sm = gWpsSm; + struct wpabuf *eap_buf = NULL; + struct wpabuf *wps_buf = NULL; + u8 bssid[6]; + u8 *buf; + int len; + int ret = 0; + enum wsc_op_code opcode; + + wpa_printf(MSG_DEBUG, "wps send wps mX rsp"); + + if (!sm) { + return ESP_FAIL; + } + + ret = esp_wifi_get_assoc_bssid_internal(bssid); + if (ret != 0) { + wpa_printf(MSG_ERROR, "bssid is empty!"); + return ret; + } + + wps_buf = (struct wpabuf *)wps_enrollee_get_msg(sm->wps, &opcode); + if (!wps_buf) { + ret = ESP_FAIL; + goto _err; + } + + eap_buf = eap_msg_alloc(EAP_VENDOR_WFA, 0x00000001, wpabuf_len(wps_buf) + 2, EAP_CODE_RESPONSE, id); + if (!eap_buf) { + ret = ESP_FAIL; + goto _err; + } + + wpabuf_put_u8(eap_buf, opcode); + wpabuf_put_u8(eap_buf, 0x00); /* flags */ + wpabuf_put_data(eap_buf, wpabuf_head_u8(wps_buf), wpabuf_len(wps_buf)); + + + wpabuf_free(wps_buf); + + buf = wps_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head_u8(eap_buf), wpabuf_len(eap_buf), (size_t *)&len, NULL); + if (!buf) { + ret = ESP_FAIL; + goto _err; + } + + ret = wps_sm_ether_send(sm, bssid, ETH_P_EAPOL, buf, len); + if (ret) { + ret = ESP_FAIL; + goto _err; + } + +_err: + wpabuf_free(eap_buf); + return ret; +} + + + +int wps_tx_start(void) +{ + struct wps_sm *sm = gWpsSm; + u8 bssid[6]; + u8 *buf; + int len; + int ret = 0; + + ret = esp_wifi_get_assoc_bssid_internal(bssid); + if (ret != 0) { + wpa_printf(MSG_ERROR, "bssid is empty!"); + return ret; + } + + if (!sm) { + return ESP_FAIL; + } + + wpa_printf(MSG_DEBUG, "WPS: Send EAPOL START."); + buf = wps_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_START, (u8 *)"", 0, (size_t *)&len, NULL); + if (!buf) { + return ESP_ERR_NO_MEM; + } + + wps_sm_ether_send(sm, bssid, ETH_P_EAPOL, buf, len); + wps_sm_free_eapol(buf); + + ets_timer_arm(&sm->wps_eapol_start_timer, 3000, 0); + + return ESP_OK; +} + +int wps_start_pending(void) +{ + if (!gWpsSm) { + return ESP_FAIL; + } + + wpa_printf(MSG_DEBUG, "wps start pending"); + return wps_tx_start(); +} + +int wps_stop_process(system_event_sta_wps_fail_reason_t reason_code) +{ + struct wps_sm *sm = gWpsSm; + + if (!gWpsSm) { + return ESP_FAIL; + } + + wps_set_status(WPS_STATUS_DISABLE); + sm->scan_cnt = 0; + sm->discover_ssid_cnt = 0; + sm->wps->state = SEND_M1; + os_bzero(sm->bssid, ETH_ALEN); + os_bzero(sm->ssid, 32); + sm->ssid_len = 0; + os_bzero((u8 *)&sm->config, sizeof(wifi_sta_config_t)); + + esp_wifi_disarm_sta_connection_timer_internal(); + ets_timer_disarm(&sm->wps_msg_timeout_timer); + ets_timer_disarm(&sm->wps_success_cb_timer); + + esp_wifi_disconnect(); + + wpa_printf(MSG_DEBUG, "Write wps_fail_information"); + system_event_t evt; + evt.event_id = SYSTEM_EVENT_STA_WPS_ER_FAILED; + evt.event_info.sta_er_fail_reason = reason_code; + esp_wifi_send_event_internal(&evt); + + return ESP_OK; +} + +int wps_finish(void) +{ + struct wps_sm *sm = gWpsSm; + int ret = ESP_FAIL; + + if (!gWpsSm) { + return ESP_FAIL; + } + + if (sm->wps->state == WPS_FINISHED) { + wifi_config_t *config = (wifi_config_t *)os_zalloc(sizeof(wifi_config_t)); + + if (config == NULL) { + system_event_t evt; + evt.event_id = SYSTEM_EVENT_STA_WPS_ER_FAILED; + esp_wifi_send_event_internal(&evt); + return ESP_FAIL; + } + + wpa_printf(MSG_DEBUG, "wps finished------>"); + wps_set_status(WPS_STATUS_SUCCESS); + esp_wifi_disarm_sta_connection_timer_internal(); + ets_timer_disarm(&sm->wps_timeout_timer); + ets_timer_disarm(&sm->wps_msg_timeout_timer); + + memset(config, 0x00, sizeof(wifi_sta_config_t)); + memcpy(config->sta.ssid, sm->ssid, sm->ssid_len); + memcpy(config->sta.password, sm->key, sm->key_len); + memcpy(config->sta.bssid, sm->bssid, ETH_ALEN); + config->sta.bssid_set = 0; + esp_wifi_set_config(0, config); + os_free(config); + config = NULL; + + ets_timer_disarm(&sm->wps_success_cb_timer); + ets_timer_arm(&sm->wps_success_cb_timer, 1000, 0); + + ret = 0; + } else { + wpa_printf(MSG_ERROR, "wps failed----->"); + + ret = wps_stop_process(WPS_FAIL_REASON_NORMAL); + } + + return ret; +} + +/* Add current ap to discard ap list */ +void wps_add_discard_ap(u8 *bssid) +{ + struct wps_sm *sm = gWpsSm; + u8 cnt = sm->discard_ap_cnt; + + if (!gWpsSm || !bssid) { + return; + } + + if (sm->discard_ap_cnt < WPS_MAX_DIS_AP_NUM) { + sm->discard_ap_cnt++; + } else { + for (cnt = 0; cnt < WPS_MAX_DIS_AP_NUM - 2; cnt++) { + memcpy(sm->dis_ap_list[cnt].bssid, sm->dis_ap_list[cnt + 1].bssid, 6); + } + sm->discard_ap_cnt = WPS_MAX_DIS_AP_NUM; + } + memcpy(sm->dis_ap_list[cnt].bssid, bssid, 6); +} + +int wps_start_msg_timer(void) +{ + struct wps_sm *sm = gWpsSm; + uint32_t msg_timeout; + int ret = ESP_FAIL; + + if (!gWpsSm) { + return ESP_FAIL; + } + + if (sm->wps->state == WPS_FINISHED) { + msg_timeout = 100; + wpa_printf(MSG_DEBUG, "start msg timer WPS_FINISHED %d ms", msg_timeout); + ets_timer_disarm(&sm->wps_msg_timeout_timer); + ets_timer_arm(&sm->wps_msg_timeout_timer, msg_timeout, 0); + ret = 0; + } else if (sm->wps->state == RECV_M2) { + msg_timeout = 5000; + wpa_printf(MSG_DEBUG, "start msg timer RECV_M2 %d ms", msg_timeout); + ets_timer_disarm(&sm->wps_msg_timeout_timer); + ets_timer_arm(&sm->wps_msg_timeout_timer, msg_timeout, 0); + ret = 0; + } + return ret; +} + +/** + * wps_sm_rx_eapol - Process received WPA EAPOL frames + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @src_addr: Source MAC address of the EAPOL packet + * @buf: Pointer to the beginning of the EAPOL data (EAPOL header) + * @len: Length of the EAPOL frame + * Returns: 1 = WPA EAPOL-Key processed, ESP_OK = not a WPA EAPOL-Key, ESP_FAIL failure + * + * This function is called for each received EAPOL frame. Other than EAPOL-Key + * frames can be skipped if filtering is done elsewhere. wpa_sm_rx_eapol() is + * only processing WPA and WPA2 EAPOL-Key frames. + * + * The received EAPOL-Key packets are validated and valid packets are replied + * to. In addition, key material (PTK, GTK) is configured at the end of a + * successful key handshake. + * buf begin from version, so remove mac header ,snap header and ether_type + */ +int wps_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len) +{ + if (!gWpsSm) { + return ESP_FAIL; + } + +#ifdef USE_WPS_TASK + { + struct wps_rx_param *param = (struct wps_rx_param *)os_zalloc(sizeof(struct wps_rx_param)); /* free in task */ + + if (!param) { + return ESP_ERR_NO_MEM; + } + + param->buf = (u8 *)os_zalloc(len); /* free in task */ + if (!param->buf) { + os_free(param); + return ESP_ERR_NO_MEM; + } + memcpy(param->buf, buf, len); + param->len = len; + memcpy(param->sa, src_addr, WPS_ADDR_LEN); + + return wps_post(SIG_WPS_RX, (uint32_t)param); + } +#else + return wps_sm_rx_eapol_internal(src_addr, buf, len); +#endif +} + +int wps_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len) +{ + struct wps_sm *sm = gWpsSm; + u32 plen, data_len, eap_len; + struct ieee802_1x_hdr *hdr; + struct eap_hdr *ehdr; + u8 *tmp; + u8 eap_code; + u8 eap_type; + int ret = ESP_FAIL; + enum wps_process_res res = WPS_DONE; + + if (!gWpsSm) { + return ESP_FAIL; + } + + if (len < sizeof(*hdr) + sizeof(*ehdr)) { +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: EAPOL frame too short to be a WPA " + "EAPOL-Key (len %lu, expecting at least %lu)", + (unsigned long) len, + (unsigned long) sizeof(*hdr) + sizeof(*ehdr)); +#endif + return ESP_OK; + } + + tmp = buf; + + hdr = (struct ieee802_1x_hdr *) tmp; + ehdr = (struct eap_hdr *) (hdr + 1); + plen = be_to_host16(hdr->length); + data_len = plen + sizeof(*hdr); + eap_len = be_to_host16(ehdr->length); + +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "IEEE 802.1X RX: version=%d type=%d length=%d", + hdr->version, hdr->type, plen); +#endif + + if (hdr->version < EAPOL_VERSION) { + /* TODO: backwards compatibility */ + } + if (hdr->type != IEEE802_1X_TYPE_EAP_PACKET) { +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPS: EAP frame (type %u) discarded, " + "not a EAP PACKET frame", hdr->type); +#endif + ret = 0; + goto out; + } + if (plen > len - sizeof(*hdr) || plen < sizeof(*ehdr)) { +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: EAPOL frame payload size %lu " + "invalid (frame size %lu)", + (unsigned long) plen, (unsigned long) len); +#endif + ret = 0; + goto out; + } + + wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-EAP PACKET", tmp, len); + + if (data_len < len) { +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: ignoring %lu bytes after the IEEE " + "802.1X data", (unsigned long) len - data_len); +#endif + } + + if (eap_len != plen) { +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: EAPOL length %lu " + "invalid (eapol length %lu)", + (unsigned long) eap_len, (unsigned long) plen); +#endif + ret = 0; + goto out; + } + + eap_code = ehdr->code; + switch (eap_code) { + case EAP_CODE_SUCCESS: + wpa_printf(MSG_DEBUG, "error: receive eapol success frame!"); + ret = 0; + break; + case EAP_CODE_FAILURE: + wpa_printf(MSG_DEBUG, "receive eap code failure!"); + ret = wps_finish(); + break; + case EAP_CODE_RESPONSE: + wpa_printf(MSG_DEBUG, "error: receive eapol response frame!"); + ret = 0; + break; + case EAP_CODE_REQUEST: { + eap_type = ((u8 *)ehdr)[sizeof(*ehdr)]; + switch (eap_type) { + case EAP_TYPE_IDENTITY: + wpa_printf(MSG_DEBUG, "=========identity==========="); + sm->current_identifier = ehdr->identifier; + ets_timer_disarm(&sm->wps_eapol_start_timer); + wpa_printf(MSG_DEBUG, "WPS: Build EAP Identity."); + ret = wps_send_eap_identity_rsp(ehdr->identifier); + ets_timer_arm(&sm->wps_eapol_start_timer, 3000, 0); + break; + case EAP_TYPE_EXPANDED: + wpa_printf(MSG_DEBUG, "=========expanded plen[%d], %d===========", plen, sizeof(*ehdr)); + if (ehdr->identifier == sm->current_identifier) { + ret = 0; + wpa_printf(MSG_DEBUG, "wps: ignore overlap identifier"); + goto out; + } + sm->current_identifier = ehdr->identifier; + + tmp = (u8 *)(ehdr + 1) + 1; + ret = wps_process_wps_mX_req(tmp, plen - sizeof(*ehdr) - 1, &res); + if (ret == 0 && res != WPS_FAILURE && res != WPS_IGNORE && res != WPS_FRAGMENT) { + ret = wps_send_wps_mX_rsp(ehdr->identifier); + if (ret == 0) { + wpa_printf(MSG_DEBUG, "sm->wps->state = %d", sm->wps->state); + wps_start_msg_timer(); + } + } else if (ret == 0 && res == WPS_FRAGMENT) { + wpa_printf(MSG_DEBUG, "wps frag, continue..."); + ret = ESP_OK; + } else if (res == WPS_IGNORE) { + wpa_printf(MSG_DEBUG, "IGNORE overlap Mx"); + ret = ESP_OK; /* IGNORE the overlap */ + } else { + ret = ESP_FAIL; + } + break; + default: + break; + } + break; + } + default: + break; + } +out: + if (ret != 0 || res == WPS_FAILURE) { + wpa_printf(MSG_DEBUG, "wpa rx eapol internal: fail ret=%d", ret); + wps_set_status(WPS_STATUS_DISABLE); + esp_wifi_disarm_sta_connection_timer_internal(); + ets_timer_disarm(&sm->wps_timeout_timer); + + system_event_t evt; + evt.event_id = SYSTEM_EVENT_STA_WPS_ER_FAILED; + esp_wifi_send_event_internal(&evt); + + return ret; + } + + return ret; +} + +int wps_set_default_factory(void) +{ + if (!s_factory_info) { + s_factory_info = os_zalloc(sizeof(wps_factory_information_t)); + if (!s_factory_info) { + wpa_printf(MSG_ERROR, "wps factory info malloc failed"); + return ESP_ERR_NO_MEM; + } + } + + sprintf(s_factory_info->manufacturer, "ESPRESSIF"); + sprintf(s_factory_info->model_name, "ESPRESSIF IOT"); + sprintf(s_factory_info->model_number, "ESP32"); + sprintf(s_factory_info->device_name, "ESP32 STATION"); + + return ESP_OK; +} + +int wps_set_factory_info(const esp_wps_config_t *config) +{ + int ret; + + ret = wps_set_default_factory(); + if (ret != 0) { + return ret; + } + + if (config->factory_info.manufacturer[0] != 0) { + memcpy(s_factory_info->manufacturer, config->factory_info.manufacturer, WPS_MAX_MANUFACTURER_LEN - 1); + } + + if (config->factory_info.model_number[0] != 0) { + memcpy(s_factory_info->model_number, config->factory_info.model_number, WPS_MAX_MODEL_NUMBER_LEN - 1); + } + + if (config->factory_info.model_name[0] != 0) { + memcpy(s_factory_info->model_name, config->factory_info.model_name, WPS_MAX_MODEL_NAME_LEN - 1); + } + + if (config->factory_info.device_name[0] != 0) { + memcpy(s_factory_info->device_name, config->factory_info.device_name, WPS_MAX_DEVICE_NAME_LEN - 1); + } + + wpa_printf(MSG_INFO, "manufacturer: %s, model number: %s, model name: %s, device name: %s", s_factory_info->manufacturer, + s_factory_info->model_number, s_factory_info->model_name, s_factory_info->device_name); + + return ESP_OK; +} + + +int wps_dev_init(void) +{ + int ret = 0; + struct wps_sm *sm = gWpsSm; + struct wps_device_data *dev = NULL; + + if (!sm) { + ret = ESP_FAIL; + goto _out; + } + + dev = &sm->wps_ctx->dev; + sm->dev = dev; + + if (!dev) { + ret = ESP_FAIL; + goto _out; + } + dev->config_methods = WPS_CONFIG_VIRT_PUSHBUTTON | WPS_CONFIG_PHY_DISPLAY; + dev->rf_bands = WPS_RF_24GHZ; + + WPA_PUT_BE16(dev->pri_dev_type, WPS_DEV_COMPUTER); + WPA_PUT_BE32(dev->pri_dev_type + 2, WPS_DEV_OUI_WFA); + WPA_PUT_BE16(dev->pri_dev_type + 6, WPS_DEV_COMPUTER_PC); + + if (!s_factory_info) { + ret = wps_set_default_factory(); + if (ret != 0) { + goto _out; + } + } + + dev->manufacturer = (char *)os_zalloc(WPS_MAX_MANUFACTURER_LEN); + if (!dev->manufacturer) { + ret = ESP_FAIL; + goto _out; + } + sprintf(dev->manufacturer, s_factory_info->manufacturer); + + dev->model_name = (char *)os_zalloc(WPS_MAX_MODEL_NAME_LEN); + if (!dev->model_name) { + ret = ESP_FAIL; + goto _out; + } + sprintf(dev->model_name, s_factory_info->model_name); + + dev->model_number = (char *)os_zalloc(WPS_MAX_MODEL_NAME_LEN); + if (!dev->model_number) { + ret = ESP_FAIL; + goto _out; + } + sprintf(dev->model_number, s_factory_info->model_number); + + dev->device_name = (char *)os_zalloc(WPS_MAX_DEVICE_NAME_LEN); + if (!dev->device_name) { + ret = ESP_FAIL; + goto _out; + } + sprintf(dev->device_name, s_factory_info->device_name); + + dev->serial_number = (char *)os_zalloc(16); + if (!dev->serial_number) { + ret = ESP_FAIL; + goto _out; + } + sprintf(dev->serial_number, "%02x%02x%02x%02x%02x%02x", + sm->ownaddr[0], sm->ownaddr[1], sm->ownaddr[2], + sm->ownaddr[3], sm->ownaddr[4], sm->ownaddr[5]); + + uuid_gen_mac_addr(sm->ownaddr, sm->uuid); + memcpy(dev->mac_addr, sm->ownaddr, ETH_ALEN); + + return ESP_OK; + +_out: + if (dev->manufacturer) { + os_free(dev->manufacturer); + } + if (dev->model_name) { + os_free(dev->model_name); + } + if (dev->model_number) { + os_free(dev->model_number); + } + if (dev->device_name) { + os_free(dev->device_name); + } + if (dev->serial_number) { + os_free(dev->serial_number); + } + + if (s_factory_info) { + os_free(s_factory_info); + s_factory_info = NULL; + } + + return ret; +} + + +int wps_dev_deinit(struct wps_device_data *dev) +{ + int ret = 0; + + if (!dev) { + return ESP_FAIL; + } + + if (dev->manufacturer) { + os_free(dev->manufacturer); + } + if (dev->model_name) { + os_free(dev->model_name); + } + if (dev->model_number) { + os_free(dev->model_number); + } + if (dev->device_name) { + os_free(dev->device_name); + } + if (dev->serial_number) { + os_free(dev->serial_number); + } + + if (s_factory_info) { + os_free(s_factory_info); + s_factory_info = NULL; + } + + return ret; +} + +void +wifi_station_wps_timeout_internal(void) +{ + struct wps_sm *sm = gWpsSm; + + if (!sm) { + return; + } + + esp_wifi_disarm_sta_connection_timer_internal(); + + wps_set_status(WPS_STATUS_DISABLE); + + system_event_t evt; + evt.event_id = SYSTEM_EVENT_STA_WPS_ER_TIMEOUT; + esp_wifi_send_event_internal(&evt); +} + +void wifi_station_wps_timeout(void) +{ +#ifdef USE_WPS_TASK + wps_post(SIG_WPS_TIMER_TIMEOUT, 0); + return; +#else + wifi_station_wps_timeout_internal(); +#endif +} + +void +wifi_station_wps_msg_timeout_internal(void) +{ + struct wps_sm *sm = gWpsSm; + + if (!sm) { + return; + } + + if (sm->wps->state == WPS_FINISHED) { + wpa_printf(MSG_DEBUG, "wps msg timeout WPS_FINISHED"); + wps_finish(); + } else if (sm->wps->state == RECV_M2) { + wpa_printf(MSG_DEBUG, "wps msg timeout RECV_M2"); + wpa_printf(MSG_DEBUG, "wps recev m2/m2d timeout------>"); + wps_add_discard_ap(sm->config.bssid); + wps_stop_process(WPS_FAIL_REASON_RECV_M2D); + } +} + +void wifi_station_wps_msg_timeout(void) +{ +#ifdef USE_WPS_TASK + wps_post(SIG_WPS_TIMER_MSG_TIMEOUT, 0); + return; +#else + wifi_station_wps_msg_timeout_internal(); +#endif +} + +void wifi_station_wps_success_internal(void) +{ + system_event_t evt; + evt.event_id = SYSTEM_EVENT_STA_WPS_ER_SUCCESS; + esp_wifi_send_event_internal(&evt); +} + +void wifi_station_wps_success(void) +{ +#ifdef USE_WPS_TASK + wps_post(SIG_WPS_TIMER_SUCCESS_CB, 0); + return; +#else + wifi_station_wps_success_internal(); +#endif +} + +void wifi_station_wps_eapol_start_handle_internal(void) +{ + wpa_printf(MSG_DEBUG, "Resend EAPOL-Start."); + wps_tx_start(); +} + +void wifi_station_wps_eapol_start_handle(void) +{ +#ifdef USE_WPS_TASK + wps_post(SIG_WPS_TIMER_EAPOL_START, 0); + return; +#else + wifi_station_wps_eapol_start_handle_internal(); +#endif +} + +int +wifi_station_wps_init(void) +{ + struct wps_funcs *wps_cb; + struct wps_sm *sm = NULL; + uint8_t mac[6]; + + if (gWpsSm) { + goto _out; + } + + wpa_printf(MSG_DEBUG, "wifi sta wps init"); + + gWpsSm = (struct wps_sm *)os_zalloc(sizeof(struct wps_sm)); /* alloc Wps_sm */ + if (!gWpsSm) { + goto _err; + } + + sm = gWpsSm; + memset(sm, 0x00, sizeof(struct wps_sm)); + + esp_wifi_get_macaddr_internal(WIFI_IF_STA, mac); + memcpy(sm->ownaddr, mac, ETH_ALEN); + + sm->discover_ssid_cnt = 0; + sm->ignore_sel_reg = false; + sm->discard_ap_cnt = 0; + memset(&sm->dis_ap_list, 0, WPS_MAX_DIS_AP_NUM * sizeof(struct discard_ap_list_t)); + memset(&sm->config, 0x00, sizeof(wifi_sta_config_t)); + sm->eapol_version = 0x1; + sm->identity_len = 29; + memcpy(sm->identity, WPS_EAP_EXT_VENDOR_TYPE, sm->identity_len); + + sm->is_wps_scan = false; + + sm->wps_ctx = (struct wps_context *)os_zalloc(sizeof(struct wps_context)); /* alloc wps_ctx */ + if (!sm->wps_ctx) { + goto _err; + } + + if (wps_dev_init() != 0) { + goto _err; + } + + if ((sm->wps = wps_init()) == NULL) { /* alloc wps_data */ + goto _err; + } + + /**************80211 reference***************/ + + if (esp_wifi_get_appie_internal(WIFI_APPIE_WPS_PR) == NULL) { /* alloc probe req wps ie */ + wps_build_ic_appie_wps_pr(); + } + + if (esp_wifi_get_appie_internal(WIFI_APPIE_WPS_AR) == NULL) { /* alloc assoc req wps ie */ + wps_build_ic_appie_wps_ar(); + } + + ets_timer_disarm(&sm->wps_timeout_timer); + ets_timer_setfn(&sm->wps_timeout_timer, (ETSTimerFunc *)wifi_station_wps_timeout, NULL); + ets_timer_disarm(&sm->wps_msg_timeout_timer); + ets_timer_setfn(&sm->wps_msg_timeout_timer, (ETSTimerFunc *)wifi_station_wps_msg_timeout, NULL); + ets_timer_disarm(&sm->wps_success_cb_timer); + ets_timer_setfn(&sm->wps_success_cb_timer, (ETSTimerFunc *)wifi_station_wps_success, NULL); + ets_timer_disarm(&sm->wps_scan_timer); + ets_timer_setfn(&sm->wps_scan_timer, (ETSTimerFunc *)wifi_wps_scan, NULL); + ets_timer_disarm(&sm->wps_eapol_start_timer); + ets_timer_setfn(&sm->wps_eapol_start_timer, (ETSTimerFunc *)wifi_station_wps_eapol_start_handle, NULL); + + sm->scan_cnt = 0; + + wps_cb = os_malloc(sizeof(struct wps_funcs)); + if (wps_cb == NULL) { + goto _err; + } else { + wps_cb->wps_parse_scan_result = wps_parse_scan_result; + wps_cb->wifi_station_wps_start = wifi_station_wps_start; + wps_cb->wps_sm_rx_eapol = wps_sm_rx_eapol; + wps_cb->wps_start_pending = wps_start_pending; + esp_wifi_set_wps_cb_internal(wps_cb); + } + + return ESP_OK; + +_err: + esp_wifi_unset_appie_internal(WIFI_APPIE_WPS_PR); + esp_wifi_unset_appie_internal(WIFI_APPIE_WPS_AR); + + if (sm->dev) { + wps_dev_deinit(sm->dev); + sm->dev = NULL; + } + if (sm->wps_ctx) { + os_free(sm->wps_ctx); + sm->wps_ctx = NULL; + } + if (sm->wps) { + wps_deinit(); + sm->wps = NULL; + } + if (sm) { + os_free(gWpsSm); + gWpsSm = NULL; + } + return ESP_FAIL; +_out: + return ESP_FAIL; +} + +int wps_delete_timer(void) +{ + struct wps_sm *sm = gWpsSm; + + if (!sm) { + return ESP_OK; + } + + ets_timer_disarm(&sm->wps_success_cb_timer); + ets_timer_disarm(&sm->wps_timeout_timer); + ets_timer_disarm(&sm->wps_msg_timeout_timer); + ets_timer_disarm(&sm->wps_scan_timer); + ets_timer_disarm(&sm->wps_eapol_start_timer); + ets_timer_done(&sm->wps_success_cb_timer); + ets_timer_done(&sm->wps_timeout_timer); + ets_timer_done(&sm->wps_msg_timeout_timer); + ets_timer_done(&sm->wps_scan_timer); + ets_timer_done(&sm->wps_eapol_start_timer); + esp_wifi_disarm_sta_connection_timer_internal(); + return ESP_OK; +} + +int +wifi_station_wps_deinit(void) +{ + struct wps_sm *sm = gWpsSm; + + if (gWpsSm == NULL) { + return ESP_FAIL; + } + + esp_wifi_unset_appie_internal(WIFI_APPIE_WPS_PR); + esp_wifi_unset_appie_internal(WIFI_APPIE_WPS_AR); + esp_wifi_set_wps_cb_internal(NULL); + + if (sm->dev) { + wps_dev_deinit(sm->dev); + sm->dev = NULL; + } + if (sm->wps_ctx) { + os_free(sm->wps_ctx); + sm->wps_ctx = NULL; + } + if (sm->wps) { + wps_deinit(); + sm->wps = NULL; + } + if (sm) { + os_free(gWpsSm); + gWpsSm = NULL; + } + + return ESP_OK; +} + +int +wps_station_wps_register_cb(wps_st_cb_t cb) +{ + if (!gWpsSm) { + return ESP_FAIL; + } + + gWpsSm->st_cb = cb; + return ESP_OK; +} + +struct wps_sm * +wps_sm_get(void) +{ + return gWpsSm; +} + +int +wps_ssid_save(u8 *ssid, u8 ssid_len) +{ + u8 *tmpssid; + + if (!ssid || !gWpsSm) { + return ESP_FAIL; + } + + memset(gWpsSm->ssid, 0x00, sizeof(gWpsSm->ssid)); + memcpy(gWpsSm->ssid, ssid, ssid_len); + gWpsSm->ssid_len = ssid_len; + + tmpssid = (u8 *)os_zalloc(ssid_len + 1); + if (tmpssid) { + memcpy(tmpssid, ssid, ssid_len); + wpa_printf(MSG_DEBUG, "WPS: ssid[%s]", tmpssid); + os_free(tmpssid); + } + return ESP_OK; +} + +int +wps_key_save(char *key, u8 key_len) +{ + u8 *tmpkey; + + if (!key || !gWpsSm) { + return ESP_FAIL; + } + + memset(gWpsSm->key, 0x00, sizeof(gWpsSm->key)); + memcpy(gWpsSm->key, key, key_len); + gWpsSm->key_len = key_len; + + tmpkey = (u8 *)os_zalloc(key_len + 1); + if (tmpkey) { + memcpy(tmpkey, key, key_len); + wpa_printf(MSG_DEBUG, "WPS: key[%s]", tmpkey); + os_free(tmpkey); + } + return ESP_OK; +} + +void +wifi_wps_scan_done(void *arg, STATUS status) +{ + struct wps_sm *sm = gWpsSm; + wifi_config_t wifi_config; + + if (wps_get_type() == WPS_TYPE_DISABLE) { + return; + } + + if (!sm) { + return; + } + + if (sm->discover_ssid_cnt == 1) { + wps_set_status(WPS_STATUS_PENDING); + } else if (sm->discover_ssid_cnt == 0) { + wps_set_status(WPS_STATUS_SCANNING); + } else { + wpa_printf(MSG_INFO, "PBC session overlap!"); + wps_set_status(WPS_STATUS_DISABLE); + + system_event_t evt; + evt.event_id = SYSTEM_EVENT_STA_WPS_ER_PBC_OVERLAP; + esp_wifi_send_event_internal(&evt); + } + + wpa_printf(MSG_DEBUG, "wps scan_done discover_ssid_cnt = %d", sm->discover_ssid_cnt); + + sm->discover_ssid_cnt = 0; + + if (wps_get_status() == WPS_STATUS_PENDING) { + esp_wifi_disconnect(); + + memcpy(&wifi_config.sta, &sm->config, sizeof(wifi_sta_config_t)); + esp_wifi_set_config(0, &wifi_config); + + wpa_printf(MSG_DEBUG, "WPS: neg start"); + esp_wifi_connect(); + } else if (wps_get_status() == WPS_STATUS_SCANNING) { + if (sm->scan_cnt < WPS_IGNORE_SEL_REG_MAX_CNT) { + sm->ignore_sel_reg = true; + } + ets_timer_arm(&sm->wps_scan_timer, 100, 0); + } else { + return; + } +} + +void +wifi_wps_scan_internal(void) +{ + struct wps_sm *sm = gWpsSm; + + sm->scan_cnt++; + wpa_printf(MSG_DEBUG, "wifi_wps_scan : %d", sm->scan_cnt); + + typedef void (* scan_done_cb_t)(void *arg, STATUS status); + extern int esp_wifi_promiscuous_scan_start(wifi_scan_config_t *config, scan_done_cb_t cb); + esp_wifi_promiscuous_scan_start(NULL, wifi_wps_scan_done); +} + +void wifi_wps_scan(void) +{ +#ifdef USE_WPS_TASK + wps_post(SIG_WPS_TIMER_SCAN, 0); + return; +#else + wifi_wps_scan_internal(); +#endif +} + +uint8_t wps_start = 0; +int wifi_station_wps_start(void) +{ + struct wps_sm *sm = wps_sm_get(); + + if (!sm) { + wpa_printf(MSG_ERROR, "WPS: wps not initial"); + return ESP_FAIL; + } + + ets_timer_arm(&sm->wps_timeout_timer, 120000, 0); /* 120s total */ + + switch (wps_get_status()) { + case WPS_STATUS_DISABLE: { + sm->is_wps_scan = true; + + wps_build_public_key(sm->wps, NULL, WPS_CALC_KEY_PRE_CALC); + + wifi_wps_scan(); + + + break; + } + case WPS_STATUS_SCANNING: + sm->scan_cnt = 0; + ets_timer_disarm(&sm->wps_timeout_timer); + ets_timer_arm(&sm->wps_timeout_timer, 120000, 0); /* 120s total */ + break; + default: + break; + } + wps_start = 1; + + return ESP_OK; +} + +int wps_task_deinit(void) +{ + wpa_printf(MSG_DEBUG, "wps task deinit"); + + if (s_wps_data_lock) { + vSemaphoreDelete(s_wps_data_lock); + s_wps_data_lock = NULL; + wpa_printf(MSG_DEBUG, "wps task deinit: free data lock"); + } + + if (s_wps_api_sem) { + vSemaphoreDelete(s_wps_api_sem); + s_wps_api_sem = NULL; + wpa_printf(MSG_DEBUG, "wps task deinit: free api sem"); + } + + if (s_wps_task_create_sem) { + vSemaphoreDelete(s_wps_task_create_sem); + s_wps_task_create_sem = NULL; + wpa_printf(MSG_DEBUG, "wps task deinit: free task create sem"); + } + + if (s_wps_queue) { + vQueueDelete(s_wps_queue); + s_wps_queue = NULL; + wpa_printf(MSG_DEBUG, "wps task deinit: free queue"); + } + + if (s_wps_task_hdl) { + vTaskDelete(s_wps_task_hdl); + s_wps_task_hdl = NULL; + wpa_printf(MSG_DEBUG, "wps task deinit: free task"); + } + + return ESP_OK; +} + +int wps_task_init(void) +{ + int ret = 0; + + /* Call wps_task_deinit() first in case esp_wifi_wps_disable() fails + */ + wps_task_deinit(); + + s_wps_data_lock = xSemaphoreCreateRecursiveMutex(); + if (!s_wps_data_lock) { + wpa_printf(MSG_ERROR, "wps task init: failed to alloc data lock"); + goto _wps_no_mem; + } + + s_wps_api_sem = xSemaphoreCreateCounting(1, 0); + if (!s_wps_api_sem) { + wpa_printf(MSG_ERROR, "wps task init: failed to create api sem"); + goto _wps_no_mem; + } + + s_wps_task_create_sem = xSemaphoreCreateCounting(1, 0); + if (!s_wps_task_create_sem) { + wpa_printf(MSG_ERROR, "wps task init: failed to create task sem"); + goto _wps_no_mem; + } + + os_bzero(s_wps_sig_cnt, SIG_WPS_NUM); + s_wps_queue = xQueueCreate(SIG_WPS_NUM, sizeof( void * ) ); + if (!s_wps_queue) { + wpa_printf(MSG_ERROR, "wps task init: failed to alloc queue"); + goto _wps_no_mem; + } + + ret = xTaskCreate(wps_task, "wpsT", WPS_TASK_STACK_SIZE, NULL, 2, &s_wps_task_hdl); + if (pdPASS != ret) { + wpa_printf(MSG_ERROR, "wps enable: failed to create task"); + goto _wps_no_mem; + } + + xSemaphoreTake(s_wps_task_create_sem, portMAX_DELAY); + vSemaphoreDelete(s_wps_task_create_sem); + s_wps_task_create_sem = NULL; + + wpa_printf(MSG_DEBUG, "wifi wps enable: task prio:%d, stack:%d", 2, WPS_TASK_STACK_SIZE); + return ESP_OK; + +_wps_no_mem: + wps_task_deinit(); + return ESP_ERR_NO_MEM; +} + +int wps_post_block(uint32_t sig, void *arg) +{ + wps_ioctl_param_t param; + + param.ret = ESP_FAIL; + param.arg = arg; + + if (ESP_OK != wps_post(sig, (uint32_t)¶m)) { + return ESP_FAIL; + } + + if (pdPASS == xSemaphoreTake(s_wps_api_sem, portMAX_DELAY)) { + return param.ret; + } else { + return ESP_FAIL; + } +} + +int wps_check_wifi_mode(void) +{ + bool sniffer = false; + wifi_mode_t mode; + int ret; + + ret = esp_wifi_get_mode(&mode); + if (ESP_OK != ret) { + wpa_printf(MSG_ERROR, "wps check wifi mode: failed to get wifi mode ret=%d", ret); + return ESP_FAIL; + } + + ret = esp_wifi_get_promiscuous(&sniffer); + if (ESP_OK != ret) { + wpa_printf(MSG_ERROR, "wps check wifi mode: failed to get sniffer mode ret=%d", ret); + return ESP_FAIL; + } + + if (mode == WIFI_MODE_AP || mode == WIFI_MODE_NULL || sniffer == true) { + wpa_printf(MSG_ERROR, "wps check wifi mode: wrong wifi mode=%d sniffer=%d", mode, sniffer); + return ESP_ERR_WIFI_MODE; + } + + return ESP_OK; +} + +int esp_wifi_wps_enable(const esp_wps_config_t *config) +{ + int ret; + + if (ESP_OK != wps_check_wifi_mode()) { + return ESP_ERR_WIFI_MODE; + } + + API_MUTEX_TAKE(); + if (s_wps_enabled) { + API_MUTEX_GIVE(); + wpa_printf(MSG_DEBUG, "wps enable: already enabled"); + return ESP_OK; + } + +#ifdef USE_WPS_TASK + ret = wps_task_init(); + if (ESP_OK != ret) { + API_MUTEX_GIVE(); + return ret; + } + + ret = wps_post_block(SIG_WPS_ENABLE, (esp_wps_config_t *)config); + if (ESP_OK != ret) { + wps_task_deinit(); + API_MUTEX_GIVE(); + return ret; + } + + s_wps_enabled = true; + wpa_printf(MSG_DEBUG, "wifi wps task: prio:%d, stack:%d\n", 2, WPS_TASK_STACK_SIZE); + API_MUTEX_GIVE(); + return ret; +#else + ret = wifi_wps_enable_internal(config); + API_MUTEX_GIVE(); + return ret; +#endif +} + +int wifi_wps_enable_internal(const esp_wps_config_t *config) +{ + int ret = 0; + + wpa_printf(MSG_DEBUG, "ESP WPS crypto initialize!"); + if (config->wps_type == WPS_TYPE_DISABLE) { + wpa_printf(MSG_ERROR, "wps enable: invalid wps type"); + return ESP_ERR_WIFI_WPS_TYPE; + } + + /* currently , we don't support REGISTRAR */ + if (IS_WPS_REGISTRAR(config->wps_type)) { + wpa_printf(MSG_ERROR, "wps enable: not support registrar"); + return ESP_ERR_WIFI_WPS_TYPE; + } + + wpa_printf(MSG_DEBUG, "Set factory information."); + ret = wps_set_factory_info(config); + if (ret != 0) { + return ret; + } + + wpa_printf(MSG_INFO, "wifi_wps_enable\n"); + + wps_set_type(config->wps_type); + wps_set_status(WPS_STATUS_DISABLE); + + ret = wifi_station_wps_init(); + + if (ret != 0) { + wps_set_type(WPS_STATUS_DISABLE); + wps_set_status(WPS_STATUS_DISABLE); + return ESP_FAIL; + } + + return ESP_OK; +} + +int wifi_wps_disable_internal(void) +{ + wps_set_status(WPS_STATUS_DISABLE); + wifi_station_wps_deinit(); + return ESP_OK; +} + +int esp_wifi_wps_disable(void) +{ + int ret = 0; + + if (ESP_OK != wps_check_wifi_mode()) { + return ESP_ERR_WIFI_MODE; + } + + API_MUTEX_TAKE(); + + if (!s_wps_enabled) { + wpa_printf(MSG_DEBUG, "wps disable: already disabled"); + API_MUTEX_GIVE(); + return ESP_OK; + } + + wpa_printf(MSG_INFO, "wifi_wps_disable\n"); + wps_set_type(WPS_TYPE_DISABLE); /* Notify WiFi task */ + + /* Call wps_delete_timer to delete all WPS timer, no timer will call wps_post() + * to post message to wps_task once this function returns. + */ + wps_delete_timer(); + +#ifdef USE_WPS_TASK + ret = wps_post_block(SIG_WPS_DISABLE, 0); +#else + ret = wifi_wps_disable_internal(); +#endif + + if (ESP_OK != ret) { + wpa_printf(MSG_ERROR, "wps disable: failed to disable wps, ret=%d", ret); + } + + esp_wifi_disconnect(); + wps_start = 0; + wps_task_deinit(); + s_wps_enabled = false; + API_MUTEX_GIVE(); + return ESP_OK; +} + +int esp_wifi_wps_start(int timeout_ms) +{ + if (ESP_OK != wps_check_wifi_mode()) { + return ESP_ERR_WIFI_MODE; + } + + API_MUTEX_TAKE(); + + if (!s_wps_enabled) { + wpa_printf(MSG_ERROR, "wps start: wps not enabled"); + API_MUTEX_GIVE(); + return ESP_ERR_WIFI_WPS_SM; + } + + if (wps_get_type() == WPS_TYPE_DISABLE || (wps_get_status() != WPS_STATUS_DISABLE && wps_get_status() != WPS_STATUS_SCANNING)) { + API_MUTEX_GIVE(); + return ESP_ERR_WIFI_WPS_TYPE; + } + + if (esp_wifi_get_user_init_flag_internal() == 0) { + API_MUTEX_GIVE(); + return ESP_ERR_WIFI_STATE; + } + + wpa_printf(MSG_DEBUG, "wps scan"); + +#ifdef USE_WPS_TASK + wps_post_block(SIG_WPS_START, 0); +#else + ic_pp_post(SIG_PP_WPS, 0); +#endif + + API_MUTEX_GIVE(); + return ESP_OK; +} + +bool +wifi_set_wps_cb(wps_st_cb_t cb) +{ + wifi_mode_t mode; + + esp_wifi_get_mode(&mode); + if (mode == WIFI_MODE_AP || mode == WIFI_MODE_NULL) { + return false; + } + + if (wps_station_wps_register_cb(cb) == 0) { + return true; + } + + return false; +} + diff --git a/components/wpa_supplicant/src/fast_crypto/fast_aes-cbc.c b/components/wpa_supplicant/src/fast_crypto/fast_aes-cbc.c index 5c362fa225..feccba9e42 100644 --- a/components/wpa_supplicant/src/fast_crypto/fast_aes-cbc.c +++ b/components/wpa_supplicant/src/fast_crypto/fast_aes-cbc.c @@ -3,8 +3,8 @@ // Licensed under the Apache License, Version 2.0 (the "License"); -#include "crypto/includes.h" -#include "crypto/common.h" +#include "utils/includes.h" +#include "utils/common.h" #include "crypto/aes.h" #include "crypto/aes_wrap.h" #include "mbedtls/aes.h" diff --git a/components/wpa_supplicant/src/fast_crypto/fast_aes-unwrap.c b/components/wpa_supplicant/src/fast_crypto/fast_aes-unwrap.c index fd4a49ff43..b4b9403147 100644 --- a/components/wpa_supplicant/src/fast_crypto/fast_aes-unwrap.c +++ b/components/wpa_supplicant/src/fast_crypto/fast_aes-unwrap.c @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "crypto/includes.h" -#include "crypto/common.h" +#include "utils/includes.h" +#include "utils/common.h" #include "mbedtls/aes.h" /** diff --git a/components/wpa_supplicant/src/fast_crypto/fast_aes-wrap.c b/components/wpa_supplicant/src/fast_crypto/fast_aes-wrap.c index 3b9eec1c16..ea15d8bc28 100644 --- a/components/wpa_supplicant/src/fast_crypto/fast_aes-wrap.c +++ b/components/wpa_supplicant/src/fast_crypto/fast_aes-wrap.c @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/aes.h" #include "crypto/aes_wrap.h" #include "mbedtls/aes.h" diff --git a/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal-cipher.c b/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal-cipher.c index 826d365e8c..667a886d13 100644 --- a/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal-cipher.c +++ b/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal-cipher.c @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -//#include "wpa/includes.h" +//#include "utils/includes.h" -//#include "wpa/common.h" -#include "crypto/common.h" +//#include "utils/common.h" +#include "utils/common.h" #include "crypto/crypto.h" #include "crypto/aes.h" #if defined(CONFIG_DES) || defined(CONFIG_DES3) @@ -39,7 +39,7 @@ struct fast_crypto_cipher { #ifdef CONFIG_DES3 struct { struct des3_key_s key; - uint8_t cbc[8]; + uint8_t cbc[8]; } des3; #endif #ifdef CONFIG_DES diff --git a/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal-modexp.c b/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal-modexp.c index 66d4aa2de6..2c869ce780 100644 --- a/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal-modexp.c +++ b/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal-modexp.c @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/crypto.h" #include "mbedtls/bignum.h" diff --git a/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal.c b/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal.c index a0f7da83ae..cb5e988cbc 100644 --- a/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal.c +++ b/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal.c @@ -8,18 +8,14 @@ * See README for more details. */ -#include "crypto/includes.h" -#include "crypto/common.h" +#include "utils/includes.h" +#include "utils/common.h" #include "crypto/crypto.h" #include "crypto/sha1_i.h" #include "crypto/md5_i.h" #include "mbedtls/sha256.h" -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - struct fast_crypto_hash { enum crypto_hash_alg alg; union { diff --git a/components/wpa_supplicant/src/fast_crypto/fast_sha256-internal.c b/components/wpa_supplicant/src/fast_crypto/fast_sha256-internal.c index 7650cb87ed..cdbd072106 100644 --- a/components/wpa_supplicant/src/fast_crypto/fast_sha256-internal.c +++ b/components/wpa_supplicant/src/fast_crypto/fast_sha256-internal.c @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "crypto/includes.h" -#include "crypto/common.h" +#include "utils/includes.h" +#include "utils/common.h" #include "mbedtls/sha256.h" /** diff --git a/components/wpa_supplicant/src/fast_crypto/fast_sha256.c b/components/wpa_supplicant/src/fast_crypto/fast_sha256.c index b0fb03e4f8..0f0a785b1a 100644 --- a/components/wpa_supplicant/src/fast_crypto/fast_sha256.c +++ b/components/wpa_supplicant/src/fast_crypto/fast_sha256.c @@ -14,9 +14,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/sha256.h" #include "crypto/crypto.h" diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.c b/components/wpa_supplicant/src/rsn_supp/wpa.c new file mode 100644 index 0000000000..c5b5c86375 --- /dev/null +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -0,0 +1,1975 @@ + +/* + * WPA Supplicant - WPA state machine and EAPOL-Key processing + * Copyright (c) 2003-2010, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ +#include "utils/includes.h" + +#include "utils/common.h" +#include "rsn_supp/wpa.h" +#include "rsn_supp/wpa_i.h" +#include "common/eapol_common.h" +#include "common/ieee802_11_defs.h" +#include "rsn_supp/wpa_ie.h" +#include "esp_supplicant/esp_wpas_glue.h" +#include "esp_supplicant/esp_wifi_driver.h" + +#include "crypto/crypto.h" +#include "crypto/sha1.h" +#include "crypto/aes_wrap.h" +#include "crypto/wepkey.h" + +/** + * eapol_sm_notify_eap_success - Notification of external EAP success trigger + * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() + * @success: %TRUE = set success, %FALSE = clear success + * + * Notify the EAPOL state machine that external event has forced EAP state to + * success (success = %TRUE). This can be cleared by setting success = %FALSE. + * + * This function is called to update EAP state when WPA-PSK key handshake has + * been completed successfully since WPA-PSK does not use EAP state machine. + */ + +#define WPA_4_4_HANDSHAKE_BIT (1<<13) +#define WPA_GROUP_HANDSHAKE_BIT (1<<14) + struct wpa_sm gWpaSm; +/* fix buf for tx for now */ +#define WPA_TX_MSG_BUFF_MAXLEN 200 + +#define ASSOC_IE_LEN 24 +u8 assoc_ie_buf[ASSOC_IE_LEN+2]; + +void set_assoc_ie(u8 * assoc_buf); + +int wpa_sm_set_key(struct install_key *sm, enum wpa_alg alg, + u8 *addr, int key_idx, int set_tx, + u8 *seq, size_t seq_len, + u8 *key, size_t key_len, + int key_entry_valid); + +int wpa_sm_get_key(uint8_t *ifx, int *alg, u8 *addr, int *key_idx, u8 *key, size_t key_len, int key_entry_valid); + +void wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len); + +static inline enum wpa_states wpa_sm_get_state(struct wpa_sm *sm) +{ + return sm->wpa_state;; +} + +static inline void wpa_sm_cancel_auth_timeout(struct wpa_sm *sm) +{ + +} + +void eapol_sm_notify_eap_success(Boolean success) +{ + +} +/** + * get_bssid - Get the current BSSID + * @priv: private driver interface data + * @bssid: buffer for BSSID (ETH_ALEN = 6 bytes) + * + * Returns: 0 on success, -1 on failure + * + * Query kernel driver for the current BSSID and copy it to bssid. + * Setting bssid to 00:00:00:00:00:00 is recommended if the STA is not + * associated. + */ +static inline int wpa_sm_get_bssid(struct wpa_sm *sm, u8 *bssid) +{ + memcpy(bssid, sm->bssid, ETH_ALEN); + return 0; +} + + /* + * wpa_ether_send - Send Ethernet frame + * @wpa_s: Pointer to wpa_supplicant data + * @dest: Destination MAC address + * @proto: Ethertype in host byte order + * @buf: Frame payload starting from IEEE 802.1X header + * @len: Frame payload length + * Returns: >=0 on success, <0 on failure + */ +static inline int wpa_sm_ether_send( struct wpa_sm *sm, const u8 *dest, u16 proto, + const u8 *data, size_t data_len) +{ + void *buffer = (void *)(data - sizeof(struct l2_ethhdr)); + struct l2_ethhdr *eth = (struct l2_ethhdr *)buffer; + + memcpy(eth->h_dest, dest, ETH_ALEN); + memcpy(eth->h_source, sm->own_addr, ETH_ALEN); + eth->h_proto = host_to_be16(proto); + sm->sendto(buffer, sizeof(struct l2_ethhdr) + data_len); + + return 0; +} + +/** + * wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @kck: Key Confirmation Key (KCK, part of PTK) + * @ver: Version field from Key Info + * @dest: Destination address for the frame + * @proto: Ethertype (usually ETH_P_EAPOL) + * @msg: EAPOL-Key message + * @msg_len: Length of message + * @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written + */ +void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, + int ver, const u8 *dest, u16 proto, + u8 *msg, size_t msg_len, u8 *key_mic) +{ + if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) { + /* + * Association event was not yet received; try to fetch + * BSSID from the driver. + */ + if (wpa_sm_get_bssid(sm, sm->bssid) < 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Failed to read BSSID for " + "EAPOL-Key destination address"); + #endif + } else { + dest = sm->bssid; + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Use BSSID (" MACSTR + ") as the destination for EAPOL-Key", + MAC2STR(dest)); + #endif + } + } + if (key_mic && + wpa_eapol_key_mic(kck, ver, msg, msg_len, key_mic)) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Failed to generate EAPOL-Key " + "version %d MIC", ver); + #endif + goto out; + } + wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len); + wpa_sm_ether_send(sm, dest, proto, msg, msg_len); +out: + return; +} + +/** + * wpa_sm_key_request - Send EAPOL-Key Request + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @error: Indicate whether this is an Michael MIC error report + * @pairwise: 1 = error report for pairwise packet, 0 = for group packet + * + * Send an EAPOL-Key Request to the current authenticator. This function is + * used to request rekeying and it is usually called when a local Michael MIC + * failure is detected. + */ +void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) +{ + size_t rlen; + struct wpa_eapol_key *reply; + int key_info, ver; + u8 bssid[ETH_ALEN], *rbuf; + + if (wpa_key_mgmt_ft(sm->key_mgmt) || wpa_key_mgmt_sha256(sm->key_mgmt)) + ver = WPA_KEY_INFO_TYPE_AES_128_CMAC; + else if (sm->pairwise_cipher == WPA_CIPHER_CCMP) + ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; + else + ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; + + if (wpa_sm_get_bssid(sm, bssid) < 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "Failed to read BSSID for EAPOL-Key " + "request"); + #endif + return; + } + + rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, + sizeof(*reply), &rlen, (void *) &reply); + if (rbuf == NULL) + return; + + reply->type = sm->proto == WPA_PROTO_RSN ? + EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; + key_info = WPA_KEY_INFO_REQUEST | ver; + if (sm->ptk_set) + key_info |= WPA_KEY_INFO_MIC; + if (error) + key_info |= WPA_KEY_INFO_ERROR|WPA_KEY_INFO_SECURE; + if (pairwise) + key_info |= WPA_KEY_INFO_KEY_TYPE; + WPA_PUT_BE16(reply->key_info, key_info); + WPA_PUT_BE16(reply->key_length, 0); + memcpy(reply->replay_counter, sm->request_counter, + WPA_REPLAY_COUNTER_LEN); + inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN); + + WPA_PUT_BE16(reply->key_data_length, 0); + + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key Request (error=%d " + "pairwise=%d ptk_set=%d len=%lu)", + error, pairwise, sm->ptk_set, (unsigned long) rlen); + #endif + wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL, + rbuf, rlen, key_info & WPA_KEY_INFO_MIC ? + reply->key_mic : NULL); + wpa_sm_free_eapol(rbuf); +} + +int wpa_supplicant_get_pmk(struct wpa_sm *sm) +{ + if(sm->pmk_len >0) { + return 0; + } else { + return 1; + } +} + +/** + * wpa_supplicant_send_2_of_4 - Send message 2 of WPA/RSN 4-Way Handshake + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @dst: Destination address for the frame + * @key: Pointer to the EAPOL-Key frame header + * @ver: Version bits from EAPOL-Key Key Info + * @nonce: Nonce value for the EAPOL-Key frame + * @wpa_ie: WPA/RSN IE + * @wpa_ie_len: Length of the WPA/RSN IE + * @ptk: PTK to use for keyed hash and encryption + * Returns: 0 on success, -1 on failure + */ +int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, + const struct wpa_eapol_key *key, + int ver, const u8 *nonce, + const u8 *wpa_ie, size_t wpa_ie_len, + struct wpa_ptk *ptk) +{ + size_t rlen; + struct wpa_eapol_key *reply; + u8 *rbuf; + + if (wpa_ie == NULL) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_ERROR, "WPA: No wpa_ie set - cannot " + "generate msg 2/4"); + #endif + return -1; + } + + wpa_hexdump(MSG_MSGDUMP, "WPA: WPA IE for msg 2/4\n", wpa_ie, wpa_ie_len); + + rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, + NULL, sizeof(*reply) + wpa_ie_len, + &rlen, (void *) &reply); + if (rbuf == NULL) { + return -1; + } + + reply->type = sm->proto == WPA_PROTO_RSN ? + EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; + WPA_PUT_BE16(reply->key_info, + ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC); + if (sm->proto == WPA_PROTO_RSN) + WPA_PUT_BE16(reply->key_length, 0); + else + memcpy(reply->key_length, key->key_length, 2); + + memcpy(reply->replay_counter, key->replay_counter, + WPA_REPLAY_COUNTER_LEN); + + WPA_PUT_BE16(reply->key_data_length, wpa_ie_len); + memcpy(reply + 1, wpa_ie, wpa_ie_len); + + memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN); + + wpa_printf(MSG_DEBUG, "WPA Send EAPOL-Key 2/4\n"); + + wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL, + rbuf, rlen, reply->key_mic); + wpa_sm_free_eapol(rbuf); + + return 0; +} + +int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr, + const struct wpa_eapol_key *key, + struct wpa_ptk *ptk) +{ + size_t ptk_len = sm->pairwise_cipher == WPA_CIPHER_CCMP ? 48 : 64; + + wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion", + sm->own_addr, sm->bssid, sm->snonce, key->key_nonce, + (u8 *) ptk, ptk_len, + wpa_key_mgmt_sha256(sm->key_mgmt)); + return 0; +} + +void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, + const unsigned char *src_addr, + const struct wpa_eapol_key *key, + u16 ver) +{ + struct wpa_eapol_ie_parse ie; + struct wpa_ptk *ptk; + int res; + + wpa_sm_set_state(WPA_FIRST_HALF_4WAY_HANDSHAKE); + + wpa_printf(MSG_DEBUG, "WPA 1/4-Way Handshake\n"); + + memset(&ie, 0, sizeof(ie)); + +#ifndef CONFIG_NO_WPA2 + if (sm->proto == WPA_PROTO_RSN) { + /* RSN: msg 1/4 should contain PMKID for the selected PMK */ + const u8 *_buf = (const u8 *) (key + 1); + size_t len = WPA_GET_BE16(key->key_data_length); + wpa_hexdump(MSG_MSGDUMP, "RSN: msg 1/4 key data", _buf, len); + wpa_supplicant_parse_ies(_buf, len, &ie); + if (ie.pmkid) { + wpa_hexdump(MSG_DEBUG, "RSN: PMKID from " + "Authenticator", ie.pmkid, PMKID_LEN); + } + } +#endif /* CONFIG_NO_WPA2 */ + + res = wpa_supplicant_get_pmk(sm); + if (res == -2) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "RSN: Do not reply to msg 1/4 - " + "requesting full EAP authentication"); + #endif + return; + } + if (res) + goto failed; + + if (sm->renew_snonce) { + if (os_get_random(sm->snonce, WPA_NONCE_LEN)) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Failed to get random data for SNonce"); + #endif + goto failed; + } + + sm->renew_snonce = 0; + wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce", + sm->snonce, WPA_NONCE_LEN); + } + + /* Calculate PTK which will be stored as a temporary PTK until it has + * been verified when processing message 3/4. */ + ptk = &sm->tptk; + wpa_derive_ptk(sm, src_addr, key, ptk); + /* Supplicant: swap tx/rx Mic keys */ + sm->tptk_set = 1; + sm->ptk_set = 0; + sm->key_install = true; + + if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce, + sm->assoc_wpa_ie, sm->assoc_wpa_ie_len, + ptk)) + goto failed; + + memcpy(sm->anonce, key->key_nonce, WPA_NONCE_LEN); + return; + +failed: + wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); +} + + void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_sm *sm = eloop_ctx; + + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Request PTK rekeying"); + #endif + wpa_sm_key_request(sm, 0, 1); +} + + +int wpa_supplicant_install_ptk(struct wpa_sm *sm) +{ + int keylen; + enum wpa_alg alg; + + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Installing PTK to the driver.\n"); + #endif + + switch (sm->pairwise_cipher) { + case WPA_CIPHER_CCMP: + alg = WPA_ALG_CCMP; + keylen = 16; + break; + case WPA_CIPHER_TKIP: + alg = WPA_ALG_TKIP; + keylen = 32; + break; + case WPA_CIPHER_NONE: + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Pairwise Cipher Suite: " + "NONE - do not use pairwise keys"); + #endif + return 0; + default: + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Unsupported pairwise cipher %d", + sm->pairwise_cipher); + #endif + return -1; + } + + //now only use keyentry 0 for pairwise key + sm->key_entry_valid = 5; + + if (wpa_sm_set_key(&(sm->install_ptk), alg, sm->bssid, 0, 1, (sm->install_ptk).seq, WPA_KEY_RSC_LEN, + (u8 *) sm->ptk.tk1, keylen,sm->key_entry_valid) < 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Failed to set PTK to the " + "driver (alg=%d keylen=%d bssid=" MACSTR ")", + alg, keylen, MAC2STR(sm->bssid)); + #endif + return -1; + } + + if (sm->wpa_ptk_rekey) { + eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL); + eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk, + sm, NULL); + } + + return 0; +} + +int wpa_supplicant_check_group_cipher(int group_cipher, + int keylen, int maxkeylen, + int *key_rsc_len, + enum wpa_alg *alg) +{ + int ret = 0; + + switch (group_cipher) { + case WPA_CIPHER_CCMP: + if (keylen != 16 || maxkeylen < 16) { + ret = -1; + break; + } + *key_rsc_len = 6; + *alg = WPA_ALG_CCMP; + break; + case WPA_CIPHER_TKIP: + if (keylen != 32 || maxkeylen < 32) { + ret = -1; + break; + } + *key_rsc_len = 6; + *alg = WPA_ALG_TKIP; + break; + case WPA_CIPHER_WEP104: + if (keylen != 13 || maxkeylen < 13) { + ret = -1; + break; + } + *key_rsc_len = 0; + *alg = WPA_ALG_WEP104; + break; + case WPA_CIPHER_WEP40: + if (keylen != 5 || maxkeylen < 5) { + ret = -1; + break; + } + *key_rsc_len = 0; + *alg = WPA_ALG_WEP40; + break; + default: + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Unsupported Group Cipher %d", + group_cipher); + #endif + return -1; + } + + if (ret < 0 ) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Unsupported %s Group Cipher key " + "length %d (%d).", + wpa_cipher_txt(group_cipher), keylen, maxkeylen); + #endif + } + + return ret; +} + +void wpa_supplicant_key_neg_complete(struct wpa_sm *sm, + const u8 *addr, int secure) +{ +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Key negotiation completed with " + MACSTR " [PTK=%s GTK=%s]\n", MAC2STR(addr), + wpa_cipher_txt(sm->pairwise_cipher), + wpa_cipher_txt(sm->group_cipher)); +#endif + wpa_sm_cancel_auth_timeout(sm); + wpa_sm_set_state(WPA_COMPLETED); + + sm->wpa_neg_complete(); + + if (secure) { + wpa_sm_mlme_setprotection( + sm, addr, MLME_SETPROTECTION_PROTECT_TYPE_RX_TX, + MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); + + if (wpa_key_mgmt_wpa_psk(sm->key_mgmt)) + eapol_sm_notify_eap_success(TRUE); + /* + * Start preauthentication after a short wait to avoid a + * possible race condition between the data receive and key + * configuration after the 4-Way Handshake. This increases the + * likelyhood of the first preauth EAPOL-Start frame getting to + * the target AP. + */ + } + +} + + +int wpa_supplicant_install_gtk(struct wpa_sm *sm, + struct wpa_gtk_data *gd) +{ + u8 *_gtk = gd->gtk; + u8 gtk_buf[32]; + u8 *key_rsc=(sm->install_gtk).seq; + + wpa_hexdump(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len); + + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Installing GTK to the driver " + "(keyidx=%d tx=%d len=%d).\n", gd->keyidx, gd->tx, + gd->gtk_len); + #endif + wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, gd->key_rsc_len); + if (sm->group_cipher == WPA_CIPHER_TKIP) { + /* Swap Tx/Rx keys for Michael MIC */ + memcpy(gtk_buf, gd->gtk, 16); + memcpy(gtk_buf + 16, gd->gtk + 16, 8); + memcpy(gtk_buf + 24, gd->gtk + 24, 8); + _gtk = gtk_buf; + } + //now only use keycache entry1 for group key + sm->key_entry_valid = gd->keyidx; + if (sm->pairwise_cipher == WPA_CIPHER_NONE) { + if (wpa_sm_set_key(&(sm->install_gtk), gd->alg, + sm->bssid, //(u8 *) "\xff\xff\xff\xff\xff\xff", + gd->keyidx, 1, key_rsc, gd->key_rsc_len, + _gtk, gd->gtk_len,sm->key_entry_valid) < 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Failed to set " + "GTK to the driver (Group only)."); + #endif + return -1; + } + } else if (wpa_sm_set_key(&(sm->install_gtk), gd->alg, + sm->bssid, //(u8 *) "\xff\xff\xff\xff\xff\xff", + gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len, + _gtk, gd->gtk_len, sm->key_entry_valid) < 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Failed to set GTK to " + "the driver (alg=%d keylen=%d keyidx=%d)", + gd->alg, gd->gtk_len, gd->keyidx); + #endif + return -1; + } + + return 0; +} + +bool wpa_supplicant_gtk_in_use(struct wpa_sm *sm, struct wpa_gtk_data *gd) +{ + u8 *_gtk = gd->gtk; + u8 gtk_buf[32]; + u8 gtk_get[32] = {0}; + u8 ifx; + int alg; + u8 bssid[6]; + int keyidx; + + wpa_hexdump(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len); + + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Judge GTK: (keyidx=%d len=%d).", gd->keyidx, gd->gtk_len); + #endif + + if (sm->group_cipher == WPA_CIPHER_TKIP) { + /* Swap Tx/Rx keys for Michael MIC */ + memcpy(gtk_buf, gd->gtk, 16); + memcpy(gtk_buf + 16, gd->gtk + 16, 8); + memcpy(gtk_buf + 24, gd->gtk + 24, 8); + _gtk = gtk_buf; + } + + //check if gtk is in use. + if (wpa_sm_get_key(&ifx, &alg, bssid, &keyidx, gtk_get, gd->gtk_len, gd->keyidx) == 0) { + if (ifx == 0 && alg == gd->alg && memcmp(bssid, sm->bssid, ETH_ALEN) == 0 && + memcmp(_gtk, gtk_get, gd->gtk_len) == 0) { + wpa_printf(MSG_DEBUG, "GTK %d is already in use in entry %d, it may be an attack, ignor it.", gd->keyidx, gd->keyidx + 2); + return true; + } + } + + if (wpa_sm_get_key(&ifx, &alg, bssid, &keyidx, gtk_get, gd->gtk_len, (gd->keyidx+1)%2) == 0) { + if (ifx == 0 && alg == gd->alg && memcmp(bssid, sm->bssid, ETH_ALEN) == 0 && + memcmp(_gtk, gtk_get, gd->gtk_len) == 0) { + wpa_printf(MSG_DEBUG, "GTK %d is already in use in entry %d, it may be an attack, ignor it.", gd->keyidx, (gd->keyidx+1)%2 + 2); + return true; + } + } + + return false; +} + +int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm, + int tx) +{ + if (tx && sm->pairwise_cipher != WPA_CIPHER_NONE) { + /* Ignore Tx bit for GTK if a pairwise key is used. One AP + * seemed to set this bit (incorrectly, since Tx is only when + * doing Group Key only APs) and without this workaround, the + * data connection does not work because wpa_supplicant + * configured non-zero keyidx to be used for unicast. */ + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Tx bit set for GTK, but pairwise " + "keys are used - ignore Tx bit"); + #endif + return 0; + } + return tx; +} + +int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, + const u8 *gtk, size_t gtk_len, + int key_info) +{ +#ifndef CONFIG_NO_WPA2 + struct wpa_gtk_data *gd=&(sm->gd); + + /* + * IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames - Figure 43x + * GTK KDE format: + * KeyID[bits 0-1], Tx [bit 2], Reserved [bits 3-7] + * Reserved [bits 0-7] + * GTK + */ + + memset(gd, 0, sizeof(struct wpa_gtk_data)); + wpa_hexdump(MSG_DEBUG, "RSN: received GTK in pairwise handshake", + gtk, gtk_len); + + if (gtk_len < 2 || gtk_len - 2 > sizeof(gd->gtk)) + return -1; + + gd->keyidx = gtk[0] & 0x3; + gd->tx = wpa_supplicant_gtk_tx_bit_workaround(sm, + !!(gtk[0] & BIT(2))); + gtk += 2; + gtk_len -= 2; + + memcpy(gd->gtk, gtk, gtk_len); + gd->gtk_len = gtk_len; + + if (wpa_supplicant_check_group_cipher(sm->group_cipher, + gtk_len, gtk_len, + &(gd->key_rsc_len), &(gd->alg))) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "RSN: Failed to install GTK"); + #endif + return -1; + } + return 0; +#else /* CONFIG_NO_WPA2 */ + return -1; +#endif /* CONFIG_NO_WPA2 */ +} + +#ifdef DEBUG_PRINT +void wpa_report_ie_mismatch(struct wpa_sm *sm, + const char *reason, const u8 *src_addr, + const u8 *wpa_ie, size_t wpa_ie_len, + const u8 *rsn_ie, size_t rsn_ie_len) +#else +void wpa_report_ie_mismatch(struct wpa_sm *sm, const u8 *src_addr, + const u8 *wpa_ie, size_t wpa_ie_len, + const u8 *rsn_ie, size_t rsn_ie_len) +#endif +{ + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: %s (src=" MACSTR ")", + reason, MAC2STR(src_addr)); + #endif + if (sm->ap_wpa_ie) { + wpa_hexdump(MSG_INFO, "WPA: WPA IE in Beacon/ProbeResp", + sm->ap_wpa_ie, sm->ap_wpa_ie_len); + } + if (wpa_ie) { + if (!sm->ap_wpa_ie) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: No WPA IE in " + "Beacon/ProbeResp"); + #endif + } + wpa_hexdump(MSG_INFO, "WPA: WPA IE in 3/4 msg", + wpa_ie, wpa_ie_len); + } + + if (sm->ap_rsn_ie) { + wpa_hexdump(MSG_INFO, "WPA: RSN IE in Beacon/ProbeResp", + sm->ap_rsn_ie, sm->ap_rsn_ie_len); + } + if (rsn_ie) { + if (!sm->ap_rsn_ie) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: No RSN IE in " + "Beacon/ProbeResp"); + #endif + } + wpa_hexdump(MSG_INFO, "WPA: RSN IE in 3/4 msg", + rsn_ie, rsn_ie_len); + } + + wpa_sm_disassociate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS); +} + +int ieee80211w_set_keys(struct wpa_sm *sm, + struct wpa_eapol_ie_parse *ie) +{ + return 0; +} + + int wpa_supplicant_validate_ie(struct wpa_sm *sm, + const unsigned char *src_addr, + struct wpa_eapol_ie_parse *ie) +{ + if (sm->ap_wpa_ie == NULL && sm->ap_rsn_ie == NULL) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: No WPA/RSN IE for this AP known. " + "Trying to get from scan results\n"); + #endif + if (wpa_sm_get_beacon_ie(sm) < 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Could not find AP from " + "the scan results"); + #endif + } else { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Found the current AP from " + "updated scan results\n"); + #endif + } + } + + if (ie->wpa_ie == NULL && ie->rsn_ie == NULL && + (sm->ap_wpa_ie || sm->ap_rsn_ie)) { +#ifdef DEBUG_PRINT + wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match " + "with IE in Beacon/ProbeResp (no IE?)", + src_addr, ie->wpa_ie, ie->wpa_ie_len, + ie->rsn_ie, ie->rsn_ie_len); +#else + wpa_report_ie_mismatch(sm, + src_addr, ie->wpa_ie, ie->wpa_ie_len, + ie->rsn_ie, ie->rsn_ie_len); +#endif + return -1; + } + + if ((ie->wpa_ie && sm->ap_wpa_ie && + (ie->wpa_ie_len != sm->ap_wpa_ie_len || + memcmp(ie->wpa_ie, sm->ap_wpa_ie, ie->wpa_ie_len) != 0)) || + (ie->rsn_ie && sm->ap_rsn_ie && + wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt), + sm->ap_rsn_ie, sm->ap_rsn_ie_len, + ie->rsn_ie, ie->rsn_ie_len))) { +#ifdef DEBUG_PRINT + wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match " + "with IE in Beacon/ProbeResp", + src_addr, ie->wpa_ie, ie->wpa_ie_len, + ie->rsn_ie, ie->rsn_ie_len); +#else + wpa_report_ie_mismatch(sm, + src_addr, ie->wpa_ie, ie->wpa_ie_len, + ie->rsn_ie, ie->rsn_ie_len); +#endif + return -1; + } + + if (sm->proto == WPA_PROTO_WPA && + ie->rsn_ie && sm->ap_rsn_ie == NULL && sm->rsn_enabled) { +#ifdef DEBUG_PRINT + wpa_report_ie_mismatch(sm, "Possible downgrade attack " + "detected - RSN was enabled and RSN IE " + "was in msg 3/4, but not in " + "Beacon/ProbeResp", + src_addr, ie->wpa_ie, ie->wpa_ie_len, + ie->rsn_ie, ie->rsn_ie_len); +#else + wpa_report_ie_mismatch(sm, + src_addr, ie->wpa_ie, ie->wpa_ie_len, + ie->rsn_ie, ie->rsn_ie_len); +#endif + return -1; + } + + return 0; +} + +/** + * wpa_supplicant_send_4_of_4 - Send message 4 of WPA/RSN 4-Way Handshake + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @dst: Destination address for the frame + * @key: Pointer to the EAPOL-Key frame header + * @ver: Version bits from EAPOL-Key Key Info + * @key_info: Key Info + * @kde: KDEs to include the EAPOL-Key frame + * @kde_len: Length of KDEs + * @ptk: PTK to use for keyed hash and encryption + * Returns: 0 on success, -1 on failure + */ + int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, + const struct wpa_eapol_key *key, + u16 ver, u16 key_info, + const u8 *kde, size_t kde_len, + struct wpa_ptk *ptk) +{ + size_t rlen; + struct wpa_eapol_key *reply; + u8 *rbuf; + + if (kde) + wpa_hexdump(MSG_DEBUG, "WPA: KDE for msg 4/4", kde, kde_len); + + rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, + sizeof(*reply) + kde_len, + &rlen, (void *) &reply); + if (rbuf == NULL) + return -1; + + sm->txcb_flags |= WPA_4_4_HANDSHAKE_BIT; + wpa_printf(MSG_DEBUG, "tx 4/4 txcb_flags=%d\n", sm->txcb_flags); + + reply->type = sm->proto == WPA_PROTO_RSN ? + EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; + key_info &= WPA_KEY_INFO_SECURE; + key_info |= ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC; + WPA_PUT_BE16(reply->key_info, key_info); + if (sm->proto == WPA_PROTO_RSN) + WPA_PUT_BE16(reply->key_length, 0); + else + memcpy(reply->key_length, key->key_length, 2); + memcpy(reply->replay_counter, key->replay_counter, + WPA_REPLAY_COUNTER_LEN); + + WPA_PUT_BE16(reply->key_data_length, kde_len); + if (kde) + memcpy(reply + 1, kde, kde_len); + + wpa_printf(MSG_DEBUG, "WPA Send EAPOL-Key 4/4\n"); + wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL, + rbuf, rlen, reply->key_mic); + wpa_sm_free_eapol(rbuf); + + return 0; +} + + void wpa_sm_set_seq(struct wpa_sm *sm, struct wpa_eapol_key *key, u8 isptk) +{ + u8 *key_rsc, *seq; + u8 null_rsc[WPA_KEY_RSC_LEN]; + + os_bzero(null_rsc, WPA_KEY_RSC_LEN); + + if (sm->proto == WPA_PROTO_RSN) { + key_rsc = null_rsc; + } else { + key_rsc = key->key_rsc; + wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, WPA_KEY_RSC_LEN); + } + + seq=(isptk) ? (sm->install_ptk).seq : (sm->install_gtk).seq; + memcpy(seq, key_rsc, WPA_KEY_RSC_LEN); +} + + void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, + struct wpa_eapol_key *key, + u16 ver) +{ + u16 key_info, keylen, len; + const u8 *pos; + struct wpa_eapol_ie_parse ie; + + wpa_sm_set_state(WPA_LAST_HALF_4WAY_HANDSHAKE); + wpa_printf(MSG_DEBUG, "WPA 3/4-Way Handshake\n"); + + key_info = WPA_GET_BE16(key->key_info); + + pos = (const u8 *) (key + 1); + len = WPA_GET_BE16(key->key_data_length); + wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len); + wpa_supplicant_parse_ies(pos, len, &ie); + if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: GTK IE in unencrypted key data"); + #endif + goto failed; + } + + if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0) + goto failed; + + if (memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: ANonce from message 1 of 4-Way " + "Handshake differs from 3 of 4-Way Handshake - drop" + " packet (src=" MACSTR ")", MAC2STR(sm->bssid)); + #endif + goto failed; + } + + keylen = WPA_GET_BE16(key->key_length); + switch (sm->pairwise_cipher) { + case WPA_CIPHER_CCMP: + if (keylen != 16) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Invalid CCMP key length " + "%d (src=" MACSTR ")", + keylen, MAC2STR(sm->bssid)); + #endif + goto failed; + } + break; + case WPA_CIPHER_TKIP: + if (keylen != 32) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Invalid TKIP key length " + "%d (src=" MACSTR ")", + keylen, MAC2STR(sm->bssid)); + #endif + goto failed; + } + break; + } + + + /* SNonce was successfully used in msg 3/4, so mark it to be renewed + * for the next 4-Way Handshake. If msg 3 is received again, the old + * SNonce will still be used to avoid changing PTK. */ + sm->renew_snonce = 1; + + /*ready for txcallback , set seq and set txcallback param*/ + wpa_sm_set_seq(sm, key, 1); + sm->key_info=key_info; + (sm->gd).gtk_len=0; //used as flag if gtk is installed in callback + if (ie.gtk) { + wpa_sm_set_seq(sm, key, 0); + if (wpa_supplicant_pairwise_gtk(sm, + ie.gtk, ie.gtk_len, key_info) < 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "RSN: Failed to configure GTK"); + #endif + goto failed; + } + } + + if (ieee80211w_set_keys(sm, &ie) < 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "RSN: Failed to configure IGTK"); + #endif + goto failed; + } + + /*after txover, callback will continue run remain task*/ + if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info, + NULL, 0, &sm->ptk)) { + goto failed; + } + + return; + +failed: + wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); +} + + + int wpa_supplicant_send_4_of_4_txcallback(struct wpa_sm *sm) +{ + u16 key_info=sm->key_info; + + if (sm->key_install && key_info & WPA_KEY_INFO_INSTALL) { + if (wpa_supplicant_install_ptk(sm)) + goto failed; + } + else if (sm->key_install == false) { + wpa_printf(MSG_DEBUG, "PTK has been installed, it may be an attack, ignor it."); + } + + wpa_sm_set_state(WPA_GROUP_HANDSHAKE); + + if((sm->gd).gtk_len) { + if (sm->key_install) { + if (wpa_supplicant_install_gtk(sm, &(sm->gd))) + goto failed; + } + else { + wpa_printf(MSG_DEBUG, "GTK has been installed, it may be an attack, ignor it."); + } + wpa_supplicant_key_neg_complete(sm, sm->bssid, + key_info & WPA_KEY_INFO_SECURE); + } + + + if (key_info & WPA_KEY_INFO_SECURE) { + wpa_sm_mlme_setprotection( + sm, sm->bssid, MLME_SETPROTECTION_PROTECT_TYPE_RX, + MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); + } + + sm->key_install = false; + + return 0; + +failed: + return WLAN_REASON_UNSPECIFIED; +} + + + int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm, + const u8 *keydata, + size_t keydatalen, + u16 key_info, + struct wpa_gtk_data *gd) +{ + int maxkeylen; + struct wpa_eapol_ie_parse ie; + + wpa_hexdump(MSG_DEBUG, "RSN: msg 1/2 key data", keydata, keydatalen); + wpa_supplicant_parse_ies(keydata, keydatalen, &ie); + if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: GTK IE in unencrypted key data"); + #endif + return -1; + } + if (ie.gtk == NULL) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: No GTK IE in Group Key msg 1/2"); + #endif + return -1; + } + maxkeylen = gd->gtk_len = ie.gtk_len - 2; + + if (wpa_supplicant_check_group_cipher(sm->group_cipher, + gd->gtk_len, maxkeylen, + &gd->key_rsc_len, &gd->alg)) + return -1; + + wpa_hexdump(MSG_DEBUG, "RSN: received GTK in group key handshake", + ie.gtk, ie.gtk_len); + gd->keyidx = ie.gtk[0] & 0x3; + gd->tx = wpa_supplicant_gtk_tx_bit_workaround(sm, + !!(ie.gtk[0] & BIT(2))); + if (ie.gtk_len - 2 > sizeof(gd->gtk)) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "RSN: Too long GTK in GTK IE " + "(len=%lu)", (unsigned long) ie.gtk_len - 2); + #endif + return -1; + } + memcpy(gd->gtk, ie.gtk + 2, ie.gtk_len - 2); + + if (ieee80211w_set_keys(sm, &ie) < 0) + { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "RSN: Failed to configure IGTK"); + #endif + } + return 0; +} + + int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm, + const struct wpa_eapol_key *key, + size_t keydatalen, int key_info, + size_t extra_len, u16 ver, + struct wpa_gtk_data *gd) +{ + size_t maxkeylen; + u8 ek[32]; + + gd->gtk_len = WPA_GET_BE16(key->key_length); + maxkeylen = keydatalen; + if (keydatalen > extra_len) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Truncated EAPOL-Key packet:" + " key_data_length=%lu > extra_len=%lu", + (unsigned long) keydatalen, + (unsigned long) extra_len); + #endif + return -1; + } + if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { + if (maxkeylen < 8) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Too short maxkeylen (%lu)", + (unsigned long) maxkeylen); + #endif + return -1; + } + maxkeylen -= 8; + } + + if (wpa_supplicant_check_group_cipher(sm->group_cipher, + gd->gtk_len, maxkeylen, + &gd->key_rsc_len, &gd->alg)) + return -1; + + gd->keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >> + WPA_KEY_INFO_KEY_INDEX_SHIFT; + if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { + memcpy(ek, key->key_iv, 16); + memcpy(ek + 16, sm->ptk.kek, 16); + if (keydatalen > sizeof(gd->gtk)) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: RC4 key data " + "too long (%lu)", + (unsigned long) keydatalen); + #endif + return -1; + } + memcpy(gd->gtk, key + 1, keydatalen); + if (rc4_skip(ek, 32, 256, gd->gtk, keydatalen)) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: RC4 failed"); + #endif + return -1; + } + } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { + if (keydatalen % 8) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Unsupported AES-WRAP " + "len %lu", (unsigned long) keydatalen); + #endif + return -1; + } + if (maxkeylen > sizeof(gd->gtk)) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: AES-WRAP key data " + "too long (keydatalen=%lu maxkeylen=%lu)", + (unsigned long) keydatalen, + (unsigned long) maxkeylen); + #endif + return -1; + } + if (fast_aes_unwrap(sm->ptk.kek, maxkeylen / 8, + (const u8 *) (key + 1), gd->gtk)) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: AES unwrap " + "failed - could not decrypt GTK"); + #endif + return -1; + } + } else { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Unsupported key_info type %d", + ver); + #endif + return -1; + } + gd->tx = wpa_supplicant_gtk_tx_bit_workaround( + sm, !!(key_info & WPA_KEY_INFO_TXRX)); + return 0; +} + + int wpa_supplicant_send_2_of_2(struct wpa_sm *sm, + const struct wpa_eapol_key *key, + int ver, u16 key_info) +{ + size_t rlen; + struct wpa_eapol_key *reply; + u8 *rbuf; + + rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, + sizeof(*reply), &rlen, (void *) &reply); + if (rbuf == NULL) + return -1; + + sm->txcb_flags |= WPA_GROUP_HANDSHAKE_BIT; + wpa_printf(MSG_DEBUG, "2/2 txcb_flags=%d\n", sm->txcb_flags); + + reply->type = sm->proto == WPA_PROTO_RSN ? + EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; + key_info &= WPA_KEY_INFO_KEY_INDEX_MASK; + key_info |= ver | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE; + WPA_PUT_BE16(reply->key_info, key_info); + if (sm->proto == WPA_PROTO_RSN) + WPA_PUT_BE16(reply->key_length, 0); + else + memcpy(reply->key_length, key->key_length, 2); + memcpy(reply->replay_counter, key->replay_counter, + WPA_REPLAY_COUNTER_LEN); + + WPA_PUT_BE16(reply->key_data_length, 0); + + wpa_printf(MSG_DEBUG, "WPA Send 2/2 Group key\n"); + + wpa_eapol_key_send(sm, sm->ptk.kck, ver, sm->bssid, ETH_P_EAPOL, + rbuf, rlen, reply->key_mic); + wpa_sm_free_eapol(rbuf); + + return 0; +} + + void wpa_supplicant_process_1_of_2(struct wpa_sm *sm, + const unsigned char *src_addr, + struct wpa_eapol_key *key, + int extra_len, u16 ver) +{ + u16 key_info, keydatalen; + int ret; + struct wpa_gtk_data *gd=&(sm->gd); + + memset(gd, 0, sizeof(struct wpa_gtk_data)); + + wpa_printf(MSG_DEBUG, "WPA 1/2 Group Key Handshake\n"); + + key_info = WPA_GET_BE16(key->key_info); + keydatalen = WPA_GET_BE16(key->key_data_length); + + if (sm->proto == WPA_PROTO_RSN) { + ret = wpa_supplicant_process_1_of_2_rsn(sm, + (const u8 *) (key + 1), + keydatalen, key_info, + gd); + } else { + ret = wpa_supplicant_process_1_of_2_wpa(sm, key, keydatalen, + key_info, extra_len, + ver, gd); + } + + wpa_sm_set_state(WPA_GROUP_HANDSHAKE); + + if (ret) + goto failed; + + /*before callback, set seq for add param difficult in callback*/ + wpa_sm_set_seq(sm, key, 0); + sm->key_info=key_info; + + if (wpa_supplicant_send_2_of_2(sm, key, ver, key_info)) + goto failed; + + return; + +failed: + wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); +} + + int wpa_supplicant_send_2_of_2_txcallback(struct wpa_sm *sm) +{ + u16 key_info=sm->key_info; + u16 rekey= (WPA_SM_STATE(sm) == WPA_COMPLETED); + + if((sm->gd).gtk_len) { + if (wpa_supplicant_gtk_in_use(sm, &(sm->gd)) == false) { + if (wpa_supplicant_install_gtk(sm, &(sm->gd))) + goto failed; + } + } else { + goto failed; + } + + if (rekey) { +#ifdef MSG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Group rekeying " + "completed with " MACSTR " [GTK=%s]", + MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher)); +#endif + wpa_sm_cancel_auth_timeout(sm); + wpa_sm_set_state(WPA_COMPLETED); + } else + wpa_supplicant_key_neg_complete(sm, sm->bssid, + key_info &WPA_KEY_INFO_SECURE); + return 0; + +failed: + return WLAN_REASON_UNSPECIFIED; +} + + int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm, + struct wpa_eapol_key *key, + u16 ver, + const u8 *buf, size_t len) +{ + u8 mic[16]; + int ok = 0; + + memcpy(mic, key->key_mic, 16); + if (sm->tptk_set) { + memset(key->key_mic, 0, 16); + wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len, + key->key_mic); + if (memcmp(mic, key->key_mic, 16) != 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Invalid EAPOL-Key MIC " + "when using TPTK - ignoring TPTK"); + #endif + } else { + ok = 1; + sm->tptk_set = 0; + sm->ptk_set = 1; + memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk)); + } + } + + if (!ok && sm->ptk_set) { + memset(key->key_mic, 0, 16); + wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len, + key->key_mic); + if (memcmp(mic, key->key_mic, 16) != 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Invalid EAPOL-Key MIC " + "- dropping packet"); + #endif + return -1; + } + ok = 1; + } + + if (!ok) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Could not verify EAPOL-Key MIC " + "- dropping packet"); + #endif + return -1; + } + + memcpy(sm->rx_replay_counter, key->replay_counter, + WPA_REPLAY_COUNTER_LEN); + sm->rx_replay_counter_set = 1; + /*update request_counter for mic failure report*/ + memcpy(sm->request_counter, key->replay_counter, + WPA_REPLAY_COUNTER_LEN); + return 0; +} + + +/* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */ + int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm, + struct wpa_eapol_key *key, u16 ver) +{ + u16 keydatalen = WPA_GET_BE16(key->key_data_length); + + wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data", + (u8 *) (key + 1), keydatalen); + if (!sm->ptk_set) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: PTK not available, " + "cannot decrypt EAPOL-Key key data."); + #endif + return -1; + } + + /* Decrypt key data here so that this operation does not need + * to be implemented separately for each message type. */ + if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { + u8 ek[32]; + memcpy(ek, key->key_iv, 16); + memcpy(ek + 16, sm->ptk.kek, 16); + if (rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen)) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: RC4 failed"); + #endif + return -1; + } + } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || + ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) { + u8 *buf; + if (keydatalen % 8) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Unsupported " + "AES-WRAP len %d", keydatalen); + #endif + return -1; + } + keydatalen -= 8; /* AES-WRAP adds 8 bytes */ + + /*replaced by xxx to remove malloc*/ + buf = ((u8 *) (key+1))+ 8; + /* + buf = os_wifi_malloc(keydatalen); + if (buf == NULL) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: No memory for " + "AES-UNWRAP buffer"); + #endif + return -1; + } + */ + if (fast_aes_unwrap(sm->ptk.kek, keydatalen / 8, + (u8 *) (key + 1), buf)) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: AES unwrap failed - " + "could not decrypt EAPOL-Key key data"); + #endif + return -1; + } + memcpy(key + 1, buf, keydatalen); + WPA_PUT_BE16(key->key_data_length, keydatalen); + } else { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Unsupported key_info type %d", + ver); + #endif + return -1; + } + wpa_hexdump(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data", + (u8 *) (key + 1), keydatalen); + return 0; +} + + + void wpa_eapol_key_dump(int level, const struct wpa_eapol_key *key) +{ +#ifdef DEBUG_PRINT + if (level < MSG_MSGDUMP) + return; + + u16 key_info = WPA_GET_BE16(key->key_info); + + wpa_printf(MSG_DEBUG, " EAPOL-Key type=%d\n", key->type); + wpa_printf(MSG_DEBUG, " key_info 0x%x (ver=%d keyidx=%d rsvd=%d %s" + "%s%s%s%s%s%s%s)\n", + key_info, (u32)(key_info & WPA_KEY_INFO_TYPE_MASK), + (u32)((key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >> + WPA_KEY_INFO_KEY_INDEX_SHIFT), + (u32)((key_info & (BIT(13) | BIT(14) | BIT(15))) >> 13), + key_info & WPA_KEY_INFO_KEY_TYPE ? "Pairwise" : "Group", + key_info & WPA_KEY_INFO_INSTALL ? " Install" : "", + key_info & WPA_KEY_INFO_ACK ? " Ack" : "", + key_info & WPA_KEY_INFO_MIC ? " MIC" : "", + key_info & WPA_KEY_INFO_SECURE ? " Secure" : "", + key_info & WPA_KEY_INFO_ERROR ? " Error" : "", + key_info & WPA_KEY_INFO_REQUEST ? " Request" : "", + key_info & WPA_KEY_INFO_ENCR_KEY_DATA ? " Encr" : ""); + wpa_printf(MSG_DEBUG, " key_length=%u key_data_length=%u\n", + WPA_GET_BE16(key->key_length), + WPA_GET_BE16(key->key_data_length)); +#endif +} + +/** + * wpa_sm_rx_eapol - Process received WPA EAPOL frames + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @src_addr: Source MAC address of the EAPOL packet + * @buf: Pointer to the beginning of the EAPOL data (EAPOL header) + * @len: Length of the EAPOL frame + * Returns: 1 = WPA EAPOL-Key processed, 0 = not a WPA EAPOL-Key, -1 failure + * + * This function is called for each received EAPOL frame. Other than EAPOL-Key + * frames can be skipped if filtering is done elsewhere. wpa_sm_rx_eapol() is + * only processing WPA and WPA2 EAPOL-Key frames. + * + * The received EAPOL-Key packets are validated and valid packets are replied + * to. In addition, key material (PTK, GTK) is configured at the end of a + * successful key handshake. + * buf begin from version, so remove mac header ,snap header and ether_type + */ +int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len) +{ + struct wpa_sm *sm = &gWpaSm; + u32 plen, data_len, extra_len; + struct ieee802_1x_hdr *hdr; + struct wpa_eapol_key *key; + u16 key_info, ver; + u8 *tmp; + int ret = -1; + + if (len < sizeof(*hdr) + sizeof(*key)) { +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: EAPOL frame too short to be a WPA " + "EAPOL-Key (len %lu, expecting at least %lu)", + (unsigned long) len, + (unsigned long) sizeof(*hdr) + sizeof(*key)); +#endif + return 0; + } + + tmp = buf; + + hdr = (struct ieee802_1x_hdr *) tmp; + key = (struct wpa_eapol_key *) (hdr + 1); + plen = be_to_host16(hdr->length); + data_len = plen + sizeof(*hdr); + +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "IEEE 802.1X RX: version=%d type=%d length=%d\n", + hdr->version, hdr->type, plen); +#endif + + if (hdr->version < EAPOL_VERSION) { + /* TODO: backwards compatibility */ + } + if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) { +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: EAPOL frame (type %u) discarded, " + "not a Key frame", hdr->type); +#endif + ret = 0; + goto out; + } + if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) { +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: EAPOL frame payload size %lu " + "invalid (frame size %lu)", + (unsigned long) plen, (unsigned long) len); +#endif + ret = 0; + goto out; + } + + if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN) + { +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key type (%d) unknown, " + "discarded", key->type); +#endif + ret = 0; + goto out; + } + + wpa_eapol_key_dump(MSG_MSGDUMP, key); + + wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", tmp, len); + + if (data_len < len) { +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: ignoring %lu bytes after the IEEE " + "802.1X data\n", (unsigned long) len - data_len); +#endif + } + key_info = WPA_GET_BE16(key->key_info); + ver = key_info & WPA_KEY_INFO_TYPE_MASK; + if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && + ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Unsupported EAPOL-Key descriptor " + "version %d.", ver); +#endif + goto out; + } + + if (sm->pairwise_cipher == WPA_CIPHER_CCMP && + ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: CCMP is used, but EAPOL-Key " + "descriptor version (%d) is not 2.", ver); +#endif + if (sm->group_cipher != WPA_CIPHER_CCMP && + !(key_info & WPA_KEY_INFO_KEY_TYPE)) { + /* Earlier versions of IEEE 802.11i did not explicitly + * require version 2 descriptor for all EAPOL-Key + * packets, so allow group keys to use version 1 if + * CCMP is not used for them. */ + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Backwards compatibility: " + "allow invalid version for non-CCMP group " + "keys"); + #endif + } else + goto out; + } + + + if ( sm->rx_replay_counter_set && + memcmp(key->replay_counter, sm->rx_replay_counter, + WPA_REPLAY_COUNTER_LEN) <= 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Replay Counter did not" + " increase - dropping packet"); + #endif + goto out; + } + + if (!(key_info & (WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE))) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: No Ack bit in key_info"); + #endif + goto out; + } + + if (key_info & WPA_KEY_INFO_REQUEST) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key with Request bit - dropped"); + #endif + goto out; + } + + if ((key_info & WPA_KEY_INFO_MIC) && + wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len)) + goto out; + + extra_len = data_len - sizeof(*hdr) - sizeof(*key); + + if (WPA_GET_BE16(key->key_data_length) > extra_len) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Invalid EAPOL-Key " + "frame - key_data overflow (%d > %lu)", + WPA_GET_BE16(key->key_data_length), + (unsigned long) extra_len); + #endif + goto out; + } + extra_len = WPA_GET_BE16(key->key_data_length); + + if (sm->proto == WPA_PROTO_RSN && + (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { + if (wpa_supplicant_decrypt_key_data(sm, key, ver)) + goto out; + extra_len = WPA_GET_BE16(key->key_data_length); + } + + if (key_info & WPA_KEY_INFO_KEY_TYPE) { + if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Ignored EAPOL-Key " + "(Pairwise) with non-zero key index"); + #endif + goto out; + } + + if (key_info & WPA_KEY_INFO_MIC) { + /* 3/4 4-Way Handshake */ + wpa_supplicant_process_3_of_4(sm, key, ver); + } else { + /* 1/4 4-Way Handshake */ + wpa_supplicant_process_1_of_4(sm, src_addr, key, + ver); + } + } else { + if (key_info & WPA_KEY_INFO_MIC) { + /* 1/2 Group Key Handshake */ + wpa_supplicant_process_1_of_2(sm, src_addr, key, + extra_len, ver); + } else { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key (Group) " + "without Mic bit - dropped"); + #endif + } + } + + ret = 1; + +out: + + return ret; +} + +/** + * wpa_supplicant_set_state - Set current connection state + * @wpa_s: Pointer to wpa_supplicant data + * @state: The new connection state + * + * This function is called whenever the connection state changes, e.g., + * association is completed for WPA/WPA2 4-Way Handshake is started. + */ +void wpa_sm_set_state(enum wpa_states state) +{ + struct wpa_sm *sm = &gWpaSm; + if(WPA_MIC_FAILURE==WPA_SM_STATE(sm)) + ets_timer_disarm(&(sm->cm_timer)); + sm->wpa_state= state; +} + +#ifdef ESP_SUPPLICANT +void wpa_register(char * payload, WPA_SEND_FUNC snd_func, + WPA_SET_ASSOC_IE set_assoc_ie_func, WPA_INSTALL_KEY ppinstallkey, WPA_GET_KEY ppgetkey, WPA_DEAUTH_FUNC wpa_deauth, + WPA_NEG_COMPLETE wpa_neg_complete) +{ + struct wpa_sm *sm = &gWpaSm; + + sm->eapol_version = 0x1; /* DEFAULT_EAPOL_VERSION */ + sm->sendto = snd_func; + sm->config_assoc_ie = set_assoc_ie_func; + sm->install_ppkey = ppinstallkey; + sm->get_ppkey = ppgetkey; + sm->wpa_deauthenticate = wpa_deauth; + sm->wpa_neg_complete = wpa_neg_complete; + sm->key_entry_valid = 0; + sm->key_install = false; + wpa_sm_set_state(WPA_INACTIVE); +} + +void wpa_set_profile(u32 wpa_proto, u8 auth_mode) +{ + struct wpa_sm *sm = &gWpaSm; + + sm->proto = wpa_proto; + if (auth_mode == WPA2_AUTH_ENT) + sm->key_mgmt = WPA_KEY_MGMT_IEEE8021X; /* for wpa2 enterprise */ + else + sm->key_mgmt = WPA_KEY_MGMT_PSK; /* fixed to PSK for now */ +} + +void wpa_set_pmk(uint8_t *pmk) +{ + struct wpa_sm *sm = &gWpaSm; + + memcpy(sm->pmk, pmk, PMK_LEN); + sm->pmk_len = PMK_LEN; +} + +void +wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, char *passphrase, u8 *ssid, size_t ssid_len) +{ + struct wpa_sm *sm = &gWpaSm; + + sm->pairwise_cipher = BIT(pairwise_cipher); + sm->group_cipher = BIT(group_cipher); + sm->rx_replay_counter_set = 0; //init state not intall replay counter value + memset(sm->rx_replay_counter, 0, WPA_REPLAY_COUNTER_LEN); + sm->wpa_ptk_rekey = 0; + sm->renew_snonce = 1; + memcpy(sm->own_addr, macddr, ETH_ALEN); + memcpy(sm->bssid, bssid, ETH_ALEN); + sm->ap_notify_completed_rsne = esp_wifi_sta_is_ap_notify_completed_rsne_internal(); + + set_assoc_ie(assoc_ie_buf); /* use static buffer */ + wpa_gen_wpa_ie(sm, sm->assoc_wpa_ie, sm->assoc_wpa_ie_len); //TODO: NEED TO DEBUG!! + wpa_set_passphrase(passphrase, ssid, ssid_len); +} + +/* + * Call after set ssid since we calc pmk inside this routine directly + */ + void +wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len) +{ + struct wifi_ssid *sta_ssid = esp_wifi_sta_get_prof_ssid_internal(); + struct wpa_sm *sm = &gWpaSm; + + if (passphrase == NULL) return; + + /* + * Here only handle passphrase string. Need extra step to handle 32B, 64Hex raw + * PMK. + */ + + /* This is really SLOW, so just re cacl while reset param */ + if (esp_wifi_sta_get_reset_param_internal() != 0) { + // check it's psk + if (strlen((char *)esp_wifi_sta_get_prof_password_internal()) == 64) { + hexstr2bin((char *)esp_wifi_sta_get_prof_password_internal(), esp_wifi_sta_get_prof_pmk_internal(), PMK_LEN); + } else { + pbkdf2_sha1((char *)esp_wifi_sta_get_prof_password_internal(), (char *)sta_ssid->ssid, (size_t)sta_ssid->len, + 4096, esp_wifi_sta_get_prof_pmk_internal(), PMK_LEN); + } + esp_wifi_sta_set_reset_param_internal(0); + } + + if (sm->key_mgmt == WPA_KEY_MGMT_IEEE8021X) { + /* TODO nothing */ + } else { + memcpy(sm->pmk, esp_wifi_sta_get_prof_pmk_internal(), PMK_LEN); + } + sm->pmk_len = PMK_LEN; +} + + void +set_assoc_ie(u8 * assoc_buf) +{ + struct wpa_sm *sm = &gWpaSm; + + sm->assoc_wpa_ie = assoc_buf + 2; + //wpa_ie insert OUI 4 byte before ver, but RSN have 2 bytes of RSN capability, + // so wpa_ie have two more bytes than rsn_ie + if ( sm->proto == WPA_PROTO_WPA) + sm->assoc_wpa_ie_len = ASSOC_IE_LEN; + else + sm->assoc_wpa_ie_len = ASSOC_IE_LEN - 2; + + sm->config_assoc_ie(sm->proto, assoc_buf, sm->assoc_wpa_ie_len); +} + + int +wpa_sm_set_key(struct install_key *key_sm, enum wpa_alg alg, + u8 *addr, int key_idx, int set_tx, + u8 *seq, size_t seq_len, + u8 *key, size_t key_len, + int key_entry_valid) +{ + struct wpa_sm *sm = &gWpaSm; + + /*gtk or ptk both need check countermeasures*/ + if (alg == WPA_ALG_TKIP && key_len == 32) { + /* Clear the MIC error counter when setting a new PTK. */ + key_sm->mic_errors_seen = 0; + } + + key_sm->keys_cleared = 0; + key_sm->alg = alg; + memcpy(key_sm->addr, addr, ETH_ALEN); + key_sm->key_idx = key_idx; + key_sm->set_tx = set_tx; + memcpy(key_sm->key, key, key_len); + + sm->install_ppkey(alg, addr, key_idx, set_tx, seq, seq_len, key, key_len, key_entry_valid); + return 0; +} + + int +wpa_sm_get_key(uint8_t *ifx, int *alg, u8 *addr, int *key_idx, u8 *key, size_t key_len, int key_entry_valid) +{ + struct wpa_sm *sm = &gWpaSm; + return sm->get_ppkey(ifx, alg, addr, key_idx, key, key_len, key_entry_valid); +} + +void wpa_supplicant_clr_countermeasures(u16 *pisunicast) +{ + struct wpa_sm *sm = &gWpaSm; + (sm->install_ptk).mic_errors_seen=0; + (sm->install_gtk).mic_errors_seen=0; + ets_timer_done(&(sm->cm_timer)); + wpa_printf(MSG_DEBUG, "WPA: TKIP countermeasures clean\n"); +} + +/*recovery from countermeasures state, countermeasures state is period that stop connection with ap + also used in wpa_init after connecting with ap +*/ +void wpa_supplicant_stop_countermeasures(u16 *pisunicast) +{ + struct wpa_sm *sm = &gWpaSm; + + ets_timer_done(&(sm->cm_timer)); + if (sm->countermeasures) { + sm->countermeasures = 0; + wpa_supplicant_clr_countermeasures(NULL); + + wpa_printf(MSG_DEBUG, "WPA: TKIP countermeasures stopped\n"); + /*renew scan preocess, this isn't done now*/ + } + wpa_sm_set_state(WPA_DISCONNECTED); +} + +int wpa_michael_mic_failure(u16 isunicast) +{ + struct wpa_sm *sm = &gWpaSm; + int32_t *pmic_errors_seen=(isunicast)? &((sm->install_ptk).mic_errors_seen) : &((sm->install_gtk).mic_errors_seen); + + wpa_printf(MSG_DEBUG, "\nTKIP MIC failure occur\n"); + + /*both unicast and multicast mic_errors_seen need statistics*/ + if ((sm->install_ptk).mic_errors_seen + (sm->install_gtk).mic_errors_seen) { + /* Send the new MIC error report immediately since we are going + * to start countermeasures and AP better do the same. + */ + wpa_sm_set_state(WPA_TKIP_COUNTERMEASURES); + wpa_sm_key_request(sm, 1, 0); + + /* initialize countermeasures */ + sm->countermeasures = 1; + wpa_printf(MSG_DEBUG, "TKIP countermeasures started\n"); + + /* + * Need to wait for completion of request frame. We do not get + * any callback for the message completion, so just wait a + * short while and hope for the best. */ + ets_delay_us(10000); + + /*deauthenticate AP*/ + + /*stop monitor next mic_failure timer,disconnect for 60sec, then stop contermeasures*/ + ets_timer_disarm(&(sm->cm_timer)); + ets_timer_done(&(sm->cm_timer)); + ets_timer_setfn(&(sm->cm_timer), (ETSTimerFunc *)wpa_supplicant_stop_countermeasures, NULL); + ets_timer_arm(&(sm->cm_timer), 60*1000, false); + + /* TODO: mark the AP rejected for 60 second. STA is + * allowed to associate with another AP.. */ + } else { + *pmic_errors_seen=(*pmic_errors_seen)+1; + wpa_sm_set_state(WPA_MIC_FAILURE); + wpa_sm_key_request(sm, 1, 0); + /*start 60sec counter to monitor whether next mic_failure occur in this period, or clear mic_errors_seen*/ + ets_timer_disarm(&(sm->cm_timer)); + ets_timer_done(&(sm->cm_timer)); + ets_timer_setfn(&(sm->cm_timer), (ETSTimerFunc *)wpa_supplicant_clr_countermeasures, NULL); + ets_timer_arm(&(sm->cm_timer), 60*1000, false); + } + + return 0; +} + +/* + eapol tx callback function to make sure new key + install after 4-way handoff +*/ +void eapol_txcb(void *eb) +{ + struct wpa_sm *sm = &gWpaSm; + u8 isdeauth = 0; //no_zero value is the reason for deauth + + if (false == esp_wifi_sta_is_running_internal()){ + return; + } + + switch(WPA_SM_STATE(sm)) { + case WPA_FIRST_HALF_4WAY_HANDSHAKE: + break; + case WPA_LAST_HALF_4WAY_HANDSHAKE: + if (sm->txcb_flags & WPA_4_4_HANDSHAKE_BIT) { + sm->txcb_flags &= ~WPA_4_4_HANDSHAKE_BIT; + isdeauth = wpa_supplicant_send_4_of_4_txcallback(sm); + } else { + wpa_printf(MSG_DEBUG, "4/4 txcb, flags=%d\n", sm->txcb_flags); + } + break; + case WPA_GROUP_HANDSHAKE: + if (sm->txcb_flags & WPA_GROUP_HANDSHAKE_BIT) { + sm->txcb_flags &= ~WPA_GROUP_HANDSHAKE_BIT; + isdeauth = wpa_supplicant_send_2_of_2_txcallback(sm); + } else { + wpa_printf(MSG_DEBUG, "2/2 txcb, flags=%d\n", sm->txcb_flags); + } + break; + case WPA_TKIP_COUNTERMEASURES: isdeauth=WLAN_REASON_MICHAEL_MIC_FAILURE; + break; + default: break; + } + + if(isdeauth) { + wpa_sm_deauthenticate(sm, isdeauth); + } +} + +bool wpa_sta_in_4way_handshake(void) +{ + struct wpa_sm *sm = &gWpaSm; + if ( WPA_SM_STATE(sm) == WPA_MIC_FAILURE || WPA_SM_STATE(sm) == WPA_FIRST_HALF_4WAY_HANDSHAKE + || WPA_SM_STATE(sm) == WPA_LAST_HALF_4WAY_HANDSHAKE) { + return true; + } + return false; +} + +#endif // ESP_SUPPLICANT + diff --git a/components/wpa_supplicant/include/wpa/wpa_i.h b/components/wpa_supplicant/src/rsn_supp/wpa.h similarity index 60% rename from components/wpa_supplicant/include/wpa/wpa_i.h rename to components/wpa_supplicant/src/rsn_supp/wpa.h index a43c33d332..c3475eafee 100644 --- a/components/wpa_supplicant/include/wpa/wpa_i.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa.h @@ -1,6 +1,6 @@ /* - * Internal WPA/RSN supplicant state machine definitions - * Copyright (c) 2004-2010, Jouni Malinen + * wpa_supplicant - WPA definitions + * Copyright (c) 2003-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -12,8 +12,31 @@ * See README and COPYING for more details. */ -#ifndef WPA_I_H -#define WPA_I_H +#ifndef WPA_H +#define WPA_H + +#include "esp32/rom/ets_sys.h" +#include "utils/common.h" +#include "common/defs.h" +#include "common/wpa_common.h" +#include "esp_wifi_crypto_types.h" +#include "wpa_i.h" + + +#define WPA_SM_STATE(_sm) ((_sm)->wpa_state) + +struct wpa_sm; + +int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len); +bool wpa_sta_in_4way_handshake(void); + +#define WPA_ASSERT assert + +struct l2_ethhdr { + u8 h_dest[ETH_ALEN]; + u8 h_source[ETH_ALEN]; + be16 h_proto; +} STRUCT_PACKED; /** * set_key - Configure encryption key @@ -60,30 +83,43 @@ * example on how this can be done. */ -typedef void (* WPA_SEND_FUNC)(struct pbuf *pb); -typedef void (* WPA_SET_ASSOC_IE)(uint8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len); +/** + * send_eapol - Optional function for sending EAPOL packets + * @priv: private driver interface data + * @dest: Destination MAC address + * @proto: Ethertype + * @data: EAPOL packet starting with IEEE 802.1X header + * @data_len: Size of the EAPOL packet + * + * Returns: 0 on success, -1 on failure + * + * This optional function can be used to override l2_packet operations + * with driver specific functionality. If this function pointer is set, + * l2_packet module is not used at all and the driver interface code is + * responsible for receiving and sending all EAPOL packets. The + * received EAPOL packets are sent to core code with EVENT_EAPOL_RX + * event. The driver interface is required to implement get_mac_addr() + * handler if send_eapol() is used. + */ -typedef void (*WPA_INSTALL_KEY) (enum wpa_alg alg, uint8 *addr, int key_idx, int set_tx, - uint8 *seq, size_t seq_len, uint8 *key, size_t key_len, int key_entry_valid); +#define KEYENTRY_TABLE_MAP(key_entry_valid) ((key_entry_valid)%5) -typedef void (*WPA_DEAUTH)(uint8 reason_code); +void pp_michael_mic_failure(u16 isunicast); -typedef void (*WPA_NEG_COMPLETE)(); +void wpa_sm_set_state(enum wpa_states state); -void wpa_register(char * payload, WPA_SEND_FUNC snd_func, \ - WPA_SET_ASSOC_IE set_assoc_ie_func, \ - WPA_INSTALL_KEY ppinstallkey, \ - WPA_DEAUTH wpa_deauth, \ - WPA_NEG_COMPLETE wpa_neg_complete); +char * dup_binstr(const void *src, size_t len); -#include "pp/esf_buf.h" -void eapol_txcb(esf_buf_t *eb); +void wpa_set_pmk(uint8_t *pmk); -void wpa_set_profile(uint32 wpa_proto); +int wpa_hook_init(void); -void wpa_set_bss(char *macddr, char * bssid, uint8 pairwise_cipher, uint8 group_cipher, char *passphrase, u8 *ssid, size_t ssid_len); +bool wpa_hook_deinit(void); -int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len); -#endif /* WPA_I_H */ +char * dup_binstr(const void *src, size_t len); + +int wpa_michael_mic_failure(u16 isunicast); + +#endif /* WPA_H */ diff --git a/components/wpa_supplicant/include/wpa/wpa.h b/components/wpa_supplicant/src/rsn_supp/wpa_i.h similarity index 72% rename from components/wpa_supplicant/include/wpa/wpa.h rename to components/wpa_supplicant/src/rsn_supp/wpa_i.h index 14ed2175af..3a09eff1d2 100644 --- a/components/wpa_supplicant/include/wpa/wpa.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa_i.h @@ -1,6 +1,6 @@ /* - * wpa_supplicant - WPA definitions - * Copyright (c) 2003-2007, Jouni Malinen + * Internal WPA/RSN supplicant state machine definitions + * Copyright (c) 2004-2010, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -12,22 +12,8 @@ * See README and COPYING for more details. */ -#ifndef WPA_H -#define WPA_H - -#include "esp32/rom/ets_sys.h" -#include "common.h" -#include "wpa/defs.h" -#include "wpa/wpa_common.h" - - -#define WPA_SM_STATE(_sm) ((_sm)->wpa_state) - -struct wpa_sm; - -int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len); - -#define WPA_ASSERT ASSERT +#ifndef WPA_I_H +#define WPA_I_H struct install_key { int mic_errors_seen; /* Michael MIC errors with the current PTK */ @@ -82,28 +68,26 @@ struct wpa_sm { u8 *ap_wpa_ie, *ap_rsn_ie; size_t ap_wpa_ie_len, ap_rsn_ie_len; + bool key_install; + struct install_key install_ptk; struct install_key install_gtk; int key_entry_valid; //present current avaliable entry for bssid, for pairkey:0,5,10,15,20, gtk: pairkey_no+i (i:1~4) - struct pbuf *pb; - - void (* sendto) (struct pbuf *pb); + void (* sendto) (void *buffer, uint16_t len); void (*config_assoc_ie) (u8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len); void (*install_ppkey) (enum wpa_alg alg, u8 *addr, int key_idx, int set_tx, u8 *seq, unsigned int seq_len, u8 *key, unsigned int key_len, int key_entry_valid); + int (*get_ppkey) (uint8_t *ifx, int *alg, uint8_t *addr, int *key_idx, + uint8_t *key, size_t key_len, int key_entry_valid); void (*wpa_deauthenticate)(u8 reason_code); void (*wpa_neg_complete)(); struct wpa_gtk_data gd; //used for calllback save param - u16 key_info; //used for txcallback param + u16 key_info; //used for txcallback param + u16 txcb_flags; + bool ap_notify_completed_rsne; }; -struct l2_ethhdr { - u8 h_dest[ETH_ALEN]; - u8 h_source[ETH_ALEN]; - be16 h_proto; -} STRUCT_PACKED; - /** * set_key - Configure encryption key * @ifname: Interface name (for multi-SSID/VLAN support) @@ -150,30 +134,32 @@ struct l2_ethhdr { */ -/** - * send_eapol - Optional function for sending EAPOL packets - * @priv: private driver interface data - * @dest: Destination MAC address - * @proto: Ethertype - * @data: EAPOL packet starting with IEEE 802.1X header - * @data_len: Size of the EAPOL packet - * - * Returns: 0 on success, -1 on failure - * - * This optional function can be used to override l2_packet operations - * with driver specific functionality. If this function pointer is set, - * l2_packet module is not used at all and the driver interface code is - * responsible for receiving and sending all EAPOL packets. The - * received EAPOL packets are sent to core code with EVENT_EAPOL_RX - * event. The driver interface is required to implement get_mac_addr() - * handler if send_eapol() is used. - */ +typedef void (* WPA_SEND_FUNC)(void *buffer, u16 len); -#define KEYENTRY_TABLE_MAP(key_entry_valid) ((key_entry_valid)%5) +typedef void (* WPA_SET_ASSOC_IE)(u8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len); -void wpa_sm_set_state(enum wpa_states state); +typedef void (*WPA_INSTALL_KEY) (enum wpa_alg alg, u8 *addr, int key_idx, int set_tx, + u8 *seq, size_t seq_len, u8 *key, size_t key_len, int key_entry_valid); -char * dup_binstr(const void *src, size_t len); +typedef int (*WPA_GET_KEY) (u8 *ifx, int *alg, u8 *addt, int *keyidx, u8 *key, size_t key_len, int key_entry_valid); -#endif /* WPA_H */ +typedef void (*WPA_DEAUTH_FUNC)(u8 reason_code); + +typedef void (*WPA_NEG_COMPLETE)(); + +void wpa_register(char * payload, WPA_SEND_FUNC snd_func, \ + WPA_SET_ASSOC_IE set_assoc_ie_func, \ + WPA_INSTALL_KEY ppinstallkey, \ + WPA_GET_KEY ppgetkey, \ + WPA_DEAUTH_FUNC wpa_deauth, \ + WPA_NEG_COMPLETE wpa_neg_complete); + +void eapol_txcb(void *eb); + +void wpa_set_profile(u32 wpa_proto, u8 auth_mode); + +void wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, char *passphrase, u8 *ssid, size_t ssid_len); + +int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len); +#endif /* WPA_I_H */ diff --git a/components/wpa_supplicant/src/rsn_supp/wpa_ie.c b/components/wpa_supplicant/src/rsn_supp/wpa_ie.c new file mode 100644 index 0000000000..ce85191c7c --- /dev/null +++ b/components/wpa_supplicant/src/rsn_supp/wpa_ie.c @@ -0,0 +1,371 @@ +/* + * wpa_supplicant - WPA/RSN IE and KDE processing + * Copyright (c) 2003-2008, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + #ifdef ESP_SUPPLICANT + +#include "utils/includes.h" + +#include "utils/common.h" +#include "rsn_supp/wpa.h" +#include "common/ieee802_11_defs.h" +#include "rsn_supp/wpa_ie.h" + +/** + * wpa_parse_wpa_ie - Parse WPA/RSN IE + * @wpa_ie: Pointer to WPA or RSN IE + * @wpa_ie_len: Length of the WPA/RSN IE + * @data: Pointer to data area for parsing results + * Returns: 0 on success, -1 on failure + * + * Parse the contents of WPA or RSN IE and write the parsed data into data. + */ +int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, + struct wpa_ie_data *data) +{ + if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN) + return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); + else + return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data); +} + +/** + * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs + * @pos: Pointer to the IE header + * @end: Pointer to the end of the Key Data buffer + * @ie: Pointer to parsed IE data + * Returns: 0 on success, 1 if end mark is found, -1 on failure + */ +static int wpa_parse_generic(const u8 *pos, const u8 *end, + struct wpa_eapol_ie_parse *ie) +{ + if (pos[1] == 0) + return 1; + + if (pos[1] >= 6 && + RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE && + pos[2 + WPA_SELECTOR_LEN] == 1 && + pos[2 + WPA_SELECTOR_LEN + 1] == 0) { + ie->wpa_ie = pos; + ie->wpa_ie_len = pos[1] + 2; + wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key", + ie->wpa_ie, ie->wpa_ie_len); + return 0; + } + + if (pos + 1 + RSN_SELECTOR_LEN < end && + pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && + RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { + ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; + wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", + pos, pos[1] + 2); + return 0; + } + + if (pos[1] > RSN_SELECTOR_LEN + 2 && + RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { + ie->gtk = pos + 2 + RSN_SELECTOR_LEN; + ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; + wpa_hexdump(MSG_DEBUG, "WPA: GTK in EAPOL-Key", + pos, pos[1] + 2); + return 0; + } + + if (pos[1] > RSN_SELECTOR_LEN + 2 && + RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) { + ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN; + ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN; + wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key", + pos, pos[1] + 2); + return 0; + } + return 0; +} + + +/** + * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs + * @buf: Pointer to the Key Data buffer + * @len: Key Data Length + * @ie: Pointer to parsed IE data + * Returns: 0 on success, -1 on failure + */ +int wpa_supplicant_parse_ies(const u8 *buf, size_t len, + struct wpa_eapol_ie_parse *ie) +{ + const u8 *pos, *end; + int ret = 0; + + memset(ie, 0, sizeof(*ie)); + for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { + if (pos[0] == 0xdd && + ((pos == buf + len - 1) || pos[1] == 0)) { + /* Ignore padding */ + break; + } + if (pos + 2 + pos[1] > end) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data " + "underflow (ie=%d len=%d pos=%d)", + pos[0], pos[1], (int) (pos - buf)); + #endif + wpa_hexdump(MSG_DEBUG, "WPA: Key Data", + buf, len); + ret = -1; + break; + } + if (*pos == WLAN_EID_RSN) { + ie->rsn_ie = pos; + ie->rsn_ie_len = pos[1] + 2; + wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key", + ie->rsn_ie, ie->rsn_ie_len); + } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { + ret = wpa_parse_generic(pos, end, ie); + if (ret < 0) + break; + if (ret > 0) { + ret = 0; + break; + } + } else { + wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " + "Key Data IE", pos, 2 + pos[1]); + } + } + + return ret; +} + + +static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len, + int pairwise_cipher, int group_cipher, + int key_mgmt) +{ + u8 *pos; + struct wpa_ie_hdr *hdr; + + if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN + + 2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN) + return -1; + + hdr = (struct wpa_ie_hdr *) wpa_ie; + hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC; + RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE); + WPA_PUT_LE16(hdr->version, WPA_VERSION); + pos = (u8 *) (hdr + 1); + + if (group_cipher == WPA_CIPHER_CCMP) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); + } else if (group_cipher == WPA_CIPHER_TKIP) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); + } else if (group_cipher == WPA_CIPHER_WEP104) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104); + } else if (group_cipher == WPA_CIPHER_WEP40) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40); + } else { + wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", + group_cipher); + return -1; + } + pos += WPA_SELECTOR_LEN; + + *pos++ = 1; + *pos++ = 0; + if (pairwise_cipher == WPA_CIPHER_CCMP) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); + } else if (pairwise_cipher == WPA_CIPHER_TKIP) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); + } else if (pairwise_cipher == WPA_CIPHER_NONE) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE); + } else { + wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", + pairwise_cipher); + return -1; + } + pos += WPA_SELECTOR_LEN; + + *pos++ = 1; + *pos++ = 0; + if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { + RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); + } else if (key_mgmt == WPA_KEY_MGMT_PSK) { + RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); + } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) { + RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE); + } else { + wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", + key_mgmt); + return -1; + } + pos += WPA_SELECTOR_LEN; + + /* WPA Capabilities; use defaults, so no need to include it */ + + hdr->len = (pos - wpa_ie) - 2; + + WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); + + return pos - wpa_ie; +} + + +static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, + int pairwise_cipher, int group_cipher, + int key_mgmt, int mgmt_group_cipher, + struct wpa_sm *sm) +{ +#ifndef CONFIG_NO_WPA2 + u8 *pos; + struct rsn_ie_hdr *hdr; + u16 capab; + u8 min_len = 0; + + + /* For WPA2-PSK, if the RSNE in AP beacon/probe response doesn't specify the + * pairwise cipher or AKM suite, the RSNE IE in association request + * should only contain group cihpher suite, otherwise the WPA2 improvements + * certification will fail. + */ + if ( (sm->ap_notify_completed_rsne == true) || (key_mgmt == WPA_KEY_MGMT_IEEE8021X) ) { + min_len = sizeof(*hdr) + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2; + } else { + min_len = sizeof(*hdr) + RSN_SELECTOR_LEN; + } + + if (rsn_ie_len < min_len) { + wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)", (unsigned long) rsn_ie_len); + } + + hdr = (struct rsn_ie_hdr *) rsn_ie; + hdr->elem_id = WLAN_EID_RSN; + WPA_PUT_LE16(hdr->version, RSN_VERSION); + pos = (u8 *) (hdr + 1); + + if (group_cipher == WPA_CIPHER_CCMP) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); + } else if (group_cipher == WPA_CIPHER_TKIP) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); + } else if (group_cipher == WPA_CIPHER_WEP104) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104); + } else if (group_cipher == WPA_CIPHER_WEP40) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40); + } else { + wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", + group_cipher); + return -1; + } + pos += RSN_SELECTOR_LEN; + + if ( (sm->ap_notify_completed_rsne == false) && (key_mgmt != WPA_KEY_MGMT_IEEE8021X) ) { + hdr->len = (pos - rsn_ie) - 2; + return (pos - rsn_ie); + } + + *pos++ = 1; + *pos++ = 0; + if (pairwise_cipher == WPA_CIPHER_CCMP) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); + } else if (pairwise_cipher == WPA_CIPHER_TKIP) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); + } else if (pairwise_cipher == WPA_CIPHER_NONE) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE); + } else { + wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", + pairwise_cipher); + return -1; + } + pos += RSN_SELECTOR_LEN; + + *pos++ = 1; + *pos++ = 0; + if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); + } else if (key_mgmt == WPA_KEY_MGMT_PSK) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); +#ifdef CONFIG_IEEE80211R + } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); + } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); +#endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_IEEE80211W + } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); + } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); +#endif /* CONFIG_IEEE80211W */ + } else { + wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", + key_mgmt); + return -1; + } + pos += RSN_SELECTOR_LEN; + + /* RSN Capabilities */ + capab = 0; +#ifdef CONFIG_IEEE80211W + if (sm->mfp) + capab |= WPA_CAPABILITY_MFPC; + if (sm->mfp == 2) + capab |= WPA_CAPABILITY_MFPR; +#endif /* CONFIG_IEEE80211W */ + WPA_PUT_LE16(pos, capab); + pos += 2; + +#ifdef CONFIG_IEEE80211W + if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { + if (!sm->cur_pmksa) { + /* PMKID Count */ + WPA_PUT_LE16(pos, 0); + pos += 2; + } + + /* Management Group Cipher Suite */ + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); + pos += RSN_SELECTOR_LEN; + } +#endif /* CONFIG_IEEE80211W */ + + hdr->len = (pos - rsn_ie) - 2; + + WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len); + + return pos - rsn_ie; +#else /* CONFIG_NO_WPA2 */ + return -1; +#endif /* CONFIG_NO_WPA2 */ +} + + +/** + * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE + * @wpa_ie_len: Maximum length of the generated WPA/RSN IE + * Returns: Length of the generated WPA/RSN IE or -1 on failure + */ +int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len) +{ + if (sm->proto == WPA_PROTO_RSN) + return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len, + sm->pairwise_cipher, + sm->group_cipher, + sm->key_mgmt, sm->mgmt_group_cipher, + sm); + else + return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len, + sm->pairwise_cipher, + sm->group_cipher, + sm->key_mgmt); +} +#endif // ESP_SUPPLICANT + diff --git a/components/wpa_supplicant/include/wpa/wpa_ie.h b/components/wpa_supplicant/src/rsn_supp/wpa_ie.h similarity index 93% rename from components/wpa_supplicant/include/wpa/wpa_ie.h rename to components/wpa_supplicant/src/rsn_supp/wpa_ie.h index 94518d8457..c71a926f2b 100644 --- a/components/wpa_supplicant/include/wpa/wpa_ie.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa_ie.h @@ -53,4 +53,7 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie); int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len); +int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, + struct wpa_ie_data *data); + #endif /* WPA_IE_H */ diff --git a/components/wpa_supplicant/src/wpa2/tls/asn1.c b/components/wpa_supplicant/src/tls/asn1.c similarity index 98% rename from components/wpa_supplicant/src/wpa2/tls/asn1.c rename to components/wpa_supplicant/src/tls/asn1.c index ced8018464..5023ec1db4 100644 --- a/components/wpa_supplicant/src/wpa2/tls/asn1.c +++ b/components/wpa_supplicant/src/tls/asn1.c @@ -6,10 +6,10 @@ * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" -#include "wpa2/tls/asn1.h" +#include "utils/common.h" +#include "tls/asn1.h" int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr) { diff --git a/components/wpa_supplicant/include/wpa2/tls/asn1.h b/components/wpa_supplicant/src/tls/asn1.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/tls/asn1.h rename to components/wpa_supplicant/src/tls/asn1.h diff --git a/components/wpa_supplicant/src/wpa2/tls/bignum.c b/components/wpa_supplicant/src/tls/bignum.c similarity index 97% rename from components/wpa_supplicant/src/wpa2/tls/bignum.c rename to components/wpa_supplicant/src/tls/bignum.c index aef8f953b3..2e1ea8e282 100644 --- a/components/wpa_supplicant/src/wpa2/tls/bignum.c +++ b/components/wpa_supplicant/src/tls/bignum.c @@ -12,15 +12,15 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" -#include "crypto/common.h" -#include "wpa/wpabuf.h" -#include "wpa/wpa_debug.h" -#include "wpa2/tls/bignum.h" +#include "utils/includes.h" +#include "utils/common.h" +#include "utils/wpabuf.h" +#include "utils/wpa_debug.h" +#include "tls/bignum.h" #define CONFIG_INTERNAL_LIBTOMMATH #ifdef CONFIG_INTERNAL_LIBTOMMATH -#include "wpa2/tls/libtommath.h" +#include "tls/libtommath.h" #else /* CONFIG_INTERNAL_LIBTOMMATH */ #include #endif /* CONFIG_INTERNAL_LIBTOMMATH */ diff --git a/components/wpa_supplicant/include/wpa2/tls/bignum.h b/components/wpa_supplicant/src/tls/bignum.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/tls/bignum.h rename to components/wpa_supplicant/src/tls/bignum.h diff --git a/components/wpa_supplicant/include/wpa2/tls/libtommath.h b/components/wpa_supplicant/src/tls/libtommath.h similarity index 99% rename from components/wpa_supplicant/include/wpa2/tls/libtommath.h rename to components/wpa_supplicant/src/tls/libtommath.h index 9be311e86a..07574de7fc 100644 --- a/components/wpa_supplicant/include/wpa2/tls/libtommath.h +++ b/components/wpa_supplicant/src/tls/libtommath.h @@ -16,10 +16,6 @@ #include "os.h" #include "stdarg.h" -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - #ifndef CHAR_BIT #define CHAR_BIT 8 #endif diff --git a/components/wpa_supplicant/src/wpa2/tls/pkcs1.c b/components/wpa_supplicant/src/tls/pkcs1.c similarity index 97% rename from components/wpa_supplicant/src/wpa2/tls/pkcs1.c rename to components/wpa_supplicant/src/tls/pkcs1.c index 6266806bc1..51f5f0312d 100644 --- a/components/wpa_supplicant/src/wpa2/tls/pkcs1.c +++ b/components/wpa_supplicant/src/tls/pkcs1.c @@ -6,11 +6,11 @@ * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" -#include "wpa2/tls/rsa.h" -#include "wpa2/tls/pkcs1.h" +#include "utils/common.h" +#include "tls/rsa.h" +#include "tls/pkcs1.h" static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen, diff --git a/components/wpa_supplicant/include/wpa2/tls/pkcs1.h b/components/wpa_supplicant/src/tls/pkcs1.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/tls/pkcs1.h rename to components/wpa_supplicant/src/tls/pkcs1.h diff --git a/components/wpa_supplicant/src/wpa2/tls/pkcs5.c b/components/wpa_supplicant/src/tls/pkcs5.c similarity index 79% rename from components/wpa_supplicant/src/wpa2/tls/pkcs5.c rename to components/wpa_supplicant/src/tls/pkcs5.c index 0a0ac9e3f6..734a033681 100644 --- a/components/wpa_supplicant/src/wpa2/tls/pkcs5.c +++ b/components/wpa_supplicant/src/tls/pkcs5.c @@ -6,15 +6,15 @@ * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/crypto.h" #include "crypto/md5.h" -#include "wpa2/tls/asn1.h" -#include "wpa2/tls/pkcs5.h" +#include "tls/asn1.h" +#include "tls/pkcs5.h" -#include "wpa2/eap_peer/eap_i.h" +#include "eap_peer/eap_i.h" struct pkcs5_params { enum pkcs5_alg { @@ -165,12 +165,8 @@ static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params, wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES key", hash, 8); wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES IV", hash + 8, 8); - if (wpa2_crypto_funcs.crypto_cipher_init) { - return wpa2_crypto_funcs.crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register crypto_cipher_init function! \r\n", __FUNCTION__); - return NULL; - } + return fast_crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8); + } u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len, @@ -198,46 +194,24 @@ u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len, if (enc_data_len < 16 || enc_data_len % 8) { wpa_printf(MSG_INFO, "PKCS #5: invalid length of ciphertext " "%d", (int) enc_data_len); - if (wpa2_crypto_funcs.crypto_cipher_deinit) { - wpa2_crypto_funcs.crypto_cipher_deinit(ctx); - } else { - wpa_printf(MSG_ERROR, "Fail to register crypto cipher deinit function!\r\n"); - return NULL; - } + fast_crypto_cipher_deinit(ctx); return NULL; } eb = os_malloc(enc_data_len); if (eb == NULL) { - if (wpa2_crypto_funcs.crypto_cipher_deinit) { - wpa2_crypto_funcs.crypto_cipher_deinit(ctx); - } else { - wpa_printf(MSG_ERROR, "Fail to register crypto cipher deinit function!\r\n"); - return NULL; - } + fast_crypto_cipher_deinit(ctx); return NULL; } - if (wpa2_crypto_funcs.crypto_cipher_decrypt) { - if ((int)wpa2_crypto_funcs.crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) { - wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB"); - wpa2_crypto_funcs.crypto_cipher_deinit(ctx); - os_free(eb); - return NULL; - } - } else { - wpa_printf(MSG_ERROR, "Fail to register crypto cipher decrypt function.\r\n"); - wpa2_crypto_funcs.crypto_cipher_deinit(ctx); + if ((int)fast_crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) { + wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB"); + fast_crypto_cipher_deinit(ctx); os_free(eb); return NULL; } - if (wpa2_crypto_funcs.crypto_cipher_deinit) { - wpa2_crypto_funcs.crypto_cipher_deinit(ctx); - } else { - wpa_printf(MSG_ERROR, "Fail to register crypto cipher deinit function!\r\n"); - return NULL; - } + fast_crypto_cipher_deinit(ctx); pad = eb[enc_data_len - 1]; if (pad > 8) { diff --git a/components/wpa_supplicant/include/wpa2/tls/pkcs5.h b/components/wpa_supplicant/src/tls/pkcs5.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/tls/pkcs5.h rename to components/wpa_supplicant/src/tls/pkcs5.h diff --git a/components/wpa_supplicant/src/wpa2/tls/pkcs8.c b/components/wpa_supplicant/src/tls/pkcs8.c similarity index 96% rename from components/wpa_supplicant/src/wpa2/tls/pkcs8.c rename to components/wpa_supplicant/src/tls/pkcs8.c index 0f39c4558e..6e012437b1 100644 --- a/components/wpa_supplicant/src/wpa2/tls/pkcs8.c +++ b/components/wpa_supplicant/src/tls/pkcs8.c @@ -6,14 +6,14 @@ * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" -#include "wpa2/tls/asn1.h" -#include "wpa2/tls/bignum.h" -#include "wpa2/tls/rsa.h" -#include "wpa2/tls/pkcs5.h" -#include "wpa2/tls/pkcs8.h" +#include "utils/common.h" +#include "tls/asn1.h" +#include "tls/bignum.h" +#include "tls/rsa.h" +#include "tls/pkcs5.h" +#include "tls/pkcs8.h" struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len) { diff --git a/components/wpa_supplicant/include/wpa2/tls/pkcs8.h b/components/wpa_supplicant/src/tls/pkcs8.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/tls/pkcs8.h rename to components/wpa_supplicant/src/tls/pkcs8.h diff --git a/components/wpa_supplicant/src/wpa2/tls/rsa.c b/components/wpa_supplicant/src/tls/rsa.c similarity index 98% rename from components/wpa_supplicant/src/wpa2/tls/rsa.c rename to components/wpa_supplicant/src/tls/rsa.c index 2afc8769f2..e1eff7f097 100644 --- a/components/wpa_supplicant/src/wpa2/tls/rsa.c +++ b/components/wpa_supplicant/src/tls/rsa.c @@ -6,12 +6,12 @@ * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" -#include "wpa2/tls/asn1.h" -#include "wpa2/tls/bignum.h" -#include "wpa2/tls/rsa.h" +#include "utils/common.h" +#include "tls/asn1.h" +#include "tls/bignum.h" +#include "tls/rsa.h" struct crypto_rsa_key { int private_key; /* whether private key is set */ diff --git a/components/wpa_supplicant/include/wpa2/tls/rsa.h b/components/wpa_supplicant/src/tls/rsa.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/tls/rsa.h rename to components/wpa_supplicant/src/tls/rsa.h diff --git a/components/wpa_supplicant/include/wpa2/tls/tls.h b/components/wpa_supplicant/src/tls/tls.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/tls/tls.h rename to components/wpa_supplicant/src/tls/tls.h diff --git a/components/wpa_supplicant/src/wpa2/tls/tls_internal.c b/components/wpa_supplicant/src/tls/tls_internal.c similarity index 98% rename from components/wpa_supplicant/src/wpa2/tls/tls_internal.c rename to components/wpa_supplicant/src/tls/tls_internal.c index 682d457c58..65e08b8fa9 100644 --- a/components/wpa_supplicant/src/wpa2/tls/tls_internal.c +++ b/components/wpa_supplicant/src/tls/tls_internal.c @@ -9,14 +9,14 @@ * integrated TLSv1 implementation. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/sha1.h" #include "crypto/md5.h" -#include "wpa2/tls/tls.h" -#include "wpa2/tls/tlsv1_client.h" -#include "wpa2/tls/tlsv1_server.h" +#include "tls/tls.h" +#include "tls/tlsv1_client.h" +#include "tls/tlsv1_server.h" #ifndef CONFIG_TLS_INTERNAL_CLIENT #define CONFIG_TLS_INTERNAL_CLIENT @@ -204,7 +204,6 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, tlsv1_client_set_time_checks( conn->client, !(params->flags & TLS_CONN_DISABLE_TIME_CHECKS)); - //conn->client, !(TLS_CONN_DISABLE_TIME_CHECKS)); //snake return 0; #else /* CONFIG_TLS_INTERNAL_CLIENT */ diff --git a/components/wpa_supplicant/src/wpa2/tls/tlsv1_client.c b/components/wpa_supplicant/src/tls/tlsv1_client.c similarity index 99% rename from components/wpa_supplicant/src/wpa2/tls/tlsv1_client.c rename to components/wpa_supplicant/src/tls/tlsv1_client.c index 62753b3b5e..6780f54dc1 100644 --- a/components/wpa_supplicant/src/wpa2/tls/tlsv1_client.c +++ b/components/wpa_supplicant/src/tls/tlsv1_client.c @@ -6,15 +6,15 @@ * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/sha1.h" -#include "wpa2/tls/tls.h" -#include "wpa2/tls/tlsv1_common.h" -#include "wpa2/tls/tlsv1_record.h" -#include "wpa2/tls/tlsv1_client.h" -#include "wpa2/tls/tlsv1_client_i.h" +#include "tls/tls.h" +#include "tls/tlsv1_common.h" +#include "tls/tlsv1_record.h" +#include "tls/tlsv1_client.h" +#include "tls/tlsv1_client_i.h" /* TODO: * Support for a message fragmented across several records (RFC 2246, 6.2.1) @@ -465,7 +465,7 @@ struct tlsv1_client * tlsv1_client_init(void) suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA; #ifdef CONFIG_DES3 suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA; -#endif +#endif //CONFIG_DES3 suites[count++] = TLS_RSA_WITH_RC4_128_SHA; suites[count++] = TLS_RSA_WITH_RC4_128_MD5; conn->num_cipher_suites = count; diff --git a/components/wpa_supplicant/include/wpa2/tls/tlsv1_client.h b/components/wpa_supplicant/src/tls/tlsv1_client.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/tls/tlsv1_client.h rename to components/wpa_supplicant/src/tls/tlsv1_client.h diff --git a/components/wpa_supplicant/include/wpa2/tls/tlsv1_client_i.h b/components/wpa_supplicant/src/tls/tlsv1_client_i.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/tls/tlsv1_client_i.h rename to components/wpa_supplicant/src/tls/tlsv1_client_i.h diff --git a/components/wpa_supplicant/src/wpa2/tls/tlsv1_client_read.c b/components/wpa_supplicant/src/tls/tlsv1_client_read.c similarity index 97% rename from components/wpa_supplicant/src/wpa2/tls/tlsv1_client_read.c rename to components/wpa_supplicant/src/tls/tlsv1_client_read.c index 13330bdbf1..89b25e149b 100644 --- a/components/wpa_supplicant/src/wpa2/tls/tlsv1_client_read.c +++ b/components/wpa_supplicant/src/tls/tlsv1_client_read.c @@ -6,19 +6,19 @@ * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/md5.h" #include "crypto/sha1.h" #include "crypto/sha256.h" -#include "wpa2/tls/tls.h" -#include "wpa2/tls/x509v3.h" -#include "wpa2/tls/tlsv1_common.h" -#include "wpa2/tls/tlsv1_record.h" -#include "wpa2/tls/tlsv1_client.h" -#include "wpa2/tls/tlsv1_client_i.h" -#include "wpa2/eap_peer/eap_i.h" +#include "tls/tls.h" +#include "tls/x509v3.h" +#include "tls/tlsv1_common.h" +#include "tls/tlsv1_record.h" +#include "tls/tlsv1_client.h" +#include "tls/tlsv1_client_i.h" +#include "eap_peer/eap_i.h" static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct, const u8 *in_data, size_t *in_len); @@ -815,15 +815,8 @@ static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct, #ifdef CONFIG_TLSV12 if (conn->rl.tls_version >= TLS_VERSION_1_2) { hlen = SHA256_MAC_LEN; - if (wpa2_crypto_funcs.crypto_hash_finish) { - if (conn->verify.sha256_server == NULL || - wpa_crypto_funcs.crypto_hash_finish(conn->verify.sha256_server, hash, &hlen) < 0) { - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); - conn->verify.sha256_server = NULL; - return -1; - } - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register crypto_hash_finish function!\r\n", __FUNCTION__); + if (conn->verify.sha256_server == NULL || + fast_crypto_hash_finish(conn->verify.sha256_server, hash, &hlen) < 0) { tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); conn->verify.sha256_server = NULL; return -1; diff --git a/components/wpa_supplicant/src/wpa2/tls/tlsv1_client_write.c b/components/wpa_supplicant/src/tls/tlsv1_client_write.c similarity index 89% rename from components/wpa_supplicant/src/wpa2/tls/tlsv1_client_write.c rename to components/wpa_supplicant/src/tls/tlsv1_client_write.c index 55644a046c..6f4f887528 100644 --- a/components/wpa_supplicant/src/wpa2/tls/tlsv1_client_write.c +++ b/components/wpa_supplicant/src/tls/tlsv1_client_write.c @@ -6,21 +6,21 @@ * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/md5.h" #include "crypto/sha1.h" #include "crypto/sha256.h" #include "crypto/random.h" -#include "wpa2/tls/tls.h" -#include "wpa2/tls/x509v3.h" -#include "wpa2/tls/tlsv1_common.h" -#include "wpa2/tls/tlsv1_record.h" -#include "wpa2/tls/tlsv1_client.h" -#include "wpa2/tls/tlsv1_client_i.h" +#include "tls/tls.h" +#include "tls/x509v3.h" +#include "tls/tlsv1_common.h" +#include "tls/tlsv1_record.h" +#include "tls/tlsv1_client.h" +#include "tls/tlsv1_client_i.h" -#include "wpa2/eap_peer/eap_i.h" +#include "eap_peer/eap_i.h" static size_t tls_client_cert_chain_der_len(struct tlsv1_client *conn) { @@ -252,23 +252,14 @@ static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end) os_free(csecret); return -1; } - if (wpa2_crypto_funcs.crypto_mod_exp) { - if(wpa2_crypto_funcs.crypto_mod_exp(conn->dh_g, conn->dh_g_len, - csecret_start, csecret_len, - conn->dh_p, conn->dh_p_len, - dh_yc, &dh_yc_len)) { - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - os_free(csecret); - os_free(dh_yc); - return -1; - } - } else { - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); + if(crypto_mod_exp(conn->dh_g, conn->dh_g_len, + csecret_start, csecret_len, + conn->dh_p, conn->dh_p_len, + dh_yc, &dh_yc_len)) { + tls_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); os_free(csecret); os_free(dh_yc); - wpa_printf(MSG_ERROR, "Fail to register crypto_mod_exp function!\r\n"); return -1; } @@ -302,23 +293,14 @@ static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end) } /* shared = Ys^csecret mod p */ - if (wpa2_crypto_funcs.crypto_mod_exp) { - if(wpa2_crypto_funcs.crypto_mod_exp(conn->dh_ys, conn->dh_ys_len, - csecret_start, csecret_len, - conn->dh_p, conn->dh_p_len, - shared, &shared_len)) { - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, + if(crypto_mod_exp(conn->dh_ys, conn->dh_ys_len, + csecret_start, csecret_len, + conn->dh_p, conn->dh_p_len, + shared, &shared_len)) { + tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); - os_free(csecret); - os_free(shared); - return -1; - } - } else { - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); os_free(csecret); os_free(shared); - wpa_printf(MSG_ERROR, "Fail to register crypto_mod_exp function!\r\n"); return -1; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange", @@ -493,20 +475,12 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn, #ifdef CONFIG_TLSV12 if (conn->rl.tls_version == TLS_VERSION_1_2) { hlen = SHA256_MAC_LEN; - if (wpa2_crypto_funcs.crypto_hash_finish) { - if (conn->verify.sha256_cert == NULL || - wpa2_crypto_funcs.crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) < - 0) { - conn->verify.sha256_cert = NULL; - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - } else { + if (conn->verify.sha256_cert == NULL || + fast_crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) < + 0) { conn->verify.sha256_cert = NULL; tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - wpa_printf(MSG_ERROR, "In function %s, fail to register crypto_hash_finish function!\r\n", __FUNCTION__); + TLS_ALERT_INTERNAL_ERROR); return -1; } conn->verify.sha256_cert = NULL; @@ -679,20 +653,12 @@ static int tls_write_client_finished(struct tlsv1_client *conn, #ifdef CONFIG_TLSV12 if (conn->rl.tls_version >= TLS_VERSION_1_2) { hlen = SHA256_MAC_LEN; - if (wpa2_crypto_funcs.crypto_hash_finish) { - if (conn->verify.sha256_client == NULL || - wpa2_crypto_funcs.crypto_hash_finish(conn->verify.sha256_client, hash, &hlen) - < 0) { - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - conn->verify.sha256_client = NULL; - return -1; - } - } else { + if (conn->verify.sha256_client == NULL || + fast_crypto_hash_finish(conn->verify.sha256_client, hash, &hlen) + < 0) { tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); + TLS_ALERT_INTERNAL_ERROR); conn->verify.sha256_client = NULL; - wpa_printf(MSG_ERROR, "In function %s, fail to register crypto_hash_finish function!\r\n", __FUNCTION__); return -1; } conn->verify.sha256_client = NULL; diff --git a/components/wpa_supplicant/src/wpa2/tls/tlsv1_common.c b/components/wpa_supplicant/src/tls/tlsv1_common.c similarity index 84% rename from components/wpa_supplicant/src/wpa2/tls/tlsv1_common.c rename to components/wpa_supplicant/src/tls/tlsv1_common.c index 38d0b694d2..5380df8769 100644 --- a/components/wpa_supplicant/src/wpa2/tls/tlsv1_common.c +++ b/components/wpa_supplicant/src/tls/tlsv1_common.c @@ -6,15 +6,15 @@ * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/sha1.h" #include "crypto/sha256.h" -#include "wpa2/tls/tls.h" -#include "wpa2/tls/x509v3.h" -#include "wpa2/tls/tlsv1_common.h" -#include "wpa2/eap_peer/eap_i.h" +#include "tls/tls.h" +#include "tls/x509v3.h" +#include "tls/tlsv1_common.h" +#include "eap_peer/eap_i.h" /* @@ -221,14 +221,10 @@ int tls_verify_hash_init(struct tls_verify_hash *verify) return -1; } #ifdef CONFIG_TLSV12 - if (wpa2_crypto_funcs.crypto_hash_init) { - verify->sha256_client = wpa2_crypto_funcs.crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0); - verify->sha256_server = wpa2_crypto_funcs.crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0); - verify->sha256_cert = wpa2_crypto_funcs.crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register crypto hash init function!\r\n", __FUNCTION__); - return -1; - } + verify->sha256_client = fast_crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0); + verify->sha256_server = fast_crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0); + verify->sha256_cert = fast_crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0); + if (verify->sha256_client == NULL || verify->sha256_server == NULL || verify->sha256_cert == NULL) { @@ -256,17 +252,12 @@ void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf, crypto_hash_update(verify->sha1_cert, buf, len); } #ifdef CONFIG_TLSV12 - if (wpa2_crypto_funcs.crypto_hash_update) { - if (verify->sha256_client) - wpa2_crypto_funcs.crypto_hash_update(verify->sha256_client, buf, len); - if (verify->sha256_server) - wpa2_crypto_funcs.crypto_hash_update(verify->sha256_server, buf, len); - if (verify->sha256_cert) - wpa2_crypto_funcs.crypto_hash_update(verify->sha256_cert, buf, len); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register crypto hash update function!\r\n", __FUNCTION__); - return; - } + if (verify->sha256_client) + fast_crypto_hash_update(verify->sha256_client, buf, len); + if (verify->sha256_server) + fast_crypto_hash_update(verify->sha256_server, buf, len); + if (verify->sha256_cert) + fast_crypto_hash_update(verify->sha256_cert, buf, len); #endif /* CONFIG_TLSV12 */ } @@ -286,17 +277,12 @@ void tls_verify_hash_free(struct tls_verify_hash *verify) verify->sha1_server = NULL; verify->sha1_cert = NULL; #ifdef CONFIG_TLSV12 - if (wpa2_crypto_funcs.crypto_hash_finish) { - wpa2_crypto_funcs.crypto_hash_finish(verify->sha256_client, NULL, NULL); - wpa2_crypto_funcs.crypto_hash_finish(verify->sha256_server, NULL, NULL); - wpa2_crypto_funcs.crypto_hash_finish(verify->sha256_cert, NULL, NULL); - verify->sha256_client = NULL; - verify->sha256_server = NULL; - verify->sha256_cert = NULL; - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register crypto hash finish function!\r\n", __FUNCTION__); - return; - } + fast_crypto_hash_finish(verify->sha256_client, NULL, NULL); + fast_crypto_hash_finish(verify->sha256_server, NULL, NULL); + fast_crypto_hash_finish(verify->sha256_cert, NULL, NULL); + verify->sha256_client = NULL; + verify->sha256_server = NULL; + verify->sha256_cert = NULL; #endif /* CONFIG_TLSV12 */ } diff --git a/components/wpa_supplicant/include/wpa2/tls/tlsv1_common.h b/components/wpa_supplicant/src/tls/tlsv1_common.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/tls/tlsv1_common.h rename to components/wpa_supplicant/src/tls/tlsv1_common.h diff --git a/components/wpa_supplicant/src/wpa2/tls/tlsv1_cred.c b/components/wpa_supplicant/src/tls/tlsv1_cred.c similarity index 97% rename from components/wpa_supplicant/src/wpa2/tls/tlsv1_cred.c rename to components/wpa_supplicant/src/tls/tlsv1_cred.c index fd359a2cc5..ed7577617a 100644 --- a/components/wpa_supplicant/src/wpa2/tls/tlsv1_cred.c +++ b/components/wpa_supplicant/src/tls/tlsv1_cred.c @@ -6,13 +6,13 @@ * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" -#include "wpa2/utils/base64.h" +#include "utils/common.h" +#include "utils/base64.h" #include "crypto/crypto.h" -#include "wpa2/tls/x509v3.h" -#include "wpa2/tls/tlsv1_cred.h" +#include "tls/x509v3.h" +#include "tls/tlsv1_cred.h" struct tlsv1_credentials * tlsv1_cred_alloc(void) { @@ -160,7 +160,6 @@ static int tlsv1_set_cert_chain(struct x509_certificate **chain, size_t len; int ret; - //buf = (u8 *) os_readfile(cert, &len); if (buf == NULL) { wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'", cert); @@ -332,7 +331,6 @@ int tlsv1_set_private_key(struct tlsv1_credentials *cred, size_t len; int ret; - //buf = (u8 *) os_readfile(private_key, &len); if (buf == NULL) { wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'", private_key); @@ -489,7 +487,6 @@ int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file, size_t len; int ret; - //buf = (u8 *) os_readfile(dh_file, &len); if (buf == NULL) { wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'", dh_file); diff --git a/components/wpa_supplicant/include/wpa2/tls/tlsv1_cred.h b/components/wpa_supplicant/src/tls/tlsv1_cred.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/tls/tlsv1_cred.h rename to components/wpa_supplicant/src/tls/tlsv1_cred.h diff --git a/components/wpa_supplicant/src/wpa2/tls/tlsv1_record.c b/components/wpa_supplicant/src/tls/tlsv1_record.c similarity index 73% rename from components/wpa_supplicant/src/wpa2/tls/tlsv1_record.c rename to components/wpa_supplicant/src/tls/tlsv1_record.c index 879d9f5454..12b14e79b8 100644 --- a/components/wpa_supplicant/src/wpa2/tls/tlsv1_record.c +++ b/components/wpa_supplicant/src/tls/tlsv1_record.c @@ -6,16 +6,16 @@ * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/md5.h" #include "crypto/sha1.h" #include "crypto/sha256.h" -#include "wpa2/tls/tlsv1_common.h" -#include "wpa2/tls/tlsv1_record.h" +#include "tls/tlsv1_common.h" +#include "tls/tlsv1_record.h" -#include "wpa2/eap_peer/eap_i.h" +#include "eap_peer/eap_i.h" /** * tlsv1_record_set_cipher_suite - TLS record layer: Set cipher suite @@ -81,23 +81,14 @@ int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl) os_memset(rl->write_seq_num, 0, TLS_SEQ_NUM_LEN); if (rl->write_cbc) { - if (wpa2_crypto_funcs.crypto_cipher_deinit) { - wpa2_crypto_funcs.crypto_cipher_deinit(rl->write_cbc); - rl->write_cbc = NULL; - } else { - wpa_printf(MSG_ERROR, "Fail to register crypto cipher deinit function!\r\n"); - return -1; - } + fast_crypto_cipher_deinit(rl->write_cbc); + rl->write_cbc = NULL; + } if (rl->cipher_alg != CRYPTO_CIPHER_NULL) { - if (wpa2_crypto_funcs.crypto_cipher_init) { - rl->write_cbc = wpa2_crypto_funcs.crypto_cipher_init(rl->cipher_alg, - rl->write_iv, rl->write_key, - rl->key_material_len); - } else { - wpa_printf(MSG_ERROR, "Fail to register crypto_cipher_init function!\r\n"); - return -1; - } + rl->write_cbc = fast_crypto_cipher_init(rl->cipher_alg, + rl->write_iv, rl->write_key, + rl->key_material_len); if (rl->write_cbc == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize " @@ -126,24 +117,14 @@ int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl) os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN); if (rl->read_cbc) { - if (wpa2_crypto_funcs.crypto_cipher_deinit) { - wpa2_crypto_funcs.crypto_cipher_deinit(rl->read_cbc); - rl->read_cbc = NULL; - } else { - wpa_printf(MSG_ERROR, "Fail to register crypto cipher deinit function!\r\n"); - return -1; - } + fast_crypto_cipher_deinit(rl->read_cbc); + rl->read_cbc = NULL; } if (rl->cipher_alg != CRYPTO_CIPHER_NULL) { - if(wpa2_crypto_funcs.crypto_cipher_init) { - rl->read_cbc = wpa2_crypto_funcs.crypto_cipher_init(rl->cipher_alg, - rl->read_iv, rl->read_key, - rl->key_material_len); - } else { - wpa_printf(MSG_ERROR, "Fail to register crypto_cipher_init function!\r\n"); - return -1; - } + rl->read_cbc = fast_crypto_cipher_init(rl->cipher_alg, + rl->read_iv, rl->read_key, + rl->key_material_len); if (rl->read_cbc == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize " "cipher"); @@ -227,49 +208,30 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf, * TLSCompressed.version + TLSCompressed.length + * TLSCompressed.fragment */ - if (wpa2_crypto_funcs.crypto_hash_init) { - hmac = wpa2_crypto_funcs.crypto_hash_init(rl->hash_alg, rl->write_mac_secret, rl->hash_size); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register crypto hash init!\r\n", __FUNCTION__); - return -1; - } + hmac = fast_crypto_hash_init(rl->hash_alg, rl->write_mac_secret, rl->hash_size); if (hmac == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " "to initialize HMAC"); return -1; } - if (wpa2_crypto_funcs.crypto_hash_update) { - wpa2_crypto_funcs.crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN); - /* type + version + length + fragment */ - wpa2_crypto_funcs.crypto_hash_update(hmac, ct_start, TLS_RECORD_HEADER_LEN); - wpa2_crypto_funcs.crypto_hash_update(hmac, payload, payload_len); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register crypto hash update!\r\n", __FUNCTION__); - return -1; - } + fast_crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN); + /* type + version + length + fragment */ + fast_crypto_hash_update(hmac, ct_start, TLS_RECORD_HEADER_LEN); + fast_crypto_hash_update(hmac, payload, payload_len); clen = buf + buf_size - pos; if (clen < rl->hash_size) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not " "enough room for MAC"); - if (wpa2_crypto_funcs.crypto_hash_finish) { - wpa2_crypto_funcs.crypto_hash_finish(hmac, NULL, NULL); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register crypto hash finish function!\r\n", __FUNCTION__); - return -1; - } - + fast_crypto_hash_finish(hmac, NULL, NULL); + return -1; } - if (wpa2_crypto_funcs.crypto_hash_finish) { - if ((int)wpa2_crypto_funcs.crypto_hash_finish(hmac, pos, (int *)&clen) < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed to calculate HMAC"); - return -1; - } - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register crypto_hash_finish function!\r\n",__FUNCTION__); + if ((int)fast_crypto_hash_finish(hmac, pos, &clen) < 0) { + wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed to calculate HMAC"); return -1; } + wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC", pos, clen); pos += clen; @@ -288,14 +250,9 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf, pos += pad + 1; } - if (wpa2_crypto_funcs.crypto_cipher_encrypt) { - if ((int)wpa2_crypto_funcs.crypto_cipher_encrypt(rl->write_cbc, cpayload, - cpayload, pos - cpayload) < 0) - return -1; - } else { - wpa_printf(MSG_ERROR, "Fail to register crypto_cipher_encrypt function!\r\n"); - return -1; - } + if ((int)fast_crypto_cipher_encrypt(rl->write_cbc, cpayload, + cpayload, pos - cpayload) < 0) + return -1; } WPA_PUT_BE16(length, pos - length - 2); @@ -401,17 +358,12 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl, if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) { size_t plen; - if (wpa2_crypto_funcs.crypto_cipher_decrypt) { - if ((int)wpa2_crypto_funcs.crypto_cipher_decrypt(rl->read_cbc, in_data, - out_data, in_len) < 0) { - *alert = TLS_ALERT_DECRYPTION_FAILED; - return -1; - } - } else { - wpa_printf(MSG_ERROR, "Fail to register crypto cipher decrypt function. \r\n"); - *alert = TLS_ALERT_DECRYPTION_FAILED; - return -1; + if ((int)fast_crypto_cipher_decrypt(rl->read_cbc, in_data, + out_data, in_len) < 0) { + *alert = TLS_ALERT_DECRYPTION_FAILED; + return -1; } + plen = in_len; wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - Decrypted " "data", out_data, plen); @@ -486,12 +438,7 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl, plen -= rl->hash_size; - if (wpa2_crypto_funcs.crypto_hash_init) { - hmac = wpa2_crypto_funcs.crypto_hash_init(rl->hash_alg, rl->read_mac_secret, rl->hash_size); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register crypto_hash_init function!\r\n", __FUNCTION__); - return -1; - } + hmac = fast_crypto_hash_init(rl->hash_alg, rl->read_mac_secret, rl->hash_size); if (hmac == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " @@ -500,29 +447,20 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl, return -1; } - if (wpa2_crypto_funcs.crypto_hash_update) { - wpa2_crypto_funcs.crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN); - /* type + version + length + fragment */ - wpa2_crypto_funcs.crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3); - WPA_PUT_BE16(len, plen); - wpa2_crypto_funcs.crypto_hash_update(hmac, len, 2); - wpa2_crypto_funcs.crypto_hash_update(hmac, out_data, plen); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register crypto hash update function!\r\n", __FUNCTION__); - return -1; - } + fast_crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN); + /* type + version + length + fragment */ + fast_crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3); + WPA_PUT_BE16(len, plen); + fast_crypto_hash_update(hmac, len, 2); + fast_crypto_hash_update(hmac, out_data, plen); + hlen = sizeof(hash); - if (wpa2_crypto_funcs.crypto_hash_finish) { - if ((int)wpa2_crypto_funcs.crypto_hash_finish(hmac, hash, (int *)&hlen) < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed to calculate HMAC"); - *alert = TLS_ALERT_INTERNAL_ERROR; - return -1; - } - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register crypto_hash_finish function!\r\n", __FUNCTION__); + if ((int)fast_crypto_hash_finish(hmac, hash, &hlen) < 0) { + wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed to calculate HMAC"); *alert = TLS_ALERT_INTERNAL_ERROR; return -1; } + if (hlen != rl->hash_size || os_memcmp(hash, out_data + plen, hlen) != 0 || force_mac_error) { diff --git a/components/wpa_supplicant/include/wpa2/tls/tlsv1_record.h b/components/wpa_supplicant/src/tls/tlsv1_record.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/tls/tlsv1_record.h rename to components/wpa_supplicant/src/tls/tlsv1_record.h diff --git a/components/wpa_supplicant/src/wpa2/tls/tlsv1_server.c b/components/wpa_supplicant/src/tls/tlsv1_server.c similarity index 98% rename from components/wpa_supplicant/src/wpa2/tls/tlsv1_server.c rename to components/wpa_supplicant/src/tls/tlsv1_server.c index 95118aa052..4628af8c50 100644 --- a/components/wpa_supplicant/src/wpa2/tls/tlsv1_server.c +++ b/components/wpa_supplicant/src/tls/tlsv1_server.c @@ -6,15 +6,15 @@ * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/sha1.h" -#include "wpa2/tls/tls.h" -#include "wpa2/tls/tlsv1_common.h" -#include "wpa2/tls/tlsv1_record.h" -#include "wpa2/tls/tlsv1_server.h" -#include "wpa2/tls/tlsv1_server_i.h" +#include "tls/tls.h" +#include "tls/tlsv1_common.h" +#include "tls/tlsv1_record.h" +#include "tls/tlsv1_server.h" +#include "tls/tlsv1_server_i.h" /* TODO: * Support for a message fragmented across several records (RFC 2246, 6.2.1) diff --git a/components/wpa_supplicant/include/wpa2/tls/tlsv1_server.h b/components/wpa_supplicant/src/tls/tlsv1_server.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/tls/tlsv1_server.h rename to components/wpa_supplicant/src/tls/tlsv1_server.h diff --git a/components/wpa_supplicant/include/wpa2/tls/tlsv1_server_i.h b/components/wpa_supplicant/src/tls/tlsv1_server_i.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/tls/tlsv1_server_i.h rename to components/wpa_supplicant/src/tls/tlsv1_server_i.h diff --git a/components/wpa_supplicant/src/wpa2/tls/tlsv1_server_read.c b/components/wpa_supplicant/src/tls/tlsv1_server_read.c similarity index 94% rename from components/wpa_supplicant/src/wpa2/tls/tlsv1_server_read.c rename to components/wpa_supplicant/src/tls/tlsv1_server_read.c index ee477c98a0..28d1e27295 100644 --- a/components/wpa_supplicant/src/wpa2/tls/tlsv1_server_read.c +++ b/components/wpa_supplicant/src/tls/tlsv1_server_read.c @@ -6,20 +6,20 @@ * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/md5.h" #include "crypto/sha1.h" #include "crypto/sha256.h" -#include "wpa2/tls/tls.h" -#include "wpa2/tls/x509v3.h" -#include "wpa2/tls/tlsv1_common.h" -#include "wpa2/tls/tlsv1_record.h" -#include "wpa2/tls/tlsv1_server.h" -#include "wpa2/tls/tlsv1_server_i.h" +#include "tls/tls.h" +#include "tls/x509v3.h" +#include "tls/tlsv1_common.h" +#include "tls/tlsv1_record.h" +#include "tls/tlsv1_server.h" +#include "tls/tlsv1_server_i.h" -#include "wpa2/eap_peer/eap_i.h" +#include "eap_peer/eap_i.h" static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct, const u8 *in_data, size_t *in_len); @@ -652,21 +652,13 @@ static int tls_process_client_key_exchange_dh_anon( } /* shared = Yc^secret mod p */ - if (wpa2_crypto_funcs.crypto_mod_exp) { - if (wpa2_crypto_funcs.crypto_mod_exp(dh_yc, dh_yc_len, conn->dh_secret, - conn->dh_secret_len, - conn->cred->dh_p, conn->cred->dh_p_len, - shared, &shared_len)) { - os_free(shared); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - } else { - wpa_printf(MSG_ERROR, "Fail to register crypto_mod_exp function!\r\n"); + if (crypto_mod_exp(dh_yc, dh_yc_len, conn->dh_secret, + conn->dh_secret_len, + conn->cred->dh_p, conn->cred->dh_p_len, + shared, &shared_len)) { os_free(shared); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); + TLS_ALERT_INTERNAL_ERROR); return -1; } @@ -878,20 +870,12 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct, pos += 2; hlen = SHA256_MAC_LEN; - if (wpa2_crypto_funcs.crypto_hash_finish) { - if (conn->verify.sha256_cert == NULL || - wpa2_crypto_funcs.crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) < - 0) { - conn->verify.sha256_cert = NULL; - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - } else { + if (conn->verify.sha256_cert == NULL || + fast_crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) < + 0) { conn->verify.sha256_cert = NULL; tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - wpa_printf(MSG_ERROR, "In function %s, fail to register crypto_hash_finish function!\r\n", __FUNCTION__); + TLS_ALERT_INTERNAL_ERROR); return -1; } conn->verify.sha256_cert = NULL; @@ -1140,20 +1124,12 @@ static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct, #ifdef CONFIG_TLSV12 if (conn->rl.tls_version >= TLS_VERSION_1_2) { hlen = SHA256_MAC_LEN; - if (wpa2_crypto_funcs.crypto_hash_finish) { - if (conn->verify.sha256_client == NULL || - crypto_hash_finish(conn->verify.sha256_client, hash, &hlen) - < 0) { - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - conn->verify.sha256_client = NULL; - return -1; - } - } else { + if (conn->verify.sha256_client == NULL || + crypto_hash_finish(conn->verify.sha256_client, hash, &hlen) + < 0) { tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); + TLS_ALERT_INTERNAL_ERROR); conn->verify.sha256_client = NULL; - wpa_printf(MSG_ERROR, "In function %s, fail to register crypto_hash_finish function!\r\n", __FUNCTION__); return -1; } conn->verify.sha256_client = NULL; diff --git a/components/wpa_supplicant/src/wpa2/tls/tlsv1_server_write.c b/components/wpa_supplicant/src/tls/tlsv1_server_write.c similarity index 93% rename from components/wpa_supplicant/src/wpa2/tls/tlsv1_server_write.c rename to components/wpa_supplicant/src/tls/tlsv1_server_write.c index 55eff1af6f..39413e8347 100644 --- a/components/wpa_supplicant/src/wpa2/tls/tlsv1_server_write.c +++ b/components/wpa_supplicant/src/tls/tlsv1_server_write.c @@ -6,21 +6,21 @@ * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/md5.h" #include "crypto/sha1.h" #include "crypto/sha256.h" #include "crypto/random.h" -#include "wpa2/tls/tls.h" -#include "wpa2/tls/x509v3.h" -#include "wpa2/tls/tlsv1_common.h" -#include "wpa2/tls/tlsv1_record.h" -#include "wpa2/tls/tlsv1_server.h" -#include "wpa2/tls/tlsv1_server_i.h" +#include "tls/tls.h" +#include "tls/x509v3.h" +#include "tls/tlsv1_common.h" +#include "tls/tlsv1_record.h" +#include "tls/tlsv1_server.h" +#include "tls/tlsv1_server_i.h" -#include "wpa2/eap_peer/eap_i.h" +#include "eap_peer/eap_i.h" static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn) { @@ -321,21 +321,13 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn, TLS_ALERT_INTERNAL_ERROR); return -1; } - if(wpa2_crypto_funcs.crypto_mod_exp) { - if (wpa2_crypto_funcs.crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len, - conn->dh_secret, conn->dh_secret_len, - conn->cred->dh_p, conn->cred->dh_p_len, - dh_ys, &dh_ys_len)) { - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - os_free(dh_ys); - return -1; - } - } else { + if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len, + conn->dh_secret, conn->dh_secret_len, + conn->cred->dh_p, conn->cred->dh_p_len, + dh_ys, &dh_ys_len)) { tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); + TLS_ALERT_INTERNAL_ERROR); os_free(dh_ys); - wpa_printf(MSG_ERROR, "Fail to register crypto_mod_exp function!\r\n"); return -1; } @@ -595,20 +587,12 @@ static int tls_write_server_finished(struct tlsv1_server *conn, #ifdef CONFIG_TLSV12 if (conn->rl.tls_version >= TLS_VERSION_1_2) { hlen = SHA256_MAC_LEN; - if (wpa2_crypto_funcs.crypto_hash_finish) { - if (conn->verify.sha256_server == NULL || - wpa2_crypto_funcs.crypto_hash_finish(conn->verify.sha256_server, hash, &hlen) - < 0) { - conn->verify.sha256_server = NULL; - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - } else { + if (conn->verify.sha256_server == NULL || + fast_crypto_hash_finish(conn->verify.sha256_server, hash, &hlen) + < 0) { conn->verify.sha256_server = NULL; tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - wpa_printf(MSG_ERROR, "In function %s, fail to register crypto_hash_finish function!\r\n", __FUNCTION__); + TLS_ALERT_INTERNAL_ERROR); return -1; } conn->verify.sha256_server = NULL; diff --git a/components/wpa_supplicant/src/wpa2/tls/x509v3.c b/components/wpa_supplicant/src/tls/x509v3.c similarity index 94% rename from components/wpa_supplicant/src/wpa2/tls/x509v3.c rename to components/wpa_supplicant/src/tls/x509v3.c index ba331cdecb..d4f4652ff0 100644 --- a/components/wpa_supplicant/src/wpa2/tls/x509v3.c +++ b/components/wpa_supplicant/src/tls/x509v3.c @@ -6,14 +6,14 @@ * See README for more details. */ -#include "wpa/includes.h" -#include "wpa/wpa.h" -#include "wpa/common.h" +#include "utils/includes.h" +#include "rsn_supp/wpa.h" +#include "utils/common.h" #include "crypto/crypto.h" -#include "wpa2/tls/asn1.h" -#include "wpa2/tls/x509v3.h" +#include "tls/asn1.h" +#include "tls/x509v3.h" -#include "wpa2/eap_peer/eap_i.h" +#include "eap_peer/eap_i.h" static void x509_free_name(struct x509_name *name) { @@ -574,110 +574,6 @@ done: static int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag, os_time_t *val) { -#if 0 - const char *pos; - int year, month, day, hour, min, sec; - - /* - * Time ::= CHOICE { - * utcTime UTCTime, - * generalTime GeneralizedTime - * } - * - * UTCTime: YYMMDDHHMMSSZ - * GeneralizedTime: YYYYMMDDHHMMSSZ - */ - - pos = (const char *) buf; - - switch (asn1_tag) { - case ASN1_TAG_UTCTIME: - if (len != 13 || buf[12] != 'Z') { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized " - "UTCTime format", buf, len); - return -1; - } - if (sscanf(pos, "%02d", &year) != 1) { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse " - "UTCTime year", buf, len); - return -1; - } - if (year < 50) - year += 2000; - else - year += 1900; - pos += 2; - break; - case ASN1_TAG_GENERALIZEDTIME: - if (len != 15 || buf[14] != 'Z') { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized " - "GeneralizedTime format", buf, len); - return -1; - } - if (sscanf(pos, "%04d", &year) != 1) { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse " - "GeneralizedTime year", buf, len); - return -1; - } - pos += 4; - break; - default: - wpa_printf(MSG_DEBUG, "X509: Expected UTCTime or " - "GeneralizedTime - found tag 0x%x", asn1_tag); - return -1; - } - - if (sscanf(pos, "%02d", &month) != 1) { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " - "(month)", buf, len); - return -1; - } - pos += 2; - - if (sscanf(pos, "%02d", &day) != 1) { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " - "(day)", buf, len); - return -1; - } - pos += 2; - - if (sscanf(pos, "%02d", &hour) != 1) { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " - "(hour)", buf, len); - return -1; - } - pos += 2; - - if (sscanf(pos, "%02d", &min) != 1) { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " - "(min)", buf, len); - return -1; - } - pos += 2; - - if (sscanf(pos, "%02d", &sec) != 1) { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " - "(sec)", buf, len); - return -1; - } - - if (os_mktime(year, month, day, hour, min, sec, val) < 0) { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to convert Time", - buf, len); - if (year < 1970) { - /* - * At least some test certificates have been configured - * to use dates prior to 1970. Set the date to - * beginning of 1970 to handle these case. - */ - wpa_printf(MSG_DEBUG, "X509: Year=%d before epoch - " - "assume epoch as the time", year); - *val = 0; - return 0; - } - return -1; - } -#endif return 0; } @@ -1792,13 +1688,8 @@ skip_digest_oid: hash, hash_len); break; case 11: /* sha256WithRSAEncryption */ - if (wpa2_crypto_funcs.sha256_vector) { - wpa2_crypto_funcs.sha256_vector(1, &cert->tbs_cert_start, (int *)&cert->tbs_cert_len, - hash); - } else { - wpa_printf(MSG_ERROR, "Fail to register sha256 vector function!\r\n"); - return -1; - } + fast_sha256_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, + hash); hash_len = 32; wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA256)", hash, hash_len); diff --git a/components/wpa_supplicant/include/wpa2/tls/x509v3.h b/components/wpa_supplicant/src/tls/x509v3.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/tls/x509v3.h rename to components/wpa_supplicant/src/tls/x509v3.h diff --git a/components/wpa_supplicant/src/wpa2/utils/base64.c b/components/wpa_supplicant/src/utils/base64.c similarity index 98% rename from components/wpa_supplicant/src/wpa2/utils/base64.c rename to components/wpa_supplicant/src/utils/base64.c index 0340c390e7..bf17e6f7d4 100644 --- a/components/wpa_supplicant/src/wpa2/utils/base64.c +++ b/components/wpa_supplicant/src/utils/base64.c @@ -6,10 +6,10 @@ * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" #include "os.h" -#include "wpa2/utils/base64.h" +#include "base64.h" static const unsigned char base64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; diff --git a/components/wpa_supplicant/include/crypto/base64.h b/components/wpa_supplicant/src/utils/base64.h similarity index 100% rename from components/wpa_supplicant/include/crypto/base64.h rename to components/wpa_supplicant/src/utils/base64.h diff --git a/components/wpa_supplicant/src/utils/common.c b/components/wpa_supplicant/src/utils/common.c new file mode 100644 index 0000000000..7e5ef1be01 --- /dev/null +++ b/components/wpa_supplicant/src/utils/common.c @@ -0,0 +1,166 @@ +/* + * wpa_supplicant/hostapd / common helper functions, etc. + * Copyright (c) 2002-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" + +/** + * inc_byte_array - Increment arbitrary length byte array by one + * @counter: Pointer to byte array + * @len: Length of the counter in bytes + * + * This function increments the last byte of the counter by one and continues + * rolling over to more significant bytes if the byte was incremented from + * 0xff to 0x00. + */ +void inc_byte_array(u8 *counter, size_t len) +{ + int pos = len - 1; + while (pos >= 0) { + counter[pos]++; + if (counter[pos] != 0) + break; + pos--; + } +} + +static int hex2num(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + + +int hex2byte(const char *hex) +{ + int a, b; + a = hex2num(*hex++); + if (a < 0) + return -1; + b = hex2num(*hex++); + if (b < 0) + return -1; + return (a << 4) | b; +} + + +/** + * hexstr2bin - Convert ASCII hex string into binary data + * @hex: ASCII hex string (e.g., "01ab") + * @buf: Buffer for the binary data + * @len: Length of the text to convert in bytes (of buf); hex will be double + * this size + * Returns: 0 on success, -1 on failure (invalid hex string) + */ +int hexstr2bin(const char *hex, u8 *buf, size_t len) +{ + size_t i; + int a; + const char *ipos = hex; + u8 *opos = buf; + + for (i = 0; i < len; i++) { + a = hex2byte(ipos); + if (a < 0) + return -1; + *opos++ = a; + ipos += 2; + } + return 0; +} + +void wpa_get_ntp_timestamp(u8 *buf) +{ + struct os_time now; + u32 sec, usec; + be32 tmp; + + /* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */ + os_get_time(&now); + sec = now.sec + 2208988800U; /* Epoch to 1900 */ + /* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */ + usec = now.usec; + usec = 4295 * usec - (usec >> 5) - (usec >> 9); + tmp = host_to_be32(sec); + memcpy(buf, (u8 *) &tmp, 4); + tmp = host_to_be32(usec); + memcpy(buf + 4, (u8 *) &tmp, 4); +} + +char * wpa_config_parse_string(const char *value, size_t *len) +{ + if (*value == '"' && (strlen(value) == 7 || strlen(value) == 15)) { + const char *pos; + char *str; + value++; + pos = (char *)strrchr(value, '"'); + if (pos == NULL) + return NULL; + *len = pos - value; + str = (char *)os_malloc(*len + 1); + if (str == NULL) + return NULL; + memcpy(str, value, *len); + str[*len] = '\0'; + return str; + } else { + u8 *str; + size_t tlen, hlen = strlen(value); + if (hlen == 5 || hlen == 13) { + *len = hlen; + str = (u8 *)os_malloc(*len + 1); + if (str == NULL) { + return NULL; + } + memcpy(str, value, *len); + str[*len] = '\0'; + } else if (hlen == 10 || hlen == 26) { + tlen = hlen / 2; + str = (u8 *)os_malloc(tlen + 1); + if (str == NULL) + return NULL; + if (hexstr2bin(value, str, tlen)) { + os_free(str); + return NULL; + } + str[tlen] = '\0'; + *len = tlen; + } else { + return NULL; + } + return (char *) str; + } +} + +char * dup_binstr(const void *src, size_t len) +{ + char *res; + + if (src == NULL) + return NULL; + res = os_malloc(len + 1); + if (res == NULL) + return NULL; + memcpy(res, src, len); + res[len] = '\0'; + + return res; +} + diff --git a/components/wpa_supplicant/src/wpa2/utils/ext_password.c b/components/wpa_supplicant/src/utils/ext_password.c similarity index 96% rename from components/wpa_supplicant/src/wpa2/utils/ext_password.c rename to components/wpa_supplicant/src/utils/ext_password.c index 3989f949b1..96e67058db 100644 --- a/components/wpa_supplicant/src/wpa2/utils/ext_password.c +++ b/components/wpa_supplicant/src/utils/ext_password.c @@ -6,10 +6,10 @@ * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" -#include "wpa2/utils/ext_password_i.h" +#include "utils/common.h" +#include "ext_password_i.h" #ifdef CONFIG_EXT_PASSWORD_TEST extern struct ext_password_backend ext_password_test; diff --git a/components/wpa_supplicant/include/wpa2/utils/ext_password.h b/components/wpa_supplicant/src/utils/ext_password.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/utils/ext_password.h rename to components/wpa_supplicant/src/utils/ext_password.h diff --git a/components/wpa_supplicant/include/wpa2/utils/ext_password_i.h b/components/wpa_supplicant/src/utils/ext_password_i.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/utils/ext_password_i.h rename to components/wpa_supplicant/src/utils/ext_password_i.h diff --git a/components/wpa_supplicant/include/crypto/includes.h b/components/wpa_supplicant/src/utils/includes.h similarity index 91% rename from components/wpa_supplicant/include/crypto/includes.h rename to components/wpa_supplicant/src/utils/includes.h index 2630789818..b7a3ce9597 100644 --- a/components/wpa_supplicant/include/crypto/includes.h +++ b/components/wpa_supplicant/src/utils/includes.h @@ -19,8 +19,9 @@ #ifndef INCLUDES_H #define INCLUDES_H +#include "supplicant_opt.h" + /* Include possible build time configuration before including anything else */ -//#include "build_config.h" //don't need anymore #ifndef __ets__ #include #include @@ -44,12 +45,8 @@ #ifndef CONFIG_NATIVE_WINDOWS #ifndef CONFIG_TI_COMPILER -//#include -//#include -//#include #ifndef __vxworks #ifndef __SYMBIAN32__ -//#include #endif /* __SYMBIAN32__ */ #include #endif /* __vxworks */ diff --git a/components/wpa_supplicant/include/wpa/list.h b/components/wpa_supplicant/src/utils/list.h similarity index 100% rename from components/wpa_supplicant/include/wpa/list.h rename to components/wpa_supplicant/src/utils/list.h diff --git a/components/wpa_supplicant/include/wpa/state_machine.h b/components/wpa_supplicant/src/utils/state_machine.h similarity index 96% rename from components/wpa_supplicant/include/wpa/state_machine.h rename to components/wpa_supplicant/src/utils/state_machine.h index ce8c51e770..c75d06dca6 100644 --- a/components/wpa_supplicant/include/wpa/state_machine.h +++ b/components/wpa_supplicant/src/utils/state_machine.h @@ -30,7 +30,7 @@ * entered by calling SM_ENTER or SM_ENTER_GLOBAL. */ #define SM_STATE(machine, state) \ -static void ICACHE_FLASH_ATTR sm_ ## machine ## _ ## state ## _Enter(STATE_MACHINE_DATA *sm, \ +static void sm_ ## machine ## _ ## state ## _Enter(STATE_MACHINE_DATA *sm, \ int global) /** @@ -124,7 +124,7 @@ sm_ ## machine ## _ ## state ## _Enter(sm, 1) * SM_ENTER and SM_ENTER_GLOBAL macros to enter new state. */ #define SM_STEP(machine) \ -static void ICACHE_FLASH_ATTR sm_ ## machine ## _Step(STATE_MACHINE_DATA *sm) +static void sm_ ## machine ## _Step(STATE_MACHINE_DATA *sm) /** * SM_STEP_RUN - Call the state machine step function diff --git a/components/wpa_supplicant/src/wps/uuid.c b/components/wpa_supplicant/src/utils/uuid.c similarity index 93% rename from components/wpa_supplicant/src/wps/uuid.c rename to components/wpa_supplicant/src/utils/uuid.c index 9f46824ee8..71568aca5d 100644 --- a/components/wpa_supplicant/src/wps/uuid.c +++ b/components/wpa_supplicant/src/utils/uuid.c @@ -6,10 +6,10 @@ * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" -#include "wps/utils/uuid.h" +#include "utils/common.h" +#include "utils/uuid.h" int uuid_str2bin(const char *str, u8 *bin) { @@ -68,4 +68,4 @@ int is_nil_uuid(const u8 *uuid) if (uuid[i]) return 0; return 1; -} \ No newline at end of file +} diff --git a/components/wpa_supplicant/include/wps/utils/uuid.h b/components/wpa_supplicant/src/utils/uuid.h similarity index 100% rename from components/wpa_supplicant/include/wps/utils/uuid.h rename to components/wpa_supplicant/src/utils/uuid.h diff --git a/components/wpa_supplicant/src/utils/wpa_debug.c b/components/wpa_supplicant/src/utils/wpa_debug.c new file mode 100644 index 0000000000..aed26664eb --- /dev/null +++ b/components/wpa_supplicant/src/utils/wpa_debug.c @@ -0,0 +1,114 @@ +/* + * wpa_supplicant/hostapd / Debug prints + * Copyright (c) 2002-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ +#ifdef ESP_SUPPLICANT +#include "utils/includes.h" +#include "utils/common.h" +#include "utils/wpa_debug.h" + +static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len, int uppercase) +{ + size_t i; + char *pos = buf, *end = buf + buf_size; + int ret; + + if (buf_size == 0) + return 0; + + for (i = 0; i < len; i++) { + ret = snprintf(pos, end - pos, uppercase? "%02X":"%02x", data[i]); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return pos - buf; + } + pos += ret; + } + end[-1]='\0'; + return pos - buf; +} + +int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, size_t len) +{ + return _wpa_snprintf_hex(buf, buf_size, data, len, 1); +} + +int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len) +{ + return _wpa_snprintf_hex(buf, buf_size, data, len, 0); +} + +#ifdef DEBUG_PRINT +void wpa_dump_mem(char* desc, uint8_t *addr, uint16_t len) +{ + wpa_printf(MSG_DEBUG, "%s\n", desc); + if (addr){ + uint16_t i=0; + for (i=0; i + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "utils/wpabuf.h" +#include "stdio.h" +#include "stdarg.h" + +#ifdef WPA_TRACE +#define WPABUF_MAGIC 0x51a974e3 + +struct wpabuf_trace { + unsigned int magic; +}; + +static struct wpabuf_trace * wpabuf_get_trace(const struct wpabuf *buf) +{ + return (struct wpabuf_trace *) + ((const u8 *) buf - sizeof(struct wpabuf_trace)); +} +#endif /* WPA_TRACE */ + + +static void wpabuf_overflow(const struct wpabuf *buf, size_t len) +{ +#ifdef WPA_TRACE + struct wpabuf_trace *trace = wpabuf_get_trace(buf); + if (trace->magic != WPABUF_MAGIC) { + wpa_printf( MSG_ERROR, "wpabuf: invalid magic %x", + trace->magic); + } +#endif /* WPA_TRACE */ + wpa_printf( MSG_ERROR, "wpabuf %p (size=%lu used=%lu) overflow len=%lu", + buf, (unsigned long) buf->size, (unsigned long) buf->used, + (unsigned long) len); +} + + +int wpabuf_resize(struct wpabuf **_buf, size_t add_len) +{ + struct wpabuf *buf = *_buf; +#ifdef WPA_TRACE + struct wpabuf_trace *trace; +#endif /* WPA_TRACE */ + + if (buf == NULL) { + *_buf = wpabuf_alloc(add_len); + return *_buf == NULL ? -1 : 0; + } + +#ifdef WPA_TRACE + trace = wpabuf_get_trace(buf); + if (trace->magic != WPABUF_MAGIC) { + wpa_printf( MSG_ERROR, "wpabuf: invalid magic %x", + trace->magic); + abort(); + } +#endif /* WPA_TRACE */ + + if (buf->used + add_len > buf->size) { + unsigned char *nbuf; + if (buf->ext_data) { + nbuf = (unsigned char*)os_realloc(buf->ext_data, buf->used + add_len); + if (nbuf == NULL) + return -1; + memset(nbuf + buf->used, 0, add_len); + buf->ext_data = nbuf; + } else { +#ifdef WPA_TRACE + nbuf = os_realloc(trace, sizeof(struct wpabuf_trace) + + sizeof(struct wpabuf) + + buf->used + add_len); + if (nbuf == NULL) + return -1; + trace = (struct wpabuf_trace *) nbuf; + buf = (struct wpabuf *) (trace + 1); + memset(nbuf + sizeof(struct wpabuf_trace) + + sizeof(struct wpabuf) + buf->used, 0, + add_len); +#else /* WPA_TRACE */ + nbuf = (unsigned char*)os_realloc(buf, sizeof(struct wpabuf) + + buf->used + add_len); + if (nbuf == NULL) + return -1; + buf = (struct wpabuf *) nbuf; + memset(nbuf + sizeof(struct wpabuf) + buf->used, 0, + add_len); +#endif /* WPA_TRACE */ + *_buf = buf; + } + buf->size = buf->used + add_len; + } + + return 0; +} + + +/** + * wpabuf_alloc - Allocate a wpabuf of the given size + * @len: Length for the allocated buffer + * Returns: Buffer to the allocated wpabuf or %NULL on failure + */ +struct wpabuf * wpabuf_alloc(size_t len) +{ +#ifdef WPA_TRACE + struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) + + sizeof(struct wpabuf) + len); + struct wpabuf *buf; + if (trace == NULL) + return NULL; + trace->magic = WPABUF_MAGIC; + buf = (struct wpabuf *) (trace + 1); +#else /* WPA_TRACE */ + struct wpabuf *buf = (struct wpabuf *)os_zalloc(sizeof(struct wpabuf) + len); + if (buf == NULL) + return NULL; +#endif /* WPA_TRACE */ + + buf->size = len; + return buf; +} + + +struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len) +{ +#ifdef WPA_TRACE + struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) + + sizeof(struct wpabuf)); + struct wpabuf *buf; + if (trace == NULL) + return NULL; + trace->magic = WPABUF_MAGIC; + buf = (struct wpabuf *) (trace + 1); +#else /* WPA_TRACE */ + struct wpabuf *buf = (struct wpabuf *)os_zalloc(sizeof(struct wpabuf)); + if (buf == NULL) + return NULL; +#endif /* WPA_TRACE */ + + buf->size = len; + buf->used = len; + buf->ext_data = data; + + return buf; +} + + +struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len) +{ + struct wpabuf *buf = wpabuf_alloc(len); + if (buf) + wpabuf_put_data(buf, data, len); + return buf; +} + + +struct wpabuf * wpabuf_dup(const struct wpabuf *src) +{ + struct wpabuf *buf = wpabuf_alloc(wpabuf_len(src)); + if (buf) + wpabuf_put_data(buf, wpabuf_head(src), wpabuf_len(src)); + return buf; +} + + +/** + * wpabuf_free - Free a wpabuf + * @buf: wpabuf buffer + */ +void wpabuf_free(struct wpabuf *buf) +{ +#ifdef WPA_TRACE + struct wpabuf_trace *trace; + if (buf == NULL) + return; + trace = wpabuf_get_trace(buf); + if (trace->magic != WPABUF_MAGIC) { + wpa_printf( MSG_ERROR, "wpabuf_free: invalid magic %x", + trace->magic); + abort(); + } + os_free(buf->ext_data); + os_free(trace); +#else /* WPA_TRACE */ + if (buf == NULL) + return; + os_free(buf->ext_data); + os_free(buf); +#endif /* WPA_TRACE */ +} + + +void * wpabuf_put(struct wpabuf *buf, size_t len) +{ + void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf); + buf->used += len; + if (buf->used > buf->size) { + wpabuf_overflow(buf, len); + } + return tmp; +} + + +/** + * wpabuf_concat - Concatenate two buffers into a newly allocated one + * @a: First buffer + * @b: Second buffer + * Returns: wpabuf with concatenated a + b data or %NULL on failure + * + * Both buffers a and b will be freed regardless of the return value. Input + * buffers can be %NULL which is interpreted as an empty buffer. + */ +struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b) +{ + struct wpabuf *n = NULL; + size_t len = 0; + + if (b == NULL) + return a; + + if (a) + len += wpabuf_len(a); + if (b) + len += wpabuf_len(b); + + n = wpabuf_alloc(len); + if (n) { + if (a) + wpabuf_put_buf(n, a); + if (b) + wpabuf_put_buf(n, b); + } + + wpabuf_free(a); + wpabuf_free(b); + + return n; +} + + +/** + * wpabuf_zeropad - Pad buffer with 0x00 octets (prefix) to specified length + * @buf: Buffer to be padded + * @len: Length for the padded buffer + * Returns: wpabuf padded to len octets or %NULL on failure + * + * If buf is longer than len octets or of same size, it will be returned as-is. + * Otherwise a new buffer is allocated and prefixed with 0x00 octets followed + * by the source data. The source buffer will be freed on error, i.e., caller + * will only be responsible on freeing the returned buffer. If buf is %NULL, + * %NULL will be returned. + */ +struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len) +{ + struct wpabuf *ret; + size_t blen; + + if (buf == NULL) + return NULL; + + blen = wpabuf_len(buf); + if (blen >= len) + return buf; + + ret = wpabuf_alloc(len); + if (ret) { + memset(wpabuf_put(ret, len - blen), 0, len - blen); + wpabuf_put_buf(ret, buf); + } + wpabuf_free(buf); + + return ret; +} + +void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) +{ + va_list ap; + void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf); + int res; + + va_start(ap, fmt); + res = vsnprintf(tmp, buf->size - buf->used, fmt, ap); + va_end(ap); + if (res < 0 || (size_t) res >= buf->size - buf->used) + wpabuf_overflow(buf, res); + buf->used += res; +} diff --git a/components/wpa_supplicant/src/wps/eap_common.c b/components/wpa_supplicant/src/wps/eap_common.c deleted file mode 100644 index 640bd5a59b..0000000000 --- a/components/wpa_supplicant/src/wps/eap_common.c +++ /dev/null @@ -1,205 +0,0 @@ -/* - * EAP common peer/server definitions - * Copyright (c) 2004-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "wpa/includes.h" - -#include "wpa/common.h" -#include "wpa2/eap_peer/eap_defs.h" -#include "wpa2/eap_peer/eap_common.h" - -/** - * eap_hdr_len_valid - Validate EAP header length field - * @msg: EAP frame (starting with EAP header) - * @min_payload: Minimum payload length needed - * Returns: 1 for valid header, 0 for invalid - * - * This is a helper function that does minimal validation of EAP messages. The - * length field is verified to be large enough to include the header and not - * too large to go beyond the end of the buffer. - */ -int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload) -{ - const struct eap_hdr *hdr; - size_t len; - - if (msg == NULL) - return 0; - - hdr = wpabuf_head(msg); - - if (wpabuf_len(msg) < sizeof(*hdr)) { - wpa_printf(MSG_INFO, "EAP: Too short EAP frame"); - return 0; - } - - len = be_to_host16(hdr->length); - if (len < sizeof(*hdr) + min_payload || len > wpabuf_len(msg)) { - wpa_printf(MSG_INFO, "EAP: Invalid EAP length"); - return 0; - } - - return 1; -} - - -/** - * eap_hdr_validate - Validate EAP header - * @vendor: Expected EAP Vendor-Id (0 = IETF) - * @eap_type: Expected EAP type number - * @msg: EAP frame (starting with EAP header) - * @plen: Pointer to variable to contain the returned payload length - * Returns: Pointer to EAP payload (after type field), or %NULL on failure - * - * This is a helper function for EAP method implementations. This is usually - * called in the beginning of struct eap_method::process() function to verify - * that the received EAP request packet has a valid header. This function is - * able to process both legacy and expanded EAP headers and in most cases, the - * caller can just use the returned payload pointer (into *plen) for processing - * the payload regardless of whether the packet used the expanded EAP header or - * not. - */ -const u8 * eap_hdr_validate(int vendor, EapType eap_type, - const struct wpabuf *msg, size_t *plen) -{ - const struct eap_hdr *hdr; - const u8 *pos; - size_t len; - - if (!eap_hdr_len_valid(msg, 1)) - return NULL; - - hdr = wpabuf_head(msg); - len = be_to_host16(hdr->length); - pos = (const u8 *) (hdr + 1); - - if (*pos == EAP_TYPE_EXPANDED) { - int exp_vendor; - u32 exp_type; - if (len < sizeof(*hdr) + 8) { - wpa_printf(MSG_INFO, "EAP: Invalid expanded EAP " - "length"); - return NULL; - } - pos++; - exp_vendor = WPA_GET_BE24(pos); - pos += 3; - exp_type = WPA_GET_BE32(pos); - pos += 4; - if (exp_vendor != vendor || exp_type != (u32) eap_type) { - wpa_printf(MSG_INFO, "EAP: Invalid expanded frame " - "type"); - return NULL; - } - - *plen = len - sizeof(*hdr) - 8; - return pos; - } else { - if (vendor != EAP_VENDOR_IETF || *pos != eap_type) { - wpa_printf(MSG_INFO, "EAP: Invalid frame type"); - return NULL; - } - *plen = len - sizeof(*hdr) - 1; - return pos + 1; - } -} - - -/** - * eap_msg_alloc - Allocate a buffer for an EAP message - * @vendor: Vendor-Id (0 = IETF) - * @type: EAP type - * @payload_len: Payload length in bytes (data after Type) - * @code: Message Code (EAP_CODE_*) - * @identifier: Identifier - * Returns: Pointer to the allocated message buffer or %NULL on error - * - * This function can be used to allocate a buffer for an EAP message and fill - * in the EAP header. This function is automatically using expanded EAP header - * if the selected Vendor-Id is not IETF. In other words, most EAP methods do - * not need to separately select which header type to use when using this - * function to allocate the message buffers. The returned buffer has room for - * payload_len bytes and has the EAP header and Type field already filled in. - */ -struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len, - u8 code, u8 identifier) -{ - struct wpabuf *buf; - struct eap_hdr *hdr; - size_t len; - - len = sizeof(struct eap_hdr) + (vendor == EAP_VENDOR_IETF ? 1 : 8) + - payload_len; - buf = wpabuf_alloc(len); - if (buf == NULL) - return NULL; - - hdr = wpabuf_put(buf, sizeof(*hdr)); - hdr->code = code; - hdr->identifier = identifier; - hdr->length = host_to_be16(len); - - if (vendor == EAP_VENDOR_IETF) { - wpabuf_put_u8(buf, type); - } else { - wpabuf_put_u8(buf, EAP_TYPE_EXPANDED); - wpabuf_put_be24(buf, vendor); - wpabuf_put_be32(buf, type); - } - - return buf; -} - - -/** - * eap_update_len - Update EAP header length - * @msg: EAP message from eap_msg_alloc - * - * This function updates the length field in the EAP header to match with the - * current length for the buffer. This allows eap_msg_alloc() to be used to - * allocate a larger buffer than the exact message length (e.g., if exact - * message length is not yet known). - */ -void eap_update_len(struct wpabuf *msg) -{ - struct eap_hdr *hdr; - hdr = wpabuf_mhead(msg); - if (wpabuf_len(msg) < sizeof(*hdr)) - return; - hdr->length = host_to_be16(wpabuf_len(msg)); -} - - -/** - * eap_get_id - Get EAP Identifier from wpabuf - * @msg: Buffer starting with an EAP header - * Returns: The Identifier field from the EAP header - */ -u8 eap_get_id(const struct wpabuf *msg) -{ - const struct eap_hdr *eap; - - if (wpabuf_len(msg) < sizeof(*eap)) - return 0; - - eap = wpabuf_head(msg); - return eap->identifier; -} - - -/** - * eap_get_id - Get EAP Type from wpabuf - * @msg: Buffer starting with an EAP header - * Returns: The EAP Type after the EAP header - */ -EapType eap_get_type(const struct wpabuf *msg) -{ - if (wpabuf_len(msg) < sizeof(struct eap_hdr) + 1) - return EAP_TYPE_NONE; - - return ((const u8 *) wpabuf_head(msg))[sizeof(struct eap_hdr)]; -} \ No newline at end of file diff --git a/components/wpa_supplicant/src/wps/wps.c b/components/wpa_supplicant/src/wps/wps.c index 2ed83bbf6f..1700f0f4b1 100644 --- a/components/wpa_supplicant/src/wps/wps.c +++ b/components/wpa_supplicant/src/wps/wps.c @@ -7,20 +7,20 @@ */ #include -#include "wpa/includes.h" -#include "wpa/wpa.h" -#include "wpa/common.h" -#include "wpa/eapol_common.h" -#include "wpa/wpa_debug.h" -#include "wpa/ieee802_11_defs.h" +#include "utils/includes.h" +#include "rsn_supp/wpa.h" +#include "utils/common.h" +#include "common/eapol_common.h" +#include "utils/wpa_debug.h" +#include "common/ieee802_11_defs.h" #include "crypto/dh_group5.h" #include "wps/wps_i.h" #include "wps/wps_dev_attr.h" -#include "wpa2/eap_peer/eap_defs.h" -#include "wpa2/eap_peer/eap_common.h" +#include "eap_peer/eap_defs.h" +#include "eap_peer/eap_common.h" /** @@ -109,16 +109,7 @@ int wps_is_selected_pbc_registrar(const struct wpabuf *msg, u8 *bssid) os_free(attr); return 0; } -#if 0 -#ifdef CONFIG_WPS_STRICT - if (!attr->sel_reg_config_methods || - !(WPA_GET_BE16(attr->sel_reg_config_methods) & - WPS_CONFIG_PUSHBUTTON)) { - os_free(attr); - return 0; - } -#endif /* CONFIG_WPS_STRICT */ -#endif + os_free(attr); return 1; } @@ -160,9 +151,7 @@ static int is_selected_pin_registrar(struct wps_parse_attr *attr, u8 *bssid) return 0; } #ifdef CONFIG_WPS_STRICT - if (!attr->sel_reg_config_methods)// || - //!(WPA_GET_BE16(attr->sel_reg_config_methods) & - //(WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD))) + if (!attr->sel_reg_config_methods) return 0; #endif /* CONFIG_WPS_STRICT */ return 1; diff --git a/components/wpa_supplicant/include/wps/wps.h b/components/wpa_supplicant/src/wps/wps.h similarity index 98% rename from components/wpa_supplicant/include/wps/wps.h rename to components/wpa_supplicant/src/wps/wps.h index 7249d6eee8..ab2eb00bda 100644 --- a/components/wpa_supplicant/include/wps/wps.h +++ b/components/wpa_supplicant/src/wps/wps.h @@ -27,7 +27,6 @@ enum wsc_op_code { }; struct wps_registrar; -//struct upnp_wps_device_sm; struct wps_er; struct wps_parse_attr; @@ -192,10 +191,8 @@ struct discard_ap_list_t{ u8 bssid[6]; }; -//struct wps_data * wps_init(const struct wps_config *cfg); struct wps_data * wps_init(void); -//void wps_deinit(struct wps_data *data); void wps_deinit(void); /** @@ -747,10 +744,7 @@ struct wps_context { */ void *cb_ctx; - //struct upnp_wps_device_sm *wps_upnp; - /* Pending messages from UPnP PutWLANResponse */ - //struct upnp_pending_message *upnp_msgs; #ifdef CONFIG_WPS_NFC u16 ap_nfc_dev_pw_id; @@ -798,11 +792,11 @@ int wps_registrar_add_nfc_password_token(struct wps_registrar *reg, int wps_build_credential_wrap(struct wpabuf *msg, const struct wps_credential *cred); #ifdef CONFIG_WPS_PIN - unsigned int wps_pin_checksum(unsigned int pin); unsigned int wps_pin_valid(unsigned int pin); int wps_pin_str_valid(const char *pin); #endif + unsigned int wps_generate_pin(void); #ifdef CONFIG_WPS_OOB @@ -1009,9 +1003,18 @@ enum wps_cb_status { typedef void (*wps_st_cb_t)(int status); #ifdef USE_WPS_TASK -#define SIG_WPS_START 2 -#define SIG_WPS_RX 3 -#define SIG_WPS_NUM 9 +enum wps_sig_type { + SIG_WPS_ENABLE = 1, //1 + SIG_WPS_DISABLE, //2 + SIG_WPS_START, //3 + SIG_WPS_RX, //4 + SIG_WPS_TIMER_TIMEOUT, //5 + SIG_WPS_TIMER_MSG_TIMEOUT, //6 + SIG_WPS_TIMER_SUCCESS_CB, //7 + SIG_WPS_TIMER_SCAN, //8 + SIG_WPS_TIMER_EAPOL_START, //9 + SIG_WPS_NUM, //10 +}; #endif #define WPS_EAP_EXT_VENDOR_TYPE "WFA-SimpleConfig-Enrollee-1-0" @@ -1051,7 +1054,7 @@ struct wps_sm { wifi_sta_config_t config; }; -#define IEEE80211_CAPINFO_PRIVACY 0x0010 +#define WIFI_CAPINFO_PRIVACY 0x0010 struct wps_sm *wps_sm_get(void); int wps_ssid_save(u8 *ssid, u8 ssid_len); diff --git a/components/wpa_supplicant/src/wps/wps_attr_build.c b/components/wpa_supplicant/src/wps/wps_attr_build.c index 602d77fc50..d57096af11 100644 --- a/components/wpa_supplicant/src/wps/wps_attr_build.c +++ b/components/wpa_supplicant/src/wps/wps_attr_build.c @@ -5,9 +5,9 @@ * This software may be distributed under the terms of the BSD license. * See README for more details. */ -#include "wpa/includes.h" -#include "wpa/common.h" -#include "wpa/wpa_debug.h" +#include "utils/includes.h" +#include "utils/common.h" +#include "utils/wpa_debug.h" #include "crypto/aes_wrap.h" #include "crypto/crypto.h" @@ -15,7 +15,7 @@ #include "crypto/sha256.h" #include "crypto/random.h" -#include "wpa/ieee802_11_defs.h" +#include "common/ieee802_11_defs.h" #include "wps/wps_i.h" int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg, wps_key_mode_t mode) @@ -166,12 +166,7 @@ int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg) len[0] = wpabuf_len(wps->last_msg); addr[1] = wpabuf_head(msg); len[1] = wpabuf_len(msg); - if (wps_crypto_funcs.hmac_sha256_vector) { - wps_crypto_funcs.hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, (int *)len, hash); - } else { - wpa_printf(MSG_ERROR, "Fail to register hmac sha256 vector!\r\n"); - return -1; - } + fast_hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash); wpa_printf(MSG_DEBUG, "WPS: * Authenticator"); wpabuf_put_be16(msg, ATTR_AUTHENTICATOR); wpabuf_put_be16(msg, WPS_AUTHENTICATOR_LEN); @@ -329,13 +324,8 @@ int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg) u8 hash[SHA256_MAC_LEN]; wpa_printf(MSG_DEBUG, "WPS: * Key Wrap Authenticator"); - if (wps_crypto_funcs.hmac_sha256) { - wps_crypto_funcs.hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg), - wpabuf_len(msg), hash); - } else { - wpa_printf(MSG_ERROR, "Fail to register hmac sha256 function!\r\n"); - return -1; - } + fast_hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg), + wpabuf_len(msg), hash); wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH); wpabuf_put_be16(msg, WPS_KWA_LEN); wpabuf_put_data(msg, hash, WPS_KWA_LEN); @@ -366,13 +356,8 @@ int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg, data = wpabuf_put(msg, 0); wpabuf_put_buf(msg, plain); wpa_printf(MSG_DEBUG, "WPS: * AES 128 Encrypted Settings"); - if (wps_crypto_funcs.aes_128_encrypt) { - if (wps_crypto_funcs.aes_128_encrypt(wps->keywrapkey, iv, data, wpabuf_len(plain))) - return -1; - } else { - wpa_printf(MSG_ERROR, "Fail to register aes_128_encrypt function!\r\n"); + if (fast_aes_128_cbc_encrypt(wps->keywrapkey, iv, data, wpabuf_len(plain))) return -1; - } return 0; } @@ -388,12 +373,7 @@ int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id, addr[0] = wpabuf_head(pubkey); hash_len = wpabuf_len(pubkey); - if (wps_crypto_funcs.sha256_vector) { - wps_crypto_funcs.sha256_vector(1, addr, &hash_len, pubkey_hash); - } else { - wpa_printf(MSG_ERROR, "Fail to register sha256 vector function!\r\n"); - return -1; - } + fast_sha256_vector(1, addr, &hash_len, pubkey_hash); wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD); wpabuf_put_be16(msg, WPS_OOB_PUBKEY_HASH_LEN + 2 + dev_pw_len); wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN); diff --git a/components/wpa_supplicant/src/wps/wps_attr_parse.c b/components/wpa_supplicant/src/wps/wps_attr_parse.c index a8cf76683d..dfe9b5359d 100644 --- a/components/wpa_supplicant/src/wps/wps_attr_parse.c +++ b/components/wpa_supplicant/src/wps/wps_attr_parse.c @@ -5,9 +5,9 @@ * This software may be distributed under the terms of the BSD license. * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" +#include "utils/common.h" #include "wps/wps_defs.h" #include "wps/wps_attr_parse.h" diff --git a/components/wpa_supplicant/include/wps/wps_attr_parse.h b/components/wpa_supplicant/src/wps/wps_attr_parse.h similarity index 100% rename from components/wpa_supplicant/include/wps/wps_attr_parse.h rename to components/wpa_supplicant/src/wps/wps_attr_parse.h diff --git a/components/wpa_supplicant/src/wps/wps_attr_process.c b/components/wpa_supplicant/src/wps/wps_attr_process.c index cd2c6d4b40..15df0360a5 100644 --- a/components/wpa_supplicant/src/wps/wps_attr_process.c +++ b/components/wpa_supplicant/src/wps/wps_attr_process.c @@ -5,9 +5,9 @@ * This software may be distributed under the terms of the BSD license. * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/sha256.h" #include "wps/wps_i.h" @@ -38,12 +38,7 @@ int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator, len[0] = wpabuf_len(wps->last_msg); addr[1] = wpabuf_head(msg); len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN; - if (wps_crypto_funcs.hmac_sha256_vector) { - wps_crypto_funcs.hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, (int *)len, hash); - } else { - wpa_printf(MSG_ERROR, "Fail to register hmac_sha256_vector function!\r\n"); - return -1; - } + fast_hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash); if (os_memcmp(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) { wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator"); return -1; @@ -73,12 +68,7 @@ int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg, return -1; } - if (wps_crypto_funcs.hmac_sha256) { - wps_crypto_funcs.hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash); - } else { - wpa_printf(MSG_ERROR, "Fail to register hmac sha256 function!\r\n"); - return -1; - } + fast_hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash); if (os_memcmp(hash, key_wrap_auth, WPS_KWA_LEN) != 0) { wpa_printf(MSG_DEBUG, "WPS: Invalid KWA"); return -1; diff --git a/components/wpa_supplicant/src/wps/wps_common.c b/components/wpa_supplicant/src/wps/wps_common.c index 8a462a4983..8eaf3e9c12 100644 --- a/components/wpa_supplicant/src/wps/wps_common.c +++ b/components/wpa_supplicant/src/wps/wps_common.c @@ -7,8 +7,8 @@ */ #include -#include "wpa/includes.h" -#include "wpa/common.h" +#include "utils/includes.h" +#include "utils/common.h" #include "crypto/aes_wrap.h" #include "crypto/crypto.h" @@ -46,12 +46,7 @@ void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len, for (i = 1; i <= iter; i++) { WPA_PUT_BE32(i_buf, i); - if (wps_crypto_funcs.hmac_sha256_vector) { - wps_crypto_funcs.hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, (int *)len, hash); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to reigster hmac sha256 vector function!\r\n", __FUNCTION__); - return ; - } + fast_hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, len, hash); if (i < iter) { os_memcpy(opos, hash, SHA256_MAC_LEN); opos += SHA256_MAC_LEN; @@ -108,12 +103,7 @@ int wps_derive_keys(struct wps_data *wps) addr[0] = wpabuf_head(dh_shared); len[0] = wpabuf_len(dh_shared); - if (wps_crypto_funcs.sha256_vector) { - wps_crypto_funcs.sha256_vector(1, addr, (int *)len, dhkey); - } else { - wpa_printf(MSG_ERROR, "In function %s, Fail to register sha256 vector function!\r\n", __FUNCTION__); - return -1; - } + fast_sha256_vector(1, addr, len, dhkey); wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey)); wpabuf_free(dh_shared); @@ -124,12 +114,7 @@ int wps_derive_keys(struct wps_data *wps) len[1] = ETH_ALEN; addr[2] = wps->nonce_r; len[2] = WPS_NONCE_LEN; - if (wps_crypto_funcs.hmac_sha256_vector) { - wps_crypto_funcs.hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, (int *)len, kdk); - } else { - wpa_printf(MSG_ERROR, "In function %s, Fail to register hmac sha256 vector function!\r\n", __FUNCTION__); - return -1; - } + fast_hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk); wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk)); wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation", @@ -154,22 +139,12 @@ void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd, { u8 hash[SHA256_MAC_LEN]; - if (wps_crypto_funcs.hmac_sha256) { - wps_crypto_funcs.hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd, + fast_hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd, (dev_passwd_len + 1) / 2, hash); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register hmac_sha256 function!\r\n", __FUNCTION__); - return ; - } os_memcpy(wps->psk1, hash, WPS_PSK_LEN); - if (wps_crypto_funcs.hmac_sha256) { - wps_crypto_funcs.hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, - dev_passwd + (dev_passwd_len + 1) / 2, - dev_passwd_len / 2, hash); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register hmac_sha256 function!\r\n", __FUNCTION__); - return ; - } + fast_hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, + dev_passwd + (dev_passwd_len + 1) / 2, + dev_passwd_len / 2, hash); os_memcpy(wps->psk2, hash, WPS_PSK_LEN); wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Device Password", @@ -202,14 +177,9 @@ struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr, wpa_hexdump(MSG_MSGDUMP, "WPS: Encrypted Settings", encr, encr_len); wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size); wpa_printf(MSG_DEBUG, "WPS: AES Decrypt setting"); - if (wps_crypto_funcs.aes_128_decrypt) { - if (wps_crypto_funcs.aes_128_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted), - wpabuf_len(decrypted))) { - wpabuf_free(decrypted); - return NULL; - } - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register aes 128 decrypt function!\r\n", __FUNCTION__); + if (fast_aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted), + wpabuf_len(decrypted))) { + wpabuf_free(decrypted); return NULL; } diff --git a/components/wpa_supplicant/include/wps/wps_defs.h b/components/wpa_supplicant/src/wps/wps_defs.h similarity index 100% rename from components/wpa_supplicant/include/wps/wps_defs.h rename to components/wpa_supplicant/src/wps/wps_defs.h diff --git a/components/wpa_supplicant/src/wps/wps_dev_attr.c b/components/wpa_supplicant/src/wps/wps_dev_attr.c index 89a14c98ba..9ef2fde03b 100644 --- a/components/wpa_supplicant/src/wps/wps_dev_attr.c +++ b/components/wpa_supplicant/src/wps/wps_dev_attr.c @@ -5,8 +5,8 @@ * This software may be distributed under the terms of the BSD license. * See README for more details. */ -#include "wpa/includes.h" -#include "wpa/common.h" +#include "utils/includes.h" +#include "utils/common.h" #include "wps/wps_i.h" #include "wps/wps_dev_attr.h" @@ -352,20 +352,12 @@ static int wps_process_dev_name(struct wps_device_data *dev, const u8 *str, static int wps_process_primary_dev_type(struct wps_device_data *dev, const u8 *dev_type) { -#if 0 -#ifndef CONFIG_NO_STDOUT_DEBUG - char devtype[WPS_DEV_TYPE_BUFSIZE]; -#endif /* CONFIG_NO_STDOUT_DEBUG */ -#endif if (dev_type == NULL) { wpa_printf(MSG_DEBUG, "WPS: No Primary Device Type received"); return -1; } os_memcpy(dev->pri_dev_type, dev_type, WPS_DEV_TYPE_LEN); - //wpa_printf(MSG_DEBUG, "WPS: Primary Device Type: %s", - // wps_dev_type_bin2str(dev->pri_dev_type, devtype, - // sizeof(devtype))); return 0; } diff --git a/components/wpa_supplicant/include/wps/wps_dev_attr.h b/components/wpa_supplicant/src/wps/wps_dev_attr.h similarity index 100% rename from components/wpa_supplicant/include/wps/wps_dev_attr.h rename to components/wpa_supplicant/src/wps/wps_dev_attr.h diff --git a/components/wpa_supplicant/src/wps/wps_enrollee.c b/components/wpa_supplicant/src/wps/wps_enrollee.c index b3890c4e86..ffe4d5789b 100644 --- a/components/wpa_supplicant/src/wps/wps_enrollee.c +++ b/components/wpa_supplicant/src/wps/wps_enrollee.c @@ -7,9 +7,9 @@ */ #include "esp32/rom/ets_sys.h" -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/crypto.h" #include "crypto/sha256.h" #include "crypto/random.h" @@ -74,12 +74,7 @@ static int wps_build_e_hash(struct wps_data *wps, struct wpabuf *msg) len[2] = wpabuf_len(wps->dh_pubkey_e); addr[3] = wpabuf_head(wps->dh_pubkey_r); len[3] = wpabuf_len(wps->dh_pubkey_r); - if (wps_crypto_funcs.hmac_sha256_vector) { - wps_crypto_funcs.hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, (int *)len, hash); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register hmac_sha256_vector function!\r\n", __FUNCTION__); - return -1; - } + fast_hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); wpa_hexdump(MSG_DEBUG, "WPS: E-Hash1", hash, SHA256_MAC_LEN); wpa_printf(MSG_DEBUG, "WPS: * E-Hash2"); @@ -89,12 +84,7 @@ static int wps_build_e_hash(struct wps_data *wps, struct wpabuf *msg) /* E-Hash2 = HMAC_AuthKey(E-S2 || PSK2 || PK_E || PK_R) */ addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN; addr[1] = wps->psk2; - if (wps_crypto_funcs.hmac_sha256_vector) { - wps_crypto_funcs.hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, (int *)len, hash); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register hmac_sha256_vector function!\r\n", __FUNCTION__); - return -1; - } + fast_hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); wpa_hexdump(MSG_DEBUG, "WPS: E-Hash2", hash, SHA256_MAC_LEN); return 0; @@ -603,12 +593,7 @@ static int wps_process_r_snonce1(struct wps_data *wps, const u8 *r_snonce1) addr[3] = wpabuf_head(wps->dh_pubkey_r); len[3] = wpabuf_len(wps->dh_pubkey_r); - if (wps_crypto_funcs.hmac_sha256_vector) { - wps_crypto_funcs.hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, (int *)len, hash); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register hmac_sha256_vector function!\r\n", __FUNCTION__); - return -1; - } + fast_hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) { wpa_printf(MSG_DEBUG, "WPS: R-Hash1 derived from R-S1 does " "not match with the pre-committed value"); @@ -648,12 +633,7 @@ static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2) addr[3] = wpabuf_head(wps->dh_pubkey_r); len[3] = wpabuf_len(wps->dh_pubkey_r); - if (wps_crypto_funcs.hmac_sha256_vector) { - wps_crypto_funcs.hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, (int *)len, hash); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to regiset hmac_sha256_vector function!\r\n", __FUNCTION__); - return -1; - } + fast_hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) { wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does " diff --git a/components/wpa_supplicant/include/wps/wps_i.h b/components/wpa_supplicant/src/wps/wps_i.h similarity index 99% rename from components/wpa_supplicant/include/wps/wps_i.h rename to components/wpa_supplicant/src/wps/wps_i.h index c20d5ef917..5cdd51ec3c 100644 --- a/components/wpa_supplicant/include/wps/wps_i.h +++ b/components/wpa_supplicant/src/wps/wps_i.h @@ -11,6 +11,7 @@ #include "wps.h" #include "wps_attr_parse.h" +#include "esp_wps.h" #include "esp_wifi_crypto_types.h" #ifdef CONFIG_WPS_NFC @@ -124,8 +125,6 @@ struct wps_data { #endif }; -wps_crypto_funcs_t wps_crypto_funcs; - /* wps_common.c */ void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len, const char *label, u8 *res, size_t res_len); diff --git a/components/wpa_supplicant/src/wps/wps_registrar.c b/components/wpa_supplicant/src/wps/wps_registrar.c index a38a75d1fe..3293ef6263 100644 --- a/components/wpa_supplicant/src/wps/wps_registrar.c +++ b/components/wpa_supplicant/src/wps/wps_registrar.c @@ -5,21 +5,18 @@ * This software may be distributed under the terms of the BSD license. * See README for more details. */ -#include "wpa/includes.h" -#include "wpa/list.h" -#include "wpa/common.h" -#include "crypto/base64.h" -//#include "utils/eloop.h" -#include "wps/utils/uuid.h" -#include "wpa/list.h" +#include "utils/includes.h" +#include "utils/list.h" +#include "utils/common.h" +#include "utils/base64.h" +#include "utils/uuid.h" +#include "utils/list.h" #include "crypto/crypto.h" #include "crypto/sha256.h" #include "crypto/random.h" -#include "wpa/ieee802_11_defs.h" +#include "common/ieee802_11_defs.h" #include "wps/wps_i.h" #include "wps/wps_dev_attr.h" -//#include "wps/wps_upnp.h" -//#include "wps/wps_upnp_i.h" #ifndef CONFIG_WPS_STRICT #define WPS_WORKAROUNDS @@ -188,11 +185,7 @@ struct wps_registrar { static int wps_set_ie(struct wps_registrar *reg); -//static void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx); -//static void wps_registrar_set_selected_timeout(void *eloop_ctx, -// void *timeout_ctx); static void wps_registrar_pbc_timeout(void *eloop_ctx); -//static void wps_registrar_set_selected_timeout(void *eloop_ctx); #ifdef CONFIG_WPS_PIN @@ -695,12 +688,6 @@ void wps_registrar_deinit(struct wps_registrar *reg) { if (reg == NULL) return; - //eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL); - //eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL); - - // TODO: snake to check, no sys_untimeout now, by wujg -// sys_untimeout(wps_registrar_pbc_timeout, reg); -// sys_untimeout(wps_registrar_set_selected_timeout, reg); #ifdef CONFIG_WPS_PIN wps_free_pins(®->pins); @@ -787,10 +774,6 @@ int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr, wps_registrar_add_authorized_mac( reg, (u8 *) "\xff\xff\xff\xff\xff\xff"); wps_registrar_selected_registrar_changed(reg); - //eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL); - //eloop_register_timeout(WPS_PBC_WALK_TIME, 0, - //wps_registrar_set_selected_timeout, - //reg, NULL); return 0; } @@ -975,7 +958,6 @@ static void wps_registrar_stop_pbc(struct wps_registrar *reg) } -//static void ICACHE_FLASH_ATTR wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx) static void wps_registrar_pbc_timeout(void *eloop_ctx) { struct wps_registrar *reg = eloop_ctx; @@ -1022,17 +1004,6 @@ int wps_registrar_button_pushed(struct wps_registrar *reg, (u8 *) "\xff\xff\xff\xff\xff\xff"); wps_registrar_selected_registrar_changed(reg); - //eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL); - //eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL); - - // TODO: snake to check, no sys_untimeout now, by wujg -// sys_untimeout(wps_registrar_set_selected_timeout, reg); -// sys_untimeout(wps_registrar_pbc_timeout, reg); - - //eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wps_registrar_pbc_timeout, - // reg, NULL); -// sys_timeout(WPS_PBC_WALK_TIME*1000, wps_registrar_pbc_timeout, reg); - return 0; } @@ -1041,10 +1012,6 @@ static void wps_registrar_pbc_completed(struct wps_registrar *reg) { wpa_printf(MSG_DEBUG, "WPS: PBC completed - stopping PBC mode"); - // TODO: snake to check, no sys_untimeout now, by wujg - //eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL); -// sys_untimeout(wps_registrar_pbc_timeout, reg); - wps_registrar_stop_pbc(reg); } @@ -1053,7 +1020,6 @@ static void wps_registrar_pbc_completed(struct wps_registrar *reg) static void wps_registrar_pin_completed(struct wps_registrar *reg) { wpa_printf(MSG_DEBUG, "WPS: PIN completed using internal Registrar"); - //eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL); reg->selected_registrar = 0; wps_registrar_selected_registrar_changed(reg); } @@ -1088,13 +1054,8 @@ int wps_registrar_wps_cancel(struct wps_registrar *reg) { if (reg->pbc) { wpa_printf(MSG_DEBUG, "WPS: PBC is set - cancelling it"); - //wps_registrar_pbc_timeout(reg, NULL); - //eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL); wps_registrar_pbc_timeout(reg); - // TODO: snake to check, no sys_untimeout now, by wujg -// sys_untimeout(wps_registrar_pbc_timeout, reg); - return 1; } else if (reg->selected_registrar) { #ifdef CONFIG_WPS_PIN @@ -1466,12 +1427,7 @@ static int wps_build_r_hash(struct wps_data *wps, struct wpabuf *msg) len[2] = wpabuf_len(wps->dh_pubkey_e); addr[3] = wpabuf_head(wps->dh_pubkey_r); len[3] = wpabuf_len(wps->dh_pubkey_r); - if (wps_crypto_funcs.hmac_sha256_vector) { - wps_crypto_funcs.hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, (int *)len, hash); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register hmac_sha256_vector function!\r\n", __FUNCTION__); - return -1; - } + fast_hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); wpa_hexdump(MSG_DEBUG, "WPS: R-Hash1", hash, SHA256_MAC_LEN); wpa_printf(MSG_DEBUG, "WPS: * R-Hash2"); @@ -1481,12 +1437,7 @@ static int wps_build_r_hash(struct wps_data *wps, struct wpabuf *msg) /* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */ addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN; addr[1] = wps->psk2; - if (wps_crypto_funcs.hmac_sha256_vector) { - wps_crypto_funcs.hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, (int *)len, hash); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register hmac_sha256_vector function!\r\n", __FUNCTION__); - return -1; - } + fast_hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); wpa_hexdump(MSG_DEBUG, "WPS: R-Hash2", hash, SHA256_MAC_LEN); return 0; @@ -1689,7 +1640,6 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) if (random_get_bytes(r, sizeof(r)) < 0) return -1; os_free(wps->new_psk); - //wps->new_psk = base64_encode(r, sizeof(r), &wps->new_psk_len); if (wps->new_psk == NULL) return -1; wps->new_psk_len--; /* remove newline */ @@ -1703,7 +1653,6 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) } else if (wps->use_psk_key && wps->wps->psk_set) { char hex[65]; wpa_printf(MSG_DEBUG, "WPS: Use PSK format for Network Key"); - //wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, 32); os_memcpy(wps->cred.key, hex, 32 * 2); wps->cred.key_len = 32 * 2; } else if (wps->wps->network_key) { @@ -1725,8 +1674,6 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) } wpa_hexdump_key(MSG_DEBUG, "WPS: Generated per-device PSK", wps->new_psk, wps->new_psk_len); - //wpa_snprintf_hex(hex, sizeof(hex), wps->new_psk, - // wps->new_psk_len); os_memcpy(wps->cred.key, hex, wps->new_psk_len * 2); wps->cred.key_len = wps->new_psk_len * 2; } @@ -2223,12 +2170,7 @@ static int wps_process_e_snonce1(struct wps_data *wps, const u8 *e_snonce1) len[2] = wpabuf_len(wps->dh_pubkey_e); addr[3] = wpabuf_head(wps->dh_pubkey_r); len[3] = wpabuf_len(wps->dh_pubkey_r); - if (wps_crypto_funcs.hmac_sha256_vector) { - wps_crypto_funcs.hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, (int *)len, hash); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register hmac_sha256_vector function!\r\n", __FUNCTION__); - return -1; - } + fast_hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) { wpa_printf(MSG_DEBUG, "WPS: E-Hash1 derived from E-S1 does " "not match with the pre-committed value"); @@ -2268,12 +2210,7 @@ static int wps_process_e_snonce2(struct wps_data *wps, const u8 *e_snonce2) addr[3] = wpabuf_head(wps->dh_pubkey_r); len[3] = wpabuf_len(wps->dh_pubkey_r); - if (wps_crypto_funcs.hmac_sha256_vector) { - wps_crypto_funcs.hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, (int *)len, hash); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register hmac_sha256_vector function!\r\n", __FUNCTION__); - return -1; - } + fast_hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) { wpa_printf(MSG_DEBUG, "WPS: E-Hash2 derived from E-S2 does " "not match with the pre-committed value"); @@ -2610,12 +2547,7 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps, wps->nfc_pw_token = token; addr[0] = attr->public_key; - if (wps_crypto_funcs.sha256_vector) { - wps_crypto_funcs.sha256_vector(1, addr, &attr->public_key_len, hash); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to register sha256_vector function!\r\n", __FUNCTION__); - return WPS_FAILURE; - } + fast_sha256_vector(1, addr, &attr->public_key_len, hash); if (os_memcmp(hash, wps->nfc_pw_token->pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN) != 0) { wpa_printf(MSG_ERROR, "WPS: Public Key hash " @@ -3161,8 +3093,6 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps, wpa_printf(MSG_DEBUG, "WPS: Received WSC_Done"); - //if (wps->state != RECV_DONE && - // (!wps->wps->wps_upnp || !wps->ext_reg)) if (wps->state != RECV_DONE && (!wps->ext_reg)){ wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " "receiving WSC_Done", wps->state); @@ -3353,21 +3283,6 @@ int wps_registrar_update_ie(struct wps_registrar *reg) } -//static void ICACHE_FLASH_ATTR wps_registrar_set_selected_timeout(void *eloop_ctx, -// void *timeout_ctx) -#if 0 -static void wps_registrar_set_selected_timeout(void *eloop_ctx) -{ - struct wps_registrar *reg = eloop_ctx; - - wpa_printf(MSG_DEBUG, "WPS: Selected Registrar timeout - " - "unselect internal Registrar"); - reg->selected_registrar = 0; - reg->pbc = 0; - wps_registrar_selected_registrar_changed(reg); -} -#endif - #ifdef CONFIG_WPS_UPNP static void wps_registrar_sel_reg_add(struct wps_registrar *reg, struct subscription *s) @@ -3582,12 +3497,6 @@ int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg, wps_registrar_add_authorized_mac(reg, (u8 *) "\xff\xff\xff\xff\xff\xff"); wps_registrar_selected_registrar_changed(reg); - #if 0 - eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL); - eloop_register_timeout(WPS_PBC_WALK_TIME, 0, - wps_registrar_set_selected_timeout, - reg, NULL); - #endif return 0; } diff --git a/components/wpa_supplicant/src/wps/wps_validate.c b/components/wpa_supplicant/src/wps/wps_validate.c index 7f2ad5eeb6..34f0865b11 100644 --- a/components/wpa_supplicant/src/wps/wps_validate.c +++ b/components/wpa_supplicant/src/wps/wps_validate.c @@ -5,9 +5,9 @@ * This software may be distributed under the terms of the BSD license. * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" +#include "utils/common.h" #include "wps/wps_i.h" #include "wps/wps.h" diff --git a/components/wpa_supplicant/tags b/components/wpa_supplicant/tags new file mode 100644 index 0000000000..781b954521 --- /dev/null +++ b/components/wpa_supplicant/tags @@ -0,0 +1,5454 @@ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ +!_TAG_PROGRAM_NAME Exuberant Ctags // +!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ +!_TAG_PROGRAM_VERSION 5.9~svn20110310 // +ACCEPT_UNLESS_DENIED src/ap/ap_config.h /^ ACCEPT_UNLESS_DENIED = 0,$/;" e enum:hostapd_bss_config::__anon17 +ACK_FINISHED src/tls/tlsv1_client_i.h /^ SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, ACK_FINISHED,$/;" e enum:tlsv1_client::__anon43 +AES_BLOCK_SIZE include/crypto/aes.h 18;" d +AES_H include/crypto/aes.h 16;" d +AES_I_H src/crypto/aes_i.h 16;" d +AES_PRIV_NR_POS src/crypto/aes_i.h 127;" d +AES_PRIV_SIZE src/crypto/aes_i.h 126;" d +AES_SMALL_TABLES src/crypto/aes-internal.c 57;" d file: +AES_SMALL_TABLES src/crypto/aes_i.h 21;" d +AES_WRAP_H include/crypto/aes_wrap.h 23;" d +ALG_AES_CMAC src/common/defs.h /^ ALG_AES_CMAC,$/;" e enum:wifi_key_alg +ALG_CCMP src/common/defs.h /^ ALG_CCMP,$/;" e enum:wifi_key_alg +ALG_TKIP src/common/defs.h /^ ALG_TKIP,$/;" e enum:wifi_key_alg +ALG_WEP src/common/defs.h /^ ALG_WEP,$/;" e enum:wifi_key_alg +ANONYMOUS_ID_LEN_MAX src/esp_supplicant/esp_wpa_enterprise.c 937;" d file: +ANS1_TAG_RELATIVE_OID src/tls/asn1.h 24;" d +ANonce src/ap/wpa_auth_i.h /^ u8 ANonce[WPA_NONCE_LEN];$/;" m struct:wpa_state_machine +API_MUTEX_GIVE src/esp_supplicant/esp_wps.c 45;" d file: +API_MUTEX_TAKE src/esp_supplicant/esp_wps.c 34;" d file: +AP_DEAUTH_DELAY src/ap/sta_info.h 144;" d +AP_DISASSOC_DELAY src/ap/sta_info.h 143;" d +AP_MAX_INACTIVITY src/ap/sta_info.h 142;" d +AP_MAX_INACTIVITY_AFTER_DEAUTH src/ap/sta_info.h 149;" d +AP_MAX_INACTIVITY_AFTER_DISASSOC src/ap/sta_info.h 147;" d +AP_REJECTED_BLOCKED_STA src/common/wpa_ctrl.h 167;" d +AP_REJECTED_MAX_STA src/common/wpa_ctrl.h 166;" d +AP_STA_CONNECTED src/common/wpa_ctrl.h 163;" d +AP_STA_DISCONNECTED src/common/wpa_ctrl.h 164;" d +ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP src/common/ieee802_11_defs.h 442;" d +ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_CAP src/common/ieee802_11_defs.h 444;" d +ASEL_CAPABILITY_ASEL_CAPABLE src/common/ieee802_11_defs.h 440;" d +ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP src/common/ieee802_11_defs.h 441;" d +ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_CAP src/common/ieee802_11_defs.h 443;" d +ASEL_CAPABILITY_RX_AS_CAP src/common/ieee802_11_defs.h 445;" d +ASEL_CAPABILITY_TX_SOUND_PPDUS_CAP src/common/ieee802_11_defs.h 446;" d +ASN1_CLASS_APPLICATION src/tls/asn1.h 41;" d +ASN1_CLASS_CONTEXT_SPECIFIC src/tls/asn1.h 42;" d +ASN1_CLASS_PRIVATE src/tls/asn1.h 43;" d +ASN1_CLASS_UNIVERSAL src/tls/asn1.h 40;" d +ASN1_H src/tls/asn1.h 10;" d +ASN1_MAX_OID_LEN src/tls/asn1.h 52;" d +ASN1_TAG_BITSTRING src/tls/asn1.h 15;" d +ASN1_TAG_BMPSTRING src/tls/asn1.h 38;" d +ASN1_TAG_BOOLEAN src/tls/asn1.h 13;" d +ASN1_TAG_ENUMERATED src/tls/asn1.h 22;" d +ASN1_TAG_EOC src/tls/asn1.h 12;" d +ASN1_TAG_EXTERNAL src/tls/asn1.h 20;" d +ASN1_TAG_GENERALIZEDTIME src/tls/asn1.h 33;" d +ASN1_TAG_GENERALSTRING src/tls/asn1.h 36;" d +ASN1_TAG_GRAPHICSTRING src/tls/asn1.h 34;" d +ASN1_TAG_IA5STRING src/tls/asn1.h 31;" d +ASN1_TAG_INTEGER src/tls/asn1.h 14;" d +ASN1_TAG_NULL src/tls/asn1.h 17;" d +ASN1_TAG_NUMERICSTRING src/tls/asn1.h 27;" d +ASN1_TAG_OBJECT_DESCRIPTOR src/tls/asn1.h 19;" d +ASN1_TAG_OCTETSTRING src/tls/asn1.h 16;" d +ASN1_TAG_OID src/tls/asn1.h 18;" d +ASN1_TAG_PRINTABLESTRING src/tls/asn1.h 28;" d +ASN1_TAG_REAL src/tls/asn1.h 21;" d +ASN1_TAG_SEQUENCE src/tls/asn1.h 25;" d +ASN1_TAG_SET src/tls/asn1.h 26;" d +ASN1_TAG_TG1STRING src/tls/asn1.h 29;" d +ASN1_TAG_UNIVERSALSTRING src/tls/asn1.h 37;" d +ASN1_TAG_UTCTIME src/tls/asn1.h 32;" d +ASN1_TAG_UTF8STRING src/tls/asn1.h 23;" d +ASN1_TAG_VIDEOTEXSTRING src/tls/asn1.h 30;" d +ASN1_TAG_VISIBLESTRING src/tls/asn1.h 35;" d +ASSOC_IE_LEN src/rsn_supp/wpa.c 50;" d file: +ATTR_802_1X_ENABLED src/wps/wps_defs.h /^ ATTR_802_1X_ENABLED = 0x1062,$/;" e enum:wps_attribute +ATTR_APPLICATION_EXT src/wps/wps_defs.h /^ ATTR_APPLICATION_EXT = 0x1058,$/;" e enum:wps_attribute +ATTR_APPSESSIONKEY src/wps/wps_defs.h /^ ATTR_APPSESSIONKEY = 0x1063,$/;" e enum:wps_attribute +ATTR_AP_CHANNEL src/wps/wps_defs.h /^ ATTR_AP_CHANNEL = 0x1001,$/;" e enum:wps_attribute +ATTR_AP_SETUP_LOCKED src/wps/wps_defs.h /^ ATTR_AP_SETUP_LOCKED = 0x1057,$/;" e enum:wps_attribute +ATTR_ASSOC_STATE src/wps/wps_defs.h /^ ATTR_ASSOC_STATE = 0x1002,$/;" e enum:wps_attribute +ATTR_AUTHENTICATOR src/wps/wps_defs.h /^ ATTR_AUTHENTICATOR = 0x1005,$/;" e enum:wps_attribute +ATTR_AUTH_TYPE src/wps/wps_defs.h /^ ATTR_AUTH_TYPE = 0x1003,$/;" e enum:wps_attribute +ATTR_AUTH_TYPE_FLAGS src/wps/wps_defs.h /^ ATTR_AUTH_TYPE_FLAGS = 0x1004,$/;" e enum:wps_attribute +ATTR_CONFIG_ERROR src/wps/wps_defs.h /^ ATTR_CONFIG_ERROR = 0x1009,$/;" e enum:wps_attribute +ATTR_CONFIG_METHODS src/wps/wps_defs.h /^ ATTR_CONFIG_METHODS = 0x1008,$/;" e enum:wps_attribute +ATTR_CONFIRM_URL4 src/wps/wps_defs.h /^ ATTR_CONFIRM_URL4 = 0x100a,$/;" e enum:wps_attribute +ATTR_CONFIRM_URL6 src/wps/wps_defs.h /^ ATTR_CONFIRM_URL6 = 0x100b,$/;" e enum:wps_attribute +ATTR_CONN_TYPE src/wps/wps_defs.h /^ ATTR_CONN_TYPE = 0x100c,$/;" e enum:wps_attribute +ATTR_CONN_TYPE_FLAGS src/wps/wps_defs.h /^ ATTR_CONN_TYPE_FLAGS = 0x100d,$/;" e enum:wps_attribute +ATTR_CRED src/wps/wps_defs.h /^ ATTR_CRED = 0x100e,$/;" e enum:wps_attribute +ATTR_DEV_NAME src/wps/wps_defs.h /^ ATTR_DEV_NAME = 0x1011,$/;" e enum:wps_attribute +ATTR_DEV_PASSWORD_ID src/wps/wps_defs.h /^ ATTR_DEV_PASSWORD_ID = 0x1012,$/;" e enum:wps_attribute +ATTR_EAP_IDENTITY src/wps/wps_defs.h /^ ATTR_EAP_IDENTITY = 0x104d,$/;" e enum:wps_attribute +ATTR_EAP_TYPE src/wps/wps_defs.h /^ ATTR_EAP_TYPE = 0x1059,$/;" e enum:wps_attribute +ATTR_ENCR_SETTINGS src/wps/wps_defs.h /^ ATTR_ENCR_SETTINGS = 0x1018,$/;" e enum:wps_attribute +ATTR_ENCR_TYPE src/wps/wps_defs.h /^ ATTR_ENCR_TYPE = 0x100f,$/;" e enum:wps_attribute +ATTR_ENCR_TYPE_FLAGS src/wps/wps_defs.h /^ ATTR_ENCR_TYPE_FLAGS = 0x1010,$/;" e enum:wps_attribute +ATTR_ENROLLEE_NONCE src/wps/wps_defs.h /^ ATTR_ENROLLEE_NONCE = 0x101a,$/;" e enum:wps_attribute +ATTR_EXTENSIBILITY_TEST src/wps/wps_defs.h /^ ATTR_EXTENSIBILITY_TEST = 0x10fa \/* _NOT_ defined in the spec *\/$/;" e enum:wps_attribute +ATTR_E_HASH1 src/wps/wps_defs.h /^ ATTR_E_HASH1 = 0x1014,$/;" e enum:wps_attribute +ATTR_E_HASH2 src/wps/wps_defs.h /^ ATTR_E_HASH2 = 0x1015,$/;" e enum:wps_attribute +ATTR_E_SNONCE1 src/wps/wps_defs.h /^ ATTR_E_SNONCE1 = 0x1016,$/;" e enum:wps_attribute +ATTR_E_SNONCE2 src/wps/wps_defs.h /^ ATTR_E_SNONCE2 = 0x1017,$/;" e enum:wps_attribute +ATTR_FEATURE_ID src/wps/wps_defs.h /^ ATTR_FEATURE_ID = 0x101b,$/;" e enum:wps_attribute +ATTR_IDENTITY src/wps/wps_defs.h /^ ATTR_IDENTITY = 0x101c,$/;" e enum:wps_attribute +ATTR_IDENTITY_PROOF src/wps/wps_defs.h /^ ATTR_IDENTITY_PROOF = 0x101d,$/;" e enum:wps_attribute +ATTR_IV src/wps/wps_defs.h /^ ATTR_IV = 0x1060,$/;" e enum:wps_attribute +ATTR_KEY_ID src/wps/wps_defs.h /^ ATTR_KEY_ID = 0x101f,$/;" e enum:wps_attribute +ATTR_KEY_LIFETIME src/wps/wps_defs.h /^ ATTR_KEY_LIFETIME = 0x1051,$/;" e enum:wps_attribute +ATTR_KEY_PROVIDED_AUTO src/wps/wps_defs.h /^ ATTR_KEY_PROVIDED_AUTO = 0x1061,$/;" e enum:wps_attribute +ATTR_KEY_WRAP_AUTH src/wps/wps_defs.h /^ ATTR_KEY_WRAP_AUTH = 0x101e,$/;" e enum:wps_attribute +ATTR_MAC_ADDR src/wps/wps_defs.h /^ ATTR_MAC_ADDR = 0x1020,$/;" e enum:wps_attribute +ATTR_MANUFACTURER src/wps/wps_defs.h /^ ATTR_MANUFACTURER = 0x1021,$/;" e enum:wps_attribute +ATTR_MODEL_NAME src/wps/wps_defs.h /^ ATTR_MODEL_NAME = 0x1023,$/;" e enum:wps_attribute +ATTR_MODEL_NUMBER src/wps/wps_defs.h /^ ATTR_MODEL_NUMBER = 0x1024,$/;" e enum:wps_attribute +ATTR_MSG_COUNTER src/wps/wps_defs.h /^ ATTR_MSG_COUNTER = 0x104e,$/;" e enum:wps_attribute +ATTR_MSG_TYPE src/wps/wps_defs.h /^ ATTR_MSG_TYPE = 0x1022,$/;" e enum:wps_attribute +ATTR_NETWORK_INDEX src/wps/wps_defs.h /^ ATTR_NETWORK_INDEX = 0x1026,$/;" e enum:wps_attribute +ATTR_NETWORK_KEY src/wps/wps_defs.h /^ ATTR_NETWORK_KEY = 0x1027,$/;" e enum:wps_attribute +ATTR_NETWORK_KEY_INDEX src/wps/wps_defs.h /^ ATTR_NETWORK_KEY_INDEX = 0x1028,$/;" e enum:wps_attribute +ATTR_NEW_DEVICE_NAME src/wps/wps_defs.h /^ ATTR_NEW_DEVICE_NAME = 0x1029,$/;" e enum:wps_attribute +ATTR_NEW_PASSWORD src/wps/wps_defs.h /^ ATTR_NEW_PASSWORD = 0x102a,$/;" e enum:wps_attribute +ATTR_OOB_DEVICE_PASSWORD src/wps/wps_defs.h /^ ATTR_OOB_DEVICE_PASSWORD = 0x102c,$/;" e enum:wps_attribute +ATTR_OS_VERSION src/wps/wps_defs.h /^ ATTR_OS_VERSION = 0x102d,$/;" e enum:wps_attribute +ATTR_PERMITTED_CFG_METHODS src/wps/wps_defs.h /^ ATTR_PERMITTED_CFG_METHODS = 0x1052,$/;" e enum:wps_attribute +ATTR_PORTABLE_DEV src/wps/wps_defs.h /^ ATTR_PORTABLE_DEV = 0x1056,$/;" e enum:wps_attribute +ATTR_POWER_LEVEL src/wps/wps_defs.h /^ ATTR_POWER_LEVEL = 0x102f,$/;" e enum:wps_attribute +ATTR_PRIMARY_DEV_TYPE src/wps/wps_defs.h /^ ATTR_PRIMARY_DEV_TYPE = 0x1054,$/;" e enum:wps_attribute +ATTR_PSK_CURRENT src/wps/wps_defs.h /^ ATTR_PSK_CURRENT = 0x1030,$/;" e enum:wps_attribute +ATTR_PSK_MAX src/wps/wps_defs.h /^ ATTR_PSK_MAX = 0x1031,$/;" e enum:wps_attribute +ATTR_PUBKEY_HASH src/wps/wps_defs.h /^ ATTR_PUBKEY_HASH = 0x104f,$/;" e enum:wps_attribute +ATTR_PUBLIC_KEY src/wps/wps_defs.h /^ ATTR_PUBLIC_KEY = 0x1032,$/;" e enum:wps_attribute +ATTR_RADIO_ENABLE src/wps/wps_defs.h /^ ATTR_RADIO_ENABLE = 0x1033,$/;" e enum:wps_attribute +ATTR_REBOOT src/wps/wps_defs.h /^ ATTR_REBOOT = 0x1034,$/;" e enum:wps_attribute +ATTR_REGISTRAR_CURRENT src/wps/wps_defs.h /^ ATTR_REGISTRAR_CURRENT = 0x1035,$/;" e enum:wps_attribute +ATTR_REGISTRAR_ESTABLISHED src/wps/wps_defs.h /^ ATTR_REGISTRAR_ESTABLISHED = 0x1036,$/;" e enum:wps_attribute +ATTR_REGISTRAR_LIST src/wps/wps_defs.h /^ ATTR_REGISTRAR_LIST = 0x1037,$/;" e enum:wps_attribute +ATTR_REGISTRAR_MAX src/wps/wps_defs.h /^ ATTR_REGISTRAR_MAX = 0x1038,$/;" e enum:wps_attribute +ATTR_REGISTRAR_NONCE src/wps/wps_defs.h /^ ATTR_REGISTRAR_NONCE = 0x1039,$/;" e enum:wps_attribute +ATTR_REKEY_KEY src/wps/wps_defs.h /^ ATTR_REKEY_KEY = 0x1050,$/;" e enum:wps_attribute +ATTR_REQUESTED_DEV_TYPE src/wps/wps_defs.h /^ ATTR_REQUESTED_DEV_TYPE = 0x106a,$/;" e enum:wps_attribute +ATTR_REQUEST_TYPE src/wps/wps_defs.h /^ ATTR_REQUEST_TYPE = 0x103a,$/;" e enum:wps_attribute +ATTR_RESPONSE_TYPE src/wps/wps_defs.h /^ ATTR_RESPONSE_TYPE = 0x103b,$/;" e enum:wps_attribute +ATTR_RF_BANDS src/wps/wps_defs.h /^ ATTR_RF_BANDS = 0x103c,$/;" e enum:wps_attribute +ATTR_R_HASH1 src/wps/wps_defs.h /^ ATTR_R_HASH1 = 0x103d,$/;" e enum:wps_attribute +ATTR_R_HASH2 src/wps/wps_defs.h /^ ATTR_R_HASH2 = 0x103e,$/;" e enum:wps_attribute +ATTR_R_SNONCE1 src/wps/wps_defs.h /^ ATTR_R_SNONCE1 = 0x103f,$/;" e enum:wps_attribute +ATTR_R_SNONCE2 src/wps/wps_defs.h /^ ATTR_R_SNONCE2 = 0x1040,$/;" e enum:wps_attribute +ATTR_SECONDARY_DEV_TYPE_LIST src/wps/wps_defs.h /^ ATTR_SECONDARY_DEV_TYPE_LIST = 0x1055,$/;" e enum:wps_attribute +ATTR_SELECTED_REGISTRAR src/wps/wps_defs.h /^ ATTR_SELECTED_REGISTRAR = 0x1041,$/;" e enum:wps_attribute +ATTR_SELECTED_REGISTRAR_CONFIG_METHODS src/wps/wps_defs.h /^ ATTR_SELECTED_REGISTRAR_CONFIG_METHODS = 0x1053,$/;" e enum:wps_attribute +ATTR_SERIAL_NUMBER src/wps/wps_defs.h /^ ATTR_SERIAL_NUMBER = 0x1042,$/;" e enum:wps_attribute +ATTR_SSID src/wps/wps_defs.h /^ ATTR_SSID = 0x1045,$/;" e enum:wps_attribute +ATTR_TOTAL_NETWORKS src/wps/wps_defs.h /^ ATTR_TOTAL_NETWORKS = 0x1046,$/;" e enum:wps_attribute +ATTR_UUID_E src/wps/wps_defs.h /^ ATTR_UUID_E = 0x1047,$/;" e enum:wps_attribute +ATTR_UUID_R src/wps/wps_defs.h /^ ATTR_UUID_R = 0x1048,$/;" e enum:wps_attribute +ATTR_VENDOR_EXT src/wps/wps_defs.h /^ ATTR_VENDOR_EXT = 0x1049,$/;" e enum:wps_attribute +ATTR_VERSION src/wps/wps_defs.h /^ ATTR_VERSION = 0x104a,$/;" e enum:wps_attribute +ATTR_WEPTRANSMITKEY src/wps/wps_defs.h /^ ATTR_WEPTRANSMITKEY = 0x1064,$/;" e enum:wps_attribute +ATTR_WPS_STATE src/wps/wps_defs.h /^ ATTR_WPS_STATE = 0x1044,$/;" e enum:wps_attribute +ATTR_X509_CERT src/wps/wps_defs.h /^ ATTR_X509_CERT = 0x104c,$/;" e enum:wps_attribute +ATTR_X509_CERT_REQ src/wps/wps_defs.h /^ ATTR_X509_CERT_REQ = 0x104b,$/;" e enum:wps_attribute +AVP_FLAGS_MANDATORY src/eap_peer/eap_ttls.h 29;" d +AVP_FLAGS_VENDOR src/eap_peer/eap_ttls.h 28;" d +AVP_PAD src/eap_peer/eap_ttls.h 31;" d +AuthenticationRequest src/ap/wpa_auth_i.h /^ Boolean AuthenticationRequest;$/;" m struct:wpa_state_machine +BASE64_H src/utils/base64.h 16;" d +BIGNUM_H src/crypto/bignum.h 16;" d +BIGNUM_H src/tls/bignum.h 16;" d +BIG_ENDIAN port/include/endian.h 37;" d +BIT include/utils/common.h 264;" d +BLOB_NAME_LEN src/eap_peer/eap_i.h 98;" d +BLOB_NUM src/eap_peer/eap_i.h 99;" d +BN_FAST_MP_MONTGOMERY_REDUCE_C src/crypto/libtommath.h 42;" d +BN_FAST_MP_MONTGOMERY_REDUCE_C src/tls/libtommath.h 44;" d +BN_FAST_S_MP_SQR_C src/crypto/libtommath.h 47;" d +BN_FAST_S_MP_SQR_C src/tls/libtommath.h 49;" d +BN_MP_ABS_C src/crypto/libtommath.h 54;" d +BN_MP_ABS_C src/tls/libtommath.h 56;" d +BN_MP_CLEAR_MULTI_C src/crypto/libtommath.h 53;" d +BN_MP_CLEAR_MULTI_C src/tls/libtommath.h 55;" d +BN_MP_DIV_SMALL src/crypto/libtommath.h 51;" d +BN_MP_DIV_SMALL src/tls/libtommath.h 53;" d +BN_MP_EXPTMOD_FAST_C src/crypto/libtommath.h 40;" d +BN_MP_EXPTMOD_FAST_C src/tls/libtommath.h 42;" d +BN_MP_INIT_MULTI_C src/crypto/libtommath.h 52;" d +BN_MP_INIT_MULTI_C src/tls/libtommath.h 54;" d +BN_MP_INVMOD_C src/crypto/libtommath.h 25;" d +BN_MP_INVMOD_C src/tls/libtommath.h 27;" d +BN_MP_INVMOD_SLOW_C src/crypto/libtommath.h 29;" d +BN_MP_INVMOD_SLOW_C src/tls/libtommath.h 31;" d +BN_MP_MONTGOMERY_CALC_NORMALIZATION_C src/crypto/libtommath.h 43;" d +BN_MP_MONTGOMERY_CALC_NORMALIZATION_C src/tls/libtommath.h 45;" d +BN_MP_MONTGOMERY_SETUP_C src/crypto/libtommath.h 41;" d +BN_MP_MONTGOMERY_SETUP_C src/tls/libtommath.h 43;" d +BN_MP_MUL_2_C src/crypto/libtommath.h 44;" d +BN_MP_MUL_2_C src/tls/libtommath.h 46;" d +BN_MP_MUL_D_C src/crypto/libtommath.h 37;" d +BN_MP_MUL_D_C src/tls/libtommath.h 39;" d +BN_S_MP_EXPTMOD_C src/crypto/libtommath.h 26;" d +BN_S_MP_EXPTMOD_C src/tls/libtommath.h 28;" d +BN_S_MP_MUL_DIGS_C src/crypto/libtommath.h 28;" d +BN_S_MP_MUL_DIGS_C src/tls/libtommath.h 30;" d +BN_S_MP_MUL_HIGH_DIGS_C src/crypto/libtommath.h 31;" d +BN_S_MP_MUL_HIGH_DIGS_C src/tls/libtommath.h 33;" d +BN_S_MP_SQR_C src/crypto/libtommath.h 30;" d +BN_S_MP_SQR_C src/tls/libtommath.h 32;" d +BYTESWAP_H port/include/byteswap.h 6;" d +BYTES_TO_T_UINT_2 test/test_crypto.c 295;" d file: +BYTES_TO_T_UINT_2 test/test_crypto.c 317;" d file: +BYTES_TO_T_UINT_4 test/test_crypto.c 289;" d file: +BYTES_TO_T_UINT_4 test/test_crypto.c 314;" d file: +BYTES_TO_T_UINT_8 test/test_crypto.c 298;" d file: +BYTES_TO_T_UINT_8 test/test_crypto.c 304;" d file: +BYTE_ORDER port/include/endian.h 45;" d +BYTE_ORDER port/include/endian.h 47;" d +Boolean src/common/defs.h /^typedef enum { FALSE = 0, TRUE = 1 } Boolean;$/;" t typeref:enum:__anon87 +CA_CERT_NAME src/eap_peer/eap_i.h 96;" d +CERTIFICATE_VERIFY src/tls/tlsv1_server_i.h /^ CERTIFICATE_VERIFY, CHANGE_CIPHER_SPEC, CLIENT_FINISHED,$/;" e enum:tlsv1_server::__anon39 +CHANGE_CIPHER_SPEC src/tls/tlsv1_client_i.h /^ SERVER_HELLO_DONE, CLIENT_KEY_EXCHANGE, CHANGE_CIPHER_SPEC,$/;" e enum:tlsv1_client::__anon43 +CHANGE_CIPHER_SPEC src/tls/tlsv1_server_i.h /^ CERTIFICATE_VERIFY, CHANGE_CIPHER_SPEC, CLIENT_FINISHED,$/;" e enum:tlsv1_server::__anon39 +CHAR_BIT src/crypto/libtommath.h 22;" d +CHAR_BIT src/tls/libtommath.h 24;" d +CIPHER_CCMP src/common/defs.h /^ CIPHER_CCMP,$/;" e enum:wpa_cipher +CIPHER_NONE src/common/defs.h /^ CIPHER_NONE,$/;" e enum:wpa_cipher +CIPHER_TKIP src/common/defs.h /^ CIPHER_TKIP,$/;" e enum:wpa_cipher +CIPHER_WEP104 src/common/defs.h /^ CIPHER_WEP104$/;" e enum:wpa_cipher +CIPHER_WEP40 src/common/defs.h /^ CIPHER_WEP40,$/;" e enum:wpa_cipher +CLIENT_CERTIFICATE src/tls/tlsv1_server_i.h /^ SERVER_HELLO_DONE, CLIENT_CERTIFICATE, CLIENT_KEY_EXCHANGE,$/;" e enum:tlsv1_server::__anon39 +CLIENT_CERT_NAME src/eap_peer/eap_i.h 95;" d +CLIENT_FINISHED src/tls/tlsv1_server_i.h /^ CERTIFICATE_VERIFY, CHANGE_CIPHER_SPEC, CLIENT_FINISHED,$/;" e enum:tlsv1_server::__anon39 +CLIENT_HELLO src/tls/tlsv1_client_i.h /^ CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,$/;" e enum:tlsv1_client::__anon43 +CLIENT_HELLO src/tls/tlsv1_server_i.h /^ CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,$/;" e enum:tlsv1_server::__anon39 +CLIENT_KEY_EXCHANGE src/tls/tlsv1_client_i.h /^ SERVER_HELLO_DONE, CLIENT_KEY_EXCHANGE, CHANGE_CIPHER_SPEC,$/;" e enum:tlsv1_client::__anon43 +CLIENT_KEY_EXCHANGE src/tls/tlsv1_server_i.h /^ SERVER_HELLO_DONE, CLIENT_CERTIFICATE, CLIENT_KEY_EXCHANGE,$/;" e enum:tlsv1_server::__anon39 +COMMON_H include/utils/common.h 16;" d +COMPONENT_ADD_INCLUDEDIRS component.mk /^COMPONENT_ADD_INCLUDEDIRS := include port\/include include\/esp_supplicant$/;" m +COMPONENT_ADD_LDFLAGS test/component.mk /^COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive$/;" m +COMPONENT_PRIV_INCLUDEDIRS component.mk /^COMPONENT_PRIV_INCLUDEDIRS := src$/;" m +COMPONENT_SRCDIRS component.mk /^COMPONENT_SRCDIRS := port src\/ap src\/common src\/crypto src\/eap_peer src\/fast_crypto src\/rsn_supp src\/tls src\/utils src\/esp_supplicant src\/wps$/;" m +CONFIG_INTERNAL_LIBTOMMATH src/crypto/bignum.c 21;" d file: +CONFIG_INTERNAL_LIBTOMMATH src/tls/bignum.c 21;" d file: +CONFIG_NO_RANDOM_POOL include/crypto/random.h 18;" d +CONFIG_TLS_INTERNAL_CLIENT src/tls/tls_internal.c 22;" d file: +CONFIG_WPS_STRICT src/wps/wps_defs.h 28;" d +CRYPTO_CIPHER_ALG_3DES include/crypto/crypto.h /^ CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES,$/;" e enum:crypto_cipher_alg +CRYPTO_CIPHER_ALG_AES include/crypto/crypto.h /^ CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES,$/;" e enum:crypto_cipher_alg +CRYPTO_CIPHER_ALG_DES include/crypto/crypto.h /^ CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4$/;" e enum:crypto_cipher_alg +CRYPTO_CIPHER_ALG_RC2 include/crypto/crypto.h /^ CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4$/;" e enum:crypto_cipher_alg +CRYPTO_CIPHER_ALG_RC4 include/crypto/crypto.h /^ CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4$/;" e enum:crypto_cipher_alg +CRYPTO_CIPHER_NULL include/crypto/crypto.h /^ CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES,$/;" e enum:crypto_cipher_alg +CRYPTO_H include/crypto/crypto.h 28;" d +CRYPTO_HASH_ALG_HMAC_MD5 include/crypto/crypto.h /^ CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1,$/;" e enum:crypto_hash_alg +CRYPTO_HASH_ALG_HMAC_SHA1 include/crypto/crypto.h /^ CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1,$/;" e enum:crypto_hash_alg +CRYPTO_HASH_ALG_HMAC_SHA256 include/crypto/crypto.h /^ CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256$/;" e enum:crypto_hash_alg +CRYPTO_HASH_ALG_MD5 include/crypto/crypto.h /^ CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1,$/;" e enum:crypto_hash_alg +CRYPTO_HASH_ALG_SHA1 include/crypto/crypto.h /^ CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1,$/;" e enum:crypto_hash_alg +CRYPTO_HASH_ALG_SHA256 include/crypto/crypto.h /^ CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256$/;" e enum:crypto_hash_alg +Ch src/crypto/sha256-internal.c 87;" d file: +Counter src/ap/wpa_auth_i.h /^ u8 Counter[WPA_NONCE_LEN];$/;" m struct:wpa_group +DATA_MUTEX_GIVE src/esp_supplicant/esp_wps.c 47;" d file: +DATA_MUTEX_TAKE src/esp_supplicant/esp_wps.c 46;" d file: +DEBUG_PRINT include/utils/wpa_debug.h 61;" d +DECISION_COND_SUCC src/eap_peer/eap_i.h /^ DECISION_FAIL, DECISION_COND_SUCC, DECISION_UNCOND_SUCC$/;" e enum:__anon1 +DECISION_FAIL src/eap_peer/eap_i.h /^ DECISION_FAIL, DECISION_COND_SUCC, DECISION_UNCOND_SUCC$/;" e enum:__anon1 +DECISION_UNCOND_SUCC src/eap_peer/eap_i.h /^ DECISION_FAIL, DECISION_COND_SUCC, DECISION_UNCOND_SUCC$/;" e enum:__anon1 +DEFINE_DL_LIST src/utils/list.h 100;" d +DEFS_H src/common/defs.h 16;" d +DENY_UNLESS_ACCEPTED src/ap/ap_config.h /^ DENY_UNLESS_ACCEPTED = 1,$/;" e enum:hostapd_bss_config::__anon17 +DES_I_H src/crypto/des_i.h 10;" d +DEV_PW_DEFAULT src/wps/wps_defs.h /^ DEV_PW_DEFAULT = 0x0000,$/;" e enum:wps_dev_password_id +DEV_PW_MACHINE_SPECIFIED src/wps/wps_defs.h /^ DEV_PW_MACHINE_SPECIFIED = 0x0002,$/;" e enum:wps_dev_password_id +DEV_PW_PUSHBUTTON src/wps/wps_defs.h /^ DEV_PW_PUSHBUTTON = 0x0004,$/;" e enum:wps_dev_password_id +DEV_PW_REGISTRAR_SPECIFIED src/wps/wps_defs.h /^ DEV_PW_REGISTRAR_SPECIFIED = 0x0005$/;" e enum:wps_dev_password_id +DEV_PW_REKEY src/wps/wps_defs.h /^ DEV_PW_REKEY = 0x0003,$/;" e enum:wps_dev_password_id +DEV_PW_USER_SPECIFIED src/wps/wps_defs.h /^ DEV_PW_USER_SPECIFIED = 0x0001,$/;" e enum:wps_dev_password_id +DH_GROUP src/crypto/dh_groups.c 518;" d file: +DH_GROUP5_H include/crypto/dh_group5.h 16;" d +DH_GROUPS_H include/crypto/dh_groups.h 16;" d +DIGIT_BIT src/crypto/libtommath.h 76;" d +DIGIT_BIT src/tls/libtommath.h 78;" d +DeauthenticationRequest src/ap/wpa_auth_i.h /^ Boolean DeauthenticationRequest;$/;" m struct:wpa_state_machine +Disconnect src/ap/wpa_auth_i.h /^ Boolean Disconnect;$/;" m struct:wpa_state_machine +EAPOLKeyPairwise src/ap/wpa_auth_i.h /^ Boolean EAPOLKeyPairwise;$/;" m struct:wpa_state_machine +EAPOLKeyReceived src/ap/wpa_auth_i.h /^ Boolean EAPOLKeyReceived;$/;" m struct:wpa_state_machine +EAPOLKeyRequest src/ap/wpa_auth_i.h /^ Boolean EAPOLKeyRequest;$/;" m struct:wpa_state_machine +EAPOL_COMMON_H src/common/eapol_common.h 16;" d +EAPOL_KEY_TYPE_RC4 src/common/eapol_common.h /^enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,$/;" e enum:__anon86 +EAPOL_KEY_TYPE_RSN src/common/eapol_common.h /^enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,$/;" e enum:__anon86 +EAPOL_KEY_TYPE_WPA src/common/eapol_common.h /^ EAPOL_KEY_TYPE_WPA = 254 };$/;" e enum:__anon86 +EAPOL_VERSION src/common/eapol_common.h 28;" d +EAP_CODE_FAILURE src/eap_peer/eap_defs.h /^ EAP_CODE_FAILURE = 4 };$/;" e enum:__anon4 +EAP_CODE_REQUEST src/eap_peer/eap_defs.h /^enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,$/;" e enum:__anon4 +EAP_CODE_RESPONSE src/eap_peer/eap_defs.h /^enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,$/;" e enum:__anon4 +EAP_CODE_SUCCESS src/eap_peer/eap_defs.h /^enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,$/;" e enum:__anon4 +EAP_COMMON_H src/eap_peer/eap_common.h 10;" d +EAP_CONFIG_FLAGS_EXT_PASSWORD src/eap_peer/eap_config.h 196;" d +EAP_CONFIG_FLAGS_PASSWORD_NTHASH src/eap_peer/eap_config.h 195;" d +EAP_CONFIG_H src/eap_peer/eap_config.h 10;" d +EAP_DEFS_H src/eap_peer/eap_defs.h 10;" d +EAP_EMSK_LEN src/eap_peer/eap_defs.h 90;" d +EAP_H src/eap_peer/eap.h 10;" d +EAP_I_H src/eap_peer/eap_i.h 10;" d +EAP_METHODS_H src/eap_peer/eap_methods.h 10;" d +EAP_MSK_LEN src/eap_peer/eap_defs.h 89;" d +EAP_PEAP_COMMON_H src/eap_peer/eap_peap_common.h 10;" d +EAP_PEAP_VERSION src/eap_peer/eap_peap.c 28;" d file: +EAP_TLS_COMMON_H src/eap_peer/eap_tls_common.h 10;" d +EAP_TLS_FLAGS_LENGTH_INCLUDED src/eap_peer/eap_tls_common.h 80;" d +EAP_TLS_FLAGS_MORE_FRAGMENTS src/eap_peer/eap_tls_common.h 81;" d +EAP_TLS_FLAGS_START src/eap_peer/eap_tls_common.h 82;" d +EAP_TLS_H src/eap_peer/eap_tls.h 10;" d +EAP_TLS_KEY_LEN src/eap_peer/eap_tls_common.h 86;" d +EAP_TLS_VERSION_MASK src/eap_peer/eap_tls_common.h 83;" d +EAP_TLV_ACTION_NEGOTIATE_EAP src/eap_peer/eap_tlv_common.h 110;" d +EAP_TLV_ACTION_PROCESS_TLV src/eap_peer/eap_tlv_common.h 109;" d +EAP_TLV_CALLED_STATION_ID_TLV src/eap_peer/eap_tlv_common.h 24;" d +EAP_TLV_CALLING_STATION_ID_TLV src/eap_peer/eap_tlv_common.h 23;" d +EAP_TLV_COMMON_H src/eap_peer/eap_tlv_common.h 10;" d +EAP_TLV_CONNECTION_BINDING_TLV src/eap_peer/eap_tlv_common.h 16;" d +EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST src/eap_peer/eap_tlv_common.h 106;" d +EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE src/eap_peer/eap_tlv_common.h 107;" d +EAP_TLV_CRYPTO_BINDING_TLV src/eap_peer/eap_tlv_common.h 22;" d +EAP_TLV_EAP_PAYLOAD_TLV src/eap_peer/eap_tlv_common.h 19;" d +EAP_TLV_ERROR_CODE_TLV src/eap_peer/eap_tlv_common.h 15;" d +EAP_TLV_IDENTITY_TYPE_TLV src/eap_peer/eap_tlv_common.h 27;" d +EAP_TLV_INTERMEDIATE_RESULT_TLV src/eap_peer/eap_tlv_common.h 20;" d +EAP_TLV_NAK_TLV src/eap_peer/eap_tlv_common.h 14;" d +EAP_TLV_NAS_PORT_TYPE_TLV src/eap_peer/eap_tlv_common.h 25;" d +EAP_TLV_PAC_TLV src/eap_peer/eap_tlv_common.h 21;" d +EAP_TLV_PKCS7_TLV src/eap_peer/eap_tlv_common.h 30;" d +EAP_TLV_REQUEST_ACTION_TLV src/eap_peer/eap_tlv_common.h 29;" d +EAP_TLV_RESULT_FAILURE src/eap_peer/eap_tlv_common.h 33;" d +EAP_TLV_RESULT_SUCCESS src/eap_peer/eap_tlv_common.h 32;" d +EAP_TLV_RESULT_TLV src/eap_peer/eap_tlv_common.h 13;" d +EAP_TLV_SERVER_IDENTIFIER_TLV src/eap_peer/eap_tlv_common.h 26;" d +EAP_TLV_SERVER_TRUSTED_ROOT_TLV src/eap_peer/eap_tlv_common.h 28;" d +EAP_TLV_TYPE_MANDATORY src/eap_peer/eap_tlv_common.h 35;" d +EAP_TLV_TYPE_MASK src/eap_peer/eap_tlv_common.h 36;" d +EAP_TLV_URI_TLV src/eap_peer/eap_tlv_common.h 18;" d +EAP_TLV_VENDOR_SPECIFIC_TLV src/eap_peer/eap_tlv_common.h 17;" d +EAP_TTLS_CHAP_CHALLENGE_LEN src/eap_peer/eap_ttls.h 62;" d +EAP_TTLS_CHAP_PASSWORD_LEN src/eap_peer/eap_ttls.h 63;" d +EAP_TTLS_H src/eap_peer/eap_ttls.h 10;" d +EAP_TTLS_MSCHAPV2_CHALLENGE_LEN src/eap_peer/eap_ttls.h 58;" d +EAP_TTLS_MSCHAPV2_RESPONSE_LEN src/eap_peer/eap_ttls.h 59;" d +EAP_TTLS_MSCHAP_CHALLENGE_LEN src/eap_peer/eap_ttls.h 60;" d +EAP_TTLS_MSCHAP_RESPONSE_LEN src/eap_peer/eap_ttls.h 61;" d +EAP_TTLS_PHASE2_CHAP src/eap_peer/eap_ttls.c /^ EAP_TTLS_PHASE2_CHAP$/;" e enum:eap_ttls_data::phase2_types file: +EAP_TTLS_PHASE2_EAP src/eap_peer/eap_ttls.c /^ EAP_TTLS_PHASE2_EAP,$/;" e enum:eap_ttls_data::phase2_types file: +EAP_TTLS_PHASE2_MSCHAP src/eap_peer/eap_ttls.c /^ EAP_TTLS_PHASE2_MSCHAP,$/;" e enum:eap_ttls_data::phase2_types file: +EAP_TTLS_PHASE2_MSCHAPV2 src/eap_peer/eap_ttls.c /^ EAP_TTLS_PHASE2_MSCHAPV2,$/;" e enum:eap_ttls_data::phase2_types file: +EAP_TTLS_PHASE2_PAP src/eap_peer/eap_ttls.c /^ EAP_TTLS_PHASE2_PAP,$/;" e enum:eap_ttls_data::phase2_types file: +EAP_TTLS_VERSION src/eap_peer/eap_ttls.c 28;" d file: +EAP_TYPE_AKA src/eap_peer/eap_defs.h /^ EAP_TYPE_AKA = 23 \/* RFC 4187 *\/,$/;" e enum:__anon5 +EAP_TYPE_AKA_PRIME src/eap_peer/eap_defs.h /^ EAP_TYPE_AKA_PRIME = 50 \/* RFC 5448 *\/,$/;" e enum:__anon5 +EAP_TYPE_EKE src/eap_peer/eap_defs.h /^ EAP_TYPE_EKE = 53 \/* RFC 6124 *\/,$/;" e enum:__anon5 +EAP_TYPE_EXPANDED src/eap_peer/eap_defs.h /^ EAP_TYPE_EXPANDED = 254 \/* RFC 3748 *\/$/;" e enum:__anon5 +EAP_TYPE_FAST src/eap_peer/eap_defs.h /^ EAP_TYPE_FAST = 43 \/* RFC 4851 *\/,$/;" e enum:__anon5 +EAP_TYPE_GPSK src/eap_peer/eap_defs.h /^ EAP_TYPE_GPSK = 51 \/* RFC 5433 *\/,$/;" e enum:__anon5 +EAP_TYPE_GTC src/eap_peer/eap_defs.h /^ EAP_TYPE_GTC = 6, \/* RFC 3748 *\/$/;" e enum:__anon5 +EAP_TYPE_IDENTITY src/eap_peer/eap_defs.h /^ EAP_TYPE_IDENTITY = 1 \/* RFC 3748 *\/,$/;" e enum:__anon5 +EAP_TYPE_IKEV2 src/eap_peer/eap_defs.h /^ EAP_TYPE_IKEV2 = 49 \/* RFC 5106 *\/,$/;" e enum:__anon5 +EAP_TYPE_LEAP src/eap_peer/eap_defs.h /^ EAP_TYPE_LEAP = 17 \/* Cisco proprietary *\/,$/;" e enum:__anon5 +EAP_TYPE_MD5 src/eap_peer/eap_defs.h /^ EAP_TYPE_MD5 = 4, \/* RFC 3748 *\/$/;" e enum:__anon5 +EAP_TYPE_MSCHAPV2 src/eap_peer/eap_defs.h /^ EAP_TYPE_MSCHAPV2 = 26 \/* draft-kamath-pppext-eap-mschapv2-00.txt *\/,$/;" e enum:__anon5 +EAP_TYPE_NAK src/eap_peer/eap_defs.h /^ EAP_TYPE_NAK = 3 \/* Response only, RFC 3748 *\/,$/;" e enum:__anon5 +EAP_TYPE_NONE src/eap_peer/eap_defs.h /^ EAP_TYPE_NONE = 0,$/;" e enum:__anon5 +EAP_TYPE_NOTIFICATION src/eap_peer/eap_defs.h /^ EAP_TYPE_NOTIFICATION = 2 \/* RFC 3748 *\/,$/;" e enum:__anon5 +EAP_TYPE_OTP src/eap_peer/eap_defs.h /^ EAP_TYPE_OTP = 5 \/* RFC 3748 *\/,$/;" e enum:__anon5 +EAP_TYPE_PAX src/eap_peer/eap_defs.h /^ EAP_TYPE_PAX = 46 \/* RFC 4746 *\/,$/;" e enum:__anon5 +EAP_TYPE_PEAP src/eap_peer/eap_defs.h /^ EAP_TYPE_PEAP = 25 \/* draft-josefsson-pppext-eap-tls-eap-06.txt *\/,$/;" e enum:__anon5 +EAP_TYPE_PSK src/eap_peer/eap_defs.h /^ EAP_TYPE_PSK = 47 \/* RFC 4764 *\/,$/;" e enum:__anon5 +EAP_TYPE_PWD src/eap_peer/eap_defs.h /^ EAP_TYPE_PWD = 52 \/* RFC 5931 *\/,$/;" e enum:__anon5 +EAP_TYPE_SAKE src/eap_peer/eap_defs.h /^ EAP_TYPE_SAKE = 48 \/* RFC 4763 *\/,$/;" e enum:__anon5 +EAP_TYPE_SIM src/eap_peer/eap_defs.h /^ EAP_TYPE_SIM = 18 \/* RFC 4186 *\/,$/;" e enum:__anon5 +EAP_TYPE_TLS src/eap_peer/eap_defs.h /^ EAP_TYPE_TLS = 13 \/* RFC 2716 *\/,$/;" e enum:__anon5 +EAP_TYPE_TLV src/eap_peer/eap_defs.h /^ EAP_TYPE_TLV = 33 \/* draft-josefsson-pppext-eap-tls-eap-07.txt *\/,$/;" e enum:__anon5 +EAP_TYPE_TNC src/eap_peer/eap_defs.h /^ EAP_TYPE_TNC = 38 \/* TNC IF-T v1.0-r3; note: tentative assignment;$/;" e enum:__anon5 +EAP_TYPE_TTLS src/eap_peer/eap_defs.h /^ EAP_TYPE_TTLS = 21 \/* RFC 5281 *\/,$/;" e enum:__anon5 +EAP_UNAUTH_TLS_TYPE src/eap_peer/eap_tls_common.h 89;" d +EAP_VENDOR_HOSTAP src/eap_peer/eap_defs.h /^ EAP_VENDOR_HOSTAP = 39068 \/* hostapd\/wpa_supplicant project *\/$/;" e enum:__anon6 +EAP_VENDOR_IETF src/eap_peer/eap_defs.h /^ EAP_VENDOR_IETF = 0,$/;" e enum:__anon6 +EAP_VENDOR_MICROSOFT src/eap_peer/eap_defs.h /^ EAP_VENDOR_MICROSOFT = 0x000137 \/* Microsoft *\/,$/;" e enum:__anon6 +EAP_VENDOR_TYPE_UNAUTH_TLS src/eap_peer/eap_defs.h 87;" d +EAP_VENDOR_UNAUTH_TLS src/eap_peer/eap_defs.h 86;" d +EAP_VENDOR_WFA src/eap_peer/eap_defs.h /^ EAP_VENDOR_WFA = 0x00372A \/* Wi-Fi Alliance *\/,$/;" e enum:__anon6 +ERP_INFO_BARKER_PREAMBLE_MODE src/common/ieee802_11_defs.h 388;" d +ERP_INFO_NON_ERP_PRESENT src/common/ieee802_11_defs.h 386;" d +ERP_INFO_USE_PROTECTION src/common/ieee802_11_defs.h 387;" d +ERROR_ACCT_DISABLED src/eap_peer/eap_mschapv2.c 35;" d file: +ERROR_AUTHENTICATION_FAILURE src/eap_peer/eap_mschapv2.c 38;" d file: +ERROR_CHANGING_PASSWORD src/eap_peer/eap_mschapv2.c 39;" d file: +ERROR_NO_DIALIN_PERMISSION src/eap_peer/eap_mschapv2.c 37;" d file: +ERROR_PASSWD_EXPIRED src/eap_peer/eap_mschapv2.c 36;" d file: +ERROR_RESTRICTED_LOGON_HOURS src/eap_peer/eap_mschapv2.c 34;" d file: +ESP_ERR_WIFI_REGISTRAR include/esp_supplicant/esp_wps.h 46;" d +ESP_ERR_WIFI_WPS_SM include/esp_supplicant/esp_wps.h 48;" d +ESP_ERR_WIFI_WPS_TYPE include/esp_supplicant/esp_wps.h 47;" d +ESP_HOSTAP_H src/esp_supplicant/esp_hostap.h 16;" d +ESP_WPA_ENTERPRISE_H include/esp_supplicant/esp_wpa_enterprise.h 16;" d +ESS_DISASSOC_IMMINENT src/common/wpa_ctrl.h 148;" d +ESTABLISHED src/tls/tlsv1_client_i.h /^ ESTABLISHED, FAILED$/;" e enum:tlsv1_client::__anon43 +ESTABLISHED src/tls/tlsv1_server_i.h /^ ESTABLISHED, FAILED$/;" e enum:tlsv1_server::__anon39 +ETH_ALEN include/utils/common.h 194;" d +ETH_P_ALL include/utils/common.h 200;" d +ETH_P_EAPOL include/utils/common.h 206;" d +ETH_P_PAE include/utils/common.h 203;" d +ETH_P_RRB include/utils/common.h 212;" d +ETH_P_RSN_PREAUTH include/utils/common.h 209;" d +ETSParam src/esp_supplicant/esp_wifi_driver.h /^typedef uint32_t ETSParam;$/;" t +ETSSignal src/esp_supplicant/esp_wifi_driver.h /^typedef uint32_t ETSSignal;$/;" t +EXT_HT_CAP_INFO_HTC_SUPPORTED src/common/ieee802_11_defs.h 416;" d +EXT_HT_CAP_INFO_MCS_FEEDBACK_OFFSET src/common/ieee802_11_defs.h 415;" d +EXT_HT_CAP_INFO_PCO src/common/ieee802_11_defs.h 413;" d +EXT_HT_CAP_INFO_RD_RESPONDER src/common/ieee802_11_defs.h 417;" d +EXT_HT_CAP_INFO_TRANS_TIME_OFFSET src/common/ieee802_11_defs.h 414;" d +EXT_PASSWORD_H src/utils/ext_password.h 10;" d +EXT_PASSWORD_I_H src/utils/ext_password_i.h 10;" d +EapDecision src/eap_peer/eap_i.h /^} EapDecision;$/;" t typeref:enum:__anon1 +EapMethodState src/eap_peer/eap_i.h /^} EapMethodState;$/;" t typeref:enum:__anon2 +EapType src/eap_peer/eap_defs.h /^} EapType;$/;" t typeref:enum:__anon5 +F1 src/crypto/md4-internal.c 128;" d file: +F1 src/crypto/md5-internal.c 201;" d file: +F2 src/crypto/md4-internal.c 129;" d file: +F2 src/crypto/md5-internal.c 202;" d file: +F3 src/crypto/md4-internal.c 130;" d file: +F3 src/crypto/md5-internal.c 203;" d file: +F4 src/crypto/md5-internal.c 204;" d file: +FAILED src/tls/tlsv1_client_i.h /^ ESTABLISHED, FAILED$/;" e enum:tlsv1_client::__anon43 +FAILED src/tls/tlsv1_server_i.h /^ ESTABLISHED, FAILED$/;" e enum:tlsv1_server::__anon39 +FALSE src/common/defs.h /^typedef enum { FALSE = 0, TRUE = 1 } Boolean;$/;" e enum:__anon87 +FALSE src/common/defs.h 19;" d +FTIE_SUBELEM_GTK src/common/wpa_common.h 290;" d +FTIE_SUBELEM_IGTK src/common/wpa_common.h 292;" d +FTIE_SUBELEM_R0KH_ID src/common/wpa_common.h 291;" d +FTIE_SUBELEM_R1KH_ID src/common/wpa_common.h 289;" d +FT_PACKET_R0KH_R1KH_PULL src/ap/wpa_auth.h 40;" d +FT_PACKET_R0KH_R1KH_PUSH src/ap/wpa_auth.h 42;" d +FT_PACKET_R0KH_R1KH_RESP src/ap/wpa_auth.h 41;" d +FT_PACKET_REQUEST src/ap/wpa_auth.h 37;" d +FT_PACKET_RESPONSE src/ap/wpa_auth.h 38;" d +FT_R0KH_ID_MAX_LEN src/common/wpa_common.h 125;" d +FT_R0KH_R1KH_PULL_DATA_LEN src/ap/wpa_auth.h 44;" d +FT_R0KH_R1KH_PUSH_DATA_LEN src/ap/wpa_auth.h 46;" d +FT_R0KH_R1KH_RESP_DATA_LEN src/ap/wpa_auth.h 45;" d +FT_R1KH_ID_LEN src/common/wpa_common.h 126;" d +GAS_DIALOG_MAX src/ap/sta_info.h 118;" d +GAS_RESPONSE_INFO src/common/wpa_ctrl.h 153;" d +GETU32 src/crypto/aes_i.h 116;" d +GETU32 src/crypto/aes_i.h 119;" d +GInit src/ap/wpa_auth_i.h /^ Boolean GInit;$/;" m struct:wpa_group +GKeyDoneStations src/ap/wpa_auth_i.h /^ int GKeyDoneStations;$/;" m struct:wpa_group +GM src/ap/wpa_auth_i.h /^ int GN, GM;$/;" m struct:wpa_group +GMK src/ap/wpa_auth_i.h /^ u8 GMK[WPA_GMK_LEN];$/;" m struct:wpa_group +GM_igtk src/ap/wpa_auth_i.h /^ int GN_igtk, GM_igtk;$/;" m struct:wpa_group +GN src/ap/wpa_auth_i.h /^ int GN, GM;$/;" m struct:wpa_group +GN_igtk src/ap/wpa_auth_i.h /^ int GN_igtk, GM_igtk;$/;" m struct:wpa_group +GNonce src/ap/wpa_auth_i.h /^ u8 GNonce[WPA_NONCE_LEN];$/;" m struct:wpa_group +GTK src/ap/wpa_auth_i.h /^ u8 GTK[2][WPA_GTK_MAX_LEN];$/;" m struct:wpa_group +GTKAuthenticator src/ap/wpa_auth_i.h /^ Boolean GTKAuthenticator;$/;" m struct:wpa_group +GTKReKey src/ap/wpa_auth_i.h /^ Boolean GTKReKey;$/;" m struct:wpa_group +GTK_len src/ap/wpa_auth_i.h /^ int GTK_len;$/;" m struct:wpa_group +GTimeoutCtr src/ap/wpa_auth_i.h /^ int GTimeoutCtr;$/;" m struct:wpa_state_machine +GUpdateStationKeys src/ap/wpa_auth_i.h /^ Boolean GUpdateStationKeys;$/;" m struct:wpa_state_machine +Gamma0 src/crypto/sha256-internal.c 93;" d file: +Gamma1 src/crypto/sha256-internal.c 94;" d file: +HOSTAPD_CONFIG_H src/ap/ap_config.h 10;" d +HOSTAPD_H src/ap/hostapd.h 10;" d +HOSTAPD_MAX_SSID_LEN src/ap/ap_config.h 32;" d +HOSTAPD_MODE_IEEE80211A src/common/defs.h /^ HOSTAPD_MODE_IEEE80211A,$/;" e enum:hostapd_hw_mode +HOSTAPD_MODE_IEEE80211AD src/common/defs.h /^ HOSTAPD_MODE_IEEE80211AD,$/;" e enum:hostapd_hw_mode +HOSTAPD_MODE_IEEE80211B src/common/defs.h /^ HOSTAPD_MODE_IEEE80211B,$/;" e enum:hostapd_hw_mode +HOSTAPD_MODE_IEEE80211G src/common/defs.h /^ HOSTAPD_MODE_IEEE80211G,$/;" e enum:hostapd_hw_mode +HOSTAPD_RATE_BASIC src/ap/hostapd.h 53;" d +HT_CAP_INFO_40MHZ_INTOLERANT src/common/ieee802_11_defs.h 409;" d +HT_CAP_INFO_DELAYED_BA src/common/ieee802_11_defs.h 405;" d +HT_CAP_INFO_DSSS_CCK40MHZ src/common/ieee802_11_defs.h 407;" d +HT_CAP_INFO_GREEN_FIELD src/common/ieee802_11_defs.h 397;" d +HT_CAP_INFO_LDPC_CODING_CAP src/common/ieee802_11_defs.h 391;" d +HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT src/common/ieee802_11_defs.h 410;" d +HT_CAP_INFO_MAX_AMSDU_SIZE src/common/ieee802_11_defs.h 406;" d +HT_CAP_INFO_PSMP_SUPP src/common/ieee802_11_defs.h 408;" d +HT_CAP_INFO_RX_STBC_1 src/common/ieee802_11_defs.h 402;" d +HT_CAP_INFO_RX_STBC_12 src/common/ieee802_11_defs.h 403;" d +HT_CAP_INFO_RX_STBC_123 src/common/ieee802_11_defs.h 404;" d +HT_CAP_INFO_RX_STBC_MASK src/common/ieee802_11_defs.h 401;" d +HT_CAP_INFO_SHORT_GI20MHZ src/common/ieee802_11_defs.h 398;" d +HT_CAP_INFO_SHORT_GI40MHZ src/common/ieee802_11_defs.h 399;" d +HT_CAP_INFO_SMPS_DISABLED src/common/ieee802_11_defs.h 396;" d +HT_CAP_INFO_SMPS_DYNAMIC src/common/ieee802_11_defs.h 395;" d +HT_CAP_INFO_SMPS_MASK src/common/ieee802_11_defs.h 393;" d +HT_CAP_INFO_SMPS_STATIC src/common/ieee802_11_defs.h 394;" d +HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET src/common/ieee802_11_defs.h 392;" d +HT_CAP_INFO_TX_STBC src/common/ieee802_11_defs.h 400;" d +HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY src/common/ieee802_11_defs.h 453;" d +HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH src/common/ieee802_11_defs.h 451;" d +HT_INFO_HT_PARAM_RIFS_MODE src/common/ieee802_11_defs.h 452;" d +HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE src/common/ieee802_11_defs.h 449;" d +HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW src/common/ieee802_11_defs.h 450;" d +HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK src/common/ieee802_11_defs.h 448;" d +HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY src/common/ieee802_11_defs.h 454;" d +HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT src/common/ieee802_11_defs.h 465;" d +HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT src/common/ieee802_11_defs.h 467;" d +HT_INFO_OPERATION_MODE_OP_MODE_MASK src/common/ieee802_11_defs.h 462;" d +HT_INFO_OPERATION_MODE_OP_MODE_OFFSET src/common/ieee802_11_defs.h 464;" d +HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT src/common/ieee802_11_defs.h 466;" d +HT_INFO_STBC_PARAM_DUAL_BEACON src/common/ieee802_11_defs.h 469;" d +HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT src/common/ieee802_11_defs.h 470;" d +HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED src/common/ieee802_11_defs.h 472;" d +HT_INFO_STBC_PARAM_PCO_ACTIVE src/common/ieee802_11_defs.h 473;" d +HT_INFO_STBC_PARAM_PCO_PHASE src/common/ieee802_11_defs.h 474;" d +HT_INFO_STBC_PARAM_SECONDARY_BCN src/common/ieee802_11_defs.h 471;" d +IANA_SECP256R1 src/crypto/crypto_mbedtls.c 30;" d file: +IBSS_RSN_COMPLETED src/common/wpa_ctrl.h 71;" d +ICACHE_RODATA_ATTR src/crypto/crypto_internal-cipher.c /^static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;$/;" v file: +ICACHE_RODATA_ATTR src/crypto/crypto_internal.c /^static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;$/;" v file: +ICACHE_RODATA_ATTR src/fast_crypto/fast_crypto_internal.c /^static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;$/;" v file: +ICACHE_RODATA_ATTR src/tls/libtommath.h /^static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;$/;" v +IEEE80211_BSSID_FROMDS src/common/ieee802_11_defs.h 252;" d +IEEE80211_DA_FROMDS src/common/ieee802_11_defs.h 251;" d +IEEE80211_FC src/common/ieee802_11_defs.h 257;" d +IEEE80211_HDRLEN src/common/ieee802_11_defs.h 255;" d +IEEE80211_SA_FROMDS src/common/ieee802_11_defs.h 253;" d +IEEE8021X_KEY_INDEX_FLAG src/common/eapol_common.h 44;" d +IEEE8021X_KEY_INDEX_MASK src/common/eapol_common.h 45;" d +IEEE8021X_KEY_IV_LEN src/common/eapol_common.h 42;" d +IEEE8021X_KEY_SIGN_LEN src/common/eapol_common.h 41;" d +IEEE8021X_REPLAY_COUNTER_LEN src/common/eapol_common.h 40;" d +IEEE802_11_DEFS_H src/common/ieee802_11_defs.h 17;" d +IEEE802_1X_H src/ap/ieee802_1x.h 10;" d +IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT src/common/eapol_common.h /^ IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4$/;" e enum:__anon85 +IEEE802_1X_TYPE_EAPOL_KEY src/common/eapol_common.h /^ IEEE802_1X_TYPE_EAPOL_KEY = 3,$/;" e enum:__anon85 +IEEE802_1X_TYPE_EAPOL_LOGOFF src/common/eapol_common.h /^ IEEE802_1X_TYPE_EAPOL_LOGOFF = 2,$/;" e enum:__anon85 +IEEE802_1X_TYPE_EAPOL_START src/common/eapol_common.h /^ IEEE802_1X_TYPE_EAPOL_START = 1,$/;" e enum:__anon85 +IEEE802_1X_TYPE_EAP_PACKET src/common/eapol_common.h /^enum { IEEE802_1X_TYPE_EAP_PACKET = 0,$/;" e enum:__anon85 +IGTK src/ap/wpa_auth_i.h /^ u8 IGTK[2][WPA_IGTK_LEN];$/;" m struct:wpa_group +INCLUDES_H src/utils/includes.h 20;" d +INLINE port/include/endian.h 118;" d +INTERWORKING_AP src/common/wpa_ctrl.h 150;" d +INTERWORKING_NO_MATCH src/common/wpa_ctrl.h 151;" d +IS_WPS_ENROLLEE src/esp_supplicant/esp_wifi_driver.h 118;" d +IS_WPS_REGISTRAR src/esp_supplicant/esp_wifi_driver.h 117;" d +Init src/ap/wpa_auth_i.h /^ Boolean Init;$/;" m struct:wpa_state_machine +K src/crypto/sha256-internal.c /^static const unsigned long K[64] = {$/;" v file: +KEYENTRY_TABLE_MAP src/rsn_supp/wpa.h 178;" d +KEY_MGMT_802_1X src/common/defs.h /^ KEY_MGMT_802_1X,$/;" e enum:wpa_key_mgmt +KEY_MGMT_802_1X_NO_WPA src/common/defs.h /^ KEY_MGMT_802_1X_NO_WPA,$/;" e enum:wpa_key_mgmt +KEY_MGMT_802_1X_SHA256 src/common/defs.h /^ KEY_MGMT_802_1X_SHA256,$/;" e enum:wpa_key_mgmt +KEY_MGMT_FT_802_1X src/common/defs.h /^ KEY_MGMT_FT_802_1X,$/;" e enum:wpa_key_mgmt +KEY_MGMT_FT_PSK src/common/defs.h /^ KEY_MGMT_FT_PSK,$/;" e enum:wpa_key_mgmt +KEY_MGMT_NONE src/common/defs.h /^ KEY_MGMT_NONE,$/;" e enum:wpa_key_mgmt +KEY_MGMT_PSK src/common/defs.h /^ KEY_MGMT_PSK,$/;" e enum:wpa_key_mgmt +KEY_MGMT_PSK_SHA256 src/common/defs.h /^ KEY_MGMT_PSK_SHA256,$/;" e enum:wpa_key_mgmt +KEY_MGMT_WPA_NONE src/common/defs.h /^ KEY_MGMT_WPA_NONE,$/;" e enum:wpa_key_mgmt +KEY_MGMT_WPS src/common/defs.h /^ KEY_MGMT_WPS$/;" e enum:wpa_key_mgmt +LIST_H src/utils/list.h 16;" d +LITTLE_ENDIAN port/include/endian.h 40;" d +LOGGER_DEBUG src/ap/wpa_auth.h /^ LOGGER_DEBUG, LOGGER_INFO, LOGGER_WARNING$/;" e enum:__anon20 +LOGGER_INFO src/ap/wpa_auth.h /^ LOGGER_DEBUG, LOGGER_INFO, LOGGER_WARNING$/;" e enum:__anon20 +LOGGER_WARNING src/ap/wpa_auth.h /^ LOGGER_DEBUG, LOGGER_INFO, LOGGER_WARNING$/;" e enum:__anon20 +LONG_PREAMBLE src/ap/ap_config.h /^ LONG_PREAMBLE = 0,$/;" e enum:hostapd_config::__anon19 +LTM_NO_NEG_EXP src/crypto/libtommath.h 59;" d +LTM_NO_NEG_EXP src/tls/libtommath.h 61;" d +MAC2STR include/utils/common.h 259;" d +MACSTR include/utils/common.h 260;" d +MAX src/crypto/libtommath.h 68;" d +MAX src/tls/libtommath.h 70;" d +MAX_CIPHER_COUNT src/tls/tlsv1_client_i.h 42;" d +MAX_CIPHER_COUNT src/tls/tlsv1_server_i.h 37;" d +MAX_CRED_COUNT src/wps/wps_attr_parse.h 92;" d +MAX_REQ_DEV_TYPE_COUNT src/wps/wps_attr_parse.h 97;" d +MAX_STA_COUNT src/ap/ap_config.h 18;" d +MAX_VLAN_ID src/ap/ap_config.h 19;" d +MAX_WPS_PARSE_VENDOR_EXT src/wps/wps.h 71;" d +MAX_WPS_VENDOR_EXTENSIONS src/wps/wps.h 67;" d +MD4Context src/crypto/md4-internal.c /^typedef struct MD4Context {$/;" s file: +MD4Final src/crypto/md4-internal.c /^static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx)$/;" f file: +MD4Init src/crypto/md4-internal.c /^static void MD4Init(MD4_CTX *ctx)$/;" f file: +MD4Pad src/crypto/md4-internal.c /^static void MD4Pad(MD4_CTX *ctx)$/;" f file: +MD4SETP src/crypto/md4-internal.c 132;" d file: +MD4Transform src/crypto/md4-internal.c /^static void MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH])$/;" f file: +MD4Update src/crypto/md4-internal.c /^static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len)$/;" f file: +MD4_BLOCK_LENGTH src/crypto/md4-internal.c 11;" d file: +MD4_CTX src/crypto/md4-internal.c /^} MD4_CTX;$/;" t typeref:struct:MD4Context file: +MD4_DIGEST_LENGTH src/crypto/md4-internal.c 12;" d file: +MD4_DIGEST_STRING_LENGTH src/crypto/md4-internal.c 36;" d file: +MD5Context src/crypto/md5_i.h /^struct MD5Context {$/;" s +MD5Final src/crypto/md5-internal.c /^MD5Final(unsigned char digest[16], struct MD5Context *ctx)$/;" f +MD5Init src/crypto/md5-internal.c /^MD5Init(struct MD5Context *ctx)$/;" f +MD5STEP src/crypto/md5-internal.c 207;" d file: +MD5Transform src/crypto/md5-internal.c /^MD5Transform(u32 buf[4], u32 const in[16])$/;" f file: +MD5Update src/crypto/md5-internal.c /^MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)$/;" f +MD5_CTX src/crypto/md5-internal.c /^typedef struct MD5Context MD5_CTX;$/;" t typeref:struct:MD5Context file: +MD5_H include/crypto/md5.h 16;" d +MD5_I_H src/crypto/md5_i.h 16;" d +MD5_MAC_LEN include/crypto/md5.h 18;" d +MD5_MAC_LEN src/common/wpa_common.c 26;" d file: +METHOD_CONT src/eap_peer/eap_i.h /^ METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE$/;" e enum:__anon2 +METHOD_DONE src/eap_peer/eap_i.h /^ METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE$/;" e enum:__anon2 +METHOD_INIT src/eap_peer/eap_i.h /^ METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE$/;" e enum:__anon2 +METHOD_MAY_CONT src/eap_peer/eap_i.h /^ METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE$/;" e enum:__anon2 +METHOD_NONE src/eap_peer/eap_i.h /^ METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE$/;" e enum:__anon2 +MICVerified src/ap/wpa_auth_i.h /^ Boolean MICVerified;$/;" m struct:wpa_state_machine +MIN src/crypto/libtommath.h 64;" d +MIN src/crypto/sha256-internal.c 96;" d file: +MIN src/tls/libtommath.h 66;" d +MLME_SETPROTECTION_KEY_TYPE_GROUP src/common/defs.h 249;" d +MLME_SETPROTECTION_KEY_TYPE_PAIRWISE src/common/defs.h 250;" d +MLME_SETPROTECTION_PROTECT_TYPE_NONE src/common/defs.h 244;" d +MLME_SETPROTECTION_PROTECT_TYPE_RX src/common/defs.h 245;" d +MLME_SETPROTECTION_PROTECT_TYPE_RX_TX src/common/defs.h 247;" d +MLME_SETPROTECTION_PROTECT_TYPE_TX src/common/defs.h 246;" d +MOBILITY_DOMAIN_ID_LEN src/common/wpa_common.h 124;" d +MP_28BIT src/crypto/libtommath.h 77;" d +MP_28BIT src/tls/libtommath.h 79;" d +MP_EQ src/crypto/libtommath.h 88;" d +MP_EQ src/tls/libtommath.h 90;" d +MP_GT src/crypto/libtommath.h 89;" d +MP_GT src/tls/libtommath.h 91;" d +MP_LOW_MEM src/crypto/libtommath.h 104;" d +MP_LOW_MEM src/tls/libtommath.h 106;" d +MP_LT src/crypto/libtommath.h 87;" d +MP_LT src/tls/libtommath.h 89;" d +MP_MASK src/crypto/libtommath.h 85;" d +MP_MASK src/tls/libtommath.h 87;" d +MP_MEM src/crypto/libtommath.h 95;" d +MP_MEM src/tls/libtommath.h 97;" d +MP_NEG src/crypto/libtommath.h 92;" d +MP_NEG src/tls/libtommath.h 94;" d +MP_NO src/crypto/libtommath.h 99;" d +MP_NO src/tls/libtommath.h 101;" d +MP_OKAY src/crypto/libtommath.h 94;" d +MP_OKAY src/tls/libtommath.h 96;" d +MP_PREC src/crypto/libtommath.h 109;" d +MP_PREC src/crypto/libtommath.h 111;" d +MP_PREC src/tls/libtommath.h 111;" d +MP_PREC src/tls/libtommath.h 113;" d +MP_VAL src/crypto/libtommath.h 96;" d +MP_VAL src/tls/libtommath.h 98;" d +MP_WARRAY src/crypto/libtommath.h 116;" d +MP_WARRAY src/tls/libtommath.h 118;" d +MP_YES src/crypto/libtommath.h 98;" d +MP_YES src/tls/libtommath.h 100;" d +MP_ZPOS src/crypto/libtommath.h 91;" d +MP_ZPOS src/tls/libtommath.h 93;" d +MSCHAPV2_AUTH_RESPONSE_LEN src/eap_peer/mschapv2.h 11;" d +MSCHAPV2_CHAL_LEN src/eap_peer/mschapv2.h 9;" d +MSCHAPV2_H src/eap_peer/mschapv2.h 7;" d +MSCHAPV2_KEY_LEN src/eap_peer/eap_mschapv2.c 32;" d file: +MSCHAPV2_MASTER_KEY_LEN src/eap_peer/mschapv2.h 12;" d +MSCHAPV2_NT_RESPONSE_LEN src/eap_peer/mschapv2.h 10;" d +MSCHAPV2_OP_CHALLENGE src/eap_peer/eap_mschapv2.c 25;" d file: +MSCHAPV2_OP_CHANGE_PASSWORD src/eap_peer/eap_mschapv2.c 29;" d file: +MSCHAPV2_OP_FAILURE src/eap_peer/eap_mschapv2.c 28;" d file: +MSCHAPV2_OP_RESPONSE src/eap_peer/eap_mschapv2.c 26;" d file: +MSCHAPV2_OP_SUCCESS src/eap_peer/eap_mschapv2.c 27;" d file: +MSG_DEBUG include/utils/wpa_debug.h /^enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };$/;" e enum:__anon91 +MSG_DEBUG include/utils/wpa_debug.h 28;" d +MSG_DONTWAIT include/utils/common.h 249;" d +MSG_ERROR include/utils/wpa_debug.h /^enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };$/;" e enum:__anon91 +MSG_ERROR include/utils/wpa_debug.h 25;" d +MSG_INFO include/utils/wpa_debug.h /^enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };$/;" e enum:__anon91 +MSG_INFO include/utils/wpa_debug.h 27;" d +MSG_MSGDUMP include/utils/wpa_debug.h /^enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };$/;" e enum:__anon91 +MSG_MSGDUMP include/utils/wpa_debug.h 29;" d +MSG_PRINT include/utils/wpa_debug.h 62;" d +MSG_WARNING include/utils/wpa_debug.h /^enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };$/;" e enum:__anon91 +MSG_WARNING include/utils/wpa_debug.h 26;" d +MS_FUNCS_H include/crypto/ms_funcs.h 8;" d +Maj src/crypto/sha256-internal.c 88;" d file: +NONE_AUTH src/esp_supplicant/esp_wifi_driver.h /^ NONE_AUTH = 0x01,$/;" e enum:__anon29 +NO_BINDING src/eap_peer/eap_peap.c /^ enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;$/;" e enum:eap_peap_data::__anon7 file: +NUM_DH_GROUPS src/crypto/dh_groups.c 536;" d file: +NUM_ELEMS src/tls/tlsv1_common.c 70;" d file: +NUM_HOSTAPD_MODES src/common/defs.h /^ NUM_HOSTAPD_MODES$/;" e enum:hostapd_hw_mode +NUM_TLS_CIPHER_DATA src/tls/tlsv1_common.c 101;" d file: +NUM_TLS_CIPHER_SUITES src/tls/tlsv1_common.c 71;" d file: +NUM_WEP_KEYS src/ap/ap_config.h 34;" d +NUM_WPS_EI_VALUES src/wps/wps_defs.h /^ NUM_WPS_EI_VALUES$/;" e enum:wps_error_indication +OPTIONAL_BINDING src/eap_peer/eap_peap.c /^ enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;$/;" e enum:eap_peap_data::__anon7 file: +OPT_CAST src/crypto/libtommath.h 71;" d +OPT_CAST src/tls/libtommath.h 73;" d +OP_MODE_20MHZ_HT_STA_ASSOCED src/common/ieee802_11_defs.h 459;" d +OP_MODE_MAY_BE_LEGACY_STAS src/common/ieee802_11_defs.h 458;" d +OP_MODE_MIXED src/common/ieee802_11_defs.h 460;" d +OP_MODE_PURE src/common/ieee802_11_defs.h 457;" d +OS_H port/include/os.h 16;" d +OUI_BROADCOM src/common/ieee802_11_defs.h 590;" d +OUI_MICROSOFT src/common/ieee802_11_defs.h 477;" d +P2P_ALLOW_CROSS_CONNECTION src/ap/ap_config.h 384;" d +P2P_ENABLED src/ap/ap_config.h 380;" d +P2P_EVENT_CROSS_CONNECT_DISABLE src/common/wpa_ctrl.h 127;" d +P2P_EVENT_CROSS_CONNECT_ENABLE src/common/wpa_ctrl.h 126;" d +P2P_EVENT_DEVICE_FOUND src/common/wpa_ctrl.h 112;" d +P2P_EVENT_DEVICE_LOST src/common/wpa_ctrl.h 115;" d +P2P_EVENT_FIND_STOPPED src/common/wpa_ctrl.h 144;" d +P2P_EVENT_GO_NEG_FAILURE src/common/wpa_ctrl.h 121;" d +P2P_EVENT_GO_NEG_REQUEST src/common/wpa_ctrl.h 119;" d +P2P_EVENT_GO_NEG_SUCCESS src/common/wpa_ctrl.h 120;" d +P2P_EVENT_GROUP_FORMATION_FAILURE src/common/wpa_ctrl.h 123;" d +P2P_EVENT_GROUP_FORMATION_SUCCESS src/common/wpa_ctrl.h 122;" d +P2P_EVENT_GROUP_REMOVED src/common/wpa_ctrl.h 125;" d +P2P_EVENT_GROUP_STARTED src/common/wpa_ctrl.h 124;" d +P2P_EVENT_INVITATION_RECEIVED src/common/wpa_ctrl.h 142;" d +P2P_EVENT_INVITATION_RESULT src/common/wpa_ctrl.h 143;" d +P2P_EVENT_PERSISTENT_PSK_FAIL src/common/wpa_ctrl.h 145;" d +P2P_EVENT_PROV_DISC_ENTER_PIN src/common/wpa_ctrl.h 131;" d +P2P_EVENT_PROV_DISC_FAILURE src/common/wpa_ctrl.h 137;" d +P2P_EVENT_PROV_DISC_PBC_REQ src/common/wpa_ctrl.h 133;" d +P2P_EVENT_PROV_DISC_PBC_RESP src/common/wpa_ctrl.h 135;" d +P2P_EVENT_PROV_DISC_SHOW_PIN src/common/wpa_ctrl.h 129;" d +P2P_EVENT_SERV_DISC_REQ src/common/wpa_ctrl.h 139;" d +P2P_EVENT_SERV_DISC_RESP src/common/wpa_ctrl.h 141;" d +P2P_GROUP_FORMATION src/ap/ap_config.h 382;" d +P2P_GROUP_OWNER src/ap/ap_config.h 381;" d +P2P_MANAGE src/ap/ap_config.h 383;" d +PADDING src/crypto/md4-internal.c /^static u8 PADDING[MD4_BLOCK_LENGTH] = {$/;" v file: +PASSWD_CHANGE_CHAL_LEN src/eap_peer/eap_mschapv2.c 31;" d file: +PIN_EXPIRES src/wps/wps_registrar.c 83;" d file: +PIN_LOCKED src/wps/wps_registrar.c 82;" d file: +PInitAKeys src/ap/wpa_auth_i.h /^ Boolean PInitAKeys; \/* WPA only, not in IEEE 802.11i *\/$/;" m struct:wpa_state_machine +PKCS1_H src/tls/pkcs1.h 10;" d +PKCS5_ALG_MD5_DES_CBC src/tls/pkcs5.c /^ PKCS5_ALG_MD5_DES_CBC$/;" e enum:pkcs5_params::pkcs5_alg file: +PKCS5_ALG_UNKNOWN src/tls/pkcs5.c /^ PKCS5_ALG_UNKNOWN,$/;" e enum:pkcs5_params::pkcs5_alg file: +PKCS5_H src/tls/pkcs5.h 10;" d +PKCS8_H src/tls/pkcs8.h 10;" d +PMK src/ap/wpa_auth_i.h /^ u8 PMK[PMK_LEN];$/;" m struct:wpa_state_machine +PMKID_LEN src/common/wpa_common.h 22;" d +PMK_LEN src/ap/ap_config.h 102;" d +PMK_LEN src/common/wpa_common.h 23;" d +PRINTF_FORMAT include/utils/common.h 217;" d +PRINTF_FORMAT include/utils/common.h 220;" d +PRIVATE_KEY_NAME src/eap_peer/eap_i.h 97;" d +PSK_RADIUS_ACCEPTED src/ap/ap_config.h /^ PSK_RADIUS_ACCEPTED = 1,$/;" e enum:hostapd_bss_config::__anon18 +PSK_RADIUS_IGNORED src/ap/ap_config.h /^ PSK_RADIUS_IGNORED = 0,$/;" e enum:hostapd_bss_config::__anon18 +PSK_RADIUS_REQUIRED src/ap/ap_config.h /^ PSK_RADIUS_REQUIRED = 2$/;" e enum:hostapd_bss_config::__anon18 +PTK src/ap/wpa_auth_i.h /^ struct wpa_ptk PTK;$/;" m struct:wpa_state_machine typeref:struct:wpa_state_machine::wpa_ptk +PTKRequest src/ap/wpa_auth_i.h /^ Boolean PTKRequest; \/* not in IEEE 802.11i state machine *\/$/;" m struct:wpa_state_machine +PTK_valid src/ap/wpa_auth_i.h /^ Boolean PTK_valid;$/;" m struct:wpa_state_machine +PUTU32 src/crypto/aes_i.h 117;" d +PUTU32 src/crypto/aes_i.h 121;" d +PUT_32BIT_LE src/crypto/md4-internal.c 50;" d file: +PUT_64BIT_LE src/crypto/md4-internal.c 40;" d file: +PWBLOCK_LEN src/crypto/ms_funcs.c 420;" d file: +Pair src/ap/wpa_auth_i.h /^ Boolean Pair;$/;" m struct:wpa_state_machine +PtkGroupInit src/ap/wpa_auth_i.h /^ Boolean PtkGroupInit; \/* init request for PTK Group state machine *\/$/;" m struct:wpa_state_machine +R src/crypto/sha256-internal.c 90;" d file: +R0 src/crypto/sha1-internal.c 146;" d file: +R1 src/crypto/sha1-internal.c 149;" d file: +R2 src/crypto/sha1-internal.c 152;" d file: +R3 src/crypto/sha1-internal.c 154;" d file: +R4 src/crypto/sha1-internal.c 157;" d file: +RADIUS_ATTR_CHAP_CHALLENGE src/eap_peer/eap_ttls.h 45;" d +RADIUS_ATTR_CHAP_PASSWORD src/eap_peer/eap_ttls.h 43;" d +RADIUS_ATTR_EAP_MESSAGE src/eap_peer/eap_ttls.h 46;" d +RADIUS_ATTR_MS_CHAP2_CPW src/eap_peer/eap_ttls.h 56;" d +RADIUS_ATTR_MS_CHAP2_RESPONSE src/eap_peer/eap_ttls.h 54;" d +RADIUS_ATTR_MS_CHAP2_SUCCESS src/eap_peer/eap_ttls.h 55;" d +RADIUS_ATTR_MS_CHAP_CHALLENGE src/eap_peer/eap_ttls.h 53;" d +RADIUS_ATTR_MS_CHAP_ERROR src/eap_peer/eap_ttls.h 51;" d +RADIUS_ATTR_MS_CHAP_NT_ENC_PW src/eap_peer/eap_ttls.h 52;" d +RADIUS_ATTR_MS_CHAP_RESPONSE src/eap_peer/eap_ttls.h 50;" d +RADIUS_ATTR_REPLY_MESSAGE src/eap_peer/eap_ttls.h 44;" d +RADIUS_ATTR_USER_NAME src/eap_peer/eap_ttls.h 41;" d +RADIUS_ATTR_USER_PASSWORD src/eap_peer/eap_ttls.h 42;" d +RADIUS_VENDOR_ID_MICROSOFT src/eap_peer/eap_ttls.h 49;" d +RANDOM_H include/crypto/random.h 16;" d +RCON src/crypto/aes_i.h 39;" d +RCON src/crypto/aes_i.h 74;" d +RECEIVED_M2D src/wps/wps_i.h /^ RECV_M8, RECEIVED_M2D, WPS_MSG_DONE, RECV_ACK, WPS_FINISHED,$/;" e enum:wps_data::__anon53 +RECV_ACK src/wps/wps_i.h /^ RECV_M8, RECEIVED_M2D, WPS_MSG_DONE, RECV_ACK, WPS_FINISHED,$/;" e enum:wps_data::__anon53 +RECV_DONE src/wps/wps_i.h /^ RECV_M7, SEND_M8, RECV_DONE, SEND_M2D, RECV_M2D_ACK$/;" e enum:wps_data::__anon53 +RECV_M1 src/wps/wps_i.h /^ RECV_M1, SEND_M2, RECV_M3, SEND_M4, RECV_M5, SEND_M6,$/;" e enum:wps_data::__anon53 +RECV_M2 src/wps/wps_i.h /^ SEND_M1, RECV_M2, SEND_M3, RECV_M4, SEND_M5, RECV_M6, SEND_M7,$/;" e enum:wps_data::__anon53 +RECV_M2D_ACK src/wps/wps_i.h /^ RECV_M7, SEND_M8, RECV_DONE, SEND_M2D, RECV_M2D_ACK$/;" e enum:wps_data::__anon53 +RECV_M3 src/wps/wps_i.h /^ RECV_M1, SEND_M2, RECV_M3, SEND_M4, RECV_M5, SEND_M6,$/;" e enum:wps_data::__anon53 +RECV_M4 src/wps/wps_i.h /^ SEND_M1, RECV_M2, SEND_M3, RECV_M4, SEND_M5, RECV_M6, SEND_M7,$/;" e enum:wps_data::__anon53 +RECV_M5 src/wps/wps_i.h /^ RECV_M1, SEND_M2, RECV_M3, SEND_M4, RECV_M5, SEND_M6,$/;" e enum:wps_data::__anon53 +RECV_M6 src/wps/wps_i.h /^ SEND_M1, RECV_M2, SEND_M3, RECV_M4, SEND_M5, RECV_M6, SEND_M7,$/;" e enum:wps_data::__anon53 +RECV_M7 src/wps/wps_i.h /^ RECV_M7, SEND_M8, RECV_DONE, SEND_M2D, RECV_M2D_ACK$/;" e enum:wps_data::__anon53 +RECV_M8 src/wps/wps_i.h /^ RECV_M8, RECEIVED_M2D, WPS_MSG_DONE, RECV_ACK, WPS_FINISHED,$/;" e enum:wps_data::__anon53 +REQUIRE_BINDING src/eap_peer/eap_peap.c /^ enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;$/;" e enum:eap_peap_data::__anon7 file: +RND src/crypto/sha256-internal.c 123;" d file: +ROLc src/crypto/des-internal.c 39;" d file: +RORc src/crypto/des-internal.c 43;" d file: +RORc src/crypto/sha256-internal.c 84;" d file: +ROUND src/crypto/aes-internal-dec.c 103;" d file: +ROUND src/crypto/aes-internal-dec.c 145;" d file: +ROUND src/crypto/aes-internal-enc.c 47;" d file: +ROUND src/crypto/aes-internal-enc.c 89;" d file: +RSA_H src/tls/rsa.h 10;" d +RSNA_MAX_EAPOL_RETRIES src/ap/wpa_auth_i.h 13;" d +RSN_AUTH_KEY_MGMT_802_1X_SHA256 src/common/wpa_common.h 58;" d +RSN_AUTH_KEY_MGMT_FT_802_1X src/common/wpa_common.h 55;" d +RSN_AUTH_KEY_MGMT_FT_PSK src/common/wpa_common.h 56;" d +RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X src/common/wpa_common.h 53;" d +RSN_AUTH_KEY_MGMT_PSK_SHA256 src/common/wpa_common.h 59;" d +RSN_AUTH_KEY_MGMT_UNSPEC_802_1X src/common/wpa_common.h 52;" d +RSN_CIPHER_SUITE_AES_128_CMAC src/common/wpa_common.h 70;" d +RSN_CIPHER_SUITE_CCMP src/common/wpa_common.h 67;" d +RSN_CIPHER_SUITE_GCMP src/common/wpa_common.h 73;" d +RSN_CIPHER_SUITE_NONE src/common/wpa_common.h 61;" d +RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED src/common/wpa_common.h 72;" d +RSN_CIPHER_SUITE_TKIP src/common/wpa_common.h 63;" d +RSN_CIPHER_SUITE_WEP104 src/common/wpa_common.h 68;" d +RSN_CIPHER_SUITE_WEP40 src/common/wpa_common.h 62;" d +RSN_FT_CAPAB_FT_OVER_DS src/common/wpa_common.h 278;" d +RSN_FT_CAPAB_FT_RESOURCE_REQ_SUPP src/common/wpa_common.h 279;" d +RSN_KEY_DATA_ERROR src/common/wpa_common.h 88;" d +RSN_KEY_DATA_GROUPKEY src/common/wpa_common.h 78;" d +RSN_KEY_DATA_IGTK src/common/wpa_common.h 91;" d +RSN_KEY_DATA_LIFETIME src/common/wpa_common.h 87;" d +RSN_KEY_DATA_MAC_ADDR src/common/wpa_common.h 82;" d +RSN_KEY_DATA_NONCE src/common/wpa_common.h 86;" d +RSN_KEY_DATA_PMKID src/common/wpa_common.h 83;" d +RSN_KEY_DATA_SMK src/common/wpa_common.h 85;" d +RSN_NUM_REPLAY_COUNTERS_1 src/common/wpa_common.h 99;" d +RSN_NUM_REPLAY_COUNTERS_16 src/common/wpa_common.h 102;" d +RSN_NUM_REPLAY_COUNTERS_2 src/common/wpa_common.h 100;" d +RSN_NUM_REPLAY_COUNTERS_4 src/common/wpa_common.h 101;" d +RSN_REMOTE_FRAME_TYPE_FT_RRB src/ap/wpa_auth.h 35;" d +RSN_SELECTOR src/common/wpa_common.h 35;" d +RSN_SELECTOR_GET src/common/wpa_common.h 97;" d +RSN_SELECTOR_LEN src/common/wpa_common.h 32;" d +RSN_SELECTOR_PUT src/common/wpa_common.h 96;" d +RSN_VERSION src/common/wpa_common.h 33;" d +ReAuthenticationRequest src/ap/wpa_auth_i.h /^ Boolean ReAuthenticationRequest;$/;" m struct:wpa_state_machine +S src/crypto/sha256-internal.c 89;" d file: +SAE_COMMIT src/ap/sta_info.h /^ enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state;$/;" e enum:sta_info::__anon16 +SAE_CONFIRM src/ap/sta_info.h /^ enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state;$/;" e enum:sta_info::__anon16 +SAE_INIT src/ap/sta_info.h /^ enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state;$/;" e enum:sta_info::__anon16 +SECURITY_IEEE_802_1X src/ap/ap_config.h /^ SECURITY_IEEE_802_1X = 2,$/;" e enum:hostap_security_policy +SECURITY_PLAINTEXT src/ap/ap_config.h /^ SECURITY_PLAINTEXT = 0,$/;" e enum:hostap_security_policy +SECURITY_STATIC_WEP src/ap/ap_config.h /^ SECURITY_STATIC_WEP = 1,$/;" e enum:hostap_security_policy +SECURITY_WPA src/ap/ap_config.h /^ SECURITY_WPA = 4$/;" e enum:hostap_security_policy +SECURITY_WPA_PSK src/ap/ap_config.h /^ SECURITY_WPA_PSK = 3,$/;" e enum:hostap_security_policy +SEND_M1 src/wps/wps_i.h /^ SEND_M1, RECV_M2, SEND_M3, RECV_M4, SEND_M5, RECV_M6, SEND_M7,$/;" e enum:wps_data::__anon53 +SEND_M2 src/wps/wps_i.h /^ RECV_M1, SEND_M2, RECV_M3, SEND_M4, RECV_M5, SEND_M6,$/;" e enum:wps_data::__anon53 +SEND_M2D src/wps/wps_i.h /^ RECV_M7, SEND_M8, RECV_DONE, SEND_M2D, RECV_M2D_ACK$/;" e enum:wps_data::__anon53 +SEND_M3 src/wps/wps_i.h /^ SEND_M1, RECV_M2, SEND_M3, RECV_M4, SEND_M5, RECV_M6, SEND_M7,$/;" e enum:wps_data::__anon53 +SEND_M4 src/wps/wps_i.h /^ RECV_M1, SEND_M2, RECV_M3, SEND_M4, RECV_M5, SEND_M6,$/;" e enum:wps_data::__anon53 +SEND_M5 src/wps/wps_i.h /^ SEND_M1, RECV_M2, SEND_M3, RECV_M4, SEND_M5, RECV_M6, SEND_M7,$/;" e enum:wps_data::__anon53 +SEND_M6 src/wps/wps_i.h /^ RECV_M1, SEND_M2, RECV_M3, SEND_M4, RECV_M5, SEND_M6,$/;" e enum:wps_data::__anon53 +SEND_M7 src/wps/wps_i.h /^ SEND_M1, RECV_M2, SEND_M3, RECV_M4, SEND_M5, RECV_M6, SEND_M7,$/;" e enum:wps_data::__anon53 +SEND_M8 src/wps/wps_i.h /^ RECV_M7, SEND_M8, RECV_DONE, SEND_M2D, RECV_M2D_ACK$/;" e enum:wps_data::__anon53 +SEND_WSC_NACK src/wps/wps_i.h /^ SEND_WSC_NACK,$/;" e enum:wps_data::__anon53 +SERVER_CERTIFICATE src/tls/tlsv1_client_i.h /^ CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,$/;" e enum:tlsv1_client::__anon43 +SERVER_CERTIFICATE src/tls/tlsv1_server_i.h /^ CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,$/;" e enum:tlsv1_server::__anon39 +SERVER_CERTIFICATE_REQUEST src/tls/tlsv1_client_i.h /^ SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,$/;" e enum:tlsv1_client::__anon43 +SERVER_CERTIFICATE_REQUEST src/tls/tlsv1_server_i.h /^ SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,$/;" e enum:tlsv1_server::__anon39 +SERVER_CHANGE_CIPHER_SPEC src/tls/tlsv1_client_i.h /^ SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, ACK_FINISHED,$/;" e enum:tlsv1_client::__anon43 +SERVER_CHANGE_CIPHER_SPEC src/tls/tlsv1_server_i.h /^ SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED,$/;" e enum:tlsv1_server::__anon39 +SERVER_FINISHED src/tls/tlsv1_client_i.h /^ SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, ACK_FINISHED,$/;" e enum:tlsv1_client::__anon43 +SERVER_FINISHED src/tls/tlsv1_server_i.h /^ SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED,$/;" e enum:tlsv1_server::__anon39 +SERVER_HELLO src/tls/tlsv1_client_i.h /^ CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,$/;" e enum:tlsv1_client::__anon43 +SERVER_HELLO src/tls/tlsv1_server_i.h /^ CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,$/;" e enum:tlsv1_server::__anon39 +SERVER_HELLO_DONE src/tls/tlsv1_client_i.h /^ SERVER_HELLO_DONE, CLIENT_KEY_EXCHANGE, CHANGE_CIPHER_SPEC,$/;" e enum:tlsv1_client::__anon43 +SERVER_HELLO_DONE src/tls/tlsv1_server_i.h /^ SERVER_HELLO_DONE, CLIENT_CERTIFICATE, CLIENT_KEY_EXCHANGE,$/;" e enum:tlsv1_server::__anon39 +SERVER_KEY_EXCHANGE src/tls/tlsv1_client_i.h /^ SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,$/;" e enum:tlsv1_client::__anon43 +SERVER_KEY_EXCHANGE src/tls/tlsv1_server_i.h /^ SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,$/;" e enum:tlsv1_server::__anon39 +SHA1Context src/crypto/sha1_i.h /^struct SHA1Context {$/;" s +SHA1Final src/crypto/sha1-internal.c /^SHA1Final(unsigned char digest[20], SHA1_CTX* context)$/;" f +SHA1HANDSOFF src/crypto/sha1-internal.c 130;" d file: +SHA1Init src/crypto/sha1-internal.c /^SHA1Init(SHA1_CTX* context)$/;" f +SHA1Transform src/crypto/sha1-internal.c /^SHA1Transform(u32 state[5], const unsigned char buffer[64])$/;" f +SHA1Update src/crypto/sha1-internal.c /^SHA1Update(SHA1_CTX* context, const void *_data, u32 len)$/;" f +SHA1_CTX src/crypto/sha1-internal.c /^typedef struct SHA1Context SHA1_CTX;$/;" t typeref:struct:SHA1Context file: +SHA1_H include/crypto/sha1.h 16;" d +SHA1_I_H src/crypto/sha1_i.h 16;" d +SHA1_MAC_LEN include/crypto/sha1.h 18;" d +SHA256_BLOCK_SIZE src/crypto/sha256-internal.c 21;" d file: +SHA256_H include/crypto/sha256.h 16;" d +SHA256_MAC_LEN include/crypto/sha256.h 18;" d +SHAPrintContext src/crypto/sha1-internal.c /^void SHAPrintContext(SHA1_CTX *context, char *msg)$/;" f +SHORT_PREAMBLE src/ap/ap_config.h /^ SHORT_PREAMBLE = 1$/;" e enum:hostapd_config::__anon19 +SIG_WPA2 src/eap_peer/eap_i.h /^enum SIG_WPA2 {$/;" g +SIG_WPA2_MAX src/eap_peer/eap_i.h /^ SIG_WPA2_MAX,$/;" e enum:SIG_WPA2 +SIG_WPA2_RX src/eap_peer/eap_i.h /^ SIG_WPA2_RX,$/;" e enum:SIG_WPA2 +SIG_WPA2_START src/eap_peer/eap_i.h /^ SIG_WPA2_START = 0,$/;" e enum:SIG_WPA2 +SIG_WPA2_TASK_DEL src/eap_peer/eap_i.h /^ SIG_WPA2_TASK_DEL,$/;" e enum:SIG_WPA2 +SIG_WPS_DISABLE src/wps/wps.h /^ SIG_WPS_DISABLE, \/\/2$/;" e enum:wps_sig_type +SIG_WPS_ENABLE src/wps/wps.h /^ SIG_WPS_ENABLE = 1, \/\/1$/;" e enum:wps_sig_type +SIG_WPS_NUM src/wps/wps.h /^ SIG_WPS_NUM, \/\/10$/;" e enum:wps_sig_type +SIG_WPS_RX src/wps/wps.h /^ SIG_WPS_RX, \/\/4$/;" e enum:wps_sig_type +SIG_WPS_START src/wps/wps.h /^ SIG_WPS_START, \/\/3$/;" e enum:wps_sig_type +SIG_WPS_TIMER_EAPOL_START src/wps/wps.h /^ SIG_WPS_TIMER_EAPOL_START, \/\/9$/;" e enum:wps_sig_type +SIG_WPS_TIMER_MSG_TIMEOUT src/wps/wps.h /^ SIG_WPS_TIMER_MSG_TIMEOUT, \/\/6$/;" e enum:wps_sig_type +SIG_WPS_TIMER_SCAN src/wps/wps.h /^ SIG_WPS_TIMER_SCAN, \/\/8$/;" e enum:wps_sig_type +SIG_WPS_TIMER_SUCCESS_CB src/wps/wps.h /^ SIG_WPS_TIMER_SUCCESS_CB, \/\/7$/;" e enum:wps_sig_type +SIG_WPS_TIMER_TIMEOUT src/wps/wps.h /^ SIG_WPS_TIMER_TIMEOUT, \/\/5$/;" e enum:wps_sig_type +SM_ENTER src/utils/state_machine.h 101;" d +SM_ENTER_GLOBAL src/utils/state_machine.h 114;" d +SM_ENTRY src/utils/state_machine.h 46;" d +SM_ENTRY_M src/utils/state_machine.h 65;" d +SM_ENTRY_MA src/utils/state_machine.h 83;" d +SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, AUTHENTICATION)$/;" f +SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, AUTHENTICATION2)$/;" f +SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, DISCONNECT)$/;" f +SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, DISCONNECTED)$/;" f +SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, INITIALIZE)$/;" f +SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, INITPMK)$/;" f +SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, INITPSK)$/;" f +SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)$/;" f +SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2)$/;" f +SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, PTKINITDONE)$/;" f +SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, PTKINITNEGOTIATING)$/;" f +SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, PTKSTART)$/;" f +SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK_GROUP, IDLE)$/;" f +SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK_GROUP, KEYERROR)$/;" f +SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)$/;" f +SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)$/;" f +SM_STATE src/utils/state_machine.h 32;" d +SM_STEP src/ap/wpa_auth.c /^SM_STEP(WPA_PTK)$/;" f +SM_STEP src/ap/wpa_auth.c /^SM_STEP(WPA_PTK_GROUP)$/;" f +SM_STEP src/utils/state_machine.h 126;" d +SM_STEP_RUN src/utils/state_machine.h 136;" d +SNonce src/ap/wpa_auth_i.h /^ u8 SNonce[WPA_NONCE_LEN];$/;" m struct:wpa_state_machine +SP1 src/crypto/des-internal.c /^static const u32 SP1[64] =$/;" v file: +SP2 src/crypto/des-internal.c /^static const u32 SP2[64] =$/;" v file: +SP3 src/crypto/des-internal.c /^static const u32 SP3[64] =$/;" v file: +SP4 src/crypto/des-internal.c /^static const u32 SP4[64] =$/;" v file: +SP5 src/crypto/des-internal.c /^static const u32 SP5[64] =$/;" v file: +SP6 src/crypto/des-internal.c /^static const u32 SP6[64] =$/;" v file: +SP7 src/crypto/des-internal.c /^static const u32 SP7[64] =$/;" v file: +SP8 src/crypto/des-internal.c /^static const u32 SP8[64] =$/;" v file: +SSID_LEN src/ap/wpa_auth.h 149;" d +STATE_MACHINE_ADDR src/ap/wpa_auth.c 34;" d file: +STATE_MACHINE_DATA src/ap/wpa_auth.c 32;" d file: +STATE_MACHINE_DEBUG_PREFIX src/ap/wpa_auth.c 33;" d file: +STATE_MACHINE_H src/utils/state_machine.h 21;" d +STA_DEAUTH src/ap/sta_info.h /^ STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE$/;" e enum:sta_info::__anon15 +STA_DISASSOC src/ap/sta_info.h /^ STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE$/;" e enum:sta_info::__anon15 +STA_INFO_H src/ap/sta_info.h 10;" d +STA_NULLFUNC src/ap/sta_info.h /^ STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE$/;" e enum:sta_info::__anon15 +STA_REMOVE src/ap/sta_info.h /^ STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE$/;" e enum:sta_info::__anon15 +STK_ERR_CPHR_NS src/common/wpa_common.h /^ STK_ERR_CPHR_NS = 3,$/;" e enum:__anon65 +STK_ERR_NO_STSL src/common/wpa_common.h /^ STK_ERR_NO_STSL = 4$/;" e enum:__anon65 +STK_ERR_STA_NR src/common/wpa_common.h /^ STK_ERR_STA_NR = 1,$/;" e enum:__anon65 +STK_ERR_STA_NRSN src/common/wpa_common.h /^ STK_ERR_STA_NRSN = 2,$/;" e enum:__anon65 +STK_MUI_4WAY_STAT_STA src/common/wpa_common.h /^ STK_MUI_4WAY_STAT_STA = 2,$/;" e enum:__anon64 +STK_MUI_4WAY_STA_AP src/common/wpa_common.h /^ STK_MUI_4WAY_STA_AP = 1,$/;" e enum:__anon64 +STK_MUI_GTK src/common/wpa_common.h /^ STK_MUI_GTK = 3,$/;" e enum:__anon64 +STK_MUI_SMK src/common/wpa_common.h /^ STK_MUI_SMK = 4$/;" e enum:__anon64 +STRUCT_PACKED include/utils/common.h 218;" d +STRUCT_PACKED include/utils/common.h 221;" d +STRUCT_PACKED src/ap/wpa_auth.h /^} STRUCT_PACKED;$/;" v typeref:struct:ft_r0kh_r1kh_pull_frame +STRUCT_PACKED src/ap/wpa_auth.h /^} STRUCT_PACKED;$/;" v typeref:struct:ft_r0kh_r1kh_push_frame +STRUCT_PACKED src/ap/wpa_auth.h /^} STRUCT_PACKED;$/;" v typeref:struct:ft_r0kh_r1kh_resp_frame +STRUCT_PACKED src/ap/wpa_auth.h /^} STRUCT_PACKED;$/;" v typeref:struct:ft_rrb_frame +STRUCT_PACKED src/common/eapol_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:ieee802_1x_eapol_key +STRUCT_PACKED src/common/eapol_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:ieee802_1x_hdr +STRUCT_PACKED src/common/ieee802_11_defs.h /^} STRUCT_PACKED;$/;" v typeref:struct:wmm_ac_parameter +STRUCT_PACKED src/common/ieee802_11_defs.h /^} STRUCT_PACKED;$/;" v typeref:struct:ieee80211_hdr +STRUCT_PACKED src/common/ieee802_11_defs.h /^} STRUCT_PACKED;$/;" v typeref:struct:ieee80211_ht_capabilities +STRUCT_PACKED src/common/ieee802_11_defs.h /^} STRUCT_PACKED;$/;" v typeref:struct:ieee80211_ht_operation +STRUCT_PACKED src/common/ieee802_11_defs.h /^} STRUCT_PACKED;$/;" v typeref:struct:ieee80211_mgmt +STRUCT_PACKED src/common/ieee802_11_defs.h /^} STRUCT_PACKED;$/;" v typeref:struct:wmm_information_element +STRUCT_PACKED src/common/ieee802_11_defs.h /^} STRUCT_PACKED;$/;" v typeref:struct:wmm_parameter_element +STRUCT_PACKED src/common/ieee802_11_defs.h /^} STRUCT_PACKED;$/;" v typeref:struct:wmm_tspec_element +STRUCT_PACKED src/common/wpa_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:rsn_error_kde +STRUCT_PACKED src/common/wpa_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:rsn_ftie +STRUCT_PACKED src/common/wpa_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:rsn_ie_hdr +STRUCT_PACKED src/common/wpa_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:rsn_mdie +STRUCT_PACKED src/common/wpa_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:rsn_rdie +STRUCT_PACKED src/common/wpa_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:wpa_eapol_key +STRUCT_PACKED src/common/wpa_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:wpa_ie_hdr +STRUCT_PACKED src/common/wpa_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:wpa_igtk_kde +STRUCT_PACKED src/common/wpa_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:wpa_ptk +STRUCT_PACKED src/eap_peer/eap_defs.h /^} STRUCT_PACKED;$/;" v typeref:struct:eap_expand +STRUCT_PACKED src/eap_peer/eap_defs.h /^} STRUCT_PACKED;$/;" v typeref:struct:eap_hdr +STRUCT_PACKED src/eap_peer/eap_tlv_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:eap_tlv_crypto_binding_tlv +STRUCT_PACKED src/eap_peer/eap_tlv_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:eap_tlv_hdr +STRUCT_PACKED src/eap_peer/eap_tlv_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:eap_tlv_intermediate_result_tlv +STRUCT_PACKED src/eap_peer/eap_tlv_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:eap_tlv_nak_tlv +STRUCT_PACKED src/eap_peer/eap_tlv_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:eap_tlv_pac_ack_tlv +STRUCT_PACKED src/eap_peer/eap_tlv_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:eap_tlv_pac_type_tlv +STRUCT_PACKED src/eap_peer/eap_tlv_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:eap_tlv_request_action_tlv +STRUCT_PACKED src/eap_peer/eap_tlv_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:eap_tlv_result_tlv +STRUCT_PACKED src/rsn_supp/wpa.h /^} STRUCT_PACKED;$/;" v typeref:struct:l2_ethhdr +SWAP src/crypto/aes_i.h 115;" d +S_SWAP src/crypto/rc4.c 20;" d file: +Sigma0 src/crypto/sha256-internal.c 91;" d file: +Sigma1 src/crypto/sha256-internal.c 92;" d file: +TAB_SIZE src/crypto/libtommath.h 1906;" d +TAB_SIZE src/crypto/libtommath.h 1908;" d +TAB_SIZE src/tls/libtommath.h 1906;" d +TAB_SIZE src/tls/libtommath.h 1908;" d +TAG include/utils/wpa_debug.h 23;" d +TASK_STACK_SIZE_ADD src/esp_supplicant/esp_wifi_driver.h 22;" d +TASK_STACK_SIZE_ADD src/esp_supplicant/esp_wifi_driver.h 24;" d +TD0 src/crypto/aes_i.h 59;" d +TD0 src/crypto/aes_i.h 99;" d +TD0_ src/crypto/aes_i.h 107;" d +TD0_ src/crypto/aes_i.h 67;" d +TD1 src/crypto/aes_i.h 100;" d +TD1 src/crypto/aes_i.h 60;" d +TD1_ src/crypto/aes_i.h 108;" d +TD1_ src/crypto/aes_i.h 68;" d +TD2 src/crypto/aes_i.h 101;" d +TD2 src/crypto/aes_i.h 61;" d +TD2_ src/crypto/aes_i.h 109;" d +TD2_ src/crypto/aes_i.h 69;" d +TD3 src/crypto/aes_i.h 102;" d +TD3 src/crypto/aes_i.h 62;" d +TD3_ src/crypto/aes_i.h 110;" d +TD3_ src/crypto/aes_i.h 70;" d +TD41 src/crypto/aes_i.h 103;" d +TD41 src/crypto/aes_i.h 63;" d +TD42 src/crypto/aes_i.h 104;" d +TD42 src/crypto/aes_i.h 64;" d +TD43 src/crypto/aes_i.h 105;" d +TD43 src/crypto/aes_i.h 65;" d +TD44 src/crypto/aes_i.h 106;" d +TD44 src/crypto/aes_i.h 66;" d +TDLS_PROHIBIT src/ap/ap_config.h 390;" d +TDLS_PROHIBIT_CHAN_SWITCH src/ap/ap_config.h 391;" d +TE0 src/crypto/aes_i.h 41;" d +TE0 src/crypto/aes_i.h 81;" d +TE1 src/crypto/aes_i.h 42;" d +TE1 src/crypto/aes_i.h 82;" d +TE2 src/crypto/aes_i.h 43;" d +TE2 src/crypto/aes_i.h 83;" d +TE3 src/crypto/aes_i.h 44;" d +TE3 src/crypto/aes_i.h 84;" d +TE4 src/crypto/aes_i.h 57;" d +TE4 src/crypto/aes_i.h 97;" d +TE41 src/crypto/aes_i.h 45;" d +TE41 src/crypto/aes_i.h 85;" d +TE411 src/crypto/aes_i.h 53;" d +TE411 src/crypto/aes_i.h 93;" d +TE414 src/crypto/aes_i.h 52;" d +TE414 src/crypto/aes_i.h 92;" d +TE42 src/crypto/aes_i.h 46;" d +TE42 src/crypto/aes_i.h 86;" d +TE421 src/crypto/aes_i.h 49;" d +TE421 src/crypto/aes_i.h 89;" d +TE422 src/crypto/aes_i.h 54;" d +TE422 src/crypto/aes_i.h 94;" d +TE43 src/crypto/aes_i.h 47;" d +TE43 src/crypto/aes_i.h 87;" d +TE432 src/crypto/aes_i.h 50;" d +TE432 src/crypto/aes_i.h 90;" d +TE433 src/crypto/aes_i.h 55;" d +TE433 src/crypto/aes_i.h 95;" d +TE44 src/crypto/aes_i.h 48;" d +TE44 src/crypto/aes_i.h 88;" d +TE443 src/crypto/aes_i.h 51;" d +TE443 src/crypto/aes_i.h 91;" d +TE444 src/crypto/aes_i.h 56;" d +TE444 src/crypto/aes_i.h 96;" d +TLSV1_CLIENT_H src/tls/tlsv1_client.h 10;" d +TLSV1_CLIENT_I_H src/tls/tlsv1_client_i.h 10;" d +TLSV1_COMMON_H src/tls/tlsv1_common.h 10;" d +TLSV1_CRED_H src/tls/tlsv1_cred.h 10;" d +TLSV1_RECORD_H src/tls/tlsv1_record.h 10;" d +TLSV1_SERVER_H src/tls/tlsv1_server.h 10;" d +TLSV1_SERVER_I_H src/tls/tlsv1_server_i.h 10;" d +TLS_ALERT src/tls/tls.h /^ TLS_ALERT$/;" e enum:tls_event +TLS_ALERT_ACCESS_DENIED src/tls/tlsv1_common.h 145;" d +TLS_ALERT_BAD_CERTIFICATE src/tls/tlsv1_common.h 138;" d +TLS_ALERT_BAD_CERTIFICATE_HASH_VALUE src/tls/tlsv1_common.h 158;" d +TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE src/tls/tlsv1_common.h 157;" d +TLS_ALERT_BAD_RECORD_MAC src/tls/tlsv1_common.h 133;" d +TLS_ALERT_CERTIFICATE_EXPIRED src/tls/tlsv1_common.h 141;" d +TLS_ALERT_CERTIFICATE_REVOKED src/tls/tlsv1_common.h 140;" d +TLS_ALERT_CERTIFICATE_UNKNOWN src/tls/tlsv1_common.h 142;" d +TLS_ALERT_CERTIFICATE_UNOBTAINABLE src/tls/tlsv1_common.h 155;" d +TLS_ALERT_CLOSE_NOTIFY src/tls/tlsv1_common.h 131;" d +TLS_ALERT_DECODE_ERROR src/tls/tlsv1_common.h 146;" d +TLS_ALERT_DECOMPRESSION_FAILURE src/tls/tlsv1_common.h 136;" d +TLS_ALERT_DECRYPTION_FAILED src/tls/tlsv1_common.h 134;" d +TLS_ALERT_DECRYPT_ERROR src/tls/tlsv1_common.h 147;" d +TLS_ALERT_EXPORT_RESTRICTION src/tls/tlsv1_common.h 148;" d +TLS_ALERT_HANDSHAKE_FAILURE src/tls/tlsv1_common.h 137;" d +TLS_ALERT_ILLEGAL_PARAMETER src/tls/tlsv1_common.h 143;" d +TLS_ALERT_INSUFFICIENT_SECURITY src/tls/tlsv1_common.h 150;" d +TLS_ALERT_INTERNAL_ERROR src/tls/tlsv1_common.h 151;" d +TLS_ALERT_LEVEL_FATAL src/tls/tlsv1_common.h 128;" d +TLS_ALERT_LEVEL_WARNING src/tls/tlsv1_common.h 127;" d +TLS_ALERT_NO_RENEGOTIATION src/tls/tlsv1_common.h 153;" d +TLS_ALERT_PROTOCOL_VERSION src/tls/tlsv1_common.h 149;" d +TLS_ALERT_RECORD_OVERFLOW src/tls/tlsv1_common.h 135;" d +TLS_ALERT_UNEXPECTED_MESSAGE src/tls/tlsv1_common.h 132;" d +TLS_ALERT_UNKNOWN_CA src/tls/tlsv1_common.h 144;" d +TLS_ALERT_UNRECOGNIZED_NAME src/tls/tlsv1_common.h 156;" d +TLS_ALERT_UNSUPPORTED_CERTIFICATE src/tls/tlsv1_common.h 139;" d +TLS_ALERT_UNSUPPORTED_EXTENSION src/tls/tlsv1_common.h 154;" d +TLS_ALERT_USER_CANCELED src/tls/tlsv1_common.h 152;" d +TLS_CERT_CHAIN_FAILURE src/tls/tls.h /^ TLS_CERT_CHAIN_FAILURE,$/;" e enum:tls_event +TLS_CERT_CHAIN_SUCCESS src/tls/tls.h /^ TLS_CERT_CHAIN_SUCCESS,$/;" e enum:tls_event +TLS_CHANGE_CIPHER_SPEC src/tls/tlsv1_common.h /^ TLS_CHANGE_CIPHER_SPEC = 1$/;" e enum:__anon48 +TLS_CIPHER_3DES_EDE_CBC src/tls/tlsv1_common.h /^ TLS_CIPHER_3DES_EDE_CBC,$/;" e enum:__anon50 +TLS_CIPHER_AES128_SHA src/tls/tls.h /^ TLS_CIPHER_AES128_SHA \/* 0x002f *\/,$/;" e enum:__anon38 +TLS_CIPHER_AES_128_CBC src/tls/tlsv1_common.h /^ TLS_CIPHER_AES_128_CBC,$/;" e enum:__anon50 +TLS_CIPHER_AES_256_CBC src/tls/tlsv1_common.h /^ TLS_CIPHER_AES_256_CBC$/;" e enum:__anon50 +TLS_CIPHER_ANON_DH_AES128_SHA src/tls/tls.h /^ TLS_CIPHER_ANON_DH_AES128_SHA \/* 0x0034 *\/$/;" e enum:__anon38 +TLS_CIPHER_BLOCK src/tls/tlsv1_common.h /^ TLS_CIPHER_BLOCK$/;" e enum:__anon52 +TLS_CIPHER_DES40_CBC src/tls/tlsv1_common.h /^ TLS_CIPHER_DES40_CBC,$/;" e enum:__anon50 +TLS_CIPHER_DES_CBC src/tls/tlsv1_common.h /^ TLS_CIPHER_DES_CBC,$/;" e enum:__anon50 +TLS_CIPHER_IDEA_CBC src/tls/tlsv1_common.h /^ TLS_CIPHER_IDEA_CBC,$/;" e enum:__anon50 +TLS_CIPHER_NONE src/tls/tls.h /^ TLS_CIPHER_NONE,$/;" e enum:__anon38 +TLS_CIPHER_NULL src/tls/tlsv1_common.h /^ TLS_CIPHER_NULL,$/;" e enum:__anon50 +TLS_CIPHER_RC2_CBC_40 src/tls/tlsv1_common.h /^ TLS_CIPHER_RC2_CBC_40,$/;" e enum:__anon50 +TLS_CIPHER_RC4_128 src/tls/tlsv1_common.h /^ TLS_CIPHER_RC4_128,$/;" e enum:__anon50 +TLS_CIPHER_RC4_40 src/tls/tlsv1_common.h /^ TLS_CIPHER_RC4_40,$/;" e enum:__anon50 +TLS_CIPHER_RC4_SHA src/tls/tls.h /^ TLS_CIPHER_RC4_SHA \/* 0x0005 *\/,$/;" e enum:__anon38 +TLS_CIPHER_RSA_DHE_AES128_SHA src/tls/tls.h /^ TLS_CIPHER_RSA_DHE_AES128_SHA \/* 0x0031 *\/,$/;" e enum:__anon38 +TLS_CIPHER_STREAM src/tls/tlsv1_common.h /^ TLS_CIPHER_STREAM,$/;" e enum:__anon52 +TLS_COMPRESSION_NULL src/tls/tlsv1_common.h 105;" d +TLS_CONN_ALLOW_SIGN_RSA_MD5 src/tls/tls.h 82;" d +TLS_CONN_DISABLE_SESSION_TICKET src/tls/tls.h 84;" d +TLS_CONN_DISABLE_TIME_CHECKS src/tls/tls.h 83;" d +TLS_CONN_REQUEST_OCSP src/tls/tls.h 85;" d +TLS_CONN_REQUIRE_OCSP src/tls/tls.h 86;" d +TLS_CONTENT_TYPE_ALERT src/tls/tlsv1_record.h /^ TLS_CONTENT_TYPE_ALERT = 21,$/;" e enum:__anon44 +TLS_CONTENT_TYPE_APPLICATION_DATA src/tls/tlsv1_record.h /^ TLS_CONTENT_TYPE_APPLICATION_DATA = 23$/;" e enum:__anon44 +TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC src/tls/tlsv1_record.h /^ TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC = 20,$/;" e enum:__anon44 +TLS_CONTENT_TYPE_HANDSHAKE src/tls/tlsv1_record.h /^ TLS_CONTENT_TYPE_HANDSHAKE = 22,$/;" e enum:__anon44 +TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA src/tls/tlsv1_common.h 67;" d +TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA src/tls/tlsv1_common.h 69;" d +TLS_DHE_DSS_WITH_AES_128_CBC_SHA src/tls/tlsv1_common.h 81;" d +TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 src/tls/tlsv1_common.h 95;" d +TLS_DHE_DSS_WITH_AES_256_CBC_SHA src/tls/tlsv1_common.h 87;" d +TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 src/tls/tlsv1_common.h 99;" d +TLS_DHE_DSS_WITH_DES_CBC_SHA src/tls/tlsv1_common.h 68;" d +TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA src/tls/tlsv1_common.h 70;" d +TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA src/tls/tlsv1_common.h 72;" d +TLS_DHE_RSA_WITH_AES_128_CBC_SHA src/tls/tlsv1_common.h 82;" d +TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 src/tls/tlsv1_common.h 96;" d +TLS_DHE_RSA_WITH_AES_256_CBC_SHA src/tls/tlsv1_common.h 88;" d +TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 src/tls/tlsv1_common.h 100;" d +TLS_DHE_RSA_WITH_DES_CBC_SHA src/tls/tlsv1_common.h 71;" d +TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA src/tls/tlsv1_common.h 61;" d +TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA src/tls/tlsv1_common.h 63;" d +TLS_DH_DSS_WITH_AES_128_CBC_SHA src/tls/tlsv1_common.h 79;" d +TLS_DH_DSS_WITH_AES_128_CBC_SHA256 src/tls/tlsv1_common.h 93;" d +TLS_DH_DSS_WITH_AES_256_CBC_SHA src/tls/tlsv1_common.h 85;" d +TLS_DH_DSS_WITH_AES_256_CBC_SHA256 src/tls/tlsv1_common.h 97;" d +TLS_DH_DSS_WITH_DES_CBC_SHA src/tls/tlsv1_common.h 62;" d +TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA src/tls/tlsv1_common.h 64;" d +TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA src/tls/tlsv1_common.h 66;" d +TLS_DH_RSA_WITH_AES_128_CBC_SHA src/tls/tlsv1_common.h 80;" d +TLS_DH_RSA_WITH_AES_128_CBC_SHA256 src/tls/tlsv1_common.h 94;" d +TLS_DH_RSA_WITH_AES_256_CBC_SHA src/tls/tlsv1_common.h 86;" d +TLS_DH_RSA_WITH_AES_256_CBC_SHA256 src/tls/tlsv1_common.h 98;" d +TLS_DH_RSA_WITH_DES_CBC_SHA src/tls/tlsv1_common.h 65;" d +TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA src/tls/tlsv1_common.h 75;" d +TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 src/tls/tlsv1_common.h 73;" d +TLS_DH_anon_WITH_3DES_EDE_CBC_SHA src/tls/tlsv1_common.h 77;" d +TLS_DH_anon_WITH_AES_128_CBC_SHA src/tls/tlsv1_common.h 83;" d +TLS_DH_anon_WITH_AES_128_CBC_SHA256 src/tls/tlsv1_common.h 101;" d +TLS_DH_anon_WITH_AES_256_CBC_SHA src/tls/tlsv1_common.h 89;" d +TLS_DH_anon_WITH_AES_256_CBC_SHA256 src/tls/tlsv1_common.h 102;" d +TLS_DH_anon_WITH_DES_CBC_SHA src/tls/tlsv1_common.h 76;" d +TLS_DH_anon_WITH_RC4_128_MD5 src/tls/tlsv1_common.h 74;" d +TLS_EXT_CLIENT_CERTIFICATE_URL src/tls/tlsv1_common.h 168;" d +TLS_EXT_MAX_FRAGMENT_LENGTH src/tls/tlsv1_common.h 167;" d +TLS_EXT_PAC_OPAQUE src/tls/tlsv1_common.h 174;" d +TLS_EXT_SERVER_NAME src/tls/tlsv1_common.h 166;" d +TLS_EXT_SESSION_TICKET src/tls/tlsv1_common.h 172;" d +TLS_EXT_STATUS_REQUEST src/tls/tlsv1_common.h 171;" d +TLS_EXT_TRUNCATED_HMAC src/tls/tlsv1_common.h 170;" d +TLS_EXT_TRUSTED_CA_KEYS src/tls/tlsv1_common.h 169;" d +TLS_FAIL_ALTSUBJECT_MISMATCH src/tls/tls.h /^ TLS_FAIL_ALTSUBJECT_MISMATCH = 6,$/;" e enum:tls_fail_reason +TLS_FAIL_BAD_CERTIFICATE src/tls/tls.h /^ TLS_FAIL_BAD_CERTIFICATE = 7,$/;" e enum:tls_fail_reason +TLS_FAIL_EXPIRED src/tls/tls.h /^ TLS_FAIL_EXPIRED = 4,$/;" e enum:tls_fail_reason +TLS_FAIL_NOT_YET_VALID src/tls/tls.h /^ TLS_FAIL_NOT_YET_VALID = 3,$/;" e enum:tls_fail_reason +TLS_FAIL_REVOKED src/tls/tls.h /^ TLS_FAIL_REVOKED = 2,$/;" e enum:tls_fail_reason +TLS_FAIL_SERVER_CHAIN_PROBE src/tls/tls.h /^ TLS_FAIL_SERVER_CHAIN_PROBE = 8$/;" e enum:tls_fail_reason +TLS_FAIL_SUBJECT_MISMATCH src/tls/tls.h /^ TLS_FAIL_SUBJECT_MISMATCH = 5,$/;" e enum:tls_fail_reason +TLS_FAIL_UNSPECIFIED src/tls/tls.h /^ TLS_FAIL_UNSPECIFIED = 0,$/;" e enum:tls_fail_reason +TLS_FAIL_UNTRUSTED src/tls/tls.h /^ TLS_FAIL_UNTRUSTED = 1,$/;" e enum:tls_fail_reason +TLS_H src/tls/tls.h 10;" d +TLS_HANDSHAKE_TYPE_CERTIFICATE src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_CERTIFICATE = 11,$/;" e enum:__anon45 +TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST = 13,$/;" e enum:__anon45 +TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS = 22 \/* RFC 4366 *\/$/;" e enum:__anon45 +TLS_HANDSHAKE_TYPE_CERTIFICATE_URL src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_CERTIFICATE_URL = 21 \/* RFC 4366 *\/,$/;" e enum:__anon45 +TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY = 15,$/;" e enum:__anon45 +TLS_HANDSHAKE_TYPE_CLIENT_HELLO src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_CLIENT_HELLO = 1,$/;" e enum:__anon45 +TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE = 16,$/;" e enum:__anon45 +TLS_HANDSHAKE_TYPE_FINISHED src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_FINISHED = 20,$/;" e enum:__anon45 +TLS_HANDSHAKE_TYPE_HELLO_REQUEST src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_HELLO_REQUEST = 0,$/;" e enum:__anon45 +TLS_HANDSHAKE_TYPE_NEW_SESSION_TICKET src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_NEW_SESSION_TICKET = 4 \/* RFC 4507 *\/,$/;" e enum:__anon45 +TLS_HANDSHAKE_TYPE_SERVER_HELLO src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_SERVER_HELLO = 2,$/;" e enum:__anon45 +TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE = 14,$/;" e enum:__anon45 +TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE = 12,$/;" e enum:__anon45 +TLS_HASH_ALG_MD5 src/tls/tlsv1_common.h /^ TLS_HASH_ALG_MD5 = 1,$/;" e enum:__anon46 +TLS_HASH_ALG_NONE src/tls/tlsv1_common.h /^ TLS_HASH_ALG_NONE = 0,$/;" e enum:__anon46 +TLS_HASH_ALG_SHA1 src/tls/tlsv1_common.h /^ TLS_HASH_ALG_SHA1 = 2,$/;" e enum:__anon46 +TLS_HASH_ALG_SHA224 src/tls/tlsv1_common.h /^ TLS_HASH_ALG_SHA224 = 3,$/;" e enum:__anon46 +TLS_HASH_ALG_SHA256 src/tls/tlsv1_common.h /^ TLS_HASH_ALG_SHA256 = 4,$/;" e enum:__anon46 +TLS_HASH_ALG_SHA384 src/tls/tlsv1_common.h /^ TLS_HASH_ALG_SHA384 = 5,$/;" e enum:__anon46 +TLS_HASH_ALG_SHA512 src/tls/tlsv1_common.h /^ TLS_HASH_ALG_SHA512 = 6$/;" e enum:__anon46 +TLS_HASH_MD5 src/tls/tlsv1_common.h /^ TLS_HASH_MD5,$/;" e enum:__anon51 +TLS_HASH_NULL src/tls/tlsv1_common.h /^ TLS_HASH_NULL,$/;" e enum:__anon51 +TLS_HASH_SHA src/tls/tlsv1_common.h /^ TLS_HASH_SHA,$/;" e enum:__anon51 +TLS_HASH_SHA256 src/tls/tlsv1_common.h /^ TLS_HASH_SHA256$/;" e enum:__anon51 +TLS_KEY_X_DHE_DSS src/tls/tlsv1_common.h /^ TLS_KEY_X_DHE_DSS,$/;" e enum:__anon49 +TLS_KEY_X_DHE_DSS_EXPORT src/tls/tlsv1_common.h /^ TLS_KEY_X_DHE_DSS_EXPORT,$/;" e enum:__anon49 +TLS_KEY_X_DHE_RSA src/tls/tlsv1_common.h /^ TLS_KEY_X_DHE_RSA,$/;" e enum:__anon49 +TLS_KEY_X_DHE_RSA_EXPORT src/tls/tlsv1_common.h /^ TLS_KEY_X_DHE_RSA_EXPORT,$/;" e enum:__anon49 +TLS_KEY_X_DH_DSS src/tls/tlsv1_common.h /^ TLS_KEY_X_DH_DSS,$/;" e enum:__anon49 +TLS_KEY_X_DH_DSS_EXPORT src/tls/tlsv1_common.h /^ TLS_KEY_X_DH_DSS_EXPORT,$/;" e enum:__anon49 +TLS_KEY_X_DH_RSA src/tls/tlsv1_common.h /^ TLS_KEY_X_DH_RSA,$/;" e enum:__anon49 +TLS_KEY_X_DH_RSA_EXPORT src/tls/tlsv1_common.h /^ TLS_KEY_X_DH_RSA_EXPORT,$/;" e enum:__anon49 +TLS_KEY_X_DH_anon src/tls/tlsv1_common.h /^ TLS_KEY_X_DH_anon$/;" e enum:__anon49 +TLS_KEY_X_DH_anon_EXPORT src/tls/tlsv1_common.h /^ TLS_KEY_X_DH_anon_EXPORT,$/;" e enum:__anon49 +TLS_KEY_X_NULL src/tls/tlsv1_common.h /^ TLS_KEY_X_NULL,$/;" e enum:__anon49 +TLS_KEY_X_RSA src/tls/tlsv1_common.h /^ TLS_KEY_X_RSA,$/;" e enum:__anon49 +TLS_KEY_X_RSA_EXPORT src/tls/tlsv1_common.h /^ TLS_KEY_X_RSA_EXPORT,$/;" e enum:__anon49 +TLS_MASTER_SECRET_LEN src/tls/tlsv1_common.h 28;" d +TLS_MAX_IV_LEN src/tls/tlsv1_record.h 16;" d +TLS_MAX_KEY_BLOCK_LEN src/tls/tlsv1_record.h 17;" d +TLS_MAX_WRITE_KEY_LEN src/tls/tlsv1_record.h 15;" d +TLS_MAX_WRITE_MAC_SECRET_LEN src/tls/tlsv1_record.h 14;" d +TLS_NULL_WITH_NULL_NULL src/tls/tlsv1_common.h 50;" d +TLS_PEER_CERTIFICATE src/tls/tls.h /^ TLS_PEER_CERTIFICATE,$/;" e enum:tls_event +TLS_PRE_MASTER_SECRET_LEN src/tls/tlsv1_common.h 27;" d +TLS_RANDOM_LEN src/tls/tlsv1_common.h 26;" d +TLS_RECORD_HEADER_LEN src/tls/tlsv1_record.h 21;" d +TLS_RSA_EXPORT_WITH_DES40_CBC_SHA src/tls/tlsv1_common.h 58;" d +TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 src/tls/tlsv1_common.h 56;" d +TLS_RSA_EXPORT_WITH_RC4_40_MD5 src/tls/tlsv1_common.h 53;" d +TLS_RSA_WITH_3DES_EDE_CBC_SHA src/tls/tlsv1_common.h 60;" d +TLS_RSA_WITH_AES_128_CBC_SHA src/tls/tlsv1_common.h 78;" d +TLS_RSA_WITH_AES_128_CBC_SHA256 src/tls/tlsv1_common.h 91;" d +TLS_RSA_WITH_AES_256_CBC_SHA src/tls/tlsv1_common.h 84;" d +TLS_RSA_WITH_AES_256_CBC_SHA256 src/tls/tlsv1_common.h 92;" d +TLS_RSA_WITH_DES_CBC_SHA src/tls/tlsv1_common.h 59;" d +TLS_RSA_WITH_IDEA_CBC_SHA src/tls/tlsv1_common.h 57;" d +TLS_RSA_WITH_NULL_MD5 src/tls/tlsv1_common.h 51;" d +TLS_RSA_WITH_NULL_SHA src/tls/tlsv1_common.h 52;" d +TLS_RSA_WITH_NULL_SHA256 src/tls/tlsv1_common.h 90;" d +TLS_RSA_WITH_RC4_128_MD5 src/tls/tlsv1_common.h 54;" d +TLS_RSA_WITH_RC4_128_SHA src/tls/tlsv1_common.h 55;" d +TLS_SEQ_NUM_LEN src/tls/tlsv1_record.h 20;" d +TLS_SESSION_ID_MAX_LEN src/tls/tlsv1_common.h 29;" d +TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED src/tls/tls.h /^ TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2$/;" e enum:__anon37 +TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED src/tls/tls.h /^ TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3,$/;" e enum:__anon37 +TLS_SIGN_ALG_ANONYMOUS src/tls/tlsv1_common.h /^ TLS_SIGN_ALG_ANONYMOUS = 0,$/;" e enum:__anon47 +TLS_SIGN_ALG_DSA src/tls/tlsv1_common.h /^ TLS_SIGN_ALG_DSA = 2,$/;" e enum:__anon47 +TLS_SIGN_ALG_ECDSA src/tls/tlsv1_common.h /^ TLS_SIGN_ALG_ECDSA = 3,$/;" e enum:__anon47 +TLS_SIGN_ALG_RSA src/tls/tlsv1_common.h /^ TLS_SIGN_ALG_RSA = 1,$/;" e enum:__anon47 +TLS_VERIFY_DATA_LEN src/tls/tlsv1_common.h 30;" d +TLS_VERSION src/tls/tlsv1_common.h 18;" d +TLS_VERSION src/tls/tlsv1_common.h 21;" d +TLS_VERSION src/tls/tlsv1_common.h 23;" d +TLS_VERSION_1 src/tls/tlsv1_common.h 14;" d +TLS_VERSION_1_1 src/tls/tlsv1_common.h 15;" d +TLS_VERSION_1_2 src/tls/tlsv1_common.h 16;" d +TRUE src/common/defs.h /^typedef enum { FALSE = 0, TRUE = 1 } Boolean;$/;" e enum:__anon87 +TRUE src/common/defs.h 22;" d +TX_BEAMFORM_CAP_CALIB_OFFSET src/common/ieee802_11_defs.h 426;" d +TX_BEAMFORM_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET src/common/ieee802_11_defs.h 436;" d +TX_BEAMFORM_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET src/common/ieee802_11_defs.h 434;" d +TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_CAP src/common/ieee802_11_defs.h 429;" d +TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET src/common/ieee802_11_defs.h 430;" d +TX_BEAMFORM_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET src/common/ieee802_11_defs.h 432;" d +TX_BEAMFORM_CAP_EXPLICIT_CSI_TXBF_CAP src/common/ieee802_11_defs.h 427;" d +TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_CAP src/common/ieee802_11_defs.h 428;" d +TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET src/common/ieee802_11_defs.h 431;" d +TX_BEAMFORM_CAP_IMPLICIT_ZLF_CAP src/common/ieee802_11_defs.h 425;" d +TX_BEAMFORM_CAP_MINIMAL_GROUPING_OFFSET src/common/ieee802_11_defs.h 433;" d +TX_BEAMFORM_CAP_RX_STAGGERED_SOUNDING_CAP src/common/ieee802_11_defs.h 421;" d +TX_BEAMFORM_CAP_RX_ZLF_CAP src/common/ieee802_11_defs.h 423;" d +TX_BEAMFORM_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET src/common/ieee802_11_defs.h 437;" d +TX_BEAMFORM_CAP_TXBF_CAP src/common/ieee802_11_defs.h 420;" d +TX_BEAMFORM_CAP_TX_STAGGERED_SOUNDING_CAP src/common/ieee802_11_defs.h 422;" d +TX_BEAMFORM_CAP_TX_ZLF_CAP src/common/ieee802_11_defs.h 424;" d +TX_BEAMFORM_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET src/common/ieee802_11_defs.h 435;" d +Td0 src/crypto/aes-internal.c /^const u32 Td0[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v +Td1 src/crypto/aes-internal.c /^const u32 Td1[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v +Td2 src/crypto/aes-internal.c /^const u32 Td2[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v +Td3 src/crypto/aes-internal.c /^const u32 Td3[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v +Td4 src/crypto/aes-internal.c /^const u32 Td4[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v +Td4s src/crypto/aes-internal.c /^const u8 Td4s[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v +Te0 src/crypto/aes-internal.c /^const u32 Te0[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v +Te1 src/crypto/aes-internal.c /^const u32 Te1[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v +Te2 src/crypto/aes-internal.c /^const u32 Te2[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v +Te3 src/crypto/aes-internal.c /^const u32 Te3[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v +Te4 src/crypto/aes-internal.c /^const u32 Te4[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v +TimeoutCtr src/ap/wpa_auth_i.h /^ int TimeoutCtr;$/;" m struct:wpa_state_machine +TimeoutEvt src/ap/wpa_auth_i.h /^ Boolean TimeoutEvt;$/;" m struct:wpa_state_machine +USERNAME_LEN_MAX src/esp_supplicant/esp_wpa_enterprise.c 969;" d file: +USE_EXTERNAL_RADIUS_AUTH src/ap/ap_config.h /^ USE_EXTERNAL_RADIUS_AUTH = 2$/;" e enum:hostapd_bss_config::__anon17 +UUID_H src/utils/uuid.h 10;" d +UUID_LEN src/utils/uuid.h 12;" d +VENDOR_HT_CAPAB_OUI_TYPE src/common/ieee802_11_defs.h 592;" d +WEPKEY_64_BYTES include/crypto/wepkey.h 4;" d +WEPKEY_H include/crypto/wepkey.h 2;" d +WFA_ELEM_AUTHORIZEDMACS src/wps/wps_defs.h /^ WFA_ELEM_AUTHORIZEDMACS = 0x01,$/;" e enum:__anon55 +WFA_ELEM_NETWORK_KEY_SHAREABLE src/wps/wps_defs.h /^ WFA_ELEM_NETWORK_KEY_SHAREABLE = 0x02,$/;" e enum:__anon55 +WFA_ELEM_REQUEST_TO_ENROLL src/wps/wps_defs.h /^ WFA_ELEM_REQUEST_TO_ENROLL = 0x03,$/;" e enum:__anon55 +WFA_ELEM_SETTINGS_DELAY_TIME src/wps/wps_defs.h /^ WFA_ELEM_SETTINGS_DELAY_TIME = 0x04$/;" e enum:__anon55 +WFA_ELEM_VERSION2 src/wps/wps_defs.h /^ WFA_ELEM_VERSION2 = 0x00,$/;" e enum:__anon55 +WIFI_APPIE_ASSOC_REQ src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_ASSOC_REQ,$/;" e enum:__anon28 +WIFI_APPIE_ASSOC_RESP src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_ASSOC_RESP,$/;" e enum:__anon28 +WIFI_APPIE_COUNTRY src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_COUNTRY,$/;" e enum:__anon28 +WIFI_APPIE_ESP_MANUFACTOR src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_ESP_MANUFACTOR,$/;" e enum:__anon28 +WIFI_APPIE_FREQ_ERROR src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_FREQ_ERROR,$/;" e enum:__anon28 +WIFI_APPIE_MAX src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_MAX,$/;" e enum:__anon28 +WIFI_APPIE_MESH_QUICK src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_MESH_QUICK,$/;" e enum:__anon28 +WIFI_APPIE_PROBEREQ src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_PROBEREQ = 0,$/;" e enum:__anon28 +WIFI_APPIE_RSN src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_RSN,$/;" e enum:__anon28 +WIFI_APPIE_WPA src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_WPA,$/;" e enum:__anon28 +WIFI_APPIE_WPS_AR src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_WPS_AR,$/;" e enum:__anon28 +WIFI_APPIE_WPS_PR src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_WPS_PR,$/;" e enum:__anon28 +WIFI_CAPINFO_PRIVACY src/wps/wps.h 1063;" d +WIFI_TID_SIZE src/esp_supplicant/esp_wifi_driver.h 144;" d +WIFI_TXCB_EAPOL_ID src/esp_supplicant/esp_wifi_driver.h 134;" d +WLAN_ACTION_BLOCK_ACK src/common/ieee802_11_defs.h 216;" d +WLAN_ACTION_DLS src/common/ieee802_11_defs.h 215;" d +WLAN_ACTION_FT src/common/ieee802_11_defs.h 219;" d +WLAN_ACTION_HT src/common/ieee802_11_defs.h 220;" d +WLAN_ACTION_PUBLIC src/common/ieee802_11_defs.h 217;" d +WLAN_ACTION_QOS src/common/ieee802_11_defs.h 214;" d +WLAN_ACTION_RADIO_MEASUREMENT src/common/ieee802_11_defs.h 218;" d +WLAN_ACTION_SA_QUERY src/common/ieee802_11_defs.h 221;" d +WLAN_ACTION_SPECTRUM_MGMT src/common/ieee802_11_defs.h 213;" d +WLAN_ACTION_WMM src/common/ieee802_11_defs.h 222;" d +WLAN_AKM_SUITE_8021X src/common/ieee802_11_defs.h 604;" d +WLAN_AKM_SUITE_PSK src/common/ieee802_11_defs.h 605;" d +WLAN_AUTH_CHALLENGE_LEN src/common/ieee802_11_defs.h 81;" d +WLAN_AUTH_FT src/common/ieee802_11_defs.h 78;" d +WLAN_AUTH_LEAP src/common/ieee802_11_defs.h 79;" d +WLAN_AUTH_OPEN src/common/ieee802_11_defs.h 76;" d +WLAN_AUTH_SHARED_KEY src/common/ieee802_11_defs.h 77;" d +WLAN_CAPABILITY_CF_POLLABLE src/common/ieee802_11_defs.h 85;" d +WLAN_CAPABILITY_CF_POLL_REQUEST src/common/ieee802_11_defs.h 86;" d +WLAN_CAPABILITY_CHANNEL_AGILITY src/common/ieee802_11_defs.h 90;" d +WLAN_CAPABILITY_DSSS_OFDM src/common/ieee802_11_defs.h 93;" d +WLAN_CAPABILITY_ESS src/common/ieee802_11_defs.h 83;" d +WLAN_CAPABILITY_IBSS src/common/ieee802_11_defs.h 84;" d +WLAN_CAPABILITY_PBCC src/common/ieee802_11_defs.h 89;" d +WLAN_CAPABILITY_PRIVACY src/common/ieee802_11_defs.h 87;" d +WLAN_CAPABILITY_SHORT_PREAMBLE src/common/ieee802_11_defs.h 88;" d +WLAN_CAPABILITY_SHORT_SLOT_TIME src/common/ieee802_11_defs.h 92;" d +WLAN_CAPABILITY_SPECTRUM_MGMT src/common/ieee802_11_defs.h 91;" d +WLAN_CIPHER_SUITE_AES_CMAC src/common/ieee802_11_defs.h 601;" d +WLAN_CIPHER_SUITE_CCMP src/common/ieee802_11_defs.h 599;" d +WLAN_CIPHER_SUITE_TKIP src/common/ieee802_11_defs.h 597;" d +WLAN_CIPHER_SUITE_USE_GROUP src/common/ieee802_11_defs.h 595;" d +WLAN_CIPHER_SUITE_WEP104 src/common/ieee802_11_defs.h 600;" d +WLAN_CIPHER_SUITE_WEP40 src/common/ieee802_11_defs.h 596;" d +WLAN_EID_20_40_BSS_COEXISTENCE src/common/ieee802_11_defs.h 205;" d +WLAN_EID_20_40_BSS_INTOLERANT src/common/ieee802_11_defs.h 206;" d +WLAN_EID_CF_PARAMS src/common/ieee802_11_defs.h 178;" d +WLAN_EID_CHALLENGE src/common/ieee802_11_defs.h 182;" d +WLAN_EID_CHANNEL_SWITCH src/common/ieee802_11_defs.h 189;" d +WLAN_EID_COUNTRY src/common/ieee802_11_defs.h 181;" d +WLAN_EID_DS_PARAMS src/common/ieee802_11_defs.h 177;" d +WLAN_EID_ERP_INFO src/common/ieee802_11_defs.h 195;" d +WLAN_EID_EXT_SUPP_RATES src/common/ieee802_11_defs.h 198;" d +WLAN_EID_FAST_BSS_TRANSITION src/common/ieee802_11_defs.h 200;" d +WLAN_EID_FH_PARAMS src/common/ieee802_11_defs.h 176;" d +WLAN_EID_HT_CAP src/common/ieee802_11_defs.h 196;" d +WLAN_EID_HT_OPERATION src/common/ieee802_11_defs.h 203;" d +WLAN_EID_IBSS_DFS src/common/ieee802_11_defs.h 193;" d +WLAN_EID_IBSS_PARAMS src/common/ieee802_11_defs.h 180;" d +WLAN_EID_MEASURE_REPORT src/common/ieee802_11_defs.h 191;" d +WLAN_EID_MEASURE_REQUEST src/common/ieee802_11_defs.h 190;" d +WLAN_EID_MMIE src/common/ieee802_11_defs.h 208;" d +WLAN_EID_MOBILITY_DOMAIN src/common/ieee802_11_defs.h 199;" d +WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS src/common/ieee802_11_defs.h 207;" d +WLAN_EID_PWR_CAPABILITY src/common/ieee802_11_defs.h 185;" d +WLAN_EID_PWR_CONSTRAINT src/common/ieee802_11_defs.h 184;" d +WLAN_EID_QUITE src/common/ieee802_11_defs.h 192;" d +WLAN_EID_RIC_DATA src/common/ieee802_11_defs.h 202;" d +WLAN_EID_RSN src/common/ieee802_11_defs.h 197;" d +WLAN_EID_SECONDARY_CHANNEL_OFFSET src/common/ieee802_11_defs.h 204;" d +WLAN_EID_SSID src/common/ieee802_11_defs.h 174;" d +WLAN_EID_SUPPORTED_CHANNELS src/common/ieee802_11_defs.h 188;" d +WLAN_EID_SUPP_RATES src/common/ieee802_11_defs.h 175;" d +WLAN_EID_TIM src/common/ieee802_11_defs.h 179;" d +WLAN_EID_TIMEOUT_INTERVAL src/common/ieee802_11_defs.h 201;" d +WLAN_EID_TPC_REPORT src/common/ieee802_11_defs.h 187;" d +WLAN_EID_TPC_REQUEST src/common/ieee802_11_defs.h 186;" d +WLAN_EID_VENDOR_SPECIFIC src/common/ieee802_11_defs.h 209;" d +WLAN_FC_FROMDS src/common/ieee802_11_defs.h 23;" d +WLAN_FC_GET_STYPE src/common/ieee802_11_defs.h 32;" d +WLAN_FC_GET_TYPE src/common/ieee802_11_defs.h 31;" d +WLAN_FC_ISWEP src/common/ieee802_11_defs.h 28;" d +WLAN_FC_MOREDATA src/common/ieee802_11_defs.h 27;" d +WLAN_FC_MOREFRAG src/common/ieee802_11_defs.h 24;" d +WLAN_FC_ORDER src/common/ieee802_11_defs.h 29;" d +WLAN_FC_PVER src/common/ieee802_11_defs.h 21;" d +WLAN_FC_PWRMGT src/common/ieee802_11_defs.h 26;" d +WLAN_FC_RETRY src/common/ieee802_11_defs.h 25;" d +WLAN_FC_STYPE_ACK src/common/ieee802_11_defs.h 60;" d +WLAN_FC_STYPE_ACTION src/common/ieee802_11_defs.h 54;" d +WLAN_FC_STYPE_ASSOC_REQ src/common/ieee802_11_defs.h 43;" d +WLAN_FC_STYPE_ASSOC_RESP src/common/ieee802_11_defs.h 44;" d +WLAN_FC_STYPE_ATIM src/common/ieee802_11_defs.h 50;" d +WLAN_FC_STYPE_AUTH src/common/ieee802_11_defs.h 52;" d +WLAN_FC_STYPE_BEACON src/common/ieee802_11_defs.h 49;" d +WLAN_FC_STYPE_CFACK src/common/ieee802_11_defs.h 70;" d +WLAN_FC_STYPE_CFACKPOLL src/common/ieee802_11_defs.h 72;" d +WLAN_FC_STYPE_CFEND src/common/ieee802_11_defs.h 61;" d +WLAN_FC_STYPE_CFENDACK src/common/ieee802_11_defs.h 62;" d +WLAN_FC_STYPE_CFPOLL src/common/ieee802_11_defs.h 71;" d +WLAN_FC_STYPE_CTS src/common/ieee802_11_defs.h 59;" d +WLAN_FC_STYPE_DATA src/common/ieee802_11_defs.h 65;" d +WLAN_FC_STYPE_DATA_CFACK src/common/ieee802_11_defs.h 66;" d +WLAN_FC_STYPE_DATA_CFACKPOLL src/common/ieee802_11_defs.h 68;" d +WLAN_FC_STYPE_DATA_CFPOLL src/common/ieee802_11_defs.h 67;" d +WLAN_FC_STYPE_DEAUTH src/common/ieee802_11_defs.h 53;" d +WLAN_FC_STYPE_DISASSOC src/common/ieee802_11_defs.h 51;" d +WLAN_FC_STYPE_NULLFUNC src/common/ieee802_11_defs.h 69;" d +WLAN_FC_STYPE_PROBE_REQ src/common/ieee802_11_defs.h 47;" d +WLAN_FC_STYPE_PROBE_RESP src/common/ieee802_11_defs.h 48;" d +WLAN_FC_STYPE_PSPOLL src/common/ieee802_11_defs.h 57;" d +WLAN_FC_STYPE_QOS_DATA src/common/ieee802_11_defs.h 73;" d +WLAN_FC_STYPE_REASSOC_REQ src/common/ieee802_11_defs.h 45;" d +WLAN_FC_STYPE_REASSOC_RESP src/common/ieee802_11_defs.h 46;" d +WLAN_FC_STYPE_RTS src/common/ieee802_11_defs.h 58;" d +WLAN_FC_TODS src/common/ieee802_11_defs.h 22;" d +WLAN_FC_TYPE_CTRL src/common/ieee802_11_defs.h 39;" d +WLAN_FC_TYPE_DATA src/common/ieee802_11_defs.h 40;" d +WLAN_FC_TYPE_MGMT src/common/ieee802_11_defs.h 38;" d +WLAN_GET_SEQ_FRAG src/common/ieee802_11_defs.h 34;" d +WLAN_GET_SEQ_SEQ src/common/ieee802_11_defs.h 35;" d +WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT src/common/ieee802_11_defs.h 161;" d +WLAN_REASON_AKMP_NOT_VALID src/common/ieee802_11_defs.h 166;" d +WLAN_REASON_CIPHER_SUITE_REJECTED src/common/ieee802_11_defs.h 170;" d +WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA src/common/ieee802_11_defs.h 151;" d +WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA src/common/ieee802_11_defs.h 152;" d +WLAN_REASON_DEAUTH_LEAVING src/common/ieee802_11_defs.h 148;" d +WLAN_REASON_DISASSOC_AP_BUSY src/common/ieee802_11_defs.h 150;" d +WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY src/common/ieee802_11_defs.h 149;" d +WLAN_REASON_DISASSOC_STA_HAS_LEFT src/common/ieee802_11_defs.h 153;" d +WLAN_REASON_GROUP_CIPHER_NOT_VALID src/common/ieee802_11_defs.h 164;" d +WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT src/common/ieee802_11_defs.h 162;" d +WLAN_REASON_IEEE_802_1X_AUTH_FAILED src/common/ieee802_11_defs.h 169;" d +WLAN_REASON_IE_IN_4WAY_DIFFERS src/common/ieee802_11_defs.h 163;" d +WLAN_REASON_INVALID_IE src/common/ieee802_11_defs.h 159;" d +WLAN_REASON_INVALID_RSN_IE_CAPAB src/common/ieee802_11_defs.h 168;" d +WLAN_REASON_MICHAEL_MIC_FAILURE src/common/ieee802_11_defs.h 160;" d +WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID src/common/ieee802_11_defs.h 165;" d +WLAN_REASON_PREV_AUTH_NOT_VALID src/common/ieee802_11_defs.h 147;" d +WLAN_REASON_PWR_CAPABILITY_NOT_VALID src/common/ieee802_11_defs.h 156;" d +WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH src/common/ieee802_11_defs.h 154;" d +WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID src/common/ieee802_11_defs.h 157;" d +WLAN_REASON_UNSPECIFIED src/common/ieee802_11_defs.h 146;" d +WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION src/common/ieee802_11_defs.h 167;" d +WLAN_SA_QUERY_REQUEST src/common/ieee802_11_defs.h 225;" d +WLAN_SA_QUERY_RESPONSE src/common/ieee802_11_defs.h 226;" d +WLAN_SA_QUERY_TR_ID_LEN src/common/ieee802_11_defs.h 228;" d +WLAN_STATUS_AKMP_NOT_VALID src/common/ieee802_11_defs.h 130;" d +WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA src/common/ieee802_11_defs.h 105;" d +WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE src/common/ieee802_11_defs.h 138;" d +WLAN_STATUS_ASSOC_DENIED_NOAGILITY src/common/ieee802_11_defs.h 110;" d +WLAN_STATUS_ASSOC_DENIED_NOPBCC src/common/ieee802_11_defs.h 109;" d +WLAN_STATUS_ASSOC_DENIED_NOSHORT src/common/ieee802_11_defs.h 108;" d +WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM src/common/ieee802_11_defs.h 118;" d +WLAN_STATUS_ASSOC_DENIED_NO_ER_PBCC src/common/ieee802_11_defs.h 117;" d +WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME src/common/ieee802_11_defs.h 116;" d +WLAN_STATUS_ASSOC_DENIED_RATES src/common/ieee802_11_defs.h 106;" d +WLAN_STATUS_ASSOC_DENIED_UNSPEC src/common/ieee802_11_defs.h 100;" d +WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY src/common/ieee802_11_defs.h 121;" d +WLAN_STATUS_AUTH_TIMEOUT src/common/ieee802_11_defs.h 104;" d +WLAN_STATUS_CAPS_UNSUPPORTED src/common/ieee802_11_defs.h 98;" d +WLAN_STATUS_CHALLENGE_FAIL src/common/ieee802_11_defs.h 103;" d +WLAN_STATUS_CIPHER_REJECTED_PER_POLICY src/common/ieee802_11_defs.h 133;" d +WLAN_STATUS_DEST_STA_NOT_PRESENT src/common/ieee802_11_defs.h 136;" d +WLAN_STATUS_DEST_STA_NOT_QOS_STA src/common/ieee802_11_defs.h 137;" d +WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED src/common/ieee802_11_defs.h 135;" d +WLAN_STATUS_GROUP_CIPHER_NOT_VALID src/common/ieee802_11_defs.h 128;" d +WLAN_STATUS_INVALID_FTIE src/common/ieee802_11_defs.h 143;" d +WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT src/common/ieee802_11_defs.h 140;" d +WLAN_STATUS_INVALID_IE src/common/ieee802_11_defs.h 127;" d +WLAN_STATUS_INVALID_MDIE src/common/ieee802_11_defs.h 142;" d +WLAN_STATUS_INVALID_PARAMETERS src/common/ieee802_11_defs.h 125;" d +WLAN_STATUS_INVALID_PMKID src/common/ieee802_11_defs.h 141;" d +WLAN_STATUS_INVALID_RSN_IE_CAPAB src/common/ieee802_11_defs.h 132;" d +WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG src/common/ieee802_11_defs.h 101;" d +WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID src/common/ieee802_11_defs.h 129;" d +WLAN_STATUS_PWR_CAPABILITY_NOT_VALID src/common/ieee802_11_defs.h 113;" d +WLAN_STATUS_R0KH_UNREACHABLE src/common/ieee802_11_defs.h 119;" d +WLAN_STATUS_REASSOC_NO_ASSOC src/common/ieee802_11_defs.h 99;" d +WLAN_STATUS_REQUEST_DECLINED src/common/ieee802_11_defs.h 124;" d +WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION src/common/ieee802_11_defs.h 122;" d +WLAN_STATUS_SPEC_MGMT_REQUIRED src/common/ieee802_11_defs.h 112;" d +WLAN_STATUS_SUCCESS src/common/ieee802_11_defs.h 96;" d +WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID src/common/ieee802_11_defs.h 114;" d +WLAN_STATUS_TS_NOT_CREATED src/common/ieee802_11_defs.h 134;" d +WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION src/common/ieee802_11_defs.h 102;" d +WLAN_STATUS_UNSPECIFIED_FAILURE src/common/ieee802_11_defs.h 97;" d +WLAN_STATUS_UNSPECIFIED_QOS_FAILURE src/common/ieee802_11_defs.h 123;" d +WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION src/common/ieee802_11_defs.h 131;" d +WLAN_STA_ASSOC src/ap/sta_info.h 14;" d +WLAN_STA_ASSOC_REQ_OK src/ap/sta_info.h 28;" d +WLAN_STA_AUTH src/ap/sta_info.h 13;" d +WLAN_STA_AUTHORIZED src/ap/sta_info.h 18;" d +WLAN_STA_GAS src/ap/sta_info.h 30;" d +WLAN_STA_HT src/ap/sta_info.h 24;" d +WLAN_STA_MAYBE_WPS src/ap/sta_info.h 26;" d +WLAN_STA_MFP src/ap/sta_info.h 23;" d +WLAN_STA_NONERP src/ap/sta_info.h 34;" d +WLAN_STA_PENDING_DEAUTH_CB src/ap/sta_info.h 33;" d +WLAN_STA_PENDING_DISASSOC_CB src/ap/sta_info.h 32;" d +WLAN_STA_PENDING_POLL src/ap/sta_info.h 19;" d +WLAN_STA_PERM src/ap/sta_info.h 17;" d +WLAN_STA_PREAUTH src/ap/sta_info.h 21;" d +WLAN_STA_PS src/ap/sta_info.h 15;" d +WLAN_STA_SHORT_PREAMBLE src/ap/sta_info.h 20;" d +WLAN_STA_TIM src/ap/sta_info.h 16;" d +WLAN_STA_VHT src/ap/sta_info.h 31;" d +WLAN_STA_WDS src/ap/sta_info.h 27;" d +WLAN_STA_WMM src/ap/sta_info.h 22;" d +WLAN_STA_WPS src/ap/sta_info.h 25;" d +WLAN_STA_WPS2 src/ap/sta_info.h 29;" d +WLAN_SUPP_RATES_MAX src/ap/sta_info.h 38;" d +WLAN_TIMEOUT_ASSOC_COMEBACK src/common/ieee802_11_defs.h 233;" d +WLAN_TIMEOUT_KEY_LIFETIME src/common/ieee802_11_defs.h 232;" d +WLAN_TIMEOUT_REASSOC_DEADLINE src/common/ieee802_11_defs.h 231;" d +WMM_ACTION_CODE_ADDTS_REQ src/common/ieee802_11_defs.h 488;" d +WMM_ACTION_CODE_ADDTS_RESP src/common/ieee802_11_defs.h 489;" d +WMM_ACTION_CODE_DELTS src/common/ieee802_11_defs.h 490;" d +WMM_AC_ACI_MASK src/common/ieee802_11_defs.h 522;" d +WMM_AC_ACI_SHIFT src/common/ieee802_11_defs.h 523;" d +WMM_AC_ACM src/common/ieee802_11_defs.h 521;" d +WMM_AC_AIFNS_SHIFT src/common/ieee802_11_defs.h 520;" d +WMM_AC_AIFSN_MASK src/common/ieee802_11_defs.h 519;" d +WMM_AC_BE src/common/ieee802_11_defs.h /^ WMM_AC_BE = 0 \/* Best Effort *\/,$/;" e enum:__anon84 +WMM_AC_BK src/common/ieee802_11_defs.h /^ WMM_AC_BK = 1 \/* Background *\/,$/;" e enum:__anon84 +WMM_AC_ECWMAX_MASK src/common/ieee802_11_defs.h 527;" d +WMM_AC_ECWMAX_SHIFT src/common/ieee802_11_defs.h 528;" d +WMM_AC_ECWMIN_MASK src/common/ieee802_11_defs.h 525;" d +WMM_AC_ECWMIN_SHIFT src/common/ieee802_11_defs.h 526;" d +WMM_AC_VI src/common/ieee802_11_defs.h /^ WMM_AC_VI = 2 \/* Video *\/,$/;" e enum:__anon84 +WMM_AC_VO src/common/ieee802_11_defs.h /^ WMM_AC_VO = 3 \/* Voice *\/$/;" e enum:__anon84 +WMM_ADDTS_STATUS_ADMISSION_ACCEPTED src/common/ieee802_11_defs.h 492;" d +WMM_ADDTS_STATUS_INVALID_PARAMETERS src/common/ieee802_11_defs.h 493;" d +WMM_ADDTS_STATUS_REFUSED src/common/ieee802_11_defs.h 495;" d +WMM_OUI_SUBTYPE_INFORMATION_ELEMENT src/common/ieee802_11_defs.h 483;" d +WMM_OUI_SUBTYPE_PARAMETER_ELEMENT src/common/ieee802_11_defs.h 484;" d +WMM_OUI_SUBTYPE_TSPEC_ELEMENT src/common/ieee802_11_defs.h 485;" d +WMM_OUI_TYPE src/common/ieee802_11_defs.h 482;" d +WMM_TSPEC_DIRECTION_BI_DIRECTIONAL src/common/ieee802_11_defs.h 502;" d +WMM_TSPEC_DIRECTION_DOWNLINK src/common/ieee802_11_defs.h 500;" d +WMM_TSPEC_DIRECTION_UPLINK src/common/ieee802_11_defs.h 499;" d +WMM_VERSION src/common/ieee802_11_defs.h 486;" d +WORDS_BIGENDIAN include/utils/common.h 116;" d +WPA2_AUTH_CCKM src/esp_supplicant/esp_wifi_driver.h /^ WPA2_AUTH_CCKM = 0x07,$/;" e enum:__anon29 +WPA2_AUTH_ENT src/esp_supplicant/esp_wifi_driver.h /^ WPA2_AUTH_ENT = 0x04,$/;" e enum:__anon29 +WPA2_AUTH_PSK src/esp_supplicant/esp_wifi_driver.h /^ WPA2_AUTH_PSK = 0x05,$/;" e enum:__anon29 +WPA2_CONFIG_INIT_DEFAULT include/esp_supplicant/esp_wpa_enterprise.h 29;" d +WPA2_ENT_EAP_STATE_FAIL src/esp_supplicant/esp_wifi_driver.h /^ WPA2_ENT_EAP_STATE_FAIL,$/;" e enum:__anon30 +WPA2_ENT_EAP_STATE_IN_PROGRESS src/esp_supplicant/esp_wifi_driver.h /^ WPA2_ENT_EAP_STATE_IN_PROGRESS,$/;" e enum:__anon30 +WPA2_ENT_EAP_STATE_NOT_START src/esp_supplicant/esp_wifi_driver.h /^ WPA2_ENT_EAP_STATE_NOT_START,$/;" e enum:__anon30 +WPA2_ENT_EAP_STATE_SUCCESS src/esp_supplicant/esp_wifi_driver.h /^ WPA2_ENT_EAP_STATE_SUCCESS,$/;" e enum:__anon30 +WPA2_STATE_DISABLED src/eap_peer/eap_i.h /^ WPA2_STATE_DISABLED,$/;" e enum:__anon3 +WPA2_STATE_ENABLED src/eap_peer/eap_i.h /^ WPA2_STATE_ENABLED = 0,$/;" e enum:__anon3 +WPA2_TASK_STACK_SIZE src/esp_supplicant/esp_wifi_driver.h 27;" d +WPA2_VERSION src/esp_supplicant/esp_wpa_enterprise.c 48;" d file: +WPABUF_H include/utils/wpabuf.h 16;" d +WPABUF_MAGIC src/utils/wpabuf.c 25;" d file: +WPAS_GLUE_H src/esp_supplicant/esp_wpas_glue.h 16;" d +WPA_4_4_HANDSHAKE_BIT src/rsn_supp/wpa.c 43;" d file: +WPA_ADDR_LEN src/esp_supplicant/esp_wpa_enterprise.c 130;" d file: +WPA_ALG_CCMP src/common/defs.h /^ WPA_ALG_CCMP = 3,$/;" e enum:wpa_alg +WPA_ALG_GCMP src/common/defs.h /^ WPA_ALG_GCMP$/;" e enum:wpa_alg +WPA_ALG_IGTK src/common/defs.h /^ WPA_ALG_IGTK,$/;" e enum:wpa_alg +WPA_ALG_NONE src/common/defs.h /^ WPA_ALG_NONE =0,$/;" e enum:wpa_alg +WPA_ALG_PMK src/common/defs.h /^ WPA_ALG_PMK,$/;" e enum:wpa_alg +WPA_ALG_TKIP src/common/defs.h /^ WPA_ALG_TKIP = 2,$/;" e enum:wpa_alg +WPA_ALG_WAPI src/common/defs.h /^ WPA_ALG_WAPI = 4,$/;" e enum:wpa_alg +WPA_ALG_WEP src/common/defs.h /^ WPA_ALG_WEP,$/;" e enum:wpa_alg +WPA_ALG_WEP104 src/common/defs.h /^ WPA_ALG_WEP104 = 5,$/;" e enum:wpa_alg +WPA_ALG_WEP40 src/common/defs.h /^ WPA_ALG_WEP40 = 1,$/;" e enum:wpa_alg +WPA_ALLOC_FAIL src/ap/wpa_auth.h /^ WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,$/;" e enum:__anon22 +WPA_ASSERT src/rsn_supp/wpa.h 32;" d +WPA_ASSOC src/ap/wpa_auth.h /^ WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,$/;" e enum:__anon23 +WPA_ASSOCIATED src/common/defs.h /^ WPA_ASSOCIATED,$/;" e enum:wpa_states +WPA_ASSOCIATING src/common/defs.h /^ WPA_ASSOCIATING,$/;" e enum:wpa_states +WPA_ASSOC_FT src/ap/wpa_auth.h /^ WPA_REAUTH_EAPOL, WPA_ASSOC_FT$/;" e enum:__anon23 +WPA_AUTH src/ap/wpa_auth.h /^ WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,$/;" e enum:__anon23 +WPA_AUTHENTICATING src/common/defs.h /^ WPA_AUTHENTICATING,$/;" e enum:wpa_states +WPA_AUTH_ALG_FT src/common/defs.h 80;" d +WPA_AUTH_ALG_LEAP src/common/defs.h 79;" d +WPA_AUTH_ALG_OPEN src/common/defs.h 77;" d +WPA_AUTH_ALG_SHARED src/common/defs.h 78;" d +WPA_AUTH_CCKM src/esp_supplicant/esp_wifi_driver.h /^ WPA_AUTH_CCKM = 0x06,$/;" e enum:__anon29 +WPA_AUTH_H src/ap/wpa_auth.h 10;" d +WPA_AUTH_IE_H src/ap/wpa_auth_ie.h 10;" d +WPA_AUTH_I_H src/ap/wpa_auth_i.h 10;" d +WPA_AUTH_KEY_MGMT_NONE src/common/wpa_common.h 39;" d +WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X src/common/wpa_common.h 41;" d +WPA_AUTH_KEY_MGMT_UNSPEC_802_1X src/common/wpa_common.h 40;" d +WPA_AUTH_PSK src/esp_supplicant/esp_wifi_driver.h /^ WPA_AUTH_PSK = 0x03,$/;" e enum:__anon29 +WPA_AUTH_UNSPEC src/esp_supplicant/esp_wifi_driver.h /^ WPA_AUTH_UNSPEC = 0x02,$/;" e enum:__anon29 +WPA_BSS_MASK_AGE src/common/wpa_ctrl.h 181;" d +WPA_BSS_MASK_ALL src/common/wpa_ctrl.h 171;" d +WPA_BSS_MASK_BEACON_INT src/common/wpa_ctrl.h 175;" d +WPA_BSS_MASK_BSSID src/common/wpa_ctrl.h 173;" d +WPA_BSS_MASK_CAPABILITIES src/common/wpa_ctrl.h 176;" d +WPA_BSS_MASK_DELIM src/common/wpa_ctrl.h 189;" d +WPA_BSS_MASK_FLAGS src/common/wpa_ctrl.h 183;" d +WPA_BSS_MASK_FREQ src/common/wpa_ctrl.h 174;" d +WPA_BSS_MASK_ID src/common/wpa_ctrl.h 172;" d +WPA_BSS_MASK_IE src/common/wpa_ctrl.h 182;" d +WPA_BSS_MASK_INTERNETW src/common/wpa_ctrl.h 187;" d +WPA_BSS_MASK_LEVEL src/common/wpa_ctrl.h 179;" d +WPA_BSS_MASK_NOISE src/common/wpa_ctrl.h 178;" d +WPA_BSS_MASK_P2P_SCAN src/common/wpa_ctrl.h 186;" d +WPA_BSS_MASK_QUAL src/common/wpa_ctrl.h 177;" d +WPA_BSS_MASK_SSID src/common/wpa_ctrl.h 184;" d +WPA_BSS_MASK_TSF src/common/wpa_ctrl.h 180;" d +WPA_BSS_MASK_WIFI_DISPLAY src/common/wpa_ctrl.h 188;" d +WPA_BSS_MASK_WPS_SCAN src/common/wpa_ctrl.h 185;" d +WPA_BYTE_SWAP_DEFINED include/utils/common.h 122;" d +WPA_BYTE_SWAP_DEFINED include/utils/common.h 71;" d +WPA_CAPABILITY_MFPC src/common/wpa_common.h 119;" d +WPA_CAPABILITY_MFPR src/common/wpa_common.h 118;" d +WPA_CAPABILITY_NO_PAIRWISE src/common/wpa_common.h 115;" d +WPA_CAPABILITY_PEERKEY_ENABLED src/common/wpa_common.h 120;" d +WPA_CAPABILITY_PREAUTH src/common/wpa_common.h 114;" d +WPA_CIPHER_AES_128_CMAC src/common/defs.h 31;" d +WPA_CIPHER_CCMP src/common/defs.h 30;" d +WPA_CIPHER_GCMP src/common/defs.h 32;" d +WPA_CIPHER_NONE src/common/defs.h 26;" d +WPA_CIPHER_SUITE_CCMP src/common/wpa_common.h 48;" d +WPA_CIPHER_SUITE_NONE src/common/wpa_common.h 42;" d +WPA_CIPHER_SUITE_TKIP src/common/wpa_common.h 44;" d +WPA_CIPHER_SUITE_WEP104 src/common/wpa_common.h 49;" d +WPA_CIPHER_SUITE_WEP40 src/common/wpa_common.h 43;" d +WPA_CIPHER_TKIP src/common/defs.h 29;" d +WPA_CIPHER_WEP104 src/common/defs.h 28;" d +WPA_CIPHER_WEP40 src/common/defs.h 27;" d +WPA_COMMON_H src/common/wpa_common.h 17;" d +WPA_COMPLETED src/common/defs.h /^ WPA_COMPLETED,$/;" e enum:wpa_states +WPA_CTRL_H src/common/wpa_ctrl.h 10;" d +WPA_CTRL_REQ src/common/wpa_ctrl.h 19;" d +WPA_CTRL_RSP src/common/wpa_ctrl.h 22;" d +WPA_DEAUTH src/ap/wpa_auth.h /^ WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,$/;" e enum:__anon23 +WPA_DEAUTH_FUNC src/rsn_supp/wpa_i.h /^typedef void (*WPA_DEAUTH_FUNC)(u8 reason_code);$/;" t +WPA_DEBUG_H include/utils/wpa_debug.h 16;" d +WPA_DISASSOC src/ap/wpa_auth.h /^ WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,$/;" e enum:__anon23 +WPA_DISCONNECTED src/common/defs.h /^ WPA_DISCONNECTED,$/;" e enum:wpa_states +WPA_EAPOL_authorized src/ap/wpa_auth.h /^ WPA_EAPOL_portEnabled, WPA_EAPOL_portValid, WPA_EAPOL_authorized,$/;" e enum:__anon21 +WPA_EAPOL_inc_EapolFramesTx src/ap/wpa_auth.h /^ WPA_EAPOL_keyDone, WPA_EAPOL_inc_EapolFramesTx$/;" e enum:__anon21 +WPA_EAPOL_keyAvailable src/ap/wpa_auth.h /^ WPA_EAPOL_portControl_Auto, WPA_EAPOL_keyRun, WPA_EAPOL_keyAvailable,$/;" e enum:__anon21 +WPA_EAPOL_keyDone src/ap/wpa_auth.h /^ WPA_EAPOL_keyDone, WPA_EAPOL_inc_EapolFramesTx$/;" e enum:__anon21 +WPA_EAPOL_keyRun src/ap/wpa_auth.h /^ WPA_EAPOL_portControl_Auto, WPA_EAPOL_keyRun, WPA_EAPOL_keyAvailable,$/;" e enum:__anon21 +WPA_EAPOL_portControl_Auto src/ap/wpa_auth.h /^ WPA_EAPOL_portControl_Auto, WPA_EAPOL_keyRun, WPA_EAPOL_keyAvailable,$/;" e enum:__anon21 +WPA_EAPOL_portEnabled src/ap/wpa_auth.h /^ WPA_EAPOL_portEnabled, WPA_EAPOL_portValid, WPA_EAPOL_authorized,$/;" e enum:__anon21 +WPA_EAPOL_portValid src/ap/wpa_auth.h /^ WPA_EAPOL_portEnabled, WPA_EAPOL_portValid, WPA_EAPOL_authorized,$/;" e enum:__anon21 +WPA_EVENT_ASSOC_REJECT src/common/wpa_ctrl.h 30;" d +WPA_EVENT_BSS_ADDED src/common/wpa_ctrl.h 62;" d +WPA_EVENT_BSS_REMOVED src/common/wpa_ctrl.h 64;" d +WPA_EVENT_CONNECTED src/common/wpa_ctrl.h 26;" d +WPA_EVENT_DISCONNECTED src/common/wpa_ctrl.h 28;" d +WPA_EVENT_EAP_FAILURE src/common/wpa_ctrl.h 52;" d +WPA_EVENT_EAP_METHOD src/common/wpa_ctrl.h 42;" d +WPA_EVENT_EAP_NOTIFICATION src/common/wpa_ctrl.h 36;" d +WPA_EVENT_EAP_PEER_CERT src/common/wpa_ctrl.h 44;" d +WPA_EVENT_EAP_PROPOSED_METHOD src/common/wpa_ctrl.h 40;" d +WPA_EVENT_EAP_STARTED src/common/wpa_ctrl.h 38;" d +WPA_EVENT_EAP_STATUS src/common/wpa_ctrl.h 48;" d +WPA_EVENT_EAP_SUCCESS include/utils/wpa_debug.h 36;" d +WPA_EVENT_EAP_SUCCESS src/common/wpa_ctrl.h 50;" d +WPA_EVENT_EAP_TLS_CERT_ERROR src/common/wpa_ctrl.h 46;" d +WPA_EVENT_FREQ_CONFLICT src/common/wpa_ctrl.h 67;" d +WPA_EVENT_PASSWORD_CHANGED src/common/wpa_ctrl.h 34;" d +WPA_EVENT_REENABLED src/common/wpa_ctrl.h 56;" d +WPA_EVENT_SCAN_RESULTS src/common/wpa_ctrl.h 58;" d +WPA_EVENT_STATE_CHANGE src/common/wpa_ctrl.h 60;" d +WPA_EVENT_TEMP_DISABLED src/common/wpa_ctrl.h 54;" d +WPA_EVENT_TERMINATING src/common/wpa_ctrl.h 32;" d +WPA_FIRST_HALF_4WAY_HANDSHAKE src/common/defs.h /^ WPA_FIRST_HALF_4WAY_HANDSHAKE,$/;" e enum:wpa_states +WPA_GET_BE16 include/utils/common.h 128;" d +WPA_GET_BE24 include/utils/common.h 142;" d +WPA_GET_BE32 include/utils/common.h 151;" d +WPA_GET_BE64 include/utils/common.h 171;" d +WPA_GET_KEY src/rsn_supp/wpa_i.h /^typedef int (*WPA_GET_KEY) (u8 *ifx, int *alg, u8 *addt, int *keyidx, u8 *key, size_t key_len, int key_entry_valid);$/;" t +WPA_GET_LE16 include/utils/common.h 135;" d +WPA_GET_LE32 include/utils/common.h 161;" d +WPA_GET_LE64 include/utils/common.h 187;" d +WPA_GMK_LEN src/common/wpa_common.h 27;" d +WPA_GROUP_GTK_INIT src/ap/wpa_auth_i.h /^ WPA_GROUP_GTK_INIT = 0,$/;" e enum:wpa_group::__anon27 +WPA_GROUP_HANDSHAKE src/common/defs.h /^ WPA_GROUP_HANDSHAKE,$/;" e enum:wpa_states +WPA_GROUP_HANDSHAKE_BIT src/rsn_supp/wpa.c 44;" d file: +WPA_GROUP_SETKEYS src/ap/wpa_auth_i.h /^ WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE$/;" e enum:wpa_group::__anon27 +WPA_GROUP_SETKEYSDONE src/ap/wpa_auth_i.h /^ WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE$/;" e enum:wpa_group::__anon27 +WPA_GTK_MAX_LEN src/common/wpa_common.h 28;" d +WPA_H src/rsn_supp/wpa.h 16;" d +WPA_IE_H src/rsn_supp/wpa_ie.h 16;" d +WPA_IE_OK src/ap/wpa_auth.h /^ WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,$/;" e enum:__anon22 +WPA_IE_VENDOR_TYPE src/common/ieee802_11_defs.h 479;" d +WPA_IGTK_LEN src/common/wpa_common.h 109;" d +WPA_INACTIVE src/common/defs.h /^ WPA_INACTIVE,$/;" e enum:wpa_states +WPA_INSTALL_KEY src/rsn_supp/wpa_i.h /^typedef void (*WPA_INSTALL_KEY) (enum wpa_alg alg, u8 *addr, int key_idx, int set_tx,$/;" t +WPA_INVALID_AKMP src/ap/wpa_auth.h /^ WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,$/;" e enum:__anon22 +WPA_INVALID_GROUP src/ap/wpa_auth.h /^ WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,$/;" e enum:__anon22 +WPA_INVALID_IE src/ap/wpa_auth.h /^ WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,$/;" e enum:__anon22 +WPA_INVALID_MDIE src/ap/wpa_auth.h /^ WPA_INVALID_MDIE, WPA_INVALID_PROTO$/;" e enum:__anon22 +WPA_INVALID_MGMT_GROUP_CIPHER src/ap/wpa_auth.h /^ WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER,$/;" e enum:__anon22 +WPA_INVALID_PAIRWISE src/ap/wpa_auth.h /^ WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,$/;" e enum:__anon22 +WPA_INVALID_PROTO src/ap/wpa_auth.h /^ WPA_INVALID_MDIE, WPA_INVALID_PROTO$/;" e enum:__anon22 +WPA_IS_MULTICAST src/ap/wpa_auth.h 20;" d +WPA_I_H src/rsn_supp/wpa_i.h 16;" d +WPA_KEY_INFO_ACK src/common/wpa_common.h 141;" d +WPA_KEY_INFO_ENCR_KEY_DATA src/common/wpa_common.h 146;" d +WPA_KEY_INFO_ERROR src/common/wpa_common.h 144;" d +WPA_KEY_INFO_INSTALL src/common/wpa_common.h 139;" d +WPA_KEY_INFO_KEY_INDEX_MASK src/common/wpa_common.h 137;" d +WPA_KEY_INFO_KEY_INDEX_SHIFT src/common/wpa_common.h 138;" d +WPA_KEY_INFO_KEY_TYPE src/common/wpa_common.h 135;" d +WPA_KEY_INFO_MIC src/common/wpa_common.h 142;" d +WPA_KEY_INFO_REQUEST src/common/wpa_common.h 145;" d +WPA_KEY_INFO_SECURE src/common/wpa_common.h 143;" d +WPA_KEY_INFO_SMK_MESSAGE src/common/wpa_common.h 147;" d +WPA_KEY_INFO_TXRX src/common/wpa_common.h 140;" d +WPA_KEY_INFO_TYPE_AES_128_CMAC src/common/wpa_common.h 134;" d +WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 src/common/wpa_common.h 132;" d +WPA_KEY_INFO_TYPE_HMAC_SHA1_AES src/common/wpa_common.h 133;" d +WPA_KEY_INFO_TYPE_MASK src/common/wpa_common.h 131;" d +WPA_KEY_MGMT_CCKM src/common/defs.h 44;" d +WPA_KEY_MGMT_FT_IEEE8021X src/common/defs.h 39;" d +WPA_KEY_MGMT_FT_PSK src/common/defs.h 40;" d +WPA_KEY_MGMT_IEEE8021X src/common/defs.h 34;" d +WPA_KEY_MGMT_IEEE8021X_NO_WPA src/common/defs.h 37;" d +WPA_KEY_MGMT_IEEE8021X_SHA256 src/common/defs.h 41;" d +WPA_KEY_MGMT_NONE src/common/defs.h 36;" d +WPA_KEY_MGMT_PSK src/common/defs.h 35;" d +WPA_KEY_MGMT_PSK_SHA256 src/common/defs.h 42;" d +WPA_KEY_MGMT_WPA_NONE src/common/defs.h 38;" d +WPA_KEY_MGMT_WPS src/common/defs.h 43;" d +WPA_KEY_RSC_LEN src/common/wpa_common.h 26;" d +WPA_LAST_HALF_4WAY_HANDSHAKE src/common/defs.h /^ WPA_LAST_HALF_4WAY_HANDSHAKE,$/;" e enum:wpa_states +WPA_MAX_SSID_LEN src/common/wpa_common.h 19;" d +WPA_MGMT_FRAME_PROTECTION_VIOLATION src/ap/wpa_auth.h /^ WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER,$/;" e enum:__anon22 +WPA_MIC_FAILURE src/common/defs.h /^ WPA_MIC_FAILURE, \/\/ first mic_error event occur$/;" e enum:wpa_states +WPA_NEG_COMPLETE src/rsn_supp/wpa_i.h /^typedef void (*WPA_NEG_COMPLETE)();$/;" t +WPA_NONCE_LEN src/common/wpa_common.h 25;" d +WPA_NOT_ENABLED src/ap/wpa_auth.h /^ WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,$/;" e enum:__anon22 +WPA_OUI_TYPE src/common/wpa_common.h 94;" d +WPA_PMK_NAME_LEN src/common/wpa_common.h 127;" d +WPA_PROTO_RSN src/common/defs.h 75;" d +WPA_PROTO_WPA src/common/defs.h 74;" d +WPA_PTK_AUTHENTICATION src/ap/wpa_auth_i.h /^ WPA_PTK_AUTHENTICATION, WPA_PTK_AUTHENTICATION2,$/;" e enum:wpa_state_machine::__anon24 +WPA_PTK_AUTHENTICATION2 src/ap/wpa_auth_i.h /^ WPA_PTK_AUTHENTICATION, WPA_PTK_AUTHENTICATION2,$/;" e enum:wpa_state_machine::__anon24 +WPA_PTK_DISCONNECT src/ap/wpa_auth_i.h /^ WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED,$/;" e enum:wpa_state_machine::__anon24 +WPA_PTK_DISCONNECTED src/ap/wpa_auth_i.h /^ WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED,$/;" e enum:wpa_state_machine::__anon24 +WPA_PTK_GROUP_IDLE src/ap/wpa_auth_i.h /^ WPA_PTK_GROUP_IDLE = 0,$/;" e enum:wpa_state_machine::__anon25 +WPA_PTK_GROUP_KEYERROR src/ap/wpa_auth_i.h /^ WPA_PTK_GROUP_KEYERROR$/;" e enum:wpa_state_machine::__anon25 +WPA_PTK_GROUP_REKEYESTABLISHED src/ap/wpa_auth_i.h /^ WPA_PTK_GROUP_REKEYESTABLISHED,$/;" e enum:wpa_state_machine::__anon25 +WPA_PTK_GROUP_REKEYNEGOTIATING src/ap/wpa_auth_i.h /^ WPA_PTK_GROUP_REKEYNEGOTIATING,$/;" e enum:wpa_state_machine::__anon25 +WPA_PTK_INITIALIZE src/ap/wpa_auth_i.h /^ WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED,$/;" e enum:wpa_state_machine::__anon24 +WPA_PTK_INITPMK src/ap/wpa_auth_i.h /^ WPA_PTK_INITPMK, WPA_PTK_INITPSK, WPA_PTK_PTKSTART,$/;" e enum:wpa_state_machine::__anon24 +WPA_PTK_INITPSK src/ap/wpa_auth_i.h /^ WPA_PTK_INITPMK, WPA_PTK_INITPSK, WPA_PTK_PTKSTART,$/;" e enum:wpa_state_machine::__anon24 +WPA_PTK_PTKCALCNEGOTIATING src/ap/wpa_auth_i.h /^ WPA_PTK_PTKCALCNEGOTIATING, WPA_PTK_PTKCALCNEGOTIATING2,$/;" e enum:wpa_state_machine::__anon24 +WPA_PTK_PTKCALCNEGOTIATING2 src/ap/wpa_auth_i.h /^ WPA_PTK_PTKCALCNEGOTIATING, WPA_PTK_PTKCALCNEGOTIATING2,$/;" e enum:wpa_state_machine::__anon24 +WPA_PTK_PTKINITDONE src/ap/wpa_auth_i.h /^ WPA_PTK_PTKINITNEGOTIATING, WPA_PTK_PTKINITDONE$/;" e enum:wpa_state_machine::__anon24 +WPA_PTK_PTKINITNEGOTIATING src/ap/wpa_auth_i.h /^ WPA_PTK_PTKINITNEGOTIATING, WPA_PTK_PTKINITDONE$/;" e enum:wpa_state_machine::__anon24 +WPA_PTK_PTKSTART src/ap/wpa_auth_i.h /^ WPA_PTK_INITPMK, WPA_PTK_INITPSK, WPA_PTK_PTKSTART,$/;" e enum:wpa_state_machine::__anon24 +WPA_PUT_BE16 include/utils/common.h 129;" d +WPA_PUT_BE24 include/utils/common.h 144;" d +WPA_PUT_BE32 include/utils/common.h 153;" d +WPA_PUT_BE64 include/utils/common.h 175;" d +WPA_PUT_LE16 include/utils/common.h 136;" d +WPA_PUT_LE32 include/utils/common.h 163;" d +WPA_REAUTH src/ap/wpa_auth.h /^ WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,$/;" e enum:__anon23 +WPA_REAUTH_EAPOL src/ap/wpa_auth.h /^ WPA_REAUTH_EAPOL, WPA_ASSOC_FT$/;" e enum:__anon23 +WPA_REPLAY_COUNTER_LEN src/common/wpa_common.h 24;" d +WPA_SCANNING src/common/defs.h /^ WPA_SCANNING,$/;" e enum:wpa_states +WPA_SELECTOR_LEN src/common/wpa_common.h 30;" d +WPA_SEND_FUNC src/rsn_supp/wpa_i.h /^typedef void (* WPA_SEND_FUNC)(void *buffer, u16 len);$/;" t +WPA_SET_ASSOC_IE src/rsn_supp/wpa_i.h /^typedef void (* WPA_SET_ASSOC_IE)(u8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len);$/;" t +WPA_SM_MAX_INDEX src/ap/wpa_auth.c 55;" d file: +WPA_SM_STATE src/rsn_supp/wpa.h 25;" d +WPA_TKIP_COUNTERMEASURES src/common/defs.h /^ WPA_TKIP_COUNTERMEASURES \/\/in countermeasure period that stop connect with ap in 60 sec$/;" e enum:wpa_states +WPA_TX_MSG_BUFF_MAXLEN src/ap/wpa_auth.c 159;" d file: +WPA_TX_MSG_BUFF_MAXLEN src/esp_supplicant/esp_wpa_main.c 62;" d file: +WPA_TX_MSG_BUFF_MAXLEN src/rsn_supp/wpa.c 47;" d file: +WPA_VERSION src/common/wpa_common.h 31;" d +WPA_VERSION_NO_WPA src/ap/wpa_auth_i.h /^ WPA_VERSION_NO_WPA = 0 \/* WPA not used *\/,$/;" e enum:wpa_state_machine::__anon26 +WPA_VERSION_WPA src/ap/wpa_auth_i.h /^ WPA_VERSION_WPA = 1 \/* WPA \/ IEEE 802.11i\/D3.0 *\/,$/;" e enum:wpa_state_machine::__anon26 +WPA_VERSION_WPA2 src/ap/wpa_auth_i.h /^ WPA_VERSION_WPA2 = 2 \/* WPA2 \/ IEEE 802.11i *\/$/;" e enum:wpa_state_machine::__anon26 +WPS_ADDR_LEN src/esp_supplicant/esp_wps.c 49;" d file: +WPS_ASSOC_CFG_FAILURE src/wps/wps_defs.h /^ WPS_ASSOC_CFG_FAILURE = 2,$/;" e enum:wps_assoc_state +WPS_ASSOC_CONN_SUCCESS src/wps/wps_defs.h /^ WPS_ASSOC_CONN_SUCCESS = 1,$/;" e enum:wps_assoc_state +WPS_ASSOC_FAILURE src/wps/wps_defs.h /^ WPS_ASSOC_FAILURE = 3,$/;" e enum:wps_assoc_state +WPS_ASSOC_IP_FAILURE src/wps/wps_defs.h /^ WPS_ASSOC_IP_FAILURE = 4$/;" e enum:wps_assoc_state +WPS_ASSOC_NOT_ASSOC src/wps/wps_defs.h /^ WPS_ASSOC_NOT_ASSOC = 0,$/;" e enum:wps_assoc_state +WPS_ATTR_PARSE_H src/wps/wps_attr_parse.h 10;" d +WPS_AUTHENTICATOR_LEN src/wps/wps_defs.h 35;" d +WPS_AUTHKEY_LEN src/wps/wps_defs.h 36;" d +WPS_AUTH_SHARED src/wps/wps_defs.h 191;" d +WPS_AUTH_TYPES src/wps/wps_defs.h 195;" d +WPS_AUTH_WPA src/wps/wps_defs.h 192;" d +WPS_AUTH_WPA2 src/wps/wps_defs.h 193;" d +WPS_AUTH_WPA2PSK src/wps/wps_defs.h 194;" d +WPS_AUTH_WPAPSK src/wps/wps_defs.h 190;" d +WPS_Beacon src/wps/wps_defs.h /^ WPS_Beacon = 0x01,$/;" e enum:wps_msg_type +WPS_CALC_KEY_MAX src/wps/wps_i.h /^ WPS_CALC_KEY_MAX,$/;" e enum:wps_calc_key_mode +WPS_CALC_KEY_NORMAL src/wps/wps_i.h /^ WPS_CALC_KEY_NORMAL = 0,$/;" e enum:wps_calc_key_mode +WPS_CALC_KEY_NO_CALC src/wps/wps_i.h /^ WPS_CALC_KEY_NO_CALC,$/;" e enum:wps_calc_key_mode +WPS_CALC_KEY_PRE_CALC src/wps/wps_i.h /^ WPS_CALC_KEY_PRE_CALC,$/;" e enum:wps_calc_key_mode +WPS_CB_ST_FAILED src/wps/wps.h /^ WPS_CB_ST_FAILED,$/;" e enum:wps_cb_status +WPS_CB_ST_SCAN_ERR src/wps/wps.h /^ WPS_CB_ST_SCAN_ERR,$/;" e enum:wps_cb_status +WPS_CB_ST_SUCCESS src/wps/wps.h /^ WPS_CB_ST_SUCCESS = 0,$/;" e enum:wps_cb_status +WPS_CB_ST_TIMEOUT src/wps/wps.h /^ WPS_CB_ST_TIMEOUT,$/;" e enum:wps_cb_status +WPS_CB_ST_WEP src/wps/wps.h /^ WPS_CB_ST_WEP,$/;" e enum:wps_cb_status +WPS_CFG_24_CHAN_NOT_SUPPORTED src/wps/wps_defs.h /^ WPS_CFG_24_CHAN_NOT_SUPPORTED = 3,$/;" e enum:wps_config_error +WPS_CFG_50_CHAN_NOT_SUPPORTED src/wps/wps_defs.h /^ WPS_CFG_50_CHAN_NOT_SUPPORTED = 4,$/;" e enum:wps_config_error +WPS_CFG_DECRYPTION_CRC_FAILURE src/wps/wps_defs.h /^ WPS_CFG_DECRYPTION_CRC_FAILURE = 2,$/;" e enum:wps_config_error +WPS_CFG_DEVICE_BUSY src/wps/wps_defs.h /^ WPS_CFG_DEVICE_BUSY = 14,$/;" e enum:wps_config_error +WPS_CFG_DEV_PASSWORD_AUTH_FAILURE src/wps/wps_defs.h /^ WPS_CFG_DEV_PASSWORD_AUTH_FAILURE = 18$/;" e enum:wps_config_error +WPS_CFG_FAILED_DHCP_CONFIG src/wps/wps_defs.h /^ WPS_CFG_FAILED_DHCP_CONFIG = 9,$/;" e enum:wps_config_error +WPS_CFG_IP_ADDR_CONFLICT src/wps/wps_defs.h /^ WPS_CFG_IP_ADDR_CONFLICT = 10,$/;" e enum:wps_config_error +WPS_CFG_MSG_TIMEOUT src/wps/wps_defs.h /^ WPS_CFG_MSG_TIMEOUT = 16,$/;" e enum:wps_config_error +WPS_CFG_MULTIPLE_PBC_DETECTED src/wps/wps_defs.h /^ WPS_CFG_MULTIPLE_PBC_DETECTED = 12,$/;" e enum:wps_config_error +WPS_CFG_NETWORK_ASSOC_FAILURE src/wps/wps_defs.h /^ WPS_CFG_NETWORK_ASSOC_FAILURE = 7,$/;" e enum:wps_config_error +WPS_CFG_NETWORK_AUTH_FAILURE src/wps/wps_defs.h /^ WPS_CFG_NETWORK_AUTH_FAILURE = 6,$/;" e enum:wps_config_error +WPS_CFG_NO_CONN_TO_REGISTRAR src/wps/wps_defs.h /^ WPS_CFG_NO_CONN_TO_REGISTRAR = 11,$/;" e enum:wps_config_error +WPS_CFG_NO_DHCP_RESPONSE src/wps/wps_defs.h /^ WPS_CFG_NO_DHCP_RESPONSE = 8,$/;" e enum:wps_config_error +WPS_CFG_NO_ERROR src/wps/wps_defs.h /^ WPS_CFG_NO_ERROR = 0,$/;" e enum:wps_config_error +WPS_CFG_OOB_IFACE_READ_ERROR src/wps/wps_defs.h /^ WPS_CFG_OOB_IFACE_READ_ERROR = 1,$/;" e enum:wps_config_error +WPS_CFG_REG_SESS_TIMEOUT src/wps/wps_defs.h /^ WPS_CFG_REG_SESS_TIMEOUT = 17,$/;" e enum:wps_config_error +WPS_CFG_ROGUE_SUSPECTED src/wps/wps_defs.h /^ WPS_CFG_ROGUE_SUSPECTED = 13,$/;" e enum:wps_config_error +WPS_CFG_SETUP_LOCKED src/wps/wps_defs.h /^ WPS_CFG_SETUP_LOCKED = 15,$/;" e enum:wps_config_error +WPS_CFG_SIGNAL_TOO_WEAK src/wps/wps_defs.h /^ WPS_CFG_SIGNAL_TOO_WEAK = 5,$/;" e enum:wps_config_error +WPS_CONFIG_DISPLAY src/wps/wps_defs.h 245;" d +WPS_CONFIG_ETHERNET src/wps/wps_defs.h 243;" d +WPS_CONFIG_EXT_NFC_TOKEN src/wps/wps_defs.h 246;" d +WPS_CONFIG_INIT_DEFAULT include/esp_supplicant/esp_wps.h 80;" d +WPS_CONFIG_INT_NFC_TOKEN src/wps/wps_defs.h 247;" d +WPS_CONFIG_KEYPAD src/wps/wps_defs.h 250;" d +WPS_CONFIG_LABEL src/wps/wps_defs.h 244;" d +WPS_CONFIG_NFC_INTERFACE src/wps/wps_defs.h 248;" d +WPS_CONFIG_PHY_DISPLAY src/wps/wps_defs.h 255;" d +WPS_CONFIG_PHY_PUSHBUTTON src/wps/wps_defs.h 253;" d +WPS_CONFIG_PUSHBUTTON src/wps/wps_defs.h 249;" d +WPS_CONFIG_USBA src/wps/wps_defs.h 242;" d +WPS_CONFIG_VIRT_DISPLAY src/wps/wps_defs.h 254;" d +WPS_CONFIG_VIRT_PUSHBUTTON src/wps/wps_defs.h 252;" d +WPS_CONN_ESS src/wps/wps_defs.h 259;" d +WPS_CONN_IBSS src/wps/wps_defs.h 260;" d +WPS_CONTINUE src/wps/wps.h /^ WPS_CONTINUE,$/;" e enum:wps_process_res +WPS_DEFS_H src/wps/wps_defs.h 10;" d +WPS_DEV_ATTR_H src/wps/wps_dev_attr.h 10;" d +WPS_DEV_CAMERA src/wps/wps_defs.h /^ WPS_DEV_CAMERA = 4,$/;" e enum:wps_dev_categ +WPS_DEV_CAMERA_DIGITAL_STILL_CAMERA src/wps/wps_defs.h /^ WPS_DEV_CAMERA_DIGITAL_STILL_CAMERA = 1,$/;" e enum:wps_dev_subcateg +WPS_DEV_COMPUTER src/wps/wps_defs.h /^ WPS_DEV_COMPUTER = 1,$/;" e enum:wps_dev_categ +WPS_DEV_COMPUTER_MEDIA_CENTER src/wps/wps_defs.h /^ WPS_DEV_COMPUTER_MEDIA_CENTER = 3,$/;" e enum:wps_dev_subcateg +WPS_DEV_COMPUTER_PC src/wps/wps_defs.h /^ WPS_DEV_COMPUTER_PC = 1,$/;" e enum:wps_dev_subcateg +WPS_DEV_COMPUTER_SERVER src/wps/wps_defs.h /^ WPS_DEV_COMPUTER_SERVER = 2,$/;" e enum:wps_dev_subcateg +WPS_DEV_DISPLAY src/wps/wps_defs.h /^ WPS_DEV_DISPLAY = 7,$/;" e enum:wps_dev_categ +WPS_DEV_DISPLAY_PICTURE_FRAME src/wps/wps_defs.h /^ WPS_DEV_DISPLAY_PICTURE_FRAME = 2,$/;" e enum:wps_dev_subcateg +WPS_DEV_DISPLAY_PROJECTOR src/wps/wps_defs.h /^ WPS_DEV_DISPLAY_PROJECTOR = 3,$/;" e enum:wps_dev_subcateg +WPS_DEV_DISPLAY_TV src/wps/wps_defs.h /^ WPS_DEV_DISPLAY_TV = 1,$/;" e enum:wps_dev_subcateg +WPS_DEV_GAMING src/wps/wps_defs.h /^ WPS_DEV_GAMING = 9,$/;" e enum:wps_dev_categ +WPS_DEV_GAMING_PLAYSTATION src/wps/wps_defs.h /^ WPS_DEV_GAMING_PLAYSTATION = 3,$/;" e enum:wps_dev_subcateg +WPS_DEV_GAMING_XBOX src/wps/wps_defs.h /^ WPS_DEV_GAMING_XBOX = 1,$/;" e enum:wps_dev_subcateg +WPS_DEV_GAMING_XBOX360 src/wps/wps_defs.h /^ WPS_DEV_GAMING_XBOX360 = 2,$/;" e enum:wps_dev_subcateg +WPS_DEV_INPUT src/wps/wps_defs.h /^ WPS_DEV_INPUT = 2,$/;" e enum:wps_dev_categ +WPS_DEV_MULTIMEDIA src/wps/wps_defs.h /^ WPS_DEV_MULTIMEDIA = 8,$/;" e enum:wps_dev_categ +WPS_DEV_MULTIMEDIA_DAR src/wps/wps_defs.h /^ WPS_DEV_MULTIMEDIA_DAR = 1,$/;" e enum:wps_dev_subcateg +WPS_DEV_MULTIMEDIA_MCX src/wps/wps_defs.h /^ WPS_DEV_MULTIMEDIA_MCX = 3,$/;" e enum:wps_dev_subcateg +WPS_DEV_MULTIMEDIA_PVR src/wps/wps_defs.h /^ WPS_DEV_MULTIMEDIA_PVR = 2,$/;" e enum:wps_dev_subcateg +WPS_DEV_NETWORK_INFRA src/wps/wps_defs.h /^ WPS_DEV_NETWORK_INFRA = 6,$/;" e enum:wps_dev_categ +WPS_DEV_NETWORK_INFRA_AP src/wps/wps_defs.h /^ WPS_DEV_NETWORK_INFRA_AP = 1,$/;" e enum:wps_dev_subcateg +WPS_DEV_NETWORK_INFRA_ROUTER src/wps/wps_defs.h /^ WPS_DEV_NETWORK_INFRA_ROUTER = 2,$/;" e enum:wps_dev_subcateg +WPS_DEV_NETWORK_INFRA_SWITCH src/wps/wps_defs.h /^ WPS_DEV_NETWORK_INFRA_SWITCH = 3,$/;" e enum:wps_dev_subcateg +WPS_DEV_OUI_WFA src/wps/wps_defs.h 278;" d +WPS_DEV_PHONE src/wps/wps_defs.h /^ WPS_DEV_PHONE = 10$/;" e enum:wps_dev_categ +WPS_DEV_PHONE_WINDOWS_MOBILE src/wps/wps_defs.h /^ WPS_DEV_PHONE_WINDOWS_MOBILE = 1$/;" e enum:wps_dev_subcateg +WPS_DEV_PRINTER src/wps/wps_defs.h /^ WPS_DEV_PRINTER = 3,$/;" e enum:wps_dev_categ +WPS_DEV_PRINTER_PRINTER src/wps/wps_defs.h /^ WPS_DEV_PRINTER_PRINTER = 1,$/;" e enum:wps_dev_subcateg +WPS_DEV_PRINTER_SCANNER src/wps/wps_defs.h /^ WPS_DEV_PRINTER_SCANNER = 2,$/;" e enum:wps_dev_subcateg +WPS_DEV_STORAGE src/wps/wps_defs.h /^ WPS_DEV_STORAGE = 5,$/;" e enum:wps_dev_categ +WPS_DEV_STORAGE_NAS src/wps/wps_defs.h /^ WPS_DEV_STORAGE_NAS = 1,$/;" e enum:wps_dev_subcateg +WPS_DEV_TYPE_BUFSIZE src/wps/wps.h 64;" d +WPS_DEV_TYPE_LEN src/wps/wps.h 63;" d +WPS_DH_GROUP src/wps/wps_defs.h 31;" d +WPS_DONE src/wps/wps.h /^ WPS_DONE,$/;" e enum:wps_process_res +WPS_EAP_EXT_VENDOR_TYPE src/wps/wps.h 1026;" d +WPS_EI_NO_ERROR src/wps/wps_defs.h /^ WPS_EI_NO_ERROR,$/;" e enum:wps_error_indication +WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED src/wps/wps_defs.h /^ WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED,$/;" e enum:wps_error_indication +WPS_EI_SECURITY_WEP_PROHIBITED src/wps/wps_defs.h /^ WPS_EI_SECURITY_WEP_PROHIBITED,$/;" e enum:wps_error_indication +WPS_EMSK_LEN src/wps/wps_defs.h 38;" d +WPS_ENCR_AES src/wps/wps_defs.h 202;" d +WPS_ENCR_NONE src/wps/wps_defs.h 199;" d +WPS_ENCR_TKIP src/wps/wps_defs.h 201;" d +WPS_ENCR_TYPES src/wps/wps_defs.h 203;" d +WPS_ENCR_WEP src/wps/wps_defs.h 200;" d +WPS_ER_SET_SEL_REG_DONE src/wps/wps.h /^ WPS_ER_SET_SEL_REG_DONE,$/;" e enum:wps_event_data::wps_event_er_set_selected_registrar::__anon54 +WPS_ER_SET_SEL_REG_FAILED src/wps/wps.h /^ WPS_ER_SET_SEL_REG_FAILED$/;" e enum:wps_event_data::wps_event_er_set_selected_registrar::__anon54 +WPS_ER_SET_SEL_REG_START src/wps/wps.h /^ WPS_ER_SET_SEL_REG_START,$/;" e enum:wps_event_data::wps_event_er_set_selected_registrar::__anon54 +WPS_EVENT_ACTIVE src/common/wpa_ctrl.h 95;" d +WPS_EVENT_AP_AVAILABLE src/common/wpa_ctrl.h 83;" d +WPS_EVENT_AP_AVAILABLE_AUTH src/common/wpa_ctrl.h 78;" d +WPS_EVENT_AP_AVAILABLE_PBC src/common/wpa_ctrl.h 76;" d +WPS_EVENT_AP_AVAILABLE_PIN src/common/wpa_ctrl.h 81;" d +WPS_EVENT_AP_PIN_DISABLED src/common/wpa_ctrl.h 162;" d +WPS_EVENT_AP_PIN_ENABLED src/common/wpa_ctrl.h 161;" d +WPS_EVENT_AP_SETUP_LOCKED src/common/wpa_ctrl.h 159;" d +WPS_EVENT_AP_SETUP_UNLOCKED src/common/wpa_ctrl.h 160;" d +WPS_EVENT_CRED_RECEIVED src/common/wpa_ctrl.h 85;" d +WPS_EVENT_DISABLE src/common/wpa_ctrl.h 97;" d +WPS_EVENT_ENROLLEE_SEEN src/common/wpa_ctrl.h 99;" d +WPS_EVENT_ER_AP_ADD src/common/wpa_ctrl.h 104;" d +WPS_EVENT_ER_AP_REMOVE src/common/wpa_ctrl.h 105;" d +WPS_EVENT_ER_AP_SETTINGS src/common/wpa_ctrl.h 108;" d +WPS_EVENT_ER_ENROLLEE_ADD src/common/wpa_ctrl.h 106;" d +WPS_EVENT_ER_ENROLLEE_REMOVE src/common/wpa_ctrl.h 107;" d +WPS_EVENT_ER_SET_SEL_REG src/common/wpa_ctrl.h 109;" d +WPS_EVENT_FAIL src/common/wpa_ctrl.h 89;" d +WPS_EVENT_M2D src/common/wpa_ctrl.h 87;" d +WPS_EVENT_NEW_AP_SETTINGS src/common/wpa_ctrl.h 157;" d +WPS_EVENT_OPEN_NETWORK src/common/wpa_ctrl.h 101;" d +WPS_EVENT_OVERLAP src/common/wpa_ctrl.h 74;" d +WPS_EVENT_PIN_NEEDED src/common/wpa_ctrl.h 156;" d +WPS_EVENT_REG_SUCCESS src/common/wpa_ctrl.h 158;" d +WPS_EVENT_SUCCESS src/common/wpa_ctrl.h 91;" d +WPS_EVENT_TIMEOUT src/common/wpa_ctrl.h 93;" d +WPS_EV_AP_PIN_SUCCESS src/wps/wps.h /^ WPS_EV_AP_PIN_SUCCESS$/;" e enum:wps_event +WPS_EV_ER_AP_ADD src/wps/wps.h /^ WPS_EV_ER_AP_ADD,$/;" e enum:wps_event +WPS_EV_ER_AP_REMOVE src/wps/wps.h /^ WPS_EV_ER_AP_REMOVE,$/;" e enum:wps_event +WPS_EV_ER_AP_SETTINGS src/wps/wps.h /^ WPS_EV_ER_AP_SETTINGS,$/;" e enum:wps_event +WPS_EV_ER_ENROLLEE_ADD src/wps/wps.h /^ WPS_EV_ER_ENROLLEE_ADD,$/;" e enum:wps_event +WPS_EV_ER_ENROLLEE_REMOVE src/wps/wps.h /^ WPS_EV_ER_ENROLLEE_REMOVE,$/;" e enum:wps_event +WPS_EV_ER_SET_SELECTED_REGISTRAR src/wps/wps.h /^ WPS_EV_ER_SET_SELECTED_REGISTRAR,$/;" e enum:wps_event +WPS_EV_FAIL src/wps/wps.h /^ WPS_EV_FAIL,$/;" e enum:wps_event +WPS_EV_M2D src/wps/wps.h /^ WPS_EV_M2D,$/;" e enum:wps_event +WPS_EV_PBC_OVERLAP src/wps/wps.h /^ WPS_EV_PBC_OVERLAP,$/;" e enum:wps_event +WPS_EV_PBC_TIMEOUT src/wps/wps.h /^ WPS_EV_PBC_TIMEOUT,$/;" e enum:wps_event +WPS_EV_PWD_AUTH_FAIL src/wps/wps.h /^ WPS_EV_PWD_AUTH_FAIL,$/;" e enum:wps_event +WPS_EV_SUCCESS src/wps/wps.h /^ WPS_EV_SUCCESS,$/;" e enum:wps_event +WPS_FAILURE src/wps/wps.h /^ WPS_FAILURE,$/;" e enum:wps_process_res +WPS_FINISHED src/wps/wps_i.h /^ RECV_M8, RECEIVED_M2D, WPS_MSG_DONE, RECV_ACK, WPS_FINISHED,$/;" e enum:wps_data::__anon53 +WPS_FRAGMENT src/wps/wps.h /^ WPS_FRAGMENT \/* Tim, send wsc fragment ack *\/$/;" e enum:wps_process_res +WPS_H src/wps/wps.h 10;" d +WPS_HASH_LEN src/wps/wps_defs.h 41;" d +WPS_IE_VENDOR_TYPE src/common/ieee802_11_defs.h 480;" d +WPS_IGNORE src/wps/wps.h /^ WPS_IGNORE, \/* snake, ignore the re-packge *\/$/;" e enum:wps_process_res +WPS_IGNORE_SEL_REG_MAX_CNT src/wps/wps_defs.h 338;" d +WPS_IGNORE_STATE src/wps/wps_enrollee.c 1235;" d file: +WPS_I_H src/wps/wps_i.h 10;" d +WPS_KEYWRAPKEY_LEN src/wps/wps_defs.h 37;" d +WPS_KWA_LEN src/wps/wps_defs.h 42;" d +WPS_M1 src/wps/wps_defs.h /^ WPS_M1 = 0x04,$/;" e enum:wps_msg_type +WPS_M2 src/wps/wps_defs.h /^ WPS_M2 = 0x05,$/;" e enum:wps_msg_type +WPS_M2D src/wps/wps_defs.h /^ WPS_M2D = 0x06,$/;" e enum:wps_msg_type +WPS_M3 src/wps/wps_defs.h /^ WPS_M3 = 0x07,$/;" e enum:wps_msg_type +WPS_M4 src/wps/wps_defs.h /^ WPS_M4 = 0x08,$/;" e enum:wps_msg_type +WPS_M5 src/wps/wps_defs.h /^ WPS_M5 = 0x09,$/;" e enum:wps_msg_type +WPS_M6 src/wps/wps_defs.h /^ WPS_M6 = 0x0a,$/;" e enum:wps_msg_type +WPS_M7 src/wps/wps_defs.h /^ WPS_M7 = 0x0b,$/;" e enum:wps_msg_type +WPS_M8 src/wps/wps_defs.h /^ WPS_M8 = 0x0c,$/;" e enum:wps_msg_type +WPS_MAX_AUTHORIZED_MACS src/wps/wps_defs.h 336;" d +WPS_MAX_DEVICE_NAME_LEN include/esp_supplicant/esp_wps.h 66;" d +WPS_MAX_DIS_AP_NUM src/wps/wps_defs.h 340;" d +WPS_MAX_MANUFACTURER_LEN include/esp_supplicant/esp_wps.h 63;" d +WPS_MAX_MODEL_NAME_LEN include/esp_supplicant/esp_wps.h 65;" d +WPS_MAX_MODEL_NUMBER_LEN include/esp_supplicant/esp_wps.h 64;" d +WPS_MAX_VENDOR_EXT_LEN src/wps/wps.h 69;" d +WPS_MGMTAUTHKEY_LEN src/wps/wps_defs.h 43;" d +WPS_MGMTENCKEY_LEN src/wps/wps_defs.h 44;" d +WPS_MGMT_KEY_ID_LEN src/wps/wps_defs.h 45;" d +WPS_MSG_DONE src/wps/wps_i.h /^ RECV_M8, RECEIVED_M2D, WPS_MSG_DONE, RECV_ACK, WPS_FINISHED,$/;" e enum:wps_data::__anon53 +WPS_MSG_FLAG_LEN src/wps/wps_defs.h /^ WPS_MSG_FLAG_LEN = 0x02$/;" e enum:wps_msg_flag +WPS_MSG_FLAG_MORE src/wps/wps_defs.h /^ WPS_MSG_FLAG_MORE = 0x01,$/;" e enum:wps_msg_flag +WPS_NONCE_LEN src/wps/wps_defs.h 34;" d +WPS_OOB_DEVICE_PASSWORD_LEN src/wps/wps_defs.h 47;" d +WPS_OOB_DEVICE_PASSWORD_MIN_LEN src/wps/wps_defs.h 46;" d +WPS_OOB_PUBKEY_HASH_LEN src/wps/wps_defs.h 48;" d +WPS_OUTBUF_SIZE src/wps/wps.h 1027;" d +WPS_PBC_WALK_TIME src/wps/wps_defs.h 334;" d +WPS_PENDING src/wps/wps.h /^ WPS_PENDING,$/;" e enum:wps_process_res +WPS_PSK_LEN src/wps/wps_defs.h 39;" d +WPS_ProbeRequest src/wps/wps_defs.h /^ WPS_ProbeRequest = 0x02,$/;" e enum:wps_msg_type +WPS_ProbeResponse src/wps/wps_defs.h /^ WPS_ProbeResponse = 0x03,$/;" e enum:wps_msg_type +WPS_REQ_ENROLLEE src/wps/wps_defs.h /^ WPS_REQ_ENROLLEE = 1,$/;" e enum:wps_request_type +WPS_REQ_ENROLLEE_INFO src/wps/wps_defs.h /^ WPS_REQ_ENROLLEE_INFO = 0,$/;" e enum:wps_request_type +WPS_REQ_REGISTRAR src/wps/wps_defs.h /^ WPS_REQ_REGISTRAR = 2,$/;" e enum:wps_request_type +WPS_REQ_WLAN_MANAGER_REGISTRAR src/wps/wps_defs.h /^ WPS_REQ_WLAN_MANAGER_REGISTRAR = 3$/;" e enum:wps_request_type +WPS_RESP_AP src/wps/wps_defs.h /^ WPS_RESP_AP = 3$/;" e enum:wps_response_type +WPS_RESP_ENROLLEE src/wps/wps_defs.h /^ WPS_RESP_ENROLLEE = 1,$/;" e enum:wps_response_type +WPS_RESP_ENROLLEE_INFO src/wps/wps_defs.h /^ WPS_RESP_ENROLLEE_INFO = 0,$/;" e enum:wps_response_type +WPS_RESP_REGISTRAR src/wps/wps_defs.h /^ WPS_RESP_REGISTRAR = 2,$/;" e enum:wps_response_type +WPS_RF_24GHZ src/wps/wps_defs.h 238;" d +WPS_RF_50GHZ src/wps/wps_defs.h 239;" d +WPS_SECRET_NONCE_LEN src/wps/wps_defs.h 40;" d +WPS_SEC_DEVICE_TYPES src/wps/wps.h 96;" d +WPS_SEC_DEV_TYPE_MAX_LEN src/wps/wps.h 65;" d +WPS_STATE_CONFIGURED src/wps/wps_defs.h /^ WPS_STATE_CONFIGURED = 2$/;" e enum:wps_state +WPS_STATE_NOT_CONFIGURED src/wps/wps_defs.h /^ WPS_STATE_NOT_CONFIGURED = 1,$/;" e enum:wps_state +WPS_STATUS_DISABLE src/esp_supplicant/esp_wifi_driver.h /^ WPS_STATUS_DISABLE = 0,$/;" e enum:wps_status +WPS_STATUS_MAX src/esp_supplicant/esp_wifi_driver.h /^ WPS_STATUS_MAX,$/;" e enum:wps_status +WPS_STATUS_PENDING src/esp_supplicant/esp_wifi_driver.h /^ WPS_STATUS_PENDING,$/;" e enum:wps_status +WPS_STATUS_SCANNING src/esp_supplicant/esp_wifi_driver.h /^ WPS_STATUS_SCANNING,$/;" e enum:wps_status +WPS_STATUS_SUCCESS src/esp_supplicant/esp_wifi_driver.h /^ WPS_STATUS_SUCCESS,$/;" e enum:wps_status +WPS_STATUS_t src/esp_supplicant/esp_wifi_driver.h /^} WPS_STATUS_t;$/;" t typeref:enum:wps_status +WPS_STRDUP src/wps/wps_registrar.c 281;" d file: +WPS_STRDUP src/wps/wps_registrar.c 290;" d file: +WPS_STRICT_WPS2 src/wps/wps_validate.c 16;" d file: +WPS_TASK_STACK_SIZE src/esp_supplicant/esp_wifi_driver.h 28;" d +WPS_TYPE_ALL_MAX include/esp_supplicant/esp_wps.h /^ WPS_TYPE_ALL_MAX,$/;" e enum:wps_type +WPS_TYPE_DISABLE include/esp_supplicant/esp_wps.h /^ WPS_TYPE_DISABLE = 0,$/;" e enum:wps_type +WPS_TYPE_DISPLAY include/esp_supplicant/esp_wps.h /^ WPS_TYPE_DISPLAY,$/;" e enum:wps_type +WPS_TYPE_E_MAX include/esp_supplicant/esp_wps.h /^ WPS_TYPE_E_MAX,$/;" e enum:wps_type +WPS_TYPE_PBC include/esp_supplicant/esp_wps.h /^ WPS_TYPE_PBC,$/;" e enum:wps_type +WPS_TYPE_PIN include/esp_supplicant/esp_wps.h /^ WPS_TYPE_PIN,$/;" e enum:wps_type +WPS_TYPE_R_DISPLAY include/esp_supplicant/esp_wps.h /^ WPS_TYPE_R_DISPLAY,$/;" e enum:wps_type +WPS_TYPE_R_MAX include/esp_supplicant/esp_wps.h /^ WPS_TYPE_R_MAX,$/;" e enum:wps_type +WPS_TYPE_R_PBC include/esp_supplicant/esp_wps.h /^ WPS_TYPE_R_PBC,$/;" e enum:wps_type +WPS_TYPE_R_PIN include/esp_supplicant/esp_wps.h /^ WPS_TYPE_R_PIN,$/;" e enum:wps_type +WPS_UUID_LEN src/wps/wps_defs.h 33;" d +WPS_VENDOR_ID_WFA src/wps/wps_defs.h 142;" d +WPS_VERSION src/wps/wps_defs.h 16;" d +WPS_VERSION src/wps/wps_defs.h 21;" d +WPS_VERSION src/wps/wps_defs.h 23;" d +WPS_WIFI_AUTH_OPEN src/wps/wps_defs.h 189;" d +WPS_WORKAROUNDS src/wps/wps_attr_parse.c 15;" d file: +WPS_WORKAROUNDS src/wps/wps_registrar.c 25;" d file: +WPS_WSC_ACK src/wps/wps_defs.h /^ WPS_WSC_ACK = 0x0d,$/;" e enum:wps_msg_type +WPS_WSC_DONE src/wps/wps_defs.h /^ WPS_WSC_DONE = 0x0f$/;" e enum:wps_msg_type +WPS_WSC_NACK src/wps/wps_defs.h /^ WPS_WSC_NACK = 0x0e,$/;" e enum:wps_msg_type +WSC_ACK src/wps/wps.h /^ WSC_ACK = 0x02,$/;" e enum:wsc_op_code +WSC_Done src/wps/wps.h /^ WSC_Done = 0x05,$/;" e enum:wsc_op_code +WSC_FRAG_ACK src/wps/wps.h /^ WSC_FRAG_ACK = 0x06$/;" e enum:wsc_op_code +WSC_MSG src/wps/wps.h /^ WSC_MSG = 0x04,$/;" e enum:wsc_op_code +WSC_NACK src/wps/wps.h /^ WSC_NACK = 0x03,$/;" e enum:wsc_op_code +WSC_Start src/wps/wps.h /^ WSC_Start = 0x01,$/;" e enum:wsc_op_code +WSC_UPnP src/wps/wps.h /^ WSC_UPnP = 0 \/* No OP Code in UPnP transport *\/,$/;" e enum:wsc_op_code +WePKEY_128_BYTES include/crypto/wepkey.h 5;" d +X509V3_H src/tls/x509v3.h 10;" d +X509_CERT_V1 src/tls/x509v3.h /^ enum { X509_CERT_V1 = 0, X509_CERT_V2 = 1, X509_CERT_V3 = 2 } version;$/;" e enum:x509_certificate::__anon41 +X509_CERT_V2 src/tls/x509v3.h /^ enum { X509_CERT_V1 = 0, X509_CERT_V2 = 1, X509_CERT_V3 = 2 } version;$/;" e enum:x509_certificate::__anon41 +X509_CERT_V3 src/tls/x509v3.h /^ enum { X509_CERT_V1 = 0, X509_CERT_V2 = 1, X509_CERT_V3 = 2 } version;$/;" e enum:x509_certificate::__anon41 +X509_EXT_BASIC_CONSTRAINTS src/tls/x509v3.h 66;" d +X509_EXT_ISSUER_ALT_NAME src/tls/x509v3.h 70;" d +X509_EXT_KEY_USAGE src/tls/x509v3.h 68;" d +X509_EXT_PATH_LEN_CONSTRAINT src/tls/x509v3.h 67;" d +X509_EXT_SUBJECT_ALT_NAME src/tls/x509v3.h 69;" d +X509_KEY_USAGE_CRL_SIGN src/tls/x509v3.h 84;" d +X509_KEY_USAGE_DATA_ENCIPHERMENT src/tls/x509v3.h 81;" d +X509_KEY_USAGE_DECIPHER_ONLY src/tls/x509v3.h 86;" d +X509_KEY_USAGE_DIGITAL_SIGNATURE src/tls/x509v3.h 78;" d +X509_KEY_USAGE_ENCIPHER_ONLY src/tls/x509v3.h 85;" d +X509_KEY_USAGE_KEY_AGREEMENT src/tls/x509v3.h 82;" d +X509_KEY_USAGE_KEY_CERT_SIGN src/tls/x509v3.h 83;" d +X509_KEY_USAGE_KEY_ENCIPHERMENT src/tls/x509v3.h 80;" d +X509_KEY_USAGE_NON_REPUDIATION src/tls/x509v3.h 79;" d +X509_MAX_NAME_ATTRIBUTES src/tls/x509v3.h 32;" d +X509_NAME_ATTR_C src/tls/x509v3.h /^ X509_NAME_ATTR_C,$/;" e enum:x509_name_attr::x509_name_attr_type +X509_NAME_ATTR_CN src/tls/x509v3.h /^ X509_NAME_ATTR_CN,$/;" e enum:x509_name_attr::x509_name_attr_type +X509_NAME_ATTR_DC src/tls/x509v3.h /^ X509_NAME_ATTR_DC,$/;" e enum:x509_name_attr::x509_name_attr_type +X509_NAME_ATTR_L src/tls/x509v3.h /^ X509_NAME_ATTR_L,$/;" e enum:x509_name_attr::x509_name_attr_type +X509_NAME_ATTR_NOT_USED src/tls/x509v3.h /^ X509_NAME_ATTR_NOT_USED,$/;" e enum:x509_name_attr::x509_name_attr_type +X509_NAME_ATTR_O src/tls/x509v3.h /^ X509_NAME_ATTR_O,$/;" e enum:x509_name_attr::x509_name_attr_type +X509_NAME_ATTR_OU src/tls/x509v3.h /^ X509_NAME_ATTR_OU$/;" e enum:x509_name_attr::x509_name_attr_type +X509_NAME_ATTR_ST src/tls/x509v3.h /^ X509_NAME_ATTR_ST,$/;" e enum:x509_name_attr::x509_name_attr_type +X509_VALIDATE_BAD_CERTIFICATE src/tls/x509v3.h /^ X509_VALIDATE_BAD_CERTIFICATE,$/;" e enum:__anon42 +X509_VALIDATE_CERTIFICATE_EXPIRED src/tls/x509v3.h /^ X509_VALIDATE_CERTIFICATE_EXPIRED,$/;" e enum:__anon42 +X509_VALIDATE_CERTIFICATE_REVOKED src/tls/x509v3.h /^ X509_VALIDATE_CERTIFICATE_REVOKED,$/;" e enum:__anon42 +X509_VALIDATE_CERTIFICATE_UNKNOWN src/tls/x509v3.h /^ X509_VALIDATE_CERTIFICATE_UNKNOWN,$/;" e enum:__anon42 +X509_VALIDATE_OK src/tls/x509v3.h /^ X509_VALIDATE_OK,$/;" e enum:__anon42 +X509_VALIDATE_UNKNOWN_CA src/tls/x509v3.h /^ X509_VALIDATE_UNKNOWN_CA$/;" e enum:__anon42 +X509_VALIDATE_UNSUPPORTED_CERTIFICATE src/tls/x509v3.h /^ X509_VALIDATE_UNSUPPORTED_CERTIFICATE,$/;" e enum:__anon42 +XFREE src/crypto/libtommath.h 81;" d +XFREE src/tls/libtommath.h 83;" d +XMALLOC src/crypto/libtommath.h 80;" d +XMALLOC src/tls/libtommath.h 82;" d +XREALLOC src/crypto/libtommath.h 82;" d +XREALLOC src/tls/libtommath.h 84;" d +_ENDIAN_H_ port/include/endian.h 30;" d +_ESP_WIFI_DRIVER_H_ src/esp_supplicant/esp_wifi_driver.h 16;" d +_UINT16_T_DECLARED port/include/endian.h 57;" d +_UINT16_T_DECLARED port/include/endian.h 60;" d +_UINT32_T_DECLARED port/include/endian.h 63;" d +_UINT32_T_DECLARED port/include/endian.h 66;" d +_UINT64_T_DECLARED port/include/endian.h 69;" d +_UINT64_T_DECLARED port/include/endian.h 72;" d +_UINT8_T_DECLARED port/include/endian.h 51;" d +_UINT8_T_DECLARED port/include/endian.h 54;" d +__BIG_ENDIAN include/utils/common.h 40;" d +__BIG_ENDIAN include/utils/common.h 82;" d +__BYTE_ORDER include/utils/common.h 38;" d +__BYTE_ORDER include/utils/common.h 84;" d +__ESP_WPA_PSK_H__ include/esp_supplicant/esp_wpa_psk.h 16;" d +__ESP_WPS_H__ include/esp_supplicant/esp_wps.h 16;" d +__LITTLE_ENDIAN include/utils/common.h 39;" d +__LITTLE_ENDIAN include/utils/common.h 81;" d +__bitwise include/utils/common.h 273;" d +__bitwise include/utils/common.h 276;" d +__bswap_16 port/include/byteswap.h /^__bswap_16 (unsigned short int __bsx)$/;" f +__bswap_16 port/include/byteswap.h 13;" d +__bswap_32 port/include/byteswap.h /^__bswap_32 (unsigned int __bsx)$/;" f +__bswap_32 port/include/byteswap.h 29;" d +__bswap_64 port/include/byteswap.h 57;" d +__bswap_constant_64 port/include/byteswap.h 47;" d +__force include/utils/common.h 272;" d +__force include/utils/common.h 275;" d +__func__ include/utils/common.h 234;" d +__must_check include/utils/common.h 288;" d +__must_check include/utils/common.h 290;" d +__packed src/eap_peer/eap_mschapv2.c /^} __packed;$/;" v typeref:struct:eap_mschapv2_hdr +__packed src/eap_peer/eap_mschapv2.c /^} __packed;$/;" v typeref:struct:ms_change_password +__packed src/eap_peer/eap_mschapv2.c /^} __packed;$/;" v typeref:struct:ms_response +__wpa_send_eapol src/ap/wpa_auth.c /^void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,$/;" f +_wpa_snprintf_hex src/utils/wpa_debug.c /^static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len, int uppercase)$/;" f file: +a_mpdu_params src/common/ieee802_11_defs.h /^ u8 a_mpdu_params;$/;" m struct:ieee80211_ht_capabilities +ac src/common/ieee802_11_defs.h /^ struct wmm_ac_parameter ac[4]; \/* AC_BE, AC_BK, AC_VI, AC_VO *\/$/;" m struct:wmm_parameter_element typeref:struct:wmm_parameter_element::wmm_ac_parameter +aci_aifsn src/common/ieee802_11_defs.h /^ u8 aci_aifsn; \/* AIFSN, ACM, ACI *\/$/;" m struct:wmm_ac_parameter +action src/common/ieee802_11_defs.h /^ u8 action; \/* *\/$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon83 +action src/common/ieee802_11_defs.h /^ u8 action;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon80 +action src/common/ieee802_11_defs.h /^ u8 action;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon81 +action src/common/ieee802_11_defs.h /^ u8 action;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon82 +action src/common/ieee802_11_defs.h /^ } STRUCT_PACKED action;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon76 +action src/eap_peer/eap_tlv_common.h /^ be16 action;$/;" m struct:eap_tlv_request_action_tlv +action_code src/common/ieee802_11_defs.h /^ u8 action_code;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon78 +action_code src/common/ieee802_11_defs.h /^ u8 action_code;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon79 +action_length src/ap/wpa_auth.h /^ le16 action_length; \/* little endian length of action_frame *\/$/;" m struct:ft_rrb_frame +add_sta src/ap/wpa_auth.h /^ struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);$/;" m struct:wpa_auth_callbacks typeref:struct:wpa_auth_callbacks::add_sta +add_tspec src/ap/wpa_auth.h /^ int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie,$/;" m struct:wpa_auth_callbacks +addr src/ap/ap_config.h /^ macaddr addr;$/;" m struct:mac_acl_entry +addr src/ap/ap_config.h /^ u8 addr[ETH_ALEN];$/;" m struct:hostapd_wpa_psk +addr src/ap/sta_info.h /^ u8 addr[6];$/;" m struct:sta_info +addr src/ap/wpa_auth.h /^ u8 addr[ETH_ALEN];$/;" m struct:ft_remote_r0kh +addr src/ap/wpa_auth.h /^ u8 addr[ETH_ALEN];$/;" m struct:ft_remote_r1kh +addr src/ap/wpa_auth_i.h /^ u8 addr[ETH_ALEN];$/;" m struct:wpa_authenticator +addr src/ap/wpa_auth_i.h /^ u8 addr[ETH_ALEN];$/;" m struct:wpa_state_machine +addr src/rsn_supp/wpa.h /^ u8 addr[ETH_ALEN];$/;" m struct:install_key +addr src/wps/wps.h /^ u8 addr[ETH_ALEN];$/;" m struct:upnp_pending_message +addr src/wps/wps_registrar.c /^ u8 addr[ETH_ALEN];$/;" m struct:wps_pbc_session file: +addr1 src/common/ieee802_11_defs.h /^ u8 addr1[6];$/;" m struct:ieee80211_hdr +addr2 src/common/ieee802_11_defs.h /^ u8 addr2[6];$/;" m struct:ieee80211_hdr +addr3 src/common/ieee802_11_defs.h /^ u8 addr3[6];$/;" m struct:ieee80211_hdr +aes src/crypto/crypto_internal-cipher.c /^ } aes;$/;" m union:crypto_cipher::__anon10 typeref:struct:crypto_cipher::__anon10::__anon12 file: +aes src/fast_crypto/fast_crypto_internal-cipher.c /^ } aes;$/;" m union:fast_crypto_cipher::__anon56 typeref:struct:fast_crypto_cipher::__anon56::__anon58 file: +aes_128_cbc_decrypt src/crypto/aes-cbc.c /^aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)$/;" f +aes_128_cbc_encrypt src/crypto/aes-cbc.c /^aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)$/;" f +aes_decrypt src/crypto/aes-internal-dec.c /^void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)$/;" f +aes_decrypt_deinit src/crypto/aes-internal-dec.c /^void aes_decrypt_deinit(void *ctx)$/;" f +aes_decrypt_init src/crypto/aes-internal-dec.c /^void * aes_decrypt_init(const u8 *key, size_t len)$/;" f +aes_encrypt src/crypto/aes-internal-enc.c /^void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)$/;" f +aes_encrypt_deinit src/crypto/aes-internal-enc.c /^void aes_encrypt_deinit(void *ctx)$/;" f +aes_encrypt_init src/crypto/aes-internal-enc.c /^void * aes_encrypt_init(const u8 *key, size_t len)$/;" f +aes_unwrap src/crypto/aes-unwrap.c /^aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)$/;" f +aes_wrap src/crypto/aes-wrap.c /^int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)$/;" f +aid src/ap/sta_info.h /^ u16 aid; \/* STA's unique AID (1 .. 2007) or 0 if not yet assigned *\/$/;" m struct:sta_info +aid src/common/ieee802_11_defs.h /^ le16 aid;$/;" m struct:ieee80211_mgmt::__anon66::__anon70 +alert src/tls/tls.h /^ } alert;$/;" m union:tls_event_data typeref:struct:tls_event_data::__anon36 +alert_description src/tls/tlsv1_client_i.h /^ u8 alert_description;$/;" m struct:tlsv1_client +alert_description src/tls/tlsv1_server_i.h /^ u8 alert_description;$/;" m struct:tlsv1_server +alert_level src/tls/tlsv1_client_i.h /^ u8 alert_level;$/;" m struct:tlsv1_client +alert_level src/tls/tlsv1_server_i.h /^ u8 alert_level;$/;" m struct:tlsv1_server +alg src/common/wpa_common.h /^ enum wpa_alg alg;$/;" m struct:wpa_gtk_data typeref:enum:wpa_gtk_data::wpa_alg +alg src/crypto/crypto_internal-cipher.c /^ enum crypto_cipher_alg alg;$/;" m struct:crypto_cipher typeref:enum:crypto_cipher::crypto_cipher_alg file: +alg src/crypto/crypto_internal.c /^ enum crypto_hash_alg alg;$/;" m struct:crypto_hash typeref:enum:crypto_hash::crypto_hash_alg file: +alg src/fast_crypto/fast_crypto_internal-cipher.c /^ enum crypto_cipher_alg alg;$/;" m struct:fast_crypto_cipher typeref:enum:fast_crypto_cipher::crypto_cipher_alg file: +alg src/fast_crypto/fast_crypto_internal.c /^ enum crypto_hash_alg alg;$/;" m struct:fast_crypto_hash typeref:enum:fast_crypto_hash::crypto_hash_alg file: +alg src/rsn_supp/wpa.h /^ enum wpa_alg alg;$/;" m struct:install_key typeref:enum:install_key::wpa_alg +alg src/tls/pkcs5.c /^ } alg;$/;" m struct:pkcs5_params typeref:enum:pkcs5_params::pkcs5_alg file: +alg src/tls/tlsv1_common.h /^ enum crypto_cipher_alg alg;$/;" m struct:tls_cipher_data typeref:enum:tls_cipher_data::crypto_cipher_alg +aliasing_hide_typecast include/utils/common.h 336;" d +alloc src/crypto/libtommath.h /^ int used, alloc, sign;$/;" m struct:__anon8 +alloc src/tls/libtommath.h /^ int used, alloc, sign;$/;" m struct:__anon40 +allowNotifications src/eap_peer/eap_i.h /^ Boolean allowNotifications;$/;" m struct:eap_method_ret +alt_email src/tls/x509v3.h /^ char *alt_email; \/* rfc822Name *\/$/;" m struct:x509_name +altsubject_match src/tls/tls.h /^ const char *altsubject_match;$/;" m struct:tls_connection_params +anonce src/common/wpa_common.h /^ u8 anonce[WPA_NONCE_LEN];$/;" m struct:rsn_ftie +anonce src/rsn_supp/wpa.h /^ u8 anonce[WPA_NONCE_LEN]; \/* ANonce from the last 1\/4 msg *\/$/;" m struct:wpa_sm +anonymous_identity src/eap_peer/eap_config.h /^ u8 *anonymous_identity;$/;" m struct:eap_peer_config +anonymous_identity_len src/eap_peer/eap_config.h /^ size_t anonymous_identity_len;$/;" m struct:eap_peer_config +ap src/wps/wps.h /^ int ap;$/;" m struct:wps_context +ap src/wps/wps.h /^ } ap;$/;" m union:wps_event_data typeref:struct:wps_event_data::wps_event_er_ap +ap_address src/ap/wpa_auth.h /^ u8 ap_address[ETH_ALEN];$/;" m struct:ft_r0kh_r1kh_pull_frame +ap_address src/ap/wpa_auth.h /^ u8 ap_address[ETH_ALEN];$/;" m struct:ft_r0kh_r1kh_push_frame +ap_address src/ap/wpa_auth.h /^ u8 ap_address[ETH_ALEN];$/;" m struct:ft_r0kh_r1kh_resp_frame +ap_address src/ap/wpa_auth.h /^ u8 ap_address[ETH_ALEN];$/;" m struct:ft_rrb_frame +ap_channel src/wps/wps.h /^ u16 ap_channel;$/;" m struct:wps_credential +ap_channel src/wps/wps_attr_parse.h /^ const u8 *ap_channel; \/* 2 octets *\/$/;" m struct:wps_parse_attr +ap_max_inactivity src/ap/ap_config.h /^ int ap_max_inactivity;$/;" m struct:hostapd_bss_config +ap_mlme src/ap/wpa_auth.h /^ int ap_mlme;$/;" m struct:wpa_auth_config +ap_nfc_dev_pw src/wps/wps.h /^ struct wpabuf *ap_nfc_dev_pw;$/;" m struct:wps_context typeref:struct:wps_context::wpabuf +ap_nfc_dev_pw_id src/wps/wps.h /^ u16 ap_nfc_dev_pw_id;$/;" m struct:wps_context +ap_nfc_dh_privkey src/wps/wps.h /^ struct wpabuf *ap_nfc_dh_privkey;$/;" m struct:wps_context typeref:struct:wps_context::wpabuf +ap_nfc_dh_pubkey src/wps/wps.h /^ struct wpabuf *ap_nfc_dh_pubkey;$/;" m struct:wps_context typeref:struct:wps_context::wpabuf +ap_notify_completed_rsne src/rsn_supp/wpa.h /^ bool ap_notify_completed_rsne;$/;" m struct:wpa_sm +ap_pin src/ap/ap_config.h /^ char *ap_pin;$/;" m struct:hostapd_bss_config +ap_pin_failures src/ap/hostapd.h /^ unsigned int ap_pin_failures;$/;" m struct:hostapd_data +ap_pin_failures_consecutive src/ap/hostapd.h /^ unsigned int ap_pin_failures_consecutive;$/;" m struct:hostapd_data +ap_pin_lockout_time src/ap/hostapd.h /^ unsigned int ap_pin_lockout_time;$/;" m struct:hostapd_data +ap_rsn_ie src/rsn_supp/wpa.h /^ u8 *ap_wpa_ie, *ap_rsn_ie;$/;" m struct:wpa_sm +ap_rsn_ie_len src/rsn_supp/wpa.h /^ size_t ap_wpa_ie_len, ap_rsn_ie_len;$/;" m struct:wpa_sm +ap_settings src/ap/ap_config.h /^ u8 *ap_settings;$/;" m struct:hostapd_bss_config +ap_settings src/wps/wps.h /^ u8 *ap_settings;$/;" m struct:wps_context +ap_settings src/wps/wps.h /^ } ap_settings;$/;" m union:wps_event_data typeref:struct:wps_event_data::wps_event_er_ap_settings +ap_settings_cb src/wps/wps_i.h /^ void (*ap_settings_cb)(void *ctx, const struct wps_credential *cred);$/;" m struct:wps_data +ap_settings_cb_ctx src/wps/wps_i.h /^ void *ap_settings_cb_ctx;$/;" m struct:wps_data +ap_settings_len src/ap/ap_config.h /^ size_t ap_settings_len;$/;" m struct:hostapd_bss_config +ap_settings_len src/wps/wps.h /^ size_t ap_settings_len;$/;" m struct:wps_context +ap_setup_locked src/ap/ap_config.h /^ int ap_setup_locked;$/;" m struct:hostapd_bss_config +ap_setup_locked src/wps/wps.h /^ int ap_setup_locked;$/;" m struct:wps_context +ap_setup_locked src/wps/wps_attr_parse.h /^ const u8 *ap_setup_locked; \/* 1 octet *\/$/;" m struct:wps_parse_attr +ap_sta_is_authorized src/ap/sta_info.h /^static inline int ap_sta_is_authorized(struct sta_info *sta)$/;" f +ap_table_expiration_time src/ap/ap_config.h /^ int ap_table_expiration_time;$/;" m struct:hostapd_config +ap_table_max_size src/ap/ap_config.h /^ int ap_table_max_size;$/;" m struct:hostapd_config +ap_wpa_ie src/rsn_supp/wpa.h /^ u8 *ap_wpa_ie, *ap_rsn_ie;$/;" m struct:wpa_sm +ap_wpa_ie_len src/rsn_supp/wpa.h /^ size_t ap_wpa_ie_len, ap_rsn_ie_len;$/;" m struct:wpa_sm +arg src/esp_supplicant/esp_wifi_driver.h /^ void *arg;$/;" m struct:__anon32 +arg src/esp_supplicant/esp_wps.c /^ void *arg;$/;" m struct:__anon33 file: +arg_size src/esp_supplicant/esp_wifi_driver.h /^ uint32_t arg_size;$/;" m struct:__anon32 +asel_capabilities src/common/ieee802_11_defs.h /^ u8 asel_capabilities;$/;" m struct:ieee80211_ht_capabilities +asn1_bit_string_to_long src/tls/asn1.c /^unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len)$/;" f +asn1_get_next src/tls/asn1.c /^int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)$/;" f +asn1_get_oid src/tls/asn1.c /^int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,$/;" f +asn1_hdr src/tls/asn1.h /^struct asn1_hdr {$/;" s +asn1_oid src/tls/asn1.h /^struct asn1_oid {$/;" s +asn1_oid_to_str src/tls/asn1.c /^void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len)$/;" f +asn1_parse_oid src/tls/asn1.c /^int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid)$/;" f +assoc_ie_buf src/rsn_supp/wpa.c /^u8 assoc_ie_buf[ASSOC_IE_LEN+2]; $/;" v +assoc_req src/common/ieee802_11_defs.h /^ } STRUCT_PACKED assoc_req;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon69 +assoc_resp src/common/ieee802_11_defs.h /^ } STRUCT_PACKED assoc_resp, reassoc_resp;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon70 +assoc_resp_ftie src/ap/wpa_auth_i.h /^ u8 *assoc_resp_ftie;$/;" m struct:wpa_state_machine +assoc_sa_query_max_timeout src/ap/ap_config.h /^ unsigned int assoc_sa_query_max_timeout;$/;" m struct:hostapd_bss_config +assoc_sa_query_retry_timeout src/ap/ap_config.h /^ int assoc_sa_query_retry_timeout;$/;" m struct:hostapd_bss_config +assoc_state src/wps/wps_attr_parse.h /^ const u8 *assoc_state; \/* 2 octets *\/$/;" m struct:wps_parse_attr +assoc_wpa_ie src/rsn_supp/wpa.h /^ u8 *assoc_wpa_ie; \/* Own WPA\/RSN IE from (Re)AssocReq *\/$/;" m struct:wpa_sm +assoc_wpa_ie_len src/rsn_supp/wpa.h /^ size_t assoc_wpa_ie_len;$/;" m struct:wpa_sm +assoc_wps_ie src/wps/wps.h /^ const struct wpabuf *assoc_wps_ie;$/;" m struct:wps_config typeref:struct:wps_config::wpabuf +attr src/tls/x509v3.h /^ struct x509_name_attr attr[X509_MAX_NAME_ATTRIBUTES];$/;" m struct:x509_name typeref:struct:x509_name::x509_name_attr +auth src/common/ieee802_11_defs.h /^ } STRUCT_PACKED auth;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon67 +auth src/common/wpa_common.h /^ } auth;$/;" m union:wpa_ptk::__anon62 typeref:struct:wpa_ptk::__anon62::__anon63 +auth_alg src/ap/sta_info.h /^ u16 auth_alg;$/;" m struct:sta_info +auth_alg src/common/ieee802_11_defs.h /^ le16 auth_alg;$/;" m struct:ieee80211_mgmt::__anon66::__anon67 +auth_algs src/ap/ap_config.h /^ int auth_algs; \/* bitfield of allowed IEEE 802.11 authentication$/;" m struct:hostapd_bss_config +auth_challenge src/eap_peer/eap_mschapv2.c /^ u8 *auth_challenge;$/;" m struct:eap_mschapv2_data file: +auth_response src/eap_peer/eap_mschapv2.c /^ u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN];$/;" m struct:eap_mschapv2_data file: +auth_response src/eap_peer/eap_ttls.c /^ u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN];$/;" m struct:eap_ttls_data file: +auth_response_valid src/eap_peer/eap_mschapv2.c /^ int auth_response_valid;$/;" m struct:eap_mschapv2_data file: +auth_response_valid src/eap_peer/eap_ttls.c /^ int auth_response_valid;$/;" m struct:eap_ttls_data file: +auth_transaction src/common/ieee802_11_defs.h /^ le16 auth_transaction;$/;" m struct:ieee80211_mgmt::__anon66::__anon67 +auth_type src/wps/wps.h /^ u16 auth_type;$/;" m struct:wps_credential +auth_type src/wps/wps_attr_parse.h /^ const u8 *auth_type; \/* 2 octets *\/$/;" m struct:wps_parse_attr +auth_type src/wps/wps_i.h /^ u16 auth_type;$/;" m struct:wps_data +auth_type_flags src/wps/wps_attr_parse.h /^ const u8 *auth_type_flags; \/* 2 octets *\/$/;" m struct:wps_parse_attr +auth_types src/wps/wps.h /^ u16 auth_types;$/;" m struct:wps_context +authenticator src/wps/wps_attr_parse.h /^ const u8 *authenticator; \/* WPS_AUTHENTICATOR_LEN (8) octets *\/$/;" m struct:wps_parse_attr +authkey src/wps/wps_i.h /^ u8 authkey[WPS_AUTHKEY_LEN];$/;" m struct:wps_data +authorized_macs src/wps/wps_attr_parse.h /^ const u8 *authorized_macs; \/* <= 30 octets *\/$/;" m struct:wps_parse_attr +authorized_macs src/wps/wps_registrar.c /^ u8 authorized_macs[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];$/;" m struct:wps_registrar file: +authorized_macs_len src/wps/wps_attr_parse.h /^ size_t authorized_macs_len;$/;" m struct:wps_parse_attr +authorized_macs_union src/wps/wps_registrar.c /^ u8 authorized_macs_union[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];$/;" m struct:wps_registrar file: +avp_code src/eap_peer/eap_ttls.h /^ be32 avp_code;$/;" m struct:ttls_avp +avp_code src/eap_peer/eap_ttls.h /^ be32 avp_code;$/;" m struct:ttls_avp_vendor +avp_length src/eap_peer/eap_ttls.h /^ be32 avp_length; \/* 8-bit flags, 24-bit length;$/;" m struct:ttls_avp +avp_length src/eap_peer/eap_ttls.h /^ be32 avp_length; \/* 8-bit flags, 24-bit length;$/;" m struct:ttls_avp_vendor +backend src/utils/ext_password.c /^ const struct ext_password_backend *backend;$/;" m struct:ext_password_data typeref:struct:ext_password_data::ext_password_backend file: +backends src/utils/ext_password.c /^static const struct ext_password_backend *backends[] = {$/;" v typeref:struct:ext_password_backend file: +base64_decode src/utils/base64.c /^unsigned char * base64_decode(const unsigned char *src, size_t len,$/;" f +base64_encode src/utils/base64.c /^unsigned char * base64_encode(const unsigned char *src, size_t len,$/;" f +base64_table src/utils/base64.c /^static const unsigned char base64_table[65] =$/;" v file: +basic_rates src/ap/ap_config.h /^ int *basic_rates;$/;" m struct:hostapd_config +basic_set src/common/ieee802_11_defs.h /^ u8 basic_set[16];$/;" m struct:ieee80211_ht_operation +be16 include/utils/common.h /^typedef u16 __bitwise be16;$/;" t +be16dec port/include/endian.h /^be16dec(const void *pp)$/;" f +be16enc port/include/endian.h /^be16enc(void *pp, uint16_t u)$/;" f +be16toh port/include/endian.h 109;" d +be16toh port/include/endian.h 94;" d +be32 include/utils/common.h /^typedef u32 __bitwise be32;$/;" t +be32dec port/include/endian.h /^be32dec(const void *pp)$/;" f +be32enc port/include/endian.h /^be32enc(void *pp, uint32_t u)$/;" f +be32toh port/include/endian.h 110;" d +be32toh port/include/endian.h 95;" d +be64 include/utils/common.h /^typedef u64 __bitwise be64;$/;" t +be64dec port/include/endian.h /^be64dec(const void *pp)$/;" f +be64enc port/include/endian.h /^be64enc(void *pp, uint64_t u)$/;" f +be64toh port/include/endian.h 111;" d +be64toh port/include/endian.h 96;" d +be_to_host16 include/utils/common.h 106;" d +be_to_host16 include/utils/common.h 65;" d +be_to_host16 include/utils/common.h 93;" d +be_to_host32 include/utils/common.h 109;" d +be_to_host32 include/utils/common.h 68;" d +be_to_host32 include/utils/common.h 97;" d +be_to_host64 include/utils/common.h 101;" d +be_to_host64 include/utils/common.h 113;" d +beacon src/common/ieee802_11_defs.h /^ } STRUCT_PACKED beacon;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon73 +beacon_int src/ap/ap_config.h /^ u16 beacon_int;$/;" m struct:hostapd_config +beacon_int src/common/ieee802_11_defs.h /^ le16 beacon_int;$/;" m struct:ieee80211_mgmt::__anon66::__anon73 +beacon_int src/common/ieee802_11_defs.h /^ le16 beacon_int;$/;" m struct:ieee80211_mgmt::__anon66::__anon75 +bigbyte src/crypto/des-internal.c /^static const u32 bigbyte[24] =$/;" v file: +bignum_add src/crypto/bignum.c /^bignum_add(const struct bignum *a, const struct bignum *b,$/;" f +bignum_add src/tls/bignum.c /^bignum_add(const struct bignum *a, const struct bignum *b,$/;" f +bignum_cmp src/crypto/bignum.c /^bignum_cmp(const struct bignum *a, const struct bignum *b)$/;" f +bignum_cmp src/tls/bignum.c /^bignum_cmp(const struct bignum *a, const struct bignum *b)$/;" f +bignum_cmp_d src/crypto/bignum.c /^bignum_cmp_d(const struct bignum *a, unsigned long b)$/;" f +bignum_cmp_d src/tls/bignum.c /^bignum_cmp_d(const struct bignum *a, unsigned long b)$/;" f +bignum_deinit src/crypto/bignum.c /^bignum_deinit(struct bignum *n)$/;" f +bignum_deinit src/tls/bignum.c /^bignum_deinit(struct bignum *n)$/;" f +bignum_exptmod src/crypto/bignum.c /^bignum_exptmod(const struct bignum *a, const struct bignum *b,$/;" f +bignum_exptmod src/tls/bignum.c /^bignum_exptmod(const struct bignum *a, const struct bignum *b,$/;" f +bignum_get_unsigned_bin src/crypto/bignum.c /^bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len)$/;" f +bignum_get_unsigned_bin src/tls/bignum.c /^bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len)$/;" f +bignum_get_unsigned_bin_len src/crypto/bignum.c /^bignum_get_unsigned_bin_len(struct bignum *n)$/;" f +bignum_get_unsigned_bin_len src/tls/bignum.c /^bignum_get_unsigned_bin_len(struct bignum *n)$/;" f +bignum_init src/crypto/bignum.c /^bignum_init(void)$/;" f +bignum_init src/tls/bignum.c /^bignum_init(void)$/;" f +bignum_mul src/crypto/bignum.c /^bignum_mul(const struct bignum *a, const struct bignum *b,$/;" f +bignum_mul src/tls/bignum.c /^bignum_mul(const struct bignum *a, const struct bignum *b,$/;" f +bignum_mulmod src/crypto/bignum.c /^bignum_mulmod(const struct bignum *a, const struct bignum *b,$/;" f +bignum_mulmod src/tls/bignum.c /^bignum_mulmod(const struct bignum *a, const struct bignum *b,$/;" f +bignum_set_unsigned_bin src/crypto/bignum.c /^bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len)$/;" f +bignum_set_unsigned_bin src/tls/bignum.c /^bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len)$/;" f +bignum_sub src/crypto/bignum.c /^bignum_sub(const struct bignum *a, const struct bignum *b,$/;" f +bignum_sub src/tls/bignum.c /^bignum_sub(const struct bignum *a, const struct bignum *b,$/;" f +binding_nonce src/eap_peer/eap_peap.c /^ u8 binding_nonce[32];$/;" m struct:eap_peap_data file: +bits src/crypto/md5_i.h /^ u32 bits[2];$/;" m struct:MD5Context +blk src/crypto/sha1-internal.c 142;" d file: +blk0 src/crypto/sha1-internal.c 137;" d file: +blk0 src/crypto/sha1-internal.c 140;" d file: +blob src/eap_peer/eap_i.h /^ struct wpa_config_blob blob[BLOB_NUM];$/;" m struct:eap_sm typeref:struct:eap_sm::wpa_config_blob +block_size src/tls/tlsv1_common.h /^ size_t block_size; \/* also iv_size *\/$/;" m struct:tls_cipher_data +bn_reverse src/crypto/libtommath.h /^bn_reverse (unsigned char *s, int len)$/;" f +bn_reverse src/tls/libtommath.h /^bn_reverse (unsigned char *s, int len)$/;" f +broadcast_ether_addr include/utils/common.h 320;" d +broadcast_key_idx_max src/ap/ap_config.h /^ int broadcast_key_idx_min, broadcast_key_idx_max;$/;" m struct:hostapd_bss_config +broadcast_key_idx_min src/ap/ap_config.h /^ int broadcast_key_idx_min, broadcast_key_idx_max;$/;" m struct:hostapd_bss_config +bss src/ap/ap_config.h /^ struct hostapd_bss_config *bss, *last_bss;$/;" m struct:hostapd_config typeref:struct:hostapd_config::hostapd_bss_config +bssid src/ap/ap_config.h /^ macaddr bssid;$/;" m struct:hostapd_bss_config +bssid src/common/ieee802_11_defs.h /^ u8 bssid[6];$/;" m struct:ieee80211_mgmt +bssid src/esp_supplicant/esp_wifi_driver.h /^ uint8_t *bssid;$/;" m struct:wps_scan_ie +bssid src/esp_supplicant/esp_wpa_enterprise.c /^ uint8_t *bssid;$/;" m struct:wpa2_rx_param file: +bssid src/rsn_supp/wpa.h /^ u8 bssid[ETH_ALEN];$/;" m struct:wpa_sm +bssid src/wps/wps.h /^ u8 bssid[6];$/;" m struct:discard_ap_list_t +bssid src/wps/wps.h /^ u8 bssid[ETH_ALEN];$/;" m struct:wps_sm +bswap16 port/include/endian.h 78;" d +bswap32 port/include/endian.h 79;" d +bswap64 port/include/endian.h 80;" d +bswap_16 include/utils/common.h 238;" d +bswap_32 include/utils/common.h 242;" d +buf src/crypto/md5_i.h /^ u32 buf[4];$/;" m struct:MD5Context +buf src/crypto/sha256-internal.c /^ u8 buf[SHA256_BLOCK_SIZE];$/;" m struct:sha256_state file: +buf src/esp_supplicant/esp_wpa_enterprise.c /^ u8 *buf;$/;" m struct:wpa2_rx_param file: +buf src/esp_supplicant/esp_wps.c /^ u8 *buf;$/;" m struct:wps_rx_param file: +buffer src/crypto/md4-internal.c /^ u8 buffer[MD4_BLOCK_LENGTH];$/;" m struct:MD4Context file: +buffer src/crypto/sha1_i.h /^ unsigned char buffer[64];$/;" m struct:SHA1Context +byteReverse src/crypto/md5-internal.c /^static void byteReverse(unsigned char *buf, unsigned longs)$/;" f file: +byteReverse src/crypto/md5-internal.c 70;" d file: +bytebit src/crypto/des-internal.c /^static const u32 bytebit[8] =$/;" v file: +ca src/tls/x509v3.h /^ int ca; \/* cA *\/$/;" m struct:x509_certificate +ca_cert src/eap_peer/eap_config.h /^ u8 *ca_cert;$/;" m struct:eap_peer_config +ca_cert src/tls/tls.h /^ const char *ca_cert;$/;" m struct:tls_connection_params +ca_cert2 src/eap_peer/eap_config.h /^ u8 *ca_cert2;$/;" m struct:eap_peer_config +ca_cert_blob src/tls/tls.h /^ const u8 *ca_cert_blob;$/;" m struct:tls_connection_params +ca_cert_blob_len src/tls/tls.h /^ size_t ca_cert_blob_len;$/;" m struct:tls_connection_params +ca_cert_id src/tls/tls.h /^ const char *ca_cert_id;$/;" m struct:tls_connection_params +ca_path src/eap_peer/eap_config.h /^ u8 *ca_path;$/;" m struct:eap_peer_config +ca_path src/tls/tls.h /^ const char *ca_path;$/;" m struct:tls_connection_params +ca_path2 src/eap_peer/eap_config.h /^ u8 *ca_path2;$/;" m struct:eap_peer_config +capab_info src/common/ieee802_11_defs.h /^ le16 capab_info;$/;" m struct:ieee80211_mgmt::__anon66::__anon69 +capab_info src/common/ieee802_11_defs.h /^ le16 capab_info;$/;" m struct:ieee80211_mgmt::__anon66::__anon70 +capab_info src/common/ieee802_11_defs.h /^ le16 capab_info;$/;" m struct:ieee80211_mgmt::__anon66::__anon71 +capab_info src/common/ieee802_11_defs.h /^ le16 capab_info;$/;" m struct:ieee80211_mgmt::__anon66::__anon73 +capab_info src/common/ieee802_11_defs.h /^ le16 capab_info;$/;" m struct:ieee80211_mgmt::__anon66::__anon75 +capabilities src/common/wpa_common.h /^ int capabilities;$/;" m struct:wpa_ie_data +capability src/ap/sta_info.h /^ u16 capability;$/;" m struct:sta_info +capinfo src/esp_supplicant/esp_wifi_driver.h /^ uint16_t capinfo;$/;" m struct:wps_scan_ie +category src/common/ieee802_11_defs.h /^ u8 category;$/;" m struct:ieee80211_mgmt::__anon66::__anon76 +cb src/ap/hostapd.h /^ int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid,$/;" m struct:hostapd_probereq_cb +cb_ctx src/tls/tls.h /^ void *cb_ctx;$/;" m struct:tls_config +cb_ctx src/wps/wps.h /^ void *cb_ctx;$/;" m struct:wps_context +cb_ctx src/wps/wps.h /^ void *cb_ctx;$/;" m struct:wps_registrar_config +cb_ctx src/wps/wps_registrar.c /^ void *cb_ctx;$/;" m struct:wps_registrar file: +cbc src/crypto/crypto_internal-cipher.c /^ u8 cbc[32];$/;" m struct:crypto_cipher::__anon10::__anon12 file: +cbc src/crypto/crypto_internal-cipher.c /^ u8 cbc[8];$/;" m struct:crypto_cipher::__anon10::__anon13 file: +cbc src/crypto/crypto_internal-cipher.c /^ u8 cbc[8];$/;" m struct:crypto_cipher::__anon10::__anon14 file: +cbc src/fast_crypto/fast_crypto_internal-cipher.c /^ uint32_t cbc[8];$/;" m struct:fast_crypto_cipher::__anon56::__anon60 file: +cbc src/fast_crypto/fast_crypto_internal-cipher.c /^ uint8_t cbc[32];$/;" m struct:fast_crypto_cipher::__anon56::__anon58 file: +cbc src/fast_crypto/fast_crypto_internal-cipher.c /^ uint8_t cbc[8];$/;" m struct:fast_crypto_cipher::__anon56::__anon59 file: +ccmp src/esp_supplicant/esp_wifi_driver.h /^struct wifi_cipher ccmp;$/;" v typeref:struct:wifi_cipher +cert src/tls/tls.h /^ const struct wpabuf *cert;$/;" m struct:tls_event_data::__anon34 typeref:struct:tls_event_data::__anon34::wpabuf +cert src/tls/tls.h /^ const struct wpabuf *cert;$/;" m struct:tls_event_data::__anon35 typeref:struct:tls_event_data::__anon35::wpabuf +cert src/tls/tlsv1_cred.h /^ struct x509_certificate *cert;$/;" m struct:tlsv1_credentials typeref:struct:tlsv1_credentials::x509_certificate +cert_fail src/tls/tls.h /^ } cert_fail;$/;" m union:tls_event_data typeref:struct:tls_event_data::__anon34 +cert_id src/tls/tls.h /^ const char *cert_id;$/;" m struct:tls_connection_params +cert_in_cb src/tls/tls.h /^ int cert_in_cb;$/;" m struct:tls_config +cert_len src/tls/x509v3.h /^ size_t cert_len;$/;" m struct:x509_certificate +cert_start src/tls/x509v3.h /^ const u8 *cert_start;$/;" m struct:x509_certificate +certificate_requested src/tls/tlsv1_client_i.h /^ unsigned int certificate_requested:1;$/;" m struct:tlsv1_client +challenge_hash src/crypto/ms_funcs.c /^static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,$/;" f file: +challenge_response src/crypto/ms_funcs.c /^void challenge_response(const u8 *challenge, const u8 *password_hash,$/;" f +chan src/esp_supplicant/esp_wifi_driver.h /^ uint8_t chan;$/;" m struct:wps_scan_ie +chan_switch src/common/ieee802_11_defs.h /^ } STRUCT_PACKED chan_switch;$/;" m union:ieee80211_mgmt::__anon66::__anon76::__anon77 typeref:struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon79 +changed src/ap/wpa_auth_i.h /^ Boolean changed;$/;" m struct:wpa_group +changed src/ap/wpa_auth_i.h /^ unsigned int changed:1;$/;" m struct:wpa_state_machine +channel src/ap/ap_config.h /^ u8 channel;$/;" m struct:hostapd_config +channel src/ap/hostapd.h /^ u32 channel;$/;" m struct:hostapd_frame_info +channel src/wps/wps.h /^ u8 channel;$/;" m struct:wps_sm +chap_md5 src/eap_peer/chap.c /^int chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge,$/;" f +check_crl src/tls/tls_internal.c /^ int check_crl;$/;" m struct:tls_global file: +cipher src/tls/tlsv1_common.h /^ tls_cipher cipher;$/;" m struct:tls_cipher_data +cipher src/tls/tlsv1_common.h /^ tls_cipher cipher;$/;" m struct:tls_cipher_suite +cipher_alg src/tls/tlsv1_record.h /^ enum crypto_cipher_alg cipher_alg;$/;" m struct:tlsv1_record_layer typeref:enum:tlsv1_record_layer::crypto_cipher_alg +cipher_suite src/tls/tlsv1_record.h /^ u16 cipher_suite;$/;" m struct:tlsv1_record_layer +cipher_suite src/tls/tlsv1_server_i.h /^ u16 cipher_suite;$/;" m struct:tlsv1_server +cipher_suites src/tls/tlsv1_client_i.h /^ u16 cipher_suites[MAX_CIPHER_COUNT];$/;" m struct:tlsv1_client +cipher_suites src/tls/tlsv1_server_i.h /^ u16 cipher_suites[MAX_CIPHER_COUNT];$/;" m struct:tlsv1_server +client src/tls/tls_internal.c /^ struct tlsv1_client *client;$/;" m struct:tls_connection typeref:struct:tls_connection::tlsv1_client file: +client_cert src/eap_peer/eap_config.h /^ u8 *client_cert;$/;" m struct:eap_peer_config +client_cert src/tls/tls.h /^ const char *client_cert;$/;" m struct:tls_connection_params +client_cert2 src/eap_peer/eap_config.h /^ u8 *client_cert2;$/;" m struct:eap_peer_config +client_cert_blob src/tls/tls.h /^ const u8 *client_cert_blob;$/;" m struct:tls_connection_params +client_cert_blob_len src/tls/tls.h /^ size_t client_cert_blob_len;$/;" m struct:tls_connection_params +client_hello_ext src/tls/tlsv1_client_i.h /^ u8 *client_hello_ext;$/;" m struct:tlsv1_client +client_hello_ext_len src/tls/tlsv1_client_i.h /^ size_t client_hello_ext_len;$/;" m struct:tlsv1_client +client_random src/tls/tls.h /^ const u8 *client_random;$/;" m struct:tls_keys +client_random src/tls/tlsv1_client_i.h /^ u8 client_random[TLS_RANDOM_LEN];$/;" m struct:tlsv1_client +client_random src/tls/tlsv1_server_i.h /^ u8 client_random[TLS_RANDOM_LEN];$/;" m struct:tlsv1_server +client_random_len src/tls/tls.h /^ size_t client_random_len;$/;" m struct:tls_keys +client_rsa_key src/tls/tlsv1_server_i.h /^ struct crypto_public_key *client_rsa_key;$/;" m struct:tlsv1_server typeref:struct:tlsv1_server::crypto_public_key +client_version src/tls/tlsv1_server_i.h /^ u16 client_version;$/;" m struct:tlsv1_server +cm_timer src/rsn_supp/wpa.h /^ ETSTimer cm_timer;$/;" m struct:wpa_sm +cmk src/eap_peer/eap_peap.c /^ u8 cmk[20];$/;" m struct:eap_peap_data file: +code src/eap_peer/eap_defs.h /^ u8 code;$/;" m struct:eap_hdr +compound_mac src/eap_peer/eap_tlv_common.h /^ u8 compound_mac[20];$/;" m struct:eap_tlv_crypto_binding_tlv +conf src/ap/hostapd.h /^ struct hostapd_bss_config *conf;$/;" m struct:hostapd_data typeref:struct:hostapd_data::hostapd_bss_config +conf src/ap/wpa_auth_i.h /^ struct wpa_auth_config conf;$/;" m struct:wpa_authenticator typeref:struct:wpa_authenticator::wpa_auth_config +config src/eap_peer/eap_i.h /^ struct eap_peer_config config;$/;" m struct:eap_sm typeref:struct:eap_sm::eap_peer_config +config src/wps/wps.h /^ wifi_sta_config_t config;$/;" m struct:wps_sm +config_assoc_ie src/rsn_supp/wpa.h /^ void (*config_assoc_ie) (u8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len);$/;" m struct:wpa_sm +config_error src/wps/wps.h /^ u16 config_error;$/;" m struct:wps_event_data::wps_event_fail +config_error src/wps/wps.h /^ u16 config_error;$/;" m struct:wps_event_data::wps_event_m2d +config_error src/wps/wps_attr_parse.h /^ const u8 *config_error; \/* 2 octets *\/$/;" m struct:wps_parse_attr +config_error src/wps/wps_i.h /^ u16 config_error;$/;" m struct:wps_data +config_methods src/ap/ap_config.h /^ char *config_methods;$/;" m struct:hostapd_bss_config +config_methods src/wps/wps.h /^ u16 config_methods;$/;" m struct:wps_event_data::wps_event_er_enrollee +config_methods src/wps/wps.h /^ u16 config_methods;$/;" m struct:wps_event_data::wps_event_m2d +config_methods src/wps/wps.h /^ u16 config_methods;$/;" m struct:wps_context +config_methods src/wps/wps.h /^ u16 config_methods;$/;" m struct:wps_device_data +config_methods src/wps/wps_attr_parse.h /^ const u8 *config_methods; \/* 2 octets *\/$/;" m struct:wps_parse_attr +config_read_cb src/ap/hostapd.h /^ struct hostapd_config * (*config_read_cb)(const char *config_fname);$/;" m struct:hapd_interfaces typeref:struct:hapd_interfaces::config_read_cb +conn src/eap_peer/eap_tls_common.h /^ struct tls_connection *conn;$/;" m struct:eap_ssl_data typeref:struct:eap_ssl_data::tls_connection +conn_type_flags src/wps/wps_attr_parse.h /^ const u8 *conn_type_flags; \/* 1 octet *\/$/;" m struct:wps_parse_attr +constructed src/tls/asn1.h /^ u8 identifier, class, constructed;$/;" m struct:asn1_hdr typeref:class:asn1_hdr:: +control_chan src/common/ieee802_11_defs.h /^ u8 control_chan;$/;" m struct:ieee80211_ht_operation +cookey src/crypto/des-internal.c /^static void cookey(const u32 *raw1, u32 *keyout)$/;" f file: +count src/ap/hostapd.h /^ size_t count;$/;" m struct:hapd_interfaces +count src/crypto/md4-internal.c /^ u64 count;$/;" m struct:MD4Context file: +count src/crypto/sha1_i.h /^ u32 count[2];$/;" m struct:SHA1Context +counter src/ap/wpa_auth_i.h /^ u8 counter[WPA_REPLAY_COUNTER_LEN];$/;" m struct:wpa_state_machine::wpa_key_replay_counter +countermeasures src/rsn_supp/wpa.h /^ int countermeasures; \/*TKIP countermeasures state flag, 1:in countermeasures state*\/$/;" m struct:wpa_sm +country src/ap/ap_config.h /^ char country[3]; \/* first two octets: country code as described in$/;" m struct:hostapd_config +cred src/tls/tlsv1_client_i.h /^ struct tlsv1_credentials *cred;$/;" m struct:tlsv1_client typeref:struct:tlsv1_client::tlsv1_credentials +cred src/tls/tlsv1_server_i.h /^ struct tlsv1_credentials *cred;$/;" m struct:tlsv1_server typeref:struct:tlsv1_server::tlsv1_credentials +cred src/wps/wps.h /^ const struct wps_credential *cred;$/;" m struct:wps_event_data::wps_event_er_ap_settings typeref:struct:wps_event_data::wps_event_er_ap_settings::wps_credential +cred src/wps/wps_attr_parse.h /^ const u8 *cred[MAX_CRED_COUNT];$/;" m struct:wps_parse_attr +cred src/wps/wps_i.h /^ struct wps_credential cred;$/;" m struct:wps_data typeref:struct:wps_data::wps_credential +cred_attr src/wps/wps.h /^ const u8 *cred_attr;$/;" m struct:wps_credential +cred_attr_len src/wps/wps.h /^ size_t cred_attr_len;$/;" m struct:wps_credential +cred_cb src/wps/wps.h /^ int (*cred_cb)(void *ctx, const struct wps_credential *cred);$/;" m struct:wps_context +cred_len src/wps/wps_attr_parse.h /^ size_t cred_len[MAX_CRED_COUNT];$/;" m struct:wps_parse_attr +crypto_bignum test/test_crypto.c /^typedef struct crypto_bignum crypto_bignum;$/;" t typeref:struct:crypto_bignum file: +crypto_bignum_add src/crypto/crypto_mbedtls.c /^int crypto_bignum_add(const struct crypto_bignum *a,$/;" f +crypto_bignum_bits src/crypto/crypto_mbedtls.c /^int crypto_bignum_bits(const struct crypto_bignum *a)$/;" f +crypto_bignum_cmp src/crypto/crypto_mbedtls.c /^int crypto_bignum_cmp(const struct crypto_bignum *a,$/;" f +crypto_bignum_deinit src/crypto/crypto_mbedtls.c /^void crypto_bignum_deinit(struct crypto_bignum *n, int clear)$/;" f +crypto_bignum_div src/crypto/crypto_mbedtls.c /^int crypto_bignum_div(const struct crypto_bignum *a,$/;" f +crypto_bignum_exptmod src/crypto/crypto_mbedtls.c /^int crypto_bignum_exptmod(const struct crypto_bignum *a,$/;" f +crypto_bignum_init src/crypto/crypto_mbedtls.c /^struct crypto_bignum *crypto_bignum_init(void)$/;" f +crypto_bignum_init_set src/crypto/crypto_mbedtls.c /^struct crypto_bignum *crypto_bignum_init_set(const u8 *buf, size_t len)$/;" f +crypto_bignum_inverse src/crypto/crypto_mbedtls.c /^int crypto_bignum_inverse(const struct crypto_bignum *a,$/;" f +crypto_bignum_is_one src/crypto/crypto_mbedtls.c /^int crypto_bignum_is_one(const struct crypto_bignum *a)$/;" f +crypto_bignum_is_zero src/crypto/crypto_mbedtls.c /^int crypto_bignum_is_zero(const struct crypto_bignum *a)$/;" f +crypto_bignum_legendre src/crypto/crypto_mbedtls.c /^int crypto_bignum_legendre(const struct crypto_bignum *a,$/;" f +crypto_bignum_mod src/crypto/crypto_mbedtls.c /^int crypto_bignum_mod(const struct crypto_bignum *a,$/;" f +crypto_bignum_mulmod src/crypto/crypto_mbedtls.c /^int crypto_bignum_mulmod(const struct crypto_bignum *a,$/;" f +crypto_bignum_sub src/crypto/crypto_mbedtls.c /^int crypto_bignum_sub(const struct crypto_bignum *a,$/;" f +crypto_bignum_to_bin src/crypto/crypto_mbedtls.c /^int crypto_bignum_to_bin(const struct crypto_bignum *a,$/;" f +crypto_binding src/eap_peer/eap_peap.c /^ enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;$/;" m struct:eap_peap_data typeref:enum:eap_peap_data::__anon7 file: +crypto_binding_used src/eap_peer/eap_peap.c /^ int crypto_binding_used;$/;" m struct:eap_peap_data file: +crypto_cipher src/crypto/crypto_internal-cipher.c /^struct crypto_cipher {$/;" s file: +crypto_cipher_alg include/crypto/crypto.h /^enum crypto_cipher_alg {$/;" g +crypto_cipher_decrypt src/crypto/crypto_internal-cipher.c /^int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,$/;" f +crypto_cipher_deinit src/crypto/crypto_internal-cipher.c /^void crypto_cipher_deinit(struct crypto_cipher *ctx)$/;" f +crypto_cipher_encrypt src/crypto/crypto_internal-cipher.c /^int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,$/;" f +crypto_cipher_init src/crypto/crypto_internal-cipher.c /^struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,$/;" f +crypto_ec src/crypto/crypto_mbedtls.c /^struct crypto_ec {$/;" s file: +crypto_ec_deinit src/crypto/crypto_mbedtls.c /^void crypto_ec_deinit(struct crypto_ec *e)$/;" f +crypto_ec_get_order src/crypto/crypto_mbedtls.c /^const struct crypto_bignum *crypto_ec_get_order(struct crypto_ec *e)$/;" f +crypto_ec_get_prime src/crypto/crypto_mbedtls.c /^const struct crypto_bignum *crypto_ec_get_prime(struct crypto_ec *e)$/;" f +crypto_ec_init src/crypto/crypto_mbedtls.c /^struct crypto_ec *crypto_ec_init(int group)$/;" f +crypto_ec_point_add src/crypto/crypto_mbedtls.c /^int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,$/;" f +crypto_ec_point_cmp src/crypto/crypto_mbedtls.c /^int crypto_ec_point_cmp(const struct crypto_ec *e,$/;" f +crypto_ec_point_compute_y_sqr src/crypto/crypto_mbedtls.c /^crypto_ec_point_compute_y_sqr(struct crypto_ec *e,$/;" f +crypto_ec_point_deinit src/crypto/crypto_mbedtls.c /^void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)$/;" f +crypto_ec_point_from_bin src/crypto/crypto_mbedtls.c /^struct crypto_ec_point *crypto_ec_point_from_bin(struct crypto_ec *e,$/;" f +crypto_ec_point_init src/crypto/crypto_mbedtls.c /^struct crypto_ec_point *crypto_ec_point_init(struct crypto_ec *e)$/;" f +crypto_ec_point_invert src/crypto/crypto_mbedtls.c /^int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p)$/;" f +crypto_ec_point_is_at_infinity src/crypto/crypto_mbedtls.c /^int crypto_ec_point_is_at_infinity(struct crypto_ec *e,$/;" f +crypto_ec_point_is_on_curve src/crypto/crypto_mbedtls.c /^int crypto_ec_point_is_on_curve(struct crypto_ec *e,$/;" f +crypto_ec_point_mul src/crypto/crypto_mbedtls.c /^int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,$/;" f +crypto_ec_point_solve_y_coord src/crypto/crypto_mbedtls.c /^int crypto_ec_point_solve_y_coord(struct crypto_ec *e,$/;" f +crypto_ec_point_to_bin src/crypto/crypto_mbedtls.c /^int crypto_ec_point_to_bin(struct crypto_ec *e,$/;" f +crypto_ec_prime_len src/crypto/crypto_mbedtls.c /^size_t crypto_ec_prime_len(struct crypto_ec *e)$/;" f +crypto_ec_prime_len_bits src/crypto/crypto_mbedtls.c /^size_t crypto_ec_prime_len_bits(struct crypto_ec *e)$/;" f +crypto_get_random src/crypto/crypto_mbedtls.c /^int crypto_get_random(void *buf, size_t len)$/;" f +crypto_global_deinit src/crypto/crypto_internal.c /^void crypto_global_deinit(void)$/;" f +crypto_global_init src/crypto/crypto_internal.c /^int crypto_global_init(void)$/;" f +crypto_hash src/crypto/crypto_internal.c /^struct crypto_hash {$/;" s file: +crypto_hash_alg include/crypto/crypto.h /^enum crypto_hash_alg {$/;" g +crypto_hash_finish src/crypto/crypto_internal.c /^int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)$/;" f +crypto_hash_init src/crypto/crypto_internal.c /^struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,$/;" f +crypto_hash_update src/crypto/crypto_internal.c /^void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)$/;" f +crypto_mod_exp src/crypto/crypto_internal-modexp.c /^crypto_mod_exp(const u8 *base, size_t base_len,$/;" f +crypto_private_key_decrypt_pkcs1_v15 src/crypto/crypto_internal-rsa.c /^int crypto_private_key_decrypt_pkcs1_v15(struct crypto_private_key *key,$/;" f +crypto_private_key_free src/crypto/crypto_internal-rsa.c /^void crypto_private_key_free(struct crypto_private_key *key)$/;" f +crypto_private_key_import src/crypto/crypto_internal-rsa.c /^struct crypto_private_key * crypto_private_key_import(const u8 *key,$/;" f +crypto_private_key_sign_pkcs1 src/crypto/crypto_internal-rsa.c /^int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,$/;" f +crypto_public_key_decrypt_pkcs1 src/crypto/crypto_internal-rsa.c /^int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,$/;" f +crypto_public_key_encrypt_pkcs1_v15 src/crypto/crypto_internal-rsa.c /^int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,$/;" f +crypto_public_key_free src/crypto/crypto_internal-rsa.c /^void crypto_public_key_free(struct crypto_public_key *key)$/;" f +crypto_public_key_from_cert src/crypto/crypto_internal-rsa.c /^struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,$/;" f +crypto_public_key_import src/crypto/crypto_internal-rsa.c /^struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)$/;" f +crypto_rsa_exptmod src/tls/rsa.c /^int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen,$/;" f +crypto_rsa_free src/tls/rsa.c /^void crypto_rsa_free(struct crypto_rsa_key *key)$/;" f +crypto_rsa_get_modulus_len src/tls/rsa.c /^size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key)$/;" f +crypto_rsa_import_private_key src/tls/rsa.c /^crypto_rsa_import_private_key(const u8 *buf, size_t len)$/;" f +crypto_rsa_import_public_key src/tls/rsa.c /^crypto_rsa_import_public_key(const u8 *buf, size_t len)$/;" f +crypto_rsa_key src/tls/rsa.c /^struct crypto_rsa_key {$/;" s file: +crypto_rsa_parse_integer src/tls/rsa.c /^static const u8 * crypto_rsa_parse_integer(const u8 *pos, const u8 *end,$/;" f file: +ctrl_iface_deinit src/ap/hostapd.h /^ void (*ctrl_iface_deinit)(struct hostapd_data *hapd);$/;" m struct:hapd_interfaces +ctrl_iface_init src/ap/hostapd.h /^ int (*ctrl_iface_init)(struct hostapd_data *hapd);$/;" m struct:hapd_interfaces +ctx src/ap/hostapd.h /^ void *ctx;$/;" m struct:hostapd_probereq_cb +ctx src/ap/wpa_auth.h /^ void *ctx;$/;" m struct:wpa_auth_callbacks +ctx_dec src/crypto/crypto_internal-cipher.c /^ void *ctx_dec;$/;" m struct:crypto_cipher::__anon10::__anon12 file: +ctx_dec src/fast_crypto/fast_crypto_internal-cipher.c /^ mbedtls_aes_context ctx_dec;$/;" m struct:fast_crypto_cipher::__anon56::__anon58 file: +ctx_enc src/crypto/crypto_internal-cipher.c /^ void *ctx_enc;$/;" m struct:crypto_cipher::__anon10::__anon12 file: +ctx_enc src/fast_crypto/fast_crypto_internal-cipher.c /^ mbedtls_aes_context ctx_enc;$/;" m struct:fast_crypto_cipher::__anon56::__anon58 file: +curlen src/crypto/sha256-internal.c /^ u32 state[8], curlen;$/;" m struct:sha256_state file: +current_ap src/common/ieee802_11_defs.h /^ u8 current_ap[6];$/;" m struct:ieee80211_mgmt::__anon66::__anon71 +current_identifier src/eap_peer/eap_i.h /^ u8 current_identifier;$/;" m struct:eap_sm +current_identifier src/wps/wps.h /^ u8 current_identifier;$/;" m struct:wps_sm +cw src/common/ieee802_11_defs.h /^ u8 cw; \/* ECWmin, ECWmax (CW = 2^ECW - 1) *\/$/;" m struct:wmm_ac_parameter +d src/tls/rsa.c /^ struct bignum *d; \/* private exponent *\/$/;" m struct:crypto_rsa_key typeref:struct:crypto_rsa_key::bignum file: +da src/common/ieee802_11_defs.h /^ u8 da[6];$/;" m struct:ieee80211_mgmt +data src/eap_peer/eap_config.h /^ const u8 *data;$/;" m struct:wpa_config_blob +data_length src/ap/wpa_auth.h /^ le16 data_length; \/* little endian length of data (44) *\/$/;" m struct:ft_r0kh_r1kh_pull_frame +data_length src/ap/wpa_auth.h /^ le16 data_length; \/* little endian length of data (76) *\/$/;" m struct:ft_r0kh_r1kh_resp_frame +data_length src/ap/wpa_auth.h /^ le16 data_length; \/* little endian length of data (88) *\/$/;" m struct:ft_r0kh_r1kh_push_frame +datarate src/ap/hostapd.h /^ u32 datarate;$/;" m struct:hostapd_frame_info +deauth src/common/ieee802_11_defs.h /^ } STRUCT_PACKED deauth;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon68 +decision src/eap_peer/eap_i.h /^ EapDecision decision;$/;" m struct:eap_method_ret +default_len src/ap/ap_config.h /^ size_t default_len; \/* key length used for dynamic key generation *\/$/;" m struct:hostapd_wep_keys +deinit src/eap_peer/eap_i.h /^ void (*deinit)(struct eap_sm *sm, void *priv);$/;" m struct:eap_method +deinit src/utils/ext_password_i.h /^ void (*deinit)(void *ctx);$/;" m struct:ext_password_backend +deinit_for_reauth src/eap_peer/eap_i.h /^ void (*deinit_for_reauth)(struct eap_sm *sm, void *priv);$/;" m struct:eap_method +delay_bound src/common/ieee802_11_defs.h /^ le32 delay_bound;$/;" m struct:wmm_tspec_element +depth src/tls/tls.h /^ int depth;$/;" m struct:tls_event_data::__anon34 +depth src/tls/tls.h /^ int depth;$/;" m struct:tls_event_data::__anon35 +des src/crypto/crypto_internal-cipher.c /^ } des;$/;" m union:crypto_cipher::__anon10 typeref:struct:crypto_cipher::__anon10::__anon14 file: +des src/fast_crypto/fast_crypto_internal-cipher.c /^ } des;$/;" m union:fast_crypto_cipher::__anon56 typeref:struct:fast_crypto_cipher::__anon56::__anon60 file: +des3 src/crypto/crypto_internal-cipher.c /^ } des3;$/;" m union:crypto_cipher::__anon10 typeref:struct:crypto_cipher::__anon10::__anon13 file: +des3 src/fast_crypto/fast_crypto_internal-cipher.c /^ } des3;$/;" m union:fast_crypto_cipher::__anon56 typeref:struct:fast_crypto_cipher::__anon56::__anon59 file: +des3_key_s src/crypto/des_i.h /^struct des3_key_s {$/;" s +des_encrypt src/crypto/des-internal.c /^void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)$/;" f +descr_count src/common/wpa_common.h /^ u8 descr_count;$/;" m struct:rsn_rdie +description src/tls/tls.h /^ const char *description;$/;" m struct:tls_event_data::__anon36 +desfunc src/crypto/des-internal.c /^static void desfunc(u32 *block, const u32 *keys)$/;" f file: +deskey src/crypto/des-internal.c /^static void deskey(const u8 *key, int decrypt, u32 *keyout)$/;" f file: +dev src/wps/wps.h /^ struct wps_device_data dev;$/;" m struct:wps_context typeref:struct:wps_context::wps_device_data +dev src/wps/wps.h /^ struct wps_device_data *dev;$/;" m struct:wps_sm typeref:struct:wps_sm::wps_device_data +dev src/wps/wps_registrar.c /^ struct wps_device_data dev;$/;" m struct:wps_registrar_device typeref:struct:wps_registrar_device::wps_device_data file: +dev_name src/wps/wps.h /^ const char *dev_name;$/;" m struct:wps_event_data::wps_event_er_enrollee +dev_name src/wps/wps.h /^ const u8 *dev_name;$/;" m struct:wps_event_data::wps_event_m2d +dev_name src/wps/wps_attr_parse.h /^ const u8 *dev_name;$/;" m struct:wps_parse_attr +dev_name_len src/wps/wps.h /^ size_t dev_name_len;$/;" m struct:wps_event_data::wps_event_m2d +dev_name_len src/wps/wps_attr_parse.h /^ size_t dev_name_len;$/;" m struct:wps_parse_attr +dev_passwd_id src/wps/wps.h /^ u16 dev_passwd_id;$/;" m struct:wps_event_data::wps_event_er_enrollee +dev_passwd_id src/wps/wps.h /^ u16 dev_passwd_id;$/;" m struct:wps_event_data::wps_event_er_set_selected_registrar +dev_password src/wps/wps_i.h /^ u8 *dev_password;$/;" m struct:wps_data +dev_password_id src/wps/wps.h /^ u16 dev_password_id;$/;" m struct:wps_event_data::wps_event_m2d +dev_password_id src/wps/wps_attr_parse.h /^ const u8 *dev_password_id; \/* 2 octets *\/$/;" m struct:wps_parse_attr +dev_password_len src/wps/wps_i.h /^ size_t dev_password_len;$/;" m struct:wps_data +dev_pw src/wps/wps_registrar.c /^ u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN];$/;" m struct:wps_nfc_pw_token file: +dev_pw_id src/wps/wps.h /^ u16 dev_pw_id;$/;" m struct:wps_config +dev_pw_id src/wps/wps_i.h /^ u16 dev_pw_id;$/;" m struct:wps_data +dev_pw_len src/wps/wps_registrar.c /^ size_t dev_pw_len;$/;" m struct:wps_nfc_pw_token file: +device_name include/esp_supplicant/esp_wps.h /^ char device_name[WPS_MAX_DEVICE_NAME_LEN]; \/*!< Device name, null-terminated string. The default device name is used if the string is empty *\/$/;" m struct:__anon89 +device_name src/ap/ap_config.h /^ char *device_name;$/;" m struct:hostapd_bss_config +device_name src/wps/wps.h /^ char *device_name;$/;" m struct:wps_device_data +device_type src/ap/ap_config.h /^ u8 device_type[WPS_DEV_TYPE_LEN];$/;" m struct:hostapd_bss_config +devices src/wps/wps_registrar.c /^ struct wps_registrar_device *devices;$/;" m struct:wps_registrar typeref:struct:wps_registrar::wps_registrar_device file: +dh5_derive_shared src/crypto/dh_group5.c /^dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,$/;" f +dh5_free src/crypto/dh_group5.c /^dh5_free(void *ctx)$/;" f +dh5_init src/crypto/dh_group5.c /^dh5_init(struct wpabuf **priv, struct wpabuf **publ)$/;" f +dh_blob src/tls/tls.h /^ const u8 *dh_blob;$/;" m struct:tls_connection_params +dh_blob_len src/tls/tls.h /^ size_t dh_blob_len;$/;" m struct:tls_connection_params +dh_ctx src/wps/wps.h /^ void *dh_ctx;$/;" m struct:wps_context +dh_ctx src/wps/wps_i.h /^ void *dh_ctx;$/;" m struct:wps_data +dh_derive_shared src/crypto/dh_groups.c /^dh_derive_shared(const struct wpabuf *peer_public,$/;" f +dh_file src/tls/tls.h /^ const char *dh_file;$/;" m struct:tls_connection_params +dh_g src/tls/tlsv1_client_i.h /^ u8 *dh_g;$/;" m struct:tlsv1_client +dh_g src/tls/tlsv1_cred.h /^ u8 *dh_g; \/* generator *\/$/;" m struct:tlsv1_credentials +dh_g_len src/tls/tlsv1_client_i.h /^ size_t dh_g_len;$/;" m struct:tlsv1_client +dh_g_len src/tls/tlsv1_cred.h /^ size_t dh_g_len;$/;" m struct:tlsv1_credentials +dh_group include/crypto/dh_groups.h /^struct dh_group {$/;" s +dh_group14_generator src/crypto/dh_groups.c /^static const u8 dh_group14_generator[1] = { 0x02 };$/;" v file: +dh_group14_prime src/crypto/dh_groups.c /^static const u8 dh_group14_prime[256] = {$/;" v file: +dh_group15_generator src/crypto/dh_groups.c /^static const u8 dh_group15_generator[1] = { 0x02 };$/;" v file: +dh_group15_prime src/crypto/dh_groups.c /^static const u8 dh_group15_prime[384] = {$/;" v file: +dh_group16_generator src/crypto/dh_groups.c /^static const u8 dh_group16_generator[1] = { 0x02 };$/;" v file: +dh_group16_prime src/crypto/dh_groups.c /^static const u8 dh_group16_prime[512] = {$/;" v file: +dh_group17_generator src/crypto/dh_groups.c /^static const u8 dh_group17_generator[1] = { 0x02 };$/;" v file: +dh_group17_prime src/crypto/dh_groups.c /^static const u8 dh_group17_prime[768] = {$/;" v file: +dh_group18_generator src/crypto/dh_groups.c /^static const u8 dh_group18_generator[1] = { 0x02 };$/;" v file: +dh_group18_prime src/crypto/dh_groups.c /^static const u8 dh_group18_prime[1024] = {$/;" v file: +dh_group1_generator src/crypto/dh_groups.c /^static const u8 dh_group1_generator[1] = { 0x02 };$/;" v file: +dh_group1_prime src/crypto/dh_groups.c /^static const u8 dh_group1_prime[96] = {$/;" v file: +dh_group2_generator src/crypto/dh_groups.c /^static const u8 dh_group2_generator[1] = { 0x02 };$/;" v file: +dh_group2_prime src/crypto/dh_groups.c /^static const u8 dh_group2_prime[128] = {$/;" v file: +dh_group5_generator src/crypto/dh_groups.c /^static const u8 dh_group5_generator[1] = { 0x02 };$/;" v file: +dh_group5_prime src/crypto/dh_groups.c /^static const u8 dh_group5_prime[192] = {$/;" v file: +dh_groups src/crypto/dh_groups.c /^static struct dh_group dh_groups[] = {$/;" v typeref:struct:dh_group file: +dh_groups_get src/crypto/dh_groups.c /^dh_groups_get(int id)$/;" f +dh_init src/crypto/dh_groups.c /^dh_init(const struct dh_group *dh, struct wpabuf **priv)$/;" f +dh_p src/tls/tlsv1_client_i.h /^ u8 *dh_p;$/;" m struct:tlsv1_client +dh_p src/tls/tlsv1_cred.h /^ u8 *dh_p; \/* prime *\/$/;" m struct:tlsv1_credentials +dh_p_len src/tls/tlsv1_client_i.h /^ size_t dh_p_len;$/;" m struct:tlsv1_client +dh_p_len src/tls/tlsv1_cred.h /^ size_t dh_p_len;$/;" m struct:tlsv1_credentials +dh_privkey src/wps/wps.h /^ struct wpabuf *dh_privkey;$/;" m struct:wps_context typeref:struct:wps_context::wpabuf +dh_privkey src/wps/wps_i.h /^ struct wpabuf *dh_privkey;$/;" m struct:wps_data typeref:struct:wps_data::wpabuf +dh_pubkey src/wps/wps.h /^ struct wpabuf *dh_pubkey;$/;" m struct:wps_context typeref:struct:wps_context::wpabuf +dh_pubkey_e src/wps/wps_i.h /^ struct wpabuf *dh_pubkey_e;$/;" m struct:wps_data typeref:struct:wps_data::wpabuf +dh_pubkey_r src/wps/wps_i.h /^ struct wpabuf *dh_pubkey_r;$/;" m struct:wps_data typeref:struct:wps_data::wpabuf +dh_secret src/tls/tlsv1_server_i.h /^ u8 *dh_secret;$/;" m struct:tlsv1_server +dh_secret_len src/tls/tlsv1_server_i.h /^ size_t dh_secret_len;$/;" m struct:tlsv1_server +dh_ys src/tls/tlsv1_client_i.h /^ u8 *dh_ys;$/;" m struct:tlsv1_client +dh_ys_len src/tls/tlsv1_client_i.h /^ size_t dh_ys_len;$/;" m struct:tlsv1_client +dialog_token src/common/ieee802_11_defs.h /^ u8 dialog_token;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon78 +dis_ap_list src/wps/wps.h /^ struct discard_ap_list_t dis_ap_list[WPS_MAX_DIS_AP_NUM];$/;" m struct:wps_sm typeref:struct:wps_sm::discard_ap_list_t +disable_auto_conf src/wps/wps.h /^ int disable_auto_conf;$/;" m struct:wps_registrar_config +disable_auto_conf src/wps/wps_registrar.c /^ int disable_auto_conf;$/;" m struct:wps_registrar file: +disable_dgaf src/ap/ap_config.h /^ int disable_dgaf;$/;" m struct:hostapd_bss_config +disable_gtk src/ap/wpa_auth.h /^ int disable_gtk;$/;" m struct:wpa_auth_config +disable_pmksa_caching src/ap/wpa_auth.h /^ int disable_pmksa_caching;$/;" m struct:wpa_auth_config +disable_time_checks src/tls/tlsv1_client_i.h /^ unsigned int disable_time_checks:1;$/;" m struct:tlsv1_client +disassoc src/common/ieee802_11_defs.h /^ } STRUCT_PACKED disassoc;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon72 +discard_ap_cnt src/wps/wps.h /^ u8 discard_ap_cnt;$/;" m struct:wps_sm +discard_ap_list_t src/wps/wps.h /^struct discard_ap_list_t{$/;" s +disconnect src/ap/wpa_auth.h /^ void (*disconnect)(void *ctx, const u8 *addr, u16 reason);$/;" m struct:wpa_auth_callbacks +discover_ssid_cnt src/wps/wps.h /^ u8 discover_ssid_cnt;$/;" m struct:wps_sm +dk src/crypto/crypto_internal-cipher.c /^ u32 dk[32];$/;" m struct:crypto_cipher::__anon10::__anon14 file: +dk src/crypto/des_i.h /^ u32 dk[3][32];$/;" m struct:des3_key_s +dk src/fast_crypto/fast_crypto_internal-cipher.c /^ uint32_t dk[32];$/;" m struct:fast_crypto_cipher::__anon56::__anon60 file: +dl_list src/utils/list.h /^struct dl_list {$/;" s +dl_list_add src/utils/list.h /^static inline void dl_list_add(struct dl_list *list, struct dl_list *item)$/;" f +dl_list_add_tail src/utils/list.h /^static inline void dl_list_add_tail(struct dl_list *list, struct dl_list *item)$/;" f +dl_list_del src/utils/list.h /^static inline void dl_list_del(struct dl_list *item)$/;" f +dl_list_empty src/utils/list.h /^static inline int dl_list_empty(struct dl_list *list)$/;" f +dl_list_entry src/utils/list.h 73;" d +dl_list_first src/utils/list.h 76;" d +dl_list_for_each src/utils/list.h 84;" d +dl_list_for_each_reverse src/utils/list.h 95;" d +dl_list_for_each_safe src/utils/list.h 89;" d +dl_list_init src/utils/list.h /^static inline void dl_list_init(struct dl_list *list)$/;" f +dl_list_last src/utils/list.h 80;" d +dl_list_len src/utils/list.h /^static inline unsigned int dl_list_len(struct dl_list *list)$/;" f +dmp1 src/tls/rsa.c /^ struct bignum *dmp1; \/* d mod (p - 1); CRT exponent *\/$/;" m struct:crypto_rsa_key typeref:struct:crypto_rsa_key::bignum file: +dmq1 src/tls/rsa.c /^ struct bignum *dmq1; \/* d mod (q - 1); CRT exponent *\/$/;" m struct:crypto_rsa_key typeref:struct:crypto_rsa_key::bignum file: +dns src/tls/x509v3.h /^ char *dns; \/* dNSName *\/$/;" m struct:x509_name +dot11RSNAConfigGroupUpdateCount src/ap/wpa_auth.c /^static const u32 dot11RSNAConfigGroupUpdateCount = 4;$/;" v file: +dot11RSNAConfigPairwiseUpdateCount src/ap/wpa_auth.c /^static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;$/;" v file: +dot1x_enabled src/wps/wps_attr_parse.h /^ const u8 *dot1x_enabled; \/* 1 octet (Bool) *\/$/;" m struct:wps_parse_attr +dp src/crypto/libtommath.h /^ mp_digit *dp;$/;" m struct:__anon8 +dp src/tls/libtommath.h /^ mp_digit *dp;$/;" m struct:__anon40 +driver src/ap/ap_config.h /^ const struct wpa_driver_ops *driver;$/;" m struct:hostapd_config typeref:struct:hostapd_config::wpa_driver_ops +driver_init src/ap/hostapd.h /^ int (*driver_init)(struct hostapd_iface *iface);$/;" m struct:hapd_interfaces +dtim_period src/ap/ap_config.h /^ int dtim_period;$/;" m struct:hostapd_bss_config +dualband src/wps/wps.h /^ int dualband;$/;" m struct:wps_registrar_config +dualband src/wps/wps_registrar.c /^ int dualband;$/;" m struct:wps_registrar file: +dump_msk_file src/ap/ap_config.h /^ char *dump_msk_file;$/;" m struct:hostapd_bss_config +dup_binstr src/utils/common.c /^char * dup_binstr(const void *src, size_t len)$/;" f +duration src/common/ieee802_11_defs.h /^ le16 duration;$/;" m struct:ieee80211_mgmt +duration_id src/common/ieee802_11_defs.h /^ le16 duration_id;$/;" m struct:ieee80211_hdr +e src/tls/rsa.c /^ struct bignum *e; \/* public exponent *\/$/;" m struct:crypto_rsa_key typeref:struct:crypto_rsa_key::bignum file: +e_hash1 src/wps/wps_attr_parse.h /^ const u8 *e_hash1; \/* WPS_HASH_LEN (32) octets *\/$/;" m struct:wps_parse_attr +e_hash2 src/wps/wps_attr_parse.h /^ const u8 *e_hash2; \/* WPS_HASH_LEN (32) octets *\/$/;" m struct:wps_parse_attr +e_snonce1 src/wps/wps_attr_parse.h /^ const u8 *e_snonce1; \/* WPS_SECRET_NONCE_LEN (16) octets *\/$/;" m struct:wps_parse_attr +e_snonce2 src/wps/wps_attr_parse.h /^ const u8 *e_snonce2; \/* WPS_SECRET_NONCE_LEN (16) octets *\/$/;" m struct:wps_parse_attr +eap src/eap_peer/eap_tls_common.h /^ struct eap_sm *eap;$/;" m struct:eap_ssl_data typeref:struct:eap_ssl_data::eap_sm +eapKeyData src/eap_peer/eap_i.h /^ u8 *eapKeyData;$/;" m struct:eap_sm +eapKeyDataLen src/eap_peer/eap_i.h /^ size_t eapKeyDataLen;$/;" m struct:eap_sm +eap_allowed_phase2_type src/eap_peer/eap.c /^eap_allowed_phase2_type(int vendor, int type)$/;" f file: +eap_deinit_prev_method src/eap_peer/eap.c /^void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)$/;" f +eap_expand src/eap_peer/eap_defs.h /^struct eap_expand {$/;" s +eap_get_config src/eap_peer/eap.c /^struct eap_peer_config * eap_get_config(struct eap_sm *sm)$/;" f +eap_get_config_blob src/eap_peer/eap.c /^const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm,$/;" f +eap_get_config_identity src/eap_peer/eap.c /^const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)$/;" f +eap_get_config_new_password src/eap_peer/eap.c /^const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len)$/;" f +eap_get_config_password src/eap_peer/eap.c /^const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)$/;" f +eap_get_config_password2 src/eap_peer/eap.c /^const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)$/;" f +eap_get_id src/eap_peer/eap_common.c /^u8 eap_get_id(const struct wpabuf *msg)$/;" f +eap_get_phase2_type src/eap_peer/eap.c /^u32 eap_get_phase2_type(const char *name, int *vendor)$/;" f +eap_get_phase2_types src/eap_peer/eap.c /^struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,$/;" f +eap_get_type src/eap_peer/eap_common.c /^EapType eap_get_type(const struct wpabuf *msg)$/;" f +eap_hdr src/eap_peer/eap_defs.h /^struct eap_hdr {$/;" s +eap_hdr_len_valid src/eap_peer/eap_common.c /^int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload)$/;" f +eap_hdr_validate src/eap_peer/eap_common.c /^const u8 * eap_hdr_validate(int vendor, EapType eap_type,$/;" f +eap_identity src/wps/wps_attr_parse.h /^ const u8 *eap_identity; \/* <= 64 octets *\/$/;" m struct:wps_parse_attr +eap_identity_len src/wps/wps_attr_parse.h /^ size_t eap_identity_len;$/;" m struct:wps_parse_attr +eap_len src/eap_peer/eap_ttls.c /^ size_t eap_len;$/;" m struct:ttls_parse_avp file: +eap_method src/eap_peer/eap_i.h /^struct eap_method {$/;" s +eap_method_priv src/eap_peer/eap_i.h /^ void *eap_method_priv;$/;" m struct:eap_sm +eap_method_ret src/eap_peer/eap_i.h /^struct eap_method_ret {$/;" s +eap_method_type src/eap_peer/eap.h /^struct eap_method_type {$/;" s +eap_methods src/eap_peer/eap.c /^static struct eap_method *eap_methods = NULL;$/;" v typeref:struct:eap_method file: +eap_methods src/eap_peer/eap_config.h /^ struct eap_method_type *eap_methods;$/;" m struct:eap_peer_config typeref:struct:eap_peer_config::eap_method_type +eap_mschapv2_challenge src/eap_peer/eap_mschapv2.c /^eap_mschapv2_challenge($/;" f file: +eap_mschapv2_challenge_reply src/eap_peer/eap_mschapv2.c /^eap_mschapv2_challenge_reply($/;" f file: +eap_mschapv2_change_password src/eap_peer/eap_mschapv2.c /^eap_mschapv2_change_password($/;" f file: +eap_mschapv2_check_config src/eap_peer/eap_mschapv2.c /^eap_mschapv2_check_config(struct eap_sm *sm)$/;" f file: +eap_mschapv2_check_mslen src/eap_peer/eap_mschapv2.c /^eap_mschapv2_check_mslen(struct eap_sm *sm, size_t len,$/;" f file: +eap_mschapv2_copy_challenge src/eap_peer/eap_mschapv2.c /^eap_mschapv2_copy_challenge(struct eap_mschapv2_data *data,$/;" f file: +eap_mschapv2_data src/eap_peer/eap_mschapv2.c /^struct eap_mschapv2_data {$/;" s file: +eap_mschapv2_deinit src/eap_peer/eap_mschapv2.c /^eap_mschapv2_deinit(struct eap_sm *sm, void *priv)$/;" f file: +eap_mschapv2_failure src/eap_peer/eap_mschapv2.c /^eap_mschapv2_failure(struct eap_sm *sm,$/;" f file: +eap_mschapv2_failure_txt src/eap_peer/eap_mschapv2.c /^eap_mschapv2_failure_txt(struct eap_sm *sm,$/;" f file: +eap_mschapv2_getKey src/eap_peer/eap_mschapv2.c /^eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)$/;" f file: +eap_mschapv2_hdr src/eap_peer/eap_mschapv2.c /^struct eap_mschapv2_hdr {$/;" s file: +eap_mschapv2_init src/eap_peer/eap_mschapv2.c /^eap_mschapv2_init(struct eap_sm *sm)$/;" f file: +eap_mschapv2_isKeyAvailable src/eap_peer/eap_mschapv2.c /^eap_mschapv2_isKeyAvailable(struct eap_sm *sm, void *priv)$/;" f file: +eap_mschapv2_password_changed src/eap_peer/eap_mschapv2.c /^eap_mschapv2_password_changed(struct eap_sm *sm,$/;" f file: +eap_mschapv2_process src/eap_peer/eap_mschapv2.c /^eap_mschapv2_process(struct eap_sm *sm, void *priv,$/;" f file: +eap_mschapv2_success src/eap_peer/eap_mschapv2.c /^eap_mschapv2_success(struct eap_sm *sm,$/;" f file: +eap_msg_alloc src/eap_peer/eap_common.c /^struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,$/;" f +eap_peap_data src/eap_peer/eap_peap.c /^struct eap_peap_data {$/;" s file: +eap_peap_decrypt src/eap_peer/eap_peap.c /^eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,$/;" f file: +eap_peap_deinit src/eap_peer/eap_peap.c /^eap_peap_deinit(struct eap_sm *sm, void *priv)$/;" f file: +eap_peap_deinit_for_reauth src/eap_peer/eap_peap.c /^eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)$/;" f file: +eap_peap_derive_cmk src/eap_peer/eap_peap.c /^eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)$/;" f file: +eap_peap_getKey src/eap_peer/eap_peap.c /^eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)$/;" f file: +eap_peap_get_isk src/eap_peer/eap_peap.c /^eap_peap_get_isk(struct eap_sm *sm, struct eap_peap_data *data,$/;" f file: +eap_peap_get_session_id src/eap_peer/eap_peap.c /^eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)$/;" f file: +eap_peap_get_status src/eap_peer/eap_peap.c /^eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf,$/;" f file: +eap_peap_has_reauth_data src/eap_peer/eap_peap.c /^eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)$/;" f file: +eap_peap_init src/eap_peer/eap_peap.c /^eap_peap_init(struct eap_sm *sm)$/;" f file: +eap_peap_init_for_reauth src/eap_peer/eap_peap.c /^eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)$/;" f file: +eap_peap_isKeyAvailable src/eap_peer/eap_peap.c /^eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv)$/;" f file: +eap_peap_parse_phase1 src/eap_peer/eap_peap.c /^eap_peap_parse_phase1(struct eap_peap_data *data,$/;" f file: +eap_peap_phase2_request src/eap_peer/eap_peap.c /^static int eap_peap_phase2_request(struct eap_sm *sm,$/;" f file: +eap_peap_process src/eap_peer/eap_peap.c /^eap_peap_process(struct eap_sm *sm, void *priv,$/;" f file: +eap_peapv2_tlv_eap_payload src/eap_peer/eap_peap.c /^eap_peapv2_tlv_eap_payload(struct wpabuf *buf)$/;" f file: +eap_peer_blob_deinit src/eap_peer/eap.c /^void eap_peer_blob_deinit(struct eap_sm *sm)$/;" f +eap_peer_blob_init src/eap_peer/eap.c /^int eap_peer_blob_init(struct eap_sm *sm)$/;" f +eap_peer_config src/eap_peer/eap_config.h /^struct eap_peer_config {$/;" s +eap_peer_config_deinit src/eap_peer/eap.c /^void eap_peer_config_deinit(struct eap_sm *sm)$/;" f +eap_peer_config_init src/eap_peer/eap.c /^int eap_peer_config_init($/;" f +eap_peer_get_eap_method src/eap_peer/eap.c /^const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method)$/;" f +eap_peer_get_methods src/eap_peer/eap.c /^const struct eap_method * eap_peer_get_methods(size_t *count)$/;" f +eap_peer_get_type src/eap_peer/eap.c /^EapType eap_peer_get_type(const char *name, int *vendor)$/;" f +eap_peer_method_alloc src/eap_peer/eap.c /^struct eap_method * eap_peer_method_alloc(int vendor, EapType method,$/;" f +eap_peer_method_free src/eap_peer/eap.c /^void eap_peer_method_free(struct eap_method *method)$/;" f +eap_peer_method_register src/eap_peer/eap.c /^int eap_peer_method_register(struct eap_method *method)$/;" f +eap_peer_mschapv2_register src/eap_peer/eap_mschapv2.c /^eap_peer_mschapv2_register(void)$/;" f +eap_peer_peap_register src/eap_peer/eap_peap.c /^eap_peer_peap_register(void)$/;" f +eap_peer_register_methods src/eap_peer/eap.c /^int eap_peer_register_methods(void)$/;" f +eap_peer_select_phase2_methods src/eap_peer/eap_tls_common.c /^int eap_peer_select_phase2_methods(struct eap_peer_config *config,$/;" f +eap_peer_sm_deinit src/esp_supplicant/esp_wpa_enterprise.c /^static void eap_peer_sm_deinit(void)$/;" f file: +eap_peer_sm_init src/esp_supplicant/esp_wpa_enterprise.c /^static int eap_peer_sm_init(void)$/;" f file: +eap_peer_tls_build_ack src/eap_peer/eap_tls_common.c /^struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,$/;" f +eap_peer_tls_data_reassemble src/eap_peer/eap_tls_common.c /^static const struct wpabuf * eap_peer_tls_data_reassemble($/;" f file: +eap_peer_tls_decrypt src/eap_peer/eap_tls_common.c /^int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data,$/;" f +eap_peer_tls_derive_key src/eap_peer/eap_tls_common.c /^u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,$/;" f +eap_peer_tls_derive_session_id src/eap_peer/eap_tls_common.c /^u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,$/;" f +eap_peer_tls_encrypt src/eap_peer/eap_tls_common.c /^int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,$/;" f +eap_peer_tls_phase2_nak src/eap_peer/eap_tls_common.c /^int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types,$/;" f +eap_peer_tls_process_helper src/eap_peer/eap_tls_common.c /^int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,$/;" f +eap_peer_tls_process_init src/eap_peer/eap_tls_common.c /^const u8 * eap_peer_tls_process_init(struct eap_sm *sm,$/;" f +eap_peer_tls_reassemble_fragment src/eap_peer/eap_tls_common.c /^static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data,$/;" f file: +eap_peer_tls_reauth_init src/eap_peer/eap_tls_common.c /^int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data)$/;" f +eap_peer_tls_register src/eap_peer/eap_tls.c /^int eap_peer_tls_register(void)$/;" f +eap_peer_tls_reset_input src/eap_peer/eap_tls_common.c /^void eap_peer_tls_reset_input(struct eap_ssl_data *data)$/;" f +eap_peer_tls_reset_output src/eap_peer/eap_tls_common.c /^void eap_peer_tls_reset_output(struct eap_ssl_data *data)$/;" f +eap_peer_tls_ssl_deinit src/eap_peer/eap_tls_common.c /^void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)$/;" f +eap_peer_tls_ssl_init src/eap_peer/eap_tls_common.c /^int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,$/;" f +eap_peer_tls_status src/eap_peer/eap_tls_common.c /^int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data,$/;" f +eap_peer_ttls_register src/eap_peer/eap_ttls.c /^int eap_peer_ttls_register(void)$/;" f +eap_peer_unregister_methods src/eap_peer/eap.c /^void eap_peer_unregister_methods(void)$/;" f +eap_sm src/eap_peer/eap_i.h /^struct eap_sm {$/;" s +eap_sm_abort src/eap_peer/eap.c /^void eap_sm_abort(struct eap_sm *sm)$/;" f +eap_sm_build_identity_resp src/eap_peer/eap.c /^struct wpabuf * eap_sm_build_identity_resp(struct eap_sm *sm, u8 id, int encrypted)$/;" f +eap_sm_build_nak src/eap_peer/eap.c /^struct wpabuf * eap_sm_build_nak(struct eap_sm *sm, EapType type, u8 id)$/;" f +eap_sm_process_request src/esp_supplicant/esp_wpa_enterprise.c /^int eap_sm_process_request(struct eap_sm *sm, struct wpabuf *reqData)$/;" f +eap_sm_send_eapol src/esp_supplicant/esp_wpa_enterprise.c /^int eap_sm_send_eapol(struct eap_sm *sm, struct wpabuf *resp)$/;" f +eap_ssl_data src/eap_peer/eap_tls_common.h /^struct eap_ssl_data {$/;" s +eap_tls_check_blob src/eap_peer/eap_tls_common.c /^static int eap_tls_check_blob(struct eap_sm *sm, const char **name,$/;" f file: +eap_tls_data src/eap_peer/eap_tls.c /^struct eap_tls_data {$/;" s file: +eap_tls_deinit src/eap_peer/eap_tls.c /^static void eap_tls_deinit(struct eap_sm *sm, void *priv)$/;" f file: +eap_tls_failure src/eap_peer/eap_tls.c /^static struct wpabuf * eap_tls_failure(struct eap_sm *sm,$/;" f file: +eap_tls_getKey src/eap_peer/eap_tls.c /^static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)$/;" f file: +eap_tls_init src/eap_peer/eap_tls.c /^static void * eap_tls_init(struct eap_sm *sm)$/;" f file: +eap_tls_init_connection src/eap_peer/eap_tls_common.c /^static int eap_tls_init_connection(struct eap_sm *sm,$/;" f file: +eap_tls_isKeyAvailable src/eap_peer/eap_tls.c /^static bool eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv)$/;" f file: +eap_tls_msg_alloc src/eap_peer/eap_tls_common.c /^static struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,$/;" f file: +eap_tls_params_flags src/eap_peer/eap_tls_common.c /^static void eap_tls_params_flags(struct tls_connection_params *params,$/;" f file: +eap_tls_params_from_conf src/eap_peer/eap_tls_common.c /^static int eap_tls_params_from_conf(struct eap_sm *sm,$/;" f file: +eap_tls_params_from_conf1 src/eap_peer/eap_tls_common.c /^static void eap_tls_params_from_conf1(struct tls_connection_params *params,$/;" f file: +eap_tls_process src/eap_peer/eap_tls.c /^static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,$/;" f file: +eap_tls_process_input src/eap_peer/eap_tls_common.c /^static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data,$/;" f file: +eap_tls_process_output src/eap_peer/eap_tls_common.c /^static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type,$/;" f file: +eap_tls_success src/eap_peer/eap_tls.c /^static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,$/;" f file: +eap_tlv_add_cryptobinding src/eap_peer/eap_peap.c /^eap_tlv_add_cryptobinding(struct eap_sm *sm,$/;" f file: +eap_tlv_build_nak src/eap_peer/eap_peap.c /^eap_tlv_build_nak(int id, u16 nak_type)$/;" f file: +eap_tlv_build_result src/eap_peer/eap_peap.c /^eap_tlv_build_result(struct eap_sm *sm,$/;" f file: +eap_tlv_crypto_binding_tlv src/eap_peer/eap_tlv_common.h /^struct eap_tlv_crypto_binding_tlv {$/;" s +eap_tlv_hdr src/eap_peer/eap_tlv_common.h /^struct eap_tlv_hdr {$/;" s +eap_tlv_intermediate_result_tlv src/eap_peer/eap_tlv_common.h /^struct eap_tlv_intermediate_result_tlv {$/;" s +eap_tlv_nak_tlv src/eap_peer/eap_tlv_common.h /^struct eap_tlv_nak_tlv {$/;" s +eap_tlv_pac_ack_tlv src/eap_peer/eap_tlv_common.h /^struct eap_tlv_pac_ack_tlv {$/;" s +eap_tlv_pac_type_tlv src/eap_peer/eap_tlv_common.h /^struct eap_tlv_pac_type_tlv {$/;" s +eap_tlv_process src/eap_peer/eap_peap.c /^eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data,$/;" f file: +eap_tlv_request_action_tlv src/eap_peer/eap_tlv_common.h /^struct eap_tlv_request_action_tlv {$/;" s +eap_tlv_result_tlv src/eap_peer/eap_tlv_common.h /^struct eap_tlv_result_tlv {$/;" s +eap_tlv_validate_cryptobinding src/eap_peer/eap_peap.c /^eap_tlv_validate_cryptobinding(struct eap_sm *sm,$/;" f file: +eap_ttls_avp_add src/eap_peer/eap_ttls.c /^static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code,$/;" f file: +eap_ttls_avp_hdr src/eap_peer/eap_ttls.c /^static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id,$/;" f file: +eap_ttls_check_auth_status src/eap_peer/eap_ttls.c /^static void eap_ttls_check_auth_status(struct eap_sm *sm, $/;" f file: +eap_ttls_data src/eap_peer/eap_ttls.c /^struct eap_ttls_data {$/;" s file: +eap_ttls_decrypt src/eap_peer/eap_ttls.c /^static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,$/;" f file: +eap_ttls_deinit src/eap_peer/eap_ttls.c /^static void eap_ttls_deinit(struct eap_sm *sm, void *priv)$/;" f file: +eap_ttls_deinit_for_reauth src/eap_peer/eap_ttls.c /^static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv)$/;" f file: +eap_ttls_encrypt_response src/eap_peer/eap_ttls.c /^static int eap_ttls_encrypt_response(struct eap_sm *sm,$/;" f file: +eap_ttls_fake_identity_request src/eap_peer/eap_ttls.c /^static u8 * eap_ttls_fake_identity_request(void)$/;" f file: +eap_ttls_getKey src/eap_peer/eap_ttls.c /^static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)$/;" f file: +eap_ttls_get_session_id src/eap_peer/eap_ttls.c /^static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)$/;" f file: +eap_ttls_get_status src/eap_peer/eap_ttls.c /^static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf,$/;" f file: +eap_ttls_has_reauth_data src/eap_peer/eap_ttls.c /^static bool eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv)$/;" f file: +eap_ttls_implicit_challenge src/eap_peer/eap_ttls.c /^static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,$/;" f file: +eap_ttls_implicit_identity_request src/eap_peer/eap_ttls.c /^static int eap_ttls_implicit_identity_request(struct eap_sm *sm,$/;" f file: +eap_ttls_init src/eap_peer/eap_ttls.c /^static void * eap_ttls_init(struct eap_sm *sm)$/;" f file: +eap_ttls_init_for_reauth src/eap_peer/eap_ttls.c /^static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv)$/;" f file: +eap_ttls_isKeyAvailable src/eap_peer/eap_ttls.c /^static bool eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv)$/;" f file: +eap_ttls_parse_attr_eap src/eap_peer/eap_ttls.c /^static int eap_ttls_parse_attr_eap(const u8 *dpos, size_t dlen,$/;" f file: +eap_ttls_parse_avp src/eap_peer/eap_ttls.c /^static int eap_ttls_parse_avp(u8 *pos, size_t left,$/;" f file: +eap_ttls_parse_avps src/eap_peer/eap_ttls.c /^static int eap_ttls_parse_avps(struct wpabuf *in_decrypted,$/;" f file: +eap_ttls_phase2_eap_deinit src/eap_peer/eap_ttls.c /^static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm,$/;" f file: +eap_ttls_phase2_request src/eap_peer/eap_ttls.c /^static int eap_ttls_phase2_request(struct eap_sm *sm,$/;" f file: +eap_ttls_phase2_request_mschapv2 src/eap_peer/eap_ttls.c /^static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,$/;" f file: +eap_ttls_phase2_start src/eap_peer/eap_ttls.c /^static int eap_ttls_phase2_start(struct eap_sm *sm, struct eap_ttls_data *data,$/;" f file: +eap_ttls_process src/eap_peer/eap_ttls.c /^static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv,$/;" f file: +eap_ttls_process_decrypted src/eap_peer/eap_ttls.c /^static int eap_ttls_process_decrypted(struct eap_sm *sm,$/;" f file: +eap_ttls_process_handshake src/eap_peer/eap_ttls.c /^static int eap_ttls_process_handshake(struct eap_sm *sm,$/;" f file: +eap_ttls_process_phase2_mschapv2 src/eap_peer/eap_ttls.c /^static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,$/;" f file: +eap_ttls_process_tnc_start src/eap_peer/eap_ttls.c /^static int eap_ttls_process_tnc_start(struct eap_sm *sm,$/;" f file: +eap_ttls_v0_derive_key src/eap_peer/eap_ttls.c /^static int eap_ttls_v0_derive_key(struct eap_sm *sm,$/;" f file: +eap_type src/eap_peer/eap_tls.c /^ u8 eap_type;$/;" m struct:eap_tls_data file: +eap_type src/eap_peer/eap_tls_common.h /^ u8 eap_type;$/;" m struct:eap_ssl_data +eap_type src/wps/wps_attr_parse.h /^ const u8 *eap_type; \/* <= 8 octets *\/$/;" m struct:wps_parse_attr +eap_type_len src/wps/wps_attr_parse.h /^ size_t eap_type_len;$/;" m struct:wps_parse_attr +eap_update_len src/eap_peer/eap_common.c /^void eap_update_len(struct wpabuf *msg)$/;" f +eapdata src/eap_peer/eap_ttls.c /^ u8 *eapdata;$/;" m struct:ttls_parse_avp file: +eapol_key_timeout_first src/ap/wpa_auth.c /^static const u32 eapol_key_timeout_first = 100; \/* ms *\/$/;" v file: +eapol_key_timeout_first_group src/ap/wpa_auth.c /^static const u32 eapol_key_timeout_first_group = 500; \/* ms *\/$/;" v file: +eapol_key_timeout_subseq src/ap/wpa_auth.c /^static const u32 eapol_key_timeout_subseq = 1000; \/* ms *\/$/;" v file: +eapol_sm_notify_eap_success src/rsn_supp/wpa.c /^void eapol_sm_notify_eap_success(Boolean success)$/;" f +eapol_txcb src/rsn_supp/wpa.c /^void eapol_txcb(void *eb)$/;" f +eapol_version src/ap/ap_config.h /^ int eapol_version;$/;" m struct:hostapd_bss_config +eapol_version src/ap/wpa_auth.h /^ int eapol_version;$/;" m struct:wpa_auth_config +eapol_version src/rsn_supp/wpa.h /^ u8 eapol_version;$/;" m struct:wpa_sm +eapol_version src/wps/wps.h /^ u8 eapol_version;$/;" m struct:wps_sm +ecp_mpi_load test/test_crypto.c /^static inline void ecp_mpi_load( mbedtls_mpi *X, const mbedtls_mpi_uint *p, size_t len )$/;" f file: +ecp_opp src/crypto/crypto_mbedtls.c /^static int ecp_opp( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_ecp_point *P)$/;" f file: +ecw2cw src/ap/ap_config.c 100;" d file: +ecw2cw src/ap/ap_config.c 124;" d file: +eid src/common/ieee802_11_defs.h /^ u8 eid; \/* 221 = 0xdd *\/$/;" m struct:wmm_tspec_element +ek src/crypto/crypto_internal-cipher.c /^ u32 ek[32];$/;" m struct:crypto_cipher::__anon10::__anon14 file: +ek src/crypto/des_i.h /^ u32 ek[3][32];$/;" m struct:des3_key_s +ek src/fast_crypto/fast_crypto_internal-cipher.c /^ uint32_t ek[32];$/;" m struct:fast_crypto_cipher::__anon56::__anon60 file: +elem_id src/common/wpa_common.h /^ u8 elem_id; \/* WLAN_EID_RSN *\/$/;" m struct:rsn_ie_hdr +elem_id src/common/wpa_common.h /^ u8 elem_id;$/;" m struct:wpa_ie_hdr +element_id src/common/ieee802_11_defs.h /^ u8 element_id;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon79 +eloop_cancel_timeout src/utils/wpa_debug.c /^int eloop_cancel_timeout(eloop_timeout_handler handler,$/;" f +eloop_register_timeout src/utils/wpa_debug.c /^int eloop_register_timeout(unsigned int secs, unsigned int usecs,$/;" f +eloop_timeout_handler include/utils/wpa_debug.h /^typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx);$/;" t +email src/tls/x509v3.h /^ char *email; \/* emailAddress *\/$/;" m struct:x509_name +emsk src/wps/wps_i.h /^ u8 emsk[WPS_EMSK_LEN];$/;" m struct:wps_data +encr_hash src/eap_peer/eap_mschapv2.c /^ u8 encr_hash[16];$/;" m struct:ms_change_password file: +encr_password src/eap_peer/eap_mschapv2.c /^ u8 encr_password[516];$/;" m struct:ms_change_password file: +encr_settings src/wps/wps_attr_parse.h /^ const u8 *encr_settings;$/;" m struct:wps_parse_attr +encr_settings_len src/wps/wps_attr_parse.h /^ size_t encr_settings_len;$/;" m struct:wps_parse_attr +encr_type src/wps/wps.h /^ u16 encr_type;$/;" m struct:wps_credential +encr_type src/wps/wps_attr_parse.h /^ const u8 *encr_type; \/* 2 octets *\/$/;" m struct:wps_parse_attr +encr_type src/wps/wps_i.h /^ u16 encr_type;$/;" m struct:wps_data +encr_type_flags src/wps/wps_attr_parse.h /^ const u8 *encr_type_flags; \/* 2 octets *\/$/;" m struct:wps_parse_attr +encr_types src/wps/wps.h /^ u16 encr_types;$/;" m struct:wps_context +encrypt_pw_block_with_password_hash src/crypto/ms_funcs.c /^int encrypt_pw_block_with_password_hash($/;" f +engine src/tls/tls.h /^ int engine;$/;" m struct:tls_connection_params +engine_id src/tls/tls.h /^ const char *engine_id;$/;" m struct:tls_connection_params +enrollee src/wps/wps.h /^ int enrollee;$/;" m struct:wps_event_data::wps_event_pwd_auth_fail +enrollee src/wps/wps.h /^ } enrollee;$/;" m union:wps_event_data typeref:struct:wps_event_data::wps_event_er_enrollee +enrollee_addr src/wps/wps_registrar.c /^ u8 enrollee_addr[ETH_ALEN];$/;" m struct:wps_uuid_pin file: +enrollee_nonce src/wps/wps_attr_parse.h /^ const u8 *enrollee_nonce; \/* WPS_NONCE_LEN (16) octets *\/$/;" m struct:wps_parse_attr +enrollee_seen_cb src/wps/wps.h /^ void (*enrollee_seen_cb)(void *ctx, const u8 *addr, const u8 *uuid_e,$/;" m struct:wps_registrar_config +enrollee_seen_cb src/wps/wps_registrar.c /^ void (*enrollee_seen_cb)(void *ctx, const u8 *addr, const u8 *uuid_e,$/;" m struct:wps_registrar file: +er src/wps/wps_i.h /^ int er;$/;" m struct:wps_data +error src/ap/wpa_auth_ie.h /^ const u8 *error;$/;" m struct:wpa_eapol_ie_parse +error src/rsn_supp/wpa_ie.h /^ const u8 *error;$/;" m struct:wpa_eapol_ie_parse +error_indication src/wps/wps.h /^ u16 error_indication;$/;" m struct:wps_event_data::wps_event_fail +error_indication src/wps/wps_i.h /^ u16 error_indication;$/;" m struct:wps_data +error_len src/ap/wpa_auth_ie.h /^ size_t error_len;$/;" m struct:wpa_eapol_ie_parse +error_len src/rsn_supp/wpa_ie.h /^ size_t error_len;$/;" m struct:wpa_eapol_ie_parse +error_type src/common/wpa_common.h /^ be16 error_type;$/;" m struct:rsn_error_kde +esp_supplicant_init src/esp_supplicant/esp_wpa_main.c /^int esp_supplicant_init(void)$/;" f +esp_wifi_sta_wpa2_ent_clear_ca_cert src/esp_supplicant/esp_wpa_enterprise.c /^void esp_wifi_sta_wpa2_ent_clear_ca_cert(void)$/;" f +esp_wifi_sta_wpa2_ent_clear_cert_key src/esp_supplicant/esp_wpa_enterprise.c /^void esp_wifi_sta_wpa2_ent_clear_cert_key(void)$/;" f +esp_wifi_sta_wpa2_ent_clear_identity src/esp_supplicant/esp_wpa_enterprise.c /^void esp_wifi_sta_wpa2_ent_clear_identity(void)$/;" f +esp_wifi_sta_wpa2_ent_clear_new_password src/esp_supplicant/esp_wpa_enterprise.c /^void esp_wifi_sta_wpa2_ent_clear_new_password(void)$/;" f +esp_wifi_sta_wpa2_ent_clear_password src/esp_supplicant/esp_wpa_enterprise.c /^void esp_wifi_sta_wpa2_ent_clear_password(void)$/;" f +esp_wifi_sta_wpa2_ent_clear_username src/esp_supplicant/esp_wpa_enterprise.c /^void esp_wifi_sta_wpa2_ent_clear_username(void)$/;" f +esp_wifi_sta_wpa2_ent_disable src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_disable(void)$/;" f +esp_wifi_sta_wpa2_ent_disable_fn src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_disable_fn(void *param)$/;" f +esp_wifi_sta_wpa2_ent_enable src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_enable(const esp_wpa2_config_t *config)$/;" f +esp_wifi_sta_wpa2_ent_enable_fn src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_enable_fn(const esp_wpa2_config_t *config)$/;" f +esp_wifi_sta_wpa2_ent_get_disable_time_check src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_get_disable_time_check(bool *disable)$/;" f +esp_wifi_sta_wpa2_ent_set_ca_cert src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_set_ca_cert(const unsigned char *ca_cert, int ca_cert_len)$/;" f +esp_wifi_sta_wpa2_ent_set_cert_key src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_set_cert_key(const unsigned char *client_cert, int client_cert_len, const unsigned char *private_key, int private_key_len, const unsigned char *private_key_passwd, int private_key_passwd_len)$/;" f +esp_wifi_sta_wpa2_ent_set_disable_time_check src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_set_disable_time_check(bool disable)$/;" f +esp_wifi_sta_wpa2_ent_set_identity src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_set_identity(const unsigned char *identity, int len)$/;" f +esp_wifi_sta_wpa2_ent_set_new_password src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_set_new_password(const unsigned char *new_password, int len)$/;" f +esp_wifi_sta_wpa2_ent_set_password src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_set_password(const unsigned char *password, int len)$/;" f +esp_wifi_sta_wpa2_ent_set_username src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_set_username(const unsigned char *username, int len)$/;" f +esp_wifi_wps_disable src/esp_supplicant/esp_wps.c /^int esp_wifi_wps_disable(void)$/;" f +esp_wifi_wps_enable src/esp_supplicant/esp_wps.c /^int esp_wifi_wps_enable(const esp_wps_config_t *config)$/;" f +esp_wifi_wps_start src/esp_supplicant/esp_wps.c /^int esp_wifi_wps_start(int timeout_ms)$/;" f +esp_wpa2_config_t include/esp_supplicant/esp_wpa_enterprise.h /^}esp_wpa2_config_t;$/;" t typeref:struct:__anon88 +esp_wps_config_t include/esp_supplicant/esp_wps.h /^} esp_wps_config_t;$/;" t typeref:struct:__anon90 +event_cb src/tls/tls.h /^ void (*event_cb)(void *ctx, enum tls_event ev,$/;" m struct:tls_config +event_cb src/wps/wps.h /^ void (*event_cb)(void *ctx, enum wps_event event,$/;" m struct:wps_context +expanded_key_material src/tls/tlsv1_common.h /^ size_t expanded_key_material;$/;" m struct:tls_cipher_data +expiration src/wps/wps_registrar.c /^ struct os_time expiration;$/;" m struct:wps_uuid_pin typeref:struct:wps_uuid_pin::os_time file: +ext_data include/utils/wpabuf.h /^ u8 *ext_data; \/* pointer to external data; NULL if data follows$/;" m struct:wpabuf +ext_password_alloc src/utils/ext_password.c /^struct wpabuf * ext_password_alloc(size_t len)$/;" f +ext_password_backend src/utils/ext_password_i.h /^struct ext_password_backend {$/;" s +ext_password_data src/utils/ext_password.c /^struct ext_password_data {$/;" s file: +ext_password_deinit src/utils/ext_password.c /^void ext_password_deinit(struct ext_password_data *data)$/;" f +ext_password_deinit src/utils/ext_password.h 27;" d +ext_password_free src/utils/ext_password.c /^void ext_password_free(struct wpabuf *pw)$/;" f +ext_password_free src/utils/ext_password.h 29;" d +ext_password_get src/utils/ext_password.c /^struct wpabuf * ext_password_get(struct ext_password_data *data,$/;" f +ext_password_get src/utils/ext_password.h 28;" d +ext_password_init src/utils/ext_password.c /^struct ext_password_data * ext_password_init(const char *backend,$/;" f +ext_password_init src/utils/ext_password.h 26;" d +ext_reg src/wps/wps_i.h /^ int ext_reg;$/;" m struct:wps_data +extensions_present src/tls/x509v3.h /^ unsigned int extensions_present;$/;" m struct:x509_certificate +extra_cred src/ap/ap_config.h /^ u8 *extra_cred;$/;" m struct:hostapd_bss_config +extra_cred src/wps/wps.h /^ const u8 *extra_cred;$/;" m struct:wps_registrar_config +extra_cred src/wps/wps_registrar.c /^ struct wpabuf *extra_cred;$/;" m struct:wps_registrar typeref:struct:wps_registrar::wpabuf file: +extra_cred_len src/ap/ap_config.h /^ size_t extra_cred_len;$/;" m struct:hostapd_bss_config +extra_cred_len src/wps/wps.h /^ size_t extra_cred_len;$/;" m struct:wps_registrar_config +factory_info include/esp_supplicant/esp_wps.h /^ wps_factory_information_t factory_info;$/;" m struct:__anon90 +fail src/wps/wps.h /^ } fail;$/;" m union:wps_event_data typeref:struct:wps_event_data::wps_event_fail +fast_aes_128_cbc_decrypt src/fast_crypto/fast_aes-cbc.c /^fast_aes_128_cbc_decrypt(const uint8_t *key, const uint8_t *iv, uint8_t *data, size_t data_len)$/;" f +fast_aes_128_cbc_encrypt src/fast_crypto/fast_aes-cbc.c /^fast_aes_128_cbc_encrypt(const uint8_t *key, const uint8_t *iv, uint8_t *data, size_t data_len)$/;" f +fast_aes_unwrap src/fast_crypto/fast_aes-unwrap.c /^fast_aes_unwrap(const uint8_t *kek, int n, const uint8_t *cipher, uint8_t *plain)$/;" f +fast_aes_wrap src/fast_crypto/fast_aes-wrap.c /^int fast_aes_wrap(const uint8_t *kek, int n, const uint8_t *plain, uint8_t *cipher)$/;" f +fast_crypto_cipher src/fast_crypto/fast_crypto_internal-cipher.c /^struct fast_crypto_cipher {$/;" s file: +fast_crypto_cipher_decrypt src/fast_crypto/fast_crypto_internal-cipher.c /^int fast_crypto_cipher_decrypt(struct crypto_cipher *ctx, const uint8_t *crypt,$/;" f +fast_crypto_cipher_deinit src/fast_crypto/fast_crypto_internal-cipher.c /^void fast_crypto_cipher_deinit(struct crypto_cipher *ctx)$/;" f +fast_crypto_cipher_encrypt src/fast_crypto/fast_crypto_internal-cipher.c /^int fast_crypto_cipher_encrypt(struct crypto_cipher *ctx, const uint8_t *plain,$/;" f +fast_crypto_cipher_init src/fast_crypto/fast_crypto_internal-cipher.c /^struct crypto_cipher * fast_crypto_cipher_init(enum crypto_cipher_alg alg,$/;" f +fast_crypto_hash src/fast_crypto/fast_crypto_internal.c /^struct fast_crypto_hash {$/;" s file: +fast_crypto_hash_finish src/fast_crypto/fast_crypto_internal.c /^int fast_crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)$/;" f +fast_crypto_hash_init src/fast_crypto/fast_crypto_internal.c /^struct crypto_hash * fast_crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,$/;" f +fast_crypto_hash_update src/fast_crypto/fast_crypto_internal.c /^void fast_crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)$/;" f +fast_crypto_mod_exp src/fast_crypto/fast_crypto_internal-modexp.c /^fast_crypto_mod_exp(const uint8_t *base, size_t base_len,$/;" f +fast_hmac_sha256 src/fast_crypto/fast_sha256.c /^fast_hmac_sha256(const uint8_t *key, size_t key_len, const uint8_t *data,$/;" f +fast_hmac_sha256_vector src/fast_crypto/fast_sha256.c /^fast_hmac_sha256_vector(const uint8_t *key, size_t key_len, size_t num_elem,$/;" f +fast_mp_montgomery_reduce src/crypto/libtommath.h /^fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)$/;" f +fast_mp_montgomery_reduce src/tls/libtommath.h /^fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)$/;" f +fast_s_mp_mul_digs src/crypto/libtommath.h /^fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)$/;" f +fast_s_mp_mul_digs src/tls/libtommath.h /^fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)$/;" f +fast_s_mp_sqr src/crypto/libtommath.h /^fast_s_mp_sqr (mp_int * a, mp_int * b)$/;" f +fast_s_mp_sqr src/tls/libtommath.h /^fast_s_mp_sqr (mp_int * a, mp_int * b)$/;" f +fast_sha256_prf src/fast_crypto/fast_sha256.c /^fast_sha256_prf(const uint8_t *key, size_t key_len, const char *label,$/;" f +fast_sha256_vector src/fast_crypto/fast_sha256-internal.c /^fast_sha256_vector(size_t num_elem, const uint8_t *addr[], const size_t *len,$/;" f +finish_state src/eap_peer/eap_i.h /^ u8 finish_state;$/;" m struct:eap_sm +fips_mode src/tls/tls.h /^ int fips_mode;$/;" m struct:tls_config +first_sta_seen src/ap/wpa_auth_i.h /^ Boolean first_sta_seen;$/;" m struct:wpa_group +flags src/ap/hostapd.h /^ int flags; \/* HOSTAPD_RATE_ flags *\/$/;" m struct:hostapd_rate_data +flags src/ap/sta_info.h /^ u32 flags; \/* Bitfield of WLAN_STA_* *\/$/;" m struct:sta_info +flags src/eap_peer/eap_config.h /^ u32 flags;$/;" m struct:eap_peer_config +flags src/eap_peer/eap_mschapv2.c /^ u8 flags;$/;" m struct:ms_response file: +flags src/eap_peer/eap_mschapv2.c /^ u8 flags[2];$/;" m struct:ms_change_password file: +flags src/tls/tls.h /^ unsigned int flags;$/;" m struct:tls_connection_params +flags src/wps/wps_registrar.c /^ int flags;$/;" m struct:wps_uuid_pin file: +fn src/esp_supplicant/esp_wifi_driver.h /^ wifi_ipc_fn_t fn;$/;" m struct:__anon32 +fn src/esp_supplicant/esp_wifi_driver.h /^ wifi_wpa2_fn_t fn;$/;" m struct:__anon31 +for_each_auth src/ap/wpa_auth.h /^ int (*for_each_auth)(void *ctx, int (*cb)(struct wpa_authenticator *a,$/;" m struct:wpa_auth_callbacks +for_each_interface src/ap/hostapd.h /^ int (*for_each_interface)(struct hapd_interfaces *interfaces,$/;" m struct:hapd_interfaces +for_each_sta src/ap/wpa_auth.h /^ int (*for_each_sta)(void *ctx, int (*cb)(struct wpa_state_machine *sm,$/;" m struct:wpa_auth_callbacks +force_new_label src/eap_peer/eap_peap.c /^ int peap_version, force_peap_version, force_new_label;$/;" m struct:eap_peap_data file: +force_pbc_overlap src/wps/wps_registrar.c /^ int force_pbc_overlap;$/;" m struct:wps_registrar file: +force_peap_version src/eap_peer/eap_peap.c /^ int peap_version, force_peap_version, force_new_label;$/;" m struct:eap_peap_data file: +fragm_threshold src/ap/ap_config.h /^ int fragm_threshold;$/;" m struct:hostapd_config +fragment_size src/eap_peer/eap_config.h /^ int fragment_size;$/;" m struct:eap_peer_config +frame_control src/common/ieee802_11_defs.h /^ le16 frame_control;$/;" m struct:ieee80211_hdr +frame_control src/common/ieee802_11_defs.h /^ le16 frame_control;$/;" m struct:ieee80211_mgmt +frame_type src/ap/wpa_auth.h /^ u8 frame_type; \/* RSN_REMOTE_FRAME_TYPE_FT_RRB *\/$/;" m struct:ft_r0kh_r1kh_pull_frame +frame_type src/ap/wpa_auth.h /^ u8 frame_type; \/* RSN_REMOTE_FRAME_TYPE_FT_RRB *\/$/;" m struct:ft_r0kh_r1kh_push_frame +frame_type src/ap/wpa_auth.h /^ u8 frame_type; \/* RSN_REMOTE_FRAME_TYPE_FT_RRB *\/$/;" m struct:ft_r0kh_r1kh_resp_frame +frame_type src/ap/wpa_auth.h /^ u8 frame_type; \/* RSN_REMOTE_FRAME_TYPE_FT_RRB *\/$/;" m struct:ft_rrb_frame +free src/eap_peer/eap_i.h /^ void (*free)(struct eap_method *method);$/;" m struct:eap_method +friendly_name src/ap/ap_config.h /^ char *friendly_name;$/;" m struct:hostapd_bss_config +friendly_name src/wps/wps.h /^ const char *friendly_name;$/;" m struct:wps_event_data::wps_event_er_ap +friendly_name src/wps/wps.h /^ char *friendly_name;$/;" m struct:wps_context +ft_action_req src/common/ieee802_11_defs.h /^ } STRUCT_PACKED ft_action_req;$/;" m union:ieee80211_mgmt::__anon66::__anon76::__anon77 typeref:struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon80 +ft_action_resp src/common/ieee802_11_defs.h /^ } STRUCT_PACKED ft_action_resp;$/;" m union:ieee80211_mgmt::__anon66::__anon76::__anon77 typeref:struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon81 +ft_capab src/common/wpa_common.h /^ u8 ft_capab;$/;" m struct:rsn_mdie +ft_check_msg_2_of_4 src/ap/wpa_auth.c /^static int ICACHE_FLASH_ATTR ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,$/;" f file: +ft_completed src/ap/wpa_auth_i.h /^ unsigned int ft_completed:1;$/;" m struct:wpa_state_machine +ft_over_ds src/ap/ap_config.h /^ int ft_over_ds;$/;" m struct:hostapd_bss_config +ft_over_ds src/ap/wpa_auth.h /^ int ft_over_ds;$/;" m struct:wpa_auth_config +ft_r0kh_r1kh_pull_frame src/ap/wpa_auth.h /^struct ft_r0kh_r1kh_pull_frame {$/;" s +ft_r0kh_r1kh_push_frame src/ap/wpa_auth.h /^struct ft_r0kh_r1kh_push_frame {$/;" s +ft_r0kh_r1kh_resp_frame src/ap/wpa_auth.h /^struct ft_r0kh_r1kh_resp_frame {$/;" s +ft_remote_r0kh src/ap/wpa_auth.h /^struct ft_remote_r0kh {$/;" s +ft_remote_r1kh src/ap/wpa_auth.h /^struct ft_remote_r1kh {$/;" s +ft_rrb_frame src/ap/wpa_auth.h /^struct ft_rrb_frame {$/;" s +ftie src/ap/wpa_auth_ie.h /^ const u8 *ftie;$/;" m struct:wpa_eapol_ie_parse +ftie src/rsn_supp/wpa_ie.h /^ const u8 *ftie;$/;" m struct:wpa_eapol_ie_parse +ftie_len src/ap/wpa_auth_ie.h /^ size_t ftie_len;$/;" m struct:wpa_eapol_ie_parse +ftie_len src/rsn_supp/wpa_ie.h /^ size_t ftie_len;$/;" m struct:wpa_eapol_ie_parse +full_dynamic_vlan src/ap/hostapd.h /^ struct full_dynamic_vlan *full_dynamic_vlan;$/;" m struct:hostapd_data typeref:struct:hostapd_data::full_dynamic_vlan +gEapSm src/esp_supplicant/esp_wpa_enterprise.c /^static struct eap_sm *gEapSm = NULL;$/;" v typeref:struct:eap_sm file: +gWpaSm src/rsn_supp/wpa.c /^ struct wpa_sm gWpaSm;$/;" v typeref:struct:wpa_sm +gWpsSm src/esp_supplicant/esp_wps.c /^struct wps_sm *gWpsSm = NULL;$/;" v typeref:struct:wps_sm +g_wifi_wpa2_sync_sem src/esp_supplicant/esp_wpa_enterprise.c /^static void *g_wifi_wpa2_sync_sem = NULL;$/;" v file: +g_wpa2_api_lock src/esp_supplicant/esp_wpa_enterprise.c /^static void *g_wpa2_api_lock = NULL;$/;" v file: +g_wpa2_state src/esp_supplicant/esp_wpa_enterprise.c /^static wpa2_state_t g_wpa2_state = WPA2_STATE_DISABLED;$/;" v file: +g_wpa_anonymous_identity src/eap_peer/eap.h /^u8 *g_wpa_anonymous_identity;$/;" v +g_wpa_anonymous_identity_len src/eap_peer/eap.h /^int g_wpa_anonymous_identity_len;$/;" v +g_wpa_ca_cert src/eap_peer/eap.h /^const u8 *g_wpa_ca_cert;$/;" v +g_wpa_ca_cert_len src/eap_peer/eap.h /^int g_wpa_ca_cert_len;$/;" v +g_wpa_client_cert src/eap_peer/eap.h /^const u8 *g_wpa_client_cert;$/;" v +g_wpa_client_cert_len src/eap_peer/eap.h /^int g_wpa_client_cert_len;$/;" v +g_wpa_new_password src/eap_peer/eap.h /^u8 *g_wpa_new_password;$/;" v +g_wpa_new_password_len src/eap_peer/eap.h /^int g_wpa_new_password_len;$/;" v +g_wpa_password src/eap_peer/eap.h /^u8 *g_wpa_password;$/;" v +g_wpa_password_len src/eap_peer/eap.h /^int g_wpa_password_len;$/;" v +g_wpa_private_key src/eap_peer/eap.h /^const u8 *g_wpa_private_key;$/;" v +g_wpa_private_key_len src/eap_peer/eap.h /^int g_wpa_private_key_len;$/;" v +g_wpa_private_key_passwd src/eap_peer/eap.h /^const u8 *g_wpa_private_key_passwd;$/;" v +g_wpa_private_key_passwd_len src/eap_peer/eap.h /^int g_wpa_private_key_passwd_len;$/;" v +g_wpa_username src/eap_peer/eap.h /^u8 *g_wpa_username;$/;" v +g_wpa_username_len src/eap_peer/eap.h /^int g_wpa_username_len;$/;" v +gas_dialog src/ap/sta_info.h /^ struct gas_dialog_info *gas_dialog;$/;" m struct:sta_info typeref:struct:sta_info::gas_dialog_info +gas_dialog_next src/ap/sta_info.h /^ u8 gas_dialog_next;$/;" m struct:sta_info +gas_frag_limit src/ap/hostapd.h /^ size_t gas_frag_limit;$/;" m struct:hostapd_data +gd src/rsn_supp/wpa.h /^ struct wpa_gtk_data gd; \/\/used for calllback save param$/;" m struct:wpa_sm typeref:struct:wpa_sm::wpa_gtk_data +generate_authenticator_response src/crypto/ms_funcs.c /^int generate_authenticator_response(const u8 *password, size_t password_len,$/;" f +generate_authenticator_response_pwhash src/crypto/ms_funcs.c /^int generate_authenticator_response_pwhash($/;" f +generate_nt_response src/crypto/ms_funcs.c /^int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,$/;" f +generate_nt_response_pwhash src/crypto/ms_funcs.c /^int generate_nt_response_pwhash(const u8 *auth_challenge,$/;" f +generator include/crypto/dh_groups.h /^ const u8 *generator;$/;" m struct:dh_group +generator_len include/crypto/dh_groups.h /^ size_t generator_len;$/;" m struct:dh_group +get src/utils/ext_password_i.h /^ struct wpabuf * (*get)(void *ctx, const char *name);$/;" m struct:ext_password_backend typeref:struct:ext_password_backend::get +getKey src/eap_peer/eap_i.h /^ u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len);$/;" m struct:eap_method +getSessionId src/eap_peer/eap_i.h /^ u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len);$/;" m struct:eap_method +get_asymetric_start_key src/crypto/ms_funcs.c /^int get_asymetric_start_key(const u8 *master_key, u8 *session_key,$/;" f +get_eapol src/ap/wpa_auth.h /^ int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);$/;" m struct:wpa_auth_callbacks +get_identity src/eap_peer/eap_i.h /^ const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len);$/;" m struct:eap_method +get_master_key src/crypto/ms_funcs.c /^int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,$/;" f +get_msk src/ap/wpa_auth.h /^ int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);$/;" m struct:wpa_auth_callbacks +get_ppkey src/rsn_supp/wpa.h /^ int (*get_ppkey) (uint8_t *ifx, int *alg, uint8_t *addr, int *key_idx,$/;" m struct:wpa_sm +get_psk src/ap/wpa_auth.h /^ const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *prev_psk);$/;" m struct:wpa_auth_callbacks +get_seqnum src/ap/wpa_auth.h /^ int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq);$/;" m struct:wpa_auth_callbacks +get_status src/eap_peer/eap_i.h /^ int (*get_status)(struct eap_sm *sm, void *priv, char *buf,$/;" m struct:eap_method +gl_disable_time_check src/esp_supplicant/esp_wpa_enterprise.c /^static bool gl_disable_time_check = true;$/;" v file: +global_ctrl_sock src/ap/hostapd.h /^ int global_ctrl_sock;$/;" m struct:hapd_interfaces +global_iface_name src/ap/hostapd.h /^ char *global_iface_name;$/;" m struct:hapd_interfaces +global_iface_path src/ap/hostapd.h /^ char *global_iface_path;$/;" m struct:hapd_interfaces +group src/ap/ap_config.h /^ int group;$/;" m struct:hostapd_wpa_psk +group src/ap/wpa_auth_i.h /^ struct wpa_group *group;$/;" m struct:wpa_authenticator typeref:struct:wpa_authenticator::wpa_group +group src/ap/wpa_auth_i.h /^ struct wpa_group *group;$/;" m struct:wpa_state_machine typeref:struct:wpa_state_machine::wpa_group +group src/crypto/crypto_mbedtls.c /^ mbedtls_ecp_group group;$/;" m struct:crypto_ec file: +group_cipher src/common/wpa_common.h /^ int group_cipher;$/;" m struct:wpa_ie_data +group_cipher src/rsn_supp/wpa.h /^ unsigned int group_cipher;$/;" m struct:wpa_sm +gtk src/ap/wpa_auth_ie.h /^ const u8 *gtk;$/;" m struct:wpa_eapol_ie_parse +gtk src/common/wpa_common.h /^ u8 gtk[32];$/;" m struct:wpa_gtk_data +gtk src/rsn_supp/wpa_ie.h /^ const u8 *gtk;$/;" m struct:wpa_eapol_ie_parse +gtk_len src/ap/wpa_auth_ie.h /^ size_t gtk_len;$/;" m struct:wpa_eapol_ie_parse +gtk_len src/common/wpa_common.h /^ int gtk_len;$/;" m struct:wpa_gtk_data +gtk_len src/rsn_supp/wpa_ie.h /^ size_t gtk_len;$/;" m struct:wpa_eapol_ie_parse +h_dest src/rsn_supp/wpa.h /^ u8 h_dest[ETH_ALEN];$/;" m struct:l2_ethhdr +h_proto src/rsn_supp/wpa.h /^ be16 h_proto;$/;" m struct:l2_ethhdr +h_source src/rsn_supp/wpa.h /^ u8 h_source[ETH_ALEN];$/;" m struct:l2_ethhdr +hapd_interfaces src/ap/hostapd.h /^struct hapd_interfaces {$/;" s +has_GTK src/ap/wpa_auth_i.h /^ Boolean has_GTK;$/;" m struct:wpa_state_machine +has_reauth_data src/eap_peer/eap_i.h /^ bool (*has_reauth_data)(struct eap_sm *sm, void *priv);$/;" m struct:eap_method +hash src/tls/tls.h /^ const u8 *hash;$/;" m struct:tls_event_data::__anon35 +hash src/tls/tlsv1_common.h /^ tls_hash hash;$/;" m struct:tls_cipher_suite +hash_alg src/tls/tlsv1_record.h /^ enum crypto_hash_alg hash_alg;$/;" m struct:tlsv1_record_layer typeref:enum:tlsv1_record_layer::crypto_hash_alg +hash_len src/tls/tls.h /^ size_t hash_len;$/;" m struct:tls_event_data::__anon35 +hash_nt_password_hash src/crypto/ms_funcs.c /^int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)$/;" f +hash_size src/tls/tlsv1_record.h /^ size_t hash_size;$/;" m struct:tlsv1_record_layer +hex2byte src/utils/common.c /^int hex2byte(const char *hex)$/;" f +hex2num src/utils/common.c /^static int hex2num(char c)$/;" f file: +hexstr2bin src/utils/common.c /^int hexstr2bin(const char *hex, u8 *buf, size_t len)$/;" f +hmac_md5 src/crypto/md5.c /^hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,$/;" f +hmac_md5_non_fips_allow include/crypto/md5.h 32;" d +hmac_md5_vector src/crypto/md5.c /^hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,$/;" f +hmac_md5_vector_non_fips_allow include/crypto/md5.h 31;" d +hmac_sha1 src/crypto/sha1.c /^hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,$/;" f +hmac_sha1_vector src/crypto/sha1.c /^hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,$/;" f +hmac_sha256 src/crypto/sha256.c /^hmac_sha256(const u8 *key, size_t key_len, const u8 *data,$/;" f +hmac_sha256_vector src/crypto/sha256.c /^hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,$/;" f +hnext src/ap/sta_info.h /^ struct sta_info *hnext; \/* next entry in hash table list *\/$/;" m struct:sta_info typeref:struct:sta_info::sta_info +host_to_be16 include/utils/common.h 107;" d +host_to_be16 include/utils/common.h 66;" d +host_to_be16 include/utils/common.h 94;" d +host_to_be32 include/utils/common.h 110;" d +host_to_be32 include/utils/common.h 69;" d +host_to_be32 include/utils/common.h 98;" d +host_to_be64 include/utils/common.h 102;" d +host_to_be64 include/utils/common.h 114;" d +host_to_le16 include/utils/common.h 105;" d +host_to_le16 include/utils/common.h 64;" d +host_to_le16 include/utils/common.h 92;" d +host_to_le32 include/utils/common.h 96;" d +host_to_le64 include/utils/common.h 100;" d +host_to_le64 include/utils/common.h 112;" d +hostap_deinit src/esp_supplicant/esp_hostap.c /^bool hostap_deinit(void *data)$/;" f +hostap_eapol_resend_process src/ap/wpa_auth.c /^void hostap_eapol_resend_process(void *timeout_ctx)$/;" f +hostap_init src/esp_supplicant/esp_hostap.c /^void* hostap_init(void)$/;" f +hostap_security_policy src/ap/ap_config.h /^typedef enum hostap_security_policy {$/;" g +hostapd_bss_config src/ap/ap_config.h /^struct hostapd_bss_config {$/;" s +hostapd_config src/ap/ap_config.h /^struct hostapd_config {$/;" s +hostapd_config_defaults src/ap/ap_config.c /^struct hostapd_config * hostapd_config_defaults(void)$/;" f +hostapd_config_defaults_bss src/ap/ap_config.c /^void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)$/;" f +hostapd_data src/ap/hostapd.h /^struct hostapd_data {$/;" s +hostapd_derive_psk src/ap/ap_config.c /^static int hostapd_derive_psk(struct hostapd_ssid *ssid)$/;" f file: +hostapd_frame_info src/ap/hostapd.h /^struct hostapd_frame_info {$/;" s +hostapd_get_psk src/ap/ap_config.c /^const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,$/;" f +hostapd_hw_mode src/common/defs.h /^enum hostapd_hw_mode {$/;" g +hostapd_mac_comp src/ap/ap_config.c /^int hostapd_mac_comp(const void *a, const void *b)$/;" f +hostapd_mac_comp_empty src/ap/ap_config.c /^int hostapd_mac_comp_empty(const void *a)$/;" f +hostapd_maclist_found src/ap/ap_config.c /^int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,$/;" f +hostapd_probereq_cb src/ap/hostapd.h /^struct hostapd_probereq_cb {$/;" s +hostapd_rate_data src/ap/hostapd.h /^struct hostapd_rate_data {$/;" s +hostapd_rate_found src/ap/ap_config.c /^int hostapd_rate_found(int *list, int rate)$/;" f +hostapd_setup_wpa_psk src/ap/ap_config.c /^int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)$/;" f +hostapd_ssid src/ap/ap_config.h /^struct hostapd_ssid {$/;" s +hostapd_sta_wpa_psk_short src/ap/ap_config.h /^struct hostapd_sta_wpa_psk_short {$/;" s +hostapd_wep_key_cmp src/ap/ap_config.c /^int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, struct hostapd_wep_keys *b)$/;" f +hostapd_wep_keys src/ap/ap_config.h /^struct hostapd_wep_keys {$/;" s +hostapd_wpa_psk src/ap/ap_config.h /^struct hostapd_wpa_psk {$/;" s +hs20 src/ap/ap_config.h /^ int hs20;$/;" m struct:hostapd_bss_config +hs20_connection_capability src/ap/ap_config.h /^ u8 *hs20_connection_capability;$/;" m struct:hostapd_bss_config +hs20_connection_capability_len src/ap/ap_config.h /^ size_t hs20_connection_capability_len;$/;" m struct:hostapd_bss_config +hs20_oper_friendly_name src/ap/ap_config.h /^ struct hostapd_lang_string *hs20_oper_friendly_name;$/;" m struct:hostapd_bss_config typeref:struct:hostapd_bss_config::hostapd_lang_string +hs20_oper_friendly_name_count src/ap/ap_config.h /^ unsigned int hs20_oper_friendly_name_count;$/;" m struct:hostapd_bss_config +hs20_operating_class src/ap/ap_config.h /^ u8 *hs20_operating_class;$/;" m struct:hostapd_bss_config +hs20_operating_class_len src/ap/ap_config.h /^ u8 hs20_operating_class_len;$/;" m struct:hostapd_bss_config +hs20_wan_metrics src/ap/ap_config.h /^ u8 *hs20_wan_metrics;$/;" m struct:hostapd_bss_config +ht_capab src/ap/ap_config.h /^ u16 ht_capab;$/;" m struct:hostapd_config +ht_capabilities_info src/common/ieee802_11_defs.h /^ le16 ht_capabilities_info;$/;" m struct:ieee80211_ht_capabilities +ht_extended_capabilities src/common/ieee802_11_defs.h /^ le16 ht_extended_capabilities;$/;" m struct:ieee80211_ht_capabilities +ht_op_mode_fixed src/ap/ap_config.h /^ int ht_op_mode_fixed;$/;" m struct:hostapd_config +ht_param src/common/ieee802_11_defs.h /^ u8 ht_param;$/;" m struct:ieee80211_ht_operation +htobe16 port/include/endian.h 102;" d +htobe16 port/include/endian.h 87;" d +htobe32 port/include/endian.h 103;" d +htobe32 port/include/endian.h 88;" d +htobe64 port/include/endian.h 104;" d +htobe64 port/include/endian.h 89;" d +htole16 port/include/endian.h 105;" d +htole16 port/include/endian.h 90;" d +htole32 port/include/endian.h 106;" d +htole32 port/include/endian.h 91;" d +htole64 port/include/endian.h 107;" d +htole64 port/include/endian.h 92;" d +hw_mode src/ap/ap_config.h /^ enum hostapd_hw_mode hw_mode; \/* HOSTAPD_MODE_IEEE80211A, .. *\/$/;" m struct:hostapd_config typeref:enum:hostapd_config::hostapd_hw_mode +ic_cipher src/esp_supplicant/esp_wifi_driver.h /^ u_int ic_cipher; \/* WIFI_CIPHER_* *\/$/;" m struct:wifi_cipher +ic_decap src/esp_supplicant/esp_wifi_driver.h /^ int (*ic_decap)(struct wifi_key *, void *, int);$/;" m struct:wifi_cipher +ic_encap src/esp_supplicant/esp_wifi_driver.h /^ int (*ic_encap)(struct wifi_key *, void *, uint8_t);$/;" m struct:wifi_cipher +ic_header src/esp_supplicant/esp_wifi_driver.h /^ u_int ic_header; \/* size of privacy header (bytes) *\/$/;" m struct:wifi_cipher +ic_miclen src/esp_supplicant/esp_wifi_driver.h /^ u_int ic_miclen; \/* size of mic trailer (bytes) *\/$/;" m struct:wifi_cipher +ic_trailer src/esp_supplicant/esp_wifi_driver.h /^ u_int ic_trailer; \/* size of privacy trailer (bytes) *\/$/;" m struct:wifi_cipher +iconf src/ap/hostapd.h /^ struct hostapd_config *iconf;$/;" m struct:hostapd_data typeref:struct:hostapd_data::hostapd_config +id include/crypto/dh_groups.h /^ int id;$/;" m struct:dh_group +id src/ap/wpa_auth.h /^ u8 id[FT_R0KH_ID_MAX_LEN];$/;" m struct:ft_remote_r0kh +id src/ap/wpa_auth.h /^ u8 id[FT_R1KH_ID_LEN];$/;" m struct:ft_remote_r1kh +id src/common/wpa_common.h /^ u8 id;$/;" m struct:rsn_rdie +id_len src/ap/wpa_auth.h /^ size_t id_len;$/;" m struct:ft_remote_r0kh +id_len src/eap_peer/eap_peap.c /^ size_t id_len;$/;" m struct:eap_peap_data file: +id_len src/eap_peer/eap_tls.c /^ size_t id_len;$/;" m struct:eap_tls_data file: +id_len src/eap_peer/eap_ttls.c /^ size_t id_len;$/;" m struct:eap_ttls_data file: +ident src/eap_peer/eap_ttls.c /^ u8 ident;$/;" m struct:eap_ttls_data file: +identifier src/eap_peer/eap_defs.h /^ u8 identifier;$/;" m struct:eap_hdr +identifier src/tls/asn1.h /^ u8 identifier, class, constructed;$/;" m struct:asn1_hdr +identity src/eap_peer/eap_config.h /^ u8 *identity;$/;" m struct:eap_peer_config +identity src/wps/wps.h /^ char identity[32];$/;" m struct:wps_sm +identity_len src/eap_peer/eap_config.h /^ size_t identity_len;$/;" m struct:eap_peer_config +identity_len src/wps/wps.h /^ u8 identity_len;$/;" m struct:wps_sm +idx src/ap/ap_config.h /^ u8 idx;$/;" m struct:hostapd_wep_keys +ie_data src/esp_supplicant/esp_wifi_driver.h /^ uint8_t ie_data[];$/;" m struct:wifi_appie +ie_len src/esp_supplicant/esp_wifi_driver.h /^ uint16_t ie_len;$/;" m struct:wifi_appie +ieee80211_hdr src/common/ieee802_11_defs.h /^struct ieee80211_hdr {$/;" s +ieee80211_ht_capabilities src/common/ieee802_11_defs.h /^struct ieee80211_ht_capabilities {$/;" s +ieee80211_ht_operation src/common/ieee802_11_defs.h /^struct ieee80211_ht_operation {$/;" s +ieee80211_mgmt src/common/ieee802_11_defs.h /^struct ieee80211_mgmt {$/;" s +ieee80211ac src/ap/ap_config.h /^ int ieee80211ac;$/;" m struct:hostapd_config +ieee80211d src/ap/ap_config.h /^ int ieee80211d;$/;" m struct:hostapd_config +ieee80211n src/ap/ap_config.h /^ int ieee80211n;$/;" m struct:hostapd_config +ieee80211w src/ap/ap_config.h /^ enum mfp_options ieee80211w;$/;" m struct:hostapd_bss_config typeref:enum:hostapd_bss_config::mfp_options +ieee80211w src/ap/wpa_auth.h /^ enum mfp_options ieee80211w;$/;" m struct:wpa_auth_config typeref:enum:wpa_auth_config::mfp_options +ieee80211w_kde_add src/ap/wpa_auth.c /^static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)$/;" f file: +ieee80211w_kde_len src/ap/wpa_auth.c /^static int ieee80211w_kde_len(struct wpa_state_machine *sm)$/;" f file: +ieee80211w_set_keys src/rsn_supp/wpa.c /^int ieee80211w_set_keys(struct wpa_sm *sm,$/;" f +ieee802_1x src/ap/ap_config.h /^ int ieee802_1x; \/* use IEEE 802.1X *\/$/;" m struct:hostapd_bss_config +ieee802_1x_eapol_key src/common/eapol_common.h /^struct ieee802_1x_eapol_key {$/;" s +ieee802_1x_hdr src/common/eapol_common.h /^struct ieee802_1x_hdr {$/;" s +ieee802_1x_receive src/ap/ieee802_1x.c /^void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,$/;" f +iface src/ap/hostapd.h /^ struct hostapd_iface **iface;$/;" m struct:hapd_interfaces typeref:struct:hapd_interfaces::hostapd_iface +ignore src/eap_peer/eap_i.h /^ Boolean ignore;$/;" m struct:eap_method_ret +ignore_broadcast_ssid src/ap/ap_config.h /^ int ignore_broadcast_ssid;$/;" m struct:hostapd_bss_config +ignore_sel_reg src/wps/wps.h /^ bool ignore_sel_reg;$/;" m struct:wps_sm +igtk src/ap/wpa_auth_ie.h /^ const u8 *igtk;$/;" m struct:wpa_eapol_ie_parse +igtk src/common/wpa_common.h /^ u8 igtk[WPA_IGTK_LEN];$/;" m struct:wpa_igtk_kde +igtk src/rsn_supp/wpa_ie.h /^ const u8 *igtk;$/;" m struct:wpa_eapol_ie_parse +igtk_len src/ap/wpa_auth_ie.h /^ size_t igtk_len;$/;" m struct:wpa_eapol_ie_parse +igtk_len src/rsn_supp/wpa_ie.h /^ size_t igtk_len;$/;" m struct:wpa_eapol_ie_parse +in src/crypto/md5_i.h /^ u8 in[64];$/;" m struct:MD5Context +in_step_loop src/ap/wpa_auth_i.h /^ unsigned int in_step_loop:1;$/;" m struct:wpa_state_machine +inactivity_interval src/common/ieee802_11_defs.h /^ le32 inactivity_interval;$/;" m struct:wmm_tspec_element +inc_byte_array src/utils/common.c /^void inc_byte_array(u8 *counter, size_t len)$/;" f +include_tls_length src/eap_peer/eap_tls_common.h /^ int include_tls_length;$/;" m struct:eap_ssl_data +index src/ap/wpa_auth_i.h /^ u32 index;$/;" m struct:wpa_state_machine +init src/eap_peer/eap_i.h /^ void * (*init)(struct eap_sm *sm);$/;" m struct:eap_method +init src/utils/ext_password_i.h /^ void * (*init)(const char *params);$/;" m struct:ext_password_backend +init_for_reauth src/eap_peer/eap_i.h /^ void * (*init_for_reauth)(struct eap_sm *sm, void *priv);$/;" m struct:eap_method +init_phase2 src/eap_peer/eap_i.h /^ int init_phase2;$/;" m struct:eap_sm +initiator src/ap/wpa_auth_i.h /^ u8 initiator[ETH_ALEN];$/;" m struct:wpa_stsl_negotiation +inline include/utils/common.h 228;" d +inline include/utils/common.h 230;" d +install_gtk src/rsn_supp/wpa.h /^ struct install_key install_gtk;$/;" m struct:wpa_sm typeref:struct:wpa_sm::install_key +install_key src/rsn_supp/wpa.h /^struct install_key {$/;" s +install_ppkey src/rsn_supp/wpa.h /^ void (*install_ppkey) (enum wpa_alg alg, u8 *addr, int key_idx, int set_tx,$/;" m struct:wpa_sm +install_ptk src/rsn_supp/wpa.h /^ struct install_key install_ptk;$/;" m struct:wpa_sm typeref:struct:wpa_sm::install_key +int_reg src/wps/wps_i.h /^ int int_reg;$/;" m struct:wps_data +interface_added src/ap/hostapd.h /^ int interface_added; \/* virtual interface added for this BSS *\/$/;" m struct:hostapd_data +ip src/tls/x509v3.h /^ u8 *ip; \/* iPAddress *\/$/;" m struct:x509_name +ip_len src/tls/x509v3.h /^ size_t ip_len; \/* IPv4: 4, IPv6: 16 *\/$/;" m struct:x509_name +ipmk src/eap_peer/eap_peap.c /^ u8 ipmk[40];$/;" m struct:eap_peap_data file: +iqmp src/tls/rsa.c /^ struct bignum *iqmp; \/* 1 \/ q mod p; CRT coefficient *\/$/;" m struct:crypto_rsa_key typeref:struct:crypto_rsa_key::bignum file: +isKeyAvailable src/eap_peer/eap_i.h /^ bool (*isKeyAvailable)(struct eap_sm *sm, void *priv);$/;" m struct:eap_method +is_local src/tls/tls.h /^ int is_local;$/;" m struct:tls_event_data::__anon36 +is_nil_uuid src/utils/uuid.c /^int is_nil_uuid(const u8 *uuid)$/;" f +is_selected_pin_registrar src/wps/wps.c /^static int is_selected_pin_registrar(struct wps_parse_attr *attr, u8 *bssid)$/;" f file: +is_wnmsleep src/ap/wpa_auth_i.h /^ unsigned int is_wnmsleep:1;$/;" m struct:wpa_state_machine +is_wps_scan src/wps/wps.h /^ bool is_wps_scan;$/;" m struct:wps_sm +is_zero_ether_addr include/utils/common.h /^static inline int is_zero_ether_addr(const u8 *a)$/;" f +issuer src/tls/x509v3.h /^ struct x509_name issuer;$/;" m struct:x509_certificate typeref:struct:x509_certificate::x509_name +iter_count src/tls/pkcs5.c /^ unsigned int iter_count;$/;" m struct:pkcs5_params file: +iv_size src/tls/tlsv1_record.h /^ size_t iv_size; \/* also block_size *\/$/;" m struct:tlsv1_record_layer +kck src/common/wpa_common.h /^ u8 kck[16]; \/* EAPOL-Key Key Confirmation Key (KCK) *\/$/;" m struct:wpa_ptk +kek src/common/wpa_common.h /^ u8 kek[16]; \/* EAPOL-Key Key Encryption Key (KEK) *\/$/;" m struct:wpa_ptk +key src/ap/ap_config.h /^ u8 *key[NUM_WEP_KEYS];$/;" m struct:hostapd_wep_keys +key src/ap/wpa_auth.h /^ u8 key[16];$/;" m struct:ft_remote_r0kh +key src/ap/wpa_auth.h /^ u8 key[16];$/;" m struct:ft_remote_r1kh +key src/crypto/crypto_internal-cipher.c /^ struct des3_key_s key;$/;" m struct:crypto_cipher::__anon10::__anon13 typeref:struct:crypto_cipher::__anon10::__anon13::des3_key_s file: +key src/crypto/crypto_internal-cipher.c /^ u8 key[16];$/;" m struct:crypto_cipher::__anon10::__anon11 file: +key src/crypto/crypto_internal.c /^ u8 key[64];$/;" m struct:crypto_hash file: +key src/fast_crypto/fast_crypto_internal-cipher.c /^ struct des3_key_s key;$/;" m struct:fast_crypto_cipher::__anon56::__anon59 typeref:struct:fast_crypto_cipher::__anon56::__anon59::des3_key_s file: +key src/fast_crypto/fast_crypto_internal-cipher.c /^ uint8_t key[16];$/;" m struct:fast_crypto_cipher::__anon56::__anon57 file: +key src/fast_crypto/fast_crypto_internal.c /^ u8 key[64];$/;" m struct:fast_crypto_hash file: +key src/rsn_supp/wpa.h /^ u8 key[32];$/;" m struct:install_key +key src/tls/tlsv1_cred.h /^ struct crypto_private_key *key;$/;" m struct:tlsv1_credentials typeref:struct:tlsv1_credentials::crypto_private_key +key src/wps/wps.h /^ u8 key[64];$/;" m struct:wps_credential +key src/wps/wps.h /^ char key[64];$/;" m struct:wps_sm +key_data src/eap_peer/eap_peap.c /^ u8 *key_data;$/;" m struct:eap_peap_data file: +key_data src/eap_peer/eap_tls.c /^ u8 *key_data;$/;" m struct:eap_tls_data file: +key_data src/eap_peer/eap_ttls.c /^ u8 *key_data;$/;" m struct:eap_ttls_data file: +key_data_length src/common/wpa_common.h /^ u8 key_data_length[2]; \/* big endian *\/$/;" m struct:wpa_eapol_key +key_entry_valid src/rsn_supp/wpa.h /^ int key_entry_valid; \/\/present current avaliable entry for bssid, for pairkey:0,5,10,15,20, gtk: pairkey_no+i (i:1~4)$/;" m struct:wpa_sm +key_exchange src/tls/tlsv1_common.h /^ tls_key_exchange key_exchange;$/;" m struct:tls_cipher_suite +key_id src/common/wpa_common.h /^ u8 key_id[8]; \/* Reserved in IEEE 802.11i\/RSN *\/$/;" m struct:wpa_eapol_key +key_id src/tls/tls.h /^ const char *key_id;$/;" m struct:tls_connection_params +key_idx src/rsn_supp/wpa.h /^ int key_idx;$/;" m struct:install_key +key_idx src/wps/wps.h /^ u8 key_idx;$/;" m struct:wps_credential +key_index src/common/eapol_common.h /^ u8 key_index; \/* key flag in the most significant bit:$/;" m struct:ieee802_1x_eapol_key +key_info src/common/wpa_common.h /^ u8 key_info[2]; \/* big endian *\/$/;" m struct:wpa_eapol_key +key_info src/rsn_supp/wpa.h /^ u16 key_info; \/\/used for txcallback param $/;" m struct:wpa_sm +key_install src/rsn_supp/wpa.h /^ bool key_install;$/;" m struct:wpa_sm +key_iv src/common/eapol_common.h /^ u8 key_iv[IEEE8021X_KEY_IV_LEN]; \/* cryptographically random number *\/$/;" m struct:ieee802_1x_eapol_key +key_iv src/common/wpa_common.h /^ u8 key_iv[16];$/;" m struct:wpa_eapol_key +key_len src/crypto/crypto_internal.c /^ size_t key_len;$/;" m struct:crypto_hash file: +key_len src/fast_crypto/fast_crypto_internal.c /^ size_t key_len;$/;" m struct:fast_crypto_hash file: +key_len src/wps/wps.h /^ size_t key_len;$/;" m struct:wps_credential +key_len src/wps/wps.h /^ u8 key_len;$/;" m struct:wps_sm +key_length src/common/eapol_common.h /^ u8 key_length[2];$/;" m struct:ieee802_1x_eapol_key +key_length src/common/wpa_common.h /^ u8 key_length[2]; \/* big endian *\/$/;" m struct:wpa_eapol_key +key_lifetime src/rsn_supp/wpa_ie.h /^ const u8 *key_lifetime;$/;" m struct:wpa_eapol_ie_parse +key_material src/tls/tlsv1_common.h /^ size_t key_material;$/;" m struct:tls_cipher_data +key_material_len src/tls/tlsv1_record.h /^ size_t key_material_len;$/;" m struct:tlsv1_record_layer +key_mgmt src/common/wpa_common.h /^ int key_mgmt;$/;" m struct:wpa_ie_data +key_mgmt src/rsn_supp/wpa.h /^ unsigned int key_mgmt;$/;" m struct:wpa_sm +key_mic src/common/wpa_common.h /^ u8 key_mic[16];$/;" m struct:wpa_eapol_key +key_nonce src/common/wpa_common.h /^ u8 key_nonce[WPA_NONCE_LEN];$/;" m struct:wpa_eapol_key +key_prov_auto src/wps/wps_attr_parse.h /^ const u8 *key_prov_auto; \/* 1 octet (Bool) *\/$/;" m struct:wps_parse_attr +key_replay src/ap/wpa_auth_i.h /^ } key_replay[RSNA_MAX_EAPOL_RETRIES],$/;" m struct:wpa_state_machine typeref:struct:wpa_state_machine::wpa_key_replay_counter +key_rsc src/common/wpa_common.h /^ u8 key_rsc[WPA_KEY_RSC_LEN];$/;" m struct:wpa_eapol_key +key_rsc_len src/common/wpa_common.h /^ int tx, key_rsc_len, keyidx;$/;" m struct:wpa_gtk_data +key_signature src/common/eapol_common.h /^ u8 key_signature[IEEE8021X_KEY_SIGN_LEN];$/;" m struct:ieee802_1x_eapol_key +key_usage src/tls/x509v3.h /^ unsigned long key_usage;$/;" m struct:x509_certificate +key_wrap_auth src/wps/wps_attr_parse.h /^ const u8 *key_wrap_auth; \/* WPS_KWA_LEN (8) octets *\/$/;" m struct:wps_parse_attr +key_wrap_extra src/ap/wpa_auth.h /^ u8 key_wrap_extra[8];$/;" m struct:ft_r0kh_r1kh_pull_frame +key_wrap_extra src/ap/wpa_auth.h /^ u8 key_wrap_extra[8];$/;" m struct:ft_r0kh_r1kh_push_frame +key_wrap_extra src/ap/wpa_auth.h /^ u8 key_wrap_extra[8];$/;" m struct:ft_r0kh_r1kh_resp_frame +keycount src/ap/wpa_auth_i.h /^ int keycount;$/;" m struct:wpa_state_machine +keyid src/common/wpa_common.h /^ u8 keyid[2];$/;" m struct:wpa_igtk_kde +keyidx src/common/wpa_common.h /^ int tx, key_rsc_len, keyidx;$/;" m struct:wpa_gtk_data +keylen src/crypto/crypto_internal-cipher.c /^ size_t keylen;$/;" m struct:crypto_cipher::__anon10::__anon11 file: +keylen src/fast_crypto/fast_crypto_internal-cipher.c /^ size_t keylen;$/;" m struct:fast_crypto_cipher::__anon56::__anon57 file: +keys_cleared src/rsn_supp/wpa.h /^ int keys_cleared;$/;" m struct:install_key +keys_set src/ap/ap_config.h /^ int keys_set;$/;" m struct:hostapd_wep_keys +keywrapkey src/wps/wps_i.h /^ u8 keywrapkey[WPS_KEYWRAPKEY_LEN];$/;" m struct:wps_data +l2_ethhdr src/rsn_supp/wpa.h /^struct l2_ethhdr {$/;" s +lastRespData src/eap_peer/eap_i.h /^ struct wpabuf *lastRespData;$/;" m struct:eap_sm typeref:struct:eap_sm::wpabuf +last_bss src/ap/ap_config.h /^ struct hostapd_bss_config *bss, *last_bss;$/;" m struct:hostapd_config typeref:struct:hostapd_config:: +last_msg src/wps/wps_i.h /^ struct wpabuf *last_msg;$/;" m struct:wps_data typeref:struct:wps_data::wpabuf +last_rx_eapol_key src/ap/wpa_auth_i.h /^ u8 *last_rx_eapol_key; \/* starting from IEEE 802.1X header *\/$/;" m struct:wpa_state_machine +last_rx_eapol_key_len src/ap/wpa_auth_i.h /^ size_t last_rx_eapol_key_len;$/;" m struct:wpa_state_machine +le16 include/utils/common.h /^typedef u16 __bitwise le16;$/;" t +le16dec port/include/endian.h /^le16dec(const void *pp)$/;" f +le16enc port/include/endian.h /^le16enc(void *pp, uint16_t u)$/;" f +le16toh port/include/endian.h 112;" d +le16toh port/include/endian.h 97;" d +le32 include/utils/common.h /^typedef u32 __bitwise le32;$/;" t +le32dec port/include/endian.h /^le32dec(const void *pp)$/;" f +le32enc port/include/endian.h /^le32enc(void *pp, uint32_t u)$/;" f +le32toh port/include/endian.h 113;" d +le32toh port/include/endian.h 98;" d +le64 include/utils/common.h /^typedef u64 __bitwise le64;$/;" t +le64dec port/include/endian.h /^le64dec(const void *pp)$/;" f +le64enc port/include/endian.h /^le64enc(void *pp, uint64_t u)$/;" f +le64toh port/include/endian.h 114;" d +le64toh port/include/endian.h 99;" d +le_to_host16 include/utils/common.h 104;" d +le_to_host16 include/utils/common.h 63;" d +le_to_host16 include/utils/common.h 91;" d +le_to_host32 include/utils/common.h 108;" d +le_to_host32 include/utils/common.h 67;" d +le_to_host32 include/utils/common.h 95;" d +le_to_host64 include/utils/common.h 111;" d +le_to_host64 include/utils/common.h 99;" d +len src/ap/ap_config.h /^ size_t len[NUM_WEP_KEYS];$/;" m struct:hostapd_wep_keys +len src/common/wpa_common.h /^ u8 len;$/;" m struct:rsn_ie_hdr +len src/common/wpa_common.h /^ u8 len;$/;" m struct:wpa_ie_hdr +len src/eap_peer/eap_config.h /^ size_t len;$/;" m struct:wpa_config_blob +len src/esp_supplicant/esp_wifi_driver.h /^ int len;$/;" m struct:wifi_ssid +len src/esp_supplicant/esp_wpa_enterprise.c /^ int len;$/;" m struct:wpa2_rx_param file: +len src/esp_supplicant/esp_wps.c /^ int len;$/;" m struct:wps_rx_param file: +len src/tls/asn1.h /^ size_t len;$/;" m struct:asn1_oid +length src/common/eapol_common.h /^ be16 length;$/;" m struct:ieee802_1x_hdr +length src/common/ieee802_11_defs.h /^ u8 length;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon79 +length src/common/ieee802_11_defs.h /^ u8 length; \/* 6 + 55 = 61 *\/$/;" m struct:wmm_tspec_element +length src/crypto/sha256-internal.c /^ u64 length;$/;" m struct:sha256_state file: +length src/eap_peer/eap_defs.h /^ be16 length; \/* including code and identifier; network byte order *\/$/;" m struct:eap_hdr +length src/eap_peer/eap_tlv_common.h /^ be16 length;$/;" m struct:eap_tlv_crypto_binding_tlv +length src/eap_peer/eap_tlv_common.h /^ be16 length;$/;" m struct:eap_tlv_hdr +length src/eap_peer/eap_tlv_common.h /^ be16 length;$/;" m struct:eap_tlv_intermediate_result_tlv +length src/eap_peer/eap_tlv_common.h /^ be16 length;$/;" m struct:eap_tlv_nak_tlv +length src/eap_peer/eap_tlv_common.h /^ be16 length;$/;" m struct:eap_tlv_pac_ack_tlv +length src/eap_peer/eap_tlv_common.h /^ be16 length;$/;" m struct:eap_tlv_pac_type_tlv +length src/eap_peer/eap_tlv_common.h /^ be16 length;$/;" m struct:eap_tlv_request_action_tlv +length src/eap_peer/eap_tlv_common.h /^ be16 length;$/;" m struct:eap_tlv_result_tlv +length src/tls/asn1.h /^ unsigned int tag, length;$/;" m struct:asn1_hdr +lifetime src/ap/wpa_auth_ie.h /^ const u8 *lifetime;$/;" m struct:wpa_eapol_ie_parse +lifetime src/rsn_supp/wpa_ie.h /^ const u8 *lifetime;$/;" m struct:wpa_eapol_ie_parse +lifetime_len src/ap/wpa_auth_ie.h /^ size_t lifetime_len;$/;" m struct:wpa_eapol_ie_parse +lifetime_len src/rsn_supp/wpa_ie.h /^ size_t lifetime_len;$/;" m struct:wpa_eapol_ie_parse +list src/wps/wps_registrar.c /^ struct dl_list list;$/;" m struct:wps_nfc_pw_token typeref:struct:wps_nfc_pw_token::dl_list file: +list src/wps/wps_registrar.c /^ struct dl_list list;$/;" m struct:wps_uuid_pin typeref:struct:wps_uuid_pin::dl_list file: +listen_interval src/ap/sta_info.h /^ u16 listen_interval; \/* or beacon_int for APs *\/$/;" m struct:sta_info +listen_interval src/common/ieee802_11_defs.h /^ le16 listen_interval;$/;" m struct:ieee80211_mgmt::__anon66::__anon69 +listen_interval src/common/ieee802_11_defs.h /^ le16 listen_interval;$/;" m struct:ieee80211_mgmt::__anon66::__anon71 +logger src/ap/wpa_auth.h /^ void (*logger)(void *ctx, const u8 *addr, logger_level level,$/;" m struct:wpa_auth_callbacks +logger_level src/ap/wpa_auth.h /^} logger_level;$/;" t typeref:enum:__anon20 +m src/eap_peer/eap_i.h /^ const struct eap_method *m;$/;" m struct:eap_sm typeref:struct:eap_sm::eap_method +m1_received src/wps/wps.h /^ int m1_received;$/;" m struct:wps_event_data::wps_event_er_enrollee +m2d src/wps/wps.h /^ } m2d;$/;" m union:wps_event_data typeref:struct:wps_event_data::wps_event_m2d +mac_acl_entry src/ap/ap_config.h /^struct mac_acl_entry {$/;" s +mac_addr src/ap/wpa_auth_ie.h /^ const u8 *mac_addr;$/;" m struct:wpa_eapol_ie_parse +mac_addr src/rsn_supp/wpa_ie.h /^ const u8 *mac_addr;$/;" m struct:wpa_eapol_ie_parse +mac_addr src/wps/wps.h /^ const u8 *mac_addr;$/;" m struct:wps_event_data::wps_event_er_ap +mac_addr src/wps/wps.h /^ const u8 *mac_addr;$/;" m struct:wps_event_data::wps_event_er_enrollee +mac_addr src/wps/wps.h /^ u8 mac_addr[ETH_ALEN];$/;" m struct:wps_credential +mac_addr src/wps/wps.h /^ u8 mac_addr[ETH_ALEN];$/;" m struct:wps_device_data +mac_addr src/wps/wps_attr_parse.h /^ const u8 *mac_addr; \/* ETH_ALEN (6) octets *\/$/;" m struct:wps_parse_attr +mac_addr_e src/wps/wps_i.h /^ u8 mac_addr_e[ETH_ALEN];$/;" m struct:wps_data +mac_addr_len src/ap/wpa_auth_ie.h /^ size_t mac_addr_len;$/;" m struct:wpa_eapol_ie_parse +mac_addr_len src/rsn_supp/wpa_ie.h /^ size_t mac_addr_len;$/;" m struct:wpa_eapol_ie_parse +macaddr src/ap/ap_config.h /^typedef u8 macaddr[ETH_ALEN];$/;" t +macaddr_acl src/ap/ap_config.h /^ } macaddr_acl;$/;" m struct:hostapd_bss_config typeref:enum:hostapd_bss_config::__anon17 +magic src/utils/wpabuf.c /^ unsigned int magic;$/;" m struct:wpabuf_trace file: +manufacturer include/esp_supplicant/esp_wps.h /^ char manufacturer[WPS_MAX_MANUFACTURER_LEN]; \/*!< Manufacturer, null-terminated string. The default manufcturer is used if the string is empty *\/$/;" m struct:__anon89 +manufacturer src/ap/ap_config.h /^ char *manufacturer;$/;" m struct:hostapd_bss_config +manufacturer src/wps/wps.h /^ const char *manufacturer;$/;" m struct:wps_event_data::wps_event_er_ap +manufacturer src/wps/wps.h /^ const char *manufacturer;$/;" m struct:wps_event_data::wps_event_er_enrollee +manufacturer src/wps/wps.h /^ const u8 *manufacturer;$/;" m struct:wps_event_data::wps_event_m2d +manufacturer src/wps/wps.h /^ char *manufacturer;$/;" m struct:wps_device_data +manufacturer src/wps/wps_attr_parse.h /^ const u8 *manufacturer;$/;" m struct:wps_parse_attr +manufacturer_len src/wps/wps.h /^ size_t manufacturer_len;$/;" m struct:wps_event_data::wps_event_m2d +manufacturer_len src/wps/wps_attr_parse.h /^ size_t manufacturer_len;$/;" m struct:wps_parse_attr +manufacturer_url src/ap/ap_config.h /^ char *manufacturer_url;$/;" m struct:hostapd_bss_config +manufacturer_url src/wps/wps.h /^ const char *manufacturer_url;$/;" m struct:wps_event_data::wps_event_er_ap +manufacturer_url src/wps/wps.h /^ char *manufacturer_url;$/;" m struct:wps_context +master_key src/eap_peer/eap_mschapv2.c /^ u8 master_key[MSCHAPV2_MASTER_KEY_LEN];$/;" m struct:eap_mschapv2_data file: +master_key src/eap_peer/eap_ttls.c /^ u8 master_key[MSCHAPV2_MASTER_KEY_LEN]; \/* MSCHAPv2 master key *\/$/;" m struct:eap_ttls_data file: +master_key src/tls/tls.h /^ const u8 *master_key; \/* TLS master secret *\/$/;" m struct:tls_keys +master_key_len src/tls/tls.h /^ size_t master_key_len;$/;" m struct:tls_keys +master_key_valid src/eap_peer/eap_mschapv2.c /^ int master_key_valid;$/;" m struct:eap_mschapv2_data file: +master_secret src/tls/tlsv1_client_i.h /^ u8 master_secret[TLS_MASTER_SECRET_LEN];$/;" m struct:tlsv1_client +master_secret src/tls/tlsv1_server_i.h /^ u8 master_secret[TLS_MASTER_SECRET_LEN];$/;" m struct:tlsv1_server +max_listen_interval src/ap/ap_config.h /^ u16 max_listen_interval;$/;" m struct:hostapd_bss_config +max_num_sta src/ap/ap_config.h /^ int max_num_sta; \/* maximum number of STAs in station table *\/$/;" m struct:hostapd_bss_config +maximum_burst_size src/common/ieee802_11_defs.h /^ le32 maximum_burst_size;$/;" m struct:wmm_tspec_element +maximum_msdu_size src/common/ieee802_11_defs.h /^ le16 maximum_msdu_size;$/;" m struct:wmm_tspec_element +maximum_service_interval src/common/ieee802_11_defs.h /^ le32 maximum_service_interval;$/;" m struct:wmm_tspec_element +md4_vector src/crypto/md4-internal.c /^int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)$/;" f +md5 src/crypto/crypto_internal.c /^ struct MD5Context md5;$/;" m union:crypto_hash::__anon9 typeref:struct:crypto_hash::__anon9::MD5Context file: +md5 src/fast_crypto/fast_crypto_internal.c /^ struct MD5Context md5;$/;" m union:fast_crypto_hash::__anon61 typeref:struct:fast_crypto_hash::__anon61::MD5Context file: +md5_cert src/tls/tlsv1_common.h /^ struct crypto_hash *md5_cert;$/;" m struct:tls_verify_hash typeref:struct:tls_verify_hash::crypto_hash +md5_client src/tls/tlsv1_common.h /^ struct crypto_hash *md5_client;$/;" m struct:tls_verify_hash typeref:struct:tls_verify_hash::crypto_hash +md5_server src/tls/tlsv1_common.h /^ struct crypto_hash *md5_server;$/;" m struct:tls_verify_hash typeref:struct:tls_verify_hash::crypto_hash +md5_vector src/crypto/md5-internal.c /^md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)$/;" f +md5_vector_non_fips_allow include/crypto/crypto.h 64;" d +mdie src/ap/wpa_auth_ie.h /^ const u8 *mdie;$/;" m struct:wpa_eapol_ie_parse +mdie src/rsn_supp/wpa_ie.h /^ const u8 *mdie;$/;" m struct:wpa_eapol_ie_parse +mdie_len src/ap/wpa_auth_ie.h /^ size_t mdie_len;$/;" m struct:wpa_eapol_ie_parse +mdie_len src/rsn_supp/wpa_ie.h /^ size_t mdie_len;$/;" m struct:wpa_eapol_ie_parse +mean_data_rate src/common/ieee802_11_defs.h /^ le32 mean_data_rate;$/;" m struct:wmm_tspec_element +medium_time src/common/ieee802_11_defs.h /^ le16 medium_time;$/;" m struct:wmm_tspec_element +method src/eap_peer/eap.h /^ EapType method;$/;" m struct:eap_method_type +method src/eap_peer/eap_i.h /^ EapType method; $/;" m struct:eap_method +methodState src/eap_peer/eap_i.h /^ EapMethodState methodState;$/;" m struct:eap_method_ret +mgmt_frame_prot src/ap/wpa_auth_i.h /^ unsigned int mgmt_frame_prot:1;$/;" m struct:wpa_state_machine +mgmt_group_cipher src/common/wpa_common.h /^ int mgmt_group_cipher;$/;" m struct:wpa_ie_data +mgmt_group_cipher src/rsn_supp/wpa.h /^ unsigned int mgmt_group_cipher;$/;" m struct:wpa_sm +mic src/common/wpa_common.h /^ u8 mic[16];$/;" m struct:rsn_ftie +mic_control src/common/wpa_common.h /^ u8 mic_control[2];$/;" m struct:rsn_ftie +mic_errors_seen src/rsn_supp/wpa.h /^ int mic_errors_seen; \/* Michael MIC errors with the current PTK *\/$/;" m struct:install_key +mic_failure_report src/ap/wpa_auth.h /^ int (*mic_failure_report)(void *ctx, const u8 *addr);$/;" m struct:wpa_auth_callbacks +minimum_data_rate src/common/ieee802_11_defs.h /^ le32 minimum_data_rate;$/;" m struct:wmm_tspec_element +minimum_phy_rate src/common/ieee802_11_defs.h /^ le32 minimum_phy_rate;$/;" m struct:wmm_tspec_element +minimum_service_interval src/common/ieee802_11_defs.h /^ le32 minimum_service_interval;$/;" m struct:wmm_tspec_element +mobility_domain src/ap/ap_config.h /^ u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];$/;" m struct:hostapd_bss_config +mobility_domain src/ap/wpa_auth.h /^ u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];$/;" m struct:wpa_auth_config +mobility_domain src/common/wpa_common.h /^ u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];$/;" m struct:rsn_mdie +model_description src/ap/ap_config.h /^ char *model_description;$/;" m struct:hostapd_bss_config +model_description src/wps/wps.h /^ const char *model_description;$/;" m struct:wps_event_data::wps_event_er_ap +model_description src/wps/wps.h /^ char *model_description;$/;" m struct:wps_context +model_name include/esp_supplicant/esp_wps.h /^ char model_name[WPS_MAX_MODEL_NAME_LEN]; \/*!< Model name, null-terminated string. The default model name is used if the string is empty *\/$/;" m struct:__anon89 +model_name src/ap/ap_config.h /^ char *model_name;$/;" m struct:hostapd_bss_config +model_name src/wps/wps.h /^ const char *model_name;$/;" m struct:wps_event_data::wps_event_er_ap +model_name src/wps/wps.h /^ const char *model_name;$/;" m struct:wps_event_data::wps_event_er_enrollee +model_name src/wps/wps.h /^ const u8 *model_name;$/;" m struct:wps_event_data::wps_event_m2d +model_name src/wps/wps.h /^ char *model_name;$/;" m struct:wps_device_data +model_name src/wps/wps_attr_parse.h /^ const u8 *model_name;$/;" m struct:wps_parse_attr +model_name_len src/wps/wps.h /^ size_t model_name_len;$/;" m struct:wps_event_data::wps_event_m2d +model_name_len src/wps/wps_attr_parse.h /^ size_t model_name_len;$/;" m struct:wps_parse_attr +model_number include/esp_supplicant/esp_wps.h /^ char model_number[WPS_MAX_MODEL_NUMBER_LEN]; \/*!< Model number, null-terminated string. The default model number is used if the string is empty *\/$/;" m struct:__anon89 +model_number src/ap/ap_config.h /^ char *model_number;$/;" m struct:hostapd_bss_config +model_number src/wps/wps.h /^ const char *model_number;$/;" m struct:wps_event_data::wps_event_er_ap +model_number src/wps/wps.h /^ const char *model_number;$/;" m struct:wps_event_data::wps_event_er_enrollee +model_number src/wps/wps.h /^ const u8 *model_number;$/;" m struct:wps_event_data::wps_event_m2d +model_number src/wps/wps.h /^ char *model_number;$/;" m struct:wps_device_data +model_number src/wps/wps_attr_parse.h /^ const u8 *model_number;$/;" m struct:wps_parse_attr +model_number_len src/wps/wps.h /^ size_t model_number_len;$/;" m struct:wps_event_data::wps_event_m2d +model_number_len src/wps/wps_attr_parse.h /^ size_t model_number_len;$/;" m struct:wps_parse_attr +model_url src/ap/ap_config.h /^ char *model_url;$/;" m struct:hostapd_bss_config +model_url src/wps/wps.h /^ const char *model_url;$/;" m struct:wps_event_data::wps_event_er_ap +model_url src/wps/wps.h /^ char *model_url;$/;" m struct:wps_context +mp_2expt src/crypto/libtommath.h /^mp_2expt (mp_int * a, int b)$/;" f +mp_2expt src/tls/libtommath.h /^mp_2expt (mp_int * a, int b)$/;" f +mp_abs src/crypto/libtommath.h /^mp_abs (mp_int * a, mp_int * b)$/;" f +mp_abs src/tls/libtommath.h /^mp_abs (mp_int * a, mp_int * b)$/;" f +mp_add src/crypto/libtommath.h /^mp_add (mp_int * a, mp_int * b, mp_int * c)$/;" f +mp_add src/tls/libtommath.h /^mp_add (mp_int * a, mp_int * b, mp_int * c)$/;" f +mp_clamp src/crypto/libtommath.h /^mp_clamp (mp_int * a)$/;" f +mp_clamp src/tls/libtommath.h /^mp_clamp (mp_int * a)$/;" f +mp_clear src/crypto/libtommath.h /^mp_clear (mp_int * a)$/;" f +mp_clear src/tls/libtommath.h /^mp_clear (mp_int * a)$/;" f +mp_clear_multi src/crypto/libtommath.h /^mp_clear_multi(mp_int *mp, ...) $/;" f +mp_clear_multi src/tls/libtommath.h /^mp_clear_multi(mp_int *mp, ...) $/;" f +mp_cmp src/crypto/libtommath.h /^mp_cmp (mp_int * a, mp_int * b)$/;" f +mp_cmp src/tls/libtommath.h /^mp_cmp (mp_int * a, mp_int * b)$/;" f +mp_cmp_d src/crypto/libtommath.h /^mp_cmp_d(mp_int * a, mp_digit b)$/;" f +mp_cmp_d src/tls/libtommath.h /^mp_cmp_d(mp_int * a, mp_digit b)$/;" f +mp_cmp_mag src/crypto/libtommath.h /^mp_cmp_mag (mp_int * a, mp_int * b)$/;" f +mp_cmp_mag src/tls/libtommath.h /^mp_cmp_mag (mp_int * a, mp_int * b)$/;" f +mp_copy src/crypto/libtommath.h /^mp_copy (mp_int * a, mp_int * b)$/;" f +mp_copy src/tls/libtommath.h /^mp_copy (mp_int * a, mp_int * b)$/;" f +mp_count_bits src/crypto/libtommath.h /^mp_count_bits (mp_int * a)$/;" f +mp_count_bits src/tls/libtommath.h /^mp_count_bits (mp_int * a)$/;" f +mp_digit src/crypto/libtommath.h /^typedef unsigned long mp_digit;$/;" t +mp_digit src/tls/libtommath.h /^typedef unsigned long mp_digit;$/;" t +mp_div src/crypto/libtommath.h /^mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)$/;" f +mp_div src/crypto/libtommath.h /^mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)$/;" f +mp_div src/tls/libtommath.h /^mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)$/;" f +mp_div src/tls/libtommath.h /^mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)$/;" f +mp_div_2 src/crypto/libtommath.h /^mp_div_2(mp_int * a, mp_int * b)$/;" f +mp_div_2 src/tls/libtommath.h /^mp_div_2(mp_int * a, mp_int * b)$/;" f +mp_div_2d src/crypto/libtommath.h /^mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)$/;" f +mp_div_2d src/tls/libtommath.h /^mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)$/;" f +mp_err src/crypto/libtommath.h /^typedef int mp_err;$/;" t +mp_err src/tls/libtommath.h /^typedef int mp_err;$/;" t +mp_exch src/crypto/libtommath.h /^mp_exch (mp_int * a, mp_int * b)$/;" f +mp_exch src/tls/libtommath.h /^mp_exch (mp_int * a, mp_int * b)$/;" f +mp_exptmod src/crypto/libtommath.h /^mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)$/;" f +mp_exptmod src/tls/libtommath.h /^mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)$/;" f +mp_exptmod_fast src/crypto/libtommath.h /^mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)$/;" f +mp_exptmod_fast src/tls/libtommath.h /^mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)$/;" f +mp_grow src/crypto/libtommath.h /^mp_grow (mp_int * a, int size)$/;" f +mp_grow src/tls/libtommath.h /^mp_grow (mp_int * a, int size)$/;" f +mp_init src/crypto/libtommath.h /^mp_init (mp_int * a)$/;" f +mp_init src/tls/libtommath.h /^mp_init (mp_int * a)$/;" f +mp_init_copy src/crypto/libtommath.h /^mp_init_copy (mp_int * a, mp_int * b)$/;" f +mp_init_copy src/tls/libtommath.h /^mp_init_copy (mp_int * a, mp_int * b)$/;" f +mp_init_multi src/crypto/libtommath.h /^mp_init_multi(mp_int *mp, ...) $/;" f +mp_init_multi src/tls/libtommath.h /^mp_init_multi(mp_int *mp, ...) $/;" f +mp_init_size src/crypto/libtommath.h /^mp_init_size (mp_int * a, int size)$/;" f +mp_init_size src/tls/libtommath.h /^mp_init_size (mp_int * a, int size)$/;" f +mp_int src/crypto/libtommath.h /^} mp_int;$/;" t typeref:struct:__anon8 +mp_int src/tls/libtommath.h /^} mp_int;$/;" t typeref:struct:__anon40 +mp_invmod src/crypto/libtommath.h /^mp_invmod (mp_int * a, mp_int * b, mp_int * c)$/;" f +mp_invmod src/tls/libtommath.h /^mp_invmod (mp_int * a, mp_int * b, mp_int * c)$/;" f +mp_invmod_slow src/crypto/libtommath.h /^mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)$/;" f +mp_invmod_slow src/tls/libtommath.h /^mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)$/;" f +mp_iseven src/crypto/libtommath.h 127;" d +mp_iseven src/tls/libtommath.h 129;" d +mp_isodd src/crypto/libtommath.h 128;" d +mp_isodd src/tls/libtommath.h 130;" d +mp_iszero src/crypto/libtommath.h 126;" d +mp_iszero src/tls/libtommath.h 128;" d +mp_lshd src/crypto/libtommath.h /^mp_lshd (mp_int * a, int b)$/;" f +mp_lshd src/tls/libtommath.h /^mp_lshd (mp_int * a, int b)$/;" f +mp_mod src/crypto/libtommath.h /^mp_mod (mp_int * a, mp_int * b, mp_int * c)$/;" f +mp_mod src/tls/libtommath.h /^mp_mod (mp_int * a, mp_int * b, mp_int * c)$/;" f +mp_mod_2d src/crypto/libtommath.h /^mp_mod_2d (mp_int * a, int b, mp_int * c)$/;" f +mp_mod_2d src/tls/libtommath.h /^mp_mod_2d (mp_int * a, int b, mp_int * c)$/;" f +mp_montgomery_calc_normalization src/crypto/libtommath.h /^mp_montgomery_calc_normalization (mp_int * a, mp_int * b)$/;" f +mp_montgomery_calc_normalization src/tls/libtommath.h /^mp_montgomery_calc_normalization (mp_int * a, mp_int * b)$/;" f +mp_montgomery_setup src/crypto/libtommath.h /^mp_montgomery_setup (mp_int * n, mp_digit * rho)$/;" f +mp_montgomery_setup src/tls/libtommath.h /^mp_montgomery_setup (mp_int * n, mp_digit * rho)$/;" f +mp_mul src/crypto/libtommath.h /^mp_mul (mp_int * a, mp_int * b, mp_int * c)$/;" f +mp_mul src/tls/libtommath.h /^mp_mul (mp_int * a, mp_int * b, mp_int * c)$/;" f +mp_mul_2 src/crypto/libtommath.h /^mp_mul_2(mp_int * a, mp_int * b)$/;" f +mp_mul_2 src/tls/libtommath.h /^mp_mul_2(mp_int * a, mp_int * b)$/;" f +mp_mul_2d src/crypto/libtommath.h /^mp_mul_2d (mp_int * a, int b, mp_int * c)$/;" f +mp_mul_2d src/tls/libtommath.h /^mp_mul_2d (mp_int * a, int b, mp_int * c)$/;" f +mp_mul_d src/crypto/libtommath.h /^mp_mul_d (mp_int * a, mp_digit b, mp_int * c)$/;" f +mp_mul_d src/tls/libtommath.h /^mp_mul_d (mp_int * a, mp_digit b, mp_int * c)$/;" f +mp_mulmod src/crypto/libtommath.h /^mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)$/;" f +mp_mulmod src/tls/libtommath.h /^mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)$/;" f +mp_read_unsigned_bin src/crypto/libtommath.h /^mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)$/;" f +mp_read_unsigned_bin src/tls/libtommath.h /^mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)$/;" f +mp_reduce src/crypto/libtommath.h /^mp_reduce (mp_int * x, mp_int * m, mp_int * mu)$/;" f +mp_reduce src/tls/libtommath.h /^mp_reduce (mp_int * x, mp_int * m, mp_int * mu)$/;" f +mp_reduce_2k_l src/crypto/libtommath.h /^mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)$/;" f +mp_reduce_2k_l src/tls/libtommath.h /^mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)$/;" f +mp_reduce_2k_setup_l src/crypto/libtommath.h /^mp_reduce_2k_setup_l(mp_int *a, mp_int *d)$/;" f +mp_reduce_2k_setup_l src/tls/libtommath.h /^mp_reduce_2k_setup_l(mp_int *a, mp_int *d)$/;" f +mp_reduce_setup src/crypto/libtommath.h /^mp_reduce_setup (mp_int * a, mp_int * b)$/;" f +mp_reduce_setup src/tls/libtommath.h /^mp_reduce_setup (mp_int * a, mp_int * b)$/;" f +mp_rshd src/crypto/libtommath.h /^mp_rshd (mp_int * a, int b)$/;" f +mp_rshd src/tls/libtommath.h /^mp_rshd (mp_int * a, int b)$/;" f +mp_set src/crypto/libtommath.h /^mp_set (mp_int * a, mp_digit b)$/;" f +mp_set src/tls/libtommath.h /^mp_set (mp_int * a, mp_digit b)$/;" f +mp_sqr src/crypto/libtommath.h /^mp_sqr (mp_int * a, mp_int * b)$/;" f +mp_sqr src/tls/libtommath.h /^mp_sqr (mp_int * a, mp_int * b)$/;" f +mp_sub src/crypto/libtommath.h /^mp_sub (mp_int * a, mp_int * b, mp_int * c)$/;" f +mp_sub src/tls/libtommath.h /^mp_sub (mp_int * a, mp_int * b, mp_int * c)$/;" f +mp_to_unsigned_bin src/crypto/libtommath.h /^mp_to_unsigned_bin (mp_int * a, unsigned char *b)$/;" f +mp_to_unsigned_bin src/tls/libtommath.h /^mp_to_unsigned_bin (mp_int * a, unsigned char *b)$/;" f +mp_unsigned_bin_size src/crypto/libtommath.h /^mp_unsigned_bin_size (mp_int * a)$/;" f +mp_unsigned_bin_size src/tls/libtommath.h /^mp_unsigned_bin_size (mp_int * a)$/;" f +mp_word src/crypto/libtommath.h /^typedef u64 mp_word;$/;" t +mp_word src/tls/libtommath.h /^typedef u64 mp_word;$/;" t +mp_zero src/crypto/libtommath.h /^mp_zero (mp_int * a)$/;" f +mp_zero src/tls/libtommath.h /^mp_zero (mp_int * a)$/;" f +ms_change_password src/eap_peer/eap_mschapv2.c /^struct ms_change_password {$/;" s file: +ms_length src/eap_peer/eap_mschapv2.c /^ u8 ms_length[2];$/;" m struct:eap_mschapv2_hdr file: +ms_response src/eap_peer/eap_mschapv2.c /^struct ms_response {$/;" s file: +mschapv2 src/eap_peer/eap_ttls.c /^ u8 *mschapv2;$/;" m struct:ttls_parse_avp file: +mschapv2_derive_response src/eap_peer/mschapv2.c /^int mschapv2_derive_response(const u8 *identity, size_t identity_len,$/;" f +mschapv2_error src/eap_peer/eap_ttls.c /^ int mschapv2_error;$/;" m struct:ttls_parse_avp file: +mschapv2_id src/eap_peer/eap_mschapv2.c /^ u8 mschapv2_id;$/;" m struct:eap_mschapv2_hdr file: +mschapv2_remove_domain src/eap_peer/mschapv2.c /^const u8 * mschapv2_remove_domain(const u8 *username, size_t *len)$/;" f +mschapv2_retry src/eap_peer/eap_config.h /^ int mschapv2_retry;$/;" m struct:eap_peer_config +mschapv2_verify_auth_response src/eap_peer/mschapv2.c /^int mschapv2_verify_auth_response(const u8 *auth_response,$/;" f +msg src/wps/wps.h /^ int msg;$/;" m struct:wps_event_data::wps_event_fail +msg src/wps/wps.h /^ struct wpabuf *msg;$/;" m struct:upnp_pending_message typeref:struct:upnp_pending_message::wpabuf +msg_type src/wps/wps_attr_parse.h /^ const u8 *msg_type; \/* 1 octet *\/$/;" m struct:wps_parse_attr +mui src/common/wpa_common.h /^ be16 mui;$/;" m struct:rsn_error_kde +n src/tls/rsa.c /^ struct bignum *n; \/* modulus (p * q) *\/$/;" m struct:crypto_rsa_key typeref:struct:crypto_rsa_key::bignum file: +nak_type src/eap_peer/eap_tlv_common.h /^ be16 nak_type;$/;" m struct:eap_tlv_nak_tlv +name src/eap_peer/eap_config.h /^ char *name;$/;" m struct:wpa_config_blob +name src/eap_peer/eap_i.h /^ const char *name;$/;" m struct:eap_method +name src/utils/ext_password_i.h /^ const char *name;$/;" m struct:ext_password_backend +network_idx src/wps/wps_attr_parse.h /^ const u8 *network_idx; \/* 1 octet *\/$/;" m struct:wps_parse_attr +network_key src/wps/wps.h /^ u8 *network_key;$/;" m struct:wps_context +network_key src/wps/wps_attr_parse.h /^ const u8 *network_key; \/* <= 64 octets *\/$/;" m struct:wps_parse_attr +network_key_idx src/wps/wps_attr_parse.h /^ const u8 *network_key_idx; \/* 1 octet *\/$/;" m struct:wps_parse_attr +network_key_len src/wps/wps.h /^ size_t network_key_len;$/;" m struct:wps_context +network_key_len src/wps/wps_attr_parse.h /^ size_t network_key_len;$/;" m struct:wps_parse_attr +network_key_shareable src/wps/wps_attr_parse.h /^ const u8 *network_key_shareable; \/* 1 octet (Bool) *\/$/;" m struct:wps_parse_attr +new_ap_settings src/wps/wps.h /^ const struct wps_credential *new_ap_settings;$/;" m struct:wps_config typeref:struct:wps_config::wps_credential +new_ap_settings src/wps/wps_i.h /^ struct wps_credential *new_ap_settings;$/;" m struct:wps_data typeref:struct:wps_data::wps_credential +new_chan src/common/ieee802_11_defs.h /^ u8 new_chan;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon79 +new_password src/eap_peer/eap_config.h /^ u8 *new_password;$/;" m struct:eap_peer_config +new_password_encrypted_with_old_nt_password_hash src/crypto/ms_funcs.c /^int new_password_encrypted_with_old_nt_password_hash($/;" f +new_password_len src/eap_peer/eap_config.h /^ size_t new_password_len;$/;" m struct:eap_peer_config +new_psk src/wps/wps_i.h /^ u8 *new_psk;$/;" m struct:wps_data +new_psk_cb src/wps/wps.h /^ int (*new_psk_cb)(void *ctx, const u8 *mac_addr, const u8 *psk,$/;" m struct:wps_registrar_config +new_psk_cb src/wps/wps_registrar.c /^ int (*new_psk_cb)(void *ctx, const u8 *mac_addr, const u8 *psk,$/;" m struct:wps_registrar file: +new_psk_len src/wps/wps_i.h /^ size_t new_psk_len;$/;" m struct:wps_data +next src/ap/ap_config.h /^ struct hostapd_sta_wpa_psk_short *next;$/;" m struct:hostapd_sta_wpa_psk_short typeref:struct:hostapd_sta_wpa_psk_short::hostapd_sta_wpa_psk_short +next src/ap/ap_config.h /^ struct hostapd_wpa_psk *next;$/;" m struct:hostapd_wpa_psk typeref:struct:hostapd_wpa_psk::hostapd_wpa_psk +next src/ap/sta_info.h /^ struct sta_info *next; \/* next entry in sta list *\/$/;" m struct:sta_info typeref:struct:sta_info::sta_info +next src/ap/wpa_auth.h /^ struct ft_remote_r0kh *next;$/;" m struct:ft_remote_r0kh typeref:struct:ft_remote_r0kh::ft_remote_r0kh +next src/ap/wpa_auth.h /^ struct ft_remote_r1kh *next;$/;" m struct:ft_remote_r1kh typeref:struct:ft_remote_r1kh::ft_remote_r1kh +next src/ap/wpa_auth_i.h /^ struct wpa_group *next;$/;" m struct:wpa_group typeref:struct:wpa_group::wpa_group +next src/ap/wpa_auth_i.h /^ struct wpa_stsl_negotiation *next;$/;" m struct:wpa_stsl_negotiation typeref:struct:wpa_stsl_negotiation::wpa_stsl_negotiation +next src/eap_peer/eap_config.h /^ struct wpa_config_blob *next;$/;" m struct:wpa_config_blob typeref:struct:wpa_config_blob::wpa_config_blob +next src/eap_peer/eap_i.h /^ struct eap_method *next;$/;" m struct:eap_method typeref:struct:eap_method::eap_method +next src/tls/x509v3.h /^ struct x509_certificate *next;$/;" m struct:x509_certificate typeref:struct:x509_certificate::x509_certificate +next src/utils/list.h /^ struct dl_list *next;$/;" m struct:dl_list typeref:struct:dl_list::dl_list +next src/wps/wps.h /^ struct upnp_pending_message *next;$/;" m struct:upnp_pending_message typeref:struct:upnp_pending_message::upnp_pending_message +next src/wps/wps_registrar.c /^ struct wps_pbc_session *next;$/;" m struct:wps_pbc_session typeref:struct:wps_pbc_session::wps_pbc_session file: +next src/wps/wps_registrar.c /^ struct wps_registrar_device *next;$/;" m struct:wps_registrar_device typeref:struct:wps_registrar_device::wps_registrar_device file: +nfc_pw_token src/wps/wps_i.h /^ struct wps_nfc_pw_token *nfc_pw_token;$/;" m struct:wps_data typeref:struct:wps_data::wps_nfc_pw_token +nfc_pw_tokens src/wps/wps_registrar.c /^ struct dl_list nfc_pw_tokens;$/;" m struct:wps_registrar typeref:struct:wps_registrar::dl_list file: +noa_duration src/ap/hostapd.h /^ int noa_duration;$/;" m struct:hostapd_data +noa_enabled src/ap/hostapd.h /^ int noa_enabled;$/;" m struct:hostapd_data +noa_start src/ap/hostapd.h /^ int noa_start;$/;" m struct:hostapd_data +nominal_msdu_size src/common/ieee802_11_defs.h /^ le16 nominal_msdu_size;$/;" m struct:wmm_tspec_element +nonce src/ap/wpa_auth.h /^ u8 nonce[16]; \/* copied from pull *\/$/;" m struct:ft_r0kh_r1kh_resp_frame +nonce src/ap/wpa_auth.h /^ u8 nonce[16];$/;" m struct:ft_r0kh_r1kh_pull_frame +nonce src/ap/wpa_auth_ie.h /^ const u8 *nonce;$/;" m struct:wpa_eapol_ie_parse +nonce src/eap_peer/eap_tlv_common.h /^ u8 nonce[32];$/;" m struct:eap_tlv_crypto_binding_tlv +nonce src/rsn_supp/wpa_ie.h /^ const u8 *nonce;$/;" m struct:wpa_eapol_ie_parse +nonce_e src/wps/wps_i.h /^ u8 nonce_e[WPS_NONCE_LEN];$/;" m struct:wps_data +nonce_len src/ap/wpa_auth_ie.h /^ size_t nonce_len;$/;" m struct:wpa_eapol_ie_parse +nonce_len src/rsn_supp/wpa_ie.h /^ size_t nonce_len;$/;" m struct:wpa_eapol_ie_parse +nonce_r src/wps/wps_i.h /^ u8 nonce_r[WPS_NONCE_LEN];$/;" m struct:wps_data +not_after src/tls/x509v3.h /^ os_time_t not_after;$/;" m struct:x509_certificate +not_before src/tls/x509v3.h /^ os_time_t not_before;$/;" m struct:x509_certificate +nt_challenge_response src/crypto/ms_funcs.c /^int nt_challenge_response(const u8 *challenge, const u8 *password,$/;" f +nt_password_hash src/crypto/ms_funcs.c /^int nt_password_hash(const u8 *password, size_t password_len,$/;" f +nt_password_hash_encrypted_with_block src/crypto/ms_funcs.c /^void nt_password_hash_encrypted_with_block(const u8 *password_hash,$/;" f +nt_response src/eap_peer/eap_mschapv2.c /^ u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN];$/;" m struct:ms_change_password file: +nt_response src/eap_peer/eap_mschapv2.c /^ u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN];$/;" m struct:ms_response file: +num_attr src/tls/x509v3.h /^ size_t num_attr;$/;" m struct:x509_name +num_bits_set src/wps/wps_validate.c /^static int num_bits_set(u16 val)$/;" f file: +num_bss src/ap/ap_config.h /^ size_t num_bss;$/;" m struct:hostapd_config +num_cipher_suites src/tls/tlsv1_client_i.h /^ size_t num_cipher_suites;$/;" m struct:tlsv1_client +num_cipher_suites src/tls/tlsv1_server_i.h /^ size_t num_cipher_suites;$/;" m struct:tlsv1_server +num_cred src/wps/wps_attr_parse.h /^ size_t num_cred;$/;" m struct:wps_parse_attr +num_phase2_eap_types src/eap_peer/eap_ttls.c /^ size_t num_phase2_eap_types;$/;" m struct:eap_ttls_data file: +num_phase2_types src/eap_peer/eap_peap.c /^ size_t num_phase2_types;$/;" m struct:eap_peap_data file: +num_pmkid src/common/wpa_common.h /^ size_t num_pmkid;$/;" m struct:wpa_ie_data +num_req_dev_type src/wps/wps_attr_parse.h /^ size_t num_req_dev_type;$/;" m struct:wps_parse_attr +num_sec_dev_types src/wps/wps.h /^ u8 num_sec_dev_types;$/;" m struct:wps_device_data +num_sta src/ap/hostapd.h /^ int num_sta; \/* number of entries in sta_list *\/$/;" m struct:hostapd_data +num_sta_no_p2p src/ap/hostapd.h /^ int num_sta_no_p2p;$/;" m struct:hostapd_data +num_vendor_ext src/wps/wps_attr_parse.h /^ size_t num_vendor_ext;$/;" m struct:wps_parse_attr +ocsp src/eap_peer/eap_config.h /^ int ocsp;$/;" m struct:eap_peer_config +ocsp_stapling_response src/tls/tls.h /^ const char *ocsp_stapling_response;$/;" m struct:tls_connection_params +offsetof src/utils/list.h 70;" d +oid src/tls/asn1.h /^ unsigned long oid[ASN1_MAX_OID_LEN];$/;" m struct:asn1_oid +oid src/tls/x509v3.h /^ struct asn1_oid oid;$/;" m struct:x509_algorithm_identifier typeref:struct:x509_algorithm_identifier::asn1_oid +okc src/ap/wpa_auth.h /^ int okc;$/;" m struct:wpa_auth_config +old_nt_password_hash_encrypted_with_new_nt_password_hash src/crypto/ms_funcs.c /^int old_nt_password_hash_encrypted_with_new_nt_password_hash($/;" f +oob_dev_password src/wps/wps_attr_parse.h /^ const u8 *oob_dev_password; \/* 38..54 octets *\/$/;" m struct:wps_parse_attr +oob_dev_password_len src/wps/wps_attr_parse.h /^ size_t oob_dev_password_len;$/;" m struct:wps_parse_attr +op_code src/eap_peer/eap_mschapv2.c /^ u8 op_code;$/;" m struct:eap_mschapv2_hdr file: +opcode src/eap_peer/eap_defs.h /^ u8 opcode;$/;" m struct:eap_expand +opensc_engine_path src/tls/tls.h /^ const char *opensc_engine_path;$/;" m struct:tls_config +operation_mode src/common/ieee802_11_defs.h /^ le16 operation_mode;$/;" m struct:ieee80211_ht_operation +os_bzero port/include/os.h 206;" d +os_free port/include/os.h 202;" d +os_get_random port/os_xtensa.c /^int os_get_random(unsigned char *buf, size_t len)$/;" f +os_get_time port/os_xtensa.c /^int os_get_time(struct os_time *t)$/;" f +os_malloc port/include/os.h 193;" d +os_memcmp port/include/os.h 229;" d +os_memcpy port/include/os.h 220;" d +os_memmove port/include/os.h 223;" d +os_memset port/include/os.h 226;" d +os_random port/os_xtensa.c /^unsigned long os_random(void)$/;" f +os_realloc port/include/os.h 196;" d +os_snprintf port/include/os.h 271;" d +os_snprintf port/include/os.h 273;" d +os_strcasecmp port/include/os.h 237;" d +os_strcasecmp port/include/os.h 239;" d +os_strchr port/include/os.h 250;" d +os_strcmp port/include/os.h 253;" d +os_strdup port/include/os.h 212;" d +os_strdup port/include/os.h 214;" d +os_strlen port/include/os.h 233;" d +os_strncasecmp port/include/os.h 244;" d +os_strncasecmp port/include/os.h 246;" d +os_strncmp port/include/os.h 256;" d +os_strncpy port/include/os.h 259;" d +os_strrchr port/include/os.h 263;" d +os_strstr port/include/os.h 266;" d +os_time port/include/os.h /^struct os_time {$/;" s +os_time_before port/include/os.h 48;" d +os_time_sub port/include/os.h 52;" d +os_time_t port/include/os.h /^typedef long os_time_t;$/;" t +os_version src/ap/ap_config.h /^ u8 os_version[4];$/;" m struct:hostapd_bss_config +os_version src/wps/wps.h /^ u32 os_version;$/;" m struct:wps_device_data +os_version src/wps/wps_attr_parse.h /^ const u8 *os_version; \/* 4 octets *\/$/;" m struct:wps_parse_attr +os_zalloc port/include/os.h 199;" d +oui src/common/ieee802_11_defs.h /^ u8 oui[3]; \/* 00:50:f2 *\/$/;" m struct:wmm_information_element +oui src/common/ieee802_11_defs.h /^ u8 oui[3]; \/* 00:50:f2 *\/$/;" m struct:wmm_parameter_element +oui src/common/ieee802_11_defs.h /^ u8 oui[3]; \/* 00:50:f2 *\/$/;" m struct:wmm_tspec_element +oui src/common/wpa_common.h /^ u8 oui[4]; \/* 24-bit OUI followed by 8-bit OUI type *\/$/;" m struct:wpa_ie_hdr +oui_subtype src/common/ieee802_11_defs.h /^ u8 oui_subtype; \/* 0 *\/$/;" m struct:wmm_information_element +oui_subtype src/common/ieee802_11_defs.h /^ u8 oui_subtype; \/* 1 *\/$/;" m struct:wmm_parameter_element +oui_subtype src/common/ieee802_11_defs.h /^ u8 oui_subtype; \/* 2 *\/$/;" m struct:wmm_tspec_element +oui_type src/common/ieee802_11_defs.h /^ u8 oui_type; \/* 2 *\/$/;" m struct:wmm_information_element +oui_type src/common/ieee802_11_defs.h /^ u8 oui_type; \/* 2 *\/$/;" m struct:wmm_parameter_element +oui_type src/common/ieee802_11_defs.h /^ u8 oui_type; \/* 2 *\/$/;" m struct:wmm_tspec_element +outbuf src/eap_peer/eap_i.h /^ struct pbuf *outbuf;$/;" m struct:eap_sm typeref:struct:eap_sm::pbuf +own_addr src/ap/hostapd.h /^ u8 own_addr[ETH_ALEN];$/;" m struct:hostapd_data +own_addr src/rsn_supp/wpa.h /^ u8 own_addr[ETH_ALEN];$/;" m struct:wpa_sm +ownaddr src/eap_peer/eap_i.h /^ u8 ownaddr[ETH_ALEN];$/;" m struct:eap_sm +ownaddr src/wps/wps.h /^ u8 ownaddr[ETH_ALEN];$/;" m struct:wps_sm +p src/tls/rsa.c /^ struct bignum *p; \/* prime p (factor of n) *\/$/;" m struct:crypto_rsa_key typeref:struct:crypto_rsa_key::bignum file: +p2p src/ap/hostapd.h /^ struct p2p_data *p2p;$/;" m struct:hostapd_data typeref:struct:hostapd_data::p2p_data +p2p src/wps/wps.h /^ int p2p;$/;" m struct:wps_device_data +p2p_beacon_ie src/ap/hostapd.h /^ struct wpabuf *p2p_beacon_ie;$/;" m struct:hostapd_data typeref:struct:hostapd_data::wpabuf +p2p_dev_addr src/wps/wps.h /^ const u8 *p2p_dev_addr;$/;" m struct:wps_config +p2p_dev_addr src/wps/wps_i.h /^ u8 p2p_dev_addr[ETH_ALEN]; \/* P2P Device Address of the client or$/;" m struct:wps_data +p2p_dev_addr src/wps/wps_registrar.c /^ u8 p2p_dev_addr[ETH_ALEN];$/;" m struct:wps_registrar file: +p2p_group src/ap/hostapd.h /^ struct p2p_group *p2p_group;$/;" m struct:hostapd_data typeref:struct:hostapd_data::p2p_group +p2p_probe_resp_ie src/ap/hostapd.h /^ struct wpabuf *p2p_probe_resp_ie;$/;" m struct:hostapd_data typeref:struct:hostapd_data::wpabuf +pac_len src/eap_peer/eap_tlv_common.h /^ be16 pac_len;$/;" m struct:eap_tlv_pac_ack_tlv +pac_type src/eap_peer/eap_tlv_common.h /^ be16 pac_type;$/;" m struct:eap_tlv_pac_ack_tlv +pac_type src/eap_peer/eap_tlv_common.h /^ be16 pac_type;$/;" m struct:eap_tlv_pac_type_tlv +packet_type src/ap/wpa_auth.h /^ u8 packet_type; \/* FT_PACKET_R0KH_R1KH_PULL *\/$/;" m struct:ft_r0kh_r1kh_pull_frame +packet_type src/ap/wpa_auth.h /^ u8 packet_type; \/* FT_PACKET_R0KH_R1KH_PUSH *\/$/;" m struct:ft_r0kh_r1kh_push_frame +packet_type src/ap/wpa_auth.h /^ u8 packet_type; \/* FT_PACKET_R0KH_R1KH_RESP *\/$/;" m struct:ft_r0kh_r1kh_resp_frame +packet_type src/ap/wpa_auth.h /^ u8 packet_type; \/* FT_PACKET_REQUEST\/FT_PACKET_RESPONSE *\/$/;" m struct:ft_rrb_frame +pad src/ap/wpa_auth.h /^ u8 pad[2]; \/* 8-octet boundary for AES key wrap *\/$/;" m struct:ft_r0kh_r1kh_resp_frame +pad src/ap/wpa_auth.h /^ u8 pad[4]; \/* 8-octet boundary for AES key wrap *\/$/;" m struct:ft_r0kh_r1kh_pull_frame +pad src/ap/wpa_auth.h /^ u8 pad[6]; \/* 8-octet boundary for AES key wrap *\/$/;" m struct:ft_r0kh_r1kh_push_frame +pairwise src/ap/wpa_auth.h /^ le16 pairwise;$/;" m struct:ft_r0kh_r1kh_push_frame +pairwise src/ap/wpa_auth.h /^ le16 pairwise;$/;" m struct:ft_r0kh_r1kh_resp_frame +pairwise src/ap/wpa_auth_i.h /^ int pairwise; \/* Pairwise cipher suite, WPA_CIPHER_* *\/$/;" m struct:wpa_state_machine +pairwise_cipher src/common/wpa_common.h /^ int pairwise_cipher;$/;" m struct:wpa_ie_data +pairwise_cipher src/rsn_supp/wpa.h /^ unsigned int pairwise_cipher;$/;" m struct:wpa_sm +pairwise_set src/ap/wpa_auth_i.h /^ Boolean pairwise_set;$/;" m struct:wpa_state_machine +param src/esp_supplicant/esp_wifi_driver.h /^ void *param;$/;" m struct:__anon31 +part src/wps/wps.h /^ int part;$/;" m struct:wps_event_data::wps_event_pwd_auth_fail +partial_input src/tls/tlsv1_client_i.h /^ struct wpabuf *partial_input;$/;" m struct:tlsv1_client typeref:struct:tlsv1_client::wpabuf +passwd_change_challenge src/eap_peer/eap_mschapv2.c /^ u8 passwd_change_challenge[PASSWD_CHANGE_CHAL_LEN];$/;" m struct:eap_mschapv2_data file: +passwd_change_challenge_valid src/eap_peer/eap_mschapv2.c /^ int passwd_change_challenge_valid;$/;" m struct:eap_mschapv2_data file: +passwd_change_version src/eap_peer/eap_mschapv2.c /^ int passwd_change_version;$/;" m struct:eap_mschapv2_data file: +password src/eap_peer/eap_config.h /^ u8 *password;$/;" m struct:eap_peer_config +password_len src/eap_peer/eap_config.h /^ size_t password_len;$/;" m struct:eap_peer_config +path_len_constraint src/tls/x509v3.h /^ unsigned long path_len_constraint; \/* pathLenConstraint *\/$/;" m struct:x509_certificate +payload src/tls/asn1.h /^ const u8 *payload;$/;" m struct:asn1_hdr +pbc src/wps/wps.h /^ int pbc;$/;" m struct:wps_config +pbc src/wps/wps_i.h /^ int pbc;$/;" m struct:wps_data +pbc src/wps/wps_registrar.c /^ int pbc;$/;" m struct:wps_registrar file: +pbc_ignore_start src/wps/wps_registrar.c /^ struct os_time pbc_ignore_start;$/;" m struct:wps_registrar typeref:struct:wps_registrar::os_time file: +pbc_ignore_uuid src/wps/wps_registrar.c /^ u8 pbc_ignore_uuid[WPS_UUID_LEN];$/;" m struct:wps_registrar file: +pbc_in_m1 src/wps/wps.h /^ int pbc_in_m1;$/;" m struct:wps_config +pbc_in_m1 src/wps/wps_i.h /^ int pbc_in_m1;$/;" m struct:wps_data +pbc_sessions src/wps/wps_registrar.c /^ struct wps_pbc_session *pbc_sessions;$/;" m struct:wps_registrar typeref:struct:wps_registrar::wps_pbc_session file: +pbkdf2_sha1 src/crypto/sha1-pbkdf2.c /^pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,$/;" f +pbkdf2_sha1_f src/crypto/sha1-pbkdf2.c /^pbkdf2_sha1_f(const char *passphrase, const char *ssid,$/;" f file: +pc1 src/crypto/des-internal.c /^static const u8 pc1[56] = {$/;" v file: +pc2 src/crypto/des-internal.c /^static const u8 pc2[48] = {$/;" v file: +peak_data_rate src/common/ieee802_11_defs.h /^ le32 peak_data_rate;$/;" m struct:wmm_tspec_element +peap_done src/eap_peer/eap_i.h /^ bool peap_done;$/;" m struct:eap_sm +peap_outer_success src/eap_peer/eap_peap.c /^ int peap_outer_success; \/* 0 = PEAP terminated on Phase 2 inner$/;" m struct:eap_peap_data file: +peap_prfplus src/eap_peer/eap_peap_common.c /^peap_prfplus(int version, const u8 *key, size_t key_len,$/;" f +peap_version src/eap_peer/eap_peap.c /^ int peap_version, force_peap_version, force_new_label;$/;" m struct:eap_peap_data file: +peer src/ap/wpa_auth_i.h /^ u8 peer[ETH_ALEN];$/;" m struct:wpa_stsl_negotiation +peer_addr src/wps/wps.h /^ const u8 *peer_addr;$/;" m struct:wps_config +peer_cert src/tls/tls.h /^ } peer_cert;$/;" m union:tls_event_data typeref:struct:tls_event_data::__anon35 +peer_challenge src/eap_peer/eap_mschapv2.c /^ u8 *peer_challenge;$/;" m struct:eap_mschapv2_data file: +peer_challenge src/eap_peer/eap_mschapv2.c /^ u8 peer_challenge[MSCHAPV2_CHAL_LEN];$/;" m struct:ms_change_password file: +peer_challenge src/eap_peer/eap_mschapv2.c /^ u8 peer_challenge[MSCHAPV2_CHAL_LEN];$/;" m struct:ms_response file: +peer_dev src/wps/wps_i.h /^ struct wps_device_data peer_dev;$/;" m struct:wps_data typeref:struct:wps_data::wps_device_data +peer_hash1 src/wps/wps_i.h /^ u8 peer_hash1[WPS_HASH_LEN];$/;" m struct:wps_data +peer_hash2 src/wps/wps_i.h /^ u8 peer_hash2[WPS_HASH_LEN];$/;" m struct:wps_data +peerkey src/ap/ap_config.h /^ int peerkey;$/;" m struct:hostapd_bss_config +peerkey src/ap/wpa_auth.h /^ int peerkey;$/;" m struct:wpa_auth_config +pem_cert_begin src/tls/tlsv1_cred.c /^static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";$/;" v file: +pem_cert_end src/tls/tlsv1_cred.c /^static const char *pem_cert_end = "-----END CERTIFICATE-----";$/;" v file: +pem_dhparams_begin src/tls/tlsv1_cred.c /^static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----";$/;" v file: +pem_dhparams_end src/tls/tlsv1_cred.c /^static const char *pem_dhparams_end = "-----END DH PARAMETERS-----";$/;" v file: +pem_key2_begin src/tls/tlsv1_cred.c /^static const char *pem_key2_begin = "-----BEGIN PRIVATE KEY-----";$/;" v file: +pem_key2_end src/tls/tlsv1_cred.c /^static const char *pem_key2_end = "-----END PRIVATE KEY-----";$/;" v file: +pem_key_begin src/tls/tlsv1_cred.c /^static const char *pem_key_begin = "-----BEGIN RSA PRIVATE KEY-----";$/;" v file: +pem_key_enc_begin src/tls/tlsv1_cred.c /^static const char *pem_key_enc_begin = "-----BEGIN ENCRYPTED PRIVATE KEY-----";$/;" v file: +pem_key_enc_end src/tls/tlsv1_cred.c /^static const char *pem_key_enc_end = "-----END ENCRYPTED PRIVATE KEY-----";$/;" v file: +pem_key_end src/tls/tlsv1_cred.c /^static const char *pem_key_end = "-----END RSA PRIVATE KEY-----";$/;" v file: +pending_1_of_4_timeout src/ap/wpa_auth_i.h /^ int pending_1_of_4_timeout;$/;" m struct:wpa_state_machine +pending_deinit src/ap/wpa_auth_i.h /^ unsigned int pending_deinit:1;$/;" m struct:wpa_state_machine +pending_phase2_req src/eap_peer/eap_peap.c /^ struct wpabuf *pending_phase2_req;$/;" m struct:eap_peap_data typeref:struct:eap_peap_data::wpabuf file: +pending_phase2_req src/eap_peer/eap_ttls.c /^ struct wpabuf *pending_phase2_req;$/;" m struct:eap_ttls_data typeref:struct:eap_ttls_data::wpabuf file: +phase1 src/eap_peer/eap_config.h /^ char *phase1;$/;" m struct:eap_peer_config +phase2 src/eap_peer/eap_config.h /^ char *phase2;$/;" m struct:eap_peer_config +phase2 src/eap_peer/eap_mschapv2.c /^ int phase2;$/;" m struct:eap_mschapv2_data file: +phase2 src/eap_peer/eap_tls_common.h /^ int phase2;$/;" m struct:eap_ssl_data +phase2_eap_started src/eap_peer/eap_peap.c /^ int phase2_eap_started;$/;" m struct:eap_peap_data file: +phase2_eap_success src/eap_peer/eap_peap.c /^ int phase2_eap_success;$/;" m struct:eap_peap_data file: +phase2_eap_type src/eap_peer/eap_ttls.c /^ struct eap_method_type phase2_eap_type;$/;" m struct:eap_ttls_data typeref:struct:eap_ttls_data::eap_method_type file: +phase2_eap_types src/eap_peer/eap_ttls.c /^ struct eap_method_type *phase2_eap_types;$/;" m struct:eap_ttls_data typeref:struct:eap_ttls_data::eap_method_type file: +phase2_method src/eap_peer/eap_peap.c /^ const struct eap_method *phase2_method;$/;" m struct:eap_peap_data typeref:struct:eap_peap_data::eap_method file: +phase2_method src/eap_peer/eap_ttls.c /^ const struct eap_method *phase2_method;$/;" m struct:eap_ttls_data typeref:struct:eap_ttls_data::eap_method file: +phase2_priv src/eap_peer/eap_peap.c /^ void *phase2_priv;$/;" m struct:eap_peap_data file: +phase2_priv src/eap_peer/eap_ttls.c /^ void *phase2_priv;$/;" m struct:eap_ttls_data file: +phase2_start src/eap_peer/eap_ttls.c /^ int phase2_start;$/;" m struct:eap_ttls_data file: +phase2_success src/eap_peer/eap_peap.c /^ int phase2_success;$/;" m struct:eap_peap_data file: +phase2_success src/eap_peer/eap_ttls.c /^ int phase2_success;$/;" m struct:eap_ttls_data file: +phase2_type src/eap_peer/eap_peap.c /^ struct eap_method_type phase2_type;$/;" m struct:eap_peap_data typeref:struct:eap_peap_data::eap_method_type file: +phase2_type src/eap_peer/eap_ttls.c /^ } phase2_type;$/;" m struct:eap_ttls_data typeref:enum:eap_ttls_data::phase2_types file: +phase2_types src/eap_peer/eap_peap.c /^ struct eap_method_type *phase2_types;$/;" m struct:eap_peap_data typeref:struct:eap_peap_data::eap_method_type file: +phase2_types src/eap_peer/eap_ttls.c /^ enum phase2_types {$/;" g struct:eap_ttls_data file: +pin src/eap_peer/eap_config.h /^ char *pin;$/;" m struct:eap_peer_config +pin src/tls/tls.h /^ const char *pin;$/;" m struct:tls_connection_params +pin src/wps/wps.h /^ const u8 *pin;$/;" m struct:wps_config +pin src/wps/wps_registrar.c /^ u8 *pin;$/;" m struct:wps_uuid_pin file: +pin_len src/wps/wps.h /^ size_t pin_len;$/;" m struct:wps_config +pin_len src/wps/wps_registrar.c /^ size_t pin_len;$/;" m struct:wps_uuid_pin file: +pin_needed_cb src/wps/wps.h /^ void (*pin_needed_cb)(void *ctx, const u8 *uuid_e,$/;" m struct:wps_registrar_config +pin_needed_cb src/wps/wps_registrar.c /^ void (*pin_needed_cb)(void *ctx, const u8 *uuid_e,$/;" m struct:wps_registrar file: +pins src/wps/wps_registrar.c /^ struct dl_list pins;$/;" m struct:wps_registrar typeref:struct:wps_registrar::dl_list file: +pkcs11_engine_path src/tls/tls.h /^ const char *pkcs11_engine_path;$/;" m struct:tls_config +pkcs11_module_path src/tls/tls.h /^ const char *pkcs11_module_path;$/;" m struct:tls_config +pkcs1_decrypt_public_key src/tls/pkcs1.c /^int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,$/;" f +pkcs1_encrypt src/tls/pkcs1.c /^int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key,$/;" f +pkcs1_generate_encryption_block src/tls/pkcs1.c /^static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,$/;" f file: +pkcs1_v15_private_key_decrypt src/tls/pkcs1.c /^int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key,$/;" f +pkcs5_alg src/tls/pkcs5.c /^ enum pkcs5_alg {$/;" g struct:pkcs5_params file: +pkcs5_crypto_init src/tls/pkcs5.c /^static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,$/;" f file: +pkcs5_decrypt src/tls/pkcs5.c /^u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len,$/;" f +pkcs5_get_alg src/tls/pkcs5.c /^static enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)$/;" f file: +pkcs5_get_params src/tls/pkcs5.c /^static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,$/;" f file: +pkcs5_params src/tls/pkcs5.c /^struct pkcs5_params {$/;" s file: +pkcs8_enc_key_import src/tls/pkcs8.c /^pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd)$/;" f +pkcs8_key_import src/tls/pkcs8.c /^struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)$/;" f +pmk src/rsn_supp/wpa.h /^ u8 pmk[PMK_LEN];$/;" m struct:wpa_sm +pmk_len src/rsn_supp/wpa.h /^ size_t pmk_len;$/;" m struct:wpa_sm +pmk_r0_name src/ap/wpa_auth.h /^ u8 pmk_r0_name[WPA_PMK_NAME_LEN];$/;" m struct:ft_r0kh_r1kh_pull_frame +pmk_r0_name src/ap/wpa_auth.h /^ u8 pmk_r0_name[WPA_PMK_NAME_LEN];$/;" m struct:ft_r0kh_r1kh_push_frame +pmk_r1 src/ap/wpa_auth.h /^ u8 pmk_r1[PMK_LEN];$/;" m struct:ft_r0kh_r1kh_push_frame +pmk_r1 src/ap/wpa_auth.h /^ u8 pmk_r1[PMK_LEN];$/;" m struct:ft_r0kh_r1kh_resp_frame +pmk_r1_name src/ap/wpa_auth.h /^ u8 pmk_r1_name[WPA_PMK_NAME_LEN];$/;" m struct:ft_r0kh_r1kh_push_frame +pmk_r1_name src/ap/wpa_auth.h /^ u8 pmk_r1_name[WPA_PMK_NAME_LEN];$/;" m struct:ft_r0kh_r1kh_resp_frame +pmk_r1_name src/ap/wpa_auth_i.h /^ u8 pmk_r1_name[WPA_PMK_NAME_LEN]; \/* PMKR1Name derived from FT Auth$/;" m struct:wpa_state_machine +pmk_r1_name_valid src/ap/wpa_auth_i.h /^ unsigned int pmk_r1_name_valid:1;$/;" m struct:wpa_state_machine +pmk_r1_push src/ap/ap_config.h /^ int pmk_r1_push;$/;" m struct:hostapd_bss_config +pmk_r1_push src/ap/wpa_auth.h /^ int pmk_r1_push;$/;" m struct:wpa_auth_config +pmkid src/ap/wpa_auth_ie.h /^ const u8 *pmkid;$/;" m struct:wpa_eapol_ie_parse +pmkid src/common/wpa_common.h /^ const u8 *pmkid;$/;" m struct:wpa_ie_data +pmkid src/rsn_supp/wpa_ie.h /^ const u8 *pmkid;$/;" m struct:wpa_eapol_ie_parse +pn src/common/wpa_common.h /^ u8 pn[6];$/;" m struct:wpa_igtk_kde +pp_michael_mic_failure src/rsn_supp/wpa.c /^pp_michael_mic_failure(u16 isunicast)$/;" f +preamble src/ap/ap_config.h /^ } preamble;$/;" m struct:hostapd_config typeref:enum:hostapd_config::__anon19 +prev src/utils/list.h /^ struct dl_list *prev;$/;" m struct:dl_list typeref:struct:dl_list::dl_list +prev_challenge src/eap_peer/eap_mschapv2.c /^ struct wpabuf *prev_challenge;$/;" m struct:eap_mschapv2_data typeref:struct:eap_mschapv2_data::wpabuf file: +prev_cipher_suite src/tls/tlsv1_client_i.h /^ u16 prev_cipher_suite;$/;" m struct:tlsv1_client +prev_error src/eap_peer/eap_mschapv2.c /^ int prev_error;$/;" m struct:eap_mschapv2_data file: +prev_key_replay src/ap/wpa_auth_i.h /^ prev_key_replay[RSNA_MAX_EAPOL_RETRIES];$/;" m struct:wpa_state_machine typeref:struct:wpa_state_machine::wpa_key_replay_counter +pri_dev_type src/wps/wps.h /^ const u8 *pri_dev_type;$/;" m struct:wps_event_data::wps_event_er_ap +pri_dev_type src/wps/wps.h /^ const u8 *pri_dev_type;$/;" m struct:wps_event_data::wps_event_er_enrollee +pri_dev_type src/wps/wps.h /^ u8 pri_dev_type[WPS_DEV_TYPE_LEN];$/;" m struct:wps_device_data +primary_dev_type src/wps/wps.h /^ const u8 *primary_dev_type; \/* 8 octets *\/$/;" m struct:wps_event_data::wps_event_m2d +primary_dev_type src/wps/wps_attr_parse.h /^ const u8 *primary_dev_type; \/* 8 octets *\/$/;" m struct:wps_parse_attr +prime include/crypto/dh_groups.h /^ const u8 *prime;$/;" m struct:dh_group +prime_len include/crypto/dh_groups.h /^ size_t prime_len;$/;" m struct:dh_group +priv src/utils/ext_password.c /^ void *priv;$/;" m struct:ext_password_data file: +private_key src/eap_peer/eap_config.h /^ u8 *private_key;$/;" m struct:eap_peer_config +private_key src/tls/rsa.c /^ int private_key; \/* whether private key is set *\/$/;" m struct:crypto_rsa_key file: +private_key src/tls/tls.h /^ const char *private_key;$/;" m struct:tls_connection_params +private_key2 src/eap_peer/eap_config.h /^ u8 *private_key2;$/;" m struct:eap_peer_config +private_key2_password src/eap_peer/eap_config.h /^ u8 *private_key2_password;$/;" m struct:eap_peer_config +private_key_blob src/tls/tls.h /^ const u8 *private_key_blob;$/;" m struct:tls_connection_params +private_key_blob_len src/tls/tls.h /^ size_t private_key_blob_len;$/;" m struct:tls_connection_params +private_key_passwd src/eap_peer/eap_config.h /^ const u8 *private_key_passwd;$/;" m struct:eap_peer_config +private_key_passwd src/tls/tls.h /^ const char *private_key_passwd;$/;" m struct:tls_connection_params +probe_req src/common/ieee802_11_defs.h /^ } STRUCT_PACKED probe_req;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon74 +probe_resp src/common/ieee802_11_defs.h /^ } STRUCT_PACKED probe_resp;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon75 +process src/eap_peer/eap_i.h /^ struct wpabuf * (*process)(struct eap_sm *sm, void *priv,$/;" m struct:eap_method typeref:struct:eap_method::process +proto src/common/wpa_common.h /^ int proto;$/;" m struct:wpa_ie_data +proto src/rsn_supp/wpa.h /^ unsigned int proto;$/;" m struct:wpa_sm +psk src/ap/ap_config.h /^ u8 psk[PMK_LEN];$/;" m struct:hostapd_sta_wpa_psk_short +psk src/ap/ap_config.h /^ u8 psk[PMK_LEN];$/;" m struct:hostapd_wpa_psk +psk src/wps/wps.h /^ u8 psk[32];$/;" m struct:wps_context +psk1 src/wps/wps_i.h /^ u8 psk1[WPS_PSK_LEN];$/;" m struct:wps_data +psk2 src/wps/wps_i.h /^ u8 psk2[WPS_PSK_LEN];$/;" m struct:wps_data +psk_set src/wps/wps.h /^ int psk_set;$/;" m struct:wps_context +ptk src/rsn_supp/wpa.h /^ struct wpa_ptk ptk, tptk;$/;" m struct:wpa_sm typeref:struct:wpa_sm::wpa_ptk +ptk_set src/rsn_supp/wpa.h /^ int ptk_set, tptk_set;$/;" m struct:wpa_sm +pubkey_hash src/wps/wps_registrar.c /^ u8 pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN];$/;" m struct:wps_nfc_pw_token file: +public_key src/tls/x509v3.h /^ u8 *public_key;$/;" m struct:x509_certificate +public_key src/wps/wps_attr_parse.h /^ const u8 *public_key;$/;" m struct:wps_parse_attr +public_key_alg src/tls/x509v3.h /^ struct x509_algorithm_identifier public_key_alg;$/;" m struct:x509_certificate typeref:struct:x509_certificate::x509_algorithm_identifier +public_key_len src/tls/x509v3.h /^ size_t public_key_len;$/;" m struct:x509_certificate +public_key_len src/wps/wps_attr_parse.h /^ size_t public_key_len;$/;" m struct:wps_parse_attr +pw_id src/wps/wps_registrar.c /^ u16 pw_id;$/;" m struct:wps_nfc_pw_token file: +pwd_auth_fail src/wps/wps.h /^ } pwd_auth_fail;$/;" m union:wps_event_data typeref:struct:wps_event_data::wps_event_pwd_auth_fail +q src/tls/rsa.c /^ struct bignum *q; \/* prime q (factor of n) *\/$/;" m struct:crypto_rsa_key typeref:struct:crypto_rsa_key::bignum file: +qos_info src/common/ieee802_11_defs.h /^ u8 qos_info; \/* AP\/STA specif QoS info *\/$/;" m struct:wmm_parameter_element +qos_info src/common/ieee802_11_defs.h /^ u8 qos_info; \/* AP\/STA specific QoS info *\/$/;" m struct:wmm_information_element +r0_key_holder src/ap/wpa_auth.h /^ u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];$/;" m struct:wpa_auth_config +r0_key_holder_len src/ap/wpa_auth.h /^ size_t r0_key_holder_len;$/;" m struct:wpa_auth_config +r0_key_lifetime src/ap/ap_config.h /^ u32 r0_key_lifetime;$/;" m struct:hostapd_bss_config +r0_key_lifetime src/ap/wpa_auth.h /^ u32 r0_key_lifetime;$/;" m struct:wpa_auth_config +r0kh_id src/ap/wpa_auth_i.h /^ u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; \/* R0KH-ID from FT Auth Request *\/$/;" m struct:wpa_state_machine +r0kh_id_len src/ap/wpa_auth_i.h /^ size_t r0kh_id_len;$/;" m struct:wpa_state_machine +r0kh_list src/ap/ap_config.h /^ struct ft_remote_r0kh *r0kh_list;$/;" m struct:hostapd_bss_config typeref:struct:hostapd_bss_config::ft_remote_r0kh +r0kh_list src/ap/wpa_auth.h /^ struct ft_remote_r0kh *r0kh_list;$/;" m struct:wpa_auth_config typeref:struct:wpa_auth_config::ft_remote_r0kh +r1_key_holder src/ap/ap_config.h /^ u8 r1_key_holder[FT_R1KH_ID_LEN];$/;" m struct:hostapd_bss_config +r1_key_holder src/ap/wpa_auth.h /^ u8 r1_key_holder[FT_R1KH_ID_LEN];$/;" m struct:wpa_auth_config +r1kh_id src/ap/wpa_auth.h /^ u8 r1kh_id[FT_R1KH_ID_LEN]; \/* copied from pull *\/$/;" m struct:ft_r0kh_r1kh_resp_frame +r1kh_id src/ap/wpa_auth.h /^ u8 r1kh_id[FT_R1KH_ID_LEN];$/;" m struct:ft_r0kh_r1kh_pull_frame +r1kh_id src/ap/wpa_auth.h /^ u8 r1kh_id[FT_R1KH_ID_LEN];$/;" m struct:ft_r0kh_r1kh_push_frame +r1kh_list src/ap/ap_config.h /^ struct ft_remote_r1kh *r1kh_list;$/;" m struct:hostapd_bss_config typeref:struct:hostapd_bss_config::ft_remote_r1kh +r1kh_list src/ap/wpa_auth.h /^ struct ft_remote_r1kh *r1kh_list;$/;" m struct:wpa_auth_config typeref:struct:wpa_auth_config::ft_remote_r1kh +r_hash1 src/wps/wps_attr_parse.h /^ const u8 *r_hash1; \/* WPS_HASH_LEN (32) octets *\/$/;" m struct:wps_parse_attr +r_hash2 src/wps/wps_attr_parse.h /^ const u8 *r_hash2; \/* WPS_HASH_LEN (32) octets *\/$/;" m struct:wps_parse_attr +r_snonce1 src/wps/wps_attr_parse.h /^ const u8 *r_snonce1; \/* WPS_SECRET_NONCE_LEN (16) octets *\/$/;" m struct:wps_parse_attr +r_snonce2 src/wps/wps_attr_parse.h /^ const u8 *r_snonce2; \/* WPS_SECRET_NONCE_LEN (16) octets *\/$/;" m struct:wps_parse_attr +random_add_randomness include/crypto/random.h 23;" d +random_deinit include/crypto/random.h 22;" d +random_get_bytes include/crypto/random.h 24;" d +random_init include/crypto/random.h 21;" d +random_mark_pool_ready include/crypto/random.h 26;" d +random_pool_ready include/crypto/random.h 25;" d +rate src/ap/hostapd.h /^ int rate; \/* rate in 100 kbps *\/$/;" m struct:hostapd_rate_data +rc4 src/crypto/crypto_internal-cipher.c /^ } rc4;$/;" m union:crypto_cipher::__anon10 typeref:struct:crypto_cipher::__anon10::__anon11 file: +rc4 src/fast_crypto/fast_crypto_internal-cipher.c /^ } rc4;$/;" m union:fast_crypto_cipher::__anon56 typeref:struct:fast_crypto_cipher::__anon56::__anon57 file: +rc4_skip src/crypto/rc4.c /^rc4_skip(const u8 *key, size_t keylen, size_t skip,$/;" f +rcon src/crypto/aes-internal.c /^const u32 rcon[] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v +rcons src/crypto/aes-internal.c /^const u8 rcons[] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v +read_cbc src/tls/tlsv1_record.h /^ struct crypto_cipher *read_cbc;$/;" m struct:tlsv1_record_layer typeref:struct:tlsv1_record_layer::crypto_cipher +read_cipher_suite src/tls/tlsv1_record.h /^ u16 read_cipher_suite;$/;" m struct:tlsv1_record_layer +read_iv src/tls/tlsv1_record.h /^ u8 read_iv[TLS_MAX_IV_LEN];$/;" m struct:tlsv1_record_layer +read_key src/tls/tlsv1_record.h /^ u8 read_key[TLS_MAX_WRITE_KEY_LEN];$/;" m struct:tlsv1_record_layer +read_mac_secret src/tls/tlsv1_record.h /^ u8 read_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];$/;" m struct:tlsv1_record_layer +read_seq_num src/tls/tlsv1_record.h /^ u8 read_seq_num[TLS_SEQ_NUM_LEN];$/;" m struct:tlsv1_record_layer +ready_for_tnc src/eap_peer/eap_ttls.c /^ int ready_for_tnc;$/;" m struct:eap_ttls_data file: +reason src/tls/tls.h /^ enum tls_fail_reason reason;$/;" m struct:tls_event_data::__anon34 typeref:enum:tls_event_data::__anon34::tls_fail_reason +reason_code src/common/ieee802_11_defs.h /^ le16 reason_code;$/;" m struct:ieee80211_mgmt::__anon66::__anon68 +reason_code src/common/ieee802_11_defs.h /^ le16 reason_code;$/;" m struct:ieee80211_mgmt::__anon66::__anon72 +reason_txt src/tls/tls.h /^ const char *reason_txt;$/;" m struct:tls_event_data::__anon34 +reassoc_deadline src/rsn_supp/wpa_ie.h /^ const u8 *reassoc_deadline;$/;" m struct:wpa_eapol_ie_parse +reassoc_req src/common/ieee802_11_defs.h /^ } STRUCT_PACKED reassoc_req;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon71 +reassoc_resp src/common/ieee802_11_defs.h /^ } STRUCT_PACKED assoc_resp, reassoc_resp;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon70 +reassociation_deadline src/ap/ap_config.h /^ u32 reassociation_deadline;$/;" m struct:hostapd_bss_config +reassociation_deadline src/ap/wpa_auth.h /^ u32 reassociation_deadline;$/;" m struct:wpa_auth_config +reauth src/eap_peer/eap_peap.c /^ int reauth; \/* reauthentication *\/$/;" m struct:eap_peap_data file: +reauth src/eap_peer/eap_ttls.c /^ int reauth; \/* reauthentication *\/$/;" m struct:eap_ttls_data file: +received_version src/eap_peer/eap_tlv_common.h /^ u8 received_version;$/;" m struct:eap_tlv_crypto_binding_tlv +reg_success_cb src/wps/wps.h /^ void (*reg_success_cb)(void *ctx, const u8 *mac_addr,$/;" m struct:wps_registrar_config +reg_success_cb src/wps/wps_registrar.c /^ void (*reg_success_cb)(void *ctx, const u8 *mac_addr,$/;" m struct:wps_registrar file: +registrar src/wps/wps.h /^ int registrar;$/;" m struct:wps_config +registrar src/wps/wps.h /^ struct wps_registrar *registrar;$/;" m struct:wps_context typeref:struct:wps_context::wps_registrar +registrar src/wps/wps_i.h /^ int registrar;$/;" m struct:wps_data +registrar_nonce src/wps/wps_attr_parse.h /^ const u8 *registrar_nonce; \/* WPS_NONCE_LEN (16) octets *\/$/;" m struct:wps_parse_attr +reject_4way_hs_for_entropy src/ap/wpa_auth_i.h /^ Boolean reject_4way_hs_for_entropy;$/;" m struct:wpa_group +reload_config src/ap/hostapd.h /^ int (*reload_config)(struct hostapd_iface *iface);$/;" m struct:hapd_interfaces +renew_snonce src/rsn_supp/wpa.h /^ int renew_snonce;$/;" m struct:wpa_sm +replay_counter src/common/eapol_common.h /^ u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];$/;" m struct:ieee802_1x_eapol_key +replay_counter src/common/wpa_common.h /^ u8 replay_counter[WPA_REPLAY_COUNTER_LEN];$/;" m struct:wpa_eapol_key +req_dev_type src/wps/wps_attr_parse.h /^ const u8 *req_dev_type[MAX_REQ_DEV_TYPE_COUNT];$/;" m struct:wps_parse_attr +req_replay_counter src/ap/wpa_auth_i.h /^ u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];$/;" m struct:wpa_state_machine +req_replay_counter_used src/ap/wpa_auth_i.h /^ int req_replay_counter_used;$/;" m struct:wpa_state_machine +request_counter src/rsn_supp/wpa.h /^ u8 request_counter[WPA_REPLAY_COUNTER_LEN];$/;" m struct:wpa_sm +request_to_enroll src/wps/wps_attr_parse.h /^ const u8 *request_to_enroll; \/* 1 octet (Bool) *\/$/;" m struct:wps_parse_attr +request_type src/wps/wps_attr_parse.h /^ const u8 *request_type; \/* 1 octet *\/$/;" m struct:wps_parse_attr +request_type src/wps/wps_i.h /^ u8 request_type;$/;" m struct:wps_data +require_ht src/ap/ap_config.h /^ int require_ht;$/;" m struct:hostapd_config +require_vht src/ap/ap_config.h /^ int require_vht;$/;" m struct:hostapd_config +resend_eapol src/ap/wpa_auth_i.h /^ ETSTimer resend_eapol;$/;" m struct:wpa_state_machine +resend_eapol_handle src/ap/wpa_auth.c /^void resend_eapol_handle(void *timeout_ctx)$/;" f +reserved src/common/ieee802_11_defs.h /^ u8 reserved; \/* 0 *\/$/;" m struct:wmm_parameter_element +reserved src/eap_peer/eap_mschapv2.c /^ u8 reserved[8];$/;" m struct:ms_change_password file: +reserved src/eap_peer/eap_mschapv2.c /^ u8 reserved[8];$/;" m struct:ms_response file: +reserved src/eap_peer/eap_tlv_common.h /^ u8 reserved;$/;" m struct:eap_tlv_crypto_binding_tlv +response_type src/wps/wps_attr_parse.h /^ const u8 *response_type; \/* 1 octet *\/$/;" m struct:wps_parse_attr +result src/eap_peer/eap_tlv_common.h /^ be16 result;$/;" m struct:eap_tlv_pac_ack_tlv +resuming src/eap_peer/eap_peap.c /^ int resuming; \/* starting a resumed session *\/$/;" m struct:eap_peap_data file: +resuming src/eap_peer/eap_ttls.c /^ int resuming; \/* starting a resumed session *\/$/;" m struct:eap_ttls_data file: +ret src/esp_supplicant/esp_wps.c /^ int ret; \/* return value *\/$/;" m struct:__anon33 file: +rf_bands src/wps/wps.h /^ u8 rf_bands;$/;" m struct:wps_device_data +rf_bands src/wps/wps_attr_parse.h /^ const u8 *rf_bands; \/* 1 octet *\/$/;" m struct:wps_parse_attr +rid src/tls/x509v3.h /^ struct asn1_oid rid; \/* registeredID *\/$/;" m struct:x509_name typeref:struct:x509_name::asn1_oid +rijndaelDecrypt src/crypto/aes-internal-dec.c /^static void rijndaelDecrypt(const u32 rk[\/*44*\/], int Nr, const u8 ct[16],$/;" f file: +rijndaelEncrypt src/crypto/aes-internal-enc.c /^void rijndaelEncrypt(const u32 rk[], int Nr, const u8 pt[16], u8 ct[16])$/;" f +rijndaelKeySetupDec src/crypto/aes-internal-dec.c /^static int rijndaelKeySetupDec(u32 rk[], const u8 cipherKey[], int keyBits)$/;" f file: +rijndaelKeySetupEnc src/crypto/aes-internal.c /^int rijndaelKeySetupEnc(u32 rk[], const u8 cipherKey[], int keyBits)$/;" f +rl src/tls/tlsv1_client_i.h /^ struct tlsv1_record_layer rl;$/;" m struct:tlsv1_client typeref:struct:tlsv1_client::tlsv1_record_layer +rl src/tls/tlsv1_server_i.h /^ struct tlsv1_record_layer rl;$/;" m struct:tlsv1_server typeref:struct:tlsv1_server::tlsv1_record_layer +rol src/crypto/sha1-internal.c 132;" d file: +rotate_bits src/tls/asn1.c /^static u8 rotate_bits(u8 octet)$/;" f file: +rotr src/crypto/aes_i.h /^static inline u32 rotr(u32 val, int bits)$/;" f +rsn src/esp_supplicant/esp_wifi_driver.h /^ uint8_t *rsn;$/;" m struct:wps_scan_ie +rsn_cipher_put_suites src/common/wpa_common.c /^int rsn_cipher_put_suites(u8 *pos, int ciphers)$/;" f +rsn_enabled src/rsn_supp/wpa.h /^ int rsn_enabled; \/* Whether RSN is enabled in configuration *\/$/;" m struct:wpa_sm +rsn_error_kde src/common/wpa_common.h /^struct rsn_error_kde {$/;" s +rsn_ftie src/common/wpa_common.h /^struct rsn_ftie {$/;" s +rsn_ie src/ap/wpa_auth_ie.h /^ const u8 *rsn_ie;$/;" m struct:wpa_eapol_ie_parse +rsn_ie src/rsn_supp/wpa_ie.h /^ const u8 *rsn_ie;$/;" m struct:wpa_eapol_ie_parse +rsn_ie_hdr src/common/wpa_common.h /^struct rsn_ie_hdr {$/;" s +rsn_ie_len src/ap/wpa_auth_ie.h /^ size_t rsn_ie_len;$/;" m struct:wpa_eapol_ie_parse +rsn_ie_len src/rsn_supp/wpa_ie.h /^ size_t rsn_ie_len;$/;" m struct:wpa_eapol_ie_parse +rsn_key_mgmt_to_bitfield src/common/wpa_common.c /^static int rsn_key_mgmt_to_bitfield(const u8 *s)$/;" f file: +rsn_mdie src/common/wpa_common.h /^struct rsn_mdie {$/;" s +rsn_pairwise src/ap/ap_config.h /^ int rsn_pairwise;$/;" m struct:hostapd_bss_config +rsn_pairwise src/ap/wpa_auth.h /^ int rsn_pairwise;$/;" m struct:wpa_auth_config +rsn_pmkid src/common/wpa_common.c /^void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,$/;" f +rsn_preauth src/ap/ap_config.h /^ int rsn_preauth;$/;" m struct:hostapd_bss_config +rsn_preauth src/ap/wpa_auth.h /^ int rsn_preauth;$/;" m struct:wpa_auth_config +rsn_preauth_interfaces src/ap/ap_config.h /^ char *rsn_preauth_interfaces;$/;" m struct:hostapd_bss_config +rsn_rdie src/common/wpa_common.h /^struct rsn_rdie {$/;" s +rsn_selector_to_bitfield src/common/wpa_common.c /^static int rsn_selector_to_bitfield(const u8 *s)$/;" f file: +rsn_testing src/ap/wpa_auth_ie.c /^int rsn_testing = 0;$/;" v +rts_threshold src/ap/ap_config.h /^ int rts_threshold;$/;" m struct:hostapd_config +rx_eapol_key_secure src/ap/wpa_auth_i.h /^ unsigned int rx_eapol_key_secure:1;$/;" m struct:wpa_state_machine +rx_mic_key src/common/wpa_common.h /^ u8 rx_mic_key[8];$/;" m struct:wpa_ptk::__anon62::__anon63 +rx_replay_counter src/rsn_supp/wpa.h /^ u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];$/;" m struct:wpa_sm +rx_replay_counter_set src/rsn_supp/wpa.h /^ int rx_replay_counter_set;$/;" m struct:wpa_sm +s16 include/utils/common.h /^typedef int16_t s16;$/;" t +s1kh_id src/ap/wpa_auth.h /^ u8 s1kh_id[ETH_ALEN]; \/* copied from pull *\/$/;" m struct:ft_r0kh_r1kh_resp_frame +s1kh_id src/ap/wpa_auth.h /^ u8 s1kh_id[ETH_ALEN];$/;" m struct:ft_r0kh_r1kh_pull_frame +s1kh_id src/ap/wpa_auth.h /^ u8 s1kh_id[ETH_ALEN];$/;" m struct:ft_r0kh_r1kh_push_frame +s32 include/utils/common.h /^typedef int32_t s32;$/;" t +s64 include/utils/common.h /^typedef int64_t s64;$/;" t +s8 include/utils/common.h /^typedef int8_t s8;$/;" t +s_factory_info src/esp_supplicant/esp_wps.c /^static wps_factory_information_t *s_factory_info = NULL;$/;" v file: +s_mp_add src/crypto/libtommath.h /^s_mp_add (mp_int * a, mp_int * b, mp_int * c)$/;" f +s_mp_add src/tls/libtommath.h /^s_mp_add (mp_int * a, mp_int * b, mp_int * c)$/;" f +s_mp_exptmod src/crypto/libtommath.h /^s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)$/;" f +s_mp_exptmod src/tls/libtommath.h /^s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)$/;" f +s_mp_mul src/crypto/libtommath.h 132;" d +s_mp_mul src/tls/libtommath.h 134;" d +s_mp_mul_digs src/crypto/libtommath.h /^s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)$/;" f +s_mp_mul_digs src/tls/libtommath.h /^s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)$/;" f +s_mp_mul_high_digs src/crypto/libtommath.h /^s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)$/;" f +s_mp_mul_high_digs src/tls/libtommath.h /^s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)$/;" f +s_mp_sqr src/crypto/libtommath.h /^s_mp_sqr (mp_int * a, mp_int * b)$/;" f +s_mp_sqr src/tls/libtommath.h /^s_mp_sqr (mp_int * a, mp_int * b)$/;" f +s_mp_sub src/crypto/libtommath.h /^s_mp_sub (mp_int * a, mp_int * b, mp_int * c)$/;" f +s_mp_sub src/tls/libtommath.h /^s_mp_sub (mp_int * a, mp_int * b, mp_int * c)$/;" f +s_sm_table src/ap/wpa_auth.c /^static void *s_sm_table[WPA_SM_MAX_INDEX];$/;" v file: +s_sm_valid_bitmap src/ap/wpa_auth.c /^static u32 s_sm_valid_bitmap = 0;$/;" v file: +s_wps_api_lock src/esp_supplicant/esp_wps.c /^static void *s_wps_api_lock = NULL; \/* Used in WPS public API only, never be freed *\/$/;" v file: +s_wps_api_sem src/esp_supplicant/esp_wps.c /^static void *s_wps_api_sem = NULL; \/* Sync semaphore used between WPS publi API caller task and WPS task *\/$/;" v file: +s_wps_data_lock src/esp_supplicant/esp_wps.c /^static void *s_wps_data_lock = NULL;$/;" v file: +s_wps_enabled src/esp_supplicant/esp_wps.c /^static bool s_wps_enabled = false;$/;" v file: +s_wps_sig_cnt src/esp_supplicant/esp_wps.c /^static uint8_t s_wps_sig_cnt[SIG_WPS_NUM] = {0};$/;" v file: +s_wps_task_create_sem src/esp_supplicant/esp_wps.c /^static void *s_wps_task_create_sem = NULL;$/;" v file: +sa src/common/ieee802_11_defs.h /^ u8 sa[6];$/;" m struct:ieee80211_mgmt +sa src/esp_supplicant/esp_wpa_enterprise.c /^ u8 sa[WPA_ADDR_LEN];$/;" m struct:wpa2_rx_param file: +sa src/esp_supplicant/esp_wps.c /^ u8 sa[WPS_ADDR_LEN];$/;" m struct:wps_rx_param file: +sa_query_count src/ap/sta_info.h /^ int sa_query_count; \/* number of pending SA Query requests;$/;" m struct:sta_info +sa_query_req src/common/ieee802_11_defs.h /^ } STRUCT_PACKED sa_query_req;$/;" m union:ieee80211_mgmt::__anon66::__anon76::__anon77 typeref:struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon82 +sa_query_resp src/common/ieee802_11_defs.h /^ } STRUCT_PACKED sa_query_resp;$/;" m union:ieee80211_mgmt::__anon66::__anon76::__anon77 typeref:struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon83 +sa_query_start src/ap/sta_info.h /^ struct os_time sa_query_start;$/;" m struct:sta_info typeref:struct:sta_info::os_time +sa_query_timed_out src/ap/sta_info.h /^ int sa_query_timed_out;$/;" m struct:sta_info +sa_query_trans_id src/ap/sta_info.h /^ u8 *sa_query_trans_id; \/* buffer of WLAN_SA_QUERY_TR_ID_LEN *$/;" m struct:sta_info +sae_send_confirm src/ap/sta_info.h /^ u16 sae_send_confirm;$/;" m struct:sta_info +sae_state src/ap/sta_info.h /^ enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state;$/;" m struct:sta_info typeref:enum:sta_info::__anon16 +salt src/tls/pkcs5.c /^ u8 salt[8];$/;" m struct:pkcs5_params file: +salt_len src/tls/pkcs5.c /^ size_t salt_len;$/;" m struct:pkcs5_params file: +scan_cnt src/wps/wps.h /^ u8 scan_cnt;$/;" m struct:wps_sm +search_tag src/tls/tlsv1_cred.c /^static const u8 * search_tag(const char *tag, const u8 *buf, size_t len)$/;" f file: +sec port/include/os.h /^ os_time_t sec;$/;" m struct:os_time +sec_dev_type src/wps/wps.h /^ u8 sec_dev_type[WPS_SEC_DEVICE_TYPES][WPS_DEV_TYPE_LEN];$/;" m struct:wps_device_data +sec_dev_type_list src/wps/wps_attr_parse.h /^ const u8 *sec_dev_type_list; \/* <= 128 octets *\/$/;" m struct:wps_parse_attr +sec_dev_type_list_len src/wps/wps_attr_parse.h /^ size_t sec_dev_type_list_len;$/;" m struct:wps_parse_attr +secondary_channel src/ap/ap_config.h /^ int secondary_channel;$/;" m struct:hostapd_config +secpolicy src/ap/ap_config.h /^} secpolicy;$/;" t typeref:enum:hostap_security_policy +sel_reg src/wps/wps.h /^ int sel_reg;$/;" m struct:wps_event_data::wps_event_er_set_selected_registrar +sel_reg_config_methods src/wps/wps.h /^ u16 sel_reg_config_methods;$/;" m struct:wps_event_data::wps_event_er_set_selected_registrar +sel_reg_config_methods src/wps/wps_attr_parse.h /^ const u8 *sel_reg_config_methods; \/* 2 octets *\/$/;" m struct:wps_parse_attr +sel_reg_config_methods_override src/wps/wps_registrar.c /^ int sel_reg_config_methods_override;$/;" m struct:wps_registrar file: +sel_reg_dev_password_id_override src/wps/wps_registrar.c /^ int sel_reg_dev_password_id_override;$/;" m struct:wps_registrar file: +sel_reg_union src/wps/wps_registrar.c /^ int sel_reg_union;$/;" m struct:wps_registrar file: +selected_registrar src/wps/wps_attr_parse.h /^ const u8 *selected_registrar; \/* 1 octet (Bool) *\/$/;" m struct:wps_parse_attr +selected_registrar src/wps/wps_registrar.c /^ int selected_registrar;$/;" m struct:wps_registrar file: +send_eapol src/ap/wpa_auth.h /^ int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data,$/;" m struct:wpa_auth_callbacks +send_ether src/ap/wpa_auth.h /^ int (*send_ether)(void *ctx, const u8 *dst, u16 proto, const u8 *data,$/;" m struct:wpa_auth_callbacks +send_ft_action src/ap/wpa_auth.h /^ int (*send_ft_action)(void *ctx, const u8 *dst,$/;" m struct:wpa_auth_callbacks +send_probe_response src/ap/ap_config.h /^ u8 send_probe_response;$/;" m struct:hostapd_config +sendto src/rsn_supp/wpa.h /^ void (* sendto) (void *buffer, uint16_t len);$/;" m struct:wpa_sm +seq src/rsn_supp/wpa.h /^ u8 seq[10];$/;" m struct:install_key +seq_ctrl src/common/ieee802_11_defs.h /^ le16 seq_ctrl;$/;" m struct:ieee80211_hdr +seq_ctrl src/common/ieee802_11_defs.h /^ le16 seq_ctrl;$/;" m struct:ieee80211_mgmt +serial_number src/ap/ap_config.h /^ char *serial_number;$/;" m struct:hostapd_bss_config +serial_number src/tls/x509v3.h /^ unsigned long serial_number;$/;" m struct:x509_certificate +serial_number src/wps/wps.h /^ const char *serial_number;$/;" m struct:wps_event_data::wps_event_er_ap +serial_number src/wps/wps.h /^ const char *serial_number;$/;" m struct:wps_event_data::wps_event_er_enrollee +serial_number src/wps/wps.h /^ const u8 *serial_number;$/;" m struct:wps_event_data::wps_event_m2d +serial_number src/wps/wps.h /^ char *serial_number;$/;" m struct:wps_device_data +serial_number src/wps/wps_attr_parse.h /^ const u8 *serial_number;$/;" m struct:wps_parse_attr +serial_number_len src/wps/wps.h /^ size_t serial_number_len;$/;" m struct:wps_event_data::wps_event_m2d +serial_number_len src/wps/wps_attr_parse.h /^ size_t serial_number_len;$/;" m struct:wps_parse_attr +server src/tls/tls_internal.c /^ int server;$/;" m struct:tls_global file: +server src/tls/tls_internal.c /^ struct tlsv1_server *server;$/;" m struct:tls_connection typeref:struct:tls_connection::tlsv1_server file: +server_cred src/tls/tls_internal.c /^ struct tlsv1_credentials *server_cred;$/;" m struct:tls_global typeref:struct:tls_global::tlsv1_credentials file: +server_random src/tls/tls.h /^ const u8 *server_random;$/;" m struct:tls_keys +server_random src/tls/tlsv1_client_i.h /^ u8 server_random[TLS_RANDOM_LEN];$/;" m struct:tlsv1_client +server_random src/tls/tlsv1_server_i.h /^ u8 server_random[TLS_RANDOM_LEN];$/;" m struct:tlsv1_server +server_random_len src/tls/tls.h /^ size_t server_random_len;$/;" m struct:tls_keys +server_rsa_key src/tls/tlsv1_client_i.h /^ struct crypto_public_key *server_rsa_key;$/;" m struct:tlsv1_client typeref:struct:tlsv1_client::crypto_public_key +service_start_time src/common/ieee802_11_defs.h /^ le32 service_start_time;$/;" m struct:wmm_tspec_element +session_id src/eap_peer/eap_peap.c /^ u8 *session_id;$/;" m struct:eap_peap_data file: +session_id src/eap_peer/eap_tls.c /^ u8 *session_id;$/;" m struct:eap_tls_data file: +session_id src/eap_peer/eap_ttls.c /^ u8 *session_id;$/;" m struct:eap_ttls_data file: +session_id src/tls/tlsv1_client_i.h /^ u8 session_id[TLS_SESSION_ID_MAX_LEN];$/;" m struct:tlsv1_client +session_id src/tls/tlsv1_server_i.h /^ u8 session_id[TLS_SESSION_ID_MAX_LEN];$/;" m struct:tlsv1_server +session_id_len src/tls/tlsv1_client_i.h /^ size_t session_id_len;$/;" m struct:tlsv1_client +session_id_len src/tls/tlsv1_server_i.h /^ size_t session_id_len;$/;" m struct:tlsv1_server +session_resumed src/tls/tlsv1_client_i.h /^ unsigned int session_resumed:1;$/;" m struct:tlsv1_client +session_ticket src/tls/tlsv1_server_i.h /^ u8 *session_ticket;$/;" m struct:tlsv1_server +session_ticket_cb src/tls/tlsv1_client_i.h /^ tlsv1_client_session_ticket_cb session_ticket_cb;$/;" m struct:tlsv1_client +session_ticket_cb src/tls/tlsv1_server_i.h /^ tlsv1_server_session_ticket_cb session_ticket_cb;$/;" m struct:tlsv1_server +session_ticket_cb_ctx src/tls/tlsv1_client_i.h /^ void *session_ticket_cb_ctx;$/;" m struct:tlsv1_client +session_ticket_cb_ctx src/tls/tlsv1_server_i.h /^ void *session_ticket_cb_ctx;$/;" m struct:tlsv1_server +session_ticket_included src/tls/tlsv1_client_i.h /^ unsigned int session_ticket_included:1;$/;" m struct:tlsv1_client +session_ticket_len src/tls/tlsv1_server_i.h /^ size_t session_ticket_len;$/;" m struct:tlsv1_server +set_assoc_ie src/rsn_supp/wpa.c /^set_assoc_ie(u8 * assoc_buf)$/;" f +set_eapol src/ap/wpa_auth.h /^ void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var,$/;" m struct:wpa_auth_callbacks +set_ie_cb src/wps/wps.h /^ int (*set_ie_cb)(void *ctx, struct wpabuf *beacon_ie,$/;" m struct:wps_registrar_config +set_ie_cb src/wps/wps_registrar.c /^ int (*set_ie_cb)(void *ctx, struct wpabuf *beacon_ie,$/;" m struct:wps_registrar file: +set_key src/ap/wpa_auth.h /^ int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg,$/;" m struct:wpa_auth_callbacks +set_sel_reg src/wps/wps.h /^ } set_sel_reg;$/;" m union:wps_event_data typeref:struct:wps_event_data::wps_event_er_set_selected_registrar +set_sel_reg_cb src/wps/wps.h /^ void (*set_sel_reg_cb)(void *ctx, int sel_reg, u16 dev_passwd_id,$/;" m struct:wps_registrar_config +set_sel_reg_cb src/wps/wps_registrar.c /^ void (*set_sel_reg_cb)(void *ctx, int sel_reg, u16 dev_passwd_id,$/;" m struct:wps_registrar file: +set_tx src/rsn_supp/wpa.h /^ int set_tx;$/;" m struct:install_key +settings_delay_time src/wps/wps_attr_parse.h /^ const u8 *settings_delay_time; \/* 1 octet *\/$/;" m struct:wps_parse_attr +sha1 src/crypto/crypto_internal.c /^ struct SHA1Context sha1;$/;" m union:crypto_hash::__anon9 typeref:struct:crypto_hash::__anon9::SHA1Context file: +sha1 src/fast_crypto/fast_crypto_internal.c /^ struct SHA1Context sha1;$/;" m union:fast_crypto_hash::__anon61 typeref:struct:fast_crypto_hash::__anon61::SHA1Context file: +sha1_cert src/tls/tlsv1_common.h /^ struct crypto_hash *sha1_cert;$/;" m struct:tls_verify_hash typeref:struct:tls_verify_hash::crypto_hash +sha1_client src/tls/tlsv1_common.h /^ struct crypto_hash *sha1_client;$/;" m struct:tls_verify_hash typeref:struct:tls_verify_hash::crypto_hash +sha1_prf src/crypto/sha1.c /^sha1_prf(const u8 *key, size_t key_len, const char *label,$/;" f +sha1_server src/tls/tlsv1_common.h /^ struct crypto_hash *sha1_server;$/;" m struct:tls_verify_hash typeref:struct:tls_verify_hash::crypto_hash +sha1_vector src/crypto/sha1-internal.c /^sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)$/;" f +sha256 src/crypto/crypto_internal.c /^ struct sha256_state sha256;$/;" m union:crypto_hash::__anon9 typeref:struct:crypto_hash::__anon9::sha256_state file: +sha256 src/fast_crypto/fast_crypto_internal.c /^ mbedtls_sha256_context sha256;$/;" m union:fast_crypto_hash::__anon61 file: +sha256_cert src/tls/tlsv1_common.h /^ struct crypto_hash *sha256_cert;$/;" m struct:tls_verify_hash typeref:struct:tls_verify_hash::crypto_hash +sha256_client src/tls/tlsv1_common.h /^ struct crypto_hash *sha256_client;$/;" m struct:tls_verify_hash typeref:struct:tls_verify_hash::crypto_hash +sha256_compress src/crypto/sha256-internal.c /^sha256_compress(struct sha256_state *md, unsigned char *buf)$/;" f file: +sha256_done src/crypto/sha256-internal.c /^sha256_done(struct sha256_state *md, unsigned char *out)$/;" f file: +sha256_init src/crypto/sha256-internal.c /^sha256_init(struct sha256_state *md)$/;" f file: +sha256_prf src/crypto/sha256.c /^sha256_prf(const u8 *key, size_t key_len, const char *label,$/;" f +sha256_process src/crypto/sha256-internal.c /^sha256_process(struct sha256_state *md, const unsigned char *in,$/;" f file: +sha256_server src/tls/tlsv1_common.h /^ struct crypto_hash *sha256_server;$/;" m struct:tls_verify_hash typeref:struct:tls_verify_hash::crypto_hash +sha256_state src/crypto/sha256-internal.c /^struct sha256_state {$/;" s file: +sha256_vector src/crypto/sha256-internal.c /^sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,$/;" f +sign src/crypto/libtommath.h /^ int used, alloc, sign;$/;" m struct:__anon8 +sign src/tls/libtommath.h /^ int used, alloc, sign;$/;" m struct:__anon40 +sign_value src/tls/x509v3.h /^ u8 *sign_value;$/;" m struct:x509_certificate +sign_value_len src/tls/x509v3.h /^ size_t sign_value_len;$/;" m struct:x509_certificate +signature src/tls/x509v3.h /^ struct x509_algorithm_identifier signature;$/;" m struct:x509_certificate typeref:struct:x509_certificate::x509_algorithm_identifier +signature_alg src/tls/x509v3.h /^ struct x509_algorithm_identifier signature_alg;$/;" m struct:x509_certificate typeref:struct:x509_certificate::x509_algorithm_identifier +size include/utils/wpabuf.h /^ size_t size; \/* total size of the allocated buffer *\/$/;" m struct:wpabuf +skip_cred_build src/ap/ap_config.h /^ int skip_cred_build;$/;" m struct:hostapd_bss_config +skip_cred_build src/wps/wps.h /^ int skip_cred_build;$/;" m struct:wps_registrar_config +skip_cred_build src/wps/wps_registrar.c /^ int skip_cred_build;$/;" m struct:wps_registrar file: +smk src/ap/wpa_auth_ie.h /^ const u8 *smk;$/;" m struct:wpa_eapol_ie_parse +smk src/rsn_supp/wpa_ie.h /^ const u8 *smk;$/;" m struct:wpa_eapol_ie_parse +smk_len src/ap/wpa_auth_ie.h /^ size_t smk_len;$/;" m struct:wpa_eapol_ie_parse +smk_len src/rsn_supp/wpa_ie.h /^ size_t smk_len;$/;" m struct:wpa_eapol_ie_parse +snonce src/common/wpa_common.h /^ u8 snonce[WPA_NONCE_LEN];$/;" m struct:rsn_ftie +snonce src/rsn_supp/wpa.h /^ u8 snonce[WPA_NONCE_LEN];$/;" m struct:wpa_sm +snonce src/wps/wps_i.h /^ u8 snonce[2 * WPS_SECRET_NONCE_LEN];$/;" m struct:wps_data +soh src/eap_peer/eap_peap.c /^ int soh; \/* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP)$/;" m struct:eap_peap_data file: +ssi_signal src/ap/hostapd.h /^ int ssi_signal; \/* dBm *\/$/;" m struct:hostapd_frame_info +ssid src/ap/ap_config.h /^ struct hostapd_ssid ssid;$/;" m struct:hostapd_bss_config typeref:struct:hostapd_bss_config::hostapd_ssid +ssid src/ap/ap_config.h /^ u8 ssid[HOSTAPD_MAX_SSID_LEN];$/;" m struct:hostapd_ssid +ssid src/ap/sta_info.h /^ struct hostapd_ssid *ssid; \/* SSID selection based on (Re)AssocReq *\/$/;" m struct:sta_info typeref:struct:sta_info::hostapd_ssid +ssid src/ap/wpa_auth.h /^ u8 ssid[SSID_LEN];$/;" m struct:wpa_auth_config +ssid src/esp_supplicant/esp_wifi_driver.h /^ uint8_t *ssid;$/;" m struct:wps_scan_ie +ssid src/esp_supplicant/esp_wifi_driver.h /^ uint8_t ssid[32];$/;" m struct:wifi_ssid +ssid src/wps/wps.h /^ u8 ssid[32];$/;" m struct:wps_context +ssid src/wps/wps.h /^ u8 ssid[32];$/;" m struct:wps_credential +ssid src/wps/wps.h /^ u8 ssid[32];$/;" m struct:wps_sm +ssid src/wps/wps_attr_parse.h /^ const u8 *ssid; \/* <= 32 octets *\/$/;" m struct:wps_parse_attr +ssid_len src/ap/ap_config.h /^ size_t ssid_len;$/;" m struct:hostapd_ssid +ssid_len src/ap/wpa_auth.h /^ size_t ssid_len;$/;" m struct:wpa_auth_config +ssid_len src/wps/wps.h /^ size_t ssid_len;$/;" m struct:wps_context +ssid_len src/wps/wps.h /^ size_t ssid_len;$/;" m struct:wps_credential +ssid_len src/wps/wps.h /^ u8 ssid_len;$/;" m struct:wps_sm +ssid_len src/wps/wps_attr_parse.h /^ size_t ssid_len;$/;" m struct:wps_parse_attr +ssid_set src/ap/ap_config.h /^ unsigned int ssid_set:1;$/;" m struct:hostapd_ssid +ssl src/eap_peer/eap_peap.c /^ struct eap_ssl_data ssl;$/;" m struct:eap_peap_data typeref:struct:eap_peap_data::eap_ssl_data file: +ssl src/eap_peer/eap_tls.c /^ struct eap_ssl_data ssl;$/;" m struct:eap_tls_data typeref:struct:eap_tls_data::eap_ssl_data file: +ssl src/eap_peer/eap_ttls.c /^ struct eap_ssl_data ssl;$/;" m struct:eap_ttls_data typeref:struct:eap_ttls_data::eap_ssl_data file: +ssl_ctx src/eap_peer/eap_i.h /^ void *ssl_ctx;$/;" m struct:eap_sm +ssl_ctx src/eap_peer/eap_tls.c /^ void *ssl_ctx;$/;" m struct:eap_tls_data file: +ssl_ctx src/eap_peer/eap_tls_common.h /^ void *ssl_ctx;$/;" m struct:eap_ssl_data +st_cb src/wps/wps.h /^ wps_st_cb_t st_cb;$/;" m struct:wps_sm +sta_addr src/common/ieee802_11_defs.h /^ u8 sta_addr[ETH_ALEN];$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon80 +sta_addr src/common/ieee802_11_defs.h /^ u8 sta_addr[ETH_ALEN];$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon81 +sta_info src/ap/sta_info.h /^struct sta_info {$/;" s +started src/ap/wpa_auth_i.h /^ unsigned int started:1;$/;" m struct:wpa_state_machine +state src/crypto/md4-internal.c /^ u32 state[4];$/;" m struct:MD4Context file: +state src/crypto/sha1_i.h /^ u32 state[5];$/;" m struct:SHA1Context +state src/crypto/sha256-internal.c /^ u32 state[8], curlen;$/;" m struct:sha256_state file: +state src/tls/tlsv1_client_i.h /^ } state;$/;" m struct:tlsv1_client typeref:enum:tlsv1_client::__anon43 +state src/tls/tlsv1_server_i.h /^ } state;$/;" m struct:tlsv1_server typeref:enum:tlsv1_server::__anon39 +state src/wps/wps.h /^ } state;$/;" m struct:wps_event_data::wps_event_er_set_selected_registrar typeref:enum:wps_event_data::wps_event_er_set_selected_registrar::__anon54 +state src/wps/wps_i.h /^ } state;$/;" m struct:wps_data typeref:enum:wps_data::__anon53 +static_wep_only src/wps/wps.h /^ int static_wep_only;$/;" m struct:wps_registrar_config +static_wep_only src/wps/wps_registrar.c /^ int static_wep_only;$/;" m struct:wps_registrar file: +status src/eap_peer/eap_tlv_common.h /^ be16 status;$/;" m struct:eap_tlv_intermediate_result_tlv +status src/eap_peer/eap_tlv_common.h /^ be16 status;$/;" m struct:eap_tlv_result_tlv +status_code src/common/ieee802_11_defs.h /^ le16 status_code;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon81 +status_code src/common/ieee802_11_defs.h /^ u8 status_code;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon78 +status_code src/common/ieee802_11_defs.h /^ le16 status_code;$/;" m struct:ieee80211_mgmt::__anon66::__anon67 +status_code src/common/ieee802_11_defs.h /^ le16 status_code;$/;" m struct:ieee80211_mgmt::__anon66::__anon70 +status_code src/common/wpa_common.h /^ le16 status_code;$/;" m struct:rsn_rdie +stbc_param src/common/ieee802_11_defs.h /^ le16 stbc_param;$/;" m struct:ieee80211_ht_operation +subject src/tls/tls.h /^ const char *subject;$/;" m struct:tls_event_data::__anon34 +subject src/tls/tls.h /^ const char *subject;$/;" m struct:tls_event_data::__anon35 +subject src/tls/x509v3.h /^ struct x509_name subject;$/;" m struct:x509_certificate typeref:struct:x509_certificate::x509_name +subject_match src/tls/tls.h /^ const char *subject_match;$/;" m struct:tls_connection_params +subtype src/eap_peer/eap_tlv_common.h /^ u8 subtype;$/;" m struct:eap_tlv_crypto_binding_tlv +success src/eap_peer/eap_mschapv2.c /^ int success;$/;" m struct:eap_mschapv2_data file: +suite src/tls/tlsv1_common.h /^ u16 suite;$/;" m struct:tls_cipher_suite +sup_pmk_r1_name src/ap/wpa_auth_i.h /^ u8 sup_pmk_r1_name[WPA_PMK_NAME_LEN]; \/* PMKR1Name from EAPOL-Key$/;" m struct:wpa_state_machine +supported_mcs_set src/common/ieee802_11_defs.h /^ u8 supported_mcs_set[16];$/;" m struct:ieee80211_ht_capabilities +supported_rates src/ap/ap_config.h /^ int *supported_rates;$/;" m struct:hostapd_config +supported_rates src/ap/sta_info.h /^ u8 supported_rates[WLAN_SUPP_RATES_MAX];$/;" m struct:sta_info +supported_rates_len src/ap/sta_info.h /^ int supported_rates_len;$/;" m struct:sta_info +surplus_bandwidth_allowance src/common/ieee802_11_defs.h /^ le16 surplus_bandwidth_allowance;$/;" m struct:wmm_tspec_element +suspension_interval src/common/ieee802_11_defs.h /^ le32 suspension_interval;$/;" m struct:wmm_tspec_element +switch_count src/common/ieee802_11_defs.h /^ u8 switch_count;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon79 +switch_mode src/common/ieee802_11_defs.h /^ u8 switch_mode;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon79 +tag src/tls/asn1.h /^ unsigned int tag, length;$/;" m struct:asn1_hdr +target_ap_addr src/common/ieee802_11_defs.h /^ u8 target_ap_addr[ETH_ALEN];$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon80 +target_ap_addr src/common/ieee802_11_defs.h /^ u8 target_ap_addr[ETH_ALEN];$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon81 +tbs_cert_len src/tls/x509v3.h /^ size_t tbs_cert_len;$/;" m struct:x509_certificate +tbs_cert_start src/tls/x509v3.h /^ const u8 *tbs_cert_start;$/;" m struct:x509_certificate +timeout_next src/ap/sta_info.h /^ } timeout_next;$/;" m struct:sta_info typeref:enum:sta_info::__anon15 +timestamp src/ap/wpa_auth.h /^ u8 timestamp[4]; \/* current time in seconds since unix epoch, little$/;" m struct:ft_r0kh_r1kh_push_frame +timestamp src/common/ieee802_11_defs.h /^ u8 timestamp[8];$/;" m struct:ieee80211_mgmt::__anon66::__anon73 +timestamp src/common/ieee802_11_defs.h /^ u8 timestamp[8];$/;" m struct:ieee80211_mgmt::__anon66::__anon75 +timestamp src/wps/wps_registrar.c /^ struct os_time timestamp;$/;" m struct:wps_pbc_session typeref:struct:wps_pbc_session::os_time file: +tk1 src/common/wpa_common.h /^ u8 tk1[16]; \/* Temporal Key 1 (TK1) *\/$/;" m struct:wpa_ptk +tk2 src/common/wpa_common.h /^ u8 tk2[16]; \/* Temporal Key 2 (TK2) *\/$/;" m union:wpa_ptk::__anon62 +tls_alert src/tls/tlsv1_client.c /^void tls_alert(struct tlsv1_client *conn, u8 level, u8 description)$/;" f +tls_capabilities src/tls/tls_internal.c /^unsigned int tls_capabilities(void *tls_ctx)$/;" f +tls_cipher src/tls/tlsv1_common.h /^} tls_cipher;$/;" t typeref:enum:__anon50 +tls_cipher_data src/tls/tlsv1_common.h /^struct tls_cipher_data {$/;" s +tls_cipher_suite src/tls/tlsv1_common.h /^struct tls_cipher_suite {$/;" s +tls_cipher_suites src/tls/tlsv1_common.c /^static const struct tls_cipher_suite tls_cipher_suites[] = {$/;" v typeref:struct:tls_cipher_suite file: +tls_cipher_type src/tls/tlsv1_common.h /^} tls_cipher_type;$/;" t typeref:enum:__anon52 +tls_ciphers src/tls/tlsv1_common.c /^static const struct tls_cipher_data tls_ciphers[] = {$/;" v typeref:struct:tls_cipher_data file: +tls_client_cert_chain_der_len src/tls/tlsv1_client_write.c /^static size_t tls_client_cert_chain_der_len(struct tlsv1_client *conn)$/;" f file: +tls_config src/tls/tls.h /^struct tls_config {$/;" s +tls_connection src/tls/tls_internal.c /^struct tls_connection {$/;" s file: +tls_connection_client_hello_ext src/tls/tls_internal.c /^int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,$/;" f +tls_connection_decrypt src/tls/tls_internal.c /^struct wpabuf * tls_connection_decrypt(void *tls_ctx,$/;" f +tls_connection_decrypt2 src/tls/tls_internal.c /^struct wpabuf * tls_connection_decrypt2(void *tls_ctx,$/;" f +tls_connection_deinit src/tls/tls_internal.c /^void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)$/;" f +tls_connection_enable_workaround src/tls/tls_internal.c /^int tls_connection_enable_workaround(void *tls_ctx,$/;" f +tls_connection_encrypt src/tls/tls_internal.c /^struct wpabuf * tls_connection_encrypt(void *tls_ctx,$/;" f +tls_connection_established src/tls/tls_internal.c /^int tls_connection_established(void *tls_ctx, struct tls_connection *conn)$/;" f +tls_connection_get_failed src/tls/tls_internal.c /^int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)$/;" f +tls_connection_get_keyblock_size src/tls/tls_internal.c /^int tls_connection_get_keyblock_size(void *tls_ctx,$/;" f +tls_connection_get_keys src/tls/tls_internal.c /^int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,$/;" f +tls_connection_get_read_alerts src/tls/tls_internal.c /^int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)$/;" f +tls_connection_get_write_alerts src/tls/tls_internal.c /^int tls_connection_get_write_alerts(void *tls_ctx,$/;" f +tls_connection_handshake src/tls/tls_internal.c /^struct wpabuf * tls_connection_handshake(void *tls_ctx,$/;" f +tls_connection_handshake2 src/tls/tls_internal.c /^struct wpabuf * tls_connection_handshake2(void *tls_ctx,$/;" f +tls_connection_init src/tls/tls_internal.c /^struct tls_connection * tls_connection_init(void *tls_ctx)$/;" f +tls_connection_params src/tls/tls.h /^struct tls_connection_params {$/;" s +tls_connection_prf src/tls/tls_internal.c /^int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,$/;" f +tls_connection_resumed src/tls/tls_internal.c /^int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)$/;" f +tls_connection_server_handshake src/tls/tls_internal.c /^struct wpabuf * tls_connection_server_handshake(void *tls_ctx,$/;" f +tls_connection_set_cipher_list src/tls/tls_internal.c /^int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,$/;" f +tls_connection_set_params src/tls/tls_internal.c /^int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,$/;" f +tls_connection_set_session_ticket_cb src/tls/tls_internal.c /^int tls_connection_set_session_ticket_cb(void *tls_ctx,$/;" f +tls_connection_set_verify src/tls/tls_internal.c /^int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,$/;" f +tls_connection_shutdown src/tls/tls_internal.c /^int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)$/;" f +tls_deinit src/tls/tls_internal.c /^void tls_deinit(void *ssl_ctx)$/;" f +tls_derive_keys src/tls/tlsv1_client.c /^int tls_derive_keys(struct tlsv1_client *conn,$/;" f +tls_derive_pre_master_secret src/tls/tlsv1_client.c /^int tls_derive_pre_master_secret(u8 *pre_master_secret)$/;" f +tls_event src/tls/tls.h /^enum tls_event {$/;" g +tls_event_data src/tls/tls.h /^union tls_event_data {$/;" u +tls_fail_reason src/tls/tls.h /^enum tls_fail_reason {$/;" g +tls_get_cipher src/tls/tls_internal.c /^int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,$/;" f +tls_get_cipher_data src/tls/tlsv1_common.c /^const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher)$/;" f +tls_get_cipher_suite src/tls/tlsv1_common.c /^const struct tls_cipher_suite * tls_get_cipher_suite(u16 suite)$/;" f +tls_get_errors src/tls/tls_internal.c /^int tls_get_errors(void *tls_ctx)$/;" f +tls_global src/tls/tls_internal.c /^struct tls_global {$/;" s file: +tls_global_set_params src/tls/tls_internal.c /^int tls_global_set_params(void *tls_ctx,$/;" f +tls_global_set_verify src/tls/tls_internal.c /^int tls_global_set_verify(void *tls_ctx, int check_crl)$/;" f +tls_hash src/tls/tlsv1_common.h /^} tls_hash;$/;" t typeref:enum:__anon51 +tls_in src/eap_peer/eap_tls_common.h /^ struct wpabuf *tls_in;$/;" m struct:eap_ssl_data typeref:struct:eap_ssl_data::wpabuf +tls_in_left src/eap_peer/eap_tls_common.h /^ size_t tls_in_left;$/;" m struct:eap_ssl_data +tls_in_total src/eap_peer/eap_tls_common.h /^ size_t tls_in_total;$/;" m struct:eap_ssl_data +tls_init src/tls/tls_internal.c /^void * tls_init(void)$/;" f +tls_key_exchange src/tls/tlsv1_common.h /^} tls_key_exchange;$/;" t typeref:enum:__anon49 +tls_keys src/tls/tls.h /^struct tls_keys {$/;" s +tls_out src/eap_peer/eap_tls_common.h /^ struct wpabuf *tls_out;$/;" m struct:eap_ssl_data typeref:struct:eap_ssl_data::wpabuf +tls_out_limit src/eap_peer/eap_tls_common.h /^ size_t tls_out_limit;$/;" m struct:eap_ssl_data +tls_out_pos src/eap_peer/eap_tls_common.h /^ size_t tls_out_pos;$/;" m struct:eap_ssl_data +tls_parse_cert src/tls/tlsv1_common.c /^int tls_parse_cert(const u8 *buf, size_t len, struct crypto_public_key **pk)$/;" f +tls_prf src/tls/tlsv1_common.c /^int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,$/;" f +tls_prf_sha1_md5 src/tls/tls_internal.c /^int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,$/;" f +tls_process_application_data src/tls/tlsv1_client_read.c /^static int tls_process_application_data(struct tlsv1_client *conn, u8 ct,$/;" f file: +tls_process_certificate src/tls/tlsv1_client_read.c /^static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,$/;" f file: +tls_process_certificate src/tls/tlsv1_server_read.c /^static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,$/;" f file: +tls_process_certificate_request src/tls/tlsv1_client_read.c /^static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,$/;" f file: +tls_process_certificate_verify src/tls/tlsv1_server_read.c /^static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,$/;" f file: +tls_process_change_cipher_spec src/tls/tlsv1_server_read.c /^static int tls_process_change_cipher_spec(struct tlsv1_server *conn,$/;" f file: +tls_process_client_finished src/tls/tlsv1_server_read.c /^static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,$/;" f file: +tls_process_client_hello src/tls/tlsv1_server_read.c /^static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,$/;" f file: +tls_process_client_key_exchange src/tls/tlsv1_server_read.c /^static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,$/;" f file: +tls_process_client_key_exchange_dh_anon src/tls/tlsv1_server_read.c /^static int tls_process_client_key_exchange_dh_anon($/;" f file: +tls_process_client_key_exchange_rsa src/tls/tlsv1_server_read.c /^static int tls_process_client_key_exchange_rsa($/;" f file: +tls_process_server_change_cipher_spec src/tls/tlsv1_client_read.c /^static int tls_process_server_change_cipher_spec(struct tlsv1_client *conn,$/;" f file: +tls_process_server_finished src/tls/tlsv1_client_read.c /^static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,$/;" f file: +tls_process_server_hello src/tls/tlsv1_client_read.c /^static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,$/;" f file: +tls_process_server_hello_done src/tls/tlsv1_client_read.c /^static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,$/;" f file: +tls_process_server_key_exchange src/tls/tlsv1_client_read.c /^static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,$/;" f file: +tls_ref_count src/tls/tls_internal.c /^static int tls_ref_count = 0;$/;" v file: +tls_send_change_cipher_spec src/tls/tlsv1_client_write.c /^static u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn,$/;" f file: +tls_send_change_cipher_spec src/tls/tlsv1_server_write.c /^static u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn,$/;" f file: +tls_send_client_hello src/tls/tlsv1_client_write.c /^u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)$/;" f +tls_send_client_key_exchange src/tls/tlsv1_client_write.c /^static u8 * tls_send_client_key_exchange(struct tlsv1_client *conn,$/;" f file: +tls_send_server_hello src/tls/tlsv1_server_write.c /^static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)$/;" f file: +tls_server_cert_chain_der_len src/tls/tlsv1_server_write.c /^static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn)$/;" f file: +tls_server_key_exchange_allowed src/tls/tlsv1_common.c /^int tls_server_key_exchange_allowed(tls_cipher cipher)$/;" f +tls_session_ticket_cb src/tls/tls.h /^typedef int (*tls_session_ticket_cb)$/;" t +tls_verify_hash src/tls/tlsv1_common.h /^struct tls_verify_hash {$/;" s +tls_verify_hash_add src/tls/tlsv1_common.c /^void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,$/;" f +tls_verify_hash_free src/tls/tlsv1_common.c /^void tls_verify_hash_free(struct tls_verify_hash *verify)$/;" f +tls_verify_hash_init src/tls/tlsv1_common.c /^int tls_verify_hash_init(struct tls_verify_hash *verify)$/;" f +tls_version src/tls/tlsv1_record.h /^ u16 tls_version;$/;" m struct:tlsv1_record_layer +tls_version_ok src/tls/tlsv1_common.c /^int tls_version_ok(u16 ver)$/;" f +tls_version_str src/tls/tlsv1_common.c /^const char * tls_version_str(u16 ver)$/;" f +tls_write_client_certificate src/tls/tlsv1_client_write.c /^static int tls_write_client_certificate(struct tlsv1_client *conn,$/;" f file: +tls_write_client_certificate_verify src/tls/tlsv1_client_write.c /^static int tls_write_client_certificate_verify(struct tlsv1_client *conn,$/;" f file: +tls_write_client_change_cipher_spec src/tls/tlsv1_client_write.c /^static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn,$/;" f file: +tls_write_client_finished src/tls/tlsv1_client_write.c /^static int tls_write_client_finished(struct tlsv1_client *conn,$/;" f file: +tls_write_client_key_exchange src/tls/tlsv1_client_write.c /^static int tls_write_client_key_exchange(struct tlsv1_client *conn,$/;" f file: +tls_write_server_certificate src/tls/tlsv1_server_write.c /^static int tls_write_server_certificate(struct tlsv1_server *conn,$/;" f file: +tls_write_server_certificate_request src/tls/tlsv1_server_write.c /^static int tls_write_server_certificate_request(struct tlsv1_server *conn,$/;" f file: +tls_write_server_change_cipher_spec src/tls/tlsv1_server_write.c /^static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,$/;" f file: +tls_write_server_finished src/tls/tlsv1_server_write.c /^static int tls_write_server_finished(struct tlsv1_server *conn,$/;" f file: +tls_write_server_hello src/tls/tlsv1_server_write.c /^static int tls_write_server_hello(struct tlsv1_server *conn,$/;" f file: +tls_write_server_hello_done src/tls/tlsv1_server_write.c /^static int tls_write_server_hello_done(struct tlsv1_server *conn,$/;" f file: +tls_write_server_key_exchange src/tls/tlsv1_server_write.c /^static int tls_write_server_key_exchange(struct tlsv1_server *conn,$/;" f file: +tlsv1_add_cert src/tls/tlsv1_cred.c /^static int tlsv1_add_cert(struct x509_certificate **chain,$/;" f file: +tlsv1_add_cert_der src/tls/tlsv1_cred.c /^static int tlsv1_add_cert_der(struct x509_certificate **chain,$/;" f file: +tlsv1_client src/tls/tlsv1_client_i.h /^struct tlsv1_client {$/;" s +tlsv1_client_decrypt src/tls/tlsv1_client.c /^struct wpabuf * tlsv1_client_decrypt(struct tlsv1_client *conn,$/;" f +tlsv1_client_deinit src/tls/tlsv1_client.c /^void tlsv1_client_deinit(struct tlsv1_client *conn)$/;" f +tlsv1_client_encrypt src/tls/tlsv1_client.c /^int tlsv1_client_encrypt(struct tlsv1_client *conn,$/;" f +tlsv1_client_established src/tls/tlsv1_client.c /^int tlsv1_client_established(struct tlsv1_client *conn)$/;" f +tlsv1_client_free_dh src/tls/tlsv1_client.c /^void tlsv1_client_free_dh(struct tlsv1_client *conn)$/;" f +tlsv1_client_get_cipher src/tls/tlsv1_client.c /^int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,$/;" f +tlsv1_client_get_keyblock_size src/tls/tlsv1_client.c /^int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn)$/;" f +tlsv1_client_get_keys src/tls/tlsv1_client.c /^int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys)$/;" f +tlsv1_client_global_deinit src/tls/tlsv1_client.c /^void tlsv1_client_global_deinit(void)$/;" f +tlsv1_client_global_init src/tls/tlsv1_client.c /^int tlsv1_client_global_init(void)$/;" f +tlsv1_client_handshake src/tls/tlsv1_client.c /^u8 * tlsv1_client_handshake(struct tlsv1_client *conn,$/;" f +tlsv1_client_handshake_write src/tls/tlsv1_client_write.c /^u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len,$/;" f +tlsv1_client_hello_ext src/tls/tlsv1_client.c /^int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,$/;" f +tlsv1_client_init src/tls/tlsv1_client.c /^struct tlsv1_client * tlsv1_client_init(void)$/;" f +tlsv1_client_prf src/tls/tlsv1_client.c /^int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,$/;" f +tlsv1_client_process_handshake src/tls/tlsv1_client_read.c /^int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,$/;" f +tlsv1_client_resumed src/tls/tlsv1_client.c /^int tlsv1_client_resumed(struct tlsv1_client *conn)$/;" f +tlsv1_client_send_alert src/tls/tlsv1_client_write.c /^u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level,$/;" f +tlsv1_client_session_ticket_cb src/tls/tlsv1_client.h /^typedef int (*tlsv1_client_session_ticket_cb)$/;" t +tlsv1_client_set_cipher_list src/tls/tlsv1_client.c /^int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers)$/;" f +tlsv1_client_set_cred src/tls/tlsv1_client.c /^int tlsv1_client_set_cred(struct tlsv1_client *conn,$/;" f +tlsv1_client_set_session_ticket_cb src/tls/tlsv1_client.c /^void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,$/;" f +tlsv1_client_set_time_checks src/tls/tlsv1_client.c /^void tlsv1_client_set_time_checks(struct tlsv1_client *conn, int enabled)$/;" f +tlsv1_client_shutdown src/tls/tlsv1_client.c /^int tlsv1_client_shutdown(struct tlsv1_client *conn)$/;" f +tlsv1_cred_alloc src/tls/tlsv1_cred.c /^struct tlsv1_credentials * tlsv1_cred_alloc(void)$/;" f +tlsv1_cred_free src/tls/tlsv1_cred.c /^void tlsv1_cred_free(struct tlsv1_credentials *cred)$/;" f +tlsv1_credentials src/tls/tlsv1_cred.h /^struct tlsv1_credentials {$/;" s +tlsv1_key_x_anon_dh src/tls/tlsv1_client_write.c /^static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)$/;" f file: +tlsv1_key_x_rsa src/tls/tlsv1_client_write.c /^static int tlsv1_key_x_rsa(struct tlsv1_client *conn, u8 **pos, u8 *end)$/;" f file: +tlsv1_process_diffie_hellman src/tls/tlsv1_client_read.c /^static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,$/;" f file: +tlsv1_record_change_read_cipher src/tls/tlsv1_record.c /^int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)$/;" f +tlsv1_record_change_write_cipher src/tls/tlsv1_record.c /^int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl)$/;" f +tlsv1_record_layer src/tls/tlsv1_record.h /^struct tlsv1_record_layer {$/;" s +tlsv1_record_receive src/tls/tlsv1_record.c /^int tlsv1_record_receive(struct tlsv1_record_layer *rl,$/;" f +tlsv1_record_send src/tls/tlsv1_record.c /^int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,$/;" f +tlsv1_record_set_cipher_suite src/tls/tlsv1_record.c /^int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,$/;" f +tlsv1_server src/tls/tlsv1_server_i.h /^struct tlsv1_server {$/;" s +tlsv1_server_alert src/tls/tlsv1_server.c /^void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description)$/;" f +tlsv1_server_clear_data src/tls/tlsv1_server.c /^static void tlsv1_server_clear_data(struct tlsv1_server *conn)$/;" f file: +tlsv1_server_decrypt src/tls/tlsv1_server.c /^int tlsv1_server_decrypt(struct tlsv1_server *conn,$/;" f +tlsv1_server_deinit src/tls/tlsv1_server.c /^void tlsv1_server_deinit(struct tlsv1_server *conn)$/;" f +tlsv1_server_derive_keys src/tls/tlsv1_server.c /^int tlsv1_server_derive_keys(struct tlsv1_server *conn,$/;" f +tlsv1_server_encrypt src/tls/tlsv1_server.c /^int tlsv1_server_encrypt(struct tlsv1_server *conn,$/;" f +tlsv1_server_established src/tls/tlsv1_server.c /^int tlsv1_server_established(struct tlsv1_server *conn)$/;" f +tlsv1_server_get_cipher src/tls/tlsv1_server.c /^int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf,$/;" f +tlsv1_server_get_keyblock_size src/tls/tlsv1_server.c /^int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn)$/;" f +tlsv1_server_get_keys src/tls/tlsv1_server.c /^int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys)$/;" f +tlsv1_server_global_deinit src/tls/tlsv1_server.c /^void tlsv1_server_global_deinit(void)$/;" f +tlsv1_server_global_init src/tls/tlsv1_server.c /^int tlsv1_server_global_init(void)$/;" f +tlsv1_server_handshake src/tls/tlsv1_server.c /^u8 * tlsv1_server_handshake(struct tlsv1_server *conn,$/;" f +tlsv1_server_handshake_write src/tls/tlsv1_server_write.c /^u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len)$/;" f +tlsv1_server_init src/tls/tlsv1_server.c /^struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred)$/;" f +tlsv1_server_prf src/tls/tlsv1_server.c /^int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,$/;" f +tlsv1_server_process_handshake src/tls/tlsv1_server_read.c /^int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,$/;" f +tlsv1_server_resumed src/tls/tlsv1_server.c /^int tlsv1_server_resumed(struct tlsv1_server *conn)$/;" f +tlsv1_server_send_alert src/tls/tlsv1_server_write.c /^u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,$/;" f +tlsv1_server_session_ticket_cb src/tls/tlsv1_server.h /^typedef int (*tlsv1_server_session_ticket_cb)$/;" t +tlsv1_server_set_cipher_list src/tls/tlsv1_server.c /^int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers)$/;" f +tlsv1_server_set_session_ticket_cb src/tls/tlsv1_server.c /^void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,$/;" f +tlsv1_server_set_verify src/tls/tlsv1_server.c /^int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer)$/;" f +tlsv1_server_shutdown src/tls/tlsv1_server.c /^int tlsv1_server_shutdown(struct tlsv1_server *conn)$/;" f +tlsv1_set_ca_cert src/tls/tlsv1_cred.c /^int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,$/;" f +tlsv1_set_cert src/tls/tlsv1_cred.c /^int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,$/;" f +tlsv1_set_cert_chain src/tls/tlsv1_cred.c /^static int tlsv1_set_cert_chain(struct x509_certificate **chain,$/;" f file: +tlsv1_set_dhparams src/tls/tlsv1_cred.c /^int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,$/;" f +tlsv1_set_dhparams_blob src/tls/tlsv1_cred.c /^static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,$/;" f file: +tlsv1_set_dhparams_der src/tls/tlsv1_cred.c /^static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,$/;" f file: +tlsv1_set_key src/tls/tlsv1_cred.c /^static int tlsv1_set_key(struct tlsv1_credentials *cred,$/;" f file: +tlsv1_set_key_enc_pem src/tls/tlsv1_cred.c /^static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,$/;" f file: +tlsv1_set_key_pem src/tls/tlsv1_cred.c /^static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len)$/;" f file: +tlsv1_set_private_key src/tls/tlsv1_cred.c /^int tlsv1_set_private_key(struct tlsv1_credentials *cred,$/;" f +tlv_type src/eap_peer/eap_tlv_common.h /^ be16 tlv_type; \/* PAC_TYPE_PAC_TYPE *\/$/;" m struct:eap_tlv_pac_type_tlv +tlv_type src/eap_peer/eap_tlv_common.h /^ be16 tlv_type;$/;" m struct:eap_tlv_crypto_binding_tlv +tlv_type src/eap_peer/eap_tlv_common.h /^ be16 tlv_type;$/;" m struct:eap_tlv_hdr +tlv_type src/eap_peer/eap_tlv_common.h /^ be16 tlv_type;$/;" m struct:eap_tlv_intermediate_result_tlv +tlv_type src/eap_peer/eap_tlv_common.h /^ be16 tlv_type;$/;" m struct:eap_tlv_nak_tlv +tlv_type src/eap_peer/eap_tlv_common.h /^ be16 tlv_type;$/;" m struct:eap_tlv_pac_ack_tlv +tlv_type src/eap_peer/eap_tlv_common.h /^ be16 tlv_type;$/;" m struct:eap_tlv_request_action_tlv +tlv_type src/eap_peer/eap_tlv_common.h /^ be16 tlv_type;$/;" m struct:eap_tlv_result_tlv +tmp_eap_user src/ap/hostapd.h /^ struct hostapd_eap_user tmp_eap_user;$/;" m struct:hostapd_data typeref:struct:hostapd_data::hostapd_eap_user +tnc_started src/eap_peer/eap_ttls.c /^ int tnc_started;$/;" m struct:eap_ttls_data file: +totrot src/crypto/des-internal.c /^static const u8 totrot[16] = {$/;" v file: +tptk src/rsn_supp/wpa.h /^ struct wpa_ptk ptk, tptk;$/;" m struct:wpa_sm typeref:struct:wpa_sm:: +tptk_set src/rsn_supp/wpa.h /^ int ptk_set, tptk_set;$/;" m struct:wpa_sm +trans_id src/common/ieee802_11_defs.h /^ u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon82 +trans_id src/common/ieee802_11_defs.h /^ u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon83 +trusted_certs src/tls/tlsv1_cred.h /^ struct x509_certificate *trusted_certs;$/;" m struct:tlsv1_credentials typeref:struct:tlsv1_credentials::x509_certificate +ts_info src/common/ieee802_11_defs.h /^ u8 ts_info[3];$/;" m struct:wmm_tspec_element +ttls_avp src/eap_peer/eap_ttls.h /^struct ttls_avp {$/;" s +ttls_avp_vendor src/eap_peer/eap_ttls.h /^struct ttls_avp_vendor {$/;" s +ttls_parse_avp src/eap_peer/eap_ttls.c /^struct ttls_parse_avp {$/;" s file: +ttls_version src/eap_peer/eap_ttls.c /^ int ttls_version;$/;" m struct:eap_ttls_data file: +tx src/common/wpa_common.h /^ int tx, key_rsc_len, keyidx;$/;" m struct:wpa_gtk_data +tx_bf_capability_info src/common/ieee802_11_defs.h /^ le32 tx_bf_capability_info;$/;" m struct:ieee80211_ht_capabilities +tx_mic_key src/common/wpa_common.h /^ u8 tx_mic_key[8];$/;" m struct:wpa_ptk::__anon62::__anon63 +tx_status src/ap/wpa_auth.h /^ int tx_status;$/;" m struct:wpa_auth_config +txcb_flags src/rsn_supp/wpa.h /^ u16 txcb_flags;$/;" m struct:wpa_sm +txop_limit src/common/ieee802_11_defs.h /^ le16 txop_limit;$/;" m struct:wmm_ac_parameter +type src/common/eapol_common.h /^ u8 type;$/;" m struct:ieee802_1x_eapol_key +type src/common/eapol_common.h /^ u8 type;$/;" m struct:ieee802_1x_hdr +type src/common/wpa_common.h /^ u8 type;$/;" m struct:wpa_eapol_key +type src/tls/tls.h /^ const char *type;$/;" m struct:tls_event_data::__anon36 +type src/tls/tlsv1_common.h /^ tls_cipher_type type;$/;" m struct:tls_cipher_data +type src/tls/x509v3.h /^ } type;$/;" m struct:x509_name_attr typeref:enum:x509_name_attr::x509_name_attr_type +type src/wps/wps.h /^ enum wps_msg_type type;$/;" m struct:upnp_pending_message typeref:enum:upnp_pending_message::wps_msg_type +u src/common/ieee802_11_defs.h /^ } u;$/;" m struct:ieee80211_mgmt::__anon66::__anon76 typeref:union:ieee80211_mgmt::__anon66::__anon76::__anon77 +u src/common/ieee802_11_defs.h /^ } u;$/;" m struct:ieee80211_mgmt typeref:union:ieee80211_mgmt::__anon66 +u src/common/wpa_common.h /^ } u;$/;" m struct:wpa_ptk typeref:union:wpa_ptk::__anon62 +u src/crypto/crypto_internal-cipher.c /^ } u;$/;" m struct:crypto_cipher typeref:union:crypto_cipher::__anon10 file: +u src/crypto/crypto_internal.c /^ } u;$/;" m struct:crypto_hash typeref:union:crypto_hash::__anon9 file: +u src/fast_crypto/fast_crypto_internal-cipher.c /^ } u;$/;" m struct:fast_crypto_cipher typeref:union:fast_crypto_cipher::__anon56 file: +u src/fast_crypto/fast_crypto_internal.c /^ } u;$/;" m struct:fast_crypto_hash typeref:union:fast_crypto_hash::__anon61 file: +u16 include/utils/common.h /^typedef uint16_t u16;$/;" t +u32 include/utils/common.h /^typedef uint32_t u32;$/;" t +u64 include/utils/common.h /^typedef uint64_t u64;$/;" t +u8 include/utils/common.h /^typedef uint8_t u8;$/;" t +uint16_t port/include/endian.h /^typedef __uint16_t uint16_t;$/;" t +uint32_t port/include/endian.h /^typedef __uint32_t uint32_t;$/;" t +uint64_t port/include/endian.h /^typedef __uint64_t uint64_t;$/;" t +uint8_t port/include/endian.h /^typedef __uint8_t uint8_t;$/;" t +upc src/ap/ap_config.h /^ char *upc;$/;" m struct:hostapd_bss_config +upc src/wps/wps.h /^ const char *upc;$/;" m struct:wps_event_data::wps_event_er_ap +upc src/wps/wps.h /^ char *upc;$/;" m struct:wps_context +update_snonce src/ap/wpa_auth_i.h /^ unsigned int update_snonce:1;$/;" m struct:wpa_state_machine +upnp_iface src/ap/ap_config.h /^ char *upnp_iface;$/;" m struct:hostapd_bss_config +upnp_pending_message src/wps/wps.h /^struct upnp_pending_message {$/;" s +uri src/tls/x509v3.h /^ char *uri; \/* uniformResourceIdentifier *\/$/;" m struct:x509_name +use_cred src/wps/wps_i.h /^ struct wps_credential *use_cred;$/;" m struct:wps_data typeref:struct:wps_data::wps_credential +use_psk_key src/wps/wps.h /^ int use_psk_key;$/;" m struct:wps_config +use_psk_key src/wps/wps_i.h /^ int use_psk_key;$/;" m struct:wps_data +use_session_ticket src/tls/tlsv1_client_i.h /^ unsigned int use_session_ticket:1;$/;" m struct:tlsv1_client +use_session_ticket src/tls/tlsv1_server_i.h /^ int use_session_ticket;$/;" m struct:tlsv1_server +usec port/include/os.h /^ os_time_t usec;$/;" m struct:os_time +used include/utils/wpabuf.h /^ size_t used; \/* length of data in the buffer *\/$/;" m struct:wpabuf +used src/crypto/libtommath.h /^ int used, alloc, sign;$/;" m struct:__anon8 +used src/tls/libtommath.h /^ int used, alloc, sign;$/;" m struct:__anon40 +used_bytes src/crypto/crypto_internal-cipher.c /^ size_t used_bytes;$/;" m struct:crypto_cipher::__anon10::__anon11 file: +used_bytes src/fast_crypto/fast_crypto_internal-cipher.c /^ size_t used_bytes;$/;" m struct:fast_crypto_cipher::__anon56::__anon57 file: +utf8_ssid src/ap/ap_config.h /^ unsigned int utf8_ssid:1;$/;" m struct:hostapd_ssid +utf8_to_ucs2 src/crypto/ms_funcs.c /^static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,$/;" f file: +uuid src/ap/ap_config.h /^ u8 uuid[16];$/;" m struct:hostapd_bss_config +uuid src/wps/wps.h /^ const u8 *uuid;$/;" m struct:wps_event_data::wps_event_er_ap +uuid src/wps/wps.h /^ const u8 *uuid;$/;" m struct:wps_event_data::wps_event_er_ap_settings +uuid src/wps/wps.h /^ const u8 *uuid;$/;" m struct:wps_event_data::wps_event_er_enrollee +uuid src/wps/wps.h /^ const u8 *uuid;$/;" m struct:wps_event_data::wps_event_er_set_selected_registrar +uuid src/wps/wps.h /^ u8 uuid[16];$/;" m struct:wps_context +uuid src/wps/wps.h /^ u8 uuid[16];$/;" m struct:wps_sm +uuid src/wps/wps_registrar.c /^ u8 uuid[WPS_UUID_LEN];$/;" m struct:wps_registrar_device file: +uuid src/wps/wps_registrar.c /^ u8 uuid[WPS_UUID_LEN];$/;" m struct:wps_uuid_pin file: +uuid_bin2str src/utils/uuid.c /^int uuid_bin2str(const u8 *bin, char *str, size_t max_len)$/;" f +uuid_e src/wps/wps_attr_parse.h /^ const u8 *uuid_e; \/* WPS_UUID_LEN (16) octets *\/$/;" m struct:wps_parse_attr +uuid_e src/wps/wps_i.h /^ u8 uuid_e[WPS_UUID_LEN];$/;" m struct:wps_data +uuid_e src/wps/wps_registrar.c /^ u8 uuid_e[WPS_UUID_LEN];$/;" m struct:wps_pbc_session file: +uuid_gen_mac_addr src/wps/wps_common.c /^void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid)$/;" f +uuid_r src/wps/wps_attr_parse.h /^ const u8 *uuid_r; \/* WPS_UUID_LEN (16) octets *\/$/;" m struct:wps_parse_attr +uuid_r src/wps/wps_i.h /^ u8 uuid_r[WPS_UUID_LEN];$/;" m struct:wps_data +uuid_str2bin src/utils/uuid.c /^int uuid_str2bin(const char *str, u8 *bin)$/;" f +valid src/ap/wpa_auth_i.h /^ Boolean valid;$/;" m struct:wpa_state_machine::wpa_key_replay_counter +valid_config_methods src/wps/wps_validate.c /^static int valid_config_methods(u16 val, int wps2)$/;" f file: +value src/tls/x509v3.h /^ char *value;$/;" m struct:x509_name_attr +variable src/common/ieee802_11_defs.h /^ u8 variable[0]; \/* FT Request *\/$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon80 +variable src/common/ieee802_11_defs.h /^ u8 variable[0]; \/* FT Request *\/$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon81 +variable src/common/ieee802_11_defs.h /^ u8 variable[0];$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon78 +variable src/common/ieee802_11_defs.h /^ u8 variable[0];$/;" m struct:ieee80211_mgmt::__anon66::__anon67 +variable src/common/ieee802_11_defs.h /^ u8 variable[0];$/;" m struct:ieee80211_mgmt::__anon66::__anon69 +variable src/common/ieee802_11_defs.h /^ u8 variable[0];$/;" m struct:ieee80211_mgmt::__anon66::__anon70 +variable src/common/ieee802_11_defs.h /^ u8 variable[0];$/;" m struct:ieee80211_mgmt::__anon66::__anon71 +variable src/common/ieee802_11_defs.h /^ u8 variable[0];$/;" m struct:ieee80211_mgmt::__anon66::__anon73 +variable src/common/ieee802_11_defs.h /^ u8 variable[0];$/;" m struct:ieee80211_mgmt::__anon66::__anon74 +variable src/common/ieee802_11_defs.h /^ u8 variable[0];$/;" m struct:ieee80211_mgmt::__anon66::__anon75 +vendor src/eap_peer/eap.h /^ int vendor;$/;" m struct:eap_method_type +vendor src/eap_peer/eap_i.h /^ int vendor;$/;" m struct:eap_method +vendor_ext src/wps/wps.h /^ struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];$/;" m struct:wps_device_data typeref:struct:wps_device_data::wpabuf +vendor_ext src/wps/wps_attr_parse.h /^ const u8 *vendor_ext[MAX_WPS_PARSE_VENDOR_EXT];$/;" m struct:wps_parse_attr +vendor_ext_len src/wps/wps_attr_parse.h /^ size_t vendor_ext_len[MAX_WPS_PARSE_VENDOR_EXT];$/;" m struct:wps_parse_attr +vendor_ext_m1 src/wps/wps.h /^ struct wpabuf *vendor_ext_m1;$/;" m struct:wps_device_data typeref:struct:wps_device_data::wpabuf +vendor_id src/eap_peer/eap_defs.h /^ u8 vendor_id[3];$/;" m struct:eap_expand +vendor_id src/eap_peer/eap_tlv_common.h /^ be32 vendor_id;$/;" m struct:eap_tlv_nak_tlv +vendor_id src/eap_peer/eap_ttls.h /^ be32 vendor_id;$/;" m struct:ttls_avp_vendor +vendor_type src/eap_peer/eap_defs.h /^ be32 vendor_type;$/;" m struct:eap_expand +verify src/tls/tlsv1_client_i.h /^ struct tls_verify_hash verify;$/;" m struct:tlsv1_client typeref:struct:tlsv1_client::tls_verify_hash +verify src/tls/tlsv1_server_i.h /^ struct tls_verify_hash verify;$/;" m struct:tlsv1_server typeref:struct:tlsv1_server::tls_verify_hash +verify_peer src/tls/tlsv1_server_i.h /^ int verify_peer;$/;" m struct:tlsv1_server +version src/common/eapol_common.h /^ u8 version;$/;" m struct:ieee802_1x_hdr +version src/common/ieee802_11_defs.h /^ u8 version; \/* 1 *\/$/;" m struct:wmm_tspec_element +version src/common/ieee802_11_defs.h /^ u8 version; \/* 1 for WMM version 1.0 *\/$/;" m struct:wmm_information_element +version src/common/ieee802_11_defs.h /^ u8 version; \/* 1 for WMM version 1.0 *\/$/;" m struct:wmm_parameter_element +version src/common/wpa_common.h /^ u8 version[2]; \/* little endian *\/$/;" m struct:rsn_ie_hdr +version src/common/wpa_common.h /^ u8 version[2]; \/* little endian *\/$/;" m struct:wpa_ie_hdr +version src/eap_peer/eap_tlv_common.h /^ u8 version;$/;" m struct:eap_tlv_crypto_binding_tlv +version src/tls/x509v3.h /^ enum { X509_CERT_V1 = 0, X509_CERT_V2 = 1, X509_CERT_V3 = 2 } version;$/;" m struct:x509_certificate typeref:enum:x509_certificate::__anon41 +version src/wps/wps_attr_parse.h /^ const u8 *version; \/* 1 octet *\/$/;" m struct:wps_parse_attr +version2 src/wps/wps_attr_parse.h /^ const u8 *version2; \/* 1 octet *\/$/;" m struct:wps_parse_attr +vht_capab src/ap/ap_config.h /^ u32 vht_capab;$/;" m struct:hostapd_config +vht_oper_centr_freq_seg0_idx src/ap/ap_config.h /^ u8 vht_oper_centr_freq_seg0_idx;$/;" m struct:hostapd_config +vht_oper_centr_freq_seg1_idx src/ap/ap_config.h /^ u8 vht_oper_centr_freq_seg1_idx;$/;" m struct:hostapd_config +vht_oper_chwidth src/ap/ap_config.h /^ u8 vht_oper_chwidth;$/;" m struct:hostapd_config +vlan_id src/ap/ap_config.h /^ int vlan_id;$/;" m struct:mac_acl_entry +vlan_id src/ap/wpa_auth_i.h /^ int vlan_id;$/;" m struct:wpa_group +wep src/ap/ap_config.h /^ struct hostapd_wep_keys wep;$/;" m struct:hostapd_ssid typeref:struct:hostapd_ssid::hostapd_wep_keys +wep_rekeying_period src/ap/ap_config.h /^ int wep_rekeying_period;$/;" m struct:hostapd_bss_config +wifi_appie src/esp_supplicant/esp_wifi_driver.h /^struct wifi_appie {$/;" s +wifi_cipher src/esp_supplicant/esp_wifi_driver.h /^struct wifi_cipher {$/;" s +wifi_ipc_config_t src/esp_supplicant/esp_wifi_driver.h /^} wifi_ipc_config_t;$/;" t typeref:struct:__anon32 +wifi_ipc_fn_t src/esp_supplicant/esp_wifi_driver.h /^typedef int (*wifi_ipc_fn_t)(void *);$/;" t +wifi_key src/esp_supplicant/esp_wifi_driver.h /^struct wifi_key {$/;" s +wifi_key_alg src/common/defs.h /^enum wifi_key_alg {$/;" g +wifi_keyix src/esp_supplicant/esp_wifi_driver.h /^typedef uint16_t wifi_keyix; \/* h\/w key index *\/$/;" t +wifi_set_wps_cb src/esp_supplicant/esp_wps.c /^wifi_set_wps_cb(wps_st_cb_t cb)$/;" f +wifi_ssid src/esp_supplicant/esp_wifi_driver.h /^struct wifi_ssid {$/;" s +wifi_sta_get_enterprise_disable_time_check src/esp_supplicant/esp_wpa_enterprise.c /^bool wifi_sta_get_enterprise_disable_time_check(void)$/;" f +wifi_station_wps_deinit src/esp_supplicant/esp_wps.c /^wifi_station_wps_deinit(void)$/;" f +wifi_station_wps_eapol_start_handle src/esp_supplicant/esp_wps.c /^void wifi_station_wps_eapol_start_handle(void)$/;" f +wifi_station_wps_eapol_start_handle_internal src/esp_supplicant/esp_wps.c /^void wifi_station_wps_eapol_start_handle_internal(void)$/;" f +wifi_station_wps_init src/esp_supplicant/esp_wps.c /^wifi_station_wps_init(void)$/;" f +wifi_station_wps_msg_timeout src/esp_supplicant/esp_wps.c /^void wifi_station_wps_msg_timeout(void)$/;" f +wifi_station_wps_msg_timeout_internal src/esp_supplicant/esp_wps.c /^wifi_station_wps_msg_timeout_internal(void)$/;" f +wifi_station_wps_start src/esp_supplicant/esp_wifi_driver.h /^ int (*wifi_station_wps_start)(void);$/;" m struct:wps_funcs +wifi_station_wps_start src/esp_supplicant/esp_wps.c /^int wifi_station_wps_start(void)$/;" f +wifi_station_wps_success src/esp_supplicant/esp_wps.c /^void wifi_station_wps_success(void)$/;" f +wifi_station_wps_success_internal src/esp_supplicant/esp_wps.c /^void wifi_station_wps_success_internal(void)$/;" f +wifi_station_wps_timeout src/esp_supplicant/esp_wps.c /^void wifi_station_wps_timeout(void)$/;" f +wifi_station_wps_timeout_internal src/esp_supplicant/esp_wps.c /^wifi_station_wps_timeout_internal(void)$/;" f +wifi_tx_cb_t src/esp_supplicant/esp_wifi_driver.h /^typedef void(* wifi_tx_cb_t)(void *);$/;" t +wifi_wpa2_fn_t src/esp_supplicant/esp_wifi_driver.h /^typedef esp_err_t (*wifi_wpa2_fn_t)(void *);$/;" t +wifi_wpa2_param_t src/esp_supplicant/esp_wifi_driver.h /^}wifi_wpa2_param_t;$/;" t typeref:struct:__anon31 +wifi_wps_disable_internal src/esp_supplicant/esp_wps.c /^int wifi_wps_disable_internal(void)$/;" f +wifi_wps_enable_internal src/esp_supplicant/esp_wps.c /^int wifi_wps_enable_internal(const esp_wps_config_t *config)$/;" f +wifi_wps_scan src/esp_supplicant/esp_wps.c /^void wifi_wps_scan(void)$/;" f +wifi_wps_scan_done src/esp_supplicant/esp_wps.c /^wifi_wps_scan_done(void *arg, STATUS status)$/;" f +wifi_wps_scan_internal src/esp_supplicant/esp_wps.c /^wifi_wps_scan_internal(void)$/;" f +wildcard_uuid src/wps/wps_registrar.c /^ int wildcard_uuid;$/;" m struct:wps_uuid_pin file: +wk_cipher src/esp_supplicant/esp_wifi_driver.h /^ const struct wifi_cipher *wk_cipher;$/;" m struct:wifi_key typeref:struct:wifi_key::wifi_cipher +wk_keyix src/esp_supplicant/esp_wifi_driver.h /^ wifi_keyix wk_keyix; \/* h\/w key index *\/$/;" m struct:wifi_key +wk_keyrsc src/esp_supplicant/esp_wifi_driver.h /^ uint64_t wk_keyrsc[WIFI_TID_SIZE];$/;" m struct:wifi_key +wk_keytsc src/esp_supplicant/esp_wifi_driver.h /^ uint64_t wk_keytsc; \/* key transmit sequence counter *\/$/;" m struct:wifi_key +wmm_ac_parameter src/common/ieee802_11_defs.h /^struct wmm_ac_parameter {$/;" s +wmm_action src/common/ieee802_11_defs.h /^ } STRUCT_PACKED wmm_action;$/;" m union:ieee80211_mgmt::__anon66::__anon76::__anon77 typeref:struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon78 +wmm_enabled src/ap/ap_config.h /^ int wmm_enabled;$/;" m struct:hostapd_bss_config +wmm_enabled src/ap/wpa_auth.h /^ int wmm_enabled;$/;" m struct:wpa_auth_config +wmm_information_element src/common/ieee802_11_defs.h /^struct wmm_information_element {$/;" s +wmm_parameter_element src/common/ieee802_11_defs.h /^struct wmm_parameter_element {$/;" s +wmm_tspec_element src/common/ieee802_11_defs.h /^struct wmm_tspec_element {$/;" s +wmm_uapsd src/ap/ap_config.h /^ int wmm_uapsd;$/;" m struct:hostapd_bss_config +wmm_uapsd src/ap/wpa_auth.h /^ int wmm_uapsd;$/;" m struct:wpa_auth_config +workaround src/eap_peer/eap_i.h /^ unsigned int workaround;$/;" m struct:eap_sm +wpa src/ap/ap_config.h /^ int wpa; \/* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN *\/$/;" m struct:hostapd_bss_config +wpa src/ap/wpa_auth.h /^ int wpa;$/;" m struct:wpa_auth_config +wpa src/ap/wpa_auth_i.h /^ } wpa;$/;" m struct:wpa_state_machine typeref:enum:wpa_state_machine::__anon26 +wpa src/esp_supplicant/esp_wifi_driver.h /^ uint8_t *wpa;$/;" m struct:wps_scan_ie +wpa2Task src/esp_supplicant/esp_wpa_enterprise.c /^void wpa2Task(void *pvParameters )$/;" f +wpa2_api_lock src/esp_supplicant/esp_wpa_enterprise.c /^static void wpa2_api_lock(void)$/;" f file: +wpa2_api_unlock src/esp_supplicant/esp_wpa_enterprise.c /^static void wpa2_api_unlock(void)$/;" f file: +wpa2_deinit src/esp_supplicant/esp_wifi_driver.h /^ void (*wpa2_deinit)(void);$/;" m struct:wpa2_funcs +wpa2_ent_eap_state_t src/esp_supplicant/esp_wifi_driver.h /^} wpa2_ent_eap_state_t;$/;" t typeref:enum:__anon30 +wpa2_funcs src/esp_supplicant/esp_wifi_driver.h /^struct wpa2_funcs {$/;" s +wpa2_get_state src/esp_supplicant/esp_wifi_driver.h /^ u8 (*wpa2_get_state)(void);$/;" m struct:wpa2_funcs +wpa2_init src/esp_supplicant/esp_wifi_driver.h /^ int (*wpa2_init)(void);$/;" m struct:wpa2_funcs +wpa2_is_disabled src/esp_supplicant/esp_wpa_enterprise.c /^static bool inline wpa2_is_disabled(void)$/;" f file: +wpa2_is_enabled src/esp_supplicant/esp_wpa_enterprise.c /^static bool inline wpa2_is_enabled(void)$/;" f file: +wpa2_machine_start src/esp_supplicant/esp_wpa_enterprise.c /^uint8_t wpa2_machine_start = 0;$/;" v +wpa2_post src/esp_supplicant/esp_wpa_enterprise.c /^ETS_STATUS wpa2_post(ETSSignal sig, ETSParam par)$/;" f +wpa2_rx_param src/esp_supplicant/esp_wpa_enterprise.c /^struct wpa2_rx_param {$/;" s file: +wpa2_sendto_wrapper src/esp_supplicant/esp_wpa_enterprise.c /^static void wpa2_sendto_wrapper(void *buffer, uint16_t len)$/;" f file: +wpa2_set_eap_state src/esp_supplicant/esp_wpa_enterprise.c /^static void wpa2_set_eap_state(wpa2_ent_eap_state_t state)$/;" f file: +wpa2_set_state src/esp_supplicant/esp_wpa_enterprise.c /^static void inline wpa2_set_state(wpa2_state_t state)$/;" f file: +wpa2_sig_cnt src/eap_peer/eap_i.h /^ u8 wpa2_sig_cnt[SIG_WPA2_MAX];$/;" m struct:eap_sm +wpa2_sm_alloc_eapol src/esp_supplicant/esp_wpa_enterprise.c /^u8 *wpa2_sm_alloc_eapol(struct eap_sm *sm, u8 type,$/;" f +wpa2_sm_ether_send src/esp_supplicant/esp_wpa_enterprise.c /^static inline int wpa2_sm_ether_send(struct eap_sm *sm, const u8 *dest, u16 proto,$/;" f file: +wpa2_sm_free_eapol src/esp_supplicant/esp_wpa_enterprise.c /^void wpa2_sm_free_eapol(u8 *buffer)$/;" f +wpa2_sm_rx_eapol src/esp_supplicant/esp_wifi_driver.h /^ int (*wpa2_sm_rx_eapol)(u8 *src_addr, u8 *buf, u32 len, u8 *bssid);$/;" m struct:wpa2_funcs +wpa2_sm_rx_eapol src/esp_supplicant/esp_wpa_enterprise.c /^static int wpa2_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid)$/;" f file: +wpa2_sm_rx_eapol_internal src/esp_supplicant/esp_wpa_enterprise.c /^static int wpa2_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid)$/;" f file: +wpa2_start src/esp_supplicant/esp_wifi_driver.h /^ int (*wpa2_start)(void);$/;" m struct:wpa2_funcs +wpa2_start_eapol src/esp_supplicant/esp_wpa_enterprise.c /^static int wpa2_start_eapol(void)$/;" f file: +wpa2_start_eapol_internal src/esp_supplicant/esp_wpa_enterprise.c /^static int wpa2_start_eapol_internal(void)$/;" f file: +wpa2_state_t src/eap_peer/eap_i.h /^}wpa2_state_t;$/;" t typeref:enum:__anon3 +wpa2_task_delete src/esp_supplicant/esp_wpa_enterprise.c /^static inline void wpa2_task_delete(void *arg)$/;" f file: +wpa2_task_hdl src/esp_supplicant/esp_wpa_enterprise.c /^static void *wpa2_task_hdl = NULL;$/;" v file: +wpa_add_kde src/ap/wpa_auth_ie.c /^u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,$/;" f +wpa_alg src/common/defs.h /^enum wpa_alg {$/;" g +wpa_ap_deinit src/esp_supplicant/esp_wifi_driver.h /^ bool (*wpa_ap_deinit)(void* data);$/;" m struct:wpa_funcs +wpa_ap_get_wpa_ie src/esp_supplicant/esp_wifi_driver.h /^ uint8_t* (*wpa_ap_get_wpa_ie)(uint8_t *len);$/;" m struct:wpa_funcs +wpa_ap_get_wpa_ie src/esp_supplicant/esp_wpa_main.c /^uint8_t *wpa_ap_get_wpa_ie(uint8_t *ie_len)$/;" f +wpa_ap_init src/esp_supplicant/esp_wifi_driver.h /^ void* (*wpa_ap_init)(void);$/;" m struct:wpa_funcs +wpa_ap_join src/ap/wpa_auth.c /^bool wpa_ap_join(void** sm, uint8_t *bssid, uint8_t *wpa_ie, uint8_t wpa_ie_len)$/;" f +wpa_ap_join src/esp_supplicant/esp_wifi_driver.h /^ bool (*wpa_ap_join)(void** sm, u8 *bssid, u8 *wpa_ie, u8 wpa_ie_len);$/;" m struct:wpa_funcs +wpa_ap_remove src/ap/wpa_auth.c /^bool wpa_ap_remove(void* sm)$/;" f +wpa_ap_remove src/esp_supplicant/esp_wifi_driver.h /^ bool (*wpa_ap_remove)(void* sm);$/;" m struct:wpa_funcs +wpa_ap_rx_eapol src/esp_supplicant/esp_wifi_driver.h /^ bool (*wpa_ap_rx_eapol)(void* hapd_data, void *sm, u8 *data, size_t data_len);$/;" m struct:wpa_funcs +wpa_ap_rx_eapol src/esp_supplicant/esp_wpa_main.c /^bool wpa_ap_rx_eapol(void *hapd_data, void *sm_data, u8 *data, size_t data_len)$/;" f +wpa_attach src/esp_supplicant/esp_wpa_main.c /^void wpa_attach(void)$/;" f +wpa_auth src/ap/hostapd.h /^ struct wpa_authenticator *wpa_auth;$/;" m struct:hostapd_data typeref:struct:hostapd_data::wpa_authenticator +wpa_auth src/ap/wpa_auth_i.h /^ struct wpa_authenticator *wpa_auth;$/;" m struct:wpa_state_machine typeref:struct:wpa_state_machine::wpa_authenticator +wpa_auth_add_sm src/ap/wpa_auth.c /^static void wpa_auth_add_sm(struct wpa_state_machine *sm)$/;" f file: +wpa_auth_callbacks src/ap/wpa_auth.h /^struct wpa_auth_callbacks {$/;" s +wpa_auth_config src/ap/wpa_auth.h /^struct wpa_auth_config {$/;" s +wpa_auth_del_sm src/ap/wpa_auth.c /^static void wpa_auth_del_sm(struct wpa_state_machine *sm)$/;" f file: +wpa_auth_for_each_sta src/ap/wpa_auth.c /^int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,$/;" f +wpa_auth_gen_wpa_ie src/ap/wpa_auth_ie.c /^int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)$/;" f +wpa_auth_get_eapol src/ap/wpa_auth.c /^static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth,$/;" f file: +wpa_auth_get_msk src/ap/wpa_auth.c /^static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,$/;" f file: +wpa_auth_get_psk src/ap/wpa_auth.c /^static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,$/;" f file: +wpa_auth_get_seqnum src/ap/wpa_auth.c /^static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,$/;" f file: +wpa_auth_get_sm src/ap/wpa_auth.c /^static struct wpa_state_machine * wpa_auth_get_sm(u32 index)$/;" f file: +wpa_auth_logger include/utils/wpa_debug.h 161;" d +wpa_auth_mic_failure_report src/ap/wpa_auth.c /^static inline int wpa_auth_mic_failure_report($/;" f file: +wpa_auth_send_eapol src/ap/wpa_auth.c /^wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,$/;" f file: +wpa_auth_set_eapol src/ap/wpa_auth.c /^static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth,$/;" f file: +wpa_auth_set_key src/ap/wpa_auth.c /^static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,$/;" f file: +wpa_auth_sm_event src/ap/wpa_auth.c /^int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)$/;" f +wpa_auth_sta_associated src/ap/wpa_auth.c /^int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,$/;" f +wpa_auth_sta_deinit src/ap/wpa_auth.c /^void wpa_auth_sta_deinit(struct wpa_state_machine *sm)$/;" f +wpa_auth_sta_init src/ap/wpa_auth.c /^wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr)$/;" f +wpa_auth_sta_no_wpa src/ap/wpa_auth.c /^void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm)$/;" f +wpa_auth_uses_mfp src/ap/wpa_auth_ie.c /^int wpa_auth_uses_mfp(struct wpa_state_machine *sm)$/;" f +wpa_auth_vlogger include/utils/wpa_debug.h 162;" d +wpa_authenticator src/ap/wpa_auth_i.h /^struct wpa_authenticator {$/;" s +wpa_cipher src/common/defs.h /^enum wpa_cipher {$/;" g +wpa_cipher_key_len src/common/wpa_common.c /^int wpa_cipher_key_len(int cipher)$/;" f +wpa_cipher_put_suites src/common/wpa_common.c /^int wpa_cipher_put_suites(u8 *pos, int ciphers)$/;" f +wpa_cipher_to_alg src/common/wpa_common.c /^int wpa_cipher_to_alg(int cipher)$/;" f +wpa_cipher_to_suite src/common/wpa_common.c /^u32 wpa_cipher_to_suite(int proto, int cipher)$/;" f +wpa_cipher_txt src/common/wpa_common.c /^const char * wpa_cipher_txt(int cipher)$/;" f +wpa_compare_rsn_ie src/common/wpa_common.c /^int wpa_compare_rsn_ie(int ft_initial_assoc,$/;" f +wpa_config_assoc_ie src/esp_supplicant/esp_wpa_main.c /^void wpa_config_assoc_ie(u8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len)$/;" f +wpa_config_blob src/eap_peer/eap_config.h /^struct wpa_config_blob {$/;" s +wpa_config_bss src/esp_supplicant/esp_wpa_main.c /^void wpa_config_bss(uint8_t *bssid)$/;" f +wpa_config_parse_string src/utils/common.c /^char * wpa_config_parse_string(const char *value, size_t *len)$/;" f +wpa_config_profile src/esp_supplicant/esp_wpa_main.c /^void wpa_config_profile()$/;" f +wpa_deattach src/esp_supplicant/esp_wpa_main.c /^bool wpa_deattach(void)$/;" f +wpa_deauthenticate src/esp_supplicant/esp_wpa_main.c /^void wpa_deauthenticate(u8 reason_code)$/;" f +wpa_deauthenticate src/rsn_supp/wpa.h /^ void (*wpa_deauthenticate)(u8 reason_code);$/;" m struct:wpa_sm +wpa_debug_print_timestamp src/utils/wpa_debug.c /^void wpa_debug_print_timestamp(void)$/;" f +wpa_derive_ptk src/ap/wpa_auth.c /^static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk,$/;" f file: +wpa_derive_ptk src/rsn_supp/wpa.c /^int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,$/;" f +wpa_dump_mem src/utils/wpa_debug.c /^void wpa_dump_mem(char* desc, uint8_t *addr, uint16_t len)$/;" f +wpa_eapol_ie_parse src/ap/wpa_auth_ie.h /^struct wpa_eapol_ie_parse {$/;" s +wpa_eapol_ie_parse src/rsn_supp/wpa_ie.h /^struct wpa_eapol_ie_parse {$/;" s +wpa_eapol_key src/common/wpa_common.h /^struct wpa_eapol_key {$/;" s +wpa_eapol_key_dump src/rsn_supp/wpa.c /^ void wpa_eapol_key_dump(int level, const struct wpa_eapol_key *key)$/;" f +wpa_eapol_key_mic src/common/wpa_common.c /^int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,$/;" f +wpa_eapol_key_send src/rsn_supp/wpa.c /^void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,$/;" f +wpa_eapol_variable src/ap/wpa_auth.h /^} wpa_eapol_variable;$/;" t typeref:enum:__anon21 +wpa_event src/ap/wpa_auth.h /^} wpa_event;$/;" t typeref:enum:__anon23 +wpa_free_sta_sm src/ap/wpa_auth.c /^static void wpa_free_sta_sm(struct wpa_state_machine *sm)$/;" f file: +wpa_funcs src/esp_supplicant/esp_wifi_driver.h /^struct wpa_funcs {$/;" s +wpa_gen_wpa_ie src/rsn_supp/wpa_ie.c /^int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)$/;" f +wpa_gen_wpa_ie_rsn src/rsn_supp/wpa_ie.c /^static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,$/;" f file: +wpa_gen_wpa_ie_wpa src/rsn_supp/wpa_ie.c /^static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,$/;" f file: +wpa_get_key src/esp_supplicant/esp_wpa_main.c /^int wpa_get_key(uint8_t *ifx, int *alg, u8 *addr, int *key_idx,$/;" f +wpa_get_ntp_timestamp src/utils/common.c /^void wpa_get_ntp_timestamp(u8 *buf)$/;" f +wpa_gmk_rekey src/ap/ap_config.h /^ int wpa_gmk_rekey;$/;" m struct:hostapd_bss_config +wpa_gmk_rekey src/ap/wpa_auth.h /^ int wpa_gmk_rekey;$/;" m struct:wpa_auth_config +wpa_gmk_to_gtk src/ap/wpa_auth.c /^static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr,$/;" f file: +wpa_group src/ap/ap_config.h /^ int wpa_group;$/;" m struct:hostapd_bss_config +wpa_group src/ap/wpa_auth.h /^ int wpa_group;$/;" m struct:wpa_auth_config +wpa_group src/ap/wpa_auth_i.h /^struct wpa_group {$/;" s +wpa_group_config_group_keys src/ap/wpa_auth.c /^static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,$/;" f file: +wpa_group_ensure_init src/ap/wpa_auth.c /^static void wpa_group_ensure_init(struct wpa_authenticator *wpa_auth,$/;" f file: +wpa_group_gtk_init src/ap/wpa_auth.c /^static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,$/;" f file: +wpa_group_init src/ap/wpa_auth.c /^static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,$/;" f file: +wpa_group_init_gmk_and_counter src/ap/wpa_auth.c /^static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,$/;" f file: +wpa_group_rekey src/ap/ap_config.h /^ int wpa_group_rekey;$/;" m struct:hostapd_bss_config +wpa_group_rekey src/ap/wpa_auth.h /^ int wpa_group_rekey;$/;" m struct:wpa_auth_config +wpa_group_setkeys src/ap/wpa_auth.c /^static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,$/;" f file: +wpa_group_setkeysdone src/ap/wpa_auth.c /^static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,$/;" f file: +wpa_group_sm_step src/ap/wpa_auth.c /^static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,$/;" f file: +wpa_group_state src/ap/wpa_auth_i.h /^ } wpa_group_state;$/;" m struct:wpa_group typeref:enum:wpa_group::__anon27 +wpa_group_update_sta src/ap/wpa_auth.c /^static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)$/;" f file: +wpa_gtk_data src/common/wpa_common.h /^struct wpa_gtk_data {$/;" s +wpa_gtk_update src/ap/wpa_auth.c /^static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,$/;" f file: +wpa_hexdump include/utils/wpa_debug.h 153;" d +wpa_hexdump src/utils/wpa_debug.c /^void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)$/;" f +wpa_hexdump_ascii include/utils/wpa_debug.h /^static inline void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len)$/;" f +wpa_hexdump_ascii include/utils/wpa_debug.h 157;" d +wpa_hexdump_ascii_key include/utils/wpa_debug.h /^static inline void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, size_t len)$/;" f +wpa_hexdump_ascii_key include/utils/wpa_debug.h 158;" d +wpa_hexdump_buf include/utils/wpa_debug.h /^static inline void wpa_hexdump_buf(int level, const char *title,$/;" f +wpa_hexdump_buf include/utils/wpa_debug.h 154;" d +wpa_hexdump_buf_key include/utils/wpa_debug.h /^static inline void wpa_hexdump_buf_key(int level, const char *title,$/;" f +wpa_hexdump_buf_key include/utils/wpa_debug.h 156;" d +wpa_hexdump_key include/utils/wpa_debug.h 155;" d +wpa_hexdump_key src/utils/wpa_debug.c /^void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len)$/;" f +wpa_hook_deinit src/esp_supplicant/esp_wpa_main.c /^bool wpa_hook_deinit(void)$/;" f +wpa_ie src/ap/wpa_auth_i.h /^ u8 *wpa_ie;$/;" m struct:wpa_authenticator +wpa_ie src/ap/wpa_auth_i.h /^ u8 *wpa_ie;$/;" m struct:wpa_state_machine +wpa_ie src/ap/wpa_auth_ie.h /^ const u8 *wpa_ie;$/;" m struct:wpa_eapol_ie_parse +wpa_ie src/rsn_supp/wpa_ie.h /^ const u8 *wpa_ie;$/;" m struct:wpa_eapol_ie_parse +wpa_ie_data src/common/wpa_common.h /^struct wpa_ie_data {$/;" s +wpa_ie_hdr src/common/wpa_common.h /^struct wpa_ie_hdr {$/;" s +wpa_ie_len src/ap/wpa_auth_i.h /^ size_t wpa_ie_len;$/;" m struct:wpa_authenticator +wpa_ie_len src/ap/wpa_auth_i.h /^ size_t wpa_ie_len;$/;" m struct:wpa_state_machine +wpa_ie_len src/ap/wpa_auth_ie.h /^ size_t wpa_ie_len;$/;" m struct:wpa_eapol_ie_parse +wpa_ie_len src/rsn_supp/wpa_ie.h /^ size_t wpa_ie_len;$/;" m struct:wpa_eapol_ie_parse +wpa_igtk_kde src/common/wpa_common.h /^struct wpa_igtk_kde {$/;" s +wpa_init src/ap/wpa_auth.c /^struct wpa_authenticator * wpa_init(const u8 *addr,$/;" f +wpa_install_key src/esp_supplicant/esp_wpa_main.c /^void wpa_install_key(enum wpa_alg alg, u8 *addr, int key_idx, int set_tx,$/;" f +wpa_key_mgmt src/ap/ap_config.h /^ int wpa_key_mgmt;$/;" m struct:hostapd_bss_config +wpa_key_mgmt src/ap/wpa_auth.h /^ int wpa_key_mgmt;$/;" m struct:wpa_auth_config +wpa_key_mgmt src/ap/wpa_auth_i.h /^ int wpa_key_mgmt; \/* the selected WPA_KEY_MGMT_* *\/$/;" m struct:wpa_state_machine +wpa_key_mgmt src/common/defs.h /^enum wpa_key_mgmt {$/;" g +wpa_key_mgmt_ft src/common/defs.h /^static inline int wpa_key_mgmt_ft(int akm)$/;" f +wpa_key_mgmt_sha256 src/common/defs.h /^static inline int wpa_key_mgmt_sha256(int akm)$/;" f +wpa_key_mgmt_to_bitfield src/common/wpa_common.c /^static int wpa_key_mgmt_to_bitfield(const u8 *s)$/;" f file: +wpa_key_mgmt_wpa_ieee8021x src/common/defs.h /^static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)$/;" f +wpa_key_mgmt_wpa_psk src/common/defs.h /^static inline int wpa_key_mgmt_wpa_psk(int akm)$/;" f +wpa_key_replay_counter src/ap/wpa_auth_i.h /^ struct wpa_key_replay_counter {$/;" s struct:wpa_state_machine +wpa_msg_cb_func include/utils/wpa_debug.h /^typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt,$/;" t +wpa_neg_complete src/esp_supplicant/esp_wpa_main.c /^void wpa_neg_complete()$/;" f +wpa_neg_complete src/rsn_supp/wpa.h /^ void (*wpa_neg_complete)();$/;" m struct:wpa_sm +wpa_pairwise src/ap/ap_config.h /^ int wpa_pairwise;$/;" m struct:hostapd_bss_config +wpa_pairwise src/ap/wpa_auth.h /^ int wpa_pairwise;$/;" m struct:wpa_auth_config +wpa_parse_generic src/ap/wpa_auth_ie.c /^static int wpa_parse_generic(const u8 *pos, const u8 *end,$/;" f file: +wpa_parse_generic src/rsn_supp/wpa_ie.c /^static int wpa_parse_generic(const u8 *pos, const u8 *end,$/;" f file: +wpa_parse_kde_ies src/ap/wpa_auth_ie.c /^int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)$/;" f +wpa_parse_wpa_ie src/rsn_supp/wpa_ie.c /^int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,$/;" f +wpa_parse_wpa_ie_rsn src/common/wpa_common.c /^int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,$/;" f +wpa_parse_wpa_ie_wpa src/common/wpa_common.c /^int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,$/;" f +wpa_passphrase src/ap/ap_config.h /^ char *wpa_passphrase;$/;" m struct:hostapd_ssid +wpa_pmk_to_ptk src/common/wpa_common.c /^void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,$/;" f +wpa_printf include/utils/wpa_debug.h 152;" d +wpa_printf include/utils/wpa_debug.h 76;" d +wpa_psk src/ap/ap_config.h /^ struct hostapd_wpa_psk *wpa_psk;$/;" m struct:hostapd_ssid typeref:struct:hostapd_ssid::hostapd_wpa_psk +wpa_psk_radius src/ap/ap_config.h /^ } wpa_psk_radius;$/;" m struct:hostapd_bss_config typeref:enum:hostapd_bss_config::__anon18 +wpa_ptk src/common/wpa_common.h /^struct wpa_ptk {$/;" s +wpa_ptk_group_state src/ap/wpa_auth_i.h /^ } wpa_ptk_group_state;$/;" m struct:wpa_state_machine typeref:enum:wpa_state_machine::__anon25 +wpa_ptk_rekey src/ap/ap_config.h /^ int wpa_ptk_rekey;$/;" m struct:hostapd_bss_config +wpa_ptk_rekey src/ap/wpa_auth.h /^ int wpa_ptk_rekey;$/;" m struct:wpa_auth_config +wpa_ptk_rekey src/rsn_supp/wpa.h /^ int wpa_ptk_rekey;$/;" m struct:wpa_sm +wpa_ptk_state src/ap/wpa_auth_i.h /^ } wpa_ptk_state;$/;" m struct:wpa_state_machine typeref:enum:wpa_state_machine::__anon24 +wpa_receive src/ap/wpa_auth.c /^void wpa_receive(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, u8 *data, size_t data_len)$/;" f +wpa_receive_error_report src/ap/wpa_auth.c /^static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth,$/;" f file: +wpa_register src/rsn_supp/wpa.c /^void wpa_register(char * payload, WPA_SEND_FUNC snd_func,$/;" f +wpa_rekey_gtk src/ap/wpa_auth.c /^static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)$/;" f file: +wpa_rekey_ptk src/ap/wpa_auth.c /^static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx)$/;" f file: +wpa_remove_ptk src/ap/wpa_auth.c /^void wpa_remove_ptk(struct wpa_state_machine *sm)$/;" f +wpa_replay_counter_mark_invalid src/ap/wpa_auth.c /^static void wpa_replay_counter_mark_invalid(struct wpa_key_replay_counter *ctr,$/;" f file: +wpa_replay_counter_valid src/ap/wpa_auth.c /^static int wpa_replay_counter_valid(struct wpa_key_replay_counter *ctr,$/;" f file: +wpa_report_ie_mismatch src/rsn_supp/wpa.c /^void wpa_report_ie_mismatch(struct wpa_sm *sm,$/;" f +wpa_request_new_ptk src/ap/wpa_auth.c /^static void wpa_request_new_ptk(struct wpa_state_machine *sm)$/;" f file: +wpa_selector_to_bitfield src/common/wpa_common.c /^static int wpa_selector_to_bitfield(const u8 *s)$/;" f file: +wpa_send_eapol src/ap/wpa_auth.c /^static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,$/;" f file: +wpa_send_eapol_timeout src/ap/wpa_auth.c /^static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx)$/;" f file: +wpa_sendto_wrapper src/esp_supplicant/esp_wpa_main.c /^void wpa_sendto_wrapper(void *buffer, u16 len)$/;" f +wpa_set_bss src/rsn_supp/wpa.c /^wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, char *passphrase, u8 *ssid, size_t ssid_len)$/;" f +wpa_set_passphrase src/rsn_supp/wpa.c /^wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len)$/;" f +wpa_set_pmk src/rsn_supp/wpa.c /^void wpa_set_pmk(uint8_t *pmk)$/;" f +wpa_set_profile src/rsn_supp/wpa.c /^void wpa_set_profile(u32 wpa_proto, u8 auth_mode)$/;" f +wpa_set_wnmsleep src/ap/wpa_auth.c /^void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag)$/;" f +wpa_sm src/ap/sta_info.h /^ struct wpa_state_machine *wpa_sm;$/;" m struct:sta_info typeref:struct:sta_info::wpa_state_machine +wpa_sm src/rsn_supp/wpa.h /^struct wpa_sm {$/;" s +wpa_sm_alloc_eapol src/esp_supplicant/esp_wpas_glue.c /^u8 *wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type,$/;" f +wpa_sm_cancel_auth_timeout src/rsn_supp/wpa.c /^static inline void wpa_sm_cancel_auth_timeout(struct wpa_sm *sm)$/;" f file: +wpa_sm_deauthenticate src/esp_supplicant/esp_wpas_glue.c /^void wpa_sm_deauthenticate(struct wpa_sm *sm, u8 reason_code)$/;" f +wpa_sm_disassociate src/esp_supplicant/esp_wpas_glue.c /^void wpa_sm_disassociate(struct wpa_sm *sm, int reason_code)$/;" f +wpa_sm_ether_send src/rsn_supp/wpa.c /^static inline int wpa_sm_ether_send( struct wpa_sm *sm, const u8 *dest, u16 proto,$/;" f file: +wpa_sm_free_eapol src/esp_supplicant/esp_wpas_glue.c /^void wpa_sm_free_eapol(u8 *buffer)$/;" f +wpa_sm_get_beacon_ie src/esp_supplicant/esp_wpas_glue.c /^int wpa_sm_get_beacon_ie(struct wpa_sm *sm)$/;" f +wpa_sm_get_bssid src/rsn_supp/wpa.c /^static inline int wpa_sm_get_bssid(struct wpa_sm *sm, u8 *bssid)$/;" f file: +wpa_sm_get_key src/rsn_supp/wpa.c /^wpa_sm_get_key(uint8_t *ifx, int *alg, u8 *addr, int *key_idx, u8 *key, size_t key_len, int key_entry_valid)$/;" f +wpa_sm_get_state src/rsn_supp/wpa.c /^static inline enum wpa_states wpa_sm_get_state(struct wpa_sm *sm)$/;" f file: +wpa_sm_key_request src/rsn_supp/wpa.c /^void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)$/;" f +wpa_sm_mlme_setprotection src/esp_supplicant/esp_wpas_glue.c /^int wpa_sm_mlme_setprotection(struct wpa_sm *sm, const u8 *addr,$/;" f +wpa_sm_rekey_ptk src/rsn_supp/wpa.c /^ void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx)$/;" f +wpa_sm_rx_eapol src/rsn_supp/wpa.c /^int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len)$/;" f +wpa_sm_set_key src/rsn_supp/wpa.c /^wpa_sm_set_key(struct install_key *key_sm, enum wpa_alg alg,$/;" f +wpa_sm_set_seq src/rsn_supp/wpa.c /^ void wpa_sm_set_seq(struct wpa_sm *sm, struct wpa_eapol_key *key, u8 isptk)$/;" f +wpa_sm_set_state src/rsn_supp/wpa.c /^void wpa_sm_set_state(enum wpa_states state)$/;" f +wpa_sm_step src/ap/wpa_auth.c /^static int wpa_sm_step(struct wpa_state_machine *sm)$/;" f file: +wpa_snprintf_hex src/utils/wpa_debug.c /^int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)$/;" f +wpa_snprintf_hex_uppercase src/utils/wpa_debug.c /^int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, size_t len)$/;" f +wpa_sta_connect src/esp_supplicant/esp_wifi_driver.h /^ void (*wpa_sta_connect)(uint8_t *bssid);$/;" m struct:wpa_funcs +wpa_sta_connect src/esp_supplicant/esp_wpa_main.c /^void wpa_sta_connect(uint8_t *bssid)$/;" f +wpa_sta_deinit src/esp_supplicant/esp_wifi_driver.h /^ bool (*wpa_sta_deinit)(void);$/;" m struct:wpa_funcs +wpa_sta_disconnect src/ap/wpa_auth.c /^static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,$/;" f file: +wpa_sta_in_4way_handshake src/esp_supplicant/esp_wifi_driver.h /^ bool (*wpa_sta_in_4way_handshake)(void);$/;" m struct:wpa_funcs +wpa_sta_in_4way_handshake src/rsn_supp/wpa.c /^bool wpa_sta_in_4way_handshake(void)$/;" f +wpa_sta_init src/esp_supplicant/esp_wifi_driver.h /^ void (*wpa_sta_init)(void);$/;" m struct:wpa_funcs +wpa_sta_rx_eapol src/esp_supplicant/esp_wifi_driver.h /^ int (*wpa_sta_rx_eapol)(u8 *src_addr, u8 *buf, u32 len);$/;" m struct:wpa_funcs +wpa_state src/rsn_supp/wpa.h /^ enum wpa_states wpa_state;$/;" m struct:wpa_sm typeref:enum:wpa_sm::wpa_states +wpa_state_machine src/ap/wpa_auth_i.h /^struct wpa_state_machine {$/;" s +wpa_states src/common/defs.h /^enum wpa_states {$/;" g +wpa_strdup_tchar include/utils/common.h 308;" d +wpa_strict_rekey src/ap/ap_config.h /^ int wpa_strict_rekey;$/;" m struct:hostapd_bss_config +wpa_strict_rekey src/ap/wpa_auth.h /^ int wpa_strict_rekey;$/;" m struct:wpa_auth_config +wpa_stsl_negotiation src/ap/wpa_auth_i.h /^struct wpa_stsl_negotiation {$/;" s +wpa_supplicant_check_group_cipher src/rsn_supp/wpa.c /^int wpa_supplicant_check_group_cipher(int group_cipher,$/;" f +wpa_supplicant_clr_countermeasures src/rsn_supp/wpa.c /^void wpa_supplicant_clr_countermeasures(u16 *pisunicast)$/;" f +wpa_supplicant_decrypt_key_data src/rsn_supp/wpa.c /^ int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,$/;" f +wpa_supplicant_get_pmk src/rsn_supp/wpa.c /^int wpa_supplicant_get_pmk(struct wpa_sm *sm)$/;" f +wpa_supplicant_gtk_in_use src/rsn_supp/wpa.c /^bool wpa_supplicant_gtk_in_use(struct wpa_sm *sm, struct wpa_gtk_data *gd)$/;" f +wpa_supplicant_gtk_tx_bit_workaround src/rsn_supp/wpa.c /^int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm,$/;" f +wpa_supplicant_install_gtk src/rsn_supp/wpa.c /^int wpa_supplicant_install_gtk(struct wpa_sm *sm,$/;" f +wpa_supplicant_install_ptk src/rsn_supp/wpa.c /^int wpa_supplicant_install_ptk(struct wpa_sm *sm)$/;" f +wpa_supplicant_key_neg_complete src/rsn_supp/wpa.c /^void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,$/;" f +wpa_supplicant_pairwise_gtk src/rsn_supp/wpa.c /^int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,$/;" f +wpa_supplicant_parse_ies src/rsn_supp/wpa_ie.c /^int wpa_supplicant_parse_ies(const u8 *buf, size_t len,$/;" f +wpa_supplicant_process_1_of_2 src/rsn_supp/wpa.c /^ void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,$/;" f +wpa_supplicant_process_1_of_2_rsn src/rsn_supp/wpa.c /^ int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,$/;" f +wpa_supplicant_process_1_of_2_wpa src/rsn_supp/wpa.c /^ int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,$/;" f +wpa_supplicant_process_1_of_4 src/rsn_supp/wpa.c /^void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,$/;" f +wpa_supplicant_process_3_of_4 src/rsn_supp/wpa.c /^ void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,$/;" f +wpa_supplicant_send_2_of_2 src/rsn_supp/wpa.c /^ int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,$/;" f +wpa_supplicant_send_2_of_2_txcallback src/rsn_supp/wpa.c /^ int wpa_supplicant_send_2_of_2_txcallback(struct wpa_sm *sm)$/;" f +wpa_supplicant_send_2_of_4 src/rsn_supp/wpa.c /^int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,$/;" f +wpa_supplicant_send_4_of_4 src/rsn_supp/wpa.c /^ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,$/;" f +wpa_supplicant_send_4_of_4_txcallback src/rsn_supp/wpa.c /^ int wpa_supplicant_send_4_of_4_txcallback(struct wpa_sm *sm)$/;" f +wpa_supplicant_stop_countermeasures src/rsn_supp/wpa.c /^void wpa_supplicant_stop_countermeasures(u16 *pisunicast)$/;" f +wpa_supplicant_validate_ie src/rsn_supp/wpa.c /^ int wpa_supplicant_validate_ie(struct wpa_sm *sm,$/;" f +wpa_supplicant_verify_eapol_key_mic src/rsn_supp/wpa.c /^ int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,$/;" f +wpa_swap_16 include/utils/common.h /^static inline unsigned short wpa_swap_16(unsigned short v)$/;" f +wpa_swap_32 include/utils/common.h /^static inline unsigned int wpa_swap_32(unsigned int v)$/;" f +wpa_unicode2ascii_inplace include/utils/common.h 307;" d +wpa_use_aes_cmac src/ap/wpa_auth.c /^static int wpa_use_aes_cmac(struct wpa_state_machine *sm)$/;" f file: +wpa_validate_wpa_ie src/ap/wpa_auth_ie.c /^int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,$/;" f +wpa_verify_key_mic src/ap/wpa_auth.c /^static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len)$/;" f file: +wpa_wnmsleep_gtk_subelem src/ap/wpa_auth.c /^int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)$/;" f +wpa_wnmsleep_igtk_subelem src/ap/wpa_auth.c /^int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)$/;" f +wpa_wnmsleep_rekey_gtk src/ap/wpa_auth.c /^void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)$/;" f +wpa_write_rsn_ie src/ap/wpa_auth_ie.c /^int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,$/;" f +wpa_write_wpa_ie src/ap/wpa_auth_ie.c /^static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)$/;" f file: +wpabuf include/utils/wpabuf.h /^struct wpabuf {$/;" s +wpabuf_alloc src/utils/wpabuf.c /^struct wpabuf * wpabuf_alloc(size_t len)$/;" f +wpabuf_alloc_copy src/utils/wpabuf.c /^struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len)$/;" f +wpabuf_alloc_ext_data src/utils/wpabuf.c /^struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len)$/;" f +wpabuf_concat src/utils/wpabuf.c /^struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b)$/;" f +wpabuf_dup src/utils/wpabuf.c /^struct wpabuf * wpabuf_dup(const struct wpabuf *src)$/;" f +wpabuf_free src/utils/wpabuf.c /^void wpabuf_free(struct wpabuf *buf)$/;" f +wpabuf_get_trace src/utils/wpabuf.c /^static struct wpabuf_trace * wpabuf_get_trace(const struct wpabuf *buf)$/;" f file: +wpabuf_head include/utils/wpabuf.h /^static inline const void * wpabuf_head(const struct wpabuf *buf)$/;" f +wpabuf_head_u8 include/utils/wpabuf.h /^static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf)$/;" f +wpabuf_len include/utils/wpabuf.h /^static inline size_t wpabuf_len(const struct wpabuf *buf)$/;" f +wpabuf_mhead include/utils/wpabuf.h /^static inline void * wpabuf_mhead(struct wpabuf *buf)$/;" f +wpabuf_mhead_u8 include/utils/wpabuf.h /^static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf)$/;" f +wpabuf_overflow src/utils/wpabuf.c /^static void wpabuf_overflow(const struct wpabuf *buf, size_t len)$/;" f file: +wpabuf_printf src/utils/wpabuf.c /^void wpabuf_printf(struct wpabuf *buf, char *fmt, ...)$/;" f +wpabuf_put src/utils/wpabuf.c /^void * wpabuf_put(struct wpabuf *buf, size_t len)$/;" f +wpabuf_put_be16 include/utils/wpabuf.h /^static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data)$/;" f +wpabuf_put_be24 include/utils/wpabuf.h /^static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data)$/;" f +wpabuf_put_be32 include/utils/wpabuf.h /^static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data)$/;" f +wpabuf_put_buf include/utils/wpabuf.h /^static inline void wpabuf_put_buf(struct wpabuf *dst,$/;" f +wpabuf_put_data include/utils/wpabuf.h /^static inline void wpabuf_put_data(struct wpabuf *buf, const void *data,$/;" f +wpabuf_put_le16 include/utils/wpabuf.h /^static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data)$/;" f +wpabuf_put_le32 include/utils/wpabuf.h /^static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data)$/;" f +wpabuf_put_str include/utils/wpabuf.h /^static inline void wpabuf_put_str(struct wpabuf *dst, const char *str)$/;" f +wpabuf_put_u8 include/utils/wpabuf.h /^static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data)$/;" f +wpabuf_resize src/utils/wpabuf.c /^int wpabuf_resize(struct wpabuf **_buf, size_t add_len)$/;" f +wpabuf_set include/utils/wpabuf.h /^static inline void wpabuf_set(struct wpabuf *buf, const void *data, size_t len)$/;" f +wpabuf_size include/utils/wpabuf.h /^static inline size_t wpabuf_size(const struct wpabuf *buf)$/;" f +wpabuf_tailroom include/utils/wpabuf.h /^static inline size_t wpabuf_tailroom(const struct wpabuf *buf)$/;" f +wpabuf_trace src/utils/wpabuf.c /^struct wpabuf_trace {$/;" s file: +wpabuf_zeropad src/utils/wpabuf.c /^struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len)$/;" f +wps src/esp_supplicant/esp_wifi_driver.h /^ uint8_t *wps;$/;" m struct:wps_scan_ie +wps src/wps/wps.h /^ struct wps_context *wps;$/;" m struct:wps_config typeref:struct:wps_config::wps_context +wps src/wps/wps.h /^ struct wps_data *wps;$/;" m struct:wps_sm typeref:struct:wps_sm::wps_data +wps src/wps/wps_i.h /^ struct wps_context *wps;$/;" m struct:wps_data typeref:struct:wps_data::wps_context +wps src/wps/wps_registrar.c /^ struct wps_context *wps;$/;" m struct:wps_registrar typeref:struct:wps_registrar::wps_context file: +wpsTask src/esp_supplicant/esp_wps.c /^void wpsTask(void *pvParameters )$/;" f +wps_add_discard_ap src/esp_supplicant/esp_wps.c /^void wps_add_discard_ap(u8 *bssid)$/;" f +wps_ap_priority_compar src/wps/wps.c /^int wps_ap_priority_compar(const struct wpabuf *wps_a,$/;" f +wps_assoc_state src/wps/wps_defs.h /^enum wps_assoc_state {$/;" g +wps_attr_text src/wps/wps.c /^int wps_attr_text(struct wpabuf *data, char *buf, char *end)$/;" f +wps_attribute src/wps/wps_defs.h /^enum wps_attribute {$/;" g +wps_authorized_macs src/wps/wps_registrar.c /^const u8 * wps_authorized_macs(struct wps_registrar *reg, size_t *count)$/;" f +wps_build_ap_cred src/wps/wps_registrar.c /^static struct wpabuf * wps_build_ap_cred(struct wps_data *wps)$/;" f file: +wps_build_ap_settings src/wps/wps_enrollee.c /^static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *plain)$/;" f file: +wps_build_ap_settings src/wps/wps_registrar.c /^static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *msg)$/;" f file: +wps_build_ap_setup_locked src/wps/wps_registrar.c /^static int wps_build_ap_setup_locked(struct wps_context *wps,$/;" f file: +wps_build_assoc_req_ie src/wps/wps.c /^struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type)$/;" f +wps_build_assoc_resp_ie src/wps/wps.c /^struct wpabuf * wps_build_assoc_resp_ie(void)$/;" f +wps_build_assoc_state src/wps/wps_attr_build.c /^int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg)$/;" f +wps_build_auth_type_flags src/wps/wps_attr_build.c /^int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg)$/;" f +wps_build_authenticator src/wps/wps_attr_build.c /^int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg)$/;" f +wps_build_config_error src/wps/wps_attr_build.c /^int wps_build_config_error(struct wpabuf *msg, u16 err)$/;" f +wps_build_config_methods src/wps/wps_attr_build.c /^int wps_build_config_methods(struct wpabuf *msg, u16 methods)$/;" f +wps_build_config_methods_r src/wps/wps_registrar.c /^static int wps_build_config_methods_r(struct wps_registrar *reg,$/;" f file: +wps_build_conn_type_flags src/wps/wps_attr_build.c /^int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg)$/;" f +wps_build_cred src/wps/wps_registrar.c /^int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)$/;" f +wps_build_cred_auth_type src/wps/wps_enrollee.c /^static int wps_build_cred_auth_type(struct wps_data *wps, struct wpabuf *msg)$/;" f file: +wps_build_cred_auth_type src/wps/wps_registrar.c /^static int wps_build_cred_auth_type(struct wpabuf *msg,$/;" f file: +wps_build_cred_encr_type src/wps/wps_enrollee.c /^static int wps_build_cred_encr_type(struct wps_data *wps, struct wpabuf *msg)$/;" f file: +wps_build_cred_encr_type src/wps/wps_registrar.c /^static int wps_build_cred_encr_type(struct wpabuf *msg,$/;" f file: +wps_build_cred_mac_addr src/wps/wps_enrollee.c /^static int wps_build_cred_mac_addr(struct wps_data *wps, struct wpabuf *msg)$/;" f file: +wps_build_cred_mac_addr src/wps/wps_registrar.c /^static int wps_build_cred_mac_addr(struct wpabuf *msg,$/;" f file: +wps_build_cred_network_idx src/wps/wps_registrar.c /^static int wps_build_cred_network_idx(struct wpabuf *msg,$/;" f file: +wps_build_cred_network_key src/wps/wps_enrollee.c /^static int wps_build_cred_network_key(struct wps_data *wps, struct wpabuf *msg)$/;" f file: +wps_build_cred_network_key src/wps/wps_registrar.c /^static int wps_build_cred_network_key(struct wpabuf *msg,$/;" f file: +wps_build_cred_ssid src/wps/wps_enrollee.c /^static int wps_build_cred_ssid(struct wps_data *wps, struct wpabuf *msg)$/;" f file: +wps_build_cred_ssid src/wps/wps_registrar.c /^static int wps_build_cred_ssid(struct wpabuf *msg,$/;" f file: +wps_build_credential src/wps/wps_registrar.c /^static int wps_build_credential(struct wpabuf *msg,$/;" f file: +wps_build_credential_wrap src/wps/wps_registrar.c /^int wps_build_credential_wrap(struct wpabuf *msg,$/;" f +wps_build_dev_name src/wps/wps_dev_attr.c /^int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg)$/;" f +wps_build_dev_password_id src/wps/wps_attr_build.c /^int wps_build_dev_password_id(struct wpabuf *msg, u16 id)$/;" f +wps_build_device_attrs src/wps/wps_dev_attr.c /^int wps_build_device_attrs(struct wps_device_data *dev, struct wpabuf *msg)$/;" f +wps_build_e_hash src/wps/wps_enrollee.c /^static int wps_build_e_hash(struct wps_data *wps, struct wpabuf *msg)$/;" f file: +wps_build_e_snonce1 src/wps/wps_enrollee.c /^static int wps_build_e_snonce1(struct wps_data *wps, struct wpabuf *msg)$/;" f file: +wps_build_e_snonce2 src/wps/wps_enrollee.c /^static int wps_build_e_snonce2(struct wps_data *wps, struct wpabuf *msg)$/;" f file: +wps_build_encr_settings src/wps/wps_attr_build.c /^int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,$/;" f +wps_build_encr_type_flags src/wps/wps_attr_build.c /^int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg)$/;" f +wps_build_enrollee_nonce src/wps/wps_attr_build.c /^int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg)$/;" f +wps_build_ic_appie_wps_ar src/esp_supplicant/esp_wps.c /^wps_build_ic_appie_wps_ar(void)$/;" f file: +wps_build_ic_appie_wps_pr src/esp_supplicant/esp_wps.c /^wps_build_ic_appie_wps_pr(void)$/;" f file: +wps_build_key_wrap_auth src/wps/wps_attr_build.c /^int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg)$/;" f +wps_build_m1 src/wps/wps_enrollee.c /^static struct wpabuf * wps_build_m1(struct wps_data *wps)$/;" f file: +wps_build_m2 src/wps/wps_registrar.c /^static struct wpabuf * wps_build_m2(struct wps_data *wps)$/;" f file: +wps_build_m2d src/wps/wps_registrar.c /^static struct wpabuf * wps_build_m2d(struct wps_data *wps)$/;" f file: +wps_build_m3 src/wps/wps_enrollee.c /^static struct wpabuf * wps_build_m3(struct wps_data *wps)$/;" f file: +wps_build_m4 src/wps/wps_registrar.c /^static struct wpabuf * wps_build_m4(struct wps_data *wps)$/;" f file: +wps_build_m5 src/wps/wps_enrollee.c /^static struct wpabuf * wps_build_m5(struct wps_data *wps)$/;" f file: +wps_build_m6 src/wps/wps_registrar.c /^static struct wpabuf * wps_build_m6(struct wps_data *wps)$/;" f file: +wps_build_m7 src/wps/wps_enrollee.c /^static struct wpabuf * wps_build_m7(struct wps_data *wps)$/;" f file: +wps_build_m8 src/wps/wps_registrar.c /^static struct wpabuf * wps_build_m8(struct wps_data *wps)$/;" f file: +wps_build_mac_addr src/wps/wps_enrollee.c /^static int wps_build_mac_addr(struct wps_data *wps, struct wpabuf *msg) {$/;" f file: +wps_build_manufacturer src/wps/wps_dev_attr.c /^int wps_build_manufacturer(struct wps_device_data *dev, struct wpabuf *msg)$/;" f +wps_build_model_name src/wps/wps_dev_attr.c /^int wps_build_model_name(struct wps_device_data *dev, struct wpabuf *msg)$/;" f +wps_build_model_number src/wps/wps_dev_attr.c /^int wps_build_model_number(struct wps_device_data *dev, struct wpabuf *msg)$/;" f +wps_build_msg_type src/wps/wps_attr_build.c /^int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type)$/;" f +wps_build_nfc_pw_token src/wps/wps_common.c /^struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,$/;" f +wps_build_oob_dev_pw src/wps/wps_attr_build.c /^int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id,$/;" f +wps_build_os_version src/wps/wps_dev_attr.c /^int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg)$/;" f +wps_build_primary_dev_type src/wps/wps_dev_attr.c /^int wps_build_primary_dev_type(struct wps_device_data *dev, struct wpabuf *msg)$/;" f +wps_build_probe_config_methods src/wps/wps_registrar.c /^static int wps_build_probe_config_methods(struct wps_registrar *reg,$/;" f file: +wps_build_probe_req_ie src/wps/wps.c /^struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev,$/;" f +wps_build_public_key src/wps/wps_attr_build.c /^int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg, wps_key_mode_t mode)$/;" f +wps_build_r_hash src/wps/wps_registrar.c /^static int wps_build_r_hash(struct wps_data *wps, struct wpabuf *msg)$/;" f file: +wps_build_r_snonce1 src/wps/wps_registrar.c /^static int wps_build_r_snonce1(struct wps_data *wps, struct wpabuf *msg)$/;" f file: +wps_build_r_snonce2 src/wps/wps_registrar.c /^static int wps_build_r_snonce2(struct wps_data *wps, struct wpabuf *msg)$/;" f file: +wps_build_registrar_nonce src/wps/wps_attr_build.c /^int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg)$/;" f +wps_build_req_dev_type src/wps/wps_dev_attr.c /^int wps_build_req_dev_type(struct wps_device_data *dev, struct wpabuf *msg,$/;" f +wps_build_req_type src/wps/wps_attr_build.c /^int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type)$/;" f +wps_build_resp_type src/wps/wps_attr_build.c /^int wps_build_resp_type(struct wpabuf *msg, enum wps_response_type type)$/;" f +wps_build_rf_bands src/wps/wps_dev_attr.c /^int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg)$/;" f +wps_build_secondary_dev_type src/wps/wps_dev_attr.c /^int wps_build_secondary_dev_type(struct wps_device_data *dev,$/;" f +wps_build_sel_pbc_reg_uuid_e src/wps/wps_registrar.c /^static int wps_build_sel_pbc_reg_uuid_e(struct wps_registrar *reg,$/;" f file: +wps_build_sel_reg_config_methods src/wps/wps_registrar.c /^static int wps_build_sel_reg_config_methods(struct wps_registrar *reg,$/;" f file: +wps_build_sel_reg_dev_password_id src/wps/wps_registrar.c /^static int wps_build_sel_reg_dev_password_id(struct wps_registrar *reg,$/;" f file: +wps_build_selected_registrar src/wps/wps_registrar.c /^static int wps_build_selected_registrar(struct wps_registrar *reg,$/;" f file: +wps_build_serial_number src/wps/wps_dev_attr.c /^static int wps_build_serial_number(struct wps_device_data *dev,$/;" f file: +wps_build_uuid_e src/wps/wps_attr_build.c /^int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid)$/;" f +wps_build_uuid_r src/wps/wps_registrar.c /^static int wps_build_uuid_r(struct wps_data *wps, struct wpabuf *msg)$/;" f file: +wps_build_vendor_ext src/wps/wps_dev_attr.c /^int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg)$/;" f +wps_build_vendor_ext_m1 src/wps/wps_dev_attr.c /^int wps_build_vendor_ext_m1(struct wps_device_data *dev, struct wpabuf *msg)$/;" f +wps_build_version src/wps/wps_attr_build.c /^int wps_build_version(struct wpabuf *msg)$/;" f +wps_build_wfa_ext src/wps/wps_attr_build.c /^int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,$/;" f +wps_build_wps_state src/wps/wps_enrollee.c /^static int wps_build_wps_state(struct wps_data *wps, struct wpabuf *msg)$/;" f file: +wps_build_wps_state src/wps/wps_registrar.c /^static int wps_build_wps_state(struct wps_context *wps, struct wpabuf *msg)$/;" f file: +wps_build_wsc_ack src/wps/wps_common.c /^struct wpabuf * wps_build_wsc_ack(struct wps_data *wps)$/;" f +wps_build_wsc_done src/wps/wps_enrollee.c /^static struct wpabuf * wps_build_wsc_done(struct wps_data *wps)$/;" f file: +wps_build_wsc_nack src/wps/wps_common.c /^struct wpabuf * wps_build_wsc_nack(struct wps_data *wps)$/;" f +wps_calc_key_mode src/wps/wps_i.h /^typedef enum wps_calc_key_mode {$/;" g +wps_cb_new_psk src/wps/wps_registrar.c /^static int wps_cb_new_psk(struct wps_registrar *reg, const u8 *mac_addr,$/;" f file: +wps_cb_pin_needed src/wps/wps_registrar.c /^static void wps_cb_pin_needed(struct wps_registrar *reg, const u8 *uuid_e,$/;" f file: +wps_cb_reg_success src/wps/wps_registrar.c /^static void wps_cb_reg_success(struct wps_registrar *reg, const u8 *mac_addr,$/;" f file: +wps_cb_set_ie src/wps/wps_registrar.c /^static int wps_cb_set_ie(struct wps_registrar *reg, struct wpabuf *beacon_ie,$/;" f file: +wps_cb_set_sel_reg src/wps/wps_registrar.c /^static void wps_cb_set_sel_reg(struct wps_registrar *reg)$/;" f file: +wps_cb_status src/wps/wps.h /^enum wps_cb_status {$/;" g +wps_cfg src/wps/wps.h /^ struct wps_config *wps_cfg;$/;" m struct:wps_sm typeref:struct:wps_sm::wps_config +wps_check_wifi_mode src/esp_supplicant/esp_wps.c /^int wps_check_wifi_mode(void)$/;" f +wps_config src/wps/wps.h /^struct wps_config {$/;" s +wps_config_error src/wps/wps_defs.h /^enum wps_config_error {$/;" g +wps_config_methods_str2bin src/wps/wps_common.c /^u16 wps_config_methods_str2bin(const char *str)$/;" f +wps_context src/wps/wps.h /^struct wps_context {$/;" s +wps_cred_processing src/ap/ap_config.h /^ int wps_cred_processing;$/;" m struct:hostapd_bss_config +wps_cred_update src/wps/wps_registrar.c /^static void wps_cred_update(struct wps_credential *dst,$/;" f file: +wps_credential src/wps/wps.h /^struct wps_credential {$/;" s +wps_ctx src/wps/wps.h /^ struct wps_context *wps_ctx;$/;" m struct:wps_sm typeref:struct:wps_sm::wps_context +wps_data src/wps/wps_i.h /^struct wps_data {$/;" s +wps_decrypt_encr_settings src/wps/wps_common.c /^struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,$/;" f +wps_deinit src/esp_supplicant/esp_wps.c /^void wps_deinit(void)$/;" f +wps_delete_timer src/esp_supplicant/esp_wps.c /^int wps_delete_timer(void)$/;" f +wps_derive_keys src/wps/wps_common.c /^int wps_derive_keys(struct wps_data *wps)$/;" f +wps_derive_psk src/wps/wps_common.c /^void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,$/;" f +wps_dev_categ src/wps/wps_defs.h /^enum wps_dev_categ {$/;" g +wps_dev_deinit src/esp_supplicant/esp_wps.c /^int wps_dev_deinit(struct wps_device_data *dev)$/;" f +wps_dev_init src/esp_supplicant/esp_wps.c /^int wps_dev_init(void)$/;" f +wps_dev_password_id src/wps/wps_defs.h /^enum wps_dev_password_id {$/;" g +wps_dev_subcateg src/wps/wps_defs.h /^enum wps_dev_subcateg {$/;" g +wps_dev_type_bin2str src/wps/wps_common.c /^char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,$/;" f +wps_dev_type_str2bin src/wps/wps_common.c /^int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN])$/;" f +wps_device_clone_data src/wps/wps_registrar.c /^static void wps_device_clone_data(struct wps_device_data *dst,$/;" f file: +wps_device_data src/wps/wps.h /^struct wps_device_data {$/;" s +wps_device_data_dup src/wps/wps_dev_attr.c /^void wps_device_data_dup(struct wps_device_data *dst,$/;" f +wps_device_data_free src/wps/wps_dev_attr.c /^void wps_device_data_free(struct wps_device_data *dev)$/;" f +wps_device_get src/wps/wps_registrar.c /^static struct wps_registrar_device * wps_device_get(struct wps_registrar *reg,$/;" f file: +wps_device_store src/wps/wps_registrar.c /^int wps_device_store(struct wps_registrar *reg,$/;" f +wps_eapol_start_timer src/wps/wps.h /^ ETSTimer wps_eapol_start_timer;$/;" m struct:wps_sm +wps_enrollee_get_msg src/wps/wps_enrollee.c /^struct wpabuf * wps_enrollee_get_msg(struct wps_data *wps,$/;" f +wps_enrollee_process_msg src/wps/wps_enrollee.c /^enum wps_process_res wps_enrollee_process_msg(struct wps_data *wps,$/;" f +wps_enrollee_process_msg_frag src/esp_supplicant/esp_wps.c /^int wps_enrollee_process_msg_frag(struct wpabuf **buf, int tot_len, u8 *frag_data, int frag_len, u8 flag)$/;" f +wps_error_indication src/wps/wps_defs.h /^enum wps_error_indication {$/;" g +wps_event src/wps/wps.h /^enum wps_event {$/;" g +wps_event_data src/wps/wps.h /^union wps_event_data {$/;" u +wps_event_er_ap src/wps/wps.h /^ struct wps_event_er_ap {$/;" s union:wps_event_data +wps_event_er_ap_settings src/wps/wps.h /^ struct wps_event_er_ap_settings {$/;" s union:wps_event_data +wps_event_er_enrollee src/wps/wps.h /^ struct wps_event_er_enrollee {$/;" s union:wps_event_data +wps_event_er_set_selected_registrar src/wps/wps.h /^ struct wps_event_er_set_selected_registrar {$/;" s union:wps_event_data +wps_event_fail src/wps/wps.h /^ struct wps_event_fail {$/;" s union:wps_event_data +wps_event_m2d src/wps/wps.h /^ struct wps_event_m2d {$/;" s union:wps_event_data +wps_event_pwd_auth_fail src/wps/wps.h /^ struct wps_event_pwd_auth_fail {$/;" s union:wps_event_data +wps_factory_information_t include/esp_supplicant/esp_wps.h /^} wps_factory_information_t;$/;" t typeref:struct:__anon89 +wps_fail_event src/wps/wps_common.c /^void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,$/;" f +wps_finish src/esp_supplicant/esp_wps.c /^int wps_finish(void)$/;" f +wps_free_devices src/wps/wps_registrar.c /^static void wps_free_devices(struct wps_registrar_device *dev)$/;" f file: +wps_free_nfc_pw_tokens src/wps/wps_registrar.c /^static void wps_free_nfc_pw_tokens(struct dl_list *tokens, u16 pw_id)$/;" f file: +wps_free_nfc_pw_tokens src/wps/wps_registrar.c 70;" d file: +wps_free_pbc_sessions src/wps/wps_registrar.c /^static void wps_free_pbc_sessions(struct wps_pbc_session *pbc)$/;" f file: +wps_free_pending_msgs src/wps/wps.c /^void wps_free_pending_msgs(struct upnp_pending_message *msgs)$/;" f +wps_free_pin src/wps/wps_registrar.c /^static void wps_free_pin(struct wps_uuid_pin *pin)$/;" f file: +wps_free_pins src/wps/wps_registrar.c /^static void wps_free_pins(struct dl_list *pins)$/;" f file: +wps_funcs src/esp_supplicant/esp_wifi_driver.h /^struct wps_funcs {$/;" s +wps_generate_pin src/wps/wps_common.c /^unsigned int wps_generate_pin(void)$/;" f +wps_get_dev_password src/wps/wps_registrar.c /^static int wps_get_dev_password(struct wps_data *wps)$/;" f file: +wps_get_msg src/wps/wps.c /^struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code)$/;" f +wps_get_nfc_pw_token src/wps/wps_registrar.c /^static struct wps_nfc_pw_token * wps_get_nfc_pw_token(struct dl_list *tokens,$/;" f file: +wps_get_oob_cred src/wps/wps_common.c /^struct wpabuf * wps_get_oob_cred(struct wps_context *wps)$/;" f +wps_get_status src/esp_supplicant/esp_wps.c /^int wps_get_status(void)$/;" f +wps_get_type src/esp_supplicant/esp_wps.c /^int wps_get_type(void)$/;" f +wps_get_uuid_e src/wps/wps.c /^const u8 * wps_get_uuid_e(const struct wpabuf *msg)$/;" f +wps_ie_encapsulate src/wps/wps_attr_build.c /^struct wpabuf * wps_ie_encapsulate(struct wpabuf *data)$/;" f +wps_init src/esp_supplicant/esp_wps.c /^struct wps_data *wps_init(void)$/;" f +wps_ioctl_param_t src/esp_supplicant/esp_wps.c /^} wps_ioctl_param_t;$/;" t typeref:struct:__anon33 file: +wps_is_20 src/wps/wps.c /^int wps_is_20(const struct wpabuf *msg)$/;" f +wps_is_addr_authorized src/wps/wps.c /^int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,$/;" f +wps_is_selected_pbc_registrar src/wps/wps.c /^int wps_is_selected_pbc_registrar(const struct wpabuf *msg, u8 *bssid)$/;" f +wps_is_selected_pin_registrar src/wps/wps.c /^int wps_is_selected_pin_registrar(const struct wpabuf *msg, u8 *bssid)$/;" f +wps_kdf src/wps/wps_common.c /^void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,$/;" f +wps_key_mode_t src/wps/wps_i.h /^} wps_key_mode_t;$/;" t typeref:enum:wps_calc_key_mode +wps_key_save src/esp_supplicant/esp_wps.c /^wps_key_save(char *key, u8 key_len)$/;" f +wps_msg_flag src/wps/wps_defs.h /^enum wps_msg_flag {$/;" g +wps_msg_timeout_timer src/wps/wps.h /^ ETSTimer wps_msg_timeout_timer;$/;" m struct:wps_sm +wps_msg_type src/wps/wps_defs.h /^enum wps_msg_type {$/;" g +wps_nfc_dev_pw src/ap/ap_config.h /^ struct wpabuf *wps_nfc_dev_pw;$/;" m struct:hostapd_bss_config typeref:struct:hostapd_bss_config::wpabuf +wps_nfc_dev_pw_id src/ap/ap_config.h /^ int wps_nfc_dev_pw_id;$/;" m struct:hostapd_bss_config +wps_nfc_dh_privkey src/ap/ap_config.h /^ struct wpabuf *wps_nfc_dh_privkey;$/;" m struct:hostapd_bss_config typeref:struct:hostapd_bss_config::wpabuf +wps_nfc_dh_pubkey src/ap/ap_config.h /^ struct wpabuf *wps_nfc_dh_pubkey;$/;" m struct:hostapd_bss_config typeref:struct:hostapd_bss_config::wpabuf +wps_nfc_pw_token src/wps/wps_registrar.c /^struct wps_nfc_pw_token {$/;" s file: +wps_nfc_token_gen src/wps/wps_common.c /^struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,$/;" f +wps_oob_use_cred src/wps/wps_common.c /^int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr)$/;" f +wps_parse_attr src/wps/wps_attr_parse.h /^struct wps_parse_attr {$/;" s +wps_parse_msg src/wps/wps_attr_parse.c /^int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)$/;" f +wps_parse_scan_result src/esp_supplicant/esp_wifi_driver.h /^ bool (*wps_parse_scan_result)(struct wps_scan_ie *scan);$/;" m struct:wps_funcs +wps_parse_scan_result src/esp_supplicant/esp_wps.c /^wps_parse_scan_result(struct wps_scan_ie *scan)$/;" f file: +wps_parse_vendor_ext src/wps/wps_attr_parse.c /^static int wps_parse_vendor_ext(struct wps_parse_attr *attr, const u8 *pos,$/;" f file: +wps_parse_vendor_ext_wfa src/wps/wps_attr_parse.c /^static int wps_parse_vendor_ext_wfa(struct wps_parse_attr *attr, const u8 *pos,$/;" f file: +wps_pbc_overlap_event src/wps/wps_common.c /^void wps_pbc_overlap_event(struct wps_context *wps)$/;" f +wps_pbc_session src/wps/wps_registrar.c /^struct wps_pbc_session {$/;" s file: +wps_pbc_timeout_event src/wps/wps_common.c /^void wps_pbc_timeout_event(struct wps_context *wps)$/;" f +wps_pin_checksum src/wps/wps_common.c /^unsigned int wps_pin_checksum(unsigned int pin)$/;" f +wps_pin_requests src/ap/ap_config.h /^ char *wps_pin_requests;$/;" m struct:hostapd_bss_config +wps_pin_revealed src/wps/wps_i.h /^ int wps_pin_revealed;$/;" m struct:wps_data +wps_pin_str_valid src/wps/wps_common.c /^int wps_pin_str_valid(const char *pin)$/;" f +wps_pin_valid src/wps/wps_common.c /^unsigned int wps_pin_valid(unsigned int pin)$/;" f +wps_post src/esp_supplicant/esp_wps.c /^ETS_STATUS wps_post(ETSSignal sig, ETSParam par)$/;" f +wps_post_block src/esp_supplicant/esp_wps.c /^int wps_post_block(ETSSignal sig, void *arg)$/;" f +wps_process_ap_settings src/wps/wps_attr_process.c /^int wps_process_ap_settings(struct wps_parse_attr *attr,$/;" f +wps_process_ap_settings_e src/wps/wps_enrollee.c /^static int wps_process_ap_settings_e(struct wps_data *wps,$/;" f file: +wps_process_ap_settings_r src/wps/wps_registrar.c /^static int wps_process_ap_settings_r(struct wps_data *wps,$/;" f file: +wps_process_assoc_state src/wps/wps_registrar.c /^static int wps_process_assoc_state(struct wps_data *wps, const u8 *assoc)$/;" f file: +wps_process_auth_type_flags src/wps/wps_registrar.c /^static int wps_process_auth_type_flags(struct wps_data *wps, const u8 *auth)$/;" f file: +wps_process_authenticator src/wps/wps_attr_process.c /^int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,$/;" f +wps_process_config_error src/wps/wps_registrar.c /^static int wps_process_config_error(struct wps_data *wps, const u8 *err)$/;" f file: +wps_process_config_methods src/wps/wps_registrar.c /^static int wps_process_config_methods(struct wps_data *wps, const u8 *methods)$/;" f file: +wps_process_conn_type_flags src/wps/wps_registrar.c /^static int wps_process_conn_type_flags(struct wps_data *wps, const u8 *conn)$/;" f file: +wps_process_cred src/wps/wps_attr_process.c /^int wps_process_cred(struct wps_parse_attr *attr,$/;" f +wps_process_cred_802_1x_enabled src/wps/wps_attr_process.c /^static int wps_process_cred_802_1x_enabled(struct wps_credential *cred,$/;" f file: +wps_process_cred_ap_channel src/wps/wps_attr_process.c /^static int wps_process_cred_ap_channel(struct wps_credential *cred,$/;" f file: +wps_process_cred_auth_type src/wps/wps_attr_process.c /^static int wps_process_cred_auth_type(struct wps_credential *cred,$/;" f file: +wps_process_cred_e src/wps/wps_enrollee.c /^static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,$/;" f file: +wps_process_cred_eap_identity src/wps/wps_attr_process.c /^static int wps_process_cred_eap_identity(struct wps_credential *cred,$/;" f file: +wps_process_cred_eap_type src/wps/wps_attr_process.c /^static int wps_process_cred_eap_type(struct wps_credential *cred,$/;" f file: +wps_process_cred_encr_type src/wps/wps_attr_process.c /^static int wps_process_cred_encr_type(struct wps_credential *cred,$/;" f file: +wps_process_cred_key_prov_auto src/wps/wps_attr_process.c /^static int wps_process_cred_key_prov_auto(struct wps_credential *cred,$/;" f file: +wps_process_cred_mac_addr src/wps/wps_attr_process.c /^static int wps_process_cred_mac_addr(struct wps_credential *cred,$/;" f file: +wps_process_cred_network_idx src/wps/wps_attr_process.c /^static int wps_process_cred_network_idx(struct wps_credential *cred,$/;" f file: +wps_process_cred_network_key src/wps/wps_attr_process.c /^static int wps_process_cred_network_key(struct wps_credential *cred,$/;" f file: +wps_process_cred_network_key_idx src/wps/wps_attr_process.c /^static int wps_process_cred_network_key_idx(struct wps_credential *cred,$/;" f file: +wps_process_cred_ssid src/wps/wps_attr_process.c /^static int wps_process_cred_ssid(struct wps_credential *cred, const u8 *ssid,$/;" f file: +wps_process_creds src/wps/wps_enrollee.c /^static int wps_process_creds(struct wps_data *wps, const u8 *cred[],$/;" f file: +wps_process_dev_name src/wps/wps_dev_attr.c /^static int wps_process_dev_name(struct wps_device_data *dev, const u8 *str,$/;" f file: +wps_process_dev_password_id src/wps/wps_registrar.c /^static int wps_process_dev_password_id(struct wps_data *wps, const u8 *pw_id)$/;" f file: +wps_process_device_attrs src/wps/wps_dev_attr.c /^int wps_process_device_attrs(struct wps_device_data *dev,$/;" f +wps_process_e_hash1 src/wps/wps_registrar.c /^static int wps_process_e_hash1(struct wps_data *wps, const u8 *e_hash1)$/;" f file: +wps_process_e_hash2 src/wps/wps_registrar.c /^static int wps_process_e_hash2(struct wps_data *wps, const u8 *e_hash2)$/;" f file: +wps_process_e_snonce1 src/wps/wps_registrar.c /^static int wps_process_e_snonce1(struct wps_data *wps, const u8 *e_snonce1)$/;" f file: +wps_process_e_snonce2 src/wps/wps_registrar.c /^static int wps_process_e_snonce2(struct wps_data *wps, const u8 *e_snonce2)$/;" f file: +wps_process_encr_type_flags src/wps/wps_registrar.c /^static int wps_process_encr_type_flags(struct wps_data *wps, const u8 *encr)$/;" f file: +wps_process_enrollee_nonce src/wps/wps_enrollee.c /^static int wps_process_enrollee_nonce(struct wps_data *wps, const u8 *e_nonce)$/;" f file: +wps_process_enrollee_nonce src/wps/wps_registrar.c /^static int wps_process_enrollee_nonce(struct wps_data *wps, const u8 *e_nonce)$/;" f file: +wps_process_key_wrap_auth src/wps/wps_attr_process.c /^int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg,$/;" f +wps_process_m1 src/wps/wps_registrar.c /^static enum wps_process_res wps_process_m1(struct wps_data *wps,$/;" f file: +wps_process_m2 src/wps/wps_enrollee.c /^static enum wps_process_res wps_process_m2(struct wps_data *wps,$/;" f file: +wps_process_m2d src/wps/wps_enrollee.c /^static enum wps_process_res wps_process_m2d(struct wps_data *wps,$/;" f file: +wps_process_m3 src/wps/wps_registrar.c /^static enum wps_process_res wps_process_m3(struct wps_data *wps,$/;" f file: +wps_process_m4 src/wps/wps_enrollee.c /^static enum wps_process_res wps_process_m4(struct wps_data *wps,$/;" f file: +wps_process_m5 src/wps/wps_registrar.c /^static enum wps_process_res wps_process_m5(struct wps_data *wps,$/;" f file: +wps_process_m6 src/wps/wps_enrollee.c /^static enum wps_process_res wps_process_m6(struct wps_data *wps,$/;" f file: +wps_process_m7 src/wps/wps_registrar.c /^static enum wps_process_res wps_process_m7(struct wps_data *wps,$/;" f file: +wps_process_m8 src/wps/wps_enrollee.c /^static enum wps_process_res wps_process_m8(struct wps_data *wps,$/;" f file: +wps_process_mac_addr src/wps/wps_registrar.c /^static int wps_process_mac_addr(struct wps_data *wps, const u8 *mac_addr)$/;" f file: +wps_process_manufacturer src/wps/wps_dev_attr.c /^static int wps_process_manufacturer(struct wps_device_data *dev, const u8 *str,$/;" f file: +wps_process_model_name src/wps/wps_dev_attr.c /^static int wps_process_model_name(struct wps_device_data *dev, const u8 *str,$/;" f file: +wps_process_model_number src/wps/wps_dev_attr.c /^static int wps_process_model_number(struct wps_device_data *dev, const u8 *str,$/;" f file: +wps_process_msg src/wps/wps.c /^enum wps_process_res wps_process_msg(struct wps_data *wps,$/;" f +wps_process_os_version src/wps/wps_dev_attr.c /^int wps_process_os_version(struct wps_device_data *dev, const u8 *ver)$/;" f +wps_process_primary_dev_type src/wps/wps_dev_attr.c /^static int wps_process_primary_dev_type(struct wps_device_data *dev,$/;" f file: +wps_process_pubkey src/wps/wps_enrollee.c /^static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,$/;" f file: +wps_process_pubkey src/wps/wps_registrar.c /^static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,$/;" f file: +wps_process_r_hash1 src/wps/wps_enrollee.c /^static int wps_process_r_hash1(struct wps_data *wps, const u8 *r_hash1)$/;" f file: +wps_process_r_hash2 src/wps/wps_enrollee.c /^static int wps_process_r_hash2(struct wps_data *wps, const u8 *r_hash2)$/;" f file: +wps_process_r_snonce1 src/wps/wps_enrollee.c /^static int wps_process_r_snonce1(struct wps_data *wps, const u8 *r_snonce1)$/;" f file: +wps_process_r_snonce2 src/wps/wps_enrollee.c /^static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2)$/;" f file: +wps_process_registrar_nonce src/wps/wps_enrollee.c /^static int wps_process_registrar_nonce(struct wps_data *wps, const u8 *r_nonce)$/;" f file: +wps_process_registrar_nonce src/wps/wps_registrar.c /^static int wps_process_registrar_nonce(struct wps_data *wps, const u8 *r_nonce)$/;" f file: +wps_process_res src/wps/wps.h /^enum wps_process_res {$/;" g +wps_process_rf_bands src/wps/wps_dev_attr.c /^int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands)$/;" f +wps_process_serial_number src/wps/wps_dev_attr.c /^static int wps_process_serial_number(struct wps_device_data *dev,$/;" f file: +wps_process_uuid_e src/wps/wps_registrar.c /^static int wps_process_uuid_e(struct wps_data *wps, const u8 *uuid_e)$/;" f file: +wps_process_uuid_r src/wps/wps_enrollee.c /^static int wps_process_uuid_r(struct wps_data *wps, const u8 *uuid_r)$/;" f file: +wps_process_wps_mX_req src/esp_supplicant/esp_wps.c /^int wps_process_wps_mX_req(u8 *ubuf, int len, enum wps_process_res *res)$/;" f +wps_process_wps_state src/wps/wps_registrar.c /^static int wps_process_wps_state(struct wps_data *wps, const u8 *state)$/;" f file: +wps_process_wsc_ack src/wps/wps_enrollee.c /^static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,$/;" f file: +wps_process_wsc_ack src/wps/wps_registrar.c /^static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,$/;" f file: +wps_process_wsc_done src/wps/wps_registrar.c /^static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,$/;" f file: +wps_process_wsc_msg src/wps/wps_enrollee.c /^static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,$/;" f file: +wps_process_wsc_msg src/wps/wps_registrar.c /^static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,$/;" f file: +wps_process_wsc_nack src/wps/wps_enrollee.c /^static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,$/;" f file: +wps_process_wsc_nack src/wps/wps_registrar.c /^static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,$/;" f file: +wps_process_wsc_start src/wps/wps_enrollee.c /^static enum wps_process_res wps_process_wsc_start(struct wps_data *wps,$/;" f file: +wps_pwd_auth_fail_event src/wps/wps_common.c /^void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part)$/;" f +wps_registrar src/wps/wps_registrar.c /^struct wps_registrar {$/;" s file: +wps_registrar_add_authorized_mac src/wps/wps_registrar.c /^static void wps_registrar_add_authorized_mac(struct wps_registrar *reg,$/;" f file: +wps_registrar_add_nfc_password_token src/wps/wps_registrar.c /^int wps_registrar_add_nfc_password_token(struct wps_registrar *reg,$/;" f +wps_registrar_add_nfc_pw_token src/wps/wps_registrar.c /^int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,$/;" f +wps_registrar_add_pbc_session src/wps/wps_registrar.c /^static void wps_registrar_add_pbc_session(struct wps_registrar *reg,$/;" f file: +wps_registrar_add_pin src/wps/wps_registrar.c /^int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,$/;" f +wps_registrar_button_pushed src/wps/wps_registrar.c /^int wps_registrar_button_pushed(struct wps_registrar *reg,$/;" f +wps_registrar_complete src/wps/wps_registrar.c /^void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e,$/;" f +wps_registrar_config src/wps/wps.h /^struct wps_registrar_config {$/;" s +wps_registrar_config_ap src/wps/wps_registrar.c /^int wps_registrar_config_ap(struct wps_registrar *reg,$/;" f +wps_registrar_deinit src/wps/wps_registrar.c /^void wps_registrar_deinit(struct wps_registrar *reg)$/;" f +wps_registrar_device src/wps/wps_registrar.c /^struct wps_registrar_device {$/;" s file: +wps_registrar_expire_pins src/wps/wps_registrar.c /^static void wps_registrar_expire_pins(struct wps_registrar *reg)$/;" f file: +wps_registrar_free_pending_m2 src/wps/wps_registrar.c /^static void wps_registrar_free_pending_m2(struct wps_context *wps)$/;" f file: +wps_registrar_get_info src/wps/wps_registrar.c /^int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr,$/;" f +wps_registrar_get_msg src/wps/wps_registrar.c /^struct wpabuf * wps_registrar_get_msg(struct wps_data *wps,$/;" f +wps_registrar_get_pin src/wps/wps_registrar.c /^static const u8 * wps_registrar_get_pin(struct wps_registrar *reg,$/;" f file: +wps_registrar_init src/wps/wps_registrar.c /^struct wps_registrar * wps_registrar_init(struct wps_context *wps,$/;" f +wps_registrar_invalidate_pin src/wps/wps_registrar.c /^int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid)$/;" f +wps_registrar_invalidate_unused src/wps/wps_registrar.c /^static void wps_registrar_invalidate_unused(struct wps_registrar *reg)$/;" f file: +wps_registrar_invalidate_wildcard_pin src/wps/wps_registrar.c /^static int wps_registrar_invalidate_wildcard_pin(struct wps_registrar *reg,$/;" f file: +wps_registrar_p2p_dev_addr_match src/wps/wps_registrar.c /^static int wps_registrar_p2p_dev_addr_match(struct wps_data *wps)$/;" f file: +wps_registrar_pbc_completed src/wps/wps_registrar.c /^static void wps_registrar_pbc_completed(struct wps_registrar *reg)$/;" f file: +wps_registrar_pbc_overlap src/wps/wps_registrar.c /^int wps_registrar_pbc_overlap(struct wps_registrar *reg,$/;" f +wps_registrar_pbc_timeout src/wps/wps_registrar.c /^static void wps_registrar_pbc_timeout(void *eloop_ctx)$/;" f file: +wps_registrar_pin_completed src/wps/wps_registrar.c /^static void wps_registrar_pin_completed(struct wps_registrar *reg)$/;" f file: +wps_registrar_probe_req_rx src/wps/wps_registrar.c /^void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,$/;" f +wps_registrar_process_msg src/wps/wps_registrar.c /^enum wps_process_res wps_registrar_process_msg(struct wps_data *wps,$/;" f +wps_registrar_remove_authorized_mac src/wps/wps_registrar.c /^static void wps_registrar_remove_authorized_mac(struct wps_registrar *reg,$/;" f file: +wps_registrar_remove_nfc_pw_token src/wps/wps_registrar.c /^void wps_registrar_remove_nfc_pw_token(struct wps_registrar *reg,$/;" f +wps_registrar_remove_pbc_session src/wps/wps_registrar.c /^static void wps_registrar_remove_pbc_session(struct wps_registrar *reg,$/;" f file: +wps_registrar_remove_pin src/wps/wps_registrar.c /^static void wps_registrar_remove_pin(struct wps_registrar *reg,$/;" f file: +wps_registrar_sel_reg_add src/wps/wps_registrar.c /^static void wps_registrar_sel_reg_add(struct wps_registrar *reg,$/;" f file: +wps_registrar_sel_reg_union src/wps/wps_registrar.c /^static void wps_registrar_sel_reg_union(struct wps_registrar *reg)$/;" f file: +wps_registrar_selected_registrar_changed src/wps/wps_registrar.c /^void wps_registrar_selected_registrar_changed(struct wps_registrar *reg)$/;" f +wps_registrar_skip_overlap src/wps/wps_registrar.c /^static int wps_registrar_skip_overlap(struct wps_data *wps)$/;" f file: +wps_registrar_stop_pbc src/wps/wps_registrar.c /^static void wps_registrar_stop_pbc(struct wps_registrar *reg)$/;" f file: +wps_registrar_unlock_pin src/wps/wps_registrar.c /^int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid)$/;" f +wps_registrar_update_ie src/wps/wps_registrar.c /^int wps_registrar_update_ie(struct wps_registrar *reg)$/;" f +wps_registrar_wps_cancel src/wps/wps_registrar.c /^int wps_registrar_wps_cancel(struct wps_registrar *reg)$/;" f +wps_remove_nfc_pw_token src/wps/wps_registrar.c /^static void wps_remove_nfc_pw_token(struct wps_nfc_pw_token *token)$/;" f file: +wps_remove_pin src/wps/wps_registrar.c /^static void wps_remove_pin(struct wps_uuid_pin *pin)$/;" f file: +wps_request_type src/wps/wps_defs.h /^enum wps_request_type {$/;" g +wps_response_type src/wps/wps_defs.h /^enum wps_response_type {$/;" g +wps_rx_param src/esp_supplicant/esp_wps.c /^struct wps_rx_param {$/;" s file: +wps_scan_ie src/esp_supplicant/esp_wifi_driver.h /^struct wps_scan_ie {$/;" s +wps_scan_timer src/wps/wps.h /^ ETSTimer wps_scan_timer;$/;" m struct:wps_sm +wps_send_eap_identity_rsp src/esp_supplicant/esp_wps.c /^int wps_send_eap_identity_rsp(u8 id)$/;" f +wps_send_frag_ack src/esp_supplicant/esp_wps.c /^int wps_send_frag_ack(u8 id)$/;" f +wps_send_wps_mX_rsp src/esp_supplicant/esp_wps.c /^int wps_send_wps_mX_rsp(u8 id)$/;" f +wps_sendto_wrapper src/esp_supplicant/esp_wps.c /^static void wps_sendto_wrapper(void *buffer, uint16_t len)$/;" f file: +wps_set_attr src/wps/wps_attr_parse.c /^static int wps_set_attr(struct wps_parse_attr *attr, u16 type,$/;" f file: +wps_set_default_factory src/esp_supplicant/esp_wps.c /^int wps_set_default_factory(void)$/;" f +wps_set_factory_info src/esp_supplicant/esp_wps.c /^int wps_set_factory_info(const esp_wps_config_t *config)$/;" f +wps_set_ie src/wps/wps_registrar.c /^static int wps_set_ie(struct wps_registrar *reg)$/;" f file: +wps_set_pushbutton src/wps/wps_registrar.c /^static void wps_set_pushbutton(u16 *methods, u16 conf_methods)$/;" f file: +wps_set_status src/esp_supplicant/esp_wps.c /^int wps_set_status(uint32_t status)$/;" f +wps_set_type src/esp_supplicant/esp_wps.c /^int wps_set_type(uint32_t type)$/;" f +wps_set_vendor_ext_wfa_subelem src/wps/wps_attr_parse.c /^static int wps_set_vendor_ext_wfa_subelem(struct wps_parse_attr *attr,$/;" f file: +wps_sig_cnt src/wps/wps.h /^ u8 wps_sig_cnt[SIG_WPS_NUM];$/;" m struct:wps_sm +wps_sig_type src/wps/wps.h /^enum wps_sig_type {$/;" g +wps_sm src/wps/wps.h /^struct wps_sm {$/;" s +wps_sm_alloc_eapol src/esp_supplicant/esp_wps.c /^u8 *wps_sm_alloc_eapol(struct wps_sm *sm, u8 type,$/;" f +wps_sm_ether_send src/esp_supplicant/esp_wps.c /^static inline int wps_sm_ether_send(struct wps_sm *sm, const u8 *dest, u16 proto,$/;" f file: +wps_sm_free_eapol src/esp_supplicant/esp_wps.c /^void wps_sm_free_eapol(u8 *buffer)$/;" f +wps_sm_get src/esp_supplicant/esp_wps.c /^wps_sm_get(void)$/;" f +wps_sm_rx_eapol src/esp_supplicant/esp_wifi_driver.h /^ int (*wps_sm_rx_eapol)(u8 *src_addr, u8 *buf, u32 len);$/;" m struct:wps_funcs +wps_sm_rx_eapol src/esp_supplicant/esp_wps.c /^int wps_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len)$/;" f +wps_sm_rx_eapol_internal src/esp_supplicant/esp_wps.c /^int wps_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len)$/;" f +wps_ssid_save src/esp_supplicant/esp_wps.c /^wps_ssid_save(u8 *ssid, u8 ssid_len)$/;" f +wps_st_cb_t src/wps/wps.h /^typedef void (*wps_st_cb_t)(int status);$/;" t +wps_sta_cred_cb src/wps/wps_registrar.c /^static void wps_sta_cred_cb(struct wps_data *wps)$/;" f file: +wps_start src/esp_supplicant/esp_wps.c /^uint8_t wps_start = 0;$/;" v +wps_start_msg_timer src/esp_supplicant/esp_wps.c /^int wps_start_msg_timer(void)$/;" f +wps_start_pending src/esp_supplicant/esp_wifi_driver.h /^ int (*wps_start_pending)(void);$/;" m struct:wps_funcs +wps_start_pending src/esp_supplicant/esp_wps.c /^int wps_start_pending(void)$/;" f +wps_state src/wps/wps.h /^ u8 wps_state;$/;" m struct:wps_event_data::wps_event_er_ap +wps_state src/wps/wps.h /^ enum wps_state wps_state;$/;" m struct:wps_context typeref:enum:wps_context::wps_state +wps_state src/wps/wps_attr_parse.h /^ const u8 *wps_state; \/* 1 octet *\/$/;" m struct:wps_parse_attr +wps_state src/wps/wps_defs.h /^enum wps_state {$/;" g +wps_station_wps_register_cb src/esp_supplicant/esp_wps.c /^wps_station_wps_register_cb(wps_st_cb_t cb)$/;" f +wps_status src/esp_supplicant/esp_wifi_driver.h /^typedef enum wps_status {$/;" g +wps_stop_process src/esp_supplicant/esp_wps.c /^int wps_stop_process(system_event_sta_wps_fail_reason_t reason_code)$/;" f +wps_success_cb_timer src/wps/wps.h /^ ETSTimer wps_success_cb_timer;$/;" m struct:wps_sm +wps_success_event src/wps/wps_common.c /^void wps_success_event(struct wps_context *wps)$/;" f +wps_task_deinit src/esp_supplicant/esp_wps.c /^int wps_task_deinit(void)$/;" f +wps_task_hdl src/esp_supplicant/esp_wps.c /^static void *wps_task_hdl = NULL;$/;" v file: +wps_task_init src/esp_supplicant/esp_wps.c /^int wps_task_init(void)$/;" f +wps_testing_dummy_cred src/esp_supplicant/esp_wps.c /^int wps_testing_dummy_cred = 0;$/;" v +wps_timeout_timer src/wps/wps.h /^ ETSTimer wps_timeout_timer;$/;" m struct:wps_sm +wps_txStart src/esp_supplicant/esp_wps.c /^int wps_txStart(void)$/;" f +wps_type include/esp_supplicant/esp_wps.h /^ wps_type_t wps_type;$/;" m struct:__anon90 +wps_type include/esp_supplicant/esp_wps.h /^typedef enum wps_type {$/;" g +wps_type_t include/esp_supplicant/esp_wps.h /^} wps_type_t;$/;" t typeref:enum:wps_type +wps_upnp src/ap/hostapd.h /^ struct upnp_wps_device_sm *wps_upnp;$/;" m struct:hostapd_data typeref:struct:hostapd_data::upnp_wps_device_sm +wps_uuid_pin src/wps/wps_registrar.c /^struct wps_uuid_pin {$/;" s file: +wps_validate_ap_config_methods src/wps/wps_validate.c /^static int wps_validate_ap_config_methods(const u8 *config_methods, int wps2,$/;" f file: +wps_validate_ap_setup_locked src/wps/wps_validate.c /^static int wps_validate_ap_setup_locked(const u8 *ap_setup_locked,$/;" f file: +wps_validate_assoc_req src/wps/wps.h /^static inline int wps_validate_assoc_req(const struct wpabuf *wps_ie)$/;" f +wps_validate_assoc_req src/wps/wps_validate.c /^int wps_validate_assoc_req(const struct wpabuf *wps_ie)$/;" f +wps_validate_assoc_resp src/wps/wps.h /^static inline int wps_validate_assoc_resp(const struct wpabuf *wps_ie)$/;" f +wps_validate_assoc_resp src/wps/wps_validate.c /^int wps_validate_assoc_resp(const struct wpabuf *wps_ie)$/;" f +wps_validate_assoc_state src/wps/wps_validate.c /^static int wps_validate_assoc_state(const u8 *assoc_state, int mandatory)$/;" f file: +wps_validate_auth_type src/wps/wps_validate.c /^static int wps_validate_auth_type(const u8 *type, int mandatory)$/;" f file: +wps_validate_auth_type_flags src/wps/wps_validate.c /^static int wps_validate_auth_type_flags(const u8 *flags, int mandatory)$/;" f file: +wps_validate_authenticator src/wps/wps_validate.c /^static int wps_validate_authenticator(const u8 *authenticator, int mandatory)$/;" f file: +wps_validate_authorized_macs src/wps/wps_validate.c /^static int wps_validate_authorized_macs(const u8 *authorized_macs, size_t len,$/;" f file: +wps_validate_beacon src/wps/wps.h /^static inline int wps_validate_beacon(const struct wpabuf *wps_ie){$/;" f +wps_validate_beacon src/wps/wps_validate.c /^int wps_validate_beacon(const struct wpabuf *wps_ie)$/;" f +wps_validate_beacon_probe_resp src/wps/wps.h /^static inline int wps_validate_beacon_probe_resp(const struct wpabuf *wps_ie,$/;" f +wps_validate_beacon_probe_resp src/wps/wps_validate.c /^int wps_validate_beacon_probe_resp(const struct wpabuf *wps_ie, int probe,$/;" f +wps_validate_config_error src/wps/wps_validate.c /^static int wps_validate_config_error(const u8 *config_error, int mandatory)$/;" f file: +wps_validate_config_methods src/wps/wps_validate.c /^static int wps_validate_config_methods(const u8 *config_methods, int wps2,$/;" f file: +wps_validate_conn_type_flags src/wps/wps_validate.c /^static int wps_validate_conn_type_flags(const u8 *flags, int mandatory)$/;" f file: +wps_validate_cred src/wps/wps_validate.c /^static int wps_validate_cred(const u8 *cred, size_t len)$/;" f file: +wps_validate_credential src/wps/wps_validate.c /^static int wps_validate_credential(const u8 *cred[], size_t len[], size_t num,$/;" f file: +wps_validate_dev_name src/wps/wps_validate.c /^static int wps_validate_dev_name(const u8 *dev_name, size_t len,$/;" f file: +wps_validate_dev_password_id src/wps/wps_validate.c /^static int wps_validate_dev_password_id(const u8 *dev_password_id,$/;" f file: +wps_validate_e_hash1 src/wps/wps_validate.c /^static int wps_validate_e_hash1(const u8 *hash, int mandatory)$/;" f file: +wps_validate_e_hash2 src/wps/wps_validate.c /^static int wps_validate_e_hash2(const u8 *hash, int mandatory)$/;" f file: +wps_validate_e_snonce1 src/wps/wps_validate.c /^static int wps_validate_e_snonce1(const u8 *nonce, int mandatory)$/;" f file: +wps_validate_e_snonce2 src/wps/wps_validate.c /^static int wps_validate_e_snonce2(const u8 *nonce, int mandatory)$/;" f file: +wps_validate_encr_settings src/wps/wps_validate.c /^static int wps_validate_encr_settings(const u8 *encr_settings, size_t len,$/;" f file: +wps_validate_encr_type src/wps/wps_validate.c /^static int wps_validate_encr_type(const u8 *type, int mandatory)$/;" f file: +wps_validate_encr_type_flags src/wps/wps_validate.c /^static int wps_validate_encr_type_flags(const u8 *flags, int mandatory)$/;" f file: +wps_validate_enrollee_nonce src/wps/wps_validate.c /^static int wps_validate_enrollee_nonce(const u8 *enrollee_nonce, int mandatory)$/;" f file: +wps_validate_key_wrap_auth src/wps/wps_validate.c /^static int wps_validate_key_wrap_auth(const u8 *auth, int mandatory)$/;" f file: +wps_validate_m1 src/wps/wps.h /^static inline int wps_validate_m1(const struct wpabuf *tlvs)$/;" f +wps_validate_m1 src/wps/wps_validate.c /^int wps_validate_m1(const struct wpabuf *tlvs)$/;" f +wps_validate_m2 src/wps/wps.h /^static inline int wps_validate_m2(const struct wpabuf *tlvs)$/;" f +wps_validate_m2 src/wps/wps_validate.c /^int wps_validate_m2(const struct wpabuf *tlvs)$/;" f +wps_validate_m2d src/wps/wps.h /^static inline int wps_validate_m2d(const struct wpabuf *tlvs)$/;" f +wps_validate_m2d src/wps/wps_validate.c /^int wps_validate_m2d(const struct wpabuf *tlvs)$/;" f +wps_validate_m3 src/wps/wps.h /^static inline int wps_validate_m3(const struct wpabuf *tlvs)$/;" f +wps_validate_m3 src/wps/wps_validate.c /^int wps_validate_m3(const struct wpabuf *tlvs)$/;" f +wps_validate_m4 src/wps/wps.h /^static inline int wps_validate_m4(const struct wpabuf *tlvs)$/;" f +wps_validate_m4 src/wps/wps_validate.c /^int wps_validate_m4(const struct wpabuf *tlvs)$/;" f +wps_validate_m4_encr src/wps/wps.h /^static inline int wps_validate_m4_encr(const struct wpabuf *tlvs, int wps2)$/;" f +wps_validate_m4_encr src/wps/wps_validate.c /^int wps_validate_m4_encr(const struct wpabuf *tlvs, int wps2)$/;" f +wps_validate_m5 src/wps/wps.h /^static inline int wps_validate_m5(const struct wpabuf *tlvs)$/;" f +wps_validate_m5 src/wps/wps_validate.c /^int wps_validate_m5(const struct wpabuf *tlvs)$/;" f +wps_validate_m5_encr src/wps/wps.h /^static inline int wps_validate_m5_encr(const struct wpabuf *tlvs, int wps2)$/;" f +wps_validate_m5_encr src/wps/wps_validate.c /^int wps_validate_m5_encr(const struct wpabuf *tlvs, int wps2)$/;" f +wps_validate_m6 src/wps/wps.h /^static inline int wps_validate_m6(const struct wpabuf *tlvs)$/;" f +wps_validate_m6 src/wps/wps_validate.c /^int wps_validate_m6(const struct wpabuf *tlvs)$/;" f +wps_validate_m6_encr src/wps/wps.h /^static inline int wps_validate_m6_encr(const struct wpabuf *tlvs, int wps2)$/;" f +wps_validate_m6_encr src/wps/wps_validate.c /^int wps_validate_m6_encr(const struct wpabuf *tlvs, int wps2)$/;" f +wps_validate_m7 src/wps/wps.h /^static inline int wps_validate_m7(const struct wpabuf *tlvs)$/;" f +wps_validate_m7 src/wps/wps_validate.c /^int wps_validate_m7(const struct wpabuf *tlvs)$/;" f +wps_validate_m7_encr src/wps/wps.h /^static inline int wps_validate_m7_encr(const struct wpabuf *tlvs, int ap,$/;" f +wps_validate_m7_encr src/wps/wps_validate.c /^int wps_validate_m7_encr(const struct wpabuf *tlvs, int ap, int wps2)$/;" f +wps_validate_m8 src/wps/wps.h /^static inline int wps_validate_m8(const struct wpabuf *tlvs)$/;" f +wps_validate_m8 src/wps/wps_validate.c /^int wps_validate_m8(const struct wpabuf *tlvs)$/;" f +wps_validate_m8_encr src/wps/wps.h /^static inline int wps_validate_m8_encr(const struct wpabuf *tlvs, int ap,$/;" f +wps_validate_m8_encr src/wps/wps_validate.c /^int wps_validate_m8_encr(const struct wpabuf *tlvs, int ap, int wps2)$/;" f +wps_validate_mac_addr src/wps/wps_validate.c /^static int wps_validate_mac_addr(const u8 *mac_addr, int mandatory)$/;" f file: +wps_validate_manufacturer src/wps/wps_validate.c /^static int wps_validate_manufacturer(const u8 *manufacturer, size_t len,$/;" f file: +wps_validate_model_name src/wps/wps_validate.c /^static int wps_validate_model_name(const u8 *model_name, size_t len,$/;" f file: +wps_validate_model_number src/wps/wps_validate.c /^static int wps_validate_model_number(const u8 *model_number, size_t len,$/;" f file: +wps_validate_msg_type src/wps/wps_validate.c /^static int wps_validate_msg_type(const u8 *msg_type, int mandatory)$/;" f file: +wps_validate_network_idx src/wps/wps_validate.c /^static int wps_validate_network_idx(const u8 *idx, int mandatory)$/;" f file: +wps_validate_network_key src/wps/wps_validate.c /^static int wps_validate_network_key(const u8 *key, size_t key_len,$/;" f file: +wps_validate_network_key_index src/wps/wps_validate.c /^static int wps_validate_network_key_index(const u8 *idx, int mandatory)$/;" f file: +wps_validate_network_key_shareable src/wps/wps_validate.c /^static int wps_validate_network_key_shareable(const u8 *val, int mandatory)$/;" f file: +wps_validate_os_version src/wps/wps_validate.c /^static int wps_validate_os_version(const u8 *os_version, int mandatory)$/;" f file: +wps_validate_primary_dev_type src/wps/wps_validate.c /^static int wps_validate_primary_dev_type(const u8 *primary_dev_type,$/;" f file: +wps_validate_probe_req src/wps/wps.h /^static inline int wps_validate_probe_req(const struct wpabuf *wps_ie,$/;" f +wps_validate_probe_req src/wps/wps_validate.c /^int wps_validate_probe_req(const struct wpabuf *wps_ie, const u8 *addr)$/;" f +wps_validate_public_key src/wps/wps_validate.c /^static int wps_validate_public_key(const u8 *public_key, size_t len,$/;" f file: +wps_validate_r_hash1 src/wps/wps_validate.c /^static int wps_validate_r_hash1(const u8 *hash, int mandatory)$/;" f file: +wps_validate_r_hash2 src/wps/wps_validate.c /^static int wps_validate_r_hash2(const u8 *hash, int mandatory)$/;" f file: +wps_validate_r_snonce1 src/wps/wps_validate.c /^static int wps_validate_r_snonce1(const u8 *nonce, int mandatory)$/;" f file: +wps_validate_r_snonce2 src/wps/wps_validate.c /^static int wps_validate_r_snonce2(const u8 *nonce, int mandatory)$/;" f file: +wps_validate_registrar_nonce src/wps/wps_validate.c /^static int wps_validate_registrar_nonce(const u8 *registrar_nonce,$/;" f file: +wps_validate_req_dev_type src/wps/wps_validate.c /^static int wps_validate_req_dev_type(const u8 *req_dev_type[], size_t num,$/;" f file: +wps_validate_request_to_enroll src/wps/wps_validate.c /^static int wps_validate_request_to_enroll(const u8 *request_to_enroll,$/;" f file: +wps_validate_request_type src/wps/wps_validate.c /^static int wps_validate_request_type(const u8 *request_type, int mandatory)$/;" f file: +wps_validate_response_type src/wps/wps_validate.c /^static int wps_validate_response_type(const u8 *response_type, int mandatory)$/;" f file: +wps_validate_rf_bands src/wps/wps_validate.c /^static int wps_validate_rf_bands(const u8 *rf_bands, int mandatory)$/;" f file: +wps_validate_sel_reg_config_methods src/wps/wps_validate.c /^static int wps_validate_sel_reg_config_methods(const u8 *config_methods,$/;" f file: +wps_validate_selected_registrar src/wps/wps_validate.c /^static int wps_validate_selected_registrar(const u8 *selected_registrar,$/;" f file: +wps_validate_serial_number src/wps/wps_validate.c /^static int wps_validate_serial_number(const u8 *serial_number, size_t len,$/;" f file: +wps_validate_settings_delay_time src/wps/wps_validate.c /^static int wps_validate_settings_delay_time(const u8 *delay, int mandatory)$/;" f file: +wps_validate_ssid src/wps/wps_validate.c /^static int wps_validate_ssid(const u8 *ssid, size_t ssid_len, int mandatory)$/;" f file: +wps_validate_upnp_set_selected_registrar src/wps/wps.h /^static inline int wps_validate_upnp_set_selected_registrar($/;" f +wps_validate_upnp_set_selected_registrar src/wps/wps_validate.c /^int wps_validate_upnp_set_selected_registrar(const struct wpabuf *tlvs)$/;" f +wps_validate_uuid_e src/wps/wps_validate.c /^static int wps_validate_uuid_e(const u8 *uuid_e, int mandatory)$/;" f file: +wps_validate_uuid_r src/wps/wps_validate.c /^static int wps_validate_uuid_r(const u8 *uuid_r, int mandatory)$/;" f file: +wps_validate_version src/wps/wps_validate.c /^static int wps_validate_version(const u8 *version, int mandatory)$/;" f file: +wps_validate_version2 src/wps/wps_validate.c /^static int wps_validate_version2(const u8 *version2, int mandatory)$/;" f file: +wps_validate_wps_state src/wps/wps_validate.c /^static int wps_validate_wps_state(const u8 *wps_state, int mandatory)$/;" f file: +wps_validate_wsc_ack src/wps/wps.h /^static inline int wps_validate_wsc_ack(const struct wpabuf *tlvs)$/;" f +wps_validate_wsc_ack src/wps/wps_validate.c /^int wps_validate_wsc_ack(const struct wpabuf *tlvs)$/;" f +wps_validate_wsc_done src/wps/wps.h /^static inline int wps_validate_wsc_done(const struct wpabuf *tlvs)$/;" f +wps_validate_wsc_done src/wps/wps_validate.c /^int wps_validate_wsc_done(const struct wpabuf *tlvs)$/;" f +wps_validate_wsc_nack src/wps/wps.h /^static inline int wps_validate_wsc_nack(const struct wpabuf *tlvs)$/;" f +wps_validate_wsc_nack src/wps/wps_validate.c /^int wps_validate_wsc_nack(const struct wpabuf *tlvs)$/;" f +wps_vendor_ext src/ap/ap_config.h /^ struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];$/;" m struct:hostapd_bss_config typeref:struct:hostapd_bss_config::wpabuf +wps_version_number src/esp_supplicant/esp_wps.c /^int wps_version_number = 0x20;$/;" v +wps_workaround_cred_key src/wps/wps_attr_process.c /^static int wps_workaround_cred_key(struct wps_credential *cred)$/;" f file: +write_cbc src/tls/tlsv1_record.h /^ struct crypto_cipher *write_cbc;$/;" m struct:tlsv1_record_layer typeref:struct:tlsv1_record_layer::crypto_cipher +write_cipher_suite src/tls/tlsv1_record.h /^ u16 write_cipher_suite;$/;" m struct:tlsv1_record_layer +write_iv src/tls/tlsv1_record.h /^ u8 write_iv[TLS_MAX_IV_LEN];$/;" m struct:tlsv1_record_layer +write_key src/tls/tlsv1_record.h /^ u8 write_key[TLS_MAX_WRITE_KEY_LEN];$/;" m struct:tlsv1_record_layer +write_mac_secret src/tls/tlsv1_record.h /^ u8 write_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];$/;" m struct:tlsv1_record_layer +write_seq_num src/tls/tlsv1_record.h /^ u8 write_seq_num[TLS_SEQ_NUM_LEN];$/;" m struct:tlsv1_record_layer +wsc_op_code src/wps/wps.h /^enum wsc_op_code {$/;" g +x509_algorithm_identifier src/tls/x509v3.h /^struct x509_algorithm_identifier {$/;" s +x509_certificate src/tls/x509v3.h /^struct x509_certificate {$/;" s +x509_certificate_chain_free src/tls/x509v3.c /^void x509_certificate_chain_free(struct x509_certificate *cert)$/;" f +x509_certificate_chain_validate src/tls/x509v3.c /^int x509_certificate_chain_validate(struct x509_certificate *trusted,$/;" f +x509_certificate_check_signature src/tls/x509v3.c /^int x509_certificate_check_signature(struct x509_certificate *issuer,$/;" f +x509_certificate_free src/tls/x509v3.c /^void x509_certificate_free(struct x509_certificate *cert)$/;" f +x509_certificate_get_subject src/tls/x509v3.c /^x509_certificate_get_subject(struct x509_certificate *chain,$/;" f +x509_certificate_parse src/tls/x509v3.c /^struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len)$/;" f +x509_certificate_self_signed src/tls/x509v3.c /^int x509_certificate_self_signed(struct x509_certificate *cert)$/;" f +x509_digest_oid src/tls/x509v3.c /^static int x509_digest_oid(struct asn1_oid *oid)$/;" f file: +x509_free_name src/tls/x509v3.c /^static void x509_free_name(struct x509_name *name)$/;" f file: +x509_id_ce_oid src/tls/x509v3.c /^static int x509_id_ce_oid(struct asn1_oid *oid)$/;" f file: +x509_name src/tls/x509v3.h /^struct x509_name {$/;" s +x509_name_attr src/tls/x509v3.h /^struct x509_name_attr {$/;" s +x509_name_attr_str src/tls/x509v3.c /^static char * x509_name_attr_str(enum x509_name_attr_type type)$/;" f file: +x509_name_attr_type src/tls/x509v3.h /^ enum x509_name_attr_type {$/;" g struct:x509_name_attr +x509_name_compare src/tls/x509v3.c /^int x509_name_compare(struct x509_name *a, struct x509_name *b)$/;" f +x509_name_string src/tls/x509v3.c /^void x509_name_string(struct x509_name *name, char *buf, size_t len)$/;" f +x509_parse_algorithm_identifier src/tls/x509v3.c /^static int x509_parse_algorithm_identifier($/;" f file: +x509_parse_alt_name_dns src/tls/x509v3.c /^static int x509_parse_alt_name_dns(struct x509_name *name,$/;" f file: +x509_parse_alt_name_ip src/tls/x509v3.c /^static int x509_parse_alt_name_ip(struct x509_name *name,$/;" f file: +x509_parse_alt_name_rfc8222 src/tls/x509v3.c /^static int x509_parse_alt_name_rfc8222(struct x509_name *name,$/;" f file: +x509_parse_alt_name_rid src/tls/x509v3.c /^static int x509_parse_alt_name_rid(struct x509_name *name,$/;" f file: +x509_parse_alt_name_uri src/tls/x509v3.c /^static int x509_parse_alt_name_uri(struct x509_name *name,$/;" f file: +x509_parse_ext_alt_name src/tls/x509v3.c /^static int x509_parse_ext_alt_name(struct x509_name *name,$/;" f file: +x509_parse_ext_basic_constraints src/tls/x509v3.c /^static int x509_parse_ext_basic_constraints(struct x509_certificate *cert,$/;" f file: +x509_parse_ext_issuer_alt_name src/tls/x509v3.c /^static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert,$/;" f file: +x509_parse_ext_key_usage src/tls/x509v3.c /^static int x509_parse_ext_key_usage(struct x509_certificate *cert,$/;" f file: +x509_parse_ext_subject_alt_name src/tls/x509v3.c /^static int x509_parse_ext_subject_alt_name(struct x509_certificate *cert,$/;" f file: +x509_parse_extension src/tls/x509v3.c /^static int x509_parse_extension(struct x509_certificate *cert,$/;" f file: +x509_parse_extension_data src/tls/x509v3.c /^static int x509_parse_extension_data(struct x509_certificate *cert,$/;" f file: +x509_parse_extensions src/tls/x509v3.c /^static int x509_parse_extensions(struct x509_certificate *cert,$/;" f file: +x509_parse_name src/tls/x509v3.c /^static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,$/;" f file: +x509_parse_public_key src/tls/x509v3.c /^static int x509_parse_public_key(const u8 *buf, size_t len,$/;" f file: +x509_parse_tbs_certificate src/tls/x509v3.c /^static int x509_parse_tbs_certificate(const u8 *buf, size_t len,$/;" f file: +x509_parse_time src/tls/x509v3.c /^static int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag,$/;" f file: +x509_parse_validity src/tls/x509v3.c /^static int x509_parse_validity(const u8 *buf, size_t len,$/;" f file: +x509_pkcs_oid src/tls/x509v3.c /^static int x509_pkcs_oid(struct asn1_oid *oid)$/;" f file: +x509_rsadsi_oid src/tls/x509v3.c /^static int x509_rsadsi_oid(struct asn1_oid *oid)$/;" f file: +x509_sha1_oid src/tls/x509v3.c /^static int x509_sha1_oid(struct asn1_oid *oid)$/;" f file: +x509_sha256_oid src/tls/x509v3.c /^static int x509_sha256_oid(struct asn1_oid *oid)$/;" f file: +x509_str_compare src/tls/x509v3.c /^static int x509_str_compare(const char *a, const char *b)$/;" f file: +x509_str_strip_whitespace src/tls/x509v3.c /^static void x509_str_strip_whitespace(char *a)$/;" f file: +x509_valid_issuer src/tls/x509v3.c /^static int x509_valid_issuer(const struct x509_certificate *cert)$/;" f file: +x509_whitespace src/tls/x509v3.c /^static int x509_whitespace(char c)$/;" f file: +xWpa2Queue src/esp_supplicant/esp_wpa_enterprise.c /^static void *xWpa2Queue = NULL;$/;" v file: +xWpsQueue src/esp_supplicant/esp_wps.c /^static void *xWpsQueue = NULL;$/;" v file: +xxkey src/ap/wpa_auth_i.h /^ u8 xxkey[PMK_LEN]; \/* PSK or the second 256 bits of MSK *\/$/;" m struct:wpa_state_machine +xxkey_len src/ap/wpa_auth_i.h /^ size_t xxkey_len;$/;" m struct:wpa_state_machine diff --git a/components/wpa_supplicant/test/CMakeLists.txt b/components/wpa_supplicant/test/CMakeLists.txt index 1be503f44f..0fd0a625ce 100644 --- a/components/wpa_supplicant/test/CMakeLists.txt +++ b/components/wpa_supplicant/test/CMakeLists.txt @@ -1,3 +1,12 @@ idf_component_register(SRC_DIRS "." - INCLUDE_DIRS "." - REQUIRES unity wpa_supplicant mbedtls) \ No newline at end of file + INCLUDE_DIRS "." "${CMAKE_CURRENT_BINARY_DIR}" + PRIV_INCLUDE_DIRS "../src" + REQUIRES unity esp_common test_utils wpa_supplicant mbedtls) + +idf_component_get_property(esp_supplicant_dir wpa_supplicant COMPONENT_DIR) + +# Calculate MD5 value of header file esp_wifi_driver.h +file(MD5 ${esp_supplicant_dir}/src/esp_supplicant/esp_wifi_driver.h WIFI_SUPPLICANT_MD5) +string(SUBSTRING "${WIFI_SUPPLICANT_MD5}" 0 7 WIFI_SUPPLICANT_MD5) + +add_definitions(-DWIFI_SUPPLICANT_MD5=\"${WIFI_SUPPLICANT_MD5}\") diff --git a/components/wpa_supplicant/test/component.mk b/components/wpa_supplicant/test/component.mk index 5dd172bdb7..cfec44f292 100644 --- a/components/wpa_supplicant/test/component.mk +++ b/components/wpa_supplicant/test/component.mk @@ -2,4 +2,10 @@ #Component Makefile # +COMPONENT_PRIV_INCLUDEDIRS := ../src +COMPONENT_SRCDIRS := . + COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive + +WIFI_SUPPLICANT_MD5_VAL=\"$(shell md5sum $(IDF_PATH)/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h | cut -c 1-7)\" +CFLAGS+=-DWIFI_SUPPLICANT_MD5=$(WIFI_SUPPLICANT_MD5_VAL) diff --git a/components/wpa_supplicant/test/test_header_files_md5.c b/components/wpa_supplicant/test/test_header_files_md5.c new file mode 100644 index 0000000000..179227c7e2 --- /dev/null +++ b/components/wpa_supplicant/test/test_header_files_md5.c @@ -0,0 +1,20 @@ +/* + Tests for the Wi-Fi +*/ +#include "unity.h" +#include "esp_log.h" +#include "utils/common.h" +#include "esp_supplicant/esp_wifi_driver.h" + +static const char* TAG = "test_header_files_md5"; + +TEST_CASE("wifi supplicant header files MD5","[wpa_supplicant]") +{ + const char *test_wifi_supplicant_header_md5 = WIFI_SUPPLICANT_MD5; + + ESP_LOGI(TAG, "test wifi supplicant MD5..."); + TEST_ESP_OK(esp_wifi_internal_supplicant_header_md5_check(test_wifi_supplicant_header_md5)); + + ESP_LOGI(TAG, "test passed..."); +} + diff --git a/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c b/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c index 1917c1eb5a..e2127d84ba 100644 --- a/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c +++ b/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c @@ -94,7 +94,6 @@ static void initialise_wifi(void) unsigned int ca_pem_bytes = ca_pem_end - ca_pem_start; unsigned int client_crt_bytes = client_crt_end - client_crt_start; unsigned int client_key_bytes = client_key_end - client_key_start; - esp_wpa2_config_t config = WPA2_CONFIG_INIT_DEFAULT(); tcpip_adapter_init(); wifi_event_group = xEventGroupCreate(); @@ -121,7 +120,7 @@ static void initialise_wifi(void) ESP_ERROR_CHECK( esp_wifi_sta_wpa2_ent_set_password((uint8_t *)EXAMPLE_EAP_PASSWORD, strlen(EXAMPLE_EAP_PASSWORD)) ); } - ESP_ERROR_CHECK( esp_wifi_sta_wpa2_ent_enable(&config) ); + ESP_ERROR_CHECK( esp_wifi_sta_wpa2_ent_enable() ); ESP_ERROR_CHECK( esp_wifi_start() ); } From 30d700273193539a79bf2e69a80b3867eea969bc Mon Sep 17 00:00:00 2001 From: baohongde Date: Fri, 28 Jun 2019 11:29:07 +0800 Subject: [PATCH 186/486] components/bt: Add AVRCP feature about volume --- components/bt/bluedroid/api/esp_avrc_api.c | 58 +++++++-- .../bluedroid/api/include/api/esp_avrc_api.h | 48 ++++++-- components/bt/bluedroid/bta/av/bta_av_cfg.c | 18 ++- components/bt/bluedroid/bta/av/bta_av_main.c | 19 ++- .../bt/bluedroid/bta/include/bta/bta_av_api.h | 6 +- .../bluedroid/btc/profile/std/avrc/btc_avrc.c | 102 +++++++++++---- .../btc/profile/std/include/btc_avrc.h | 12 +- examples/bluetooth/a2dp_source/main/main.c | 116 +++++++++++++++++- 8 files changed, 315 insertions(+), 64 deletions(-) diff --git a/components/bt/bluedroid/api/esp_avrc_api.c b/components/bt/bluedroid/api/esp_avrc_api.c index 9b9e6616c2..cbfa71a035 100644 --- a/components/bt/bluedroid/api/esp_avrc_api.c +++ b/components/bt/bluedroid/api/esp_avrc_api.c @@ -29,7 +29,7 @@ esp_err_t esp_avrc_ct_register_callback(esp_avrc_ct_cb_t callback) } if (callback == NULL) { - return ESP_FAIL; + return ESP_ERR_INVALID_ARG; } btc_profile_cb_set(BTC_PID_AVRC_CT, callback); @@ -76,8 +76,8 @@ esp_err_t esp_avrc_ct_send_set_player_value_cmd(uint8_t tl, uint8_t attr_id, uin return ESP_ERR_INVALID_STATE; } - if (tl >= 16 || attr_id > ESP_AVRC_PS_MAX_ATTR - 1) { - return ESP_FAIL; + if (tl > ESP_AVRC_TRANS_LABEL_MAX || attr_id > ESP_AVRC_PS_MAX_ATTR - 1) { + return ESP_ERR_INVALID_ARG; } btc_msg_t msg; @@ -103,7 +103,7 @@ esp_err_t esp_avrc_ct_send_get_rn_capabilities_cmd(uint8_t tl) return ESP_ERR_INVALID_STATE; } - if (tl >= 16) { + if (tl > ESP_AVRC_TRANS_LABEL_MAX) { return ESP_ERR_INVALID_ARG; } @@ -128,8 +128,8 @@ esp_err_t esp_avrc_ct_send_register_notification_cmd(uint8_t tl, uint8_t event_i return ESP_ERR_INVALID_STATE; } - if (tl >= 16 || event_id > ESP_AVRC_RN_MAX_EVT - 1) { - return ESP_FAIL; + if (tl > ESP_AVRC_TRANS_LABEL_MAX || event_id > ESP_AVRC_RN_MAX_EVT - 1) { + return ESP_ERR_INVALID_ARG; } if (!btc_avrc_ct_rn_evt_supported(event_id)) { @@ -153,14 +153,48 @@ esp_err_t esp_avrc_ct_send_register_notification_cmd(uint8_t tl, uint8_t event_i return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; } +esp_err_t esp_avrc_ct_send_set_absolute_volume_cmd(uint8_t tl, uint8_t volume) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + if (tl > ESP_AVRC_TRANS_LABEL_MAX) { + return ESP_ERR_INVALID_ARG; + } + + if (volume > BTC_AVRC_MAX_VOLUME) { + return ESP_ERR_INVALID_ARG; + } + + if (!btc_avrc_ct_rn_evt_supported(ESP_AVRC_RN_VOLUME_CHANGE)) { + return ESP_ERR_NOT_SUPPORTED; + } + + btc_msg_t msg; + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_AVRC_CT; + msg.act = BTC_AVRC_CTRL_API_SND_SET_ABSOLUTE_VOLUME_EVT; + + btc_avrc_args_t arg; + memset(&arg, 0, sizeof(btc_avrc_args_t)); + + arg.set_abs_vol_cmd.tl = tl; + arg.set_abs_vol_cmd.volume = volume; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_avrc_args_t), NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + esp_err_t esp_avrc_ct_send_metadata_cmd(uint8_t tl, uint8_t attr_mask) { if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { return ESP_ERR_INVALID_STATE; } - if (tl >= 16) { - return ESP_FAIL; + if (tl > ESP_AVRC_TRANS_LABEL_MAX) { + return ESP_ERR_INVALID_ARG; } btc_msg_t msg; @@ -185,8 +219,8 @@ esp_err_t esp_avrc_ct_send_passthrough_cmd(uint8_t tl, uint8_t key_code, uint8_t return ESP_ERR_INVALID_STATE; } - if (tl >= 16 || key_state > ESP_AVRC_PT_CMD_STATE_RELEASED) { - return ESP_FAIL; + if (tl > ESP_AVRC_TRANS_LABEL_MAX || key_state > ESP_AVRC_PT_CMD_STATE_RELEASED) { + return ESP_ERR_INVALID_ARG; } btc_msg_t msg; @@ -217,7 +251,7 @@ esp_err_t esp_avrc_tg_register_callback(esp_avrc_tg_cb_t callback) } if (callback == NULL) { - return ESP_FAIL; + return ESP_ERR_INVALID_ARG; } btc_profile_cb_set(BTC_PID_AVRC_TG, callback); @@ -445,7 +479,7 @@ esp_err_t esp_avrc_tg_send_rn_rsp(esp_avrc_rn_event_ids_t event_id, esp_avrc_rn_ /* Switch to BTC context */ bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_avrc_tg_args_t), NULL); return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; - + } #endif /* #if BTC_AV_INCLUDED */ diff --git a/components/bt/bluedroid/api/include/api/esp_avrc_api.h b/components/bt/bluedroid/api/include/api/esp_avrc_api.h index 814f2be338..e75eb637df 100644 --- a/components/bt/bluedroid/api/include/api/esp_avrc_api.h +++ b/components/bt/bluedroid/api/include/api/esp_avrc_api.h @@ -24,6 +24,8 @@ extern "C" { #endif +#define ESP_AVRC_TRANS_LABEL_MAX 15 /*!< max transaction label */ + /// AVRC feature bit mask typedef enum { ESP_AVRC_FEAT_RCTG = 0x0001, /*!< remote control target */ @@ -140,6 +142,7 @@ typedef enum { ESP_AVRC_CT_CHANGE_NOTIFY_EVT = 4, /*!< notification event */ ESP_AVRC_CT_REMOTE_FEATURES_EVT = 5, /*!< feature of remote device indication event */ ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT = 6, /*!< supported notification events capability of peer device */ + ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_RSP_EVT = 7, /*!< set absolute volume response event */ } esp_avrc_ct_cb_event_t; /// AVRC Target callback events @@ -327,6 +330,13 @@ typedef union { uint8_t cap_count; /*!< number of items provided in event or company_id according to cap_id used */ esp_avrc_rn_evt_cap_mask_t evt_set; /*!< supported event_ids represented in bit-mask */ } get_rn_caps_rsp; /*!< get supported event capabilities response from AVRCP target */ + + /** + * @brief ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_RSP_EVT + */ + struct avrc_ct_set_volume_rsp_param { + uint8_t volume; /*!< the volume which has actually been set, range is 0 to 0x7f, means 0% to 100% */ + } set_volume_rsp; /*!< set absolute volume response event */ } esp_avrc_ct_cb_param_t; /// AVRC target callback parameters @@ -460,7 +470,8 @@ esp_err_t esp_avrc_ct_send_get_rn_capabilities_cmd(uint8_t tl); * * @param[in] tl : transaction label, 0 to 15, consecutive commands should use different values. * @param[in] event_id : id of events, e.g. ESP_AVRC_RN_PLAY_STATUS_CHANGE, ESP_AVRC_RN_TRACK_CHANGE, etc. - * @param[in] event_parameter : special parameters, eg. playback interval for ESP_AVRC_RN_PLAY_POS_CHANGED + * @param[in] event_parameter : playback interval for ESP_AVRC_RN_PLAY_POS_CHANGED; + * For other events , value of this parameter is ignored. * @return * - ESP_OK: success * - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled @@ -469,6 +480,19 @@ esp_err_t esp_avrc_ct_send_get_rn_capabilities_cmd(uint8_t tl); */ esp_err_t esp_avrc_ct_send_register_notification_cmd(uint8_t tl, uint8_t event_id, uint32_t event_parameter); +/** + * @brief Send set absolute volume command to AVRCP target, This function should be called after + * ESP_AVRC_CT_CONNECTION_STATE_EVT is received and AVRCP connection is established + * + * @param[in] tl : transaction label, 0 to 15, consecutive commands should use different values. + * @param[in] volume : volume, 0 to 0x7f, means 0% to 100% + * @return + * - ESP_OK: success + * - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_ERR_NOT_SUPPORTED: if the event_id is not supported in current implementation + * - ESP_FAIL: others + */ +esp_err_t esp_avrc_ct_send_set_absolute_volume_cmd(uint8_t tl, uint8_t volume); /** * @brief Send metadata command to AVRCP target, This function should be called after @@ -562,22 +586,22 @@ esp_err_t esp_avrc_tg_get_psth_cmd_filter(esp_avrc_psth_filter_t filter, esp_avr /** * - * @brief Set the filter of remote passthrough commands on AVRC target. Filter is given by - * filter type and bit mask for the passthrough commands. This function should be called + * @brief Set the filter of remote passthrough commands on AVRC target. Filter is given by + * filter type and bit mask for the passthrough commands. This function should be called * after esp_avrc_tg_init(). * If filter type is ESP_AVRC_PSTH_FILTER_SUPPORT_CMD, the passthrough commands which - * are set "1" as given in cmd_set will generate ESP_AVRC_CT_PASSTHROUGH_RSP_EVT callback + * are set "1" as given in cmd_set will generate ESP_AVRC_CT_PASSTHROUGH_RSP_EVT callback * event and are auto-accepted in the protocol stack, other commands are replied with response - * type "NOT IMPLEMENTED" (8). The set of supported commands should be a subset of allowed - * command set. The allowed command set can be retrieved using esp_avrc_tg_get_psth_cmd_filter() + * type "NOT IMPLEMENTED" (8). The set of supported commands should be a subset of allowed + * command set. The allowed command set can be retrieved using esp_avrc_tg_get_psth_cmd_filter() * with filter type "ESP_AVRC_PSTH_FILTER_ALLOWED_CMD". - * + * * Filter type "ESP_AVRC_PSTH_FILTER_ALLOWED_CMD" does not apply to this function * @return * - ESP_OK: success * - ESP_ERR_INVALID_STATE: if bluetooth stack is not enabled * - ESP_ERR_INVALID_ARG: if filter type is invalid or cmd_set is NULL - * - ESP_ERR_NOT_SUPPORTED:: if filter type is ESP_AVRC_PSTH_FILTER_ALLOWED_CMD, or cmd_set + * - ESP_ERR_NOT_SUPPORTED:: if filter type is ESP_AVRC_PSTH_FILTER_ALLOWED_CMD, or cmd_set * includes unallowed commands * */ @@ -601,13 +625,13 @@ bool esp_avrc_psth_bit_mask_operation(esp_avrc_bit_mask_op_t op, esp_avrc_psth_b /** * * @brief Get the requested event notification capabilies on local AVRC target. The capability is returned - * in a bit mask representation in evt_set. This function should be called after + * in a bit mask representation in evt_set. This function should be called after * esp_avrc_tg_init(). * For capability type "ESP_AVRC_RN_CAP_ALLOWED_EVT, the retrieved event set is constant and - * it covers all of the notifcation events that can possibly be supported with current + * it covers all of the notifcation events that can possibly be supported with current * implementation. * For capability type ESP_AVRC_RN_CAP_SUPPORTED_EVT, the event set covers the notification - * events selected to be supported under current configuration, The configuration can be + * events selected to be supported under current configuration, The configuration can be * changed using esp_avrc_tg_set_rn_evt_cap() * * @return @@ -652,7 +676,7 @@ bool esp_avrc_rn_evt_bit_mask_operation(esp_avrc_bit_mask_op_t op, esp_avrc_rn_e * @brief Send RegisterNotification Response to remote AVRCP controller. Local event notification * capability can be set using esp_avrc_tg_set_rn_evt_cap(), * in a bit mask representation in evt_set. This function should be called after - * esp_avrc_tg_init() + * esp_avrc_tg_init() * @param[in] event_id: notification event ID that remote AVRCP CT registers * @param[in] rsp: notification response code * @param[in] param: parameters included in the specific notification diff --git a/components/bt/bluedroid/bta/av/bta_av_cfg.c b/components/bt/bluedroid/bta/av/bta_av_cfg.c index b8a86831c5..9f39239f5c 100644 --- a/components/bt/bluedroid/bta/av/bta_av_cfg.c +++ b/components/bt/bluedroid/bta/av/bta_av_cfg.c @@ -40,8 +40,10 @@ const UINT32 bta_av_meta_caps_co_ids[] = { AVRC_CO_BROADCOM }; -/* AVRCP cupported categories */ -#define BTA_AV_RC_SUPF_CT (AVRC_SUPF_CT_CAT1) +/* AVRCP supported categories */ +#define BTA_AV_RC_SNK_SUPF_CT (AVRC_SUPF_CT_CAT1) +#define BTA_AV_RC_SRC_SUPF_CT (AVRC_SUPF_CT_CAT2) + /* Added to modify ** 1. flush timeout @@ -62,9 +64,11 @@ const UINT16 bta_av_audio_flush_to[] = { /* Note: Android doesnt support AVRC_SUPF_TG_GROUP_NAVI */ /* Note: if AVRC_SUPF_TG_GROUP_NAVI is set, bta_av_cfg.avrc_group should be TRUE */ #if AVRC_METADATA_INCLUDED == TRUE -#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT2) /* TODO: | AVRC_SUPF_TG_APP_SETTINGS) */ +#define BTA_AV_RC_SNK_SUPF_TG (AVRC_SUPF_TG_CAT2) /* TODO: | AVRC_SUPF_TG_APP_SETTINGS) */ +#define BTA_AV_RC_SRC_SUPF_TG (AVRC_SUPF_TG_CAT1) /* TODO: | AVRC_SUPF_TG_APP_SETTINGS) */ #else -#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT2) +#define BTA_AV_RC_SNK_SUPF_TG (AVRC_SUPF_TG_CAT2) +#define BTA_AV_RC_SRC_SUPF_TG (AVRC_SUPF_TG_CAT1) #endif /* the MTU for the AVRCP browsing channel */ @@ -80,8 +84,10 @@ const tBTA_AV_CFG bta_av_cfg = { 48, /* AVRCP MTU at L2CAP for control channel */ #endif BTA_AV_MAX_RC_BR_MTU, /* AVRCP MTU at L2CAP for browsing channel */ - BTA_AV_RC_SUPF_CT, /* AVRCP controller categories */ - BTA_AV_RC_SUPF_TG, /* AVRCP target categories */ + BTA_AV_RC_SNK_SUPF_CT, /* AVRCP controller categories as SNK */ + BTA_AV_RC_SNK_SUPF_TG, /* AVRCP target categories as SNK */ + BTA_AV_RC_SRC_SUPF_CT, /* AVRCP controller categories as SRC */ + BTA_AV_RC_SRC_SUPF_TG, /* AVRCP target categories as SRC */ 672, /* AVDTP signaling channel MTU at L2CAP */ BTA_AV_MAX_A2DP_MTU, /* AVDTP audio transport channel MTU at L2CAP */ bta_av_audio_flush_to, /* AVDTP audio transport channel flush timeout */ diff --git a/components/bt/bluedroid/bta/av/bta_av_main.c b/components/bt/bluedroid/bta/av/bta_av_main.c index bc352c8fa4..f669365268 100644 --- a/components/bt/bluedroid/bta/av/bta_av_main.c +++ b/components/bt/bluedroid/bta/av/bta_av_main.c @@ -576,9 +576,13 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data) bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu, (UINT8)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)), BTA_ID_AV); #endif - - bta_ar_reg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target\n", NULL, - p_bta_av_cfg->avrc_tg_cat, BTA_ID_AV); + if (p_data->api_reg.tsep == AVDT_TSEP_SRC) { + bta_ar_reg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target\n", NULL, + p_bta_av_cfg->avrc_src_tg_cat, BTA_ID_AV); + } else { + bta_ar_reg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target\n", NULL, + p_bta_av_cfg->avrc_snk_tg_cat, BTA_ID_AV); + } #endif } @@ -711,8 +715,13 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data) } #if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) /* create an SDP record as AVRC CT. */ - bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL, - p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV); + if (p_data->api_reg.tsep == AVDT_TSEP_SRC) { + bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, "AV Remote Control Controller\n", NULL, + p_bta_av_cfg->avrc_src_ct_cat, BTA_ID_AV); + } else { + bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, "AV Remote Control Controller\n", NULL, + p_bta_av_cfg->avrc_snk_ct_cat, BTA_ID_AV); + } #endif } } diff --git a/components/bt/bluedroid/bta/include/bta/bta_av_api.h b/components/bt/bluedroid/bta/include/bta/bta_av_api.h index 351c0bc61f..5efc2662c4 100644 --- a/components/bt/bluedroid/bta/include/bta/bta_av_api.h +++ b/components/bt/bluedroid/bta/include/bta/bta_av_api.h @@ -529,8 +529,10 @@ typedef struct { UINT32 company_id; /* AVRCP Company ID */ UINT16 avrc_mtu; /* AVRCP MTU at L2CAP for control channel */ UINT16 avrc_br_mtu; /* AVRCP MTU at L2CAP for browsing channel */ - UINT16 avrc_ct_cat; /* AVRCP controller categories */ - UINT16 avrc_tg_cat; /* AVRCP target categories */ + UINT16 avrc_snk_ct_cat; /* AVRCP controller categories as SNK */ + UINT16 avrc_snk_tg_cat; /* AVRCP target categories SNK */ + UINT16 avrc_src_ct_cat; /* AVRCP controller categories as SRC */ + UINT16 avrc_src_tg_cat; /* AVRCP target categories as SRC */ UINT16 sig_mtu; /* AVDTP signaling channel MTU at L2CAP */ UINT16 audio_mtu; /* AVDTP audio transport channel MTU at L2CAP */ const UINT16 *p_audio_flush_to;/* AVDTP audio transport channel flush timeout */ diff --git a/components/bt/bluedroid/btc/profile/std/avrc/btc_avrc.c b/components/bt/bluedroid/btc/profile/std/avrc/btc_avrc.c index 28ecb85e63..0e4d0e4922 100644 --- a/components/bt/bluedroid/btc/profile/std/avrc/btc_avrc.c +++ b/components/bt/bluedroid/btc/profile/std/avrc/btc_avrc.c @@ -71,7 +71,7 @@ const static uint16_t cs_psth_allowed_cmd[8] = { 0x0078, /* bit mask: 0=CHAN_UP, 1=CHAN_DOWN, 2=PREV_CHAN, 3=SOUND_SEL, 4=INPUT_SEL, 5=DISP_INFO, 6=HELP, 7=PAGE_UP, 8=PAGE_DOWN */ - 0x1b3F, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE, + 0x1b7F, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE, 4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD, 8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD, 12=BACKWARD */ @@ -635,6 +635,16 @@ static void handle_rc_get_caps_rsp (tAVRC_GET_CAPS_RSP *rsp) } } +static void handle_rc_set_absolute_volume_rsp(tAVRC_SET_VOLUME_RSP *rsp) +{ + esp_avrc_ct_cb_param_t param; + memset(¶m, 0, sizeof(esp_avrc_ct_cb_param_t)); + + param.set_volume_rsp.volume = rsp->volume; + + btc_avrc_ct_cb_to_app(ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_RSP_EVT, ¶m); +} + /*************************************************************************** * Function handle_rc_metamsg_cmd * @@ -822,6 +832,11 @@ static void handle_rc_metamsg_rsp (tBTA_AV_META_MSG *p_meta_msg) handle_rc_get_caps_rsp(&avrc_response.get_caps); } break; + case AVRC_PDU_SET_ABSOLUTE_VOLUME: + if (vendor_msg->hdr.ctype == AVRC_RSP_ACCEPT) { + handle_rc_set_absolute_volume_rsp(&avrc_response.volume); + } + break; default: BTC_TRACE_WARNING("%s: unhandled meta rsp: pdu 0x%x", __FUNCTION__, avrc_response.rsp.pdu); } @@ -1055,15 +1070,15 @@ static bt_status_t btc_avrc_ct_send_set_player_value_cmd(uint8_t tl, uint8_t att avrc_cmd.set_app_val.p_vals = &values; avrc_cmd.set_app_val.pdu = AVRC_PDU_SET_PLAYER_APP_VALUE; - status = AVRC_BldCommand(&avrc_cmd, &p_msg); - if (status == AVRC_STS_NO_ERROR) { - if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) { + if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) { + status = AVRC_BldCommand(&avrc_cmd, &p_msg); + if (status == AVRC_STS_NO_ERROR) { BTA_AvMetaCmd(btc_rc_cb.rc_handle, tl, BTA_AV_CMD_CTRL, p_msg); status = BT_STATUS_SUCCESS; - } else { - status = BT_STATUS_FAIL; - BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__); } + } else { + status = BT_STATUS_FAIL; + BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__); } #else @@ -1088,15 +1103,15 @@ static bt_status_t btc_avrc_ct_send_get_rn_caps_cmd(uint8_t tl) avrc_cmd.get_caps.pdu = AVRC_PDU_GET_CAPABILITIES; avrc_cmd.get_caps.capability_id = AVRC_CAP_EVENTS_SUPPORTED; - status = AVRC_BldCommand(&avrc_cmd, &p_msg); - if (status == AVRC_STS_NO_ERROR) { - if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) { + if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) { + status = AVRC_BldCommand(&avrc_cmd, &p_msg); + if (status == AVRC_STS_NO_ERROR) { BTA_AvMetaCmd(btc_rc_cb.rc_handle, tl, AVRC_CMD_STATUS, p_msg); status = BT_STATUS_SUCCESS; - } else { - status = BT_STATUS_FAIL; - BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__); } + } else { + status = BT_STATUS_FAIL; + BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__); } #else @@ -1122,15 +1137,48 @@ static bt_status_t btc_avrc_ct_send_register_notification_cmd(uint8_t tl, uint8_ avrc_cmd.reg_notif.param = event_parameter; avrc_cmd.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION; - status = AVRC_BldCommand(&avrc_cmd, &p_msg); - if (status == AVRC_STS_NO_ERROR) { - if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) { + if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) { + status = AVRC_BldCommand(&avrc_cmd, &p_msg); + if (status == AVRC_STS_NO_ERROR) { BTA_AvMetaCmd(btc_rc_cb.rc_handle, tl, AVRC_CMD_NOTIF, p_msg); status = BT_STATUS_SUCCESS; - } else { - status = BT_STATUS_FAIL; - BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__); } + } else { + status = BT_STATUS_FAIL; + BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__); + } + +#else + BTC_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__); +#endif + + return status; +} + +static bt_status_t btc_avrc_ct_send_set_absolute_volume_cmd(uint8_t tl, uint8_t volume) +{ + tAVRC_STS status = BT_STATUS_UNSUPPORTED; + +#if (AVRC_METADATA_INCLUDED == TRUE) + CHECK_ESP_RC_CONNECTED; + + tAVRC_COMMAND avrc_cmd = {0}; + BT_HDR *p_msg = NULL; + + avrc_cmd.volume.opcode = AVRC_OP_VENDOR; + avrc_cmd.volume.status = AVRC_STS_NO_ERROR; + avrc_cmd.volume.volume = volume; + avrc_cmd.volume.pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME; + + if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) { + status = AVRC_BldCommand(&avrc_cmd, &p_msg); + if (status == AVRC_STS_NO_ERROR) { + BTA_AvMetaCmd(btc_rc_cb.rc_handle, tl, AVRC_CMD_CTRL, p_msg); + status = BT_STATUS_SUCCESS; + } + } else { + status = BT_STATUS_FAIL; + BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__); } #else @@ -1164,15 +1212,15 @@ static bt_status_t btc_avrc_ct_send_metadata_cmd (uint8_t tl, uint8_t attr_mask) avrc_cmd.get_elem_attrs.num_attr = index; - status = AVRC_BldCommand(&avrc_cmd, &p_msg); - if (status == AVRC_STS_NO_ERROR) { - if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) { + if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) { + status = AVRC_BldCommand(&avrc_cmd, &p_msg); + if (status == AVRC_STS_NO_ERROR) { BTA_AvMetaCmd(btc_rc_cb.rc_handle, tl, AVRC_CMD_STATUS, p_msg); status = BT_STATUS_SUCCESS; - } else { - status = BT_STATUS_FAIL; - BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__); } + } else { + status = BT_STATUS_FAIL; + BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__); } #else @@ -1338,6 +1386,10 @@ void btc_avrc_ct_call_handler(btc_msg_t *msg) btc_avrc_ct_send_set_player_value_cmd(arg->ps_cmd.tl, arg->ps_cmd.attr_id, arg->ps_cmd.value_id); break; } + case BTC_AVRC_CTRL_API_SND_SET_ABSOLUTE_VOLUME_EVT: { + btc_avrc_ct_send_set_absolute_volume_cmd(arg->set_abs_vol_cmd.tl, arg->set_abs_vol_cmd.volume); + break; + } default: BTC_TRACE_WARNING("%s : unhandled event: %d\n", __FUNCTION__, msg->act); } diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_avrc.h b/components/bt/bluedroid/btc/profile/std/include/btc_avrc.h index ec98c5ee56..2ff164b50d 100644 --- a/components/bt/bluedroid/btc/profile/std/include/btc_avrc.h +++ b/components/bt/bluedroid/btc/profile/std/include/btc_avrc.h @@ -38,7 +38,8 @@ typedef enum { BTC_AVRC_STATUS_API_SND_PLAY_STATUS_EVT, BTC_AVRC_STATUS_API_SND_GET_RN_CAPS_EVT, BTC_AVRC_NOTIFY_API_SND_REG_NOTIFY_EVT, - BTC_AVRC_CTRL_API_SND_SET_PLAYER_SETTING_EVT + BTC_AVRC_CTRL_API_SND_SET_PLAYER_SETTING_EVT, + BTC_AVRC_CTRL_API_SND_SET_ABSOLUTE_VOLUME_EVT } btc_avrc_act_t; typedef struct { @@ -68,6 +69,14 @@ typedef struct { uint8_t tl; } get_caps_cmd_t; +#define BTC_AVRC_MIN_VOLUME 0x00 +#define BTC_AVRC_MAX_VOLUME 0x7f + +typedef struct { + uint8_t tl; + uint8_t volume; +} set_abs_vol_cmd_t; + /* btc_avrc_args_t */ typedef union { pt_cmd_t pt_cmd; @@ -75,6 +84,7 @@ typedef union { rn_cmd_t rn_cmd; ps_cmd_t ps_cmd; get_caps_cmd_t get_caps_cmd; + set_abs_vol_cmd_t set_abs_vol_cmd; } btc_avrc_args_t; /* btc_avrc_tg_act_t */ diff --git a/examples/bluetooth/a2dp_source/main/main.c b/examples/bluetooth/a2dp_source/main/main.c index dbf7618b8c..a3971f8cdb 100644 --- a/examples/bluetooth/a2dp_source/main/main.c +++ b/examples/bluetooth/a2dp_source/main/main.c @@ -27,6 +27,11 @@ #include "esp_avrc_api.h" #define BT_AV_TAG "BT_AV" +#define BT_RC_CT_TAG "RCCT" + +// AVRCP used transaction label +#define APP_RC_CT_TL_GET_CAPS (0) +#define APP_RC_CT_TL_RN_VOLUME_CHANGE (1) /* event for handler "bt_av_hdl_stack_up */ enum { @@ -63,11 +68,17 @@ static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param); /// callback function for A2DP source audio data stream static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len); +/// callback function for AVRCP controller +static void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param); + static void a2d_app_heart_beat(void *arg); /// A2DP application state machine static void bt_app_av_sm_hdlr(uint16_t event, void *param); +/// avrc CT event handler +static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param); + /* A2DP application state machine handler for each state */ static void bt_app_av_state_unconnected(uint16_t event, void *param); static void bt_app_av_state_connecting(uint16_t event, void *param); @@ -81,7 +92,7 @@ static int s_media_state = APP_AV_MEDIA_STATE_IDLE; static int s_intv_cnt = 0; static int s_connecting_intv = 0; static uint32_t s_pkt_cnt = 0; - +static esp_avrc_rn_evt_cap_mask_t s_avrc_peer_rn_cap; static TimerHandle_t s_tmr; static char *bda2str(esp_bd_addr_t bda, char *str, size_t size) @@ -322,6 +333,14 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param) /* register GAP callback function */ esp_bt_gap_register_callback(bt_app_gap_cb); + /* initialize AVRCP controller */ + esp_avrc_ct_init(); + esp_avrc_ct_register_callback(bt_app_rc_ct_cb); + + esp_avrc_rn_evt_cap_mask_t evt_set = {0}; + esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_SET, &evt_set, ESP_AVRC_RN_VOLUME_CHANGE); + assert(esp_avrc_tg_set_rn_evt_cap(&evt_set) == ESP_OK); + /* initialize A2DP source */ esp_a2d_register_callback(&bt_app_a2d_cb); esp_a2d_source_register_data_callback(bt_app_a2d_data_cb); @@ -578,3 +597,98 @@ static void bt_app_av_state_disconnecting(uint16_t event, void *param) break; } } + +static void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param) +{ + switch (event) { + case ESP_AVRC_CT_METADATA_RSP_EVT: + case ESP_AVRC_CT_CONNECTION_STATE_EVT: + case ESP_AVRC_CT_PASSTHROUGH_RSP_EVT: + case ESP_AVRC_CT_CHANGE_NOTIFY_EVT: + case ESP_AVRC_CT_REMOTE_FEATURES_EVT: + case ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT: + case ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_RSP_EVT: { + bt_app_work_dispatch(bt_av_hdl_avrc_ct_evt, event, param, sizeof(esp_avrc_ct_cb_param_t), NULL); + break; + } + default: + ESP_LOGE(BT_RC_CT_TAG, "Invalid AVRC event: %d", event); + break; + } +} + +static void bt_av_volume_changed(void) +{ + if (esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_TEST, &s_avrc_peer_rn_cap, + ESP_AVRC_RN_VOLUME_CHANGE)) { + esp_avrc_ct_send_register_notification_cmd(APP_RC_CT_TL_RN_VOLUME_CHANGE, ESP_AVRC_RN_VOLUME_CHANGE, 0); + } +} + +void bt_av_notify_evt_handler(uint8_t event_id, esp_avrc_rn_param_t *event_parameter) +{ + switch (event_id) { + case ESP_AVRC_RN_VOLUME_CHANGE: + ESP_LOGI(BT_RC_CT_TAG, "Volume changed: %d", event_parameter->volume); + ESP_LOGI(BT_RC_CT_TAG, "Set absolute volume: volume %d", event_parameter->volume + 5); + esp_avrc_ct_send_set_absolute_volume_cmd(APP_RC_CT_TL_RN_VOLUME_CHANGE, event_parameter->volume + 5); + bt_av_volume_changed(); + break; + } +} + +static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param) +{ + ESP_LOGD(BT_RC_CT_TAG, "%s evt %d", __func__, event); + esp_avrc_ct_cb_param_t *rc = (esp_avrc_ct_cb_param_t *)(p_param); + switch (event) { + case ESP_AVRC_CT_CONNECTION_STATE_EVT: { + uint8_t *bda = rc->conn_stat.remote_bda; + ESP_LOGI(BT_RC_CT_TAG, "AVRC conn_state evt: state %d, [%02x:%02x:%02x:%02x:%02x:%02x]", + rc->conn_stat.connected, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); + + if (rc->conn_stat.connected) { + // get remote supported event_ids of peer AVRCP Target + esp_avrc_ct_send_get_rn_capabilities_cmd(APP_RC_CT_TL_GET_CAPS); + } else { + // clear peer notification capability record + s_avrc_peer_rn_cap.bits = 0; + } + break; + } + case ESP_AVRC_CT_PASSTHROUGH_RSP_EVT: { + ESP_LOGI(BT_RC_CT_TAG, "AVRC passthrough rsp: key_code 0x%x, key_state %d", rc->psth_rsp.key_code, rc->psth_rsp.key_state); + break; + } + case ESP_AVRC_CT_METADATA_RSP_EVT: { + ESP_LOGI(BT_RC_CT_TAG, "AVRC metadata rsp: attribute id 0x%x, %s", rc->meta_rsp.attr_id, rc->meta_rsp.attr_text); + free(rc->meta_rsp.attr_text); + break; + } + case ESP_AVRC_CT_CHANGE_NOTIFY_EVT: { + ESP_LOGI(BT_RC_CT_TAG, "AVRC event notification: %d", rc->change_ntf.event_id); + bt_av_notify_evt_handler(rc->change_ntf.event_id, &rc->change_ntf.event_parameter); + break; + } + case ESP_AVRC_CT_REMOTE_FEATURES_EVT: { + ESP_LOGI(BT_RC_CT_TAG, "AVRC remote features %x, TG features %x", rc->rmt_feats.feat_mask, rc->rmt_feats.tg_feat_flag); + break; + } + case ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT: { + ESP_LOGI(BT_RC_CT_TAG, "remote rn_cap: count %d, bitmask 0x%x", rc->get_rn_caps_rsp.cap_count, + rc->get_rn_caps_rsp.evt_set.bits); + s_avrc_peer_rn_cap.bits = rc->get_rn_caps_rsp.evt_set.bits; + + bt_av_volume_changed(); + break; + } + case ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_RSP_EVT: { + ESP_LOGI(BT_RC_CT_TAG, "Set absolute volume rsp: volume %d", rc->set_volume_rsp.volume); + break; + } + + default: + ESP_LOGE(BT_RC_CT_TAG, "%s unhandled evt %d", __func__, event); + break; + } +} \ No newline at end of file From 21165edf41813482bd1d0a8183969854d1011f24 Mon Sep 17 00:00:00 2001 From: Hrishikesh Dhayagude Date: Sun, 30 Jun 2019 16:39:00 +0800 Subject: [PATCH 187/486] Bluetooth component refactoring --- .gitmodules | 8 +- components/bt/CMakeLists.txt | 830 ++++---- components/bt/Kconfig | 1798 +---------------- .../btc/core/btc_alarm.c | 1 + .../btc/core/btc_manage.c | 3 - .../{bluedroid => common}/btc/core/btc_task.c | 15 +- .../btc/include/btc/btc_alarm.h | 0 .../btc/include/btc/btc_manage.h | 0 .../btc/include/btc/btc_task.h | 7 +- components/bt/common/include/bt_common.h | 158 ++ components/bt/common/include/bt_user_config.h | 83 + .../bt/{bluedroid => common}/osi/alarm.c | 14 +- .../bt/{bluedroid => common}/osi/allocator.c | 2 +- .../bt/{bluedroid => common}/osi/buffer.c | 4 +- .../bt/{bluedroid => common}/osi/config.c | 2 +- .../{bluedroid => common}/osi/fixed_queue.c | 2 - .../bt/{bluedroid => common}/osi/future.c | 3 +- .../osi/hash_functions.c | 0 .../bt/{bluedroid => common}/osi/hash_map.c | 3 +- .../osi/include/osi/alarm.h | 0 .../osi/include/osi/allocator.h | 0 .../osi/include/osi/buffer.h | 0 .../osi/include/osi/config.h | 0 .../osi/include/osi/fixed_queue.h | 0 .../osi/include/osi/future.h | 0 .../osi/include/osi/hash_functions.h | 0 .../osi/include/osi/hash_map.h | 0 .../osi/include/osi/list.h | 0 .../osi/include/osi/mutex.h | 0 .../osi/include/osi/osi.h | 0 .../osi/include/osi/semaphore.h | 0 .../osi/include/osi/thread.h | 4 +- .../bt/{bluedroid => common}/osi/list.c | 3 +- .../bt/{bluedroid => common}/osi/mutex.c | 0 components/bt/{bluedroid => common}/osi/osi.c | 0 .../bt/{bluedroid => common}/osi/semaphore.c | 0 .../bt/{bluedroid => common}/osi/thread.c | 0 components/bt/component.mk | 291 +-- components/bt/{ => controller}/bt.c | 0 components/bt/controller/lib | 1 + components/bt/esp_ble_mesh/Kconfig.in | 803 ++++++++ .../api/core/esp_ble_mesh_common_api.c | 0 .../esp_ble_mesh_local_data_operation_api.c | 0 .../api/core/esp_ble_mesh_low_power_api.c | 0 .../api/core/esp_ble_mesh_networking_api.c | 0 .../api/core/esp_ble_mesh_provisioning_api.c | 0 .../api/core/esp_ble_mesh_proxy_api.c | 0 .../core/include/esp_ble_mesh_common_api.h | 0 .../esp_ble_mesh_local_data_operation_api.h | 0 .../core/include/esp_ble_mesh_low_power_api.h | 0 .../include/esp_ble_mesh_networking_api.h | 0 .../include/esp_ble_mesh_provisioning_api.h | 0 .../api/core/include/esp_ble_mesh_proxy_api.h | 0 .../api/esp_ble_mesh_defs.h | 0 .../models/esp_ble_mesh_config_model_api.c | 0 .../models/esp_ble_mesh_generic_model_api.c | 0 .../models/esp_ble_mesh_health_model_api.c | 0 .../models/esp_ble_mesh_lighting_model_api.c | 0 .../models/esp_ble_mesh_sensor_model_api.c | 0 .../esp_ble_mesh_time_scene_model_api.c | 0 .../include/esp_ble_mesh_config_model_api.h | 0 .../include/esp_ble_mesh_generic_model_api.h | 0 .../include/esp_ble_mesh_health_model_api.h | 0 .../include/esp_ble_mesh_lighting_model_api.h | 0 .../include/esp_ble_mesh_sensor_model_api.h | 0 .../esp_ble_mesh_time_scene_model_api.h | 0 .../btc/btc_ble_mesh_config_model.c | 0 .../btc/btc_ble_mesh_generic_model.c | 0 .../btc/btc_ble_mesh_health_model.c | 0 .../btc/btc_ble_mesh_lighting_model.c | 0 .../btc/btc_ble_mesh_prov.c | 0 .../btc/btc_ble_mesh_sensor_model.c | 0 .../btc/btc_ble_mesh_time_scene_model.c | 0 .../btc/include/btc_ble_mesh_config_model.h | 0 .../btc/include/btc_ble_mesh_generic_model.h | 0 .../btc/include/btc_ble_mesh_health_model.h | 0 .../btc/include/btc_ble_mesh_lighting_model.h | 0 .../btc/include/btc_ble_mesh_prov.h | 0 .../btc/include/btc_ble_mesh_sensor_model.h | 0 .../include/btc_ble_mesh_time_scene_model.h | 0 .../mesh_core/access.c | 0 .../mesh_core/access.h | 0 .../mesh_core/adv.c | 0 .../mesh_core/adv.h | 0 .../mesh_core/beacon.c | 0 .../mesh_core/beacon.h | 0 .../mesh_core/cfg_cli.c | 0 .../mesh_core/cfg_srv.c | 0 .../mesh_core/crypto.c | 0 .../mesh_core/crypto.h | 0 .../mesh_core/foundation.h | 0 .../mesh_core/friend.c | 0 .../mesh_core/friend.h | 0 .../mesh_core/health_cli.c | 0 .../mesh_core/health_srv.c | 0 .../mesh_core/include/cfg_cli.h | 0 .../mesh_core/include/cfg_srv.h | 0 .../mesh_core/include/health_cli.h | 0 .../mesh_core/include/health_srv.h | 0 .../mesh_core/include/mesh_access.h | 0 .../mesh_core/include/mesh_aes_encrypt.h | 0 .../mesh_core/include/mesh_atomic.h | 0 .../mesh_core/include/mesh_bearer_adapt.h | 0 .../mesh_core/include/mesh_buf.h | 0 .../mesh_core/include/mesh_dlist.h | 0 .../mesh_core/include/mesh_hci.h | 0 .../mesh_core/include/mesh_kernel.h | 0 .../mesh_core/include/mesh_main.h | 0 .../mesh_core/include/mesh_proxy.h | 0 .../mesh_core/include/mesh_slist.h | 0 .../mesh_core/include/mesh_trace.h | 0 .../mesh_core/include/mesh_types.h | 0 .../mesh_core/include/mesh_util.h | 0 .../mesh_core/include/mesh_uuid.h | 0 .../mesh_core/lpn.c | 0 .../mesh_core/lpn.h | 0 .../mesh_core/mesh.h | 0 .../mesh_core/mesh_aes_encrypt.c | 0 .../mesh_core/mesh_atomic.c | 0 .../mesh_core/mesh_bearer_adapt.c | 0 .../mesh_core/mesh_buf.c | 0 .../mesh_core/mesh_hci.c | 0 .../mesh_core/mesh_kernel.c | 0 .../mesh_core/mesh_main.c | 0 .../mesh_core/mesh_util.c | 0 .../mesh_core/net.c | 0 .../mesh_core/net.h | 0 .../mesh_core/prov.c | 0 .../mesh_core/prov.h | 0 .../mesh_core/provisioner_beacon.c | 0 .../mesh_core/provisioner_beacon.h | 0 .../mesh_core/provisioner_main.c | 0 .../mesh_core/provisioner_main.h | 0 .../mesh_core/provisioner_prov.c | 0 .../mesh_core/provisioner_prov.h | 0 .../mesh_core/provisioner_proxy.c | 0 .../mesh_core/provisioner_proxy.h | 0 .../mesh_core/proxy.c | 0 .../mesh_core/proxy.h | 0 .../mesh_core/settings.c | 0 .../mesh_core/settings.h | 0 .../mesh_core/settings/settings_nvs.c | 0 .../mesh_core/settings/settings_nvs.h | 0 .../mesh_core/test.c | 0 .../mesh_core/test.h | 0 .../mesh_core/transport.c | 0 .../mesh_core/transport.h | 0 .../mesh_docs/BLE-Mesh_FAQs_EN.md | 0 .../mesh_docs/BLE-Mesh_Feature_List_EN.md | 0 .../mesh_docs/BLE-Mesh_Getting_Started_EN.md | 0 .../mesh_docs/BLE-Mesh_Known_Issues_EN.md | 0 .../mesh_docs/README.md | 0 .../mesh_models/generic_client.c | 0 .../mesh_models/include/generic_client.h | 0 .../mesh_models/include/lighting_client.h | 0 .../mesh_models/include/mesh_common.h | 0 .../mesh_models/include/model_common.h | 0 .../mesh_models/include/model_opcode.h | 0 .../mesh_models/include/sensor_client.h | 0 .../mesh_models/include/time_scene_client.h | 0 .../mesh_models/lighting_client.c | 0 .../mesh_models/mesh_common.c | 0 .../mesh_models/model_common.c | 0 .../mesh_models/sensor_client.c | 0 .../mesh_models/time_scene_client.c | 0 components/bt/host/bluedroid/Kconfig.in | 985 +++++++++ .../{ => host}/bluedroid/api/esp_a2dp_api.c | 0 .../{ => host}/bluedroid/api/esp_avrc_api.c | 0 .../{ => host}/bluedroid/api/esp_blufi_api.c | 0 .../{ => host}/bluedroid/api/esp_bt_device.c | 0 .../bt/{ => host}/bluedroid/api/esp_bt_main.c | 0 .../bluedroid/api/esp_gap_ble_api.c | 0 .../{ => host}/bluedroid/api/esp_gap_bt_api.c | 0 .../bluedroid/api/esp_gatt_common_api.c | 0 .../{ => host}/bluedroid/api/esp_gattc_api.c | 0 .../{ => host}/bluedroid/api/esp_gatts_api.c | 0 .../bluedroid/api/esp_hf_client_api.c | 0 .../bt/{ => host}/bluedroid/api/esp_spp_api.c | 0 .../bluedroid/api/include/api/esp_a2dp_api.h | 0 .../bluedroid/api/include/api/esp_avrc_api.h | 0 .../bluedroid/api/include/api/esp_blufi_api.h | 0 .../bluedroid/api/include/api/esp_bt_defs.h | 0 .../bluedroid/api/include/api/esp_bt_device.h | 0 .../bluedroid/api/include/api/esp_bt_main.h | 0 .../api/include/api/esp_gap_ble_api.h | 0 .../api/include/api/esp_gap_bt_api.h | 0 .../api/include/api/esp_gatt_common_api.h | 0 .../bluedroid/api/include/api/esp_gatt_defs.h | 0 .../bluedroid/api/include/api/esp_gattc_api.h | 0 .../bluedroid/api/include/api/esp_gatts_api.h | 0 .../api/include/api/esp_hf_client_api.h | 0 .../bluedroid/api/include/api/esp_hf_defs.h | 0 .../bluedroid/api/include/api/esp_spp_api.h | 0 .../bt/{ => host}/bluedroid/bta/ar/bta_ar.c | 0 .../bluedroid/bta/ar/include/bta_ar_int.h | 0 .../{ => host}/bluedroid/bta/av/bta_av_aact.c | 0 .../{ => host}/bluedroid/bta/av/bta_av_act.c | 0 .../{ => host}/bluedroid/bta/av/bta_av_api.c | 0 .../{ => host}/bluedroid/bta/av/bta_av_cfg.c | 0 .../{ => host}/bluedroid/bta/av/bta_av_ci.c | 0 .../{ => host}/bluedroid/bta/av/bta_av_main.c | 0 .../{ => host}/bluedroid/bta/av/bta_av_sbc.c | 0 .../{ => host}/bluedroid/bta/av/bta_av_ssm.c | 0 .../bluedroid/bta/av/include/bta_av_int.h | 0 .../{ => host}/bluedroid/bta/dm/bta_dm_act.c | 0 .../{ => host}/bluedroid/bta/dm/bta_dm_api.c | 0 .../{ => host}/bluedroid/bta/dm/bta_dm_cfg.c | 0 .../{ => host}/bluedroid/bta/dm/bta_dm_ci.c | 0 .../{ => host}/bluedroid/bta/dm/bta_dm_co.c | 0 .../{ => host}/bluedroid/bta/dm/bta_dm_main.c | 0 .../{ => host}/bluedroid/bta/dm/bta_dm_pm.c | 0 .../{ => host}/bluedroid/bta/dm/bta_dm_sco.c | 0 .../bluedroid/bta/dm/include/bta_dm_int.h | 0 .../bluedroid/bta/gatt/bta_gatt_common.c | 0 .../bluedroid/bta/gatt/bta_gattc_act.c | 0 .../bluedroid/bta/gatt/bta_gattc_api.c | 0 .../bluedroid/bta/gatt/bta_gattc_cache.c | 0 .../bluedroid/bta/gatt/bta_gattc_ci.c | 0 .../bluedroid/bta/gatt/bta_gattc_co.c | 0 .../bluedroid/bta/gatt/bta_gattc_main.c | 0 .../bluedroid/bta/gatt/bta_gattc_utils.c | 0 .../bluedroid/bta/gatt/bta_gatts_act.c | 0 .../bluedroid/bta/gatt/bta_gatts_api.c | 0 .../bluedroid/bta/gatt/bta_gatts_co.c | 0 .../bluedroid/bta/gatt/bta_gatts_main.c | 0 .../bluedroid/bta/gatt/bta_gatts_utils.c | 0 .../bta/gatt/include/bta_gattc_int.h | 0 .../bta/gatt/include/bta_gatts_int.h | 0 .../bta/hf_client/bta_hf_client_act.c | 0 .../bta/hf_client/bta_hf_client_api.c | 0 .../bta/hf_client/bta_hf_client_at.c | 0 .../bta/hf_client/bta_hf_client_cmd.c | 0 .../bta/hf_client/bta_hf_client_main.c | 0 .../bta/hf_client/bta_hf_client_rfc.c | 0 .../bta/hf_client/bta_hf_client_sco.c | 0 .../bta/hf_client/bta_hf_client_sdp.c | 0 .../bta/hf_client/include/bta_hf_client_at.h | 0 .../bta/hf_client/include/bta_hf_client_int.h | 0 .../{ => host}/bluedroid/bta/hh/bta_hh_act.c | 0 .../{ => host}/bluedroid/bta/hh/bta_hh_api.c | 0 .../{ => host}/bluedroid/bta/hh/bta_hh_cfg.c | 0 .../{ => host}/bluedroid/bta/hh/bta_hh_le.c | 0 .../{ => host}/bluedroid/bta/hh/bta_hh_main.c | 0 .../bluedroid/bta/hh/bta_hh_utils.c | 0 .../bluedroid/bta/hh/include/bta_hh_int.h | 0 .../bluedroid/bta/include/bta/bta_api.h | 0 .../bluedroid/bta/include/bta/bta_ar_api.h | 0 .../bluedroid/bta/include/bta/bta_av_api.h | 0 .../bluedroid/bta/include/bta/bta_av_ci.h | 0 .../bluedroid/bta/include/bta/bta_av_co.h | 0 .../bluedroid/bta/include/bta/bta_av_sbc.h | 0 .../bluedroid/bta/include/bta/bta_dm_ci.h | 0 .../bluedroid/bta/include/bta/bta_dm_co.h | 0 .../bluedroid/bta/include/bta/bta_gap_bt_co.h | 0 .../bluedroid/bta/include/bta/bta_gatt_api.h | 0 .../bta/include/bta/bta_gatt_common.h | 0 .../bluedroid/bta/include/bta/bta_gattc_ci.h | 0 .../bluedroid/bta/include/bta/bta_gattc_co.h | 0 .../bluedroid/bta/include/bta/bta_gatts_co.h | 0 .../bta/include/bta/bta_hf_client_api.h | 0 .../bta/include/bta/bta_hf_client_co.h | 0 .../bluedroid/bta/include/bta/bta_hfp_defs.h | 0 .../bluedroid/bta/include/bta/bta_hh_api.h | 0 .../bluedroid/bta/include/bta/bta_hh_co.h | 0 .../bluedroid/bta/include/bta/bta_jv_api.h | 0 .../bluedroid/bta/include/bta/bta_jv_co.h | 0 .../bluedroid/bta/include/bta/bta_sdp_api.h | 0 .../bluedroid/bta/include/bta/bta_sys.h | 0 .../bluedroid/bta/include/bta/utl.h | 0 .../{ => host}/bluedroid/bta/jv/bta_jv_act.c | 0 .../{ => host}/bluedroid/bta/jv/bta_jv_api.c | 0 .../{ => host}/bluedroid/bta/jv/bta_jv_cfg.c | 0 .../{ => host}/bluedroid/bta/jv/bta_jv_main.c | 0 .../bluedroid/bta/jv/include/bta_jv_int.h | 0 .../bt/{ => host}/bluedroid/bta/sdp/bta_sdp.c | 0 .../bluedroid/bta/sdp/bta_sdp_act.c | 0 .../bluedroid/bta/sdp/bta_sdp_api.c | 0 .../bluedroid/bta/sdp/bta_sdp_cfg.c | 0 .../bluedroid/bta/sdp/include/bta_sdp_int.h | 0 .../bluedroid/bta/sys/bta_sys_conn.c | 0 .../bluedroid/bta/sys/bta_sys_main.c | 0 .../bluedroid/bta/sys/include/bta_sys_int.h | 0 .../bt/{ => host}/bluedroid/bta/sys/utl.c | 0 .../bluedroid/btc/core/btc_ble_storage.c | 0 .../bluedroid/btc/core/btc_config.c | 0 .../{ => host}/bluedroid/btc/core/btc_dev.c | 0 .../bt/{ => host}/bluedroid/btc/core/btc_dm.c | 0 .../{ => host}/bluedroid/btc/core/btc_main.c | 0 .../bluedroid/btc/core/btc_profile_queue.c | 0 .../{ => host}/bluedroid/btc/core/btc_sec.c | 0 .../bt/{ => host}/bluedroid/btc/core/btc_sm.c | 0 .../bluedroid/btc/core/btc_storage.c | 0 .../{ => host}/bluedroid/btc/core/btc_util.c | 0 .../btc/include/btc/btc_ble_storage.h | 0 .../bluedroid/btc/include/btc/btc_common.h | 0 .../bluedroid/btc/include/btc/btc_config.h | 0 .../bluedroid/btc/include/btc/btc_dev.h | 0 .../bluedroid/btc/include/btc/btc_dm.h | 0 .../bluedroid/btc/include/btc/btc_main.h | 0 .../btc/include/btc/btc_profile_queue.h | 0 .../bluedroid/btc/include/btc/btc_sm.h | 0 .../bluedroid/btc/include/btc/btc_storage.h | 0 .../bluedroid/btc/include/btc/btc_util.h | 0 .../btc/profile/esp/ble_button/button_pro.c | 0 .../btc/profile/esp/blufi/blufi_prf.c | 0 .../btc/profile/esp/blufi/blufi_protocol.c | 0 .../btc/profile/esp/blufi/include/blufi_int.h | 0 .../btc/profile/esp/include/btc_blufi_prf.h | 0 .../btc/profile/esp/include/button_pro.h | 0 .../btc/profile/esp/include/wx_airsync_prf.h | 0 .../esp/wechat_AirSync/wx_airsync_prf.c | 0 .../btc/profile/std/a2dp/bta_av_co.c | 0 .../bluedroid/btc/profile/std/a2dp/btc_a2dp.c | 0 .../btc/profile/std/a2dp/btc_a2dp_control.c | 0 .../btc/profile/std/a2dp/btc_a2dp_sink.c | 0 .../btc/profile/std/a2dp/btc_a2dp_source.c | 0 .../bluedroid/btc/profile/std/a2dp/btc_av.c | 0 .../btc/profile/std/a2dp/include/btc_av_co.h | 0 .../btc/profile/std/avrc/bta_avrc_co.c | 0 .../bluedroid/btc/profile/std/avrc/btc_avrc.c | 0 .../btc/profile/std/battery/battery_prf.c | 0 .../std/battery/include/srvc_battery_int.h | 0 .../btc/profile/std/dis/dis_profile.c | 0 .../profile/std/dis/include/srvc_dis_int.h | 0 .../btc/profile/std/gap/bta_gap_bt_co.c | 0 .../btc/profile/std/gap/btc_gap_ble.c | 0 .../btc/profile/std/gap/btc_gap_bt.c | 0 .../btc/profile/std/gatt/btc_gatt_common.c | 0 .../btc/profile/std/gatt/btc_gatt_util.c | 0 .../btc/profile/std/gatt/btc_gattc.c | 0 .../btc/profile/std/gatt/btc_gatts.c | 0 .../profile/std/hf_client/bta_hf_client_co.c | 0 .../btc/profile/std/hf_client/btc_hf_client.c | 0 .../btc/profile/std/hid/include/hid_conn.h | 0 .../btc/profile/std/hid/include/hidh_int.h | 0 .../btc/profile/std/include/bt_sdp.h | 0 .../btc/profile/std/include/btc_a2dp.h | 0 .../profile/std/include/btc_a2dp_control.h | 0 .../btc/profile/std/include/btc_a2dp_sink.h | 0 .../btc/profile/std/include/btc_a2dp_source.h | 0 .../btc/profile/std/include/btc_av.h | 0 .../btc/profile/std/include/btc_av_api.h | 0 .../btc/profile/std/include/btc_avrc.h | 0 .../btc/profile/std/include/btc_gap_ble.h | 0 .../btc/profile/std/include/btc_gap_bt.h | 1 + .../btc/profile/std/include/btc_gatt_common.h | 0 .../btc/profile/std/include/btc_gatt_util.h | 0 .../btc/profile/std/include/btc_gattc.h | 0 .../btc/profile/std/include/btc_gatts.h | 0 .../btc/profile/std/include/btc_hf_client.h | 0 .../btc/profile/std/include/btc_spp.h | 0 .../btc/profile/std/include/dis_api.h | 0 .../btc/profile/std/include/srvc_api.h | 0 .../btc/profile/std/smp/esp_app_sec.c | 0 .../btc/profile/std/smp/include/esp_sec_api.h | 0 .../bluedroid/btc/profile/std/spp/btc_spp.c | 0 .../include/common/bluedroid_user_config.h} | 68 +- .../common/include/common/bt_common_types.h | 0 .../bluedroid/common/include/common/bt_defs.h | 28 +- .../common/include/common/bt_target.h | 11 +- .../common/include/common/bt_trace.h | 69 +- .../common/include/common/bt_vendor_lib.h | 0 .../bluedroid/common/include/common/bte.h | 0 .../common/include/common/bte_appl.h | 0 .../bt/{ => host}/bluedroid/device/bdaddr.c | 0 .../{ => host}/bluedroid/device/controller.c | 2 +- .../bluedroid/device/include/device/bdaddr.h | 0 .../device/include/device/controller.h | 0 .../device/include/device/device_features.h | 0 .../device/include/device/event_mask.h | 0 .../bluedroid/device/include/device/interop.h | 0 .../device/include/device/interop_database.h | 0 .../bluedroid/device/include/device/version.h | 0 .../bt/{ => host}/bluedroid/device/interop.c | 0 .../external/sbc/decoder/include/oi_assert.h | 0 .../sbc/decoder/include/oi_bitstream.h | 0 .../external/sbc/decoder/include/oi_bt_spec.h | 0 .../sbc/decoder/include/oi_codec_sbc.h | 0 .../decoder/include/oi_codec_sbc_private.h | 0 .../external/sbc/decoder/include/oi_common.h | 0 .../external/sbc/decoder/include/oi_cpu_dep.h | 0 .../external/sbc/decoder/include/oi_modules.h | 0 .../sbc/decoder/include/oi_osinterface.h | 0 .../external/sbc/decoder/include/oi_status.h | 0 .../external/sbc/decoder/include/oi_stddefs.h | 0 .../external/sbc/decoder/include/oi_string.h | 0 .../external/sbc/decoder/include/oi_time.h | 0 .../external/sbc/decoder/include/oi_utils.h | 0 .../external/sbc/decoder/srce/alloc.c | 0 .../external/sbc/decoder/srce/bitalloc-sbc.c | 0 .../external/sbc/decoder/srce/bitalloc.c | 0 .../sbc/decoder/srce/bitstream-decode.c | 0 .../external/sbc/decoder/srce/decoder-oina.c | 0 .../sbc/decoder/srce/decoder-private.c | 0 .../external/sbc/decoder/srce/decoder-sbc.c | 0 .../external/sbc/decoder/srce/dequant.c | 0 .../external/sbc/decoder/srce/framing-sbc.c | 0 .../external/sbc/decoder/srce/framing.c | 0 .../sbc/decoder/srce/oi_codec_version.c | 0 .../sbc/decoder/srce/readsamplesjoint.inc | 0 .../sbc/decoder/srce/synthesis-8-generated.c | 0 .../sbc/decoder/srce/synthesis-dct8.c | 0 .../external/sbc/decoder/srce/synthesis-sbc.c | 0 .../external/sbc/encoder/include/sbc_dct.h | 0 .../encoder/include/sbc_enc_func_declare.h | 0 .../sbc/encoder/include/sbc_encoder.h | 0 .../external/sbc/encoder/include/sbc_if.h | 0 .../external/sbc/encoder/include/sbc_types.h | 0 .../external/sbc/encoder/srce/sbc_analysis.c | 0 .../external/sbc/encoder/srce/sbc_dct.c | 0 .../sbc/encoder/srce/sbc_dct_coeffs.c | 0 .../sbc/encoder/srce/sbc_enc_bit_alloc_mono.c | 0 .../sbc/encoder/srce/sbc_enc_bit_alloc_ste.c | 0 .../sbc/encoder/srce/sbc_enc_coeffs.c | 0 .../external/sbc/encoder/srce/sbc_encoder.c | 0 .../external/sbc/encoder/srce/sbc_packing.c | 0 .../external/sbc/plc/include/sbc_plc.h | 0 .../bluedroid/external/sbc/plc/sbc_plc.c | 0 .../bt/{ => host}/bluedroid/hci/hci_audio.c | 0 .../bt/{ => host}/bluedroid/hci/hci_hal_h4.c | 0 .../bt/{ => host}/bluedroid/hci/hci_layer.c | 0 .../bluedroid/hci/hci_packet_factory.c | 0 .../bluedroid/hci/hci_packet_parser.c | 0 .../bluedroid/hci/include/hci/bt_vendor_lib.h | 0 .../bluedroid/hci/include/hci/hci_audio.h | 0 .../bluedroid/hci/include/hci/hci_hal.h | 0 .../bluedroid/hci/include/hci/hci_internals.h | 0 .../bluedroid/hci/include/hci/hci_layer.h | 0 .../hci/include/hci/hci_packet_factory.h | 0 .../hci/include/hci/hci_packet_parser.h | 0 .../hci/include/hci/packet_fragmenter.h | 0 .../bluedroid/hci/packet_fragmenter.c | 0 .../bt/{ => host}/bluedroid/main/bte_init.c | 0 .../bt/{ => host}/bluedroid/main/bte_main.c | 0 .../{ => host}/bluedroid/stack/a2dp/a2d_api.c | 0 .../{ => host}/bluedroid/stack/a2dp/a2d_sbc.c | 0 .../bluedroid/stack/a2dp/include/a2d_int.h | 0 .../bluedroid/stack/avct/avct_api.c | 0 .../bluedroid/stack/avct/avct_ccb.c | 0 .../bluedroid/stack/avct/avct_l2c.c | 0 .../bluedroid/stack/avct/avct_lcb.c | 0 .../bluedroid/stack/avct/avct_lcb_act.c | 0 .../bluedroid/stack/avct/include/avct_defs.h | 0 .../bluedroid/stack/avct/include/avct_int.h | 0 .../{ => host}/bluedroid/stack/avdt/avdt_ad.c | 0 .../bluedroid/stack/avdt/avdt_api.c | 0 .../bluedroid/stack/avdt/avdt_ccb.c | 0 .../bluedroid/stack/avdt/avdt_ccb_act.c | 0 .../bluedroid/stack/avdt/avdt_l2c.c | 0 .../bluedroid/stack/avdt/avdt_msg.c | 0 .../bluedroid/stack/avdt/avdt_scb.c | 0 .../bluedroid/stack/avdt/avdt_scb_act.c | 0 .../bluedroid/stack/avdt/include/avdt_defs.h | 0 .../bluedroid/stack/avdt/include/avdt_int.h | 0 .../bluedroid/stack/avrc/avrc_api.c | 0 .../bluedroid/stack/avrc/avrc_bld_ct.c | 0 .../bluedroid/stack/avrc/avrc_bld_tg.c | 0 .../bluedroid/stack/avrc/avrc_opt.c | 0 .../bluedroid/stack/avrc/avrc_pars_ct.c | 0 .../bluedroid/stack/avrc/avrc_pars_tg.c | 0 .../bluedroid/stack/avrc/avrc_sdp.c | 0 .../bluedroid/stack/avrc/avrc_utils.c | 0 .../bluedroid/stack/avrc/include/avrc_int.h | 0 .../{ => host}/bluedroid/stack/btm/btm_acl.c | 0 .../{ => host}/bluedroid/stack/btm/btm_ble.c | 0 .../bluedroid/stack/btm/btm_ble_addr.c | 0 .../bluedroid/stack/btm/btm_ble_adv_filter.c | 0 .../bluedroid/stack/btm/btm_ble_batchscan.c | 0 .../bluedroid/stack/btm/btm_ble_bgconn.c | 0 .../bluedroid/stack/btm/btm_ble_cont_energy.c | 0 .../bluedroid/stack/btm/btm_ble_gap.c | 0 .../bluedroid/stack/btm/btm_ble_multi_adv.c | 0 .../bluedroid/stack/btm/btm_ble_privacy.c | 0 .../{ => host}/bluedroid/stack/btm/btm_dev.c | 0 .../bluedroid/stack/btm/btm_devctl.c | 0 .../{ => host}/bluedroid/stack/btm/btm_inq.c | 0 .../{ => host}/bluedroid/stack/btm/btm_main.c | 0 .../{ => host}/bluedroid/stack/btm/btm_pm.c | 0 .../{ => host}/bluedroid/stack/btm/btm_sco.c | 0 .../{ => host}/bluedroid/stack/btm/btm_sec.c | 0 .../bluedroid/stack/btm/include/btm_ble_int.h | 0 .../bluedroid/stack/btm/include/btm_int.h | 0 .../{ => host}/bluedroid/stack/btu/btu_hcif.c | 0 .../{ => host}/bluedroid/stack/btu/btu_init.c | 2 +- .../{ => host}/bluedroid/stack/btu/btu_task.c | 0 .../{ => host}/bluedroid/stack/gap/gap_api.c | 0 .../{ => host}/bluedroid/stack/gap/gap_ble.c | 0 .../{ => host}/bluedroid/stack/gap/gap_conn.c | 0 .../bluedroid/stack/gap/gap_utils.c | 0 .../bluedroid/stack/gap/include/gap_int.h | 0 .../bluedroid/stack/gatt/att_protocol.c | 0 .../bluedroid/stack/gatt/gatt_api.c | 0 .../bluedroid/stack/gatt/gatt_attr.c | 0 .../bluedroid/stack/gatt/gatt_auth.c | 0 .../{ => host}/bluedroid/stack/gatt/gatt_cl.c | 0 .../{ => host}/bluedroid/stack/gatt/gatt_db.c | 0 .../bluedroid/stack/gatt/gatt_main.c | 0 .../{ => host}/bluedroid/stack/gatt/gatt_sr.c | 0 .../bluedroid/stack/gatt/gatt_utils.c | 0 .../bluedroid/stack/gatt/include/gatt_int.h | 0 .../bluedroid/stack/hcic/hciblecmds.c | 0 .../{ => host}/bluedroid/stack/hcic/hcicmds.c | 0 .../bluedroid/stack/include/stack/a2d_api.h | 0 .../bluedroid/stack/include/stack/a2d_sbc.h | 0 .../bluedroid/stack/include/stack/avct_api.h | 0 .../bluedroid/stack/include/stack/avdt_api.h | 0 .../bluedroid/stack/include/stack/avdtc_api.h | 0 .../bluedroid/stack/include/stack/avrc_api.h | 0 .../bluedroid/stack/include/stack/avrc_defs.h | 0 .../bluedroid/stack/include/stack/bt_types.h | 22 +- .../bluedroid/stack/include/stack/btm_api.h | 0 .../stack/include/stack/btm_ble_api.h | 0 .../bluedroid/stack/include/stack/btu.h | 0 .../bluedroid/stack/include/stack/dyn_mem.h | 9 +- .../bluedroid/stack/include/stack/gap_api.h | 0 .../bluedroid/stack/include/stack/gatt_api.h | 0 .../bluedroid/stack/include/stack/gattdefs.h | 0 .../bluedroid/stack/include/stack/hcidefs.h | 0 .../bluedroid/stack/include/stack/hcimsgs.h | 0 .../bluedroid/stack/include/stack/hiddefs.h | 0 .../bluedroid/stack/include/stack/hidh_api.h | 0 .../bluedroid/stack/include/stack/l2c_api.h | 0 .../stack/include/stack/l2cap_client.h | 0 .../bluedroid/stack/include/stack/l2cdefs.h | 0 .../bluedroid/stack/include/stack/port_api.h | 0 .../bluedroid/stack/include/stack/port_ext.h | 0 .../stack/include/stack/profiles_api.h | 0 .../bluedroid/stack/include/stack/rfcdefs.h | 0 .../bluedroid/stack/include/stack/sdp_api.h | 0 .../bluedroid/stack/include/stack/sdpdefs.h | 0 .../bluedroid/stack/include/stack/smp_api.h | 0 .../bluedroid/stack/l2cap/include/l2c_int.h | 0 .../bluedroid/stack/l2cap/l2c_api.c | 0 .../bluedroid/stack/l2cap/l2c_ble.c | 0 .../bluedroid/stack/l2cap/l2c_csm.c | 0 .../bluedroid/stack/l2cap/l2c_fcr.c | 0 .../bluedroid/stack/l2cap/l2c_link.c | 0 .../bluedroid/stack/l2cap/l2c_main.c | 0 .../bluedroid/stack/l2cap/l2c_ucd.c | 0 .../bluedroid/stack/l2cap/l2c_utils.c | 0 .../bluedroid/stack/l2cap/l2cap_client.c | 0 .../bluedroid/stack/rfcomm/include/port_int.h | 0 .../bluedroid/stack/rfcomm/include/rfc_int.h | 0 .../bluedroid/stack/rfcomm/port_api.c | 0 .../bluedroid/stack/rfcomm/port_rfc.c | 0 .../bluedroid/stack/rfcomm/port_utils.c | 0 .../bluedroid/stack/rfcomm/rfc_l2cap_if.c | 0 .../bluedroid/stack/rfcomm/rfc_mx_fsm.c | 0 .../bluedroid/stack/rfcomm/rfc_port_fsm.c | 0 .../bluedroid/stack/rfcomm/rfc_port_if.c | 0 .../bluedroid/stack/rfcomm/rfc_ts_frames.c | 0 .../bluedroid/stack/rfcomm/rfc_utils.c | 0 .../bluedroid/stack/sdp/include/sdpint.h | 0 .../{ => host}/bluedroid/stack/sdp/sdp_api.c | 0 .../{ => host}/bluedroid/stack/sdp/sdp_db.c | 0 .../bluedroid/stack/sdp/sdp_discovery.c | 0 .../{ => host}/bluedroid/stack/sdp/sdp_main.c | 0 .../bluedroid/stack/sdp/sdp_server.c | 0 .../bluedroid/stack/sdp/sdp_utils.c | 0 .../bt/{ => host}/bluedroid/stack/smp/aes.c | 0 .../bluedroid/stack/smp/include/aes.h | 0 .../stack/smp/include/p_256_ecc_pp.h | 0 .../stack/smp/include/p_256_multprecision.h | 0 .../bluedroid/stack/smp/include/smp_int.h | 0 .../bluedroid/stack/smp/p_256_curvepara.c | 0 .../bluedroid/stack/smp/p_256_ecc_pp.c | 0 .../bluedroid/stack/smp/p_256_multprecision.c | 0 .../{ => host}/bluedroid/stack/smp/smp_act.c | 0 .../{ => host}/bluedroid/stack/smp/smp_api.c | 0 .../bluedroid/stack/smp/smp_br_main.c | 0 .../{ => host}/bluedroid/stack/smp/smp_cmac.c | 0 .../{ => host}/bluedroid/stack/smp/smp_keys.c | 0 .../{ => host}/bluedroid/stack/smp/smp_l2c.c | 0 .../{ => host}/bluedroid/stack/smp/smp_main.c | 0 .../bluedroid/stack/smp/smp_utils.c | 0 components/{ => bt/host}/nimble/Kconfig.in | 0 .../nimble/esp-hci/include/esp_nimble_hci.h | 0 .../host}/nimble/esp-hci/src/esp_nimble_hci.c | 0 components/{ => bt/host}/nimble/nimble | 0 .../nimble/port/include/console/console.h | 0 .../nimble/port/include/esp_nimble_cfg.h | 0 components/bt/lib | 1 - components/nimble/CMakeLists.txt | 142 -- components/nimble/component.mk | 47 - docs/Doxyfile | 30 +- .../bluetooth/nimble/blemesh/CMakeLists.txt | 2 +- examples/bluetooth/nimble/blemesh/Makefile | 2 +- 587 files changed, 2756 insertions(+), 2700 deletions(-) rename components/bt/{bluedroid => common}/btc/core/btc_alarm.c (97%) rename components/bt/{bluedroid => common}/btc/core/btc_manage.c (94%) rename components/bt/{bluedroid => common}/btc/core/btc_task.c (98%) rename components/bt/{bluedroid => common}/btc/include/btc/btc_alarm.h (100%) rename components/bt/{bluedroid => common}/btc/include/btc/btc_manage.h (100%) rename components/bt/{bluedroid => common}/btc/include/btc/btc_task.h (97%) create mode 100644 components/bt/common/include/bt_common.h create mode 100644 components/bt/common/include/bt_user_config.h rename components/bt/{bluedroid => common}/osi/alarm.c (97%) rename components/bt/{bluedroid => common}/osi/allocator.c (99%) rename components/bt/{bluedroid => common}/osi/buffer.c (96%) rename components/bt/{bluedroid => common}/osi/config.c (99%) rename components/bt/{bluedroid => common}/osi/fixed_queue.c (98%) rename components/bt/{bluedroid => common}/osi/future.c (98%) rename components/bt/{bluedroid => common}/osi/hash_functions.c (100%) rename components/bt/{bluedroid => common}/osi/hash_map.c (99%) rename components/bt/{bluedroid => common}/osi/include/osi/alarm.h (100%) rename components/bt/{bluedroid => common}/osi/include/osi/allocator.h (100%) rename components/bt/{bluedroid => common}/osi/include/osi/buffer.h (100%) rename components/bt/{bluedroid => common}/osi/include/osi/config.h (100%) rename components/bt/{bluedroid => common}/osi/include/osi/fixed_queue.h (100%) rename components/bt/{bluedroid => common}/osi/include/osi/future.h (100%) rename components/bt/{bluedroid => common}/osi/include/osi/hash_functions.h (100%) rename components/bt/{bluedroid => common}/osi/include/osi/hash_map.h (100%) rename components/bt/{bluedroid => common}/osi/include/osi/list.h (100%) rename components/bt/{bluedroid => common}/osi/include/osi/mutex.h (100%) rename components/bt/{bluedroid => common}/osi/include/osi/osi.h (100%) rename components/bt/{bluedroid => common}/osi/include/osi/semaphore.h (100%) rename components/bt/{bluedroid => common}/osi/include/osi/thread.h (99%) rename components/bt/{bluedroid => common}/osi/list.c (99%) rename components/bt/{bluedroid => common}/osi/mutex.c (100%) rename components/bt/{bluedroid => common}/osi/osi.c (100%) rename components/bt/{bluedroid => common}/osi/semaphore.c (100%) rename components/bt/{bluedroid => common}/osi/thread.c (100%) rename components/bt/{ => controller}/bt.c (100%) create mode 160000 components/bt/controller/lib create mode 100644 components/bt/esp_ble_mesh/Kconfig.in rename components/bt/{ble_mesh => esp_ble_mesh}/api/core/esp_ble_mesh_common_api.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/core/esp_ble_mesh_local_data_operation_api.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/core/esp_ble_mesh_low_power_api.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/core/esp_ble_mesh_networking_api.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/core/esp_ble_mesh_provisioning_api.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/core/esp_ble_mesh_proxy_api.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/core/include/esp_ble_mesh_common_api.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/core/include/esp_ble_mesh_local_data_operation_api.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/core/include/esp_ble_mesh_low_power_api.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/core/include/esp_ble_mesh_networking_api.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/core/include/esp_ble_mesh_provisioning_api.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/core/include/esp_ble_mesh_proxy_api.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/esp_ble_mesh_defs.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/models/esp_ble_mesh_config_model_api.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/models/esp_ble_mesh_generic_model_api.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/models/esp_ble_mesh_health_model_api.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/models/esp_ble_mesh_lighting_model_api.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/models/esp_ble_mesh_sensor_model_api.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/models/esp_ble_mesh_time_scene_model_api.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/models/include/esp_ble_mesh_config_model_api.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/models/include/esp_ble_mesh_generic_model_api.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/models/include/esp_ble_mesh_health_model_api.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/models/include/esp_ble_mesh_lighting_model_api.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/models/include/esp_ble_mesh_sensor_model_api.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/api/models/include/esp_ble_mesh_time_scene_model_api.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/btc/btc_ble_mesh_config_model.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/btc/btc_ble_mesh_generic_model.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/btc/btc_ble_mesh_health_model.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/btc/btc_ble_mesh_lighting_model.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/btc/btc_ble_mesh_prov.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/btc/btc_ble_mesh_sensor_model.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/btc/btc_ble_mesh_time_scene_model.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/btc/include/btc_ble_mesh_config_model.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/btc/include/btc_ble_mesh_generic_model.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/btc/include/btc_ble_mesh_health_model.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/btc/include/btc_ble_mesh_lighting_model.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/btc/include/btc_ble_mesh_prov.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/btc/include/btc_ble_mesh_sensor_model.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/btc/include/btc_ble_mesh_time_scene_model.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/access.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/access.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/adv.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/adv.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/beacon.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/beacon.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/cfg_cli.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/cfg_srv.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/crypto.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/crypto.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/foundation.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/friend.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/friend.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/health_cli.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/health_srv.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/include/cfg_cli.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/include/cfg_srv.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/include/health_cli.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/include/health_srv.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/include/mesh_access.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/include/mesh_aes_encrypt.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/include/mesh_atomic.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/include/mesh_bearer_adapt.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/include/mesh_buf.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/include/mesh_dlist.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/include/mesh_hci.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/include/mesh_kernel.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/include/mesh_main.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/include/mesh_proxy.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/include/mesh_slist.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/include/mesh_trace.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/include/mesh_types.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/include/mesh_util.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/include/mesh_uuid.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/lpn.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/lpn.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/mesh.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/mesh_aes_encrypt.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/mesh_atomic.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/mesh_bearer_adapt.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/mesh_buf.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/mesh_hci.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/mesh_kernel.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/mesh_main.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/mesh_util.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/net.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/net.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/prov.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/prov.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/provisioner_beacon.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/provisioner_beacon.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/provisioner_main.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/provisioner_main.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/provisioner_prov.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/provisioner_prov.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/provisioner_proxy.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/provisioner_proxy.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/proxy.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/proxy.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/settings.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/settings.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/settings/settings_nvs.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/settings/settings_nvs.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/test.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/test.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/transport.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_core/transport.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_docs/BLE-Mesh_FAQs_EN.md (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_docs/BLE-Mesh_Feature_List_EN.md (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_docs/BLE-Mesh_Getting_Started_EN.md (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_docs/BLE-Mesh_Known_Issues_EN.md (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_docs/README.md (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_models/generic_client.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_models/include/generic_client.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_models/include/lighting_client.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_models/include/mesh_common.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_models/include/model_common.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_models/include/model_opcode.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_models/include/sensor_client.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_models/include/time_scene_client.h (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_models/lighting_client.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_models/mesh_common.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_models/model_common.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_models/sensor_client.c (100%) rename components/bt/{ble_mesh => esp_ble_mesh}/mesh_models/time_scene_client.c (100%) create mode 100644 components/bt/host/bluedroid/Kconfig.in rename components/bt/{ => host}/bluedroid/api/esp_a2dp_api.c (100%) rename components/bt/{ => host}/bluedroid/api/esp_avrc_api.c (100%) rename components/bt/{ => host}/bluedroid/api/esp_blufi_api.c (100%) rename components/bt/{ => host}/bluedroid/api/esp_bt_device.c (100%) rename components/bt/{ => host}/bluedroid/api/esp_bt_main.c (100%) rename components/bt/{ => host}/bluedroid/api/esp_gap_ble_api.c (100%) rename components/bt/{ => host}/bluedroid/api/esp_gap_bt_api.c (100%) rename components/bt/{ => host}/bluedroid/api/esp_gatt_common_api.c (100%) rename components/bt/{ => host}/bluedroid/api/esp_gattc_api.c (100%) rename components/bt/{ => host}/bluedroid/api/esp_gatts_api.c (100%) rename components/bt/{ => host}/bluedroid/api/esp_hf_client_api.c (100%) rename components/bt/{ => host}/bluedroid/api/esp_spp_api.c (100%) rename components/bt/{ => host}/bluedroid/api/include/api/esp_a2dp_api.h (100%) rename components/bt/{ => host}/bluedroid/api/include/api/esp_avrc_api.h (100%) rename components/bt/{ => host}/bluedroid/api/include/api/esp_blufi_api.h (100%) rename components/bt/{ => host}/bluedroid/api/include/api/esp_bt_defs.h (100%) rename components/bt/{ => host}/bluedroid/api/include/api/esp_bt_device.h (100%) rename components/bt/{ => host}/bluedroid/api/include/api/esp_bt_main.h (100%) rename components/bt/{ => host}/bluedroid/api/include/api/esp_gap_ble_api.h (100%) rename components/bt/{ => host}/bluedroid/api/include/api/esp_gap_bt_api.h (100%) rename components/bt/{ => host}/bluedroid/api/include/api/esp_gatt_common_api.h (100%) rename components/bt/{ => host}/bluedroid/api/include/api/esp_gatt_defs.h (100%) rename components/bt/{ => host}/bluedroid/api/include/api/esp_gattc_api.h (100%) rename components/bt/{ => host}/bluedroid/api/include/api/esp_gatts_api.h (100%) rename components/bt/{ => host}/bluedroid/api/include/api/esp_hf_client_api.h (100%) rename components/bt/{ => host}/bluedroid/api/include/api/esp_hf_defs.h (100%) rename components/bt/{ => host}/bluedroid/api/include/api/esp_spp_api.h (100%) rename components/bt/{ => host}/bluedroid/bta/ar/bta_ar.c (100%) rename components/bt/{ => host}/bluedroid/bta/ar/include/bta_ar_int.h (100%) rename components/bt/{ => host}/bluedroid/bta/av/bta_av_aact.c (100%) rename components/bt/{ => host}/bluedroid/bta/av/bta_av_act.c (100%) rename components/bt/{ => host}/bluedroid/bta/av/bta_av_api.c (100%) rename components/bt/{ => host}/bluedroid/bta/av/bta_av_cfg.c (100%) rename components/bt/{ => host}/bluedroid/bta/av/bta_av_ci.c (100%) rename components/bt/{ => host}/bluedroid/bta/av/bta_av_main.c (100%) rename components/bt/{ => host}/bluedroid/bta/av/bta_av_sbc.c (100%) rename components/bt/{ => host}/bluedroid/bta/av/bta_av_ssm.c (100%) rename components/bt/{ => host}/bluedroid/bta/av/include/bta_av_int.h (100%) rename components/bt/{ => host}/bluedroid/bta/dm/bta_dm_act.c (100%) rename components/bt/{ => host}/bluedroid/bta/dm/bta_dm_api.c (100%) rename components/bt/{ => host}/bluedroid/bta/dm/bta_dm_cfg.c (100%) rename components/bt/{ => host}/bluedroid/bta/dm/bta_dm_ci.c (100%) rename components/bt/{ => host}/bluedroid/bta/dm/bta_dm_co.c (100%) rename components/bt/{ => host}/bluedroid/bta/dm/bta_dm_main.c (100%) rename components/bt/{ => host}/bluedroid/bta/dm/bta_dm_pm.c (100%) rename components/bt/{ => host}/bluedroid/bta/dm/bta_dm_sco.c (100%) rename components/bt/{ => host}/bluedroid/bta/dm/include/bta_dm_int.h (100%) rename components/bt/{ => host}/bluedroid/bta/gatt/bta_gatt_common.c (100%) rename components/bt/{ => host}/bluedroid/bta/gatt/bta_gattc_act.c (100%) rename components/bt/{ => host}/bluedroid/bta/gatt/bta_gattc_api.c (100%) rename components/bt/{ => host}/bluedroid/bta/gatt/bta_gattc_cache.c (100%) rename components/bt/{ => host}/bluedroid/bta/gatt/bta_gattc_ci.c (100%) rename components/bt/{ => host}/bluedroid/bta/gatt/bta_gattc_co.c (100%) rename components/bt/{ => host}/bluedroid/bta/gatt/bta_gattc_main.c (100%) rename components/bt/{ => host}/bluedroid/bta/gatt/bta_gattc_utils.c (100%) rename components/bt/{ => host}/bluedroid/bta/gatt/bta_gatts_act.c (100%) rename components/bt/{ => host}/bluedroid/bta/gatt/bta_gatts_api.c (100%) rename components/bt/{ => host}/bluedroid/bta/gatt/bta_gatts_co.c (100%) rename components/bt/{ => host}/bluedroid/bta/gatt/bta_gatts_main.c (100%) rename components/bt/{ => host}/bluedroid/bta/gatt/bta_gatts_utils.c (100%) rename components/bt/{ => host}/bluedroid/bta/gatt/include/bta_gattc_int.h (100%) rename components/bt/{ => host}/bluedroid/bta/gatt/include/bta_gatts_int.h (100%) rename components/bt/{ => host}/bluedroid/bta/hf_client/bta_hf_client_act.c (100%) rename components/bt/{ => host}/bluedroid/bta/hf_client/bta_hf_client_api.c (100%) rename components/bt/{ => host}/bluedroid/bta/hf_client/bta_hf_client_at.c (100%) rename components/bt/{ => host}/bluedroid/bta/hf_client/bta_hf_client_cmd.c (100%) rename components/bt/{ => host}/bluedroid/bta/hf_client/bta_hf_client_main.c (100%) rename components/bt/{ => host}/bluedroid/bta/hf_client/bta_hf_client_rfc.c (100%) rename components/bt/{ => host}/bluedroid/bta/hf_client/bta_hf_client_sco.c (100%) rename components/bt/{ => host}/bluedroid/bta/hf_client/bta_hf_client_sdp.c (100%) rename components/bt/{ => host}/bluedroid/bta/hf_client/include/bta_hf_client_at.h (100%) rename components/bt/{ => host}/bluedroid/bta/hf_client/include/bta_hf_client_int.h (100%) rename components/bt/{ => host}/bluedroid/bta/hh/bta_hh_act.c (100%) rename components/bt/{ => host}/bluedroid/bta/hh/bta_hh_api.c (100%) rename components/bt/{ => host}/bluedroid/bta/hh/bta_hh_cfg.c (100%) rename components/bt/{ => host}/bluedroid/bta/hh/bta_hh_le.c (100%) rename components/bt/{ => host}/bluedroid/bta/hh/bta_hh_main.c (100%) rename components/bt/{ => host}/bluedroid/bta/hh/bta_hh_utils.c (100%) rename components/bt/{ => host}/bluedroid/bta/hh/include/bta_hh_int.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_api.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_ar_api.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_av_api.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_av_ci.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_av_co.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_av_sbc.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_dm_ci.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_dm_co.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_gap_bt_co.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_gatt_api.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_gatt_common.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_gattc_ci.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_gattc_co.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_gatts_co.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_hf_client_api.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_hf_client_co.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_hfp_defs.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_hh_api.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_hh_co.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_jv_api.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_jv_co.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_sdp_api.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/bta_sys.h (100%) rename components/bt/{ => host}/bluedroid/bta/include/bta/utl.h (100%) rename components/bt/{ => host}/bluedroid/bta/jv/bta_jv_act.c (100%) rename components/bt/{ => host}/bluedroid/bta/jv/bta_jv_api.c (100%) rename components/bt/{ => host}/bluedroid/bta/jv/bta_jv_cfg.c (100%) rename components/bt/{ => host}/bluedroid/bta/jv/bta_jv_main.c (100%) rename components/bt/{ => host}/bluedroid/bta/jv/include/bta_jv_int.h (100%) rename components/bt/{ => host}/bluedroid/bta/sdp/bta_sdp.c (100%) rename components/bt/{ => host}/bluedroid/bta/sdp/bta_sdp_act.c (100%) rename components/bt/{ => host}/bluedroid/bta/sdp/bta_sdp_api.c (100%) rename components/bt/{ => host}/bluedroid/bta/sdp/bta_sdp_cfg.c (100%) rename components/bt/{ => host}/bluedroid/bta/sdp/include/bta_sdp_int.h (100%) rename components/bt/{ => host}/bluedroid/bta/sys/bta_sys_conn.c (100%) rename components/bt/{ => host}/bluedroid/bta/sys/bta_sys_main.c (100%) rename components/bt/{ => host}/bluedroid/bta/sys/include/bta_sys_int.h (100%) rename components/bt/{ => host}/bluedroid/bta/sys/utl.c (100%) rename components/bt/{ => host}/bluedroid/btc/core/btc_ble_storage.c (100%) rename components/bt/{ => host}/bluedroid/btc/core/btc_config.c (100%) rename components/bt/{ => host}/bluedroid/btc/core/btc_dev.c (100%) rename components/bt/{ => host}/bluedroid/btc/core/btc_dm.c (100%) rename components/bt/{ => host}/bluedroid/btc/core/btc_main.c (100%) rename components/bt/{ => host}/bluedroid/btc/core/btc_profile_queue.c (100%) rename components/bt/{ => host}/bluedroid/btc/core/btc_sec.c (100%) rename components/bt/{ => host}/bluedroid/btc/core/btc_sm.c (100%) rename components/bt/{ => host}/bluedroid/btc/core/btc_storage.c (100%) rename components/bt/{ => host}/bluedroid/btc/core/btc_util.c (100%) rename components/bt/{ => host}/bluedroid/btc/include/btc/btc_ble_storage.h (100%) rename components/bt/{ => host}/bluedroid/btc/include/btc/btc_common.h (100%) rename components/bt/{ => host}/bluedroid/btc/include/btc/btc_config.h (100%) rename components/bt/{ => host}/bluedroid/btc/include/btc/btc_dev.h (100%) rename components/bt/{ => host}/bluedroid/btc/include/btc/btc_dm.h (100%) rename components/bt/{ => host}/bluedroid/btc/include/btc/btc_main.h (100%) rename components/bt/{ => host}/bluedroid/btc/include/btc/btc_profile_queue.h (100%) rename components/bt/{ => host}/bluedroid/btc/include/btc/btc_sm.h (100%) rename components/bt/{ => host}/bluedroid/btc/include/btc/btc_storage.h (100%) rename components/bt/{ => host}/bluedroid/btc/include/btc/btc_util.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/esp/ble_button/button_pro.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/esp/blufi/blufi_prf.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/esp/blufi/blufi_protocol.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/esp/blufi/include/blufi_int.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/esp/include/btc_blufi_prf.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/esp/include/button_pro.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/esp/include/wx_airsync_prf.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/esp/wechat_AirSync/wx_airsync_prf.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/a2dp/bta_av_co.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/a2dp/btc_a2dp.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/a2dp/btc_a2dp_control.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/a2dp/btc_av.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/a2dp/include/btc_av_co.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/avrc/bta_avrc_co.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/avrc/btc_avrc.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/battery/battery_prf.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/battery/include/srvc_battery_int.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/dis/dis_profile.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/dis/include/srvc_dis_int.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/gap/bta_gap_bt_co.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/gap/btc_gap_ble.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/gap/btc_gap_bt.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/gatt/btc_gatt_common.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/gatt/btc_gatt_util.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/gatt/btc_gattc.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/gatt/btc_gatts.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/hf_client/btc_hf_client.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/hid/include/hid_conn.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/hid/include/hidh_int.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/include/bt_sdp.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/include/btc_a2dp.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/include/btc_a2dp_control.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/include/btc_a2dp_sink.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/include/btc_a2dp_source.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/include/btc_av.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/include/btc_av_api.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/include/btc_avrc.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/include/btc_gap_ble.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/include/btc_gap_bt.h (99%) rename components/bt/{ => host}/bluedroid/btc/profile/std/include/btc_gatt_common.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/include/btc_gatt_util.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/include/btc_gattc.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/include/btc_gatts.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/include/btc_hf_client.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/include/btc_spp.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/include/dis_api.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/include/srvc_api.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/smp/esp_app_sec.c (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/smp/include/esp_sec_api.h (100%) rename components/bt/{ => host}/bluedroid/btc/profile/std/spp/btc_spp.c (100%) rename components/bt/{bluedroid/common/include/common/bt_user_config.h => host/bluedroid/common/include/common/bluedroid_user_config.h} (80%) rename components/bt/{ => host}/bluedroid/common/include/common/bt_common_types.h (100%) rename components/bt/{ => host}/bluedroid/common/include/common/bt_defs.h (80%) rename components/bt/{ => host}/bluedroid/common/include/common/bt_target.h (99%) rename components/bt/{ => host}/bluedroid/common/include/common/bt_trace.h (88%) rename components/bt/{ => host}/bluedroid/common/include/common/bt_vendor_lib.h (100%) rename components/bt/{ => host}/bluedroid/common/include/common/bte.h (100%) rename components/bt/{ => host}/bluedroid/common/include/common/bte_appl.h (100%) rename components/bt/{ => host}/bluedroid/device/bdaddr.c (100%) rename components/bt/{ => host}/bluedroid/device/controller.c (99%) rename components/bt/{ => host}/bluedroid/device/include/device/bdaddr.h (100%) rename components/bt/{ => host}/bluedroid/device/include/device/controller.h (100%) rename components/bt/{ => host}/bluedroid/device/include/device/device_features.h (100%) rename components/bt/{ => host}/bluedroid/device/include/device/event_mask.h (100%) rename components/bt/{ => host}/bluedroid/device/include/device/interop.h (100%) rename components/bt/{ => host}/bluedroid/device/include/device/interop_database.h (100%) rename components/bt/{ => host}/bluedroid/device/include/device/version.h (100%) rename components/bt/{ => host}/bluedroid/device/interop.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/include/oi_assert.h (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/include/oi_bitstream.h (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/include/oi_bt_spec.h (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/include/oi_codec_sbc.h (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/include/oi_codec_sbc_private.h (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/include/oi_common.h (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/include/oi_cpu_dep.h (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/include/oi_modules.h (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/include/oi_osinterface.h (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/include/oi_status.h (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/include/oi_stddefs.h (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/include/oi_string.h (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/include/oi_time.h (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/include/oi_utils.h (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/srce/alloc.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/srce/bitalloc-sbc.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/srce/bitalloc.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/srce/bitstream-decode.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/srce/decoder-oina.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/srce/decoder-private.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/srce/decoder-sbc.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/srce/dequant.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/srce/framing-sbc.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/srce/framing.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/srce/oi_codec_version.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/srce/readsamplesjoint.inc (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/srce/synthesis-8-generated.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/srce/synthesis-dct8.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/decoder/srce/synthesis-sbc.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/encoder/include/sbc_dct.h (100%) rename components/bt/{ => host}/bluedroid/external/sbc/encoder/include/sbc_enc_func_declare.h (100%) rename components/bt/{ => host}/bluedroid/external/sbc/encoder/include/sbc_encoder.h (100%) rename components/bt/{ => host}/bluedroid/external/sbc/encoder/include/sbc_if.h (100%) rename components/bt/{ => host}/bluedroid/external/sbc/encoder/include/sbc_types.h (100%) rename components/bt/{ => host}/bluedroid/external/sbc/encoder/srce/sbc_analysis.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/encoder/srce/sbc_dct.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/encoder/srce/sbc_dct_coeffs.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/encoder/srce/sbc_enc_coeffs.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/encoder/srce/sbc_encoder.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/encoder/srce/sbc_packing.c (100%) rename components/bt/{ => host}/bluedroid/external/sbc/plc/include/sbc_plc.h (100%) rename components/bt/{ => host}/bluedroid/external/sbc/plc/sbc_plc.c (100%) rename components/bt/{ => host}/bluedroid/hci/hci_audio.c (100%) rename components/bt/{ => host}/bluedroid/hci/hci_hal_h4.c (100%) rename components/bt/{ => host}/bluedroid/hci/hci_layer.c (100%) rename components/bt/{ => host}/bluedroid/hci/hci_packet_factory.c (100%) rename components/bt/{ => host}/bluedroid/hci/hci_packet_parser.c (100%) rename components/bt/{ => host}/bluedroid/hci/include/hci/bt_vendor_lib.h (100%) rename components/bt/{ => host}/bluedroid/hci/include/hci/hci_audio.h (100%) rename components/bt/{ => host}/bluedroid/hci/include/hci/hci_hal.h (100%) rename components/bt/{ => host}/bluedroid/hci/include/hci/hci_internals.h (100%) rename components/bt/{ => host}/bluedroid/hci/include/hci/hci_layer.h (100%) rename components/bt/{ => host}/bluedroid/hci/include/hci/hci_packet_factory.h (100%) rename components/bt/{ => host}/bluedroid/hci/include/hci/hci_packet_parser.h (100%) rename components/bt/{ => host}/bluedroid/hci/include/hci/packet_fragmenter.h (100%) rename components/bt/{ => host}/bluedroid/hci/packet_fragmenter.c (100%) rename components/bt/{ => host}/bluedroid/main/bte_init.c (100%) rename components/bt/{ => host}/bluedroid/main/bte_main.c (100%) rename components/bt/{ => host}/bluedroid/stack/a2dp/a2d_api.c (100%) rename components/bt/{ => host}/bluedroid/stack/a2dp/a2d_sbc.c (100%) rename components/bt/{ => host}/bluedroid/stack/a2dp/include/a2d_int.h (100%) rename components/bt/{ => host}/bluedroid/stack/avct/avct_api.c (100%) rename components/bt/{ => host}/bluedroid/stack/avct/avct_ccb.c (100%) rename components/bt/{ => host}/bluedroid/stack/avct/avct_l2c.c (100%) rename components/bt/{ => host}/bluedroid/stack/avct/avct_lcb.c (100%) rename components/bt/{ => host}/bluedroid/stack/avct/avct_lcb_act.c (100%) rename components/bt/{ => host}/bluedroid/stack/avct/include/avct_defs.h (100%) rename components/bt/{ => host}/bluedroid/stack/avct/include/avct_int.h (100%) rename components/bt/{ => host}/bluedroid/stack/avdt/avdt_ad.c (100%) rename components/bt/{ => host}/bluedroid/stack/avdt/avdt_api.c (100%) rename components/bt/{ => host}/bluedroid/stack/avdt/avdt_ccb.c (100%) rename components/bt/{ => host}/bluedroid/stack/avdt/avdt_ccb_act.c (100%) rename components/bt/{ => host}/bluedroid/stack/avdt/avdt_l2c.c (100%) rename components/bt/{ => host}/bluedroid/stack/avdt/avdt_msg.c (100%) rename components/bt/{ => host}/bluedroid/stack/avdt/avdt_scb.c (100%) rename components/bt/{ => host}/bluedroid/stack/avdt/avdt_scb_act.c (100%) rename components/bt/{ => host}/bluedroid/stack/avdt/include/avdt_defs.h (100%) rename components/bt/{ => host}/bluedroid/stack/avdt/include/avdt_int.h (100%) rename components/bt/{ => host}/bluedroid/stack/avrc/avrc_api.c (100%) rename components/bt/{ => host}/bluedroid/stack/avrc/avrc_bld_ct.c (100%) rename components/bt/{ => host}/bluedroid/stack/avrc/avrc_bld_tg.c (100%) rename components/bt/{ => host}/bluedroid/stack/avrc/avrc_opt.c (100%) rename components/bt/{ => host}/bluedroid/stack/avrc/avrc_pars_ct.c (100%) rename components/bt/{ => host}/bluedroid/stack/avrc/avrc_pars_tg.c (100%) rename components/bt/{ => host}/bluedroid/stack/avrc/avrc_sdp.c (100%) rename components/bt/{ => host}/bluedroid/stack/avrc/avrc_utils.c (100%) rename components/bt/{ => host}/bluedroid/stack/avrc/include/avrc_int.h (100%) rename components/bt/{ => host}/bluedroid/stack/btm/btm_acl.c (100%) rename components/bt/{ => host}/bluedroid/stack/btm/btm_ble.c (100%) rename components/bt/{ => host}/bluedroid/stack/btm/btm_ble_addr.c (100%) rename components/bt/{ => host}/bluedroid/stack/btm/btm_ble_adv_filter.c (100%) rename components/bt/{ => host}/bluedroid/stack/btm/btm_ble_batchscan.c (100%) rename components/bt/{ => host}/bluedroid/stack/btm/btm_ble_bgconn.c (100%) rename components/bt/{ => host}/bluedroid/stack/btm/btm_ble_cont_energy.c (100%) rename components/bt/{ => host}/bluedroid/stack/btm/btm_ble_gap.c (100%) rename components/bt/{ => host}/bluedroid/stack/btm/btm_ble_multi_adv.c (100%) rename components/bt/{ => host}/bluedroid/stack/btm/btm_ble_privacy.c (100%) rename components/bt/{ => host}/bluedroid/stack/btm/btm_dev.c (100%) rename components/bt/{ => host}/bluedroid/stack/btm/btm_devctl.c (100%) rename components/bt/{ => host}/bluedroid/stack/btm/btm_inq.c (100%) rename components/bt/{ => host}/bluedroid/stack/btm/btm_main.c (100%) rename components/bt/{ => host}/bluedroid/stack/btm/btm_pm.c (100%) rename components/bt/{ => host}/bluedroid/stack/btm/btm_sco.c (100%) rename components/bt/{ => host}/bluedroid/stack/btm/btm_sec.c (100%) rename components/bt/{ => host}/bluedroid/stack/btm/include/btm_ble_int.h (100%) rename components/bt/{ => host}/bluedroid/stack/btm/include/btm_int.h (100%) rename components/bt/{ => host}/bluedroid/stack/btu/btu_hcif.c (100%) rename components/bt/{ => host}/bluedroid/stack/btu/btu_init.c (98%) rename components/bt/{ => host}/bluedroid/stack/btu/btu_task.c (100%) rename components/bt/{ => host}/bluedroid/stack/gap/gap_api.c (100%) rename components/bt/{ => host}/bluedroid/stack/gap/gap_ble.c (100%) rename components/bt/{ => host}/bluedroid/stack/gap/gap_conn.c (100%) rename components/bt/{ => host}/bluedroid/stack/gap/gap_utils.c (100%) rename components/bt/{ => host}/bluedroid/stack/gap/include/gap_int.h (100%) rename components/bt/{ => host}/bluedroid/stack/gatt/att_protocol.c (100%) rename components/bt/{ => host}/bluedroid/stack/gatt/gatt_api.c (100%) rename components/bt/{ => host}/bluedroid/stack/gatt/gatt_attr.c (100%) rename components/bt/{ => host}/bluedroid/stack/gatt/gatt_auth.c (100%) rename components/bt/{ => host}/bluedroid/stack/gatt/gatt_cl.c (100%) rename components/bt/{ => host}/bluedroid/stack/gatt/gatt_db.c (100%) rename components/bt/{ => host}/bluedroid/stack/gatt/gatt_main.c (100%) rename components/bt/{ => host}/bluedroid/stack/gatt/gatt_sr.c (100%) rename components/bt/{ => host}/bluedroid/stack/gatt/gatt_utils.c (100%) rename components/bt/{ => host}/bluedroid/stack/gatt/include/gatt_int.h (100%) rename components/bt/{ => host}/bluedroid/stack/hcic/hciblecmds.c (100%) rename components/bt/{ => host}/bluedroid/stack/hcic/hcicmds.c (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/a2d_api.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/a2d_sbc.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/avct_api.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/avdt_api.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/avdtc_api.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/avrc_api.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/avrc_defs.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/bt_types.h (97%) rename components/bt/{ => host}/bluedroid/stack/include/stack/btm_api.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/btm_ble_api.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/btu.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/dyn_mem.h (95%) rename components/bt/{ => host}/bluedroid/stack/include/stack/gap_api.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/gatt_api.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/gattdefs.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/hcidefs.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/hcimsgs.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/hiddefs.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/hidh_api.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/l2c_api.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/l2cap_client.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/l2cdefs.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/port_api.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/port_ext.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/profiles_api.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/rfcdefs.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/sdp_api.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/sdpdefs.h (100%) rename components/bt/{ => host}/bluedroid/stack/include/stack/smp_api.h (100%) rename components/bt/{ => host}/bluedroid/stack/l2cap/include/l2c_int.h (100%) rename components/bt/{ => host}/bluedroid/stack/l2cap/l2c_api.c (100%) rename components/bt/{ => host}/bluedroid/stack/l2cap/l2c_ble.c (100%) rename components/bt/{ => host}/bluedroid/stack/l2cap/l2c_csm.c (100%) rename components/bt/{ => host}/bluedroid/stack/l2cap/l2c_fcr.c (100%) rename components/bt/{ => host}/bluedroid/stack/l2cap/l2c_link.c (100%) rename components/bt/{ => host}/bluedroid/stack/l2cap/l2c_main.c (100%) rename components/bt/{ => host}/bluedroid/stack/l2cap/l2c_ucd.c (100%) rename components/bt/{ => host}/bluedroid/stack/l2cap/l2c_utils.c (100%) rename components/bt/{ => host}/bluedroid/stack/l2cap/l2cap_client.c (100%) rename components/bt/{ => host}/bluedroid/stack/rfcomm/include/port_int.h (100%) rename components/bt/{ => host}/bluedroid/stack/rfcomm/include/rfc_int.h (100%) rename components/bt/{ => host}/bluedroid/stack/rfcomm/port_api.c (100%) rename components/bt/{ => host}/bluedroid/stack/rfcomm/port_rfc.c (100%) rename components/bt/{ => host}/bluedroid/stack/rfcomm/port_utils.c (100%) rename components/bt/{ => host}/bluedroid/stack/rfcomm/rfc_l2cap_if.c (100%) rename components/bt/{ => host}/bluedroid/stack/rfcomm/rfc_mx_fsm.c (100%) rename components/bt/{ => host}/bluedroid/stack/rfcomm/rfc_port_fsm.c (100%) rename components/bt/{ => host}/bluedroid/stack/rfcomm/rfc_port_if.c (100%) rename components/bt/{ => host}/bluedroid/stack/rfcomm/rfc_ts_frames.c (100%) rename components/bt/{ => host}/bluedroid/stack/rfcomm/rfc_utils.c (100%) rename components/bt/{ => host}/bluedroid/stack/sdp/include/sdpint.h (100%) rename components/bt/{ => host}/bluedroid/stack/sdp/sdp_api.c (100%) rename components/bt/{ => host}/bluedroid/stack/sdp/sdp_db.c (100%) rename components/bt/{ => host}/bluedroid/stack/sdp/sdp_discovery.c (100%) rename components/bt/{ => host}/bluedroid/stack/sdp/sdp_main.c (100%) rename components/bt/{ => host}/bluedroid/stack/sdp/sdp_server.c (100%) rename components/bt/{ => host}/bluedroid/stack/sdp/sdp_utils.c (100%) rename components/bt/{ => host}/bluedroid/stack/smp/aes.c (100%) rename components/bt/{ => host}/bluedroid/stack/smp/include/aes.h (100%) rename components/bt/{ => host}/bluedroid/stack/smp/include/p_256_ecc_pp.h (100%) rename components/bt/{ => host}/bluedroid/stack/smp/include/p_256_multprecision.h (100%) rename components/bt/{ => host}/bluedroid/stack/smp/include/smp_int.h (100%) rename components/bt/{ => host}/bluedroid/stack/smp/p_256_curvepara.c (100%) rename components/bt/{ => host}/bluedroid/stack/smp/p_256_ecc_pp.c (100%) rename components/bt/{ => host}/bluedroid/stack/smp/p_256_multprecision.c (100%) rename components/bt/{ => host}/bluedroid/stack/smp/smp_act.c (100%) rename components/bt/{ => host}/bluedroid/stack/smp/smp_api.c (100%) rename components/bt/{ => host}/bluedroid/stack/smp/smp_br_main.c (100%) rename components/bt/{ => host}/bluedroid/stack/smp/smp_cmac.c (100%) rename components/bt/{ => host}/bluedroid/stack/smp/smp_keys.c (100%) rename components/bt/{ => host}/bluedroid/stack/smp/smp_l2c.c (100%) rename components/bt/{ => host}/bluedroid/stack/smp/smp_main.c (100%) rename components/bt/{ => host}/bluedroid/stack/smp/smp_utils.c (100%) rename components/{ => bt/host}/nimble/Kconfig.in (100%) rename components/{ => bt/host}/nimble/esp-hci/include/esp_nimble_hci.h (100%) rename components/{ => bt/host}/nimble/esp-hci/src/esp_nimble_hci.c (100%) rename components/{ => bt/host}/nimble/nimble (100%) rename components/{ => bt/host}/nimble/port/include/console/console.h (100%) rename components/{ => bt/host}/nimble/port/include/esp_nimble_cfg.h (100%) delete mode 160000 components/bt/lib delete mode 100644 components/nimble/CMakeLists.txt delete mode 100644 components/nimble/component.mk diff --git a/.gitmodules b/.gitmodules index b14915bc26..21a8c1df34 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,8 +6,8 @@ path = components/esptool_py/esptool url = ../esptool.git -[submodule "components/bt/lib"] - path = components/bt/lib +[submodule "components/bt/controller/lib"] + path = components/bt/controller/lib url = ../esp32-bt-lib.git [submodule "components/bootloader/subproject/components/micro-ecc/micro-ecc"] @@ -70,6 +70,6 @@ path = components/esp_wifi/lib_esp32 url = ../esp32-wifi-lib.git -[submodule "components/nimble/nimble"] - path = components/nimble/nimble +[submodule "components/bt/host/nimble/nimble"] + path = components/bt/host/nimble/nimble url = ../esp-nimble.git diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index e6e76db345..095493c1dd 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -1,359 +1,497 @@ if(CONFIG_BT_ENABLED) - set(srcs "bt.c") - set(include_dirs include) + set(srcs "controller/bt.c") + set(include_dirs include + common/osi/include) + + list(APPEND priv_include_dirs + common/btc/include + common/include) + + list(APPEND srcs "common/btc/core/btc_alarm.c" + "common/btc/core/btc_manage.c" + "common/btc/core/btc_task.c" + "common/osi/alarm.c" + "common/osi/allocator.c" + "common/osi/buffer.c" + "common/osi/config.c" + "common/osi/fixed_queue.c" + "common/osi/future.c" + "common/osi/hash_functions.c" + "common/osi/hash_map.c" + "common/osi/list.c" + "common/osi/mutex.c" + "common/osi/thread.c" + "common/osi/osi.c" + "common/osi/semaphore.c") if(CONFIG_BT_BLUEDROID_ENABLED) list(APPEND priv_include_dirs - bluedroid/bta/include - bluedroid/bta/ar/include - bluedroid/bta/av/include - bluedroid/bta/dm/include - bluedroid/bta/gatt/include - bluedroid/bta/hf_client/include - bluedroid/bta/hh/include - bluedroid/bta/jv/include - bluedroid/bta/sdp/include - bluedroid/bta/sys/include - bluedroid/device/include - bluedroid/hci/include - bluedroid/osi/include - bluedroid/external/sbc/decoder/include - bluedroid/external/sbc/encoder/include - bluedroid/external/sbc/plc/include - bluedroid/btc/profile/esp/blufi/include - bluedroid/btc/profile/esp/include - bluedroid/btc/profile/std/a2dp/include - bluedroid/btc/profile/std/include - bluedroid/btc/include - bluedroid/stack/btm/include - bluedroid/stack/gap/include - bluedroid/stack/gatt/include - bluedroid/stack/l2cap/include - bluedroid/stack/sdp/include - bluedroid/stack/smp/include - bluedroid/stack/avct/include - bluedroid/stack/avrc/include - bluedroid/stack/avdt/include - bluedroid/stack/a2dp/include - bluedroid/stack/rfcomm/include - bluedroid/stack/include - bluedroid/common/include) + host/bluedroid/bta/include + host/bluedroid/bta/ar/include + host/bluedroid/bta/av/include + host/bluedroid/bta/dm/include + host/bluedroid/bta/gatt/include + host/bluedroid/bta/hf_client/include + host/bluedroid/bta/hh/include + host/bluedroid/bta/jv/include + host/bluedroid/bta/sdp/include + host/bluedroid/bta/sys/include + host/bluedroid/device/include + host/bluedroid/hci/include + host/bluedroid/external/sbc/decoder/include + host/bluedroid/external/sbc/encoder/include + host/bluedroid/external/sbc/plc/include + host/bluedroid/btc/profile/esp/blufi/include + host/bluedroid/btc/profile/esp/include + host/bluedroid/btc/profile/std/a2dp/include + host/bluedroid/btc/profile/std/include + host/bluedroid/btc/include + host/bluedroid/stack/btm/include + host/bluedroid/stack/gap/include + host/bluedroid/stack/gatt/include + host/bluedroid/stack/l2cap/include + host/bluedroid/stack/sdp/include + host/bluedroid/stack/smp/include + host/bluedroid/stack/avct/include + host/bluedroid/stack/avrc/include + host/bluedroid/stack/avdt/include + host/bluedroid/stack/a2dp/include + host/bluedroid/stack/rfcomm/include + host/bluedroid/stack/include + host/bluedroid/common/include) - list(APPEND include_dirs bluedroid/api/include/api) + list(APPEND include_dirs host/bluedroid/api/include/api) - list(APPEND srcs "bluedroid/api/esp_a2dp_api.c" - "bluedroid/api/esp_avrc_api.c" - "bluedroid/api/esp_blufi_api.c" - "bluedroid/api/esp_bt_device.c" - "bluedroid/api/esp_bt_main.c" - "bluedroid/api/esp_gap_ble_api.c" - "bluedroid/api/esp_gap_bt_api.c" - "bluedroid/api/esp_gatt_common_api.c" - "bluedroid/api/esp_gattc_api.c" - "bluedroid/api/esp_gatts_api.c" - "bluedroid/api/esp_hf_client_api.c" - "bluedroid/api/esp_spp_api.c" - "bluedroid/bta/ar/bta_ar.c" - "bluedroid/bta/av/bta_av_aact.c" - "bluedroid/bta/av/bta_av_act.c" - "bluedroid/bta/av/bta_av_api.c" - "bluedroid/bta/av/bta_av_cfg.c" - "bluedroid/bta/av/bta_av_ci.c" - "bluedroid/bta/av/bta_av_main.c" - "bluedroid/bta/av/bta_av_sbc.c" - "bluedroid/bta/av/bta_av_ssm.c" - "bluedroid/bta/dm/bta_dm_act.c" - "bluedroid/bta/dm/bta_dm_api.c" - "bluedroid/bta/dm/bta_dm_cfg.c" - "bluedroid/bta/dm/bta_dm_ci.c" - "bluedroid/bta/dm/bta_dm_co.c" - "bluedroid/bta/dm/bta_dm_main.c" - "bluedroid/bta/dm/bta_dm_pm.c" - "bluedroid/bta/dm/bta_dm_sco.c" - "bluedroid/bta/gatt/bta_gatt_common.c" - "bluedroid/bta/gatt/bta_gattc_act.c" - "bluedroid/bta/gatt/bta_gattc_api.c" - "bluedroid/bta/gatt/bta_gattc_cache.c" - "bluedroid/bta/gatt/bta_gattc_ci.c" - "bluedroid/bta/gatt/bta_gattc_co.c" - "bluedroid/bta/gatt/bta_gattc_main.c" - "bluedroid/bta/gatt/bta_gattc_utils.c" - "bluedroid/bta/gatt/bta_gatts_act.c" - "bluedroid/bta/gatt/bta_gatts_api.c" - "bluedroid/bta/gatt/bta_gatts_co.c" - "bluedroid/bta/gatt/bta_gatts_main.c" - "bluedroid/bta/gatt/bta_gatts_utils.c" - "bluedroid/bta/hh/bta_hh_act.c" - "bluedroid/bta/hh/bta_hh_api.c" - "bluedroid/bta/hh/bta_hh_cfg.c" - "bluedroid/bta/hh/bta_hh_le.c" - "bluedroid/bta/hh/bta_hh_main.c" - "bluedroid/bta/hh/bta_hh_utils.c" - "bluedroid/bta/jv/bta_jv_act.c" - "bluedroid/bta/jv/bta_jv_api.c" - "bluedroid/bta/jv/bta_jv_cfg.c" - "bluedroid/bta/jv/bta_jv_main.c" - "bluedroid/bta/hf_client/bta_hf_client_act.c" - "bluedroid/bta/hf_client/bta_hf_client_api.c" - "bluedroid/bta/hf_client/bta_hf_client_at.c" - "bluedroid/bta/hf_client/bta_hf_client_cmd.c" - "bluedroid/bta/hf_client/bta_hf_client_main.c" - "bluedroid/bta/hf_client/bta_hf_client_rfc.c" - "bluedroid/bta/hf_client/bta_hf_client_sco.c" - "bluedroid/bta/hf_client/bta_hf_client_sdp.c" - "bluedroid/bta/sdp/bta_sdp.c" - "bluedroid/bta/sdp/bta_sdp_act.c" - "bluedroid/bta/sdp/bta_sdp_api.c" - "bluedroid/bta/sdp/bta_sdp_cfg.c" - "bluedroid/bta/sys/bta_sys_conn.c" - "bluedroid/bta/sys/bta_sys_main.c" - "bluedroid/bta/sys/utl.c" - "bluedroid/btc/core/btc_alarm.c" - "bluedroid/btc/core/btc_ble_storage.c" - "bluedroid/btc/core/btc_config.c" - "bluedroid/btc/core/btc_dev.c" - "bluedroid/btc/core/btc_dm.c" - "bluedroid/btc/core/btc_main.c" - "bluedroid/btc/core/btc_manage.c" - "bluedroid/btc/core/btc_profile_queue.c" - "bluedroid/btc/core/btc_sec.c" - "bluedroid/btc/core/btc_sm.c" - "bluedroid/btc/core/btc_storage.c" - "bluedroid/btc/core/btc_task.c" - "bluedroid/btc/core/btc_util.c" - "bluedroid/btc/profile/esp/blufi/blufi_prf.c" - "bluedroid/btc/profile/esp/blufi/blufi_protocol.c" - "bluedroid/btc/profile/std/a2dp/bta_av_co.c" - "bluedroid/btc/profile/std/a2dp/btc_a2dp.c" - "bluedroid/btc/profile/std/a2dp/btc_a2dp_control.c" - "bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c" - "bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c" - "bluedroid/btc/profile/std/a2dp/btc_av.c" - "bluedroid/btc/profile/std/avrc/btc_avrc.c" - "bluedroid/btc/profile/std/avrc/bta_avrc_co.c" - "bluedroid/btc/profile/std/hf_client/btc_hf_client.c" - "bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c" - "bluedroid/btc/profile/std/gap/btc_gap_ble.c" - "bluedroid/btc/profile/std/gap/btc_gap_bt.c" - "bluedroid/btc/profile/std/gap/bta_gap_bt_co.c" - "bluedroid/btc/profile/std/gatt/btc_gatt_common.c" - "bluedroid/btc/profile/std/gatt/btc_gatt_util.c" - "bluedroid/btc/profile/std/gatt/btc_gattc.c" - "bluedroid/btc/profile/std/gatt/btc_gatts.c" - "bluedroid/btc/profile/std/spp/btc_spp.c" - "bluedroid/device/bdaddr.c" - "bluedroid/device/controller.c" - "bluedroid/device/interop.c" - "bluedroid/external/sbc/decoder/srce/alloc.c" - "bluedroid/external/sbc/decoder/srce/bitalloc-sbc.c" - "bluedroid/external/sbc/decoder/srce/bitalloc.c" - "bluedroid/external/sbc/decoder/srce/bitstream-decode.c" - "bluedroid/external/sbc/decoder/srce/decoder-oina.c" - "bluedroid/external/sbc/decoder/srce/decoder-private.c" - "bluedroid/external/sbc/decoder/srce/decoder-sbc.c" - "bluedroid/external/sbc/decoder/srce/dequant.c" - "bluedroid/external/sbc/decoder/srce/framing-sbc.c" - "bluedroid/external/sbc/decoder/srce/framing.c" - "bluedroid/external/sbc/decoder/srce/oi_codec_version.c" - "bluedroid/external/sbc/decoder/srce/synthesis-8-generated.c" - "bluedroid/external/sbc/decoder/srce/synthesis-dct8.c" - "bluedroid/external/sbc/decoder/srce/synthesis-sbc.c" - "bluedroid/external/sbc/encoder/srce/sbc_analysis.c" - "bluedroid/external/sbc/encoder/srce/sbc_dct.c" - "bluedroid/external/sbc/encoder/srce/sbc_dct_coeffs.c" - "bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c" - "bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c" - "bluedroid/external/sbc/encoder/srce/sbc_enc_coeffs.c" - "bluedroid/external/sbc/encoder/srce/sbc_encoder.c" - "bluedroid/external/sbc/encoder/srce/sbc_packing.c" - "bluedroid/external/sbc/plc/sbc_plc.c" - "bluedroid/hci/hci_audio.c" - "bluedroid/hci/hci_hal_h4.c" - "bluedroid/hci/hci_layer.c" - "bluedroid/hci/hci_packet_factory.c" - "bluedroid/hci/hci_packet_parser.c" - "bluedroid/hci/packet_fragmenter.c" - "bluedroid/main/bte_init.c" - "bluedroid/main/bte_main.c" - "bluedroid/osi/alarm.c" - "bluedroid/osi/allocator.c" - "bluedroid/osi/buffer.c" - "bluedroid/osi/config.c" - "bluedroid/osi/fixed_queue.c" - "bluedroid/osi/future.c" - "bluedroid/osi/hash_functions.c" - "bluedroid/osi/hash_map.c" - "bluedroid/osi/list.c" - "bluedroid/osi/mutex.c" - "bluedroid/osi/osi.c" - "bluedroid/osi/semaphore.c" - "bluedroid/osi/thread.c" - "bluedroid/stack/a2dp/a2d_api.c" - "bluedroid/stack/a2dp/a2d_sbc.c" - "bluedroid/stack/avct/avct_api.c" - "bluedroid/stack/avct/avct_ccb.c" - "bluedroid/stack/avct/avct_l2c.c" - "bluedroid/stack/avct/avct_lcb.c" - "bluedroid/stack/avct/avct_lcb_act.c" - "bluedroid/stack/avdt/avdt_ad.c" - "bluedroid/stack/avdt/avdt_api.c" - "bluedroid/stack/avdt/avdt_ccb.c" - "bluedroid/stack/avdt/avdt_ccb_act.c" - "bluedroid/stack/avdt/avdt_l2c.c" - "bluedroid/stack/avdt/avdt_msg.c" - "bluedroid/stack/avdt/avdt_scb.c" - "bluedroid/stack/avdt/avdt_scb_act.c" - "bluedroid/stack/avrc/avrc_api.c" - "bluedroid/stack/avrc/avrc_bld_ct.c" - "bluedroid/stack/avrc/avrc_bld_tg.c" - "bluedroid/stack/avrc/avrc_opt.c" - "bluedroid/stack/avrc/avrc_pars_ct.c" - "bluedroid/stack/avrc/avrc_pars_tg.c" - "bluedroid/stack/avrc/avrc_sdp.c" - "bluedroid/stack/avrc/avrc_utils.c" - "bluedroid/stack/btm/btm_acl.c" - "bluedroid/stack/btm/btm_ble.c" - "bluedroid/stack/btm/btm_ble_addr.c" - "bluedroid/stack/btm/btm_ble_adv_filter.c" - "bluedroid/stack/btm/btm_ble_batchscan.c" - "bluedroid/stack/btm/btm_ble_bgconn.c" - "bluedroid/stack/btm/btm_ble_cont_energy.c" - "bluedroid/stack/btm/btm_ble_gap.c" - "bluedroid/stack/btm/btm_ble_multi_adv.c" - "bluedroid/stack/btm/btm_ble_privacy.c" - "bluedroid/stack/btm/btm_dev.c" - "bluedroid/stack/btm/btm_devctl.c" - "bluedroid/stack/btm/btm_inq.c" - "bluedroid/stack/btm/btm_main.c" - "bluedroid/stack/btm/btm_pm.c" - "bluedroid/stack/btm/btm_sco.c" - "bluedroid/stack/btm/btm_sec.c" - "bluedroid/stack/btu/btu_hcif.c" - "bluedroid/stack/btu/btu_init.c" - "bluedroid/stack/btu/btu_task.c" - "bluedroid/stack/gap/gap_api.c" - "bluedroid/stack/gap/gap_ble.c" - "bluedroid/stack/gap/gap_conn.c" - "bluedroid/stack/gap/gap_utils.c" - "bluedroid/stack/gatt/att_protocol.c" - "bluedroid/stack/gatt/gatt_api.c" - "bluedroid/stack/gatt/gatt_attr.c" - "bluedroid/stack/gatt/gatt_auth.c" - "bluedroid/stack/gatt/gatt_cl.c" - "bluedroid/stack/gatt/gatt_db.c" - "bluedroid/stack/gatt/gatt_main.c" - "bluedroid/stack/gatt/gatt_sr.c" - "bluedroid/stack/gatt/gatt_utils.c" - "bluedroid/stack/hcic/hciblecmds.c" - "bluedroid/stack/hcic/hcicmds.c" - "bluedroid/stack/l2cap/l2c_api.c" - "bluedroid/stack/l2cap/l2c_ble.c" - "bluedroid/stack/l2cap/l2c_csm.c" - "bluedroid/stack/l2cap/l2c_fcr.c" - "bluedroid/stack/l2cap/l2c_link.c" - "bluedroid/stack/l2cap/l2c_main.c" - "bluedroid/stack/l2cap/l2c_ucd.c" - "bluedroid/stack/l2cap/l2c_utils.c" - "bluedroid/stack/l2cap/l2cap_client.c" - "bluedroid/stack/rfcomm/port_api.c" - "bluedroid/stack/rfcomm/port_rfc.c" - "bluedroid/stack/rfcomm/port_utils.c" - "bluedroid/stack/rfcomm/rfc_l2cap_if.c" - "bluedroid/stack/rfcomm/rfc_mx_fsm.c" - "bluedroid/stack/rfcomm/rfc_port_fsm.c" - "bluedroid/stack/rfcomm/rfc_port_if.c" - "bluedroid/stack/rfcomm/rfc_ts_frames.c" - "bluedroid/stack/rfcomm/rfc_utils.c" - "bluedroid/stack/sdp/sdp_api.c" - "bluedroid/stack/sdp/sdp_db.c" - "bluedroid/stack/sdp/sdp_discovery.c" - "bluedroid/stack/sdp/sdp_main.c" - "bluedroid/stack/sdp/sdp_server.c" - "bluedroid/stack/sdp/sdp_utils.c" - "bluedroid/stack/smp/aes.c" - "bluedroid/stack/smp/p_256_curvepara.c" - "bluedroid/stack/smp/p_256_ecc_pp.c" - "bluedroid/stack/smp/p_256_multprecision.c" - "bluedroid/stack/smp/smp_act.c" - "bluedroid/stack/smp/smp_api.c" - "bluedroid/stack/smp/smp_br_main.c" - "bluedroid/stack/smp/smp_cmac.c" - "bluedroid/stack/smp/smp_keys.c" - "bluedroid/stack/smp/smp_l2c.c" - "bluedroid/stack/smp/smp_main.c" - "bluedroid/stack/smp/smp_utils.c") + list(APPEND srcs "host/bluedroid/api/esp_a2dp_api.c" + "host/bluedroid/api/esp_avrc_api.c" + "host/bluedroid/api/esp_blufi_api.c" + "host/bluedroid/api/esp_bt_device.c" + "host/bluedroid/api/esp_bt_main.c" + "host/bluedroid/api/esp_gap_ble_api.c" + "host/bluedroid/api/esp_gap_bt_api.c" + "host/bluedroid/api/esp_gatt_common_api.c" + "host/bluedroid/api/esp_gattc_api.c" + "host/bluedroid/api/esp_gatts_api.c" + "host/bluedroid/api/esp_hf_client_api.c" + "host/bluedroid/api/esp_spp_api.c" + "host/bluedroid/bta/ar/bta_ar.c" + "host/bluedroid/bta/av/bta_av_aact.c" + "host/bluedroid/bta/av/bta_av_act.c" + "host/bluedroid/bta/av/bta_av_api.c" + "host/bluedroid/bta/av/bta_av_cfg.c" + "host/bluedroid/bta/av/bta_av_ci.c" + "host/bluedroid/bta/av/bta_av_main.c" + "host/bluedroid/bta/av/bta_av_sbc.c" + "host/bluedroid/bta/av/bta_av_ssm.c" + "host/bluedroid/bta/dm/bta_dm_act.c" + "host/bluedroid/bta/dm/bta_dm_api.c" + "host/bluedroid/bta/dm/bta_dm_cfg.c" + "host/bluedroid/bta/dm/bta_dm_ci.c" + "host/bluedroid/bta/dm/bta_dm_co.c" + "host/bluedroid/bta/dm/bta_dm_main.c" + "host/bluedroid/bta/dm/bta_dm_pm.c" + "host/bluedroid/bta/dm/bta_dm_sco.c" + "host/bluedroid/bta/gatt/bta_gatt_common.c" + "host/bluedroid/bta/gatt/bta_gattc_act.c" + "host/bluedroid/bta/gatt/bta_gattc_api.c" + "host/bluedroid/bta/gatt/bta_gattc_cache.c" + "host/bluedroid/bta/gatt/bta_gattc_ci.c" + "host/bluedroid/bta/gatt/bta_gattc_co.c" + "host/bluedroid/bta/gatt/bta_gattc_main.c" + "host/bluedroid/bta/gatt/bta_gattc_utils.c" + "host/bluedroid/bta/gatt/bta_gatts_act.c" + "host/bluedroid/bta/gatt/bta_gatts_api.c" + "host/bluedroid/bta/gatt/bta_gatts_co.c" + "host/bluedroid/bta/gatt/bta_gatts_main.c" + "host/bluedroid/bta/gatt/bta_gatts_utils.c" + "host/bluedroid/bta/hh/bta_hh_act.c" + "host/bluedroid/bta/hh/bta_hh_api.c" + "host/bluedroid/bta/hh/bta_hh_cfg.c" + "host/bluedroid/bta/hh/bta_hh_le.c" + "host/bluedroid/bta/hh/bta_hh_main.c" + "host/bluedroid/bta/hh/bta_hh_utils.c" + "host/bluedroid/bta/jv/bta_jv_act.c" + "host/bluedroid/bta/jv/bta_jv_api.c" + "host/bluedroid/bta/jv/bta_jv_cfg.c" + "host/bluedroid/bta/jv/bta_jv_main.c" + "host/bluedroid/bta/hf_client/bta_hf_client_act.c" + "host/bluedroid/bta/hf_client/bta_hf_client_api.c" + "host/bluedroid/bta/hf_client/bta_hf_client_at.c" + "host/bluedroid/bta/hf_client/bta_hf_client_cmd.c" + "host/bluedroid/bta/hf_client/bta_hf_client_main.c" + "host/bluedroid/bta/hf_client/bta_hf_client_rfc.c" + "host/bluedroid/bta/hf_client/bta_hf_client_sco.c" + "host/bluedroid/bta/hf_client/bta_hf_client_sdp.c" + "host/bluedroid/bta/sdp/bta_sdp.c" + "host/bluedroid/bta/sdp/bta_sdp_act.c" + "host/bluedroid/bta/sdp/bta_sdp_api.c" + "host/bluedroid/bta/sdp/bta_sdp_cfg.c" + "host/bluedroid/bta/sys/bta_sys_conn.c" + "host/bluedroid/bta/sys/bta_sys_main.c" + "host/bluedroid/bta/sys/utl.c" + "host/bluedroid/btc/core/btc_ble_storage.c" + "host/bluedroid/btc/core/btc_config.c" + "host/bluedroid/btc/core/btc_dev.c" + "host/bluedroid/btc/core/btc_dm.c" + "host/bluedroid/btc/core/btc_main.c" + "host/bluedroid/btc/core/btc_profile_queue.c" + "host/bluedroid/btc/core/btc_sec.c" + "host/bluedroid/btc/core/btc_sm.c" + "host/bluedroid/btc/core/btc_storage.c" + "host/bluedroid/btc/core/btc_util.c" + "host/bluedroid/btc/profile/esp/blufi/blufi_prf.c" + "host/bluedroid/btc/profile/esp/blufi/blufi_protocol.c" + "host/bluedroid/btc/profile/std/a2dp/bta_av_co.c" + "host/bluedroid/btc/profile/std/a2dp/btc_a2dp.c" + "host/bluedroid/btc/profile/std/a2dp/btc_a2dp_control.c" + "host/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c" + "host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c" + "host/bluedroid/btc/profile/std/a2dp/btc_av.c" + "host/bluedroid/btc/profile/std/avrc/btc_avrc.c" + "host/bluedroid/btc/profile/std/avrc/bta_avrc_co.c" + "host/bluedroid/btc/profile/std/hf_client/btc_hf_client.c" + "host/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c" + "host/bluedroid/btc/profile/std/gap/btc_gap_ble.c" + "host/bluedroid/btc/profile/std/gap/btc_gap_bt.c" + "host/bluedroid/btc/profile/std/gap/bta_gap_bt_co.c" + "host/bluedroid/btc/profile/std/gatt/btc_gatt_common.c" + "host/bluedroid/btc/profile/std/gatt/btc_gatt_util.c" + "host/bluedroid/btc/profile/std/gatt/btc_gattc.c" + "host/bluedroid/btc/profile/std/gatt/btc_gatts.c" + "host/bluedroid/btc/profile/std/spp/btc_spp.c" + "host/bluedroid/device/bdaddr.c" + "host/bluedroid/device/controller.c" + "host/bluedroid/device/interop.c" + "host/bluedroid/external/sbc/decoder/srce/alloc.c" + "host/bluedroid/external/sbc/decoder/srce/bitalloc-sbc.c" + "host/bluedroid/external/sbc/decoder/srce/bitalloc.c" + "host/bluedroid/external/sbc/decoder/srce/bitstream-decode.c" + "host/bluedroid/external/sbc/decoder/srce/decoder-oina.c" + "host/bluedroid/external/sbc/decoder/srce/decoder-private.c" + "host/bluedroid/external/sbc/decoder/srce/decoder-sbc.c" + "host/bluedroid/external/sbc/decoder/srce/dequant.c" + "host/bluedroid/external/sbc/decoder/srce/framing-sbc.c" + "host/bluedroid/external/sbc/decoder/srce/framing.c" + "host/bluedroid/external/sbc/decoder/srce/oi_codec_version.c" + "host/bluedroid/external/sbc/decoder/srce/synthesis-8-generated.c" + "host/bluedroid/external/sbc/decoder/srce/synthesis-dct8.c" + "host/bluedroid/external/sbc/decoder/srce/synthesis-sbc.c" + "host/bluedroid/external/sbc/encoder/srce/sbc_analysis.c" + "host/bluedroid/external/sbc/encoder/srce/sbc_dct.c" + "host/bluedroid/external/sbc/encoder/srce/sbc_dct_coeffs.c" + "host/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c" + "host/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c" + "host/bluedroid/external/sbc/encoder/srce/sbc_enc_coeffs.c" + "host/bluedroid/external/sbc/encoder/srce/sbc_encoder.c" + "host/bluedroid/external/sbc/encoder/srce/sbc_packing.c" + "host/bluedroid/external/sbc/plc/sbc_plc.c" + "host/bluedroid/hci/hci_audio.c" + "host/bluedroid/hci/hci_hal_h4.c" + "host/bluedroid/hci/hci_layer.c" + "host/bluedroid/hci/hci_packet_factory.c" + "host/bluedroid/hci/hci_packet_parser.c" + "host/bluedroid/hci/packet_fragmenter.c" + "host/bluedroid/main/bte_init.c" + "host/bluedroid/main/bte_main.c" + "host/bluedroid/stack/a2dp/a2d_api.c" + "host/bluedroid/stack/a2dp/a2d_sbc.c" + "host/bluedroid/stack/avct/avct_api.c" + "host/bluedroid/stack/avct/avct_ccb.c" + "host/bluedroid/stack/avct/avct_l2c.c" + "host/bluedroid/stack/avct/avct_lcb.c" + "host/bluedroid/stack/avct/avct_lcb_act.c" + "host/bluedroid/stack/avdt/avdt_ad.c" + "host/bluedroid/stack/avdt/avdt_api.c" + "host/bluedroid/stack/avdt/avdt_ccb.c" + "host/bluedroid/stack/avdt/avdt_ccb_act.c" + "host/bluedroid/stack/avdt/avdt_l2c.c" + "host/bluedroid/stack/avdt/avdt_msg.c" + "host/bluedroid/stack/avdt/avdt_scb.c" + "host/bluedroid/stack/avdt/avdt_scb_act.c" + "host/bluedroid/stack/avrc/avrc_api.c" + "host/bluedroid/stack/avrc/avrc_bld_ct.c" + "host/bluedroid/stack/avrc/avrc_bld_tg.c" + "host/bluedroid/stack/avrc/avrc_opt.c" + "host/bluedroid/stack/avrc/avrc_pars_ct.c" + "host/bluedroid/stack/avrc/avrc_pars_tg.c" + "host/bluedroid/stack/avrc/avrc_sdp.c" + "host/bluedroid/stack/avrc/avrc_utils.c" + "host/bluedroid/stack/btm/btm_acl.c" + "host/bluedroid/stack/btm/btm_ble.c" + "host/bluedroid/stack/btm/btm_ble_addr.c" + "host/bluedroid/stack/btm/btm_ble_adv_filter.c" + "host/bluedroid/stack/btm/btm_ble_batchscan.c" + "host/bluedroid/stack/btm/btm_ble_bgconn.c" + "host/bluedroid/stack/btm/btm_ble_cont_energy.c" + "host/bluedroid/stack/btm/btm_ble_gap.c" + "host/bluedroid/stack/btm/btm_ble_multi_adv.c" + "host/bluedroid/stack/btm/btm_ble_privacy.c" + "host/bluedroid/stack/btm/btm_dev.c" + "host/bluedroid/stack/btm/btm_devctl.c" + "host/bluedroid/stack/btm/btm_inq.c" + "host/bluedroid/stack/btm/btm_main.c" + "host/bluedroid/stack/btm/btm_pm.c" + "host/bluedroid/stack/btm/btm_sco.c" + "host/bluedroid/stack/btm/btm_sec.c" + "host/bluedroid/stack/btu/btu_hcif.c" + "host/bluedroid/stack/btu/btu_init.c" + "host/bluedroid/stack/btu/btu_task.c" + "host/bluedroid/stack/gap/gap_api.c" + "host/bluedroid/stack/gap/gap_ble.c" + "host/bluedroid/stack/gap/gap_conn.c" + "host/bluedroid/stack/gap/gap_utils.c" + "host/bluedroid/stack/gatt/att_protocol.c" + "host/bluedroid/stack/gatt/gatt_api.c" + "host/bluedroid/stack/gatt/gatt_attr.c" + "host/bluedroid/stack/gatt/gatt_auth.c" + "host/bluedroid/stack/gatt/gatt_cl.c" + "host/bluedroid/stack/gatt/gatt_db.c" + "host/bluedroid/stack/gatt/gatt_main.c" + "host/bluedroid/stack/gatt/gatt_sr.c" + "host/bluedroid/stack/gatt/gatt_utils.c" + "host/bluedroid/stack/hcic/hciblecmds.c" + "host/bluedroid/stack/hcic/hcicmds.c" + "host/bluedroid/stack/l2cap/l2c_api.c" + "host/bluedroid/stack/l2cap/l2c_ble.c" + "host/bluedroid/stack/l2cap/l2c_csm.c" + "host/bluedroid/stack/l2cap/l2c_fcr.c" + "host/bluedroid/stack/l2cap/l2c_link.c" + "host/bluedroid/stack/l2cap/l2c_main.c" + "host/bluedroid/stack/l2cap/l2c_ucd.c" + "host/bluedroid/stack/l2cap/l2c_utils.c" + "host/bluedroid/stack/l2cap/l2cap_client.c" + "host/bluedroid/stack/rfcomm/port_api.c" + "host/bluedroid/stack/rfcomm/port_rfc.c" + "host/bluedroid/stack/rfcomm/port_utils.c" + "host/bluedroid/stack/rfcomm/rfc_l2cap_if.c" + "host/bluedroid/stack/rfcomm/rfc_mx_fsm.c" + "host/bluedroid/stack/rfcomm/rfc_port_fsm.c" + "host/bluedroid/stack/rfcomm/rfc_port_if.c" + "host/bluedroid/stack/rfcomm/rfc_ts_frames.c" + "host/bluedroid/stack/rfcomm/rfc_utils.c" + "host/bluedroid/stack/sdp/sdp_api.c" + "host/bluedroid/stack/sdp/sdp_db.c" + "host/bluedroid/stack/sdp/sdp_discovery.c" + "host/bluedroid/stack/sdp/sdp_main.c" + "host/bluedroid/stack/sdp/sdp_server.c" + "host/bluedroid/stack/sdp/sdp_utils.c" + "host/bluedroid/stack/smp/aes.c" + "host/bluedroid/stack/smp/p_256_curvepara.c" + "host/bluedroid/stack/smp/p_256_ecc_pp.c" + "host/bluedroid/stack/smp/p_256_multprecision.c" + "host/bluedroid/stack/smp/smp_act.c" + "host/bluedroid/stack/smp/smp_api.c" + "host/bluedroid/stack/smp/smp_br_main.c" + "host/bluedroid/stack/smp/smp_cmac.c" + "host/bluedroid/stack/smp/smp_keys.c" + "host/bluedroid/stack/smp/smp_l2c.c" + "host/bluedroid/stack/smp/smp_main.c" + "host/bluedroid/stack/smp/smp_utils.c") endif() -endif() -if (CONFIG_BLE_MESH) - list(APPEND include_dirs - "bluedroid/osi/include" - "ble_mesh/mesh_core" - "ble_mesh/mesh_core/include" - "ble_mesh/mesh_core/settings" - "ble_mesh/btc/include" - "ble_mesh/mesh_models/include" - "ble_mesh/api/core/include" - "ble_mesh/api/models/include" - "ble_mesh/api") + if(CONFIG_BLE_MESH) + list(APPEND include_dirs + "esp_ble_mesh/mesh_core" + "esp_ble_mesh/mesh_core/include" + "esp_ble_mesh/mesh_core/settings" + "esp_ble_mesh/btc/include" + "esp_ble_mesh/mesh_models/include" + "esp_ble_mesh/api/core/include" + "esp_ble_mesh/api/models/include" + "esp_ble_mesh/api") - list(APPEND srcs - "ble_mesh/api/core/esp_ble_mesh_common_api.c" - "ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c" - "ble_mesh/api/core/esp_ble_mesh_low_power_api.c" - "ble_mesh/api/core/esp_ble_mesh_networking_api.c" - "ble_mesh/api/core/esp_ble_mesh_provisioning_api.c" - "ble_mesh/api/core/esp_ble_mesh_proxy_api.c" - "ble_mesh/api/models/esp_ble_mesh_config_model_api.c" - "ble_mesh/api/models/esp_ble_mesh_generic_model_api.c" - "ble_mesh/api/models/esp_ble_mesh_health_model_api.c" - "ble_mesh/api/models/esp_ble_mesh_lighting_model_api.c" - "ble_mesh/api/models/esp_ble_mesh_sensor_model_api.c" - "ble_mesh/api/models/esp_ble_mesh_time_scene_model_api.c" - "ble_mesh/btc/btc_ble_mesh_config_model.c" - "ble_mesh/btc/btc_ble_mesh_generic_model.c" - "ble_mesh/btc/btc_ble_mesh_health_model.c" - "ble_mesh/btc/btc_ble_mesh_lighting_model.c" - "ble_mesh/btc/btc_ble_mesh_prov.c" - "ble_mesh/btc/btc_ble_mesh_sensor_model.c" - "ble_mesh/btc/btc_ble_mesh_time_scene_model.c" - "ble_mesh/mesh_core/settings/settings_nvs.c" - "ble_mesh/mesh_core/access.c" - "ble_mesh/mesh_core/adv.c" - "ble_mesh/mesh_core/beacon.c" - "ble_mesh/mesh_core/cfg_cli.c" - "ble_mesh/mesh_core/cfg_srv.c" - "ble_mesh/mesh_core/crypto.c" - "ble_mesh/mesh_core/friend.c" - "ble_mesh/mesh_core/health_cli.c" - "ble_mesh/mesh_core/health_srv.c" - "ble_mesh/mesh_core/lpn.c" - "ble_mesh/mesh_core/mesh_aes_encrypt.c" - "ble_mesh/mesh_core/mesh_atomic.c" - "ble_mesh/mesh_core/mesh_bearer_adapt.c" - "ble_mesh/mesh_core/mesh_buf.c" - "ble_mesh/mesh_core/mesh_hci.c" - "ble_mesh/mesh_core/mesh_kernel.c" - "ble_mesh/mesh_core/mesh_main.c" - "ble_mesh/mesh_core/mesh_util.c" - "ble_mesh/mesh_core/net.c" - "ble_mesh/mesh_core/prov.c" - "ble_mesh/mesh_core/provisioner_beacon.c" - "ble_mesh/mesh_core/provisioner_main.c" - "ble_mesh/mesh_core/provisioner_prov.c" - "ble_mesh/mesh_core/provisioner_proxy.c" - "ble_mesh/mesh_core/proxy.c" - "ble_mesh/mesh_core/settings.c" - "ble_mesh/mesh_core/test.c" - "ble_mesh/mesh_core/transport.c" - "ble_mesh/mesh_models/generic_client.c" - "ble_mesh/mesh_models/lighting_client.c" - "ble_mesh/mesh_models/mesh_common.c" - "ble_mesh/mesh_models/model_common.c" - "ble_mesh/mesh_models/sensor_client.c" - "ble_mesh/mesh_models/time_scene_client.c") + list(APPEND srcs "esp_ble_mesh/api/core/esp_ble_mesh_common_api.c" + "esp_ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c" + "esp_ble_mesh/api/core/esp_ble_mesh_low_power_api.c" + "esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c" + "esp_ble_mesh/api/core/esp_ble_mesh_provisioning_api.c" + "esp_ble_mesh/api/core/esp_ble_mesh_proxy_api.c" + "esp_ble_mesh/api/models/esp_ble_mesh_config_model_api.c" + "esp_ble_mesh/api/models/esp_ble_mesh_generic_model_api.c" + "esp_ble_mesh/api/models/esp_ble_mesh_health_model_api.c" + "esp_ble_mesh/api/models/esp_ble_mesh_lighting_model_api.c" + "esp_ble_mesh/api/models/esp_ble_mesh_sensor_model_api.c" + "esp_ble_mesh/api/models/esp_ble_mesh_time_scene_model_api.c" + "esp_ble_mesh/btc/btc_ble_mesh_config_model.c" + "esp_ble_mesh/btc/btc_ble_mesh_generic_model.c" + "esp_ble_mesh/btc/btc_ble_mesh_health_model.c" + "esp_ble_mesh/btc/btc_ble_mesh_lighting_model.c" + "esp_ble_mesh/btc/btc_ble_mesh_prov.c" + "esp_ble_mesh/btc/btc_ble_mesh_sensor_model.c" + "esp_ble_mesh/btc/btc_ble_mesh_time_scene_model.c" + "esp_ble_mesh/mesh_core/settings/settings_nvs.c" + "esp_ble_mesh/mesh_core/access.c" + "esp_ble_mesh/mesh_core/adv.c" + "esp_ble_mesh/mesh_core/beacon.c" + "esp_ble_mesh/mesh_core/cfg_cli.c" + "esp_ble_mesh/mesh_core/cfg_srv.c" + "esp_ble_mesh/mesh_core/crypto.c" + "esp_ble_mesh/mesh_core/friend.c" + "esp_ble_mesh/mesh_core/health_cli.c" + "esp_ble_mesh/mesh_core/health_srv.c" + "esp_ble_mesh/mesh_core/lpn.c" + "esp_ble_mesh/mesh_core/mesh_aes_encrypt.c" + "esp_ble_mesh/mesh_core/mesh_atomic.c" + "esp_ble_mesh/mesh_core/mesh_bearer_adapt.c" + "esp_ble_mesh/mesh_core/mesh_buf.c" + "esp_ble_mesh/mesh_core/mesh_hci.c" + "esp_ble_mesh/mesh_core/mesh_kernel.c" + "esp_ble_mesh/mesh_core/mesh_main.c" + "esp_ble_mesh/mesh_core/mesh_util.c" + "esp_ble_mesh/mesh_core/net.c" + "esp_ble_mesh/mesh_core/prov.c" + "esp_ble_mesh/mesh_core/provisioner_beacon.c" + "esp_ble_mesh/mesh_core/provisioner_main.c" + "esp_ble_mesh/mesh_core/provisioner_prov.c" + "esp_ble_mesh/mesh_core/provisioner_proxy.c" + "esp_ble_mesh/mesh_core/proxy.c" + "esp_ble_mesh/mesh_core/settings.c" + "esp_ble_mesh/mesh_core/test.c" + "esp_ble_mesh/mesh_core/transport.c" + "esp_ble_mesh/mesh_models/generic_client.c" + "esp_ble_mesh/mesh_models/lighting_client.c" + "esp_ble_mesh/mesh_models/mesh_common.c" + "esp_ble_mesh/mesh_models/model_common.c" + "esp_ble_mesh/mesh_models/sensor_client.c" + "esp_ble_mesh/mesh_models/time_scene_client.c") + endif() + + if(CONFIG_BT_NIMBLE_ENABLED) + + list(APPEND include_dirs + host/nimble/nimble/porting/nimble/include + host/nimble/port/include + host/nimble/nimble/nimble/include + host/nimble/nimble/nimble/host/include + host/nimble/nimble/nimble/host/services/ans/include + host/nimble/nimble/nimble/host/services/bas/include + host/nimble/nimble/nimble/host/services/gap/include + host/nimble/nimble/nimble/host/services/gatt/include + host/nimble/nimble/nimble/host/services/ias/include + host/nimble/nimble/nimble/host/services/lls/include + host/nimble/nimble/nimble/host/services/tps/include + host/nimble/nimble/nimble/host/util/include + host/nimble/nimble/nimble/host/store/ram/include + host/nimble/nimble/nimble/host/store/config/include + host/nimble/nimble/porting/npl/freertos/include + host/nimble/nimble/ext/tinycrypt/include + host/nimble/esp-hci/include) + + list(APPEND srcs "host/nimble/nimble/ext/tinycrypt/src/utils.c" + "host/nimble/nimble/ext/tinycrypt/src/sha256.c" + "host/nimble/nimble/ext/tinycrypt/src/ecc.c" + "host/nimble/nimble/ext/tinycrypt/src/ctr_prng.c" + "host/nimble/nimble/ext/tinycrypt/src/ctr_mode.c" + "host/nimble/nimble/ext/tinycrypt/src/aes_decrypt.c" + "host/nimble/nimble/ext/tinycrypt/src/aes_encrypt.c" + "host/nimble/nimble/ext/tinycrypt/src/ccm_mode.c" + "host/nimble/nimble/ext/tinycrypt/src/ecc_dsa.c" + "host/nimble/nimble/ext/tinycrypt/src/cmac_mode.c" + "host/nimble/nimble/ext/tinycrypt/src/ecc_dh.c" + "host/nimble/nimble/ext/tinycrypt/src/hmac_prng.c" + "host/nimble/nimble/ext/tinycrypt/src/ecc_platform_specific.c" + "host/nimble/nimble/ext/tinycrypt/src/hmac.c" + "host/nimble/nimble/ext/tinycrypt/src/cbc_mode.c" + "host/nimble/nimble/nimble/host/util/src/addr.c" + "host/nimble/nimble/nimble/host/services/gatt/src/ble_svc_gatt.c" + "host/nimble/nimble/nimble/host/services/tps/src/ble_svc_tps.c" + "host/nimble/nimble/nimble/host/services/ias/src/ble_svc_ias.c" + "host/nimble/nimble/nimble/host/services/ans/src/ble_svc_ans.c" + "host/nimble/nimble/nimble/host/services/gap/src/ble_svc_gap.c" + "host/nimble/nimble/nimble/host/services/bas/src/ble_svc_bas.c" + "host/nimble/nimble/nimble/host/services/lls/src/ble_svc_lls.c" + "host/nimble/nimble/nimble/host/src/ble_hs_conn.c" + "host/nimble/nimble/nimble/host/src/ble_store_util.c" + "host/nimble/nimble/nimble/host/src/ble_sm.c" + "host/nimble/nimble/nimble/host/src/ble_hs_shutdown.c" + "host/nimble/nimble/nimble/host/src/ble_l2cap_sig_cmd.c" + "host/nimble/nimble/nimble/host/src/ble_hs_hci_cmd.c" + "host/nimble/nimble/nimble/host/src/ble_hs_id.c" + "host/nimble/nimble/nimble/host/src/ble_att_svr.c" + "host/nimble/nimble/nimble/host/src/ble_gatts_lcl.c" + "host/nimble/nimble/nimble/host/src/ble_ibeacon.c" + "host/nimble/nimble/nimble/host/src/ble_hs_atomic.c" + "host/nimble/nimble/nimble/host/src/ble_sm_alg.c" + "host/nimble/nimble/nimble/host/src/ble_hs_stop.c" + "host/nimble/nimble/nimble/host/src/ble_hs.c" + "host/nimble/nimble/nimble/host/src/ble_hs_hci_evt.c" + "host/nimble/nimble/nimble/host/src/ble_hs_dbg.c" + "host/nimble/nimble/nimble/host/src/ble_hs_mqueue.c" + "host/nimble/nimble/nimble/host/src/ble_att.c" + "host/nimble/nimble/nimble/host/src/ble_gattc.c" + "host/nimble/nimble/nimble/host/src/ble_store.c" + "host/nimble/nimble/nimble/host/src/ble_sm_lgcy.c" + "host/nimble/nimble/nimble/host/src/ble_hs_cfg.c" + "host/nimble/nimble/nimble/host/src/ble_monitor.c" + "host/nimble/nimble/nimble/host/src/ble_att_clt.c" + "host/nimble/nimble/nimble/host/src/ble_l2cap_coc.c" + "host/nimble/nimble/nimble/host/src/ble_hs_mbuf.c" + "host/nimble/nimble/nimble/host/src/ble_att_cmd.c" + "host/nimble/nimble/nimble/host/src/ble_hs_log.c" + "host/nimble/nimble/nimble/host/src/ble_eddystone.c" + "host/nimble/nimble/nimble/host/src/ble_hs_startup.c" + "host/nimble/nimble/nimble/host/src/ble_l2cap_sig.c" + "host/nimble/nimble/nimble/host/src/ble_gap.c" + "host/nimble/nimble/nimble/host/src/ble_sm_cmd.c" + "host/nimble/nimble/nimble/host/src/ble_uuid.c" + "host/nimble/nimble/nimble/host/src/ble_hs_pvcy.c" + "host/nimble/nimble/nimble/host/src/ble_hs_flow.c" + "host/nimble/nimble/nimble/host/src/ble_l2cap.c" + "host/nimble/nimble/nimble/host/src/ble_sm_sc.c" + "host/nimble/nimble/nimble/host/src/ble_hs_misc.c" + "host/nimble/nimble/nimble/host/src/ble_gatts.c" + "host/nimble/nimble/nimble/host/src/ble_hs_adv.c" + "host/nimble/nimble/nimble/host/src/ble_hs_hci.c" + "host/nimble/nimble/nimble/host/src/ble_hs_hci_util.c" + "host/nimble/nimble/nimble/host/store/ram/src/ble_store_ram.c" + "host/nimble/nimble/nimble/host/store/config/src/ble_store_config.c" + "host/nimble/nimble/nimble/host/store/config/src/ble_store_nvs.c" + "host/nimble/nimble/nimble/src/ble_util.c" + "host/nimble/nimble/porting/npl/freertos/src/nimble_port_freertos.c" + "host/nimble/nimble/porting/npl/freertos/src/npl_os_freertos.c" + "host/nimble/nimble/porting/nimble/src/endian.c" + "host/nimble/nimble/porting/nimble/src/os_cputime_pwr2.c" + "host/nimble/nimble/porting/nimble/src/hal_timer.c" + "host/nimble/nimble/porting/nimble/src/os_mempool.c" + "host/nimble/nimble/porting/nimble/src/os_msys_init.c" + "host/nimble/nimble/porting/nimble/src/nimble_port.c" + "host/nimble/nimble/porting/nimble/src/mem.c" + "host/nimble/nimble/porting/nimble/src/os_mbuf.c" + "host/nimble/nimble/porting/nimble/src/os_cputime.c" + "host/nimble/esp-hci/src/esp_nimble_hci.c") + + if(CONFIG_BT_NIMBLE_MESH) + + list(APPEND include_dirs + host/nimble/nimble/nimble/host/mesh/include) + + list(APPEND srcs "host/nimble/nimble/nimble/host/mesh/src/shell.c" + "host/nimble/nimble/nimble/host/mesh/src/friend.c" + "host/nimble/nimble/nimble/host/mesh/src/crypto.c" + "host/nimble/nimble/nimble/host/mesh/src/settings.c" + "host/nimble/nimble/nimble/host/mesh/src/adv.c" + "host/nimble/nimble/nimble/host/mesh/src/model_srv.c" + "host/nimble/nimble/nimble/host/mesh/src/beacon.c" + "host/nimble/nimble/nimble/host/mesh/src/glue.c" + "host/nimble/nimble/nimble/host/mesh/src/model_cli.c" + "host/nimble/nimble/nimble/host/mesh/src/transport.c" + "host/nimble/nimble/nimble/host/mesh/src/prov.c" + "host/nimble/nimble/nimble/host/mesh/src/mesh.c" + "host/nimble/nimble/nimble/host/mesh/src/access.c" + "host/nimble/nimble/nimble/host/mesh/src/cfg_srv.c" + "host/nimble/nimble/nimble/host/mesh/src/cfg_cli.c" + "host/nimble/nimble/nimble/host/mesh/src/light_model.c" + "host/nimble/nimble/nimble/host/mesh/src/health_cli.c" + "host/nimble/nimble/nimble/host/mesh/src/lpn.c" + "host/nimble/nimble/nimble/host/mesh/src/proxy.c" + "host/nimble/nimble/nimble/host/mesh/src/health_srv.c" + "host/nimble/nimble/nimble/host/mesh/src/testing.c" + "host/nimble/nimble/nimble/host/mesh/src/net.c") + + endif() + endif() endif() # requirements can't depend on config @@ -367,6 +505,6 @@ if(CONFIG_BT_ENABLED) target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-implicit-fallthrough -Wno-unused-const-variable) endif() - target_link_libraries(${COMPONENT_LIB} INTERFACE "-L${CMAKE_CURRENT_LIST_DIR}/lib") + target_link_libraries(${COMPONENT_LIB} INTERFACE "-L${CMAKE_CURRENT_LIST_DIR}/controller/lib") target_link_libraries(${COMPONENT_LIB} PUBLIC btdm_app) endif() diff --git a/components/bt/Kconfig b/components/bt/Kconfig index 15286d05f9..8553cc9f70 100644 --- a/components/bt/Kconfig +++ b/components/bt/Kconfig @@ -383,1810 +383,22 @@ menu Bluetooth menu "Bluedroid Options" visible if BT_BLUEDROID_ENABLED - choice BT_BLUEDROID_PINNED_TO_CORE_CHOICE - prompt "The cpu core which Bluedroid run" - depends on BT_BLUEDROID_ENABLED && !FREERTOS_UNICORE - help - Which the cpu core to run Bluedroid. Can choose core0 and core1. - Can not specify no-affinity. - - config BT_BLUEDROID_PINNED_TO_CORE_0 - bool "Core 0 (PRO CPU)" - config BT_BLUEDROID_PINNED_TO_CORE_1 - bool "Core 1 (APP CPU)" - depends on !FREERTOS_UNICORE - endchoice - - config BT_BLUEDROID_PINNED_TO_CORE - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_BLUEDROID_PINNED_TO_CORE_0 - default 1 if BT_BLUEDROID_PINNED_TO_CORE_1 - default 0 - - config BT_BTC_TASK_STACK_SIZE - int "Bluetooth event (callback to application) task stack size" - depends on BT_BLUEDROID_ENABLED - default 3072 - help - This select btc task stack size - - config BT_BTU_TASK_STACK_SIZE - int "Bluetooth Bluedroid Host Stack task stack size" - depends on BT_BLUEDROID_ENABLED - default 4096 - help - This select btu task stack size - - config BT_BLUEDROID_MEM_DEBUG - bool "Bluedroid memory debug" - depends on BT_BLUEDROID_ENABLED - default n - help - Bluedroid memory debug - - config BT_CLASSIC_ENABLED - bool "Classic Bluetooth" - depends on BT_BLUEDROID_ENABLED - default n - help - For now this option needs "SMP_ENABLE" to be set to yes - - config BT_A2DP_ENABLE - bool "A2DP" - depends on BT_CLASSIC_ENABLED - default n - help - Advanced Audio Distrubution Profile - - config BT_A2DP_SINK_TASK_STACK_SIZE - int "A2DP sink (audio stream decoding) task stack size" - depends on BT_A2DP_ENABLE - default 2048 - - config BT_A2DP_SOURCE_TASK_STACK_SIZE - int "A2DP source (audio stream encoding) task stack size" - depends on BT_A2DP_ENABLE - default 2048 - - config BT_SPP_ENABLED - bool "SPP" - depends on BT_CLASSIC_ENABLED - default n - help - This enables the Serial Port Profile - - config BT_HFP_ENABLE - bool "Hands Free/Handset Profile" - depends on BT_CLASSIC_ENABLED - default n - - choice BT_HFP_ROLE - prompt "Hands-free Profile Role configuration" - depends on BT_HFP_ENABLE - - config BT_HFP_CLIENT_ENABLE - bool "Hands Free Unit" - endchoice - - choice BT_HFP_AUDIO_DATA_PATH - prompt "audio(SCO) data path" - depends on BT_HFP_ENABLE - help - SCO data path, i.e. HCI or PCM. This option is set using API - "esp_bredr_sco_datapath_set" in Bluetooth host. Default SCO data - path can also be set in Bluetooth Controller. - - config BT_HFP_AUDIO_DATA_PATH_PCM - bool "PCM" - config BT_HFP_AUDIO_DATA_PATH_HCI - bool "HCI" - endchoice - - config BT_SSP_ENABLED - bool "Secure Simple Pairing" - depends on BT_CLASSIC_ENABLED - default y - help - This enables the Secure Simple Pairing. If disable this option, - Bluedroid will only support Legacy Pairing - - config BT_BLE_ENABLED - bool "Bluetooth Low Energy" - depends on BT_BLUEDROID_ENABLED - default y - help - This enables Bluetooth Low Energy - - config BT_GATTS_ENABLE - bool "Include GATT server module(GATTS)" - depends on BT_BLE_ENABLED - default y - help - This option can be disabled when the app work only on gatt client mode - - choice BT_GATTS_SEND_SERVICE_CHANGE_MODE - prompt "GATTS Service Change Mode" - default BT_GATTS_SEND_SERVICE_CHANGE_AUTO - depends on BT_GATTS_ENABLE - help - Service change indication mode for GATT Server. - - config BT_GATTS_SEND_SERVICE_CHANGE_MANUAL - bool "GATTS manually send service change indication" - help - Manually send service change indication through API esp_ble_gatts_send_service_change_indication() - - config BT_GATTS_SEND_SERVICE_CHANGE_AUTO - bool "GATTS automatically send service change indication" - help - Let Bluedroid handle the service change indication internally - - endchoice - - config BT_GATTS_SEND_SERVICE_CHANGE_MODE - int - depends on BT_GATTS_ENABLE - default 0 if BT_GATTS_SEND_SERVICE_CHANGE_AUTO - default 1 if BT_GATTS_SEND_SERVICE_CHANGE_MANUAL - default 0 - - config BT_GATTC_ENABLE - bool "Include GATT client module(GATTC)" - depends on BT_BLE_ENABLED - default y - help - This option can be close when the app work only on gatt server mode - - config BT_GATTC_CACHE_NVS_FLASH - bool "Save gattc cache data to nvs flash" - depends on BT_GATTC_ENABLE - default n - help - This select can save gattc cache data to nvs flash - - config BT_BLE_SMP_ENABLE - bool "Include BLE security module(SMP)" - depends on BT_BLE_ENABLED - default y - help - This option can be close when the app not used the ble security connect. - - config BT_SMP_SLAVE_CON_PARAMS_UPD_ENABLE - bool "Slave enable connection parameters update during pairing" - depends on BT_BLE_SMP_ENABLE - default n - help - In order to reduce the pairing time, slave actively initiates connection parameters - update during pairing. - - config BT_STACK_NO_LOG - bool "Disable BT debug logs (minimize bin size)" - depends on BT_BLUEDROID_ENABLED - default n - help - This select can save the rodata code size - - menu "BT DEBUG LOG LEVEL" - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - - choice BT_LOG_HCI_TRACE_LEVEL - prompt "HCI layer" - default BT_LOG_HCI_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for HCI layer - - config BT_LOG_HCI_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_HCI_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_HCI_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_HCI_TRACE_LEVEL_API - bool "API" - config BT_LOG_HCI_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_HCI_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_HCI_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_HCI_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_HCI_TRACE_LEVEL_NONE - default 1 if BT_LOG_HCI_TRACE_LEVEL_ERROR - default 2 if BT_LOG_HCI_TRACE_LEVEL_WARNING - default 3 if BT_LOG_HCI_TRACE_LEVEL_API - default 4 if BT_LOG_HCI_TRACE_LEVEL_EVENT - default 5 if BT_LOG_HCI_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_HCI_TRACE_LEVEL_VERBOSE - default 2 - - choice BT_LOG_BTM_TRACE_LEVEL - prompt "BTM layer" - default BT_LOG_BTM_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for BTM layer - - config BT_LOG_BTM_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_BTM_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_BTM_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_BTM_TRACE_LEVEL_API - bool "API" - config BT_LOG_BTM_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_BTM_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_BTM_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_BTM_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_BTM_TRACE_LEVEL_NONE - default 1 if BT_LOG_BTM_TRACE_LEVEL_ERROR - default 2 if BT_LOG_BTM_TRACE_LEVEL_WARNING - default 3 if BT_LOG_BTM_TRACE_LEVEL_API - default 4 if BT_LOG_BTM_TRACE_LEVEL_EVENT - default 5 if BT_LOG_BTM_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_BTM_TRACE_LEVEL_VERBOSE - default 2 - - choice BT_LOG_L2CAP_TRACE_LEVEL - prompt "L2CAP layer" - default BT_LOG_L2CAP_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for L2CAP layer - - config BT_LOG_L2CAP_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_L2CAP_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_L2CAP_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_L2CAP_TRACE_LEVEL_API - bool "API" - config BT_LOG_L2CAP_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_L2CAP_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_L2CAP_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_L2CAP_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_L2CAP_TRACE_LEVEL_NONE - default 1 if BT_LOG_L2CAP_TRACE_LEVEL_ERROR - default 2 if BT_LOG_L2CAP_TRACE_LEVEL_WARNING - default 3 if BT_LOG_L2CAP_TRACE_LEVEL_API - default 4 if BT_LOG_L2CAP_TRACE_LEVEL_EVENT - default 5 if BT_LOG_L2CAP_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_L2CAP_TRACE_LEVEL_VERBOSE - default 2 - - choice BT_LOG_RFCOMM_TRACE_LEVEL - prompt "RFCOMM layer" - default BT_LOG_RFCOMM_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for RFCOMM layer - - config BT_LOG_RFCOMM_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_RFCOMM_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_RFCOMM_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_RFCOMM_TRACE_LEVEL_API - bool "API" - config BT_LOG_RFCOMM_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_RFCOMM_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_RFCOMM_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_RFCOMM_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_RFCOMM_TRACE_LEVEL_NONE - default 1 if BT_LOG_RFCOMM_TRACE_LEVEL_ERROR - default 2 if BT_LOG_RFCOMM_TRACE_LEVEL_WARNING - default 3 if BT_LOG_RFCOMM_TRACE_LEVEL_API - default 4 if BT_LOG_RFCOMM_TRACE_LEVEL_EVENT - default 5 if BT_LOG_RFCOMM_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_RFCOMM_TRACE_LEVEL_VERBOSE - default 2 - - choice BT_LOG_SDP_TRACE_LEVEL - prompt "SDP layer" - default BT_LOG_SDP_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for SDP layer - - config BT_LOG_SDP_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_SDP_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_SDP_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_SDP_TRACE_LEVEL_API - bool "API" - config BT_LOG_SDP_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_SDP_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_SDP_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_SDP_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_SDP_TRACE_LEVEL_NONE - default 1 if BT_LOG_SDP_TRACE_LEVEL_ERROR - default 2 if BT_LOG_SDP_TRACE_LEVEL_WARNING - default 3 if BT_LOG_SDP_TRACE_LEVEL_API - default 4 if BT_LOG_SDP_TRACE_LEVEL_EVENT - default 5 if BT_LOG_SDP_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_SDP_TRACE_LEVEL_VERBOSE - default 2 - - choice BT_LOG_GAP_TRACE_LEVEL - prompt "GAP layer" - default BT_LOG_GAP_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for GAP layer - - config BT_LOG_GAP_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_GAP_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_GAP_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_GAP_TRACE_LEVEL_API - bool "API" - config BT_LOG_GAP_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_GAP_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_GAP_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_GAP_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_GAP_TRACE_LEVEL_NONE - default 1 if BT_LOG_GAP_TRACE_LEVEL_ERROR - default 2 if BT_LOG_GAP_TRACE_LEVEL_WARNING - default 3 if BT_LOG_GAP_TRACE_LEVEL_API - default 4 if BT_LOG_GAP_TRACE_LEVEL_EVENT - default 5 if BT_LOG_GAP_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_GAP_TRACE_LEVEL_VERBOSE - default 2 - - choice BT_LOG_BNEP_TRACE_LEVEL - prompt "BNEP layer" - default BT_LOG_BNEP_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for BNEP layer - - config BT_LOG_BNEP_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_BNEP_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_BNEP_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_BNEP_TRACE_LEVEL_API - bool "API" - config BT_LOG_BNEP_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_BNEP_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_BNEP_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_BNEP_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_BNEP_TRACE_LEVEL_NONE - default 1 if BT_LOG_BNEP_TRACE_LEVEL_ERROR - default 2 if BT_LOG_BNEP_TRACE_LEVEL_WARNING - default 3 if BT_LOG_BNEP_TRACE_LEVEL_API - default 4 if BT_LOG_BNEP_TRACE_LEVEL_EVENT - default 5 if BT_LOG_BNEP_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_BNEP_TRACE_LEVEL_VERBOSE - default 2 - - choice BT_LOG_PAN_TRACE_LEVEL - prompt "PAN layer" - default BT_LOG_PAN_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for PAN layer - - config BT_LOG_PAN_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_PAN_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_PAN_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_PAN_TRACE_LEVEL_API - bool "API" - config BT_LOG_PAN_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_PAN_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_PAN_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_PAN_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_PAN_TRACE_LEVEL_NONE - default 1 if BT_LOG_PAN_TRACE_LEVEL_ERROR - default 2 if BT_LOG_PAN_TRACE_LEVEL_WARNING - default 3 if BT_LOG_PAN_TRACE_LEVEL_API - default 4 if BT_LOG_PAN_TRACE_LEVEL_EVENT - default 5 if BT_LOG_PAN_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_PAN_TRACE_LEVEL_VERBOSE - default 2 - - choice BT_LOG_A2D_TRACE_LEVEL - prompt "A2D layer" - default BT_LOG_A2D_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for A2D layer - - config BT_LOG_A2D_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_A2D_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_A2D_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_A2D_TRACE_LEVEL_API - bool "API" - config BT_LOG_A2D_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_A2D_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_A2D_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_A2D_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_A2D_TRACE_LEVEL_NONE - default 1 if BT_LOG_A2D_TRACE_LEVEL_ERROR - default 2 if BT_LOG_A2D_TRACE_LEVEL_WARNING - default 3 if BT_LOG_A2D_TRACE_LEVEL_API - default 4 if BT_LOG_A2D_TRACE_LEVEL_EVENT - default 5 if BT_LOG_A2D_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_A2D_TRACE_LEVEL_VERBOSE - default 2 - - choice BT_LOG_AVDT_TRACE_LEVEL - prompt "AVDT layer" - default BT_LOG_AVDT_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for AVDT layer - - config BT_LOG_AVDT_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_AVDT_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_AVDT_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_AVDT_TRACE_LEVEL_API - bool "API" - config BT_LOG_AVDT_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_AVDT_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_AVDT_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_AVDT_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_AVDT_TRACE_LEVEL_NONE - default 1 if BT_LOG_AVDT_TRACE_LEVEL_ERROR - default 2 if BT_LOG_AVDT_TRACE_LEVEL_WARNING - default 3 if BT_LOG_AVDT_TRACE_LEVEL_API - default 4 if BT_LOG_AVDT_TRACE_LEVEL_EVENT - default 5 if BT_LOG_AVDT_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_AVDT_TRACE_LEVEL_VERBOSE - default 2 - - choice BT_LOG_AVCT_TRACE_LEVEL - prompt "AVCT layer" - default BT_LOG_AVCT_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for AVCT layer - - config BT_LOG_AVCT_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_AVCT_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_AVCT_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_AVCT_TRACE_LEVEL_API - bool "API" - config BT_LOG_AVCT_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_AVCT_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_AVCT_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_AVCT_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_AVCT_TRACE_LEVEL_NONE - default 1 if BT_LOG_AVCT_TRACE_LEVEL_ERROR - default 2 if BT_LOG_AVCT_TRACE_LEVEL_WARNING - default 3 if BT_LOG_AVCT_TRACE_LEVEL_API - default 4 if BT_LOG_AVCT_TRACE_LEVEL_EVENT - default 5 if BT_LOG_AVCT_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_AVCT_TRACE_LEVEL_VERBOSE - default 2 - - choice BT_LOG_AVRC_TRACE_LEVEL - prompt "AVRC layer" - default BT_LOG_AVRC_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for AVRC layer - - config BT_LOG_AVRC_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_AVRC_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_AVRC_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_AVRC_TRACE_LEVEL_API - bool "API" - config BT_LOG_AVRC_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_AVRC_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_AVRC_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_AVRC_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_AVRC_TRACE_LEVEL_NONE - default 1 if BT_LOG_AVRC_TRACE_LEVEL_ERROR - default 2 if BT_LOG_AVRC_TRACE_LEVEL_WARNING - default 3 if BT_LOG_AVRC_TRACE_LEVEL_API - default 4 if BT_LOG_AVRC_TRACE_LEVEL_EVENT - default 5 if BT_LOG_AVRC_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_AVRC_TRACE_LEVEL_VERBOSE - default 2 - - choice BT_LOG_MCA_TRACE_LEVEL - prompt "MCA layer" - default BT_LOG_MCA_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for MCA layer - - config BT_LOG_MCA_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_MCA_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_MCA_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_MCA_TRACE_LEVEL_API - bool "API" - config BT_LOG_MCA_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_MCA_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_MCA_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_MCA_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_MCA_TRACE_LEVEL_NONE - default 1 if BT_LOG_MCA_TRACE_LEVEL_ERROR - default 2 if BT_LOG_MCA_TRACE_LEVEL_WARNING - default 3 if BT_LOG_MCA_TRACE_LEVEL_API - default 4 if BT_LOG_MCA_TRACE_LEVEL_EVENT - default 5 if BT_LOG_MCA_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_MCA_TRACE_LEVEL_VERBOSE - default 2 - - choice BT_LOG_HID_TRACE_LEVEL - prompt "HID layer" - default BT_LOG_HID_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for HID layer - - config BT_LOG_HID_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_HID_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_HID_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_HID_TRACE_LEVEL_API - bool "API" - config BT_LOG_HID_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_HID_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_HID_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_HID_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_HID_TRACE_LEVEL_NONE - default 1 if BT_LOG_HID_TRACE_LEVEL_ERROR - default 2 if BT_LOG_HID_TRACE_LEVEL_WARNING - default 3 if BT_LOG_HID_TRACE_LEVEL_API - default 4 if BT_LOG_HID_TRACE_LEVEL_EVENT - default 5 if BT_LOG_HID_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_HID_TRACE_LEVEL_VERBOSE - default 2 - - choice BT_LOG_APPL_TRACE_LEVEL - prompt "APPL layer" - default BT_LOG_APPL_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for APPL layer - - config BT_LOG_APPL_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_APPL_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_APPL_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_APPL_TRACE_LEVEL_API - bool "API" - config BT_LOG_APPL_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_APPL_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_APPL_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_APPL_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_APPL_TRACE_LEVEL_NONE - default 1 if BT_LOG_APPL_TRACE_LEVEL_ERROR - default 2 if BT_LOG_APPL_TRACE_LEVEL_WARNING - default 3 if BT_LOG_APPL_TRACE_LEVEL_API - default 4 if BT_LOG_APPL_TRACE_LEVEL_EVENT - default 5 if BT_LOG_APPL_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_APPL_TRACE_LEVEL_VERBOSE - default 2 - - choice BT_LOG_GATT_TRACE_LEVEL - prompt "GATT layer" - default BT_LOG_GATT_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for GATT layer - - config BT_LOG_GATT_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_GATT_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_GATT_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_GATT_TRACE_LEVEL_API - bool "API" - config BT_LOG_GATT_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_GATT_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_GATT_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_GATT_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_GATT_TRACE_LEVEL_NONE - default 1 if BT_LOG_GATT_TRACE_LEVEL_ERROR - default 2 if BT_LOG_GATT_TRACE_LEVEL_WARNING - default 3 if BT_LOG_GATT_TRACE_LEVEL_API - default 4 if BT_LOG_GATT_TRACE_LEVEL_EVENT - default 5 if BT_LOG_GATT_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_GATT_TRACE_LEVEL_VERBOSE - default 2 - - choice BT_LOG_SMP_TRACE_LEVEL - prompt "SMP layer" - default BT_LOG_SMP_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for SMP layer - - config BT_LOG_SMP_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_SMP_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_SMP_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_SMP_TRACE_LEVEL_API - bool "API" - config BT_LOG_SMP_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_SMP_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_SMP_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_SMP_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_SMP_TRACE_LEVEL_NONE - default 1 if BT_LOG_SMP_TRACE_LEVEL_ERROR - default 2 if BT_LOG_SMP_TRACE_LEVEL_WARNING - default 3 if BT_LOG_SMP_TRACE_LEVEL_API - default 4 if BT_LOG_SMP_TRACE_LEVEL_EVENT - default 5 if BT_LOG_SMP_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_SMP_TRACE_LEVEL_VERBOSE - default 2 - - choice BT_LOG_BTIF_TRACE_LEVEL - prompt "BTIF layer" - default BT_LOG_BTIF_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for BTIF layer - - config BT_LOG_BTIF_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_BTIF_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_BTIF_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_BTIF_TRACE_LEVEL_API - bool "API" - config BT_LOG_BTIF_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_BTIF_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_BTIF_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_BTIF_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_BTIF_TRACE_LEVEL_NONE - default 1 if BT_LOG_BTIF_TRACE_LEVEL_ERROR - default 2 if BT_LOG_BTIF_TRACE_LEVEL_WARNING - default 3 if BT_LOG_BTIF_TRACE_LEVEL_API - default 4 if BT_LOG_BTIF_TRACE_LEVEL_EVENT - default 5 if BT_LOG_BTIF_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_BTIF_TRACE_LEVEL_VERBOSE - default 2 - - choice BT_LOG_BTC_TRACE_LEVEL - prompt "BTC layer" - default BT_LOG_BTC_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for BTC layer - - config BT_LOG_BTC_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_BTC_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_BTC_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_BTC_TRACE_LEVEL_API - bool "API" - config BT_LOG_BTC_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_BTC_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_BTC_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_BTC_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_BTC_TRACE_LEVEL_NONE - default 1 if BT_LOG_BTC_TRACE_LEVEL_ERROR - default 2 if BT_LOG_BTC_TRACE_LEVEL_WARNING - default 3 if BT_LOG_BTC_TRACE_LEVEL_API - default 4 if BT_LOG_BTC_TRACE_LEVEL_EVENT - default 5 if BT_LOG_BTC_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_BTC_TRACE_LEVEL_VERBOSE - default 2 - - choice BT_LOG_OSI_TRACE_LEVEL - prompt "OSI layer" - default BT_LOG_OSI_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for OSI layer - - config BT_LOG_OSI_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_OSI_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_OSI_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_OSI_TRACE_LEVEL_API - bool "API" - config BT_LOG_OSI_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_OSI_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_OSI_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_OSI_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_OSI_TRACE_LEVEL_NONE - default 1 if BT_LOG_OSI_TRACE_LEVEL_ERROR - default 2 if BT_LOG_OSI_TRACE_LEVEL_WARNING - default 3 if BT_LOG_OSI_TRACE_LEVEL_API - default 4 if BT_LOG_OSI_TRACE_LEVEL_EVENT - default 5 if BT_LOG_OSI_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_OSI_TRACE_LEVEL_VERBOSE - default 2 - - choice BT_LOG_BLUFI_TRACE_LEVEL - prompt "BLUFI layer" - default BT_LOG_BLUFI_TRACE_LEVEL_WARNING - depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG - help - Define BT trace level for BLUFI layer - - config BT_LOG_BLUFI_TRACE_LEVEL_NONE - bool "NONE" - config BT_LOG_BLUFI_TRACE_LEVEL_ERROR - bool "ERROR" - config BT_LOG_BLUFI_TRACE_LEVEL_WARNING - bool "WARNING" - config BT_LOG_BLUFI_TRACE_LEVEL_API - bool "API" - config BT_LOG_BLUFI_TRACE_LEVEL_EVENT - bool "EVENT" - config BT_LOG_BLUFI_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BT_LOG_BLUFI_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BT_LOG_BLUFI_TRACE_LEVEL - int - depends on BT_BLUEDROID_ENABLED - default 0 if BT_LOG_BLUFI_TRACE_LEVEL_NONE - default 1 if BT_LOG_BLUFI_TRACE_LEVEL_ERROR - default 2 if BT_LOG_BLUFI_TRACE_LEVEL_WARNING - default 3 if BT_LOG_BLUFI_TRACE_LEVEL_API - default 4 if BT_LOG_BLUFI_TRACE_LEVEL_EVENT - default 5 if BT_LOG_BLUFI_TRACE_LEVEL_DEBUG - default 6 if BT_LOG_BLUFI_TRACE_LEVEL_VERBOSE - default 2 - - endmenu #BT DEBUG LOG LEVEL - - - config BT_ACL_CONNECTIONS - int "BT/BLE MAX ACL CONNECTIONS(1~7)" - depends on BT_BLUEDROID_ENABLED - range 1 7 - default 4 - help - Maximum BT/BLE connection count - - config BT_ALLOCATION_FROM_SPIRAM_FIRST - bool "BT/BLE will first malloc the memory from the PSRAM" - depends on BT_BLUEDROID_ENABLED - default n - help - This select can save the internal RAM if there have the PSRAM - - config BT_BLE_DYNAMIC_ENV_MEMORY - bool "Use dynamic memory allocation in BT/BLE stack" - depends on BT_BLUEDROID_ENABLED - default n - help - This select can make the allocation of memory will become more flexible - - config BT_BLE_HOST_QUEUE_CONG_CHECK - bool "BLE queue congestion check" - depends on BT_BLUEDROID_ENABLED - default n - help - When scanning and scan duplicate is not enabled, if there are a lot of adv packets around - or application layer handling adv packets is slow, it will cause the controller memory - to run out. if enabled, adv packets will be lost when host queue is congested. - - config BT_SMP_ENABLE - bool - depends on BT_BLUEDROID_ENABLED - default BT_CLASSIC_ENABLED || BT_BLE_SMP_ENABLE - - config BT_BLE_ACT_SCAN_REP_ADV_SCAN - bool "Report adv data and scan response individually when BLE active scan" - depends on BT_BLUEDROID_ENABLED && (BTDM_CTRL_MODE_BTDM || BTDM_CTRL_MODE_BLE_ONLY) - default n - help - Originally, when doing BLE active scan, Bluedroid will not report adv to application layer - until receive scan response. This option is used to disable the behavior. When enable this option, - Bluedroid will report adv data or scan response to application layer immediately. - - # Memory reserved at start of DRAM for Bluetooth stack - - config BT_BLE_ESTAB_LINK_CONN_TOUT - int "Timeout of BLE connection establishment" - depends on BT_BLUEDROID_ENABLED - range 1 60 - default 30 - help - Bluetooth Connection establishment maximum time, if connection time exceeds this value, the connection - establishment fails, ESP_GATTC_OPEN_EVT or ESP_GATTS_OPEN_EVT is triggered. - - config BT_RESERVE_DRAM - hex - default 0xdb5c if BT_ENABLED - default 0 - + source "$IDF_PATH/components/bt/host/bluedroid/Kconfig.in" endmenu - menu "NimBLE Options" visible if BT_NIMBLE_ENABLED - source "$IDF_PATH/components/nimble/Kconfig.in" + source "$IDF_PATH/components/bt/host/nimble/Kconfig.in" endmenu endmenu menuconfig BLE_MESH - bool "BLE Mesh Support" + bool "ESP BLE Mesh Support" depends on BT_BLUEDROID_ENABLED help - This option enables BLE Mesh support. The specific features that are + This option enables ESP BLE Mesh support. The specific features that are available may depend on other features that have been enabled in the stack, such as Bluetooth Support, Bluedroid Support & GATT support. -if BLE_MESH - - config BLE_MESH_HCI_5_0 - bool "Support sending 20ms non-connectable adv packets" - default y - help - It is a temporary solution and needs further modifications. - - config BLE_MESH_USE_DUPLICATE_SCAN - bool "Support Duplicate Scan in BLE Mesh" - select BLE_SCAN_DUPLICATE - select BLE_MESH_SCAN_DUPLICATE_EN - default y - help - Enable this option to allow using specific duplicate scan filter - in BLE Mesh, and Scan Duplicate Type must be set to 0x02. - - config BLE_MESH_FAST_PROV - bool "Enable BLE Mesh Fast Provisioning" - select BLE_MESH_NODE - select BLE_MESH_PROVISIONER - select BLE_MESH_PB_ADV - default n - help - Enable this option to allow BLE Mesh fast provisioning solution to be used. - - config BLE_MESH_NODE - bool "Support for BLE Mesh Node" - help - Enable the device to be provisioned into a node. - - config BLE_MESH_PROVISIONER - bool "Support for BLE Mesh Provisioner" - help - Enable the device to be a provisioner. - - if BLE_MESH_PROVISIONER - - config BLE_MESH_WAIT_FOR_PROV_MAX_DEV_NUM - int "Maximum number of unprovisioned devices that can be added to device queue" - default 20 - range 1 100 - help - This option specifies how may unprovisioned devices can be added to device - queue for provisioning. - - config BLE_MESH_MAX_STORED_NODES - int "Maximum number of nodes whose information can be stored" - default 20 - range 1 1000 - help - This option specifies the maximum number of nodes whose information can be - stored by a provisioner in its upper layer. - - config BLE_MESH_MAX_PROV_NODES - int "Maximum number of devices that can be provisioned by provisioner" - default 20 - range 1 100 - help - This option specifies how many devices can be provisioned by provisioner. - - if BLE_MESH_PB_ADV - config BLE_MESH_PBA_SAME_TIME - int "Maximum number of PB-ADV running at the same time by provisioner" - default 2 - range 1 10 - help - This option specifies how many devices can be provisioned at the same - time using PB-ADV. - endif # BLE_MESH_PB_ADV - - if BLE_MESH_PB_GATT - config BLE_MESH_PBG_SAME_TIME - int "Maximum number of PB-GATT running at the same time by provisioner" - default 1 - range 1 5 - help - This option specifies how many devices can be provisioned at the same - time using PB-GATT. - endif # BLE_MESH_PB_GATT - - config BLE_MESH_PROVISIONER_SUBNET_COUNT - int "Maximum number of mesh subnets that can be created by provisioner" - default 3 - range 1 4096 - help - This option specifies how many subnets per network a provisioner can create. - - config BLE_MESH_PROVISIONER_APP_KEY_COUNT - int "Maximum number of application keys that can be owned by provisioner" - default 9 - range 1 4096 - help - This option specifies how many application keys the provisioner can have. - - endif # BLE_MESH_PROVISIONER - - # Virtual option enabled whenever Generic Provisioning layer is needed - config BLE_MESH_PROV - bool "BLE Mesh Provisioning support" - default y - help - Enable this option to support BLE Mesh Provisioning functionality. For - BLE Mesh, this option should be always enabled. - - config BLE_MESH_PB_ADV - bool "Provisioning support using the advertising bearer (PB-ADV)" - select BLE_MESH_PROV - default y - help - Enable this option to allow the device to be provisioned over the - advertising bearer. - - config BLE_MESH_PB_GATT - bool "Provisioning support using GATT (PB-GATT)" - select BLE_MESH_PROXY - select BLE_MESH_PROV - help - Enable this option to allow the device to be provisioned over GATT. - - # Virtual option enabled whenever any Proxy protocol is needed - config BLE_MESH_PROXY - bool "BLE Mesh Proxy protocol support" - default y - help - Enable this option to support BLE Mesh Proxy protocol used by PB-GATT - and other proxy pdu transmission. - - config BLE_MESH_GATT_PROXY - bool "BLE Mesh GATT Proxy Service" - select BLE_MESH_PROXY - help - This option enables support for Mesh GATT Proxy Service, i.e. the - ability to act as a proxy between a Mesh GATT Client and a Mesh network. - - config BLE_MESH_NODE_ID_TIMEOUT - int "Node Identity advertising timeout" - depends on BLE_MESH_GATT_PROXY - range 1 60 - default 60 - help - This option determines for how long the local node advertises using - Node Identity. The given value is in seconds. The specification limits - this to 60 seconds and lists it as the recommended value as well. - So leaving the default value is the safest option. - - if BLE_MESH_PROXY - - config BLE_MESH_PROXY_FILTER_SIZE - int "Maximum number of filter entries per Proxy Client" - default 1 - default 3 if BLE_MESH_GATT_PROXY - range 1 32767 - help - This option specifies how many Proxy Filter entries the local node supports. - - endif # BLE_MESH_PROXY - - config BLE_MESH_NET_BUF_POOL_USAGE - bool "BLE Mesh net buffer pool usage tracking" - default y - help - Enable BLE Mesh net buffer pool tracking. - - config BLE_MESH_SETTINGS - bool "Store BLE Mesh Node configuration persistently" - default n - help - When selected, the BLE Mesh stack will take care of storing/restoring the - BLE Mesh configuration persistently in flash. Currently this only supports - storing BLE Mesh node configuration. - - if BLE_MESH_SETTINGS - config BLE_MESH_STORE_TIMEOUT - int "Delay (in seconds) before storing anything persistently" - range 0 1000000 - default 0 - help - This value defines in seconds how soon any pending changes are actually - written into persistent storage (flash) after a change occurs. - - config BLE_MESH_SEQ_STORE_RATE - int "How often the sequence number gets updated in storage" - range 0 1000000 - default 128 - help - This value defines how often the local sequence number gets updated in - persistent storage (i.e. flash). e.g. a value of 100 means that the - sequence number will be stored to flash on every 100th increment. - If the node sends messages very frequently a higher value makes more - sense, whereas if the node sends infrequently a value as low as 0 - (update storage for every increment) can make sense. When the stack - gets initialized it will add sequence number to the last stored one, - so that it starts off with a value that's guaranteed to be larger than - the last one used before power off. - - config BLE_MESH_RPL_STORE_TIMEOUT - int "Minimum frequency that the RPL gets updated in storage" - range 0 1000000 - default 5 - help - This value defines in seconds how soon the RPL(Replay Protection List) - gets written to persistent storage after a change occurs. If the node - receives messages frequently, then a large value is recommended. If the - node receives messages rarely, then the value can be as low as 0 (which - means the PRL is written into the storage immediately). - Note that if the node operates in a security-sensitive case, and there is - a risk of sudden power-off, then a value of 0 is strongly recommended. - Otherwise, a power loss before RPL being written into the storage may - introduce message replay attacks and system security will be in a - vulnerable state. - endif # if BLE_MESH_SETTINGS - - config BLE_MESH_SUBNET_COUNT - int "Maximum number of mesh subnets per network" - default 3 - range 1 4096 - help - This option specifies how many subnets a Mesh network can have at the same time. - - config BLE_MESH_APP_KEY_COUNT - int "Maximum number of application keys per network" - default 3 - range 1 4096 - help - This option specifies how many application keys the device can store per network. - - config BLE_MESH_MODEL_KEY_COUNT - int "Maximum number of application keys per model" - default 3 - range 1 4096 - help - This option specifies the maximum number of application keys to which each model - can be bound. - - config BLE_MESH_MODEL_GROUP_COUNT - int "Maximum number of group address subscriptions per model" - default 3 - range 1 4096 - help - This option specifies the maximum number of addresses to which each model can - be subscribed. - - config BLE_MESH_LABEL_COUNT - int "Maximum number of Label UUIDs used for Virtual Addresses" - default 3 - range 0 4096 - help - This option specifies how many Label UUIDs can be stored. - - config BLE_MESH_CRPL - int "Maximum capacity of the replay protection list" - default 10 - range 2 65535 - help - This option specifies the maximum capacity of the replay protection list. - It is similar to Network message cache size, but has a different purpose. - - config BLE_MESH_MSG_CACHE_SIZE - int "Network message cache size" - default 10 - range 2 65535 - help - Number of messages that are cached for the network. This helps prevent - unnecessary decryption operations and unnecessary relays. This option - is similar to Replay protection list, but has a different purpose. - - config BLE_MESH_ADV_BUF_COUNT - int "Number of advertising buffers" - default 60 - range 6 256 - help - Number of advertising buffers available. The transport layer reserves - ADV_BUF_COUNT - 3 buffers for outgoing segments. The maximum outgoing - SDU size is 12 times this value (out of which 4 or 8 bytes are used - for the Transport Layer MIC). For example, 5 segments means the maximum - SDU size is 60 bytes, which leaves 56 bytes for application layer data - using a 4-byte MIC, or 52 bytes using an 8-byte MIC. - - config BLE_MESH_IVU_DIVIDER - int "Divider for IV Update state refresh timer" - default 4 - range 2 96 - help - When the IV Update state enters Normal operation or IV Update - in Progress, we need to keep track of how many hours has passed - in the state, since the specification requires us to remain in - the state at least for 96 hours (Update in Progress has an - additional upper limit of 144 hours). - - In order to fulfill the above requirement, even if the node might - be powered off once in a while, we need to store persistently - how many hours the node has been in the state. This doesn't - necessarily need to happen every hour (thanks to the flexible - duration range). The exact cadence will depend a lot on the - ways that the node will be used and what kind of power source it - has. - - Since there is no single optimal answer, this configuration - option allows specifying a divider, i.e. how many intervals - the 96 hour minimum gets split into. After each interval the - duration that the node has been in the current state gets - stored to flash. E.g. the default value of 4 means that the - state is saved every 24 hours (96 / 4). - - config BLE_MESH_TX_SEG_MSG_COUNT - int "Maximum number of simultaneous outgoing segmented messages" - default 1 - range 1 BLE_MESH_ADV_BUF_COUNT - help - Maximum number of simultaneous outgoing multi-segment and/or reliable messages. - - config BLE_MESH_RX_SEG_MSG_COUNT - int "Maximum number of simultaneous incoming segmented messages" - default 1 - range 1 255 - help - Maximum number of simultaneous incoming multi-segment and/or reliable messages. - - config BLE_MESH_RX_SDU_MAX - int "Maximum incoming Upper Transport Access PDU length" - default 384 - range 36 384 - help - Maximum incoming Upper Transport Access PDU length. Leave this to the default - value, unless you really need to optimize memory usage. - - config BLE_MESH_TX_SEG_MAX - int "Maximum number of segments in outgoing messages" - default 20 - range 2 32 - help - Maximum number of segments supported for outgoing messages. - This value should typically be fine-tuned based on what - models the local node supports, i.e. what's the largest - message payload that the node needs to be able to send. - This value affects memory and call stack consumption, which - is why the default is lower than the maximum that the - specification would allow (32 segments). - - The maximum outgoing SDU size is 12 times this number (out of - which 4 or 8 bytes is used for the Transport Layer MIC). For - example, 5 segments means the maximum SDU size is 60 bytes, - which leaves 56 bytes for application layer data using a - 4-byte MIC and 52 bytes using an 8-byte MIC. - - Be sure to specify a sufficient number of advertising buffers - when setting this option to a higher value. There must be at - least three more advertising buffers (BLE_MESH_ADV_BUF_COUNT) - as there are outgoing segments. - - config BLE_MESH_RELAY - bool "Relay support" - help - Support for acting as a Mesh Relay Node. - - config BLE_MESH_LOW_POWER - bool "Support for Low Power features" - help - Enable this option to operate as a Low Power Node. - - if BLE_MESH_LOW_POWER - - config BLE_MESH_LPN_ESTABLISHMENT - bool "Perform Friendship establishment using low power" - default y - help - Perform the Friendship establishment using low power with the help of a - reduced scan duty cycle. The downside of this is that the node may miss - out on messages intended for it until it has successfully set up Friendship - with a Friend node. - - config BLE_MESH_LPN_AUTO - bool "Automatically start looking for Friend nodes once provisioned" - default y - help - Once provisioned, automatically enable LPN functionality and start looking - for Friend nodes. If this option is disabled LPN mode needs to be manually - enabled by calling bt_mesh_lpn_set(true). - - config BLE_MESH_LPN_AUTO_TIMEOUT - int "Time from last received message before going to LPN mode" - default 15 - range 0 3600 - depends on BLE_MESH_LPN_AUTO - help - Time in seconds from the last received message, that the node waits out - before starting to look for Friend nodes. - - config BLE_MESH_LPN_RETRY_TIMEOUT - int "Retry timeout for Friend requests" - default 8 - range 1 3600 - help - Time in seconds between Friend Requests, if a previous Friend Request did - not yield any acceptable Friend Offers. - - config BLE_MESH_LPN_RSSI_FACTOR - int "RSSIFactor, used in Friend Offer Delay calculation" - range 0 3 - default 0 - help - The contribution of the RSSI, measured by the Friend node, used in Friend - Offer Delay calculations. 0 = 1, 1 = 1.5, 2 = 2, 3 = 2.5. - - config BLE_MESH_LPN_RECV_WIN_FACTOR - int "ReceiveWindowFactor, used in Friend Offer Delay calculation" - range 0 3 - default 0 - help - The contribution of the supported Receive Window used in Friend Offer - Delay calculations. 0 = 1, 1 = 1.5, 2 = 2, 3 = 2.5. - - config BLE_MESH_LPN_MIN_QUEUE_SIZE - int "Minimum size of the acceptable friend queue (MinQueueSizeLog)" - range 1 7 - default 1 - help - The MinQueueSizeLog field is defined as log_2(N), where N is the minimum - number of maximum size Lower Transport PDUs that the Friend node can store - in its Friend Queue. As an example, MinQueueSizeLog value 1 gives N = 2, - and value 7 gives N = 128. - - config BLE_MESH_LPN_RECV_DELAY - int "Receive delay requested by the local node" - range 10 255 - default 100 - help - The ReceiveDelay is the time between the Low Power node sending a - request and listening for a response. This delay allows the Friend - node time to prepare the response. The value is in units of milliseconds. - - config BLE_MESH_LPN_POLL_TIMEOUT - int "The value of the PollTimeout timer" - range 10 244735 - default 300 - help - PollTimeout timer is used to measure time between two consecutive - requests sent by a Low Power node. If no requests are received - the Friend node before the PollTimeout timer expires, then the - friendship is considered terminated. The value is in units of 100 - milliseconds, so e.g. a value of 300 means 30 seconds. - - config BLE_MESH_LPN_INIT_POLL_TIMEOUT - int "The starting value of the PollTimeout timer" - range 10 BLE_MESH_LPN_POLL_TIMEOUT - default BLE_MESH_LPN_POLL_TIMEOUT - help - The initial value of the PollTimeout timer when Friendship is to be - established for the first time. After this, the timeout gradually - grows toward the actual PollTimeout, doubling in value for each iteration. - The value is in units of 100 milliseconds, so e.g. a value of 300 means - 30 seconds. - - config BLE_MESH_LPN_SCAN_LATENCY - int "Latency for enabling scanning" - range 0 50 - default 10 - help - Latency (in milliseconds) is the time it takes to enable scanning. In - practice, it means how much time in advance of the Receive Window, the - request to enable scanning is made. - - config BLE_MESH_LPN_GROUPS - int "Number of groups the LPN can subscribe to" - range 0 16384 - default 8 - help - Maximum number of groups to which the LPN can subscribe. - endif # BLE_MESH_LOW_POWER - - config BLE_MESH_FRIEND - bool "Support for acting as a Friend Node" - help - Enable this option to be able to act as a Friend Node. - - if BLE_MESH_FRIEND - - config BLE_MESH_FRIEND_RECV_WIN - int "Friend Receive Window" - range 1 255 - default 255 - help - Receive Window in milliseconds supported by the Friend node. - - config BLE_MESH_FRIEND_QUEUE_SIZE - int "Minimum number of buffers supported per Friend Queue" - range 2 65536 - default 16 - help - Minimum number of buffers available to be stored for each local Friend Queue. - - config BLE_MESH_FRIEND_SUB_LIST_SIZE - int "Friend Subscription List Size" - range 0 1023 - default 3 - help - Size of the Subscription List that can be supported by a Friend node for a - Low Power node. - - config BLE_MESH_FRIEND_LPN_COUNT - int "Number of supported LPN nodes" - range 1 1000 - default 2 - help - Number of Low Power Nodes with which a Friend can have Friendship simultaneously. - - config BLE_MESH_FRIEND_SEG_RX - int "Number of incomplete segment lists per LPN" - range 1 1000 - default 1 - help - Number of incomplete segment lists tracked for each Friends' LPN. - In other words, this determines from how many elements can segmented - messages destined for the Friend queue be received simultaneously. - - endif # BLE_MESH_FRIEND - - config BLE_MESH_NO_LOG - bool "Disable BLE Mesh debug logs (minimize bin size)" - depends on BLE_MESH - default n - help - Select this to save the BLE Mesh related rodata code size. - - menu "BLE Mesh STACK DEBUG LOG LEVEL" - depends on BLE_MESH && !BLE_MESH_NO_LOG - - choice BLE_MESH_STACK_TRACE_LEVEL - prompt "BLE_MESH_STACK" - default BLE_MESH_TRACE_LEVEL_WARNING - depends on BLE_MESH && !BLE_MESH_NO_LOG - help - Define BLE Mesh trace level for BLE Mesh stack. - - config BLE_MESH_TRACE_LEVEL_NONE - bool "NONE" - config BLE_MESH_TRACE_LEVEL_ERROR - bool "ERROR" - config BLE_MESH_TRACE_LEVEL_WARNING - bool "WARNING" - config BLE_MESH_TRACE_LEVEL_INFO - bool "INFO" - config BLE_MESH_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BLE_MESH_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BLE_MESH_STACK_TRACE_LEVEL - int - depends on BLE_MESH - default 0 if BLE_MESH_TRACE_LEVEL_NONE - default 1 if BLE_MESH_TRACE_LEVEL_ERROR - default 2 if BLE_MESH_TRACE_LEVEL_WARNING - default 3 if BLE_MESH_TRACE_LEVEL_INFO - default 4 if BLE_MESH_TRACE_LEVEL_DEBUG - default 5 if BLE_MESH_TRACE_LEVEL_VERBOSE - default 2 - - endmenu #BLE Mesh DEBUG LOG LEVEL - - menu "BLE Mesh NET BUF DEBUG LOG LEVEL" - depends on BLE_MESH && !BLE_MESH_NO_LOG - - choice BLE_MESH_NET_BUF_TRACE_LEVEL - prompt "BLE_MESH_NET_BUF" - default BLE_MESH_NET_BUF_TRACE_LEVEL_WARNING - depends on BLE_MESH && !BLE_MESH_NO_LOG - help - Define BLE Mesh trace level for BLE Mesh net buffer. - - config BLE_MESH_NET_BUF_TRACE_LEVEL_NONE - bool "NONE" - config BLE_MESH_NET_BUF_TRACE_LEVEL_ERROR - bool "ERROR" - config BLE_MESH_NET_BUF_TRACE_LEVEL_WARNING - bool "WARNING" - config BLE_MESH_NET_BUF_TRACE_LEVEL_INFO - bool "INFO" - config BLE_MESH_NET_BUF_TRACE_LEVEL_DEBUG - bool "DEBUG" - config BLE_MESH_NET_BUF_TRACE_LEVEL_VERBOSE - bool "VERBOSE" - endchoice - - config BLE_MESH_NET_BUF_TRACE_LEVEL - int - depends on BLE_MESH - default 0 if BLE_MESH_NET_BUF_TRACE_LEVEL_NONE - default 1 if BLE_MESH_NET_BUF_TRACE_LEVEL_ERROR - default 2 if BLE_MESH_NET_BUF_TRACE_LEVEL_WARNING - default 3 if BLE_MESH_NET_BUF_TRACE_LEVEL_INFO - default 4 if BLE_MESH_NET_BUF_TRACE_LEVEL_DEBUG - default 5 if BLE_MESH_NET_BUF_TRACE_LEVEL_VERBOSE - default 2 - - endmenu #BLE Mesh NET BUF DEBUG LOG LEVEL - - config BLE_MESH_IRQ_LOCK - bool "Used the IRQ lock instead of task lock" - help - To improve the real-time requirements of bt controller in BLE Mesh, - task lock is used to replace IRQ lock. - - config BLE_MESH_CLIENT_MSG_TIMEOUT - int "Timeout(ms) for client message response" - range 100 1200000 - default 4000 - help - Timeout value used by the node to get response of the acknowledged - message which is sent by the client model. - - menu "Support for BLE Mesh Client Models" - - config BLE_MESH_CFG_CLI - bool "Configuration Client Model" - help - Enable support for Configuration client model. - - config BLE_MESH_HEALTH_CLI - bool "Health Client Model" - help - Enable support for Health client model. - - config BLE_MESH_GENERIC_ONOFF_CLI - bool "Generic OnOff Client Model" - help - Enable support for Generic OnOff client model. - - config BLE_MESH_GENERIC_LEVEL_CLI - bool "Generic Level Client Model" - help - Enable support for Generic Level client model. - - config BLE_MESH_GENERIC_DEF_TRANS_TIME_CLI - bool "Generic Default Transition Time Client Model" - help - Enable support for Generic Default Transition Time client model. - - config BLE_MESH_GENERIC_POWER_ONOFF_CLI - bool "Generic Power Onoff Client Model" - help - Enable support for Generic Power Onoff client model. - - config BLE_MESH_GENERIC_POWER_LEVEL_CLI - bool "Generic Power Level Client Model" - help - Enable support for Generic Power Level client model. - - config BLE_MESH_GENERIC_BATTERY_CLI - bool "Generic Battery Client Model" - help - Enable support for Generic Battery client model. - - config BLE_MESH_GENERIC_LOCATION_CLI - bool "Generic Location Client Model" - help - Enable support for Generic Location client model. - - config BLE_MESH_GENERIC_PROPERTY_CLI - bool "Generic Property Client Model" - help - Enable support for Generic Property client model. - - config BLE_MESH_SENSOR_CLI - bool "Sensor Client Model" - help - Enable support for Sensor client model. - - config BLE_MESH_TIME_CLI - bool "Time Client Model" - help - Enable support for Time client model. - - config BLE_MESH_SCENE_CLI - bool "Scene Client Model" - help - Enable support for Scene client model. - - config BLE_MESH_SCHEDULER_CLI - bool "Scheduler Client Model" - help - Enable support for Scheduler client model. - - config BLE_MESH_LIGHT_LIGHTNESS_CLI - bool "Light Lightness Client Model" - help - Enable support for Light Lightness client model. - - config BLE_MESH_LIGHT_CTL_CLI - bool "Light CTL Client Model" - help - Enable support for Light CTL client model. - - config BLE_MESH_LIGHT_HSL_CLI - bool "Light HSL Client Model" - help - Enable support for Light HSL client model. - - config BLE_MESH_LIGHT_XYL_CLI - bool "Light XYL Client Model" - help - Enable support for Light XYL client model. - - config BLE_MESH_LIGHT_LC_CLI - bool "Light LC Client Model" - help - Enable support for Light LC client model. - - endmenu - - config BLE_MESH_IV_UPDATE_TEST - bool "Test the IV Update Procedure" - default n - help - This option removes the 96 hour limit of the IV Update Procedure and - lets the state to be changed at any time. - - menu "BLE Mesh specific test option" - - config BLE_MESH_SELF_TEST - bool "Perform BLE Mesh self-tests" - default n - help - This option adds extra self-tests which are run every time BLE Mesh - networking is initialized. - - config BLE_MESH_SHELL - bool "Enable BLE Mesh shell" - default n - help - Activate shell module that provides BLE Mesh commands to the console. - - config BLE_MESH_DEBUG - bool "Enable BLE Mesh debug logs" - default n - help - Enable debug logs for the BLE Mesh functionality. - - if BLE_MESH_DEBUG - - config BLE_MESH_DEBUG_NET - bool "Network layer debug" - help - Enable Network layer debug logs for the BLE Mesh functionality. - - config BLE_MESH_DEBUG_TRANS - bool "Transport layer debug" - help - Enable Transport layer debug logs for the BLE Mesh functionality. - - config BLE_MESH_DEBUG_BEACON - bool "Beacon debug" - help - Enable Beacon-related debug logs for the BLE Mesh functionality. - - config BLE_MESH_DEBUG_CRYPTO - bool "Crypto debug" - help - Enable cryptographic debug logs for the BLE Mesh functionality. - - config BLE_MESH_DEBUG_PROV - bool "Provisioning debug" - help - Enable Provisioning debug logs for the BLE Mesh functionality. - - config BLE_MESH_DEBUG_ACCESS - bool "Access layer debug" - help - Enable Access layer debug logs for the BLE Mesh functionality. - - config BLE_MESH_DEBUG_MODEL - bool "Foundation model debug" - help - Enable Foundation Models debug logs for the BLE Mesh functionality. - - config BLE_MESH_DEBUG_ADV - bool "Advertising debug" - help - Enable advertising debug logs for the BLE Mesh functionality. - - config BLE_MESH_DEBUG_LOW_POWER - bool "Low Power debug" - help - Enable Low Power debug logs for the BLE Mesh functionality. - - config BLE_MESH_DEBUG_FRIEND - bool "Friend debug" - help - Enable Friend debug logs for the BLE Mesh functionality. - - config BLE_MESH_DEBUG_PROXY - bool "Proxy debug" - depends on BLE_MESH_PROXY - help - Enable Proxy protocol debug logs for the BLE Mesh functionality. - - endif # BLE_MESH_DEBUG - - endmenu - -endif # BLE_MESH +source "$IDF_PATH/components/bt/esp_ble_mesh/Kconfig.in" diff --git a/components/bt/bluedroid/btc/core/btc_alarm.c b/components/bt/common/btc/core/btc_alarm.c similarity index 97% rename from components/bt/bluedroid/btc/core/btc_alarm.c rename to components/bt/common/btc/core/btc_alarm.c index ade9f093ac..653f9826d2 100644 --- a/components/bt/bluedroid/btc/core/btc_alarm.c +++ b/components/bt/common/btc/core/btc_alarm.c @@ -14,6 +14,7 @@ #include "btc/btc_task.h" #include "btc/btc_alarm.h" +#include "esp_log.h" void btc_alarm_handler(btc_msg_t *msg) { diff --git a/components/bt/bluedroid/btc/core/btc_manage.c b/components/bt/common/btc/core/btc_manage.c similarity index 94% rename from components/bt/bluedroid/btc/core/btc_manage.c rename to components/bt/common/btc/core/btc_manage.c index 5f394ee946..6c96be3cc4 100644 --- a/components/bt/bluedroid/btc/core/btc_manage.c +++ b/components/bt/common/btc/core/btc_manage.c @@ -14,10 +14,7 @@ #include "btc/btc_task.h" -#include "common/bt_trace.h" #include "osi/thread.h" -#include "esp_bt_defs.h" -#include "esp_gatt_defs.h" #if BTC_DYNAMIC_MEMORY == FALSE void *btc_profile_cb_tab[BTC_PID_NUM] = {}; diff --git a/components/bt/bluedroid/btc/core/btc_task.c b/components/bt/common/btc/core/btc_task.c similarity index 98% rename from components/bt/bluedroid/btc/core/btc_task.c rename to components/bt/common/btc/core/btc_task.c index c0e57ee417..bd70ec6db7 100644 --- a/components/bt/bluedroid/btc/core/btc_task.c +++ b/components/bt/common/btc/core/btc_task.c @@ -14,12 +14,14 @@ #include #include -#include "common/bt_target.h" #include "btc/btc_task.h" -#include "common/bt_trace.h" #include "osi/thread.h" -#include "common/bt_defs.h" +#include "esp_log.h" +#include "bt_common.h" #include "osi/allocator.h" + +#ifdef CONFIG_BT_BLUEDROID_ENABLED +#include "common/bt_target.h" #include "btc/btc_main.h" #include "btc/btc_manage.h" #include "btc/btc_dev.h" @@ -49,6 +51,8 @@ #include "btc_hf_client.h" #endif /* #if BTC_HF_CLIENT_INCLUDED */ #endif /* #if CLASSIC_BT_INCLUDED */ +#endif + #if CONFIG_BLE_MESH #include "btc_ble_mesh_prov.h" #include "btc_ble_mesh_health_model.h" @@ -67,6 +71,7 @@ osi_thread_t *btc_thread; static const btc_func_t profile_tab[BTC_PID_NUM] = { +#ifdef CONFIG_BT_BLUEDROID_ENABLED [BTC_PID_MAIN_INIT] = {btc_main_call_handler, NULL }, [BTC_PID_DEV] = {btc_dev_call_handler, NULL }, #if (GATTS_INCLUDED == TRUE) @@ -107,6 +112,7 @@ static const btc_func_t profile_tab[BTC_PID_NUM] = { [BTC_PID_HF_CLIENT] = {btc_hf_client_call_handler, btc_hf_client_cb_handler}, #endif /* #if BTC_HF_CLIENT_INCLUDED */ #endif /* #if CLASSIC_BT_INCLUDED */ +#endif #if CONFIG_BLE_MESH [BTC_PID_PROV] = {btc_mesh_prov_call_handler, btc_mesh_prov_cb_handler}, [BTC_PID_MODEL] = {btc_mesh_model_call_handler, btc_mesh_model_cb_handler}, @@ -353,9 +359,10 @@ void btc_deinit(void) bool btc_check_queue_is_congest(void) { - if (osi_thread_queue_wait_size(btc_thread, 2) >= QUEUE_CONGEST_SIZE) { + if (osi_thread_queue_wait_size(btc_thread, 2) >= BT_QUEUE_CONGEST_SIZE) { return true; } return false; } + diff --git a/components/bt/bluedroid/btc/include/btc/btc_alarm.h b/components/bt/common/btc/include/btc/btc_alarm.h similarity index 100% rename from components/bt/bluedroid/btc/include/btc/btc_alarm.h rename to components/bt/common/btc/include/btc/btc_alarm.h diff --git a/components/bt/bluedroid/btc/include/btc/btc_manage.h b/components/bt/common/btc/include/btc/btc_manage.h similarity index 100% rename from components/bt/bluedroid/btc/include/btc/btc_manage.h rename to components/bt/common/btc/include/btc/btc_manage.h diff --git a/components/bt/bluedroid/btc/include/btc/btc_task.h b/components/bt/common/btc/include/btc/btc_task.h similarity index 97% rename from components/bt/bluedroid/btc/include/btc/btc_task.h rename to components/bt/common/btc/include/btc/btc_task.h index 7c5ec80072..c94de7126a 100644 --- a/components/bt/bluedroid/btc/include/btc/btc_task.h +++ b/components/bt/common/btc/include/btc/btc_task.h @@ -16,10 +16,13 @@ #define __BTC_TASK_H__ #include -#include "common/bt_target.h" -#include "common/bt_defs.h" +#include "bt_common.h" #include "osi/thread.h" +#if CONFIG_BT_BLUEDROID_ENABLED +#include "common/bt_target.h" +#endif + typedef struct btc_msg { uint8_t sig; //event signal uint8_t aid; //application id diff --git a/components/bt/common/include/bt_common.h b/components/bt/common/include/bt_common.h new file mode 100644 index 0000000000..15662303e3 --- /dev/null +++ b/components/bt/common/include/bt_common.h @@ -0,0 +1,158 @@ + +// Copyright 2019 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. + +#ifndef _BT_COMMON_H_ +#define _BT_COMMON_H_ + +#include "bt_user_config.h" +#include "esp_log.h" + +#ifndef FALSE +#define FALSE false +#endif + +#ifndef TRUE +#define TRUE true +#endif + +#ifndef BT_QUEUE_CONGEST_SIZE +#define BT_QUEUE_CONGEST_SIZE 40 +#endif + +#define BTC_INITIAL_TRACE_LEVEL UC_BT_LOG_BTC_TRACE_LEVEL +#define OSI_INITIAL_TRACE_LEVEL UC_BT_LOG_OSI_TRACE_LEVEL + +#if UC_BT_BLE_DYNAMIC_ENV_MEMORY +#define BT_BLE_DYNAMIC_ENV_MEMORY TRUE +#define BTC_DYNAMIC_MEMORY TRUE +#else +#define BT_BLE_DYNAMIC_ENV_MEMORY FALSE +#define BTC_DYNAMIC_MEMORY FALSE +#endif + +#ifndef BT_BLE_DYNAMIC_ENV_MEMORY +#define BT_BLE_DYNAMIC_ENV_MEMORY FALSE +#endif + +/* OS Configuration from User config (eg: sdkconfig) */ +#define TASK_PINNED_TO_CORE UC_TASK_PINNED_TO_CORE +#define BT_TASK_MAX_PRIORITIES configMAX_PRIORITIES +#define BT_BTC_TASK_STACK_SIZE UC_BTC_TASK_STACK_SIZE + +/* Define trace levels */ +#define BT_TRACE_LEVEL_NONE UC_TRACE_LEVEL_NONE /* No trace messages to be generated */ +#define BT_TRACE_LEVEL_ERROR UC_TRACE_LEVEL_ERROR /* Error condition trace messages */ +#define BT_TRACE_LEVEL_WARNING UC_TRACE_LEVEL_WARNING /* Warning condition trace messages */ +#define BT_TRACE_LEVEL_API UC_TRACE_LEVEL_API /* API traces */ +#define BT_TRACE_LEVEL_EVENT UC_TRACE_LEVEL_EVENT /* Debug messages for events */ +#define BT_TRACE_LEVEL_DEBUG UC_TRACE_LEVEL_DEBUG /* Full debug messages */ +#define BT_TRACE_LEVEL_VERBOSE UC_TRACE_LEVEL_VERBOSE /* Verbose debug messages */ + +#define MAX_TRACE_LEVEL UC_TRACE_LEVEL_VERBOSE + +#ifndef LOG_LOCAL_LEVEL +#ifndef BOOTLOADER_BUILD +#define LOG_LOCAL_LEVEL UC_LOG_DEFAULT_LEVEL +#else +#define LOG_LOCAL_LEVEL UC_BOOTLOADER_LOG_LEVEL +#endif +#endif + +// Mapping between ESP_LOG_LEVEL and BT_TRACE_LEVEL +#if (LOG_LOCAL_LEVEL >= 4) +#define LOG_LOCAL_LEVEL_MAPPING (LOG_LOCAL_LEVEL+1) +#else +#define LOG_LOCAL_LEVEL_MAPPING LOG_LOCAL_LEVEL +#endif + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +#define BT_LOG_LEVEL_CHECK(LAYER, LEVEL) (MAX(LAYER##_INITIAL_TRACE_LEVEL, LOG_LOCAL_LEVEL_MAPPING) >= BT_TRACE_LEVEL_##LEVEL) + +#define BT_PRINT_E(tag, format, ...) {esp_log_write(ESP_LOG_ERROR, tag, LOG_FORMAT(E, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } +#define BT_PRINT_W(tag, format, ...) {esp_log_write(ESP_LOG_WARN, tag, LOG_FORMAT(W, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } +#define BT_PRINT_I(tag, format, ...) {esp_log_write(ESP_LOG_INFO, tag, LOG_FORMAT(I, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } +#define BT_PRINT_D(tag, format, ...) {esp_log_write(ESP_LOG_DEBUG, tag, LOG_FORMAT(D, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } +#define BT_PRINT_V(tag, format, ...) {esp_log_write(ESP_LOG_VERBOSE, tag, LOG_FORMAT(V, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } + +#ifndef assert +#define assert(x) do { if (!(x)) BT_PRINT_E("BT", "bt host error %s %u\n", __FILE__, __LINE__); } while (0) +#endif + + +#if !UC_BT_STACK_NO_LOG +/* define traces for BTC */ +#define BTC_TRACE_ERROR(fmt, args...) {if (BTC_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_ERROR && BT_LOG_LEVEL_CHECK(BTC, ERROR)) BT_PRINT_E("BT_BTC", fmt, ## args);} +#define BTC_TRACE_WARNING(fmt, args...) {if (BTC_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_WARNING && BT_LOG_LEVEL_CHECK(BTC, WARNING)) BT_PRINT_W("BT_BTC", fmt, ## args);} +#define BTC_TRACE_API(fmt, args...) {if (BTC_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_API && BT_LOG_LEVEL_CHECK(BTC,API)) BT_PRINT_I("BT_BTC", fmt, ## args);} +#define BTC_TRACE_EVENT(fmt, args...) {if (BTC_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_EVENT && BT_LOG_LEVEL_CHECK(BTC,EVENT)) BT_PRINT_D("BT_BTC", fmt, ## args);} +#define BTC_TRACE_DEBUG(fmt, args...) {if (BTC_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_DEBUG && BT_LOG_LEVEL_CHECK(BTC,DEBUG)) BT_PRINT_D("BT_BTC", fmt, ## args);} +#define BTC_TRACE_VERBOSE(fmt, args...) {if (BTC_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_VERBOSE && BT_LOG_LEVEL_CHECK(BTC,VERBOSE)) BT_PRINT_V("BT_BTC", fmt, ## args);} + +/* define traces for OSI */ +#define OSI_TRACE_ERROR(fmt, args...) {if (OSI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_ERROR && BT_LOG_LEVEL_CHECK(OSI, ERROR)) BT_PRINT_E("BT_OSI", fmt, ## args);} +#define OSI_TRACE_WARNING(fmt, args...) {if (OSI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_WARNING && BT_LOG_LEVEL_CHECK(OSI, WARNING)) BT_PRINT_W("BT_OSI", fmt, ## args);} +#define OSI_TRACE_API(fmt, args...) {if (OSI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_API && BT_LOG_LEVEL_CHECK(OSI,API)) BT_PRINT_I("BT_OSI", fmt, ## args);} +#define OSI_TRACE_EVENT(fmt, args...) {if (OSI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_EVENT && BT_LOG_LEVEL_CHECK(OSI,EVENT)) BT_PRINT_D("BT_OSI", fmt, ## args);} +#define OSI_TRACE_DEBUG(fmt, args...) {if (OSI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_DEBUG && BT_LOG_LEVEL_CHECK(OSI,DEBUG)) BT_PRINT_D("BT_OSI", fmt, ## args);} +#define OSI_TRACE_VERBOSE(fmt, args...) {if (OSI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_VERBOSE && BT_LOG_LEVEL_CHECK(OSI,VERBOSE)) BT_PRINT_V("BT_OSI", fmt, ## args);} + +#else + +/* define traces for BTC */ +#define BTC_TRACE_ERROR(fmt, args...) +#define BTC_TRACE_WARNING(fmt, args...) +#define BTC_TRACE_API(fmt, args...) +#define BTC_TRACE_EVENT(fmt, args...) +#define BTC_TRACE_DEBUG(fmt, args...) +#define BTC_TRACE_VERBOSE(fmt, args...) + +/* define traces for OSI */ +#define OSI_TRACE_ERROR(fmt, args...) +#define OSI_TRACE_WARNING(fmt, args...) +#define OSI_TRACE_API(fmt, args...) +#define OSI_TRACE_EVENT(fmt, args...) +#define OSI_TRACE_DEBUG(fmt, args...) +#define OSI_TRACE_VERBOSE(fmt, args...) + +#endif + +/** Bluetooth Error Status */ +/** We need to build on this */ + +/* relate to ESP_BT_STATUS_xxx in esp_bt_defs.h */ +typedef enum { + BT_STATUS_SUCCESS = 0, + BT_STATUS_FAIL, + BT_STATUS_NOT_READY, + BT_STATUS_NOMEM, + BT_STATUS_BUSY, + BT_STATUS_DONE, /* request already completed */ + BT_STATUS_UNSUPPORTED, + BT_STATUS_PARM_INVALID, + BT_STATUS_UNHANDLED, + BT_STATUS_AUTH_FAILURE, + BT_STATUS_RMT_DEV_DOWN, + BT_STATUS_AUTH_REJECTED, + BT_STATUS_INVALID_STATIC_RAND_ADDR, + BT_STATUS_PENDING, + BT_STATUS_UNACCEPT_CONN_INTERVAL, + BT_STATUS_PARAM_OUT_OF_RANGE, + BT_STATUS_TIMEOUT, + BT_STATUS_MEMORY_FULL, + BT_STATUS_EIR_TOO_LARGE, +} bt_status_t; + +#endif /* _BT_COMMON_H_ */ diff --git a/components/bt/common/include/bt_user_config.h b/components/bt/common/include/bt_user_config.h new file mode 100644 index 0000000000..37f5ca1158 --- /dev/null +++ b/components/bt/common/include/bt_user_config.h @@ -0,0 +1,83 @@ +// Copyright 2019 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. + +#ifndef __BT_USER_CONFIG_H__ +#define __BT_USER_CONFIG_H__ +#include "sdkconfig.h" + +#define UC_TRACE_LEVEL_NONE 0 /* No trace messages to be generated */ +#define UC_TRACE_LEVEL_ERROR 1 /* Error condition trace messages */ +#define UC_TRACE_LEVEL_WARNING 2 /* Warning condition trace messages */ +#define UC_TRACE_LEVEL_API 3 /* API traces */ +#define UC_TRACE_LEVEL_EVENT 4 /* Debug messages for events */ +#define UC_TRACE_LEVEL_DEBUG 5 /* Full debug messages */ +#define UC_TRACE_LEVEL_VERBOSE 6 /* Verbose debug messages */ + +//DYNAMIC ENV ALLOCATOR +#ifdef CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY +#define UC_BT_BLE_DYNAMIC_ENV_MEMORY CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY +#else +#define UC_BT_BLE_DYNAMIC_ENV_MEMORY FALSE +#endif + +#ifdef CONFIG_BT_STACK_NO_LOG +#define UC_BT_STACK_NO_LOG CONFIG_BT_STACK_NO_LOG +#else +#define UC_BT_STACK_NO_LOG FALSE +#endif + +/********************************************************** + * Thread/Task reference + **********************************************************/ +#ifdef CONFIG_BLUEDROID_PINNED_TO_CORE +#define UC_TASK_PINNED_TO_CORE (CONFIG_BLUEDROID_PINNED_TO_CORE < portNUM_PROCESSORS ? CONFIG_BLUEDROID_PINNED_TO_CORE : tskNO_AFFINITY) +#else +#define UC_TASK_PINNED_TO_CORE (0) +#endif + +#ifdef CONFIG_BTC_TASK_STACK_SIZE +#define UC_BTC_TASK_STACK_SIZE CONFIG_BTC_TASK_STACK_SIZE +#else +#define UC_BTC_TASK_STACK_SIZE 3072 +#endif + +/********************************************************** + * Trace reference + **********************************************************/ + +#ifdef CONFIG_LOG_DEFAULT_LEVEL +#define UC_LOG_DEFAULT_LEVEL CONFIG_LOG_DEFAULT_LEVEL +#else +#define UC_LOG_DEFAULT_LEVEL 3 +#endif + +#ifdef CONFIG_BOOTLOADER_LOG_LEVEL +#define UC_BOOTLOADER_LOG_LEVEL CONFIG_BOOTLOADER_LOG_LEVEL +#else +#define UC_BOOTLOADER_LOG_LEVEL 3 +#endif + +#ifdef CONFIG_BT_LOG_BTC_TRACE_LEVEL +#define UC_BT_LOG_BTC_TRACE_LEVEL CONFIG_BT_LOG_BTC_TRACE_LEVEL +#else +#define UC_BT_LOG_BTC_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#ifdef CONFIG_BT_LOG_OSI_TRACE_LEVEL +#define UC_BT_LOG_OSI_TRACE_LEVEL CONFIG_BT_LOG_OSI_TRACE_LEVEL +#else +#define UC_BT_LOG_OSI_TRACE_LEVEL UC_TRACE_LEVEL_WARNING +#endif + +#endif /* __BT_USER_CONFIG_H__ */ diff --git a/components/bt/bluedroid/osi/alarm.c b/components/bt/common/osi/alarm.c similarity index 97% rename from components/bt/bluedroid/osi/alarm.c rename to components/bt/common/osi/alarm.c index 21241b96da..178a52a93d 100644 --- a/components/bt/bluedroid/osi/alarm.c +++ b/components/bt/common/osi/alarm.c @@ -18,8 +18,6 @@ #include #include #include -#include "common/bt_defs.h" -#include "common/bt_trace.h" #include "osi/alarm.h" #include "osi/allocator.h" #include "osi/list.h" @@ -27,6 +25,7 @@ #include "btc/btc_task.h" #include "btc/btc_alarm.h" #include "osi/mutex.h" +#include "bt_common.h" typedef struct alarm_t { /* timer id point to here */ @@ -44,7 +43,7 @@ enum { static osi_mutex_t alarm_mutex; static int alarm_state; -#if BT_BLE_DYNAMIC_ENV_MEMORY == FALSE +#if (BT_BLE_DYNAMIC_ENV_MEMORY == FALSE) static struct alarm_t alarm_cbs[ALARM_CBS_NUM]; #else static struct alarm_t *alarm_cbs; @@ -82,7 +81,8 @@ void osi_alarm_init(void) OSI_TRACE_WARNING("%s, invalid state %d\n", __func__, alarm_state); goto end; } -#if BT_BLE_DYNAMIC_ENV_MEMORY == TRUE +#if (BT_BLE_DYNAMIC_ENV_MEMORY == TRUE) +xyz if ((alarm_cbs = (osi_alarm_t *)osi_malloc(sizeof(osi_alarm_t) * ALARM_CBS_NUM)) == NULL) { OSI_TRACE_ERROR("%s, malloc failed\n", __func__); goto end; @@ -112,7 +112,7 @@ void osi_alarm_deinit(void) } } -#if BT_BLE_DYNAMIC_ENV_MEMORY == TRUE +#if (BT_BLE_DYNAMIC_ENV_MEMORY == TRUE) osi_free(alarm_cbs); alarm_cbs = NULL; #endif @@ -268,12 +268,12 @@ end: osi_alarm_err_t osi_alarm_set(osi_alarm_t *alarm, period_ms_t timeout) { - return alarm_set(alarm, timeout, false); + return alarm_set(alarm, timeout, FALSE); } osi_alarm_err_t osi_alarm_set_periodic(osi_alarm_t *alarm, period_ms_t period) { - return alarm_set(alarm, period, true); + return alarm_set(alarm, period, TRUE); } osi_alarm_err_t osi_alarm_cancel(osi_alarm_t *alarm) diff --git a/components/bt/bluedroid/osi/allocator.c b/components/bt/common/osi/allocator.c similarity index 99% rename from components/bt/bluedroid/osi/allocator.c rename to components/bt/common/osi/allocator.c index 569bb5f021..4d10e10f47 100644 --- a/components/bt/bluedroid/osi/allocator.c +++ b/components/bt/common/osi/allocator.c @@ -18,7 +18,7 @@ #include #include -#include "common/bt_defs.h" +#include "bt_common.h" #include "osi/allocator.h" extern void *pvPortZalloc(size_t size); diff --git a/components/bt/bluedroid/osi/buffer.c b/components/bt/common/osi/buffer.c similarity index 96% rename from components/bt/bluedroid/osi/buffer.c rename to components/bt/common/osi/buffer.c index 6b21ed8e28..5593675296 100644 --- a/components/bt/bluedroid/osi/buffer.c +++ b/components/bt/common/osi/buffer.c @@ -16,11 +16,9 @@ * ******************************************************************************/ #include -#include "common/bt_trace.h" +#include "bt_common.h" #include "osi/allocator.h" #include "osi/buffer.h" -#include "common/bt_defs.h" -#include "common/bt_trace.h" struct buffer_t { buffer_t *root; diff --git a/components/bt/bluedroid/osi/config.c b/components/bt/common/osi/config.c similarity index 99% rename from components/bt/bluedroid/osi/config.c rename to components/bt/common/osi/config.c index 9e60f5c107..c1d9a8ad58 100644 --- a/components/bt/bluedroid/osi/config.c +++ b/components/bt/common/osi/config.c @@ -23,10 +23,10 @@ #include #include +#include "bt_common.h" #include "osi/allocator.h" #include "osi/config.h" #include "osi/list.h" -#include "common/bt_trace.h" #define CONFIG_FILE_MAX_SIZE (1536)//1.5k #define CONFIG_FILE_DEFAULE_LENGTH (2048) diff --git a/components/bt/bluedroid/osi/fixed_queue.c b/components/bt/common/osi/fixed_queue.c similarity index 98% rename from components/bt/bluedroid/osi/fixed_queue.c rename to components/bt/common/osi/fixed_queue.c index 0b21dd8be1..b346d2d806 100644 --- a/components/bt/bluedroid/osi/fixed_queue.c +++ b/components/bt/common/osi/fixed_queue.c @@ -16,12 +16,10 @@ * ******************************************************************************/ -#include "common/bt_defs.h" #include "osi/allocator.h" #include "osi/fixed_queue.h" #include "osi/list.h" #include "osi/osi.h" -#include "common/bt_trace.h" #include "osi/mutex.h" #include "osi/semaphore.h" diff --git a/components/bt/bluedroid/osi/future.c b/components/bt/common/osi/future.c similarity index 98% rename from components/bt/bluedroid/osi/future.c rename to components/bt/common/osi/future.c index 25eb5605e6..aee33b1c01 100644 --- a/components/bt/bluedroid/osi/future.c +++ b/components/bt/common/osi/future.c @@ -16,8 +16,7 @@ * ******************************************************************************/ -#include "common/bt_trace.h" - +#include "bt_common.h" #include "osi/allocator.h" #include "osi/future.h" #include "osi/osi.h" diff --git a/components/bt/bluedroid/osi/hash_functions.c b/components/bt/common/osi/hash_functions.c similarity index 100% rename from components/bt/bluedroid/osi/hash_functions.c rename to components/bt/common/osi/hash_functions.c diff --git a/components/bt/bluedroid/osi/hash_map.c b/components/bt/common/osi/hash_map.c similarity index 99% rename from components/bt/bluedroid/osi/hash_map.c rename to components/bt/common/osi/hash_map.c index 1487b07edc..bd7f67d00b 100644 --- a/components/bt/bluedroid/osi/hash_map.c +++ b/components/bt/common/osi/hash_map.c @@ -16,8 +16,7 @@ * ******************************************************************************/ -#include "common/bt_defs.h" -#include "common/bt_trace.h" +#include "bt_common.h" #include "osi/list.h" #include "osi/hash_map.h" #include "osi/allocator.h" diff --git a/components/bt/bluedroid/osi/include/osi/alarm.h b/components/bt/common/osi/include/osi/alarm.h similarity index 100% rename from components/bt/bluedroid/osi/include/osi/alarm.h rename to components/bt/common/osi/include/osi/alarm.h diff --git a/components/bt/bluedroid/osi/include/osi/allocator.h b/components/bt/common/osi/include/osi/allocator.h similarity index 100% rename from components/bt/bluedroid/osi/include/osi/allocator.h rename to components/bt/common/osi/include/osi/allocator.h diff --git a/components/bt/bluedroid/osi/include/osi/buffer.h b/components/bt/common/osi/include/osi/buffer.h similarity index 100% rename from components/bt/bluedroid/osi/include/osi/buffer.h rename to components/bt/common/osi/include/osi/buffer.h diff --git a/components/bt/bluedroid/osi/include/osi/config.h b/components/bt/common/osi/include/osi/config.h similarity index 100% rename from components/bt/bluedroid/osi/include/osi/config.h rename to components/bt/common/osi/include/osi/config.h diff --git a/components/bt/bluedroid/osi/include/osi/fixed_queue.h b/components/bt/common/osi/include/osi/fixed_queue.h similarity index 100% rename from components/bt/bluedroid/osi/include/osi/fixed_queue.h rename to components/bt/common/osi/include/osi/fixed_queue.h diff --git a/components/bt/bluedroid/osi/include/osi/future.h b/components/bt/common/osi/include/osi/future.h similarity index 100% rename from components/bt/bluedroid/osi/include/osi/future.h rename to components/bt/common/osi/include/osi/future.h diff --git a/components/bt/bluedroid/osi/include/osi/hash_functions.h b/components/bt/common/osi/include/osi/hash_functions.h similarity index 100% rename from components/bt/bluedroid/osi/include/osi/hash_functions.h rename to components/bt/common/osi/include/osi/hash_functions.h diff --git a/components/bt/bluedroid/osi/include/osi/hash_map.h b/components/bt/common/osi/include/osi/hash_map.h similarity index 100% rename from components/bt/bluedroid/osi/include/osi/hash_map.h rename to components/bt/common/osi/include/osi/hash_map.h diff --git a/components/bt/bluedroid/osi/include/osi/list.h b/components/bt/common/osi/include/osi/list.h similarity index 100% rename from components/bt/bluedroid/osi/include/osi/list.h rename to components/bt/common/osi/include/osi/list.h diff --git a/components/bt/bluedroid/osi/include/osi/mutex.h b/components/bt/common/osi/include/osi/mutex.h similarity index 100% rename from components/bt/bluedroid/osi/include/osi/mutex.h rename to components/bt/common/osi/include/osi/mutex.h diff --git a/components/bt/bluedroid/osi/include/osi/osi.h b/components/bt/common/osi/include/osi/osi.h similarity index 100% rename from components/bt/bluedroid/osi/include/osi/osi.h rename to components/bt/common/osi/include/osi/osi.h diff --git a/components/bt/bluedroid/osi/include/osi/semaphore.h b/components/bt/common/osi/include/osi/semaphore.h similarity index 100% rename from components/bt/bluedroid/osi/include/osi/semaphore.h rename to components/bt/common/osi/include/osi/semaphore.h diff --git a/components/bt/bluedroid/osi/include/osi/thread.h b/components/bt/common/osi/include/osi/thread.h similarity index 99% rename from components/bt/bluedroid/osi/include/osi/thread.h rename to components/bt/common/osi/include/osi/thread.h index 7f4c46aedf..f6616a6c23 100644 --- a/components/bt/bluedroid/osi/include/osi/thread.h +++ b/components/bt/common/osi/include/osi/thread.h @@ -20,9 +20,9 @@ #include "freertos/FreeRTOS.h" #include "freertos/queue.h" #include "freertos/task.h" -#include "esp_task.h" -#include "common/bt_defs.h" #include "osi/semaphore.h" +#include "esp_task.h" +#include "bt_common.h" #define portBASE_TYPE int diff --git a/components/bt/bluedroid/osi/list.c b/components/bt/common/osi/list.c similarity index 99% rename from components/bt/bluedroid/osi/list.c rename to components/bt/common/osi/list.c index 1a41873acf..730fe4e97a 100644 --- a/components/bt/bluedroid/osi/list.c +++ b/components/bt/common/osi/list.c @@ -1,6 +1,5 @@ -#include "common/bt_defs.h" - +#include "bt_common.h" #include "osi/allocator.h" #include "osi/list.h" #include "osi/osi.h" diff --git a/components/bt/bluedroid/osi/mutex.c b/components/bt/common/osi/mutex.c similarity index 100% rename from components/bt/bluedroid/osi/mutex.c rename to components/bt/common/osi/mutex.c diff --git a/components/bt/bluedroid/osi/osi.c b/components/bt/common/osi/osi.c similarity index 100% rename from components/bt/bluedroid/osi/osi.c rename to components/bt/common/osi/osi.c diff --git a/components/bt/bluedroid/osi/semaphore.c b/components/bt/common/osi/semaphore.c similarity index 100% rename from components/bt/bluedroid/osi/semaphore.c rename to components/bt/common/osi/semaphore.c diff --git a/components/bt/bluedroid/osi/thread.c b/components/bt/common/osi/thread.c similarity index 100% rename from components/bt/bluedroid/osi/thread.c rename to components/bt/common/osi/thread.c diff --git a/components/bt/component.mk b/components/bt/component.mk index 529da89139..2e7148d22e 100644 --- a/components/bt/component.mk +++ b/components/bt/component.mk @@ -3,151 +3,196 @@ # ifdef CONFIG_BT_ENABLED -COMPONENT_SRCDIRS := . +COMPONENT_SRCDIRS := controller COMPONENT_ADD_INCLUDEDIRS := include LIBS := btdm_app -COMPONENT_ADD_LDFLAGS := -lbt -L $(COMPONENT_PATH)/lib \ +COMPONENT_ADD_LDFLAGS := -lbt -L $(COMPONENT_PATH)/controller/lib \ $(addprefix -l,$(LIBS)) # re-link program if BT binary libs change -COMPONENT_ADD_LINKER_DEPS := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS)) +COMPONENT_ADD_LINKER_DEPS := $(patsubst %,$(COMPONENT_PATH)/controller/lib/lib%.a,$(LIBS)) -COMPONENT_SUBMODULES += lib +COMPONENT_SUBMODULES += controller/lib ifeq ($(GCC_NOT_5_2_0), 1) # TODO: annotate fallthroughs in Bluedroid code with comments CFLAGS += -Wno-implicit-fallthrough endif -endif - - ifdef CONFIG_BT_BLUEDROID_ENABLED -COMPONENT_PRIV_INCLUDEDIRS += bluedroid/bta/include \ - bluedroid/bta/ar/include \ - bluedroid/bta/av/include \ - bluedroid/bta/hf_client/include \ - bluedroid/bta/dm/include \ - bluedroid/bta/gatt/include \ - bluedroid/bta/hh/include \ - bluedroid/bta/jv/include \ - bluedroid/bta/sdp/include \ - bluedroid/bta/sys/include \ - bluedroid/btcore/include \ - bluedroid/device/include \ - bluedroid/gki/include \ - bluedroid/hci/include \ - bluedroid/osi/include \ - bluedroid/utils/include \ - bluedroid/external/sbc/decoder/include \ - bluedroid/external/sbc/encoder/include \ - bluedroid/external/sbc/plc/include \ - bluedroid/btc/core/include \ - bluedroid/btc/profile/esp/blufi/include \ - bluedroid/btc/profile/esp/include \ - bluedroid/btc/profile/std/gatt/include \ - bluedroid/btc/profile/std/gap/include \ - bluedroid/btc/profile/std/a2dp/include \ - bluedroid/btc/profile/std/include \ - bluedroid/btc/include \ - bluedroid/btif/include \ - bluedroid/stack/btm/include \ - bluedroid/stack/btu/include \ - bluedroid/stack/gap/include \ - bluedroid/stack/gatt/include \ - bluedroid/stack/hcic/include \ - bluedroid/stack/l2cap/include \ - bluedroid/stack/sdp/include \ - bluedroid/stack/smp/include \ - bluedroid/stack/avct/include \ - bluedroid/stack/avrc/include \ - bluedroid/stack/avdt/include \ - bluedroid/stack/a2dp/include \ - bluedroid/stack/rfcomm/include \ - bluedroid/stack/include \ - bluedroid/utils/include \ - bluedroid/common/include +COMPONENT_PRIV_INCLUDEDIRS += host/bluedroid/bta/include \ + host/bluedroid/bta/ar/include \ + host/bluedroid/bta/av/include \ + host/bluedroid/bta/hf_client/include \ + host/bluedroid/bta/dm/include \ + host/bluedroid/bta/gatt/include \ + host/bluedroid/bta/hh/include \ + host/bluedroid/bta/jv/include \ + host/bluedroid/bta/sdp/include \ + host/bluedroid/bta/sys/include \ + host/bluedroid/device/include \ + host/bluedroid/gki/include \ + host/bluedroid/hci/include \ + host/bluedroid/utils/include \ + host/bluedroid/external/sbc/decoder/include \ + host/bluedroid/external/sbc/encoder/include \ + host/bluedroid/external/sbc/plc/include \ + host/bluedroid/btc/profile/esp/blufi/include \ + host/bluedroid/btc/profile/esp/include \ + host/bluedroid/btc/profile/std/gatt/include \ + host/bluedroid/btc/profile/std/gap/include \ + host/bluedroid/btc/profile/std/a2dp/include \ + host/bluedroid/btc/profile/std/include \ + host/bluedroid/btc/include \ + host/bluedroid/btif/include \ + host/bluedroid/stack/btm/include \ + host/bluedroid/stack/btu/include \ + host/bluedroid/stack/gap/include \ + host/bluedroid/stack/gatt/include \ + host/bluedroid/stack/hcic/include \ + host/bluedroid/stack/l2cap/include \ + host/bluedroid/stack/sdp/include \ + host/bluedroid/stack/smp/include \ + host/bluedroid/stack/avct/include \ + host/bluedroid/stack/avrc/include \ + host/bluedroid/stack/avdt/include \ + host/bluedroid/stack/a2dp/include \ + host/bluedroid/stack/rfcomm/include \ + host/bluedroid/stack/include \ + host/bluedroid/utils/include \ + host/bluedroid/common/include -COMPONENT_ADD_INCLUDEDIRS += bluedroid/api/include/api \ - bluedroid/osi/include \ +COMPONENT_ADD_INCLUDEDIRS += host/bluedroid/api/include/api \ + common/osi/include -ifdef CONFIG_BLE_MESH - COMPONENT_ADD_INCLUDEDIRS += ble_mesh/mesh_core \ - ble_mesh/mesh_core/include \ - ble_mesh/mesh_core/settings \ - ble_mesh/btc/include \ - ble_mesh/mesh_models/include \ - ble_mesh/api/core/include \ - ble_mesh/api/models/include \ - ble_mesh/api -endif +COMPONENT_SRCDIRS += host/bluedroid/bta/dm \ + host/bluedroid/bta/gatt \ + host/bluedroid/bta/hh \ + host/bluedroid/bta/sdp \ + host/bluedroid/bta/av \ + host/bluedroid/bta/ar \ + host/bluedroid/bta/sys \ + host/bluedroid/bta/jv \ + host/bluedroid/bta/hf_client \ + host/bluedroid/bta \ + host/bluedroid/btif \ + host/bluedroid/device \ + host/bluedroid/gki \ + host/bluedroid/hci \ + host/bluedroid/main \ + host/bluedroid/external/sbc/decoder/srce \ + host/bluedroid/external/sbc/encoder/srce \ + host/bluedroid/external/sbc/plc \ + host/bluedroid/btc/core \ + host/bluedroid/btc/profile/esp/blufi \ + host/bluedroid/btc/profile/std/gap \ + host/bluedroid/btc/profile/std/gatt \ + host/bluedroid/btc/profile/std/a2dp \ + host/bluedroid/btc/profile/std/avrc \ + host/bluedroid/btc/profile/std/spp \ + host/bluedroid/btc/profile/std/hf_client \ + host/bluedroid/btc/profile \ + host/bluedroid/stack/btm \ + host/bluedroid/stack/btu \ + host/bluedroid/stack/gap \ + host/bluedroid/stack/gatt \ + host/bluedroid/stack/hcic \ + host/bluedroid/stack/include \ + host/bluedroid/stack/l2cap \ + host/bluedroid/stack/sdp \ + host/bluedroid/stack/smp \ + host/bluedroid/stack/avct \ + host/bluedroid/stack/avrc \ + host/bluedroid/stack/avdt \ + host/bluedroid/stack/a2dp \ + host/bluedroid/stack/rfcomm \ + host/bluedroid/stack \ + host/bluedroid/utils \ + host/bluedroid/api \ + host/bluedroid -COMPONENT_SRCDIRS += bluedroid/bta/dm \ - bluedroid/bta/gatt \ - bluedroid/bta/hh \ - bluedroid/bta/sdp \ - bluedroid/bta/av \ - bluedroid/bta/ar \ - bluedroid/bta/sys \ - bluedroid/bta/jv \ - bluedroid/bta/hf_client \ - bluedroid/bta \ - bluedroid/btcore \ - bluedroid/btif \ - bluedroid/device \ - bluedroid/gki \ - bluedroid/hci \ - bluedroid/main \ - bluedroid/osi \ - bluedroid/external/sbc/decoder/srce \ - bluedroid/external/sbc/encoder/srce \ - bluedroid/external/sbc/plc \ - bluedroid/btc/core \ - bluedroid/btc/profile/esp/blufi \ - bluedroid/btc/profile/std/gap \ - bluedroid/btc/profile/std/gatt \ - bluedroid/btc/profile/std/a2dp \ - bluedroid/btc/profile/std/avrc \ - bluedroid/btc/profile/std/spp \ - bluedroid/btc/profile/std/hf_client \ - bluedroid/btc/profile \ - bluedroid/stack/btm \ - bluedroid/stack/btu \ - bluedroid/stack/gap \ - bluedroid/stack/gatt \ - bluedroid/stack/hcic \ - bluedroid/stack/include \ - bluedroid/stack/l2cap \ - bluedroid/stack/sdp \ - bluedroid/stack/smp \ - bluedroid/stack/avct \ - bluedroid/stack/avrc \ - bluedroid/stack/avdt \ - bluedroid/stack/a2dp \ - bluedroid/stack/rfcomm \ - bluedroid/stack \ - bluedroid/utils \ - bluedroid/api \ - bluedroid - -ifdef CONFIG_BLE_MESH - COMPONENT_SRCDIRS += ble_mesh/mesh_core \ - ble_mesh/mesh_core/settings \ - ble_mesh/btc \ - ble_mesh/mesh_models \ - ble_mesh/api/core \ - ble_mesh/api/models -endif ifeq ($(GCC_NOT_5_2_0), 1) -bluedroid/bta/sdp/bta_sdp_act.o: CFLAGS += -Wno-unused-const-variable -bluedroid/btc/core/btc_config.o: CFLAGS += -Wno-unused-const-variable -bluedroid/stack/btm/btm_sec.o: CFLAGS += -Wno-unused-const-variable -bluedroid/stack/smp/smp_keys.o: CFLAGS += -Wno-unused-const-variable +host/bluedroid/bta/sdp/bta_sdp_act.o: CFLAGS += -Wno-unused-const-variable +host/bluedroid/btc/core/btc_config.o: CFLAGS += -Wno-unused-const-variable +host/bluedroid/stack/btm/btm_sec.o: CFLAGS += -Wno-unused-const-variable +host/bluedroid/stack/smp/smp_keys.o: CFLAGS += -Wno-unused-const-variable +endif + +COMPONENT_PRIV_INCLUDEDIRS += common/btc/include \ + common/include + +COMPONENT_SRCDIRS += common/osi \ + common/btc/core + +endif + +ifdef CONFIG_BLE_MESH + COMPONENT_ADD_INCLUDEDIRS += esp_ble_mesh/mesh_core \ + esp_ble_mesh/mesh_core/include \ + esp_ble_mesh/mesh_core/settings \ + esp_ble_mesh/btc/include \ + esp_ble_mesh/mesh_models/include \ + esp_ble_mesh/api/core/include \ + esp_ble_mesh/api/models/include \ + esp_ble_mesh/api + + COMPONENT_SRCDIRS += esp_ble_mesh/mesh_core \ + esp_ble_mesh/mesh_core/settings \ + esp_ble_mesh/btc \ + esp_ble_mesh/mesh_models \ + esp_ble_mesh/api/core \ + esp_ble_mesh/api/models +endif + + +ifdef CONFIG_BT_NIMBLE_ENABLED +COMPONENT_ADD_INCLUDEDIRS += host/nimble/nimble/nimble/include \ + host/nimble/nimble/nimble/host/include \ + host/nimble/nimble/porting/nimble/include \ + host/nimble/nimble/porting/npl/freertos/include \ + host/nimble/nimble/nimble/host/services/ans/include \ + host/nimble/nimble/nimble/host/services/bas/include \ + host/nimble/nimble/nimble/host/services/gap/include \ + host/nimble/nimble/nimble/host/services/gatt/include \ + host/nimble/nimble/nimble/host/services/ias/include \ + host/nimble/nimble/nimble/host/services/lls/include \ + host/nimble/nimble/nimble/host/services/tps/include \ + host/nimble/nimble/nimble/host/util/include \ + host/nimble/nimble/nimble/host/store/ram/include \ + host/nimble/nimble/nimble/host/store/config/include \ + host/nimble/nimble/ext/tinycrypt/include \ + host/nimble/esp-hci/include \ + host/nimble/port/include + +COMPONENT_SRCDIRS += host/nimble/nimble/nimble/host/src \ + host/nimble/nimble/porting/nimble/src \ + host/nimble/nimble/porting/npl/freertos/src \ + host/nimble/nimble/ext/tinycrypt/src \ + host/nimble/nimble/nimble/host/services/ans/src \ + host/nimble/nimble/nimble/host/services/bas/src \ + host/nimble/nimble/nimble/host/services/gap/src \ + host/nimble/nimble/nimble/host/services/gatt/src \ + host/nimble/nimble/nimble/host/services/ias/src \ + host/nimble/nimble/nimble/host/services/lls/src \ + host/nimble/nimble/nimble/host/services/tps/src \ + host/nimble/nimble/nimble/host/util/src \ + host/nimble/nimble/nimble/host/store/ram/src \ + host/nimble/nimble/nimble/host/store/config/src \ + host/nimble/esp-hci/src + +COMPONENT_OBJEXCLUDE += host/nimble/nimble/nimble/host/store/config/src/ble_store_config_conf.o + +ifdef CONFIG_BT_NIMBLE_MESH + +COMPONENT_ADD_INCLUDEDIRS += host/nimble/nimble/nimble/host/mesh/include +COMPONENT_SRCDIRS += host/nimble/nimble/nimble/host/mesh/src + +endif endif endif diff --git a/components/bt/bt.c b/components/bt/controller/bt.c similarity index 100% rename from components/bt/bt.c rename to components/bt/controller/bt.c diff --git a/components/bt/controller/lib b/components/bt/controller/lib new file mode 160000 index 0000000000..45df297ff2 --- /dev/null +++ b/components/bt/controller/lib @@ -0,0 +1 @@ +Subproject commit 45df297ff295c106171d8c3621216e9f48f7d8b4 diff --git a/components/bt/esp_ble_mesh/Kconfig.in b/components/bt/esp_ble_mesh/Kconfig.in new file mode 100644 index 0000000000..806f98521a --- /dev/null +++ b/components/bt/esp_ble_mesh/Kconfig.in @@ -0,0 +1,803 @@ +if BLE_MESH + + config BLE_MESH_HCI_5_0 + bool "Support sending 20ms non-connectable adv packets" + default y + help + It is a temporary solution and needs further modifications. + + config BLE_MESH_USE_DUPLICATE_SCAN + bool "Support Duplicate Scan in BLE Mesh" + select BLE_SCAN_DUPLICATE + select BLE_MESH_SCAN_DUPLICATE_EN + default y + help + Enable this option to allow using specific duplicate scan filter + in BLE Mesh, and Scan Duplicate Type must be set to 0x02. + + config BLE_MESH_FAST_PROV + bool "Enable BLE Mesh Fast Provisioning" + select BLE_MESH_NODE + select BLE_MESH_PROVISIONER + select BLE_MESH_PB_ADV + default n + help + Enable this option to allow BLE Mesh fast provisioning solution to be used. + + config BLE_MESH_NODE + bool "Support for BLE Mesh Node" + help + Enable the device to be provisioned into a node. + + config BLE_MESH_PROVISIONER + bool "Support for BLE Mesh Provisioner" + help + Enable the device to be a provisioner. + + if BLE_MESH_PROVISIONER + + config BLE_MESH_WAIT_FOR_PROV_MAX_DEV_NUM + int "Maximum number of unprovisioned devices that can be added to device queue" + default 20 + range 1 100 + help + This option specifies how may unprovisioned devices can be added to device + queue for provisioning. + + config BLE_MESH_MAX_STORED_NODES + int "Maximum number of nodes whose information can be stored" + default 20 + range 1 1000 + help + This option specifies the maximum number of nodes whose information can be + stored by a provisioner in its upper layer. + + config BLE_MESH_MAX_PROV_NODES + int "Maximum number of devices that can be provisioned by provisioner" + default 20 + range 1 100 + help + This option specifies how many devices can be provisioned by provisioner. + + if BLE_MESH_PB_ADV + config BLE_MESH_PBA_SAME_TIME + int "Maximum number of PB-ADV running at the same time by provisioner" + default 2 + range 1 10 + help + This option specifies how many devices can be provisioned at the same + time using PB-ADV. + endif # BLE_MESH_PB_ADV + + if BLE_MESH_PB_GATT + config BLE_MESH_PBG_SAME_TIME + int "Maximum number of PB-GATT running at the same time by provisioner" + default 1 + range 1 5 + help + This option specifies how many devices can be provisioned at the same + time using PB-GATT. + endif # BLE_MESH_PB_GATT + + config BLE_MESH_PROVISIONER_SUBNET_COUNT + int "Maximum number of mesh subnets that can be created by provisioner" + default 3 + range 1 4096 + help + This option specifies how many subnets per network a provisioner can create. + + config BLE_MESH_PROVISIONER_APP_KEY_COUNT + int "Maximum number of application keys that can be owned by provisioner" + default 9 + range 1 4096 + help + This option specifies how many application keys the provisioner can have. + + endif # BLE_MESH_PROVISIONER + + # Virtual option enabled whenever Generic Provisioning layer is needed + config BLE_MESH_PROV + bool "BLE Mesh Provisioning support" + default y + help + Enable this option to support BLE Mesh Provisioning functionality. For + BLE Mesh, this option should be always enabled. + + config BLE_MESH_PB_ADV + bool "Provisioning support using the advertising bearer (PB-ADV)" + select BLE_MESH_PROV + default y + help + Enable this option to allow the device to be provisioned over the + advertising bearer. + + config BLE_MESH_PB_GATT + bool "Provisioning support using GATT (PB-GATT)" + select BLE_MESH_PROXY + select BLE_MESH_PROV + help + Enable this option to allow the device to be provisioned over GATT. + + # Virtual option enabled whenever any Proxy protocol is needed + config BLE_MESH_PROXY + bool "BLE Mesh Proxy protocol support" + default y + help + Enable this option to support BLE Mesh Proxy protocol used by PB-GATT + and other proxy pdu transmission. + + config BLE_MESH_GATT_PROXY + bool "BLE Mesh GATT Proxy Service" + select BLE_MESH_PROXY + help + This option enables support for Mesh GATT Proxy Service, i.e. the + ability to act as a proxy between a Mesh GATT Client and a Mesh network. + + config BLE_MESH_NODE_ID_TIMEOUT + int "Node Identity advertising timeout" + depends on BLE_MESH_GATT_PROXY + range 1 60 + default 60 + help + This option determines for how long the local node advertises using + Node Identity. The given value is in seconds. The specification limits + this to 60 seconds and lists it as the recommended value as well. + So leaving the default value is the safest option. + + if BLE_MESH_PROXY + + config BLE_MESH_PROXY_FILTER_SIZE + int "Maximum number of filter entries per Proxy Client" + default 1 + default 3 if BLE_MESH_GATT_PROXY + range 1 32767 + help + This option specifies how many Proxy Filter entries the local node supports. + + endif # BLE_MESH_PROXY + + config BLE_MESH_NET_BUF_POOL_USAGE + bool "BLE Mesh net buffer pool usage tracking" + default y + help + Enable BLE Mesh net buffer pool tracking. + + config BLE_MESH_SETTINGS + bool "Store BLE Mesh Node configuration persistently" + default n + help + When selected, the BLE Mesh stack will take care of storing/restoring the + BLE Mesh configuration persistently in flash. Currently this only supports + storing BLE Mesh node configuration. + + if BLE_MESH_SETTINGS + config BLE_MESH_STORE_TIMEOUT + int "Delay (in seconds) before storing anything persistently" + range 0 1000000 + default 0 + help + This value defines in seconds how soon any pending changes are actually + written into persistent storage (flash) after a change occurs. + + config BLE_MESH_SEQ_STORE_RATE + int "How often the sequence number gets updated in storage" + range 0 1000000 + default 128 + help + This value defines how often the local sequence number gets updated in + persistent storage (i.e. flash). e.g. a value of 100 means that the + sequence number will be stored to flash on every 100th increment. + If the node sends messages very frequently a higher value makes more + sense, whereas if the node sends infrequently a value as low as 0 + (update storage for every increment) can make sense. When the stack + gets initialized it will add sequence number to the last stored one, + so that it starts off with a value that's guaranteed to be larger than + the last one used before power off. + + config BLE_MESH_RPL_STORE_TIMEOUT + int "Minimum frequency that the RPL gets updated in storage" + range 0 1000000 + default 5 + help + This value defines in seconds how soon the RPL(Replay Protection List) + gets written to persistent storage after a change occurs. If the node + receives messages frequently, then a large value is recommended. If the + node receives messages rarely, then the value can be as low as 0 (which + means the PRL is written into the storage immediately). + Note that if the node operates in a security-sensitive case, and there is + a risk of sudden power-off, then a value of 0 is strongly recommended. + Otherwise, a power loss before RPL being written into the storage may + introduce message replay attacks and system security will be in a + vulnerable state. + endif # if BLE_MESH_SETTINGS + + config BLE_MESH_SUBNET_COUNT + int "Maximum number of mesh subnets per network" + default 3 + range 1 4096 + help + This option specifies how many subnets a Mesh network can have at the same time. + + config BLE_MESH_APP_KEY_COUNT + int "Maximum number of application keys per network" + default 3 + range 1 4096 + help + This option specifies how many application keys the device can store per network. + + config BLE_MESH_MODEL_KEY_COUNT + int "Maximum number of application keys per model" + default 3 + range 1 4096 + help + This option specifies the maximum number of application keys to which each model + can be bound. + + config BLE_MESH_MODEL_GROUP_COUNT + int "Maximum number of group address subscriptions per model" + default 3 + range 1 4096 + help + This option specifies the maximum number of addresses to which each model can + be subscribed. + + config BLE_MESH_LABEL_COUNT + int "Maximum number of Label UUIDs used for Virtual Addresses" + default 3 + range 0 4096 + help + This option specifies how many Label UUIDs can be stored. + + config BLE_MESH_CRPL + int "Maximum capacity of the replay protection list" + default 10 + range 2 65535 + help + This option specifies the maximum capacity of the replay protection list. + It is similar to Network message cache size, but has a different purpose. + + config BLE_MESH_MSG_CACHE_SIZE + int "Network message cache size" + default 10 + range 2 65535 + help + Number of messages that are cached for the network. This helps prevent + unnecessary decryption operations and unnecessary relays. This option + is similar to Replay protection list, but has a different purpose. + + config BLE_MESH_ADV_BUF_COUNT + int "Number of advertising buffers" + default 60 + range 6 256 + help + Number of advertising buffers available. The transport layer reserves + ADV_BUF_COUNT - 3 buffers for outgoing segments. The maximum outgoing + SDU size is 12 times this value (out of which 4 or 8 bytes are used + for the Transport Layer MIC). For example, 5 segments means the maximum + SDU size is 60 bytes, which leaves 56 bytes for application layer data + using a 4-byte MIC, or 52 bytes using an 8-byte MIC. + + config BLE_MESH_IVU_DIVIDER + int "Divider for IV Update state refresh timer" + default 4 + range 2 96 + help + When the IV Update state enters Normal operation or IV Update + in Progress, we need to keep track of how many hours has passed + in the state, since the specification requires us to remain in + the state at least for 96 hours (Update in Progress has an + additional upper limit of 144 hours). + + In order to fulfill the above requirement, even if the node might + be powered off once in a while, we need to store persistently + how many hours the node has been in the state. This doesn't + necessarily need to happen every hour (thanks to the flexible + duration range). The exact cadence will depend a lot on the + ways that the node will be used and what kind of power source it + has. + + Since there is no single optimal answer, this configuration + option allows specifying a divider, i.e. how many intervals + the 96 hour minimum gets split into. After each interval the + duration that the node has been in the current state gets + stored to flash. E.g. the default value of 4 means that the + state is saved every 24 hours (96 / 4). + + config BLE_MESH_TX_SEG_MSG_COUNT + int "Maximum number of simultaneous outgoing segmented messages" + default 1 + range 1 BLE_MESH_ADV_BUF_COUNT + help + Maximum number of simultaneous outgoing multi-segment and/or reliable messages. + + config BLE_MESH_RX_SEG_MSG_COUNT + int "Maximum number of simultaneous incoming segmented messages" + default 1 + range 1 255 + help + Maximum number of simultaneous incoming multi-segment and/or reliable messages. + + config BLE_MESH_RX_SDU_MAX + int "Maximum incoming Upper Transport Access PDU length" + default 384 + range 36 384 + help + Maximum incoming Upper Transport Access PDU length. Leave this to the default + value, unless you really need to optimize memory usage. + + config BLE_MESH_TX_SEG_MAX + int "Maximum number of segments in outgoing messages" + default 20 + range 2 32 + help + Maximum number of segments supported for outgoing messages. + This value should typically be fine-tuned based on what + models the local node supports, i.e. what's the largest + message payload that the node needs to be able to send. + This value affects memory and call stack consumption, which + is why the default is lower than the maximum that the + specification would allow (32 segments). + + The maximum outgoing SDU size is 12 times this number (out of + which 4 or 8 bytes is used for the Transport Layer MIC). For + example, 5 segments means the maximum SDU size is 60 bytes, + which leaves 56 bytes for application layer data using a + 4-byte MIC and 52 bytes using an 8-byte MIC. + + Be sure to specify a sufficient number of advertising buffers + when setting this option to a higher value. There must be at + least three more advertising buffers (BLE_MESH_ADV_BUF_COUNT) + as there are outgoing segments. + + config BLE_MESH_RELAY + bool "Relay support" + help + Support for acting as a Mesh Relay Node. + + config BLE_MESH_LOW_POWER + bool "Support for Low Power features" + help + Enable this option to operate as a Low Power Node. + + if BLE_MESH_LOW_POWER + + config BLE_MESH_LPN_ESTABLISHMENT + bool "Perform Friendship establishment using low power" + default y + help + Perform the Friendship establishment using low power with the help of a + reduced scan duty cycle. The downside of this is that the node may miss + out on messages intended for it until it has successfully set up Friendship + with a Friend node. + + config BLE_MESH_LPN_AUTO + bool "Automatically start looking for Friend nodes once provisioned" + default y + help + Once provisioned, automatically enable LPN functionality and start looking + for Friend nodes. If this option is disabled LPN mode needs to be manually + enabled by calling bt_mesh_lpn_set(true). + + config BLE_MESH_LPN_AUTO_TIMEOUT + int "Time from last received message before going to LPN mode" + default 15 + range 0 3600 + depends on BLE_MESH_LPN_AUTO + help + Time in seconds from the last received message, that the node waits out + before starting to look for Friend nodes. + + config BLE_MESH_LPN_RETRY_TIMEOUT + int "Retry timeout for Friend requests" + default 8 + range 1 3600 + help + Time in seconds between Friend Requests, if a previous Friend Request did + not yield any acceptable Friend Offers. + + config BLE_MESH_LPN_RSSI_FACTOR + int "RSSIFactor, used in Friend Offer Delay calculation" + range 0 3 + default 0 + help + The contribution of the RSSI, measured by the Friend node, used in Friend + Offer Delay calculations. 0 = 1, 1 = 1.5, 2 = 2, 3 = 2.5. + + config BLE_MESH_LPN_RECV_WIN_FACTOR + int "ReceiveWindowFactor, used in Friend Offer Delay calculation" + range 0 3 + default 0 + help + The contribution of the supported Receive Window used in Friend Offer + Delay calculations. 0 = 1, 1 = 1.5, 2 = 2, 3 = 2.5. + + config BLE_MESH_LPN_MIN_QUEUE_SIZE + int "Minimum size of the acceptable friend queue (MinQueueSizeLog)" + range 1 7 + default 1 + help + The MinQueueSizeLog field is defined as log_2(N), where N is the minimum + number of maximum size Lower Transport PDUs that the Friend node can store + in its Friend Queue. As an example, MinQueueSizeLog value 1 gives N = 2, + and value 7 gives N = 128. + + config BLE_MESH_LPN_RECV_DELAY + int "Receive delay requested by the local node" + range 10 255 + default 100 + help + The ReceiveDelay is the time between the Low Power node sending a + request and listening for a response. This delay allows the Friend + node time to prepare the response. The value is in units of milliseconds. + + config BLE_MESH_LPN_POLL_TIMEOUT + int "The value of the PollTimeout timer" + range 10 244735 + default 300 + help + PollTimeout timer is used to measure time between two consecutive + requests sent by a Low Power node. If no requests are received + the Friend node before the PollTimeout timer expires, then the + friendship is considered terminated. The value is in units of 100 + milliseconds, so e.g. a value of 300 means 30 seconds. + + config BLE_MESH_LPN_INIT_POLL_TIMEOUT + int "The starting value of the PollTimeout timer" + range 10 BLE_MESH_LPN_POLL_TIMEOUT + default BLE_MESH_LPN_POLL_TIMEOUT + help + The initial value of the PollTimeout timer when Friendship is to be + established for the first time. After this, the timeout gradually + grows toward the actual PollTimeout, doubling in value for each iteration. + The value is in units of 100 milliseconds, so e.g. a value of 300 means + 30 seconds. + + config BLE_MESH_LPN_SCAN_LATENCY + int "Latency for enabling scanning" + range 0 50 + default 10 + help + Latency (in milliseconds) is the time it takes to enable scanning. In + practice, it means how much time in advance of the Receive Window, the + request to enable scanning is made. + + config BLE_MESH_LPN_GROUPS + int "Number of groups the LPN can subscribe to" + range 0 16384 + default 8 + help + Maximum number of groups to which the LPN can subscribe. + endif # BLE_MESH_LOW_POWER + + config BLE_MESH_FRIEND + bool "Support for acting as a Friend Node" + help + Enable this option to be able to act as a Friend Node. + + if BLE_MESH_FRIEND + + config BLE_MESH_FRIEND_RECV_WIN + int "Friend Receive Window" + range 1 255 + default 255 + help + Receive Window in milliseconds supported by the Friend node. + + config BLE_MESH_FRIEND_QUEUE_SIZE + int "Minimum number of buffers supported per Friend Queue" + range 2 65536 + default 16 + help + Minimum number of buffers available to be stored for each local Friend Queue. + + config BLE_MESH_FRIEND_SUB_LIST_SIZE + int "Friend Subscription List Size" + range 0 1023 + default 3 + help + Size of the Subscription List that can be supported by a Friend node for a + Low Power node. + + config BLE_MESH_FRIEND_LPN_COUNT + int "Number of supported LPN nodes" + range 1 1000 + default 2 + help + Number of Low Power Nodes with which a Friend can have Friendship simultaneously. + + config BLE_MESH_FRIEND_SEG_RX + int "Number of incomplete segment lists per LPN" + range 1 1000 + default 1 + help + Number of incomplete segment lists tracked for each Friends' LPN. + In other words, this determines from how many elements can segmented + messages destined for the Friend queue be received simultaneously. + + endif # BLE_MESH_FRIEND + + config BLE_MESH_NO_LOG + bool "Disable BLE Mesh debug logs (minimize bin size)" + depends on BLE_MESH + default n + help + Select this to save the BLE Mesh related rodata code size. + + menu "BLE Mesh STACK DEBUG LOG LEVEL" + depends on BLE_MESH && !BLE_MESH_NO_LOG + + choice BLE_MESH_STACK_TRACE_LEVEL + prompt "BLE_MESH_STACK" + default BLE_MESH_TRACE_LEVEL_WARNING + depends on BLE_MESH && !BLE_MESH_NO_LOG + help + Define BLE Mesh trace level for BLE Mesh stack. + + config BLE_MESH_TRACE_LEVEL_NONE + bool "NONE" + config BLE_MESH_TRACE_LEVEL_ERROR + bool "ERROR" + config BLE_MESH_TRACE_LEVEL_WARNING + bool "WARNING" + config BLE_MESH_TRACE_LEVEL_INFO + bool "INFO" + config BLE_MESH_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BLE_MESH_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BLE_MESH_STACK_TRACE_LEVEL + int + depends on BLE_MESH + default 0 if BLE_MESH_TRACE_LEVEL_NONE + default 1 if BLE_MESH_TRACE_LEVEL_ERROR + default 2 if BLE_MESH_TRACE_LEVEL_WARNING + default 3 if BLE_MESH_TRACE_LEVEL_INFO + default 4 if BLE_MESH_TRACE_LEVEL_DEBUG + default 5 if BLE_MESH_TRACE_LEVEL_VERBOSE + default 2 + + endmenu #BLE Mesh DEBUG LOG LEVEL + + menu "BLE Mesh NET BUF DEBUG LOG LEVEL" + depends on BLE_MESH && !BLE_MESH_NO_LOG + + choice BLE_MESH_NET_BUF_TRACE_LEVEL + prompt "BLE_MESH_NET_BUF" + default BLE_MESH_NET_BUF_TRACE_LEVEL_WARNING + depends on BLE_MESH && !BLE_MESH_NO_LOG + help + Define BLE Mesh trace level for BLE Mesh net buffer. + + config BLE_MESH_NET_BUF_TRACE_LEVEL_NONE + bool "NONE" + config BLE_MESH_NET_BUF_TRACE_LEVEL_ERROR + bool "ERROR" + config BLE_MESH_NET_BUF_TRACE_LEVEL_WARNING + bool "WARNING" + config BLE_MESH_NET_BUF_TRACE_LEVEL_INFO + bool "INFO" + config BLE_MESH_NET_BUF_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BLE_MESH_NET_BUF_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BLE_MESH_NET_BUF_TRACE_LEVEL + int + depends on BLE_MESH + default 0 if BLE_MESH_NET_BUF_TRACE_LEVEL_NONE + default 1 if BLE_MESH_NET_BUF_TRACE_LEVEL_ERROR + default 2 if BLE_MESH_NET_BUF_TRACE_LEVEL_WARNING + default 3 if BLE_MESH_NET_BUF_TRACE_LEVEL_INFO + default 4 if BLE_MESH_NET_BUF_TRACE_LEVEL_DEBUG + default 5 if BLE_MESH_NET_BUF_TRACE_LEVEL_VERBOSE + default 2 + + endmenu #BLE Mesh NET BUF DEBUG LOG LEVEL + + config BLE_MESH_IRQ_LOCK + bool "Used the IRQ lock instead of task lock" + help + To improve the real-time requirements of bt controller in BLE Mesh, + task lock is used to replace IRQ lock. + + config BLE_MESH_CLIENT_MSG_TIMEOUT + int "Timeout(ms) for client message response" + range 100 1200000 + default 4000 + help + Timeout value used by the node to get response of the acknowledged + message which is sent by the client model. + + menu "Support for BLE Mesh Client Models" + + config BLE_MESH_CFG_CLI + bool "Configuration Client Model" + help + Enable support for Configuration client model. + + config BLE_MESH_HEALTH_CLI + bool "Health Client Model" + help + Enable support for Health client model. + + config BLE_MESH_GENERIC_ONOFF_CLI + bool "Generic OnOff Client Model" + help + Enable support for Generic OnOff client model. + + config BLE_MESH_GENERIC_LEVEL_CLI + bool "Generic Level Client Model" + help + Enable support for Generic Level client model. + + config BLE_MESH_GENERIC_DEF_TRANS_TIME_CLI + bool "Generic Default Transition Time Client Model" + help + Enable support for Generic Default Transition Time client model. + + config BLE_MESH_GENERIC_POWER_ONOFF_CLI + bool "Generic Power Onoff Client Model" + help + Enable support for Generic Power Onoff client model. + + config BLE_MESH_GENERIC_POWER_LEVEL_CLI + bool "Generic Power Level Client Model" + help + Enable support for Generic Power Level client model. + + config BLE_MESH_GENERIC_BATTERY_CLI + bool "Generic Battery Client Model" + help + Enable support for Generic Battery client model. + + config BLE_MESH_GENERIC_LOCATION_CLI + bool "Generic Location Client Model" + help + Enable support for Generic Location client model. + + config BLE_MESH_GENERIC_PROPERTY_CLI + bool "Generic Property Client Model" + help + Enable support for Generic Property client model. + + config BLE_MESH_SENSOR_CLI + bool "Sensor Client Model" + help + Enable support for Sensor client model. + + config BLE_MESH_TIME_CLI + bool "Time Client Model" + help + Enable support for Time client model. + + config BLE_MESH_SCENE_CLI + bool "Scene Client Model" + help + Enable support for Scene client model. + + config BLE_MESH_SCHEDULER_CLI + bool "Scheduler Client Model" + help + Enable support for Scheduler client model. + + config BLE_MESH_LIGHT_LIGHTNESS_CLI + bool "Light Lightness Client Model" + help + Enable support for Light Lightness client model. + + config BLE_MESH_LIGHT_CTL_CLI + bool "Light CTL Client Model" + help + Enable support for Light CTL client model. + + config BLE_MESH_LIGHT_HSL_CLI + bool "Light HSL Client Model" + help + Enable support for Light HSL client model. + + config BLE_MESH_LIGHT_XYL_CLI + bool "Light XYL Client Model" + help + Enable support for Light XYL client model. + + config BLE_MESH_LIGHT_LC_CLI + bool "Light LC Client Model" + help + Enable support for Light LC client model. + + endmenu + + config BLE_MESH_IV_UPDATE_TEST + bool "Test the IV Update Procedure" + default n + help + This option removes the 96 hour limit of the IV Update Procedure and + lets the state to be changed at any time. + + menu "BLE Mesh specific test option" + + config BLE_MESH_SELF_TEST + bool "Perform BLE Mesh self-tests" + default n + help + This option adds extra self-tests which are run every time BLE Mesh + networking is initialized. + + config BLE_MESH_SHELL + bool "Enable BLE Mesh shell" + default n + help + Activate shell module that provides BLE Mesh commands to the console. + + config BLE_MESH_DEBUG + bool "Enable BLE Mesh debug logs" + default n + help + Enable debug logs for the BLE Mesh functionality. + + if BLE_MESH_DEBUG + + config BLE_MESH_DEBUG_NET + bool "Network layer debug" + help + Enable Network layer debug logs for the BLE Mesh functionality. + + config BLE_MESH_DEBUG_TRANS + bool "Transport layer debug" + help + Enable Transport layer debug logs for the BLE Mesh functionality. + + config BLE_MESH_DEBUG_BEACON + bool "Beacon debug" + help + Enable Beacon-related debug logs for the BLE Mesh functionality. + + config BLE_MESH_DEBUG_CRYPTO + bool "Crypto debug" + help + Enable cryptographic debug logs for the BLE Mesh functionality. + + config BLE_MESH_DEBUG_PROV + bool "Provisioning debug" + help + Enable Provisioning debug logs for the BLE Mesh functionality. + + config BLE_MESH_DEBUG_ACCESS + bool "Access layer debug" + help + Enable Access layer debug logs for the BLE Mesh functionality. + + config BLE_MESH_DEBUG_MODEL + bool "Foundation model debug" + help + Enable Foundation Models debug logs for the BLE Mesh functionality. + + config BLE_MESH_DEBUG_ADV + bool "Advertising debug" + help + Enable advertising debug logs for the BLE Mesh functionality. + + config BLE_MESH_DEBUG_LOW_POWER + bool "Low Power debug" + help + Enable Low Power debug logs for the BLE Mesh functionality. + + config BLE_MESH_DEBUG_FRIEND + bool "Friend debug" + help + Enable Friend debug logs for the BLE Mesh functionality. + + config BLE_MESH_DEBUG_PROXY + bool "Proxy debug" + depends on BLE_MESH_PROXY + help + Enable Proxy protocol debug logs for the BLE Mesh functionality. + + endif # BLE_MESH_DEBUG + + endmenu + +endif # BLE_MESH diff --git a/components/bt/ble_mesh/api/core/esp_ble_mesh_common_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_common_api.c similarity index 100% rename from components/bt/ble_mesh/api/core/esp_ble_mesh_common_api.c rename to components/bt/esp_ble_mesh/api/core/esp_ble_mesh_common_api.c diff --git a/components/bt/ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c similarity index 100% rename from components/bt/ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c rename to components/bt/esp_ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c diff --git a/components/bt/ble_mesh/api/core/esp_ble_mesh_low_power_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_low_power_api.c similarity index 100% rename from components/bt/ble_mesh/api/core/esp_ble_mesh_low_power_api.c rename to components/bt/esp_ble_mesh/api/core/esp_ble_mesh_low_power_api.c diff --git a/components/bt/ble_mesh/api/core/esp_ble_mesh_networking_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c similarity index 100% rename from components/bt/ble_mesh/api/core/esp_ble_mesh_networking_api.c rename to components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c diff --git a/components/bt/ble_mesh/api/core/esp_ble_mesh_provisioning_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_provisioning_api.c similarity index 100% rename from components/bt/ble_mesh/api/core/esp_ble_mesh_provisioning_api.c rename to components/bt/esp_ble_mesh/api/core/esp_ble_mesh_provisioning_api.c diff --git a/components/bt/ble_mesh/api/core/esp_ble_mesh_proxy_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_proxy_api.c similarity index 100% rename from components/bt/ble_mesh/api/core/esp_ble_mesh_proxy_api.c rename to components/bt/esp_ble_mesh/api/core/esp_ble_mesh_proxy_api.c diff --git a/components/bt/ble_mesh/api/core/include/esp_ble_mesh_common_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_common_api.h similarity index 100% rename from components/bt/ble_mesh/api/core/include/esp_ble_mesh_common_api.h rename to components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_common_api.h diff --git a/components/bt/ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h similarity index 100% rename from components/bt/ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h rename to components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h diff --git a/components/bt/ble_mesh/api/core/include/esp_ble_mesh_low_power_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_low_power_api.h similarity index 100% rename from components/bt/ble_mesh/api/core/include/esp_ble_mesh_low_power_api.h rename to components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_low_power_api.h diff --git a/components/bt/ble_mesh/api/core/include/esp_ble_mesh_networking_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_networking_api.h similarity index 100% rename from components/bt/ble_mesh/api/core/include/esp_ble_mesh_networking_api.h rename to components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_networking_api.h diff --git a/components/bt/ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h similarity index 100% rename from components/bt/ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h rename to components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h diff --git a/components/bt/ble_mesh/api/core/include/esp_ble_mesh_proxy_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_proxy_api.h similarity index 100% rename from components/bt/ble_mesh/api/core/include/esp_ble_mesh_proxy_api.h rename to components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_proxy_api.h diff --git a/components/bt/ble_mesh/api/esp_ble_mesh_defs.h b/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h similarity index 100% rename from components/bt/ble_mesh/api/esp_ble_mesh_defs.h rename to components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h diff --git a/components/bt/ble_mesh/api/models/esp_ble_mesh_config_model_api.c b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_config_model_api.c similarity index 100% rename from components/bt/ble_mesh/api/models/esp_ble_mesh_config_model_api.c rename to components/bt/esp_ble_mesh/api/models/esp_ble_mesh_config_model_api.c diff --git a/components/bt/ble_mesh/api/models/esp_ble_mesh_generic_model_api.c b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_generic_model_api.c similarity index 100% rename from components/bt/ble_mesh/api/models/esp_ble_mesh_generic_model_api.c rename to components/bt/esp_ble_mesh/api/models/esp_ble_mesh_generic_model_api.c diff --git a/components/bt/ble_mesh/api/models/esp_ble_mesh_health_model_api.c b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_health_model_api.c similarity index 100% rename from components/bt/ble_mesh/api/models/esp_ble_mesh_health_model_api.c rename to components/bt/esp_ble_mesh/api/models/esp_ble_mesh_health_model_api.c diff --git a/components/bt/ble_mesh/api/models/esp_ble_mesh_lighting_model_api.c b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_lighting_model_api.c similarity index 100% rename from components/bt/ble_mesh/api/models/esp_ble_mesh_lighting_model_api.c rename to components/bt/esp_ble_mesh/api/models/esp_ble_mesh_lighting_model_api.c diff --git a/components/bt/ble_mesh/api/models/esp_ble_mesh_sensor_model_api.c b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_sensor_model_api.c similarity index 100% rename from components/bt/ble_mesh/api/models/esp_ble_mesh_sensor_model_api.c rename to components/bt/esp_ble_mesh/api/models/esp_ble_mesh_sensor_model_api.c diff --git a/components/bt/ble_mesh/api/models/esp_ble_mesh_time_scene_model_api.c b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_time_scene_model_api.c similarity index 100% rename from components/bt/ble_mesh/api/models/esp_ble_mesh_time_scene_model_api.c rename to components/bt/esp_ble_mesh/api/models/esp_ble_mesh_time_scene_model_api.c diff --git a/components/bt/ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h similarity index 100% rename from components/bt/ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h rename to components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h diff --git a/components/bt/ble_mesh/api/models/include/esp_ble_mesh_generic_model_api.h b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_generic_model_api.h similarity index 100% rename from components/bt/ble_mesh/api/models/include/esp_ble_mesh_generic_model_api.h rename to components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_generic_model_api.h diff --git a/components/bt/ble_mesh/api/models/include/esp_ble_mesh_health_model_api.h b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_health_model_api.h similarity index 100% rename from components/bt/ble_mesh/api/models/include/esp_ble_mesh_health_model_api.h rename to components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_health_model_api.h diff --git a/components/bt/ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h similarity index 100% rename from components/bt/ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h rename to components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h diff --git a/components/bt/ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h similarity index 100% rename from components/bt/ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h rename to components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h diff --git a/components/bt/ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h similarity index 100% rename from components/bt/ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h rename to components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h diff --git a/components/bt/ble_mesh/btc/btc_ble_mesh_config_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_config_model.c similarity index 100% rename from components/bt/ble_mesh/btc/btc_ble_mesh_config_model.c rename to components/bt/esp_ble_mesh/btc/btc_ble_mesh_config_model.c diff --git a/components/bt/ble_mesh/btc/btc_ble_mesh_generic_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_generic_model.c similarity index 100% rename from components/bt/ble_mesh/btc/btc_ble_mesh_generic_model.c rename to components/bt/esp_ble_mesh/btc/btc_ble_mesh_generic_model.c diff --git a/components/bt/ble_mesh/btc/btc_ble_mesh_health_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_health_model.c similarity index 100% rename from components/bt/ble_mesh/btc/btc_ble_mesh_health_model.c rename to components/bt/esp_ble_mesh/btc/btc_ble_mesh_health_model.c diff --git a/components/bt/ble_mesh/btc/btc_ble_mesh_lighting_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_lighting_model.c similarity index 100% rename from components/bt/ble_mesh/btc/btc_ble_mesh_lighting_model.c rename to components/bt/esp_ble_mesh/btc/btc_ble_mesh_lighting_model.c diff --git a/components/bt/ble_mesh/btc/btc_ble_mesh_prov.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c similarity index 100% rename from components/bt/ble_mesh/btc/btc_ble_mesh_prov.c rename to components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c diff --git a/components/bt/ble_mesh/btc/btc_ble_mesh_sensor_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_sensor_model.c similarity index 100% rename from components/bt/ble_mesh/btc/btc_ble_mesh_sensor_model.c rename to components/bt/esp_ble_mesh/btc/btc_ble_mesh_sensor_model.c diff --git a/components/bt/ble_mesh/btc/btc_ble_mesh_time_scene_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_time_scene_model.c similarity index 100% rename from components/bt/ble_mesh/btc/btc_ble_mesh_time_scene_model.c rename to components/bt/esp_ble_mesh/btc/btc_ble_mesh_time_scene_model.c diff --git a/components/bt/ble_mesh/btc/include/btc_ble_mesh_config_model.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_config_model.h similarity index 100% rename from components/bt/ble_mesh/btc/include/btc_ble_mesh_config_model.h rename to components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_config_model.h diff --git a/components/bt/ble_mesh/btc/include/btc_ble_mesh_generic_model.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_generic_model.h similarity index 100% rename from components/bt/ble_mesh/btc/include/btc_ble_mesh_generic_model.h rename to components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_generic_model.h diff --git a/components/bt/ble_mesh/btc/include/btc_ble_mesh_health_model.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_health_model.h similarity index 100% rename from components/bt/ble_mesh/btc/include/btc_ble_mesh_health_model.h rename to components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_health_model.h diff --git a/components/bt/ble_mesh/btc/include/btc_ble_mesh_lighting_model.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_lighting_model.h similarity index 100% rename from components/bt/ble_mesh/btc/include/btc_ble_mesh_lighting_model.h rename to components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_lighting_model.h diff --git a/components/bt/ble_mesh/btc/include/btc_ble_mesh_prov.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h similarity index 100% rename from components/bt/ble_mesh/btc/include/btc_ble_mesh_prov.h rename to components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h diff --git a/components/bt/ble_mesh/btc/include/btc_ble_mesh_sensor_model.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_sensor_model.h similarity index 100% rename from components/bt/ble_mesh/btc/include/btc_ble_mesh_sensor_model.h rename to components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_sensor_model.h diff --git a/components/bt/ble_mesh/btc/include/btc_ble_mesh_time_scene_model.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_time_scene_model.h similarity index 100% rename from components/bt/ble_mesh/btc/include/btc_ble_mesh_time_scene_model.h rename to components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_time_scene_model.h diff --git a/components/bt/ble_mesh/mesh_core/access.c b/components/bt/esp_ble_mesh/mesh_core/access.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/access.c rename to components/bt/esp_ble_mesh/mesh_core/access.c diff --git a/components/bt/ble_mesh/mesh_core/access.h b/components/bt/esp_ble_mesh/mesh_core/access.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/access.h rename to components/bt/esp_ble_mesh/mesh_core/access.h diff --git a/components/bt/ble_mesh/mesh_core/adv.c b/components/bt/esp_ble_mesh/mesh_core/adv.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/adv.c rename to components/bt/esp_ble_mesh/mesh_core/adv.c diff --git a/components/bt/ble_mesh/mesh_core/adv.h b/components/bt/esp_ble_mesh/mesh_core/adv.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/adv.h rename to components/bt/esp_ble_mesh/mesh_core/adv.h diff --git a/components/bt/ble_mesh/mesh_core/beacon.c b/components/bt/esp_ble_mesh/mesh_core/beacon.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/beacon.c rename to components/bt/esp_ble_mesh/mesh_core/beacon.c diff --git a/components/bt/ble_mesh/mesh_core/beacon.h b/components/bt/esp_ble_mesh/mesh_core/beacon.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/beacon.h rename to components/bt/esp_ble_mesh/mesh_core/beacon.h diff --git a/components/bt/ble_mesh/mesh_core/cfg_cli.c b/components/bt/esp_ble_mesh/mesh_core/cfg_cli.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/cfg_cli.c rename to components/bt/esp_ble_mesh/mesh_core/cfg_cli.c diff --git a/components/bt/ble_mesh/mesh_core/cfg_srv.c b/components/bt/esp_ble_mesh/mesh_core/cfg_srv.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/cfg_srv.c rename to components/bt/esp_ble_mesh/mesh_core/cfg_srv.c diff --git a/components/bt/ble_mesh/mesh_core/crypto.c b/components/bt/esp_ble_mesh/mesh_core/crypto.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/crypto.c rename to components/bt/esp_ble_mesh/mesh_core/crypto.c diff --git a/components/bt/ble_mesh/mesh_core/crypto.h b/components/bt/esp_ble_mesh/mesh_core/crypto.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/crypto.h rename to components/bt/esp_ble_mesh/mesh_core/crypto.h diff --git a/components/bt/ble_mesh/mesh_core/foundation.h b/components/bt/esp_ble_mesh/mesh_core/foundation.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/foundation.h rename to components/bt/esp_ble_mesh/mesh_core/foundation.h diff --git a/components/bt/ble_mesh/mesh_core/friend.c b/components/bt/esp_ble_mesh/mesh_core/friend.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/friend.c rename to components/bt/esp_ble_mesh/mesh_core/friend.c diff --git a/components/bt/ble_mesh/mesh_core/friend.h b/components/bt/esp_ble_mesh/mesh_core/friend.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/friend.h rename to components/bt/esp_ble_mesh/mesh_core/friend.h diff --git a/components/bt/ble_mesh/mesh_core/health_cli.c b/components/bt/esp_ble_mesh/mesh_core/health_cli.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/health_cli.c rename to components/bt/esp_ble_mesh/mesh_core/health_cli.c diff --git a/components/bt/ble_mesh/mesh_core/health_srv.c b/components/bt/esp_ble_mesh/mesh_core/health_srv.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/health_srv.c rename to components/bt/esp_ble_mesh/mesh_core/health_srv.c diff --git a/components/bt/ble_mesh/mesh_core/include/cfg_cli.h b/components/bt/esp_ble_mesh/mesh_core/include/cfg_cli.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/include/cfg_cli.h rename to components/bt/esp_ble_mesh/mesh_core/include/cfg_cli.h diff --git a/components/bt/ble_mesh/mesh_core/include/cfg_srv.h b/components/bt/esp_ble_mesh/mesh_core/include/cfg_srv.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/include/cfg_srv.h rename to components/bt/esp_ble_mesh/mesh_core/include/cfg_srv.h diff --git a/components/bt/ble_mesh/mesh_core/include/health_cli.h b/components/bt/esp_ble_mesh/mesh_core/include/health_cli.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/include/health_cli.h rename to components/bt/esp_ble_mesh/mesh_core/include/health_cli.h diff --git a/components/bt/ble_mesh/mesh_core/include/health_srv.h b/components/bt/esp_ble_mesh/mesh_core/include/health_srv.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/include/health_srv.h rename to components/bt/esp_ble_mesh/mesh_core/include/health_srv.h diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_access.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_access.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/include/mesh_access.h rename to components/bt/esp_ble_mesh/mesh_core/include/mesh_access.h diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_aes_encrypt.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_aes_encrypt.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/include/mesh_aes_encrypt.h rename to components/bt/esp_ble_mesh/mesh_core/include/mesh_aes_encrypt.h diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_atomic.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_atomic.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/include/mesh_atomic.h rename to components/bt/esp_ble_mesh/mesh_core/include/mesh_atomic.h diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_bearer_adapt.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_bearer_adapt.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/include/mesh_bearer_adapt.h rename to components/bt/esp_ble_mesh/mesh_core/include/mesh_bearer_adapt.h diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_buf.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_buf.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/include/mesh_buf.h rename to components/bt/esp_ble_mesh/mesh_core/include/mesh_buf.h diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_dlist.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_dlist.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/include/mesh_dlist.h rename to components/bt/esp_ble_mesh/mesh_core/include/mesh_dlist.h diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_hci.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_hci.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/include/mesh_hci.h rename to components/bt/esp_ble_mesh/mesh_core/include/mesh_hci.h diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_kernel.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_kernel.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/include/mesh_kernel.h rename to components/bt/esp_ble_mesh/mesh_core/include/mesh_kernel.h diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_main.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_main.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/include/mesh_main.h rename to components/bt/esp_ble_mesh/mesh_core/include/mesh_main.h diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_proxy.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_proxy.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/include/mesh_proxy.h rename to components/bt/esp_ble_mesh/mesh_core/include/mesh_proxy.h diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_slist.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_slist.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/include/mesh_slist.h rename to components/bt/esp_ble_mesh/mesh_core/include/mesh_slist.h diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_trace.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_trace.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/include/mesh_trace.h rename to components/bt/esp_ble_mesh/mesh_core/include/mesh_trace.h diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_types.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_types.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/include/mesh_types.h rename to components/bt/esp_ble_mesh/mesh_core/include/mesh_types.h diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_util.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_util.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/include/mesh_util.h rename to components/bt/esp_ble_mesh/mesh_core/include/mesh_util.h diff --git a/components/bt/ble_mesh/mesh_core/include/mesh_uuid.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_uuid.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/include/mesh_uuid.h rename to components/bt/esp_ble_mesh/mesh_core/include/mesh_uuid.h diff --git a/components/bt/ble_mesh/mesh_core/lpn.c b/components/bt/esp_ble_mesh/mesh_core/lpn.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/lpn.c rename to components/bt/esp_ble_mesh/mesh_core/lpn.c diff --git a/components/bt/ble_mesh/mesh_core/lpn.h b/components/bt/esp_ble_mesh/mesh_core/lpn.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/lpn.h rename to components/bt/esp_ble_mesh/mesh_core/lpn.h diff --git a/components/bt/ble_mesh/mesh_core/mesh.h b/components/bt/esp_ble_mesh/mesh_core/mesh.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/mesh.h rename to components/bt/esp_ble_mesh/mesh_core/mesh.h diff --git a/components/bt/ble_mesh/mesh_core/mesh_aes_encrypt.c b/components/bt/esp_ble_mesh/mesh_core/mesh_aes_encrypt.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/mesh_aes_encrypt.c rename to components/bt/esp_ble_mesh/mesh_core/mesh_aes_encrypt.c diff --git a/components/bt/ble_mesh/mesh_core/mesh_atomic.c b/components/bt/esp_ble_mesh/mesh_core/mesh_atomic.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/mesh_atomic.c rename to components/bt/esp_ble_mesh/mesh_core/mesh_atomic.c diff --git a/components/bt/ble_mesh/mesh_core/mesh_bearer_adapt.c b/components/bt/esp_ble_mesh/mesh_core/mesh_bearer_adapt.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/mesh_bearer_adapt.c rename to components/bt/esp_ble_mesh/mesh_core/mesh_bearer_adapt.c diff --git a/components/bt/ble_mesh/mesh_core/mesh_buf.c b/components/bt/esp_ble_mesh/mesh_core/mesh_buf.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/mesh_buf.c rename to components/bt/esp_ble_mesh/mesh_core/mesh_buf.c diff --git a/components/bt/ble_mesh/mesh_core/mesh_hci.c b/components/bt/esp_ble_mesh/mesh_core/mesh_hci.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/mesh_hci.c rename to components/bt/esp_ble_mesh/mesh_core/mesh_hci.c diff --git a/components/bt/ble_mesh/mesh_core/mesh_kernel.c b/components/bt/esp_ble_mesh/mesh_core/mesh_kernel.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/mesh_kernel.c rename to components/bt/esp_ble_mesh/mesh_core/mesh_kernel.c diff --git a/components/bt/ble_mesh/mesh_core/mesh_main.c b/components/bt/esp_ble_mesh/mesh_core/mesh_main.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/mesh_main.c rename to components/bt/esp_ble_mesh/mesh_core/mesh_main.c diff --git a/components/bt/ble_mesh/mesh_core/mesh_util.c b/components/bt/esp_ble_mesh/mesh_core/mesh_util.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/mesh_util.c rename to components/bt/esp_ble_mesh/mesh_core/mesh_util.c diff --git a/components/bt/ble_mesh/mesh_core/net.c b/components/bt/esp_ble_mesh/mesh_core/net.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/net.c rename to components/bt/esp_ble_mesh/mesh_core/net.c diff --git a/components/bt/ble_mesh/mesh_core/net.h b/components/bt/esp_ble_mesh/mesh_core/net.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/net.h rename to components/bt/esp_ble_mesh/mesh_core/net.h diff --git a/components/bt/ble_mesh/mesh_core/prov.c b/components/bt/esp_ble_mesh/mesh_core/prov.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/prov.c rename to components/bt/esp_ble_mesh/mesh_core/prov.c diff --git a/components/bt/ble_mesh/mesh_core/prov.h b/components/bt/esp_ble_mesh/mesh_core/prov.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/prov.h rename to components/bt/esp_ble_mesh/mesh_core/prov.h diff --git a/components/bt/ble_mesh/mesh_core/provisioner_beacon.c b/components/bt/esp_ble_mesh/mesh_core/provisioner_beacon.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/provisioner_beacon.c rename to components/bt/esp_ble_mesh/mesh_core/provisioner_beacon.c diff --git a/components/bt/ble_mesh/mesh_core/provisioner_beacon.h b/components/bt/esp_ble_mesh/mesh_core/provisioner_beacon.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/provisioner_beacon.h rename to components/bt/esp_ble_mesh/mesh_core/provisioner_beacon.h diff --git a/components/bt/ble_mesh/mesh_core/provisioner_main.c b/components/bt/esp_ble_mesh/mesh_core/provisioner_main.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/provisioner_main.c rename to components/bt/esp_ble_mesh/mesh_core/provisioner_main.c diff --git a/components/bt/ble_mesh/mesh_core/provisioner_main.h b/components/bt/esp_ble_mesh/mesh_core/provisioner_main.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/provisioner_main.h rename to components/bt/esp_ble_mesh/mesh_core/provisioner_main.h diff --git a/components/bt/ble_mesh/mesh_core/provisioner_prov.c b/components/bt/esp_ble_mesh/mesh_core/provisioner_prov.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/provisioner_prov.c rename to components/bt/esp_ble_mesh/mesh_core/provisioner_prov.c diff --git a/components/bt/ble_mesh/mesh_core/provisioner_prov.h b/components/bt/esp_ble_mesh/mesh_core/provisioner_prov.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/provisioner_prov.h rename to components/bt/esp_ble_mesh/mesh_core/provisioner_prov.h diff --git a/components/bt/ble_mesh/mesh_core/provisioner_proxy.c b/components/bt/esp_ble_mesh/mesh_core/provisioner_proxy.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/provisioner_proxy.c rename to components/bt/esp_ble_mesh/mesh_core/provisioner_proxy.c diff --git a/components/bt/ble_mesh/mesh_core/provisioner_proxy.h b/components/bt/esp_ble_mesh/mesh_core/provisioner_proxy.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/provisioner_proxy.h rename to components/bt/esp_ble_mesh/mesh_core/provisioner_proxy.h diff --git a/components/bt/ble_mesh/mesh_core/proxy.c b/components/bt/esp_ble_mesh/mesh_core/proxy.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/proxy.c rename to components/bt/esp_ble_mesh/mesh_core/proxy.c diff --git a/components/bt/ble_mesh/mesh_core/proxy.h b/components/bt/esp_ble_mesh/mesh_core/proxy.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/proxy.h rename to components/bt/esp_ble_mesh/mesh_core/proxy.h diff --git a/components/bt/ble_mesh/mesh_core/settings.c b/components/bt/esp_ble_mesh/mesh_core/settings.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/settings.c rename to components/bt/esp_ble_mesh/mesh_core/settings.c diff --git a/components/bt/ble_mesh/mesh_core/settings.h b/components/bt/esp_ble_mesh/mesh_core/settings.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/settings.h rename to components/bt/esp_ble_mesh/mesh_core/settings.h diff --git a/components/bt/ble_mesh/mesh_core/settings/settings_nvs.c b/components/bt/esp_ble_mesh/mesh_core/settings/settings_nvs.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/settings/settings_nvs.c rename to components/bt/esp_ble_mesh/mesh_core/settings/settings_nvs.c diff --git a/components/bt/ble_mesh/mesh_core/settings/settings_nvs.h b/components/bt/esp_ble_mesh/mesh_core/settings/settings_nvs.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/settings/settings_nvs.h rename to components/bt/esp_ble_mesh/mesh_core/settings/settings_nvs.h diff --git a/components/bt/ble_mesh/mesh_core/test.c b/components/bt/esp_ble_mesh/mesh_core/test.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/test.c rename to components/bt/esp_ble_mesh/mesh_core/test.c diff --git a/components/bt/ble_mesh/mesh_core/test.h b/components/bt/esp_ble_mesh/mesh_core/test.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/test.h rename to components/bt/esp_ble_mesh/mesh_core/test.h diff --git a/components/bt/ble_mesh/mesh_core/transport.c b/components/bt/esp_ble_mesh/mesh_core/transport.c similarity index 100% rename from components/bt/ble_mesh/mesh_core/transport.c rename to components/bt/esp_ble_mesh/mesh_core/transport.c diff --git a/components/bt/ble_mesh/mesh_core/transport.h b/components/bt/esp_ble_mesh/mesh_core/transport.h similarity index 100% rename from components/bt/ble_mesh/mesh_core/transport.h rename to components/bt/esp_ble_mesh/mesh_core/transport.h diff --git a/components/bt/ble_mesh/mesh_docs/BLE-Mesh_FAQs_EN.md b/components/bt/esp_ble_mesh/mesh_docs/BLE-Mesh_FAQs_EN.md similarity index 100% rename from components/bt/ble_mesh/mesh_docs/BLE-Mesh_FAQs_EN.md rename to components/bt/esp_ble_mesh/mesh_docs/BLE-Mesh_FAQs_EN.md diff --git a/components/bt/ble_mesh/mesh_docs/BLE-Mesh_Feature_List_EN.md b/components/bt/esp_ble_mesh/mesh_docs/BLE-Mesh_Feature_List_EN.md similarity index 100% rename from components/bt/ble_mesh/mesh_docs/BLE-Mesh_Feature_List_EN.md rename to components/bt/esp_ble_mesh/mesh_docs/BLE-Mesh_Feature_List_EN.md diff --git a/components/bt/ble_mesh/mesh_docs/BLE-Mesh_Getting_Started_EN.md b/components/bt/esp_ble_mesh/mesh_docs/BLE-Mesh_Getting_Started_EN.md similarity index 100% rename from components/bt/ble_mesh/mesh_docs/BLE-Mesh_Getting_Started_EN.md rename to components/bt/esp_ble_mesh/mesh_docs/BLE-Mesh_Getting_Started_EN.md diff --git a/components/bt/ble_mesh/mesh_docs/BLE-Mesh_Known_Issues_EN.md b/components/bt/esp_ble_mesh/mesh_docs/BLE-Mesh_Known_Issues_EN.md similarity index 100% rename from components/bt/ble_mesh/mesh_docs/BLE-Mesh_Known_Issues_EN.md rename to components/bt/esp_ble_mesh/mesh_docs/BLE-Mesh_Known_Issues_EN.md diff --git a/components/bt/ble_mesh/mesh_docs/README.md b/components/bt/esp_ble_mesh/mesh_docs/README.md similarity index 100% rename from components/bt/ble_mesh/mesh_docs/README.md rename to components/bt/esp_ble_mesh/mesh_docs/README.md diff --git a/components/bt/ble_mesh/mesh_models/generic_client.c b/components/bt/esp_ble_mesh/mesh_models/generic_client.c similarity index 100% rename from components/bt/ble_mesh/mesh_models/generic_client.c rename to components/bt/esp_ble_mesh/mesh_models/generic_client.c diff --git a/components/bt/ble_mesh/mesh_models/include/generic_client.h b/components/bt/esp_ble_mesh/mesh_models/include/generic_client.h similarity index 100% rename from components/bt/ble_mesh/mesh_models/include/generic_client.h rename to components/bt/esp_ble_mesh/mesh_models/include/generic_client.h diff --git a/components/bt/ble_mesh/mesh_models/include/lighting_client.h b/components/bt/esp_ble_mesh/mesh_models/include/lighting_client.h similarity index 100% rename from components/bt/ble_mesh/mesh_models/include/lighting_client.h rename to components/bt/esp_ble_mesh/mesh_models/include/lighting_client.h diff --git a/components/bt/ble_mesh/mesh_models/include/mesh_common.h b/components/bt/esp_ble_mesh/mesh_models/include/mesh_common.h similarity index 100% rename from components/bt/ble_mesh/mesh_models/include/mesh_common.h rename to components/bt/esp_ble_mesh/mesh_models/include/mesh_common.h diff --git a/components/bt/ble_mesh/mesh_models/include/model_common.h b/components/bt/esp_ble_mesh/mesh_models/include/model_common.h similarity index 100% rename from components/bt/ble_mesh/mesh_models/include/model_common.h rename to components/bt/esp_ble_mesh/mesh_models/include/model_common.h diff --git a/components/bt/ble_mesh/mesh_models/include/model_opcode.h b/components/bt/esp_ble_mesh/mesh_models/include/model_opcode.h similarity index 100% rename from components/bt/ble_mesh/mesh_models/include/model_opcode.h rename to components/bt/esp_ble_mesh/mesh_models/include/model_opcode.h diff --git a/components/bt/ble_mesh/mesh_models/include/sensor_client.h b/components/bt/esp_ble_mesh/mesh_models/include/sensor_client.h similarity index 100% rename from components/bt/ble_mesh/mesh_models/include/sensor_client.h rename to components/bt/esp_ble_mesh/mesh_models/include/sensor_client.h diff --git a/components/bt/ble_mesh/mesh_models/include/time_scene_client.h b/components/bt/esp_ble_mesh/mesh_models/include/time_scene_client.h similarity index 100% rename from components/bt/ble_mesh/mesh_models/include/time_scene_client.h rename to components/bt/esp_ble_mesh/mesh_models/include/time_scene_client.h diff --git a/components/bt/ble_mesh/mesh_models/lighting_client.c b/components/bt/esp_ble_mesh/mesh_models/lighting_client.c similarity index 100% rename from components/bt/ble_mesh/mesh_models/lighting_client.c rename to components/bt/esp_ble_mesh/mesh_models/lighting_client.c diff --git a/components/bt/ble_mesh/mesh_models/mesh_common.c b/components/bt/esp_ble_mesh/mesh_models/mesh_common.c similarity index 100% rename from components/bt/ble_mesh/mesh_models/mesh_common.c rename to components/bt/esp_ble_mesh/mesh_models/mesh_common.c diff --git a/components/bt/ble_mesh/mesh_models/model_common.c b/components/bt/esp_ble_mesh/mesh_models/model_common.c similarity index 100% rename from components/bt/ble_mesh/mesh_models/model_common.c rename to components/bt/esp_ble_mesh/mesh_models/model_common.c diff --git a/components/bt/ble_mesh/mesh_models/sensor_client.c b/components/bt/esp_ble_mesh/mesh_models/sensor_client.c similarity index 100% rename from components/bt/ble_mesh/mesh_models/sensor_client.c rename to components/bt/esp_ble_mesh/mesh_models/sensor_client.c diff --git a/components/bt/ble_mesh/mesh_models/time_scene_client.c b/components/bt/esp_ble_mesh/mesh_models/time_scene_client.c similarity index 100% rename from components/bt/ble_mesh/mesh_models/time_scene_client.c rename to components/bt/esp_ble_mesh/mesh_models/time_scene_client.c diff --git a/components/bt/host/bluedroid/Kconfig.in b/components/bt/host/bluedroid/Kconfig.in new file mode 100644 index 0000000000..21b3fc985a --- /dev/null +++ b/components/bt/host/bluedroid/Kconfig.in @@ -0,0 +1,985 @@ +config BT_BTC_TASK_STACK_SIZE + int "Bluetooth event (callback to application) task stack size" + depends on BT_BLUEDROID_ENABLED + default 3072 + help + This select btc task stack size + +choice BT_BLUEDROID_PINNED_TO_CORE_CHOICE + prompt "The cpu core which Bluedroid run" + depends on BT_BLUEDROID_ENABLED && !FREERTOS_UNICORE + help + Which the cpu core to run Bluedroid. Can choose core0 and core1. + Can not specify no-affinity. + + config BT_BLUEDROID_PINNED_TO_CORE_0 + bool "Core 0 (PRO CPU)" + config BT_BLUEDROID_PINNED_TO_CORE_1 + bool "Core 1 (APP CPU)" + depends on !FREERTOS_UNICORE +endchoice + +config BT_BLUEDROID_PINNED_TO_CORE + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_BLUEDROID_PINNED_TO_CORE_0 + default 1 if BT_BLUEDROID_PINNED_TO_CORE_1 + default 0 + +config BT_BTU_TASK_STACK_SIZE + int "Bluetooth Bluedroid Host Stack task stack size" + depends on BT_BLUEDROID_ENABLED + default 4096 + help + This select btu task stack size + +config BT_BLUEDROID_MEM_DEBUG + bool "Bluedroid memory debug" + depends on BT_BLUEDROID_ENABLED + default n + help + Bluedroid memory debug + +config BT_CLASSIC_ENABLED + bool "Classic Bluetooth" + depends on BT_BLUEDROID_ENABLED + default n + help + For now this option needs "SMP_ENABLE" to be set to yes + +config BT_A2DP_ENABLE + bool "A2DP" + depends on BT_CLASSIC_ENABLED + default n + help + Advanced Audio Distrubution Profile + +config BT_A2DP_SINK_TASK_STACK_SIZE + int "A2DP sink (audio stream decoding) task stack size" + depends on BT_A2DP_ENABLE + default 2048 + +config BT_A2DP_SOURCE_TASK_STACK_SIZE + int "A2DP source (audio stream encoding) task stack size" + depends on BT_A2DP_ENABLE + default 2048 + +config BT_SPP_ENABLED + bool "SPP" + depends on BT_CLASSIC_ENABLED + default n + help + This enables the Serial Port Profile + +config BT_HFP_ENABLE + bool "Hands Free/Handset Profile" + depends on BT_CLASSIC_ENABLED + default n + +choice BT_HFP_ROLE + prompt "Hands-free Profile Role configuration" + depends on BT_HFP_ENABLE + + config BT_HFP_CLIENT_ENABLE + bool "Hands Free Unit" +endchoice + +choice BT_HFP_AUDIO_DATA_PATH + prompt "audio(SCO) data path" + depends on BT_HFP_ENABLE + help + SCO data path, i.e. HCI or PCM. This option is set using API + "esp_bredr_sco_datapath_set" in Bluetooth host. Default SCO data + path can also be set in Bluetooth Controller. + + config BT_HFP_AUDIO_DATA_PATH_PCM + bool "PCM" + config BT_HFP_AUDIO_DATA_PATH_HCI + bool "HCI" +endchoice + +config BT_SSP_ENABLED + bool "Secure Simple Pairing" + depends on BT_CLASSIC_ENABLED + default y + help + This enables the Secure Simple Pairing. If disable this option, + Bluedroid will only support Legacy Pairing + +config BT_BLE_ENABLED + bool "Bluetooth Low Energy" + depends on BT_BLUEDROID_ENABLED + default y + help + This enables Bluetooth Low Energy + +config BT_GATTS_ENABLE + bool "Include GATT server module(GATTS)" + depends on BT_BLE_ENABLED + default y + help + This option can be disabled when the app work only on gatt client mode + +choice BT_GATTS_SEND_SERVICE_CHANGE_MODE + prompt "GATTS Service Change Mode" + default BT_GATTS_SEND_SERVICE_CHANGE_AUTO + depends on BT_GATTS_ENABLE + help + Service change indication mode for GATT Server. + + config BT_GATTS_SEND_SERVICE_CHANGE_MANUAL + bool "GATTS manually send service change indication" + help + Manually send service change indication through API esp_ble_gatts_send_service_change_indication() + + config BT_GATTS_SEND_SERVICE_CHANGE_AUTO + bool "GATTS automatically send service change indication" + help + Let Bluedroid handle the service change indication internally + +endchoice + +config BT_GATTS_SEND_SERVICE_CHANGE_MODE + int + depends on BT_GATTS_ENABLE + default 0 if BT_GATTS_SEND_SERVICE_CHANGE_AUTO + default 1 if BT_GATTS_SEND_SERVICE_CHANGE_MANUAL + default 0 + +config BT_GATTC_ENABLE + bool "Include GATT client module(GATTC)" + depends on BT_BLE_ENABLED + default y + help + This option can be close when the app work only on gatt server mode + +config BT_GATTC_CACHE_NVS_FLASH + bool "Save gattc cache data to nvs flash" + depends on BT_GATTC_ENABLE + default n + help + This select can save gattc cache data to nvs flash + +config BT_BLE_SMP_ENABLE + bool "Include BLE security module(SMP)" + depends on BT_BLE_ENABLED + default y + help + This option can be close when the app not used the ble security connect. + +config BT_SMP_SLAVE_CON_PARAMS_UPD_ENABLE + bool "Slave enable connection parameters update during pairing" + depends on BT_BLE_SMP_ENABLE + default n + help + In order to reduce the pairing time, slave actively initiates connection parameters + update during pairing. + +config BT_STACK_NO_LOG + bool "Disable BT debug logs (minimize bin size)" + depends on BT_BLUEDROID_ENABLED + default n + help + This select can save the rodata code size + +menu "BT DEBUG LOG LEVEL" + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + + choice BT_LOG_HCI_TRACE_LEVEL + prompt "HCI layer" + default BT_LOG_HCI_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for HCI layer + + config BT_LOG_HCI_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_HCI_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_HCI_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_HCI_TRACE_LEVEL_API + bool "API" + config BT_LOG_HCI_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_HCI_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_HCI_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_HCI_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_HCI_TRACE_LEVEL_NONE + default 1 if BT_LOG_HCI_TRACE_LEVEL_ERROR + default 2 if BT_LOG_HCI_TRACE_LEVEL_WARNING + default 3 if BT_LOG_HCI_TRACE_LEVEL_API + default 4 if BT_LOG_HCI_TRACE_LEVEL_EVENT + default 5 if BT_LOG_HCI_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_HCI_TRACE_LEVEL_VERBOSE + default 2 + + choice BT_LOG_BTM_TRACE_LEVEL + prompt "BTM layer" + default BT_LOG_BTM_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for BTM layer + + config BT_LOG_BTM_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_BTM_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_BTM_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_BTM_TRACE_LEVEL_API + bool "API" + config BT_LOG_BTM_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_BTM_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_BTM_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_BTM_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_BTM_TRACE_LEVEL_NONE + default 1 if BT_LOG_BTM_TRACE_LEVEL_ERROR + default 2 if BT_LOG_BTM_TRACE_LEVEL_WARNING + default 3 if BT_LOG_BTM_TRACE_LEVEL_API + default 4 if BT_LOG_BTM_TRACE_LEVEL_EVENT + default 5 if BT_LOG_BTM_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_BTM_TRACE_LEVEL_VERBOSE + default 2 + + choice BT_LOG_L2CAP_TRACE_LEVEL + prompt "L2CAP layer" + default BT_LOG_L2CAP_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for L2CAP layer + + config BT_LOG_L2CAP_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_L2CAP_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_L2CAP_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_L2CAP_TRACE_LEVEL_API + bool "API" + config BT_LOG_L2CAP_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_L2CAP_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_L2CAP_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_L2CAP_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_L2CAP_TRACE_LEVEL_NONE + default 1 if BT_LOG_L2CAP_TRACE_LEVEL_ERROR + default 2 if BT_LOG_L2CAP_TRACE_LEVEL_WARNING + default 3 if BT_LOG_L2CAP_TRACE_LEVEL_API + default 4 if BT_LOG_L2CAP_TRACE_LEVEL_EVENT + default 5 if BT_LOG_L2CAP_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_L2CAP_TRACE_LEVEL_VERBOSE + default 2 + + choice BT_LOG_RFCOMM_TRACE_LEVEL + prompt "RFCOMM layer" + default BT_LOG_RFCOMM_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for RFCOMM layer + + config BT_LOG_RFCOMM_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_RFCOMM_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_RFCOMM_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_RFCOMM_TRACE_LEVEL_API + bool "API" + config BT_LOG_RFCOMM_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_RFCOMM_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_RFCOMM_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_RFCOMM_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_RFCOMM_TRACE_LEVEL_NONE + default 1 if BT_LOG_RFCOMM_TRACE_LEVEL_ERROR + default 2 if BT_LOG_RFCOMM_TRACE_LEVEL_WARNING + default 3 if BT_LOG_RFCOMM_TRACE_LEVEL_API + default 4 if BT_LOG_RFCOMM_TRACE_LEVEL_EVENT + default 5 if BT_LOG_RFCOMM_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_RFCOMM_TRACE_LEVEL_VERBOSE + default 2 + + choice BT_LOG_SDP_TRACE_LEVEL + prompt "SDP layer" + default BT_LOG_SDP_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for SDP layer + + config BT_LOG_SDP_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_SDP_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_SDP_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_SDP_TRACE_LEVEL_API + bool "API" + config BT_LOG_SDP_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_SDP_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_SDP_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_SDP_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_SDP_TRACE_LEVEL_NONE + default 1 if BT_LOG_SDP_TRACE_LEVEL_ERROR + default 2 if BT_LOG_SDP_TRACE_LEVEL_WARNING + default 3 if BT_LOG_SDP_TRACE_LEVEL_API + default 4 if BT_LOG_SDP_TRACE_LEVEL_EVENT + default 5 if BT_LOG_SDP_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_SDP_TRACE_LEVEL_VERBOSE + default 2 + + choice BT_LOG_GAP_TRACE_LEVEL + prompt "GAP layer" + default BT_LOG_GAP_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for GAP layer + + config BT_LOG_GAP_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_GAP_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_GAP_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_GAP_TRACE_LEVEL_API + bool "API" + config BT_LOG_GAP_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_GAP_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_GAP_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_GAP_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_GAP_TRACE_LEVEL_NONE + default 1 if BT_LOG_GAP_TRACE_LEVEL_ERROR + default 2 if BT_LOG_GAP_TRACE_LEVEL_WARNING + default 3 if BT_LOG_GAP_TRACE_LEVEL_API + default 4 if BT_LOG_GAP_TRACE_LEVEL_EVENT + default 5 if BT_LOG_GAP_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_GAP_TRACE_LEVEL_VERBOSE + default 2 + + choice BT_LOG_BNEP_TRACE_LEVEL + prompt "BNEP layer" + default BT_LOG_BNEP_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for BNEP layer + + config BT_LOG_BNEP_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_BNEP_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_BNEP_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_BNEP_TRACE_LEVEL_API + bool "API" + config BT_LOG_BNEP_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_BNEP_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_BNEP_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_BNEP_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_BNEP_TRACE_LEVEL_NONE + default 1 if BT_LOG_BNEP_TRACE_LEVEL_ERROR + default 2 if BT_LOG_BNEP_TRACE_LEVEL_WARNING + default 3 if BT_LOG_BNEP_TRACE_LEVEL_API + default 4 if BT_LOG_BNEP_TRACE_LEVEL_EVENT + default 5 if BT_LOG_BNEP_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_BNEP_TRACE_LEVEL_VERBOSE + default 2 + + choice BT_LOG_PAN_TRACE_LEVEL + prompt "PAN layer" + default BT_LOG_PAN_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for PAN layer + + config BT_LOG_PAN_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_PAN_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_PAN_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_PAN_TRACE_LEVEL_API + bool "API" + config BT_LOG_PAN_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_PAN_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_PAN_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_PAN_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_PAN_TRACE_LEVEL_NONE + default 1 if BT_LOG_PAN_TRACE_LEVEL_ERROR + default 2 if BT_LOG_PAN_TRACE_LEVEL_WARNING + default 3 if BT_LOG_PAN_TRACE_LEVEL_API + default 4 if BT_LOG_PAN_TRACE_LEVEL_EVENT + default 5 if BT_LOG_PAN_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_PAN_TRACE_LEVEL_VERBOSE + default 2 + + choice BT_LOG_A2D_TRACE_LEVEL + prompt "A2D layer" + default BT_LOG_A2D_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for A2D layer + + config BT_LOG_A2D_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_A2D_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_A2D_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_A2D_TRACE_LEVEL_API + bool "API" + config BT_LOG_A2D_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_A2D_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_A2D_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_A2D_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_A2D_TRACE_LEVEL_NONE + default 1 if BT_LOG_A2D_TRACE_LEVEL_ERROR + default 2 if BT_LOG_A2D_TRACE_LEVEL_WARNING + default 3 if BT_LOG_A2D_TRACE_LEVEL_API + default 4 if BT_LOG_A2D_TRACE_LEVEL_EVENT + default 5 if BT_LOG_A2D_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_A2D_TRACE_LEVEL_VERBOSE + default 2 + + choice BT_LOG_AVDT_TRACE_LEVEL + prompt "AVDT layer" + default BT_LOG_AVDT_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for AVDT layer + + config BT_LOG_AVDT_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_AVDT_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_AVDT_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_AVDT_TRACE_LEVEL_API + bool "API" + config BT_LOG_AVDT_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_AVDT_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_AVDT_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_AVDT_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_AVDT_TRACE_LEVEL_NONE + default 1 if BT_LOG_AVDT_TRACE_LEVEL_ERROR + default 2 if BT_LOG_AVDT_TRACE_LEVEL_WARNING + default 3 if BT_LOG_AVDT_TRACE_LEVEL_API + default 4 if BT_LOG_AVDT_TRACE_LEVEL_EVENT + default 5 if BT_LOG_AVDT_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_AVDT_TRACE_LEVEL_VERBOSE + default 2 + + choice BT_LOG_AVCT_TRACE_LEVEL + prompt "AVCT layer" + default BT_LOG_AVCT_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for AVCT layer + + config BT_LOG_AVCT_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_AVCT_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_AVCT_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_AVCT_TRACE_LEVEL_API + bool "API" + config BT_LOG_AVCT_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_AVCT_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_AVCT_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_AVCT_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_AVCT_TRACE_LEVEL_NONE + default 1 if BT_LOG_AVCT_TRACE_LEVEL_ERROR + default 2 if BT_LOG_AVCT_TRACE_LEVEL_WARNING + default 3 if BT_LOG_AVCT_TRACE_LEVEL_API + default 4 if BT_LOG_AVCT_TRACE_LEVEL_EVENT + default 5 if BT_LOG_AVCT_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_AVCT_TRACE_LEVEL_VERBOSE + default 2 + + choice BT_LOG_AVRC_TRACE_LEVEL + prompt "AVRC layer" + default BT_LOG_AVRC_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for AVRC layer + + config BT_LOG_AVRC_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_AVRC_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_AVRC_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_AVRC_TRACE_LEVEL_API + bool "API" + config BT_LOG_AVRC_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_AVRC_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_AVRC_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_AVRC_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_AVRC_TRACE_LEVEL_NONE + default 1 if BT_LOG_AVRC_TRACE_LEVEL_ERROR + default 2 if BT_LOG_AVRC_TRACE_LEVEL_WARNING + default 3 if BT_LOG_AVRC_TRACE_LEVEL_API + default 4 if BT_LOG_AVRC_TRACE_LEVEL_EVENT + default 5 if BT_LOG_AVRC_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_AVRC_TRACE_LEVEL_VERBOSE + default 2 + + choice BT_LOG_MCA_TRACE_LEVEL + prompt "MCA layer" + default BT_LOG_MCA_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for MCA layer + + config BT_LOG_MCA_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_MCA_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_MCA_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_MCA_TRACE_LEVEL_API + bool "API" + config BT_LOG_MCA_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_MCA_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_MCA_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_MCA_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_MCA_TRACE_LEVEL_NONE + default 1 if BT_LOG_MCA_TRACE_LEVEL_ERROR + default 2 if BT_LOG_MCA_TRACE_LEVEL_WARNING + default 3 if BT_LOG_MCA_TRACE_LEVEL_API + default 4 if BT_LOG_MCA_TRACE_LEVEL_EVENT + default 5 if BT_LOG_MCA_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_MCA_TRACE_LEVEL_VERBOSE + default 2 + + choice BT_LOG_HID_TRACE_LEVEL + prompt "HID layer" + default BT_LOG_HID_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for HID layer + + config BT_LOG_HID_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_HID_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_HID_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_HID_TRACE_LEVEL_API + bool "API" + config BT_LOG_HID_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_HID_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_HID_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_HID_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_HID_TRACE_LEVEL_NONE + default 1 if BT_LOG_HID_TRACE_LEVEL_ERROR + default 2 if BT_LOG_HID_TRACE_LEVEL_WARNING + default 3 if BT_LOG_HID_TRACE_LEVEL_API + default 4 if BT_LOG_HID_TRACE_LEVEL_EVENT + default 5 if BT_LOG_HID_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_HID_TRACE_LEVEL_VERBOSE + default 2 + + choice BT_LOG_APPL_TRACE_LEVEL + prompt "APPL layer" + default BT_LOG_APPL_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for APPL layer + + config BT_LOG_APPL_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_APPL_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_APPL_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_APPL_TRACE_LEVEL_API + bool "API" + config BT_LOG_APPL_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_APPL_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_APPL_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_APPL_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_APPL_TRACE_LEVEL_NONE + default 1 if BT_LOG_APPL_TRACE_LEVEL_ERROR + default 2 if BT_LOG_APPL_TRACE_LEVEL_WARNING + default 3 if BT_LOG_APPL_TRACE_LEVEL_API + default 4 if BT_LOG_APPL_TRACE_LEVEL_EVENT + default 5 if BT_LOG_APPL_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_APPL_TRACE_LEVEL_VERBOSE + default 2 + + choice BT_LOG_GATT_TRACE_LEVEL + prompt "GATT layer" + default BT_LOG_GATT_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for GATT layer + + config BT_LOG_GATT_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_GATT_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_GATT_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_GATT_TRACE_LEVEL_API + bool "API" + config BT_LOG_GATT_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_GATT_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_GATT_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_GATT_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_GATT_TRACE_LEVEL_NONE + default 1 if BT_LOG_GATT_TRACE_LEVEL_ERROR + default 2 if BT_LOG_GATT_TRACE_LEVEL_WARNING + default 3 if BT_LOG_GATT_TRACE_LEVEL_API + default 4 if BT_LOG_GATT_TRACE_LEVEL_EVENT + default 5 if BT_LOG_GATT_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_GATT_TRACE_LEVEL_VERBOSE + default 2 + + choice BT_LOG_SMP_TRACE_LEVEL + prompt "SMP layer" + default BT_LOG_SMP_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for SMP layer + + config BT_LOG_SMP_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_SMP_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_SMP_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_SMP_TRACE_LEVEL_API + bool "API" + config BT_LOG_SMP_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_SMP_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_SMP_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_SMP_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_SMP_TRACE_LEVEL_NONE + default 1 if BT_LOG_SMP_TRACE_LEVEL_ERROR + default 2 if BT_LOG_SMP_TRACE_LEVEL_WARNING + default 3 if BT_LOG_SMP_TRACE_LEVEL_API + default 4 if BT_LOG_SMP_TRACE_LEVEL_EVENT + default 5 if BT_LOG_SMP_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_SMP_TRACE_LEVEL_VERBOSE + default 2 + + choice BT_LOG_BTIF_TRACE_LEVEL + prompt "BTIF layer" + default BT_LOG_BTIF_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for BTIF layer + + config BT_LOG_BTIF_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_BTIF_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_BTIF_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_BTIF_TRACE_LEVEL_API + bool "API" + config BT_LOG_BTIF_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_BTIF_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_BTIF_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_BTIF_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_BTIF_TRACE_LEVEL_NONE + default 1 if BT_LOG_BTIF_TRACE_LEVEL_ERROR + default 2 if BT_LOG_BTIF_TRACE_LEVEL_WARNING + default 3 if BT_LOG_BTIF_TRACE_LEVEL_API + default 4 if BT_LOG_BTIF_TRACE_LEVEL_EVENT + default 5 if BT_LOG_BTIF_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_BTIF_TRACE_LEVEL_VERBOSE + default 2 + + choice BT_LOG_BTC_TRACE_LEVEL + prompt "BTC layer" + default BT_LOG_BTC_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for BTC layer + + config BT_LOG_BTC_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_BTC_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_BTC_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_BTC_TRACE_LEVEL_API + bool "API" + config BT_LOG_BTC_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_BTC_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_BTC_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_BTC_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_BTC_TRACE_LEVEL_NONE + default 1 if BT_LOG_BTC_TRACE_LEVEL_ERROR + default 2 if BT_LOG_BTC_TRACE_LEVEL_WARNING + default 3 if BT_LOG_BTC_TRACE_LEVEL_API + default 4 if BT_LOG_BTC_TRACE_LEVEL_EVENT + default 5 if BT_LOG_BTC_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_BTC_TRACE_LEVEL_VERBOSE + default 2 + + choice BT_LOG_OSI_TRACE_LEVEL + prompt "OSI layer" + default BT_LOG_OSI_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for OSI layer + + config BT_LOG_OSI_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_OSI_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_OSI_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_OSI_TRACE_LEVEL_API + bool "API" + config BT_LOG_OSI_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_OSI_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_OSI_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_OSI_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_OSI_TRACE_LEVEL_NONE + default 1 if BT_LOG_OSI_TRACE_LEVEL_ERROR + default 2 if BT_LOG_OSI_TRACE_LEVEL_WARNING + default 3 if BT_LOG_OSI_TRACE_LEVEL_API + default 4 if BT_LOG_OSI_TRACE_LEVEL_EVENT + default 5 if BT_LOG_OSI_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_OSI_TRACE_LEVEL_VERBOSE + default 2 + + choice BT_LOG_BLUFI_TRACE_LEVEL + prompt "BLUFI layer" + default BT_LOG_BLUFI_TRACE_LEVEL_WARNING + depends on BT_BLUEDROID_ENABLED && !BT_STACK_NO_LOG + help + Define BT trace level for BLUFI layer + + config BT_LOG_BLUFI_TRACE_LEVEL_NONE + bool "NONE" + config BT_LOG_BLUFI_TRACE_LEVEL_ERROR + bool "ERROR" + config BT_LOG_BLUFI_TRACE_LEVEL_WARNING + bool "WARNING" + config BT_LOG_BLUFI_TRACE_LEVEL_API + bool "API" + config BT_LOG_BLUFI_TRACE_LEVEL_EVENT + bool "EVENT" + config BT_LOG_BLUFI_TRACE_LEVEL_DEBUG + bool "DEBUG" + config BT_LOG_BLUFI_TRACE_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_LOG_BLUFI_TRACE_LEVEL + int + depends on BT_BLUEDROID_ENABLED + default 0 if BT_LOG_BLUFI_TRACE_LEVEL_NONE + default 1 if BT_LOG_BLUFI_TRACE_LEVEL_ERROR + default 2 if BT_LOG_BLUFI_TRACE_LEVEL_WARNING + default 3 if BT_LOG_BLUFI_TRACE_LEVEL_API + default 4 if BT_LOG_BLUFI_TRACE_LEVEL_EVENT + default 5 if BT_LOG_BLUFI_TRACE_LEVEL_DEBUG + default 6 if BT_LOG_BLUFI_TRACE_LEVEL_VERBOSE + default 2 + +endmenu #BT DEBUG LOG LEVEL + + +config BT_ACL_CONNECTIONS + int "BT/BLE MAX ACL CONNECTIONS(1~7)" + depends on BT_BLUEDROID_ENABLED + range 1 7 + default 4 + help + Maximum BT/BLE connection count + +config BT_ALLOCATION_FROM_SPIRAM_FIRST + bool "BT/BLE will first malloc the memory from the PSRAM" + depends on BT_BLUEDROID_ENABLED + default n + help + This select can save the internal RAM if there have the PSRAM + +config BT_BLE_DYNAMIC_ENV_MEMORY + bool "Use dynamic memory allocation in BT/BLE stack" + depends on BT_BLUEDROID_ENABLED + default n + help + This select can make the allocation of memory will become more flexible + +config BT_BLE_HOST_QUEUE_CONG_CHECK + bool "BLE queue congestion check" + depends on BT_BLUEDROID_ENABLED + default n + help + When scanning and scan duplicate is not enabled, if there are a lot of adv packets around + or application layer handling adv packets is slow, it will cause the controller memory + to run out. if enabled, adv packets will be lost when host queue is congested. + +config BT_SMP_ENABLE + bool + depends on BT_BLUEDROID_ENABLED + default BT_CLASSIC_ENABLED || BT_BLE_SMP_ENABLE + +config BT_BLE_ACT_SCAN_REP_ADV_SCAN + bool "Report adv data and scan response individually when BLE active scan" + depends on BT_BLUEDROID_ENABLED && (BTDM_CTRL_MODE_BTDM || BTDM_CTRL_MODE_BLE_ONLY) + default n + help + Originally, when doing BLE active scan, Bluedroid will not report adv to application layer + until receive scan response. This option is used to disable the behavior. When enable this option, + Bluedroid will report adv data or scan response to application layer immediately. + + # Memory reserved at start of DRAM for Bluetooth stack + +config BT_BLE_ESTAB_LINK_CONN_TOUT + int "Timeout of BLE connection establishment" + depends on BT_BLUEDROID_ENABLED + range 1 60 + default 30 + help + Bluetooth Connection establishment maximum time, if connection time exceeds this value, the connection + establishment fails, ESP_GATTC_OPEN_EVT or ESP_GATTS_OPEN_EVT is triggered. + +config BT_RESERVE_DRAM + hex + default 0xdb5c if BT_ENABLED + default 0 diff --git a/components/bt/bluedroid/api/esp_a2dp_api.c b/components/bt/host/bluedroid/api/esp_a2dp_api.c similarity index 100% rename from components/bt/bluedroid/api/esp_a2dp_api.c rename to components/bt/host/bluedroid/api/esp_a2dp_api.c diff --git a/components/bt/bluedroid/api/esp_avrc_api.c b/components/bt/host/bluedroid/api/esp_avrc_api.c similarity index 100% rename from components/bt/bluedroid/api/esp_avrc_api.c rename to components/bt/host/bluedroid/api/esp_avrc_api.c diff --git a/components/bt/bluedroid/api/esp_blufi_api.c b/components/bt/host/bluedroid/api/esp_blufi_api.c similarity index 100% rename from components/bt/bluedroid/api/esp_blufi_api.c rename to components/bt/host/bluedroid/api/esp_blufi_api.c diff --git a/components/bt/bluedroid/api/esp_bt_device.c b/components/bt/host/bluedroid/api/esp_bt_device.c similarity index 100% rename from components/bt/bluedroid/api/esp_bt_device.c rename to components/bt/host/bluedroid/api/esp_bt_device.c diff --git a/components/bt/bluedroid/api/esp_bt_main.c b/components/bt/host/bluedroid/api/esp_bt_main.c similarity index 100% rename from components/bt/bluedroid/api/esp_bt_main.c rename to components/bt/host/bluedroid/api/esp_bt_main.c diff --git a/components/bt/bluedroid/api/esp_gap_ble_api.c b/components/bt/host/bluedroid/api/esp_gap_ble_api.c similarity index 100% rename from components/bt/bluedroid/api/esp_gap_ble_api.c rename to components/bt/host/bluedroid/api/esp_gap_ble_api.c diff --git a/components/bt/bluedroid/api/esp_gap_bt_api.c b/components/bt/host/bluedroid/api/esp_gap_bt_api.c similarity index 100% rename from components/bt/bluedroid/api/esp_gap_bt_api.c rename to components/bt/host/bluedroid/api/esp_gap_bt_api.c diff --git a/components/bt/bluedroid/api/esp_gatt_common_api.c b/components/bt/host/bluedroid/api/esp_gatt_common_api.c similarity index 100% rename from components/bt/bluedroid/api/esp_gatt_common_api.c rename to components/bt/host/bluedroid/api/esp_gatt_common_api.c diff --git a/components/bt/bluedroid/api/esp_gattc_api.c b/components/bt/host/bluedroid/api/esp_gattc_api.c similarity index 100% rename from components/bt/bluedroid/api/esp_gattc_api.c rename to components/bt/host/bluedroid/api/esp_gattc_api.c diff --git a/components/bt/bluedroid/api/esp_gatts_api.c b/components/bt/host/bluedroid/api/esp_gatts_api.c similarity index 100% rename from components/bt/bluedroid/api/esp_gatts_api.c rename to components/bt/host/bluedroid/api/esp_gatts_api.c diff --git a/components/bt/bluedroid/api/esp_hf_client_api.c b/components/bt/host/bluedroid/api/esp_hf_client_api.c similarity index 100% rename from components/bt/bluedroid/api/esp_hf_client_api.c rename to components/bt/host/bluedroid/api/esp_hf_client_api.c diff --git a/components/bt/bluedroid/api/esp_spp_api.c b/components/bt/host/bluedroid/api/esp_spp_api.c similarity index 100% rename from components/bt/bluedroid/api/esp_spp_api.c rename to components/bt/host/bluedroid/api/esp_spp_api.c diff --git a/components/bt/bluedroid/api/include/api/esp_a2dp_api.h b/components/bt/host/bluedroid/api/include/api/esp_a2dp_api.h similarity index 100% rename from components/bt/bluedroid/api/include/api/esp_a2dp_api.h rename to components/bt/host/bluedroid/api/include/api/esp_a2dp_api.h diff --git a/components/bt/bluedroid/api/include/api/esp_avrc_api.h b/components/bt/host/bluedroid/api/include/api/esp_avrc_api.h similarity index 100% rename from components/bt/bluedroid/api/include/api/esp_avrc_api.h rename to components/bt/host/bluedroid/api/include/api/esp_avrc_api.h diff --git a/components/bt/bluedroid/api/include/api/esp_blufi_api.h b/components/bt/host/bluedroid/api/include/api/esp_blufi_api.h similarity index 100% rename from components/bt/bluedroid/api/include/api/esp_blufi_api.h rename to components/bt/host/bluedroid/api/include/api/esp_blufi_api.h diff --git a/components/bt/bluedroid/api/include/api/esp_bt_defs.h b/components/bt/host/bluedroid/api/include/api/esp_bt_defs.h similarity index 100% rename from components/bt/bluedroid/api/include/api/esp_bt_defs.h rename to components/bt/host/bluedroid/api/include/api/esp_bt_defs.h diff --git a/components/bt/bluedroid/api/include/api/esp_bt_device.h b/components/bt/host/bluedroid/api/include/api/esp_bt_device.h similarity index 100% rename from components/bt/bluedroid/api/include/api/esp_bt_device.h rename to components/bt/host/bluedroid/api/include/api/esp_bt_device.h diff --git a/components/bt/bluedroid/api/include/api/esp_bt_main.h b/components/bt/host/bluedroid/api/include/api/esp_bt_main.h similarity index 100% rename from components/bt/bluedroid/api/include/api/esp_bt_main.h rename to components/bt/host/bluedroid/api/include/api/esp_bt_main.h diff --git a/components/bt/bluedroid/api/include/api/esp_gap_ble_api.h b/components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h similarity index 100% rename from components/bt/bluedroid/api/include/api/esp_gap_ble_api.h rename to components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h diff --git a/components/bt/bluedroid/api/include/api/esp_gap_bt_api.h b/components/bt/host/bluedroid/api/include/api/esp_gap_bt_api.h similarity index 100% rename from components/bt/bluedroid/api/include/api/esp_gap_bt_api.h rename to components/bt/host/bluedroid/api/include/api/esp_gap_bt_api.h diff --git a/components/bt/bluedroid/api/include/api/esp_gatt_common_api.h b/components/bt/host/bluedroid/api/include/api/esp_gatt_common_api.h similarity index 100% rename from components/bt/bluedroid/api/include/api/esp_gatt_common_api.h rename to components/bt/host/bluedroid/api/include/api/esp_gatt_common_api.h diff --git a/components/bt/bluedroid/api/include/api/esp_gatt_defs.h b/components/bt/host/bluedroid/api/include/api/esp_gatt_defs.h similarity index 100% rename from components/bt/bluedroid/api/include/api/esp_gatt_defs.h rename to components/bt/host/bluedroid/api/include/api/esp_gatt_defs.h diff --git a/components/bt/bluedroid/api/include/api/esp_gattc_api.h b/components/bt/host/bluedroid/api/include/api/esp_gattc_api.h similarity index 100% rename from components/bt/bluedroid/api/include/api/esp_gattc_api.h rename to components/bt/host/bluedroid/api/include/api/esp_gattc_api.h diff --git a/components/bt/bluedroid/api/include/api/esp_gatts_api.h b/components/bt/host/bluedroid/api/include/api/esp_gatts_api.h similarity index 100% rename from components/bt/bluedroid/api/include/api/esp_gatts_api.h rename to components/bt/host/bluedroid/api/include/api/esp_gatts_api.h diff --git a/components/bt/bluedroid/api/include/api/esp_hf_client_api.h b/components/bt/host/bluedroid/api/include/api/esp_hf_client_api.h similarity index 100% rename from components/bt/bluedroid/api/include/api/esp_hf_client_api.h rename to components/bt/host/bluedroid/api/include/api/esp_hf_client_api.h diff --git a/components/bt/bluedroid/api/include/api/esp_hf_defs.h b/components/bt/host/bluedroid/api/include/api/esp_hf_defs.h similarity index 100% rename from components/bt/bluedroid/api/include/api/esp_hf_defs.h rename to components/bt/host/bluedroid/api/include/api/esp_hf_defs.h diff --git a/components/bt/bluedroid/api/include/api/esp_spp_api.h b/components/bt/host/bluedroid/api/include/api/esp_spp_api.h similarity index 100% rename from components/bt/bluedroid/api/include/api/esp_spp_api.h rename to components/bt/host/bluedroid/api/include/api/esp_spp_api.h diff --git a/components/bt/bluedroid/bta/ar/bta_ar.c b/components/bt/host/bluedroid/bta/ar/bta_ar.c similarity index 100% rename from components/bt/bluedroid/bta/ar/bta_ar.c rename to components/bt/host/bluedroid/bta/ar/bta_ar.c diff --git a/components/bt/bluedroid/bta/ar/include/bta_ar_int.h b/components/bt/host/bluedroid/bta/ar/include/bta_ar_int.h similarity index 100% rename from components/bt/bluedroid/bta/ar/include/bta_ar_int.h rename to components/bt/host/bluedroid/bta/ar/include/bta_ar_int.h diff --git a/components/bt/bluedroid/bta/av/bta_av_aact.c b/components/bt/host/bluedroid/bta/av/bta_av_aact.c similarity index 100% rename from components/bt/bluedroid/bta/av/bta_av_aact.c rename to components/bt/host/bluedroid/bta/av/bta_av_aact.c diff --git a/components/bt/bluedroid/bta/av/bta_av_act.c b/components/bt/host/bluedroid/bta/av/bta_av_act.c similarity index 100% rename from components/bt/bluedroid/bta/av/bta_av_act.c rename to components/bt/host/bluedroid/bta/av/bta_av_act.c diff --git a/components/bt/bluedroid/bta/av/bta_av_api.c b/components/bt/host/bluedroid/bta/av/bta_av_api.c similarity index 100% rename from components/bt/bluedroid/bta/av/bta_av_api.c rename to components/bt/host/bluedroid/bta/av/bta_av_api.c diff --git a/components/bt/bluedroid/bta/av/bta_av_cfg.c b/components/bt/host/bluedroid/bta/av/bta_av_cfg.c similarity index 100% rename from components/bt/bluedroid/bta/av/bta_av_cfg.c rename to components/bt/host/bluedroid/bta/av/bta_av_cfg.c diff --git a/components/bt/bluedroid/bta/av/bta_av_ci.c b/components/bt/host/bluedroid/bta/av/bta_av_ci.c similarity index 100% rename from components/bt/bluedroid/bta/av/bta_av_ci.c rename to components/bt/host/bluedroid/bta/av/bta_av_ci.c diff --git a/components/bt/bluedroid/bta/av/bta_av_main.c b/components/bt/host/bluedroid/bta/av/bta_av_main.c similarity index 100% rename from components/bt/bluedroid/bta/av/bta_av_main.c rename to components/bt/host/bluedroid/bta/av/bta_av_main.c diff --git a/components/bt/bluedroid/bta/av/bta_av_sbc.c b/components/bt/host/bluedroid/bta/av/bta_av_sbc.c similarity index 100% rename from components/bt/bluedroid/bta/av/bta_av_sbc.c rename to components/bt/host/bluedroid/bta/av/bta_av_sbc.c diff --git a/components/bt/bluedroid/bta/av/bta_av_ssm.c b/components/bt/host/bluedroid/bta/av/bta_av_ssm.c similarity index 100% rename from components/bt/bluedroid/bta/av/bta_av_ssm.c rename to components/bt/host/bluedroid/bta/av/bta_av_ssm.c diff --git a/components/bt/bluedroid/bta/av/include/bta_av_int.h b/components/bt/host/bluedroid/bta/av/include/bta_av_int.h similarity index 100% rename from components/bt/bluedroid/bta/av/include/bta_av_int.h rename to components/bt/host/bluedroid/bta/av/include/bta_av_int.h diff --git a/components/bt/bluedroid/bta/dm/bta_dm_act.c b/components/bt/host/bluedroid/bta/dm/bta_dm_act.c similarity index 100% rename from components/bt/bluedroid/bta/dm/bta_dm_act.c rename to components/bt/host/bluedroid/bta/dm/bta_dm_act.c diff --git a/components/bt/bluedroid/bta/dm/bta_dm_api.c b/components/bt/host/bluedroid/bta/dm/bta_dm_api.c similarity index 100% rename from components/bt/bluedroid/bta/dm/bta_dm_api.c rename to components/bt/host/bluedroid/bta/dm/bta_dm_api.c diff --git a/components/bt/bluedroid/bta/dm/bta_dm_cfg.c b/components/bt/host/bluedroid/bta/dm/bta_dm_cfg.c similarity index 100% rename from components/bt/bluedroid/bta/dm/bta_dm_cfg.c rename to components/bt/host/bluedroid/bta/dm/bta_dm_cfg.c diff --git a/components/bt/bluedroid/bta/dm/bta_dm_ci.c b/components/bt/host/bluedroid/bta/dm/bta_dm_ci.c similarity index 100% rename from components/bt/bluedroid/bta/dm/bta_dm_ci.c rename to components/bt/host/bluedroid/bta/dm/bta_dm_ci.c diff --git a/components/bt/bluedroid/bta/dm/bta_dm_co.c b/components/bt/host/bluedroid/bta/dm/bta_dm_co.c similarity index 100% rename from components/bt/bluedroid/bta/dm/bta_dm_co.c rename to components/bt/host/bluedroid/bta/dm/bta_dm_co.c diff --git a/components/bt/bluedroid/bta/dm/bta_dm_main.c b/components/bt/host/bluedroid/bta/dm/bta_dm_main.c similarity index 100% rename from components/bt/bluedroid/bta/dm/bta_dm_main.c rename to components/bt/host/bluedroid/bta/dm/bta_dm_main.c diff --git a/components/bt/bluedroid/bta/dm/bta_dm_pm.c b/components/bt/host/bluedroid/bta/dm/bta_dm_pm.c similarity index 100% rename from components/bt/bluedroid/bta/dm/bta_dm_pm.c rename to components/bt/host/bluedroid/bta/dm/bta_dm_pm.c diff --git a/components/bt/bluedroid/bta/dm/bta_dm_sco.c b/components/bt/host/bluedroid/bta/dm/bta_dm_sco.c similarity index 100% rename from components/bt/bluedroid/bta/dm/bta_dm_sco.c rename to components/bt/host/bluedroid/bta/dm/bta_dm_sco.c diff --git a/components/bt/bluedroid/bta/dm/include/bta_dm_int.h b/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h similarity index 100% rename from components/bt/bluedroid/bta/dm/include/bta_dm_int.h rename to components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h diff --git a/components/bt/bluedroid/bta/gatt/bta_gatt_common.c b/components/bt/host/bluedroid/bta/gatt/bta_gatt_common.c similarity index 100% rename from components/bt/bluedroid/bta/gatt/bta_gatt_common.c rename to components/bt/host/bluedroid/bta/gatt/bta_gatt_common.c diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_act.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c similarity index 100% rename from components/bt/bluedroid/bta/gatt/bta_gattc_act.c rename to components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_api.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_api.c similarity index 100% rename from components/bt/bluedroid/bta/gatt/bta_gattc_api.c rename to components/bt/host/bluedroid/bta/gatt/bta_gattc_api.c diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_cache.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_cache.c similarity index 100% rename from components/bt/bluedroid/bta/gatt/bta_gattc_cache.c rename to components/bt/host/bluedroid/bta/gatt/bta_gattc_cache.c diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_ci.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_ci.c similarity index 100% rename from components/bt/bluedroid/bta/gatt/bta_gattc_ci.c rename to components/bt/host/bluedroid/bta/gatt/bta_gattc_ci.c diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_co.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_co.c similarity index 100% rename from components/bt/bluedroid/bta/gatt/bta_gattc_co.c rename to components/bt/host/bluedroid/bta/gatt/bta_gattc_co.c diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_main.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_main.c similarity index 100% rename from components/bt/bluedroid/bta/gatt/bta_gattc_main.c rename to components/bt/host/bluedroid/bta/gatt/bta_gattc_main.c diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_utils.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_utils.c similarity index 100% rename from components/bt/bluedroid/bta/gatt/bta_gattc_utils.c rename to components/bt/host/bluedroid/bta/gatt/bta_gattc_utils.c diff --git a/components/bt/bluedroid/bta/gatt/bta_gatts_act.c b/components/bt/host/bluedroid/bta/gatt/bta_gatts_act.c similarity index 100% rename from components/bt/bluedroid/bta/gatt/bta_gatts_act.c rename to components/bt/host/bluedroid/bta/gatt/bta_gatts_act.c diff --git a/components/bt/bluedroid/bta/gatt/bta_gatts_api.c b/components/bt/host/bluedroid/bta/gatt/bta_gatts_api.c similarity index 100% rename from components/bt/bluedroid/bta/gatt/bta_gatts_api.c rename to components/bt/host/bluedroid/bta/gatt/bta_gatts_api.c diff --git a/components/bt/bluedroid/bta/gatt/bta_gatts_co.c b/components/bt/host/bluedroid/bta/gatt/bta_gatts_co.c similarity index 100% rename from components/bt/bluedroid/bta/gatt/bta_gatts_co.c rename to components/bt/host/bluedroid/bta/gatt/bta_gatts_co.c diff --git a/components/bt/bluedroid/bta/gatt/bta_gatts_main.c b/components/bt/host/bluedroid/bta/gatt/bta_gatts_main.c similarity index 100% rename from components/bt/bluedroid/bta/gatt/bta_gatts_main.c rename to components/bt/host/bluedroid/bta/gatt/bta_gatts_main.c diff --git a/components/bt/bluedroid/bta/gatt/bta_gatts_utils.c b/components/bt/host/bluedroid/bta/gatt/bta_gatts_utils.c similarity index 100% rename from components/bt/bluedroid/bta/gatt/bta_gatts_utils.c rename to components/bt/host/bluedroid/bta/gatt/bta_gatts_utils.c diff --git a/components/bt/bluedroid/bta/gatt/include/bta_gattc_int.h b/components/bt/host/bluedroid/bta/gatt/include/bta_gattc_int.h similarity index 100% rename from components/bt/bluedroid/bta/gatt/include/bta_gattc_int.h rename to components/bt/host/bluedroid/bta/gatt/include/bta_gattc_int.h diff --git a/components/bt/bluedroid/bta/gatt/include/bta_gatts_int.h b/components/bt/host/bluedroid/bta/gatt/include/bta_gatts_int.h similarity index 100% rename from components/bt/bluedroid/bta/gatt/include/bta_gatts_int.h rename to components/bt/host/bluedroid/bta/gatt/include/bta_gatts_int.h diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_act.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_act.c similarity index 100% rename from components/bt/bluedroid/bta/hf_client/bta_hf_client_act.c rename to components/bt/host/bluedroid/bta/hf_client/bta_hf_client_act.c diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_api.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_api.c similarity index 100% rename from components/bt/bluedroid/bta/hf_client/bta_hf_client_api.c rename to components/bt/host/bluedroid/bta/hf_client/bta_hf_client_api.c diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_at.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c similarity index 100% rename from components/bt/bluedroid/bta/hf_client/bta_hf_client_at.c rename to components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_cmd.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_cmd.c similarity index 100% rename from components/bt/bluedroid/bta/hf_client/bta_hf_client_cmd.c rename to components/bt/host/bluedroid/bta/hf_client/bta_hf_client_cmd.c diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_main.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_main.c similarity index 100% rename from components/bt/bluedroid/bta/hf_client/bta_hf_client_main.c rename to components/bt/host/bluedroid/bta/hf_client/bta_hf_client_main.c diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_rfc.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_rfc.c similarity index 100% rename from components/bt/bluedroid/bta/hf_client/bta_hf_client_rfc.c rename to components/bt/host/bluedroid/bta/hf_client/bta_hf_client_rfc.c diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_sco.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_sco.c similarity index 100% rename from components/bt/bluedroid/bta/hf_client/bta_hf_client_sco.c rename to components/bt/host/bluedroid/bta/hf_client/bta_hf_client_sco.c diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_sdp.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_sdp.c similarity index 100% rename from components/bt/bluedroid/bta/hf_client/bta_hf_client_sdp.c rename to components/bt/host/bluedroid/bta/hf_client/bta_hf_client_sdp.c diff --git a/components/bt/bluedroid/bta/hf_client/include/bta_hf_client_at.h b/components/bt/host/bluedroid/bta/hf_client/include/bta_hf_client_at.h similarity index 100% rename from components/bt/bluedroid/bta/hf_client/include/bta_hf_client_at.h rename to components/bt/host/bluedroid/bta/hf_client/include/bta_hf_client_at.h diff --git a/components/bt/bluedroid/bta/hf_client/include/bta_hf_client_int.h b/components/bt/host/bluedroid/bta/hf_client/include/bta_hf_client_int.h similarity index 100% rename from components/bt/bluedroid/bta/hf_client/include/bta_hf_client_int.h rename to components/bt/host/bluedroid/bta/hf_client/include/bta_hf_client_int.h diff --git a/components/bt/bluedroid/bta/hh/bta_hh_act.c b/components/bt/host/bluedroid/bta/hh/bta_hh_act.c similarity index 100% rename from components/bt/bluedroid/bta/hh/bta_hh_act.c rename to components/bt/host/bluedroid/bta/hh/bta_hh_act.c diff --git a/components/bt/bluedroid/bta/hh/bta_hh_api.c b/components/bt/host/bluedroid/bta/hh/bta_hh_api.c similarity index 100% rename from components/bt/bluedroid/bta/hh/bta_hh_api.c rename to components/bt/host/bluedroid/bta/hh/bta_hh_api.c diff --git a/components/bt/bluedroid/bta/hh/bta_hh_cfg.c b/components/bt/host/bluedroid/bta/hh/bta_hh_cfg.c similarity index 100% rename from components/bt/bluedroid/bta/hh/bta_hh_cfg.c rename to components/bt/host/bluedroid/bta/hh/bta_hh_cfg.c diff --git a/components/bt/bluedroid/bta/hh/bta_hh_le.c b/components/bt/host/bluedroid/bta/hh/bta_hh_le.c similarity index 100% rename from components/bt/bluedroid/bta/hh/bta_hh_le.c rename to components/bt/host/bluedroid/bta/hh/bta_hh_le.c diff --git a/components/bt/bluedroid/bta/hh/bta_hh_main.c b/components/bt/host/bluedroid/bta/hh/bta_hh_main.c similarity index 100% rename from components/bt/bluedroid/bta/hh/bta_hh_main.c rename to components/bt/host/bluedroid/bta/hh/bta_hh_main.c diff --git a/components/bt/bluedroid/bta/hh/bta_hh_utils.c b/components/bt/host/bluedroid/bta/hh/bta_hh_utils.c similarity index 100% rename from components/bt/bluedroid/bta/hh/bta_hh_utils.c rename to components/bt/host/bluedroid/bta/hh/bta_hh_utils.c diff --git a/components/bt/bluedroid/bta/hh/include/bta_hh_int.h b/components/bt/host/bluedroid/bta/hh/include/bta_hh_int.h similarity index 100% rename from components/bt/bluedroid/bta/hh/include/bta_hh_int.h rename to components/bt/host/bluedroid/bta/hh/include/bta_hh_int.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_api.h b/components/bt/host/bluedroid/bta/include/bta/bta_api.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_api.h rename to components/bt/host/bluedroid/bta/include/bta/bta_api.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_ar_api.h b/components/bt/host/bluedroid/bta/include/bta/bta_ar_api.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_ar_api.h rename to components/bt/host/bluedroid/bta/include/bta/bta_ar_api.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_av_api.h b/components/bt/host/bluedroid/bta/include/bta/bta_av_api.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_av_api.h rename to components/bt/host/bluedroid/bta/include/bta/bta_av_api.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_av_ci.h b/components/bt/host/bluedroid/bta/include/bta/bta_av_ci.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_av_ci.h rename to components/bt/host/bluedroid/bta/include/bta/bta_av_ci.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_av_co.h b/components/bt/host/bluedroid/bta/include/bta/bta_av_co.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_av_co.h rename to components/bt/host/bluedroid/bta/include/bta/bta_av_co.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_av_sbc.h b/components/bt/host/bluedroid/bta/include/bta/bta_av_sbc.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_av_sbc.h rename to components/bt/host/bluedroid/bta/include/bta/bta_av_sbc.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_dm_ci.h b/components/bt/host/bluedroid/bta/include/bta/bta_dm_ci.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_dm_ci.h rename to components/bt/host/bluedroid/bta/include/bta/bta_dm_ci.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_dm_co.h b/components/bt/host/bluedroid/bta/include/bta/bta_dm_co.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_dm_co.h rename to components/bt/host/bluedroid/bta/include/bta/bta_dm_co.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_gap_bt_co.h b/components/bt/host/bluedroid/bta/include/bta/bta_gap_bt_co.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_gap_bt_co.h rename to components/bt/host/bluedroid/bta/include/bta/bta_gap_bt_co.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_gatt_api.h b/components/bt/host/bluedroid/bta/include/bta/bta_gatt_api.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_gatt_api.h rename to components/bt/host/bluedroid/bta/include/bta/bta_gatt_api.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_gatt_common.h b/components/bt/host/bluedroid/bta/include/bta/bta_gatt_common.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_gatt_common.h rename to components/bt/host/bluedroid/bta/include/bta/bta_gatt_common.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_gattc_ci.h b/components/bt/host/bluedroid/bta/include/bta/bta_gattc_ci.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_gattc_ci.h rename to components/bt/host/bluedroid/bta/include/bta/bta_gattc_ci.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_gattc_co.h b/components/bt/host/bluedroid/bta/include/bta/bta_gattc_co.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_gattc_co.h rename to components/bt/host/bluedroid/bta/include/bta/bta_gattc_co.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_gatts_co.h b/components/bt/host/bluedroid/bta/include/bta/bta_gatts_co.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_gatts_co.h rename to components/bt/host/bluedroid/bta/include/bta/bta_gatts_co.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_hf_client_api.h b/components/bt/host/bluedroid/bta/include/bta/bta_hf_client_api.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_hf_client_api.h rename to components/bt/host/bluedroid/bta/include/bta/bta_hf_client_api.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_hf_client_co.h b/components/bt/host/bluedroid/bta/include/bta/bta_hf_client_co.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_hf_client_co.h rename to components/bt/host/bluedroid/bta/include/bta/bta_hf_client_co.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_hfp_defs.h b/components/bt/host/bluedroid/bta/include/bta/bta_hfp_defs.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_hfp_defs.h rename to components/bt/host/bluedroid/bta/include/bta/bta_hfp_defs.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_hh_api.h b/components/bt/host/bluedroid/bta/include/bta/bta_hh_api.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_hh_api.h rename to components/bt/host/bluedroid/bta/include/bta/bta_hh_api.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_hh_co.h b/components/bt/host/bluedroid/bta/include/bta/bta_hh_co.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_hh_co.h rename to components/bt/host/bluedroid/bta/include/bta/bta_hh_co.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_jv_api.h b/components/bt/host/bluedroid/bta/include/bta/bta_jv_api.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_jv_api.h rename to components/bt/host/bluedroid/bta/include/bta/bta_jv_api.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_jv_co.h b/components/bt/host/bluedroid/bta/include/bta/bta_jv_co.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_jv_co.h rename to components/bt/host/bluedroid/bta/include/bta/bta_jv_co.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_sdp_api.h b/components/bt/host/bluedroid/bta/include/bta/bta_sdp_api.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_sdp_api.h rename to components/bt/host/bluedroid/bta/include/bta/bta_sdp_api.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_sys.h b/components/bt/host/bluedroid/bta/include/bta/bta_sys.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/bta_sys.h rename to components/bt/host/bluedroid/bta/include/bta/bta_sys.h diff --git a/components/bt/bluedroid/bta/include/bta/utl.h b/components/bt/host/bluedroid/bta/include/bta/utl.h similarity index 100% rename from components/bt/bluedroid/bta/include/bta/utl.h rename to components/bt/host/bluedroid/bta/include/bta/utl.h diff --git a/components/bt/bluedroid/bta/jv/bta_jv_act.c b/components/bt/host/bluedroid/bta/jv/bta_jv_act.c similarity index 100% rename from components/bt/bluedroid/bta/jv/bta_jv_act.c rename to components/bt/host/bluedroid/bta/jv/bta_jv_act.c diff --git a/components/bt/bluedroid/bta/jv/bta_jv_api.c b/components/bt/host/bluedroid/bta/jv/bta_jv_api.c similarity index 100% rename from components/bt/bluedroid/bta/jv/bta_jv_api.c rename to components/bt/host/bluedroid/bta/jv/bta_jv_api.c diff --git a/components/bt/bluedroid/bta/jv/bta_jv_cfg.c b/components/bt/host/bluedroid/bta/jv/bta_jv_cfg.c similarity index 100% rename from components/bt/bluedroid/bta/jv/bta_jv_cfg.c rename to components/bt/host/bluedroid/bta/jv/bta_jv_cfg.c diff --git a/components/bt/bluedroid/bta/jv/bta_jv_main.c b/components/bt/host/bluedroid/bta/jv/bta_jv_main.c similarity index 100% rename from components/bt/bluedroid/bta/jv/bta_jv_main.c rename to components/bt/host/bluedroid/bta/jv/bta_jv_main.c diff --git a/components/bt/bluedroid/bta/jv/include/bta_jv_int.h b/components/bt/host/bluedroid/bta/jv/include/bta_jv_int.h similarity index 100% rename from components/bt/bluedroid/bta/jv/include/bta_jv_int.h rename to components/bt/host/bluedroid/bta/jv/include/bta_jv_int.h diff --git a/components/bt/bluedroid/bta/sdp/bta_sdp.c b/components/bt/host/bluedroid/bta/sdp/bta_sdp.c similarity index 100% rename from components/bt/bluedroid/bta/sdp/bta_sdp.c rename to components/bt/host/bluedroid/bta/sdp/bta_sdp.c diff --git a/components/bt/bluedroid/bta/sdp/bta_sdp_act.c b/components/bt/host/bluedroid/bta/sdp/bta_sdp_act.c similarity index 100% rename from components/bt/bluedroid/bta/sdp/bta_sdp_act.c rename to components/bt/host/bluedroid/bta/sdp/bta_sdp_act.c diff --git a/components/bt/bluedroid/bta/sdp/bta_sdp_api.c b/components/bt/host/bluedroid/bta/sdp/bta_sdp_api.c similarity index 100% rename from components/bt/bluedroid/bta/sdp/bta_sdp_api.c rename to components/bt/host/bluedroid/bta/sdp/bta_sdp_api.c diff --git a/components/bt/bluedroid/bta/sdp/bta_sdp_cfg.c b/components/bt/host/bluedroid/bta/sdp/bta_sdp_cfg.c similarity index 100% rename from components/bt/bluedroid/bta/sdp/bta_sdp_cfg.c rename to components/bt/host/bluedroid/bta/sdp/bta_sdp_cfg.c diff --git a/components/bt/bluedroid/bta/sdp/include/bta_sdp_int.h b/components/bt/host/bluedroid/bta/sdp/include/bta_sdp_int.h similarity index 100% rename from components/bt/bluedroid/bta/sdp/include/bta_sdp_int.h rename to components/bt/host/bluedroid/bta/sdp/include/bta_sdp_int.h diff --git a/components/bt/bluedroid/bta/sys/bta_sys_conn.c b/components/bt/host/bluedroid/bta/sys/bta_sys_conn.c similarity index 100% rename from components/bt/bluedroid/bta/sys/bta_sys_conn.c rename to components/bt/host/bluedroid/bta/sys/bta_sys_conn.c diff --git a/components/bt/bluedroid/bta/sys/bta_sys_main.c b/components/bt/host/bluedroid/bta/sys/bta_sys_main.c similarity index 100% rename from components/bt/bluedroid/bta/sys/bta_sys_main.c rename to components/bt/host/bluedroid/bta/sys/bta_sys_main.c diff --git a/components/bt/bluedroid/bta/sys/include/bta_sys_int.h b/components/bt/host/bluedroid/bta/sys/include/bta_sys_int.h similarity index 100% rename from components/bt/bluedroid/bta/sys/include/bta_sys_int.h rename to components/bt/host/bluedroid/bta/sys/include/bta_sys_int.h diff --git a/components/bt/bluedroid/bta/sys/utl.c b/components/bt/host/bluedroid/bta/sys/utl.c similarity index 100% rename from components/bt/bluedroid/bta/sys/utl.c rename to components/bt/host/bluedroid/bta/sys/utl.c diff --git a/components/bt/bluedroid/btc/core/btc_ble_storage.c b/components/bt/host/bluedroid/btc/core/btc_ble_storage.c similarity index 100% rename from components/bt/bluedroid/btc/core/btc_ble_storage.c rename to components/bt/host/bluedroid/btc/core/btc_ble_storage.c diff --git a/components/bt/bluedroid/btc/core/btc_config.c b/components/bt/host/bluedroid/btc/core/btc_config.c similarity index 100% rename from components/bt/bluedroid/btc/core/btc_config.c rename to components/bt/host/bluedroid/btc/core/btc_config.c diff --git a/components/bt/bluedroid/btc/core/btc_dev.c b/components/bt/host/bluedroid/btc/core/btc_dev.c similarity index 100% rename from components/bt/bluedroid/btc/core/btc_dev.c rename to components/bt/host/bluedroid/btc/core/btc_dev.c diff --git a/components/bt/bluedroid/btc/core/btc_dm.c b/components/bt/host/bluedroid/btc/core/btc_dm.c similarity index 100% rename from components/bt/bluedroid/btc/core/btc_dm.c rename to components/bt/host/bluedroid/btc/core/btc_dm.c diff --git a/components/bt/bluedroid/btc/core/btc_main.c b/components/bt/host/bluedroid/btc/core/btc_main.c similarity index 100% rename from components/bt/bluedroid/btc/core/btc_main.c rename to components/bt/host/bluedroid/btc/core/btc_main.c diff --git a/components/bt/bluedroid/btc/core/btc_profile_queue.c b/components/bt/host/bluedroid/btc/core/btc_profile_queue.c similarity index 100% rename from components/bt/bluedroid/btc/core/btc_profile_queue.c rename to components/bt/host/bluedroid/btc/core/btc_profile_queue.c diff --git a/components/bt/bluedroid/btc/core/btc_sec.c b/components/bt/host/bluedroid/btc/core/btc_sec.c similarity index 100% rename from components/bt/bluedroid/btc/core/btc_sec.c rename to components/bt/host/bluedroid/btc/core/btc_sec.c diff --git a/components/bt/bluedroid/btc/core/btc_sm.c b/components/bt/host/bluedroid/btc/core/btc_sm.c similarity index 100% rename from components/bt/bluedroid/btc/core/btc_sm.c rename to components/bt/host/bluedroid/btc/core/btc_sm.c diff --git a/components/bt/bluedroid/btc/core/btc_storage.c b/components/bt/host/bluedroid/btc/core/btc_storage.c similarity index 100% rename from components/bt/bluedroid/btc/core/btc_storage.c rename to components/bt/host/bluedroid/btc/core/btc_storage.c diff --git a/components/bt/bluedroid/btc/core/btc_util.c b/components/bt/host/bluedroid/btc/core/btc_util.c similarity index 100% rename from components/bt/bluedroid/btc/core/btc_util.c rename to components/bt/host/bluedroid/btc/core/btc_util.c diff --git a/components/bt/bluedroid/btc/include/btc/btc_ble_storage.h b/components/bt/host/bluedroid/btc/include/btc/btc_ble_storage.h similarity index 100% rename from components/bt/bluedroid/btc/include/btc/btc_ble_storage.h rename to components/bt/host/bluedroid/btc/include/btc/btc_ble_storage.h diff --git a/components/bt/bluedroid/btc/include/btc/btc_common.h b/components/bt/host/bluedroid/btc/include/btc/btc_common.h similarity index 100% rename from components/bt/bluedroid/btc/include/btc/btc_common.h rename to components/bt/host/bluedroid/btc/include/btc/btc_common.h diff --git a/components/bt/bluedroid/btc/include/btc/btc_config.h b/components/bt/host/bluedroid/btc/include/btc/btc_config.h similarity index 100% rename from components/bt/bluedroid/btc/include/btc/btc_config.h rename to components/bt/host/bluedroid/btc/include/btc/btc_config.h diff --git a/components/bt/bluedroid/btc/include/btc/btc_dev.h b/components/bt/host/bluedroid/btc/include/btc/btc_dev.h similarity index 100% rename from components/bt/bluedroid/btc/include/btc/btc_dev.h rename to components/bt/host/bluedroid/btc/include/btc/btc_dev.h diff --git a/components/bt/bluedroid/btc/include/btc/btc_dm.h b/components/bt/host/bluedroid/btc/include/btc/btc_dm.h similarity index 100% rename from components/bt/bluedroid/btc/include/btc/btc_dm.h rename to components/bt/host/bluedroid/btc/include/btc/btc_dm.h diff --git a/components/bt/bluedroid/btc/include/btc/btc_main.h b/components/bt/host/bluedroid/btc/include/btc/btc_main.h similarity index 100% rename from components/bt/bluedroid/btc/include/btc/btc_main.h rename to components/bt/host/bluedroid/btc/include/btc/btc_main.h diff --git a/components/bt/bluedroid/btc/include/btc/btc_profile_queue.h b/components/bt/host/bluedroid/btc/include/btc/btc_profile_queue.h similarity index 100% rename from components/bt/bluedroid/btc/include/btc/btc_profile_queue.h rename to components/bt/host/bluedroid/btc/include/btc/btc_profile_queue.h diff --git a/components/bt/bluedroid/btc/include/btc/btc_sm.h b/components/bt/host/bluedroid/btc/include/btc/btc_sm.h similarity index 100% rename from components/bt/bluedroid/btc/include/btc/btc_sm.h rename to components/bt/host/bluedroid/btc/include/btc/btc_sm.h diff --git a/components/bt/bluedroid/btc/include/btc/btc_storage.h b/components/bt/host/bluedroid/btc/include/btc/btc_storage.h similarity index 100% rename from components/bt/bluedroid/btc/include/btc/btc_storage.h rename to components/bt/host/bluedroid/btc/include/btc/btc_storage.h diff --git a/components/bt/bluedroid/btc/include/btc/btc_util.h b/components/bt/host/bluedroid/btc/include/btc/btc_util.h similarity index 100% rename from components/bt/bluedroid/btc/include/btc/btc_util.h rename to components/bt/host/bluedroid/btc/include/btc/btc_util.h diff --git a/components/bt/bluedroid/btc/profile/esp/ble_button/button_pro.c b/components/bt/host/bluedroid/btc/profile/esp/ble_button/button_pro.c similarity index 100% rename from components/bt/bluedroid/btc/profile/esp/ble_button/button_pro.c rename to components/bt/host/bluedroid/btc/profile/esp/ble_button/button_pro.c diff --git a/components/bt/bluedroid/btc/profile/esp/blufi/blufi_prf.c b/components/bt/host/bluedroid/btc/profile/esp/blufi/blufi_prf.c similarity index 100% rename from components/bt/bluedroid/btc/profile/esp/blufi/blufi_prf.c rename to components/bt/host/bluedroid/btc/profile/esp/blufi/blufi_prf.c diff --git a/components/bt/bluedroid/btc/profile/esp/blufi/blufi_protocol.c b/components/bt/host/bluedroid/btc/profile/esp/blufi/blufi_protocol.c similarity index 100% rename from components/bt/bluedroid/btc/profile/esp/blufi/blufi_protocol.c rename to components/bt/host/bluedroid/btc/profile/esp/blufi/blufi_protocol.c diff --git a/components/bt/bluedroid/btc/profile/esp/blufi/include/blufi_int.h b/components/bt/host/bluedroid/btc/profile/esp/blufi/include/blufi_int.h similarity index 100% rename from components/bt/bluedroid/btc/profile/esp/blufi/include/blufi_int.h rename to components/bt/host/bluedroid/btc/profile/esp/blufi/include/blufi_int.h diff --git a/components/bt/bluedroid/btc/profile/esp/include/btc_blufi_prf.h b/components/bt/host/bluedroid/btc/profile/esp/include/btc_blufi_prf.h similarity index 100% rename from components/bt/bluedroid/btc/profile/esp/include/btc_blufi_prf.h rename to components/bt/host/bluedroid/btc/profile/esp/include/btc_blufi_prf.h diff --git a/components/bt/bluedroid/btc/profile/esp/include/button_pro.h b/components/bt/host/bluedroid/btc/profile/esp/include/button_pro.h similarity index 100% rename from components/bt/bluedroid/btc/profile/esp/include/button_pro.h rename to components/bt/host/bluedroid/btc/profile/esp/include/button_pro.h diff --git a/components/bt/bluedroid/btc/profile/esp/include/wx_airsync_prf.h b/components/bt/host/bluedroid/btc/profile/esp/include/wx_airsync_prf.h similarity index 100% rename from components/bt/bluedroid/btc/profile/esp/include/wx_airsync_prf.h rename to components/bt/host/bluedroid/btc/profile/esp/include/wx_airsync_prf.h diff --git a/components/bt/bluedroid/btc/profile/esp/wechat_AirSync/wx_airsync_prf.c b/components/bt/host/bluedroid/btc/profile/esp/wechat_AirSync/wx_airsync_prf.c similarity index 100% rename from components/bt/bluedroid/btc/profile/esp/wechat_AirSync/wx_airsync_prf.c rename to components/bt/host/bluedroid/btc/profile/esp/wechat_AirSync/wx_airsync_prf.c diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/bta_av_co.c b/components/bt/host/bluedroid/btc/profile/std/a2dp/bta_av_co.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/a2dp/bta_av_co.c rename to components/bt/host/bluedroid/btc/profile/std/a2dp/bta_av_co.c diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp.c b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp.c rename to components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp.c diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_control.c b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_control.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_control.c rename to components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_control.c diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c rename to components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c rename to components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/btc_av.c b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_av.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/a2dp/btc_av.c rename to components/bt/host/bluedroid/btc/profile/std/a2dp/btc_av.c diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/include/btc_av_co.h b/components/bt/host/bluedroid/btc/profile/std/a2dp/include/btc_av_co.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/a2dp/include/btc_av_co.h rename to components/bt/host/bluedroid/btc/profile/std/a2dp/include/btc_av_co.h diff --git a/components/bt/bluedroid/btc/profile/std/avrc/bta_avrc_co.c b/components/bt/host/bluedroid/btc/profile/std/avrc/bta_avrc_co.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/avrc/bta_avrc_co.c rename to components/bt/host/bluedroid/btc/profile/std/avrc/bta_avrc_co.c diff --git a/components/bt/bluedroid/btc/profile/std/avrc/btc_avrc.c b/components/bt/host/bluedroid/btc/profile/std/avrc/btc_avrc.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/avrc/btc_avrc.c rename to components/bt/host/bluedroid/btc/profile/std/avrc/btc_avrc.c diff --git a/components/bt/bluedroid/btc/profile/std/battery/battery_prf.c b/components/bt/host/bluedroid/btc/profile/std/battery/battery_prf.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/battery/battery_prf.c rename to components/bt/host/bluedroid/btc/profile/std/battery/battery_prf.c diff --git a/components/bt/bluedroid/btc/profile/std/battery/include/srvc_battery_int.h b/components/bt/host/bluedroid/btc/profile/std/battery/include/srvc_battery_int.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/battery/include/srvc_battery_int.h rename to components/bt/host/bluedroid/btc/profile/std/battery/include/srvc_battery_int.h diff --git a/components/bt/bluedroid/btc/profile/std/dis/dis_profile.c b/components/bt/host/bluedroid/btc/profile/std/dis/dis_profile.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/dis/dis_profile.c rename to components/bt/host/bluedroid/btc/profile/std/dis/dis_profile.c diff --git a/components/bt/bluedroid/btc/profile/std/dis/include/srvc_dis_int.h b/components/bt/host/bluedroid/btc/profile/std/dis/include/srvc_dis_int.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/dis/include/srvc_dis_int.h rename to components/bt/host/bluedroid/btc/profile/std/dis/include/srvc_dis_int.h diff --git a/components/bt/bluedroid/btc/profile/std/gap/bta_gap_bt_co.c b/components/bt/host/bluedroid/btc/profile/std/gap/bta_gap_bt_co.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/gap/bta_gap_bt_co.c rename to components/bt/host/bluedroid/btc/profile/std/gap/bta_gap_bt_co.c diff --git a/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c rename to components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c diff --git a/components/bt/bluedroid/btc/profile/std/gap/btc_gap_bt.c b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_bt.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/gap/btc_gap_bt.c rename to components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_bt.c diff --git a/components/bt/bluedroid/btc/profile/std/gatt/btc_gatt_common.c b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatt_common.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/gatt/btc_gatt_common.c rename to components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatt_common.c diff --git a/components/bt/bluedroid/btc/profile/std/gatt/btc_gatt_util.c b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatt_util.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/gatt/btc_gatt_util.c rename to components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatt_util.c diff --git a/components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gattc.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c rename to components/bt/host/bluedroid/btc/profile/std/gatt/btc_gattc.c diff --git a/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatts.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c rename to components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatts.c diff --git a/components/bt/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c b/components/bt/host/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c rename to components/bt/host/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c diff --git a/components/bt/bluedroid/btc/profile/std/hf_client/btc_hf_client.c b/components/bt/host/bluedroid/btc/profile/std/hf_client/btc_hf_client.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/hf_client/btc_hf_client.c rename to components/bt/host/bluedroid/btc/profile/std/hf_client/btc_hf_client.c diff --git a/components/bt/bluedroid/btc/profile/std/hid/include/hid_conn.h b/components/bt/host/bluedroid/btc/profile/std/hid/include/hid_conn.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/hid/include/hid_conn.h rename to components/bt/host/bluedroid/btc/profile/std/hid/include/hid_conn.h diff --git a/components/bt/bluedroid/btc/profile/std/hid/include/hidh_int.h b/components/bt/host/bluedroid/btc/profile/std/hid/include/hidh_int.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/hid/include/hidh_int.h rename to components/bt/host/bluedroid/btc/profile/std/hid/include/hidh_int.h diff --git a/components/bt/bluedroid/btc/profile/std/include/bt_sdp.h b/components/bt/host/bluedroid/btc/profile/std/include/bt_sdp.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/bt_sdp.h rename to components/bt/host/bluedroid/btc/profile/std/include/bt_sdp.h diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_a2dp.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_a2dp.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/btc_a2dp.h rename to components/bt/host/bluedroid/btc/profile/std/include/btc_a2dp.h diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_a2dp_control.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_a2dp_control.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/btc_a2dp_control.h rename to components/bt/host/bluedroid/btc/profile/std/include/btc_a2dp_control.h diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_a2dp_sink.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_a2dp_sink.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/btc_a2dp_sink.h rename to components/bt/host/bluedroid/btc/profile/std/include/btc_a2dp_sink.h diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_a2dp_source.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_a2dp_source.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/btc_a2dp_source.h rename to components/bt/host/bluedroid/btc/profile/std/include/btc_a2dp_source.h diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_av.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_av.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/btc_av.h rename to components/bt/host/bluedroid/btc/profile/std/include/btc_av.h diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_av_api.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_av_api.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/btc_av_api.h rename to components/bt/host/bluedroid/btc/profile/std/include/btc_av_api.h diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_avrc.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_avrc.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/btc_avrc.h rename to components/bt/host/bluedroid/btc/profile/std/include/btc_avrc.h diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_gap_ble.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_gap_ble.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/btc_gap_ble.h rename to components/bt/host/bluedroid/btc/profile/std/include/btc_gap_ble.h diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_gap_bt.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_gap_bt.h similarity index 99% rename from components/bt/bluedroid/btc/profile/std/include/btc_gap_bt.h rename to components/bt/host/bluedroid/btc/profile/std/include/btc_gap_bt.h index cae2a09bc1..7214da8777 100644 --- a/components/bt/bluedroid/btc/profile/std/include/btc_gap_bt.h +++ b/components/bt/host/bluedroid/btc/profile/std/include/btc_gap_bt.h @@ -16,6 +16,7 @@ #define __BTC_GAP_BT_H__ #include "common/bt_target.h" +#include "common/bt_defs.h" #include "esp_bt_defs.h" #include "esp_gap_bt_api.h" #include "btc/btc_task.h" diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_gatt_common.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_gatt_common.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/btc_gatt_common.h rename to components/bt/host/bluedroid/btc/profile/std/include/btc_gatt_common.h diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_gatt_util.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_gatt_util.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/btc_gatt_util.h rename to components/bt/host/bluedroid/btc/profile/std/include/btc_gatt_util.h diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_gattc.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_gattc.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/btc_gattc.h rename to components/bt/host/bluedroid/btc/profile/std/include/btc_gattc.h diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_gatts.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_gatts.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/btc_gatts.h rename to components/bt/host/bluedroid/btc/profile/std/include/btc_gatts.h diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_hf_client.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_hf_client.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/btc_hf_client.h rename to components/bt/host/bluedroid/btc/profile/std/include/btc_hf_client.h diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_spp.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_spp.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/btc_spp.h rename to components/bt/host/bluedroid/btc/profile/std/include/btc_spp.h diff --git a/components/bt/bluedroid/btc/profile/std/include/dis_api.h b/components/bt/host/bluedroid/btc/profile/std/include/dis_api.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/dis_api.h rename to components/bt/host/bluedroid/btc/profile/std/include/dis_api.h diff --git a/components/bt/bluedroid/btc/profile/std/include/srvc_api.h b/components/bt/host/bluedroid/btc/profile/std/include/srvc_api.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/srvc_api.h rename to components/bt/host/bluedroid/btc/profile/std/include/srvc_api.h diff --git a/components/bt/bluedroid/btc/profile/std/smp/esp_app_sec.c b/components/bt/host/bluedroid/btc/profile/std/smp/esp_app_sec.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/smp/esp_app_sec.c rename to components/bt/host/bluedroid/btc/profile/std/smp/esp_app_sec.c diff --git a/components/bt/bluedroid/btc/profile/std/smp/include/esp_sec_api.h b/components/bt/host/bluedroid/btc/profile/std/smp/include/esp_sec_api.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/smp/include/esp_sec_api.h rename to components/bt/host/bluedroid/btc/profile/std/smp/include/esp_sec_api.h diff --git a/components/bt/bluedroid/btc/profile/std/spp/btc_spp.c b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c similarity index 100% rename from components/bt/bluedroid/btc/profile/std/spp/btc_spp.c rename to components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c diff --git a/components/bt/bluedroid/common/include/common/bt_user_config.h b/components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h similarity index 80% rename from components/bt/bluedroid/common/include/common/bt_user_config.h rename to components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h index 7fa8ed5c51..b107a01e15 100644 --- a/components/bt/bluedroid/common/include/common/bt_user_config.h +++ b/components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h @@ -12,29 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef __BT_USER_CONFIG_H__ -#define __BT_USER_CONFIG_H__ +#ifndef __BLUEDROID_USER_CONFIG_H__ +#define __BLUEDROID_USER_CONFIG_H__ /* All the configuration from SDK defined here */ - -#include "sdkconfig.h" -#include "esp_task.h" - +#include "bt_common.h" +#include "bt_user_config.h" /********************************************************** * Thread/Task reference **********************************************************/ -#ifdef CONFIG_BLUEDROID_PINNED_TO_CORE -#define UC_TASK_PINNED_TO_CORE (CONFIG_BLUEDROID_PINNED_TO_CORE < portNUM_PROCESSORS ? CONFIG_BLUEDROID_PINNED_TO_CORE : tskNO_AFFINITY) -#else -#define UC_TASK_PINNED_TO_CORE (0) -#endif - -#ifdef CONFIG_BTC_TASK_STACK_SIZE -#define UC_BTC_TASK_STACK_SIZE CONFIG_BTC_TASK_STACK_SIZE -#else -#define UC_BTC_TASK_STACK_SIZE 3072 -#endif #ifdef CONFIG_A2DP_SINK_TASK_STACK_SIZE #define UC_A2DP_SINK_TASK_STACK_SIZE CONFIG_A2DP_SINK_TASK_STACK_SIZE @@ -193,12 +180,6 @@ /********************************************************** * Memory reference **********************************************************/ -//DYNAMIC ENV ALLOCATOR -#ifdef CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY -#define UC_BT_BLE_DYNAMIC_ENV_MEMORY CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY -#else -#define UC_BT_BLE_DYNAMIC_ENV_MEMORY FALSE -#endif //MEMORY ALLOCATOR #ifdef CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST @@ -218,30 +199,6 @@ /********************************************************** * Trace reference **********************************************************/ -#ifdef CONFIG_LOG_DEFAULT_LEVEL -#define UC_LOG_DEFAULT_LEVEL CONFIG_LOG_DEFAULT_LEVEL -#else -#define UC_LOG_DEFAULT_LEVEL 3 -#endif -#ifdef CONFIG_BOOTLOADER_LOG_LEVEL -#define UC_BOOTLOADER_LOG_LEVEL CONFIG_BOOTLOADER_LOG_LEVEL -#else -#define UC_BOOTLOADER_LOG_LEVEL 3 -#endif - -#ifdef CONFIG_BT_STACK_NO_LOG -#define UC_BT_STACK_NO_LOG CONFIG_BT_STACK_NO_LOG -#else -#define UC_BT_STACK_NO_LOG FALSE -#endif - -#define UC_TRACE_LEVEL_NONE 0 /* No trace messages to be generated */ -#define UC_TRACE_LEVEL_ERROR 1 /* Error condition trace messages */ -#define UC_TRACE_LEVEL_WARNING 2 /* Warning condition trace messages */ -#define UC_TRACE_LEVEL_API 3 /* API traces */ -#define UC_TRACE_LEVEL_EVENT 4 /* Debug messages for events */ -#define UC_TRACE_LEVEL_DEBUG 5 /* Full debug messages */ -#define UC_TRACE_LEVEL_VERBOSE 6 /* Verbose debug messages */ #ifdef CONFIG_BT_LOG_HCI_TRACE_LEVEL #define UC_BT_LOG_HCI_TRACE_LEVEL CONFIG_BT_LOG_HCI_TRACE_LEVEL @@ -351,25 +308,10 @@ #define UC_BT_LOG_BTIF_TRACE_LEVEL UC_TRACE_LEVEL_WARNING #endif -#ifdef CONFIG_BT_LOG_BTC_TRACE_LEVEL -#define UC_BT_LOG_BTC_TRACE_LEVEL CONFIG_BT_LOG_BTC_TRACE_LEVEL -#else -#define UC_BT_LOG_BTC_TRACE_LEVEL UC_TRACE_LEVEL_WARNING -#endif - -#ifdef CONFIG_BT_LOG_OSI_TRACE_LEVEL -#define UC_BT_LOG_OSI_TRACE_LEVEL CONFIG_BT_LOG_OSI_TRACE_LEVEL -#else -#define UC_BT_LOG_OSI_TRACE_LEVEL UC_TRACE_LEVEL_WARNING -#endif - #ifdef CONFIG_BT_LOG_BLUFI_TRACE_LEVEL #define UC_BT_LOG_BLUFI_TRACE_LEVEL CONFIG_BT_LOG_BLUFI_TRACE_LEVEL #else #define UC_BT_LOG_BLUFI_TRACE_LEVEL UC_TRACE_LEVEL_WARNING #endif -#endif /* __BT_USER_CONFIG_H__ */ - - - +#endif /* __BLUEDROID_USER_CONFIG_H__ */ diff --git a/components/bt/bluedroid/common/include/common/bt_common_types.h b/components/bt/host/bluedroid/common/include/common/bt_common_types.h similarity index 100% rename from components/bt/bluedroid/common/include/common/bt_common_types.h rename to components/bt/host/bluedroid/common/include/common/bt_common_types.h diff --git a/components/bt/bluedroid/common/include/common/bt_defs.h b/components/bt/host/bluedroid/common/include/common/bt_defs.h similarity index 80% rename from components/bt/bluedroid/common/include/common/bt_defs.h rename to components/bt/host/bluedroid/common/include/common/bt_defs.h index 7cfa3d5b8e..7421e7b147 100644 --- a/components/bt/bluedroid/common/include/common/bt_defs.h +++ b/components/bt/host/bluedroid/common/include/common/bt_defs.h @@ -21,7 +21,7 @@ #include #include -#include "common/bt_trace.h" +#include "bt_common.h" #include "common/bt_target.h" #define UNUSED(x) (void)(x) @@ -65,32 +65,6 @@ typedef struct { uint8_t uu[16]; } bt_uuid_t; -/** Bluetooth Error Status */ -/** We need to build on this */ - -/* relate to ESP_BT_STATUS_xxx in esp_bt_defs.h */ -typedef enum { - BT_STATUS_SUCCESS = 0, - BT_STATUS_FAIL, - BT_STATUS_NOT_READY, - BT_STATUS_NOMEM, - BT_STATUS_BUSY, - BT_STATUS_DONE, /* request already completed */ - BT_STATUS_UNSUPPORTED, - BT_STATUS_PARM_INVALID, - BT_STATUS_UNHANDLED, - BT_STATUS_AUTH_FAILURE, - BT_STATUS_RMT_DEV_DOWN, - BT_STATUS_AUTH_REJECTED, - BT_STATUS_INVALID_STATIC_RAND_ADDR, - BT_STATUS_PENDING, - BT_STATUS_UNACCEPT_CONN_INTERVAL, - BT_STATUS_PARAM_OUT_OF_RANGE, - BT_STATUS_TIMEOUT, - BT_STATUS_MEMORY_FULL, - BT_STATUS_EIR_TOO_LARGE, -} bt_status_t; - #ifndef CPU_LITTLE_ENDIAN #define CPU_LITTLE_ENDIAN #endif diff --git a/components/bt/bluedroid/common/include/common/bt_target.h b/components/bt/host/bluedroid/common/include/common/bt_target.h similarity index 99% rename from components/bt/bluedroid/common/include/common/bt_target.h rename to components/bt/host/bluedroid/common/include/common/bt_target.h index 6adf32a9f5..146a1ad110 100644 --- a/components/bt/bluedroid/common/include/common/bt_target.h +++ b/components/bt/host/bluedroid/common/include/common/bt_target.h @@ -20,6 +20,8 @@ #ifndef BT_TARGET_H #define BT_TARGET_H +#include + #ifndef BUILDCFG #define BUILDCFG #endif @@ -34,16 +36,13 @@ #include "bdroid_buildcfg.h" #endif -#include "bt_user_config.h" +#include "bluedroid_user_config.h" #include "stack/bt_types.h" /* This must be defined AFTER buildcfg.h */ #include "stack/dyn_mem.h" /* defines static and/or dynamic memory for components */ /* OS Configuration from User config (eg: sdkconfig) */ -#define TASK_PINNED_TO_CORE UC_TASK_PINNED_TO_CORE -#define BT_TASK_MAX_PRIORITIES configMAX_PRIORITIES -#define BT_BTC_TASK_STACK_SIZE UC_BTC_TASK_STACK_SIZE #define A2DP_SINK_TASK_STACK_SIZE UC_A2DP_SINK_TASK_STACK_SIZE #define A2DP_SOURCE_TASK_STACK_SIZE UC_A2DP_SOURCE_TASK_STACK_SIZE @@ -355,10 +354,6 @@ #define BTA_AV_CO_CP_SCMS_T FALSE #endif -#ifndef QUEUE_CONGEST_SIZE -#define QUEUE_CONGEST_SIZE 40 -#endif - #if UC_BT_BLE_HOST_QUEUE_CONGESTION_CHECK #define SCAN_QUEUE_CONGEST_CHECK TRUE #else diff --git a/components/bt/bluedroid/common/include/common/bt_trace.h b/components/bt/host/bluedroid/common/include/common/bt_trace.h similarity index 88% rename from components/bt/bluedroid/common/include/common/bt_trace.h rename to components/bt/host/bluedroid/common/include/common/bt_trace.h index 920cfa7134..09412ca7f3 100644 --- a/components/bt/bluedroid/common/include/common/bt_trace.h +++ b/components/bt/host/bluedroid/common/include/common/bt_trace.h @@ -21,40 +21,9 @@ #include #include -#include "bt_user_config.h" +#include "bluedroid_user_config.h" #include "stack/bt_types.h" - -#ifndef LOG_LOCAL_LEVEL -#ifndef BOOTLOADER_BUILD -#define LOG_LOCAL_LEVEL UC_LOG_DEFAULT_LEVEL -#else -#define LOG_LOCAL_LEVEL UC_BOOTLOADER_LOG_LEVEL -#endif -#endif - -#include "esp_log.h" - -// Mapping between ESP_LOG_LEVEL and BT_TRACE_LEVEL -#if (LOG_LOCAL_LEVEL >= 4) -#define LOG_LOCAL_LEVEL_MAPPING (LOG_LOCAL_LEVEL+1) -#else -#define LOG_LOCAL_LEVEL_MAPPING LOG_LOCAL_LEVEL -#endif - -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define BT_LOG_LEVEL_CHECK(LAYER, LEVEL) (MAX(LAYER##_INITIAL_TRACE_LEVEL, LOG_LOCAL_LEVEL_MAPPING) >= BT_TRACE_LEVEL_##LEVEL) - -//#define TAG "BT" - -#define BT_PRINT_E(tag, format, ...) {esp_log_write(ESP_LOG_ERROR, tag, LOG_FORMAT(E, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } -#define BT_PRINT_W(tag, format, ...) {esp_log_write(ESP_LOG_WARN, tag, LOG_FORMAT(W, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } -#define BT_PRINT_I(tag, format, ...) {esp_log_write(ESP_LOG_INFO, tag, LOG_FORMAT(I, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } -#define BT_PRINT_D(tag, format, ...) {esp_log_write(ESP_LOG_DEBUG, tag, LOG_FORMAT(D, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } -#define BT_PRINT_V(tag, format, ...) {esp_log_write(ESP_LOG_VERBOSE, tag, LOG_FORMAT(V, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } - -#ifndef assert -#define assert(x) do { if (!(x)) BT_PRINT_E(TAG, "bt host error %s %u\n", __FILE__, __LINE__); } while (0) -#endif +#include "bt_common.h" inline void trc_dump_buffer(const char *prefix, uint8_t *data, uint16_t len) { @@ -234,8 +203,6 @@ inline void trc_dump_buffer(const char *prefix, uint8_t *data, uint16_t len) #define GATT_INITIAL_TRACE_LEVEL UC_BT_LOG_GATT_TRACE_LEVEL #define SMP_INITIAL_TRACE_LEVEL UC_BT_LOG_SMP_TRACE_LEVEL #define BTIF_INITIAL_TRACE_LEVEL UC_BT_LOG_BTIF_TRACE_LEVEL -#define BTC_INITIAL_TRACE_LEVEL UC_BT_LOG_BTC_TRACE_LEVEL -#define OSI_INITIAL_TRACE_LEVEL UC_BT_LOG_OSI_TRACE_LEVEL #define BLUFI_INITIAL_TRACE_LEVEL UC_BT_LOG_BLUFI_TRACE_LEVEL // btla-specific -- @@ -393,22 +360,6 @@ extern UINT8 btif_trace_level; #define HCI_TRACE_EVENT(fmt, args...) {if (HCI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_EVENT && BT_LOG_LEVEL_CHECK(HCI,EVENT)) BT_PRINT_D("BT_HCI", fmt,## args);} #define HCI_TRACE_DEBUG(fmt, args...) {if (HCI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_DEBUG && BT_LOG_LEVEL_CHECK(HCI,DEBUG)) BT_PRINT_D("BT_HCI", fmt,## args);} -/* define traces for BTC */ -#define BTC_TRACE_ERROR(fmt, args...) {if (BTC_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_ERROR && BT_LOG_LEVEL_CHECK(BTC, ERROR)) BT_PRINT_E("BT_BTC", fmt, ## args);} -#define BTC_TRACE_WARNING(fmt, args...) {if (BTC_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_WARNING && BT_LOG_LEVEL_CHECK(BTC, WARNING)) BT_PRINT_W("BT_BTC", fmt, ## args);} -#define BTC_TRACE_API(fmt, args...) {if (BTC_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_API && BT_LOG_LEVEL_CHECK(BTC,API)) BT_PRINT_I("BT_BTC", fmt, ## args);} -#define BTC_TRACE_EVENT(fmt, args...) {if (BTC_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_EVENT && BT_LOG_LEVEL_CHECK(BTC,EVENT)) BT_PRINT_D("BT_BTC", fmt, ## args);} -#define BTC_TRACE_DEBUG(fmt, args...) {if (BTC_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_DEBUG && BT_LOG_LEVEL_CHECK(BTC,DEBUG)) BT_PRINT_D("BT_BTC", fmt, ## args);} -#define BTC_TRACE_VERBOSE(fmt, args...) {if (BTC_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_VERBOSE && BT_LOG_LEVEL_CHECK(BTC,VERBOSE)) BT_PRINT_V("BT_BTC", fmt, ## args);} - -/* define traces for OSI */ -#define OSI_TRACE_ERROR(fmt, args...) {if (OSI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_ERROR && BT_LOG_LEVEL_CHECK(OSI, ERROR)) BT_PRINT_E("BT_OSI", fmt, ## args);} -#define OSI_TRACE_WARNING(fmt, args...) {if (OSI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_WARNING && BT_LOG_LEVEL_CHECK(OSI, WARNING)) BT_PRINT_W("BT_OSI", fmt, ## args);} -#define OSI_TRACE_API(fmt, args...) {if (OSI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_API && BT_LOG_LEVEL_CHECK(OSI,API)) BT_PRINT_I("BT_OSI", fmt, ## args);} -#define OSI_TRACE_EVENT(fmt, args...) {if (OSI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_EVENT && BT_LOG_LEVEL_CHECK(OSI,EVENT)) BT_PRINT_D("BT_OSI", fmt, ## args);} -#define OSI_TRACE_DEBUG(fmt, args...) {if (OSI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_DEBUG && BT_LOG_LEVEL_CHECK(OSI,DEBUG)) BT_PRINT_D("BT_OSI", fmt, ## args);} -#define OSI_TRACE_VERBOSE(fmt, args...) {if (OSI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_VERBOSE && BT_LOG_LEVEL_CHECK(OSI,VERBOSE)) BT_PRINT_V("BT_OSI", fmt, ## args);} - /* define traces for BLUFI */ #define BLUFI_TRACE_ERROR(fmt, args...) {if (BLUFI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_ERROR && BT_LOG_LEVEL_CHECK(BLUFI, ERROR)) BT_PRINT_E("BT_BLUFI", fmt, ## args);} #define BLUFI_TRACE_WARNING(fmt, args...) {if (BLUFI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_WARNING && BT_LOG_LEVEL_CHECK(BLUFI, WARNING)) BT_PRINT_W("BT_BLUFI", fmt, ## args);} @@ -567,22 +518,6 @@ extern UINT8 btif_trace_level; #define APPL_TRACE_DEBUG(fmt, args...) #define APPL_TRACE_VERBOSE(fmt, args...) -/* define traces for BTC */ -#define BTC_TRACE_ERROR(fmt, args...) -#define BTC_TRACE_WARNING(fmt, args...) -#define BTC_TRACE_API(fmt, args...) -#define BTC_TRACE_EVENT(fmt, args...) -#define BTC_TRACE_DEBUG(fmt, args...) -#define BTC_TRACE_VERBOSE(fmt, args...) - -/* define traces for OSI */ -#define OSI_TRACE_ERROR(fmt, args...) -#define OSI_TRACE_WARNING(fmt, args...) -#define OSI_TRACE_API(fmt, args...) -#define OSI_TRACE_EVENT(fmt, args...) -#define OSI_TRACE_DEBUG(fmt, args...) -#define OSI_TRACE_VERBOSE(fmt, args...) - /* define traces for BLUFI */ #define BLUFI_TRACE_ERROR(fmt, args...) #define BLUFI_TRACE_WARNING(fmt, args...) diff --git a/components/bt/bluedroid/common/include/common/bt_vendor_lib.h b/components/bt/host/bluedroid/common/include/common/bt_vendor_lib.h similarity index 100% rename from components/bt/bluedroid/common/include/common/bt_vendor_lib.h rename to components/bt/host/bluedroid/common/include/common/bt_vendor_lib.h diff --git a/components/bt/bluedroid/common/include/common/bte.h b/components/bt/host/bluedroid/common/include/common/bte.h similarity index 100% rename from components/bt/bluedroid/common/include/common/bte.h rename to components/bt/host/bluedroid/common/include/common/bte.h diff --git a/components/bt/bluedroid/common/include/common/bte_appl.h b/components/bt/host/bluedroid/common/include/common/bte_appl.h similarity index 100% rename from components/bt/bluedroid/common/include/common/bte_appl.h rename to components/bt/host/bluedroid/common/include/common/bte_appl.h diff --git a/components/bt/bluedroid/device/bdaddr.c b/components/bt/host/bluedroid/device/bdaddr.c similarity index 100% rename from components/bt/bluedroid/device/bdaddr.c rename to components/bt/host/bluedroid/device/bdaddr.c diff --git a/components/bt/bluedroid/device/controller.c b/components/bt/host/bluedroid/device/controller.c similarity index 99% rename from components/bt/bluedroid/device/controller.c rename to components/bt/host/bluedroid/device/controller.c index 84d6f59737..96c773ebe2 100644 --- a/components/bt/bluedroid/device/controller.c +++ b/components/bt/host/bluedroid/device/controller.c @@ -549,7 +549,7 @@ const controller_t *controller_get_interface() static bool loaded = false; if (!loaded) { loaded = true; -#if BT_BLE_DYNAMIC_ENV_MEMORY == TRUE +#if (BT_BLE_DYNAMIC_ENV_MEMORY == TRUE) controller_param_ptr = (controller_local_param_t *)osi_calloc(sizeof(controller_local_param_t)); assert(controller_param_ptr); #endif diff --git a/components/bt/bluedroid/device/include/device/bdaddr.h b/components/bt/host/bluedroid/device/include/device/bdaddr.h similarity index 100% rename from components/bt/bluedroid/device/include/device/bdaddr.h rename to components/bt/host/bluedroid/device/include/device/bdaddr.h diff --git a/components/bt/bluedroid/device/include/device/controller.h b/components/bt/host/bluedroid/device/include/device/controller.h similarity index 100% rename from components/bt/bluedroid/device/include/device/controller.h rename to components/bt/host/bluedroid/device/include/device/controller.h diff --git a/components/bt/bluedroid/device/include/device/device_features.h b/components/bt/host/bluedroid/device/include/device/device_features.h similarity index 100% rename from components/bt/bluedroid/device/include/device/device_features.h rename to components/bt/host/bluedroid/device/include/device/device_features.h diff --git a/components/bt/bluedroid/device/include/device/event_mask.h b/components/bt/host/bluedroid/device/include/device/event_mask.h similarity index 100% rename from components/bt/bluedroid/device/include/device/event_mask.h rename to components/bt/host/bluedroid/device/include/device/event_mask.h diff --git a/components/bt/bluedroid/device/include/device/interop.h b/components/bt/host/bluedroid/device/include/device/interop.h similarity index 100% rename from components/bt/bluedroid/device/include/device/interop.h rename to components/bt/host/bluedroid/device/include/device/interop.h diff --git a/components/bt/bluedroid/device/include/device/interop_database.h b/components/bt/host/bluedroid/device/include/device/interop_database.h similarity index 100% rename from components/bt/bluedroid/device/include/device/interop_database.h rename to components/bt/host/bluedroid/device/include/device/interop_database.h diff --git a/components/bt/bluedroid/device/include/device/version.h b/components/bt/host/bluedroid/device/include/device/version.h similarity index 100% rename from components/bt/bluedroid/device/include/device/version.h rename to components/bt/host/bluedroid/device/include/device/version.h diff --git a/components/bt/bluedroid/device/interop.c b/components/bt/host/bluedroid/device/interop.c similarity index 100% rename from components/bt/bluedroid/device/interop.c rename to components/bt/host/bluedroid/device/interop.c diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_assert.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_assert.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_assert.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_assert.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_bitstream.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_bitstream.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_bitstream.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_bitstream.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_bt_spec.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_bt_spec.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_bt_spec.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_bt_spec.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_codec_sbc.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_codec_sbc.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_codec_sbc.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_codec_sbc.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_codec_sbc_private.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_codec_sbc_private.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_codec_sbc_private.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_codec_sbc_private.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_common.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_common.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_common.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_common.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_cpu_dep.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_cpu_dep.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_cpu_dep.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_cpu_dep.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_modules.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_modules.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_modules.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_modules.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_osinterface.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_osinterface.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_osinterface.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_osinterface.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_status.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_status.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_status.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_status.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_stddefs.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_stddefs.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_stddefs.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_stddefs.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_string.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_string.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_string.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_string.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_time.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_time.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_time.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_time.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_utils.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_utils.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_utils.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_utils.h diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/alloc.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/alloc.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/alloc.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/alloc.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/bitalloc-sbc.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/bitalloc-sbc.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/bitalloc-sbc.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/bitalloc-sbc.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/bitalloc.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/bitalloc.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/bitalloc.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/bitalloc.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/bitstream-decode.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/bitstream-decode.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/bitstream-decode.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/bitstream-decode.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/decoder-oina.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/decoder-oina.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/decoder-oina.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/decoder-oina.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/decoder-private.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/decoder-private.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/decoder-private.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/decoder-private.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/decoder-sbc.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/decoder-sbc.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/decoder-sbc.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/decoder-sbc.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/dequant.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/dequant.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/dequant.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/dequant.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/framing-sbc.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/framing-sbc.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/framing-sbc.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/framing-sbc.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/framing.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/framing.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/framing.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/framing.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/oi_codec_version.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/oi_codec_version.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/oi_codec_version.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/oi_codec_version.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/readsamplesjoint.inc b/components/bt/host/bluedroid/external/sbc/decoder/srce/readsamplesjoint.inc similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/readsamplesjoint.inc rename to components/bt/host/bluedroid/external/sbc/decoder/srce/readsamplesjoint.inc diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/synthesis-8-generated.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/synthesis-8-generated.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/synthesis-8-generated.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/synthesis-8-generated.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/synthesis-dct8.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/synthesis-dct8.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/synthesis-dct8.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/synthesis-dct8.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/synthesis-sbc.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/synthesis-sbc.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/synthesis-sbc.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/synthesis-sbc.c diff --git a/components/bt/bluedroid/external/sbc/encoder/include/sbc_dct.h b/components/bt/host/bluedroid/external/sbc/encoder/include/sbc_dct.h similarity index 100% rename from components/bt/bluedroid/external/sbc/encoder/include/sbc_dct.h rename to components/bt/host/bluedroid/external/sbc/encoder/include/sbc_dct.h diff --git a/components/bt/bluedroid/external/sbc/encoder/include/sbc_enc_func_declare.h b/components/bt/host/bluedroid/external/sbc/encoder/include/sbc_enc_func_declare.h similarity index 100% rename from components/bt/bluedroid/external/sbc/encoder/include/sbc_enc_func_declare.h rename to components/bt/host/bluedroid/external/sbc/encoder/include/sbc_enc_func_declare.h diff --git a/components/bt/bluedroid/external/sbc/encoder/include/sbc_encoder.h b/components/bt/host/bluedroid/external/sbc/encoder/include/sbc_encoder.h similarity index 100% rename from components/bt/bluedroid/external/sbc/encoder/include/sbc_encoder.h rename to components/bt/host/bluedroid/external/sbc/encoder/include/sbc_encoder.h diff --git a/components/bt/bluedroid/external/sbc/encoder/include/sbc_if.h b/components/bt/host/bluedroid/external/sbc/encoder/include/sbc_if.h similarity index 100% rename from components/bt/bluedroid/external/sbc/encoder/include/sbc_if.h rename to components/bt/host/bluedroid/external/sbc/encoder/include/sbc_if.h diff --git a/components/bt/bluedroid/external/sbc/encoder/include/sbc_types.h b/components/bt/host/bluedroid/external/sbc/encoder/include/sbc_types.h similarity index 100% rename from components/bt/bluedroid/external/sbc/encoder/include/sbc_types.h rename to components/bt/host/bluedroid/external/sbc/encoder/include/sbc_types.h diff --git a/components/bt/bluedroid/external/sbc/encoder/srce/sbc_analysis.c b/components/bt/host/bluedroid/external/sbc/encoder/srce/sbc_analysis.c similarity index 100% rename from components/bt/bluedroid/external/sbc/encoder/srce/sbc_analysis.c rename to components/bt/host/bluedroid/external/sbc/encoder/srce/sbc_analysis.c diff --git a/components/bt/bluedroid/external/sbc/encoder/srce/sbc_dct.c b/components/bt/host/bluedroid/external/sbc/encoder/srce/sbc_dct.c similarity index 100% rename from components/bt/bluedroid/external/sbc/encoder/srce/sbc_dct.c rename to components/bt/host/bluedroid/external/sbc/encoder/srce/sbc_dct.c diff --git a/components/bt/bluedroid/external/sbc/encoder/srce/sbc_dct_coeffs.c b/components/bt/host/bluedroid/external/sbc/encoder/srce/sbc_dct_coeffs.c similarity index 100% rename from components/bt/bluedroid/external/sbc/encoder/srce/sbc_dct_coeffs.c rename to components/bt/host/bluedroid/external/sbc/encoder/srce/sbc_dct_coeffs.c diff --git a/components/bt/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c b/components/bt/host/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c similarity index 100% rename from components/bt/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c rename to components/bt/host/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c diff --git a/components/bt/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c b/components/bt/host/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c similarity index 100% rename from components/bt/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c rename to components/bt/host/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c diff --git a/components/bt/bluedroid/external/sbc/encoder/srce/sbc_enc_coeffs.c b/components/bt/host/bluedroid/external/sbc/encoder/srce/sbc_enc_coeffs.c similarity index 100% rename from components/bt/bluedroid/external/sbc/encoder/srce/sbc_enc_coeffs.c rename to components/bt/host/bluedroid/external/sbc/encoder/srce/sbc_enc_coeffs.c diff --git a/components/bt/bluedroid/external/sbc/encoder/srce/sbc_encoder.c b/components/bt/host/bluedroid/external/sbc/encoder/srce/sbc_encoder.c similarity index 100% rename from components/bt/bluedroid/external/sbc/encoder/srce/sbc_encoder.c rename to components/bt/host/bluedroid/external/sbc/encoder/srce/sbc_encoder.c diff --git a/components/bt/bluedroid/external/sbc/encoder/srce/sbc_packing.c b/components/bt/host/bluedroid/external/sbc/encoder/srce/sbc_packing.c similarity index 100% rename from components/bt/bluedroid/external/sbc/encoder/srce/sbc_packing.c rename to components/bt/host/bluedroid/external/sbc/encoder/srce/sbc_packing.c diff --git a/components/bt/bluedroid/external/sbc/plc/include/sbc_plc.h b/components/bt/host/bluedroid/external/sbc/plc/include/sbc_plc.h similarity index 100% rename from components/bt/bluedroid/external/sbc/plc/include/sbc_plc.h rename to components/bt/host/bluedroid/external/sbc/plc/include/sbc_plc.h diff --git a/components/bt/bluedroid/external/sbc/plc/sbc_plc.c b/components/bt/host/bluedroid/external/sbc/plc/sbc_plc.c similarity index 100% rename from components/bt/bluedroid/external/sbc/plc/sbc_plc.c rename to components/bt/host/bluedroid/external/sbc/plc/sbc_plc.c diff --git a/components/bt/bluedroid/hci/hci_audio.c b/components/bt/host/bluedroid/hci/hci_audio.c similarity index 100% rename from components/bt/bluedroid/hci/hci_audio.c rename to components/bt/host/bluedroid/hci/hci_audio.c diff --git a/components/bt/bluedroid/hci/hci_hal_h4.c b/components/bt/host/bluedroid/hci/hci_hal_h4.c similarity index 100% rename from components/bt/bluedroid/hci/hci_hal_h4.c rename to components/bt/host/bluedroid/hci/hci_hal_h4.c diff --git a/components/bt/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c similarity index 100% rename from components/bt/bluedroid/hci/hci_layer.c rename to components/bt/host/bluedroid/hci/hci_layer.c diff --git a/components/bt/bluedroid/hci/hci_packet_factory.c b/components/bt/host/bluedroid/hci/hci_packet_factory.c similarity index 100% rename from components/bt/bluedroid/hci/hci_packet_factory.c rename to components/bt/host/bluedroid/hci/hci_packet_factory.c diff --git a/components/bt/bluedroid/hci/hci_packet_parser.c b/components/bt/host/bluedroid/hci/hci_packet_parser.c similarity index 100% rename from components/bt/bluedroid/hci/hci_packet_parser.c rename to components/bt/host/bluedroid/hci/hci_packet_parser.c diff --git a/components/bt/bluedroid/hci/include/hci/bt_vendor_lib.h b/components/bt/host/bluedroid/hci/include/hci/bt_vendor_lib.h similarity index 100% rename from components/bt/bluedroid/hci/include/hci/bt_vendor_lib.h rename to components/bt/host/bluedroid/hci/include/hci/bt_vendor_lib.h diff --git a/components/bt/bluedroid/hci/include/hci/hci_audio.h b/components/bt/host/bluedroid/hci/include/hci/hci_audio.h similarity index 100% rename from components/bt/bluedroid/hci/include/hci/hci_audio.h rename to components/bt/host/bluedroid/hci/include/hci/hci_audio.h diff --git a/components/bt/bluedroid/hci/include/hci/hci_hal.h b/components/bt/host/bluedroid/hci/include/hci/hci_hal.h similarity index 100% rename from components/bt/bluedroid/hci/include/hci/hci_hal.h rename to components/bt/host/bluedroid/hci/include/hci/hci_hal.h diff --git a/components/bt/bluedroid/hci/include/hci/hci_internals.h b/components/bt/host/bluedroid/hci/include/hci/hci_internals.h similarity index 100% rename from components/bt/bluedroid/hci/include/hci/hci_internals.h rename to components/bt/host/bluedroid/hci/include/hci/hci_internals.h diff --git a/components/bt/bluedroid/hci/include/hci/hci_layer.h b/components/bt/host/bluedroid/hci/include/hci/hci_layer.h similarity index 100% rename from components/bt/bluedroid/hci/include/hci/hci_layer.h rename to components/bt/host/bluedroid/hci/include/hci/hci_layer.h diff --git a/components/bt/bluedroid/hci/include/hci/hci_packet_factory.h b/components/bt/host/bluedroid/hci/include/hci/hci_packet_factory.h similarity index 100% rename from components/bt/bluedroid/hci/include/hci/hci_packet_factory.h rename to components/bt/host/bluedroid/hci/include/hci/hci_packet_factory.h diff --git a/components/bt/bluedroid/hci/include/hci/hci_packet_parser.h b/components/bt/host/bluedroid/hci/include/hci/hci_packet_parser.h similarity index 100% rename from components/bt/bluedroid/hci/include/hci/hci_packet_parser.h rename to components/bt/host/bluedroid/hci/include/hci/hci_packet_parser.h diff --git a/components/bt/bluedroid/hci/include/hci/packet_fragmenter.h b/components/bt/host/bluedroid/hci/include/hci/packet_fragmenter.h similarity index 100% rename from components/bt/bluedroid/hci/include/hci/packet_fragmenter.h rename to components/bt/host/bluedroid/hci/include/hci/packet_fragmenter.h diff --git a/components/bt/bluedroid/hci/packet_fragmenter.c b/components/bt/host/bluedroid/hci/packet_fragmenter.c similarity index 100% rename from components/bt/bluedroid/hci/packet_fragmenter.c rename to components/bt/host/bluedroid/hci/packet_fragmenter.c diff --git a/components/bt/bluedroid/main/bte_init.c b/components/bt/host/bluedroid/main/bte_init.c similarity index 100% rename from components/bt/bluedroid/main/bte_init.c rename to components/bt/host/bluedroid/main/bte_init.c diff --git a/components/bt/bluedroid/main/bte_main.c b/components/bt/host/bluedroid/main/bte_main.c similarity index 100% rename from components/bt/bluedroid/main/bte_main.c rename to components/bt/host/bluedroid/main/bte_main.c diff --git a/components/bt/bluedroid/stack/a2dp/a2d_api.c b/components/bt/host/bluedroid/stack/a2dp/a2d_api.c similarity index 100% rename from components/bt/bluedroid/stack/a2dp/a2d_api.c rename to components/bt/host/bluedroid/stack/a2dp/a2d_api.c diff --git a/components/bt/bluedroid/stack/a2dp/a2d_sbc.c b/components/bt/host/bluedroid/stack/a2dp/a2d_sbc.c similarity index 100% rename from components/bt/bluedroid/stack/a2dp/a2d_sbc.c rename to components/bt/host/bluedroid/stack/a2dp/a2d_sbc.c diff --git a/components/bt/bluedroid/stack/a2dp/include/a2d_int.h b/components/bt/host/bluedroid/stack/a2dp/include/a2d_int.h similarity index 100% rename from components/bt/bluedroid/stack/a2dp/include/a2d_int.h rename to components/bt/host/bluedroid/stack/a2dp/include/a2d_int.h diff --git a/components/bt/bluedroid/stack/avct/avct_api.c b/components/bt/host/bluedroid/stack/avct/avct_api.c similarity index 100% rename from components/bt/bluedroid/stack/avct/avct_api.c rename to components/bt/host/bluedroid/stack/avct/avct_api.c diff --git a/components/bt/bluedroid/stack/avct/avct_ccb.c b/components/bt/host/bluedroid/stack/avct/avct_ccb.c similarity index 100% rename from components/bt/bluedroid/stack/avct/avct_ccb.c rename to components/bt/host/bluedroid/stack/avct/avct_ccb.c diff --git a/components/bt/bluedroid/stack/avct/avct_l2c.c b/components/bt/host/bluedroid/stack/avct/avct_l2c.c similarity index 100% rename from components/bt/bluedroid/stack/avct/avct_l2c.c rename to components/bt/host/bluedroid/stack/avct/avct_l2c.c diff --git a/components/bt/bluedroid/stack/avct/avct_lcb.c b/components/bt/host/bluedroid/stack/avct/avct_lcb.c similarity index 100% rename from components/bt/bluedroid/stack/avct/avct_lcb.c rename to components/bt/host/bluedroid/stack/avct/avct_lcb.c diff --git a/components/bt/bluedroid/stack/avct/avct_lcb_act.c b/components/bt/host/bluedroid/stack/avct/avct_lcb_act.c similarity index 100% rename from components/bt/bluedroid/stack/avct/avct_lcb_act.c rename to components/bt/host/bluedroid/stack/avct/avct_lcb_act.c diff --git a/components/bt/bluedroid/stack/avct/include/avct_defs.h b/components/bt/host/bluedroid/stack/avct/include/avct_defs.h similarity index 100% rename from components/bt/bluedroid/stack/avct/include/avct_defs.h rename to components/bt/host/bluedroid/stack/avct/include/avct_defs.h diff --git a/components/bt/bluedroid/stack/avct/include/avct_int.h b/components/bt/host/bluedroid/stack/avct/include/avct_int.h similarity index 100% rename from components/bt/bluedroid/stack/avct/include/avct_int.h rename to components/bt/host/bluedroid/stack/avct/include/avct_int.h diff --git a/components/bt/bluedroid/stack/avdt/avdt_ad.c b/components/bt/host/bluedroid/stack/avdt/avdt_ad.c similarity index 100% rename from components/bt/bluedroid/stack/avdt/avdt_ad.c rename to components/bt/host/bluedroid/stack/avdt/avdt_ad.c diff --git a/components/bt/bluedroid/stack/avdt/avdt_api.c b/components/bt/host/bluedroid/stack/avdt/avdt_api.c similarity index 100% rename from components/bt/bluedroid/stack/avdt/avdt_api.c rename to components/bt/host/bluedroid/stack/avdt/avdt_api.c diff --git a/components/bt/bluedroid/stack/avdt/avdt_ccb.c b/components/bt/host/bluedroid/stack/avdt/avdt_ccb.c similarity index 100% rename from components/bt/bluedroid/stack/avdt/avdt_ccb.c rename to components/bt/host/bluedroid/stack/avdt/avdt_ccb.c diff --git a/components/bt/bluedroid/stack/avdt/avdt_ccb_act.c b/components/bt/host/bluedroid/stack/avdt/avdt_ccb_act.c similarity index 100% rename from components/bt/bluedroid/stack/avdt/avdt_ccb_act.c rename to components/bt/host/bluedroid/stack/avdt/avdt_ccb_act.c diff --git a/components/bt/bluedroid/stack/avdt/avdt_l2c.c b/components/bt/host/bluedroid/stack/avdt/avdt_l2c.c similarity index 100% rename from components/bt/bluedroid/stack/avdt/avdt_l2c.c rename to components/bt/host/bluedroid/stack/avdt/avdt_l2c.c diff --git a/components/bt/bluedroid/stack/avdt/avdt_msg.c b/components/bt/host/bluedroid/stack/avdt/avdt_msg.c similarity index 100% rename from components/bt/bluedroid/stack/avdt/avdt_msg.c rename to components/bt/host/bluedroid/stack/avdt/avdt_msg.c diff --git a/components/bt/bluedroid/stack/avdt/avdt_scb.c b/components/bt/host/bluedroid/stack/avdt/avdt_scb.c similarity index 100% rename from components/bt/bluedroid/stack/avdt/avdt_scb.c rename to components/bt/host/bluedroid/stack/avdt/avdt_scb.c diff --git a/components/bt/bluedroid/stack/avdt/avdt_scb_act.c b/components/bt/host/bluedroid/stack/avdt/avdt_scb_act.c similarity index 100% rename from components/bt/bluedroid/stack/avdt/avdt_scb_act.c rename to components/bt/host/bluedroid/stack/avdt/avdt_scb_act.c diff --git a/components/bt/bluedroid/stack/avdt/include/avdt_defs.h b/components/bt/host/bluedroid/stack/avdt/include/avdt_defs.h similarity index 100% rename from components/bt/bluedroid/stack/avdt/include/avdt_defs.h rename to components/bt/host/bluedroid/stack/avdt/include/avdt_defs.h diff --git a/components/bt/bluedroid/stack/avdt/include/avdt_int.h b/components/bt/host/bluedroid/stack/avdt/include/avdt_int.h similarity index 100% rename from components/bt/bluedroid/stack/avdt/include/avdt_int.h rename to components/bt/host/bluedroid/stack/avdt/include/avdt_int.h diff --git a/components/bt/bluedroid/stack/avrc/avrc_api.c b/components/bt/host/bluedroid/stack/avrc/avrc_api.c similarity index 100% rename from components/bt/bluedroid/stack/avrc/avrc_api.c rename to components/bt/host/bluedroid/stack/avrc/avrc_api.c diff --git a/components/bt/bluedroid/stack/avrc/avrc_bld_ct.c b/components/bt/host/bluedroid/stack/avrc/avrc_bld_ct.c similarity index 100% rename from components/bt/bluedroid/stack/avrc/avrc_bld_ct.c rename to components/bt/host/bluedroid/stack/avrc/avrc_bld_ct.c diff --git a/components/bt/bluedroid/stack/avrc/avrc_bld_tg.c b/components/bt/host/bluedroid/stack/avrc/avrc_bld_tg.c similarity index 100% rename from components/bt/bluedroid/stack/avrc/avrc_bld_tg.c rename to components/bt/host/bluedroid/stack/avrc/avrc_bld_tg.c diff --git a/components/bt/bluedroid/stack/avrc/avrc_opt.c b/components/bt/host/bluedroid/stack/avrc/avrc_opt.c similarity index 100% rename from components/bt/bluedroid/stack/avrc/avrc_opt.c rename to components/bt/host/bluedroid/stack/avrc/avrc_opt.c diff --git a/components/bt/bluedroid/stack/avrc/avrc_pars_ct.c b/components/bt/host/bluedroid/stack/avrc/avrc_pars_ct.c similarity index 100% rename from components/bt/bluedroid/stack/avrc/avrc_pars_ct.c rename to components/bt/host/bluedroid/stack/avrc/avrc_pars_ct.c diff --git a/components/bt/bluedroid/stack/avrc/avrc_pars_tg.c b/components/bt/host/bluedroid/stack/avrc/avrc_pars_tg.c similarity index 100% rename from components/bt/bluedroid/stack/avrc/avrc_pars_tg.c rename to components/bt/host/bluedroid/stack/avrc/avrc_pars_tg.c diff --git a/components/bt/bluedroid/stack/avrc/avrc_sdp.c b/components/bt/host/bluedroid/stack/avrc/avrc_sdp.c similarity index 100% rename from components/bt/bluedroid/stack/avrc/avrc_sdp.c rename to components/bt/host/bluedroid/stack/avrc/avrc_sdp.c diff --git a/components/bt/bluedroid/stack/avrc/avrc_utils.c b/components/bt/host/bluedroid/stack/avrc/avrc_utils.c similarity index 100% rename from components/bt/bluedroid/stack/avrc/avrc_utils.c rename to components/bt/host/bluedroid/stack/avrc/avrc_utils.c diff --git a/components/bt/bluedroid/stack/avrc/include/avrc_int.h b/components/bt/host/bluedroid/stack/avrc/include/avrc_int.h similarity index 100% rename from components/bt/bluedroid/stack/avrc/include/avrc_int.h rename to components/bt/host/bluedroid/stack/avrc/include/avrc_int.h diff --git a/components/bt/bluedroid/stack/btm/btm_acl.c b/components/bt/host/bluedroid/stack/btm/btm_acl.c similarity index 100% rename from components/bt/bluedroid/stack/btm/btm_acl.c rename to components/bt/host/bluedroid/stack/btm/btm_acl.c diff --git a/components/bt/bluedroid/stack/btm/btm_ble.c b/components/bt/host/bluedroid/stack/btm/btm_ble.c similarity index 100% rename from components/bt/bluedroid/stack/btm/btm_ble.c rename to components/bt/host/bluedroid/stack/btm/btm_ble.c diff --git a/components/bt/bluedroid/stack/btm/btm_ble_addr.c b/components/bt/host/bluedroid/stack/btm/btm_ble_addr.c similarity index 100% rename from components/bt/bluedroid/stack/btm/btm_ble_addr.c rename to components/bt/host/bluedroid/stack/btm/btm_ble_addr.c diff --git a/components/bt/bluedroid/stack/btm/btm_ble_adv_filter.c b/components/bt/host/bluedroid/stack/btm/btm_ble_adv_filter.c similarity index 100% rename from components/bt/bluedroid/stack/btm/btm_ble_adv_filter.c rename to components/bt/host/bluedroid/stack/btm/btm_ble_adv_filter.c diff --git a/components/bt/bluedroid/stack/btm/btm_ble_batchscan.c b/components/bt/host/bluedroid/stack/btm/btm_ble_batchscan.c similarity index 100% rename from components/bt/bluedroid/stack/btm/btm_ble_batchscan.c rename to components/bt/host/bluedroid/stack/btm/btm_ble_batchscan.c diff --git a/components/bt/bluedroid/stack/btm/btm_ble_bgconn.c b/components/bt/host/bluedroid/stack/btm/btm_ble_bgconn.c similarity index 100% rename from components/bt/bluedroid/stack/btm/btm_ble_bgconn.c rename to components/bt/host/bluedroid/stack/btm/btm_ble_bgconn.c diff --git a/components/bt/bluedroid/stack/btm/btm_ble_cont_energy.c b/components/bt/host/bluedroid/stack/btm/btm_ble_cont_energy.c similarity index 100% rename from components/bt/bluedroid/stack/btm/btm_ble_cont_energy.c rename to components/bt/host/bluedroid/stack/btm/btm_ble_cont_energy.c diff --git a/components/bt/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c similarity index 100% rename from components/bt/bluedroid/stack/btm/btm_ble_gap.c rename to components/bt/host/bluedroid/stack/btm/btm_ble_gap.c diff --git a/components/bt/bluedroid/stack/btm/btm_ble_multi_adv.c b/components/bt/host/bluedroid/stack/btm/btm_ble_multi_adv.c similarity index 100% rename from components/bt/bluedroid/stack/btm/btm_ble_multi_adv.c rename to components/bt/host/bluedroid/stack/btm/btm_ble_multi_adv.c diff --git a/components/bt/bluedroid/stack/btm/btm_ble_privacy.c b/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c similarity index 100% rename from components/bt/bluedroid/stack/btm/btm_ble_privacy.c rename to components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c diff --git a/components/bt/bluedroid/stack/btm/btm_dev.c b/components/bt/host/bluedroid/stack/btm/btm_dev.c similarity index 100% rename from components/bt/bluedroid/stack/btm/btm_dev.c rename to components/bt/host/bluedroid/stack/btm/btm_dev.c diff --git a/components/bt/bluedroid/stack/btm/btm_devctl.c b/components/bt/host/bluedroid/stack/btm/btm_devctl.c similarity index 100% rename from components/bt/bluedroid/stack/btm/btm_devctl.c rename to components/bt/host/bluedroid/stack/btm/btm_devctl.c diff --git a/components/bt/bluedroid/stack/btm/btm_inq.c b/components/bt/host/bluedroid/stack/btm/btm_inq.c similarity index 100% rename from components/bt/bluedroid/stack/btm/btm_inq.c rename to components/bt/host/bluedroid/stack/btm/btm_inq.c diff --git a/components/bt/bluedroid/stack/btm/btm_main.c b/components/bt/host/bluedroid/stack/btm/btm_main.c similarity index 100% rename from components/bt/bluedroid/stack/btm/btm_main.c rename to components/bt/host/bluedroid/stack/btm/btm_main.c diff --git a/components/bt/bluedroid/stack/btm/btm_pm.c b/components/bt/host/bluedroid/stack/btm/btm_pm.c similarity index 100% rename from components/bt/bluedroid/stack/btm/btm_pm.c rename to components/bt/host/bluedroid/stack/btm/btm_pm.c diff --git a/components/bt/bluedroid/stack/btm/btm_sco.c b/components/bt/host/bluedroid/stack/btm/btm_sco.c similarity index 100% rename from components/bt/bluedroid/stack/btm/btm_sco.c rename to components/bt/host/bluedroid/stack/btm/btm_sco.c diff --git a/components/bt/bluedroid/stack/btm/btm_sec.c b/components/bt/host/bluedroid/stack/btm/btm_sec.c similarity index 100% rename from components/bt/bluedroid/stack/btm/btm_sec.c rename to components/bt/host/bluedroid/stack/btm/btm_sec.c diff --git a/components/bt/bluedroid/stack/btm/include/btm_ble_int.h b/components/bt/host/bluedroid/stack/btm/include/btm_ble_int.h similarity index 100% rename from components/bt/bluedroid/stack/btm/include/btm_ble_int.h rename to components/bt/host/bluedroid/stack/btm/include/btm_ble_int.h diff --git a/components/bt/bluedroid/stack/btm/include/btm_int.h b/components/bt/host/bluedroid/stack/btm/include/btm_int.h similarity index 100% rename from components/bt/bluedroid/stack/btm/include/btm_int.h rename to components/bt/host/bluedroid/stack/btm/include/btm_int.h diff --git a/components/bt/bluedroid/stack/btu/btu_hcif.c b/components/bt/host/bluedroid/stack/btu/btu_hcif.c similarity index 100% rename from components/bt/bluedroid/stack/btu/btu_hcif.c rename to components/bt/host/bluedroid/stack/btu/btu_hcif.c diff --git a/components/bt/bluedroid/stack/btu/btu_init.c b/components/bt/host/bluedroid/stack/btu/btu_init.c similarity index 98% rename from components/bt/bluedroid/stack/btu/btu_init.c rename to components/bt/host/bluedroid/stack/btu/btu_init.c index 617bb5de66..52ce3a6e15 100644 --- a/components/bt/bluedroid/stack/btu/btu_init.c +++ b/components/bt/host/bluedroid/stack/btu/btu_init.c @@ -253,7 +253,7 @@ UINT16 BTU_BleAclPktSize(void) #if SCAN_QUEUE_CONGEST_CHECK bool BTU_check_queue_is_congest(void) { - if (osi_thread_queue_wait_size(btu_thread, 0) >= QUEUE_CONGEST_SIZE) { + if (osi_thread_queue_wait_size(btu_thread, 0) >= BT_QUEUE_CONGEST_SIZE) { return true; } diff --git a/components/bt/bluedroid/stack/btu/btu_task.c b/components/bt/host/bluedroid/stack/btu/btu_task.c similarity index 100% rename from components/bt/bluedroid/stack/btu/btu_task.c rename to components/bt/host/bluedroid/stack/btu/btu_task.c diff --git a/components/bt/bluedroid/stack/gap/gap_api.c b/components/bt/host/bluedroid/stack/gap/gap_api.c similarity index 100% rename from components/bt/bluedroid/stack/gap/gap_api.c rename to components/bt/host/bluedroid/stack/gap/gap_api.c diff --git a/components/bt/bluedroid/stack/gap/gap_ble.c b/components/bt/host/bluedroid/stack/gap/gap_ble.c similarity index 100% rename from components/bt/bluedroid/stack/gap/gap_ble.c rename to components/bt/host/bluedroid/stack/gap/gap_ble.c diff --git a/components/bt/bluedroid/stack/gap/gap_conn.c b/components/bt/host/bluedroid/stack/gap/gap_conn.c similarity index 100% rename from components/bt/bluedroid/stack/gap/gap_conn.c rename to components/bt/host/bluedroid/stack/gap/gap_conn.c diff --git a/components/bt/bluedroid/stack/gap/gap_utils.c b/components/bt/host/bluedroid/stack/gap/gap_utils.c similarity index 100% rename from components/bt/bluedroid/stack/gap/gap_utils.c rename to components/bt/host/bluedroid/stack/gap/gap_utils.c diff --git a/components/bt/bluedroid/stack/gap/include/gap_int.h b/components/bt/host/bluedroid/stack/gap/include/gap_int.h similarity index 100% rename from components/bt/bluedroid/stack/gap/include/gap_int.h rename to components/bt/host/bluedroid/stack/gap/include/gap_int.h diff --git a/components/bt/bluedroid/stack/gatt/att_protocol.c b/components/bt/host/bluedroid/stack/gatt/att_protocol.c similarity index 100% rename from components/bt/bluedroid/stack/gatt/att_protocol.c rename to components/bt/host/bluedroid/stack/gatt/att_protocol.c diff --git a/components/bt/bluedroid/stack/gatt/gatt_api.c b/components/bt/host/bluedroid/stack/gatt/gatt_api.c similarity index 100% rename from components/bt/bluedroid/stack/gatt/gatt_api.c rename to components/bt/host/bluedroid/stack/gatt/gatt_api.c diff --git a/components/bt/bluedroid/stack/gatt/gatt_attr.c b/components/bt/host/bluedroid/stack/gatt/gatt_attr.c similarity index 100% rename from components/bt/bluedroid/stack/gatt/gatt_attr.c rename to components/bt/host/bluedroid/stack/gatt/gatt_attr.c diff --git a/components/bt/bluedroid/stack/gatt/gatt_auth.c b/components/bt/host/bluedroid/stack/gatt/gatt_auth.c similarity index 100% rename from components/bt/bluedroid/stack/gatt/gatt_auth.c rename to components/bt/host/bluedroid/stack/gatt/gatt_auth.c diff --git a/components/bt/bluedroid/stack/gatt/gatt_cl.c b/components/bt/host/bluedroid/stack/gatt/gatt_cl.c similarity index 100% rename from components/bt/bluedroid/stack/gatt/gatt_cl.c rename to components/bt/host/bluedroid/stack/gatt/gatt_cl.c diff --git a/components/bt/bluedroid/stack/gatt/gatt_db.c b/components/bt/host/bluedroid/stack/gatt/gatt_db.c similarity index 100% rename from components/bt/bluedroid/stack/gatt/gatt_db.c rename to components/bt/host/bluedroid/stack/gatt/gatt_db.c diff --git a/components/bt/bluedroid/stack/gatt/gatt_main.c b/components/bt/host/bluedroid/stack/gatt/gatt_main.c similarity index 100% rename from components/bt/bluedroid/stack/gatt/gatt_main.c rename to components/bt/host/bluedroid/stack/gatt/gatt_main.c diff --git a/components/bt/bluedroid/stack/gatt/gatt_sr.c b/components/bt/host/bluedroid/stack/gatt/gatt_sr.c similarity index 100% rename from components/bt/bluedroid/stack/gatt/gatt_sr.c rename to components/bt/host/bluedroid/stack/gatt/gatt_sr.c diff --git a/components/bt/bluedroid/stack/gatt/gatt_utils.c b/components/bt/host/bluedroid/stack/gatt/gatt_utils.c similarity index 100% rename from components/bt/bluedroid/stack/gatt/gatt_utils.c rename to components/bt/host/bluedroid/stack/gatt/gatt_utils.c diff --git a/components/bt/bluedroid/stack/gatt/include/gatt_int.h b/components/bt/host/bluedroid/stack/gatt/include/gatt_int.h similarity index 100% rename from components/bt/bluedroid/stack/gatt/include/gatt_int.h rename to components/bt/host/bluedroid/stack/gatt/include/gatt_int.h diff --git a/components/bt/bluedroid/stack/hcic/hciblecmds.c b/components/bt/host/bluedroid/stack/hcic/hciblecmds.c similarity index 100% rename from components/bt/bluedroid/stack/hcic/hciblecmds.c rename to components/bt/host/bluedroid/stack/hcic/hciblecmds.c diff --git a/components/bt/bluedroid/stack/hcic/hcicmds.c b/components/bt/host/bluedroid/stack/hcic/hcicmds.c similarity index 100% rename from components/bt/bluedroid/stack/hcic/hcicmds.c rename to components/bt/host/bluedroid/stack/hcic/hcicmds.c diff --git a/components/bt/bluedroid/stack/include/stack/a2d_api.h b/components/bt/host/bluedroid/stack/include/stack/a2d_api.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/a2d_api.h rename to components/bt/host/bluedroid/stack/include/stack/a2d_api.h diff --git a/components/bt/bluedroid/stack/include/stack/a2d_sbc.h b/components/bt/host/bluedroid/stack/include/stack/a2d_sbc.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/a2d_sbc.h rename to components/bt/host/bluedroid/stack/include/stack/a2d_sbc.h diff --git a/components/bt/bluedroid/stack/include/stack/avct_api.h b/components/bt/host/bluedroid/stack/include/stack/avct_api.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/avct_api.h rename to components/bt/host/bluedroid/stack/include/stack/avct_api.h diff --git a/components/bt/bluedroid/stack/include/stack/avdt_api.h b/components/bt/host/bluedroid/stack/include/stack/avdt_api.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/avdt_api.h rename to components/bt/host/bluedroid/stack/include/stack/avdt_api.h diff --git a/components/bt/bluedroid/stack/include/stack/avdtc_api.h b/components/bt/host/bluedroid/stack/include/stack/avdtc_api.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/avdtc_api.h rename to components/bt/host/bluedroid/stack/include/stack/avdtc_api.h diff --git a/components/bt/bluedroid/stack/include/stack/avrc_api.h b/components/bt/host/bluedroid/stack/include/stack/avrc_api.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/avrc_api.h rename to components/bt/host/bluedroid/stack/include/stack/avrc_api.h diff --git a/components/bt/bluedroid/stack/include/stack/avrc_defs.h b/components/bt/host/bluedroid/stack/include/stack/avrc_defs.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/avrc_defs.h rename to components/bt/host/bluedroid/stack/include/stack/avrc_defs.h diff --git a/components/bt/bluedroid/stack/include/stack/bt_types.h b/components/bt/host/bluedroid/stack/include/stack/bt_types.h similarity index 97% rename from components/bt/bluedroid/stack/include/stack/bt_types.h rename to components/bt/host/bluedroid/stack/include/stack/bt_types.h index f8b15919d2..fb49e18b1e 100644 --- a/components/bt/bluedroid/stack/include/stack/bt_types.h +++ b/components/bt/host/bluedroid/stack/include/stack/bt_types.h @@ -21,14 +21,7 @@ #include #include - -#ifndef FALSE -# define FALSE false -#endif - -#ifndef TRUE -# define TRUE true -#endif +#include "bt_common.h" typedef uint8_t UINT8; typedef uint16_t UINT16; @@ -525,19 +518,6 @@ typedef struct { typedef UINT8 tBT_DEVICE_TYPE; /*****************************************************************************/ - -/* Define trace levels */ -#define BT_TRACE_LEVEL_NONE 0 /* No trace messages to be generated */ -#define BT_TRACE_LEVEL_ERROR 1 /* Error condition trace messages */ -#define BT_TRACE_LEVEL_WARNING 2 /* Warning condition trace messages */ -#define BT_TRACE_LEVEL_API 3 /* API traces */ -#define BT_TRACE_LEVEL_EVENT 4 /* Debug messages for events */ -#define BT_TRACE_LEVEL_DEBUG 5 /* Full debug messages */ -#define BT_TRACE_LEVEL_VERBOSE 6 /* Verbose debug messages */ - -#define MAX_TRACE_LEVEL 6 - - /* Define New Trace Type Definition */ /* TRACE_CTRL_TYPE 0x^^000000*/ #define TRACE_CTRL_MASK 0xff000000 diff --git a/components/bt/bluedroid/stack/include/stack/btm_api.h b/components/bt/host/bluedroid/stack/include/stack/btm_api.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/btm_api.h rename to components/bt/host/bluedroid/stack/include/stack/btm_api.h diff --git a/components/bt/bluedroid/stack/include/stack/btm_ble_api.h b/components/bt/host/bluedroid/stack/include/stack/btm_ble_api.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/btm_ble_api.h rename to components/bt/host/bluedroid/stack/include/stack/btm_ble_api.h diff --git a/components/bt/bluedroid/stack/include/stack/btu.h b/components/bt/host/bluedroid/stack/include/stack/btu.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/btu.h rename to components/bt/host/bluedroid/stack/include/stack/btu.h diff --git a/components/bt/bluedroid/stack/include/stack/dyn_mem.h b/components/bt/host/bluedroid/stack/include/stack/dyn_mem.h similarity index 95% rename from components/bt/bluedroid/stack/include/stack/dyn_mem.h rename to components/bt/host/bluedroid/stack/include/stack/dyn_mem.h index c2679a318b..fa1ed4982a 100644 --- a/components/bt/bluedroid/stack/include/stack/dyn_mem.h +++ b/components/bt/host/bluedroid/stack/include/stack/dyn_mem.h @@ -18,17 +18,15 @@ #ifndef DYN_MEM_H #define DYN_MEM_H -#include "common/bt_user_config.h" +#include "common/bluedroid_user_config.h" #if UC_BT_BLE_DYNAMIC_ENV_MEMORY -#define BT_BLE_DYNAMIC_ENV_MEMORY TRUE #define BTU_DYNAMIC_MEMORY TRUE #define BTM_DYNAMIC_MEMORY TRUE #define L2C_DYNAMIC_MEMORY TRUE #define GATT_DYNAMIC_MEMORY TRUE #define SMP_DYNAMIC_MEMORY TRUE #define BTA_DYNAMIC_MEMORY TRUE -#define BTC_DYNAMIC_MEMORY TRUE #define SDP_DYNAMIC_MEMORY TRUE #define GAP_DYNAMIC_MEMORY TRUE #define RFC_DYNAMIC_MEMORY TRUE @@ -57,14 +55,12 @@ #define BTC_SBC_DEC_DYNAMIC_MEMORY TRUE #else /* #if UC_BT_BLE_DYNAMIC_ENV_MEMORY */ -#define BT_BLE_DYNAMIC_ENV_MEMORY FALSE #define BTU_DYNAMIC_MEMORY FALSE #define BTM_DYNAMIC_MEMORY FALSE #define L2C_DYNAMIC_MEMORY FALSE #define GATT_DYNAMIC_MEMORY FALSE #define SMP_DYNAMIC_MEMORY FALSE #define BTA_DYNAMIC_MEMORY FALSE -#define BTC_DYNAMIC_MEMORY FALSE #define SDP_DYNAMIC_MEMORY FALSE #define GAP_DYNAMIC_MEMORY FALSE #define RFC_DYNAMIC_MEMORY FALSE @@ -94,9 +90,6 @@ #endif /* #if UC_BT_BLE_DYNAMIC_ENV_MEMORY */ -#ifndef BT_BLE_DYNAMIC_ENV_MEMORY -#define BT_BLE_DYNAMIC_ENV_MEMORY FALSE -#endif /**************************************************************************** ** Define memory usage for each CORE component (if not defined in bdroid_buildcfg.h) diff --git a/components/bt/bluedroid/stack/include/stack/gap_api.h b/components/bt/host/bluedroid/stack/include/stack/gap_api.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/gap_api.h rename to components/bt/host/bluedroid/stack/include/stack/gap_api.h diff --git a/components/bt/bluedroid/stack/include/stack/gatt_api.h b/components/bt/host/bluedroid/stack/include/stack/gatt_api.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/gatt_api.h rename to components/bt/host/bluedroid/stack/include/stack/gatt_api.h diff --git a/components/bt/bluedroid/stack/include/stack/gattdefs.h b/components/bt/host/bluedroid/stack/include/stack/gattdefs.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/gattdefs.h rename to components/bt/host/bluedroid/stack/include/stack/gattdefs.h diff --git a/components/bt/bluedroid/stack/include/stack/hcidefs.h b/components/bt/host/bluedroid/stack/include/stack/hcidefs.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/hcidefs.h rename to components/bt/host/bluedroid/stack/include/stack/hcidefs.h diff --git a/components/bt/bluedroid/stack/include/stack/hcimsgs.h b/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/hcimsgs.h rename to components/bt/host/bluedroid/stack/include/stack/hcimsgs.h diff --git a/components/bt/bluedroid/stack/include/stack/hiddefs.h b/components/bt/host/bluedroid/stack/include/stack/hiddefs.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/hiddefs.h rename to components/bt/host/bluedroid/stack/include/stack/hiddefs.h diff --git a/components/bt/bluedroid/stack/include/stack/hidh_api.h b/components/bt/host/bluedroid/stack/include/stack/hidh_api.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/hidh_api.h rename to components/bt/host/bluedroid/stack/include/stack/hidh_api.h diff --git a/components/bt/bluedroid/stack/include/stack/l2c_api.h b/components/bt/host/bluedroid/stack/include/stack/l2c_api.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/l2c_api.h rename to components/bt/host/bluedroid/stack/include/stack/l2c_api.h diff --git a/components/bt/bluedroid/stack/include/stack/l2cap_client.h b/components/bt/host/bluedroid/stack/include/stack/l2cap_client.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/l2cap_client.h rename to components/bt/host/bluedroid/stack/include/stack/l2cap_client.h diff --git a/components/bt/bluedroid/stack/include/stack/l2cdefs.h b/components/bt/host/bluedroid/stack/include/stack/l2cdefs.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/l2cdefs.h rename to components/bt/host/bluedroid/stack/include/stack/l2cdefs.h diff --git a/components/bt/bluedroid/stack/include/stack/port_api.h b/components/bt/host/bluedroid/stack/include/stack/port_api.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/port_api.h rename to components/bt/host/bluedroid/stack/include/stack/port_api.h diff --git a/components/bt/bluedroid/stack/include/stack/port_ext.h b/components/bt/host/bluedroid/stack/include/stack/port_ext.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/port_ext.h rename to components/bt/host/bluedroid/stack/include/stack/port_ext.h diff --git a/components/bt/bluedroid/stack/include/stack/profiles_api.h b/components/bt/host/bluedroid/stack/include/stack/profiles_api.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/profiles_api.h rename to components/bt/host/bluedroid/stack/include/stack/profiles_api.h diff --git a/components/bt/bluedroid/stack/include/stack/rfcdefs.h b/components/bt/host/bluedroid/stack/include/stack/rfcdefs.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/rfcdefs.h rename to components/bt/host/bluedroid/stack/include/stack/rfcdefs.h diff --git a/components/bt/bluedroid/stack/include/stack/sdp_api.h b/components/bt/host/bluedroid/stack/include/stack/sdp_api.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/sdp_api.h rename to components/bt/host/bluedroid/stack/include/stack/sdp_api.h diff --git a/components/bt/bluedroid/stack/include/stack/sdpdefs.h b/components/bt/host/bluedroid/stack/include/stack/sdpdefs.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/sdpdefs.h rename to components/bt/host/bluedroid/stack/include/stack/sdpdefs.h diff --git a/components/bt/bluedroid/stack/include/stack/smp_api.h b/components/bt/host/bluedroid/stack/include/stack/smp_api.h similarity index 100% rename from components/bt/bluedroid/stack/include/stack/smp_api.h rename to components/bt/host/bluedroid/stack/include/stack/smp_api.h diff --git a/components/bt/bluedroid/stack/l2cap/include/l2c_int.h b/components/bt/host/bluedroid/stack/l2cap/include/l2c_int.h similarity index 100% rename from components/bt/bluedroid/stack/l2cap/include/l2c_int.h rename to components/bt/host/bluedroid/stack/l2cap/include/l2c_int.h diff --git a/components/bt/bluedroid/stack/l2cap/l2c_api.c b/components/bt/host/bluedroid/stack/l2cap/l2c_api.c similarity index 100% rename from components/bt/bluedroid/stack/l2cap/l2c_api.c rename to components/bt/host/bluedroid/stack/l2cap/l2c_api.c diff --git a/components/bt/bluedroid/stack/l2cap/l2c_ble.c b/components/bt/host/bluedroid/stack/l2cap/l2c_ble.c similarity index 100% rename from components/bt/bluedroid/stack/l2cap/l2c_ble.c rename to components/bt/host/bluedroid/stack/l2cap/l2c_ble.c diff --git a/components/bt/bluedroid/stack/l2cap/l2c_csm.c b/components/bt/host/bluedroid/stack/l2cap/l2c_csm.c similarity index 100% rename from components/bt/bluedroid/stack/l2cap/l2c_csm.c rename to components/bt/host/bluedroid/stack/l2cap/l2c_csm.c diff --git a/components/bt/bluedroid/stack/l2cap/l2c_fcr.c b/components/bt/host/bluedroid/stack/l2cap/l2c_fcr.c similarity index 100% rename from components/bt/bluedroid/stack/l2cap/l2c_fcr.c rename to components/bt/host/bluedroid/stack/l2cap/l2c_fcr.c diff --git a/components/bt/bluedroid/stack/l2cap/l2c_link.c b/components/bt/host/bluedroid/stack/l2cap/l2c_link.c similarity index 100% rename from components/bt/bluedroid/stack/l2cap/l2c_link.c rename to components/bt/host/bluedroid/stack/l2cap/l2c_link.c diff --git a/components/bt/bluedroid/stack/l2cap/l2c_main.c b/components/bt/host/bluedroid/stack/l2cap/l2c_main.c similarity index 100% rename from components/bt/bluedroid/stack/l2cap/l2c_main.c rename to components/bt/host/bluedroid/stack/l2cap/l2c_main.c diff --git a/components/bt/bluedroid/stack/l2cap/l2c_ucd.c b/components/bt/host/bluedroid/stack/l2cap/l2c_ucd.c similarity index 100% rename from components/bt/bluedroid/stack/l2cap/l2c_ucd.c rename to components/bt/host/bluedroid/stack/l2cap/l2c_ucd.c diff --git a/components/bt/bluedroid/stack/l2cap/l2c_utils.c b/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c similarity index 100% rename from components/bt/bluedroid/stack/l2cap/l2c_utils.c rename to components/bt/host/bluedroid/stack/l2cap/l2c_utils.c diff --git a/components/bt/bluedroid/stack/l2cap/l2cap_client.c b/components/bt/host/bluedroid/stack/l2cap/l2cap_client.c similarity index 100% rename from components/bt/bluedroid/stack/l2cap/l2cap_client.c rename to components/bt/host/bluedroid/stack/l2cap/l2cap_client.c diff --git a/components/bt/bluedroid/stack/rfcomm/include/port_int.h b/components/bt/host/bluedroid/stack/rfcomm/include/port_int.h similarity index 100% rename from components/bt/bluedroid/stack/rfcomm/include/port_int.h rename to components/bt/host/bluedroid/stack/rfcomm/include/port_int.h diff --git a/components/bt/bluedroid/stack/rfcomm/include/rfc_int.h b/components/bt/host/bluedroid/stack/rfcomm/include/rfc_int.h similarity index 100% rename from components/bt/bluedroid/stack/rfcomm/include/rfc_int.h rename to components/bt/host/bluedroid/stack/rfcomm/include/rfc_int.h diff --git a/components/bt/bluedroid/stack/rfcomm/port_api.c b/components/bt/host/bluedroid/stack/rfcomm/port_api.c similarity index 100% rename from components/bt/bluedroid/stack/rfcomm/port_api.c rename to components/bt/host/bluedroid/stack/rfcomm/port_api.c diff --git a/components/bt/bluedroid/stack/rfcomm/port_rfc.c b/components/bt/host/bluedroid/stack/rfcomm/port_rfc.c similarity index 100% rename from components/bt/bluedroid/stack/rfcomm/port_rfc.c rename to components/bt/host/bluedroid/stack/rfcomm/port_rfc.c diff --git a/components/bt/bluedroid/stack/rfcomm/port_utils.c b/components/bt/host/bluedroid/stack/rfcomm/port_utils.c similarity index 100% rename from components/bt/bluedroid/stack/rfcomm/port_utils.c rename to components/bt/host/bluedroid/stack/rfcomm/port_utils.c diff --git a/components/bt/bluedroid/stack/rfcomm/rfc_l2cap_if.c b/components/bt/host/bluedroid/stack/rfcomm/rfc_l2cap_if.c similarity index 100% rename from components/bt/bluedroid/stack/rfcomm/rfc_l2cap_if.c rename to components/bt/host/bluedroid/stack/rfcomm/rfc_l2cap_if.c diff --git a/components/bt/bluedroid/stack/rfcomm/rfc_mx_fsm.c b/components/bt/host/bluedroid/stack/rfcomm/rfc_mx_fsm.c similarity index 100% rename from components/bt/bluedroid/stack/rfcomm/rfc_mx_fsm.c rename to components/bt/host/bluedroid/stack/rfcomm/rfc_mx_fsm.c diff --git a/components/bt/bluedroid/stack/rfcomm/rfc_port_fsm.c b/components/bt/host/bluedroid/stack/rfcomm/rfc_port_fsm.c similarity index 100% rename from components/bt/bluedroid/stack/rfcomm/rfc_port_fsm.c rename to components/bt/host/bluedroid/stack/rfcomm/rfc_port_fsm.c diff --git a/components/bt/bluedroid/stack/rfcomm/rfc_port_if.c b/components/bt/host/bluedroid/stack/rfcomm/rfc_port_if.c similarity index 100% rename from components/bt/bluedroid/stack/rfcomm/rfc_port_if.c rename to components/bt/host/bluedroid/stack/rfcomm/rfc_port_if.c diff --git a/components/bt/bluedroid/stack/rfcomm/rfc_ts_frames.c b/components/bt/host/bluedroid/stack/rfcomm/rfc_ts_frames.c similarity index 100% rename from components/bt/bluedroid/stack/rfcomm/rfc_ts_frames.c rename to components/bt/host/bluedroid/stack/rfcomm/rfc_ts_frames.c diff --git a/components/bt/bluedroid/stack/rfcomm/rfc_utils.c b/components/bt/host/bluedroid/stack/rfcomm/rfc_utils.c similarity index 100% rename from components/bt/bluedroid/stack/rfcomm/rfc_utils.c rename to components/bt/host/bluedroid/stack/rfcomm/rfc_utils.c diff --git a/components/bt/bluedroid/stack/sdp/include/sdpint.h b/components/bt/host/bluedroid/stack/sdp/include/sdpint.h similarity index 100% rename from components/bt/bluedroid/stack/sdp/include/sdpint.h rename to components/bt/host/bluedroid/stack/sdp/include/sdpint.h diff --git a/components/bt/bluedroid/stack/sdp/sdp_api.c b/components/bt/host/bluedroid/stack/sdp/sdp_api.c similarity index 100% rename from components/bt/bluedroid/stack/sdp/sdp_api.c rename to components/bt/host/bluedroid/stack/sdp/sdp_api.c diff --git a/components/bt/bluedroid/stack/sdp/sdp_db.c b/components/bt/host/bluedroid/stack/sdp/sdp_db.c similarity index 100% rename from components/bt/bluedroid/stack/sdp/sdp_db.c rename to components/bt/host/bluedroid/stack/sdp/sdp_db.c diff --git a/components/bt/bluedroid/stack/sdp/sdp_discovery.c b/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c similarity index 100% rename from components/bt/bluedroid/stack/sdp/sdp_discovery.c rename to components/bt/host/bluedroid/stack/sdp/sdp_discovery.c diff --git a/components/bt/bluedroid/stack/sdp/sdp_main.c b/components/bt/host/bluedroid/stack/sdp/sdp_main.c similarity index 100% rename from components/bt/bluedroid/stack/sdp/sdp_main.c rename to components/bt/host/bluedroid/stack/sdp/sdp_main.c diff --git a/components/bt/bluedroid/stack/sdp/sdp_server.c b/components/bt/host/bluedroid/stack/sdp/sdp_server.c similarity index 100% rename from components/bt/bluedroid/stack/sdp/sdp_server.c rename to components/bt/host/bluedroid/stack/sdp/sdp_server.c diff --git a/components/bt/bluedroid/stack/sdp/sdp_utils.c b/components/bt/host/bluedroid/stack/sdp/sdp_utils.c similarity index 100% rename from components/bt/bluedroid/stack/sdp/sdp_utils.c rename to components/bt/host/bluedroid/stack/sdp/sdp_utils.c diff --git a/components/bt/bluedroid/stack/smp/aes.c b/components/bt/host/bluedroid/stack/smp/aes.c similarity index 100% rename from components/bt/bluedroid/stack/smp/aes.c rename to components/bt/host/bluedroid/stack/smp/aes.c diff --git a/components/bt/bluedroid/stack/smp/include/aes.h b/components/bt/host/bluedroid/stack/smp/include/aes.h similarity index 100% rename from components/bt/bluedroid/stack/smp/include/aes.h rename to components/bt/host/bluedroid/stack/smp/include/aes.h diff --git a/components/bt/bluedroid/stack/smp/include/p_256_ecc_pp.h b/components/bt/host/bluedroid/stack/smp/include/p_256_ecc_pp.h similarity index 100% rename from components/bt/bluedroid/stack/smp/include/p_256_ecc_pp.h rename to components/bt/host/bluedroid/stack/smp/include/p_256_ecc_pp.h diff --git a/components/bt/bluedroid/stack/smp/include/p_256_multprecision.h b/components/bt/host/bluedroid/stack/smp/include/p_256_multprecision.h similarity index 100% rename from components/bt/bluedroid/stack/smp/include/p_256_multprecision.h rename to components/bt/host/bluedroid/stack/smp/include/p_256_multprecision.h diff --git a/components/bt/bluedroid/stack/smp/include/smp_int.h b/components/bt/host/bluedroid/stack/smp/include/smp_int.h similarity index 100% rename from components/bt/bluedroid/stack/smp/include/smp_int.h rename to components/bt/host/bluedroid/stack/smp/include/smp_int.h diff --git a/components/bt/bluedroid/stack/smp/p_256_curvepara.c b/components/bt/host/bluedroid/stack/smp/p_256_curvepara.c similarity index 100% rename from components/bt/bluedroid/stack/smp/p_256_curvepara.c rename to components/bt/host/bluedroid/stack/smp/p_256_curvepara.c diff --git a/components/bt/bluedroid/stack/smp/p_256_ecc_pp.c b/components/bt/host/bluedroid/stack/smp/p_256_ecc_pp.c similarity index 100% rename from components/bt/bluedroid/stack/smp/p_256_ecc_pp.c rename to components/bt/host/bluedroid/stack/smp/p_256_ecc_pp.c diff --git a/components/bt/bluedroid/stack/smp/p_256_multprecision.c b/components/bt/host/bluedroid/stack/smp/p_256_multprecision.c similarity index 100% rename from components/bt/bluedroid/stack/smp/p_256_multprecision.c rename to components/bt/host/bluedroid/stack/smp/p_256_multprecision.c diff --git a/components/bt/bluedroid/stack/smp/smp_act.c b/components/bt/host/bluedroid/stack/smp/smp_act.c similarity index 100% rename from components/bt/bluedroid/stack/smp/smp_act.c rename to components/bt/host/bluedroid/stack/smp/smp_act.c diff --git a/components/bt/bluedroid/stack/smp/smp_api.c b/components/bt/host/bluedroid/stack/smp/smp_api.c similarity index 100% rename from components/bt/bluedroid/stack/smp/smp_api.c rename to components/bt/host/bluedroid/stack/smp/smp_api.c diff --git a/components/bt/bluedroid/stack/smp/smp_br_main.c b/components/bt/host/bluedroid/stack/smp/smp_br_main.c similarity index 100% rename from components/bt/bluedroid/stack/smp/smp_br_main.c rename to components/bt/host/bluedroid/stack/smp/smp_br_main.c diff --git a/components/bt/bluedroid/stack/smp/smp_cmac.c b/components/bt/host/bluedroid/stack/smp/smp_cmac.c similarity index 100% rename from components/bt/bluedroid/stack/smp/smp_cmac.c rename to components/bt/host/bluedroid/stack/smp/smp_cmac.c diff --git a/components/bt/bluedroid/stack/smp/smp_keys.c b/components/bt/host/bluedroid/stack/smp/smp_keys.c similarity index 100% rename from components/bt/bluedroid/stack/smp/smp_keys.c rename to components/bt/host/bluedroid/stack/smp/smp_keys.c diff --git a/components/bt/bluedroid/stack/smp/smp_l2c.c b/components/bt/host/bluedroid/stack/smp/smp_l2c.c similarity index 100% rename from components/bt/bluedroid/stack/smp/smp_l2c.c rename to components/bt/host/bluedroid/stack/smp/smp_l2c.c diff --git a/components/bt/bluedroid/stack/smp/smp_main.c b/components/bt/host/bluedroid/stack/smp/smp_main.c similarity index 100% rename from components/bt/bluedroid/stack/smp/smp_main.c rename to components/bt/host/bluedroid/stack/smp/smp_main.c diff --git a/components/bt/bluedroid/stack/smp/smp_utils.c b/components/bt/host/bluedroid/stack/smp/smp_utils.c similarity index 100% rename from components/bt/bluedroid/stack/smp/smp_utils.c rename to components/bt/host/bluedroid/stack/smp/smp_utils.c diff --git a/components/nimble/Kconfig.in b/components/bt/host/nimble/Kconfig.in similarity index 100% rename from components/nimble/Kconfig.in rename to components/bt/host/nimble/Kconfig.in diff --git a/components/nimble/esp-hci/include/esp_nimble_hci.h b/components/bt/host/nimble/esp-hci/include/esp_nimble_hci.h similarity index 100% rename from components/nimble/esp-hci/include/esp_nimble_hci.h rename to components/bt/host/nimble/esp-hci/include/esp_nimble_hci.h diff --git a/components/nimble/esp-hci/src/esp_nimble_hci.c b/components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c similarity index 100% rename from components/nimble/esp-hci/src/esp_nimble_hci.c rename to components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c diff --git a/components/nimble/nimble b/components/bt/host/nimble/nimble similarity index 100% rename from components/nimble/nimble rename to components/bt/host/nimble/nimble diff --git a/components/nimble/port/include/console/console.h b/components/bt/host/nimble/port/include/console/console.h similarity index 100% rename from components/nimble/port/include/console/console.h rename to components/bt/host/nimble/port/include/console/console.h diff --git a/components/nimble/port/include/esp_nimble_cfg.h b/components/bt/host/nimble/port/include/esp_nimble_cfg.h similarity index 100% rename from components/nimble/port/include/esp_nimble_cfg.h rename to components/bt/host/nimble/port/include/esp_nimble_cfg.h diff --git a/components/bt/lib b/components/bt/lib deleted file mode 160000 index 471f03c2ca..0000000000 --- a/components/bt/lib +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 471f03c2ca55225a600d3783dd277a910bfe80ed diff --git a/components/nimble/CMakeLists.txt b/components/nimble/CMakeLists.txt deleted file mode 100644 index 34c5944e58..0000000000 --- a/components/nimble/CMakeLists.txt +++ /dev/null @@ -1,142 +0,0 @@ -if(CONFIG_BT_NIMBLE_ENABLED) - - set(COMPONENT_ADD_INCLUDEDIRS - nimble/porting/nimble/include - port/include - nimble/nimble/include - nimble/nimble/host/include - nimble/nimble/host/services/ans/include - nimble/nimble/host/services/bas/include - nimble/nimble/host/services/gap/include - nimble/nimble/host/services/gatt/include - nimble/nimble/host/services/ias/include - nimble/nimble/host/services/lls/include - nimble/nimble/host/services/tps/include - nimble/nimble/host/util/include - nimble/nimble/host/store/ram/include - nimble/nimble/host/store/config/include - nimble/porting/npl/freertos/include - nimble/ext/tinycrypt/include - esp-hci/include) - - - - set(COMPONENT_SRCS "./nimble/ext/tinycrypt/src/utils.c" - "./nimble/ext/tinycrypt/src/sha256.c" - "./nimble/ext/tinycrypt/src/ecc.c" - "./nimble/ext/tinycrypt/src/ctr_prng.c" - "./nimble/ext/tinycrypt/src/ctr_mode.c" - "./nimble/ext/tinycrypt/src/aes_decrypt.c" - "./nimble/ext/tinycrypt/src/aes_encrypt.c" - "./nimble/ext/tinycrypt/src/ccm_mode.c" - "./nimble/ext/tinycrypt/src/ecc_dsa.c" - "./nimble/ext/tinycrypt/src/cmac_mode.c" - "./nimble/ext/tinycrypt/src/ecc_dh.c" - "./nimble/ext/tinycrypt/src/hmac_prng.c" - "./nimble/ext/tinycrypt/src/ecc_platform_specific.c" - "./nimble/ext/tinycrypt/src/hmac.c" - "./nimble/ext/tinycrypt/src/cbc_mode.c" - "./nimble/nimble/host/util/src/addr.c" - "./nimble/nimble/host/services/gatt/src/ble_svc_gatt.c" - "./nimble/nimble/host/services/tps/src/ble_svc_tps.c" - "./nimble/nimble/host/services/ias/src/ble_svc_ias.c" - "./nimble/nimble/host/services/ans/src/ble_svc_ans.c" - "./nimble/nimble/host/services/gap/src/ble_svc_gap.c" - "./nimble/nimble/host/services/bas/src/ble_svc_bas.c" - "./nimble/nimble/host/services/lls/src/ble_svc_lls.c" - "./nimble/nimble/host/src/ble_hs_conn.c" - "./nimble/nimble/host/src/ble_store_util.c" - "./nimble/nimble/host/src/ble_sm.c" - "./nimble/nimble/host/src/ble_hs_shutdown.c" - "./nimble/nimble/host/src/ble_l2cap_sig_cmd.c" - "./nimble/nimble/host/src/ble_hs_hci_cmd.c" - "./nimble/nimble/host/src/ble_hs_id.c" - "./nimble/nimble/host/src/ble_att_svr.c" - "./nimble/nimble/host/src/ble_gatts_lcl.c" - "./nimble/nimble/host/src/ble_ibeacon.c" - "./nimble/nimble/host/src/ble_hs_atomic.c" - "./nimble/nimble/host/src/ble_sm_alg.c" - "./nimble/nimble/host/src/ble_hs_stop.c" - "./nimble/nimble/host/src/ble_hs.c" - "./nimble/nimble/host/src/ble_hs_hci_evt.c" - "./nimble/nimble/host/src/ble_hs_dbg.c" - "./nimble/nimble/host/src/ble_hs_mqueue.c" - "./nimble/nimble/host/src/ble_att.c" - "./nimble/nimble/host/src/ble_gattc.c" - "./nimble/nimble/host/src/ble_store.c" - "./nimble/nimble/host/src/ble_sm_lgcy.c" - "./nimble/nimble/host/src/ble_hs_cfg.c" - "./nimble/nimble/host/src/ble_monitor.c" - "./nimble/nimble/host/src/ble_att_clt.c" - "./nimble/nimble/host/src/ble_l2cap_coc.c" - "./nimble/nimble/host/src/ble_hs_mbuf.c" - "./nimble/nimble/host/src/ble_att_cmd.c" - "./nimble/nimble/host/src/ble_hs_log.c" - "./nimble/nimble/host/src/ble_eddystone.c" - "./nimble/nimble/host/src/ble_hs_startup.c" - "./nimble/nimble/host/src/ble_l2cap_sig.c" - "./nimble/nimble/host/src/ble_gap.c" - "./nimble/nimble/host/src/ble_sm_cmd.c" - "./nimble/nimble/host/src/ble_uuid.c" - "./nimble/nimble/host/src/ble_hs_pvcy.c" - "./nimble/nimble/host/src/ble_hs_flow.c" - "./nimble/nimble/host/src/ble_l2cap.c" - "./nimble/nimble/host/src/ble_sm_sc.c" - "./nimble/nimble/host/src/ble_hs_misc.c" - "./nimble/nimble/host/src/ble_gatts.c" - "./nimble/nimble/host/src/ble_hs_adv.c" - "./nimble/nimble/host/src/ble_hs_hci.c" - "./nimble/nimble/host/src/ble_hs_hci_util.c" - "./nimble/nimble/host/store/ram/src/ble_store_ram.c" - "./nimble/nimble/host/store/config/src/ble_store_config.c" - "./nimble/nimble/host/store/config/src/ble_store_nvs.c" - "./nimble/nimble/src/ble_util.c" - "./nimble/porting/npl/freertos/src/nimble_port_freertos.c" - "./nimble/porting/npl/freertos/src/npl_os_freertos.c" - "./nimble/porting/nimble/src/endian.c" - "./nimble/porting/nimble/src/os_cputime_pwr2.c" - "./nimble/porting/nimble/src/hal_timer.c" - "./nimble/porting/nimble/src/os_mempool.c" - "./nimble/porting/nimble/src/os_msys_init.c" - "./nimble/porting/nimble/src/nimble_port.c" - "./nimble/porting/nimble/src/mem.c" - "./nimble/porting/nimble/src/os_mbuf.c" - "./nimble/porting/nimble/src/os_cputime.c" - "./esp-hci/src/esp_nimble_hci.c") - - if(CONFIG_BT_NIMBLE_MESH) - - list(APPEND COMPONENT_ADD_INCLUDEDIRS - nimble/nimble/host/mesh/include) - - list(APPEND COMPONENT_SRCS - "./nimble/nimble/host/mesh/src/shell.c" - "./nimble/nimble/host/mesh/src/friend.c" - "./nimble/nimble/host/mesh/src/crypto.c" - "./nimble/nimble/host/mesh/src/settings.c" - "./nimble/nimble/host/mesh/src/adv.c" - "./nimble/nimble/host/mesh/src/model_srv.c" - "./nimble/nimble/host/mesh/src/beacon.c" - "./nimble/nimble/host/mesh/src/glue.c" - "./nimble/nimble/host/mesh/src/model_cli.c" - "./nimble/nimble/host/mesh/src/transport.c" - "./nimble/nimble/host/mesh/src/prov.c" - "./nimble/nimble/host/mesh/src/mesh.c" - "./nimble/nimble/host/mesh/src/access.c" - "./nimble/nimble/host/mesh/src/cfg_srv.c" - "./nimble/nimble/host/mesh/src/cfg_cli.c" - "./nimble/nimble/host/mesh/src/light_model.c" - "./nimble/nimble/host/mesh/src/health_cli.c" - "./nimble/nimble/host/mesh/src/lpn.c" - "./nimble/nimble/host/mesh/src/proxy.c" - "./nimble/nimble/host/mesh/src/health_srv.c" - "./nimble/nimble/host/mesh/src/testing.c" - "./nimble/nimble/host/mesh/src/net.c") - - endif() -endif() - -# requirements can't depend on config -set(COMPONENT_PRIV_REQUIRES bt nvs_flash) - -register_component() diff --git a/components/nimble/component.mk b/components/nimble/component.mk deleted file mode 100644 index 148e13d673..0000000000 --- a/components/nimble/component.mk +++ /dev/null @@ -1,47 +0,0 @@ -# -# Component Makefile -# - -ifeq ($(CONFIG_BT_NIMBLE_ENABLED),y) -COMPONENT_ADD_INCLUDEDIRS := nimble/nimble/include \ - nimble/nimble/host/include \ - nimble/porting/nimble/include \ - nimble/porting/npl/freertos/include \ - nimble/nimble/host/services/ans/include \ - nimble/nimble/host/services/bas/include \ - nimble/nimble/host/services/gap/include \ - nimble/nimble/host/services/gatt/include \ - nimble/nimble/host/services/ias/include \ - nimble/nimble/host/services/lls/include \ - nimble/nimble/host/services/tps/include \ - nimble/nimble/host/util/include \ - nimble/nimble/host/store/ram/include \ - nimble/nimble/host/store/config/include \ - nimble/nimble/host/mesh/include \ - nimble/ext/tinycrypt/include \ - esp-hci/include \ - port/include \ - - -COMPONENT_SRCDIRS := nimble/nimble/host/src \ - nimble/porting/nimble/src \ - nimble/porting/npl/freertos/src \ - nimble/ext/tinycrypt/src \ - nimble/nimble/host/services/ans/src \ - nimble/nimble/host/services/bas/src \ - nimble/nimble/host/services/gap/src \ - nimble/nimble/host/services/gatt/src \ - nimble/nimble/host/services/ias/src \ - nimble/nimble/host/services/lls/src \ - nimble/nimble/host/services/tps/src \ - nimble/nimble/host/util/src \ - nimble/nimble/host/store/ram/src \ - nimble/nimble/host/store/config/src \ - esp-hci/src \ - -COMPONENT_OBJEXCLUDE := nimble/nimble/host/store/config/src/ble_store_config_conf.o - -ifeq ($(CONFIG_BT_NIMBLE_MESH),y) -COMPONENT_SRCDIRS += nimble/nimble/host/mesh/src -endif -endif diff --git a/docs/Doxyfile b/docs/Doxyfile index 5ed61cce0a..ee91aab2b3 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -39,26 +39,26 @@ INPUT = \ ../../components/bt/include/esp_bt.h \ ## Bluetooth COMMON ## Issue with __attribute__ - ../../components/bt/bluedroid/api/include/api/esp_bt_defs.h \ - ../../components/bt/bluedroid/api/include/api/esp_bt_main.h \ - ../../components/bt/bluedroid/api/include/api/esp_bt_device.h \ + ../../components/bt/host/bluedroid/api/include/api/esp_bt_defs.h \ + ../../components/bt/host/bluedroid/api/include/api/esp_bt_main.h \ + ../../components/bt/host/bluedroid/api/include/api/esp_bt_device.h \ ## Bluetooth LE - ../../components/bt/bluedroid/api/include/api/esp_gap_ble_api.h \ + ../../components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h \ ## Issue with __attribute__ - ../../components/bt/bluedroid/api/include/api/esp_gatt_defs.h \ - ../../components/bt/bluedroid/api/include/api/esp_gatts_api.h \ - ../../components/bt/bluedroid/api/include/api/esp_gattc_api.h \ - ../../components/bt/bluedroid/api/include/api/esp_blufi_api.h \ + ../../components/bt/host/bluedroid/api/include/api/esp_gatt_defs.h \ + ../../components/bt/host/bluedroid/api/include/api/esp_gatts_api.h \ + ../../components/bt/host/bluedroid/api/include/api/esp_gattc_api.h \ + ../../components/bt/host/bluedroid/api/include/api/esp_blufi_api.h \ ## Bluetooth Classic - ../../components/bt/bluedroid/api/include/api/esp_gap_bt_api.h \ + ../../components/bt/host/bluedroid/api/include/api/esp_gap_bt_api.h \ ## Issue with __attribute__ - ../../components/bt/bluedroid/api/include/api/esp_a2dp_api.h \ - ../../components/bt/bluedroid/api/include/api/esp_avrc_api.h \ - ../../components/bt/bluedroid/api/include/api/esp_spp_api.h \ - ../../components/bt/bluedroid/api/include/api/esp_hf_defs.h \ - ../../components/bt/bluedroid/api/include/api/esp_hf_client_api.h \ + ../../components/bt/host/bluedroid/api/include/api/esp_a2dp_api.h \ + ../../components/bt/host/bluedroid/api/include/api/esp_avrc_api.h \ + ../../components/bt/host/bluedroid/api/include/api/esp_spp_api.h \ + ../../components/bt/host/bluedroid/api/include/api/esp_hf_defs.h \ + ../../components/bt/host/bluedroid/api/include/api/esp_hf_client_api.h \ ## NimBLE related Bluetooth APIs - ../../components/nimble/esp-hci/include/esp_nimble_hci.h \ + ../../components/bt/host/nimble/esp-hci/include/esp_nimble_hci.h \ ## ## Ethernet - API Reference ## diff --git a/examples/bluetooth/nimble/blemesh/CMakeLists.txt b/examples/bluetooth/nimble/blemesh/CMakeLists.txt index d1341c6ea7..f022ba3d27 100644 --- a/examples/bluetooth/nimble/blemesh/CMakeLists.txt +++ b/examples/bluetooth/nimble/blemesh/CMakeLists.txt @@ -3,4 +3,4 @@ cmake_minimum_required(VERSION 3.5) include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(ble_mesh) +project(blemesh) diff --git a/examples/bluetooth/nimble/blemesh/Makefile b/examples/bluetooth/nimble/blemesh/Makefile index bba3cb6152..720983f4d2 100644 --- a/examples/bluetooth/nimble/blemesh/Makefile +++ b/examples/bluetooth/nimble/blemesh/Makefile @@ -3,6 +3,6 @@ # project subdirectory. # -PROJECT_NAME := ble_mesh +PROJECT_NAME := blemesh include $(IDF_PATH)/make/project.mk From bd699985169ecf44cd957e3832077c79b180760e Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 28 Jun 2019 13:35:55 +1000 Subject: [PATCH 188/486] mconf-idf: Use same 'simple expand' logic, same as kconfig-frontends Previously, wordexp() was used. However for providing Windows builds of mconf-idf we can't use wordexp() so we use this simplified environment variable expansion code instead. The reasoning here is to make the behaviour consistent across Windows (CMake vs GNU Make), Linux & macOS mconf. --- tools/kconfig/Makefile | 12 +++--- tools/kconfig/expand_env.c | 88 ++++++++++++++++++++++++++++++++++++++ tools/kconfig/expand_env.h | 13 ++++++ tools/kconfig/zconf.l | 34 ++++++++++----- 4 files changed, 131 insertions(+), 16 deletions(-) create mode 100644 tools/kconfig/expand_env.c create mode 100644 tools/kconfig/expand_env.h diff --git a/tools/kconfig/Makefile b/tools/kconfig/Makefile index 106ffb6b40..c9488d8cdf 100644 --- a/tools/kconfig/Makefile +++ b/tools/kconfig/Makefile @@ -192,13 +192,13 @@ lxdialog/%.o: $(SRCDIR)/lxdialog/%.c lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o -conf-objs := conf.o zconf.tab.o -mconf-objs := mconf.o zconf.tab.o $(lxdialog) -nconf-objs := nconf.o zconf.tab.o nconf.gui.o -kxgettext-objs := kxgettext.o zconf.tab.o +conf-objs := conf.o zconf.tab.o expand_env.o +mconf-objs := mconf.o zconf.tab.o $(lxdialog) expand_env.o +nconf-objs := nconf.o zconf.tab.o nconf.gui.o expand_env.o +kxgettext-objs := kxgettext.o zconf.tab.o expand_env.o qconf-cxxobjs := qconf.o -qconf-objs := zconf.tab.o -gconf-objs := gconf.o zconf.tab.o +qconf-objs := zconf.tab.o expand_env.o +gconf-objs := gconf.o zconf.tab.o expand_env.o hostprogs-y := conf-idf nconf mconf-idf kxgettext qconf gconf diff --git a/tools/kconfig/expand_env.c b/tools/kconfig/expand_env.c new file mode 100644 index 0000000000..185280e009 --- /dev/null +++ b/tools/kconfig/expand_env.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include +#include + +#include "expand_env.h" + +static bool allowed_env_var_name(char c) +{ + return c != '\0' && + !isblank(c) && + !iscntrl(c) && + c != '/' && + c != '\\' && + c != '=' && + c != '$'; +} + +#define MAX_LEN (128 * 1024) /* Longest a result can expand to */ + +/* Very basic expansion that looks for variable references like $NAME and expands them + * + */ +char *expand_environment(const char *input, const char *src_name, int src_line_no) +{ + char *result = malloc(MAX_LEN); + + char *out = result; + const char *in = input; + + while (*in != '\0') { + // check for buffer overflow + if (out >= result + MAX_LEN - 1) { + goto too_long; + } + + if (*in != '$') { + // not part of an environment variable name, copy directly + *out++ = *in++; + continue; + } + + // *in points to start of an environment variable reference + in++; + const char *env_start = in; + while (allowed_env_var_name(*in)) { // scan to the end of the name + in++; + } + size_t env_len = in - env_start; + + // make a buffer to hold the environment variable name + // + // strndup is not available on mingw32, apparently. + char *env_name = calloc(1, env_len + 1); + assert(env_name != NULL); + strncpy(env_name, env_start, env_len); + + const char *value = getenv(env_name); + if (value == NULL || strlen(value) == 0) { + printf("%s:%d: undefined environment variable \"%s\"\n", + src_name, src_line_no, env_name); + exit(1); + } + free(env_name); + if (out + strlen(value) >= result + MAX_LEN - 1) { + goto too_long; + } + strcpy(out, value); // append the value to the result (range checked in previous statement) + out += strlen(value); + } + + *out = '\0'; // null terminate the result string + + return result; + +too_long: + printf("%s:%d: Expansion is longer than %d bytes\n", + src_name, src_line_no, MAX_LEN); + free(result); + exit(1); +} + +void free_expanded(char *expanded) +{ + free(expanded); +} diff --git a/tools/kconfig/expand_env.h b/tools/kconfig/expand_env.h new file mode 100644 index 0000000000..4404523afd --- /dev/null +++ b/tools/kconfig/expand_env.h @@ -0,0 +1,13 @@ +#pragma once + +/* Expand any $ENV type environment variables in 'input', + return a newly allocated buffer with the result. + + Buffer should be freed after use. + + This is very basic expansion, doesn't do escaping or anything else. +*/ +char *expand_environment(const char *input, const char *src_name, int src_line_no); + +/* Free a buffer allocated by expand_environment */ +void free_expanded(char *expanded); diff --git a/tools/kconfig/zconf.l b/tools/kconfig/zconf.l index fa0da6b700..b8cc8939a5 100644 --- a/tools/kconfig/zconf.l +++ b/tools/kconfig/zconf.l @@ -13,9 +13,9 @@ #include #include #include -#include #include "lkc.h" +#include "expand_env.h" #define START_STRSIZE 16 @@ -348,19 +348,33 @@ void zconf_nextfile(const char *name) current_file = file; } -void zconf_nextfiles(const char *wildcard) +void zconf_nextfiles(const char *expression) { - wordexp_t p; - char **w; - int i; + /* Expand environment variables in 'expression' */ + char* str = expand_environment(expression, zconf_curname(), zconf_lineno()); - wordexp(wildcard, &p, 0); - w = p.we_wordv; + /* zconf_nextfile() processes files in LIFO order, so to keep the + files in the order provided we need to process the list backwards + */ + if (str != NULL && strlen(str)) { + char* pos = str + strlen(str); // start at null terminator - for (i = p.we_wordc - 1; i >= 0; i--) - zconf_nextfile(w[i]); + while (pos != str) { + pos--; + if(*pos == ' ') { + *pos = '\0'; // split buffer into multiple c-strings + if (strlen(pos + 1)) { + zconf_nextfile(pos + 1); + } + } + } - wordfree(&p); + if (strlen(str)) { // re-check as first character may have been a space + zconf_nextfile(str); + } + } + + free_expanded(str); } static void zconf_endfile(void) From c5150d16b2ab47030ce1c5e76c9d09247e740663 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Fri, 14 Jun 2019 14:10:48 +0800 Subject: [PATCH 189/486] ringbuffer: seperate acquire from send --- .../esp_ringbuf/include/freertos/ringbuf.h | 8 +- components/esp_ringbuf/ringbuf.c | 208 ++++++++++++------ components/esp_ringbuf/test/test_ringbuf.c | 12 +- 3 files changed, 149 insertions(+), 79 deletions(-) diff --git a/components/esp_ringbuf/include/freertos/ringbuf.h b/components/esp_ringbuf/include/freertos/ringbuf.h index fd3407e4a4..87c1f08f31 100644 --- a/components/esp_ringbuf/include/freertos/ringbuf.h +++ b/components/esp_ringbuf/include/freertos/ringbuf.h @@ -1,9 +1,9 @@ -// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2019 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 @@ -73,7 +73,7 @@ typedef struct xSTATIC_RINGBUFFER { size_t xDummy1[2]; UBaseType_t uxDummy2; BaseType_t xDummy3; - void *pvDummy4[10]; + void *pvDummy4[11]; StaticSemaphore_t xDummy5[2]; portMUX_TYPE muxDummy; /** @endcond */ @@ -453,12 +453,14 @@ BaseType_t xRingbufferRemoveFromQueueSetRead(RingbufHandle_t xRingbuffer, QueueS * @param[out] uxFree Pointer use to store free pointer position * @param[out] uxRead Pointer use to store read pointer position * @param[out] uxWrite Pointer use to store write pointer position + * @param[out] uxAcquire Pointer use to store acquire pointer position * @param[out] uxItemsWaiting Pointer use to store number of items (bytes for byte buffer) waiting to be retrieved */ void vRingbufferGetInfo(RingbufHandle_t xRingbuffer, UBaseType_t *uxFree, UBaseType_t *uxRead, UBaseType_t *uxWrite, + UBaseType_t *uxAcquire, UBaseType_t *uxItemsWaiting); /** diff --git a/components/esp_ringbuf/ringbuf.c b/components/esp_ringbuf/ringbuf.c index b3b43b0aae..63d08ea11d 100644 --- a/components/esp_ringbuf/ringbuf.c +++ b/components/esp_ringbuf/ringbuf.c @@ -1,9 +1,9 @@ -// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2019 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 @@ -33,6 +33,7 @@ #define rbITEM_FREE_FLAG ( ( UBaseType_t ) 1 ) //Item has been retrieved and returned by application, free to overwrite #define rbITEM_DUMMY_DATA_FLAG ( ( UBaseType_t ) 2 ) //Data from here to end of the ring buffer is dummy data. Restart reading at start of head of the buffer #define rbITEM_SPLIT_FLAG ( ( UBaseType_t ) 4 ) //Valid for RINGBUF_TYPE_ALLOWSPLIT, indicating that rest of the data is wrapped around +#define rbITEM_WRITTEN_FLAG ( ( UBaseType_t ) 8 ) //Item has been written to by the application, thus it is free to be read //Static allocation related #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) @@ -69,6 +70,7 @@ typedef struct RingbufferDefinition { ReturnItemFunction_t vReturnItem; //Function to return item to ring buffer GetCurMaxSizeFunction_t xGetCurMaxSize; //Function to get current free size + uint8_t *pucAcquire; //Acquire Pointer. Points to where the next item should be acquired. uint8_t *pucWrite; //Write Pointer. Points to where the next item should be written uint8_t *pucRead; //Read Pointer. Points to where the next item should be read from uint8_t *pucFree; //Free Pointer. Points to the last item that has yet to be returned to the ring buffer @@ -212,6 +214,7 @@ static void prvInitializeNewRingbuffer(size_t xBufferSize, pxNewRingbuffer->pucFree = pucRingbufferStorage; pxNewRingbuffer->pucRead = pucRingbufferStorage; pxNewRingbuffer->pucWrite = pucRingbufferStorage; + pxNewRingbuffer->pucAcquire = pucRingbufferStorage; pxNewRingbuffer->xItemsWaiting = 0; pxNewRingbuffer->uxRingbufferFlags = 0; @@ -222,7 +225,7 @@ static void prvInitializeNewRingbuffer(size_t xBufferSize, pxNewRingbuffer->pvGetItem = prvGetItemDefault; pxNewRingbuffer->vReturnItem = prvReturnItemDefault; /* - * Worst case scenario is when the read/write/free pointers are all + * Worst case scenario is when the read/write/acquire/free pointers are all * pointing to the halfway point of the buffer. */ pxNewRingbuffer->xMaxItemSize = rbALIGN_SIZE(pxNewRingbuffer->xSize / 2) - rbHEADER_SIZE; @@ -256,7 +259,7 @@ static size_t prvGetFreeSize(Ringbuffer_t *pxRingbuffer) if (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG) { xReturn = 0; } else { - BaseType_t xFreeSize = pxRingbuffer->pucFree - pxRingbuffer->pucWrite; + BaseType_t xFreeSize = pxRingbuffer->pucFree - pxRingbuffer->pucAcquire; //Check if xFreeSize has underflowed if (xFreeSize <= 0) { xFreeSize += pxRingbuffer->xSize; @@ -270,26 +273,26 @@ static size_t prvGetFreeSize(Ringbuffer_t *pxRingbuffer) static BaseType_t prvCheckItemFitsDefault( Ringbuffer_t *pxRingbuffer, size_t xItemSize) { //Check arguments and buffer state - configASSERT(rbCHECK_ALIGNED(pxRingbuffer->pucWrite)); //pucWrite is always aligned in no-split ring buffers - configASSERT(pxRingbuffer->pucWrite >= pxRingbuffer->pucHead && pxRingbuffer->pucWrite < pxRingbuffer->pucTail); //Check write pointer is within bounds + configASSERT(rbCHECK_ALIGNED(pxRingbuffer->pucAcquire)); //pucAcquire is always aligned in no-split/allow-split ring buffers + configASSERT(pxRingbuffer->pucAcquire >= pxRingbuffer->pucHead && pxRingbuffer->pucAcquire < pxRingbuffer->pucTail); //Check write pointer is within bounds size_t xTotalItemSize = rbALIGN_SIZE(xItemSize) + rbHEADER_SIZE; //Rounded up aligned item size with header - if (pxRingbuffer->pucWrite == pxRingbuffer->pucFree) { + if (pxRingbuffer->pucAcquire == pxRingbuffer->pucFree) { //Buffer is either complete empty or completely full return (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG) ? pdFALSE : pdTRUE; } - if (pxRingbuffer->pucFree > pxRingbuffer->pucWrite) { + if (pxRingbuffer->pucFree > pxRingbuffer->pucAcquire) { //Free space does not wrap around - return (xTotalItemSize <= pxRingbuffer->pucFree - pxRingbuffer->pucWrite) ? pdTRUE : pdFALSE; + return (xTotalItemSize <= pxRingbuffer->pucFree - pxRingbuffer->pucAcquire) ? pdTRUE : pdFALSE; } //Free space wraps around - if (xTotalItemSize <= pxRingbuffer->pucTail - pxRingbuffer->pucWrite) { + if (xTotalItemSize <= pxRingbuffer->pucTail - pxRingbuffer->pucAcquire) { return pdTRUE; //Item fits without wrapping around } //Check if item fits by wrapping if (pxRingbuffer->uxRingbufferFlags & rbALLOW_SPLIT_FLAG) { //Allow split wrapping incurs an extra header - return (xTotalItemSize + rbHEADER_SIZE <= pxRingbuffer->xSize - (pxRingbuffer->pucWrite - pxRingbuffer->pucFree)) ? pdTRUE : pdFALSE; + return (xTotalItemSize + rbHEADER_SIZE <= pxRingbuffer->xSize - (pxRingbuffer->pucAcquire - pxRingbuffer->pucFree)) ? pdTRUE : pdFALSE; } else { return (xTotalItemSize <= pxRingbuffer->pucFree - pxRingbuffer->pucHead) ? pdTRUE : pdFALSE; } @@ -298,76 +301,130 @@ static BaseType_t prvCheckItemFitsDefault( Ringbuffer_t *pxRingbuffer, size_t xI static BaseType_t prvCheckItemFitsByteBuffer( Ringbuffer_t *pxRingbuffer, size_t xItemSize) { //Check arguments and buffer state - configASSERT(pxRingbuffer->pucWrite >= pxRingbuffer->pucHead && pxRingbuffer->pucWrite < pxRingbuffer->pucTail); //Check write pointer is within bounds + configASSERT(pxRingbuffer->pucAcquire >= pxRingbuffer->pucHead && pxRingbuffer->pucAcquire < pxRingbuffer->pucTail); //Check acquire pointer is within bounds - if (pxRingbuffer->pucWrite == pxRingbuffer->pucFree) { + if (pxRingbuffer->pucAcquire == pxRingbuffer->pucFree) { //Buffer is either complete empty or completely full return (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG) ? pdFALSE : pdTRUE; } - if (pxRingbuffer->pucFree > pxRingbuffer->pucWrite) { + if (pxRingbuffer->pucFree > pxRingbuffer->pucAcquire) { //Free space does not wrap around - return (xItemSize <= pxRingbuffer->pucFree - pxRingbuffer->pucWrite) ? pdTRUE : pdFALSE; + return (xItemSize <= pxRingbuffer->pucFree - pxRingbuffer->pucAcquire) ? pdTRUE : pdFALSE; } //Free space wraps around - return (xItemSize <= pxRingbuffer->xSize - (pxRingbuffer->pucWrite - pxRingbuffer->pucFree)) ? pdTRUE : pdFALSE; + return (xItemSize <= pxRingbuffer->xSize - (pxRingbuffer->pucAcquire - pxRingbuffer->pucFree)) ? pdTRUE : pdFALSE; } -static void prvCopyItemNoSplit(Ringbuffer_t *pxRingbuffer, const uint8_t *pucItem, size_t xItemSize) +static uint8_t* prvAcquireItemNoSplit(Ringbuffer_t *pxRingbuffer, size_t xItemSize) { //Check arguments and buffer state size_t xAlignedItemSize = rbALIGN_SIZE(xItemSize); //Rounded up aligned item size - size_t xRemLen = pxRingbuffer->pucTail - pxRingbuffer->pucWrite; //Length from pucWrite until end of buffer - configASSERT(rbCHECK_ALIGNED(pxRingbuffer->pucWrite)); //pucWrite is always aligned in no-split ring buffers - configASSERT(pxRingbuffer->pucWrite >= pxRingbuffer->pucHead && pxRingbuffer->pucWrite < pxRingbuffer->pucTail); //Check write pointer is within bounds + size_t xRemLen = pxRingbuffer->pucTail - pxRingbuffer->pucAcquire; //Length from pucAcquire until end of buffer + configASSERT(rbCHECK_ALIGNED(pxRingbuffer->pucAcquire)); //pucAcquire is always aligned in no-split ring buffers + configASSERT(pxRingbuffer->pucAcquire >= pxRingbuffer->pucHead && pxRingbuffer->pucAcquire < pxRingbuffer->pucTail); //Check write pointer is within bounds configASSERT(xRemLen >= rbHEADER_SIZE); //Remaining length must be able to at least fit an item header //If remaining length can't fit item, set as dummy data and wrap around if (xRemLen < xAlignedItemSize + rbHEADER_SIZE) { - ItemHeader_t *pxDummy = (ItemHeader_t *)pxRingbuffer->pucWrite; + ItemHeader_t *pxDummy = (ItemHeader_t *)pxRingbuffer->pucAcquire; pxDummy->uxItemFlags = rbITEM_DUMMY_DATA_FLAG; //Set remaining length as dummy data pxDummy->xItemLen = 0; //Dummy data should have no length - pxRingbuffer->pucWrite = pxRingbuffer->pucHead; //Reset write pointer to wrap around + pxRingbuffer->pucAcquire = pxRingbuffer->pucHead; //Reset acquire pointer to wrap around } //Item should be guaranteed to fit at this point. Set item header and copy data - ItemHeader_t *pxHeader = (ItemHeader_t *)pxRingbuffer->pucWrite; + ItemHeader_t *pxHeader = (ItemHeader_t *)pxRingbuffer->pucAcquire; pxHeader->xItemLen = xItemSize; pxHeader->uxItemFlags = 0; - pxRingbuffer->pucWrite += rbHEADER_SIZE; //Advance pucWrite past header - memcpy(pxRingbuffer->pucWrite, pucItem, xItemSize); - pxRingbuffer->xItemsWaiting++; - pxRingbuffer->pucWrite += xAlignedItemSize; //Advance pucWrite past item to next aligned address + //hold the buffer address without touching pucWrite + uint8_t* item_address = pxRingbuffer->pucAcquire + rbHEADER_SIZE; + pxRingbuffer->pucAcquire += rbHEADER_SIZE + xAlignedItemSize; //Advance pucAcquire past header and the item to next aligned address + + //After the allocation, add some padding after the buffer and correct the flags //If current remaining length can't fit a header, wrap around write pointer - if (pxRingbuffer->pucTail - pxRingbuffer->pucWrite < rbHEADER_SIZE) { - pxRingbuffer->pucWrite = pxRingbuffer->pucHead; //Wrap around pucWrite + if (pxRingbuffer->pucTail - pxRingbuffer->pucAcquire < rbHEADER_SIZE) { + pxRingbuffer->pucAcquire = pxRingbuffer->pucHead; //Wrap around pucAcquire } //Check if buffer is full - if (pxRingbuffer->pucWrite == pxRingbuffer->pucFree) { + if (pxRingbuffer->pucAcquire == pxRingbuffer->pucFree) { //Mark the buffer as full to distinguish with an empty buffer pxRingbuffer->uxRingbufferFlags |= rbBUFFER_FULL_FLAG; } + return item_address; +} + +static void prvSendItemDoneNoSplit(Ringbuffer_t *pxRingbuffer, uint8_t* pucItem) +{ + //Check arguments and buffer state + configASSERT(rbCHECK_ALIGNED(pucItem)); + configASSERT(pucItem >= pxRingbuffer->pucHead); + configASSERT(pucItem <= pxRingbuffer->pucTail); //Inclusive of pucTail in the case of zero length item at the very end + + //Get and check header of the item + ItemHeader_t *pxCurHeader = (ItemHeader_t *)(pucItem - rbHEADER_SIZE); + configASSERT(pxCurHeader->xItemLen <= pxRingbuffer->xMaxItemSize); + configASSERT((pxCurHeader->uxItemFlags & rbITEM_DUMMY_DATA_FLAG) == 0); //Dummy items should never have been written + configASSERT((pxCurHeader->uxItemFlags & rbITEM_WRITTEN_FLAG) == 0); //Indicates item has already been written before + pxCurHeader->uxItemFlags &= ~rbITEM_SPLIT_FLAG; //Clear wrap flag if set (not strictly necessary) + pxCurHeader->uxItemFlags |= rbITEM_WRITTEN_FLAG; //Mark as written + + pxRingbuffer->xItemsWaiting++; + + /* + * Items might not be written in the order they were acquired. Move the + * write pointer up to the next item that has not been marked as written (by + * written flag) or up till the acquire pointer. When advancing the write + * pointer, items that have already been written or items with dummy data + * should be skipped over + */ + pxCurHeader = (ItemHeader_t *)pxRingbuffer->pucWrite; + //Skip over Items that have already been written or are dummy items + while (((pxCurHeader->uxItemFlags & rbITEM_WRITTEN_FLAG) || (pxCurHeader->uxItemFlags & rbITEM_DUMMY_DATA_FLAG)) && pxRingbuffer->pucWrite != pxRingbuffer->pucAcquire) { + if (pxCurHeader->uxItemFlags & rbITEM_DUMMY_DATA_FLAG) { + pxCurHeader->uxItemFlags |= rbITEM_WRITTEN_FLAG; //Mark as freed (not strictly necessary but adds redundancy) + pxRingbuffer->pucWrite = pxRingbuffer->pucHead; //Wrap around due to dummy data + } else { + //Item with data that has already been written, advance write pointer past this item + size_t xAlignedItemSize = rbALIGN_SIZE(pxCurHeader->xItemLen); + pxRingbuffer->pucWrite += xAlignedItemSize + rbHEADER_SIZE; + //Redundancy check to ensure write pointer has not overshot buffer bounds + configASSERT(pxRingbuffer->pucWrite <= pxRingbuffer->pucHead + pxRingbuffer->xSize); + } + //Check if pucAcquire requires wrap around + if ((pxRingbuffer->pucTail - pxRingbuffer->pucWrite) < rbHEADER_SIZE) { + pxRingbuffer->pucWrite = pxRingbuffer->pucHead; + } + pxCurHeader = (ItemHeader_t *)pxRingbuffer->pucWrite; //Update header to point to item + } +} + +static void prvCopyItemNoSplit(Ringbuffer_t *pxRingbuffer, const uint8_t *pucItem, size_t xItemSize) +{ + uint8_t* item_addr = prvAcquireItemNoSplit(pxRingbuffer, xItemSize); + memcpy(item_addr, pucItem, xItemSize); + prvSendItemDoneNoSplit(pxRingbuffer, item_addr); } static void prvCopyItemAllowSplit(Ringbuffer_t *pxRingbuffer, const uint8_t *pucItem, size_t xItemSize) { //Check arguments and buffer state size_t xAlignedItemSize = rbALIGN_SIZE(xItemSize); //Rounded up aligned item size - size_t xRemLen = pxRingbuffer->pucTail - pxRingbuffer->pucWrite; //Length from pucWrite until end of buffer - configASSERT(rbCHECK_ALIGNED(pxRingbuffer->pucWrite)); //pucWrite is always aligned in split ring buffers - configASSERT(pxRingbuffer->pucWrite >= pxRingbuffer->pucHead && pxRingbuffer->pucWrite < pxRingbuffer->pucTail); //Check write pointer is within bounds + size_t xRemLen = pxRingbuffer->pucTail - pxRingbuffer->pucAcquire; //Length from pucAcquire until end of buffer + configASSERT(rbCHECK_ALIGNED(pxRingbuffer->pucAcquire)); //pucAcquire is always aligned in split ring buffers + configASSERT(pxRingbuffer->pucAcquire >= pxRingbuffer->pucHead && pxRingbuffer->pucAcquire < pxRingbuffer->pucTail); //Check write pointer is within bounds configASSERT(xRemLen >= rbHEADER_SIZE); //Remaining length must be able to at least fit an item header //Split item if necessary if (xRemLen < xAlignedItemSize + rbHEADER_SIZE) { //Write first part of the item - ItemHeader_t *pxFirstHeader = (ItemHeader_t *)pxRingbuffer->pucWrite; + ItemHeader_t *pxFirstHeader = (ItemHeader_t *)pxRingbuffer->pucAcquire; pxFirstHeader->uxItemFlags = 0; pxFirstHeader->xItemLen = xRemLen - rbHEADER_SIZE; //Fill remaining length with first part - pxRingbuffer->pucWrite += rbHEADER_SIZE; //Advance pucWrite past header + pxRingbuffer->pucAcquire += rbHEADER_SIZE; //Advance pucAcquire past header xRemLen -= rbHEADER_SIZE; if (xRemLen > 0) { - memcpy(pxRingbuffer->pucWrite, pucItem, xRemLen); + memcpy(pxRingbuffer->pucAcquire, pucItem, xRemLen); pxRingbuffer->xItemsWaiting++; //Update item arguments to account for data already copied pucItem += xRemLen; @@ -378,57 +435,63 @@ static void prvCopyItemAllowSplit(Ringbuffer_t *pxRingbuffer, const uint8_t *puc //Remaining length was only large enough to fit header pxFirstHeader->uxItemFlags |= rbITEM_DUMMY_DATA_FLAG; //Item will completely be stored in 2nd part } - pxRingbuffer->pucWrite = pxRingbuffer->pucHead; //Reset write pointer to start of buffer + pxRingbuffer->pucAcquire = pxRingbuffer->pucHead; //Reset acquire pointer to start of buffer } //Item (whole or second part) should be guaranteed to fit at this point - ItemHeader_t *pxSecondHeader = (ItemHeader_t *)pxRingbuffer->pucWrite; + ItemHeader_t *pxSecondHeader = (ItemHeader_t *)pxRingbuffer->pucAcquire; pxSecondHeader->xItemLen = xItemSize; pxSecondHeader->uxItemFlags = 0; - pxRingbuffer->pucWrite += rbHEADER_SIZE; //Advance write pointer past header - memcpy(pxRingbuffer->pucWrite, pucItem, xItemSize); + pxRingbuffer->pucAcquire += rbHEADER_SIZE; //Advance acquire pointer past header + memcpy(pxRingbuffer->pucAcquire, pucItem, xItemSize); pxRingbuffer->xItemsWaiting++; - pxRingbuffer->pucWrite += xAlignedItemSize; //Advance pucWrite past item to next aligned address + pxRingbuffer->pucAcquire += xAlignedItemSize; //Advance pucAcquire past item to next aligned address //If current remaining length can't fit a header, wrap around write pointer - if (pxRingbuffer->pucTail - pxRingbuffer->pucWrite < rbHEADER_SIZE) { - pxRingbuffer->pucWrite = pxRingbuffer->pucHead; //Wrap around pucWrite + if (pxRingbuffer->pucTail - pxRingbuffer->pucAcquire < rbHEADER_SIZE) { + pxRingbuffer->pucAcquire = pxRingbuffer->pucHead; //Wrap around pucAcquire } //Check if buffer is full - if (pxRingbuffer->pucWrite == pxRingbuffer->pucFree) { + if (pxRingbuffer->pucAcquire == pxRingbuffer->pucFree) { //Mark the buffer as full to distinguish with an empty buffer pxRingbuffer->uxRingbufferFlags |= rbBUFFER_FULL_FLAG; } + + //currently the Split mode is not supported, pucWrite tracks the pucAcquire + pxRingbuffer->pucWrite = pxRingbuffer->pucAcquire; } static void prvCopyItemByteBuf(Ringbuffer_t *pxRingbuffer, const uint8_t *pucItem, size_t xItemSize) { //Check arguments and buffer state - configASSERT(pxRingbuffer->pucWrite >= pxRingbuffer->pucHead && pxRingbuffer->pucWrite < pxRingbuffer->pucTail); //Check write pointer is within bounds + configASSERT(pxRingbuffer->pucAcquire >= pxRingbuffer->pucHead && pxRingbuffer->pucAcquire < pxRingbuffer->pucTail); //Check acquire pointer is within bounds - size_t xRemLen = pxRingbuffer->pucTail - pxRingbuffer->pucWrite; //Length from pucWrite until end of buffer + size_t xRemLen = pxRingbuffer->pucTail - pxRingbuffer->pucAcquire; //Length from pucAcquire until end of buffer if (xRemLen < xItemSize) { //Copy as much as possible into remaining length - memcpy(pxRingbuffer->pucWrite, pucItem, xRemLen); + memcpy(pxRingbuffer->pucAcquire, pucItem, xRemLen); pxRingbuffer->xItemsWaiting += xRemLen; //Update item arguments to account for data already written pucItem += xRemLen; xItemSize -= xRemLen; - pxRingbuffer->pucWrite = pxRingbuffer->pucHead; //Reset write pointer to start of buffer + pxRingbuffer->pucAcquire = pxRingbuffer->pucHead; //Reset acquire pointer to start of buffer } //Copy all or remaining portion of the item - memcpy(pxRingbuffer->pucWrite, pucItem, xItemSize); + memcpy(pxRingbuffer->pucAcquire, pucItem, xItemSize); pxRingbuffer->xItemsWaiting += xItemSize; - pxRingbuffer->pucWrite += xItemSize; + pxRingbuffer->pucAcquire += xItemSize; - //Wrap around pucWrite if it reaches the end - if (pxRingbuffer->pucWrite == pxRingbuffer->pucTail) { - pxRingbuffer->pucWrite = pxRingbuffer->pucHead; + //Wrap around pucAcquire if it reaches the end + if (pxRingbuffer->pucAcquire == pxRingbuffer->pucTail) { + pxRingbuffer->pucAcquire = pxRingbuffer->pucHead; } //Check if buffer is full - if (pxRingbuffer->pucWrite == pxRingbuffer->pucFree) { + if (pxRingbuffer->pucAcquire == pxRingbuffer->pucFree) { pxRingbuffer->uxRingbufferFlags |= rbBUFFER_FULL_FLAG; //Mark the buffer as full to avoid confusion with an empty buffer } + + //Currently, acquiring memory is not supported in byte mode. pucWrite tracks the pucAcquire. + pxRingbuffer->pucWrite = pxRingbuffer->pucAcquire; } static BaseType_t prvCheckItemAvail(Ringbuffer_t *pxRingbuffer) @@ -568,9 +631,9 @@ static void prvReturnItemDefault(Ringbuffer_t *pxRingbuffer, uint8_t *pucItem) //Check if the buffer full flag should be reset if (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG) { - if (pxRingbuffer->pucFree != pxRingbuffer->pucWrite) { + if (pxRingbuffer->pucFree != pxRingbuffer->pucAcquire) { pxRingbuffer->uxRingbufferFlags &= ~rbBUFFER_FULL_FLAG; - } else if (pxRingbuffer->pucFree == pxRingbuffer->pucWrite && pxRingbuffer->pucFree == pxRingbuffer->pucRead) { + } else if (pxRingbuffer->pucFree == pxRingbuffer->pucAcquire && pxRingbuffer->pucFree == pxRingbuffer->pucRead) { //Special case where a full buffer is completely freed in one go pxRingbuffer->uxRingbufferFlags &= ~rbBUFFER_FULL_FLAG; } @@ -597,13 +660,13 @@ static size_t prvGetCurMaxSizeNoSplit(Ringbuffer_t *pxRingbuffer) if (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG) { return 0; } - if (pxRingbuffer->pucWrite < pxRingbuffer->pucFree) { - //Free space is contiguous between pucWrite and pucFree - xFreeSize = pxRingbuffer->pucFree - pxRingbuffer->pucWrite; + if (pxRingbuffer->pucAcquire < pxRingbuffer->pucFree) { + //Free space is contiguous between pucAcquire and pucFree + xFreeSize = pxRingbuffer->pucFree - pxRingbuffer->pucAcquire; } else { //Free space wraps around (or overlapped at pucHead), select largest //contiguous free space as no-split items require contiguous space - size_t xSize1 = pxRingbuffer->pucTail - pxRingbuffer->pucWrite; + size_t xSize1 = pxRingbuffer->pucTail - pxRingbuffer->pucAcquire; size_t xSize2 = pxRingbuffer->pucFree - pxRingbuffer->pucHead; xFreeSize = (xSize1 > xSize2) ? xSize1 : xSize2; } @@ -627,16 +690,16 @@ static size_t prvGetCurMaxSizeAllowSplit(Ringbuffer_t *pxRingbuffer) if (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG) { return 0; } - if (pxRingbuffer->pucWrite == pxRingbuffer->pucHead && pxRingbuffer->pucFree == pxRingbuffer->pucHead) { - //Check for special case where pucWrite and pucFree are both at pucHead + if (pxRingbuffer->pucAcquire == pxRingbuffer->pucHead && pxRingbuffer->pucFree == pxRingbuffer->pucHead) { + //Check for special case where pucAcquire and pucFree are both at pucHead xFreeSize = pxRingbuffer->xSize - rbHEADER_SIZE; - } else if (pxRingbuffer->pucWrite < pxRingbuffer->pucFree) { - //Free space is contiguous between pucWrite and pucFree, requires single header - xFreeSize = (pxRingbuffer->pucFree - pxRingbuffer->pucWrite) - rbHEADER_SIZE; + } else if (pxRingbuffer->pucAcquire < pxRingbuffer->pucFree) { + //Free space is contiguous between pucAcquire and pucFree, requires single header + xFreeSize = (pxRingbuffer->pucFree - pxRingbuffer->pucAcquire) - rbHEADER_SIZE; } else { //Free space wraps around, requires two headers xFreeSize = (pxRingbuffer->pucFree - pxRingbuffer->pucHead) + - (pxRingbuffer->pucTail - pxRingbuffer->pucWrite) - + (pxRingbuffer->pucTail - pxRingbuffer->pucAcquire) - (rbHEADER_SIZE * 2); } @@ -659,9 +722,9 @@ static size_t prvGetCurMaxSizeByteBuf(Ringbuffer_t *pxRingbuffer) /* * Return whatever space is available depending on relative positions of the free - * pointer and write pointer. There is no overhead of headers in this mode + * pointer and Acquire pointer. There is no overhead of headers in this mode */ - xFreeSize = pxRingbuffer->pucFree - pxRingbuffer->pucWrite; + xFreeSize = pxRingbuffer->pucFree - pxRingbuffer->pucAcquire; if (xFreeSize <= 0) { xFreeSize += pxRingbuffer->xSize; } @@ -1228,6 +1291,7 @@ void vRingbufferGetInfo(RingbufHandle_t xRingbuffer, UBaseType_t *uxFree, UBaseType_t *uxRead, UBaseType_t *uxWrite, + UBaseType_t *uxAcquire, UBaseType_t *uxItemsWaiting) { Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; @@ -1243,6 +1307,9 @@ void vRingbufferGetInfo(RingbufHandle_t xRingbuffer, if (uxWrite != NULL) { *uxWrite = (UBaseType_t)(pxRingbuffer->pucWrite - pxRingbuffer->pucHead); } + if (uxAcquire != NULL) { + *uxAcquire = (UBaseType_t)(pxRingbuffer->pucAcquire - pxRingbuffer->pucHead); + } if (uxItemsWaiting != NULL) { *uxItemsWaiting = (UBaseType_t)(pxRingbuffer->xItemsWaiting); } @@ -1253,10 +1320,11 @@ void xRingbufferPrintInfo(RingbufHandle_t xRingbuffer) { Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; configASSERT(pxRingbuffer); - printf("Rb size:%d\tfree: %d\trptr: %d\tfreeptr: %d\twptr: %d\n", + printf("Rb size:%d\tfree: %d\trptr: %d\tfreeptr: %d\twptr: %d, aptr: %d\n", pxRingbuffer->xSize, prvGetFreeSize(pxRingbuffer), pxRingbuffer->pucRead - pxRingbuffer->pucHead, pxRingbuffer->pucFree - pxRingbuffer->pucHead, - pxRingbuffer->pucWrite - pxRingbuffer->pucHead); + pxRingbuffer->pucWrite - pxRingbuffer->pucHead, + pxRingbuffer->pucAcquire - pxRingbuffer->pucHead); } diff --git a/components/esp_ringbuf/test/test_ringbuf.c b/components/esp_ringbuf/test/test_ringbuf.c index d48f54d279..376b119a78 100644 --- a/components/esp_ringbuf/test/test_ringbuf.c +++ b/components/esp_ringbuf/test/test_ringbuf.c @@ -185,12 +185,12 @@ TEST_CASE("Test ring buffer No-Split", "[esp_ringbuf]") //Write pointer should be near the end, test wrap around uint32_t write_pos_before, write_pos_after; - vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL); + vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL, NULL); //Send large item that causes wrap around send_item_and_check(buffer_handle, large_item, LARGE_ITEM_SIZE, TIMEOUT_TICKS, false); //Receive wrapped item receive_check_and_return_item_no_split(buffer_handle, large_item, LARGE_ITEM_SIZE, TIMEOUT_TICKS, false); - vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_after, NULL); + vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_after, NULL, NULL); TEST_ASSERT_MESSAGE(write_pos_after < write_pos_before, "Failed to wrap around"); //Cleanup @@ -216,12 +216,12 @@ TEST_CASE("Test ring buffer Allow-Split", "[esp_ringbuf]") //Write pointer should be near the end, test wrap around uint32_t write_pos_before, write_pos_after; - vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL); + vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL, NULL); //Send large item that causes wrap around send_item_and_check(buffer_handle, large_item, LARGE_ITEM_SIZE, TIMEOUT_TICKS, false); //Receive wrapped item receive_check_and_return_item_allow_split(buffer_handle, large_item, LARGE_ITEM_SIZE, TIMEOUT_TICKS, false); - vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_after, NULL); + vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_after, NULL, NULL); TEST_ASSERT_MESSAGE(write_pos_after < write_pos_before, "Failed to wrap around"); //Cleanup @@ -247,12 +247,12 @@ TEST_CASE("Test ring buffer Byte Buffer", "[esp_ringbuf]") //Write pointer should be near the end, test wrap around uint32_t write_pos_before, write_pos_after; - vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL); + vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL, NULL); //Send large item that causes wrap around send_item_and_check(buffer_handle, large_item, LARGE_ITEM_SIZE, TIMEOUT_TICKS, false); //Receive wrapped item receive_check_and_return_item_byte_buffer(buffer_handle, large_item, LARGE_ITEM_SIZE, TIMEOUT_TICKS, false); - vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_after, NULL); + vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_after, NULL, NULL); TEST_ASSERT_MESSAGE(write_pos_after < write_pos_before, "Failed to wrap around"); //Cleanup From 687908b1e9ffdc7e05dc87b59220075ac383d7af Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Fri, 14 Jun 2019 15:05:00 +0800 Subject: [PATCH 190/486] ringbuffer: support to allocate memory on the ringbuffer before send --- .../esp_ringbuf/include/freertos/ringbuf.h | 44 +++++++++++ components/esp_ringbuf/ringbuf.c | 75 +++++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/components/esp_ringbuf/include/freertos/ringbuf.h b/components/esp_ringbuf/include/freertos/ringbuf.h index 87c1f08f31..338fa3eae2 100644 --- a/components/esp_ringbuf/include/freertos/ringbuf.h +++ b/components/esp_ringbuf/include/freertos/ringbuf.h @@ -181,6 +181,50 @@ BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer, size_t xItemSize, BaseType_t *pxHigherPriorityTaskWoken); +/** + * @brief Acquire memory from the ring buffer to be written to by an external + * source and to be sent later. + * + * Attempt to allocate buffer for an item to be sent into the ring buffer. This + * function will block until enough free space is available or until it + * timesout. + * + * The item, as well as the following items ``SendAcquire`` or ``Send`` after it, + * will not be able to be read from the ring buffer until this item is actually + * sent into the ring buffer. + * + * @param[in] xRingbuffer Ring buffer to allocate the memory + * @param[out] ppvItem Double pointer to memory acquired (set to NULL if no memory were retrieved) + * @param[in] xItemSize Size of item to acquire. + * @param[in] xTicksToWait Ticks to wait for room in the ring buffer. + * + * @note Only applicable for no-split ring buffers now, the actual size of + * memory that the item will occupy will be rounded up to the nearest 32-bit + * aligned size. This is done to ensure all items are always stored in 32-bit + * aligned fashion. + * + * @return + * - pdTRUE if succeeded + * - pdFALSE on time-out or when the data is larger than the maximum permissible size of the buffer + */ +BaseType_t xRingbufferSendAcquire(RingbufHandle_t xRingbuffer, void **ppvItem, size_t xItemSize, TickType_t xTicksToWait); + +/** + * @brief Actually send an item into the ring buffer allocated before by + * ``xRingbufferSendAcquire``. + * + * @param[in] xRingbuffer Ring buffer to insert the item into + * @param[in] pvItem Pointer to item in allocated memory to insert. + * + * @note Only applicable for no-split ring buffers. Only call for items + * allocated by ``xRingbufferSendAcquire``. + * + * @return + * - pdTRUE if succeeded + * - pdFALSE if fail for some reason. + */ +BaseType_t xRingbufferSendComplete(RingbufHandle_t xRingbuffer, void *pvItem); + /** * @brief Retrieve an item from the ring buffer * diff --git a/components/esp_ringbuf/ringbuf.c b/components/esp_ringbuf/ringbuf.c index 63d08ea11d..33a1a5de88 100644 --- a/components/esp_ringbuf/ringbuf.c +++ b/components/esp_ringbuf/ringbuf.c @@ -914,6 +914,81 @@ RingbufHandle_t xRingbufferCreateStatic(size_t xBufferSize, } #endif +BaseType_t xRingbufferSendAcquire(RingbufHandle_t xRingbuffer, void **ppvItem, size_t xItemSize, TickType_t xTicksToWait) +{ + //Check arguments + Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; + configASSERT(pxRingbuffer); + configASSERT(ppvItem != NULL || xItemSize == 0); + //currently only supported in NoSplit buffers + configASSERT((pxRingbuffer->uxRingbufferFlags & (rbBYTE_BUFFER_FLAG | rbALLOW_SPLIT_FLAG)) == 0); + + *ppvItem = NULL; + if (xItemSize > pxRingbuffer->xMaxItemSize) { + return pdFALSE; //Data will never ever fit in the queue. + } + if ((pxRingbuffer->uxRingbufferFlags & rbBYTE_BUFFER_FLAG) && xItemSize == 0) { + return pdTRUE; //Sending 0 bytes to byte buffer has no effect + } + + //Attempt to send an item + BaseType_t xReturn = pdFALSE; + BaseType_t xReturnSemaphore = pdFALSE; + TickType_t xTicksEnd = xTaskGetTickCount() + xTicksToWait; + TickType_t xTicksRemaining = xTicksToWait; + while (xTicksRemaining <= xTicksToWait) { //xTicksToWait will underflow once xTaskGetTickCount() > ticks_end + //Block until more free space becomes available or timeout + if (xSemaphoreTake(rbGET_TX_SEM_HANDLE(pxRingbuffer), xTicksRemaining) != pdTRUE) { + xReturn = pdFALSE; + break; + } + + //Semaphore obtained, check if item can fit + portENTER_CRITICAL(&pxRingbuffer->mux); + if(pxRingbuffer->xCheckItemFits(pxRingbuffer, xItemSize) == pdTRUE) { + //Item will fit, copy item + *ppvItem = prvAcquireItemNoSplit(pxRingbuffer, xItemSize); + xReturn = pdTRUE; + //Check if the free semaphore should be returned to allow other tasks to send + if (prvGetFreeSize(pxRingbuffer) > 0) { + xReturnSemaphore = pdTRUE; + } + portEXIT_CRITICAL(&pxRingbuffer->mux); + break; + } + //Item doesn't fit, adjust ticks and take the semaphore again + if (xTicksToWait != portMAX_DELAY) { + xTicksRemaining = xTicksEnd - xTaskGetTickCount(); + } + portEXIT_CRITICAL(&pxRingbuffer->mux); + /* + * Gap between critical section and re-acquiring of the semaphore. If + * semaphore is given now, priority inversion might occur (see docs) + */ + } + + if (xReturnSemaphore == pdTRUE) { + xSemaphoreGive(rbGET_TX_SEM_HANDLE(pxRingbuffer)); //Give back semaphore so other tasks can acquire + } + return xReturn; +} + +BaseType_t xRingbufferSendComplete(RingbufHandle_t xRingbuffer, void *pvItem) +{ + //Check arguments + Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; + configASSERT(pxRingbuffer); + configASSERT(pvItem != NULL); + configASSERT((pxRingbuffer->uxRingbufferFlags & (rbBYTE_BUFFER_FLAG | rbALLOW_SPLIT_FLAG)) == 0); + + portENTER_CRITICAL(&pxRingbuffer->mux); + prvSendItemDoneNoSplit(pxRingbuffer, pvItem); + portEXIT_CRITICAL(&pxRingbuffer->mux); + + xSemaphoreGive(rbGET_RX_SEM_HANDLE(pxRingbuffer)); + return pdTRUE; +} + BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer, const void *pvItem, size_t xItemSize, From 26db05833960730e62b7e8b72ec6866a088a6cf5 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 26 Jun 2019 15:56:47 +1000 Subject: [PATCH 191/486] cmake kconfig: Pass environment variables to confgen.py via a file Works around "command line too long" errors when using Windows and CMake < 3.11 Closes IDF-711 --- tools/cmake/kconfig.cmake | 12 ++++++++---- tools/kconfig_new/confgen.env.in | 6 ++++++ tools/kconfig_new/confgen.py | 8 ++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 tools/kconfig_new/confgen.env.in diff --git a/tools/cmake/kconfig.cmake b/tools/cmake/kconfig.cmake index 97702935ee..bd1a306687 100644 --- a/tools/cmake/kconfig.cmake +++ b/tools/cmake/kconfig.cmake @@ -123,15 +123,19 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) string(REPLACE ";" " " kconfigs "${kconfigs}") string(REPLACE ";" " " kconfig_projbuilds "${kconfig_projbuilds}") + # Place the long environment arguments into an input file + # to work around command line length limits for execute_process + # on Windows & CMake < 3.11 + configure_file( + "${idf_path}/tools/kconfig_new/confgen.env.in" + "${CMAKE_CURRENT_BINARY_DIR}/confgen.env") + set(confgen_basecommand ${python} ${idf_path}/tools/kconfig_new/confgen.py --kconfig ${root_kconfig} --config ${sdkconfig} ${defaults_arg} - --env "COMPONENT_KCONFIGS=${kconfigs}" - --env "COMPONENT_KCONFIGS_PROJBUILD=${kconfig_projbuilds}" - --env "IDF_CMAKE=y" - --env "IDF_TARGET=${idf_target}") + --env-file "${CMAKE_CURRENT_BINARY_DIR}/confgen.env") idf_build_get_property(build_dir BUILD_DIR) set(config_dir ${build_dir}/config) diff --git a/tools/kconfig_new/confgen.env.in b/tools/kconfig_new/confgen.env.in new file mode 100644 index 0000000000..e639c4d3ac --- /dev/null +++ b/tools/kconfig_new/confgen.env.in @@ -0,0 +1,6 @@ +{ + "COMPONENT_KCONFIGS": "${kconfigs}", + "COMPONENT_KCONFIGS_PROJBUILD": "${kconfig_projbuilds}", + "IDF_CMAKE": "y", + "IDF_TARGET": "${idf_target}" +} diff --git a/tools/kconfig_new/confgen.py b/tools/kconfig_new/confgen.py index bbd4e28042..d4e8752902 100755 --- a/tools/kconfig_new/confgen.py +++ b/tools/kconfig_new/confgen.py @@ -198,6 +198,10 @@ def main(): parser.add_argument('--env', action='append', default=[], help='Environment to set when evaluating the config file', metavar='NAME=VAL') + parser.add_argument('--env-file', type=argparse.FileType('r'), + help='Optional file to load environment variables from. Contents ' + 'should be a JSON object where each key/value pair is a variable.') + args = parser.parse_args() for fmt, filename in args.output: @@ -214,6 +218,10 @@ def main(): for name, value in args.env: os.environ[name] = value + if args.env_file is not None: + env = json.load(args.env_file) + os.environ.update(env) + config = kconfiglib.Kconfig(args.kconfig) config.disable_redun_warnings() config.disable_override_warnings() From f1e07663c42699ff28a29b7d340634e10edb00e0 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 27 Jun 2019 20:30:42 +1000 Subject: [PATCH 192/486] cmake: Use environment variables file for all config binaries --- tools/cmake/kconfig.cmake | 32 +++++++++---------- tools/cmake/ldgen.cmake | 10 +++--- .../{confgen.env.in => config.env.in} | 3 +- tools/kconfig_new/confserver.py | 8 +++++ tools/ldgen/ldgen.py | 20 +++++++++++- tools/ldgen/sdkconfig.py | 8 +---- 6 files changed, 50 insertions(+), 31 deletions(-) rename tools/kconfig_new/{confgen.env.in => config.env.in} (66%) diff --git a/tools/cmake/kconfig.cmake b/tools/cmake/kconfig.cmake index bd1a306687..f865c804eb 100644 --- a/tools/cmake/kconfig.cmake +++ b/tools/cmake/kconfig.cmake @@ -107,6 +107,17 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) idf_build_set_property(KCONFIG_PROJBUILDS "${kconfig_projbuilds}") idf_build_get_property(idf_target IDF_TARGET) + idf_build_get_property(idf_path IDF_PATH) + + string(REPLACE ";" " " kconfigs "${kconfigs}") + string(REPLACE ";" " " kconfig_projbuilds "${kconfig_projbuilds}") + + # Place config-related environment arguments into config.env file + # to work around command line length limits for execute_process + # on Windows & CMake < 3.11 + set(config_env_path "${CMAKE_CURRENT_BINARY_DIR}/config.env") + configure_file("${idf_path}/tools/kconfig_new/config.env.in" ${config_env_path}) + idf_build_set_property(CONFIG_ENV_PATH ${config_env_path}) if(sdkconfig_defaults) set(defaults_arg --defaults "${sdkconfig_defaults}") @@ -116,26 +127,15 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) list(APPEND defaults_arg --defaults "${sdkconfig_defaults}.${idf_target}") endif() - idf_build_get_property(idf_path IDF_PATH) idf_build_get_property(root_kconfig __ROOT_KCONFIG) idf_build_get_property(python PYTHON) - string(REPLACE ";" " " kconfigs "${kconfigs}") - string(REPLACE ";" " " kconfig_projbuilds "${kconfig_projbuilds}") - - # Place the long environment arguments into an input file - # to work around command line length limits for execute_process - # on Windows & CMake < 3.11 - configure_file( - "${idf_path}/tools/kconfig_new/confgen.env.in" - "${CMAKE_CURRENT_BINARY_DIR}/confgen.env") - set(confgen_basecommand ${python} ${idf_path}/tools/kconfig_new/confgen.py --kconfig ${root_kconfig} --config ${sdkconfig} ${defaults_arg} - --env-file "${CMAKE_CURRENT_BINARY_DIR}/confgen.env") + --env-file ${config_env_path}) idf_build_get_property(build_dir BUILD_DIR) set(config_dir ${build_dir}/config) @@ -221,10 +221,10 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) # Custom target to run confserver.py from the build tool add_custom_target(confserver - COMMAND ${CMAKE_COMMAND} -E env - "COMPONENT_KCONFIGS=${kconfigs}" - "COMPONENT_KCONFIGS_PROJBUILD=${kconfig_projbuilds}" - ${PYTHON} ${IDF_PATH}/tools/kconfig_new/confserver.py --kconfig ${IDF_PATH}/Kconfig --config ${sdkconfig} + COMMAND ${PYTHON} ${IDF_PATH}/tools/kconfig_new/confserver.py + --env-file ${config_env_path} + --kconfig ${IDF_PATH}/Kconfig + --config ${sdkconfig} VERBATIM USES_TERMINAL) endfunction() diff --git a/tools/cmake/ldgen.cmake b/tools/cmake/ldgen.cmake index 27db72ae36..22d7fe672d 100644 --- a/tools/cmake/ldgen.cmake +++ b/tools/cmake/ldgen.cmake @@ -54,6 +54,8 @@ function(__ldgen_process_template template output) string(REPLACE ";" " " kconfigs "${kconfigs}") string(REPLACE ";" " " kconfig_projbuilds "${kconfig_projbuilds}") + idf_build_get_property(config_env_path CONFIG_ENV_PATH) + add_custom_command( OUTPUT ${output} COMMAND ${python} ${idf_path}/tools/ldgen/ldgen.py @@ -62,11 +64,7 @@ function(__ldgen_process_template template output) --input ${template} --output ${output} --kconfig ${root_kconfig} - --env "COMPONENT_KCONFIGS=${kconfigs}" - --env "COMPONENT_KCONFIGS_PROJBUILD=${kconfig_projbuilds}" - --env "IDF_CMAKE=y" - --env "IDF_PATH=${idf_path}" - --env "IDF_TARGET=${idf_target}" + --env-file "${config_env_path}" --libraries-file ${build_dir}/ldgen_libraries --objdump ${CMAKE_OBJDUMP} DEPENDS ${template} ${ldgen_fragment_files} ${ldgen_depends} ${SDKCONFIG} @@ -76,4 +74,4 @@ function(__ldgen_process_template template output) add_custom_target(__ldgen_output_${_name} DEPENDS ${output}) add_dependencies(__idf_build_target __ldgen_output_${_name}) idf_build_set_property(__LINK_DEPENDS ${output} APPEND) -endfunction() \ No newline at end of file +endfunction() diff --git a/tools/kconfig_new/confgen.env.in b/tools/kconfig_new/config.env.in similarity index 66% rename from tools/kconfig_new/confgen.env.in rename to tools/kconfig_new/config.env.in index e639c4d3ac..d685c85d06 100644 --- a/tools/kconfig_new/confgen.env.in +++ b/tools/kconfig_new/config.env.in @@ -2,5 +2,6 @@ "COMPONENT_KCONFIGS": "${kconfigs}", "COMPONENT_KCONFIGS_PROJBUILD": "${kconfig_projbuilds}", "IDF_CMAKE": "y", - "IDF_TARGET": "${idf_target}" + "IDF_TARGET": "${idf_target}", + "IDF_PATH": "${idf_path}" } diff --git a/tools/kconfig_new/confserver.py b/tools/kconfig_new/confserver.py index 7b90d4692c..914a2dd735 100755 --- a/tools/kconfig_new/confserver.py +++ b/tools/kconfig_new/confserver.py @@ -32,6 +32,10 @@ def main(): parser.add_argument('--env', action='append', default=[], help='Environment to set when evaluating the config file', metavar='NAME=VAL') + parser.add_argument('--env-file', type=argparse.FileType('r'), + help='Optional file to load environment variables from. Contents ' + 'should be a JSON object where each key/value pair is a variable.') + parser.add_argument('--version', help='Set protocol version to use on initial status', type=int, default=MAX_PROTOCOL_VERSION) @@ -54,6 +58,10 @@ def main(): for name, value in args.env: os.environ[name] = value + if args.env_file is not None: + env = json.load(args.env_file) + os.environ.update(env) + run_server(args.kconfig, args.config) diff --git a/tools/ldgen/ldgen.py b/tools/ldgen/ldgen.py index dcc0db4e07..0eabb3d2e2 100755 --- a/tools/ldgen/ldgen.py +++ b/tools/ldgen/ldgen.py @@ -16,6 +16,7 @@ # import argparse +import json import sys import tempfile import subprocess @@ -30,6 +31,17 @@ from pyparsing import ParseException, ParseFatalException from io import StringIO +def _update_environment(args): + env = [(name, value) for (name,value) in (e.split("=",1) for e in args.env)] + for name, value in env: + value = " ".join(value.split()) + os.environ[name] = value + + if args.env_file is not None: + env = json.load(args.env_file) + os.environ.update(env) + + def main(): argparser = argparse.ArgumentParser(description="ESP-IDF linker script generator") @@ -68,6 +80,10 @@ def main(): action='append', default=[], help='Environment to set when evaluating the config file', metavar='NAME=VAL') + argparser.add_argument('--env-file', type=argparse.FileType('r'), + help='Optional file to load environment variables from. Contents ' + 'should be a JSON object where each key/value pair is a variable.') + argparser.add_argument( "--objdump", help="Path to toolchain objdump") @@ -93,7 +109,9 @@ def main(): generation_model = GenerationModel() - sdkconfig = SDKConfig(kconfig_file, config_file, args.env) + _update_environment(args) # assign args.env and args.env_file to os.environ + + sdkconfig = SDKConfig(kconfig_file, config_file) for fragment_file in fragment_files: try: diff --git a/tools/ldgen/sdkconfig.py b/tools/ldgen/sdkconfig.py index 6a118e83e5..943013dfcf 100644 --- a/tools/ldgen/sdkconfig.py +++ b/tools/ldgen/sdkconfig.py @@ -46,13 +46,7 @@ class SDKConfig: # Operators supported by the expression evaluation OPERATOR = oneOf(["=", "!=", ">", "<", "<=", ">="]) - def __init__(self, kconfig_file, sdkconfig_file, env=[]): - env = [(name, value) for (name,value) in (e.split("=",1) for e in env)] - - for name, value in env: - value = " ".join(value.split()) - os.environ[name] = value - + def __init__(self, kconfig_file, sdkconfig_file): self.config = kconfiglib.Kconfig(kconfig_file) self.config.load_config(sdkconfig_file) From cba69dd088344ed9d26739f04736ae7a37541b3a Mon Sep 17 00:00:00 2001 From: Hrishikesh Dhayagude Date: Mon, 1 Jul 2019 19:21:57 +0800 Subject: [PATCH 193/486] Bluetooth examples restructuring The existing Bluetooth examples are split as: 1. examples/bluetooth/bluedroid - Bluedroid Host (BT + BLE) examples a. examples/bluetooth/bluedroid/classic_bt - Classic BT examples b. examples/bluetooth/bluedroid/ble - BLE examples c. examples/bluetooth/bluedroid/coex - Classic BT and BLE coex examples d. examples/bluetooth/bluedroid/hci - VHCI and HCI UART examples i. Rename ble_adv to controller_vhci_ble_adv and move it in hci folder 2. examples/bluetooth/nimble - NimBLE BLE Host + NimBLE Mesh examples 3. examples/bluetooth/esp_ble_mesh - ESP BLE Mesh examples 4. Update documentation references --- .../api-reference/bluetooth/controller_vhci.rst | 4 ++-- docs/en/api-reference/bluetooth/esp_a2dp.rst | 4 ++-- docs/en/api-reference/bluetooth/esp_blufi.rst | 4 ++-- docs/en/api-reference/bluetooth/esp_gap_ble.rst | 10 +++++----- docs/en/api-reference/bluetooth/esp_gattc.rst | 12 ++++++------ docs/en/api-reference/bluetooth/esp_gatts.rst | 12 ++++++------ docs/en/api-reference/bluetooth/esp_spp.rst | 4 ++-- docs/en/api-reference/bluetooth/index.rst | 14 +++++++------- docs/zh_CN/api-reference/bluetooth/index.rst | 14 +++++++------- examples/README.md | 5 +++-- examples/bluetooth/README.md | 5 ----- examples/bluetooth/bluedroid/README.md | 13 +++++++++++++ .../ble}/ble_compatibility_test/CMakeLists.txt | 0 .../ble}/ble_compatibility_test/Makefile | 0 .../ble_compatibility_test_case.md | 2 +- .../esp_ble_compatibility_test_report.md | 2 +- .../ble_compatibility_test/main/CMakeLists.txt | 0 .../main/ble_compatibility_test.c | 0 .../main/ble_compatibility_test.h | 0 .../ble/ble_compatibility_test}/main/component.mk | 0 .../ble_compatibility_test/sdkconfig.defaults | 0 .../ble}/ble_eddystone/CMakeLists.txt | 0 .../{ => bluedroid/ble}/ble_eddystone/Makefile | 0 .../{ => bluedroid/ble}/ble_eddystone/README.md | 0 .../ble}/ble_eddystone/main/CMakeLists.txt | 0 .../ble/ble_eddystone}/main/component.mk | 0 .../ble}/ble_eddystone/main/esp_eddystone_api.c | 0 .../ble}/ble_eddystone/main/esp_eddystone_api.h | 0 .../ble}/ble_eddystone/main/esp_eddystone_demo.c | 0 .../ble_eddystone/main/esp_eddystone_protocol.h | 0 .../ble}/ble_eddystone/sdkconfig.defaults | 0 .../ble}/ble_hid_device_demo/CMakeLists.txt | 0 .../ble}/ble_hid_device_demo/Makefile | 0 .../ble}/ble_hid_device_demo/README.md | 0 .../ble}/ble_hid_device_demo/main/CMakeLists.txt | 0 .../ble_hid_device_demo/main/ble_hidd_demo_main.c | 0 .../ble}/ble_hid_device_demo/main/component.mk | 0 .../ble_hid_device_demo/main/esp_hidd_prf_api.c | 0 .../ble_hid_device_demo/main/esp_hidd_prf_api.h | 0 .../ble}/ble_hid_device_demo/main/hid_dev.c | 0 .../ble}/ble_hid_device_demo/main/hid_dev.h | 0 .../ble_hid_device_demo/main/hid_device_le_prf.c | 0 .../ble_hid_device_demo/main/hidd_le_prf_int.h | 0 .../ble}/ble_hid_device_demo/sdkconfig.defaults | 0 .../ble}/ble_ibeacon/CMakeLists.txt | 0 .../{ => bluedroid/ble}/ble_ibeacon/Makefile | 0 .../{ => bluedroid/ble}/ble_ibeacon/README.md | 0 .../ble}/ble_ibeacon/main/CMakeLists.txt | 0 .../ble}/ble_ibeacon/main/Kconfig.projbuild | 0 .../ble/ble_ibeacon}/main/component.mk | 0 .../ble}/ble_ibeacon/main/esp_ibeacon_api.c | 0 .../ble}/ble_ibeacon/main/esp_ibeacon_api.h | 0 .../ble}/ble_ibeacon/main/ibeacon_demo.c | 0 .../ble}/ble_ibeacon/sdkconfig.defaults | 0 .../ble}/ble_spp_client/CMakeLists.txt | 0 .../{ => bluedroid/ble}/ble_spp_client/Makefile | 0 .../{ => bluedroid/ble}/ble_spp_client/README.md | 0 .../ble}/ble_spp_client/main/CMakeLists.txt | 0 .../ble/ble_spp_client}/main/component.mk | 0 .../ble}/ble_spp_client/main/spp_client_demo.c | 0 .../ble}/ble_spp_client/sdkconfig.defaults | 0 .../ble}/ble_spp_server/CMakeLists.txt | 0 .../{ => bluedroid/ble}/ble_spp_server/Makefile | 0 .../{ => bluedroid/ble}/ble_spp_server/README.md | 0 .../ble}/ble_spp_server/main/CMakeLists.txt | 0 .../ble_spp_server/main/ble_spp_server_demo.c | 0 .../ble_spp_server/main/ble_spp_server_demo.h | 0 .../ble/ble_spp_server}/main/component.mk | 0 .../ble}/ble_spp_server/sdkconfig.defaults | 0 .../throughput_client/CMakeLists.txt | 0 .../ble_throughput/throughput_client/Makefile | 0 .../ble_throughput/throughput_client/README.md | 0 .../throughput_client/main/CMakeLists.txt | 0 .../ble_throughput/throughput_client/main/Kconfig | 0 .../throughput_client}/main/component.mk | 0 .../main/example_ble_client_throughput.c | 0 .../throughput_client/sdkconfig.defaults | 0 .../throughput_server/CMakeLists.txt | 0 .../ble_throughput/throughput_server/Makefile | 0 .../ble_throughput/throughput_server/README.md | 0 .../throughput_server/main/CMakeLists.txt | 0 .../ble_throughput/throughput_server/main/Kconfig | 0 .../throughput_server}/main/component.mk | 0 .../main/example_ble_server_throughput.c | 0 .../throughput_server/sdkconfig.defaults | 0 .../{ => bluedroid/ble}/blufi/CMakeLists.txt | 0 .../bluetooth/{ => bluedroid/ble}/blufi/Makefile | 0 .../bluetooth/{ => bluedroid/ble}/blufi/README.md | 0 .../{ => bluedroid/ble}/blufi/main/CMakeLists.txt | 0 .../ble}/blufi/main/blufi_example.h | 0 .../ble}/blufi/main/blufi_example_main.c | 0 .../ble}/blufi/main/blufi_security.c | 0 .../ble/blufi}/main/component.mk | 0 .../{ => bluedroid/ble}/blufi/sdkconfig.defaults | 0 .../ble}/gatt_client/CMakeLists.txt | 0 .../{ => bluedroid/ble}/gatt_client/Makefile | 0 .../{ => bluedroid/ble}/gatt_client/README.md | 0 .../ble}/gatt_client/main/CMakeLists.txt | 0 .../ble}/gatt_client/main/Kconfig.projbuild | 0 .../ble/gatt_client}/main/component.mk | 0 .../ble}/gatt_client/main/gattc_demo.c | 0 .../ble}/gatt_client/sdkconfig.defaults | 0 .../tutorial/Gatt_Client_Example_Walkthrough.md | 4 ++-- .../ble}/gatt_security_client/CMakeLists.txt | 0 .../ble}/gatt_security_client/Makefile | 0 .../ble}/gatt_security_client/README.md | 0 .../ble}/gatt_security_client/main/CMakeLists.txt | 0 .../ble/gatt_security_client}/main/component.mk | 0 .../main/example_ble_sec_gattc_demo.c | 0 .../ble}/gatt_security_client/sdkconfig.defaults | 0 .../Gatt_Security_Client_Example_Walkthrough.md | 0 .../ble}/gatt_security_server/CMakeLists.txt | 0 .../ble}/gatt_security_server/Makefile | 0 .../ble}/gatt_security_server/README.md | 0 .../ble}/gatt_security_server/main/CMakeLists.txt | 0 .../ble}/gatt_security_server/main/component.mk | 0 .../main/example_ble_sec_gatts_demo.c | 0 .../main/example_ble_sec_gatts_demo.h | 0 .../ble}/gatt_security_server/sdkconfig.defaults | 0 .../Gatt_Security_Server_Example_Walkthrough.md | 0 .../ble}/gatt_server/CMakeLists.txt | 0 .../{ => bluedroid/ble}/gatt_server/Makefile | 0 .../{ => bluedroid/ble}/gatt_server/README.md | 0 .../ble}/gatt_server/main/CMakeLists.txt | 0 .../{ => bluedroid/ble}/gatt_server/main/Kconfig | 0 .../ble/gatt_server}/main/component.mk | 0 .../ble}/gatt_server/main/gatts_demo.c | 0 .../ble}/gatt_server/sdkconfig.defaults | 0 .../tutorial/Gatt_Server_Example_Walkthrough.md | 0 .../tutorial/image/GATT_Server_Figure_1.png | Bin .../tutorial/image/GATT_Server_Figure_2.png | Bin .../ble}/gatt_server_service_table/CMakeLists.txt | 0 .../ble}/gatt_server_service_table/Makefile | 0 .../ble}/gatt_server_service_table/README.md | 0 .../gatt_server_service_table/main/CMakeLists.txt | 0 .../gatt_server_service_table}/main/component.mk | 0 .../main/gatts_table_creat_demo.c | 0 .../main/gatts_table_creat_demo.h | 0 .../gatt_server_service_table/sdkconfig.defaults | 0 ...tt_Server_Service_Table_Example_Walkthrough.md | 0 .../tutorial/image/Heart_Rate_Service.png | Bin .../ble}/gattc_multi_connect/CMakeLists.txt | 0 .../ble}/gattc_multi_connect/Makefile | 0 .../ble}/gattc_multi_connect/README.md | 0 .../ble}/gattc_multi_connect/main/CMakeLists.txt | 0 .../ble/gattc_multi_connect}/main/component.mk | 0 .../main/gattc_multi_connect.c | 0 .../ble}/gattc_multi_connect/sdkconfig.defaults | 0 ...Client_Multi_Connection_Example_Walkthrough.md | 2 +- ..._Multi_Connect_Client_Application_Profiles.png | Bin .../Multi_Connection_GATT_Client_Flowchart.png | Bin .../classic_bt}/a2dp_sink/CMakeLists.txt | 0 .../{ => bluedroid/classic_bt}/a2dp_sink/Makefile | 0 .../classic_bt}/a2dp_sink/README.md | 0 .../classic_bt/a2dp_sink}/main/CMakeLists.txt | 0 .../classic_bt/a2dp_sink}/main/Kconfig.projbuild | 0 .../classic_bt/a2dp_sink}/main/bt_app_av.c | 0 .../classic_bt/a2dp_sink}/main/bt_app_av.h | 0 .../classic_bt/a2dp_sink}/main/bt_app_core.c | 0 .../classic_bt/a2dp_sink}/main/bt_app_core.h | 0 .../classic_bt/a2dp_sink}/main/component.mk | 0 .../classic_bt}/a2dp_sink/main/main.c | 0 .../classic_bt}/a2dp_sink/sdkconfig.defaults | 0 .../classic_bt}/a2dp_source/CMakeLists.txt | 0 .../classic_bt}/a2dp_source/Makefile | 0 .../classic_bt}/a2dp_source/README.md | 0 .../classic_bt}/a2dp_source/main/CMakeLists.txt | 0 .../classic_bt}/a2dp_source/main/bt_app_core.c | 0 .../classic_bt/a2dp_source}/main/bt_app_core.h | 0 .../classic_bt/a2dp_source}/main/component.mk | 0 .../classic_bt}/a2dp_source/main/main.c | 0 .../classic_bt}/a2dp_source/sdkconfig.defaults | 0 .../classic_bt}/bt_discovery/CMakeLists.txt | 0 .../classic_bt}/bt_discovery/Makefile | 0 .../classic_bt}/bt_discovery/README.rst | 0 .../classic_bt}/bt_discovery/main/CMakeLists.txt | 0 .../classic_bt}/bt_discovery/main/bt_discovery.c | 0 .../classic_bt/bt_discovery}/main/component.mk | 0 .../classic_bt}/bt_discovery/sdkconfig.defaults | 0 .../classic_bt}/bt_spp_acceptor/CMakeLists.txt | 0 .../classic_bt}/bt_spp_acceptor/Makefile | 0 .../classic_bt}/bt_spp_acceptor/README.rst | 0 .../bt_spp_acceptor/main/CMakeLists.txt | 0 .../classic_bt/bt_spp_acceptor}/main/component.mk | 0 .../main/example_spp_acceptor_demo.c | 0 .../bt_spp_acceptor/sdkconfig.defaults | 0 .../classic_bt}/bt_spp_initiator/CMakeLists.txt | 0 .../classic_bt}/bt_spp_initiator/Makefile | 0 .../classic_bt}/bt_spp_initiator/README.rst | 0 .../bt_spp_initiator/main/CMakeLists.txt | 0 .../bt_spp_initiator}/main/component.mk | 0 .../main/example_spp_initiator_demo.c | 0 .../bt_spp_initiator/sdkconfig.defaults | 0 .../bt_spp_vfs_acceptor/CMakeLists.txt | 0 .../classic_bt}/bt_spp_vfs_acceptor/Makefile | 0 .../classic_bt}/bt_spp_vfs_acceptor/README.rst | 0 .../bt_spp_vfs_acceptor/main/CMakeLists.txt | 0 .../bt_spp_vfs_acceptor}/main/component.mk | 0 .../main/example_spp_vfs_acceptor_demo.c | 0 .../bt_spp_vfs_acceptor/main/spp_task.c | 0 .../bt_spp_vfs_acceptor/main/spp_task.h | 0 .../bt_spp_vfs_acceptor/sdkconfig.defaults | 0 .../bt_spp_vfs_initiator/CMakeLists.txt | 0 .../classic_bt}/bt_spp_vfs_initiator/Makefile | 0 .../classic_bt}/bt_spp_vfs_initiator/README.rst | 0 .../bt_spp_vfs_initiator/main/CMakeLists.txt | 0 .../bt_spp_vfs_initiator}/main/component.mk | 0 .../main/example_spp_vfs_initiator_demo.c | 0 .../bt_spp_vfs_initiator/main/spp_task.c | 0 .../bt_spp_vfs_initiator/main/spp_task.h | 0 .../bt_spp_vfs_initiator/sdkconfig.defaults | 0 .../coex}/a2dp_gatts_coex/CMakeLists.txt | 0 .../{ => bluedroid/coex}/a2dp_gatts_coex/Makefile | 0 .../coex}/a2dp_gatts_coex/README.md | 0 .../coex/a2dp_gatts_coex}/main/CMakeLists.txt | 0 .../coex/a2dp_gatts_coex}/main/Kconfig.projbuild | 0 .../coex/a2dp_gatts_coex}/main/bt_app_av.c | 0 .../coex/a2dp_gatts_coex}/main/bt_app_av.h | 0 .../coex/a2dp_gatts_coex}/main/bt_app_core.c | 0 .../coex/a2dp_gatts_coex}/main/bt_app_core.h | 0 .../coex/a2dp_gatts_coex}/main/component.mk | 0 .../coex}/a2dp_gatts_coex/main/main.c | 0 .../coex}/a2dp_gatts_coex/sdkconfig.defaults | 0 .../coex}/gattc_gatts_coex/CMakeLists.txt | 0 .../coex}/gattc_gatts_coex/Makefile | 0 .../coex}/gattc_gatts_coex/README.md | 0 .../coex}/gattc_gatts_coex/main/CMakeLists.txt | 0 .../coex/gattc_gatts_coex}/main/component.mk | 0 .../gattc_gatts_coex/main/gattc_gatts_coex.c | 0 .../coex}/gattc_gatts_coex/sdkconfig.defaults | 0 .../hci}/controller_hci_uart/CMakeLists.txt | 0 .../hci}/controller_hci_uart/Makefile | 0 .../hci}/controller_hci_uart/README.md | 0 .../hci}/controller_hci_uart/main/CMakeLists.txt | 0 .../hci}/controller_hci_uart/main/component.mk | 0 .../main/controller_hci_uart_demo.c | 0 .../hci}/controller_hci_uart/sdkconfig.defaults | 0 .../hci/controller_vhci_ble_adv}/CMakeLists.txt | 0 .../hci/controller_vhci_ble_adv}/Makefile | 0 .../hci/controller_vhci_ble_adv}/README.md | 4 ++-- .../controller_vhci_ble_adv}/main/CMakeLists.txt | 0 .../hci/controller_vhci_ble_adv}/main/app_bt.c | 0 .../controller_vhci_ble_adv}/main/component.mk | 0 .../controller_vhci_ble_adv}/sdkconfig.defaults | 0 .../ble_mesh_client_model/CMakeLists.txt | 0 .../ble_mesh_client_model/Makefile | 0 .../ble_mesh_client_model/README.md | 0 .../ble_mesh_client_model/main/CMakeLists.txt | 0 .../ble_mesh_client_model/main/Kconfig.projbuild | 0 .../main/ble_mesh_demo_main.c | 0 .../ble_mesh_client_model/main/board.c | 0 .../ble_mesh_client_model/main/board.h | 0 .../ble_mesh_client_model}/main/component.mk | 0 .../ble_mesh_client_model/sdkconfig.defaults | 0 .../tutorial/ble_mesh_client_model.md | 0 .../ble_mesh_client_model/tutorial/images/app.png | Bin .../tutorial/images/message.png | Bin .../tutorial/images/picture5.png | Bin .../ble_mesh_console/ble_mesh_node/CMakeLists.txt | 0 .../ble_mesh_console/ble_mesh_node/Makefile | 0 .../ble_mesh_console/ble_mesh_node/README.md | 0 .../ble_mesh_node/main/CMakeLists.txt | 0 .../ble_mesh_node/main/ble_mesh_adapter.c | 0 .../ble_mesh_node/main/ble_mesh_adapter.h | 0 .../ble_mesh_node/main/ble_mesh_cfg_srv_model.c | 0 .../ble_mesh_node/main/ble_mesh_cfg_srv_model.h | 0 .../ble_mesh_node/main/ble_mesh_console_decl.h | 0 .../ble_mesh_node/main/ble_mesh_console_lib.c | 0 .../ble_mesh_node/main/ble_mesh_console_lib.h | 0 .../ble_mesh_node/main/ble_mesh_console_main.c | 0 .../ble_mesh_node/main/ble_mesh_console_system.c | 0 .../main/ble_mesh_register_node_cmd.c | 0 .../main/ble_mesh_register_server_cmd.c | 0 .../ble_mesh_node}/main/component.mk | 0 .../ble_mesh_node/main/register_bluetooth.c | 0 .../ble_mesh_node/sdkconfig.defaults | 0 .../ble_mesh_provisioner/CMakeLists.txt | 0 .../ble_mesh_provisioner/Makefile | 0 .../ble_mesh_provisioner/README.md | 0 .../ble_mesh_provisioner/main/CMakeLists.txt | 0 .../ble_mesh_provisioner/main/ble_mesh_adapter.c | 0 .../ble_mesh_provisioner/main/ble_mesh_adapter.h | 0 .../main/ble_mesh_cfg_srv_model.c | 0 .../main/ble_mesh_cfg_srv_model.h | 0 .../main/ble_mesh_console_decl.h | 0 .../main/ble_mesh_console_lib.c | 0 .../main/ble_mesh_console_lib.h | 0 .../main/ble_mesh_console_main.c | 0 .../main/ble_mesh_console_system.c | 0 .../main/ble_mesh_reg_cfg_client_cmd.c | 0 .../main/ble_mesh_reg_gen_onoff_client_cmd.c | 0 .../main/ble_mesh_reg_test_perf_client_cmd.c | 0 .../main/ble_mesh_register_node_cmd.c | 0 .../main/ble_mesh_register_provisioner_cmd.c | 0 .../ble_mesh_provisioner}/main/component.mk | 0 .../main/register_bluetooth.c | 0 .../ble_mesh_provisioner/sdkconfig.defaults | 0 .../ble_mesh_fast_prov_client/CMakeLists.txt | 2 +- .../ble_mesh_fast_prov_client/Makefile | 2 +- .../ble_mesh_fast_prov_client/README.md | 0 .../ble_mesh_fast_prov_client/main/CMakeLists.txt | 0 .../main/ble_mesh_demo_main.c | 0 .../ble_mesh_fast_prov_client}/main/component.mk | 0 .../ble_mesh_fast_prov_client/sdkconfig.defaults | 0 .../tutorial/ble_mesh_fast_provision_client.md | 0 .../ble_mesh_fast_prov_server/CMakeLists.txt | 2 +- .../ble_mesh_fast_prov_server/Makefile | 2 +- .../ble_mesh_fast_prov_server/README.md | 0 .../ble_mesh_fast_prov_server/main/CMakeLists.txt | 0 .../main/Kconfig.projbuild | 0 .../main/ble_mesh_demo_main.c | 0 .../ble_mesh_fast_prov_server/main/board.c | 0 .../ble_mesh_fast_prov_server/main/board.h | 0 .../ble_mesh_fast_prov_server}/main/component.mk | 0 .../ble_mesh_fast_prov_server/sdkconfig.defaults | 0 .../tutorial/EspBleMesh.md | 4 ++-- .../tutorial/ble_mesh_fast_provision_server.md | 0 .../tutorial/images/app_ble.png | Bin .../tutorial/images/device.png | Bin .../tutorial/images/picture1.png | Bin .../tutorial/images/picture2.png | Bin .../tutorial/images/time.png | Bin .../ble_mesh_node/CMakeLists.txt | 0 .../ble_mesh_node/Makefile | 0 .../ble_mesh_node/README.md | 0 .../ble_mesh_node/main/CMakeLists.txt | 0 .../ble_mesh_node/main/Kconfig.projbuild | 0 .../ble_mesh_node/main/ble_mesh_demo_main.c | 0 .../ble_mesh_node/main/board.c | 0 .../ble_mesh_node/main/board.h | 0 .../ble_mesh_node}/main/component.mk | 0 .../ble_mesh_node/sdkconfig.defaults | 0 .../tutorial/Ble_Mesh_Node_Example_Walkthrough.md | 4 ++-- .../ble_mesh_provisioner/CMakeLists.txt | 0 .../ble_mesh_provisioner/Makefile | 0 .../ble_mesh_provisioner/README.md | 0 .../ble_mesh_provisioner/main/CMakeLists.txt | 0 .../main/ble_mesh_demo_main.c | 0 .../ble_mesh_provisioner}/main/component.mk | 0 .../ble_mesh_provisioner/sdkconfig.defaults | 0 .../Ble_Mesh_Provisioner_Example_Walkthrough.md | 0 .../fast_prov_vendor_model/CMakeLists.txt | 0 .../fast_prov_vendor_model/Makefile | 0 .../components/CMakeLists.txt | 0 .../components/component.mk | 0 .../components/esp_fast_prov_client_model.c | 0 .../components/esp_fast_prov_client_model.h | 0 .../components/esp_fast_prov_common.h | 0 .../components/esp_fast_prov_operation.c | 0 .../components/esp_fast_prov_operation.h | 0 .../components/esp_fast_prov_server_model.c | 0 .../components/esp_fast_prov_server_model.h | 0 .../fast_prov_vendor_model/main/CMakeLists.txt | 0 .../fast_prov_vendor_model/main/component.mk | 0 .../fast_prov_vendor_model/main/main.c | 0 .../fast_prov_vendor_model/sdkconfig.defaults | 0 .../ble_mesh_wifi_coexist/CMakeLists.txt | 2 +- .../ble_mesh_wifi_coexist/Makefile | 2 +- .../ble_mesh_wifi_coexist/README.md | 0 .../components/iperf/CMakeLists.txt | 0 .../components/iperf/cmd_decl.h | 0 .../components/iperf/cmd_wifi.c | 0 .../components/iperf/component.mk | 0 .../components/iperf/iperf.c | 0 .../components/iperf/iperf.h | 0 .../ble_mesh_wifi_coexist/main/CMakeLists.txt | 0 .../ble_mesh_wifi_coexist/main/Kconfig.projbuild | 0 .../main/ble_mesh_demo_main.c | 0 .../ble_mesh_wifi_coexist/main/board.c | 0 .../ble_mesh_wifi_coexist/main/board.h | 0 .../ble_mesh_wifi_coexist/main/component.mk | 0 .../ble_mesh_wifi_coexist/partitions.csv | 0 .../ble_mesh_wifi_coexist/sdkconfig.defaults | 0 .../tutorial/ble_mesh_wifi_coexist.md | 2 +- examples/bluetooth/nimble/README.md | 6 +++++- 375 files changed, 78 insertions(+), 65 deletions(-) delete mode 100644 examples/bluetooth/README.md create mode 100644 examples/bluetooth/bluedroid/README.md rename examples/bluetooth/{ => bluedroid/ble}/ble_compatibility_test/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_compatibility_test/Makefile (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_compatibility_test/ble_compatibility_test_case.md (98%) rename examples/bluetooth/{ => bluedroid/ble}/ble_compatibility_test/esp_ble_compatibility_test_report.md (99%) rename examples/bluetooth/{ => bluedroid/ble}/ble_compatibility_test/main/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_compatibility_test/main/ble_compatibility_test.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_compatibility_test/main/ble_compatibility_test.h (100%) rename examples/bluetooth/{ble_adv => bluedroid/ble/ble_compatibility_test}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_compatibility_test/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_eddystone/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_eddystone/Makefile (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_eddystone/README.md (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_eddystone/main/CMakeLists.txt (100%) rename examples/bluetooth/{ble_compatibility_test => bluedroid/ble/ble_eddystone}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_eddystone/main/esp_eddystone_api.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_eddystone/main/esp_eddystone_api.h (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_eddystone/main/esp_eddystone_demo.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_eddystone/main/esp_eddystone_protocol.h (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_eddystone/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_hid_device_demo/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_hid_device_demo/Makefile (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_hid_device_demo/README.md (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_hid_device_demo/main/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_hid_device_demo/main/ble_hidd_demo_main.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_hid_device_demo/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_hid_device_demo/main/esp_hidd_prf_api.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_hid_device_demo/main/esp_hidd_prf_api.h (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_hid_device_demo/main/hid_dev.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_hid_device_demo/main/hid_dev.h (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_hid_device_demo/main/hid_device_le_prf.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_hid_device_demo/main/hidd_le_prf_int.h (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_hid_device_demo/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_ibeacon/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_ibeacon/Makefile (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_ibeacon/README.md (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_ibeacon/main/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_ibeacon/main/Kconfig.projbuild (100%) rename examples/bluetooth/{ble_eddystone => bluedroid/ble/ble_ibeacon}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_ibeacon/main/esp_ibeacon_api.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_ibeacon/main/esp_ibeacon_api.h (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_ibeacon/main/ibeacon_demo.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_ibeacon/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_spp_client/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_spp_client/Makefile (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_spp_client/README.md (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_spp_client/main/CMakeLists.txt (100%) rename examples/bluetooth/{ble_ibeacon => bluedroid/ble/ble_spp_client}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_spp_client/main/spp_client_demo.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_spp_client/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_spp_server/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_spp_server/Makefile (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_spp_server/README.md (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_spp_server/main/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_spp_server/main/ble_spp_server_demo.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_spp_server/main/ble_spp_server_demo.h (100%) rename examples/bluetooth/{ble_mesh/ble_mesh_client_model => bluedroid/ble/ble_spp_server}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_spp_server/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_throughput/throughput_client/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_throughput/throughput_client/Makefile (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_throughput/throughput_client/README.md (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_throughput/throughput_client/main/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_throughput/throughput_client/main/Kconfig (100%) rename examples/bluetooth/{ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client => bluedroid/ble/ble_throughput/throughput_client}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_throughput/throughput_client/main/example_ble_client_throughput.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_throughput/throughput_client/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_throughput/throughput_server/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_throughput/throughput_server/Makefile (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_throughput/throughput_server/README.md (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_throughput/throughput_server/main/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_throughput/throughput_server/main/Kconfig (100%) rename examples/bluetooth/{ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server => bluedroid/ble/ble_throughput/throughput_server}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_throughput/throughput_server/main/example_ble_server_throughput.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_throughput/throughput_server/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/ble}/blufi/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/blufi/Makefile (100%) rename examples/bluetooth/{ => bluedroid/ble}/blufi/README.md (100%) rename examples/bluetooth/{ => bluedroid/ble}/blufi/main/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/blufi/main/blufi_example.h (100%) rename examples/bluetooth/{ => bluedroid/ble}/blufi/main/blufi_example_main.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/blufi/main/blufi_security.c (100%) rename examples/bluetooth/{ble_mesh/ble_mesh_node => bluedroid/ble/blufi}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/ble}/blufi/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_client/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_client/Makefile (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_client/README.md (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_client/main/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_client/main/Kconfig.projbuild (100%) rename examples/bluetooth/{ble_mesh/ble_mesh_provisioner => bluedroid/ble/gatt_client}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_client/main/gattc_demo.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_client/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md (98%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_security_client/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_security_client/Makefile (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_security_client/README.md (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_security_client/main/CMakeLists.txt (100%) rename examples/bluetooth/{ble_spp_client => bluedroid/ble/gatt_security_client}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_security_client/main/example_ble_sec_gattc_demo.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_security_client/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_security_client/tutorial/Gatt_Security_Client_Example_Walkthrough.md (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_security_server/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_security_server/Makefile (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_security_server/README.md (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_security_server/main/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_security_server/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_security_server/main/example_ble_sec_gatts_demo.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_security_server/main/example_ble_sec_gatts_demo.h (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_security_server/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_security_server/tutorial/Gatt_Security_Server_Example_Walkthrough.md (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_server/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_server/Makefile (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_server/README.md (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_server/main/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_server/main/Kconfig (100%) rename examples/bluetooth/{ble_spp_server => bluedroid/ble/gatt_server}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_server/main/gatts_demo.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_server/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_server/tutorial/Gatt_Server_Example_Walkthrough.md (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_server/tutorial/image/GATT_Server_Figure_1.png (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_server/tutorial/image/GATT_Server_Figure_2.png (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_server_service_table/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_server_service_table/Makefile (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_server_service_table/README.md (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_server_service_table/main/CMakeLists.txt (100%) rename examples/bluetooth/{ble_throughput/throughput_client => bluedroid/ble/gatt_server_service_table}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_server_service_table/main/gatts_table_creat_demo.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_server_service_table/main/gatts_table_creat_demo.h (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_server_service_table/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_server_service_table/tutorial/Gatt_Server_Service_Table_Example_Walkthrough.md (100%) rename examples/bluetooth/{ => bluedroid/ble}/gatt_server_service_table/tutorial/image/Heart_Rate_Service.png (100%) rename examples/bluetooth/{ => bluedroid/ble}/gattc_multi_connect/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/gattc_multi_connect/Makefile (100%) rename examples/bluetooth/{ => bluedroid/ble}/gattc_multi_connect/README.md (100%) rename examples/bluetooth/{ => bluedroid/ble}/gattc_multi_connect/main/CMakeLists.txt (100%) rename examples/bluetooth/{ble_throughput/throughput_server => bluedroid/ble/gattc_multi_connect}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/ble}/gattc_multi_connect/main/gattc_multi_connect.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/gattc_multi_connect/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/ble}/gattc_multi_connect/tutorial/Gatt_Client_Multi_Connection_Example_Walkthrough.md (99%) rename examples/bluetooth/{ => bluedroid/ble}/gattc_multi_connect/tutorial/image/ESP32_GATT_Multi_Connect_Client_Application_Profiles.png (100%) rename examples/bluetooth/{ => bluedroid/ble}/gattc_multi_connect/tutorial/image/Multi_Connection_GATT_Client_Flowchart.png (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/a2dp_sink/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/a2dp_sink/Makefile (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/a2dp_sink/README.md (100%) rename examples/bluetooth/{a2dp_gatts_coex => bluedroid/classic_bt/a2dp_sink}/main/CMakeLists.txt (100%) rename examples/bluetooth/{a2dp_gatts_coex => bluedroid/classic_bt/a2dp_sink}/main/Kconfig.projbuild (100%) rename examples/bluetooth/{a2dp_gatts_coex => bluedroid/classic_bt/a2dp_sink}/main/bt_app_av.c (100%) rename examples/bluetooth/{a2dp_gatts_coex => bluedroid/classic_bt/a2dp_sink}/main/bt_app_av.h (100%) rename examples/bluetooth/{a2dp_gatts_coex => bluedroid/classic_bt/a2dp_sink}/main/bt_app_core.c (100%) rename examples/bluetooth/{a2dp_gatts_coex => bluedroid/classic_bt/a2dp_sink}/main/bt_app_core.h (100%) rename examples/bluetooth/{a2dp_gatts_coex => bluedroid/classic_bt/a2dp_sink}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/a2dp_sink/main/main.c (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/a2dp_sink/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/a2dp_source/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/a2dp_source/Makefile (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/a2dp_source/README.md (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/a2dp_source/main/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/a2dp_source/main/bt_app_core.c (100%) rename examples/bluetooth/{a2dp_sink => bluedroid/classic_bt/a2dp_source}/main/bt_app_core.h (100%) rename examples/bluetooth/{a2dp_sink => bluedroid/classic_bt/a2dp_source}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/a2dp_source/main/main.c (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/a2dp_source/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_discovery/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_discovery/Makefile (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_discovery/README.rst (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_discovery/main/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_discovery/main/bt_discovery.c (100%) rename examples/bluetooth/{a2dp_source => bluedroid/classic_bt/bt_discovery}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_discovery/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_acceptor/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_acceptor/Makefile (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_acceptor/README.rst (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_acceptor/main/CMakeLists.txt (100%) rename examples/bluetooth/{blufi => bluedroid/classic_bt/bt_spp_acceptor}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_acceptor/main/example_spp_acceptor_demo.c (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_acceptor/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_initiator/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_initiator/Makefile (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_initiator/README.rst (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_initiator/main/CMakeLists.txt (100%) rename examples/bluetooth/{bt_spp_acceptor => bluedroid/classic_bt/bt_spp_initiator}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_initiator/main/example_spp_initiator_demo.c (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_initiator/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_vfs_acceptor/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_vfs_acceptor/Makefile (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_vfs_acceptor/README.rst (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_vfs_acceptor/main/CMakeLists.txt (100%) rename examples/bluetooth/{bt_spp_initiator => bluedroid/classic_bt/bt_spp_vfs_acceptor}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_vfs_acceptor/main/example_spp_vfs_acceptor_demo.c (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_vfs_acceptor/main/spp_task.c (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_vfs_acceptor/main/spp_task.h (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_vfs_acceptor/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_vfs_initiator/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_vfs_initiator/Makefile (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_vfs_initiator/README.rst (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_vfs_initiator/main/CMakeLists.txt (100%) rename examples/bluetooth/{bt_spp_vfs_acceptor => bluedroid/classic_bt/bt_spp_vfs_initiator}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_vfs_initiator/main/example_spp_vfs_initiator_demo.c (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_vfs_initiator/main/spp_task.c (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_vfs_initiator/main/spp_task.h (100%) rename examples/bluetooth/{ => bluedroid/classic_bt}/bt_spp_vfs_initiator/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/coex}/a2dp_gatts_coex/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/coex}/a2dp_gatts_coex/Makefile (100%) rename examples/bluetooth/{ => bluedroid/coex}/a2dp_gatts_coex/README.md (100%) rename examples/bluetooth/{a2dp_sink => bluedroid/coex/a2dp_gatts_coex}/main/CMakeLists.txt (100%) rename examples/bluetooth/{a2dp_sink => bluedroid/coex/a2dp_gatts_coex}/main/Kconfig.projbuild (100%) rename examples/bluetooth/{a2dp_sink => bluedroid/coex/a2dp_gatts_coex}/main/bt_app_av.c (100%) rename examples/bluetooth/{a2dp_sink => bluedroid/coex/a2dp_gatts_coex}/main/bt_app_av.h (100%) rename examples/bluetooth/{a2dp_sink => bluedroid/coex/a2dp_gatts_coex}/main/bt_app_core.c (100%) rename examples/bluetooth/{a2dp_source => bluedroid/coex/a2dp_gatts_coex}/main/bt_app_core.h (100%) rename examples/bluetooth/{ble_mesh/ble_mesh_console/ble_mesh_node => bluedroid/coex/a2dp_gatts_coex}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/coex}/a2dp_gatts_coex/main/main.c (100%) rename examples/bluetooth/{ => bluedroid/coex}/a2dp_gatts_coex/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/coex}/gattc_gatts_coex/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/coex}/gattc_gatts_coex/Makefile (100%) rename examples/bluetooth/{ => bluedroid/coex}/gattc_gatts_coex/README.md (100%) rename examples/bluetooth/{ => bluedroid/coex}/gattc_gatts_coex/main/CMakeLists.txt (100%) rename examples/bluetooth/{bt_spp_vfs_initiator => bluedroid/coex/gattc_gatts_coex}/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/coex}/gattc_gatts_coex/main/gattc_gatts_coex.c (100%) rename examples/bluetooth/{ => bluedroid/coex}/gattc_gatts_coex/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/hci}/controller_hci_uart/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/hci}/controller_hci_uart/Makefile (100%) rename examples/bluetooth/{ => bluedroid/hci}/controller_hci_uart/README.md (100%) rename examples/bluetooth/{ => bluedroid/hci}/controller_hci_uart/main/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/hci}/controller_hci_uart/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/hci}/controller_hci_uart/main/controller_hci_uart_demo.c (100%) rename examples/bluetooth/{ => bluedroid/hci}/controller_hci_uart/sdkconfig.defaults (100%) rename examples/bluetooth/{ble_adv => bluedroid/hci/controller_vhci_ble_adv}/CMakeLists.txt (100%) rename examples/bluetooth/{ble_adv => bluedroid/hci/controller_vhci_ble_adv}/Makefile (100%) rename examples/bluetooth/{ble_adv => bluedroid/hci/controller_vhci_ble_adv}/README.md (67%) rename examples/bluetooth/{ble_adv => bluedroid/hci/controller_vhci_ble_adv}/main/CMakeLists.txt (100%) rename examples/bluetooth/{ble_adv => bluedroid/hci/controller_vhci_ble_adv}/main/app_bt.c (100%) rename examples/bluetooth/{gatt_client => bluedroid/hci/controller_vhci_ble_adv}/main/component.mk (100%) rename examples/bluetooth/{ble_adv => bluedroid/hci/controller_vhci_ble_adv}/sdkconfig.defaults (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_client_model/CMakeLists.txt (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_client_model/Makefile (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_client_model/README.md (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_client_model/main/CMakeLists.txt (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_client_model/main/Kconfig.projbuild (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_client_model/main/ble_mesh_demo_main.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_client_model/main/board.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_client_model/main/board.h (100%) rename examples/bluetooth/{gatt_security_client => esp_ble_mesh/ble_mesh_client_model}/main/component.mk (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_client_model/sdkconfig.defaults (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_client_model/tutorial/ble_mesh_client_model.md (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_client_model/tutorial/images/app.png (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_client_model/tutorial/images/message.png (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_client_model/tutorial/images/picture5.png (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_node/CMakeLists.txt (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_node/Makefile (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_node/README.md (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_node/main/CMakeLists.txt (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.h (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.h (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_decl.h (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.h (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_system.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_server_cmd.c (100%) rename examples/bluetooth/{ble_mesh/ble_mesh_console/ble_mesh_provisioner => esp_ble_mesh/ble_mesh_console/ble_mesh_node}/main/component.mk (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_node/sdkconfig.defaults (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_provisioner/CMakeLists.txt (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_provisioner/Makefile (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_provisioner/README.md (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_provisioner/main/CMakeLists.txt (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.h (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.h (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_decl.h (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.h (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_system.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_cfg_client_cmd.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_gen_onoff_client_cmd.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_test_perf_client_cmd.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c (100%) rename examples/bluetooth/{bt_discovery => esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner}/main/component.mk (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_provisioner/main/register_bluetooth.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_console/ble_mesh_provisioner/sdkconfig.defaults (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_client/CMakeLists.txt (65%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_client/Makefile (66%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_client/README.md (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/CMakeLists.txt (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/ble_mesh_demo_main.c (100%) rename examples/bluetooth/{gatt_server => esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client}/main/component.mk (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_client/sdkconfig.defaults (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_client/tutorial/ble_mesh_fast_provision_client.md (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_server/CMakeLists.txt (65%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_server/Makefile (66%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_server/README.md (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/CMakeLists.txt (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/Kconfig.projbuild (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/ble_mesh_demo_main.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.h (100%) rename examples/bluetooth/{gatt_server_service_table => esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server}/main/component.mk (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_server/sdkconfig.defaults (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/EspBleMesh.md (95%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/ble_mesh_fast_provision_server.md (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/app_ble.png (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/device.png (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/picture1.png (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/picture2.png (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/time.png (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_node/CMakeLists.txt (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_node/Makefile (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_node/README.md (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_node/main/CMakeLists.txt (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_node/main/Kconfig.projbuild (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_node/main/ble_mesh_demo_main.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_node/main/board.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_node/main/board.h (100%) rename examples/bluetooth/{gattc_gatts_coex => esp_ble_mesh/ble_mesh_node}/main/component.mk (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_node/sdkconfig.defaults (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_node/tutorial/Ble_Mesh_Node_Example_Walkthrough.md (99%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_provisioner/CMakeLists.txt (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_provisioner/Makefile (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_provisioner/README.md (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_provisioner/main/CMakeLists.txt (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_provisioner/main/ble_mesh_demo_main.c (100%) rename examples/bluetooth/{gattc_multi_connect => esp_ble_mesh/ble_mesh_provisioner}/main/component.mk (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_provisioner/sdkconfig.defaults (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_provisioner/tutorial/Ble_Mesh_Provisioner_Example_Walkthrough.md (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_vendor_models/fast_prov_vendor_model/CMakeLists.txt (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_vendor_models/fast_prov_vendor_model/Makefile (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_vendor_models/fast_prov_vendor_model/components/CMakeLists.txt (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_vendor_models/fast_prov_vendor_model/components/component.mk (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.h (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_common.h (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.h (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.h (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_vendor_models/fast_prov_vendor_model/main/CMakeLists.txt (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_vendor_models/fast_prov_vendor_model/main/component.mk (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_vendor_models/fast_prov_vendor_model/main/main.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_vendor_models/fast_prov_vendor_model/sdkconfig.defaults (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_wifi_coexist/CMakeLists.txt (65%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_wifi_coexist/Makefile (65%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_wifi_coexist/README.md (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_wifi_coexist/components/iperf/CMakeLists.txt (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_wifi_coexist/components/iperf/cmd_decl.h (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_wifi_coexist/components/iperf/cmd_wifi.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_wifi_coexist/components/iperf/component.mk (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_wifi_coexist/components/iperf/iperf.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_wifi_coexist/components/iperf/iperf.h (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_wifi_coexist/main/CMakeLists.txt (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_wifi_coexist/main/Kconfig.projbuild (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_wifi_coexist/main/ble_mesh_demo_main.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_wifi_coexist/main/board.c (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_wifi_coexist/main/board.h (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_wifi_coexist/main/component.mk (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_wifi_coexist/partitions.csv (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_wifi_coexist/sdkconfig.defaults (100%) rename examples/bluetooth/{ble_mesh => esp_ble_mesh}/ble_mesh_wifi_coexist/tutorial/ble_mesh_wifi_coexist.md (99%) diff --git a/docs/en/api-reference/bluetooth/controller_vhci.rst b/docs/en/api-reference/bluetooth/controller_vhci.rst index 3db69ca027..abc037b662 100644 --- a/docs/en/api-reference/bluetooth/controller_vhci.rst +++ b/docs/en/api-reference/bluetooth/controller_vhci.rst @@ -11,9 +11,9 @@ Overview Application Example ------------------- -Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following application: +Check :example:`bluetooth/bluedroid/hci` folder in ESP-IDF examples, which contains the following application: -* This is a BLE advertising demo with virtual HCI interface. Send Reset/ADV_PARAM/ADV_DATA/ADV_ENABLE HCI command for BLE advertising - :example:`bluetooth/ble_adv`. +* This is a BLE advertising demo with virtual HCI interface. Send Reset/ADV_PARAM/ADV_DATA/ADV_ENABLE HCI command for BLE advertising - :example:`bluetooth/bluedroid/hci/controller_vhci_ble_adv`. API Reference ------------- diff --git a/docs/en/api-reference/bluetooth/esp_a2dp.rst b/docs/en/api-reference/bluetooth/esp_a2dp.rst index ee30b6debd..873c9405cc 100644 --- a/docs/en/api-reference/bluetooth/esp_a2dp.rst +++ b/docs/en/api-reference/bluetooth/esp_a2dp.rst @@ -11,9 +11,9 @@ Overview Application Example ------------------- -Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following application: +Check :example:`bluetooth/bluedroid/classic_bt` folder in ESP-IDF examples, which contains the following application: -* This is a A2DP sink client demo. This demo can be discovered and connected by A2DP source device and receive the audio stream from remote device - :example:`bluetooth/a2dp_sink` +* This is a A2DP sink client demo. This demo can be discovered and connected by A2DP source device and receive the audio stream from remote device - :example:`bluetooth/bluedroid/classic_bt/a2dp_sink` API Reference ------------- diff --git a/docs/en/api-reference/bluetooth/esp_blufi.rst b/docs/en/api-reference/bluetooth/esp_blufi.rst index a9c5c5e0e8..1f20ae16e8 100644 --- a/docs/en/api-reference/bluetooth/esp_blufi.rst +++ b/docs/en/api-reference/bluetooth/esp_blufi.rst @@ -12,9 +12,9 @@ Use should concern these things: Application Example ------------------- -Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following application: +Check :example:`bluetooth/bluedroid/ble` folder in ESP-IDF examples, which contains the following application: -* This is a BLUFI demo. This demo can set ESP32's wifi to softap/station/softap&station mode and config wifi connections - :example:`bluetooth/blufi` +* This is the BLUFI demo. This demo can set ESP32's wifi to softap/station/softap&station mode and config wifi connections - :example:`bluetooth/bluedroid/ble/blufi` API Reference ------------- diff --git a/docs/en/api-reference/bluetooth/esp_gap_ble.rst b/docs/en/api-reference/bluetooth/esp_gap_ble.rst index 6e69a0167e..b997daff7d 100644 --- a/docs/en/api-reference/bluetooth/esp_gap_ble.rst +++ b/docs/en/api-reference/bluetooth/esp_gap_ble.rst @@ -11,17 +11,17 @@ Overview Application Example ------------------- -Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following demos and their tutorials: +Check :example:`bluetooth/bluedroid/ble` folder in ESP-IDF examples, which contains the following demos and their tutorials: * This is a SMP security client demo and its tutorial. This demo initiates its security parameters and acts as a GATT client, which can send a security request to the peer device and then complete the encryption procedure. - - :example:`bluetooth/gatt_security_client` - - :example_file:`GATT Security Client Example Walkthrough ` + - :example:`bluetooth/bluedroid/ble/gatt_security_client` + - :example_file:`GATT Security Client Example Walkthrough ` * This is a SMP security server demo and its tutorial. This demo initiates its security parameters and acts as a GATT server, which can send a pair request to the peer device and then complete the encryption procedure. - - :example:`bluetooth/gatt_security_server` - - :example_file:`GATT Security Server Example Walkthrough ` + - :example:`bluetooth/bluedroid/ble/gatt_security_server` + - :example_file:`GATT Security Server Example Walkthrough ` API Reference ------------- diff --git a/docs/en/api-reference/bluetooth/esp_gattc.rst b/docs/en/api-reference/bluetooth/esp_gattc.rst index 450eda7021..90f9782b11 100644 --- a/docs/en/api-reference/bluetooth/esp_gattc.rst +++ b/docs/en/api-reference/bluetooth/esp_gattc.rst @@ -11,21 +11,21 @@ Overview Application Example ------------------- -Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following demos and their tutorials: +Check :example:`bluetooth/bluedroid/ble` folder in ESP-IDF examples, which contains the following demos and their tutorials: * This is a GATT client demo and its tutorial. This demo can scan for devices, connect to the GATT server and discover its services. - - :example:`bluetooth/gatt_client` - - :example_file:`GATT Client Example Walkthrough ` + - :example:`bluetooth/bluedroid/ble/gatt_client` + - :example_file:`GATT Client Example Walkthrough ` * This is a multiple connection demo and its tutorial. This demo can connect to multiple GATT server devices and discover their services. - - :example:`bluetooth/gattc_multi_connect` - - :example_file:`GATT Client Multi-connection Example Walkthrough ` + - :example:`bluetooth/bluedroid/ble/gattc_multi_connect` + - :example_file:`GATT Client Multi-connection Example Walkthrough ` * This is a BLE SPP-Like demo. This demo, which acts as a GATT client, can receive data from UART and then send the data to the peer device automatically. - - :example:`bluetooth/ble_spp_client` + - :example:`bluetooth/bluedroid/ble/ble_spp_client` API Reference ------------- diff --git a/docs/en/api-reference/bluetooth/esp_gatts.rst b/docs/en/api-reference/bluetooth/esp_gatts.rst index 78a1bc3bb2..7915a653d8 100644 --- a/docs/en/api-reference/bluetooth/esp_gatts.rst +++ b/docs/en/api-reference/bluetooth/esp_gatts.rst @@ -11,21 +11,21 @@ Overview Application Example ------------------- -Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following demos and their tutorials: +Check :example:`bluetooth/bluedroid/ble` folder in ESP-IDF examples, which contains the following demos and their tutorials: * This is a GATT sever demo and its tutorial. This demo creates a GATT service with an attribute table, which releases the user from adding attributes one by one. This is the recommended method of adding attributes. - - :example:`bluetooth/gatt_server_service_table` - - :example_file:`GATT Server Service Table Example Walkthrough ` + - :example:`bluetooth/bluedroid/ble/gatt_server_service_table` + - :example_file:`GATT Server Service Table Example Walkthrough ` * This is a GATT server demo and its tutorial. This demo creates a GATT service by adding attributes one by one as defined by Bluedroid. The recommended method of adding attributes is presented in example above. - - :example:`bluetooth/gatt_server` - - :example_file:`GATT Server Example Walkthrough ` + - :example:`bluetooth/bluedroid/ble/gatt_server` + - :example_file:`GATT Server Example Walkthrough ` * This is a BLE SPP-Like demo. This demo, which acts as a GATT server, can receive data from UART and then send the data to the peer device automatically. - - :example:`bluetooth/ble_spp_server` + - :example:`bluetooth/bluedroid/ble/ble_spp_server` API Reference ------------- diff --git a/docs/en/api-reference/bluetooth/esp_spp.rst b/docs/en/api-reference/bluetooth/esp_spp.rst index f686810f48..2a6a6acc51 100644 --- a/docs/en/api-reference/bluetooth/esp_spp.rst +++ b/docs/en/api-reference/bluetooth/esp_spp.rst @@ -11,9 +11,9 @@ Overview Application Example ------------------- -Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following application: +Check :example:`bluetooth/bluedroid/classic_bt` folder in ESP-IDF examples, which contains the following application: -* This is a SPP demo. This demo can discover the service, connect, send and recive SPP data :example:`bluetooth/bt_spp_acceptor`, :example:`bluetooth/bt_spp_initiator` +* This is a SPP demo. This demo can discover the service, connect, send and recive SPP data :example:`bluetooth/bluedroid/classic_bt/bt_spp_acceptor`, :example:`bluetooth/bluedroid/classic_bt/bt_spp_initiator` API Reference ------------- diff --git a/docs/en/api-reference/bluetooth/index.rst b/docs/en/api-reference/bluetooth/index.rst index b9e3ce2c53..da9f19d65c 100644 --- a/docs/en/api-reference/bluetooth/index.rst +++ b/docs/en/api-reference/bluetooth/index.rst @@ -22,13 +22,13 @@ For the overview of the ESP32 Bluetooth stack architecture, follow the links bel * `ESP32 Bluetooth Architecture (PDF) [English] `_ * `ESP32 Bluetooth Architecture (PDF) [中文] `_ -Code examples for this API section are provided in the :example:`bluetooth` directory of ESP-IDF examples. +Code examples for this API section are provided in the :example:`bluetooth/bluedroid` directory of ESP-IDF examples. The following examples contain detailed walkthroughs: -* :example_file:`GATT Client Example Walkthrough ` -* :example_file:`GATT Server Service Table Example Walkthrough ` -* :example_file:`GATT Server Example Walkthrough ` -* :example_file:`GATT Security Client Example Walkthrough ` -* :example_file:`GATT Security Server Example Walkthrough ` -* :example_file:`GATT Client Multi-connection Example Walkthrough ` +* :example_file:`GATT Client Example Walkthrough ` +* :example_file:`GATT Server Service Table Example Walkthrough ` +* :example_file:`GATT Server Example Walkthrough ` +* :example_file:`GATT Security Client Example Walkthrough ` +* :example_file:`GATT Security Server Example Walkthrough ` +* :example_file:`GATT Client Multi-connection Example Walkthrough ` diff --git a/docs/zh_CN/api-reference/bluetooth/index.rst b/docs/zh_CN/api-reference/bluetooth/index.rst index e8383b09ea..2ec48307f9 100644 --- a/docs/zh_CN/api-reference/bluetooth/index.rst +++ b/docs/zh_CN/api-reference/bluetooth/index.rst @@ -17,14 +17,14 @@ `ESP32 蓝牙架构 (PDF) `_ -蓝牙 API 的示例代码存放于 ESP-IDF :example:`bluetooth` 示例目录下,请查看。 +蓝牙 API 的示例代码存放于 ESP-IDF :example:`bluetooth/bluedroid` 示例目录下,请查看。 下面的示例给出了详细介绍: -* :example_file:`GATT 客户端示例 ` -* :example_file:`GATT 服务端服务表格示例 ` -* :example_file:`GATT 服务端示例 ` -* :example_file:`GATT 客户端安全性示例 ` -* :example_file:`GATT 服务端安全性示例 ` -* :example_file:`GATT 客户端多连接示例 ` +* :example_file:`GATT 客户端示例 ` +* :example_file:`GATT 服务端服务表格示例 ` +* :example_file:`GATT 服务端示例 ` +* :example_file:`GATT 客户端安全性示例 ` +* :example_file:`GATT 服务端安全性示例 ` +* :example_file:`GATT 客户端多连接示例 ` diff --git a/examples/README.md b/examples/README.md index 339115b12d..af04945bfd 100644 --- a/examples/README.md +++ b/examples/README.md @@ -6,8 +6,9 @@ This directory contains a range of example ESP-IDF projects. These are intended The examples are grouped into subdirectories by category. Each category directory contains one or more example projects: -* `bluetooth` contains Bluetooth (BLE & BT Classic) examples using default Bluedroid host stack. -* `bleutooth/nimble` contains BLE examples using NimBLE host stack +* `bluetooth/bluedroid` contains Classic BT, BLE and coex examples using default Bluedroid host stack. +* `bluetooth/nimble` contains BLE examples using NimBLE host stack. +* `bluetooth/esp_ble_mesh` contains ESP BLE Mesh examples. * `ethernet` contains Ethernet examples. * `get-started` contains some very simple examples with minimal functionality. * `mesh` contains Wi-Fi Mesh examples. diff --git a/examples/bluetooth/README.md b/examples/bluetooth/README.md deleted file mode 100644 index da38561428..0000000000 --- a/examples/bluetooth/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Bluetooth Examples - -Note: To use examples in this directory, you need to have Bluetooth enabled in configuration. Run `make menuconfig`, go to `Component config` and verify if you see `[*] Bluetooth`. If not - enable it and save. - -See the [README.md](../README.md) file in the upper level [examples](../) directory for more information about examples. diff --git a/examples/bluetooth/bluedroid/README.md b/examples/bluetooth/bluedroid/README.md new file mode 100644 index 0000000000..f7173737ba --- /dev/null +++ b/examples/bluetooth/bluedroid/README.md @@ -0,0 +1,13 @@ +# Bluetooth Examples for Bluedroid host + +Note: To use examples in this directory, you need to have Bluetooth enabled in configuration and Bluedroid selected as the host stack. + +# Example Layout + +The examples are grouped into subdirectories by category. Each category directory contains one or more example projects: +* `classic_bt` contains Classic BT examples +* `ble` contains BLE examples +* `coex` contains Classic BT and BLE coex examples +* `hci` contains HCI transport (VHCI and HCI UART) examples + +See the [README.md](../../README.md) file in the upper level [examples](../../) directory for more information about examples. diff --git a/examples/bluetooth/ble_compatibility_test/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_compatibility_test/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_compatibility_test/CMakeLists.txt diff --git a/examples/bluetooth/ble_compatibility_test/Makefile b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/Makefile similarity index 100% rename from examples/bluetooth/ble_compatibility_test/Makefile rename to examples/bluetooth/bluedroid/ble/ble_compatibility_test/Makefile diff --git a/examples/bluetooth/ble_compatibility_test/ble_compatibility_test_case.md b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/ble_compatibility_test_case.md similarity index 98% rename from examples/bluetooth/ble_compatibility_test/ble_compatibility_test_case.md rename to examples/bluetooth/bluedroid/ble/ble_compatibility_test/ble_compatibility_test_case.md index b0d544c1ab..84922d014b 100644 --- a/examples/bluetooth/ble_compatibility_test/ble_compatibility_test_case.md +++ b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/ble_compatibility_test_case.md @@ -6,7 +6,7 @@ This document provides a test case for BLE smartphone compatibility and includes ### What You Need -* ESP device which needs to flash [this test program] (https://github.com/espressif/esp-idf/blob/master/examples/bluetooth/ble_compatibility_test/main/ble_compatibility_test.c) +* ESP device which needs to flash [this test program] (https://github.com/espressif/esp-idf/blob/master/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.c) * Smartphone with LightBlue® Explorer app ### Initialization diff --git a/examples/bluetooth/ble_compatibility_test/esp_ble_compatibility_test_report.md b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/esp_ble_compatibility_test_report.md similarity index 99% rename from examples/bluetooth/ble_compatibility_test/esp_ble_compatibility_test_report.md rename to examples/bluetooth/bluedroid/ble/ble_compatibility_test/esp_ble_compatibility_test_report.md index a8ed4efac7..dd11e24290 100644 --- a/examples/bluetooth/ble_compatibility_test/esp_ble_compatibility_test_report.md +++ b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/esp_ble_compatibility_test_report.md @@ -12,7 +12,7 @@ Test Demo: - https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/ble_compatibility_test + https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/bluedroid/ble/ble_compatibility_test Phone Brand diff --git a/examples/bluetooth/ble_compatibility_test/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_compatibility_test/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_compatibility_test/main/ble_compatibility_test.c b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.c similarity index 100% rename from examples/bluetooth/ble_compatibility_test/main/ble_compatibility_test.c rename to examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.c diff --git a/examples/bluetooth/ble_compatibility_test/main/ble_compatibility_test.h b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.h similarity index 100% rename from examples/bluetooth/ble_compatibility_test/main/ble_compatibility_test.h rename to examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.h diff --git a/examples/bluetooth/ble_adv/main/component.mk b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/component.mk similarity index 100% rename from examples/bluetooth/ble_adv/main/component.mk rename to examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/component.mk diff --git a/examples/bluetooth/ble_compatibility_test/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_compatibility_test/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/ble_compatibility_test/sdkconfig.defaults diff --git a/examples/bluetooth/ble_eddystone/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_eddystone/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_eddystone/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_eddystone/CMakeLists.txt diff --git a/examples/bluetooth/ble_eddystone/Makefile b/examples/bluetooth/bluedroid/ble/ble_eddystone/Makefile similarity index 100% rename from examples/bluetooth/ble_eddystone/Makefile rename to examples/bluetooth/bluedroid/ble/ble_eddystone/Makefile diff --git a/examples/bluetooth/ble_eddystone/README.md b/examples/bluetooth/bluedroid/ble/ble_eddystone/README.md similarity index 100% rename from examples/bluetooth/ble_eddystone/README.md rename to examples/bluetooth/bluedroid/ble/ble_eddystone/README.md diff --git a/examples/bluetooth/ble_eddystone/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_eddystone/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_eddystone/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_eddystone/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_compatibility_test/main/component.mk b/examples/bluetooth/bluedroid/ble/ble_eddystone/main/component.mk similarity index 100% rename from examples/bluetooth/ble_compatibility_test/main/component.mk rename to examples/bluetooth/bluedroid/ble/ble_eddystone/main/component.mk diff --git a/examples/bluetooth/ble_eddystone/main/esp_eddystone_api.c b/examples/bluetooth/bluedroid/ble/ble_eddystone/main/esp_eddystone_api.c similarity index 100% rename from examples/bluetooth/ble_eddystone/main/esp_eddystone_api.c rename to examples/bluetooth/bluedroid/ble/ble_eddystone/main/esp_eddystone_api.c diff --git a/examples/bluetooth/ble_eddystone/main/esp_eddystone_api.h b/examples/bluetooth/bluedroid/ble/ble_eddystone/main/esp_eddystone_api.h similarity index 100% rename from examples/bluetooth/ble_eddystone/main/esp_eddystone_api.h rename to examples/bluetooth/bluedroid/ble/ble_eddystone/main/esp_eddystone_api.h diff --git a/examples/bluetooth/ble_eddystone/main/esp_eddystone_demo.c b/examples/bluetooth/bluedroid/ble/ble_eddystone/main/esp_eddystone_demo.c similarity index 100% rename from examples/bluetooth/ble_eddystone/main/esp_eddystone_demo.c rename to examples/bluetooth/bluedroid/ble/ble_eddystone/main/esp_eddystone_demo.c diff --git a/examples/bluetooth/ble_eddystone/main/esp_eddystone_protocol.h b/examples/bluetooth/bluedroid/ble/ble_eddystone/main/esp_eddystone_protocol.h similarity index 100% rename from examples/bluetooth/ble_eddystone/main/esp_eddystone_protocol.h rename to examples/bluetooth/bluedroid/ble/ble_eddystone/main/esp_eddystone_protocol.h diff --git a/examples/bluetooth/ble_eddystone/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/ble_eddystone/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_eddystone/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/ble_eddystone/sdkconfig.defaults diff --git a/examples/bluetooth/ble_hid_device_demo/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/CMakeLists.txt diff --git a/examples/bluetooth/ble_hid_device_demo/Makefile b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/Makefile similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/Makefile rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/Makefile diff --git a/examples/bluetooth/ble_hid_device_demo/README.md b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/README.md similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/README.md rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/README.md diff --git a/examples/bluetooth/ble_hid_device_demo/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_hid_device_demo/main/ble_hidd_demo_main.c b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/ble_hidd_demo_main.c similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/main/ble_hidd_demo_main.c rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/ble_hidd_demo_main.c diff --git a/examples/bluetooth/ble_hid_device_demo/main/component.mk b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/component.mk similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/main/component.mk rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/component.mk diff --git a/examples/bluetooth/ble_hid_device_demo/main/esp_hidd_prf_api.c b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/esp_hidd_prf_api.c similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/main/esp_hidd_prf_api.c rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/esp_hidd_prf_api.c diff --git a/examples/bluetooth/ble_hid_device_demo/main/esp_hidd_prf_api.h b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/esp_hidd_prf_api.h similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/main/esp_hidd_prf_api.h rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/esp_hidd_prf_api.h diff --git a/examples/bluetooth/ble_hid_device_demo/main/hid_dev.c b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/hid_dev.c similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/main/hid_dev.c rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/hid_dev.c diff --git a/examples/bluetooth/ble_hid_device_demo/main/hid_dev.h b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/hid_dev.h similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/main/hid_dev.h rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/hid_dev.h diff --git a/examples/bluetooth/ble_hid_device_demo/main/hid_device_le_prf.c b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/hid_device_le_prf.c similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/main/hid_device_le_prf.c rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/hid_device_le_prf.c diff --git a/examples/bluetooth/ble_hid_device_demo/main/hidd_le_prf_int.h b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/hidd_le_prf_int.h similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/main/hidd_le_prf_int.h rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/hidd_le_prf_int.h diff --git a/examples/bluetooth/ble_hid_device_demo/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/sdkconfig.defaults diff --git a/examples/bluetooth/ble_ibeacon/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_ibeacon/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_ibeacon/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_ibeacon/CMakeLists.txt diff --git a/examples/bluetooth/ble_ibeacon/Makefile b/examples/bluetooth/bluedroid/ble/ble_ibeacon/Makefile similarity index 100% rename from examples/bluetooth/ble_ibeacon/Makefile rename to examples/bluetooth/bluedroid/ble/ble_ibeacon/Makefile diff --git a/examples/bluetooth/ble_ibeacon/README.md b/examples/bluetooth/bluedroid/ble/ble_ibeacon/README.md similarity index 100% rename from examples/bluetooth/ble_ibeacon/README.md rename to examples/bluetooth/bluedroid/ble/ble_ibeacon/README.md diff --git a/examples/bluetooth/ble_ibeacon/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_ibeacon/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_ibeacon/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_ibeacon/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_ibeacon/main/Kconfig.projbuild b/examples/bluetooth/bluedroid/ble/ble_ibeacon/main/Kconfig.projbuild similarity index 100% rename from examples/bluetooth/ble_ibeacon/main/Kconfig.projbuild rename to examples/bluetooth/bluedroid/ble/ble_ibeacon/main/Kconfig.projbuild diff --git a/examples/bluetooth/ble_eddystone/main/component.mk b/examples/bluetooth/bluedroid/ble/ble_ibeacon/main/component.mk similarity index 100% rename from examples/bluetooth/ble_eddystone/main/component.mk rename to examples/bluetooth/bluedroid/ble/ble_ibeacon/main/component.mk diff --git a/examples/bluetooth/ble_ibeacon/main/esp_ibeacon_api.c b/examples/bluetooth/bluedroid/ble/ble_ibeacon/main/esp_ibeacon_api.c similarity index 100% rename from examples/bluetooth/ble_ibeacon/main/esp_ibeacon_api.c rename to examples/bluetooth/bluedroid/ble/ble_ibeacon/main/esp_ibeacon_api.c diff --git a/examples/bluetooth/ble_ibeacon/main/esp_ibeacon_api.h b/examples/bluetooth/bluedroid/ble/ble_ibeacon/main/esp_ibeacon_api.h similarity index 100% rename from examples/bluetooth/ble_ibeacon/main/esp_ibeacon_api.h rename to examples/bluetooth/bluedroid/ble/ble_ibeacon/main/esp_ibeacon_api.h diff --git a/examples/bluetooth/ble_ibeacon/main/ibeacon_demo.c b/examples/bluetooth/bluedroid/ble/ble_ibeacon/main/ibeacon_demo.c similarity index 100% rename from examples/bluetooth/ble_ibeacon/main/ibeacon_demo.c rename to examples/bluetooth/bluedroid/ble/ble_ibeacon/main/ibeacon_demo.c diff --git a/examples/bluetooth/ble_ibeacon/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/ble_ibeacon/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_ibeacon/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/ble_ibeacon/sdkconfig.defaults diff --git a/examples/bluetooth/ble_spp_client/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_spp_client/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_spp_client/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_spp_client/CMakeLists.txt diff --git a/examples/bluetooth/ble_spp_client/Makefile b/examples/bluetooth/bluedroid/ble/ble_spp_client/Makefile similarity index 100% rename from examples/bluetooth/ble_spp_client/Makefile rename to examples/bluetooth/bluedroid/ble/ble_spp_client/Makefile diff --git a/examples/bluetooth/ble_spp_client/README.md b/examples/bluetooth/bluedroid/ble/ble_spp_client/README.md similarity index 100% rename from examples/bluetooth/ble_spp_client/README.md rename to examples/bluetooth/bluedroid/ble/ble_spp_client/README.md diff --git a/examples/bluetooth/ble_spp_client/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_spp_client/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_spp_client/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_spp_client/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_ibeacon/main/component.mk b/examples/bluetooth/bluedroid/ble/ble_spp_client/main/component.mk similarity index 100% rename from examples/bluetooth/ble_ibeacon/main/component.mk rename to examples/bluetooth/bluedroid/ble/ble_spp_client/main/component.mk diff --git a/examples/bluetooth/ble_spp_client/main/spp_client_demo.c b/examples/bluetooth/bluedroid/ble/ble_spp_client/main/spp_client_demo.c similarity index 100% rename from examples/bluetooth/ble_spp_client/main/spp_client_demo.c rename to examples/bluetooth/bluedroid/ble/ble_spp_client/main/spp_client_demo.c diff --git a/examples/bluetooth/ble_spp_client/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/ble_spp_client/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_spp_client/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/ble_spp_client/sdkconfig.defaults diff --git a/examples/bluetooth/ble_spp_server/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_spp_server/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_spp_server/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_spp_server/CMakeLists.txt diff --git a/examples/bluetooth/ble_spp_server/Makefile b/examples/bluetooth/bluedroid/ble/ble_spp_server/Makefile similarity index 100% rename from examples/bluetooth/ble_spp_server/Makefile rename to examples/bluetooth/bluedroid/ble/ble_spp_server/Makefile diff --git a/examples/bluetooth/ble_spp_server/README.md b/examples/bluetooth/bluedroid/ble/ble_spp_server/README.md similarity index 100% rename from examples/bluetooth/ble_spp_server/README.md rename to examples/bluetooth/bluedroid/ble/ble_spp_server/README.md diff --git a/examples/bluetooth/ble_spp_server/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_spp_server/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_spp_server/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_spp_server/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_spp_server/main/ble_spp_server_demo.c b/examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.c similarity index 100% rename from examples/bluetooth/ble_spp_server/main/ble_spp_server_demo.c rename to examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.c diff --git a/examples/bluetooth/ble_spp_server/main/ble_spp_server_demo.h b/examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.h similarity index 100% rename from examples/bluetooth/ble_spp_server/main/ble_spp_server_demo.h rename to examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.h diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/component.mk b/examples/bluetooth/bluedroid/ble/ble_spp_server/main/component.mk similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_client_model/main/component.mk rename to examples/bluetooth/bluedroid/ble/ble_spp_server/main/component.mk diff --git a/examples/bluetooth/ble_spp_server/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/ble_spp_server/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_spp_server/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/ble_spp_server/sdkconfig.defaults diff --git a/examples/bluetooth/ble_throughput/throughput_client/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_client/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/CMakeLists.txt diff --git a/examples/bluetooth/ble_throughput/throughput_client/Makefile b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/Makefile similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_client/Makefile rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/Makefile diff --git a/examples/bluetooth/ble_throughput/throughput_client/README.md b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/README.md similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_client/README.md rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/README.md diff --git a/examples/bluetooth/ble_throughput/throughput_client/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_client/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_throughput/throughput_client/main/Kconfig b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/main/Kconfig similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_client/main/Kconfig rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/main/Kconfig diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/component.mk b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/main/component.mk similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/component.mk rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/main/component.mk diff --git a/examples/bluetooth/ble_throughput/throughput_client/main/example_ble_client_throughput.c b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/main/example_ble_client_throughput.c similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_client/main/example_ble_client_throughput.c rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/main/example_ble_client_throughput.c diff --git a/examples/bluetooth/ble_throughput/throughput_client/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_client/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/sdkconfig.defaults diff --git a/examples/bluetooth/ble_throughput/throughput_server/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_server/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/CMakeLists.txt diff --git a/examples/bluetooth/ble_throughput/throughput_server/Makefile b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/Makefile similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_server/Makefile rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/Makefile diff --git a/examples/bluetooth/ble_throughput/throughput_server/README.md b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/README.md similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_server/README.md rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/README.md diff --git a/examples/bluetooth/ble_throughput/throughput_server/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_server/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_throughput/throughput_server/main/Kconfig b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/main/Kconfig similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_server/main/Kconfig rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/main/Kconfig diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/component.mk b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/main/component.mk similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/component.mk rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/main/component.mk diff --git a/examples/bluetooth/ble_throughput/throughput_server/main/example_ble_server_throughput.c b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/main/example_ble_server_throughput.c similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_server/main/example_ble_server_throughput.c rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/main/example_ble_server_throughput.c diff --git a/examples/bluetooth/ble_throughput/throughput_server/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_server/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/sdkconfig.defaults diff --git a/examples/bluetooth/blufi/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/blufi/CMakeLists.txt similarity index 100% rename from examples/bluetooth/blufi/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/blufi/CMakeLists.txt diff --git a/examples/bluetooth/blufi/Makefile b/examples/bluetooth/bluedroid/ble/blufi/Makefile similarity index 100% rename from examples/bluetooth/blufi/Makefile rename to examples/bluetooth/bluedroid/ble/blufi/Makefile diff --git a/examples/bluetooth/blufi/README.md b/examples/bluetooth/bluedroid/ble/blufi/README.md similarity index 100% rename from examples/bluetooth/blufi/README.md rename to examples/bluetooth/bluedroid/ble/blufi/README.md diff --git a/examples/bluetooth/blufi/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/blufi/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/blufi/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/blufi/main/CMakeLists.txt diff --git a/examples/bluetooth/blufi/main/blufi_example.h b/examples/bluetooth/bluedroid/ble/blufi/main/blufi_example.h similarity index 100% rename from examples/bluetooth/blufi/main/blufi_example.h rename to examples/bluetooth/bluedroid/ble/blufi/main/blufi_example.h diff --git a/examples/bluetooth/blufi/main/blufi_example_main.c b/examples/bluetooth/bluedroid/ble/blufi/main/blufi_example_main.c similarity index 100% rename from examples/bluetooth/blufi/main/blufi_example_main.c rename to examples/bluetooth/bluedroid/ble/blufi/main/blufi_example_main.c diff --git a/examples/bluetooth/blufi/main/blufi_security.c b/examples/bluetooth/bluedroid/ble/blufi/main/blufi_security.c similarity index 100% rename from examples/bluetooth/blufi/main/blufi_security.c rename to examples/bluetooth/bluedroid/ble/blufi/main/blufi_security.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_node/main/component.mk b/examples/bluetooth/bluedroid/ble/blufi/main/component.mk similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_node/main/component.mk rename to examples/bluetooth/bluedroid/ble/blufi/main/component.mk diff --git a/examples/bluetooth/blufi/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/blufi/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/blufi/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/blufi/sdkconfig.defaults diff --git a/examples/bluetooth/gatt_client/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gatt_client/CMakeLists.txt similarity index 100% rename from examples/bluetooth/gatt_client/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/gatt_client/CMakeLists.txt diff --git a/examples/bluetooth/gatt_client/Makefile b/examples/bluetooth/bluedroid/ble/gatt_client/Makefile similarity index 100% rename from examples/bluetooth/gatt_client/Makefile rename to examples/bluetooth/bluedroid/ble/gatt_client/Makefile diff --git a/examples/bluetooth/gatt_client/README.md b/examples/bluetooth/bluedroid/ble/gatt_client/README.md similarity index 100% rename from examples/bluetooth/gatt_client/README.md rename to examples/bluetooth/bluedroid/ble/gatt_client/README.md diff --git a/examples/bluetooth/gatt_client/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gatt_client/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/gatt_client/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/gatt_client/main/CMakeLists.txt diff --git a/examples/bluetooth/gatt_client/main/Kconfig.projbuild b/examples/bluetooth/bluedroid/ble/gatt_client/main/Kconfig.projbuild similarity index 100% rename from examples/bluetooth/gatt_client/main/Kconfig.projbuild rename to examples/bluetooth/bluedroid/ble/gatt_client/main/Kconfig.projbuild diff --git a/examples/bluetooth/ble_mesh/ble_mesh_provisioner/main/component.mk b/examples/bluetooth/bluedroid/ble/gatt_client/main/component.mk similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_provisioner/main/component.mk rename to examples/bluetooth/bluedroid/ble/gatt_client/main/component.mk diff --git a/examples/bluetooth/gatt_client/main/gattc_demo.c b/examples/bluetooth/bluedroid/ble/gatt_client/main/gattc_demo.c similarity index 100% rename from examples/bluetooth/gatt_client/main/gattc_demo.c rename to examples/bluetooth/bluedroid/ble/gatt_client/main/gattc_demo.c diff --git a/examples/bluetooth/gatt_client/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/gatt_client/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/gatt_client/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/gatt_client/sdkconfig.defaults diff --git a/examples/bluetooth/gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md b/examples/bluetooth/bluedroid/ble/gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md similarity index 98% rename from examples/bluetooth/gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md rename to examples/bluetooth/bluedroid/ble/gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md index 2ed2c86b5e..44cb2af8df 100644 --- a/examples/bluetooth/gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md +++ b/examples/bluetooth/bluedroid/ble/gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md @@ -6,7 +6,7 @@ In this tutorial, the GATT client example code for the ESP32 is reviewed. The co # Includes -This example is located in the examples folder of the ESP-IDF under the [bluetooth/gatt_client/main](../main). The [gattc_demo.c](../main/gattc_demo.c) file located in the main folder contains all the functionality that we are going to review. The header files contained in [gattc_demo.c](../main/gattc_demo.c) are: +This example is located in the examples folder of the ESP-IDF under the [bluetooth/bluedroid/ble/gatt_client/main](../main). The [gattc_demo.c](../main/gattc_demo.c) file located in the main folder contains all the functionality that we are going to review. The header files contained in [gattc_demo.c](../main/gattc_demo.c) are: ```c #include @@ -511,7 +511,7 @@ In case that the client finds the service that it is looking for, the flag get_s ## Getting Characteristics -This examples implements getting characteristic data from a predefined service. The service that we want the characteristics from has an UUID of 0x00FF, and the characteristic we are interested in has an UUID of 0xFF01: +This example implements getting characteristic data from a predefined service. The service that we want the characteristics from has an UUID of 0x00FF, and the characteristic we are interested in has an UUID of 0xFF01: ```c #define REMOTE_NOTIFY_CHAR_UUID 0xFF01 diff --git a/examples/bluetooth/gatt_security_client/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gatt_security_client/CMakeLists.txt similarity index 100% rename from examples/bluetooth/gatt_security_client/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/gatt_security_client/CMakeLists.txt diff --git a/examples/bluetooth/gatt_security_client/Makefile b/examples/bluetooth/bluedroid/ble/gatt_security_client/Makefile similarity index 100% rename from examples/bluetooth/gatt_security_client/Makefile rename to examples/bluetooth/bluedroid/ble/gatt_security_client/Makefile diff --git a/examples/bluetooth/gatt_security_client/README.md b/examples/bluetooth/bluedroid/ble/gatt_security_client/README.md similarity index 100% rename from examples/bluetooth/gatt_security_client/README.md rename to examples/bluetooth/bluedroid/ble/gatt_security_client/README.md diff --git a/examples/bluetooth/gatt_security_client/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gatt_security_client/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/gatt_security_client/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/gatt_security_client/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_spp_client/main/component.mk b/examples/bluetooth/bluedroid/ble/gatt_security_client/main/component.mk similarity index 100% rename from examples/bluetooth/ble_spp_client/main/component.mk rename to examples/bluetooth/bluedroid/ble/gatt_security_client/main/component.mk diff --git a/examples/bluetooth/gatt_security_client/main/example_ble_sec_gattc_demo.c b/examples/bluetooth/bluedroid/ble/gatt_security_client/main/example_ble_sec_gattc_demo.c similarity index 100% rename from examples/bluetooth/gatt_security_client/main/example_ble_sec_gattc_demo.c rename to examples/bluetooth/bluedroid/ble/gatt_security_client/main/example_ble_sec_gattc_demo.c diff --git a/examples/bluetooth/gatt_security_client/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/gatt_security_client/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/gatt_security_client/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/gatt_security_client/sdkconfig.defaults diff --git a/examples/bluetooth/gatt_security_client/tutorial/Gatt_Security_Client_Example_Walkthrough.md b/examples/bluetooth/bluedroid/ble/gatt_security_client/tutorial/Gatt_Security_Client_Example_Walkthrough.md similarity index 100% rename from examples/bluetooth/gatt_security_client/tutorial/Gatt_Security_Client_Example_Walkthrough.md rename to examples/bluetooth/bluedroid/ble/gatt_security_client/tutorial/Gatt_Security_Client_Example_Walkthrough.md diff --git a/examples/bluetooth/gatt_security_server/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gatt_security_server/CMakeLists.txt similarity index 100% rename from examples/bluetooth/gatt_security_server/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/gatt_security_server/CMakeLists.txt diff --git a/examples/bluetooth/gatt_security_server/Makefile b/examples/bluetooth/bluedroid/ble/gatt_security_server/Makefile similarity index 100% rename from examples/bluetooth/gatt_security_server/Makefile rename to examples/bluetooth/bluedroid/ble/gatt_security_server/Makefile diff --git a/examples/bluetooth/gatt_security_server/README.md b/examples/bluetooth/bluedroid/ble/gatt_security_server/README.md similarity index 100% rename from examples/bluetooth/gatt_security_server/README.md rename to examples/bluetooth/bluedroid/ble/gatt_security_server/README.md diff --git a/examples/bluetooth/gatt_security_server/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gatt_security_server/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/gatt_security_server/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/gatt_security_server/main/CMakeLists.txt diff --git a/examples/bluetooth/gatt_security_server/main/component.mk b/examples/bluetooth/bluedroid/ble/gatt_security_server/main/component.mk similarity index 100% rename from examples/bluetooth/gatt_security_server/main/component.mk rename to examples/bluetooth/bluedroid/ble/gatt_security_server/main/component.mk diff --git a/examples/bluetooth/gatt_security_server/main/example_ble_sec_gatts_demo.c b/examples/bluetooth/bluedroid/ble/gatt_security_server/main/example_ble_sec_gatts_demo.c similarity index 100% rename from examples/bluetooth/gatt_security_server/main/example_ble_sec_gatts_demo.c rename to examples/bluetooth/bluedroid/ble/gatt_security_server/main/example_ble_sec_gatts_demo.c diff --git a/examples/bluetooth/gatt_security_server/main/example_ble_sec_gatts_demo.h b/examples/bluetooth/bluedroid/ble/gatt_security_server/main/example_ble_sec_gatts_demo.h similarity index 100% rename from examples/bluetooth/gatt_security_server/main/example_ble_sec_gatts_demo.h rename to examples/bluetooth/bluedroid/ble/gatt_security_server/main/example_ble_sec_gatts_demo.h diff --git a/examples/bluetooth/gatt_security_server/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/gatt_security_server/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/gatt_security_server/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/gatt_security_server/sdkconfig.defaults diff --git a/examples/bluetooth/gatt_security_server/tutorial/Gatt_Security_Server_Example_Walkthrough.md b/examples/bluetooth/bluedroid/ble/gatt_security_server/tutorial/Gatt_Security_Server_Example_Walkthrough.md similarity index 100% rename from examples/bluetooth/gatt_security_server/tutorial/Gatt_Security_Server_Example_Walkthrough.md rename to examples/bluetooth/bluedroid/ble/gatt_security_server/tutorial/Gatt_Security_Server_Example_Walkthrough.md diff --git a/examples/bluetooth/gatt_server/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gatt_server/CMakeLists.txt similarity index 100% rename from examples/bluetooth/gatt_server/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/gatt_server/CMakeLists.txt diff --git a/examples/bluetooth/gatt_server/Makefile b/examples/bluetooth/bluedroid/ble/gatt_server/Makefile similarity index 100% rename from examples/bluetooth/gatt_server/Makefile rename to examples/bluetooth/bluedroid/ble/gatt_server/Makefile diff --git a/examples/bluetooth/gatt_server/README.md b/examples/bluetooth/bluedroid/ble/gatt_server/README.md similarity index 100% rename from examples/bluetooth/gatt_server/README.md rename to examples/bluetooth/bluedroid/ble/gatt_server/README.md diff --git a/examples/bluetooth/gatt_server/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gatt_server/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/gatt_server/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/gatt_server/main/CMakeLists.txt diff --git a/examples/bluetooth/gatt_server/main/Kconfig b/examples/bluetooth/bluedroid/ble/gatt_server/main/Kconfig similarity index 100% rename from examples/bluetooth/gatt_server/main/Kconfig rename to examples/bluetooth/bluedroid/ble/gatt_server/main/Kconfig diff --git a/examples/bluetooth/ble_spp_server/main/component.mk b/examples/bluetooth/bluedroid/ble/gatt_server/main/component.mk similarity index 100% rename from examples/bluetooth/ble_spp_server/main/component.mk rename to examples/bluetooth/bluedroid/ble/gatt_server/main/component.mk diff --git a/examples/bluetooth/gatt_server/main/gatts_demo.c b/examples/bluetooth/bluedroid/ble/gatt_server/main/gatts_demo.c similarity index 100% rename from examples/bluetooth/gatt_server/main/gatts_demo.c rename to examples/bluetooth/bluedroid/ble/gatt_server/main/gatts_demo.c diff --git a/examples/bluetooth/gatt_server/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/gatt_server/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/gatt_server/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/gatt_server/sdkconfig.defaults diff --git a/examples/bluetooth/gatt_server/tutorial/Gatt_Server_Example_Walkthrough.md b/examples/bluetooth/bluedroid/ble/gatt_server/tutorial/Gatt_Server_Example_Walkthrough.md similarity index 100% rename from examples/bluetooth/gatt_server/tutorial/Gatt_Server_Example_Walkthrough.md rename to examples/bluetooth/bluedroid/ble/gatt_server/tutorial/Gatt_Server_Example_Walkthrough.md diff --git a/examples/bluetooth/gatt_server/tutorial/image/GATT_Server_Figure_1.png b/examples/bluetooth/bluedroid/ble/gatt_server/tutorial/image/GATT_Server_Figure_1.png similarity index 100% rename from examples/bluetooth/gatt_server/tutorial/image/GATT_Server_Figure_1.png rename to examples/bluetooth/bluedroid/ble/gatt_server/tutorial/image/GATT_Server_Figure_1.png diff --git a/examples/bluetooth/gatt_server/tutorial/image/GATT_Server_Figure_2.png b/examples/bluetooth/bluedroid/ble/gatt_server/tutorial/image/GATT_Server_Figure_2.png similarity index 100% rename from examples/bluetooth/gatt_server/tutorial/image/GATT_Server_Figure_2.png rename to examples/bluetooth/bluedroid/ble/gatt_server/tutorial/image/GATT_Server_Figure_2.png diff --git a/examples/bluetooth/gatt_server_service_table/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gatt_server_service_table/CMakeLists.txt similarity index 100% rename from examples/bluetooth/gatt_server_service_table/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/gatt_server_service_table/CMakeLists.txt diff --git a/examples/bluetooth/gatt_server_service_table/Makefile b/examples/bluetooth/bluedroid/ble/gatt_server_service_table/Makefile similarity index 100% rename from examples/bluetooth/gatt_server_service_table/Makefile rename to examples/bluetooth/bluedroid/ble/gatt_server_service_table/Makefile diff --git a/examples/bluetooth/gatt_server_service_table/README.md b/examples/bluetooth/bluedroid/ble/gatt_server_service_table/README.md similarity index 100% rename from examples/bluetooth/gatt_server_service_table/README.md rename to examples/bluetooth/bluedroid/ble/gatt_server_service_table/README.md diff --git a/examples/bluetooth/gatt_server_service_table/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gatt_server_service_table/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/gatt_server_service_table/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/gatt_server_service_table/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_throughput/throughput_client/main/component.mk b/examples/bluetooth/bluedroid/ble/gatt_server_service_table/main/component.mk similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_client/main/component.mk rename to examples/bluetooth/bluedroid/ble/gatt_server_service_table/main/component.mk diff --git a/examples/bluetooth/gatt_server_service_table/main/gatts_table_creat_demo.c b/examples/bluetooth/bluedroid/ble/gatt_server_service_table/main/gatts_table_creat_demo.c similarity index 100% rename from examples/bluetooth/gatt_server_service_table/main/gatts_table_creat_demo.c rename to examples/bluetooth/bluedroid/ble/gatt_server_service_table/main/gatts_table_creat_demo.c diff --git a/examples/bluetooth/gatt_server_service_table/main/gatts_table_creat_demo.h b/examples/bluetooth/bluedroid/ble/gatt_server_service_table/main/gatts_table_creat_demo.h similarity index 100% rename from examples/bluetooth/gatt_server_service_table/main/gatts_table_creat_demo.h rename to examples/bluetooth/bluedroid/ble/gatt_server_service_table/main/gatts_table_creat_demo.h diff --git a/examples/bluetooth/gatt_server_service_table/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/gatt_server_service_table/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/gatt_server_service_table/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/gatt_server_service_table/sdkconfig.defaults diff --git a/examples/bluetooth/gatt_server_service_table/tutorial/Gatt_Server_Service_Table_Example_Walkthrough.md b/examples/bluetooth/bluedroid/ble/gatt_server_service_table/tutorial/Gatt_Server_Service_Table_Example_Walkthrough.md similarity index 100% rename from examples/bluetooth/gatt_server_service_table/tutorial/Gatt_Server_Service_Table_Example_Walkthrough.md rename to examples/bluetooth/bluedroid/ble/gatt_server_service_table/tutorial/Gatt_Server_Service_Table_Example_Walkthrough.md diff --git a/examples/bluetooth/gatt_server_service_table/tutorial/image/Heart_Rate_Service.png b/examples/bluetooth/bluedroid/ble/gatt_server_service_table/tutorial/image/Heart_Rate_Service.png similarity index 100% rename from examples/bluetooth/gatt_server_service_table/tutorial/image/Heart_Rate_Service.png rename to examples/bluetooth/bluedroid/ble/gatt_server_service_table/tutorial/image/Heart_Rate_Service.png diff --git a/examples/bluetooth/gattc_multi_connect/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/CMakeLists.txt similarity index 100% rename from examples/bluetooth/gattc_multi_connect/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/gattc_multi_connect/CMakeLists.txt diff --git a/examples/bluetooth/gattc_multi_connect/Makefile b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/Makefile similarity index 100% rename from examples/bluetooth/gattc_multi_connect/Makefile rename to examples/bluetooth/bluedroid/ble/gattc_multi_connect/Makefile diff --git a/examples/bluetooth/gattc_multi_connect/README.md b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/README.md similarity index 100% rename from examples/bluetooth/gattc_multi_connect/README.md rename to examples/bluetooth/bluedroid/ble/gattc_multi_connect/README.md diff --git a/examples/bluetooth/gattc_multi_connect/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/gattc_multi_connect/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/gattc_multi_connect/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_throughput/throughput_server/main/component.mk b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/main/component.mk similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_server/main/component.mk rename to examples/bluetooth/bluedroid/ble/gattc_multi_connect/main/component.mk diff --git a/examples/bluetooth/gattc_multi_connect/main/gattc_multi_connect.c b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/main/gattc_multi_connect.c similarity index 100% rename from examples/bluetooth/gattc_multi_connect/main/gattc_multi_connect.c rename to examples/bluetooth/bluedroid/ble/gattc_multi_connect/main/gattc_multi_connect.c diff --git a/examples/bluetooth/gattc_multi_connect/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/gattc_multi_connect/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/gattc_multi_connect/sdkconfig.defaults diff --git a/examples/bluetooth/gattc_multi_connect/tutorial/Gatt_Client_Multi_Connection_Example_Walkthrough.md b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/tutorial/Gatt_Client_Multi_Connection_Example_Walkthrough.md similarity index 99% rename from examples/bluetooth/gattc_multi_connect/tutorial/Gatt_Client_Multi_Connection_Example_Walkthrough.md rename to examples/bluetooth/bluedroid/ble/gattc_multi_connect/tutorial/Gatt_Client_Multi_Connection_Example_Walkthrough.md index 918f6377ab..17614d0391 100644 --- a/examples/bluetooth/gattc_multi_connect/tutorial/Gatt_Client_Multi_Connection_Example_Walkthrough.md +++ b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/tutorial/Gatt_Client_Multi_Connection_Example_Walkthrough.md @@ -8,7 +8,7 @@ This example’s workflow is similar to the [GATT Client Example Walkthrough](.. Four ESP32 devices are needed in order to demonstrate this example, among which: * one would be employed as a GATT Client flashed with the [gattc_multi_connect](../../gattc_multi_connect) demo, and, -* the rest run as GATT servers flashed with the [gatt_server](../../gatt_server) demo of the ESP-IDF Bluetooth examples folder. +* the rest run as GATT servers flashed with the [gatt_server](../../gatt_server) demo of the ESP-IDF examples/bluetooth/bluedroid/ble folder.
Multi-Connection GATT Client Flowchart
diff --git a/examples/bluetooth/gattc_multi_connect/tutorial/image/ESP32_GATT_Multi_Connect_Client_Application_Profiles.png b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/tutorial/image/ESP32_GATT_Multi_Connect_Client_Application_Profiles.png similarity index 100% rename from examples/bluetooth/gattc_multi_connect/tutorial/image/ESP32_GATT_Multi_Connect_Client_Application_Profiles.png rename to examples/bluetooth/bluedroid/ble/gattc_multi_connect/tutorial/image/ESP32_GATT_Multi_Connect_Client_Application_Profiles.png diff --git a/examples/bluetooth/gattc_multi_connect/tutorial/image/Multi_Connection_GATT_Client_Flowchart.png b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/tutorial/image/Multi_Connection_GATT_Client_Flowchart.png similarity index 100% rename from examples/bluetooth/gattc_multi_connect/tutorial/image/Multi_Connection_GATT_Client_Flowchart.png rename to examples/bluetooth/bluedroid/ble/gattc_multi_connect/tutorial/image/Multi_Connection_GATT_Client_Flowchart.png diff --git a/examples/bluetooth/a2dp_sink/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/CMakeLists.txt similarity index 100% rename from examples/bluetooth/a2dp_sink/CMakeLists.txt rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/CMakeLists.txt diff --git a/examples/bluetooth/a2dp_sink/Makefile b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/Makefile similarity index 100% rename from examples/bluetooth/a2dp_sink/Makefile rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/Makefile diff --git a/examples/bluetooth/a2dp_sink/README.md b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/README.md similarity index 100% rename from examples/bluetooth/a2dp_sink/README.md rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/README.md diff --git a/examples/bluetooth/a2dp_gatts_coex/main/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/a2dp_gatts_coex/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/CMakeLists.txt diff --git a/examples/bluetooth/a2dp_gatts_coex/main/Kconfig.projbuild b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/Kconfig.projbuild similarity index 100% rename from examples/bluetooth/a2dp_gatts_coex/main/Kconfig.projbuild rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/Kconfig.projbuild diff --git a/examples/bluetooth/a2dp_gatts_coex/main/bt_app_av.c b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_av.c similarity index 100% rename from examples/bluetooth/a2dp_gatts_coex/main/bt_app_av.c rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_av.c diff --git a/examples/bluetooth/a2dp_gatts_coex/main/bt_app_av.h b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_av.h similarity index 100% rename from examples/bluetooth/a2dp_gatts_coex/main/bt_app_av.h rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_av.h diff --git a/examples/bluetooth/a2dp_gatts_coex/main/bt_app_core.c b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_core.c similarity index 100% rename from examples/bluetooth/a2dp_gatts_coex/main/bt_app_core.c rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_core.c diff --git a/examples/bluetooth/a2dp_gatts_coex/main/bt_app_core.h b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_core.h similarity index 100% rename from examples/bluetooth/a2dp_gatts_coex/main/bt_app_core.h rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_core.h diff --git a/examples/bluetooth/a2dp_gatts_coex/main/component.mk b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/component.mk similarity index 100% rename from examples/bluetooth/a2dp_gatts_coex/main/component.mk rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/component.mk diff --git a/examples/bluetooth/a2dp_sink/main/main.c b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c similarity index 100% rename from examples/bluetooth/a2dp_sink/main/main.c rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c diff --git a/examples/bluetooth/a2dp_sink/sdkconfig.defaults b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/a2dp_sink/sdkconfig.defaults rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/sdkconfig.defaults diff --git a/examples/bluetooth/a2dp_source/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/a2dp_source/CMakeLists.txt similarity index 100% rename from examples/bluetooth/a2dp_source/CMakeLists.txt rename to examples/bluetooth/bluedroid/classic_bt/a2dp_source/CMakeLists.txt diff --git a/examples/bluetooth/a2dp_source/Makefile b/examples/bluetooth/bluedroid/classic_bt/a2dp_source/Makefile similarity index 100% rename from examples/bluetooth/a2dp_source/Makefile rename to examples/bluetooth/bluedroid/classic_bt/a2dp_source/Makefile diff --git a/examples/bluetooth/a2dp_source/README.md b/examples/bluetooth/bluedroid/classic_bt/a2dp_source/README.md similarity index 100% rename from examples/bluetooth/a2dp_source/README.md rename to examples/bluetooth/bluedroid/classic_bt/a2dp_source/README.md diff --git a/examples/bluetooth/a2dp_source/main/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/a2dp_source/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/CMakeLists.txt diff --git a/examples/bluetooth/a2dp_source/main/bt_app_core.c b/examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/bt_app_core.c similarity index 100% rename from examples/bluetooth/a2dp_source/main/bt_app_core.c rename to examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/bt_app_core.c diff --git a/examples/bluetooth/a2dp_sink/main/bt_app_core.h b/examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/bt_app_core.h similarity index 100% rename from examples/bluetooth/a2dp_sink/main/bt_app_core.h rename to examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/bt_app_core.h diff --git a/examples/bluetooth/a2dp_sink/main/component.mk b/examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/component.mk similarity index 100% rename from examples/bluetooth/a2dp_sink/main/component.mk rename to examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/component.mk diff --git a/examples/bluetooth/a2dp_source/main/main.c b/examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/main.c similarity index 100% rename from examples/bluetooth/a2dp_source/main/main.c rename to examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/main.c diff --git a/examples/bluetooth/a2dp_source/sdkconfig.defaults b/examples/bluetooth/bluedroid/classic_bt/a2dp_source/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/a2dp_source/sdkconfig.defaults rename to examples/bluetooth/bluedroid/classic_bt/a2dp_source/sdkconfig.defaults diff --git a/examples/bluetooth/bt_discovery/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/bt_discovery/CMakeLists.txt similarity index 100% rename from examples/bluetooth/bt_discovery/CMakeLists.txt rename to examples/bluetooth/bluedroid/classic_bt/bt_discovery/CMakeLists.txt diff --git a/examples/bluetooth/bt_discovery/Makefile b/examples/bluetooth/bluedroid/classic_bt/bt_discovery/Makefile similarity index 100% rename from examples/bluetooth/bt_discovery/Makefile rename to examples/bluetooth/bluedroid/classic_bt/bt_discovery/Makefile diff --git a/examples/bluetooth/bt_discovery/README.rst b/examples/bluetooth/bluedroid/classic_bt/bt_discovery/README.rst similarity index 100% rename from examples/bluetooth/bt_discovery/README.rst rename to examples/bluetooth/bluedroid/classic_bt/bt_discovery/README.rst diff --git a/examples/bluetooth/bt_discovery/main/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/bt_discovery/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/bt_discovery/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/classic_bt/bt_discovery/main/CMakeLists.txt diff --git a/examples/bluetooth/bt_discovery/main/bt_discovery.c b/examples/bluetooth/bluedroid/classic_bt/bt_discovery/main/bt_discovery.c similarity index 100% rename from examples/bluetooth/bt_discovery/main/bt_discovery.c rename to examples/bluetooth/bluedroid/classic_bt/bt_discovery/main/bt_discovery.c diff --git a/examples/bluetooth/a2dp_source/main/component.mk b/examples/bluetooth/bluedroid/classic_bt/bt_discovery/main/component.mk similarity index 100% rename from examples/bluetooth/a2dp_source/main/component.mk rename to examples/bluetooth/bluedroid/classic_bt/bt_discovery/main/component.mk diff --git a/examples/bluetooth/bt_discovery/sdkconfig.defaults b/examples/bluetooth/bluedroid/classic_bt/bt_discovery/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/bt_discovery/sdkconfig.defaults rename to examples/bluetooth/bluedroid/classic_bt/bt_discovery/sdkconfig.defaults diff --git a/examples/bluetooth/bt_spp_acceptor/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/CMakeLists.txt similarity index 100% rename from examples/bluetooth/bt_spp_acceptor/CMakeLists.txt rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/CMakeLists.txt diff --git a/examples/bluetooth/bt_spp_acceptor/Makefile b/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/Makefile similarity index 100% rename from examples/bluetooth/bt_spp_acceptor/Makefile rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/Makefile diff --git a/examples/bluetooth/bt_spp_acceptor/README.rst b/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/README.rst similarity index 100% rename from examples/bluetooth/bt_spp_acceptor/README.rst rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/README.rst diff --git a/examples/bluetooth/bt_spp_acceptor/main/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/bt_spp_acceptor/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/main/CMakeLists.txt diff --git a/examples/bluetooth/blufi/main/component.mk b/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/main/component.mk similarity index 100% rename from examples/bluetooth/blufi/main/component.mk rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/main/component.mk diff --git a/examples/bluetooth/bt_spp_acceptor/main/example_spp_acceptor_demo.c b/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/main/example_spp_acceptor_demo.c similarity index 100% rename from examples/bluetooth/bt_spp_acceptor/main/example_spp_acceptor_demo.c rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/main/example_spp_acceptor_demo.c diff --git a/examples/bluetooth/bt_spp_acceptor/sdkconfig.defaults b/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/bt_spp_acceptor/sdkconfig.defaults rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/sdkconfig.defaults diff --git a/examples/bluetooth/bt_spp_initiator/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/CMakeLists.txt similarity index 100% rename from examples/bluetooth/bt_spp_initiator/CMakeLists.txt rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/CMakeLists.txt diff --git a/examples/bluetooth/bt_spp_initiator/Makefile b/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/Makefile similarity index 100% rename from examples/bluetooth/bt_spp_initiator/Makefile rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/Makefile diff --git a/examples/bluetooth/bt_spp_initiator/README.rst b/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/README.rst similarity index 100% rename from examples/bluetooth/bt_spp_initiator/README.rst rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/README.rst diff --git a/examples/bluetooth/bt_spp_initiator/main/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/bt_spp_initiator/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/CMakeLists.txt diff --git a/examples/bluetooth/bt_spp_acceptor/main/component.mk b/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/component.mk similarity index 100% rename from examples/bluetooth/bt_spp_acceptor/main/component.mk rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/component.mk diff --git a/examples/bluetooth/bt_spp_initiator/main/example_spp_initiator_demo.c b/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/example_spp_initiator_demo.c similarity index 100% rename from examples/bluetooth/bt_spp_initiator/main/example_spp_initiator_demo.c rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/example_spp_initiator_demo.c diff --git a/examples/bluetooth/bt_spp_initiator/sdkconfig.defaults b/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/bt_spp_initiator/sdkconfig.defaults rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/sdkconfig.defaults diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/CMakeLists.txt similarity index 100% rename from examples/bluetooth/bt_spp_vfs_acceptor/CMakeLists.txt rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/CMakeLists.txt diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/Makefile b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/Makefile similarity index 100% rename from examples/bluetooth/bt_spp_vfs_acceptor/Makefile rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/Makefile diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/README.rst b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/README.rst similarity index 100% rename from examples/bluetooth/bt_spp_vfs_acceptor/README.rst rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/README.rst diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/main/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/bt_spp_vfs_acceptor/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/CMakeLists.txt diff --git a/examples/bluetooth/bt_spp_initiator/main/component.mk b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/component.mk similarity index 100% rename from examples/bluetooth/bt_spp_initiator/main/component.mk rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/component.mk diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/main/example_spp_vfs_acceptor_demo.c b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/example_spp_vfs_acceptor_demo.c similarity index 100% rename from examples/bluetooth/bt_spp_vfs_acceptor/main/example_spp_vfs_acceptor_demo.c rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/example_spp_vfs_acceptor_demo.c diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/main/spp_task.c b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/spp_task.c similarity index 100% rename from examples/bluetooth/bt_spp_vfs_acceptor/main/spp_task.c rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/spp_task.c diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/main/spp_task.h b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/spp_task.h similarity index 100% rename from examples/bluetooth/bt_spp_vfs_acceptor/main/spp_task.h rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/spp_task.h diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/sdkconfig.defaults b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/bt_spp_vfs_acceptor/sdkconfig.defaults rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/sdkconfig.defaults diff --git a/examples/bluetooth/bt_spp_vfs_initiator/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/CMakeLists.txt similarity index 100% rename from examples/bluetooth/bt_spp_vfs_initiator/CMakeLists.txt rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/CMakeLists.txt diff --git a/examples/bluetooth/bt_spp_vfs_initiator/Makefile b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/Makefile similarity index 100% rename from examples/bluetooth/bt_spp_vfs_initiator/Makefile rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/Makefile diff --git a/examples/bluetooth/bt_spp_vfs_initiator/README.rst b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/README.rst similarity index 100% rename from examples/bluetooth/bt_spp_vfs_initiator/README.rst rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/README.rst diff --git a/examples/bluetooth/bt_spp_vfs_initiator/main/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/bt_spp_vfs_initiator/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/CMakeLists.txt diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/main/component.mk b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/component.mk similarity index 100% rename from examples/bluetooth/bt_spp_vfs_acceptor/main/component.mk rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/component.mk diff --git a/examples/bluetooth/bt_spp_vfs_initiator/main/example_spp_vfs_initiator_demo.c b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/example_spp_vfs_initiator_demo.c similarity index 100% rename from examples/bluetooth/bt_spp_vfs_initiator/main/example_spp_vfs_initiator_demo.c rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/example_spp_vfs_initiator_demo.c diff --git a/examples/bluetooth/bt_spp_vfs_initiator/main/spp_task.c b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/spp_task.c similarity index 100% rename from examples/bluetooth/bt_spp_vfs_initiator/main/spp_task.c rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/spp_task.c diff --git a/examples/bluetooth/bt_spp_vfs_initiator/main/spp_task.h b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/spp_task.h similarity index 100% rename from examples/bluetooth/bt_spp_vfs_initiator/main/spp_task.h rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/spp_task.h diff --git a/examples/bluetooth/bt_spp_vfs_initiator/sdkconfig.defaults b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/bt_spp_vfs_initiator/sdkconfig.defaults rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/sdkconfig.defaults diff --git a/examples/bluetooth/a2dp_gatts_coex/CMakeLists.txt b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/CMakeLists.txt similarity index 100% rename from examples/bluetooth/a2dp_gatts_coex/CMakeLists.txt rename to examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/CMakeLists.txt diff --git a/examples/bluetooth/a2dp_gatts_coex/Makefile b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/Makefile similarity index 100% rename from examples/bluetooth/a2dp_gatts_coex/Makefile rename to examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/Makefile diff --git a/examples/bluetooth/a2dp_gatts_coex/README.md b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/README.md similarity index 100% rename from examples/bluetooth/a2dp_gatts_coex/README.md rename to examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/README.md diff --git a/examples/bluetooth/a2dp_sink/main/CMakeLists.txt b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/a2dp_sink/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/CMakeLists.txt diff --git a/examples/bluetooth/a2dp_sink/main/Kconfig.projbuild b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/Kconfig.projbuild similarity index 100% rename from examples/bluetooth/a2dp_sink/main/Kconfig.projbuild rename to examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/Kconfig.projbuild diff --git a/examples/bluetooth/a2dp_sink/main/bt_app_av.c b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_av.c similarity index 100% rename from examples/bluetooth/a2dp_sink/main/bt_app_av.c rename to examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_av.c diff --git a/examples/bluetooth/a2dp_sink/main/bt_app_av.h b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_av.h similarity index 100% rename from examples/bluetooth/a2dp_sink/main/bt_app_av.h rename to examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_av.h diff --git a/examples/bluetooth/a2dp_sink/main/bt_app_core.c b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_core.c similarity index 100% rename from examples/bluetooth/a2dp_sink/main/bt_app_core.c rename to examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_core.c diff --git a/examples/bluetooth/a2dp_source/main/bt_app_core.h b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_core.h similarity index 100% rename from examples/bluetooth/a2dp_source/main/bt_app_core.h rename to examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_core.h diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/component.mk b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/component.mk similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/component.mk rename to examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/component.mk diff --git a/examples/bluetooth/a2dp_gatts_coex/main/main.c b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c similarity index 100% rename from examples/bluetooth/a2dp_gatts_coex/main/main.c rename to examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c diff --git a/examples/bluetooth/a2dp_gatts_coex/sdkconfig.defaults b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/a2dp_gatts_coex/sdkconfig.defaults rename to examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/sdkconfig.defaults diff --git a/examples/bluetooth/gattc_gatts_coex/CMakeLists.txt b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/CMakeLists.txt similarity index 100% rename from examples/bluetooth/gattc_gatts_coex/CMakeLists.txt rename to examples/bluetooth/bluedroid/coex/gattc_gatts_coex/CMakeLists.txt diff --git a/examples/bluetooth/gattc_gatts_coex/Makefile b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/Makefile similarity index 100% rename from examples/bluetooth/gattc_gatts_coex/Makefile rename to examples/bluetooth/bluedroid/coex/gattc_gatts_coex/Makefile diff --git a/examples/bluetooth/gattc_gatts_coex/README.md b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/README.md similarity index 100% rename from examples/bluetooth/gattc_gatts_coex/README.md rename to examples/bluetooth/bluedroid/coex/gattc_gatts_coex/README.md diff --git a/examples/bluetooth/gattc_gatts_coex/main/CMakeLists.txt b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/gattc_gatts_coex/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/coex/gattc_gatts_coex/main/CMakeLists.txt diff --git a/examples/bluetooth/bt_spp_vfs_initiator/main/component.mk b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/main/component.mk similarity index 100% rename from examples/bluetooth/bt_spp_vfs_initiator/main/component.mk rename to examples/bluetooth/bluedroid/coex/gattc_gatts_coex/main/component.mk diff --git a/examples/bluetooth/gattc_gatts_coex/main/gattc_gatts_coex.c b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/main/gattc_gatts_coex.c similarity index 100% rename from examples/bluetooth/gattc_gatts_coex/main/gattc_gatts_coex.c rename to examples/bluetooth/bluedroid/coex/gattc_gatts_coex/main/gattc_gatts_coex.c diff --git a/examples/bluetooth/gattc_gatts_coex/sdkconfig.defaults b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/gattc_gatts_coex/sdkconfig.defaults rename to examples/bluetooth/bluedroid/coex/gattc_gatts_coex/sdkconfig.defaults diff --git a/examples/bluetooth/controller_hci_uart/CMakeLists.txt b/examples/bluetooth/bluedroid/hci/controller_hci_uart/CMakeLists.txt similarity index 100% rename from examples/bluetooth/controller_hci_uart/CMakeLists.txt rename to examples/bluetooth/bluedroid/hci/controller_hci_uart/CMakeLists.txt diff --git a/examples/bluetooth/controller_hci_uart/Makefile b/examples/bluetooth/bluedroid/hci/controller_hci_uart/Makefile similarity index 100% rename from examples/bluetooth/controller_hci_uart/Makefile rename to examples/bluetooth/bluedroid/hci/controller_hci_uart/Makefile diff --git a/examples/bluetooth/controller_hci_uart/README.md b/examples/bluetooth/bluedroid/hci/controller_hci_uart/README.md similarity index 100% rename from examples/bluetooth/controller_hci_uart/README.md rename to examples/bluetooth/bluedroid/hci/controller_hci_uart/README.md diff --git a/examples/bluetooth/controller_hci_uart/main/CMakeLists.txt b/examples/bluetooth/bluedroid/hci/controller_hci_uart/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/controller_hci_uart/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/hci/controller_hci_uart/main/CMakeLists.txt diff --git a/examples/bluetooth/controller_hci_uart/main/component.mk b/examples/bluetooth/bluedroid/hci/controller_hci_uart/main/component.mk similarity index 100% rename from examples/bluetooth/controller_hci_uart/main/component.mk rename to examples/bluetooth/bluedroid/hci/controller_hci_uart/main/component.mk diff --git a/examples/bluetooth/controller_hci_uart/main/controller_hci_uart_demo.c b/examples/bluetooth/bluedroid/hci/controller_hci_uart/main/controller_hci_uart_demo.c similarity index 100% rename from examples/bluetooth/controller_hci_uart/main/controller_hci_uart_demo.c rename to examples/bluetooth/bluedroid/hci/controller_hci_uart/main/controller_hci_uart_demo.c diff --git a/examples/bluetooth/controller_hci_uart/sdkconfig.defaults b/examples/bluetooth/bluedroid/hci/controller_hci_uart/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/controller_hci_uart/sdkconfig.defaults rename to examples/bluetooth/bluedroid/hci/controller_hci_uart/sdkconfig.defaults diff --git a/examples/bluetooth/ble_adv/CMakeLists.txt b/examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_adv/CMakeLists.txt rename to examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/CMakeLists.txt diff --git a/examples/bluetooth/ble_adv/Makefile b/examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/Makefile similarity index 100% rename from examples/bluetooth/ble_adv/Makefile rename to examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/Makefile diff --git a/examples/bluetooth/ble_adv/README.md b/examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/README.md similarity index 67% rename from examples/bluetooth/ble_adv/README.md rename to examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/README.md index 5e9ff15c5c..6db914225d 100644 --- a/examples/bluetooth/ble_adv/README.md +++ b/examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/README.md @@ -1,5 +1,5 @@ -ESP-IDF ble_advertising app -==================== +ESP-IDF VHCI ble_advertising app +================================ This is a BLE advertising demo with virtual HCI interface. Send Reset/ADV_PARAM/ADV_DATA/ADV_ENABLE HCI command for BLE advertising. diff --git a/examples/bluetooth/ble_adv/main/CMakeLists.txt b/examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_adv/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_adv/main/app_bt.c b/examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/main/app_bt.c similarity index 100% rename from examples/bluetooth/ble_adv/main/app_bt.c rename to examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/main/app_bt.c diff --git a/examples/bluetooth/gatt_client/main/component.mk b/examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/main/component.mk similarity index 100% rename from examples/bluetooth/gatt_client/main/component.mk rename to examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/main/component.mk diff --git a/examples/bluetooth/ble_adv/sdkconfig.defaults b/examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_adv/sdkconfig.defaults rename to examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/sdkconfig.defaults diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_client_model/CMakeLists.txt rename to examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/CMakeLists.txt diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/Makefile b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/Makefile similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_client_model/Makefile rename to examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/Makefile diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/README.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/README.md similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_client_model/README.md rename to examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/README.md diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_client_model/main/CMakeLists.txt rename to examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/Kconfig.projbuild b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/Kconfig.projbuild similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_client_model/main/Kconfig.projbuild rename to examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/Kconfig.projbuild diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/ble_mesh_demo_main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/ble_mesh_demo_main.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_client_model/main/ble_mesh_demo_main.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/ble_mesh_demo_main.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/board.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/board.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_client_model/main/board.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/board.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/main/board.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/board.h similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_client_model/main/board.h rename to examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/board.h diff --git a/examples/bluetooth/gatt_security_client/main/component.mk b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/component.mk similarity index 100% rename from examples/bluetooth/gatt_security_client/main/component.mk rename to examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/component.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_client_model/sdkconfig.defaults rename to examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/sdkconfig.defaults diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/ble_mesh_client_model.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/tutorial/ble_mesh_client_model.md similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/ble_mesh_client_model.md rename to examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/tutorial/ble_mesh_client_model.md diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/images/app.png b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/tutorial/images/app.png similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/images/app.png rename to examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/tutorial/images/app.png diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/images/message.png b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/tutorial/images/message.png similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/images/message.png rename to examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/tutorial/images/message.png diff --git a/examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/images/picture5.png b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/tutorial/images/picture5.png similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_client_model/tutorial/images/picture5.png rename to examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/tutorial/images/picture5.png diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/CMakeLists.txt rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/CMakeLists.txt diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/Makefile b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/Makefile similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/Makefile rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/Makefile diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/README.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/README.md similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/README.md rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/README.md diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/CMakeLists.txt rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.h similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.h rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.h diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.h similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.h rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.h diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_decl.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_decl.h similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_decl.h rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_decl.h diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.h similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.h rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.h diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_system.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_system.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_system.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_system.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_server_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_server_cmd.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_server_cmd.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_server_cmd.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/component.mk b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/component.mk similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/component.mk rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/component.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_node/sdkconfig.defaults rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/sdkconfig.defaults diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/CMakeLists.txt rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/CMakeLists.txt diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/Makefile b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/Makefile similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/Makefile rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/Makefile diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/README.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/README.md similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/README.md rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/README.md diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/CMakeLists.txt rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.h similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.h rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.h diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.h similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.h rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.h diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_decl.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_decl.h similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_decl.h rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_decl.h diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.h similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.h rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.h diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_system.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_system.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_system.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_system.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_cfg_client_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_cfg_client_cmd.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_cfg_client_cmd.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_cfg_client_cmd.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_gen_onoff_client_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_gen_onoff_client_cmd.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_gen_onoff_client_cmd.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_gen_onoff_client_cmd.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_test_perf_client_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_test_perf_client_cmd.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_test_perf_client_cmd.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_test_perf_client_cmd.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c diff --git a/examples/bluetooth/bt_discovery/main/component.mk b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/component.mk similarity index 100% rename from examples/bluetooth/bt_discovery/main/component.mk rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/component.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/register_bluetooth.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/register_bluetooth.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/register_bluetooth.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/register_bluetooth.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_console/ble_mesh_provisioner/sdkconfig.defaults rename to examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/sdkconfig.defaults diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/CMakeLists.txt similarity index 65% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/CMakeLists.txt rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/CMakeLists.txt index df96eec280..5f9bd92c1c 100644 --- a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/CMakeLists.txt @@ -2,7 +2,7 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.5) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components) +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(ble_mesh_fast_prov_client) diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/Makefile b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/Makefile similarity index 66% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/Makefile rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/Makefile index 06bba88878..9aff276e25 100644 --- a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/Makefile +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/Makefile @@ -7,6 +7,6 @@ PROJECT_NAME := ble_mesh_fast_prov_client COMPONENT_ADD_INCLUDEDIRS := components/include -EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components +EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components include $(IDF_PATH)/make/project.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/README.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/README.md similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/README.md rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/README.md diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/CMakeLists.txt rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/ble_mesh_demo_main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/ble_mesh_demo_main.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/ble_mesh_demo_main.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/ble_mesh_demo_main.c diff --git a/examples/bluetooth/gatt_server/main/component.mk b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/component.mk similarity index 100% rename from examples/bluetooth/gatt_server/main/component.mk rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/component.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/sdkconfig.defaults rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/sdkconfig.defaults diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/tutorial/ble_mesh_fast_provision_client.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/tutorial/ble_mesh_fast_provision_client.md similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/tutorial/ble_mesh_fast_provision_client.md rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/tutorial/ble_mesh_fast_provision_client.md diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/CMakeLists.txt similarity index 65% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/CMakeLists.txt rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/CMakeLists.txt index 594effdbb8..56ef44654e 100644 --- a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/CMakeLists.txt @@ -2,7 +2,7 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.5) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components) +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(ble_mesh_fast_prov_server) diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/Makefile b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/Makefile similarity index 66% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/Makefile rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/Makefile index f6ece484ac..31160373ff 100644 --- a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/Makefile +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/Makefile @@ -7,6 +7,6 @@ PROJECT_NAME := ble_mesh_fast_prov_server COMPONENT_ADD_INCLUDEDIRS := components/include -EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components +EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components include $(IDF_PATH)/make/project.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/README.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/README.md similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/README.md rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/README.md diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/CMakeLists.txt rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/Kconfig.projbuild b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/Kconfig.projbuild similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/Kconfig.projbuild rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/Kconfig.projbuild diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/ble_mesh_demo_main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/ble_mesh_demo_main.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/ble_mesh_demo_main.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/ble_mesh_demo_main.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.h similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.h rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.h diff --git a/examples/bluetooth/gatt_server_service_table/main/component.mk b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/component.mk similarity index 100% rename from examples/bluetooth/gatt_server_service_table/main/component.mk rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/component.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/sdkconfig.defaults rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/sdkconfig.defaults diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/EspBleMesh.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/EspBleMesh.md similarity index 95% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/EspBleMesh.md rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/EspBleMesh.md index 274ecf581d..0d087ce2d9 100644 --- a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/EspBleMesh.md +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/EspBleMesh.md @@ -13,7 +13,7 @@ A video of this demo can be seen > Note: > -> 1. Please flash the [`ble_mesh_fast_prov_server`](https://glab.espressif.cn/ble_mesh/esp-ble-mesh-v0.6/tree/ble_mesh_release/esp-ble-mesh-v0.6/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server) to your boards first; +> 1. Please flash the [`ble_mesh_fast_prov_server`](https://glab.espressif.cn/ble_mesh/esp-ble-mesh-v0.6/tree/ble_mesh_release/esp-ble-mesh-v0.6/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server) to your boards first; > 2. To have a better understanding of the performance of the BLE Mesh network, we recommend that at least 3 devices should be added in your network. > 3. We recommend that you solder LED indicators if your development board does not come with lights. > 4. Please check the type of board and LED pin definition enabled in `Example BLE Mesh Config` by running `make menuconfig` @@ -24,7 +24,7 @@ A video of this demo can be seen # Flash and Monitor 1. Enter the directory: -examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server +examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server 2. Make sure that the `IDF_PATH` environment variable was set in accordance with your current IDF path 3. Check the version of your toolchain. Version 4.1 or newer should be used. diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/ble_mesh_fast_provision_server.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/ble_mesh_fast_provision_server.md similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/ble_mesh_fast_provision_server.md rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/ble_mesh_fast_provision_server.md diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/app_ble.png b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/app_ble.png similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/app_ble.png rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/app_ble.png diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/device.png b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/device.png similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/device.png rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/device.png diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/picture1.png b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/picture1.png similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/picture1.png rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/picture1.png diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/picture2.png b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/picture2.png similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/picture2.png rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/picture2.png diff --git a/examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/time.png b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/time.png similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/time.png rename to examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/images/time.png diff --git a/examples/bluetooth/ble_mesh/ble_mesh_node/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_node/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_node/CMakeLists.txt rename to examples/bluetooth/esp_ble_mesh/ble_mesh_node/CMakeLists.txt diff --git a/examples/bluetooth/ble_mesh/ble_mesh_node/Makefile b/examples/bluetooth/esp_ble_mesh/ble_mesh_node/Makefile similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_node/Makefile rename to examples/bluetooth/esp_ble_mesh/ble_mesh_node/Makefile diff --git a/examples/bluetooth/ble_mesh/ble_mesh_node/README.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_node/README.md similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_node/README.md rename to examples/bluetooth/esp_ble_mesh/ble_mesh_node/README.md diff --git a/examples/bluetooth/ble_mesh/ble_mesh_node/main/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_node/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_node/main/CMakeLists.txt rename to examples/bluetooth/esp_ble_mesh/ble_mesh_node/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_mesh/ble_mesh_node/main/Kconfig.projbuild b/examples/bluetooth/esp_ble_mesh/ble_mesh_node/main/Kconfig.projbuild similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_node/main/Kconfig.projbuild rename to examples/bluetooth/esp_ble_mesh/ble_mesh_node/main/Kconfig.projbuild diff --git a/examples/bluetooth/ble_mesh/ble_mesh_node/main/ble_mesh_demo_main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_node/main/ble_mesh_demo_main.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_node/main/ble_mesh_demo_main.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_node/main/ble_mesh_demo_main.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_node/main/board.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_node/main/board.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_node/main/board.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_node/main/board.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_node/main/board.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_node/main/board.h similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_node/main/board.h rename to examples/bluetooth/esp_ble_mesh/ble_mesh_node/main/board.h diff --git a/examples/bluetooth/gattc_gatts_coex/main/component.mk b/examples/bluetooth/esp_ble_mesh/ble_mesh_node/main/component.mk similarity index 100% rename from examples/bluetooth/gattc_gatts_coex/main/component.mk rename to examples/bluetooth/esp_ble_mesh/ble_mesh_node/main/component.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_node/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/ble_mesh_node/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_node/sdkconfig.defaults rename to examples/bluetooth/esp_ble_mesh/ble_mesh_node/sdkconfig.defaults diff --git a/examples/bluetooth/ble_mesh/ble_mesh_node/tutorial/Ble_Mesh_Node_Example_Walkthrough.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_node/tutorial/Ble_Mesh_Node_Example_Walkthrough.md similarity index 99% rename from examples/bluetooth/ble_mesh/ble_mesh_node/tutorial/Ble_Mesh_Node_Example_Walkthrough.md rename to examples/bluetooth/esp_ble_mesh/ble_mesh_node/tutorial/Ble_Mesh_Node_Example_Walkthrough.md index 639d10de3f..8776590045 100644 --- a/examples/bluetooth/ble_mesh/ble_mesh_node/tutorial/Ble_Mesh_Node_Example_Walkthrough.md +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_node/tutorial/Ble_Mesh_Node_Example_Walkthrough.md @@ -22,7 +22,7 @@ This demo has only one element, in which the following two models are implemente The folder `ble_mesh_node` contains the following files and subfolders: ``` -$ tree examples/bluetooth/ble_mesh/ble_mesh/ble_mesh_node +$ tree examples/bluetooth/esp_ble_mesh/ble_mesh/ble_mesh_node ├── Makefile /* Compiling parameters for the demo */ ├── README.md /* Quick start guide */ ├── build @@ -468,4 +468,4 @@ The detailed information about the roles and functions of these options is prese - **Support for Light Lightness Client Model**: Indicates if the given model is supported. - **Support for Light CTL Client Model**: Indicates if the given model is supported. - **Support for Light HSL Client Model**: Indicates if the given model is supported. -- **Enable Bluetooth Mesh shell**: \ No newline at end of file +- **Enable Bluetooth Mesh shell**: diff --git a/examples/bluetooth/ble_mesh/ble_mesh_provisioner/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_provisioner/CMakeLists.txt rename to examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/CMakeLists.txt diff --git a/examples/bluetooth/ble_mesh/ble_mesh_provisioner/Makefile b/examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/Makefile similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_provisioner/Makefile rename to examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/Makefile diff --git a/examples/bluetooth/ble_mesh/ble_mesh_provisioner/README.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/README.md similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_provisioner/README.md rename to examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/README.md diff --git a/examples/bluetooth/ble_mesh/ble_mesh_provisioner/main/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_provisioner/main/CMakeLists.txt rename to examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_mesh/ble_mesh_provisioner/main/ble_mesh_demo_main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/main/ble_mesh_demo_main.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_provisioner/main/ble_mesh_demo_main.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/main/ble_mesh_demo_main.c diff --git a/examples/bluetooth/gattc_multi_connect/main/component.mk b/examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/main/component.mk similarity index 100% rename from examples/bluetooth/gattc_multi_connect/main/component.mk rename to examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/main/component.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_provisioner/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_provisioner/sdkconfig.defaults rename to examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/sdkconfig.defaults diff --git a/examples/bluetooth/ble_mesh/ble_mesh_provisioner/tutorial/Ble_Mesh_Provisioner_Example_Walkthrough.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/tutorial/Ble_Mesh_Provisioner_Example_Walkthrough.md similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_provisioner/tutorial/Ble_Mesh_Provisioner_Example_Walkthrough.md rename to examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/tutorial/Ble_Mesh_Provisioner_Example_Walkthrough.md diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/CMakeLists.txt rename to examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/CMakeLists.txt diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/Makefile b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/Makefile similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/Makefile rename to examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/Makefile diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/CMakeLists.txt rename to examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/CMakeLists.txt diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/component.mk b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/component.mk similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/component.mk rename to examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/component.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.h similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.h rename to examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.h diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_common.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_common.h similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_common.h rename to examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_common.h diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.h similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.h rename to examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.h diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.h similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.h rename to examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.h diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/CMakeLists.txt rename to examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/component.mk b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/component.mk similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/component.mk rename to examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/component.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/main.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/main.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/main.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/sdkconfig.defaults rename to examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/sdkconfig.defaults diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/CMakeLists.txt similarity index 65% rename from examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/CMakeLists.txt rename to examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/CMakeLists.txt index 8f5e74e32f..8933ca7f25 100644 --- a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/CMakeLists.txt @@ -2,7 +2,7 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.5) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components) +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(ble_mesh_wifi_coexist) diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/Makefile b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/Makefile similarity index 65% rename from examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/Makefile rename to examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/Makefile index 2db430c14f..501e1f2917 100644 --- a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/Makefile +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/Makefile @@ -7,6 +7,6 @@ PROJECT_NAME := ble_mesh_wifi_coexist COMPONENT_ADD_INCLUDEDIRS := components/include -EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/bluetooth/ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components +EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components include $(IDF_PATH)/make/project.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/README.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/README.md similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/README.md rename to examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/README.md diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/components/iperf/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/CMakeLists.txt rename to examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/components/iperf/CMakeLists.txt diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/cmd_decl.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/components/iperf/cmd_decl.h similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/cmd_decl.h rename to examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/components/iperf/cmd_decl.h diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/cmd_wifi.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/components/iperf/cmd_wifi.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/cmd_wifi.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/components/iperf/cmd_wifi.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/component.mk b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/components/iperf/component.mk similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/component.mk rename to examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/components/iperf/component.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/iperf.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/components/iperf/iperf.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/iperf.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/components/iperf/iperf.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/iperf.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/components/iperf/iperf.h similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/components/iperf/iperf.h rename to examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/components/iperf/iperf.h diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/main/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/main/CMakeLists.txt rename to examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/main/Kconfig.projbuild b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/Kconfig.projbuild similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/main/Kconfig.projbuild rename to examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/Kconfig.projbuild diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/main/ble_mesh_demo_main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/ble_mesh_demo_main.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/main/ble_mesh_demo_main.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/ble_mesh_demo_main.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/main/board.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/board.c similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/main/board.c rename to examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/board.c diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/main/board.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/board.h similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/main/board.h rename to examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/board.h diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/main/component.mk b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/component.mk similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/main/component.mk rename to examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/component.mk diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/partitions.csv b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/partitions.csv similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/partitions.csv rename to examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/partitions.csv diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/sdkconfig.defaults rename to examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/sdkconfig.defaults diff --git a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/tutorial/ble_mesh_wifi_coexist.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/tutorial/ble_mesh_wifi_coexist.md similarity index 99% rename from examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/tutorial/ble_mesh_wifi_coexist.md rename to examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/tutorial/ble_mesh_wifi_coexist.md index c44ef4c719..e60446ca72 100644 --- a/examples/bluetooth/ble_mesh/ble_mesh_wifi_coexist/tutorial/ble_mesh_wifi_coexist.md +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/tutorial/ble_mesh_wifi_coexist.md @@ -34,7 +34,7 @@ Meanwhile, you can use the Bluetooth function during the whole process, for exam The `ble_mesh_wifi_coexist` demo contains the following files and subfolders: ``` -$ tree examples/bluetooth/ble_mesh/ble_mesh/ble_mesh_wifi_coexist +$ tree examples/bluetooth/esp_ble_mesh/ble_mesh/ble_mesh_wifi_coexist ├── main /* Stores the `.c` and `.h` application code files for this demo */ ├── components /* Stores the `.c` and `.h` iperf code files for this demo */ ├── Makefile /* Compiling parameters for the demo */ diff --git a/examples/bluetooth/nimble/README.md b/examples/bluetooth/nimble/README.md index 39f97c19a7..d77a2cfe7f 100644 --- a/examples/bluetooth/nimble/README.md +++ b/examples/bluetooth/nimble/README.md @@ -1,4 +1,8 @@ -# NimBLE Examples +# Bluetooth Examples for NimBLE host + +Note: To use examples in this directory, you need to have Bluetooth enabled in configuration and NimBLE selected as the host stack. + +# Example Layout This directory includes examples to demonstrate BLE functionality using Apache MyNewt NimBLE (https://github.com/apache/mynewt-nimble) host stack. From a32534497c1a51c211992ec7c14e8e4bfca1e530 Mon Sep 17 00:00:00 2001 From: Hrishikesh Dhayagude Date: Mon, 1 Jul 2019 19:22:55 +0800 Subject: [PATCH 194/486] Fix failure in flake8 due to incorrect NimBLE path --- .flake8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.flake8 b/.flake8 index cd06e2afe9..d03e1999a4 100644 --- a/.flake8 +++ b/.flake8 @@ -147,7 +147,7 @@ exclude = components/libsodium/libsodium, components/mbedtls/mbedtls, components/nghttp/nghttp2, - components/nimble/nimble, + components/bt/host/nimble/nimble, components/unity/unity, examples/build_system/cmake/import_lib/main/lib/tinyxml2, # other third-party libraries From 1a2bf4d8ffe682636bd7faecff42b7c21359cfa0 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Fri, 28 Jun 2019 14:23:21 +0200 Subject: [PATCH 195/486] idf_tools: print additional info when download verification fails --- tools/idf_tools.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/idf_tools.py b/tools/idf_tools.py index d53e036bf6..30ed7b6389 100755 --- a/tools/idf_tools.py +++ b/tools/idf_tools.py @@ -559,10 +559,10 @@ class IDFTool(object): expected_size = download_obj.size file_size, file_sha256 = get_file_size_sha256(local_path) if file_size != expected_size: - warn('file size mismatch for {0}'.format(local_path)) + warn('file size mismatch for {}, expected {}, got {}'.format(local_path, expected_size, file_size)) return False if file_sha256 != expected_sha256: - warn('hash mismatch for {0}'.format(local_path)) + warn('hash mismatch for {}, expected {}, got {}'.format(local_path, expected_sha256, file_sha256)) return False return True From 916c0c575479b10c85c59fa7137fbd894c2d6f3e Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 9 May 2019 14:14:47 +0800 Subject: [PATCH 196/486] idf.py.exe wrapper program for Windows --- tools/windows/idf_exe/CMakeLists.txt | 25 ++++ tools/windows/idf_exe/README.md | 34 ++++++ tools/windows/idf_exe/idf_main.c | 111 ++++++++++++++++++ .../idf_exe/toolchain-i686-w64-mingw32.cmake | 7 ++ 4 files changed, 177 insertions(+) create mode 100644 tools/windows/idf_exe/CMakeLists.txt create mode 100644 tools/windows/idf_exe/README.md create mode 100644 tools/windows/idf_exe/idf_main.c create mode 100644 tools/windows/idf_exe/toolchain-i686-w64-mingw32.cmake diff --git a/tools/windows/idf_exe/CMakeLists.txt b/tools/windows/idf_exe/CMakeLists.txt new file mode 100644 index 0000000000..ba7e940af7 --- /dev/null +++ b/tools/windows/idf_exe/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.5) +project(idfexe) + +set(VERSION 1.0) +set(ARCHIVE_NAME idf-exe-v${VERSION}.zip) + +add_executable(idf idf_main.c) +set_target_properties(idf PROPERTIES C_STANDARD 99) +target_link_libraries(idf "-lshlwapi") + +if(CMAKE_BUILD_TYPE STREQUAL Release) + add_custom_command(TARGET idf + POST_BUILD + COMMAND ${CMAKE_STRIP} idf.exe) +endif() + +add_custom_target(dist ALL DEPENDS idf) + +add_custom_command( + TARGET dist + POST_BUILD + COMMAND ${CMAKE_COMMAND} ARGS -E copy "${CMAKE_CURRENT_BINARY_DIR}/idf.exe" "${CMAKE_CURRENT_BINARY_DIR}/idf.py.exe" + COMMAND ${CMAKE_COMMAND} ARGS -E tar cfv ${ARCHIVE_NAME} --format=zip + "${CMAKE_CURRENT_BINARY_DIR}/idf.py.exe" + ) diff --git a/tools/windows/idf_exe/README.md b/tools/windows/idf_exe/README.md new file mode 100644 index 0000000000..0a0b543807 --- /dev/null +++ b/tools/windows/idf_exe/README.md @@ -0,0 +1,34 @@ +# IDF wrapper tool (idf.py.exe) + +This tools helps invoke idf.py in Windows CMD shell. + +In Windows CMD shell, python scripts can be executed directly (by typing their name) if `.py` extension is associated with Python. The issue with such association is that it is incompatible with virtual environments. That is, if `.py` extension is associated with a global (or user-specific) copy of `python.exe`, then the virtual environment will not be used when running the script. [Python Launcher](https://www.python.org/dev/peps/pep-0397/) solves this issue, but it is installed by default only with Python 3.6 and newer. In addition to that, the user may choose not to install Python Launcher (for example, to keep `.py` files associated with an editor). + +Hence, `idf.py.exe` is introduced. It is a simple program which forwards the command line arguments to `idf.py`. That is, + +``` +idf.py args... +``` +has the same effect as: + +``` +python.exe %IDF_PATH%\tools\idf.py args... +``` + +`python.exe` location is determined using the default search rules, which include searching the directories in `%PATH%`. Standard I/O streams are forwarded between `idf.py.exe` and `python.exe` processes. The exit code of `idf.py.exe` is the same as the exit code of `python.exe` process. + +For compatibility with `idf_tools.py`, a flag to obtain the version of `idf.py.exe` is provided: `idf.py.exe -v` or `idf.py.exe --version`. Note that this flag only works when `idf.py.exe` is started by the full name (with `.exe` extension). Running `idf.py -v` results in same behavior as `python idf.py -v`, that is `-v` argument is propagated to the Python script. + +## Building + +On Linux/Mac, install mingw-w64 toolchain (`i686-w64-mingw32-gcc`). Then build `idf.py.exe` using CMake: + +``` +mkdir -p build +cd build +cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain-i686-w64-mingw32.cmake -DCMAKE_BUILD_TYPE=Release .. +cmake --build . +``` + +On Windows, it is also possible to build using Visual Studio, with CMake support installed. + diff --git a/tools/windows/idf_exe/idf_main.c b/tools/windows/idf_exe/idf_main.c new file mode 100644 index 0000000000..a8d1aec541 --- /dev/null +++ b/tools/windows/idf_exe/idf_main.c @@ -0,0 +1,111 @@ +// Copyright 2019 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 +#include +#include +#include + +#define LINESIZE 1024 +#define VERSION "1.0" + +static void fail(LPCSTR message, ...) __attribute__((noreturn)); + +static void fail(LPCSTR message, ...) +{ + DWORD written; + char msg[LINESIZE]; + va_list args = NULL; + va_start(args, message); + StringCchVPrintfA(msg, sizeof(msg), message, args); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), message, lstrlen(msg), &written, NULL); + ExitProcess(1); +} + +int main(int argc, LPTSTR argv[]) +{ + /* Print the version of this wrapper tool, but only if invoked as "idf.exe". + * "idf -v" will invoke idf.py as expected. + */ + + LPCTSTR cmdname = PathFindFileName(argv[0]); + int cmdname_length = strlen(cmdname); + + if (argc == 2 && + cmdname_length > 4 && + StrCmp(cmdname + cmdname_length - 4, TEXT(".exe")) == 0 && + (StrCmp(argv[1], TEXT("--version")) == 0 || + StrCmp(argv[1], TEXT("-v")) == 0)) { + LPCSTR msg = VERSION "\n"; + WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msg, lstrlen(msg), NULL, NULL); + return 0; + } + + LPCTSTR idfpy_script_name = TEXT("idf.py"); + + /* Get IDF_PATH */ + TCHAR idf_path[LINESIZE] = {}; + if (GetEnvironmentVariable(TEXT("IDF_PATH"), idf_path, sizeof(idf_path)) == 0) { + DWORD err = GetLastError(); + if (err == ERROR_ENVVAR_NOT_FOUND) { + fail("IDF_PATH environment variable needs to be set to use this tool\n"); + } else { + fail("Unknown error (%u)\n", err); + } + } + + /* Prepare the command line: python.exe %IDF_PATH%\\tools\idf.py */ + TCHAR cmdline[LINESIZE] = {}; + StringCchCat(cmdline, sizeof(cmdline), TEXT("python.exe ")); + StringCchCat(cmdline, sizeof(cmdline), idf_path); + StringCchCat(cmdline, sizeof(cmdline), TEXT("\\tools\\")); + StringCchCat(cmdline, sizeof(cmdline), idfpy_script_name); + StringCchCat(cmdline, sizeof(cmdline), TEXT(" ")); + for (int i = 1; i < argc; ++i) { + StringCchCat(cmdline, sizeof(cmdline), argv[i]); + StringCchCat(cmdline, sizeof(cmdline), TEXT(" ")); + } + + SetEnvironmentVariable(TEXT("IDF_PY_PROGRAM_NAME"), idfpy_script_name); + + /* Reuse the standard streams of this process */ + STARTUPINFO start_info = { + .cb = sizeof(STARTUPINFO), + .hStdError = GetStdHandle(STD_ERROR_HANDLE), + .hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE), + .hStdInput = GetStdHandle(STD_INPUT_HANDLE), + .dwFlags = STARTF_USESTDHANDLES + }; + + /* Run the child process */ + PROCESS_INFORMATION child_process; + if (!CreateProcess(NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &start_info, &child_process)) { + DWORD err = GetLastError(); + if (err == ERROR_FILE_NOT_FOUND) { + fail("Can not find Python\n"); + } else { + fail("Unknown error (%u)\n", err); + } + } + + /* Wait for it to complete */ + WaitForSingleObject(child_process.hProcess, INFINITE); + + /* Return with the exit code of the child process */ + DWORD exitcode; + if (!GetExitCodeProcess(child_process.hProcess, &exitcode)) { + fail("Couldn't get the exit code (%u)\n", GetLastError()); + } + return exitcode; +} diff --git a/tools/windows/idf_exe/toolchain-i686-w64-mingw32.cmake b/tools/windows/idf_exe/toolchain-i686-w64-mingw32.cmake new file mode 100644 index 0000000000..8e9acb4ae6 --- /dev/null +++ b/tools/windows/idf_exe/toolchain-i686-w64-mingw32.cmake @@ -0,0 +1,7 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR x86) +set(CMAKE_C_COMPILER i686-w64-mingw32-gcc) +set(CMAKE_CXX_COMPILER i686-w64-mingw32-g++) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) From 3d866694c9a81d61089d6ead4a8f61d0bad36864 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Fri, 10 May 2019 18:12:19 +0800 Subject: [PATCH 197/486] tools.json: add idf.py.exe --- tools/tools.json | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tools/tools.json b/tools/tools.json index 3d0941660f..e96040307a 100644 --- a/tools/tools.json +++ b/tools/tools.json @@ -306,6 +306,49 @@ } ] }, + { + "description": "IDF wrapper tool for Windows", + "export_paths": [ + [ + "" + ] + ], + "export_vars": {}, + "info_url": "https://github.com/espressif/esp-idf/tree/master/tools/windows/idf_exe", + "install": "never", + "license": "Apache-2.0", + "name": "idf-exe", + "platform_overrides": [ + { + "install": "always", + "platforms": [ + "win32", + "win64" + ] + } + ], + "version_cmd": [ + "idf.py.exe", + "-v" + ], + "version_regex": "([0-9.]+)", + "versions": [ + { + "name": "1.0", + "status": "recommended", + "win32": { + "sha256": "83a83ac7a246cbae93884db7c5f2ef9a7607d602340b1cf1e64ec2a925071748", + "size": 11289, + "url": "https://dl.espressif.com/dl/idf-exe-v1.0.zip" + }, + "win64": { + "sha256": "83a83ac7a246cbae93884db7c5f2ef9a7607d602340b1cf1e64ec2a925071748", + "size": 11289, + "url": "https://dl.espressif.com/dl/idf-exe-v1.0.zip" + } + } + ] + }, { "description": "Ccache (compiler cache)", "export_paths": [ From 12b6da0388a55d56bf68729bf558dc82a84660c7 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 29 Apr 2019 10:37:02 +0800 Subject: [PATCH 198/486] tools: {install,export}.{bat,sh} tools --- add_path.sh | 3 +- export.bat | 70 ++++++++++++++++++++++++++++++ export.sh | 82 ++++++++++++++++++++++++++++++++++++ install.bat | 19 +++++++++ install.sh | 18 ++++++++ tools/ci/executable-list.txt | 1 + 6 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 export.bat create mode 100644 export.sh create mode 100644 install.bat create mode 100755 install.sh diff --git a/add_path.sh b/add_path.sh index bfc27bb49f..f48c9b0c2c 100644 --- a/add_path.sh +++ b/add_path.sh @@ -9,8 +9,7 @@ if [ -z ${IDF_PATH} ]; then echo "IDF_PATH must be set before including this script." else - IDF_ADD_PATHS_EXTRAS= - IDF_ADD_PATHS_EXTRAS="${IDF_ADD_PATHS_EXTRAS}:${IDF_PATH}/components/esptool_py/esptool" + IDF_ADD_PATHS_EXTRAS="${IDF_PATH}/components/esptool_py/esptool" IDF_ADD_PATHS_EXTRAS="${IDF_ADD_PATHS_EXTRAS}:${IDF_PATH}/components/espcoredump" IDF_ADD_PATHS_EXTRAS="${IDF_ADD_PATHS_EXTRAS}:${IDF_PATH}/components/partition_table/" IDF_ADD_PATHS_EXTRAS="${IDF_ADD_PATHS_EXTRAS}:${IDF_PATH}/tools/" diff --git a/export.bat b/export.bat new file mode 100644 index 0000000000..51a3965ce6 --- /dev/null +++ b/export.bat @@ -0,0 +1,70 @@ +@echo off +if defined MSYSTEM ( + echo This .bat file is for Windows CMD.EXE shell only. When using MSYS, run: + echo . ./export.sh. + goto :eof +) + +:: Infer IDF_PATH from script location +set IDF_PATH=%~dp0 +set IDF_PATH=%IDF_PATH:~0,-1% + +set IDF_TOOLS_PY_PATH=%IDF_PATH%\tools\idf_tools.py +set IDF_TOOLS_JSON_PATH=%IDF_PATH%\tools\tools.json +set IDF_TOOLS_EXPORT_CMD=%IDF_PATH%\export.bat +set IDF_TOOLS_INSTALL_CMD=%IDF_PATH%\install.bat +echo Setting IDF_PATH: %IDF_PATH% +echo. + +set "OLD_PATH=%PATH%" +echo Adding ESP-IDF tools to PATH... +:: Export tool paths and environment variables. +:: It is possible to do this without a temporary file (running idf_tools.py from for /r command), +:: but that way it is impossible to get the exit code of idf_tools.py. +set "IDF_TOOLS_EXPORTS_FILE=%TEMP%\idf_export_vars.tmp" +python.exe %IDF_PATH%\tools\idf_tools.py export --format key-value >"%IDF_TOOLS_EXPORTS_FILE%" +if %errorlevel% neq 0 goto :end + +for /f "usebackq tokens=1,2 eol=# delims==" %%a in ("%IDF_TOOLS_EXPORTS_FILE%") do ( + call set "%%a=%%b" + ) + +:: This removes OLD_PATH substring from PATH, leaving only the paths which have been added, +:: and prints semicolon-delimited components of the path on separate lines +call set PATH_ADDITIONS=%%PATH:%OLD_PATH%=%% +if "%PATH_ADDITIONS%"=="" call :print_nothing_added +if not "%PATH_ADDITIONS%"=="" echo %PATH_ADDITIONS:;=&echo. % + +echo Checking if Python packages are up to date... +python.exe %IDF_PATH%\tools\check_python_dependencies.py +if %errorlevel% neq 0 goto :end + +echo. +echo Done! You can now compile ESP-IDF projects. +echo Go to the project directory and run: +echo. +echo idf.py build +echo. + +goto :end + +:print_nothing_added + echo No directories added to PATH: + echo. + echo %PATH% + echo. + goto :eof + +:end + +:: Clean up +if not "%IDF_TOOLS_EXPORTS_FILE%"=="" ( + del "%IDF_TOOLS_EXPORTS_FILE%" 1>nul 2>nul +) +set IDF_TOOLS_EXPORTS_FILE= +set IDF_TOOLS_EXPORT_CMD= +set IDF_TOOLS_INSTALL_CMD= +set IDF_TOOLS_PY_PATH= +set IDF_TOOLS_JSON_PATH= +set OLD_PATH= +set PATH_ADDITIONS= diff --git a/export.sh b/export.sh new file mode 100644 index 0000000000..a136ab2856 --- /dev/null +++ b/export.sh @@ -0,0 +1,82 @@ +# This script should be sourced, not executed. + +function idf_export_main() { + # The file doesn't have executable permissions, so this shouldn't really happen. + # Doing this in case someone tries to chmod +x it and execute... + if [[ -n "${BASH_SOURCE}" && ( "${BASH_SOURCE[0]}" == "${0}" ) ]]; then + echo "This script should be sourced, not executed:" + echo ". ${BASH_SOURCE[0]}" + return 1 + fi + + if [[ -z "${IDF_PATH}" ]] + then + # If using bash, try to guess IDF_PATH from script location + if [[ -n "${BASH_SOURCE}" ]] + then + script_name="$(readlink -f $BASH_SOURCE)" + export IDF_PATH="$(dirname ${script_name})" + else + echo "IDF_PATH must be set before sourcing this script" + return 1 + fi + fi + + old_path=$PATH + + echo "Adding ESP-IDF tools to PATH..." + # Call idf_tools.py to export tool paths + export IDF_TOOLS_EXPORT_CMD=${IDF_PATH}/export.sh + export IDF_TOOLS_INSTALL_CMD=${IDF_PATH}/install.sh + idf_exports=$(${IDF_PATH}/tools/idf_tools.py export) || return 1 + eval "${idf_exports}" + + echo "Checking if Python packages are up to date..." + python ${IDF_PATH}/tools/check_python_dependencies.py || return 1 + + + # Allow calling some IDF python tools without specifying the full path + # ${IDF_PATH}/tools is already added by 'idf_tools.py export' + IDF_ADD_PATHS_EXTRAS="${IDF_PATH}/components/esptool_py/esptool" + IDF_ADD_PATHS_EXTRAS="${IDF_ADD_PATHS_EXTRAS}:${IDF_PATH}/components/espcoredump" + IDF_ADD_PATHS_EXTRAS="${IDF_ADD_PATHS_EXTRAS}:${IDF_PATH}/components/partition_table/" + export PATH="${IDF_ADD_PATHS_EXTRAS}:${PATH}" + + if [[ -n "$BASH" ]] + then + path_prefix=${PATH%%${old_path}} + paths="${path_prefix//:/ }" + if [ -n "${paths}" ]; then + echo "Added the following directories to PATH:" + else + echo "All paths are already set." + fi + for path_entry in ${paths} + do + echo " ${path_entry}" + done + else + echo "Updated PATH variable:" + echo " ${PATH}" + fi + + # Clean up + unset old_path + unset paths + unset path_prefix + unset path_entry + unset IDF_ADD_PATHS_EXTRAS + unset idf_exports + # Not unsetting IDF_PYTHON_ENV_PATH, it can be used by IDF build system + # to check whether we are using a private Python environment + + echo "Done! You can now compile ESP-IDF projects." + echo "Go to the project directory and run:" + echo "" + echo " idf.py build" + echo "" +} + +idf_export_main + +unset idf_export_main diff --git a/install.bat b/install.bat new file mode 100644 index 0000000000..fdb9771a46 --- /dev/null +++ b/install.bat @@ -0,0 +1,19 @@ +@echo off +if defined MSYSTEM ( + echo This .bat file is for Windows CMD.EXE shell only. When using MSYS, run: + echo ./install.sh. + goto end +) +:: Infer IDF_PATH from script location +set IDF_PATH=%~dp0 +set IDF_PATH=%IDF_PATH:~0,-1% + +echo Installing ESP-IDF tools +python.exe %IDF_PATH%\tools\idf_tools.py install + +echo Setting up Python environment +python.exe %IDF_PATH%\tools\idf_tools.py install-python-env + +echo All done! You can now run: +echo export.bat +:: Clean up diff --git a/install.sh b/install.sh new file mode 100755 index 0000000000..d026e3c931 --- /dev/null +++ b/install.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +set -e +set -u + +export IDF_PATH=$(cd $(dirname $0); pwd) + +echo "Installing ESP-IDF tools" +${IDF_PATH}/tools/idf_tools.py install + +echo "Installing Python environment and packages" +${IDF_PATH}/tools/idf_tools.py install-python-env + +basedir="$(dirname $0)" +echo "All done! You can now run:" +echo "" +echo " . ${basedir}/export.sh" +echo "" diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index fa86287cca..a3b2845577 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -26,6 +26,7 @@ examples/storage/parttool/parttool_example.sh examples/system/ota/otatool/get_running_partition.py examples/system/ota/otatool/otatool_example.py examples/system/ota/otatool/otatool_example.sh +install.sh tools/check_kconfigs.py tools/check_python_dependencies.py tools/ci/apply_bot_filter.py From 04d24c750a85be886eee5833764bd531c011f178 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 29 Apr 2019 10:36:03 +0800 Subject: [PATCH 199/486] tools: new installer for Windows --- .gitignore | 7 - tools/windows/tool_setup/.gitignore | 6 + tools/windows/tool_setup/README.md | 39 +++ tools/windows/tool_setup/choice_page.iss.inc | 247 ++++++++++++++ tools/windows/tool_setup/cmdline_page.iss.inc | 154 +++++++++ .../tool_setup/cmdlinerunner/CMakeLists.txt | 8 + .../tool_setup/cmdlinerunner/cmdlinerunner.c | 194 +++++++++++ .../tool_setup/cmdlinerunner/cmdlinerunner.h | 32 ++ .../toolchain-i686-w64-mingw32.cmake | 7 + .../tool_setup/git_find_installed.iss.inc | 98 ++++++ tools/windows/tool_setup/git_page.iss.inc | 194 +++++++++++ tools/windows/tool_setup/idf_cmd_init.bat | 117 +++++++ .../tool_setup/idf_download_page.iss.inc | 142 ++++++++ tools/windows/tool_setup/idf_page.iss.inc | 111 +++++++ tools/windows/tool_setup/idf_setup.iss.inc | 255 +++++++++++++++ tools/windows/tool_setup/idf_tool_setup.iss | 303 +++++------------- tools/windows/tool_setup/main.iss.inc | 121 +++++++ .../tool_setup/python_find_installed.iss.inc | 113 +++++++ tools/windows/tool_setup/python_page.iss.inc | 149 +++++++++ tools/windows/tool_setup/summary.iss.inc | 40 +++ tools/windows/tool_setup/utils.iss.inc | 157 +++++++++ 21 files changed, 2263 insertions(+), 231 deletions(-) create mode 100644 tools/windows/tool_setup/.gitignore create mode 100644 tools/windows/tool_setup/README.md create mode 100644 tools/windows/tool_setup/choice_page.iss.inc create mode 100644 tools/windows/tool_setup/cmdline_page.iss.inc create mode 100644 tools/windows/tool_setup/cmdlinerunner/CMakeLists.txt create mode 100644 tools/windows/tool_setup/cmdlinerunner/cmdlinerunner.c create mode 100644 tools/windows/tool_setup/cmdlinerunner/cmdlinerunner.h create mode 100644 tools/windows/tool_setup/cmdlinerunner/toolchain-i686-w64-mingw32.cmake create mode 100644 tools/windows/tool_setup/git_find_installed.iss.inc create mode 100644 tools/windows/tool_setup/git_page.iss.inc create mode 100644 tools/windows/tool_setup/idf_cmd_init.bat create mode 100644 tools/windows/tool_setup/idf_download_page.iss.inc create mode 100644 tools/windows/tool_setup/idf_page.iss.inc create mode 100644 tools/windows/tool_setup/idf_setup.iss.inc create mode 100644 tools/windows/tool_setup/main.iss.inc create mode 100644 tools/windows/tool_setup/python_find_installed.iss.inc create mode 100644 tools/windows/tool_setup/python_page.iss.inc create mode 100644 tools/windows/tool_setup/summary.iss.inc create mode 100644 tools/windows/tool_setup/utils.iss.inc diff --git a/.gitignore b/.gitignore index f6b52b9f04..48ee2b0f16 100644 --- a/.gitignore +++ b/.gitignore @@ -58,13 +58,6 @@ TEST_LOGS coverage.info coverage_report/ -# Windows tools installer build -tools/windows/tool_setup/.* -tools/windows/tool_setup/input -tools/windows/tool_setup/dl -tools/windows/tool_setup/keys -tools/windows/tool_setup/Output - test_multi_heap_host # VS Code Settings diff --git a/tools/windows/tool_setup/.gitignore b/tools/windows/tool_setup/.gitignore new file mode 100644 index 0000000000..620ec0e2ac --- /dev/null +++ b/tools/windows/tool_setup/.gitignore @@ -0,0 +1,6 @@ +Output +cmdlinerunner/build +dist +unzip +keys +idf_versions.txt diff --git a/tools/windows/tool_setup/README.md b/tools/windows/tool_setup/README.md new file mode 100644 index 0000000000..f9e71e9b48 --- /dev/null +++ b/tools/windows/tool_setup/README.md @@ -0,0 +1,39 @@ +# ESP-IDF Tools Installer for Windows + +This directory contains source files required to build the tools installer for Windows. + +The installer is built using [Inno Setup](http://www.jrsoftware.org/isinfo.php). At the time of writing, the installer can be built with Inno Setup version 6.0.2. + +The main source file of the installer is `idf_tools_setup.iss`. PascalScript code is split into multiple `*.iss.inc` files. + +Some functionality of the installer depends on additional programs: + +* [Inno Download Plugin](https://bitbucket.org/mitrich_k/inno-download-plugin) — used to download additional files during the installation. + +* [7-zip](https://www.7-zip.org) — used to extract downloaded IDF archives. + +* [cmdlinerunner](cmdlinerunner/cmdlinerunner.c) — a helper DLL used to run external command line programs from the installer, capture live console output, and get the exit code. + +## Steps required to build the installer + +* Build cmdlinerunner DLL. + - On Linux/Mac, install mingw-w64 toolchain (`i686-w64-mingw32-gcc`). Then build the DLL using CMake: + ``` + mkdir -p cmdlinerunner/build + cd cmdlinerunner/build + cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain-i686-w64-mingw32.cmake -DCMAKE_BUILD_TYPE=Release .. + cmake --build . + ``` + This will produce `cmdlinerunner.dll` in the build directory. + - On Windows, it is possible to build using Visual Studio, with CMake support installed. By default, VS produces build artifacts in some hard to find directory. You can adjust this in CmakeSettings.json file generated by VS. + +* Download 7zip.exe [("standalone console version")](https://www.7-zip.org/download.html) and put it into `unzip` directory (to get `unzip/7za.exe`). + +* Download [idf_versions.txt](https://dl.espressif.com/dl/esp-idf/idf_versions.txt) and place it into the current directory. The installer will use it as a fallback, if it can not download idf_versions.txt at run time. + +* Create the `dist` directory and populate it with the tools which should be bundled with the installer. At the moment the easiest way to obtain it is to use `install.sh`/`install.bat` in IDF, and then copy the contents of `$HOME/.espressif/dist` directory. If the directory is empty, the installer should still work, and the tools will be downloaded during the installation. + +* Build the installer using Inno Setup Compiler: `ISCC.exe idf_tools_setup.iss`. + +* Obtain the signing keys, then sign `Output/esp-idf-tools-setup-unsigned.exe`. + diff --git a/tools/windows/tool_setup/choice_page.iss.inc b/tools/windows/tool_setup/choice_page.iss.inc new file mode 100644 index 0000000000..8291edc2fa --- /dev/null +++ b/tools/windows/tool_setup/choice_page.iss.inc @@ -0,0 +1,247 @@ +var + ChoicePagePrepare: array of TNotifyEvent; + ChoicePageSelectionChange: array of TNotifyEvent; + ChoicePageValidate: array of TWizardPageButtonEvent; + ChoicePageMaxTag: Integer; + ChoicePages: array of TInputOptionWizardPage; + +procedure ChoicePageOnClickCheck(Sender: TObject); +var + ListBox: TNewCheckListBox; + Id: Integer; +begin + ListBox := TNewCheckListBox(Sender); + Id := Integer(ListBox.Tag); + ChoicePageSelectionChange[Id](ChoicePages[Id]); +end; + +function ChoicePageGetInput(Page: TInputOptionWizardPage): TNewEdit; +begin + Result := TNewEdit(Page.FindComponent('ChoicePageInput')); +end; + +function ChoicePageGetLabel(Page: TInputOptionWizardPage): TNewStaticText; +begin + Result := TNewStaticText(Page.FindComponent('ChoicePageLabel')); +end; + +function ChoicePageGetButton(Page: TInputOptionWizardPage): TNewButton; +begin + Result := TNewButton(Page.FindComponent('ChoicePageBrowseButton')); +end; + +procedure ChoicePageSetEditLabel(Page: TInputOptionWizardPage; Caption: String); +var + InputLabel: TNewStaticText; +begin + InputLabel := ChoicePageGetLabel(Page); + InputLabel.Caption := Caption; +end; + +function ChoicePageGetInputText(Page: TInputOptionWizardPage): String; +begin + Result := ChoicePageGetInput(Page).Text; +end; + +procedure ChoicePageSetInputText(Page: TInputOptionWizardPage; Text: String); +begin + ChoicePageGetInput(Page).Text := Text; +end; + +procedure ChoicePageSetInputEnabled(Page: TInputOptionWizardPage; Enabled: Boolean); +begin + ChoicePageGetLabel(Page).Enabled := Enabled; + ChoicePageGetInput(Page).Enabled := Enabled; + ChoicePageGetButton(Page).Enabled := Enabled; +end; + + +procedure ChoicePageOnBrowseButtonClick(Sender: TObject); +var + Button: TNewButton; + Page: TInputOptionWizardPage; + InputLabel: TNewStaticText; + Input: TNewEdit; + Dir: String; +begin + Button := TNewButton(Sender); + Page := TInputOptionWizardPage(Button.Owner); + Input := ChoicePageGetInput(Page); + InputLabel := ChoicePageGetLabel(Page); + Dir := Input.Text; + if BrowseForFolder(InputLabel.Caption, Dir, True) then + begin + Input.Text := Dir; + end; +end; + + +procedure ChoicePageOnCurPageChanged(CurPageID: Integer); +var + i: Integer; +begin + for i := 1 to ChoicePageMaxTag do + begin + if ChoicePages[i].ID = CurPageID then + begin + ChoicePagePrepare[i](ChoicePages[i]); + break; + end; + end; +end; + + +function ChoicePageOnNextButtonClick(CurPageID: Integer): Boolean; +var + i: Integer; +begin + Result := True; + for i := 1 to ChoicePageMaxTag do + begin + if ChoicePages[i].ID = CurPageID then + begin + Result := ChoicePageValidate[i](ChoicePages[i]); + break; + end; + end; +end; + + +procedure InitChoicePages(); +begin + ChoicePages := [ ]; + ChoicePagePrepare := [ ]; + ChoicePageSelectionChange := [ ]; + ChoicePageValidate := [ ]; +end; + +function FindLinkInText(Text: String): String; +var + Tmp: String; + LinkStartPos, LinkEndPos: Integer; +begin + Result := ''; + Tmp := Text; + LinkStartPos := Pos('https://', Tmp); + if LinkStartPos = 0 then exit; + Delete(Tmp, 1, LinkStartPos - 1); + + { Try to find the end of the link } + LinkEndPos := 0 + if LinkEndPos = 0 then LinkEndPos := Pos(' ', Tmp); + if LinkEndPos = 0 then LinkEndPos := Pos(',', Tmp); + if LinkEndPos = 0 then LinkEndPos := Pos('.', Tmp); + if LinkEndPos = 0 then LinkEndPos := Length(Tmp); + Delete(Text, LinkEndPos, Length(Tmp)); + + Log('Found link in "' + Text + '": "' + Tmp + '"'); + Result := Tmp; +end; + +procedure OnStaticTextClick(Sender: TObject); +var + StaticText: TNewStaticText; + Link: String; + Err: Integer; +begin + StaticText := TNewStaticText(Sender); + Link := FindLinkInText(StaticText.Caption); + if Link = '' then + exit; + + ShellExec('open', Link, '', '', SW_SHOWNORMAL, ewNoWait, Err); +end; + +procedure MakeStaticTextClickable(StaticText: TNewStaticText); +begin + if FindLinkInText(StaticText.Caption) = '' then + exit; + + StaticText.OnClick := @OnStaticTextClick; + StaticText.Cursor := crHand; +end; + +function ChoicePageCreate( + const AfterID: Integer; + const Caption, Description, SubCaption, EditCaption: String; + HasDirectoryChooser: Boolean; + Prepare: TNotifyEvent; + SelectionChange: TNotifyEvent; + Validate: TWizardPageButtonEvent): TInputOptionWizardPage; +var + VSpace, Y : Integer; + ChoicePage: TInputOptionWizardPage; + InputLabel: TNewStaticText; + Input: TNewEdit; + Button: TNewButton; + +begin + ChoicePageMaxTag := ChoicePageMaxTag + 1; + VSpace := ScaleY(8); + ChoicePage := CreateInputOptionPage(AfterID, Caption, + Description, SubCaption, True, True); + + MakeStaticTextClickable(ChoicePage.SubCaptionLabel); + + ChoicePage.Tag := ChoicePageMaxTag; + ChoicePage.CheckListBox.OnClickCheck := @ChoicePageOnClickCheck; + ChoicePage.CheckListBox.Tag := ChoicePageMaxTag; + + if HasDirectoryChooser then + begin + ChoicePage.CheckListBox.Anchors := [ akLeft, akTop, akRight ]; + ChoicePage.CheckListBox.Height := ChoicePage.CheckListBox.Height - ScaleY(60); + Y := ChoicePage.CheckListBox.Top + ChoicePage.CheckListBox.Height + VSpace; + + InputLabel := TNewStaticText.Create(ChoicePage); + with InputLabel do + begin + Top := Y; + Anchors := [akTop, akLeft, akRight]; + Caption := EditCaption; + AutoSize := True; + Parent := ChoicePage.Surface; + Name := 'ChoicePageLabel'; + end; + MakeStaticTextClickable(InputLabel); + Y := Y + InputLabel.Height + VSpace; + + Input := TNewEdit.Create(ChoicePage); + with Input do + begin + Top := Y; + Anchors := [akTop, akLeft, akRight]; + Parent := ChoicePage.Surface; + Name := 'ChoicePageInput'; + Text := ''; + end; + + Button := TNewButton.Create(ChoicePage); + with Button do + begin + Anchors := [akTop, akRight]; + Parent := ChoicePage.Surface; + Width := WizardForm.NextButton.Width; + Height := WizardForm.NextButton.Height; + Top := Y - (Height - Input.Height) / 2; + Left := ChoicePage.SurfaceWidth - Button.Width; + Name := 'ChoicePageBrowseButton'; + Caption := SetupMessage(msgButtonWizardBrowse); + OnClick := @ChoicePageOnBrowseButtonClick; + end; + + Input.Width := Button.Left - ScaleX(8); + end; + + SetArrayLength(ChoicePages, ChoicePageMaxTag+1); + SetArrayLength(ChoicePagePrepare, ChoicePageMaxTag+1); + SetArrayLength(ChoicePageSelectionChange, ChoicePageMaxTag+1); + SetArrayLength(ChoicePageValidate, ChoicePageMaxTag+1); + + ChoicePages[ChoicePageMaxTag] := ChoicePage; + ChoicePagePrepare[ChoicePageMaxTag] := Prepare; + ChoicePageSelectionChange[ChoicePageMaxTag] := SelectionChange; + ChoicePageValidate[ChoicePageMaxTag] := Validate; + + Result := ChoicePage; +end; diff --git a/tools/windows/tool_setup/cmdline_page.iss.inc b/tools/windows/tool_setup/cmdline_page.iss.inc new file mode 100644 index 0000000000..fa5fdc63db --- /dev/null +++ b/tools/windows/tool_setup/cmdline_page.iss.inc @@ -0,0 +1,154 @@ +{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD + SPDX-License-Identifier: Apache-2.0 } + +{ ------------------------------ Progress & log page for command line tools ------------------------------ } + +var + CmdlineInstallCancel: Boolean; + +{ ------------------------------ Splitting strings into lines and adding them to TStrings ------------------------------ } + +procedure StringsAddLine(Dest: TStrings; Line: String; var ReplaceLastLine: Boolean); +begin + if ReplaceLastLine then + begin + Dest.Strings[Dest.Count - 1] := Line; + ReplaceLastLine := False; + end else begin + Dest.Add(Line); + end; +end; + +procedure StrSplitAppendToList(Text: String; Dest: TStrings; var LastLine: String); +var + pCR, pLF, Len: Integer; + Tmp: String; + ReplaceLastLine: Boolean; +begin + if Length(LastLine) > 0 then + begin + ReplaceLastLine := True; + Text := LastLine + Text; + end; + repeat + Len := Length(Text); + pLF := Pos(#10, Text); + pCR := Pos(#13, Text); + if (pLF > 0) and ((pCR = 0) or (pLF < pCR) or (pLF = pCR + 1)) then + begin + if pLF < pCR then + Tmp := Copy(Text, 1, pLF - 1) + else + Tmp := Copy(Text, 1, pLF - 2); + StringsAddLine(Dest, Tmp, ReplaceLastLine); + Text := Copy(Text, pLF + 1, Len) + end else begin + if (pCR = Len) or (pCR = 0) then + begin + break; + end; + Text := Copy(Text, pCR + 1, Len) + end; + until (pLF = 0) and (pCR = 0); + + LastLine := Text; + if pCR = Len then + begin + Text := Copy(Text, 1, pCR - 1); + end; + if Length(LastLine) > 0 then + begin + StringsAddLine(Dest, Text, ReplaceLastLine); + end; + +end; + +{ ------------------------------ The actual command line install page ------------------------------ } + +procedure OnCmdlineInstallCancel(Sender: TObject); +begin + CmdlineInstallCancel := True; +end; + +function DoCmdlineInstall(caption, description, command: String): Boolean; +var + CmdlineInstallPage: TOutputProgressWizardPage; + Res: Integer; + Handle: Longword; + ExitCode: Integer; + LogTextAnsi: AnsiString; + LogText, LeftOver: String; + Memo: TNewMemo; + PrevCancelButtonOnClick: TNotifyEvent; + +begin + CmdlineInstallPage := CreateOutputProgressPage('', '') + CmdlineInstallPage.Caption := caption; + CmdlineInstallPage.Description := description; + + Memo := TNewMemo.Create(CmdlineInstallPage); + Memo.Top := CmdlineInstallPage.ProgressBar.Top + CmdlineInstallPage.ProgressBar.Height + ScaleY(8); + Memo.Width := CmdlineInstallPage.SurfaceWidth; + Memo.Height := ScaleY(120); + Memo.ScrollBars := ssVertical; + Memo.Parent := CmdlineInstallPage.Surface; + Memo.Lines.Clear(); + + CmdlineInstallPage.Show(); + + try + WizardForm.CancelButton.Visible := True; + WizardForm.CancelButton.Enabled := True; + PrevCancelButtonOnClick := WizardForm.CancelButton.OnClick; + WizardForm.CancelButton.OnClick := @OnCmdlineInstallCancel; + + CmdlineInstallPage.SetProgress(0, 100); + CmdlineInstallPage.ProgressBar.Style := npbstMarquee; + + ExitCode := -1; + Memo.Lines.Append('Running command: ' + command); + Handle := ProcStart(command, ExpandConstant('{tmp}')) + if Handle = 0 then + begin + Log('ProcStart failed'); + ExitCode := -2; + end; + while (ExitCode = -1) and not CmdlineInstallCancel do + begin + ExitCode := ProcGetExitCode(Handle); + SetLength(LogTextAnsi, 4096); + Res := ProcGetOutput(Handle, LogTextAnsi, 4096) + if Res > 0 then + begin + SetLength(LogTextAnsi, Res); + LogText := LeftOver + String(LogTextAnsi); + StrSplitAppendToList(LogText, Memo.Lines, LeftOver); + end; + CmdlineInstallPage.SetProgress(0, 100); + Sleep(10); + end; + ProcEnd(Handle); + finally + Log('Done, exit code=' + IntToStr(ExitCode)); + Log('--------'); + Log(Memo.Lines.Text); + Log('--------'); + if CmdlineInstallCancel then + begin + MsgBox('Installation has been cancelled.', mbError, MB_OK); + Result := False; + end else if ExitCode <> 0 then + begin + MsgBox('Installation has failed with exit code ' + IntToStr(ExitCode), mbError, MB_OK); + Result := False; + end else begin + Result := True; + end; + CmdlineInstallPage.Hide; + CmdlineInstallPage.Free; + WizardForm.CancelButton.OnClick := PrevCancelButtonOnClick; + end; + if not Result then + RaiseException('Installation has failed at step: ' + caption); +end; + diff --git a/tools/windows/tool_setup/cmdlinerunner/CMakeLists.txt b/tools/windows/tool_setup/cmdlinerunner/CMakeLists.txt new file mode 100644 index 0000000000..1f4368a3fc --- /dev/null +++ b/tools/windows/tool_setup/cmdlinerunner/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.5) +project(cmdlinerunner) +set(CMAKE_EXE_LINKER_FLAGS " -static") +add_library(cmdlinerunner SHARED cmdlinerunner.c) +target_compile_definitions(cmdlinerunner PUBLIC UNICODE _UNICODE) +set_target_properties(cmdlinerunner PROPERTIES PREFIX "") +set_target_properties(cmdlinerunner PROPERTIES C_STANDARD 99) +target_link_libraries(cmdlinerunner "-static-libgcc") diff --git a/tools/windows/tool_setup/cmdlinerunner/cmdlinerunner.c b/tools/windows/tool_setup/cmdlinerunner/cmdlinerunner.c new file mode 100644 index 0000000000..0688ea4302 --- /dev/null +++ b/tools/windows/tool_setup/cmdlinerunner/cmdlinerunner.c @@ -0,0 +1,194 @@ +// Copyright 2019 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 + +#define CMDLINERUNNER_EXPORTS + +#include +#include +#include +#include "cmdlinerunner.h" + +#define LINESIZE 1024 + +#ifdef WITH_DEBUG +#include +#define DEBUGV(...) do { fprintf(stderr, __VA_ARG__); } while(0) +#else +#define DEBUGV(...) +#endif + +struct proc_instance_s { + PROCESS_INFORMATION child_process; + HANDLE pipe_server_handle; + HANDLE pipe_client_handle; +}; + +#ifdef WITH_DEBUG +static void print_last_error() +{ + DWORD dw; + TCHAR errmsg[LINESIZE]; + dw = GetLastError(); + + FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + errmsg, sizeof(errmsg) - 1, NULL ); + DEBUGV("error %d: %s\n", dw, errmsg); +} +#define PRINT_LAST_ERROR() print_last_error() +#else +#define PRINT_LAST_ERROR() +#endif + +static proc_instance_t *proc_instance_allocate() +{ + return (proc_instance_t*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(proc_instance_t)); +} + +static void proc_instance_free(proc_instance_t *instance) +{ + if (instance->pipe_server_handle) { + CloseHandle(instance->pipe_server_handle); + } + if (instance->pipe_client_handle) { + CloseHandle(instance->pipe_client_handle); + } + if (instance->child_process.hProcess) { + TerminateProcess(instance->child_process.hProcess, 1); + CloseHandle(instance->child_process.hProcess); + CloseHandle(instance->child_process.hThread); + } + HeapFree(GetProcessHeap(), 0, instance); +} + +void proc_end(proc_instance_t *inst) +{ + if (inst == NULL) { + return; + } + proc_instance_free(inst); +} + +CMDLINERUNNER_API proc_instance_t * proc_start(LPCTSTR cmdline, LPCTSTR workdir) +{ + proc_instance_t *inst = proc_instance_allocate(); + if (inst == NULL) { + return NULL; + } + + SECURITY_ATTRIBUTES sec_attr = { + .nLength = sizeof(SECURITY_ATTRIBUTES), + .bInheritHandle = TRUE, + .lpSecurityDescriptor = NULL + }; + + LPCTSTR pipename = TEXT("\\\\.\\pipe\\cmdlinerunner_pipe"); + + inst->pipe_server_handle = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX, + PIPE_TYPE_BYTE | PIPE_WAIT, 1, 1024 * 16, 1024 * 16, + NMPWAIT_WAIT_FOREVER, &sec_attr); + if (inst->pipe_server_handle == INVALID_HANDLE_VALUE) { + DEBUGV("inst->pipe_server_handle == INVALID_HANDLE_VALUE\n"); + goto error; + } + + inst->pipe_client_handle = CreateFile(pipename, GENERIC_WRITE | GENERIC_READ, + 0, &sec_attr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (inst->pipe_client_handle == INVALID_HANDLE_VALUE) { + DEBUGV("inst->pipe_client_handle == INVALID_HANDLE_VALUE\n"); + goto error; + } + + DWORD new_mode = PIPE_READMODE_BYTE | PIPE_NOWAIT; + if (!SetNamedPipeHandleState(inst->pipe_server_handle, &new_mode, NULL, + NULL)) { + DEBUGV("SetNamedPipeHandleState failed\n"); + goto error; + } + + if (!SetHandleInformation(inst->pipe_server_handle, HANDLE_FLAG_INHERIT, 0)) { + DEBUGV("SetHandleInformation failed\n"); + goto error; + } + + if (!SetHandleInformation(inst->pipe_client_handle, HANDLE_FLAG_INHERIT, + HANDLE_FLAG_INHERIT)) { + DEBUGV("SetHandleInformation failed\n"); + goto error; + } + + STARTUPINFO siStartInfo = { + .cb = sizeof(STARTUPINFO), + .hStdError = inst->pipe_client_handle, + .hStdOutput = inst->pipe_client_handle, + .hStdInput = inst->pipe_client_handle, + .dwFlags = STARTF_USESTDHANDLES + }; + + size_t workdir_len = 0; + StringCbLength(workdir, STRSAFE_MAX_CCH * sizeof(TCHAR), &workdir_len); + if (workdir_len == 0) { + workdir = NULL; + } + + TCHAR cmdline_tmp[LINESIZE]; + StringCbCopy(cmdline_tmp, sizeof(cmdline_tmp), cmdline); + if (!CreateProcess(NULL, cmdline_tmp, + NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, workdir, &siStartInfo, + &inst->child_process)) { + DEBUGV("CreateProcess failed\n"); + goto error; + } + return inst; + +error: + PRINT_LAST_ERROR(); + proc_instance_free(inst); + return NULL; +} + +int proc_get_exit_code(proc_instance_t *inst) +{ + DWORD result; + if (!GetExitCodeProcess(inst->child_process.hProcess, &result)) { + return -2; + } + if (result == STILL_ACTIVE) { + return -1; + } + return (int) result; +} + +DWORD proc_get_output(proc_instance_t *inst, LPSTR dest, DWORD sz) +{ + DWORD read_bytes; + BOOL res = ReadFile(inst->pipe_server_handle, dest, + sz - 1, &read_bytes, NULL); + if (!res) { + if (GetLastError() == ERROR_NO_DATA) { + return 0; + } else { + PRINT_LAST_ERROR(); + return 0; + } + } + dest[read_bytes] = 0; + return read_bytes; +} + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved ) +{ + return TRUE; +} + diff --git a/tools/windows/tool_setup/cmdlinerunner/cmdlinerunner.h b/tools/windows/tool_setup/cmdlinerunner/cmdlinerunner.h new file mode 100644 index 0000000000..bdfdf2dc3f --- /dev/null +++ b/tools/windows/tool_setup/cmdlinerunner/cmdlinerunner.h @@ -0,0 +1,32 @@ +// Copyright 2019 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 + +#include + +struct proc_instance_s; +typedef struct proc_instance_s proc_instance_t; + +#ifdef CMDLINERUNNER_EXPORTS +#define CMDLINERUNNER_API __declspec(dllexport) +#else +#define CMDLINERUNNER_API __declspec(dllimport) +#endif + +CMDLINERUNNER_API proc_instance_t * proc_start(LPCTSTR cmdline, LPCTSTR workdir); +CMDLINERUNNER_API int proc_get_exit_code(proc_instance_t *inst); +CMDLINERUNNER_API DWORD proc_get_output(proc_instance_t *inst, LPSTR dest, DWORD sz); +CMDLINERUNNER_API void proc_end(proc_instance_t *inst); +CMDLINERUNNER_API BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved ); diff --git a/tools/windows/tool_setup/cmdlinerunner/toolchain-i686-w64-mingw32.cmake b/tools/windows/tool_setup/cmdlinerunner/toolchain-i686-w64-mingw32.cmake new file mode 100644 index 0000000000..8e9acb4ae6 --- /dev/null +++ b/tools/windows/tool_setup/cmdlinerunner/toolchain-i686-w64-mingw32.cmake @@ -0,0 +1,7 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR x86) +set(CMAKE_C_COMPILER i686-w64-mingw32-gcc) +set(CMAKE_CXX_COMPILER i686-w64-mingw32-g++) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/tools/windows/tool_setup/git_find_installed.iss.inc b/tools/windows/tool_setup/git_find_installed.iss.inc new file mode 100644 index 0000000000..328294cdd0 --- /dev/null +++ b/tools/windows/tool_setup/git_find_installed.iss.inc @@ -0,0 +1,98 @@ +{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD + SPDX-License-Identifier: Apache-2.0 } + +{ ------------------------------ Find installed copies of Git ------------------------------ } + +var + InstalledGitVersions: TStringList; + InstalledGitDisplayNames: TStringList; + InstalledGitExecutables: TStringList; + + +procedure GitVersionAdd(Version, DisplayName, Executable: String); +begin + Log('Adding Git version=' + Version + ' name='+DisplayName+' executable='+Executable); + InstalledGitVersions.Append(Version); + InstalledGitDisplayNames.Append(DisplayName); + InstalledGitExecutables.Append(Executable); +end; + +function GetVersionOfGitExe(Path: String; var Version: String; var ErrStr: String): Boolean; +var + VersionOutputFile: String; + Args: String; + GitVersionAnsi: AnsiString; + GitVersion: String; + GitVersionPrefix: String; + Err: Integer; +begin + VersionOutputFile := ExpandConstant('{tmp}\gitver.txt'); + + DeleteFile(VersionOutputFile); + Args := '/C "' + Path + '" --version >gitver.txt'; + Log('Running ' + Args); + if not ShellExec('', 'cmd.exe', Args, + ExpandConstant('{tmp}'), SW_HIDE, ewWaitUntilTerminated, Err) then + begin + ErrStr := 'Failed to get git version, error=' + IntToStr(err); + Log(ErrStr); + Result := False; + exit; + end; + + LoadStringFromFile(VersionOutputFile, GitVersionAnsi); + GitVersion := Trim(String(GitVersionAnsi)); + GitVersionPrefix := 'git version '; + if Pos(GitVersionPrefix, GitVersion) <> 1 then + begin + ErrStr := 'Unexpected git version format: ' + GitVersion; + Log(ErrStr); + Result := False; + exit; + end; + + Delete(GitVersion, 1, Length(GitVersionPrefix)); + Version := GitVersion; + Result := True; +end; + +procedure FindGitInPath(); +var + Args: String; + GitListFile: String; + GitPaths: TArrayOfString; + GitVersion: String; + ErrStr: String; + Err: Integer; + i: Integer; +begin + GitListFile := ExpandConstant('{tmp}\gitlist.txt'); + Args := '/C where git.exe >"' + GitListFile + '"'; + if not ShellExec('', 'cmd.exe', Args, + '', SW_HIDE, ewWaitUntilTerminated, Err) then + begin + Log('Failed to find git using "where", error='+IntToStr(Err)); + exit; + end; + + LoadStringsFromFile(GitListFile, GitPaths); + + for i:= 0 to GetArrayLength(GitPaths) - 1 do + begin + Log('Git path: ' + GitPaths[i]); + if not GetVersionOfGitExe(GitPaths[i], GitVersion, ErrStr) then + continue; + + Log('Git version: ' + GitVersion); + GitVersionAdd(GitVersion, GitVersion, GitPaths[i]); + end; +end; + +procedure FindInstalledGitVersions(); +begin + InstalledGitVersions := TStringList.Create(); + InstalledGitDisplayNames := TStringList.Create(); + InstalledGitExecutables := TStringList.Create(); + + FindGitInPath(); +end; diff --git a/tools/windows/tool_setup/git_page.iss.inc b/tools/windows/tool_setup/git_page.iss.inc new file mode 100644 index 0000000000..b9c1ef7d0f --- /dev/null +++ b/tools/windows/tool_setup/git_page.iss.inc @@ -0,0 +1,194 @@ +{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD + SPDX-License-Identifier: Apache-2.0 } + +{ ------------------------------ Page to select Git ------------------------------ } + +#include "git_find_installed.iss.inc" + +var + GitPage: TInputOptionWizardPage; + GitPath, GitExecutablePath, GitVersion: String; + GitUseExisting: Boolean; + GitSelectionInstallIndex: Integer; + GitSelectionCustomPathIndex: Integer; + +function GetGitPath(Unused: String): String; +begin + Result := GitPath; +end; + +function GitInstallRequired(): Boolean; +begin + Result := not GitUseExisting; +end; + +function GitVersionSupported(Version: String): Boolean; +var + Major, Minor: Integer; +begin + Result := False; + if not VersionExtractMajorMinor(Version, Major, Minor) then + begin + Log('GitVersionSupported: Could not parse version=' + Version); + exit; + end; + + { Need at least git 2.12 for 'git clone --reference' to work with submodules } + if (Major = 2) and (Minor >= 12) then Result := True; + if (Major > 2) then Result := True; +end; + +procedure GitCustomPathUpdateEnabled(); +var + Enable: Boolean; +begin + if GitPage.SelectedValueIndex = GitSelectionCustomPathIndex then + Enable := True; + + ChoicePageSetInputEnabled(GitPage, Enable); +end; + +procedure OnGitPagePrepare(Sender: TObject); +var + Page: TInputOptionWizardPage; + FullName: String; + i, Index, FirstEnabledIndex: Integer; + OfferToInstall: Boolean; + VersionToInstall: String; + VersionSupported: Boolean; +begin + Page := TInputOptionWizardPage(Sender); + Log('OnGitPagePrepare'); + if Page.CheckListBox.Items.Count > 0 then + exit; + + FindInstalledGitVersions(); + + VersionToInstall := '{#GitVersion}'; + OfferToInstall := True; + FirstEnabledIndex := -1; + + for i := 0 to InstalledGitVersions.Count - 1 do + begin + VersionSupported := GitVersionSupported(InstalledGitVersions[i]); + FullName := InstalledGitDisplayNames.Strings[i]; + if not VersionSupported then + begin + FullName := FullName + ' (unsupported)'; + end; + FullName := FullName + #13#10 + InstalledGitExecutables.Strings[i]; + Index := Page.Add(FullName); + if not VersionSupported then + begin + Page.CheckListBox.ItemEnabled[Index] := False; + end else begin + if FirstEnabledIndex < 0 then FirstEnabledIndex := Index; + end; + if InstalledGitVersions[i] = VersionToInstall then + begin + OfferToInstall := False; + end; + end; + + if OfferToInstall then + begin + Index := Page.Add('Install Git ' + VersionToInstall); + if FirstEnabledIndex < 0 then FirstEnabledIndex := Index; + GitSelectionInstallIndex := Index; + end; + + Index := Page.Add('Custom git.exe location'); + if FirstEnabledIndex < 0 then FirstEnabledIndex := Index; + GitSelectionCustomPathIndex := Index; + + Page.SelectedValueIndex := FirstEnabledIndex; + GitCustomPathUpdateEnabled(); +end; + +procedure OnGitSelectionChange(Sender: TObject); +var + Page: TInputOptionWizardPage; +begin + Page := TInputOptionWizardPage(Sender); + Log('OnGitSelectionChange index=' + IntToStr(Page.SelectedValueIndex)); + GitCustomPathUpdateEnabled(); +end; + +function OnGitPageValidate(Sender: TWizardPage): Boolean; +var + Page: TInputOptionWizardPage; + Version, ErrStr: String; +begin + Page := TInputOptionWizardPage(Sender); + Log('OnGitPageValidate index=' + IntToStr(Page.SelectedValueIndex)); + if Page.SelectedValueIndex = GitSelectionInstallIndex then + begin + GitUseExisting := False; + GitExecutablePath := ''; + GitPath := ''; + GitVersion := '{#GitVersion}'; + Result := True; + end else if Page.SelectedValueIndex = GitSelectionCustomPathIndex then + begin + GitPath := ChoicePageGetInputText(Page); + GitExecutablePath := GitPath + '\git.exe'; + if not FileExists(GitExecutablePath) then + begin + MsgBox('Can not find git.exe in ' + GitPath, mbError, MB_OK); + Result := False; + exit; + end; + + if not GetVersionOfGitExe(GitExecutablePath, Version, ErrStr) then + begin + MsgBox('Can not determine version of git.exe.' + #13#10 + + 'Please check that this copy of git works from cmd.exe.', mbError, MB_OK); + Result := False; + exit; + end; + Log('Version of ' + GitExecutablePath + ' is ' + Version); + if not GitVersionSupported(Version) then + begin + MsgBox('Selected git version (' + Version + ') is not supported.', mbError, MB_OK); + Result := False; + exit; + end; + Log('Version of git is supported'); + GitUseExisting := True; + GitVersion := Version; + end else begin + GitUseExisting := True; + GitExecutablePath := InstalledGitExecutables[Page.SelectedValueIndex]; + GitPath := ExtractFilePath(GitExecutablePath); + GitVersion := InstalledGitVersions[Page.SelectedValueIndex]; + Result := True; + end; +end; + +procedure GitExecutablePathUpdateAfterInstall(); +var + GitInstallPath: String; +begin + GitInstallPath := GetInstallPath('SOFTWARE\GitForWindows', 'InstallPath'); + if GitInstallPath = '' then + begin + Log('Failed to find Git install path'); + exit; + end; + GitPath := GitInstallPath + '\cmd'; + GitExecutablePath := GitPath + '\git.exe'; +end; + + +procedure CreateGitPage(); +begin + GitPage := ChoicePageCreate( + wpLicense, + 'Git choice', 'Please choose Git version', + 'Available Git versions', + 'Enter custom location of git.exe', + True, + @OnGitPagePrepare, + @OnGitSelectionChange, + @OnGitPageValidate); +end; diff --git a/tools/windows/tool_setup/idf_cmd_init.bat b/tools/windows/tool_setup/idf_cmd_init.bat new file mode 100644 index 0000000000..853dcf4da7 --- /dev/null +++ b/tools/windows/tool_setup/idf_cmd_init.bat @@ -0,0 +1,117 @@ +@echo off + +:: This script is called from a shortcut (cmd.exe /k export_fallback.bat), with +:: the working directory set to an ESP-IDF directory. +:: Its purpose is to support using the "IDF Tools Directory" method of +:: installation for ESP-IDF versions older than IDF v4.0. +:: It does the same thing as "export.bat" in IDF v4.0. + +set IDF_PATH=%CD% +if not exist "%IDF_PATH%\tools\idf.py" ( + echo This script must be invoked from ESP-IDF directory. + goto :end +) + +if "%~2"=="" ( + echo Usage: idf_cmd_init.bat ^ ^ + echo This script must be invoked from ESP-IDF directory. + goto :end +) + +set IDF_PYTHON_DIR=%1 +set IDF_GIT_DIR=%2 + +:: Strip quoutes +set "IDF_PYTHON_DIR=%IDF_PYTHON_DIR:"=%" +set "IDF_GIT_DIR=%IDF_GIT_DIR:"=%" + +:: Clear PYTHONPATH as it may contain libraries of other Python versions +if not "%PYTHONPATH%"=="" ( + echo Clearing PYTHONPATH, was set to %PYTHONPATH% + set PYTHONPATH= +) + +:: Add Python and Git paths to PATH +set "PATH=%IDF_PYTHON_DIR%;%IDF_GIT_DIR%;%PATH%" +echo Using Python in %IDF_PYTHON_DIR% +python.exe --version +echo Using Git in %IDF_GIT_DIR% +git.exe --version + +:: Check if this is a recent enough copy of ESP-IDF. +:: If so, use export.bat provided there. +:: Note: no "call", will not return into this batch file. +if exist "%IDF_PATH%\export.bat" %IDF_PATH%\export.bat + +echo IDF version does not include export.bat. Using the fallback version. + +if exist "%IDF_PATH%\tools\tools.json" ( + set "IDF_TOOLS_JSON_PATH=%IDF_PATH%\tools\tools.json" +) else ( + echo IDF version does not include tools\tools.json. Using the fallback version. + set "IDF_TOOLS_JSON_PATH=%~dp0%tools_fallback.json" +) + +if exist "%IDF_PATH%\tools\idf_tools.py" ( + set "IDF_TOOLS_PY_PATH=%IDF_PATH%\tools\idf_tools.py" +) else ( + echo IDF version does not include tools\idf_tools.py. Using the fallback version. + set "IDF_TOOLS_PY_PATH=%~dp0%idf_tools_fallback.py" +) + +echo. +echo Setting IDF_PATH: %IDF_PATH% +echo. + +set "OLD_PATH=%PATH%" +echo Adding ESP-IDF tools to PATH... +:: Export tool paths and environment variables. +:: It is possible to do this without a temporary file (running idf_tools.py from for /r command), +:: but that way it is impossible to get the exit code of idf_tools.py. +set "IDF_TOOLS_EXPORTS_FILE=%TEMP%\idf_export_vars.tmp" +python.exe %IDF_TOOLS_PY_PATH% --tools-json %IDF_TOOLS_JSON_PATH% export --format key-value >"%IDF_TOOLS_EXPORTS_FILE%" +if %errorlevel% neq 0 goto :end + +for /f "usebackq tokens=1,2 eol=# delims==" %%a in ("%IDF_TOOLS_EXPORTS_FILE%") do ( + call set "%%a=%%b" + ) + +:: This removes OLD_PATH substring from PATH, leaving only the paths which have been added, +:: and prints semicolon-delimited components of the path on separate lines +call set PATH_ADDITIONS=%%PATH:%OLD_PATH%=%% +if "%PATH_ADDITIONS%"=="" call :print_nothing_added +if not "%PATH_ADDITIONS%"=="" echo %PATH_ADDITIONS:;=&echo. % + +echo Checking if Python packages are up to date... +python.exe %IDF_PATH%\tools\check_python_dependencies.py +if %errorlevel% neq 0 goto :end + +echo. +echo Done! You can now compile ESP-IDF projects. +echo Go to the project directory and run: +echo. +echo idf.py build +echo. + +goto :end + +:print_nothing_added + echo No directories added to PATH: + echo. + echo %PATH% + echo. + goto :eof + +:end + +:: Clean up +if not "%IDF_TOOLS_EXPORTS_FILE%"=="" ( + del "%IDF_TOOLS_EXPORTS_FILE%" 1>nul 2>nul +) +set IDF_TOOLS_EXPORTS_FILE= +set IDF_PYTHON_DIR= +set IDF_GIT_DIR= +set IDF_TOOLS_PY_PATH= +set IDF_TOOLS_JSON_PATH= +set OLD_PATH= +set PATH_ADDITIONS= diff --git a/tools/windows/tool_setup/idf_download_page.iss.inc b/tools/windows/tool_setup/idf_download_page.iss.inc new file mode 100644 index 0000000000..3636123e7e --- /dev/null +++ b/tools/windows/tool_setup/idf_download_page.iss.inc @@ -0,0 +1,142 @@ +{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD + SPDX-License-Identifier: Apache-2.0 } + +{ ------------------------------ Page to select the version of ESP-IDF to download ------------------------------ } + +var + IDFDownloadPage: TInputOptionWizardPage; + IDFDownloadAvailableVersions: TArrayOfString; + IDFDownloadPath, IDFDownloadVersion: String; + +function GetSuggestedIDFDirectory(): String; +var +BaseName: String; +RepeatIndex: Integer; +begin + { Start with Desktop\esp-idf name and if it already exists, + keep trying with Desktop\esp-idf-N for N=2 and above. } + BaseName := ExpandConstant('{userdesktop}\esp-idf'); + Result := BaseName; + RepeatIndex := 1; + while DirExists(Result) do + begin + RepeatIndex := RepeatIndex + 1; + Result := BaseName + '-' + IntToStr(RepeatIndex); + end; +end; + +function GetIDFVersionDescription(Version: String): String; +begin + if WildCardMatch(Version, 'v*-beta*') then + Result := 'beta version' + else if WildCardMatch(Version, 'v*-rc*') then + Result := 'pre-release version' + else if WildCardMatch(Version, 'v*') then + Result := 'release version' + else if WildCardMatch(Version, 'release/v*') then + Result := 'release branch' + else if WildCardMatch(Version, 'master') then + Result := 'development branch' + else + Result := ''; +end; + +procedure DownloadIDFVersionsList(); +var + Url: String; + VersionFile: String; +begin + Url := '{#IDFVersionsURL}'; + VersionFile := ExpandConstant('{tmp}\idf_versions.txt'); + if idpDownloadFile(Url, VersionFile) then + begin + Log('Downloaded ' + Url + ' to ' + VersionFile); + end else begin + Log('Download of ' + Url + ' failed, using a fallback versions list'); + ExtractTemporaryFile('idf_versions.txt'); + end; +end; + +procedure OnIDFDownloadPagePrepare(Sender: TObject); +var + Page: TInputOptionWizardPage; + VersionFile: String; + i: Integer; +begin + Page := TInputOptionWizardPage(Sender); + Log('OnIDFDownloadPagePrepare'); + if Page.CheckListBox.Items.Count > 0 then + exit; + + DownloadIDFVersionsList(); + + VersionFile := ExpandConstant('{tmp}\idf_versions.txt'); + if not LoadStringsFromFile(VersionFile, IDFDownloadAvailableVersions) then + begin + Log('Failed to load versions from ' + VersionFile); + exit; + end; + + Log('Versions count: ' + IntToStr(GetArrayLength(IDFDownloadAvailableVersions))) + for i := 0 to GetArrayLength(IDFDownloadAvailableVersions) - 1 do + begin + Log('Version ' + IntToStr(i) + ': ' + IDFDownloadAvailableVersions[i]); + Page.Add(IDFDownloadAvailableVersions[i] + ' (' + + GetIDFVersionDescription(IDFDownloadAvailableVersions[i]) + ')'); + end; + Page.SelectedValueIndex := 0; + + ChoicePageSetInputText(Page, GetSuggestedIDFDirectory()); +end; + +procedure OnIDFDownloadSelectionChange(Sender: TObject); +var + Page: TInputOptionWizardPage; +begin + Page := TInputOptionWizardPage(Sender); + Log('OnIDFDownloadSelectionChange index=' + IntToStr(Page.SelectedValueIndex)); +end; + +function OnIDFDownloadPageValidate(Sender: TWizardPage): Boolean; +var + Page: TInputOptionWizardPage; + IDFPath: String; +begin + Page := TInputOptionWizardPage(Sender); + Log('OnIDFDownloadPageValidate index=' + IntToStr(Page.SelectedValueIndex)); + + IDFPath := ChoicePageGetInputText(Page); + if DirExists(IDFPath) and not DirIsEmpty(IDFPath) then + begin + MsgBox('Directory already exists and is not empty:' + #13#10 + + IDFPath + #13#10 + 'Please choose a different directory.', mbError, MB_OK); + Result := False; + exit; + end; + + IDFDownloadPath := IDFPath; + IDFDownloadVersion := IDFDownloadAvailableVersions[Page.SelectedValueIndex]; + Result := True; +end; + + +function ShouldSkipIDFDownloadPage(PageID: Integer): Boolean; +begin + if (PageID = IDFDownloadPage.ID) and not IDFDownloadRequired() then + Result := True; +end; + + +procedure CreateIDFDownloadPage(); +begin + IDFDownloadPage := ChoicePageCreate( + IDFPage.ID, + 'Download ESP-IDF', 'Please choose ESP-IDF version to download', + 'For more information about ESP-IDF versions, see' + #13#10 + + 'https://docs.espressif.com/projects/esp-idf/en/latest/versions.html', + 'Choose a directory to download ESP-IDF to', + True, + @OnIDFDownloadPagePrepare, + @OnIDFDownloadSelectionChange, + @OnIDFDownloadPageValidate); +end; diff --git a/tools/windows/tool_setup/idf_page.iss.inc b/tools/windows/tool_setup/idf_page.iss.inc new file mode 100644 index 0000000000..87cc5c5d07 --- /dev/null +++ b/tools/windows/tool_setup/idf_page.iss.inc @@ -0,0 +1,111 @@ +{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD + SPDX-License-Identifier: Apache-2.0 } + +{ ------------------------------ Page to select whether to download ESP-IDF, or use an existing copy ------------------------------ } + +var + IDFPage: TInputOptionWizardPage; + IDFSelectionDownloadIndex: Integer; + IDFSelectionCustomPathIndex: Integer; + IDFUseExisting: Boolean; + IDFExistingPath: String; + +function IDFDownloadRequired(): Boolean; +begin + Result := not IDFUseExisting; +end; + +procedure IDFPageUpdateInput(); +var + Enable: Boolean; +begin + if IDFPage.SelectedValueIndex = IDFSelectionCustomPathIndex then + Enable := True; + + ChoicePageSetInputEnabled(IDFPage, Enable); +end; + +procedure OnIDFPagePrepare(Sender: TObject); +var + Page: TInputOptionWizardPage; +begin + Page := TInputOptionWizardPage(Sender); + Log('OnIDFPagePrepare'); + if Page.CheckListBox.Items.Count > 0 then + exit; + + IDFSelectionDownloadIndex := Page.Add('Download ESP-IDF') + IDFSelectionCustomPathIndex := Page.Add('Use an existing ESP-IDF directory'); + + Page.SelectedValueIndex := 0; + IDFPageUpdateInput(); +end; + +procedure OnIDFSelectionChange(Sender: TObject); +var + Page: TInputOptionWizardPage; +begin + Page := TInputOptionWizardPage(Sender); + Log('OnIDFSelectionChange index=' + IntToStr(Page.SelectedValueIndex)); + IDFPageUpdateInput(); +end; + +function OnIDFPageValidate(Sender: TWizardPage): Boolean; +var + Page: TInputOptionWizardPage; + NotSupportedMsg, IDFPath, IDFPyPath, RequirementsPath: String; +begin + Page := TInputOptionWizardPage(Sender); + Log('OnIDFPageValidate index=' + IntToStr(Page.SelectedValueIndex)); + + if Page.SelectedValueIndex = IDFSelectionDownloadIndex then + begin + IDFUseExisting := False; + Result := True; + end else begin + IDFUseExisting := True; + Result := False; + NotSupportedMsg := 'The selected version of ESP-IDF is not supported:' + #13#10; + IDFPath := ChoicePageGetInputText(Page); + + if not DirExists(IDFPath) then + begin + MsgBox('Directory doesn''t exist: ' + IDFPath + #13#10 + + 'Please choose an existing ESP-IDF directory', mbError, MB_OK); + exit; + end; + + IDFPyPath := IDFPath + '\tools\idf.py'; + if not FileExists(IDFPyPath) then + begin + MsgBox(NotSupportedMsg + + 'Can not find idf.py in ' + IDFPath + '\tools', mbError, MB_OK); + exit; + end; + + RequirementsPath := IDFPath + '\requirements.txt'; + if not FileExists(RequirementsPath) then + begin + MsgBox(NotSupportedMsg + + 'Can not find requirements.txt in ' + IDFPath, mbError, MB_OK); + exit; + end; + + IDFExistingPath := IDFPath; + Result := True; + end; +end; + + +procedure CreateIDFPage(); +begin + IDFPage := ChoicePageCreate( + wpLicense, + 'Download or use ESP-IDF', 'Please choose ESP-IDF version to download, or use an existing ESP-IDF copy', + 'Available ESP-IDF versions', + 'Choose existing ESP-IDF directory', + True, + @OnIDFPagePrepare, + @OnIDFSelectionChange, + @OnIDFPageValidate); +end; diff --git a/tools/windows/tool_setup/idf_setup.iss.inc b/tools/windows/tool_setup/idf_setup.iss.inc new file mode 100644 index 0000000000..30c626a8dc --- /dev/null +++ b/tools/windows/tool_setup/idf_setup.iss.inc @@ -0,0 +1,255 @@ +{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD + SPDX-License-Identifier: Apache-2.0 } + +{ ------------------------------ Downloading ESP-IDF ------------------------------ } + +var + IDFZIPFileVersion, IDFZIPFileName: String; + +function GetIDFPath(Unused: String): String; +begin + if IDFUseExisting then + Result := IDFExistingPath + else + Result := IDFDownloadPath; +end; + +function GetIDFZIPFileVersion(Version: String): String; +var + ReleaseVerPart: String; + i: Integer; + Found: Boolean; +begin + if WildCardMatch(Version, 'v*') or WildCardMatch(Version, 'v*-rc*') then + Result := Version + else if Version = 'master' then + Result := '' + else if WildCardMatch(Version, 'release/v*') then + begin + ReleaseVerPart := Version; + Log('ReleaseVerPart=' + ReleaseVerPart) + Delete(ReleaseVerPart, 1, Length('release/')); + Log('ReleaseVerPart=' + ReleaseVerPart) + Found := False; + for i := 0 to GetArrayLength(IDFDownloadAvailableVersions) - 1 do + begin + if Pos(ReleaseVerPart, IDFDownloadAvailableVersions[i]) = 1 then + begin + Result := IDFDownloadAvailableVersions[i]; + Found := True; + break; + end; + end; + if not Found then + Result := ''; + end; + Log('GetIDFZIPFileVersion(' + Version + ')=' + Result); +end; + +procedure IDFAddDownload(); +var + Url, MirrorUrl: String; +begin + IDFZIPFileVersion := GetIDFZIPFileVersion(IDFDownloadVersion); + if IDFZIPFileVersion <> '' then + begin + Url := 'https://github.com/espressif/esp-idf/releases/download/' + IDFZIPFileVersion + '/esp-idf-' + IDFZIPFileVersion + '.zip'; + MirrorUrl := 'https://dl.espressif.com/dl/esp-idf/releases/esp-idf-' + IDFZIPFileVersion + '.zip'; + IDFZIPFileName := ExpandConstant('{app}\releases\esp-idf-' + IDFZIPFileVersion + '.zip') + if not FileExists(IDFZIPFileName) then + begin + ForceDirectories(ExpandConstant('{app}\releases')) + Log('Adding download: ' + Url + ', mirror: ' + MirrorUrl + ', destination: ' + IDFZIPFileName); + idpAddFile(Url, IDFZIPFileName); + idpAddMirror(Url, MirrorUrl); + end else begin + Log(IDFZIPFileName + ' already exists') + end; + end; +end; + +procedure RemoveAlternatesFile(Path: String); +begin + Log('Removing ' + Path); + DeleteFile(Path); +end; + +{ + Replacement of the '--dissociate' flag of 'git clone', to support older versions of Git. + '--reference' is supported for submodules since git 2.12, but '--dissociate' only from 2.18. +} +procedure GitRepoDissociate(Path: String); +var + CmdLine: String; +begin + CmdLine := GitExecutablePath + ' -C ' + Path + ' repack -d -a' + DoCmdlineInstall('Finishing ESP-IDF installation', 'Re-packing the repository', CmdLine); + CmdLine := GitExecutablePath + ' -C ' + Path + ' submodule foreach git repack -d -a' + DoCmdlineInstall('Finishing ESP-IDF installation', 'Re-packing the submodules', CmdLine); + + FindFileRecusive(Path + '\.git', 'alternates', @RemoveAlternatesFile); +end; + +{ Run git reset --hard in the repo and in the submodules, to fix the newlines. } +procedure GitRepoFixNewlines(Path: String); +var + CmdLine: String; +begin + CmdLine := GitExecutablePath + ' -C ' + Path + ' reset --hard'; + Log('Resetting the repository: ' + CmdLine); + DoCmdlineInstall('Finishing ESP-IDF installation', 'Updating newlines', CmdLine); + + Log('Resetting the submodules: ' + CmdLine); + CmdLine := GitExecutablePath + ' -C ' + Path + ' submodule foreach git reset --hard'; + DoCmdlineInstall('Finishing ESP-IDF installation', 'Updating newlines in submodules', CmdLine); +end; + +{ + There are 3 possible ways how an ESP-IDF copy can be obtained: + - Download the .zip archive with submodules included, extract to destination directory, + then do 'git reset --hard' and 'git submodule foreach git reset --hard' to correct for + possibly different newlines. This is done for release versions. + - Do a git clone of the Github repository into the destination directory. + This is done for the master branch. + - Download the .zip archive of a "close enough" release version, extract into a temporary + directory. Then do a git clone of the Github repository, using the temporary directory + as a '--reference'. This is done for other versions (such as release branches). +} + +procedure IDFDownload(); +var + CmdLine: String; + IDFTempPath: String; + IDFPath: String; + NeedToClone: Boolean; + Res: Boolean; + +begin + IDFPath := IDFDownloadPath; + { If there is a release archive to download, IDFZIPFileName and IDFZIPFileVersion will be set. + See GetIDFZIPFileVersion function. + } + + if IDFZIPFileName <> '' then + begin + if IDFZIPFileVersion <> IDFDownloadVersion then + begin + { The version of .zip file downloaded is not the same as the version the user has requested. + Will use 'git clone --reference' to obtain the correct version, using the contents + of the .zip file as reference. + } + NeedToClone := True; + end; + + ExtractTemporaryFile('7za.exe') + CmdLine := ExpandConstant('{tmp}\7za.exe x -o' + ExpandConstant('{tmp}') + ' -r -aoa ' + IDFZIPFileName); + IDFTempPath := ExpandConstant('{tmp}\esp-idf-') + IDFZIPFileVersion; + Log('Extracting ESP-IDF reference repository: ' + CmdLine); + Log('Reference repository path: ' + IDFTempPath); + DoCmdlineInstall('Extracting ESP-IDF', 'Setting up reference repository', CmdLine); + end else begin + { IDFZIPFileName is not set, meaning that we will rely on 'git clone'. } + NeedToClone := True; + Log('Not .zip release archive. Will do full clone.'); + end; + + if NeedToClone then + begin + CmdLine := GitExecutablePath + ' clone --recursive --progress -b ' + IDFDownloadVersion; + + if IDFTempPath <> '' then + CmdLine := CmdLine + ' --reference ' + IDFTempPath; + + CmdLine := CmdLine + ' https://github.com/espressif/esp-idf.git ' + IDFPath; + Log('Cloning IDF: ' + CmdLine); + DoCmdlineInstall('Downloading ESP-IDF', 'Using git to clone ESP-IDF repository', CmdLine); + + if IDFTempPath <> '' then + GitRepoDissociate(IDFPath); + + end else begin + Log('Moving ' + IDFTempPath + ' to ' + IDFPath); + if DirExists(IDFPath) then + begin + if not DirIsEmpty(IDFPath) then + begin + MsgBox('Destination directory exists and is not empty: ' + IDFPath, mbError, MB_OK); + RaiseException('Failed to copy ESP-IDF') + end; + + Res := RemoveDir(IDFPath); + if not Res then + begin + MsgBox('Failed to remove destination directory: ' + IDFPath, mbError, MB_OK); + RaiseException('Failed to copy ESP-IDF') + end; + end; + Res := RenameFile(IDFTempPath, IDFPath); + if not Res then + begin + MsgBox('Failed to copy ESP-IDF to the destination directory: ' + IDFPath, mbError, MB_OK); + RaiseException('Failed to copy ESP-IDF'); + end; + GitRepoFixNewlines(IDFPath); + end; +end; + +{ ------------------------------ IDF Tools setup, Python environment setup ------------------------------ } + +procedure IDFToolsSetup(); +var + CmdLine: String; + IDFPath: String; + IDFToolsPyPath: String; + IDFToolsPyCmd: String; +begin + IDFPath := GetIDFPath(''); + IDFToolsPyPath := IDFPath + '\tools\idf_tools.py'; + if FileExists(IDFToolsPyPath) then + begin + Log('idf_tools.py exists in IDF directory'); + IDFToolsPyCmd := PythonExecutablePath + ' ' + IDFToolsPyPath; + end else begin + Log('idf_tools.py does not exist in IDF directory, using a fallback version'); + IDFToolsPyCmd := ExpandConstant(PythonExecutablePath + + ' {app}\idf_tools_fallback.py' + + ' --idf-path ' + IDFPath + + ' --tools {app}\tools_fallback.json'); + end; + + Log('idf_tools.py command: ' + IDFToolsPyCmd); + CmdLine := IDFToolsPyCmd + ' install'; + Log('Installing tools:' + CmdLine); + DoCmdlineInstall('Installing ESP-IDF tools', '', CmdLine); + + CmdLine := IDFToolsPyCmd + ' install-python-env'; + Log('Installing Python environment:' + CmdLine); + DoCmdlineInstall('Installing Python environment', '', CmdLine); +end; + +{ ------------------------------ Start menu shortcut ------------------------------ } + +procedure CreateIDFCommandPromptShortcut(); +var + Destination: String; + Description: String; + Command: String; +begin + ForceDirectories(ExpandConstant('{group}')); + Destination := ExpandConstant('{group}\{#IDFCmdExeShortcutFile}'); + Description := '{#IDFCmdExeShortcutDescription}'; + Command := ExpandConstant('/k {app}\idf_cmd_init.bat "') + PythonPath + '" "' + GitPath + '"'; + Log('CreateShellLink Destination=' + Destination + ' Description=' + Description + ' Command=' + Command) + try + CreateShellLink( + Destination, + Description, + 'cmd.exe', + Command, + GetIDFPath(''), + '', 0, SW_SHOWNORMAL); + except + MsgBox('Failed to create the Start menu shortcut: ' + Destination, mbError, MB_OK); + RaiseException('Failed to create the shortcut'); + end; +end; diff --git a/tools/windows/tool_setup/idf_tool_setup.iss b/tools/windows/tool_setup/idf_tool_setup.iss index 5ca48ab477..40de6dedba 100644 --- a/tools/windows/tool_setup/idf_tool_setup.iss +++ b/tools/windows/tool_setup/idf_tool_setup.iss @@ -1,242 +1,97 @@ +; Copyright 2019 Espressif Systems (Shanghai) PTE LTD +; SPDX-License-Identifier: Apache-2.0 + +#pragma include __INCLUDE__ + ";" + ReadReg(HKLM, "Software\Mitrich Software\Inno Download Plugin", "InstallDir") #include -[Setup] -AppName=ESP-IDF Tools -AppVersion=1.2 -OutputBaseFilename=esp-idf-tools-setup-unsigned +#define MyAppName "ESP-IDF Tools" +#define MyAppVersion "2.0" +#define MyAppPublisher "Espressif Systems (Shanghai) Co. Ltd." +#define MyAppURL "https://github.com/espressif/esp-idf" -DefaultDirName={pf}\Espressif\ESP-IDF Tools -DefaultGroupName=ESP-IDF Tools -Compression=lzma2 +#define PythonVersion "3.7" +#define PythonInstallerName "python-3.7.3-amd64.exe" +#define PythonInstallerDownloadURL "https://www.python.org/ftp/python/3.7.3/python-3.7.3-amd64.exe" + +#define GitVersion "2.21.0" +#define GitInstallerName "Git-2.21.0-64-bit.exe" +#define GitInstallerDownloadURL "https://github.com/git-for-windows/git/releases/download/v2.21.0.windows.1/Git-2.21.0-64-bit.exe" + +#define IDFVersionsURL "https://dl.espressif.com/dl/esp-idf/idf_versions.txt" + +#define IDFCmdExeShortcutDescription "Open ESP-IDF Command Prompt (cmd.exe)" +#define IDFCmdExeShortcutFile "ESP-IDF Command Prompt (cmd.exe).lnk" + +[Setup] +; NOTE: The value of AppId uniquely identifies this application. +; Do not use the same AppId value in installers for other applications. +; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) +AppId={{9E068D99-5C4B-4E5F-96A3-B17CF291E6BD} +AppName={#MyAppName} +AppVersion={#MyAppVersion} +AppVerName={#MyAppName} {#MyAppVersion} +AppPublisher={#MyAppPublisher} +AppPublisherURL={#MyAppURL} +AppSupportURL={#MyAppURL} +AppUpdatesURL={#MyAppURL} +DefaultDirName={%USERPROFILE}\.espressif +DirExistsWarning=no +DefaultGroupName=ESP-IDF +DisableProgramGroupPage=yes +OutputBaseFilename=esp-idf-tools-setup-unsigned +Compression=lzma SolidCompression=yes -ChangesEnvironment=yes -LicenseFile=license.txt -; Note: the rest of the installer setup is written to work cleanly on win32 also, *however* -; Ninja doesn't ship a 32-bit binary so there's no way yet to install on win32 :( -; See https://github.com/ninja-build/ninja/issues/1339 ArchitecturesAllowed=x64 ArchitecturesInstallIn64BitMode=x64 +LicenseFile=license.txt +PrivilegesRequired=lowest +SetupLogging=yes +ChangesEnvironment=yes +WizardStyle=modern -[Types] -Name: "full"; Description: "Default installation" -Name: "custom"; Description: "Custom installation"; Flags: iscustom +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" -[Components] -Name: xtensa_esp32; Description: ESP32 Xtensa GCC Cross-Toolchain; Types: full custom; -Name: mconf_idf; Description: ESP-IDF console menuconfig tool; Types: full custom; -Name: openocd_esp32; Description: openocd debug interface for ESP32; Types: full custom; -Name: esp32ulp_elf_binutils; Description: ULP binutils toolchain for ESP32; Types: full custom; -Name: ninja; Description: Install Ninja build v1.8.2; Types: full custom - -[Tasks] -; Should installer prepend to Path (does this by default) -Name: addpath; Description: "Add tools to Path"; GroupDescription: "Add to Path:"; -Name: addpath\allusers; Description: "For all users"; GroupDescription: "Add to Path:"; Flags: exclusive -Name: addpath\user; Description: "For the current user only"; GroupDescription: "Add to Path:"; Flags: exclusive unchecked - -; External installation tasks -; -; Note: The Check conditions here auto-select 32-bit or 64-bit installers, as needed -; The tasks won't appear if CMake/Python27 already appear to be installed on this system -Name: cmake32; Description: Download and Run CMake 3.11.1 Installer; GroupDescription: "Other Required Tools:"; Check: not IsWin64 and not CMakeInstalled -Name: cmake64; Description: Download and Run CMake 3.11.1 Installer; GroupDescription: "Other Required Tools:"; Check: IsWin64 and not CMakeInstalled -Name: python32; Description: Download and Run Python 2.7.14 Installer and install Python dependencies; GroupDescription: "Other Required Tools:"; Check: not IsWin64 and not Python27Installed -Name: python64; Description: Download and Run Python 2.7.14 Installer and install Python dependencies; GroupDescription: "Other Required Tools:"; Check: IsWin64 and not Python27Installed -Name: python_requirements; Description: Install any missing Python dependencies; GroupDescription: "Other Required Tools:"; Check: Python27Installed +[Dirs] +Name: "{app}\dist" [Files] -Components: xtensa_esp32; Source: "input\xtensa-esp32-elf\*"; DestDir: "{app}\tools\"; Flags: recursesubdirs; -Components: mconf_idf; Source: "input\mconf-v4.6.0.0-idf-20180525-win32\*"; DestDir: "{app}\mconf-idf\"; -Components: esp32ulp_elf_binutils; Source: "input\esp32ulp-elf-binutils\*"; DestDir: "{app}\tools\"; Flags: recursesubdirs; -; Excludes for openocd are because some config files contain Cyrillic characters and inno can't encode them -Components: openocd_esp32; Source: "input\openocd-esp32\*"; DestDir: "{app}\tools\"; Flags: recursesubdirs; Excludes: "target\1986*.cfg,target\*1879*.cfg" -Components: ninja; Source: "input\ninja.exe"; DestDir: "{app}\tools\bin\"; -Tasks: python32 python64 python_requirements; Source: "..\..\..\requirements.txt"; DestDir: "{tmp}"; Flags: deleteafterinstall; +Source: "cmdlinerunner\build\cmdlinerunner.dll"; Flags: dontcopy +Source: "unzip\7za.exe"; Flags: dontcopy +Source: "idf_versions.txt"; Flags: dontcopy +Source: "..\..\idf_tools.py"; DestDir: "{app}"; DestName: "idf_tools_fallback.py" +; Note: this tools.json should match the requirements of IDF v3.x versions. +; For now, we use this copy to avoid duplication. Later we should create +; tools_fallback.json in this directory. +Source: "..\..\tools.json"; DestDir: "{app}"; DestName: "tools_fallback.json" +Source: "idf_cmd_init.bat"; DestDir: "{app}" +Source: "dist\*"; DestDir: "{app}\dist" + +[UninstallDelete] +Type: filesandordirs; Name: "{app}\dist" +Type: filesandordirs; Name: "{app}\releases" +Type: filesandordirs; Name: "{app}\tools" +Type: filesandordirs; Name: "{app}\python_env" [Run] -Tasks: cmake32 cmake64; Filename: "msiexec.exe"; Parameters: "/i ""{tmp}\cmake.msi"" /qb! {code:GetCMakeInstallerArgs}"; StatusMsg: Running CMake installer...; -Tasks: python32 python64; Filename: "msiexec.exe"; Parameters: "/i ""{tmp}\python.msi"" /qb! {code:GetPythonInstallerArgs} REBOOT=Supress"; StatusMsg: Running Python installer...; -Tasks: python32 python64; Filename: "C:\Python27\Scripts\pip.exe"; Parameters: "install -r ""{tmp}\requirements.txt"""; StatusMsg: Installing Python modules...; -Tasks: python_requirements; Filename: "{code:Python27InstallPathInclude}\Scripts\pip.exe"; Parameters: "install -r ""{tmp}\requirements.txt"""; StatusMsg: Installing Python modules...; +Filename: "{app}\dist\{#PythonInstallerName}"; Parameters: "/passive PrependPath=1 InstallLauncherAllUsers=0 Include_dev=0 Include_tcltk=0 Include_launcher=0 Include_test=0 Include_doc=0"; Description: "Installing Python"; Check: PythonInstallRequired +Filename: "{app}\dist\{#GitInstallerName}"; Parameters: "/silent /tasks="""" /norestart"; Description: "Installing Git"; Check: GitInstallRequired +Filename: "{group}\{#IDFCmdExeShortcutFile}"; Flags: postinstall shellexec; Description: "Run ESP-IDF Command Prompt (cmd.exe)"; Check: InstallationSuccessful [Registry] -; Prepend various entries to Path in the registry. Can either be HKLM (all users) or HKCU (single user only) - -; "tools" bin dir (ninja, xtensa & ULP toolchains, openocd all in this dir) -Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \ - ValueType: expandsz; ValueName: "Path"; ValueData: "{app}\tools\bin;{olddata}"; Check: not IsInPath('{app}'); \ - Components: xtensa_esp32 esp32ulp_elf_binutils openocd_esp32 ninja; Tasks: addpath\allusers -Root: HKCU; Subkey: "Environment"; \ - ValueType: expandsz; ValueName: "Path"; ValueData: "{app}\tools\bin;{olddata}"; Check: not IsInPath('{app}'); \ - Components: xtensa_esp32 esp32ulp_elf_binutils openocd_esp32 ninja; Tasks: addpath\user - -; mconf-idf path -Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \ - ValueType: expandsz; ValueName: "Path"; ValueData: "{app}\mconf-idf;{olddata}"; Check: not IsInPath('{app}\mconf-idf'); \ - Components: mconf_idf; Tasks: addpath\allusers -Root: HKCU; Subkey: "Environment"; \ - ValueType: expandsz; ValueName: "Path"; ValueData: "{app}\mconf-idf;{olddata}"; Check: not IsInPath('{app}\mconf-idf'); \ - Components: mconf_idf; Tasks: addpath\user - -; set OPENOCD_SCRIPTS environment variable -[Registry] -Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \ - ValueType:string; ValueName: "OPENOCD_SCRIPTS"; \ - ValueData: "{app}\tools\share\openocd\scripts"; Flags: preservestringtype createvalueifdoesntexist; \ - Components: openocd_esp32; Tasks: addpath\allusers -Root: HKCU; Subkey: "Environment"; ValueType:string; ValueName: "OPENOCD_SCRIPTS"; \ - ValueData: "{app}\tools\share\openocd\scripts"; Flags: preservestringtype createvalueifdoesntexist; \ - Components: openocd_esp32; Tasks: addpath\user - +Root: HKCU; Subkey: "Environment"; ValueType: string; ValueName: "IDF_TOOLS_PATH"; \ + ValueData: "{app}"; Flags: preservestringtype createvalueifdoesntexist; [Code] -procedure InitializeWizard; -begin - idpDownloadAfter(wpReady); -end; - -procedure CurPageChanged(CurPageID: Integer); -begin - { When the Ready page is being displayed, initialise downloads based on which Tasks are selected } - if CurPageID=wpReady then - begin - if IsTaskSelected('python32') then - begin - idpAddFile('https://www.python.org/ftp/python/2.7.14/python-2.7.14.msi', ExpandConstant('{tmp}\python.msi')); - end; - if IsTaskSelected('python64') then - begin - idpAddFile('https://www.python.org/ftp/python/2.7.14/python-2.7.14.amd64.msi', ExpandConstant('{tmp}\python.msi')); - end; - if IsTaskSelected('cmake32') then - begin - idpAddFile('https://cmake.org/files/v3.11/cmake-3.11.1-win32-x86.msi', ExpandConstant('{tmp}\cmake.msi')); - end; - if IsTaskSelected('cmake64') then - begin - idpAddFile('https://cmake.org/files/v3.11/cmake-3.11.1-win64-x64.msi', ExpandConstant('{tmp}\cmake.msi')); - end; - end; -end; - -{ Utility to search in HKLM for an installation path. Looks in both 64-bit & 32-bit registry. } -function GetInstallPath(key, valuename : String) : Variant; -var - value : string; -begin - Result := Null; - if RegQueryStringValue(HKEY_LOCAL_MACHINE, key, valuename, value) then - begin - Result := value; - end - else - begin - { This is 32-bit setup running on 64-bit Windows, but ESP-IDF can use 64-bit tools also } - if IsWin64 and RegQueryStringValue(HKLM64, key, valuename, value) then - begin - Result := value; - end; - end; -end; - -{ Return the path of the CMake install, if there is one } -function CMakeInstallPath() : Variant; -begin - Result := GetInstallPath('SOFTWARE\Kitware\CMake', 'InstallDir'); -end; - -{ Return 'True' if CMake is installed } -function CMakeInstalled() : Boolean; -begin - Result := not VarIsNull(CMakeInstallPath()); -end; - -{ Return the path where Python 2.7 is installed, if there is one } -function Python27InstallPath() : Variant; -begin - Result := GetInstallPath('SOFTWARE\Python\PythonCore\2.7\InstallPath', ''); -end; - -{ Return the path where Python 2.7 is installed, suitable for including in code: tag } -function Python27InstallPathInclude(Ignored : String) : String; -begin - Result := Python27InstallPath(); -end; - -{ Return True if Python 2.7 is installed } -function Python27Installed() : Boolean; -begin - Result := not VarIsNull(Python27InstallPath()); -end; - -{ Return arguments to pass to CMake installer, ie should it add CMake to the Path } -function GetCMakeInstallerArgs(Param : String) : String; -begin - if IsTaskSelected('addpath\allusers') then - begin - Result := 'ADD_CMAKE_TO_PATH=System'; - end - else if IsTaskSelected('addpath\user') then - begin - Result := 'ADD_CMAKE_TO_PATH=User'; - end - else begin - Result := 'ADD_CMAKE_TO_PATH=None'; - end; -end; - -{ Return arguments to pass to the Python installer, - ie should it install for all users and should it prepend to the Path } -function GetPythonInstallerArgs(Param : String) : String; -begin - { Note: The Python 2.7 installer appears to always add PATH to - system environment variables, regardless of ALLUSERS setting. - - This appears to be fixed in the Python 3.x installers (which use WiX) } - if IsTaskSelected('addpath') then - begin - Result := 'ADDLOCAL=ALL '; - end - else begin - Result := '' - end; - if IsTaskSelected('addpath\allusers') then - begin - Result := Result + 'ALLUSERS=1'; - end - else begin - Result := Result + 'ALLUSERS='; - end; -end; -{ Return True if the param is already set in the Path - (user or system, depending on which Task is chosen) - - Adapted from https://stackoverflow.com/a/3431379 -} -function IsInPath(Param: string): boolean; -var - OrigPath: string; - RootKey : Integer; - SubKey : String; -begin - if IsTaskSelected('addpath\allusers') then - begin - RootKey := HKEY_LOCAL_MACHINE; - SubKey := 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'; - end - else begin - RootKey := HKEY_CURRENT_USER; - SubKey := 'Environment'; - end; - - if not RegQueryStringValue(RootKey, SubKey, 'Path', OrigPath) - then begin - Result := False; - end - else begin - { look for the path with leading and trailing semicolon } - Result := Pos(';' + Param + ';', ';' + OrigPath + ';') > 0; - end; -end; +#include "utils.iss.inc" +#include "choice_page.iss.inc" +#include "cmdline_page.iss.inc" +#include "idf_page.iss.inc" +#include "git_page.iss.inc" +#include "python_page.iss.inc" +#include "idf_download_page.iss.inc" +#include "idf_setup.iss.inc" +#include "summary.iss.inc" +#include "main.iss.inc" diff --git a/tools/windows/tool_setup/main.iss.inc b/tools/windows/tool_setup/main.iss.inc new file mode 100644 index 0000000000..857f448796 --- /dev/null +++ b/tools/windows/tool_setup/main.iss.inc @@ -0,0 +1,121 @@ +{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD + SPDX-License-Identifier: Apache-2.0 } + +{ ------------------------------ Custom steps before the main installation flow ------------------------------ } + +var + SetupAborted: Boolean; + +function InstallationSuccessful(): Boolean; +begin + Result := not SetupAborted; +end; + + +procedure InitializeDownloader(); +begin + idpDownloadAfter(wpReady); +end; + + +function PreInstallSteps(CurPageID: Integer): Boolean; +var + DestPath: String; +begin + Result := True; + if CurPageID <> wpReady then + exit; + + ForceDirectories(ExpandConstant('{app}\dist')); + + if not PythonUseExisting then + begin + DestPath := ExpandConstant('{app}\dist\{#PythonInstallerName}'); + if FileExists(DestPath) then + begin + Log('Python installer already downloaded: ' + DestPath); + end else begin + idpAddFile('{#PythonInstallerDownloadURL}', DestPath); + end; + end; + + if not GitUseExisting then + begin + DestPath := ExpandConstant('{app}\dist\{#GitInstallerName}'); + if FileExists(DestPath) then + begin + Log('Git installer already downloaded: ' + DestPath); + end else begin + idpAddFile('{#GitInstallerDownloadURL}', DestPath); + end; + end; + + if not IDFUseExisting then + begin + IDFAddDownload(); + end; +end; + +{ ------------------------------ Custom steps after the main installation flow ------------------------------ } + +procedure AddPythonGitToPath(); +var + EnvPath: String; + PythonLibPath: String; +begin + EnvPath := GetEnv('PATH'); + + if not PythonUseExisting then + PythonExecutablePathUpdateAfterInstall(); + + if not GitUseExisting then + GitExecutablePathUpdateAfterInstall(); + + EnvPath := PythonPath + ';' + GitPath + ';' + EnvPath; + Log('Setting PATH for this process: ' + EnvPath); + SetEnvironmentVariable('PATH', EnvPath); + + { Log and clear PYTHONPATH variable, as it might point to libraries of another Python version} + PythonLibPath := GetEnv('PYTHONPATH') + Log('PYTHONPATH=' + PythonLibPath) + SetEnvironmentVariable('PYTHONPATH', '') +end; + + +procedure PostInstallSteps(CurStep: TSetupStep); +var + Err: Integer; +begin + if CurStep <> ssPostInstall then + exit; + + try + AddPythonGitToPath(); + + if not IDFUseExisting then + IDFDownload(); + + IDFToolsSetup(); + + CreateIDFCommandPromptShortcut(); + except + SetupAborted := True; + if MsgBox('Installation log has been created, it may contain more information about the problem.' + #13#10 + + 'Display the installation log now?', mbConfirmation, MB_YESNO or MB_DEFBUTTON1) = IDYES then + begin + ShellExec('', 'notepad.exe', ExpandConstant('{log}'), ExpandConstant('{tmp}'), SW_SHOW, ewNoWait, Err); + end; + Abort(); + end; +end; + + +function SkipFinishedPage(PageID: Integer): Boolean; +begin + Result := False; + + if PageID = wpFinished then + begin + Result := SetupAborted; + end; +end; diff --git a/tools/windows/tool_setup/python_find_installed.iss.inc b/tools/windows/tool_setup/python_find_installed.iss.inc new file mode 100644 index 0000000000..4485030dd5 --- /dev/null +++ b/tools/windows/tool_setup/python_find_installed.iss.inc @@ -0,0 +1,113 @@ +{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD + SPDX-License-Identifier: Apache-2.0 } + +{ ------------------------------ Find installed Python interpreters in Windows Registry (see PEP 514) ------------------------------ } + +var + InstalledPythonVersions: TStringList; + InstalledPythonDisplayNames: TStringList; + InstalledPythonExecutables: TStringList; + +procedure PythonVersionAdd(Version, DisplayName, Executable: String); +begin + Log('Adding Python version=' + Version + ' name='+DisplayName+' executable='+Executable); + InstalledPythonVersions.Append(Version); + InstalledPythonDisplayNames.Append(DisplayName); + InstalledPythonExecutables.Append(Executable); +end; + +function GetPythonVersionInfoFromKey(RootKey: Integer; SubKeyName, CompanyName, TagName: String; + var Version: String; + var DisplayName: String; + var ExecutablePath: String): Boolean; +var + TagKey, InstallPathKey, DefaultPath: String; +begin + TagKey := SubKeyName + '\' + CompanyName + '\' + TagName; + InstallPathKey := TagKey + '\InstallPath'; + + if not RegQueryStringValue(RootKey, InstallPathKey, '', DefaultPath) then + begin + Log('No (Default) key, skipping'); + Result := False; + exit; + end; + + if not RegQueryStringValue(RootKey, InstallPathKey, 'ExecutablePath', ExecutablePath) then + begin + Log('No ExecutablePath, using the default'); + ExecutablePath := DefaultPath + '\python.exe'; + end; + + if not RegQueryStringValue(RootKey, TagKey, 'SysVersion', Version) then + begin + if CompanyName = 'PythonCore' then + begin + Version := TagName; + Delete(Version, 4, Length(Version)); + end else begin + Log('Can not determine SysVersion'); + Result := False; + exit; + end; + end; + + if not RegQueryStringValue(RootKey, TagKey, 'DisplayName', DisplayName) then + begin + DisplayName := 'Python ' + Version; + end; + + Result := True; +end; + +procedure FindPythonVersionsFromKey(RootKey: Integer; SubKeyName: String); +var + CompanyNames: TArrayOfString; + CompanyName, CompanySubKey, TagName, TagSubKey: String; + ExecutablePath, DisplayName, Version: String; + TagNames: TArrayOfString; + CompanyId, TagId: Integer; +begin + if not RegGetSubkeyNames(RootKey, SubKeyName, CompanyNames) then + begin + Log('Nothing found in ' + IntToStr(RootKey) + '\' + SubKeyName); + Exit; + end; + + for CompanyId := 0 to GetArrayLength(CompanyNames) - 1 do + begin + CompanyName := CompanyNames[CompanyId]; + + if CompanyName = 'PyLauncher' then + continue; + + CompanySubKey := SubKeyName + '\' + CompanyName; + Log('In ' + IntToStr(RootKey) + '\' + CompanySubKey); + + if not RegGetSubkeyNames(RootKey, CompanySubKey, TagNames) then + continue; + + for TagId := 0 to GetArrayLength(TagNames) - 1 do + begin + TagName := TagNames[TagId]; + TagSubKey := CompanySubKey + '\' + TagName; + Log('In ' + IntToStr(RootKey) + '\' + TagSubKey); + + if not GetPythonVersionInfoFromKey(RootKey, SubKeyName, CompanyName, TagName, Version, DisplayName, ExecutablePath) then + continue; + + PythonVersionAdd(Version, DisplayName, ExecutablePath); + end; + end; +end; + +procedure FindInstalledPythonVersions(); +begin + InstalledPythonVersions := TStringList.Create(); + InstalledPythonDisplayNames := TStringList.Create(); + InstalledPythonExecutables := TStringList.Create(); + + FindPythonVersionsFromKey(HKEY_CURRENT_USER, 'Software\Python'); + FindPythonVersionsFromKey(HKEY_LOCAL_MACHINE, 'Software\Python'); + FindPythonVersionsFromKey(HKEY_LOCAL_MACHINE, 'Software\Wow6432Node\Python'); +end; diff --git a/tools/windows/tool_setup/python_page.iss.inc b/tools/windows/tool_setup/python_page.iss.inc new file mode 100644 index 0000000000..a0325fc7a1 --- /dev/null +++ b/tools/windows/tool_setup/python_page.iss.inc @@ -0,0 +1,149 @@ +{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD + SPDX-License-Identifier: Apache-2.0 } + +{ ------------------------------ Page to select Python interpreter ------------------------------ } + +#include "python_find_installed.iss.inc" + +var + PythonPage: TInputOptionWizardPage; + PythonVersion, PythonPath, PythonExecutablePath: String; + PythonUseExisting: Boolean; + + +function GetPythonPath(Unused: String): String; +begin + Result := PythonPath; +end; + +function PythonInstallRequired(): Boolean; +begin + Result := not PythonUseExisting; +end; + +function PythonVersionSupported(Version: String): Boolean; +var + Major, Minor: Integer; +begin + Result := False; + if not VersionExtractMajorMinor(Version, Major, Minor) then + begin + Log('PythonVersionSupported: Could not parse version=' + Version); + exit; + end; + + if (Major = 2) and (Minor = 7) then Result := True; + if (Major = 3) and (Minor >= 5) then Result := True; +end; + +procedure OnPythonPagePrepare(Sender: TObject); +var + Page: TInputOptionWizardPage; + FullName: String; + i, Index, FirstEnabledIndex: Integer; + OfferToInstall: Boolean; + VersionToInstall: String; + VersionSupported: Boolean; +begin + Page := TInputOptionWizardPage(Sender); + Log('OnPythonPagePrepare'); + if Page.CheckListBox.Items.Count > 0 then + exit; + + FindInstalledPythonVersions(); + + VersionToInstall := '{#PythonVersion}'; + OfferToInstall := True; + FirstEnabledIndex := -1; + + for i := 0 to InstalledPythonVersions.Count - 1 do + begin + VersionSupported := PythonVersionSupported(InstalledPythonVersions[i]); + FullName := InstalledPythonDisplayNames.Strings[i]; + if not VersionSupported then + begin + FullName := FullName + ' (unsupported)'; + end; + FullName := FullName + #13#10 + InstalledPythonExecutables.Strings[i]; + Index := Page.Add(FullName); + if not VersionSupported then + begin + Page.CheckListBox.ItemEnabled[Index] := False; + end else begin + if FirstEnabledIndex < 0 then FirstEnabledIndex := Index; + end; + if InstalledPythonVersions[i] = VersionToInstall then + begin + OfferToInstall := False; + end; + end; + + if OfferToInstall then + begin + Index := Page.Add('Install Python ' + VersionToInstall); + if FirstEnabledIndex < 0 then FirstEnabledIndex := Index; + end; + + Page.SelectedValueIndex := FirstEnabledIndex; +end; + +procedure OnPythonSelectionChange(Sender: TObject); +var + Page: TInputOptionWizardPage; +begin + Page := TInputOptionWizardPage(Sender); + Log('OnPythonSelectionChange index=' + IntToStr(Page.SelectedValueIndex)); +end; + +function OnPythonPageValidate(Sender: TWizardPage): Boolean; +var + Page: TInputOptionWizardPage; +begin + Page := TInputOptionWizardPage(Sender); + Log('OnPythonPageValidate index=' + IntToStr(Page.SelectedValueIndex)); + if Page.SelectedValueIndex < InstalledPythonExecutables.Count then + begin + PythonUseExisting := True; + PythonExecutablePath := InstalledPythonExecutables[Page.SelectedValueIndex]; + PythonPath := ExtractFilePath(PythonExecutablePath); + PythonVersion := InstalledPythonVersions[Page.SelectedValueIndex]; + end else begin + PythonUseExisting := False; + PythonExecutablePath := ''; + PythonPath := ''; + PythonVersion := '{#PythonVersion}'; + end; + Log('OnPythonPageValidate: PythonPath='+PythonPath+' PythonExecutablePath='+PythonExecutablePath); + Result := True; +end; + +procedure PythonExecutablePathUpdateAfterInstall(); +var + Version, DisplayName, ExecutablePath: String; +begin + if not GetPythonVersionInfoFromKey( + HKEY_CURRENT_USER, 'Software\Python', 'PythonCore', '{#PythonVersion}', + Version, DisplayName, ExecutablePath) then + begin + Log('Failed to find ExecutablePath for the installed copy of Python'); + exit; + end; + Log('Found ExecutablePath for ' + DisplayName + ': ' + ExecutablePath); + PythonExecutablePath := ExecutablePath; + PythonPath := ExtractFilePath(PythonExecutablePath); + Log('PythonExecutablePathUpdateAfterInstall: PythonPath='+PythonPath+' PythonExecutablePath='+PythonExecutablePath); +end; + + +procedure CreatePythonPage(); +begin + PythonPage := ChoicePageCreate( + wpLicense, + 'Python choice', 'Please choose Python version', + 'Available Python versions', + '', + False, + @OnPythonPagePrepare, + @OnPythonSelectionChange, + @OnPythonPageValidate); +end; diff --git a/tools/windows/tool_setup/summary.iss.inc b/tools/windows/tool_setup/summary.iss.inc new file mode 100644 index 0000000000..6a5923601d --- /dev/null +++ b/tools/windows/tool_setup/summary.iss.inc @@ -0,0 +1,40 @@ +{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD + SPDX-License-Identifier: Apache-2.0 } + +{ ------------------------------ Installation summary page ------------------------------ } + +function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo, + MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String; +begin + Result := '' + + if PythonUseExisting then + begin + Result := Result + 'Using Python ' + PythonVersion + ':' + NewLine + + Space + PythonExecutablePath + NewLine + NewLine; + end else begin + Result := Result + 'Will download and install Python ' + PythonVersion + NewLine + NewLine; + end; + + if GitUseExisting then + begin + Result := Result + 'Using Git ' + GitVersion + ':' + NewLine + + Space + GitExecutablePath + NewLine + NewLine; + end else begin + Result := Result + 'Will download and install Git for Windows ' + GitVersion + NewLine + NewLine; + end; + + if IDFUseExisting then + begin + Result := Result + 'Using existing ESP-IDF copy: ' + NewLine + + Space + IDFExistingPath + NewLine + NewLine; + end else begin + Result := Result + 'Will download ESP-IDF ' + IDFDownloadVersion + ' into:' + NewLine + + Space + IDFDownloadPath + NewLine + NewLine; + end; + + Result := Result + 'IDF tools directory (IDF_TOOLS_PATH):' + NewLine + + Space + ExpandConstant('{app}') + NewLine + NewLine; + + Log('Summary message: ' + NewLine + Result); +end; diff --git a/tools/windows/tool_setup/utils.iss.inc b/tools/windows/tool_setup/utils.iss.inc new file mode 100644 index 0000000000..a93f6ad491 --- /dev/null +++ b/tools/windows/tool_setup/utils.iss.inc @@ -0,0 +1,157 @@ +{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD + SPDX-License-Identifier: Apache-2.0 } + +{ ------------------------------ Helper functions from libcmdlinerunner.dll ------------------------------ } + +function ProcStart(cmdline, workdir: string): Longword; + external 'proc_start@files:cmdlinerunner.dll cdecl'; + +function ProcGetExitCode(inst: Longword): DWORD; + external 'proc_get_exit_code@files:cmdlinerunner.dll cdecl'; + +function ProcGetOutput(inst: Longword; dest: PAnsiChar; sz: DWORD): DWORD; + external 'proc_get_output@files:cmdlinerunner.dll cdecl'; + +procedure ProcEnd(inst: Longword); + external 'proc_end@files:cmdlinerunner.dll cdecl'; + +{ ------------------------------ WinAPI functions ------------------------------ } + +#ifdef UNICODE + #define AW "W" +#else + #define AW "A" +#endif + +function SetEnvironmentVariable(lpName: string; lpValue: string): BOOL; + external 'SetEnvironmentVariable{#AW}@kernel32.dll stdcall'; + +{ ------------------------------ Functions to query the registry ------------------------------ } + +{ Utility to search in HKLM and HKCU for an installation path. Looks in both 64-bit & 32-bit registry. } +function GetInstallPath(key, valuename : String) : String; +var + value: String; +begin + Result := ''; + if RegQueryStringValue(HKEY_LOCAL_MACHINE, key, valuename, value) then + begin + Result := value; + exit; + end; + + if RegQueryStringValue(HKEY_CURRENT_USER, key, valuename, value) then + begin + Result := value; + exit; + end; + + { This is 32-bit setup running on 64-bit Windows, but ESP-IDF can use 64-bit tools also } + if IsWin64 and RegQueryStringValue(HKLM64, key, valuename, value) then + begin + Result := value; + exit; + end; + + if IsWin64 and RegQueryStringValue(HKCU64, key, valuename, value) then + begin + Result := value; + exit; + end; +end; + +{ ------------------------------ Function to exit from the installer ------------------------------ } + +procedure AbortInstallation(Message: String); +begin + MsgBox(Message, mbError, MB_OK); + Abort(); +end; + +{ ------------------------------ File system related functions ------------------------------ } + +function DirIsEmpty(DirName: String): Boolean; +var + FindRec: TFindRec; +begin + Result := True; + if FindFirst(DirName+'\*', FindRec) then begin + try + repeat + if (FindRec.Name <> '.') and (FindRec.Name <> '..') then begin + Result := False; + break; + end; + until not FindNext(FindRec); + finally + FindClose(FindRec); + end; + end; +end; + +type + TFindFileCallback = procedure(Filename: String); + +procedure FindFileRecusive(Directory: string; FileName: string; Callback: TFindFileCallback); +var + FindRec: TFindRec; + FilePath: string; +begin + if FindFirst(Directory + '\*', FindRec) then + begin + try + repeat + if (FindRec.Name = '.') or (FindRec.Name = '..') then + continue; + + FilePath := Directory + '\' + FindRec.Name; + if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY <> 0 then + begin + FindFileRecusive(FilePath, FileName, Callback); + end else if CompareText(FindRec.Name, FileName) = 0 then + begin + Callback(FilePath); + end; + until not FindNext(FindRec); + finally + FindClose(FindRec); + end; + end; +end; + +{ ------------------------------ Version related functions ------------------------------ } + +function VersionExtractMajorMinor(Version: String; var Major: Integer; var Minor: Integer): Boolean; +var + Delim: Integer; + MajorStr, MinorStr: String; + OrigVersion, ExpectedPrefix: String; +begin + Result := False; + OrigVersion := Version; + Delim := Pos('.', Version); + if Delim = 0 then exit; + + MajorStr := Version; + Delete(MajorStr, Delim, Length(MajorStr)); + Delete(Version, 1, Delim); + Major := StrToInt(MajorStr); + + Delim := Pos('.', Version); + if Delim = 0 then Delim := Length(MinorStr); + + MinorStr := Version; + Delete(MinorStr, Delim, Length(MinorStr)); + Delete(Version, 1, Delim); + Minor := StrToInt(MinorStr); + + { Sanity check } + ExpectedPrefix := IntToStr(Major) + '.' + IntToStr(Minor); + if Pos(ExpectedPrefix, OrigVersion) <> 1 then + begin + Log('VersionExtractMajorMinor: version=' + OrigVersion + ', expected=' + ExpectedPrefix); + exit; + end; + + Result := True; +end; From 6f5c7a21ace04effe2c13ab3b2aa81133524e0b2 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 27 Mar 2019 13:29:06 +0800 Subject: [PATCH 200/486] docs: update CMake getting started guide to use install.bat and export.bat --- .../add-idf_path-to-profile.rst | 76 +-------- docs/en/get-started-cmake/index.rst | 157 +++++++++--------- .../get-started-cmake/linux-setup-scratch.rst | 2 +- docs/en/get-started-cmake/linux-setup.rst | 60 +------ .../get-started-cmake/macos-setup-scratch.rst | 2 +- docs/en/get-started-cmake/macos-setup.rst | 44 +---- .../toolchain-setup-scratch.rst | 2 +- .../windows-setup-scratch.rst | 37 ++++- .../windows-setup-update.rst | 31 ++++ docs/en/get-started-cmake/windows-setup.rst | 41 +++-- .../windows-setup-update.rst | 3 + 11 files changed, 175 insertions(+), 280 deletions(-) create mode 100644 docs/en/get-started-cmake/windows-setup-update.rst create mode 100644 docs/zh_CN/get-started-cmake/windows-setup-update.rst diff --git a/docs/en/get-started-cmake/add-idf_path-to-profile.rst b/docs/en/get-started-cmake/add-idf_path-to-profile.rst index 87f9ae7c8a..cdaf9a5b88 100644 --- a/docs/en/get-started-cmake/add-idf_path-to-profile.rst +++ b/docs/en/get-started-cmake/add-idf_path-to-profile.rst @@ -1,75 +1,3 @@ -Add IDF_PATH & idf.py PATH to User Profile (CMake) -================================================== +:orphan: -:link_to_translation:`zh_CN:[中文]` - -.. include:: ../cmake-warning.rst - -To use the CMake-based build system and the idf.py tool, two modifications need to be made to system environment variables: - -- ``IDF_PATH`` needs to be set to the path of the directory containing ESP-IDF. -- System ``PATH`` variable to include the directory containing the ``idf.py`` tool (part of ESP-IDF). - -To preserve setting of these variables between system restarts, add them to the user profile by following the instructions below. - -.. note:: If using an IDE, you can optionally set these environment variables in your IDE's project environment rather than from the command line as described below. - -.. note:: If you don't ever use the command line ``idf.py`` tool, but run cmake directly or via an IDE, then it is not necessary to set the ``PATH`` variable - only ``IDF_PATH``. However it can be useful to set both. - -.. note:: If you only ever use the command line ``idf.py`` tool, and never use cmake directly or via an IDE, then it is not necessary to set the ``IDF_PATH`` variable - ``idf.py`` will detect the directory it is contained within and set ``IDF_PATH`` appropriately if it is missing. - -.. _add-paths-to-profile-windows-cmake: - -Windows -------- - -To edit Environment Variables on Windows 10, search for "Edit Environment Variables" under the Start menu. - -On earlier Windows versions, open the System Control Panel then choose "Advanced" and look for the Environment Variables button. - -You can set these environment variables for all users, or only for the current user, depending on whether other users of your computer will be using ESP-IDF. - -- Click ``New...`` to add a new system variable named ``IDF_PATH``. Set the path to directory containing ESP-IDF, for example ``C:\Users\user-name\esp\esp-idf``. -- Locate the ``Path`` environment variable and double-click to edit it. Append the following to the end: ``;%IDF_PATH%\tools``. This will allow you to run ``idf.py`` and other tools from Windows Command Prompt. - -If you got here from :ref:`get-started-setup-path-cmake`, while installing s/w for ESP32 development, then you can continue with :ref:`get-started-get-packages-cmake`. - - -.. _add-idf_path-to-profile-linux-macos-cmake: - -Linux and MacOS ---------------- - -Set up ``IDF_PATH`` and add ``idf.py`` to the PATH by adding the following two lines to your ``~/.profile`` file:: - - export IDF_PATH=~/esp/esp-idf - export PATH="$IDF_PATH/tools:$PATH" - -.. note:: - - ``~/.profile`` means a file named ``.profile`` in your user's home directory (which is abbreviated ``~`` in the shell). - -Log off and log in back to make this change effective. - -.. note:: - - Not all shells use ``.profile``. If you have ``/bin/bash`` and ``.bash_profile`` exists then update this file instead. For ``zsh``, update ``.zprofile``. Other shells may use other profile files (consult the shell's documentation). - -Run the following command to check if ``IDF_PATH`` is set:: - - printenv IDF_PATH - -The path previously entered in ``~/.profile`` file (or set manually) should be printed out. - -To verify ``idf.py`` is now on the ``PATH``, you can run the following:: - - which idf.py - -A path like ``${IDF_PATH}/tools/idf.py`` should be printed. - -If you do not like to have ``IDF_PATH`` or ``PATH`` modifications set, you can enter it manually in terminal window on each restart or logout:: - - export IDF_PATH=~/esp/esp-idf - export PATH="$IDF_PATH/tools:$PATH" - -If you got here from :ref:`get-started-setup-path-cmake`, while installing s/w for ESP32 development, then you can continue with :ref:`get-started-get-packages-cmake`. +.. Remove this file when the Chinese translation of CMake getting started guide is updated diff --git a/docs/en/get-started-cmake/index.rst b/docs/en/get-started-cmake/index.rst index 5df2314f8a..af24a9cf5d 100644 --- a/docs/en/get-started-cmake/index.rst +++ b/docs/en/get-started-cmake/index.rst @@ -78,10 +78,10 @@ This is a detailed roadmap to walk you through the installation process. Setting up Development Environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* :ref:`get-started-setup-toolchain-cmake` for :doc:`Windows `, :doc:`Linux ` or :doc:`MacOS ` +* :ref:`get-started-get-prerequisites-cmake` for :doc:`Windows `, :doc:`Linux ` or :doc:`macOS ` * :ref:`get-started-get-esp-idf-cmake` -* :ref:`get-started-setup-path-cmake` -* :ref:`get-started-get-packages-cmake` +* :ref:`get-started-set-up-tools-cmake` +* :ref:`get-started-set-up-env-cmake` Creating Your First Project ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -94,60 +94,40 @@ Creating Your First Project * :ref:`get-started-build-monitor-cmake` -.. _get-started-setup-toolchain-cmake: +.. _get-started-get-prerequisites-cmake: -Step 1. Set up the Toolchain -============================ +Step 1. Install prerequisites +============================= -The toolchain is a set of programs for compiling code and building applications. - -The quickest way to start development with ESP32 is by installing a prebuilt toolchain. Pick up your OS below and follow the provided instructions. +Some tools need to be installed on the computer before proceeding to the next steps. Follow the links below for the instructions for your OS: .. toctree:: :hidden: Windows - Linux - MacOS - -+-------------------+-------------------+-------------------+ -| |windows-logo| | |linux-logo| | |macos-logo| | -+-------------------+-------------------+-------------------+ -| `Windows`_ | `Linux`_ | `Mac OS`_ | -+-------------------+-------------------+-------------------+ - -.. |windows-logo| image:: ../../_static/windows-logo.png - :target: ../get-started-cmake/windows-setup.html - -.. |linux-logo| image:: ../../_static/linux-logo.png - :target: ../get-started-cmake/linux-setup.html - -.. |macos-logo| image:: ../../_static/macos-logo.png - :target: ../get-started-cmake/macos-setup.html - -.. _Windows: ../get-started-cmake/windows-setup.html -.. _Linux: ../get-started-cmake/linux-setup.html -.. _Mac OS: ../get-started-cmake/macos-setup.html - -.. note:: - - This guide uses the directory ``~/esp`` on Linux and macOS or ``%userprofile%\esp`` on Windows as an installation folder for ESP-IDF. You can use any directory, but you will need to adjust paths for the commands respectively. Keep in mind that ESP-IDF does not support spaces in paths. - -Depending on your experience and preferences, you may want to customize your environment instead of using a prebuilt toolchain. To set up the system your own way go to Section :ref:`get-started-customized-setup-cmake`. + Linux + macOS +* :doc:`windows-setup` +* :doc:`linux-setup` +* :doc:`macos-setup` .. _get-started-get-esp-idf-cmake: Step 2. Get ESP-IDF =================== -Besides the toolchain, you also need ESP32-specific API (software libraries and source code). They are provided by Espressif in `ESP-IDF repository `_. +To build applications for the ESP32, you need the software libraries provided by Espressif in `ESP-IDF repository `_. Get ESP-IDF in accordance with your operating system. To get ESP-IDF, navigate to your installation directory and clone the repository with ``git clone``. -Linux and MacOS +.. note:: + + This guide uses the directory ``~/esp`` on Linux and macOS or ``%userprofile%\esp`` on Windows as an installation folder for ESP-IDF. You can use any directory, but you will need to adjust paths for the commands respectively. Keep in mind that ESP-IDF does not support spaces in paths. + +Linux and macOS ~~~~~~~~~~~~~~~ Open Terminal, and run the following commands: @@ -161,60 +141,76 @@ Consult :doc:`/versions` for information about which ESP-IDF version to use in a Windows ~~~~~~~ -.. note:: - - Previous versions of ESP-IDF used the **MSYS2 bash terminal** command line. The current cmake-based build system can run in the regular **Windows Command Prompt** which is used here. - - If you use a bash-based terminal or PowerShell, please note that some command syntax will be different to what is shown below. - -Open Command Prompt and run the following commands: - -.. include:: /_build/inc/git-clone-windows.inc - -ESP-IDF will be downloaded into ``%userprofile%\esp\esp-idf``. +In addition to installing the tools, :ref:`get-started-cmake-windows-tools-installer` for Windows introduced in Step 1 can also download a copy of ESP-IDF. Consult :doc:`/versions` for information about which ESP-IDF version to use in a given situation. -.. include:: /_build/inc/git-clone-notes.inc +If you wish to download ESP-IDF without the help of ESP-IDF Tools Installer, refer to these :ref:`instructions `. -.. note:: +.. _get-started-set-up-tools-cmake: - Do not miss the ``--recursive`` option. If you have already cloned ESP-IDF without this option, run another command to get all the submodules:: +Step 3. Set up the tools +======================== - cd esp-idf - git submodule update --init +Aside from the ESP-IDF, you also need to install the tools used by ESP-IDF, such as the compiler, debugger, Python packages, etc. +Windows +~~~~~~~ -.. _get-started-setup-path-cmake: +:ref:`get-started-cmake-windows-tools-installer` for Windows introduced in Step 1 installs all the required tools. -Step 3. Set Environment Variables -================================= +If you want to install the tools without the help of ESP-IDF Tools Installer, open the Command Prompt and follow these steps: -Set the following environment variables on your computer, so that projects can be built: +.. code-block:: batch -- Create ``IDF_PATH`` and assign it the path to the ESP-IDF directory. -- Add to ``PATH`` the path to the ``tools`` directory inside the ``IDF_PATH`` directory. + cd %userprofile%\esp\esp-idf + install.bat -These variables can be set temporarily (per session) or permanently. Please follow the instructions specific to :ref:`Windows ` , :ref:`Linux and MacOS ` in Section :doc:`add-idf_path-to-profile`. +Linux and macOS +~~~~~~~~~~~~~~~ +.. code-block:: bash -.. _get-started-get-packages-cmake: + cd ~/esp/esp-idf + ./install.sh -Step 4. Install the Required Python Packages -============================================ +Customizing the tools installation path +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The python packages required by ESP-IDF are located in ``IDF_PATH/requirements.txt``. You can install them by running:: +The scripts introduced in this step install compilation tools required by ESP-IDF inside the user home directory: ``$HOME/.espressif`` on Linux and macOS, ``%USERPROFILE%\.espressif`` on Windows. If you wish to install the tools into a different directory, set the environment variable ``IDF_TOOLS_PATH`` before running the installation scripts. Make sure that your user has sufficient permissions to read and write this path. - python -m pip install --user -r $IDF_PATH/requirements.txt +If changing the ``IDF_TOOLS_PATH``, make sure it is set to the same value every time the ``install.bat``/``install.sh`` and ``export.bat``/``export.sh`` scripts are executed. -.. note:: +.. _get-started-set-up-env-cmake: - Please check the version of the Python interpreter that you will be using with ESP-IDF. For this, run - the command ``python --version`` and depending on the result, you might want to use ``python2``, ``python2.7`` - or similar instead of just ``python``, e.g.:: +Step 4. Set up the environment variables +======================================== - python2.7 -m pip install --user -r $IDF_PATH/requirements.txt +The installed tools are not yet added to the PATH environment variable. To make the tools usable from the command line, some environment variables must be set. ESP-IDF provides another script which does that. +Windows +~~~~~~~ + +:ref:`get-started-cmake-windows-tools-installer` for Windows creates an "ESP-IDF Command Prompt" shortcut in the Start Menu. This shortcut opens the Command Prompt and sets up all the required environment variables. You can open this shortcut and proceed to the next step. + +Alternatively, if you want to use ESP-IDF in an existing Command Prompt window, you can run: + +.. code-block:: batch + + %userprofile%\esp\esp-idf\export.bat + +Linux and macOS +~~~~~~~~~~~~~~~ + +In the terminal where you are going to use ESP-IDF, run: + +.. code-block:: bash + + . $HOME/esp/esp-idf/export.sh + +Note the space between the leading dot and the path! + +You can also automate this step, making ESP-IDF tools available in every terminal, by adding this line to your ``.profile`` or ``.bash_profile`` script. .. _get-started-start-project-cmake: @@ -225,7 +221,7 @@ Now you are ready to prepare your application for ESP32. You can start with :exa Copy :example:`get-started/hello_world` to ``~/esp`` directory: -Linux and MacOS +Linux and macOS ~~~~~~~~~~~~~~~ .. code-block:: bash @@ -247,7 +243,7 @@ It is also possible to build examples in-place, without copying them first. .. important:: - The esp-idf build system does not support spaces in the paths to either esp-idf or to projects. + The ESP-IDF build system does not support spaces in the paths to either ESP-IDF or to projects. .. _get-started-connect-cmake: @@ -276,7 +272,7 @@ Step 7. Configure Navigate to your ``hello_world`` directory from :ref:`get-started-start-project-cmake` and run the project configuration utility ``menuconfig``. -Linux and MacOS +Linux and macOS ~~~~~~~~~~~~~~~ .. code-block:: bash @@ -294,12 +290,6 @@ Windows cd %userprofile%\esp\hello_world idf.py menuconfig -The Python 2.7 installer will try to configure Windows to associate ``.py`` files with Python 2. If a separately installed program, such as Visual Studio Python Tools, has created an association with a different version of Python, then running ``idf.py`` may not work (it opens the file in Visual Studio instead). You can either run ``C:\Python27\python idf.py`` each time instead, or change the association that Windows uses for ``.py`` files. - -.. note:: - - If you get an error ``idf.py not found``, make sure that the ``PATH`` environment variable was set correctly in :ref:`get-started-setup-path-cmake`. If there is no ``idf.py`` in ``tools``, make sure you have the correct branch for the CMake preview as shown under :ref:`get-started-get-esp-idf-cmake`. - If the previous steps have been done correctly, the following menu appears: .. figure:: ../../_static/project-configuration.png @@ -480,17 +470,18 @@ Updating ESP-IDF You should update ESP-IDF from time to time, as newer versions fix bugs and provide new features. The simplest way to do the update is to delete the existing ``esp-idf`` folder and clone it again, as if performing the initial installation described in :ref:`get-started-get-esp-idf-cmake`. -If downloading to a new path, remember to :doc:`add-idf_path-to-profile` so that the toolchain scripts can find ESP-IDF in its release specific location. - Another solution is to update only what has changed. :ref:`The update procedure depends on the version of ESP-IDF you are using `. +After updating ESP-IDF, execute ``install.sh`` (``install.bat`` on Windows) again, in case the new ESP-IDF version requires different versions of tools. See instructions at :ref:`get-started-set-up-tools-cmake`. + +Once the new tools are installed, update the environment using ``export.sh`` (``export.bat`` on Windows). See instructions at :ref:`get-started-set-up-env-cmake`. + Related Documents ================= .. toctree:: :maxdepth: 1 - add-idf_path-to-profile establish-serial-connection eclipse-setup ../api-guides/tools/idf-monitor diff --git a/docs/en/get-started-cmake/linux-setup-scratch.rst b/docs/en/get-started-cmake/linux-setup-scratch.rst index cde88ccfc4..51abaf6fd3 100644 --- a/docs/en/get-started-cmake/linux-setup-scratch.rst +++ b/docs/en/get-started-cmake/linux-setup-scratch.rst @@ -68,7 +68,7 @@ Build the toolchain:: ./ct-ng build chmod -R u+w builds/xtensa-esp32-elf -Toolchain will be built in ``~/esp/crosstool-NG/builds/xtensa-esp32-elf``. Follow `instructions for standard setup `_ to add the toolchain to your ``PATH``. +Toolchain will be built in ``~/esp/crosstool-NG/builds/xtensa-esp32-elf``. To use it, you need to add ``~/esp/crosstool-NG/builds/xtensa-esp32-elf/bin`` to ``PATH`` environment variable. Next Steps diff --git a/docs/en/get-started-cmake/linux-setup.rst b/docs/en/get-started-cmake/linux-setup.rst index 8df911f53c..429755b9bd 100644 --- a/docs/en/get-started-cmake/linux-setup.rst +++ b/docs/en/get-started-cmake/linux-setup.rst @@ -1,6 +1,6 @@ -********************************************* -Standard Setup of Toolchain for Linux (CMake) -********************************************* +*********************************************** +Installation of Prerequisites for Linux (CMake) +*********************************************** :link_to_translation:`zh_CN:[中文]` @@ -26,61 +26,9 @@ To compile with ESP-IDF you need to get the following packages: .. note:: CMake version 3.5 or newer is required for use with ESP-IDF. Older Linux distributions may require updating, enabling of a "backports" repository, or installing of a "cmake3" package rather than "cmake". -Toolchain Setup +Additional Tips =============== -.. include:: /_build/inc/download-links.inc - -ESP32 toolchain for Linux is available for download from Espressif website: - -- for 64-bit Linux: - - |download_link_linux64| - -- for 32-bit Linux: - - |download_link_linux32| - -1. Download this file, then extract it in ``~/esp`` directory: - - - for 64-bit Linux: - - .. include:: /_build/inc/unpack-code-linux64.inc - - - for 32-bit Linux: - - .. include:: /_build/inc/unpack-code-linux32.inc - -.. _setup-linux-toolchain-add-it-to-path-cmake: - -2. The toolchain will be extracted into ``~/esp/xtensa-esp32-elf/`` directory. - - To use it, you will need to update your ``PATH`` environment variable in ``~/.profile`` file. To make ``xtensa-esp32-elf`` available for all terminal sessions, add the following line to your ``~/.profile`` file:: - - export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH" - - Alternatively, you may create an alias for the above command. This way you can get the toolchain only when you need it. To do this, add different line to your ``~/.profile`` file:: - - alias get_esp32='export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH"' - - Then when you need the toolchain you can type ``get_esp32`` on the command line and the toolchain will be added to your ``PATH``. - - .. note:: - - If you have ``/bin/bash`` set as login shell, and both ``.bash_profile`` and ``.profile`` exist, then update ``.bash_profile`` instead. - -3. Log off and log in back to make the ``.profile`` changes effective. Run the following command to verify if ``PATH`` is correctly set:: - - printenv PATH - - You are looking for similar result containing toolchain's path at the beginning of displayed string:: - - $ printenv PATH - /home/user-name/esp/xtensa-esp32-elf/bin:/home/user-name/bin:/home/user-name/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin - - Instead of ``/home/user-name`` there should be a home path specific to your installation. - - Permission issues /dev/ttyUSB0 ------------------------------ diff --git a/docs/en/get-started-cmake/macos-setup-scratch.rst b/docs/en/get-started-cmake/macos-setup-scratch.rst index dfbbc50508..45fa4238ca 100644 --- a/docs/en/get-started-cmake/macos-setup-scratch.rst +++ b/docs/en/get-started-cmake/macos-setup-scratch.rst @@ -79,7 +79,7 @@ Build the toolchain:: ./ct-ng build chmod -R u+w builds/xtensa-esp32-elf -Toolchain will be built in ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf``. Follow :ref:`instructions for standard setup ` to add the toolchain to your ``PATH``. +Toolchain will be built in ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf``. To use it, you need to add ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf/bin`` to ``PATH`` environment variable. Next Steps diff --git a/docs/en/get-started-cmake/macos-setup.rst b/docs/en/get-started-cmake/macos-setup.rst index 75130d71ae..7926ea9d5f 100644 --- a/docs/en/get-started-cmake/macos-setup.rst +++ b/docs/en/get-started-cmake/macos-setup.rst @@ -1,6 +1,6 @@ -********************************************** -Standard Setup of Toolchain for Mac OS (CMake) -********************************************** +*********************************************** +Installation of Prerequisites for macOS (CMake) +*********************************************** :link_to_translation:`zh_CN:[中文]` @@ -9,7 +9,7 @@ Standard Setup of Toolchain for Mac OS (CMake) Install Prerequisites ===================== -ESP-IDF will use the version of Python installed by default on Mac OS. +ESP-IDF will use the version of Python installed by default on macOS. - install pip:: @@ -29,7 +29,7 @@ ESP-IDF will use the version of Python installed by default on Mac OS. sudo port install cmake ninja - - Otherwise, consult the CMake_ and Ninja_ home pages for Mac OS installation downloads. + - Otherwise, consult the CMake_ and Ninja_ home pages for macOS installation downloads. - It is strongly recommended to also install ccache_ for faster builds. If you have HomeBrew_, this can be done via ``brew install ccache`` or ``sudo port install ccache`` on MacPorts_. @@ -38,39 +38,7 @@ ESP-IDF will use the version of Python installed by default on Mac OS. xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun - Then you will need to install the XCode command line tools to continue. You can install these by running ``xcode-select --install``. - -Toolchain Setup -=============== - -.. include:: /_build/inc/download-links.inc - -ESP32 toolchain for macOS is available for download from Espressif website: - -|download_link_osx| - -Download this file, then extract it in ``~/esp`` directory: - -.. include:: /_build/inc/unpack-code-osx.inc - -.. _setup-macos-toolchain-add-it-to-path-cmake: - -The toolchain will be extracted into ``~/esp/xtensa-esp32-elf/`` directory. - -To use it, you will need to update your ``PATH`` environment variable in ``~/.profile`` file. To make ``xtensa-esp32-elf`` available for all terminal sessions, add the following line to your ``~/.profile`` file:: - - export PATH=$HOME/esp/xtensa-esp32-elf/bin:$PATH - -Alternatively, you may create an alias for the above command. This way you can get the toolchain only when you need it. To do this, add different line to your ``~/.profile`` file:: - - alias get_esp32="export PATH=$HOME/esp/xtensa-esp32-elf/bin:$PATH" - -Then when you need the toolchain you can type ``get_esp32`` on the command line and the toolchain will be added to your ``PATH``. - -Log off and log in back to make the ``.profile`` changes effective. Run the following command to verify if ``PATH`` is correctly set:: - - printenv PATH - + Then you will need to install the XCode command line tools to continue. You can install these by running ``xcode-select --install``. Next Steps ========== diff --git a/docs/en/get-started-cmake/toolchain-setup-scratch.rst b/docs/en/get-started-cmake/toolchain-setup-scratch.rst index e96aa2fa7b..c7b0ee32d5 100644 --- a/docs/en/get-started-cmake/toolchain-setup-scratch.rst +++ b/docs/en/get-started-cmake/toolchain-setup-scratch.rst @@ -6,7 +6,7 @@ Customized Setup of Toolchain (CMake) :link_to_translation:`zh_CN:[中文]` -Instead of downloading binary toolchain from Espressif website (see :ref:`get-started-setup-toolchain-cmake`) you may build the toolchain yourself. +Instead of downloading binary toolchain from Espressif website (see :ref:`get-started-set-up-tools-cmake`) you may build the toolchain yourself. If you can't think of a reason why you need to build it yourself, then probably it's better to stick with the binary version. However, here are some of the reasons why you might want to compile it from source: diff --git a/docs/en/get-started-cmake/windows-setup-scratch.rst b/docs/en/get-started-cmake/windows-setup-scratch.rst index 5c33e77f5c..4fa8168fef 100644 --- a/docs/en/get-started-cmake/windows-setup-scratch.rst +++ b/docs/en/get-started-cmake/windows-setup-scratch.rst @@ -1,6 +1,6 @@ -******************************************** -Setup Windows Toolchain from Scratch (CMake) -******************************************** +********************************** +Windows Setup from Scratch (CMake) +********************************** :link_to_translation:`zh_CN:[中文]` @@ -10,10 +10,38 @@ This is a step-by-step alternative to running the :doc:`ESP-IDF Tools Installer To quickly setup the toolchain and other tools in standard way, using the ESP-IDF Tools installer, proceed to section :doc:`windows-setup`. - .. note:: The GNU Make based build system requires the MSYS2_ Unix compatibility environment on Windows. The CMake-based build system does not require this environment. +.. _get-esp-idf-windows-command-line-cmake: + +Get ESP-IDF +=========== + +.. note:: + + Previous versions of ESP-IDF used the **MSYS2 bash terminal** command line. The current cmake-based build system can run in the regular **Windows Command Prompt** which is used here. + + If you use a bash-based terminal or PowerShell, please note that some command syntax will be different to what is shown below. + +Open Command Prompt and run the following commands: + +.. include:: /_build/inc/git-clone-windows.inc + +ESP-IDF will be downloaded into ``%userprofile%\esp\esp-idf``. + +Consult :doc:`/versions` for information about which ESP-IDF version to use in a given situation. + +.. include:: /_build/inc/git-clone-notes.inc + +.. note:: + + Do not miss the ``--recursive`` option. If you have already cloned ESP-IDF without this option, run another command to get all the submodules:: + + cd esp-idf + git submodule update --init + + Tools ===== @@ -90,4 +118,5 @@ To carry on with development environment setup, proceed to :ref:`get-started-get .. _ninja: https://ninja-build.org/ .. _Python: https://www.python.org/downloads/windows/ .. _MSYS2: https://msys2.github.io/ +.. _Stable version: https://docs.espressif.com/projects/esp-idf/en/stable/ diff --git a/docs/en/get-started-cmake/windows-setup-update.rst b/docs/en/get-started-cmake/windows-setup-update.rst new file mode 100644 index 0000000000..1a8e4fb54a --- /dev/null +++ b/docs/en/get-started-cmake/windows-setup-update.rst @@ -0,0 +1,31 @@ +********************************* +Updating ESP-IDF tools on Windows +********************************* + +.. _get-started-cmake-install_bat-windows: + +Install ESP-IDF tools using ``install.bat`` +=========================================== + +From the Windows Command Prompt, change to the directory where ESP-IDF is installed. Then run:: + + install.bat + +This will download and install the tools necessary to use ESP-IDF. If the specific version of the tool is already installed, no action will be taken. +The tools are downloaded and installed into a directory specified during ESP-IDF Tools Installer process. By default, this is ``C:\Users\username\.espressif``. + +.. _get-started-cmake-export_bat-windows: + +Add ESP-IDF tools to PATH using ``export.bat`` +============================================== + +ESP-IDF tools installer creates a Start menu shortcut for "ESP-IDF Command Prompt". This shortcut opens a Command Prompt window where all the tools are already available. + +In some cases, you may want to work with ESP-IDF in a Command Prompt window which wasn't started using that shortcut. If this is the case, follow the instructions below to add ESP-IDF tools to PATH. + +In the command prompt where you need to use ESP-IDF, change to the directory where ESP-IDF is installed, then execute ``export.bat``:: + + cd %userprofile%\esp\esp-idf + export.bat + +When this is done, the tools will be available in this command prompt. diff --git a/docs/en/get-started-cmake/windows-setup.rst b/docs/en/get-started-cmake/windows-setup.rst index fa8735aba7..d226c5f0f7 100644 --- a/docs/en/get-started-cmake/windows-setup.rst +++ b/docs/en/get-started-cmake/windows-setup.rst @@ -1,6 +1,6 @@ -*********************************************** -Standard Setup of Toolchain for Windows (CMake) -*********************************************** +************************************************* +Installation of Prerequisites for Windows (CMake) +************************************************* :link_to_translation:`zh_CN:[中文]` @@ -12,46 +12,43 @@ Standard Setup of Toolchain for Windows (CMake) Introduction ============ -ESP-IDF requires some prerequisite tools to be installed so you can build firmware for the ESP32. The prerequisite tools include Git, a cross-compiler and the CMake build tool. We'll go over each one in this document. +ESP-IDF requires some prerequisite tools to be installed so you can build firmware for the ESP32. The prerequisite tools include Python, Git, cross-compilers, menuconfig tool, CMake and Ninja build tools. -For this Getting Started we're going to use a command prompt, but after ESP-IDF is installed you can use :doc:`Eclipse ` or another graphical IDE with CMake support instead. +For this Getting Started we're going to use the Command Prompt, but after ESP-IDF is installed you can use :doc:`Eclipse ` or another graphical IDE with CMake support instead. .. note:: The GNU Make based build system requires the MSYS2_ Unix compatibility environment on Windows. The CMake-based build system does not require this environment. +.. _get-started-cmake-windows-tools-installer: + ESP-IDF Tools Installer ======================= The easiest way to install ESP-IDF's prerequisites is to download the ESP-IDF Tools installer from this URL: -https://dl.espressif.com/dl/esp-idf-tools-setup-1.2.exe +https://dl.espressif.com/dl/esp-idf-tools-setup-2.0.exe -The installer will automatically install the ESP32 Xtensa gcc toolchain, Ninja_ build tool, and a configuration tool called mconf-idf_. The installer can also download and run installers for CMake_ and Python_ 2.7 if these are not already installed on the computer. +The installer includes the cross-compilers, OpenOCD, cmake_ and Ninja_ build tool, and a configuration tool called mconf-idf_. The installer can also download and run installers for Python_ 3.7 and `Git For Windows`_ if they are not already installed on the computer. -By default, the installer updates the Windows ``Path`` environment variable so all of these tools can be run from anywhere. If you disable this option, you will need to configure the environment where you are using ESP-IDF (terminal or chosen IDE) with the correct paths. +The installer also offers to download one of the ESP-IDF release versions. -Note that this installer is for the ESP-IDF Tools package, it doesn't include ESP-IDF itself. +Using the Command Prompt +======================== -Installing Git -============== +For the remaining Getting Started steps, we're going to use the Windows Command Prompt. -The ESP-IDF tools installer does not install Git. By default, the getting started guide assumes you will be using Git on the command line. You can download and install a command line Git for Windows (along with the "Git Bash" terminal) from `Git For Windows`_. +ESP-IDF Tools Installer creates a shortcut in the Start menu to launch the ESP-IDF Command Prompt. This shortcut launches the Command Prompt (cmd.exe) and runs ``export.bat`` script to set up the environment variables (``PATH``, ``IDF_PATH`` and others). Inside this command prompt, all the installed tools are available. -If you prefer to use a different graphical Git client, then you can install one such as `Github Desktop`. You will need to translate the Git commands in the Getting Started guide for use with your chosen Git client. +Note that this shortcut is specific to the ESP-IDF directory selected in the ESP-IDF Tools Installer. If you have multiple ESP-IDF directories on the computer (for example, to work with different versions of ESP-IDF), you have two options to use them: -Using a Terminal -================ +1. Create a copy of the shortcut created by the ESP-IDF Tools Installer, and change the working directory of the new shortcut to the ESP-IDF directory you wish to use. -For the remaining Getting Started steps, we're going to use a terminal command prompt. It doesn't matter which command prompt you use: - -- You can use the built-in Windows Command Prompt, under the Start menu. All Windows command line instructions in this documentation are "batch" commands for use with the Windows Command Prompt. -- You can use the "Git Bash" terminal which is part of `Git for Windows`_. This uses the same "bash" command prompt syntax as is given for Mac OS or Linux. You can find it in the Start menu once installed. -- If you have MSYS2_ installed (maybe from a previous ESP-IDF version), then you can also use the MSYS terminal. +2. Alternatively, run ``cmd.exe``, then change to the ESP-IDF directory you wish to use, and run ``export.bat``. Note that unlike the previous option, this way requires Python and Git to be present in ``PATH``. If you get errors related to Python or Git not being found, use the first option. Next Steps ========== -To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf-cmake`. +If the ESP-IDF Tools Installer has finished successfully, then the development environment setup is complete. Proceed directly to :ref:`get-started-start-project-cmake`. Related Documents ================= @@ -62,7 +59,7 @@ For advanced users who want to customize the install process: :maxdepth: 1 windows-setup-scratch - + windows-setup-update .. _MSYS2: https://msys2.github.io/ .. _cmake: https://cmake.org/download/ diff --git a/docs/zh_CN/get-started-cmake/windows-setup-update.rst b/docs/zh_CN/get-started-cmake/windows-setup-update.rst new file mode 100644 index 0000000000..cdaf9a5b88 --- /dev/null +++ b/docs/zh_CN/get-started-cmake/windows-setup-update.rst @@ -0,0 +1,3 @@ +:orphan: + +.. Remove this file when the Chinese translation of CMake getting started guide is updated From 4f5f30d37da179602929e4f1132466e2ec6eac45 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 26 Jun 2019 15:27:14 +0800 Subject: [PATCH 201/486] tools: add fallback tools.json for IDF v3.x --- tools/windows/tool_setup/idf_tool_setup.iss | 6 +- tools/windows/tool_setup/tools_fallback.json | 390 +++++++++++++++++++ 2 files changed, 392 insertions(+), 4 deletions(-) create mode 100644 tools/windows/tool_setup/tools_fallback.json diff --git a/tools/windows/tool_setup/idf_tool_setup.iss b/tools/windows/tool_setup/idf_tool_setup.iss index 40de6dedba..7fd8b2f735 100644 --- a/tools/windows/tool_setup/idf_tool_setup.iss +++ b/tools/windows/tool_setup/idf_tool_setup.iss @@ -60,10 +60,8 @@ Source: "cmdlinerunner\build\cmdlinerunner.dll"; Flags: dontcopy Source: "unzip\7za.exe"; Flags: dontcopy Source: "idf_versions.txt"; Flags: dontcopy Source: "..\..\idf_tools.py"; DestDir: "{app}"; DestName: "idf_tools_fallback.py" -; Note: this tools.json should match the requirements of IDF v3.x versions. -; For now, we use this copy to avoid duplication. Later we should create -; tools_fallback.json in this directory. -Source: "..\..\tools.json"; DestDir: "{app}"; DestName: "tools_fallback.json" +; Note: this tools.json matches the requirements of IDF v3.x versions. +Source: "tools_fallback.json"; DestDir: "{app}"; DestName: "tools_fallback.json" Source: "idf_cmd_init.bat"; DestDir: "{app}" Source: "dist\*"; DestDir: "{app}\dist" diff --git a/tools/windows/tool_setup/tools_fallback.json b/tools/windows/tool_setup/tools_fallback.json new file mode 100644 index 0000000000..5bb7118291 --- /dev/null +++ b/tools/windows/tool_setup/tools_fallback.json @@ -0,0 +1,390 @@ +{ + "tools": [ + { + "description": "Toolchain for Xtensa (ESP32) based on GCC", + "export_paths": [ + [ + "xtensa-esp32-elf", + "bin" + ] + ], + "export_vars": {}, + "info_url": "https://github.com/espressif/crosstool-NG", + "install": "always", + "license": "GPL-3.0-with-GCC-exception", + "name": "xtensa-esp32-elf", + "version_cmd": [ + "xtensa-esp32-elf-gcc", + "--version" + ], + "version_regex": "\\(crosstool-NG\\s+(?:crosstool-ng-)?([0-9a-z\\.\\-]+)\\)\\s*([0-9\\.]+)", + "version_regex_replace": "\\1-\\2", + "versions": [ + { + "name": "1.22.0-80-g6c4433a5-5.2.0", + "status": "recommended", + "win32": { + "sha256": "f217fccbeaaa8c92db239036e0d6202458de4488b954a3a38f35ac2ec48058a4", + "size": 125719261, + "url": "https://dl.espressif.com/dl/xtensa-esp32-elf-win32-1.22.0-80-g6c4433a-5.2.0.zip" + }, + "win64": { + "sha256": "f217fccbeaaa8c92db239036e0d6202458de4488b954a3a38f35ac2ec48058a4", + "size": 125719261, + "url": "https://dl.espressif.com/dl/xtensa-esp32-elf-win32-1.22.0-80-g6c4433a-5.2.0.zip" + } + }, + { + "linux-amd64": { + "sha256": "3fe96c151d46c1d4e5edc6ed690851b8e53634041114bad04729bc16b0445156", + "size": 44219107, + "url": "https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz" + }, + "linux-i686": { + "sha256": "b4055695ffc2dfc0bcb6dafdc2572a6e01151c4179ef5fa972b3fcb2183eb155", + "size": 45566336, + "url": "https://dl.espressif.com/dl/xtensa-esp32-elf-linux32-1.22.0-80-g6c4433a-5.2.0.tar.gz" + }, + "macos": { + "sha256": "a4307a97945d2f2f2745f415fbe80d727750e19f91f9a1e7e2f8a6065652f9da", + "size": 46517409, + "url": "https://dl.espressif.com/dl/xtensa-esp32-elf-osx-1.22.0-80-g6c4433a-5.2.0.tar.gz" + }, + "name": "1.22.0-80-g6c4433a-5.2.0", + "status": "recommended" + } + ] + }, + { + "description": "Toolchain for ESP32 ULP coprocessor", + "export_paths": [ + [ + "esp32ulp-elf-binutils", + "bin" + ] + ], + "export_vars": {}, + "info_url": "https://github.com/espressif/binutils-esp32ulp", + "install": "always", + "license": "GPL-2.0-or-later", + "name": "esp32ulp-elf", + "version_cmd": [ + "esp32ulp-elf-as", + "--version" + ], + "version_regex": "\\(GNU Binutils\\)\\s+([0-9a-z\\.\\-]+)", + "versions": [ + { + "linux-amd64": { + "sha256": "c1bbcd65e1e30c7312a50344c8dbc70c2941580a79aa8f8abbce8e0e90c79566", + "size": 8246604, + "url": "https://dl.espressif.com/dl/binutils-esp32ulp-linux64-2.28.51-esp32ulp-20180809.tar.gz" + }, + "macos": { + "sha256": "c92937d85cc9a90eb6c6099ce767ca021108c18c94e34bd7b1fa0cde168f94a0", + "size": 5726662, + "url": "https://dl.espressif.com/dl/binutils-esp32ulp-macos-2.28.51-esp32ulp-20180809.tar.gz" + }, + "name": "2.28.51.20170517", + "status": "recommended", + "win32": { + "sha256": "92dc83e69e534c9f73d7b939088f2e84f757d2478483415d17fe9dd1c236f2fd", + "size": 12231559, + "url": "https://dl.espressif.com/dl/binutils-esp32ulp-win32-2.28.51-esp32ulp-20180809.zip" + }, + "win64": { + "sha256": "92dc83e69e534c9f73d7b939088f2e84f757d2478483415d17fe9dd1c236f2fd", + "size": 12231559, + "url": "https://dl.espressif.com/dl/binutils-esp32ulp-win32-2.28.51-esp32ulp-20180809.zip" + } + } + ] + }, + { + "description": "CMake build system", + "export_paths": [ + [ + "bin" + ] + ], + "export_vars": {}, + "info_url": "https://github.com/Kitware/CMake", + "install": "on_request", + "license": "BSD-3-Clause", + "name": "cmake", + "platform_overrides": [ + { + "install": "always", + "platforms": [ + "win32", + "win64" + ] + }, + { + "export_paths": [ + [ + "CMake.app", + "Contents", + "bin" + ] + ], + "platforms": [ + "macos" + ] + } + ], + "strip_container_dirs": 1, + "version_cmd": [ + "cmake", + "--version" + ], + "version_regex": "cmake version ([0-9.]+)", + "versions": [ + { + "linux-amd64": { + "sha256": "563a39e0a7c7368f81bfa1c3aff8b590a0617cdfe51177ddc808f66cc0866c76", + "size": 38405896, + "url": "https://github.com/Kitware/CMake/releases/download/v3.13.4/cmake-3.13.4-Linux-x86_64.tar.gz" + }, + "macos": { + "sha256": "fef537614d73fda848f6168273b6c7ba45f850484533361e7bc50ac1d315f780", + "size": 32062124, + "url": "https://github.com/Kitware/CMake/releases/download/v3.13.4/cmake-3.13.4-Darwin-x86_64.tar.gz" + }, + "name": "3.13.4", + "status": "recommended", + "win32": { + "sha256": "28daf772f55d817a13ef14e25af2a5569f8326dac66a6aa3cc5208cf1f8e943f", + "size": 26385104, + "url": "https://github.com/Kitware/CMake/releases/download/v3.13.4/cmake-3.13.4-win32-x86.zip" + }, + "win64": { + "sha256": "bcd477d49e4a9400b41213d53450b474beaedb264631693c958ef9affa8e5623", + "size": 29696565, + "url": "https://github.com/Kitware/CMake/releases/download/v3.13.4/cmake-3.13.4-win64-x64.zip" + } + } + ] + }, + { + "description": "OpenOCD for ESP32", + "export_paths": [ + [ + "openocd-esp32", + "bin" + ] + ], + "export_vars": { + "OPENOCD_SCRIPTS": "${TOOL_PATH}/openocd-esp32/share/openocd/scripts" + }, + "info_url": "https://github.com/espressif/openocd-esp32", + "install": "always", + "license": "GPL-2.0-only", + "name": "openocd-esp32", + "version_cmd": [ + "openocd", + "--version" + ], + "version_regex": "Open On-Chip Debugger\\s+([a-z0-9.-]+)\\s+", + "versions": [ + { + "linux-amd64": { + "sha256": "e5b5579edffde090e426b4995b346e281843bf84394f8e68c8e41bd1e4c576bd", + "size": 1681596, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.10.0-esp32-20190313/openocd-esp32-linux64-0.10.0-esp32-20190313.tar.gz" + }, + "macos": { + "sha256": "09504eea5aa92646a117f16573c95b34e04b4010791a2f8fefcd2bd8c430f081", + "size": 1760536, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.10.0-esp32-20190313/openocd-esp32-macos-0.10.0-esp32-20190313.tar.gz" + }, + "name": "v0.10.0-esp32-20190313", + "status": "recommended", + "win32": { + "sha256": "b86a7f9f39dfc4d8e289fc819375bbb7a5e9fcb8895805ba2b5faf67b8b25ce2", + "size": 2098513, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.10.0-esp32-20190313/openocd-esp32-win32-0.10.0-esp32-20190313.zip" + }, + "win64": { + "sha256": "b86a7f9f39dfc4d8e289fc819375bbb7a5e9fcb8895805ba2b5faf67b8b25ce2", + "size": 2098513, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.10.0-esp32-20190313/openocd-esp32-win32-0.10.0-esp32-20190313.zip" + } + } + ] + }, + { + "description": "menuconfig tool", + "export_paths": [ + [ + "" + ] + ], + "export_vars": {}, + "info_url": "https://github.com/espressif/kconfig-frontends", + "install": "never", + "license": "GPL-2.0-only", + "name": "mconf", + "platform_overrides": [ + { + "install": "always", + "platforms": [ + "win32", + "win64" + ] + } + ], + "strip_container_dirs": 1, + "version_cmd": [ + "mconf-idf", + "-v" + ], + "version_regex": "mconf-idf version mconf-([a-z0-9.-]+)-win32", + "versions": [ + { + "name": "v4.6.0.0-idf-20190313", + "status": "recommended", + "win32": { + "sha256": "051bef09c782bc31b737b047808d1b6588b0965101b77dc979af9139773c4b4f", + "size": 826167, + "url": "https://github.com/espressif/kconfig-frontends/releases/download/v4.6.0.0-idf-20190313/mconf-v4.6.0.0-idf-20190313-win32.zip" + }, + "win64": { + "sha256": "051bef09c782bc31b737b047808d1b6588b0965101b77dc979af9139773c4b4f", + "size": 826167, + "url": "https://github.com/espressif/kconfig-frontends/releases/download/v4.6.0.0-idf-20190313/mconf-v4.6.0.0-idf-20190313-win32.zip" + } + } + ] + }, + { + "description": "Ninja build system", + "export_paths": [ + [ + "" + ] + ], + "export_vars": {}, + "info_url": "https://github.com/ninja-build/ninja", + "install": "on_request", + "license": "Apache-2.0", + "name": "ninja", + "platform_overrides": [ + { + "install": "always", + "platforms": [ + "win32", + "win64" + ] + } + ], + "version_cmd": [ + "ninja", + "--version" + ], + "version_regex": "([0-9.]+)", + "versions": [ + { + "linux-amd64": { + "sha256": "978fd9e26c2db8d33392c6daef50e9edac0a3db6680710a9f9ad47e01f3e49b7", + "size": 85276, + "url": "https://dl.espressif.com/dl/ninja-1.9.0-linux64.tar.gz" + }, + "macos": { + "sha256": "9504cd1783ef3c242d06330a50d54dc8f838b605f5fc3e892c47254929f7350c", + "size": 91457, + "url": "https://dl.espressif.com/dl/ninja-1.9.0-osx.tar.gz" + }, + "name": "1.9.0", + "status": "recommended", + "win64": { + "sha256": "2d70010633ddaacc3af4ffbd21e22fae90d158674a09e132e06424ba3ab036e9", + "size": 254497, + "url": "https://dl.espressif.com/dl/ninja-1.9.0-win64.zip" + } + } + ] + }, + { + "description": "IDF wrapper tool for Windows", + "export_paths": [ + [ + "" + ] + ], + "export_vars": {}, + "info_url": "https://github.com/espressif/esp-idf/tree/master/tools/windows/idf_exe", + "install": "never", + "license": "Apache-2.0", + "name": "idf-exe", + "platform_overrides": [ + { + "install": "always", + "platforms": [ + "win32", + "win64" + ] + } + ], + "version_cmd": [ + "idf.py.exe", + "-v" + ], + "version_regex": "([0-9.]+)", + "versions": [ + { + "name": "1.0", + "status": "recommended", + "win32": { + "sha256": "83a83ac7a246cbae93884db7c5f2ef9a7607d602340b1cf1e64ec2a925071748", + "size": 11289, + "url": "https://dl.espressif.com/dl/idf-exe-v1.0.zip" + }, + "win64": { + "sha256": "83a83ac7a246cbae93884db7c5f2ef9a7607d602340b1cf1e64ec2a925071748", + "size": 11289, + "url": "https://dl.espressif.com/dl/idf-exe-v1.0.zip" + } + } + ] + }, + { + "description": "Ccache (compiler cache)", + "export_paths": [ + [ + "" + ] + ], + "export_vars": {}, + "info_url": "https://github.com/ccache/ccache", + "install": "never", + "license": "GPL-3.0-or-later", + "name": "ccache", + "platform_overrides": [ + { + "install": "always", + "platforms": [ + "win64" + ] + } + ], + "version_cmd": [ + "ccache.exe", + "--version" + ], + "version_regex": "ccache version ([0-9.]+)", + "versions": [ + { + "name": "3.7", + "status": "recommended", + "win64": { + "sha256": "37e833f3f354f1145503533e776c1bd44ec2e77ff8a2476a1d2039b0b10c78d6", + "size": 142401, + "url": "https://dl.espressif.com/dl/ccache-3.7-w64.zip" + } + } + ] + } + ], + "version": 1 +} From 22dfac7405e2c015c0195efa31bf498d0ba905aa Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Fri, 28 Jun 2019 10:59:52 +0200 Subject: [PATCH 202/486] mconf-idf: update to v4.6.0.0-idf-20190603 --- tools/tools.json | 14 +++++++------- tools/windows/tool_setup/tools_fallback.json | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tools/tools.json b/tools/tools.json index e96040307a..54249d7dcc 100644 --- a/tools/tools.json +++ b/tools/tools.json @@ -243,17 +243,17 @@ "version_regex": "mconf-idf version mconf-([a-z0-9.-]+)-win32", "versions": [ { - "name": "v4.6.0.0-idf-20190313", + "name": "v4.6.0.0-idf-20190628", "status": "recommended", "win32": { - "sha256": "051bef09c782bc31b737b047808d1b6588b0965101b77dc979af9139773c4b4f", - "size": 826167, - "url": "https://github.com/espressif/kconfig-frontends/releases/download/v4.6.0.0-idf-20190313/mconf-v4.6.0.0-idf-20190313-win32.zip" + "sha256": "1b8f17f48740ab669c13bd89136e8cc92efe0cd29872f0d6c44148902a2dc40c", + "size": 826114, + "url": "https://github.com/espressif/kconfig-frontends/releases/download/v4.6.0.0-idf-20190628/mconf-v4.6.0.0-idf-20190628-win32.zip" }, "win64": { - "sha256": "051bef09c782bc31b737b047808d1b6588b0965101b77dc979af9139773c4b4f", - "size": 826167, - "url": "https://github.com/espressif/kconfig-frontends/releases/download/v4.6.0.0-idf-20190313/mconf-v4.6.0.0-idf-20190313-win32.zip" + "sha256": "1b8f17f48740ab669c13bd89136e8cc92efe0cd29872f0d6c44148902a2dc40c", + "size": 826114, + "url": "https://github.com/espressif/kconfig-frontends/releases/download/v4.6.0.0-idf-20190628/mconf-v4.6.0.0-idf-20190628-win32.zip" } } ] diff --git a/tools/windows/tool_setup/tools_fallback.json b/tools/windows/tool_setup/tools_fallback.json index 5bb7118291..6b1585c8a4 100644 --- a/tools/windows/tool_setup/tools_fallback.json +++ b/tools/windows/tool_setup/tools_fallback.json @@ -242,17 +242,17 @@ "version_regex": "mconf-idf version mconf-([a-z0-9.-]+)-win32", "versions": [ { - "name": "v4.6.0.0-idf-20190313", + "name": "v4.6.0.0-idf-20190628", "status": "recommended", "win32": { - "sha256": "051bef09c782bc31b737b047808d1b6588b0965101b77dc979af9139773c4b4f", - "size": 826167, - "url": "https://github.com/espressif/kconfig-frontends/releases/download/v4.6.0.0-idf-20190313/mconf-v4.6.0.0-idf-20190313-win32.zip" + "sha256": "1b8f17f48740ab669c13bd89136e8cc92efe0cd29872f0d6c44148902a2dc40c", + "size": 826114, + "url": "https://github.com/espressif/kconfig-frontends/releases/download/v4.6.0.0-idf-20190628/mconf-v4.6.0.0-idf-20190628-win32.zip" }, "win64": { - "sha256": "051bef09c782bc31b737b047808d1b6588b0965101b77dc979af9139773c4b4f", - "size": 826167, - "url": "https://github.com/espressif/kconfig-frontends/releases/download/v4.6.0.0-idf-20190313/mconf-v4.6.0.0-idf-20190313-win32.zip" + "sha256": "1b8f17f48740ab669c13bd89136e8cc92efe0cd29872f0d6c44148902a2dc40c", + "size": 826114, + "url": "https://github.com/espressif/kconfig-frontends/releases/download/v4.6.0.0-idf-20190628/mconf-v4.6.0.0-idf-20190628-win32.zip" } } ] From eb99b27f2e7085cce8af64d517b5f75226474ed0 Mon Sep 17 00:00:00 2001 From: Vikram Dattu Date: Sat, 15 Jun 2019 15:13:51 +0530 Subject: [PATCH 203/486] Bugfix: ota fails with secure boot on for image size greater than 3.2MB When an OTA image size is larger than 50 MMU pages (approx. 3.2 MB), secure_boot_generate fails while trying to map it into memory: https://gitlab.espressif.cn:6688/idf/esp-idf/blob/master/components/bootloader_support/src/esp32/secure_boot.c#L72 Instead of trying to map the whole image, secure boot code should split the image into chunks and map them one by one, like it is done in esp_image_format.c: https://gitlab.espressif.cn:6688/idf/esp-idf/blob/master/components/bootloader_support/src/esp_image_format.c#L372 Closes https://jira.espressif.com:8443/browse/IDF-709 Signed-off-by: Vikram Dattu --- .../include_bootloader/bootloader_flash.h | 7 +++ .../bootloader_support/src/bootloader_flash.c | 15 ++++++ .../src/esp32/secure_boot_signatures.c | 48 ++++++++++++++----- 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/components/bootloader_support/include_bootloader/bootloader_flash.h b/components/bootloader_support/include_bootloader/bootloader_flash.h index ce867d7573..6ac7246462 100644 --- a/components/bootloader_support/include_bootloader/bootloader_flash.h +++ b/components/bootloader_support/include_bootloader/bootloader_flash.h @@ -30,6 +30,13 @@ bootloader_support components only. */ +/** + * @brief Get number of free pages + * + * @return Number of free pages + */ +uint32_t bootloader_mmap_get_free_pages(); + /** * @brief Map a region of flash to data memory * diff --git a/components/bootloader_support/src/bootloader_flash.c b/components/bootloader_support/src/bootloader_flash.c index 5b4a555e1c..6b25addf22 100644 --- a/components/bootloader_support/src/bootloader_flash.c +++ b/components/bootloader_support/src/bootloader_flash.c @@ -25,6 +25,11 @@ static const char *TAG = "bootloader_mmap"; static spi_flash_mmap_handle_t map; +uint32_t bootloader_mmap_get_free_pages() +{ + return spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA); +} + const void *bootloader_mmap(uint32_t src_addr, uint32_t size) { if (map) { @@ -91,12 +96,22 @@ static const char *TAG = "bootloader_flash"; */ #define MMU_BLOCK0_VADDR 0x3f400000 #define MMU_BLOCK50_VADDR 0x3f720000 +#define MMU_FREE_PAGES ((MMU_BLOCK50_VADDR - MMU_BLOCK0_VADDR) / FLASH_BLOCK_SIZE) static bool mapped; // Current bootloader mapping (ab)used for bootloader_read() static uint32_t current_read_mapping = UINT32_MAX; +uint32_t bootloader_mmap_get_free_pages() +{ + /** + * Allow mapping up to 50 of the 51 available MMU blocks (last one used for reads) + * Since, bootloader_mmap function below assumes it to be 0x320000 (50 pages), we can safely do this. + */ + return MMU_FREE_PAGES; +} + const void *bootloader_mmap(uint32_t src_addr, uint32_t size) { if (mapped) { diff --git a/components/bootloader_support/src/esp32/secure_boot_signatures.c b/components/bootloader_support/src/esp32/secure_boot_signatures.c index 3642b309df..dbc32eab5f 100644 --- a/components/bootloader_support/src/esp32/secure_boot_signatures.c +++ b/components/bootloader_support/src/esp32/secure_boot_signatures.c @@ -21,7 +21,7 @@ #include "esp32/rom/sha.h" #include "uECC.h" -typedef SHA_CTX sha_context; +#include static const char *TAG = "secure_boot"; @@ -32,6 +32,9 @@ extern const uint8_t signature_verification_key_end[] asm("_binary_signature_ver #define DIGEST_LEN 32 +/* Mmap source address mask */ +#define MMAP_ALIGNED_MASK 0x0000FFFF + esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length) { uint8_t digest[DIGEST_LEN]; @@ -40,21 +43,44 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length) ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length); - data = bootloader_mmap(src_addr, length + sizeof(esp_secure_boot_sig_block_t)); - if (data == NULL) { - ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, length + sizeof(esp_secure_boot_sig_block_t)); - return ESP_FAIL; + bootloader_sha256_handle_t handle = bootloader_sha256_start(); + + uint32_t free_page_count = bootloader_mmap_get_free_pages(); + ESP_LOGD(TAG, "free data page_count 0x%08x", free_page_count); + + int32_t data_len_remain = length; + uint32_t data_addr = src_addr; + while (data_len_remain > 0) { + uint32_t offset_page = ((data_addr & MMAP_ALIGNED_MASK) != 0) ? 1 : 0; + /* Data we could map in case we are not aligned to PAGE boundary is one page size lesser. */ + uint32_t data_len = MIN(data_len_remain, ((free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE)); + data = (const uint8_t *) bootloader_mmap(data_addr, data_len); + if(!data) { + ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", data_addr, data_len); + bootloader_sha256_finish(handle, NULL); + return ESP_FAIL; + } + bootloader_sha256_data(handle, data, data_len); + bootloader_munmap(data); + + data_addr += data_len; + data_len_remain -= data_len; } - // Calculate digest of main image - bootloader_sha256_handle_t handle = bootloader_sha256_start(); - bootloader_sha256_data(handle, data, length); + /* Done! Get the digest */ bootloader_sha256_finish(handle, digest); - // Map the signature block and verify the signature - sigblock = (const esp_secure_boot_sig_block_t *)(data + length); + // Map the signature block + sigblock = (const esp_secure_boot_sig_block_t *) bootloader_mmap(src_addr + length, sizeof(esp_secure_boot_sig_block_t)); + if(!sigblock) { + ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr + length, sizeof(esp_secure_boot_sig_block_t)); + return ESP_FAIL; + } + // Verify the signature esp_err_t err = esp_secure_boot_verify_signature_block(sigblock, digest); - bootloader_munmap(data); + // Unmap + bootloader_munmap(sigblock); + return err; } From da77dcb0be7949d99a29bbf3bd3a999ce607fce5 Mon Sep 17 00:00:00 2001 From: Vikram Dattu Date: Tue, 18 Jun 2019 14:04:32 +0530 Subject: [PATCH 204/486] Changed log level for spi_master There are lot of prints of `Allocate TX buffer for DMA` Changed these from `ESP_LOGI` to `ESP_LOGD` Signed-off-by: Vikram Dattu --- components/driver/spi_master.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/driver/spi_master.c b/components/driver/spi_master.c index bf86117f4d..14a9e08a45 100644 --- a/components/driver/spi_master.c +++ b/components/driver/spi_master.c @@ -872,7 +872,7 @@ static SPI_MASTER_ISR_ATTR esp_err_t setup_priv_desc(spi_transaction_t *trans_de } if (send_ptr && isdma && !esp_ptr_dma_capable( send_ptr )) { //if txbuf in the desc not DMA-capable, malloc a new one - ESP_LOGI( SPI_TAG, "Allocate TX buffer for DMA" ); + ESP_LOGD( SPI_TAG, "Allocate TX buffer for DMA" ); uint32_t *temp = heap_caps_malloc((trans_desc->length + 7) / 8, MALLOC_CAP_DMA); if (temp == NULL) goto clean_up; From 4b42f535edc3c4e87ebc454bfe0ea6cb62cfb012 Mon Sep 17 00:00:00 2001 From: Vikram Dattu Date: Wed, 19 Jun 2019 17:23:44 +0530 Subject: [PATCH 205/486] Add mmu pages available check in non-secure image hash check path. Made MMU pages available check in `esp_image_format.c` This now makes it possible to map and process bootoader image as well in chunks when image doesn't fit completely into available free pages. Signed-off-by: Vikram Dattu --- .../bootloader_support/src/esp_image_format.c | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/components/bootloader_support/src/esp_image_format.c b/components/bootloader_support/src/esp_image_format.c index 77af08c3cf..620d884a2e 100644 --- a/components/bootloader_support/src/esp_image_format.c +++ b/components/bootloader_support/src/esp_image_format.c @@ -368,24 +368,22 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme } #endif // BOOTLOADER_BUILD -#ifndef BOOTLOADER_BUILD - uint32_t free_page_count = spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA); - ESP_LOGD(TAG, "free data page_count 0x%08x",free_page_count); - uint32_t offset_page = 0; - while (data_len >= free_page_count * SPI_FLASH_MMU_PAGE_SIZE) { - offset_page = ((data_addr & MMAP_ALIGNED_MASK) != 0)?1:0; - err = process_segment_data(load_addr, data_addr, (free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE, do_load, sha_handle, checksum); + uint32_t free_page_count = bootloader_mmap_get_free_pages(); + ESP_LOGD(TAG, "free data page_count 0x%08x", free_page_count); + + int32_t data_len_remain = data_len; + while (data_len_remain > 0) { + uint32_t offset_page = ((data_addr & MMAP_ALIGNED_MASK) != 0) ? 1 : 0; + /* Data we could map in case we are not aligned to PAGE boundary is one page size lesser. */ + data_len = MIN(data_len_remain, ((free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE)); + err = process_segment_data(load_addr, data_addr, data_len, do_load, sha_handle, checksum); if (err != ESP_OK) { return err; } - data_addr += (free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE; - data_len -= (free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE; - } -#endif - err = process_segment_data(load_addr, data_addr, data_len, do_load, sha_handle, checksum); - if (err != ESP_OK) { - return err; + data_addr += data_len; + data_len_remain -= data_len; } + return ESP_OK; err: From 18bea96bf5c36fdf47c6fb13ff3082fa6e026268 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 6 May 2019 10:59:43 +0800 Subject: [PATCH 206/486] esp32: verify that RTC_NOINIT_ATTR vars are preserved after WDT reset Related to https://github.com/espressif/esp-idf/issues/2973 --- components/esp32/test/test_reset_reason.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/esp32/test/test_reset_reason.c b/components/esp32/test/test_reset_reason.c index 9d57a7f4c0..78d051358e 100644 --- a/components/esp32/test/test_reset_reason.c +++ b/components/esp32/test/test_reset_reason.c @@ -141,12 +141,14 @@ TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_SW after restart from APP CPU", static void do_int_wdt() { + setup_values(); portENTER_CRITICAL_NESTED(); while(1); } static void do_int_wdt_hw() { + setup_values(); XTOS_SET_INTLEVEL(XCHAL_NMILEVEL); while(1); } @@ -154,6 +156,7 @@ static void do_int_wdt_hw() static void check_reset_reason_int_wdt() { TEST_ASSERT_EQUAL(ESP_RST_INT_WDT, esp_reset_reason()); + TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val); } TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_INT_WDT after interrupt watchdog (panic)", @@ -194,6 +197,7 @@ TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_TASK_WDT after task watchdog", static void do_rtc_wdt() { + setup_values(); WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE); REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_SYS_RESET_LENGTH, 7); REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_RESET_SYSTEM); @@ -205,6 +209,7 @@ static void do_rtc_wdt() static void check_reset_reason_any_wdt() { TEST_ASSERT_EQUAL(ESP_RST_WDT, esp_reset_reason()); + TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val); } TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_WDT after RTC watchdog", From 396258380a3b9ada6d88ba76698382c409cc864c Mon Sep 17 00:00:00 2001 From: Prasad Alatkar Date: Tue, 2 Jul 2019 11:26:24 +0800 Subject: [PATCH 207/486] NimBLE: update nimble submodule - Update submodule to fix https://jira.espressif.com:8443/browse/BT-192. - Upstream PR: https://github.com/apache/mynewt-nimble/pull/427 --- components/bt/host/nimble/nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 4f96f4cc35..30480fdb5d 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 4f96f4cc351dd5bff2310b311285a89f73104bb6 +Subproject commit 30480fdb5d11547bba8c34647dbfc629c6fdb74c From 388b350f0d0af7bfb19f51e6568cd2a998dfb527 Mon Sep 17 00:00:00 2001 From: Prasad Alatkar Date: Tue, 2 Jul 2019 14:20:10 +0800 Subject: [PATCH 208/486] NimBLE-provisioning: Add NimBLE support to unified provisioning framework - Adds NimBLE stack support to existing BLE variant of unified provisioning. - Uses scan response to send device name, 128 bit custom UUIDs based on service UUID. - Minimal changes to `app_prov.c`, component.mk, CMakeLists.txt and `protocomm_ble.h` to accomodate NimBLE stack for provisioning. --- components/protocomm/CMakeLists.txt | 13 +- components/protocomm/component.mk | 8 +- .../include/transports/protocomm_ble.h | 7 +- .../src/transports/protocomm_nimble.c | 909 ++++++++++++++++++ components/wifi_provisioning/CMakeLists.txt | 2 +- components/wifi_provisioning/component.mk | 7 +- .../provisioning/ble_prov/main/app_prov.c | 7 + .../provisioning/manager/sdkconfig.defaults | 3 +- 8 files changed, 943 insertions(+), 13 deletions(-) create mode 100644 components/protocomm/src/transports/protocomm_nimble.c diff --git a/components/protocomm/CMakeLists.txt b/components/protocomm/CMakeLists.txt index 334e279145..b58698020e 100644 --- a/components/protocomm/CMakeLists.txt +++ b/components/protocomm/CMakeLists.txt @@ -1,8 +1,8 @@ set(include_dirs include/common include/security include/transports) -set(priv_include_dirs proto-c src/common src/simple_ble) -set(srcs +set(priv_include_dirs proto-c src/common) +set(srcs "src/common/protocomm.c" "src/security/security0.c" "src/security/security1.c" @@ -18,10 +18,17 @@ if(CONFIG_BT_ENABLED) list(APPEND srcs "src/simple_ble/simple_ble.c" "src/transports/protocomm_ble.c") + list(APPEND priv_include_dirs + src/simple_ble) + endif() + if(CONFIG_BT_NIMBLE_ENABLED) + list(APPEND srcs + "src/transports/protocomm_nimble.c") endif() endif() idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "${include_dirs}" PRIV_INCLUDE_DIRS "${priv_include_dirs}" - PRIV_REQUIRES protobuf-c mbedtls console esp_http_server bt) + PRIV_REQUIRES protobuf-c mbedtls console esp_http_server + REQUIRES bt) diff --git a/components/protocomm/component.mk b/components/protocomm/component.mk index 918fed4ded..fbc0232f08 100644 --- a/components/protocomm/component.mk +++ b/components/protocomm/component.mk @@ -2,6 +2,10 @@ COMPONENT_ADD_INCLUDEDIRS := include/common include/security include/transports COMPONENT_PRIV_INCLUDEDIRS := proto-c src/common src/simple_ble COMPONENT_SRCDIRS := src/common src/security proto-c src/simple_ble src/transports -ifneq ($(filter y, $(CONFIG_BT_ENABLED) $(CONFIG_BT_BLUEDROID_ENABLED)),y y) - COMPONENT_OBJEXCLUDE := src/simple_ble/simple_ble.o src/transports/protocomm_ble.o +ifndef CONFIG_BT_BLUEDROID_ENABLED + COMPONENT_OBJEXCLUDE += src/simple_ble/simple_ble.o src/transports/protocomm_ble.o +endif + +ifndef CONFIG_BT_NIMBLE_ENABLED + COMPONENT_OBJEXCLUDE += src/transports/protocomm_nimble.o endif diff --git a/components/protocomm/include/transports/protocomm_ble.h b/components/protocomm/include/transports/protocomm_ble.h index 92714444f0..b7d70e59ec 100644 --- a/components/protocomm/include/transports/protocomm_ble.h +++ b/components/protocomm/include/transports/protocomm_ble.h @@ -14,8 +14,6 @@ #pragma once -#include - #include #ifdef __cplusplus @@ -26,7 +24,8 @@ extern "C" { * BLE device name cannot be larger than this value * 31 bytes (max scan response size) - 1 byte (length) - 1 byte (type) = 29 bytes */ -#define MAX_BLE_DEVNAME_LEN (ESP_BLE_SCAN_RSP_DATA_LEN_MAX - 2) +#define MAX_BLE_DEVNAME_LEN 29 +#define BLE_UUID128_VAL_LENGTH 16 /** * @brief This structure maps handler required by protocomm layer to @@ -58,7 +57,7 @@ typedef struct { /** * 128 bit UUID of the provisioning service */ - uint8_t service_uuid[ESP_UUID_LEN_128]; + uint8_t service_uuid[BLE_UUID128_VAL_LENGTH]; /** * Number of entries in the Name-UUID lookup table diff --git a/components/protocomm/src/transports/protocomm_nimble.c b/components/protocomm/src/transports/protocomm_nimble.c new file mode 100644 index 0000000000..cbe7bdb8d8 --- /dev/null +++ b/components/protocomm/src/transports/protocomm_nimble.c @@ -0,0 +1,909 @@ +// Copyright 2019 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 +#include +#include +#include "nvs_flash.h" + +#include +#include +#include "protocomm_priv.h" + +/* NimBLE */ +#include "esp_nimble_hci.h" +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" +#include "host/ble_hs.h" +#include "host/ble_uuid.h" +#include "host/util/util.h" +#include "services/gap/ble_svc_gap.h" + +static const char *TAG = "protocomm_nimble"; + +int ble_uuid_flat(const ble_uuid_t *, void *); +static uint8_t ble_uuid_base[BLE_UUID128_VAL_LENGTH]; +static int num_chr_dsc; + +/* Standard 16 bit UUID for characteristic User Description*/ +#define BLE_GATT_UUID_CHAR_DSC 0x2901 + +/******************************************************** +* Maintain database for Attribute specific data * +********************************************************/ +struct data_mbuf { + SLIST_ENTRY(data_mbuf) node; + uint8_t *outbuf; + ssize_t outlen; + uint16_t attr_handle; +}; + +static SLIST_HEAD(data_mbuf_head, data_mbuf) data_mbuf_list = + SLIST_HEAD_INITIALIZER(data_mbuf_list); + +static struct data_mbuf *find_attr_with_handle(uint16_t attr_handle) +{ + struct data_mbuf *cur; + SLIST_FOREACH(cur, &data_mbuf_list, node) { + if (cur->attr_handle == attr_handle) { + return cur; + } + } + return NULL; +} +/************************************************************** +* Initialize GAP, protocomm parameters * +**************************************************************/ +static int simple_ble_gap_event(struct ble_gap_event *event, void *arg); +static uint8_t own_addr_type; +void ble_store_config_init(void); + +typedef struct _protocomm_ble { + protocomm_t *pc_ble; + protocomm_ble_name_uuid_t *g_nu_lookup; + ssize_t g_nu_lookup_count; + uint16_t gatt_mtu; +} _protocomm_ble_internal_t; + +static _protocomm_ble_internal_t *protoble_internal; +static struct ble_gap_adv_params adv_params; +static char *protocomm_ble_device_name; +static struct ble_hs_adv_fields adv_data, resp_data; + +/********************************************************************** +* Maintain database of uuid_name addresses to free memory afterwards * +**********************************************************************/ +struct uuid128_name_buf { + SLIST_ENTRY(uuid128_name_buf) link; + ble_uuid128_t *uuid128_name_table; +}; + +static SLIST_HEAD(uuid128_name_buf_head, uuid128_name_buf) uuid128_name_list = + SLIST_HEAD_INITIALIZER(uuid128_name_list); + +/********************************************************************** +* Initialize simple BLE parameters, advertisement, scan response etc * +**********************************************************************/ +static int +gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); +static int +gatt_svr_dsc_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg); + +typedef void (simple_ble_cb_t)(struct ble_gap_event *event, void *arg); +static void transport_simple_ble_connect(struct ble_gap_event *event, void *arg); +static void transport_simple_ble_disconnect(struct ble_gap_event *event, void *arg); +static void transport_simple_ble_set_mtu(struct ble_gap_event *event, void *arg); + +typedef struct { + /** Name to be displayed to devices scanning for ESP32 */ + const char *device_name; + /** Advertising data content, according to "Supplement to the Bluetooth Core Specification" */ + struct ble_hs_adv_fields adv_data; + /** Parameters to configure the nature of advertising */ + struct ble_gap_adv_params adv_params; + /** Descriptor table which consists the configuration required by services and characteristics */ + struct ble_gatt_svc_def *gatt_db; + /** Client disconnect callback */ + simple_ble_cb_t *disconnect_fn; + /** Client connect callback */ + simple_ble_cb_t *connect_fn; + /** MTU set callback */ + simple_ble_cb_t *set_mtu_fn; +} simple_ble_cfg_t; + +static simple_ble_cfg_t *ble_cfg_p; + +/************************************************************ +* Functions to set and get attr value based on attr Handle * +************************************************************/ +static int simple_ble_gatts_set_attr_value(uint16_t attr_handle, ssize_t outlen, + uint8_t *outbuf) +{ + struct data_mbuf *attr_mbuf = find_attr_with_handle(attr_handle); + if (!attr_mbuf) { + attr_mbuf = calloc(1, sizeof(struct data_mbuf)); + if (!attr_mbuf) { + ESP_LOGE(TAG, "Failed to allocate memory for storing outbuf and outlen"); + return ESP_ERR_NO_MEM; + } + SLIST_INSERT_HEAD(&data_mbuf_list, attr_mbuf, node); + attr_mbuf->attr_handle = attr_handle; + } else { + free(attr_mbuf->outbuf); + } + attr_mbuf->outbuf = outbuf; + attr_mbuf->outlen = outlen; + return ESP_OK; +} + +static int simple_ble_gatts_get_attr_value(uint16_t attr_handle, ssize_t + *outlen, uint8_t **outbuf) +{ + struct data_mbuf *attr_mbuf = find_attr_with_handle(attr_handle); + if (!attr_mbuf) { + ESP_LOGE(TAG, "Outbuf with handle %d not found", attr_handle); + return ESP_ERR_NOT_FOUND; + } + *outbuf = attr_mbuf->outbuf; + *outlen = attr_mbuf->outlen; + return ESP_OK; +} + +/*****************************************************************************************/ +/* SIMPLE BLE INTEGRATION */ +/*****************************************************************************************/ +static void +simple_ble_advertise(void) +{ + int rc; + + adv_data.flags = (BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP); + adv_data.num_uuids128 = 1; + adv_data.uuids128_is_complete = 1; + + rc = ble_gap_adv_set_fields(&adv_data); + if (rc != 0) { + ESP_LOGE(TAG, "Error setting advertisement data; rc = %d", rc); + return; + } + + rc = ble_gap_adv_rsp_set_fields((const struct ble_hs_adv_fields *) &resp_data); + if (rc != 0) { + ESP_LOGE(TAG, "Error in setting scan response; rc = %d", rc); + return; + } + + adv_params.conn_mode = BLE_GAP_CONN_MODE_UND; + adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; + adv_params.itvl_min = 0x100; + adv_params.itvl_max = 0x100; + + rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER, + &adv_params, simple_ble_gap_event, NULL); + if (rc != 0) { + /* If BLE Host is disabled, it probably means device is already + * provisioned in previous session. Avoid error prints for this case.*/ + if (rc == BLE_HS_EDISABLED) { + ESP_LOGD(TAG, "BLE Host is disabled !!"); + } else { + ESP_LOGE(TAG, "Error enabling advertisement; rc = %d", rc); + } + return; + } + /* Take note of free heap space */ + ESP_LOGD(TAG, "Minimum free heap size = %d, free Heap size = %d", + esp_get_minimum_free_heap_size(), esp_get_free_heap_size()); +} + +static int +simple_ble_gap_event(struct ble_gap_event *event, void *arg) +{ + struct ble_gap_conn_desc desc; + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + transport_simple_ble_connect(event, arg); + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); + if (rc != 0) { + ESP_LOGE(TAG, "No open connection with the specified handle"); + return rc; + } + } else { + /* Connection failed; resume advertising. */ + simple_ble_advertise(); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + ESP_LOGD(TAG, "disconnect; reason=%d ", event->disconnect.reason); + transport_simple_ble_disconnect(event, arg); + + /* Connection terminated; resume advertising. */ + simple_ble_advertise(); + return 0; + + case BLE_GAP_EVENT_ADV_COMPLETE: + simple_ble_advertise(); + return 0; + + case BLE_GAP_EVENT_MTU: + ESP_LOGI(TAG, "mtu update event; conn_handle=%d cid=%d mtu=%d\n", + event->mtu.conn_handle, + event->mtu.channel_id, + event->mtu.value); + transport_simple_ble_set_mtu(event, arg); + return 0; + } + return 0; +} + +/* Gets `g_nu_lookup name handler` from 128 bit UUID */ +static const char *uuid128_to_handler(uint8_t *uuid) +{ + /* Use it to convert 128 bit UUID to 16 bit UUID.*/ + uint8_t *uuid16 = uuid + 12; + for (int i = 0; i < protoble_internal->g_nu_lookup_count; i++) { + if (protoble_internal->g_nu_lookup[i].uuid == *(uint16_t *)uuid16 ) { + ESP_LOGD(TAG, "UUID (0x%x) matched with proto-name = %s", *uuid16, protoble_internal->g_nu_lookup[i].name); + return protoble_internal->g_nu_lookup[i].name; + } else { + ESP_LOGD(TAG, "UUID did not match... %x", *uuid16); + } + } + return NULL; +} + +/* Callback to handle GATT characteristic descriptor read */ +static int +gatt_svr_dsc_access(uint16_t conn_handle, uint16_t attr_handle, struct + ble_gatt_access_ctxt *ctxt, void *arg) +{ + if (ctxt->op != BLE_GATT_ACCESS_OP_READ_DSC) { + ESP_LOGE(TAG, "Invalid operation on Read-only Descriptor"); + return BLE_ATT_ERR_UNLIKELY; + } + + int rc; + char *temp_outbuf = strdup(ctxt->dsc->arg); + if (temp_outbuf == NULL) { + ESP_LOGE(TAG, "Error duplicating user description of characteristic"); + return ESP_ERR_NO_MEM; + } + + ssize_t temp_outlen = strlen(temp_outbuf); + rc = os_mbuf_append(ctxt->om, temp_outbuf, temp_outlen); + free(temp_outbuf); + return rc; +} + +/* Callback to handle GATT characteristic value Read & Write */ +static int +gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + int rc; + esp_err_t ret; + char buf[BLE_UUID_STR_LEN]; + ssize_t temp_outlen = 0; + uint8_t *temp_outbuf = NULL; + uint8_t *uuid = NULL; + + switch (ctxt->op) { + case BLE_GATT_ACCESS_OP_READ_CHR: + ESP_LOGD(TAG, "Read attempeted for Characterstic UUID = %s, attr_handle = %d", + ble_uuid_to_str(ctxt->chr->uuid, buf), attr_handle); + + rc = simple_ble_gatts_get_attr_value(attr_handle, &temp_outlen, + &temp_outbuf); + if (rc != 0) { + ESP_LOGE(TAG, "Failed to read characteristic with attr_handle = %d", attr_handle); + return rc; + } + + rc = os_mbuf_append(ctxt->om, temp_outbuf, temp_outlen); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + + case BLE_GATT_ACCESS_OP_WRITE_CHR: + uuid = (uint8_t *) calloc(BLE_UUID128_VAL_LENGTH, sizeof(uint8_t)); + if (!uuid) { + ESP_LOGE(TAG, "Error allocating memory for 128 bit UUID"); + return ESP_ERR_NO_MEM; + } + + rc = ble_uuid_flat(ctxt->chr->uuid, uuid); + if (rc != 0) { + free(uuid); + ESP_LOGE(TAG, "Error fetching Characteristic UUID128"); + return rc; + } + + ESP_LOGD(TAG, "Write attempt for uuid = %s, attr_handle = %d, om_len = %d", + ble_uuid_to_str(ctxt->chr->uuid, buf), attr_handle, ctxt->om->om_len); + ret = protocomm_req_handle(protoble_internal->pc_ble, + uuid128_to_handler(uuid), + conn_handle, + ctxt->om->om_data, + ctxt->om->om_len, + &temp_outbuf, &temp_outlen); + /* Release the 16 bytes allocated for uuid*/ + free(uuid); + if (ret == ESP_OK) { + + /* Save data address and length outbuf and outlen internally */ + rc = simple_ble_gatts_set_attr_value(attr_handle, temp_outlen, + temp_outbuf); + if (rc != 0) { + ESP_LOGE(TAG, "Failed to set outbuf for characteristic with attr_handle = %d", + attr_handle); + free(temp_outbuf); + } + + return rc; + } else { + ESP_LOGE(TAG, "Invalid content received, killing connection"); + return BLE_ATT_ERR_INVALID_PDU; + } + + default: + return BLE_ATT_ERR_UNLIKELY; + } +} + +void +gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) +{ + char buf[BLE_UUID_STR_LEN]; + + switch (ctxt->op) { + case BLE_GATT_REGISTER_OP_SVC: + ESP_LOGD(TAG, "registering service %s with handle=%d TYPE =%d", + ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf), + ctxt->svc.handle, ctxt->svc.svc_def->uuid->type); + break; + + case BLE_GATT_REGISTER_OP_CHR: + ESP_LOGD(TAG, "registering characteristic %s with " + "def_handle=%d val_handle=%d , TYPE = %d", + ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf), + ctxt->chr.def_handle, + ctxt->chr.val_handle, ctxt->chr.chr_def->uuid->type); + break; + + case BLE_GATT_REGISTER_OP_DSC: + ESP_LOGD(TAG, "registering descriptor %s with handle=%d", + ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf), + ctxt->dsc.handle); + break; + + default: + assert(0); + break; + } +} + +int +gatt_svr_init(const simple_ble_cfg_t *config) +{ + int rc; + rc = ble_gatts_count_cfg(config->gatt_db); + if (rc != 0) { + return rc; + } + + rc = ble_gatts_add_svcs(config->gatt_db); + if (rc != 0) { + return rc; + } + + return 0; +} + +static void +simple_ble_on_reset(int reason) +{ + ESP_LOGE(TAG, "Resetting state; reason=%d\n", reason); +} + +static void +simple_ble_on_sync(void) +{ + int rc; + + rc = ble_hs_util_ensure_addr(0); + if (rc != 0) { + ESP_LOGE(TAG, "Error loading address"); + return; + } + + /* Figure out address to use while advertising (no privacy for now) */ + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) { + ESP_LOGE(TAG, "error determining address type; rc=%d\n", rc); + return; + } + + /* Begin advertising. */ + simple_ble_advertise(); +} + +void +nimble_host_task(void *param) +{ + /* This function will return only when nimble_port_stop() is executed */ + ESP_LOGI(TAG, "BLE Host Task Started"); + nimble_port_run(); + + nimble_port_freertos_deinit(); +} + +static int simple_ble_start(const simple_ble_cfg_t *cfg) +{ + ble_cfg_p = (void *)cfg; + int rc; + ESP_LOGD(TAG, "Free mem at start of simple_ble_init %d", esp_get_free_heap_size()); + + ESP_ERROR_CHECK(esp_nimble_hci_and_controller_init()); + nimble_port_init(); + + /* Initialize the NimBLE host configuration. */ + ble_hs_cfg.reset_cb = simple_ble_on_reset; + ble_hs_cfg.sync_cb = simple_ble_on_sync; + ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb; + + rc = gatt_svr_init(cfg); + if (rc != 0) { + ESP_LOGE(TAG, "Error initializing GATT server"); + return rc; + } + + /* Set device name, configure response data to be sent while advertising */ + rc = ble_svc_gap_device_name_set(cfg->device_name); + if (rc != 0) { + ESP_LOGE(TAG, "Error setting device name"); + return rc; + } + + resp_data.name = (void *) ble_svc_gap_device_name(); + if (resp_data.name != NULL) { + resp_data.name_len = strlen(ble_svc_gap_device_name()); + resp_data.name_is_complete = 1; + } + + /* XXX Need to have template for store */ + ble_store_config_init(); + nimble_port_freertos_init(nimble_host_task); + + return 0; +} + +/* transport_simple BLE Fn */ +static void transport_simple_ble_disconnect(struct ble_gap_event *event, void *arg) +{ + esp_err_t ret; + ESP_LOGD(TAG, "Inside disconnect w/ session - %d", + event->disconnect.conn.conn_handle); + if (protoble_internal->pc_ble->sec && + protoble_internal->pc_ble->sec->close_transport_session) { + ret = + protoble_internal->pc_ble->sec->close_transport_session(protoble_internal->pc_ble->sec_inst, event->disconnect.conn.conn_handle); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "error closing the session after disconnect"); + } + } + protoble_internal->gatt_mtu = BLE_ATT_MTU_DFLT; +} + +static void transport_simple_ble_connect(struct ble_gap_event *event, void *arg) +{ + esp_err_t ret; + ESP_LOGD(TAG, "Inside BLE connect w/ conn_id - %d", event->connect.conn_handle); + if (protoble_internal->pc_ble->sec && + protoble_internal->pc_ble->sec->new_transport_session) { + ret = + protoble_internal->pc_ble->sec->new_transport_session(protoble_internal->pc_ble->sec_inst, event->connect.conn_handle); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "error creating the session"); + } + } +} + +static void transport_simple_ble_set_mtu(struct ble_gap_event *event, void *arg) +{ + protoble_internal->gatt_mtu = event->mtu.value; + return; +} + +static esp_err_t protocomm_ble_add_endpoint(const char *ep_name, + protocomm_req_handler_t req_handler, + void *priv_data) +{ + /* Endpoint UUID already added when protocomm_ble_start() was called */ + return ESP_OK; +} + +static esp_err_t protocomm_ble_remove_endpoint(const char *ep_name) +{ + /* Endpoint UUID will be removed when protocomm_ble_stop() is called */ + return ESP_OK; +} + +/* Function to add descriptor to characteristic. The value of descriptor is + * filled with corresponding protocomm endpoint names. Characteristic address, + * its serial no. and XXX 16 bit standard UUID for descriptor to be provided as + * input parameters. Returns 0 on success and returns ESP_ERR_NO_MEM on + * failure. */ +static int +ble_gatt_add_char_dsc(struct ble_gatt_chr_def *characteristics, int idx, uint16_t dsc_uuid) +{ + ble_uuid_t *uuid16 = BLE_UUID16_DECLARE(dsc_uuid); + + /* Allocate memory for 2 descriptors, the 2nd descriptor shall be all NULLs + * to indicate End of Descriptors. */ + (characteristics + idx)->descriptors = (struct ble_gatt_dsc_def *) calloc(2, + sizeof(struct ble_gatt_dsc_def)); + if ((characteristics + idx)->descriptors == NULL) { + ESP_LOGE(TAG, "Error while allocating memory for characteristic descriptor"); + return ESP_ERR_NO_MEM; + } + + (characteristics + idx)->descriptors[0].uuid = (ble_uuid_t *) calloc(1, + sizeof(ble_uuid16_t)); + if ((characteristics + idx)->descriptors[0].uuid == NULL) { + ESP_LOGE(TAG, "Error while allocating memory for characteristic descriptor"); + return ESP_ERR_NO_MEM; + } + memcpy((void *)(characteristics + idx)->descriptors[0].uuid, uuid16, + sizeof(ble_uuid16_t)); + (characteristics + idx)->descriptors[0].att_flags = BLE_ATT_F_READ; + (characteristics + idx)->descriptors[0].access_cb = gatt_svr_dsc_access; + (characteristics + idx)->descriptors[0].arg = (void *) + protoble_internal->g_nu_lookup[idx].name; + + return 0; +} + +/* Function to add characteristics to the service. For simplicity the + * flags and access callbacks are same for all the characteristics. The Fn + * requires pointer to characteristic of service and index of characteristic, + * depending upon the index no. individual characteristics can be handled in + * future. The fn also assumes that the required memory for all characteristics + * is already allocated while adding corresponding service. Returns 0 on + * success and returns ESP_ERR_NO_MEM on failure to add characteristic. */ +static int +ble_gatt_add_characteristics(struct ble_gatt_chr_def *characteristics, int idx) +{ + /* Prepare 128 bit UUID of characteristics using custom base 128 + * bit UUID and replacing byte 12 and 13 with corresponding protocom + * endpoint 16 bit UUID value. */ + ble_uuid128_t temp_uuid128_name = {0}; + temp_uuid128_name.u.type = BLE_UUID_TYPE_128; + memcpy(temp_uuid128_name.value, ble_uuid_base, BLE_UUID128_VAL_LENGTH); + memcpy(&temp_uuid128_name.value[12], &protoble_internal->g_nu_lookup[idx].uuid, 2); + + (characteristics + idx)->flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE; + (characteristics + idx)->access_cb = gatt_svr_chr_access; + + /* Out of 128 bit UUID, 16 bits from g_nu_lookup table. Currently + * g_nu_lookup table has 16 bit UUID, XXX this can be changed to 128 bit UUID + * in future. For time being continue using 16 bit UUID on top of base 128 + * bit service UUID */ + (characteristics + idx)->uuid = (ble_uuid_t *)calloc(1, + sizeof(ble_uuid128_t)); + if ((characteristics + idx)->uuid == NULL) { + ESP_LOGE(TAG, "Error allocating memory for characteristic UUID"); + return ESP_ERR_NO_MEM; + } + memcpy((void *)(characteristics + idx)->uuid, &temp_uuid128_name, + sizeof(ble_uuid128_t)); + + return 0; +} + +/* Function to add primary service. It also allocates memory for the + * characteristics. Returns 0 on success, returns ESP_ERR_NO_MEM on failure to + * add service. */ +static int +ble_gatt_add_primary_svcs(struct ble_gatt_svc_def *gatt_db_svcs, int char_count) +{ + /* Remember the count of characteristics here, as it will be used to free + * memory afterwards */ + num_chr_dsc = char_count; + gatt_db_svcs->type = BLE_GATT_SVC_TYPE_PRIMARY; + + /* Allocate (number of characteristics + 1) memory for characteristics, the + * addtional characteristic consist of all 0s indicating end of + * characteristics */ + gatt_db_svcs->characteristics = (struct ble_gatt_chr_def *) calloc((char_count + 1), + sizeof(struct ble_gatt_chr_def)); + if (gatt_db_svcs->characteristics == NULL) { + ESP_LOGE(TAG, "Memory allocation for GATT characteristics failed"); + return ESP_ERR_NO_MEM; + } + return 0; +} + +static int +populate_gatt_db(struct ble_gatt_svc_def **gatt_db_svcs, const protocomm_ble_config_t *config) +{ + /* Allocate memory for 2 services, 2nd to be all NULL indicating end of + * services */ + *gatt_db_svcs = (struct ble_gatt_svc_def *) calloc(2, sizeof(struct ble_gatt_svc_def)); + if (*gatt_db_svcs == NULL) { + ESP_LOGE(TAG, "Error allocating memory for GATT services"); + return ESP_ERR_NO_MEM; + } + + /* Allocate space for 1st service UUID as well, assume length = 128 bit */ + (*gatt_db_svcs)->uuid = (ble_uuid_t *) calloc(1, sizeof(ble_uuid128_t)); + if ((*gatt_db_svcs)->uuid == NULL) { + ESP_LOGE(TAG, "Error allocating memory for GATT service UUID"); + return ESP_ERR_NO_MEM; + } + + /* Prepare 128 bit UUID for primary service from config service UUID. */ + ble_uuid128_t uuid128 = {0}; + uuid128.u.type = BLE_UUID_TYPE_128; + memcpy(uuid128.value, config->service_uuid, BLE_UUID128_VAL_LENGTH); + memcpy((void *) (*gatt_db_svcs)->uuid, &uuid128, sizeof(ble_uuid128_t)); + + /* GATT: Add primary service. */ + int rc = ble_gatt_add_primary_svcs(*gatt_db_svcs, config->nu_lookup_count); + if (rc != 0) { + ESP_LOGE(TAG, "Error adding primary service !!!"); + return rc; + } + + for (int i = 0 ; i < config->nu_lookup_count; i++) { + + /* GATT: Add characteristics to the service at index no. i*/ + rc = ble_gatt_add_characteristics((void *) (*gatt_db_svcs)->characteristics, i); + if (rc != 0) { + ESP_LOGE(TAG, "Error adding GATT characteristic !!!"); + return rc; + } + /* GATT: Add user description to characteristic no. i*/ + rc = ble_gatt_add_char_dsc((void *) (*gatt_db_svcs)->characteristics, + i, BLE_GATT_UUID_CHAR_DSC); + if (rc != 0) { + ESP_LOGE(TAG, "Error adding GATT Discriptor !!"); + return rc; + } + } + return 0; +} + +static void protocomm_ble_cleanup(void) +{ + if (protoble_internal) { + if (protoble_internal->g_nu_lookup) { + for (unsigned i = 0; i < protoble_internal->g_nu_lookup_count; i++) { + if (protoble_internal->g_nu_lookup[i].name) { + free((void *)protoble_internal->g_nu_lookup[i].name); + } + } + free(protoble_internal->g_nu_lookup); + } + free(protoble_internal); + protoble_internal = NULL; + } + if (protocomm_ble_device_name) { + free(protocomm_ble_device_name); + protocomm_ble_device_name = NULL; + } +} + +static void free_gatt_ble_misc_memory(simple_ble_cfg_t *ble_config) +{ + /* Free up gatt_db memory if exists */ + if (ble_config->gatt_db->characteristics) { + for (int i = 0; i < num_chr_dsc; i++) { + if ((ble_config->gatt_db->characteristics + i)->descriptors) { + free((void *)(ble_config->gatt_db->characteristics + i)->descriptors->uuid); + free((ble_config->gatt_db->characteristics + i)->descriptors); + } + free((void *)(ble_config->gatt_db->characteristics + i)->uuid); + } + free((void *)(ble_config->gatt_db->characteristics)); + } + + if (ble_config->gatt_db) { + free((void *)ble_config->gatt_db->uuid); + free(ble_config->gatt_db); + } + + if (ble_config) { + free(ble_config); + } + ble_config = NULL; + + /* Free the uuid_name_table struct list if exists */ + struct uuid128_name_buf *cur; + while (!SLIST_EMPTY(&uuid128_name_list)) { + cur = SLIST_FIRST(&uuid128_name_list); + SLIST_REMOVE_HEAD(&uuid128_name_list, link); + if (cur->uuid128_name_table) { + free(cur->uuid128_name_table); + } + free(cur); + } + + /* Free the data_mbuf list if exists */ + struct data_mbuf *curr; + while (!SLIST_EMPTY(&data_mbuf_list)) { + curr = SLIST_FIRST(&data_mbuf_list); + SLIST_REMOVE_HEAD(&data_mbuf_list, node); + free(curr->outbuf); + free(curr); + } +} + +esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *config) +{ + /* copy the 128 bit service UUID into local buffer to use as base 128 bit + * UUID. */ + memcpy(ble_uuid_base, config->service_uuid, BLE_UUID128_VAL_LENGTH); + + if (!pc || !config || !config->device_name || !config->nu_lookup) { + return ESP_ERR_INVALID_ARG; + } + + if (protoble_internal) { + ESP_LOGE(TAG, "Protocomm BLE already started"); + return ESP_FAIL; + } + + /* Store 128 bit service UUID internally. */ + ble_uuid128_t *svc_uuid128 = (ble_uuid128_t *) + calloc(1, sizeof(ble_uuid128_t)); + if (svc_uuid128 == NULL) { + ESP_LOGE(TAG, "Error while allocating memory for 128 bit UUID"); + return ESP_ERR_NO_MEM; + } + svc_uuid128->u.type = BLE_UUID_TYPE_128; + memcpy(svc_uuid128->value, config->service_uuid, BLE_UUID128_VAL_LENGTH); + adv_data.uuids128 = (void *)svc_uuid128; + + /* Store service uuid128 in SLIST, to free it afterwards */ + struct uuid128_name_buf *temp_uuid128_name_buf = (struct uuid128_name_buf *) + calloc(1, sizeof(struct uuid128_name_buf)); + + if (temp_uuid128_name_buf == NULL) { + ESP_LOGE(TAG, "Error allocating memory for UUID128 address database"); + return ESP_ERR_NO_MEM; + } + SLIST_INSERT_HEAD(&uuid128_name_list, temp_uuid128_name_buf, link); + temp_uuid128_name_buf->uuid128_name_table = svc_uuid128; + + if (adv_data.uuids128 == NULL) { + ESP_LOGE(TAG, "Error allocating memory for storing service UUID"); + protocomm_ble_cleanup(); + return ESP_ERR_NO_MEM; + } + + /* Store BLE device name internally */ + protocomm_ble_device_name = strdup(config->device_name); + + if (protocomm_ble_device_name == NULL) { + ESP_LOGE(TAG, "Error allocating memory for storing BLE device name"); + protocomm_ble_cleanup(); + return ESP_ERR_NO_MEM; + } + + protoble_internal = (_protocomm_ble_internal_t *) calloc(1, sizeof(_protocomm_ble_internal_t)); + if (protoble_internal == NULL) { + ESP_LOGE(TAG, "Error allocating internal protocomm structure"); + protocomm_ble_cleanup(); + return ESP_ERR_NO_MEM; + } + + protoble_internal->g_nu_lookup_count = config->nu_lookup_count; + protoble_internal->g_nu_lookup = malloc(config->nu_lookup_count * sizeof(protocomm_ble_name_uuid_t)); + if (protoble_internal->g_nu_lookup == NULL) { + ESP_LOGE(TAG, "Error allocating internal name UUID table"); + protocomm_ble_cleanup(); + return ESP_ERR_NO_MEM; + } + + for (unsigned i = 0; i < protoble_internal->g_nu_lookup_count; i++) { + protoble_internal->g_nu_lookup[i].uuid = config->nu_lookup[i].uuid; + protoble_internal->g_nu_lookup[i].name = strdup(config->nu_lookup[i].name); + if (protoble_internal->g_nu_lookup[i].name == NULL) { + ESP_LOGE(TAG, "Error allocating internal name UUID entry"); + protocomm_ble_cleanup(); + return ESP_ERR_NO_MEM; + } + } + + pc->add_endpoint = protocomm_ble_add_endpoint; + pc->remove_endpoint = protocomm_ble_remove_endpoint; + protoble_internal->pc_ble = pc; + protoble_internal->gatt_mtu = BLE_ATT_MTU_DFLT; + + simple_ble_cfg_t *ble_config = (simple_ble_cfg_t *) calloc(1, sizeof(simple_ble_cfg_t)); + if (ble_config == NULL) { + ESP_LOGE(TAG, "Ran out of memory for BLE config"); + protocomm_ble_cleanup(); + return ESP_ERR_NO_MEM; + } + + /* Set function pointers required for simple BLE layer */ + ble_config->connect_fn = transport_simple_ble_connect; + ble_config->disconnect_fn = transport_simple_ble_disconnect; + ble_config->set_mtu_fn = transport_simple_ble_set_mtu; + + /* Set parameters required for advertising */ + ble_config->adv_data = adv_data; + ble_config->adv_params = adv_params; + + ble_config->device_name = protocomm_ble_device_name; + + if (populate_gatt_db(&ble_config->gatt_db, config) != 0) { + ESP_LOGE(TAG, "Error populating GATT Database"); + free_gatt_ble_misc_memory(ble_config); + return ESP_ERR_NO_MEM; + } + + esp_err_t err = simple_ble_start(ble_config); + ESP_LOGD(TAG, "Free Heap size after simple_ble_start= %d", esp_get_free_heap_size()); + + if (err != ESP_OK) { + ESP_LOGE(TAG, "simple_ble_start failed w/ error code 0x%x", err); + free_gatt_ble_misc_memory(ble_config); + protocomm_ble_cleanup(); + return err; + } + + ESP_LOGV(TAG, "Waiting for client to connect ......"); + return ESP_OK; +} + +esp_err_t protocomm_ble_stop(protocomm_t *pc) +{ + ESP_LOGD(TAG, "protocomm_ble_stop called here..."); + if ((pc != NULL) && + (protoble_internal != NULL ) && + (pc == protoble_internal->pc_ble)) { + esp_err_t ret = ESP_OK; + + esp_err_t rc = ble_gap_adv_stop(); + if (rc) { + ESP_LOGD(TAG, "Error in stopping advertisement with err code = %d", + rc); + } + + ret = nimble_port_stop(); + if (ret == 0) { + nimble_port_deinit(); + ret = esp_nimble_hci_and_controller_deinit(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "esp_nimble_hci_and_controller_deinit() failed with error: %d", ret); + } + } + + free_gatt_ble_misc_memory(ble_cfg_p); + protocomm_ble_cleanup(); + return ret; + } + return ESP_ERR_INVALID_ARG; +} diff --git a/components/wifi_provisioning/CMakeLists.txt b/components/wifi_provisioning/CMakeLists.txt index 679a061a8b..41e09b17f3 100644 --- a/components/wifi_provisioning/CMakeLists.txt +++ b/components/wifi_provisioning/CMakeLists.txt @@ -9,7 +9,7 @@ set(srcs "src/wifi_config.c" "proto-c/wifi_constants.pb-c.c") if(CONFIG_BT_ENABLED) - if(CONFIG_BT_BLUEDROID_ENABLED) + if(CONFIG_BT_BLUEDROID_ENABLED OR CONFIG_BT_NIMBLE_ENABLED) list(APPEND srcs "src/scheme_ble.c") endif() diff --git a/components/wifi_provisioning/component.mk b/components/wifi_provisioning/component.mk index 458d957c76..66a43c3f24 100644 --- a/components/wifi_provisioning/component.mk +++ b/components/wifi_provisioning/component.mk @@ -2,6 +2,9 @@ COMPONENT_SRCDIRS := src proto-c COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_PRIV_INCLUDEDIRS := src proto-c ../protocomm/proto-c/ -ifneq ($(filter y, $(CONFIG_BT_ENABLED) $(CONFIG_BT_BLUEDROID_ENABLED)),y y) - COMPONENT_OBJEXCLUDE := src/scheme_ble.o +ifndef CONFIG_BT_BLUEDROID_ENABLED + ifndef CONFIG_BT_NIMBLE_ENABLED + COMPONENT_OBJEXCLUDE := src/scheme_ble.o + endif endif + diff --git a/examples/provisioning/ble_prov/main/app_prov.c b/examples/provisioning/ble_prov/main/app_prov.c index 4fec90b292..19ea1b311e 100644 --- a/examples/provisioning/ble_prov/main/app_prov.c +++ b/examples/provisioning/ble_prov/main/app_prov.c @@ -16,6 +16,13 @@ #include #include +#ifdef CONFIG_BT_NIMBLE_ENABLED +#include "esp_nimble_hci.h" +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" +#include "host/ble_hs.h" +#endif + #include #include #include diff --git a/examples/provisioning/manager/sdkconfig.defaults b/examples/provisioning/manager/sdkconfig.defaults index e28cc05069..b8548ff9db 100644 --- a/examples/provisioning/manager/sdkconfig.defaults +++ b/examples/provisioning/manager/sdkconfig.defaults @@ -3,8 +3,9 @@ CONFIG_BT_ENABLED=y CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY= CONFIG_BTDM_CTRL_MODE_BTDM= +CONFIG_BT_NIMBLE_ENABLED=y -# Binary is larger than default size +## For Bluedroid as binary is larger than default size CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" From ebcb08ec8901cd64c9b6ccfca4b267656b7cd888 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 19 Jun 2019 21:24:51 +0800 Subject: [PATCH 209/486] host tests: correct definition of CONFIG_SPI_FLASH_USE_LEGACY_IMPL --- components/nvs_flash/test_nvs_host/sdkconfig.h | 2 ++ components/spiffs/test_spiffs_host/sdkconfig/sdkconfig.h | 3 ++- components/wear_levelling/test_wl_host/sdkconfig/sdkconfig.h | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/components/nvs_flash/test_nvs_host/sdkconfig.h b/components/nvs_flash/test_nvs_host/sdkconfig.h index e69de29bb2..80ffec3016 100644 --- a/components/nvs_flash/test_nvs_host/sdkconfig.h +++ b/components/nvs_flash/test_nvs_host/sdkconfig.h @@ -0,0 +1,2 @@ +//currently use the legacy implementation, since the stubs for new HAL are not done yet +#define CONFIG_SPI_FLASH_USE_LEGACY_IMPL 1 diff --git a/components/spiffs/test_spiffs_host/sdkconfig/sdkconfig.h b/components/spiffs/test_spiffs_host/sdkconfig/sdkconfig.h index 5fd1979b19..f2fbfff6b5 100644 --- a/components/spiffs/test_spiffs_host/sdkconfig/sdkconfig.h +++ b/components/spiffs/test_spiffs_host/sdkconfig/sdkconfig.h @@ -18,4 +18,5 @@ #define CONFIG_ESPTOOLPY_FLASHSIZE "8MB" //currently use the legacy implementation, since the stubs for new HAL are not done yet -#define CONFIG_SPI_FLASH_USE_LEGACY_IMPL +#define CONFIG_SPI_FLASH_USE_LEGACY_IMPL 1 + diff --git a/components/wear_levelling/test_wl_host/sdkconfig/sdkconfig.h b/components/wear_levelling/test_wl_host/sdkconfig/sdkconfig.h index d630f1a8e4..0c44e1b77a 100644 --- a/components/wear_levelling/test_wl_host/sdkconfig/sdkconfig.h +++ b/components/wear_levelling/test_wl_host/sdkconfig/sdkconfig.h @@ -5,5 +5,5 @@ #define CONFIG_PARTITION_TABLE_OFFSET 0x8000 #define CONFIG_ESPTOOLPY_FLASHSIZE "8MB" //currently use the legacy implementation, since the stubs for new HAL are not done yet -#define CONFIG_SPI_FLASH_USE_LEGACY_IMPL +#define CONFIG_SPI_FLASH_USE_LEGACY_IMPL 1 From ec427a5b4308bcea7837bd3309748279f95b6788 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 19 Jun 2019 01:31:43 +0800 Subject: [PATCH 210/486] spi_flash: support for partitions in external flash --- components/spi_flash/esp_flash_api.c | 7 +- components/spi_flash/include/esp_partition.h | 40 +++++++ components/spi_flash/partition.c | 113 +++++++++++++++++- components/spi_flash/sim/flash_mock.cpp | 2 + .../spi_flash/test/test_partition_ext.c | 47 ++++++++ 5 files changed, 202 insertions(+), 7 deletions(-) create mode 100644 components/spi_flash/test/test_partition_ext.c diff --git a/components/spi_flash/esp_flash_api.c b/components/spi_flash/esp_flash_api.c index f86b9c749e..1ce52e47b2 100644 --- a/components/spi_flash/esp_flash_api.c +++ b/components/spi_flash/esp_flash_api.c @@ -621,6 +621,8 @@ inline static IRAM_ATTR bool regions_overlap(uint32_t a_start, uint32_t a_len,ui Adapter layer to original api before IDF v4.0 ------------------------------------------------------------------------------*/ +#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL + static esp_err_t spi_flash_translate_rc(esp_err_t err) { switch (err) { @@ -644,7 +646,6 @@ static esp_err_t spi_flash_translate_rc(esp_err_t err) return ESP_OK; } -#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL esp_err_t spi_flash_erase_range(uint32_t start_addr, uint32_t size) { esp_err_t err = esp_flash_erase_region(NULL, start_addr, size); @@ -655,8 +656,6 @@ esp_err_t spi_flash_write(size_t dst, const void *srcv, size_t size) { esp_err_t err = esp_flash_write(NULL, srcv, dst, size); return spi_flash_translate_rc(err); - - //CHECK_WRITE_ADDRESS(dst, size); } esp_err_t spi_flash_read(size_t src, void *dstv, size_t size) @@ -671,4 +670,4 @@ esp_err_t spi_flash_unlock() return spi_flash_translate_rc(err); } -#endif +#endif // CONFIG_SPI_FLASH_USE_LEGACY_IMPL diff --git a/components/spi_flash/include/esp_partition.h b/components/spi_flash/include/esp_partition.h index 6537967eb7..d9ec1e3a52 100644 --- a/components/spi_flash/include/esp_partition.h +++ b/components/spi_flash/include/esp_partition.h @@ -19,8 +19,10 @@ #include #include #include "esp_err.h" +#include "esp_flash.h" #include "esp_spi_flash.h" + #ifdef __cplusplus extern "C" { #endif @@ -98,6 +100,7 @@ typedef struct esp_partition_iterator_opaque_* esp_partition_iterator_t; * However, this is the format used by this API. */ typedef struct { + esp_flash_t* flash_chip; /*!< SPI flash chip on which the partition resides */ esp_partition_type_t type; /*!< partition type (app/data) */ esp_partition_subtype_t subtype; /*!< partition subtype */ uint32_t address; /*!< starting address of the partition in flash */ @@ -320,6 +323,43 @@ esp_err_t esp_partition_get_sha256(const esp_partition_t *partition, uint8_t *sh */ bool esp_partition_check_identity(const esp_partition_t *partition_1, const esp_partition_t *partition_2); +/** + * @brief Register a partition on an external flash chip + * + * This API allows designating certain areas of external flash chips (identified by the esp_flash_t structure) + * as partitions. This allows using them with components which access SPI flash through the esp_partition API. + * + * @param flash_chip Pointer to the structure identifying the flash chip + * @param offset Address in bytes, where the partition starts + * @param size Size of the partition in bytes + * @param label Partition name + * @param type One of the partition types (ESP_PARTITION_TYPE_*). Note that applications can not be booted from external flash + * chips, so using ESP_PARTITION_TYPE_APP is not supported. + * @param subtype One of the partition subtypes (ESP_PARTITION_SUBTYPE_*) + * @param[out] out_partition Output, if non-NULL, receives the pointer to the resulting esp_partition_t structure + * @return + * - ESP_OK on success + * - ESP_ERR_NOT_SUPPORTED if CONFIG_CONFIG_SPI_FLASH_USE_LEGACY_IMPL is enabled + * - ESP_ERR_NO_MEM if memory allocation has failed + * - ESP_ERR_INVALID_ARG if the new partition overlaps another partition on the same flash chip + * - ESP_ERR_INVALID_SIZE if the partition doesn't fit into the flash chip size + */ +esp_err_t esp_partition_register_external(esp_flash_t* flash_chip, size_t offset, size_t size, + const char* label, esp_partition_type_t type, esp_partition_subtype_t subtype, + const esp_partition_t** out_partition); + +/** + * @brief Deregister the partition previously registered using esp_partition_register_external + * @param partition pointer to the partition structure obtained from esp_partition_register_external, + * @return + * - ESP_OK on success + * - ESP_ERR_NOT_FOUND if the partition pointer is not found + * - ESP_ERR_INVALID_ARG if the partition comes from the partition table + * - ESP_ERR_INVALID_ARG if the partition was not registered using + * esp_partition_register_external function. + */ +esp_err_t esp_partition_deregister_external(const esp_partition_t* partition); + #ifdef __cplusplus } #endif diff --git a/components/spi_flash/partition.c b/components/spi_flash/partition.c index 5da204ae56..6876ee71ad 100644 --- a/components/spi_flash/partition.c +++ b/components/spi_flash/partition.c @@ -19,11 +19,13 @@ #include #include "esp_flash_partitions.h" #include "esp_attr.h" +#include "esp_flash.h" #include "esp_spi_flash.h" #include "esp_partition.h" #include "esp_flash_encrypt.h" #include "esp_log.h" #include "bootloader_common.h" +#include "bootloader_util.h" #include "esp_ota_ops.h" #define HASH_LEN 32 /* SHA-256 digest length */ @@ -35,8 +37,10 @@ #include "sys/queue.h" + typedef struct partition_list_item_ { esp_partition_t info; + bool user_registered; SLIST_ENTRY(partition_list_item_) next; } partition_list_item_t; @@ -163,12 +167,18 @@ static esp_err_t load_partitions() break; } // allocate new linked list item and populate it with data from partition table - partition_list_item_t* item = (partition_list_item_t*) malloc(sizeof(partition_list_item_t)); + partition_list_item_t* item = (partition_list_item_t*) calloc(sizeof(partition_list_item_t), 1); + if (item == NULL) { + err = ESP_ERR_NO_MEM; + break; + } + item->info.flash_chip = esp_flash_default_chip; item->info.address = it->pos.offset; item->info.size = it->pos.size; item->info.type = it->type; item->info.subtype = it->subtype; item->info.encrypted = it->flags & PART_FLAG_ENCRYPTED; + item->user_registered = false; if (!esp_flash_encryption_enabled()) { /* If flash encryption is not turned on, no partitions should be treated as encrypted */ @@ -193,7 +203,7 @@ static esp_err_t load_partitions() last = item; } spi_flash_munmap(handle); - return ESP_OK; + return err; } void esp_partition_iterator_release(esp_partition_iterator_t iterator) @@ -208,6 +218,80 @@ const esp_partition_t* esp_partition_get(esp_partition_iterator_t iterator) return iterator->info; } +esp_err_t esp_partition_register_external(esp_flash_t* flash_chip, size_t offset, size_t size, + const char* label, esp_partition_type_t type, esp_partition_subtype_t subtype, + const esp_partition_t** out_partition) +{ + if (out_partition != NULL) { + *out_partition = NULL; + } +#ifdef CONFIG_SPI_FLASH_USE_LEGACY_IMPL + return ESP_ERR_NOT_SUPPORTED; +#endif + + if (offset + size > flash_chip->size) { + return ESP_ERR_INVALID_SIZE; + } + + partition_list_item_t* item = (partition_list_item_t*) calloc(sizeof(partition_list_item_t), 1); + if (item == NULL) { + return ESP_ERR_NO_MEM; + } + item->info.flash_chip = flash_chip; + item->info.address = offset; + item->info.size = size; + item->info.type = type; + item->info.subtype = subtype; + item->info.encrypted = false; + item->user_registered = true; + strlcpy(item->info.label, label, sizeof(item->info.label)); + + _lock_acquire(&s_partition_list_lock); + partition_list_item_t *it, *last = NULL; + SLIST_FOREACH(it, &s_partition_list, next) { + /* Check if the new partition overlaps an existing one */ + if (it->info.flash_chip == flash_chip && + bootloader_util_regions_overlap(offset, offset + size, + it->info.address, it->info.address + it->info.size)) { + _lock_release(&s_partition_list_lock); + free(item); + return ESP_ERR_INVALID_ARG; + } + last = it; + } + if (last == NULL) { + SLIST_INSERT_HEAD(&s_partition_list, item, next); + } else { + SLIST_INSERT_AFTER(last, item, next); + } + _lock_release(&s_partition_list_lock); + if (out_partition != NULL) { + *out_partition = &item->info; + } + return ESP_OK; +} + +esp_err_t esp_partition_deregister_external(const esp_partition_t* partition) +{ + esp_err_t result = ESP_ERR_NOT_FOUND; + _lock_acquire(&s_partition_list_lock); + partition_list_item_t *it; + SLIST_FOREACH(it, &s_partition_list, next) { + if (&it->info == partition) { + if (!it->user_registered) { + result = ESP_ERR_INVALID_ARG; + break; + } + SLIST_REMOVE(&s_partition_list, it, partition_list_item_, next); + free(it); + result = ESP_OK; + break; + } + } + _lock_release(&s_partition_list_lock); + return result; +} + const esp_partition_t *esp_partition_verify(const esp_partition_t *partition) { assert(partition != NULL); @@ -218,7 +302,8 @@ const esp_partition_t *esp_partition_verify(const esp_partition_t *partition) while (it != NULL) { const esp_partition_t *p = esp_partition_get(it); /* Can't memcmp() whole structure here as padding contents may be different */ - if (p->address == partition->address + if (p->flash_chip == partition->flash_chip + && p->address == partition->address && partition->size == p->size && partition->encrypted == p->encrypted) { esp_partition_iterator_release(it); @@ -242,9 +327,17 @@ esp_err_t esp_partition_read(const esp_partition_t* partition, } if (!partition->encrypted) { +#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL + return esp_flash_read(partition->flash_chip, dst, partition->address + src_offset, size); +#else return spi_flash_read(partition->address + src_offset, dst, size); +#endif // CONFIG_SPI_FLASH_USE_LEGACY_IMPL } else { #if CONFIG_SECURE_FLASH_ENC_ENABLED + if (partition->flash_chip != esp_flash_default_chip) { + return ESP_ERR_NOT_SUPPORTED; + } + /* Encrypted partitions need to be read via a cache mapping */ const void *buf; spi_flash_mmap_handle_t handle; @@ -276,9 +369,16 @@ esp_err_t esp_partition_write(const esp_partition_t* partition, } dst_offset = partition->address + dst_offset; if (!partition->encrypted) { +#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL + return esp_flash_write(partition->flash_chip, src, dst_offset, size); +#else return spi_flash_write(dst_offset, src, size); +#endif // CONFIG_SPI_FLASH_USE_LEGACY_IMPL } else { #if CONFIG_SECURE_FLASH_ENC_ENABLED + if (partition->flash_chip != esp_flash_default_chip) { + return ESP_ERR_NOT_SUPPORTED; + } return spi_flash_write_encrypted(dst_offset, src, size); #else return ESP_ERR_NOT_SUPPORTED; @@ -302,7 +402,11 @@ esp_err_t esp_partition_erase_range(const esp_partition_t* partition, if (start_addr % SPI_FLASH_SEC_SIZE != 0) { return ESP_ERR_INVALID_ARG; } +#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL + return esp_flash_erase_region(partition->flash_chip, partition->address + start_addr, size); +#else return spi_flash_erase_range(partition->address + start_addr, size); +#endif // CONFIG_SPI_FLASH_USE_LEGACY_IMPL } @@ -325,6 +429,9 @@ esp_err_t esp_partition_mmap(const esp_partition_t* partition, uint32_t offset, if (offset + size > partition->size) { return ESP_ERR_INVALID_SIZE; } + if (partition->flash_chip != esp_flash_default_chip) { + return ESP_ERR_NOT_SUPPORTED; + } size_t phys_addr = partition->address + offset; // offset within 64kB block size_t region_offset = phys_addr & 0xffff; diff --git a/components/spi_flash/sim/flash_mock.cpp b/components/spi_flash/sim/flash_mock.cpp index 9535bf29b1..1a275d5180 100644 --- a/components/spi_flash/sim/flash_mock.cpp +++ b/components/spi_flash/sim/flash_mock.cpp @@ -109,3 +109,5 @@ void *heap_caps_malloc( size_t size, uint32_t caps ) { return NULL; } + +esp_flash_t* esp_flash_default_chip = NULL; diff --git a/components/spi_flash/test/test_partition_ext.c b/components/spi_flash/test/test_partition_ext.c new file mode 100644 index 0000000000..ead550879d --- /dev/null +++ b/components/spi_flash/test/test_partition_ext.c @@ -0,0 +1,47 @@ +#include "esp_flash.h" +#include "esp_partition.h" +#include "unity.h" + + +TEST_CASE("Basic handling of a partition in external flash", "[partition]") +{ + esp_flash_t flash = { + .size = 1 * 1024 * 1024, + }; + + const esp_partition_type_t t = ESP_PARTITION_TYPE_DATA; + const esp_partition_subtype_t st = ESP_PARTITION_SUBTYPE_DATA_FAT; + const char* label = "ext_fat"; + + /* can register */ + const esp_partition_t* ext_partition; + TEST_ESP_OK(esp_partition_register_external(&flash, 0, flash.size, label, t, st, &ext_partition)); + + /* can find the registered partition */ + const esp_partition_t* found = esp_partition_find_first(t, st, label); + TEST_ASSERT_EQUAL_HEX(ext_partition, found); + TEST_ASSERT_EQUAL(found->size, flash.size); + TEST_ASSERT_EQUAL(found->address, 0); + + /* can deregister */ + TEST_ESP_OK(esp_partition_deregister_external(ext_partition)); + + /* can not deregister one of the partitions on the main flash chip */ + const esp_partition_t* nvs_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); + TEST_ASSERT_NOT_NULL(nvs_partition); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_partition_deregister_external(nvs_partition)); + + /* can not deregister an unknown partition */ + esp_partition_t dummy_partition = {}; + TEST_ESP_ERR(ESP_ERR_NOT_FOUND, esp_partition_deregister_external(&dummy_partition)); + + /* can not register a partition larger than the flash size */ + TEST_ESP_ERR(ESP_ERR_INVALID_SIZE, + esp_partition_register_external(&flash, 0, 2 * flash.size, "ext_fat", t, st, &ext_partition)); + + /* can not register an overlapping partition */ + TEST_ESP_OK(esp_partition_register_external(&flash, 0, 2 * SPI_FLASH_SEC_SIZE, "p1", t, st, &ext_partition)); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_partition_register_external(&flash, SPI_FLASH_SEC_SIZE, 2 * SPI_FLASH_SEC_SIZE, + "p2", t, st, NULL)); + TEST_ESP_OK(esp_partition_deregister_external(ext_partition)); +} From 1c17558e6e2601fea6b9b1c2ac1f6b4ce99b7421 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 19 Jun 2019 21:26:02 +0800 Subject: [PATCH 211/486] spi_flash: use same argument types in .h and .c files Fixes compilations on targets where size_t != uint32_t --- components/spi_flash/flash_ops.c | 2 +- components/spi_flash/include/esp_partition.h | 4 ++-- components/spi_flash/partition.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index dcfc6cc4cb..1b06447b1c 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -208,7 +208,7 @@ esp_err_t IRAM_ATTR spi_flash_erase_sector(size_t sec) #ifdef CONFIG_SPI_FLASH_USE_LEGACY_IMPL //deprecated, only used in compatible mode -esp_err_t IRAM_ATTR spi_flash_erase_range(uint32_t start_addr, uint32_t size) +esp_err_t IRAM_ATTR spi_flash_erase_range(size_t start_addr, size_t size) { CHECK_WRITE_ADDRESS(start_addr, size); if (start_addr % SPI_FLASH_SEC_SIZE != 0) { diff --git a/components/spi_flash/include/esp_partition.h b/components/spi_flash/include/esp_partition.h index d9ec1e3a52..ade2e9eab8 100644 --- a/components/spi_flash/include/esp_partition.h +++ b/components/spi_flash/include/esp_partition.h @@ -260,7 +260,7 @@ esp_err_t esp_partition_write(const esp_partition_t* partition, * or one of error codes from lower-level flash driver. */ esp_err_t esp_partition_erase_range(const esp_partition_t* partition, - uint32_t start_addr, uint32_t size); + size_t start_addr, size_t size); /** * @brief Configure MMU to map partition into data memory @@ -287,7 +287,7 @@ esp_err_t esp_partition_erase_range(const esp_partition_t* partition, * * @return ESP_OK, if successful */ -esp_err_t esp_partition_mmap(const esp_partition_t* partition, uint32_t offset, uint32_t size, +esp_err_t esp_partition_mmap(const esp_partition_t* partition, size_t offset, size_t size, spi_flash_mmap_memory_t memory, const void** out_ptr, spi_flash_mmap_handle_t* out_handle); diff --git a/components/spi_flash/partition.c b/components/spi_flash/partition.c index 6876ee71ad..b598fcd5f2 100644 --- a/components/spi_flash/partition.c +++ b/components/spi_flash/partition.c @@ -418,7 +418,7 @@ esp_err_t esp_partition_erase_range(const esp_partition_t* partition, * we can add esp_partition_mmapv which will accept an array of offsets and sizes, and return array of * mmaped pointers, and a single handle for all these regions. */ -esp_err_t esp_partition_mmap(const esp_partition_t* partition, uint32_t offset, uint32_t size, +esp_err_t esp_partition_mmap(const esp_partition_t* partition, size_t offset, size_t size, spi_flash_mmap_memory_t memory, const void** out_ptr, spi_flash_mmap_handle_t* out_handle) { From c730c9e397938206dc950b8bd02c972ccaa7e6d2 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Fri, 21 Jun 2019 20:31:22 +0800 Subject: [PATCH 212/486] nvs: minor host test fixes Fixes the tests to pass when some files already exist. Fixes clean target. Moves CONFIG_NVS_ENCRYPTION definition into sdkconfig.h. --- components/nvs_flash/test_nvs_host/Makefile | 12 ++++++------ components/nvs_flash/test_nvs_host/sdkconfig.h | 1 + components/nvs_flash/test_nvs_host/test_nvs.cpp | 9 +++++---- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/components/nvs_flash/test_nvs_host/Makefile b/components/nvs_flash/test_nvs_host/Makefile index 76a8a5b875..d509fd6ee3 100644 --- a/components/nvs_flash/test_nvs_host/Makefile +++ b/components/nvs_flash/test_nvs_host/Makefile @@ -21,7 +21,7 @@ SOURCE_FILES = \ crc.cpp \ main.cpp -CPPFLAGS += -I../include -I../src -I./ -I../../esp_common/include -I../../esp32/include -I ../../mbedtls/mbedtls/include -I ../../spi_flash/include -I ../../../tools/catch -fprofile-arcs -ftest-coverage -DCONFIG_NVS_ENCRYPTION +CPPFLAGS += -I../include -I../src -I./ -I../../esp_common/include -I../../esp32/include -I ../../mbedtls/mbedtls/include -I ../../spi_flash/include -I ../../soc/include -I ../../../tools/catch -fprofile-arcs -ftest-coverage CFLAGS += -fprofile-arcs -ftest-coverage CXXFLAGS += -std=c++11 -Wall -Werror LDFLAGS += -lstdc++ -Wall -fprofile-arcs -ftest-coverage @@ -61,10 +61,10 @@ clean: rm -f $(COVERAGE_FILES) *.gcov rm -rf coverage_report/ rm -f coverage.info - rm ../nvs_partition_generator/partition_single_page.bin - rm ../nvs_partition_generator/partition_multipage_blob.bin - rm ../nvs_partition_generator/partition_encrypted.bin - rm ../nvs_partition_generator/partition_encrypted_using_keygen.bin - rm ../nvs_partition_generator/partition_encrypted_using_keyfile.bin + rm -f ../nvs_partition_generator/partition_single_page.bin + rm -f ../nvs_partition_generator/partition_multipage_blob.bin + rm -f ../nvs_partition_generator/partition_encrypted.bin + rm -f ../nvs_partition_generator/partition_encrypted_using_keygen.bin + rm -f ../nvs_partition_generator/partition_encrypted_using_keyfile.bin .PHONY: clean all test long-test diff --git a/components/nvs_flash/test_nvs_host/sdkconfig.h b/components/nvs_flash/test_nvs_host/sdkconfig.h index 80ffec3016..a38e0a10d8 100644 --- a/components/nvs_flash/test_nvs_host/sdkconfig.h +++ b/components/nvs_flash/test_nvs_host/sdkconfig.h @@ -1,2 +1,3 @@ +#define CONFIG_NVS_ENCRYPTION 1 //currently use the legacy implementation, since the stubs for new HAL are not done yet #define CONFIG_SPI_FLASH_USE_LEGACY_IMPL 1 diff --git a/components/nvs_flash/test_nvs_host/test_nvs.cpp b/components/nvs_flash/test_nvs_host/test_nvs.cpp index a92a20bc67..8326235ab4 100644 --- a/components/nvs_flash/test_nvs_host/test_nvs.cpp +++ b/components/nvs_flash/test_nvs_host/test_nvs.cpp @@ -14,6 +14,7 @@ #include "catch.hpp" #include "nvs.hpp" #include "nvs_test_api.h" +#include "sdkconfig.h" #ifdef CONFIG_NVS_ENCRYPTION #include "nvs_encr.hpp" #endif @@ -2470,10 +2471,10 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit if (childpid == 0) { exit(execlp("bash", "bash", "-c", - "rm -rf ../../../tools/mass_mfg/host_test | \ - cp -rf ../../../tools/mass_mfg/testdata mfg_testdata | \ - cp -rf ../nvs_partition_generator/testdata . | \ - mkdir -p ../../../tools/mass_mfg/host_test",NULL)); + "rm -rf ../../../tools/mass_mfg/host_test && \ + cp -rf ../../../tools/mass_mfg/testdata mfg_testdata && \ + cp -rf ../nvs_partition_generator/testdata . && \ + mkdir -p ../../../tools/mass_mfg/host_test", NULL)); } else { CHECK(childpid > 0); waitpid(childpid, &status, 0); From 66e0b2f9df223bf45a12cd96558c40de52b3813c Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Fri, 14 Jun 2019 00:43:49 +0800 Subject: [PATCH 213/486] gdbstub: move to a separate component, support multiple targets --- components/esp32/CMakeLists.txt | 1 - components/esp32/Kconfig | 1 + components/esp32/gdbstub.c | 557 ------------------ components/esp_common/Kconfig | 18 - components/esp_gdbstub/CMakeLists.txt | 13 + components/esp_gdbstub/Kconfig | 25 + components/esp_gdbstub/component.mk | 4 + components/esp_gdbstub/esp32/gdbstub_esp32.c | 51 ++ .../esp_gdbstub/esp32/gdbstub_target_config.h | 18 + components/esp_gdbstub/include/esp_gdbstub.h | 27 + components/esp_gdbstub/linker.lf | 4 + .../private_include/esp_gdbstub_common.h | 151 +++++ components/esp_gdbstub/src/gdbstub.c | 343 +++++++++++ components/esp_gdbstub/src/packet.c | 177 ++++++ .../esp_gdbstub/xtensa/esp_gdbstub_arch.h | 91 +++ .../esp_gdbstub/xtensa/gdbstub_xtensa.c | 118 ++++ 16 files changed, 1023 insertions(+), 576 deletions(-) delete mode 100644 components/esp32/gdbstub.c create mode 100644 components/esp_gdbstub/CMakeLists.txt create mode 100644 components/esp_gdbstub/Kconfig create mode 100644 components/esp_gdbstub/component.mk create mode 100644 components/esp_gdbstub/esp32/gdbstub_esp32.c create mode 100644 components/esp_gdbstub/esp32/gdbstub_target_config.h create mode 100644 components/esp_gdbstub/include/esp_gdbstub.h create mode 100644 components/esp_gdbstub/linker.lf create mode 100644 components/esp_gdbstub/private_include/esp_gdbstub_common.h create mode 100644 components/esp_gdbstub/src/gdbstub.c create mode 100644 components/esp_gdbstub/src/packet.c create mode 100644 components/esp_gdbstub/xtensa/esp_gdbstub_arch.h create mode 100644 components/esp_gdbstub/xtensa/gdbstub_xtensa.c diff --git a/components/esp32/CMakeLists.txt b/components/esp32/CMakeLists.txt index 916113b533..f0ef035067 100644 --- a/components/esp32/CMakeLists.txt +++ b/components/esp32/CMakeLists.txt @@ -16,7 +16,6 @@ else() "esp_adapter.c" "esp_timer_esp32.c" "esp_himem.c" - "gdbstub.c" "hw_random.c" "int_wdt.c" "intr_alloc.c" diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index ad7f228d9a..6fdfcc3e2a 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -425,6 +425,7 @@ menu "ESP32-specific" config ESP32_PANIC_GDBSTUB bool "Invoke GDBStub" + select ESP_GDBSTUB_ENABLED help Invoke gdbstub on the serial port, allowing for gdb to attach to it to do a postmortem of the crash. diff --git a/components/esp32/gdbstub.c b/components/esp32/gdbstub.c deleted file mode 100644 index c690e42b59..0000000000 --- a/components/esp32/gdbstub.c +++ /dev/null @@ -1,557 +0,0 @@ -// 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. - -/****************************************************************************** - * Description: A stub to make the ESP32 debuggable by GDB over the serial - * port, at least enough to do a backtrace on panic. This gdbstub is read-only: - * it allows inspecting the ESP32 state - *******************************************************************************/ - -#include -#include "esp32/rom/ets_sys.h" -#include "soc/uart_periph.h" -#include "soc/gpio_periph.h" -#include "soc/soc_memory_layout.h" -#include "esp_private/gdbstub.h" -#include "driver/gpio.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "sdkconfig.h" - -//Length of buffer used to reserve GDB commands. Has to be at least able to fit the G command, which -//implies a minimum size of about 320 bytes. -#define PBUFLEN 512 - -static unsigned char cmd[PBUFLEN]; //GDB command input buffer -static char chsum; //Running checksum of the output packet - -#define ATTR_GDBFN - -//Receive a char from the uart. Uses polling and feeds the watchdog. -static int ATTR_GDBFN gdbRecvChar() { - int i; - while (((READ_PERI_REG(UART_STATUS_REG(0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT)==0) ; - i=READ_PERI_REG(UART_FIFO_REG(0)); - return i; -} - -//Send a char to the uart. -static void ATTR_GDBFN gdbSendChar(char c) { - while (((READ_PERI_REG(UART_STATUS_REG(0))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=126) ; - WRITE_PERI_REG(UART_FIFO_REG(0), c); -} - -//Send the start of a packet; reset checksum calculation. -static void ATTR_GDBFN gdbPacketStart() { - chsum=0; - gdbSendChar('$'); -} - -//Send a char as part of a packet -static void ATTR_GDBFN gdbPacketChar(char c) { - if (c=='#' || c=='$' || c=='}' || c=='*') { - gdbSendChar('}'); - gdbSendChar(c^0x20); - chsum+=(c^0x20)+'}'; - } else { - gdbSendChar(c); - chsum+=c; - } -} - -//Send a string as part of a packet -static void ATTR_GDBFN gdbPacketStr(const char *c) { - while (*c!=0) { - gdbPacketChar(*c); - c++; - } -} - -//Send a hex val as part of a packet. 'bits'/4 dictates the number of hex chars sent. -static void ATTR_GDBFN gdbPacketHex(int val, int bits) { - char hexChars[]="0123456789abcdef"; - int i; - for (i=bits; i>0; i-=4) { - gdbPacketChar(hexChars[(val>>(i-4))&0xf]); - } -} - -//Finish sending a packet. -static void ATTR_GDBFN gdbPacketEnd() { - gdbSendChar('#'); - gdbPacketHex(chsum, 8); -} - -//Error states used by the routines that grab stuff from the incoming gdb packet -#define ST_ENDPACKET -1 -#define ST_ERR -2 -#define ST_OK -3 -#define ST_CONT -4 - -//Grab a hex value from the gdb packet. Ptr will get positioned on the end -//of the hex string, as far as the routine has read into it. Bits/4 indicates -//the max amount of hex chars it gobbles up. Bits can be -1 to eat up as much -//hex chars as possible. -static long ATTR_GDBFN gdbGetHexVal(unsigned char **ptr, int bits) { - int i; - int no; - unsigned int v=0; - char c; - no=bits/4; - if (bits==-1) no=64; - for (i=0; i='0' && c<='9') { - v<<=4; - v|=(c-'0'); - } else if (c>='A' && c<='F') { - v<<=4; - v|=(c-'A')+10; - } else if (c>='a' && c<='f') { - v<<=4; - v|=(c-'a')+10; - } else if (c=='#') { - if (bits==-1) { - (*ptr)--; - return v; - } - return ST_ENDPACKET; - } else { - if (bits==-1) { - (*ptr)--; - return v; - } - return ST_ERR; - } - } - return v; -} - -//Swap an int into the form gdb wants it -static int ATTR_GDBFN iswap(int i) { - int r; - r=((i>>24)&0xff); - r|=((i>>16)&0xff)<<8; - r|=((i>>8)&0xff)<<16; - r|=((i>>0)&0xff)<<24; - return r; -} - -//Read a byte from ESP32 memory. -static unsigned char ATTR_GDBFN readbyte(unsigned int p) { - int *i=(int*)(p&(~3)); - if (p<0x20000000 || p>=0x80000000) return -1; - return *i>>((p&3)*8); -} - - -//Register file in the format exp108 gdb port expects it. -//Inspired by gdb/regformats/reg-xtensa.dat -typedef struct { - uint32_t pc; - uint32_t a[64]; - uint32_t lbeg; - uint32_t lend; - uint32_t lcount; - uint32_t sar; - uint32_t windowbase; - uint32_t windowstart; - uint32_t configid0; - uint32_t configid1; - uint32_t ps; - uint32_t threadptr; - uint32_t br; - uint32_t scompare1; - uint32_t acclo; - uint32_t acchi; - uint32_t m0; - uint32_t m1; - uint32_t m2; - uint32_t m3; - uint32_t expstate; //I'm going to assume this is exccause... - uint32_t f64r_lo; - uint32_t f64r_hi; - uint32_t f64s; - uint32_t f[16]; - uint32_t fcr; - uint32_t fsr; -} GdbRegFile; - - -GdbRegFile gdbRegFile; - -/* -//Register format as the Xtensa HAL has it: -STRUCT_FIELD (long, 4, XT_STK_EXIT, exit) -STRUCT_FIELD (long, 4, XT_STK_PC, pc) -STRUCT_FIELD (long, 4, XT_STK_PS, ps) -STRUCT_FIELD (long, 4, XT_STK_A0, a0) -[..] -STRUCT_FIELD (long, 4, XT_STK_A15, a15) -STRUCT_FIELD (long, 4, XT_STK_SAR, sar) -STRUCT_FIELD (long, 4, XT_STK_EXCCAUSE, exccause) -STRUCT_FIELD (long, 4, XT_STK_EXCVADDR, excvaddr) -STRUCT_FIELD (long, 4, XT_STK_LBEG, lbeg) -STRUCT_FIELD (long, 4, XT_STK_LEND, lend) -STRUCT_FIELD (long, 4, XT_STK_LCOUNT, lcount) -// Temporary space for saving stuff during window spill -STRUCT_FIELD (long, 4, XT_STK_TMP0, tmp0) -STRUCT_FIELD (long, 4, XT_STK_TMP1, tmp1) -STRUCT_FIELD (long, 4, XT_STK_TMP2, tmp2) -STRUCT_FIELD (long, 4, XT_STK_VPRI, vpri) -STRUCT_FIELD (long, 4, XT_STK_OVLY, ovly) -#endif -STRUCT_END(XtExcFrame) -*/ - -static void commonRegfile() { - if (gdbRegFile.a[0] & 0x8000000U) gdbRegFile.a[0] = (gdbRegFile.a[0] & 0x3fffffffU) | 0x40000000U; - if (!esp_stack_ptr_is_sane(gdbRegFile.a[1])) gdbRegFile.a[1] = 0xDEADBEEF; - gdbRegFile.windowbase=0; //0 - gdbRegFile.windowstart=0x1; //1 - gdbRegFile.configid0=0xdeadbeef; //ToDo - gdbRegFile.configid1=0xdeadbeef; //ToDo - gdbRegFile.threadptr=0xdeadbeef; //ToDo - gdbRegFile.br=0xdeadbeef; //ToDo - gdbRegFile.scompare1=0xdeadbeef; //ToDo - gdbRegFile.acclo=0xdeadbeef; //ToDo - gdbRegFile.acchi=0xdeadbeef; //ToDo - gdbRegFile.m0=0xdeadbeef; //ToDo - gdbRegFile.m1=0xdeadbeef; //ToDo - gdbRegFile.m2=0xdeadbeef; //ToDo - gdbRegFile.m3=0xdeadbeef; //ToDo -} - -static void dumpHwToRegfile(XtExcFrame *frame) { - int i; - long *frameAregs=&frame->a0; - gdbRegFile.pc=(frame->pc & 0x3fffffffU)|0x40000000U; - for (i=0; i<16; i++) gdbRegFile.a[i]=frameAregs[i]; - for (i=16; i<64; i++) gdbRegFile.a[i]=0xDEADBEEF; - gdbRegFile.lbeg=frame->lbeg; - gdbRegFile.lend=frame->lend; - gdbRegFile.lcount=frame->lcount; - gdbRegFile.ps=(frame->ps & PS_UM) ? (frame->ps & ~PS_EXCM) : frame->ps; - //All windows have been spilled to the stack by the ISR routines. The following values should indicate that. - gdbRegFile.sar=frame->sar; - commonRegfile(); - gdbRegFile.expstate=frame->exccause; //ToDo -} - -//Send the reason execution is stopped to GDB. -static void sendReason() { - //exception-to-signal mapping - char exceptionSignal[]={4,31,11,11,2,6,8,0,6,7,0,0,7,7,7,7}; - int i=0; - gdbPacketStart(); - gdbPacketChar('T'); - i=gdbRegFile.expstate&0x7f; - if (ia0; - gdbRegFile.pc=(frame->pc & 0x3fffffffU)|0x40000000U; - for (i=0; i<4; i++) gdbRegFile.a[i]=frameAregs[i]; - for (i=4; i<64; i++) gdbRegFile.a[i]=0xDEADBEEF; - gdbRegFile.lbeg=0; - gdbRegFile.lend=0; - gdbRegFile.lcount=0; - gdbRegFile.ps=(frame->ps & PS_UM) ? (frame->ps & ~PS_EXCM) : frame->ps; - //All windows have been spilled to the stack by the ISR routines. The following values should indicate that. - gdbRegFile.sar=0; - commonRegfile(); - gdbRegFile.expstate=0; //ToDo -} - -// Fetch the task status. Returns the total number of tasks. -static unsigned getTaskInfo(unsigned index, unsigned * handle, const char ** name, unsigned * coreId) { - static unsigned taskCount = 0; - static TaskSnapshot_t tasks[STUB_TASKS_NUM]; - - if (!taskCount) { - unsigned tcbSize = 0; - taskCount = uxTaskGetSnapshotAll(tasks, STUB_TASKS_NUM, &tcbSize); - } - if (index < taskCount) { - TaskHandle_t h = (TaskHandle_t)tasks[index].pxTCB; - if (handle) *handle = (unsigned)h; - if (name) *name = pcTaskGetTaskName(h); - if (coreId) *coreId = xTaskGetAffinity(h); - } - return taskCount; -} - -typedef struct -{ - uint8_t * topOfStack; -} DumpTCB; - - -static void dumpTCBToRegFile(unsigned handle) { - // A task handle is a pointer to a TCB in FreeRTOS - DumpTCB * tcb = (DumpTCB*)handle; - uint8_t * pxTopOfStack = tcb->topOfStack; - - //Deduced from coredump code - XtExcFrame * frame = (XtExcFrame*)pxTopOfStack; - if (frame->exit) { - // It's an exception frame - dumpHwToRegfile(frame); - } else { - XtSolFrame * taskFrame = (XtSolFrame*)pxTopOfStack; - dumpTaskToRegfile(taskFrame); - } -} - -#define CUR_TASK_INDEX_NOT_SET -2 -#define CUR_TASK_INDEX_UNKNOWN -1 - -// Get the index of the task currently running on the current CPU, and cache the result -static int findCurrentTaskIndex() { - static int curTaskIndex = CUR_TASK_INDEX_NOT_SET; - if (curTaskIndex == CUR_TASK_INDEX_NOT_SET) { - unsigned curHandle = (unsigned)xTaskGetCurrentTaskHandleForCPU(xPortGetCoreID()); - unsigned handle; - unsigned count = getTaskInfo(0, 0, 0, 0); - for(int k=0; k<(int)count; k++) { - if (getTaskInfo(k, &handle, 0, 0) && curHandle == handle) { - curTaskIndex = k; - return curTaskIndex; - } - } - curTaskIndex = CUR_TASK_INDEX_UNKNOWN; - } - return curTaskIndex; -} - -#endif // CONFIG_ESP_GDBSTUB_SUPPORT_TASKS - -//Handle a command as received from GDB. -static int gdbHandleCommand(unsigned char *cmd, int len) { - //Handle a command - int i, j, k; - unsigned char *data=cmd+1; - if (cmd[0]=='g') { //send all registers to gdb - int *p=(int*)&gdbRegFile; - gdbPacketStart(); - for (i=0; i 16 && cmd[1] == 'T' && cmd[2] == 'h' && cmd[3] == 'r' && cmd[7] == 'E' && cmd[12] == 'I' && cmd[16] == ',') { - data=&cmd[17]; - i=gdbGetHexVal(&data, -1); - - unsigned handle = 0, coreId = 3; - const char * name = 0; - // Extract the task name and CPU from freeRTOS - unsigned tCount = getTaskInfo(i, &handle, &name, &coreId); - if (i < tCount) { - gdbPacketStart(); - for(k=0; name[k]; k++) gdbPacketHex(name[k], 8); - gdbPacketStr("20435055"); // CPU - gdbPacketStr(coreId == 0 ? "30": coreId == 1 ? "31" : "78"); // 0 or 1 or x - gdbPacketEnd(); - return ST_OK; - } - } else if (len >= 12 && (cmd[1] == 'f' || cmd[1] == 's') && (cmd[2] == 'T' && cmd[3] == 'h' && cmd[4] == 'r' && cmd[5] == 'e' && cmd[6] == 'a' && cmd[7] == 'd' && cmd[8] == 'I')) { - // Only react to qfThreadInfo and qsThreadInfo, not using strcmp here since it can be in ROM - // Extract the number of task from freeRTOS - static int taskIndex = 0; - unsigned tCount = 0; - if (cmd[1] == 'f') { - taskIndex = 0; - handlerState = HANDLER_STARTED; //It seems it's the first request GDB is sending - } - tCount = getTaskInfo(0, 0, 0, 0); - if (taskIndex < tCount) { - gdbPacketStart(); - gdbPacketStr("m"); - gdbPacketHex(taskIndex, 32); - gdbPacketEnd(); - taskIndex++; - } else return sendPacket("l"); - } else if (len >= 2 && cmd[1] == 'C') { - // Get current task id - gdbPacketStart(); - k = findCurrentTaskIndex(); - if (k != CUR_TASK_INDEX_UNKNOWN) { - gdbPacketStr("QC"); - gdbPacketHex(k, 32); - } else gdbPacketStr("bad"); - gdbPacketEnd(); - return ST_OK; - } - return sendPacket(NULL); - } -#endif // CONFIG_ESP_GDBSTUB_SUPPORT_TASKS - } else { - //We don't recognize or support whatever GDB just sent us. - return sendPacket(NULL); - } - return ST_OK; -} - - -//Lower layer: grab a command packet and check the checksum -//Calls gdbHandleCommand on the packet if the checksum is OK -//Returns ST_OK on success, ST_ERR when checksum fails, a -//character if it is received instead of the GDB packet -//start char. -static int gdbReadCommand() { - unsigned char c; - unsigned char chsum=0, rchsum; - unsigned char sentchs[2]; - int p=0; - unsigned char *ptr; - c=gdbRecvChar(); - if (c!='$') return c; - while(1) { - c=gdbRecvChar(); - if (c=='#') { //end of packet, checksum follows - cmd[p]=0; - break; - } - chsum+=c; - if (c=='$') { - //Wut, restart packet? - chsum=0; - p=0; - continue; - } - if (c=='}') { //escape the next char - c=gdbRecvChar(); - chsum+=c; - c^=0x20; - } - cmd[p++]=c; - if (p>=PBUFLEN) return ST_ERR; - } - //A # has been received. Get and check the received chsum. - sentchs[0]=gdbRecvChar(); - sentchs[1]=gdbRecvChar(); - ptr=&sentchs[0]; - rchsum=gdbGetHexVal(&ptr, 8); - if (rchsum!=chsum) { - gdbSendChar('-'); - return ST_ERR; - } else { - gdbSendChar('+'); - return gdbHandleCommand(cmd, p); - } -} - - -void esp_gdbstub_panic_handler(XtExcFrame *frame) { -#if CONFIG_ESP_GDBSTUB_SUPPORT_TASKS - if (handlerState == HANDLER_STARTED) { - //We have re-entered GDB Stub. Try disabling task support. - handlerState = HANDLER_TASK_SUPPORT_DISABLED; - gdbPacketEnd(); // Ends up any pending GDB packet (this creates a garbage value) - } else if (handlerState == HANDLER_NOT_STARTED) { - //Need to remember the frame that panic'd since gdb will ask for all threads before ours - memcpy(&paniced_frame, frame, sizeof(paniced_frame)); - dumpHwToRegfile(&paniced_frame); - } -#else // CONFIG_ESP_GDBSTUB_SUPPORT_TASKS - dumpHwToRegfile(frame); -#endif // CONFIG_ESP_GDBSTUB_SUPPORT_TASKS - - //Make sure txd/rxd are enabled - gpio_pullup_dis(1); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_U0RXD); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_U0TXD); - - sendReason(); - while(gdbReadCommand()!=ST_CONT); - while(1); -} diff --git a/components/esp_common/Kconfig b/components/esp_common/Kconfig index 80f20e6069..ca5608b8e4 100644 --- a/components/esp_common/Kconfig +++ b/components/esp_common/Kconfig @@ -127,24 +127,6 @@ menu "Common ESP-related" range 1200 4000000 - config ESP_GDBSTUB_SUPPORT_TASKS - bool "GDBStub: enable listing FreeRTOS tasks" - default y - depends on ESP32_PANIC_GDBSTUB - help - If enabled, GDBStub can supply the list of FreeRTOS tasks to GDB. - Thread list can be queried from GDB using 'info threads' command. - Note that if GDB task lists were corrupted, this feature may not work. - If GDBStub fails, try disabling this feature. - - config ESP_GDBSTUB_MAX_TASKS - int "GDBStub: maximum number of tasks supported" - default 32 - depends on ESP_GDBSTUB_SUPPORT_TASKS - help - Set the number of tasks which GDB Stub will support. - - config ESP_INT_WDT bool "Interrupt watchdog" default y diff --git a/components/esp_gdbstub/CMakeLists.txt b/components/esp_gdbstub/CMakeLists.txt new file mode 100644 index 0000000000..14528a4b52 --- /dev/null +++ b/components/esp_gdbstub/CMakeLists.txt @@ -0,0 +1,13 @@ +idf_build_get_property(target IDF_TARGET) + +set(esp_gdbstub_srcs "src/gdbstub.c" + "src/packet.c" + "${target}/gdbstub_${target}.c" + "xtensa/gdbstub_xtensa.c") + +idf_component_register(SRCS "${esp_gdbstub_srcs}" + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "private_include" "${target}" "xtensa" + LDFRAGMENTS "linker.lf" + REQUIRES "freertos" + PRIV_REQUIRES "soc" "xtensa" "esp_rom") diff --git a/components/esp_gdbstub/Kconfig b/components/esp_gdbstub/Kconfig new file mode 100644 index 0000000000..14e7d859c2 --- /dev/null +++ b/components/esp_gdbstub/Kconfig @@ -0,0 +1,25 @@ +menu "GDB Stub" + + # Hidden option which is selected from the "Panic handler behavior" + # menu in the target component. + config ESP_GDBSTUB_ENABLED + bool + + config ESP_GDBSTUB_SUPPORT_TASKS + bool "Enable listing FreeRTOS tasks through GDB Stub" + depends on ESP_GDBSTUB_ENABLED + default y + help + If enabled, GDBStub can supply the list of FreeRTOS tasks to GDB. + Thread list can be queried from GDB using 'info threads' command. + Note that if GDB task lists were corrupted, this feature may not work. + If GDBStub fails, try disabling this feature. + + config ESP_GDBSTUB_MAX_TASKS + int "Maximum number of tasks supported by GDB Stub" + default 32 + depends on ESP_GDBSTUB_SUPPORT_TASKS + help + Set the number of tasks which GDB Stub will support. + +endmenu diff --git a/components/esp_gdbstub/component.mk b/components/esp_gdbstub/component.mk new file mode 100644 index 0000000000..97dfce265f --- /dev/null +++ b/components/esp_gdbstub/component.mk @@ -0,0 +1,4 @@ +COMPONENT_ADD_INCLUDEDIRS := include +COMPONENT_PRIV_INCLUDEDIRS := private_include esp32 xtensa +COMPONENT_SRCDIRS := src esp32 xtensa +COMPONENT_ADD_LDFRAGMENTS += linker.lf diff --git a/components/esp_gdbstub/esp32/gdbstub_esp32.c b/components/esp_gdbstub/esp32/gdbstub_esp32.c new file mode 100644 index 0000000000..3fe393a0db --- /dev/null +++ b/components/esp_gdbstub/esp32/gdbstub_esp32.c @@ -0,0 +1,51 @@ +// Copyright 2015-2019 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 "soc/uart_periph.h" +#include "soc/gpio_periph.h" +#include "esp_gdbstub_common.h" +#include "sdkconfig.h" + +#define UART_NUM CONFIG_CONSOLE_UART_NUM + +void esp_gdbstub_target_init() +{ +} + +int esp_gdbstub_getchar() +{ + while (REG_GET_FIELD(UART_STATUS_REG(UART_NUM), UART_RXFIFO_CNT) == 0) { + ; + } + return REG_READ(UART_FIFO_REG(UART_NUM)); +} + +void esp_gdbstub_putchar(int c) +{ + while (REG_GET_FIELD(UART_STATUS_REG(UART_NUM), UART_TXFIFO_CNT) >= 126) { + ; + } + REG_WRITE(UART_FIFO_REG(UART_NUM), c); +} + +int esp_gdbstub_readmem(intptr_t addr) +{ + if (addr < 0x20000000 || addr >= 0x80000000) { + /* see cpu_configure_region_protection */ + return -1; + } + uint32_t val_aligned = *(uint32_t *)(addr & (~3)); + uint32_t shift = (addr & 3) * 8; + return (val_aligned >> shift) & 0xff; +} diff --git a/components/esp_gdbstub/esp32/gdbstub_target_config.h b/components/esp_gdbstub/esp32/gdbstub_target_config.h new file mode 100644 index 0000000000..ae31ae9dae --- /dev/null +++ b/components/esp_gdbstub/esp32/gdbstub_target_config.h @@ -0,0 +1,18 @@ +// Copyright 2019 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 + +/* Number of extra TIE defined registers, not listed in the XCHAL */ +#define GDBSTUB_EXTRA_TIE_SIZE 0 diff --git a/components/esp_gdbstub/include/esp_gdbstub.h b/components/esp_gdbstub/include/esp_gdbstub.h new file mode 100644 index 0000000000..02fda63e58 --- /dev/null +++ b/components/esp_gdbstub/include/esp_gdbstub.h @@ -0,0 +1,27 @@ +// Copyright 2015-2019 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 + +#include "esp_gdbstub_arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void esp_gdbstub_panic_handler(esp_gdbstub_frame_t *frame) __attribute__((noreturn)); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_gdbstub/linker.lf b/components/esp_gdbstub/linker.lf new file mode 100644 index 0000000000..b5d88a2675 --- /dev/null +++ b/components/esp_gdbstub/linker.lf @@ -0,0 +1,4 @@ +[mapping:esp_gdbstub] +archive: libesp_gdbstub.a +entries: + * (noflash) diff --git a/components/esp_gdbstub/private_include/esp_gdbstub_common.h b/components/esp_gdbstub/private_include/esp_gdbstub_common.h new file mode 100644 index 0000000000..75674ff026 --- /dev/null +++ b/components/esp_gdbstub/private_include/esp_gdbstub_common.h @@ -0,0 +1,151 @@ +// Copyright 2015-2019 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 + +#include +#include +#include + +#include "esp_gdbstub.h" +#include "sdkconfig.h" + +#ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#endif // CONFIG_ESP_GDBSTUB_SUPPORT_TASKS + +/* Internal error codes used by the routines that parse the incoming gdb packet */ +#define GDBSTUB_ST_ENDPACKET -1 +#define GDBSTUB_ST_ERR -2 +#define GDBSTUB_ST_OK -3 + +/* Special task index values */ +#define GDBSTUB_CUR_TASK_INDEX_UNKNOWN -1 + +/* Cab be set to a lower value in gdbstub_target_config.h */ +#ifndef GDBSTUB_CMD_BUFLEN +#define GDBSTUB_CMD_BUFLEN 512 +#endif + +#if CONFIG_ESP_GDBSTUB_SUPPORT_TASKS +typedef enum { + GDBSTUB_NOT_STARTED, + GDBSTUB_STARTED, + GDBSTUB_TASK_SUPPORT_DISABLED +} esp_gdbstub_state_t; + +#define GDBSTUB_TASKS_NUM CONFIG_ESP_GDBSTUB_MAX_TASKS + +#endif // CONFIG_ESP_GDBSTUB_SUPPORT_TASKS + +/* gdbstub temporary run-time data, stored in .bss to reduce stack usage */ +typedef struct { + esp_gdbstub_gdb_regfile_t regfile; + int signal; +#if CONFIG_ESP_GDBSTUB_SUPPORT_TASKS + esp_gdbstub_state_t state; + int task_count; + int paniced_task_index; + int current_task_index; + int thread_info_index; //!< index of the last task passed to qsThreadInfo + esp_gdbstub_frame_t paniced_frame; + TaskSnapshot_t tasks[GDBSTUB_TASKS_NUM]; // TODO: add an API to get snapshots one by one +#endif // CONFIG_ESP_GDBSTUB_SUPPORT_TASKS +} esp_gdbstub_scratch_t; + + +/**** Functions provided by the architecture specific part ****/ + +/** + * @param frame exception frame pointer + * @return the appropriate "signal" number for the given exception cause + */ +int esp_gdbstub_get_signal(const esp_gdbstub_frame_t *frame); + +/** + * Write registers from the exception frame to the GDB register file + * @param frame exception frame to parse + * @param dst pointer to the GDB register file + */ +void esp_gdbstub_frame_to_regfile(const esp_gdbstub_frame_t *frame, esp_gdbstub_gdb_regfile_t *dst); + +#if CONFIG_ESP_GDBSTUB_SUPPORT_TASKS +/** + * Write registers from the saved frame of a given task to the GDB register file + * @param tcb pointer to the TCB of the task + * @param dst pointer to the GDB register file + */ +void esp_gdbstub_tcb_to_regfile(TaskHandle_t tcb, esp_gdbstub_gdb_regfile_t *dst); +#endif // CONFIG_ESP_GDBSTUB_SUPPORT_TASKS + + + +/**** Functions provided by the target specific part ****/ + +/** + * Do target-specific initialization before gdbstub can start communicating. + * This may involve, for example, configuring the UART. + */ +void esp_gdbstub_target_init(); + +/** + * Receive a byte from the GDB client. Blocks until a byte is available. + * @return received byte + */ +int esp_gdbstub_getchar(); + +/** + * Send a byte to the GDB client + * @param c byte to send + */ +void esp_gdbstub_putchar(int c); + +/** + * Read a byte from target memory + * @param ptr address + * @return byte value, or GDBSTUB_ST_ERR if the address is not readable + */ +int esp_gdbstub_readmem(intptr_t addr); + + +/**** GDB packet related functions ****/ + +/** Begin a packet */ +void esp_gdbstub_send_start(); + +/** Send a character as part of the packet */ +void esp_gdbstub_send_char(char c); + +/** Send a string as part of the packet */ +void esp_gdbstub_send_str(const char *s); + +/** Send a hex value as part of the packet */ +void esp_gdbstub_send_hex(int val, int bits); + +/** Finish sending the packet */ +void esp_gdbstub_send_end(); + +/** Send a packet with a string as content */ +void esp_gdbstub_send_str_packet(const char* str); + +/** Get a hex value from the gdb packet */ +uint32_t esp_gdbstub_gethex(const unsigned char **ptr, int bits); + +/** Read, unescape, and validate the incoming GDB command */ +int esp_gdbstub_read_command(unsigned char **out_cmd, size_t *out_size); + +/** Handle a command received from gdb */ +int esp_gdbstub_handle_command(unsigned char *cmd, int len); + diff --git a/components/esp_gdbstub/src/gdbstub.c b/components/esp_gdbstub/src/gdbstub.c new file mode 100644 index 0000000000..4d1f4cf54c --- /dev/null +++ b/components/esp_gdbstub/src/gdbstub.c @@ -0,0 +1,343 @@ +// Copyright 2015-2019 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 +#include "esp_gdbstub.h" +#include "esp_gdbstub_common.h" +#include "sdkconfig.h" + + +#ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS +static void init_task_info(); +static void find_paniced_task_index(); +static int handle_task_commands(unsigned char *cmd, int len); +#endif + +static void send_reason(); + + +static esp_gdbstub_scratch_t s_scratch; + + +void esp_gdbstub_panic_handler(esp_gdbstub_frame_t *frame) +{ +#ifndef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS + esp_gdbstub_frame_to_regfile(frame, &s_scratch.regfile); +#else + if (s_scratch.state == GDBSTUB_STARTED) { + /* We have re-entered GDB Stub. Try disabling task support. */ + s_scratch.state = GDBSTUB_TASK_SUPPORT_DISABLED; + /* Flush any pending GDB packet (this creates a garbage value) */ + esp_gdbstub_send_end(); + } else if (s_scratch.state == GDBSTUB_NOT_STARTED) { + s_scratch.state = GDBSTUB_STARTED; + /* Save the paniced frame and get the list of tasks */ + memcpy(&s_scratch.paniced_frame, frame, sizeof(*frame)); + esp_gdbstub_frame_to_regfile(frame, &s_scratch.regfile); + init_task_info(); + find_paniced_task_index(); + /* Current task is the paniced task */ + if (s_scratch.paniced_task_index == GDBSTUB_CUR_TASK_INDEX_UNKNOWN) { + s_scratch.current_task_index = 0; + } + } +#endif // CONFIG_ESP_GDBSTUB_SUPPORT_TASKS + + esp_gdbstub_target_init(); + s_scratch.signal = esp_gdbstub_get_signal(frame); + send_reason(); + while (true) { + unsigned char *cmd; + size_t size; + int res = esp_gdbstub_read_command(&cmd, &size); + if (res > 0) { + /* character received instead of a command */ + continue; + } + if (res == GDBSTUB_ST_ERR) { + esp_gdbstub_send_str_packet("E01"); + continue; + } + res = esp_gdbstub_handle_command(cmd, size); + if (res == GDBSTUB_ST_ERR) { + esp_gdbstub_send_str_packet(NULL); + } + } +} + + +static void send_reason() +{ + esp_gdbstub_send_start(); + esp_gdbstub_send_char('T'); + esp_gdbstub_send_hex(s_scratch.signal, 8); + esp_gdbstub_send_end(); +} + +static uint32_t gdbstub_hton(uint32_t i) +{ + return __builtin_bswap32(i); +} + +/** Send all registers to gdb */ +static void handle_g_command(const unsigned char* cmd, int len) +{ + uint32_t *p = (uint32_t *) &s_scratch.regfile; + esp_gdbstub_send_start(); + for (int i = 0; i < sizeof(s_scratch.regfile) / sizeof(*p); ++i) { + esp_gdbstub_send_hex(gdbstub_hton(*p++), 32); + } + esp_gdbstub_send_end(); +} + +/** Receive register values from gdb */ +static void handle_G_command(const unsigned char* cmd, int len) +{ + uint32_t *p = (uint32_t *) &s_scratch.regfile; + for (int i = 0; i < sizeof(s_scratch.regfile) / sizeof(*p); ++i) { + *p++ = gdbstub_hton(esp_gdbstub_gethex(&cmd, 32)); + } + esp_gdbstub_send_str_packet("OK"); +} + +/** Read memory to gdb */ +static void handle_m_command(const unsigned char* cmd, int len) +{ + intptr_t addr = (intptr_t) esp_gdbstub_gethex(&cmd, -1); + cmd++; + uint32_t size = esp_gdbstub_gethex(&cmd, -1); + + if (esp_gdbstub_readmem(addr) < 0 || esp_gdbstub_readmem(addr + size - 1) < 0) { + esp_gdbstub_send_str_packet("E01"); + return; + } + + esp_gdbstub_send_start(); + for (int i = 0; i < size; ++i) { + int b = esp_gdbstub_readmem(addr++); + esp_gdbstub_send_hex(b, 8); + } + esp_gdbstub_send_end(); +} + +/** Handle a command received from gdb */ +int esp_gdbstub_handle_command(unsigned char *cmd, int len) +{ + unsigned char *data = cmd + 1; + if (cmd[0] == 'g') + { + handle_g_command(data, len - 1); + } else if (cmd[0] == 'G') { + /* receive content for all registers from gdb */ + handle_G_command(data, len - 1); + } else if (cmd[0] == 'm') { + /* read memory to gdb */ + handle_m_command(data, len - 1); + } else if (cmd[0] == '?') { + /* Reply with stop reason */ + send_reason(); +#if CONFIG_ESP_GDBSTUB_SUPPORT_TASKS + } else if (s_scratch.state != GDBSTUB_TASK_SUPPORT_DISABLED) { + return handle_task_commands(cmd, len); +#endif // CONFIG_ESP_GDBSTUB_SUPPORT_TASKS + } else { + /* Unrecognized command */ + return GDBSTUB_ST_ERR; + } + return GDBSTUB_ST_OK; +} + +/* Everything below is related to the support for listing FreeRTOS tasks as threads in GDB */ + +#ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS + +static void init_task_info() +{ + unsigned tcb_size; + s_scratch.task_count = uxTaskGetSnapshotAll(s_scratch.tasks, GDBSTUB_TASKS_NUM, &tcb_size); +} + +static bool get_task_handle(size_t index, TaskHandle_t *handle) +{ + if (index >= s_scratch.task_count) { + return false; + } + *handle = (TaskHandle_t) s_scratch.tasks[index].pxTCB; + return true; +} + +/** Get the index of the task running on the current CPU, and save the result */ +static void find_paniced_task_index() +{ + TaskHandle_t cur_handle = xTaskGetCurrentTaskHandleForCPU(xPortGetCoreID()); + TaskHandle_t handle; + for (int i = 0; i < s_scratch.task_count; i++) { + if (get_task_handle(i, &handle) && cur_handle == handle) { + s_scratch.paniced_task_index = i; + return; + } + } + s_scratch.paniced_task_index = GDBSTUB_CUR_TASK_INDEX_UNKNOWN; +} + +/** H command sets the "current task" for the purpose of further commands */ +static void handle_H_command(const unsigned char* cmd, int len) +{ + if (cmd[1] == 'g' || cmd[1] == 'c') { + const char *ret = "OK"; + cmd += 2; + int requested_task_index = esp_gdbstub_gethex(&cmd, -1); + if (requested_task_index == s_scratch.paniced_task_index || + (requested_task_index == 0 && s_scratch.current_task_index == GDBSTUB_CUR_TASK_INDEX_UNKNOWN)) { + /* Get the registers of the paniced task */ + esp_gdbstub_frame_to_regfile(&s_scratch.paniced_frame, &s_scratch.regfile); + } else if (requested_task_index > s_scratch.task_count) { + ret = "E00"; + } else { + TaskHandle_t handle; + get_task_handle(requested_task_index, &handle); + /* FIXME: for the task currently running on the other CPU, extracting the registers from TCB + * isn't valid. Need to use some IPC mechanism to obtain the registers of the other CPU + */ + esp_gdbstub_tcb_to_regfile(handle, &s_scratch.regfile); + } + esp_gdbstub_send_str_packet(ret); + } else { + esp_gdbstub_send_str_packet(NULL); + } +} + +/** qC returns the current thread ID */ +static void handle_qC_command(const unsigned char* cmd, int len) +{ + esp_gdbstub_send_start(); + esp_gdbstub_send_str("QC"); + esp_gdbstub_send_hex(s_scratch.current_task_index, 32); + esp_gdbstub_send_end(); +} + +/** T command checks if the task is alive. + * Since GDB isn't going to ask about the tasks which haven't been listed by q*ThreadInfo, + * and the state of tasks can not change (no stepping allowed), simply return "OK" here. + */ +static void handle_T_command(const unsigned char* cmd, int len) +{ + esp_gdbstub_send_str_packet("OK"); +} + +/** qfThreadInfo requests the start of the thread list, qsThreadInfo (below) is repeated to + * get the subsequent threads. + */ +static void handle_qfThreadInfo_command(const unsigned char* cmd, int len) +{ + /* The first task in qfThreadInfo reply is going to be the one which GDB will request to stop. + * Therefore it has to be the paniced task. + * Reply with the paniced task index, and later skip over this index while handling qsThreadInfo + */ + esp_gdbstub_send_start(); + esp_gdbstub_send_str("m"); + esp_gdbstub_send_hex(s_scratch.paniced_task_index, 32); + esp_gdbstub_send_end(); + + s_scratch.thread_info_index = 0; +} + +static void handle_qsThreadInfo_command(const unsigned char* cmd, int len) +{ + int next_task_index = ++s_scratch.thread_info_index; + + if (next_task_index == s_scratch.task_count) { + /* No more tasks */ + esp_gdbstub_send_str_packet("l"); + return; + } + + if (next_task_index == s_scratch.paniced_task_index) { + /* Have already sent this one in the reply to qfThreadInfo, skip over it */ + handle_qsThreadInfo_command(cmd, len); + return; + } + + esp_gdbstub_send_start(); + esp_gdbstub_send_str("m"); + esp_gdbstub_send_hex(next_task_index, 32); + esp_gdbstub_send_end(); +} + +/** qThreadExtraInfo requests the thread name */ +static void handle_qThreadExtraInfo_command(const unsigned char* cmd, int len) +{ + cmd += sizeof("qThreadExtraInfo,") - 1; + int task_index = esp_gdbstub_gethex(&cmd, -1); + TaskHandle_t handle; + if (!get_task_handle(task_index, &handle)) { + esp_gdbstub_send_str_packet("E01"); + return; + } + esp_gdbstub_send_start(); + const char* task_name = pcTaskGetTaskName(handle); + while (*task_name) { + esp_gdbstub_send_hex(*task_name, 8); + task_name++; + } + /** TODO: add "Running" or "Suspended" and "CPU0" or "CPU1" */ + esp_gdbstub_send_end(); +} + +bool command_name_matches(const char* pattern, const unsigned char* ucmd, int len) +{ + const char* cmd = (const char*) ucmd; + const char* end = cmd + len; + for (; *pattern && cmd < end; ++cmd, ++pattern) { + if (*pattern == '?') { + continue; + } + if (*pattern != *cmd) { + return false; + } + } + return *pattern == 0 && (cmd == end || *cmd == ','); +} + +/** Handle all the thread-related commands */ +static int handle_task_commands(unsigned char *cmd, int len) +{ + if (cmd[0] == 'H') { + /* Continue with task */ + handle_H_command(cmd, len); + } else if (cmd[0] == 'T') { + /* Task alive check */ + handle_T_command(cmd, len); + } else if (cmd[0] == 'q') { + if (command_name_matches("qfThreadInfo", cmd, len)) { + handle_qfThreadInfo_command(cmd, len); + } else if (command_name_matches("qsThreadInfo", cmd, len)) { + handle_qsThreadInfo_command(cmd, len); + } else if (command_name_matches("qC", cmd, len)) { + handle_qC_command(cmd, len); + } else if (command_name_matches("qThreadExtraInfo", cmd, len)) { + handle_qThreadExtraInfo_command(cmd, len); + } else { + /* Unrecognized command */ + return GDBSTUB_ST_ERR; + } + } else { + /* Unrecognized command */ + return GDBSTUB_ST_ERR; + } + return GDBSTUB_ST_OK; +} + +#endif // CONFIG_ESP_GDBSTUB_SUPPORT_TASKS + diff --git a/components/esp_gdbstub/src/packet.c b/components/esp_gdbstub/src/packet.c new file mode 100644 index 0000000000..9bf0c5d5a7 --- /dev/null +++ b/components/esp_gdbstub/src/packet.c @@ -0,0 +1,177 @@ +// Copyright 2015-2019 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 "esp_gdbstub_common.h" + +// GDB command input buffer +static unsigned char s_cmd[GDBSTUB_CMD_BUFLEN]; + +// Running checksum of the output packet +static char s_chsum; + +// Send the start of a packet; reset checksum calculation. +void esp_gdbstub_send_start() +{ + s_chsum = 0; + esp_gdbstub_putchar('$'); +} + +// Send a char as part of a packet +void esp_gdbstub_send_char(char c) +{ + if (c == '#' || c == '$' || c == '}' || c == '*') { + esp_gdbstub_putchar('}'); + esp_gdbstub_putchar(c ^ 0x20); + s_chsum += (c ^ 0x20) + '}'; + } else { + esp_gdbstub_putchar(c); + s_chsum += c; + } +} + +// Send a string as part of a packet +void esp_gdbstub_send_str(const char *c) +{ + while (*c != 0) { + esp_gdbstub_send_char(*c); + c++; + } +} + +// Send a hex val as part of a packet. +// 'bits'/4 dictates the number of hex chars sent. +void esp_gdbstub_send_hex(int val, int bits) +{ + const char* hex_chars = "0123456789abcdef"; + for (int i = bits; i > 0; i -= 4) { + esp_gdbstub_send_char(hex_chars[(val >> (i - 4)) & 0xf]); + } +} + +// Finish sending a packet. +void esp_gdbstub_send_end() +{ + esp_gdbstub_putchar('#'); + esp_gdbstub_send_hex(s_chsum, 8); +} + +// Send a packet with a string as content +void esp_gdbstub_send_str_packet(const char* str) +{ + esp_gdbstub_send_start(); + if (str != NULL) { + esp_gdbstub_send_str(str); + } + esp_gdbstub_send_end(); +} + +// Grab a hex value from the gdb packet. Ptr will get positioned on the end +// of the hex string, as far as the routine has read into it. Bits/4 indicates +// the max amount of hex chars it gobbles up. Bits can be -1 to eat up as much +// hex chars as possible. +uint32_t esp_gdbstub_gethex(const unsigned char **ptr, int bits) +{ + int i; + int no; + uint32_t v = 0; + char c; + no = bits / 4; + if (bits == -1) { + no = 64; + } + for (i = 0; i < no; i++) { + c = **ptr; + (*ptr)++; + if (c >= '0' && c <= '9') { + v <<= 4; + v |= (c - '0'); + } else if (c >= 'A' && c <= 'F') { + v <<= 4; + v |= (c - 'A') + 10; + } else if (c >= 'a' && c <= 'f') { + v <<= 4; + v |= (c - 'a') + 10; + } else if (c == '#') { + if (bits == -1) { + (*ptr)--; + return v; + } + return GDBSTUB_ST_ENDPACKET; + } else { + if (bits == -1) { + (*ptr)--; + return v; + } + return GDBSTUB_ST_ERR; + } + } + return v; +} + + +// Lower layer: grab a command packet and check the checksum +// Calls gdbHandleCommand on the packet if the checksum is OK +// Returns GDBSTUB_ST_OK on success, GDBSTUB_ST_ERR when checksum fails, a +// character if it is received instead of the GDB packet +// start char. +int esp_gdbstub_read_command(unsigned char **out_cmd, size_t *out_size) +{ + unsigned char c; + unsigned char chsum = 0; + unsigned char sentchs[2]; + int p = 0; + c = esp_gdbstub_getchar(); + if (c != '$') { + return c; + } + while (1) { + c = esp_gdbstub_getchar(); + if (c == '#') { + // end of packet, checksum follows + s_cmd[p] = 0; + break; + } + chsum += c; + if (c == '$') { + // restart packet? + chsum = 0; + p = 0; + continue; + } + if (c == '}') { + //escape the next char + c = esp_gdbstub_getchar(); + chsum += c; + c ^= 0x20; + } + s_cmd[p++] = c; + if (p >= GDBSTUB_CMD_BUFLEN) { + return GDBSTUB_ST_ERR; + } + } + // A # has been received. Get and check the received chsum. + sentchs[0] = esp_gdbstub_getchar(); + sentchs[1] = esp_gdbstub_getchar(); + const unsigned char* c_ptr = &sentchs[0]; + unsigned char rchsum = esp_gdbstub_gethex(&c_ptr, 8); + if (rchsum != chsum) { + esp_gdbstub_putchar('-'); + return GDBSTUB_ST_ERR; + } else { + esp_gdbstub_putchar('+'); + *out_cmd = s_cmd; + *out_size = p; + return GDBSTUB_ST_OK; + } +} diff --git a/components/esp_gdbstub/xtensa/esp_gdbstub_arch.h b/components/esp_gdbstub/xtensa/esp_gdbstub_arch.h new file mode 100644 index 0000000000..18b119cb3f --- /dev/null +++ b/components/esp_gdbstub/xtensa/esp_gdbstub_arch.h @@ -0,0 +1,91 @@ +// Copyright 2015-2019 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 +#include +#include "freertos/xtensa_context.h" +#include "gdbstub_target_config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef XtExcFrame esp_gdbstub_frame_t; + +/* GDB regfile structure, configuration dependent */ +typedef struct { + uint32_t pc; + uint32_t a[XCHAL_NUM_AREGS]; + +#if XCHAL_HAVE_LOOPS + uint32_t lbeg; + uint32_t lend; + uint32_t lcount; +#endif + + uint32_t sar; + +#if XCHAL_HAVE_WINDOWED + uint32_t windowbase; + uint32_t windowstart; +#endif + + uint32_t configid0; + uint32_t configid1; + uint32_t ps; + +#if XCHAL_HAVE_THREADPTR + uint32_t threadptr; +#endif + +#if XCHAL_HAVE_BOOLEANS + uint32_t br; +#endif + +#if XCHAL_HAVE_S32C1I + uint32_t scompare1; +#endif + +#if XCHAL_HAVE_MAC16 + uint32_t acclo; + uint32_t acchi; + uint32_t m0; + uint32_t m1; + uint32_t m2; + uint32_t m3; +#endif + +#if XCHAL_HAVE_DFP_ACCEL + uint32_t expstate; + uint32_t f64r_lo; + uint32_t f64r_hi; + uint32_t f64s; +#endif + +#if XCHAL_HAVE_FP + uint32_t f[16]; + uint32_t fcr; + uint32_t fsr; +#endif + +#if GDBSTUB_EXTRA_TIE_SIZE > 0 + uint32_t tie[GDBSTUB_EXTRA_TIE_SIZE]; +#endif + +} esp_gdbstub_gdb_regfile_t; + + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_gdbstub/xtensa/gdbstub_xtensa.c b/components/esp_gdbstub/xtensa/gdbstub_xtensa.c new file mode 100644 index 0000000000..853b1ba085 --- /dev/null +++ b/components/esp_gdbstub/xtensa/gdbstub_xtensa.c @@ -0,0 +1,118 @@ +// Copyright 2015-2019 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 +#include "esp_gdbstub.h" +#include "esp_gdbstub_common.h" +#include "soc/cpu.h" +#include "soc/soc_memory_layout.h" +#include "sdkconfig.h" + +#if !XCHAL_HAVE_WINDOWED +#warning "gdbstub_xtensa: revisit the implementation for Call0 ABI" +#endif + +static void init_regfile(esp_gdbstub_gdb_regfile_t *dst) +{ + memset(dst, 0, sizeof(*dst)); +} + +static void update_regfile_common(esp_gdbstub_gdb_regfile_t *dst) +{ + if (dst->a[0] & 0x8000000U) { + dst->a[0] = (dst->a[0] & 0x3fffffffU) | 0x40000000U; + } + if (!esp_stack_ptr_is_sane(dst->a[1])) { + dst->a[1] = 0xDEADBEEF; + } + dst->windowbase = 0; + dst->windowstart = 0x1; + RSR(CONFIGID0, dst->configid0); + RSR(CONFIGID1, dst->configid1); +} + +void esp_gdbstub_frame_to_regfile(const esp_gdbstub_frame_t *frame, esp_gdbstub_gdb_regfile_t *dst) +{ + init_regfile(dst); + const uint32_t *a_regs = (const uint32_t *) &frame->a0; + dst->pc = (frame->pc & 0x3fffffffU) | 0x40000000U; + + for (int i = 0; i < 16; i++) { + dst->a[i] = a_regs[i]; + } + for (int i = 16; i < 64; i++) { + dst->a[i] = 0xDEADBEEF; + } + +#if XCHAL_HAVE_LOOPS + dst->lbeg = frame->lbeg; + dst->lend = frame->lend; + dst->lcount = frame->lcount; +#endif + + dst->ps = (frame->ps & PS_UM) ? (frame->ps & ~PS_EXCM) : frame->ps; + dst->sar = frame->sar; + update_regfile_common(dst); +} + +#ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS + +static void solicited_frame_to_regfile(const XtSolFrame *frame, esp_gdbstub_gdb_regfile_t *dst) +{ + init_regfile(dst); + const uint32_t *a_regs = (const uint32_t *) &frame->a0; + dst->pc = (frame->pc & 0x3fffffffU) | 0x40000000U; + + /* only 4 registers saved in the solicited frame */ + for (int i = 0; i < 4; i++) { + dst->a[i] = a_regs[i]; + } + for (int i = 4; i < 64; i++) { + dst->a[i] = 0xDEADBEEF; + } + + dst->ps = (frame->ps & PS_UM) ? (frame->ps & ~PS_EXCM) : frame->ps; + update_regfile_common(dst); +} + +/* Represents FreeRTOS TCB structure */ +typedef struct { + uint8_t *top_of_stack; + /* Other members aren't needed */ +} dummy_tcb_t; + + +void esp_gdbstub_tcb_to_regfile(TaskHandle_t tcb, esp_gdbstub_gdb_regfile_t *dst) +{ + const dummy_tcb_t *dummy_tcb = (const dummy_tcb_t *) tcb; + + const XtExcFrame *frame = (XtExcFrame *) dummy_tcb->top_of_stack; + if (frame->exit != 0) { + esp_gdbstub_frame_to_regfile(frame, dst); + } else { + const XtSolFrame *taskFrame = (const XtSolFrame *) dummy_tcb->top_of_stack; + solicited_frame_to_regfile(taskFrame, dst); + } +} + +#endif // CONFIG_ESP_GDBSTUB_SUPPORT_TASKS + +int esp_gdbstub_get_signal(const esp_gdbstub_frame_t *frame) +{ + const char exccause_to_signal[] = {4, 31, 11, 11, 2, 6, 8, 0, 6, 7, 0, 0, 7, 7, 7, 7}; + if (frame->exccause > sizeof(exccause_to_signal)) { + return 11; + } + return (int) exccause_to_signal[frame->exccause]; +} From b0168310dba6227017b6d059c28fb39cdaa60604 Mon Sep 17 00:00:00 2001 From: boarchuz <46267286+boarchuz@users.noreply.github.com> Date: Mon, 10 Jun 2019 02:17:20 +1000 Subject: [PATCH 214/486] Typo correction Merges https://github.com/espressif/esp-idf/pull/3604 --- components/soc/esp32/include/soc/rtc_i2c_reg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/soc/esp32/include/soc/rtc_i2c_reg.h b/components/soc/esp32/include/soc/rtc_i2c_reg.h index be7b64c6b1..556a455663 100644 --- a/components/soc/esp32/include/soc/rtc_i2c_reg.h +++ b/components/soc/esp32/include/soc/rtc_i2c_reg.h @@ -35,13 +35,13 @@ #define RTC_I2C_CTRL_REG (DR_REG_RTC_I2C_BASE + 0x004) /* RTC_I2C_RX_LSB_FIRST : R/W ;bitpos:[7] ;default: 1'b0 ; */ -/*description: Send LSB first */ +/*description: Receive LSB first */ #define RTC_I2C_RX_LSB_FIRST BIT(7) #define RTC_I2C_RX_LSB_FIRST_M BIT(7) #define RTC_I2C_RX_LSB_FIRST_V (1) #define RTC_I2C_RX_LSB_FIRST_S (7) /* RTC_I2C_TX_LSB_FIRST : R/W ;bitpos:[6] ;default: 1'b0 ; */ -/*description: Receive LSB first */ +/*description: Send LSB first */ #define RTC_I2C_TX_LSB_FIRST BIT(6) #define RTC_I2C_TX_LSB_FIRST_M BIT(6) #define RTC_I2C_TX_LSB_FIRST_V (1) From d1ceaf81ae9a3ed74af933ec8a967f85fa4f6252 Mon Sep 17 00:00:00 2001 From: fakefred Date: Sat, 22 Jun 2019 17:56:31 +0800 Subject: [PATCH 215/486] example/wifi/scan: fix README grammar Merges https://github.com/espressif/esp-idf/pull/3678 --- examples/wifi/scan/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/wifi/scan/README.md b/examples/wifi/scan/README.md index 9d146266e6..dd275ccdcd 100644 --- a/examples/wifi/scan/README.md +++ b/examples/wifi/scan/README.md @@ -1,11 +1,11 @@ # Wifi SCAN Example -This example shows how to use scan of ESP32. +This example shows how to use the scan functionality of the Wi-Fi driver of ESP32. -We have two way to scan, fast scan and all channel scan: +Two scan methods are supported: fast scan and all channel scan. -* fast scan: in this mode, scan will finish after find match AP even didn't scan all the channel, you can set thresholds for signal and authmode, it will ignore the AP which below the thresholds. +* fast scan: in this mode, scan finishes right after a matching AP is detected, even if channels are not completely scanned. You can set thresholds for signal strength, as well as select desired authmodes provided by the AP's. The Wi-Fi driver will ignore AP's that fail to meet mentioned criteria. -* all channel scan : scan will end after checked all the channel, it will store four of the whole matched AP, you can set the sort method base on rssi or authmode, after scan, it will choose the best one +* all channel scan: scan will end only after all channel are scanned; the Wi-Fi driver will store 4 of the fully matching AP's. Sort methods for AP's include rssi and authmode. After the scan, the Wi-Fi driver selects the AP that fits best based on the sort. -and try to connect. Because it need malloc dynamic memory to store match AP, and most of cases is to connect to better signal AP, so it needn't record all the AP matched. The number of matches is limited to 4 in order to limit dynamic memory usage. Four matches allows APs with the same SSID name and all possible auth modes - Open, WEP, WPA and WPA2. +After the scan, the Wi-Fi driver will try to connect. Because it needs to malloc precious dynamic memory to store matching AP's, and, most of the cases, connect to the AP with the strongest reception, it does not need to record all the AP's matched. The number of matches stored is limited to 4 in order to limit dynamic memory usage. Among the 4 matches, AP's are allowed to carry the same SSID name and all possible auth modes - Open, WEP, WPA and WPA2. From 82ba58db22ddfa203679cc3499cd5d1cfb90183d Mon Sep 17 00:00:00 2001 From: Stefan Venz Date: Tue, 11 Jun 2019 15:57:41 +0200 Subject: [PATCH 216/486] Fix reference in jtag debugging section Merges https://github.com/espressif/esp-idf/pull/3617 Signed-off-by: Stefan Venz --- docs/en/api-guides/jtag-debugging/using-debugger.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/api-guides/jtag-debugging/using-debugger.rst b/docs/en/api-guides/jtag-debugging/using-debugger.rst index 70fa251969..29483c8890 100644 --- a/docs/en/api-guides/jtag-debugging/using-debugger.rst +++ b/docs/en/api-guides/jtag-debugging/using-debugger.rst @@ -101,7 +101,7 @@ If you are not quite sure how to use GDB, check :ref:`jtag-debugging-examples-ec Command Line ^^^^^^^^^^^^ -1. Begin with completing steps described under :ref:``jtag-debugging-configuring-esp32-target``. This is prerequisite to start a debugging session. +1. Begin with completing steps described under :ref:`jtag-debugging-configuring-esp32-target`. This is prerequisite to start a debugging session. .. highlight:: bash From 8d251d73694bb3896419f401922601410421da74 Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Thu, 27 Jun 2019 20:23:28 +0800 Subject: [PATCH 217/486] Implement review comments --- examples/wifi/scan/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/wifi/scan/README.md b/examples/wifi/scan/README.md index dd275ccdcd..dec4d5ebb8 100644 --- a/examples/wifi/scan/README.md +++ b/examples/wifi/scan/README.md @@ -4,8 +4,8 @@ This example shows how to use the scan functionality of the Wi-Fi driver of ESP3 Two scan methods are supported: fast scan and all channel scan. -* fast scan: in this mode, scan finishes right after a matching AP is detected, even if channels are not completely scanned. You can set thresholds for signal strength, as well as select desired authmodes provided by the AP's. The Wi-Fi driver will ignore AP's that fail to meet mentioned criteria. +* fast scan: in this mode, scan finishes right after a matching AP is detected, even if channels are not completely scanned. You can set thresholds for signal strength, as well as select desired authentication modes provided by the AP's. The Wi-Fi driver will ignore AP's that fail to meet mentioned criteria. -* all channel scan: scan will end only after all channel are scanned; the Wi-Fi driver will store 4 of the fully matching AP's. Sort methods for AP's include rssi and authmode. After the scan, the Wi-Fi driver selects the AP that fits best based on the sort. +* all channel scan: scan will end only after all channels are scanned; the Wi-Fi driver will store 4 of the fully matching AP's. Sort methods for AP's include rssi and authmode. After the scan, the Wi-Fi driver selects the AP that fits best based on the sort. -After the scan, the Wi-Fi driver will try to connect. Because it needs to malloc precious dynamic memory to store matching AP's, and, most of the cases, connect to the AP with the strongest reception, it does not need to record all the AP's matched. The number of matches stored is limited to 4 in order to limit dynamic memory usage. Among the 4 matches, AP's are allowed to carry the same SSID name and all possible auth modes - Open, WEP, WPA and WPA2. +After the scan, the Wi-Fi driver will try to connect. Because it needs to to allocate precious dynamic memory to store matching AP's, and, most of the cases, connect to the AP with the strongest reception, it does not need to record all the AP's matched. The number of matches stored is limited to 4 in order to limit dynamic memory usage. Among the 4 matches, AP's are allowed to carry the same SSID name and all possible authentication modes - Open, WEP, WPA and WPA2. From 660eb84da7193345d80767c99ba05fa944c7e8ce Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Tue, 2 Jul 2019 18:03:40 +0800 Subject: [PATCH 218/486] Correct links Closes https://github.com/espressif/esp-idf/issues/3723 --- examples/protocols/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/protocols/README.md b/examples/protocols/README.md index 0e31668a70..0ab0a7628f 100644 --- a/examples/protocols/README.md +++ b/examples/protocols/README.md @@ -8,9 +8,9 @@ See the [README.md](../README.md) file in the upper level [examples](../) direct ### About the `example_connect()` Function -Protocols examples use a simple helper function, `example_connect()`, to establish Wi-Fi or Ethernet connection. This function is implemented in [examples/common_components/protocol_examples/common/connect.c](../common_components/protocol_examples/common/connect.c), and has a very simple behavior: block until connection is established and IP address is obtained, then return. This function is used to reduce the amount of boilerplate and to keep the example code focused on the protocol or library being demonstrated. +Protocols examples use a simple helper function, `example_connect()`, to establish Wi-Fi or Ethernet connection. This function is implemented in [examples/common_components/protocol_examples/common/connect.c](../common_components/protocol_examples_common/connect.c), and has a very simple behavior: block until connection is established and IP address is obtained, then return. This function is used to reduce the amount of boilerplate and to keep the example code focused on the protocol or library being demonstrated. -The simple `example_connect()` function does not handle timeouts, does not gracefully handle various error conditions, and is only suited for use in examples. When developing real applications, this helper function needs to be replaced with full Wi-Fi / Ethernet connection handling code. Such code can be found in [examples/wifi/getting_started/](../examples/wifi/getting_started) and [examples/ethernet/ethernet/](../examples/ethernet/ethernet) examples. +The simple `example_connect()` function does not handle timeouts, does not gracefully handle various error conditions, and is only suited for use in examples. When developing real applications, this helper function needs to be replaced with full Wi-Fi / Ethernet connection handling code. Such code can be found in [examples/wifi/getting_started/](../wifi/getting_started) and [examples/ethernet/basic/](../ethernet/basic) examples. ### Configuring the Example @@ -18,7 +18,7 @@ To configure the example to use Wi-Fi or Ethernet connection, run `make menuconf When connecting using Wi-Fi, enter SSID and password of your Wi-Fi access point into the corresponding fields. If connecting to an open Wi-Fi network, keep the password field empty. -When connecting using Ethernet, set up PHY type and configuration in the provided fields. If using Ethernet for the first time, it is recommended to start with the [Ethernet example readme](../examples/ethernet/ethernet/README.md), which contains instructions for connecting and configuring the PHY. Once Ethernet example obtains IP address successfully, proceed to the protocols example and set the same configuration options. +When connecting using Ethernet, set up PHY type and configuration in the provided fields. If using Ethernet for the first time, it is recommended to start with the [Ethernet example readme](../ethernet/basic/README.md), which contains instructions for connecting and configuring the PHY. Once Ethernet example obtains IP address successfully, proceed to the protocols example and set the same configuration options. ### Disabling IPv6 From b7ca18edcdb3be373bd68106507640fc218285b8 Mon Sep 17 00:00:00 2001 From: Sergei Silnov Date: Tue, 2 Jul 2019 13:33:55 +0200 Subject: [PATCH 219/486] idf.py Run reconfigure on ccache option change.make --no-ccache default --- tools/idf.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/tools/idf.py b/tools/idf.py index 1e234215f3..669a18898e 100755 --- a/tools/idf.py +++ b/tools/idf.py @@ -222,6 +222,9 @@ def _ensure_build_directory(args, always_run_cmake=False): os.makedirs(build_dir) cache_path = os.path.join(build_dir, "CMakeCache.txt") + args.define_cache_entry = list(args.define_cache_entry) + args.define_cache_entry.append("CCACHE_ENABLE=%d" % args.ccache) + if always_run_cmake or _new_cmakecache_entries(cache_path, args.define_cache_entry): if args.generator is None: args.generator = detect_cmake_generator() @@ -235,8 +238,7 @@ def _ensure_build_directory(args, always_run_cmake=False): ] if not args.no_warnings: cmake_args += ["--warn-uninitialized"] - if args.ccache: - cmake_args += ["-DCCACHE_ENABLE=1"] + if args.define_cache_entry: cmake_args += ["-D" + d for d in args.define_cache_entry] cmake_args += [project_dir] @@ -960,19 +962,11 @@ def init_cli(): "default": False, }, { - "names": ["--ccache"], - "help": "Use ccache in build", + "names": ["--ccache/--no-ccache"], + "help": "Use ccache in build. Disabled by default.", "is_flag": True, "default": False, }, - { - # This is unused/ignored argument, as ccache use was originally opt-out. - # Use of ccache has been made opt-in using --cache arg. - "names": ["--no-ccache"], - "default": True, - "is_flag": True, - "hidden": True, - }, { "names": ["-G", "--generator"], "help": "CMake generator.", From 82b3779b2bd45f15f96144826650b30f8833780d Mon Sep 17 00:00:00 2001 From: Wojciech Szczurek Date: Thu, 20 Jun 2019 15:34:17 -0500 Subject: [PATCH 220/486] Fix broken link to components/wifi_provisioning/proto Merges https://github.com/espressif/esp-idf/pull/3668 --- docs/en/api-reference/provisioning/wifi_provisioning.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/api-reference/provisioning/wifi_provisioning.rst b/docs/en/api-reference/provisioning/wifi_provisioning.rst index 5cec30165a..24b3009646 100644 --- a/docs/en/api-reference/provisioning/wifi_provisioning.rst +++ b/docs/en/api-reference/provisioning/wifi_provisioning.rst @@ -250,7 +250,7 @@ User side applications need to implement the signature handshaking required for See Unified Provisioning for more details about the secure handshake and encryption used. Applications must use the `.proto` files found under `components/protocomm/proto `_, which define the Protobuf message structures supported by `prov-session` endpoint. -Once a session is established, Wi-Fi credentials are configured using the following set of `wifi_config` commands, serialized as Protobuf messages (the corresponding `.proto` files can be found under `components/wifi_provisioning/proto `_) : +Once a session is established, Wi-Fi credentials are configured using the following set of commands, serialized as Protobuf messages (the corresponding `.proto` files can be found under `components/wifi_provisioning/proto `_) : * `get_status` - For querying the Wi-Fi connection status. The device will respond with a status which will be one of connecting / connected / disconnected. If status is disconnected, a disconnection reason will also be included in the status response. * `set_config` - For setting the Wi-Fi connection credentials From 5aa019fce60f11fb80186000a735711495f07161 Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Tue, 2 Jul 2019 20:58:39 +0800 Subject: [PATCH 221/486] Replace hardcoded links with link roles --- docs/en/api-reference/provisioning/wifi_provisioning.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/api-reference/provisioning/wifi_provisioning.rst b/docs/en/api-reference/provisioning/wifi_provisioning.rst index 24b3009646..fb6c060eca 100644 --- a/docs/en/api-reference/provisioning/wifi_provisioning.rst +++ b/docs/en/api-reference/provisioning/wifi_provisioning.rst @@ -248,9 +248,9 @@ Immediately after connecting, the client application may fetch the version / cap User side applications need to implement the signature handshaking required for establishing and authenticating secure protocomm sessions as per the security scheme configured for use (this is not needed when manager is configured to use protocomm security 0). -See Unified Provisioning for more details about the secure handshake and encryption used. Applications must use the `.proto` files found under `components/protocomm/proto `_, which define the Protobuf message structures supported by `prov-session` endpoint. +See Unified Provisioning for more details about the secure handshake and encryption used. Applications must use the `.proto` files found under :component:`protocomm/proto`, which define the Protobuf message structures supported by `prov-session` endpoint. -Once a session is established, Wi-Fi credentials are configured using the following set of commands, serialized as Protobuf messages (the corresponding `.proto` files can be found under `components/wifi_provisioning/proto `_) : +Once a session is established, Wi-Fi credentials are configured using the following set of `wifi_config` commands, serialized as Protobuf messages (the corresponding `.proto` files can be found under :component:`wifi_provisioning/proto`) : * `get_status` - For querying the Wi-Fi connection status. The device will respond with a status which will be one of connecting / connected / disconnected. If status is disconnected, a disconnection reason will also be included in the status response. * `set_config` - For setting the Wi-Fi connection credentials From 56a624e305ddd1df0b59dfd7e04249d0651e1000 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 2 Jul 2019 13:19:10 +0200 Subject: [PATCH 222/486] ci: add unit test job --- .gitlab-ci.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 264023579e..8fb6b35d12 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1568,6 +1568,18 @@ UT_001_44: - ESP32_IDF - UT_T1_1 +UT_001_45: + <<: *unit_test_template + tags: + - ESP32_IDF + - UT_T1_1 + +UT_001_46: + <<: *unit_test_template + tags: + - ESP32_IDF + - UT_T1_1 + UT_002_01: <<: *unit_test_template tags: From 43eb58da996b8b39a138cfc55b64c5854d8edeb7 Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Tue, 2 Jul 2019 17:14:58 +0200 Subject: [PATCH 223/486] VFS: Fix Kconfig prefix --- components/newlib/platform_include/sys/termios.h | 4 ++-- components/newlib/select.c | 4 ++-- components/newlib/termios.c | 4 ++-- components/vfs/Kconfig | 4 ++-- components/vfs/include/esp_vfs.h | 4 ++-- components/vfs/sdkconfig.rename | 5 +++++ components/vfs/test/test_vfs_uart.c | 4 ++-- components/vfs/vfs.c | 8 ++++---- components/vfs/vfs_uart.c | 8 ++++---- 9 files changed, 25 insertions(+), 20 deletions(-) create mode 100644 components/vfs/sdkconfig.rename diff --git a/components/newlib/platform_include/sys/termios.h b/components/newlib/platform_include/sys/termios.h index fd0eb5ca88..c27e107be3 100644 --- a/components/newlib/platform_include/sys/termios.h +++ b/components/newlib/platform_include/sys/termios.h @@ -27,7 +27,7 @@ #include #include "sdkconfig.h" -#ifdef CONFIG_SUPPORT_TERMIOS +#ifdef CONFIG_VFS_SUPPORT_TERMIOS // subscripts for the array c_cc: #define VEOF 0 /** EOF character */ @@ -291,6 +291,6 @@ int tcsetattr(int fd, int optional_actions, const struct termios *p); } // extern "C" #endif -#endif // CONFIG_SUPPORT_TERMIOS +#endif // CONFIG_VFS_SUPPORT_TERMIOS #endif //__ESP_SYS_TERMIOS_H__ diff --git a/components/newlib/select.c b/components/newlib/select.c index 38b2523913..a8e68e72b2 100644 --- a/components/newlib/select.c +++ b/components/newlib/select.c @@ -19,9 +19,9 @@ #ifdef CONFIG_LWIP_USE_ONLY_LWIP_SELECT #include "lwip/sockets.h" -#ifdef CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT +#ifdef CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT #define LOG_LOCAL_LEVEL ESP_LOG_NONE -#endif //CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT +#endif //CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT #include "esp_log.h" static const char *TAG = "newlib_select"; diff --git a/components/newlib/termios.c b/components/newlib/termios.c index bccd5bf839..cb0c94b9bb 100644 --- a/components/newlib/termios.c +++ b/components/newlib/termios.c @@ -14,7 +14,7 @@ #include "sdkconfig.h" -#ifdef CONFIG_SUPPORT_TERMIOS +#ifdef CONFIG_VFS_SUPPORT_TERMIOS #include #include @@ -51,4 +51,4 @@ int cfsetospeed(struct termios *p, speed_t sp) } } -#endif // CONFIG_SUPPORT_TERMIOS +#endif // CONFIG_VFS_SUPPORT_TERMIOS diff --git a/components/vfs/Kconfig b/components/vfs/Kconfig index b34679b20e..c18397bdcb 100644 --- a/components/vfs/Kconfig +++ b/components/vfs/Kconfig @@ -1,6 +1,6 @@ menu "Virtual file system" - config SUPPRESS_SELECT_DEBUG_OUTPUT + config VFS_SUPPRESS_SELECT_DEBUG_OUTPUT bool "Suppress select() related debug outputs" default y help @@ -9,7 +9,7 @@ menu "Virtual file system" It is possible to suppress these debug outputs by enabling this option. - config SUPPORT_TERMIOS + config VFS_SUPPORT_TERMIOS bool "Add support for termios.h" default y help diff --git a/components/vfs/include/esp_vfs.h b/components/vfs/include/esp_vfs.h index 1d8abd8b35..3e711f2540 100644 --- a/components/vfs/include/esp_vfs.h +++ b/components/vfs/include/esp_vfs.h @@ -196,7 +196,7 @@ typedef struct int (*utime_p)(void* ctx, const char *path, const struct utimbuf *times); int (*utime)(const char *path, const struct utimbuf *times); }; -#ifdef CONFIG_SUPPORT_TERMIOS +#ifdef CONFIG_VFS_SUPPORT_TERMIOS union { int (*tcsetattr_p)(void *ctx, int fd, int optional_actions, const struct termios *p); int (*tcsetattr)(int fd, int optional_actions, const struct termios *p); @@ -225,7 +225,7 @@ typedef struct int (*tcsendbreak_p)(void *ctx, int fd, int duration); int (*tcsendbreak)(int fd, int duration); }; -#endif // CONFIG_SUPPORT_TERMIOS +#endif // CONFIG_VFS_SUPPORT_TERMIOS /** start_select is called for setting up synchronous I/O multiplexing of the desired file descriptors in the given VFS */ esp_err_t (*start_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, esp_vfs_select_sem_t sem); diff --git a/components/vfs/sdkconfig.rename b/components/vfs/sdkconfig.rename new file mode 100644 index 0000000000..92fb091ffc --- /dev/null +++ b/components/vfs/sdkconfig.rename @@ -0,0 +1,5 @@ +# sdkconfig replacement configurations for deprecated options formatted as +# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION + +CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT +CONFIG_SUPPORT_TERMIOS CONFIG_VFS_SUPPORT_TERMIOS diff --git a/components/vfs/test/test_vfs_uart.c b/components/vfs/test/test_vfs_uart.c index d46c7cb757..5c3d3f1d60 100644 --- a/components/vfs/test/test_vfs_uart.c +++ b/components/vfs/test/test_vfs_uart.c @@ -202,7 +202,7 @@ TEST_CASE("can write to UART while another task is reading", "[vfs]") vSemaphoreDelete(write_arg.done); } -#ifdef CONFIG_SUPPORT_TERMIOS +#ifdef CONFIG_VFS_SUPPORT_TERMIOS TEST_CASE("Can use termios for UART", "[vfs]") { uart_config_t uart_config = { @@ -328,4 +328,4 @@ TEST_CASE("Can use termios for UART", "[vfs]") close(uart_fd); uart_driver_delete(UART_NUM_1); } -#endif // CONFIG_SUPPORT_TERMIOS +#endif // CONFIG_VFS_SUPPORT_TERMIOS diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index 19f081c5a3..ecbaf6acf1 100644 --- a/components/vfs/vfs.c +++ b/components/vfs/vfs.c @@ -27,9 +27,9 @@ #include "esp_vfs.h" #include "sdkconfig.h" -#ifdef CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT +#ifdef CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT #define LOG_LOCAL_LEVEL ESP_LOG_NONE -#endif //CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT +#endif //CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT #include "esp_log.h" static const char *TAG = "vfs"; @@ -1032,7 +1032,7 @@ void esp_vfs_select_triggered_isr(esp_vfs_select_sem_t sem, BaseType_t *woken) } } -#ifdef CONFIG_SUPPORT_TERMIOS +#ifdef CONFIG_VFS_SUPPORT_TERMIOS int tcgetattr(int fd, struct termios *p) { const vfs_entry_t* vfs = get_vfs_for_fd(fd); @@ -1130,7 +1130,7 @@ int tcsendbreak(int fd, int duration) CHECK_AND_CALL(ret, r, vfs, tcsendbreak, local_fd, duration); return ret; } -#endif // CONFIG_SUPPORT_TERMIOS +#endif // CONFIG_VFS_SUPPORT_TERMIOS int esp_vfs_utime(const char *path, const struct utimbuf *times) { diff --git a/components/vfs/vfs_uart.c b/components/vfs/vfs_uart.c index 2bb865b297..5cb179a4a6 100644 --- a/components/vfs/vfs_uart.c +++ b/components/vfs/vfs_uart.c @@ -463,7 +463,7 @@ static void uart_end_select() _lock_release(&s_one_select_lock); } -#ifdef CONFIG_SUPPORT_TERMIOS +#ifdef CONFIG_VFS_SUPPORT_TERMIOS static int uart_tcsetattr(int fd, int optional_actions, const struct termios *p) { if (fd < 0 || fd >= UART_NUM) { @@ -913,7 +913,7 @@ static int uart_tcflush(int fd, int select) return 0; } -#endif // CONFIG_SUPPORT_TERMIOS +#endif // CONFIG_VFS_SUPPORT_TERMIOS void esp_vfs_dev_uart_register() { @@ -929,12 +929,12 @@ void esp_vfs_dev_uart_register() .access = &uart_access, .start_select = &uart_start_select, .end_select = &uart_end_select, -#ifdef CONFIG_SUPPORT_TERMIOS +#ifdef CONFIG_VFS_SUPPORT_TERMIOS .tcsetattr = &uart_tcsetattr, .tcgetattr = &uart_tcgetattr, .tcdrain = &uart_tcdrain, .tcflush = &uart_tcflush, -#endif // CONFIG_SUPPORT_TERMIOS +#endif // CONFIG_VFS_SUPPORT_TERMIOS }; ESP_ERROR_CHECK(esp_vfs_register("/dev/uart", &vfs, NULL)); } From 60a3f3e09d2e960e8720f3b220e4be59c1d7ba62 Mon Sep 17 00:00:00 2001 From: baohongde Date: Mon, 1 Jul 2019 15:52:27 +0800 Subject: [PATCH 224/486] components/bt: Fix Wrong bt lib from commit "Bluetooth component refactoring" --- components/bt/controller/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib b/components/bt/controller/lib index 45df297ff2..471f03c2ca 160000 --- a/components/bt/controller/lib +++ b/components/bt/controller/lib @@ -1 +1 @@ -Subproject commit 45df297ff295c106171d8c3621216e9f48f7d8b4 +Subproject commit 471f03c2ca55225a600d3783dd277a910bfe80ed From 2639d5b6c37ea0f4103f47b9cbf4916329c09459 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 1 Jul 2019 14:43:58 +1000 Subject: [PATCH 225/486] cmake: Fix some bugs building mconf-idf from scratch - Makefile didn't quite work with out-of-tree build unless there was already an in-tree build done. - CMake needs to delete some of the in-tree build artifacts or they're used instead of the correct files. --- tools/cmake/kconfig.cmake | 15 +++++++++++---- tools/kconfig/Makefile | 2 ++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/tools/cmake/kconfig.cmake b/tools/cmake/kconfig.cmake index f865c804eb..561c95ccd2 100644 --- a/tools/cmake/kconfig.cmake +++ b/tools/cmake/kconfig.cmake @@ -39,23 +39,30 @@ function(__kconfig_init) # Use the existing Makefile to build mconf (out of tree) when needed # set(MCONF ${CMAKE_BINARY_DIR}/kconfig_bin/mconf-idf) + set(src_path ${idf_path}/tools/kconfig) + # note: we preemptively remove any build files from the src dir + # as we're building out of tree, but don't want build system to + # #include any from there that were previously build with/for make externalproject_add(mconf-idf - SOURCE_DIR ${idf_path}/tools/kconfig + SOURCE_DIR ${src_path} CONFIGURE_COMMAND "" BINARY_DIR "kconfig_bin" - BUILD_COMMAND make -f ${idf_path}/tools/kconfig/Makefile mconf-idf + BUILD_COMMAND rm -f ${src_path}/zconf.lex.c ${src_path}/zconf.hash.c + COMMAND make -f ${src_path}/Makefile mconf-idf BUILD_BYPRODUCTS ${MCONF} INSTALL_COMMAND "" EXCLUDE_FROM_ALL 1 ) - file(GLOB mconf_srcfiles ${idf_path}/tools/kconfig/*.c) + file(GLOB mconf_srcfiles ${src_path}/*.c) + list(REMOVE_ITEM mconf_srcfiles "${src_path}/zconf.lex.c" "${src_path}/zconf.hash.c") externalproject_add_stepdependencies(mconf-idf build ${mconf_srcfiles} - ${idf_path}/tools/kconfig/Makefile + ${src_path}/Makefile ${CMAKE_CURRENT_LIST_FILE}) unset(mconf_srcfiles) + unset(src_path) set(menuconfig_depends DEPENDS mconf-idf) endif() diff --git a/tools/kconfig/Makefile b/tools/kconfig/Makefile index c9488d8cdf..b91cbc2828 100644 --- a/tools/kconfig/Makefile +++ b/tools/kconfig/Makefile @@ -167,6 +167,8 @@ check-lxdialog := $(SRCDIR)/lxdialog/check-lxdialog.sh CFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \ -DLOCALE -MMD +CFLAGS += -I "." -I "${SRCDIR}" + %.o: $(SRCDIR)/%.c $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@ From 46a268dc7860ffab676cb7c1cedf1d66c843bb8b Mon Sep 17 00:00:00 2001 From: Hrishikesh Dhayagude Date: Wed, 3 Jul 2019 16:49:30 +0800 Subject: [PATCH 226/486] Correct UUID value for ESP_GATT_UUID_ENVIRONMENTAL_SENSING_SVC --- components/bt/host/bluedroid/api/include/api/esp_gatt_defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/bluedroid/api/include/api/esp_gatt_defs.h b/components/bt/host/bluedroid/api/include/api/esp_gatt_defs.h index 1fe7d731ca..1ffffbb510 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_gatt_defs.h +++ b/components/bt/host/bluedroid/api/include/api/esp_gatt_defs.h @@ -54,7 +54,7 @@ extern "C" { #define ESP_GATT_UUID_CYCLING_SPEED_CADENCE_SVC 0x1816 /* Cycling Speed and Cadence Service*/ #define ESP_GATT_UUID_CYCLING_POWER_SVC 0x1818 /* Cycling Power Service*/ #define ESP_GATT_UUID_LOCATION_AND_NAVIGATION_SVC 0x1819 /* Location and Navigation Service*/ -#define ESP_GATT_UUID_ENVIRONMENTAL_SENSING_SVC OX181A /* Environmental Sensing Service*/ +#define ESP_GATT_UUID_ENVIRONMENTAL_SENSING_SVC 0x181A /* Environmental Sensing Service*/ #define ESP_GATT_UUID_BODY_COMPOSITION 0x181B /* Body Composition Service*/ #define ESP_GATT_UUID_USER_DATA_SVC 0x181C /* User Data Service*/ #define ESP_GATT_UUID_WEIGHT_SCALE_SVC 0x181D /* Weight Scale Service*/ From 81dd9d4e2700f65d0077ef7fec2381f0eea20085 Mon Sep 17 00:00:00 2001 From: He Yin Ling Date: Sun, 28 Apr 2019 15:29:05 +0800 Subject: [PATCH 227/486] CI: use parallel attribute in CI config file --- .gitlab-ci.yml | 1134 +------ ...ible_test.yml => nvs_compatible_test_.yml} | 0 .../unit_test/InitialConditionAll.yml | 2955 ----------------- .../TestCaseScript/IDFUnitTest/__init__.py | 1 - components/idf_test/unit_test/TestEnvAll.yml | 292 -- tools/ci/build_examples.sh | 27 +- tools/ci/build_examples_cmake.sh | 24 +- tools/tiny-test-fw/Utility/CIAssignTest.py | 15 +- tools/unit-test-app/tools/UnitTestParser.py | 11 +- 9 files changed, 139 insertions(+), 4320 deletions(-) rename components/idf_test/integration_test/CIConfigs/{nvs_compatible_test.yml => nvs_compatible_test_.yml} (100%) delete mode 100644 components/idf_test/unit_test/InitialConditionAll.yml delete mode 100755 components/idf_test/unit_test/TestCaseScript/IDFUnitTest/__init__.py delete mode 100644 components/idf_test/unit_test/TestEnvAll.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8fb6b35d12..99a21cbb8d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -158,8 +158,9 @@ build_template_app: BATCH_BUILD: "1" V: "0" -.build_ssc_template: &build_ssc_template +build_ssc: <<: *build_template + parallel: 3 artifacts: paths: - SSC/ssc_bin @@ -176,21 +177,10 @@ build_template_app: - git clone $SSC_REPOSITORY - cd SSC - python $CHECKOUT_REF_SCRIPT SSC - - MAKEFLAGS= ./ci_build_ssc.sh "${CI_JOB_NAME}" "${IDF_PATH}/.gitlab-ci.yml" - -# don't forget to add to dependency to test_template when adding new build_ssc jobs -build_ssc_00: - <<: *build_ssc_template - -build_ssc_01: - <<: *build_ssc_template - -build_ssc_02: - <<: *build_ssc_template + - MAKEFLAGS= ./ci_build_ssc.sh # If you want to add new build ssc jobs, please add it into dependencies of `assign_test` and `.test_template` - .build_esp_idf_unit_test_template: &build_esp_idf_unit_test_template <<: *build_template artifacts: @@ -235,8 +225,9 @@ build_esp_idf_tests_cmake: - rm -rf builds output sdkconfig - rm $CI_PROJECT_DIR/components/idf_test/unit_test/TestCaseAll.yml -.build_examples_make_template: &build_examples_make_template +build_examples_make: <<: *build_template + parallel: 8 # This is a workaround for a rarely encountered issue with building examples in CI. # Probably related to building of Kconfig in 'make clean' stage retry: 1 @@ -268,11 +259,12 @@ build_esp_idf_tests_cmake: - cd build_examples # build some of examples - mkdir -p ${LOG_PATH} - - ${IDF_PATH}/tools/ci/build_examples.sh "${CI_JOB_NAME}" + - ${IDF_PATH}/tools/ci/build_examples.sh # same as above, but for CMake -.build_examples_cmake_template: &build_examples_cmake_template +build_examples_cmake: <<: *build_template + parallel: 5 artifacts: when: always paths: @@ -301,55 +293,7 @@ build_esp_idf_tests_cmake: - cd build_examples_cmake # build some of examples - mkdir -p ${LOG_PATH} - - ${IDF_PATH}/tools/ci/build_examples_cmake.sh "${CI_JOB_NAME}" - -build_examples_make_00: - <<: *build_examples_make_template - -build_examples_make_01: - <<: *build_examples_make_template - -build_examples_make_02: - <<: *build_examples_make_template - -build_examples_make_03: - <<: *build_examples_make_template - -build_examples_make_04: - <<: *build_examples_make_template - -build_examples_make_05: - <<: *build_examples_make_template - -build_examples_make_06: - <<: *build_examples_make_template - -build_examples_make_07: - <<: *build_examples_make_template - -build_examples_cmake_00: - <<: *build_examples_cmake_template - -build_examples_cmake_01: - <<: *build_examples_cmake_template - -build_examples_cmake_02: - <<: *build_examples_cmake_template - -build_examples_cmake_03: - <<: *build_examples_cmake_template - -build_examples_cmake_04: - <<: *build_examples_cmake_template - -build_examples_cmake_05: - <<: *build_examples_cmake_template - -build_examples_cmake_06: - <<: *build_examples_cmake_template - -build_examples_cmake_07: - <<: *build_examples_cmake_template + - ${IDF_PATH}/tools/ci/build_examples_cmake.sh # If you want to add new build example jobs, please add it into dependencies of `.example_test_template` @@ -1036,9 +980,7 @@ assign_test: # gitlab ci do not support match job with RegEx or wildcard now in dependencies. # we have a lot build example jobs. now we don't use dependencies, just download all artificats of build stage. dependencies: - - build_ssc_00 - - build_ssc_01 - - build_ssc_02 + - build_ssc - build_esp_idf_tests_make - build_esp_idf_tests_cmake variables: @@ -1083,22 +1025,8 @@ assign_test: - $BOT_LABEL_EXAMPLE_TEST dependencies: - assign_test - - build_examples_make_00 - - build_examples_make_01 - - build_examples_make_02 - - build_examples_make_03 - - build_examples_make_04 - - build_examples_make_05 - - build_examples_make_06 - - build_examples_make_07 - - build_examples_cmake_00 - - build_examples_cmake_01 - - build_examples_cmake_02 - - build_examples_cmake_03 - - build_examples_cmake_04 - - build_examples_cmake_05 - - build_examples_cmake_06 - - build_examples_cmake_07 + - build_examples_make + - build_examples_cmake artifacts: when: always paths: @@ -1109,7 +1037,7 @@ assign_test: variables: TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw" TEST_CASE_PATH: "$CI_PROJECT_DIR/examples" - CONFIG_FILE: "$CI_PROJECT_DIR/examples/test_configs/$CI_JOB_NAME.yml" + CONFIG_FILE: "$CI_PROJECT_DIR/examples/test_configs/$CI_JOB_NAME_$CI_NODE_INDEX.yml" LOG_PATH: "$CI_PROJECT_DIR/TEST_LOGS" ENV_FILE: "$CI_PROJECT_DIR/ci-test-runner-configs/$CI_RUNNER_DESCRIPTION/EnvConfig.yml" script: @@ -1143,7 +1071,7 @@ assign_test: variables: TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw" TEST_CASE_PATH: "$CI_PROJECT_DIR/tools/unit-test-app" - CONFIG_FILE: "$CI_PROJECT_DIR/components/idf_test/unit_test/CIConfigs/$CI_JOB_NAME.yml" + CONFIG_FILE: "$CI_PROJECT_DIR/components/idf_test/unit_test/CIConfigs/$CI_JOB_NAME_$CI_NODE_INDEX.yml" LOG_PATH: "$CI_PROJECT_DIR/TEST_LOGS" ENV_FILE: "$CI_PROJECT_DIR/ci-test-runner-configs/$CI_RUNNER_DESCRIPTION/EnvConfig.yml" @@ -1195,9 +1123,7 @@ test_weekend_network: - $BOT_LABEL_INTEGRATION_TEST dependencies: - assign_test - - build_ssc_00 - - build_ssc_01 - - build_ssc_02 + - build_ssc artifacts: when: always reports: @@ -1211,7 +1137,7 @@ test_weekend_network: LOG_PATH: "$CI_PROJECT_DIR/$CI_COMMIT_SHA" TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/components/idf_test/integration_test" MODULE_UPDATE_FILE: "$CI_PROJECT_DIR/components/idf_test/ModuleDefinition.yml" - CONFIG_FILE: "$CI_PROJECT_DIR/components/idf_test/integration_test/CIConfigs/$CI_JOB_NAME.yml" + CONFIG_FILE: "$CI_PROJECT_DIR/components/idf_test/integration_test/CIConfigs/$CI_JOB_NAME_$CI_NODE_INDEX.yml" script: # first test if config file exists, if not exist, exit 0 - test -e $CONFIG_FILE || exit 0 @@ -1224,7 +1150,7 @@ test_weekend_network: - cd auto_test_script - python $CHECKOUT_REF_SCRIPT auto_test_script # run test - - python CIRunner.py -l "$LOG_PATH/$CI_JOB_NAME" -c $CONFIG_FILE -e $LOCAL_ENV_CONFIG_PATH -t $TEST_CASE_FILE_PATH -m $MODULE_UPDATE_FILE + - python CIRunner.py -l "$LOG_PATH/$CI_JOB_NAME_$CI_NODE_INDEX" -c $CONFIG_FILE -e $LOCAL_ENV_CONFIG_PATH -t $TEST_CASE_FILE_PATH -m $MODULE_UPDATE_FILE nvs_compatible_test: <<: *test_template @@ -1251,44 +1177,39 @@ nvs_compatible_test: # run test - python CIRunner.py -l "$LOG_PATH/$CI_JOB_NAME" -c $CONFIG_FILE -e $LOCAL_ENV_CONFIG_PATH -t $TEST_CASE_FILE_PATH -m $MODULE_UPDATE_FILE -example_test_001_01: +example_test_001: <<: *example_test_template + parallel: 2 tags: - ESP32 - Example_WIFI -example_test_001_02: - <<: *example_test_template - tags: - - ESP32 - - Example_WIFI - -example_test_002_01: +example_test_002: <<: *example_test_template image: $CI_DOCKER_REGISTRY/ubuntu-test-env$BOT_DOCKER_IMAGE_TAG tags: - ESP32 - Example_ShieldBox_Basic -.example_test_003_01: +.example_test_003: <<: *example_test_template tags: - ESP32 - Example_SDIO -example_test_004_01: +example_test_004: <<: *example_test_template tags: - ESP32 - Example_CAN -example_test_005_01: +example_test_005: <<: *example_test_template tags: - ESP32 - Example_WIFI_BT -example_test_006_01: +example_test_006: <<: *example_test_template image: $CI_DOCKER_REGISTRY/ubuntu-test-env$BOT_DOCKER_IMAGE_TAG only: @@ -1298,1203 +1219,354 @@ example_test_006_01: - ESP32 - Example_ShieldBox -example_test_007_01: +example_test_007: <<: *example_test_template tags: - ESP32 - Example_I2C_CCS811_SENSOR -UT_001_01: +UT_001: <<: *unit_test_template + parallel: 50 tags: - ESP32_IDF - UT_T1_1 -UT_001_02: +UT_002: <<: *unit_test_template + parallel: 18 tags: - ESP32_IDF - UT_T1_1 + - psram -UT_001_03: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_04: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_05: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_06: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_07: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_08: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_09: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_10: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_11: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_12: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_13: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_14: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_15: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_16: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_17: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_18: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_19: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_20: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_21: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_22: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_23: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_24: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_25: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_26: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_27: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_28: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_29: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_30: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_31: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_32: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_33: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_34: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_35: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_36: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_37: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_38: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_39: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_40: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_41: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_42: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_43: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_44: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_45: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_46: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_002_01: +UT_003: <<: *unit_test_template + parallel: 3 tags: - ESP32_IDF - UT_T1_SDMODE -UT_002_02: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_SDMODE - -UT_002_03: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_SDMODE - -UT_003_01: +UT_004: <<: *unit_test_template + parallel: 3 tags: - ESP32_IDF - UT_T1_SPIMODE -UT_003_02: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_SPIMODE - -UT_003_03: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_SPIMODE - -UT_004_01: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_004_02: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_004_03: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_004_04: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_004_05: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_004_06: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_004_07: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_004_08: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_004_09: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_004_10: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_004_11: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_004_12: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_004_13: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_004_14: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_004_15: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_004_16: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_004_17: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_004_18: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_004_19: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_005_01: +UT_005: <<: *unit_test_template tags: - ESP32_IDF - UT_T1_SDMODE - psram -UT_005_02: +UT_006: <<: *unit_test_template tags: - ESP32_IDF - UT_T1_SPIMODE - psram -UT_005_03: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_SPIMODE - - psram - -UT_006_01: +UT_007: <<: *unit_test_template + parallel: 4 tags: - ESP32_IDF - UT_T1_GPIO -UT_006_02: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_GPIO - -UT_006_03: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_GPIO - -UT_006_04: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_GPIO - -UT_006_05: +UT_008: <<: *unit_test_template tags: - ESP32_IDF - UT_T1_GPIO - psram -UT_007_01: +UT_009: <<: *unit_test_template + parallel: 4 tags: - ESP32_IDF - UT_T1_PCNT -UT_007_02: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_PCNT - -UT_007_03: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_PCNT - -UT_007_04: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_PCNT - -UT_007_05: +UT_010: <<: *unit_test_template tags: - ESP32_IDF - UT_T1_PCNT - psram -UT_008_01: +UT_011: <<: *unit_test_template + parallel: 4 tags: - ESP32_IDF - UT_T1_LEDC -UT_008_02: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_LEDC - -UT_008_03: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_LEDC - -UT_008_04: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_LEDC - -UT_008_05: +UT_012: <<: *unit_test_template tags: - ESP32_IDF - UT_T1_LEDC - psram -UT_009_01: +UT_013: <<: *unit_test_template + parallel: 4 tags: - ESP32_IDF - UT_T2_RS485 -UT_009_02: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T2_RS485 - -UT_009_03: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T2_RS485 - -UT_009_04: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T2_RS485 - -UT_009_05: +UT_014: <<: *unit_test_template tags: - ESP32_IDF - UT_T2_RS485 - psram -UT_010_01: +UT_015: <<: *unit_test_template + parallel: 4 tags: - ESP32_IDF - UT_T1_RMT -UT_010_02: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_RMT - -UT_010_03: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_RMT - -UT_010_04: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_RMT - -UT_010_05: +UT_016: <<: *unit_test_template tags: - ESP32_IDF - UT_T1_RMT - psram -UT_011_01: +UT_017: <<: *unit_test_template + parallel: 3 tags: - ESP32_IDF - EMMC -UT_011_02: - <<: *unit_test_template - tags: - - ESP32_IDF - - EMMC - -UT_011_03: - <<: *unit_test_template - tags: - - ESP32_IDF - - EMMC - -UT_012_01: +UT_018: <<: *unit_test_template + parallel: 5 tags: - ESP32_IDF - UT_T1_1 - 8Mpsram -UT_012_02: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - 8Mpsram - -UT_012_03: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - 8Mpsram - -UT_012_04: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - 8Mpsram - -UT_012_05: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - 8Mpsram - -UT_013_01: +UT_019: <<: *unit_test_template + parallel: 4 tags: - ESP32_IDF - Example_SPI_Multi_device -UT_013_02: - <<: *unit_test_template - tags: - - ESP32_IDF - - Example_SPI_Multi_device - -UT_013_03: - <<: *unit_test_template - tags: - - ESP32_IDF - - Example_SPI_Multi_device - -UT_013_04: - <<: *unit_test_template - tags: - - ESP32_IDF - - Example_SPI_Multi_device - -UT_013_05: +UT_020: <<: *unit_test_template tags: - ESP32_IDF - Example_SPI_Multi_device - psram -UT_014_01: +UT_021: <<: *unit_test_template + parallel: 4 tags: - ESP32_IDF - UT_T2_I2C -UT_014_02: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T2_I2C - -UT_014_03: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T2_I2C - -UT_014_04: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T2_I2C - -UT_014_05: +UT_022: <<: *unit_test_template tags: - ESP32_IDF - UT_T2_I2C - psram -UT_015_01: +UT_023: <<: *unit_test_template + parallel: 4 tags: - ESP32_IDF - UT_T1_MCPWM -UT_015_02: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_MCPWM - -UT_015_03: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_MCPWM - -UT_015_04: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_MCPWM - -UT_015_05: +UT_024: <<: *unit_test_template tags: - ESP32_IDF - UT_T1_MCPWM - psram -UT_016_01: +UT_025: <<: *unit_test_template + parallel: 4 tags: - ESP32_IDF - UT_T1_I2S -UT_016_02: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_I2S - -UT_016_03: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_I2S - -UT_016_04: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_I2S - -UT_016_05: +UT_026: <<: *unit_test_template tags: - ESP32_IDF - UT_T1_I2S - psram -UT_017_01: +UT_027: <<: *unit_test_template + parallel: 3 tags: - ESP32_IDF - UT_T2_1 -UT_017_02: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T2_1 - -UT_017_03: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T2_1 - -UT_017_04: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T2_1 - -UT_017_05: +UT_028: <<: *unit_test_template tags: - ESP32_IDF - UT_T2_1 - psram -UT_017_06: +UT_029: <<: *unit_test_template tags: - ESP32_IDF - UT_T2_1 - 8Mpsram -UT_017_06: +UT_030: <<: *unit_test_template + parallel: 5 tags: - ESP32_IDF - UT_T1_1 -UT_017_07: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_601_01: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_601_02: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_601_03: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_601_04: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_601_05: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_601_06: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_601_07: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -IT_001_01: +IT_001: <<: *test_template + parallel: 3 tags: - ESP32_IDF - SSC_T1_4 -IT_001_02: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_4 - -IT_001_03: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_4 - -IT_002_01: +IT_002: <<: *test_template tags: - ESP32_IDF - SSC_T1_2 -IT_003_01: +IT_003: <<: *test_template + parallel: 13 tags: - ESP32_IDF - SSC_T2_5 -IT_003_02: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_5 - -IT_003_03: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_5 - -IT_003_04: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_5 - -IT_003_05: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_5 - -IT_003_06: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_5 - -IT_003_07: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_5 - -IT_003_08: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_5 - -IT_003_09: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_5 - -IT_003_10: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_5 - -IT_003_11: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_5 - -IT_003_12: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_5 - -IT_003_13: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_5 - -IT_004_01: +IT_004: <<: *test_template tags: - ESP32_IDF - SSC_T1_APC -IT_005_01: +IT_005: <<: *test_template + parallel: 2 tags: - ESP32_IDF - SSC_T1_5 -IT_005_02: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_5 - -IT_006_01: +IT_006: <<: *test_template + parallel: 8 tags: - ESP32_IDF - SSC_T1_6 -IT_006_02: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_6 - -IT_006_03: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_6 - -IT_006_04: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_6 - -IT_006_05: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_6 - -IT_006_06: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_6 - -IT_006_07: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_6 - -IT_006_08: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_6 - -IT_007_01: +IT_007: <<: *test_template + parallel: 3 tags: - ESP32_IDF - SSC_T1_7 -IT_007_02: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_7 - -IT_007_03: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_7 - -IT_008_01: +IT_008: <<: *test_template tags: - ESP32_IDF - SSC_T1_8 -IT_009_01: +IT_009: <<: *test_template tags: - ESP32_IDF - SSC_T1_3 -IT_010_01: +IT_010: <<: *test_template + parallel: 4 tags: - ESP32_IDF - SSC_T5_1 -IT_010_02: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T5_1 - -IT_010_03: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T5_1 - -IT_010_04: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T5_1 - -IT_011_01: +IT_011: <<: *test_template tags: - ESP32_IDF - SSC_T1_MESH1 -IT_011_02: +IT_012: <<: *test_template + parallel: 2 tags: - ESP32_IDF - SSC_T2_MESH1 -IT_011_03: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_MESH1 - -IT_011_04: +IT_013: <<: *test_template tags: - ESP32_IDF - SSC_T3_MESH1 -IT_011_05: +IT_014: <<: *test_template tags: - ESP32_IDF - SSC_T6_MESH1 -IT_011_06: +IT_015: <<: *test_template tags: - ESP32_IDF - SSC_T12_MESH1 -IT_011_07: +IT_016: <<: *test_template tags: - ESP32_IDF - SSC_T50_MESH1 -IT_011_08: +IT_017: <<: *test_template tags: - ESP32_IDF - SSC_T1_MESH2 -IT_012_01: +IT_018: <<: *test_template + parallel: 2 tags: - ESP32_IDF - SSC_T1_9 -IT_012_02: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_9 - -IT_013_01: +IT_019: <<: *test_template + parallel: 2 tags: - ESP32_IDF - SSC_T2_2 -IT_013_02: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_2 - -IT_014_01: +IT_020: <<: *test_template tags: - ESP32_IDF - SSC_T2_3 -IT_015_01: +IT_021: <<: *test_template tags: - ESP32_IDF diff --git a/components/idf_test/integration_test/CIConfigs/nvs_compatible_test.yml b/components/idf_test/integration_test/CIConfigs/nvs_compatible_test_.yml similarity index 100% rename from components/idf_test/integration_test/CIConfigs/nvs_compatible_test.yml rename to components/idf_test/integration_test/CIConfigs/nvs_compatible_test_.yml diff --git a/components/idf_test/unit_test/InitialConditionAll.yml b/components/idf_test/unit_test/InitialConditionAll.yml deleted file mode 100644 index 6e5d898e72..0000000000 --- a/components/idf_test/unit_test/InitialConditionAll.yml +++ /dev/null @@ -1,2955 +0,0 @@ -initial condition: -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:2'] - - - SSC SSC1 ap -Q - - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] - - - SSC SSC1 dhcp -Q -o 2 - - ['R SSC1 C +DHCP:AP,STARTED'] - - - SSC SSC1 mac -Q -o 2 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - initial condition detail: AP mode, DHCP on, will autogen a TC with initial condition - APSTA1 - restore cmd set: - - '' - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 31.0 - tag: APM1 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:2'] - - - SSC SSC1 ap -Q - - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] - - - SSC SSC1 ap -L - - ['R SSC1 RE "\+LSTA:.+,%%s"%%()'] - - - SSC SSC1 dhcp -Q -o 2 - - ['R SSC1 C +DHCP:AP,STARTED'] - - - SSC SSC1 mac -Q -o 2 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - initial condition detail: AP mode, PC join AP, DHCP on, will autogen a TC with initial - condition APSTA2 - restore cmd set: - - '' - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 38.0 - tag: APM2 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:2'] - - - SSC SSC1 ap -Q - - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] - - - SSC SSC1 dhcp -Q -o 2 - - ['R SSC1 C +DHCP:AP,STARTED'] - - - SSC SSC1 mac -Q -o 2 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - initial condition detail: AP mode, will NOT autogen a TC with initial condition - APSTA1 - restore cmd set: - - '' - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 31.0 - tag: APO1 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:2'] - - - SSC SSC1 ap -Q - - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] - - - SSC SSC1 ap -L - - ['R SSC1 RE "\+LSTA:.+,%%s"%%()'] - - - SSC SSC1 dhcp -Q -o 2 - - ['R SSC1 C +DHCP:AP,STARTED'] - - - SSC SSC1 mac -Q -o 2 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - initial condition detail: AP mode, will NOT autogen a TC with initial condition - APSTA2 - restore cmd set: - - '' - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 38.0 - tag: APO2 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 upgrade -Q -t 1 - - ['R SSC1 C BIN_ID,0'] - - - SSC SSC1 upgrade -Q -t 2 -b 0 - - ['R SSC1 C BIN_INFO,0'] - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - force restore cmd set: - - '' - - - SSC SSC1 upgrade -R -r 1 -s - - [R SSC1 NC ERROR C !!!ready!!!] - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - - - SOC SOC1 ULISTEN - - [R SOC_COM L OK] - - - SOC SOC1 SETOPT REPLY BIN - - [R SOC_COM C OK] - - - SSC SSC1 upgrade -I -b 0 -f 0 - - ['P SSC1 C +UPGRADE:OK'] - - - SSC SSC1 upgrade -U -i -p -u - - ['P SSC1 C +UPGRADE:SUCCEED'] - - - SSC SSC1 upgrade -R -b 0 - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - initial condition detail: AP only mode, running BIN0 (located on flash id 0) - restore cmd set: - - '' - - - SSC SSC1 upgrade -Q -t 2 -b 0 - - ['R SSC1 C BIN_INFO,0'] - - - SSC SSC1 upgrade -R -b 0 - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - restore post cmd set: - - '' - - - SSC SSC1 upgrade -D - - ['R SSC1 C +UPGRADE:OK'] - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 31.0 - tag: APOBIN0 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:3'] - - - SSC SSC1 ap -Q - - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] - - - SSC SSC1 dhcp -Q -o 2 - - ['R SSC1 C +DHCP:AP,STARTED'] - - - SSC SSC1 mac -Q -o 2 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - initial condition detail: testing ap on sta + ap mode (autogen by APM1) - restore cmd set: - - '' - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 59.0 - tag: APSTA1 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:3'] - - - SSC SSC1 ap -Q - - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] - - - SSC SSC1 ap -L - - ['R SSC1 RE "\+LSTA:.+,%%s"%%()'] - - - SSC SSC1 dhcp -Q -o 2 - - ['R SSC1 C +DHCP:AP,STARTED'] - - - SSC SSC1 mac -Q -o 2 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - initial condition detail: testing ap on sta + ap mode, PC join AP (autogen by APM2) - restore cmd set: - - '' - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 66.0 - tag: APSTA2 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:3'] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - DELAY 5 - - [''] - - - ATC AT1 CWSAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - initial condition detail: StationSoftAP mode - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 24.0 - tag: ATAP1 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 C +CWMODE_CUR:3 L OK'] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:1'] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - DELAY 5 - - [''] - - - ATC AT1 CWSAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - initial condition detail: StationSoftAP mode, PC join Target AP, multi link, use - dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 R *] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 31.0 - tag: ATAP3 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 C +CWMODE_CUR:3 L OK'] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:0'] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - DELAY 10 - - [''] - - - ATC AT1 CWSAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - initial condition detail: StationSoftAP mode, PC join Target AP, single link, use - dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 45.0 - tag: ATAP4 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT - - [R AT1 L OK] - - - ATS AT1 AT - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+RST - - [R AT1 L OK] - initial condition detail: StationSoftAP mode, both PC join Target AP, single link, - use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 3.0 - tag: ATAP5 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT - - [R AT1 L OK] - - - ATS AT1 AT - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+RST - - [R AT1 L OK] - initial condition detail: StationSoftAP mode, both PC join Target AP, multi link, - use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 3.0 - tag: ATAP6 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:2'] - - - ATS AT1 AT+CWDHCP_DEF=0,1 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=2 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=0,1 - - [R AT1 R *] - initial condition detail: SoftAP mode, use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=2 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=0,1 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 59.0 - tag: ATAPO1 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 C +CWMODE_CUR:2 L OK'] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:1'] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CWDHCP_DEF=0,1 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=2 - - [R AT1 L OK] - - - ATC AT1 CWSAP_DEF - - [R AT1 L OK] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CWDHCP_DEF=0,1 - - [R AT1 R *] - initial condition detail: SoftAP mode, PC join Target AP, multi link, use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=2 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 R *] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CWDHCP_DEF=0,1 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 66.0 - tag: ATAPO3 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 C +CWMODE_CUR:2 L OK'] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:0'] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CWDHCP_DEF=0,1 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=2 - - [R AT1 L OK] - - - ATC AT1 CWSAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=0,1 - - [R AT1 R *] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - initial condition detail: SoftAP mode, PC join Target AP, single link, use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=2 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CWDHCP_DEF=0,1 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 73.0 - tag: ATAPO4 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT - - [R AT1 L OK] - - - ATS AT1 AT - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+RST - - [R AT1 L OK] - initial condition detail: SoftAP mode, both PC join Target AP, single link, use - dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 3.0 - tag: ATAPO5 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT - - [R AT1 L OK] - - - ATS AT1 AT - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+RST - - [R AT1 L OK] - initial condition detail: SoftAP mode, both PC join Target AP, multi link, use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 3.0 - tag: ATAPO6 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:3'] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - initial condition detail: StationSoftAP mode - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 87.0 - tag: ATAPSTA1 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:3'] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - initial condition detail: StationSoftAP mode, DHCP client on - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 87.0 - tag: ATAPSTA2 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:3'] - - - ATS AT1 AT+CWJAP_CUR? - - ['R AT1 C +CWJAP_CUR:', R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:1'] - - - ATS AT1 AT+CWDHCP_CUR? - - ['R AT1 C DHCP:3'] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - initial condition detail: StationSoftAP mode, connected to AP, multi link, use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 94.0 - tag: ATAPSTA3 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:3'] - - - ATS AT1 AT+CWJAP_CUR? - - ['R AT1 C +CWJAP_CUR:', R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:0'] - - - ATS AT1 AT+CWDHCP_CUR? - - ['R AT1 C DHCP:3'] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - initial condition detail: StationSoftAP mode, connected to AP, single link, use - dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 101.0 - tag: ATAPSTA4 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:3'] - - - ATS AT1 AT+CWJAP_CUR? - - ['R AT1 C +CWJAP_CUR:', R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:1'] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - initial condition detail: StationSoftAP mode, connected to AP, multi link, use static - ip - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 129.0 - tag: ATAPSTA5 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:3'] - - - ATS AT1 AT+CWJAP_CUR? - - ['R AT1 C +CWJAP_CUR:', R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:0'] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - initial condition detail: StationSoftAP mode, connected to AP, single link, use - static ip - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 136.0 - tag: ATAPSTA6 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT - - [R AT1 L OK] - - - ATS AT1 AT+RESTORE - - [R AT1 L OK, R AT1 C ready] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT - - [R AT1 L OK] - - - ATS AT1 AT+RESTORE - - [R AT1 L OK, R AT1 C ready] - initial condition detail: 'first time usage. Use restore function. ' - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+RESTORE - - [R AT1 L OK, R AT1 C ready] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 143.0 - tag: ATFTU - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT - - [R AT1 L OK] - - - ATS AT1 AT - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+RST - - [R AT1 L OK] - initial condition detail: none - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 3.0 - tag: ATNone - test script: InitCondBase -- check cmd set: - - '' - - - DELAY 0.1 - - [dummy] - force restore cmd set: - - '' - - - DELAY 0.1 - - [dummy] - initial condition detail: none 2 - restore cmd set: - - '' - - - DELAY 0.1 - - [dummy] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 108.0 - tag: ATNone2 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:1'] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 L OK] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 L OK] - initial condition detail: same as STA1, but will not autogen STA+AP STA test case - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 L OK] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 10.0 - tag: ATOSTA1 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:1'] - - - ATS AT1 AT+CWJAP_CUR? - - ['R AT1 C +CWJAP_CUR:', R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:0'] - - - ATS AT1 AT+CWDHCP_CUR? - - ['R AT1 C DHCP:3'] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 R *] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - initial condition detail: same as STA4, but will not autogen STA+AP STA test case - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 R *] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 17.0 - tag: ATOSTA4 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 C +CWMODE_CUR:3 C OK'] - - - ATS AT2 AT+CWMODE_CUR? - - ['R AT2 C +CWMODE_CUR:1 C OK'] - - - ATS AT1 AT+CWJAP_CUR? - - [R AT1 NC OK L ERROR] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT2 AT+CWMODE_DEF=1 - - [R AT2 L OK] - - - ATS AT1 AT+CWQAP - - [R AT1 L OK] - initial condition detail: same as OT2_1, but will not autogen STA+AP STA test case - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT2 AT+CWMODE_DEF=1 - - [R AT2 L OK] - - - ATS AT1 AT+CWQAP - - [R AT1 L OK] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 52.0 - tag: ATOT2_1 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:1'] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 L OK] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 L OK] - initial condition detail: station mode, use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 L OK] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 10.0 - tag: ATSTA1 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:1'] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 L OK] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 L OK] - initial condition detail: station mode, DHCP client on, use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 L OK] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 10.0 - tag: ATSTA2 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:1'] - - - ATS AT1 AT+CWJAP_CUR? - - ['R AT1 C +CWJAP_CUR:', R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:1'] - - - ATS AT1 AT+CWDHCP_CUR? - - ['R AT1 C DHCP:3'] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 R *] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - initial condition detail: station mode, connected to AP, multi link, use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 R *] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 38.0 - tag: ATSTA3 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:1'] - - - ATS AT1 AT+CWJAP_CUR? - - ['R AT1 C +CWJAP_CUR:', R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:0'] - - - ATS AT1 AT+CWDHCP_CUR? - - ['R AT1 C DHCP:3'] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 R *] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - initial condition detail: station mode, connected to AP, single link, use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 R *] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 17.0 - tag: ATSTA4 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:1'] - - - ATS AT1 AT+CWJAP_CUR? - - ['R AT1 C +CWJAP_CUR:', R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:1'] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - initial condition detail: station mode, connected to AP, multi link, use static - ip - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 115.0 - tag: ATSTA5 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:1'] - - - ATS AT1 AT+CWJAP_CUR? - - ['R AT1 C +CWJAP_CUR:', R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:0'] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - initial condition detail: station mode, connected to AP, single link, use static - ip - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 122.0 - tag: ATSTA6 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 C +CWMODE_CUR:3 C OK'] - - - ATS AT2 AT+CWMODE_CUR? - - ['R AT2 C +CWMODE_CUR:1 C OK'] - - - ATS AT1 AT+CWJAP_CUR? - - [R AT1 NC OK L ERROR] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT2 AT+CWMODE_DEF=1 - - [R AT2 L OK] - - - ATS AT1 AT+CWQAP - - [R AT1 L OK] - initial condition detail: Target 1 in StationSoftAP mode, Target 2 in station mode, - use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT2 AT+CWMODE_DEF=1 - - [R AT2 L OK] - - - ATS AT1 AT+CWQAP - - [R AT1 L OK] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 52.0 - tag: ATT2_1 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 C +CWMODE_CUR:2 C OK'] - - - ATS AT2 AT+CWMODE_CUR? - - ['R AT2 C +CWMODE_CUR:3 C OK'] - - - ATS AT1 AT+CWJAP_CUR? - - [R AT1 NC OK L ERROR] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=2 - - [R AT1 L OK] - - - ATS AT2 AT+CWMODE_DEF=3 - - [R AT2 L OK] - initial condition detail: Target 1 in SoftAP mode, Target 2 in StationSoftAP mode, - use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=2 - - [R AT1 L OK] - - - ATS AT2 AT+CWMODE_DEF=3 - - [R AT2 L OK] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 80.0 - tag: ATT2_2 - test script: InitCondBase -- check cmd set: - - '' - - - ASSERT - - [dummy] - force restore cmd set: - - '' - - - SSC SSC[1-] reboot - - ['P SSC[1-] C !!!ready!!!'] - - - SSC SSC[1-] mesh -E -o 0 - - ['P SSC[1-] C +MESH:DISABLED'] - - - SSC SSC[1-] op -S -o 1 - - ['P SSC[1-] C +MODE:OK'] - - - SSC SSC[1-] sta -D - - ['P SSC[1-] C +QAP:OK'] - initial condition detail: all mesh node disabled - restore cmd set: - - '' - - - SSC SSC[1-] mesh -E -o 0 - - ['P SSC[1-] C +MESH:DISABLED'] - - - SSC SSC[1-] op -S -o 1 - - ['P SSC[1-] C +MODE:OK'] - - - SSC SSC[1-] sta -D - - ['P SSC[1-] C +QAP:OK'] - restore post cmd set: - - '' - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 31.0 - tag: DISABLED - test script: InitCondBase -- check cmd set: - - '' - - - ASSERT - - [dummy] - - - SSC SSC[1-] mesh -Q -t 4 - - ['R SSC[1-] T '] - - - MESHTREE - - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] - force restore cmd set: - - '' - - - SOC SOC1 LISTEN - - [R SOC_COM L OK] - - - SSC SSC[1-] mesh -E -o 0 - - ['P SSC[1-] C +MESH:DISABLED'] - - - SSC SSC[1-] mesh -I -g -a 4 -k -i - -p -h 5 - - ['P SSC[1-] C ENCRYPTION,OK C GROUP,OK C SERVER,OK C HOP,OK'] - - - SSC SSC[1-] mesh -A -s -k - - ['P SSC[1-] C +MESHINIT:AP,OK'] - - - SSC SSC1 mesh -E -o 1 -t 2 - - ['P SSC1 C +MESH:ENABLED'] - - - SOC SOC1 MACCEPT GSOC1 - - [R SOC_COM L OK] - - - SSC SSC[2-] mesh -E -o 1 -t 2 - - ['P SSC[2-] C +MESH:ENABLED'] - - - DELAY 60 - - [''] - - - SSC SSC[1-] mesh -C - - ['P SSC[1-] C +MESH:CONNECTED'] - - - SSC SSC[1-] mesh -Q -t 4 - - ['R SSC[1-] T '] - - - MESHTREE - - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] - - - SSC SSC[1-] mesh -O -t 1 -o 1 - - ['P SSC[1-] C +MESH:OK'] - initial condition detail: all mesh node enabled as ONLINE, mesh network established - restore cmd set: - - '' - - - SSC SSC[1-] reboot - - ['P SSC[1-] C !!!ready!!!'] - - - SOC SOC1 LISTEN - - [R SOC_COM L OK] - - - SSC SSC[1-] mesh -E -o 0 - - ['P SSC[1-] C +MESH:DISABLED'] - - - SSC SSC[1-] mesh -I -g -a 4 -k -i - -p -h 5 - - ['P SSC[1-] C ENCRYPTION,OK C GROUP,OK C SERVER,OK C HOP,OK'] - - - SSC SSC[1-] mesh -A -s -k - - ['P SSC[1-] C +MESHINIT:AP,OK'] - - - SSC SSC1 mesh -E -o 1 -t 2 - - ['P SSC1 C +MESH:ENABLED'] - - - SOC SOC1 MACCEPT GSOC1 - - [R SOC_COM L OK] - - - SSC SSC[2-] mesh -E -o 1 -t 2 - - ['P SSC[2-] C +MESH:ENABLED'] - - - DELAY 60 - - [''] - - - SSC SSC[1-] mesh -C - - ['P SSC[1-] C +MESH:CONNECTED'] - - - SSC SSC[1-] mesh -Q -t 4 - - ['R SSC[1-] T '] - - - MESHTREE - - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] - - - SSC SSC[1-] mesh -O -t 1 -o 1 - - ['P SSC[1-] C +MESH:OK'] - restore post cmd set: - - '' - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 17.0 - tag: ENABLED_1 - test script: InitCondBase -- check cmd set: - - '' - - - ASSERT - - [dummy] - - - SSC SSC[1-] mesh -Q -t 4 - - ['R SSC[1-] T '] - - - MESHTREE - - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] - force restore cmd set: - - '' - - - SSC SSC[1-] reboot - - ['P SSC[1-] C !!!ready!!!'] - - - SSC SSC[1-] mesh -I -g -a 4 -k -i - -p -h 5 - - ['P SSC[1-] C ENCRYPTION,OK C GROUP,OK C SERVER,OK C HOP,OK'] - - - SSC SSC1 mesh -A -s -k - - ['P SSC1 C +MESHINIT:AP,OK'] - - - SSC SSC1 mesh -E -o 1 -t 1 - - ['P SSC1 C +MESH:ENABLED'] - - - SSC SSC[2-] mesh -E -o 1 -t 2 - - [''] - - - DELAY 60 - - ['P SSC[2-] C +MESH:ENABLED'] - - - SSC SSC[1-] mesh -C - - ['P SSC[1-] C +MESH:CONNECTED'] - - - SSC SSC[1-] mesh -Q -t 4 - - ['R SSC[1-] T '] - - - MESHTREE - - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] - initial condition detail: root as LOCAL, rest node as ONLINE, mesh network established - restore cmd set: - - '' - - - SSC SSC[1-] mesh -E -o 0 - - ['P SSC[1-] C +MESH:DISABLED'] - - - SSC SSC[1-] mesh -I -g -a 4 -k -i - -p -h 5 - - ['P SSC[1-] C ENCRYPTION,OK C GROUP,OK C SERVER,OK C HOP,OK'] - - - SSC SSC1 mesh -A -s -k - - ['P SSC1 C +MESHINIT:AP,OK'] - - - SSC SSC1 mesh -E -o 1 -t 1 - - ['P SSC1 C +MESH:ENABLED'] - - - SSC SSC[2-] mesh -E -o 1 -t 2 - - [''] - - - DELAY 60 - - ['P SSC[2-] C +MESH:ENABLED'] - - - SSC SSC[1-] mesh -C - - ['P SSC[1-] C +MESH:CONNECTED'] - - - SSC SSC[1-] mesh -Q -t 4 - - ['R SSC[1-] T '] - - - MESHTREE - - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] - restore post cmd set: - - '' - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 24.0 - tag: ENABLED_2 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:2'] - - - SSC SSC1 mac -Q -o 2 - - [R SSC1 P ] - - - SSC SSC1 espnow -D - - ['R SSC1 C +ESPNOW:'] - force restore cmd set: - - '' - - - SSC SSC[1-] reboot - - ['R SSC[1-] C !!!ready!!!'] - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 mac -S -m -o 2 - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 espnow -D - - ['R SSC1 C +ESPNOW:'] - initial condition detail: one target in AP mode and espnow is de-initialized - restore cmd set: - - '' - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 mac -S -m -o 2 - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 espnow -D - - ['R SSC1 C +ESPNOW:'] - restore post cmd set: - - '' - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 17.0 - tag: NOW1 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC[1-] op -Q - - ['R SSC[1-] C +CURMODE:2'] - - - SSC SSC[1-] mac -Q -o 3 - - ['R SSC[1-] P ]_ap_mac> P ]_mac>'] - - - SSC SSC[1-] espnow -D - - ['R SSC[1-] C +ESPNOW:'] - - - SSC SSC[1-] espnow -I - - ['R SSC[1-] C +ESPNOW:OK'] - - - SSC SSC[1-] espnow -R -t Set -r 2 - - ['R SSC[1-] C +ESPNOW:OK'] - force restore cmd set: - - '' - - - SSC SSC[1-] reboot - - ['R SSC[1-] C !!!ready!!!'] - - - SSC SSC[1-] op -S -o 3 - - ['R SSC[1-] C +MODE:OK'] - - - SSC SSC[1-] mac -S -m ]_ap_mac> -o 2 - - ['R SSC[1-] C +MAC:AP,OK'] - - - SSC SSC[1-] mac -S -m ]_mac> -o 1 - - ['R SSC[1-] C +MAC:STA,OK'] - - - SSC SSC[1-] op -S -o 2 - - ['R SSC[1-] C +MODE:OK'] - - - SSC SSC[1-] espnow -D - - ['R SSC[1-] C +ESPNOW:'] - - - SSC SSC[1-] espnow -I - - ['R SSC[1-] C +ESPNOW:OK'] - - - SSC SSC[1-] espnow -R -t Set -r 2 - - ['R SSC[1-] C +ESPNOW:OK'] - initial condition detail: multiple () targets in AP mode, espnow is initialized - with self role slave - restore cmd set: - - '' - - - SSC SSC[1-] op -S -o 3 - - ['R SSC[1-] C +MODE:OK'] - - - SSC SSC[1-] mac -S -m ]_ap_mac> -o 2 - - ['R SSC[1-] C +MAC:AP,OK'] - - - SSC SSC[1-] mac -S -m ]_mac> -o 1 - - ['R SSC[1-] C +MAC:STA,OK'] - - - SSC SSC[1-] op -S -o 2 - - ['R SSC[1-] C +MODE:OK'] - - - SSC SSC[1-] espnow -D - - ['R SSC[1-] C +ESPNOW:'] - - - SSC SSC[1-] espnow -I - - ['R SSC[1-] C +ESPNOW:OK'] - - - SSC SSC[1-] espnow -R -t Set -r 2 - - ['R SSC[1-] C +ESPNOW:OK'] - restore post cmd set: - - '' - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 24.0 - tag: NOW2 - test script: InitCondBase -- check cmd set: - - '' - - - DELAY 0.1 - - [dummy] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - initial condition detail: none - restore cmd set: - - '' - - - DELAY 0.1 - - [dummy] - restore post cmd set: - - '' - - - DELAY 0.1 - - [dummy] - script path: InitCondBase.py - start: 10.0 - tag: None - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 sp -D - - ['R SSC1 C +SP:OK'] - force restore cmd set: - - '' - - - SSC SSC1 sp -D - - ['R SSC1 C +SP:OK'] - initial condition detail: one target and simple is de-inited - restore cmd set: - - '' - - - SSC SSC1 sp -D - - ['R SSC1 C +SP:OK'] - restore post cmd set: - - '' - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 31.0 - tag: PAIR1 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC[1,2] op -Q - - ['R SSC[1,2] C +MODE:[2,1]'] - - - SSC SSC[1,2] mac -Q -o 3 - - ['R SSC[1,2] P P '] - - - SSC SSC[1,2] sp -D - - ['R SSC[1,2] C +SP:OK'] - - - SSC SSC[1,2] sp -I - - ['R SSC[1,2] C +SP:OK'] - force restore cmd set: - - '' - - - SSC SSC[1,2] reboot - - ['R SSC[1,2] C !!!ready!!!'] - - - SSC SSC[1,2] op -S -o 3 - - ['R SSC[1,2] C +MODE:OK'] - - - SSC SSC[1,2] mac -S -m -o 2 - - ['R SSC[1,2] C +MAC:AP,OK'] - - - SSC SSC[1,2] mac -S -m -o 1 - - ['R SSC[1,2] C +MAC:STA,OK'] - - - SSC SSC[1,2] op -S -o [2,1] - - ['R SSC[1,2] C +MODE:OK'] - - - SSC SSC[1,2] sp -D - - ['R SSC[1,2] C +SP:OK'] - - - SSC SSC[1,2] sp -I - - ['R SSC[1,2] C +SP:OK'] - initial condition detail: target1 in AP mode, target2 in STA mode, two targets de-init - and init simple pair - restore cmd set: - - '' - - - SSC SSC[1,2] op -S -o 3 - - ['R SSC[1,2] C +MODE:OK'] - - - SSC SSC[1,2] mac -S -m -o 2 - - ['R SSC[1,2] C +MAC:AP,OK'] - - - SSC SSC[1,2] mac -S -m -o 1 - - ['R SSC[1,2] C +MAC:STA,OK'] - - - SSC SSC[1,2] op -S -o [2,1] - - ['R SSC[1,2] C +MODE:OK'] - - - SSC SSC[1,2] sp -D - - ['R SSC[1,2] C +SP:OK'] - - - SSC SSC[1,2] sp -I - - ['R SSC[1,2] C +SP:OK'] - restore post cmd set: - - '' - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 38.0 - tag: PAIR2 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC[1,2] op -Q - - ['R SSC[1,2] C +MODE:[3,3]'] - - - SSC SSC[1,2] mac -Q -o 3 - - ['R SSC[1,2] P P '] - - - SSC SSC[1,2] sp -D - - ['R SSC[1,2] C +SP:OK'] - - - SSC SSC[1,2] sp -I - - ['R SSC[1,2] C +SP:OK'] - force restore cmd set: - - '' - - - SSC SSC[1,2] reboot - - ['R SSC[1,2] C !!!ready!!!'] - - - SSC SSC[1,2] op -S -o [3,3] - - ['R SSC[1,2] C +MODE:OK'] - - - SSC SSC[1,2] mac -S -m -o 2 - - ['R SSC[1,2] C +MAC:AP,OK'] - - - SSC SSC[1,2] mac -S -m -o 1 - - ['R SSC[1,2] C +MAC:STA,OK'] - - - SSC SSC[1,2] sp -D - - ['R SSC[1,2] C +SP:OK'] - - - SSC SSC[1,2] sp -I - - ['R SSC[1,2] C +SP:OK'] - initial condition detail: target1 and target2 in STA+AP mode, two targets de-init - and init simple pair - restore cmd set: - - '' - - - SSC SSC[1,2] op -S -o [3,3] - - ['R SSC[1,2] C +MODE:OK'] - - - SSC SSC[1,2] mac -S -m -o 2 - - ['R SSC[1,2] C +MAC:AP,OK'] - - - SSC SSC[1,2] mac -S -m -o 1 - - ['R SSC[1,2] C +MAC:STA,OK'] - - - SSC SSC[1,2] sp -D - - ['R SSC[1,2] C +SP:OK'] - - - SSC SSC[1,2] sp -I - - ['R SSC[1,2] C +SP:OK'] - restore post cmd set: - - '' - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 45.0 - tag: PAIR3 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:3'] - - - SSC SSC1 sta -D - - ['R SSC1 C +QAP:'] - - - SSC SSC1 dhcp -Q -o 1 - - ['R SSC1 C +DHCP:STA,STARTED'] - - - SSC SSC1 mac -Q -o 1 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 sta -D - - ['R SSC1 C +QAP:'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - initial condition detail: testing sta on sta + ap mode, quit AP (autogen by STAM1) - restore cmd set: - - '' - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 sta -D - - ['R SSC1 C +QAP:'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 45.0 - tag: STAAP1 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:3'] - - - SSC SSC1 sta -Q - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - - - SSC SSC1 dhcp -Q -o 1 - - ['R SSC1 C +DHCP:STA,STARTED'] - - - SSC SSC1 mac -Q -o 1 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - initial condition detail: testing sta on sta + ap mode, join AP, DHCP on (autogen - by STAM2) - restore cmd set: - - '' - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 52.0 - tag: STAAP2 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 upgrade -Q -t 1 - - ['R SSC1 C BIN_ID,0'] - - - SSC SSC1 upgrade -Q -t 2 -b 0 - - ['R SSC1 C BIN_INFO,0'] - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - force restore cmd set: - - '' - - - SSC SSC1 upgrade -R -r 1 -s - - [R SSC1 NC ERROR C !!!ready!!!] - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - - - SOC SOC1 ULISTEN - - [R SOC_COM L OK] - - - SOC SOC1 SETOPT REPLY BIN - - [R SOC_COM C OK] - - - SSC SSC1 upgrade -I -b 0 -f 0 - - ['P SSC1 C +UPGRADE:OK'] - - - SSC SSC1 upgrade -U -i -p -u - - ['P SSC1 C +UPGRADE:SUCCEED'] - - - SSC SSC1 upgrade -R -b 0 - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - initial condition detail: APSTA mode, connected to AP, running BIN0 (located on - flash id 0) - restore cmd set: - - '' - - - SSC SSC1 upgrade -Q -t 2 -b 0 - - ['R SSC1 C BIN_INFO,0'] - - - SSC SSC1 upgrade -R -b 0 - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - restore post cmd set: - - '' - - - SSC SSC1 upgrade -D - - ['R SSC1 C +UPGRADE:OK'] - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 24.0 - tag: STAAPBIN0 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:1'] - - - SSC SSC1 sta -D - - ['R SSC1 C +QAP:'] - - - SSC SSC1 dhcp -Q -o 1 - - ['R SSC1 C +DHCP:STA,STARTED'] - - - SSC SSC1 mac -Q -o 1 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 sta -D - - ['R SSC1 C +QAP:'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - initial condition detail: sta mode, quit AP, DHCP on, will autogen a TC with initial - condition STAAP1 - restore cmd set: - - '' - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 sta -D - - ['R SSC1 C +QAP:'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 17.0 - tag: STAM1 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:1'] - - - SSC SSC1 sta -Q - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - - - SSC SSC1 dhcp -Q -o 1 - - ['R SSC1 C +DHCP:STA,STARTED'] - - - SSC SSC1 mac -Q -o 1 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - initial condition detail: sta mode, join AP, DHCP on, will autogen a TC with initial - condition STAAP2 - restore cmd set: - - '' - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 24.0 - tag: STAM2 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 upgrade -Q -t 1 - - ['R SSC1 C BIN_ID,0'] - - - SSC SSC1 upgrade -Q -t 2 -b 0 - - ['R SSC1 C BIN_INFO,0'] - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - force restore cmd set: - - '' - - - SSC SSC1 upgrade -R -r 1 -s - - [R SSC1 NC ERROR C !!!ready!!!] - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - - - SOC SOC1 ULISTEN - - [R SOC_COM L OK] - - - SOC SOC1 SETOPT REPLY BIN - - [R SOC_COM C OK] - - - SSC SSC1 upgrade -I -b 0 -f 0 - - ['P SSC1 C +UPGRADE:OK'] - - - SSC SSC1 upgrade -U -i -p -u - - ['P SSC1 C +UPGRADE:SUCCEED'] - - - SSC SSC1 upgrade -R -b 0 - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - initial condition detail: STA mode, connected to AP, running BIN0 (located on flash - id 0) - restore cmd set: - - '' - - - SSC SSC1 upgrade -Q -t 2 -b 0 - - ['R SSC1 C BIN_INFO,0'] - - - SSC SSC1 upgrade -R -b 0 - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - restore post cmd set: - - '' - - - SSC SSC1 upgrade -D - - ['R SSC1 C +UPGRADE:OK'] - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 17.0 - tag: STAMBIN0 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:1'] - - - SSC SSC1 sta -D - - ['R SSC1 C +QAP:'] - - - SSC SSC1 dhcp -Q -o 1 - - ['R SSC1 C +DHCP:STA,STARTED'] - - - SSC SSC1 mac -Q -o 1 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 sta -D - - ['R SSC1 C +QAP:'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - initial condition detail: sta mode, quit AP, will NOT autogen a TC with initial - condition STAAP1 - restore cmd set: - - '' - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 sta -D - - ['R SSC1 C +QAP:'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 17.0 - tag: STAO1 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:1'] - - - SSC SSC1 sta -Q - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - - - SSC SSC1 dhcp -Q -o 1 - - ['R SSC1 C +DHCP:STA,STARTED'] - - - SSC SSC1 mac -Q -o 1 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - initial condition detail: sta mode, join AP, DHCP on, will NOT autogen a TC with - initial condition STAAP2 - restore cmd set: - - '' - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 24.0 - tag: STAO2 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:2'] - - - SSC SSC2 op -Q - - ['R SSC2 C +CURMODE:1'] - - - SSC SSC2 sta -D - - ['R SSC2 C +QAP:'] - - - SSC SSC2 soc -T - - [''] - - - SSC SSC1 dhcp -Q -o 2 - - ['R SSC1 C +DHCP:AP,STARTED'] - - - SSC SSC2 dhcp -Q -o 1 - - ['R SSC2 C +DHCP:STA,STARTED'] - - - SSC SSC1 mac -Q -o 2 - - [R SSC1 P ] - - - SSC SSC2 mac -Q -o 1 - - [R SSC2 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC2 reboot - - [R SSC2 C !!!ready!!!] - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC2 op -S -o 1 - - ['R SSC2 C +MODE:OK'] - - - SSC SSC2 sta -D - - ['R SSC2 C +QAP:'] - - - SSC SSC2 soc -T - - [''] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC2 dhcp -S -o 1 - - [R SSC2 C +DHCP] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC2 mac -S -o 1 -m - - ['R SSC2 C +MAC:STA,OK'] - initial condition detail: same as T2_1 but will NOT autogen a TC with initial condition - T2_2 - restore cmd set: - - '' - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC2 op -S -o 1 - - ['R SSC2 C +MODE:OK'] - - - SSC SSC2 sta -D - - ['R SSC2 C +QAP:'] - - - SSC SSC2 soc -T - - [''] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC2 dhcp -S -o 1 - - [R SSC2 C +DHCP] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC2 mac -S -o 1 -m - - ['R SSC2 C +MAC:STA,OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 73.0 - tag: T2O_1 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:2'] - - - SSC SSC2 op -Q - - ['R SSC2 C +CURMODE:1'] - - - SSC SSC2 sta -D - - ['R SSC2 C +QAP:'] - - - SSC SSC2 soc -T - - [''] - - - SSC SSC1 dhcp -Q -o 2 - - ['R SSC1 C +DHCP:AP,STARTED'] - - - SSC SSC2 dhcp -Q -o 1 - - ['R SSC2 C +DHCP:STA,STARTED'] - - - SSC SSC1 mac -Q -o 2 - - [R SSC1 P ] - - - SSC SSC2 mac -Q -o 1 - - [R SSC2 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC2 reboot - - [R SSC2 C !!!ready!!!] - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC2 op -S -o 1 - - ['R SSC2 C +MODE:OK'] - - - SSC SSC2 sta -D - - ['R SSC2 C +QAP:'] - - - SSC SSC2 soc -T - - [''] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC2 dhcp -S -o 1 - - [R SSC2 C +DHCP] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC2 mac -S -o 1 -m - - ['R SSC2 C +MAC:STA,OK'] - initial condition detail: target 1 as SoftAP, target 2 as STA, will autogen a TC - with initial condition T2_2 - restore cmd set: - - '' - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC2 op -S -o 1 - - ['R SSC2 C +MODE:OK'] - - - SSC SSC2 sta -D - - ['R SSC2 C +QAP:'] - - - SSC SSC2 soc -T - - [''] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC2 dhcp -S -o 1 - - [R SSC2 C +DHCP] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC2 mac -S -o 1 -m - - ['R SSC2 C +MAC:STA,OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 73.0 - tag: T2_1 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:3'] - - - SSC SSC2 op -Q - - ['R SSC2 C +CURMODE:3'] - - - SSC SSC2 sta -D - - ['R SSC2 C +QAP:'] - - - SSC SSC2 soc -T - - [R SSC2 C +CLOSEALL] - - - SSC SSC1 dhcp -Q -o 2 - - ['R SSC1 C +DHCP:AP,STARTED'] - - - SSC SSC2 dhcp -Q -o 1 - - ['R SSC2 C +DHCP:STA,STARTED'] - - - SSC SSC1 mac -Q -o 2 - - [R SSC1 P ] - - - SSC SSC2 mac -Q -o 1 - - [R SSC2 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC2 reboot - - [R SSC2 C !!!ready!!!] - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC2 op -S -o 3 - - ['R SSC2 C +MODE:OK'] - - - SSC SSC2 sta -D - - ['R SSC2 C +QAP:'] - - - SSC SSC2 soc -T - - [R SSC2 C +CLOSEALL] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC2 dhcp -S -o 1 - - [R SSC2 C +DHCP] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC2 mac -S -o 1 -m - - ['R SSC2 C +MAC:STA,OK'] - initial condition detail: target 1 as AP+STA, target 2 as AP+STA (autogen) - restore cmd set: - - '' - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC2 op -S -o 3 - - ['R SSC2 C +MODE:OK'] - - - SSC SSC2 sta -D - - ['R SSC2 C +QAP:'] - - - SSC SSC2 soc -T - - [R SSC2 C +CLOSEALL] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC2 dhcp -S -o 1 - - [R SSC2 C +DHCP] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC2 mac -S -o 1 -m - - ['R SSC2 C +MAC:STA,OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 80.0 - tag: T2_2 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC[1-3] op -Q - - ['R SSC[1-3] C +CURMODE:3'] - - - SSC SSC[1-3] phy -Q -o 3 - - ['R SSC[1-3] C STA,n,40 C AP,n,40'] - force restore cmd set: - - '' - - - SSC SSC[1-3] reboot - - ['R SSC[1-3] C !!!ready!!!'] - - - SSC SSC[1-3] op -S -o 3 - - ['R SSC[1-3] C +MODE:OK'] - - - SSC SSC[1-3] phy -S -o 3 -m n -b 40 - - ['R SSC[1-3] C +PHY:OK'] - initial condition detail: '1. target 1 and target 2 set to AP+STA mode, target 3 - set to STA mode - - 2. all interface of target 2,3 set to 11n ht40 - - 3. config softAP of target 1 and target 2' - restore cmd set: - - '' - - - SSC SSC[1-3] op -S -o 3 - - ['R SSC[1-3] C +MODE:OK'] - - - SSC SSC[1-3] phy -S -o 3 -m n -b 40 - - ['R SSC[1-3] C +PHY:OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 sta -R -r 1 - - [R SSC1 C OK] - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 87.0 - tag: T3_PHY1 - test script: InitCondBase -- check cmd set: - - '' - - - FREBOOT UT1 - - ['R UT1 C Press%20ENTER%20to%20see%20the%20list%20of%20tests'] - force restore cmd set: - - '' - - - FREBOOT UT1 - - ['R UT1 C Press%20ENTER%20to%20see%20the%20list%20of%20tests'] - initial condition detail: At UT menu page - restore cmd set: - - '' - - - FREBOOT UT1 - - ['R UT1 C Press%20ENTER%20to%20see%20the%20list%20of%20tests'] - restore post cmd set: - - '' - - - DELAY 0.1 - - [''] - script path: InitCondBase.py - tag: UTINIT1 - test script: InitCondBase diff --git a/components/idf_test/unit_test/TestCaseScript/IDFUnitTest/__init__.py b/components/idf_test/unit_test/TestCaseScript/IDFUnitTest/__init__.py deleted file mode 100755 index 876a5d4023..0000000000 --- a/components/idf_test/unit_test/TestCaseScript/IDFUnitTest/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__all__ = ["UnitTest"] diff --git a/components/idf_test/unit_test/TestEnvAll.yml b/components/idf_test/unit_test/TestEnvAll.yml deleted file mode 100644 index a6054cf512..0000000000 --- a/components/idf_test/unit_test/TestEnvAll.yml +++ /dev/null @@ -1,292 +0,0 @@ -test environment: -- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_1, - test environment detail: 'PC has 2 wired NIC connected to AP. - - PC has 1 WiFi NIC. - - 1 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_2, - test environment detail: 'PC has 1 WiFi NIC. - - 1 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_3, - test environment detail: 'Able to access WAN after connect to AP. - - 1 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_ADC, - test environment detail: 'PC has 1 wired NIC connected to AP. - - Analog input connect to AT1 TOUT. - - Multimeter connect to input, able to measure input voltage. - - 1 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_APC1, - test environment detail: "PC has 1 wired NIC connected to AP.\nPC has 1 wired NIC\ - \ connected to APC (static IP within the same subnet with APC). \nAPC control\ - \ AP power supply. \nPC has 1 WiFi NIC. \n1 AT target connect with PC by UART\ - \ (AT and LOG port).", test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_APC2, - test environment detail: "Able to access WAN after connect to AP.\nPC has 1 wired\ - \ NIC connected to APC (static IP within the same subnet with APC). \nAPC control\ - \ AP power supply.\nPC has 1 WiFi NIC.\n1 AT target connect with PC by UART (AT\ - \ and LOG port).", test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_HighSpeedUART, - test environment detail: 'PC has 2 wired NIC connected to AP. - - PC has 1 WiFi NIC. - - 1 AT target connect with PC by high speed UART (AT and LOG port).', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_SmartConfigIOT, - test environment detail: '1 AT target connect with PC by UART (AT and LOG port). - - PC has 1 wired NIC connect to Common AP. - - Several AP are placed near AT target. - - Several smart phone installed test APK are placed near AT target.', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: AT_T2_1, - test environment detail: 'PC has 1 wired NIC connected to AP. - - PC has 1 WiFi NIC. - - 2 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: AT_T2_JAP, - test environment detail: "Several AP are placed near AT target.\nPC has 1 wired\ - \ NIC connected to APC (static IP within the same subnet with APC).\nAPC control\ - \ power supply for all APs. \n2 AT target connect with PC by UART (AT and LOG\ - \ port).", test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: AT_T2_Sleep, - test environment detail: 'AP support DTIM placed with AT target. - - 2 AT target connect with PC by UART (AT and LOG port). - - Multimeter connect with PC via GPIB. - - Series multimeter between GND and VCC of AT1. - - AT1''s light sleep wakeup pin and wakeup indication connect with AT2''s GPIO.', - test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: AT_T2_SmartConfig, - test environment detail: '2 AT target connect with PC by UART (AT and LOG port). - - PC has 1 WiFi NIC. - - One HT20 AP and One HT40 AP are placed near target.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: 'SSC1 - - SSC2', additional param list: '', basic param list: '', script path: EnvBase.py, - tag: IR_T2_1, test environment detail: '[TBD] 本测试为非自动测试, 红外能够做到数据收发吻合即可通过', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: NVS_T1_1, - test environment detail: '1 NVS target connect with PC by UART. - - 1 SSC target connect with PC by UART. - - SSC2 GPIO connect to NVS1 power control pin.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: SSC_1, additional param list: '', - basic param list: '', script path: EnvBase.py, tag: PWM_T1_1, test environment detail: "[TBD]\ - \ 1. PWM OS SDK 以及 Non-OS SDK的测试建议分开进行, 放在不同的文件夹, 防止文件命名混淆\n2. 分析CSV文件的Python脚本只能分析单个channel\ - \ \n3. 如果Init脚本打印\"Network Error\" 检查TCP Server是不是正常发送data", test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_1, - test environment detail: 'PC has 2 wired NIC connected to AP. - - PC has 1 WiFi NIC. - - 1 SSC target connect with PC by UART.', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_2, - test environment detail: 'Able to access WAN after connect to AP. - - 1 SSC target connect with PC by UART.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_8089, - test environment detail: 'PC has 1 wired NIC connected to AP. - - 1 8089 tablet able to run iperf test placed near SSC1. - - 1 SSC target connect with PC by UART.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_ADC, - test environment detail: 'PC has 1 wired NIC connected to AP. - - Analog input connect to SSC1 TOUT. - - Multimeter connect to input, able to measure input voltage. - - 1 SSC target connect with PC by UART.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_APC, - test environment detail: "PC has 1 wired NIC connected to AP.\nPC has 1 wired NIC\ - \ connected to APC (static IP within the same subnet with APC). \nAPC control\ - \ AP power supply. \nPC has 1 WiFi NIC. \n1 SSC target connect with PC by UART.", - test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_Enterprise, - test environment detail: "AP use WPA2-Etherprise is placed near SSC1. \n1 SSC target\ - \ connect with PC by UART.", test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_IOT1, - test environment detail: 'PC has 1 WiFi NIC. - - 1 SSC target connect with PC by UART. - - AP todo IOT test are placed near SSC1.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T1_InitData, - test environment detail: '2 SSC target connect with PC by UART. - - SSC1 use 40M crystal oscillator. - - SSC2 use normal 26M crystal oscillator. - - SSC2 GPIO connect to SSC1 power control pin.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_ShieldBox, - test environment detail: 'refer to figure. - - All APs and APC should be set to the same IP subnet. - - PC wired NIC should set static IP address within the same subnet with AP. - - Must use onboard wired NIC.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_Sleep1, - test environment detail: 'AP support DTIM placed with AT target. - - SSC target connect with Raspberry Pi by UART. - - Multimeter connect with Raspberry Pi via GPIB. - - Series multimeter between GND and VCC of SSC1. - - SSC1''s light sleep wakeup pin and wakeup indication connect with Raspberry Pi''s - GPIO. - - SSC1''s XPD connect with RSTB.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_Sleep2, - test environment detail: 'AP support DTIM placed with AT target. - - SSC target connect with Raspberry Pi by UART. - - Multimeter connect with Raspberry Pi via GPIB. - - Series multimeter between GND and VCC of SSC1. - - SSC1''s RSTB pin connect with Raspberry Pi''s GPIO.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_TempBox, - test environment detail: '1 SSC target connect with PC by UART. - - Put SSC target to temperature box.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: SSC_1, additional param list: '', - basic param list: '', script path: EnvBase.py, tag: SSC_T1_Timer, test environment detail: '[TBD] - 通过串口工具调节Timer, 将GPIO_13端口连接到逻辑分析仪', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_VDD33, - test environment detail: '1 SSC target connect with PC by UART. - - Multimeter connect to VDD33, able to measure voltage.', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_WEP, - test environment detail: '1 SSC target connect with PC by UART. - - One WEP share key AP placed near SSC1.', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_1, - test environment detail: 'PC has 1 wired NIC connected to AP. - - PC has 1 WiFi NIC. - - 2 SSC target connect with PC by UART.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 2.0, UART ports: 'SSC1 - - SSC2', additional param list: '', basic param list: '', script path: EnvBase.py, - tag: SSC_T2_GPIO1, test environment detail: '[TBD] 2个ESP_8266通过UART连到PC, ESP_8266的 - GPIO_6相连', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 2.0, UART ports: 'SSC1 - - SSC2', additional param list: '', basic param list: '', script path: EnvBase.py, - tag: SSC_T2_GPIO2, test environment detail: '[TBD] 1. 2个ESP_8266通过UART连到PC, ESP_8266的 - GPIO_15通过面包板相连 - - 2. 可借助面包板, 将GPIO_15, 以及中断函数被打开的8266板的GPIO_2 相连', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 2.0, UART ports: 'SSC1 - - SSC2', additional param list: '', basic param list: '', script path: EnvBase.py, - tag: SSC_T2_GPIO3, test environment detail: '[TBD] 2个ESP_8266通过UART连到PC, ESP_8266之间需要测试的Target_GPIO相连', - test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_JAP, - test environment detail: 'PC has 1 wired NIC connected to APC. - - APC control the power supply of multiple APs. - - 2 SSC target connect with PC by UART.', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_PhyMode, - test environment detail: '2 SSC target connect with PC by UART. - - PC has one WiFi NIC support capture wlan packet using libpcap. - - Set 4 AP with phy mode 11b, 11g, 11n HT20, 11n HT40. - - Put 4 APs near SSC targets.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_ShieldBox, - test environment detail: '2 SSC target connect with PC by UART. - - Put them to Shield box.', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_SmartConfig, - test environment detail: '2 SSC target connect with PC by UART. - - PC has 1 WiFi NIC. - - One HT20 AP and One HT40 AP are placed near target.', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 3.0, script path: EnvBase.py, tag: SSC_T3_PhyMode, - test environment detail: '3 SSC target connect with PC by UART. - - PC has one WiFi NIC support capture wlan packet using libpcap. - - Set 4 AP with (HT20, channel1), (HT20, channel2), (HT40, channel1), (HT40, channel2). - - Put 4 APs near SSC targets.', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 5.0, script path: EnvBase.py, tag: SSC_T5_1, - test environment detail: 5 SSC target connect with PC by UART., test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 5.0, script path: EnvBase.py, tag: SSC_T5_IOT1, - test environment detail: '5 SSC targets connect with PC by UART. - - some Android smart phone are placed near SSC targets.', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T6_1, - test environment detail: 'PC has 1 wired NIC connected to AP. - - PC has 1 WiFi NIC. - - 6 SSC target connect with PC by UART.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: TempSensor_T1_1, - test environment detail: 'Tempeture sensor target connect with PC by UART. - - AP support DTIM placed with AT target. - - Multimeter connect with PC via GPIB. - - Series multimeter between GND and VCC of TempSensor1. - - PC has 1 wired NIC connected to switch. - - APC, AP also connect with swtich. - - All devices connected with switch use the same IP subnet. - - APC control AP power supply.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: SSC_1, additional param list: '', - basic param list: '', script path: EnvBase.py, tag: UART_T1_1, test environment detail: '[TBD] - 将ESP_8266通过UART连到PC', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: 'SSC1 - - SSC2', additional param list: '', basic param list: '', script path: EnvBase.py, - tag: UART_T1_2, test environment detail: '[TBD] ESP_8266通过UART_0通过USB, UART_1 TXD - 通过 TTLcable 连到PC', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: UT_T1_1, - test environment detail: Environment for running ESP32 unit tests, test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: UT_T1_SDMODE, - test environment detail: Environment for running sd card sd mode unit tests, test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: UT_T1_SPIMODE, - test environment detail: Environment for running sd card spi mode unit tests, test script: EnvBase} -- {PC OS: linux, Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: WebServer_T1_1, - test environment detail: 'Web Server target connect with PC by UART. - - PC has 1 wired NIC connected to switch. - - APC, AP also connect with swtich. - - All devices connected with switch use same IP subnet. - - APC control AP power supply.', test script: EnvBase} -- {PC OS: linux, Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: WebServer_T1_2, - test environment detail: 'Web Server target connect with PC by UART. - - 4 PC with WiFi NIC placed near WebServer1.', test script: EnvBase} diff --git a/tools/ci/build_examples.sh b/tools/ci/build_examples.sh index 3f3d3e9385..c300452e75 100755 --- a/tools/ci/build_examples.sh +++ b/tools/ci/build_examples.sh @@ -48,9 +48,6 @@ die() { echo "build_examples running in ${PWD}" -# only 0 or 1 arguments -[ $# -le 1 ] || die "Have to run as $(basename $0) []" - export BATCH_BUILD=1 export V=0 # only build verbose if there's an error @@ -65,26 +62,14 @@ SDKCONFIG_DEFAULTS_CI=sdkconfig.ci EXAMPLE_PATHS=$( find ${IDF_PATH}/examples/ -type f -name Makefile | grep -v "/build_system/cmake/" | sort ) -if [ $# -eq 0 ] +if [ -z {CI_NODE_TOTAL} ] then START_NUM=0 END_NUM=999 else - JOB_NAME=$1 - - # parse text prefix at the beginning of string 'some_your_text_NUM' - # (will be 'some_your_text' without last '_') - JOB_PATTERN=$( echo ${JOB_NAME} | sed -n -r 's/^(.*)_[0-9]+$/\1/p' ) - [ -z ${JOB_PATTERN} ] && die "JOB_PATTERN is bad" - - # parse number 'NUM' at the end of string 'some_your_text_NUM' - # NOTE: Getting rid of the leading zero to get the decimal - JOB_NUM=$( echo ${JOB_NAME} | sed -n -r 's/^.*_0*([0-9]+)$/\1/p' ) - [ -z ${JOB_NUM} ] && die "JOB_NUM is bad" - + JOB_NUM=${CI_NODE_INDEX} # count number of the jobs - NUM_OF_JOBS=$( grep -c -E "^${JOB_PATTERN}_[0-9]+:$" "${IDF_PATH}/.gitlab-ci.yml" ) - [ -z ${NUM_OF_JOBS} ] && die "NUM_OF_JOBS is bad" + NUM_OF_JOBS=${CI_NODE_TOTAL} # count number of examples NUM_OF_EXAMPLES=$( echo "${EXAMPLE_PATHS}" | wc -l ) @@ -96,10 +81,10 @@ else [ -z ${NUM_OF_EX_PER_JOB} ] && die "NUM_OF_EX_PER_JOB is bad" # ex.: [0; 12); [12; 24); [24; 36); [36; 48); [48; 60) - START_NUM=$(( ${JOB_NUM} * ${NUM_OF_EX_PER_JOB} )) + START_NUM=$(( (${JOB_NUM} - 1) * ${NUM_OF_EX_PER_JOB} )) [ -z ${START_NUM} ] && die "START_NUM is bad" - END_NUM=$(( (${JOB_NUM} + 1) * ${NUM_OF_EX_PER_JOB} )) + END_NUM=$(( ${JOB_NUM} * ${NUM_OF_EX_PER_JOB} )) [ -z ${END_NUM} ] && die "END_NUM is bad" fi @@ -168,6 +153,8 @@ build_example () { EXAMPLE_NUM=0 +echo "Current job will build example ${START_NUM} - ${END_NUM}" + for EXAMPLE_PATH in ${EXAMPLE_PATHS} do if [[ $EXAMPLE_NUM -lt $START_NUM || $EXAMPLE_NUM -ge $END_NUM ]] diff --git a/tools/ci/build_examples_cmake.sh b/tools/ci/build_examples_cmake.sh index e19d255c14..3e76271d4a 100755 --- a/tools/ci/build_examples_cmake.sh +++ b/tools/ci/build_examples_cmake.sh @@ -68,26 +68,14 @@ SDKCONFIG_DEFAULTS_CI=sdkconfig.ci EXAMPLE_PATHS=$( find ${IDF_PATH}/examples/ -type f -name CMakeLists.txt | grep -v "/components/" | grep -v "/common_components/" | grep -v "/main/" | grep -v "/idf_as_lib/stubs/" | sort ) -if [ $# -eq 0 ] +if [ -z {CI_NODE_TOTAL} ] then START_NUM=0 END_NUM=999 else - JOB_NAME=$1 - - # parse text prefix at the beginning of string 'some_your_text_NUM' - # (will be 'some_your_text' without last '_') - JOB_PATTERN=$( echo ${JOB_NAME} | sed -n -r 's/^(.*)_[0-9]+$/\1/p' ) - [ -z ${JOB_PATTERN} ] && die "JOB_PATTERN is bad" - - # parse number 'NUM' at the end of string 'some_your_text_NUM' - # NOTE: Getting rid of the leading zero to get the decimal - JOB_NUM=$( echo ${JOB_NAME} | sed -n -r 's/^.*_0*([0-9]+)$/\1/p' ) - [ -z ${JOB_NUM} ] && die "JOB_NUM is bad" - + JOB_NUM=${CI_NODE_INDEX} # count number of the jobs - NUM_OF_JOBS=$( grep -c -E "^${JOB_PATTERN}_[0-9]+:$" "${IDF_PATH}/.gitlab-ci.yml" ) - [ -z ${NUM_OF_JOBS} ] && die "NUM_OF_JOBS is bad" + NUM_OF_JOBS=${CI_NODE_TOTAL} # count number of examples NUM_OF_EXAMPLES=$( echo "${EXAMPLE_PATHS}" | wc -l ) @@ -99,10 +87,10 @@ else [ -z ${NUM_OF_EX_PER_JOB} ] && die "NUM_OF_EX_PER_JOB is bad" # ex.: [0; 12); [12; 24); [24; 36); [36; 48); [48; 60) - START_NUM=$(( ${JOB_NUM} * ${NUM_OF_EX_PER_JOB} )) + START_NUM=$(( (${JOB_NUM} - 1) * ${NUM_OF_EX_PER_JOB} )) [ -z ${START_NUM} ] && die "START_NUM is bad" - END_NUM=$(( (${JOB_NUM} + 1) * ${NUM_OF_EX_PER_JOB} )) + END_NUM=$(( ${JOB_NUM} * ${NUM_OF_EX_PER_JOB} )) [ -z ${END_NUM} ] && die "END_NUM is bad" fi @@ -156,6 +144,8 @@ build_example () { EXAMPLE_NUM=0 +echo "Current job will build example ${START_NUM} - ${END_NUM}" + for EXAMPLE_PATH in ${EXAMPLE_PATHS} do if [[ $EXAMPLE_NUM -lt $START_NUM || $EXAMPLE_NUM -ge $END_NUM ]] diff --git a/tools/tiny-test-fw/Utility/CIAssignTest.py b/tools/tiny-test-fw/Utility/CIAssignTest.py index 9d727b5eb6..6a93f9a885 100644 --- a/tools/tiny-test-fw/Utility/CIAssignTest.py +++ b/tools/tiny-test-fw/Utility/CIAssignTest.py @@ -134,6 +134,19 @@ class AssignTest(object): self.jobs = self._parse_gitlab_ci_config(ci_config_file) self.case_group = case_group + @staticmethod + def _handle_parallel_attribute(job_name, job): + jobs_out = [] + try: + for i in range(job["parallel"]): + jobs_out.append(GitlabCIJob.Job(job, job_name + "_{}".format(i + 1))) + except KeyError: + # Gitlab don't allow to set parallel to 1. + # to make test job name same ($CI_JOB_NAME_$CI_NODE_INDEX), + # we append "_" to jobs don't have parallel attribute + jobs_out.append(GitlabCIJob.Job(job, job_name + "_")) + return jobs_out + def _parse_gitlab_ci_config(self, ci_config_file): with open(ci_config_file, "r") as f: @@ -142,7 +155,7 @@ class AssignTest(object): job_list = list() for job_name in ci_config: if self.CI_TEST_JOB_PATTERN.search(job_name) is not None: - job_list.append(GitlabCIJob.Job(ci_config[job_name], job_name)) + job_list.extend(self._handle_parallel_attribute(job_name, ci_config[job_name])) job_list.sort(key=lambda x: x["name"]) return job_list diff --git a/tools/unit-test-app/tools/UnitTestParser.py b/tools/unit-test-app/tools/UnitTestParser.py index f7715dc658..0058a65741 100644 --- a/tools/unit-test-app/tools/UnitTestParser.py +++ b/tools/unit-test-app/tools/UnitTestParser.py @@ -28,8 +28,8 @@ TEST_CASE_PATTERN = { class Parser(object): """ parse unit test cases from build files and create files for test bench """ - TAG_PATTERN = re.compile("([^=]+)(=)?(.+)?") - DESCRIPTION_PATTERN = re.compile("\[([^]\[]+)\]") # noqa: W605 - regular expression + TAG_PATTERN = re.compile(r"([^=]+)(=)?(.+)?") + DESCRIPTION_PATTERN = re.compile(r"\[([^]\[]+)\]") CONFIG_PATTERN = re.compile(r"{([^}]+)}") TEST_GROUPS_PATTERN = re.compile(r"TEST_GROUPS=(.*)$") @@ -261,7 +261,12 @@ class Parser(object): dump parsed test cases to YAML file for test bench input :param test_cases: parsed test cases """ - with open(os.path.join(self.idf_path, self.TEST_CASE_FILE), "w+") as f: + filename = os.path.join(self.idf_path, self.TEST_CASE_FILE) + try: + os.mkdir(os.path.dirname(filename)) + except OSError: + pass + with open(os.path.join(filename), "w+") as f: yaml.dump({"test cases": test_cases}, f, allow_unicode=True, default_flow_style=False) def copy_module_def_file(self): From 6eca80a9899ec02325fe9d8a5c9bfb5c9d2c68d1 Mon Sep 17 00:00:00 2001 From: He Yin Ling Date: Sun, 28 Apr 2019 16:57:59 +0800 Subject: [PATCH 228/486] CI: try to use the correct branch of other projects used in CI: 1. revision defined in bot message 2. branch name (or tag name) of current IDF 3. CI_MERGE_REQUEST_TARGET_BRANCH_NAME 4. branch name parsed from `git describe` 5. default branch --- .gitlab-ci.yml | 23 +++++------- tools/ci/checkout_project_ref.py | 63 +++++++++++++++++++++++++------- 2 files changed, 59 insertions(+), 27 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 99a21cbb8d..a42b47fa49 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -131,11 +131,11 @@ build_template_app: # Set the variable for 'esp-idf-template' testing - ESP_IDF_TEMPLATE_GIT=${ESP_IDF_TEMPLATE_GIT:-"https://github.com/espressif/esp-idf-template.git"} - git clone ${ESP_IDF_TEMPLATE_GIT} + - python $CHECKOUT_REF_SCRIPT esp-idf-template esp-idf-template - cd esp-idf-template # Try to use the same branch name for esp-idf-template that we're # using on esp-idf. If it doesn't exist then just stick to the default # branch - - python $CHECKOUT_REF_SCRIPT esp-idf-template - make defconfig # Test debug build (default) - make all V=1 @@ -175,8 +175,8 @@ build_ssc: - $BOT_LABEL_REGULAR_TEST script: - git clone $SSC_REPOSITORY + - python $CHECKOUT_REF_SCRIPT SSC SSC - cd SSC - - python $CHECKOUT_REF_SCRIPT SSC - MAKEFLAGS= ./ci_build_ssc.sh # If you want to add new build ssc jobs, please add it into dependencies of `assign_test` and `.test_template` @@ -771,8 +771,8 @@ update_test_cases: script: - export GIT_SHA=$(echo ${CI_COMMIT_SHA} | cut -c 1-8) - git clone $TEST_MANAGEMENT_REPO + - python $CHECKOUT_REF_SCRIPT test-management test-management - cd test-management - - python $CHECKOUT_REF_SCRIPT test-management - echo $BOT_JIRA_ACCOUNT > ${BOT_ACCOUNT_CONFIG_FILE} # update unit test cases - python ImportTestCase.py $JIRA_TEST_MANAGEMENT_PROJECT unity -d $UNIT_TEST_CASE_FILE -r $GIT_SHA @@ -821,8 +821,8 @@ deploy_test_result: # we need to remove it so we can clone test-management folder again - rm -r test-management - git clone $TEST_MANAGEMENT_REPO + - python3 $CHECKOUT_REF_SCRIPT test-management test-management - cd test-management - - python3 $CHECKOUT_REF_SCRIPT test-management - echo $BOT_JIRA_ACCOUNT > ${BOT_ACCOUNT_CONFIG_FILE} # update test results - python3 ImportTestResult.py -r "$GIT_SHA (r${REV_COUNT})" -j $JIRA_TEST_MANAGEMENT_PROJECT -s "$SUMMARY" -l CI -p ${CI_PROJECT_DIR}/TEST_LOGS ${CI_PROJECT_DIR}/${CI_COMMIT_SHA} --pipeline_url ${CI_PIPELINE_URL} @@ -1005,8 +1005,8 @@ assign_test: - python $TEST_FW_PATH/CIAssignUnitTest.py $IDF_PATH/components/idf_test/unit_test/TestCaseAll.yml $IDF_PATH/.gitlab-ci.yml $IDF_PATH/components/idf_test/unit_test/CIConfigs # clone test script to assign tests - git clone $TEST_SCRIPT_REPOSITORY + - python $CHECKOUT_REF_SCRIPT auto_test_script auto_test_script - cd auto_test_script - - python $CHECKOUT_REF_SCRIPT auto_test_script # assgin integration test cases - python CIAssignTestCases.py -t $IDF_PATH/components/idf_test/integration_test -c $IDF_PATH/.gitlab-ci.yml -b $IDF_PATH/SSC/ssc_bin @@ -1045,8 +1045,7 @@ assign_test: - test -e $CONFIG_FILE || exit 0 # clone test env configs - git clone $TEST_ENV_CONFIG_REPOSITORY - - cd ci-test-runner-configs - - python $CHECKOUT_REF_SCRIPT ci-test-runner-configs + - python $CHECKOUT_REF_SCRIPT ci-test-runner-configs ci-test-runner-configs - cd $TEST_FW_PATH # run test - python Runner.py $TEST_CASE_PATH -c $CONFIG_FILE -e $ENV_FILE @@ -1143,12 +1142,11 @@ test_weekend_network: - test -e $CONFIG_FILE || exit 0 # clone local test env configs - git clone $TEST_ENV_CONFIG_REPOSITORY - - cd ci-test-runner-configs - - python $CHECKOUT_REF_SCRIPT ci-test-runner-configs + - python $CHECKOUT_REF_SCRIPT ci-test-runner-configs ci-test-runner-configs # clone test bench - git clone $TEST_SCRIPT_REPOSITORY + - python $CHECKOUT_REF_SCRIPT auto_test_script auto_test_script - cd auto_test_script - - python $CHECKOUT_REF_SCRIPT auto_test_script # run test - python CIRunner.py -l "$LOG_PATH/$CI_JOB_NAME_$CI_NODE_INDEX" -c $CONFIG_FILE -e $LOCAL_ENV_CONFIG_PATH -t $TEST_CASE_FILE_PATH -m $MODULE_UPDATE_FILE @@ -1166,12 +1164,11 @@ nvs_compatible_test: script: # clone local test env configs - git clone $TEST_ENV_CONFIG_REPOSITORY - - cd ci-test-runner-configs - - python $CHECKOUT_REF_SCRIPT ci-test-runner-configs + - python $CHECKOUT_REF_SCRIPT ci-test-runner-configs ci-test-runner-configs # clone test bench - git clone $TEST_SCRIPT_REPOSITORY + - python $CHECKOUT_REF_SCRIPT auto_test_script auto_test_script - cd auto_test_script - - git checkout ${CI_COMMIT_REF_NAME} || echo "Using default branch..." # prepare nvs bins - ./Tools/prepare_nvs_bin.sh # run test diff --git a/tools/ci/checkout_project_ref.py b/tools/ci/checkout_project_ref.py index 5218a7cc23..5b6b332c9c 100755 --- a/tools/ci/checkout_project_ref.py +++ b/tools/ci/checkout_project_ref.py @@ -7,32 +7,67 @@ import os import json import argparse import subprocess +import re -def checkout_branch(proj_name, customized_revision, default_ref_name): +IDF_GIT_DESCRIBE_PATTERN = re.compile(r"^v(\d)\.(\d)") + + +def target_branch_candidates(proj_name): + """ + :return: a list of target branch candidates, from highest priority to lowest priority. + """ + candidates = [ + # branch name (or tag name) of current IDF + os.getenv("CI_COMMIT_REF_NAME"), + # CI_MERGE_REQUEST_TARGET_BRANCH_NAME + os.getenv("CI_MERGE_REQUEST_TARGET_BRANCH_NAME"), + ] + # revision defined in bot message + customized_project_revisions = os.getenv("BOT_CUSTOMIZED_REVISION") + if customized_project_revisions: + customized_project_revisions = json.loads(customized_project_revisions) try: - ref_to_use = customized_revision[proj_name.lower()] + ref_to_use = customized_project_revisions[proj_name.lower()] + # highest priority, insert to head of list + candidates.insert(0, ref_to_use) except (KeyError, TypeError): - ref_to_use = default_ref_name + pass + # branch name read from IDF + git_describe = subprocess.check_output(["git", "describe", "--tags", "HEAD"]) + match = IDF_GIT_DESCRIBE_PATTERN.search(git_describe) + if match: + major_revision = match.group(1) + minor_revision = match.group(2) + # release branch + candidates.append("release/v{}.{}".format(major_revision, minor_revision)) + # branch to match all major branches, like v3.x or v3 + candidates.append("release/v{}.x".format(major_revision)) + candidates.append("release/v{}".format(major_revision)) - try: - subprocess.check_call(["git", "checkout", ref_to_use]) - print("CI using ref {} for project {}".format(ref_to_use, proj_name)) - except subprocess.CalledProcessError: - print("using default branch") + return [c for c in candidates if c] # filter out null value if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("project", help="the name of project") + parser.add_argument("project_relative_path", + help="relative path of project to IDF repository directory") args = parser.parse_args() - project_name = args.project - customized_project_revisions = os.getenv("BOT_CUSTOMIZED_REVISION") - if customized_project_revisions: - customized_project_revisions = json.loads(customized_project_revisions) - ci_ref_name = os.getenv("CI_COMMIT_REF_NAME") + candidate_branches = target_branch_candidates(args.project) - checkout_branch(project_name, customized_project_revisions, ci_ref_name) + # change to project dir for checkout + os.chdir(args.project_relative_path) + + for candidate in candidate_branches: + try: + subprocess.check_call(["git", "checkout", candidate]) + print("CI using ref {} for project {}".format(candidate, args.project)) + break + except subprocess.CalledProcessError: + pass + else: + print("using default branch") From e390dd3eab8f39287713387341385e74e22e7ee0 Mon Sep 17 00:00:00 2001 From: He Yin Ling Date: Sat, 29 Jun 2019 00:39:21 +0800 Subject: [PATCH 229/486] CI: use `include` to split large CI config file --- .gitlab-ci.yml | 1463 +------------------------------ tools/ci/config/assign-test.yml | 74 ++ tools/ci/config/build.yml | 247 ++++++ tools/ci/config/check.yml | 122 +++ tools/ci/config/deploy.yml | 153 ++++ tools/ci/config/host-test.yml | 286 ++++++ tools/ci/config/target-test.yml | 572 ++++++++++++ 7 files changed, 1472 insertions(+), 1445 deletions(-) create mode 100644 tools/ci/config/assign-test.yml create mode 100644 tools/ci/config/build.yml create mode 100644 tools/ci/config/check.yml create mode 100644 tools/ci/config/deploy.yml create mode 100644 tools/ci/config/host-test.yml create mode 100644 tools/ci/config/target-test.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a42b47fa49..5bf113b946 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -38,6 +38,9 @@ variables: # Docker images BOT_DOCKER_IMAGE_TAG: ":latest" +# target test config file, used by assign test job + CI_TARGET_TEST_CONFIG_FILE: "$CI_PROJECT_DIR/tools/ci/config/target-test.yml" + # before each job, we need to check if this job is filtered by bot stage/job filter .apply_bot_filter: &apply_bot_filter @@ -91,7 +94,7 @@ before_script: - *setup_custom_toolchain # used for check scripts which we want to run unconditionally -.before_script_lesser_nofilter: &before_script_lesser_nofilter +.before_script_lesser_nofilter: variables: GIT_SUBMODULE_STRATEGY: none before_script: @@ -101,7 +104,7 @@ before_script: - *setup_custom_toolchain # used for everything else where we want to do no prep, except for bot filter -.before_script_lesser: &before_script_lesser +.before_script_lesser: variables: GIT_SUBMODULE_STRATEGY: none before_script: @@ -115,1456 +118,26 @@ before_script: after_script: - *cleanup_custom_toolchain -build_template_app: - stage: build - image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG - tags: - - build - variables: - BATCH_BUILD: "1" - only: - variables: - - $BOT_TRIGGER_WITH_LABEL == null - - $BOT_LABEL_BUILD - - $BOT_LABEL_REGULAR_TEST - script: - # Set the variable for 'esp-idf-template' testing - - ESP_IDF_TEMPLATE_GIT=${ESP_IDF_TEMPLATE_GIT:-"https://github.com/espressif/esp-idf-template.git"} - - git clone ${ESP_IDF_TEMPLATE_GIT} - - python $CHECKOUT_REF_SCRIPT esp-idf-template esp-idf-template - - cd esp-idf-template - # Try to use the same branch name for esp-idf-template that we're - # using on esp-idf. If it doesn't exist then just stick to the default - # branch - - make defconfig - # Test debug build (default) - - make all V=1 - # Now test release build - - make clean - - sed -i.bak -e's/CONFIG_OPTIMIZATION_LEVEL_DEBUG\=y/CONFIG_OPTIMIZATION_LEVEL_RELEASE=y/' sdkconfig - - make all V=1 - # Check if there are any stray printf/ets_printf references in WiFi libs - - cd ../components/esp_wifi/lib_esp32 - - test $(xtensa-esp32-elf-nm *.a | grep -w printf | wc -l) -eq 0 - - test $(xtensa-esp32-elf-nm *.a | grep -w ets_printf | wc -l) -eq 0 - - -.build_template: &build_template - stage: build - image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG - tags: - - build - variables: - BATCH_BUILD: "1" - V: "0" - -build_ssc: - <<: *build_template - parallel: 3 - artifacts: - paths: - - SSC/ssc_bin - expire_in: 1 week - variables: - SSC_CONFIG_FOLDER: "$CI_PROJECT_DIR/SSC/configs/ESP32_IDF" - only: - variables: - - $BOT_TRIGGER_WITH_LABEL == null - - $BOT_LABEL_BUILD - - $BOT_LABEL_INTEGRATION_TEST - - $BOT_LABEL_REGULAR_TEST - script: - - git clone $SSC_REPOSITORY - - python $CHECKOUT_REF_SCRIPT SSC SSC - - cd SSC - - MAKEFLAGS= ./ci_build_ssc.sh - -# If you want to add new build ssc jobs, please add it into dependencies of `assign_test` and `.test_template` - -.build_esp_idf_unit_test_template: &build_esp_idf_unit_test_template - <<: *build_template - artifacts: - paths: - - tools/unit-test-app/output - - components/idf_test/unit_test/TestCaseAll.yml - expire_in: 2 days - only: - variables: - - $BOT_TRIGGER_WITH_LABEL == null - - $BOT_LABEL_BUILD - - $BOT_LABEL_UNIT_TEST - - $BOT_LABEL_REGULAR_TEST - -build_esp_idf_tests_make: - <<: *build_esp_idf_unit_test_template - script: - - export EXTRA_CFLAGS=${PEDANTIC_CFLAGS} - - export EXTRA_CXXFLAGS=${EXTRA_CFLAGS} - - cd $CI_PROJECT_DIR/tools/unit-test-app - - MAKEFLAGS= make help # make sure kconfig tools are built in single process - - make ut-clean-all-configs - - make ut-build-all-configs - - python tools/UnitTestParser.py - # Check if the tests demand Make built binaries. If not, delete them - - if [ "$UNIT_TEST_BUILD_SYSTEM" == "make" ]; then exit 0; fi - - rm -rf builds output sdkconfig - - rm $CI_PROJECT_DIR/components/idf_test/unit_test/TestCaseAll.yml - -build_esp_idf_tests_cmake: - <<: *build_esp_idf_unit_test_template - script: - - export PATH="$IDF_PATH/tools:$PATH" - - export EXTRA_CFLAGS=${PEDANTIC_CFLAGS} - - export EXTRA_CXXFLAGS=${EXTRA_CFLAGS} - - cd $CI_PROJECT_DIR/tools/unit-test-app - - idf.py ut-clean-all-configs - - idf.py ut-build-all-configs - - python tools/UnitTestParser.py - # Check if the tests demand CMake built binaries. If not, delete them - - if [ "$UNIT_TEST_BUILD_SYSTEM" == "cmake" ]; then exit 0; fi - - rm -rf builds output sdkconfig - - rm $CI_PROJECT_DIR/components/idf_test/unit_test/TestCaseAll.yml - -build_examples_make: - <<: *build_template - parallel: 8 - # This is a workaround for a rarely encountered issue with building examples in CI. - # Probably related to building of Kconfig in 'make clean' stage - retry: 1 - artifacts: - when: always - paths: - - build_examples/*/*/*/build/*.bin - - build_examples/*/*/*/sdkconfig - - build_examples/*/*/*/build/*.elf - - build_examples/*/*/*/build/*.map - - build_examples/*/*/*/build/download.config - - build_examples/*/*/*/build/bootloader/*.bin - - $LOG_PATH - expire_in: 2 days - variables: - LOG_PATH: "$CI_PROJECT_DIR/log_examples_make" - only: - variables: - - $BOT_TRIGGER_WITH_LABEL == null - - $BOT_LABEL_BUILD - - $BOT_LABEL_EXAMPLE_TEST - - $BOT_LABEL_REGULAR_TEST - - $BOT_LABEL_WEEKEND_TEST - script: - # it's not possible to build 100% out-of-tree and have the "artifacts" - # mechanism work, but this is the next best thing - - rm -rf build_examples - - mkdir build_examples - - cd build_examples - # build some of examples - - mkdir -p ${LOG_PATH} - - ${IDF_PATH}/tools/ci/build_examples.sh - -# same as above, but for CMake -build_examples_cmake: - <<: *build_template - parallel: 5 - artifacts: - when: always - paths: - - build_examples_cmake/*/*/*/build/*.bin - - build_examples_cmake/*/*/*/sdkconfig - - build_examples_cmake/*/*/*/build/*.elf - - build_examples_cmake/*/*/*/build/*.map - - build_examples_cmake/*/*/*/build/flasher_args.json - - build_examples_cmake/*/*/*/build/bootloader/*.bin - - $LOG_PATH - expire_in: 2 days - variables: - LOG_PATH: "$CI_PROJECT_DIR/log_examples_cmake" - only: - variables: - - $BOT_TRIGGER_WITH_LABEL == null - - $BOT_LABEL_BUILD - - $BOT_LABEL_EXAMPLE_TEST - - $BOT_LABEL_REGULAR_TEST - - $BOT_LABEL_WEEKEND_TEST - script: - # it's not possible to build 100% out-of-tree and have the "artifacts" - # mechanism work, but this is the next best thing - - rm -rf build_examples_cmake - - mkdir build_examples_cmake - - cd build_examples_cmake - # build some of examples - - mkdir -p ${LOG_PATH} - - ${IDF_PATH}/tools/ci/build_examples_cmake.sh - -# If you want to add new build example jobs, please add it into dependencies of `.example_test_template` - -build_docs: - stage: build - image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG - tags: - - build_docs - artifacts: - when: always - paths: - # English version of documentation - - docs/en/doxygen-warning-log.txt - - docs/en/sphinx-warning-log.txt - - docs/en/sphinx-warning-log-sanitized.txt - - docs/en/_build/html - - docs/sphinx-err-* - # Chinese version of documentation - - docs/zh_CN/doxygen-warning-log.txt - - docs/zh_CN/sphinx-warning-log.txt - - docs/zh_CN/sphinx-warning-log-sanitized.txt - - docs/zh_CN/_build/html - expire_in: 1 day - only: - variables: - - $BOT_TRIGGER_WITH_LABEL == null - - $BOT_LABEL_BUILD - - $BOT_LABEL_BUILD_DOCS - - $BOT_LABEL_REGULAR_TEST - script: - - cd docs - - ./check_lang_folder_sync.sh - - cd en - - make gh-linkcheck - - make html - - ../check_doc_warnings.sh - - cd ../zh_CN - - make gh-linkcheck - - make html - - ../check_doc_warnings.sh - -.check_job_template: &check_job_template +.check_job_template: stage: check image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG tags: - host_test dependencies: [] - <<: *before_script_lesser_nofilter + extends: .before_script_lesser_nofilter -verify_cmake_style: - <<: *check_job_template - stage: build - only: - variables: - - $BOT_TRIGGER_WITH_LABEL == null - - $BOT_LABEL_BUILD - - $BOT_LABEL_REGULAR_TEST - script: - tools/cmake/run_cmake_lint.sh - -.host_test_template: &host_test_template - stage: host_test - image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG - tags: - - host_test - dependencies: [] - only: - variables: - - $BOT_TRIGGER_WITH_LABEL == null - - $BOT_LABEL_HOST_TEST - - $BOT_LABEL_REGULAR_TEST - -test_nvs_on_host: - <<: *host_test_template - script: - - cd components/nvs_flash/test_nvs_host - - make test - -test_nvs_coverage: - <<: *host_test_template - artifacts: - paths: - - components/nvs_flash/test_nvs_host/coverage_report - expire_in: 1 week - only: - refs: - - triggers - variables: - - $BOT_LABEL_NVS_COVERAGE - script: - - cd components/nvs_flash/test_nvs_host - - make coverage_report - -test_partition_table_on_host: - <<: *host_test_template - tags: - - build - script: - - cd components/partition_table/test_gen_esp32part_host - - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./gen_esp32part_tests.py - -test_wl_on_host: - <<: *host_test_template - artifacts: - paths: - - components/wear_levelling/test_wl_host/coverage_report.zip - expire_in: 1 week - script: - - cd components/wear_levelling/test_wl_host - - make test - -test_fatfs_on_host: - <<: *host_test_template - script: - - cd components/fatfs/test_fatfs_host/ - - make test - -test_ldgen_on_host: - <<: *host_test_template - script: - - cd tools/ldgen/test - - ./test_fragments.py - - ./test_generation.py - -.host_fuzzer_test_template: &host_fuzzer_test_template - stage: host_test - image: $CI_DOCKER_REGISTRY/afl-fuzzer-test - tags: - - host_test - dependencies: [] - artifacts: - when: always - paths: - - ${FUZZER_TEST_DIR}/out/crashes - - ${FUZZER_TEST_DIR}/fuzz_output.log - expire_in: 1 week - only: - variables: - - $BOT_LABEL_FUZZER_TEST - - $BOT_LABEL_WEEKEND_TEST - script: - - export AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 && export AFL_SKIP_CPUFREQ=1 - - cd ${FUZZER_TEST_DIR} - # run AFL fuzzer for one hour - - ( ( make ${FUZZER_PARAMS} fuzz | tee fuzz_output.log | grep -v '\(Fuzzing test case\|Entering queue cycle\)' ) || pkill sleep ) & - - ( sleep 3600 || mkdir -p out/crashes/env_failed ) && pkill afl-fuz - # check no crashes found - - test -z "$(ls out/crashes/)" || exit 1 - -.clang_tidy_check_template: &clang_tidy_check_template - stage: host_test - image: ${CI_DOCKER_REGISTRY}/clang-static-analysis - tags: - - host_test - dependencies: [] - artifacts: - reports: - junit: $IDF_PATH/output.xml - when: always - paths: - - $IDF_PATH/examples/get-started/hello_world/tidybuild/report/* - expire_in: 1 day - script: - - git clone $IDF_ANALYSIS_UTILS static_analysis_utils && cd static_analysis_utils - # Setup parameters of triggered/regular job - - export TRIGGERED_RELATIVE=${BOT_LABEL_STATIC_ANALYSIS-} && export TRIGGERED_ABSOLUTE=${BOT_LABEL_STATIC_ANALYSIS_ALL-} && export TARGET_BRANCH=${BOT_CUSTOMIZED_REVISION-} - - ./analyze.sh $IDF_PATH/examples/get-started/hello_world/ $IDF_PATH/tools/ci/static-analysis-rules.yml $IDF_PATH/output.xml - -.clang_tidy_deploy_template: &clang_tidy_deploy_template - stage: deploy - image: $CI_DOCKER_REGISTRY/esp32-ci-env - tags: - - deploy - script: - - mkdir -p ~/.ssh - - chmod 700 ~/.ssh - - echo -n $DOCS_DEPLOY_KEY > ~/.ssh/id_rsa_base64 - - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa - - chmod 600 ~/.ssh/id_rsa - - echo -e "Host $DOCS_SERVER\n\tStrictHostKeyChecking no\n\tUser $DOCS_SERVER_USER\n" >> ~/.ssh/config - - export GIT_VER=$(git describe --always) - - cd $IDF_PATH/examples/get-started/hello_world/tidybuild - - mv report $GIT_VER - - tar czvf $GIT_VER.tar.gz $GIT_VER - - export STATIC_REPORT_PATH="web/static_analysis/esp-idf/" - - ssh $DOCS_SERVER -x "mkdir -p $STATIC_REPORT_PATH/clang-tidy" - - scp $GIT_VER.tar.gz $DOCS_SERVER:$STATIC_REPORT_PATH/clang-tidy - - ssh $DOCS_SERVER -x "cd $STATIC_REPORT_PATH/clang-tidy && tar xzvf $GIT_VER.tar.gz && rm -f latest && ln -s $GIT_VER latest" - # add link to view the report - - echo "[static analysis][clang tidy] $CI_DOCKER_REGISTRY/static_analysis/esp-idf/clang-tidy/${GIT_VER}/index.html" - - test ! -e ${GIT_VER}/FAILED_RULES || { echo 'Failed static analysis rules!'; cat ${GIT_VER}/FAILED_RULES; exit 1; } - -clang_tidy_check: - <<: *clang_tidy_check_template - variables: - BOT_NEEDS_TRIGGER_BY_NAME: 1 - BOT_LABEL_STATIC_ANALYSIS: 1 - -clang_tidy_check_regular: - <<: *clang_tidy_check_template - -clang_tidy_check_all: - <<: *clang_tidy_check_template - variables: - BOT_NEEDS_TRIGGER_BY_NAME: 1 - BOT_LABEL_STATIC_ANALYSIS_ALL: 1 - -clang_tidy_deploy: - <<: *clang_tidy_deploy_template - dependencies: - - clang_tidy_check - - clang_tidy_check_all - variables: - BOT_NEEDS_TRIGGER_BY_NAME: 1 - -clang_tidy_deploy_regular: - <<: *clang_tidy_deploy_template - dependencies: - - clang_tidy_check_regular - only: - refs: - - master - - /^release\/v/ - - /^v\d+\.\d+(\.\d+)?($|-)/ - - triggers - - schedules - variables: - - $BOT_LABEL_STATIC_ANALYSIS - - $BOT_LABEL_STATIC_ANALYSIS_ALL - -test_mdns_fuzzer_on_host: - <<: *host_fuzzer_test_template - variables: - FUZZER_TEST_DIR: components/mdns/test_afl_fuzz_host - -test_lwip_dns_fuzzer_on_host: - <<: *host_fuzzer_test_template - variables: - FUZZER_TEST_DIR: components/lwip/test_afl_host - FUZZER_PARAMS: MODE=dns - -test_lwip_dhcp_fuzzer_on_host: - <<: *host_fuzzer_test_template - variables: - FUZZER_TEST_DIR: components/lwip/test_afl_host - FUZZER_PARAMS: MODE=dhcp_client - -test_lwip_dhcps_fuzzer_on_host: - <<: *host_fuzzer_test_template - variables: - FUZZER_TEST_DIR: components/lwip/test_afl_host - FUZZER_PARAMS: MODE=dhcp_server - -test_spiffs_on_host: - <<: *host_test_template - script: - - cd components/spiffs/test_spiffs_host/ - - make test - -test_multi_heap_on_host: - <<: *host_test_template - script: - - cd components/heap/test_multi_heap_host - - ./test_all_configs.sh - -test_confserver: - <<: *host_test_template - script: - - cd tools/kconfig_new/test - - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test_confserver.py - -test_build_system: - <<: *host_test_template - script: - - ${IDF_PATH}/tools/ci/test_configure_ci_environment.sh - - rm -rf test_build_system - - mkdir test_build_system - - cd test_build_system - - ${IDF_PATH}/tools/ci/test_build_system.sh - -test_build_system_cmake: - <<: *host_test_template - script: - - ${IDF_PATH}/tools/ci/test_configure_ci_environment.sh - - rm -rf test_build_system - - mkdir test_build_system - - cd test_build_system - - ${IDF_PATH}/tools/ci/test_build_system_cmake.sh - -test_idf_monitor: - <<: *host_test_template - artifacts: - # save artifacts always in order to access results which were retried without consequent failure - when: always - paths: - - tools/test_idf_monitor/outputs/* - expire_in: 1 week - script: - - cd ${IDF_PATH}/tools/test_idf_monitor - - ./run_test_idf_monitor.py - -test_idf_size: - <<: *host_test_template - artifacts: - when: on_failure - paths: - - tools/test_idf_size/output - - tools/test_idf_size/.coverage - expire_in: 1 week - script: - - cd ${IDF_PATH}/tools/test_idf_size - - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test.sh - -test_idf_tools: - <<: *host_test_template - script: - # Remove Xtensa and ULP toolchains from the PATH, tests will expect a clean environment - - export PATH=$(p=$(echo $PATH | tr ":" "\n" | grep -v "/root/.espressif/tools\|/opt/espressif${CUSTOM_TOOLCHAIN_PATH:+\|${CUSTOM_TOOLCHAIN_PATH}}" | tr "\n" ":"); echo ${p%:}) - - cd ${IDF_PATH}/tools/test_idf_tools - - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test_idf_tools.py - -test_esp_err_to_name_on_host: - <<: *host_test_template - artifacts: - when: on_failure - paths: - - components/esp32/esp_err_to_name.c - expire_in: 1 week - script: - - cd ${IDF_PATH}/tools/ - - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh -p 2.7.15 ./gen_esp_err_to_name.py - - git diff --exit-code -- ../components/esp32/esp_err_to_name.c || { echo 'Differences found. Please run gen_esp_err_to_name.py and commit the changes.'; exit 1; } - - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh -p 3.4.8 ./gen_esp_err_to_name.py - - git diff --exit-code -- ../components/esp32/esp_err_to_name.c || { echo 'Differences found between running under Python 2 and 3.'; exit 1; } - -test_esp_efuse_table_on_host: - <<: *host_test_template - artifacts: - when: on_failure - paths: - - components/efuse/esp32/esp_efuse_table.c - expire_in: 1 week - script: - - cd ${IDF_PATH}/components/efuse/ - - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh -p 2.7.15 ./efuse_table_gen.py ${IDF_PATH}/components/efuse/esp32/esp_efuse_table.csv - - git diff --exit-code -- esp32/esp_efuse_table.c || { echo 'Differences found. Please run make efuse_common_table or idf.py efuse_common_table and commit the changes.'; exit 1; } - - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh -p 3.4.8 ./efuse_table_gen.py ${IDF_PATH}/components/efuse/esp32/esp_efuse_table.csv - - git diff --exit-code -- ../components/esp32/esp_efuse_table.c || { echo 'Differences found between running under Python 2 and 3.'; exit 1; } - - cd ${IDF_PATH}/components/efuse/test_efuse_host - - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./efuse_tests.py - -test_espcoredump: - <<: *host_test_template - artifacts: - when: always - paths: - - components/espcoredump/test/.coverage - - components/espcoredump/test/output - expire_in: 1 week - script: - - cd components/espcoredump/test/ - - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test_espcoredump.sh - -test_logtrace_proc: - <<: *host_test_template - artifacts: - when: on_failure - paths: - - tools/esp_app_trace/test/logtrace/output - - tools/esp_app_trace/test/logtrace/.coverage - expire_in: 1 week - script: - - cd ${IDF_PATH}/tools/esp_app_trace/test/logtrace - - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test.sh - -test_sysviewtrace_proc: - <<: *host_test_template - artifacts: - when: on_failure - paths: - - tools/esp_app_trace/test/sysview/output - - tools/esp_app_trace/test/sysview/.coverage - expire_in: 1 week - script: - - cd ${IDF_PATH}/tools/esp_app_trace/test/sysview - - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test.sh - -push_to_github: - stage: deploy - image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG - tags: - - deploy - only: - - master - - /^release\/v/ - - /^v\d+\.\d+(\.\d+)?($|-)/ - when: on_success - dependencies: [] - <<: *before_script_lesser - script: - - mkdir -p ~/.ssh - - chmod 700 ~/.ssh - - echo -n $GH_PUSH_KEY > ~/.ssh/id_rsa_base64 - - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa - - chmod 600 ~/.ssh/id_rsa - - echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config - - git remote remove github &>/dev/null || true - - git remote add github git@github.com:espressif/esp-idf.git - - tools/ci/push_to_github.sh - -deploy_docs: - stage: deploy - image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG - tags: - - deploy - only: - refs: - - master - - /^release\/v/ - - /^v\d+\.\d+(\.\d+)?($|-)/ - - triggers - variables: - - $BOT_TRIGGER_WITH_LABEL == null - - $BOT_LABEL_BUILD_DOCS - dependencies: - - build_docs - <<: *before_script_lesser - script: - - mkdir -p ~/.ssh - - chmod 700 ~/.ssh - - echo -n $DOCS_DEPLOY_KEY > ~/.ssh/id_rsa_base64 - - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa - - chmod 600 ~/.ssh/id_rsa - - echo -e "Host $DOCS_SERVER\n\tStrictHostKeyChecking no\n\tUser $DOCS_SERVER_USER\n" >> ~/.ssh/config - - export GIT_VER=$(git describe --always) - - cd docs/en/_build/ - - mv html $GIT_VER - - tar czvf $GIT_VER.tar.gz $GIT_VER - - scp $GIT_VER.tar.gz $DOCS_SERVER:$DOCS_PATH/en - - ssh $DOCS_SERVER -x "cd $DOCS_PATH/en && tar xzvf $GIT_VER.tar.gz && rm -f latest && ln -s $GIT_VER latest" - - cd ../../zh_CN/_build/ - - mv html $GIT_VER - - tar czvf $GIT_VER.tar.gz $GIT_VER - - scp $GIT_VER.tar.gz $DOCS_SERVER:$DOCS_PATH/zh_CN - - ssh $DOCS_SERVER -x "cd $DOCS_PATH/zh_CN && tar xzvf $GIT_VER.tar.gz && rm -f latest && ln -s $GIT_VER latest" - # add link to preview doc - - echo "[document preview][en] $CI_DOCKER_REGISTRY/docs/esp-idf/en/${GIT_VER}/index.html" - - echo "[document preview][zh_CN] $CI_DOCKER_REGISTRY/docs/esp-idf/zh_CN/${GIT_VER}/index.html" - -update_test_cases: - stage: assign_test - image: $CI_DOCKER_REGISTRY/ubuntu-test-env - tags: - - deploy_test - only: - refs: - - master - - schedules - variables: - - $DEPLOY_TEST_RESULT_TO_JIRA == "Yes" - dependencies: - - build_esp_idf_tests_make - - build_esp_idf_tests_cmake - artifacts: - when: always - paths: - - ${CI_PROJECT_DIR}/test-management/*.log - expire_in: 1 week - variables: - UNIT_TEST_CASE_FILE: "${CI_PROJECT_DIR}/components/idf_test/unit_test/TestCaseAll.yml" - BOT_ACCOUNT_CONFIG_FILE: "${CI_PROJECT_DIR}/test-management/Config/Account.local.yml" - TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw" - AUTO_TEST_SCRIPT_PATH: "${CI_PROJECT_DIR}/auto_test_script" - PYTHON_VER: 3 - script: - - export GIT_SHA=$(echo ${CI_COMMIT_SHA} | cut -c 1-8) - - git clone $TEST_MANAGEMENT_REPO - - python $CHECKOUT_REF_SCRIPT test-management test-management - - cd test-management - - echo $BOT_JIRA_ACCOUNT > ${BOT_ACCOUNT_CONFIG_FILE} - # update unit test cases - - python ImportTestCase.py $JIRA_TEST_MANAGEMENT_PROJECT unity -d $UNIT_TEST_CASE_FILE -r $GIT_SHA - # update example test cases - - python ImportTestCase.py $JIRA_TEST_MANAGEMENT_PROJECT tiny_test_fw -d ${CI_PROJECT_DIR}/examples -r $GIT_SHA - # organize test cases - - python OrganizeTestCases.py $JIRA_TEST_MANAGEMENT_PROJECT - -deploy_test_result: - stage: deploy - image: $CI_DOCKER_REGISTRY/bot-env - tags: - - deploy_test - when: always - only: - refs: - - master - - schedules - variables: - - $DEPLOY_TEST_RESULT_TO_JIRA == "Yes" - artifacts: - when: always - paths: - - ${CI_PROJECT_DIR}/test-management/*.log - # save all test logs as artifacts, make it easier to track errors - - ${CI_PROJECT_DIR}/TEST_LOGS - - $CI_PROJECT_DIR/$CI_COMMIT_SHA - expire_in: 1 mos - variables: - UNIT_TEST_CASE_FILE: "${CI_PROJECT_DIR}/components/idf_test/unit_test/TestCaseAll.yml" - BOT_ACCOUNT_CONFIG_FILE: "${CI_PROJECT_DIR}/test-management/Config/Account.local.yml" - TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw" - AUTO_TEST_SCRIPT_PATH: "${CI_PROJECT_DIR}/auto_test_script" - before_script: - - mkdir -p ~/.ssh - - chmod 700 ~/.ssh - - echo -n $GITLAB_KEY > ~/.ssh/id_rsa_base64 - - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa - - chmod 600 ~/.ssh/id_rsa - - echo -e "Host gitlab.espressif.cn\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config - script: - - export GIT_SHA=$(echo ${CI_COMMIT_SHA} | cut -c 1-8) - - export REV_COUNT=$(git rev-list --count HEAD) - - export SUMMARY="IDF CI test result for $GIT_SHA (r${REV_COUNT})" - # artifacts of job update_test_cases creates test-management folder - # we need to remove it so we can clone test-management folder again - - rm -r test-management - - git clone $TEST_MANAGEMENT_REPO - - python3 $CHECKOUT_REF_SCRIPT test-management test-management - - cd test-management - - echo $BOT_JIRA_ACCOUNT > ${BOT_ACCOUNT_CONFIG_FILE} - # update test results - - python3 ImportTestResult.py -r "$GIT_SHA (r${REV_COUNT})" -j $JIRA_TEST_MANAGEMENT_PROJECT -s "$SUMMARY" -l CI -p ${CI_PROJECT_DIR}/TEST_LOGS ${CI_PROJECT_DIR}/${CI_COMMIT_SHA} --pipeline_url ${CI_PIPELINE_URL} - -check_doc_links: - stage: host_test - image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG - tags: - - check_doc_links - only: - refs: - # can only be triggered - - triggers - variables: - - $BOT_TRIGGER_WITH_LABEL == null - - $BOT_LABEL_BUILD_DOCS - artifacts: - paths: - - docs/_build/linkcheck - expire_in: 1 week - script: - # must be triggered with CHECK_LINKS=Yes, otherwise exit without test - - test "$CHECK_LINKS" = "Yes" || exit 0 - # can only run on master branch (otherwise the commit is not on Github yet) - - test "${CI_COMMIT_REF_NAME}" = "master" || exit 0 - - cd docs - - make linkcheck - -check_line_endings: - <<: *check_job_template - script: - - tools/ci/check-line-endings.sh ${IDF_PATH} - -check_commit_msg: - <<: *check_job_template - script: - - git status - - git log -n10 --oneline - # commit start with "WIP: " need to be squashed before merge - - 'git log --pretty=%s master.. -- | grep "^WIP: " && exit 1 || exit 0' - -check_permissions: - <<: *check_job_template - script: - - tools/ci/check-executable.sh - -check_version: - <<: *check_job_template - # Don't run this for feature/bugfix branches, so that it is possible to modify - # esp_idf_version.h in a branch before tagging the next version. - only: - - master - - /^release\/v/ - - /^v\d+\.\d+(\.\d+)?($|-)/ - script: - - export IDF_PATH=$PWD - - tools/ci/check_idf_version.sh - -check_examples_cmake_make: - <<: *check_job_template - except: - - master - - /^release\/v/ - - /^v\d+\.\d+(\.\d+)?($|-)/ - <<: *before_script_lesser - script: - - tools/ci/check_examples_cmake_make.sh - -check_python_style: - <<: *check_job_template - artifacts: - when: on_failure - paths: - - flake8_output.txt - expire_in: 1 week - <<: *before_script_lesser - script: - # run it only under Python 3 (it is very slow under Python 2) - - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh -p 3.4.8 python -m flake8 --config=$IDF_PATH/.flake8 --output-file=flake8_output.txt --tee --benchmark $IDF_PATH - -check_kconfigs: - <<: *check_job_template - artifacts: - when: on_failure - paths: - - components/*/Kconfig*.new - - examples/*/*/*/Kconfig*.new - - examples/*/*/*/*/Kconfig*.new - - tools/*/Kconfig*.new - - tools/*/*/Kconfig*.new - - tools/*/*/*/Kconfig*.new - expire_in: 1 week - <<: *before_script_lesser - script: - - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ${IDF_PATH}/tools/test_check_kconfigs.py - - ${IDF_PATH}/tools/check_kconfigs.py - -check_ut_cmake_make: +.check_job_template_with_filter: stage: check image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG tags: - - build - except: - - master - - /^release\/v/ - - /^v\d+\.\d+(\.\d+)?($|-)/ + - host_test dependencies: [] - <<: *before_script_lesser - script: - - tools/ci/check_ut_cmake_make.sh - -check_submodule_sync: - <<: *check_job_template - tags: - - github_sync - retry: 2 - variables: - GIT_STRATEGY: clone - GIT_SUBMODULE_STRATEGY: none - PUBLIC_IDF_URL: "https://github.com/espressif/esp-idf.git" - before_script: [] - after_script: [] - script: - - git submodule deinit --force . - # setting the default remote URL to the public one, to resolve relative location URLs - - git config remote.origin.url ${PUBLIC_IDF_URL} - # check if all submodules are correctly synced to public repostory - - git submodule init - - *show_submodule_urls - - git submodule update --recursive - - echo "IDF was cloned from ${PUBLIC_IDF_URL} completely" - -check_artifacts_expire_time: - <<: *check_job_template - script: - # check if we have set expire time for all artifacts - - python tools/ci/check_artifacts_expire_time.py - -check_pipeline_triggered_by_label: - <<: *check_job_template - stage: post_check - only: - variables: - - $BOT_TRIGGER_WITH_LABEL - script: - # If the pipeline is triggered with label, the pipeline will only succeeded if "regular_test" label is added. - # We want to make sure some jobs are always executed to detect regression. - - test "$BOT_LABEL_REGULAR_TEST" = "true" || { echo "CI can only pass if 'regular_test' label is included"; exit -1; } - -assign_test: - tags: - - assign_test - image: $CI_DOCKER_REGISTRY/ubuntu-test-env$BOT_DOCKER_IMAGE_TAG - stage: assign_test - # gitlab ci do not support match job with RegEx or wildcard now in dependencies. - # we have a lot build example jobs. now we don't use dependencies, just download all artificats of build stage. - dependencies: - - build_ssc - - build_esp_idf_tests_make - - build_esp_idf_tests_cmake - variables: - TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw" - EXAMPLE_CONFIG_OUTPUT_PATH: "$CI_PROJECT_DIR/examples/test_configs" - artifacts: - paths: - - components/idf_test/*/CIConfigs - - components/idf_test/*/TC.sqlite - - $EXAMPLE_CONFIG_OUTPUT_PATH - expire_in: 1 week - only: - variables: - - $BOT_TRIGGER_WITH_LABEL == null - - $BOT_LABEL_UNIT_TEST - - $BOT_LABEL_INTEGRATION_TEST - - $BOT_LABEL_EXAMPLE_TEST - script: - # assign example tests - - python $TEST_FW_PATH/CIAssignExampleTest.py $IDF_PATH/examples $IDF_PATH/.gitlab-ci.yml $EXAMPLE_CONFIG_OUTPUT_PATH - # assign unit test cases - - python $TEST_FW_PATH/CIAssignUnitTest.py $IDF_PATH/components/idf_test/unit_test/TestCaseAll.yml $IDF_PATH/.gitlab-ci.yml $IDF_PATH/components/idf_test/unit_test/CIConfigs - # clone test script to assign tests - - git clone $TEST_SCRIPT_REPOSITORY - - python $CHECKOUT_REF_SCRIPT auto_test_script auto_test_script - - cd auto_test_script - # assgin integration test cases - - python CIAssignTestCases.py -t $IDF_PATH/components/idf_test/integration_test -c $IDF_PATH/.gitlab-ci.yml -b $IDF_PATH/SSC/ssc_bin - -.example_test_template: &example_test_template - stage: target_test - when: on_success - only: - refs: - - master - - /^release\/v/ - - /^v\d+\.\d+(\.\d+)?($|-)/ - - triggers - - schedules - variables: - - $BOT_TRIGGER_WITH_LABEL == null - - $BOT_LABEL_EXAMPLE_TEST - dependencies: - - assign_test - - build_examples_make - - build_examples_cmake - artifacts: - when: always - paths: - - $LOG_PATH - expire_in: 1 week - reports: - junit: $LOG_PATH/*/XUNIT_RESULT.xml - variables: - TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw" - TEST_CASE_PATH: "$CI_PROJECT_DIR/examples" - CONFIG_FILE: "$CI_PROJECT_DIR/examples/test_configs/$CI_JOB_NAME_$CI_NODE_INDEX.yml" - LOG_PATH: "$CI_PROJECT_DIR/TEST_LOGS" - ENV_FILE: "$CI_PROJECT_DIR/ci-test-runner-configs/$CI_RUNNER_DESCRIPTION/EnvConfig.yml" - script: - # first test if config file exists, if not exist, exit 0 - - test -e $CONFIG_FILE || exit 0 - # clone test env configs - - git clone $TEST_ENV_CONFIG_REPOSITORY - - python $CHECKOUT_REF_SCRIPT ci-test-runner-configs ci-test-runner-configs - - cd $TEST_FW_PATH - # run test - - python Runner.py $TEST_CASE_PATH -c $CONFIG_FILE -e $ENV_FILE - -.unit_test_template: &unit_test_template - <<: *example_test_template - stage: target_test - dependencies: - - assign_test - - build_esp_idf_tests_make - - build_esp_idf_tests_cmake - only: - refs: - - master - - /^release\/v/ - - /^v\d+\.\d+(\.\d+)?($|-)/ - - triggers - - schedules - variables: - - $BOT_TRIGGER_WITH_LABEL == null - - $BOT_LABEL_UNIT_TEST - variables: - TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw" - TEST_CASE_PATH: "$CI_PROJECT_DIR/tools/unit-test-app" - CONFIG_FILE: "$CI_PROJECT_DIR/components/idf_test/unit_test/CIConfigs/$CI_JOB_NAME_$CI_NODE_INDEX.yml" - LOG_PATH: "$CI_PROJECT_DIR/TEST_LOGS" - ENV_FILE: "$CI_PROJECT_DIR/ci-test-runner-configs/$CI_RUNNER_DESCRIPTION/EnvConfig.yml" - -test_weekend_mqtt: - <<: *example_test_template - stage: target_test - tags: - - ESP32 - - Example_WIFI - only: - variables: - - $BOT_LABEL_WEEKEND_TEST - variables: - TEST_CASE_PATH: "$CI_PROJECT_DIR/components/mqtt/weekend_test" - TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw" - LOG_PATH: "$CI_PROJECT_DIR/TEST_LOGS" - ENV_FILE: "$CI_PROJECT_DIR/components/mqtt/weekend_test/env.yml" - CONFIG_FILE: "$CI_PROJECT_DIR/components/mqtt/weekend_test/config.yml" - -test_weekend_network: - <<: *example_test_template - stage: target_test - image: $CI_DOCKER_REGISTRY/rpi-net-suite$BOT_DOCKER_IMAGE_TAG - tags: - - ESP32 - - Example_WIFI - only: - variables: - - $BOT_LABEL_WEEKEND_TEST - variables: - TEST_CASE_PATH: "$CI_PROJECT_DIR/components/lwip/weekend_test" - TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw" - LOG_PATH: "$CI_PROJECT_DIR/TEST_LOGS" - ENV_FILE: "$CI_PROJECT_DIR/components/lwip/weekend_test/env.yml" - CONFIG_FILE: "$CI_PROJECT_DIR/components/lwip/weekend_test/config.yml" - -.test_template: &test_template - stage: target_test - when: on_success - only: - refs: - - master - - /^release\/v/ - - /^v\d+\.\d+(\.\d+)?($|-)/ - - triggers - - schedules - variables: - - $BOT_TRIGGER_WITH_LABEL == null - - $BOT_LABEL_INTEGRATION_TEST - dependencies: - - assign_test - - build_ssc - artifacts: - when: always - reports: - junit: $LOG_PATH/*/XUNIT_RESULT.xml - paths: - - $LOG_PATH - expire_in: 1 week - variables: - GIT_SUBMODULE_STRATEGY: none - LOCAL_ENV_CONFIG_PATH: "$CI_PROJECT_DIR/ci-test-runner-configs/$CI_RUNNER_DESCRIPTION/ESP32_IDF" - LOG_PATH: "$CI_PROJECT_DIR/$CI_COMMIT_SHA" - TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/components/idf_test/integration_test" - MODULE_UPDATE_FILE: "$CI_PROJECT_DIR/components/idf_test/ModuleDefinition.yml" - CONFIG_FILE: "$CI_PROJECT_DIR/components/idf_test/integration_test/CIConfigs/$CI_JOB_NAME_$CI_NODE_INDEX.yml" - script: - # first test if config file exists, if not exist, exit 0 - - test -e $CONFIG_FILE || exit 0 - # clone local test env configs - - git clone $TEST_ENV_CONFIG_REPOSITORY - - python $CHECKOUT_REF_SCRIPT ci-test-runner-configs ci-test-runner-configs - # clone test bench - - git clone $TEST_SCRIPT_REPOSITORY - - python $CHECKOUT_REF_SCRIPT auto_test_script auto_test_script - - cd auto_test_script - # run test - - python CIRunner.py -l "$LOG_PATH/$CI_JOB_NAME_$CI_NODE_INDEX" -c $CONFIG_FILE -e $LOCAL_ENV_CONFIG_PATH -t $TEST_CASE_FILE_PATH -m $MODULE_UPDATE_FILE - -nvs_compatible_test: - <<: *test_template - artifacts: - when: always - paths: - - $LOG_PATH - - nvs_wifi.bin - expire_in: 1 mos - tags: - - ESP32_IDF - - NVS_Compatible - script: - # clone local test env configs - - git clone $TEST_ENV_CONFIG_REPOSITORY - - python $CHECKOUT_REF_SCRIPT ci-test-runner-configs ci-test-runner-configs - # clone test bench - - git clone $TEST_SCRIPT_REPOSITORY - - python $CHECKOUT_REF_SCRIPT auto_test_script auto_test_script - - cd auto_test_script - # prepare nvs bins - - ./Tools/prepare_nvs_bin.sh - # run test - - python CIRunner.py -l "$LOG_PATH/$CI_JOB_NAME" -c $CONFIG_FILE -e $LOCAL_ENV_CONFIG_PATH -t $TEST_CASE_FILE_PATH -m $MODULE_UPDATE_FILE - -example_test_001: - <<: *example_test_template - parallel: 2 - tags: - - ESP32 - - Example_WIFI - -example_test_002: - <<: *example_test_template - image: $CI_DOCKER_REGISTRY/ubuntu-test-env$BOT_DOCKER_IMAGE_TAG - tags: - - ESP32 - - Example_ShieldBox_Basic - -.example_test_003: - <<: *example_test_template - tags: - - ESP32 - - Example_SDIO - -example_test_004: - <<: *example_test_template - tags: - - ESP32 - - Example_CAN - -example_test_005: - <<: *example_test_template - tags: - - ESP32 - - Example_WIFI_BT - -example_test_006: - <<: *example_test_template - image: $CI_DOCKER_REGISTRY/ubuntu-test-env$BOT_DOCKER_IMAGE_TAG - only: - variables: - - $BOT_LABEL_IPERF_STRESS_TEST - tags: - - ESP32 - - Example_ShieldBox - -example_test_007: - <<: *example_test_template - tags: - - ESP32 - - Example_I2C_CCS811_SENSOR - -UT_001: - <<: *unit_test_template - parallel: 50 - tags: - - ESP32_IDF - - UT_T1_1 - -UT_002: - <<: *unit_test_template - parallel: 18 - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_003: - <<: *unit_test_template - parallel: 3 - tags: - - ESP32_IDF - - UT_T1_SDMODE - -UT_004: - <<: *unit_test_template - parallel: 3 - tags: - - ESP32_IDF - - UT_T1_SPIMODE - -UT_005: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_SDMODE - - psram - -UT_006: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_SPIMODE - - psram - -UT_007: - <<: *unit_test_template - parallel: 4 - tags: - - ESP32_IDF - - UT_T1_GPIO - -UT_008: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_GPIO - - psram - -UT_009: - <<: *unit_test_template - parallel: 4 - tags: - - ESP32_IDF - - UT_T1_PCNT - -UT_010: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_PCNT - - psram - -UT_011: - <<: *unit_test_template - parallel: 4 - tags: - - ESP32_IDF - - UT_T1_LEDC - -UT_012: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_LEDC - - psram - -UT_013: - <<: *unit_test_template - parallel: 4 - tags: - - ESP32_IDF - - UT_T2_RS485 - -UT_014: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T2_RS485 - - psram - -UT_015: - <<: *unit_test_template - parallel: 4 - tags: - - ESP32_IDF - - UT_T1_RMT - -UT_016: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_RMT - - psram - -UT_017: - <<: *unit_test_template - parallel: 3 - tags: - - ESP32_IDF - - EMMC - -UT_018: - <<: *unit_test_template - parallel: 5 - tags: - - ESP32_IDF - - UT_T1_1 - - 8Mpsram - -UT_019: - <<: *unit_test_template - parallel: 4 - tags: - - ESP32_IDF - - Example_SPI_Multi_device - -UT_020: - <<: *unit_test_template - tags: - - ESP32_IDF - - Example_SPI_Multi_device - - psram - -UT_021: - <<: *unit_test_template - parallel: 4 - tags: - - ESP32_IDF - - UT_T2_I2C - -UT_022: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T2_I2C - - psram - -UT_023: - <<: *unit_test_template - parallel: 4 - tags: - - ESP32_IDF - - UT_T1_MCPWM - -UT_024: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_MCPWM - - psram - -UT_025: - <<: *unit_test_template - parallel: 4 - tags: - - ESP32_IDF - - UT_T1_I2S - -UT_026: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_I2S - - psram - -UT_027: - <<: *unit_test_template - parallel: 3 - tags: - - ESP32_IDF - - UT_T2_1 - -UT_028: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T2_1 - - psram - -UT_029: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T2_1 - - 8Mpsram - -UT_030: - <<: *unit_test_template - parallel: 5 - tags: - - ESP32_IDF - - UT_T1_1 - -IT_001: - <<: *test_template - parallel: 3 - tags: - - ESP32_IDF - - SSC_T1_4 - -IT_002: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_2 - -IT_003: - <<: *test_template - parallel: 13 - tags: - - ESP32_IDF - - SSC_T2_5 - -IT_004: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_APC - -IT_005: - <<: *test_template - parallel: 2 - tags: - - ESP32_IDF - - SSC_T1_5 - -IT_006: - <<: *test_template - parallel: 8 - tags: - - ESP32_IDF - - SSC_T1_6 - -IT_007: - <<: *test_template - parallel: 3 - tags: - - ESP32_IDF - - SSC_T1_7 - -IT_008: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_8 - -IT_009: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_3 - -IT_010: - <<: *test_template - parallel: 4 - tags: - - ESP32_IDF - - SSC_T5_1 - -IT_011: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_MESH1 - -IT_012: - <<: *test_template - parallel: 2 - tags: - - ESP32_IDF - - SSC_T2_MESH1 - -IT_013: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T3_MESH1 - -IT_014: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T6_MESH1 - -IT_015: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T12_MESH1 - -IT_016: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T50_MESH1 - -IT_017: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_MESH2 - -IT_018: - <<: *test_template - parallel: 2 - tags: - - ESP32_IDF - - SSC_T1_9 - -IT_019: - <<: *test_template - parallel: 2 - tags: - - ESP32_IDF - - SSC_T2_2 - -IT_020: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_3 - -IT_021: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_4 + extends: .before_script_lesser_nofilter + +include: + - '/tools/ci/config/build.yml' + - '/tools/ci/config/assign-test.yml' + - '/tools/ci/config/host-test.yml' + - '/tools/ci/config/target-test.yml' + - '/tools/ci/config/check.yml' + - '/tools/ci/config/deploy.yml' diff --git a/tools/ci/config/assign-test.yml b/tools/ci/config/assign-test.yml new file mode 100644 index 0000000000..92dc8cad2c --- /dev/null +++ b/tools/ci/config/assign-test.yml @@ -0,0 +1,74 @@ + +assign_test: + tags: + - assign_test + image: $CI_DOCKER_REGISTRY/ubuntu-test-env$BOT_DOCKER_IMAGE_TAG + stage: assign_test + # gitlab ci do not support match job with RegEx or wildcard now in dependencies. + # we have a lot build example jobs. now we don't use dependencies, just download all artificats of build stage. + dependencies: + - build_ssc + - build_esp_idf_tests_make + - build_esp_idf_tests_cmake + variables: + TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw" + EXAMPLE_CONFIG_OUTPUT_PATH: "$CI_PROJECT_DIR/examples/test_configs" + artifacts: + paths: + - components/idf_test/*/CIConfigs + - components/idf_test/*/TC.sqlite + - $EXAMPLE_CONFIG_OUTPUT_PATH + expire_in: 1 week + only: + variables: + - $BOT_TRIGGER_WITH_LABEL == null + - $BOT_LABEL_UNIT_TEST + - $BOT_LABEL_INTEGRATION_TEST + - $BOT_LABEL_EXAMPLE_TEST + script: + # assign example tests + - python $TEST_FW_PATH/CIAssignExampleTest.py $IDF_PATH/examples $CI_TARGET_TEST_CONFIG_FILE $EXAMPLE_CONFIG_OUTPUT_PATH + # assign unit test cases + - python $TEST_FW_PATH/CIAssignUnitTest.py $IDF_PATH/components/idf_test/unit_test/TestCaseAll.yml $CI_TARGET_TEST_CONFIG_FILE $IDF_PATH/components/idf_test/unit_test/CIConfigs + # clone test script to assign tests + - git clone $TEST_SCRIPT_REPOSITORY + - python $CHECKOUT_REF_SCRIPT auto_test_script auto_test_script + - cd auto_test_script + # assgin integration test cases + - python CIAssignTestCases.py -t $IDF_PATH/components/idf_test/integration_test -c $CI_TARGET_TEST_CONFIG_FILE -b $IDF_PATH/SSC/ssc_bin + +update_test_cases: + stage: assign_test + image: $CI_DOCKER_REGISTRY/ubuntu-test-env + tags: + - deploy_test + only: + refs: + - master + - schedules + dependencies: + - build_esp_idf_tests_make + - build_esp_idf_tests_cmake + artifacts: + when: always + paths: + - ${CI_PROJECT_DIR}/test-management/*.log + expire_in: 1 week + variables: + UNIT_TEST_CASE_FILE: "${CI_PROJECT_DIR}/components/idf_test/unit_test/TestCaseAll.yml" + BOT_ACCOUNT_CONFIG_FILE: "${CI_PROJECT_DIR}/test-management/Config/Account.local.yml" + TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw" + AUTO_TEST_SCRIPT_PATH: "${CI_PROJECT_DIR}/auto_test_script" + PYTHON_VER: 3 + script: + - export GIT_SHA=$(echo ${CI_COMMIT_SHA} | cut -c 1-8) + - git clone $TEST_MANAGEMENT_REPO + - python $CHECKOUT_REF_SCRIPT test-management test-management + - cd test-management + - echo $BOT_JIRA_ACCOUNT > ${BOT_ACCOUNT_CONFIG_FILE} + # update unit test cases + - python ImportTestCase.py $JIRA_TEST_MANAGEMENT_PROJECT unity -d $UNIT_TEST_CASE_FILE -r $GIT_SHA + # update example test cases + - python ImportTestCase.py $JIRA_TEST_MANAGEMENT_PROJECT tiny_test_fw -d ${CI_PROJECT_DIR}/examples -r $GIT_SHA + # organize test cases + - python OrganizeTestCases.py $JIRA_TEST_MANAGEMENT_PROJECT diff --git a/tools/ci/config/build.yml b/tools/ci/config/build.yml new file mode 100644 index 0000000000..1eb151c054 --- /dev/null +++ b/tools/ci/config/build.yml @@ -0,0 +1,247 @@ + +.build_template: + stage: build + image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG + tags: + - build + variables: + BATCH_BUILD: "1" + V: "0" + +.build_esp_idf_unit_test_template: + extends: .build_template + artifacts: + paths: + - tools/unit-test-app/output + - components/idf_test/unit_test/TestCaseAll.yml + expire_in: 3 days + only: + variables: + - $BOT_TRIGGER_WITH_LABEL == null + - $BOT_LABEL_BUILD + - $BOT_LABEL_UNIT_TEST + - $BOT_LABEL_REGULAR_TEST + +build_template_app: + stage: build + image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG + tags: + - build + variables: + BATCH_BUILD: "1" + only: + variables: + - $BOT_TRIGGER_WITH_LABEL == null + - $BOT_LABEL_BUILD + - $BOT_LABEL_REGULAR_TEST + script: + # Set the variable for 'esp-idf-template' testing + - ESP_IDF_TEMPLATE_GIT=${ESP_IDF_TEMPLATE_GIT:-"https://github.com/espressif/esp-idf-template.git"} + - git clone ${ESP_IDF_TEMPLATE_GIT} + - python $CHECKOUT_REF_SCRIPT esp-idf-template esp-idf-template + - cd esp-idf-template + # Try to use the same branch name for esp-idf-template that we're + # using on esp-idf. If it doesn't exist then just stick to the default + # branch + - make defconfig + # Test debug build (default) + - make all V=1 + # Now test release build + - make clean + - sed -i.bak -e's/CONFIG_OPTIMIZATION_LEVEL_DEBUG\=y/CONFIG_OPTIMIZATION_LEVEL_RELEASE=y/' sdkconfig + - make all V=1 + # Check if there are any stray printf/ets_printf references in WiFi libs + - cd ../components/esp_wifi/lib_esp32 + - test $(xtensa-esp32-elf-nm *.a | grep -w printf | wc -l) -eq 0 + - test $(xtensa-esp32-elf-nm *.a | grep -w ets_printf | wc -l) -eq 0 + + +build_ssc: + extends: .build_template + parallel: 3 + artifacts: + paths: + - SSC/ssc_bin + expire_in: 1 week + variables: + SSC_CONFIG_FOLDER: "$CI_PROJECT_DIR/SSC/configs/ESP32_IDF" + only: + variables: + - $BOT_TRIGGER_WITH_LABEL == null + - $BOT_LABEL_BUILD + - $BOT_LABEL_INTEGRATION_TEST + - $BOT_LABEL_REGULAR_TEST + script: + - git clone $SSC_REPOSITORY + - python $CHECKOUT_REF_SCRIPT SSC SSC + - cd SSC + - MAKEFLAGS= ./ci_build_ssc.sh + +build_esp_idf_tests_make: + extends: .build_esp_idf_unit_test_template + script: + - export EXTRA_CFLAGS=${PEDANTIC_CFLAGS} + - export EXTRA_CXXFLAGS=${EXTRA_CFLAGS} + - cd $CI_PROJECT_DIR/tools/unit-test-app + - MAKEFLAGS= make help # make sure kconfig tools are built in single process + - make ut-clean-all-configs + - make ut-build-all-configs + - python tools/UnitTestParser.py + # Check if the tests demand Make built binaries. If not, delete them + - if [ "$UNIT_TEST_BUILD_SYSTEM" == "make" ]; then exit 0; fi + - rm -rf builds output sdkconfig + - rm $CI_PROJECT_DIR/components/idf_test/unit_test/TestCaseAll.yml + +build_esp_idf_tests_cmake: + extends: .build_esp_idf_unit_test_template + script: + - export PATH="$IDF_PATH/tools:$PATH" + - export EXTRA_CFLAGS=${PEDANTIC_CFLAGS} + - export EXTRA_CXXFLAGS=${EXTRA_CFLAGS} + - cd $CI_PROJECT_DIR/tools/unit-test-app + - idf.py ut-clean-all-configs + - idf.py ut-build-all-configs + - python tools/UnitTestParser.py + # Check if the tests demand CMake built binaries. If not, delete them + - if [ "$UNIT_TEST_BUILD_SYSTEM" == "cmake" ]; then exit 0; fi + - rm -rf builds output sdkconfig + - rm $CI_PROJECT_DIR/components/idf_test/unit_test/TestCaseAll.yml + +build_examples_make: + extends: .build_template + parallel: 8 + # This is a workaround for a rarely encountered issue with building examples in CI. + # Probably related to building of Kconfig in 'make clean' stage + retry: 1 + artifacts: + when: always + paths: + - build_examples/*/*/*/build/*.bin + - build_examples/*/*/*/sdkconfig + - build_examples/*/*/*/build/*.elf + - build_examples/*/*/*/build/*.map + - build_examples/*/*/*/build/download.config + - build_examples/*/*/*/build/bootloader/*.bin + - $LOG_PATH + expire_in: 3 days + variables: + LOG_PATH: "$CI_PROJECT_DIR/log_examples_make" + only: + variables: + - $BOT_TRIGGER_WITH_LABEL == null + - $BOT_LABEL_BUILD + - $BOT_LABEL_EXAMPLE_TEST + - $BOT_LABEL_REGULAR_TEST + - $BOT_LABEL_WEEKEND_TEST + script: + # it's not possible to build 100% out-of-tree and have the "artifacts" + # mechanism work, but this is the next best thing + - rm -rf build_examples + - mkdir build_examples + - cd build_examples + # build some of examples + - mkdir -p ${LOG_PATH} + - ${IDF_PATH}/tools/ci/build_examples.sh + +# same as above, but for CMake +build_examples_cmake: + extends: .build_template + parallel: 5 + artifacts: + when: always + paths: + - build_examples_cmake/*/*/*/build/*.bin + - build_examples_cmake/*/*/*/sdkconfig + - build_examples_cmake/*/*/*/build/*.elf + - build_examples_cmake/*/*/*/build/*.map + - build_examples_cmake/*/*/*/build/flasher_args.json + - build_examples_cmake/*/*/*/build/bootloader/*.bin + - $LOG_PATH + expire_in: 3 days + variables: + LOG_PATH: "$CI_PROJECT_DIR/log_examples_cmake" + only: + variables: + - $BOT_TRIGGER_WITH_LABEL == null + - $BOT_LABEL_BUILD + - $BOT_LABEL_EXAMPLE_TEST + - $BOT_LABEL_REGULAR_TEST + - $BOT_LABEL_WEEKEND_TEST + script: + # it's not possible to build 100% out-of-tree and have the "artifacts" + # mechanism work, but this is the next best thing + - rm -rf build_examples_cmake + - mkdir build_examples_cmake + - cd build_examples_cmake + # build some of examples + - mkdir -p ${LOG_PATH} + - ${IDF_PATH}/tools/ci/build_examples_cmake.sh + +# If you want to add new build example jobs, please add it into dependencies of `.example_test_template` + +build_docs: + stage: build + image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG + tags: + - build_docs + artifacts: + when: always + paths: + # English version of documentation + - docs/en/doxygen-warning-log.txt + - docs/en/sphinx-warning-log.txt + - docs/en/sphinx-warning-log-sanitized.txt + - docs/en/_build/html + - docs/sphinx-err-* + # Chinese version of documentation + - docs/zh_CN/doxygen-warning-log.txt + - docs/zh_CN/sphinx-warning-log.txt + - docs/zh_CN/sphinx-warning-log-sanitized.txt + - docs/zh_CN/_build/html + expire_in: 3 days + only: + variables: + - $BOT_TRIGGER_WITH_LABEL == null + - $BOT_LABEL_BUILD + - $BOT_LABEL_BUILD_DOCS + - $BOT_LABEL_REGULAR_TEST + script: + - cd docs + - ./check_lang_folder_sync.sh + - cd en + - make gh-linkcheck + - make html + - ../check_doc_warnings.sh + - cd ../zh_CN + - make gh-linkcheck + - make html + - ../check_doc_warnings.sh + +verify_cmake_style: + extends: .check_job_template + stage: build + only: + variables: + - $BOT_TRIGGER_WITH_LABEL == null + - $BOT_LABEL_BUILD + - $BOT_LABEL_REGULAR_TEST + script: + tools/cmake/run_cmake_lint.sh + +test_build_system: + extends: .build_template + script: + - ${IDF_PATH}/tools/ci/test_configure_ci_environment.sh + - rm -rf test_build_system + - mkdir test_build_system + - cd test_build_system + - ${IDF_PATH}/tools/ci/test_build_system.sh + +test_build_system_cmake: + extends: .build_template + script: + - ${IDF_PATH}/tools/ci/test_configure_ci_environment.sh + - rm -rf test_build_system + - mkdir test_build_system + - cd test_build_system + - ${IDF_PATH}/tools/ci/test_build_system_cmake.sh diff --git a/tools/ci/config/check.yml b/tools/ci/config/check.yml new file mode 100644 index 0000000000..ad4f71290c --- /dev/null +++ b/tools/ci/config/check.yml @@ -0,0 +1,122 @@ + +# copy from .gitlab-ci.yml as anchor is not global +.show_submodule_urls: &show_submodule_urls | + git config --get-regexp '^submodule\..*\.url$' || true + +check_line_endings: + extends: .check_job_template + script: + - tools/ci/check-line-endings.sh ${IDF_PATH} + +check_commit_msg: + extends: .check_job_template + script: + - git status + - git log -n10 --oneline + # commit start with "WIP: " need to be squashed before merge + - 'git log --pretty=%s master.. -- | grep "^WIP: " && exit 1 || exit 0' + +check_permissions: + extends: .check_job_template + script: + - tools/ci/check-executable.sh + +check_version: + extends: .check_job_template + # Don't run this for feature/bugfix branches, so that it is possible to modify + # esp_idf_version.h in a branch before tagging the next version. + only: + - master + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ + script: + - export IDF_PATH=$PWD + - tools/ci/check_idf_version.sh + +check_examples_cmake_make: + extends: .check_job_template_with_filter + except: + - master + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ + script: + - tools/ci/check_examples_cmake_make.sh + +check_python_style: + extends: .check_job_template_with_filter + artifacts: + when: on_failure + paths: + - flake8_output.txt + expire_in: 1 week + script: + # run it only under Python 3 (it is very slow under Python 2) + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh -p 3.4.8 python -m flake8 --config=$IDF_PATH/.flake8 --output-file=flake8_output.txt --tee --benchmark $IDF_PATH + +check_kconfigs: + extends: .check_job_template_with_filter + artifacts: + when: on_failure + paths: + - components/*/Kconfig*.new + - examples/*/*/*/Kconfig*.new + - examples/*/*/*/*/Kconfig*.new + - tools/*/Kconfig*.new + - tools/*/*/Kconfig*.new + - tools/*/*/*/Kconfig*.new + expire_in: 1 week + script: + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ${IDF_PATH}/tools/test_check_kconfigs.py + - ${IDF_PATH}/tools/check_kconfigs.py + +check_ut_cmake_make: + extends: .check_job_template_with_filter + stage: check + image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG + tags: + - build + except: + - master + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ + dependencies: [] + script: + - tools/ci/check_ut_cmake_make.sh + +check_submodule_sync: + extends: .check_job_template + tags: + - github_sync + retry: 2 + variables: + GIT_STRATEGY: clone + GIT_SUBMODULE_STRATEGY: none + PUBLIC_IDF_URL: "https://github.com/espressif/esp-idf.git" + before_script: [] + after_script: [] + script: + - git submodule deinit --force . + # setting the default remote URL to the public one, to resolve relative location URLs + - git config remote.origin.url ${PUBLIC_IDF_URL} + # check if all submodules are correctly synced to public repostory + - git submodule init + - *show_submodule_urls + - git submodule update --recursive + - echo "IDF was cloned from ${PUBLIC_IDF_URL} completely" + +check_artifacts_expire_time: + extends: .check_job_template + script: + # check if we have set expire time for all artifacts + - python tools/ci/check_artifacts_expire_time.py + +check_pipeline_triggered_by_label: + extends: .check_job_template + stage: post_check + only: + variables: + - $BOT_TRIGGER_WITH_LABEL + script: + # If the pipeline is triggered with label, the pipeline will only succeeded if "regular_test" label is added. + # We want to make sure some jobs are always executed to detect regression. + - test "$BOT_LABEL_REGULAR_TEST" = "true" || { echo "CI can only pass if 'regular_test' label is included"; exit -1; } diff --git a/tools/ci/config/deploy.yml b/tools/ci/config/deploy.yml new file mode 100644 index 0000000000..5a057a9e68 --- /dev/null +++ b/tools/ci/config/deploy.yml @@ -0,0 +1,153 @@ + +.clang_tidy_deploy_template: + stage: deploy + image: $CI_DOCKER_REGISTRY/esp32-ci-env + tags: + - deploy + script: + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - echo -n $DOCS_DEPLOY_KEY > ~/.ssh/id_rsa_base64 + - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa + - chmod 600 ~/.ssh/id_rsa + - echo -e "Host $DOCS_SERVER\n\tStrictHostKeyChecking no\n\tUser $DOCS_SERVER_USER\n" >> ~/.ssh/config + - export GIT_VER=$(git describe --always) + - cd $IDF_PATH/examples/get-started/hello_world/tidybuild + - mv report $GIT_VER + - tar czvf $GIT_VER.tar.gz $GIT_VER + - export STATIC_REPORT_PATH="web/static_analysis/esp-idf/" + - ssh $DOCS_SERVER -x "mkdir -p $STATIC_REPORT_PATH/clang-tidy" + - scp $GIT_VER.tar.gz $DOCS_SERVER:$STATIC_REPORT_PATH/clang-tidy + - ssh $DOCS_SERVER -x "cd $STATIC_REPORT_PATH/clang-tidy && tar xzvf $GIT_VER.tar.gz && rm -f latest && ln -s $GIT_VER latest" + # add link to view the report + - echo "[static analysis][clang tidy] $CI_DOCKER_REGISTRY/static_analysis/esp-idf/clang-tidy/${GIT_VER}/index.html" + - test ! -e ${GIT_VER}/FAILED_RULES || { echo 'Failed static analysis rules!'; cat ${GIT_VER}/FAILED_RULES; exit 1; } + +clang_tidy_deploy: + extends: .clang_tidy_deploy_template + dependencies: + - clang_tidy_check + - clang_tidy_check_all + variables: + BOT_NEEDS_TRIGGER_BY_NAME: 1 + +clang_tidy_deploy_regular: + extends: .clang_tidy_deploy_template + dependencies: + - clang_tidy_check_regular + only: + refs: + - master + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ + - triggers + - schedules + variables: + - $BOT_LABEL_STATIC_ANALYSIS + - $BOT_LABEL_STATIC_ANALYSIS_ALL + +push_to_github: + stage: deploy + image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG + tags: + - deploy + only: + - master + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ + when: on_success + dependencies: [] + extends: .before_script_lesser + script: + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - echo -n $GH_PUSH_KEY > ~/.ssh/id_rsa_base64 + - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa + - chmod 600 ~/.ssh/id_rsa + - echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config + - git remote remove github &>/dev/null || true + - git remote add github git@github.com:espressif/esp-idf.git + - tools/ci/push_to_github.sh + +deploy_docs: + stage: deploy + image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG + tags: + - deploy + only: + refs: + - master + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ + - triggers + variables: + - $BOT_TRIGGER_WITH_LABEL == null + - $BOT_LABEL_BUILD_DOCS + dependencies: + - build_docs + extends: .before_script_lesser + script: + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - echo -n $DOCS_DEPLOY_KEY > ~/.ssh/id_rsa_base64 + - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa + - chmod 600 ~/.ssh/id_rsa + - echo -e "Host $DOCS_SERVER\n\tStrictHostKeyChecking no\n\tUser $DOCS_SERVER_USER\n" >> ~/.ssh/config + - export GIT_VER=$(git describe --always) + - cd docs/en/_build/ + - mv html $GIT_VER + - tar czvf $GIT_VER.tar.gz $GIT_VER + - scp $GIT_VER.tar.gz $DOCS_SERVER:$DOCS_PATH/en + - ssh $DOCS_SERVER -x "cd $DOCS_PATH/en && tar xzvf $GIT_VER.tar.gz && rm -f latest && ln -s $GIT_VER latest" + - cd ../../zh_CN/_build/ + - mv html $GIT_VER + - tar czvf $GIT_VER.tar.gz $GIT_VER + - scp $GIT_VER.tar.gz $DOCS_SERVER:$DOCS_PATH/zh_CN + - ssh $DOCS_SERVER -x "cd $DOCS_PATH/zh_CN && tar xzvf $GIT_VER.tar.gz && rm -f latest && ln -s $GIT_VER latest" + # add link to preview doc + - echo "[document preview][en] $CI_DOCKER_REGISTRY/docs/esp-idf/en/${GIT_VER}/index.html" + - echo "[document preview][zh_CN] $CI_DOCKER_REGISTRY/docs/esp-idf/zh_CN/${GIT_VER}/index.html" + +deploy_test_result: + stage: deploy + image: $CI_DOCKER_REGISTRY/bot-env + tags: + - deploy_test + when: always + only: + refs: + - master + - schedules + artifacts: + when: always + paths: + - ${CI_PROJECT_DIR}/test-management/*.log + # save all test logs as artifacts, make it easier to track errors + - ${CI_PROJECT_DIR}/TEST_LOGS + - $CI_PROJECT_DIR/$CI_COMMIT_SHA + expire_in: 1 mos + variables: + UNIT_TEST_CASE_FILE: "${CI_PROJECT_DIR}/components/idf_test/unit_test/TestCaseAll.yml" + BOT_ACCOUNT_CONFIG_FILE: "${CI_PROJECT_DIR}/test-management/Config/Account.local.yml" + TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw" + AUTO_TEST_SCRIPT_PATH: "${CI_PROJECT_DIR}/auto_test_script" + before_script: + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - echo -n $GITLAB_KEY > ~/.ssh/id_rsa_base64 + - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa + - chmod 600 ~/.ssh/id_rsa + - echo -e "Host gitlab.espressif.cn\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config + script: + - export GIT_SHA=$(echo ${CI_COMMIT_SHA} | cut -c 1-8) + - export REV_COUNT=$(git rev-list --count HEAD) + - export SUMMARY="IDF CI test result for $GIT_SHA (r${REV_COUNT})" + # artifacts of job update_test_cases creates test-management folder + # we need to remove it so we can clone test-management folder again + - rm -r test-management + - git clone $TEST_MANAGEMENT_REPO + - python3 $CHECKOUT_REF_SCRIPT test-management test-management + - cd test-management + - echo $BOT_JIRA_ACCOUNT > ${BOT_ACCOUNT_CONFIG_FILE} + # update test results + - python3 ImportTestResult.py -r "$GIT_SHA (r${REV_COUNT})" -j $JIRA_TEST_MANAGEMENT_PROJECT -s "$SUMMARY" -l CI -p ${CI_PROJECT_DIR}/TEST_LOGS ${CI_PROJECT_DIR}/${CI_COMMIT_SHA} --pipeline_url ${CI_PIPELINE_URL} diff --git a/tools/ci/config/host-test.yml b/tools/ci/config/host-test.yml new file mode 100644 index 0000000000..9ac5c0b4a9 --- /dev/null +++ b/tools/ci/config/host-test.yml @@ -0,0 +1,286 @@ + +.host_test_template: + stage: host_test + image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG + tags: + - host_test + dependencies: [] + only: + variables: + - $BOT_TRIGGER_WITH_LABEL == null + - $BOT_LABEL_HOST_TEST + - $BOT_LABEL_REGULAR_TEST + +.host_fuzzer_test_template: + stage: host_test + image: $CI_DOCKER_REGISTRY/afl-fuzzer-test + tags: + - host_test + dependencies: [] + artifacts: + when: always + paths: + - ${FUZZER_TEST_DIR}/out/crashes + - ${FUZZER_TEST_DIR}/fuzz_output.log + expire_in: 1 week + only: + variables: + - $BOT_LABEL_FUZZER_TEST + - $BOT_LABEL_WEEKEND_TEST + script: + - export AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 && export AFL_SKIP_CPUFREQ=1 + - cd ${FUZZER_TEST_DIR} + # run AFL fuzzer for one hour + - ( ( make ${FUZZER_PARAMS} fuzz | tee fuzz_output.log | grep -v '\(Fuzzing test case\|Entering queue cycle\)' ) || pkill sleep ) & + - ( sleep 3600 || mkdir -p out/crashes/env_failed ) && pkill afl-fuz + # check no crashes found + - test -z "$(ls out/crashes/)" || exit 1 + +.clang_tidy_check_template: + stage: host_test + image: ${CI_DOCKER_REGISTRY}/clang-static-analysis + tags: + - host_test + dependencies: [] + artifacts: + reports: + junit: $IDF_PATH/output.xml + when: always + paths: + - $IDF_PATH/examples/get-started/hello_world/tidybuild/report/* + expire_in: 1 day + script: + - git clone $IDF_ANALYSIS_UTILS static_analysis_utils && cd static_analysis_utils + # Setup parameters of triggered/regular job + - export TRIGGERED_RELATIVE=${BOT_LABEL_STATIC_ANALYSIS-} && export TRIGGERED_ABSOLUTE=${BOT_LABEL_STATIC_ANALYSIS_ALL-} && export TARGET_BRANCH=${BOT_CUSTOMIZED_REVISION-} + - ./analyze.sh $IDF_PATH/examples/get-started/hello_world/ $IDF_PATH/tools/ci/static-analysis-rules.yml $IDF_PATH/output.xml + +test_nvs_on_host: + extends: .host_test_template + script: + - cd components/nvs_flash/test_nvs_host + - make test + +test_nvs_coverage: + extends: .host_test_template + artifacts: + paths: + - components/nvs_flash/test_nvs_host/coverage_report + expire_in: 1 week + only: + refs: + - triggers + variables: + - $BOT_LABEL_NVS_COVERAGE + script: + - cd components/nvs_flash/test_nvs_host + - make coverage_report + +test_partition_table_on_host: + extends: .host_test_template + tags: + - build + script: + - cd components/partition_table/test_gen_esp32part_host + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./gen_esp32part_tests.py + +test_wl_on_host: + extends: .host_test_template + artifacts: + paths: + - components/wear_levelling/test_wl_host/coverage_report.zip + expire_in: 1 week + script: + - cd components/wear_levelling/test_wl_host + - make test + +test_fatfs_on_host: + extends: .host_test_template + script: + - cd components/fatfs/test_fatfs_host/ + - make test + +test_ldgen_on_host: + extends: .host_test_template + script: + - cd tools/ldgen/test + - ./test_fragments.py + - ./test_generation.py + +clang_tidy_check: + extends: .clang_tidy_check_template + variables: + BOT_NEEDS_TRIGGER_BY_NAME: 1 + BOT_LABEL_STATIC_ANALYSIS: 1 + +clang_tidy_check_regular: + extends: .clang_tidy_check_template + +clang_tidy_check_all: + extends: .clang_tidy_check_template + variables: + BOT_NEEDS_TRIGGER_BY_NAME: 1 + BOT_LABEL_STATIC_ANALYSIS_ALL: 1 + +test_mdns_fuzzer_on_host: + extends: .host_fuzzer_test_template + variables: + FUZZER_TEST_DIR: components/mdns/test_afl_fuzz_host + +test_lwip_dns_fuzzer_on_host: + extends: .host_fuzzer_test_template + variables: + FUZZER_TEST_DIR: components/lwip/test_afl_host + FUZZER_PARAMS: MODE=dns + +test_lwip_dhcp_fuzzer_on_host: + extends: .host_fuzzer_test_template + variables: + FUZZER_TEST_DIR: components/lwip/test_afl_host + FUZZER_PARAMS: MODE=dhcp_client + +test_lwip_dhcps_fuzzer_on_host: + extends: .host_fuzzer_test_template + variables: + FUZZER_TEST_DIR: components/lwip/test_afl_host + FUZZER_PARAMS: MODE=dhcp_server + +test_spiffs_on_host: + extends: .host_test_template + script: + - cd components/spiffs/test_spiffs_host/ + - make test + +test_multi_heap_on_host: + extends: .host_test_template + script: + - cd components/heap/test_multi_heap_host + - ./test_all_configs.sh + +test_confserver: + extends: .host_test_template + script: + - cd tools/kconfig_new/test + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test_confserver.py + +test_idf_monitor: + extends: .host_test_template + artifacts: + # save artifacts always in order to access results which were retried without consequent failure + when: always + paths: + - tools/test_idf_monitor/outputs/* + expire_in: 1 week + script: + - cd ${IDF_PATH}/tools/test_idf_monitor + - ./run_test_idf_monitor.py + +test_idf_size: + extends: .host_test_template + artifacts: + when: on_failure + paths: + - tools/test_idf_size/output + - tools/test_idf_size/.coverage + expire_in: 1 week + script: + - cd ${IDF_PATH}/tools/test_idf_size + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test.sh + +test_idf_tools: + extends: .host_test_template + script: + # Remove Xtensa and ULP toolchains from the PATH, tests will expect a clean environment + - export PATH=$(p=$(echo $PATH | tr ":" "\n" | grep -v "/root/.espressif/tools\|/opt/espressif${CUSTOM_TOOLCHAIN_PATH:+\|${CUSTOM_TOOLCHAIN_PATH}}" | tr "\n" ":"); echo ${p%:}) + - cd ${IDF_PATH}/tools/test_idf_tools + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test_idf_tools.py + +test_esp_err_to_name_on_host: + extends: .host_test_template + artifacts: + when: on_failure + paths: + - components/esp32/esp_err_to_name.c + expire_in: 1 week + script: + - cd ${IDF_PATH}/tools/ + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh -p 2.7.15 ./gen_esp_err_to_name.py + - git diff --exit-code -- ../components/esp32/esp_err_to_name.c || { echo 'Differences found. Please run gen_esp_err_to_name.py and commit the changes.'; exit 1; } + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh -p 3.4.8 ./gen_esp_err_to_name.py + - git diff --exit-code -- ../components/esp32/esp_err_to_name.c || { echo 'Differences found between running under Python 2 and 3.'; exit 1; } + +test_esp_efuse_table_on_host: + extends: .host_test_template + artifacts: + when: on_failure + paths: + - components/efuse/esp32/esp_efuse_table.c + expire_in: 1 week + script: + - cd ${IDF_PATH}/components/efuse/ + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh -p 2.7.15 ./efuse_table_gen.py ${IDF_PATH}/components/efuse/esp32/esp_efuse_table.csv + - git diff --exit-code -- esp32/esp_efuse_table.c || { echo 'Differences found. Please run make efuse_common_table or idf.py efuse_common_table and commit the changes.'; exit 1; } + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh -p 3.4.8 ./efuse_table_gen.py ${IDF_PATH}/components/efuse/esp32/esp_efuse_table.csv + - git diff --exit-code -- ../components/esp32/esp_efuse_table.c || { echo 'Differences found between running under Python 2 and 3.'; exit 1; } + - cd ${IDF_PATH}/components/efuse/test_efuse_host + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./efuse_tests.py + +test_espcoredump: + extends: .host_test_template + artifacts: + when: always + paths: + - components/espcoredump/test/.coverage + - components/espcoredump/test/output + expire_in: 1 week + script: + - cd components/espcoredump/test/ + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test_espcoredump.sh + +test_logtrace_proc: + extends: .host_test_template + artifacts: + when: on_failure + paths: + - tools/esp_app_trace/test/logtrace/output + - tools/esp_app_trace/test/logtrace/.coverage + expire_in: 1 week + script: + - cd ${IDF_PATH}/tools/esp_app_trace/test/logtrace + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test.sh + +test_sysviewtrace_proc: + extends: .host_test_template + artifacts: + when: on_failure + paths: + - tools/esp_app_trace/test/sysview/output + - tools/esp_app_trace/test/sysview/.coverage + expire_in: 1 week + script: + - cd ${IDF_PATH}/tools/esp_app_trace/test/sysview + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test.sh + +check_doc_links: + stage: host_test + image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG + tags: + - check_doc_links + only: + refs: + # can only be triggered + - triggers + variables: + - $BOT_TRIGGER_WITH_LABEL == null + - $BOT_LABEL_BUILD_DOCS + artifacts: + paths: + - docs/_build/linkcheck + expire_in: 1 week + script: + # must be triggered with CHECK_LINKS=Yes, otherwise exit without test + - test "$CHECK_LINKS" = "Yes" || exit 0 + # can only run on master branch (otherwise the commit is not on Github yet) + - test "${CI_COMMIT_REF_NAME}" = "master" || exit 0 + - cd docs + - make linkcheck diff --git a/tools/ci/config/target-test.yml b/tools/ci/config/target-test.yml new file mode 100644 index 0000000000..069a328895 --- /dev/null +++ b/tools/ci/config/target-test.yml @@ -0,0 +1,572 @@ + +# for parallel jobs, CI_JOB_NAME will be "job_name index/total" (for example, "IT_001 1/2") +# we need to convert to pattern "job_name_index.yml" +.define_config_file_name: &define_config_file_name | + JOB_NAME_PREFIX=$(echo ${CI_JOB_NAME} | awk '{print $1}') + JOG_FULL_NAME="${JOB_NAME_PREFIX}_${CI_NODE_INDEX}" + CONFIG_FILE="${CONFIG_FILE_PATH}/${JOG_FULL_NAME}.yml" + +.example_test_template: + stage: target_test + when: on_success + only: + refs: + - master + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ + - triggers + - schedules + variables: + - $BOT_TRIGGER_WITH_LABEL == null + - $BOT_LABEL_EXAMPLE_TEST + dependencies: + - assign_test + - build_examples_make + - build_examples_cmake + artifacts: + when: always + paths: + - $LOG_PATH + expire_in: 1 week + reports: + junit: $LOG_PATH/*/XUNIT_RESULT.xml + variables: + TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw" + TEST_CASE_PATH: "$CI_PROJECT_DIR/examples" + CONFIG_FILE_PATH: "${CI_PROJECT_DIR}/examples/test_configs" + LOG_PATH: "$CI_PROJECT_DIR/TEST_LOGS" + ENV_FILE: "$CI_PROJECT_DIR/ci-test-runner-configs/$CI_RUNNER_DESCRIPTION/EnvConfig.yml" + script: + - *define_config_file_name + # first test if config file exists, if not exist, exit 0 + - test -e $CONFIG_FILE || exit 0 + # clone test env configs + - git clone $TEST_ENV_CONFIG_REPOSITORY + - python $CHECKOUT_REF_SCRIPT ci-test-runner-configs ci-test-runner-configs + - cd $TEST_FW_PATH + # run test + - python Runner.py $TEST_CASE_PATH -c $CONFIG_FILE -e $ENV_FILE + +.unit_test_template: + extends: .example_test_template + stage: target_test + dependencies: + - assign_test + - build_esp_idf_tests_make + - build_esp_idf_tests_cmake + only: + refs: + - master + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ + - triggers + - schedules + variables: + - $BOT_TRIGGER_WITH_LABEL == null + - $BOT_LABEL_UNIT_TEST + variables: + TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw" + TEST_CASE_PATH: "$CI_PROJECT_DIR/tools/unit-test-app" + CONFIG_FILE_PATH: "${CI_PROJECT_DIR}/components/idf_test/unit_test/CIConfigs" + LOG_PATH: "$CI_PROJECT_DIR/TEST_LOGS" + ENV_FILE: "$CI_PROJECT_DIR/ci-test-runner-configs/$CI_RUNNER_DESCRIPTION/EnvConfig.yml" + +.test_template: + stage: target_test + when: on_success + only: + refs: + - master + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ + - triggers + - schedules + variables: + - $BOT_TRIGGER_WITH_LABEL == null + - $BOT_LABEL_INTEGRATION_TEST + dependencies: + - assign_test + - build_ssc + artifacts: + when: always + reports: + junit: $LOG_PATH/*/XUNIT_RESULT.xml + paths: + - $LOG_PATH + expire_in: 1 week + variables: + GIT_SUBMODULE_STRATEGY: none + LOCAL_ENV_CONFIG_PATH: "$CI_PROJECT_DIR/ci-test-runner-configs/$CI_RUNNER_DESCRIPTION/ESP32_IDF" + LOG_PATH: "${CI_PROJECT_DIR}/${CI_COMMIT_SHA}" + TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/components/idf_test/integration_test" + MODULE_UPDATE_FILE: "$CI_PROJECT_DIR/components/idf_test/ModuleDefinition.yml" + CONFIG_FILE_PATH: "${CI_PROJECT_DIR}/components/idf_test/integration_test/CIConfigs" + script: + - *define_config_file_name + # first test if config file exists, if not exist, exit 0 + - test -e $CONFIG_FILE || exit 0 + # clone local test env configs + - git clone $TEST_ENV_CONFIG_REPOSITORY + - python $CHECKOUT_REF_SCRIPT ci-test-runner-configs ci-test-runner-configs + # clone test bench + - git clone $TEST_SCRIPT_REPOSITORY + - python $CHECKOUT_REF_SCRIPT auto_test_script auto_test_script + - cd auto_test_script + # run test + - python CIRunner.py -l "$LOG_PATH/$JOG_FULL_NAME" -c $CONFIG_FILE -e $LOCAL_ENV_CONFIG_PATH -t $TEST_CASE_FILE_PATH + +test_weekend_mqtt: + extends: .example_test_template + stage: target_test + tags: + - ESP32 + - Example_WIFI + only: + variables: + - $BOT_LABEL_WEEKEND_TEST + variables: + TEST_CASE_PATH: "$CI_PROJECT_DIR/components/mqtt/weekend_test" + TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw" + LOG_PATH: "$CI_PROJECT_DIR/TEST_LOGS" + ENV_FILE: "$CI_PROJECT_DIR/components/mqtt/weekend_test/env.yml" + CONFIG_FILE: "$CI_PROJECT_DIR/components/mqtt/weekend_test/config.yml" + +test_weekend_network: + extends: .example_test_template + stage: target_test + image: $CI_DOCKER_REGISTRY/rpi-net-suite$BOT_DOCKER_IMAGE_TAG + tags: + - ESP32 + - Example_WIFI + only: + variables: + - $BOT_LABEL_WEEKEND_TEST + variables: + TEST_CASE_PATH: "$CI_PROJECT_DIR/components/lwip/weekend_test" + TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw" + LOG_PATH: "$CI_PROJECT_DIR/TEST_LOGS" + ENV_FILE: "$CI_PROJECT_DIR/components/lwip/weekend_test/env.yml" + CONFIG_FILE: "$CI_PROJECT_DIR/components/lwip/weekend_test/config.yml" + +example_test_001: + extends: .example_test_template + parallel: 2 + tags: + - ESP32 + - Example_WIFI + +example_test_002: + extends: .example_test_template + image: $CI_DOCKER_REGISTRY/ubuntu-test-env$BOT_DOCKER_IMAGE_TAG + tags: + - ESP32 + - Example_ShieldBox_Basic + +.example_test_003: + extends: .example_test_template + tags: + - ESP32 + - Example_SDIO + +example_test_004: + extends: .example_test_template + tags: + - ESP32 + - Example_CAN + +example_test_005: + extends: .example_test_template + tags: + - ESP32 + - Example_WIFI_BT + +example_test_006: + extends: .example_test_template + image: $CI_DOCKER_REGISTRY/ubuntu-test-env$BOT_DOCKER_IMAGE_TAG + only: + variables: + - $BOT_LABEL_IPERF_STRESS_TEST + tags: + - ESP32 + - Example_ShieldBox + +example_test_007: + extends: .example_test_template + tags: + - ESP32 + - Example_I2C_CCS811_SENSOR + +UT_001: + extends: .unit_test_template + parallel: 50 + tags: + - ESP32_IDF + - UT_T1_1 + +UT_002: + extends: .unit_test_template + parallel: 18 + tags: + - ESP32_IDF + - UT_T1_1 + - psram + +UT_003: + extends: .unit_test_template + parallel: 3 + tags: + - ESP32_IDF + - UT_T1_SDMODE + +UT_004: + extends: .unit_test_template + parallel: 3 + tags: + - ESP32_IDF + - UT_T1_SPIMODE + +UT_005: + extends: .unit_test_template + tags: + - ESP32_IDF + - UT_T1_SDMODE + - psram + +UT_006: + extends: .unit_test_template + tags: + - ESP32_IDF + - UT_T1_SPIMODE + - psram + +UT_007: + extends: .unit_test_template + parallel: 4 + tags: + - ESP32_IDF + - UT_T1_GPIO + +UT_008: + extends: .unit_test_template + tags: + - ESP32_IDF + - UT_T1_GPIO + - psram + +UT_009: + extends: .unit_test_template + parallel: 4 + tags: + - ESP32_IDF + - UT_T1_PCNT + +UT_010: + extends: .unit_test_template + tags: + - ESP32_IDF + - UT_T1_PCNT + - psram + +UT_011: + extends: .unit_test_template + parallel: 4 + tags: + - ESP32_IDF + - UT_T1_LEDC + +UT_012: + extends: .unit_test_template + tags: + - ESP32_IDF + - UT_T1_LEDC + - psram + +UT_013: + extends: .unit_test_template + parallel: 4 + tags: + - ESP32_IDF + - UT_T2_RS485 + +UT_014: + extends: .unit_test_template + tags: + - ESP32_IDF + - UT_T2_RS485 + - psram + +UT_015: + extends: .unit_test_template + parallel: 4 + tags: + - ESP32_IDF + - UT_T1_RMT + +UT_016: + extends: .unit_test_template + tags: + - ESP32_IDF + - UT_T1_RMT + - psram + +UT_017: + extends: .unit_test_template + parallel: 3 + tags: + - ESP32_IDF + - EMMC + +UT_018: + extends: .unit_test_template + parallel: 5 + tags: + - ESP32_IDF + - UT_T1_1 + - 8Mpsram + +UT_019: + extends: .unit_test_template + parallel: 4 + tags: + - ESP32_IDF + - Example_SPI_Multi_device + +UT_020: + extends: .unit_test_template + tags: + - ESP32_IDF + - Example_SPI_Multi_device + - psram + +UT_021: + extends: .unit_test_template + parallel: 4 + tags: + - ESP32_IDF + - UT_T2_I2C + +UT_022: + extends: .unit_test_template + tags: + - ESP32_IDF + - UT_T2_I2C + - psram + +UT_023: + extends: .unit_test_template + parallel: 4 + tags: + - ESP32_IDF + - UT_T1_MCPWM + +UT_024: + extends: .unit_test_template + tags: + - ESP32_IDF + - UT_T1_MCPWM + - psram + +UT_025: + extends: .unit_test_template + parallel: 4 + tags: + - ESP32_IDF + - UT_T1_I2S + +UT_026: + extends: .unit_test_template + tags: + - ESP32_IDF + - UT_T1_I2S + - psram + +UT_027: + extends: .unit_test_template + parallel: 3 + tags: + - ESP32_IDF + - UT_T2_1 + +UT_028: + extends: .unit_test_template + tags: + - ESP32_IDF + - UT_T2_1 + - psram + +UT_029: + extends: .unit_test_template + tags: + - ESP32_IDF + - UT_T2_1 + - 8Mpsram + +# Gitlab parallel max value is 50. We need to create another UT job if parallel is larger than 50. +UT_030: + extends: .unit_test_template + parallel: 5 + tags: + - ESP32_IDF + - UT_T1_1 + +nvs_compatible_test: + extends: .test_template + artifacts: + when: always + paths: + - $LOG_PATH + - nvs_wifi.bin + expire_in: 1 mos + tags: + - ESP32_IDF + - NVS_Compatible + script: + - *define_config_file_name + # first test if config file exists, if not exist, exit 0 + - test -e $CONFIG_FILE || exit 0 + # clone local test env configs + - git clone $TEST_ENV_CONFIG_REPOSITORY + - python $CHECKOUT_REF_SCRIPT ci-test-runner-configs ci-test-runner-configs + # clone test bench + - git clone $TEST_SCRIPT_REPOSITORY + - python $CHECKOUT_REF_SCRIPT auto_test_script auto_test_script + - cd auto_test_script + # prepare nvs bins + - ./Tools/prepare_nvs_bin.sh + # run test + - python CIRunner.py -l "$LOG_PATH/$JOG_FULL_NAME" -c $CONFIG_FILE -e $LOCAL_ENV_CONFIG_PATH -t $TEST_CASE_FILE_PATH + +IT_001: + extends: .test_template + parallel: 3 + tags: + - ESP32_IDF + - SSC_T1_4 + +IT_002: + extends: .test_template + tags: + - ESP32_IDF + - SSC_T1_2 + +IT_003: + extends: .test_template + parallel: 13 + tags: + - ESP32_IDF + - SSC_T2_5 + +IT_004: + extends: .test_template + tags: + - ESP32_IDF + - SSC_T1_APC + +IT_005: + extends: .test_template + parallel: 2 + tags: + - ESP32_IDF + - SSC_T1_5 + +IT_006: + extends: .test_template + parallel: 8 + tags: + - ESP32_IDF + - SSC_T1_6 + +IT_007: + extends: .test_template + parallel: 3 + tags: + - ESP32_IDF + - SSC_T1_7 + +IT_008: + extends: .test_template + tags: + - ESP32_IDF + - SSC_T1_8 + +IT_009: + extends: .test_template + tags: + - ESP32_IDF + - SSC_T1_3 + +IT_010: + extends: .test_template + parallel: 4 + tags: + - ESP32_IDF + - SSC_T5_1 + +IT_011: + extends: .test_template + tags: + - ESP32_IDF + - SSC_T1_MESH1 + +IT_012: + extends: .test_template + parallel: 2 + tags: + - ESP32_IDF + - SSC_T2_MESH1 + +IT_013: + extends: .test_template + tags: + - ESP32_IDF + - SSC_T3_MESH1 + +IT_014: + extends: .test_template + tags: + - ESP32_IDF + - SSC_T6_MESH1 + +IT_015: + extends: .test_template + tags: + - ESP32_IDF + - SSC_T12_MESH1 + +IT_016: + extends: .test_template + tags: + - ESP32_IDF + - SSC_T50_MESH1 + +IT_017: + extends: .test_template + tags: + - ESP32_IDF + - SSC_T1_MESH2 + +IT_018: + extends: .test_template + parallel: 2 + tags: + - ESP32_IDF + - SSC_T1_9 + +IT_019: + extends: .test_template + parallel: 2 + tags: + - ESP32_IDF + - SSC_T2_2 + +IT_020: + extends: .test_template + tags: + - ESP32_IDF + - SSC_T2_3 + +IT_021: + extends: .test_template + tags: + - ESP32_IDF + - SSC_T2_4 From daa71d5e1875bb9af6c38228257572b955fbda0c Mon Sep 17 00:00:00 2001 From: Hrishikesh Dhayagude Date: Wed, 3 Jul 2019 17:17:14 +0800 Subject: [PATCH 230/486] Fix the irrelevant characters added to test the config options --- components/bt/common/osi/alarm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/components/bt/common/osi/alarm.c b/components/bt/common/osi/alarm.c index 178a52a93d..c8bfc83ab7 100644 --- a/components/bt/common/osi/alarm.c +++ b/components/bt/common/osi/alarm.c @@ -82,7 +82,6 @@ void osi_alarm_init(void) goto end; } #if (BT_BLE_DYNAMIC_ENV_MEMORY == TRUE) -xyz if ((alarm_cbs = (osi_alarm_t *)osi_malloc(sizeof(osi_alarm_t) * ALARM_CBS_NUM)) == NULL) { OSI_TRACE_ERROR("%s, malloc failed\n", __func__); goto end; From ff40911a516531d27620177edc5e9e2620f8fd9c Mon Sep 17 00:00:00 2001 From: lly Date: Fri, 28 Jun 2019 11:13:18 +0800 Subject: [PATCH 231/486] ble_mesh: add Doxyfile for core apis & model apis --- .../api/core/esp_ble_mesh_common_api.c | 2 +- .../esp_ble_mesh_local_data_operation_api.c | 2 +- .../api/core/esp_ble_mesh_low_power_api.c | 2 +- .../api/core/esp_ble_mesh_networking_api.c | 2 +- .../api/core/esp_ble_mesh_provisioning_api.c | 2 +- .../api/core/esp_ble_mesh_proxy_api.c | 2 +- .../core/include/esp_ble_mesh_common_api.h | 2 +- .../esp_ble_mesh_local_data_operation_api.h | 8 +- .../core/include/esp_ble_mesh_low_power_api.h | 2 +- .../include/esp_ble_mesh_networking_api.h | 4 +- .../include/esp_ble_mesh_provisioning_api.h | 4 +- .../api/core/include/esp_ble_mesh_proxy_api.h | 8 +- .../bt/esp_ble_mesh/api/esp_ble_mesh_defs.h | 513 ++++++++++-------- .../models/esp_ble_mesh_config_model_api.c | 2 +- .../models/esp_ble_mesh_generic_model_api.c | 2 +- .../models/esp_ble_mesh_health_model_api.c | 2 +- .../models/esp_ble_mesh_lighting_model_api.c | 2 +- .../models/esp_ble_mesh_sensor_model_api.c | 2 +- .../esp_ble_mesh_time_scene_model_api.c | 2 +- .../include/esp_ble_mesh_config_model_api.h | 193 ++++--- .../include/esp_ble_mesh_generic_model_api.h | 251 +++++---- .../include/esp_ble_mesh_health_model_api.h | 71 ++- .../include/esp_ble_mesh_lighting_model_api.h | 409 ++++++++------ .../include/esp_ble_mesh_sensor_model_api.h | 121 +++-- .../esp_ble_mesh_time_scene_model_api.h | 173 +++--- .../btc/btc_ble_mesh_config_model.c | 2 +- .../btc/btc_ble_mesh_generic_model.c | 2 +- .../btc/btc_ble_mesh_health_model.c | 2 +- .../btc/btc_ble_mesh_lighting_model.c | 2 +- .../bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c | 2 +- .../btc/btc_ble_mesh_sensor_model.c | 2 +- .../btc/btc_ble_mesh_time_scene_model.c | 2 +- .../btc/include/btc_ble_mesh_config_model.h | 2 +- .../btc/include/btc_ble_mesh_generic_model.h | 2 +- .../btc/include/btc_ble_mesh_health_model.h | 2 +- .../btc/include/btc_ble_mesh_lighting_model.h | 2 +- .../btc/include/btc_ble_mesh_prov.h | 2 +- .../btc/include/btc_ble_mesh_sensor_model.h | 2 +- .../include/btc_ble_mesh_time_scene_model.h | 2 +- .../mesh_core/provisioner_beacon.c | 2 +- .../mesh_core/provisioner_beacon.h | 2 +- .../esp_ble_mesh/mesh_core/provisioner_main.c | 2 +- .../esp_ble_mesh/mesh_core/provisioner_main.h | 2 +- .../esp_ble_mesh/mesh_core/provisioner_prov.c | 2 +- .../esp_ble_mesh/mesh_core/provisioner_prov.h | 2 +- .../mesh_core/provisioner_proxy.c | 2 +- .../mesh_core/provisioner_proxy.h | 2 +- .../mesh_core/settings/settings_nvs.c | 2 +- .../mesh_core/settings/settings_nvs.h | 2 +- .../esp_ble_mesh/mesh_models/generic_client.c | 2 +- .../mesh_models/include/generic_client.h | 2 +- .../mesh_models/include/lighting_client.h | 2 +- .../mesh_models/include/mesh_common.h | 2 +- .../mesh_models/include/model_common.h | 2 +- .../mesh_models/include/model_opcode.h | 2 +- .../mesh_models/include/sensor_client.h | 2 +- .../mesh_models/include/time_scene_client.h | 2 +- .../mesh_models/lighting_client.c | 2 +- .../bt/esp_ble_mesh/mesh_models/mesh_common.c | 2 +- .../esp_ble_mesh/mesh_models/model_common.c | 2 +- .../esp_ble_mesh/mesh_models/sensor_client.c | 2 +- .../mesh_models/time_scene_client.c | 2 +- docs/Doxyfile | 14 + .../ble_mesh_node/main/ble_mesh_adapter.c | 2 +- .../ble_mesh_node/main/ble_mesh_adapter.h | 2 +- .../main/ble_mesh_cfg_srv_model.c | 2 +- .../main/ble_mesh_cfg_srv_model.h | 2 +- .../ble_mesh_node/main/ble_mesh_console_lib.c | 2 +- .../ble_mesh_node/main/ble_mesh_console_lib.h | 2 +- .../main/ble_mesh_console_main.c | 2 +- .../main/ble_mesh_register_node_cmd.c | 2 +- .../main/ble_mesh_register_server_cmd.c | 2 +- .../ble_mesh_node/main/register_bluetooth.c | 2 +- .../main/ble_mesh_adapter.c | 2 +- .../main/ble_mesh_adapter.h | 2 +- .../main/ble_mesh_cfg_srv_model.c | 2 +- .../main/ble_mesh_cfg_srv_model.h | 2 +- .../main/ble_mesh_console_lib.c | 2 +- .../main/ble_mesh_console_lib.h | 2 +- .../main/ble_mesh_console_main.c | 2 +- .../main/ble_mesh_reg_cfg_client_cmd.c | 2 +- .../main/ble_mesh_reg_gen_onoff_client_cmd.c | 2 +- .../main/ble_mesh_reg_test_perf_client_cmd.c | 2 +- .../main/ble_mesh_register_node_cmd.c | 2 +- .../main/ble_mesh_register_provisioner_cmd.c | 2 +- .../main/register_bluetooth.c | 2 +- .../main/ble_mesh_demo_main.c | 2 +- .../main/ble_mesh_demo_main.c | 2 +- .../ble_mesh_fast_prov_server/main/board.c | 2 +- .../ble_mesh_fast_prov_server/main/board.h | 2 +- .../components/esp_fast_prov_client_model.c | 2 +- .../components/esp_fast_prov_client_model.h | 2 +- .../components/esp_fast_prov_common.h | 2 +- .../components/esp_fast_prov_operation.c | 2 +- .../components/esp_fast_prov_operation.h | 2 +- .../components/esp_fast_prov_server_model.c | 2 +- .../components/esp_fast_prov_server_model.h | 2 +- .../fast_prov_vendor_model/main/main.c | 2 +- .../main/ble_mesh_demo_main.c | 2 +- .../ble_mesh_wifi_coexist/main/board.c | 2 +- .../ble_mesh_wifi_coexist/main/board.h | 2 +- 101 files changed, 1109 insertions(+), 838 deletions(-) diff --git a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_common_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_common_api.c index 4172ef0c7d..2a5253f907 100644 --- a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_common_api.c +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_common_api.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c index 6efeaf1765..50e49b80ab 100644 --- a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_low_power_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_low_power_api.c index 6d3745ca6e..4d93f809ef 100644 --- a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_low_power_api.c +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_low_power_api.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c index 9e920dd113..721999bb0e 100644 --- a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_provisioning_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_provisioning_api.c index 855bcf188f..b8f12244eb 100644 --- a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_provisioning_api.c +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_provisioning_api.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_proxy_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_proxy_api.c index 0605e97a6b..4d25a656f4 100644 --- a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_proxy_api.c +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_proxy_api.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_common_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_common_api.h index a550ad381f..7f48436685 100644 --- a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_common_api.h +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_common_api.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h index 0acb6d73f0..a1b0ff00de 100644 --- a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. @@ -30,8 +30,6 @@ int32_t esp_ble_mesh_get_model_publish_period(esp_ble_mesh_model_t *model); /** * @brief Get the address of the primary element. * - * @param None. - * * @return Address of the primary element on success, or * ESP_BLE_MESH_ADDR_UNASSIGNED on failure which means the device has not been provisioned. * @@ -68,8 +66,6 @@ esp_ble_mesh_elem_t *esp_ble_mesh_find_element(uint16_t element_addr); /** * @brief Get the number of elements that have been registered. * - * @param None. - * * @return Number of elements. * */ @@ -103,8 +99,6 @@ esp_ble_mesh_model_t *esp_ble_mesh_find_sig_model(const esp_ble_mesh_elem_t *ele /** * @brief Get the Composition data which has been registered. * - * @param None. - * * @return Pointer to the Composition data on success, or NULL on failure which means the Composition data is not initialized. * */ diff --git a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_low_power_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_low_power_api.h index 7a203d50cc..48238c5eba 100644 --- a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_low_power_api.h +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_low_power_api.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_networking_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_networking_api.h index d3df66879d..ae51b60818 100644 --- a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_networking_api.h +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_networking_api.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. @@ -141,8 +141,6 @@ esp_err_t esp_ble_mesh_model_publish(esp_ble_mesh_model_t *model, uint32_t opcod * needs to be reprovisioned. The API function esp_ble_mesh_node_prov_enable() * needs to be called to start a new provisioning procedure. * - * @param None. - * * @return ESP_OK on success or error code otherwise. * */ diff --git a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h index e03c4d4ef1..a5a4256f44 100644 --- a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. @@ -34,8 +34,6 @@ esp_err_t esp_ble_mesh_register_prov_callback(esp_ble_mesh_prov_cb_t callback); /** * @brief Check if a device has been provisioned. * - * @param None. - * * @return TRUE if the device is provisioned, FALSE if the device is unprovisioned. * */ diff --git a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_proxy_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_proxy_api.h index 67a785dda6..cb67b96a0d 100644 --- a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_proxy_api.h +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_proxy_api.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. @@ -27,8 +27,6 @@ * Network ID advertising will be enabled automatically by BLE Mesh * stack after the device is provisioned. * - * @param None. - * * @return ESP_OK on success or error code otherwise. * */ @@ -37,8 +35,6 @@ esp_err_t esp_ble_mesh_proxy_identity_enable(void); /** * @brief Enable BLE Mesh GATT Proxy Service. * - * @param None. - * * @return ESP_OK on success or error code otherwise. * */ @@ -48,8 +44,6 @@ esp_err_t esp_ble_mesh_proxy_gatt_enable(void); * @brief Disconnect the BLE Mesh GATT Proxy connection if there is any, and * disable the BLE Mesh GATT Proxy Service. * - * @param None. - * * @return ESP_OK on success or error code otherwise. * */ diff --git a/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h b/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h index 6e751bd315..e72faf95e7 100644 --- a/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h +++ b/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. @@ -31,6 +31,7 @@ #include "model_opcode.h" #include "mesh_common.h" +/*!< The maximum length of a BLE Mesh message, including Opcode, Payload and TransMIC */ #define ESP_BLE_MESH_SDU_MAX_LEN 384 /*!< The maximum length of a BLE Mesh provisioned node name */ @@ -392,7 +393,7 @@ typedef uint32_t esp_ble_mesh_generic_message_opcode_t; /*!< esp_ble_mesh_ge typedef uint32_t esp_ble_mesh_sensor_message_opcode_t; /*!< esp_ble_mesh_sensor_message_opcode_t belongs to esp_ble_mesh_opcode_t, this typedef is only used to locate the opcodes used by functions - esp_ble_mesh_sensor_client_get_state & esp_ble_mesh_sensor_client_set_state */ + esp_ble_mesh_sensor_client_get_state & esp_ble_mesh_sensor_client_set_state */ /*!< Sensor Message Opcode */ #define ESP_BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET #define ESP_BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS @@ -663,7 +664,7 @@ typedef uint8_t esp_ble_mesh_model_status_t; /*!< This typedef is only used t */ #define ESP_BLE_MESH_GET_PUBLISH_TRANSMIT_INTERVAL(transmit) BLE_MESH_PUB_TRANSMIT_INT(transmit) -/* esp_ble_mesh_cb_t is not needed to be initialized by users (set with 0 and will be initialized internally) */ +/*!< Callbacks which are not needed to be initialized by users (set with 0 and will be initialized internally) */ typedef uint32_t esp_ble_mesh_cb_t; typedef enum { @@ -727,6 +728,7 @@ typedef enum { ESP_BLE_MESH_PROV_OOB_ON_DEV = BIT(15), } esp_ble_mesh_prov_oob_info_t; +/*!< Macros used to define message opcode */ #define ESP_BLE_MESH_MODEL_OP_1(b0) BLE_MESH_MODEL_OP_1(b0) #define ESP_BLE_MESH_MODEL_OP_2(b0, b1) BLE_MESH_MODEL_OP_2(b0, b1) #define ESP_BLE_MESH_MODEL_OP_3(b0, cid) BLE_MESH_MODEL_OP_3(b0, cid) @@ -790,43 +792,43 @@ typedef enum { typedef struct esp_ble_mesh_model esp_ble_mesh_model_t; -/*!< Abstraction that describes a BLE Mesh Element. - This structure is associated with bt_mesh_elem in mesh_access.h */ +/** Abstraction that describes a BLE Mesh Element. + * This structure is associated with struct bt_mesh_elem in mesh_access.h + */ typedef struct { - /* Element Address, assigned during provisioning. */ + /** Element Address, assigned during provisioning. */ uint16_t element_addr; - /* Location Descriptor (GATT Bluetooth Namespace Descriptors) */ + /** Location Descriptor (GATT Bluetooth Namespace Descriptors) */ const uint16_t location; - /* Model count */ - const uint8_t sig_model_count; - const uint8_t vnd_model_count; + const uint8_t sig_model_count; /*!< SIG Model count */ + const uint8_t vnd_model_count; /*!< Vendor Model count */ - /* Models */ - esp_ble_mesh_model_t *sig_models; - esp_ble_mesh_model_t *vnd_models; + esp_ble_mesh_model_t *sig_models; /*!< SIG Models */ + esp_ble_mesh_model_t *vnd_models; /*!< Vendor Models */ } esp_ble_mesh_elem_t; -/*!< Model publication context. - This structure is associated with bt_mesh_model_pub in mesh_access.h */ +/** Abstraction that describes a model publication context. + * This structure is associated with struct bt_mesh_model_pub in mesh_access.h + */ typedef struct { - /** The model to which the context belongs. Initialized by the stack. */ + /** Pointer to the model to which the context belongs. Initialized by the stack. */ esp_ble_mesh_model_t *model; - uint16_t publish_addr; /**< Publish Address. */ - uint16_t app_idx; /**< Publish AppKey Index. */ + uint16_t publish_addr; /*!< Publish Address. */ + uint16_t app_idx; /*!< Publish AppKey Index. */ - uint8_t ttl; /**< Publish Time to Live. */ - uint8_t retransmit; /**< Retransmit Count & Interval Steps. */ + uint8_t ttl; /*!< Publish Time to Live. */ + uint8_t retransmit; /*!< Retransmit Count & Interval Steps. */ uint8_t period; /*!< Publish Period. */ uint16_t period_div: 4, /*!< Divisor for the Period. */ cred: 1, /*!< Friendship Credentials Flag. */ - fast_period: 1, /**< Use FastPeriodDivisor */ + fast_period: 1, /*!< Use FastPeriodDivisor */ count: 3; /*!< Retransmissions left. */ - uint32_t period_start; /**< Start of the current period. */ + uint32_t period_start; /*!< Start of the current period. */ /** @brief Publication buffer, containing the publication message. * @@ -837,13 +839,13 @@ typedef struct { */ struct net_buf_simple *msg; - /* The callback is only used for the BLE Mesh stack, not for the app layer. */ + /** Callback used to update publish message. Initialized by the stack. */ esp_ble_mesh_cb_t update; - /* Role of the device that is going to publish messages */ + /** Role of the device that is going to publish messages */ uint8_t dev_role; - /** Publish Period Timer. Only for stack-internal use. */ + /** Publish Period Timer. Initialized by the stack. */ struct k_delayed_work timer; } esp_ble_mesh_model_pub_t; @@ -863,8 +865,13 @@ typedef struct { .dev_role = _role, \ } -/*!< Model operation context. - This structure is associated with bt_mesh_model_op in mesh_access.h */ +/** @def ESP_BLE_MESH_MODEL_OP + * + * Define a model operation context. + * + * @param _opcode Message opcode. + * @param _min_len Message minimum length. + */ #define ESP_BLE_MESH_MODEL_OP(_opcode, _min_len) \ { \ .opcode = _opcode, \ @@ -872,23 +879,26 @@ typedef struct { .param_cb = (uint32_t)NULL, \ } +/** Abstraction that describes a model operation context. + * This structure is associated with struct bt_mesh_model_op in mesh_access.h + */ typedef struct { - const uint32_t opcode; /* Opcode encoded with the ESP_BLE_MESH_MODEL_OP_* macro */ - const size_t min_len; /* Minimum required message length */ - esp_ble_mesh_cb_t param_cb; /* The callback is only used for BLE Mesh stack, not for the app layer. */ + const uint32_t opcode; /*!< Message opcode */ + const size_t min_len; /*!< Message minimum length */ + esp_ble_mesh_cb_t param_cb; /*!< Callback used to handle message. Initialized by the stack. */ } esp_ble_mesh_model_op_t; -/** Define the terminator for the model operation table, each - * model operation struct array must use this terminator as +/** Define the terminator for the model operation table. + * Each model operation struct array must use this terminator as * the end tag of the operation unit. */ #define ESP_BLE_MESH_MODEL_OP_END {0, 0, 0} /** Abstraction that describes a Mesh Model instance. - * This structure is associated with bt_mesh_model in mesh_access.h + * This structure is associated with struct bt_mesh_model in mesh_access.h */ struct esp_ble_mesh_model { - /* Model ID */ + /** Model ID */ union { const uint16_t model_id; struct { @@ -897,27 +907,27 @@ struct esp_ble_mesh_model { } vnd; }; - /* Internal information, mainly for persistent storage */ - uint8_t element_idx; /* Belongs to Nth element */ - uint8_t model_idx; /* Is the Nth model in the element */ - uint16_t flags; /* Information about what has changed */ + /** Internal information, mainly for persistent storage */ + uint8_t element_idx; /*!< Belongs to Nth element */ + uint8_t model_idx; /*!< Is the Nth model in the element */ + uint16_t flags; /*!< Information about what has changed */ - /* The Element to which this Model belongs */ + /** The Element to which this Model belongs */ esp_ble_mesh_elem_t *element; - /* Model Publication */ + /** Model Publication */ esp_ble_mesh_model_pub_t *const pub; - /* AppKey List */ + /** AppKey List */ uint16_t keys[CONFIG_BLE_MESH_MODEL_KEY_COUNT]; - /* Subscription List (group or virtual addresses) */ + /** Subscription List (group or virtual addresses) */ uint16_t groups[CONFIG_BLE_MESH_MODEL_GROUP_COUNT]; - /* Model operation context */ + /** Model operation context */ esp_ble_mesh_model_op_t *op; - /* Model-specific user data */ + /** Model-specific user data */ void *user_data; }; @@ -927,7 +937,7 @@ struct esp_ble_mesh_model { #define ESP_BLE_MESH_MODEL_NONE ((esp_ble_mesh_model_t []){}) /** Message sending context. - * This structure is associated with bt_mesh_msg_ctx in mesh_access.h + * This structure is associated with struct bt_mesh_msg_ctx in mesh_access.h */ typedef struct { /** NetKey Index of the subnet through which to send the message. */ @@ -962,7 +972,7 @@ typedef struct { } esp_ble_mesh_msg_ctx_t; /** Provisioning properties & capabilities. - * This structure is associated with bt_mesh_prov in mesh_access.h + * This structure is associated with struct bt_mesh_prov in mesh_access.h */ typedef struct { #if CONFIG_BLE_MESH_NODE @@ -982,7 +992,7 @@ typedef struct { /** Flag indicates whether unprovisioned devices support OOB public key */ bool oob_pub_key; - /* This callback is only used for the BLE Mesh stack, not for the app layer */ + /** Callback used to notify to set OOB Public Key. Initialized by the stack. */ esp_ble_mesh_cb_t oob_pub_key_cb; /** Static OOB value */ @@ -1000,136 +1010,154 @@ typedef struct { /** Supported Input OOB Actions */ uint16_t input_actions; - /* These callbacks are only used for the BLE Mesh stack, not for the app layer */ + /** Callback used to output the number. Initialized by the stack. */ esp_ble_mesh_cb_t output_num_cb; + /** Callback used to output the string. Initialized by the stack. */ esp_ble_mesh_cb_t output_str_cb; + /** Callback used to notify to input number/string. Initialized by the stack. */ esp_ble_mesh_cb_t input_cb; + /** Callback used to indicate that link is opened. Initialized by the stack. */ esp_ble_mesh_cb_t link_open_cb; + /** Callback used to indicate that link is closed. Initialized by the stack. */ esp_ble_mesh_cb_t link_close_cb; + /** Callback used to indicate that provisioning is completed. Initialized by the stack. */ esp_ble_mesh_cb_t complete_cb; + /** Callback used to indicate that node has been reset. Initialized by the stack. */ esp_ble_mesh_cb_t reset_cb; #endif /* CONFIG_BLE_MESH_NODE */ #ifdef CONFIG_BLE_MESH_PROVISIONER - /* Provisioner device UUID */ + /** Provisioner device UUID */ const uint8_t *prov_uuid; - /* Primary element address of the provisioner */ + /** Primary element address of the provisioner */ const uint16_t prov_unicast_addr; - /* Pre-incremental unicast address value to be assigned to the first device */ + /** Pre-incremental unicast address value to be assigned to the first device */ uint16_t prov_start_address; - /* Attention timer contained in Provisioning Invite PDU */ + /** Attention timer contained in Provisioning Invite PDU */ uint8_t prov_attention; - /* Provisioning Algorithm for the Provisioner */ + /** Provisioning Algorithm for the Provisioner */ uint8_t prov_algorithm; - /* Provisioner public key oob */ + /** Provisioner public key oob */ uint8_t prov_pub_key_oob; - /* The callback is only used for BLE Mesh stack, not for the app layer */ + /** Callback used to notify to set device OOB Public Key. Initialized by the stack. */ esp_ble_mesh_cb_t provisioner_prov_read_oob_pub_key; - /* Provisioner static oob value */ + /** Provisioner static oob value */ uint8_t *prov_static_oob_val; - /* Provisioner static oob value length */ + /** Provisioner static oob value length */ uint8_t prov_static_oob_len; - /* These callbacks are only used for BLE Mesh stack, not for the app layer */ + /** Callback used to notify to input number/string. Initialized by the stack. */ esp_ble_mesh_cb_t provisioner_prov_input; + /** Callback used to output number/string. Initialized by the stack. */ esp_ble_mesh_cb_t provisioner_prov_output; - /* Key refresh and IV update flag */ + /** Key refresh and IV update flag */ uint8_t flags; - /* IV index */ + /** IV index */ uint32_t iv_index; - /* These callbacks are only used for BLE Mesh stack, not for the app layer */ + /** Callback used to indicate that link is opened. Initialized by the stack. */ esp_ble_mesh_cb_t provisioner_link_open; + /** Callback used to indicate that link is closed. Initialized by the stack. */ esp_ble_mesh_cb_t provisioner_link_close; + /** Callback used to indicate that a device is provisioned. Initialized by the stack. */ esp_ble_mesh_cb_t provisioner_prov_comp; #endif /* CONFIG_BLE_MESH_PROVISIONER */ } esp_ble_mesh_prov_t; -/** Node Composition - * This structure is associated with bt_mesh_comp in mesh_access.h +/** Node Composition data context. + * This structure is associated with struct bt_mesh_comp in mesh_access.h */ typedef struct { - uint16_t cid; - uint16_t pid; - uint16_t vid; + uint16_t cid; /*!< 16-bit SIG-assigned company identifier */ + uint16_t pid; /*!< 16-bit vendor-assigned product identifier */ + uint16_t vid; /*!< 16-bit vendor-assigned product version identifier */ - size_t element_count; - esp_ble_mesh_elem_t *elements; + size_t element_count; /*!< Element count */ + esp_ble_mesh_elem_t *elements; /*!< A sequence of elements */ } esp_ble_mesh_comp_t; +/*!< This enum value is the role of the device */ typedef enum { ROLE_NODE = 0, ROLE_PROVISIONER, ROLE_FAST_PROV, } esp_ble_mesh_dev_role_t; +/** Common parameters of the messages sent by Client Model. */ typedef struct { esp_ble_mesh_opcode_t opcode; /*!< Message opcode */ esp_ble_mesh_model_t *model; /*!< Pointer to the client model structure */ esp_ble_mesh_msg_ctx_t ctx; /*!< The context used to send message */ int32_t msg_timeout; /*!< Timeout value (ms) to get response to the sent message */ - /*!< Note: if using default timeout value in menuconfig, make sure to set this value to 0 */ - uint8_t msg_role; /*!< Role of the device - Node/Provisioner, only used for tx */ + /*!< Note: if using default timeout value in menuconfig, make sure to set this value to 0 */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ } esp_ble_mesh_client_common_param_t; +/*!< Flag which will be set when device is going to be added. */ typedef uint8_t esp_ble_mesh_dev_add_flag_t; -#define ADD_DEV_RM_AFTER_PROV_FLAG BIT(0) -#define ADD_DEV_START_PROV_NOW_FLAG BIT(1) -#define ADD_DEV_FLUSHABLE_DEV_FLAG BIT(2) +#define ADD_DEV_RM_AFTER_PROV_FLAG BIT(0) /*!< Device will be removed from queue after provisioned successfully */ +#define ADD_DEV_START_PROV_NOW_FLAG BIT(1) /*!< Start provisioning device immediately */ +#define ADD_DEV_FLUSHABLE_DEV_FLAG BIT(2) /*!< Device can be remove when queue is full and new device is going to added */ + +/** Information of the device which is going to be added for provisioning. */ typedef struct { - esp_bd_addr_t addr; - esp_ble_addr_type_t addr_type; - uint8_t uuid[16]; - uint16_t oob_info; + esp_bd_addr_t addr; /*!< Device address */ + esp_ble_addr_type_t addr_type; /*!< Device address type */ + uint8_t uuid[16]; /*!< Device UUID */ + uint16_t oob_info; /*!< Device OOB Info */ /*!< ADD_DEV_START_PROV_NOW_FLAG shall not be set if the bearer has both PB-ADV and PB-GATT enabled */ - esp_ble_mesh_prov_bearer_t bearer; + esp_ble_mesh_prov_bearer_t bearer; /*!< Provisioning Bearer */ } esp_ble_mesh_unprov_dev_add_t; #define DEL_DEV_ADDR_FLAG BIT(0) #define DEL_DEV_UUID_FLAG BIT(1) +/** Information of the device which is going to be deleted. */ typedef struct { union { struct { - esp_bd_addr_t addr; - esp_ble_addr_type_t addr_type; + esp_bd_addr_t addr; /*!< Device address */ + esp_ble_addr_type_t addr_type; /*!< Device address type */ }; - uint8_t uuid[16]; + uint8_t uuid[16]; /*!< Device UUID */ }; - uint8_t flag; /*!< BIT0: device address; BIT1: device UUID */ + uint8_t flag; /*!< BIT0: device address; BIT1: device UUID */ } esp_ble_mesh_device_delete_t; #define PROV_DATA_NET_IDX_FLAG BIT(0) #define PROV_DATA_FLAGS_FLAG BIT(1) #define PROV_DATA_IV_INDEX_FLAG BIT(2) +/** Information of the provisioner which is going to be updated. */ typedef struct { union { - uint16_t net_idx; - uint8_t flags; - uint32_t iv_index; + uint16_t net_idx; /*!< NetKey Index */ + uint8_t flags; /*!< Flags */ + uint32_t iv_index; /*!< IV Index */ }; - uint8_t flag; /*!< BIT0: net_idx; BIT1: flags; BIT2: iv_index */ + uint8_t flag; /*!< BIT0: net_idx; BIT1: flags; BIT2: iv_index */ } esp_ble_mesh_prov_data_info_t; +/** Context of fast provisioning which need to be set. */ typedef struct { - uint16_t unicast_min; /* Minimum unicast address used for fast provisioning */ - uint16_t unicast_max; /* Maximum unicast address used for fast provisioning */ - uint16_t net_idx; /* Netkey index used for fast provisioning */ - uint8_t flags; /* Flags used for fast provisioning */ - uint32_t iv_index; /* IV Index used for fast provisioning */ - uint8_t offset; /* Offset of the UUID to be compared */ - uint8_t match_len; /* Length of the UUID to be compared */ - uint8_t match_val[16]; /* Value of UUID to be compared */ + uint16_t unicast_min; /*!< Minimum unicast address used for fast provisioning */ + uint16_t unicast_max; /*!< Maximum unicast address used for fast provisioning */ + uint16_t net_idx; /*!< Netkey index used for fast provisioning */ + uint8_t flags; /*!< Flags used for fast provisioning */ + uint32_t iv_index; /*!< IV Index used for fast provisioning */ + uint8_t offset; /*!< Offset of the UUID to be compared */ + uint8_t match_len; /*!< Length of the UUID to be compared */ + uint8_t match_val[16]; /*!< Value of UUID to be compared */ } esp_ble_mesh_fast_prov_info_t; +/*!< This enum value is the action of fast provisioning */ typedef enum { FAST_PROV_ACT_NONE, FAST_PROV_ACT_ENTER, @@ -1138,6 +1166,7 @@ typedef enum { FAST_PROV_ACT_MAX, } esp_ble_mesh_fast_prov_action_t; +/*!< This enum value is the event of node/provisioner/fast provisioning */ typedef enum { ESP_BLE_MESH_PROV_REGISTER_COMP_EVT, /*!< Initialize BLE Mesh provisioning capabilities and internal data information completion event */ ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT, /*!< Set the unprovisioned device name completion event */ @@ -1177,11 +1206,12 @@ typedef enum { ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT, /*!< Provisioner add local app key completion event */ ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT, /*!< Provisioner bind local model with local app key completion event */ ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_NET_KEY_COMP_EVT, /*!< Provisioner add local network key completion event */ - ESP_BLE_MESH_SET_FAST_PROV_INFO_COMP_EVT, /* !< Set fast provisioning information (e.g. unicast address range, net_idx, etc.) completion event */ - ESP_BLE_MESH_SET_FAST_PROV_ACTION_COMP_EVT, /* !< Set fast provisioning action completion event */ + ESP_BLE_MESH_SET_FAST_PROV_INFO_COMP_EVT, /*!< Set fast provisioning information (e.g. unicast address range, net_idx, etc.) completion event */ + ESP_BLE_MESH_SET_FAST_PROV_ACTION_COMP_EVT, /*!< Set fast provisioning action completion event */ ESP_BLE_MESH_PROV_EVT_MAX, } esp_ble_mesh_prov_cb_event_t; +/*!< This enum value is the event of undefined SIG Models and Vendor Models */ typedef enum { ESP_BLE_MESH_MODEL_OPERATION_EVT, /*!< User-defined models receive messages from peer devices (e.g. get, set, status, etc) event */ ESP_BLE_MESH_MODEL_SEND_COMP_EVT, /*!< User-defined models send messages completion event */ @@ -1192,332 +1222,345 @@ typedef enum { ESP_BLE_MESH_MODEL_EVT_MAX, } esp_ble_mesh_model_cb_event_t; +/** + * @brief BLE Mesh Node/Provisioner callback parameters union + */ typedef union { /** * @brief ESP_BLE_MESH_PROV_REGISTER_COMP_EVT */ struct ble_mesh_prov_register_comp_param { - int err_code; - } prov_register_comp; + int err_code; /*!< Indicate the result of BLE Mesh initialization */ + } prov_register_comp; /*!< Event parameter of ESP_BLE_MESH_PROV_REGISTER_COMP_EVT */ /** * @brief ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT */ struct ble_mesh_set_unprov_dev_name_comp_param { - int err_code; - } node_set_unprov_dev_name_comp; + int err_code; /*!< Indicate the result of setting BLE Mesh device name */ + } node_set_unprov_dev_name_comp; /*!< Event parameter of ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT */ /** * @brief ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT */ struct ble_mesh_prov_enable_comp_param { - int err_code; - } node_prov_enable_comp; + int err_code; /*!< Indicate the result of enabling BLE Mesh device */ + } node_prov_enable_comp; /*!< Event parameter of ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT */ /** * @brief ESP_BLE_MESH_NODE_PROV_DISABLE_COMP_EVT */ struct ble_mesh_prov_disable_comp_param { - int err_code; - } node_prov_disable_comp; + int err_code; /*!< Indicate the result of disabling BLE Mesh device */ + } node_prov_disable_comp; /*!< Event parameter of ESP_BLE_MESH_NODE_PROV_DISABLE_COMP_EVT */ /** * @brief ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT */ struct ble_mesh_link_open_evt_param { - esp_ble_mesh_prov_bearer_t bearer; - } node_prov_link_open; + esp_ble_mesh_prov_bearer_t bearer; /*!< Type of the bearer used when device link is open */ + } node_prov_link_open; /*!< Event parameter of ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT */ /** * @brief ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT */ struct ble_mesh_link_close_evt_param { - esp_ble_mesh_prov_bearer_t bearer; - } node_prov_link_close; + esp_ble_mesh_prov_bearer_t bearer; /*!< Type of the bearer used when device link is closed */ + } node_prov_link_close; /*!< Event parameter of ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT */ /** * @brief ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT */ struct ble_mesh_output_num_evt_param { - esp_ble_mesh_output_action_t action; - uint32_t number; - } node_prov_output_num; + esp_ble_mesh_output_action_t action; /*!< Action of Output OOB Authentication */ + uint32_t number; /*!< Number of Output OOB Authentication */ + } node_prov_output_num; /*!< Event parameter of ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT */ /** * @brief ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT */ struct ble_mesh_output_str_evt_param { - char string[8]; - } node_prov_output_str; + char string[8]; /*!< String of Output OOB Authentication */ + } node_prov_output_str; /*!< Event parameter of ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT */ /** * @brief ESP_BLE_MESH_NODE_PROV_INPUT_EVT */ struct ble_mesh_input_evt_param { - esp_ble_mesh_input_action_t action; - uint8_t size; - } node_prov_input; + esp_ble_mesh_input_action_t action; /*!< Action of Input OOB Authentication */ + uint8_t size; /*!< Size of Input OOB Authentication */ + } node_prov_input; /*!< Event parameter of ESP_BLE_MESH_NODE_PROV_INPUT_EVT */ /** * @brief ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT */ struct ble_mesh_provision_complete_evt_param { - uint16_t net_idx; - uint16_t addr; - uint8_t flags; - uint32_t iv_index; - } node_prov_complete; + uint16_t net_idx; /*!< NetKey Index */ + uint16_t addr; /*!< Primary address */ + uint8_t flags; /*!< Flags */ + uint32_t iv_index; /*!< IV Index */ + } node_prov_complete; /*!< Event parameter of ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT */ /** * @brief ESP_BLE_MESH_NODE_PROV_RESET_EVT */ struct ble_mesh_provision_reset_param { - } node_prov_reset; + } node_prov_reset; /*!< Event parameter of ESP_BLE_MESH_NODE_PROV_RESET_EVT */ /** * @brief ESP_BLE_MESH_NODE_PROV_SET_OOB_PUB_KEY_COMP_EVT */ struct ble_mesh_set_oob_pub_key_comp_param { - int err_code; - } node_prov_set_oob_pub_key_comp; + int err_code; /*!< Indicate the result of setting OOB Public Key */ + } node_prov_set_oob_pub_key_comp; /*!< Event parameter of ESP_BLE_MESH_NODE_PROV_SET_OOB_PUB_KEY_COMP_EVT */ /** * @brief ESP_BLE_MESH_NODE_PROV_INPUT_NUM_COMP_EVT */ struct ble_mesh_input_number_comp_param { - int err_code; - } node_prov_input_num_comp; + int err_code; /*!< Indicate the result of inputting number */ + } node_prov_input_num_comp; /*!< Event parameter of ESP_BLE_MESH_NODE_PROV_INPUT_NUM_COMP_EVT */ /** * @brief ESP_BLE_MESH_NODE_PROV_INPUT_STR_COMP_EVT */ struct ble_mesh_input_string_comp_param { - int err_code; - } node_prov_input_str_comp; + int err_code; /*!< Indicate the result of inputting string */ + } node_prov_input_str_comp; /*!< Event parameter of ESP_BLE_MESH_NODE_PROV_INPUT_STR_COMP_EVT */ /** * @brief ESP_BLE_MESH_NODE_PROXY_IDENTITY_ENABLE_COMP_EVT */ struct ble_mesh_proxy_identity_enable_comp_param { - int err_code; - } node_proxy_identity_enable_comp; + int err_code; /*!< Indicate the result of enabling Mesh Proxy advertising */ + } node_proxy_identity_enable_comp; /*!< Event parameter of ESP_BLE_MESH_NODE_PROXY_IDENTITY_ENABLE_COMP_EVT */ /** * @brief ESP_BLE_MESH_NODE_PROXY_GATT_ENABLE_COMP_EVT */ struct ble_mesh_proxy_gatt_enable_comp_param { - int err_code; - } node_proxy_gatt_enable_comp; + int err_code; /*!< Indicate the result of enabling Mesh Proxy Service */ + } node_proxy_gatt_enable_comp; /*!< Event parameter of ESP_BLE_MESH_NODE_PROXY_GATT_ENABLE_COMP_EVT */ /** * @brief ESP_BLE_MESH_NODE_PROXY_GATT_DISABLE_COMP_EVT */ struct ble_mesh_proxy_gatt_disable_comp_param { - int err_code; - } node_proxy_gatt_disable_comp; + int err_code; /*!< Indicate the result of disabling Mesh Proxy Service */ + } node_proxy_gatt_disable_comp; /*!< Event parameter of ESP_BLE_MESH_NODE_PROXY_GATT_DISABLE_COMP_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT */ struct ble_mesh_provisioner_recv_unprov_adv_pkt_param { - uint8_t dev_uuid[16]; - uint8_t addr[6]; - esp_ble_addr_type_t addr_type; - uint16_t oob_info; - uint8_t adv_type; - esp_ble_mesh_prov_bearer_t bearer; - } provisioner_recv_unprov_adv_pkt; + uint8_t dev_uuid[16]; /*!< Device UUID of the unprovisoned device */ + uint8_t addr[6]; /*!< Device address of the unprovisoned device */ + esp_ble_addr_type_t addr_type; /*!< Device address type */ + uint16_t oob_info; /*!< OOB Info of the unprovisoned device */ + uint8_t adv_type; /*!< Avertising type of the unprovisoned device */ + esp_ble_mesh_prov_bearer_t bearer; /*!< Bearer of the unprovisoned device */ + } provisioner_recv_unprov_adv_pkt; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT */ struct ble_mesh_provisioner_prov_enable_comp_param { - int err_code; - } provisioner_prov_enable_comp; + int err_code; /*!< Indicate the result of enabling BLE Mesh Provisioner */ + } provisioner_prov_enable_comp; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_PROV_DISABLE_COMP_EVT */ struct ble_mesh_provisioner_prov_disable_comp_param { - int err_code; - } provisioner_prov_disable_comp; + int err_code; /*!< Indicate the result of disabling BLE Mesh Provisioner */ + } provisioner_prov_disable_comp; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_PROV_DISABLE_COMP_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT */ struct ble_mesh_provisioner_link_open_evt_param { - esp_ble_mesh_prov_bearer_t bearer; - } provisioner_prov_link_open; + esp_ble_mesh_prov_bearer_t bearer; /*!< Type of the bearer used when Provisioner link is opened */ + } provisioner_prov_link_open; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_PROV_READ_OOB_PUB_KEY_EVT */ struct ble_mesh_provisioner_prov_read_oob_pub_key_evt_param { - uint8_t link_idx; - } provisioner_prov_read_oob_pub_key; + uint8_t link_idx; /*!< Index of the provisioning link */ + } provisioner_prov_read_oob_pub_key; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_PROV_READ_OOB_PUB_KEY_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_PROV_INPUT_EVT */ struct ble_mesh_provisioner_prov_input_evt_param { - esp_ble_mesh_oob_method_t method; - esp_ble_mesh_output_action_t action; - uint8_t size; - uint8_t link_idx; - } provisioner_prov_input; + esp_ble_mesh_oob_method_t method; /*!< Method of device Output OOB Authentication */ + esp_ble_mesh_output_action_t action; /*!< Action of device Output OOB Authentication */ + uint8_t size; /*!< Size of device Output OOB Authentication */ + uint8_t link_idx; /*!< Index of the provisioning link */ + } provisioner_prov_input; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_PROV_INPUT_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_PROV_OUTPUT_EVT */ struct ble_mesh_provisioner_prov_output_evt_param { - esp_ble_mesh_oob_method_t method; - esp_ble_mesh_input_action_t action; - uint8_t size; - uint8_t link_idx; + esp_ble_mesh_oob_method_t method; /*!< Method of device Input OOB Authentication */ + esp_ble_mesh_input_action_t action; /*!< Action of device Input OOB Authentication */ + uint8_t size; /*!< Size of device Input OOB Authentication */ + uint8_t link_idx; /*!< Index of the provisioning link */ union { - char string[8]; - uint32_t number; + char string[8]; /*!< String output by the Provisioner */ + uint32_t number; /*!< Number output by the Provisioner */ }; - } provisioner_prov_output; + } provisioner_prov_output; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_PROV_OUTPUT_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT */ struct ble_mesh_provisioner_link_close_evt_param { - esp_ble_mesh_prov_bearer_t bearer; - uint8_t reason; - } provisioner_prov_link_close; + esp_ble_mesh_prov_bearer_t bearer; /*!< Type of the bearer used when Provisioner link is closed */ + uint8_t reason; /*!< Reason of the closed provisioning link */ + } provisioner_prov_link_close; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT */ struct ble_mesh_provisioner_prov_comp_param { - int node_idx; - esp_ble_mesh_octet16_t device_uuid; - uint16_t unicast_addr; - uint8_t element_num; - uint16_t netkey_idx; - } provisioner_prov_complete; + int node_idx; /*!< Index of the provisioned device */ + esp_ble_mesh_octet16_t device_uuid; /*!< Device UUID of the provisioned device */ + uint16_t unicast_addr; /*!< Primary address of the provisioned device */ + uint8_t element_num; /*!< Element count of the provisioned device */ + uint16_t netkey_idx; /*!< NetKey Index of the provisioned device */ + } provisioner_prov_complete; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT */ struct ble_mesh_provisioner_add_unprov_dev_comp_param { - int err_code; - } provisioner_add_unprov_dev_comp; + int err_code; /*!< Indicate the result of adding device into queue by the Provisioner */ + } provisioner_add_unprov_dev_comp; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_DELETE_DEV_COMP_EVT */ struct ble_mesh_provisioner_delete_dev_comp_param { - int err_code; - } provisioner_delete_dev_comp; + int err_code; /*!< Indicate the result of deleting device by the Provisioner */ + } provisioner_delete_dev_comp; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_DELETE_DEV_COMP_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT */ struct ble_mesh_provisioner_set_dev_uuid_match_comp_param { - int err_code; - } provisioner_set_dev_uuid_match_comp; + int err_code; /*!< Indicate the result of setting Device UUID match value by the Provisioner */ + } provisioner_set_dev_uuid_match_comp; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_SET_PROV_DATA_INFO_COMP_EVT */ struct ble_mesh_provisioner_set_prov_data_info_comp_param { - int err_code; - } provisioner_set_prov_data_info_comp; + int err_code; /*!< Indicate the result of setting provisioning info by the Provisioner */ + } provisioner_set_prov_data_info_comp; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_SET_PROV_DATA_INFO_COMP_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_PROV_READ_OOB_PUB_KEY_COMP_EVT */ struct ble_mesh_provisioner_prov_read_oob_pub_key_comp_param { - int err_code; - } provisioner_prov_read_oob_pub_key_comp; + int err_code; /*!< Indicate the result of setting OOB Public Key by the Provisioner */ + } provisioner_prov_read_oob_pub_key_comp; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_PROV_READ_OOB_PUB_KEY_COMP_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_PROV_INPUT_NUMBER_COMP_EVT */ struct ble_mesh_provisioner_prov_input_num_comp_param { - int err_code; - } provisioner_prov_input_num_comp; + int err_code; /*!< Indicate the result of inputting number by the Provisioner */ + } provisioner_prov_input_num_comp; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_PROV_INPUT_NUMBER_COMP_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_PROV_INPUT_STRING_COMP_EVT */ struct ble_mesh_provisioner_prov_input_str_comp_param { - int err_code; - } provisioner_prov_input_str_comp; + int err_code; /*!< Indicate the result of inputting string by the Provisioner */ + } provisioner_prov_input_str_comp; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_PROV_INPUT_STRING_COMP_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT */ struct ble_mesh_provisioner_set_node_name_comp_param { - int err_code; - int node_index; - } provisioner_set_node_name_comp; + int err_code; /*!< Indicate the result of setting provisioned device name by the Provisioner */ + int node_index; /*!< Index of the provisioned device */ + } provisioner_set_node_name_comp; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT */ struct ble_mesh_provisioner_add_local_app_key_comp_param { - int err_code; - uint16_t app_idx; - } provisioner_add_app_key_comp; + int err_code; /*!< Indicate the result of adding local AppKey by the Provisioner */ + uint16_t app_idx; /*!< AppKey Index */ + } provisioner_add_app_key_comp; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT */ struct ble_mesh_provisioner_bind_local_mod_app_comp_param { - int err_code; - } provisioner_bind_app_key_to_model_comp; + int err_code; /*!< Indicate the result of binding AppKey with model by the Provisioner */ + } provisioner_bind_app_key_to_model_comp; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_NET_KEY_COMP_EVT */ struct ble_mesh_provisioner_add_local_net_key_comp_param { - int err_code; - uint16_t net_idx; - } provisioner_add_net_key_comp; + int err_code; /*!< Indicate the result of adding local NetKey by the Provisioner */ + uint16_t net_idx; /*!< NetKey Index */ + } provisioner_add_net_key_comp; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_NET_KEY_COMP_EVT */ + /** + * @brief ESP_BLE_MESH_SET_FAST_PROV_INFO_COMP_EVT + */ struct ble_mesh_set_fast_prov_info_comp_param { - uint8_t status_unicast; - uint8_t status_net_idx; - uint8_t status_match; - } set_fast_prov_info_comp; + uint8_t status_unicast; /*!< Indicate the result of setting unicast address range of fast provisioning */ + uint8_t status_net_idx; /*!< Indicate the result of setting NetKey Index of fast provisioning */ + uint8_t status_match; /*!< Indicate the result of setting matching Device UUID of fast provisioning */ + } set_fast_prov_info_comp; /*!< Event parameter of ESP_BLE_MESH_SET_FAST_PROV_INFO_COMP_EVT */ + /** + * @brief ESP_BLE_MESH_SET_FAST_PROV_ACTION_COMP_EVT + */ struct ble_mesh_set_fast_prov_action_comp_param { - uint8_t status_action; - } set_fast_prov_action_comp; + uint8_t status_action; /*!< Indicate the result of setting action of fast provisioning */ + } set_fast_prov_action_comp; /*!< Event parameter of ESP_BLE_MESH_SET_FAST_PROV_ACTION_COMP_EVT */ } esp_ble_mesh_prov_cb_param_t; +/** + * @brief BLE Mesh model callback parameters union + */ typedef union { /** * @brief ESP_BLE_MESH_MODEL_OPERATION_EVT */ struct ble_mesh_model_operation_evt_param { - uint32_t opcode; - esp_ble_mesh_model_t *model; - esp_ble_mesh_msg_ctx_t *ctx; - uint16_t length; - uint8_t *msg; - } model_operation; + uint32_t opcode; /*!< Opcode of the recieved message */ + esp_ble_mesh_model_t *model; /*!< Pointer to the model which receives the message */ + esp_ble_mesh_msg_ctx_t *ctx; /*!< Pointer to the context of the received message */ + uint16_t length; /*!< Length of the received message */ + uint8_t *msg; /*!< Value of the received message */ + } model_operation; /*!< Event parameter of ESP_BLE_MESH_MODEL_OPERATION_EVT */ /** * @brief ESP_BLE_MESH_MODEL_SEND_COMP_EVT */ struct ble_mesh_model_send_comp_param { - int err_code; - uint32_t opcode; - esp_ble_mesh_model_t *model; - esp_ble_mesh_msg_ctx_t *ctx; - } model_send_comp; + int err_code; /*!< Indicate the result of sending a message */ + uint32_t opcode; /*!< Opcode of the message */ + esp_ble_mesh_model_t *model; /*!< Pointer to the model which sends the message */ + esp_ble_mesh_msg_ctx_t *ctx; /*!< Context of the message */ + } model_send_comp; /*!< Event parameter of ESP_BLE_MESH_MODEL_SEND_COMP_EVT */ /** - * @brief ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT - */ + * @brief ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT + */ struct ble_mesh_model_publish_comp_param { - int err_code; - esp_ble_mesh_model_t *model; - } model_publish_comp; + int err_code; /*!< Indicate the result of publishing a message */ + esp_ble_mesh_model_t *model; /*!< Pointer to the model which publishes the message */ + } model_publish_comp; /*!< Event parameter of ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT */ /** * @brief ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT */ struct ble_mesh_mod_recv_publish_msg_param { - uint32_t opcode; - esp_ble_mesh_model_t *model; - esp_ble_mesh_msg_ctx_t *ctx; - uint16_t length; - uint8_t *msg; - } client_recv_publish_msg; + uint32_t opcode; /*!< Opcode of the unsoliciated received message */ + esp_ble_mesh_model_t *model; /*!< Pointer to the model which receives the message */ + esp_ble_mesh_msg_ctx_t *ctx; /*!< Pointer to the context of the message */ + uint16_t length; /*!< Length of the received message */ + uint8_t *msg; /*!< Value of the received message */ + } client_recv_publish_msg; /*!< Event parameter of ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT */ /** * @brief ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT */ struct ble_mesh_client_model_send_timeout_param { - uint32_t opcode; - esp_ble_mesh_model_t *model; - esp_ble_mesh_msg_ctx_t *ctx; - } client_send_timeout; + uint32_t opcode; /*!< Opcode of the previously sent message */ + esp_ble_mesh_model_t *model; /*!< Pointer to the model which sends the previous message */ + esp_ble_mesh_msg_ctx_t *ctx; /*!< Pointer to the context of the previous message */ + } client_send_timeout; /*!< Event parameter of ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT */ /** - * @brief ESP_BLE_MESH_MODEL_PUBLISH_UPDATE_EVT - */ + * @brief ESP_BLE_MESH_MODEL_PUBLISH_UPDATE_EVT + */ struct ble_mesh_model_publish_update_evt_param { - esp_ble_mesh_model_t *model; - } model_publish_update; + esp_ble_mesh_model_t *model; /*!< Pointer to the model which is going to update its publish message */ + } model_publish_update; /*!< Event parameter of ESP_BLE_MESH_MODEL_PUBLISH_UPDATE_EVT */ } esp_ble_mesh_model_cb_param_t; +/** Client Model Get/Set message opcode and corresponding Status message opcode */ typedef struct { uint32_t cli_op; /*!< The client message opcode */ uint32_t status_op; /*!< The server status opcode corresponding to the client message opcode */ } esp_ble_mesh_client_op_pair_t; -/*!< Mesh Client Model Context */ +/** Client Model user data context. */ typedef struct { - esp_ble_mesh_model_t *model; + esp_ble_mesh_model_t *model; /*!< Pointer to the client model. Initialized by the stack. */ int op_pair_size; /*!< Size of the op_pair */ const esp_ble_mesh_client_op_pair_t *op_pair; /*!< Table containing get/set message opcode and corresponding status message opcode */ - uint32_t publish_status; /*!< This variable is reserved for BLE Mesh Stack, does not require initializing on the application layer */ - void *internal_data; /*!< Pointer to the structure of the client model internal data */ + uint32_t publish_status; /*!< Callback used to handle the received unsoliciated message. Initialized by the stack. */ + void *internal_data; /*!< Pointer to the internal data of client model */ uint8_t msg_role; /*!< Role of the device (Node/Provisioner) that is going to send messages */ } esp_ble_mesh_client_t; diff --git a/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_config_model_api.c b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_config_model_api.c index 67694eef4e..593927ff2f 100644 --- a/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_config_model_api.c +++ b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_config_model_api.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_generic_model_api.c b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_generic_model_api.c index 82f6ff5850..fdf1f72d63 100644 --- a/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_generic_model_api.c +++ b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_generic_model_api.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_health_model_api.c b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_health_model_api.c index e7df777dc0..cdbdb04ac4 100644 --- a/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_health_model_api.c +++ b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_health_model_api.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_lighting_model_api.c b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_lighting_model_api.c index eea415d618..83f0c98b5b 100644 --- a/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_lighting_model_api.c +++ b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_lighting_model_api.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_sensor_model_api.c b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_sensor_model_api.c index 41072d227f..20ae8bdd5e 100644 --- a/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_sensor_model_api.c +++ b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_sensor_model_api.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_time_scene_model_api.c b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_time_scene_model_api.c index 13823b9787..88c27cea98 100644 --- a/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_time_scene_model_api.c +++ b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_time_scene_model_api.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h index 755e0671b2..66f1d17d4a 100644 --- a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h +++ b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. @@ -45,142 +45,143 @@ ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_CONFIG_CLI, \ NULL, NULL, cli_data) +/** Configuration Server Model context */ typedef struct esp_ble_mesh_cfg_srv { - esp_ble_mesh_model_t *model; + esp_ble_mesh_model_t *model; /*!< Pointer to Configuration Server Model */ - uint8_t net_transmit; /*!< Network Transmit state */ - uint8_t relay; /*!< Relay Mode state */ - uint8_t relay_retransmit; /*!< Relay Retransmit state */ - uint8_t beacon; /*!< Secure Network Beacon state */ - uint8_t gatt_proxy; /*!< GATT Proxy state */ - uint8_t friend_state; /*!< Friend state */ - uint8_t default_ttl; /*!< Default TTL */ + uint8_t net_transmit; /*!< Network Transmit state */ + uint8_t relay; /*!< Relay Mode state */ + uint8_t relay_retransmit; /*!< Relay Retransmit state */ + uint8_t beacon; /*!< Secure Network Beacon state */ + uint8_t gatt_proxy; /*!< GATT Proxy state */ + uint8_t friend_state; /*!< Friend state */ + uint8_t default_ttl; /*!< Default TTL */ /** Heartbeat Publication */ struct { - struct k_delayed_work timer; + struct k_delayed_work timer; /*!< Heartbeat Publication timer */ - uint16_t dst; - uint16_t count; - uint8_t period; - uint8_t ttl; - uint16_t feature; - uint16_t net_idx; + uint16_t dst; /*!< Destination address for Heartbeat messages */ + uint16_t count; /*!< Number of Heartbeat messages to be sent */ + uint8_t period; /*!< Period for sending Heartbeat messages */ + uint8_t ttl; /*!< TTL to be used when sending Heartbeat messages */ + uint16_t feature; /*!< Bit field indicating features that trigger Heartbeat messages when changed */ + uint16_t net_idx; /*!< NetKey Index used by Heartbeat Publication */ } heartbeat_pub; /** Heartbeat Subscription */ struct { - int64_t expiry; + int64_t expiry; /*!< Timestamp when Heartbeat subscription period is expired */ - uint16_t src; - uint16_t dst; - uint16_t count; - uint8_t min_hops; - uint8_t max_hops; + uint16_t src; /*!< Source address for Heartbeat messages */ + uint16_t dst; /*!< Destination address for Heartbeat messages */ + uint16_t count; /*!< Number of Heartbeat messages received */ + uint8_t min_hops; /*!< Minimum hops when receiving Heartbeat messages */ + uint8_t max_hops; /*!< Maximum hops when receiving Heartbeat messages */ /** Optional subscription tracking function */ void (*func)(uint8_t hops, uint16_t feature); } heartbeat_sub; } esp_ble_mesh_cfg_srv_t; -/** Parameters of Composition Data Get. */ +/** Parameters of Config Composition Data Get. */ typedef struct { uint8_t page; /*!< Page number of the Composition Data. */ } esp_ble_mesh_cfg_composition_data_get_t; -/** Parameters of Model Publication Get. */ +/** Parameters of Config Model Publication Get. */ typedef struct { uint16_t element_addr; /*!< The element address */ uint16_t model_id; /*!< The model id */ uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ } esp_ble_mesh_cfg_model_pub_get_t; -/** Parameters of SIG Model Subscription Get. */ +/** Parameters of Config SIG Model Subscription Get. */ typedef struct { uint16_t element_addr; /*!< The element address */ uint16_t model_id; /*!< The model id */ } esp_ble_mesh_cfg_sig_model_sub_get_t; -/** Parameters of Vendor Model Subscription Get. */ +/** Parameters of Config Vendor Model Subscription Get. */ typedef struct { uint16_t element_addr; /*!< The element address */ uint16_t model_id; /*!< The model id */ uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ } esp_ble_mesh_cfg_vnd_model_sub_get_t; -/** Parameters of Application Key Get. */ +/** Parameters of Config AppKey Get. */ typedef struct { uint16_t net_idx; /*!< The network key index */ } esp_ble_mesh_cfg_app_key_get_t; -/** Parameters of Node Identity Get. */ +/** Parameters of Config Node Identity Get. */ typedef struct { uint16_t net_idx; /*!< The network key index */ } esp_ble_mesh_cfg_node_identity_get_t; -/** Parameters of SIG Model App Get. */ +/** Parameters of Config SIG Model App Get. */ typedef struct { uint16_t element_addr; /*!< The element address */ uint16_t model_id; /*!< The model id */ } esp_ble_mesh_cfg_sig_model_app_get_t; -/** Parameters of Vendor Model App Get. */ +/** Parameters of Config Vendor Model App Get. */ typedef struct { uint16_t element_addr; /*!< The element address */ uint16_t model_id; /*!< The model id */ uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ } esp_ble_mesh_cfg_vnd_model_app_get_t; -/** Parameters of Key Refresh Phase Get. */ +/** Parameters of Config Key Refresh Phase Get. */ typedef struct { uint16_t net_idx; /*!< The network key index */ } esp_ble_mesh_cfg_kr_phase_get_t; -/** Parameters of Low Power Node PollTimeout Get. */ +/** Parameters of Config Low Power Node PollTimeout Get. */ typedef struct { uint16_t lpn_addr; /*!< The unicast address of the Low Power node */ } esp_ble_mesh_cfg_lpn_polltimeout_get_t; -/** Parameters of Beacon Set. */ +/** Parameters of Config Beacon Set. */ typedef struct { - uint8_t beacon; + uint8_t beacon; /*!< New Secure Network Beacon state */ } esp_ble_mesh_cfg_beacon_set_t; -/** Parameters of Default TTL Set. */ +/** Parameters of Config Default TTL Set. */ typedef struct { uint8_t ttl; /*!< The default TTL state value */ } esp_ble_mesh_cfg_default_ttl_set_t; -/** Parameters of Friend Set. */ +/** Parameters of Config Friend Set. */ typedef struct { uint8_t friend_state; /*!< The friend state value */ } esp_ble_mesh_cfg_friend_set_t; -/** Parameters of GATT Proxy Set. */ +/** Parameters of Config GATT Proxy Set. */ typedef struct { uint8_t gatt_proxy; /*!< The GATT Proxy state value */ } esp_ble_mesh_cfg_gatt_proxy_set_t; -/** Parameters of Relay Set. */ +/** Parameters of Config Relay Set. */ typedef struct { uint8_t relay; /*!< The relay value */ uint8_t relay_retransmit; /*!< The relay retransmit value */ } esp_ble_mesh_cfg_relay_set_t; -/** Parameters of Network Key Add. */ +/** Parameters of Config NetKey Add. */ typedef struct { uint16_t net_idx; /*!< The network key index */ uint8_t net_key[16]; /*!< The network key value */ } esp_ble_mesh_cfg_net_key_add_t; -/** Parameters of Application Key Add. */ +/** Parameters of Config AppKey Add. */ typedef struct { uint16_t net_idx; /*!< The network key index */ uint16_t app_idx; /*!< The app key index */ uint8_t app_key[16]; /*!< The app key value */ } esp_ble_mesh_cfg_app_key_add_t; -/** Parameters of Model Application Key Bind. */ +/** Parameters of Config Model App Bind. */ typedef struct { uint16_t element_addr; /*!< The element address */ uint16_t model_app_idx; /*!< Index of the app key to bind with the model */ @@ -188,7 +189,7 @@ typedef struct { uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ } esp_ble_mesh_cfg_model_app_bind_t; -/** Parameters of Model Publication Set. */ +/** Parameters of Config Model Publication Set. */ typedef struct { uint16_t element_addr; /*!< The element address */ uint16_t publish_addr; /*!< Value of the publish address */ @@ -201,7 +202,7 @@ typedef struct { uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ } esp_ble_mesh_cfg_model_pub_set_t; -/** Parameters of Model Subscription Add. */ +/** Parameters of Config Model Subscription Add. */ typedef struct { uint16_t element_addr; /*!< The element address */ uint16_t sub_addr; /*!< The address to be added to the Subscription List */ @@ -209,7 +210,7 @@ typedef struct { uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ } esp_ble_mesh_cfg_model_sub_add_t; -/** Parameters of Model Subscription Delete. */ +/** Parameters of Config Model Subscription Delete. */ typedef struct { uint16_t element_addr; /*!< The element address */ uint16_t sub_addr; /*!< The address to be removed from the Subscription List */ @@ -217,7 +218,7 @@ typedef struct { uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ } esp_ble_mesh_cfg_model_sub_delete_t; -/** Parameters of Model Subscription Overwrite. */ +/** Parameters of Config Model Subscription Overwrite. */ typedef struct { uint16_t element_addr; /*!< The element address */ uint16_t sub_addr; /*!< The address to be added to the Subscription List */ @@ -225,7 +226,7 @@ typedef struct { uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ } esp_ble_mesh_cfg_model_sub_overwrite_t; -/** Parameters of Model Subscription Virtual Address Add. */ +/** Parameters of Config Model Subscription Virtual Address Add. */ typedef struct { uint16_t element_addr; /*!< The element address */ uint8_t label_uuid[16]; /*!< The Label UUID of the virtual address to be added to the Subscription List */ @@ -233,7 +234,7 @@ typedef struct { uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ } esp_ble_mesh_cfg_model_sub_va_add_t; -/** Parameters of Model Subscription Virtual Address Delete. */ +/** Parameters of Config Model Subscription Virtual Address Delete. */ typedef struct { uint16_t element_addr; /*!< The element address */ uint8_t label_uuid[16]; /*!< The Label UUID of the virtual address to be removed from the Subscription List */ @@ -241,7 +242,7 @@ typedef struct { uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ } esp_ble_mesh_cfg_model_sub_va_delete_t; -/** Parameters of Model Subscription Virtual Address Overwrite. */ +/** Parameters of Config Model Subscription Virtual Address Overwrite. */ typedef struct { uint16_t element_addr; /*!< The element address */ uint8_t label_uuid[16]; /*!< The Label UUID of the virtual address to be added to the Subscription List */ @@ -249,7 +250,7 @@ typedef struct { uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ } esp_ble_mesh_cfg_model_sub_va_overwrite_t; -/** Parameters of Model Publication Virtual Address Set. */ +/** Parameters of Config Model Publication Virtual Address Set. */ typedef struct { uint16_t element_addr; /*!< The element address */ uint8_t label_uuid[16]; /*!< Value of the Label UUID publish address */ @@ -262,44 +263,44 @@ typedef struct { uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ } esp_ble_mesh_cfg_model_pub_va_set_t; -/** Parameters of Model Subscription Delete All. */ +/** Parameters of Config Model Subscription Delete All. */ typedef struct { uint16_t element_addr; /*!< The element address */ uint16_t model_id; /*!< The model id */ uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ } esp_ble_mesh_cfg_model_sub_delete_all_t; -/** Parameters of Network Key Update. */ +/** Parameters of Config NetKey Update. */ typedef struct { uint16_t net_idx; /*!< The network key index */ uint8_t net_key[16]; /*!< The network key value */ } esp_ble_mesh_cfg_net_key_update_t; -/** Parameters of Network Key Delete. */ +/** Parameters of Config NetKey Delete. */ typedef struct { uint16_t net_idx; /*!< The network key index */ } esp_ble_mesh_cfg_net_key_delete_t; -/** Parameters of Application Key Update. */ +/** Parameters of Config AppKey Update. */ typedef struct { uint16_t net_idx; /*!< The network key index */ uint16_t app_idx; /*!< The app key index */ uint8_t app_key[16]; /*!< The app key value */ } esp_ble_mesh_cfg_app_key_update_t; -/** Parameters of Application Key Delete. */ +/** Parameters of Config AppKey Delete. */ typedef struct { uint16_t net_idx; /*!< The network key index */ uint16_t app_idx; /*!< The app key index */ } esp_ble_mesh_cfg_app_key_delete_t; -/** Parameters of Node Identity Set. */ +/** Parameters of Config Node Identity Set. */ typedef struct { uint16_t net_idx; /*!< The network key index */ uint8_t identity; /*!< New Node Identity state */ } esp_ble_mesh_cfg_node_identity_set_t; -/** Parameters of Model Application Key Unbind. */ +/** Parameters of Config Model App Unbind. */ typedef struct { uint16_t element_addr; /*!< The element address */ uint16_t model_app_idx; /*!< Index of the app key to bind with the model */ @@ -307,32 +308,32 @@ typedef struct { uint16_t company_id; /*!< The company id, if not a vendor model, shall set to 0xFFFF */ } esp_ble_mesh_cfg_model_app_unbind_t; -/** Parameters of Key Refresh Phase Set. */ +/** Parameters of Config Key Refresh Phase Set. */ typedef struct { uint16_t net_idx; /*!< The network key index */ uint8_t transition; /*!< New Key Refresh Phase Transition */ } esp_ble_mesh_cfg_kr_phase_set_t; -/** Parameters of Network Transmit Set. */ +/** Parameters of Config Network Transmit Set. */ typedef struct { uint8_t net_transmit; /*!< Network Transmit State */ } esp_ble_mesh_cfg_net_transmit_set_t; -/** Parameters of Model Heartbeat Publication Set. */ +/** Parameters of Config Model Heartbeat Publication Set. */ typedef struct { - uint16_t dst; - uint8_t count; - uint8_t period; - uint8_t ttl; - uint16_t feature; - uint16_t net_idx; + uint16_t dst; /*!< Destination address for Heartbeat messages */ + uint8_t count; /*!< Number of Heartbeat messages to be sent */ + uint8_t period; /*!< Period for sending Heartbeat messages */ + uint8_t ttl; /*!< TTL to be used when sending Heartbeat messages */ + uint16_t feature; /*!< Bit field indicating features that trigger Heartbeat messages when changed */ + uint16_t net_idx; /*!< NetKey Index */ } esp_ble_mesh_cfg_heartbeat_pub_set_t; -/** Parameters of Model Heartbeat Subscription Set. */ +/** Parameters of Config Model Heartbeat Subscription Set. */ typedef struct { - uint16_t src; - uint16_t dst; - uint8_t period; + uint16_t src; /*!< Source address for Heartbeat messages */ + uint16_t dst; /*!< Destination address for Heartbeat messages */ + uint8_t period; /*!< Period for receiving Heartbeat messages */ } esp_ble_mesh_cfg_heartbeat_sub_set_t; /** @@ -411,28 +412,34 @@ typedef union { esp_ble_mesh_cfg_net_transmit_set_t net_transmit_set; /*!< For ESP_BLE_MESH_MODEL_OP_NETWORK_TRANSMIT_SET */ } esp_ble_mesh_cfg_client_set_state_t; +/** Parameter of Config Beacon Status */ typedef struct { uint8_t beacon; /*!< Secure Network Beacon state value */ } esp_ble_mesh_cfg_beacon_status_cb_t; +/** Parameters of Config Composition Data Status */ typedef struct { uint8_t page; /*!< Page number of the Composition Data */ struct net_buf_simple *composition_data; /*!< Pointer to Composition Data for the identified page */ } esp_ble_mesh_cfg_comp_data_status_cb_t; +/** Parameter of Config Default TTL Status */ typedef struct { uint8_t default_ttl; /*!< Default TTL state value */ } esp_ble_mesh_cfg_default_ttl_status_cb_t; +/** Parameter of Config GATT Proxy Status */ typedef struct { uint8_t gatt_proxy; /*!< GATT Proxy state value */ } esp_ble_mesh_cfg_gatt_proxy_status_cb_t; +/** Parameters of Config Relay Status */ typedef struct { uint8_t relay; /*!< Relay state value */ uint8_t retransmit; /*!< Relay retransmit value(number of retransmissions and number of 10-millisecond steps between retransmissions) */ } esp_ble_mesh_cfg_relay_status_cb_t; +/** Parameters of Config Model Publication Status */ typedef struct { uint8_t status; /*!< Status Code for the request message */ uint16_t element_addr; /*!< Address of the element */ @@ -446,6 +453,7 @@ typedef struct { uint16_t model_id; /*!< Model ID */ } esp_ble_mesh_cfg_model_pub_status_cb_t; +/** Parameters of Config Model Subscription Status */ typedef struct { uint8_t status; /*!< Status Code for the request message */ uint16_t element_addr; /*!< Address of the element */ @@ -454,17 +462,20 @@ typedef struct { uint16_t model_id; /*!< Model ID */ } esp_ble_mesh_cfg_model_sub_status_cb_t; +/** Parameters of Config NetKey Status */ typedef struct { uint8_t status; /*!< Status Code for the request message */ uint16_t net_idx; /*!< Index of the NetKey */ } esp_ble_mesh_cfg_net_key_status_cb_t; +/** Parameters of Config AppKey Status */ typedef struct { uint8_t status; /*!< Status Code for the request message */ uint16_t net_idx; /*!< Index of the NetKey */ uint16_t app_idx; /*!< Index of the application key */ } esp_ble_mesh_cfg_app_key_status_cb_t; +/** Parameters of Config Model App Status */ typedef struct { uint8_t status; /*!< Status Code for the request message */ uint16_t element_addr; /*!< Address of the element */ @@ -473,10 +484,12 @@ typedef struct { uint16_t model_id; /*!< Model ID */ } esp_ble_mesh_cfg_mod_app_status_cb_t; +/** Parameter of Config Friend Status */ typedef struct { uint8_t friend_state; /*!< Friend state value */ } esp_ble_mesh_cfg_friend_status_cb_t; +/** Parameters of Config Heartbeat Publication Status */ typedef struct { uint8_t status; /*!< Status Code for the request message */ uint16_t dst; /*!< Destination address for Heartbeat messages */ @@ -487,6 +500,7 @@ typedef struct { uint16_t net_idx; /*!< Index of the NetKey */ } esp_ble_mesh_cfg_hb_pub_status_cb_t; +/** Parameters of Config Heartbeat Subscription Status */ typedef struct { uint8_t status; /*!< Status Code for the request message */ uint16_t src; /*!< Source address for Heartbeat messages */ @@ -497,11 +511,13 @@ typedef struct { uint8_t max_hops; /*!< Maximum hops when receiving Heartbeat messages */ } esp_ble_mesh_cfg_hb_sub_status_cb_t; +/** Parameters of Config Network Transmit Status */ typedef struct { uint8_t net_trans_count:3; /*!< Number of transmissions for each Network PDU originating from the node */ uint8_t net_trans_step :5; /*!< Maximum hops when receiving Heartbeat messages */ } esp_ble_mesh_cfg_net_trans_status_cb_t; +/** Parameters of Config SIG/Vendor Subscription List */ typedef struct { uint8_t status; /*!< Status Code for the request message */ uint16_t element_addr; /*!< Address of the element */ @@ -510,41 +526,50 @@ typedef struct { struct net_buf_simple *sub_addr; /*!< A block of all addresses from the Subscription List */ } esp_ble_mesh_cfg_model_sub_list_cb_t; +/** Parameter of Config NetKey List */ typedef struct { struct net_buf_simple *net_idx; /*!< A list of NetKey Indexes known to the node */ } esp_ble_mesh_cfg_net_key_list_cb_t; +/** Parameters of Config AppKey List */ typedef struct { uint8_t status; /*!< Status Code for the request message */ uint16_t net_idx; /*!< NetKey Index of the NetKey that the AppKeys are bound to */ struct net_buf_simple *app_idx; /*!< A list of AppKey indexes that are bound to the NetKey identified by NetKeyIndex */ } esp_ble_mesh_cfg_app_key_list_cb_t; +/** Parameters of Config Node Identity Status */ typedef struct { uint8_t status; /*!< Status Code for the request message */ uint16_t net_idx; /*!< Index of the NetKey */ uint8_t identity; /*!< Node Identity state */ } esp_ble_mesh_cfg_node_id_status_cb_t; +/** Parameters of Config SIG/Vendor Model App List */ typedef struct { uint8_t status; /*!< Status Code for the request message */ uint16_t element_addr; /*!< Address of the element */ uint16_t company_id; /*!< Company ID */ uint16_t model_id; /*!< Model ID */ - struct net_buf_simple *app_idx; /*!< All AppKey indexes bound to the Model */ + struct net_buf_simple *app_idx; /*!< All AppKey indexes bound to the Model */ } esp_ble_mesh_cfg_model_app_list_cb_t; +/** Parameters of Config Key Refresh Phase Status */ typedef struct { uint8_t status; /*!< Status Code for the request message */ uint16_t net_idx; /*!< Index of the NetKey */ uint8_t phase; /*!< Key Refresh Phase state */ } esp_ble_mesh_cfg_kr_phase_status_cb_t; +/** Parameters of Config Low Power Node PollTimeout Status */ typedef struct { uint16_t lpn_addr; /*!< The unicast address of the Low Power node */ int32_t poll_timeout; /*!< The current value of the PollTimeout timer of the Low Power node */ } esp_ble_mesh_cfg_lpn_pollto_status_cb_t; +/** + * @brief Configuration Client Model received message union + */ typedef union { esp_ble_mesh_cfg_beacon_status_cb_t beacon_status; /*!< The beacon status value */ esp_ble_mesh_cfg_comp_data_status_cb_t comp_data_status; /*!< The composition data status value */ @@ -569,12 +594,14 @@ typedef union { esp_ble_mesh_cfg_lpn_pollto_status_cb_t lpn_timeout_status; /*!< The low power node poll timeout status value */ } esp_ble_mesh_cfg_client_common_cb_param_t; +/** Configuration Client Model callback parameters */ typedef struct { int error_code; /*!< Appropriate error code */ esp_ble_mesh_client_common_param_t *params; /*!< The client common parameters */ esp_ble_mesh_cfg_client_common_cb_param_t status_cb; /*!< The config status message callback values */ } esp_ble_mesh_cfg_client_cb_param_t; +/** This enum value is the event of Configuration Client Model */ typedef enum { ESP_BLE_MESH_CFG_CLIENT_GET_STATE_EVT, ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT, @@ -583,20 +610,26 @@ typedef enum { ESP_BLE_MESH_CFG_CLIENT_EVT_MAX, } esp_ble_mesh_cfg_client_cb_event_t; +/** Parameter of Config AppKey Add */ typedef struct { - uint16_t app_idx; /* AppKey Index of the Config AppKey Add */ + uint16_t app_idx; /*!< AppKey Index of the Config AppKey Add */ } esp_ble_mesh_cfg_srv_app_key_add_cb_t; +/** + * @brief Configuration Server Model received message union + */ typedef union { - esp_ble_mesh_cfg_srv_app_key_add_cb_t app_key_add; /* !< The Config AppKey Add event value */ + esp_ble_mesh_cfg_srv_app_key_add_cb_t app_key_add; /*!< The Config AppKey Add event value */ } esp_ble_mesh_cfg_server_common_cb_param_t; +/** Configuration Server Model callback parameters */ typedef struct { esp_ble_mesh_model_t *model; /*!< Pointer to the server model structure */ esp_ble_mesh_msg_ctx_t ctx; /*!< The context of the received message */ esp_ble_mesh_cfg_server_common_cb_param_t status_cb; /*!< The received configuration message callback values */ } esp_ble_mesh_cfg_server_cb_param_t; +/** This enum value is the event of Configuration Server Model */ typedef enum { ESP_BLE_MESH_CFG_SERVER_RECV_MSG_EVT, ESP_BLE_MESH_CFG_SERVER_EVT_MAX, @@ -606,11 +639,19 @@ typedef enum { * @brief Bluetooth Mesh Config Client and Server Model functions. */ -/** @brief: event, event code of Config Client Model events; param, parameters of Config Client Model events */ +/** + * @brief Configuration Client Model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ typedef void (* esp_ble_mesh_cfg_client_cb_t)(esp_ble_mesh_cfg_client_cb_event_t event, esp_ble_mesh_cfg_client_cb_param_t *param); -/** @brief: event, event code of Config Client Model events; param, parameters of Config Client Model events */ +/** + * @brief Configuration Server Model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ typedef void (* esp_ble_mesh_cfg_server_cb_t)(esp_ble_mesh_cfg_server_cb_event_t event, esp_ble_mesh_cfg_server_cb_param_t *param); @@ -638,7 +679,7 @@ esp_err_t esp_ble_mesh_register_config_server_callback(esp_ble_mesh_cfg_server_c * @brief Get the value of Config Server Model states using the Config Client Model get messages. * * @note If you want to find the opcodes and corresponding meanings accepted by this API, - * please refer to (@ref esp_ble_mesh_opcode_config_client_get_t). + * please refer to esp_ble_mesh_opcode_config_client_get_t in esp_ble_mesh_defs.h * * @param[in] params: Pointer to BLE Mesh common client parameters. * @param[in] get_state: Pointer to a union, each kind of opcode corresponds to one structure inside. @@ -654,7 +695,7 @@ esp_err_t esp_ble_mesh_config_client_get_state(esp_ble_mesh_client_common_param_ * @brief Set the value of the Configuration Server Model states using the Config Client Model set messages. * * @note If you want to find the opcodes and corresponding meanings accepted by this API, - * please refer to (@ref esp_ble_mesh_opcode_config_client_set_t). + * please refer to esp_ble_mesh_opcode_config_client_set_t in esp_ble_mesh_defs.h * * @param[in] params: Pointer to BLE Mesh common client parameters. * @param[in] set_state: Pointer to a union, each kind of opcode corresponds to one structure inside. diff --git a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_generic_model_api.h b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_generic_model_api.h index a8db2852f7..e34c706302 100644 --- a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_generic_model_api.h +++ b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_generic_model_api.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. @@ -156,109 +156,130 @@ * @brief Bluetooth Mesh Generic Client Model Get and Set parameters structure. */ +/** Parameters of Generic OnOff Set. */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - uint8_t onoff; /* Target value of Generic OnOff state */ - uint8_t tid; /* Transaction ID */ - uint8_t trans_time; /* Time to complete state transition (optional) */ - uint8_t delay; /* Indicate message execution delay (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + uint8_t onoff; /*!< Target value of Generic OnOff state */ + uint8_t tid; /*!< Transaction ID */ + uint8_t trans_time; /*!< Time to complete state transition (optional) */ + uint8_t delay; /*!< Indicate message execution delay (C.1) */ } esp_ble_mesh_gen_onoff_set_t; +/** Parameters of Generic Level Set. */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - int16_t level; /* Target value of Generic Level state */ - uint8_t tid; /* Transaction ID */ - uint8_t trans_time; /* Time to complete state transition (optional) */ - uint8_t delay; /* Indicate message execution delay (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + int16_t level; /*!< Target value of Generic Level state */ + uint8_t tid; /*!< Transaction ID */ + uint8_t trans_time; /*!< Time to complete state transition (optional) */ + uint8_t delay; /*!< Indicate message execution delay (C.1) */ } esp_ble_mesh_gen_level_set_t; +/** Parameters of Generic Delta Set. */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - int32_t level; /* Delta change of Generic Level state */ - uint8_t tid; /* Transaction ID */ - uint8_t trans_time; /* Time to complete state transition (optional) */ - uint8_t delay; /* Indicate message execution delay (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + int32_t level; /*!< Delta change of Generic Level state */ + uint8_t tid; /*!< Transaction ID */ + uint8_t trans_time; /*!< Time to complete state transition (optional) */ + uint8_t delay; /*!< Indicate message execution delay (C.1) */ } esp_ble_mesh_gen_delta_set_t; +/** Parameters of Generic Move Set. */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - int16_t delta_level;/* Delta Level step to calculate Move speed for Generic Level state */ - uint8_t tid; /* Transaction ID */ - uint8_t trans_time; /* Time to complete state transition (optional) */ - uint8_t delay; /* Indicate message execution delay (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + int16_t delta_level; /*!< Delta Level step to calculate Move speed for Generic Level state */ + uint8_t tid; /*!< Transaction ID */ + uint8_t trans_time; /*!< Time to complete state transition (optional) */ + uint8_t delay; /*!< Indicate message execution delay (C.1) */ } esp_ble_mesh_gen_move_set_t; +/** Parameter of Generic Default Transition Time Set. */ typedef struct { - uint8_t trans_time; /* The value of the Generic Default Transition Time state */ + uint8_t trans_time; /*!< The value of the Generic Default Transition Time state */ } esp_ble_mesh_gen_def_trans_time_set_t; +/** Parameter of Generic OnPowerUp Set. */ typedef struct { - uint8_t onpowerup; /* The value of the Generic OnPowerUp state */ + uint8_t onpowerup; /*!< The value of the Generic OnPowerUp state */ } esp_ble_mesh_gen_onpowerup_set_t; +/** Parameters of Generic Power Level Set. */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - uint16_t power; /* Target value of Generic Power Actual state */ - uint8_t tid; /* Transaction ID */ - uint8_t trans_time; /* Time to complete state transition (optional) */ - uint8_t delay; /* Indicate message execution delay (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + uint16_t power; /*!< Target value of Generic Power Actual state */ + uint8_t tid; /*!< Transaction ID */ + uint8_t trans_time; /*!< Time to complete state transition (optional) */ + uint8_t delay; /*!< Indicate message execution delay (C.1) */ } esp_ble_mesh_gen_power_level_set_t; +/** Parameter of Generic Power Default Set. */ typedef struct { - uint16_t power; /* The value of the Generic Power Default state */ + uint16_t power; /*!< The value of the Generic Power Default state */ } esp_ble_mesh_gen_power_default_set_t; +/** Parameters of Generic Power Range Set. */ typedef struct { - uint16_t range_min; /* Value of Range Min field of Generic Power Range state */ - uint16_t range_max; /* Value of Range Max field of Generic Power Range state */ + uint16_t range_min; /*!< Value of Range Min field of Generic Power Range state */ + uint16_t range_max; /*!< Value of Range Max field of Generic Power Range state */ } esp_ble_mesh_gen_power_range_set_t; +/** Parameters of Generic Location Global Set. */ typedef struct { - int32_t global_latitude; /* Global Coordinates (Latitude) */ - int32_t global_longitude; /* Global Coordinates (Longitude) */ - int16_t global_altitude; /* Global Altitude */ + int32_t global_latitude; /*!< Global Coordinates (Latitude) */ + int32_t global_longitude; /*!< Global Coordinates (Longitude) */ + int16_t global_altitude; /*!< Global Altitude */ } esp_ble_mesh_gen_loc_global_set_t; +/** Parameters of Generic Location Local Set. */ typedef struct { - int16_t local_north; /* Local Coordinates (North) */ - int16_t local_east; /* Local Coordinates (East) */ - int16_t local_altitude; /* Local Altitude */ - uint8_t floor_number; /* Floor Number */ - uint16_t uncertainty; /* Uncertainty */ + int16_t local_north; /*!< Local Coordinates (North) */ + int16_t local_east; /*!< Local Coordinates (East) */ + int16_t local_altitude; /*!< Local Altitude */ + uint8_t floor_number; /*!< Floor Number */ + uint16_t uncertainty; /*!< Uncertainty */ } esp_ble_mesh_gen_loc_local_set_t; +/** Parameter of Generic User Property Get. */ typedef struct { - uint16_t property_id; /* Property ID identifying a Generic User Property */ + uint16_t property_id; /*!< Property ID identifying a Generic User Property */ } esp_ble_mesh_gen_user_property_get_t; +/** Parameters of Generic User Property Set. */ typedef struct { - uint16_t property_id; /* Property ID identifying a Generic User Property */ - struct net_buf_simple *property_value; /* Raw value for the User Property */ + uint16_t property_id; /*!< Property ID identifying a Generic User Property */ + struct net_buf_simple *property_value; /*!< Raw value for the User Property */ } esp_ble_mesh_gen_user_property_set_t; +/** Parameter of Generic Admin Property Get. */ typedef struct { - uint16_t property_id; /* Property ID identifying a Generic Admin Property */ + uint16_t property_id; /*!< Property ID identifying a Generic Admin Property */ } esp_ble_mesh_gen_admin_property_get_t; +/** Parameters of Generic Admin Property Set. */ typedef struct { - uint16_t property_id; /* Property ID identifying a Generic Admin Property */ - uint8_t user_access; /* Enumeration indicating user access */ - struct net_buf_simple *property_value; /* Raw value for the Admin Property */ + uint16_t property_id; /*!< Property ID identifying a Generic Admin Property */ + uint8_t user_access; /*!< Enumeration indicating user accessn */ + struct net_buf_simple *property_value; /*!< Raw value for the Admin Property */ } esp_ble_mesh_gen_admin_property_set_t; +/** Parameter of Generic Manufacturer Property Get. */ typedef struct { - uint16_t property_id; /* Property ID identifying a Generic Manufacturer Property */ + uint16_t property_id; /*!< Property ID identifying a Generic Manufacturer Property */ } esp_ble_mesh_gen_manufacturer_property_get_t; +/** Parameters of Generic Manufacturer Property Set. */ typedef struct { - uint16_t property_id; /* Property ID identifying a Generic Manufacturer Property */ - uint8_t user_access; /* Enumeration indicating user access */ + uint16_t property_id; /*!< Property ID identifying a Generic Manufacturer Property */ + uint8_t user_access; /*!< Enumeration indicating user access */ } esp_ble_mesh_gen_manufacturer_property_set_t; +/** Parameter of Generic Client Properties Get. */ typedef struct { - uint16_t property_id; /* A starting Client Property ID present within an element */ + uint16_t property_id; /*!< A starting Client Property ID present within an element */ } esp_ble_mesh_gen_client_properties_get_t; +/** + * @brief Generic Client Model get message union + */ typedef union { esp_ble_mesh_gen_user_property_get_t user_property_get; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET */ esp_ble_mesh_gen_admin_property_get_t admin_property_get; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET*/ @@ -266,6 +287,9 @@ typedef union { esp_ble_mesh_gen_client_properties_get_t client_properties_get; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_GET */ } esp_ble_mesh_generic_client_get_state_t; +/** + * @brief Generic Client Model set message union + */ typedef union { esp_ble_mesh_gen_onoff_set_t onoff_set; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET & ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK */ esp_ble_mesh_gen_level_set_t level_set; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_LEVEL_SET & ESP_BLE_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK */ @@ -287,107 +311,128 @@ typedef union { * @brief Bluetooth Mesh Generic Client Model Get and Set callback parameters structure. */ +/** Parameters of Generic OnOff Status. */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - uint8_t present_onoff; /* Current value of Generic OnOff state */ - uint8_t target_onoff; /* Target value of Generic OnOff state (optional) */ - uint8_t remain_time; /* Time to complete state transition (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + uint8_t present_onoff; /*!< Current value of Generic OnOff state */ + uint8_t target_onoff; /*!< Target value of Generic OnOff state (optional) */ + uint8_t remain_time; /*!< Time to complete state transition (C.1) */ } esp_ble_mesh_gen_onoff_status_cb_t; +/** Parameters of Generic Level Status. */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - int16_t present_level; /* Current value of Generic Level state */ - int16_t target_level; /* Target value of the Generic Level state (optional) */ - uint8_t remain_time; /* Time to complete state transition (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + int16_t present_level; /*!< Current value of Generic Level state */ + int16_t target_level; /*!< Target value of the Generic Level state (optional) */ + uint8_t remain_time; /*!< Time to complete state transition (C.1) */ } esp_ble_mesh_gen_level_status_cb_t; +/** Parameter of Generic Default Transition Time Status. */ typedef struct { - uint8_t trans_time; /* The value of the Generic Default Transition Time state */ + uint8_t trans_time; /*!< The value of the Generic Default Transition Time state */ } esp_ble_mesh_gen_def_trans_time_status_cb_t; +/** Parameter of Generic OnPowerUp Status. */ typedef struct { - uint8_t onpowerup; /* The value of the Generic OnPowerUp state */ + uint8_t onpowerup; /*!< The value of the Generic OnPowerUp state */ } esp_ble_mesh_gen_onpowerup_status_cb_t; +/** Parameters of Generic Power Level Status. */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - uint16_t present_power; /* Current value of Generic Power Actual state */ - uint16_t target_power; /* Target value of Generic Power Actual state (optional) */ - uint8_t remain_time; /* Time to complete state transition (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + uint16_t present_power; /*!< Current value of Generic Power Actual state */ + uint16_t target_power; /*!< Target value of Generic Power Actual state (optional) */ + uint8_t remain_time; /*!< Time to complete state transition (C.1) */ } esp_ble_mesh_gen_power_level_status_cb_t; +/** Parameter of Generic Power Last Status. */ typedef struct { - uint16_t power; /* The value of the Generic Power Last state */ + uint16_t power; /*!< The value of the Generic Power Last state */ } esp_ble_mesh_gen_power_last_status_cb_t; +/** Parameter of Generic Power Default Status. */ typedef struct { - uint16_t power; /* The value of the Generic Default Last state */ + uint16_t power; /*!< The value of the Generic Default Last state */ } esp_ble_mesh_gen_power_default_status_cb_t; +/** Parameters of Generic Power Range Status. */ typedef struct { - uint8_t status_code; /* Status Code for the request message */ - uint16_t range_min; /* Value of Range Min field of Generic Power Range state */ - uint16_t range_max; /* Value of Range Max field of Generic Power Range state */ + uint8_t status_code; /*!< Status Code for the request message */ + uint16_t range_min; /*!< Value of Range Min field of Generic Power Range state */ + uint16_t range_max; /*!< Value of Range Max field of Generic Power Range state */ } esp_ble_mesh_gen_power_range_status_cb_t; +/** Parameters of Generic Battery Status. */ typedef struct { - u32_t battery_level : 8; /* Value of Generic Battery Level state */ - u32_t time_to_discharge : 24; /* Value of Generic Battery Time to Discharge state */ - u32_t time_to_charge : 24; /* Value of Generic Battery Time to Charge state */ - u32_t flags : 8; /* Value of Generic Battery Flags state */ + u32_t battery_level : 8; /*!< Value of Generic Battery Level state */ + u32_t time_to_discharge : 24; /*!< Value of Generic Battery Time to Discharge state */ + u32_t time_to_charge : 24; /*!< Value of Generic Battery Time to Charge state */ + u32_t flags : 8; /*!< Value of Generic Battery Flags state */ } esp_ble_mesh_gen_battery_status_cb_t; +/** Parameters of Generic Location Global Status. */ typedef struct { - int32_t global_latitude; /* Global Coordinates (Latitude) */ - int32_t global_longitude; /* Global Coordinates (Longitude) */ - int16_t global_altitude; /* Global Altitude */ + int32_t global_latitude; /*!< Global Coordinates (Latitude) */ + int32_t global_longitude; /*!< Global Coordinates (Longitude) */ + int16_t global_altitude; /*!< Global Altitude */ } esp_ble_mesh_gen_loc_global_status_cb_t; +/** Parameters of Generic Location Local Status. */ typedef struct { - int16_t local_north; /* Local Coordinates (North) */ - int16_t local_east; /* Local Coordinates (East) */ - int16_t local_altitude; /* Local Altitude */ - uint8_t floor_number; /* Floor Number */ - uint16_t uncertainty; /* Uncertainty */ + int16_t local_north; /*!< Local Coordinates (North) */ + int16_t local_east; /*!< Local Coordinates (East) */ + int16_t local_altitude; /*!< Local Altitude */ + uint8_t floor_number; /*!< Floor Number */ + uint16_t uncertainty; /*!< Uncertainty */ } esp_ble_mesh_gen_loc_local_status_cb_t; +/** Parameter of Generic User Properties Status. */ typedef struct { - struct net_buf_simple *property_ids; /* Buffer contains a sequence of N User Property IDs */ + struct net_buf_simple *property_ids; /*!< Buffer contains a sequence of N User Property IDs */ } esp_ble_mesh_gen_user_properties_status_cb_t; +/** Parameters of Generic User Property Status. */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - uint16_t property_id; /* Property ID identifying a Generic User Property */ - uint8_t user_access; /* Enumeration indicating user access (optional) */ - struct net_buf_simple *property_value; /* Raw value for the User Property (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + uint16_t property_id; /*!< Property ID identifying a Generic User Property */ + uint8_t user_access; /*!< Enumeration indicating user access (optional) */ + struct net_buf_simple *property_value; /*!< Raw value for the User Property (C.1) */ } esp_ble_mesh_gen_user_property_status_cb_t; +/** Parameter of Generic Admin Properties Status. */ typedef struct { - struct net_buf_simple *property_ids; /* Buffer contains a sequence of N Admin Property IDs */ + struct net_buf_simple *property_ids; /*!< Buffer contains a sequence of N Admin Property IDs */ } esp_ble_mesh_gen_admin_properties_status_cb_t; +/** Parameters of Generic Admin Property Status. */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - uint16_t property_id; /* Property ID identifying a Generic Admin Property */ - uint8_t user_access; /* Enumeration indicating user access (optional) */ - struct net_buf_simple *property_value; /* Raw value for the Admin Property (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + uint16_t property_id; /*!< Property ID identifying a Generic Admin Property */ + uint8_t user_access; /*!< Enumeration indicating user access (optional) */ + struct net_buf_simple *property_value; /*!< Raw value for the Admin Property (C.1) */ } esp_ble_mesh_gen_admin_property_status_cb_t; +/** Parameter of Generic Manufacturer Properties Status. */ typedef struct { - struct net_buf_simple *property_ids; /* Buffer contains a sequence of N Manufacturer Property IDs */ + struct net_buf_simple *property_ids; /*!< Buffer contains a sequence of N Manufacturer Property IDs */ } esp_ble_mesh_gen_manufacturer_properties_status_cb_t; +/** Parameters of Generic Manufacturer Property Status. */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - uint16_t property_id; /* Property ID identifying a Generic Manufacturer Property */ - uint8_t user_access; /* Enumeration indicating user access (optional) */ - struct net_buf_simple *property_value; /* Raw value for the Manufacturer Property (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + uint16_t property_id; /*!< Property ID identifying a Generic Manufacturer Property */ + uint8_t user_access; /*!< Enumeration indicating user access (optional) */ + struct net_buf_simple *property_value; /*!< Raw value for the Manufacturer Property (C.1) */ } esp_ble_mesh_gen_manufacturer_property_status_cb_t; +/** Parameter of Generic Client Properties Status. */ typedef struct { - struct net_buf_simple *property_ids; /* Buffer contains a sequence of N Client Property IDs */ + struct net_buf_simple *property_ids; /*!< Buffer contains a sequence of N Client Property IDs */ } esp_ble_mesh_gen_client_properties_status_cb_t; +/** + * @brief Generic Client Model received message union + */ typedef union { esp_ble_mesh_gen_onoff_status_cb_t onoff_status; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS */ esp_ble_mesh_gen_level_status_cb_t level_status; /*!< For ESP_BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS */ @@ -409,12 +454,14 @@ typedef union { esp_ble_mesh_gen_client_properties_status_cb_t client_properties_status; /*!< ESP_BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS */ } esp_ble_mesh_gen_client_status_cb_t; +/** Generic Client Model callback parameters */ typedef struct { int error_code; /*!< Appropriate error code */ esp_ble_mesh_client_common_param_t *params; /*!< The client common parameters. */ esp_ble_mesh_gen_client_status_cb_t status_cb; /*!< The generic status message callback values */ } esp_ble_mesh_generic_client_cb_param_t; +/** This enum value is the event of Generic Client Model */ typedef enum { ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT, ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT, @@ -427,7 +474,11 @@ typedef enum { * @brief Bluetooth Mesh Generic Client Model function. */ -/** @brief: event, event code of Generic Client Model events; param, parameters of Generic Client Model events */ +/** + * @brief Generic Client Model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ typedef void (* esp_ble_mesh_generic_client_cb_t)(esp_ble_mesh_generic_client_cb_event_t event, esp_ble_mesh_generic_client_cb_param_t *param); @@ -445,7 +496,7 @@ esp_err_t esp_ble_mesh_register_generic_client_callback(esp_ble_mesh_generic_cli * @brief Get the value of Generic Server Model states using the Generic Client Model get messages. * * @note If you want to find the opcodes and corresponding meanings accepted by this API, - * please refer to (@ref esp_ble_mesh_generic_message_opcode_t). + * please refer to esp_ble_mesh_generic_message_opcode_t in esp_ble_mesh_defs.h * * @param[in] params: Pointer to BLE Mesh common client parameters. * @param[in] get_state: Pointer to generic get message value. @@ -461,7 +512,7 @@ esp_err_t esp_ble_mesh_generic_client_get_state(esp_ble_mesh_client_common_param * @brief Set the value of Generic Server Model states using the Generic Client Model set messages. * * @note If you want to find the opcodes and corresponding meanings accepted by this API, - * please refer to (@ref esp_ble_mesh_generic_message_opcode_t). + * please refer to esp_ble_mesh_generic_message_opcode_t in esp_ble_mesh_defs.h * * @param[in] params: Pointer to BLE Mesh common client parameters. * @param[in] set_state: Pointer to generic set message value. diff --git a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_health_model_api.h b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_health_model_api.h index 687bdc604e..b35cb0e0b1 100644 --- a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_health_model_api.h +++ b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_health_model_api.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. @@ -47,63 +47,65 @@ ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_HEALTH_CLI, \ NULL, NULL, cli_data) +/** Health Server Model callbacks */ typedef struct { - /* Fetch current faults */ + /** Fetch current faults */ int (*fault_get_cur)(esp_ble_mesh_model_t *model, uint8_t *test_id, uint16_t *company_id, uint8_t *faults, uint8_t *fault_count); - /* Fetch registered faults */ + /** Fetch registered faults */ int (*fault_get_reg)(esp_ble_mesh_model_t *model, uint16_t company_id, uint8_t *test_id, uint8_t *faults, uint8_t *fault_count); - /* Clear registered faults */ + /** Clear registered faults */ int (*fault_clear)(esp_ble_mesh_model_t *model, uint16_t company_id); - /* Run a specific test */ + /** Run a specific test */ int (*fault_test)(esp_ble_mesh_model_t *model, uint8_t test_id, uint16_t company_id); - /* Attention on */ + /** Attention on */ void (*attn_on)(esp_ble_mesh_model_t *model); - /* Attention off */ + /** Attention off */ void (*attn_off)(esp_ble_mesh_model_t *model); } esp_ble_mesh_health_srv_cb_t; -/** ESP BLE Mesh Health Server Model Context */ +/** Health Server Model Context */ typedef struct { + /** Pointer to Health Server Model */ esp_ble_mesh_model_t *model; - /* Optional callback struct */ + /** Optional callback struct */ const esp_ble_mesh_health_srv_cb_t *cb; - /* Attention Timer state */ + /** Attention Timer state */ struct k_delayed_work attn_timer; } esp_ble_mesh_health_srv_t; -/** BLE Mesh Health Client Model fault get Context */ +/** Parameter of Health Fault Get */ typedef struct { - uint16_t company_id; /*!< Bluetooth assigned 16-bit Company ID */ + uint16_t company_id; /*!< Bluetooth assigned 16-bit Company ID */ } esp_ble_mesh_health_fault_get_t; -/** Mesh Health Client Model attention set Context */ +/** Parameter of Health Attention Set */ typedef struct { - uint8_t attention; /*!< Value of the Attention Timer state */ + uint8_t attention; /*!< Value of the Attention Timer state */ } esp_ble_mesh_health_attention_set_t; -/** Mesh Health client Model period set Context */ +/** Parameter of Health Period Set */ typedef struct { - uint8_t fast_period_divisor; /*!< Divider for the Publish Period */ + uint8_t fast_period_divisor; /*!< Divider for the Publish Period */ } esp_ble_mesh_health_period_set_t; -/** BLE Mesh Health Client Model fault test Context */ +/** Parameter of Health Fault Test */ typedef struct { - uint16_t company_id; /*!< Bluetooth assigned 16-bit Company ID */ - uint8_t test_id; /*!< ID of a specific test to be performed */ + uint16_t company_id; /*!< Bluetooth assigned 16-bit Company ID */ + uint8_t test_id; /*!< ID of a specific test to be performed */ } esp_ble_mesh_health_fault_test_t; -/** BLE Mesh Health Client Model fault clear Context */ +/** Parameter of Health Fault Clear */ typedef struct { - uint16_t company_id; /*!< Bluetooth assigned 16-bit Company ID */ + uint16_t company_id; /*!< Bluetooth assigned 16-bit Company ID */ } esp_ble_mesh_health_fault_clear_t; /** @@ -134,26 +136,33 @@ typedef union { esp_ble_mesh_health_fault_clear_t fault_clear; /*!< For ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_CLEAR or ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_CLEAR_UNACK. */ } esp_ble_mesh_health_client_set_state_t; +/** Parameters of Health Current Status */ typedef struct { uint8_t test_id; /*!< ID of a most recently performed test */ uint16_t company_id; /*!< Bluetooth assigned 16-bit Company ID */ struct net_buf_simple *fault_array; /*!< FaultArray field contains a sequence of 1-octet fault values */ } esp_ble_mesh_health_current_status_cb_t; +/** Parameters of Health Fault Status */ typedef struct { uint8_t test_id; /*!< ID of a most recently performed test */ uint16_t company_id; /*!< Bluetooth assigned 16-bit Company ID */ struct net_buf_simple *fault_array; /*!< FaultArray field contains a sequence of 1-octet fault values */ } esp_ble_mesh_health_fault_status_cb_t; +/** Parameter of Health Period Status */ typedef struct { uint8_t fast_period_divisor; /*!< Divider for the Publish Period */ } esp_ble_mesh_health_period_status_cb_t; +/** Parameter of Health Attention Status */ typedef struct { uint8_t attention; /*!< Value of the Attention Timer state */ } esp_ble_mesh_health_attention_status_cb_t; +/** + * @brief Health Client Model received message union + */ typedef union { esp_ble_mesh_health_current_status_cb_t current_status; /*!< The health current status value */ esp_ble_mesh_health_fault_status_cb_t fault_status; /*!< The health fault status value */ @@ -161,12 +170,14 @@ typedef union { esp_ble_mesh_health_attention_status_cb_t attention_status; /*!< The health attention status value */ } esp_ble_mesh_health_client_common_cb_param_t; +/** Health Client Model callback parameters */ typedef struct { int error_code; /*!< Appropriate error code */ esp_ble_mesh_client_common_param_t *params; /*!< The client common parameters. */ esp_ble_mesh_health_client_common_cb_param_t status_cb; /*!< The health message status callback values */ } esp_ble_mesh_health_client_cb_param_t; +/** This enum value is the event of Health Client Model */ typedef enum { ESP_BLE_MESH_HEALTH_CLIENT_GET_STATE_EVT, ESP_BLE_MESH_HEALTH_CLIENT_SET_STATE_EVT, @@ -175,10 +186,12 @@ typedef enum { ESP_BLE_MESH_HEALTH_CLIENT_EVT_MAX, } esp_ble_mesh_health_client_cb_event_t; +/** Health Server Model callback parameter */ typedef struct { int error_code; /*!< Appropriate error code */ } esp_ble_mesh_health_server_cb_param_t; +/** This enum value is the event of Health Server Model */ typedef enum { ESP_BLE_MESH_HEALTH_SERVER_FAULT_UPDATE_COMPLETE_EVT, ESP_BLE_MESH_HEALTH_SERVER_EVT_MAX, @@ -188,11 +201,19 @@ typedef enum { * @brief Bluetooth Mesh Health Client and Server Model function. */ -/** @brief: event, event code of Health Client Model event; param, parameters of Health Client Model event) */ +/** + * @brief Health Client Model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ typedef void (* esp_ble_mesh_health_client_cb_t)(esp_ble_mesh_health_client_cb_event_t event, esp_ble_mesh_health_client_cb_param_t *param); -/** @brief: event, event code of Health Server Model event; param, parameters of Health Server Model event) */ +/** + * @brief Health Server Model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ typedef void (* esp_ble_mesh_health_server_cb_t)(esp_ble_mesh_health_server_cb_event_t event, esp_ble_mesh_health_server_cb_param_t *param); @@ -220,7 +241,7 @@ esp_err_t esp_ble_mesh_register_health_server_callback(esp_ble_mesh_health_serve * @brief This function is called to get the Health Server states using the Health Client Model get messages. * * @note If you want to find the opcodes and corresponding meanings accepted by this API, - * please refer to (@ref esp_ble_mesh_opcode_health_client_get_t). + * please refer to esp_ble_mesh_opcode_health_client_get_t in esp_ble_mesh_defs.h * * @param[in] params: Pointer to BLE Mesh common client parameters. * @param[in] get_state: Pointer to a union, each kind of opcode corresponds to one structure inside. @@ -236,7 +257,7 @@ esp_err_t esp_ble_mesh_health_client_get_state(esp_ble_mesh_client_common_param_ * @brief This function is called to set the Health Server states using the Health Client Model set messages. * * @note If you want to find the opcodes and corresponding meanings accepted by this API, - * please refer to (@ref esp_ble_mesh_opcode_health_client_set_t). + * please refer to esp_ble_mesh_opcode_health_client_set_t in esp_ble_mesh_defs.h * * @param[in] params: Pointer to BLE Mesh common client parameters. * @param[in] set_state: Pointer to a union, each kind of opcode corresponds to one structure inside. diff --git a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h index ab119a48bc..d40ead593b 100644 --- a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h +++ b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. @@ -106,152 +106,179 @@ * @brief Bluetooth Mesh Light Lightness Client Model Get and Set parameters structure. */ +/** Parameters of Light Lightness Set */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - u16_t lightness; /* Target value of light lightness actual state */ - u8_t tid; /* Transaction ID */ - u8_t trans_time; /* Time to complete state transition (optional) */ - u8_t delay; /* Indicate message execution delay (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + u16_t lightness; /*!< Target value of light lightness actual state */ + u8_t tid; /*!< Transaction ID */ + u8_t trans_time; /*!< Time to complete state transition (optional) */ + u8_t delay; /*!< Indicate message execution delay (C.1) */ } esp_ble_mesh_light_lightness_set_t; +/** Parameters of Light Lightness Linear Set */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - u16_t lightness; /* Target value of light lightness linear state */ - u8_t tid; /* Transaction ID */ - u8_t trans_time; /* Time to complete state transition (optional) */ - u8_t delay; /* Indicate message execution delay (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + u16_t lightness; /*!< Target value of light lightness linear state */ + u8_t tid; /*!< Transaction ID */ + u8_t trans_time; /*!< Time to complete state transition (optional) */ + u8_t delay; /*!< Indicate message execution delay (C.1) */ } esp_ble_mesh_light_lightness_linear_set_t; +/** Parameter of Light Lightness Default Set */ typedef struct { - u16_t lightness; /* The value of the Light Lightness Default state */ + u16_t lightness; /*!< The value of the Light Lightness Default state */ } esp_ble_mesh_light_lightness_default_set_t; +/** Parameters of Light Lightness Range Set */ typedef struct { - u16_t range_min; /* Value of range min field of light lightness range state */ - u16_t range_max; /* Value of range max field of light lightness range state */ + u16_t range_min; /*!< Value of range min field of light lightness range state */ + u16_t range_max; /*!< Value of range max field of light lightness range state */ } esp_ble_mesh_light_lightness_range_set_t; +/** Parameters of Light CTL Set */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - u16_t ctl_lightness; /* Target value of light ctl lightness state */ - u16_t ctl_temperatrue; /* Target value of light ctl temperature state */ - s16_t ctl_delta_uv; /* Target value of light ctl delta UV state */ - u8_t tid; /* Transaction ID */ - u8_t trans_time; /* Time to complete state transition (optional) */ - u8_t delay; /* Indicate message execution delay (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + u16_t ctl_lightness; /*!< Target value of light ctl lightness state */ + u16_t ctl_temperatrue; /*!< Target value of light ctl temperature state */ + s16_t ctl_delta_uv; /*!< Target value of light ctl delta UV state */ + u8_t tid; /*!< Transaction ID */ + u8_t trans_time; /*!< Time to complete state transition (optional) */ + u8_t delay; /*!< Indicate message execution delay (C.1) */ } esp_ble_mesh_light_ctl_set_t; +/** Parameters of Light CTL Temperature Set */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - u16_t ctl_temperatrue; /* Target value of light ctl temperature state */ - s16_t ctl_delta_uv; /* Target value of light ctl delta UV state */ - u8_t tid; /* Transaction ID */ - u8_t trans_time; /* Time to complete state transition (optional) */ - u8_t delay; /* Indicate message execution delay (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + u16_t ctl_temperatrue; /*!< Target value of light ctl temperature state */ + s16_t ctl_delta_uv; /*!< Target value of light ctl delta UV state */ + u8_t tid; /*!< Transaction ID */ + u8_t trans_time; /*!< Time to complete state transition (optional) */ + u8_t delay; /*!< Indicate message execution delay (C.1) */ } esp_ble_mesh_light_ctl_temperature_set_t; +/** Parameters of Light CTL Temperature Range Set */ typedef struct { - u16_t range_min; /* Value of temperature range min field of light ctl temperature range state */ - u16_t range_max; /* Value of temperature range max field of light ctl temperature range state */ + u16_t range_min; /*!< Value of temperature range min field of light ctl temperature range state */ + u16_t range_max; /*!< Value of temperature range max field of light ctl temperature range state */ } esp_ble_mesh_light_ctl_temperature_range_set_t; +/** Parameters of Light CTL Default Set */ typedef struct { - u16_t lightness; /* Value of light lightness default state */ - u16_t temperature; /* Value of light temperature default state */ - s16_t delta_uv; /* Value of light delta UV default state */ + u16_t lightness; /*!< Value of light lightness default state */ + u16_t temperature; /*!< Value of light temperature default state */ + s16_t delta_uv; /*!< Value of light delta UV default state */ } esp_ble_mesh_light_ctl_default_set_t; +/** Parameters of Light HSL Set */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - u16_t hsl_lightness; /* Target value of light hsl lightness state */ - u16_t hsl_hue; /* Target value of light hsl hue state */ - u16_t hsl_saturation; /* Target value of light hsl saturation state */ - u8_t tid; /* Transaction ID */ - u8_t trans_time; /* Time to complete state transition (optional) */ - u8_t delay; /* Indicate message execution delay (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + u16_t hsl_lightness; /*!< Target value of light hsl lightness state */ + u16_t hsl_hue; /*!< Target value of light hsl hue state */ + u16_t hsl_saturation; /*!< Target value of light hsl saturation state */ + u8_t tid; /*!< Transaction ID */ + u8_t trans_time; /*!< Time to complete state transition (optional) */ + u8_t delay; /*!< Indicate message execution delay (C.1) */ } esp_ble_mesh_light_hsl_set_t; +/** Parameters of Light HSL Hue Set */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - u16_t hue; /* Target value of light hsl hue state */ - u8_t tid; /* Transaction ID */ - u8_t trans_time; /* Time to complete state transition (optional) */ - u8_t delay; /* Indicate message execution delay (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + u16_t hue; /*!< Target value of light hsl hue state */ + u8_t tid; /*!< Transaction ID */ + u8_t trans_time; /*!< Time to complete state transition (optional) */ + u8_t delay; /*!< Indicate message execution delay (C.1) */ } esp_ble_mesh_light_hsl_hue_set_t; +/** Parameters of Light HSL Saturation Set */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - u16_t saturation; /* Target value of light hsl hue state */ - u8_t tid; /* Transaction ID */ - u8_t trans_time; /* Time to complete state transition (optional) */ - u8_t delay; /* Indicate message execution delay (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + u16_t saturation; /*!< Target value of light hsl hue state */ + u8_t tid; /*!< Transaction ID */ + u8_t trans_time; /*!< Time to complete state transition (optional) */ + u8_t delay; /*!< Indicate message execution delay (C.1) */ } esp_ble_mesh_light_hsl_saturation_set_t; +/** Parameters of Light HSL Default Set */ typedef struct { - u16_t lightness; /* Value of light lightness default state */ - u16_t hue; /* Value of light hue default state */ - u16_t saturation; /* Value of light saturation default state */ + u16_t lightness; /*!< Value of light lightness default state */ + u16_t hue; /*!< Value of light hue default state */ + u16_t saturation; /*!< Value of light saturation default state */ } esp_ble_mesh_light_hsl_default_set_t; -typedef struct { - u16_t hue_range_min; /* Value of hue range min field of light hsl hue range state */ - u16_t hue_range_max; /* Value of hue range max field of light hsl hue range state */ - u16_t saturation_range_min; /* Value of saturation range min field of light hsl saturation range state */ - u16_t saturation_range_max; /* Value of saturation range max field of light hsl saturation range state */ +/** Parameters of Light HSL Range Set */ +typedef struct { + u16_t hue_range_min; /*!< Value of hue range min field of light hsl hue range state */ + u16_t hue_range_max; /*!< Value of hue range max field of light hsl hue range state */ + u16_t saturation_range_min; /*!< Value of saturation range min field of light hsl saturation range state */ + u16_t saturation_range_max; /*!< Value of saturation range max field of light hsl saturation range state */ } esp_ble_mesh_light_hsl_range_set_t; -typedef struct { - bool op_en; /* Indicate whether optional parameters included */ - u16_t xyl_lightness; /* The target value of the Light xyL Lightness state */ - u16_t xyl_x; /* The target value of the Light xyL x state */ - u16_t xyl_y; /* The target value of the Light xyL y state */ - u8_t tid; /* Transaction Identifier */ - u8_t trans_time; /* Time to complete state transition (optional) */ - u8_t delay; /* Indicate message execution delay (C.1) */ +/** Parameters of Light xyL Set */ +typedef struct { + bool op_en; /*!< Indicate whether optional parameters included */ + u16_t xyl_lightness; /*!< The target value of the Light xyL Lightness state */ + u16_t xyl_x; /*!< The target value of the Light xyL x state */ + u16_t xyl_y; /*!< The target value of the Light xyL y state */ + u8_t tid; /*!< Transaction Identifier */ + u8_t trans_time; /*!< Time to complete state transition (optional) */ + u8_t delay; /*!< Indicate message execution delay (C.1) */ } esp_ble_mesh_light_xyl_set_t; -typedef struct { - u16_t lightness; /* The value of the Light Lightness Default state */ - u16_t xyl_x; /* The value of the Light xyL x Default state */ - u16_t xyl_y; /* The value of the Light xyL y Default state */ +/** Parameters of Light xyL Default Set */ +typedef struct { + u16_t lightness; /*!< The value of the Light Lightness Default state */ + u16_t xyl_x; /*!< The value of the Light xyL x Default state */ + u16_t xyl_y; /*!< The value of the Light xyL y Default state */ } esp_ble_mesh_light_xyl_default_set_t; -typedef struct { - u16_t xyl_x_range_min; /* The value of the xyL x Range Min field of the Light xyL x Range state */ - u16_t xyl_x_range_max; /* The value of the xyL x Range Max field of the Light xyL x Range state */ - u16_t xyl_y_range_min; /* The value of the xyL y Range Min field of the Light xyL y Range state */ - u16_t xyl_y_range_max; /* The value of the xyL y Range Max field of the Light xyL y Range state */ +/** Parameters of Light xyL Range Set */ +typedef struct { + u16_t xyl_x_range_min; /*!< The value of the xyL x Range Min field of the Light xyL x Range state */ + u16_t xyl_x_range_max; /*!< The value of the xyL x Range Max field of the Light xyL x Range state */ + u16_t xyl_y_range_min; /*!< The value of the xyL y Range Min field of the Light xyL y Range state */ + u16_t xyl_y_range_max; /*!< The value of the xyL y Range Max field of the Light xyL y Range state */ } esp_ble_mesh_light_xyl_range_set_t; -typedef struct { - u8_t mode; /* The target value of the Light LC Mode state */ +/** Parameter of Light LC Mode Set */ +typedef struct { + u8_t mode; /*!< The target value of the Light LC Mode state */ } esp_ble_mesh_light_lc_mode_set_t; -typedef struct { - u8_t mode; /* The target value of the Light LC Occupancy Mode state */ +/** Parameter of Light LC OM Set */ +typedef struct { + u8_t mode; /*!< The target value of the Light LC Occupancy Mode state */ } esp_ble_mesh_light_lc_om_set_t; -typedef struct { - bool op_en; /* Indicate whether optional parameters included */ - u8_t light_onoff; /* The target value of the Light LC Light OnOff state */ - u8_t tid; /* Transaction Identifier */ - u8_t trans_time; /* Time to complete state transition (optional) */ - u8_t delay; /* Indicate message execution delay (C.1) */ +/** Parameters of Light LC Light OnOff Set */ +typedef struct { + bool op_en; /*!< Indicate whether optional parameters included */ + u8_t light_onoff; /*!< The target value of the Light LC Light OnOff state */ + u8_t tid; /*!< Transaction Identifier */ + u8_t trans_time; /*!< Time to complete state transition (optional) */ + u8_t delay; /*!< Indicate message execution delay (C.1) */ } esp_ble_mesh_light_lc_light_onoff_set_t; -typedef struct { - u16_t property_id; /* Property ID identifying a Light LC Property */ +/** Parameter of Light LC Property Get */ +typedef struct { + u16_t property_id; /*!< Property ID identifying a Light LC Property */ } esp_ble_mesh_light_lc_property_get_t; -typedef struct { - u16_t property_id; /* Property ID identifying a Light LC Property */ - struct net_buf_simple *property_value; /* Raw value for the Light LC Property */ +/** Parameters of Light LC Property Set */ +typedef struct { + u16_t property_id; /*!< Property ID identifying a Light LC Property */ + struct net_buf_simple *property_value; /*!< Raw value for the Light LC Property */ } esp_ble_mesh_light_lc_property_set_t; +/** + * @brief Lighting Client Model get message union + */ typedef union { esp_ble_mesh_light_lc_property_get_t lc_property_get; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_GET */ } esp_ble_mesh_light_client_get_state_t; +/** + * @brief Lighting Client Model set message union + */ typedef union { esp_ble_mesh_light_lightness_set_t lightness_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET_UNACK */ esp_ble_mesh_light_lightness_linear_set_t lightness_linear_set; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET & ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET_UNACK */ @@ -279,158 +306,184 @@ typedef union { * @brief Bluetooth Mesh Light Lightness Client Model Get and Set callback parameters structure. */ +/** Parameters of Light Lightness Status */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - u16_t present_lightness; /* Current value of light lightness actual state */ - u16_t target_lightness; /* Target value of light lightness actual state (optional) */ - u8_t remain_time; /* Time to complete state transition (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + u16_t present_lightness; /*!< Current value of light lightness actual state */ + u16_t target_lightness; /*!< Target value of light lightness actual state (optional) */ + u8_t remain_time; /*!< Time to complete state transition (C.1) */ } esp_ble_mesh_light_lightness_status_cb_t; +/** Parameters of Light Lightness Linear Status */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - u16_t present_lightness; /* Current value of light lightness linear state */ - u16_t target_lightness; /* Target value of light lightness linear state (optional) */ - u8_t remain_time; /* Time to complete state transition (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + u16_t present_lightness; /*!< Current value of light lightness linear state */ + u16_t target_lightness; /*!< Target value of light lightness linear state (optional) */ + u8_t remain_time; /*!< Time to complete state transition (C.1) */ } esp_ble_mesh_light_lightness_linear_status_cb_t; +/** Parameter of Light Lightness Last Status */ typedef struct { - u16_t lightness; /* The value of the Light Lightness Last state */ + u16_t lightness; /*!< The value of the Light Lightness Last state */ } esp_ble_mesh_light_lightness_last_status_cb_t; +/** Parameter of Light Lightness Default Status */ typedef struct { - u16_t lightness; /* The value of the Light Lightness default State */ + u16_t lightness; /*!< The value of the Light Lightness default State */ } esp_ble_mesh_light_lightness_default_status_cb_t; +/** Parameters of Light Lightness Range Status */ typedef struct { - u8_t status_code; /* Status Code for the request message */ - u16_t range_min; /* Value of range min field of light lightness range state */ - u16_t range_max; /* Value of range max field of light lightness range state */ + u8_t status_code; /*!< Status Code for the request message */ + u16_t range_min; /*!< Value of range min field of light lightness range state */ + u16_t range_max; /*!< Value of range max field of light lightness range state */ } esp_ble_mesh_light_lightness_range_status_cb_t; +/** Parameters of Light CTL Status */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - u16_t present_ctl_lightness; /* Current value of light ctl lightness state */ - u16_t present_ctl_temperature; /* Current value of light ctl temperature state */ - u16_t target_ctl_lightness; /* Target value of light ctl lightness state (optional) */ - u16_t target_ctl_temperature; /* Target value of light ctl temperature state (C.1) */ - u8_t remain_time; /* Time to complete state transition (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + u16_t present_ctl_lightness; /*!< Current value of light ctl lightness state */ + u16_t present_ctl_temperature; /*!< Current value of light ctl temperature state */ + u16_t target_ctl_lightness; /*!< Target value of light ctl lightness state (optional) */ + u16_t target_ctl_temperature; /*!< Target value of light ctl temperature state (C.1) */ + u8_t remain_time; /*!< Time to complete state transition (C.1) */ } esp_ble_mesh_light_ctl_status_cb_t; +/** Parameters of Light CTL Temperature Status */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - u16_t present_ctl_temperature; /* Current value of light ctl temperature state */ - u16_t present_ctl_delta_uv; /* Current value of light ctl delta UV state */ - u16_t target_ctl_temperature; /* Target value of light ctl temperature state (optional) */ - u16_t target_ctl_delta_uv; /* Target value of light ctl delta UV state (C.1) */ - u8_t remain_time; /* Time to complete state transition (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + u16_t present_ctl_temperature; /*!< Current value of light ctl temperature state */ + u16_t present_ctl_delta_uv; /*!< Current value of light ctl delta UV state */ + u16_t target_ctl_temperature; /*!< Target value of light ctl temperature state (optional) */ + u16_t target_ctl_delta_uv; /*!< Target value of light ctl delta UV state (C.1) */ + u8_t remain_time; /*!< Time to complete state transition (C.1) */ } esp_ble_mesh_light_ctl_temperature_status_cb_t; +/** Parameters of Light CTL Temperature Range Status */ typedef struct { - u8_t status_code; /* Status code for the request message */ - u16_t range_min; /* Value of temperature range min field of light ctl temperature range state */ - u16_t range_max; /* Value of temperature range max field of light ctl temperature range state */ + u8_t status_code; /*!< Status code for the request message */ + u16_t range_min; /*!< Value of temperature range min field of light ctl temperature range state */ + u16_t range_max; /*!< Value of temperature range max field of light ctl temperature range state */ } esp_ble_mesh_light_ctl_temperature_range_status_cb_t; +/** Parameters of Light CTL Default Status */ typedef struct { - u16_t lightness; /* Value of light lightness default state */ - u16_t temperature; /* Value of light temperature default state */ - s16_t delta_uv; /* Value of light delta UV default state */ + u16_t lightness; /*!< Value of light lightness default state */ + u16_t temperature; /*!< Value of light temperature default state */ + s16_t delta_uv; /*!< Value of light delta UV default state */ } esp_ble_mesh_light_ctl_default_status_cb_t; +/** Parameters of Light HSL Status */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - u16_t hsl_lightness; /* Current value of light hsl lightness state */ - u16_t hsl_hue; /* Current value of light hsl hue state */ - u16_t hsl_saturation; /* Current value of light hsl saturation state */ - u8_t remain_time; /* Time to complete state transition (optional) */ + bool op_en; /*!< Indicate if optional parameters are included */ + u16_t hsl_lightness; /*!< Current value of light hsl lightness state */ + u16_t hsl_hue; /*!< Current value of light hsl hue state */ + u16_t hsl_saturation; /*!< Current value of light hsl saturation state */ + u8_t remain_time; /*!< Time to complete state transition (optional) */ } esp_ble_mesh_light_hsl_status_cb_t; +/** Parameters of Light HSL Target Status */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - u16_t hsl_lightness_target; /* Target value of light hsl lightness state */ - u16_t hsl_hue_target; /* Target value of light hsl hue state */ - u16_t hsl_saturation_target; /* Target value of light hsl saturation state */ - u8_t remain_time; /* Time to complete state transition (optional) */ + bool op_en; /*!< Indicate if optional parameters are included */ + u16_t hsl_lightness_target; /*!< Target value of light hsl lightness state */ + u16_t hsl_hue_target; /*!< Target value of light hsl hue state */ + u16_t hsl_saturation_target; /*!< Target value of light hsl saturation state */ + u8_t remain_time; /*!< Time to complete state transition (optional) */ } esp_ble_mesh_light_hsl_target_status_cb_t; +/** Parameters of Light HSL Hue Status */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - u16_t present_hue; /* Current value of light hsl hue state */ - u16_t target_hue; /* Target value of light hsl hue state (optional) */ - u8_t remain_time; /* Time to complete state transition (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + u16_t present_hue; /*!< Current value of light hsl hue state */ + u16_t target_hue; /*!< Target value of light hsl hue state (optional) */ + u8_t remain_time; /*!< Time to complete state transition (C.1) */ } esp_ble_mesh_light_hsl_hue_status_cb_t; +/** Parameters of Light HSL Saturation Status */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - u16_t present_saturation; /* Current value of light hsl saturation state */ - u16_t target_saturation; /* Target value of light hsl saturation state (optional) */ - u8_t remain_time; /* Time to complete state transition (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + u16_t present_saturation; /*!< Current value of light hsl saturation state */ + u16_t target_saturation; /*!< Target value of light hsl saturation state (optional) */ + u8_t remain_time; /*!< Time to complete state transition (C.1) */ } esp_ble_mesh_light_hsl_saturation_status_cb_t; +/** Parameters of Light HSL Default Status */ typedef struct { - u16_t lightness; /* Value of light lightness default state */ - u16_t hue; /* Value of light hue default state */ - u16_t saturation; /* Value of light saturation default state */ + u16_t lightness; /*!< Value of light lightness default state */ + u16_t hue; /*!< Value of light hue default state */ + u16_t saturation; /*!< Value of light saturation default state */ } esp_ble_mesh_light_hsl_default_status_cb_t; +/** Parameters of Light HSL Range Status */ typedef struct { - u8_t status_code; /* Status code for the request message */ - u16_t hue_range_min; /* Value of hue range min field of light hsl hue range state */ - u16_t hue_range_max; /* Value of hue range max field of light hsl hue range state */ - u16_t saturation_range_min; /* Value of saturation range min field of light hsl saturation range state */ - u16_t saturation_range_max; /* Value of saturation range max field of light hsl saturation range state */ + u8_t status_code; /*!< Status code for the request message */ + u16_t hue_range_min; /*!< Value of hue range min field of light hsl hue range state */ + u16_t hue_range_max; /*!< Value of hue range max field of light hsl hue range state */ + u16_t saturation_range_min; /*!< Value of saturation range min field of light hsl saturation range state */ + u16_t saturation_range_max; /*!< Value of saturation range max field of light hsl saturation range state */ } esp_ble_mesh_light_hsl_range_status_cb_t; +/** Parameters of Light xyL Status */ typedef struct { - bool op_en; /* Indicate whether optional parameters included */ - u16_t xyl_lightness; /* The present value of the Light xyL Lightness state */ - u16_t xyl_x; /* The present value of the Light xyL x state */ - u16_t xyl_y; /* The present value of the Light xyL y state */ - u8_t remain_time; /* Time to complete state transition (optional) */ + bool op_en; /*!< Indicate whether optional parameters included */ + u16_t xyl_lightness; /*!< The present value of the Light xyL Lightness state */ + u16_t xyl_x; /*!< The present value of the Light xyL x state */ + u16_t xyl_y; /*!< The present value of the Light xyL y state */ + u8_t remain_time; /*!< Time to complete state transition (optional) */ } esp_ble_mesh_light_xyl_status_cb_t; +/** Parameters of Light xyL Target Status */ typedef struct { - bool op_en; /* Indicate whether optional parameters included */ - u16_t target_xyl_lightness; /* The target value of the Light xyL Lightness state */ - u16_t target_xyl_x; /* The target value of the Light xyL x state */ - u16_t target_xyl_y; /* The target value of the Light xyL y state */ - u8_t remain_time; /* Time to complete state transition (optional) */ + bool op_en; /*!< Indicate whether optional parameters included */ + u16_t target_xyl_lightness; /*!< The target value of the Light xyL Lightness state */ + u16_t target_xyl_x; /*!< The target value of the Light xyL x state */ + u16_t target_xyl_y; /*!< The target value of the Light xyL y state */ + u8_t remain_time; /*!< Time to complete state transition (optional) */ } esp_ble_mesh_light_xyl_target_status_cb_t; +/** Parameters of Light xyL Default Status */ typedef struct { - u16_t lightness; /* The value of the Light Lightness Default state */ - u16_t xyl_x; /* The value of the Light xyL x Default state */ - u16_t xyl_y; /* The value of the Light xyL y Default state */ + u16_t lightness; /*!< The value of the Light Lightness Default state */ + u16_t xyl_x; /*!< The value of the Light xyL x Default state */ + u16_t xyl_y; /*!< The value of the Light xyL y Default state */ } esp_ble_mesh_light_xyl_default_status_cb_t; +/** Parameters of Light xyL Range Status */ typedef struct { - u8_t status_code; /* Status Code for the requesting message */ - u16_t xyl_x_range_min; /* The value of the xyL x Range Min field of the Light xyL x Range state */ - u16_t xyl_x_range_max; /* The value of the xyL x Range Max field of the Light xyL x Range state */ - u16_t xyl_y_range_min; /* The value of the xyL y Range Min field of the Light xyL y Range state */ - u16_t xyl_y_range_max; /* The value of the xyL y Range Max field of the Light xyL y Range state */ + u8_t status_code; /*!< Status Code for the requesting message */ + u16_t xyl_x_range_min; /*!< The value of the xyL x Range Min field of the Light xyL x Range state */ + u16_t xyl_x_range_max; /*!< The value of the xyL x Range Max field of the Light xyL x Range state */ + u16_t xyl_y_range_min; /*!< The value of the xyL y Range Min field of the Light xyL y Range state */ + u16_t xyl_y_range_max; /*!< The value of the xyL y Range Max field of the Light xyL y Range state */ } esp_ble_mesh_light_xyl_range_status_cb_t; +/** Parameter of Light LC Mode Status */ typedef struct { - u8_t mode; /* The present value of the Light LC Mode state */ + u8_t mode; /*!< The present value of the Light LC Mode state */ } esp_ble_mesh_light_lc_mode_status_cb_t; +/** Parameter of Light LC OM Status */ typedef struct { - u8_t mode; /* The present value of the Light LC Occupancy Mode state */ + u8_t mode; /*!< The present value of the Light LC Occupancy Mode state */ } esp_ble_mesh_light_lc_om_status_cb_t; +/** Parameters of Light LC Light OnOff Status */ typedef struct { - bool op_en; /* Indicate whether optional parameters included */ - u8_t present_light_onoff; /* The present value of the Light LC Light OnOff state */ - u8_t target_light_onoff; /* The target value of the Light LC Light OnOff state (Optional) */ - u8_t remain_time; /* Time to complete state transition (C.1) */ + bool op_en; /*!< Indicate whether optional parameters included */ + u8_t present_light_onoff; /*!< The present value of the Light LC Light OnOff state */ + u8_t target_light_onoff; /*!< The target value of the Light LC Light OnOff state (Optional) */ + u8_t remain_time; /*!< Time to complete state transition (C.1) */ } esp_ble_mesh_light_lc_light_onoff_status_cb_t; +/** Parameters of Light LC Property Status */ typedef struct { - u16_t property_id; /* Property ID identifying a Light LC Property */ - struct net_buf_simple *property_value; /* Raw value for the Light LC Property */ + u16_t property_id; /*!< Property ID identifying a Light LC Property */ + struct net_buf_simple *property_value; /*!< Raw value for the Light LC Property */ } esp_ble_mesh_light_lc_property_status_cb_t; +/** + * @brief Lighting Client Model received message union + */ typedef union { esp_ble_mesh_light_lightness_status_cb_t lightness_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS */ esp_ble_mesh_light_lightness_linear_status_cb_t lightness_linear_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS */ @@ -457,12 +510,14 @@ typedef union { esp_ble_mesh_light_lc_property_status_cb_t lc_property_status; /*!< For ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS */ } esp_ble_mesh_light_client_status_cb_t; +/** Lighting Client Model callback parameters */ typedef struct { int error_code; /*!< Appropriate error code */ esp_ble_mesh_client_common_param_t *params; /*!< The client common parameters. */ esp_ble_mesh_light_client_status_cb_t status_cb; /*!< The light status message callback values */ } esp_ble_mesh_light_client_cb_param_t; +/** This enum value is the event of Lighting Client Model */ typedef enum { ESP_BLE_MESH_LIGHT_CLIENT_GET_STATE_EVT, ESP_BLE_MESH_LIGHT_CLIENT_SET_STATE_EVT, @@ -475,7 +530,11 @@ typedef enum { * @brief Bluetooth Mesh Light Client Model function. */ -/** @brief: event, event code of Light Client Model events; param, parameters of Light Client Model events */ +/** + * @brief Lighting Client Model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ typedef void (* esp_ble_mesh_light_client_cb_t)(esp_ble_mesh_light_client_cb_event_t event, esp_ble_mesh_light_client_cb_param_t *param); @@ -493,7 +552,7 @@ esp_err_t esp_ble_mesh_register_light_client_callback(esp_ble_mesh_light_client_ * @brief Get the value of Light Server Model states using the Light Client Model get messages. * * @note If you want to know the opcodes and corresponding meanings accepted by this API, - * please refer to (@ref esp_ble_mesh_light_message_opcode_t). + * please refer to esp_ble_mesh_light_message_opcode_t in esp_ble_mesh_defs.h * * @param[in] params: Pointer to BLE Mesh common client parameters. * @param[in] get_state: Pointer of light get message value. @@ -509,7 +568,7 @@ esp_err_t esp_ble_mesh_light_client_get_state(esp_ble_mesh_client_common_param_t * @brief Set the value of Light Server Model states using the Light Client Model set messages. * * @note If you want to know the opcodes and corresponding meanings accepted by this API, - * please refer to (@ref esp_ble_mesh_light_message_opcode_t). + * please refer to esp_ble_mesh_light_message_opcode_t in esp_ble_mesh_defs.h * * @param[in] params: Pointer to BLE Mesh common client parameters. * @param[in] set_state: Pointer of generic set message value. diff --git a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h index 553845cad8..d303e63a14 100644 --- a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h +++ b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. @@ -41,58 +41,71 @@ /** * @brief Bluetooth Mesh Sensor Client Model Get and Set parameters structure. */ + +/** Parameters of Sensor Descriptor Get */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - u16_t property_id; /* Property ID of a sensor (optional) */ + bool op_en; /*!< Indicate if optional parameters are included */ + u16_t property_id; /*!< Property ID of a sensor (optional) */ } esp_ble_mesh_sensor_descriptor_get_t; +/** Parameter of Sensor Cadence Get */ typedef struct { - u16_t property_id; /* Property ID of a sensor */ + u16_t property_id; /*!< Property ID of a sensor */ } esp_ble_mesh_sensor_cadence_get_t; +/** Parameters of Sensor Cadence Set */ typedef struct { - u16_t property_id; /* Property ID for the sensor */ - u8_t fast_cadence_period_divisor : 7, /* Divisor for the publish period */ - status_trigger_type : 1; /* The unit and format of the Status Trigger Delta fields */ - struct net_buf_simple *status_trigger_delta_down; /* Delta down value that triggers a status message */ - struct net_buf_simple *status_trigger_delta_up; /* Delta up value that triggers a status message */ - u8_t status_min_interval; /* Minimum interval between two consecutive Status messages */ - struct net_buf_simple *fast_cadence_low; /* Low value for the fast cadence range */ - struct net_buf_simple *fast_cadence_high; /* Fast value for the fast cadence range */ + u16_t property_id; /*!< Property ID for the sensor */ + u8_t fast_cadence_period_divisor : 7, /*!< Divisor for the publish period */ + status_trigger_type : 1; /*!< The unit and format of the Status Trigger Delta fields */ + struct net_buf_simple *status_trigger_delta_down; /*!< Delta down value that triggers a status message */ + struct net_buf_simple *status_trigger_delta_up; /*!< Delta up value that triggers a status message */ + u8_t status_min_interval; /*!< Minimum interval between two consecutive Status messages */ + struct net_buf_simple *fast_cadence_low; /*!< Low value for the fast cadence range */ + struct net_buf_simple *fast_cadence_high; /*!< Fast value for the fast cadence range */ } esp_ble_mesh_sensor_cadence_set_t; +/** Parameter of Sensor Settings Get */ typedef struct { - u16_t sensor_property_id; /* Property ID of a sensor */ + u16_t sensor_property_id; /*!< Property ID of a sensor */ } esp_ble_mesh_sensor_settings_get_t; +/** Parameters of Sensor Setting Get */ typedef struct { - u16_t sensor_property_id; /* Property ID of a sensor */ - u16_t sensor_setting_property_id; /* Setting ID identifying a setting within a sensor */ + u16_t sensor_property_id; /*!< Property ID of a sensor */ + u16_t sensor_setting_property_id; /*!< Setting ID identifying a setting within a sensor */ } esp_ble_mesh_sensor_setting_get_t; +/** Parameters of Sensor Setting Set */ typedef struct { - u16_t sensor_property_id; /* Property ID identifying a sensor */ - u16_t sensor_setting_property_id; /* Setting ID identifying a setting within a sensor */ - struct net_buf_simple *sensor_setting_raw; /* Raw value for the setting */ + u16_t sensor_property_id; /*!< Property ID identifying a sensor */ + u16_t sensor_setting_property_id; /*!< Setting ID identifying a setting within a sensor */ + struct net_buf_simple *sensor_setting_raw; /*!< Raw value for the setting */ } esp_ble_mesh_sensor_setting_set_t; +/** Parameters of Sensor Get */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - u16_t property_id; /* Property ID for the sensor (optional) */ + bool op_en; /*!< Indicate if optional parameters are included */ + u16_t property_id; /*!< Property ID for the sensor (optional) */ } esp_ble_mesh_sensor_get_t; +/** Parameters of Sensor Column Get */ typedef struct { - u16_t property_id; /* Property identifying a sensor */ - struct net_buf_simple *raw_value_x; /* Raw value identifying a column */ + u16_t property_id; /*!< Property identifying a sensor */ + struct net_buf_simple *raw_value_x; /*!< Raw value identifying a column */ } esp_ble_mesh_sensor_column_get_t; +/** Parameters of Sensor Series Get */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - u16_t property_id; /* Property identifying a sensor */ - struct net_buf_simple *raw_value_x1; /* Raw value identifying a starting column (optional) */ - struct net_buf_simple *raw_value_x2; /* Raw value identifying an ending column (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + u16_t property_id; /*!< Property identifying a sensor */ + struct net_buf_simple *raw_value_x1; /*!< Raw value identifying a starting column (optional) */ + struct net_buf_simple *raw_value_x2; /*!< Raw value identifying an ending column (C.1) */ } esp_ble_mesh_sensor_series_get_t; +/** + * @brief Sensor Client Model get message union + */ typedef union { esp_ble_mesh_sensor_descriptor_get_t descriptor_get; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET */ esp_ble_mesh_sensor_cadence_get_t cadence_get; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET */ @@ -103,6 +116,9 @@ typedef union { esp_ble_mesh_sensor_series_get_t series_get; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_SERIES_GET */ } esp_ble_mesh_sensor_client_get_state_t; +/** + * @brief Sensor Client Model set message union + */ typedef union { esp_ble_mesh_sensor_cadence_set_t cadence_set; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET & ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK */ esp_ble_mesh_sensor_setting_set_t setting_set; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET & ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET_UNACK */ @@ -112,43 +128,52 @@ typedef union { * @brief Bluetooth Mesh Sensor Client Model Get and Set callback parameters structure. */ +/** Parameter of Sensor Descriptor Status */ typedef struct { - struct net_buf_simple *descriptor; /* Sequence of 8-octet sensor descriptors (optional) */ + struct net_buf_simple *descriptor; /*!< Sequence of 8-octet sensor descriptors (optional) */ } esp_ble_mesh_sensor_descriptor_status_cb_t; +/** Parameters of Sensor Cadence Status */ typedef struct { - u16_t property_id; /* Property for the sensor */ - struct net_buf_simple *sensor_cadence_value; /* Value of sensor cadence state */ + u16_t property_id; /*!< Property for the sensor */ + struct net_buf_simple *sensor_cadence_value; /*!< Value of sensor cadence state */ } esp_ble_mesh_sensor_cadence_status_cb_t; +/** Parameters of Sensor Settings Status */ typedef struct { - u16_t sensor_property_id; /* Property ID identifying a sensor */ - struct net_buf_simple *sensor_setting_property_ids; /* A sequence of N sensor setting property IDs (optional) */ + u16_t sensor_property_id; /*!< Property ID identifying a sensor */ + struct net_buf_simple *sensor_setting_property_ids; /*!< A sequence of N sensor setting property IDs (optional) */ } esp_ble_mesh_sensor_settings_status_cb_t; +/** Parameters of Sensor Setting Status */ typedef struct { - bool op_en; /* Indicate id optional parameters are included */ - u16_t sensor_property_id; /* Property ID identifying a sensor */ - u16_t sensor_setting_property_id; /* Setting ID identifying a setting within a sensor */ - u8_t sensor_setting_access; /* Read/Write access rights for the setting (optional) */ - struct net_buf_simple *sensor_setting_raw; /* Raw value for the setting */ + bool op_en; /*!< Indicate id optional parameters are included */ + u16_t sensor_property_id; /*!< Property ID identifying a sensor */ + u16_t sensor_setting_property_id; /*!< Setting ID identifying a setting within a sensor */ + u8_t sensor_setting_access; /*!< Read/Write access rights for the setting (optional) */ + struct net_buf_simple *sensor_setting_raw; /*!< Raw value for the setting */ } esp_ble_mesh_sensor_setting_status_cb_t; +/** Parameter of Sensor Status */ typedef struct { - struct net_buf_simple *marshalled_sensor_data; /* Value of sensor data state (optional) */ + struct net_buf_simple *marshalled_sensor_data; /*!< Value of sensor data state (optional) */ } esp_ble_mesh_sensor_status_cb_t; +/** Parameters of Sensor Column Status */ typedef struct { - u16_t property_id; /* Property identifying a sensor and the Y axis */ - struct net_buf_simple *sensor_column_value; /* Left values of sensor column status */ + u16_t property_id; /*!< Property identifying a sensor and the Y axis */ + struct net_buf_simple *sensor_column_value; /*!< Left values of sensor column status */ } esp_ble_mesh_sensor_column_status_cb_t; +/** Parameters of Sensor Series Status */ typedef struct { - u16_t property_id; /* Property identifying a sensor and the Y axis */ - struct net_buf_simple *sensor_series_value; /* Left values of sensor series status */ + u16_t property_id; /*!< Property identifying a sensor and the Y axis */ + struct net_buf_simple *sensor_series_value; /*!< Left values of sensor series status */ } esp_ble_mesh_sensor_series_status_cb_t; - +/** + * @brief Sensor Client Model received message union + */ typedef union { esp_ble_mesh_sensor_descriptor_status_cb_t descriptor_status; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS */ esp_ble_mesh_sensor_cadence_status_cb_t cadence_status; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS */ @@ -159,6 +184,7 @@ typedef union { esp_ble_mesh_sensor_series_status_cb_t series_status; /*!< For ESP_BLE_MESH_MODEL_OP_SENSOR_SERIES_STATUS */ } esp_ble_mesh_sensor_client_status_cb_t; +/** Sensor Client Model callback parameters */ typedef struct { int error_code; /*!< 0: success, * otherwise failure. For the error code values please refer to errno.h file. @@ -167,6 +193,7 @@ typedef struct { esp_ble_mesh_sensor_client_status_cb_t status_cb; /*!< The sensor status message callback values */ } esp_ble_mesh_sensor_client_cb_param_t; +/** This enum value is the event of Sensor Client Model */ typedef enum { ESP_BLE_MESH_SENSOR_CLIENT_GET_STATE_EVT, ESP_BLE_MESH_SENSOR_CLIENT_SET_STATE_EVT, @@ -179,7 +206,11 @@ typedef enum { * @brief Bluetooth Mesh Sensor Client Model function. */ -/** @brief: event, event code of Sensor Client Model events; param, parameters of Sensor Client Model events */ +/** + * @brief Sensor Client Model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ typedef void (* esp_ble_mesh_sensor_client_cb_t)(esp_ble_mesh_sensor_client_cb_event_t event, esp_ble_mesh_sensor_client_cb_param_t *param); @@ -197,7 +228,7 @@ esp_err_t esp_ble_mesh_register_sensor_client_callback(esp_ble_mesh_sensor_clien * @brief Get the value of Sensor Server Model states using the Sensor Client Model get messages. * * @note If you want to know the opcodes and corresponding meanings accepted by this API, - * please refer to (@ref esp_ble_mesh_sensor_message_opcode_t). + * please refer to esp_ble_mesh_sensor_message_opcode_t in esp_ble_mesh_defs.h * * @param[in] params: Pointer to BLE Mesh common client parameters. * @param[in] get_state: Pointer to sensor get message value. @@ -213,7 +244,7 @@ esp_err_t esp_ble_mesh_sensor_client_get_state(esp_ble_mesh_client_common_param_ * @brief Set the value of Sensor Server Model states using the Sensor Client Model set messages. * * @note If you want to know the opcodes and corresponding meanings accepted by this API, - * please refer to (@ref esp_ble_mesh_sensor_message_opcode_t). + * please refer to esp_ble_mesh_sensor_message_opcode_t in esp_ble_mesh_defs.h * * @param[in] params: Pointer to BLE Mesh common client parameters. * @param[in] set_state: Pointer to sensor set message value. diff --git a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h index cdf55ef170..da45b40517 100644 --- a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h +++ b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. @@ -74,73 +74,83 @@ * @brief Bluetooth Mesh Time Scene Client Model Get and Set parameters structure. */ +/** Parameters of Time Set */ typedef struct { - u8_t tai_seconds[5]; /* The current TAI time in seconds */ - u8_t sub_second; /* The sub-second time in units of 1/256 second */ - u8_t uncertainty; /* The estimated uncertainty in 10-millisecond steps */ - u16_t time_authority : 1; /* 0 = No Time Authority, 1 = Time Authority */ - u16_t tai_utc_delta : 15; /* Current difference between TAI and UTC in seconds */ - u8_t time_zone_offset; /* The local time zone offset in 15-minute increments */ + u8_t tai_seconds[5]; /*!< The current TAI time in seconds */ + u8_t sub_second; /*!< The sub-second time in units of 1/256 second */ + u8_t uncertainty; /*!< The estimated uncertainty in 10-millisecond steps */ + u16_t time_authority : 1; /*!< 0 = No Time Authority, 1 = Time Authority */ + u16_t tai_utc_delta : 15; /*!< Current difference between TAI and UTC in seconds */ + u8_t time_zone_offset; /*!< The local time zone offset in 15-minute increments */ } esp_ble_mesh_time_set_t; +/** Parameters of Time Zone Set */ typedef struct { - u8_t time_zone_offset_new; /* Upcoming local time zone offset */ - u8_t tai_zone_change[5]; /* TAI Seconds time of the upcoming Time Zone Offset change */ + u8_t time_zone_offset_new; /*!< Upcoming local time zone offset */ + u8_t tai_zone_change[5]; /*!< TAI Seconds time of the upcoming Time Zone Offset change */ } esp_ble_mesh_time_zone_set_t; +/** Parameters of TAI-UTC Delta Set */ typedef struct { - u16_t tai_utc_delta_new : 15; /* Upcoming difference between TAI and UTC in seconds */ - u16_t padding : 1; /* Always 0b0. Other values are Prohibited. */ - u8_t tai_delta_change[5]; /* TAI Seconds time of the upcoming TAI-UTC Delta change */ + u16_t tai_utc_delta_new : 15; /*!< Upcoming difference between TAI and UTC in seconds */ + u16_t padding : 1; /*!< Always 0b0. Other values are Prohibited. */ + u8_t tai_delta_change[5]; /*!< TAI Seconds time of the upcoming TAI-UTC Delta change */ } esp_ble_mesh_tai_utc_delta_set_t; +/** Parameter of Time Role Set */ typedef struct { - u8_t time_role; /* The Time Role for the element */ + u8_t time_role; /*!< The Time Role for the element */ } esp_ble_mesh_time_role_set_t; +/** Parameter of Scene Store */ typedef struct { - u16_t scene_number; /* The number of scenes to be stored */ + u16_t scene_number; /*!< The number of scenes to be stored */ } esp_ble_mesh_scene_store_t; +/** Parameters of Scene Recall */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - u16_t scene_number; /* The number of scenes to be recalled */ - u8_t tid; /* Transaction ID */ - u8_t trans_time; /* Time to complete state transition (optional) */ - u8_t delay; /* Indicate message execution delay (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + u16_t scene_number; /*!< The number of scenes to be recalled */ + u8_t tid; /*!< Transaction ID */ + u8_t trans_time; /*!< Time to complete state transition (optional) */ + u8_t delay; /*!< Indicate message execution delay (C.1) */ } esp_ble_mesh_scene_recall_t; +/** Parameter of Scene Delete */ typedef struct { - u16_t scene_number; /* The number of scenes to be deleted */ + u16_t scene_number; /*!< The number of scenes to be deleted */ } esp_ble_mesh_scene_delete_t; +/** Parameter of Scheduler Action Get */ typedef struct { - u8_t index; /* Index of the Schedule Register entry to get */ + u8_t index; /*!< Index of the Schedule Register entry to get */ } esp_ble_mesh_scheduler_act_get_t; +/** Parameters of Scheduler Action Set */ typedef struct { - u64_t index : 4; /* Index of the Schedule Register entry to set */ - u64_t year : 7; /* Scheduled year for the action */ - u64_t month : 12; /* Scheduled month for the action */ - u64_t day : 5; /* Scheduled day of the month for the action */ - u64_t hour : 5; /* Scheduled hour for the action */ - u64_t minute : 6; /* Scheduled minute for the action */ - u64_t second : 6; /* Scheduled second for the action */ - u64_t day_of_week : 7; /* Schedule days of the week for the action */ - u64_t action : 4; /* Action to be performed at the scheduled time */ - u64_t trans_time : 8; /* Transition time for this action */ - u16_t scene_number; /* Transition time for this action */ + u64_t index : 4; /*!< Index of the Schedule Register entry to set */ + u64_t year : 7; /*!< Scheduled year for the action */ + u64_t month : 12; /*!< Scheduled month for the action */ + u64_t day : 5; /*!< Scheduled day of the month for the action */ + u64_t hour : 5; /*!< Scheduled hour for the action */ + u64_t minute : 6; /*!< Scheduled minute for the action */ + u64_t second : 6; /*!< Scheduled second for the action */ + u64_t day_of_week : 7; /*!< Schedule days of the week for the action */ + u64_t action : 4; /*!< Action to be performed at the scheduled time */ + u64_t trans_time : 8; /*!< Transition time for this action */ + u16_t scene_number; /*!< Transition time for this action */ } esp_ble_mesh_scheduler_act_set_t; /** - * @brief For - * - * the get_state parameter in the esp_ble_mesh_time_scene_client_get_state function should be set to NULL. + * @brief Time Scene Client Model get message union */ typedef union { esp_ble_mesh_scheduler_act_get_t scheduler_act_get; /*!< For ESP_BLE_MESH_MODEL_OP_SCHEDULER_ACT_GET */ } esp_ble_mesh_time_scene_client_get_state_t; +/** + * @brief Time Scene Client Model set message union + */ typedef union { esp_ble_mesh_time_set_t time_set; /*!< For ESP_BLE_MESH_MODEL_OP_TIME_SET */ esp_ble_mesh_time_zone_set_t time_zone_set; /*!< For ESP_BLE_MESH_MODEL_OP_TIME_ZONE_SET */ @@ -156,65 +166,76 @@ typedef union { * @brief Bluetooth Mesh Time Scene Client Model Get and Set callback parameters structure. */ +/** Parameters of Time Status */ typedef struct { - u8_t tai_seconds[5]; /* The current TAI time in seconds */ - u8_t sub_second; /* The sub-second time in units of 1/256 second */ - u8_t uncertainty; /* The estimated uncertainty in 10-millisecond steps */ - u16_t time_authority : 1; /* 0 = No Time Authority, 1 = Time Authority */ - u16_t tai_utc_delta : 15; /* Current difference between TAI and UTC in seconds */ - u8_t time_zone_offset; /* The local time zone offset in 15-minute increments */ + u8_t tai_seconds[5]; /*!< The current TAI time in seconds */ + u8_t sub_second; /*!< The sub-second time in units of 1/256 second */ + u8_t uncertainty; /*!< The estimated uncertainty in 10-millisecond steps */ + u16_t time_authority : 1; /*!< 0 = No Time Authority, 1 = Time Authority */ + u16_t tai_utc_delta : 15; /*!< Current difference between TAI and UTC in seconds */ + u8_t time_zone_offset; /*!< The local time zone offset in 15-minute increments */ } esp_ble_mesh_time_status_cb_t; +/** Parameters of Time Zone Status */ typedef struct { - u8_t time_zone_offset_curr; /* Current local time zone offset */ - u8_t time_zone_offset_new; /* Upcoming local time zone offset */ - u8_t tai_zone_change[5]; /* TAI Seconds time of the upcoming Time Zone Offset change */ + u8_t time_zone_offset_curr; /*!< Current local time zone offset */ + u8_t time_zone_offset_new; /*!< Upcoming local time zone offset */ + u8_t tai_zone_change[5]; /*!< TAI Seconds time of the upcoming Time Zone Offset change */ } esp_ble_mesh_time_zone_status_cb_t; +/** Parameters of TAI-UTC Delta Status */ typedef struct { - u16_t tai_utc_delta_curr : 15; /* Current difference between TAI and UTC in seconds */ - u16_t padding_1 : 1; /* Always 0b0. Other values are Prohibited. */ - u16_t tai_utc_delta_new : 15; /* Upcoming difference between TAI and UTC in seconds */ - u16_t padding_2 : 1; /* Always 0b0. Other values are Prohibited. */ - u8_t tai_delta_change[5]; /* TAI Seconds time of the upcoming TAI-UTC Delta change */ + u16_t tai_utc_delta_curr : 15; /*!< Current difference between TAI and UTC in seconds */ + u16_t padding_1 : 1; /*!< Always 0b0. Other values are Prohibited. */ + u16_t tai_utc_delta_new : 15; /*!< Upcoming difference between TAI and UTC in seconds */ + u16_t padding_2 : 1; /*!< Always 0b0. Other values are Prohibited. */ + u8_t tai_delta_change[5]; /*!< TAI Seconds time of the upcoming TAI-UTC Delta change */ } esp_ble_mesh_tai_utc_delta_status_cb_t; +/** Parameter of Time Role Status */ typedef struct { - u8_t time_role; /* The Time Role for the element */ + u8_t time_role; /*!< The Time Role for the element */ } esp_ble_mesh_time_role_status_cb_t; +/** Parameters of Scene Status */ typedef struct { - bool op_en; /* Indicate if optional parameters are included */ - u8_t status_code; /* Status code of the last operation */ - u16_t current_scene; /* Scene Number of the current scene */ - u16_t target_scene; /* Scene Number of the target scene (optional) */ - u8_t remain_time; /* Time to complete state transition (C.1) */ + bool op_en; /*!< Indicate if optional parameters are included */ + u8_t status_code; /*!< Status code of the last operation */ + u16_t current_scene; /*!< Scene Number of the current scene */ + u16_t target_scene; /*!< Scene Number of the target scene (optional) */ + u8_t remain_time; /*!< Time to complete state transition (C.1) */ } esp_ble_mesh_scene_status_cb_t; +/** Parameters of Scene Register Status */ typedef struct { - u8_t status_code; /* Status code for the previous operation */ - u16_t current_scene; /* Scene Number of the current scene */ - struct net_buf_simple *scenes; /* A list of scenes stored within an element */ + u8_t status_code; /*!< Status code for the previous operation */ + u16_t current_scene; /*!< Scene Number of the current scene */ + struct net_buf_simple *scenes; /*!< A list of scenes stored within an element */ } esp_ble_mesh_scene_register_status_cb_t; +/** Parameter of Scheduler Status */ typedef struct { - u16_t schedules; /* Bit field indicating defined Actions in the Schedule Register */ + u16_t schedules; /*!< Bit field indicating defined Actions in the Schedule Register */ } esp_ble_mesh_scheduler_status_cb_t; +/** Parameters of Scheduler Action Status */ typedef struct { - u64_t index : 4; /* Enumerates (selects) a Schedule Register entry */ - u64_t year : 7; /* Scheduled year for the action */ - u64_t month : 12; /* Scheduled month for the action */ - u64_t day : 5; /* Scheduled day of the month for the action */ - u64_t hour : 5; /* Scheduled hour for the action */ - u64_t minute : 6; /* Scheduled minute for the action */ - u64_t second : 6; /* Scheduled second for the action */ - u64_t day_of_week : 7; /* Schedule days of the week for the action */ - u64_t action : 4; /* Action to be performed at the scheduled time */ - u64_t trans_time : 8; /* Transition time for this action */ - u16_t scene_number; /* Transition time for this action */ + u64_t index : 4; /*!< Enumerates (selects) a Schedule Register entry */ + u64_t year : 7; /*!< Scheduled year for the action */ + u64_t month : 12; /*!< Scheduled month for the action */ + u64_t day : 5; /*!< Scheduled day of the month for the action */ + u64_t hour : 5; /*!< Scheduled hour for the action */ + u64_t minute : 6; /*!< Scheduled minute for the action */ + u64_t second : 6; /*!< Scheduled second for the action */ + u64_t day_of_week : 7; /*!< Schedule days of the week for the action */ + u64_t action : 4; /*!< Action to be performed at the scheduled time */ + u64_t trans_time : 8; /*!< Transition time for this action */ + u16_t scene_number; /*!< Transition time for this action */ } esp_ble_mesh_scheduler_act_status_cb_t; +/** + * @brief Time Scene Client Model received message union + */ typedef union { esp_ble_mesh_time_status_cb_t time_status; /*!< For ESP_BLE_MESH_MODEL_OP_TIME_STATUS */ esp_ble_mesh_time_zone_status_cb_t time_zone_status; /*!< For ESP_BLE_MESH_MODEL_OP_TIME_ZONE_STATUS */ @@ -226,12 +247,14 @@ typedef union { esp_ble_mesh_scheduler_act_status_cb_t scheduler_act_status; /*!< For ESP_BLE_MESH_MODEL_OP_SCHEDULER_ACT_STATUS */ } esp_ble_mesh_time_scene_client_status_cb_t; +/** Time Scene Client Model callback parameters */ typedef struct { int error_code; /*!< Appropriate error code */ esp_ble_mesh_client_common_param_t *params; /*!< The client common parameters. */ esp_ble_mesh_time_scene_client_status_cb_t status_cb; /*!< The scene status message callback values */ } esp_ble_mesh_time_scene_client_cb_param_t; +/** This enum value is the event of Time Scene Client Model */ typedef enum { ESP_BLE_MESH_TIME_SCENE_CLIENT_GET_STATE_EVT, ESP_BLE_MESH_TIME_SCENE_CLIENT_SET_STATE_EVT, @@ -244,7 +267,11 @@ typedef enum { * @brief Bluetooth Mesh Time Scene Client Model function. */ -/** @brief: event, event code of Time Scene Client Model events; param, parameters of Time Scene Client Model events */ +/** + * @brief Time Scene Client Model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ typedef void (* esp_ble_mesh_time_scene_client_cb_t)(esp_ble_mesh_time_scene_client_cb_event_t event, esp_ble_mesh_time_scene_client_cb_param_t *param); @@ -262,7 +289,7 @@ esp_err_t esp_ble_mesh_register_time_scene_client_callback(esp_ble_mesh_time_sce * @brief Get the value of Time Scene Server Model states using the Time Scene Client Model get messages. * * @note If you want to know the opcodes and corresponding meanings accepted by this API, - * please refer to (@ref esp_ble_mesh_time_scene_message_opcode_t). + * please refer to esp_ble_mesh_time_scene_message_opcode_t in esp_ble_mesh_defs.h * * @param[in] params: Pointer to BLE Mesh common client parameters. * @param[in] get_state: Pointer to time scene get message value. @@ -277,7 +304,7 @@ esp_err_t esp_ble_mesh_time_scene_client_get_state(esp_ble_mesh_client_common_pa * @brief Set the value of Time Scene Server Model states using the Time Scene Client Model set messages. * * @note If you want to know the opcodes and corresponding meanings accepted by this API, - * please refer to (@ref esp_ble_mesh_time_scene_message_opcode_t). + * please refer to esp_ble_mesh_time_scene_message_opcode_t in esp_ble_mesh_defs.h * * @param[in] params: Pointer to BLE Mesh common client parameters. * @param[in] set_state: Pointer to time scene set message value. diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_config_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_config_model.c index 7fe0e0595d..0937721bb2 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_config_model.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_config_model.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_generic_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_generic_model.c index b8fc338169..761fbeebe5 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_generic_model.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_generic_model.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_health_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_health_model.c index 6651f59936..1f6d88340b 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_health_model.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_health_model.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_lighting_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_lighting_model.c index 1b89c51713..d07dba47a0 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_lighting_model.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_lighting_model.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c index d53b0d8cb4..c825e93907 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_sensor_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_sensor_model.c index 53d773842f..b9f3de6bde 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_sensor_model.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_sensor_model.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_time_scene_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_time_scene_model.c index 4c1a36905e..4f03567dc9 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_time_scene_model.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_time_scene_model.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_config_model.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_config_model.h index 6744b96120..87889923cc 100644 --- a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_config_model.h +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_config_model.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_generic_model.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_generic_model.h index 480003141d..21a159f20a 100644 --- a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_generic_model.h +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_generic_model.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_health_model.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_health_model.h index 859624dba2..a00efb0c1e 100644 --- a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_health_model.h +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_health_model.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_lighting_model.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_lighting_model.h index 8a3088f32d..98353c6acd 100644 --- a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_lighting_model.h +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_lighting_model.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h index 9ce21e4865..ff0f4154fd 100644 --- a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_sensor_model.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_sensor_model.h index 6bd97355e8..e94ccdc4b0 100644 --- a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_sensor_model.h +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_sensor_model.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_time_scene_model.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_time_scene_model.h index 1778fa2347..0ee1d244c8 100644 --- a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_time_scene_model.h +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_time_scene_model.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_core/provisioner_beacon.c b/components/bt/esp_ble_mesh/mesh_core/provisioner_beacon.c index dfe4e39fa0..0790b538de 100644 --- a/components/bt/esp_ble_mesh/mesh_core/provisioner_beacon.c +++ b/components/bt/esp_ble_mesh/mesh_core/provisioner_beacon.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_core/provisioner_beacon.h b/components/bt/esp_ble_mesh/mesh_core/provisioner_beacon.h index 0b3cfae6e6..a58de225fe 100644 --- a/components/bt/esp_ble_mesh/mesh_core/provisioner_beacon.h +++ b/components/bt/esp_ble_mesh/mesh_core/provisioner_beacon.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_core/provisioner_main.c b/components/bt/esp_ble_mesh/mesh_core/provisioner_main.c index d78cc1484a..586fd33842 100644 --- a/components/bt/esp_ble_mesh/mesh_core/provisioner_main.c +++ b/components/bt/esp_ble_mesh/mesh_core/provisioner_main.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_core/provisioner_main.h b/components/bt/esp_ble_mesh/mesh_core/provisioner_main.h index a4585d4009..50bb656b2c 100644 --- a/components/bt/esp_ble_mesh/mesh_core/provisioner_main.h +++ b/components/bt/esp_ble_mesh/mesh_core/provisioner_main.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_core/provisioner_prov.c b/components/bt/esp_ble_mesh/mesh_core/provisioner_prov.c index a07c8cec87..dbaae8ebb6 100644 --- a/components/bt/esp_ble_mesh/mesh_core/provisioner_prov.c +++ b/components/bt/esp_ble_mesh/mesh_core/provisioner_prov.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_core/provisioner_prov.h b/components/bt/esp_ble_mesh/mesh_core/provisioner_prov.h index 30a2f94d76..103a223f21 100644 --- a/components/bt/esp_ble_mesh/mesh_core/provisioner_prov.h +++ b/components/bt/esp_ble_mesh/mesh_core/provisioner_prov.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_core/provisioner_proxy.c b/components/bt/esp_ble_mesh/mesh_core/provisioner_proxy.c index 2961af3c42..022994f382 100644 --- a/components/bt/esp_ble_mesh/mesh_core/provisioner_proxy.c +++ b/components/bt/esp_ble_mesh/mesh_core/provisioner_proxy.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_core/provisioner_proxy.h b/components/bt/esp_ble_mesh/mesh_core/provisioner_proxy.h index 5da92f433b..6a64167b39 100644 --- a/components/bt/esp_ble_mesh/mesh_core/provisioner_proxy.h +++ b/components/bt/esp_ble_mesh/mesh_core/provisioner_proxy.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_core/settings/settings_nvs.c b/components/bt/esp_ble_mesh/mesh_core/settings/settings_nvs.c index 1a19bee297..59e9ac1142 100644 --- a/components/bt/esp_ble_mesh/mesh_core/settings/settings_nvs.c +++ b/components/bt/esp_ble_mesh/mesh_core/settings/settings_nvs.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_core/settings/settings_nvs.h b/components/bt/esp_ble_mesh/mesh_core/settings/settings_nvs.h index b1e929adf8..a4216fadca 100644 --- a/components/bt/esp_ble_mesh/mesh_core/settings/settings_nvs.h +++ b/components/bt/esp_ble_mesh/mesh_core/settings/settings_nvs.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_models/generic_client.c b/components/bt/esp_ble_mesh/mesh_models/generic_client.c index 7aeb5d00d3..9e963095dd 100644 --- a/components/bt/esp_ble_mesh/mesh_models/generic_client.c +++ b/components/bt/esp_ble_mesh/mesh_models/generic_client.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_models/include/generic_client.h b/components/bt/esp_ble_mesh/mesh_models/include/generic_client.h index 3f272cb952..e82587d766 100644 --- a/components/bt/esp_ble_mesh/mesh_models/include/generic_client.h +++ b/components/bt/esp_ble_mesh/mesh_models/include/generic_client.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_models/include/lighting_client.h b/components/bt/esp_ble_mesh/mesh_models/include/lighting_client.h index 5b6b92a5ae..9e9789a821 100644 --- a/components/bt/esp_ble_mesh/mesh_models/include/lighting_client.h +++ b/components/bt/esp_ble_mesh/mesh_models/include/lighting_client.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_models/include/mesh_common.h b/components/bt/esp_ble_mesh/mesh_models/include/mesh_common.h index 2a116be01e..468cf65afc 100644 --- a/components/bt/esp_ble_mesh/mesh_models/include/mesh_common.h +++ b/components/bt/esp_ble_mesh/mesh_models/include/mesh_common.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_models/include/model_common.h b/components/bt/esp_ble_mesh/mesh_models/include/model_common.h index fd9cc6dfda..486cdb769d 100644 --- a/components/bt/esp_ble_mesh/mesh_models/include/model_common.h +++ b/components/bt/esp_ble_mesh/mesh_models/include/model_common.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_models/include/model_opcode.h b/components/bt/esp_ble_mesh/mesh_models/include/model_opcode.h index 01929d5cfe..d9a49e71de 100644 --- a/components/bt/esp_ble_mesh/mesh_models/include/model_opcode.h +++ b/components/bt/esp_ble_mesh/mesh_models/include/model_opcode.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_models/include/sensor_client.h b/components/bt/esp_ble_mesh/mesh_models/include/sensor_client.h index 2b259a8953..095499ef5d 100644 --- a/components/bt/esp_ble_mesh/mesh_models/include/sensor_client.h +++ b/components/bt/esp_ble_mesh/mesh_models/include/sensor_client.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_models/include/time_scene_client.h b/components/bt/esp_ble_mesh/mesh_models/include/time_scene_client.h index baa0d4abc0..a37cf878f4 100644 --- a/components/bt/esp_ble_mesh/mesh_models/include/time_scene_client.h +++ b/components/bt/esp_ble_mesh/mesh_models/include/time_scene_client.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_models/lighting_client.c b/components/bt/esp_ble_mesh/mesh_models/lighting_client.c index 3aea99a8a4..8f0481b86d 100644 --- a/components/bt/esp_ble_mesh/mesh_models/lighting_client.c +++ b/components/bt/esp_ble_mesh/mesh_models/lighting_client.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_models/mesh_common.c b/components/bt/esp_ble_mesh/mesh_models/mesh_common.c index 801644ace1..bb4aa6f934 100644 --- a/components/bt/esp_ble_mesh/mesh_models/mesh_common.c +++ b/components/bt/esp_ble_mesh/mesh_models/mesh_common.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_models/model_common.c b/components/bt/esp_ble_mesh/mesh_models/model_common.c index c904543de5..cc694082cd 100644 --- a/components/bt/esp_ble_mesh/mesh_models/model_common.c +++ b/components/bt/esp_ble_mesh/mesh_models/model_common.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_models/sensor_client.c b/components/bt/esp_ble_mesh/mesh_models/sensor_client.c index 1933d1027a..26ea1f8d7e 100644 --- a/components/bt/esp_ble_mesh/mesh_models/sensor_client.c +++ b/components/bt/esp_ble_mesh/mesh_models/sensor_client.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/components/bt/esp_ble_mesh/mesh_models/time_scene_client.c b/components/bt/esp_ble_mesh/mesh_models/time_scene_client.c index 3296edf925..921c504ae3 100644 --- a/components/bt/esp_ble_mesh/mesh_models/time_scene_client.c +++ b/components/bt/esp_ble_mesh/mesh_models/time_scene_client.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/docs/Doxyfile b/docs/Doxyfile index ee91aab2b3..1091f29ed7 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -59,6 +59,20 @@ INPUT = \ ../../components/bt/host/bluedroid/api/include/api/esp_hf_client_api.h \ ## NimBLE related Bluetooth APIs ../../components/bt/host/nimble/esp-hci/include/esp_nimble_hci.h \ + ## ESP BLE Mesh APIs + ../../components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_common_api.h \ + ../../components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h \ + ../../components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_low_power_api.h \ + ../../components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_networking_api.h \ + ../../components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h \ + ../../components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_proxy_api.h \ + ../../components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h \ + ../../components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_generic_model_api.h \ + ../../components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_health_model_api.h \ + ../../components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h \ + ../../components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h \ + ../../components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h \ + ../../components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h \ ## ## Ethernet - API Reference ## diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.c index 4123756b8c..5cf017bdca 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.h index a5122336e2..06c876fd64 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.h +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.c index 2e7c938460..4fa715f0c8 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.h index 9e43333eb9..eba953c4ec 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.h +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.c index 88b728bbab..efcb6766a7 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.h index 8f8449eca4..f0e2e77c97 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.h +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c index e629cf3054..f1f9635526 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c index da08884e35..919e69f777 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_server_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_server_cmd.c index 3abe85dc01..e2ae583bf8 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_server_cmd.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_server_cmd.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c index 5afaca813b..e6b03ed590 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.c index 5f668718f3..754b0115fa 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.h index 87bc7399a4..bdc083a215 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.h +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.c index 9518e74b42..705ad8d488 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.h index 9e43333eb9..eba953c4ec 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.h +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.c index d15ee3adc1..8116935c2c 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.h index 11dd05cb37..da4d7c20bf 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.h +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c index f7c4eacf6b..d9d4a9e4e9 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_cfg_client_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_cfg_client_cmd.c index fd2852de82..53a10d38d1 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_cfg_client_cmd.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_cfg_client_cmd.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_gen_onoff_client_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_gen_onoff_client_cmd.c index 70a28162f7..6f34a1b271 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_gen_onoff_client_cmd.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_gen_onoff_client_cmd.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_test_perf_client_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_test_perf_client_cmd.c index e2e85ba43d..e46efc8eca 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_test_perf_client_cmd.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_test_perf_client_cmd.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c index 57e89605c9..0e0775acaf 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c index c5a2d3ad1b..2df3ec5b7a 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/register_bluetooth.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/register_bluetooth.c index bcb548520f..6b856c30f4 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/register_bluetooth.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/register_bluetooth.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/ble_mesh_demo_main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/ble_mesh_demo_main.c index 3337277340..fa3c948dc4 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/ble_mesh_demo_main.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/main/ble_mesh_demo_main.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/ble_mesh_demo_main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/ble_mesh_demo_main.c index 87bc00e1d0..612c292b2c 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/ble_mesh_demo_main.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/ble_mesh_demo_main.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.c index 4c51d04af7..192d730671 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.h index b00fc1e04b..09ebd40075 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.h +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/main/board.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.c index a9d3d8bc8b..89e0c2a416 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.h index 9dac3c241c..f98ba0eb1d 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.h +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_client_model.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_common.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_common.h index 6f4771239f..95a8ca80c0 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_common.h +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_common.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.c index c9a2bb795b..930baaf150 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.h index 3a3135062e..2fcc006063 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.h +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_operation.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.c index 99f4facff5..198b4bb75b 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.h index b4dec616a6..ef48c01fde 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.h +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components/esp_fast_prov_server_model.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/main.c index 889f706f78..3c9f9632ff 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/main.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/main/main.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/ble_mesh_demo_main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/ble_mesh_demo_main.c index ee0742e354..cdb2635add 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/ble_mesh_demo_main.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/ble_mesh_demo_main.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/board.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/board.c index 4c51d04af7..192d730671 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/board.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/board.c @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/board.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/board.h index b00fc1e04b..09ebd40075 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/board.h +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/board.h @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2017-2019 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. From b75f8b1b20c2b3c470b0b611125891e60c1d0de9 Mon Sep 17 00:00:00 2001 From: Anurag Kar Date: Wed, 26 Jun 2019 01:03:55 +0530 Subject: [PATCH 232/486] ESP Local Control Feature Added List of changes: * New component esp_local_ctrl added * Example added under examples/protocols/esp_local_ctrl * Documentation added under protocols/esp_local_ctrl * Demo client side app esp_local_ctrl.py added under examples/protocols/esp_local_ctrl/scripts * protocomm_ble : protocomm_ble_config_t given struct name for allowing forward declaration * esp_prov/transport_softap renamed to transport_http * transport_http module supports verification of server certificate * transport_http module performs name resolution before connection --- .flake8 | 1 + components/esp_local_ctrl/CMakeLists.txt | 23 + components/esp_local_ctrl/component.mk | 11 + .../esp_local_ctrl/include/esp_local_ctrl.h | 339 +++++++ .../proto-c/esp_local_ctrl.pb-c.c | 942 ++++++++++++++++++ .../proto-c/esp_local_ctrl.pb-c.h | 383 +++++++ .../esp_local_ctrl/proto/CMakeLists.txt | 30 + components/esp_local_ctrl/proto/README.md | 25 + .../esp_local_ctrl/proto/esp_local_ctrl.proto | 62 ++ components/esp_local_ctrl/proto/makefile | 7 + .../python/esp_local_ctrl_pb2.py | 549 ++++++++++ .../esp_local_ctrl/src/esp_local_ctrl.c | 417 ++++++++ .../src/esp_local_ctrl_handler.c | 298 ++++++ .../esp_local_ctrl/src/esp_local_ctrl_priv.h | 153 +++ .../src/esp_local_ctrl_transport_ble.c | 140 +++ .../src/esp_local_ctrl_transport_httpd.c | 128 +++ .../include/transports/protocomm_ble.h | 2 +- docs/Doxyfile | 3 + .../protocols/esp_local_ctrl.rst | 206 ++++ docs/en/api-reference/protocols/index.rst | 1 + .../protocols/esp_local_ctrl.rst | 1 + docs/zh_CN/api-reference/protocols/index.rst | 1 + .../protocols/esp_local_ctrl/CMakeLists.txt | 10 + examples/protocols/esp_local_ctrl/Makefile | 9 + examples/protocols/esp_local_ctrl/README.md | 93 ++ .../esp_local_ctrl/main/CMakeLists.txt | 8 + .../esp_local_ctrl/main/Kconfig.projbuild | 20 + .../protocols/esp_local_ctrl/main/app_main.c | 111 +++ .../esp_local_ctrl/main/certs/cacert.pem | 17 + .../esp_local_ctrl/main/certs/prvtkey.pem | 28 + .../esp_local_ctrl/main/certs/rootCA.pem | 19 + .../esp_local_ctrl/main/component.mk | 7 + .../main/esp_local_ctrl_service.c | 274 +++++ .../esp_local_ctrl/scripts/esp_local_ctrl.py | 273 +++++ .../protocols/esp_local_ctrl/scripts/proto.py | 93 ++ .../esp_local_ctrl/sdkconfig.defaults | 1 + tools/esp_prov/esp_prov.py | 2 +- tools/esp_prov/transport/__init__.py | 2 +- ...{transport_softap.py => transport_http.py} | 17 +- 39 files changed, 4700 insertions(+), 6 deletions(-) create mode 100644 components/esp_local_ctrl/CMakeLists.txt create mode 100644 components/esp_local_ctrl/component.mk create mode 100644 components/esp_local_ctrl/include/esp_local_ctrl.h create mode 100644 components/esp_local_ctrl/proto-c/esp_local_ctrl.pb-c.c create mode 100644 components/esp_local_ctrl/proto-c/esp_local_ctrl.pb-c.h create mode 100644 components/esp_local_ctrl/proto/CMakeLists.txt create mode 100644 components/esp_local_ctrl/proto/README.md create mode 100644 components/esp_local_ctrl/proto/esp_local_ctrl.proto create mode 100644 components/esp_local_ctrl/proto/makefile create mode 100644 components/esp_local_ctrl/python/esp_local_ctrl_pb2.py create mode 100644 components/esp_local_ctrl/src/esp_local_ctrl.c create mode 100644 components/esp_local_ctrl/src/esp_local_ctrl_handler.c create mode 100644 components/esp_local_ctrl/src/esp_local_ctrl_priv.h create mode 100644 components/esp_local_ctrl/src/esp_local_ctrl_transport_ble.c create mode 100644 components/esp_local_ctrl/src/esp_local_ctrl_transport_httpd.c create mode 100644 docs/en/api-reference/protocols/esp_local_ctrl.rst create mode 100644 docs/zh_CN/api-reference/protocols/esp_local_ctrl.rst create mode 100644 examples/protocols/esp_local_ctrl/CMakeLists.txt create mode 100644 examples/protocols/esp_local_ctrl/Makefile create mode 100644 examples/protocols/esp_local_ctrl/README.md create mode 100644 examples/protocols/esp_local_ctrl/main/CMakeLists.txt create mode 100644 examples/protocols/esp_local_ctrl/main/Kconfig.projbuild create mode 100644 examples/protocols/esp_local_ctrl/main/app_main.c create mode 100644 examples/protocols/esp_local_ctrl/main/certs/cacert.pem create mode 100644 examples/protocols/esp_local_ctrl/main/certs/prvtkey.pem create mode 100644 examples/protocols/esp_local_ctrl/main/certs/rootCA.pem create mode 100644 examples/protocols/esp_local_ctrl/main/component.mk create mode 100644 examples/protocols/esp_local_ctrl/main/esp_local_ctrl_service.c create mode 100644 examples/protocols/esp_local_ctrl/scripts/esp_local_ctrl.py create mode 100644 examples/protocols/esp_local_ctrl/scripts/proto.py create mode 100644 examples/protocols/esp_local_ctrl/sdkconfig.defaults rename tools/esp_prov/transport/{transport_softap.py => transport_http.py} (71%) diff --git a/.flake8 b/.flake8 index d03e1999a4..eda227ab4a 100644 --- a/.flake8 +++ b/.flake8 @@ -160,4 +160,5 @@ exclude = components/wifi_provisioning/python/wifi_scan_pb2.py, components/wifi_provisioning/python/wifi_config_pb2.py, components/wifi_provisioning/python/wifi_constants_pb2.py, + components/esp_local_ctrl/python/esp_local_ctrl_pb2.py, examples/provisioning/custom_config/components/custom_provisioning/python/custom_config_pb2.py, diff --git a/components/esp_local_ctrl/CMakeLists.txt b/components/esp_local_ctrl/CMakeLists.txt new file mode 100644 index 0000000000..562ed91911 --- /dev/null +++ b/components/esp_local_ctrl/CMakeLists.txt @@ -0,0 +1,23 @@ +set(include_dirs include) +set(priv_include_dirs proto-c src ../protocomm/proto-c) +set(srcs "src/esp_local_ctrl.c" + "src/esp_local_ctrl_handler.c" + "proto-c/esp_local_ctrl.pb-c.c") + +if(CONFIG_ESP_HTTPS_SERVER_ENABLE) + list(APPEND srcs + "src/esp_local_ctrl_transport_httpd.c") +endif() + +if(CONFIG_BT_ENABLED) + if(CONFIG_BT_BLUEDROID_ENABLED) + list(APPEND srcs + "src/esp_local_ctrl_transport_ble.c") + endif() +endif() + +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + PRIV_INCLUDE_DIRS "${priv_include_dirs}" + REQUIRES protocomm esp_https_server + PRIV_REQUIRES protobuf-c mdns) diff --git a/components/esp_local_ctrl/component.mk b/components/esp_local_ctrl/component.mk new file mode 100644 index 0000000000..c7d18301d4 --- /dev/null +++ b/components/esp_local_ctrl/component.mk @@ -0,0 +1,11 @@ +COMPONENT_SRCDIRS := src proto-c +COMPONENT_ADD_INCLUDEDIRS := include +COMPONENT_PRIV_INCLUDEDIRS := src proto-c ../protocomm/proto-c/ + +ifndef CONFIG_BT_BLUEDROID_ENABLED + COMPONENT_OBJEXCLUDE += src/esp_local_ctrl_transport_ble.o +endif + +ifndef CONFIG_ESP_HTTPS_SERVER_ENABLE + COMPONENT_OBJEXCLUDE += src/esp_local_ctrl_transport_httpd.o +endif diff --git a/components/esp_local_ctrl/include/esp_local_ctrl.h b/components/esp_local_ctrl/include/esp_local_ctrl.h new file mode 100644 index 0000000000..53d062b104 --- /dev/null +++ b/components/esp_local_ctrl/include/esp_local_ctrl.h @@ -0,0 +1,339 @@ +// Copyright 2019 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 + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * @brief Property description data structure, which is to be populated + * and passed to the `esp_local_ctrl_add_property()` function + * + * Once a property is added, its structure is available for read-only access + * inside `get_prop_values()` and `set_prop_values()` handlers. + */ +typedef struct esp_local_ctrl_prop { + /** + * Unique name of property + */ + char *name; + + /** + * Type of property. This may be set to application defined enums + */ + uint32_t type; + + /** + * Size of the property value, which: + * - if zero, the property can have values of variable size + * - if non-zero, the property can have values of fixed size only, + * therefore, checks are performed internally by esp_local_ctrl + * when setting the value of such a property + */ + size_t size; + + /** + * Flags set for this property. This could be a bit field. + * A flag may indicate property behavior, e.g. read-only / constant + */ + uint32_t flags; + + /** + * Pointer to some context data relevant for this property. This will + * be available for use inside the `get_prop_values` and `set_prop_values` + * handlers as a part of this property structure. When set, this is valid + * throughout the lifetime of a property, till either the property is + * removed or the esp_local_ctrl service is stopped. + */ + void *ctx; + + /** + * Function used by esp_local_ctrl to internally free the property + * context when `esp_local_ctrl_remove_property()` or + * `esp_local_ctrl_stop()` is called. + */ + void (*ctx_free_fn)(void *ctx); +} esp_local_ctrl_prop_t; + +/** + * @brief Property value data structure. This gets passed to the + * `get_prop_values()` and `set_prop_values()` handlers for + * the purpose of retrieving or setting the present value + * of a property. + */ +typedef struct esp_local_ctrl_prop_val { + /** + * Pointer to memory holding property value + */ + void *data; + + /** + * Size of property value + */ + size_t size; + + /** + * This may be set by the application in `get_prop_values()` handler + * to tell `esp_local_ctrl` to call this function on the data pointer + * above, for freeing its resources after sending the `get_prop_values` + * response. + */ + void (*free_fn)(void *data); +} esp_local_ctrl_prop_val_t; + +/** + * @brief Handlers for receiving and responding to local + * control commands for getting and setting properties. + */ +typedef struct esp_local_ctrl_handlers { + /** + * @brief Handler function to be implemented for retrieving current + * values of properties + * + * @note If any of the properties have fixed sizes, the size field of + * corresponding element in `prop_values` need to be set + * + * @param[in] props_count Total elements in the props array + * @param[in] props Array of properties, the current values for which + * have been requested by the client + * @param[out] prop_values Array of empty property values, the elements of + * which need to be populated with the current values + * of those properties specified by props argument + * @param[in] usr_ctx This provides value of the `usr_ctx` field of + * `esp_local_ctrl_handlers_t` structure + * + * @return Returning different error codes will convey the corresponding + * protocol level errors to the client : + * - ESP_OK : Success + * - ESP_ERR_INVALID_ARG : InvalidArgument + * - ESP_ERR_INVALID_STATE : InvalidProto + * - All other error codes : InternalError + */ + esp_err_t (*get_prop_values)(size_t props_count, + const esp_local_ctrl_prop_t props[], + esp_local_ctrl_prop_val_t prop_values[], + void *usr_ctx); + + /** + * @brief Handler function to be implemented for changing values of properties + * + * @note If any of the properties have variable sizes, the size field + * of the corresponding element in `prop_values` must be checked + * explicitly before making any assumptions on the size. + * + * @param[in] props_count Total elements in the props array + * @param[in] props Array of properties, the values for which the + * client requests to change + * @param[in] prop_values Array of property values, the elements of which + * need to be used for updating those properties + * specified by props argument + * @param[in] usr_ctx This provides value of the `usr_ctx` field of + * `esp_local_ctrl_handlers_t` structure + * + * @return Returning different error codes will convey the corresponding + * protocol level errors to the client : + * - ESP_OK : Success + * - ESP_ERR_INVALID_ARG : InvalidArgument + * - ESP_ERR_INVALID_STATE : InvalidProto + * - All other error codes : InternalError + */ + esp_err_t (*set_prop_values)(size_t props_count, + const esp_local_ctrl_prop_t props[], + const esp_local_ctrl_prop_val_t prop_values[], + void *usr_ctx); + + /** + * Context pointer to be passed to above handler functions upon invocation. + * This is different from the property level context, as this is valid + * throughout the lifetime of the `esp_local_ctrl` service, and freed only + * when the service is stopped. + */ + void *usr_ctx; + + /** + * Pointer to function which will be internally invoked on `usr_ctx` for + * freeing the context resources when `esp_local_ctrl_stop()` is called. + */ + void (*usr_ctx_free_fn)(void *usr_ctx); +} esp_local_ctrl_handlers_t; + +/** + * @brief Transport mode (BLE / HTTPD) over which the service will be provided + * + * This is forward declaration of a private structure, implemented internally + * by `esp_local_ctrl`. + */ +typedef struct esp_local_ctrl_transport esp_local_ctrl_transport_t; + +/** + * @brief Function for obtaining BLE transport mode + */ +const esp_local_ctrl_transport_t *esp_local_ctrl_get_transport_ble(); + +/** + * @brief Function for obtaining HTTPD transport mode + */ +const esp_local_ctrl_transport_t *esp_local_ctrl_get_transport_httpd(); + +#define ESP_LOCAL_CTRL_TRANSPORT_BLE esp_local_ctrl_get_transport_ble() +#define ESP_LOCAL_CTRL_TRANSPORT_HTTPD esp_local_ctrl_get_transport_httpd() + +/** + * @brief Configuration for transport mode BLE + * + * This is a forward declaration for `protocomm_ble_config_t`. + * To use this, application must set CONFIG_BT_BLUEDROID_ENABLED + * and include `protocomm_ble.h`. + */ +typedef struct protocomm_ble_config esp_local_ctrl_transport_config_ble_t; + +/** + * @brief Configuration for transport mode HTTPD + * + * This is a forward declaration for `httpd_ssl_config_t`. + * To use this, application must set CONFIG_ESP_HTTPS_SERVER_ENABLE + * and include `esp_https_server.h` + */ +typedef struct httpd_ssl_config esp_local_ctrl_transport_config_httpd_t; + +/** + * @brief Transport mode (BLE / HTTPD) configuration + */ +typedef union { + /** + * This is same as `protocomm_ble_config_t`. See `protocomm_ble.h` for + * available configuration parameters. + */ + esp_local_ctrl_transport_config_ble_t *ble; + + /** + * This is same as `httpd_ssl_config_t`. See `esp_https_server.h` for + * available configuration parameters. + */ + esp_local_ctrl_transport_config_httpd_t *httpd; +} esp_local_ctrl_transport_config_t; + +/** + * @brief Configuration structure to pass to `esp_local_ctrl_start()` + */ +typedef struct esp_local_ctrl_config { + /** + * Transport layer over which service will be provided + */ + const esp_local_ctrl_transport_t *transport; + + /** + * Transport layer over which service will be provided + */ + esp_local_ctrl_transport_config_t transport_config; + + /** + * Register handlers for responding to get/set requests on properties + */ + esp_local_ctrl_handlers_t handlers; + + /** + * This limits the number of properties that are available at a time + */ + size_t max_properties; +} esp_local_ctrl_config_t; + +/** + * @brief Start local control service + * + * @param[in] config Pointer to configuration structure + * + * @return + * - ESP_OK : Success + * - ESP_FAIL : Failure + */ +esp_err_t esp_local_ctrl_start(const esp_local_ctrl_config_t *config); + +/** + * @brief Stop local control service + */ +esp_err_t esp_local_ctrl_stop(void); + +/** + * @brief Add a new property + * + * This adds a new property and allocates internal resources for it. + * The total number of properties that could be added is limited by + * configuration option `max_properties` + * + * @param[in] prop Property description structure + * + * @return + * - ESP_OK : Success + * - ESP_FAIL : Failure + */ +esp_err_t esp_local_ctrl_add_property(const esp_local_ctrl_prop_t *prop); + +/** + * @brief Remove a property + * + * This finds a property by name, and releases the internal resources + * which are associated with it. + * + * @param[in] name Name of the property to remove + * + * @return + * - ESP_OK : Success + * - ESP_ERR_NOT_FOUND : Failure + */ +esp_err_t esp_local_ctrl_remove_property(const char *name); + +/** + * @brief Get property description structure by name + * + * This API may be used to get a property's context structure + * `esp_local_ctrl_prop_t` when its name is known + * + * @param[in] name Name of the property to find + * + * @return + * - Pointer to property + * - NULL if not found + */ +const esp_local_ctrl_prop_t *esp_local_ctrl_get_property(const char *name); + +/** + * @brief Register protocomm handler for a custom endpoint + * + * This API can be called by the application to register a protocomm handler + * for an endpoint after the local control service has started. + * + * @note In case of BLE transport the names and uuids of all custom + * endpoints must be provided beforehand as a part of the `protocomm_ble_config_t` + * structure set in `esp_local_ctrl_config_t`, and passed to `esp_local_ctrl_start()`. + * + * @param[in] ep_name Name of the endpoint + * @param[in] handler Endpoint handler function + * @param[in] user_ctx User data + * + * @return + * - ESP_OK : Success + * - ESP_FAIL : Failure + */ +esp_err_t esp_local_ctrl_set_handler(const char *ep_name, + protocomm_req_handler_t handler, + void *user_ctx); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_local_ctrl/proto-c/esp_local_ctrl.pb-c.c b/components/esp_local_ctrl/proto-c/esp_local_ctrl.pb-c.c new file mode 100644 index 0000000000..a6dd76eb2e --- /dev/null +++ b/components/esp_local_ctrl/proto-c/esp_local_ctrl.pb-c.c @@ -0,0 +1,942 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: esp_local_ctrl.proto */ + +/* Do not generate deprecated warnings for self */ +#ifndef PROTOBUF_C__NO_DEPRECATED +#define PROTOBUF_C__NO_DEPRECATED +#endif + +#include "esp_local_ctrl.pb-c.h" +void cmd_get_property_count__init + (CmdGetPropertyCount *message) +{ + static const CmdGetPropertyCount init_value = CMD_GET_PROPERTY_COUNT__INIT; + *message = init_value; +} +size_t cmd_get_property_count__get_packed_size + (const CmdGetPropertyCount *message) +{ + assert(message->base.descriptor == &cmd_get_property_count__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t cmd_get_property_count__pack + (const CmdGetPropertyCount *message, + uint8_t *out) +{ + assert(message->base.descriptor == &cmd_get_property_count__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t cmd_get_property_count__pack_to_buffer + (const CmdGetPropertyCount *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &cmd_get_property_count__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +CmdGetPropertyCount * + cmd_get_property_count__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (CmdGetPropertyCount *) + protobuf_c_message_unpack (&cmd_get_property_count__descriptor, + allocator, len, data); +} +void cmd_get_property_count__free_unpacked + (CmdGetPropertyCount *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &cmd_get_property_count__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void resp_get_property_count__init + (RespGetPropertyCount *message) +{ + static const RespGetPropertyCount init_value = RESP_GET_PROPERTY_COUNT__INIT; + *message = init_value; +} +size_t resp_get_property_count__get_packed_size + (const RespGetPropertyCount *message) +{ + assert(message->base.descriptor == &resp_get_property_count__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t resp_get_property_count__pack + (const RespGetPropertyCount *message, + uint8_t *out) +{ + assert(message->base.descriptor == &resp_get_property_count__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t resp_get_property_count__pack_to_buffer + (const RespGetPropertyCount *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &resp_get_property_count__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +RespGetPropertyCount * + resp_get_property_count__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (RespGetPropertyCount *) + protobuf_c_message_unpack (&resp_get_property_count__descriptor, + allocator, len, data); +} +void resp_get_property_count__free_unpacked + (RespGetPropertyCount *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &resp_get_property_count__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void property_info__init + (PropertyInfo *message) +{ + static const PropertyInfo init_value = PROPERTY_INFO__INIT; + *message = init_value; +} +size_t property_info__get_packed_size + (const PropertyInfo *message) +{ + assert(message->base.descriptor == &property_info__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t property_info__pack + (const PropertyInfo *message, + uint8_t *out) +{ + assert(message->base.descriptor == &property_info__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t property_info__pack_to_buffer + (const PropertyInfo *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &property_info__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +PropertyInfo * + property_info__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (PropertyInfo *) + protobuf_c_message_unpack (&property_info__descriptor, + allocator, len, data); +} +void property_info__free_unpacked + (PropertyInfo *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &property_info__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void cmd_get_property_values__init + (CmdGetPropertyValues *message) +{ + static const CmdGetPropertyValues init_value = CMD_GET_PROPERTY_VALUES__INIT; + *message = init_value; +} +size_t cmd_get_property_values__get_packed_size + (const CmdGetPropertyValues *message) +{ + assert(message->base.descriptor == &cmd_get_property_values__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t cmd_get_property_values__pack + (const CmdGetPropertyValues *message, + uint8_t *out) +{ + assert(message->base.descriptor == &cmd_get_property_values__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t cmd_get_property_values__pack_to_buffer + (const CmdGetPropertyValues *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &cmd_get_property_values__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +CmdGetPropertyValues * + cmd_get_property_values__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (CmdGetPropertyValues *) + protobuf_c_message_unpack (&cmd_get_property_values__descriptor, + allocator, len, data); +} +void cmd_get_property_values__free_unpacked + (CmdGetPropertyValues *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &cmd_get_property_values__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void resp_get_property_values__init + (RespGetPropertyValues *message) +{ + static const RespGetPropertyValues init_value = RESP_GET_PROPERTY_VALUES__INIT; + *message = init_value; +} +size_t resp_get_property_values__get_packed_size + (const RespGetPropertyValues *message) +{ + assert(message->base.descriptor == &resp_get_property_values__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t resp_get_property_values__pack + (const RespGetPropertyValues *message, + uint8_t *out) +{ + assert(message->base.descriptor == &resp_get_property_values__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t resp_get_property_values__pack_to_buffer + (const RespGetPropertyValues *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &resp_get_property_values__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +RespGetPropertyValues * + resp_get_property_values__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (RespGetPropertyValues *) + protobuf_c_message_unpack (&resp_get_property_values__descriptor, + allocator, len, data); +} +void resp_get_property_values__free_unpacked + (RespGetPropertyValues *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &resp_get_property_values__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void property_value__init + (PropertyValue *message) +{ + static const PropertyValue init_value = PROPERTY_VALUE__INIT; + *message = init_value; +} +size_t property_value__get_packed_size + (const PropertyValue *message) +{ + assert(message->base.descriptor == &property_value__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t property_value__pack + (const PropertyValue *message, + uint8_t *out) +{ + assert(message->base.descriptor == &property_value__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t property_value__pack_to_buffer + (const PropertyValue *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &property_value__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +PropertyValue * + property_value__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (PropertyValue *) + protobuf_c_message_unpack (&property_value__descriptor, + allocator, len, data); +} +void property_value__free_unpacked + (PropertyValue *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &property_value__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void cmd_set_property_values__init + (CmdSetPropertyValues *message) +{ + static const CmdSetPropertyValues init_value = CMD_SET_PROPERTY_VALUES__INIT; + *message = init_value; +} +size_t cmd_set_property_values__get_packed_size + (const CmdSetPropertyValues *message) +{ + assert(message->base.descriptor == &cmd_set_property_values__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t cmd_set_property_values__pack + (const CmdSetPropertyValues *message, + uint8_t *out) +{ + assert(message->base.descriptor == &cmd_set_property_values__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t cmd_set_property_values__pack_to_buffer + (const CmdSetPropertyValues *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &cmd_set_property_values__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +CmdSetPropertyValues * + cmd_set_property_values__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (CmdSetPropertyValues *) + protobuf_c_message_unpack (&cmd_set_property_values__descriptor, + allocator, len, data); +} +void cmd_set_property_values__free_unpacked + (CmdSetPropertyValues *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &cmd_set_property_values__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void resp_set_property_values__init + (RespSetPropertyValues *message) +{ + static const RespSetPropertyValues init_value = RESP_SET_PROPERTY_VALUES__INIT; + *message = init_value; +} +size_t resp_set_property_values__get_packed_size + (const RespSetPropertyValues *message) +{ + assert(message->base.descriptor == &resp_set_property_values__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t resp_set_property_values__pack + (const RespSetPropertyValues *message, + uint8_t *out) +{ + assert(message->base.descriptor == &resp_set_property_values__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t resp_set_property_values__pack_to_buffer + (const RespSetPropertyValues *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &resp_set_property_values__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +RespSetPropertyValues * + resp_set_property_values__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (RespSetPropertyValues *) + protobuf_c_message_unpack (&resp_set_property_values__descriptor, + allocator, len, data); +} +void resp_set_property_values__free_unpacked + (RespSetPropertyValues *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &resp_set_property_values__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void local_ctrl_message__init + (LocalCtrlMessage *message) +{ + static const LocalCtrlMessage init_value = LOCAL_CTRL_MESSAGE__INIT; + *message = init_value; +} +size_t local_ctrl_message__get_packed_size + (const LocalCtrlMessage *message) +{ + assert(message->base.descriptor == &local_ctrl_message__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t local_ctrl_message__pack + (const LocalCtrlMessage *message, + uint8_t *out) +{ + assert(message->base.descriptor == &local_ctrl_message__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t local_ctrl_message__pack_to_buffer + (const LocalCtrlMessage *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &local_ctrl_message__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +LocalCtrlMessage * + local_ctrl_message__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (LocalCtrlMessage *) + protobuf_c_message_unpack (&local_ctrl_message__descriptor, + allocator, len, data); +} +void local_ctrl_message__free_unpacked + (LocalCtrlMessage *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &local_ctrl_message__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +#define cmd_get_property_count__field_descriptors NULL +#define cmd_get_property_count__field_indices_by_name NULL +#define cmd_get_property_count__number_ranges NULL +const ProtobufCMessageDescriptor cmd_get_property_count__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "CmdGetPropertyCount", + "CmdGetPropertyCount", + "CmdGetPropertyCount", + "", + sizeof(CmdGetPropertyCount), + 0, + cmd_get_property_count__field_descriptors, + cmd_get_property_count__field_indices_by_name, + 0, cmd_get_property_count__number_ranges, + (ProtobufCMessageInit) cmd_get_property_count__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor resp_get_property_count__field_descriptors[2] = +{ + { + "status", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(RespGetPropertyCount, status), + &status__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "count", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(RespGetPropertyCount, count), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned resp_get_property_count__field_indices_by_name[] = { + 1, /* field[1] = count */ + 0, /* field[0] = status */ +}; +static const ProtobufCIntRange resp_get_property_count__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 2 } +}; +const ProtobufCMessageDescriptor resp_get_property_count__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "RespGetPropertyCount", + "RespGetPropertyCount", + "RespGetPropertyCount", + "", + sizeof(RespGetPropertyCount), + 2, + resp_get_property_count__field_descriptors, + resp_get_property_count__field_indices_by_name, + 1, resp_get_property_count__number_ranges, + (ProtobufCMessageInit) resp_get_property_count__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor property_info__field_descriptors[5] = +{ + { + "status", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(PropertyInfo, status), + &status__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "name", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(PropertyInfo, name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "type", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(PropertyInfo, type), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "flags", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(PropertyInfo, flags), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "value", + 5, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BYTES, + 0, /* quantifier_offset */ + offsetof(PropertyInfo, value), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned property_info__field_indices_by_name[] = { + 3, /* field[3] = flags */ + 1, /* field[1] = name */ + 0, /* field[0] = status */ + 2, /* field[2] = type */ + 4, /* field[4] = value */ +}; +static const ProtobufCIntRange property_info__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 5 } +}; +const ProtobufCMessageDescriptor property_info__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "PropertyInfo", + "PropertyInfo", + "PropertyInfo", + "", + sizeof(PropertyInfo), + 5, + property_info__field_descriptors, + property_info__field_indices_by_name, + 1, property_info__number_ranges, + (ProtobufCMessageInit) property_info__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor cmd_get_property_values__field_descriptors[1] = +{ + { + "indices", + 1, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_UINT32, + offsetof(CmdGetPropertyValues, n_indices), + offsetof(CmdGetPropertyValues, indices), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned cmd_get_property_values__field_indices_by_name[] = { + 0, /* field[0] = indices */ +}; +static const ProtobufCIntRange cmd_get_property_values__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 1 } +}; +const ProtobufCMessageDescriptor cmd_get_property_values__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "CmdGetPropertyValues", + "CmdGetPropertyValues", + "CmdGetPropertyValues", + "", + sizeof(CmdGetPropertyValues), + 1, + cmd_get_property_values__field_descriptors, + cmd_get_property_values__field_indices_by_name, + 1, cmd_get_property_values__number_ranges, + (ProtobufCMessageInit) cmd_get_property_values__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor resp_get_property_values__field_descriptors[2] = +{ + { + "status", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(RespGetPropertyValues, status), + &status__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "props", + 2, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(RespGetPropertyValues, n_props), + offsetof(RespGetPropertyValues, props), + &property_info__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned resp_get_property_values__field_indices_by_name[] = { + 1, /* field[1] = props */ + 0, /* field[0] = status */ +}; +static const ProtobufCIntRange resp_get_property_values__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 2 } +}; +const ProtobufCMessageDescriptor resp_get_property_values__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "RespGetPropertyValues", + "RespGetPropertyValues", + "RespGetPropertyValues", + "", + sizeof(RespGetPropertyValues), + 2, + resp_get_property_values__field_descriptors, + resp_get_property_values__field_indices_by_name, + 1, resp_get_property_values__number_ranges, + (ProtobufCMessageInit) resp_get_property_values__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor property_value__field_descriptors[2] = +{ + { + "index", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(PropertyValue, index), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "value", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BYTES, + 0, /* quantifier_offset */ + offsetof(PropertyValue, value), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned property_value__field_indices_by_name[] = { + 0, /* field[0] = index */ + 1, /* field[1] = value */ +}; +static const ProtobufCIntRange property_value__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 2 } +}; +const ProtobufCMessageDescriptor property_value__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "PropertyValue", + "PropertyValue", + "PropertyValue", + "", + sizeof(PropertyValue), + 2, + property_value__field_descriptors, + property_value__field_indices_by_name, + 1, property_value__number_ranges, + (ProtobufCMessageInit) property_value__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor cmd_set_property_values__field_descriptors[1] = +{ + { + "props", + 1, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(CmdSetPropertyValues, n_props), + offsetof(CmdSetPropertyValues, props), + &property_value__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned cmd_set_property_values__field_indices_by_name[] = { + 0, /* field[0] = props */ +}; +static const ProtobufCIntRange cmd_set_property_values__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 1 } +}; +const ProtobufCMessageDescriptor cmd_set_property_values__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "CmdSetPropertyValues", + "CmdSetPropertyValues", + "CmdSetPropertyValues", + "", + sizeof(CmdSetPropertyValues), + 1, + cmd_set_property_values__field_descriptors, + cmd_set_property_values__field_indices_by_name, + 1, cmd_set_property_values__number_ranges, + (ProtobufCMessageInit) cmd_set_property_values__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor resp_set_property_values__field_descriptors[1] = +{ + { + "status", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(RespSetPropertyValues, status), + &status__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned resp_set_property_values__field_indices_by_name[] = { + 0, /* field[0] = status */ +}; +static const ProtobufCIntRange resp_set_property_values__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 1 } +}; +const ProtobufCMessageDescriptor resp_set_property_values__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "RespSetPropertyValues", + "RespSetPropertyValues", + "RespSetPropertyValues", + "", + sizeof(RespSetPropertyValues), + 1, + resp_set_property_values__field_descriptors, + resp_set_property_values__field_indices_by_name, + 1, resp_set_property_values__number_ranges, + (ProtobufCMessageInit) resp_set_property_values__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor local_ctrl_message__field_descriptors[7] = +{ + { + "msg", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(LocalCtrlMessage, msg), + &local_ctrl_msg_type__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "cmd_get_prop_count", + 10, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(LocalCtrlMessage, payload_case), + offsetof(LocalCtrlMessage, cmd_get_prop_count), + &cmd_get_property_count__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "resp_get_prop_count", + 11, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(LocalCtrlMessage, payload_case), + offsetof(LocalCtrlMessage, resp_get_prop_count), + &resp_get_property_count__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "cmd_get_prop_vals", + 12, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(LocalCtrlMessage, payload_case), + offsetof(LocalCtrlMessage, cmd_get_prop_vals), + &cmd_get_property_values__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "resp_get_prop_vals", + 13, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(LocalCtrlMessage, payload_case), + offsetof(LocalCtrlMessage, resp_get_prop_vals), + &resp_get_property_values__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "cmd_set_prop_vals", + 14, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(LocalCtrlMessage, payload_case), + offsetof(LocalCtrlMessage, cmd_set_prop_vals), + &cmd_set_property_values__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "resp_set_prop_vals", + 15, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(LocalCtrlMessage, payload_case), + offsetof(LocalCtrlMessage, resp_set_prop_vals), + &resp_set_property_values__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned local_ctrl_message__field_indices_by_name[] = { + 1, /* field[1] = cmd_get_prop_count */ + 3, /* field[3] = cmd_get_prop_vals */ + 5, /* field[5] = cmd_set_prop_vals */ + 0, /* field[0] = msg */ + 2, /* field[2] = resp_get_prop_count */ + 4, /* field[4] = resp_get_prop_vals */ + 6, /* field[6] = resp_set_prop_vals */ +}; +static const ProtobufCIntRange local_ctrl_message__number_ranges[2 + 1] = +{ + { 1, 0 }, + { 10, 1 }, + { 0, 7 } +}; +const ProtobufCMessageDescriptor local_ctrl_message__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "LocalCtrlMessage", + "LocalCtrlMessage", + "LocalCtrlMessage", + "", + sizeof(LocalCtrlMessage), + 7, + local_ctrl_message__field_descriptors, + local_ctrl_message__field_indices_by_name, + 2, local_ctrl_message__number_ranges, + (ProtobufCMessageInit) local_ctrl_message__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCEnumValue local_ctrl_msg_type__enum_values_by_number[6] = +{ + { "TypeCmdGetPropertyCount", "LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyCount", 0 }, + { "TypeRespGetPropertyCount", "LOCAL_CTRL_MSG_TYPE__TypeRespGetPropertyCount", 1 }, + { "TypeCmdGetPropertyValues", "LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyValues", 4 }, + { "TypeRespGetPropertyValues", "LOCAL_CTRL_MSG_TYPE__TypeRespGetPropertyValues", 5 }, + { "TypeCmdSetPropertyValues", "LOCAL_CTRL_MSG_TYPE__TypeCmdSetPropertyValues", 6 }, + { "TypeRespSetPropertyValues", "LOCAL_CTRL_MSG_TYPE__TypeRespSetPropertyValues", 7 }, +}; +static const ProtobufCIntRange local_ctrl_msg_type__value_ranges[] = { +{0, 0},{4, 2},{0, 6} +}; +static const ProtobufCEnumValueIndex local_ctrl_msg_type__enum_values_by_name[6] = +{ + { "TypeCmdGetPropertyCount", 0 }, + { "TypeCmdGetPropertyValues", 2 }, + { "TypeCmdSetPropertyValues", 4 }, + { "TypeRespGetPropertyCount", 1 }, + { "TypeRespGetPropertyValues", 3 }, + { "TypeRespSetPropertyValues", 5 }, +}; +const ProtobufCEnumDescriptor local_ctrl_msg_type__descriptor = +{ + PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC, + "LocalCtrlMsgType", + "LocalCtrlMsgType", + "LocalCtrlMsgType", + "", + 6, + local_ctrl_msg_type__enum_values_by_number, + 6, + local_ctrl_msg_type__enum_values_by_name, + 2, + local_ctrl_msg_type__value_ranges, + NULL,NULL,NULL,NULL /* reserved[1234] */ +}; diff --git a/components/esp_local_ctrl/proto-c/esp_local_ctrl.pb-c.h b/components/esp_local_ctrl/proto-c/esp_local_ctrl.pb-c.h new file mode 100644 index 0000000000..1a1723ec48 --- /dev/null +++ b/components/esp_local_ctrl/proto-c/esp_local_ctrl.pb-c.h @@ -0,0 +1,383 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: esp_local_ctrl.proto */ + +#ifndef PROTOBUF_C_esp_5flocal_5fctrl_2eproto__INCLUDED +#define PROTOBUF_C_esp_5flocal_5fctrl_2eproto__INCLUDED + +#include + +PROTOBUF_C__BEGIN_DECLS + +#if PROTOBUF_C_VERSION_NUMBER < 1003000 +# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. +#elif 1003001 < PROTOBUF_C_MIN_COMPILER_VERSION +# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. +#endif + +#include "constants.pb-c.h" + +typedef struct _CmdGetPropertyCount CmdGetPropertyCount; +typedef struct _RespGetPropertyCount RespGetPropertyCount; +typedef struct _PropertyInfo PropertyInfo; +typedef struct _CmdGetPropertyValues CmdGetPropertyValues; +typedef struct _RespGetPropertyValues RespGetPropertyValues; +typedef struct _PropertyValue PropertyValue; +typedef struct _CmdSetPropertyValues CmdSetPropertyValues; +typedef struct _RespSetPropertyValues RespSetPropertyValues; +typedef struct _LocalCtrlMessage LocalCtrlMessage; + + +/* --- enums --- */ + +typedef enum _LocalCtrlMsgType { + LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyCount = 0, + LOCAL_CTRL_MSG_TYPE__TypeRespGetPropertyCount = 1, + LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyValues = 4, + LOCAL_CTRL_MSG_TYPE__TypeRespGetPropertyValues = 5, + LOCAL_CTRL_MSG_TYPE__TypeCmdSetPropertyValues = 6, + LOCAL_CTRL_MSG_TYPE__TypeRespSetPropertyValues = 7 + PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(LOCAL_CTRL_MSG_TYPE) +} LocalCtrlMsgType; + +/* --- messages --- */ + +struct _CmdGetPropertyCount +{ + ProtobufCMessage base; +}; +#define CMD_GET_PROPERTY_COUNT__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&cmd_get_property_count__descriptor) \ + } + + +struct _RespGetPropertyCount +{ + ProtobufCMessage base; + Status status; + uint32_t count; +}; +#define RESP_GET_PROPERTY_COUNT__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&resp_get_property_count__descriptor) \ + , STATUS__Success, 0 } + + +struct _PropertyInfo +{ + ProtobufCMessage base; + Status status; + char *name; + uint32_t type; + uint32_t flags; + ProtobufCBinaryData value; +}; +#define PROPERTY_INFO__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&property_info__descriptor) \ + , STATUS__Success, (char *)protobuf_c_empty_string, 0, 0, {0,NULL} } + + +struct _CmdGetPropertyValues +{ + ProtobufCMessage base; + size_t n_indices; + uint32_t *indices; +}; +#define CMD_GET_PROPERTY_VALUES__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&cmd_get_property_values__descriptor) \ + , 0,NULL } + + +struct _RespGetPropertyValues +{ + ProtobufCMessage base; + Status status; + size_t n_props; + PropertyInfo **props; +}; +#define RESP_GET_PROPERTY_VALUES__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&resp_get_property_values__descriptor) \ + , STATUS__Success, 0,NULL } + + +struct _PropertyValue +{ + ProtobufCMessage base; + uint32_t index; + ProtobufCBinaryData value; +}; +#define PROPERTY_VALUE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&property_value__descriptor) \ + , 0, {0,NULL} } + + +struct _CmdSetPropertyValues +{ + ProtobufCMessage base; + size_t n_props; + PropertyValue **props; +}; +#define CMD_SET_PROPERTY_VALUES__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&cmd_set_property_values__descriptor) \ + , 0,NULL } + + +struct _RespSetPropertyValues +{ + ProtobufCMessage base; + Status status; +}; +#define RESP_SET_PROPERTY_VALUES__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&resp_set_property_values__descriptor) \ + , STATUS__Success } + + +typedef enum { + LOCAL_CTRL_MESSAGE__PAYLOAD__NOT_SET = 0, + LOCAL_CTRL_MESSAGE__PAYLOAD_CMD_GET_PROP_COUNT = 10, + LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_GET_PROP_COUNT = 11, + LOCAL_CTRL_MESSAGE__PAYLOAD_CMD_GET_PROP_VALS = 12, + LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_GET_PROP_VALS = 13, + LOCAL_CTRL_MESSAGE__PAYLOAD_CMD_SET_PROP_VALS = 14, + LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_SET_PROP_VALS = 15 + PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(LOCAL_CTRL_MESSAGE__PAYLOAD) +} LocalCtrlMessage__PayloadCase; + +struct _LocalCtrlMessage +{ + ProtobufCMessage base; + LocalCtrlMsgType msg; + LocalCtrlMessage__PayloadCase payload_case; + union { + CmdGetPropertyCount *cmd_get_prop_count; + RespGetPropertyCount *resp_get_prop_count; + CmdGetPropertyValues *cmd_get_prop_vals; + RespGetPropertyValues *resp_get_prop_vals; + CmdSetPropertyValues *cmd_set_prop_vals; + RespSetPropertyValues *resp_set_prop_vals; + }; +}; +#define LOCAL_CTRL_MESSAGE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&local_ctrl_message__descriptor) \ + , LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyCount, LOCAL_CTRL_MESSAGE__PAYLOAD__NOT_SET, {0} } + + +/* CmdGetPropertyCount methods */ +void cmd_get_property_count__init + (CmdGetPropertyCount *message); +size_t cmd_get_property_count__get_packed_size + (const CmdGetPropertyCount *message); +size_t cmd_get_property_count__pack + (const CmdGetPropertyCount *message, + uint8_t *out); +size_t cmd_get_property_count__pack_to_buffer + (const CmdGetPropertyCount *message, + ProtobufCBuffer *buffer); +CmdGetPropertyCount * + cmd_get_property_count__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void cmd_get_property_count__free_unpacked + (CmdGetPropertyCount *message, + ProtobufCAllocator *allocator); +/* RespGetPropertyCount methods */ +void resp_get_property_count__init + (RespGetPropertyCount *message); +size_t resp_get_property_count__get_packed_size + (const RespGetPropertyCount *message); +size_t resp_get_property_count__pack + (const RespGetPropertyCount *message, + uint8_t *out); +size_t resp_get_property_count__pack_to_buffer + (const RespGetPropertyCount *message, + ProtobufCBuffer *buffer); +RespGetPropertyCount * + resp_get_property_count__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void resp_get_property_count__free_unpacked + (RespGetPropertyCount *message, + ProtobufCAllocator *allocator); +/* PropertyInfo methods */ +void property_info__init + (PropertyInfo *message); +size_t property_info__get_packed_size + (const PropertyInfo *message); +size_t property_info__pack + (const PropertyInfo *message, + uint8_t *out); +size_t property_info__pack_to_buffer + (const PropertyInfo *message, + ProtobufCBuffer *buffer); +PropertyInfo * + property_info__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void property_info__free_unpacked + (PropertyInfo *message, + ProtobufCAllocator *allocator); +/* CmdGetPropertyValues methods */ +void cmd_get_property_values__init + (CmdGetPropertyValues *message); +size_t cmd_get_property_values__get_packed_size + (const CmdGetPropertyValues *message); +size_t cmd_get_property_values__pack + (const CmdGetPropertyValues *message, + uint8_t *out); +size_t cmd_get_property_values__pack_to_buffer + (const CmdGetPropertyValues *message, + ProtobufCBuffer *buffer); +CmdGetPropertyValues * + cmd_get_property_values__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void cmd_get_property_values__free_unpacked + (CmdGetPropertyValues *message, + ProtobufCAllocator *allocator); +/* RespGetPropertyValues methods */ +void resp_get_property_values__init + (RespGetPropertyValues *message); +size_t resp_get_property_values__get_packed_size + (const RespGetPropertyValues *message); +size_t resp_get_property_values__pack + (const RespGetPropertyValues *message, + uint8_t *out); +size_t resp_get_property_values__pack_to_buffer + (const RespGetPropertyValues *message, + ProtobufCBuffer *buffer); +RespGetPropertyValues * + resp_get_property_values__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void resp_get_property_values__free_unpacked + (RespGetPropertyValues *message, + ProtobufCAllocator *allocator); +/* PropertyValue methods */ +void property_value__init + (PropertyValue *message); +size_t property_value__get_packed_size + (const PropertyValue *message); +size_t property_value__pack + (const PropertyValue *message, + uint8_t *out); +size_t property_value__pack_to_buffer + (const PropertyValue *message, + ProtobufCBuffer *buffer); +PropertyValue * + property_value__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void property_value__free_unpacked + (PropertyValue *message, + ProtobufCAllocator *allocator); +/* CmdSetPropertyValues methods */ +void cmd_set_property_values__init + (CmdSetPropertyValues *message); +size_t cmd_set_property_values__get_packed_size + (const CmdSetPropertyValues *message); +size_t cmd_set_property_values__pack + (const CmdSetPropertyValues *message, + uint8_t *out); +size_t cmd_set_property_values__pack_to_buffer + (const CmdSetPropertyValues *message, + ProtobufCBuffer *buffer); +CmdSetPropertyValues * + cmd_set_property_values__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void cmd_set_property_values__free_unpacked + (CmdSetPropertyValues *message, + ProtobufCAllocator *allocator); +/* RespSetPropertyValues methods */ +void resp_set_property_values__init + (RespSetPropertyValues *message); +size_t resp_set_property_values__get_packed_size + (const RespSetPropertyValues *message); +size_t resp_set_property_values__pack + (const RespSetPropertyValues *message, + uint8_t *out); +size_t resp_set_property_values__pack_to_buffer + (const RespSetPropertyValues *message, + ProtobufCBuffer *buffer); +RespSetPropertyValues * + resp_set_property_values__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void resp_set_property_values__free_unpacked + (RespSetPropertyValues *message, + ProtobufCAllocator *allocator); +/* LocalCtrlMessage methods */ +void local_ctrl_message__init + (LocalCtrlMessage *message); +size_t local_ctrl_message__get_packed_size + (const LocalCtrlMessage *message); +size_t local_ctrl_message__pack + (const LocalCtrlMessage *message, + uint8_t *out); +size_t local_ctrl_message__pack_to_buffer + (const LocalCtrlMessage *message, + ProtobufCBuffer *buffer); +LocalCtrlMessage * + local_ctrl_message__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void local_ctrl_message__free_unpacked + (LocalCtrlMessage *message, + ProtobufCAllocator *allocator); +/* --- per-message closures --- */ + +typedef void (*CmdGetPropertyCount_Closure) + (const CmdGetPropertyCount *message, + void *closure_data); +typedef void (*RespGetPropertyCount_Closure) + (const RespGetPropertyCount *message, + void *closure_data); +typedef void (*PropertyInfo_Closure) + (const PropertyInfo *message, + void *closure_data); +typedef void (*CmdGetPropertyValues_Closure) + (const CmdGetPropertyValues *message, + void *closure_data); +typedef void (*RespGetPropertyValues_Closure) + (const RespGetPropertyValues *message, + void *closure_data); +typedef void (*PropertyValue_Closure) + (const PropertyValue *message, + void *closure_data); +typedef void (*CmdSetPropertyValues_Closure) + (const CmdSetPropertyValues *message, + void *closure_data); +typedef void (*RespSetPropertyValues_Closure) + (const RespSetPropertyValues *message, + void *closure_data); +typedef void (*LocalCtrlMessage_Closure) + (const LocalCtrlMessage *message, + void *closure_data); + +/* --- services --- */ + + +/* --- descriptors --- */ + +extern const ProtobufCEnumDescriptor local_ctrl_msg_type__descriptor; +extern const ProtobufCMessageDescriptor cmd_get_property_count__descriptor; +extern const ProtobufCMessageDescriptor resp_get_property_count__descriptor; +extern const ProtobufCMessageDescriptor property_info__descriptor; +extern const ProtobufCMessageDescriptor cmd_get_property_values__descriptor; +extern const ProtobufCMessageDescriptor resp_get_property_values__descriptor; +extern const ProtobufCMessageDescriptor property_value__descriptor; +extern const ProtobufCMessageDescriptor cmd_set_property_values__descriptor; +extern const ProtobufCMessageDescriptor resp_set_property_values__descriptor; +extern const ProtobufCMessageDescriptor local_ctrl_message__descriptor; + +PROTOBUF_C__END_DECLS + + +#endif /* PROTOBUF_C_esp_5flocal_5fctrl_2eproto__INCLUDED */ diff --git a/components/esp_local_ctrl/proto/CMakeLists.txt b/components/esp_local_ctrl/proto/CMakeLists.txt new file mode 100644 index 0000000000..ffe6a54252 --- /dev/null +++ b/components/esp_local_ctrl/proto/CMakeLists.txt @@ -0,0 +1,30 @@ +cmake_minimum_required(VERSION 3.5) + +set(PROTO_COMPILER "protoc") +set(PROTO_C_COMPILER "protoc-c") +set(C_OUT_PATH "${CMAKE_CURRENT_LIST_DIR}/../proto-c") +set(PY_OUT_PATH "${CMAKE_CURRENT_LIST_DIR}/../python") +set(PROTOCOMM_INCL_PATH "${CMAKE_CURRENT_LIST_DIR}/../../protocomm/proto") + +file(GLOB PROTO_FILES + LIST_DIRECTORIES false + RELATIVE ${CMAKE_CURRENT_LIST_DIR} + "*.proto") + +add_custom_target(c_proto + COMMAND ${PROTO_C_COMPILER} --c_out=${C_OUT_PATH} -I . -I ${PROTOCOMM_INCL_PATH} ${PROTO_FILES} + VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + ) + +add_custom_target(python_proto + COMMAND ${PROTO_COMPILER} --python_out=${PY_OUT_PATH} -I . -I ${PROTOCOMM_INCL_PATH} ${PROTO_FILES} + VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + ) + +add_custom_target(proto ALL + DEPENDS c_proto python_proto + VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + ) diff --git a/components/esp_local_ctrl/proto/README.md b/components/esp_local_ctrl/proto/README.md new file mode 100644 index 0000000000..cdb4e2ce2a --- /dev/null +++ b/components/esp_local_ctrl/proto/README.md @@ -0,0 +1,25 @@ +# Protobuf files for defining ESP Local Control message structures + +The proto files under this directory are used by esp_local_ctrl for defining protobuf messages which are sent and received over protocomm transport layer. These proto files cannot be used directly and have to be compiled into C and Python files. The generated C files are used by esp_local_ctrl itself to create, delete and manipulate transaction packets. The generated Python files can be used by python based applications for implementing client side interface to esp_local_ctrl service running on a device. + +Note : These proto files are not automatically compiled during the build process. + +# Compilation + +Compilation requires protoc (Protobuf Compiler) and protoc-c (Protobuf C Compiler) installed. Since the generated files are to remain the same, as long as the proto files are not modified, therefore the generated files are already available under `components/esp_local_ctrl/proto-c` and `components/esp_local_ctrl/python` directories, and thus running `cmake` / `make` (and installing the Protobuf compilers) is optional. + +If using `cmake` follow the below steps. If using `make`, jump to Step 2 directly. + +## Step 1 (Only for cmake) + +When using cmake, first create a build directory and call cmake from inside: + +``` +mkdir build +cd build +cmake .. +``` + +## Step 2 + +Simply run `make` to generate the respective C and Python files. The newly created files will overwrite those under `components/esp_local_ctrl/proto-c` and `components/esp_local_ctrl/python` diff --git a/components/esp_local_ctrl/proto/esp_local_ctrl.proto b/components/esp_local_ctrl/proto/esp_local_ctrl.proto new file mode 100644 index 0000000000..1d91b56c2d --- /dev/null +++ b/components/esp_local_ctrl/proto/esp_local_ctrl.proto @@ -0,0 +1,62 @@ +syntax = "proto3"; + +import "constants.proto"; + +message CmdGetPropertyCount { +} + +message RespGetPropertyCount { + Status status = 1; + uint32 count = 2; +} + +message PropertyInfo { + Status status = 1; + string name = 2; + uint32 type = 3; + uint32 flags = 4; + bytes value = 5; +} + +message CmdGetPropertyValues { + repeated uint32 indices = 1; +} + +message RespGetPropertyValues { + Status status = 1; + repeated PropertyInfo props = 2; +} + +message PropertyValue { + uint32 index = 1; + bytes value = 2; +} + +message CmdSetPropertyValues { + repeated PropertyValue props = 1; +} + +message RespSetPropertyValues { + Status status = 1; +} + +enum LocalCtrlMsgType { + TypeCmdGetPropertyCount = 0; + TypeRespGetPropertyCount = 1; + TypeCmdGetPropertyValues = 4; + TypeRespGetPropertyValues = 5; + TypeCmdSetPropertyValues = 6; + TypeRespSetPropertyValues = 7; +} + +message LocalCtrlMessage { + LocalCtrlMsgType msg = 1; + oneof payload { + CmdGetPropertyCount cmd_get_prop_count = 10; + RespGetPropertyCount resp_get_prop_count = 11; + CmdGetPropertyValues cmd_get_prop_vals = 12; + RespGetPropertyValues resp_get_prop_vals = 13; + CmdSetPropertyValues cmd_set_prop_vals = 14; + RespSetPropertyValues resp_set_prop_vals = 15; + } +} diff --git a/components/esp_local_ctrl/proto/makefile b/components/esp_local_ctrl/proto/makefile new file mode 100644 index 0000000000..585e42267b --- /dev/null +++ b/components/esp_local_ctrl/proto/makefile @@ -0,0 +1,7 @@ +all: c_proto python_proto + +c_proto: *.proto + @protoc-c --c_out=../proto-c/ -I . -I ../../protocomm/proto/ *.proto + +python_proto: *.proto + @protoc --python_out=../python/ -I . -I ../../protocomm/proto/ *.proto diff --git a/components/esp_local_ctrl/python/esp_local_ctrl_pb2.py b/components/esp_local_ctrl/python/esp_local_ctrl_pb2.py new file mode 100644 index 0000000000..39f081f230 --- /dev/null +++ b/components/esp_local_ctrl/python/esp_local_ctrl_pb2.py @@ -0,0 +1,549 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: esp_local_ctrl.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf.internal import enum_type_wrapper +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +import constants_pb2 as constants__pb2 + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='esp_local_ctrl.proto', + package='', + syntax='proto3', + serialized_options=None, + serialized_pb=_b('\n\x14\x65sp_local_ctrl.proto\x1a\x0f\x63onstants.proto\"\x15\n\x13\x43mdGetPropertyCount\">\n\x14RespGetPropertyCount\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\x12\r\n\x05\x63ount\x18\x02 \x01(\r\"a\n\x0cPropertyInfo\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0c\n\x04type\x18\x03 \x01(\r\x12\r\n\x05\x66lags\x18\x04 \x01(\r\x12\r\n\x05value\x18\x05 \x01(\x0c\"\'\n\x14\x43mdGetPropertyValues\x12\x0f\n\x07indices\x18\x01 \x03(\r\"N\n\x15RespGetPropertyValues\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\x12\x1c\n\x05props\x18\x02 \x03(\x0b\x32\r.PropertyInfo\"-\n\rPropertyValue\x12\r\n\x05index\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\x0c\"5\n\x14\x43mdSetPropertyValues\x12\x1d\n\x05props\x18\x01 \x03(\x0b\x32\x0e.PropertyValue\"0\n\x15RespSetPropertyValues\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\"\xfb\x02\n\x10LocalCtrlMessage\x12\x1e\n\x03msg\x18\x01 \x01(\x0e\x32\x11.LocalCtrlMsgType\x12\x32\n\x12\x63md_get_prop_count\x18\n \x01(\x0b\x32\x14.CmdGetPropertyCountH\x00\x12\x34\n\x13resp_get_prop_count\x18\x0b \x01(\x0b\x32\x15.RespGetPropertyCountH\x00\x12\x32\n\x11\x63md_get_prop_vals\x18\x0c \x01(\x0b\x32\x15.CmdGetPropertyValuesH\x00\x12\x34\n\x12resp_get_prop_vals\x18\r \x01(\x0b\x32\x16.RespGetPropertyValuesH\x00\x12\x32\n\x11\x63md_set_prop_vals\x18\x0e \x01(\x0b\x32\x15.CmdSetPropertyValuesH\x00\x12\x34\n\x12resp_set_prop_vals\x18\x0f \x01(\x0b\x32\x16.RespSetPropertyValuesH\x00\x42\t\n\x07payload*\xc7\x01\n\x10LocalCtrlMsgType\x12\x1b\n\x17TypeCmdGetPropertyCount\x10\x00\x12\x1c\n\x18TypeRespGetPropertyCount\x10\x01\x12\x1c\n\x18TypeCmdGetPropertyValues\x10\x04\x12\x1d\n\x19TypeRespGetPropertyValues\x10\x05\x12\x1c\n\x18TypeCmdSetPropertyValues\x10\x06\x12\x1d\n\x19TypeRespSetPropertyValues\x10\x07\x62\x06proto3') + , + dependencies=[constants__pb2.DESCRIPTOR,]) + +_LOCALCTRLMSGTYPE = _descriptor.EnumDescriptor( + name='LocalCtrlMsgType', + full_name='LocalCtrlMsgType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='TypeCmdGetPropertyCount', index=0, number=0, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='TypeRespGetPropertyCount', index=1, number=1, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='TypeCmdGetPropertyValues', index=2, number=4, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='TypeRespGetPropertyValues', index=3, number=5, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='TypeCmdSetPropertyValues', index=4, number=6, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='TypeRespSetPropertyValues', index=5, number=7, + serialized_options=None, + type=None), + ], + containing_type=None, + serialized_options=None, + serialized_start=883, + serialized_end=1082, +) +_sym_db.RegisterEnumDescriptor(_LOCALCTRLMSGTYPE) + +LocalCtrlMsgType = enum_type_wrapper.EnumTypeWrapper(_LOCALCTRLMSGTYPE) +TypeCmdGetPropertyCount = 0 +TypeRespGetPropertyCount = 1 +TypeCmdGetPropertyValues = 4 +TypeRespGetPropertyValues = 5 +TypeCmdSetPropertyValues = 6 +TypeRespSetPropertyValues = 7 + + + +_CMDGETPROPERTYCOUNT = _descriptor.Descriptor( + name='CmdGetPropertyCount', + full_name='CmdGetPropertyCount', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=41, + serialized_end=62, +) + + +_RESPGETPROPERTYCOUNT = _descriptor.Descriptor( + name='RespGetPropertyCount', + full_name='RespGetPropertyCount', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='status', full_name='RespGetPropertyCount.status', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='count', full_name='RespGetPropertyCount.count', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=64, + serialized_end=126, +) + + +_PROPERTYINFO = _descriptor.Descriptor( + name='PropertyInfo', + full_name='PropertyInfo', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='status', full_name='PropertyInfo.status', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='name', full_name='PropertyInfo.name', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='type', full_name='PropertyInfo.type', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='flags', full_name='PropertyInfo.flags', index=3, + number=4, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='value', full_name='PropertyInfo.value', index=4, + number=5, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=128, + serialized_end=225, +) + + +_CMDGETPROPERTYVALUES = _descriptor.Descriptor( + name='CmdGetPropertyValues', + full_name='CmdGetPropertyValues', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='indices', full_name='CmdGetPropertyValues.indices', index=0, + number=1, type=13, cpp_type=3, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=227, + serialized_end=266, +) + + +_RESPGETPROPERTYVALUES = _descriptor.Descriptor( + name='RespGetPropertyValues', + full_name='RespGetPropertyValues', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='status', full_name='RespGetPropertyValues.status', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='props', full_name='RespGetPropertyValues.props', index=1, + number=2, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=268, + serialized_end=346, +) + + +_PROPERTYVALUE = _descriptor.Descriptor( + name='PropertyValue', + full_name='PropertyValue', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='index', full_name='PropertyValue.index', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='value', full_name='PropertyValue.value', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=348, + serialized_end=393, +) + + +_CMDSETPROPERTYVALUES = _descriptor.Descriptor( + name='CmdSetPropertyValues', + full_name='CmdSetPropertyValues', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='props', full_name='CmdSetPropertyValues.props', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=395, + serialized_end=448, +) + + +_RESPSETPROPERTYVALUES = _descriptor.Descriptor( + name='RespSetPropertyValues', + full_name='RespSetPropertyValues', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='status', full_name='RespSetPropertyValues.status', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=450, + serialized_end=498, +) + + +_LOCALCTRLMESSAGE = _descriptor.Descriptor( + name='LocalCtrlMessage', + full_name='LocalCtrlMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='msg', full_name='LocalCtrlMessage.msg', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='cmd_get_prop_count', full_name='LocalCtrlMessage.cmd_get_prop_count', index=1, + number=10, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='resp_get_prop_count', full_name='LocalCtrlMessage.resp_get_prop_count', index=2, + number=11, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='cmd_get_prop_vals', full_name='LocalCtrlMessage.cmd_get_prop_vals', index=3, + number=12, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='resp_get_prop_vals', full_name='LocalCtrlMessage.resp_get_prop_vals', index=4, + number=13, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='cmd_set_prop_vals', full_name='LocalCtrlMessage.cmd_set_prop_vals', index=5, + number=14, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='resp_set_prop_vals', full_name='LocalCtrlMessage.resp_set_prop_vals', index=6, + number=15, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='payload', full_name='LocalCtrlMessage.payload', + index=0, containing_type=None, fields=[]), + ], + serialized_start=501, + serialized_end=880, +) + +_RESPGETPROPERTYCOUNT.fields_by_name['status'].enum_type = constants__pb2._STATUS +_PROPERTYINFO.fields_by_name['status'].enum_type = constants__pb2._STATUS +_RESPGETPROPERTYVALUES.fields_by_name['status'].enum_type = constants__pb2._STATUS +_RESPGETPROPERTYVALUES.fields_by_name['props'].message_type = _PROPERTYINFO +_CMDSETPROPERTYVALUES.fields_by_name['props'].message_type = _PROPERTYVALUE +_RESPSETPROPERTYVALUES.fields_by_name['status'].enum_type = constants__pb2._STATUS +_LOCALCTRLMESSAGE.fields_by_name['msg'].enum_type = _LOCALCTRLMSGTYPE +_LOCALCTRLMESSAGE.fields_by_name['cmd_get_prop_count'].message_type = _CMDGETPROPERTYCOUNT +_LOCALCTRLMESSAGE.fields_by_name['resp_get_prop_count'].message_type = _RESPGETPROPERTYCOUNT +_LOCALCTRLMESSAGE.fields_by_name['cmd_get_prop_vals'].message_type = _CMDGETPROPERTYVALUES +_LOCALCTRLMESSAGE.fields_by_name['resp_get_prop_vals'].message_type = _RESPGETPROPERTYVALUES +_LOCALCTRLMESSAGE.fields_by_name['cmd_set_prop_vals'].message_type = _CMDSETPROPERTYVALUES +_LOCALCTRLMESSAGE.fields_by_name['resp_set_prop_vals'].message_type = _RESPSETPROPERTYVALUES +_LOCALCTRLMESSAGE.oneofs_by_name['payload'].fields.append( + _LOCALCTRLMESSAGE.fields_by_name['cmd_get_prop_count']) +_LOCALCTRLMESSAGE.fields_by_name['cmd_get_prop_count'].containing_oneof = _LOCALCTRLMESSAGE.oneofs_by_name['payload'] +_LOCALCTRLMESSAGE.oneofs_by_name['payload'].fields.append( + _LOCALCTRLMESSAGE.fields_by_name['resp_get_prop_count']) +_LOCALCTRLMESSAGE.fields_by_name['resp_get_prop_count'].containing_oneof = _LOCALCTRLMESSAGE.oneofs_by_name['payload'] +_LOCALCTRLMESSAGE.oneofs_by_name['payload'].fields.append( + _LOCALCTRLMESSAGE.fields_by_name['cmd_get_prop_vals']) +_LOCALCTRLMESSAGE.fields_by_name['cmd_get_prop_vals'].containing_oneof = _LOCALCTRLMESSAGE.oneofs_by_name['payload'] +_LOCALCTRLMESSAGE.oneofs_by_name['payload'].fields.append( + _LOCALCTRLMESSAGE.fields_by_name['resp_get_prop_vals']) +_LOCALCTRLMESSAGE.fields_by_name['resp_get_prop_vals'].containing_oneof = _LOCALCTRLMESSAGE.oneofs_by_name['payload'] +_LOCALCTRLMESSAGE.oneofs_by_name['payload'].fields.append( + _LOCALCTRLMESSAGE.fields_by_name['cmd_set_prop_vals']) +_LOCALCTRLMESSAGE.fields_by_name['cmd_set_prop_vals'].containing_oneof = _LOCALCTRLMESSAGE.oneofs_by_name['payload'] +_LOCALCTRLMESSAGE.oneofs_by_name['payload'].fields.append( + _LOCALCTRLMESSAGE.fields_by_name['resp_set_prop_vals']) +_LOCALCTRLMESSAGE.fields_by_name['resp_set_prop_vals'].containing_oneof = _LOCALCTRLMESSAGE.oneofs_by_name['payload'] +DESCRIPTOR.message_types_by_name['CmdGetPropertyCount'] = _CMDGETPROPERTYCOUNT +DESCRIPTOR.message_types_by_name['RespGetPropertyCount'] = _RESPGETPROPERTYCOUNT +DESCRIPTOR.message_types_by_name['PropertyInfo'] = _PROPERTYINFO +DESCRIPTOR.message_types_by_name['CmdGetPropertyValues'] = _CMDGETPROPERTYVALUES +DESCRIPTOR.message_types_by_name['RespGetPropertyValues'] = _RESPGETPROPERTYVALUES +DESCRIPTOR.message_types_by_name['PropertyValue'] = _PROPERTYVALUE +DESCRIPTOR.message_types_by_name['CmdSetPropertyValues'] = _CMDSETPROPERTYVALUES +DESCRIPTOR.message_types_by_name['RespSetPropertyValues'] = _RESPSETPROPERTYVALUES +DESCRIPTOR.message_types_by_name['LocalCtrlMessage'] = _LOCALCTRLMESSAGE +DESCRIPTOR.enum_types_by_name['LocalCtrlMsgType'] = _LOCALCTRLMSGTYPE +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +CmdGetPropertyCount = _reflection.GeneratedProtocolMessageType('CmdGetPropertyCount', (_message.Message,), dict( + DESCRIPTOR = _CMDGETPROPERTYCOUNT, + __module__ = 'esp_local_ctrl_pb2' + # @@protoc_insertion_point(class_scope:CmdGetPropertyCount) + )) +_sym_db.RegisterMessage(CmdGetPropertyCount) + +RespGetPropertyCount = _reflection.GeneratedProtocolMessageType('RespGetPropertyCount', (_message.Message,), dict( + DESCRIPTOR = _RESPGETPROPERTYCOUNT, + __module__ = 'esp_local_ctrl_pb2' + # @@protoc_insertion_point(class_scope:RespGetPropertyCount) + )) +_sym_db.RegisterMessage(RespGetPropertyCount) + +PropertyInfo = _reflection.GeneratedProtocolMessageType('PropertyInfo', (_message.Message,), dict( + DESCRIPTOR = _PROPERTYINFO, + __module__ = 'esp_local_ctrl_pb2' + # @@protoc_insertion_point(class_scope:PropertyInfo) + )) +_sym_db.RegisterMessage(PropertyInfo) + +CmdGetPropertyValues = _reflection.GeneratedProtocolMessageType('CmdGetPropertyValues', (_message.Message,), dict( + DESCRIPTOR = _CMDGETPROPERTYVALUES, + __module__ = 'esp_local_ctrl_pb2' + # @@protoc_insertion_point(class_scope:CmdGetPropertyValues) + )) +_sym_db.RegisterMessage(CmdGetPropertyValues) + +RespGetPropertyValues = _reflection.GeneratedProtocolMessageType('RespGetPropertyValues', (_message.Message,), dict( + DESCRIPTOR = _RESPGETPROPERTYVALUES, + __module__ = 'esp_local_ctrl_pb2' + # @@protoc_insertion_point(class_scope:RespGetPropertyValues) + )) +_sym_db.RegisterMessage(RespGetPropertyValues) + +PropertyValue = _reflection.GeneratedProtocolMessageType('PropertyValue', (_message.Message,), dict( + DESCRIPTOR = _PROPERTYVALUE, + __module__ = 'esp_local_ctrl_pb2' + # @@protoc_insertion_point(class_scope:PropertyValue) + )) +_sym_db.RegisterMessage(PropertyValue) + +CmdSetPropertyValues = _reflection.GeneratedProtocolMessageType('CmdSetPropertyValues', (_message.Message,), dict( + DESCRIPTOR = _CMDSETPROPERTYVALUES, + __module__ = 'esp_local_ctrl_pb2' + # @@protoc_insertion_point(class_scope:CmdSetPropertyValues) + )) +_sym_db.RegisterMessage(CmdSetPropertyValues) + +RespSetPropertyValues = _reflection.GeneratedProtocolMessageType('RespSetPropertyValues', (_message.Message,), dict( + DESCRIPTOR = _RESPSETPROPERTYVALUES, + __module__ = 'esp_local_ctrl_pb2' + # @@protoc_insertion_point(class_scope:RespSetPropertyValues) + )) +_sym_db.RegisterMessage(RespSetPropertyValues) + +LocalCtrlMessage = _reflection.GeneratedProtocolMessageType('LocalCtrlMessage', (_message.Message,), dict( + DESCRIPTOR = _LOCALCTRLMESSAGE, + __module__ = 'esp_local_ctrl_pb2' + # @@protoc_insertion_point(class_scope:LocalCtrlMessage) + )) +_sym_db.RegisterMessage(LocalCtrlMessage) + + +# @@protoc_insertion_point(module_scope) diff --git a/components/esp_local_ctrl/src/esp_local_ctrl.c b/components/esp_local_ctrl/src/esp_local_ctrl.c new file mode 100644 index 0000000000..1eead4d7c1 --- /dev/null +++ b/components/esp_local_ctrl/src/esp_local_ctrl.c @@ -0,0 +1,417 @@ +// Copyright 2019 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 +#include +#include +#include + +#include +#include + +#include +#include "esp_local_ctrl_priv.h" +#include "esp_local_ctrl.pb-c.h" + +#define ESP_LOCAL_CTRL_VERSION "v1.0" + +struct inst_ctx { + protocomm_t *pc; + esp_local_ctrl_config_t config; + esp_local_ctrl_prop_t **props; + size_t props_count; +}; + +struct inst_ctx *local_ctrl_inst_ctx; + +static const char *TAG = "esp_local_ctrl"; + +esp_err_t esp_local_ctrl_start(const esp_local_ctrl_config_t *config) +{ + esp_err_t ret; + + if (!config) { + ESP_LOGE(TAG, "NULL configuration provided"); + return ESP_ERR_INVALID_ARG; + } + + if (!config->transport) { + ESP_LOGE(TAG, "No transport provided"); + return ESP_ERR_INVALID_ARG; + } + + if (config->max_properties == 0) { + ESP_LOGE(TAG, "max_properties must be greater than 0"); + return ESP_ERR_INVALID_ARG; + } + + if (!config->handlers.get_prop_values || + !config->handlers.set_prop_values) { + ESP_LOGE(TAG, "Handlers cannot be null"); + return ESP_ERR_INVALID_ARG; + } + + if (local_ctrl_inst_ctx) { + ESP_LOGW(TAG, "Service already active"); + return ESP_ERR_INVALID_STATE; + } + + local_ctrl_inst_ctx = calloc(1, sizeof(struct inst_ctx)); + if (!local_ctrl_inst_ctx) { + ESP_LOGE(TAG, "Failed to allocate memory for instance"); + return ESP_ERR_NO_MEM; + } + memcpy(&local_ctrl_inst_ctx->config, config, sizeof(local_ctrl_inst_ctx->config)); + + local_ctrl_inst_ctx->props = calloc(local_ctrl_inst_ctx->config.max_properties, + sizeof(esp_local_ctrl_prop_t *)); + if (!local_ctrl_inst_ctx->props) { + ESP_LOGE(TAG, "Failed to allocate memory for properties"); + free(local_ctrl_inst_ctx); + local_ctrl_inst_ctx = NULL; + return ESP_ERR_NO_MEM; + } + + /* Since the config structure will be different for different transport modes, each transport may + * implement a `copy_config()` function, which accepts a configuration structure as input and + * creates a copy of that, which can be kept in the context structure of the `esp_local_ctrl` instance. + * This copy can be later be freed using `free_config()` */ + if (config->transport->copy_config) { + ret = config->transport->copy_config(&local_ctrl_inst_ctx->config.transport_config, + &config->transport_config); + if (ret != ESP_OK) { + esp_local_ctrl_stop(); + return ret; + } + } + + /* For a selected transport mode, endpoints may need to be declared prior to starting the + * `esp_local_ctrl` service, e.g. in case of BLE. By declaration it means that the transport layer + * allocates some resources for an endpoint, and later, after service has started, a handler + * is assigned for that endpoint */ + if (config->transport->declare_ep) { + /* UUIDs are 16bit unique IDs for each endpoint. This may or may not be relevant for + * a chosen transport. We reserve all values from FF50 to FFFF for the internal endpoints. + * The remaining endpoints can be used by the application for its own custom endpoints */ + uint16_t start_uuid = 0xFF50; + ret = config->transport->declare_ep(&local_ctrl_inst_ctx->config.transport_config, + "esp_local_ctrl/version", start_uuid++); + if (ret != ESP_OK) { + esp_local_ctrl_stop(); + return ret; + } + ret = config->transport->declare_ep(&local_ctrl_inst_ctx->config.transport_config, + "esp_local_ctrl/session", start_uuid++); + if (ret != ESP_OK) { + esp_local_ctrl_stop(); + return ret; + } + ret = config->transport->declare_ep(&local_ctrl_inst_ctx->config.transport_config, + "esp_local_ctrl/control", start_uuid++); + if (ret != ESP_OK) { + esp_local_ctrl_stop(); + return ret; + } + } + + local_ctrl_inst_ctx->pc = protocomm_new(); + if (!local_ctrl_inst_ctx->pc) { + ESP_LOGE(TAG, "Failed to create new protocomm instance"); + esp_local_ctrl_stop(); + return ESP_FAIL; + } + + if (config->transport->start_service) { + ret = config->transport->start_service(local_ctrl_inst_ctx->pc, + &local_ctrl_inst_ctx->config.transport_config); + if (ret != ESP_OK) { + esp_local_ctrl_stop(); + return ret; + } + } + + ret = protocomm_set_version(local_ctrl_inst_ctx->pc, "esp_local_ctrl/version", + ESP_LOCAL_CTRL_VERSION); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to set version endpoint"); + esp_local_ctrl_stop(); + return ret; + } + + ret = protocomm_set_security(local_ctrl_inst_ctx->pc, "esp_local_ctrl/session", + &protocomm_security0, NULL); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to set session endpoint"); + esp_local_ctrl_stop(); + return ret; + } + + ret = protocomm_add_endpoint(local_ctrl_inst_ctx->pc, "esp_local_ctrl/control", + esp_local_ctrl_data_handler, NULL); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to set control endpoint"); + esp_local_ctrl_stop(); + return ret; + } + return ESP_OK; +} + +esp_err_t esp_local_ctrl_stop(void) +{ + if (local_ctrl_inst_ctx) { + if (local_ctrl_inst_ctx->config.transport->free_config) { + local_ctrl_inst_ctx->config.transport->free_config(&local_ctrl_inst_ctx->config.transport_config); + } + if (local_ctrl_inst_ctx->pc) { + if (local_ctrl_inst_ctx->config.transport->stop_service) { + local_ctrl_inst_ctx->config.transport->stop_service(local_ctrl_inst_ctx->pc); + } + protocomm_delete(local_ctrl_inst_ctx->pc); + } + if (local_ctrl_inst_ctx->config.handlers.usr_ctx_free_fn) { + local_ctrl_inst_ctx->config.handlers.usr_ctx_free_fn( + local_ctrl_inst_ctx->config.handlers.usr_ctx); + } + + /* Iterate through all properties one by one and free them */ + for (uint32_t i = 0; i < local_ctrl_inst_ctx->config.max_properties; i++) { + if (local_ctrl_inst_ctx->props[i] == NULL) { + continue; + } + /* Release memory allocated for property data */ + free(local_ctrl_inst_ctx->props[i]->name); + if (local_ctrl_inst_ctx->props[i]->ctx_free_fn) { + local_ctrl_inst_ctx->props[i]->ctx_free_fn(local_ctrl_inst_ctx->props[i]->ctx); + } + free(local_ctrl_inst_ctx->props[i]); + } + free(local_ctrl_inst_ctx->props); + free(local_ctrl_inst_ctx); + local_ctrl_inst_ctx = NULL; + } + return ESP_OK; +} + +static int esp_local_ctrl_get_property_index(const char *name) +{ + if (!local_ctrl_inst_ctx || !name) { + return -1; + } + + /* Iterate through all properties one by one + * and find the one with matching name */ + for (uint32_t i = 0; i < local_ctrl_inst_ctx->props_count; i++) { + if (strcmp(local_ctrl_inst_ctx->props[i]->name, name) == 0) { + return i; + } + } + return -1; +} + +esp_err_t esp_local_ctrl_add_property(const esp_local_ctrl_prop_t *prop) +{ + if (!local_ctrl_inst_ctx) { + ESP_LOGE(TAG, "Service not running"); + return ESP_ERR_INVALID_STATE; + } + if (!prop || !prop->name) { + return ESP_ERR_INVALID_ARG; + } + if (esp_local_ctrl_get_property_index(prop->name) >= 0) { + ESP_LOGE(TAG, "Property with name %s exists", prop->name); + return ESP_ERR_INVALID_STATE; + } + + if (local_ctrl_inst_ctx->config.max_properties + == local_ctrl_inst_ctx->props_count) { + ESP_LOGE(TAG, "Max properties limit reached. Cannot add property %s", prop->name); + return ESP_ERR_NO_MEM; + } + + uint32_t i = local_ctrl_inst_ctx->props_count; + local_ctrl_inst_ctx->props[i] = calloc(1, sizeof(esp_local_ctrl_prop_t)); + if (!local_ctrl_inst_ctx->props[i]) { + ESP_LOGE(TAG, "Failed to allocate memory for new property %s", prop->name); + return ESP_ERR_NO_MEM; + } + local_ctrl_inst_ctx->props[i]->name = strdup(prop->name); + if (!local_ctrl_inst_ctx->props[i]->name) { + ESP_LOGE(TAG, "Failed to allocate memory for property data %s", prop->name); + free(local_ctrl_inst_ctx->props[i]); + local_ctrl_inst_ctx->props[i] = NULL; + return ESP_ERR_NO_MEM; + } + local_ctrl_inst_ctx->props[i]->type = prop->type; + local_ctrl_inst_ctx->props[i]->size = prop->size; + local_ctrl_inst_ctx->props[i]->flags = prop->flags; + local_ctrl_inst_ctx->props[i]->ctx = prop->ctx; + local_ctrl_inst_ctx->props[i]->ctx_free_fn = prop->ctx_free_fn; + local_ctrl_inst_ctx->props_count++; + return ESP_OK; +} + + +esp_err_t esp_local_ctrl_remove_property(const char *name) +{ + int idx = esp_local_ctrl_get_property_index(name); + if (idx < 0) { + ESP_LOGE(TAG, "Property %s not found", name); + return ESP_ERR_NOT_FOUND; + } + + /* Release memory allocated for property data */ + if (local_ctrl_inst_ctx->props[idx]->ctx_free_fn) { + local_ctrl_inst_ctx->props[idx]->ctx_free_fn( + local_ctrl_inst_ctx->props[idx]->ctx); + } + free(local_ctrl_inst_ctx->props[idx]->name); + free(local_ctrl_inst_ctx->props[idx]); + local_ctrl_inst_ctx->props[idx++] = NULL; + + /* Move the following properties forward, so that there is + * no empty space between two properties */ + for (uint32_t i = idx; i < local_ctrl_inst_ctx->props_count; i++) { + if (local_ctrl_inst_ctx->props[i] == NULL) { + break; + } + local_ctrl_inst_ctx->props[i-1] = local_ctrl_inst_ctx->props[i]; + } + local_ctrl_inst_ctx->props_count--; + return ESP_OK; +} + +const esp_local_ctrl_prop_t *esp_local_ctrl_get_property(const char *name) +{ + int idx = esp_local_ctrl_get_property_index(name); + if (idx < 0) { + ESP_LOGE(TAG, "Property %s not found", name); + return NULL; + } + + return local_ctrl_inst_ctx->props[idx]; +} + +esp_err_t esp_local_ctrl_get_prop_count(size_t *count) +{ + if (!local_ctrl_inst_ctx) { + ESP_LOGE(TAG, "Service not running"); + return ESP_ERR_INVALID_STATE; + } + if (!count) { + return ESP_ERR_INVALID_ARG; + } + *count = local_ctrl_inst_ctx->props_count; + return ESP_OK; +} + +esp_err_t esp_local_ctrl_get_prop_values(size_t total_indices, uint32_t *indices, + esp_local_ctrl_prop_t *props, + esp_local_ctrl_prop_val_t *values) +{ + if (!local_ctrl_inst_ctx) { + ESP_LOGE(TAG, "Service not running"); + return ESP_ERR_INVALID_STATE; + } + if (!indices || !props || !values) { + return ESP_ERR_INVALID_ARG; + } + + /* Convert indices to names */ + for (size_t i = 0; i < total_indices; i++) { + if (indices[i] >= local_ctrl_inst_ctx->props_count) { + ESP_LOGE(TAG, "Invalid property index %d", indices[i]); + return ESP_ERR_INVALID_ARG; + } + props[i].name = local_ctrl_inst_ctx->props[indices[i]]->name; + props[i].type = local_ctrl_inst_ctx->props[indices[i]]->type; + props[i].flags = local_ctrl_inst_ctx->props[indices[i]]->flags; + props[i].size = local_ctrl_inst_ctx->props[indices[i]]->size; + props[i].ctx = local_ctrl_inst_ctx->props[indices[i]]->ctx; + } + + esp_local_ctrl_handlers_t *h = &local_ctrl_inst_ctx->config.handlers; + esp_err_t ret = h->get_prop_values(total_indices, props, values, h->usr_ctx); + + /* Properties with fixed sizes need to be checked */ + for (size_t i = 0; i < total_indices; i++) { + if (local_ctrl_inst_ctx->props[indices[i]]->size != 0) { + values[i].size = local_ctrl_inst_ctx->props[indices[i]]->size; + } + } + return ret; +} + +esp_err_t esp_local_ctrl_set_prop_values(size_t total_indices, uint32_t *indices, + const esp_local_ctrl_prop_val_t *values) +{ + if (!local_ctrl_inst_ctx) { + ESP_LOGE(TAG, "Service not running"); + return ESP_ERR_INVALID_STATE; + } + if (!indices || !values) { + return ESP_ERR_INVALID_ARG; + } + + esp_local_ctrl_prop_t *props = calloc(total_indices, + sizeof(esp_local_ctrl_prop_t)); + if (!props) { + ESP_LOGE(TAG, "Unable to allocate memory for properties array"); + return ESP_ERR_NO_MEM; + } + for (size_t i = 0; i < total_indices; i++) { + if (indices[i] >= local_ctrl_inst_ctx->props_count) { + ESP_LOGE(TAG, "Invalid property index %d", indices[i]); + free(props); + return ESP_ERR_INVALID_ARG; + } + + /* Properties with fixed sizes need to be checked */ + if ((local_ctrl_inst_ctx->props[indices[i]]->size != values[i].size) && + (local_ctrl_inst_ctx->props[indices[i]]->size != 0)) { + ESP_LOGE(TAG, "Invalid property size %d. Expected %d", + values[i].size, local_ctrl_inst_ctx->props[indices[i]]->size); + free(props); + return ESP_ERR_INVALID_ARG; + } + + props[i].name = local_ctrl_inst_ctx->props[indices[i]]->name; + props[i].type = local_ctrl_inst_ctx->props[indices[i]]->type; + props[i].flags = local_ctrl_inst_ctx->props[indices[i]]->flags; + props[i].size = local_ctrl_inst_ctx->props[indices[i]]->size; + props[i].ctx = local_ctrl_inst_ctx->props[indices[i]]->ctx; + } + + esp_local_ctrl_handlers_t *h = &local_ctrl_inst_ctx->config.handlers; + esp_err_t ret = h->set_prop_values(total_indices, props, values, h->usr_ctx); + + free(props); + return ret; +} + +esp_err_t esp_local_ctrl_set_handler(const char *ep_name, + protocomm_req_handler_t handler, + void *priv_data) +{ + esp_err_t ret = ESP_ERR_INVALID_STATE; + + if (local_ctrl_inst_ctx) { + ret = protocomm_add_endpoint(local_ctrl_inst_ctx->pc, ep_name, + handler, priv_data); + } + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to register endpoint handler"); + } + return ret; +} diff --git a/components/esp_local_ctrl/src/esp_local_ctrl_handler.c b/components/esp_local_ctrl/src/esp_local_ctrl_handler.c new file mode 100644 index 0000000000..23a92abd6c --- /dev/null +++ b/components/esp_local_ctrl/src/esp_local_ctrl_handler.c @@ -0,0 +1,298 @@ +// Copyright 2019 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 +#include +#include +#include + +#include "esp_local_ctrl.h" +#include "esp_local_ctrl_priv.h" +#include "esp_local_ctrl.pb-c.h" + +#define SAFE_ALLOCATION(type, var) \ + type *var = (type *) malloc(sizeof(type)); \ + if (!var) { \ + ESP_LOGE(TAG, "Error allocating memory"); \ + return ESP_ERR_NO_MEM; \ + } + +static const char* TAG = "esp_local_ctrl_handler"; + +typedef struct esp_local_ctrl_cmd { + int cmd_num; + esp_err_t (*command_handler)(LocalCtrlMessage *req, + LocalCtrlMessage *resp, void **ctx); +} esp_local_ctrl_cmd_t; + +static esp_err_t cmd_get_prop_count_handler(LocalCtrlMessage *req, + LocalCtrlMessage *resp, void **ctx); + +static esp_err_t cmd_get_prop_vals_handler(LocalCtrlMessage *req, + LocalCtrlMessage *resp, void **ctx); + +static esp_err_t cmd_set_prop_vals_handler(LocalCtrlMessage *req, + LocalCtrlMessage *resp, void **ctx); + +static esp_local_ctrl_cmd_t cmd_table[] = { + { + .cmd_num = LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyCount, + .command_handler = cmd_get_prop_count_handler + }, + { + .cmd_num = LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyValues, + .command_handler = cmd_get_prop_vals_handler + }, + { + .cmd_num = LOCAL_CTRL_MSG_TYPE__TypeCmdSetPropertyValues, + .command_handler = cmd_set_prop_vals_handler + } +}; + +static uint16_t err_to_status(esp_err_t err) +{ + uint16_t status; + switch (err) { + case ESP_OK: + status = STATUS__Success; + break; + case ESP_ERR_INVALID_ARG: + status = STATUS__InvalidArgument; + break; + case ESP_ERR_INVALID_STATE: + status = STATUS__InvalidProto; + break; + default: + status = STATUS__InternalError; + } + return status; +} + +static esp_err_t cmd_get_prop_count_handler(LocalCtrlMessage *req, + LocalCtrlMessage *resp, void **ctx) +{ + SAFE_ALLOCATION(RespGetPropertyCount, resp_payload); + resp_get_property_count__init(resp_payload); + + size_t prop_count = 0; + resp_payload->status = err_to_status(esp_local_ctrl_get_prop_count(&prop_count)); + resp_payload->count = prop_count; + resp->payload_case = LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_GET_PROP_COUNT; + resp->resp_get_prop_count = resp_payload; + ESP_LOGD(TAG, "Got properties count %d", prop_count); + return ESP_OK; +} + +typedef void (*prop_val_free_fn_t)(void *val); + +static esp_err_t cmd_get_prop_vals_handler(LocalCtrlMessage *req, + LocalCtrlMessage *resp, void **ctx) +{ + SAFE_ALLOCATION(RespGetPropertyValues, resp_payload); + resp_get_property_values__init(resp_payload); + + esp_local_ctrl_prop_val_t *vals = calloc(req->cmd_get_prop_vals->n_indices, + sizeof(esp_local_ctrl_prop_val_t)); + esp_local_ctrl_prop_t *descs = calloc(req->cmd_get_prop_vals->n_indices, + sizeof(esp_local_ctrl_prop_t)); + prop_val_free_fn_t *free_fns = calloc(req->cmd_get_prop_vals->n_indices, + sizeof(prop_val_free_fn_t)); + resp_payload->props = calloc(req->cmd_get_prop_vals->n_indices, + sizeof(PropertyInfo *)); + if (!vals || !descs || !free_fns || !resp_payload->props) { + ESP_LOGE(TAG, "Failed to allocate memory for getting values"); + free(vals); + free(descs); + free(free_fns); + free(resp_payload->props); + free(resp_payload); + return ESP_ERR_NO_MEM; + } + + esp_err_t ret = esp_local_ctrl_get_prop_values(req->cmd_get_prop_vals->n_indices, + req->cmd_get_prop_vals->indices, + descs, vals); + resp_payload->status = err_to_status(ret); + if (ret == ESP_OK) { + resp_payload->n_props = 0; + for (size_t i = 0; i < req->cmd_get_prop_vals->n_indices; i++) { + resp_payload->props[i] = malloc(sizeof(PropertyInfo)); + if (!resp_payload->props[i]) { + resp_payload->status = STATUS__InternalError; + break; + } + resp_payload->n_props++; + property_info__init(resp_payload->props[i]); + resp_payload->props[i]->name = descs[i].name; + resp_payload->props[i]->type = descs[i].type; + resp_payload->props[i]->flags = descs[i].flags; + resp_payload->props[i]->value.data = vals[i].data; + resp_payload->props[i]->value.len = vals[i].size; + free_fns[i] = vals[i].free_fn; + } + } + resp->payload_case = LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_GET_PROP_VALS; + resp->resp_get_prop_vals = resp_payload; + (*ctx) = (void *)free_fns; + free(vals); + free(descs); + + /* Unless it's a fatal error, always return ESP_OK, otherwise + * the underlying connection will be closed by protocomm */ + return ESP_OK; +} + +static esp_err_t cmd_set_prop_vals_handler(LocalCtrlMessage *req, + LocalCtrlMessage *resp, void **ctx) +{ + SAFE_ALLOCATION(RespSetPropertyValues, resp_payload); + resp_set_property_values__init(resp_payload); + + uint32_t *idxs = calloc(req->cmd_set_prop_vals->n_props, sizeof(uint32_t)); + esp_local_ctrl_prop_val_t *vals = calloc(req->cmd_set_prop_vals->n_props, + sizeof(esp_local_ctrl_prop_val_t)); + if (!idxs || !vals) { + ESP_LOGE(TAG, "Failed to allocate memory for setting values"); + free(idxs); + free(vals); + return ESP_ERR_NO_MEM; + } + for (size_t i = 0; i < req->cmd_set_prop_vals->n_props; i++) { + idxs[i] = req->cmd_set_prop_vals->props[i]->index; + vals[i].data = req->cmd_set_prop_vals->props[i]->value.data; + vals[i].size = req->cmd_set_prop_vals->props[i]->value.len; + } + + esp_err_t ret = esp_local_ctrl_set_prop_values(req->cmd_set_prop_vals->n_props, + idxs, vals); + resp_payload->status = err_to_status(ret); + resp->payload_case = LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_SET_PROP_VALS; + resp->resp_set_prop_vals = resp_payload; + free(idxs); + free(vals); + + /* Unless it's a fatal error, always return ESP_OK, otherwise + * the underlying connection will be closed by protocomm */ + return ESP_OK; +} + +static int lookup_cmd_handler(int cmd_id) +{ + int i; + + for (i = 0; i < sizeof(cmd_table)/sizeof(esp_local_ctrl_cmd_t); i++) { + if (cmd_table[i].cmd_num == cmd_id) { + return i; + } + } + + return -1; +} + +static void esp_local_ctrl_command_cleanup(LocalCtrlMessage *resp, void **ctx) +{ + if (!resp) { + return; + } + + switch (resp->msg) { + case LOCAL_CTRL_MSG_TYPE__TypeRespGetPropertyCount: + free(resp->resp_get_prop_count); + break; + case LOCAL_CTRL_MSG_TYPE__TypeRespGetPropertyValues: { + if (resp->resp_get_prop_vals) { + prop_val_free_fn_t *free_fns = (prop_val_free_fn_t *)(*ctx); + for (size_t i = 0; i < resp->resp_get_prop_vals->n_props; i++) { + if (free_fns[i]) { + free_fns[i](resp->resp_get_prop_vals->props[i]->value.data); + } + free(resp->resp_get_prop_vals->props[i]); + } + free(free_fns); + free(resp->resp_get_prop_vals->props); + free(resp->resp_get_prop_vals); + } + } + break; + case LOCAL_CTRL_MSG_TYPE__TypeRespSetPropertyValues: + free(resp->resp_set_prop_vals); + break; + default: + ESP_LOGE(TAG, "Unsupported response type in cleanup_handler"); + } + return; +} + +static esp_err_t esp_local_ctrl_command_dispatcher(LocalCtrlMessage *req, + LocalCtrlMessage *resp, + void **ctx) +{ + int cmd_index = lookup_cmd_handler(req->msg); + if (cmd_index < 0) { + ESP_LOGE(TAG, "Invalid command handler lookup"); + return ESP_ERR_INVALID_ARG; + } + + esp_err_t ret = cmd_table[cmd_index].command_handler(req, resp, ctx); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error executing command handler"); + return ret; + } + + return ESP_OK; +} + +esp_err_t esp_local_ctrl_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen, + uint8_t **outbuf, ssize_t *outlen, void *priv_data) +{ + void *temp_ctx = NULL; + LocalCtrlMessage *req = local_ctrl_message__unpack(NULL, inlen, inbuf); + if (!req) { + ESP_LOGE(TAG, "Unable to unpack payload data"); + return ESP_ERR_INVALID_ARG; + } + + LocalCtrlMessage resp; + local_ctrl_message__init(&resp); + resp.msg = req->msg + 1; /* Response is request + 1 */ + + esp_err_t ret = esp_local_ctrl_command_dispatcher(req, &resp, &temp_ctx); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "command dispatcher failed"); + esp_local_ctrl_command_cleanup(&resp, &temp_ctx); + local_ctrl_message__free_unpacked(req, NULL); + return ESP_FAIL; + } + + local_ctrl_message__free_unpacked(req, NULL); + + *outlen = local_ctrl_message__get_packed_size(&resp); + if (*outlen <= 0) { + ESP_LOGE(TAG, "Invalid encoding for response"); + esp_local_ctrl_command_cleanup(&resp, &temp_ctx); + return ESP_FAIL; + } + + *outbuf = (uint8_t *) malloc(*outlen); + if (!*outbuf) { + ESP_LOGE(TAG, "System out of memory"); + esp_local_ctrl_command_cleanup(&resp, &temp_ctx); + return ESP_ERR_NO_MEM; + } + + local_ctrl_message__pack(&resp, *outbuf); + esp_local_ctrl_command_cleanup(&resp, &temp_ctx); + ESP_LOG_BUFFER_HEX_LEVEL(TAG, *outbuf, *outlen, ESP_LOG_DEBUG); + return ESP_OK; +} diff --git a/components/esp_local_ctrl/src/esp_local_ctrl_priv.h b/components/esp_local_ctrl/src/esp_local_ctrl_priv.h new file mode 100644 index 0000000000..9241054e35 --- /dev/null +++ b/components/esp_local_ctrl/src/esp_local_ctrl_priv.h @@ -0,0 +1,153 @@ +// Copyright 2019 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 + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/** + * @brief `esp_local_ctrl` transport specific structure + * + * Every supported transport layer should have the following functions + * implemented for starting, stopping and configuring a protocomm service + */ +struct esp_local_ctrl_transport { + /** + * Handler for starting a protocomm service as per specified configuration + */ + esp_err_t (*start_service) (protocomm_t *pc, + const esp_local_ctrl_transport_config_t *config); + + /** + * Handler for stopping a protocomm service + */ + void (*stop_service) (protocomm_t *pc); + + /** + * Handler for creating a copy of the transport specific configuration + */ + esp_err_t (*copy_config) (esp_local_ctrl_transport_config_t *dest_config, + const esp_local_ctrl_transport_config_t *src_config); + + /** + * Handler for allocating resources corresponding to a protocomm endpoint. + * Usually when adding a new endpoint `protocomm_endpoint_add()` API is used, + * but the transport layer may need to perform resource allocation for + * each endpoint, prior to starting the protocomm instance. This handler + * is useful in that case, as it is called before `start_service()`. + */ + esp_err_t (*declare_ep) (esp_local_ctrl_transport_config_t *config, + const char *ep_name, uint16_t ep_uuid); + + /** + * Handler for freeing a transport specific configuration + */ + void (*free_config) (esp_local_ctrl_transport_config_t *config); +}; + +/** + * @brief Protocomm handler for `esp_local_ctrl` + * + * This is the handler which is responsible for processing incoming requests + * over a protocomm channel, then invokes one of the following functions + * depending upon the request type: + * - `esp_local_ctrl_get_prop_count()` + * - `esp_local_ctrl_get_prop_values()` + * -` esp_local_ctrl_set_prop_values()` + * The output of the above functions are used to form the response messages + * corresponding to request types. The formed response messages are packed and + * sent back via the protocomm channel. + * + * @param[in] session_id A number to identify an ongoing session between + * device and client + * @param[in] inbuf Buffer which holds serialized / packed request data + * @param[in] inlen Length of input buffer + * @param[out] outbuf Buffer which holds serialized / packed response data + * @param[out] outlen Length of output buffer + * @param[in] priv_data Private data associated with `esp_local_ctrl` endpoint + * + * @return + * - ESP_OK : Success + * - ESP_FAIL : Failure + */ +esp_err_t esp_local_ctrl_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen, + uint8_t **outbuf, ssize_t *outlen, void *priv_data); + +/** + * @brief Use this for obtaining total number of properties registered + * with `esp_local_ctrl` service + * + * @param[out] count Pointer to variable where the result is to be stored + * + * @return + * - ESP_OK : Success + * - ESP_FAIL : Failure + */ +esp_err_t esp_local_ctrl_get_prop_count(size_t *count); + +/** + * @brief Get descriptions and values of multiple properties at the same time. + * The properties are requested by indices. This internally calls the + * `get_prop_values` handler specified in the `esp_local_ctrl_handlers_t` + * structure. Since `get_prop_values` accepts property structure, the + * indices are first converted to the corresponding `esp_local_ctrl_prop_t` + * internally. + * + * @param[in] total_indices The number of elements in the `indices` array argument + * @param[in] indices An array of indices, that specify which properties to get + * @param[out] props A pre-allocated array of empty property structures, elements of + * which are to be populated with names, types and flags of those + * properties which correspond to the provided indices + * @param[out] values A pre-allocated array of empty value structures, elements of + * which are to be populated with values and sizes of those + * properties which correspond to the provided indices + * + * @return + * - ESP_OK : Success + * - ESP_FAIL : Failure + */ +esp_err_t esp_local_ctrl_get_prop_values(size_t total_indices, uint32_t *indices, + esp_local_ctrl_prop_t *props, + esp_local_ctrl_prop_val_t *values); + +/** + * @brief Set values of multiple properties at the same time. The properties to + * set are specified by indices. This internally calls the `set_prop_values` + * handler specified in the `esp_local_ctrl_handlers_t` structure. Since + * `set_prop_values` accepts property structures, the indices are first + * converted to the corresponding `esp_local_ctrl_prop_t` internally. + * + * @param[in] total_indices The number of elements in the `indices` array argument + * @param[in] indices An array of indices, that specify which properties to set + * @param[in] values A array of values. Every value should have the correct + * size, if it is for setting a fixed size property, else + * error will be generated and none of the properties will + * be set to any of the given values + * + * @return + * - ESP_OK : Success + * - ESP_FAIL : Failure + */ +esp_err_t esp_local_ctrl_set_prop_values(size_t total_indices, uint32_t *indices, + const esp_local_ctrl_prop_val_t *values); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_local_ctrl/src/esp_local_ctrl_transport_ble.c b/components/esp_local_ctrl/src/esp_local_ctrl_transport_ble.c new file mode 100644 index 0000000000..248b410899 --- /dev/null +++ b/components/esp_local_ctrl/src/esp_local_ctrl_transport_ble.c @@ -0,0 +1,140 @@ +// Copyright 2019 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 +#include +#include +#include + +#include +#include + +#include "esp_local_ctrl_priv.h" + +#define LOCAL_CTRL_VERSION "v1.0" + +static const char *TAG = "esp_local_ctrl_transport_ble"; + +static esp_err_t start_ble_transport(protocomm_t *pc, const esp_local_ctrl_transport_config_t *config) +{ + if (!config || !config->ble) { + ESP_LOGE(TAG, "NULL configuration provided"); + return ESP_ERR_INVALID_ARG; + } + return protocomm_ble_start(pc, config->ble); +} + +static void stop_ble_transport(protocomm_t *pc) +{ + protocomm_ble_stop(pc); +} + +static esp_err_t copy_ble_config(esp_local_ctrl_transport_config_t *dest_config, const esp_local_ctrl_transport_config_t *src_config) +{ + if (!dest_config || !src_config || !src_config->ble) { + ESP_LOGE(TAG, "NULL arguments provided"); + return ESP_ERR_INVALID_ARG; + } + + dest_config->ble = calloc(1, sizeof(protocomm_ble_config_t)); + if (!dest_config->ble) { + ESP_LOGE(TAG, "Failed to allocate memory for BLE transport config"); + return ESP_ERR_NO_MEM; + } + + /* Copy BLE device name */ + memcpy(dest_config->ble->device_name, + src_config->ble->device_name, + sizeof(src_config->ble->device_name)); + + /* Copy Service UUID */ + memcpy(dest_config->ble->service_uuid, + src_config->ble->service_uuid, + sizeof(src_config->ble->service_uuid)); + + dest_config->ble->nu_lookup_count = 0; + if (src_config->ble->nu_lookup_count) { + /* Copy any provided name-uuid lookup table */ + dest_config->ble->nu_lookup = calloc(src_config->ble->nu_lookup_count, + sizeof(protocomm_ble_name_uuid_t)); + if (!dest_config->ble->nu_lookup) { + ESP_LOGE(TAG, "Failed to allocate memory for BLE characteristic names"); + free(dest_config->ble); + return ESP_ERR_NO_MEM; + } + for (uint16_t i = 0; i < src_config->ble->nu_lookup_count; i++) { + dest_config->ble->nu_lookup[i].uuid = src_config->ble->nu_lookup[i].uuid; + if (!src_config->ble->nu_lookup[i].name) { + ESP_LOGE(TAG, "Endpoint name cannot be null"); + return ESP_ERR_INVALID_ARG; + } + dest_config->ble->nu_lookup[i].name = strdup(src_config->ble->nu_lookup[i].name); + if (!dest_config->ble->nu_lookup[i].name) { + ESP_LOGE(TAG, "Failed to allocate memory for endpoint name"); + return ESP_ERR_NO_MEM; + } + dest_config->ble->nu_lookup_count++; + } + } + return ESP_OK; +} + +static esp_err_t declare_endpoint(esp_local_ctrl_transport_config_t *config, const char *ep_name, uint16_t ep_uuid) +{ + if (!config || !config->ble) { + ESP_LOGE(TAG, "NULL configuration provided"); + return ESP_ERR_INVALID_ARG; + } + + protocomm_ble_name_uuid_t *nu_lookup = realloc(config->ble->nu_lookup, + (config->ble->nu_lookup_count + 1) + * sizeof(protocomm_ble_name_uuid_t)); + if (!nu_lookup) { + ESP_LOGE(TAG, "Failed to allocate memory for new endpoint entry"); + return ESP_ERR_NO_MEM; + } + config->ble->nu_lookup = nu_lookup; + nu_lookup[config->ble->nu_lookup_count].uuid = ep_uuid; + nu_lookup[config->ble->nu_lookup_count].name = strdup(ep_name); + if (!nu_lookup[config->ble->nu_lookup_count].name) { + ESP_LOGE(TAG, "Failed to allocate memory for new endpoint name"); + return ESP_ERR_NO_MEM; + } + config->ble->nu_lookup_count++; + return ESP_OK; +} + +static void free_config(esp_local_ctrl_transport_config_t *config) +{ + if (config && config->ble) { + for (unsigned int i = 0; i < config->ble->nu_lookup_count; i++) { + free((void*) config->ble->nu_lookup[i].name); + } + free(config->ble->nu_lookup); + free(config->ble); + config->ble = NULL; + } +} + +const esp_local_ctrl_transport_t *esp_local_ctrl_get_transport_ble(void) +{ + static const esp_local_ctrl_transport_t tp = { + .start_service = start_ble_transport, + .stop_service = stop_ble_transport, + .copy_config = copy_ble_config, + .declare_ep = declare_endpoint, + .free_config = free_config + }; + return &tp; +}; diff --git a/components/esp_local_ctrl/src/esp_local_ctrl_transport_httpd.c b/components/esp_local_ctrl/src/esp_local_ctrl_transport_httpd.c new file mode 100644 index 0000000000..2089c3dbf5 --- /dev/null +++ b/components/esp_local_ctrl/src/esp_local_ctrl_transport_httpd.c @@ -0,0 +1,128 @@ +// Copyright 2019 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 +#include +#include +#include + +#include +#include +#include +#include + +#include "esp_local_ctrl_priv.h" + +#define LOCAL_CTRL_VERSION "v1.0" + +static const char *TAG = "esp_local_ctrl_transport_httpd"; + +static httpd_handle_t server_handle = NULL; + +static esp_err_t start_httpd_transport(protocomm_t *pc, const esp_local_ctrl_transport_config_t *config) +{ + if (!config || !config->httpd) { + ESP_LOGE(TAG, "NULL configuration provided"); + return ESP_ERR_INVALID_ARG; + } + + /* Extract configured port */ + uint16_t port = ( + config->httpd->transport_mode == HTTPD_SSL_TRANSPORT_SECURE ? + config->httpd->port_secure : + config->httpd->port_insecure + ); + + esp_err_t err = mdns_service_add("Local Control Service", "_esp_local_ctrl", + "_tcp", port, NULL, 0); + if (err != ESP_OK) { + /* mDNS is not mandatory for provisioning to work, + * so print warning and return without failure */ + ESP_LOGW(TAG, "Error adding mDNS service! Check if mDNS is running"); + } else { + /* Information to identify the roles of the various + * protocomm endpoint URIs provided by the service */ + err |= mdns_service_txt_item_set("_esp_local_ctrl", "_tcp", + "version_endpoint", "/esp_local_ctrl/version"); + err |= mdns_service_txt_item_set("_esp_local_ctrl", "_tcp", + "session_endpoint", "/esp_local_ctrl/session"); + err |= mdns_service_txt_item_set("_esp_local_ctrl", "_tcp", + "control_endpoint", "/esp_local_ctrl/control"); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Error adding mDNS service text item"); + } + } + + err = httpd_ssl_start(&server_handle, config->httpd); + if (ESP_OK != err) { + ESP_LOGE(TAG, "Error starting HTTPS service!"); + mdns_service_remove("_esp_local_ctrl", "_tcp"); + return err; + } + + protocomm_httpd_config_t pc_conf = { + .ext_handle_provided = true, + .data = { + .handle = &server_handle + } + }; + + return protocomm_httpd_start(pc, &pc_conf); +} + +static void stop_httpd_transport(protocomm_t *pc) +{ + mdns_service_remove("_esp_local_ctrl", "_tcp"); + protocomm_httpd_stop(pc); + httpd_ssl_stop(server_handle); + server_handle = NULL; +} + +static esp_err_t copy_httpd_config(esp_local_ctrl_transport_config_t *dest_config, const esp_local_ctrl_transport_config_t *src_config) +{ + if (!dest_config || !src_config || !src_config->httpd) { + ESP_LOGE(TAG, "NULL configuration provided"); + return ESP_ERR_INVALID_ARG; + } + + dest_config->httpd = calloc(1, sizeof(httpd_ssl_config_t)); + if (!dest_config->httpd) { + ESP_LOGE(TAG, "Failed to allocate memory for HTTPD transport config"); + return ESP_ERR_NO_MEM; + } + memcpy(dest_config->httpd, + src_config->httpd, + sizeof(httpd_ssl_config_t)); + return ESP_OK; +} + +static void free_config(esp_local_ctrl_transport_config_t *config) +{ + if (config && config->httpd) { + free(config->httpd); + config->httpd = NULL; + } +} + +const esp_local_ctrl_transport_t *esp_local_ctrl_get_transport_httpd(void) +{ + static const esp_local_ctrl_transport_t tp = { + .start_service = start_httpd_transport, + .stop_service = stop_httpd_transport, + .copy_config = copy_httpd_config, + .declare_ep = NULL, + .free_config = free_config + }; + return &tp; +}; diff --git a/components/protocomm/include/transports/protocomm_ble.h b/components/protocomm/include/transports/protocomm_ble.h index b7d70e59ec..b30d5707b6 100644 --- a/components/protocomm/include/transports/protocomm_ble.h +++ b/components/protocomm/include/transports/protocomm_ble.h @@ -48,7 +48,7 @@ typedef struct name_uuid { /** * @brief Config parameters for protocomm BLE service */ -typedef struct { +typedef struct protocomm_ble_config { /** * BLE device name being broadcast at the time of provisioning */ diff --git a/docs/Doxyfile b/docs/Doxyfile index ee91aab2b3..d9bf17dc2f 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -107,8 +107,11 @@ INPUT = \ ../../components/mdns/include/mdns.h \ ../../components/esp_http_client/include/esp_http_client.h \ ../../components/esp_websocket_client/include/esp_websocket_client.h \ + ## HTTP / HTTPS Server ../../components/esp_http_server/include/esp_http_server.h \ ../../components/esp_https_server/include/esp_https_server.h \ + ## ESP Local Ctrl + ../../components/esp_local_ctrl/include/esp_local_ctrl.h \ ## ## Provisioning - API Reference ## diff --git a/docs/en/api-reference/protocols/esp_local_ctrl.rst b/docs/en/api-reference/protocols/esp_local_ctrl.rst new file mode 100644 index 0000000000..3c6ba60b32 --- /dev/null +++ b/docs/en/api-reference/protocols/esp_local_ctrl.rst @@ -0,0 +1,206 @@ +ESP Local Control +================= + +Overview +-------- +ESP Local Control (**esp_local_ctrl**) component in ESP-IDF provides capability to control an ESP device over Wi-Fi + HTTPS or BLE. It provides access to application defined **properties** that are available for reading / writing via a set of configurable handlers. + +Initialization of the **esp_local_ctrl** service over BLE transport is performed as follows: + + .. highlight:: c + + :: + + esp_local_ctrl_config_t config = { + .transport = ESP_LOCAL_CTRL_TRANSPORT_BLE, + .transport_config = { + .ble = & (protocomm_ble_config_t) { + .device_name = SERVICE_NAME, + .service_uuid = { + /* LSB <--------------------------------------- + * ---------------------------------------> MSB */ + 0x21, 0xd5, 0x3b, 0x8d, 0xbd, 0x75, 0x68, 0x8a, + 0xb4, 0x42, 0xeb, 0x31, 0x4a, 0x1e, 0x98, 0x3d + } + } + }, + .handlers = { + /* User defined handler functions */ + .get_prop_values = get_property_values, + .set_prop_values = set_property_values, + .usr_ctx = NULL, + .usr_ctx_free_fn = NULL + }, + /* Maximum number of properties that may be set */ + .max_properties = 10 + }; + + /* Start esp_local_ctrl service */ + ESP_ERROR_CHECK(esp_local_ctrl_start(&config)); + + +Similarly for HTTPS transport: + + .. highlight:: c + + :: + + /* Set the configuration */ + httpd_ssl_config_t https_conf = HTTPD_SSL_CONFIG_DEFAULT(); + + /* Load server certificate */ + extern const unsigned char cacert_pem_start[] asm("_binary_cacert_pem_start"); + extern const unsigned char cacert_pem_end[] asm("_binary_cacert_pem_end"); + https_conf.cacert_pem = cacert_pem_start; + https_conf.cacert_len = cacert_pem_end - cacert_pem_start; + + /* Load server private key */ + extern const unsigned char prvtkey_pem_start[] asm("_binary_prvtkey_pem_start"); + extern const unsigned char prvtkey_pem_end[] asm("_binary_prvtkey_pem_end"); + https_conf.prvtkey_pem = prvtkey_pem_start; + https_conf.prvtkey_len = prvtkey_pem_end - prvtkey_pem_start; + + esp_local_ctrl_config_t config = { + .transport = ESP_LOCAL_CTRL_TRANSPORT_HTTPD, + .transport_config = { + .httpd = &https_conf + }, + .handlers = { + /* User defined handler functions */ + .get_prop_values = get_property_values, + .set_prop_values = set_property_values, + .usr_ctx = NULL, + .usr_ctx_free_fn = NULL + }, + /* Maximum number of properties that may be set */ + .max_properties = 10 + }; + + /* Start esp_local_ctrl service */ + ESP_ERROR_CHECK(esp_local_ctrl_start(&config)); + + +Creating a property +=================== + +Now that we know how to start the **esp_local_ctrl** service, let's add a property to it. Each property must have a unique `name` (string), a `type` (e.g. enum), `flags` (bit fields) and `size`. + +The `size` is to be kept 0, if we want our property value to be of variable length (e.g. if its a string or bytestream). For fixed length property value data-types, like int, float, etc., setting the `size` field to the right value, helps **esp_local_ctrl** to perform internal checks on arguments received with write requests. + +The interpretation of `type` and `flags` fields is totally upto the application, hence they may be used as enumerations, bitfields, or even simple integers. One way is to use `type` values to classify properties, while `flags` to specify characteristics of a property. + +Here is an example property which is to function as a timestamp. It is assumed that the application defines `TYPE_TIMESTAMP` and `READONLY`, which are used for setting the `type` and `flags` fields here. + + .. highlight:: c + + :: + + /* Create a timestamp property */ + esp_local_ctrl_prop_t timestamp = { + .name = "timestamp", + .type = TYPE_TIMESTAMP, + .size = sizeof(int32_t), + .flags = READONLY, + .ctx = func_get_time, + .ctx_free_fn = NULL + }; + + /* Now register the property */ + esp_local_ctrl_add_property(×tamp); + + +Also notice that there is a ctx field, which is set to point to some custom `func_get_time()`. This can be used inside the property get / set handlers to retrieve timestamp. + +Here is an example of `get_prop_values()` handler, which is used for retrieving the timestamp. + + .. highlight:: c + + :: + + static esp_err_t get_property_values(size_t props_count, + const esp_local_ctrl_prop_t *props, + esp_local_ctrl_prop_val_t *prop_values, + void *usr_ctx) + { + for (uint32_t i = 0; i < props_count; i++) { + ESP_LOGI(TAG, "Reading %s", props[i].name); + if (props[i].type == TYPE_TIMESTAMP) { + /* Obtain the timer function from ctx */ + int32_t (*func_get_time)(void) = props[i].ctx; + + /* Use static variable for saving the value. + * This is essential because the value has to be + * valid even after this function returns. + * Alternative is to use dynamic allocation + * and set the free_fn field */ + static int32_t ts = func_get_time(); + prop_values[i].data = &ts; + } + } + return ESP_OK; + } + + +Here is an example of `set_prop_values()` handler. Notice how we restrict from writing to read-only properties. + + .. highlight:: c + + :: + + static esp_err_t set_property_values(size_t props_count, + const esp_local_ctrl_prop_t *props, + const esp_local_ctrl_prop_val_t *prop_values, + void *usr_ctx) + { + for (uint32_t i = 0; i < props_count; i++) { + if (props[i].flags & READONLY) { + ESP_LOGE(TAG, "Cannot write to read-only property %s", props[i].name); + return ESP_ERR_INVALID_ARG; + } else { + ESP_LOGI(TAG, "Setting %s", props[i].name); + + /* For keeping it simple, lets only log the incoming data */ + ESP_LOG_BUFFER_HEX_LEVEL(TAG, prop_values[i].data, + prop_values[i].size, ESP_LOG_INFO); + } + } + return ESP_OK; + } + + +For complete example see :example:`protocols/esp_local_ctrl` + +Client Side Implementation +========================== + +The client side implementation will have establish a protocomm session with the device first, over the supported mode of transport, and then send and receive protobuf messages understood by the **esp_local_ctrl** service. The service will translate these messages into requests and then call the appropriate handlers (set / get). Then, the generated response for each handler is again packed into a protobuf message and transmitted back to the client. + +See below the various protobuf messages understood by the **esp_local_ctrl** service: + +1. `get_prop_count` : This should simply return the total number of properties supported by the service +2. `get_prop_values` : This accepts an array of indices and should return the information (name, type, flags) and values of the properties corresponding to those indices +3. `set_prop_values` : This accepts an array of indices and an array of new values, which are used for setting the values of the properties corresponding to the indices + +Note that indices may or may not be the same for a property, across multiple sessions. Therefore, the client must only use the names of the properties to uniquely identify them. So, every time a new session is established, the client should first call `get_prop_count` and then `get_prop_values`, hence form an index to name mapping for all properties. Now when calling `set_prop_values` for a set of properties, it must first convert the names to indexes, using the created mapping. As emphasized earlier, the client must refresh the index to name mapping every time a new session is established with the same device. + +The various protocomm endpoints provided by **esp_local_ctrl** are listed below: + +.. list-table:: Endpoints provided by ESP Local Control + :widths: 10 25 50 + :header-rows: 1 + + * - Endpoint Name (BLE + GATT Server) + - URI (HTTPS Server + mDNS) + - Description + * - esp_local_ctrl/version + - https://.local/esp_local_ctrl/version + - Endpoint used for retrieving version string + * - esp_local_ctrl/control + - https://.local/esp_local_ctrl/control + - Endpoint used for sending / receiving control messages + + +API Reference +------------- + +.. include:: /_build/inc/esp_local_ctrl.inc diff --git a/docs/en/api-reference/protocols/index.rst b/docs/en/api-reference/protocols/index.rst index 97386abe4c..c35c954f35 100644 --- a/docs/en/api-reference/protocols/index.rst +++ b/docs/en/api-reference/protocols/index.rst @@ -14,6 +14,7 @@ Application Protocols ASIO ESP-MQTT Modbus + Local Control Code examples for this API section are provided in the :example:`protocols` directory of ESP-IDF examples. diff --git a/docs/zh_CN/api-reference/protocols/esp_local_ctrl.rst b/docs/zh_CN/api-reference/protocols/esp_local_ctrl.rst new file mode 100644 index 0000000000..587542d5d8 --- /dev/null +++ b/docs/zh_CN/api-reference/protocols/esp_local_ctrl.rst @@ -0,0 +1 @@ +.. include:: ../../../en/api-reference/protocols/esp_local_ctrl.rst diff --git a/docs/zh_CN/api-reference/protocols/index.rst b/docs/zh_CN/api-reference/protocols/index.rst index 9d893c29b6..d385082b3b 100644 --- a/docs/zh_CN/api-reference/protocols/index.rst +++ b/docs/zh_CN/api-reference/protocols/index.rst @@ -14,6 +14,7 @@ ASIO ESP-MQTT Modbus slave + Local Control 此 API 部分的示例代码在 ESP-IDF 示例工程的 :example:`protocols` 目录下提供。 diff --git a/examples/protocols/esp_local_ctrl/CMakeLists.txt b/examples/protocols/esp_local_ctrl/CMakeLists.txt new file mode 100644 index 0000000000..2ee3492ecb --- /dev/null +++ b/examples/protocols/esp_local_ctrl/CMakeLists.txt @@ -0,0 +1,10 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +# (Not part of the boilerplate) +# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(esp_local_ctrl) diff --git a/examples/protocols/esp_local_ctrl/Makefile b/examples/protocols/esp_local_ctrl/Makefile new file mode 100644 index 0000000000..e3e0a7ac6d --- /dev/null +++ b/examples/protocols/esp_local_ctrl/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := esp_local_ctrl + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/protocols/esp_local_ctrl/README.md b/examples/protocols/esp_local_ctrl/README.md new file mode 100644 index 0000000000..81abdea2e8 --- /dev/null +++ b/examples/protocols/esp_local_ctrl/README.md @@ -0,0 +1,93 @@ +# ESP Local Control using HTTPS server + +This example creates a `esp_local_ctrl` service over HTTPS transport, for securely controlling the device over local network. In this case the device name is resolved through `mDNS`, which in this example is `my_esp_ctrl_device.local`. + +See the `esp_local_ctrl` component documentation for details. + +Before using the example, run `make menuconfig` (or `idf.py menuconfig` if using CMake build system) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../README.md) for more details. + +## Client Side Implementation + +A python test script `scripts/esp_local_ctrl.py` has been provided for as a client side application for controlling the device over the same Wi-Fi network. The script relies on a pre-generated `main/certs/rootCA.pem` to verify the server certificate. The server side private key and certificate can also be found under `main/certs`, namely `prvtkey.pem` and `cacert.pem`. + +After configuring the Wi-Fi, flashing and booting the device, run: + +``` +python scripts/esp_local_ctrl.py +``` +Sample output: + +``` +python2 scripts/esp_local_ctrl.py + +==== Acquiring properties information ==== + +==== Acquired properties information ==== + +==== Available Properties ==== +S.N. Name Type Flags Value +[ 1] timestamp (us) TIME(us) Read-Only 168561481 +[ 2] property1 INT32 123456 +[ 3] property2 BOOLEAN Read-Only True +[ 4] property3 STRING + +Select properties to set (0 to re-read, 'q' to quit) : 0 + +==== Available Properties ==== +S.N. Name Type Flags Value +[ 1] timestamp (us) TIME(us) Read-Only 22380117 +[ 2] property1 INT32 123456 +[ 3] property2 BOOLEAN Read-Only False +[ 4] property3 STRING + +Select properties to set (0 to re-read, 'q' to quit) : 2,4 +Enter value to set for property (property1) : -5555 +Enter value to set for property (property3) : hello world! + +==== Available Properties ==== +S.N. Name Type Flags Value +[ 1] timestamp (us) TIME(us) Read-Only 55110859 +[ 2] property1 INT32 -5555 +[ 3] property2 BOOLEAN Read-Only False +[ 4] property3 STRING hello world! + +Select properties to set (0 to re-read, 'q' to quit) : q +Quitting... +``` + +The script also allows to connect over BLE, and provide a custom service name. To display the list of supported parameters, run: + +``` +python scripts/esp_local_ctrl.py --help +``` + +## Certificates + +You can generate a new server certificate using the OpenSSL command line tool. + +For the purpose of this example, lets generate a rootCA, which we will use to sign the server certificates and which the client will use to verify the server certificate during SSL handshake. You will need to set a password for encrypting the generated `rootkey.pem`. + +``` +openssl req -new -x509 -subj "/CN=root" -days 3650 -sha256 -out rootCA.pem -keyout rootkey.pem +``` + +Now generate a certificate signing request for the server, along with its private key `prvtkey.pem`. + +``` +openssl req -newkey rsa:2048 -nodes -keyout prvtkey.pem -days 3650 -out server.csr -subj "/CN=my_esp_ctrl_device.local" +``` + +Now use the previously generated rootCA to process the server's certificate signing request, and generate a signed certificate `cacert.pem`. The password set for encrypting `rootkey.pem` earlier, has to be entered during this step. + +``` +openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootkey.pem -CAcreateserial -out cacert.pem -days 500 -sha256 +``` + +Now that we have `rootCA.pem`, `cacert.pem` and `prvtkey.pem`, copy these into main/certs. Note that only the server related files (`cacert.pem` and `prvtkey.pem`) are embedded into the firmware. + +Expiry time and metadata fields can be adjusted in the invocation. + +Please see the `openssl` man pages (man `openssl-req`) for more details. + +It is **strongly recommended** to not reuse the example certificate in your application; +it is included only for demonstration. diff --git a/examples/protocols/esp_local_ctrl/main/CMakeLists.txt b/examples/protocols/esp_local_ctrl/main/CMakeLists.txt new file mode 100644 index 0000000000..87f57d1076 --- /dev/null +++ b/examples/protocols/esp_local_ctrl/main/CMakeLists.txt @@ -0,0 +1,8 @@ +set(COMPONENT_SRCS "app_main.c" "esp_local_ctrl_service.c") +set(COMPONENT_ADD_INCLUDEDIRS ".") + +set(COMPONENT_EMBED_TXTFILES + "certs/cacert.pem" + "certs/prvtkey.pem") + +register_component() diff --git a/examples/protocols/esp_local_ctrl/main/Kconfig.projbuild b/examples/protocols/esp_local_ctrl/main/Kconfig.projbuild new file mode 100644 index 0000000000..7403f8f834 --- /dev/null +++ b/examples/protocols/esp_local_ctrl/main/Kconfig.projbuild @@ -0,0 +1,20 @@ +menu "Example Configuration" + + config ESP_WIFI_SSID + string "WiFi SSID" + default "myssid" + help + SSID (network name) for the example to connect to. + + config ESP_WIFI_PASSWORD + string "WiFi Password" + default "mypassword" + help + WiFi password (WPA or WPA2) for the example to use. + + config ESP_MAXIMUM_RETRY + int "Maximum retry" + default 5 + help + Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent. +endmenu diff --git a/examples/protocols/esp_local_ctrl/main/app_main.c b/examples/protocols/esp_local_ctrl/main/app_main.c new file mode 100644 index 0000000000..d19feffda1 --- /dev/null +++ b/examples/protocols/esp_local_ctrl/main/app_main.c @@ -0,0 +1,111 @@ +/* Local Ctrl Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_event.h" +#include "esp_log.h" +#include "nvs_flash.h" + +#include "lwip/err.h" +#include "lwip/sys.h" + +/* The examples use 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_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID +#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD +#define EXAMPLE_ESP_MAXIMUM_RETRY CONFIG_ESP_MAXIMUM_RETRY + +/* FreeRTOS event group to signal when we are connected*/ +static EventGroupHandle_t s_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 WIFI_CONNECTED_BIT = BIT0; + +static const char *TAG = "local_ctrl_example"; + +static int s_retry_num = 0; + +static void event_handler(void* arg, esp_event_base_t event_base, + int32_t event_id, void* event_data) +{ + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { + esp_wifi_connect(); + } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { + if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) { + esp_wifi_connect(); + xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT); + s_retry_num++; + ESP_LOGI(TAG, "retry to connect to the AP"); + } + ESP_LOGI(TAG,"connect to the AP fail"); + } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { + ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; + ESP_LOGI(TAG, "got ip:%s", + ip4addr_ntoa(&event->ip_info.ip)); + s_retry_num = 0; + xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); + } +} + +void wifi_init_sta() +{ + s_wifi_event_group = xEventGroupCreate(); + + tcpip_adapter_init(); + + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL)); + + wifi_config_t wifi_config = { + .sta = { + .ssid = EXAMPLE_ESP_WIFI_SSID, + .password = EXAMPLE_ESP_WIFI_PASS + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); + ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) ); + ESP_ERROR_CHECK(esp_wifi_start() ); + + ESP_LOGI(TAG, "wifi_init_sta finished."); + ESP_LOGI(TAG, "connect to ap SSID:%s password:%s", + EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS); +} + +/* Function responsible for configuring and starting the esp_local_ctrl service. + * See local_ctrl_service.c for implementation */ +extern void start_esp_local_ctrl_service(void); + +void app_main() +{ + //Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + ESP_LOGI(TAG, "ESP_WIFI_MODE_STA"); + wifi_init_sta(); + start_esp_local_ctrl_service(); +} diff --git a/examples/protocols/esp_local_ctrl/main/certs/cacert.pem b/examples/protocols/esp_local_ctrl/main/certs/cacert.pem new file mode 100644 index 0000000000..6323ff0dd0 --- /dev/null +++ b/examples/protocols/esp_local_ctrl/main/certs/cacert.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICuTCCAaECFFnose4o8INWoH5BA5TOCz2e9zAOMA0GCSqGSIb3DQEBCwUAMA8x +DTALBgNVBAMMBHJvb3QwHhcNMTkwNjI1MTkyMTU4WhcNMjAxMTA2MTkyMTU4WjAj +MSEwHwYDVQQDDBhteV9lc3BfY3RybF9kZXZpY2UubG9jYWwwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDY2B46AdNfrJRGgHy7cECmEMxOWn8CvygC2g77 +Gog/DWxkqaEksBJt8qQcqGLumv+HfXE4erNPGU+RTNal+zMXHliIMVi2IiVw5uuC +Tze7cK28HDvC5noED/TWGSJIaCQAUP/GdE0sqCJ1O7W0IhrZBjsmen4d0nPrInCz +X9YDOfaWxdwnBJ3q0+7ZTSWETbDrKUJ0tgPe6m96j/zRYCtCo2Dpu/pZvPyIvXwT +zt6enB8cwDtk35KwOrscAJGNqkCRyKaNvOSuHv9/02vpzwqk/J6JbIcXFVNuYSPg +0wb0iltMqn0IwC3KyaI9gBg0VexMeOhFV/gRt8dvEYehtTB7AgMBAAEwDQYJKoZI +hvcNAQELBQADggEBAFnKbunoBvKun4hJV4sp0ztDKpjOJevsQp3X36egm4NGCpEj +cdHxEmAvmeiu/12C6OfvFmZ/QiqNmp2gihpy4DiuxWnI+iC9JjfYuWTsKj+xcVkw +4IvGZbFtE9YW+XwNWqXPi1urVk9wKpZmCWpWgFWnLwPgIQs16+y3+CQF3vefX9Iy +aqmYrTYkBpLEXRjYJeU253mvN6FXQgOoPuld1Ph+IO+DUEJr+zeM88xkmjAo37ej +VkCMXA5HqdT64HuZC1RnnbpP76assgFW2oTycG28jzHSYjuK2q1PIoZtzpW8Sv7i +jn17E6ryf24r1DVkQByR54rvzl6Qu3M8TJe6EYI= +-----END CERTIFICATE----- diff --git a/examples/protocols/esp_local_ctrl/main/certs/prvtkey.pem b/examples/protocols/esp_local_ctrl/main/certs/prvtkey.pem new file mode 100644 index 0000000000..fbf3a5026a --- /dev/null +++ b/examples/protocols/esp_local_ctrl/main/certs/prvtkey.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDY2B46AdNfrJRG +gHy7cECmEMxOWn8CvygC2g77Gog/DWxkqaEksBJt8qQcqGLumv+HfXE4erNPGU+R +TNal+zMXHliIMVi2IiVw5uuCTze7cK28HDvC5noED/TWGSJIaCQAUP/GdE0sqCJ1 +O7W0IhrZBjsmen4d0nPrInCzX9YDOfaWxdwnBJ3q0+7ZTSWETbDrKUJ0tgPe6m96 +j/zRYCtCo2Dpu/pZvPyIvXwTzt6enB8cwDtk35KwOrscAJGNqkCRyKaNvOSuHv9/ +02vpzwqk/J6JbIcXFVNuYSPg0wb0iltMqn0IwC3KyaI9gBg0VexMeOhFV/gRt8dv +EYehtTB7AgMBAAECggEBAJSvM6Kgp9fdVNo2tdAsOxfjQsOjB53RhtTVwhnpamyZ +fq5TJZwrYqejDWZdC2ECRJ4ZpG2OrK5a85T0s+Whpbl/ZEMWWvaf2T5eCDQUr2lF +7MqkLVIJiLaKXl4DY990EONqpsbj7hrluqLZ61B1ZiVTQXGz4g/+wt8CgXZtCyiv +7XOTTmQueugq4f54JBX5isdB7/xLaXV3kycaEK1b6ZVFYB3ii5IKKsX7RK/ksA6O +fRrQ8702prqphPfbjZ9wPHif/zLiyiF2FG6OX1Y3aZe1npRsvuH2c3M2h+HGAQUR +3lDxMTNbsE8E+XKZFVAVdMqot2RfxENSHoJHcp1R2YECgYEA9qe1+eOZKd0w5lC1 +PuG6FLAAbK1nuv/ovESEHtILTLFkMijgAqcWjtp1klS86IBJLnjv+GYxZu2n1WI9 +QLnh++NNTjRGCMM2Adf5SBJ/5F85rpgzz7Yur1guqkUQx/2dmErOaWQ4IO304VlM +vrJB8+XmAiysEgJOkK0Mx8xRVcECgYEA4Q9GBADLryvwjisp/PdTRXOvd7pJRGH3 +SdC1k/nBsmpmbouc0ihqzOiiN0kUjE2yLSlhwxxWBJqNSzOk9z5/LB4TNRqH9gCL +rUN67FgzwR5H70OblWpcjWRurFq34+ZWEmCG+1qUwZMT7dYe4CiDYnVjcwfUpQwN +qRpjeMLDrTsCgYEAgo1CRIGzD/WDbGRLinzvgQOnNd6SiOfqx7t8MtP6Jx29as83 +wi+uQO5gTJONaYJ9OZvJaDCu9UvVCZx1z0yT0D7/K+V/LCQm8dLenscr6jR802y7 +/7TuAOEr0fO8bh5Oy8zMc/wXuVY5xwz9EfJH9lA47e23JdESxIDTwuziIAECgYEA +qKQdPtqpxbUTKDTH3bomN6CcFwcL56XQ+wrdROidb+eyoZsUA5YtkSWwh+TG9Osz +XAvqKZ2OBx0YSwWD05CNEq3mjqA2yOtXvpkV/wuInGjoVi0+5BMzDu/2zkecC7WJ +QXP7MVWKqhJfmJQdxrIU4S49OvDfMl15zwDrEI5AugkCgYBn5+/KvrA8GGWD9p1r +qwjoojGBvCJn1Kj/s+IQYePYeiRe6/eSPGFHRyON9aMGjZmeiqyBA4bW71Wf8Rs1 +X5LSwZhJpCTjO4B92w40u0r86Jxmp5Wz+zHUeM3mO2E6lAF+15YjhxpMT0YOmHFE ++oKD8U6dMjkTqntavBauz8M8fQ== +-----END PRIVATE KEY----- diff --git a/examples/protocols/esp_local_ctrl/main/certs/rootCA.pem b/examples/protocols/esp_local_ctrl/main/certs/rootCA.pem new file mode 100644 index 0000000000..dcc340d6a2 --- /dev/null +++ b/examples/protocols/esp_local_ctrl/main/certs/rootCA.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIC/zCCAeegAwIBAgIUH0R6q5vbgMnMZgD5r4xSu+WhSMwwDQYJKoZIhvcNAQEL +BQAwDzENMAsGA1UEAwwEcm9vdDAeFw0xOTA2MjUxOTIxNDVaFw0yOTA2MjIxOTIx +NDVaMA8xDTALBgNVBAMMBHJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQDGDetEF+4HEOU5uoxvHsYAksmpF1tjw/M+aKtyGuTWInJPDJ3YjjjnF7hb +ylx5W7Qj4O4N+TmqYkwA4ztq2CXSmX1uc7OOfxU/wED663NoC2P1Mw0fI5fX2518 +WdJeQilYymIOilmdtNqU9ad/3RdSZg+fxL5z9MTidHlUyzJG5LlO1cDiYRRURj9S +Fc2wWEUCETGA78ADCxKsdf2gBZDcZo/PHNXZc7fi2K18T5UmkRd50aoSLWUNY5tT +4DsyL19PUJCmtwcoLMT3p3kmepN4C0JByOxWceIvlAbq7+L3zMURWfpBcIqxXvEP +Y/JXw7GCfTJgjUz1IoHVz/ERNtrnAgMBAAGjUzBRMB0GA1UdDgQWBBSaztoCfcw+ +mBrfMXLCBU8mOyj2BTAfBgNVHSMEGDAWgBSaztoCfcw+mBrfMXLCBU8mOyj2BTAP +BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCSgkWG4QAblyxXN/R5 +tNLKbzQIbaMj8uXSdcVtNHrNfydA0Sq2M8w7mT7N2axiMAusN3fhgztQvkWCvKdy +ou++NpFBb11+QJ2chgatLtoR7QPQ2TVlTUObAh2ZSt1jDOqvGQynbYqJ+9N6BKpK +S8faScaWP78J02TSMiNIvh8iYukZPMdCyJaHw2x0PtCRYVBSlFIwC5dn/sIJgyrV +g8RAlnsKTCQC3X20AQ851aID6JXDIaTn9pn9PN0XJC+iButpLZM4ZHHZpBtSQZ+d +6lD0tvS8bysCEkamDMt3z8/ncsytAS08VoFqwXdY3EXF8T+sKSi7+ACJXE/kivwu +8jvm +-----END CERTIFICATE----- diff --git a/examples/protocols/esp_local_ctrl/main/component.mk b/examples/protocols/esp_local_ctrl/main/component.mk new file mode 100644 index 0000000000..b120d66e5e --- /dev/null +++ b/examples/protocols/esp_local_ctrl/main/component.mk @@ -0,0 +1,7 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) + +COMPONENT_EMBED_TXTFILES := certs/cacert.pem +COMPONENT_EMBED_TXTFILES += certs/prvtkey.pem diff --git a/examples/protocols/esp_local_ctrl/main/esp_local_ctrl_service.c b/examples/protocols/esp_local_ctrl/main/esp_local_ctrl_service.c new file mode 100644 index 0000000000..2e80baeebb --- /dev/null +++ b/examples/protocols/esp_local_ctrl/main/esp_local_ctrl_service.c @@ -0,0 +1,274 @@ +/* Local Ctrl Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +static const char *TAG = "control"; + +#define SERVICE_NAME "my_esp_ctrl_device" + +/* Custom allowed property types */ +enum property_types { + PROP_TYPE_TIMESTAMP = 0, + PROP_TYPE_INT32, + PROP_TYPE_BOOLEAN, + PROP_TYPE_STRING, +}; + +/* Custom flags that can be set for a property */ +enum property_flags { + PROP_FLAG_READONLY = (1 << 0) +}; + +/********* Handler functions for responding to control requests / commands *********/ + +static esp_err_t get_property_values(size_t props_count, + const esp_local_ctrl_prop_t props[], + esp_local_ctrl_prop_val_t prop_values[], + void *usr_ctx) +{ + for (uint32_t i = 0; i < props_count; i++) { + ESP_LOGI(TAG, "Reading property : %s", props[i].name); + /* For the purpose of this example, to keep things simple + * we have set the context pointer of each property to + * point to its value (except for timestamp) */ + switch (props[i].type) { + case PROP_TYPE_INT32: + case PROP_TYPE_BOOLEAN: + /* No need to set size for these types as sizes where + * specified when declaring the properties, unlike for + * string type. */ + prop_values[i].data = props[i].ctx; + break; + case PROP_TYPE_TIMESTAMP: { + /* Get the time stamp */ + static int64_t ts = 0; + ts = esp_timer_get_time(); + + /* Set the current time. Since this is statically + * allocated, we don't need to provide a free_fn */ + prop_values[i].data = &ts; + break; + } + case PROP_TYPE_STRING: { + char **prop3_value = (char **) props[i].ctx; + if (*prop3_value == NULL) { + prop_values[i].size = 0; + prop_values[i].data = NULL; + } else { + /* We could try dynamically allocating the output value, + * and it should get freed automatically after use, as + * `esp_local_ctrl` internally calls the provided `free_fn` */ + prop_values[i].size = strlen(*prop3_value); + prop_values[i].data = strdup(*prop3_value); + if (!prop_values[i].data) { + return ESP_ERR_NO_MEM; + } + prop_values[i].free_fn = free; + } + } + default: + break; + } + } + return ESP_OK; +} + +static esp_err_t set_property_values(size_t props_count, + const esp_local_ctrl_prop_t props[], + const esp_local_ctrl_prop_val_t prop_values[], + void *usr_ctx) +{ + for (uint32_t i = 0; i < props_count; i++) { + /* Cannot set the value of a read-only property */ + if (props[i].flags & PROP_FLAG_READONLY) { + ESP_LOGE(TAG, "%s is read-only", props[i].name); + return ESP_ERR_INVALID_ARG; + } + /* For the purpose of this example, to keep things simple + * we have set the context pointer of each property to + * point to its value (except for timestamp) */ + switch (props[i].type) { + case PROP_TYPE_STRING: { + /* Free the previously set string */ + char **prop3_value = (char **) props[i].ctx; + free(*prop3_value); + *prop3_value = NULL; + + /* Copy the input string */ + if (prop_values[i].size) { + *prop3_value = strndup((const char *)prop_values[i].data, prop_values[i].size); + if (*prop3_value == NULL) { + return ESP_ERR_NO_MEM; + } + ESP_LOGI(TAG, "Setting %s value to %s", props[i].name, (const char*)*prop3_value); + } + } + break; + case PROP_TYPE_INT32: { + const int32_t *new_value = (const int32_t *) prop_values[i].data; + ESP_LOGI(TAG, "Setting %s value to %d", props[i].name, *new_value); + memcpy(props[i].ctx, new_value, sizeof(int32_t)); + } + break; + case PROP_TYPE_BOOLEAN: { + const bool *value = (const bool *) prop_values[i].data; + ESP_LOGI(TAG, "Setting %s value to %d", props[i].name, *value); + memcpy(props[i].ctx, value, sizeof(bool)); + } + break; + default: + break; + } + } + return ESP_OK; +} + +/******************************************************************************/ + +/* A custom free_fn to free a pointer to a string as + * well as the string being pointed to */ +static void free_str(void *arg) +{ + char **ptr_to_strptr = (char **)arg; + if (ptr_to_strptr) { + free(*ptr_to_strptr); + free(ptr_to_strptr); + } +} + +/* Function used by app_main to start the esp_local_ctrl service */ +void start_esp_local_ctrl_service(void) +{ + /* Set the configuration */ + httpd_ssl_config_t https_conf = HTTPD_SSL_CONFIG_DEFAULT(); + + /* Load server certificate */ + extern const unsigned char cacert_pem_start[] asm("_binary_cacert_pem_start"); + extern const unsigned char cacert_pem_end[] asm("_binary_cacert_pem_end"); + https_conf.cacert_pem = cacert_pem_start; + https_conf.cacert_len = cacert_pem_end - cacert_pem_start; + + /* Load server private key */ + extern const unsigned char prvtkey_pem_start[] asm("_binary_prvtkey_pem_start"); + extern const unsigned char prvtkey_pem_end[] asm("_binary_prvtkey_pem_end"); + https_conf.prvtkey_pem = prvtkey_pem_start; + https_conf.prvtkey_len = prvtkey_pem_end - prvtkey_pem_start; + + esp_local_ctrl_config_t config = { + .transport = ESP_LOCAL_CTRL_TRANSPORT_HTTPD, + .transport_config = { + .httpd = &https_conf + }, + .handlers = { + /* User defined handler functions */ + .get_prop_values = get_property_values, + .set_prop_values = set_property_values, + .usr_ctx = NULL, + .usr_ctx_free_fn = NULL + }, + /* Maximum number of properties that may be set */ + .max_properties = 10 + }; + + mdns_init(); + mdns_hostname_set(SERVICE_NAME); + + /* Start esp_local_ctrl service */ + ESP_ERROR_CHECK(esp_local_ctrl_start(&config)); + ESP_LOGI(TAG, "esp_local_ctrl service started with name : %s", SERVICE_NAME); + + /* Create a timestamp property. The client should see this as a read-only property. + * Property value is fetched using `esp_timer_get_time()` in the `get_prop_values` + * handler */ + esp_local_ctrl_prop_t timestamp = { + .name = "timestamp (us)", + .type = PROP_TYPE_TIMESTAMP, + .size = sizeof(int64_t), + .flags = PROP_FLAG_READONLY, + .ctx = NULL, + .ctx_free_fn = NULL + }; + + /* Create a writable integer property. Use dynamically allocated memory + * for storing its value and pass it as context, so that it can be accessed + * inside the set / get handlers. */ + int32_t *prop1_value = malloc(sizeof(int32_t)); + assert(prop1_value != NULL); + + /* Initialize the property value */ + *prop1_value = 123456789; + + /* Populate the property structure accordingly. Since, we would want the memory + * occupied by the property value to be freed automatically upon call to + * `esp_local_ctrl_stop()` or `esp_local_ctrl_remove_property()`, the `ctx_free_fn` + * field will need to be set with the appropriate de-allocation function, + * which in this case is simply `free()` */ + esp_local_ctrl_prop_t property1 = { + .name = "property1", + .type = PROP_TYPE_INT32, + .size = sizeof(int32_t), + .flags = 0, + .ctx = prop1_value, + .ctx_free_fn = free + }; + + /* Create another read-only property. Just for demonstration, we use statically + * allocated value. No `ctx_free_fn` needs to be set for this */ + static bool prop2_value = false; + + esp_local_ctrl_prop_t property2 = { + .name = "property2", + .type = PROP_TYPE_BOOLEAN, + .size = sizeof(bool), + .flags = PROP_FLAG_READONLY, + .ctx = &prop2_value, + .ctx_free_fn = NULL + }; + + /* Create a variable sized property. Its context is a pointer for storing the + * pointer to a dynamically allocate string, therefore it will require a + * customized free function `free_str()` */ + char **prop3_value = calloc(1, sizeof(char *)); + assert(prop3_value != NULL); + + esp_local_ctrl_prop_t property3 = { + .name = "property3", + .type = PROP_TYPE_STRING, + .size = 0, // When zero, this is assumed to be of variable size + .flags = 0, + .ctx = prop3_value, + .ctx_free_fn = free_str + }; + + /* Now register the properties */ + ESP_ERROR_CHECK(esp_local_ctrl_add_property(×tamp)); + ESP_ERROR_CHECK(esp_local_ctrl_add_property(&property1)); + ESP_ERROR_CHECK(esp_local_ctrl_add_property(&property2)); + ESP_ERROR_CHECK(esp_local_ctrl_add_property(&property3)); + + /* Just for fun, let us keep toggling the value + * of the boolean property2, every 1 second */ + while (1) { + vTaskDelay(1000 / portTICK_RATE_MS); + prop2_value = !prop2_value; + } +} diff --git a/examples/protocols/esp_local_ctrl/scripts/esp_local_ctrl.py b/examples/protocols/esp_local_ctrl/scripts/esp_local_ctrl.py new file mode 100644 index 0000000000..23888bd2d9 --- /dev/null +++ b/examples/protocols/esp_local_ctrl/scripts/esp_local_ctrl.py @@ -0,0 +1,273 @@ +#!/usr/bin/env python +# +# Copyright 2018 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. +# + +from __future__ import print_function +from future.utils import tobytes +from builtins import input +import os +import sys +import struct +import argparse + +import proto + +try: + import esp_prov + +except ImportError: + idf_path = os.environ['IDF_PATH'] + sys.path.insert(1, idf_path + "/tools/esp_prov") + import esp_prov + + +# Set this to true to allow exceptions to be thrown +config_throw_except = False + + +# Property types enum +PROP_TYPE_TIMESTAMP = 0 +PROP_TYPE_INT32 = 1 +PROP_TYPE_BOOLEAN = 2 +PROP_TYPE_STRING = 3 + + +# Property flags enum +PROP_FLAG_READONLY = (1 << 0) + + +def prop_typestr(prop): + if prop["type"] == PROP_TYPE_TIMESTAMP: + return "TIME(us)" + elif prop["type"] == PROP_TYPE_INT32: + return "INT32" + elif prop["type"] == PROP_TYPE_BOOLEAN: + return "BOOLEAN" + elif prop["type"] == PROP_TYPE_STRING: + return "STRING" + return "UNKNOWN" + + +def encode_prop_value(prop, value): + try: + if prop["type"] == PROP_TYPE_TIMESTAMP: + return struct.pack('q', value) + elif prop["type"] == PROP_TYPE_INT32: + return struct.pack('i', value) + elif prop["type"] == PROP_TYPE_BOOLEAN: + return struct.pack('?', value) + elif prop["type"] == PROP_TYPE_STRING: + return tobytes(value) + return value + except struct.error as e: + print(e) + return None + + +def decode_prop_value(prop, value): + try: + if prop["type"] == PROP_TYPE_TIMESTAMP: + return struct.unpack('q', value)[0] + elif prop["type"] == PROP_TYPE_INT32: + return struct.unpack('i', value)[0] + elif prop["type"] == PROP_TYPE_BOOLEAN: + return struct.unpack('?', value)[0] + elif prop["type"] == PROP_TYPE_STRING: + return value.decode('latin-1') + return value + except struct.error as e: + print(e) + return None + + +def str_to_prop_value(prop, strval): + try: + if prop["type"] == PROP_TYPE_TIMESTAMP: + return int(strval) + elif prop["type"] == PROP_TYPE_INT32: + return int(strval) + elif prop["type"] == PROP_TYPE_BOOLEAN: + return bool(strval) + elif prop["type"] == PROP_TYPE_STRING: + return strval + return strval + except ValueError as e: + print(e) + return None + + +def prop_is_readonly(prop): + return (prop["flags"] & PROP_FLAG_READONLY) is not 0 + + +def on_except(err): + if config_throw_except: + raise RuntimeError(err) + else: + print(err) + + +def get_transport(sel_transport, service_name): + try: + tp = None + if (sel_transport == 'http'): + example_path = os.environ['IDF_PATH'] + "/examples/protocols/esp_local_ctrl" + cert_path = example_path + "/main/certs/rootCA.pem" + tp = esp_prov.transport.Transport_HTTP(service_name, cert_path) + elif (sel_transport == 'ble'): + tp = esp_prov.transport.Transport_BLE( + devname=service_name, service_uuid='0000ffff-0000-1000-8000-00805f9b34fb', + nu_lookup={'esp_local_ctrl/version': '0001', + 'esp_local_ctrl/session': '0002', + 'esp_local_ctrl/control': '0003'} + ) + return tp + except RuntimeError as e: + on_except(e) + return None + + +def version_match(tp, expected, verbose=False): + try: + response = tp.send_data('esp_local_ctrl/version', expected) + return (response.lower() == expected.lower()) + except Exception as e: + on_except(e) + return None + + +def get_all_property_values(tp): + try: + props = [] + message = proto.get_prop_count_request() + response = tp.send_data('esp_local_ctrl/control', message) + count = proto.get_prop_count_response(response) + if count == 0: + raise RuntimeError("No properties found!") + indices = [i for i in range(count)] + message = proto.get_prop_vals_request(indices) + response = tp.send_data('esp_local_ctrl/control', message) + props = proto.get_prop_vals_response(response) + if len(props) != count: + raise RuntimeError("Incorrect count of properties!") + for p in props: + p["value"] = decode_prop_value(p, p["value"]) + return props + except RuntimeError as e: + on_except(e) + return [] + + +def set_property_values(tp, props, indices, values, check_readonly=False): + try: + if check_readonly: + for index in indices: + if prop_is_readonly(props[index]): + raise RuntimeError("Cannot set value of Read-Only property") + message = proto.set_prop_vals_request(indices, values) + response = tp.send_data('esp_local_ctrl/control', message) + return proto.set_prop_vals_response(response) + except RuntimeError as e: + on_except(e) + return False + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(add_help=False) + + parser = argparse.ArgumentParser(description="Control an ESP32 running esp_local_ctrl service") + + parser.add_argument("--version", dest='version', type=str, + help="Protocol version", default='') + + parser.add_argument("--transport", dest='transport', type=str, + help="transport i.e http or ble", default='http') + + parser.add_argument("--name", dest='service_name', type=str, + help="BLE Device Name / HTTP Server hostname or IP", default='') + + parser.add_argument("-v", "--verbose", dest='verbose', help="increase output verbosity", action="store_true") + args = parser.parse_args() + + if args.version != '': + print("==== Esp_Ctrl Version: " + args.version + " ====") + + if args.service_name == '': + args.service_name = 'my_esp_ctrl_device' + if args.transport == 'http': + args.service_name += '.local' + + obj_transport = get_transport(args.transport, args.service_name) + if obj_transport is None: + print("---- Invalid transport ----") + exit(1) + + if args.version != '': + print("\n==== Verifying protocol version ====") + if not version_match(obj_transport, args.version, args.verbose): + print("---- Error in protocol version matching ----") + exit(2) + print("==== Verified protocol version successfully ====") + + while True: + properties = get_all_property_values(obj_transport) + if len(properties) == 0: + print("---- Error in reading property values ----") + exit(4) + + print("\n==== Available Properties ====") + print("{0: >4} {1: <16} {2: <10} {3: <16} {4: <16}".format( + "S.N.", "Name", "Type", "Flags", "Value")) + for i in range(len(properties)): + print("[{0: >2}] {1: <16} {2: <10} {3: <16} {4: <16}".format( + i + 1, properties[i]["name"], prop_typestr(properties[i]), + ["","Read-Only"][prop_is_readonly(properties[i])], + str(properties[i]["value"]))) + + select = 0 + while True: + try: + inval = input("\nSelect properties to set (0 to re-read, 'q' to quit) : ") + if inval.lower() == 'q': + print("Quitting...") + exit(5) + invals = inval.split(',') + selections = [int(val) for val in invals] + if min(selections) < 0 or max(selections) > len(properties): + raise ValueError("Invalid input") + break + except ValueError as e: + print(str(e) + "! Retry...") + + if len(selections) == 1 and selections[0] == 0: + continue + + set_values = [] + set_indices = [] + for select in selections: + while True: + inval = input("Enter value to set for property (" + properties[select - 1]["name"] + ") : ") + value = encode_prop_value(properties[select - 1], + str_to_prop_value(properties[select - 1], inval)) + if value is None: + print("Invalid input! Retry...") + continue + break + set_values += [value] + set_indices += [select - 1] + + if not set_property_values(obj_transport, properties, set_indices, set_values): + print("Failed to set values!") diff --git a/examples/protocols/esp_local_ctrl/scripts/proto.py b/examples/protocols/esp_local_ctrl/scripts/proto.py new file mode 100644 index 0000000000..15dda7ab4b --- /dev/null +++ b/examples/protocols/esp_local_ctrl/scripts/proto.py @@ -0,0 +1,93 @@ +# Copyright 2018 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. +# + + +from __future__ import print_function +from future.utils import tobytes +import os + + +def _load_source(name, path): + try: + from importlib.machinery import SourceFileLoader + return SourceFileLoader(name, path).load_module() + except ImportError: + # importlib.machinery doesn't exists in Python 2 so we will use imp (deprecated in Python 3) + import imp + return imp.load_source(name, path) + + +idf_path = os.environ['IDF_PATH'] +constants_pb2 = _load_source("constants_pb2", idf_path + "/components/protocomm/python/constants_pb2.py") +local_ctrl_pb2 = _load_source("esp_local_ctrl_pb2", idf_path + "/components/esp_local_ctrl/python/esp_local_ctrl_pb2.py") + + +def get_prop_count_request(): + req = local_ctrl_pb2.LocalCtrlMessage() + req.msg = local_ctrl_pb2.TypeCmdGetPropertyCount + payload = local_ctrl_pb2.CmdGetPropertyCount() + req.cmd_get_prop_count.MergeFrom(payload) + return req.SerializeToString() + + +def get_prop_count_response(response_data): + resp = local_ctrl_pb2.LocalCtrlMessage() + resp.ParseFromString(tobytes(response_data)) + if (resp.resp_get_prop_count.status == 0): + return resp.resp_get_prop_count.count + else: + return 0 + + +def get_prop_vals_request(indices): + req = local_ctrl_pb2.LocalCtrlMessage() + req.msg = local_ctrl_pb2.TypeCmdGetPropertyValues + payload = local_ctrl_pb2.CmdGetPropertyValues() + payload.indices.extend(indices) + req.cmd_get_prop_vals.MergeFrom(payload) + return req.SerializeToString() + + +def get_prop_vals_response(response_data): + resp = local_ctrl_pb2.LocalCtrlMessage() + resp.ParseFromString(tobytes(response_data)) + results = [] + if (resp.resp_get_prop_vals.status == 0): + for prop in resp.resp_get_prop_vals.props: + results += [{ + "name": prop.name, + "type": prop.type, + "flags": prop.flags, + "value": tobytes(prop.value) + }] + return results + + +def set_prop_vals_request(indices, values): + req = local_ctrl_pb2.LocalCtrlMessage() + req.msg = local_ctrl_pb2.TypeCmdSetPropertyValues + payload = local_ctrl_pb2.CmdSetPropertyValues() + for i, v in zip(indices, values): + prop = payload.props.add() + prop.index = i + prop.value = v + req.cmd_set_prop_vals.MergeFrom(payload) + return req.SerializeToString() + + +def set_prop_vals_response(response_data): + resp = local_ctrl_pb2.LocalCtrlMessage() + resp.ParseFromString(tobytes(response_data)) + return (resp.resp_set_prop_vals.status == 0) diff --git a/examples/protocols/esp_local_ctrl/sdkconfig.defaults b/examples/protocols/esp_local_ctrl/sdkconfig.defaults new file mode 100644 index 0000000000..a9595bf0c1 --- /dev/null +++ b/examples/protocols/esp_local_ctrl/sdkconfig.defaults @@ -0,0 +1 @@ +CONFIG_ESP_HTTPS_SERVER_ENABLE=y diff --git a/tools/esp_prov/esp_prov.py b/tools/esp_prov/esp_prov.py index ad199143ae..d80db3cd7e 100644 --- a/tools/esp_prov/esp_prov.py +++ b/tools/esp_prov/esp_prov.py @@ -61,7 +61,7 @@ def get_transport(sel_transport, softap_endpoint=None, ble_devname=None): try: tp = None if (sel_transport == 'softap'): - tp = transport.Transport_Softap(softap_endpoint) + tp = transport.Transport_HTTP(softap_endpoint) elif (sel_transport == 'ble'): # BLE client is now capable of automatically figuring out # the primary service from the advertisement data and the diff --git a/tools/esp_prov/transport/__init__.py b/tools/esp_prov/transport/__init__.py index 809d1335d3..907df1f3ca 100644 --- a/tools/esp_prov/transport/__init__.py +++ b/tools/esp_prov/transport/__init__.py @@ -14,5 +14,5 @@ # from .transport_console import * # noqa: F403, F401 -from .transport_softap import * # noqa: F403, F401 +from .transport_http import * # noqa: F403, F401 from .transport_ble import * # noqa: F403, F401 diff --git a/tools/esp_prov/transport/transport_softap.py b/tools/esp_prov/transport/transport_http.py similarity index 71% rename from tools/esp_prov/transport/transport_softap.py rename to tools/esp_prov/transport/transport_http.py index 5b0d2908fd..47e8b28efa 100644 --- a/tools/esp_prov/transport/transport_softap.py +++ b/tools/esp_prov/transport/transport_http.py @@ -16,14 +16,25 @@ from __future__ import print_function from future.utils import tobytes +import socket import http.client +import ssl from .transport import Transport -class Transport_Softap(Transport): - def __init__(self, url): - self.conn = http.client.HTTPConnection(url, timeout=30) +class Transport_HTTP(Transport): + def __init__(self, hostname, certfile=None): + try: + socket.gethostbyname(hostname.split(':')[0]) + except socket.gaierror: + raise RuntimeError("Unable to resolve hostname :" + hostname) + + if certfile is None: + self.conn = http.client.HTTPConnection(hostname, timeout=30) + else: + ssl_ctx = ssl.create_default_context(cafile=certfile) + self.conn = http.client.HTTPSConnection(hostname, context=ssl_ctx, timeout=30) self.headers = {"Content-type": "application/x-www-form-urlencoded","Accept": "text/plain"} def _send_post_request(self, path, data): From b24341a664ea1613a8194cf45bdbd68bc8c96b5a Mon Sep 17 00:00:00 2001 From: Wang Fang Date: Thu, 4 Jul 2019 13:16:18 +0800 Subject: [PATCH 233/486] Merge make-related documents: 1. Moved get-started files, 7 documents in total, from get-started-cmake folder to hw-reference folder; 2. Deleted get-started files, 7 documents in total, in get-started folder; 3. Updated links in get-started-cmake/index.rst and in get-started/index.rst; 4. Modified descriptions for build system in these files. --- docs/conf_common.py | 8 +- .../jtag-debugging/configure-wrover.rst | 2 +- docs/en/get-started-cmake/index.rst | 6 +- .../en/get-started/get-started-devkitc-v2.rst | 82 ---- docs/en/get-started/get-started-devkitc.rst | 153 ------- .../get-started/get-started-pico-kit-v3.rst | 77 ---- docs/en/get-started/get-started-pico-kit.rst | 234 ----------- .../get-started/get-started-wrover-kit-v2.rst | 195 --------- .../get-started/get-started-wrover-kit-v3.rst | 381 ----------------- .../en/get-started/get-started-wrover-kit.rst | 385 ------------------ docs/en/get-started/index.rst | 6 +- .../get-started-devkitc-v2.rst | 6 +- .../get-started-devkitc.rst | 6 +- .../get-started-pico-kit-v3.rst | 6 +- .../get-started-pico-kit.rst | 4 +- .../get-started-wrover-kit-v2.rst | 6 +- .../get-started-wrover-kit-v3.rst | 6 +- .../get-started-wrover-kit.rst | 6 +- .../modules-and-boards-previous.rst | 10 +- docs/en/hw-reference/modules-and-boards.rst | 6 +- .../jtag-debugging/configure-wrover.rst | 2 +- docs/zh_CN/get-started-cmake/index.rst | 6 +- .../get-started/get-started-devkitc-v2.rst | 81 ---- .../zh_CN/get-started/get-started-devkitc.rst | 153 ------- .../get-started/get-started-pico-kit-v3.rst | 78 ---- .../get-started/get-started-pico-kit.rst | 235 ----------- .../get-started/get-started-wrover-kit-v2.rst | 191 --------- .../get-started/get-started-wrover-kit-v3.rst | 377 ----------------- .../get-started/get-started-wrover-kit.rst | 382 ----------------- docs/zh_CN/get-started/index.rst | 6 +- .../get-started-devkitc-v2.rst | 7 +- .../get-started-devkitc.rst | 6 +- .../get-started-pico-kit-v3.rst | 6 +- .../get-started-pico-kit.rst | 6 +- .../get-started-wrover-kit-v2.rst | 6 +- .../get-started-wrover-kit-v3.rst | 6 +- .../get-started-wrover-kit.rst | 6 +- 37 files changed, 85 insertions(+), 3054 deletions(-) delete mode 100644 docs/en/get-started/get-started-devkitc-v2.rst delete mode 100644 docs/en/get-started/get-started-devkitc.rst delete mode 100644 docs/en/get-started/get-started-pico-kit-v3.rst delete mode 100644 docs/en/get-started/get-started-pico-kit.rst delete mode 100644 docs/en/get-started/get-started-wrover-kit-v2.rst delete mode 100644 docs/en/get-started/get-started-wrover-kit-v3.rst delete mode 100644 docs/en/get-started/get-started-wrover-kit.rst rename docs/en/{get-started-cmake => hw-reference}/get-started-devkitc-v2.rst (91%) rename docs/en/{get-started-cmake => hw-reference}/get-started-devkitc.rst (93%) rename docs/en/{get-started-cmake => hw-reference}/get-started-pico-kit-v3.rst (88%) rename docs/en/{get-started-cmake => hw-reference}/get-started-pico-kit.rst (97%) rename docs/en/{get-started-cmake => hw-reference}/get-started-wrover-kit-v2.rst (96%) rename docs/en/{get-started-cmake => hw-reference}/get-started-wrover-kit-v3.rst (97%) rename docs/en/{get-started-cmake => hw-reference}/get-started-wrover-kit.rst (97%) delete mode 100644 docs/zh_CN/get-started/get-started-devkitc-v2.rst delete mode 100644 docs/zh_CN/get-started/get-started-devkitc.rst delete mode 100644 docs/zh_CN/get-started/get-started-pico-kit-v3.rst delete mode 100644 docs/zh_CN/get-started/get-started-pico-kit.rst delete mode 100644 docs/zh_CN/get-started/get-started-wrover-kit-v2.rst delete mode 100644 docs/zh_CN/get-started/get-started-wrover-kit-v3.rst delete mode 100644 docs/zh_CN/get-started/get-started-wrover-kit.rst rename docs/zh_CN/{get-started-cmake => hw-reference}/get-started-devkitc-v2.rst (90%) rename docs/zh_CN/{get-started-cmake => hw-reference}/get-started-devkitc.rst (93%) rename docs/zh_CN/{get-started-cmake => hw-reference}/get-started-pico-kit-v3.rst (90%) rename docs/zh_CN/{get-started-cmake => hw-reference}/get-started-pico-kit.rst (97%) rename docs/zh_CN/{get-started-cmake => hw-reference}/get-started-wrover-kit-v2.rst (97%) rename docs/zh_CN/{get-started-cmake => hw-reference}/get-started-wrover-kit-v3.rst (98%) rename docs/zh_CN/{get-started-cmake => hw-reference}/get-started-wrover-kit.rst (98%) diff --git a/docs/conf_common.py b/docs/conf_common.py index a008829bda..8bd4eb988e 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -247,7 +247,13 @@ html_redirect_pages = [('api-reference/ethernet/index', 'api-reference/network/i ('api-reference/wifi/esp_wifi', 'api-reference/network/esp_wifi'), ('api-reference/system/tcpip_adapter', 'api-reference/network/tcpip_adapter'), ('get-started/idf-monitor', 'api-guides/tools/idf-monitor'), - ('get-started-cmake/idf-monitor', 'api-guides/tools/idf-monitor'),] + ('get-started-cmake/idf-monitor', 'api-guides/tools/idf-monitor'), + ('get-started/get-started-devkitc', 'hw-reference/get-started-devkitc'), + ('get-started/get-started-wrover-kit', 'hw-reference/get-started-wrover-kit'), + ('get-started/get-started-pico-kit', 'hw-reference/get-started-pico-kit'), + ('get-started-cmake/get-started-devkitc', 'hw-reference/get-started-devkitc'), + ('get-started-cmake/get-started-wrover-kit', 'hw-reference/get-started-wrover-kit'), + ('get-started-cmake/get-started-pico-kit', 'hw-reference/get-started-pico-kit')] # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. diff --git a/docs/en/api-guides/jtag-debugging/configure-wrover.rst b/docs/en/api-guides/jtag-debugging/configure-wrover.rst index c985e640ac..0f1ca1f887 100644 --- a/docs/en/api-guides/jtag-debugging/configure-wrover.rst +++ b/docs/en/api-guides/jtag-debugging/configure-wrover.rst @@ -8,7 +8,7 @@ All versions of ESP-WROVER-KIT boards have built-in JTAG functionality. Putting Configure Hardware ^^^^^^^^^^^^^^^^^^ -1. Enable on-board JTAG functionality by setting JP8 according to :doc:`../../get-started/get-started-wrover-kit`, Section :ref:`get-started-esp-wrover-kit-v4.1-setup-options`. +1. Enable on-board JTAG functionality by setting JP8 according to :doc:`../../hw-reference/get-started-wrover-kit`, Section :ref:`get-started-esp-wrover-kit-v4.1-setup-options-cmake`. 2. Verify if ESP32 pins used for JTAG communication are not connected to some other h/w that may disturb JTAG operation: diff --git a/docs/en/get-started-cmake/index.rst b/docs/en/get-started-cmake/index.rst index af24a9cf5d..e5f810c093 100644 --- a/docs/en/get-started-cmake/index.rst +++ b/docs/en/get-started-cmake/index.rst @@ -62,9 +62,9 @@ If you have one of ESP32 development boards listed below, you can click on the l .. toctree:: :maxdepth: 1 - ESP32-DevKitC - ESP-WROVER-KIT - ESP32-PICO-KIT + ESP32-DevKitC <../hw-reference/get-started-devkitc> + ESP-WROVER-KIT <../hw-reference/get-started-wrover-kit> + ESP32-PICO-KIT <../hw-reference/get-started-pico-kit> ESP32-Ethernet-Kit <../hw-reference/get-started-ethernet-kit> diff --git a/docs/en/get-started/get-started-devkitc-v2.rst b/docs/en/get-started/get-started-devkitc-v2.rst deleted file mode 100644 index 97d6ef6842..0000000000 --- a/docs/en/get-started/get-started-devkitc-v2.rst +++ /dev/null @@ -1,82 +0,0 @@ -ESP32-DevKitC V2 Getting Started Guide (CMake) -============================================== - -:link_to_translation:`zh_CN:[中文]` - -This guide shows how to start using the ESP32-DevKitC V2 development board. - - -What You Need -------------- - -* ESP32-DevKitC V2 board -* USB A / micro USB B cable -* Computer running Windows, Linux, or macOS - -You can skip the introduction sections and go directly to Section `Start Application Development`_. - - -Overview --------- - -ESP32-DevKitC V2 is a small-sized ESP32-based development board produced by `Espressif `_. Most of the I/O pins are broken out to the pin headers on both sides for easy interfacing. Developers can either connect peripherals with jumper wires or mount ESP32-DevKitC V4 on a breadboard. - - -Functional Description ----------------------- - -The following figure and the table below describe the key components, interfaces and controls of the ESP32-DevKitC V2 board. - -.. _get-started-esp32-devkitc-v2-board-front-make: - -.. figure:: ../../_static/esp32-devkitc-v2-functional-overview.png - :align: center - :alt: ESP32-DevKitC V2 board layout - :figclass: align-center - - ESP32-DevKitC V2 board layout - - -+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Key Component | Description | -+=====================+=========================================================================================================================================================================================+ -| ESP32-WROOM-32 | Standard module with ESP32 at its core. For more information, see `ESP32-WROOM-32 Datasheet `_ | -+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| EN | Reset button. | -+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Boot | Download button. Holding down **Boot** and then pressing **EN** initiates Firmware Download mode for downloading firmware through the serial port. | -+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Micro USB Port | USB interface. Power supply for the board as well as the communication interface between a computer and ESP32-WROOM-32. | -+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| I/O | Most of the pins on the ESP module are broken out to the pin headers on the board. You can program ESP32 to enable multiple functions such as PWM, ADC, DAC, I2C, I2S, SPI, etc. | -+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -Power Supply Options --------------------- - -There are three mutually exclusive ways to provide power to the board: - -* Micro USB port, default power supply -* 5V / GND header pins -* 3V3 / GND header pins - -.. warning:: - - The power supply must be provided using **one and only one of the options above**, otherwise the board and/or the power supply source can be damaged. - - -Start Application Development ------------------------------- - -Before powering up your ESP32-DevKitC V2, please make sure that the board is in good condition with no obvious signs of damage. - -After that, proceed to :doc:`index`, where Section :ref:`get-started-step-by-step` will quickly help you set up the development environment and then flash an example project onto your board. - - -Related Documents ------------------ - -* `ESP32-DevKitC schematics `_ (PDF) -* `ESP32 Datasheet `_ (PDF) -* `ESP32-WROOM-32 Datasheet `_ (PDF) diff --git a/docs/en/get-started/get-started-devkitc.rst b/docs/en/get-started/get-started-devkitc.rst deleted file mode 100644 index 3d10640252..0000000000 --- a/docs/en/get-started/get-started-devkitc.rst +++ /dev/null @@ -1,153 +0,0 @@ -ESP32-DevKitC V4 Getting Started Guide -====================================== - -:link_to_translation:`zh_CN:[中文]` - -This guide shows how to start using the ESP32-DevKitC V4 development board. For description of other versions of ESP32-DevKitC check :doc:`../hw-reference/index`. - - -What You Need -------------- - -* ESP32-DevKitC V4 board -* USB A / micro USB B cable -* Computer running Windows, Linux, or macOS - -You can skip the introduction sections and go directly to Section `Start Application Development`_. - - -.. _DevKitC-Overview: - -Overview --------- - -ESP32-DevKitC V4 is a small-sized ESP32-based development board produced by `Espressif `_. Most of the I/O pins are broken out to the pin headers on both sides for easy interfacing. Developers can either connect peripherals with jumper wires or mount ESP32-DevKitC V4 on a breadboard. - -To cover a wide range of user requirements, the following versions of ESP32-DevKitC V4 are available: - -- different ESP32 modules - - - :ref:`esp-modules-and-boards-esp32-wroom-32` - - :ref:`ESP32-WROOM-32D ` - - :ref:`ESP32-WROOM-32U ` - - :ref:`esp-modules-and-boards-esp32-solo-1` - - :ref:`ESP32-WROVER ` - - :ref:`ESP32-WROVER-B ` - - :ref:`ESP32-WROVER-I ` - - :ref:`ESP32-WROVER-B (IPEX) ` - -- male or female pin headers. - -For details please refer to `Espressif Product Ordering Information`_. - - -Functional Description ----------------------- - -The following figure and the table below describe the key components, interfaces and controls of the ESP32-DevKitC V4 board. - -.. _get-started-esp32-devkitc-board-front: - -.. figure:: ../../_static/esp32-devkitc-functional-overview.jpg - :align: center - :alt: ESP32-DevKitC V4 with ESP-WROOM-32 module soldered - :figclass: align-center - - ESP32-DevKitC V4 with ESP32-WROOM-32 module soldered - - -+--------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Key Component | Description | -+====================+======================================================================================================================================================================================+ -| ESP32-WROOM-32 | A module with ESP32 at its core. | -+--------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| EN | Reset button. | -+--------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Boot | Download button. Holding down **Boot** and then pressing **EN** initiates Firmware Download mode for downloading firmware through the serial port. | -+--------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| USB-to-UART Bridge | Single USB-UART bridge chip provides transfer rates of up to 3 Mbps. | -+--------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Micro USB Port | USB interface. Power supply for the board as well as the communication interface between a computer and the ESP32 module. | -+--------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 5V Power On LED | Turns on when the USB or an external 5V power supply is connected to the board. For details see the schematics in `Related Documents`_. | -+--------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| I/O | Most of the pins on the ESP module are broken out to the pin headers on the board. You can program ESP32 to enable multiple functions such as PWM, ADC, DAC, I2C, I2S, SPI, etc. | -+--------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - .. note:: - - The pins D0, D1, D2, D3, CMD and CLK are used internally for communication between ESP32 and SPI flash memory. They are grouped on both sides near the USB connector. Avoid using these pins, as it may disrupt access to the SPI flash memory / SPI RAM. - - .. note:: - - The pins GPIO16 and GPIO17 are available for use only on the boards with the modules ESP32-WROOM and ESP32-SOLO-1. The boards with ESP32-WROVER modules have the pins reserved for internal use. - - -Power Supply Options --------------------- - -There are three mutually exclusive ways to provide power to the board: - -* Micro USB port, default power supply -* 5V / GND header pins -* 3V3 / GND header pins - -.. warning:: - - The power supply must be provided using **one and only one of the options above**, otherwise the board and/or the power supply source can be damaged. - - -Note on C15 ------------ - -The component C15 may cause the following issues on earlier ESP32-DevKitC V4 boards: - -* The board may boot into Download mode -* If you output clock on GPIO0, C15 may impact the signal - -In case these issues occur, please remove the component. The figure below shows C15 highlighted in yellow. - - -.. figure:: ../../_static/esp32-devkitc-c15-location.png - :align: center - :alt: Location of C15 (colored yellow) on ESP32-DevKitC V4 board - :figclass: align-center - :width: 30% - - Location of C15 (yellow) on ESP32-DevKitC V4 board - - -Start Application Development ------------------------------- - -Before powering up your ESP32-DevKitC V4, please make sure that the board is in good condition with no obvious signs of damage. - -After that, proceed to :doc:`index`, where Section :ref:`get-started-step-by-step` will quickly help you set up the development environment and then flash an example project onto your board. - - -Board Dimensions ----------------- - -.. figure:: ../../_static/esp32-devkitc-dimensions-back.jpg - :align: center - :alt: ESP32 DevKitC board dimensions - back - :figclass: align-center - - ESP32 DevKitC board dimensions - back - - -Related Documents ------------------ - -* `ESP32-DevKitC V4 schematics `_ (PDF) -* `ESP32 Datasheet `_ (PDF) -* `ESP32-WROOM-32 Datasheet `_ (PDF) -* `ESP32-WROOM-32D & ESP32-WROOM-32U Datasheet `_ (PDF) -* `ESP32-WROVER Datasheet `_ (PDF) -* `ESP32-WROVER-B Datasheet `_ (PDF) -* `Espressif Product Ordering Information `_ (PDF) - -.. toctree:: - :hidden: - - get-started-devkitc-v2 diff --git a/docs/en/get-started/get-started-pico-kit-v3.rst b/docs/en/get-started/get-started-pico-kit-v3.rst deleted file mode 100644 index b8b2366f61..0000000000 --- a/docs/en/get-started/get-started-pico-kit-v3.rst +++ /dev/null @@ -1,77 +0,0 @@ -ESP32-PICO-KIT V3 Getting Started Guide -======================================= -:link_to_translation:`zh_CN:[中文]` - -This guide shows how to get started with the ESP32-PICO-KIT V3 mini development board. For the description of other ESP32-PICO-KIT versions, please check :doc:`../hw-reference/index`. - - -What You Need -------------- - -* ESP32-PICO-KIT V3 mini development board -* USB 2.0 A to Micro B cable -* Computer running Windows, Linux, or macOS - -You can skip the introduction sections and go directly to Section `Start Application Development`_. - - -Overview --------- - -ESP32-PICO-KIT V3 is an ESP32-based mini development board produced by `Espressif `_. The core of this board is ESP32-PICO-D4 - a System-in-Package (SiP) module. - -The development board features a USB-UART Bridge circuit, which allows developers to connect the board to a computer's USB port for flashing and debugging. - -All the IO signals and system power on ESP32-PICO-D4 are led out to two rows of 20 x 0.1" header pads on both sides of the development board for easy access. - - -Functional Description ----------------------- - -The following figure and the table below describe the key components, interfaces, and controls of the ESP32-PICO-KIT V3 board. - -.. figure:: ../../_static/esp32-pico-kit-v3-layout.jpg - :align: center - :alt: ESP32-PICO-KIT V3 board layout - :figclass: align-center - - ESP32-PICO-KIT V3 board layout - -Below is the description of the items identified in the figure starting from the top left corner and going clockwise. - -================== ================================================================================================================================= -Key Component Description -================== ================================================================================================================================= -ESP32-PICO-D4 Standard ESP32-PICO-D4 module soldered to the ESP32-PICO-KIT V3 board. The complete ESP32 system on a chip (ESP32 SoC) has been integrated into the SiP module, requiring only an external antenna with LC matching network, decoupling capacitors, and a pull-up resistor for EN signals to function properly. - -LDO 5V-to-3.3V Low dropout voltage regulator (LDO). - -USB-UART bridge Single-chip USB-UART bridge provides up to 1 Mbps transfers rates. - -Micro USB Port USB interface. Power supply for the board as well as the communication interface between a computer and the board. - -Power On LED This red LED turns on when power is supplied to the board. - -I/O All the pins on ESP32-PICO-D4 are broken out to pin headers. You can program ESP32 to enable multiple functions, such as PWM, ADC, DAC, I2C, I2S, SPI, etc. - -BOOT Button Download button. Holding down **Boot** and then pressing **EN** initiates Firmware Download mode for downloading firmware through the serial port. - -EN Button Reset button. -================== ================================================================================================================================= - - -Start Application Development ------------------------------ - -Before powering up your ESP32-PICO-KIT V3, please make sure that the board is in good condition with no obvious signs of damage. - -After that, proceed to :doc:`index`, where Section :ref:`get-started-step-by-step` will quickly help you set up the development environment and then flash an example project onto your board. - - -Related Documents ------------------ - -* `ESP32-PICO-KIT V3 schematic `_ (PDF) -* `ESP32-PICO-D4 Datasheet `_ (PDF) -* :doc:`../hw-reference/index` - diff --git a/docs/en/get-started/get-started-pico-kit.rst b/docs/en/get-started/get-started-pico-kit.rst deleted file mode 100644 index 73c4b5ef65..0000000000 --- a/docs/en/get-started/get-started-pico-kit.rst +++ /dev/null @@ -1,234 +0,0 @@ -ESP32-PICO-KIT V4 / V4.1 Getting Started Guide -============================================== -:link_to_translation:`zh_CN:[中文]` - -This guide shows how to get started with the ESP32-PICO-KIT V4 / V4.1 mini development board. For the description of other ESP32-PICO-KIT versions, please check :doc:`../hw-reference/index`. - -This particular description covers ESP32-PICO-KIT V4 and V4.1. The difference is the upgraded USB-UART bridge from CP2102 in V4 with up to 1 Mbps transfer rates to CP2102N in V4.1 with up to 3 Mbps transfer rates. - - -What You Need -------------- - -* :ref:`ESP32-PICO-KIT mini development board ` -* USB 2.0 A to Micro B cable -* Computer running Windows, Linux, or macOS - -You can skip the introduction sections and go directly to Section `Start Application Development`_. - - -Overview --------- - -ESP32-PICO-KIT is an ESP32-based mini development board produced by `Espressif `_. - -The core of this board is ESP32-PICO-D4 - a System-in-Package (SiP) module with complete Wi-Fi and Bluetooth functionalities. Compared to other ESP32 modules, ESP32-PICO-D4 integrates the following peripheral components in one single package, which otherwise would need to be installed separately: - -- 40 MHz crystal oscillator -- 4 MB flash -- Filter capacitors -- RF matching links - -This setup reduces the costs of additional external components as well as the cost of assembly and testing and also increases the overall usability of the product. - -The development board features a USB-UART Bridge circuit which allows developers to connect the board to a computer's USB port for flashing and debugging. - -All the IO signals and system power on ESP32-PICO-D4 are led out to two rows of 20 x 0.1" header pads on both sides of the development board for easy access. For compatibility with Dupont wires, 2 x 17 header pads are populated with two rows of male pin headers. The remaining 2 x 3 header pads beside the antenna are not populated. These pads may be populated later by the user if required. - -.. note:: - - 1. The 2 x 3 pads not populated with pin headers are connected to the flash memory embedded in the ESP32-PICO-D4 SiP module. For more details see module's datasheet in `Related Documents`_. - 2. ESP32-PICO-KIT comes with male headers by default. - -Functionality Overview ----------------------- - -The block diagram below shows the main components of ESP32-PICO-KIT and their interconnections. - -.. figure:: ../../_static/esp32-pico-kit-v4-functional-block-diagram.png - :align: center - :alt: ESP32-PICO-KIT functional block diagram - :figclass: align-center - - ESP32-PICO-KIT block diagram - - -Functional Description ----------------------- - -The following figure and the table below describe the key components, interfaces, and controls of the ESP32-PICO-KIT board. - -.. _get-started-pico-kit-v4-board-front: - -.. figure:: ../../_static/esp32-pico-kit-v4.1-f-layout.jpeg - :align: center - :alt: ESP32-PICO-KIT board layout - :figclass: align-center - - ESP32-PICO-KIT board layout - -Below is the description of the items identified in the figure starting from the top left corner and going clockwise. - -================== ================================================================================================================================= -Key Component Description -================== ================================================================================================================================= -ESP32-PICO-D4 Standard ESP32-PICO-D4 module soldered to the ESP32-PICO-KIT board. The complete ESP32 system on a chip (ESP32 SoC) has been integrated into the SiP module, requiring only an external antenna with LC matching network, decoupling capacitors, and a pull-up resistor for EN signals to function properly. - -LDO 5V-to-3.3V Low dropout voltage regulator (LDO). - -USB-UART bridge Single-chip USB-UART bridge: CP2102 in V4 provides up to 1 Mbps transfer rates and CP2102N in V4.1 offers up to 3 Mbps transfers rates. - -Micro USB Port USB interface. Power supply for the board as well as the communication interface between a computer and the board. - -5V Power On LED This red LED turns on when power is supplied to the board. For details, see the schematics in `Related Documents`_. - -I/O All the pins on ESP32-PICO-D4 are broken out to pin headers. You can program ESP32 to enable multiple functions, such as PWM, ADC, DAC, I2C, I2S, SPI, etc. For details, please see Section `Pin Descriptions`_. - -BOOT Button Download button. Holding down **Boot** and then pressing **EN** initiates Firmware Download mode for downloading firmware through the serial port. - -EN Button Reset button. -================== ================================================================================================================================= - - -Power Supply Options --------------------- - -There are three mutually exclusive ways to provide power to the board: - -* Micro USB port, default power supply -* 5V / GND header pins -* 3V3 / GND header pins - -.. warning:: - - The power supply must be provided using **one and only one of the options above**, otherwise the board and/or the power supply source can be damaged. - - -Pin Descriptions ----------------- - -The two tables below provide the **Name** and **Function** of I/O header pins on both sides of the board, see :ref:`get-started-pico-kit-v4-board-front`. The pin numbering and header names are the same as in the schematic given in `Related Documents`_. - - -Header J2 -""""""""" - -====== ================= ====== ====================================================== -No. Name Type Function -====== ================= ====== ====================================================== -1 FLASH_SD1 (FSD1) I/O | GPIO8, SD_DATA1, SPID, HS1_DATA1 :ref:`(See 1) ` , U2CTS -2 FLASH_SD3 (FSD3) I/O | GPIO7, SD_DATA0, SPIQ, HS1_DATA0 :ref:`(See 1) ` , U2RTS -3 FLASH_CLK (FCLK) I/O | GPIO6, SD_CLK, SPICLK, HS1_CLK :ref:`(See 1) ` , U1CTS -4 IO21 I/O | GPIO21, VSPIHD, EMAC_TX_EN -5 IO22 I/O | GPIO22, VSPIWP, U0RTS, EMAC_TXD1 -6 IO19 I/O | GPIO19, VSPIQ, U0CTS, EMAC_TXD0 -7 IO23 I/O | GPIO23, VSPID, HS1_STROBE -8 IO18 I/O | GPIO18, VSPICLK, HS1_DATA7 -9 IO5 I/O | GPIO5, VSPICS0, HS1_DATA6, EMAC_RX_CLK -10 IO10 I/O | GPIO10, SD_DATA3, SPIWP, HS1_DATA3, U1TXD -11 IO9 I/O | GPIO9, SD_DATA2, SPIHD, HS1_DATA2, U1RXD -12 RXD0 I/O | GPIO3, U0RXD :ref:`(See 3) ` , CLK_OUT2 -13 TXD0 I/O | GPIO1, U0TXD :ref:`(See 3) ` , CLK_OUT3, EMAC_RXD2 -14 IO35 I | ADC1_CH7, RTC_GPIO5 -15 IO34 I | ADC1_CH6, RTC_GPIO4 -16 IO38 I | GPIO38, ADC1_CH2, RTC_GPIO2 -17 IO37 I | GPIO37, ADC1_CH1, RTC_GPIO1 -18 EN I | CHIP_PU -19 GND P | Ground -20 VDD33 (3V3) P | 3.3V power supply -====== ================= ====== ====================================================== - - -Header J3 -""""""""" - -====== ================= ====== ====================================================== -No. Name Type Function -====== ================= ====== ====================================================== -1 FLASH_CS (FCS) I/O | GPIO16, HS1_DATA4 :ref:`(See 1) ` , U2RXD, EMAC_CLK_OUT -2 FLASH_SD0 (FSD0) I/O | GPIO17, HS1_DATA5 :ref:`(See 1) ` , U2TXD, EMAC_CLK_OUT_180 -3 FLASH_SD2 (FSD2) I/O | GPIO11, SD_CMD, SPICS0, HS1_CMD :ref:`(See 1) ` , U1RTS -4 SENSOR_VP (FSVP) I | GPIO36, ADC1_CH0, RTC_GPIO0 -5 SENSOR_VN (FSVN) I | GPIO39, ADC1_CH3, RTC_GPIO3 -6 IO25 I/O | GPIO25, DAC_1, ADC2_CH8, RTC_GPIO6, EMAC_RXD0 -7 IO26 I/O | GPIO26, DAC_2, ADC2_CH9, RTC_GPIO7, EMAC_RXD1 -8 IO32 I/O | 32K_XP :ref:`(See 2a) ` , ADC1_CH4, TOUCH9, RTC_GPIO9 -9 IO33 I/O | 32K_XN :ref:`(See 2b) ` , ADC1_CH5, TOUCH8, RTC_GPIO8 -10 IO27 I/O | GPIO27, ADC2_CH7, TOUCH7, RTC_GPIO17 - | EMAC_RX_DV -11 IO14 I/O | ADC2_CH6, TOUCH6, RTC_GPIO16, MTMS, HSPICLK, - | HS2_CLK, SD_CLK, EMAC_TXD2 -12 IO12 I/O | ADC2_CH5, TOUCH5, RTC_GPIO15, MTDI :ref:`(See 4) ` , HSPIQ, - | HS2_DATA2, SD_DATA2, EMAC_TXD3 -13 IO13 I/O | ADC2_CH4, TOUCH4, RTC_GPIO14, MTCK, HSPID, - | HS2_DATA3, SD_DATA3, EMAC_RX_ER -14 IO15 I/O | ADC2_CH3, TOUCH3, RTC_GPIO13, MTDO, HSPICS0 - | HS2_CMD, SD_CMD, EMAC_RXD3 -15 IO2 I/O | ADC2_CH2, TOUCH2, RTC_GPIO12, HSPIWP, - | HS2_DATA0, SD_DATA0 -16 IO4 I/O | ADC2_CH0, TOUCH0, RTC_GPIO10, HSPIHD, - | HS2_DATA1, SD_DATA1, EMAC_TX_ER -17 IO0 I/O | ADC2_CH1, TOUCH1, RTC_GPIO11, CLK_OUT1 - | EMAC_TX_CLK -18 VDD33 (3V3) P | 3.3V power supply -19 GND P | Ground -20 EXT_5V (5V) P | 5V power supply -====== ================= ====== ====================================================== - - -.. _get-started-pico-kit-v4-pin-notes: - -The following notes give more information about the items in the tables above. - - 1. This pin is connected to the flash pin of ESP32-PICO-D4. - 2. 32.768 kHz crystal oscillator: - a) input - b) output - 3. This pin is connected to the pin of the USB bridge chip on the board. - 4. The operating voltage of ESP32-PICO-KIT’s embedded SPI flash is 3.3V. Therefore, the strapping pin MTDI should hold bit zero during the module power-on reset. If connected, please make sure that this pin is not held up on reset. - - -Start Application Development ------------------------------ - -Before powering up your ESP32-PICO-KIT, please make sure that the board is in good condition with no obvious signs of damage. - -After that, proceed to :doc:`index`, where Section :ref:`get-started-step-by-step` will quickly help you set up the development environment and then flash an example project onto your board. - - -Board Dimensions ----------------- - -The dimensions are 52 x 20.3 x 10 mm (2.1" x 0.8" x 0.4"). - -.. figure:: ../../_static/esp32-pico-kit-v4.1-dimensions-back.jpg - :align: center - :alt: ESP32-PICO-KIT dimensions - back - :figclass: align-center - - ESP32-PICO-KIT dimensions - back - -.. figure:: ../../_static/esp32-pico-kit-v4-dimensions-side.jpg - :align: center - :alt: ESP32-PICO-KIT V4 dimensions - side - :figclass: align-center - - ESP32-PICO-KIT dimensions - side - -For the board physical construction details, please refer to its Reference Design listed below. - - -Related Documents ------------------ - -* `ESP32-PICO-KIT V4 schematic `_ (PDF) -* `ESP32-PICO-KIT V4.1 schematic `_ (PDF) -* `ESP32-PICO-KIT Reference Design `_ containing OrCAD schematic, PCB layout, gerbers and BOM -* `ESP32-PICO-D4 Datasheet `_ (PDF) -* :doc:`../hw-reference/index` - - -.. toctree:: - :hidden: - - get-started-pico-kit-v3 diff --git a/docs/en/get-started/get-started-wrover-kit-v2.rst b/docs/en/get-started/get-started-wrover-kit-v2.rst deleted file mode 100644 index 9f0b760b08..0000000000 --- a/docs/en/get-started/get-started-wrover-kit-v2.rst +++ /dev/null @@ -1,195 +0,0 @@ -ESP-WROVER-KIT V2 Getting Started Guide -======================================= -:link_to_translation:`zh_CN:[中文]` - -This guide shows how to get started with the ESP-WROVER-KIT V2 development board and also provides information about its functionality and configuration options. For the description of other ESP-WROVER-KIT versions, please check :doc:`../hw-reference/index`. - - -What You Need -------------- - -* ESP-WROVER-KIT V2 board -* USB 2.0 cable(A to Micro-B) -* Computer running Windows, Linux, or macOS - -You can skip the introduction sections and go directly to Section `Start Application Development`_. - - -Overview --------- - -ESP-WROVER-KIT is an ESP32-based development board produced by `Espressif `_. This board features an integrated LCD screen and MicroSD card slot. - -ESP-WROVER-KIT comes with the following ESP32 modules: - -- :ref:`esp-modules-and-boards-esp32-wroom-32` -- :ref:`ESP32-WROVER ` - -Its another distinguishing feature is the embedded FTDI FT2232HL chip - an advanced multi-interface USB bridge. This chip enables to use JTAG for direct debugging of ESP32 through the USB interface without a separate JTAG debugger. ESP-WROVER-KIT makes development convenient, easy, and cost-effective. - -Most of the ESP32 I/O pins are broken out to the board's pin headers for easy access. - - .. note:: - - The version with the ESP32-WROVER module uses ESP32's GPIO16 and GPIO17 as chip select and clock signals for PSRAM. By default, the two GPIOs are not broken out to the board's pin headers in order to ensure reliable performance. - - -Functionality Overview ----------------------- - -The block diagram below shows the main components of ESP-WROVER-KIT and their interconnections. - -.. figure:: ../../_static/esp-wrover-kit-block-diagram.png - :align: center - :alt: ESP-WROVER-KIT block diagram - :figclass: align-center - - ESP-WROVER-KIT block diagram - - -Functional Description ----------------------- - -The following two figures and the table below describe the key components, interfaces, and controls of the ESP-WROVER-KIT board. - -.. _get-started-esp-wrover-kit-v2-board-front: - -.. figure:: ../../_static/esp-wrover-kit-v2-layout-front.png - :align: center - :alt: ESP-WROVER-KIT board layout - front - :figclass: align-center - - ESP-WROVER-KIT board layout - front - -.. _get-started-esp-wrover-kit-v2-board-back: - -.. figure:: ../../_static/esp-wrover-kit-v2-layout-back.png - :align: center - :alt: ESP-WROVER-KIT board layout - back - :figclass: align-center - - ESP-WROVER-KIT board layout - back - - -The table below provides description in the following manner: - -- Starting from the first picture's top right corner and going clockwise -- Then moving on to the second picture - - -================== ================================================================================================================================= -Key Component Description -================== ================================================================================================================================= -32.768 kHz External precision 32.768 kHz crystal oscillator serves as a clock with low-power consumption while the chip is in Deep-sleep mode. - -ESP32 Module Either ESP32-WROOM-32 or ESP32-WROVER with an integrated ESP32. The ESP32-WROVER module features all the functions of ESP32-WROOM-32 and integrates an external 32-MBit PSRAM for flexible extended storage and data processing capabilities. - -CTS/RTS Serial port flow control signals: the pins are not connected to the circuitry by default. To enable them, short the respective pins of JP14 with jumpers. - -UART Serial port. The serial TX/RX signals of FT2232 and ESP32 are broken out to the inward and outward sides of JP11 respectively. By default, these pairs of pins are connected with jumpers. To use ESP32's serial interface, remove the jumpers and connect another external serial device to the respective pins. - -SPI By default, ESP32 uses its SPI interface to access flash and PSRAM memory inside the module. Use these pins to connect ESP32 to another SPI device. In this case, an extra chip select (CS) signal is needed. Please note that the interface voltage for the version with ESP32-WROVER is 1.8V, while that for the version with ESP32-WROOM-32 is 3.3V. - -JTAG JTAG interface. JTAG signals of FT2232 and ESP32 are broken out to the inward and outward sides of JP8 respectively. By default, these pairs of pins are disconnected. To enable JTAG, short the respective pins with jumpers as shown in Section `Setup Options`_. - -FT2232 The FT2232 chip serves as a multi-protocol USB-to-serial bridge which can be programmed and controlled via USB to provide communication with ESP32. FT2232 features USB-to-UART and USB-to-JTAG functionalities. - -EN Reset button. - -Boot Download button. Holding down **Boot** and then pressing **EN** initiates Firmware Download mode for downloading firmware through the serial port. - -USB USB interface. Power supply for the board as well as the communication interface between a computer and the board. - -Power Select Power supply selector interface. The board can be powered either via USB or via the 5V Input interface. Select the power source with a jumper. For more details, see Section `Setup Options`_, jumper header JP7. - -Power Key Power On/Off Switch. Toggling toward **USB** powers the board on, toggling away from **USB** powers the board off. - -5V Input The 5V power supply interface can be more convenient when the board is operating autonomously (not connected to a computer). - -LDO NCP1117(1A). 5V-to-3.3V LDO. NCP1117 can provide a maximum current of 1A. The LDO on the board has a fixed output voltage. Although, the user can install an LDO with adjustable output voltage. For details, please refer to `ESP-WROVER-KIT V2 schematic`_. - -Camera Camera interface, a standard OV7670 camera module. - -RGB Red, green and blue (RGB) light emitting diodes (LEDs), can be controlled by pulse width modulation (PWM). - -I/O All the pins on the ESP32 module are broken out to pin headers. You can program ESP32 to enable multiple functions, such as PWM, ADC, DAC, I2C, I2S, SPI, etc. - -MicroSD Card MicroSD card slot for data storage: when ESP32 enters the download mode, GPIO2 cannot be held high. However, a pull-up resistor is required on GPIO2 to enable the MicroSD Card. By default, GPIO2 and the pull-up resistor R153 are disconnected. To enable the SD Card, use jumpers on JP1 as shown in Section `Setup Options`_. - -LCD Support for mounting and interfacing a 3.2” SPI (standard 4-wire Serial Peripheral Interface) LCD, as shown on figure :ref:`get-started-esp-wrover-kit-v2-board-back`. -================== ================================================================================================================================= - - -.. _get-started-esp-wrover-kit-v2-setup-options: - -Setup Options -------------- - -There are five jumper blocks available to set up the board functionality. The most frequently required options are listed in the table below. - -======= ================ ========================================================= -Header Jumper Setting Description of Functionality -======= ================ ========================================================= -JP1 |jp1-sd_io2| Enable pull up for the MicroSD Card -JP1 |jp1-both| Assert GPIO2 low during each download (by jumping it to GPIO0) -JP7 |jp7-ext_5v| Power ESP-WROVER-KIT via an external power supply -JP7 |jp7-usb_5v| Power ESP-WROVER-KIT via USB -JP8 |jp8| Enable JTAG functionality -JP11 |jp11-tx-rx| Enable UART communication -JP14 |jp14| Enable RTS/CTS flow control for serial communication -======= ================ ========================================================= - - -.. _get-started-esp-wrover-kit-v2-start-development: - -Start Application Development ------------------------------ - -Before powering up your ESP-WROVER-KIT, please make sure that the board is in good condition with no obvious signs of damage. - - -Initial Setup -^^^^^^^^^^^^^ - -Please set only the following jumpers shown in the pictures below: - -- Select USB as the power source using the jumper block JP7. - -- Enable UART communication using the jumper block JP11. - -======================== ========================== -Power up from USB port Enable UART communication -======================== ========================== -|jp7-usb_5v| |jp11-tx-rx| -======================== ========================== - -Do not install any other jumpers. - -Turn the **Power Switch** to ON, the **5V Power On LED** should light up. - -Now to Development -^^^^^^^^^^^^^^^^^^ - -Please proceed to :doc:`index`, where Section :ref:`get-started-step-by-step` will quickly help you set up the development environment and then flash an example project onto your board. - - -Related Documents ------------------ - -* `ESP-WROVER-KIT V2 schematic`_ (PDF) -* `ESP32 Datasheet `_ (PDF) -* `ESP32-WROVER Datasheet `_ (PDF) -* `ESP32-WROOM-32 Datasheet `_ (PDF) -* :doc:`../api-guides/jtag-debugging/index` -* :doc:`../hw-reference/index` - - -.. |jp1-sd_io2| image:: ../../_static/wrover-jp1-sd_io2.png -.. |jp1-both| image:: ../../_static/wrover-jp1-both.png -.. |jp7-ext_5v| image:: ../../_static/wrover-jp7-ext_5v.png -.. |jp7-usb_5v| image:: ../../_static/wrover-jp7-usb_5v.png -.. |jp8| image:: ../../_static/wrover-jp8.png -.. |jp11-tx-rx| image:: ../../_static/wrover-jp11-tx-rx.png -.. |jp14| image:: ../../_static/wrover-jp14.png - -.. _ESP-WROVER-KIT V2 schematic: https://dl.espressif.com/dl/schematics/ESP-WROVER-KIT_SCH-2.pdf \ No newline at end of file diff --git a/docs/en/get-started/get-started-wrover-kit-v3.rst b/docs/en/get-started/get-started-wrover-kit-v3.rst deleted file mode 100644 index 4f290a3bf0..0000000000 --- a/docs/en/get-started/get-started-wrover-kit-v3.rst +++ /dev/null @@ -1,381 +0,0 @@ - -ESP-WROVER-KIT V3 Getting Started Guide -======================================= -:link_to_translation:`zh_CN:[中文]` - -This guide shows how to get started with the ESP-WROVER-KIT V3 development board and also provides information about its functionality and configuration options. For the description of other ESP-WROVER-KIT versions, please check :doc:`../hw-reference/index`. - - -What You Need -------------- - -* :ref:`ESP-WROVER-KIT V3 board ` -* USB 2.0 cable(A to Micro-B) -* Computer running Windows, Linux, or macOS - -You can skip the introduction sections and go directly to Section `Start Application Development`_. - - -Overview --------- - -ESP-WROVER-KIT is an ESP32-based development board produced by `Espressif `_. This board features an integrated LCD screen and MicroSD card slot. - -ESP-WROVER-KIT comes with the following ESP32 modules: - -- :ref:`esp-modules-and-boards-esp32-wroom-32` -- :ref:`ESP32-WROVER ` - -Its another distinguishing feature is the embedded FTDI FT2232HL chip - an advanced multi-interface USB bridge. This chip enables to use JTAG for direct debugging of ESP32 through the USB interface without a separate JTAG debugger. ESP-WROVER-KIT makes development convenient, easy, and cost-effective. - -Most of the ESP32 I/O pins are broken out to the board's pin headers for easy access. - - .. note:: - - The version with the ESP32-WROVER module uses ESP32's GPIO16 and GPIO17 as chip select and clock signals for PSRAM. By default, the two GPIOs are not broken out to the board's pin headers in order to ensure reliable performance. - - -Functionality Overview ----------------------- - -The block diagram below shows the main components of ESP-WROVER-KIT and their interconnections. - -.. figure:: ../../_static/esp-wrover-kit-block-diagram.png - :align: center - :alt: ESP-WROVER-KIT block diagram - :figclass: align-center - - ESP-WROVER-KIT block diagram - - -Functional Description ----------------------- - -The following two figures and the table below describe the key components, interfaces, and controls of the ESP-WROVER-KIT board. - -.. _get-started-esp-wrover-kit-v3-board-front: - -.. figure:: ../../_static/esp-wrover-kit-v3-layout-front.jpg - :align: center - :alt: ESP-WROVER-KIT board layout - front - :figclass: align-center - - ESP-WROVER-KIT board layout - front - -.. _get-started-esp-wrover-kit-v3-board-back: - -.. figure:: ../../_static/esp-wrover-kit-v3-layout-back.jpg - :align: center - :alt: ESP-WROVER-KIT board layout - back - :figclass: align-center - - ESP-WROVER-KIT board layout - back - - -The table below provides description in the following manner: - -- Starting from the first picture's top right corner and going clockwise -- Then moving on to the second picture - - -================== ================================================================================================================================= -Key Component Description -================== ================================================================================================================================= -32.768 kHz External precision 32.768 kHz crystal oscillator serves as a clock with low-power consumption while the chip is in Deep-sleep mode. - -0R Zero-ohm resistor intended as a placeholder for a current shunt, can be desoldered or replaced with a current shunt to facilitate the measurement of ESP32's current consumption in different modes. - -ESP32 Module Either ESP32-WROOM-32 or ESP32-WROVER with an integrated ESP32. The ESP32-WROVER module features all the functions of ESP32-WROOM-32 and integrates an external 32-MBit PSRAM for flexible extended storage and data processing capabilities. - -FT2232 The FT2232 chip serves as a multi-protocol USB-to-serial bridge which can be programmed and controlled via USB to provide communication with ESP32. FT2232 also features USB-to-JTAG interface which is available on channel A of the chip, while USB-to-serial is on channel B. The FT2232 chip enhances user-friendliness in terms of application development and debugging. See `ESP-WROVER-KIT V3 schematic`_. - -UART Serial port. The serial TX/RX signals of FT2232 and ESP32 are broken out to the inward and outward sides of JP11 respectively. By default, these pairs of pins are connected with jumpers. To use ESP32's serial interface, remove the jumpers and connect another external serial device to the respective pins. - -SPI By default, ESP32 uses its SPI interface to access flash and PSRAM memory inside the module. Use these pins to connect ESP32 to another SPI device. In this case, an extra chip select (CS) signal is needed. Please note that the interface voltage for the version with ESP32-WROVER is 1.8V, while that for the version with ESP32-WROOM-32 is 3.3V. - -CTS/RTS Serial port flow control signals: the pins are not connected to the circuitry by default. To enable them, short the respective pins of JP14 with jumpers. - -JTAG JTAG interface. JTAG signals of FT2232 and ESP32 are broken out to the inward and outward sides of JP8 respectively. By default, these pairs of pins are disconnected. To enable JTAG, short the respective pins with jumpers as shown in Section `Setup Options`_. - -EN Reset button. - -Boot Download button. Holding down **Boot** and then pressing **EN** initiates Firmware Download mode for downloading firmware through the serial port. - -USB USB interface. Power supply for the board as well as the communication interface between a computer and the board. - -Power Key Power On/Off Switch. Toggling toward **USB** powers the board on, toggling away from **USB** powers the board off. - -Power Select Power supply selector interface. The board can be powered either via USB or via the 5V Input interface. Select the power source with a jumper. For more details, see Section `Setup Options`_, jumper header JP7. - -5V Input The 5V power supply interface can be more convenient when the board is operating autonomously (not connected to a computer). - -LDO NCP1117(1A). 5V-to-3.3V LDO. NCP1117 can provide a maximum current of 1A. The LDO on the board has a fixed output voltage. Although, the user can install an LDO with adjustable output voltage. For details, please refer to `ESP-WROVER-KIT V3 schematic`_. - -Camera Camera interface, a standard OV7670 camera module. - -RGB LED Red, green and blue (RGB) light emitting diodes (LEDs), can be controlled by pulse width modulation (PWM). - -I/O All the pins on the ESP32 module are broken out to pin headers. You can program ESP32 to enable multiple functions, such as PWM, ADC, DAC, I2C, I2S, SPI, etc. - -MicroSD Card Slot Useful for developing applications that access MicroSD card for data storage and retrieval. - -LCD Support for mounting and interfacing a 3.2” SPI (standard 4-wire Serial Peripheral Interface) LCD, as shown on figure :ref:`get-started-esp-wrover-kit-v3-board-back`. -================== ================================================================================================================================= - - -.. _get-started-esp-wrover-kit-v3-setup-options: - -Setup Options -------------- - -There are five jumper blocks available to set up the board functionality. The most frequently required options are listed in the table below. - -======= ================ ========================================================= -Header Jumper Setting Description of Functionality -======= ================ ========================================================= -JP7 |jp7-ext_5v| Power ESP-WROVER-KIT via an external power supply -JP7 |jp7-usb_5v| Power ESP-WROVER-KIT via USB -JP8 |jp8| Enable JTAG functionality -JP11 |jp11-tx-rx| Enable UART communication -JP14 |jp14| Enable RTS/CTS flow control for serial communication -======= ================ ========================================================= - - -Allocation of ESP32 Pins ------------------------- - -Some pins / terminals of ESP32 are allocated for use with the onboard or external hardware. If that hardware is not used, e.g., nothing is plugged into the Camera (JP4) header, then these GPIOs can be used for other purposes. - -Some of the pins, such as GPIO0 or GPIO2, have multiple functions and some of them are shared among onboard and external peripheral devices. Certain combinations of peripherals cannot work together. For example, it is not possible to do JTAG debugging of an application that is using SD card, because several pins are shared by JTAG and the SD card slot. - -In other cases, peripherals can coexist under certain conditions. This is applicable to, for example, LCD screen and SD card that share only a single pin GPIO21. This pin is used to provide D/C (Data / Control) signal for the LCD as well as the CD (Card Detect) signal read from the SD card slot. If the card detect functionality is not essential, then it may be disabled by removing R167, so both LCD and SD may operate together. - -For more details on which pins are shared among which peripherals, please refer to the table in the next section. - - -Main I/O Connector / JP1 -^^^^^^^^^^^^^^^^^^^^^^^^ - -The JP1 connector consists of 14x2 male pins whose functions are shown in the middle two "I/O" columns of the table below. The two "Shared With" columns on both sides describe where else on the board a certain GPIO is used. - -===================== ===== ===== ===================== -Shared With I/O I/O Shared With -===================== ===== ===== ===================== -n/a 3.3V GND n/a -NC/XTAL IO32 IO33 NC/XTAL -JTAG, MicroSD IO12 IO13 JTAG, MicroSD -JTAG, MicroSD IO14 IO27 Camera -Camera IO26 IO25 Camera, LCD -Camera IO35 IO34 Camera -Camera IO39 IO36 Camera -JTAG EN IO23 Camera, LCD -Camera, LCD IO22 IO21 Camera, LCD, MicroSD -Camera, LCD IO19 IO18 Camera, LCD -Camera, LCD IO5 IO17 PSRAM -PSRAM IO16 IO4 LED, Camera, MicroSD -Camera, LED, Boot IO0 IO2 LED, MicroSD -JTAG, MicroSD IO15 5V -===================== ===== ===== ===================== - -Legend: - -* NC/XTAL - :ref:`32.768 kHz Oscillator ` -* JTAG - :ref:`JTAG / JP8 ` -* Boot - Boot button / SW2 -* Camera - :ref:`Camera / JP4 ` -* LED - :ref:`RGB LED ` -* MicroSD - :ref:`MicroSD Card / J4 ` -* LCD - :ref:`LCD / U5 ` -* PSRAM - only in case ESP32-WROVER is installed - - -.. _get-started-esp-wrover-kit-v3-xtal: - -32.768 kHz Oscillator -^^^^^^^^^^^^^^^^^^^^^ - -==== ========== -. ESP32 Pin -==== ========== -1 GPIO32 -2 GPIO33 -==== ========== - -.. note:: - - Since GPIO32 and GPIO33 are connected to the oscillator by default, they are not connected to the JP1 I/O connector to maintain signal integrity. This allocation may be changed from the oscillator to JP1 by desoldering the zero-ohm resistors from positions R11 / R23 and re-soldering them to positions R12 / R24. - - -.. _get-started-esp-wrover-kit-v3-spi-flash-header: - -SPI Flash / JP13 -^^^^^^^^^^^^^^^^ - -==== ============= -. ESP32 Pin -==== ============= -1 CLK / GPIO6 -2 SD0 / GPIO7 -3 SD1 / GPIO8 -4 SD2 / GPIO9 -5 SD3 / GPIO10 -6 CMD / GPIO11 -==== ============= - -.. important:: - - The module's flash bus is connected to the jumper block JP13 through zero-ohm resistors R140 ~ R145. If the flash memory needs to operate at the frequency of 80 MHz, for reasons such as improving the integrity of bus signals, you can desolder these resistors to disconnect the module's flash bus from the pin header JP13. - - -.. _get-started-esp-wrover-kit-v3-jtag-header: - -JTAG / JP8 -^^^^^^^^^^ - -==== ============== ============= -. ESP32 Pin JTAG Signal -==== ============== ============= -1 EN TRST_N -2 MTMS / GPIO14 TMS -3 MTDO / GPIO15 TDO -4 MTDI / GPIO12 TDI -5 MTCK / GPIO13 TCK -==== ============== ============= - - -.. _get-started-esp-wrover-kit-v3-camera-header: - -Camera / JP4 -^^^^^^^^^^^^ - -==== ========== ============================= -. ESP32 Pin Camera Signal -==== ========== ============================= - 1 n/a 3.3V - 2 n/a Ground - 3 GPIO27 SIO_C / SCCB Clock - 4 GPIO26 SIO_D / SCCB Data - 5 GPIO25 VSYNC / Vertical Sync - 6 GPIO23 HREF / Horizontal Reference - 7 GPIO22 PCLK / Pixel Clock - 8 GPIO21 XCLK / System Clock - 9 GPIO35 D7 / Pixel Data Bit 7 -10 GPIO34 D6 / Pixel Data Bit 6 -11 GPIO39 D5 / Pixel Data Bit 5 -12 GPIO36 D4 / Pixel Data Bit 4 -13 GPIO19 D3 / Pixel Data Bit 3 -14 GPIO18 D2 / Pixel Data Bit 2 -15 GPIO5 D1 / Pixel Data Bit 1 -16 GPIO4 D0 / Pixel Data Bit 0 -17 GPIO0 RESET / Camera Reset -18 n/a PWDN / Camera Power Down -==== ========== ============================= - -* Signals D0 .. D7 denote camera data bus - - -.. _get-started-esp-wrover-kit-v3-rgb-led-connections: - -RGB LED -^^^^^^^ - -==== ========== ========= -. ESP32 Pin RGB LED -==== ========== ========= -1 GPIO0 Red -2 GPIO2 Green -3 GPIO4 Blue -==== ========== ========= - - -.. _get-started-esp-wrover-kit-v3-microsd-card-slot: - -MicroSD Card -^^^^^^^^^^^^ - -==== ============== =============== -. ESP32 Pin MicroSD Signal -==== ============== =============== -1 MTDI / GPIO12 DATA2 -2 MTCK / GPIO13 CD / DATA3 -3 MTDO / GPIO15 CMD -4 MTMS / GPIO14 CLK -5 GPIO2 DATA0 -6 GPIO4 DATA1 -7 GPIO21 CD -==== ============== =============== - - -.. _get-started-esp-wrover-kit-v3-lcd-connector: - -LCD / U5 -^^^^^^^^ - -==== ============== =============== -. ESP32 Pin LCD Signal -==== ============== =============== -1 GPIO18 RESET -2 GPIO19 SCL -3 GPIO21 D/C -4 GPIO22 CS -5 GPIO23 SDA -6 GPIO25 SDO -7 GPIO5 Backlight -==== ============== =============== - - -.. _get-started-esp-wrover-kit-v3-start-development: - -Start Application Development ------------------------------ - -Before powering up your ESP-WROVER-KIT, please make sure that the board is in good condition with no obvious signs of damage. - - -Initial Setup -^^^^^^^^^^^^^ - -Please set only the following jumpers shown in the pictures below: - -- Select USB as the power source using the jumper block JP7. - -- Enable UART communication using the jumper block JP11. - -======================== ========================== -Power up from USB port Enable UART communication -======================== ========================== -|jp7-usb_5v| |jp11-tx-rx| -======================== ========================== - -Do not install any other jumpers. - -Turn the **Power Switch** to ON, the **5V Power On LED** should light up. - -Now to Development -^^^^^^^^^^^^^^^^^^ - -Please proceed to :doc:`index`, where Section :ref:`get-started-step-by-step` will quickly help you set up the development environment and then flash an example project onto your board. - - -Related Documents ------------------ - -* `ESP-WROVER-KIT V3 schematic`_ (PDF) -* `ESP32 Datasheet `_ (PDF) -* `ESP32-WROVER Datasheet `_ (PDF) -* `ESP32-WROOM-32 Datasheet `_ (PDF) -* :doc:`../api-guides/jtag-debugging/index` -* :doc:`../hw-reference/index` - -.. |jp7-ext_5v| image:: ../../_static/esp-wrover-kit-v3-jp7-ext_5v.png -.. |jp7-usb_5v| image:: ../../_static/esp-wrover-kit-v3-jp7-usb_5v.png -.. |jp8| image:: ../../_static/esp-wrover-kit-v3-jp8.png -.. |jp11-tx-rx| image:: ../../_static/esp-wrover-kit-v3-jp11-tx-rx.png -.. |jp14| image:: ../../_static/esp-wrover-kit-v3-jp14.png - -.. _ESP-WROVER-KIT V3 schematic: https://dl.espressif.com/dl/schematics/ESP-WROVER-KIT_SCH-3.pdf - -.. toctree:: - :hidden: - - get-started-wrover-kit-v2.rst \ No newline at end of file diff --git a/docs/en/get-started/get-started-wrover-kit.rst b/docs/en/get-started/get-started-wrover-kit.rst deleted file mode 100644 index c1bd14cb0f..0000000000 --- a/docs/en/get-started/get-started-wrover-kit.rst +++ /dev/null @@ -1,385 +0,0 @@ -ESP-WROVER-KIT V4.1 Getting Started Guide -========================================= -:link_to_translation:`zh_CN:[中文]` - -This guide shows how to get started with the ESP-WROVER-KIT V4.1 development board and also provides information about its functionality and configuration options. For the description of other ESP-WROVER-KIT versions, please check :doc:`../hw-reference/index`. - - -What You Need -------------- - -* :ref:`ESP-WROVER-KIT V4.1 board ` -* USB 2.0 cable(A to Micro-B) -* Computer running Windows, Linux, or macOS - -You can skip the introduction sections and go directly to Section `Start Application Development`_. - - -Overview --------- - -ESP-WROVER-KIT is an ESP32-based development board produced by `Espressif `_. - -ESP-WROVER-KIT features the following integrated components: - -- ESP32-WROVER-B module -- LCD screen -- MicroSD card slot - -Its another distinguishing feature is the embedded FTDI FT2232HL chip - an advanced multi-interface USB bridge. This chip enables to use JTAG for direct debugging of ESP32 through the USB interface without a separate JTAG debugger. ESP-WROVER-KIT makes development convenient, easy, and cost-effective. - -Most of the ESP32 I/O pins are broken out to the board's pin headers for easy access. - - .. note:: - - ESP32's GPIO16 and GPIO17 are used as chip select and clock signals for PSRAM. By default, the two GPIOs are not broken out to the board's pin headers in order to ensure reliable performance. - - -Functionality Overview ----------------------- - -The block diagram below shows the main components of ESP-WROVER-KIT and their interconnections. - -.. figure:: ../../_static/esp-wrover-kit-block-diagram.png - :align: center - :alt: ESP-WROVER-KIT block diagram - :figclass: align-center - - ESP-WROVER-KIT block diagram - - -Functional Description ----------------------- - -The following two figures and the table below describe the key components, interfaces, and controls of the ESP-WROVER-KIT board. - -.. _get-started-esp-wrover-kit-v4.1-board-front: - -.. figure:: ../../_static/esp-wrover-kit-v4.1-layout-front.png - :align: center - :alt: ESP-WROVER-KIT board layout - front - :figclass: align-center - - ESP-WROVER-KIT board layout - front - -.. _get-started-esp-wrover-kit-v4.1-board-back: - -.. figure:: ../../_static/esp-wrover-kit-v4.1-layout-back.png - :align: center - :alt: ESP-WROVER-KIT board layout - back - :figclass: align-center - - ESP-WROVER-KIT board layout - back - - -The table below provides description in the following manner: - -- Starting from the first picture's top right corner and going clockwise -- Then moving on to the second picture - - -================== ================================================================================================================================= -Key Component Description -================== ================================================================================================================================= -FT2232 The FT2232 chip serves as a multi-protocol USB-to-serial bridge which can be programmed and controlled via USB to provide communication with ESP32. FT2232 also features USB-to-JTAG interface which is available on channel A of the chip, while USB-to-serial is on channel B. The FT2232 chip enhances user-friendliness in terms of application development and debugging. See `ESP-WROVER-KIT V4.1 schematic`_. - -32.768 kHz External precision 32.768 kHz crystal oscillator serves as a clock with low-power consumption while the chip is in Deep-sleep mode. - -0R Zero-ohm resistor intended as a placeholder for a current shunt, can be desoldered or replaced with a current shunt to facilitate the measurement of ESP32's current consumption in different modes. - -ESP32-WROVER-B This EPS32 module features 64-Mbit PSRAM for flexible extended storage and data processing capabilities. - -Diagnostic LEDs Four red LEDs connected to the GPIO pins of FT2232. Intended for future use. - -UART Serial port. The serial TX/RX signals of FT2232 and ESP32 are broken out to the inward and outward sides of JP2 respectively. By default, these pairs of pins are connected with jumpers. To use ESP32's serial interface, remove the jumpers and connect another external serial device to the respective pins. - -SPI By default, ESP32 uses its SPI interface to access flash and PSRAM memory inside the module. Use these pins to connect ESP32 to another SPI device. In this case, an extra chip select (CS) signal is needed. Please note that the voltage of this interface is 3.3V. - -CTS/RTS Serial port flow control signals: the pins are not connected to the circuitry by default. To enable them, short the respective pins of JP14 with jumpers. - -JTAG JTAG interface. JTAG signals of FT2232 and ESP32 are broken out to the inward and outward sides of JP2 respectively. By default, these pairs of pins are disconnected. To enable JTAG, short the respective pins with jumpers as shown in Section `Setup Options`_. - -USB Port USB interface. Power supply for the board as well as the communication interface between a computer and the board. - -EN Button Reset button. - -Boot Button Download button. Holding down **Boot** and then pressing **EN** initiates Firmware Download mode for downloading firmware through the serial port. - -Power Switch Power On/Off Switch. Toggling toward the **Boot** button powers the board on, toggling away from **Boot** powers the board off. - -Power Selector Power supply selector interface. The board can be powered either via USB or via the 5V Input interface. Select the power source with a jumper. For more details, see Section `Setup Options`_, jumper header JP7. - -5V Input The 5V power supply interface can be more convenient when the board is operating autonomously (not connected to a computer). - -5V Power On LED This red LED turns on when power is supplied to the board, either from **USB** or **5V Input**. - -LDO NCP1117(1A). 5V-to-3.3V LDO. NCP1117 can provide a maximum current of 1A. The LDO on the board has a fixed output voltage. Although, the user can install an LDO with adjustable output voltage. For details, please refer to `ESP-WROVER-KIT V4.1 schematic`_. - -Camera Connector Camera interface, a standard OV7670 camera module. - -RGB LED Red, green and blue (RGB) light emitting diodes (LEDs), can be controlled by pulse width modulation (PWM). - -I/O Connector All the pins on the ESP32 module are broken out to pin headers. You can program ESP32 to enable multiple functions, such as PWM, ADC, DAC, I2C, I2S, SPI, etc. - -MicroSD Card Slot Useful for developing applications that access MicroSD card for data storage and retrieval. - -LCD Support for mounting and interfacing a 3.2” SPI (standard 4-wire Serial Peripheral Interface) LCD, as shown on figure :ref:`get-started-esp-wrover-kit-v4.1-board-back`. -================== ================================================================================================================================= - - -.. _get-started-esp-wrover-kit-v4.1-setup-options: - -Setup Options -------------- - -There are three jumper blocks available to set up the board functionality. The most frequently required options are listed in the table below. - -======= ================ ========================================================= -Header Jumper Setting Description of Functionality -======= ================ ========================================================= -JP7 |jp7-ext_5v| Power ESP-WROVER-KIT via an external power supply -JP7 |jp7-usb_5v| Power ESP-WROVER-KIT via USB -JP2 |jp2-jtag| Enable JTAG functionality -JP2 |jp2-tx-rx| Enable UART communication -JP14 |jp14| Enable RTS/CTS flow control for serial communication -======= ================ ========================================================= - - -Allocation of ESP32 Pins ------------------------- - -Some pins / terminals of ESP32 are allocated for use with the onboard or external hardware. If that hardware is not used, e.g., nothing is plugged into the Camera (JP4) header, then these GPIOs can be used for other purposes. - -Some of the pins, such as GPIO0 or GPIO2, have multiple functions and some of them are shared among onboard and external peripheral devices. Certain combinations of peripherals cannot work together. For example, it is not possible to do JTAG debugging of an application that is using SD card, because several pins are shared by JTAG and the SD card slot. - -In other cases, peripherals can coexist under certain conditions. This is applicable to, for example, LCD screen and SD card that share only a single pin GPIO21. This pin is used to provide D/C (Data / Control) signal for the LCD as well as the CD (Card Detect) signal read from the SD card slot. If the card detect functionality is not essential, then it may be disabled by removing R167, so both LCD and SD may operate together. - -For more details on which pins are shared among which peripherals, please refer to the table in the next section. - - -Main I/O Connector / JP1 -^^^^^^^^^^^^^^^^^^^^^^^^ - -The JP1 connector consists of 14x2 male pins whose functions are shown in the middle two "I/O" columns of the table below. The two "Shared With" columns on both sides describe where else on the board a certain GPIO is used. - -===================== ===== ===== ===================== -Shared With I/O I/O Shared With -===================== ===== ===== ===================== -n/a 3.3V GND n/a -NC/XTAL IO32 IO33 NC/XTAL -JTAG, MicroSD IO12 IO13 JTAG, MicroSD -JTAG, MicroSD IO14 IO27 Camera -Camera IO26 IO25 Camera, LCD -Camera IO35 IO34 Camera -Camera IO39 IO36 Camera -JTAG EN IO23 Camera, LCD -Camera, LCD IO22 IO21 Camera, LCD, MicroSD -Camera, LCD IO19 IO18 Camera, LCD -Camera, LCD IO5 IO17 PSRAM -PSRAM IO16 IO4 LED, Camera, MicroSD -Camera, LED, Boot IO0 IO2 LED, MicroSD -JTAG, MicroSD IO15 5V -===================== ===== ===== ===================== - -Legend: - -* NC/XTAL - :ref:`32.768 kHz Oscillator ` -* JTAG - :ref:`JTAG / JP8 ` -* Boot - Boot button / SW2 -* Camera - :ref:`Camera / JP4 ` -* LED - :ref:`RGB LED ` -* MicroSD - :ref:`MicroSD Card / J4 ` -* LCD - :ref:`LCD / U5 ` -* PSRAM - ESP32-WROVER-B's PSRAM - - -.. _get-started-esp-wrover-kit-v4.1-xtal: - -32.768 kHz Oscillator -^^^^^^^^^^^^^^^^^^^^^ - -==== ========== -. ESP32 Pin -==== ========== -1 GPIO32 -2 GPIO33 -==== ========== - -.. note:: - - Since GPIO32 and GPIO33 are connected to the oscillator by default, they are not connected to the JP1 I/O connector to maintain signal integrity. This allocation may be changed from the oscillator to JP1 by desoldering the zero-ohm resistors from positions R11 / R23 and re-soldering them to positions R12 / R24. - - -.. _get-started-esp-wrover-kit-v4.1-spi-flash-header: - -SPI Flash / JP2 -^^^^^^^^^^^^^^^ - -==== ============= -. ESP32 Pin -==== ============= -1 CLK / GPIO6 -2 SD0 / GPIO7 -3 SD1 / GPIO8 -4 SD2 / GPIO9 -5 SD3 / GPIO10 -6 CMD / GPIO11 -==== ============= - -.. important:: - - The module's flash bus is connected to the jumper block JP2 through zero-ohm resistors R140 ~ R145. If the flash memory needs to operate at the frequency of 80 MHz, for reasons such as improving the integrity of bus signals, you can desolder these resistors to disconnect the module's flash bus from the pin header JP2. - - -.. _get-started-esp-wrover-kit-v4.1-jtag-header: - -JTAG / JP2 -^^^^^^^^^^ - -==== ============== ============= -. ESP32 Pin JTAG Signal -==== ============== ============= -1 EN TRST_N -2 MTMS / GPIO14 TMS -3 MTDO / GPIO15 TDO -4 MTDI / GPIO12 TDI -5 MTCK / GPIO13 TCK -==== ============== ============= - - -.. _get-started-esp-wrover-kit-v4.1-camera-header: - -Camera / JP4 -^^^^^^^^^^^^ - -==== ========== ============================= -. ESP32 Pin Camera Signal -==== ========== ============================= - 1 n/a 3.3V - 2 n/a Ground - 3 GPIO27 SIO_C / SCCB Clock - 4 GPIO26 SIO_D / SCCB Data - 5 GPIO25 VSYNC / Vertical Sync - 6 GPIO23 HREF / Horizontal Reference - 7 GPIO22 PCLK / Pixel Clock - 8 GPIO21 XCLK / System Clock - 9 GPIO35 D7 / Pixel Data Bit 7 -10 GPIO34 D6 / Pixel Data Bit 6 -11 GPIO39 D5 / Pixel Data Bit 5 -12 GPIO36 D4 / Pixel Data Bit 4 -13 GPIO19 D3 / Pixel Data Bit 3 -14 GPIO18 D2 / Pixel Data Bit 2 -15 GPIO5 D1 / Pixel Data Bit 1 -16 GPIO4 D0 / Pixel Data Bit 0 -17 GPIO0 RESET / Camera Reset -18 n/a PWDN / Camera Power Down -==== ========== ============================= - -* Signals D0 .. D7 denote camera data bus - - -.. _get-started-esp-wrover-kit-v4.1-rgb-led-connections: - -RGB LED -^^^^^^^ - -==== ========== ========= -. ESP32 Pin RGB LED -==== ========== ========= -1 GPIO0 Red -2 GPIO2 Green -3 GPIO4 Blue -==== ========== ========= - - -.. _get-started-esp-wrover-kit-v4.1-microsd-card-slot: - -MicroSD Card -^^^^^^^^^^^^ - -==== ============== =============== -. ESP32 Pin MicroSD Signal -==== ============== =============== -1 MTDI / GPIO12 DATA2 -2 MTCK / GPIO13 CD / DATA3 -3 MTDO / GPIO15 CMD -4 MTMS / GPIO14 CLK -5 GPIO2 DATA0 -6 GPIO4 DATA1 -7 GPIO21 CD -==== ============== =============== - - -.. _get-started-esp-wrover-kit-v4.1-lcd-connector: - -LCD / U5 -^^^^^^^^ - -==== ============== =============== -. ESP32 Pin LCD Signal -==== ============== =============== -1 GPIO18 RESET -2 GPIO19 SCL -3 GPIO21 D/C -4 GPIO22 CS -5 GPIO23 SDA -6 GPIO25 SDO -7 GPIO5 Backlight -==== ============== =============== - - -.. _get-started-esp-wrover-kit-start-development: - -Start Application Development ------------------------------ - -Before powering up your ESP-WROVER-KIT, please make sure that the board is in good condition with no obvious signs of damage. - - -Initial Setup -^^^^^^^^^^^^^ - -Please set only the following jumpers shown in the pictures below: - -- Select USB as the power source using the jumper block JP7. - -- Enable UART communication using the jumper block JP2. - -======================== ========================== -Power up from USB port Enable UART communication -======================== ========================== -|jp7-usb_5v| |jp2-tx-rx| -======================== ========================== - -Do not install any other jumpers. - -Turn the **Power Switch** to ON, the **5V Power On LED** should light up. - -Now to Development -^^^^^^^^^^^^^^^^^^ - -Please proceed to :doc:`index`, where Section :ref:`get-started-step-by-step` will quickly help you set up the development environment and then flash an example project onto your board. - - -Related Documents ------------------ - -* `ESP-WROVER-KIT V4.1 schematic`_ (PDF) -* `ESP32 Datasheet `_ (PDF) -* `ESP32-WROVER-B Datasheet `_ (PDF) -* :doc:`../api-guides/jtag-debugging/index` -* :doc:`../hw-reference/index` - -.. |jp7-ext_5v| image:: ../../_static/esp-wrover-kit-v4.1-jp7-ext_5v.jpg -.. |jp7-usb_5v| image:: ../../_static/esp-wrover-kit-v4.1-jp7-usb_5v.jpg -.. |jp2-jtag| image:: ../../_static/esp-wrover-kit-v4.1-jp2-jtag.jpg -.. |jp2-tx-rx| image:: ../../_static/esp-wrover-kit-v4.1-jp2-tx-rx.jpg -.. |jp14| image:: ../../_static/esp-wrover-kit-v4.1-jp14.jpg - -.. _ESP-WROVER-KIT V4.1 schematic: https://dl.espressif.com/dl/schematics/ESP-WROVER-KIT_V4_1.pdf - -.. toctree:: - :hidden: - - get-started-wrover-kit-v3.rst - get-started-wrover-kit-v2.rst \ No newline at end of file diff --git a/docs/en/get-started/index.rst b/docs/en/get-started/index.rst index 12ab81c020..ffcc6f0797 100644 --- a/docs/en/get-started/index.rst +++ b/docs/en/get-started/index.rst @@ -57,9 +57,9 @@ If you have one of ESP32 development boards listed below, you can click on the l .. toctree:: :maxdepth: 1 - ESP32-DevKitC - ESP-WROVER-KIT - ESP32-PICO-KIT + ESP32-DevKitC <../hw-reference/get-started-devkitc> + ESP-WROVER-KIT <../hw-reference/get-started-wrover-kit> + ESP32-PICO-KIT <../hw-reference/get-started-pico-kit> ESP32-Ethernet-Kit <../hw-reference/get-started-ethernet-kit> diff --git a/docs/en/get-started-cmake/get-started-devkitc-v2.rst b/docs/en/hw-reference/get-started-devkitc-v2.rst similarity index 91% rename from docs/en/get-started-cmake/get-started-devkitc-v2.rst rename to docs/en/hw-reference/get-started-devkitc-v2.rst index 977c3a455d..2b558f6e91 100644 --- a/docs/en/get-started-cmake/get-started-devkitc-v2.rst +++ b/docs/en/hw-reference/get-started-devkitc-v2.rst @@ -1,4 +1,4 @@ -ESP32-DevKitC V2 Getting Started Guide (CMake) +ESP32-DevKitC V2 Getting Started Guide ============================================== :link_to_translation:`zh_CN:[中文]` @@ -71,7 +71,9 @@ Start Application Development Before powering up your ESP32-DevKitC V2, please make sure that the board is in good condition with no obvious signs of damage. -After that, proceed to :doc:`index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. +After that, proceed to :doc:`../get-started-cmake/index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. + +If you prefer using an older GNU Make build system, then proceed to respective :ref:`get-started-step-by-step` for the GNU Make. Related Documents diff --git a/docs/en/get-started-cmake/get-started-devkitc.rst b/docs/en/hw-reference/get-started-devkitc.rst similarity index 93% rename from docs/en/get-started-cmake/get-started-devkitc.rst rename to docs/en/hw-reference/get-started-devkitc.rst index 2ee9835f3d..d15807dbc8 100644 --- a/docs/en/get-started-cmake/get-started-devkitc.rst +++ b/docs/en/hw-reference/get-started-devkitc.rst @@ -1,4 +1,4 @@ -ESP32-DevKitC V4 Getting Started Guide (CMake) +ESP32-DevKitC V4 Getting Started Guide ============================================== :link_to_translation:`zh_CN:[中文]` @@ -121,7 +121,9 @@ Start Application Development Before powering up your ESP32-DevKitC V4, please make sure that the board is in good condition with no obvious signs of damage. -After that, proceed to :doc:`index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. +After that, proceed to :doc:`../get-started-cmake/index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. + +If you prefer using an older GNU Make build system, then proceed to respective :ref:`get-started-step-by-step` for the GNU Make. Board Dimensions diff --git a/docs/en/get-started-cmake/get-started-pico-kit-v3.rst b/docs/en/hw-reference/get-started-pico-kit-v3.rst similarity index 88% rename from docs/en/get-started-cmake/get-started-pico-kit-v3.rst rename to docs/en/hw-reference/get-started-pico-kit-v3.rst index d93dbd692d..a124582a56 100644 --- a/docs/en/get-started-cmake/get-started-pico-kit-v3.rst +++ b/docs/en/hw-reference/get-started-pico-kit-v3.rst @@ -1,4 +1,4 @@ -ESP32-PICO-KIT V3 Getting Started Guide (CMake) +ESP32-PICO-KIT V3 Getting Started Guide =============================================== :link_to_translation:`zh_CN:[中文]` @@ -65,7 +65,9 @@ Start Application Development Before powering up your ESP32-PICO-KIT V3, please make sure that the board is in good condition with no obvious signs of damage. -After that, proceed to :doc:`index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. +After that, proceed to :doc:`../get-started-cmake/index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. + +If you prefer using an older GNU Make build system, then proceed to respective :ref:`get-started-step-by-step` for the GNU Make. Related Documents diff --git a/docs/en/get-started-cmake/get-started-pico-kit.rst b/docs/en/hw-reference/get-started-pico-kit.rst similarity index 97% rename from docs/en/get-started-cmake/get-started-pico-kit.rst rename to docs/en/hw-reference/get-started-pico-kit.rst index 9252071362..7c7ff7304c 100644 --- a/docs/en/get-started-cmake/get-started-pico-kit.rst +++ b/docs/en/hw-reference/get-started-pico-kit.rst @@ -193,7 +193,9 @@ Start Application Development Before powering up your ESP32-PICO-KIT, please make sure that the board is in good condition with no obvious signs of damage. -After that, proceed to :doc:`index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. +After that, proceed to :doc:`../get-started-cmake/index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. + +If you prefer using an older GNU Make build system, then proceed to respective :ref:`get-started-step-by-step` for the GNU Make. Board Dimensions diff --git a/docs/en/get-started-cmake/get-started-wrover-kit-v2.rst b/docs/en/hw-reference/get-started-wrover-kit-v2.rst similarity index 96% rename from docs/en/get-started-cmake/get-started-wrover-kit-v2.rst rename to docs/en/hw-reference/get-started-wrover-kit-v2.rst index 0324e04f1d..08da1d59f3 100644 --- a/docs/en/get-started-cmake/get-started-wrover-kit-v2.rst +++ b/docs/en/hw-reference/get-started-wrover-kit-v2.rst @@ -1,4 +1,4 @@ -ESP-WROVER-KIT V2 Getting Started Guide (CMake) +ESP-WROVER-KIT V2 Getting Started Guide =============================================== :link_to_translation:`zh_CN:[中文]` @@ -170,7 +170,9 @@ Turn the **Power Switch** to ON, the **5V Power On LED** should light up. Now to Development ^^^^^^^^^^^^^^^^^^ -Please proceed to :doc:`index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. +Proceed to :doc:`../get-started-cmake/index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. + +If you prefer using an older GNU Make build system, then proceed to respective :ref:`get-started-step-by-step` for the GNU Make. Related Documents diff --git a/docs/en/get-started-cmake/get-started-wrover-kit-v3.rst b/docs/en/hw-reference/get-started-wrover-kit-v3.rst similarity index 97% rename from docs/en/get-started-cmake/get-started-wrover-kit-v3.rst rename to docs/en/hw-reference/get-started-wrover-kit-v3.rst index ca80c56de6..e64e50d7d9 100644 --- a/docs/en/get-started-cmake/get-started-wrover-kit-v3.rst +++ b/docs/en/hw-reference/get-started-wrover-kit-v3.rst @@ -1,4 +1,4 @@ -ESP-WROVER-KIT V3 Getting Started Guide (CMake) +ESP-WROVER-KIT V3 Getting Started Guide =============================================== :link_to_translation:`zh_CN:[中文]` @@ -353,7 +353,9 @@ Turn the **Power Switch** to ON, the **5V Power On LED** should light up. Now to Development ^^^^^^^^^^^^^^^^^^ -Please proceed to :doc:`index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. +Proceed to :doc:`../get-started-cmake/index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. + +If you prefer using an older GNU Make build system, then proceed to respective :ref:`get-started-step-by-step` for the GNU Make. Related Documents diff --git a/docs/en/get-started-cmake/get-started-wrover-kit.rst b/docs/en/hw-reference/get-started-wrover-kit.rst similarity index 97% rename from docs/en/get-started-cmake/get-started-wrover-kit.rst rename to docs/en/hw-reference/get-started-wrover-kit.rst index a1df79357f..5a40efeb56 100644 --- a/docs/en/get-started-cmake/get-started-wrover-kit.rst +++ b/docs/en/hw-reference/get-started-wrover-kit.rst @@ -1,4 +1,4 @@ -ESP-WROVER-KIT V4.1 Getting Started Guide (CMake) +ESP-WROVER-KIT V4.1 Getting Started Guide ================================================= :link_to_translation:`zh_CN:[中文]` @@ -358,7 +358,9 @@ Turn the **Power Switch** to ON, the **5V Power On LED** should light up. Now to Development ^^^^^^^^^^^^^^^^^^ -Please proceed to :doc:`index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. +Proceed to :doc:`../get-started-cmake/index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. + +If you prefer using an older GNU Make build system, then proceed to respective :ref:`get-started-step-by-step` for the GNU Make. Related Documents diff --git a/docs/en/hw-reference/modules-and-boards-previous.rst b/docs/en/hw-reference/modules-and-boards-previous.rst index 8332355d54..192b3724a9 100644 --- a/docs/en/hw-reference/modules-and-boards-previous.rst +++ b/docs/en/hw-reference/modules-and-boards-previous.rst @@ -27,7 +27,7 @@ Comparing to ESP32-PICO-KIT V3, this version has revised printout and reduced nu Documentation ------------- -* :doc:`../get-started/get-started-pico-kit` +* :doc:`../hw-reference/get-started-pico-kit` * `ESP32-PICO-KIT V4 Schematic `_ (PDF) * `ESP32-PICO-D4 Datasheet `_ (PDF) @@ -48,7 +48,7 @@ The first public release of Espressif's ESP32-PICO-D4 module on a mini developme Documentation ------------- -* :doc:`../get-started/get-started-pico-kit-v3` +* :doc:`../hw-reference/get-started-pico-kit-v3` * `ESP32-PICO-KIT V3 Schematic `_ (PDF) * `ESP32-PICO-D4 Datasheet `_ (PDF) @@ -70,7 +70,7 @@ Small and convenient development board with ESP-WROOM-32 module installed, break Documentation ------------- -* :doc:`../get-started/get-started-devkitc-v2` +* :doc:`../hw-reference/get-started-devkitc-v2` * `ESP32 DevKitC V2 Schematic `__ (PDF) * `CP210x USB to UART Bridge VCP Drivers `_ @@ -97,7 +97,7 @@ The camera header has been changed from male back to female. The board soldermas Documentation ------------- -* :doc:`../get-started/get-started-wrover-kit-v3` +* :doc:`../hw-reference/get-started-wrover-kit-v3` * `ESP-WROVER-KIT V3 Schematic `__ (PDF) * :doc:`../api-guides/jtag-debugging/index` * `FTDI Virtual COM Port Drivers`_ @@ -121,7 +121,7 @@ Comparing to previous version, this board has a shiny black finish and a male ca Documentation ------------- -* :doc:`../get-started/get-started-wrover-kit-v2` +* :doc:`../hw-reference/get-started-wrover-kit-v2` * `ESP-WROVER-KIT V2 Schematic `__ (PDF) * :doc:`../api-guides/jtag-debugging/index` * `FTDI Virtual COM Port Drivers`_ diff --git a/docs/en/hw-reference/modules-and-boards.rst b/docs/en/hw-reference/modules-and-boards.rst index ddc41a7353..838348e252 100644 --- a/docs/en/hw-reference/modules-and-boards.rst +++ b/docs/en/hw-reference/modules-and-boards.rst @@ -202,7 +202,7 @@ Comparing to ESP32-PICO-KIT V4, this version features the CP2102N USB-UART bridg Documentation ^^^^^^^^^^^^^ -* :doc:`../get-started-cmake/get-started-pico-kit` +* :doc:`../hw-reference/get-started-pico-kit` * `ESP32-PICO-KIT V4.1 Schematic `_ (PDF) * `ESP32-PICO-KIT Reference Design `_ containing OrCAD schematic, PCB layout, gerber and BOM files * `ESP32-PICO-D4 Datasheet `_ (PDF) @@ -239,7 +239,7 @@ Comparing to the previous :ref:`esp-modules-and-boards-esp32-devkitc-v2`, this v Documentation ^^^^^^^^^^^^^ -* :doc:`../get-started-cmake/get-started-devkitc` +* :doc:`../hw-reference/get-started-devkitc` * `ESP32-DevKitC schematic `_ (PDF) * `ESP32-DevKitC Reference Design `_ containing OrCAD schematic, PCB layout, gerber and BOM files * `CP210x USB to UART Bridge VCP Drivers `_ @@ -288,7 +288,7 @@ The board in the picture above integrates the ESP32-WROVER-B module. Documentation ^^^^^^^^^^^^^ -* :doc:`../get-started-cmake/get-started-wrover-kit` +* :doc:`../hw-reference/get-started-wrover-kit` * `ESP-WROVER-KIT V4.1 Schematic `__ (PDF) * :doc:`../api-guides/jtag-debugging/index` * `FTDI Virtual COM Port Drivers`_ diff --git a/docs/zh_CN/api-guides/jtag-debugging/configure-wrover.rst b/docs/zh_CN/api-guides/jtag-debugging/configure-wrover.rst index 07b113f485..f440d3c5a1 100644 --- a/docs/zh_CN/api-guides/jtag-debugging/configure-wrover.rst +++ b/docs/zh_CN/api-guides/jtag-debugging/configure-wrover.rst @@ -8,7 +8,7 @@ 配置硬件 ^^^^^^^^ -1. 根据 :doc:`../../get-started/get-started-wrover-kit` 文档中 :ref:`get-started-esp-wrover-kit-v4.1-setup-options` 章节所描述的信息,设置 JP8 便可以启用 JTAG 功能。 +1. 根据 :doc:`../../hw-reference/get-started-wrover-kit` 文档中 :ref:`get-started-esp-wrover-kit-v4.1-setup-options-cmake` 章节所描述的信息,设置 JP8 便可以启用 JTAG 功能。 2. 检查 ESP32 上用于 JTAG 通信的引脚是否被接到了其它硬件上,这可能会影响 JTAG 的工作。 diff --git a/docs/zh_CN/get-started-cmake/index.rst b/docs/zh_CN/get-started-cmake/index.rst index 79d951be46..73d4f05940 100644 --- a/docs/zh_CN/get-started-cmake/index.rst +++ b/docs/zh_CN/get-started-cmake/index.rst @@ -62,9 +62,9 @@ ESP32 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、 .. toctree:: :maxdepth: 1 - ESP32-DevKitC - ESP-WROVER-KIT - ESP32-PICO-KIT + ESP32-DevKitC <../hw-reference/get-started-devkitc> + ESP-WROVER-KIT <../hw-reference/get-started-wrover-kit> + ESP32-PICO-KIT <../hw-reference/get-started-pico-kit> ESP32-Ethernet-Kit <../hw-reference/get-started-ethernet-kit> diff --git a/docs/zh_CN/get-started/get-started-devkitc-v2.rst b/docs/zh_CN/get-started/get-started-devkitc-v2.rst deleted file mode 100644 index 3549c8f045..0000000000 --- a/docs/zh_CN/get-started/get-started-devkitc-v2.rst +++ /dev/null @@ -1,81 +0,0 @@ -ESP32-DevKitC V2 入门指南 -========================================= - -:link_to_translation:`en: [English]` - -本指南介绍了如何开始使用 ESP32-DevKitC V2 开发板。 - - -准备工作 -------------- - -* ESP32-DevKitC V2 开发板 -* USB A / micro USB B 数据线 -* PC(Windows、Linux 或 Mac OS) - -您可以跳过介绍部分,直接前往 `应用程序开发`_ 章节。 - - -概述 --------- - -ESP32-DevKitC V2 是 `乐鑫 `_ 一款基于 ESP32 的小型开发板,板上模组的绝大部分管脚均已引出,开发人员可根据实际需求,轻松通过跳线连接多种外围器件,或将开发板插在面包板上使用。 - - -功能说明 ----------------------- - -ESP32-DevKitC V2 开发板的主要组件、接口及控制方式见下。 - -.. _get-started-esp32-devkitc-v2-board-front-make: - -.. figure:: ../../_static/esp32-devkitc-v2-functional-overview.png - :align: center - :alt: ESP32-DevKitC V2 开发板 - :figclass: align-center - -ESP32-DevKitC V2 开发板 - -+----------------+--------------------------------------------------------------------------------------------------------------------------+ -| 主要组件 | 基本介绍 | -+----------------+--------------------------------------------------------------------------------------------------------------------------+ -| ESP32-WROOM-32 | 基于 ESP32 的模组。更多详情,请见 `《ESP32-WROOM-32 技术规格书》`_。 | -+----------------+--------------------------------------------------------------------------------------------------------------------------+ -| EN | 复位按键。 | -+----------------+--------------------------------------------------------------------------------------------------------------------------+ -| Boot | 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 | -+----------------+--------------------------------------------------------------------------------------------------------------------------+ -| Micro USB 端口 | USB 接口。可用作电路板的供电电源,或连接 PC 和 ESP32-WROOM-32 模组的通信接口。 | -+----------------+--------------------------------------------------------------------------------------------------------------------------+ -| I/O | 板上模组的绝大部分管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。 | -+----------------+--------------------------------------------------------------------------------------------------------------------------+ - - -电源选项 --------------------- - -开发板可任一选用以下三种供电方式: - -* Micro USB 供电(默认) -* 5V / GND 管脚供电 -* 3V3 / GND 管脚供电 - -.. warning:: - - 上述供电模式 **不可同时连接**,否则可能会损坏开发板和/或电源。 - - -应用程序开发 ------------------------------- - -ESP32-DevKitC V2 上电前,请首先确认开发板完好无损。 - -之后,请前往 :doc:`index` 的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 - - -相关文档 ------------------ - -* `ESP32-DevKitC 原理图 `_ (PDF) -* `《ESP32 技术规格书》 `_ (PDF) -* `《ESP32-WROOM-32 技术规格书》 `_ (PDF) \ No newline at end of file diff --git a/docs/zh_CN/get-started/get-started-devkitc.rst b/docs/zh_CN/get-started/get-started-devkitc.rst deleted file mode 100644 index 3a087fcdf1..0000000000 --- a/docs/zh_CN/get-started/get-started-devkitc.rst +++ /dev/null @@ -1,153 +0,0 @@ -ESP32-DevKitC V4 入门指南 -=========================== - -:link_to_translation:`en: [English]` - -本指南介绍了如何开始使用 ESP32-DevKitC V4 开发板。有关 ESP32-DevKitC 其他版本的介绍,请见::doc:`../hw-reference/index`。 - - -准备工作 --------- - -* ESP32-DevKitC V4 开发板 -* USB A / micro USB B 数据线 -* PC(Windows、Linux 或 Mac OS) - -您可以跳过介绍部分,直接前往 `应用程序开发`_ 章节。 - - -.. _DevKitC-Overview: - -概述 ----- - -ESP32-DevKitC V4 是 `乐鑫 `_ 一款基于 ESP32 的小型开发板,板上模组的绝大部分管脚均已引出,开发人员可根据实际需求,轻松通过跳线连接多种外围器件,或将开发板插在面包板上使用。 - -为了更好地满足不同用户需求,ESP32-DevKitC V4 还支持以下不同配置: - -- 可选多款 ESP32 模组 - - - :ref:`esp-modules-and-boards-esp32-wroom-32` - - :ref:`ESP32-WROOM-32D ` - - :ref:`ESP32-WROOM-32U ` - - :ref:`esp-modules-and-boards-esp32-solo-1` - - :ref:`ESP32-WROVER ` - - :ref:`ESP32-WROVER-B ` - - :ref:`ESP32-WROVER-I ` - - :ref:`ESP32-WROVER-I (IPEX) ` - -- 可选排针或排母 - -详情请见 `《乐鑫产品订购信息》 `_。 - - -功能说明 --------- - -ESP32-DevKitC V4 开发板的主要组件、接口及控制方式见下。 - -.. _get-started-esp32-devkitc-board-front: - -.. figure:: ../../_static/esp32-devkitc-functional-overview.jpg - :align: center - :alt: ESP32-DevKitC V4(板载 ESP32-WROOM-32) - :figclass: align-center - -ESP32-DevKitC V4(板载 ESP32-WROOM-32) - - -+--------------------+--------------------------------------------------------------------------------------------------------------------------+ -| 主要组件 | 基本介绍 | -+--------------------+--------------------------------------------------------------------------------------------------------------------------+ -| ESP32-WROOM-32 | 基于 ESP32 的模组。更多详情,请见 `《ESP32-WROOM-32 技术规格书》`_。 | -+--------------------+--------------------------------------------------------------------------------------------------------------------------+ -| EN | 复位按键。 | -+--------------------+--------------------------------------------------------------------------------------------------------------------------+ -| Boot | 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 | -+--------------------+--------------------------------------------------------------------------------------------------------------------------+ -| USB-to-UART 桥接器 | 单芯片 USB-UART 桥接器,可提供高达 3 Mbps 的传输速率。 | -+--------------------+--------------------------------------------------------------------------------------------------------------------------+ -| Micro USB 端口 | USB 接口。可用作电路板的供电电源,或连接 PC 和 ESP32-WROOM-32 模组的通信接口。 | -+--------------------+--------------------------------------------------------------------------------------------------------------------------+ -| 5V Power On LED | 开发板通电后(USB 或外部 5 V),该指示灯将亮起。更多信息,请见 `相关文档`_ 中的原理图。 | -+--------------------+--------------------------------------------------------------------------------------------------------------------------+ -| I/O | 板上模组的绝大部分管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。 | -+--------------------+--------------------------------------------------------------------------------------------------------------------------+ - -.. note:: - - 管脚 D0、D1、D2、D3、CMD 和 CLK 用于 ESP32 芯片与 SPI flash 间的内部通信,集中分布在开发板两侧靠近 USB 端口的位置。通常而言,这些管脚最好不连,否则可能影响 SPI flash / SPI RAM 的工作。 - -.. note:: - - 管脚 GPIO16 和 GPIO17 仅适用于板载 ESP32-WROOM 系列和 ESP32-SOLO-1 的开发板,保留内部使用。 - - -电源选项 --------- - -开发板可任一选用以下三种供电方式: - -* Micro USB 供电(默认) -* 5V / GND 管脚供电 -* 3V3 / GND 管脚供电 - -.. warning:: - - 上述供电模式 **不可同时连接**,否则可能会损坏开发板和/或电源。 - - -有关 C15 的提示 ------------------ - -较早版本 ESP32-DevKitC 开发板上的 C15 可能存在以下问题: - -* 开发板上电后可能进入下载模式; -* 如果用户通过 GPIO0 输出时钟,C15 可能会影响信号。 - -用户如果认为 C15 可能影响开发板的使用,则可以将 C15 完全移除。C15 在开发板上的具体位置见下图黄色部分。 - - -.. figure:: ../../_static/esp32-devkitc-c15-location.png - :align: center - :alt: C15(黄色)在 ESP32-DevKitC V4 开发板上的位置 - :figclass: align-center - :width: 30% - -C15(黄色)在 ESP32-DevKitC V4 开发板上的位置 - - -应用程序开发 ------------- - -ESP32-DevKitC V4 上电前,请首先确认开发板完好无损。 - -之后,请前往 :doc:`index` 的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 - -开发板尺寸 ------------ - -.. figure:: ../../_static/esp32-devkitc-dimensions-back.jpg - :align: center - :alt: ESP32-DevKitC 开发板尺寸 -- 仰视图 - :figclass: align-center - -ESP32-DevKitC 开发板尺寸 -- 仰视图 - - -相关文档 --------- - -* `ESP32-DevKitC V4 原理图 `_ (PDF) -* `《ESP32 技术规格书》 `_ (PDF) -* `《ESP32-WROOM-32 技术规格书》 `_ (PDF) -* `《ESP32-WROOM-32D & ESP32-WROOM-32U 技术规格书》 `_ (PDF) -* `《ESP32-WROVER 技术规格书》 `_ (PDF) -* `《ESP32-WROVER-B 技术规格书》 `_ (PDF) -* `《乐鑫产品订购信息》 `_ (PDF) - -.. toctree:: - :hidden: - - get-started-devkitc-v2 - diff --git a/docs/zh_CN/get-started/get-started-pico-kit-v3.rst b/docs/zh_CN/get-started/get-started-pico-kit-v3.rst deleted file mode 100644 index c8141f6d9f..0000000000 --- a/docs/zh_CN/get-started/get-started-pico-kit-v3.rst +++ /dev/null @@ -1,78 +0,0 @@ -ESP32-PICO-KIT V3 入门指南 -======================================= -:link_to_translation:`en:[English]` - -本指南介绍了如何开始使用 ESP32-PICO-KIT V3 迷你开发板。有关 ESP32-PICO-KIT 其他版本的介绍,请见::doc:`../hw-reference/index`。 - - -准备工作 --------- - -* ESP32-PICO-KIT V3 迷你开发板 -* USB 2.0 线(A 型转 Micro-B 型) -* PC(Windows、Linux 或 Mac OS) - -您可以跳过介绍部分,直接前往 `应用程序开发`_ 章节。 - - -概述 ----- - -ESP32-PICO-KIT V3 是一款来自 `乐鑫 `_ 的迷你开发板,其核心是具有完整 Wi-Fi 和蓝牙功能的 ESP32 系列 SiP 模组 ESP32-PICO-D4。 - -ESP32-PICO-KIT 集成了 USB 转 UART 桥接电路,允许开发人员直接通过 PC 的 USB 端口进行下载和调试。 - -为了便于连接,ESP32-PICO-D4 上的所有 IO 信号和系统电源管脚均通过开发板两侧焊盘(每侧 20 个 x 0.1 英寸间隔)引出。 - - -功能说明 --------- - -ESP32-PICO-KIT V3 开发板的主要组件、接口及控制方式见下。 - -.. figure:: ../../_static/esp32-pico-kit-v3-layout.jpg - :align: center - :alt: ESP32-PICO-KIT V3 开发板布局 - :figclass: align-center - - ESP32-PICO-KIT V3 开发板布局 - -ESP32-PICO-KIT 开发板的主要组件描述见下表。 - -================== ======================================================================================================================================================================================================================================================================= -主要组件 基本介绍 -================== ======================================================================================================================================================================================================================================================================= -ESP32-PICO-D4 ESP32-PICO-KIT V3 开发板上焊接的标准 ESP32-PICO-D4 模组,集成了 ESP32 芯片的完整系统,仅需连接天线、LC 匹配电路、退耦电容和一个 EN 信号上拉电阻即可正常工作。 - -LDO 5V-to-3.3V 低压差稳压器。 - -USB-to-UART 桥接器 单芯片 USB-to-UART 桥接器,可提供高达 1 Mbps 的传输速率。 - -Micro USB 端口 USB 接口。可用作开发板的供电电源,或连接 PC 和开发板的通信接口。 - -Power On LED 开发板通电后,该红色指示灯将亮起。 - -I/O ESP32-PICO-D4 的所有管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。 - -BOOT 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 - -EN 复位按键。 -================== ======================================================================================================================================================================================================================================================================= - - -应用程序开发 ------------- - -ESP32-PICO-KIT V3 上电前,请首先确认开发板完好无损。 - -之后,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 - - -相关文档 ------------------ - -* `ESP32-PICO-KIT V3 原理图 `_ (PDF) -* `《ESP32-PICO-D4 技术规格书》 `_ (PDF) -* :doc:`../hw-reference/index` - - diff --git a/docs/zh_CN/get-started/get-started-pico-kit.rst b/docs/zh_CN/get-started/get-started-pico-kit.rst deleted file mode 100644 index a40887c5ae..0000000000 --- a/docs/zh_CN/get-started/get-started-pico-kit.rst +++ /dev/null @@ -1,235 +0,0 @@ -ESP32-PICO-KIT V4/V4.1 入门指南 -====================================== -:link_to_translation:`en:[English]` - -本指南介绍了如何开始使用 ESP32-PICO-KIT V4 / V4.1 迷你开发板。有关 ESP32-PICO-KIT 其他版本的介绍,请见::doc:`../hw-reference/index`。 - -本指南仅适用于 ESP32-PICO-KIT V4 和 V4.1。ESP32-PICO-KIT V4.1 与 V4 的最大差别在于桥接器,其中 V4 搭载的 CP2102 USB-to-UART 桥接器最高速率为 1 Mbps,V4.1 搭载的 CP2102N 桥接器最高传输速率 3 Mbps。 - - -准备工作 --------- - -* :ref:`ESP32-PICO-KIT 迷你开发板 ` -* USB 2.0 线(A 型转 Micro-B 型) -* PC(Windows、Linux 或 Mac OS) - -您可以跳过介绍部分,直接前往 `应用程序开发`_ 章节。 - - -概述 ----- - -ESP32-PICO-KIT 是一款来自 `乐鑫 `_ 的迷你开发板,其核心是具有完整 Wi-Fi 和蓝牙功能的 ESP32 系列 SiP 模组 ESP32-PICO-D4。与其他 ESP32 系列模组相比,ESP32-PICO-D4 模组已完整集成以下外围器件: - -- 40 MHz 晶体振荡器 -- 4 MB flash -- 滤波电容 -- 射频匹配网络等 - -这大大降低了用户额外采购和安装这些元器件的数量和成本,及额外组装测试的复杂度,并增加了可用性。 - -ESP32-PICO-KIT 集成了 USB 转 UART 桥接电路,允许开发人员直接通过 PC 的 USB 端口进行下载和调试。 - -为了便于连接,ESP32-PICO-D4 上的所有 IO 信号和系统电源管脚均通过开发板两侧焊盘(每侧 20 个 x 0.1 英寸间隔)引出。为了方便杜邦线的使用,ESP32-PICO-KIT 开发板每侧的 20 个焊盘中,有 17 个引出至排针,另外 3 个靠近天线的焊盘未引出,可供用户日后焊接使用。 - -.. note:: - - 1. 每排未引出至排针的 3 个管脚已连接至 ESP32-PICO-D4 SiP 模组的内置 flash 模块。更多信息,请见 `相关文档`_ 中的模组技术规格书。 - 2. ESP32-PICO-D4 开发板默认采用排针。 - -功能概述 --------- - -ESP32-PICO-KIT 开发板的主要组件和连接方式见下。 - -.. figure:: ../../_static/esp32-pico-kit-v4-functional-block-diagram.png - :align: center - :alt: ESP32-PICO-KIT 功能框图 - :figclass: align-center - - ESP32-PICO-KIT 框图 - - -功能说明 --------- - -ESP32-PICO-KIT 开发板的主要组件、接口及控制方式见下。 - -.. _get-started-pico-kit-v4-board-front: - -.. figure:: ../../_static/esp32-pico-kit-v4.1-f-layout.jpeg - :align: center - :alt: ESP32-PICO-KIT 开发板布局 - :figclass: align-center - - ESP32-PICO-KIT 开发板布局 - -ESP32-PICO-KIT 开发板的主要组件描述见下表(从左上角起顺时针顺序)。 - -================== ============================================================================================================================================= -主要组件 基本介绍 -================== ============================================================================================================================================= -ESP32-PICO-D4 ESP32-PICO-KIT 开发板上焊接的标准 ESP32-PICO-D4 模组,集成了 ESP32 芯片的完整系统,仅需连接天线、LC 匹配电路、退耦电容和一个 EN 信号上拉电阻即可正常工作。 - -LDO 5V-to-3.3V 低压差稳压器 - -USB-to-UART 桥接器 单芯片 USB-to-UART 桥接器。V4 版本搭载的 CP2102 可提供高达 1 Mbps 的传输速率,V4.1 版本搭载的 CP2102N 可提供高达 3 Mbps 的传输速率。 - -Micro USB 端口 USB 接口。可用作开发板的供电电源,或连接 PC 和开发板的通信接口。 - -5V Power On LED 开发板通电后,该红色指示灯将亮起。更多信息,请见 `相关文档`_ 中的原理图。 - -I/O ESP32-PICO-D4 的所有管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。更多详情,请见章节 `管脚说明`_。 - -BOOT 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 - -EN 复位按键。 -================== ============================================================================================================================================= - - -电源选项 --------- - -开发板可任一选用以下三种供电方式: - -* Micro USB 供电(默认) -* 5V / GND 管脚供电 -* 3V3 / GND 管脚供电 - -.. warning:: - - 上述供电模式 **不可同时连接**,否则可能会损坏开发板和/或电源。 - - -管脚说明 ----------- - -下表介绍了开发板 I/O 管脚的 **名称** 和 **功能**,具体布局请见 `相关文档`_ 中的原理图。请参考 :ref:`get-started-pico-kit-v4-board-front`。 - - - - -Header J2 -""""""""" - -====== ================= ====== ====================================================== -编号 名称 类型 功能 -====== ================= ====== ====================================================== -1 FLASH_SD1 (FSD1) I/O | GPIO8, SD_DATA1, SPID, HS1_DATA1 :ref:`(见说明 1) ` , U2CTS -2 FLASH_SD3 (FSD3) I/O | GPIO7, SD_DATA0, SPIQ, HS1_DATA0 :ref:`(见说明 1) ` , U2RTS -3 FLASH_CLK (FCLK) I/O | GPIO6, SD_CLK, SPICLK, HS1_CLK :ref:`(见说明 1) ` , U1CTS -4 IO21 I/O | GPIO21, VSPIHD, EMAC_TX_EN -5 IO22 I/O | GPIO22, VSPIWP, U0RTS, EMAC_TXD1 -6 IO19 I/O | GPIO19, VSPIQ, U0CTS, EMAC_TXD0 -7 IO23 I/O | GPIO23, VSPID, HS1_STROBE -8 IO18 I/O | GPIO18, VSPICLK, HS1_DATA7 -9 IO5 I/O | GPIO5, VSPICS0, HS1_DATA6, EMAC_RX_CLK -10 IO10 I/O | GPIO10, SD_DATA3, SPIWP, HS1_DATA3, U1TXD -11 IO9 I/O | GPIO9, SD_DATA2, SPIHD, HS1_DATA2, U1RXD -12 RXD0 I/O | GPIO3, U0RXD :ref:`(见说明 3) ` , CLK_OUT2 -13 TXD0 I/O | GPIO1, U0TXD :ref:`(见说明 3) ` , CLK_OUT3, EMAC_RXD2 -14 IO35 I | ADC1_CH7, RTC_GPIO5 -15 IO34 I | ADC1_CH6, RTC_GPIO4 -16 IO38 I | GPIO38, ADC1_CH2, RTC_GPIO2 -17 IO37 I | GPIO37, ADC1_CH1, RTC_GPIO1 -18 EN I | CHIP_PU -19 GND P | Ground -20 VDD33 (3V3) P | 3.3V 电源 -====== ================= ====== ====================================================== - - -Header J3 -""""""""" - - -====== ================= ====== ====================================================== -编号 名称 类型 功能 -====== ================= ====== ====================================================== -1 FLASH_CS (FCS) I/O | GPIO16, HS1_DATA4 :ref:`(见说明 1) ` , U2RXD, EMAC_CLK_OUT -2 FLASH_SD0 (FSD0) I/O | GPIO17, HS1_DATA5 :ref:`(见说明 1) ` , U2TXD, EMAC_CLK_OUT_180 -3 FLASH_SD2 (FSD2) I/O | GPIO11, SD_CMD, SPICS0, HS1_CMD :ref:`(见说明 1) ` , U1RTS -4 SENSOR_VP (FSVP) I | GPIO36, ADC1_CH0, RTC_GPIO0 -5 SENSOR_VN (FSVN) I | GPIO39, ADC1_CH3, RTC_GPIO3 -6 IO25 I/O | GPIO25, DAC_1, ADC2_CH8, RTC_GPIO6, EMAC_RXD0 -7 IO26 I/O | GPIO26, DAC_2, ADC2_CH9, RTC_GPIO7, EMAC_RXD1 -8 IO32 I/O | 32K_XP :ref:`(见说明 2a) ` , ADC1_CH4, TOUCH9, RTC_GPIO9 -9 IO33 I/O | 32K_XN :ref:`(见说明 2b) ` , ADC1_CH5, TOUCH8, RTC_GPIO8 -10 IO27 I/O | GPIO27, ADC2_CH7, TOUCH7, RTC_GPIO17 - | EMAC_RX_DV -11 IO14 I/O | ADC2_CH6, TOUCH6, RTC_GPIO16, MTMS, HSPICLK, - | HS2_CLK, SD_CLK, EMAC_TXD2 -12 IO12 I/O | ADC2_CH5, TOUCH5, RTC_GPIO15, MTDI :ref:`(见说明 4) ` , HSPIQ, - | HS2_DATA2, SD_DATA2, EMAC_TXD3 -13 IO13 I/O | ADC2_CH4, TOUCH4, RTC_GPIO14, MTCK, HSPID, - | HS2_DATA3, SD_DATA3, EMAC_RX_ER -14 IO15 I/O | ADC2_CH3, TOUCH3, RTC_GPIO13, MTDO, HSPICS0 - | HS2_CMD, SD_CMD, EMAC_RXD3 -15 IO2 I/O | ADC2_CH2, TOUCH2, RTC_GPIO12, HSPIWP, - | HS2_DATA0, SD_DATA0 -16 IO4 I/O | ADC2_CH0, TOUCH0, RTC_GPIO10, HSPIHD, - | HS2_DATA1, SD_DATA1, EMAC_TX_ER -17 IO0 I/O | ADC2_CH1, TOUCH1, RTC_GPIO11, CLK_OUT1 - | EMAC_TX_CLK -18 VDD33 (3V3) P | 3.3V 电源 -19 GND P | Ground -20 EXT_5V (5V) P | 5V 电源 -====== ================= ====== ====================================================== - - - -.. _get-started-pico-kit-v4-pin-notes: - -有关上表的说明: - -1. 该管脚已连接至 ESP32-PICO-D4 的内置 flash 管脚。 -2. 32.768 kHz 晶振:(a) 输入;(b) 输出。 -3. 该管脚已连接至开发板的 USB 桥接器芯片。 -4. ESP32-PICO-KIT 内置 SPI flash 的工作电压为 3.3V。因此,strapping 管脚 MTDI 在模组上电复位过程中应保持低电平。如连接该管脚,请确保该管脚在复位中不要保持高电平。 - - -应用程序开发 ------------- - -ESP32-PICO-KIT 上电前,请首先确认开发板完好无损。 - -之后,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 - - -开发板尺寸 ----------- - -ESP32-PICO-KIT 的尺寸为 52 x 20.3 x 10 mm (2.1" x 0.8" x 0.4")。 - -.. figure:: ../../_static/esp32-pico-kit-v4.1-dimensions-back.jpg - :align: center - :alt: ESP32-PICO-KIT 尺寸图 -- 背面 - :figclass: align-center - - ESP32-PICO-KIT 尺寸图 -- 背面 - -.. figure:: ../../_static/esp32-pico-kit-v4-dimensions-side.jpg - :align: center - :alt: ESP32-PICO-KIT V4 尺寸图 -- 侧面 - :figclass: align-center - - ESP32-PICO-KIT 尺寸图 -- 侧面 - -有关开发板的物理结构细节,请见下方参考设计。 - - -相关文档 ------------------ - -* `ESP32-PICO-KIT V4 原理图 `_ (PDF) -* `ESP32-PICO-KIT V4.1 原理图 `_ (PDF) -* `ESP32-PICO-KIT 参考设计 `_ ,内含 OrCAD 原理图、PCB 布局、Gerbers 和 BOM 表。 -* `《ESP32-PICO-D4 技术规格书》 `_ (PDF) -* :doc:`../hw-reference/index` - - -.. toctree:: - :hidden: - - get-started-pico-kit-v3 - diff --git a/docs/zh_CN/get-started/get-started-wrover-kit-v2.rst b/docs/zh_CN/get-started/get-started-wrover-kit-v2.rst deleted file mode 100644 index 637c5c47b9..0000000000 --- a/docs/zh_CN/get-started/get-started-wrover-kit-v2.rst +++ /dev/null @@ -1,191 +0,0 @@ -ESP-WROVER-KIT V2 入门指南 -=========================================== -:link_to_translation:`en:[English]` - -本指南介绍了如何开始使用 ESP-WROVER-KIT V2 开发板及其功能和相关配置。有关 ESP-WROVER-KIT 其他版本的介绍,请见::doc:`../hw-reference/index`。 - - -准备工作 -------------- - -* ESP-WROVER-KIT V2 开发板 -* USB 数据线(A 转 Micro-B) -* PC(Windows、Linux 或 macOS) - -您可以跳过介绍部分,直接前往 `应用程序开发`_ 章节。 - - -概述 --------- - -ESP-WROVER-KIT 是 `乐鑫 `_ 一款基于 ESP32 的开发板,集成了 LCD 屏幕和 MicroSD 卡槽。 - -ESP-WROVER-KIT 可选贴以下 ESP32 模组: - -- :ref:`esp-modules-and-boards-esp32-wroom-32` -- :ref:`ESP32-WROVER ` - -此外,ESP-WROVER-KIT 的独特之处在于集成了一款先进多协议 USB 桥接器 (FTDI FT2232HL),允许开发人员直接通过 USB 接口,使用 JTAG 对 ESP32 进行调试,无需额外的 JTAG 调试器。ESP-WROVER-KIT 可为开发人员提供简单、便捷且极具成本效益的开发体验。 - -为了便于使用,板上模组的绝大部分管脚均已引出至开发板的引脚。 - -.. note:: - - ESP-WROVER-KIT V2 板载 ESP32-WROVER 模组的 GPIO16 和 GPIO17 管脚用作 PSRAM 的片选和时钟信号。 默认情况下,为了给用户提供可靠的性能,这两个 GPIO 管脚不引出至开发板引脚。 - - -功能概述 ----------------------- - -ESP-WROVER-KIT 开发板的主要组件和连接方式如下图所示。 - -.. figure:: ../../_static/esp-wrover-kit-block-diagram.png - :align: center - :alt: ESP-WROVER-KIT 功能框图 - :figclass: align-center - - ESP-WROVER-KIT 功能框图 - - -功能说明 ----------------------- - -ESP-WROVER-KIT 开发板的主要组件、接口及控制方式见下。 - -.. _get-started-esp-wrover-kit-v2-board-front: - -.. figure:: ../../_static/esp-wrover-kit-v2-layout-front.png - :align: center - :alt: ESP-WROVER-KIT 开发板布局 -- 俯视图 - :figclass: align-center - - ESP-WROVER-KIT 开发板布局 -- 俯视图 - -.. _get-started-esp-wrover-kit-v2-board-back: - -.. figure:: ../../_static/esp-wrover-kit-v2-layout-back.png - :align: center - :alt: ESP-WROVER-KIT 开发板布局 -- 仰视图 - :figclass: align-center - - ESP-WROVER-KIT 开发板布局 -- 仰视图 - - -下表从图片右上角开始,以顺时针顺序介绍了图 1 中的主要组件,然后以同样的顺序介绍了图 2 中的主要组件。 - - -==================== ====================================================================================================================================================================================================================================================================================================================================== -主要组件 基本介绍 -==================== ====================================================================================================================================================================================================================================================================================================================================== -32.768 kHz 外接 32.768 kHz 晶振,可提供 Deep-sleep 下使用的低功耗时钟。 - -ESP32 模组 可选贴 ESP32-WROOM-32 或 ESP32-WROVER。ESP32-WROVER 模组完整集成了 ESP32-WROOM-32 的所有功能,且内置 32-Mbit PSRAM,可提供灵活的额外存储空间和数据处理能力。 - -CTS/RTS 串口流控信号。管脚默认不连接至电路。为了使能该功能,必须用跳线帽短路掉 JP14 的相应管脚。 - -UART 串口。FT2232HL 和 ESP32 的串行 TX/RX 信号已引出至 JP11 的两端。默认情况下,这两路信号由跳线帽连接。如果要跳过 FT2232 使用 ESP32 模组串口,则可移除相关跳线帽,将模组连接至其他外部串口设备。 - -SPI 默认情况下,ESP32 使用 SPI 接口访问内置 flash 和 PSRAM。使用这些引脚连接 ESP32 和其他 SPI 设备。这种情况下,需增加额外的片选 (CS) 信号。注意,选贴 ESP32-WROVER 模组时,该接口的工作电压为 1.8 V;选贴 ESP32-WROOM-32 时,该接口的工作电压为 3.3V。 - -JTAG JTAG 接口。FT2232HL 和 ESP32 的 JTAG 信号已引出至 JP8 的两端。默认情况下,这两路信号不连接。如需使能 JTAG,请按照 `设置选项`_ 的介绍,连接跳线帽。 - -FT2232 FT2232 多协议 USB 转串口桥接器。开发人员可通过 USB 接口对 FT2232 芯片进行控制和编程,与 ESP32 建立连接。FT2232 具有 USB-to-UART 和 USB-to-JTAG 功能。 - -EN 复位按键。 - -Boot 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 - -USB USB 接口。可用作开发板的供电电源,或连接 PC 和开发板的通信接口。 - -电源选择开关 ESP-WROVER-KIT 开发板可通过 USB 端口或 5V 输入接口供电。用户可使用跳线帽在两种供电模式中进行选择。更多详细信息,请见章节 `设置选项`_ 中有关 JP7 连接器的描述。 - -电源开关 拨向 **USB** 按键一侧,开发板上电;拨离 **USB** 按键一侧,开发板掉电。 - -5V Input 5V 电源接口建议仅在开发板自动运行(未连接 PC)时使用。仅用于全负荷工作下的后备电源。 - -LDO 5V-to-3.3V 低压差线型稳压器 NCP1117(1A)。NCP1117 最大电流输出为 1 A。板上 LDO 为固定输出电压,但用户也可以选用具有可变输出电压的 LDO。更多信息,请见 `ESP-WROVER-KIT V2 原理图`_。 - -摄像头 摄像头接口,支持标准 OV7670 摄像头模块。 - -RGB LED 红绿蓝发光二极管,可由 PWM(脉冲宽度调制)控制。 - -I/O 板上模组的所有管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。 - -MicroSD 卡槽 MicroSD 卡槽,可扩充存储空间:当 ESP32 进入下载模式时,GPIO2 不可处于高电平。然而,为了使能 MicroSD 卡功能,需为 GPIO2 增加一个上拉电阻。默认情况下,GPIO2 和上拉电阻 R153 处于断开状态。为了使能 MicroSD 卡,请按照 `设置选项`_ 章节的要求,连接 JP1 连接器。 - -LCD 显示屏 支持贴装一款 3.2” 的 SPI(标准四线串行外设接口)LCD 显示器,请见 :ref:`get-started-esp-wrover-kit-v2-board-back`。 -==================== ====================================================================================================================================================================================================================================================================================================================================== - -.. _get-started-esp-wrover-kit-v2-setup-options: - -设置选项 -------------- - -用户可通过 5 组排针,设置开发板功能,其中常见功能见下表: - -======= ================ ===================================================================================== -排针 跳线设置 功能描述 -======= ================ ===================================================================================== -JP1 |jp1-sd_io2| 使能 MicroSD Card 功能的上拉电阻 -JP1 |jp1-both| 确保开发板处于下载模式时,GPIO2 时钟处于低位(将 JP1 连接至 GPIO0) -JP7 |jp7-ext_5v| 使用外部电源为 ESP-WROVER-KIT 开发板供电 -JP7 |jp7-usb_5v| 使用 USB 端口为 ESP-WROVER-KIT 开发板供电 -JP8 |jp8| 使能 JTAG 功能 -JP11 |jp11-tx-rx| 使能 UART 通信 -JP14 |jp14| 使能 RTS/CTS 串口流控 -======= ================ ===================================================================================== - - -.. _get-started-esp-wrover-kit-v2-start-development: - -应用程序开发 ------------------------------ - -ESP-WROVER-KIT 上电前,请首先确认开发板完好无损。 - - -初始设置 -^^^^^^^^^^^^^ - -请严格按照下图所示连接跳线帽,注意不要额外连接其他跳线帽。 - -- 使用 JP7 连接器,选择 USB 为开发板供电。 - -- 使用 JP11 连接器,使能 UART 通信。 - -======================== ========================== -USB 供电 使能 UART 通信 -======================== ========================== -|jp7-usb_5v| |jp11-tx-rx| -======================== ========================== - -注意不要连接其他跳线帽。 - -打开 **电源开关**,**5V Power On LED** 应点亮。 - -正式开始开发 -^^^^^^^^^^^^^^^^^^ - -现在,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 - - -相关文档 ------------------ - -* `ESP-WROVER-KIT V2 原理图`_ (PDF) -* `《ESP32 技术规格书》 `_ (PDF) -* `《ESP32-WROVER 技术规格书》 `_ (PDF) -* `《ESP32-WROOM-32 技术规格书》 `_ (PDF) -* :doc:`../api-guides/jtag-debugging/index` -* :doc:`../hw-reference/index` - - -.. |jp1-sd_io2| image:: ../../_static/wrover-jp1-sd_io2.png -.. |jp1-both| image:: ../../_static/wrover-jp1-both.png -.. |jp7-ext_5v| image:: ../../_static/wrover-jp7-ext_5v.png -.. |jp7-usb_5v| image:: ../../_static/wrover-jp7-usb_5v.png -.. |jp8| image:: ../../_static/wrover-jp8.png -.. |jp11-tx-rx| image:: ../../_static/wrover-jp11-tx-rx.png -.. |jp14| image:: ../../_static/wrover-jp14.png - -.. _ESP-WROVER-KIT V2 原理图: https://dl.espressif.com/dl/schematics/ESP-WROVER-KIT_SCH-2.pdf \ No newline at end of file diff --git a/docs/zh_CN/get-started/get-started-wrover-kit-v3.rst b/docs/zh_CN/get-started/get-started-wrover-kit-v3.rst deleted file mode 100644 index dad52a2c06..0000000000 --- a/docs/zh_CN/get-started/get-started-wrover-kit-v3.rst +++ /dev/null @@ -1,377 +0,0 @@ -ESP-WROVER-KIT V3 入门指南 -======================================= -:link_to_translation:`en:[Engish]` - -本指南介绍了如何开始使用 ESP-WROVER-KIT V3 开发板及其功能和相关配置。有关 ESP-WROVER-KIT 其他版本的介绍,请见::doc:`../hw-reference/index`。 - - -准备工作 -------------- - -* :ref:`ESP-WROVER-KIT V3 开发板 ` -* USB 数据线(A 转 Micro-B) -* PC(Windows、Linux 或 macOS) - -您可以跳过介绍部分,直接前往 `应用程序开发`_ 章节。 - - -概述 --------- - -ESP-WROVER-KIT 是 `乐鑫 `_ 一款基于 ESP32 的开发板,集成了 LCD 屏幕和 MicroSD 卡槽。 - -ESP-WROVER-KIT 可选贴以下 ESP32 模组: - -- :ref:`esp-modules-and-boards-esp32-wroom-32` -- :ref:`ESP32-WROVER ` - -此外,ESP-WROVER-KIT 的独特之处在于集成了一款先进多协议 USB 桥接器 (FTDI FT2232HL),允许开发人员直接通过 USB 接口,使用 JTAG 对 ESP32 进行调试,无需额外的 JTAG 调试器。ESP-WROVER-KIT 可为开发人员提供简单、便捷且极具成本效益的开发体验。 - -为了便于使用,板上模组的绝大部分管脚均已引出至开发板的引脚。 - -.. note:: - - 该版本 ESP32-WROVER 模组 的 GPIO16 和 GPIO17 管脚用作 PSRAM 的片选和时钟信号。默认情况下,为了给用户提供可靠的性能,这两个 GPIO 管脚不引出至开发板引脚。 - - -功能概述 ----------------------- - -ESP-WROVER-KIT 开发板的主要组件和连接方式如下图所示。 - -.. figure:: ../../_static/esp-wrover-kit-block-diagram.png - :align: center - :alt: ESP-WROVER-KIT 功能框图 - :figclass: align-center - - ESP-WROVER-KIT 功能框图 - - -功能说明 ----------------------- - -ESP-WROVER-KIT 开发板的主要组件、接口及控制方式见下。 - -.. _get-started-esp-wrover-kit-v3-board-front: - -.. figure:: ../../_static/esp-wrover-kit-v3-layout-front.jpg - :align: center - :alt: ESP-WROVER-KIT 开发板布局 -- 俯视图 - :figclass: align-center - - ESP-WROVER-KIT 开发板布局 -- 俯视图 - -.. _get-started-esp-wrover-kit-v3-board-back: - -.. figure:: ../../_static/esp-wrover-kit-v3-layout-back.jpg - :align: center - :alt: ESP-WROVER-KIT 开发板布局 -- 仰视图 - :figclass: align-center - - ESP-WROVER-KIT 开发板布局 -- 仰视图 - - -下表从图片右上角开始,以顺时针顺序介绍了图 1 中的主要组件,然后以同样的顺序介绍图 2 中的主要组件。 - - -==================== ====================================================================================================================================================================================================================================================================================================================================== -主要组件 基本介绍 -==================== ====================================================================================================================================================================================================================================================================================================================================== -32.768 kHz 外接 32.768 kHz 晶振,可提供 Deep-sleep 下使用的低功耗时钟。 - -0 欧电阻 ESP-WROVER-KIT 开发板设计了一个 0 欧电阻,可在测量 ESP32 系列模组在不同功耗模式下的电流时,直接移除或替换为分流器。 - -ESP32 模组 可选贴 ESP32-WROOM-32 或 ESP32-WROVER。ESP32-WROVER 模组完整集成了 ESP32-WROOM-32 的所有功能,且内置 32-Mbit PSRAM,可提供灵活的额外存储空间和数据处理能力。 - -FT2232 FT2232 多协议 USB 转串口桥接器。开发人员可通过 USB 接口对 FT2232 芯片进行控制和编程,与 ESP32 建立连接。FT2232 芯片可在通道 A 提供 USB-to-JTAG 接口功能,并在通道 B 提供 USB-to-Serial 接口功能,便利开发人员的应用开发与调试。见 `ESP-WROVER-KIT V3 原理图`_。 - -UART 串口。FT2232HL 和 ESP32 的串行 TX/RX 信号已引出至 JP11 的两端。默认情况下,这两路信号由跳线帽连接。如果要跳过 FT2232 使用 ESP32 模组串口,则可移除相关跳线帽,将模组连接至其他外部串口设备。 - -SPI 默认情况下,ESP32 使用 SPI 接口访问内置 flash 和 PSRAM。使用这些引脚连接 ESP32 和其他 SPI 设备。这种情况下,需增加额外的片选 (CS) 信号。注意,选贴 ESP32-WROVER 模组时,该接口的工作电压为 1.8 V;选贴 ESP32-WROOM-32 时,该接口的工作电压为 3.3V。 - -CTS/RTS 串口流控信号。管脚默认不连接至电路。为了使能该功能,必须用跳线帽短路掉 JP14 的相应管脚。 - -JTAG JTAG 接口。FT2232HL 和 ESP32 的 JTAG 信号已引出至 JP8 的两端。默认情况下,这两路信号不连接。如需使能 JTAG,请按照 `设置选项`_ 的介绍,连接跳线帽。 - -EN 复位按键。 - -Boot 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 - -USB USB 接口。可用作开发板的供电电源,或连接 PC 和开发板的通信接口。 - -电源开关 拨向 **USB** 按键一侧,开发板上电;拨离 **USB** 按键一侧,开发板掉电。 - -电源选择开关 ESP-WROVER-KIT 开发板可通过 USB 端口或 5V 输入接口供电。用户可使用跳线帽在两种供电模式中进行选择。更多详细信息,请见章节 `设置选项`_ 中有关 JP7 连接器的描述。 - -5V Input 5V 电源接口建议仅在开发板自动运行(未连接 PC)时使用。仅用于全负荷工作下的后备电源。 - -LDO 5V-to-3.3V 低压差线型稳压器 NCP1117(1A)。NCP1117 最大电流输出为 1 A。板上 LDO 为固定输出电压,但用户也可以选用具有可变输出电压的 LDO。更多信息,请见 `ESP-WROVER-KIT V3 原理图`_。 - -摄像头 摄像头接口,支持标准 OV7670 摄像头模块。 - -RGB LED 红绿蓝发光二极管,可由 PWM(脉冲宽度调制)控制。 - -I/O 板上模组的所有管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。 - -MicroSD 卡槽 适用于需要扩充数据存储空间或进行备份的应用开发场景。 - -LCD 显示屏 支持贴装一款 3.2” 的 SPI(标准四线串行外设接口)LCD 显示器,请见 :ref:`get-started-esp-wrover-kit-v3-board-back`。 -==================== ====================================================================================================================================================================================================================================================================================================================================== - - -.. _get-started-esp-wrover-kit-v3-setup-options: - -设置选项 -------------- - -用户可通过 5 组排针,设置开发板功能,其中常见功能见下表: - -======= ================ ========================================================================= -排针 跳线设置 功能描述 -======= ================ ========================================================================= -JP7 |jp7-ext_5v| 使用外部电源为 ESP-WROVER-KIT 开发板供电 -JP7 |jp7-usb_5v| 使用 USB 端口为 ESP-WROVER-KIT 开发板供电 -JP8 |jp8| 使能 JTAG 功能 -JP11 |jp11-tx-rx| 使能 UART 通信 -JP14 |jp14| 使能 RTS/CTS 串口流控 -======= ================ ========================================================================= - - -ESP32 管脚分配 ------------------------- - -ESP32 模组的部分管脚/终端已被板上组件占用或用于外部硬件设备。如果某管脚对应的特定硬件未连接,则该管脚可用作他用。比如,摄像头/JP4 排针未连接相应硬件,则这些 GPIO 可用于其他用途。 - -部分管脚具备多个功能,可供板上组件或外部硬件设备同时使用,比如 GPIO0 和 GPIO2。由于管脚限制,一些外围设备不可同时使用,比如,由于 JTAG 和 SD 卡槽需共用部分管脚,因此一些使用 SD 卡功能的应用无法同时进行 JTAG 调试。 - -其他情况下,不同外设可同时使用。比如,LCD 屏幕和 SD 卡仅共用一个 GPIO21 管脚,可以同时使用。该管脚可为 LCD 屏幕提供 D/C(数据/控制)信号,并用于读取来自 SD 卡槽的 CD 信号(卡检测信号)。如无需使用卡检测功能,开发人员还可以通过移除 R167 来禁用该功能。此时,LCD 和 SD 卡槽可同时使用。 - -更多外设共享管脚的介绍,请见下一章节中的表格。 - - -主要 I/O 连接器 / JP1 -^^^^^^^^^^^^^^^^^^^^^^^^ - -JP1 连接器包括 14 x 2 个排针,具体功能可见下表中间 “I/O” 列的介绍。两侧的“共用”列则介绍了这些管脚在板上的其他用途。 - -===================== ===== ===== ===================== -共用 I/O I/O 共用 -===================== ===== ===== ===================== -n/a 3.3V GND n/a -NC/XTAL IO32 IO33 NC/XTAL -JTAG, MicroSD IO12 IO13 JTAG, MicroSD -JTAG, MicroSD IO14 IO27 摄像头 -摄像头 IO26 IO25 摄像头,LCD -摄像头 IO35 IO34 摄像头 -摄像头 IO39 IO36 摄像头 -JTAG EN IO23 摄像头,LCD -摄像头,LCD IO22 IO21 摄像头,LCD,MicroSD -摄像头,LCD IO19 IO18 摄像头,LCD -摄像头,LCD IO5 IO17 PSRAM -PSRAM IO16 IO4 LED,摄像头,MicroSD -摄像头,LED,Boot IO0 IO2 LED,MicroSD -JTAG,MicroSD IO15 5V -===================== ===== ===== ===================== - -说明: - -* NC/XTAL - :ref:`32.768 kHz Oscillator ` -* JTAG - :ref:`JTAG / JP8 ` -* Boot - Boot 按键 / SW2 -* 摄像头 - :ref:`摄像头 / JP4 ` -* LED - :ref:`RGB LED ` -* MicroSD - :ref:`MicroSD Card / J4 ` -* LCD - :ref:`LCD / U5 ` -* PSRAM - 仅适用于选贴 ESP32-WROVER 的情况。 - - -.. _get-started-esp-wrover-kit-v3-xtal: - -32.768 kHz 晶振 -^^^^^^^^^^^^^^^^^^^^^ - -==== ========== -. ESP32 管脚 -==== ========== -1. GPIO32 -2. GPIO33 -==== ========== - -.. note:: - - 默认情况下,管脚 GPIO32 和 GPIO33 已连接至晶振。因此,为了保证信号的完整性,这两个管脚并未连接至 JP1 I/O 连接器。用户可通过将 R11/R23 处的 0 欧电阻移至 R12/R24 处,以将 GP1O32 和 GPIO33 的连接从晶振移至 JP1。 - - -.. _get-started-esp-wrover-kit-v3-spi-flash-header: - -SPI Flash / JP13 -^^^^^^^^^^^^^^^^ - -==== ============= -. ESP32 管脚 -==== ============= -1. CLK / GPIO6 -2. SD0 / GPIO7 -3. SD1 / GPIO8 -4. SD2 / GPIO9 -5. SD3 / GPIO10 -6. CMD / GPIO11 -==== ============= - -.. important:: - - 模组的 flash 总线已通过 0 欧电阻 R140 ~ R145 连接至排针 JP13。如果需要将 flash 的工作频率控制在 80 MHz,为了达到保证总线信号完整性等目的,建议移除 R140 ~ R145 电阻,将模组的 flash 总线与排针 JP2 断开。 - - -.. _get-started-esp-wrover-kit-v3-jtag-header: - -JTAG / JP8 -^^^^^^^^^^ - -==== ============== ============= -. ESP32 管脚 JTAG 信号 -==== ============== ============= -1. EN TRST_N -2. MTMS / GPIO14 TMS -3. MTDO / GPIO15 TDO -4. MTDI / GPIO12 TDI -5. MTCK / GPIO13 TCK -==== ============== ============= - - -.. _get-started-esp-wrover-kit-v3-camera-header: - -摄像头 / JP4 -^^^^^^^^^^^^ - -==== ========== ============================= -. ESP32 管脚 摄像头信号 -==== ========== ============================= -1. n/a 3.3V -2. n/a 地 -3. GPIO27 SIO_C / SCCB 时钟 -4. GPIO26 SIO_D / SCCB 数据 -5. GPIO25 VSYNC / 垂直同步 -6. GPIO23 HREF / 水平参考 -7. GPIO22 PCLK / 像素时钟 -8. GPIO21 XCLK / 系统时钟 -9. GPIO35 D7 / 像素数据 Bit 7 -10. GPIO34 D6 / 像素数据 Bit 6 -11. GPIO39 D5 / 像素数据 Bit 5 -12. GPIO36 D4 / 像素数据 Bit 4 -13. GPIO19 D3 / 像素数据 Bit 3 -14. GPIO18 D2 / 像素数据 Bit 2 -15. GPIO5 D1 / 像素数据 Bit 1 -16. GPIO4 D0 / 像素数据 Bit 0 -17. GPIO0 RESET / 摄像头复位 -18. n/a PWDN / 摄像头断电 -==== ========== ============================= - -* D0 到 D7 为摄像头的数据总线 - - -.. _get-started-esp-wrover-kit-v3-rgb-led-connections: - -RGB LED -^^^^^^^ - -==== ========== ========= -. ESP32 管脚 RGB LED -==== ========== ========= -1. GPIO0 红色 -2. GPIO2 绿色 -3. GPIO4 蓝色 -==== ========== ========= - - -.. _get-started-esp-wrover-kit-v3-microsd-card-slot: - -MicroSD 卡 -^^^^^^^^^^^^ - -==== ============== =============== -. ESP32 管脚 MicroSD 信号 -==== ============== =============== -1. MTDI / GPIO12 DATA2 -2. MTCK / GPIO13 CD / DATA3 -3. MTDO / GPIO15 CMD -4. MTMS / GPIO14 CLK -5. GPIO2 DATA0 -6. GPIO4 DATA1 -7. GPIO21 CD -==== ============== =============== - - -.. _get-started-esp-wrover-kit-v3-lcd-connector: - -LCD / U5 -^^^^^^^^ - -==== ============== =============== -. ESP32 管脚 LCD 信号 -==== ============== =============== -1. GPIO18 复位 -2. GPIO19 SCL -3. GPIO21 D/C -4. GPIO22 CS -5. GPIO23 SDA -6. GPIO25 SDO -7. GPIO5 背光 -==== ============== =============== - - -.. _get-started-esp-wrover-kit-v3-start-development: - -应用程序开发 ------------------------------ - -ESP-WROVER-KIT 上电前,请首先确认开发板完好无损。 - - -初始设置 -^^^^^^^^^^^^^ - -请严格按照下图所示连接跳线帽,注意不要额外连接其他跳线帽。 - -- 使用 JP7 连接器,选择 USB 为开发板供电。 - -- 使用 JP11 连接器,使能 UART 通信。 - -======================== ========================== -USB 供电 使能 UART 通信 -======================== ========================== -|jp7-usb_5v| |jp11-tx-rx| -======================== ========================== - -注意不要连接其他跳线帽。 - -打开 **电源开关**,**5V Power On LED** 应点亮。 - -正式开始开发 -^^^^^^^^^^^^^^^^^^ - -现在,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 - - -相关文档 ------------------ - -* `ESP-WROVER-KIT V3 原理图`_ (PDF) -* `《ESP32 技术规格书》 `_ (PDF) -* `《ESP32-WROVER 技术规格书》 `_ (PDF) -* `《ESP32-WROOM-32 技术规格书》 `_ (PDF) -* :doc:`../api-guides/jtag-debugging/index` -* :doc:`../hw-reference/index` - -.. |jp7-ext_5v| image:: ../../_static/esp-wrover-kit-v3-jp7-ext_5v.png -.. |jp7-usb_5v| image:: ../../_static/esp-wrover-kit-v3-jp7-usb_5v.png -.. |jp8| image:: ../../_static/esp-wrover-kit-v3-jp8.png -.. |jp11-tx-rx| image:: ../../_static/esp-wrover-kit-v3-jp11-tx-rx.png -.. |jp14| image:: ../../_static/esp-wrover-kit-v3-jp14.png - -.. _ESP-WROVER-KIT V3 原理图: https://dl.espressif.com/dl/schematics/ESP-WROVER-KIT_SCH-3.pdf - -.. toctree:: - :hidden: - - get-started-wrover-kit-v2.rst diff --git a/docs/zh_CN/get-started/get-started-wrover-kit.rst b/docs/zh_CN/get-started/get-started-wrover-kit.rst deleted file mode 100644 index 90416f46e1..0000000000 --- a/docs/zh_CN/get-started/get-started-wrover-kit.rst +++ /dev/null @@ -1,382 +0,0 @@ -ESP-WROVER-KIT V4.1 入门指南 -========================================= -:link_to_translation:`en:[English]` - -本指南介绍了如何开始使用 ESP-WROVER-KIT V4.1 开发板及其功能和相关配置。有关 ESP-WROVER-KIT 其他版本的介绍,请见::doc:`../hw-reference/index`。 - - -准备工作 -------------- - -* :ref:`ESP-WROVER-KIT V4.1 开发板 ` -* USB 数据线(A 转 Micro-B) -* PC(Windows、Linux 或 macOS) - -您可以跳过介绍部分,直接前往 `应用程序开发`_ 章节。 - - -概述 --------- - -ESP-WROVER-KIT 是 `乐鑫 `_ 一款基于 ESP32 的开发板。 - -ESP-WROVER-KIT 开发板已集成了如下组件: - -- ESP32-WROVER-B 模组 -- LCD 屏 -- MicroSD 卡槽 - -此外,ESP-WROVER-KIT 的独特之处在于集成了一款先进多协议 USB 桥接器 (FTDI FT2232HL),允许开发人员直接通过 USB 接口,使用 JTAG 对 ESP32 进行调试,无需额外的 JTAG 调试器。ESP-WROVER-KIT 可为开发人员提供简单、便捷且极具成本效益的开发体验。 - -为了便于使用,板上模组的绝大部分管脚均已引出至开发板的引脚。 - -.. note:: - - ESP32 的 GPIO16 和 GPIO17 管脚用作 PSRAM 的片选和时钟信号。默认情况下,为了给用户提供可靠的性能,这两个 GPIO 管脚不引出至开发板引脚。 - - -功能概述 ----------------------- - -ESP-WROVER-KIT 开发板的主要组件和连接方式如下图所示。 - -.. figure:: ../../_static/esp-wrover-kit-block-diagram.png - :align: center - :alt: ESP-WROVER-KIT 功能框图 - :figclass: align-center - - ESP-WROVER-KIT 功能框图 - - -功能说明 ----------------------- - -ESP-WROVER-KIT 开发板的主要组件、接口及控制方式见下。 - -.. _get-started-esp-wrover-kit-v4.1-board-front: - -.. figure:: ../../_static/esp-wrover-kit-v4.1-layout-front.png - :align: center - :alt: ESP-WROVER-KIT 开发板布局 -- 俯视图 - :figclass: align-center - - ESP-WROVER-KIT 开发板布局 -- 俯视图 - -.. _get-started-esp-wrover-kit-v4.1-board-back: - -.. figure:: ../../_static/esp-wrover-kit-v4.1-layout-back.png - :align: center - :alt: ESP-WROVER-KIT 开发板布局 -- 仰视图 - :figclass: align-center - - ESP-WROVER-KIT 开发板布局 -- 仰视图 - - -下表将从图片右上角开始,以顺时针顺序介绍图 1 中的主要组件,然后按同样顺序介绍图 2 中的主要组件。 - - -==================== ====================================================================================================================================================================================================================================================================================================================================== -主要组件 基本介绍 -==================== ====================================================================================================================================================================================================================================================================================================================================== -FT2232 FT2232 多协议 USB 转串口桥接器。开发人员可通过 USB 接口对 FT2232 芯片进行控制和编程,与 ESP32 建立连接。FT2232 芯片可在通道 A 提供 USB-to-JTAG 接口功能,并在通道 B 提供 USB-to-Serial 接口功能,便利开发人员的应用开发与调试。详见 `ESP-WROVER-KIT V4.1 原理图`_。 - -32.768 kHz 外接 32.768 kHz 晶振,可提供 Deep-sleep 下使用的低功耗时钟。 - -0 欧电阻. ESP-WROVER-KIT 开发板设计了一个 0 欧电阻,可在测量 ESP32 系列模组在不同功耗模式下的电流时,直接移除或替换为分流器。 - -ESP32-WROVER-B 模组 ESP-WROVER 模组内置 64-Mbit PSRAM,可提供灵活的额外存储空间和数据处理能力。 - -诊断 LED 信号灯 本开发板 FT2232 芯片的 GPIO 管脚连接了 4 个红色 LED 信号灯,以备后用。 - -UART 串口。FT2232HL 和 ESP32 的串行 TX/RX 信号已引出至 JP11 的两端。默认情况下,这两路信号由跳线帽连接。如果要跳过 FT2232 使用 ESP32 模组串口,则可移除相关跳线帽,将模组连接至其他外部串口设备。 - -SPI 默认情况下,ESP32 使用 SPI 接口访问内置 flash 和 PSRAM。使用这些引脚连接 ESP32 和其他 SPI 设备。这种情况下,需增加额外的片选 (CS) 信号。注意,本接口的工作电压为 3.3 V。 - -CTS/RTS 串口流控信号。管脚默认不连接至电路。为了使能该功能,必须用跳线帽短路掉 JP14 的相应管脚。 - -JTAG JTAG 接口。FT2232HL 和 ESP32 的 JTAG 信号已引出至 JP2 的两端。默认情况下,这两路信号不连接。如需使能 JTAG,请按照 `设置选项`_ 的介绍,连接跳线帽。 - -USB 端口 USB 接口。可用作开发板的供电电源,或连接 PC 和开发板的通信接口。 - -EN 复位按键。 - -Boot 按键 下载按键。按下 **Boot** 键并保持,同时按一下 **EN** 键(此时不要松开 **Boot** 键)进入“固件下载”模式,通过串口下载固件。 - -电源开关 拨向 **Boot** 按键一侧,开发板上电;拨离 **Boot** 按键一侧,开发板掉电。 - -电源选择开关 ESP-WROVER-KIT 开发板可通过 USB 端口或 5V 输入接口供电。用户可使用跳线帽在两种供电模式中进行选择。更多详细信息,请见章节 `设置选项`_ 中有关 JP7 连接器的描述。 - -5V Input 5V 电源接口建议仅在开发板自动运行(未连接 PC)时使用。仅用于全负荷工作下的后备电源。 - -5V Power On LED 当开发板通电后(USB 或外部 5V 供电),该红色指示灯将亮起。 - -LDO 5V-to-3.3V 低压差线型稳压器 NCP1117(1A)。NCP1117 最大电流输出为 1 A。板上 LDO 为固定输出电压,但用户也可以选用具有可变输出电压的 LDO。更多信息,请见 `ESP-WROVER-KIT V4.1 原理图`_。 - -摄像头连接器 摄像头接口,支持标准 OV7670 摄像头模块。 - -RGB LED 红绿蓝发光二极管,可由 PWM(脉冲宽度调制)控制。 - -I/O 连接器 板上模组的所有管脚均已引出至开发板的排针。用户可以对 ESP32 进行编程,实现 PWM、ADC、DAC、I2C、I2S、SPI 等多种功能。 - -MicroSD 卡槽 适用于需要扩充数据存储空间或进行备份的应用开发场景。 - -LCD 显示屏 支持贴装一款 3.2” 的 SPI(标准四线串行外设接口)LCD 显示器,请见 :ref:`get-started-esp-wrover-kit-v4.1-board-back`。 -==================== ====================================================================================================================================================================================================================================================================================================================================== - - -.. _get-started-esp-wrover-kit-v4.1-setup-options: - -设置选项 -------------- - -用户可通过 3 组排针,设置开发板功能,其中常见功能见下表: - -======= ================ ========================================================================= -排针 跳线设置 功能描述 -======= ================ ========================================================================= -JP7 |jp7-ext_5v| 使用外部电源为 ESP-WROVER-KIT 开发板供电 -JP7 |jp7-usb_5v| 使用 USB 端口为 ESP-WROVER-KIT 开发板供电 -JP2 |jp2-jtag| 使能 JTAG 功能 -JP2 |jp2-tx-rx| 使能 UART 通信 -JP14 |jp14| 使能 RTS/CTS 串口流控 -======= ================ ========================================================================= - - -ESP32 管脚分配 ------------------------- - -ESP32 模组的部分管脚/终端已被板上组件占用或用于外部硬件设备。如果某管脚对应的特定硬件未连接,则该管脚可用作他用。比如,摄像头/JP4 排针未连接相应硬件,则这些 GPIO 可用于其他用途。 - -部分管脚具备多个功能,可供板上组件或外部硬件设备同时使用,比如 GPIO0 和 GPIO2。由于管脚限制,一些外围设备不可同时使用,比如,由于 JTAG 和 SD 卡槽需共用部分管脚,因此一些使用 SD 卡功能的应用无法同时进行 JTAG 调试。 - -其他情况下,不同外设可同时使用。比如,LCD 屏幕和 SD 卡仅共用一个 GPIO21 管脚,可以同时使用。该管脚可为 LCD 屏幕提供 D/C(数据/控制)信号,并用于读取来自 SD 卡槽的 CD 信号(卡检测信号)。如无需使用卡检测功能,开发人员还可以通过移除 R167 来禁用该功能。此时,LCD 和 SD 卡槽可同时使用。 - -更多外设共享管脚的介绍,请见下一章节中的表格。 - - -主要 I/O 连接器 / JP1 -^^^^^^^^^^^^^^^^^^^^^^^^ - -JP1 连接器包括 14 x 2 个排针,具体功能可见下表中间 “I/O” 列的介绍。两侧的“共用”列则介绍了这些管脚在板上的其他用途。 - -===================== ===== ===== ===================== -共用 I/O I/O 共用 -===================== ===== ===== ===================== -n/a 3.3V GND n/a -NC/XTAL IO32 IO33 NC/XTAL -JTAG,MicroSD IO12 IO13 JTAG,MicroSD -JTAG,MicroSD IO14 IO27 摄像头 -摄像头 IO26 IO25 摄像头,LCD -摄像头 IO35 IO34 摄像头 -摄像头 IO39 IO36 摄像头 -JTAG EN IO23 摄像头,LCD -摄像头,LCD IO22 IO21 摄像头,LCD,MicroSD -摄像头,LCD IO19 IO18 摄像头,LCD -摄像头,LCD IO5 IO17 PSRAM -PSRAM IO16 IO4 LED,摄像头,MicroSD -摄像头,LED,Boot IO0 IO2 LED,MicroSD -JTAG,MicroSD IO15 5V -===================== ===== ===== ===================== - -说明: - -* NC/XTAL - :ref:`32.768 kHz 晶振 ` -* JTAG - :ref:`JTAG / JP8 ` -* Boot - Boot 按键 / SW2 -* 摄像头 - :ref:`摄像头 / JP4 ` -* LED - :ref:`RGB LED ` -* MicroSD - :ref:`MicroSD Card / J4 ` -* LCD - :ref:`LCD / U5 ` -* PSRAM - ESP32-WROVER-B 的 PSRAM - - -.. _get-started-esp-wrover-kit-v4.1-xtal: - -32.768 kHz 晶振 -^^^^^^^^^^^^^^^^^^^^^ - -==== ========== - . ESP32 管脚 -==== ========== -1. GPIO32 -2. GPIO33 -==== ========== - -.. note:: - - 默认情况下,管脚 GPIO32 和 GPIO33 已连接至晶振。因此,为了保证信号的完整性,这两个管脚并未连接至 JP1 I/O 连接器。用户可通过将 R11/R23 处的 0 欧电阻移至 R12/R24 处,以将 GP1O32 和 GPIO33 的连接从晶振移至 JP1。 - - -.. _get-started-esp-wrover-kit-v4.1-spi-flash-header: - -SPI Flash / JP2 -^^^^^^^^^^^^^^^ - -==== ============= -. ESP32 管脚 -==== ============= -1. CLK / GPIO6 -2. SD0 / GPIO7 -3. SD1 / GPIO8 -4. SD2 / GPIO9 -5. SD3 / GPIO10 -6. CMD / GPIO11 -==== ============= - -.. important:: - - 模组的 flash 总线已通过 0 欧电阻 R140 ~ R145 连接至排针 JP2。如果需要将 flash 的工作频率控制在 80 MHz,以达到保证总线信号完整性等目的,建议移除 R140 ~ R145 电阻,将模组的 flash 总线与排针 JP2 断开。 - - -.. _get-started-esp-wrover-kit-v4.1-jtag-header: - -JTAG / JP2 -^^^^^^^^^^ - -==== ============== ============= -. ESP32 管脚 JTAG 信号 -==== ============== ============= -1. EN TRST_N -2. MTMS / GPIO14 TMS -3. MTDO / GPIO15 TDO -4. MTDI / GPIO12 TDI -5. MTCK / GPIO13 TCK -==== ============== ============= - - -.. _get-started-esp-wrover-kit-v4.1-camera-header: - -摄像头 / JP4 -^^^^^^^^^^^^ - -==== ========== ============================= -. ESP32 管脚 摄像头信号 -==== ========== ============================= -1. n/a 3.3V -2. n/a 地 -3. GPIO27 SIO_C / SCCB 时钟 -4. GPIO26 SIO_D / SCCB 数据 -5. GPIO25 VSYNC / 垂直同步 -6. GPIO23 HREF / 水平参考 -7. GPIO22 PCLK / 像素时钟 -8. GPIO21 XCLK / 系统时钟 -9. GPIO35 D7 / 像素数据 Bit 7 -10. GPIO34 D6 / 像素数据 Bit 6 -11. GPIO39 D5 / 像素数据 Bit 5 -12. GPIO36 D4 / 像素数据 Bit 4 -13. GPIO19 D3 / 像素数据 Bit 3 -14. GPIO18 D2 / 像素数据 Bit 2 -15. GPIO5 D1 / 像素数据 Bit 1 -16. GPIO4 D0 / 像素数据 Bit 0 -17. GPIO0 RESET / 摄像头复位 -18. n/a PWDN / 摄像头断电 -==== ========== ============================= - -* D0 到 D7 为摄像头的数据总线 - - -.. _get-started-esp-wrover-kit-v4.1-rgb-led-connections: - -RGB LED -^^^^^^^ - -==== ========== ========= -. ESP32 管脚 RGB LED -==== ========== ========= -1. GPIO0 红色 -2. GPIO2 绿色 -3. GPIO4 蓝色 -==== ========== ========= - - -.. _get-started-esp-wrover-kit-v4.1-microsd-card-slot: - -MicroSD 卡 -^^^^^^^^^^^^ - -==== ============== =============== -. ESP32 管脚 MicroSD 信号 -==== ============== =============== -1. MTDI / GPIO12 DATA2 -2. MTCK / GPIO13 CD / DATA3 -3. MTDO / GPIO15 CMD -4. MTMS / GPIO14 CLK -5. GPIO2 DATA0 -6. GPIO4 DATA1 -7. GPIO21 CD -==== ============== =============== - - -.. _get-started-esp-wrover-kit-v4.1-lcd-connector: - -LCD / U5 -^^^^^^^^ - -==== ============== =============== -. ESP32 管脚 LCD 信号 -==== ============== =============== -1. GPIO18 复位 -2. GPIO19 SCL -3. GPIO21 D/C -4. GPIO22 CS -5. GPIO23 SDA -6. GPIO25 SDO -7. GPIO5 背光 -==== ============== =============== - - -.. _get-started-esp-wrover-kit-start-development: - -应用程序开发 ------------------------------ - -ESP-WROVER-KIT 上电前,请首先确认开发板完好无损。 - - -初始设置 -^^^^^^^^^^^^^ - -请严格按照下图所示连接跳线帽,注意不要额外连接其他跳线帽。 - -- 使用 JP7 连接器,选择 USB 为开发板供电。 - -- 使用 JP2 连接器,使能 UART 通信。 - -======================== ========================== -USB 供电 使能 UART 通信 -======================== ========================== -|jp7-usb_5v| |jp2-tx-rx| -======================== ========================== - -注意不要连接其他跳线帽。 - -打开 **电源开关**,**5V Power On LED** 应点亮。 - -正式开始开发 -^^^^^^^^^^^^^^^^^^ - -现在,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 - - -相关文档 ------------------ - -* `ESP-WROVER-KIT V4.1 原理图`_ (PDF) -* `《ESP32 技术规格书》 `_ (PDF) -* `《ESP32-WROVER-B 技术规格书》 `_ (PDF) -* :doc:`../api-guides/jtag-debugging/index` -* :doc:`../hw-reference/index` - -.. |jp7-ext_5v| image:: ../../_static/esp-wrover-kit-v4.1-jp7-ext_5v.jpg -.. |jp7-usb_5v| image:: ../../_static/esp-wrover-kit-v4.1-jp7-usb_5v.jpg -.. |jp2-jtag| image:: ../../_static/esp-wrover-kit-v4.1-jp2-jtag.jpg -.. |jp2-tx-rx| image:: ../../_static/esp-wrover-kit-v4.1-jp2-tx-rx.jpg -.. |jp14| image:: ../../_static/esp-wrover-kit-v4.1-jp14.jpg - -.. _ESP-WROVER-KIT V4.1 原理图: https://dl.espressif.com/dl/schematics/ESP-WROVER-KIT_V4_1.pdf - -.. toctree:: - :hidden: - - get-started-wrover-kit-v3.rst - get-started-wrover-kit-v2.rst \ No newline at end of file diff --git a/docs/zh_CN/get-started/index.rst b/docs/zh_CN/get-started/index.rst index 8c7ca716ec..6afcc12e3c 100644 --- a/docs/zh_CN/get-started/index.rst +++ b/docs/zh_CN/get-started/index.rst @@ -57,9 +57,9 @@ ESP32 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、 .. toctree:: :maxdepth: 1 - ESP32-DevKitC - ESP-WROVER-KIT - ESP32-PICO-KIT + ESP32-DevKitC <../hw-reference/get-started-devkitc> + ESP-WROVER-KIT <../hw-reference/get-started-wrover-kit> + ESP32-PICO-KIT <../hw-reference/get-started-pico-kit> ESP32-Ethernet-Kit <../hw-reference/get-started-ethernet-kit> diff --git a/docs/zh_CN/get-started-cmake/get-started-devkitc-v2.rst b/docs/zh_CN/hw-reference/get-started-devkitc-v2.rst similarity index 90% rename from docs/zh_CN/get-started-cmake/get-started-devkitc-v2.rst rename to docs/zh_CN/hw-reference/get-started-devkitc-v2.rst index 6b5cefdf13..f0ca5c62cf 100644 --- a/docs/zh_CN/get-started-cmake/get-started-devkitc-v2.rst +++ b/docs/zh_CN/hw-reference/get-started-devkitc-v2.rst @@ -1,4 +1,4 @@ -ESP32-DevKitC V2 入门指南 (CMake) +ESP32-DevKitC V2 入门指南 ================================== :link_to_translation:`en: [English]` @@ -71,7 +71,10 @@ ESP32-DevKitC V2 开发板 ESP32-DevKitC V2 上电前,请首先确认开发板完好无损。 -之后,请前往 :doc:`index` 的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 +之后,请前往 :doc:`../get-started-cmake/index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 + +如需使用较早 GNU Make 编译系统,则请参考 :ref:`get-started-step-by-step` 章节。 + 相关文档 -------- diff --git a/docs/zh_CN/get-started-cmake/get-started-devkitc.rst b/docs/zh_CN/hw-reference/get-started-devkitc.rst similarity index 93% rename from docs/zh_CN/get-started-cmake/get-started-devkitc.rst rename to docs/zh_CN/hw-reference/get-started-devkitc.rst index 1305bbe304..5e0f160cff 100644 --- a/docs/zh_CN/get-started-cmake/get-started-devkitc.rst +++ b/docs/zh_CN/hw-reference/get-started-devkitc.rst @@ -1,4 +1,4 @@ -ESP32-DevKitC V4 入门指南 (CMake) +ESP32-DevKitC V4 入门指南 ============================================= :link_to_translation:`en: [English]` @@ -121,7 +121,9 @@ C15(黄色)在 ESP32-DevKitC V4 开发板上的位置 ESP32-DevKitC V4 上电前,请首先确认开发板完好无损。 -之后,请前往 :doc:`index` 的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 +之后,请前往 :doc:`../get-started-cmake/index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 + +如需使用较早 GNU Make 编译系统,则请参考 :ref:`get-started-step-by-step` 章节。 开发板尺寸 diff --git a/docs/zh_CN/get-started-cmake/get-started-pico-kit-v3.rst b/docs/zh_CN/hw-reference/get-started-pico-kit-v3.rst similarity index 90% rename from docs/zh_CN/get-started-cmake/get-started-pico-kit-v3.rst rename to docs/zh_CN/hw-reference/get-started-pico-kit-v3.rst index e92f4cce75..99b70fe898 100644 --- a/docs/zh_CN/get-started-cmake/get-started-pico-kit-v3.rst +++ b/docs/zh_CN/hw-reference/get-started-pico-kit-v3.rst @@ -1,4 +1,4 @@ -ESP32-PICO-KIT V3 入门指南(CMake) +ESP32-PICO-KIT V3 入门指南 ======================================= :link_to_translation:`en:[English]` @@ -65,7 +65,9 @@ EN 复位按键。 ESP32-PICO-KIT V3 上电前,请首先确认开发板完好无损。 -之后,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 +之后,请前往 :doc:`../get-started-cmake/index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 + +如需使用较早 GNU Make 编译系统,则请参考 :ref:`get-started-step-by-step` 章节。 相关文档 diff --git a/docs/zh_CN/get-started-cmake/get-started-pico-kit.rst b/docs/zh_CN/hw-reference/get-started-pico-kit.rst similarity index 97% rename from docs/zh_CN/get-started-cmake/get-started-pico-kit.rst rename to docs/zh_CN/hw-reference/get-started-pico-kit.rst index 7e8e72e8fd..a07b5b5785 100644 --- a/docs/zh_CN/get-started-cmake/get-started-pico-kit.rst +++ b/docs/zh_CN/hw-reference/get-started-pico-kit.rst @@ -1,4 +1,4 @@ -ESP32-PICO-KIT V4/V4.1 入门指南(CMake) +ESP32-PICO-KIT V4/V4.1 入门指南 ======================================================= :link_to_translation:`en:[English]` @@ -190,7 +190,9 @@ No. Name Type Function ESP32-PICO-KIT 上电前,请首先确认开发板完好无损。 -之后,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例目烧录至您的开发板。 +之后,请前往 :doc:`../get-started-cmake/index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 + +如需使用较早 GNU Make 编译系统,则请参考 :ref:`get-started-step-by-step` 章节。 开发板尺寸 diff --git a/docs/zh_CN/get-started-cmake/get-started-wrover-kit-v2.rst b/docs/zh_CN/hw-reference/get-started-wrover-kit-v2.rst similarity index 97% rename from docs/zh_CN/get-started-cmake/get-started-wrover-kit-v2.rst rename to docs/zh_CN/hw-reference/get-started-wrover-kit-v2.rst index f19573290d..1dcce65b90 100644 --- a/docs/zh_CN/get-started-cmake/get-started-wrover-kit-v2.rst +++ b/docs/zh_CN/hw-reference/get-started-wrover-kit-v2.rst @@ -1,4 +1,4 @@ -ESP-WROVER-KIT V2 入门指南(CMake) +ESP-WROVER-KIT V2 入门指南 =========================================== :link_to_translation:`en:[English]` @@ -167,7 +167,9 @@ USB 供电 使能 UART 通信 正式开始开发 ^^^^^^^^^^^^^^^^^^ -现在,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 +请前往 :doc:`../get-started-cmake/index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 + +如需使用较早 GNU Make 编译系统,则请参考 :ref:`get-started-step-by-step` 章节。 相关文档 diff --git a/docs/zh_CN/get-started-cmake/get-started-wrover-kit-v3.rst b/docs/zh_CN/hw-reference/get-started-wrover-kit-v3.rst similarity index 98% rename from docs/zh_CN/get-started-cmake/get-started-wrover-kit-v3.rst rename to docs/zh_CN/hw-reference/get-started-wrover-kit-v3.rst index 3254f1b11f..57a72931b0 100644 --- a/docs/zh_CN/get-started-cmake/get-started-wrover-kit-v3.rst +++ b/docs/zh_CN/hw-reference/get-started-wrover-kit-v3.rst @@ -1,4 +1,4 @@ -ESP-WROVER-KIT V3 入门指南(CMake) +ESP-WROVER-KIT V3 入门指南 ======================================= :link_to_translation:`en:[English]` @@ -351,7 +351,9 @@ USB 供电 使能 UART 通信 正式开始开发 ^^^^^^^^^^^^^^^^^^ -现在,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 +请前往 :doc:`../get-started-cmake/index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 + +如需使用较早 GNU Make 编译系统,则请参考 :ref:`get-started-step-by-step` 章节。 相关文档 diff --git a/docs/zh_CN/get-started-cmake/get-started-wrover-kit.rst b/docs/zh_CN/hw-reference/get-started-wrover-kit.rst similarity index 98% rename from docs/zh_CN/get-started-cmake/get-started-wrover-kit.rst rename to docs/zh_CN/hw-reference/get-started-wrover-kit.rst index e2d5ce9199..b08547841d 100644 --- a/docs/zh_CN/get-started-cmake/get-started-wrover-kit.rst +++ b/docs/zh_CN/hw-reference/get-started-wrover-kit.rst @@ -1,4 +1,4 @@ -ESP-WROVER-KIT V4.1 入门指南(CMake) +ESP-WROVER-KIT V4.1 入门指南 ========================================= :link_to_translation:`en:[English]` @@ -356,7 +356,9 @@ USB 供电 使能 UART 通信 正式开始开发 ^^^^^^^^^^^^^^^^^^ -现在,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 +请前往 :doc:`../get-started-cmake/index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 + +如需使用较早 GNU Make 编译系统,则请参考 :ref:`get-started-step-by-step` 章节。 相关文档 From 471f4b2f0e5e669ac20bd8eeb18f77986cc998a0 Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Mon, 1 Apr 2019 12:30:10 +0800 Subject: [PATCH 234/486] zh_CN translation of fatal_error --- docs/en/api-guides/build-system-cmake.rst | 1 + docs/en/api-guides/fatal-errors.rst | 1 + docs/zh_CN/api-guides/fatal-errors.rst | 302 +++++++++++++++++++++- docs/zh_CN/api-guides/index.rst | 2 +- 4 files changed, 304 insertions(+), 2 deletions(-) diff --git a/docs/en/api-guides/build-system-cmake.rst b/docs/en/api-guides/build-system-cmake.rst index a8d124daa1..ec63c0fc41 100644 --- a/docs/en/api-guides/build-system-cmake.rst +++ b/docs/en/api-guides/build-system-cmake.rst @@ -2,6 +2,7 @@ Build System (CMake) ******************** :link_to_translation:`zh_CN:[中文]` + .. include:: ../cmake-warning.rst .. include:: ../cmake-pending-features.rst diff --git a/docs/en/api-guides/fatal-errors.rst b/docs/en/api-guides/fatal-errors.rst index b6e90c6dcf..c64268fb76 100644 --- a/docs/en/api-guides/fatal-errors.rst +++ b/docs/en/api-guides/fatal-errors.rst @@ -1,5 +1,6 @@ Fatal Errors ============ +:link_to_translation:`zh_CN:[中文]` Overview -------- diff --git a/docs/zh_CN/api-guides/fatal-errors.rst b/docs/zh_CN/api-guides/fatal-errors.rst index e9e5b71701..211658f689 100644 --- a/docs/zh_CN/api-guides/fatal-errors.rst +++ b/docs/zh_CN/api-guides/fatal-errors.rst @@ -1 +1,301 @@ -.. include:: ../../en/api-guides/fatal-errors.rst \ No newline at end of file +严重错误 +======== +:link_to_translation:`en:[English]` + +.. _Overview: + +概述 +---- + +在某些情况下,程序并不会按照我们的预期运行,在 ESP-IDF 中,这些情况包括: + +- CPU 异常:非法指令,加载/存储时的内存对齐错误,加载/存储时的访问权限错误,双重异常。 +- 系统级检查错误: + + - :doc:`中断看门狗 <../api-reference/system/wdts>` 超时 + - :doc:`任务看门狗 <../api-reference/system/wdts>` 超时(只有开启 :ref:`CONFIG_ESP_TASK_WDT_PANIC` 后才会触发严重错误) + - 高速缓存访问错误 + - 掉电检测事件 + - 堆栈溢出 + - Stack 粉碎保护检查 + - Heap 完整性检查 + +- 使用 ``assert``、``configASSERT`` 等类似的宏断言失败。 + +本指南会介绍 ESP-IDF 中这类错误的处理流程,并给出对应的解决建议。 + +紧急处理程序 +------------ + +:ref:`Overview` 中列举的所有错误都会由 *紧急处理程序(Panic Handler)* 负责处理。 + +紧急处理程序首先会将出错原因打印到控制台,例如 CPU 异常的错误信息通常会类似于:: + + Guru Meditation Error: Core 0 panic'ed (IllegalInstruction). Exception was unhandled. + +对于一些系统级检查错误(如中断看门狗超时,高速缓存访问错误等),错误信息会类似于:: + + Guru Meditation Error: Core 0 panic'ed (Cache disabled but cached memory region accessed) + +不管哪种情况,错误原因都会被打印在括号中。请参阅 :ref:`Guru-Meditation-Errors` 以查看所有可能的出错原因。 + +紧急处理程序接下来的行为将取决于 :ref:`CONFIG_ESP32_PANIC` 的设置,支持的选项包括: + +- 打印 CPU 寄存器,然后重启(``CONFIG_ESP32_PANIC_PRINT_REBOOT``)- 默认选项 + + 打印系统发生异常时 CPU 寄存器的值,打印回溯,最后重启芯片。 + +- 打印 CPU 寄存器,然后暂停(``CONFIG_ESP32_PANIC_PRINT_HALT``) + + 与上一个选项类似,但不会重启,而是选择暂停程序的运行。重启程序需要外部执行复位操作。 + +- 静默重启(``CONFIG_ESP32_PANIC_SILENT_REBOOT``) + + 不打印 CPU 寄存器的值,也不打印回溯,立即重启芯片。 + +- 调用 GDB Stub(``CONFIG_ESP32_PANIC_GDBSTUB``) + + 启动 GDB 服务器,通过控制台 UART 接口与 GDB 进行通信。详细信息请参阅 :ref:`GDB-Stub`。 + +紧急处理程序的行为还受到另外两个配置项的影响: + +- 如果 :ref:`CONFIG_ESP32_DEBUG_OCDAWARE` 被使能了(默认),紧急处理程序会检测 ESP32 是否已经连接 JTAG 调试器。如果检测成功,程序会暂停运行,并将控制权交给调试器。在这种情况下,寄存器和回溯不会被打印到控制台,并且也不会使用 GDB Stub 和 Core Dump 的功能。 + +- 如果使能了 :doc:`Core Dump ` 功能(``CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH`` 或者 ``CONFIG_ESP32_ENABLE_COREDUMP_TO_UART`` 选项),系统状态(任务堆栈和寄存器)会被转储到 Flash 或者 UART 以供后续分析。 + +下图展示了紧急处理程序的行为: + +.. blockdiag:: + :scale: 100% + :caption: 紧急处理程序流程图(点击放大) + :align: center + + blockdiag panic-handler { + orientation = portrait; + edge_layout = flowchart; + default_group_color = white; + node_width = 160; + node_height = 60; + + cpu_exception [label = "CPU 异常", shape=roundedbox]; + sys_check [label = "Cache 错误,\nInterrupt WDT,\nabort()", shape=roundedbox]; + check_ocd [label = "JTAG 调试器\n已连接?", shape=diamond, height=80]; + print_error_cause [label = "打印出错原因"]; + use_jtag [label = "发送信号给 JTAG 调试器", shape=roundedbox]; + dump_registers [label = "打印寄存器\n和回溯"]; + check_coredump [label = "Core dump\n使能?", shape=diamond, height=80]; + do_coredump [label = "Core dump 至 UART 或者 Flash"]; + check_gdbstub [label = "GDB Stub\n使能?", shape=diamond, height=80]; + do_gdbstub [label = "启动 GDB Stub", shape=roundedbox]; + halt [label = "暂停", shape=roundedbox]; + reboot [label = "重启", shape=roundedbox]; + check_halt [label = "暂停?", shape=diamond, height=80]; + + group {cpu_exception, sys_check}; + + cpu_exception -> print_error_cause; + sys_check -> print_error_cause; + print_error_cause -> check_ocd; + check_ocd -> use_jtag [label = "Yes"]; + check_ocd -> dump_registers [label = "No"]; + dump_registers -> check_coredump + check_coredump -> do_coredump [label = "Yes"]; + do_coredump -> check_gdbstub; + check_coredump -> check_gdbstub [label = "No"]; + check_gdbstub -> check_halt [label = "No"]; + check_gdbstub -> do_gdbstub [label = "Yes"]; + check_halt -> halt [label = "Yes"]; + check_halt -> reboot [label = "No"]; + } + +寄存器转储与回溯 +---------------- + +除非启用了 ``CONFIG_ESP32_PANIC_SILENT_REBOOT`` 否则紧急处理程序会将 CPU 寄存器和回溯打印到控制台:: + + Core 0 register dump: + PC : 0x400e14ed PS : 0x00060030 A0 : 0x800d0805 A1 : 0x3ffb5030 + A2 : 0x00000000 A3 : 0x00000001 A4 : 0x00000001 A5 : 0x3ffb50dc + A6 : 0x00000000 A7 : 0x00000001 A8 : 0x00000000 A9 : 0x3ffb5000 + A10 : 0x00000000 A11 : 0x3ffb2bac A12 : 0x40082d1c A13 : 0x06ff1ff8 + A14 : 0x3ffb7078 A15 : 0x00000000 SAR : 0x00000014 EXCCAUSE: 0x0000001d + EXCVADDR: 0x00000000 LBEG : 0x4000c46c LEND : 0x4000c477 LCOUNT : 0xffffffff + + Backtrace: 0x400e14ed:0x3ffb5030 0x400d0802:0x3ffb5050 + +仅会打印异常帧中 CPU 寄存器的值,即引发 CPU 异常或者其它严重错误时刻的值。 + +紧急处理程序如果是因 abort() 而调用,则不会打印寄存器转储。 + +在某些情况下,例如中断看门狗超时,紧急处理程序会额外打印 CPU 寄存器(EPC1-EPC4)的值,以及另一个 CPU 的寄存器值和代码回溯。 + +回溯行包含了当前任务中每个堆栈帧的 PC:SP 对(PC 是程序计数器,SP 是堆栈指针)。如果在 ISR 中发生了严重错误,回溯会同时包括被中断任务的 PC:SP 对,以及 ISR 中的 PC:SP 对。 + +如果使用了 :doc:`IDF 监视器 `,该工具会将程序计数器的值转换为对应的代码位置(函数名,文件名,行号),并加以注释:: + + Core 0 register dump: + PC : 0x400e14ed PS : 0x00060030 A0 : 0x800d0805 A1 : 0x3ffb5030 + 0x400e14ed: app_main at /Users/user/esp/example/main/main.cpp:36 + + A2 : 0x00000000 A3 : 0x00000001 A4 : 0x00000001 A5 : 0x3ffb50dc + A6 : 0x00000000 A7 : 0x00000001 A8 : 0x00000000 A9 : 0x3ffb5000 + A10 : 0x00000000 A11 : 0x3ffb2bac A12 : 0x40082d1c A13 : 0x06ff1ff8 + 0x40082d1c: _calloc_r at /Users/user/esp/esp-idf/components/newlib/syscalls.c:51 + + A14 : 0x3ffb7078 A15 : 0x00000000 SAR : 0x00000014 EXCCAUSE: 0x0000001d + EXCVADDR: 0x00000000 LBEG : 0x4000c46c LEND : 0x4000c477 LCOUNT : 0xffffffff + + Backtrace: 0x400e14ed:0x3ffb5030 0x400d0802:0x3ffb5050 + 0x400e14ed: app_main at /Users/user/esp/example/main/main.cpp:36 + + 0x400d0802: main_task at /Users/user/esp/esp-idf/components/esp32/cpu_start.c:470 + +若要查找发生严重错误的代码位置,请查看 "Backtrace" 的后面几行,发生严重错误的代码显示在顶行,后续几行显示的是调用堆栈。 + +.. _GDB-Stub: + +GDB Stub +-------- + +如果启用了 ``CONFIG_ESP32_PANIC_GDBSTUB`` 选项,在发生严重错误时,紧急处理程序不会复位芯片,相反,它将启动 GDB 远程协议服务器,通常称为 GDB Stub。发生这种情况时,可以让主机上运行的 GDB 实例通过 UART 端口连接到 ESP32。 + +如果使用了 :doc:`IDF 监视器 `,该工具会在 UART 端口检测到 GDB Stub 提示符后自动启动 GDB,输出会类似于:: + + Entering gdb stub now. + $T0b#e6GNU gdb (crosstool-NG crosstool-ng-1.22.0-80-gff1f415) 7.10 + Copyright (C) 2015 Free Software Foundation, Inc. + License GPLv3+: GNU GPL version 3 or later + This is free software: you are free to change and redistribute it. + There is NO WARRANTY, to the extent permitted by law. Type "show copying" + and "show warranty" for details. + This GDB was configured as "--host=x86_64-build_apple-darwin16.3.0 --target=xtensa-esp32-elf". + Type "show configuration" for configuration details. + For bug reporting instructions, please see: + . + Find the GDB manual and other documentation resources online at: + . + For help, type "help". + Type "apropos word" to search for commands related to "word"... + Reading symbols from /Users/user/esp/example/build/example.elf...done. + Remote debugging using /dev/cu.usbserial-31301 + 0x400e1b41 in app_main () + at /Users/user/esp/example/main/main.cpp:36 + 36 *((int*) 0) = 0; + (gdb) + +在 GDB 会话中,我们可以检查 CPU 寄存器,本地和静态变量以及内存中任意位置的值。但是不支持设置断点,改变 PC 值或者恢复程序的运行。若要复位程序,请退出 GDB 会话,在 IDF 监视器 中连续输入 Ctrl-T Ctrl-R,或者按下开发板上的复位按键也可以重新运行程序。 + +.. _Guru-Meditation-Errors: + +Guru Meditation 错误 +-------------------- + +.. Note to editor: titles of the following section need to match exception causes printed by the panic handler. Do not change the titles (insert spaces, reword, etc.) unless panic handler messages are also changed. + +.. Note to translator: When translating this section, avoid translating the following section titles. "Guru Meditation" in the title of this section should also not be translated. Keep these two notes when translating. + +本节将对打印在 ``Guru Meditation Error: Core panic'ed`` 后面括号中的致错原因进行逐一解释。 + +.. note:: 想要了解 "Guru Meditation" 的历史渊源,请参阅 `维基百科 `_ 。 + + +IllegalInstruction +^^^^^^^^^^^^^^^^^^ + +此 CPU 异常表示当前执行的指令不是有效指令,引起此错误的常见原因包括: + +- FreeRTOS 中的任务函数已返回。在 FreeRTOS 中,如果想终止任务函数,需要调用 :cpp:func:`vTaskDelete` 函数释放当前任务的资源,而不是直接返回。 + +- 无法从 SPI Flash 中加载下一条指令,这通常发生在: + + - 应用程序将 SPI Flash 的引脚重新配置为其它功能(如 GPIO,UART 等等)。有关 SPI Flash 引脚的详细信息,请参阅硬件设计指南和芯片/模组的数据手册。 + + - 某些外部设备意外连接到 SPI Flash 的引脚上,干扰了 ESP32 和 SPI Flash 之间的通信。 + + +InstrFetchProhibited +^^^^^^^^^^^^^^^^^^^^ + +此 CPU 异常表示 CPU 无法加载指令,因为指令的地址不在 IRAM 或者 IROM 中的有效区域中。 + +通常这意味着代码中调用了并不指向有效代码块的函数指针。这种情况下,可以查看 ``PC`` (程序计数器)寄存器的值并做进一步判断:若为 0 或者其它非法值(即只要不是 ``0x4xxxxxxx`` 的情况),则证实确实是该原因。 + +LoadProhibited, StoreProhibited +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +当应用程序尝试读取或写入无效的内存位置时,会发生此类 CPU 异常。此类无效内存地址可以在寄存器转储的 ``EXCVADDR`` 中找到。如果该地址为零,通常意味着应用程序正尝试解引用一个 NULL 指针。如果该地址接近于零,则通常意味着应用程序尝试访问某个结构体的成员,但是该结构体的指针为 NULL。如果该地址是其它非法值(不在 ``0x3fxxxxxx`` - ``0x6xxxxxxx`` 的范围内),则可能意味着用于访问数据的指针未初始化或者已经损坏。 + +IntegerDivideByZero +^^^^^^^^^^^^^^^^^^^ + +应用程序尝试将整数除以零。 + +LoadStoreAlignment +^^^^^^^^^^^^^^^^^^ + +应用程序尝试读取/写入的内存位置不符合加载/存储指令对字节对齐大小的要求,例如,32 位加载指令只能访问 4 字节对齐的内存地址,而 16 位加载指令只能访问 2 字节对齐的内存地址。 + +LoadStoreError +^^^^^^^^^^^^^^ + +应用程序尝试从仅支持 32 位加载/存储的内存区域执行 8 位或 16 位加载/存储操作,例如,解引用一个指向指令内存区域的 ``char*`` 指针就会导致这样的错误。 + +Unhandled debug exception +^^^^^^^^^^^^^^^^^^^^^^^^^ + +这后面通常会再跟一条消息:: + + Debug exception reason: Stack canary watchpoint triggered (task_name) + +此错误表示应用程序写入的位置越过了 ``task_name`` 任务堆栈的末尾,请注意,并非每次堆栈溢出都会触发此错误。任务有可能会绕过堆栈金丝雀(stack canary)的位置访问堆栈,在这种情况下,监视点就不会被触发。 + +Interrupt wdt timeout on CPU0 / CPU1 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +这表示发生了中断看门狗超时,详细信息请查阅 :doc:`看门狗 <../api-reference/system/wdts>` 文档。 + +Cache disabled but cached memory region accessed +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +在某些情况下,ESP-IDF 会暂时禁止通过高速缓存访问外部 SPI Flash 和 SPI RAM,例如在使用 spi_flash API 读取/写入/擦除/映射 SPI Flash 的时候。在这些情况下,任务会被挂起,并且未使用 ``ESP_INTR_FLAG_IRAM`` 注册的中断处理程序会被禁用。请确保任何使用此标志注册的中断处理程序所访问的代码和数据分别位于 IRAM 和 DRAM 中。更多详细信息请参阅 :ref:`SPI Flash API 文档 `。 + +其它严重错误 +------------ + +欠压 +^^^^ + +ESP32 内部集成掉电检测电路,并且会默认启用。如果电源电压低于安全值,掉电检测器可以触发系统复位。掉电检测器可以使用 :ref:`CONFIG_ESP32_BROWNOUT_DET` 和 :ref:`CONFIG_ESP32_BROWNOUT_DET_LVL_SEL` 这两个选项进行设置。 +当掉电检测器被触发时,会打印如下信息:: + + Brownout detector was triggered + +芯片会在该打印信息结束后复位。 + +请注意,如果电源电压快速下降,则只能在控制台上看到部分打印信息。 + +Heap 不完整 +^^^^^^^^^^^ + +ESP-IDF 堆的实现包含许多运行时的堆结构检查,可以在 menuconfig 中开启额外的检查(“Heap Poisoning”)。如果其中的某项检查失败,则会打印类似如下信息:: + + CORRUPT HEAP: Bad tail at 0x3ffe270a. Expected 0xbaad5678 got 0xbaac5678 + assertion "head != NULL" failed: file "/Users/user/esp/esp-idf/components/heap/multi_heap_poisoning.c", line 201, function: multi_heap_free + abort() was called at PC 0x400dca43 on core 0 + +更多详细信息,请查阅 :doc:`堆内存调试 <../api-reference/system/heap_debug>` 文档。 + +Stack 粉碎 +^^^^^^^^^^ + +Stack 粉碎保护(基于 GCC ``-fstack-protector*`` 标志)可以通过 ESP-IDF 中的 :ref:`CONFIG_COMPILER_STACK_CHECK_MODE` 选项来开启。如果检测到 Stack 粉碎,则会打印类似如下的信息:: + + Stack smashing protect failure! + + abort() was called at PC 0x400d2138 on core 0 + + Backtrace: 0x4008e6c0:0x3ffc1780 0x4008e8b7:0x3ffc17a0 0x400d2138:0x3ffc17c0 0x400e79d5:0x3ffc17e0 0x400e79a7:0x3ffc1840 0x400e79df:0x3ffc18a0 0x400e2235:0x3ffc18c0 0x400e1916:0x3ffc18f0 0x400e19cd:0x3ffc1910 0x400e1a11:0x3ffc1930 0x400e1bb2:0x3ffc1950 0x400d2c44:0x3ffc1a80 + 0 + +回溯信息会指明发生 Stack 粉碎的函数,建议检查函数中是否有代码访问本地数组时发生了越界。 + diff --git a/docs/zh_CN/api-guides/index.rst b/docs/zh_CN/api-guides/index.rst index c6f9690c2a..a454616787 100644 --- a/docs/zh_CN/api-guides/index.rst +++ b/docs/zh_CN/api-guides/index.rst @@ -9,7 +9,7 @@ API 指南 构建系统 构建系统 (CMake) 错误处理 - Fatal Errors + 严重错误 Event Handling Deep Sleep Wake Stubs ESP32 Core Dump From 9ecd0436f54c9225d53e1072e6126bd472472c3e Mon Sep 17 00:00:00 2001 From: He Yin Ling Date: Thu, 4 Jul 2019 15:06:00 +0800 Subject: [PATCH 235/486] tools: fix idf_tools.py exception with python3 use `subprocess.Popen` when catch TypeError: ``` Traceback (most recent call last): File "tools/idf_tools.py", line 1249, in main(sys.argv[1:]) File "tools/idf_tools.py", line 1245, in main action_func(args) File "tools/idf_tools.py", line 1038, in action_install tool_obj.find_installed_versions() File "tools/idf_tools.py", line 468, in find_installed_versions ver_str = self.check_version() File "tools/idf_tools.py", line 426, in check_version version_cmd_result = run_cmd_check_output(cmd, None, extra_paths) File "tools/idf_tools.py", line 176, in run_cmd_check_output result = subprocess.run(cmd, capture_output=True, check=True, input=input_text) File "/opt/pyenv/pyenv-1.2.6/versions/3.5.5/lib/python3.5/subprocess.py", line 383, in run with Popen(*popenargs, **kwargs) as process: TypeError: __init__() got an unexpected keyword argument 'capture_output' ``` --- tools/idf_tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/idf_tools.py b/tools/idf_tools.py index 30ed7b6389..c005ecd6f4 100755 --- a/tools/idf_tools.py +++ b/tools/idf_tools.py @@ -175,7 +175,7 @@ def run_cmd_check_output(cmd, input_text=None, extra_paths=None): input_text = input_text.encode() result = subprocess.run(cmd, capture_output=True, check=True, input=input_text) return result.stdout + result.stderr - except AttributeError: + except (AttributeError, TypeError): p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate(input_text) if p.returncode != 0: From 50af558df9072e2247d44cfa09c5061be313d34e Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Mon, 10 Jun 2019 12:00:46 +0800 Subject: [PATCH 236/486] update pm document with changes in bluetooth that supports automatic light sleep in case that external 32.768KHz crystal is used as the sleep clock If bluetooth modem sleep is enabled and "External 32kHz crystal" is used as bluetooth sleep clock, the power management lock "ESP_PM_NO_LIGHT_SLEEP" in bluetooth is released for the periods of time when Bluetooth enters modem sleep. In this case automatic light sleep is allowed. --- docs/en/api-reference/system/power_management.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/api-reference/system/power_management.rst b/docs/en/api-reference/system/power_management.rst index 95d5ccc79d..a10b9b03bc 100644 --- a/docs/en/api-reference/system/power_management.rst +++ b/docs/en/api-reference/system/power_management.rst @@ -127,7 +127,7 @@ The following drivers will hold the ``ESP_PM_APB_FREQ_MAX`` lock while the drive - **SPI slave**: between calls to :cpp:func:`spi_slave_initialize` and :cpp:func:`spi_slave_free`. - **Ethernet**: between calls to :cpp:func:`esp_eth_enable` and :cpp:func:`esp_eth_disable`. - **WiFi**: between calls to :cpp:func:`esp_wifi_start` and :cpp:func:`esp_wifi_stop`. If modem sleep is enabled, the lock will be released for the periods of time when radio is disabled. -- **Bluetooth**: between calls to :cpp:func:`esp_bt_controller_enable` and :cpp:func:`esp_bt_controller_disable`. If Bluetooth modem sleep is enabled, the ``ESP_PM_APB_FREQ_MAX`` lock will be released for the periods of time when radio is disabled. However the ``ESP_PM_NO_LIGHT_SLEEP`` lock will still be held. +- **Bluetooth**: between calls to :cpp:func:`esp_bt_controller_enable` and :cpp:func:`esp_bt_controller_disable`. If Bluetooth modem sleep is enabled, the ``ESP_PM_APB_FREQ_MAX`` lock will be released for the periods of time when radio is disabled. However the ``ESP_PM_NO_LIGHT_SLEEP`` lock will still be held, unless :ref:`CONFIG_BTDM_LOW_POWER_CLOCK` option is set to "External 32kHz crystal". - **CAN**: between calls to :cpp:func:`can_driver_install` and :cpp:func:`can_driver_uninstall`. The following peripheral drivers are not aware of DFS yet. Applications need to acquire/release locks themselves, when necessary: From a626061f3c2468710c29634273071c7692e76c22 Mon Sep 17 00:00:00 2001 From: He Yin Ling Date: Thu, 4 Jul 2019 16:30:42 +0800 Subject: [PATCH 237/486] tools: fix exception in checkout ref script: decode bytes before searching with RegEx --- tools/ci/checkout_project_ref.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/tools/ci/checkout_project_ref.py b/tools/ci/checkout_project_ref.py index 5b6b332c9c..e9c060a1b0 100755 --- a/tools/ci/checkout_project_ref.py +++ b/tools/ci/checkout_project_ref.py @@ -34,16 +34,20 @@ def target_branch_candidates(proj_name): except (KeyError, TypeError): pass # branch name read from IDF - git_describe = subprocess.check_output(["git", "describe", "--tags", "HEAD"]) - match = IDF_GIT_DESCRIBE_PATTERN.search(git_describe) - if match: - major_revision = match.group(1) - minor_revision = match.group(2) - # release branch - candidates.append("release/v{}.{}".format(major_revision, minor_revision)) - # branch to match all major branches, like v3.x or v3 - candidates.append("release/v{}.x".format(major_revision)) - candidates.append("release/v{}".format(major_revision)) + try: + git_describe = subprocess.check_output(["git", "describe", "--tags", "HEAD"]) + match = IDF_GIT_DESCRIBE_PATTERN.search(git_describe.decode()) + if match: + major_revision = match.group(1) + minor_revision = match.group(2) + # release branch + candidates.append("release/v{}.{}".format(major_revision, minor_revision)) + # branch to match all major branches, like v3.x or v3 + candidates.append("release/v{}.x".format(major_revision)) + candidates.append("release/v{}".format(major_revision)) + except subprocess.CalledProcessError: + # this should not happen as IDF should have describe message + pass return [c for c in candidates if c] # filter out null value From 3bd4003e98a20e0aba39a76fa28dba1a69d400a2 Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Wed, 3 Jul 2019 13:51:53 +0200 Subject: [PATCH 238/486] tools: Fix hex parsing in confgen.py Closes https://github.com/espressif/esp-idf/issues/3568 --- tools/kconfig_new/confgen.py | 4 +++- tools/kconfig_new/test/Kconfig | 6 ++++++ tools/kconfig_new/test/testcases_v1.txt | 4 ++-- tools/kconfig_new/test/testcases_v2.txt | 4 ++-- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/tools/kconfig_new/confgen.py b/tools/kconfig_new/confgen.py index d4e8752902..0765c9f890 100755 --- a/tools/kconfig_new/confgen.py +++ b/tools/kconfig_new/confgen.py @@ -475,7 +475,9 @@ def write_json_menus(deprecated_options, config, filename): # should have one condition which is true for min_range, max_range, cond_expr in sym.ranges: if kconfiglib.expr_value(cond_expr): - greatest_range = [int(min_range.str_value), int(max_range.str_value)] + base = 16 if sym.type == kconfiglib.HEX else 10 + greatest_range = [int(min_range.str_value, base), int(max_range.str_value, base)] + break new_json = { "type": kconfiglib.TYPE_TO_STR[sym.type], diff --git a/tools/kconfig_new/test/Kconfig b/tools/kconfig_new/test/Kconfig index 6462fe82de..8529fd5208 100644 --- a/tools/kconfig_new/test/Kconfig +++ b/tools/kconfig_new/test/Kconfig @@ -41,6 +41,12 @@ menu "Test config" range 0 10 default 1 + config TEST_CONDITIONAL_HEX_RANGES + hex "Something with a hex range" + range 0x00 0xaf if TEST_BOOL + range 0x10 0xaf + default 0xa0 + config SUBMENU_TRIGGER bool "I enable/disable some submenu items" default y diff --git a/tools/kconfig_new/test/testcases_v1.txt b/tools/kconfig_new/test/testcases_v1.txt index 4563d49280..0f68536cc0 100644 --- a/tools/kconfig_new/test/testcases_v1.txt +++ b/tools/kconfig_new/test/testcases_v1.txt @@ -1,6 +1,6 @@ * Set TEST_BOOL, showing child items > { "TEST_BOOL" : true } -< { "values" : { "TEST_BOOL" : true, "TEST_CHILD_STR" : "OHAI!", "TEST_CHILD_BOOL" : true }, "ranges": {"TEST_CONDITIONAL_RANGES": [0, 100]} } +< { "values" : { "TEST_BOOL" : true, "TEST_CHILD_STR" : "OHAI!", "TEST_CHILD_BOOL" : true }, "ranges": {"TEST_CONDITIONAL_RANGES": [0, 100], "TEST_CONDITIONAL_HEX_RANGES": [0, 175]} } * Set TEST_CHILD_STR > { "TEST_CHILD_STR" : "Other value" } @@ -8,7 +8,7 @@ * Clear TEST_BOOL, hiding child items > { "TEST_BOOL" : false } -< { "values" : { "TEST_BOOL" : false, "TEST_CHILD_STR" : null, "TEST_CHILD_BOOL" : null }, "ranges": {"TEST_CONDITIONAL_RANGES": [0, 10]} } +< { "values" : { "TEST_BOOL" : false, "TEST_CHILD_STR" : null, "TEST_CHILD_BOOL" : null }, "ranges": {"TEST_CONDITIONAL_RANGES": [0, 10], "TEST_CONDITIONAL_HEX_RANGES": [16, 175]} } * Set TEST_CHILD_BOOL, invalid as parent is disabled > { "TEST_CHILD_BOOL" : false } diff --git a/tools/kconfig_new/test/testcases_v2.txt b/tools/kconfig_new/test/testcases_v2.txt index 77d23bf66a..7a735fd1a6 100644 --- a/tools/kconfig_new/test/testcases_v2.txt +++ b/tools/kconfig_new/test/testcases_v2.txt @@ -1,6 +1,6 @@ * Set TEST_BOOL, showing child items > { "TEST_BOOL" : true } -< { "values" : { "TEST_BOOL" : true, "TEST_CHILD_STR" : "OHAI!", "TEST_CHILD_BOOL" : true }, "ranges": {"TEST_CONDITIONAL_RANGES": [0, 100]}, "visible": {"TEST_CHILD_BOOL" : true, "TEST_CHILD_STR" : true} } +< { "values" : { "TEST_BOOL" : true, "TEST_CHILD_STR" : "OHAI!", "TEST_CHILD_BOOL" : true }, "ranges": {"TEST_CONDITIONAL_RANGES": [0, 100], "TEST_CONDITIONAL_HEX_RANGES": [0, 175]}, "visible": {"TEST_CHILD_BOOL" : true, "TEST_CHILD_STR" : true} } * Set TEST_CHILD_STR > { "TEST_CHILD_STR" : "Other value" } @@ -8,7 +8,7 @@ * Clear TEST_BOOL, hiding child items > { "TEST_BOOL" : false } -< { "values" : { "TEST_BOOL" : false }, "ranges": {"TEST_CONDITIONAL_RANGES": [0, 10]}, "visible": { "TEST_CHILD_BOOL" : false, "TEST_CHILD_STR" : false } } +< { "values" : { "TEST_BOOL" : false }, "ranges": {"TEST_CONDITIONAL_RANGES": [0, 10], "TEST_CONDITIONAL_HEX_RANGES": [16, 175]}, "visible": { "TEST_CHILD_BOOL" : false, "TEST_CHILD_STR" : false } } * Set TEST_CHILD_BOOL, invalid as parent is disabled > { "TEST_CHILD_BOOL" : false } From 510042160dffc780b926f35dc24174216015c723 Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Mon, 1 Jul 2019 17:03:55 +0200 Subject: [PATCH 239/486] tools: avoid using directly _write_to_conf from kconfiglib Closes https://github.com/espressif/esp-idf/issues/3543 --- tools/kconfig_new/confgen.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tools/kconfig_new/confgen.py b/tools/kconfig_new/confgen.py index d4e8752902..496650cff9 100755 --- a/tools/kconfig_new/confgen.py +++ b/tools/kconfig_new/confgen.py @@ -349,10 +349,8 @@ def write_cmake(deprecated_options, config, filename): if not isinstance(sym, kconfiglib.Symbol): return - # Note: str_value calculates _write_to_conf, due to - # internal magic in kconfiglib... - val = sym.str_value - if sym._write_to_conf: + if sym.config_string: + val = sym.str_value if sym.orig_type in (kconfiglib.BOOL, kconfiglib.TRISTATE) and val == "n": val = "" # write unset values as empty variables write("set({}{} \"{}\")\n".format( @@ -380,8 +378,8 @@ def get_json_values(config): if not isinstance(sym, kconfiglib.Symbol): return - val = sym.str_value # this calculates _write_to_conf, due to kconfiglib magic - if sym._write_to_conf: + if sym.config_string: + val = sym.str_value if sym.type in [kconfiglib.BOOL, kconfiglib.TRISTATE]: val = (val != "n") elif sym.type == kconfiglib.HEX: From 412dc9516874928bb18c29c85ef5e914bf653c18 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 11 Jun 2019 15:56:04 +0200 Subject: [PATCH 240/486] tcp_transport: added basic unit tests for init/destroy transports in lists or when used separately --- components/tcp_transport/test/CMakeLists.txt | 5 ++++ components/tcp_transport/test/component.mk | 5 ++++ .../tcp_transport/test/test_transport.c | 28 +++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 components/tcp_transport/test/CMakeLists.txt create mode 100644 components/tcp_transport/test/component.mk create mode 100644 components/tcp_transport/test/test_transport.c diff --git a/components/tcp_transport/test/CMakeLists.txt b/components/tcp_transport/test/CMakeLists.txt new file mode 100644 index 0000000000..88504a27f6 --- /dev/null +++ b/components/tcp_transport/test/CMakeLists.txt @@ -0,0 +1,5 @@ +set(COMPONENT_SRCDIRS ".") +set(COMPONENT_PRIV_INCLUDEDIRS "../private_include" ".") +set(COMPONENT_PRIV_REQUIRES unity test_utils tcp_transport) + +register_component() \ No newline at end of file diff --git a/components/tcp_transport/test/component.mk b/components/tcp_transport/test/component.mk new file mode 100644 index 0000000000..22e49eddde --- /dev/null +++ b/components/tcp_transport/test/component.mk @@ -0,0 +1,5 @@ +# +#Component Makefile +# +COMPONENT_PRIV_INCLUDEDIRS := ../private_include . +COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive \ No newline at end of file diff --git a/components/tcp_transport/test/test_transport.c b/components/tcp_transport/test/test_transport.c new file mode 100644 index 0000000000..28702fb08b --- /dev/null +++ b/components/tcp_transport/test/test_transport.c @@ -0,0 +1,28 @@ +#include "unity.h" + +#include "esp_transport.h" +#include "esp_transport_tcp.h" +#include "esp_transport_ssl.h" +#include "esp_transport_ws.h" + +TEST_CASE("tcp_transport: init and deinit transport list", "[tcp_transport][leaks=0]") +{ + esp_transport_list_handle_t transport_list = esp_transport_list_init(); + esp_transport_handle_t tcp = esp_transport_tcp_init(); + esp_transport_list_add(transport_list, tcp, "tcp"); + TEST_ASSERT_EQUAL(ESP_OK, esp_transport_list_destroy(transport_list)); +} + +TEST_CASE("tcp_transport: using ssl transport separately", "[tcp_transport][leaks=0]") +{ + esp_transport_handle_t h = esp_transport_ssl_init(); + TEST_ASSERT_EQUAL(ESP_OK, esp_transport_destroy(h)); +} + +TEST_CASE("tcp_transport: using ws transport separately", "[tcp_transport][leaks=0]") +{ + esp_transport_handle_t tcp = esp_transport_tcp_init(); + esp_transport_handle_t ws = esp_transport_ws_init(tcp); + TEST_ASSERT_EQUAL(ESP_OK, esp_transport_destroy(ws)); + TEST_ASSERT_EQUAL(ESP_OK, esp_transport_destroy(tcp)); +} From edbcb5b2951f7cb11b5803849e75ff64545abeff Mon Sep 17 00:00:00 2001 From: Max Holtzberg Date: Fri, 24 May 2019 23:31:44 +0200 Subject: [PATCH 241/486] esp_transport_destroy: Fix memory leak if tcp_transport component was used separately (e.g. using tranpsort_ssl.h directly without building list of transport) then it leaks memory on unitialization Merges https://github.com/espressif/esp-idf/pull/3541 Closes https://github.com/espressif/esp-idf/issues/3531 Signed-off-by: David Cermak --- components/tcp_transport/transport.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/tcp_transport/transport.c b/components/tcp_transport/transport.c index 44756e1d4b..0626c1685a 100644 --- a/components/tcp_transport/transport.c +++ b/components/tcp_transport/transport.c @@ -110,9 +110,6 @@ esp_err_t esp_transport_list_clean(esp_transport_list_handle_t list) esp_transport_handle_t tmp; while (item != NULL) { tmp = STAILQ_NEXT(item, next); - if (item->_destroy) { - item->_destroy(item); - } esp_transport_destroy(item); item = tmp; } @@ -137,6 +134,9 @@ esp_transport_handle_t esp_transport_get_payload_transport_handle(esp_transport_ esp_err_t esp_transport_destroy(esp_transport_handle_t t) { + if (t->_destroy) { + t->_destroy(t); + } if (t->scheme) { free(t->scheme); } From 61923d37b6c024bb42d4ae6e5138135dccf0ac49 Mon Sep 17 00:00:00 2001 From: Anurag Kar Date: Tue, 2 Jul 2019 20:12:47 +0530 Subject: [PATCH 242/486] esp_prov : Minor refactoring in argument dependent logic Other changes: * Command line argument name and descriptions updated and formatted * Some exception messages updated for clarity * READMEs updated for tool and all provisioning examples * Minor update in example test scripts due to change in esp_prov.get_transport() API * Transport_HTTP now forces connect on initialization --- examples/provisioning/ble_prov/README.md | 3 +- .../provisioning/ble_prov/ble_prov_test.py | 2 +- examples/provisioning/console_prov/README.md | 6 +- examples/provisioning/custom_config/README.md | 2 +- examples/provisioning/manager/README.md | 52 ++++- .../manager/wifi_prov_mgr_test.py | 2 +- examples/provisioning/softap_prov/README.md | 2 +- .../softap_prov/softap_prov_test.py | 2 +- tools/esp_prov/README.md | 10 +- tools/esp_prov/esp_prov.py | 183 ++++++++++++------ tools/esp_prov/transport/transport_http.py | 5 + 11 files changed, 195 insertions(+), 74 deletions(-) diff --git a/examples/provisioning/ble_prov/README.md b/examples/provisioning/ble_prov/README.md index d6d5223a9c..fa49ba8e4d 100644 --- a/examples/provisioning/ble_prov/README.md +++ b/examples/provisioning/ble_prov/README.md @@ -80,7 +80,7 @@ Make sure to note down the BLE device name (starting with PROV_) displayed in th In a separate terminal run the `esp_prov.py` script under `$IDP_PATH/tools/esp_prov` directory (please replace `myssid` and `mypassword` with the credentials of the AP to which the device is supposed to connect to after provisioning). Assuming default example configuration : ``` -python esp_prov.py --ssid myssid --passphrase mypassword --sec_ver 1 --pop abcd1234 --transport ble --ble_devname PROV_261FCC +python esp_prov.py --transport ble --service_name PROV_261FCC --sec_ver 1 --pop abcd1234 --ssid myssid --passphrase mypassword ``` Above command will perform the provisioning steps, and the monitor log should display something like this : @@ -150,7 +150,6 @@ Or, enable `Reset Provisioning` option under `Example Configuration` under menuc If the platform requirement, for running `esp_prov` is not satisfied, then the script execution will fallback to console mode, in which case the full process (involving user inputs) will look like this : ``` -==== Esp_Prov Version: V0.1 ==== BLE client is running in console mode This could be due to your platform not being supported or dependencies not being met Please ensure all pre-requisites are met to run the full fledged client diff --git a/examples/provisioning/ble_prov/ble_prov_test.py b/examples/provisioning/ble_prov/ble_prov_test.py index f379e7d3ac..01277117ed 100644 --- a/examples/provisioning/ble_prov/ble_prov_test.py +++ b/examples/provisioning/ble_prov/ble_prov_test.py @@ -76,7 +76,7 @@ def test_examples_provisioning_ble(env, extra_data): raise RuntimeError("Failed to get security") print("Getting transport") - transport = esp_prov.get_transport(provmode, None, devname) + transport = esp_prov.get_transport(provmode, devname) if transport is None: raise RuntimeError("Failed to get transport") diff --git a/examples/provisioning/console_prov/README.md b/examples/provisioning/console_prov/README.md index cb7551c614..0732c54505 100644 --- a/examples/provisioning/console_prov/README.md +++ b/examples/provisioning/console_prov/README.md @@ -65,14 +65,12 @@ I (398) app_prov: Console provisioning started In a separate terminal run the `esp_prov.py` script under `$IDP_PATH/tools/esp_prov` directory (please replace `myssid` and `mypassword` with the credentials of the AP to which the device is supposed to connect to after provisioning). Assuming default example configuration, the script should be run as follows : ``` -python esp_prov.py --ssid myssid --passphrase mypassword --sec_ver 1 --pop abcd1234 --transport console +python esp_prov.py --transport console --proto_ver "V0.1" --sec_ver 1 --pop abcd1234 --ssid myssid --passphrase mypassword ``` A console will open up and the `Client->Device` commands have to be copied manually to the serial monitor console prompt : ``` -==== Esp_Prov Version: V0.1 ==== - ==== Verifying protocol version ==== Client->Device msg : proto-ver 0 56302e31 Enter device->client msg : @@ -111,8 +109,6 @@ This is helpful in understanding the provisioning process and the order in which The full execution sequence of `esp_prov`, as seen on the console, is shown here : ``` -==== Esp_Prov Version: V0.1 ==== - ==== Verifying protocol version ==== Client->Device msg : proto-ver 0 56302e31 Enter device->client msg : 53554343455353 diff --git a/examples/provisioning/custom_config/README.md b/examples/provisioning/custom_config/README.md index 6a07e69f60..82ed6ffe31 100644 --- a/examples/provisioning/custom_config/README.md +++ b/examples/provisioning/custom_config/README.md @@ -68,7 +68,7 @@ I (519482) tcpip_adapter: softAP assign IP to station,IP is: 192.168.4.2 In a separate terminal run the `esp_prov.py` script under `$IDP_PATH/tools/esp_prov` directory (please replace the values corresponding to the parameters `--custom_info` and `--custom_ver` with your desired values for the custom configuration). Assuming default example configuration, the script should be run as follows : ``` -python esp_prov.py --ssid myssid --passphrase mypassword --sec_ver 0 --transport softap --softap_endpoint 192.168.4.1:80 --custom_config --custom_info "some string" --custom_ver 4321 +python esp_prov.py --transport softap --service_name "192.168.4.1:80" --sec_ver 0 --ssid myssid --passphrase mypassword --custom_config --custom_info "some string" --custom_ver 4321 ``` Above command will perform the provisioning steps, and the monitor log should display something like this : diff --git a/examples/provisioning/manager/README.md b/examples/provisioning/manager/README.md index 5bba6aad4c..b59f83710b 100644 --- a/examples/provisioning/manager/README.md +++ b/examples/provisioning/manager/README.md @@ -74,10 +74,10 @@ I (1045) wifi_prov_mgr: Provisioning started with service name : PROV_261FCC Make sure to note down the BLE device name (starting with `PROV_`) displayed in the serial monitor log (eg. PROV_261FCC). This will depend on the MAC ID and will be unique for every device. -In a separate terminal run the `esp_prov.py` script under `$IDP_PATH/tools/esp_prov` directory (please replace `myssid` and `mypassword` with the credentials of the AP to which the device is supposed to connect to after provisioning). Assuming default example configuration : +In a separate terminal run the `esp_prov.py` script under `$IDP_PATH/tools/esp_prov` directory (make sure to replace `myssid` and `mypassword` with the credentials of the AP to which the device is supposed to connect to after provisioning). Assuming default example configuration, which uses protocomm security scheme 1 and proof of possession PoP based authentication : ``` -python esp_prov.py --ssid myssid --passphrase mypassword --sec_ver 1 --pop abcd1234 --transport ble --ble_devname PROV_261FCC +python esp_prov.py --transport ble --service_name PROV_261FCC --sec_ver 1 --pop abcd1234 --ssid myssid --passphrase mypassword ``` Above command will perform the provisioning steps, and the monitor log should display something like this : @@ -109,6 +109,54 @@ I (54355) app: Hello World! I (55355) app: Hello World! ``` +### Wi-Fi Scanning + +Provisioning manager also supports providing real-time Wi-Fi scan results (performed on the device) during provisioning. This allows the client side applications to choose the AP for which the device Wi-Fi station is to be configured. Various information about the visible APs is available, like signal strength (RSSI) and security type, etc. Also, the manager now provides capabilities information which can be used by client applications to determine the security type and availability of specific features (like `wifi_scan`). + +When using the scan based provisioning, we don't need to specify the `--ssid` and `--passphrase` fields explicitly: + +``` +python esp_prov.py --transport ble --service_name PROV_261FCC --pop abcd1234 +``` + +See below the sample output from `esp_prov` tool on running above command: + +``` +Connecting... +Connected +Getting Services... +Security scheme determined to be : 1 + +==== Starting Session ==== +==== Session Established ==== + +==== Scanning Wi-Fi APs ==== +++++ Scan process executed in 1.9967520237 sec +++++ Scan results : 5 + +++++ Scan finished in 2.7374596596 sec +==== Wi-Fi Scan results ==== +S.N. SSID BSSID CHN RSSI AUTH +[ 1] MyHomeWiFiAP 788a20841996 1 -45 WPA2_PSK +[ 2] MobileHotspot 7a8a20841996 11 -46 WPA2_PSK +[ 3] MyHomeWiFiAP 788a208daa26 11 -54 WPA2_PSK +[ 4] NeighborsWiFiAP 8a8a20841996 6 -61 WPA2_PSK +[ 5] InsecureWiFiAP dca4caf1227c 7 -74 Open + +Select AP by number (0 to rescan) : 1 +Enter passphrase for MyHomeWiFiAP : + +==== Sending Wi-Fi credential to esp32 ==== +==== Wi-Fi Credentials sent successfully ==== + +==== Applying config to esp32 ==== +==== Apply config sent successfully ==== + +==== Wi-Fi connection state ==== +++++ WiFi state: connected ++++ +==== Provisioning was successful ==== +``` + ## Troubleshooting ### Provisioning failed diff --git a/examples/provisioning/manager/wifi_prov_mgr_test.py b/examples/provisioning/manager/wifi_prov_mgr_test.py index 25bb463d2e..ea7172dc4d 100644 --- a/examples/provisioning/manager/wifi_prov_mgr_test.py +++ b/examples/provisioning/manager/wifi_prov_mgr_test.py @@ -76,7 +76,7 @@ def test_examples_wifi_prov_mgr(env, extra_data): raise RuntimeError("Failed to get security") print("Getting transport") - transport = esp_prov.get_transport(provmode, None, devname) + transport = esp_prov.get_transport(provmode, devname) if transport is None: raise RuntimeError("Failed to get transport") diff --git a/examples/provisioning/softap_prov/README.md b/examples/provisioning/softap_prov/README.md index e5445b80c8..56d092dbfa 100644 --- a/examples/provisioning/softap_prov/README.md +++ b/examples/provisioning/softap_prov/README.md @@ -81,7 +81,7 @@ I (519482) tcpip_adapter: softAP assign IP to station,IP is: 192.168.4.2 In a separate terminal run the `esp_prov.py` script under `$IDP_PATH/tools/esp_prov` directory (please replace `myssid` and `mypassword` with the credentials of the AP to which the device is supposed to connect to after provisioning). The SoftAP endpoint corresponds to the IP and port of the device on the SoftAP network, but this is usually same as the default value and may be left out. Assuming default example configuration, the script should be run as follows : ``` -python esp_prov.py --ssid myssid --passphrase mypassword --sec_ver 1 --pop abcd1234 --transport softap --softap_endpoint 192.168.4.1:80 +python esp_prov.py --transport softap --service_name "192.168.4.1:80" --sec_ver 1 --pop abcd1234 --ssid myssid --passphrase mypassword ``` Above command will perform the provisioning steps, and the monitor log should display something like this : diff --git a/examples/provisioning/softap_prov/softap_prov_test.py b/examples/provisioning/softap_prov/softap_prov_test.py index e54ef23bec..6f67f47c8e 100644 --- a/examples/provisioning/softap_prov/softap_prov_test.py +++ b/examples/provisioning/softap_prov/softap_prov_test.py @@ -97,7 +97,7 @@ def test_examples_provisioning_softap(env, extra_data): raise RuntimeError("Failed to get security") print("Getting transport") - transport = esp_prov.get_transport(provmode, softap_endpoint, None) + transport = esp_prov.get_transport(provmode, softap_endpoint) if transport is None: raise RuntimeError("Failed to get transport") diff --git a/tools/esp_prov/README.md b/tools/esp_prov/README.md index c4fef6938c..7f8a443b00 100644 --- a/tools/esp_prov/README.md +++ b/tools/esp_prov/README.md @@ -6,7 +6,7 @@ # SYNOPSIS ``` -python esp_prov.py --transport < mode of provisioning : softap \ ble \ console > --sec_ver < Security version 0 / 1 > [ Optional parameters... ] +python esp_prov.py --transport < mode of provisioning : softap \ ble \ console > [ Optional parameters... ] ``` # DESCRIPTION @@ -53,11 +53,9 @@ Usage of `esp-prov` assumes that the provisioning app has specific protocomm end * `--pop ` (Optional) For specifying optional Proof of Possession string to use for protocomm endpoint security version 1. This option is ignored when security version 0 is in use -* `--softap_endpoint ` (Optional) (Default `192.168.4.1:80`) - For specifying the IP and port of the HTTP server on which provisioning app is running. The client must connect to the device SoftAP prior to running `esp_prov` - -* `--ble_devname ` (Optional) - For specifying name of the BLE device to which connection is to be established prior to starting provisioning process. This is only used when `--transport ble` is specified, else it is ignored. Since connection with BLE is supported only on Linux, so this option is again ignored for other platforms +* `--service_name (Optional) + When transport mode is ble, this specifies the BLE device name to which connection is to be established for provisioned. + When transport mode is softap, this specifies the HTTP server hostname / IP which is running the provisioning service, on the SoftAP network of the device which is to be provisioned. This defaults to `192.168.4.1:80` if not specified * `--custom_config` (Optional) This flag assumes the provisioning app has an endpoint called `custom-config`. Use `--custom_info` and `--custom_ver` options to specify the fields accepted by this endpoint diff --git a/tools/esp_prov/esp_prov.py b/tools/esp_prov/esp_prov.py index d80db3cd7e..52fb394f26 100644 --- a/tools/esp_prov/esp_prov.py +++ b/tools/esp_prov/esp_prov.py @@ -18,6 +18,7 @@ from __future__ import print_function from builtins import input import argparse +import textwrap import time import os import sys @@ -57,12 +58,16 @@ def get_security(secver, pop=None, verbose=False): return None -def get_transport(sel_transport, softap_endpoint=None, ble_devname=None): +def get_transport(sel_transport, service_name): try: tp = None if (sel_transport == 'softap'): - tp = transport.Transport_HTTP(softap_endpoint) + if service_name is None: + service_name = '192.168.4.1:80' + tp = transport.Transport_HTTP(service_name) elif (sel_transport == 'ble'): + if service_name is None: + raise RuntimeError('"--service_name" must be specified for ble transport') # BLE client is now capable of automatically figuring out # the primary service from the advertisement data and the # characteristics corresponding to each endpoint. @@ -71,7 +76,7 @@ def get_transport(sel_transport, softap_endpoint=None, ble_devname=None): # in which case, the automated discovery will fail and the client # will fallback to using the provided UUIDs instead nu_lookup = {'prov-session': 'ff51', 'prov-config': 'ff52', 'proto-ver': 'ff53'} - tp = transport.Transport_BLE(devname=ble_devname, + tp = transport.Transport_BLE(devname=service_name, service_uuid='0000ffff-0000-1000-8000-00805f9b34fb', nu_lookup=nu_lookup) elif (sel_transport == 'console'): @@ -93,31 +98,53 @@ def version_match(tp, protover, verbose=False): if response.lower() == protover.lower(): return True - # Else interpret this as JSON structure containing - # information with versions and capabilities of both - # provisioning service and application - info = json.loads(response) - if info['prov']['ver'].lower() == protover.lower(): - return True + try: + # Else interpret this as JSON structure containing + # information with versions and capabilities of both + # provisioning service and application + info = json.loads(response) + if info['prov']['ver'].lower() == protover.lower(): + return True + + except ValueError: + # If decoding as JSON fails, it means that capabilities + # are not supported + return False - return False except Exception as e: on_except(e) return None -def has_capability(tp, capability, verbose=False): +def has_capability(tp, capability='none', verbose=False): + # Note : default value of `capability` argument cannot be empty string + # because protocomm_httpd expects non zero content lengths try: response = tp.send_data('proto-ver', capability) if verbose: print("proto-ver response : ", response) - info = json.loads(response) - if capability in info['prov']['cap']: - return True + try: + # Interpret this as JSON structure containing + # information with versions and capabilities of both + # provisioning service and application + info = json.loads(response) + supported_capabilities = info['prov']['cap'] + if capability.lower() == 'none': + # No specific capability to check, but capabilities + # feature is present so return True + return True + elif capability in supported_capabilities: + return True + return False - except Exception as e: + except ValueError: + # If decoding as JSON fails, it means that capabilities + # are not supported + return False + + except RuntimeError as e: on_except(e) return False @@ -239,75 +266,123 @@ def get_wifi_config(tp, sec): return None +def desc_format(*args): + desc = '' + for arg in args: + desc += textwrap.fill(replace_whitespace=False, text=arg) + "\n" + return desc + + if __name__ == '__main__': - parser = argparse.ArgumentParser(description="Generate ESP prov payload") + parser = argparse.ArgumentParser(description=desc_format( + 'ESP Provisioning tool for configuring devices ' + 'running protocomm based provisioning service.', + 'See esp-idf/examples/provisioning for sample applications'), + formatter_class=argparse.RawTextHelpFormatter) - parser.add_argument("--ssid", dest='ssid', type=str, - help="SSID of Wi-Fi Network", default='') - parser.add_argument("--passphrase", dest='passphrase', type=str, - help="Passphrase of Wi-Fi network", default='') + parser.add_argument("--transport", required=True, dest='mode', type=str, + help=desc_format( + 'Mode of transport over which provisioning is to be performed.', + 'This should be one of "softap", "ble" or "console"')) - parser.add_argument("--sec_ver", dest='secver', type=int, - help="Security scheme version", default=None) - parser.add_argument("--proto_ver", dest='protover', type=str, - help="Protocol version", default='') - parser.add_argument("--pop", dest='pop', type=str, - help="Proof of possession", default='') + parser.add_argument("--service_name", dest='name', type=str, + help=desc_format( + 'This specifies the name of the provisioning service to connect to, ' + 'depending upon the mode of transport :', + '\t- transport "ble" : The BLE Device Name', + '\t- transport "softap" : HTTP Server hostname or IP', + '\t (default "192.168.4.1:80")')) - parser.add_argument("--softap_endpoint", dest='softap_endpoint', type=str, - help=", http(s):// shouldn't be included", default='192.168.4.1:80') + parser.add_argument("--proto_ver", dest='version', type=str, default='', + help=desc_format( + 'This checks the protocol version of the provisioning service running ' + 'on the device before initiating Wi-Fi configuration')) - parser.add_argument("--ble_devname", dest='ble_devname', type=str, - help="BLE Device Name", default='') + parser.add_argument("--sec_ver", dest='secver', type=int, default=None, + help=desc_format( + 'Protocomm security scheme used by the provisioning service for secure ' + 'session establishment. Accepted values are :', + '\t- 0 : No security', + '\t- 1 : X25519 key exchange + AES-CTR encryption', + '\t + Authentication using Proof of Possession (PoP)', + 'In case device side application uses IDF\'s provisioning manager, ' + 'the compatible security version is automatically determined from ' + 'capabilities retrieved via the version endpoint')) - parser.add_argument("--transport", dest='provmode', type=str, - help="provisioning mode i.e console or softap or ble", default='softap') + parser.add_argument("--pop", dest='pop', type=str, default='', + help=desc_format( + 'This specifies the Proof of possession (PoP) when security scheme 1 ' + 'is used')) - parser.add_argument("--custom_config", help="Provision Custom Configuration", - action="store_true") - parser.add_argument("--custom_info", dest='custom_info', type=str, - help="Custom Config Info String", default='') - parser.add_argument("--custom_ver", dest='custom_ver', type=int, - help="Custom Config Version Number", default=2) + parser.add_argument("--ssid", dest='ssid', type=str, default='', + help=desc_format( + 'This configures the device to use SSID of the Wi-Fi network to which ' + 'we would like it to connect to permanently, once provisioning is complete. ' + 'If Wi-Fi scanning is supported by the provisioning service, this need not ' + 'be specified')) + + parser.add_argument("--passphrase", dest='passphrase', type=str, default='', + help=desc_format( + 'This configures the device to use Passphrase for the Wi-Fi network to which ' + 'we would like it to connect to permanently, once provisioning is complete. ' + 'If Wi-Fi scanning is supported by the provisioning service, this need not ' + 'be specified')) + + parser.add_argument("--custom_config", action="store_true", + help=desc_format( + 'This is an optional parameter, only intended for use with ' + '"examples/provisioning/custom_config"')) + parser.add_argument("--custom_info", dest='custom_info', type=str, default='', + help=desc_format( + 'Custom Config Info String. "--custom_config" must be specified for using this')) + parser.add_argument("--custom_ver", dest='custom_ver', type=int, default=2, + help=desc_format( + 'Custom Config Version Number. "--custom_config" must be specified for using this')) + + parser.add_argument("-v","--verbose", help="Increase output verbosity", action="store_true") - parser.add_argument("-v","--verbose", help="increase output verbosity", action="store_true") args = parser.parse_args() - if args.protover != '': - print("==== Esp_Prov Version: " + args.protover + " ====") - - obj_transport = get_transport(args.provmode, args.softap_endpoint, args.ble_devname) + obj_transport = get_transport(args.mode.lower(), args.name) if obj_transport is None: - print("---- Invalid provisioning mode ----") + print("---- Failed to establish connection ----") exit(1) # If security version not specified check in capabilities if args.secver is None: + # First check if capabilities are supported or not + if not has_capability(obj_transport): + print('Security capabilities could not be determined. Please specify "--sec_ver" explicitly') + print("---- Invalid Security Version ----") + exit(2) + # When no_sec is present, use security 0, else security 1 args.secver = int(not has_capability(obj_transport, 'no_sec')) + print("Security scheme determined to be :", args.secver) - if (args.secver != 0) and not has_capability(obj_transport, 'no_pop'): - if len(args.pop) == 0: - print("---- Proof of Possession argument not provided ----") - exit(2) - elif len(args.pop) != 0: - print("---- Proof of Possession will be ignored ----") - args.pop = '' + if (args.secver != 0) and not has_capability(obj_transport, 'no_pop'): + if len(args.pop) == 0: + print("---- Proof of Possession argument not provided ----") + exit(2) + elif len(args.pop) != 0: + print("---- Proof of Possession will be ignored ----") + args.pop = '' obj_security = get_security(args.secver, args.pop, args.verbose) if obj_security is None: print("---- Invalid Security Version ----") exit(2) - if args.protover != '': + if args.version != '': print("\n==== Verifying protocol version ====") - if not version_match(obj_transport, args.protover, args.verbose): + if not version_match(obj_transport, args.version, args.verbose): print("---- Error in protocol version matching ----") exit(3) print("==== Verified protocol version successfully ====") print("\n==== Starting Session ====") if not establish_session(obj_transport, obj_security): + print("Failed to establish session. Ensure that security scheme and proof of possession are correct") print("---- Error in establishing session ----") exit(4) print("==== Session Established ====") @@ -328,7 +403,7 @@ if __name__ == '__main__': while True: print("\n==== Scanning Wi-Fi APs ====") start_time = time.time() - APs = scan_wifi_APs(args.provmode, obj_transport, obj_security) + APs = scan_wifi_APs(args.mode.lower(), obj_transport, obj_security) end_time = time.time() print("\n++++ Scan finished in " + str(end_time - start_time) + " sec") if APs is None: diff --git a/tools/esp_prov/transport/transport_http.py b/tools/esp_prov/transport/transport_http.py index 47e8b28efa..3c7aed013c 100644 --- a/tools/esp_prov/transport/transport_http.py +++ b/tools/esp_prov/transport/transport_http.py @@ -35,6 +35,11 @@ class Transport_HTTP(Transport): else: ssl_ctx = ssl.create_default_context(cafile=certfile) self.conn = http.client.HTTPSConnection(hostname, context=ssl_ctx, timeout=30) + try: + print("Connecting to " + hostname) + self.conn.connect() + except Exception as err: + raise RuntimeError("Connection Failure : " + str(err)) self.headers = {"Content-type": "application/x-www-form-urlencoded","Accept": "text/plain"} def _send_post_request(self, path, data): From 29d1d2bd388a984e2cb7dd5a21f32bea7361da03 Mon Sep 17 00:00:00 2001 From: XiaXiaotian Date: Wed, 17 Apr 2019 11:44:51 +0800 Subject: [PATCH 243/486] esp_wifi: refactor smartconfig callback to use esp event --- components/esp32/CMakeLists.txt | 2 +- components/esp32/esp_adapter.c | 19 +++-- components/esp_wifi/CMakeLists.txt | 3 +- .../esp_wifi/include/esp_private/wifi.h | 29 +++++++ .../include/esp_private/wifi_os_adapter.h | 5 +- components/esp_wifi/include/esp_smartconfig.h | 56 ++++++++------ components/esp_wifi/lib_esp32 | 2 +- components/esp_wifi/src/smartconfig.c | 77 +++++++++++++++++++ .../smartconfig_ack/include/smartconfig_ack.h | 48 +++--------- components/smartconfig_ack/smartconfig_ack.c | 58 ++++++++++---- .../wifi/smart_config/main/smartconfig_main.c | 71 ++++++++--------- 11 files changed, 240 insertions(+), 130 deletions(-) create mode 100644 components/esp_wifi/src/smartconfig.c diff --git a/components/esp32/CMakeLists.txt b/components/esp32/CMakeLists.txt index 916113b533..0a314e2ec1 100644 --- a/components/esp32/CMakeLists.txt +++ b/components/esp32/CMakeLists.txt @@ -36,7 +36,7 @@ else() # driver is a public requirement because esp_sleep.h uses gpio_num_t & touch_pad_t # app_update is added here because cpu_start.c uses esp_ota_get_app_description() function. set(priv_requires app_trace app_update bootloader_support log mbedtls nvs_flash pthread - smartconfig_ack spi_flash vfs wpa_supplicant espcoredump esp_common esp_wifi) + spi_flash vfs wpa_supplicant espcoredump esp_common esp_wifi) set(fragments linker.lf ld/esp32_fragments.lf) idf_component_register(SRCS "${srcs}" diff --git a/components/esp32/esp_adapter.c b/components/esp32/esp_adapter.c index 40888f5a53..0699bf70ca 100644 --- a/components/esp32/esp_adapter.c +++ b/components/esp32/esp_adapter.c @@ -33,6 +33,7 @@ #include "esp_intr_alloc.h" #include "esp_attr.h" #include "esp_log.h" +#include "esp_event.h" #include "esp_heap_caps.h" #include "esp_private/wifi_os_adapter.h" #include "esp_private/wifi.h" @@ -46,7 +47,6 @@ #include "nvs.h" #include "os.h" #include "esp_smartconfig.h" -#include "smartconfig_ack.h" #include "esp_coexist_internal.h" #include "esp_coexist_adapter.h" @@ -373,6 +373,15 @@ static int32_t task_get_max_priority_wrapper(void) return (int32_t)(configMAX_PRIORITIES); } +static int32_t esp_event_post_wrapper(const char* event_base, int32_t event_id, void* event_data, size_t event_data_size, uint32_t ticks_to_wait) +{ + if (ticks_to_wait == OSI_FUNCS_TIME_BLOCKING) { + return (int32_t)esp_event_post(event_base, event_id, event_data, event_data_size, portMAX_DELAY); + } else { + return (int32_t)esp_event_post(event_base, event_id, event_data, event_data_size, ticks_to_wait); + } +} + static void IRAM_ATTR timer_arm_wrapper(void *timer, uint32_t tmout, bool repeat) { ets_timer_arm(timer, tmout, repeat); @@ -427,11 +436,6 @@ static void * IRAM_ATTR zalloc_internal_wrapper(size_t size) return ptr; } -static void sc_ack_send_wrapper(void *param) -{ - return sc_ack_send((sc_ack_t *)param); -} - static uint32_t coex_status_get_wrapper(void) { #if CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE @@ -544,6 +548,7 @@ wifi_osi_funcs_t g_wifi_osi_funcs = { ._task_get_max_priority = task_get_max_priority_wrapper, ._malloc = malloc, ._free = free, + ._event_post = esp_event_post_wrapper, ._get_free_heap_size = esp_get_free_heap_size, ._rand = esp_random, ._dport_access_stall_other_cpu_start_wrap = esp_dport_access_stall_other_cpu_start_wrap, @@ -590,8 +595,6 @@ wifi_osi_funcs_t g_wifi_osi_funcs = { ._modem_sleep_exit = esp_modem_sleep_exit, ._modem_sleep_register = esp_modem_sleep_register, ._modem_sleep_deregister = esp_modem_sleep_deregister, - ._sc_ack_send = sc_ack_send_wrapper, - ._sc_ack_send_stop = sc_ack_send_stop, ._coex_status_get = coex_status_get_wrapper, ._coex_wifi_request = coex_wifi_request_wrapper, ._coex_wifi_release = coex_wifi_release_wrapper, diff --git a/components/esp_wifi/CMakeLists.txt b/components/esp_wifi/CMakeLists.txt index dd3e3d1d2d..469497f699 100644 --- a/components/esp_wifi/CMakeLists.txt +++ b/components/esp_wifi/CMakeLists.txt @@ -10,9 +10,10 @@ idf_component_register(SRCS "src/coexist.c" "src/mesh_event.c" "src/phy_init.c" "src/restore.c" + "src/smartconfig.c" "src/wifi_init.c" INCLUDE_DIRS "include" "${idf_target}/include" - PRIV_REQUIRES wpa_supplicant nvs_flash + PRIV_REQUIRES wpa_supplicant nvs_flash smartconfig_ack LDFRAGMENTS "${ldfragments}") idf_build_get_property(build_dir BUILD_DIR) diff --git a/components/esp_wifi/include/esp_private/wifi.h b/components/esp_wifi/include/esp_private/wifi.h index c8fbe90ed0..ee0654f8bf 100644 --- a/components/esp_wifi/include/esp_private/wifi.h +++ b/components/esp_wifi/include/esp_private/wifi.h @@ -36,6 +36,7 @@ #include "esp_wifi_types.h" #include "esp_event.h" #include "esp_wifi.h" +#include "esp_smartconfig.h" #ifdef __cplusplus extern "C" { @@ -181,6 +182,34 @@ esp_err_t esp_wifi_internal_set_sta_ip(void); */ esp_err_t esp_wifi_internal_set_fix_rate(wifi_interface_t ifx, bool en, wifi_phy_rate_t rate); +/** + * @brief Start SmartConfig, config ESP device to connect AP. You need to broadcast information by phone APP. + * Device sniffer special packets from the air that containing SSID and password of target AP. + * + * @attention 1. This API can be called in station or softAP-station mode. + * @attention 2. Can not call esp_smartconfig_start twice before it finish, please call + * esp_smartconfig_stop first. + * + * @param config pointer to smartconfig start configure structure + * + * @return + * - ESP_OK: succeed + * - others: fail + */ +esp_err_t esp_smartconfig_internal_start(const smartconfig_start_config_t *config); + +/** + * @brief Stop SmartConfig, free the buffer taken by esp_smartconfig_start. + * + * @attention Whether connect to AP succeed or not, this API should be called to free + * memory taken by smartconfig_start. + * + * @return + * - ESP_OK: succeed + * - others: fail + */ +esp_err_t esp_smartconfig_internal_stop(void); + /** * @brief Check the MD5 values of the OS adapter header files in IDF and WiFi library * diff --git a/components/esp_wifi/include/esp_private/wifi_os_adapter.h b/components/esp_wifi/include/esp_private/wifi_os_adapter.h index 165caa6edc..912ec3a537 100644 --- a/components/esp_wifi/include/esp_private/wifi_os_adapter.h +++ b/components/esp_wifi/include/esp_private/wifi_os_adapter.h @@ -21,7 +21,7 @@ extern "C" { #endif -#define ESP_WIFI_OS_ADAPTER_VERSION 0x00000002 +#define ESP_WIFI_OS_ADAPTER_VERSION 0x00000003 #define ESP_WIFI_OS_ADAPTER_MAGIC 0xDEADBEAF #define OSI_FUNCS_TIME_BLOCKING 0xffffffff @@ -72,6 +72,7 @@ typedef struct { int32_t (* _task_get_max_priority)(void); void *(* _malloc)(uint32_t size); void (* _free)(void *p); + int32_t (* _event_post)(const char* event_base, int32_t event_id, void* event_data, size_t event_data_size, uint32_t ticks_to_wait); uint32_t (* _get_free_heap_size)(void); uint32_t (* _rand)(void); void (* _dport_access_stall_other_cpu_start_wrap)(void); @@ -118,8 +119,6 @@ typedef struct { int32_t (* _modem_sleep_exit)(uint32_t module); int32_t (* _modem_sleep_register)(uint32_t module); int32_t (* _modem_sleep_deregister)(uint32_t module); - void (* _sc_ack_send)(void *param); - void (* _sc_ack_send_stop)(void); uint32_t (* _coex_status_get)(void); int32_t (* _coex_wifi_request)(uint32_t event, uint32_t latency, uint32_t duration); int32_t (* _coex_wifi_release)(uint32_t event); diff --git a/components/esp_wifi/include/esp_smartconfig.h b/components/esp_wifi/include/esp_smartconfig.h index 34cf8667ab..bd5c545e58 100644 --- a/components/esp_wifi/include/esp_smartconfig.h +++ b/components/esp_wifi/include/esp_smartconfig.h @@ -18,37 +18,48 @@ #include #include #include "esp_err.h" +#include "esp_event_base.h" #ifdef __cplusplus extern "C" { #endif -typedef enum { - SC_STATUS_WAIT = 0, /**< Waiting to start connect */ - SC_STATUS_FIND_CHANNEL, /**< Finding target channel */ - SC_STATUS_GETTING_SSID_PSWD, /**< Getting SSID and password of target AP */ - SC_STATUS_LINK, /**< Connecting to target AP */ - SC_STATUS_LINK_OVER, /**< Connected to AP successfully */ -} smartconfig_status_t; - typedef enum { SC_TYPE_ESPTOUCH = 0, /**< protocol: ESPTouch */ SC_TYPE_AIRKISS, /**< protocol: AirKiss */ SC_TYPE_ESPTOUCH_AIRKISS, /**< protocol: ESPTouch and AirKiss */ } smartconfig_type_t; -/** - * @brief The callback of SmartConfig, executed when smart-config status changed. - * - * @param status Status of SmartConfig: - * - SC_STATUS_GETTING_SSID_PSWD : pdata is a pointer of smartconfig_type_t, means config type. - * - SC_STATUS_LINK : pdata is a pointer to wifi_config_t. - * - SC_STATUS_LINK_OVER : pdata is a pointer of phone's IP address(4 bytes) if pdata unequal NULL. - * - otherwise : parameter void *pdata is NULL. - * @param pdata According to the different status have different values. - * - */ -typedef void (*sc_callback_t)(smartconfig_status_t status, void *pdata); +/** Smartconfig event declarations */ +typedef enum { + SC_EVENT_SCAN_DONE, /*!< ESP32 station smartconfig has finished to scan for APs */ + SC_EVENT_FOUND_CHANNEL, /*!< ESP32 station smartconfig has found the channel of the target AP */ + SC_EVENT_GOT_SSID_PSWD, /*!< ESP32 station smartconfig got the SSID and password */ + SC_EVENT_SEND_ACK_DONE, /*!< ESP32 station smartconfig has sent ACK to cellphone */ +} smartconfig_event_t; + +/** @brief smartconfig event base declaration */ +ESP_EVENT_DECLARE_BASE(SC_EVENT); + +/** Argument structure for SC_EVENT_GOT_SSID_PSWD event */ +typedef struct { + uint8_t ssid[32]; /**< SSID of the AP. Null terminated string. */ + uint8_t password[64]; /**< Password of the AP. Null terminated string. */ + bool bssid_set; /**< whether set MAC address of target AP or not. */ + uint8_t bssid[6]; /**< MAC address of target AP. */ + smartconfig_type_t type; /**< Type of smartconfig(ESPTouch or AirKiss). */ + uint8_t token; /**< Token from cellphone which is used to send ACK to cellphone. */ + uint8_t cellphone_ip[4]; /**< IP address of cellphone. */ +} smartconfig_event_got_ssid_pswd_t; + +/** Configure structure for esp_smartconfig_start */ +typedef struct { + bool enable_log; /**< Enable smartconfig logs. */ +} smartconfig_start_config_t; + +#define SMARTCONFIG_START_CONFIG_DEFAULT() { \ + .enable_log = false \ +}; /** * @brief Get the version of SmartConfig. @@ -66,14 +77,13 @@ const char *esp_smartconfig_get_version(void); * @attention 2. Can not call esp_smartconfig_start twice before it finish, please call * esp_smartconfig_stop first. * - * @param cb SmartConfig callback function. - * @param ... log 1: UART output logs; 0: UART only outputs the result. + * @param config pointer to smartconfig start configure structure * * @return * - ESP_OK: succeed * - others: fail */ -esp_err_t esp_smartconfig_start(sc_callback_t cb, ...); +esp_err_t esp_smartconfig_start(const smartconfig_start_config_t *config); /** * @brief Stop SmartConfig, free the buffer taken by esp_smartconfig_start. diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index 6579ef9a7e..7657dd453d 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit 6579ef9a7ebdfa4196398056ee5337c300ca74e3 +Subproject commit 7657dd453d4349d03458b77c082acbfe6b6736c4 diff --git a/components/esp_wifi/src/smartconfig.c b/components/esp_wifi/src/smartconfig.c new file mode 100644 index 0000000000..a4138c89bb --- /dev/null +++ b/components/esp_wifi/src/smartconfig.c @@ -0,0 +1,77 @@ +// Copyright 2019 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 +#include +#include "esp_log.h" +#include "esp_event_base.h" +#include "esp_private/wifi.h" +#include "esp_smartconfig.h" +#include "smartconfig_ack.h" + +/* Smartconfig events definitions */ +ESP_EVENT_DEFINE_BASE(SC_EVENT); + +static const char *TAG = "smartconfig"; + +static void handler_got_ssid_passwd(void *arg, esp_event_base_t base, int32_t event_id, void *data) +{ + smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)data; + uint8_t ssid[33] = { 0 }; + uint8_t password[65] = { 0 }; + uint8_t cellphone_ip[4]; + esp_err_t err = ESP_OK; + + memcpy(ssid, evt->ssid, sizeof(evt->ssid)); + memcpy(password, evt->password, sizeof(evt->password)); + memcpy(cellphone_ip, evt->cellphone_ip, sizeof(evt->cellphone_ip)); + + ESP_LOGD(TAG, "SSID:%s", ssid); + ESP_LOGD(TAG, "PASSWORD:%s", password); + ESP_LOGD(TAG, "Phone ip: %d.%d.%d.%d\n", cellphone_ip[0], cellphone_ip[1], cellphone_ip[2], cellphone_ip[3]); + + err = sc_send_ack_start(evt->type, evt->token, evt->cellphone_ip); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Send smartconfig ACK error: %d", err); + } +} + +esp_err_t esp_smartconfig_start(const smartconfig_start_config_t *config) +{ + esp_err_t err = ESP_OK; + + err = esp_event_handler_register(SC_EVENT, SC_EVENT_GOT_SSID_PSWD, handler_got_ssid_passwd, NULL); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Register smartconfig default event handler fail!"); + return err; + } + + err = esp_smartconfig_internal_start(config); + if (err != ESP_OK) { + esp_event_handler_unregister(SC_EVENT, SC_EVENT_GOT_SSID_PSWD, handler_got_ssid_passwd); + } + return err; +} + +esp_err_t esp_smartconfig_stop(void) +{ + esp_err_t err = ESP_OK; + + err = esp_smartconfig_internal_stop(); + if (err == ESP_OK) { + sc_send_ack_stop(); + esp_event_handler_unregister(SC_EVENT, SC_EVENT_GOT_SSID_PSWD, handler_got_ssid_passwd); + } + return err; +} \ No newline at end of file diff --git a/components/smartconfig_ack/include/smartconfig_ack.h b/components/smartconfig_ack/include/smartconfig_ack.h index be49fd3bd1..0eb3e4b660 100644 --- a/components/smartconfig_ack/include/smartconfig_ack.h +++ b/components/smartconfig_ack/include/smartconfig_ack.h @@ -19,54 +19,24 @@ extern "C" { #endif -#define SC_ACK_TASK_PRIORITY 2 /*!< Priority of sending smartconfig ACK task */ -#define SC_ACK_TASK_STACK_SIZE 2048 /*!< Stack size of sending smartconfig ACK task */ - -#define SC_ACK_TOUCH_SERVER_PORT 18266 /*!< ESP touch UDP port of server on cellphone */ -#define SC_ACK_AIRKISS_SERVER_PORT 10000 /*!< Airkiss UDP port of server on cellphone */ - -#define SC_ACK_TOUCH_LEN 11 /*!< Length of ESP touch ACK context */ -#define SC_ACK_AIRKISS_LEN 7 /*!< Length of Airkiss ACK context */ - -#define SC_ACK_MAX_COUNT 30 /*!< Maximum count of sending smartconfig ACK */ - -/** - * @brief Smartconfig ACK type. - */ -typedef enum { - SC_ACK_TYPE_ESPTOUCH = 0, /*!< ESP touch ACK type */ - SC_ACK_TYPE_AIRKISS, /*!< Airkiss ACK type */ -} sc_ack_type_t; - -/** - * @brief Smartconfig parameters passed to sc_ack_send call. - */ -typedef struct sc_ack { - sc_ack_type_t type; /*!< Smartconfig ACK type */ - uint8_t *link_flag; /*!< Smartconfig link flag */ - sc_callback_t cb; /*!< Smartconfig callback function */ - struct { - uint8_t token; /*!< Smartconfig token to be sent */ - uint8_t mac[6]; /*!< MAC address of station */ - uint8_t ip[4]; /*!< IP address of cellphone */ - } ctx; -} sc_ack_t; - /** * @brief Send smartconfig ACK to cellphone. * - * @attention The API is only used in libsmartconfig.a. + * @attention The API can only be used when receiving SC_EVENT_GOT_SSID_PSWD event. * - * @param param: smartconfig parameters; + * @param type: smartconfig type(ESPTouch or AirKiss); + * token: token from the cellphone; + * cellphone_ip: IP address of the cellphone; + * + * @retuen ESP_OK: succeed + * others: fail */ -void sc_ack_send(sc_ack_t *param); +esp_err_t sc_send_ack_start(smartconfig_type_t type, uint8_t token, uint8_t *cellphone_ip); /** * @brief Stop sending smartconfig ACK to cellphone. - * - * @attention The API is only used in libsmartconfig.a. */ -void sc_ack_send_stop(void); +void sc_send_ack_stop(void); #ifdef __cplusplus } diff --git a/components/smartconfig_ack/smartconfig_ack.c b/components/smartconfig_ack/smartconfig_ack.c index f84aad3672..fae5e58bbc 100644 --- a/components/smartconfig_ack/smartconfig_ack.c +++ b/components/smartconfig_ack/smartconfig_ack.c @@ -24,9 +24,33 @@ #include "tcpip_adapter.h" #include "esp_log.h" #include "esp_wifi.h" +#include "esp_event.h" #include "esp_smartconfig.h" #include "smartconfig_ack.h" +#define SC_ACK_TASK_PRIORITY 2 /*!< Priority of sending smartconfig ACK task */ +#define SC_ACK_TASK_STACK_SIZE 2048 /*!< Stack size of sending smartconfig ACK task */ + +#define SC_ACK_TOUCH_SERVER_PORT 18266 /*!< ESP touch UDP port of server on cellphone */ +#define SC_ACK_AIRKISS_SERVER_PORT 10000 /*!< Airkiss UDP port of server on cellphone */ + +#define SC_ACK_TOUCH_LEN 11 /*!< Length of ESP touch ACK context */ +#define SC_ACK_AIRKISS_LEN 7 /*!< Length of Airkiss ACK context */ + +#define SC_ACK_MAX_COUNT 30 /*!< Maximum count of sending smartconfig ACK */ + +/** + * @brief Smartconfig parameters passed to sc_ack_send call. + */ +typedef struct sc_ack { + smartconfig_type_t type; /*!< Smartconfig type(ESPTouch or AirKiss) */ + struct { + uint8_t token; /*!< Smartconfig token from the cellphone */ + uint8_t mac[6]; /*!< MAC address of station */ + uint8_t ip[4]; /*!< IP address of cellphone */ + } ctx; +} sc_ack_t; + static const char *TAG = "smartconfig"; /* Flag to indicate sending smartconfig ACK or not. */ @@ -48,13 +72,13 @@ static void sc_ack_send_task(void *pvParameters) tcpip_adapter_ip_info_t local_ip; uint8_t remote_ip[4]; memcpy(remote_ip, ack->ctx.ip, sizeof(remote_ip)); - int remote_port = (ack->type == SC_ACK_TYPE_ESPTOUCH) ? SC_ACK_TOUCH_SERVER_PORT : SC_ACK_AIRKISS_SERVER_PORT; + int remote_port = (ack->type == SC_TYPE_ESPTOUCH) ? SC_ACK_TOUCH_SERVER_PORT : SC_ACK_AIRKISS_SERVER_PORT; struct sockaddr_in server_addr; socklen_t sin_size = sizeof(server_addr); int send_sock = -1; int optval = 1; int sendlen; - int ack_len = (ack->type == SC_ACK_TYPE_ESPTOUCH) ? SC_ACK_TOUCH_LEN : SC_ACK_AIRKISS_LEN; + int ack_len = (ack->type == SC_TYPE_ESPTOUCH) ? SC_ACK_TOUCH_LEN : SC_ACK_AIRKISS_LEN; uint8_t packet_count = 1; int err; int ret; @@ -73,7 +97,7 @@ static void sc_ack_send_task(void *pvParameters) ret = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &local_ip); if ((ESP_OK == ret) && (local_ip.ip.addr != INADDR_ANY)) { /* If ESP touch, smartconfig ACK contains local IP address. */ - if (ack->type == SC_ACK_TYPE_ESPTOUCH) { + if (ack->type == SC_TYPE_ESPTOUCH) { memcpy(ack->ctx.ip, &local_ip.ip.addr, 4); } @@ -94,12 +118,7 @@ static void sc_ack_send_task(void *pvParameters) if (sendlen > 0) { /* Totally send 30 smartconfig ACKs. Then smartconfig is successful. */ if (packet_count++ >= SC_ACK_MAX_COUNT) { - if (ack->link_flag) { - *ack->link_flag = 1; - } - if (ack->cb) { - ack->cb(SC_STATUS_LINK_OVER, remote_ip); - } + esp_event_post(SC_EVENT, SC_EVENT_SEND_ACK_DONE, NULL, 0, portMAX_DELAY); goto _end; } } @@ -127,31 +146,36 @@ _end: vTaskDelete(NULL); } -void sc_ack_send(sc_ack_t *param) +esp_err_t sc_send_ack_start(smartconfig_type_t type, uint8_t token, uint8_t *cellphone_ip) { sc_ack_t *ack = NULL; - if (param == NULL) { - ESP_LOGE(TAG, "Smart config ack parameter error"); - return; + if (cellphone_ip == NULL) { + ESP_LOGE(TAG, "Cellphone IP address is NULL"); + return ESP_ERR_INVALID_ARG; } ack = malloc(sizeof(sc_ack_t)); if (ack == NULL) { - ESP_LOGE(TAG, "Smart config ack parameter malloc fail"); - return; + ESP_LOGE(TAG, "ACK parameter malloc fail"); + return ESP_ERR_NO_MEM; } - memcpy(ack, param, sizeof(sc_ack_t)); + ack->type = type; + ack->ctx.token = token; + memcpy(ack->ctx.ip, cellphone_ip, 4); s_sc_ack_send = true; if (xTaskCreate(sc_ack_send_task, "sc_ack_send_task", SC_ACK_TASK_STACK_SIZE, ack, SC_ACK_TASK_PRIORITY, NULL) != pdPASS) { ESP_LOGE(TAG, "Create sending smartconfig ACK task fail"); free(ack); + return ESP_ERR_NO_MEM; } + + return ESP_OK; } -void sc_ack_send_stop(void) +void sc_send_ack_stop(void) { s_sc_ack_send = false; } diff --git a/examples/wifi/smart_config/main/smartconfig_main.c b/examples/wifi/smart_config/main/smartconfig_main.c index 3a405ff8a3..0819f256da 100644 --- a/examples/wifi/smart_config/main/smartconfig_main.c +++ b/examples/wifi/smart_config/main/smartconfig_main.c @@ -29,7 +29,7 @@ static EventGroupHandle_t s_wifi_event_group; to the AP with an IP? */ static const int CONNECTED_BIT = BIT0; static const int ESPTOUCH_DONE_BIT = BIT1; -static const char *TAG = "sc"; +static const char *TAG = "smartconfig_example"; static void smartconfig_example_task(void * parm); @@ -43,6 +43,36 @@ static void event_handler(void* arg, esp_event_base_t event_base, xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT); } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT); + } else if (event_base == SC_EVENT && event_id == SC_EVENT_SCAN_DONE) { + ESP_LOGI(TAG, "Scan done"); + } else if (event_base == SC_EVENT && event_id == SC_EVENT_FOUND_CHANNEL) { + ESP_LOGI(TAG, "Found channel"); + } else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD) { + ESP_LOGI(TAG, "Got SSID and password"); + + smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data; + wifi_config_t wifi_config; + uint8_t ssid[33] = { 0 }; + uint8_t password[65] = { 0 }; + + bzero(&wifi_config, sizeof(wifi_config_t)); + memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid)); + memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password)); + wifi_config.sta.bssid_set = evt->bssid_set; + if (wifi_config.sta.bssid_set == true) { + memcpy(wifi_config.sta.bssid, evt->bssid, sizeof(wifi_config.sta.bssid)); + } + + memcpy(ssid, evt->ssid, sizeof(evt->ssid)); + memcpy(password, evt->password, sizeof(evt->password)); + ESP_LOGI(TAG, "SSID:%s", ssid); + ESP_LOGI(TAG, "PASSWORD:%s", password); + + ESP_ERROR_CHECK( esp_wifi_disconnect() ); + ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) ); + ESP_ERROR_CHECK( esp_wifi_connect() ); + } else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE) { + xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT); } } @@ -57,51 +87,18 @@ static void initialise_wifi(void) ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) ); ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL) ); + ESP_ERROR_CHECK( esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) ); ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); ESP_ERROR_CHECK( esp_wifi_start() ); } -static void sc_callback(smartconfig_status_t status, void *pdata) -{ - switch (status) { - case SC_STATUS_WAIT: - ESP_LOGI(TAG, "SC_STATUS_WAIT"); - break; - case SC_STATUS_FIND_CHANNEL: - ESP_LOGI(TAG, "SC_STATUS_FINDING_CHANNEL"); - break; - case SC_STATUS_GETTING_SSID_PSWD: - ESP_LOGI(TAG, "SC_STATUS_GETTING_SSID_PSWD"); - break; - case SC_STATUS_LINK: - ESP_LOGI(TAG, "SC_STATUS_LINK"); - wifi_config_t *wifi_config = pdata; - ESP_LOGI(TAG, "SSID:%s", wifi_config->sta.ssid); - ESP_LOGI(TAG, "PASSWORD:%s", wifi_config->sta.password); - ESP_ERROR_CHECK( esp_wifi_disconnect() ); - ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, wifi_config) ); - ESP_ERROR_CHECK( esp_wifi_connect() ); - break; - case SC_STATUS_LINK_OVER: - ESP_LOGI(TAG, "SC_STATUS_LINK_OVER"); - if (pdata != NULL) { - uint8_t phone_ip[4] = { 0 }; - memcpy(phone_ip, (uint8_t* )pdata, 4); - ESP_LOGI(TAG, "Phone ip: %d.%d.%d.%d\n", phone_ip[0], phone_ip[1], phone_ip[2], phone_ip[3]); - } - xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT); - break; - default: - break; - } -} - static void smartconfig_example_task(void * parm) { EventBits_t uxBits; ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_ESPTOUCH) ); - ESP_ERROR_CHECK( esp_smartconfig_start(sc_callback) ); + smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT(); + ESP_ERROR_CHECK( esp_smartconfig_start(&cfg) ); while (1) { uxBits = xEventGroupWaitBits(s_wifi_event_group, CONNECTED_BIT | ESPTOUCH_DONE_BIT, true, false, portMAX_DELAY); if(uxBits & CONNECTED_BIT) { From cb42c292525f38723ca596d8acef533873019be7 Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Tue, 25 Jun 2019 19:36:56 +0800 Subject: [PATCH 244/486] ethernet: support dm9051 1. move resource allocation from xxx_init to xxx_new 2. fix enabling tx checksum insertion by mistake 3. iperf example: enlarge max arguments 4. add examples for spi-ethernet Closes https://github.com/espressif/esp-idf/issues/3715 Closes https://github.com/espressif/esp-idf/issues/3711 --- components/esp_eth/CMakeLists.txt | 5 + components/esp_eth/Kconfig | 27 +- components/esp_eth/component.mk | 4 + components/esp_eth/include/esp_eth_mac.h | 25 + components/esp_eth/include/esp_eth_phy.h | 12 + components/esp_eth/linker.lf | 3 + components/esp_eth/src/esp_eth_mac_dm9051.c | 852 ++++++++++++++++++ components/esp_eth/src/esp_eth_mac_esp32.c | 87 +- components/esp_eth/src/esp_eth_phy_dm9051.c | 302 +++++++ components/esp_eth/test/test_emac.c | 46 + components/soc/esp32/emac_hal.c | 2 - .../Kconfig.projbuild | 149 ++- .../protocol_examples_common/connect.c | 29 +- examples/ethernet/basic/README.md | 62 +- .../ethernet/basic/main/Kconfig.projbuild | 115 ++- .../basic/main/ethernet_example_main.c | 39 +- examples/ethernet/eth2ap/README.md | 40 +- .../ethernet/eth2ap/main/Kconfig.projbuild | 116 ++- .../eth2ap/main/ethernet_example_main.c | 28 +- examples/ethernet/iperf/README.md | 113 ++- .../ethernet/iperf/main/Kconfig.projbuild | 115 ++- examples/ethernet/iperf/main/cmd_ethernet.c | 28 +- .../iperf/main/ethernet_example_main.c | 2 +- 23 files changed, 1945 insertions(+), 256 deletions(-) create mode 100644 components/esp_eth/src/esp_eth_mac_dm9051.c create mode 100644 components/esp_eth/src/esp_eth_phy_dm9051.c diff --git a/components/esp_eth/CMakeLists.txt b/components/esp_eth/CMakeLists.txt index 5c17f86794..7f41a8409e 100644 --- a/components/esp_eth/CMakeLists.txt +++ b/components/esp_eth/CMakeLists.txt @@ -8,6 +8,11 @@ if(CONFIG_IDF_TARGET_ESP32) list(APPEND esp_eth_srcs "src/esp_eth_mac_esp32.c") endif() +if(CONFIG_ETH_SPI_ETHERNET_DM9051) + list(APPEND esp_eth_srcs "src/esp_eth_mac_dm9051.c" + "src/esp_eth_phy_dm9051.c") +endif() + idf_component_register(SRCS "${esp_eth_srcs}" INCLUDE_DIRS "include" LDFRAGMENTS "linker.lf" diff --git a/components/esp_eth/Kconfig b/components/esp_eth/Kconfig index 275e0d75ea..40e7ee36dc 100644 --- a/components/esp_eth/Kconfig +++ b/components/esp_eth/Kconfig @@ -2,7 +2,7 @@ menu "Ethernet" menuconfig ETH_USE_ESP32_EMAC depends on IDF_TARGET_ESP32 - bool "Use ESP32 internal EMAC controller" + bool "Support ESP32 internal EMAC controller" default y help ESP32 integrates a 10/100M Ethernet MAC controller. @@ -128,4 +128,29 @@ menu "Ethernet" Number of DMA transmit buffers. Each buffer's size is ETH_DMA_BUFFER_SIZE. Larger number of buffers could increase throughput somehow. endif + + menuconfig ETH_USE_SPI_ETHERNET + bool "Support SPI to Ethernet Module" + default y + help + ESP-IDF can also support some SPI-Ethernet module. + + if ETH_USE_SPI_ETHERNET + menuconfig ETH_SPI_ETHERNET_DM9051 + bool "Use DM9051" + default y + help + DM9051 is a fast Ethernet controller with an SPI interface. + It's also integrated with a 10/100M PHY and MAC. + Set true to enable DM9051 driver. + + if ETH_SPI_ETHERNET_DM9051 + config ETH_DM9051_INT_GPIO + int "DM9051 Interrupt GPIO number" + default 4 + range 0 33 + help + Set the GPIO number used by DM9051's Interrupt pin. + endif + endif endmenu diff --git a/components/esp_eth/component.mk b/components/esp_eth/component.mk index 3f02901922..2a5ba23b38 100644 --- a/components/esp_eth/component.mk +++ b/components/esp_eth/component.mk @@ -8,3 +8,7 @@ COMPONENT_ADD_LDFRAGMENTS += linker.lf ifndef CONFIG_IDF_TARGET_ESP32 COMPONENT_OBJEXCLUDE += src/esp_eth_mac_esp32.o endif + +ifndef CONFIG_ETH_SPI_ETHERNET_DM9051 + COMPONENT_OBJEXCLUDE += src/esp_eth_mac_dm9051.o src/esp_eth_phy_dm9051.o +endif diff --git a/components/esp_eth/include/esp_eth_mac.h b/components/esp_eth/include/esp_eth_mac.h index 3c3bd7032a..07507cefed 100644 --- a/components/esp_eth/include/esp_eth_mac.h +++ b/components/esp_eth/include/esp_eth_mac.h @@ -20,6 +20,11 @@ extern "C" { #include #include "esp_eth_com.h" #include "sdkconfig.h" +#if CONFIG_ETH_USE_SPI_ETHERNET +#include "driver/gpio.h" +#include "driver/spi_master.h" +#endif + /** * @brief Ethernet MAC @@ -115,6 +120,7 @@ struct esp_eth_mac_s { * - ESP_OK: read PHY register successfully * - ESP_ERR_INVALID_ARG: read PHY register failed because of invalid argument * - ESP_ERR_INVALID_STATE: read PHY register failed because of wrong state of MAC + * - ESP_ERR_TIMEOUT: read PHY register failed because of timeout * - ESP_FAIL: read PHY register failed because some other error occurred * */ @@ -131,6 +137,7 @@ struct esp_eth_mac_s { * @return * - ESP_OK: write PHY register successfully * - ESP_ERR_INVALID_STATE: write PHY register failed because of wrong state of MAC + * - ESP_ERR_TIMEOUT: write PHY register failed because of timeout * - ESP_FAIL: write PHY register failed because some other error occurred * */ @@ -241,6 +248,10 @@ typedef struct { uint32_t rx_task_stack_size; /*!< Stack size of the receive task */ uint32_t rx_task_prio; /*!< Priority of the receive task */ uint32_t queue_len; /*!< Length of the transaction queue */ +#if CONFIG_ETH_USE_SPI_ETHERNET + spi_device_handle_t spi_hdl; /*!< Handle of spi device */ +#endif + } eth_mac_config_t; /** @@ -255,6 +266,7 @@ typedef struct { .queue_len = 100, \ } +#if CONFIG_ETH_USE_ESP32_EMAC /** * @brief Create ESP32 Ethernet MAC instance * @@ -265,7 +277,20 @@ typedef struct { * - NULL: create MAC instance failed because some error occurred */ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config); +#endif +#if CONFIG_ETH_SPI_ETHERNET_DM9051 +/** +* @brief Create DM9051 Ethernet MAC instance +* +* @param config: Ethernet MAC configuration +* +* @return +* - instance: create MAC instance successfully +* - NULL: create MAC instance failed because some error occurred +*/ +esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_mac_config_t *config); +#endif #ifdef __cplusplus } #endif diff --git a/components/esp_eth/include/esp_eth_phy.h b/components/esp_eth/include/esp_eth_phy.h index 9d29b31494..b30fdad5dd 100644 --- a/components/esp_eth/include/esp_eth_phy.h +++ b/components/esp_eth/include/esp_eth_phy.h @@ -222,6 +222,18 @@ esp_eth_phy_t *esp_eth_phy_new_lan8720(const eth_phy_config_t *config); */ esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config); +#if CONFIG_ETH_SPI_ETHERNET_DM9051 +/** +* @brief Create a PHY instance of DM9051 +* +* @param[in] config: configuration of PHY +* +* @return +* - instance: create PHY instance successfully +* - NULL: create PHY instance failed because some error occurred +*/ +esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config); +#endif #ifdef __cplusplus } #endif diff --git a/components/esp_eth/linker.lf b/components/esp_eth/linker.lf index e8ec8886cc..69f864d8d6 100644 --- a/components/esp_eth/linker.lf +++ b/components/esp_eth/linker.lf @@ -1,8 +1,11 @@ [mapping:esp_eth] archive: libesp_eth.a entries: + if ETH_USE_ESP32_EMAC = y: esp_eth_mac_esp32:emac_hal_tx_complete_cb (noflash_text) esp_eth_mac_esp32:emac_hal_tx_unavail_cb (noflash_text) esp_eth_mac_esp32:emac_hal_rx_complete_cb (noflash_text) esp_eth_mac_esp32:emac_hal_rx_early_cb (noflash_text) esp_eth_mac_esp32:emac_hal_rx_unavail_cb (noflash_text) + if ETH_SPI_ETHERNET_DM9051 = y: + esp_eth_mac_dm9051:dm9051_isr_handler (noflash_text) diff --git a/components/esp_eth/src/esp_eth_mac_dm9051.c b/components/esp_eth/src/esp_eth_mac_dm9051.c new file mode 100644 index 0000000000..b76c5a4fd5 --- /dev/null +++ b/components/esp_eth/src/esp_eth_mac_dm9051.c @@ -0,0 +1,852 @@ +// Copyright 2019 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 +#include +#include +#include "driver/gpio.h" +#include "driver/spi_master.h" +#include "esp_log.h" +#include "esp_eth.h" +#include "esp_system.h" +#include "esp_intr_alloc.h" +#include "esp_heap_caps.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "sdkconfig.h" + +static const char *TAG = "emac_dm9051"; +#define MAC_CHECK(a, str, goto_tag, ret_value, ...) \ + do \ + { \ + if (!(a)) \ + { \ + ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + ret = ret_value; \ + goto goto_tag; \ + } \ + } while (0) + +#define RX_QUEUE_WAIT_MS (100) +#define DM9051_SPI_LOCK_TIMEOUT_MS (50) +#define DM9051_PHY_OPERATION_TIMEOUT_US (1000) + +/** + * @brief Registers in DM9051 + * + */ +#define DM9051_NCR (0x00) // Network Control Register +#define DM9051_NSR (0x01) // Network Status Register +#define DM9051_TCR (0x02) // Tx Control Register +#define DM9051_TSR1 (0x03) // Tx Status Register I +#define DM9051_TSR2 (0x04) // Tx Status Register II +#define DM9051_RCR (0x05) // Rx Control Register +#define DM9051_RSR (0x06) // Rx Status Register +#define DM9051_ROCR (0x07) // Receive Overflow Counter Register +#define DM9051_BPTR (0x08) // Back Pressure Threshold Register +#define DM9051_FCTR (0x09) // Flow Control Threshold Register +#define DM9051_FCR (0x0A) // Rx/Tx Flow Control Register +#define DM9051_EPCR (0x0B) // EEPROM & PHY Control Register +#define DM9051_EPAR (0x0C) // EEPROM & PHY Address Register +#define DM9051_EPDRL (0x0D) // EEPROM & PHY Data Register Low +#define DM9051_EPDRH (0x0E) // EEPROM & PHY Data Register High +#define DM9051_WCR (0x0F) // Wake Up Control Register +#define DM9051_PAR (0x10) // Physical Address Register +#define DM9051_MAR (0x16) // Multicast Address Hash Table Register +#define DM9051_GPCR (0x1E) // General Purpose Control Register +#define DM9051_GPR (0x1F) // General Purpose Register +#define DM9051_TRPAL (0x22) // Tx Memory Read Pointer Address Low Byte +#define DM9051_TRPAH (0x23) // Tx Memory Read Pointer Address High Byte +#define DM9051_RWPAL (0x24) // Rx Memory Read Pointer Address Low Byte +#define DM9051_RWPAH (0x25) // Rx Memory Read Pointer Address High Byte +#define DM9051_VIDL (0x28) // Vendor ID Low Byte +#define DM9051_VIDH (0x29) // Vendor ID High Byte +#define DM9051_PIDL (0x2A) // Product ID Low Byte +#define DM9051_PIDH (0x2B) // Product ID High Byte +#define DM9051_CHIPR (0x2C) // CHIP Revision +#define DM9051_TCR2 (0x2D) // Transmit Control Register 2 +#define DM9051_ATCR (0x30) // Auto-Transmit Control Register +#define DM9051_TCSCR (0x31) // Transmit Check Sum Control Register +#define DM9051_RCSCSR (0x32) // Receive Check Sum Control Status Register +#define DM9051_SBCR (0x38) // SPI Bus Control Register +#define DM9051_INTCR (0x39) // INT Pin Control Register +#define DM9051_PPCSR (0x3D) // Pause Packet Control Status Register +#define DM9051_EEE_IN (0x3E) // IEEE 802.3az Enter Counter Register +#define DM9051_EEE_OUT (0x3F) // IEEE 802.3az Leave Counter Register +#define DM9051_ALNCR (0x4A) // SPI Byte Align Error Counter Register +#define DM9051_RLENCR (0x52) // Rx Packet Length Control Register +#define DM9051_BCASTCR (0x53) // RX Broadcast Control Register +#define DM9051_INTCKCR (0x54) // INT Pin Clock Output Control Register +#define DM9051_MPTRCR (0x55) // Memory Pointer Control Register +#define DM9051_MLEDCR (0x57) // More LED Control Register +#define DM9051_MEMSCR (0x59) // Memory Control Register +#define DM9051_TMEMR (0x5A) // Transmit Memory Size Register +#define DM9051_MBSR (0x5D) // Memory BIST Status Register +#define DM9051_MRCMDX (0x70) // Memory Data Pre-Fetch Read Command Without Address Increment Register +#define DM9051_MRCMDX1 (0x71) // Memory Read Command Without Pre-Fetch and Without Address Increment Register +#define DM9051_MRCMD (0x72) // Memory Data Read Command With Address Increment Register +#define DM9051_SDR_DLY (0x73) // SPI Data Read Delay Counter Register +#define DM9051_MRRL (0x74) // Memory Data Read Address Register Low Byte +#define DM9051_MRRH (0x75) // Memory Data Read Address Register High Byte +#define DM9051_MWCMDX (0x76) // Memory Data Write Command Without Address Increment Register +#define DM9051_MWCMD (0x78) // Memory Data Write Command With Address Increment Register +#define DM9051_MWRL (0x7A) // Memory Data Write Address Register Low Byte +#define DM9051_MWRH (0x7B) // Memory Data Write Address Register High Byte +#define DM9051_TXPLL (0x7C) // TX Packet Length Low Byte Register +#define DM9051_TXPLH (0x7D) // TX Packet Length High Byte Register +#define DM9051_ISR (0x7E) // Interrupt Status Register +#define DM9051_IMR (0x7F) // Interrupt Mask Register + +/** + * @brief status and flag of DM9051 specific registers + * + */ +#define DM9051_SPI_RD (0) // Burst Read Command +#define DM9051_SPI_WR (1) // Burst Write Command + +#define NCR_WAKEEN (1 << 6) // Enable Wakeup Function +#define NCR_FDX (1 << 3) // Duplex Mode of the Internal PHY +#define NCR_RST (1 << 0) // Software Reset and Auto-Clear after 10us + +#define NSR_SPEED (1 << 7) // Speed of Internal PHY +#define NSR_LINKST (1 << 6) // Link Status of Internal PHY +#define NSR_WAKEST (1 << 5) // Wakeup Event Status +#define NSR_TX2END (1 << 3) // TX Packet Index II Complete Status +#define NSR_TX1END (1 << 2) // TX Packet Index I Complete Status +#define NSR_RXOV (1 << 1) // RX Memory Overflow Status +#define NSR_RXRDY (1 << 0) // RX Packet Ready + +#define TCR_TXREQ (1 << 0) // TX Request. Auto-Clear after Sending Completely + +#define RCR_WTDIS (1 << 6) // Watchdog Timer Disable +#define RCR_DIS_LONG (1 << 5) // Discard Long Packet +#define RCR_DIS_CRC (1 << 4) // Discard CRC Error Packet +#define RCR_ALL (1 << 3) // Receive All Multicast +#define RCR_RUNT (1 << 2) // Receive Runt Packet +#define RCR_PRMSC (1 << 1) // Promiscuous Mode +#define RCR_RXEN (1 << 0) // RX Enable + +#define RSR_RF (1 << 7) // Runt Frame +#define RSR_MF (1 << 6) // Multicast Frame +#define RSR_LCS (1 << 5) // Late Collision Seen +#define RSR_RWTO (1 << 4) // Receive Watchdog Time-Out +#define RSR_PLE (1 << 3) // Physical Layer Error +#define RSR_AE (1 << 2) // Alignment Error +#define RSR_CE (1 << 1) // CRC Error +#define RSR_FOE (1 << 0) // RX Memory Overflow Error + +#define FCR_FLOW_ENABLE (0x39) // Enable Flow Control + +#define EPCR_REEP (1 << 5) // Reload EEPROM +#define EPCR_WEP (1 << 4) // Write EEPROM Enable +#define EPCR_EPOS (1 << 3) // EEPROM or PHY Operation Select +#define EPCR_ERPRR (1 << 2) // EEPROM Read or PHY Register Read Command +#define EPCR_ERPRW (1 << 1) // EEPROM Write or PHY Register Write Command +#define EPCR_ERRE (1 << 0) // EEPROM Access Status or PHY Access Status + +#define TCR2_RLCP (1 << 6) // Retry Late Collision Packet + +#define ATCR_AUTO_TX (1 << 7) // Auto-Transmit Control + +#define TCSCR_UDPCSE (1 << 2) // UDP CheckSum Generation +#define TCSCR_TCPCSE (1 << 1) // TCP CheckSum Generation +#define TCSCR_IPCSE (1 << 0) // IPv4 CheckSum Generation + +#define MPTRCR_RST_TX (1 << 1) // Reset TX Memory Pointer +#define MPTRCR_RST_RX (1 << 0) // Reset RX Memory Pointer + +#define ISR_LNKCHGS (1 << 5) // Link Status Change +#define ISR_ROO (1 << 3) // Receive Overflow Counter Overflow +#define ISR_ROS (1 << 2) // Receive Overflow +#define ISR_PT (1 << 1) // Packet Transmitted +#define ISR_PR (1 << 0) // Packet Received +#define ISR_CLR_STATUS (ISR_LNKCHGS | ISR_ROO | ISR_ROS | ISR_PT | ISR_PR) + +#define IMR_PAR (1 << 7) // Pointer Auto-Return Mode +#define IMR_LNKCHGI (1 << 5) // Enable Link Status Change Interrupt +#define IMR_ROOI (1 << 3) // Enable Receive Overflow Counter Overflow Interrupt +#define IMR_ROI (1 << 2) // Enable Receive Overflow Interrupt +#define IMR_PTI (1 << 1) // Enable Packet Transmitted Interrupt +#define IMR_PRI (1 << 0) // Enable Packet Received Interrupt +#define IMR_ALL (IMR_PAR | IMR_LNKCHGI | IMR_ROOI | IMR_ROI | IMR_PTI | IMR_PRI) + +typedef struct { + uint8_t flag; + uint8_t status; + uint8_t length_low; + uint8_t length_high; +} dm9051_rx_header_t; + +typedef struct { + esp_eth_mac_t parent; + esp_eth_mediator_t *eth; + spi_device_handle_t spi_hdl; + SemaphoreHandle_t spi_lock; + TaskHandle_t rx_task_hdl; + uint32_t sw_reset_timeout_ms; + uint8_t addr[6]; + bool packets_remain; +} emac_dm9051_t; + +static inline bool dm9051_lock(emac_dm9051_t *emac) +{ + return xSemaphoreTake(emac->spi_lock, DM9051_SPI_LOCK_TIMEOUT_MS) == pdTRUE; +} + +static inline bool dm9051_unlock(emac_dm9051_t *emac) +{ + return xSemaphoreGive(emac->spi_lock) == pdTRUE; +} + +/** + * @brief write value to dm9051 internal register + */ +static esp_err_t dm9051_register_write(emac_dm9051_t *emac, uint8_t reg_addr, uint8_t value) +{ + esp_err_t ret = ESP_OK; + spi_transaction_t trans = { + .cmd = DM9051_SPI_WR, + .addr = reg_addr, + .length = 8, + .flags = SPI_TRANS_USE_TXDATA + }; + trans.tx_data[0] = value; + if (dm9051_lock(emac)) { + if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) { + ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); + ret = ESP_FAIL; + } + dm9051_unlock(emac); + } else { + ret = ESP_ERR_TIMEOUT; + } + return ret; +} + +/** + * @brief read value from dm9051 internal register + */ +static esp_err_t dm9051_register_read(emac_dm9051_t *emac, uint8_t reg_addr, uint8_t *value) +{ + esp_err_t ret = ESP_OK; + spi_transaction_t trans = { + .cmd = DM9051_SPI_RD, + .addr = reg_addr, + .length = 8, + .flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA + }; + if (dm9051_lock(emac)) { + if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) { + ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); + ret = ESP_FAIL; + } else { + *value = trans.rx_data[0]; + } + dm9051_unlock(emac); + } else { + ret = ESP_ERR_TIMEOUT; + } + return ret; +} + +/** + * @brief write buffer to dm9051 internal memory + */ +static esp_err_t dm9051_memory_write(emac_dm9051_t *emac, uint8_t *buffer, uint32_t len) +{ + esp_err_t ret = ESP_OK; + spi_transaction_t trans = { + .cmd = DM9051_SPI_WR, + .addr = DM9051_MWCMD, + .length = len * 8, + .tx_buffer = buffer + }; + if (dm9051_lock(emac)) { + if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) { + ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); + ret = ESP_FAIL; + } + dm9051_unlock(emac); + } else { + ret = ESP_ERR_TIMEOUT; + } + return ret; +} + +/** + * @brief read buffer from dm9051 internal memory + */ +static esp_err_t dm9051_memory_read(emac_dm9051_t *emac, uint8_t *buffer, uint32_t len) +{ + esp_err_t ret = ESP_OK; + spi_transaction_t trans = { + .cmd = DM9051_SPI_RD, + .addr = DM9051_MRCMD, + .length = len * 8, + .rx_buffer = buffer + }; + if (dm9051_lock(emac)) { + if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) { + ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); + ret = ESP_FAIL; + } + dm9051_unlock(emac); + } else { + ret = ESP_ERR_TIMEOUT; + } + return ret; +} + +/** + * @brief read mac address from internal registers + */ +static esp_err_t dm9051_get_mac_addr(emac_dm9051_t *emac) +{ + esp_err_t ret = ESP_OK; + for (int i = 0; i < 6; i++) { + MAC_CHECK(dm9051_register_read(emac, DM9051_PAR + i, &emac->addr[i]) == ESP_OK, "read PAR failed", err, ESP_FAIL); + } + return ESP_OK; +err: + return ret; +} + +/** + * @brief set new mac address to internal registers + */ +static esp_err_t dm9051_set_mac_addr(emac_dm9051_t *emac) +{ + esp_err_t ret = ESP_OK; + for (int i = 0; i < 6; i++) { + MAC_CHECK(dm9051_register_write(emac, DM9051_PAR + i, emac->addr[i]) == ESP_OK, "write PAR failed", err, ESP_FAIL); + } + return ESP_OK; +err: + return ret; +} + +/** + * @brief clear multicast hash table + */ +static esp_err_t dm9051_clear_multicast_table(emac_dm9051_t *emac) +{ + esp_err_t ret = ESP_OK; + /* rx broadcast packet control by bit7 of MAC register 1DH */ + MAC_CHECK(dm9051_register_write(emac, DM9051_BCASTCR, 0x00) == ESP_OK, "write BCASTCR failed", err, ESP_FAIL); + for (int i = 0; i < 7; i++) { + MAC_CHECK(dm9051_register_write(emac, DM9051_MAR + i, 0x00) == ESP_OK, "write MAR failed", err, ESP_FAIL); + } + /* enable receive broadcast paclets */ + MAC_CHECK(dm9051_register_write(emac, DM9051_MAR + 7, 0x80) == ESP_OK, "write MAR failed", err, ESP_FAIL); + return ESP_OK; +err: + return ret; +} + +/** + * @brief software reset dm9051 internal register + */ +static esp_err_t dm9051_reset(emac_dm9051_t *emac) +{ + esp_err_t ret = ESP_OK; + /* power on phy */ + MAC_CHECK(dm9051_register_write(emac, DM9051_GPR, 0x00) == ESP_OK, "write GPR failed", err, ESP_FAIL); + /* mac and phy register won't be accesable within at least 1ms */ + vTaskDelay(pdMS_TO_TICKS(10)); + /* software reset */ + uint8_t ncr = NCR_RST; + MAC_CHECK(dm9051_register_write(emac, DM9051_NCR, ncr) == ESP_OK, "write NCR failed", err, ESP_FAIL); + uint32_t to = 0; + for (to = 0; to < emac->sw_reset_timeout_ms / 10; to++) { + MAC_CHECK(dm9051_register_read(emac, DM9051_NCR, &ncr) == ESP_OK, "read NCR failed", err, ESP_FAIL); + if (!(ncr & NCR_RST)) { + break; + } + vTaskDelay(pdMS_TO_TICKS(10)); + } + MAC_CHECK(to < emac->sw_reset_timeout_ms / 10, "reset timeout", err, ESP_ERR_TIMEOUT); + return ESP_OK; +err: + return ret; +} + +/** + * @brief verify dm9051 chip ID + */ +static esp_err_t dm9051_verify_id(emac_dm9051_t *emac) +{ + esp_err_t ret = ESP_OK; + uint8_t id[2]; + MAC_CHECK(dm9051_register_read(emac, DM9051_VIDL, &id[0]) == ESP_OK, "read VIDL failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_read(emac, DM9051_VIDH, &id[1]) == ESP_OK, "read VIDH failed", err, ESP_FAIL); + MAC_CHECK(0x0A46 == *(uint16_t *)id, "wrong Vendor ID", err, ESP_ERR_INVALID_VERSION); + MAC_CHECK(dm9051_register_read(emac, DM9051_PIDL, &id[0]) == ESP_OK, "read PIDL failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_read(emac, DM9051_PIDH, &id[1]) == ESP_OK, "read PIDH failed", err, ESP_FAIL); + MAC_CHECK(0x9051 == *(uint16_t *)id, "wrong Product ID", err, ESP_ERR_INVALID_VERSION); + return ESP_OK; +err: + return ret; +} + +/** + * @brief default setup for dm9051 internal registers + */ +static esp_err_t dm9051_setup_default(emac_dm9051_t *emac) +{ + esp_err_t ret = ESP_OK; + /* disable wakeup */ + MAC_CHECK(dm9051_register_write(emac, DM9051_NCR, 0x00) == ESP_OK, "write NCR failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_write(emac, DM9051_WCR, 0x00) == ESP_OK, "write WCR failed", err, ESP_FAIL); + /* stop transmitting, enable appending pad, crc for packets */ + MAC_CHECK(dm9051_register_write(emac, DM9051_TCR, 0x00) == ESP_OK, "write TCR failed", err, ESP_FAIL); + /* stop receiving, no promiscuous mode, no runt packet(size < 64bytes), not all multicast packets*/ + /* discard long packet(size > 1522bytes) and crc error packet, enable watchdog */ + MAC_CHECK(dm9051_register_write(emac, DM9051_RCR, RCR_DIS_LONG | RCR_DIS_CRC) == ESP_OK, "write RCR failed", err, ESP_FAIL); + /* send jam pattern (duration time = 1.15ms) when rx free space < 3k bytes */ + MAC_CHECK(dm9051_register_write(emac, DM9051_BPTR, 0x3F) == ESP_OK, "write BPTR failed", err, ESP_FAIL); + /* flow control: high water threshold = 3k bytes, low water threshold = 8k bytes */ + MAC_CHECK(dm9051_register_write(emac, DM9051_FCTR, 0x38) == ESP_OK, "write FCTR failed", err, ESP_FAIL); + /* enable flow control */ + MAC_CHECK(dm9051_register_write(emac, DM9051_FCR, FCR_FLOW_ENABLE) == ESP_OK, "write FCR failed", err, ESP_FAIL); + /* retry late collision packet, at most two transmit command can be issued before transmit complete */ + MAC_CHECK(dm9051_register_write(emac, DM9051_TCR2, TCR2_RLCP) == ESP_OK, "write TCR2 failed", err, ESP_FAIL); + /* enable auto transmit */ + MAC_CHECK(dm9051_register_write(emac, DM9051_ATCR, ATCR_AUTO_TX) == ESP_OK, "write ATCR failed", err, ESP_FAIL); + /* generate checksum for UDP, TCP and IPv4 packets */ + MAC_CHECK(dm9051_register_write(emac, DM9051_TCSCR, TCSCR_IPCSE | TCSCR_TCPCSE | TCSCR_UDPCSE) == ESP_OK, + "write TCSCR failed", err, ESP_FAIL); + /* disable check sum for receive packets */ + MAC_CHECK(dm9051_register_write(emac, DM9051_RCSCSR, 0x00) == ESP_OK, "write RCSCSR failed", err, ESP_FAIL); + /* interrupt pin config: push-pull output, active high */ + MAC_CHECK(dm9051_register_write(emac, DM9051_INTCR, 0x00) == ESP_OK, "write INTCR failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_write(emac, DM9051_INTCKCR, 0x00) == ESP_OK, "write INTCKCR failed", err, ESP_FAIL); + /* no length limitation for rx packets */ + MAC_CHECK(dm9051_register_write(emac, DM9051_RLENCR, 0x00) == ESP_OK, "write RLENCR failed", err, ESP_FAIL); + /* 3K-byte for TX and 13K-byte for RX */ + MAC_CHECK(dm9051_register_write(emac, DM9051_MEMSCR, 0x00) == ESP_OK, "write MEMSCR failed", err, ESP_FAIL); + /* reset tx and rx memory pointer */ + MAC_CHECK(dm9051_register_write(emac, DM9051_MPTRCR, MPTRCR_RST_RX | MPTRCR_RST_TX) == ESP_OK, + "write MPTRCR failed", err, ESP_FAIL); + /* clear network status: wakeup event, tx complete */ + MAC_CHECK(dm9051_register_write(emac, DM9051_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END) == ESP_OK, "write NSR failed", err, ESP_FAIL); + /* clear interrupt status */ + MAC_CHECK(dm9051_register_write(emac, DM9051_ISR, ISR_CLR_STATUS) == ESP_OK, "write ISR failed", err, ESP_FAIL); + return ESP_OK; +err: + return ret; +} + +/** + * @brief start dm9051: enable interrupt and start receive + */ +static esp_err_t dm9051_start(emac_dm9051_t *emac) +{ + esp_err_t ret = ESP_OK; + /* enable interrupt */ + MAC_CHECK(dm9051_register_write(emac, DM9051_IMR, IMR_ALL) == ESP_OK, "write IMR failed", err, ESP_FAIL); + /* enable rx */ + uint8_t rcr = 0; + MAC_CHECK(dm9051_register_read(emac, DM9051_RCR, &rcr) == ESP_OK, "read RCR failed", err, ESP_FAIL); + rcr |= RCR_RXEN; + MAC_CHECK(dm9051_register_write(emac, DM9051_RCR, rcr) == ESP_OK, "write RCR failed", err, ESP_FAIL); + return ESP_OK; +err: + return ret; +} + +/** + * @brief stop dm9051: disable interrupt and stop receive + */ +static esp_err_t dm9051_stop(emac_dm9051_t *emac) +{ + esp_err_t ret = ESP_OK; + /* disable interrupt */ + MAC_CHECK(dm9051_register_write(emac, DM9051_IMR, 0x00) == ESP_OK, "write IMR failed", err, ESP_FAIL); + /* disable rx */ + uint8_t rcr = 0; + MAC_CHECK(dm9051_register_read(emac, DM9051_RCR, &rcr) == ESP_OK, "read RCR failed", err, ESP_FAIL); + rcr &= ~RCR_RXEN; + MAC_CHECK(dm9051_register_write(emac, DM9051_RCR, rcr) == ESP_OK, "write RCR failed", err, ESP_FAIL); + return ESP_OK; +err: + return ret; +} + +static void dm9051_isr_handler(void *arg) +{ + emac_dm9051_t *emac = (emac_dm9051_t *)arg; + BaseType_t high_task_wakeup = pdFALSE; + /* notify dm9051 task */ + vTaskNotifyGiveFromISR(emac->rx_task_hdl, &high_task_wakeup); + if (high_task_wakeup != pdFALSE) { + portYIELD_FROM_ISR(); + } +} + +static void emac_dm9051_task(void *arg) +{ + emac_dm9051_t *emac = (emac_dm9051_t *)arg; + uint8_t status = 0; + uint8_t *buffer = NULL; + uint32_t length = 0; + while (1) { + if (ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(RX_QUEUE_WAIT_MS))) { + /* clear interrupt status */ + dm9051_register_read(emac, DM9051_ISR, &status); + dm9051_register_write(emac, DM9051_ISR, status); + /* packet received */ + if (status & ISR_PR) { + do { + buffer = (uint8_t *)heap_caps_malloc(ETH_MAX_PACKET_SIZE, MALLOC_CAP_DMA); + if (emac->parent.receive(&emac->parent, buffer, &length) == ESP_OK) { + /* pass the buffer to stack (e.g. TCP/IP layer) */ + emac->eth->stack_input(emac->eth, buffer, length); + } else { + free(buffer); + } + } while (emac->packets_remain); + } + } + } + vTaskDelete(NULL); +} + +static esp_err_t emac_dm9051_set_mediator(esp_eth_mac_t *mac, esp_eth_mediator_t *eth) +{ + esp_err_t ret = ESP_OK; + MAC_CHECK(eth, "can't set mac's mediator to null", err, ESP_ERR_INVALID_ARG); + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + emac->eth = eth; + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_write_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value) +{ + esp_err_t ret = ESP_OK; + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + /* check if phy access is in progress */ + uint8_t epcr = 0; + MAC_CHECK(dm9051_register_read(emac, DM9051_EPCR, &epcr) == ESP_OK, "read EPCR failed", err, ESP_FAIL); + MAC_CHECK(!(epcr & EPCR_ERRE), "phy is busy", err, ESP_ERR_INVALID_STATE); + MAC_CHECK(dm9051_register_write(emac, DM9051_EPAR, (uint8_t)(((phy_addr << 6) & 0xFF) | phy_reg)) == ESP_OK, + "write EPAR failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_write(emac, DM9051_EPDRL, (uint8_t)(reg_value & 0xFF)) == ESP_OK, + "write EPDRL failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_write(emac, DM9051_EPDRH, (uint8_t)((reg_value >> 8) & 0xFF)) == ESP_OK, + "write EPDRH failed", err, ESP_FAIL); + /* select PHY and select write operation */ + MAC_CHECK(dm9051_register_write(emac, DM9051_EPCR, EPCR_EPOS | EPCR_ERPRW) == ESP_OK, "write EPCR failed", err, ESP_FAIL); + /* polling the busy flag */ + uint32_t to = 0; + do { + ets_delay_us(100); + MAC_CHECK(dm9051_register_read(emac, DM9051_EPCR, &epcr) == ESP_OK, "read EPCR failed", err, ESP_FAIL); + to += 100; + } while ((epcr & EPCR_ERRE) && to < DM9051_PHY_OPERATION_TIMEOUT_US); + MAC_CHECK(!(epcr & EPCR_ERRE), "phy is busy", err, ESP_ERR_TIMEOUT); + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_read_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value) +{ + esp_err_t ret = ESP_OK; + MAC_CHECK(reg_value, "can't set reg_value to null", err, ESP_ERR_INVALID_ARG); + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + /* check if phy access is in progress */ + uint8_t epcr = 0; + MAC_CHECK(dm9051_register_read(emac, DM9051_EPCR, &epcr) == ESP_OK, "read EPCR failed", err, ESP_FAIL); + MAC_CHECK(!(epcr & 0x01), "phy is busy", err, ESP_ERR_INVALID_STATE); + MAC_CHECK(dm9051_register_write(emac, DM9051_EPAR, (uint8_t)(((phy_addr << 6) & 0xFF) | phy_reg)) == ESP_OK, + "write EPAR failed", err, ESP_FAIL); + /* Select PHY and select read operation */ + MAC_CHECK(dm9051_register_write(emac, DM9051_EPCR, 0x0C) == ESP_OK, "write EPCR failed", err, ESP_FAIL); + /* polling the busy flag */ + uint32_t to = 0; + do { + ets_delay_us(100); + MAC_CHECK(dm9051_register_read(emac, DM9051_EPCR, &epcr) == ESP_OK, "read EPCR failed", err, ESP_FAIL); + to += 100; + } while ((epcr & EPCR_ERRE) && to < DM9051_PHY_OPERATION_TIMEOUT_US); + MAC_CHECK(!(epcr & EPCR_ERRE), "phy is busy", err, ESP_ERR_TIMEOUT); + uint8_t value_h = 0; + uint8_t value_l = 0; + MAC_CHECK(dm9051_register_read(emac, DM9051_EPDRH, &value_h) == ESP_OK, "read EPDRH failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_read(emac, DM9051_EPDRL, &value_l) == ESP_OK, "read EPDRL failed", err, ESP_FAIL); + *reg_value = (value_h << 8) | value_l; + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_set_addr(esp_eth_mac_t *mac, uint8_t *addr) +{ + esp_err_t ret = ESP_OK; + MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG); + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + memcpy(emac->addr, addr, 6); + MAC_CHECK(dm9051_set_mac_addr(emac) == ESP_OK, "set mac address failed", err, ESP_FAIL); + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_get_addr(esp_eth_mac_t *mac, uint8_t *addr) +{ + esp_err_t ret = ESP_OK; + MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG); + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + memcpy(addr, emac->addr, 6); + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_set_link(esp_eth_mac_t *mac, eth_link_t link) +{ + esp_err_t ret = ESP_OK; + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + uint8_t nsr = 0; + MAC_CHECK(dm9051_register_read(emac, DM9051_NSR, &nsr) == ESP_OK, "read NSR failed", err, ESP_FAIL); + switch (link) { + case ETH_LINK_UP: + MAC_CHECK(nsr & NSR_LINKST, "phy is not link up", err, ESP_ERR_INVALID_STATE); + MAC_CHECK(dm9051_start(emac) == ESP_OK, "dm9051 start failed", err, ESP_FAIL); + break; + case ETH_LINK_DOWN: + MAC_CHECK(!(nsr & NSR_LINKST), "phy is not link down", err, ESP_ERR_INVALID_STATE); + MAC_CHECK(dm9051_stop(emac) == ESP_OK, "dm9051 stop failed", err, ESP_FAIL); + break; + default: + MAC_CHECK(false, "unknown link status", err, ESP_ERR_INVALID_ARG); + break; + } + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_set_speed(esp_eth_mac_t *mac, eth_speed_t speed) +{ + esp_err_t ret = ESP_OK; + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + uint8_t nsr = 0; + MAC_CHECK(dm9051_register_read(emac, DM9051_NSR, &nsr) == ESP_OK, "read NSR failed", err, ESP_FAIL); + switch (speed) { + case ETH_SPEED_10M: + MAC_CHECK(nsr & NSR_SPEED, "phy speed is not at 10Mbps", err, ESP_ERR_INVALID_STATE); + break; + case ETH_SPEED_100M: + MAC_CHECK(!(nsr & NSR_SPEED), "phy speed is not at 100Mbps", err, ESP_ERR_INVALID_STATE); + break; + default: + MAC_CHECK(false, "unknown speed", err, ESP_ERR_INVALID_ARG); + break; + } + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_set_duplex(esp_eth_mac_t *mac, eth_duplex_t duplex) +{ + esp_err_t ret = ESP_OK; + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + uint8_t ncr = 0; + MAC_CHECK(dm9051_register_read(emac, DM9051_NCR, &ncr) == ESP_OK, "read NCR failed", err, ESP_FAIL); + switch (duplex) { + case ETH_DUPLEX_HALF: + MAC_CHECK(!(ncr & NCR_FDX), "phy is not at half duplex", err, ESP_ERR_INVALID_STATE); + break; + case ETH_DUPLEX_FULL: + MAC_CHECK(ncr & NCR_FDX, "phy is not at full duplex", err, ESP_ERR_INVALID_STATE); + break; + default: + MAC_CHECK(false, "unknown duplex", err, ESP_ERR_INVALID_ARG); + break; + } + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_set_promiscuous(esp_eth_mac_t *mac, bool enable) +{ + esp_err_t ret = ESP_OK; + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + uint8_t rcr = 0; + MAC_CHECK(dm9051_register_read(emac, DM9051_EPDRL, &rcr) == ESP_OK, "read RCR failed", err, ESP_FAIL); + if (enable) { + rcr |= RCR_PRMSC; + } else { + rcr &= ~RCR_PRMSC; + } + MAC_CHECK(dm9051_register_write(emac, DM9051_RCR, rcr) == ESP_OK, "write RCR failed", err, ESP_FAIL); + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint32_t length) +{ + esp_err_t ret = ESP_OK; + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + MAC_CHECK(buf, "can't set buf to null", err, ESP_ERR_INVALID_ARG); + MAC_CHECK(length, "buf length can't be zero", err, ESP_ERR_INVALID_ARG); + /* Check if last transmit complete */ + uint8_t tcr = 0; + MAC_CHECK(dm9051_register_read(emac, DM9051_TCR, &tcr) == ESP_OK, "read TCR failed", err, ESP_FAIL); + MAC_CHECK(!(tcr & TCR_TXREQ), "last transmit still in progress", err, ESP_ERR_INVALID_STATE); + /* set tx length */ + MAC_CHECK(dm9051_register_write(emac, DM9051_TXPLL, length & 0xFF) == ESP_OK, "write TXPLL failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_write(emac, DM9051_TXPLH, (length >> 8) & 0xFF) == ESP_OK, "write TXPLH failed", err, ESP_FAIL); + /* copy data to tx memory */ + MAC_CHECK(dm9051_memory_write(emac, buf, length) == ESP_OK, "write memory failed", err, ESP_FAIL); + /* issue tx polling command */ + tcr |= TCR_TXREQ; + MAC_CHECK(dm9051_register_write(emac, DM9051_TCR, tcr) == ESP_OK, "write TCR failed", err, ESP_FAIL); + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t *length) +{ + esp_err_t ret = ESP_OK; + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + MAC_CHECK(buf && length, "can't set buf and length to null", err, ESP_ERR_INVALID_ARG); + uint8_t rxbyte = 0; + uint16_t rx_len = 0; + __attribute__((aligned(4))) dm9051_rx_header_t header; // SPI driver needs the rx buffer 4 byte align + emac->packets_remain = false; + /* dummy read, get the most updated data */ + MAC_CHECK(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte) == ESP_OK, "read MRCMDX failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte) == ESP_OK, "read MRCMDX failed", err, ESP_FAIL); + /* rxbyte must be 0xFF, 0 or 1 */ + if (rxbyte > 1) { + MAC_CHECK(dm9051_stop(emac) == ESP_OK, "stop dm9051 failed", err, ESP_FAIL); + /* reset rx fifo pointer */ + MAC_CHECK(dm9051_register_write(emac, DM9051_MPTRCR, MPTRCR_RST_RX) == ESP_OK, "write MPTRCR failed", err, ESP_FAIL); + ets_delay_us(10); + MAC_CHECK(dm9051_start(emac) == ESP_OK, "start dm9051 failed", err, ESP_FAIL); + MAC_CHECK(false, "reset rx fifo pointer", err, ESP_FAIL); + } else if (rxbyte) { + MAC_CHECK(dm9051_memory_read(emac, (uint8_t *)&header, sizeof(header)) == ESP_OK, "read rx header failed", err, ESP_FAIL); + rx_len = header.length_low + (header.length_high << 8); + MAC_CHECK(dm9051_memory_read(emac, buf, rx_len) == ESP_OK, "read rx data failed", err, ESP_FAIL); + MAC_CHECK(!(header.status & 0xBF), "receive status error: %xH", err, ESP_FAIL, header.status); + *length = rx_len - 4; // substract the CRC length (4Bytes) + /* dummy read, get the most updated data */ + MAC_CHECK(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte) == ESP_OK, "read MRCMDX failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte) == ESP_OK, "read MRCMDX failed", err, ESP_FAIL); + emac->packets_remain = rxbyte > 0; + } + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_init(esp_eth_mac_t *mac) +{ + esp_err_t ret = ESP_OK; + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + esp_eth_mediator_t *eth = emac->eth; + /* init gpio used by spi-ethernet interrupt */ + gpio_pad_select_gpio(CONFIG_ETH_DM9051_INT_GPIO); + gpio_set_direction(CONFIG_ETH_DM9051_INT_GPIO, GPIO_MODE_INPUT); + gpio_set_pull_mode(CONFIG_ETH_DM9051_INT_GPIO, GPIO_PULLDOWN_ONLY); + gpio_set_intr_type(CONFIG_ETH_DM9051_INT_GPIO, GPIO_INTR_POSEDGE); + gpio_intr_enable(CONFIG_ETH_DM9051_INT_GPIO); + gpio_isr_handler_add(CONFIG_ETH_DM9051_INT_GPIO, dm9051_isr_handler, emac); + MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL) == ESP_OK, "lowlevel init failed", err, ESP_FAIL); + /* reset dm9051 */ + MAC_CHECK(dm9051_reset(emac) == ESP_OK, "reset dm9051 failed", err, ESP_FAIL); + /* verify chip id */ + MAC_CHECK(dm9051_verify_id(emac) == ESP_OK, "vefiry chip ID failed", err, ESP_FAIL); + /* default setup of internal registers */ + MAC_CHECK(dm9051_setup_default(emac) == ESP_OK, "dm9051 default setup failed", err, ESP_FAIL); + /* clear multicast hash table */ + MAC_CHECK(dm9051_clear_multicast_table(emac) == ESP_OK, "clear multicast table failed", err, ESP_FAIL); + /* get emac address from eeprom */ + MAC_CHECK(dm9051_get_mac_addr(emac) == ESP_OK, "fetch ethernet mac address failed", err, ESP_FAIL); + return ESP_OK; +err: + gpio_isr_handler_remove(CONFIG_ETH_DM9051_INT_GPIO); + gpio_reset_pin(CONFIG_ETH_DM9051_INT_GPIO); + eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL); + return ret; +} + +static esp_err_t emac_dm9051_deinit(esp_eth_mac_t *mac) +{ + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + esp_eth_mediator_t *eth = emac->eth; + dm9051_stop(emac); + gpio_isr_handler_remove(CONFIG_ETH_DM9051_INT_GPIO); + gpio_reset_pin(CONFIG_ETH_DM9051_INT_GPIO); + eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL); + return ESP_OK; +} + +static esp_err_t emac_dm9051_del(esp_eth_mac_t *mac) +{ + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + vTaskDelete(emac->rx_task_hdl); + vSemaphoreDelete(emac->spi_lock); + free(emac); + return ESP_OK; +} + +esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_mac_config_t *config) +{ + esp_eth_mac_t *ret = NULL; + MAC_CHECK(config, "can't set mac config to null", err, NULL); + MAC_CHECK(config->spi_hdl, "can't set spi handle to null", err, NULL); + emac_dm9051_t *emac = calloc(1, sizeof(emac_dm9051_t)); + MAC_CHECK(emac, "calloc emac failed", err, NULL); + /* bind methods and attributes */ + emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms; + emac->spi_hdl = config->spi_hdl; + emac->parent.set_mediator = emac_dm9051_set_mediator; + emac->parent.init = emac_dm9051_init; + emac->parent.deinit = emac_dm9051_deinit; + emac->parent.del = emac_dm9051_del; + emac->parent.write_phy_reg = emac_dm9051_write_phy_reg; + emac->parent.read_phy_reg = emac_dm9051_read_phy_reg; + emac->parent.set_addr = emac_dm9051_set_addr; + emac->parent.get_addr = emac_dm9051_get_addr; + emac->parent.set_speed = emac_dm9051_set_speed; + emac->parent.set_duplex = emac_dm9051_set_duplex; + emac->parent.set_link = emac_dm9051_set_link; + emac->parent.set_promiscuous = emac_dm9051_set_promiscuous; + emac->parent.transmit = emac_dm9051_transmit; + emac->parent.receive = emac_dm9051_receive; + /* create mutex */ + emac->spi_lock = xSemaphoreCreateMutex(); + MAC_CHECK(emac->spi_lock, "create lock failed", err_lock, NULL); + /* create dm9051 task */ + BaseType_t xReturned = xTaskCreate(emac_dm9051_task, "dm9051_tsk", config->rx_task_stack_size, emac, + config->rx_task_prio, &emac->rx_task_hdl); + MAC_CHECK(xReturned == pdPASS, "create dm9051 task failed", err_tsk, NULL); + return &(emac->parent); +err_tsk: + vSemaphoreDelete(emac->spi_lock); +err_lock: + free(emac); +err: + return ret; +} diff --git a/components/esp_eth/src/esp_eth_mac_esp32.c b/components/esp_eth/src/esp_eth_mac_esp32.c index f68a16ac9e..1c1fbcc90c 100644 --- a/components/esp_eth/src/esp_eth_mac_esp32.c +++ b/components/esp_eth/src/esp_eth_mac_esp32.c @@ -41,6 +41,7 @@ static const char *TAG = "emac_esp32"; } while (0) #define RX_QUEUE_WAIT_MS (20) +#define PHY_OPERATION_TIMEOUT_US (1000) typedef struct { esp_eth_mac_t parent; @@ -49,12 +50,8 @@ typedef struct { intr_handle_t intr_hdl; SemaphoreHandle_t rx_counting_sem; TaskHandle_t rx_task_hdl; - const char *name; uint32_t sw_reset_timeout_ms; uint32_t frames_remain; - uint32_t rx_task_stack_size; - uint32_t rx_task_prio; - uint32_t queue_len; uint8_t addr[6]; uint8_t *rx_buf[CONFIG_ETH_DMA_RX_BUFFER_NUM]; uint8_t *tx_buf[CONFIG_ETH_DMA_TX_BUFFER_NUM]; @@ -78,9 +75,15 @@ static esp_err_t emac_esp32_write_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, MAC_CHECK(!emac_hal_is_mii_busy(emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE); emac_hal_set_phy_data(emac->hal, reg_value); emac_hal_set_phy_cmd(emac->hal, phy_addr, phy_reg, true); - /* Delay some time and Check for the Busy flag */ - ets_delay_us(1000); - MAC_CHECK(!emac_hal_is_mii_busy(emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE); + /* polling the busy flag */ + uint32_t to = 0; + bool busy = true; + do { + ets_delay_us(100); + busy = emac_hal_is_mii_busy(emac->hal); + to += 100; + } while (busy && to < PHY_OPERATION_TIMEOUT_US); + MAC_CHECK(!busy, "phy is busy", err, ESP_ERR_TIMEOUT); return ESP_OK; err: return ret; @@ -93,9 +96,15 @@ static esp_err_t emac_esp32_read_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); MAC_CHECK(!emac_hal_is_mii_busy(emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE); emac_hal_set_phy_cmd(emac->hal, phy_addr, phy_reg, false); - /* Delay some time and Check for the Busy flag */ - ets_delay_us(1000); - MAC_CHECK(!emac_hal_is_mii_busy(emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE); + /* polling the busy flag */ + uint32_t to = 0; + bool busy = true; + do { + ets_delay_us(100); + busy = emac_hal_is_mii_busy(emac->hal); + to += 100; + } while (busy && to < PHY_OPERATION_TIMEOUT_US); + MAC_CHECK(!busy, "phy is busy", err, ESP_ERR_TIMEOUT); /* Store value */ *reg_value = emac_hal_get_phy_data(emac->hal); return ESP_OK; @@ -224,16 +233,14 @@ err: static void emac_esp32_rx_task(void *arg) { emac_esp32_t *emac = (emac_esp32_t *)arg; - esp_eth_mediator_t *eth = emac->eth; uint8_t *buffer = NULL; uint32_t length = 0; - while (1) { if (xSemaphoreTake(emac->rx_counting_sem, pdMS_TO_TICKS(RX_QUEUE_WAIT_MS)) == pdTRUE) { buffer = (uint8_t *)malloc(ETH_MAX_PACKET_SIZE); if (emac_esp32_receive(&emac->parent, buffer, &length) == ESP_OK) { /* pass the buffer to stack (e.g. TCP/IP layer) */ - eth->stack_input(eth, buffer, length); + emac->eth->stack_input(emac->eth, buffer, length); } else { free(buffer); } @@ -298,50 +305,32 @@ static esp_err_t emac_esp32_init(esp_eth_mac_t *mac) MAC_CHECK(esp_read_mac(emac->addr, ESP_MAC_ETH) == ESP_OK, "fetch ethernet mac address failed", err, ESP_FAIL); /* set MAC address to emac register */ emac_hal_set_address(emac->hal, emac->addr); - /* Interrupt configuration */ - MAC_CHECK(esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, ESP_INTR_FLAG_IRAM, emac_hal_isr, - &emac->hal, &(emac->intr_hdl)) == ESP_OK, - "alloc emac interrupt failed", err, ESP_FAIL); - /* create counting semaphore */ - emac->rx_counting_sem = xSemaphoreCreateCounting(emac->queue_len, 0); - MAC_CHECK(emac->rx_counting_sem, "create semaphore failed", err_sem, ESP_FAIL); - /* create rx task */ - BaseType_t xReturned = xTaskCreate(emac_esp32_rx_task, "emac_rx", emac->rx_task_stack_size, emac, - emac->rx_task_prio, &emac->rx_task_hdl); - MAC_CHECK(xReturned == pdPASS, "create emac_rx task failed", err_task, ESP_FAIL); return ESP_OK; -err_task: - vSemaphoreDelete(emac->rx_counting_sem); -err_sem: - esp_intr_free(emac->intr_hdl); err: - periph_module_disable(PERIPH_EMAC_MODULE); eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL); + periph_module_disable(PERIPH_EMAC_MODULE); return ret; } static esp_err_t emac_esp32_deinit(esp_eth_mac_t *mac) { - esp_err_t ret = ESP_OK; emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); esp_eth_mediator_t *eth = emac->eth; #if CONFIG_ETH_PHY_USE_RST gpio_set_level(CONFIG_ETH_PHY_RST_GPIO, 0); #endif emac_hal_stop(emac->hal); - MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL) == ESP_OK, "lowlevel deinit failed", err, ESP_FAIL); - MAC_CHECK(esp_intr_free(emac->intr_hdl) == ESP_OK, "free emac interrupt failed", err, ESP_FAIL); - vTaskDelete(emac->rx_task_hdl); - vSemaphoreDelete(emac->rx_counting_sem); + eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL); periph_module_disable(PERIPH_EMAC_MODULE); return ESP_OK; -err: - return ret; } static esp_err_t emac_esp32_del(esp_eth_mac_t *mac) { emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); + esp_intr_free(emac->intr_hdl); + vTaskDelete(emac->rx_task_hdl); + vSemaphoreDelete(emac->rx_counting_sem); int i = 0; for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { free(emac->hal->rx_buf[i]); @@ -400,10 +389,6 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config) /* initialize hal layer driver */ emac_hal_init(emac->hal, descriptors, emac->rx_buf, emac->tx_buf); emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms; - emac->rx_task_stack_size = config->rx_task_stack_size; - emac->rx_task_prio = config->rx_task_prio; - emac->queue_len = config->queue_len; - emac->name = "emac_esp32"; emac->parent.set_mediator = emac_esp32_set_mediator; emac->parent.init = emac_esp32_init; emac->parent.deinit = emac_esp32_deinit; @@ -418,7 +403,29 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config) emac->parent.set_promiscuous = emac_esp32_set_promiscuous; emac->parent.transmit = emac_esp32_transmit; emac->parent.receive = emac_esp32_receive; + /* Interrupt configuration */ + MAC_CHECK(esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, ESP_INTR_FLAG_IRAM, emac_hal_isr, + &emac->hal, &(emac->intr_hdl)) == ESP_OK, + "alloc emac interrupt failed", err_intr, NULL); + /* create counting semaphore */ + emac->rx_counting_sem = xSemaphoreCreateCounting(config->queue_len, 0); + MAC_CHECK(emac->rx_counting_sem, "create semaphore failed", err_sem, NULL); + /* create rx task */ + BaseType_t xReturned = xTaskCreate(emac_esp32_rx_task, "emac_rx", config->rx_task_stack_size, emac, + config->rx_task_prio, &emac->rx_task_hdl); + MAC_CHECK(xReturned == pdPASS, "create emac_rx task failed", err_task, NULL); return &(emac->parent); +err_task: + vSemaphoreDelete(emac->rx_counting_sem); +err_sem: + esp_intr_free(emac->intr_hdl); +err_intr: + for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { + free(emac->tx_buf[i]); + } + for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { + free(emac->rx_buf[i]); + } err_buffer: free(emac->hal); err_hal: diff --git a/components/esp_eth/src/esp_eth_phy_dm9051.c b/components/esp_eth/src/esp_eth_phy_dm9051.c new file mode 100644 index 0000000000..cb658c181d --- /dev/null +++ b/components/esp_eth/src/esp_eth_phy_dm9051.c @@ -0,0 +1,302 @@ +// Copyright 2019 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 +#include +#include +#include "esp_log.h" +#include "esp_eth.h" +#include "eth_phy_regs_struct.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +static const char *TAG = "dm9051"; +#define PHY_CHECK(a, str, goto_tag, ...) \ + do \ + { \ + if (!(a)) \ + { \ + ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + goto goto_tag; \ + } \ + } while (0) + +/***************Vendor Specific Register***************/ + +/** + * @brief DSCR(DAVICOM Specified Configuration Register) + * + */ +typedef union { + struct { + uint32_t reserved1 : 1; /* Reserved */ + uint32_t sleep : 1; /* Set 1 to enable PHY into sleep mode */ + uint32_t mfpsc : 1; /* MII frame preamble suppression control bit */ + uint32_t smrst : 1; /* Set 1 to reset all state machines of PHY */ + uint32_t rpdctr_en : 1; /* Set 1 to enable automatic reduced power down */ + uint32_t reserved2 : 2; /* Reserved */ + uint32_t flink100 : 1; /* Force Good Link in 100Mbps */ + uint32_t reserved3 : 2; /* Reserved */ + uint32_t tx_fx : 1; /* 100BASE-TX or FX Mode Control */ + uint32_t reserved4 : 1; /* Reserved */ + uint32_t bp_adpok : 1; /* BYPASS ADPOK */ + uint32_t bp_align : 1; /* Bypass Symbol Alignment Function */ + uint32_t bp_scr : 1; /* Bypass Scrambler/Descrambler Function */ + uint32_t bp_4b5b : 1; /* Bypass 4B5B Encoding and 5B4B Decoding */ + }; + uint32_t val; +} dscr_reg_t; +#define ETH_PHY_DSCR_REG_ADDR (0x10) + +/** + * @brief DSCSR(DAVICOM Specified Configuration and Status Register) + * + */ +typedef union { + struct { + uint32_t anmb : 4; /* Auto-Negotiation Monitor Bits */ + uint32_t phy_addr : 5; /* PHY Address */ + uint32_t reserved : 3; /* Reserved */ + uint32_t hdx10 : 1; /* 10M Half-Duplex Operation Mode */ + uint32_t fdx10 : 1; /* 10M Full-Duplex Operation Mode */ + uint32_t hdx100 : 1; /* 100M Half-Duplex Operation Mode */ + uint32_t fdx100 : 1; /* 100M Full-Duplex Operation Mode */ + }; + uint32_t val; +} dscsr_reg_t; +#define ETH_PHY_DSCSR_REG_ADDR (0x11) + +typedef struct { + esp_eth_phy_t parent; + esp_eth_mediator_t *eth; + const char *name; + uint32_t addr; + uint32_t reset_timeout_ms; + uint32_t autonego_timeout_ms; + eth_link_t link_status; +} phy_dm9051_t; + +static esp_err_t dm9051_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) +{ + PHY_CHECK(eth, "can't set mediator for dm9051 to null", err); + phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); + dm9051->eth = eth; + return ESP_OK; +err: + return ESP_ERR_INVALID_ARG; +} + +static esp_err_t dm9051_get_link(esp_eth_phy_t *phy) +{ + phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); + esp_eth_mediator_t *eth = dm9051->eth; + bmsr_reg_t bmsr; + + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); + eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + if (dm9051->link_status != link) { + if (link == ETH_LINK_UP) { + phy->negotiate(phy); + } else { + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); + dm9051->link_status = link; + } + } + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t dm9051_reset(esp_eth_phy_t *phy) +{ + phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); + esp_eth_mediator_t *eth = dm9051->eth; + dscr_reg_t dscr; + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK, "read DSCR failed", err); + dscr.smrst = 1; + PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, dscr.val) == ESP_OK, "write DSCR failed", err); + bmcr_reg_t bmcr = {.reset = 1}; + PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + /* Wait for reset complete */ + uint32_t to = 0; + for (to = 0; to < dm9051->reset_timeout_ms / 10; to++) { + vTaskDelay(pdMS_TO_TICKS(10)); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK, "read DSCR failed", err); + if (!bmcr.reset && !dscr.smrst) { + break; + } + } + PHY_CHECK(to < dm9051->reset_timeout_ms / 10, "PHY reset timeout", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t dm9051_negotiate(esp_eth_phy_t *phy) +{ + phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); + esp_eth_mediator_t *eth = dm9051->eth; + /* Start auto negotiation */ + bmcr_reg_t bmcr = { + .speed_select = 1, /* 100Mbps */ + .duplex_mode = 1, /* Full Duplex */ + .en_auto_nego = 1, /* Auto Negotiation */ + .restart_auto_nego = 1 /* Restart Auto Negotiation */ + }; + PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + /* Wait for auto negotiation complete */ + bmsr_reg_t bmsr; + dscsr_reg_t dscsr; + uint32_t to = 0; + for (to = 0; to < dm9051->autonego_timeout_ms / 10; to++) { + vTaskDelay(pdMS_TO_TICKS(10)); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)) == ESP_OK, "read DSCSR failed", err); + if (bmsr.auto_nego_complete && dscsr.anmb & 0x08) { + break; + } + } + if (to >= dm9051->autonego_timeout_ms / 10) { + ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout"); + } + /* Updata information about link, speed, duplex */ + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)) == ESP_OK, "read DSCSR failed", err); + eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + eth_speed_t speed = ETH_SPEED_10M; + eth_duplex_t duplex = ETH_DUPLEX_HALF; + if (dscsr.fdx100 || dscsr.hdx100) { + speed = ETH_SPEED_100M; + } else { + speed = ETH_SPEED_10M; + } + if (dscsr.fdx100 || dscsr.fdx10) { + duplex = ETH_DUPLEX_FULL; + } else { + duplex = ETH_DUPLEX_HALF; + } + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err); + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err); + if (dm9051->link_status != link) { + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); + dm9051->link_status = link; + } + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t dm9051_pwrctl(esp_eth_phy_t *phy, bool enable) +{ + phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); + esp_eth_mediator_t *eth = dm9051->eth; + bmcr_reg_t bmcr; + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + if (!enable) { + /* Enable IEEE Power Down Mode */ + bmcr.power_down = 1; + } else { + /* Disable IEEE Power Down Mode */ + bmcr.power_down = 0; + } + PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + if (!enable) { + PHY_CHECK(bmcr.power_down == 1, "power down failed", err); + } else { + PHY_CHECK(bmcr.power_down == 0, "power up failed", err); + } + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t dm9051_set_addr(esp_eth_phy_t *phy, uint32_t addr) +{ + phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); + dm9051->addr = addr; + return ESP_OK; +} + +static esp_err_t dm9051_get_addr(esp_eth_phy_t *phy, uint32_t *addr) +{ + PHY_CHECK(addr, "get phy address failed", err); + phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); + *addr = dm9051->addr; + return ESP_OK; +err: + return ESP_ERR_INVALID_ARG; +} + +static esp_err_t dm9051_del(esp_eth_phy_t *phy) +{ + phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); + free(dm9051); + return ESP_OK; +} + +static esp_err_t dm9051_init(esp_eth_phy_t *phy) +{ + phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); + esp_eth_mediator_t *eth = dm9051->eth; + /* Power on Ethernet PHY */ + PHY_CHECK(dm9051_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err); + /* Reset Ethernet PHY */ + PHY_CHECK(dm9051_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err); + /* Check PHY ID */ + phyidr1_reg_t id1; + phyidr2_reg_t id2; + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err); + PHY_CHECK(id1.oui_msb == 0x0181 && id2.oui_lsb == 0x2E && id2.vendor_model == 0x0A, "wrong PHY chip ID", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t dm9051_deinit(esp_eth_phy_t *phy) +{ + /* Power off Ethernet PHY */ + PHY_CHECK(dm9051_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config) +{ + PHY_CHECK(config, "can't set phy config to null", err); + PHY_CHECK(config->phy_addr == 1, "dm9051's phy address can only set to 1", err); + phy_dm9051_t *dm9051 = calloc(1, sizeof(phy_dm9051_t)); + PHY_CHECK(dm9051, "calloc dm9051 object failed", err); + dm9051->name = "dm9051"; + dm9051->addr = config->phy_addr; + dm9051->reset_timeout_ms = config->reset_timeout_ms; + dm9051->link_status = ETH_LINK_DOWN; + dm9051->autonego_timeout_ms = config->autonego_timeout_ms; + dm9051->parent.reset = dm9051_reset; + dm9051->parent.init = dm9051_init; + dm9051->parent.deinit = dm9051_deinit; + dm9051->parent.set_mediator = dm9051_set_mediator; + dm9051->parent.negotiate = dm9051_negotiate; + dm9051->parent.get_link = dm9051_get_link; + dm9051->parent.pwrctl = dm9051_pwrctl; + dm9051->parent.get_addr = dm9051_get_addr; + dm9051->parent.set_addr = dm9051_set_addr; + dm9051->parent.del = dm9051_del; + + return &(dm9051->parent); +err: + return NULL; +} diff --git a/components/esp_eth/test/test_emac.c b/components/esp_eth/test/test_emac.c index ac2d10a75c..141bf3e1da 100644 --- a/components/esp_eth/test/test_emac.c +++ b/components/esp_eth/test/test_emac.c @@ -8,6 +8,7 @@ #include "test_utils.h" #include "esp_eth.h" #include "esp_log.h" +#include "sdkconfig.h" static const char *TAG = "esp_eth_test"; /** Event handler for Ethernet events */ @@ -89,3 +90,48 @@ TEST_CASE("ethernet tcpip_adapter", "[ethernet][ignore]") TEST_ESP_OK(esp_eth_driver_install(&config, ð_handle)); vTaskDelay(portMAX_DELAY); } + +#if CONFIG_ETH_USE_SPI_ETHERNET +TEST_CASE("dm9051 io test", "[ethernet][ignore]") +{ + spi_device_handle_t spi_handle = NULL; + spi_bus_config_t buscfg = { + .miso_io_num = 25, + .mosi_io_num = 23, + .sclk_io_num = 19, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + }; + TEST_ESP_OK(spi_bus_initialize(HSPI_HOST, &buscfg, 1)); + spi_device_interface_config_t devcfg = { + .command_bits = 1, + .address_bits = 7, + .mode = 0, + .clock_speed_hz = 20 * 1000 * 1000, + .spics_io_num = 22, + .queue_size = 20 + }; + TEST_ESP_OK(spi_bus_add_device(HSPI_HOST, &devcfg, &spi_handle)); + gpio_install_isr_service(0); + tcpip_adapter_init(); + TEST_ESP_OK(esp_event_loop_create_default()); + TEST_ESP_OK(tcpip_adapter_set_default_eth_handlers()); + TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL)); + TEST_ESP_OK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL)); + eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); + mac_config.spi_hdl = spi_handle; + esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&mac_config); + eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); + esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config); + esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); + esp_eth_handle_t eth_handle = NULL; + TEST_ESP_OK(esp_eth_driver_install(&config, ð_handle)); + vTaskDelay(pdMS_TO_TICKS(portMAX_DELAY)); + TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle)); + TEST_ESP_OK(phy->del(phy)); + TEST_ESP_OK(mac->del(mac)); + TEST_ESP_OK(esp_event_loop_delete_default()); + TEST_ESP_OK(spi_bus_remove_device(spi_handle)); + TEST_ESP_OK(spi_bus_free(HSPI_HOST)); +} +#endif diff --git a/components/soc/esp32/emac_hal.c b/components/soc/esp32/emac_hal.c index f7c6fb38ca..4722ee4ecf 100644 --- a/components/soc/esp32/emac_hal.c +++ b/components/soc/esp32/emac_hal.c @@ -163,8 +163,6 @@ void emac_hal_reset_desc_chain(emac_hal_context_t *hal) hal->tx_desc[i].TDES1.TransmitBuffer1Size = CONFIG_ETH_DMA_BUFFER_SIZE; /* Enable Ethernet DMA Tx Descriptor interrupt */ hal->tx_desc[1].TDES0.InterruptOnComplete = 1; - /* Set the DMA Tx descriptors checksum insertion */ - hal->tx_desc[i].TDES0.ChecksumInsertControl = EMAC_DMATXDESC_CHECKSUM_TCPUDPICMPFULL; /* Enable Transmit Timestamp */ hal->tx_desc[i].TDES0.TransmitTimestampEnable = 1; /* point to the buffer */ diff --git a/examples/common_components/protocol_examples_common/Kconfig.projbuild b/examples/common_components/protocol_examples_common/Kconfig.projbuild index 7de1c43591..f5d288e9ae 100644 --- a/examples/common_components/protocol_examples_common/Kconfig.projbuild +++ b/examples/common_components/protocol_examples_common/Kconfig.projbuild @@ -1,5 +1,4 @@ menu "Example Connection Configuration" - choice EXAMPLE_CONNECT_INTERFACE prompt "Connect using" default EXAMPLE_CONNECT_WIFI @@ -15,53 +14,120 @@ menu "Example Connection Configuration" endchoice - config EXAMPLE_WIFI_SSID - depends on EXAMPLE_CONNECT_WIFI - string "WiFi SSID" - default "myssid" - help - SSID (network name) for the example to connect to. - - config EXAMPLE_WIFI_PASSWORD - depends on EXAMPLE_CONNECT_WIFI - string "WiFi Password" - default "mypassword" - help - WiFi password (WPA or WPA2) for the example to use. - Can be left blank if the network has no security set. - - choice EXAMPLE_ETH_PHY_MODEL - depends on EXAMPLE_CONNECT_ETHERNET - prompt "Ethernet PHY Device" - default EXAMPLE_ETH_PHY_IP101 - help - Select the PHY driver to use for the example. - - config EXAMPLE_ETH_PHY_IP101 - bool "IP101" + if EXAMPLE_CONNECT_WIFI + config EXAMPLE_WIFI_SSID + string "WiFi SSID" + default "myssid" help - IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver. - Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it. + SSID (network name) for the example to connect to. - config EXAMPLE_ETH_PHY_RTL8201 - bool "RTL8201/SR8201" + config EXAMPLE_WIFI_PASSWORD + string "WiFi Password" + default "mypassword" help - RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX. - Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it. + WiFi password (WPA or WPA2) for the example to use. + Can be left blank if the network has no security set. + endif - config EXAMPLE_ETH_PHY_LAN8720 - bool "LAN8720" + if EXAMPLE_CONNECT_ETHERNET + choice EXAMPLE_USE_ETHERNET + prompt "Ethernet Type" + default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32 + default EXAMPLE_USE_SPI_ETHERNET if !IDF_TARGET_ESP32 help - LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support. - Goto https://www.microchip.com/LAN8720A for more information about it. + Select which kind of Ethernet will be used in the example. - config EXAMPLE_ETH_PHY_DP83848 - bool "DP83848" - help - DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver. - Goto http://www.ti.com/product/DP83848J for more information about it. + config EXAMPLE_USE_INTERNAL_ETHERNET + depends on IDF_TARGET_ESP32 + select ETH_USE_ESP32_EMAC + bool "Internal EMAC" + help + Select internal Ethernet MAC controller. - endchoice + config EXAMPLE_USE_SPI_ETHERNET + bool "SPI Ethernet Module" + select ETH_USE_SPI_ETHERNET + help + Select external SPI-Ethernet module. + endchoice + + if EXAMPLE_USE_INTERNAL_ETHERNET + choice EXAMPLE_ETH_PHY_MODEL + prompt "Ethernet PHY Device" + default EXAMPLE_ETH_PHY_IP101 + help + Select the Ethernet PHY device to use in the example. + + config EXAMPLE_ETH_PHY_IP101 + bool "IP101" + help + IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver. + Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it. + + config EXAMPLE_ETH_PHY_RTL8201 + bool "RTL8201/SR8201" + help + RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX. + Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it. + + config EXAMPLE_ETH_PHY_LAN8720 + bool "LAN8720" + help + LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support. + Goto https://www.microchip.com/LAN8720A for more information about it. + + config EXAMPLE_ETH_PHY_DP83848 + bool "DP83848" + help + DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver. + Goto http://www.ti.com/product/DP83848J for more information about it. + endchoice + endif + + if EXAMPLE_USE_SPI_ETHERNET + config EXAMPLE_ETH_SPI_HOST + int "SPI Host Number" + range 0 2 + default 1 + help + Set the SPI host used to communicate with DM9051. + + config EXAMPLE_ETH_SCLK_GPIO + int "SPI SCLK GPIO number" + range 0 33 + default 19 + help + Set the GPIO number used by SPI SCLK. + + config EXAMPLE_ETH_MOSI_GPIO + int "SPI MOSI GPIO number" + range 0 33 + default 23 + help + Set the GPIO number used by SPI MOSI. + + config EXAMPLE_ETH_MISO_GPIO + int "SPI MISO GPIO number" + range 0 33 + default 25 + help + Set the GPIO number used by SPI MISO. + + config EXAMPLE_ETH_CS_GPIO + int "SPI CS GPIO number" + range 0 33 + default 22 + help + Set the GPIO number used by SPI CS. + + config EXAMPLE_ETH_SPI_CLOCK_MHZ + int "SPI clock speed (MHz)" + range 20 80 + default 20 + help + Set the clock speed (MHz) of SPI interface. + endif + endif config EXAMPLE_CONNECT_IPV6 bool "Obtain IPv6 link-local address" @@ -69,5 +135,4 @@ menu "Example Connection Configuration" help By default, examples will wait until IPv4 and IPv6 addresses are obtained. Disable this option if the network does not support IPv6. - endmenu diff --git a/examples/common_components/protocol_examples_common/connect.c b/examples/common_components/protocol_examples_common/connect.c index f12d40dda5..68895905a4 100644 --- a/examples/common_components/protocol_examples_common/connect.c +++ b/examples/common_components/protocol_examples_common/connect.c @@ -187,8 +187,9 @@ static void start() ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_GOT_IP6, &on_got_ipv6, NULL)); #endif eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); - s_mac = esp_eth_mac_new_esp32(&mac_config); eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); +#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET + s_mac = esp_eth_mac_new_esp32(&mac_config); #if CONFIG_EXAMPLE_ETH_PHY_IP101 s_phy = esp_eth_phy_new_ip101(&phy_config); #elif CONFIG_EXAMPLE_ETH_PHY_RTL8201 @@ -197,9 +198,33 @@ static void start() s_phy = esp_eth_phy_new_lan8720(&phy_config); #elif CONFIG_EXAMPLE_ETH_PHY_DP83848 s_phy = esp_eth_phy_new_dp83848(&phy_config); +#endif +#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET + gpio_install_isr_service(0); + spi_device_handle_t spi_handle = NULL; + spi_bus_config_t buscfg = { + .miso_io_num = CONFIG_EXAMPLE_ETH_MISO_GPIO, + .mosi_io_num = CONFIG_EXAMPLE_ETH_MOSI_GPIO, + .sclk_io_num = CONFIG_EXAMPLE_ETH_SCLK_GPIO, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + }; + ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1)); + spi_device_interface_config_t devcfg = { + .command_bits = 1, + .address_bits = 7, + .mode = 0, + .clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000, + .spics_io_num = CONFIG_EXAMPLE_ETH_CS_GPIO, + .queue_size = 20 + }; + ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle)); + /* dm9051 ethernet driver is based on spi driver, so need to specify the spi handle */ + mac_config.spi_hdl = spi_handle; + s_mac = esp_eth_mac_new_dm9051(&mac_config); + s_phy = esp_eth_phy_new_dm9051(&phy_config); #endif esp_eth_config_t config = ETH_DEFAULT_CONFIG(s_mac, s_phy); - ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle)); s_connection_name = "Ethernet"; } diff --git a/examples/ethernet/basic/README.md b/examples/ethernet/basic/README.md index fead5dd44a..57f4b472cd 100644 --- a/examples/ethernet/basic/README.md +++ b/examples/ethernet/basic/README.md @@ -15,35 +15,47 @@ If you have a new Ethernet application to go (for example, connect to IoT cloud ### Hardware Required -To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves. +To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports up to four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves. + +`esp_eth` component not only supports ESP32 internal Ethernet MAC controller, but also can drive third-party Ethernet module which integrates MAC and PHY and provides SPI interface. This example also take the **DM9051** as an example, illustrating how to install the Ethernet driver with only a little different configuration. ### Project configuration in menuconfig Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you' are using CMake based build system. 1. In the `Example Configuration` menu: + * Choose the kind of Ethernet this example will run on under `Ethernet Type`. + * If `Internal EMAC` is selected: + * Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board. -* Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board. + * If `SPI Ethernet Module` is selected: + * Set SPI specific configuration, including GPIO and clock speed. 2. In the `Component config > Ethernet` menu: + * If `Internal EMAC` is selected: + * Enable `Use ESP32 internal EMAC controller`, and then go into this menu. + * In the `PHY interface`, it's highly recommended that you choose `Reduced Media Independent Interface (RMII)` which will cost fewer pins. + * In the `RMII clock mode`, you can choose the source of RMII clock (50MHz): `Input RMII clock from external` or `Output RMII clock from internal`. + * Once `Output RMII clock from internal` is enabled, you also have to set the number of the GPIO used for outputting the RMII clock under `RMII clock GPIO number`. In this case, you can set the GPIO number to 16 or 17. + * Once `Output RMII clock from GPIO0 (Experimental!)` is enabled, then you have no choice but GPIO0 to output the RMII clock. + * Set SMI MDC/MDIO GPIO number according to board schematic, by default these two GPIOs are set as below: -* Enable `Use ESP32 internal EMAC controller`, and then go into this menu. -* In the `PHY interface`, it's highly recommended that you choose `Reduced Media Independent Interface (RMII)` which will cost fewer pins. -* In the `RMII clock mode`, you can choose the source of RMII clock (50MHz): `Input RMII clock from external` or `Output RMII clock from internal`. -* Once `Output RMII clock from internal` is enabled, you also have to set the number of the GPIO used for outputting the RMII clock under `RMII clock GPIO number`. In this case, you can set the GPIO number to 16 or 17. -* Once `Output RMII clock from GPIO0 (Experimental!)` is enabled, then you have no choice but GPIO0 to output the RMII clock. -* Set SMI MDC/MDIO GPIO number according to board schematic, by default these two GPIOs are set as below: + | Default Example GPIO | RMII Signal | Notes | + | -------------------- | ----------- | ------------- | + | GPIO23 | MDC | Output to PHY | + | GPIO18 | MDIO | Bidirectional | - | Default Example GPIO | RMII Signal | Notes | - | -------------------- | ----------- | ------------- | - | GPIO23 | MDC | Output to PHY | - | GPIO18 | MDIO | Bidirectional | + * If you have connect a GPIO to the PHY chip's RST pin, then you need to enable `Use Reset Pin of PHY Chip` and set the GPIO number under `PHY RST GPIO number`. + + * If `SPI Ethernet Module` is selected: + * Set the GPIO number used by interrupt pin under `DM9051 Interrupt GPIO number`. -* If you have connect a GPIO to the PHY chip's RST pin, then you need to enable `Use Reset Pin of PHY Chip` and set the GPIO number under `PHY RST GPIO number`. ### Extra configuration in the code (Optional) * By default Ethernet driver will assume the PHY address to `1`, but you can alway reconfigure this value after `eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();`. The actual PHY address should depend on the hardware you use, so make sure to consult the schematic and datasheet. + +**Note:** DM9051 has a fixed PHY address `1`, which cannot be modified. ### Build and Flash @@ -56,20 +68,20 @@ See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/l ## Example Output ```bash -I (336) cpu_start: Starting scheduler on PRO CPU. -I (0) cpu_start: Starting scheduler on APP CPU. -I (382) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE -I (392) eth_example: Ethernet Started -I (3922) eth_example: Ethernet Link Up -I (5862) tcpip_adapter: eth ip: 192.168.2.151, mask: 255.255.255.0, gw: 192.168.2.2 -I (5862) eth_example: Ethernet Got IP Address -I (5862) eth_example: ~~~~~~~~~~~ -I (5862) eth_example: ETHIP:192.168.2.151 -I (5872) eth_example: ETHMASK:255.255.255.0 -I (5872) eth_example: ETHGW:192.168.2.2 -I (5882) eth_example: ~~~~~~~~~~~ +I (394) eth_example: Ethernet Started +I (3934) eth_example: Ethernet Link Up +I (3934) eth_example: Ethernet HW Addr 30:ae:a4:c6:87:5b +I (5864) tcpip_adapter: eth ip: 192.168.2.151, mask: 255.255.255.0, gw: 192.168.2.2 +I (5864) eth_example: Ethernet Got IP Address +I (5864) eth_example: ~~~~~~~~~~~ +I (5864) eth_example: ETHIP:192.168.2.151 +I (5874) eth_example: ETHMASK:255.255.255.0 +I (5874) eth_example: ETHGW:192.168.2.2 +I (5884) eth_example: ~~~~~~~~~~~ ``` +Now you can ping your ESP32 in the terminal by entering `ping 192.168.2.151` (it depends on the actual IP address you get). + ## Troubleshooting * RMII Clock diff --git a/examples/ethernet/basic/main/Kconfig.projbuild b/examples/ethernet/basic/main/Kconfig.projbuild index 1040116540..9c6cae1f73 100644 --- a/examples/ethernet/basic/main/Kconfig.projbuild +++ b/examples/ethernet/basic/main/Kconfig.projbuild @@ -1,34 +1,99 @@ menu "Example Configuration" - - choice EXAMPLE_ETH_PHY_MODEL - prompt "Ethernet PHY Device" - default EXAMPLE_ETH_PHY_IP101 + choice EXAMPLE_USE_ETHERNET + prompt "Ethernet Type" + default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32 + default EXAMPLE_USE_SPI_ETHERNET if !IDF_TARGET_ESP32 help - Select the Ethernet PHY device to use in the example. + Select which kind of Ethernet will be used in the example. - config EXAMPLE_ETH_PHY_IP101 - bool "IP101" + config EXAMPLE_USE_INTERNAL_ETHERNET + depends on IDF_TARGET_ESP32 + select ETH_USE_ESP32_EMAC + bool "Internal EMAC" help - IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver. - Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it. + Select internal Ethernet MAC controller. - config EXAMPLE_ETH_PHY_RTL8201 - bool "RTL8201/SR8201" + config EXAMPLE_USE_SPI_ETHERNET + bool "SPI Ethernet Module" + select ETH_USE_SPI_ETHERNET help - RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX. - Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it. - - config EXAMPLE_ETH_PHY_LAN8720 - bool "LAN8720" - help - LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support. - Goto https://www.microchip.com/LAN8720A for more information about it. - - config EXAMPLE_ETH_PHY_DP83848 - bool "DP83848" - help - DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver. - Goto http://www.ti.com/product/DP83848J for more information about it. + Select external SPI-Ethernet module. endchoice + if EXAMPLE_USE_INTERNAL_ETHERNET + choice EXAMPLE_ETH_PHY_MODEL + prompt "Ethernet PHY Device" + default EXAMPLE_ETH_PHY_IP101 + help + Select the Ethernet PHY device to use in the example. + + config EXAMPLE_ETH_PHY_IP101 + bool "IP101" + help + IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver. + Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it. + + config EXAMPLE_ETH_PHY_RTL8201 + bool "RTL8201/SR8201" + help + RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX. + Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it. + + config EXAMPLE_ETH_PHY_LAN8720 + bool "LAN8720" + help + LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support. + Goto https://www.microchip.com/LAN8720A for more information about it. + + config EXAMPLE_ETH_PHY_DP83848 + bool "DP83848" + help + DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver. + Goto http://www.ti.com/product/DP83848J for more information about it. + endchoice + endif + + if EXAMPLE_USE_SPI_ETHERNET + config EXAMPLE_ETH_SPI_HOST + int "SPI Host Number" + range 0 2 + default 1 + help + Set the SPI host used to communicate with DM9051. + + config EXAMPLE_ETH_SCLK_GPIO + int "SPI SCLK GPIO number" + range 0 33 + default 19 + help + Set the GPIO number used by SPI SCLK. + + config EXAMPLE_ETH_MOSI_GPIO + int "SPI MOSI GPIO number" + range 0 33 + default 23 + help + Set the GPIO number used by SPI MOSI. + + config EXAMPLE_ETH_MISO_GPIO + int "SPI MISO GPIO number" + range 0 33 + default 25 + help + Set the GPIO number used by SPI MISO. + + config EXAMPLE_ETH_CS_GPIO + int "SPI CS GPIO number" + range 0 33 + default 22 + help + Set the GPIO number used by SPI CS. + + config EXAMPLE_ETH_SPI_CLOCK_MHZ + int "SPI clock speed (MHz)" + range 20 80 + default 20 + help + Set the clock speed (MHz) of SPI interface. + endif endmenu diff --git a/examples/ethernet/basic/main/ethernet_example_main.c b/examples/ethernet/basic/main/ethernet_example_main.c index 4c52b33817..ed794a32b3 100644 --- a/examples/ethernet/basic/main/ethernet_example_main.c +++ b/examples/ethernet/basic/main/ethernet_example_main.c @@ -17,15 +17,21 @@ #include "sdkconfig.h" static const char *TAG = "eth_example"; -static esp_eth_handle_t s_eth_handle = NULL; /** Event handler for Ethernet events */ static void eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { + uint8_t mac_addr[6] = {0}; + /* we can get the ethernet driver handle from event data */ + esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data; + switch (event_id) { case ETHERNET_EVENT_CONNECTED: + esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr); ESP_LOGI(TAG, "Ethernet Link Up"); + ESP_LOGI(TAG, "Ethernet HW Addr %02x:%02x:%02x:%02x:%02x:%02x", + mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); break; case ETHERNET_EVENT_DISCONNECTED: ESP_LOGI(TAG, "Ethernet Link Down"); @@ -66,8 +72,9 @@ void app_main() ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL)); eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); - esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); +#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET + esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); #if CONFIG_EXAMPLE_ETH_PHY_IP101 esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config); #elif CONFIG_EXAMPLE_ETH_PHY_RTL8201 @@ -76,7 +83,33 @@ void app_main() esp_eth_phy_t *phy = esp_eth_phy_new_lan8720(&phy_config); #elif CONFIG_EXAMPLE_ETH_PHY_DP83848 esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config); +#endif +#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET + gpio_install_isr_service(0); + spi_device_handle_t spi_handle = NULL; + spi_bus_config_t buscfg = { + .miso_io_num = CONFIG_EXAMPLE_ETH_MISO_GPIO, + .mosi_io_num = CONFIG_EXAMPLE_ETH_MOSI_GPIO, + .sclk_io_num = CONFIG_EXAMPLE_ETH_SCLK_GPIO, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + }; + ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1)); + spi_device_interface_config_t devcfg = { + .command_bits = 1, + .address_bits = 7, + .mode = 0, + .clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000, + .spics_io_num = CONFIG_EXAMPLE_ETH_CS_GPIO, + .queue_size = 20 + }; + ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle)); + /* dm9051 ethernet driver is based on spi driver, so need to specify the spi handle */ + mac_config.spi_hdl = spi_handle; + esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&mac_config); + esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config); #endif esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); - ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle)); + esp_eth_handle_t eth_handle = NULL; + ESP_ERROR_CHECK(esp_eth_driver_install(&config, ð_handle)); } diff --git a/examples/ethernet/eth2ap/README.md b/examples/ethernet/eth2ap/README.md index 4d1c8e0f2d..26d81db121 100644 --- a/examples/ethernet/eth2ap/README.md +++ b/examples/ethernet/eth2ap/README.md @@ -12,38 +12,48 @@ The similarities on MAC layer between Ethernet and Wi-Fi make it easy to forward ### Hardware Required -To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves. +To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports up to four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves. + +`esp_eth` component not only supports ESP32 internal Ethernet MAC controller, but also can drive third-party Ethernet module which integrates MAC and PHY and provides SPI interface. This example also take the **DM9051** as an example, illustrating how to install the Ethernet driver with only a little different configuration. ### Project configuration in menuconfig Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you' are using CMake based build system. 1. In the `Example Configuration` menu: + * Set the SSID and password for Wi-Fi ap interface under `Wi-Fi SSID` and `Wi-Fi Password`. + * Set the maximum connection number under `Maximum STA connections`. + * Choose the kind of Ethernet this example will run on under `Ethernet Type`. + * If `Internal EMAC` is selected: + * Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board. -* Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board. -* Set the SSID and password for Wi-Fi ap interface under `Wi-Fi SSID` and `Wi-Fi Password`. -* Set the maximum connection number under `Maximum STA connections`. + * If `SPI Ethernet Module` is selected: + * Set SPI specific configuration, including GPIO and clock speed. 2. In the `Component config > Ethernet` menu: + * If `Internal EMAC` is selected: + * Enable `Use ESP32 internal EMAC controller`, and then go into this menu. + * In the `PHY interface`, it's highly recommended that you choose `Reduced Media Independent Interface (RMII)` which will cost fewer pins. + * In the `RMII clock mode`, you can choose the source of RMII clock (50MHz): `Input RMII clock from external` or `Output RMII clock from internal`. + * Once `Output RMII clock from internal` is enabled, you also have to set the number of the GPIO used for outputting the RMII clock under `RMII clock GPIO number`. In this case, you can set the GPIO number to 16 or 17. + * Once `Output RMII clock from GPIO0 (Experimental!)` is enabled, then you have no choice but GPIO0 to output the RMII clock. + * Set SMI MDC/MDIO GPIO number according to board schematic, by default these two GPIOs are set as below: -* Enable `Use ESP32 internal EMAC controller`, and then go into this menu. -* In the `PHY interface`, it's highly recommended that you choose `Reduced Media Independent Interface (RMII)` which will cost fewer pins. -* In the `RMII clock mode`, you can choose the source of RMII clock (50MHz): `Input RMII clock from external` or `Output RMII clock from internal`. -* Once `Output RMII clock from internal` is enabled, you also have to set the number of the GPIO used for outputting the RMII clock under `RMII clock GPIO number`. In this case, you can set the GPIO number to 16 or 17. -* Once `Output RMII clock from GPIO0 (Experimental!)` is enabled, then you have no choice but GPIO0 to output the RMII clock. -* Set SMI MDC/MDIO GPIO number according to board schematic, by default these two GPIOs are set as below: + | Default Example GPIO | RMII Signal | Notes | + | -------------------- | ----------- | ------------- | + | GPIO23 | MDC | Output to PHY | + | GPIO18 | MDIO | Bidirectional | - | Default Example GPIO | RMII Signal | Notes | - | -------------------- | ----------- | ------------- | - | GPIO23 | MDC | Output to PHY | - | GPIO18 | MDIO | Bidirectional | + * If you have connect a GPIO to the PHY chip's RST pin, then you need to enable `Use Reset Pin of PHY Chip` and set the GPIO number under `PHY RST GPIO number`. -* If you have connect a GPIO to the PHY chip's RST pin, then you need to enable `Use Reset Pin of PHY Chip` and set the GPIO number under `PHY RST GPIO number`. + * If `SPI Ethernet Module` is selected: + * Set the GPIO number used by interrupt pin under `DM9051 Interrupt GPIO number`. ### Extra configuration in the code (Optional) * By default Ethernet driver will assume the PHY address to `1`, but you can alway reconfigure this value after `eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();`. The actual PHY address should depend on the hardware you use, so make sure to consult the schematic and datasheet.peripheral (e.g. I²S), you'd better choose the external clock. +**Note:** DM9051 has a fixed PHY address `1`, which cannot be modified. ### Build and Flash diff --git a/examples/ethernet/eth2ap/main/Kconfig.projbuild b/examples/ethernet/eth2ap/main/Kconfig.projbuild index 7c6b87810a..40b54b9ad3 100644 --- a/examples/ethernet/eth2ap/main/Kconfig.projbuild +++ b/examples/ethernet/eth2ap/main/Kconfig.projbuild @@ -1,36 +1,102 @@ menu "Example Configuration" - - choice EXAMPLE_ETH_PHY_MODEL - prompt "Ethernet PHY Device" - default EXAMPLE_ETH_PHY_IP101 + choice EXAMPLE_USE_ETHERNET + prompt "Ethernet Type" + default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32 + default EXAMPLE_USE_SPI_ETHERNET if !IDF_TARGET_ESP32 help - Select the Ethernet PHY device to use in the example. + Select which kind of Ethernet will be used in the example. - config EXAMPLE_ETH_PHY_IP101 - bool "IP101" + config EXAMPLE_USE_INTERNAL_ETHERNET + depends on IDF_TARGET_ESP32 + select ETH_USE_ESP32_EMAC + bool "Internal EMAC" help - IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver. - Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it. + Select internal Ethernet MAC controller. - config EXAMPLE_ETH_PHY_RTL8201 - bool "RTL8201/SR8201" + config EXAMPLE_USE_SPI_ETHERNET + bool "SPI Ethernet Module" + select ETH_USE_SPI_ETHERNET help - RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX. - Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it. - - config EXAMPLE_ETH_PHY_LAN8720 - bool "LAN8720" - help - LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support. - Goto https://www.microchip.com/LAN8720A for more information about it. - - config EXAMPLE_ETH_PHY_DP83848 - bool "DP83848" - help - DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver. - Goto http://www.ti.com/product/DP83848J for more information about it. + Select external SPI-Ethernet module. endchoice + if EXAMPLE_USE_INTERNAL_ETHERNET + choice EXAMPLE_ETH_PHY_MODEL + prompt "Ethernet PHY Device" + default EXAMPLE_ETH_PHY_IP101 + help + Select the Ethernet PHY device to use in the example. + + config EXAMPLE_ETH_PHY_IP101 + bool "IP101" + help + IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver. + Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it. + + config EXAMPLE_ETH_PHY_RTL8201 + bool "RTL8201/SR8201" + help + RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX. + Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it. + + config EXAMPLE_ETH_PHY_LAN8720 + bool "LAN8720" + help + LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support. + Goto https://www.microchip.com/LAN8720A for more information about it. + + config EXAMPLE_ETH_PHY_DP83848 + bool "DP83848" + help + DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver. + Goto http://www.ti.com/product/DP83848J for more information about it. + endchoice + endif + + if EXAMPLE_USE_SPI_ETHERNET + config EXAMPLE_ETH_SPI_HOST + int "SPI Host Number" + range 0 2 + default 1 + help + Set the SPI host used to communicate with DM9051. + + config EXAMPLE_ETH_SCLK_GPIO + int "SPI SCLK GPIO number" + range 0 33 + default 19 + help + Set the GPIO number used by SPI SCLK. + + config EXAMPLE_ETH_MOSI_GPIO + int "SPI MOSI GPIO number" + range 0 33 + default 23 + help + Set the GPIO number used by SPI MOSI. + + config EXAMPLE_ETH_MISO_GPIO + int "SPI MISO GPIO number" + range 0 33 + default 25 + help + Set the GPIO number used by SPI MISO. + + config EXAMPLE_ETH_CS_GPIO + int "SPI CS GPIO number" + range 0 33 + default 22 + help + Set the GPIO number used by SPI CS. + + config EXAMPLE_ETH_SPI_CLOCK_MHZ + int "SPI clock speed (MHz)" + range 20 80 + default 20 + help + Set the clock speed (MHz) of SPI interface. + endif + config EXAMPLE_WIFI_SSID string "Wi-Fi SSID" default "eth2ap" diff --git a/examples/ethernet/eth2ap/main/ethernet_example_main.c b/examples/ethernet/eth2ap/main/ethernet_example_main.c index a28bd7740d..6ea43dd3b0 100644 --- a/examples/ethernet/eth2ap/main/ethernet_example_main.c +++ b/examples/ethernet/eth2ap/main/ethernet_example_main.c @@ -145,8 +145,9 @@ static void initialize_ethernet(void) { ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler, NULL)); eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); - esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); +#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET + esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); #if CONFIG_EXAMPLE_ETH_PHY_IP101 esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config); #elif CONFIG_EXAMPLE_ETH_PHY_RTL8201 @@ -155,6 +156,31 @@ static void initialize_ethernet(void) esp_eth_phy_t *phy = esp_eth_phy_new_lan8720(&phy_config); #elif CONFIG_EXAMPLE_ETH_PHY_DP83848 esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config); +#endif +#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET + gpio_install_isr_service(0); + spi_device_handle_t spi_handle = NULL; + spi_bus_config_t buscfg = { + .miso_io_num = CONFIG_EXAMPLE_ETH_MISO_GPIO, + .mosi_io_num = CONFIG_EXAMPLE_ETH_MOSI_GPIO, + .sclk_io_num = CONFIG_EXAMPLE_ETH_SCLK_GPIO, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + }; + ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1)); + spi_device_interface_config_t devcfg = { + .command_bits = 1, + .address_bits = 7, + .mode = 0, + .clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000, + .spics_io_num = CONFIG_EXAMPLE_ETH_CS_GPIO, + .queue_size = 20 + }; + ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle)); + /* dm9051 ethernet driver is based on spi driver, so need to specify the spi handle */ + mac_config.spi_hdl = spi_handle; + esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&mac_config); + esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config); #endif esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); config.stack_input = pkt_eth2wifi; diff --git a/examples/ethernet/iperf/README.md b/examples/ethernet/iperf/README.md index 47ed723f8f..c75e90096a 100644 --- a/examples/ethernet/iperf/README.md +++ b/examples/ethernet/iperf/README.md @@ -10,9 +10,13 @@ The cli environment in the example is based on the [console component](https://d ## How to use example -To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves. +### Hardware Required -### Prepare work +To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports up to four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves. + +`esp_eth` component not only supports ESP32 internal Ethernet MAC controller, but also can drive third-party Ethernet module which integrates MAC and PHY and provides SPI interface. This example also take the **DM9051** as an example, illustrating how to install the Ethernet driver with only a little different configuration. + +### Other Preparation 1. Install iperf tool on PC * Debian/Ubuntu: `sudo apt-get install iperf` @@ -24,30 +28,39 @@ To run this example, it's recommended that you have an official ESP32 Ethernet d Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you' are using CMake based build system. 1. In the `Example Configuration` menu: + * Enable storing history commands in flash under `Store command history in flash`. + * Choose the kind of Ethernet this example will run on under `Ethernet Type`. + * If `Internal EMAC` is selected: + * Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board. -* Enable storing history commands in flash under `Store command history in flash`. -* Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board. + * If `SPI Ethernet Module` is selected: + * Set SPI specific configuration, including GPIO and clock speed. 2. In the `Component config > Ethernet` menu: + * If `Internal EMAC` is selected: + * Enable `Use ESP32 internal EMAC controller`, and then go into this menu. + * In the `PHY interface`, it's highly recommended that you choose `Reduced Media Independent Interface (RMII)` which will cost fewer pins. + * In the `RMII clock mode`, you can choose the source of RMII clock (50MHz): `Input RMII clock from external` or `Output RMII clock from internal`. + * Once `Output RMII clock from internal` is enabled, you also have to set the number of the GPIO used for outputting the RMII clock under `RMII clock GPIO number`. In this case, you can set the GPIO number to 16 or 17. + * Once `Output RMII clock from GPIO0 (Experimental!)` is enabled, then you have no choice but GPIO0 to output the RMII clock. + * Set SMI MDC/MDIO GPIO number according to board schematic, by default these two GPIOs are set as below: -* Enable `Use ESP32 internal EMAC controller`, and then go into this menu. -* In the `PHY interface`, it's highly recommended that you choose `Reduced Media Independent Interface (RMII)` which will cost fewer pins. -* In the `RMII clock mode`, you can choose the source of RMII clock (50MHz): `Input RMII clock from external` or `Output RMII clock from internal`. -* Once `Output RMII clock from internal` is enabled, you also have to set the number of the GPIO used for outputting the RMII clock under `RMII clock GPIO number`. In this case, you can set the GPIO number to 16 or 17. -* Once `Output RMII clock from GPIO0 (Experimental!)` is enabled, then you have no choice but GPIO0 to output the RMII clock. -* Set SMI MDC/MDIO GPIO number according to board schematic, by default these two GPIOs are set as below: + | Default Example GPIO | RMII Signal | Notes | + | -------------------- | ----------- | ------------- | + | GPIO23 | MDC | Output to PHY | + | GPIO18 | MDIO | Bidirectional | - | Default Example GPIO | RMII Signal | Notes | - | -------------------- | ----------- | ------------- | - | GPIO23 | MDC | Output to PHY | - | GPIO18 | MDIO | Bidirectional | + * If you have connect a GPIO to the PHY chip's RST pin, then you need to enable `Use Reset Pin of PHY Chip` and set the GPIO number under `PHY RST GPIO number`. -* If you have connect a GPIO to the PHY chip's RST pin, then you need to enable `Use Reset Pin of PHY Chip` and set the GPIO number under `PHY RST GPIO number`. + * If `SPI Ethernet Module` is selected: + * Set the GPIO number used by interrupt pin under `DM9051 Interrupt GPIO number`. ### Extra configuration in the code (Optional) * By default Ethernet driver will assume the PHY address to `1`, but you can alway reconfigure this value after `eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();`. The actual PHY address should depend on the hardware you use, so make sure to consult the schematic and datasheet. +**Note:** DM9051 has a fixed PHY address `1`, which cannot be modified. + ### Build and Flash Enter `make -j4 flash monitor` if you are using GNU Make based build system or enter `idf.py build flash monitor` if you' are using CMake based build system. @@ -73,15 +86,15 @@ UDP buffer size: 208 KByte (default) ------------------------------------------------------------ [ 3] local 192.168.2.160 port 5001 connected with 192.168.2.156 port 49154 [ ID] Interval Transfer Bandwidth Jitter Lost/Total Datagrams -[ 3] 0.0- 3.0 sec 24.8 MBytes 69.5 Mbits/sec 0.172 ms 1/17721 (0.0056%) -[ 3] 3.0- 6.0 sec 24.8 MBytes 69.5 Mbits/sec 0.169 ms 0/17719 (0%) -[ 3] 6.0- 9.0 sec 24.8 MBytes 69.5 Mbits/sec 0.170 ms 0/17719 (0%) -[ 3] 9.0-12.0 sec 24.8 MBytes 69.5 Mbits/sec 0.170 ms 0/17718 (0%) -[ 3] 12.0-15.0 sec 24.8 MBytes 69.5 Mbits/sec 0.169 ms 0/17717 (0%) -[ 3] 15.0-18.0 sec 24.8 MBytes 69.5 Mbits/sec 0.170 ms 0/17720 (0%) -[ 3] 18.0-21.0 sec 24.8 MBytes 69.5 Mbits/sec 0.170 ms 0/17721 (0%) -[ 3] 21.0-24.0 sec 24.8 MBytes 69.5 Mbits/sec 0.169 ms 0/17720 (0%) -[ 3] 24.0-27.0 sec 24.8 MBytes 69.5 Mbits/sec 0.169 ms 0/17723 (0%) +[ 3] 0.0- 3.0 sec 26.1 MBytes 72.8 Mbits/sec 0.198 ms 1/18585 (0.0054%) +[ 3] 3.0- 6.0 sec 26.3 MBytes 73.7 Mbits/sec 0.192 ms 0/18792 (0%) +[ 3] 6.0- 9.0 sec 26.3 MBytes 73.5 Mbits/sec 0.189 ms 0/18741 (0%) +[ 3] 9.0-12.0 sec 26.2 MBytes 73.3 Mbits/sec 0.191 ms 43/18739 (0.23%) +[ 3] 12.0-15.0 sec 26.3 MBytes 73.5 Mbits/sec 0.194 ms 0/18739 (0%) +[ 3] 15.0-18.0 sec 26.3 MBytes 73.5 Mbits/sec 0.191 ms 0/18741 (0%) +[ 3] 18.0-21.0 sec 26.3 MBytes 73.5 Mbits/sec 0.187 ms 0/18752 (0%) +[ 3] 21.0-24.0 sec 26.3 MBytes 73.4 Mbits/sec 0.192 ms 0/18737 (0%) +[ 3] 24.0-27.0 sec 26.3 MBytes 73.5 Mbits/sec 0.188 ms 0/18739 (0%) ``` #### ESP32 output @@ -89,16 +102,17 @@ UDP buffer size: 208 KByte (default) ```bash mode=udp-client sip=192.168.2.156:5001, dip=192.168.2.160:5001, interval=3, time=30 Interval Bandwidth - 0- 3 sec 69.34 Mbits/sec - 3- 6 sec 69.55 Mbits/sec - 6- 9 sec 69.55 Mbits/sec - 9- 12 sec 69.55 Mbits/sec - 12- 15 sec 69.55 Mbits/sec - 15- 18 sec 69.56 Mbits/sec - 18- 21 sec 69.56 Mbits/sec - 21- 24 sec 69.56 Mbits/sec - 24- 27 sec 69.56 Mbits/sec - 27- 30 sec 69.56 Mbits/sec + 0- 3 sec 72.92 Mbits/sec + 3- 6 sec 73.76 Mbits/sec + 6- 9 sec 73.56 Mbits/sec + 9- 12 sec 73.56 Mbits/sec + 12- 15 sec 73.56 Mbits/sec + 15- 18 sec 73.56 Mbits/sec + 18- 21 sec 73.61 Mbits/sec + 21- 24 sec 73.55 Mbits/sec + 24- 27 sec 73.56 Mbits/sec + 27- 30 sec 73.56 Mbits/sec + 0- 30 sec 73.52 Mbits/sec ``` ### Test downlink bandwidth @@ -119,11 +133,13 @@ UDP buffer size: 208 KByte (default) [ 3] 3.0- 6.0 sec 28.6 MBytes 80.0 Mbits/sec [ 3] 6.0- 9.0 sec 28.6 MBytes 80.0 Mbits/sec [ 3] 9.0-12.0 sec 28.6 MBytes 80.0 Mbits/sec -[ 3] 12.0-15.0 sec 28.6 MBytes 79.9 Mbits/sec -[ 3] 15.0-18.0 sec 28.6 MBytes 80.0 Mbits/sec -[ 3] 18.0-21.0 sec 28.6 MBytes 80.0 Mbits/sec -[ 3] 21.0-24.0 sec 28.6 MBytes 80.0 Mbits/sec +[ 3] 12.0-15.0 sec 28.4 MBytes 79.5 Mbits/sec +[ 3] 15.0-18.0 sec 28.6 MBytes 79.9 Mbits/sec +[ 3] 18.0-21.0 sec 28.6 MBytes 79.9 Mbits/sec +[ 3] 21.0-24.0 sec 28.6 MBytes 79.9 Mbits/sec [ 3] 24.0-27.0 sec 28.6 MBytes 80.0 Mbits/sec +[ 3] 27.0-30.0 sec 28.5 MBytes 79.7 Mbits/sec +[ 3] 0.0-30.0 sec 286 MBytes 79.9 Mbits/sec ``` #### ESP32 output @@ -131,16 +147,17 @@ UDP buffer size: 208 KByte (default) mode=udp-server sip=192.168.2.156:5001, dip=0.0.0.0:5001, interval=3, time=30 Interval Bandwidth I (2534456) iperf: want recv=16384 - 0- 30 sec 72.67 Mbits/sec - 3- 6 sec 74.18 Mbits/sec - 6- 9 sec 73.14 Mbits/sec - 9- 12 sec 73.65 Mbits/sec - 12- 15 sec 72.87 Mbits/sec - 15- 18 sec 73.29 Mbits/sec - 18- 21 sec 74.35 Mbits/sec - 21- 24 sec 72.28 Mbits/sec - 24- 27 sec 73.39 Mbits/sec - 27- 30 sec 73.49 Mbits/sec + 0- 3 sec 79.36 Mbits/sec + 3- 6 sec 79.56 Mbits/sec + 6- 9 sec 79.51 Mbits/sec + 9- 12 sec 79.24 Mbits/sec + 12- 15 sec 77.33 Mbits/sec + 15- 18 sec 79.01 Mbits/sec + 18- 21 sec 78.58 Mbits/sec + 21- 24 sec 78.24 Mbits/sec + 24- 27 sec 79.56 Mbits/sec + 27- 30 sec 77.20 Mbits/sec + 0- 30 sec 78.76 Mbits/sec ``` ## Suggestions of getting higher bandwidth diff --git a/examples/ethernet/iperf/main/Kconfig.projbuild b/examples/ethernet/iperf/main/Kconfig.projbuild index 001b648a57..b84eefa7e7 100644 --- a/examples/ethernet/iperf/main/Kconfig.projbuild +++ b/examples/ethernet/iperf/main/Kconfig.projbuild @@ -1,5 +1,4 @@ menu "Example Configuration" - config EXAMPLE_STORE_HISTORY bool "Store command history in flash" default y @@ -8,35 +7,101 @@ menu "Example Configuration" command history. If this option is enabled, initalizes a FAT filesystem and uses it to store command history. - choice EXAMPLE_ETH_PHY_MODEL - prompt "Ethernet PHY Device" - default EXAMPLE_ETH_PHY_IP101 + choice EXAMPLE_USE_ETHERNET + prompt "Ethernet Type" + default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32 + default EXAMPLE_USE_SPI_ETHERNET if !IDF_TARGET_ESP32 help - Select the Ethernet PHY device to use in the example. + Select which kind of Ethernet will be used in the example. - config EXAMPLE_ETH_PHY_IP101 - bool "IP101" + config EXAMPLE_USE_INTERNAL_ETHERNET + depends on IDF_TARGET_ESP32 + select ETH_USE_ESP32_EMAC + bool "Internal EMAC" help - IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver. - Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it. + Select internal Ethernet MAC controller. - config EXAMPLE_ETH_PHY_RTL8201 - bool "RTL8201/SR8201" + config EXAMPLE_USE_SPI_ETHERNET + bool "SPI Ethernet Module" + select ETH_USE_SPI_ETHERNET help - RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX. - Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it. - - config EXAMPLE_ETH_PHY_LAN8720 - bool "LAN8720" - help - LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support. - Goto https://www.microchip.com/LAN8720A for more information about it. - - config EXAMPLE_ETH_PHY_DP83848 - bool "DP83848" - help - DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver. - Goto http://www.ti.com/product/DP83848J for more information about it. + Select external SPI-Ethernet module. endchoice + if EXAMPLE_USE_INTERNAL_ETHERNET + choice EXAMPLE_ETH_PHY_MODEL + prompt "Ethernet PHY Device" + default EXAMPLE_ETH_PHY_IP101 + help + Select the Ethernet PHY device to use in the example. + + config EXAMPLE_ETH_PHY_IP101 + bool "IP101" + help + IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver. + Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it. + + config EXAMPLE_ETH_PHY_RTL8201 + bool "RTL8201/SR8201" + help + RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX. + Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it. + + config EXAMPLE_ETH_PHY_LAN8720 + bool "LAN8720" + help + LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support. + Goto https://www.microchip.com/LAN8720A for more information about it. + + config EXAMPLE_ETH_PHY_DP83848 + bool "DP83848" + help + DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver. + Goto http://www.ti.com/product/DP83848J for more information about it. + endchoice + endif + + if EXAMPLE_USE_SPI_ETHERNET + config EXAMPLE_ETH_SPI_HOST + int "SPI Host Number" + range 0 2 + default 1 + help + Set the SPI host used to communicate with DM9051. + + config EXAMPLE_ETH_SCLK_GPIO + int "SPI SCLK GPIO number" + range 0 33 + default 19 + help + Set the GPIO number used by SPI SCLK. + + config EXAMPLE_ETH_MOSI_GPIO + int "SPI MOSI GPIO number" + range 0 33 + default 23 + help + Set the GPIO number used by SPI MOSI. + + config EXAMPLE_ETH_MISO_GPIO + int "SPI MISO GPIO number" + range 0 33 + default 25 + help + Set the GPIO number used by SPI MISO. + + config EXAMPLE_ETH_CS_GPIO + int "SPI CS GPIO number" + range 0 33 + default 22 + help + Set the GPIO number used by SPI CS. + + config EXAMPLE_ETH_SPI_CLOCK_MHZ + int "SPI clock speed (MHz)" + range 20 80 + default 20 + help + Set the clock speed (MHz) of SPI interface. + endif endmenu diff --git a/examples/ethernet/iperf/main/cmd_ethernet.c b/examples/ethernet/iperf/main/cmd_ethernet.c index 1692a5dd63..832d049b04 100644 --- a/examples/ethernet/iperf/main/cmd_ethernet.c +++ b/examples/ethernet/iperf/main/cmd_ethernet.c @@ -183,8 +183,9 @@ void register_ethernet() ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &event_handler, NULL)); eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); - esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); +#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET + esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); #if CONFIG_EXAMPLE_ETH_PHY_IP101 esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config); #elif CONFIG_EXAMPLE_ETH_PHY_RTL8201 @@ -193,6 +194,31 @@ void register_ethernet() esp_eth_phy_t *phy = esp_eth_phy_new_lan8720(&phy_config); #elif CONFIG_EXAMPLE_ETH_PHY_DP83848 esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config); +#endif +#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET + gpio_install_isr_service(0); + spi_device_handle_t spi_handle = NULL; + spi_bus_config_t buscfg = { + .miso_io_num = CONFIG_EXAMPLE_ETH_MISO_GPIO, + .mosi_io_num = CONFIG_EXAMPLE_ETH_MOSI_GPIO, + .sclk_io_num = CONFIG_EXAMPLE_ETH_SCLK_GPIO, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + }; + ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1)); + spi_device_interface_config_t devcfg = { + .command_bits = 1, + .address_bits = 7, + .mode = 0, + .clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000, + .spics_io_num = CONFIG_EXAMPLE_ETH_CS_GPIO, + .queue_size = 20 + }; + ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle)); + /* dm9051 ethernet driver is based on spi driver, so need to specify the spi handle */ + mac_config.spi_hdl = spi_handle; + esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&mac_config); + esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config); #endif esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); ESP_ERROR_CHECK(esp_eth_driver_install(&config, ð_handle)); diff --git a/examples/ethernet/iperf/main/ethernet_example_main.c b/examples/ethernet/iperf/main/ethernet_example_main.c index 53e5cfb984..1f0718fd03 100644 --- a/examples/ethernet/iperf/main/ethernet_example_main.c +++ b/examples/ethernet/iperf/main/ethernet_example_main.c @@ -85,7 +85,7 @@ static void initialize_console() /* Initialize the console */ esp_console_config_t console_config = { - .max_cmdline_args = 8, + .max_cmdline_args = 16, .max_cmdline_length = 256, #if CONFIG_LOG_COLORS .hint_color = atoi(LOG_COLOR_CYAN) From 6029ef1b5879c5f641f299279550b25a76627557 Mon Sep 17 00:00:00 2001 From: zhiweijian Date: Thu, 4 Jul 2019 19:44:59 +0800 Subject: [PATCH 245/486] component/bt: fix rxwinsz assert in ble and wifi coex --- components/bt/controller/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib b/components/bt/controller/lib index d915fc9349..cc2fd1177d 160000 --- a/components/bt/controller/lib +++ b/components/bt/controller/lib @@ -1 +1 @@ -Subproject commit d915fc93499fd925ae301306a7539b5f13bf6e65 +Subproject commit cc2fd1177d97f1a4b9e0d819035ddf52ba77079d From 09ee7219322c127aaa102a4809d8f29e9bf67cad Mon Sep 17 00:00:00 2001 From: KonstantinKondrashov Date: Thu, 4 Jul 2019 15:54:13 +0800 Subject: [PATCH 246/486] efuse: Fix mode EFUSE_SECURE_VERSION_EMULATE --- components/efuse/CMakeLists.txt | 2 +- components/esp32/cpu_start.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/components/efuse/CMakeLists.txt b/components/efuse/CMakeLists.txt index 9a05e7cc14..5fe2cde147 100644 --- a/components/efuse/CMakeLists.txt +++ b/components/efuse/CMakeLists.txt @@ -13,7 +13,7 @@ list(APPEND srcs "src/esp_efuse_utility.c") idf_component_register(SRCS "${srcs}" - PRIV_REQUIRES bootloader_support soc + PRIV_REQUIRES bootloader_support soc spi_flash INCLUDE_DIRS "${include_dirs}") set(GEN_EFUSE_TABLE_ARG --max_blk_len ${CONFIG_EFUSE_MAX_BLK_LEN}) diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index b7b35e16f0..4b8c2d5c4b 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -70,6 +70,7 @@ #include "esp_private/pm_impl.h" #include "trax.h" #include "esp_ota_ops.h" +#include "esp_efuse.h" #define STRINGIFY(s) STRINGIFY2(s) #define STRINGIFY2(s) #s From 2972f96982551c84717092e516fbd26f6c8d27dc Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 9 Apr 2019 16:08:05 +0200 Subject: [PATCH 247/486] esp-tls: capturing specific errors to be available in tcp_transport and then in application code --- components/esp-tls/CMakeLists.txt | 1 + components/esp-tls/component.mk | 2 +- components/esp-tls/esp_tls.c | 241 +++++++++++------- components/esp-tls/esp_tls.h | 56 +++- .../esp_tls_error_capture_internal.h | 48 ++++ components/mqtt/esp-mqtt | 2 +- .../tcp_transport/include/esp_transport.h | 21 +- components/tcp_transport/transport.c | 64 +++-- components/tcp_transport/transport_ssl.c | 13 +- examples/protocols/mqtt/ssl/main/app_main.c | 1 + 10 files changed, 329 insertions(+), 120 deletions(-) create mode 100644 components/esp-tls/private_include/esp_tls_error_capture_internal.h diff --git a/components/esp-tls/CMakeLists.txt b/components/esp-tls/CMakeLists.txt index e08418e5a1..f6cc17c801 100644 --- a/components/esp-tls/CMakeLists.txt +++ b/components/esp-tls/CMakeLists.txt @@ -1,4 +1,5 @@ idf_component_register(SRCS "esp_tls.c" INCLUDE_DIRS "." + PRIVATE_INCLUDE_DIRS "private_include" REQUIRES mbedtls PRIV_REQUIRES lwip nghttp) diff --git a/components/esp-tls/component.mk b/components/esp-tls/component.mk index 7267d5f37f..06991cd1c7 100644 --- a/components/esp-tls/component.mk +++ b/components/esp-tls/component.mk @@ -1,3 +1,3 @@ COMPONENT_SRCDIRS := . -COMPONENT_ADD_INCLUDEDIRS := . +COMPONENT_ADD_INCLUDEDIRS := . private_include diff --git a/components/esp-tls/esp_tls.c b/components/esp-tls/esp_tls.c index c857435ed3..7adc02dc20 100644 --- a/components/esp-tls/esp_tls.c +++ b/components/esp-tls/esp_tls.c @@ -22,6 +22,7 @@ #include #include "esp_tls.h" +#include "esp_tls_error_capture_internal.h" #include static const char *TAG = "esp-tls"; @@ -45,7 +46,7 @@ typedef struct esp_tls_pki_t { unsigned int privkey_password_len; } esp_tls_pki_t; -static struct addrinfo *resolve_host_name(const char *host, size_t hostlen) +static esp_err_t resolve_host_name(const char *host, size_t hostlen, struct addrinfo **address_info) { struct addrinfo hints; memset(&hints, 0, sizeof(hints)); @@ -54,18 +55,17 @@ static struct addrinfo *resolve_host_name(const char *host, size_t hostlen) char *use_host = strndup(host, hostlen); if (!use_host) { - return NULL; + return ESP_ERR_NO_MEM; } ESP_LOGD(TAG, "host:%s: strlen %lu", use_host, (unsigned long)hostlen); - struct addrinfo *res; - if (getaddrinfo(use_host, NULL, &hints, &res)) { + if (getaddrinfo(use_host, NULL, &hints, address_info)) { ESP_LOGE(TAG, "couldn't get hostname for :%s:", use_host); free(use_host); - return NULL; + return ESP_ERR_ESP_TLS_CANNOT_RESOLVE_HOSTNAME; } free(use_host); - return res; + return ESP_OK; } static ssize_t tcp_read(esp_tls_t *tls, char *data, size_t datalen) @@ -81,6 +81,7 @@ static ssize_t tls_read(esp_tls_t *tls, char *data, size_t datalen) return 0; } if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, ret); ESP_LOGE(TAG, "read error :%d:", ret); } } @@ -93,32 +94,35 @@ static void ms_to_timeval(int timeout_ms, struct timeval *tv) tv->tv_usec = (timeout_ms % 1000) * 1000; } -static int esp_tcp_connect(const char *host, int hostlen, int port, int *sockfd, const esp_tls_cfg_t *cfg) +static esp_err_t esp_tcp_connect(const char *host, int hostlen, int port, int *sockfd, const esp_tls_t *tls, const esp_tls_cfg_t *cfg) { - int ret = -1; - struct addrinfo *res = resolve_host_name(host, hostlen); - if (!res) { + esp_err_t ret; + struct addrinfo *addrinfo; + if ((ret = resolve_host_name(host, hostlen, &addrinfo)) != ESP_OK) { return ret; } - int fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + int fd = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol); if (fd < 0) { - ESP_LOGE(TAG, "Failed to create socket (family %d socktype %d protocol %d)", res->ai_family, res->ai_socktype, res->ai_protocol); + ESP_LOGE(TAG, "Failed to create socket (family %d socktype %d protocol %d)", addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_SYSTEM, errno); + ret = ESP_ERR_ESP_TLS_CANNOT_CREATE_SOCKET; goto err_freeaddr; } void *addr_ptr; - if (res->ai_family == AF_INET) { - struct sockaddr_in *p = (struct sockaddr_in *)res->ai_addr; + if (addrinfo->ai_family == AF_INET) { + struct sockaddr_in *p = (struct sockaddr_in *)addrinfo->ai_addr; p->sin_port = htons(port); addr_ptr = p; - } else if (res->ai_family == AF_INET6) { - struct sockaddr_in6 *p = (struct sockaddr_in6 *)res->ai_addr; + } else if (addrinfo->ai_family == AF_INET6) { + struct sockaddr_in6 *p = (struct sockaddr_in6 *)addrinfo->ai_addr; p->sin6_port = htons(port); p->sin6_family = AF_INET6; addr_ptr = p; } else { - ESP_LOGE(TAG, "Unsupported protocol family %d", res->ai_family); + ESP_LOGE(TAG, "Unsupported protocol family %d", addrinfo->ai_family); + ret = ESP_ERR_ESP_TLS_UNSUPPORTED_PROTOCOL_FAMILY; goto err_freesocket; } @@ -134,21 +138,23 @@ static int esp_tcp_connect(const char *host, int hostlen, int port, int *sockfd, } } - ret = connect(fd, addr_ptr, res->ai_addrlen); + ret = connect(fd, addr_ptr, addrinfo->ai_addrlen); if (ret < 0 && !(errno == EINPROGRESS && cfg && cfg->non_block)) { - ESP_LOGE(TAG, "Failed to connect to host (errno %d)", errno); + ESP_LOGE(TAG, "Failed to connnect to host (errno %d)", errno); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_SYSTEM, errno); + ret = ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST; goto err_freesocket; } *sockfd = fd; - freeaddrinfo(res); - return 0; + freeaddrinfo(addrinfo); + return ESP_OK; err_freesocket: close(fd); err_freeaddr: - freeaddrinfo(res); + freeaddrinfo(addrinfo); return ret; } @@ -186,6 +192,7 @@ esp_err_t esp_tls_set_global_ca_store(const unsigned char *cacert_pem_buf, const return ESP_FAIL; } else if (ret > 0) { ESP_LOGE(TAG, "mbedtls_x509_crt_parse was partly successful. No. of failed certificates: %d", ret); + return ESP_ERR_MBEDTLS_CERT_PARTLY_OK; } return ESP_OK; } @@ -209,6 +216,7 @@ static void verify_certificate(esp_tls_t *tls) char buf[100]; if ((flags = mbedtls_ssl_get_verify_result(&tls->ssl)) != 0) { ESP_LOGI(TAG, "Failed to verify peer certificate!"); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS_CERT_FLAGS, flags); bzero(buf, sizeof(buf)); mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags); ESP_LOGI(TAG, "verification info: %s", buf); @@ -239,20 +247,20 @@ static void mbedtls_cleanup(esp_tls_t *tls) mbedtls_ssl_free(&tls->ssl); } -static int set_global_ca_store(esp_tls_t *tls) +static esp_err_t set_global_ca_store(esp_tls_t *tls) { assert(tls); if (global_cacert == NULL) { ESP_LOGE(TAG, "global_cacert is NULL"); - return -1; + return ESP_ERR_INVALID_STATE; } tls->cacert_ptr = global_cacert; mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED); mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL); - return 0; + return ESP_OK; } -static int set_ca_cert(esp_tls_t *tls, const unsigned char *cacert, size_t cacert_len) +static esp_err_t set_ca_cert(esp_tls_t *tls, const unsigned char *cacert, size_t cacert_len) { assert(tls); tls->cacert_ptr = &tls->cacert; @@ -260,14 +268,15 @@ static int set_ca_cert(esp_tls_t *tls, const unsigned char *cacert, size_t cacer int ret = mbedtls_x509_crt_parse(tls->cacert_ptr, cacert, cacert_len); if (ret < 0) { ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x", -ret); - return ret; + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + return ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED; } mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED); mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL); - return 0; + return ESP_OK; } -static int set_pki_context(esp_tls_t *tls, const esp_tls_pki_t *pki) +static esp_err_t set_pki_context(esp_tls_t *tls, const esp_tls_pki_t *pki) { assert(tls); assert(pki); @@ -284,39 +293,44 @@ static int set_pki_context(esp_tls_t *tls, const esp_tls_pki_t *pki) ret = mbedtls_x509_crt_parse(pki->public_cert, pki->publiccert_pem_buf, pki->publiccert_pem_bytes); if (ret < 0) { ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x", -ret); - return ret; + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + return ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED; } ret = mbedtls_pk_parse_key(pki->pk_key, pki->privkey_pem_buf, pki->privkey_pem_bytes, NULL, 0); if (ret < 0) { ESP_LOGE(TAG, "mbedtls_pk_parse_keyfile returned -0x%x", -ret); - return ret; + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + return ESP_ERR_MBEDTLS_PK_PARSE_KEY_FAILED; } ret = mbedtls_ssl_conf_own_cert(&tls->conf, pki->public_cert, pki->pk_key); if (ret < 0) { ESP_LOGE(TAG, "mbedtls_ssl_conf_own_cert returned -0x%x", -ret); - return ret; + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + return ESP_ERR_MBEDTLS_SSL_CONF_OWN_CERT_FAILED; } } else { return ESP_ERR_INVALID_ARG; } - return 0; + return ESP_OK; } #ifdef CONFIG_ESP_TLS_SERVER -static int set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls) +static esp_err_t set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls) { assert(cfg != NULL); assert(tls != NULL); int ret; + esp_err_t esp_ret; if ((ret = mbedtls_ssl_config_defaults(&tls->conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", ret); - return ret; + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + return ESP_ERR_MBEDTLS_SSL_CONFIG_DEFAULTS_FAILED; } #ifdef CONFIG_MBEDTLS_SSL_ALPN @@ -326,9 +340,9 @@ static int set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls) #endif if (cfg->cacert_pem_buf != NULL) { - ret = set_ca_cert(tls, cfg->cacert_pem_buf, cfg->cacert_pem_bytes); - if (ret != 0) { - return ret; + esp_ret = set_ca_cert(tls, cfg->cacert_pem_buf, cfg->cacert_pem_bytes); + if (esp_ret != ESP_OK) { + return esp_ret; } } else { mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE); @@ -345,20 +359,20 @@ static int set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls) .privkey_password = cfg->serverkey_password, .privkey_password_len = cfg->serverkey_password_len, }; - ret = set_pki_context(tls, &pki); - if (ret != 0) { + esp_ret = set_pki_context(tls, &pki); + if (esp_ret != ESP_OK) { ESP_LOGE(TAG, "Failed to set server pki context"); - return ret; + return esp_ret; } } else { ESP_LOGE(TAG, "Missing server certificate and/or key"); - return -1; + return ESP_ERR_INVALID_STATE; } - return 0; + return ESP_OK; } #endif /* ! CONFIG_ESP_TLS_SERVER */ -static int set_client_config(const char *hostname, size_t hostlen, esp_tls_cfg_t *cfg, esp_tls_t *tls) +static esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls_cfg_t *cfg, esp_tls_t *tls) { assert(cfg != NULL); assert(tls != NULL); @@ -372,13 +386,14 @@ static int set_client_config(const char *hostname, size_t hostlen, esp_tls_cfg_t } if (use_host == NULL) { - return -1; + return ESP_ERR_NO_MEM; } /* Hostname set here should match CN in server certificate */ if ((ret = mbedtls_ssl_set_hostname(&tls->ssl, use_host)) != 0) { ESP_LOGE(TAG, "mbedtls_ssl_set_hostname returned -0x%x", -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); free(use_host); - return ret; + return ESP_ERR_MBEDTLS_SSL_SET_HOSTNAME_FAILED; } free(use_host); } @@ -387,25 +402,29 @@ static int set_client_config(const char *hostname, size_t hostlen, esp_tls_cfg_t MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { - ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", ret); - return ret; + ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned -0x%x", -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + return ESP_ERR_MBEDTLS_SSL_CONFIG_DEFAULTS_FAILED; } #ifdef CONFIG_MBEDTLS_SSL_ALPN if (cfg->alpn_protos) { - mbedtls_ssl_conf_alpn_protocols(&tls->conf, cfg->alpn_protos); + if ((ret =mbedtls_ssl_conf_alpn_protocols(&tls->conf, cfg->alpn_protos) != 0)) { + ESP_LOGE(TAG, "mbedtls_ssl_conf_alpn_protocols returned -0x%x", -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + return ESP_ERR_MBEDTLS_SSL_CONF_ALPN_PROTOCOLS_FAILED; + } } #endif - if (cfg->use_global_ca_store == true) { - ret = set_global_ca_store(tls); - if (ret < 0) { - return ret; + esp_err_t esp_ret = set_global_ca_store(tls); + if (esp_ret != ESP_OK) { + return esp_ret; } } else if (cfg->cacert_pem_buf != NULL) { - ret = set_ca_cert(tls, cfg->cacert_pem_buf, cfg->cacert_pem_bytes); - if (ret < 0) { - return ret; + esp_err_t esp_ret = set_ca_cert(tls, cfg->cacert_pem_buf, cfg->cacert_pem_bytes); + if (esp_ret != ESP_OK) { + return esp_ret; } } else { mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE); @@ -422,23 +441,24 @@ static int set_client_config(const char *hostname, size_t hostlen, esp_tls_cfg_t .privkey_password = cfg->clientkey_password, .privkey_password_len = cfg->clientkey_password_len, }; - ret = set_pki_context(tls, &pki); - if (ret < 0) { + esp_err_t esp_ret = set_pki_context(tls, &pki); + if (esp_ret != ESP_OK) { ESP_LOGE(TAG, "Failed to set server pki context"); - return ret; + return esp_ret; } } else if (cfg->clientcert_pem_buf != NULL || cfg->clientkey_pem_buf != NULL) { ESP_LOGE(TAG, "You have to provide both clientcert_pem_buf and clientkey_pem_buf for mutual authentication"); - return -1; + return ESP_ERR_INVALID_STATE; } - return 0; + return ESP_OK; } -static int create_ssl_handle(const char *hostname, size_t hostlen, const void *cfg, esp_tls_t *tls) +static esp_err_t create_ssl_handle(const char *hostname, size_t hostlen, const void *cfg, esp_tls_t *tls) { assert(cfg != NULL); assert(tls != NULL); int ret; + esp_err_t esp_ret; tls->server_fd.fd = tls->sockfd; mbedtls_ssl_init(&tls->ssl); mbedtls_ctr_drbg_init(&tls->ctr_drbg); @@ -446,15 +466,15 @@ static int create_ssl_handle(const char *hostname, size_t hostlen, const void *c mbedtls_entropy_init(&tls->entropy); if (tls->role == ESP_TLS_CLIENT) { - ret = set_client_config(hostname, hostlen, (esp_tls_cfg_t *)cfg, tls); - if (ret != 0) { + esp_ret = set_client_config(hostname, hostlen, (esp_tls_cfg_t *)cfg, tls); + if (esp_ret != ESP_OK) { ESP_LOGE(TAG, "Failed to set client configurations"); goto exit; } #ifdef CONFIG_ESP_TLS_SERVER } else if (tls->role == ESP_TLS_SERVER) { - ret = set_server_config((esp_tls_cfg_server_t *) cfg, tls); - if (ret != 0) { + esp_ret = set_server_config((esp_tls_cfg_server_t *) cfg, tls); + if (esp_ret != 0) { ESP_LOGE(TAG, "Failed to set server configurations"); goto exit; } @@ -463,7 +483,9 @@ static int create_ssl_handle(const char *hostname, size_t hostlen, const void *c if ((ret = mbedtls_ctr_drbg_seed(&tls->ctr_drbg, mbedtls_entropy_func, &tls->entropy, NULL, 0)) != 0) { - ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned %d", ret); + ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned -0x%x", -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + esp_ret = ESP_ERR_MBEDTLS_CTR_DRBG_SEED_FAILED; goto exit; } @@ -475,14 +497,16 @@ static int create_ssl_handle(const char *hostname, size_t hostlen, const void *c if ((ret = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) { ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x", -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + esp_ret = ESP_ERR_MBEDTLS_SSL_SETUP_FAILED; goto exit; } mbedtls_ssl_set_bio(&tls->ssl, &tls->server_fd, mbedtls_net_send, mbedtls_net_recv, NULL); - return 0; + return ESP_OK; exit: mbedtls_cleanup(tls); - return ret; + return esp_ret; } /** @@ -497,6 +521,7 @@ void esp_tls_conn_delete(esp_tls_t *tls) } else if (tls->sockfd >= 0) { close(tls->sockfd); } + free(tls->error_handle); free(tls); } }; @@ -511,6 +536,8 @@ static ssize_t tls_write(esp_tls_t *tls, const char *data, size_t datalen) ssize_t ret = mbedtls_ssl_write(&tls->ssl, (unsigned char*) data, datalen); if (ret < 0) { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, ESP_ERR_MBEDTLS_SSL_WRITE_FAILED); ESP_LOGE(TAG, "write error :%d:", ret); } } @@ -523,6 +550,9 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c ESP_LOGE(TAG, "empty esp_tls parameter"); return -1; } + esp_err_t esp_ret; + int ret; + /* These states are used to keep a tab on connection progress in case of non-blocking connect, and in case of blocking connect these cases will get executed one after the other */ switch (tls->conn_state) { @@ -532,8 +562,8 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c mbedtls_net_init(&tls->server_fd); tls->is_tls = true; } - int ret = esp_tcp_connect(hostname, hostlen, port, &tls->sockfd, cfg); - if (ret < 0) { + if ((esp_ret = esp_tcp_connect(hostname, hostlen, port, &tls->sockfd, tls, cfg)) != ESP_OK) { + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, esp_ret); return -1; } if (!cfg) { @@ -568,15 +598,18 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c /* pending error check */ if (getsockopt(tls->sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { ESP_LOGD(TAG, "Non blocking connect failed"); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_SYSTEM, errno); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED); tls->conn_state = ESP_TLS_FAIL; return -1; } } } /* By now, the connection has been established */ - ret = create_ssl_handle(hostname, hostlen, cfg, tls); - if (ret != 0) { - ESP_LOGD(TAG, "create_ssl_handshake failed"); + esp_ret = create_ssl_handle(hostname, hostlen, cfg, tls); + if (esp_ret != ESP_OK) { + ESP_LOGE(TAG, "create_ssl_handle failed"); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, esp_ret); tls->conn_state = ESP_TLS_FAIL; return -1; } @@ -593,6 +626,8 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c } else { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { ESP_LOGE(TAG, "mbedtls_ssl_handshake returned -0x%x", -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED); if (cfg->cacert_pem_buf != NULL || cfg->use_global_ca_store == true) { /* This is to check whether handshake failed due to invalid certificate*/ verify_certificate(tls); @@ -618,22 +653,17 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c /** * @brief Create a new TLS/SSL connection */ -esp_tls_t *esp_tls_conn_new(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg) +int esp_tls_conn_new(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg, esp_tls_t *tls) { - esp_tls_t *tls = (esp_tls_t *)calloc(1, sizeof(esp_tls_t)); - if (!tls) { - return NULL; - } /* esp_tls_conn_new() API establishes connection in a blocking manner thus this loop ensures that esp_tls_conn_new() API returns only after connection is established unless there is an error*/ while (1) { int ret = esp_tls_low_level_conn(hostname, hostlen, port, cfg, tls); if (ret == 1) { - return tls; + return ret; } else if (ret == -1) { - esp_tls_conn_delete(tls); ESP_LOGE(TAG, "Failed to open new connection"); - return NULL; + return -1; } } return NULL; @@ -670,17 +700,21 @@ esp_tls_t *esp_tls_conn_http_new(const char *url, const esp_tls_cfg_t *cfg) struct http_parser_url u; http_parser_url_init(&u); http_parser_parse_url(url, strlen(url), 0, &u); - + esp_tls_t *tls = esp_tls_init(); + if (!tls) return NULL; /* Connect to host */ - return esp_tls_conn_new(&url[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len, - get_port(url, &u), cfg); + if (esp_tls_conn_new(&url[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len, + get_port(url, &u), cfg, tls) == 1) { + return tls; + } + return NULL; } -size_t esp_tls_get_bytes_avail(esp_tls_t *tls) +ssize_t esp_tls_get_bytes_avail(esp_tls_t *tls) { if (!tls) { ESP_LOGE(TAG, "empty arg passed to esp_tls_get_bytes_avail()"); - return ESP_FAIL; + return -1; } return mbedtls_ssl_get_bytes_avail(&tls->ssl); } @@ -711,14 +745,16 @@ int esp_tls_server_session_create(esp_tls_cfg_server_t *cfg, int sockfd, esp_tls } tls->role = ESP_TLS_SERVER; tls->sockfd = sockfd; - int ret = create_ssl_handle(NULL, 0, cfg, tls); - if (ret != 0) { - ESP_LOGD(TAG, "create_ssl_handle failed"); + esp_err_t esp_ret = create_ssl_handle(NULL, 0, cfg, tls); + if (esp_ret != ESP_OK) { + ESP_LOGE(TAG, "create_ssl_handle failed"); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, esp_ret); tls->conn_state = ESP_TLS_FAIL; - return ret; + return -1; } tls->read = tls_read; tls->write = tls_write; + int ret; while ((ret = mbedtls_ssl_handshake(&tls->ssl)) != 0) { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { ESP_LOGE(TAG, "mbedtls_ssl_handshake returned %d", ret); @@ -739,3 +775,26 @@ void esp_tls_server_session_delete(esp_tls_t *tls) } }; #endif /* ! CONFIG_ESP_TLS_SERVER */ + +esp_tls_t *esp_tls_init() +{ + esp_tls_t *tls = (esp_tls_t *)calloc(1, sizeof(esp_tls_t)); + if (!tls) { + return NULL; + } + tls->error_handle = calloc(1, sizeof(esp_err_t)); + tls->server_fd.fd = tls->sockfd = -1; + return tls; +} + +esp_err_t esp_tls_get_and_clear_last_error(esp_tls_t* tls) +{ + if (tls && tls->error_handle) { + esp_err_t last_err = tls->error_handle->last_error; + if (last_err != ESP_OK) { + tls->error_handle->last_error = ESP_OK; + return last_err; + } + } + return ESP_OK; +} diff --git a/components/esp-tls/esp_tls.h b/components/esp-tls/esp_tls.h index 8a76bf2198..3e0f50bb6d 100644 --- a/components/esp-tls/esp_tls.h +++ b/components/esp-tls/esp_tls.h @@ -31,6 +31,26 @@ extern "C" { #endif +#define ESP_ERR_ESP_TLS_BASE 0x8000 /*!< Starting number of ESP-TLS error codes */ +#define ESP_ERR_ESP_TLS_CANNOT_RESOLVE_HOSTNAME (ESP_ERR_ESP_TLS_BASE + 0x01) /*!< Error if hostname couldn't be resolved upon tls connection */ +#define ESP_ERR_ESP_TLS_CANNOT_CREATE_SOCKET (ESP_ERR_ESP_TLS_BASE + 0x02) /*!< Failed to create socket */ +#define ESP_ERR_ESP_TLS_UNSUPPORTED_PROTOCOL_FAMILY (ESP_ERR_ESP_TLS_BASE + 0x03) /*!< Unsupported protocol family */ +#define ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST (ESP_ERR_ESP_TLS_BASE + 0x04) /*!< Failed to connnect to host */ +#define ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED (ESP_ERR_ESP_TLS_BASE + 0x05) /*!< failed to set socket option */ +#define ESP_ERR_MBEDTLS_CERT_PARTLY_OK (ESP_ERR_ESP_TLS_BASE + 0x06) /*!< embedtls parse certificates was partly successful */ +#define ESP_ERR_MBEDTLS_CTR_DRBG_SEED_FAILED (ESP_ERR_ESP_TLS_BASE + 0x07) /*!< embedtls api returned failed */ +#define ESP_ERR_MBEDTLS_SSL_SET_HOSTNAME_FAILED (ESP_ERR_ESP_TLS_BASE + 0x08) /*!< embedtls api returned failed */ +#define ESP_ERR_MBEDTLS_SSL_CONFIG_DEFAULTS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x09) /*!< embedtls api returned failed */ +#define ESP_ERR_MBEDTLS_SSL_CONF_ALPN_PROTOCOLS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0A) /*!< embedtls api returned failed */ +#define ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0B) /*!< embedtls api returned failed */ +#define ESP_ERR_MBEDTLS_SSL_CONF_OWN_CERT_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0C) /*!< embedtls api returned failed */ +#define ESP_ERR_MBEDTLS_SSL_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0D) /*!< embedtls api returned failed */ +#define ESP_ERR_MBEDTLS_SSL_WRITE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0E) /*!< embedtls api returned failed */ +#define ESP_ERR_MBEDTLS_PK_PARSE_KEY_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0F) /*!< embedtls api returned failed */ +#define ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x10) /*!< embedtls api returned failed */ + +typedef struct esp_error_private* esp_error_handle_t; + /** * @brief ESP-TLS Connection State */ @@ -186,8 +206,22 @@ typedef struct esp_tls { esp_tls_role_t role; /*!< esp-tls role - ESP_TLS_CLIENT - ESP_TLS_SERVER */ + + esp_error_handle_t error_handle; /*!< handle to internal error descriptor */ + } esp_tls_t; + +/** + * @brief Create TLS connection + * + * This function allocates and initializes esp-tls structure handle. + * + * @return tls Pointer to esp-tls as esp-tls handle if successfully initialized, + * NULL if allocation error + */ +esp_tls_t *esp_tls_init(); + /** * @brief Create a new blocking TLS/SSL connection * @@ -200,9 +234,14 @@ typedef struct esp_tls { * non-TLS connection, keep this NULL. For TLS connection, * a pass pointer to esp_tls_cfg_t. At a minimum, this * structure should be zero-initialized. - * @return pointer to esp_tls_t, or NULL if connection couldn't be opened. + * @param[in] tls Pointer to esp-tls as esp-tls handle. + * + * @return + * - -1 If connection establishment fails. + * - 1 If connection establishment is successful. + * - 0 Reserved for connection state is in progress. */ -esp_tls_t *esp_tls_conn_new(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg); +int esp_tls_conn_new(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg, esp_tls_t *tls); /** * @brief Create a new blocking TLS/SSL connection with a given "HTTP" url @@ -317,7 +356,7 @@ void esp_tls_conn_delete(esp_tls_t *tls); * - bytes available in the application data * record read buffer */ -size_t esp_tls_get_bytes_avail(esp_tls_t *tls); +ssize_t esp_tls_get_bytes_avail(esp_tls_t *tls); /** * @brief Create a global CA store, initially empty. @@ -373,6 +412,17 @@ mbedtls_x509_crt *esp_tls_get_global_ca_store(); */ void esp_tls_free_global_ca_store(); +/** + * @brief Returns last error in esp_tls (if any) and clears it. + * + * @param[in] tls pointer to esp-tls as esp-tls handle. + * + * @return + * - ESP_OK if no error occurred + * - specific error code (based on ESP_ERR_ESP_TLS_BASE) otherwise + */ +esp_err_t esp_tls_get_and_clear_last_error(esp_tls_t* tls); + #ifdef CONFIG_ESP_TLS_SERVER /** * @brief Create TLS/SSL server session diff --git a/components/esp-tls/private_include/esp_tls_error_capture_internal.h b/components/esp-tls/private_include/esp_tls_error_capture_internal.h new file mode 100644 index 0000000000..aabd5587b3 --- /dev/null +++ b/components/esp-tls/private_include/esp_tls_error_capture_internal.h @@ -0,0 +1,48 @@ +// Copyright 2017-2019 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. + +#ifndef __ESP_TLS_ERROR_CAPTURE_INTERNAL_H__ +#define __ESP_TLS_ERROR_CAPTURE_INTERNAL_H__ +/** +* Note: this is an implementation placeholder for error logger. +* This version is internal to esp-tls component and only saves single esp_err of last occurred error +*/ + + +/** +* Definition of different types/sources of error codes reported +* from different components +*/ +typedef enum { + ERR_TYPE_UNKNOWN = 0, + ERR_TYPE_SYSTEM, + ERR_TYPE_MBEDTLS, + ERR_TYPE_MBEDTLS_CERT_FLAGS, + ERR_TYPE_ESP, +} err_type_t; + +/** +* Internal structure for error description +* - contains only the last error of esp_err_t in this implementation +*/ +typedef struct esp_error_private { + esp_err_t last_error; +} esp_error_private_t; + +/** + * Error tracker logging macro, this implementation only saves the ERR_TYPE_ESP error, other types are ignored + */ +#define ESP_INT_EVENT_TRACKER_CAPTURE(h, type, code) do { if (h && type==ERR_TYPE_ESP) { h->last_error = code; } } while (0) + +#endif //__ESP_TLS_ERROR_CAPTURE_INTERNAL_H__ diff --git a/components/mqtt/esp-mqtt b/components/mqtt/esp-mqtt index 11f884623b..65bf2255d7 160000 --- a/components/mqtt/esp-mqtt +++ b/components/mqtt/esp-mqtt @@ -1 +1 @@ -Subproject commit 11f884623bd32cb4269f24f47847f5d046da93f5 +Subproject commit 65bf2255d74c79e3c6abe3e3f791ba8d42efdee3 diff --git a/components/tcp_transport/include/esp_transport.h b/components/tcp_transport/include/esp_transport.h index e163a010cd..bd4d33f67c 100644 --- a/components/tcp_transport/include/esp_transport.h +++ b/components/tcp_transport/include/esp_transport.h @@ -22,7 +22,7 @@ extern "C" { #endif -typedef struct esp_transport_list_t* esp_transport_list_handle_t; +typedef struct esp_transport_internal* esp_transport_list_handle_t; typedef struct esp_transport_item_t* esp_transport_handle_t; typedef int (*connect_func)(esp_transport_handle_t t, const char *host, int port, int timeout_ms); @@ -298,6 +298,25 @@ esp_err_t esp_transport_set_async_connect_func(esp_transport_handle_t t, connect */ esp_err_t esp_transport_set_parent_transport_func(esp_transport_handle_t t, payload_transfer_func _parent_transport); +/** + * @brief Returns last error in esp_tls (if any) and clears it. + * + * @param[in] A transport handle + * + * @return + * - ESP_OK if no error occurred + * - specific error code (based on ESP_ERR_ESP_TLS_BASE) otherwise + */ +esp_err_t get_and_clear_last_error(esp_transport_handle_t t); + +/** + * @brief Sets error to common transport handle + * + * @param[in] A transport handle + * + */ +void esp_transport_set_error(esp_transport_handle_t t, esp_err_t err); + #ifdef __cplusplus } #endif diff --git a/components/tcp_transport/transport.c b/components/tcp_transport/transport.c index 44756e1d4b..3db2a69b6c 100644 --- a/components/tcp_transport/transport.c +++ b/components/tcp_transport/transport.c @@ -41,7 +41,8 @@ struct esp_transport_item_t { poll_func _poll_write; /*!< Poll and write */ trans_func _destroy; /*!< Destroy and free transport */ connect_async_func _connect_async; /*!< non-blocking connect function of this transport */ - payload_transfer_func _parent_transfer; /*!< Function returning underlying transport layer */ + payload_transfer_func _parent_transfer; /*!< Function returning underlying transport layer */ + esp_err_t* error_handle; /*!< Pointer to the last error */ STAILQ_ENTRY(esp_transport_item_t) next; }; @@ -52,6 +53,14 @@ struct esp_transport_item_t { */ STAILQ_HEAD(esp_transport_list_t, esp_transport_item_t); +/** + * Internal transport structure holding list of transports and other data common to all transports + */ +typedef struct esp_transport_internal { + struct esp_transport_list_t list; /*!< List of transports */ + esp_err_t* error_handle; /*!< Pointer to the error tracker if enabled */ +} esp_transport_internal_t; + static esp_transport_handle_t esp_transport_get_default_parent(esp_transport_handle_t t) { /* @@ -62,34 +71,37 @@ static esp_transport_handle_t esp_transport_get_default_parent(esp_transport_han esp_transport_list_handle_t esp_transport_list_init() { - esp_transport_list_handle_t list = calloc(1, sizeof(struct esp_transport_list_t)); - ESP_TRANSPORT_MEM_CHECK(TAG, list, return NULL); - STAILQ_INIT(list); - return list; + esp_transport_list_handle_t transport = calloc(1, sizeof(esp_transport_internal_t)); + ESP_TRANSPORT_MEM_CHECK(TAG, transport, return NULL); + STAILQ_INIT(&transport->list); + transport->error_handle = calloc(1, sizeof(esp_err_t)); + return transport; } -esp_err_t esp_transport_list_add(esp_transport_list_handle_t list, esp_transport_handle_t t, const char *scheme) +esp_err_t esp_transport_list_add(esp_transport_list_handle_t h, esp_transport_handle_t t, const char *scheme) { - if (list == NULL || t == NULL) { + if (h == NULL || t == NULL) { return ESP_ERR_INVALID_ARG; } t->scheme = calloc(1, strlen(scheme) + 1); ESP_TRANSPORT_MEM_CHECK(TAG, t->scheme, return ESP_ERR_NO_MEM); strcpy(t->scheme, scheme); - STAILQ_INSERT_TAIL(list, t, next); + STAILQ_INSERT_TAIL(&h->list, t, next); + // Each transport in a list to share the same error tracker + t->error_handle = h->error_handle; return ESP_OK; } -esp_transport_handle_t esp_transport_list_get_transport(esp_transport_list_handle_t list, const char *scheme) +esp_transport_handle_t esp_transport_list_get_transport(esp_transport_list_handle_t h, const char *scheme) { - if (!list) { + if (!h) { return NULL; } if (scheme == NULL) { - return STAILQ_FIRST(list); + return STAILQ_FIRST(&h->list); } esp_transport_handle_t item; - STAILQ_FOREACH(item, list, next) { + STAILQ_FOREACH(item, &h->list, next) { if (strcasecmp(item->scheme, scheme) == 0) { return item; } @@ -97,16 +109,17 @@ esp_transport_handle_t esp_transport_list_get_transport(esp_transport_list_handl return NULL; } -esp_err_t esp_transport_list_destroy(esp_transport_list_handle_t list) +esp_err_t esp_transport_list_destroy(esp_transport_list_handle_t h) { - esp_transport_list_clean(list); - free(list); + esp_transport_list_clean(h); + free(h->error_handle); + free(h); return ESP_OK; } -esp_err_t esp_transport_list_clean(esp_transport_list_handle_t list) +esp_err_t esp_transport_list_clean(esp_transport_list_handle_t h) { - esp_transport_handle_t item = STAILQ_FIRST(list); + esp_transport_handle_t item = STAILQ_FIRST(&h->list); esp_transport_handle_t tmp; while (item != NULL) { tmp = STAILQ_NEXT(item, next); @@ -116,7 +129,7 @@ esp_err_t esp_transport_list_clean(esp_transport_list_handle_t list) esp_transport_destroy(item); item = tmp; } - STAILQ_INIT(list); + STAILQ_INIT(&h->list); return ESP_OK; } @@ -277,3 +290,18 @@ esp_err_t esp_transport_set_parent_transport_func(esp_transport_handle_t t, payl t->_parent_transfer = _parent_transport; return ESP_OK; } + +esp_err_t get_and_clear_last_error(esp_transport_handle_t t) +{ + esp_err_t err = *(t->error_handle); + *(t->error_handle) = 0; + return err; +} + +void esp_transport_set_error(esp_transport_handle_t t, esp_err_t err) +{ + if (t) { + *t->error_handle = err; + } + return NULL; +} \ No newline at end of file diff --git a/components/tcp_transport/transport_ssl.c b/components/tcp_transport/transport_ssl.c index 49f71bb2d2..67b21999de 100644 --- a/components/tcp_transport/transport_ssl.c +++ b/components/tcp_transport/transport_ssl.c @@ -51,7 +51,7 @@ static int ssl_connect_async(esp_transport_handle_t t, const char *host, int por ssl->cfg.timeout_ms = timeout_ms; ssl->cfg.non_block = true; ssl->ssl_initialized = true; - ssl->tls = calloc(1, sizeof(esp_tls_t)); + ssl->tls = esp_tls_init(); if (!ssl->tls) { return -1; } @@ -69,9 +69,12 @@ static int ssl_connect(esp_transport_handle_t t, const char *host, int port, int ssl->cfg.timeout_ms = timeout_ms; ssl->ssl_initialized = true; - ssl->tls = esp_tls_conn_new(host, strlen(host), port, &ssl->cfg); - if (!ssl->tls) { + ssl->tls = esp_tls_init(); + if (esp_tls_conn_new(host, strlen(host), port, &ssl->cfg, ssl->tls) < 0) { ESP_LOGE(TAG, "Failed to open a new connection"); + esp_transport_set_error(t, esp_tls_get_and_clear_last_error(ssl->tls)); + esp_tls_conn_delete(ssl->tls); + ssl->tls = NULL; return -1; } return 0; @@ -112,7 +115,7 @@ static int ssl_write(esp_transport_handle_t t, const char *buffer, int len, int ret = esp_tls_conn_write(ssl->tls, (const unsigned char *) buffer, len); if (ret < 0) { ESP_LOGE(TAG, "esp_tls_conn_write error, errno=%s", strerror(errno)); - return -1; + esp_transport_set_error(t, esp_tls_get_and_clear_last_error(ssl->tls)); } return ret; } @@ -130,7 +133,7 @@ static int ssl_read(esp_transport_handle_t t, char *buffer, int len, int timeout ret = esp_tls_conn_read(ssl->tls, (unsigned char *)buffer, len); if (ret < 0) { ESP_LOGE(TAG, "esp_tls_conn_read error, errno=%s", strerror(errno)); - return -1; + esp_transport_set_error(t, esp_tls_get_and_clear_last_error(ssl->tls)); } if (ret == 0) { ret = -1; diff --git a/examples/protocols/mqtt/ssl/main/app_main.c b/examples/protocols/mqtt/ssl/main/app_main.c index 090e80255b..fa50e16949 100644 --- a/examples/protocols/mqtt/ssl/main/app_main.c +++ b/examples/protocols/mqtt/ssl/main/app_main.c @@ -79,6 +79,7 @@ static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) break; case MQTT_EVENT_ERROR: ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); + ESP_LOGI(TAG, "Error code: 0x%x", event->last_err); break; default: ESP_LOGI(TAG, "Other event id:%d", event->event_id); From 587739391ca119fb6f3f6c3c31bad4296cc8911b Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 16 Apr 2019 11:58:38 +0200 Subject: [PATCH 248/486] esp-tls: extending error handle to contain error descriptors with last mbedtls failure and latest certificate verification result flags, reworked tcp_transport to use this error handle --- components/esp-tls/esp_tls.c | 57 +++++++++---- components/esp-tls/esp_tls.h | 81 ++++++++++++++----- .../esp_tls_error_capture_internal.h | 33 +++++--- .../esp_http_client/lib/include/http_utils.h | 8 +- components/mqtt/esp-mqtt | 2 +- components/tcp_transport/CMakeLists.txt | 5 +- components/tcp_transport/component.mk | 6 +- .../tcp_transport/include/esp_transport.h | 20 +++-- .../esp_transport_ssl_internal.h | 30 +++++++ .../esp_transport_utils.h | 14 ++-- components/tcp_transport/transport.c | 29 +++---- components/tcp_transport/transport_ssl.c | 9 ++- examples/protocols/mqtt/ssl/main/app_main.c | 6 +- 13 files changed, 210 insertions(+), 90 deletions(-) create mode 100644 components/tcp_transport/private_include/esp_transport_ssl_internal.h rename components/tcp_transport/{include => private_include}/esp_transport_utils.h (88%) diff --git a/components/esp-tls/esp_tls.c b/components/esp-tls/esp_tls.c index 7adc02dc20..65cd789f39 100644 --- a/components/esp-tls/esp_tls.c +++ b/components/esp-tls/esp_tls.c @@ -81,7 +81,7 @@ static ssize_t tls_read(esp_tls_t *tls, char *data, size_t datalen) return 0; } if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { - ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); ESP_LOGE(TAG, "read error :%d:", ret); } } @@ -626,7 +626,7 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c } else { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { ESP_LOGE(TAG, "mbedtls_ssl_handshake returned -0x%x", -ret); - ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED); if (cfg->cacert_pem_buf != NULL || cfg->use_global_ca_store == true) { /* This is to check whether handshake failed due to invalid certificate*/ @@ -653,10 +653,31 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c /** * @brief Create a new TLS/SSL connection */ -int esp_tls_conn_new(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg, esp_tls_t *tls) +esp_tls_t *esp_tls_conn_new(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg) { + esp_tls_t *tls = (esp_tls_t *)calloc(1, sizeof(esp_tls_t)); + if (!tls) { + return NULL; + } /* esp_tls_conn_new() API establishes connection in a blocking manner thus this loop ensures that esp_tls_conn_new() API returns only after connection is established unless there is an error*/ + while (1) { + int ret = esp_tls_low_level_conn(hostname, hostlen, port, cfg, tls); + if (ret == 1) { + return tls; + } else if (ret == -1) { + esp_tls_conn_delete(tls); + ESP_LOGE(TAG, "Failed to open new connection"); + return NULL; + } + } + return NULL; +} + +int esp_tls_conn_new_sync(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg, esp_tls_t *tls) +{ + /* esp_tls_conn_new_sync() is a sync alternative to esp_tls_conn_new_async() with symetric function prototype + it is an alternative to esp_tls_conn_new() which is left for compatibility reasons */ while (1) { int ret = esp_tls_low_level_conn(hostname, hostlen, port, cfg, tls); if (ret == 1) { @@ -666,7 +687,7 @@ int esp_tls_conn_new(const char *hostname, int hostlen, int port, const esp_tls_ return -1; } } - return NULL; + return 0; } /* @@ -703,7 +724,7 @@ esp_tls_t *esp_tls_conn_http_new(const char *url, const esp_tls_cfg_t *cfg) esp_tls_t *tls = esp_tls_init(); if (!tls) return NULL; /* Connect to host */ - if (esp_tls_conn_new(&url[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len, + if (esp_tls_conn_new_sync(&url[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len, get_port(url, &u), cfg, tls) == 1) { return tls; } @@ -782,19 +803,27 @@ esp_tls_t *esp_tls_init() if (!tls) { return NULL; } - tls->error_handle = calloc(1, sizeof(esp_err_t)); + tls->error_handle = calloc(1, sizeof(esp_tls_last_error_t)); + if (!tls->error_handle) { + free(tls); + return NULL; + } tls->server_fd.fd = tls->sockfd = -1; return tls; } -esp_err_t esp_tls_get_and_clear_last_error(esp_tls_t* tls) +esp_err_t esp_tls_get_and_clear_last_error(esp_tls_error_handle_t h, int *mbedtls_code, int *mbedtls_flags) { - if (tls && tls->error_handle) { - esp_err_t last_err = tls->error_handle->last_error; - if (last_err != ESP_OK) { - tls->error_handle->last_error = ESP_OK; - return last_err; - } + if (!h) { + return ESP_ERR_INVALID_STATE; } - return ESP_OK; + esp_err_t last_err = h->last_error; + if (mbedtls_code) { + *mbedtls_code = h->mbedtls_error_code; + } + if (mbedtls_flags) { + *mbedtls_flags = h->mbedtls_flags; + } + memset(h, 0, sizeof(esp_tls_last_error_t)); + return last_err; } diff --git a/components/esp-tls/esp_tls.h b/components/esp-tls/esp_tls.h index 3e0f50bb6d..1c2f785ea5 100644 --- a/components/esp-tls/esp_tls.h +++ b/components/esp-tls/esp_tls.h @@ -35,21 +35,30 @@ extern "C" { #define ESP_ERR_ESP_TLS_CANNOT_RESOLVE_HOSTNAME (ESP_ERR_ESP_TLS_BASE + 0x01) /*!< Error if hostname couldn't be resolved upon tls connection */ #define ESP_ERR_ESP_TLS_CANNOT_CREATE_SOCKET (ESP_ERR_ESP_TLS_BASE + 0x02) /*!< Failed to create socket */ #define ESP_ERR_ESP_TLS_UNSUPPORTED_PROTOCOL_FAMILY (ESP_ERR_ESP_TLS_BASE + 0x03) /*!< Unsupported protocol family */ -#define ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST (ESP_ERR_ESP_TLS_BASE + 0x04) /*!< Failed to connnect to host */ +#define ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST (ESP_ERR_ESP_TLS_BASE + 0x04) /*!< Failed to connect to host */ #define ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED (ESP_ERR_ESP_TLS_BASE + 0x05) /*!< failed to set socket option */ -#define ESP_ERR_MBEDTLS_CERT_PARTLY_OK (ESP_ERR_ESP_TLS_BASE + 0x06) /*!< embedtls parse certificates was partly successful */ -#define ESP_ERR_MBEDTLS_CTR_DRBG_SEED_FAILED (ESP_ERR_ESP_TLS_BASE + 0x07) /*!< embedtls api returned failed */ -#define ESP_ERR_MBEDTLS_SSL_SET_HOSTNAME_FAILED (ESP_ERR_ESP_TLS_BASE + 0x08) /*!< embedtls api returned failed */ -#define ESP_ERR_MBEDTLS_SSL_CONFIG_DEFAULTS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x09) /*!< embedtls api returned failed */ -#define ESP_ERR_MBEDTLS_SSL_CONF_ALPN_PROTOCOLS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0A) /*!< embedtls api returned failed */ -#define ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0B) /*!< embedtls api returned failed */ -#define ESP_ERR_MBEDTLS_SSL_CONF_OWN_CERT_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0C) /*!< embedtls api returned failed */ -#define ESP_ERR_MBEDTLS_SSL_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0D) /*!< embedtls api returned failed */ -#define ESP_ERR_MBEDTLS_SSL_WRITE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0E) /*!< embedtls api returned failed */ -#define ESP_ERR_MBEDTLS_PK_PARSE_KEY_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0F) /*!< embedtls api returned failed */ -#define ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x10) /*!< embedtls api returned failed */ +#define ESP_ERR_MBEDTLS_CERT_PARTLY_OK (ESP_ERR_ESP_TLS_BASE + 0x06) /*!< mbedtls parse certificates was partly successful */ +#define ESP_ERR_MBEDTLS_CTR_DRBG_SEED_FAILED (ESP_ERR_ESP_TLS_BASE + 0x07) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_SSL_SET_HOSTNAME_FAILED (ESP_ERR_ESP_TLS_BASE + 0x08) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_SSL_CONFIG_DEFAULTS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x09) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_SSL_CONF_ALPN_PROTOCOLS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0A) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0B) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_SSL_CONF_OWN_CERT_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0C) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_SSL_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0D) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_SSL_WRITE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0E) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_PK_PARSE_KEY_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0F) /*!< mbedtls api returned failed */ +#define ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x10) /*!< mbedtls api returned failed */ -typedef struct esp_error_private* esp_error_handle_t; +typedef struct esp_tls_last_error* esp_tls_error_handle_t; + +/** +* @brief Error structure containing relevant errors in case tls error occurred +*/ +typedef struct esp_tls_last_error { + esp_err_t last_error; /*!< error code (based on ESP_ERR_ESP_TLS_BASE) of the last occurred error */ + int mbedtls_error_code; /*!< mbedtls error code from last mbedtls failed api */ + int mbedtls_flags; /*!< last certification verification flags */ +} esp_tls_last_error_t; /** * @brief ESP-TLS Connection State @@ -207,7 +216,7 @@ typedef struct esp_tls { - ESP_TLS_CLIENT - ESP_TLS_SERVER */ - esp_error_handle_t error_handle; /*!< handle to internal error descriptor */ + esp_tls_error_handle_t error_handle; /*!< handle to error descriptor */ } esp_tls_t; @@ -222,15 +231,39 @@ typedef struct esp_tls { */ esp_tls_t *esp_tls_init(); + + + /** * @brief Create a new blocking TLS/SSL connection * * This function establishes a TLS/SSL connection with the specified host in blocking manner. - * + * + * Note: This API is present for backward compatibility reasons. Alternative function + * with the same functionality is `esp_tls_conn_new_sync` (and its asynchronous version + * `esp_tls_conn_new_async`) + * * @param[in] hostname Hostname of the host. * @param[in] hostlen Length of hostname. * @param[in] port Port number of the host. - * @param[in] cfg TLS configuration as esp_tls_cfg_t. If you wish to open + * @param[in] cfg TLS configuration as esp_tls_cfg_t. If you wish to open + * non-TLS connection, keep this NULL. For TLS connection, + * a pass pointer to esp_tls_cfg_t. At a minimum, this + * structure should be zero-initialized. + * + * @return pointer to esp_tls_t, or NULL if connection couldn't be opened. + */ +esp_tls_t *esp_tls_conn_new(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg) __attribute__ ((deprecated)); + +/** + * @brief Create a new blocking TLS/SSL connection + * + * This function establishes a TLS/SSL connection with the specified host in blocking manner. + * + * @param[in] hostname Hostname of the host. + * @param[in] hostlen Length of hostname. + * @param[in] port Port number of the host. + * @param[in] cfg TLS configuration as esp_tls_cfg_t. If you wish to open * non-TLS connection, keep this NULL. For TLS connection, * a pass pointer to esp_tls_cfg_t. At a minimum, this * structure should be zero-initialized. @@ -241,7 +274,7 @@ esp_tls_t *esp_tls_init(); * - 1 If connection establishment is successful. * - 0 Reserved for connection state is in progress. */ -int esp_tls_conn_new(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg, esp_tls_t *tls); +int esp_tls_conn_new_sync(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg, esp_tls_t *tls); /** * @brief Create a new blocking TLS/SSL connection with a given "HTTP" url @@ -413,15 +446,21 @@ mbedtls_x509_crt *esp_tls_get_global_ca_store(); void esp_tls_free_global_ca_store(); /** - * @brief Returns last error in esp_tls (if any) and clears it. + * @brief Returns last error in esp_tls with detailed mbedtls related error codes. + * The error information is cleared internally upon return * - * @param[in] tls pointer to esp-tls as esp-tls handle. + * @param[in] h esp-tls error handle. + * @param[out] mbedtls_code last error code returned from mbedtls api (set to zero if none) + * This pointer could be NULL if caller does not care about mbedtls_code + * @param[out] mbedtls_flags last certification verification flags (set to zero if none) + * This pointer could be NULL if caller does not care about mbedtls_flags * * @return - * - ESP_OK if no error occurred + * - ESP_ERR_INVALID_STATE if invalid parameters + * - ESP_OK (0) if no error occurred * - specific error code (based on ESP_ERR_ESP_TLS_BASE) otherwise */ -esp_err_t esp_tls_get_and_clear_last_error(esp_tls_t* tls); +esp_err_t esp_tls_get_and_clear_last_error(esp_tls_error_handle_t h, int *mbedtls_code, int *mbedtls_flags); #ifdef CONFIG_ESP_TLS_SERVER /** diff --git a/components/esp-tls/private_include/esp_tls_error_capture_internal.h b/components/esp-tls/private_include/esp_tls_error_capture_internal.h index aabd5587b3..89ee4435cf 100644 --- a/components/esp-tls/private_include/esp_tls_error_capture_internal.h +++ b/components/esp-tls/private_include/esp_tls_error_capture_internal.h @@ -19,6 +19,9 @@ * This version is internal to esp-tls component and only saves single esp_err of last occurred error */ +#ifdef __cplusplus +extern "C" { +#endif /** * Definition of different types/sources of error codes reported @@ -33,16 +36,26 @@ typedef enum { } err_type_t; /** -* Internal structure for error description -* - contains only the last error of esp_err_t in this implementation -*/ -typedef struct esp_error_private { - esp_err_t last_error; -} esp_error_private_t; - -/** - * Error tracker logging macro, this implementation only saves the ERR_TYPE_ESP error, other types are ignored + * Error tracker logging macro, this implementation saves latest errors of + * ERR_TYPE_ESP, ERR_TYPE_MBEDTLS and ERR_TYPE_MBEDTLS_CERT_FLAGS types */ -#define ESP_INT_EVENT_TRACKER_CAPTURE(h, type, code) do { if (h && type==ERR_TYPE_ESP) { h->last_error = code; } } while (0) +#define ESP_INT_EVENT_TRACKER_CAPTURE(h, type, code) esp_int_event_tracker_capture(h, type, code) + +static inline void esp_int_event_tracker_capture(esp_tls_error_handle_t h, uint32_t type, int code) +{ + if (h) { + if (type == ERR_TYPE_ESP) { + h->last_error = code; + } else if (type == ERR_TYPE_MBEDTLS) { + h->mbedtls_error_code = code; + } else if (type == ERR_TYPE_MBEDTLS_CERT_FLAGS) { + h->mbedtls_flags = code; + } + } +} + +#ifdef __cplusplus +} +#endif #endif //__ESP_TLS_ERROR_CAPTURE_INTERNAL_H__ diff --git a/components/esp_http_client/lib/include/http_utils.h b/components/esp_http_client/lib/include/http_utils.h index d57840228f..14c3b10c4e 100644 --- a/components/esp_http_client/lib/include/http_utils.h +++ b/components/esp_http_client/lib/include/http_utils.h @@ -16,7 +16,7 @@ #ifndef _HTTP_UTILS_H_ #define _HTTP_UTILS_H_ #include -#include "esp_transport_utils.h" + /** * @brief Assign new_str to *str pointer, and realloc *str if it not NULL * @@ -80,7 +80,9 @@ char *http_utils_join_string(const char *first_str, int len_first, const char *s int http_utils_str_starts_with(const char *str, const char *start); -#define HTTP_MEM_CHECK(TAG, a, action) ESP_TRANSPORT_MEM_CHECK(TAG, a, action) - +#define HTTP_MEM_CHECK(TAG, a, action) if (!(a)) { \ + ESP_LOGE(TAG,"%s:%d (%s): %s", __FILE__, __LINE__, __FUNCTION__, "Memory exhausted"); \ + action; \ + } #endif diff --git a/components/mqtt/esp-mqtt b/components/mqtt/esp-mqtt index 65bf2255d7..0cc4077bd3 160000 --- a/components/mqtt/esp-mqtt +++ b/components/mqtt/esp-mqtt @@ -1 +1 @@ -Subproject commit 65bf2255d74c79e3c6abe3e3f791ba8d42efdee3 +Subproject commit 0cc4077bd3e10bb93456ff2785309ec9237a5906 diff --git a/components/tcp_transport/CMakeLists.txt b/components/tcp_transport/CMakeLists.txt index f1821db60f..9d5028a1b6 100644 --- a/components/tcp_transport/CMakeLists.txt +++ b/components/tcp_transport/CMakeLists.txt @@ -4,5 +4,6 @@ idf_component_register(SRCS "transport.c" "transport_ws.c" "transport_utils.c" "transport_strcasestr.c" - INCLUDE_DIRS include - REQUIRES lwip esp-tls) \ No newline at end of file + INCLUDE_DIRS "include" + PRIVATE_INCLUDE_DIRS "private_include" + REQUIRES lwip esp-tls) diff --git a/components/tcp_transport/component.mk b/components/tcp_transport/component.mk index 308f64f0ea..c81b547721 100644 --- a/components/tcp_transport/component.mk +++ b/components/tcp_transport/component.mk @@ -1,4 +1,2 @@ -# -# Component Makefile -# -# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) +COMPONENT_ADD_INCLUDEDIRS := include +COMPONENT_PRIV_INCLUDEDIRS := private_include \ No newline at end of file diff --git a/components/tcp_transport/include/esp_transport.h b/components/tcp_transport/include/esp_transport.h index bd4d33f67c..9dd7ff4495 100644 --- a/components/tcp_transport/include/esp_transport.h +++ b/components/tcp_transport/include/esp_transport.h @@ -33,6 +33,8 @@ typedef int (*poll_func)(esp_transport_handle_t t, int timeout_ms); typedef int (*connect_async_func)(esp_transport_handle_t t, const char *host, int port, int timeout_ms); typedef esp_transport_handle_t (*payload_transfer_func)(esp_transport_handle_t); +typedef struct esp_tls_last_error* esp_tls_error_handle_t; + /** * @brief Create transport list * @@ -299,23 +301,19 @@ esp_err_t esp_transport_set_async_connect_func(esp_transport_handle_t t, connect esp_err_t esp_transport_set_parent_transport_func(esp_transport_handle_t t, payload_transfer_func _parent_transport); /** - * @brief Returns last error in esp_tls (if any) and clears it. + * @brief Returns esp_tls error handle. + * Warning: The returned pointer is valid only as long as esp_transport_handle_t exists. Once transport + * handle gets destroyed, this value (esp_tls_error_handle_t) is freed automatically. * * @param[in] A transport handle * * @return - * - ESP_OK if no error occurred - * - specific error code (based on ESP_ERR_ESP_TLS_BASE) otherwise + * - valid pointer of esp_error_handle_t + * - NULL if invalid transport handle */ -esp_err_t get_and_clear_last_error(esp_transport_handle_t t); +esp_tls_error_handle_t esp_transport_get_error_handle(esp_transport_handle_t t); + -/** - * @brief Sets error to common transport handle - * - * @param[in] A transport handle - * - */ -void esp_transport_set_error(esp_transport_handle_t t, esp_err_t err); #ifdef __cplusplus } diff --git a/components/tcp_transport/private_include/esp_transport_ssl_internal.h b/components/tcp_transport/private_include/esp_transport_ssl_internal.h new file mode 100644 index 0000000000..8b794e05b9 --- /dev/null +++ b/components/tcp_transport/private_include/esp_transport_ssl_internal.h @@ -0,0 +1,30 @@ +// Copyright 2015-2019 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. + +#ifndef _ESP_TRANSPORT_INTERNAL_H_ +#define _ESP_TRANSPORT_INTERNAL_H_ + +/** + * @brief Sets error to common transport handle + * + * Note: This function copies the supplied error handle object to tcp_transport's internal + * error handle object + * + * @param[in] A transport handle + * + */ +void esp_transport_set_errors(esp_transport_handle_t t, const esp_tls_error_handle_t error_handle); + + +#endif /* _ESP_TRANSPORT_INTERNAL_H_ */ diff --git a/components/tcp_transport/include/esp_transport_utils.h b/components/tcp_transport/private_include/esp_transport_utils.h similarity index 88% rename from components/tcp_transport/include/esp_transport_utils.h rename to components/tcp_transport/private_include/esp_transport_utils.h index 405b4f6b46..6a9d1d02c7 100644 --- a/components/tcp_transport/include/esp_transport_utils.h +++ b/components/tcp_transport/private_include/esp_transport_utils.h @@ -20,6 +20,15 @@ extern "C" { #endif +/** + * @brief Utility macro to be used for NULL ptr check after malloc + * + */ +#define ESP_TRANSPORT_MEM_CHECK(TAG, a, action) if (!(a)) { \ + ESP_LOGE(TAG,"%s:%d (%s): %s", __FILE__, __LINE__, __FUNCTION__, "Memory exhausted"); \ + action; \ + } + /** * @brief Convert milliseconds to timeval struct * @@ -29,11 +38,6 @@ extern "C" { void esp_transport_utils_ms_to_timeval(int timeout_ms, struct timeval *tv); -#define ESP_TRANSPORT_MEM_CHECK(TAG, a, action) if (!(a)) { \ - ESP_LOGE(TAG,"%s:%d (%s): %s", __FILE__, __LINE__, __FUNCTION__, "Memory exhausted"); \ - action; \ - } - #ifdef __cplusplus } #endif diff --git a/components/tcp_transport/transport.c b/components/tcp_transport/transport.c index 3db2a69b6c..ddceba93c9 100644 --- a/components/tcp_transport/transport.c +++ b/components/tcp_transport/transport.c @@ -15,6 +15,7 @@ #include #include +#include #include "sys/queue.h" #include "esp_log.h" @@ -42,7 +43,7 @@ struct esp_transport_item_t { trans_func _destroy; /*!< Destroy and free transport */ connect_async_func _connect_async; /*!< non-blocking connect function of this transport */ payload_transfer_func _parent_transfer; /*!< Function returning underlying transport layer */ - esp_err_t* error_handle; /*!< Pointer to the last error */ + esp_tls_error_handle_t error_handle; /*!< Pointer to esp-tls error handle */ STAILQ_ENTRY(esp_transport_item_t) next; }; @@ -58,7 +59,7 @@ STAILQ_HEAD(esp_transport_list_t, esp_transport_item_t); */ typedef struct esp_transport_internal { struct esp_transport_list_t list; /*!< List of transports */ - esp_err_t* error_handle; /*!< Pointer to the error tracker if enabled */ + esp_tls_error_handle_t error_handle; /*!< Pointer to the error tracker if enabled */ } esp_transport_internal_t; static esp_transport_handle_t esp_transport_get_default_parent(esp_transport_handle_t t) @@ -74,7 +75,7 @@ esp_transport_list_handle_t esp_transport_list_init() esp_transport_list_handle_t transport = calloc(1, sizeof(esp_transport_internal_t)); ESP_TRANSPORT_MEM_CHECK(TAG, transport, return NULL); STAILQ_INIT(&transport->list); - transport->error_handle = calloc(1, sizeof(esp_err_t)); + transport->error_handle = calloc(1, sizeof(esp_tls_last_error_t)); return transport; } @@ -88,7 +89,7 @@ esp_err_t esp_transport_list_add(esp_transport_list_handle_t h, esp_transport_ha strcpy(t->scheme, scheme); STAILQ_INSERT_TAIL(&h->list, t, next); // Each transport in a list to share the same error tracker - t->error_handle = h->error_handle; + t->error_handle = h->error_handle; return ESP_OK; } @@ -291,17 +292,17 @@ esp_err_t esp_transport_set_parent_transport_func(esp_transport_handle_t t, payl return ESP_OK; } -esp_err_t get_and_clear_last_error(esp_transport_handle_t t) +esp_tls_error_handle_t esp_transport_get_error_handle(esp_transport_handle_t t) { - esp_err_t err = *(t->error_handle); - *(t->error_handle) = 0; - return err; -} - -void esp_transport_set_error(esp_transport_handle_t t, esp_err_t err) -{ - if (t) { - *t->error_handle = err; + if (t) { + return t->error_handle; } return NULL; +} + +void esp_transport_set_errors(esp_transport_handle_t t, const esp_tls_error_handle_t error_handle) +{ + if (t) { + memcpy(t->error_handle, error_handle, sizeof(esp_tls_last_error_t)); + } } \ No newline at end of file diff --git a/components/tcp_transport/transport_ssl.c b/components/tcp_transport/transport_ssl.c index 67b21999de..1651a2f87f 100644 --- a/components/tcp_transport/transport_ssl.c +++ b/components/tcp_transport/transport_ssl.c @@ -24,6 +24,7 @@ #include "esp_transport.h" #include "esp_transport_ssl.h" #include "esp_transport_utils.h" +#include "esp_transport_ssl_internal.h" static const char *TAG = "TRANS_SSL"; @@ -70,9 +71,9 @@ static int ssl_connect(esp_transport_handle_t t, const char *host, int port, int ssl->cfg.timeout_ms = timeout_ms; ssl->ssl_initialized = true; ssl->tls = esp_tls_init(); - if (esp_tls_conn_new(host, strlen(host), port, &ssl->cfg, ssl->tls) < 0) { + if (esp_tls_conn_new_sync(host, strlen(host), port, &ssl->cfg, ssl->tls) < 0) { ESP_LOGE(TAG, "Failed to open a new connection"); - esp_transport_set_error(t, esp_tls_get_and_clear_last_error(ssl->tls)); + esp_transport_set_errors(t, ssl->tls->error_handle); esp_tls_conn_delete(ssl->tls); ssl->tls = NULL; return -1; @@ -115,7 +116,7 @@ static int ssl_write(esp_transport_handle_t t, const char *buffer, int len, int ret = esp_tls_conn_write(ssl->tls, (const unsigned char *) buffer, len); if (ret < 0) { ESP_LOGE(TAG, "esp_tls_conn_write error, errno=%s", strerror(errno)); - esp_transport_set_error(t, esp_tls_get_and_clear_last_error(ssl->tls)); + esp_transport_set_errors(t, ssl->tls->error_handle); } return ret; } @@ -133,7 +134,7 @@ static int ssl_read(esp_transport_handle_t t, char *buffer, int len, int timeout ret = esp_tls_conn_read(ssl->tls, (unsigned char *)buffer, len); if (ret < 0) { ESP_LOGE(TAG, "esp_tls_conn_read error, errno=%s", strerror(errno)); - esp_transport_set_error(t, esp_tls_get_and_clear_last_error(ssl->tls)); + esp_transport_set_errors(t, ssl->tls->error_handle); } if (ret == 0) { ret = -1; diff --git a/examples/protocols/mqtt/ssl/main/app_main.c b/examples/protocols/mqtt/ssl/main/app_main.c index fa50e16949..e819c8fdc8 100644 --- a/examples/protocols/mqtt/ssl/main/app_main.c +++ b/examples/protocols/mqtt/ssl/main/app_main.c @@ -29,6 +29,7 @@ #include "esp_log.h" #include "mqtt_client.h" +#include "esp_tls.h" static const char *TAG = "MQTTS_EXAMPLE"; @@ -79,7 +80,10 @@ static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) break; case MQTT_EVENT_ERROR: ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); - ESP_LOGI(TAG, "Error code: 0x%x", event->last_err); + int mbedtls_err = 0; + esp_err_t err = esp_tls_get_and_clear_last_error(event->error_handle, &mbedtls_err, NULL); + ESP_LOGI(TAG, "Last esp error code: 0x%x", err); + ESP_LOGI(TAG, "Last mbedtls failure: 0x%x", mbedtls_err); break; default: ESP_LOGI(TAG, "Other event id:%d", event->event_id); From a001eb39bf43849d6171d759ab9c925e5ce23a10 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 23 Apr 2019 21:29:34 +0200 Subject: [PATCH 249/486] http_client: disconnect event to read last occurred error in esp-tls --- components/esp_http_client/esp_http_client.c | 2 +- .../esp_http_client/main/esp_http_client_example.c | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/components/esp_http_client/esp_http_client.c b/components/esp_http_client/esp_http_client.c index 822a02b785..f03aa83f08 100644 --- a/components/esp_http_client/esp_http_client.c +++ b/components/esp_http_client/esp_http_client.c @@ -1145,7 +1145,7 @@ int esp_http_client_write(esp_http_client_handle_t client, const char *buffer, i esp_err_t esp_http_client_close(esp_http_client_handle_t client) { if (client->state >= HTTP_STATE_INIT) { - http_dispatch_event(client, HTTP_EVENT_DISCONNECTED, NULL, 0); + http_dispatch_event(client, HTTP_EVENT_DISCONNECTED, esp_transport_get_error_handle(client->transport), 0); client->state = HTTP_STATE_INIT; return esp_transport_close(client->transport); } diff --git a/examples/protocols/esp_http_client/main/esp_http_client_example.c b/examples/protocols/esp_http_client/main/esp_http_client_example.c index c1aa73ea98..d6ae5b270f 100644 --- a/examples/protocols/esp_http_client/main/esp_http_client_example.c +++ b/examples/protocols/esp_http_client/main/esp_http_client_example.c @@ -17,6 +17,7 @@ #include "esp_event.h" #include "tcpip_adapter.h" #include "protocol_examples_common.h" +#include "esp_tls.h" #include "esp_http_client.h" @@ -63,7 +64,13 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt) ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH"); break; case HTTP_EVENT_DISCONNECTED: - ESP_LOGD(TAG, "HTTP_EVENT_DISCONNECTED"); + ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED"); + int mbedtls_err = 0; + esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL); + if (err != 0) { + ESP_LOGI(TAG, "Last esp error code: 0x%x", err); + ESP_LOGI(TAG, "Last mbedtls failure: 0x%x", mbedtls_err); + } break; } return ESP_OK; From dc16b8243fde94cea063c58d790d0a86e305e1ae Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 24 Apr 2019 14:49:20 +0200 Subject: [PATCH 250/486] esp_http_client: added example test case to verify error code received when connecting to non-existent url --- .../esp_http_client/esp_http_client_test.py | 3 ++- .../main/esp_http_client_example.c | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/examples/protocols/esp_http_client/esp_http_client_test.py b/examples/protocols/esp_http_client/esp_http_client_test.py index 0d161da4c2..1c9c1d5701 100644 --- a/examples/protocols/esp_http_client/esp_http_client_test.py +++ b/examples/protocols/esp_http_client/esp_http_client_test.py @@ -45,8 +45,9 @@ def test_examples_protocol_esp_http_client(env, extra_data): dut1.expect(re.compile(r"HTTP Absolute path redirect Status = 200, content_length = (\d)")) dut1.expect(re.compile(r"HTTPS Status = 200, content_length = (\d)")) dut1.expect(re.compile(r"HTTP redirect to HTTPS Status = 200, content_length = (\d)"), timeout=10) - dut1.expect(re.compile(r"HTTP chunk encoding Status = 200, content_length = -1")) + dut1.expect(re.compile(r"HTTP chunk encoding Status = 200, content_length = (\d)")) dut1.expect(re.compile(r"HTTP Stream reader Status = 200, content_length = (\d)")) + dut1.expect(re.compile(r"Last esp error code: 0x8001")) dut1.expect("Finish http example") diff --git a/examples/protocols/esp_http_client/main/esp_http_client_example.c b/examples/protocols/esp_http_client/main/esp_http_client_example.c index d6ae5b270f..6a642a73f4 100644 --- a/examples/protocols/esp_http_client/main/esp_http_client_example.c +++ b/examples/protocols/esp_http_client/main/esp_http_client_example.c @@ -492,6 +492,25 @@ static void https_async() esp_http_client_cleanup(client); } +static void https_with_invalid_url() +{ + esp_http_client_config_t config = { + .url = "https://not.existent.url", + .event_handler = _http_event_handler, + }; + esp_http_client_handle_t client = esp_http_client_init(&config); + esp_err_t err = esp_http_client_perform(client); + + if (err == ESP_OK) { + ESP_LOGI(TAG, "HTTPS Status = %d, content_length = %d", + esp_http_client_get_status_code(client), + esp_http_client_get_content_length(client)); + } else { + ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err)); + } + esp_http_client_cleanup(client); +} + static void http_test_task(void *pvParameters) { @@ -508,6 +527,7 @@ static void http_test_task(void *pvParameters) http_download_chunk(); http_perform_as_stream_reader(); https_async(); + https_with_invalid_url(); ESP_LOGI(TAG, "Finish http example"); vTaskDelete(NULL); @@ -529,6 +549,7 @@ void app_main() * examples/protocols/README.md for more information about this function. */ ESP_ERROR_CHECK(example_connect()); + ESP_LOGI(TAG, "Connected to AP, begin http example"); xTaskCreate(&http_test_task, "http_test_task", 8192, NULL, 5, NULL); } From d1433564ecfc885f80a7a261a88ab87d227cf1c2 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 3 Jul 2019 17:06:38 +0200 Subject: [PATCH 251/486] ws_client: removed dependency on internal tcp_transport header --- .../esp_websocket_client.c | 54 ++++++++++--------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/components/esp_websocket_client/esp_websocket_client.c b/components/esp_websocket_client/esp_websocket_client.c index 9d4b1f053f..e545559dc8 100644 --- a/components/esp_websocket_client/esp_websocket_client.c +++ b/components/esp_websocket_client/esp_websocket_client.c @@ -19,7 +19,6 @@ #include "esp_transport_tcp.h" #include "esp_transport_ssl.h" #include "esp_transport_ws.h" -#include "esp_transport_utils.h" /* using uri parser */ #include "http_parser.h" #include "freertos/task.h" @@ -42,6 +41,11 @@ static const char *TAG = "WEBSOCKET_CLIENT"; #define WEBSOCKET_EVENT_QUEUE_SIZE (1) #define WEBSOCKET_SEND_EVENT_TIMEOUT_MS (1000/portTICK_RATE_MS) +#define ESP_WS_CLIENT_MEM_CHECK(TAG, a, action) if (!(a)) { \ + ESP_LOGE(TAG,"%s:%d (%s): %s", __FILE__, __LINE__, __FUNCTION__, "Memory exhausted"); \ + action; \ + } + const static int STOPPED_BIT = BIT0; ESP_EVENT_DEFINE_BASE(WEBSOCKET_EVENTS); @@ -139,7 +143,7 @@ static esp_err_t esp_websocket_client_set_config(esp_websocket_client_handle_t c if (config->host) { cfg->host = strdup(config->host); - ESP_TRANSPORT_MEM_CHECK(TAG, cfg->host, return ESP_ERR_NO_MEM); + ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->host, return ESP_ERR_NO_MEM); } if (config->port) { @@ -149,7 +153,7 @@ static esp_err_t esp_websocket_client_set_config(esp_websocket_client_handle_t c if (config->username) { free(cfg->username); cfg->username = strdup(config->username); - ESP_TRANSPORT_MEM_CHECK(TAG, cfg->username, { + ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->username, { free(cfg->host); return ESP_ERR_NO_MEM; }); @@ -158,7 +162,7 @@ static esp_err_t esp_websocket_client_set_config(esp_websocket_client_handle_t c if (config->password) { free(cfg->password); cfg->password = strdup(config->password); - ESP_TRANSPORT_MEM_CHECK(TAG, cfg->password, { + ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->password, { free(cfg->host); free(cfg->username); return ESP_ERR_NO_MEM; @@ -168,7 +172,7 @@ static esp_err_t esp_websocket_client_set_config(esp_websocket_client_handle_t c if (config->uri) { free(cfg->uri); cfg->uri = strdup(config->uri); - ESP_TRANSPORT_MEM_CHECK(TAG, cfg->uri, { + ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->uri, { free(cfg->host); free(cfg->username); free(cfg->password); @@ -178,7 +182,7 @@ static esp_err_t esp_websocket_client_set_config(esp_websocket_client_handle_t c if (config->path) { free(cfg->path); cfg->path = strdup(config->path); - ESP_TRANSPORT_MEM_CHECK(TAG, cfg->path, { + ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->path, { free(cfg->uri); free(cfg->host); free(cfg->username); @@ -222,7 +226,7 @@ static esp_err_t esp_websocket_client_destroy_config(esp_websocket_client_handle esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_client_config_t *config) { esp_websocket_client_handle_t client = calloc(1, sizeof(struct esp_websocket_client)); - ESP_TRANSPORT_MEM_CHECK(TAG, client, return NULL); + ESP_WS_CLIENT_MEM_CHECK(TAG, client, return NULL); esp_event_loop_args_t event_args = { .queue_size = WEBSOCKET_EVENT_QUEUE_SIZE, @@ -236,30 +240,30 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie } client->lock = xSemaphoreCreateMutex(); - ESP_TRANSPORT_MEM_CHECK(TAG, client->lock, goto _websocket_init_fail); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->lock, goto _websocket_init_fail); client->transport_list = esp_transport_list_init(); - ESP_TRANSPORT_MEM_CHECK(TAG, client->transport_list, goto _websocket_init_fail); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->transport_list, goto _websocket_init_fail); esp_transport_handle_t tcp = esp_transport_tcp_init(); - ESP_TRANSPORT_MEM_CHECK(TAG, tcp, goto _websocket_init_fail); + ESP_WS_CLIENT_MEM_CHECK(TAG, tcp, goto _websocket_init_fail); esp_transport_set_default_port(tcp, WEBSOCKET_TCP_DEFAULT_PORT); esp_transport_list_add(client->transport_list, tcp, "_tcp"); // need to save to transport list, for cleanup esp_transport_handle_t ws = esp_transport_ws_init(tcp); - ESP_TRANSPORT_MEM_CHECK(TAG, ws, goto _websocket_init_fail); + ESP_WS_CLIENT_MEM_CHECK(TAG, ws, goto _websocket_init_fail); esp_transport_set_default_port(ws, WEBSOCKET_TCP_DEFAULT_PORT); esp_transport_list_add(client->transport_list, ws, "ws"); if (config->transport == WEBSOCKET_TRANSPORT_OVER_TCP) { asprintf(&client->config->scheme, "ws"); - ESP_TRANSPORT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail); } esp_transport_handle_t ssl = esp_transport_ssl_init(); - ESP_TRANSPORT_MEM_CHECK(TAG, ssl, goto _websocket_init_fail); + ESP_WS_CLIENT_MEM_CHECK(TAG, ssl, goto _websocket_init_fail); esp_transport_set_default_port(ssl, WEBSOCKET_SSL_DEFAULT_PORT); if (config->cert_pem) { @@ -268,18 +272,18 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie esp_transport_list_add(client->transport_list, ssl, "_ssl"); // need to save to transport list, for cleanup esp_transport_handle_t wss = esp_transport_ws_init(ssl); - ESP_TRANSPORT_MEM_CHECK(TAG, wss, goto _websocket_init_fail); + ESP_WS_CLIENT_MEM_CHECK(TAG, wss, goto _websocket_init_fail); esp_transport_set_default_port(wss, WEBSOCKET_SSL_DEFAULT_PORT); esp_transport_list_add(client->transport_list, wss, "wss"); if (config->transport == WEBSOCKET_TRANSPORT_OVER_TCP) { asprintf(&client->config->scheme, "wss"); - ESP_TRANSPORT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail); } client->config = calloc(1, sizeof(websocket_config_storage_t)); - ESP_TRANSPORT_MEM_CHECK(TAG, client->config, goto _websocket_init_fail); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->config, goto _websocket_init_fail); if (config->uri) { if (esp_websocket_client_set_uri(client, config->uri) != ESP_OK) { @@ -295,7 +299,7 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie if (client->config->scheme == NULL) { asprintf(&client->config->scheme, "ws"); - ESP_TRANSPORT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail); } client->keepalive_tick_ms = _tick_get_ms(); @@ -307,15 +311,15 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie buffer_size = WEBSOCKET_BUFFER_SIZE_BYTE; } client->rx_buffer = malloc(buffer_size); - ESP_TRANSPORT_MEM_CHECK(TAG, client->rx_buffer, { + ESP_WS_CLIENT_MEM_CHECK(TAG, client->rx_buffer, { goto _websocket_init_fail; }); client->tx_buffer = malloc(buffer_size); - ESP_TRANSPORT_MEM_CHECK(TAG, client->tx_buffer, { + ESP_WS_CLIENT_MEM_CHECK(TAG, client->tx_buffer, { goto _websocket_init_fail; }); client->status_bits = xEventGroupCreate(); - ESP_TRANSPORT_MEM_CHECK(TAG, client->status_bits, { + ESP_WS_CLIENT_MEM_CHECK(TAG, client->status_bits, { goto _websocket_init_fail; }); @@ -366,20 +370,20 @@ esp_err_t esp_websocket_client_set_uri(esp_websocket_client_handle_t client, con if (puri.field_data[UF_SCHEMA].len) { free(client->config->scheme); asprintf(&client->config->scheme, "%.*s", puri.field_data[UF_SCHEMA].len, uri + puri.field_data[UF_SCHEMA].off); - ESP_TRANSPORT_MEM_CHECK(TAG, client->config->scheme, return ESP_ERR_NO_MEM); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, return ESP_ERR_NO_MEM); } if (puri.field_data[UF_HOST].len) { free(client->config->host); asprintf(&client->config->host, "%.*s", puri.field_data[UF_HOST].len, uri + puri.field_data[UF_HOST].off); - ESP_TRANSPORT_MEM_CHECK(TAG, client->config->host, return ESP_ERR_NO_MEM); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->host, return ESP_ERR_NO_MEM); } if (puri.field_data[UF_PATH].len) { free(client->config->path); asprintf(&client->config->path, "%.*s", puri.field_data[UF_PATH].len, uri + puri.field_data[UF_PATH].off); - ESP_TRANSPORT_MEM_CHECK(TAG, client->config->path, return ESP_ERR_NO_MEM); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->path, return ESP_ERR_NO_MEM); esp_transport_handle_t trans = esp_transport_list_get_transport(client->transport_list, "ws"); if (trans) { @@ -404,11 +408,11 @@ esp_err_t esp_websocket_client_set_uri(esp_websocket_client_handle_t client, con pass ++; free(client->config->password); client->config->password = strdup(pass); - ESP_TRANSPORT_MEM_CHECK(TAG, client->config->password, return ESP_ERR_NO_MEM); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->password, return ESP_ERR_NO_MEM); } free(client->config->username); client->config->username = strdup(user_info); - ESP_TRANSPORT_MEM_CHECK(TAG, client->config->username, return ESP_ERR_NO_MEM); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->username, return ESP_ERR_NO_MEM); free(user_info); } else { return ESP_ERR_NO_MEM; From bfd1eeefa283a00cd52190666008ed0b00b7d66d Mon Sep 17 00:00:00 2001 From: Shivani Tipnis Date: Fri, 5 Jul 2019 08:14:04 +0800 Subject: [PATCH 252/486] Add NimBLE bleprph,blecent,blehr example tests --- examples/bluetooth/nimble/blecent/README.md | 69 +- .../bluetooth/nimble/blecent/blecent_test.py | 129 +++ examples/bluetooth/nimble/blehr/README.md | 54 ++ examples/bluetooth/nimble/blehr/blehr_test.py | 149 ++++ examples/bluetooth/nimble/bleprph/README.md | 75 ++ .../bluetooth/nimble/bleprph/bleprph_test.py | 169 ++++ tools/ble/lib_ble_client.py | 805 ++++++++++++++++++ tools/ble/lib_gap.py | 87 ++ tools/ble/lib_gatt.py | 412 +++++++++ tools/ble/requirements.txt | 3 + 10 files changed, 1950 insertions(+), 2 deletions(-) create mode 100644 examples/bluetooth/nimble/blecent/blecent_test.py create mode 100644 examples/bluetooth/nimble/blehr/blehr_test.py create mode 100644 examples/bluetooth/nimble/bleprph/bleprph_test.py create mode 100644 tools/ble/lib_ble_client.py create mode 100644 tools/ble/lib_gap.py create mode 100644 tools/ble/lib_gatt.py create mode 100644 tools/ble/requirements.txt diff --git a/examples/bluetooth/nimble/blecent/README.md b/examples/bluetooth/nimble/blecent/README.md index bfa7b68d4c..4b531f9787 100644 --- a/examples/bluetooth/nimble/blecent/README.md +++ b/examples/bluetooth/nimble/blecent/README.md @@ -20,6 +20,12 @@ This example aims at understanding BLE service discovery, connection and charact To test this demo, use any BLE GATT server app that advertises support for the Alert Notification service (0x1811) and includes it in the GATT database. +A Python based utility `blecent_test.py` is also provided (which will run as a BLE GATT server) and can be used to test this example. + +Note : + +* Make sure to run `python -m pip install --user -r $IDF_PATH/requirements.txt -r $IDF_PATH/tools/ble/requirements.txt` to install the dependency packages needed. +* Currently this Python utility is only supported on Linux (BLE communication is via BLuez + DBus). ## How to use example @@ -45,7 +51,8 @@ See the Getting Started Guide for full steps to configure and use ESP-IDF to bui ## Example Output -There is this console output on successful connection: +This is the console output on successful connection: + ``` I (202) BTDM_INIT: BT controller compile version [0b60040] I (202) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE @@ -71,7 +78,8 @@ Write complete; status=0 conn_handle=0 attr_handle=47 Subscribe complete; status=0 conn_handle=0 attr_handle=43 ``` -There is this console output on failure (or peripheral does not support New Alert Service category): +This is the console output on failure (or peripheral does not support New Alert Service category): + ``` I (180) BTDM_INIT: BT controller compile version [8e87ec7] I (180) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE @@ -92,3 +100,60 @@ Error: Peer doesn't support the Supported New Alert Category characteristic GAP procedure initiated: terminate connection; conn_handle=0 hci_reason=19 disconnect; reason=534 ``` + +## Running Python Utility + +``` +python blecent_test.py +``` + +## Python Utility Output + +This is this output seen on the python side on successful connection: + +``` +discovering adapter... +bluetooth adapter discovered +powering on adapter... +bluetooth adapter powered on +Advertising started +GATT Data created +GATT Application registered +Advertising data created +Advertisement registered +Read Request received + SupportedNewAlertCategoryCharacteristic + Value: [dbus.Byte(2)] +Write Request received + AlertNotificationControlPointCharacteristic + Current value: [dbus.Byte(0)] + New value: [dbus.Byte(99), dbus.Byte(100)] + +Notify Started +New value on write: [dbus.Byte(1), dbus.Byte(0)] + Value on read: [dbus.Byte(1), dbus.Byte(0)] + +Notify Stopped + +exiting from test... +GATT Data removed +GATT Application unregistered +Advertising data removed +Advertisement unregistered +Stop Advertising status: True +disconnecting device... +device disconnected +powering off adapter... +bluetooth adapter powered off +Service discovery passed + Service Discovery Status: 0 +Read passed + SupportedNewAlertCategoryCharacteristic + Read Status: 0 +Write passed + AlertNotificationControlPointCharacteristic + Write Status: 0 +Subscribe passed + ClientCharacteristicConfigurationDescriptor + Subscribe Status: 0 +``` diff --git a/examples/bluetooth/nimble/blecent/blecent_test.py b/examples/bluetooth/nimble/blecent/blecent_test.py new file mode 100644 index 0000000000..d1d79298c4 --- /dev/null +++ b/examples/bluetooth/nimble/blecent/blecent_test.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python +# +# Copyright 2019 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. + +from __future__ import print_function +import os +import sys +import re +import uuid +import subprocess + +try: + # This environment variable is expected on the host machine + test_fw_path = os.getenv("TEST_FW_PATH") + if test_fw_path and test_fw_path not in sys.path: + sys.path.insert(0, test_fw_path) + import IDF +except ImportError as e: + print(e) + print("\nCheck your IDF_PATH\nOR") + print("Try `export TEST_FW_PATH=$IDF_PATH/tools/tiny-test-fw` for resolving the issue\nOR") + print("Try `pip install -r $IDF_PATH/tools/tiny-test-fw/requirements.txt` for resolving the issue") + import IDF + +try: + import lib_ble_client +except ImportError: + lib_ble_client_path = os.getenv("IDF_PATH") + "/tools/ble" + if lib_ble_client_path and lib_ble_client_path not in sys.path: + sys.path.insert(0, lib_ble_client_path) + import lib_ble_client + + +import Utility + +# When running on local machine execute the following before running this script +# > make app bootloader +# > make print_flash_cmd | tail -n 1 > build/download.config +# > export TEST_FW_PATH=~/esp/esp-idf/tools/tiny-test-fw + + +@IDF.idf_example_test(env_tag="Example_WIFI_BT") +def test_example_app_ble_central(env, extra_data): + """ + Steps: + 1. Discover Bluetooth Adapter and Power On + """ + + interface = 'hci0' + adv_host_name = "BleCentTestApp" + adv_iface_index = 0 + adv_type = 'peripheral' + adv_uuid = '1811' + + # Acquire DUT + dut = env.get_dut("blecent", "examples/bluetooth/nimble/blecent") + + # Get binary file + binary_file = os.path.join(dut.app.binary_path, "blecent.bin") + bin_size = os.path.getsize(binary_file) + IDF.log_performance("blecent_bin_size", "{}KB".format(bin_size // 1024)) + + # Upload binary and start testing + Utility.console_log("Starting blecent example test app") + dut.start_app() + + subprocess.check_output(['rm','-rf','/var/lib/bluetooth/*']) + device_addr = ':'.join(re.findall('..', '%012x' % uuid.getnode())) + + # Get BLE client module + ble_client_obj = lib_ble_client.BLE_Bluez_Client(interface) + if not ble_client_obj: + raise RuntimeError("Get DBus-Bluez object failed !!") + + # Discover Bluetooth Adapter and power on + is_adapter_set = ble_client_obj.set_adapter() + if not is_adapter_set: + raise RuntimeError("Adapter Power On failed !!") + + # Write device address to dut + dut.expect("BLE Host Task Started", timeout=60) + dut.write(device_addr + "\n") + + ''' + Blecent application run: + Create GATT data + Register GATT Application + Create Advertising data + Register advertisement + Start advertising + ''' + ble_client_obj.start_advertising(adv_host_name, adv_iface_index, adv_type, adv_uuid) + + # Call disconnect to perform cleanup operations before exiting application + ble_client_obj.disconnect() + + # Check dut responses + dut.expect("Connection established", timeout=30) + + dut.expect("Service discovery complete; status=0", timeout=30) + print("Service discovery passed\n\tService Discovery Status: 0") + + dut.expect("GATT procedure initiated: read;", timeout=30) + dut.expect("Read complete; status=0", timeout=30) + print("Read passed\n\tSupportedNewAlertCategoryCharacteristic\n\tRead Status: 0") + + dut.expect("GATT procedure initiated: write;", timeout=30) + dut.expect("Write complete; status=0", timeout=30) + print("Write passed\n\tAlertNotificationControlPointCharacteristic\n\tWrite Status: 0") + + dut.expect("GATT procedure initiated: write;", timeout=30) + dut.expect("Subscribe complete; status=0", timeout=30) + print("Subscribe passed\n\tClientCharacteristicConfigurationDescriptor\n\tSubscribe Status: 0") + + +if __name__ == '__main__': + test_example_app_ble_central() diff --git a/examples/bluetooth/nimble/blehr/README.md b/examples/bluetooth/nimble/blehr/README.md index 29a773d96b..af4b0581f6 100644 --- a/examples/bluetooth/nimble/blehr/README.md +++ b/examples/bluetooth/nimble/blehr/README.md @@ -10,6 +10,13 @@ This example aims at understanding notification subscriptions and sending notifi To test this demo, any BLE scanner app can be used. +A Python based utility `blehr_test.py` is also provided (which will run as a BLE GATT Client) and can be used to test this example. + +Note : + +* Make sure to run `python -m pip install --user -r $IDF_PATH/requirements.txt -r $IDF_PATH/tools/ble/requirements.txt` to install the dependency packages needed. +* Currently this Python utility is only supported on Linux (BLE communication is via BLuez + DBus). + ## How to use example @@ -59,3 +66,50 @@ GATT procedure initiated: notify; att_handle=3 ``` +## Running Python Utility + +``` +python blehr_test.py +``` + +## Python Utility Output + +This is this output seen on the python side on successful connection: + +``` +discovering adapter... +bluetooth adapter discovered +powering on adapter... +bluetooth adapter powered on + +Started Discovery + +Connecting to device... + +Connected to device + +Services + +[dbus.String(u'00001801-0000-1000-8000-00805f9b34fb', variant_level=1), dbus.String(u'0000180d-0000-1000-8000-00805f9b34fb', variant_level=1), dbus.String(u'0000180a-0000-1000-8000-00805f9b34fb', variant_level=1)] + +Subscribe to notifications: On +dbus.Array([dbus.Byte(6), dbus.Byte(90)], signature=dbus.Signature('y'), variant_level=1) +dbus.Array([dbus.Byte(6), dbus.Byte(91)], signature=dbus.Signature('y'), variant_level=1) +dbus.Array([dbus.Byte(6), dbus.Byte(92)], signature=dbus.Signature('y'), variant_level=1) +dbus.Array([dbus.Byte(6), dbus.Byte(93)], signature=dbus.Signature('y'), variant_level=1) +dbus.Array([dbus.Byte(6), dbus.Byte(94)], signature=dbus.Signature('y'), variant_level=1) +dbus.Array([dbus.Byte(6), dbus.Byte(95)], signature=dbus.Signature('y'), variant_level=1) +dbus.Array([dbus.Byte(6), dbus.Byte(96)], signature=dbus.Signature('y'), variant_level=1) +dbus.Array([dbus.Byte(6), dbus.Byte(97)], signature=dbus.Signature('y'), variant_level=1) +dbus.Array([dbus.Byte(6), dbus.Byte(98)], signature=dbus.Signature('y'), variant_level=1) +dbus.Array([dbus.Byte(6), dbus.Byte(99)], signature=dbus.Signature('y'), variant_level=1) + +Subscribe to notifications: Off +Success: blehr example test passed + +exiting from test... +disconnecting device... +device disconnected +powering off adapter... +bluetooth adapter powered off +``` diff --git a/examples/bluetooth/nimble/blehr/blehr_test.py b/examples/bluetooth/nimble/blehr/blehr_test.py new file mode 100644 index 0000000000..81f21ee92b --- /dev/null +++ b/examples/bluetooth/nimble/blehr/blehr_test.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python +# +# Copyright 2019 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. + +from __future__ import print_function +import os +import sys +import re +from threading import Thread +import subprocess + +try: + # This environment variable is expected on the host machine + test_fw_path = os.getenv("TEST_FW_PATH") + if test_fw_path and test_fw_path not in sys.path: + sys.path.insert(0, test_fw_path) + import IDF +except ImportError as e: + print(e) + print("\nCheck your IDF_PATH\nOR") + print("Try `export TEST_FW_PATH=$IDF_PATH/tools/tiny-test-fw` for resolving the issue\nOR") + print("Try `pip install -r $IDF_PATH/tools/tiny-test-fw/requirements.txt` for resolving the issue\n") + import IDF + +try: + import lib_ble_client +except ImportError: + lib_ble_client_path = os.getenv("IDF_PATH") + "/tools/ble" + if lib_ble_client_path and lib_ble_client_path not in sys.path: + sys.path.insert(0, lib_ble_client_path) + import lib_ble_client + + +import Utility + +# When running on local machine execute the following before running this script +# > make app bootloader +# > make print_flash_cmd | tail -n 1 > build/download.config +# > export TEST_FW_PATH=~/esp/esp-idf/tools/tiny-test-fw + + +def blehr_client_task(dut_addr, dut): + interface = 'hci0' + ble_devname = 'blehr_sensor_1.0' + hr_srv_uuid = '180d' + hr_char_uuid = '2a37' + + # Get BLE client module + ble_client_obj = lib_ble_client.BLE_Bluez_Client(interface, devname=ble_devname, devaddr=dut_addr) + if not ble_client_obj: + raise RuntimeError("Failed to get DBus-Bluez object") + + # Discover Bluetooth Adapter and power on + is_adapter_set = ble_client_obj.set_adapter() + if not is_adapter_set: + raise RuntimeError("Adapter Power On failed !!") + + # Connect BLE Device + is_connected = ble_client_obj.connect() + if not is_connected: + Utility.console_log("Connection to device ", ble_devname, "failed !!") + # Call disconnect to perform cleanup operations before exiting application + ble_client_obj.disconnect() + return + + # Read Services + services_ret = ble_client_obj.get_services() + if services_ret: + print("\nServices\n") + print(services_ret) + else: + print("Failure: Read Services failed") + ble_client_obj.disconnect() + return + + ''' + Blehr application run: + Start Notifications + Retrieve updated value + Stop Notifications + ''' + blehr_ret = ble_client_obj.hr_update_simulation(hr_srv_uuid, hr_char_uuid) + if blehr_ret: + print("Success: blehr example test passed") + else: + print("Failure: blehr example test failed") + + # Call disconnect to perform cleanup operations before exiting application + ble_client_obj.disconnect() + + +@IDF.idf_example_test(env_tag="Example_WIFI_BT") +def test_example_app_ble_hr(env, extra_data): + """ + Steps: + 1. Discover Bluetooth Adapter and Power On + 2. Connect BLE Device + 3. Start Notifications + 4. Updated value is retrieved + 5. Stop Notifications + """ + try: + # Acquire DUT + dut = env.get_dut("blehr", "examples/bluetooth/nimble/blehr") + + # Get binary file + binary_file = os.path.join(dut.app.binary_path, "blehr.bin") + bin_size = os.path.getsize(binary_file) + IDF.log_performance("blehr_bin_size", "{}KB".format(bin_size // 1024)) + IDF.check_performance("blehr_bin_size", bin_size // 1024) + + # Upload binary and start testing + Utility.console_log("Starting blehr simple example test app") + dut.start_app() + + subprocess.check_output(['rm','-rf','/var/lib/bluetooth/*']) + + # Get device address from dut + dut_addr = dut.expect(re.compile(r"Device Address: ([a-fA-F0-9:]+)"), timeout=30)[0] + + # Starting a py-client in a separate thread + thread1 = Thread(target=blehr_client_task, args=(dut_addr,dut,)) + thread1.start() + thread1.join() + + # Check dut responses + dut.expect("subscribe event; cur_notify=1", timeout=30) + dut.expect("GATT procedure initiated: notify;", timeout=30) + dut.expect("subscribe event; cur_notify=0", timeout=30) + dut.expect("disconnect;", timeout=30) + + except Exception as e: + sys.exit(e) + + +if __name__ == '__main__': + test_example_app_ble_hr() diff --git a/examples/bluetooth/nimble/bleprph/README.md b/examples/bluetooth/nimble/bleprph/README.md index 5630bd0efa..6f0d96e8a5 100644 --- a/examples/bluetooth/nimble/bleprph/README.md +++ b/examples/bluetooth/nimble/bleprph/README.md @@ -12,6 +12,12 @@ It also demonstrates security features of NimBLE stack. SMP parameters like I/O To test this demo, any BLE scanner app can be used. +A Python based utility `bleprph_test.py` is also provided (which will run as a BLE GATT Client) and can be used to test this example. + +Note : + +* Make sure to run `python -m pip install --user -r $IDF_PATH/requirements.txt -r $IDF_PATH/tools/ble/requirements.txt` to install the dependency packages needed. +* Currently this Python utility is only supported on Linux (BLE communication is via BLuez + DBus). ## How to use example @@ -73,3 +79,72 @@ peer_ota_addr_type=1 peer_ota_addr=xx:xx:xx:xx:xx:xx peer_id_addr_type=1 peer_id ``` +## Running Python Utility + +``` +python bleprph_test.py +``` + +## Python Utility Output + +This is this output seen on the python side on successful connection: + +``` +discovering adapter... +bluetooth adapter discovered +powering on adapter... +bluetooth adapter powered on + +Started Discovery + +Connecting to device... + +Connected to device + +Services + +[dbus.String(u'00001801-0000-1000-8000-00805f9b34fb', variant_level=1), dbus.String(u'59462f12-9543-9999-12c8-58b459a2712d', variant_level=1)] + +Characteristics retrieved + + Characteristic: /org/bluez/hci0/dev_xx_xx_xx_xx_xx_xx/service000a/char000b + Characteristic UUID: 5c3a659e-897e-45e1-b016-007107c96df6 + Value: dbus.Array([dbus.Byte(45), dbus.Byte(244), dbus.Byte(81), dbus.Byte(88)], signature=dbus.Signature('y')) + Properties: : dbus.Array([dbus.String(u'read')], signature=dbus.Signature('s'), variant_level=1) + + Characteristic: /org/bluez/hci0/dev_xx_xx_xx_xx_xx_xx/service000a/char000d + Characteristic UUID: 5c3a659e-897e-45e1-b016-007107c96df7 + Value: dbus.Array([dbus.Byte(0)], signature=dbus.Signature('y')) + Properties: : dbus.Array([dbus.String(u'read'), dbus.String(u'write')], signature=dbus.Signature('s'), variant_level=1) + + Characteristic: /org/bluez/hci0/dev_xx_xx_xx_xx_xx_xx/service0006/char0007 + Characteristic UUID: 00002a05-0000-1000-8000-00805f9b34fb + Value: None + Properties: : dbus.Array([dbus.String(u'indicate')], signature=dbus.Signature('s'), variant_level=1) + +Characteristics after write operation + + Characteristic: /org/bluez/hci0/dev_xx_xx_xx_xx_xx_xx/service000a/char000b + Characteristic UUID: 5c3a659e-897e-45e1-b016-007107c96df6 + Value: dbus.Array([dbus.Byte(45), dbus.Byte(244), dbus.Byte(81), dbus.Byte(88)], signature=dbus.Signature('y')) + Properties: : dbus.Array([dbus.String(u'read')], signature=dbus.Signature('s'), variant_level=1) + + Characteristic: /org/bluez/hci0/dev_xx_xx_xx_xx_xx_xx/service000a/char000d + Characteristic UUID: 5c3a659e-897e-45e1-b016-007107c96df7 + Value: dbus.Array([dbus.Byte(65)], signature=dbus.Signature('y')) + Properties: : dbus.Array([dbus.String(u'read'), dbus.String(u'write')], signature=dbus.Signature('s'), variant_level=1) + + Characteristic: /org/bluez/hci0/dev_xx_xx_xx_xx_xx_xx/service0006/char0007 + Characteristic UUID: 00002a05-0000-1000-8000-00805f9b34fb + Value: None + Properties: : dbus.Array([dbus.String(u'indicate')], signature=dbus.Signature('s'), variant_level=1) + +exiting from test... +disconnecting device... +device disconnected +powering off adapter... +bluetooth adapter powered off +``` + +## Note +* NVS support is not yet integrated to bonding. So, for now, bonding is not persistent across reboot. diff --git a/examples/bluetooth/nimble/bleprph/bleprph_test.py b/examples/bluetooth/nimble/bleprph/bleprph_test.py new file mode 100644 index 0000000000..3e29f668c2 --- /dev/null +++ b/examples/bluetooth/nimble/bleprph/bleprph_test.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python +# +# Copyright 2019 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. + +from __future__ import print_function +import os +import sys +import re +from threading import Thread +import subprocess + +try: + # This environment variable is expected on the host machine + test_fw_path = os.getenv("TEST_FW_PATH") + if test_fw_path and test_fw_path not in sys.path: + sys.path.insert(0, test_fw_path) + import IDF +except ImportError as e: + print(e) + print("Try `export TEST_FW_PATH=$IDF_PATH/tools/tiny-test-fw` for resolving the issue") + print("Try `pip install -r $IDF_PATH/tools/tiny-test-fw/requirements.txt` for resolving the issue") + import IDF + +try: + import lib_ble_client +except ImportError: + lib_ble_client_path = os.getenv("IDF_PATH") + "/tools/ble" + if lib_ble_client_path and lib_ble_client_path not in sys.path: + sys.path.insert(0, lib_ble_client_path) + import lib_ble_client + + +import Utility + +# When running on local machine execute the following before running this script +# > make app bootloader +# > make print_flash_cmd | tail -n 1 > build/download.config +# > export TEST_FW_PATH=~/esp/esp-idf/tools/tiny-test-fw + + +def bleprph_client_task(dut_addr, dut): + interface = 'hci0' + ble_devname = 'nimble-bleprph' + srv_uuid = '2f12' + + # Get BLE client module + ble_client_obj = lib_ble_client.BLE_Bluez_Client(interface, devname=ble_devname, devaddr=dut_addr) + if not ble_client_obj: + raise RuntimeError("Failed to get DBus-Bluez object") + + # Discover Bluetooth Adapter and power on + is_adapter_set = ble_client_obj.set_adapter() + if not is_adapter_set: + raise RuntimeError("Adapter Power On failed !!") + + # Connect BLE Device + is_connected = ble_client_obj.connect() + if not is_connected: + Utility.console_log("Connection to device ", ble_devname, "failed !!") + # Call disconnect to perform cleanup operations before exiting application + ble_client_obj.disconnect() + return + + # Check dut responses + dut.expect("GAP procedure initiated: advertise;", timeout=30) + + # Read Services + services_ret = ble_client_obj.get_services(srv_uuid) + if services_ret: + print("\nServices\n") + print(services_ret) + else: + print("Failure: Read Services failed") + ble_client_obj.disconnect() + return + + # Read Characteristics + chars_ret = {} + chars_ret = ble_client_obj.read_chars() + if chars_ret: + Utility.console_log("\nCharacteristics retrieved") + for path, props in chars_ret.items(): + print("\n\tCharacteristic: ", path) + print("\tCharacteristic UUID: ", props[2]) + print("\tValue: ", props[0]) + print("\tProperties: : ", props[1]) + else: + print("Failure: Read Characteristics failed") + ble_client_obj.disconnect() + return + + ''' + Write Characteristics + - write 'A' to characteristic with write permission + ''' + chars_ret_on_write = {} + chars_ret_on_write = ble_client_obj.write_chars('A') + if chars_ret_on_write: + Utility.console_log("\nCharacteristics after write operation") + for path, props in chars_ret_on_write.items(): + print("\n\tCharacteristic:", path) + print("\tCharacteristic UUID: ", props[2]) + print("\tValue:", props[0]) + print("\tProperties: : ", props[1]) + else: + print("Failure: Write Characteristics failed") + ble_client_obj.disconnect() + return + + # Call disconnect to perform cleanup operations before exiting application + ble_client_obj.disconnect() + + +@IDF.idf_example_test(env_tag="Example_WIFI_BT") +def test_example_app_ble_peripheral(env, extra_data): + """ + Steps: + 1. Discover Bluetooth Adapter and Power On + 2. Connect BLE Device + 3. Read Services + 4. Read Characteristics + 5. Write Characteristics + """ + try: + + # Acquire DUT + dut = env.get_dut("bleprph", "examples/bluetooth/nimble/bleprph") + + # Get binary file + binary_file = os.path.join(dut.app.binary_path, "bleprph.bin") + bin_size = os.path.getsize(binary_file) + IDF.log_performance("bleprph_bin_size", "{}KB".format(bin_size // 1024)) + IDF.check_performance("bleprph_bin_size", bin_size // 1024) + + # Upload binary and start testing + Utility.console_log("Starting bleprph simple example test app") + dut.start_app() + + subprocess.check_output(['rm','-rf','/var/lib/bluetooth/*']) + + # Get device address from dut + dut_addr = dut.expect(re.compile(r"Device Address: ([a-fA-F0-9:]+)"), timeout=30)[0] + + # Starting a py-client in a separate thread + thread1 = Thread(target=bleprph_client_task, args=(dut_addr,dut,)) + thread1.start() + thread1.join() + + # Check dut responses + dut.expect("connection established; status=0", timeout=30) + dut.expect("disconnect;", timeout=30) + except Exception as e: + sys.exit(e) + + +if __name__ == '__main__': + test_example_app_ble_peripheral() diff --git a/tools/ble/lib_ble_client.py b/tools/ble/lib_ble_client.py new file mode 100644 index 0000000000..3cbec03709 --- /dev/null +++ b/tools/ble/lib_ble_client.py @@ -0,0 +1,805 @@ +#!/usr/bin/env python +# +# Copyright 2019 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. +# + +# DBus-Bluez BLE library + +from __future__ import print_function +import sys +import time + +try: + from future.moves.itertools import zip_longest + import dbus + import dbus.mainloop.glib + from gi.repository import GLib +except ImportError as e: + if 'linux' not in sys.platform: + sys.exit("Error: Only supported on Linux platform") + print(e) + print("Install packages `libgirepository1.0-dev gir1.2-gtk-3.0 libcairo2-dev libdbus-1-dev libdbus-glib-1-dev` for resolving the issue") + print("Run `pip install -r $IDF_PATH/tools/ble/requirements.txt` for resolving the issue") + raise + +import lib_gatt +import lib_gap + +srv_added_old_cnt = 0 +srv_added_new_cnt = 0 +blecent_retry_check_cnt = 0 +verify_service_cnt = 0 +verify_readchars_cnt = 0 +blecent_adv_uuid = '1811' +iface_added = False +gatt_app_obj_check = False +gatt_app_reg_check = False +adv_data_check = False +adv_reg_check = False +read_req_check = False +write_req_check = False +subscribe_req_check = False +ble_hr_chrc = False + +DISCOVERY_START = False + +TEST_CHECKS_PASS = False +ADV_STOP = False + +SERVICES_RESOLVED = False +SERVICE_UUID_FOUND = False + +BLUEZ_SERVICE_NAME = 'org.bluez' +DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager' +DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties' + +ADAPTER_IFACE = 'org.bluez.Adapter1' +DEVICE_IFACE = 'org.bluez.Device1' + +GATT_MANAGER_IFACE = 'org.bluez.GattManager1' +LE_ADVERTISING_MANAGER_IFACE = 'org.bluez.LEAdvertisingManager1' + +GATT_SERVICE_IFACE = 'org.bluez.GattService1' +GATT_CHRC_IFACE = 'org.bluez.GattCharacteristic1' + +ADAPTER_ON = False +DEVICE_CONNECTED = False +GATT_APP_REGISTERED = False +ADV_REGISTERED = False +ADV_ACTIVE_INSTANCE = False + +CHRC_VALUE_CNT = False + +# Set up the main loop. +dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) +dbus.mainloop.glib.threads_init() +# Set up the event main loop. +event_loop = GLib.MainLoop() + + +def set_props_status(props): + """ + Set Adapter status if it is powered on or off + """ + global ADAPTER_ON, SERVICES_RESOLVED, GATT_OBJ_REMOVED, GATT_APP_REGISTERED, \ + ADV_REGISTERED, ADV_ACTIVE_INSTANCE, DEVICE_CONNECTED, CHRC_VALUE, CHRC_VALUE_CNT + is_service_uuid = False + # Signal caught for change in Adapter Powered property + if 'Powered' in props: + if props['Powered'] == 1: + ADAPTER_ON = True + else: + ADAPTER_ON = False + event_loop.quit() + elif 'ServicesResolved' in props: + if props['ServicesResolved'] == 1: + SERVICES_RESOLVED = True + else: + SERVICES_RESOLVED = False + elif 'UUIDs' in props: + # Signal caught for add/remove GATT data having service uuid + for uuid in props['UUIDs']: + if blecent_adv_uuid in uuid: + is_service_uuid = True + if not is_service_uuid: + # Signal caught for removing GATT data having service uuid + # and for unregistering GATT application + GATT_APP_REGISTERED = False + lib_gatt.GATT_APP_OBJ = False + elif 'ActiveInstances' in props: + # Signal caught for Advertising - add/remove Instances property + if props['ActiveInstances'] == 1: + ADV_ACTIVE_INSTANCE = True + elif props['ActiveInstances'] == 0: + ADV_ACTIVE_INSTANCE = False + ADV_REGISTERED = False + lib_gap.ADV_OBJ = False + elif 'Connected' in props: + # Signal caught for device connect/disconnect + if props['Connected'] is True: + DEVICE_CONNECTED = True + event_loop.quit() + else: + DEVICE_CONNECTED = False + elif 'Value' in props: + # Signal caught for change in chars value + if ble_hr_chrc: + CHRC_VALUE_CNT += 1 + print(props['Value']) + if CHRC_VALUE_CNT == 10: + event_loop.quit() + + +def props_change_handler(iface, changed_props, invalidated): + """ + PropertiesChanged Signal handler. + Catch and print information about PropertiesChanged signal. + """ + + if iface == ADAPTER_IFACE: + set_props_status(changed_props) + if iface == LE_ADVERTISING_MANAGER_IFACE: + set_props_status(changed_props) + if iface == DEVICE_IFACE: + set_props_status(changed_props) + if iface == GATT_CHRC_IFACE: + set_props_status(changed_props) + + +class BLE_Bluez_Client: + def __init__(self, iface, devname=None, devaddr=None): + self.bus = None + self.device = None + self.devname = devname + self.devaddr = devaddr + self.iface = iface + self.ble_objs = None + self.props_iface_obj = None + self.adapter_path = [] + self.adapter = None + self.services = [] + self.srv_uuid = [] + self.chars = {} + self.char_uuid = [] + + try: + self.bus = dbus.SystemBus() + om_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, "/"), DBUS_OM_IFACE) + self.ble_objs = om_iface_obj.GetManagedObjects() + + except Exception as e: + print(e) + + def __del__(self): + try: + print("Test Exit") + except Exception as e: + print(e) + sys.exit(1) + + def set_adapter(self): + ''' + Discover Bluetooth Adapter + Power On Bluetooth Adapter + ''' + try: + print("discovering adapter...") + for path, interfaces in self.ble_objs.items(): + adapter = interfaces.get(ADAPTER_IFACE) + if adapter is not None: + if path.endswith(self.iface): + self.adapter = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, path), ADAPTER_IFACE) + # Create Properties Interface object only after adapter is found + self.props_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, path), DBUS_PROP_IFACE) + self.adapter_path = [path, interfaces] + # Check adapter status - power on/off + set_props_status(interfaces[ADAPTER_IFACE]) + break + + if self.adapter is None: + raise RuntimeError("\nError: bluetooth adapter not found") + + if self.props_iface_obj is None: + raise RuntimeError("\nError: properties interface not found") + + print("bluetooth adapter discovered") + + self.props_iface_obj.connect_to_signal('PropertiesChanged', props_change_handler) + + # Check if adapter is already powered on + if ADAPTER_ON: + print("bluetooth adapter is already on") + return True + + # Power On Adapter + print("powering on adapter...") + self.props_iface_obj.Set(ADAPTER_IFACE, "Powered", dbus.Boolean(1)) + + event_loop.run() + + if ADAPTER_ON: + print("bluetooth adapter powered on") + return True + else: + print("Failure: bluetooth adapter not powered on") + return False + + except Exception as e: + print(e) + sys.exit(1) + + def connect(self): + ''' + Connect to the device discovered + Retry 10 times to discover and connect to device + ''' + global DISCOVERY_START + + device_found = False + try: + self.adapter.StartDiscovery() + print("\nStarted Discovery") + + DISCOVERY_START = True + + for retry_cnt in range(10,0,-1): + try: + if self.device is None: + print("\nConnecting to device...") + # Wait for device to be discovered + time.sleep(5) + device_found = self.get_device() + if device_found: + self.device.Connect(dbus_interface=DEVICE_IFACE) + event_loop.quit() + print("\nConnected to device") + return True + except Exception as e: + print(e) + print("\nRetries left", retry_cnt - 1) + continue + + # Device not found + return False + + except Exception as e: + print(e) + self.device = None + return False + + def get_device(self): + ''' + Discover device based on device name + and device address and connect + ''' + dev_path = None + + om_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, "/"), DBUS_OM_IFACE) + self.ble_objs = om_iface_obj.GetManagedObjects() + for path, interfaces in self.ble_objs.items(): + if DEVICE_IFACE not in interfaces.keys(): + continue + device_addr_iface = (path.replace('_', ':')).lower() + dev_addr = self.devaddr.lower() + if dev_addr in device_addr_iface and \ + interfaces[DEVICE_IFACE].get("Name") == self.devname: + dev_path = path + break + + if dev_path is None: + print("\nBLE device not found") + return False + + device_props_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, dev_path), DBUS_PROP_IFACE) + device_props_iface_obj.connect_to_signal('PropertiesChanged', props_change_handler) + + self.device = self.bus.get_object(BLUEZ_SERVICE_NAME, dev_path) + return True + + def srvc_iface_added_handler(self, path, interfaces): + ''' + Add services found as lib_ble_client obj + ''' + if self.device and path.startswith(self.device.object_path): + if GATT_SERVICE_IFACE in interfaces.keys(): + service = self.bus.get_object(BLUEZ_SERVICE_NAME, path) + uuid = service.Get(GATT_SERVICE_IFACE, 'UUID', dbus_interface=DBUS_PROP_IFACE) + if uuid not in self.srv_uuid: + self.srv_uuid.append(uuid) + if path not in self.services: + self.services.append(path) + + def verify_get_services(self): + global SERVICE_SCAN_FAIL, verify_service_cnt + verify_service_cnt += 1 + if iface_added and self.services and SERVICES_RESOLVED: + event_loop.quit() + + if verify_service_cnt == 10: + event_loop.quit() + + def verify_service_uuid_found(self): + ''' + Verify service uuid found + ''' + global SERVICE_UUID_FOUND + + srv_uuid_found = [uuid for uuid in self.srv_uuid if service_uuid in uuid] + if srv_uuid_found: + SERVICE_UUID_FOUND = True + + def get_services(self, srv_uuid=None): + ''' + Retrieve Services found in the device connected + ''' + global service_uuid, iface_added, SERVICE_UUID_FOUND + service_uuid = srv_uuid + iface_added = False + SERVICE_UUID_FOUND = False + try: + om_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, "/"), DBUS_OM_IFACE) + self.ble_objs = om_iface_obj.GetManagedObjects() + + for path, interfaces in self.ble_objs.items(): + self.srvc_iface_added_handler(path, interfaces) + # If services not found, then they may not have been added yet on dbus + if not self.services: + iface_added = True + GLib.timeout_add_seconds(2, self.verify_get_services) + om_iface_obj.connect_to_signal('InterfacesAdded', self.srvc_iface_added_handler) + event_loop.run() + if service_uuid: + self.verify_service_uuid_found() + if not SERVICE_UUID_FOUND: + raise Exception("Service with uuid: %s not found !!!" % service_uuid) + return self.srv_uuid + except Exception as e: + print("Error: ", e) + return False + + def chrc_iface_added_handler(self, path, interfaces): + ''' + Add services found as lib_ble_client obj + ''' + global chrc, chrc_discovered + chrc_val = None + + if self.device and path.startswith(self.device.object_path): + if GATT_CHRC_IFACE in interfaces.keys(): + chrc = self.bus.get_object(BLUEZ_SERVICE_NAME, path) + chrc_props = chrc.GetAll(GATT_CHRC_IFACE, + dbus_interface=DBUS_PROP_IFACE) + chrc_flags = chrc_props['Flags'] + if 'read' in chrc_flags: + chrc_val = chrc.ReadValue({}, dbus_interface=GATT_CHRC_IFACE) + uuid = chrc_props['UUID'] + self.chars[path] = chrc_val, chrc_flags, uuid + + def verify_get_chars(self): + global verify_readchars_cnt + verify_readchars_cnt += 1 + if iface_added and self.chars: + event_loop.quit() + if verify_readchars_cnt == 10: + event_loop.quit() + + def read_chars(self): + ''' + Read characteristics found in the device connected + ''' + global iface_added, chrc_discovered + chrc_discovered = False + iface_added = False + + try: + om_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, "/"), DBUS_OM_IFACE) + self.ble_objs = om_iface_obj.GetManagedObjects() + for path, interfaces in self.ble_objs.items(): + self.chrc_iface_added_handler(path, interfaces) + + # If chars not found, then they have not been added yet to interface + if not self.chars: + iface_added = True + GLib.timeout_add_seconds(2, self.verify_get_chars) + om_iface_obj.connect_to_signal('InterfacesAdded', self.chars_iface_added_handler) + event_loop.run() + return self.chars + except Exception as e: + print("Error: ", e) + return False + + def write_chars(self, write_val): + ''' + Write characteristics to the device connected + ''' + chrc = None + chrc_val = None + char_write_props = False + + try: + for path, props in self.chars.items(): + if 'write' in props[1]: # check permission + char_write_props = True + chrc = self.bus.get_object(BLUEZ_SERVICE_NAME, path) + chrc.WriteValue(write_val,{},dbus_interface=GATT_CHRC_IFACE) + if 'read' in props[1]: + chrc_val = chrc.ReadValue({}, dbus_interface=GATT_CHRC_IFACE) + else: + print("Warning: Cannot read value. Characteristic does not have read permission.") + if not (ord(write_val) == int(chrc_val[0])): + print("\nWrite Failed") + return False + self.chars[path] = chrc_val, props[1], props[2] # update value + if not char_write_props: + print("Failure: Cannot perform write operation. Characteristic does not have write permission.") + return False + + return self.chars + except Exception as e: + print(e) + return False + + def hr_update_simulation(self, hr_srv_uuid, hr_char_uuid): + ''' + Start Notifications + Retrieve updated value + Stop Notifications + ''' + global ble_hr_chrc + + srv_path = None + chrc = None + uuid = None + chrc_path = None + chars_ret = None + ble_hr_chrc = True + + try: + # Get HR Measurement characteristic + services = list(zip_longest(self.srv_uuid, self.services)) + for uuid, path in services: + if hr_srv_uuid in uuid: + srv_path = path + break + + if srv_path is None: + print("Failure: HR UUID:", hr_srv_uuid, "not found") + return False + + chars_ret = self.read_chars() + + for path, props in chars_ret.items(): + if path.startswith(srv_path): + chrc = self.bus.get_object(BLUEZ_SERVICE_NAME, path) + chrc_path = path + if hr_char_uuid in props[2]: # uuid + break + if chrc is None: + print("Failure: Characteristics for service: ", srv_path, "not found") + return False + # Subscribe to notifications + print("\nSubscribe to notifications: On") + chrc.StartNotify(dbus_interface=GATT_CHRC_IFACE) + + chrc_props_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, chrc_path), DBUS_PROP_IFACE) + chrc_props_iface_obj.connect_to_signal('PropertiesChanged', props_change_handler) + + event_loop.run() + chrc.StopNotify(dbus_interface=GATT_CHRC_IFACE) + time.sleep(2) + print("\nSubscribe to notifications: Off") + + ble_hr_chrc = False + return True + + except Exception as e: + print(e) + return False + + def create_gatt_app(self): + ''' + Create GATT data + Register GATT Application + ''' + global gatt_app_obj, gatt_manager_iface_obj + + gatt_app_obj = None + gatt_manager_iface_obj = None + + try: + gatt_app_obj = lib_gatt.Application(self.bus, self.adapter_path[0]) + gatt_manager_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME,self.adapter_path[0]), GATT_MANAGER_IFACE) + + gatt_manager_iface_obj.RegisterApplication(gatt_app_obj, {}, + reply_handler=self.gatt_app_handler, + error_handler=self.gatt_app_error_handler) + return True + except Exception as e: + print(e) + return False + + def gatt_app_handler(self): + ''' + GATT Application Register success handler + ''' + global GATT_APP_REGISTERED + GATT_APP_REGISTERED = True + + def gatt_app_error_handler(self, error): + ''' + GATT Application Register error handler + ''' + global GATT_APP_REGISTERED + GATT_APP_REGISTERED = False + + def start_advertising(self, adv_host_name, adv_iface_index, adv_type, adv_uuid): + ''' + Create Advertising data + Register Advertisement + Start Advertising + ''' + global le_adv_obj, le_adv_manager_iface_obj + le_adv_obj = None + le_adv_manager_iface_obj = None + le_adv_iface_path = None + + try: + print("Advertising started") + gatt_app_ret = self.create_gatt_app() + + if not gatt_app_ret: + return False + + for path,interface in self.ble_objs.items(): + if LE_ADVERTISING_MANAGER_IFACE in interface: + le_adv_iface_path = path + + if le_adv_iface_path is None: + print('\n Cannot start advertising. LEAdvertisingManager1 Interface not found') + return False + + le_adv_obj = lib_gap.Advertisement(self.bus, adv_iface_index, adv_type, adv_uuid, adv_host_name) + le_adv_manager_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, le_adv_iface_path), LE_ADVERTISING_MANAGER_IFACE) + + le_adv_manager_iface_obj.RegisterAdvertisement(le_adv_obj.get_path(), {}, + reply_handler=self.adv_handler, + error_handler=self.adv_error_handler) + + GLib.timeout_add_seconds(2, self.verify_blecent) + event_loop.run() + + if TEST_CHECKS_PASS: + return True + else: + return False + + except Exception as e: + print("in Exception") + print(e) + return False + + def adv_handler(self): + ''' + Advertisement Register success handler + ''' + global ADV_REGISTERED + ADV_REGISTERED = True + + def adv_error_handler(self, error): + ''' + Advertisement Register error handler + ''' + global ADV_REGISTERED + ADV_REGISTERED = False + + def verify_blecent(self): + """ + Verify blecent test commands are successful + """ + global blecent_retry_check_cnt, gatt_app_obj_check, gatt_app_reg_check,\ + adv_data_check, adv_reg_check, read_req_check, write_req_check,\ + subscribe_req_check, TEST_CHECKS_PASS + + # Get device when connected + if not self.device: + om_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, "/"), DBUS_OM_IFACE) + self.ble_objs = om_iface_obj.GetManagedObjects() + + for path, interfaces in self.ble_objs.items(): + if DEVICE_IFACE not in interfaces.keys(): + continue + device_props_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, path), DBUS_PROP_IFACE) + device_props_iface_obj.connect_to_signal('PropertiesChanged', props_change_handler) + self.device = self.bus.get_object(BLUEZ_SERVICE_NAME, path) + + # Check for failures after 10 retries + if blecent_retry_check_cnt == 10: + # check for failures + if not gatt_app_obj_check: + print("Failure: GATT Data could not be created") + if not gatt_app_reg_check: + print("Failure: GATT Application could not be registered") + if not adv_data_check: + print("Failure: Advertising data could not be created") + if not adv_reg_check: + print("Failure: Advertisement could not be registered") + if not read_req_check: + print("Failure: Read Request not received") + if not write_req_check: + print("Failure: Write Request not received") + if not subscribe_req_check: + print("Failure: Subscribe Request not received") + + # Blecent Test failed + TEST_CHECKS_PASS = False + if subscribe_req_check: + lib_gatt.alert_status_char_obj.StopNotify() + event_loop.quit() + return False # polling for checks will stop + + # Check for success + if not gatt_app_obj_check and lib_gatt.GATT_APP_OBJ: + print("GATT Data created") + gatt_app_obj_check = True + if not gatt_app_reg_check and GATT_APP_REGISTERED: + print("GATT Application registered") + gatt_app_reg_check = True + if not adv_data_check and lib_gap.ADV_OBJ: + print("Advertising data created") + adv_data_check = True + if not adv_reg_check and ADV_REGISTERED and ADV_ACTIVE_INSTANCE: + print("Advertisement registered") + adv_reg_check = True + if not read_req_check and lib_gatt.CHAR_READ: + read_req_check = True + if not write_req_check and lib_gatt.CHAR_WRITE: + write_req_check = True + if not subscribe_req_check and lib_gatt.CHAR_SUBSCRIBE: + subscribe_req_check = True + + # Increment retry count + blecent_retry_check_cnt += 1 + if read_req_check and write_req_check and subscribe_req_check: + # all checks passed + # Blecent Test passed + TEST_CHECKS_PASS = True + lib_gatt.alert_status_char_obj.StopNotify() + event_loop.quit() + return False # polling for checks will stop + + # Default return True - polling for checks will continue + return True + + def verify_blecent_disconnect(self): + """ + Verify cleanup is successful + """ + global blecent_retry_check_cnt, gatt_app_obj_check, gatt_app_reg_check,\ + adv_data_check, adv_reg_check, ADV_STOP + + if blecent_retry_check_cnt == 0: + gatt_app_obj_check = False + gatt_app_reg_check = False + adv_data_check = False + adv_reg_check = False + + # Check for failures after 10 retries + if blecent_retry_check_cnt == 10: + # check for failures + if not gatt_app_obj_check: + print("Warning: GATT Data could not be removed") + if not gatt_app_reg_check: + print("Warning: GATT Application could not be unregistered") + if not adv_data_check: + print("Warning: Advertising data could not be removed") + if not adv_reg_check: + print("Warning: Advertisement could not be unregistered") + + # Blecent Test failed + ADV_STOP = False + event_loop.quit() + return False # polling for checks will stop + + # Check for success + if not gatt_app_obj_check and not lib_gatt.GATT_APP_OBJ: + print("GATT Data removed") + gatt_app_obj_check = True + if not gatt_app_reg_check and not GATT_APP_REGISTERED: + print("GATT Application unregistered") + gatt_app_reg_check = True + if not adv_data_check and not adv_reg_check and not (ADV_REGISTERED or ADV_ACTIVE_INSTANCE or lib_gap.ADV_OBJ): + print("Advertising data removed") + print("Advertisement unregistered") + adv_data_check = True + adv_reg_check = True + + # Increment retry count + blecent_retry_check_cnt += 1 + if adv_reg_check: + # all checks passed + ADV_STOP = True + event_loop.quit() + return False # polling for checks will stop + + # Default return True - polling for checks will continue + return True + + def disconnect(self): + ''' + Before application exits: + Advertisement is unregistered + Advertisement object created is removed from dbus + GATT Application is unregistered + GATT Application object created is removed from dbus + Disconnect device if connected + Adapter is powered off + ''' + try: + global blecent_retry_check_cnt, DISCOVERY_START + blecent_retry_check_cnt = 0 + + print("\nexiting from test...") + + if ADV_REGISTERED: + # Unregister Advertisement + le_adv_manager_iface_obj.UnregisterAdvertisement(le_adv_obj.get_path()) + + # Remove Advertising data + dbus.service.Object.remove_from_connection(le_adv_obj) + + if GATT_APP_REGISTERED: + # Unregister GATT Application + gatt_manager_iface_obj.UnregisterApplication(gatt_app_obj.get_path()) + + # Remove GATT data + dbus.service.Object.remove_from_connection(gatt_app_obj) + + GLib.timeout_add_seconds(2, self.verify_blecent_disconnect) + event_loop.run() + + if ADV_STOP: + print("Stop Advertising status: ", ADV_STOP) + else: + print("Warning: Stop Advertising status: ", ADV_STOP) + + # Disconnect device + if self.device: + print("disconnecting device...") + self.device.Disconnect(dbus_interface=DEVICE_IFACE) + if self.adapter: + self.adapter.RemoveDevice(self.device) + self.device = None + if DISCOVERY_START: + self.adapter.StopDiscovery() + DISCOVERY_START = False + + # Power off Adapter + self.props_iface_obj.Set(ADAPTER_IFACE, "Powered", dbus.Boolean(0)) + event_loop.run() + + if not DEVICE_CONNECTED: + print("device disconnected") + else: + print("Warning: device could not be disconnected") + + print("powering off adapter...") + if not ADAPTER_ON: + print("bluetooth adapter powered off") + else: + print("\nWarning: Bluetooth adapter not powered off") + + except Exception as e: + print(e) + return False diff --git a/tools/ble/lib_gap.py b/tools/ble/lib_gap.py new file mode 100644 index 0000000000..2033dc4ab8 --- /dev/null +++ b/tools/ble/lib_gap.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# +# Copyright 2019 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. +# + +# Register Advertisement + +from __future__ import print_function +import sys + +try: + import dbus + import dbus.service +except ImportError as e: + if 'linux' not in sys.platform: + sys.exit("Error: Only supported on Linux platform") + print(e) + print("Install packages `libgirepository1.0-dev gir1.2-gtk-3.0 libcairo2-dev libdbus-1-dev libdbus-glib-1-dev` for resolving the issue") + print("Run `pip install -r $IDF_PATH/tools/ble/requirements.txt` for resolving the issue") + raise + +ADV_OBJ = False + +DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties' +LE_ADVERTISEMENT_IFACE = 'org.bluez.LEAdvertisement1' + + +class InvalidArgsException(dbus.exceptions.DBusException): + _dbus_error_name = 'org.freedesktop.DBus.Error.InvalidArgs' + + +class Advertisement(dbus.service.Object): + PATH_BASE = '/org/bluez/hci0/advertisement' + + def __init__(self, bus, index, advertising_type, uuid, name): + self.path = self.PATH_BASE + str(index) + self.bus = bus + self.ad_type = advertising_type + self.service_uuids = [uuid] + self.local_name = dbus.String(name) + dbus.service.Object.__init__(self, bus, self.path) + + def __del__(self): + pass + + def get_properties(self): + properties = dict() + properties['Type'] = self.ad_type + + if self.service_uuids is not None: + properties['ServiceUUIDs'] = dbus.Array(self.service_uuids, + signature='s') + if self.local_name is not None: + properties['LocalName'] = dbus.String(self.local_name) + + return {LE_ADVERTISEMENT_IFACE: properties} + + def get_path(self): + return dbus.ObjectPath(self.path) + + @dbus.service.method(DBUS_PROP_IFACE, + in_signature='s', + out_signature='a{sv}') + def GetAll(self, interface): + global ADV_OBJ + if interface != LE_ADVERTISEMENT_IFACE: + raise InvalidArgsException() + ADV_OBJ = True + return self.get_properties()[LE_ADVERTISEMENT_IFACE] + + @dbus.service.method(LE_ADVERTISEMENT_IFACE, + in_signature='', + out_signature='') + def Release(self): + pass diff --git a/tools/ble/lib_gatt.py b/tools/ble/lib_gatt.py new file mode 100644 index 0000000000..c666d8e7e8 --- /dev/null +++ b/tools/ble/lib_gatt.py @@ -0,0 +1,412 @@ +#!/usr/bin/env python +# +# Copyright 2019 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. +# + +# Creating GATT Application which then becomes available to remote devices. + +from __future__ import print_function +import sys + +try: + import dbus + import dbus.service +except ImportError as e: + if 'linux' not in sys.platform: + sys.exit("Error: Only supported on Linux platform") + print(e) + print("Install packages `libgirepository1.0-dev gir1.2-gtk-3.0 libcairo2-dev libdbus-1-dev libdbus-glib-1-dev` for resolving the issue") + print("Run `pip install -r $IDF_PATH/tools/ble/requirements.txt` for resolving the issue") + raise + +alert_status_char_obj = None + +GATT_APP_OBJ = False +CHAR_READ = False +CHAR_WRITE = False +CHAR_SUBSCRIBE = False + +DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager' +DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties' +GATT_MANAGER_IFACE = 'org.bluez.GattManager1' +GATT_SERVICE_IFACE = 'org.bluez.GattService1' +GATT_CHRC_IFACE = 'org.bluez.GattCharacteristic1' +GATT_DESC_IFACE = 'org.bluez.GattDescriptor1' + + +class InvalidArgsException(dbus.exceptions.DBusException): + _dbus_error_name = 'org.freedesktop.DBus.Error.InvalidArgs' + + +class NotSupportedException(dbus.exceptions.DBusException): + _dbus_error_name = 'org.bluez.Error.NotSupported' + + +class Application(dbus.service.Object): + """ + org.bluez.GattApplication1 interface implementation + """ + + def __init__(self, bus, path): + self.path = path + self.services = [] + srv_obj = AlertNotificationService(bus, '0001') + self.add_service(srv_obj) + dbus.service.Object.__init__(self, bus, self.path) + + def __del__(self): + pass + + def get_path(self): + return dbus.ObjectPath(self.path) + + def add_service(self, service): + self.services.append(service) + + @dbus.service.method(DBUS_OM_IFACE, out_signature='a{oa{sa{sv}}}') + def GetManagedObjects(self): + global GATT_APP_OBJ + response = {} + + for service in self.services: + response[service.get_path()] = service.get_properties() + chrcs = service.get_characteristics() + for chrc in chrcs: + response[chrc.get_path()] = chrc.get_properties() + descs = chrc.get_descriptors() + for desc in descs: + response[desc.get_path()] = desc.get_properties() + + GATT_APP_OBJ = True + return response + + def Release(self): + pass + + +class Service(dbus.service.Object): + """ + org.bluez.GattService1 interface implementation + """ + PATH_BASE = '/org/bluez/hci0/service' + + def __init__(self, bus, index, uuid, primary=False): + self.path = self.PATH_BASE + str(index) + self.bus = bus + self.uuid = uuid + self.primary = primary + self.characteristics = [] + dbus.service.Object.__init__(self, bus, self.path) + + def get_properties(self): + return { + GATT_SERVICE_IFACE: { + 'UUID': self.uuid, + 'Primary': self.primary, + 'Characteristics': dbus.Array( + self.get_characteristic_paths(), + signature='o') + } + } + + def get_path(self): + return dbus.ObjectPath(self.path) + + def add_characteristic(self, characteristic): + self.characteristics.append(characteristic) + + def get_characteristic_paths(self): + result = [] + for chrc in self.characteristics: + result.append(chrc.get_path()) + return result + + def get_characteristics(self): + return self.characteristics + + @dbus.service.method(DBUS_PROP_IFACE, + in_signature='s', + out_signature='a{sv}') + def GetAll(self, interface): + if interface != GATT_SERVICE_IFACE: + raise InvalidArgsException() + return self.get_properties()[GATT_SERVICE_IFACE] + + +class Characteristic(dbus.service.Object): + """ + org.bluez.GattCharacteristic1 interface implementation + """ + def __init__(self, bus, index, uuid, flags, service): + self.path = service.path + '/char' + str(index) + self.bus = bus + self.uuid = uuid + self.service = service + self.flags = flags + self.value = [0] + self.descriptors = [] + dbus.service.Object.__init__(self, bus, self.path) + + def get_properties(self): + return { + GATT_CHRC_IFACE: { + 'Service': self.service.get_path(), + 'UUID': self.uuid, + 'Flags': self.flags, + 'Value': self.value, + 'Descriptors': dbus.Array(self.get_descriptor_paths(), signature='o') + + } + } + + def get_path(self): + return dbus.ObjectPath(self.path) + + def add_descriptor(self, descriptor): + self.descriptors.append(descriptor) + + def get_descriptor_paths(self): + result = [] + for desc in self.descriptors: + result.append(desc.get_path()) + return result + + def get_descriptors(self): + return self.descriptors + + @dbus.service.method(DBUS_PROP_IFACE, in_signature='s', out_signature='a{sv}') + def GetAll(self, interface): + if interface != GATT_CHRC_IFACE: + raise InvalidArgsException() + + return self.get_properties()[GATT_CHRC_IFACE] + + @dbus.service.method(GATT_CHRC_IFACE, in_signature='a{sv}', out_signature='ay') + def ReadValue(self, options): + print('\nDefault ReadValue called, returning error') + raise NotSupportedException() + + @dbus.service.method(GATT_CHRC_IFACE, in_signature='aya{sv}') + def WriteValue(self, value, options): + print('\nDefault WriteValue called, returning error') + raise NotSupportedException() + + @dbus.service.method(GATT_CHRC_IFACE) + def StartNotify(self): + print('Default StartNotify called, returning error') + raise NotSupportedException() + + @dbus.service.method(GATT_CHRC_IFACE) + def StopNotify(self): + print('Default StopNotify called, returning error') + raise NotSupportedException() + + @dbus.service.signal(DBUS_PROP_IFACE, + signature='sa{sv}as') + def PropertiesChanged(self, interface, changed, invalidated): + print("\nProperties Changed") + + +class Descriptor(dbus.service.Object): + """ + org.bluez.GattDescriptor1 interface implementation + """ + def __init__(self, bus, index, uuid, flags, characteristic): + self.path = characteristic.path + '/desc' + str(index) + self.bus = bus + self.uuid = uuid + self.flags = flags + self.chrc = characteristic + dbus.service.Object.__init__(self, bus, self.path) + + def get_properties(self): + return { + GATT_DESC_IFACE: { + 'Characteristic': self.chrc.get_path(), + 'UUID': self.uuid, + 'Flags': self.flags, + } + } + + def get_path(self): + return dbus.ObjectPath(self.path) + + @dbus.service.method(DBUS_PROP_IFACE, + in_signature='s', + out_signature='a{sv}') + def GetAll(self, interface): + if interface != GATT_DESC_IFACE: + raise InvalidArgsException() + + return self.get_properties()[GATT_DESC_IFACE] + + @dbus.service.method(GATT_DESC_IFACE, in_signature='a{sv}', out_signature='ay') + def ReadValue(self, options): + print('Default ReadValue called, returning error') + raise NotSupportedException() + + @dbus.service.method(GATT_DESC_IFACE, in_signature='aya{sv}') + def WriteValue(self, value, options): + print('Default WriteValue called, returning error') + raise NotSupportedException() + + +class AlertNotificationService(Service): + TEST_SVC_UUID = '00001811-0000-1000-8000-00805f9b34fb' + + def __init__(self, bus, index): + global alert_status_char_obj + Service.__init__(self, bus, index, self.TEST_SVC_UUID, primary=True) + self.add_characteristic(SupportedNewAlertCategoryCharacteristic(bus, '0001', self)) + self.add_characteristic(AlertNotificationControlPointCharacteristic(bus, '0002', self)) + alert_status_char_obj = UnreadAlertStatusCharacteristic(bus, '0003', self) + self.add_characteristic(alert_status_char_obj) + + +class SupportedNewAlertCategoryCharacteristic(Characteristic): + SUPPORT_NEW_ALERT_UUID = '00002A47-0000-1000-8000-00805f9b34fb' + + def __init__(self, bus, index, service): + Characteristic.__init__( + self, bus, index, + self.SUPPORT_NEW_ALERT_UUID, + ['read'], + service) + + self.value = [dbus.Byte(2)] + + def ReadValue(self, options): + global CHAR_READ + CHAR_READ = True + val_list = [] + for val in self.value: + val_list.append(dbus.Byte(val)) + print("Read Request received\n", "\tSupportedNewAlertCategoryCharacteristic") + print("\tValue:", "\t", val_list) + return val_list + + +class AlertNotificationControlPointCharacteristic(Characteristic): + ALERT_NOTIF_UUID = '00002A44-0000-1000-8000-00805f9b34fb' + + def __init__(self, bus, index, service): + Characteristic.__init__( + self, bus, index, + self.ALERT_NOTIF_UUID, + ['read','write'], + service) + + self.value = [dbus.Byte(0)] + + def ReadValue(self, options): + val_list = [] + for val in self.value: + val_list.append(dbus.Byte(val)) + print("Read Request received\n", "\tAlertNotificationControlPointCharacteristic") + print("\tValue:", "\t", val_list) + return val_list + + def WriteValue(self, value, options): + global CHAR_WRITE + CHAR_WRITE = True + print("Write Request received\n", "\tAlertNotificationControlPointCharacteristic") + print("\tCurrent value:", "\t", self.value) + val_list = [] + for val in value: + val_list.append(val) + self.value = val_list + # Check if new value is written + print("\tNew value:", "\t", self.value) + if not self.value == value: + print("Failed: Write Request\n\tNew value not written\tCurrent value:", self.value) + + +class UnreadAlertStatusCharacteristic(Characteristic): + UNREAD_ALERT_STATUS_UUID = '00002A45-0000-1000-8000-00805f9b34fb' + + def __init__(self, bus, index, service): + Characteristic.__init__( + self, bus, index, + self.UNREAD_ALERT_STATUS_UUID, + ['read', 'write', 'notify'], + service) + self.value = [dbus.Byte(0)] + self.cccd_obj = ClientCharacteristicConfigurationDescriptor(bus, '0001', self) + self.add_descriptor(self.cccd_obj) + self.notifying = False + + def StartNotify(self): + global CHAR_SUBSCRIBE + CHAR_SUBSCRIBE = True + + if self.notifying: + print('\nAlready notifying, nothing to do') + return + self.notifying = True + print("\nNotify Started") + self.cccd_obj.WriteValue([dbus.Byte(1), dbus.Byte(0)]) + self.cccd_obj.ReadValue() + + def StopNotify(self): + if not self.notifying: + print('\nNot notifying, nothing to do') + return + self.notifying = False + print("\nNotify Stopped") + + def ReadValue(self, options): + print("Read Request received\n", "\tUnreadAlertStatusCharacteristic") + val_list = [] + for val in self.value: + val_list.append(dbus.Byte(val)) + print("\tValue:", "\t", val_list) + return val_list + + def WriteValue(self, value, options): + print("Write Request received\n", "\tUnreadAlertStatusCharacteristic") + val_list = [] + for val in value: + val_list.append(val) + self.value = val_list + # Check if new value is written + print("\tNew value:", "\t", self.value) + if not self.value == value: + print("Failed: Write Request\n\tNew value not written\tCurrent value:", self.value) + + +class ClientCharacteristicConfigurationDescriptor(Descriptor): + CCCD_UUID = '00002902-0000-1000-8000-00805f9b34fb' + + def __init__(self, bus, index, characteristic): + self.value = [dbus.Byte(0)] + Descriptor.__init__( + self, bus, index, + self.CCCD_UUID, + ['read', 'write'], + characteristic) + + def ReadValue(self): + print("\tValue on read:", "\t", self.value) + return self.value + + def WriteValue(self, value): + val_list = [] + for val in value: + val_list.append(val) + self.value = val_list + # Check if new value is written + print("New value on write:", "\t", self.value) + if not self.value == value: + print("Failed: Write Request\n\tNew value not written\tCurrent value:", self.value) diff --git a/tools/ble/requirements.txt b/tools/ble/requirements.txt new file mode 100644 index 0000000000..8049fd2f9b --- /dev/null +++ b/tools/ble/requirements.txt @@ -0,0 +1,3 @@ +future +dbus-python +pygobject From 84b2fa4c1cdc3725084a98003d8b640fa0242c37 Mon Sep 17 00:00:00 2001 From: Shivani Tipnis Date: Fri, 28 Jun 2019 11:36:23 +0530 Subject: [PATCH 253/486] nvs_util: Add check for key len in input csv file Closes https://github.com/espressif/esp-idf/issues/3113 --- .../nvs_flash/nvs_partition_generator/nvs_partition_gen.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py b/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py index 68bf657e37..3bc10e8c3f 100755 --- a/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py +++ b/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py @@ -903,6 +903,9 @@ def generate(args, is_encr_enabled=False, encr_key=None): print("\nCreating NVS binary with version:", version_set) for row in reader: try: + # Check key length + if len(row["key"]) > 15: + raise InputError("Length of key `%s` should be <= 15 characters." % row["key"]) write_entry(nvs_obj, row["key"], row["type"], row["encoding"], row["value"]) except InputError as e: print(e) From cc75721f9c080e104d4af811b4ef997936b3d649 Mon Sep 17 00:00:00 2001 From: Shivani Tipnis Date: Thu, 20 Jun 2019 18:47:59 +0530 Subject: [PATCH 254/486] mfg_util: Optimise by adding subparser changes w.r.t similar changes in nvs util changes --- .../nvs_flash/test_nvs_host/test_nvs.cpp | 77 +--- tools/mass_mfg/docs/README.rst | 143 +++--- tools/mass_mfg/mfg_gen.py | 413 ++++++++---------- 3 files changed, 306 insertions(+), 327 deletions(-) diff --git a/components/nvs_flash/test_nvs_host/test_nvs.cpp b/components/nvs_flash/test_nvs_host/test_nvs.cpp index 8326235ab4..f78440a0de 100644 --- a/components/nvs_flash/test_nvs_host/test_nvs.cpp +++ b/components/nvs_flash/test_nvs_host/test_nvs.cpp @@ -2462,7 +2462,6 @@ TEST_CASE("check and read data from partition generated via partition generation } } -#if false TEST_CASE("check and read data from partition generated via manufacturing utility with multipage blob support disabled", "[mfg_gen]") { int childpid = fork(); @@ -2484,18 +2483,15 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit if (childpid == 0) { exit(execlp("python", "python", "../../../tools/mass_mfg/mfg_gen.py", - "--conf", + "generate", "../../../tools/mass_mfg/samples/sample_config.csv", - "--values", "../../../tools/mass_mfg/samples/sample_values_singlepage_blob.csv", - "--prefix", "Test", - "--size", "0x3000", "--outdir", "../../../tools/mass_mfg/host_test", "--version", - "v1",NULL)); + "1",NULL)); } else { CHECK(childpid > 0); @@ -2506,14 +2502,12 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit if (childpid == 0) { exit(execlp("python", "python", "../nvs_partition_generator/nvs_partition_gen.py", - "--input", + "generate", "../../../tools/mass_mfg/host_test/csv/Test-1.csv", - "--output", "../nvs_partition_generator/Test-1-partition.bin", - "--size", "0x3000", "--version", - "v1",NULL)); + "1",NULL)); } else { CHECK(childpid > 0); @@ -2570,18 +2564,15 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit if (childpid == 0) { exit(execlp("python", "python", "../../../tools/mass_mfg/mfg_gen.py", - "--conf", + "generate", "../../../tools/mass_mfg/samples/sample_config.csv", - "--values", "../../../tools/mass_mfg/samples/sample_values_multipage_blob.csv", - "--prefix", "Test", - "--size", "0x4000", "--outdir", "../../../tools/mass_mfg/host_test", "--version", - "v2",NULL)); + "2",NULL)); } else { CHECK(childpid > 0); @@ -2592,14 +2583,12 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit if (childpid == 0) { exit(execlp("python", "python", "../nvs_partition_generator/nvs_partition_gen.py", - "--input", + "generate", "../../../tools/mass_mfg/host_test/csv/Test-1.csv", - "--output", "../nvs_partition_generator/Test-1-partition.bin", - "--size", "0x4000", "--version", - "v2",NULL)); + "2",NULL)); } else { CHECK(childpid > 0); @@ -2633,7 +2622,6 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit } } -#endif #if CONFIG_NVS_ENCRYPTION TEST_CASE("check underlying xts code for 32-byte size sector encryption", "[nvs]") @@ -3015,8 +3003,7 @@ TEST_CASE("test nvs apis for nvs partition generator utility with encryption ena } -#if false -TEST_CASE("check and read data from partition generated via manufacturing utility with encryption enabled using sample keyfile", "[mfg_gen]") +TEST_CASE("check and read data from partition generated via manufacturing utility with encryption enabled using sample inputkey", "[mfg_gen]") { int childpid = fork(); int status; @@ -3037,21 +3024,16 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit if (childpid == 0) { exit(execlp("python", "python", "../../../tools/mass_mfg/mfg_gen.py", - "--conf", + "generate", "../../../tools/mass_mfg/samples/sample_config.csv", - "--values", "../../../tools/mass_mfg/samples/sample_values_multipage_blob.csv", - "--prefix", "Test", - "--size", "0x4000", "--outdir", "../../../tools/mass_mfg/host_test", "--version", - "v2", - "--encrypt", - "true", - "--keyfile", + "2", + "--inputkey", "mfg_testdata/sample_encryption_keys.bin",NULL)); } else { @@ -3063,17 +3045,13 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit if (childpid == 0) { exit(execlp("python", "python", "../nvs_partition_generator/nvs_partition_gen.py", - "--input", + "encrypt", "../../../tools/mass_mfg/host_test/csv/Test-1.csv", - "--output", "../nvs_partition_generator/Test-1-partition-encrypted.bin", - "--size", "0x4000", "--version", - "v2", - "--encrypt", - "true", - "--keyfile", + "2", + "--inputkey", "testdata/sample_encryption_keys.bin",NULL)); } else { @@ -3143,8 +3121,7 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit if (childpid == 0) { exit(execlp("python", "python", "../../../tools/mass_mfg/mfg_gen.py", - "--keygen", - "true", + "generate-key", "--outdir", "../../../tools/mass_mfg/host_test", "--keyfile", @@ -3159,21 +3136,16 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit if (childpid == 0) { exit(execlp("python", "python", "../../../tools/mass_mfg/mfg_gen.py", - "--conf", + "generate", "../../../tools/mass_mfg/samples/sample_config.csv", - "--values", "../../../tools/mass_mfg/samples/sample_values_multipage_blob.csv", - "--prefix", "Test", - "--size", "0x4000", "--outdir", "../../../tools/mass_mfg/host_test", "--version", - "v2", - "--encrypt", - "true", - "--keyfile", + "2", + "--inputkey", "../../../tools/mass_mfg/host_test/keys/encr_keys_host_test.bin",NULL)); } else { @@ -3185,17 +3157,13 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit if (childpid == 0) { exit(execlp("python", "python", "../nvs_partition_generator/nvs_partition_gen.py", - "--input", + "encrypt", "../../../tools/mass_mfg/host_test/csv/Test-1.csv", - "--output", "../nvs_partition_generator/Test-1-partition-encrypted.bin", - "--size", "0x4000", "--version", - "v2", - "--encrypt", - "true", - "--keyfile", + "2", + "--inputkey", "../../../tools/mass_mfg/host_test/keys/encr_keys_host_test.bin",NULL)); } else { @@ -3256,7 +3224,6 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit } #endif -#endif /* Add new tests above */ /* This test has to be the final one */ diff --git a/tools/mass_mfg/docs/README.rst b/tools/mass_mfg/docs/README.rst index ce614f77ef..e38b1f1ece 100644 --- a/tools/mass_mfg/docs/README.rst +++ b/tools/mass_mfg/docs/README.rst @@ -127,75 +127,117 @@ An instance of an intermediate CSV file will be created for each device on an in Running the utility ------------------- -The mfg\_gen.py utility uses the generated CSV Configuration file and the master value CSV file to generate factory images for each device. - -*A sample CSV Configuration file and a master value CSV file are both provided with this utility.* - **Usage**:: - - ./mfg_gen.py [-h] [--conf CONFIG_FILE] [--values VALUES_FILE] - [--prefix PREFIX] [--fileid FILEID] [--outdir OUTDIR] - [--size PART_SIZE] [--version {v1,v2}] - [--keygen {true,false}] [--encrypt {true,false}] - [--keyfile KEYFILE] -The description of the arguments is given in the table below. + python mfg_gen.py [-h] {generate,generate-key} ... -+------------------------+------------------------------------------------------------+-------------------+ -| Arguments | Description | Default Value | -+========================+============================================================+===================+ -| --conf CONFIG_FILE | Path to existing CSV configuration file | | -+------------------------+------------------------------------------------------------+-------------------+ -| --values VALUES_FILE | Path to existing master value CSV file | | -+------------------------+------------------------------------------------------------+-------------------+ -| --prefix PREFIX | Unique filename prefix | | -+------------------------+------------------------------------------------------------+-------------------+ -| --fileid FILEID | Unique file identifier (any key in the file with values) | numeric value | -| | as a filename suffix | (1,2,3...) | -+------------------------+------------------------------------------------------------+-------------------+ -| --outdir OUTDIR | Output directory to store created files | current directory | -+------------------------+------------------------------------------------------------+-------------------+ -| --size PART_SIZE | Size of NVS Partition in bytes (must be multiple of 4096) | | -+------------------------+------------------------------------------------------------+-------------------+ -| --version {v1,v2} | Set version | v2 | -+------------------------+------------------------------------------------------------+-------------------+ -| --keygen {true,false} | Generate keys for encryption | false | -+------------------------+------------------------------------------------------------+-------------------+ -| --encrypt {true,false} | Set encryption mode | false | -+------------------------+------------------------------------------------------------+-------------------+ -| --keyfile KEYFILE | File storing key for encryption (Applicable only if | | -| | Encryption mode is true). | | -+------------------------+------------------------------------------------------------+-------------------+ + Optional Arguments: + +-----+------------+----------------------------------------------------------------------+ + | No. | Parameter | Description | + +=====+============+======================================================================+ + | 1 | -h, --help | show this help message and exit | + +-----+------------+----------------------------------------------------------------------+ -*To run this utility with the provided sample files, use the commands below*:: + Commands: + Run mfg_gen.py {command} -h for additional help + +-----+--------------+--------------------------------------------------------------------+ + | No. | Parameter | Description | + +=====+==============+====================================================================+ + | 1 | generate | Generate NVS partition | + +-----+--------------+--------------------------------------------------------------------+ + | 2 | generate-key | Generate keys for encryption | + +-----+--------------+--------------------------------------------------------------------+ - ./mfg_gen.py --conf samples/sample_config.csv --values samples/sample_values_singlepage_blob.csv --prefix Fan --size 0x3000 +**To generate factory images for each device (Default):** + **Usage**:: - ./mfg_gen.py --conf samples/sample_config.csv --values samples/sample_values_multipage_blob.csv --prefix Fan --size 0x4000 + python mfg_gen.py generate [-h] [--fileid FILEID] [--version {1,2}] [--keygen] + [--keyfile KEYFILE] [--inputkey INPUTKEY] + [--outdir OUTDIR] + conf values prefix size + + Positional Arguments: + +--------------+----------------------------------------------------------------------+ + | Parameter | Description | + +==============+======================================================================+ + | conf | Path to configuration csv file to parse | + +--------------+----------------------------------------------------------------------+ + | values | Path to values csv file to parse | + +--------------+----------------------------------------------------------------------+ + | prefix | Unique name for each output filename prefix | + +-----+--------------+----------------------------------------------------------------+ + | size | Size of NVS partition in bytes | + | | (must be multiple of 4096) | + +--------------+----------------------------------------------------------------------+ -When you use this utility to generate factory images on a per device basis, keep in mind that the arguments --conf, --values, --prefix, and --size are mandatory. + Optional Arguments: + +---------------------+--------------------------------------------------------------------+ + | Parameter | Description | + +=====================+====================================================================+ + | -h, --help | show this help message and exit | + +---------------------+--------------------------------------------------------------------+ + | --fileid FILEID | Unique file identifier(any key in values file) | + | | for each filename suffix (Default: numeric value(1,2,3...) | + +---------------------+--------------------------------------------------------------------+ + | --version {1,2} | Set multipage blob version. | + | | Version 1 - Multipage blob support disabled. | + | | Version 2 - Multipage blob support enabled. | + | | Default: Version 2 | + +---------------------+--------------------------------------------------------------------+ + | --keygen | Generates key for encrypting NVS partition | + +---------------------+--------------------------------------------------------------------+ + | --inputkey INPUTKEY | File having key for encrypting NVS partition | + +---------------------+--------------------------------------------------------------------+ + | --outdir OUTDIR | Output directory to store files created | + | | (Default: current directory) | + +---------------------+--------------------------------------------------------------------+ - ./mfg_gen.py --conf samples/sample_config.csv --values samples/sample_values_singlepage_blob.csv --prefix Fan --size 0x3000 --outdir tmp +You can run the utility to generate factory images for each device using the command below. A sample CSV file is provided with the utility:: -.. note:: If the --outdir directory does not exist, it will be created. + python mfg_gen.py generate samples/sample_config.csmples/sample_values_singlepage_blob.csv Sample 0x3000 The master value CSV file should have the path in the ``file`` type relative to the directory from which you are running the utility. - ./mfg_gen.py --conf samples/sample_config.csv --values samples/sample_values_singlepage_blob.csv --prefix Fan --size 0x3000 --encrypt true --keygen true +**To generate encrypted factory images for each device:** -.. note:: The generated ``keys/`` directory is named as the file with encryption keys of the form ``prefix-fileid-keys.bin``. +You can run the utility to encrypt factory images for each device using the command below. A sample CSV file is provided with the utility: -*If you* **only** *want to generate a binary file with encryption keys, you can run the command below.*:: +- Encrypt by allowing the utility to generate encryption keys:: - ./mfg_gen.py --keygen true + python mfg_gen.py generate samples/sample_config.csv samples/sample_values_singlepage_blob.csv Sample 0x3000 --keygen -.. note:: When you use this utility to generate encryption keys only, the --keygen argument is mandatory. +.. note:: Encryption key of the following format ``/keys/keys--.bin`` is created. +.. note:: This newly created file having encryption keys in ``keys/`` directory is compatible with NVS key-partition structure. Refer to :ref:`nvs_key_partition` for more details. -In the following example, the 'keys/' directory will be created at the current path. This binary file can further be used to encrypt factory images created on the per device basis*.:: +- Encrypt by providing the encryption keys as input binary file:: - ./mfg_gen.py --keygen true --keyfile encr_keys.bin + python mfg_gen.py generate samples/sample_config.csv samples/sample_values_singlepage_blob.csv Sample 0x3000 --inputkey keys/sample_keys.bin -.. note:: When running the utility to generate encryption keys only, if --keyfile is given, it will generate encryption keys with the filename given in the --keyfile argument. +**To generate only encryption keys:** + **Usage**:: + + python mfg_gen.py generate-key [-h] [--keyfile KEYFILE] [--outdir OUTDIR] + + Optional Arguments: + +--------------------+----------------------------------------------------------------------+ + | Parameter | Description | + +====================+======================================================================+ + | -h, --help | show this help message and exit | + +--------------------+----------------------------------------------------------------------+ + | --keyfile KEYFILE | Path to output encryption keys file | + +--------------------+----------------------------------------------------------------------+ + | --outdir OUTDIR | Output directory to store files created. | + | | (Default: current directory) | + +--------------------+----------------------------------------------------------------------+ + +You can run the utility to generate only encryption keys using the command below:: + + python mfg_gen.py generate-key + +.. note:: Encryption key of the following format ``/keys/keys-.bin`` is created. Timestamp format is: ``%m-%d_%H-%M``. +.. note:: To provide custom target filename use the --keyfile argument. + +Generated encryption key binary file can further be used to encrypt factory images created on the per device basis. The default numeric value: 1,2,3... of the ``fileid`` argument corresponds to each line bearing device instance values in the master value CSV file. @@ -203,3 +245,4 @@ While running the manufacturing utility, the following folders will be created i - ``bin/`` for storing the generated binary files - ``csv/`` for storing the generated intermediate CSV files +- ``keys/`` for storing encryption keys (when generating encrypted factory images) diff --git a/tools/mass_mfg/mfg_gen.py b/tools/mass_mfg/mfg_gen.py index 9a1df1a465..7843c5cdbf 100755 --- a/tools/mass_mfg/mfg_gen.py +++ b/tools/mass_mfg/mfg_gen.py @@ -45,7 +45,7 @@ def verify_values_exist(input_values_file, keys_in_values_file): for values_data in values_file_reader: line_no += 1 if len(values_data) != key_count_in_values_file: - raise SystemExit("\nOops...Number of values is not equal to number of keys in file: %s at line No:%s\n" + raise SystemExit("\nError: Number of values is not equal to number of keys in file: %s at line No:%s\n" % (str(input_values_file), str(line_no))) @@ -88,11 +88,11 @@ def verify_datatype_encoding(input_config_file): for config_data in config_file_reader: line_no += 1 if config_data[1] not in valid_datatypes: - raise SystemExit("Oops...config file: %s has invalid datatype at line no:%s\n`" + raise SystemExit("Error: config file: %s has invalid datatype at line no:%s\n`" % (str(input_config_file), str(line_no))) if 'namespace' not in config_data: if config_data[2] not in valid_encodings: - raise SystemExit("Oops...config file: %s has invalid encoding at line no:%s\n`" + raise SystemExit("Error: config file: %s has invalid encoding at line no:%s\n`" % (str(input_config_file), str(line_no))) @@ -106,7 +106,7 @@ def verify_file_data_count(input_config_file, keys_repeat): for line in config_file_reader: line_no += 1 if len(line) != 3 and line[0] not in keys_repeat: - raise SystemExit("Oops...data missing in config file at line no:%s \n" + raise SystemExit("Error: data missing in config file at line no:%s \n" % str(line_no)) config_file.close() @@ -134,7 +134,7 @@ def verify_data_in_file(input_config_file, input_values_file, config_file_keys, except Exception as err: print(err) - raise + exit(1) def get_keys(keys_in_values_file, config_file_keys): @@ -226,14 +226,13 @@ def add_data_to_file(config_data_to_write, key_value_pair, output_csv_file): # Set index to start of file target_csv_file.seek(0) - target_csv_file.close() def create_dir(filetype, output_dir_path): """ Create new directory(if doesn't exist) to store file generated """ - output_target_dir = output_dir_path + filetype + output_target_dir = os.path.join(output_dir_path,filetype,'') if not os.path.isdir(output_target_dir): distutils.dir_util.mkpath(output_target_dir) @@ -272,152 +271,116 @@ def set_repeat_value(total_keys_repeat, keys, csv_file, target_filename): return target_filename -def main(input_config_file=None,input_values_file=None,target_file_name_prefix=None, - file_identifier=None,output_dir_path=None,part_size=None,input_version=None, - input_is_keygen=None,input_is_encrypt=None,input_is_keyfile=None): +def create_intermediate_csv(args, keys_in_config_file, keys_in_values_file, keys_repeat, is_encr=False): + file_identifier_value = '0' + csv_str = 'csv' + bin_str = 'bin' + set_output_keyfile = False + + # Add config data per namespace to `config_data_to_write` list + config_data_to_write = add_config_data_per_namespace(args.conf) + try: - if all(arg is None for arg in [input_config_file,input_values_file,target_file_name_prefix, - file_identifier,output_dir_path]): - parser = argparse.ArgumentParser(prog='./mfg_gen.py', - description="Create binary files from input config and values file", - formatter_class=argparse.RawDescriptionHelpFormatter) + with open(args.values, 'r') as csv_values_file: + values_file_reader = csv.reader(csv_values_file, delimiter=',') + keys = next(values_file_reader) - parser.add_argument('--conf', - dest='config_file', - help='the input configuration csv file', - default=None) + filename, file_ext = os.path.splitext(args.values) + target_filename = filename + "_created" + file_ext + if keys_repeat: + target_values_file = set_repeat_value(keys_repeat, keys, args.values, target_filename) + else: + target_values_file = args.values - parser.add_argument('--values', - dest='values_file', - help='the input values csv file', - default=None) + csv_values_file = open(target_values_file, 'r') - parser.add_argument('--prefix', - dest='prefix', - help='the unique name as each filename prefix') + values_file_reader = csv.reader(csv_values_file, delimiter=',') + next(values_file_reader) - parser.add_argument('--fileid', - dest='fileid', - help='the unique file identifier(any key in values file) \ - as each filename suffix (Default: numeric value(1,2,3...)') + # Create new directory(if doesn't exist) to store csv file generated + output_csv_target_dir = create_dir(csv_str, args.outdir) + # Create new directory(if doesn't exist) to store bin file generated + output_bin_target_dir = create_dir(bin_str, args.outdir) + if args.keygen: + set_output_keyfile = True - parser.add_argument('--outdir', - dest='outdir', - default=os.getcwd(), - help='the output directory to store the files created\ - (Default: current directory)') + for values_data_line in values_file_reader: + key_value_data = list(zip_longest(keys_in_values_file, values_data_line)) - parser.add_argument("--size", - dest='part_size', - help='Size of NVS Partition in bytes (must be multiple of 4096)') + # Get file identifier value from values file + file_identifier_value = get_fileid_val(args.fileid, keys_in_config_file, + keys_in_values_file, values_data_line, key_value_data, + file_identifier_value) - parser.add_argument("--version", - dest="version", - help='Set version. Default: v2', - choices=['v1','v2'], - default='v2', - type=str.lower) + key_value_pair = key_value_data[:] - parser.add_argument("--keygen", - dest="keygen", - help='Generate keys for encryption. Default: false', - choices=['true','false'], - default='false', - type=str.lower) + # Verify if output csv file does not exist + csv_filename = args.prefix + "-" + file_identifier_value + "." + csv_str + output_csv_file = output_csv_target_dir + csv_filename + if os.path.isfile(output_csv_file): + raise SystemExit("Target csv file: %s already exists.`" % output_csv_file) - parser.add_argument("--encrypt", - dest="encrypt", - help='Set encryption mode. Default: false', - choices=['true','false'], - default='false', - type=str.lower) + # Add values corresponding to each key to csv intermediate file + add_data_to_file(config_data_to_write, key_value_pair, output_csv_file) + print("\nCreated CSV file: ===>", output_csv_file) - parser.add_argument("--keyfile", - dest="keyfile", - help='File having key for encryption (Applicable only if encryption mode is true)', - default=None) + # Verify if output bin file does not exist + bin_filename = args.prefix + "-" + file_identifier_value + "." + bin_str + output_bin_file = output_bin_target_dir + bin_filename + if os.path.isfile(output_bin_file): + raise SystemExit("Target binary file: %s already exists.`" % output_bin_file) - args = parser.parse_args() + args.input = output_csv_file + args.output = os.path.join(bin_str, bin_filename) + if set_output_keyfile: + args.keyfile = "keys-" + args.prefix + "-" + file_identifier_value - args.outdir = os.path.join(args.outdir, '') + if is_encr: + nvs_partition_gen.encrypt(args) + else: + nvs_partition_gen.generate(args) - input_config_file = args.config_file - input_values_file = args.values_file - target_file_name_prefix = args.prefix - output_dir_path = args.outdir - part_size = args.part_size - input_version = args.version - input_is_keygen = args.keygen - input_is_encrypt = args.encrypt - input_is_keyfile = args.keyfile - file_identifier = '' - print_arg_str = "Invalid.\nTo generate binary --conf, --values, --prefix and --size arguments are mandatory.\ - \nTo generate encryption keys --keygen argument is mandatory." - print_encrypt_arg_str = "Missing parameter. Enter --keygen or --keyfile." + print("\nFiles generated in %s ..." % args.outdir) - if args.fileid: - file_identifier = args.fileid + except Exception as e: + print(e) + exit(1) + finally: + csv_values_file.close() - if input_config_file and input_is_encrypt.lower() == 'true' and input_is_keygen.lower() == 'true' and input_is_keyfile: - sys.exit('Invalid. Cannot provide both --keygen and --keyfile argument together.') - nvs_partition_gen.check_input_args(input_config_file, input_values_file, part_size, input_is_keygen, - input_is_encrypt, input_is_keyfile, input_version, print_arg_str, - print_encrypt_arg_str, output_dir_path) +def verify_empty_lines_exist(args, input_file): + input_file_reader = csv.reader(input_file, delimiter=',') + for file_data in input_file_reader: + for data in file_data: + if len(data.strip()) == 0: + raise SystemExit("Error: config file: %s cannot have empty lines. " % args.conf) + else: + break + if not file_data: + raise SystemExit("Error: config file: %s cannot have empty lines." % args.conf) - if not input_config_file and input_is_keygen: - if input_is_encrypt == 'true': - sys.exit("Invalid.\nOnly --keyfile and --outdir arguments allowed.\n") - # Generate Key Only - nvs_partition_gen.nvs_part_gen(input_filename=input_config_file, output_filename=input_values_file, - input_part_size=part_size, is_key_gen=input_is_keygen, - encrypt_mode=input_is_encrypt, key_file=input_is_keyfile, - version_no=input_version, output_dir=output_dir_path) - exit(0) + input_file.seek(0) + return input_file_reader - if not (input_config_file and input_values_file and target_file_name_prefix and part_size): - sys.exit(print_arg_str) - keys_in_values_file = [] - keys_in_config_file = [] - config_data_to_write = [] - key_value_data = [] - csv_file_list = [] - keys_repeat = [] - is_empty_line = False - files_created = False - file_identifier_value = '0' - output_target_dir = '' - target_values_file = None - output_file_prefix = None +def verify_file_format(args): + keys_in_config_file = [] + keys_in_values_file = [] + keys_repeat = [] - # Verify config file is not empty - if os.stat(input_config_file).st_size == 0: - raise SystemExit("Oops...config file: %s is empty." % input_config_file) + # Verify config file is not empty + if os.stat(args.conf).st_size == 0: + raise SystemExit("Error: config file: %s is empty." % args.conf) - # Verify values file is not empty - if os.stat(input_values_file).st_size == 0: - raise SystemExit("Oops...values file: %s is empty." % input_values_file) + # Verify values file is not empty + if os.stat(args.values).st_size == 0: + raise SystemExit("Error: values file: %s is empty." % args.values) - # Verify config file does not have empty lines - csv_config_file = open(input_config_file,'r') + # Verify config file does not have empty lines + with open(args.conf, 'r') as csv_config_file: try: - config_file_reader = csv.reader(csv_config_file, delimiter=',') - for config_data in config_file_reader: - for data in config_data: - empty_line = data.strip() - if empty_line is '': - is_empty_line = True - else: - is_empty_line = False - break - if is_empty_line: - raise SystemExit("Oops...config file: %s cannot have empty lines. " % input_config_file) - if not config_data: - raise SystemExit("Oops...config file: %s cannot have empty lines." % input_config_file) - - csv_config_file.seek(0) - + config_file_reader = verify_empty_lines_exist(args, csv_config_file) # Extract keys from config file for config_data in config_file_reader: if 'namespace' not in config_data: @@ -425,124 +388,130 @@ def main(input_config_file=None,input_values_file=None,target_file_name_prefix=N if 'REPEAT' in config_data: keys_repeat.append(config_data[0]) - csv_config_file.close() except Exception as e: print(e) - finally: - csv_config_file.close() - is_empty_line = False - # Verify values file does not have empty lines - csv_values_file = open(input_values_file, 'r') + # Verify values file does not have empty lines + with open(args.values, 'r') as csv_values_file: try: - values_file_reader = csv.reader(csv_values_file, delimiter=',') - for values_data in values_file_reader: - for data in values_data: - empty_line = data.strip() - if empty_line is '': - is_empty_line = True - else: - is_empty_line = False - break - if is_empty_line: - raise SystemExit("Oops...values file: %s cannot have empty lines." % input_values_file) - if not values_data: - raise SystemExit("Oops...values file: %s cannot have empty lines." % input_values_file) - - csv_values_file.seek(0) - + values_file_reader = verify_empty_lines_exist(args, csv_values_file) # Extract keys from values file keys_in_values_file = next(values_file_reader) - csv_values_file.close() except Exception as e: print(e) - exit(1) - finally: - csv_values_file.close() - # Verify file identifier exists in values file - if file_identifier: - if file_identifier not in keys_in_values_file: - raise SystemExit('Oops...target_file_identifier: %s does not exist in values file.\n' % file_identifier) + # Verify file identifier exists in values file + if args.fileid: + if args.fileid not in keys_in_values_file: + raise SystemExit('Error: target_file_identifier: %s does not exist in values file.\n' % args.fileid) + else: + args.fileid = 1 - # Verify data in the input_config_file and input_values_file - verify_data_in_file(input_config_file, input_values_file, keys_in_config_file, - keys_in_values_file, keys_repeat) + return keys_in_config_file, keys_in_values_file, keys_repeat - # Add config data per namespace to `config_data_to_write` list - config_data_to_write = add_config_data_per_namespace(input_config_file) - try: - with open(input_values_file, 'r') as csv_values_file: - values_file_reader = csv.reader(csv_values_file, delimiter=',') - keys = next(values_file_reader) +def generate(args): + keys_in_config_file = [] + keys_in_values_file = [] + keys_repeat = [] + encryption_enabled = False - filename, file_ext = os.path.splitext(input_values_file) - target_filename = filename + "_created" + file_ext - if keys_repeat: - target_values_file = set_repeat_value(keys_repeat, keys, input_values_file, target_filename) - else: - target_values_file = input_values_file + args.outdir = os.path.join(args.outdir, '') + # Verify input config and values file format + keys_in_config_file, keys_in_values_file, keys_repeat = verify_file_format(args) - csv_values_file = open(target_values_file, 'r') + # Verify data in the input_config_file and input_values_file + verify_data_in_file(args.conf, args.values, keys_in_config_file, + keys_in_values_file, keys_repeat) - values_file_reader = csv.reader(csv_values_file, delimiter=',') - next(values_file_reader) - for values_data_line in values_file_reader: - key_value_data = list(zip_longest(keys_in_values_file,values_data_line)) + if (args.keygen or args.inputkey): + encryption_enabled = True + print("\nGenerating encrypted NVS binary images...") + # Create intermediate csv file + create_intermediate_csv(args, keys_in_config_file, keys_in_values_file, + keys_repeat, is_encr=encryption_enabled) - # Get file identifier value from values file - file_identifier_value = get_fileid_val(file_identifier, keys_in_config_file, - keys_in_values_file, values_data_line, key_value_data, file_identifier_value) - key_value_pair = key_value_data[:] +def generate_key(args): + nvs_partition_gen.generate_key(args) - # Create new directory(if doesn't exist) to store csv file generated - output_target_dir = create_dir("csv/", output_dir_path) - # Verify if output csv file does not exist - csv_filename = target_file_name_prefix + "-" + file_identifier_value + ".csv" - csv_file_list.append(csv_filename) - output_csv_file = output_target_dir + csv_filename - if os.path.isfile(output_csv_file): - raise SystemExit("Target csv file: %s already exists.`" % output_csv_file) +def main(): + try: + parser = argparse.ArgumentParser(description="\nESP Manufacturing Utility", formatter_class=argparse.RawTextHelpFormatter) + subparser = parser.add_subparsers(title='Commands', + dest='command', + help='\nRun mfg_gen.py {command} -h for additional help\n\n') - # Add values corresponding to each key to csv target file - add_data_to_file(config_data_to_write, key_value_pair, output_csv_file) + parser_gen = subparser.add_parser('generate', + help='Generate NVS partition', + formatter_class=argparse.RawTextHelpFormatter) + parser_gen.set_defaults(func=generate) + parser_gen.add_argument('conf', + default=None, + help='Path to configuration csv file to parse') + parser_gen.add_argument('values', + default=None, + help='Path to values csv file to parse') + parser_gen.add_argument('prefix', + default=None, + help='Unique name for each output filename prefix') + parser_gen.add_argument('size', + default=None, + help='Size of NVS partition in bytes\ + \n(must be multiple of 4096)') + parser_gen.add_argument('--fileid', + default=None, + help='''Unique file identifier(any key in values file) \ + \nfor each filename suffix (Default: numeric value(1,2,3...)''') + parser_gen.add_argument('--version', + choices=[1, 2], + default=2, + type=int, + help='''Set multipage blob version.\ + \nVersion 1 - Multipage blob support disabled.\ + \nVersion 2 - Multipage blob support enabled.\ + \nDefault: Version 2 ''') + parser_gen.add_argument('--keygen', + action="store_true", + default=False, + help='Generates key for encrypting NVS partition') + parser_gen.add_argument('--keyfile', + default=None, + help=argparse.SUPPRESS) + parser_gen.add_argument('--inputkey', + default=None, + help='File having key for encrypting NVS partition') + parser_gen.add_argument('--outdir', + default=os.getcwd(), + help='Output directory to store files created\ + \n(Default: current directory)') + parser_gen.add_argument('--input', + default=None, + help=argparse.SUPPRESS) + parser_gen.add_argument('--output', + default=None, + help=argparse.SUPPRESS) + parser_gen_key = subparser.add_parser('generate-key', + help='Generate keys for encryption', + formatter_class=argparse.RawTextHelpFormatter) + parser_gen_key.set_defaults(func=generate_key) + parser_gen_key.add_argument('--keyfile', + default=None, + help='Path to output encryption keys file') + parser_gen_key.add_argument('--outdir', + default=os.getcwd(), + help='Output directory to store files created.\ + \n(Default: current directory)') - # Create new directory(if doesn't exist) to store bin file generated - output_target_dir = create_dir("bin/", output_dir_path) - - # Verify if output bin file does not exist - output_file_prefix = target_file_name_prefix + "-" + file_identifier_value - output_bin_file = output_target_dir + output_file_prefix + ".bin" - if os.path.isfile(output_bin_file): - raise SystemExit("Target csv file: %s already exists.`" % output_bin_file) - - # Create output csv and bin file - if input_is_keygen.lower() == 'true' and input_is_keyfile: - input_is_keyfile = os.path.basename(input_is_keyfile) - nvs_partition_gen.nvs_part_gen(input_filename=output_csv_file, output_filename=output_bin_file, - input_part_size=part_size, is_key_gen=input_is_keygen, - encrypt_mode=input_is_encrypt, key_file=input_is_keyfile, - version_no=input_version, encr_key_prefix=output_file_prefix, output_dir=output_dir_path) - print("CSV Generated: ", str(output_csv_file)) - - files_created = True - - csv_values_file.close() - except Exception as e: - print(e) - exit(1) - finally: - csv_values_file.close() - return csv_file_list, files_created, target_values_file + args = parser.parse_args() + args.func(args) except ValueError as err: print(err) - except Exception: - raise + except Exception as e: + print(e) if __name__ == "__main__": From 2360d882d941db4a8069f93e29ba922196a53be1 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Thu, 28 Mar 2019 14:07:53 +0800 Subject: [PATCH 255/486] parttool, otatool: accept esptool args --- components/app_update/otatool.py | 31 +++++++++++++---- components/partition_table/parttool.py | 46 +++++++++++++++++++++++--- 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/components/app_update/otatool.py b/components/app_update/otatool.py index 2cfecde18b..9bc392c39e 100755 --- a/components/app_update/otatool.py +++ b/components/app_update/otatool.py @@ -50,8 +50,11 @@ class OtatoolTarget(): OTADATA_PARTITION = PartitionType("data", "ota") - def __init__(self, port=None, partition_table_offset=PARTITION_TABLE_OFFSET, partition_table_file=None, spi_flash_sec_size=SPI_FLASH_SEC_SIZE): - self.target = ParttoolTarget(port, partition_table_offset, partition_table_file) + def __init__(self, port=None, partition_table_offset=PARTITION_TABLE_OFFSET, partition_table_file=None, + spi_flash_sec_size=SPI_FLASH_SEC_SIZE, esptool_args=[], esptool_write_args=[], + esptool_read_args=[], esptool_erase_args=[]): + self.target = ParttoolTarget(port, partition_table_offset, partition_table_file, esptool_args, + esptool_write_args, esptool_read_args, esptool_erase_args) self.spi_flash_sec_size = spi_flash_sec_size temp_file = tempfile.NamedTemporaryFile(delete=False) @@ -214,11 +217,11 @@ class OtatoolTarget(): def _read_otadata(target): target._check_otadata_partition() - otadata_info = target._get_otadata_info(target.otadata) + otadata_info = target._get_otadata_info() - print("\t\t{:11}\t{:8s}|\t{:8s}\t{:8s}".format("OTA_SEQ", "CRC", "OTA_SEQ", "CRC")) - print("Firmware: 0x{:8x} \t 0x{:8x} |\t0x{:8x} \t 0x{:8x}".format(otadata_info[0].seq, otadata_info[0].crc, - otadata_info[1].seq, otadata_info[1].crc)) + print(" {:8s} \t {:8s} | \t {:8s} \t {:8s}".format("OTA_SEQ", "CRC", "OTA_SEQ", "CRC")) + print("Firmware: 0x{:8x} \t0x{:8x} | \t0x{:8x} \t 0x{:8x}".format(otadata_info[0].seq, otadata_info[0].crc, + otadata_info[1].seq, otadata_info[1].crc)) def _erase_otadata(target): @@ -251,6 +254,10 @@ def main(): parser = argparse.ArgumentParser("ESP-IDF OTA Partitions Tool") parser.add_argument("--quiet", "-q", help="suppress stderr messages", action="store_true") + parser.add_argument("--esptool-args", help="additional main arguments for esptool", nargs="+") + parser.add_argument("--esptool-write-args", help="additional subcommand arguments for esptool write_flash", nargs="+") + parser.add_argument("--esptool-read-args", help="additional subcommand arguments for esptool read_flash", nargs="+") + parser.add_argument("--esptool-erase-args", help="additional subcommand arguments for esptool erase_region", nargs="+") # There are two possible sources for the partition table: a device attached to the host # or a partition table CSV/binary file. These sources are mutually exclusive. @@ -312,6 +319,18 @@ def main(): except AttributeError: pass + if args.esptool_args: + target_args["esptool_args"] = args.esptool_args + + if args.esptool_write_args: + target_args["esptool_write_args"] = args.esptool_write_args + + if args.esptool_read_args: + target_args["esptool_read_args"] = args.esptool_read_args + + if args.esptool_erase_args: + target_args["esptool_erase_args"] = args.esptool_erase_args + target = OtatoolTarget(**target_args) # Create the operation table and execute the operation diff --git a/components/partition_table/parttool.py b/components/partition_table/parttool.py index f2c005a10c..f82b90c3fa 100755 --- a/components/partition_table/parttool.py +++ b/components/partition_table/parttool.py @@ -22,6 +22,7 @@ import os import sys import subprocess import tempfile +import re import gen_esp32part as gen @@ -66,11 +67,30 @@ PARTITION_BOOT_DEFAULT = _PartitionId() class ParttoolTarget(): - def __init__(self, port=None, partition_table_offset=PARTITION_TABLE_OFFSET, partition_table_file=None): + def __init__(self, port=None, partition_table_offset=PARTITION_TABLE_OFFSET, partition_table_file=None, + esptool_args=[], esptool_write_args=[], esptool_read_args=[], esptool_erase_args=[]): self.port = port gen.offset_part_table = partition_table_offset + def parse_esptool_args(esptool_args): + results = list() + for arg in esptool_args: + pattern = re.compile(r"(.+)=(.+)") + result = pattern.match(arg) + try: + key = result.group(1) + value = result.group(2) + results.extend(["--" + key, value]) + except AttributeError: + results.extend(["--" + arg]) + return results + + self.esptool_args = parse_esptool_args(esptool_args) + self.esptool_write_args = parse_esptool_args(esptool_write_args) + self.esptool_read_args = parse_esptool_args(esptool_read_args) + self.esptool_erase_args = parse_esptool_args(esptool_erase_args) + if partition_table_file: try: with open(partition_table_file, "rb") as f: @@ -93,7 +113,7 @@ class ParttoolTarget(): self.partition_table = partition_table def _call_esptool(self, args, out=None): - esptool_args = [sys.executable, ESPTOOL_PY] + esptool_args = [sys.executable, ESPTOOL_PY] + self.esptool_args if self.port: esptool_args += ["--port", self.port] @@ -124,11 +144,11 @@ class ParttoolTarget(): def erase_partition(self, partition_id): partition = self.get_partition_info(partition_id) - self._call_esptool(["erase_region", str(partition.offset), str(partition.size)]) + self._call_esptool(["erase_region", str(partition.offset), str(partition.size)] + self.esptool_erase_args) def read_partition(self, partition_id, output): partition = self.get_partition_info(partition_id) - self._call_esptool(["read_flash", str(partition.offset), str(partition.size), output]) + self._call_esptool(["read_flash", str(partition.offset), str(partition.size), output] + self.esptool_read_args) def write_partition(self, partition_id, input): self.erase_partition(partition_id) @@ -141,7 +161,7 @@ class ParttoolTarget(): if content_len > partition.size: raise Exception("Input file size exceeds partition size") - self._call_esptool(["write_flash", str(partition.offset), input]) + self._call_esptool(["write_flash", str(partition.offset), input] + self.esptool_write_args) def _write_partition(target, partition_id, input): @@ -191,6 +211,10 @@ def main(): parser = argparse.ArgumentParser("ESP-IDF Partitions Tool") parser.add_argument("--quiet", "-q", help="suppress stderr messages", action="store_true") + parser.add_argument("--esptool-args", help="additional main arguments for esptool", nargs="+") + parser.add_argument("--esptool-write-args", help="additional subcommand arguments when writing to flash", nargs="+") + parser.add_argument("--esptool-read-args", help="additional subcommand arguments when reading flash", nargs="+") + parser.add_argument("--esptool-erase-args", help="additional subcommand arguments when erasing regions of flash", nargs="+") # By default the device attached to the specified port is queried for the partition table. If a partition table file # is specified, that is used instead. @@ -264,6 +288,18 @@ def main(): if args.partition_table_offset: target_args["partition_table_offset"] = int(args.partition_table_offset, 0) + if args.esptool_args: + target_args["esptool_args"] = args.esptool_args + + if args.esptool_write_args: + target_args["esptool_write_args"] = args.esptool_write_args + + if args.esptool_read_args: + target_args["esptool_read_args"] = args.esptool_read_args + + if args.esptool_erase_args: + target_args["esptool_erase_args"] = args.esptool_erase_args + target = ParttoolTarget(**target_args) # Create the operation table and execute the operation From 94e0569c2b5587f350cb048984a7952122eb38ee Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Thu, 28 Mar 2019 14:08:32 +0800 Subject: [PATCH 256/486] make, cmake: pass config esptool args for otatool invocation Closes https://github.com/espressif/esp-idf/issues/3135 --- components/app_update/CMakeLists.txt | 6 ++++-- components/app_update/Makefile.projbuild | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/components/app_update/CMakeLists.txt b/components/app_update/CMakeLists.txt index a683b1c394..8d0e45dbb0 100644 --- a/components/app_update/CMakeLists.txt +++ b/components/app_update/CMakeLists.txt @@ -38,14 +38,16 @@ if(NOT BOOTLOADER_BUILD) set(otatool_py ${python} ${COMPONENT_DIR}/otatool.py) + set(esptool_args --esptool-args before=${CONFIG_ESPTOOLPY_BEFORE} after=${CONFIG_ESPTOOLPY_AFTER}) + add_custom_target(read_otadata DEPENDS "${PARTITION_CSV_PATH}" - COMMAND ${otatool_py} + COMMAND ${otatool_py} ${esptool_args} --partition-table-file ${PARTITION_CSV_PATH} --partition-table-offset ${PARTITION_TABLE_OFFSET} read_otadata) add_custom_target(erase_otadata DEPENDS "${PARTITION_CSV_PATH}" - COMMAND ${otatool_py} + COMMAND ${otatool_py} ${esptool_args} --partition-table-file ${PARTITION_CSV_PATH} --partition-table-offset ${PARTITION_TABLE_OFFSET} erase_otadata) diff --git a/components/app_update/Makefile.projbuild b/components/app_update/Makefile.projbuild index 518e04dfa4..4081aab976 100644 --- a/components/app_update/Makefile.projbuild +++ b/components/app_update/Makefile.projbuild @@ -28,13 +28,15 @@ blank_ota_data: $(BLANK_OTA_DATA_FILE) # expand to empty values. ESPTOOL_ALL_FLASH_ARGS += $(OTA_DATA_OFFSET) $(BLANK_OTA_DATA_FILE) +ESPTOOL_ARGS := --esptool-args port=$(CONFIG_ESPTOOLPY_PORT) baud=$(CONFIG_ESPTOOLPY_BAUD) before=$(CONFIG_ESPTOOLPY_BEFORE) after=$(CONFIG_ESPTOOLPY_AFTER) + erase_otadata: $(PARTITION_TABLE_CSV_PATH) partition_table_get_info | check_python_dependencies - $(OTATOOL_PY) --partition-table-file $(PARTITION_TABLE_CSV_PATH) \ + $(OTATOOL_PY) $(ESPTOOL_ARGS) --partition-table-file $(PARTITION_TABLE_CSV_PATH) \ --partition-table-offset $(PARTITION_TABLE_OFFSET) \ erase_otadata read_otadata: $(PARTITION_TABLE_CSV_PATH) partition_table_get_info | check_python_dependencies - $(OTATOOL_PY) --partition-table-file $(PARTITION_TABLE_CSV_PATH) \ + $(OTATOOL_PY) $(ESPTOOL_ARGS) --partition-table-file $(PARTITION_TABLE_CSV_PATH) \ --partition-table-offset $(partition_table_offset) \ read_otadata From e72a09ee274e0d50edcdcb3eacdd3aa4471a1350 Mon Sep 17 00:00:00 2001 From: nif Date: Mon, 1 Jul 2019 17:52:43 +0200 Subject: [PATCH 257/486] Make submodules work in forks Merges https://github.com/espressif/esp-idf/pull/3721 --- .gitmodules | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.gitmodules b/.gitmodules index 21a8c1df34..e32b97a7ab 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,11 +4,11 @@ [submodule "components/esptool_py/esptool"] path = components/esptool_py/esptool - url = ../esptool.git + url = ../../espressif/esptool.git [submodule "components/bt/controller/lib"] path = components/bt/controller/lib - url = ../esp32-bt-lib.git + url = ../../espressif/esp32-bt-lib.git [submodule "components/bootloader/subproject/components/micro-ecc/micro-ecc"] path = components/bootloader/subproject/components/micro-ecc/micro-ecc @@ -36,11 +36,11 @@ [submodule "components/mbedtls/mbedtls"] path = components/mbedtls/mbedtls - url = ../mbedtls.git + url = ../../espressif/mbedtls.git [submodule "components/asio/asio"] path = components/asio/asio - url = ../asio.git + url = ../../espressif/asio.git [submodule "components/expat/expat"] path = components/expat/expat @@ -48,11 +48,11 @@ [submodule "components/lwip/lwip"] path = components/lwip/lwip - url = ../esp-lwip.git + url = ../../espressif/esp-lwip.git [submodule "components/mqtt/esp-mqtt"] path = components/mqtt/esp-mqtt - url = ../esp-mqtt.git + url = ../../espressif/esp-mqtt.git [submodule "components/protobuf-c/protobuf-c"] path = components/protobuf-c/protobuf-c @@ -68,8 +68,8 @@ [submodule "components/esp_wifi/lib_esp32"] path = components/esp_wifi/lib_esp32 - url = ../esp32-wifi-lib.git + url = ../../espressif/esp32-wifi-lib.git [submodule "components/bt/host/nimble/nimble"] path = components/bt/host/nimble/nimble - url = ../esp-nimble.git + url = ../../espressif/esp-nimble.git From b54762597aa3e450ae212ca67c63e02da87d5b40 Mon Sep 17 00:00:00 2001 From: Anton Maklakov Date: Tue, 2 Jul 2019 13:40:04 +0700 Subject: [PATCH 258/486] Avoid 'redirecting to' warnings when cloning --- .gitmodules | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index e32b97a7ab..150118b11e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -56,15 +56,15 @@ [submodule "components/protobuf-c/protobuf-c"] path = components/protobuf-c/protobuf-c - url = ../../protobuf-c/protobuf-c + url = ../../protobuf-c/protobuf-c.git [submodule "components/unity/unity"] path = components/unity/unity - url = ../../ThrowTheSwitch/Unity + url = ../../ThrowTheSwitch/Unity.git [submodule "examples/build_system/cmake/import_lib/main/lib/tinyxml2"] path = examples/build_system/cmake/import_lib/main/lib/tinyxml2 - url = ../../leethomason/tinyxml2 + url = ../../leethomason/tinyxml2.git [submodule "components/esp_wifi/lib_esp32"] path = components/esp_wifi/lib_esp32 From c9cf0afb6ef207af2cbc094f0028f2ce82b39619 Mon Sep 17 00:00:00 2001 From: Anton Maklakov Date: Mon, 1 Jul 2019 15:19:10 +0700 Subject: [PATCH 259/486] tools: Add a script for switching to real submodules in forks --- .gitmodules | 1 + README.md | 8 ++++++ tools/ci/executable-list.txt | 1 + tools/set-submodules-to-github.sh | 41 +++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+) create mode 100755 tools/set-submodules-to-github.sh diff --git a/.gitmodules b/.gitmodules index 150118b11e..70bd0c478e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,5 +1,6 @@ # # All the relative URL paths are intended to be GitHub ones +# For Espressif's public projects please use '../../espressif/proj', not a '../proj' # [submodule "components/esptool_py/esptool"] diff --git a/README.md b/README.md index 55487c9b2c..bbb8d3a54b 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,14 @@ See setup guides for detailed instructions to set up the ESP-IDF: * [Getting Started Guide for the stable ESP-IDF version](https://docs.espressif.com/projects/esp-idf/en/stable/get-started/) * [Getting Started Guide for the latest (master branch) ESP-IDF version](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/) +### Non-GitHub forks + +ESP-IDF uses relative locations as its submodules URLs ([.gitmodules](.gitmodules)). So they link to GitHub. +If ESP-IDF is forked to a Git repository which is not on GitHub, you will need to run the script +[tools/set-submodules-to-github.sh](tools/set-submodules-to-github.sh) after git clone. +The script sets absolute URLs for all submodules, allowing `git submodule update --init --recursive` to complete. +If cloning ESP-IDF from GitHub, this step is not needed. + ## Finding a Project As well as the [esp-idf-template](https://github.com/espressif/esp-idf-template) project mentioned in Getting Started, ESP-IDF comes with some example projects in the [examples](examples) directory. diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index a3b2845577..e7b9715194 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -70,6 +70,7 @@ tools/ldgen/ldgen.py tools/ldgen/test/test_fragments.py tools/ldgen/test/test_generation.py tools/mass_mfg/mfg_gen.py +tools/set-submodules-to-github.sh tools/test_check_kconfigs.py tools/test_idf_monitor/run_test_idf_monitor.py tools/test_idf_size/test.sh diff --git a/tools/set-submodules-to-github.sh b/tools/set-submodules-to-github.sh new file mode 100755 index 0000000000..5495fb4a29 --- /dev/null +++ b/tools/set-submodules-to-github.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# +# Explicitly switches the relative submodules locations on GitHub to the original public URLs +# +# '../../group/repo.git' to 'https://github.com/group/repo.git' +# +# This can be useful for non-GitHub forks to automate getting of right submodules sources. +# + +# +# It makes sense to do +# +# git submodule deinit --force . +# git submodule init +# +# before running this, and +# +# git submodule update --recursive +# +# after that. These were not included over this script deliberately, to use the script flexibly +# + +set -o errexit +set -o pipefail +set -o nounset + +DEBUG_SHELL=${DEBUG_SHELL:-"0"} +[ "${DEBUG_SHELL}" = "1" ] && set -x + +### '../../' relative locations + +for LINE in $(git config -f .gitmodules --list | grep "\.url=../../[^.]") +do + SUBPATH=$(echo "${LINE}" | sed "s|^submodule\.\([^.]*\)\.url.*$|\1|") + LOCATION=$(echo "${LINE}" | sed 's|.*\.url=\.\./\.\./\(.*\)$|\1|') + SUBURL="https://github.com/$LOCATION" + + git config submodule."${SUBPATH}".url "${SUBURL}" +done + +git config --get-regexp '^submodule\..*\.url$' From c516819ba6764ebb967aca2c198fe5cab75fddbd Mon Sep 17 00:00:00 2001 From: qiyuexia Date: Mon, 1 Jul 2019 19:38:06 +0800 Subject: [PATCH 260/486] mesh: bugfix 1. resend eb which are pending in g_ic.tx_buf due to channel switch. 2. add lock for mgmg/xon/bcast to protect send from user flush. 3. softap: add check if secondary offset is correct when start softap. 4. softap: in inactive timer handler, add check if child bss is removed to avoid removing it again. 5. disable A-MPDU for non-root. 6. fix reusing a freed eb. 7. fix when node becomes root, it does not record assoc value to nvs. 8. discard unnecessary forwarded group packets. 9. fix toDS state is not updated in time. 10. fix s_sta_cnx_times is not cleared when deinit causes root sends ADD annoucement. 11. root: increase beacon timeout time from 6 seconds to 15 seconds to delay initiation of reconnection. 12. add esp_mesh_get_tsf_time to return TSF time. 13. send the whole routing table multi-times. 14. clear candidate settings if not receive candidate beacon within 8 seconds. --- components/esp_wifi/include/esp_mesh.h | 7 +++++++ components/esp_wifi/lib_esp32 | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/components/esp_wifi/include/esp_mesh.h b/components/esp_wifi/include/esp_mesh.h index a532117567..e52e541ff8 100644 --- a/components/esp_wifi/include/esp_mesh.h +++ b/components/esp_wifi/include/esp_mesh.h @@ -1479,6 +1479,13 @@ esp_err_t esp_mesh_switch_channel(const uint8_t *new_bssid, int csa_newchan, int */ esp_err_t esp_mesh_get_router_bssid(uint8_t *router_bssid); +/** + * @brief Get the TSF time + * + * @return the TSF time + */ +int64_t esp_mesh_get_tsf_time(void); + #ifdef __cplusplus } #endif diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index 7657dd453d..b7bfeeccdb 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit 7657dd453d4349d03458b77c082acbfe6b6736c4 +Subproject commit b7bfeeccdb63fd20cf6b4abc52d9185934af4cb8 From 69ade757e242712ff6a457328a8eee9d0bd4c17a Mon Sep 17 00:00:00 2001 From: Anurag Kar Date: Wed, 24 Apr 2019 00:07:39 +0530 Subject: [PATCH 261/486] Wi-Fi Provisioning : Manager now uses esp_event to catch system events and emit provisioning events to the default event loop List of changes: * Deprecated public API wifi_prov_mgr_event_handler() and added private function wifi_prov_mgr_event_handler_internal(), registered with the default event loop for catching WIFI and IP system events --- .../include/wifi_provisioning/manager.h | 11 +- components/wifi_provisioning/src/manager.c | 111 ++++++++++++------ 2 files changed, 81 insertions(+), 41 deletions(-) diff --git a/components/wifi_provisioning/include/wifi_provisioning/manager.h b/components/wifi_provisioning/include/wifi_provisioning/manager.h index 6b535604d4..8f31aedba5 100644 --- a/components/wifi_provisioning/include/wifi_provisioning/manager.h +++ b/components/wifi_provisioning/include/wifi_provisioning/manager.h @@ -23,6 +23,8 @@ extern "C" { #endif +ESP_EVENT_DECLARE_BASE(WIFI_PROV_EVENT); + /** * @brief Events generated by manager * @@ -489,14 +491,17 @@ void wifi_prov_mgr_endpoint_unregister(const char *ep_name); * provisioning manager's internal state machine depending on * incoming Wi-Fi events * + * @note : This function is DEPRECATED, because events are now + * handled internally using the event loop library, esp_event. + * Calling this will do nothing and simply return ESP_OK. + * * @param[in] ctx Event context data * @param[in] event Event info * * @return - * - ESP_OK : Event handled successfully - * - ESP_ERR_FAIL : This event cannot be handled + * - ESP_OK : Event handled successfully */ -esp_err_t wifi_prov_mgr_event_handler(void *ctx, system_event_t *event); +esp_err_t wifi_prov_mgr_event_handler(void *ctx, system_event_t *event) __attribute__ ((deprecated)); /** * @brief Get state of Wi-Fi Station during provisioning diff --git a/components/wifi_provisioning/src/manager.c b/components/wifi_provisioning/src/manager.c index af7991fa76..078a4b05d7 100644 --- a/components/wifi_provisioning/src/manager.c +++ b/components/wifi_provisioning/src/manager.c @@ -40,6 +40,8 @@ static const char *TAG = "wifi_prov_mgr"; +ESP_EVENT_DEFINE_BASE(WIFI_PROV_EVENT); + typedef enum { WIFI_PROV_STATE_IDLE, WIFI_PROV_STATE_STARTING, @@ -155,7 +157,7 @@ static struct wifi_prov_mgr_ctx *prov_ctx; * * NOTE: This function should be called only after ensuring that the * context is valid and the control mutex is locked. */ -static void execute_event_cb(wifi_prov_cb_event_t event_id, void *event_data) +static void execute_event_cb(wifi_prov_cb_event_t event_id, void *event_data, size_t event_data_size) { ESP_LOGD(TAG, "execute_event_cb : %d", event_id); @@ -180,6 +182,12 @@ static void execute_event_cb(wifi_prov_cb_event_t event_id, void *event_data) app_cb(app_data, event_id, event_data); } + if (esp_event_post(WIFI_PROV_EVENT, event_id, + event_data, event_data_size, + portMAX_DELAY) != ESP_OK) { + ESP_LOGE(TAG, "Failed to post event %d to default event loop", event_id); + } + ACQUIRE_LOCK(prov_ctx_lock); } } @@ -255,6 +263,10 @@ static cJSON* wifi_prov_get_info_json(void) return full_info_json; } +/* Declare the internal event handler */ +static void wifi_prov_mgr_event_handler_internal(void* arg, esp_event_base_t event_base, + int event_id, void* event_data); + static esp_err_t wifi_prov_mgr_start_service(const char *service_name, const char *service_key) { const wifi_prov_scheme_t *scheme = &prov_ctx->mgr_config.scheme; @@ -355,6 +367,31 @@ static esp_err_t wifi_prov_mgr_start_service(const char *service_name, const cha return ret; } + /* Register global event handler */ + ret = esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, + wifi_prov_mgr_event_handler_internal, NULL); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to register WiFi event handler"); + free(prov_ctx->wifi_scan_handlers); + free(prov_ctx->wifi_prov_handlers); + scheme->prov_stop(prov_ctx->pc); + protocomm_delete(prov_ctx->pc); + return ret; + } + + ret = esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, + wifi_prov_mgr_event_handler_internal, NULL); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to register IP event handler"); + esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, + wifi_prov_mgr_event_handler_internal); + free(prov_ctx->wifi_scan_handlers); + free(prov_ctx->wifi_prov_handlers); + scheme->prov_stop(prov_ctx->pc); + protocomm_delete(prov_ctx->pc); + return ret; + } + ESP_LOGI(TAG, "Provisioning started with service name : %s ", service_name ? service_name : ""); return ESP_OK; @@ -549,6 +586,12 @@ static bool wifi_prov_mgr_stop_service(bool blocking) prov_ctx->ap_list_sorted[i] = NULL; } + /* Remove event handler */ + esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, + wifi_prov_mgr_event_handler_internal); + esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, + wifi_prov_mgr_event_handler_internal); + if (blocking) { /* Run the cleanup without launching a separate task. Also the * WIFI_PROV_END event is not emitted in this case */ @@ -734,17 +777,20 @@ static esp_err_t update_wifi_scan_results(void) return ret; } -/* Event handler for starting/stopping provisioning. +/* DEPRECATED : Event handler for starting/stopping provisioning. * To be called from within the context of the main * event handler */ esp_err_t wifi_prov_mgr_event_handler(void *ctx, system_event_t *event) { - /* For accessing reason codes in case of disconnection */ - system_event_info_t *info = &event->event_info; + return ESP_OK; +} +static void wifi_prov_mgr_event_handler_internal( + void* arg, esp_event_base_t event_base, int event_id, void* event_data) +{ if (!prov_ctx_lock) { ESP_LOGE(TAG, "Provisioning manager not initialized"); - return ESP_ERR_INVALID_STATE; + return; } ACQUIRE_LOCK(prov_ctx_lock); @@ -753,12 +799,13 @@ esp_err_t wifi_prov_mgr_event_handler(void *ctx, system_event_t *event) * return with error to allow the global handler to act */ if (!prov_ctx) { RELEASE_LOCK(prov_ctx_lock); - return ESP_ERR_INVALID_STATE; + return; } /* If scan completed then update scan result */ if (prov_ctx->prov_state == WIFI_PROV_STATE_STARTED && - event->event_id == SYSTEM_EVENT_SCAN_DONE) { + event_base == WIFI_EVENT && + event_id == WIFI_EVENT_SCAN_DONE) { update_wifi_scan_results(); } @@ -766,22 +813,18 @@ esp_err_t wifi_prov_mgr_event_handler(void *ctx, system_event_t *event) * Wi-Fi STA is yet to complete trying the connection */ if (prov_ctx->prov_state != WIFI_PROV_STATE_CRED_RECV) { RELEASE_LOCK(prov_ctx_lock); - return ESP_OK; + return; } - esp_err_t ret = ESP_OK; - switch (event->event_id) { - case SYSTEM_EVENT_STA_START: - ESP_LOGD(TAG, "STA Start"); + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { + ESP_LOGI(TAG, "STA Start"); /* Once configuration is received through protocomm, * device is started as station. Once station starts, * wait for connection to establish with configured * host SSID and password */ prov_ctx->wifi_state = WIFI_PROV_STA_CONNECTING; - break; - - case SYSTEM_EVENT_STA_GOT_IP: - ESP_LOGD(TAG, "STA Got IP"); + } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { + ESP_LOGI(TAG, "STA Got IP"); /* Station got IP. That means configuration is successful. */ prov_ctx->wifi_state = WIFI_PROV_STA_CONNECTED; prov_ctx->prov_state = WIFI_PROV_STATE_SUCCESS; @@ -794,28 +837,28 @@ esp_err_t wifi_prov_mgr_event_handler(void *ctx, system_event_t *event) } /* Execute user registered callback handler */ - execute_event_cb(WIFI_PROV_CRED_SUCCESS, NULL); - break; - - case SYSTEM_EVENT_STA_DISCONNECTED: - ESP_LOGD(TAG, "STA Disconnected"); + execute_event_cb(WIFI_PROV_CRED_SUCCESS, NULL, 0); + } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { + ESP_LOGE(TAG, "STA Disconnected"); /* Station couldn't connect to configured host SSID */ prov_ctx->wifi_state = WIFI_PROV_STA_DISCONNECTED; - ESP_LOGD(TAG, "Disconnect reason : %d", info->disconnected.reason); + + wifi_event_sta_disconnected_t* disconnected = (wifi_event_sta_disconnected_t*) event_data; + ESP_LOGE(TAG, "Disconnect reason : %d", disconnected->reason); /* Set code corresponding to the reason for disconnection */ - switch (info->disconnected.reason) { + switch (disconnected->reason) { case WIFI_REASON_AUTH_EXPIRE: case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT: case WIFI_REASON_BEACON_TIMEOUT: case WIFI_REASON_AUTH_FAIL: case WIFI_REASON_ASSOC_FAIL: case WIFI_REASON_HANDSHAKE_TIMEOUT: - ESP_LOGD(TAG, "STA Auth Error"); + ESP_LOGE(TAG, "STA Auth Error"); prov_ctx->wifi_disconnect_reason = WIFI_PROV_STA_AUTH_ERROR; break; case WIFI_REASON_NO_AP_FOUND: - ESP_LOGD(TAG, "STA AP Not found"); + ESP_LOGE(TAG, "STA AP Not found"); prov_ctx->wifi_disconnect_reason = WIFI_PROV_STA_AP_NOT_FOUND; break; default: @@ -831,20 +874,11 @@ esp_err_t wifi_prov_mgr_event_handler(void *ctx, system_event_t *event) prov_ctx->prov_state = WIFI_PROV_STATE_FAIL; wifi_prov_sta_fail_reason_t reason = prov_ctx->wifi_disconnect_reason; /* Execute user registered callback handler */ - execute_event_cb(WIFI_PROV_CRED_FAIL, (void *)&reason); + execute_event_cb(WIFI_PROV_CRED_FAIL, (void *)&reason, sizeof(reason)); } - break; - - default: - /* This event is not intended to be handled by this handler. - * Return ESP_FAIL to signal global event handler to take - * control */ - ret = ESP_FAIL; - break; } RELEASE_LOCK(prov_ctx_lock); - return ret; } esp_err_t wifi_prov_mgr_wifi_scan_start(bool blocking, bool passive, @@ -1125,7 +1159,7 @@ esp_err_t wifi_prov_mgr_configure_sta(wifi_config_t *wifi_cfg) prov_ctx->wifi_state = WIFI_PROV_STA_CONNECTING; prov_ctx->prov_state = WIFI_PROV_STATE_CRED_RECV; /* Execute user registered callback handler */ - execute_event_cb(WIFI_PROV_CRED_RECV, (void *)&wifi_cfg->sta); + execute_event_cb(WIFI_PROV_CRED_RECV, (void *)&wifi_cfg->sta, sizeof(wifi_cfg->sta)); RELEASE_LOCK(prov_ctx_lock); return ESP_OK; @@ -1230,7 +1264,7 @@ exit: } free(prov_ctx); } else { - execute_event_cb(WIFI_PROV_INIT, NULL); + execute_event_cb(WIFI_PROV_INIT, NULL, 0); } RELEASE_LOCK(prov_ctx_lock); return ret; @@ -1322,6 +1356,7 @@ void wifi_prov_mgr_deinit(void) if (app_cb) { app_cb(app_data, WIFI_PROV_DEINIT, NULL); } + esp_event_post(WIFI_PROV_EVENT, WIFI_PROV_DEINIT, NULL, 0, portMAX_DELAY); } esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const char *pop, @@ -1442,7 +1477,7 @@ esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const if (ret == ESP_OK) { prov_ctx->prov_state = WIFI_PROV_STATE_STARTED; /* Execute user registered callback handler */ - execute_event_cb(WIFI_PROV_START, NULL); + execute_event_cb(WIFI_PROV_START, NULL, 0); goto exit; } From 0e8bd1699d3763480fa39f3531fb6bc808184287 Mon Sep 17 00:00:00 2001 From: Anurag Kar Date: Wed, 24 Apr 2019 00:12:16 +0530 Subject: [PATCH 262/486] Wi-Fi Provisioning : Manager docs updated with information about esp_event_loop support --- .../provisioning/wifi_provisioning.rst | 117 +++++++----------- 1 file changed, 42 insertions(+), 75 deletions(-) diff --git a/docs/en/api-reference/provisioning/wifi_provisioning.rst b/docs/en/api-reference/provisioning/wifi_provisioning.rst index fb6c060eca..0cf035aeee 100644 --- a/docs/en/api-reference/provisioning/wifi_provisioning.rst +++ b/docs/en/api-reference/provisioning/wifi_provisioning.rst @@ -19,11 +19,7 @@ Initialization wifi_prov_mgr_config_t config = { .scheme = wifi_prov_scheme_ble, - .scheme_event_handler = WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM, - .app_event_handler = { - .event_cb = prov_event_handler, - .user_data = NULL - } + .scheme_event_handler = WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM }; ESP_ERR_CHECK( wifi_prov_mgr_init(config) ); @@ -44,53 +40,51 @@ The configuration structure ``wifi_prov_mgr_config_t`` has a few fields to speci * ``WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BT`` - Free only classic BT. Used when main application requires BLE. In this case freeing happens right when the manager is initialized. * ``WIFI_PROV_EVENT_HANDLER_NONE`` - Don't use any scheme specific handler. Used when provisioning scheme is not BLE (i.e. SoftAP or Console), or when main application wants to handle the memory reclaiming on its own, or needs both BLE and classic BT to function. - * `app_event_handler` : Application specific event handler which can be used to execute specific calls depending on the state of the provisioning service. This is to be set to a function of the form ``void app_event_handler(void *user_data, wifi_prov_cb_event_t event, void *event_data)`` along with any user data to be made available at the time of handling. This can also be set to ``WIFI_PROV_EVENT_HANDLER_NONE`` if not used. See definition of ``wifi_prov_cb_event_t`` for the list of events that are generated by the provisioning service. Following is a snippet showing a typical application specific provisioning event handler along with usage of the ``event_data`` parameter : + * `app_event_handler` (Deprecated) : It is now recommended to catch ``WIFI_PROV_EVENT``s that are emitted to the default event loop handler. See definition of ``wifi_prov_cb_event_t`` for the list of events that are generated by the provisioning service. Here is an excerpt showing some of the provisioning events: .. highlight:: c :: - void prov_event_handler(void *user_data, - wifi_prov_cb_event_t event, - void *event_data) + static void event_handler(void* arg, esp_event_base_t event_base, + int event_id, void* event_data) { - switch (event) { - case WIFI_PROV_INIT: - ESP_LOGI(TAG, "Manager initialized"); - break; - case WIFI_PROV_START: - ESP_LOGI(TAG, "Provisioning started"); - break; - case WIFI_PROV_CRED_RECV: { - wifi_sta_config_t *wifi_sta_cfg = (wifi_sta_config_t *)event_data; - ESP_LOGI(TAG, "Received Wi-Fi credentials" - "\n\tSSID : %s\n\tPassword : %s", - (const char *) wifi_sta_cfg->ssid, - (const char *) wifi_sta_cfg->password); - break; + if (event_base == WIFI_PROV_EVENT) { + switch (event_id) { + case WIFI_PROV_START: + ESP_LOGI(TAG, "Provisioning started"); + break; + case WIFI_PROV_CRED_RECV: { + wifi_sta_config_t *wifi_sta_cfg = (wifi_sta_config_t *)event_data; + ESP_LOGI(TAG, "Received Wi-Fi credentials" + "\n\tSSID : %s\n\tPassword : %s", + (const char *) wifi_sta_cfg->ssid, + (const char *) wifi_sta_cfg->password); + break; + } + case WIFI_PROV_CRED_FAIL: { + wifi_prov_sta_fail_reason_t *reason = (wifi_prov_sta_fail_reason_t *)event_data; + ESP_LOGE(TAG, "Provisioning failed!\n\tReason : %s" + "\n\tPlease reset to factory and retry provisioning", + (*reason == WIFI_PROV_STA_AUTH_ERROR) ? + "Wi-Fi station authentication failed" : "Wi-Fi access-point not found"); + break; + } + case WIFI_PROV_CRED_SUCCESS: + ESP_LOGI(TAG, "Provisioning successful"); + break; + case WIFI_PROV_END: + /* De-initialize manager once provisioning is finished */ + wifi_prov_mgr_deinit(); + break; + default: + break; } - case WIFI_PROV_CRED_FAIL: { - wifi_prov_sta_fail_reason_t *reason = (wifi_prov_sta_fail_reason_t *)event_data; - ESP_LOGE(TAG, "Provisioning failed : %s", - (*reason == WIFI_PROV_STA_AUTH_ERROR) ? - "Wi-Fi AP password incorrect" : - "Wi-Fi AP not found"); - break; - } - case WIFI_PROV_CRED_SUCCESS: - ESP_LOGI(TAG, "Provisioning successful"); - break; - case WIFI_PROV_END: - ESP_LOGI(TAG, "Provisioning stopped"); - break; - case WIFI_PROV_DEINIT: - ESP_LOGI(TAG, "Manager de-initialized"); - break; - default: - break; } } +The manager can be de-initialized at any moment by making a call to :cpp:func:`wifi_prov_mgr_deinit()`. + .. _wifi-prov-check-state: Check Provisioning State @@ -114,30 +108,6 @@ If provisioning state needs to be reset, any of the following approaches may be ESP_ERR_CHECK( wifi_prov_mgr_is_provisioned(&provisioned) ); -Event Loop Handling -^^^^^^^^^^^^^^^^^^^ - -Presently Wi-Fi provisioning manager cannot directly catch external system events, hence it is necessary to explicitly call :cpp:func:`wifi_prov_mgr_event_handler()` from inside the global event loop handler. See the following snippet : - - .. highlight:: c - - :: - - static esp_err_t global_event_loop_handler(void *ctx, system_event_t *event) - { - /* Pass event information to provisioning manager so that it can - * maintain its internal state depending upon the system event */ - wifi_prov_mgr_event_handler(ctx, event); - - /* Event handling logic for main application */ - switch (event->event_id) { - ..... - ..... - ..... - } - return ESP_OK; - } - Start Provisioning Service ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -194,21 +164,18 @@ There are two ways for making this possible. The simpler way is to use a blockin wifi_prov_mgr_deinit(); -The other way is to use the application specific event handler which is to be configured during initialization, as explained above in :ref:`wifi-prov-mgr-init`. +The other way is to use the default event loop handler to catch ``WIFI_PROV_EVENT``s and call :cpp:func:`wifi_prov_mgr_deinit()` when event ID is ``WIFI_PROV_END``: .. highlight:: c :: - void prov_event_handler(void *user_data, wifi_prov_cb_event_t event, void *event_data) + static void event_handler(void* arg, esp_event_base_t event_base, + int event_id, void* event_data) { - switch (event) { - case WIFI_PROV_END: - // De-initialize manager once provisioning is finished - wifi_prov_mgr_deinit(); - break; - default: - break; + if (event_base == WIFI_PROV_EVENT && event_id == WIFI_PROV_END) { + /* De-initialize manager once provisioning is finished */ + wifi_prov_mgr_deinit(); } } From a13cc7da7ab6ce32627caf71b58f9091770f514d Mon Sep 17 00:00:00 2001 From: Anurag Kar Date: Wed, 24 Apr 2019 00:13:14 +0530 Subject: [PATCH 263/486] Provisioning : Manager example updated to use esp_event_loop feature --- examples/provisioning/manager/main/app_main.c | 127 ++++++++---------- 1 file changed, 55 insertions(+), 72 deletions(-) diff --git a/examples/provisioning/manager/main/app_main.c b/examples/provisioning/manager/main/app_main.c index d6fd9a47e0..96634fa71a 100644 --- a/examples/provisioning/manager/main/app_main.c +++ b/examples/provisioning/manager/main/app_main.c @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include @@ -30,73 +30,56 @@ const int WIFI_CONNECTED_EVENT = BIT0; static EventGroupHandle_t wifi_event_group; /* Event handler for catching system events */ -static esp_err_t event_handler(void *ctx, system_event_t *event) +static void event_handler(void* arg, esp_event_base_t event_base, + int event_id, void* event_data) { - /* Pass event information to provisioning manager so that it can - * maintain its internal state depending upon the system event */ - wifi_prov_mgr_event_handler(ctx, event); - - /* Global event handling */ - switch (event->event_id) { - case SYSTEM_EVENT_STA_START: - esp_wifi_connect(); - break; - case SYSTEM_EVENT_STA_GOT_IP: - ESP_LOGI(TAG, "Connected with IP Address:%s", - ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip)); - xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_EVENT); - break; - case SYSTEM_EVENT_STA_DISCONNECTED: - ESP_LOGI(TAG, "Disconnected. Connecting to the AP again..."); - esp_wifi_connect(); - break; - default: - break; - } - return ESP_OK; -} - -/* Event handler for catching provisioning manager events */ -static void prov_event_handler(void *user_data, - wifi_prov_cb_event_t event, void *event_data) -{ - switch (event) { - case WIFI_PROV_START: - ESP_LOGI(TAG, "Provisioning started"); - break; - case WIFI_PROV_CRED_RECV: { - wifi_sta_config_t *wifi_sta_cfg = (wifi_sta_config_t *)event_data; - /* If SSID length is exactly 32 bytes, null termination - * will not be present, so explicitly obtain the length */ - size_t ssid_len = strnlen((const char *)wifi_sta_cfg->ssid, sizeof(wifi_sta_cfg->ssid)); - ESP_LOGI(TAG, "Received Wi-Fi credentials" - "\n\tSSID : %.*s\n\tPassword : %s", - ssid_len, (const char *) wifi_sta_cfg->ssid, - (const char *) wifi_sta_cfg->password); - break; + if (event_base == WIFI_PROV_EVENT) { + switch (event_id) { + case WIFI_PROV_START: + ESP_LOGI(TAG, "Provisioning started"); + break; + case WIFI_PROV_CRED_RECV: { + wifi_sta_config_t *wifi_sta_cfg = (wifi_sta_config_t *)event_data; + ESP_LOGI(TAG, "Received Wi-Fi credentials" + "\n\tSSID : %s\n\tPassword : %s", + (const char *) wifi_sta_cfg->ssid, + (const char *) wifi_sta_cfg->password); + break; + } + case WIFI_PROV_CRED_FAIL: { + wifi_prov_sta_fail_reason_t *reason = (wifi_prov_sta_fail_reason_t *)event_data; + ESP_LOGE(TAG, "Provisioning failed!\n\tReason : %s" + "\n\tPlease reset to factory and retry provisioning", + (*reason == WIFI_PROV_STA_AUTH_ERROR) ? + "Wi-Fi station authentication failed" : "Wi-Fi access-point not found"); + break; + } + case WIFI_PROV_CRED_SUCCESS: + ESP_LOGI(TAG, "Provisioning successful"); + break; + case WIFI_PROV_END: + /* De-initialize manager once provisioning is finished */ + wifi_prov_mgr_deinit(); + break; + default: + break; } - case WIFI_PROV_CRED_FAIL: { - wifi_prov_sta_fail_reason_t *reason = (wifi_prov_sta_fail_reason_t *)event_data; - ESP_LOGE(TAG, "Provisioning failed!\n\tReason : %s" - "\n\tPlease reset to factory and retry provisioning", - (*reason == WIFI_PROV_STA_AUTH_ERROR) ? - "Wi-Fi AP password incorrect" : "Wi-Fi AP not found"); - break; - } - case WIFI_PROV_CRED_SUCCESS: - ESP_LOGI(TAG, "Provisioning successful"); - break; - case WIFI_PROV_END: - /* De-initialize manager once provisioning is finished */ - wifi_prov_mgr_deinit(); - break; - default: - break; + } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { + esp_wifi_connect(); + } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { + ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; + ESP_LOGI(TAG, "Connected with IP Address:%s", ip4addr_ntoa(&event->ip_info.ip)); + /* Signal main application to continue execution */ + xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_EVENT); + } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { + ESP_LOGI(TAG, "Disconnected. Connecting to the AP again..."); + esp_wifi_connect(); } } static void wifi_init_sta() { + /* Start Wi-Fi in station mode */ ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); ESP_ERROR_CHECK(esp_wifi_start()); } @@ -123,11 +106,18 @@ void app_main() ESP_ERROR_CHECK(nvs_flash_init()); } - /* Initialize TCP/IP and the event loop */ + /* Initialize TCP/IP */ tcpip_adapter_init(); - ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL)); + + /* Initialize the event loop */ + ESP_ERROR_CHECK(esp_event_loop_create_default()); wifi_event_group = xEventGroupCreate(); + /* Register our event handler for Wi-Fi, IP and Provisioning related events */ + ESP_ERROR_CHECK(esp_event_handler_register(WIFI_PROV_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL)); + /* Initialize Wi-Fi */ wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); @@ -146,14 +136,7 @@ void app_main() * appropriate scheme specific event handler allows the manager * to take care of this automatically. This can be set to * WIFI_PROV_EVENT_HANDLER_NONE when using wifi_prov_scheme_softap*/ - .scheme_event_handler = WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM, - - /* Do we want an application specific handler be executed on - * various provisioning related events */ - .app_event_handler = { - .event_cb = prov_event_handler, - .user_data = NULL - } + .scheme_event_handler = WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM }; /* Initialize provisioning manager with the @@ -219,7 +202,7 @@ void app_main() /* Uncomment the following to wait for the provisioning to finish and then release * the resources of the manager. Since in this case de-initialization is triggered - * by the configured prov_event_handler(), we don't need to call the following */ + * by the default event loop handler, we don't need to call the following */ // wifi_prov_mgr_wait(); // wifi_prov_mgr_deinit(); } else { From 9f1033862dc13fa1e565940ac147ef2655e1ea40 Mon Sep 17 00:00:00 2001 From: Anurag Kar Date: Fri, 28 Jun 2019 12:12:42 +0530 Subject: [PATCH 264/486] wifi_prov_mgr : Free memory allocated by cJSON_Print --- components/wifi_provisioning/src/manager.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/wifi_provisioning/src/manager.c b/components/wifi_provisioning/src/manager.c index 078a4b05d7..c2404dbc19 100644 --- a/components/wifi_provisioning/src/manager.c +++ b/components/wifi_provisioning/src/manager.c @@ -296,7 +296,9 @@ static esp_err_t wifi_prov_mgr_start_service(const char *service_name, const cha /* Set version information / capabilities of provisioning service and application */ cJSON *version_json = wifi_prov_get_info_json(); - ret = protocomm_set_version(prov_ctx->pc, "proto-ver", cJSON_Print(version_json)); + char *version_str = cJSON_Print(version_json); + ret = protocomm_set_version(prov_ctx->pc, "proto-ver", version_str); + free(version_str); cJSON_Delete(version_json); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to set version endpoint"); From 703e98eb98ff2ef7822a836b917c47e677c40b5a Mon Sep 17 00:00:00 2001 From: Anurag Kar Date: Wed, 3 Jul 2019 20:51:11 +0530 Subject: [PATCH 265/486] wifi_prov_mgr : Updated the set of WIFI_REASON_ codes used for setting WIFI_PROV_STA_AUTH_ERROR --- components/wifi_provisioning/src/manager.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/wifi_provisioning/src/manager.c b/components/wifi_provisioning/src/manager.c index c2404dbc19..3d7a8355cb 100644 --- a/components/wifi_provisioning/src/manager.c +++ b/components/wifi_provisioning/src/manager.c @@ -852,9 +852,8 @@ static void wifi_prov_mgr_event_handler_internal( switch (disconnected->reason) { case WIFI_REASON_AUTH_EXPIRE: case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT: - case WIFI_REASON_BEACON_TIMEOUT: case WIFI_REASON_AUTH_FAIL: - case WIFI_REASON_ASSOC_FAIL: + case WIFI_REASON_ASSOC_EXPIRE: case WIFI_REASON_HANDSHAKE_TIMEOUT: ESP_LOGE(TAG, "STA Auth Error"); prov_ctx->wifi_disconnect_reason = WIFI_PROV_STA_AUTH_ERROR; From 773ddcf0ffea7a18c5cfaa187bb8addc479d7350 Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Fri, 5 Jul 2019 14:13:02 +0530 Subject: [PATCH 266/486] wpa_supplicant: Remove tags file which was added by mistake Merge request idf/esp-idf!5219 added a ctags 'tags' file to the repository by mistake. Remove it. --- components/wpa_supplicant/tags | 5454 -------------------------------- 1 file changed, 5454 deletions(-) delete mode 100644 components/wpa_supplicant/tags diff --git a/components/wpa_supplicant/tags b/components/wpa_supplicant/tags deleted file mode 100644 index 781b954521..0000000000 --- a/components/wpa_supplicant/tags +++ /dev/null @@ -1,5454 +0,0 @@ -!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ -!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ -!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ -!_TAG_PROGRAM_NAME Exuberant Ctags // -!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ -!_TAG_PROGRAM_VERSION 5.9~svn20110310 // -ACCEPT_UNLESS_DENIED src/ap/ap_config.h /^ ACCEPT_UNLESS_DENIED = 0,$/;" e enum:hostapd_bss_config::__anon17 -ACK_FINISHED src/tls/tlsv1_client_i.h /^ SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, ACK_FINISHED,$/;" e enum:tlsv1_client::__anon43 -AES_BLOCK_SIZE include/crypto/aes.h 18;" d -AES_H include/crypto/aes.h 16;" d -AES_I_H src/crypto/aes_i.h 16;" d -AES_PRIV_NR_POS src/crypto/aes_i.h 127;" d -AES_PRIV_SIZE src/crypto/aes_i.h 126;" d -AES_SMALL_TABLES src/crypto/aes-internal.c 57;" d file: -AES_SMALL_TABLES src/crypto/aes_i.h 21;" d -AES_WRAP_H include/crypto/aes_wrap.h 23;" d -ALG_AES_CMAC src/common/defs.h /^ ALG_AES_CMAC,$/;" e enum:wifi_key_alg -ALG_CCMP src/common/defs.h /^ ALG_CCMP,$/;" e enum:wifi_key_alg -ALG_TKIP src/common/defs.h /^ ALG_TKIP,$/;" e enum:wifi_key_alg -ALG_WEP src/common/defs.h /^ ALG_WEP,$/;" e enum:wifi_key_alg -ANONYMOUS_ID_LEN_MAX src/esp_supplicant/esp_wpa_enterprise.c 937;" d file: -ANS1_TAG_RELATIVE_OID src/tls/asn1.h 24;" d -ANonce src/ap/wpa_auth_i.h /^ u8 ANonce[WPA_NONCE_LEN];$/;" m struct:wpa_state_machine -API_MUTEX_GIVE src/esp_supplicant/esp_wps.c 45;" d file: -API_MUTEX_TAKE src/esp_supplicant/esp_wps.c 34;" d file: -AP_DEAUTH_DELAY src/ap/sta_info.h 144;" d -AP_DISASSOC_DELAY src/ap/sta_info.h 143;" d -AP_MAX_INACTIVITY src/ap/sta_info.h 142;" d -AP_MAX_INACTIVITY_AFTER_DEAUTH src/ap/sta_info.h 149;" d -AP_MAX_INACTIVITY_AFTER_DISASSOC src/ap/sta_info.h 147;" d -AP_REJECTED_BLOCKED_STA src/common/wpa_ctrl.h 167;" d -AP_REJECTED_MAX_STA src/common/wpa_ctrl.h 166;" d -AP_STA_CONNECTED src/common/wpa_ctrl.h 163;" d -AP_STA_DISCONNECTED src/common/wpa_ctrl.h 164;" d -ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP src/common/ieee802_11_defs.h 442;" d -ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_CAP src/common/ieee802_11_defs.h 444;" d -ASEL_CAPABILITY_ASEL_CAPABLE src/common/ieee802_11_defs.h 440;" d -ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP src/common/ieee802_11_defs.h 441;" d -ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_CAP src/common/ieee802_11_defs.h 443;" d -ASEL_CAPABILITY_RX_AS_CAP src/common/ieee802_11_defs.h 445;" d -ASEL_CAPABILITY_TX_SOUND_PPDUS_CAP src/common/ieee802_11_defs.h 446;" d -ASN1_CLASS_APPLICATION src/tls/asn1.h 41;" d -ASN1_CLASS_CONTEXT_SPECIFIC src/tls/asn1.h 42;" d -ASN1_CLASS_PRIVATE src/tls/asn1.h 43;" d -ASN1_CLASS_UNIVERSAL src/tls/asn1.h 40;" d -ASN1_H src/tls/asn1.h 10;" d -ASN1_MAX_OID_LEN src/tls/asn1.h 52;" d -ASN1_TAG_BITSTRING src/tls/asn1.h 15;" d -ASN1_TAG_BMPSTRING src/tls/asn1.h 38;" d -ASN1_TAG_BOOLEAN src/tls/asn1.h 13;" d -ASN1_TAG_ENUMERATED src/tls/asn1.h 22;" d -ASN1_TAG_EOC src/tls/asn1.h 12;" d -ASN1_TAG_EXTERNAL src/tls/asn1.h 20;" d -ASN1_TAG_GENERALIZEDTIME src/tls/asn1.h 33;" d -ASN1_TAG_GENERALSTRING src/tls/asn1.h 36;" d -ASN1_TAG_GRAPHICSTRING src/tls/asn1.h 34;" d -ASN1_TAG_IA5STRING src/tls/asn1.h 31;" d -ASN1_TAG_INTEGER src/tls/asn1.h 14;" d -ASN1_TAG_NULL src/tls/asn1.h 17;" d -ASN1_TAG_NUMERICSTRING src/tls/asn1.h 27;" d -ASN1_TAG_OBJECT_DESCRIPTOR src/tls/asn1.h 19;" d -ASN1_TAG_OCTETSTRING src/tls/asn1.h 16;" d -ASN1_TAG_OID src/tls/asn1.h 18;" d -ASN1_TAG_PRINTABLESTRING src/tls/asn1.h 28;" d -ASN1_TAG_REAL src/tls/asn1.h 21;" d -ASN1_TAG_SEQUENCE src/tls/asn1.h 25;" d -ASN1_TAG_SET src/tls/asn1.h 26;" d -ASN1_TAG_TG1STRING src/tls/asn1.h 29;" d -ASN1_TAG_UNIVERSALSTRING src/tls/asn1.h 37;" d -ASN1_TAG_UTCTIME src/tls/asn1.h 32;" d -ASN1_TAG_UTF8STRING src/tls/asn1.h 23;" d -ASN1_TAG_VIDEOTEXSTRING src/tls/asn1.h 30;" d -ASN1_TAG_VISIBLESTRING src/tls/asn1.h 35;" d -ASSOC_IE_LEN src/rsn_supp/wpa.c 50;" d file: -ATTR_802_1X_ENABLED src/wps/wps_defs.h /^ ATTR_802_1X_ENABLED = 0x1062,$/;" e enum:wps_attribute -ATTR_APPLICATION_EXT src/wps/wps_defs.h /^ ATTR_APPLICATION_EXT = 0x1058,$/;" e enum:wps_attribute -ATTR_APPSESSIONKEY src/wps/wps_defs.h /^ ATTR_APPSESSIONKEY = 0x1063,$/;" e enum:wps_attribute -ATTR_AP_CHANNEL src/wps/wps_defs.h /^ ATTR_AP_CHANNEL = 0x1001,$/;" e enum:wps_attribute -ATTR_AP_SETUP_LOCKED src/wps/wps_defs.h /^ ATTR_AP_SETUP_LOCKED = 0x1057,$/;" e enum:wps_attribute -ATTR_ASSOC_STATE src/wps/wps_defs.h /^ ATTR_ASSOC_STATE = 0x1002,$/;" e enum:wps_attribute -ATTR_AUTHENTICATOR src/wps/wps_defs.h /^ ATTR_AUTHENTICATOR = 0x1005,$/;" e enum:wps_attribute -ATTR_AUTH_TYPE src/wps/wps_defs.h /^ ATTR_AUTH_TYPE = 0x1003,$/;" e enum:wps_attribute -ATTR_AUTH_TYPE_FLAGS src/wps/wps_defs.h /^ ATTR_AUTH_TYPE_FLAGS = 0x1004,$/;" e enum:wps_attribute -ATTR_CONFIG_ERROR src/wps/wps_defs.h /^ ATTR_CONFIG_ERROR = 0x1009,$/;" e enum:wps_attribute -ATTR_CONFIG_METHODS src/wps/wps_defs.h /^ ATTR_CONFIG_METHODS = 0x1008,$/;" e enum:wps_attribute -ATTR_CONFIRM_URL4 src/wps/wps_defs.h /^ ATTR_CONFIRM_URL4 = 0x100a,$/;" e enum:wps_attribute -ATTR_CONFIRM_URL6 src/wps/wps_defs.h /^ ATTR_CONFIRM_URL6 = 0x100b,$/;" e enum:wps_attribute -ATTR_CONN_TYPE src/wps/wps_defs.h /^ ATTR_CONN_TYPE = 0x100c,$/;" e enum:wps_attribute -ATTR_CONN_TYPE_FLAGS src/wps/wps_defs.h /^ ATTR_CONN_TYPE_FLAGS = 0x100d,$/;" e enum:wps_attribute -ATTR_CRED src/wps/wps_defs.h /^ ATTR_CRED = 0x100e,$/;" e enum:wps_attribute -ATTR_DEV_NAME src/wps/wps_defs.h /^ ATTR_DEV_NAME = 0x1011,$/;" e enum:wps_attribute -ATTR_DEV_PASSWORD_ID src/wps/wps_defs.h /^ ATTR_DEV_PASSWORD_ID = 0x1012,$/;" e enum:wps_attribute -ATTR_EAP_IDENTITY src/wps/wps_defs.h /^ ATTR_EAP_IDENTITY = 0x104d,$/;" e enum:wps_attribute -ATTR_EAP_TYPE src/wps/wps_defs.h /^ ATTR_EAP_TYPE = 0x1059,$/;" e enum:wps_attribute -ATTR_ENCR_SETTINGS src/wps/wps_defs.h /^ ATTR_ENCR_SETTINGS = 0x1018,$/;" e enum:wps_attribute -ATTR_ENCR_TYPE src/wps/wps_defs.h /^ ATTR_ENCR_TYPE = 0x100f,$/;" e enum:wps_attribute -ATTR_ENCR_TYPE_FLAGS src/wps/wps_defs.h /^ ATTR_ENCR_TYPE_FLAGS = 0x1010,$/;" e enum:wps_attribute -ATTR_ENROLLEE_NONCE src/wps/wps_defs.h /^ ATTR_ENROLLEE_NONCE = 0x101a,$/;" e enum:wps_attribute -ATTR_EXTENSIBILITY_TEST src/wps/wps_defs.h /^ ATTR_EXTENSIBILITY_TEST = 0x10fa \/* _NOT_ defined in the spec *\/$/;" e enum:wps_attribute -ATTR_E_HASH1 src/wps/wps_defs.h /^ ATTR_E_HASH1 = 0x1014,$/;" e enum:wps_attribute -ATTR_E_HASH2 src/wps/wps_defs.h /^ ATTR_E_HASH2 = 0x1015,$/;" e enum:wps_attribute -ATTR_E_SNONCE1 src/wps/wps_defs.h /^ ATTR_E_SNONCE1 = 0x1016,$/;" e enum:wps_attribute -ATTR_E_SNONCE2 src/wps/wps_defs.h /^ ATTR_E_SNONCE2 = 0x1017,$/;" e enum:wps_attribute -ATTR_FEATURE_ID src/wps/wps_defs.h /^ ATTR_FEATURE_ID = 0x101b,$/;" e enum:wps_attribute -ATTR_IDENTITY src/wps/wps_defs.h /^ ATTR_IDENTITY = 0x101c,$/;" e enum:wps_attribute -ATTR_IDENTITY_PROOF src/wps/wps_defs.h /^ ATTR_IDENTITY_PROOF = 0x101d,$/;" e enum:wps_attribute -ATTR_IV src/wps/wps_defs.h /^ ATTR_IV = 0x1060,$/;" e enum:wps_attribute -ATTR_KEY_ID src/wps/wps_defs.h /^ ATTR_KEY_ID = 0x101f,$/;" e enum:wps_attribute -ATTR_KEY_LIFETIME src/wps/wps_defs.h /^ ATTR_KEY_LIFETIME = 0x1051,$/;" e enum:wps_attribute -ATTR_KEY_PROVIDED_AUTO src/wps/wps_defs.h /^ ATTR_KEY_PROVIDED_AUTO = 0x1061,$/;" e enum:wps_attribute -ATTR_KEY_WRAP_AUTH src/wps/wps_defs.h /^ ATTR_KEY_WRAP_AUTH = 0x101e,$/;" e enum:wps_attribute -ATTR_MAC_ADDR src/wps/wps_defs.h /^ ATTR_MAC_ADDR = 0x1020,$/;" e enum:wps_attribute -ATTR_MANUFACTURER src/wps/wps_defs.h /^ ATTR_MANUFACTURER = 0x1021,$/;" e enum:wps_attribute -ATTR_MODEL_NAME src/wps/wps_defs.h /^ ATTR_MODEL_NAME = 0x1023,$/;" e enum:wps_attribute -ATTR_MODEL_NUMBER src/wps/wps_defs.h /^ ATTR_MODEL_NUMBER = 0x1024,$/;" e enum:wps_attribute -ATTR_MSG_COUNTER src/wps/wps_defs.h /^ ATTR_MSG_COUNTER = 0x104e,$/;" e enum:wps_attribute -ATTR_MSG_TYPE src/wps/wps_defs.h /^ ATTR_MSG_TYPE = 0x1022,$/;" e enum:wps_attribute -ATTR_NETWORK_INDEX src/wps/wps_defs.h /^ ATTR_NETWORK_INDEX = 0x1026,$/;" e enum:wps_attribute -ATTR_NETWORK_KEY src/wps/wps_defs.h /^ ATTR_NETWORK_KEY = 0x1027,$/;" e enum:wps_attribute -ATTR_NETWORK_KEY_INDEX src/wps/wps_defs.h /^ ATTR_NETWORK_KEY_INDEX = 0x1028,$/;" e enum:wps_attribute -ATTR_NEW_DEVICE_NAME src/wps/wps_defs.h /^ ATTR_NEW_DEVICE_NAME = 0x1029,$/;" e enum:wps_attribute -ATTR_NEW_PASSWORD src/wps/wps_defs.h /^ ATTR_NEW_PASSWORD = 0x102a,$/;" e enum:wps_attribute -ATTR_OOB_DEVICE_PASSWORD src/wps/wps_defs.h /^ ATTR_OOB_DEVICE_PASSWORD = 0x102c,$/;" e enum:wps_attribute -ATTR_OS_VERSION src/wps/wps_defs.h /^ ATTR_OS_VERSION = 0x102d,$/;" e enum:wps_attribute -ATTR_PERMITTED_CFG_METHODS src/wps/wps_defs.h /^ ATTR_PERMITTED_CFG_METHODS = 0x1052,$/;" e enum:wps_attribute -ATTR_PORTABLE_DEV src/wps/wps_defs.h /^ ATTR_PORTABLE_DEV = 0x1056,$/;" e enum:wps_attribute -ATTR_POWER_LEVEL src/wps/wps_defs.h /^ ATTR_POWER_LEVEL = 0x102f,$/;" e enum:wps_attribute -ATTR_PRIMARY_DEV_TYPE src/wps/wps_defs.h /^ ATTR_PRIMARY_DEV_TYPE = 0x1054,$/;" e enum:wps_attribute -ATTR_PSK_CURRENT src/wps/wps_defs.h /^ ATTR_PSK_CURRENT = 0x1030,$/;" e enum:wps_attribute -ATTR_PSK_MAX src/wps/wps_defs.h /^ ATTR_PSK_MAX = 0x1031,$/;" e enum:wps_attribute -ATTR_PUBKEY_HASH src/wps/wps_defs.h /^ ATTR_PUBKEY_HASH = 0x104f,$/;" e enum:wps_attribute -ATTR_PUBLIC_KEY src/wps/wps_defs.h /^ ATTR_PUBLIC_KEY = 0x1032,$/;" e enum:wps_attribute -ATTR_RADIO_ENABLE src/wps/wps_defs.h /^ ATTR_RADIO_ENABLE = 0x1033,$/;" e enum:wps_attribute -ATTR_REBOOT src/wps/wps_defs.h /^ ATTR_REBOOT = 0x1034,$/;" e enum:wps_attribute -ATTR_REGISTRAR_CURRENT src/wps/wps_defs.h /^ ATTR_REGISTRAR_CURRENT = 0x1035,$/;" e enum:wps_attribute -ATTR_REGISTRAR_ESTABLISHED src/wps/wps_defs.h /^ ATTR_REGISTRAR_ESTABLISHED = 0x1036,$/;" e enum:wps_attribute -ATTR_REGISTRAR_LIST src/wps/wps_defs.h /^ ATTR_REGISTRAR_LIST = 0x1037,$/;" e enum:wps_attribute -ATTR_REGISTRAR_MAX src/wps/wps_defs.h /^ ATTR_REGISTRAR_MAX = 0x1038,$/;" e enum:wps_attribute -ATTR_REGISTRAR_NONCE src/wps/wps_defs.h /^ ATTR_REGISTRAR_NONCE = 0x1039,$/;" e enum:wps_attribute -ATTR_REKEY_KEY src/wps/wps_defs.h /^ ATTR_REKEY_KEY = 0x1050,$/;" e enum:wps_attribute -ATTR_REQUESTED_DEV_TYPE src/wps/wps_defs.h /^ ATTR_REQUESTED_DEV_TYPE = 0x106a,$/;" e enum:wps_attribute -ATTR_REQUEST_TYPE src/wps/wps_defs.h /^ ATTR_REQUEST_TYPE = 0x103a,$/;" e enum:wps_attribute -ATTR_RESPONSE_TYPE src/wps/wps_defs.h /^ ATTR_RESPONSE_TYPE = 0x103b,$/;" e enum:wps_attribute -ATTR_RF_BANDS src/wps/wps_defs.h /^ ATTR_RF_BANDS = 0x103c,$/;" e enum:wps_attribute -ATTR_R_HASH1 src/wps/wps_defs.h /^ ATTR_R_HASH1 = 0x103d,$/;" e enum:wps_attribute -ATTR_R_HASH2 src/wps/wps_defs.h /^ ATTR_R_HASH2 = 0x103e,$/;" e enum:wps_attribute -ATTR_R_SNONCE1 src/wps/wps_defs.h /^ ATTR_R_SNONCE1 = 0x103f,$/;" e enum:wps_attribute -ATTR_R_SNONCE2 src/wps/wps_defs.h /^ ATTR_R_SNONCE2 = 0x1040,$/;" e enum:wps_attribute -ATTR_SECONDARY_DEV_TYPE_LIST src/wps/wps_defs.h /^ ATTR_SECONDARY_DEV_TYPE_LIST = 0x1055,$/;" e enum:wps_attribute -ATTR_SELECTED_REGISTRAR src/wps/wps_defs.h /^ ATTR_SELECTED_REGISTRAR = 0x1041,$/;" e enum:wps_attribute -ATTR_SELECTED_REGISTRAR_CONFIG_METHODS src/wps/wps_defs.h /^ ATTR_SELECTED_REGISTRAR_CONFIG_METHODS = 0x1053,$/;" e enum:wps_attribute -ATTR_SERIAL_NUMBER src/wps/wps_defs.h /^ ATTR_SERIAL_NUMBER = 0x1042,$/;" e enum:wps_attribute -ATTR_SSID src/wps/wps_defs.h /^ ATTR_SSID = 0x1045,$/;" e enum:wps_attribute -ATTR_TOTAL_NETWORKS src/wps/wps_defs.h /^ ATTR_TOTAL_NETWORKS = 0x1046,$/;" e enum:wps_attribute -ATTR_UUID_E src/wps/wps_defs.h /^ ATTR_UUID_E = 0x1047,$/;" e enum:wps_attribute -ATTR_UUID_R src/wps/wps_defs.h /^ ATTR_UUID_R = 0x1048,$/;" e enum:wps_attribute -ATTR_VENDOR_EXT src/wps/wps_defs.h /^ ATTR_VENDOR_EXT = 0x1049,$/;" e enum:wps_attribute -ATTR_VERSION src/wps/wps_defs.h /^ ATTR_VERSION = 0x104a,$/;" e enum:wps_attribute -ATTR_WEPTRANSMITKEY src/wps/wps_defs.h /^ ATTR_WEPTRANSMITKEY = 0x1064,$/;" e enum:wps_attribute -ATTR_WPS_STATE src/wps/wps_defs.h /^ ATTR_WPS_STATE = 0x1044,$/;" e enum:wps_attribute -ATTR_X509_CERT src/wps/wps_defs.h /^ ATTR_X509_CERT = 0x104c,$/;" e enum:wps_attribute -ATTR_X509_CERT_REQ src/wps/wps_defs.h /^ ATTR_X509_CERT_REQ = 0x104b,$/;" e enum:wps_attribute -AVP_FLAGS_MANDATORY src/eap_peer/eap_ttls.h 29;" d -AVP_FLAGS_VENDOR src/eap_peer/eap_ttls.h 28;" d -AVP_PAD src/eap_peer/eap_ttls.h 31;" d -AuthenticationRequest src/ap/wpa_auth_i.h /^ Boolean AuthenticationRequest;$/;" m struct:wpa_state_machine -BASE64_H src/utils/base64.h 16;" d -BIGNUM_H src/crypto/bignum.h 16;" d -BIGNUM_H src/tls/bignum.h 16;" d -BIG_ENDIAN port/include/endian.h 37;" d -BIT include/utils/common.h 264;" d -BLOB_NAME_LEN src/eap_peer/eap_i.h 98;" d -BLOB_NUM src/eap_peer/eap_i.h 99;" d -BN_FAST_MP_MONTGOMERY_REDUCE_C src/crypto/libtommath.h 42;" d -BN_FAST_MP_MONTGOMERY_REDUCE_C src/tls/libtommath.h 44;" d -BN_FAST_S_MP_SQR_C src/crypto/libtommath.h 47;" d -BN_FAST_S_MP_SQR_C src/tls/libtommath.h 49;" d -BN_MP_ABS_C src/crypto/libtommath.h 54;" d -BN_MP_ABS_C src/tls/libtommath.h 56;" d -BN_MP_CLEAR_MULTI_C src/crypto/libtommath.h 53;" d -BN_MP_CLEAR_MULTI_C src/tls/libtommath.h 55;" d -BN_MP_DIV_SMALL src/crypto/libtommath.h 51;" d -BN_MP_DIV_SMALL src/tls/libtommath.h 53;" d -BN_MP_EXPTMOD_FAST_C src/crypto/libtommath.h 40;" d -BN_MP_EXPTMOD_FAST_C src/tls/libtommath.h 42;" d -BN_MP_INIT_MULTI_C src/crypto/libtommath.h 52;" d -BN_MP_INIT_MULTI_C src/tls/libtommath.h 54;" d -BN_MP_INVMOD_C src/crypto/libtommath.h 25;" d -BN_MP_INVMOD_C src/tls/libtommath.h 27;" d -BN_MP_INVMOD_SLOW_C src/crypto/libtommath.h 29;" d -BN_MP_INVMOD_SLOW_C src/tls/libtommath.h 31;" d -BN_MP_MONTGOMERY_CALC_NORMALIZATION_C src/crypto/libtommath.h 43;" d -BN_MP_MONTGOMERY_CALC_NORMALIZATION_C src/tls/libtommath.h 45;" d -BN_MP_MONTGOMERY_SETUP_C src/crypto/libtommath.h 41;" d -BN_MP_MONTGOMERY_SETUP_C src/tls/libtommath.h 43;" d -BN_MP_MUL_2_C src/crypto/libtommath.h 44;" d -BN_MP_MUL_2_C src/tls/libtommath.h 46;" d -BN_MP_MUL_D_C src/crypto/libtommath.h 37;" d -BN_MP_MUL_D_C src/tls/libtommath.h 39;" d -BN_S_MP_EXPTMOD_C src/crypto/libtommath.h 26;" d -BN_S_MP_EXPTMOD_C src/tls/libtommath.h 28;" d -BN_S_MP_MUL_DIGS_C src/crypto/libtommath.h 28;" d -BN_S_MP_MUL_DIGS_C src/tls/libtommath.h 30;" d -BN_S_MP_MUL_HIGH_DIGS_C src/crypto/libtommath.h 31;" d -BN_S_MP_MUL_HIGH_DIGS_C src/tls/libtommath.h 33;" d -BN_S_MP_SQR_C src/crypto/libtommath.h 30;" d -BN_S_MP_SQR_C src/tls/libtommath.h 32;" d -BYTESWAP_H port/include/byteswap.h 6;" d -BYTES_TO_T_UINT_2 test/test_crypto.c 295;" d file: -BYTES_TO_T_UINT_2 test/test_crypto.c 317;" d file: -BYTES_TO_T_UINT_4 test/test_crypto.c 289;" d file: -BYTES_TO_T_UINT_4 test/test_crypto.c 314;" d file: -BYTES_TO_T_UINT_8 test/test_crypto.c 298;" d file: -BYTES_TO_T_UINT_8 test/test_crypto.c 304;" d file: -BYTE_ORDER port/include/endian.h 45;" d -BYTE_ORDER port/include/endian.h 47;" d -Boolean src/common/defs.h /^typedef enum { FALSE = 0, TRUE = 1 } Boolean;$/;" t typeref:enum:__anon87 -CA_CERT_NAME src/eap_peer/eap_i.h 96;" d -CERTIFICATE_VERIFY src/tls/tlsv1_server_i.h /^ CERTIFICATE_VERIFY, CHANGE_CIPHER_SPEC, CLIENT_FINISHED,$/;" e enum:tlsv1_server::__anon39 -CHANGE_CIPHER_SPEC src/tls/tlsv1_client_i.h /^ SERVER_HELLO_DONE, CLIENT_KEY_EXCHANGE, CHANGE_CIPHER_SPEC,$/;" e enum:tlsv1_client::__anon43 -CHANGE_CIPHER_SPEC src/tls/tlsv1_server_i.h /^ CERTIFICATE_VERIFY, CHANGE_CIPHER_SPEC, CLIENT_FINISHED,$/;" e enum:tlsv1_server::__anon39 -CHAR_BIT src/crypto/libtommath.h 22;" d -CHAR_BIT src/tls/libtommath.h 24;" d -CIPHER_CCMP src/common/defs.h /^ CIPHER_CCMP,$/;" e enum:wpa_cipher -CIPHER_NONE src/common/defs.h /^ CIPHER_NONE,$/;" e enum:wpa_cipher -CIPHER_TKIP src/common/defs.h /^ CIPHER_TKIP,$/;" e enum:wpa_cipher -CIPHER_WEP104 src/common/defs.h /^ CIPHER_WEP104$/;" e enum:wpa_cipher -CIPHER_WEP40 src/common/defs.h /^ CIPHER_WEP40,$/;" e enum:wpa_cipher -CLIENT_CERTIFICATE src/tls/tlsv1_server_i.h /^ SERVER_HELLO_DONE, CLIENT_CERTIFICATE, CLIENT_KEY_EXCHANGE,$/;" e enum:tlsv1_server::__anon39 -CLIENT_CERT_NAME src/eap_peer/eap_i.h 95;" d -CLIENT_FINISHED src/tls/tlsv1_server_i.h /^ CERTIFICATE_VERIFY, CHANGE_CIPHER_SPEC, CLIENT_FINISHED,$/;" e enum:tlsv1_server::__anon39 -CLIENT_HELLO src/tls/tlsv1_client_i.h /^ CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,$/;" e enum:tlsv1_client::__anon43 -CLIENT_HELLO src/tls/tlsv1_server_i.h /^ CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,$/;" e enum:tlsv1_server::__anon39 -CLIENT_KEY_EXCHANGE src/tls/tlsv1_client_i.h /^ SERVER_HELLO_DONE, CLIENT_KEY_EXCHANGE, CHANGE_CIPHER_SPEC,$/;" e enum:tlsv1_client::__anon43 -CLIENT_KEY_EXCHANGE src/tls/tlsv1_server_i.h /^ SERVER_HELLO_DONE, CLIENT_CERTIFICATE, CLIENT_KEY_EXCHANGE,$/;" e enum:tlsv1_server::__anon39 -COMMON_H include/utils/common.h 16;" d -COMPONENT_ADD_INCLUDEDIRS component.mk /^COMPONENT_ADD_INCLUDEDIRS := include port\/include include\/esp_supplicant$/;" m -COMPONENT_ADD_LDFLAGS test/component.mk /^COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive$/;" m -COMPONENT_PRIV_INCLUDEDIRS component.mk /^COMPONENT_PRIV_INCLUDEDIRS := src$/;" m -COMPONENT_SRCDIRS component.mk /^COMPONENT_SRCDIRS := port src\/ap src\/common src\/crypto src\/eap_peer src\/fast_crypto src\/rsn_supp src\/tls src\/utils src\/esp_supplicant src\/wps$/;" m -CONFIG_INTERNAL_LIBTOMMATH src/crypto/bignum.c 21;" d file: -CONFIG_INTERNAL_LIBTOMMATH src/tls/bignum.c 21;" d file: -CONFIG_NO_RANDOM_POOL include/crypto/random.h 18;" d -CONFIG_TLS_INTERNAL_CLIENT src/tls/tls_internal.c 22;" d file: -CONFIG_WPS_STRICT src/wps/wps_defs.h 28;" d -CRYPTO_CIPHER_ALG_3DES include/crypto/crypto.h /^ CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES,$/;" e enum:crypto_cipher_alg -CRYPTO_CIPHER_ALG_AES include/crypto/crypto.h /^ CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES,$/;" e enum:crypto_cipher_alg -CRYPTO_CIPHER_ALG_DES include/crypto/crypto.h /^ CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4$/;" e enum:crypto_cipher_alg -CRYPTO_CIPHER_ALG_RC2 include/crypto/crypto.h /^ CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4$/;" e enum:crypto_cipher_alg -CRYPTO_CIPHER_ALG_RC4 include/crypto/crypto.h /^ CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4$/;" e enum:crypto_cipher_alg -CRYPTO_CIPHER_NULL include/crypto/crypto.h /^ CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES,$/;" e enum:crypto_cipher_alg -CRYPTO_H include/crypto/crypto.h 28;" d -CRYPTO_HASH_ALG_HMAC_MD5 include/crypto/crypto.h /^ CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1,$/;" e enum:crypto_hash_alg -CRYPTO_HASH_ALG_HMAC_SHA1 include/crypto/crypto.h /^ CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1,$/;" e enum:crypto_hash_alg -CRYPTO_HASH_ALG_HMAC_SHA256 include/crypto/crypto.h /^ CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256$/;" e enum:crypto_hash_alg -CRYPTO_HASH_ALG_MD5 include/crypto/crypto.h /^ CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1,$/;" e enum:crypto_hash_alg -CRYPTO_HASH_ALG_SHA1 include/crypto/crypto.h /^ CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1,$/;" e enum:crypto_hash_alg -CRYPTO_HASH_ALG_SHA256 include/crypto/crypto.h /^ CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256$/;" e enum:crypto_hash_alg -Ch src/crypto/sha256-internal.c 87;" d file: -Counter src/ap/wpa_auth_i.h /^ u8 Counter[WPA_NONCE_LEN];$/;" m struct:wpa_group -DATA_MUTEX_GIVE src/esp_supplicant/esp_wps.c 47;" d file: -DATA_MUTEX_TAKE src/esp_supplicant/esp_wps.c 46;" d file: -DEBUG_PRINT include/utils/wpa_debug.h 61;" d -DECISION_COND_SUCC src/eap_peer/eap_i.h /^ DECISION_FAIL, DECISION_COND_SUCC, DECISION_UNCOND_SUCC$/;" e enum:__anon1 -DECISION_FAIL src/eap_peer/eap_i.h /^ DECISION_FAIL, DECISION_COND_SUCC, DECISION_UNCOND_SUCC$/;" e enum:__anon1 -DECISION_UNCOND_SUCC src/eap_peer/eap_i.h /^ DECISION_FAIL, DECISION_COND_SUCC, DECISION_UNCOND_SUCC$/;" e enum:__anon1 -DEFINE_DL_LIST src/utils/list.h 100;" d -DEFS_H src/common/defs.h 16;" d -DENY_UNLESS_ACCEPTED src/ap/ap_config.h /^ DENY_UNLESS_ACCEPTED = 1,$/;" e enum:hostapd_bss_config::__anon17 -DES_I_H src/crypto/des_i.h 10;" d -DEV_PW_DEFAULT src/wps/wps_defs.h /^ DEV_PW_DEFAULT = 0x0000,$/;" e enum:wps_dev_password_id -DEV_PW_MACHINE_SPECIFIED src/wps/wps_defs.h /^ DEV_PW_MACHINE_SPECIFIED = 0x0002,$/;" e enum:wps_dev_password_id -DEV_PW_PUSHBUTTON src/wps/wps_defs.h /^ DEV_PW_PUSHBUTTON = 0x0004,$/;" e enum:wps_dev_password_id -DEV_PW_REGISTRAR_SPECIFIED src/wps/wps_defs.h /^ DEV_PW_REGISTRAR_SPECIFIED = 0x0005$/;" e enum:wps_dev_password_id -DEV_PW_REKEY src/wps/wps_defs.h /^ DEV_PW_REKEY = 0x0003,$/;" e enum:wps_dev_password_id -DEV_PW_USER_SPECIFIED src/wps/wps_defs.h /^ DEV_PW_USER_SPECIFIED = 0x0001,$/;" e enum:wps_dev_password_id -DH_GROUP src/crypto/dh_groups.c 518;" d file: -DH_GROUP5_H include/crypto/dh_group5.h 16;" d -DH_GROUPS_H include/crypto/dh_groups.h 16;" d -DIGIT_BIT src/crypto/libtommath.h 76;" d -DIGIT_BIT src/tls/libtommath.h 78;" d -DeauthenticationRequest src/ap/wpa_auth_i.h /^ Boolean DeauthenticationRequest;$/;" m struct:wpa_state_machine -Disconnect src/ap/wpa_auth_i.h /^ Boolean Disconnect;$/;" m struct:wpa_state_machine -EAPOLKeyPairwise src/ap/wpa_auth_i.h /^ Boolean EAPOLKeyPairwise;$/;" m struct:wpa_state_machine -EAPOLKeyReceived src/ap/wpa_auth_i.h /^ Boolean EAPOLKeyReceived;$/;" m struct:wpa_state_machine -EAPOLKeyRequest src/ap/wpa_auth_i.h /^ Boolean EAPOLKeyRequest;$/;" m struct:wpa_state_machine -EAPOL_COMMON_H src/common/eapol_common.h 16;" d -EAPOL_KEY_TYPE_RC4 src/common/eapol_common.h /^enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,$/;" e enum:__anon86 -EAPOL_KEY_TYPE_RSN src/common/eapol_common.h /^enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,$/;" e enum:__anon86 -EAPOL_KEY_TYPE_WPA src/common/eapol_common.h /^ EAPOL_KEY_TYPE_WPA = 254 };$/;" e enum:__anon86 -EAPOL_VERSION src/common/eapol_common.h 28;" d -EAP_CODE_FAILURE src/eap_peer/eap_defs.h /^ EAP_CODE_FAILURE = 4 };$/;" e enum:__anon4 -EAP_CODE_REQUEST src/eap_peer/eap_defs.h /^enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,$/;" e enum:__anon4 -EAP_CODE_RESPONSE src/eap_peer/eap_defs.h /^enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,$/;" e enum:__anon4 -EAP_CODE_SUCCESS src/eap_peer/eap_defs.h /^enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,$/;" e enum:__anon4 -EAP_COMMON_H src/eap_peer/eap_common.h 10;" d -EAP_CONFIG_FLAGS_EXT_PASSWORD src/eap_peer/eap_config.h 196;" d -EAP_CONFIG_FLAGS_PASSWORD_NTHASH src/eap_peer/eap_config.h 195;" d -EAP_CONFIG_H src/eap_peer/eap_config.h 10;" d -EAP_DEFS_H src/eap_peer/eap_defs.h 10;" d -EAP_EMSK_LEN src/eap_peer/eap_defs.h 90;" d -EAP_H src/eap_peer/eap.h 10;" d -EAP_I_H src/eap_peer/eap_i.h 10;" d -EAP_METHODS_H src/eap_peer/eap_methods.h 10;" d -EAP_MSK_LEN src/eap_peer/eap_defs.h 89;" d -EAP_PEAP_COMMON_H src/eap_peer/eap_peap_common.h 10;" d -EAP_PEAP_VERSION src/eap_peer/eap_peap.c 28;" d file: -EAP_TLS_COMMON_H src/eap_peer/eap_tls_common.h 10;" d -EAP_TLS_FLAGS_LENGTH_INCLUDED src/eap_peer/eap_tls_common.h 80;" d -EAP_TLS_FLAGS_MORE_FRAGMENTS src/eap_peer/eap_tls_common.h 81;" d -EAP_TLS_FLAGS_START src/eap_peer/eap_tls_common.h 82;" d -EAP_TLS_H src/eap_peer/eap_tls.h 10;" d -EAP_TLS_KEY_LEN src/eap_peer/eap_tls_common.h 86;" d -EAP_TLS_VERSION_MASK src/eap_peer/eap_tls_common.h 83;" d -EAP_TLV_ACTION_NEGOTIATE_EAP src/eap_peer/eap_tlv_common.h 110;" d -EAP_TLV_ACTION_PROCESS_TLV src/eap_peer/eap_tlv_common.h 109;" d -EAP_TLV_CALLED_STATION_ID_TLV src/eap_peer/eap_tlv_common.h 24;" d -EAP_TLV_CALLING_STATION_ID_TLV src/eap_peer/eap_tlv_common.h 23;" d -EAP_TLV_COMMON_H src/eap_peer/eap_tlv_common.h 10;" d -EAP_TLV_CONNECTION_BINDING_TLV src/eap_peer/eap_tlv_common.h 16;" d -EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST src/eap_peer/eap_tlv_common.h 106;" d -EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE src/eap_peer/eap_tlv_common.h 107;" d -EAP_TLV_CRYPTO_BINDING_TLV src/eap_peer/eap_tlv_common.h 22;" d -EAP_TLV_EAP_PAYLOAD_TLV src/eap_peer/eap_tlv_common.h 19;" d -EAP_TLV_ERROR_CODE_TLV src/eap_peer/eap_tlv_common.h 15;" d -EAP_TLV_IDENTITY_TYPE_TLV src/eap_peer/eap_tlv_common.h 27;" d -EAP_TLV_INTERMEDIATE_RESULT_TLV src/eap_peer/eap_tlv_common.h 20;" d -EAP_TLV_NAK_TLV src/eap_peer/eap_tlv_common.h 14;" d -EAP_TLV_NAS_PORT_TYPE_TLV src/eap_peer/eap_tlv_common.h 25;" d -EAP_TLV_PAC_TLV src/eap_peer/eap_tlv_common.h 21;" d -EAP_TLV_PKCS7_TLV src/eap_peer/eap_tlv_common.h 30;" d -EAP_TLV_REQUEST_ACTION_TLV src/eap_peer/eap_tlv_common.h 29;" d -EAP_TLV_RESULT_FAILURE src/eap_peer/eap_tlv_common.h 33;" d -EAP_TLV_RESULT_SUCCESS src/eap_peer/eap_tlv_common.h 32;" d -EAP_TLV_RESULT_TLV src/eap_peer/eap_tlv_common.h 13;" d -EAP_TLV_SERVER_IDENTIFIER_TLV src/eap_peer/eap_tlv_common.h 26;" d -EAP_TLV_SERVER_TRUSTED_ROOT_TLV src/eap_peer/eap_tlv_common.h 28;" d -EAP_TLV_TYPE_MANDATORY src/eap_peer/eap_tlv_common.h 35;" d -EAP_TLV_TYPE_MASK src/eap_peer/eap_tlv_common.h 36;" d -EAP_TLV_URI_TLV src/eap_peer/eap_tlv_common.h 18;" d -EAP_TLV_VENDOR_SPECIFIC_TLV src/eap_peer/eap_tlv_common.h 17;" d -EAP_TTLS_CHAP_CHALLENGE_LEN src/eap_peer/eap_ttls.h 62;" d -EAP_TTLS_CHAP_PASSWORD_LEN src/eap_peer/eap_ttls.h 63;" d -EAP_TTLS_H src/eap_peer/eap_ttls.h 10;" d -EAP_TTLS_MSCHAPV2_CHALLENGE_LEN src/eap_peer/eap_ttls.h 58;" d -EAP_TTLS_MSCHAPV2_RESPONSE_LEN src/eap_peer/eap_ttls.h 59;" d -EAP_TTLS_MSCHAP_CHALLENGE_LEN src/eap_peer/eap_ttls.h 60;" d -EAP_TTLS_MSCHAP_RESPONSE_LEN src/eap_peer/eap_ttls.h 61;" d -EAP_TTLS_PHASE2_CHAP src/eap_peer/eap_ttls.c /^ EAP_TTLS_PHASE2_CHAP$/;" e enum:eap_ttls_data::phase2_types file: -EAP_TTLS_PHASE2_EAP src/eap_peer/eap_ttls.c /^ EAP_TTLS_PHASE2_EAP,$/;" e enum:eap_ttls_data::phase2_types file: -EAP_TTLS_PHASE2_MSCHAP src/eap_peer/eap_ttls.c /^ EAP_TTLS_PHASE2_MSCHAP,$/;" e enum:eap_ttls_data::phase2_types file: -EAP_TTLS_PHASE2_MSCHAPV2 src/eap_peer/eap_ttls.c /^ EAP_TTLS_PHASE2_MSCHAPV2,$/;" e enum:eap_ttls_data::phase2_types file: -EAP_TTLS_PHASE2_PAP src/eap_peer/eap_ttls.c /^ EAP_TTLS_PHASE2_PAP,$/;" e enum:eap_ttls_data::phase2_types file: -EAP_TTLS_VERSION src/eap_peer/eap_ttls.c 28;" d file: -EAP_TYPE_AKA src/eap_peer/eap_defs.h /^ EAP_TYPE_AKA = 23 \/* RFC 4187 *\/,$/;" e enum:__anon5 -EAP_TYPE_AKA_PRIME src/eap_peer/eap_defs.h /^ EAP_TYPE_AKA_PRIME = 50 \/* RFC 5448 *\/,$/;" e enum:__anon5 -EAP_TYPE_EKE src/eap_peer/eap_defs.h /^ EAP_TYPE_EKE = 53 \/* RFC 6124 *\/,$/;" e enum:__anon5 -EAP_TYPE_EXPANDED src/eap_peer/eap_defs.h /^ EAP_TYPE_EXPANDED = 254 \/* RFC 3748 *\/$/;" e enum:__anon5 -EAP_TYPE_FAST src/eap_peer/eap_defs.h /^ EAP_TYPE_FAST = 43 \/* RFC 4851 *\/,$/;" e enum:__anon5 -EAP_TYPE_GPSK src/eap_peer/eap_defs.h /^ EAP_TYPE_GPSK = 51 \/* RFC 5433 *\/,$/;" e enum:__anon5 -EAP_TYPE_GTC src/eap_peer/eap_defs.h /^ EAP_TYPE_GTC = 6, \/* RFC 3748 *\/$/;" e enum:__anon5 -EAP_TYPE_IDENTITY src/eap_peer/eap_defs.h /^ EAP_TYPE_IDENTITY = 1 \/* RFC 3748 *\/,$/;" e enum:__anon5 -EAP_TYPE_IKEV2 src/eap_peer/eap_defs.h /^ EAP_TYPE_IKEV2 = 49 \/* RFC 5106 *\/,$/;" e enum:__anon5 -EAP_TYPE_LEAP src/eap_peer/eap_defs.h /^ EAP_TYPE_LEAP = 17 \/* Cisco proprietary *\/,$/;" e enum:__anon5 -EAP_TYPE_MD5 src/eap_peer/eap_defs.h /^ EAP_TYPE_MD5 = 4, \/* RFC 3748 *\/$/;" e enum:__anon5 -EAP_TYPE_MSCHAPV2 src/eap_peer/eap_defs.h /^ EAP_TYPE_MSCHAPV2 = 26 \/* draft-kamath-pppext-eap-mschapv2-00.txt *\/,$/;" e enum:__anon5 -EAP_TYPE_NAK src/eap_peer/eap_defs.h /^ EAP_TYPE_NAK = 3 \/* Response only, RFC 3748 *\/,$/;" e enum:__anon5 -EAP_TYPE_NONE src/eap_peer/eap_defs.h /^ EAP_TYPE_NONE = 0,$/;" e enum:__anon5 -EAP_TYPE_NOTIFICATION src/eap_peer/eap_defs.h /^ EAP_TYPE_NOTIFICATION = 2 \/* RFC 3748 *\/,$/;" e enum:__anon5 -EAP_TYPE_OTP src/eap_peer/eap_defs.h /^ EAP_TYPE_OTP = 5 \/* RFC 3748 *\/,$/;" e enum:__anon5 -EAP_TYPE_PAX src/eap_peer/eap_defs.h /^ EAP_TYPE_PAX = 46 \/* RFC 4746 *\/,$/;" e enum:__anon5 -EAP_TYPE_PEAP src/eap_peer/eap_defs.h /^ EAP_TYPE_PEAP = 25 \/* draft-josefsson-pppext-eap-tls-eap-06.txt *\/,$/;" e enum:__anon5 -EAP_TYPE_PSK src/eap_peer/eap_defs.h /^ EAP_TYPE_PSK = 47 \/* RFC 4764 *\/,$/;" e enum:__anon5 -EAP_TYPE_PWD src/eap_peer/eap_defs.h /^ EAP_TYPE_PWD = 52 \/* RFC 5931 *\/,$/;" e enum:__anon5 -EAP_TYPE_SAKE src/eap_peer/eap_defs.h /^ EAP_TYPE_SAKE = 48 \/* RFC 4763 *\/,$/;" e enum:__anon5 -EAP_TYPE_SIM src/eap_peer/eap_defs.h /^ EAP_TYPE_SIM = 18 \/* RFC 4186 *\/,$/;" e enum:__anon5 -EAP_TYPE_TLS src/eap_peer/eap_defs.h /^ EAP_TYPE_TLS = 13 \/* RFC 2716 *\/,$/;" e enum:__anon5 -EAP_TYPE_TLV src/eap_peer/eap_defs.h /^ EAP_TYPE_TLV = 33 \/* draft-josefsson-pppext-eap-tls-eap-07.txt *\/,$/;" e enum:__anon5 -EAP_TYPE_TNC src/eap_peer/eap_defs.h /^ EAP_TYPE_TNC = 38 \/* TNC IF-T v1.0-r3; note: tentative assignment;$/;" e enum:__anon5 -EAP_TYPE_TTLS src/eap_peer/eap_defs.h /^ EAP_TYPE_TTLS = 21 \/* RFC 5281 *\/,$/;" e enum:__anon5 -EAP_UNAUTH_TLS_TYPE src/eap_peer/eap_tls_common.h 89;" d -EAP_VENDOR_HOSTAP src/eap_peer/eap_defs.h /^ EAP_VENDOR_HOSTAP = 39068 \/* hostapd\/wpa_supplicant project *\/$/;" e enum:__anon6 -EAP_VENDOR_IETF src/eap_peer/eap_defs.h /^ EAP_VENDOR_IETF = 0,$/;" e enum:__anon6 -EAP_VENDOR_MICROSOFT src/eap_peer/eap_defs.h /^ EAP_VENDOR_MICROSOFT = 0x000137 \/* Microsoft *\/,$/;" e enum:__anon6 -EAP_VENDOR_TYPE_UNAUTH_TLS src/eap_peer/eap_defs.h 87;" d -EAP_VENDOR_UNAUTH_TLS src/eap_peer/eap_defs.h 86;" d -EAP_VENDOR_WFA src/eap_peer/eap_defs.h /^ EAP_VENDOR_WFA = 0x00372A \/* Wi-Fi Alliance *\/,$/;" e enum:__anon6 -ERP_INFO_BARKER_PREAMBLE_MODE src/common/ieee802_11_defs.h 388;" d -ERP_INFO_NON_ERP_PRESENT src/common/ieee802_11_defs.h 386;" d -ERP_INFO_USE_PROTECTION src/common/ieee802_11_defs.h 387;" d -ERROR_ACCT_DISABLED src/eap_peer/eap_mschapv2.c 35;" d file: -ERROR_AUTHENTICATION_FAILURE src/eap_peer/eap_mschapv2.c 38;" d file: -ERROR_CHANGING_PASSWORD src/eap_peer/eap_mschapv2.c 39;" d file: -ERROR_NO_DIALIN_PERMISSION src/eap_peer/eap_mschapv2.c 37;" d file: -ERROR_PASSWD_EXPIRED src/eap_peer/eap_mschapv2.c 36;" d file: -ERROR_RESTRICTED_LOGON_HOURS src/eap_peer/eap_mschapv2.c 34;" d file: -ESP_ERR_WIFI_REGISTRAR include/esp_supplicant/esp_wps.h 46;" d -ESP_ERR_WIFI_WPS_SM include/esp_supplicant/esp_wps.h 48;" d -ESP_ERR_WIFI_WPS_TYPE include/esp_supplicant/esp_wps.h 47;" d -ESP_HOSTAP_H src/esp_supplicant/esp_hostap.h 16;" d -ESP_WPA_ENTERPRISE_H include/esp_supplicant/esp_wpa_enterprise.h 16;" d -ESS_DISASSOC_IMMINENT src/common/wpa_ctrl.h 148;" d -ESTABLISHED src/tls/tlsv1_client_i.h /^ ESTABLISHED, FAILED$/;" e enum:tlsv1_client::__anon43 -ESTABLISHED src/tls/tlsv1_server_i.h /^ ESTABLISHED, FAILED$/;" e enum:tlsv1_server::__anon39 -ETH_ALEN include/utils/common.h 194;" d -ETH_P_ALL include/utils/common.h 200;" d -ETH_P_EAPOL include/utils/common.h 206;" d -ETH_P_PAE include/utils/common.h 203;" d -ETH_P_RRB include/utils/common.h 212;" d -ETH_P_RSN_PREAUTH include/utils/common.h 209;" d -ETSParam src/esp_supplicant/esp_wifi_driver.h /^typedef uint32_t ETSParam;$/;" t -ETSSignal src/esp_supplicant/esp_wifi_driver.h /^typedef uint32_t ETSSignal;$/;" t -EXT_HT_CAP_INFO_HTC_SUPPORTED src/common/ieee802_11_defs.h 416;" d -EXT_HT_CAP_INFO_MCS_FEEDBACK_OFFSET src/common/ieee802_11_defs.h 415;" d -EXT_HT_CAP_INFO_PCO src/common/ieee802_11_defs.h 413;" d -EXT_HT_CAP_INFO_RD_RESPONDER src/common/ieee802_11_defs.h 417;" d -EXT_HT_CAP_INFO_TRANS_TIME_OFFSET src/common/ieee802_11_defs.h 414;" d -EXT_PASSWORD_H src/utils/ext_password.h 10;" d -EXT_PASSWORD_I_H src/utils/ext_password_i.h 10;" d -EapDecision src/eap_peer/eap_i.h /^} EapDecision;$/;" t typeref:enum:__anon1 -EapMethodState src/eap_peer/eap_i.h /^} EapMethodState;$/;" t typeref:enum:__anon2 -EapType src/eap_peer/eap_defs.h /^} EapType;$/;" t typeref:enum:__anon5 -F1 src/crypto/md4-internal.c 128;" d file: -F1 src/crypto/md5-internal.c 201;" d file: -F2 src/crypto/md4-internal.c 129;" d file: -F2 src/crypto/md5-internal.c 202;" d file: -F3 src/crypto/md4-internal.c 130;" d file: -F3 src/crypto/md5-internal.c 203;" d file: -F4 src/crypto/md5-internal.c 204;" d file: -FAILED src/tls/tlsv1_client_i.h /^ ESTABLISHED, FAILED$/;" e enum:tlsv1_client::__anon43 -FAILED src/tls/tlsv1_server_i.h /^ ESTABLISHED, FAILED$/;" e enum:tlsv1_server::__anon39 -FALSE src/common/defs.h /^typedef enum { FALSE = 0, TRUE = 1 } Boolean;$/;" e enum:__anon87 -FALSE src/common/defs.h 19;" d -FTIE_SUBELEM_GTK src/common/wpa_common.h 290;" d -FTIE_SUBELEM_IGTK src/common/wpa_common.h 292;" d -FTIE_SUBELEM_R0KH_ID src/common/wpa_common.h 291;" d -FTIE_SUBELEM_R1KH_ID src/common/wpa_common.h 289;" d -FT_PACKET_R0KH_R1KH_PULL src/ap/wpa_auth.h 40;" d -FT_PACKET_R0KH_R1KH_PUSH src/ap/wpa_auth.h 42;" d -FT_PACKET_R0KH_R1KH_RESP src/ap/wpa_auth.h 41;" d -FT_PACKET_REQUEST src/ap/wpa_auth.h 37;" d -FT_PACKET_RESPONSE src/ap/wpa_auth.h 38;" d -FT_R0KH_ID_MAX_LEN src/common/wpa_common.h 125;" d -FT_R0KH_R1KH_PULL_DATA_LEN src/ap/wpa_auth.h 44;" d -FT_R0KH_R1KH_PUSH_DATA_LEN src/ap/wpa_auth.h 46;" d -FT_R0KH_R1KH_RESP_DATA_LEN src/ap/wpa_auth.h 45;" d -FT_R1KH_ID_LEN src/common/wpa_common.h 126;" d -GAS_DIALOG_MAX src/ap/sta_info.h 118;" d -GAS_RESPONSE_INFO src/common/wpa_ctrl.h 153;" d -GETU32 src/crypto/aes_i.h 116;" d -GETU32 src/crypto/aes_i.h 119;" d -GInit src/ap/wpa_auth_i.h /^ Boolean GInit;$/;" m struct:wpa_group -GKeyDoneStations src/ap/wpa_auth_i.h /^ int GKeyDoneStations;$/;" m struct:wpa_group -GM src/ap/wpa_auth_i.h /^ int GN, GM;$/;" m struct:wpa_group -GMK src/ap/wpa_auth_i.h /^ u8 GMK[WPA_GMK_LEN];$/;" m struct:wpa_group -GM_igtk src/ap/wpa_auth_i.h /^ int GN_igtk, GM_igtk;$/;" m struct:wpa_group -GN src/ap/wpa_auth_i.h /^ int GN, GM;$/;" m struct:wpa_group -GN_igtk src/ap/wpa_auth_i.h /^ int GN_igtk, GM_igtk;$/;" m struct:wpa_group -GNonce src/ap/wpa_auth_i.h /^ u8 GNonce[WPA_NONCE_LEN];$/;" m struct:wpa_group -GTK src/ap/wpa_auth_i.h /^ u8 GTK[2][WPA_GTK_MAX_LEN];$/;" m struct:wpa_group -GTKAuthenticator src/ap/wpa_auth_i.h /^ Boolean GTKAuthenticator;$/;" m struct:wpa_group -GTKReKey src/ap/wpa_auth_i.h /^ Boolean GTKReKey;$/;" m struct:wpa_group -GTK_len src/ap/wpa_auth_i.h /^ int GTK_len;$/;" m struct:wpa_group -GTimeoutCtr src/ap/wpa_auth_i.h /^ int GTimeoutCtr;$/;" m struct:wpa_state_machine -GUpdateStationKeys src/ap/wpa_auth_i.h /^ Boolean GUpdateStationKeys;$/;" m struct:wpa_state_machine -Gamma0 src/crypto/sha256-internal.c 93;" d file: -Gamma1 src/crypto/sha256-internal.c 94;" d file: -HOSTAPD_CONFIG_H src/ap/ap_config.h 10;" d -HOSTAPD_H src/ap/hostapd.h 10;" d -HOSTAPD_MAX_SSID_LEN src/ap/ap_config.h 32;" d -HOSTAPD_MODE_IEEE80211A src/common/defs.h /^ HOSTAPD_MODE_IEEE80211A,$/;" e enum:hostapd_hw_mode -HOSTAPD_MODE_IEEE80211AD src/common/defs.h /^ HOSTAPD_MODE_IEEE80211AD,$/;" e enum:hostapd_hw_mode -HOSTAPD_MODE_IEEE80211B src/common/defs.h /^ HOSTAPD_MODE_IEEE80211B,$/;" e enum:hostapd_hw_mode -HOSTAPD_MODE_IEEE80211G src/common/defs.h /^ HOSTAPD_MODE_IEEE80211G,$/;" e enum:hostapd_hw_mode -HOSTAPD_RATE_BASIC src/ap/hostapd.h 53;" d -HT_CAP_INFO_40MHZ_INTOLERANT src/common/ieee802_11_defs.h 409;" d -HT_CAP_INFO_DELAYED_BA src/common/ieee802_11_defs.h 405;" d -HT_CAP_INFO_DSSS_CCK40MHZ src/common/ieee802_11_defs.h 407;" d -HT_CAP_INFO_GREEN_FIELD src/common/ieee802_11_defs.h 397;" d -HT_CAP_INFO_LDPC_CODING_CAP src/common/ieee802_11_defs.h 391;" d -HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT src/common/ieee802_11_defs.h 410;" d -HT_CAP_INFO_MAX_AMSDU_SIZE src/common/ieee802_11_defs.h 406;" d -HT_CAP_INFO_PSMP_SUPP src/common/ieee802_11_defs.h 408;" d -HT_CAP_INFO_RX_STBC_1 src/common/ieee802_11_defs.h 402;" d -HT_CAP_INFO_RX_STBC_12 src/common/ieee802_11_defs.h 403;" d -HT_CAP_INFO_RX_STBC_123 src/common/ieee802_11_defs.h 404;" d -HT_CAP_INFO_RX_STBC_MASK src/common/ieee802_11_defs.h 401;" d -HT_CAP_INFO_SHORT_GI20MHZ src/common/ieee802_11_defs.h 398;" d -HT_CAP_INFO_SHORT_GI40MHZ src/common/ieee802_11_defs.h 399;" d -HT_CAP_INFO_SMPS_DISABLED src/common/ieee802_11_defs.h 396;" d -HT_CAP_INFO_SMPS_DYNAMIC src/common/ieee802_11_defs.h 395;" d -HT_CAP_INFO_SMPS_MASK src/common/ieee802_11_defs.h 393;" d -HT_CAP_INFO_SMPS_STATIC src/common/ieee802_11_defs.h 394;" d -HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET src/common/ieee802_11_defs.h 392;" d -HT_CAP_INFO_TX_STBC src/common/ieee802_11_defs.h 400;" d -HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY src/common/ieee802_11_defs.h 453;" d -HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH src/common/ieee802_11_defs.h 451;" d -HT_INFO_HT_PARAM_RIFS_MODE src/common/ieee802_11_defs.h 452;" d -HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE src/common/ieee802_11_defs.h 449;" d -HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW src/common/ieee802_11_defs.h 450;" d -HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK src/common/ieee802_11_defs.h 448;" d -HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY src/common/ieee802_11_defs.h 454;" d -HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT src/common/ieee802_11_defs.h 465;" d -HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT src/common/ieee802_11_defs.h 467;" d -HT_INFO_OPERATION_MODE_OP_MODE_MASK src/common/ieee802_11_defs.h 462;" d -HT_INFO_OPERATION_MODE_OP_MODE_OFFSET src/common/ieee802_11_defs.h 464;" d -HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT src/common/ieee802_11_defs.h 466;" d -HT_INFO_STBC_PARAM_DUAL_BEACON src/common/ieee802_11_defs.h 469;" d -HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT src/common/ieee802_11_defs.h 470;" d -HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED src/common/ieee802_11_defs.h 472;" d -HT_INFO_STBC_PARAM_PCO_ACTIVE src/common/ieee802_11_defs.h 473;" d -HT_INFO_STBC_PARAM_PCO_PHASE src/common/ieee802_11_defs.h 474;" d -HT_INFO_STBC_PARAM_SECONDARY_BCN src/common/ieee802_11_defs.h 471;" d -IANA_SECP256R1 src/crypto/crypto_mbedtls.c 30;" d file: -IBSS_RSN_COMPLETED src/common/wpa_ctrl.h 71;" d -ICACHE_RODATA_ATTR src/crypto/crypto_internal-cipher.c /^static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;$/;" v file: -ICACHE_RODATA_ATTR src/crypto/crypto_internal.c /^static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;$/;" v file: -ICACHE_RODATA_ATTR src/fast_crypto/fast_crypto_internal.c /^static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;$/;" v file: -ICACHE_RODATA_ATTR src/tls/libtommath.h /^static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;$/;" v -IEEE80211_BSSID_FROMDS src/common/ieee802_11_defs.h 252;" d -IEEE80211_DA_FROMDS src/common/ieee802_11_defs.h 251;" d -IEEE80211_FC src/common/ieee802_11_defs.h 257;" d -IEEE80211_HDRLEN src/common/ieee802_11_defs.h 255;" d -IEEE80211_SA_FROMDS src/common/ieee802_11_defs.h 253;" d -IEEE8021X_KEY_INDEX_FLAG src/common/eapol_common.h 44;" d -IEEE8021X_KEY_INDEX_MASK src/common/eapol_common.h 45;" d -IEEE8021X_KEY_IV_LEN src/common/eapol_common.h 42;" d -IEEE8021X_KEY_SIGN_LEN src/common/eapol_common.h 41;" d -IEEE8021X_REPLAY_COUNTER_LEN src/common/eapol_common.h 40;" d -IEEE802_11_DEFS_H src/common/ieee802_11_defs.h 17;" d -IEEE802_1X_H src/ap/ieee802_1x.h 10;" d -IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT src/common/eapol_common.h /^ IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4$/;" e enum:__anon85 -IEEE802_1X_TYPE_EAPOL_KEY src/common/eapol_common.h /^ IEEE802_1X_TYPE_EAPOL_KEY = 3,$/;" e enum:__anon85 -IEEE802_1X_TYPE_EAPOL_LOGOFF src/common/eapol_common.h /^ IEEE802_1X_TYPE_EAPOL_LOGOFF = 2,$/;" e enum:__anon85 -IEEE802_1X_TYPE_EAPOL_START src/common/eapol_common.h /^ IEEE802_1X_TYPE_EAPOL_START = 1,$/;" e enum:__anon85 -IEEE802_1X_TYPE_EAP_PACKET src/common/eapol_common.h /^enum { IEEE802_1X_TYPE_EAP_PACKET = 0,$/;" e enum:__anon85 -IGTK src/ap/wpa_auth_i.h /^ u8 IGTK[2][WPA_IGTK_LEN];$/;" m struct:wpa_group -INCLUDES_H src/utils/includes.h 20;" d -INLINE port/include/endian.h 118;" d -INTERWORKING_AP src/common/wpa_ctrl.h 150;" d -INTERWORKING_NO_MATCH src/common/wpa_ctrl.h 151;" d -IS_WPS_ENROLLEE src/esp_supplicant/esp_wifi_driver.h 118;" d -IS_WPS_REGISTRAR src/esp_supplicant/esp_wifi_driver.h 117;" d -Init src/ap/wpa_auth_i.h /^ Boolean Init;$/;" m struct:wpa_state_machine -K src/crypto/sha256-internal.c /^static const unsigned long K[64] = {$/;" v file: -KEYENTRY_TABLE_MAP src/rsn_supp/wpa.h 178;" d -KEY_MGMT_802_1X src/common/defs.h /^ KEY_MGMT_802_1X,$/;" e enum:wpa_key_mgmt -KEY_MGMT_802_1X_NO_WPA src/common/defs.h /^ KEY_MGMT_802_1X_NO_WPA,$/;" e enum:wpa_key_mgmt -KEY_MGMT_802_1X_SHA256 src/common/defs.h /^ KEY_MGMT_802_1X_SHA256,$/;" e enum:wpa_key_mgmt -KEY_MGMT_FT_802_1X src/common/defs.h /^ KEY_MGMT_FT_802_1X,$/;" e enum:wpa_key_mgmt -KEY_MGMT_FT_PSK src/common/defs.h /^ KEY_MGMT_FT_PSK,$/;" e enum:wpa_key_mgmt -KEY_MGMT_NONE src/common/defs.h /^ KEY_MGMT_NONE,$/;" e enum:wpa_key_mgmt -KEY_MGMT_PSK src/common/defs.h /^ KEY_MGMT_PSK,$/;" e enum:wpa_key_mgmt -KEY_MGMT_PSK_SHA256 src/common/defs.h /^ KEY_MGMT_PSK_SHA256,$/;" e enum:wpa_key_mgmt -KEY_MGMT_WPA_NONE src/common/defs.h /^ KEY_MGMT_WPA_NONE,$/;" e enum:wpa_key_mgmt -KEY_MGMT_WPS src/common/defs.h /^ KEY_MGMT_WPS$/;" e enum:wpa_key_mgmt -LIST_H src/utils/list.h 16;" d -LITTLE_ENDIAN port/include/endian.h 40;" d -LOGGER_DEBUG src/ap/wpa_auth.h /^ LOGGER_DEBUG, LOGGER_INFO, LOGGER_WARNING$/;" e enum:__anon20 -LOGGER_INFO src/ap/wpa_auth.h /^ LOGGER_DEBUG, LOGGER_INFO, LOGGER_WARNING$/;" e enum:__anon20 -LOGGER_WARNING src/ap/wpa_auth.h /^ LOGGER_DEBUG, LOGGER_INFO, LOGGER_WARNING$/;" e enum:__anon20 -LONG_PREAMBLE src/ap/ap_config.h /^ LONG_PREAMBLE = 0,$/;" e enum:hostapd_config::__anon19 -LTM_NO_NEG_EXP src/crypto/libtommath.h 59;" d -LTM_NO_NEG_EXP src/tls/libtommath.h 61;" d -MAC2STR include/utils/common.h 259;" d -MACSTR include/utils/common.h 260;" d -MAX src/crypto/libtommath.h 68;" d -MAX src/tls/libtommath.h 70;" d -MAX_CIPHER_COUNT src/tls/tlsv1_client_i.h 42;" d -MAX_CIPHER_COUNT src/tls/tlsv1_server_i.h 37;" d -MAX_CRED_COUNT src/wps/wps_attr_parse.h 92;" d -MAX_REQ_DEV_TYPE_COUNT src/wps/wps_attr_parse.h 97;" d -MAX_STA_COUNT src/ap/ap_config.h 18;" d -MAX_VLAN_ID src/ap/ap_config.h 19;" d -MAX_WPS_PARSE_VENDOR_EXT src/wps/wps.h 71;" d -MAX_WPS_VENDOR_EXTENSIONS src/wps/wps.h 67;" d -MD4Context src/crypto/md4-internal.c /^typedef struct MD4Context {$/;" s file: -MD4Final src/crypto/md4-internal.c /^static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx)$/;" f file: -MD4Init src/crypto/md4-internal.c /^static void MD4Init(MD4_CTX *ctx)$/;" f file: -MD4Pad src/crypto/md4-internal.c /^static void MD4Pad(MD4_CTX *ctx)$/;" f file: -MD4SETP src/crypto/md4-internal.c 132;" d file: -MD4Transform src/crypto/md4-internal.c /^static void MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH])$/;" f file: -MD4Update src/crypto/md4-internal.c /^static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len)$/;" f file: -MD4_BLOCK_LENGTH src/crypto/md4-internal.c 11;" d file: -MD4_CTX src/crypto/md4-internal.c /^} MD4_CTX;$/;" t typeref:struct:MD4Context file: -MD4_DIGEST_LENGTH src/crypto/md4-internal.c 12;" d file: -MD4_DIGEST_STRING_LENGTH src/crypto/md4-internal.c 36;" d file: -MD5Context src/crypto/md5_i.h /^struct MD5Context {$/;" s -MD5Final src/crypto/md5-internal.c /^MD5Final(unsigned char digest[16], struct MD5Context *ctx)$/;" f -MD5Init src/crypto/md5-internal.c /^MD5Init(struct MD5Context *ctx)$/;" f -MD5STEP src/crypto/md5-internal.c 207;" d file: -MD5Transform src/crypto/md5-internal.c /^MD5Transform(u32 buf[4], u32 const in[16])$/;" f file: -MD5Update src/crypto/md5-internal.c /^MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)$/;" f -MD5_CTX src/crypto/md5-internal.c /^typedef struct MD5Context MD5_CTX;$/;" t typeref:struct:MD5Context file: -MD5_H include/crypto/md5.h 16;" d -MD5_I_H src/crypto/md5_i.h 16;" d -MD5_MAC_LEN include/crypto/md5.h 18;" d -MD5_MAC_LEN src/common/wpa_common.c 26;" d file: -METHOD_CONT src/eap_peer/eap_i.h /^ METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE$/;" e enum:__anon2 -METHOD_DONE src/eap_peer/eap_i.h /^ METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE$/;" e enum:__anon2 -METHOD_INIT src/eap_peer/eap_i.h /^ METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE$/;" e enum:__anon2 -METHOD_MAY_CONT src/eap_peer/eap_i.h /^ METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE$/;" e enum:__anon2 -METHOD_NONE src/eap_peer/eap_i.h /^ METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE$/;" e enum:__anon2 -MICVerified src/ap/wpa_auth_i.h /^ Boolean MICVerified;$/;" m struct:wpa_state_machine -MIN src/crypto/libtommath.h 64;" d -MIN src/crypto/sha256-internal.c 96;" d file: -MIN src/tls/libtommath.h 66;" d -MLME_SETPROTECTION_KEY_TYPE_GROUP src/common/defs.h 249;" d -MLME_SETPROTECTION_KEY_TYPE_PAIRWISE src/common/defs.h 250;" d -MLME_SETPROTECTION_PROTECT_TYPE_NONE src/common/defs.h 244;" d -MLME_SETPROTECTION_PROTECT_TYPE_RX src/common/defs.h 245;" d -MLME_SETPROTECTION_PROTECT_TYPE_RX_TX src/common/defs.h 247;" d -MLME_SETPROTECTION_PROTECT_TYPE_TX src/common/defs.h 246;" d -MOBILITY_DOMAIN_ID_LEN src/common/wpa_common.h 124;" d -MP_28BIT src/crypto/libtommath.h 77;" d -MP_28BIT src/tls/libtommath.h 79;" d -MP_EQ src/crypto/libtommath.h 88;" d -MP_EQ src/tls/libtommath.h 90;" d -MP_GT src/crypto/libtommath.h 89;" d -MP_GT src/tls/libtommath.h 91;" d -MP_LOW_MEM src/crypto/libtommath.h 104;" d -MP_LOW_MEM src/tls/libtommath.h 106;" d -MP_LT src/crypto/libtommath.h 87;" d -MP_LT src/tls/libtommath.h 89;" d -MP_MASK src/crypto/libtommath.h 85;" d -MP_MASK src/tls/libtommath.h 87;" d -MP_MEM src/crypto/libtommath.h 95;" d -MP_MEM src/tls/libtommath.h 97;" d -MP_NEG src/crypto/libtommath.h 92;" d -MP_NEG src/tls/libtommath.h 94;" d -MP_NO src/crypto/libtommath.h 99;" d -MP_NO src/tls/libtommath.h 101;" d -MP_OKAY src/crypto/libtommath.h 94;" d -MP_OKAY src/tls/libtommath.h 96;" d -MP_PREC src/crypto/libtommath.h 109;" d -MP_PREC src/crypto/libtommath.h 111;" d -MP_PREC src/tls/libtommath.h 111;" d -MP_PREC src/tls/libtommath.h 113;" d -MP_VAL src/crypto/libtommath.h 96;" d -MP_VAL src/tls/libtommath.h 98;" d -MP_WARRAY src/crypto/libtommath.h 116;" d -MP_WARRAY src/tls/libtommath.h 118;" d -MP_YES src/crypto/libtommath.h 98;" d -MP_YES src/tls/libtommath.h 100;" d -MP_ZPOS src/crypto/libtommath.h 91;" d -MP_ZPOS src/tls/libtommath.h 93;" d -MSCHAPV2_AUTH_RESPONSE_LEN src/eap_peer/mschapv2.h 11;" d -MSCHAPV2_CHAL_LEN src/eap_peer/mschapv2.h 9;" d -MSCHAPV2_H src/eap_peer/mschapv2.h 7;" d -MSCHAPV2_KEY_LEN src/eap_peer/eap_mschapv2.c 32;" d file: -MSCHAPV2_MASTER_KEY_LEN src/eap_peer/mschapv2.h 12;" d -MSCHAPV2_NT_RESPONSE_LEN src/eap_peer/mschapv2.h 10;" d -MSCHAPV2_OP_CHALLENGE src/eap_peer/eap_mschapv2.c 25;" d file: -MSCHAPV2_OP_CHANGE_PASSWORD src/eap_peer/eap_mschapv2.c 29;" d file: -MSCHAPV2_OP_FAILURE src/eap_peer/eap_mschapv2.c 28;" d file: -MSCHAPV2_OP_RESPONSE src/eap_peer/eap_mschapv2.c 26;" d file: -MSCHAPV2_OP_SUCCESS src/eap_peer/eap_mschapv2.c 27;" d file: -MSG_DEBUG include/utils/wpa_debug.h /^enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };$/;" e enum:__anon91 -MSG_DEBUG include/utils/wpa_debug.h 28;" d -MSG_DONTWAIT include/utils/common.h 249;" d -MSG_ERROR include/utils/wpa_debug.h /^enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };$/;" e enum:__anon91 -MSG_ERROR include/utils/wpa_debug.h 25;" d -MSG_INFO include/utils/wpa_debug.h /^enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };$/;" e enum:__anon91 -MSG_INFO include/utils/wpa_debug.h 27;" d -MSG_MSGDUMP include/utils/wpa_debug.h /^enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };$/;" e enum:__anon91 -MSG_MSGDUMP include/utils/wpa_debug.h 29;" d -MSG_PRINT include/utils/wpa_debug.h 62;" d -MSG_WARNING include/utils/wpa_debug.h /^enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };$/;" e enum:__anon91 -MSG_WARNING include/utils/wpa_debug.h 26;" d -MS_FUNCS_H include/crypto/ms_funcs.h 8;" d -Maj src/crypto/sha256-internal.c 88;" d file: -NONE_AUTH src/esp_supplicant/esp_wifi_driver.h /^ NONE_AUTH = 0x01,$/;" e enum:__anon29 -NO_BINDING src/eap_peer/eap_peap.c /^ enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;$/;" e enum:eap_peap_data::__anon7 file: -NUM_DH_GROUPS src/crypto/dh_groups.c 536;" d file: -NUM_ELEMS src/tls/tlsv1_common.c 70;" d file: -NUM_HOSTAPD_MODES src/common/defs.h /^ NUM_HOSTAPD_MODES$/;" e enum:hostapd_hw_mode -NUM_TLS_CIPHER_DATA src/tls/tlsv1_common.c 101;" d file: -NUM_TLS_CIPHER_SUITES src/tls/tlsv1_common.c 71;" d file: -NUM_WEP_KEYS src/ap/ap_config.h 34;" d -NUM_WPS_EI_VALUES src/wps/wps_defs.h /^ NUM_WPS_EI_VALUES$/;" e enum:wps_error_indication -OPTIONAL_BINDING src/eap_peer/eap_peap.c /^ enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;$/;" e enum:eap_peap_data::__anon7 file: -OPT_CAST src/crypto/libtommath.h 71;" d -OPT_CAST src/tls/libtommath.h 73;" d -OP_MODE_20MHZ_HT_STA_ASSOCED src/common/ieee802_11_defs.h 459;" d -OP_MODE_MAY_BE_LEGACY_STAS src/common/ieee802_11_defs.h 458;" d -OP_MODE_MIXED src/common/ieee802_11_defs.h 460;" d -OP_MODE_PURE src/common/ieee802_11_defs.h 457;" d -OS_H port/include/os.h 16;" d -OUI_BROADCOM src/common/ieee802_11_defs.h 590;" d -OUI_MICROSOFT src/common/ieee802_11_defs.h 477;" d -P2P_ALLOW_CROSS_CONNECTION src/ap/ap_config.h 384;" d -P2P_ENABLED src/ap/ap_config.h 380;" d -P2P_EVENT_CROSS_CONNECT_DISABLE src/common/wpa_ctrl.h 127;" d -P2P_EVENT_CROSS_CONNECT_ENABLE src/common/wpa_ctrl.h 126;" d -P2P_EVENT_DEVICE_FOUND src/common/wpa_ctrl.h 112;" d -P2P_EVENT_DEVICE_LOST src/common/wpa_ctrl.h 115;" d -P2P_EVENT_FIND_STOPPED src/common/wpa_ctrl.h 144;" d -P2P_EVENT_GO_NEG_FAILURE src/common/wpa_ctrl.h 121;" d -P2P_EVENT_GO_NEG_REQUEST src/common/wpa_ctrl.h 119;" d -P2P_EVENT_GO_NEG_SUCCESS src/common/wpa_ctrl.h 120;" d -P2P_EVENT_GROUP_FORMATION_FAILURE src/common/wpa_ctrl.h 123;" d -P2P_EVENT_GROUP_FORMATION_SUCCESS src/common/wpa_ctrl.h 122;" d -P2P_EVENT_GROUP_REMOVED src/common/wpa_ctrl.h 125;" d -P2P_EVENT_GROUP_STARTED src/common/wpa_ctrl.h 124;" d -P2P_EVENT_INVITATION_RECEIVED src/common/wpa_ctrl.h 142;" d -P2P_EVENT_INVITATION_RESULT src/common/wpa_ctrl.h 143;" d -P2P_EVENT_PERSISTENT_PSK_FAIL src/common/wpa_ctrl.h 145;" d -P2P_EVENT_PROV_DISC_ENTER_PIN src/common/wpa_ctrl.h 131;" d -P2P_EVENT_PROV_DISC_FAILURE src/common/wpa_ctrl.h 137;" d -P2P_EVENT_PROV_DISC_PBC_REQ src/common/wpa_ctrl.h 133;" d -P2P_EVENT_PROV_DISC_PBC_RESP src/common/wpa_ctrl.h 135;" d -P2P_EVENT_PROV_DISC_SHOW_PIN src/common/wpa_ctrl.h 129;" d -P2P_EVENT_SERV_DISC_REQ src/common/wpa_ctrl.h 139;" d -P2P_EVENT_SERV_DISC_RESP src/common/wpa_ctrl.h 141;" d -P2P_GROUP_FORMATION src/ap/ap_config.h 382;" d -P2P_GROUP_OWNER src/ap/ap_config.h 381;" d -P2P_MANAGE src/ap/ap_config.h 383;" d -PADDING src/crypto/md4-internal.c /^static u8 PADDING[MD4_BLOCK_LENGTH] = {$/;" v file: -PASSWD_CHANGE_CHAL_LEN src/eap_peer/eap_mschapv2.c 31;" d file: -PIN_EXPIRES src/wps/wps_registrar.c 83;" d file: -PIN_LOCKED src/wps/wps_registrar.c 82;" d file: -PInitAKeys src/ap/wpa_auth_i.h /^ Boolean PInitAKeys; \/* WPA only, not in IEEE 802.11i *\/$/;" m struct:wpa_state_machine -PKCS1_H src/tls/pkcs1.h 10;" d -PKCS5_ALG_MD5_DES_CBC src/tls/pkcs5.c /^ PKCS5_ALG_MD5_DES_CBC$/;" e enum:pkcs5_params::pkcs5_alg file: -PKCS5_ALG_UNKNOWN src/tls/pkcs5.c /^ PKCS5_ALG_UNKNOWN,$/;" e enum:pkcs5_params::pkcs5_alg file: -PKCS5_H src/tls/pkcs5.h 10;" d -PKCS8_H src/tls/pkcs8.h 10;" d -PMK src/ap/wpa_auth_i.h /^ u8 PMK[PMK_LEN];$/;" m struct:wpa_state_machine -PMKID_LEN src/common/wpa_common.h 22;" d -PMK_LEN src/ap/ap_config.h 102;" d -PMK_LEN src/common/wpa_common.h 23;" d -PRINTF_FORMAT include/utils/common.h 217;" d -PRINTF_FORMAT include/utils/common.h 220;" d -PRIVATE_KEY_NAME src/eap_peer/eap_i.h 97;" d -PSK_RADIUS_ACCEPTED src/ap/ap_config.h /^ PSK_RADIUS_ACCEPTED = 1,$/;" e enum:hostapd_bss_config::__anon18 -PSK_RADIUS_IGNORED src/ap/ap_config.h /^ PSK_RADIUS_IGNORED = 0,$/;" e enum:hostapd_bss_config::__anon18 -PSK_RADIUS_REQUIRED src/ap/ap_config.h /^ PSK_RADIUS_REQUIRED = 2$/;" e enum:hostapd_bss_config::__anon18 -PTK src/ap/wpa_auth_i.h /^ struct wpa_ptk PTK;$/;" m struct:wpa_state_machine typeref:struct:wpa_state_machine::wpa_ptk -PTKRequest src/ap/wpa_auth_i.h /^ Boolean PTKRequest; \/* not in IEEE 802.11i state machine *\/$/;" m struct:wpa_state_machine -PTK_valid src/ap/wpa_auth_i.h /^ Boolean PTK_valid;$/;" m struct:wpa_state_machine -PUTU32 src/crypto/aes_i.h 117;" d -PUTU32 src/crypto/aes_i.h 121;" d -PUT_32BIT_LE src/crypto/md4-internal.c 50;" d file: -PUT_64BIT_LE src/crypto/md4-internal.c 40;" d file: -PWBLOCK_LEN src/crypto/ms_funcs.c 420;" d file: -Pair src/ap/wpa_auth_i.h /^ Boolean Pair;$/;" m struct:wpa_state_machine -PtkGroupInit src/ap/wpa_auth_i.h /^ Boolean PtkGroupInit; \/* init request for PTK Group state machine *\/$/;" m struct:wpa_state_machine -R src/crypto/sha256-internal.c 90;" d file: -R0 src/crypto/sha1-internal.c 146;" d file: -R1 src/crypto/sha1-internal.c 149;" d file: -R2 src/crypto/sha1-internal.c 152;" d file: -R3 src/crypto/sha1-internal.c 154;" d file: -R4 src/crypto/sha1-internal.c 157;" d file: -RADIUS_ATTR_CHAP_CHALLENGE src/eap_peer/eap_ttls.h 45;" d -RADIUS_ATTR_CHAP_PASSWORD src/eap_peer/eap_ttls.h 43;" d -RADIUS_ATTR_EAP_MESSAGE src/eap_peer/eap_ttls.h 46;" d -RADIUS_ATTR_MS_CHAP2_CPW src/eap_peer/eap_ttls.h 56;" d -RADIUS_ATTR_MS_CHAP2_RESPONSE src/eap_peer/eap_ttls.h 54;" d -RADIUS_ATTR_MS_CHAP2_SUCCESS src/eap_peer/eap_ttls.h 55;" d -RADIUS_ATTR_MS_CHAP_CHALLENGE src/eap_peer/eap_ttls.h 53;" d -RADIUS_ATTR_MS_CHAP_ERROR src/eap_peer/eap_ttls.h 51;" d -RADIUS_ATTR_MS_CHAP_NT_ENC_PW src/eap_peer/eap_ttls.h 52;" d -RADIUS_ATTR_MS_CHAP_RESPONSE src/eap_peer/eap_ttls.h 50;" d -RADIUS_ATTR_REPLY_MESSAGE src/eap_peer/eap_ttls.h 44;" d -RADIUS_ATTR_USER_NAME src/eap_peer/eap_ttls.h 41;" d -RADIUS_ATTR_USER_PASSWORD src/eap_peer/eap_ttls.h 42;" d -RADIUS_VENDOR_ID_MICROSOFT src/eap_peer/eap_ttls.h 49;" d -RANDOM_H include/crypto/random.h 16;" d -RCON src/crypto/aes_i.h 39;" d -RCON src/crypto/aes_i.h 74;" d -RECEIVED_M2D src/wps/wps_i.h /^ RECV_M8, RECEIVED_M2D, WPS_MSG_DONE, RECV_ACK, WPS_FINISHED,$/;" e enum:wps_data::__anon53 -RECV_ACK src/wps/wps_i.h /^ RECV_M8, RECEIVED_M2D, WPS_MSG_DONE, RECV_ACK, WPS_FINISHED,$/;" e enum:wps_data::__anon53 -RECV_DONE src/wps/wps_i.h /^ RECV_M7, SEND_M8, RECV_DONE, SEND_M2D, RECV_M2D_ACK$/;" e enum:wps_data::__anon53 -RECV_M1 src/wps/wps_i.h /^ RECV_M1, SEND_M2, RECV_M3, SEND_M4, RECV_M5, SEND_M6,$/;" e enum:wps_data::__anon53 -RECV_M2 src/wps/wps_i.h /^ SEND_M1, RECV_M2, SEND_M3, RECV_M4, SEND_M5, RECV_M6, SEND_M7,$/;" e enum:wps_data::__anon53 -RECV_M2D_ACK src/wps/wps_i.h /^ RECV_M7, SEND_M8, RECV_DONE, SEND_M2D, RECV_M2D_ACK$/;" e enum:wps_data::__anon53 -RECV_M3 src/wps/wps_i.h /^ RECV_M1, SEND_M2, RECV_M3, SEND_M4, RECV_M5, SEND_M6,$/;" e enum:wps_data::__anon53 -RECV_M4 src/wps/wps_i.h /^ SEND_M1, RECV_M2, SEND_M3, RECV_M4, SEND_M5, RECV_M6, SEND_M7,$/;" e enum:wps_data::__anon53 -RECV_M5 src/wps/wps_i.h /^ RECV_M1, SEND_M2, RECV_M3, SEND_M4, RECV_M5, SEND_M6,$/;" e enum:wps_data::__anon53 -RECV_M6 src/wps/wps_i.h /^ SEND_M1, RECV_M2, SEND_M3, RECV_M4, SEND_M5, RECV_M6, SEND_M7,$/;" e enum:wps_data::__anon53 -RECV_M7 src/wps/wps_i.h /^ RECV_M7, SEND_M8, RECV_DONE, SEND_M2D, RECV_M2D_ACK$/;" e enum:wps_data::__anon53 -RECV_M8 src/wps/wps_i.h /^ RECV_M8, RECEIVED_M2D, WPS_MSG_DONE, RECV_ACK, WPS_FINISHED,$/;" e enum:wps_data::__anon53 -REQUIRE_BINDING src/eap_peer/eap_peap.c /^ enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;$/;" e enum:eap_peap_data::__anon7 file: -RND src/crypto/sha256-internal.c 123;" d file: -ROLc src/crypto/des-internal.c 39;" d file: -RORc src/crypto/des-internal.c 43;" d file: -RORc src/crypto/sha256-internal.c 84;" d file: -ROUND src/crypto/aes-internal-dec.c 103;" d file: -ROUND src/crypto/aes-internal-dec.c 145;" d file: -ROUND src/crypto/aes-internal-enc.c 47;" d file: -ROUND src/crypto/aes-internal-enc.c 89;" d file: -RSA_H src/tls/rsa.h 10;" d -RSNA_MAX_EAPOL_RETRIES src/ap/wpa_auth_i.h 13;" d -RSN_AUTH_KEY_MGMT_802_1X_SHA256 src/common/wpa_common.h 58;" d -RSN_AUTH_KEY_MGMT_FT_802_1X src/common/wpa_common.h 55;" d -RSN_AUTH_KEY_MGMT_FT_PSK src/common/wpa_common.h 56;" d -RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X src/common/wpa_common.h 53;" d -RSN_AUTH_KEY_MGMT_PSK_SHA256 src/common/wpa_common.h 59;" d -RSN_AUTH_KEY_MGMT_UNSPEC_802_1X src/common/wpa_common.h 52;" d -RSN_CIPHER_SUITE_AES_128_CMAC src/common/wpa_common.h 70;" d -RSN_CIPHER_SUITE_CCMP src/common/wpa_common.h 67;" d -RSN_CIPHER_SUITE_GCMP src/common/wpa_common.h 73;" d -RSN_CIPHER_SUITE_NONE src/common/wpa_common.h 61;" d -RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED src/common/wpa_common.h 72;" d -RSN_CIPHER_SUITE_TKIP src/common/wpa_common.h 63;" d -RSN_CIPHER_SUITE_WEP104 src/common/wpa_common.h 68;" d -RSN_CIPHER_SUITE_WEP40 src/common/wpa_common.h 62;" d -RSN_FT_CAPAB_FT_OVER_DS src/common/wpa_common.h 278;" d -RSN_FT_CAPAB_FT_RESOURCE_REQ_SUPP src/common/wpa_common.h 279;" d -RSN_KEY_DATA_ERROR src/common/wpa_common.h 88;" d -RSN_KEY_DATA_GROUPKEY src/common/wpa_common.h 78;" d -RSN_KEY_DATA_IGTK src/common/wpa_common.h 91;" d -RSN_KEY_DATA_LIFETIME src/common/wpa_common.h 87;" d -RSN_KEY_DATA_MAC_ADDR src/common/wpa_common.h 82;" d -RSN_KEY_DATA_NONCE src/common/wpa_common.h 86;" d -RSN_KEY_DATA_PMKID src/common/wpa_common.h 83;" d -RSN_KEY_DATA_SMK src/common/wpa_common.h 85;" d -RSN_NUM_REPLAY_COUNTERS_1 src/common/wpa_common.h 99;" d -RSN_NUM_REPLAY_COUNTERS_16 src/common/wpa_common.h 102;" d -RSN_NUM_REPLAY_COUNTERS_2 src/common/wpa_common.h 100;" d -RSN_NUM_REPLAY_COUNTERS_4 src/common/wpa_common.h 101;" d -RSN_REMOTE_FRAME_TYPE_FT_RRB src/ap/wpa_auth.h 35;" d -RSN_SELECTOR src/common/wpa_common.h 35;" d -RSN_SELECTOR_GET src/common/wpa_common.h 97;" d -RSN_SELECTOR_LEN src/common/wpa_common.h 32;" d -RSN_SELECTOR_PUT src/common/wpa_common.h 96;" d -RSN_VERSION src/common/wpa_common.h 33;" d -ReAuthenticationRequest src/ap/wpa_auth_i.h /^ Boolean ReAuthenticationRequest;$/;" m struct:wpa_state_machine -S src/crypto/sha256-internal.c 89;" d file: -SAE_COMMIT src/ap/sta_info.h /^ enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state;$/;" e enum:sta_info::__anon16 -SAE_CONFIRM src/ap/sta_info.h /^ enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state;$/;" e enum:sta_info::__anon16 -SAE_INIT src/ap/sta_info.h /^ enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state;$/;" e enum:sta_info::__anon16 -SECURITY_IEEE_802_1X src/ap/ap_config.h /^ SECURITY_IEEE_802_1X = 2,$/;" e enum:hostap_security_policy -SECURITY_PLAINTEXT src/ap/ap_config.h /^ SECURITY_PLAINTEXT = 0,$/;" e enum:hostap_security_policy -SECURITY_STATIC_WEP src/ap/ap_config.h /^ SECURITY_STATIC_WEP = 1,$/;" e enum:hostap_security_policy -SECURITY_WPA src/ap/ap_config.h /^ SECURITY_WPA = 4$/;" e enum:hostap_security_policy -SECURITY_WPA_PSK src/ap/ap_config.h /^ SECURITY_WPA_PSK = 3,$/;" e enum:hostap_security_policy -SEND_M1 src/wps/wps_i.h /^ SEND_M1, RECV_M2, SEND_M3, RECV_M4, SEND_M5, RECV_M6, SEND_M7,$/;" e enum:wps_data::__anon53 -SEND_M2 src/wps/wps_i.h /^ RECV_M1, SEND_M2, RECV_M3, SEND_M4, RECV_M5, SEND_M6,$/;" e enum:wps_data::__anon53 -SEND_M2D src/wps/wps_i.h /^ RECV_M7, SEND_M8, RECV_DONE, SEND_M2D, RECV_M2D_ACK$/;" e enum:wps_data::__anon53 -SEND_M3 src/wps/wps_i.h /^ SEND_M1, RECV_M2, SEND_M3, RECV_M4, SEND_M5, RECV_M6, SEND_M7,$/;" e enum:wps_data::__anon53 -SEND_M4 src/wps/wps_i.h /^ RECV_M1, SEND_M2, RECV_M3, SEND_M4, RECV_M5, SEND_M6,$/;" e enum:wps_data::__anon53 -SEND_M5 src/wps/wps_i.h /^ SEND_M1, RECV_M2, SEND_M3, RECV_M4, SEND_M5, RECV_M6, SEND_M7,$/;" e enum:wps_data::__anon53 -SEND_M6 src/wps/wps_i.h /^ RECV_M1, SEND_M2, RECV_M3, SEND_M4, RECV_M5, SEND_M6,$/;" e enum:wps_data::__anon53 -SEND_M7 src/wps/wps_i.h /^ SEND_M1, RECV_M2, SEND_M3, RECV_M4, SEND_M5, RECV_M6, SEND_M7,$/;" e enum:wps_data::__anon53 -SEND_M8 src/wps/wps_i.h /^ RECV_M7, SEND_M8, RECV_DONE, SEND_M2D, RECV_M2D_ACK$/;" e enum:wps_data::__anon53 -SEND_WSC_NACK src/wps/wps_i.h /^ SEND_WSC_NACK,$/;" e enum:wps_data::__anon53 -SERVER_CERTIFICATE src/tls/tlsv1_client_i.h /^ CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,$/;" e enum:tlsv1_client::__anon43 -SERVER_CERTIFICATE src/tls/tlsv1_server_i.h /^ CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,$/;" e enum:tlsv1_server::__anon39 -SERVER_CERTIFICATE_REQUEST src/tls/tlsv1_client_i.h /^ SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,$/;" e enum:tlsv1_client::__anon43 -SERVER_CERTIFICATE_REQUEST src/tls/tlsv1_server_i.h /^ SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,$/;" e enum:tlsv1_server::__anon39 -SERVER_CHANGE_CIPHER_SPEC src/tls/tlsv1_client_i.h /^ SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, ACK_FINISHED,$/;" e enum:tlsv1_client::__anon43 -SERVER_CHANGE_CIPHER_SPEC src/tls/tlsv1_server_i.h /^ SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED,$/;" e enum:tlsv1_server::__anon39 -SERVER_FINISHED src/tls/tlsv1_client_i.h /^ SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, ACK_FINISHED,$/;" e enum:tlsv1_client::__anon43 -SERVER_FINISHED src/tls/tlsv1_server_i.h /^ SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED,$/;" e enum:tlsv1_server::__anon39 -SERVER_HELLO src/tls/tlsv1_client_i.h /^ CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,$/;" e enum:tlsv1_client::__anon43 -SERVER_HELLO src/tls/tlsv1_server_i.h /^ CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,$/;" e enum:tlsv1_server::__anon39 -SERVER_HELLO_DONE src/tls/tlsv1_client_i.h /^ SERVER_HELLO_DONE, CLIENT_KEY_EXCHANGE, CHANGE_CIPHER_SPEC,$/;" e enum:tlsv1_client::__anon43 -SERVER_HELLO_DONE src/tls/tlsv1_server_i.h /^ SERVER_HELLO_DONE, CLIENT_CERTIFICATE, CLIENT_KEY_EXCHANGE,$/;" e enum:tlsv1_server::__anon39 -SERVER_KEY_EXCHANGE src/tls/tlsv1_client_i.h /^ SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,$/;" e enum:tlsv1_client::__anon43 -SERVER_KEY_EXCHANGE src/tls/tlsv1_server_i.h /^ SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,$/;" e enum:tlsv1_server::__anon39 -SHA1Context src/crypto/sha1_i.h /^struct SHA1Context {$/;" s -SHA1Final src/crypto/sha1-internal.c /^SHA1Final(unsigned char digest[20], SHA1_CTX* context)$/;" f -SHA1HANDSOFF src/crypto/sha1-internal.c 130;" d file: -SHA1Init src/crypto/sha1-internal.c /^SHA1Init(SHA1_CTX* context)$/;" f -SHA1Transform src/crypto/sha1-internal.c /^SHA1Transform(u32 state[5], const unsigned char buffer[64])$/;" f -SHA1Update src/crypto/sha1-internal.c /^SHA1Update(SHA1_CTX* context, const void *_data, u32 len)$/;" f -SHA1_CTX src/crypto/sha1-internal.c /^typedef struct SHA1Context SHA1_CTX;$/;" t typeref:struct:SHA1Context file: -SHA1_H include/crypto/sha1.h 16;" d -SHA1_I_H src/crypto/sha1_i.h 16;" d -SHA1_MAC_LEN include/crypto/sha1.h 18;" d -SHA256_BLOCK_SIZE src/crypto/sha256-internal.c 21;" d file: -SHA256_H include/crypto/sha256.h 16;" d -SHA256_MAC_LEN include/crypto/sha256.h 18;" d -SHAPrintContext src/crypto/sha1-internal.c /^void SHAPrintContext(SHA1_CTX *context, char *msg)$/;" f -SHORT_PREAMBLE src/ap/ap_config.h /^ SHORT_PREAMBLE = 1$/;" e enum:hostapd_config::__anon19 -SIG_WPA2 src/eap_peer/eap_i.h /^enum SIG_WPA2 {$/;" g -SIG_WPA2_MAX src/eap_peer/eap_i.h /^ SIG_WPA2_MAX,$/;" e enum:SIG_WPA2 -SIG_WPA2_RX src/eap_peer/eap_i.h /^ SIG_WPA2_RX,$/;" e enum:SIG_WPA2 -SIG_WPA2_START src/eap_peer/eap_i.h /^ SIG_WPA2_START = 0,$/;" e enum:SIG_WPA2 -SIG_WPA2_TASK_DEL src/eap_peer/eap_i.h /^ SIG_WPA2_TASK_DEL,$/;" e enum:SIG_WPA2 -SIG_WPS_DISABLE src/wps/wps.h /^ SIG_WPS_DISABLE, \/\/2$/;" e enum:wps_sig_type -SIG_WPS_ENABLE src/wps/wps.h /^ SIG_WPS_ENABLE = 1, \/\/1$/;" e enum:wps_sig_type -SIG_WPS_NUM src/wps/wps.h /^ SIG_WPS_NUM, \/\/10$/;" e enum:wps_sig_type -SIG_WPS_RX src/wps/wps.h /^ SIG_WPS_RX, \/\/4$/;" e enum:wps_sig_type -SIG_WPS_START src/wps/wps.h /^ SIG_WPS_START, \/\/3$/;" e enum:wps_sig_type -SIG_WPS_TIMER_EAPOL_START src/wps/wps.h /^ SIG_WPS_TIMER_EAPOL_START, \/\/9$/;" e enum:wps_sig_type -SIG_WPS_TIMER_MSG_TIMEOUT src/wps/wps.h /^ SIG_WPS_TIMER_MSG_TIMEOUT, \/\/6$/;" e enum:wps_sig_type -SIG_WPS_TIMER_SCAN src/wps/wps.h /^ SIG_WPS_TIMER_SCAN, \/\/8$/;" e enum:wps_sig_type -SIG_WPS_TIMER_SUCCESS_CB src/wps/wps.h /^ SIG_WPS_TIMER_SUCCESS_CB, \/\/7$/;" e enum:wps_sig_type -SIG_WPS_TIMER_TIMEOUT src/wps/wps.h /^ SIG_WPS_TIMER_TIMEOUT, \/\/5$/;" e enum:wps_sig_type -SM_ENTER src/utils/state_machine.h 101;" d -SM_ENTER_GLOBAL src/utils/state_machine.h 114;" d -SM_ENTRY src/utils/state_machine.h 46;" d -SM_ENTRY_M src/utils/state_machine.h 65;" d -SM_ENTRY_MA src/utils/state_machine.h 83;" d -SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, AUTHENTICATION)$/;" f -SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, AUTHENTICATION2)$/;" f -SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, DISCONNECT)$/;" f -SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, DISCONNECTED)$/;" f -SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, INITIALIZE)$/;" f -SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, INITPMK)$/;" f -SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, INITPSK)$/;" f -SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)$/;" f -SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2)$/;" f -SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, PTKINITDONE)$/;" f -SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, PTKINITNEGOTIATING)$/;" f -SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK, PTKSTART)$/;" f -SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK_GROUP, IDLE)$/;" f -SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK_GROUP, KEYERROR)$/;" f -SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)$/;" f -SM_STATE src/ap/wpa_auth.c /^SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)$/;" f -SM_STATE src/utils/state_machine.h 32;" d -SM_STEP src/ap/wpa_auth.c /^SM_STEP(WPA_PTK)$/;" f -SM_STEP src/ap/wpa_auth.c /^SM_STEP(WPA_PTK_GROUP)$/;" f -SM_STEP src/utils/state_machine.h 126;" d -SM_STEP_RUN src/utils/state_machine.h 136;" d -SNonce src/ap/wpa_auth_i.h /^ u8 SNonce[WPA_NONCE_LEN];$/;" m struct:wpa_state_machine -SP1 src/crypto/des-internal.c /^static const u32 SP1[64] =$/;" v file: -SP2 src/crypto/des-internal.c /^static const u32 SP2[64] =$/;" v file: -SP3 src/crypto/des-internal.c /^static const u32 SP3[64] =$/;" v file: -SP4 src/crypto/des-internal.c /^static const u32 SP4[64] =$/;" v file: -SP5 src/crypto/des-internal.c /^static const u32 SP5[64] =$/;" v file: -SP6 src/crypto/des-internal.c /^static const u32 SP6[64] =$/;" v file: -SP7 src/crypto/des-internal.c /^static const u32 SP7[64] =$/;" v file: -SP8 src/crypto/des-internal.c /^static const u32 SP8[64] =$/;" v file: -SSID_LEN src/ap/wpa_auth.h 149;" d -STATE_MACHINE_ADDR src/ap/wpa_auth.c 34;" d file: -STATE_MACHINE_DATA src/ap/wpa_auth.c 32;" d file: -STATE_MACHINE_DEBUG_PREFIX src/ap/wpa_auth.c 33;" d file: -STATE_MACHINE_H src/utils/state_machine.h 21;" d -STA_DEAUTH src/ap/sta_info.h /^ STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE$/;" e enum:sta_info::__anon15 -STA_DISASSOC src/ap/sta_info.h /^ STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE$/;" e enum:sta_info::__anon15 -STA_INFO_H src/ap/sta_info.h 10;" d -STA_NULLFUNC src/ap/sta_info.h /^ STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE$/;" e enum:sta_info::__anon15 -STA_REMOVE src/ap/sta_info.h /^ STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE$/;" e enum:sta_info::__anon15 -STK_ERR_CPHR_NS src/common/wpa_common.h /^ STK_ERR_CPHR_NS = 3,$/;" e enum:__anon65 -STK_ERR_NO_STSL src/common/wpa_common.h /^ STK_ERR_NO_STSL = 4$/;" e enum:__anon65 -STK_ERR_STA_NR src/common/wpa_common.h /^ STK_ERR_STA_NR = 1,$/;" e enum:__anon65 -STK_ERR_STA_NRSN src/common/wpa_common.h /^ STK_ERR_STA_NRSN = 2,$/;" e enum:__anon65 -STK_MUI_4WAY_STAT_STA src/common/wpa_common.h /^ STK_MUI_4WAY_STAT_STA = 2,$/;" e enum:__anon64 -STK_MUI_4WAY_STA_AP src/common/wpa_common.h /^ STK_MUI_4WAY_STA_AP = 1,$/;" e enum:__anon64 -STK_MUI_GTK src/common/wpa_common.h /^ STK_MUI_GTK = 3,$/;" e enum:__anon64 -STK_MUI_SMK src/common/wpa_common.h /^ STK_MUI_SMK = 4$/;" e enum:__anon64 -STRUCT_PACKED include/utils/common.h 218;" d -STRUCT_PACKED include/utils/common.h 221;" d -STRUCT_PACKED src/ap/wpa_auth.h /^} STRUCT_PACKED;$/;" v typeref:struct:ft_r0kh_r1kh_pull_frame -STRUCT_PACKED src/ap/wpa_auth.h /^} STRUCT_PACKED;$/;" v typeref:struct:ft_r0kh_r1kh_push_frame -STRUCT_PACKED src/ap/wpa_auth.h /^} STRUCT_PACKED;$/;" v typeref:struct:ft_r0kh_r1kh_resp_frame -STRUCT_PACKED src/ap/wpa_auth.h /^} STRUCT_PACKED;$/;" v typeref:struct:ft_rrb_frame -STRUCT_PACKED src/common/eapol_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:ieee802_1x_eapol_key -STRUCT_PACKED src/common/eapol_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:ieee802_1x_hdr -STRUCT_PACKED src/common/ieee802_11_defs.h /^} STRUCT_PACKED;$/;" v typeref:struct:wmm_ac_parameter -STRUCT_PACKED src/common/ieee802_11_defs.h /^} STRUCT_PACKED;$/;" v typeref:struct:ieee80211_hdr -STRUCT_PACKED src/common/ieee802_11_defs.h /^} STRUCT_PACKED;$/;" v typeref:struct:ieee80211_ht_capabilities -STRUCT_PACKED src/common/ieee802_11_defs.h /^} STRUCT_PACKED;$/;" v typeref:struct:ieee80211_ht_operation -STRUCT_PACKED src/common/ieee802_11_defs.h /^} STRUCT_PACKED;$/;" v typeref:struct:ieee80211_mgmt -STRUCT_PACKED src/common/ieee802_11_defs.h /^} STRUCT_PACKED;$/;" v typeref:struct:wmm_information_element -STRUCT_PACKED src/common/ieee802_11_defs.h /^} STRUCT_PACKED;$/;" v typeref:struct:wmm_parameter_element -STRUCT_PACKED src/common/ieee802_11_defs.h /^} STRUCT_PACKED;$/;" v typeref:struct:wmm_tspec_element -STRUCT_PACKED src/common/wpa_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:rsn_error_kde -STRUCT_PACKED src/common/wpa_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:rsn_ftie -STRUCT_PACKED src/common/wpa_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:rsn_ie_hdr -STRUCT_PACKED src/common/wpa_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:rsn_mdie -STRUCT_PACKED src/common/wpa_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:rsn_rdie -STRUCT_PACKED src/common/wpa_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:wpa_eapol_key -STRUCT_PACKED src/common/wpa_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:wpa_ie_hdr -STRUCT_PACKED src/common/wpa_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:wpa_igtk_kde -STRUCT_PACKED src/common/wpa_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:wpa_ptk -STRUCT_PACKED src/eap_peer/eap_defs.h /^} STRUCT_PACKED;$/;" v typeref:struct:eap_expand -STRUCT_PACKED src/eap_peer/eap_defs.h /^} STRUCT_PACKED;$/;" v typeref:struct:eap_hdr -STRUCT_PACKED src/eap_peer/eap_tlv_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:eap_tlv_crypto_binding_tlv -STRUCT_PACKED src/eap_peer/eap_tlv_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:eap_tlv_hdr -STRUCT_PACKED src/eap_peer/eap_tlv_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:eap_tlv_intermediate_result_tlv -STRUCT_PACKED src/eap_peer/eap_tlv_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:eap_tlv_nak_tlv -STRUCT_PACKED src/eap_peer/eap_tlv_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:eap_tlv_pac_ack_tlv -STRUCT_PACKED src/eap_peer/eap_tlv_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:eap_tlv_pac_type_tlv -STRUCT_PACKED src/eap_peer/eap_tlv_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:eap_tlv_request_action_tlv -STRUCT_PACKED src/eap_peer/eap_tlv_common.h /^} STRUCT_PACKED;$/;" v typeref:struct:eap_tlv_result_tlv -STRUCT_PACKED src/rsn_supp/wpa.h /^} STRUCT_PACKED;$/;" v typeref:struct:l2_ethhdr -SWAP src/crypto/aes_i.h 115;" d -S_SWAP src/crypto/rc4.c 20;" d file: -Sigma0 src/crypto/sha256-internal.c 91;" d file: -Sigma1 src/crypto/sha256-internal.c 92;" d file: -TAB_SIZE src/crypto/libtommath.h 1906;" d -TAB_SIZE src/crypto/libtommath.h 1908;" d -TAB_SIZE src/tls/libtommath.h 1906;" d -TAB_SIZE src/tls/libtommath.h 1908;" d -TAG include/utils/wpa_debug.h 23;" d -TASK_STACK_SIZE_ADD src/esp_supplicant/esp_wifi_driver.h 22;" d -TASK_STACK_SIZE_ADD src/esp_supplicant/esp_wifi_driver.h 24;" d -TD0 src/crypto/aes_i.h 59;" d -TD0 src/crypto/aes_i.h 99;" d -TD0_ src/crypto/aes_i.h 107;" d -TD0_ src/crypto/aes_i.h 67;" d -TD1 src/crypto/aes_i.h 100;" d -TD1 src/crypto/aes_i.h 60;" d -TD1_ src/crypto/aes_i.h 108;" d -TD1_ src/crypto/aes_i.h 68;" d -TD2 src/crypto/aes_i.h 101;" d -TD2 src/crypto/aes_i.h 61;" d -TD2_ src/crypto/aes_i.h 109;" d -TD2_ src/crypto/aes_i.h 69;" d -TD3 src/crypto/aes_i.h 102;" d -TD3 src/crypto/aes_i.h 62;" d -TD3_ src/crypto/aes_i.h 110;" d -TD3_ src/crypto/aes_i.h 70;" d -TD41 src/crypto/aes_i.h 103;" d -TD41 src/crypto/aes_i.h 63;" d -TD42 src/crypto/aes_i.h 104;" d -TD42 src/crypto/aes_i.h 64;" d -TD43 src/crypto/aes_i.h 105;" d -TD43 src/crypto/aes_i.h 65;" d -TD44 src/crypto/aes_i.h 106;" d -TD44 src/crypto/aes_i.h 66;" d -TDLS_PROHIBIT src/ap/ap_config.h 390;" d -TDLS_PROHIBIT_CHAN_SWITCH src/ap/ap_config.h 391;" d -TE0 src/crypto/aes_i.h 41;" d -TE0 src/crypto/aes_i.h 81;" d -TE1 src/crypto/aes_i.h 42;" d -TE1 src/crypto/aes_i.h 82;" d -TE2 src/crypto/aes_i.h 43;" d -TE2 src/crypto/aes_i.h 83;" d -TE3 src/crypto/aes_i.h 44;" d -TE3 src/crypto/aes_i.h 84;" d -TE4 src/crypto/aes_i.h 57;" d -TE4 src/crypto/aes_i.h 97;" d -TE41 src/crypto/aes_i.h 45;" d -TE41 src/crypto/aes_i.h 85;" d -TE411 src/crypto/aes_i.h 53;" d -TE411 src/crypto/aes_i.h 93;" d -TE414 src/crypto/aes_i.h 52;" d -TE414 src/crypto/aes_i.h 92;" d -TE42 src/crypto/aes_i.h 46;" d -TE42 src/crypto/aes_i.h 86;" d -TE421 src/crypto/aes_i.h 49;" d -TE421 src/crypto/aes_i.h 89;" d -TE422 src/crypto/aes_i.h 54;" d -TE422 src/crypto/aes_i.h 94;" d -TE43 src/crypto/aes_i.h 47;" d -TE43 src/crypto/aes_i.h 87;" d -TE432 src/crypto/aes_i.h 50;" d -TE432 src/crypto/aes_i.h 90;" d -TE433 src/crypto/aes_i.h 55;" d -TE433 src/crypto/aes_i.h 95;" d -TE44 src/crypto/aes_i.h 48;" d -TE44 src/crypto/aes_i.h 88;" d -TE443 src/crypto/aes_i.h 51;" d -TE443 src/crypto/aes_i.h 91;" d -TE444 src/crypto/aes_i.h 56;" d -TE444 src/crypto/aes_i.h 96;" d -TLSV1_CLIENT_H src/tls/tlsv1_client.h 10;" d -TLSV1_CLIENT_I_H src/tls/tlsv1_client_i.h 10;" d -TLSV1_COMMON_H src/tls/tlsv1_common.h 10;" d -TLSV1_CRED_H src/tls/tlsv1_cred.h 10;" d -TLSV1_RECORD_H src/tls/tlsv1_record.h 10;" d -TLSV1_SERVER_H src/tls/tlsv1_server.h 10;" d -TLSV1_SERVER_I_H src/tls/tlsv1_server_i.h 10;" d -TLS_ALERT src/tls/tls.h /^ TLS_ALERT$/;" e enum:tls_event -TLS_ALERT_ACCESS_DENIED src/tls/tlsv1_common.h 145;" d -TLS_ALERT_BAD_CERTIFICATE src/tls/tlsv1_common.h 138;" d -TLS_ALERT_BAD_CERTIFICATE_HASH_VALUE src/tls/tlsv1_common.h 158;" d -TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE src/tls/tlsv1_common.h 157;" d -TLS_ALERT_BAD_RECORD_MAC src/tls/tlsv1_common.h 133;" d -TLS_ALERT_CERTIFICATE_EXPIRED src/tls/tlsv1_common.h 141;" d -TLS_ALERT_CERTIFICATE_REVOKED src/tls/tlsv1_common.h 140;" d -TLS_ALERT_CERTIFICATE_UNKNOWN src/tls/tlsv1_common.h 142;" d -TLS_ALERT_CERTIFICATE_UNOBTAINABLE src/tls/tlsv1_common.h 155;" d -TLS_ALERT_CLOSE_NOTIFY src/tls/tlsv1_common.h 131;" d -TLS_ALERT_DECODE_ERROR src/tls/tlsv1_common.h 146;" d -TLS_ALERT_DECOMPRESSION_FAILURE src/tls/tlsv1_common.h 136;" d -TLS_ALERT_DECRYPTION_FAILED src/tls/tlsv1_common.h 134;" d -TLS_ALERT_DECRYPT_ERROR src/tls/tlsv1_common.h 147;" d -TLS_ALERT_EXPORT_RESTRICTION src/tls/tlsv1_common.h 148;" d -TLS_ALERT_HANDSHAKE_FAILURE src/tls/tlsv1_common.h 137;" d -TLS_ALERT_ILLEGAL_PARAMETER src/tls/tlsv1_common.h 143;" d -TLS_ALERT_INSUFFICIENT_SECURITY src/tls/tlsv1_common.h 150;" d -TLS_ALERT_INTERNAL_ERROR src/tls/tlsv1_common.h 151;" d -TLS_ALERT_LEVEL_FATAL src/tls/tlsv1_common.h 128;" d -TLS_ALERT_LEVEL_WARNING src/tls/tlsv1_common.h 127;" d -TLS_ALERT_NO_RENEGOTIATION src/tls/tlsv1_common.h 153;" d -TLS_ALERT_PROTOCOL_VERSION src/tls/tlsv1_common.h 149;" d -TLS_ALERT_RECORD_OVERFLOW src/tls/tlsv1_common.h 135;" d -TLS_ALERT_UNEXPECTED_MESSAGE src/tls/tlsv1_common.h 132;" d -TLS_ALERT_UNKNOWN_CA src/tls/tlsv1_common.h 144;" d -TLS_ALERT_UNRECOGNIZED_NAME src/tls/tlsv1_common.h 156;" d -TLS_ALERT_UNSUPPORTED_CERTIFICATE src/tls/tlsv1_common.h 139;" d -TLS_ALERT_UNSUPPORTED_EXTENSION src/tls/tlsv1_common.h 154;" d -TLS_ALERT_USER_CANCELED src/tls/tlsv1_common.h 152;" d -TLS_CERT_CHAIN_FAILURE src/tls/tls.h /^ TLS_CERT_CHAIN_FAILURE,$/;" e enum:tls_event -TLS_CERT_CHAIN_SUCCESS src/tls/tls.h /^ TLS_CERT_CHAIN_SUCCESS,$/;" e enum:tls_event -TLS_CHANGE_CIPHER_SPEC src/tls/tlsv1_common.h /^ TLS_CHANGE_CIPHER_SPEC = 1$/;" e enum:__anon48 -TLS_CIPHER_3DES_EDE_CBC src/tls/tlsv1_common.h /^ TLS_CIPHER_3DES_EDE_CBC,$/;" e enum:__anon50 -TLS_CIPHER_AES128_SHA src/tls/tls.h /^ TLS_CIPHER_AES128_SHA \/* 0x002f *\/,$/;" e enum:__anon38 -TLS_CIPHER_AES_128_CBC src/tls/tlsv1_common.h /^ TLS_CIPHER_AES_128_CBC,$/;" e enum:__anon50 -TLS_CIPHER_AES_256_CBC src/tls/tlsv1_common.h /^ TLS_CIPHER_AES_256_CBC$/;" e enum:__anon50 -TLS_CIPHER_ANON_DH_AES128_SHA src/tls/tls.h /^ TLS_CIPHER_ANON_DH_AES128_SHA \/* 0x0034 *\/$/;" e enum:__anon38 -TLS_CIPHER_BLOCK src/tls/tlsv1_common.h /^ TLS_CIPHER_BLOCK$/;" e enum:__anon52 -TLS_CIPHER_DES40_CBC src/tls/tlsv1_common.h /^ TLS_CIPHER_DES40_CBC,$/;" e enum:__anon50 -TLS_CIPHER_DES_CBC src/tls/tlsv1_common.h /^ TLS_CIPHER_DES_CBC,$/;" e enum:__anon50 -TLS_CIPHER_IDEA_CBC src/tls/tlsv1_common.h /^ TLS_CIPHER_IDEA_CBC,$/;" e enum:__anon50 -TLS_CIPHER_NONE src/tls/tls.h /^ TLS_CIPHER_NONE,$/;" e enum:__anon38 -TLS_CIPHER_NULL src/tls/tlsv1_common.h /^ TLS_CIPHER_NULL,$/;" e enum:__anon50 -TLS_CIPHER_RC2_CBC_40 src/tls/tlsv1_common.h /^ TLS_CIPHER_RC2_CBC_40,$/;" e enum:__anon50 -TLS_CIPHER_RC4_128 src/tls/tlsv1_common.h /^ TLS_CIPHER_RC4_128,$/;" e enum:__anon50 -TLS_CIPHER_RC4_40 src/tls/tlsv1_common.h /^ TLS_CIPHER_RC4_40,$/;" e enum:__anon50 -TLS_CIPHER_RC4_SHA src/tls/tls.h /^ TLS_CIPHER_RC4_SHA \/* 0x0005 *\/,$/;" e enum:__anon38 -TLS_CIPHER_RSA_DHE_AES128_SHA src/tls/tls.h /^ TLS_CIPHER_RSA_DHE_AES128_SHA \/* 0x0031 *\/,$/;" e enum:__anon38 -TLS_CIPHER_STREAM src/tls/tlsv1_common.h /^ TLS_CIPHER_STREAM,$/;" e enum:__anon52 -TLS_COMPRESSION_NULL src/tls/tlsv1_common.h 105;" d -TLS_CONN_ALLOW_SIGN_RSA_MD5 src/tls/tls.h 82;" d -TLS_CONN_DISABLE_SESSION_TICKET src/tls/tls.h 84;" d -TLS_CONN_DISABLE_TIME_CHECKS src/tls/tls.h 83;" d -TLS_CONN_REQUEST_OCSP src/tls/tls.h 85;" d -TLS_CONN_REQUIRE_OCSP src/tls/tls.h 86;" d -TLS_CONTENT_TYPE_ALERT src/tls/tlsv1_record.h /^ TLS_CONTENT_TYPE_ALERT = 21,$/;" e enum:__anon44 -TLS_CONTENT_TYPE_APPLICATION_DATA src/tls/tlsv1_record.h /^ TLS_CONTENT_TYPE_APPLICATION_DATA = 23$/;" e enum:__anon44 -TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC src/tls/tlsv1_record.h /^ TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC = 20,$/;" e enum:__anon44 -TLS_CONTENT_TYPE_HANDSHAKE src/tls/tlsv1_record.h /^ TLS_CONTENT_TYPE_HANDSHAKE = 22,$/;" e enum:__anon44 -TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA src/tls/tlsv1_common.h 67;" d -TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA src/tls/tlsv1_common.h 69;" d -TLS_DHE_DSS_WITH_AES_128_CBC_SHA src/tls/tlsv1_common.h 81;" d -TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 src/tls/tlsv1_common.h 95;" d -TLS_DHE_DSS_WITH_AES_256_CBC_SHA src/tls/tlsv1_common.h 87;" d -TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 src/tls/tlsv1_common.h 99;" d -TLS_DHE_DSS_WITH_DES_CBC_SHA src/tls/tlsv1_common.h 68;" d -TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA src/tls/tlsv1_common.h 70;" d -TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA src/tls/tlsv1_common.h 72;" d -TLS_DHE_RSA_WITH_AES_128_CBC_SHA src/tls/tlsv1_common.h 82;" d -TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 src/tls/tlsv1_common.h 96;" d -TLS_DHE_RSA_WITH_AES_256_CBC_SHA src/tls/tlsv1_common.h 88;" d -TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 src/tls/tlsv1_common.h 100;" d -TLS_DHE_RSA_WITH_DES_CBC_SHA src/tls/tlsv1_common.h 71;" d -TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA src/tls/tlsv1_common.h 61;" d -TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA src/tls/tlsv1_common.h 63;" d -TLS_DH_DSS_WITH_AES_128_CBC_SHA src/tls/tlsv1_common.h 79;" d -TLS_DH_DSS_WITH_AES_128_CBC_SHA256 src/tls/tlsv1_common.h 93;" d -TLS_DH_DSS_WITH_AES_256_CBC_SHA src/tls/tlsv1_common.h 85;" d -TLS_DH_DSS_WITH_AES_256_CBC_SHA256 src/tls/tlsv1_common.h 97;" d -TLS_DH_DSS_WITH_DES_CBC_SHA src/tls/tlsv1_common.h 62;" d -TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA src/tls/tlsv1_common.h 64;" d -TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA src/tls/tlsv1_common.h 66;" d -TLS_DH_RSA_WITH_AES_128_CBC_SHA src/tls/tlsv1_common.h 80;" d -TLS_DH_RSA_WITH_AES_128_CBC_SHA256 src/tls/tlsv1_common.h 94;" d -TLS_DH_RSA_WITH_AES_256_CBC_SHA src/tls/tlsv1_common.h 86;" d -TLS_DH_RSA_WITH_AES_256_CBC_SHA256 src/tls/tlsv1_common.h 98;" d -TLS_DH_RSA_WITH_DES_CBC_SHA src/tls/tlsv1_common.h 65;" d -TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA src/tls/tlsv1_common.h 75;" d -TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 src/tls/tlsv1_common.h 73;" d -TLS_DH_anon_WITH_3DES_EDE_CBC_SHA src/tls/tlsv1_common.h 77;" d -TLS_DH_anon_WITH_AES_128_CBC_SHA src/tls/tlsv1_common.h 83;" d -TLS_DH_anon_WITH_AES_128_CBC_SHA256 src/tls/tlsv1_common.h 101;" d -TLS_DH_anon_WITH_AES_256_CBC_SHA src/tls/tlsv1_common.h 89;" d -TLS_DH_anon_WITH_AES_256_CBC_SHA256 src/tls/tlsv1_common.h 102;" d -TLS_DH_anon_WITH_DES_CBC_SHA src/tls/tlsv1_common.h 76;" d -TLS_DH_anon_WITH_RC4_128_MD5 src/tls/tlsv1_common.h 74;" d -TLS_EXT_CLIENT_CERTIFICATE_URL src/tls/tlsv1_common.h 168;" d -TLS_EXT_MAX_FRAGMENT_LENGTH src/tls/tlsv1_common.h 167;" d -TLS_EXT_PAC_OPAQUE src/tls/tlsv1_common.h 174;" d -TLS_EXT_SERVER_NAME src/tls/tlsv1_common.h 166;" d -TLS_EXT_SESSION_TICKET src/tls/tlsv1_common.h 172;" d -TLS_EXT_STATUS_REQUEST src/tls/tlsv1_common.h 171;" d -TLS_EXT_TRUNCATED_HMAC src/tls/tlsv1_common.h 170;" d -TLS_EXT_TRUSTED_CA_KEYS src/tls/tlsv1_common.h 169;" d -TLS_FAIL_ALTSUBJECT_MISMATCH src/tls/tls.h /^ TLS_FAIL_ALTSUBJECT_MISMATCH = 6,$/;" e enum:tls_fail_reason -TLS_FAIL_BAD_CERTIFICATE src/tls/tls.h /^ TLS_FAIL_BAD_CERTIFICATE = 7,$/;" e enum:tls_fail_reason -TLS_FAIL_EXPIRED src/tls/tls.h /^ TLS_FAIL_EXPIRED = 4,$/;" e enum:tls_fail_reason -TLS_FAIL_NOT_YET_VALID src/tls/tls.h /^ TLS_FAIL_NOT_YET_VALID = 3,$/;" e enum:tls_fail_reason -TLS_FAIL_REVOKED src/tls/tls.h /^ TLS_FAIL_REVOKED = 2,$/;" e enum:tls_fail_reason -TLS_FAIL_SERVER_CHAIN_PROBE src/tls/tls.h /^ TLS_FAIL_SERVER_CHAIN_PROBE = 8$/;" e enum:tls_fail_reason -TLS_FAIL_SUBJECT_MISMATCH src/tls/tls.h /^ TLS_FAIL_SUBJECT_MISMATCH = 5,$/;" e enum:tls_fail_reason -TLS_FAIL_UNSPECIFIED src/tls/tls.h /^ TLS_FAIL_UNSPECIFIED = 0,$/;" e enum:tls_fail_reason -TLS_FAIL_UNTRUSTED src/tls/tls.h /^ TLS_FAIL_UNTRUSTED = 1,$/;" e enum:tls_fail_reason -TLS_H src/tls/tls.h 10;" d -TLS_HANDSHAKE_TYPE_CERTIFICATE src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_CERTIFICATE = 11,$/;" e enum:__anon45 -TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST = 13,$/;" e enum:__anon45 -TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS = 22 \/* RFC 4366 *\/$/;" e enum:__anon45 -TLS_HANDSHAKE_TYPE_CERTIFICATE_URL src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_CERTIFICATE_URL = 21 \/* RFC 4366 *\/,$/;" e enum:__anon45 -TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY = 15,$/;" e enum:__anon45 -TLS_HANDSHAKE_TYPE_CLIENT_HELLO src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_CLIENT_HELLO = 1,$/;" e enum:__anon45 -TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE = 16,$/;" e enum:__anon45 -TLS_HANDSHAKE_TYPE_FINISHED src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_FINISHED = 20,$/;" e enum:__anon45 -TLS_HANDSHAKE_TYPE_HELLO_REQUEST src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_HELLO_REQUEST = 0,$/;" e enum:__anon45 -TLS_HANDSHAKE_TYPE_NEW_SESSION_TICKET src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_NEW_SESSION_TICKET = 4 \/* RFC 4507 *\/,$/;" e enum:__anon45 -TLS_HANDSHAKE_TYPE_SERVER_HELLO src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_SERVER_HELLO = 2,$/;" e enum:__anon45 -TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE = 14,$/;" e enum:__anon45 -TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE src/tls/tlsv1_common.h /^ TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE = 12,$/;" e enum:__anon45 -TLS_HASH_ALG_MD5 src/tls/tlsv1_common.h /^ TLS_HASH_ALG_MD5 = 1,$/;" e enum:__anon46 -TLS_HASH_ALG_NONE src/tls/tlsv1_common.h /^ TLS_HASH_ALG_NONE = 0,$/;" e enum:__anon46 -TLS_HASH_ALG_SHA1 src/tls/tlsv1_common.h /^ TLS_HASH_ALG_SHA1 = 2,$/;" e enum:__anon46 -TLS_HASH_ALG_SHA224 src/tls/tlsv1_common.h /^ TLS_HASH_ALG_SHA224 = 3,$/;" e enum:__anon46 -TLS_HASH_ALG_SHA256 src/tls/tlsv1_common.h /^ TLS_HASH_ALG_SHA256 = 4,$/;" e enum:__anon46 -TLS_HASH_ALG_SHA384 src/tls/tlsv1_common.h /^ TLS_HASH_ALG_SHA384 = 5,$/;" e enum:__anon46 -TLS_HASH_ALG_SHA512 src/tls/tlsv1_common.h /^ TLS_HASH_ALG_SHA512 = 6$/;" e enum:__anon46 -TLS_HASH_MD5 src/tls/tlsv1_common.h /^ TLS_HASH_MD5,$/;" e enum:__anon51 -TLS_HASH_NULL src/tls/tlsv1_common.h /^ TLS_HASH_NULL,$/;" e enum:__anon51 -TLS_HASH_SHA src/tls/tlsv1_common.h /^ TLS_HASH_SHA,$/;" e enum:__anon51 -TLS_HASH_SHA256 src/tls/tlsv1_common.h /^ TLS_HASH_SHA256$/;" e enum:__anon51 -TLS_KEY_X_DHE_DSS src/tls/tlsv1_common.h /^ TLS_KEY_X_DHE_DSS,$/;" e enum:__anon49 -TLS_KEY_X_DHE_DSS_EXPORT src/tls/tlsv1_common.h /^ TLS_KEY_X_DHE_DSS_EXPORT,$/;" e enum:__anon49 -TLS_KEY_X_DHE_RSA src/tls/tlsv1_common.h /^ TLS_KEY_X_DHE_RSA,$/;" e enum:__anon49 -TLS_KEY_X_DHE_RSA_EXPORT src/tls/tlsv1_common.h /^ TLS_KEY_X_DHE_RSA_EXPORT,$/;" e enum:__anon49 -TLS_KEY_X_DH_DSS src/tls/tlsv1_common.h /^ TLS_KEY_X_DH_DSS,$/;" e enum:__anon49 -TLS_KEY_X_DH_DSS_EXPORT src/tls/tlsv1_common.h /^ TLS_KEY_X_DH_DSS_EXPORT,$/;" e enum:__anon49 -TLS_KEY_X_DH_RSA src/tls/tlsv1_common.h /^ TLS_KEY_X_DH_RSA,$/;" e enum:__anon49 -TLS_KEY_X_DH_RSA_EXPORT src/tls/tlsv1_common.h /^ TLS_KEY_X_DH_RSA_EXPORT,$/;" e enum:__anon49 -TLS_KEY_X_DH_anon src/tls/tlsv1_common.h /^ TLS_KEY_X_DH_anon$/;" e enum:__anon49 -TLS_KEY_X_DH_anon_EXPORT src/tls/tlsv1_common.h /^ TLS_KEY_X_DH_anon_EXPORT,$/;" e enum:__anon49 -TLS_KEY_X_NULL src/tls/tlsv1_common.h /^ TLS_KEY_X_NULL,$/;" e enum:__anon49 -TLS_KEY_X_RSA src/tls/tlsv1_common.h /^ TLS_KEY_X_RSA,$/;" e enum:__anon49 -TLS_KEY_X_RSA_EXPORT src/tls/tlsv1_common.h /^ TLS_KEY_X_RSA_EXPORT,$/;" e enum:__anon49 -TLS_MASTER_SECRET_LEN src/tls/tlsv1_common.h 28;" d -TLS_MAX_IV_LEN src/tls/tlsv1_record.h 16;" d -TLS_MAX_KEY_BLOCK_LEN src/tls/tlsv1_record.h 17;" d -TLS_MAX_WRITE_KEY_LEN src/tls/tlsv1_record.h 15;" d -TLS_MAX_WRITE_MAC_SECRET_LEN src/tls/tlsv1_record.h 14;" d -TLS_NULL_WITH_NULL_NULL src/tls/tlsv1_common.h 50;" d -TLS_PEER_CERTIFICATE src/tls/tls.h /^ TLS_PEER_CERTIFICATE,$/;" e enum:tls_event -TLS_PRE_MASTER_SECRET_LEN src/tls/tlsv1_common.h 27;" d -TLS_RANDOM_LEN src/tls/tlsv1_common.h 26;" d -TLS_RECORD_HEADER_LEN src/tls/tlsv1_record.h 21;" d -TLS_RSA_EXPORT_WITH_DES40_CBC_SHA src/tls/tlsv1_common.h 58;" d -TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 src/tls/tlsv1_common.h 56;" d -TLS_RSA_EXPORT_WITH_RC4_40_MD5 src/tls/tlsv1_common.h 53;" d -TLS_RSA_WITH_3DES_EDE_CBC_SHA src/tls/tlsv1_common.h 60;" d -TLS_RSA_WITH_AES_128_CBC_SHA src/tls/tlsv1_common.h 78;" d -TLS_RSA_WITH_AES_128_CBC_SHA256 src/tls/tlsv1_common.h 91;" d -TLS_RSA_WITH_AES_256_CBC_SHA src/tls/tlsv1_common.h 84;" d -TLS_RSA_WITH_AES_256_CBC_SHA256 src/tls/tlsv1_common.h 92;" d -TLS_RSA_WITH_DES_CBC_SHA src/tls/tlsv1_common.h 59;" d -TLS_RSA_WITH_IDEA_CBC_SHA src/tls/tlsv1_common.h 57;" d -TLS_RSA_WITH_NULL_MD5 src/tls/tlsv1_common.h 51;" d -TLS_RSA_WITH_NULL_SHA src/tls/tlsv1_common.h 52;" d -TLS_RSA_WITH_NULL_SHA256 src/tls/tlsv1_common.h 90;" d -TLS_RSA_WITH_RC4_128_MD5 src/tls/tlsv1_common.h 54;" d -TLS_RSA_WITH_RC4_128_SHA src/tls/tlsv1_common.h 55;" d -TLS_SEQ_NUM_LEN src/tls/tlsv1_record.h 20;" d -TLS_SESSION_ID_MAX_LEN src/tls/tlsv1_common.h 29;" d -TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED src/tls/tls.h /^ TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2$/;" e enum:__anon37 -TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED src/tls/tls.h /^ TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3,$/;" e enum:__anon37 -TLS_SIGN_ALG_ANONYMOUS src/tls/tlsv1_common.h /^ TLS_SIGN_ALG_ANONYMOUS = 0,$/;" e enum:__anon47 -TLS_SIGN_ALG_DSA src/tls/tlsv1_common.h /^ TLS_SIGN_ALG_DSA = 2,$/;" e enum:__anon47 -TLS_SIGN_ALG_ECDSA src/tls/tlsv1_common.h /^ TLS_SIGN_ALG_ECDSA = 3,$/;" e enum:__anon47 -TLS_SIGN_ALG_RSA src/tls/tlsv1_common.h /^ TLS_SIGN_ALG_RSA = 1,$/;" e enum:__anon47 -TLS_VERIFY_DATA_LEN src/tls/tlsv1_common.h 30;" d -TLS_VERSION src/tls/tlsv1_common.h 18;" d -TLS_VERSION src/tls/tlsv1_common.h 21;" d -TLS_VERSION src/tls/tlsv1_common.h 23;" d -TLS_VERSION_1 src/tls/tlsv1_common.h 14;" d -TLS_VERSION_1_1 src/tls/tlsv1_common.h 15;" d -TLS_VERSION_1_2 src/tls/tlsv1_common.h 16;" d -TRUE src/common/defs.h /^typedef enum { FALSE = 0, TRUE = 1 } Boolean;$/;" e enum:__anon87 -TRUE src/common/defs.h 22;" d -TX_BEAMFORM_CAP_CALIB_OFFSET src/common/ieee802_11_defs.h 426;" d -TX_BEAMFORM_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET src/common/ieee802_11_defs.h 436;" d -TX_BEAMFORM_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET src/common/ieee802_11_defs.h 434;" d -TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_CAP src/common/ieee802_11_defs.h 429;" d -TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET src/common/ieee802_11_defs.h 430;" d -TX_BEAMFORM_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET src/common/ieee802_11_defs.h 432;" d -TX_BEAMFORM_CAP_EXPLICIT_CSI_TXBF_CAP src/common/ieee802_11_defs.h 427;" d -TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_CAP src/common/ieee802_11_defs.h 428;" d -TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET src/common/ieee802_11_defs.h 431;" d -TX_BEAMFORM_CAP_IMPLICIT_ZLF_CAP src/common/ieee802_11_defs.h 425;" d -TX_BEAMFORM_CAP_MINIMAL_GROUPING_OFFSET src/common/ieee802_11_defs.h 433;" d -TX_BEAMFORM_CAP_RX_STAGGERED_SOUNDING_CAP src/common/ieee802_11_defs.h 421;" d -TX_BEAMFORM_CAP_RX_ZLF_CAP src/common/ieee802_11_defs.h 423;" d -TX_BEAMFORM_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET src/common/ieee802_11_defs.h 437;" d -TX_BEAMFORM_CAP_TXBF_CAP src/common/ieee802_11_defs.h 420;" d -TX_BEAMFORM_CAP_TX_STAGGERED_SOUNDING_CAP src/common/ieee802_11_defs.h 422;" d -TX_BEAMFORM_CAP_TX_ZLF_CAP src/common/ieee802_11_defs.h 424;" d -TX_BEAMFORM_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET src/common/ieee802_11_defs.h 435;" d -Td0 src/crypto/aes-internal.c /^const u32 Td0[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v -Td1 src/crypto/aes-internal.c /^const u32 Td1[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v -Td2 src/crypto/aes-internal.c /^const u32 Td2[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v -Td3 src/crypto/aes-internal.c /^const u32 Td3[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v -Td4 src/crypto/aes-internal.c /^const u32 Td4[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v -Td4s src/crypto/aes-internal.c /^const u8 Td4s[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v -Te0 src/crypto/aes-internal.c /^const u32 Te0[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v -Te1 src/crypto/aes-internal.c /^const u32 Te1[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v -Te2 src/crypto/aes-internal.c /^const u32 Te2[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v -Te3 src/crypto/aes-internal.c /^const u32 Te3[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v -Te4 src/crypto/aes-internal.c /^const u32 Te4[256] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v -TimeoutCtr src/ap/wpa_auth_i.h /^ int TimeoutCtr;$/;" m struct:wpa_state_machine -TimeoutEvt src/ap/wpa_auth_i.h /^ Boolean TimeoutEvt;$/;" m struct:wpa_state_machine -USERNAME_LEN_MAX src/esp_supplicant/esp_wpa_enterprise.c 969;" d file: -USE_EXTERNAL_RADIUS_AUTH src/ap/ap_config.h /^ USE_EXTERNAL_RADIUS_AUTH = 2$/;" e enum:hostapd_bss_config::__anon17 -UUID_H src/utils/uuid.h 10;" d -UUID_LEN src/utils/uuid.h 12;" d -VENDOR_HT_CAPAB_OUI_TYPE src/common/ieee802_11_defs.h 592;" d -WEPKEY_64_BYTES include/crypto/wepkey.h 4;" d -WEPKEY_H include/crypto/wepkey.h 2;" d -WFA_ELEM_AUTHORIZEDMACS src/wps/wps_defs.h /^ WFA_ELEM_AUTHORIZEDMACS = 0x01,$/;" e enum:__anon55 -WFA_ELEM_NETWORK_KEY_SHAREABLE src/wps/wps_defs.h /^ WFA_ELEM_NETWORK_KEY_SHAREABLE = 0x02,$/;" e enum:__anon55 -WFA_ELEM_REQUEST_TO_ENROLL src/wps/wps_defs.h /^ WFA_ELEM_REQUEST_TO_ENROLL = 0x03,$/;" e enum:__anon55 -WFA_ELEM_SETTINGS_DELAY_TIME src/wps/wps_defs.h /^ WFA_ELEM_SETTINGS_DELAY_TIME = 0x04$/;" e enum:__anon55 -WFA_ELEM_VERSION2 src/wps/wps_defs.h /^ WFA_ELEM_VERSION2 = 0x00,$/;" e enum:__anon55 -WIFI_APPIE_ASSOC_REQ src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_ASSOC_REQ,$/;" e enum:__anon28 -WIFI_APPIE_ASSOC_RESP src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_ASSOC_RESP,$/;" e enum:__anon28 -WIFI_APPIE_COUNTRY src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_COUNTRY,$/;" e enum:__anon28 -WIFI_APPIE_ESP_MANUFACTOR src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_ESP_MANUFACTOR,$/;" e enum:__anon28 -WIFI_APPIE_FREQ_ERROR src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_FREQ_ERROR,$/;" e enum:__anon28 -WIFI_APPIE_MAX src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_MAX,$/;" e enum:__anon28 -WIFI_APPIE_MESH_QUICK src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_MESH_QUICK,$/;" e enum:__anon28 -WIFI_APPIE_PROBEREQ src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_PROBEREQ = 0,$/;" e enum:__anon28 -WIFI_APPIE_RSN src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_RSN,$/;" e enum:__anon28 -WIFI_APPIE_WPA src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_WPA,$/;" e enum:__anon28 -WIFI_APPIE_WPS_AR src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_WPS_AR,$/;" e enum:__anon28 -WIFI_APPIE_WPS_PR src/esp_supplicant/esp_wifi_driver.h /^ WIFI_APPIE_WPS_PR,$/;" e enum:__anon28 -WIFI_CAPINFO_PRIVACY src/wps/wps.h 1063;" d -WIFI_TID_SIZE src/esp_supplicant/esp_wifi_driver.h 144;" d -WIFI_TXCB_EAPOL_ID src/esp_supplicant/esp_wifi_driver.h 134;" d -WLAN_ACTION_BLOCK_ACK src/common/ieee802_11_defs.h 216;" d -WLAN_ACTION_DLS src/common/ieee802_11_defs.h 215;" d -WLAN_ACTION_FT src/common/ieee802_11_defs.h 219;" d -WLAN_ACTION_HT src/common/ieee802_11_defs.h 220;" d -WLAN_ACTION_PUBLIC src/common/ieee802_11_defs.h 217;" d -WLAN_ACTION_QOS src/common/ieee802_11_defs.h 214;" d -WLAN_ACTION_RADIO_MEASUREMENT src/common/ieee802_11_defs.h 218;" d -WLAN_ACTION_SA_QUERY src/common/ieee802_11_defs.h 221;" d -WLAN_ACTION_SPECTRUM_MGMT src/common/ieee802_11_defs.h 213;" d -WLAN_ACTION_WMM src/common/ieee802_11_defs.h 222;" d -WLAN_AKM_SUITE_8021X src/common/ieee802_11_defs.h 604;" d -WLAN_AKM_SUITE_PSK src/common/ieee802_11_defs.h 605;" d -WLAN_AUTH_CHALLENGE_LEN src/common/ieee802_11_defs.h 81;" d -WLAN_AUTH_FT src/common/ieee802_11_defs.h 78;" d -WLAN_AUTH_LEAP src/common/ieee802_11_defs.h 79;" d -WLAN_AUTH_OPEN src/common/ieee802_11_defs.h 76;" d -WLAN_AUTH_SHARED_KEY src/common/ieee802_11_defs.h 77;" d -WLAN_CAPABILITY_CF_POLLABLE src/common/ieee802_11_defs.h 85;" d -WLAN_CAPABILITY_CF_POLL_REQUEST src/common/ieee802_11_defs.h 86;" d -WLAN_CAPABILITY_CHANNEL_AGILITY src/common/ieee802_11_defs.h 90;" d -WLAN_CAPABILITY_DSSS_OFDM src/common/ieee802_11_defs.h 93;" d -WLAN_CAPABILITY_ESS src/common/ieee802_11_defs.h 83;" d -WLAN_CAPABILITY_IBSS src/common/ieee802_11_defs.h 84;" d -WLAN_CAPABILITY_PBCC src/common/ieee802_11_defs.h 89;" d -WLAN_CAPABILITY_PRIVACY src/common/ieee802_11_defs.h 87;" d -WLAN_CAPABILITY_SHORT_PREAMBLE src/common/ieee802_11_defs.h 88;" d -WLAN_CAPABILITY_SHORT_SLOT_TIME src/common/ieee802_11_defs.h 92;" d -WLAN_CAPABILITY_SPECTRUM_MGMT src/common/ieee802_11_defs.h 91;" d -WLAN_CIPHER_SUITE_AES_CMAC src/common/ieee802_11_defs.h 601;" d -WLAN_CIPHER_SUITE_CCMP src/common/ieee802_11_defs.h 599;" d -WLAN_CIPHER_SUITE_TKIP src/common/ieee802_11_defs.h 597;" d -WLAN_CIPHER_SUITE_USE_GROUP src/common/ieee802_11_defs.h 595;" d -WLAN_CIPHER_SUITE_WEP104 src/common/ieee802_11_defs.h 600;" d -WLAN_CIPHER_SUITE_WEP40 src/common/ieee802_11_defs.h 596;" d -WLAN_EID_20_40_BSS_COEXISTENCE src/common/ieee802_11_defs.h 205;" d -WLAN_EID_20_40_BSS_INTOLERANT src/common/ieee802_11_defs.h 206;" d -WLAN_EID_CF_PARAMS src/common/ieee802_11_defs.h 178;" d -WLAN_EID_CHALLENGE src/common/ieee802_11_defs.h 182;" d -WLAN_EID_CHANNEL_SWITCH src/common/ieee802_11_defs.h 189;" d -WLAN_EID_COUNTRY src/common/ieee802_11_defs.h 181;" d -WLAN_EID_DS_PARAMS src/common/ieee802_11_defs.h 177;" d -WLAN_EID_ERP_INFO src/common/ieee802_11_defs.h 195;" d -WLAN_EID_EXT_SUPP_RATES src/common/ieee802_11_defs.h 198;" d -WLAN_EID_FAST_BSS_TRANSITION src/common/ieee802_11_defs.h 200;" d -WLAN_EID_FH_PARAMS src/common/ieee802_11_defs.h 176;" d -WLAN_EID_HT_CAP src/common/ieee802_11_defs.h 196;" d -WLAN_EID_HT_OPERATION src/common/ieee802_11_defs.h 203;" d -WLAN_EID_IBSS_DFS src/common/ieee802_11_defs.h 193;" d -WLAN_EID_IBSS_PARAMS src/common/ieee802_11_defs.h 180;" d -WLAN_EID_MEASURE_REPORT src/common/ieee802_11_defs.h 191;" d -WLAN_EID_MEASURE_REQUEST src/common/ieee802_11_defs.h 190;" d -WLAN_EID_MMIE src/common/ieee802_11_defs.h 208;" d -WLAN_EID_MOBILITY_DOMAIN src/common/ieee802_11_defs.h 199;" d -WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS src/common/ieee802_11_defs.h 207;" d -WLAN_EID_PWR_CAPABILITY src/common/ieee802_11_defs.h 185;" d -WLAN_EID_PWR_CONSTRAINT src/common/ieee802_11_defs.h 184;" d -WLAN_EID_QUITE src/common/ieee802_11_defs.h 192;" d -WLAN_EID_RIC_DATA src/common/ieee802_11_defs.h 202;" d -WLAN_EID_RSN src/common/ieee802_11_defs.h 197;" d -WLAN_EID_SECONDARY_CHANNEL_OFFSET src/common/ieee802_11_defs.h 204;" d -WLAN_EID_SSID src/common/ieee802_11_defs.h 174;" d -WLAN_EID_SUPPORTED_CHANNELS src/common/ieee802_11_defs.h 188;" d -WLAN_EID_SUPP_RATES src/common/ieee802_11_defs.h 175;" d -WLAN_EID_TIM src/common/ieee802_11_defs.h 179;" d -WLAN_EID_TIMEOUT_INTERVAL src/common/ieee802_11_defs.h 201;" d -WLAN_EID_TPC_REPORT src/common/ieee802_11_defs.h 187;" d -WLAN_EID_TPC_REQUEST src/common/ieee802_11_defs.h 186;" d -WLAN_EID_VENDOR_SPECIFIC src/common/ieee802_11_defs.h 209;" d -WLAN_FC_FROMDS src/common/ieee802_11_defs.h 23;" d -WLAN_FC_GET_STYPE src/common/ieee802_11_defs.h 32;" d -WLAN_FC_GET_TYPE src/common/ieee802_11_defs.h 31;" d -WLAN_FC_ISWEP src/common/ieee802_11_defs.h 28;" d -WLAN_FC_MOREDATA src/common/ieee802_11_defs.h 27;" d -WLAN_FC_MOREFRAG src/common/ieee802_11_defs.h 24;" d -WLAN_FC_ORDER src/common/ieee802_11_defs.h 29;" d -WLAN_FC_PVER src/common/ieee802_11_defs.h 21;" d -WLAN_FC_PWRMGT src/common/ieee802_11_defs.h 26;" d -WLAN_FC_RETRY src/common/ieee802_11_defs.h 25;" d -WLAN_FC_STYPE_ACK src/common/ieee802_11_defs.h 60;" d -WLAN_FC_STYPE_ACTION src/common/ieee802_11_defs.h 54;" d -WLAN_FC_STYPE_ASSOC_REQ src/common/ieee802_11_defs.h 43;" d -WLAN_FC_STYPE_ASSOC_RESP src/common/ieee802_11_defs.h 44;" d -WLAN_FC_STYPE_ATIM src/common/ieee802_11_defs.h 50;" d -WLAN_FC_STYPE_AUTH src/common/ieee802_11_defs.h 52;" d -WLAN_FC_STYPE_BEACON src/common/ieee802_11_defs.h 49;" d -WLAN_FC_STYPE_CFACK src/common/ieee802_11_defs.h 70;" d -WLAN_FC_STYPE_CFACKPOLL src/common/ieee802_11_defs.h 72;" d -WLAN_FC_STYPE_CFEND src/common/ieee802_11_defs.h 61;" d -WLAN_FC_STYPE_CFENDACK src/common/ieee802_11_defs.h 62;" d -WLAN_FC_STYPE_CFPOLL src/common/ieee802_11_defs.h 71;" d -WLAN_FC_STYPE_CTS src/common/ieee802_11_defs.h 59;" d -WLAN_FC_STYPE_DATA src/common/ieee802_11_defs.h 65;" d -WLAN_FC_STYPE_DATA_CFACK src/common/ieee802_11_defs.h 66;" d -WLAN_FC_STYPE_DATA_CFACKPOLL src/common/ieee802_11_defs.h 68;" d -WLAN_FC_STYPE_DATA_CFPOLL src/common/ieee802_11_defs.h 67;" d -WLAN_FC_STYPE_DEAUTH src/common/ieee802_11_defs.h 53;" d -WLAN_FC_STYPE_DISASSOC src/common/ieee802_11_defs.h 51;" d -WLAN_FC_STYPE_NULLFUNC src/common/ieee802_11_defs.h 69;" d -WLAN_FC_STYPE_PROBE_REQ src/common/ieee802_11_defs.h 47;" d -WLAN_FC_STYPE_PROBE_RESP src/common/ieee802_11_defs.h 48;" d -WLAN_FC_STYPE_PSPOLL src/common/ieee802_11_defs.h 57;" d -WLAN_FC_STYPE_QOS_DATA src/common/ieee802_11_defs.h 73;" d -WLAN_FC_STYPE_REASSOC_REQ src/common/ieee802_11_defs.h 45;" d -WLAN_FC_STYPE_REASSOC_RESP src/common/ieee802_11_defs.h 46;" d -WLAN_FC_STYPE_RTS src/common/ieee802_11_defs.h 58;" d -WLAN_FC_TODS src/common/ieee802_11_defs.h 22;" d -WLAN_FC_TYPE_CTRL src/common/ieee802_11_defs.h 39;" d -WLAN_FC_TYPE_DATA src/common/ieee802_11_defs.h 40;" d -WLAN_FC_TYPE_MGMT src/common/ieee802_11_defs.h 38;" d -WLAN_GET_SEQ_FRAG src/common/ieee802_11_defs.h 34;" d -WLAN_GET_SEQ_SEQ src/common/ieee802_11_defs.h 35;" d -WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT src/common/ieee802_11_defs.h 161;" d -WLAN_REASON_AKMP_NOT_VALID src/common/ieee802_11_defs.h 166;" d -WLAN_REASON_CIPHER_SUITE_REJECTED src/common/ieee802_11_defs.h 170;" d -WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA src/common/ieee802_11_defs.h 151;" d -WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA src/common/ieee802_11_defs.h 152;" d -WLAN_REASON_DEAUTH_LEAVING src/common/ieee802_11_defs.h 148;" d -WLAN_REASON_DISASSOC_AP_BUSY src/common/ieee802_11_defs.h 150;" d -WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY src/common/ieee802_11_defs.h 149;" d -WLAN_REASON_DISASSOC_STA_HAS_LEFT src/common/ieee802_11_defs.h 153;" d -WLAN_REASON_GROUP_CIPHER_NOT_VALID src/common/ieee802_11_defs.h 164;" d -WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT src/common/ieee802_11_defs.h 162;" d -WLAN_REASON_IEEE_802_1X_AUTH_FAILED src/common/ieee802_11_defs.h 169;" d -WLAN_REASON_IE_IN_4WAY_DIFFERS src/common/ieee802_11_defs.h 163;" d -WLAN_REASON_INVALID_IE src/common/ieee802_11_defs.h 159;" d -WLAN_REASON_INVALID_RSN_IE_CAPAB src/common/ieee802_11_defs.h 168;" d -WLAN_REASON_MICHAEL_MIC_FAILURE src/common/ieee802_11_defs.h 160;" d -WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID src/common/ieee802_11_defs.h 165;" d -WLAN_REASON_PREV_AUTH_NOT_VALID src/common/ieee802_11_defs.h 147;" d -WLAN_REASON_PWR_CAPABILITY_NOT_VALID src/common/ieee802_11_defs.h 156;" d -WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH src/common/ieee802_11_defs.h 154;" d -WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID src/common/ieee802_11_defs.h 157;" d -WLAN_REASON_UNSPECIFIED src/common/ieee802_11_defs.h 146;" d -WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION src/common/ieee802_11_defs.h 167;" d -WLAN_SA_QUERY_REQUEST src/common/ieee802_11_defs.h 225;" d -WLAN_SA_QUERY_RESPONSE src/common/ieee802_11_defs.h 226;" d -WLAN_SA_QUERY_TR_ID_LEN src/common/ieee802_11_defs.h 228;" d -WLAN_STATUS_AKMP_NOT_VALID src/common/ieee802_11_defs.h 130;" d -WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA src/common/ieee802_11_defs.h 105;" d -WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE src/common/ieee802_11_defs.h 138;" d -WLAN_STATUS_ASSOC_DENIED_NOAGILITY src/common/ieee802_11_defs.h 110;" d -WLAN_STATUS_ASSOC_DENIED_NOPBCC src/common/ieee802_11_defs.h 109;" d -WLAN_STATUS_ASSOC_DENIED_NOSHORT src/common/ieee802_11_defs.h 108;" d -WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM src/common/ieee802_11_defs.h 118;" d -WLAN_STATUS_ASSOC_DENIED_NO_ER_PBCC src/common/ieee802_11_defs.h 117;" d -WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME src/common/ieee802_11_defs.h 116;" d -WLAN_STATUS_ASSOC_DENIED_RATES src/common/ieee802_11_defs.h 106;" d -WLAN_STATUS_ASSOC_DENIED_UNSPEC src/common/ieee802_11_defs.h 100;" d -WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY src/common/ieee802_11_defs.h 121;" d -WLAN_STATUS_AUTH_TIMEOUT src/common/ieee802_11_defs.h 104;" d -WLAN_STATUS_CAPS_UNSUPPORTED src/common/ieee802_11_defs.h 98;" d -WLAN_STATUS_CHALLENGE_FAIL src/common/ieee802_11_defs.h 103;" d -WLAN_STATUS_CIPHER_REJECTED_PER_POLICY src/common/ieee802_11_defs.h 133;" d -WLAN_STATUS_DEST_STA_NOT_PRESENT src/common/ieee802_11_defs.h 136;" d -WLAN_STATUS_DEST_STA_NOT_QOS_STA src/common/ieee802_11_defs.h 137;" d -WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED src/common/ieee802_11_defs.h 135;" d -WLAN_STATUS_GROUP_CIPHER_NOT_VALID src/common/ieee802_11_defs.h 128;" d -WLAN_STATUS_INVALID_FTIE src/common/ieee802_11_defs.h 143;" d -WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT src/common/ieee802_11_defs.h 140;" d -WLAN_STATUS_INVALID_IE src/common/ieee802_11_defs.h 127;" d -WLAN_STATUS_INVALID_MDIE src/common/ieee802_11_defs.h 142;" d -WLAN_STATUS_INVALID_PARAMETERS src/common/ieee802_11_defs.h 125;" d -WLAN_STATUS_INVALID_PMKID src/common/ieee802_11_defs.h 141;" d -WLAN_STATUS_INVALID_RSN_IE_CAPAB src/common/ieee802_11_defs.h 132;" d -WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG src/common/ieee802_11_defs.h 101;" d -WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID src/common/ieee802_11_defs.h 129;" d -WLAN_STATUS_PWR_CAPABILITY_NOT_VALID src/common/ieee802_11_defs.h 113;" d -WLAN_STATUS_R0KH_UNREACHABLE src/common/ieee802_11_defs.h 119;" d -WLAN_STATUS_REASSOC_NO_ASSOC src/common/ieee802_11_defs.h 99;" d -WLAN_STATUS_REQUEST_DECLINED src/common/ieee802_11_defs.h 124;" d -WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION src/common/ieee802_11_defs.h 122;" d -WLAN_STATUS_SPEC_MGMT_REQUIRED src/common/ieee802_11_defs.h 112;" d -WLAN_STATUS_SUCCESS src/common/ieee802_11_defs.h 96;" d -WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID src/common/ieee802_11_defs.h 114;" d -WLAN_STATUS_TS_NOT_CREATED src/common/ieee802_11_defs.h 134;" d -WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION src/common/ieee802_11_defs.h 102;" d -WLAN_STATUS_UNSPECIFIED_FAILURE src/common/ieee802_11_defs.h 97;" d -WLAN_STATUS_UNSPECIFIED_QOS_FAILURE src/common/ieee802_11_defs.h 123;" d -WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION src/common/ieee802_11_defs.h 131;" d -WLAN_STA_ASSOC src/ap/sta_info.h 14;" d -WLAN_STA_ASSOC_REQ_OK src/ap/sta_info.h 28;" d -WLAN_STA_AUTH src/ap/sta_info.h 13;" d -WLAN_STA_AUTHORIZED src/ap/sta_info.h 18;" d -WLAN_STA_GAS src/ap/sta_info.h 30;" d -WLAN_STA_HT src/ap/sta_info.h 24;" d -WLAN_STA_MAYBE_WPS src/ap/sta_info.h 26;" d -WLAN_STA_MFP src/ap/sta_info.h 23;" d -WLAN_STA_NONERP src/ap/sta_info.h 34;" d -WLAN_STA_PENDING_DEAUTH_CB src/ap/sta_info.h 33;" d -WLAN_STA_PENDING_DISASSOC_CB src/ap/sta_info.h 32;" d -WLAN_STA_PENDING_POLL src/ap/sta_info.h 19;" d -WLAN_STA_PERM src/ap/sta_info.h 17;" d -WLAN_STA_PREAUTH src/ap/sta_info.h 21;" d -WLAN_STA_PS src/ap/sta_info.h 15;" d -WLAN_STA_SHORT_PREAMBLE src/ap/sta_info.h 20;" d -WLAN_STA_TIM src/ap/sta_info.h 16;" d -WLAN_STA_VHT src/ap/sta_info.h 31;" d -WLAN_STA_WDS src/ap/sta_info.h 27;" d -WLAN_STA_WMM src/ap/sta_info.h 22;" d -WLAN_STA_WPS src/ap/sta_info.h 25;" d -WLAN_STA_WPS2 src/ap/sta_info.h 29;" d -WLAN_SUPP_RATES_MAX src/ap/sta_info.h 38;" d -WLAN_TIMEOUT_ASSOC_COMEBACK src/common/ieee802_11_defs.h 233;" d -WLAN_TIMEOUT_KEY_LIFETIME src/common/ieee802_11_defs.h 232;" d -WLAN_TIMEOUT_REASSOC_DEADLINE src/common/ieee802_11_defs.h 231;" d -WMM_ACTION_CODE_ADDTS_REQ src/common/ieee802_11_defs.h 488;" d -WMM_ACTION_CODE_ADDTS_RESP src/common/ieee802_11_defs.h 489;" d -WMM_ACTION_CODE_DELTS src/common/ieee802_11_defs.h 490;" d -WMM_AC_ACI_MASK src/common/ieee802_11_defs.h 522;" d -WMM_AC_ACI_SHIFT src/common/ieee802_11_defs.h 523;" d -WMM_AC_ACM src/common/ieee802_11_defs.h 521;" d -WMM_AC_AIFNS_SHIFT src/common/ieee802_11_defs.h 520;" d -WMM_AC_AIFSN_MASK src/common/ieee802_11_defs.h 519;" d -WMM_AC_BE src/common/ieee802_11_defs.h /^ WMM_AC_BE = 0 \/* Best Effort *\/,$/;" e enum:__anon84 -WMM_AC_BK src/common/ieee802_11_defs.h /^ WMM_AC_BK = 1 \/* Background *\/,$/;" e enum:__anon84 -WMM_AC_ECWMAX_MASK src/common/ieee802_11_defs.h 527;" d -WMM_AC_ECWMAX_SHIFT src/common/ieee802_11_defs.h 528;" d -WMM_AC_ECWMIN_MASK src/common/ieee802_11_defs.h 525;" d -WMM_AC_ECWMIN_SHIFT src/common/ieee802_11_defs.h 526;" d -WMM_AC_VI src/common/ieee802_11_defs.h /^ WMM_AC_VI = 2 \/* Video *\/,$/;" e enum:__anon84 -WMM_AC_VO src/common/ieee802_11_defs.h /^ WMM_AC_VO = 3 \/* Voice *\/$/;" e enum:__anon84 -WMM_ADDTS_STATUS_ADMISSION_ACCEPTED src/common/ieee802_11_defs.h 492;" d -WMM_ADDTS_STATUS_INVALID_PARAMETERS src/common/ieee802_11_defs.h 493;" d -WMM_ADDTS_STATUS_REFUSED src/common/ieee802_11_defs.h 495;" d -WMM_OUI_SUBTYPE_INFORMATION_ELEMENT src/common/ieee802_11_defs.h 483;" d -WMM_OUI_SUBTYPE_PARAMETER_ELEMENT src/common/ieee802_11_defs.h 484;" d -WMM_OUI_SUBTYPE_TSPEC_ELEMENT src/common/ieee802_11_defs.h 485;" d -WMM_OUI_TYPE src/common/ieee802_11_defs.h 482;" d -WMM_TSPEC_DIRECTION_BI_DIRECTIONAL src/common/ieee802_11_defs.h 502;" d -WMM_TSPEC_DIRECTION_DOWNLINK src/common/ieee802_11_defs.h 500;" d -WMM_TSPEC_DIRECTION_UPLINK src/common/ieee802_11_defs.h 499;" d -WMM_VERSION src/common/ieee802_11_defs.h 486;" d -WORDS_BIGENDIAN include/utils/common.h 116;" d -WPA2_AUTH_CCKM src/esp_supplicant/esp_wifi_driver.h /^ WPA2_AUTH_CCKM = 0x07,$/;" e enum:__anon29 -WPA2_AUTH_ENT src/esp_supplicant/esp_wifi_driver.h /^ WPA2_AUTH_ENT = 0x04,$/;" e enum:__anon29 -WPA2_AUTH_PSK src/esp_supplicant/esp_wifi_driver.h /^ WPA2_AUTH_PSK = 0x05,$/;" e enum:__anon29 -WPA2_CONFIG_INIT_DEFAULT include/esp_supplicant/esp_wpa_enterprise.h 29;" d -WPA2_ENT_EAP_STATE_FAIL src/esp_supplicant/esp_wifi_driver.h /^ WPA2_ENT_EAP_STATE_FAIL,$/;" e enum:__anon30 -WPA2_ENT_EAP_STATE_IN_PROGRESS src/esp_supplicant/esp_wifi_driver.h /^ WPA2_ENT_EAP_STATE_IN_PROGRESS,$/;" e enum:__anon30 -WPA2_ENT_EAP_STATE_NOT_START src/esp_supplicant/esp_wifi_driver.h /^ WPA2_ENT_EAP_STATE_NOT_START,$/;" e enum:__anon30 -WPA2_ENT_EAP_STATE_SUCCESS src/esp_supplicant/esp_wifi_driver.h /^ WPA2_ENT_EAP_STATE_SUCCESS,$/;" e enum:__anon30 -WPA2_STATE_DISABLED src/eap_peer/eap_i.h /^ WPA2_STATE_DISABLED,$/;" e enum:__anon3 -WPA2_STATE_ENABLED src/eap_peer/eap_i.h /^ WPA2_STATE_ENABLED = 0,$/;" e enum:__anon3 -WPA2_TASK_STACK_SIZE src/esp_supplicant/esp_wifi_driver.h 27;" d -WPA2_VERSION src/esp_supplicant/esp_wpa_enterprise.c 48;" d file: -WPABUF_H include/utils/wpabuf.h 16;" d -WPABUF_MAGIC src/utils/wpabuf.c 25;" d file: -WPAS_GLUE_H src/esp_supplicant/esp_wpas_glue.h 16;" d -WPA_4_4_HANDSHAKE_BIT src/rsn_supp/wpa.c 43;" d file: -WPA_ADDR_LEN src/esp_supplicant/esp_wpa_enterprise.c 130;" d file: -WPA_ALG_CCMP src/common/defs.h /^ WPA_ALG_CCMP = 3,$/;" e enum:wpa_alg -WPA_ALG_GCMP src/common/defs.h /^ WPA_ALG_GCMP$/;" e enum:wpa_alg -WPA_ALG_IGTK src/common/defs.h /^ WPA_ALG_IGTK,$/;" e enum:wpa_alg -WPA_ALG_NONE src/common/defs.h /^ WPA_ALG_NONE =0,$/;" e enum:wpa_alg -WPA_ALG_PMK src/common/defs.h /^ WPA_ALG_PMK,$/;" e enum:wpa_alg -WPA_ALG_TKIP src/common/defs.h /^ WPA_ALG_TKIP = 2,$/;" e enum:wpa_alg -WPA_ALG_WAPI src/common/defs.h /^ WPA_ALG_WAPI = 4,$/;" e enum:wpa_alg -WPA_ALG_WEP src/common/defs.h /^ WPA_ALG_WEP,$/;" e enum:wpa_alg -WPA_ALG_WEP104 src/common/defs.h /^ WPA_ALG_WEP104 = 5,$/;" e enum:wpa_alg -WPA_ALG_WEP40 src/common/defs.h /^ WPA_ALG_WEP40 = 1,$/;" e enum:wpa_alg -WPA_ALLOC_FAIL src/ap/wpa_auth.h /^ WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,$/;" e enum:__anon22 -WPA_ASSERT src/rsn_supp/wpa.h 32;" d -WPA_ASSOC src/ap/wpa_auth.h /^ WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,$/;" e enum:__anon23 -WPA_ASSOCIATED src/common/defs.h /^ WPA_ASSOCIATED,$/;" e enum:wpa_states -WPA_ASSOCIATING src/common/defs.h /^ WPA_ASSOCIATING,$/;" e enum:wpa_states -WPA_ASSOC_FT src/ap/wpa_auth.h /^ WPA_REAUTH_EAPOL, WPA_ASSOC_FT$/;" e enum:__anon23 -WPA_AUTH src/ap/wpa_auth.h /^ WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,$/;" e enum:__anon23 -WPA_AUTHENTICATING src/common/defs.h /^ WPA_AUTHENTICATING,$/;" e enum:wpa_states -WPA_AUTH_ALG_FT src/common/defs.h 80;" d -WPA_AUTH_ALG_LEAP src/common/defs.h 79;" d -WPA_AUTH_ALG_OPEN src/common/defs.h 77;" d -WPA_AUTH_ALG_SHARED src/common/defs.h 78;" d -WPA_AUTH_CCKM src/esp_supplicant/esp_wifi_driver.h /^ WPA_AUTH_CCKM = 0x06,$/;" e enum:__anon29 -WPA_AUTH_H src/ap/wpa_auth.h 10;" d -WPA_AUTH_IE_H src/ap/wpa_auth_ie.h 10;" d -WPA_AUTH_I_H src/ap/wpa_auth_i.h 10;" d -WPA_AUTH_KEY_MGMT_NONE src/common/wpa_common.h 39;" d -WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X src/common/wpa_common.h 41;" d -WPA_AUTH_KEY_MGMT_UNSPEC_802_1X src/common/wpa_common.h 40;" d -WPA_AUTH_PSK src/esp_supplicant/esp_wifi_driver.h /^ WPA_AUTH_PSK = 0x03,$/;" e enum:__anon29 -WPA_AUTH_UNSPEC src/esp_supplicant/esp_wifi_driver.h /^ WPA_AUTH_UNSPEC = 0x02,$/;" e enum:__anon29 -WPA_BSS_MASK_AGE src/common/wpa_ctrl.h 181;" d -WPA_BSS_MASK_ALL src/common/wpa_ctrl.h 171;" d -WPA_BSS_MASK_BEACON_INT src/common/wpa_ctrl.h 175;" d -WPA_BSS_MASK_BSSID src/common/wpa_ctrl.h 173;" d -WPA_BSS_MASK_CAPABILITIES src/common/wpa_ctrl.h 176;" d -WPA_BSS_MASK_DELIM src/common/wpa_ctrl.h 189;" d -WPA_BSS_MASK_FLAGS src/common/wpa_ctrl.h 183;" d -WPA_BSS_MASK_FREQ src/common/wpa_ctrl.h 174;" d -WPA_BSS_MASK_ID src/common/wpa_ctrl.h 172;" d -WPA_BSS_MASK_IE src/common/wpa_ctrl.h 182;" d -WPA_BSS_MASK_INTERNETW src/common/wpa_ctrl.h 187;" d -WPA_BSS_MASK_LEVEL src/common/wpa_ctrl.h 179;" d -WPA_BSS_MASK_NOISE src/common/wpa_ctrl.h 178;" d -WPA_BSS_MASK_P2P_SCAN src/common/wpa_ctrl.h 186;" d -WPA_BSS_MASK_QUAL src/common/wpa_ctrl.h 177;" d -WPA_BSS_MASK_SSID src/common/wpa_ctrl.h 184;" d -WPA_BSS_MASK_TSF src/common/wpa_ctrl.h 180;" d -WPA_BSS_MASK_WIFI_DISPLAY src/common/wpa_ctrl.h 188;" d -WPA_BSS_MASK_WPS_SCAN src/common/wpa_ctrl.h 185;" d -WPA_BYTE_SWAP_DEFINED include/utils/common.h 122;" d -WPA_BYTE_SWAP_DEFINED include/utils/common.h 71;" d -WPA_CAPABILITY_MFPC src/common/wpa_common.h 119;" d -WPA_CAPABILITY_MFPR src/common/wpa_common.h 118;" d -WPA_CAPABILITY_NO_PAIRWISE src/common/wpa_common.h 115;" d -WPA_CAPABILITY_PEERKEY_ENABLED src/common/wpa_common.h 120;" d -WPA_CAPABILITY_PREAUTH src/common/wpa_common.h 114;" d -WPA_CIPHER_AES_128_CMAC src/common/defs.h 31;" d -WPA_CIPHER_CCMP src/common/defs.h 30;" d -WPA_CIPHER_GCMP src/common/defs.h 32;" d -WPA_CIPHER_NONE src/common/defs.h 26;" d -WPA_CIPHER_SUITE_CCMP src/common/wpa_common.h 48;" d -WPA_CIPHER_SUITE_NONE src/common/wpa_common.h 42;" d -WPA_CIPHER_SUITE_TKIP src/common/wpa_common.h 44;" d -WPA_CIPHER_SUITE_WEP104 src/common/wpa_common.h 49;" d -WPA_CIPHER_SUITE_WEP40 src/common/wpa_common.h 43;" d -WPA_CIPHER_TKIP src/common/defs.h 29;" d -WPA_CIPHER_WEP104 src/common/defs.h 28;" d -WPA_CIPHER_WEP40 src/common/defs.h 27;" d -WPA_COMMON_H src/common/wpa_common.h 17;" d -WPA_COMPLETED src/common/defs.h /^ WPA_COMPLETED,$/;" e enum:wpa_states -WPA_CTRL_H src/common/wpa_ctrl.h 10;" d -WPA_CTRL_REQ src/common/wpa_ctrl.h 19;" d -WPA_CTRL_RSP src/common/wpa_ctrl.h 22;" d -WPA_DEAUTH src/ap/wpa_auth.h /^ WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,$/;" e enum:__anon23 -WPA_DEAUTH_FUNC src/rsn_supp/wpa_i.h /^typedef void (*WPA_DEAUTH_FUNC)(u8 reason_code);$/;" t -WPA_DEBUG_H include/utils/wpa_debug.h 16;" d -WPA_DISASSOC src/ap/wpa_auth.h /^ WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,$/;" e enum:__anon23 -WPA_DISCONNECTED src/common/defs.h /^ WPA_DISCONNECTED,$/;" e enum:wpa_states -WPA_EAPOL_authorized src/ap/wpa_auth.h /^ WPA_EAPOL_portEnabled, WPA_EAPOL_portValid, WPA_EAPOL_authorized,$/;" e enum:__anon21 -WPA_EAPOL_inc_EapolFramesTx src/ap/wpa_auth.h /^ WPA_EAPOL_keyDone, WPA_EAPOL_inc_EapolFramesTx$/;" e enum:__anon21 -WPA_EAPOL_keyAvailable src/ap/wpa_auth.h /^ WPA_EAPOL_portControl_Auto, WPA_EAPOL_keyRun, WPA_EAPOL_keyAvailable,$/;" e enum:__anon21 -WPA_EAPOL_keyDone src/ap/wpa_auth.h /^ WPA_EAPOL_keyDone, WPA_EAPOL_inc_EapolFramesTx$/;" e enum:__anon21 -WPA_EAPOL_keyRun src/ap/wpa_auth.h /^ WPA_EAPOL_portControl_Auto, WPA_EAPOL_keyRun, WPA_EAPOL_keyAvailable,$/;" e enum:__anon21 -WPA_EAPOL_portControl_Auto src/ap/wpa_auth.h /^ WPA_EAPOL_portControl_Auto, WPA_EAPOL_keyRun, WPA_EAPOL_keyAvailable,$/;" e enum:__anon21 -WPA_EAPOL_portEnabled src/ap/wpa_auth.h /^ WPA_EAPOL_portEnabled, WPA_EAPOL_portValid, WPA_EAPOL_authorized,$/;" e enum:__anon21 -WPA_EAPOL_portValid src/ap/wpa_auth.h /^ WPA_EAPOL_portEnabled, WPA_EAPOL_portValid, WPA_EAPOL_authorized,$/;" e enum:__anon21 -WPA_EVENT_ASSOC_REJECT src/common/wpa_ctrl.h 30;" d -WPA_EVENT_BSS_ADDED src/common/wpa_ctrl.h 62;" d -WPA_EVENT_BSS_REMOVED src/common/wpa_ctrl.h 64;" d -WPA_EVENT_CONNECTED src/common/wpa_ctrl.h 26;" d -WPA_EVENT_DISCONNECTED src/common/wpa_ctrl.h 28;" d -WPA_EVENT_EAP_FAILURE src/common/wpa_ctrl.h 52;" d -WPA_EVENT_EAP_METHOD src/common/wpa_ctrl.h 42;" d -WPA_EVENT_EAP_NOTIFICATION src/common/wpa_ctrl.h 36;" d -WPA_EVENT_EAP_PEER_CERT src/common/wpa_ctrl.h 44;" d -WPA_EVENT_EAP_PROPOSED_METHOD src/common/wpa_ctrl.h 40;" d -WPA_EVENT_EAP_STARTED src/common/wpa_ctrl.h 38;" d -WPA_EVENT_EAP_STATUS src/common/wpa_ctrl.h 48;" d -WPA_EVENT_EAP_SUCCESS include/utils/wpa_debug.h 36;" d -WPA_EVENT_EAP_SUCCESS src/common/wpa_ctrl.h 50;" d -WPA_EVENT_EAP_TLS_CERT_ERROR src/common/wpa_ctrl.h 46;" d -WPA_EVENT_FREQ_CONFLICT src/common/wpa_ctrl.h 67;" d -WPA_EVENT_PASSWORD_CHANGED src/common/wpa_ctrl.h 34;" d -WPA_EVENT_REENABLED src/common/wpa_ctrl.h 56;" d -WPA_EVENT_SCAN_RESULTS src/common/wpa_ctrl.h 58;" d -WPA_EVENT_STATE_CHANGE src/common/wpa_ctrl.h 60;" d -WPA_EVENT_TEMP_DISABLED src/common/wpa_ctrl.h 54;" d -WPA_EVENT_TERMINATING src/common/wpa_ctrl.h 32;" d -WPA_FIRST_HALF_4WAY_HANDSHAKE src/common/defs.h /^ WPA_FIRST_HALF_4WAY_HANDSHAKE,$/;" e enum:wpa_states -WPA_GET_BE16 include/utils/common.h 128;" d -WPA_GET_BE24 include/utils/common.h 142;" d -WPA_GET_BE32 include/utils/common.h 151;" d -WPA_GET_BE64 include/utils/common.h 171;" d -WPA_GET_KEY src/rsn_supp/wpa_i.h /^typedef int (*WPA_GET_KEY) (u8 *ifx, int *alg, u8 *addt, int *keyidx, u8 *key, size_t key_len, int key_entry_valid);$/;" t -WPA_GET_LE16 include/utils/common.h 135;" d -WPA_GET_LE32 include/utils/common.h 161;" d -WPA_GET_LE64 include/utils/common.h 187;" d -WPA_GMK_LEN src/common/wpa_common.h 27;" d -WPA_GROUP_GTK_INIT src/ap/wpa_auth_i.h /^ WPA_GROUP_GTK_INIT = 0,$/;" e enum:wpa_group::__anon27 -WPA_GROUP_HANDSHAKE src/common/defs.h /^ WPA_GROUP_HANDSHAKE,$/;" e enum:wpa_states -WPA_GROUP_HANDSHAKE_BIT src/rsn_supp/wpa.c 44;" d file: -WPA_GROUP_SETKEYS src/ap/wpa_auth_i.h /^ WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE$/;" e enum:wpa_group::__anon27 -WPA_GROUP_SETKEYSDONE src/ap/wpa_auth_i.h /^ WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE$/;" e enum:wpa_group::__anon27 -WPA_GTK_MAX_LEN src/common/wpa_common.h 28;" d -WPA_H src/rsn_supp/wpa.h 16;" d -WPA_IE_H src/rsn_supp/wpa_ie.h 16;" d -WPA_IE_OK src/ap/wpa_auth.h /^ WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,$/;" e enum:__anon22 -WPA_IE_VENDOR_TYPE src/common/ieee802_11_defs.h 479;" d -WPA_IGTK_LEN src/common/wpa_common.h 109;" d -WPA_INACTIVE src/common/defs.h /^ WPA_INACTIVE,$/;" e enum:wpa_states -WPA_INSTALL_KEY src/rsn_supp/wpa_i.h /^typedef void (*WPA_INSTALL_KEY) (enum wpa_alg alg, u8 *addr, int key_idx, int set_tx,$/;" t -WPA_INVALID_AKMP src/ap/wpa_auth.h /^ WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,$/;" e enum:__anon22 -WPA_INVALID_GROUP src/ap/wpa_auth.h /^ WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,$/;" e enum:__anon22 -WPA_INVALID_IE src/ap/wpa_auth.h /^ WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,$/;" e enum:__anon22 -WPA_INVALID_MDIE src/ap/wpa_auth.h /^ WPA_INVALID_MDIE, WPA_INVALID_PROTO$/;" e enum:__anon22 -WPA_INVALID_MGMT_GROUP_CIPHER src/ap/wpa_auth.h /^ WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER,$/;" e enum:__anon22 -WPA_INVALID_PAIRWISE src/ap/wpa_auth.h /^ WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,$/;" e enum:__anon22 -WPA_INVALID_PROTO src/ap/wpa_auth.h /^ WPA_INVALID_MDIE, WPA_INVALID_PROTO$/;" e enum:__anon22 -WPA_IS_MULTICAST src/ap/wpa_auth.h 20;" d -WPA_I_H src/rsn_supp/wpa_i.h 16;" d -WPA_KEY_INFO_ACK src/common/wpa_common.h 141;" d -WPA_KEY_INFO_ENCR_KEY_DATA src/common/wpa_common.h 146;" d -WPA_KEY_INFO_ERROR src/common/wpa_common.h 144;" d -WPA_KEY_INFO_INSTALL src/common/wpa_common.h 139;" d -WPA_KEY_INFO_KEY_INDEX_MASK src/common/wpa_common.h 137;" d -WPA_KEY_INFO_KEY_INDEX_SHIFT src/common/wpa_common.h 138;" d -WPA_KEY_INFO_KEY_TYPE src/common/wpa_common.h 135;" d -WPA_KEY_INFO_MIC src/common/wpa_common.h 142;" d -WPA_KEY_INFO_REQUEST src/common/wpa_common.h 145;" d -WPA_KEY_INFO_SECURE src/common/wpa_common.h 143;" d -WPA_KEY_INFO_SMK_MESSAGE src/common/wpa_common.h 147;" d -WPA_KEY_INFO_TXRX src/common/wpa_common.h 140;" d -WPA_KEY_INFO_TYPE_AES_128_CMAC src/common/wpa_common.h 134;" d -WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 src/common/wpa_common.h 132;" d -WPA_KEY_INFO_TYPE_HMAC_SHA1_AES src/common/wpa_common.h 133;" d -WPA_KEY_INFO_TYPE_MASK src/common/wpa_common.h 131;" d -WPA_KEY_MGMT_CCKM src/common/defs.h 44;" d -WPA_KEY_MGMT_FT_IEEE8021X src/common/defs.h 39;" d -WPA_KEY_MGMT_FT_PSK src/common/defs.h 40;" d -WPA_KEY_MGMT_IEEE8021X src/common/defs.h 34;" d -WPA_KEY_MGMT_IEEE8021X_NO_WPA src/common/defs.h 37;" d -WPA_KEY_MGMT_IEEE8021X_SHA256 src/common/defs.h 41;" d -WPA_KEY_MGMT_NONE src/common/defs.h 36;" d -WPA_KEY_MGMT_PSK src/common/defs.h 35;" d -WPA_KEY_MGMT_PSK_SHA256 src/common/defs.h 42;" d -WPA_KEY_MGMT_WPA_NONE src/common/defs.h 38;" d -WPA_KEY_MGMT_WPS src/common/defs.h 43;" d -WPA_KEY_RSC_LEN src/common/wpa_common.h 26;" d -WPA_LAST_HALF_4WAY_HANDSHAKE src/common/defs.h /^ WPA_LAST_HALF_4WAY_HANDSHAKE,$/;" e enum:wpa_states -WPA_MAX_SSID_LEN src/common/wpa_common.h 19;" d -WPA_MGMT_FRAME_PROTECTION_VIOLATION src/ap/wpa_auth.h /^ WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER,$/;" e enum:__anon22 -WPA_MIC_FAILURE src/common/defs.h /^ WPA_MIC_FAILURE, \/\/ first mic_error event occur$/;" e enum:wpa_states -WPA_NEG_COMPLETE src/rsn_supp/wpa_i.h /^typedef void (*WPA_NEG_COMPLETE)();$/;" t -WPA_NONCE_LEN src/common/wpa_common.h 25;" d -WPA_NOT_ENABLED src/ap/wpa_auth.h /^ WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,$/;" e enum:__anon22 -WPA_OUI_TYPE src/common/wpa_common.h 94;" d -WPA_PMK_NAME_LEN src/common/wpa_common.h 127;" d -WPA_PROTO_RSN src/common/defs.h 75;" d -WPA_PROTO_WPA src/common/defs.h 74;" d -WPA_PTK_AUTHENTICATION src/ap/wpa_auth_i.h /^ WPA_PTK_AUTHENTICATION, WPA_PTK_AUTHENTICATION2,$/;" e enum:wpa_state_machine::__anon24 -WPA_PTK_AUTHENTICATION2 src/ap/wpa_auth_i.h /^ WPA_PTK_AUTHENTICATION, WPA_PTK_AUTHENTICATION2,$/;" e enum:wpa_state_machine::__anon24 -WPA_PTK_DISCONNECT src/ap/wpa_auth_i.h /^ WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED,$/;" e enum:wpa_state_machine::__anon24 -WPA_PTK_DISCONNECTED src/ap/wpa_auth_i.h /^ WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED,$/;" e enum:wpa_state_machine::__anon24 -WPA_PTK_GROUP_IDLE src/ap/wpa_auth_i.h /^ WPA_PTK_GROUP_IDLE = 0,$/;" e enum:wpa_state_machine::__anon25 -WPA_PTK_GROUP_KEYERROR src/ap/wpa_auth_i.h /^ WPA_PTK_GROUP_KEYERROR$/;" e enum:wpa_state_machine::__anon25 -WPA_PTK_GROUP_REKEYESTABLISHED src/ap/wpa_auth_i.h /^ WPA_PTK_GROUP_REKEYESTABLISHED,$/;" e enum:wpa_state_machine::__anon25 -WPA_PTK_GROUP_REKEYNEGOTIATING src/ap/wpa_auth_i.h /^ WPA_PTK_GROUP_REKEYNEGOTIATING,$/;" e enum:wpa_state_machine::__anon25 -WPA_PTK_INITIALIZE src/ap/wpa_auth_i.h /^ WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED,$/;" e enum:wpa_state_machine::__anon24 -WPA_PTK_INITPMK src/ap/wpa_auth_i.h /^ WPA_PTK_INITPMK, WPA_PTK_INITPSK, WPA_PTK_PTKSTART,$/;" e enum:wpa_state_machine::__anon24 -WPA_PTK_INITPSK src/ap/wpa_auth_i.h /^ WPA_PTK_INITPMK, WPA_PTK_INITPSK, WPA_PTK_PTKSTART,$/;" e enum:wpa_state_machine::__anon24 -WPA_PTK_PTKCALCNEGOTIATING src/ap/wpa_auth_i.h /^ WPA_PTK_PTKCALCNEGOTIATING, WPA_PTK_PTKCALCNEGOTIATING2,$/;" e enum:wpa_state_machine::__anon24 -WPA_PTK_PTKCALCNEGOTIATING2 src/ap/wpa_auth_i.h /^ WPA_PTK_PTKCALCNEGOTIATING, WPA_PTK_PTKCALCNEGOTIATING2,$/;" e enum:wpa_state_machine::__anon24 -WPA_PTK_PTKINITDONE src/ap/wpa_auth_i.h /^ WPA_PTK_PTKINITNEGOTIATING, WPA_PTK_PTKINITDONE$/;" e enum:wpa_state_machine::__anon24 -WPA_PTK_PTKINITNEGOTIATING src/ap/wpa_auth_i.h /^ WPA_PTK_PTKINITNEGOTIATING, WPA_PTK_PTKINITDONE$/;" e enum:wpa_state_machine::__anon24 -WPA_PTK_PTKSTART src/ap/wpa_auth_i.h /^ WPA_PTK_INITPMK, WPA_PTK_INITPSK, WPA_PTK_PTKSTART,$/;" e enum:wpa_state_machine::__anon24 -WPA_PUT_BE16 include/utils/common.h 129;" d -WPA_PUT_BE24 include/utils/common.h 144;" d -WPA_PUT_BE32 include/utils/common.h 153;" d -WPA_PUT_BE64 include/utils/common.h 175;" d -WPA_PUT_LE16 include/utils/common.h 136;" d -WPA_PUT_LE32 include/utils/common.h 163;" d -WPA_REAUTH src/ap/wpa_auth.h /^ WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,$/;" e enum:__anon23 -WPA_REAUTH_EAPOL src/ap/wpa_auth.h /^ WPA_REAUTH_EAPOL, WPA_ASSOC_FT$/;" e enum:__anon23 -WPA_REPLAY_COUNTER_LEN src/common/wpa_common.h 24;" d -WPA_SCANNING src/common/defs.h /^ WPA_SCANNING,$/;" e enum:wpa_states -WPA_SELECTOR_LEN src/common/wpa_common.h 30;" d -WPA_SEND_FUNC src/rsn_supp/wpa_i.h /^typedef void (* WPA_SEND_FUNC)(void *buffer, u16 len);$/;" t -WPA_SET_ASSOC_IE src/rsn_supp/wpa_i.h /^typedef void (* WPA_SET_ASSOC_IE)(u8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len);$/;" t -WPA_SM_MAX_INDEX src/ap/wpa_auth.c 55;" d file: -WPA_SM_STATE src/rsn_supp/wpa.h 25;" d -WPA_TKIP_COUNTERMEASURES src/common/defs.h /^ WPA_TKIP_COUNTERMEASURES \/\/in countermeasure period that stop connect with ap in 60 sec$/;" e enum:wpa_states -WPA_TX_MSG_BUFF_MAXLEN src/ap/wpa_auth.c 159;" d file: -WPA_TX_MSG_BUFF_MAXLEN src/esp_supplicant/esp_wpa_main.c 62;" d file: -WPA_TX_MSG_BUFF_MAXLEN src/rsn_supp/wpa.c 47;" d file: -WPA_VERSION src/common/wpa_common.h 31;" d -WPA_VERSION_NO_WPA src/ap/wpa_auth_i.h /^ WPA_VERSION_NO_WPA = 0 \/* WPA not used *\/,$/;" e enum:wpa_state_machine::__anon26 -WPA_VERSION_WPA src/ap/wpa_auth_i.h /^ WPA_VERSION_WPA = 1 \/* WPA \/ IEEE 802.11i\/D3.0 *\/,$/;" e enum:wpa_state_machine::__anon26 -WPA_VERSION_WPA2 src/ap/wpa_auth_i.h /^ WPA_VERSION_WPA2 = 2 \/* WPA2 \/ IEEE 802.11i *\/$/;" e enum:wpa_state_machine::__anon26 -WPS_ADDR_LEN src/esp_supplicant/esp_wps.c 49;" d file: -WPS_ASSOC_CFG_FAILURE src/wps/wps_defs.h /^ WPS_ASSOC_CFG_FAILURE = 2,$/;" e enum:wps_assoc_state -WPS_ASSOC_CONN_SUCCESS src/wps/wps_defs.h /^ WPS_ASSOC_CONN_SUCCESS = 1,$/;" e enum:wps_assoc_state -WPS_ASSOC_FAILURE src/wps/wps_defs.h /^ WPS_ASSOC_FAILURE = 3,$/;" e enum:wps_assoc_state -WPS_ASSOC_IP_FAILURE src/wps/wps_defs.h /^ WPS_ASSOC_IP_FAILURE = 4$/;" e enum:wps_assoc_state -WPS_ASSOC_NOT_ASSOC src/wps/wps_defs.h /^ WPS_ASSOC_NOT_ASSOC = 0,$/;" e enum:wps_assoc_state -WPS_ATTR_PARSE_H src/wps/wps_attr_parse.h 10;" d -WPS_AUTHENTICATOR_LEN src/wps/wps_defs.h 35;" d -WPS_AUTHKEY_LEN src/wps/wps_defs.h 36;" d -WPS_AUTH_SHARED src/wps/wps_defs.h 191;" d -WPS_AUTH_TYPES src/wps/wps_defs.h 195;" d -WPS_AUTH_WPA src/wps/wps_defs.h 192;" d -WPS_AUTH_WPA2 src/wps/wps_defs.h 193;" d -WPS_AUTH_WPA2PSK src/wps/wps_defs.h 194;" d -WPS_AUTH_WPAPSK src/wps/wps_defs.h 190;" d -WPS_Beacon src/wps/wps_defs.h /^ WPS_Beacon = 0x01,$/;" e enum:wps_msg_type -WPS_CALC_KEY_MAX src/wps/wps_i.h /^ WPS_CALC_KEY_MAX,$/;" e enum:wps_calc_key_mode -WPS_CALC_KEY_NORMAL src/wps/wps_i.h /^ WPS_CALC_KEY_NORMAL = 0,$/;" e enum:wps_calc_key_mode -WPS_CALC_KEY_NO_CALC src/wps/wps_i.h /^ WPS_CALC_KEY_NO_CALC,$/;" e enum:wps_calc_key_mode -WPS_CALC_KEY_PRE_CALC src/wps/wps_i.h /^ WPS_CALC_KEY_PRE_CALC,$/;" e enum:wps_calc_key_mode -WPS_CB_ST_FAILED src/wps/wps.h /^ WPS_CB_ST_FAILED,$/;" e enum:wps_cb_status -WPS_CB_ST_SCAN_ERR src/wps/wps.h /^ WPS_CB_ST_SCAN_ERR,$/;" e enum:wps_cb_status -WPS_CB_ST_SUCCESS src/wps/wps.h /^ WPS_CB_ST_SUCCESS = 0,$/;" e enum:wps_cb_status -WPS_CB_ST_TIMEOUT src/wps/wps.h /^ WPS_CB_ST_TIMEOUT,$/;" e enum:wps_cb_status -WPS_CB_ST_WEP src/wps/wps.h /^ WPS_CB_ST_WEP,$/;" e enum:wps_cb_status -WPS_CFG_24_CHAN_NOT_SUPPORTED src/wps/wps_defs.h /^ WPS_CFG_24_CHAN_NOT_SUPPORTED = 3,$/;" e enum:wps_config_error -WPS_CFG_50_CHAN_NOT_SUPPORTED src/wps/wps_defs.h /^ WPS_CFG_50_CHAN_NOT_SUPPORTED = 4,$/;" e enum:wps_config_error -WPS_CFG_DECRYPTION_CRC_FAILURE src/wps/wps_defs.h /^ WPS_CFG_DECRYPTION_CRC_FAILURE = 2,$/;" e enum:wps_config_error -WPS_CFG_DEVICE_BUSY src/wps/wps_defs.h /^ WPS_CFG_DEVICE_BUSY = 14,$/;" e enum:wps_config_error -WPS_CFG_DEV_PASSWORD_AUTH_FAILURE src/wps/wps_defs.h /^ WPS_CFG_DEV_PASSWORD_AUTH_FAILURE = 18$/;" e enum:wps_config_error -WPS_CFG_FAILED_DHCP_CONFIG src/wps/wps_defs.h /^ WPS_CFG_FAILED_DHCP_CONFIG = 9,$/;" e enum:wps_config_error -WPS_CFG_IP_ADDR_CONFLICT src/wps/wps_defs.h /^ WPS_CFG_IP_ADDR_CONFLICT = 10,$/;" e enum:wps_config_error -WPS_CFG_MSG_TIMEOUT src/wps/wps_defs.h /^ WPS_CFG_MSG_TIMEOUT = 16,$/;" e enum:wps_config_error -WPS_CFG_MULTIPLE_PBC_DETECTED src/wps/wps_defs.h /^ WPS_CFG_MULTIPLE_PBC_DETECTED = 12,$/;" e enum:wps_config_error -WPS_CFG_NETWORK_ASSOC_FAILURE src/wps/wps_defs.h /^ WPS_CFG_NETWORK_ASSOC_FAILURE = 7,$/;" e enum:wps_config_error -WPS_CFG_NETWORK_AUTH_FAILURE src/wps/wps_defs.h /^ WPS_CFG_NETWORK_AUTH_FAILURE = 6,$/;" e enum:wps_config_error -WPS_CFG_NO_CONN_TO_REGISTRAR src/wps/wps_defs.h /^ WPS_CFG_NO_CONN_TO_REGISTRAR = 11,$/;" e enum:wps_config_error -WPS_CFG_NO_DHCP_RESPONSE src/wps/wps_defs.h /^ WPS_CFG_NO_DHCP_RESPONSE = 8,$/;" e enum:wps_config_error -WPS_CFG_NO_ERROR src/wps/wps_defs.h /^ WPS_CFG_NO_ERROR = 0,$/;" e enum:wps_config_error -WPS_CFG_OOB_IFACE_READ_ERROR src/wps/wps_defs.h /^ WPS_CFG_OOB_IFACE_READ_ERROR = 1,$/;" e enum:wps_config_error -WPS_CFG_REG_SESS_TIMEOUT src/wps/wps_defs.h /^ WPS_CFG_REG_SESS_TIMEOUT = 17,$/;" e enum:wps_config_error -WPS_CFG_ROGUE_SUSPECTED src/wps/wps_defs.h /^ WPS_CFG_ROGUE_SUSPECTED = 13,$/;" e enum:wps_config_error -WPS_CFG_SETUP_LOCKED src/wps/wps_defs.h /^ WPS_CFG_SETUP_LOCKED = 15,$/;" e enum:wps_config_error -WPS_CFG_SIGNAL_TOO_WEAK src/wps/wps_defs.h /^ WPS_CFG_SIGNAL_TOO_WEAK = 5,$/;" e enum:wps_config_error -WPS_CONFIG_DISPLAY src/wps/wps_defs.h 245;" d -WPS_CONFIG_ETHERNET src/wps/wps_defs.h 243;" d -WPS_CONFIG_EXT_NFC_TOKEN src/wps/wps_defs.h 246;" d -WPS_CONFIG_INIT_DEFAULT include/esp_supplicant/esp_wps.h 80;" d -WPS_CONFIG_INT_NFC_TOKEN src/wps/wps_defs.h 247;" d -WPS_CONFIG_KEYPAD src/wps/wps_defs.h 250;" d -WPS_CONFIG_LABEL src/wps/wps_defs.h 244;" d -WPS_CONFIG_NFC_INTERFACE src/wps/wps_defs.h 248;" d -WPS_CONFIG_PHY_DISPLAY src/wps/wps_defs.h 255;" d -WPS_CONFIG_PHY_PUSHBUTTON src/wps/wps_defs.h 253;" d -WPS_CONFIG_PUSHBUTTON src/wps/wps_defs.h 249;" d -WPS_CONFIG_USBA src/wps/wps_defs.h 242;" d -WPS_CONFIG_VIRT_DISPLAY src/wps/wps_defs.h 254;" d -WPS_CONFIG_VIRT_PUSHBUTTON src/wps/wps_defs.h 252;" d -WPS_CONN_ESS src/wps/wps_defs.h 259;" d -WPS_CONN_IBSS src/wps/wps_defs.h 260;" d -WPS_CONTINUE src/wps/wps.h /^ WPS_CONTINUE,$/;" e enum:wps_process_res -WPS_DEFS_H src/wps/wps_defs.h 10;" d -WPS_DEV_ATTR_H src/wps/wps_dev_attr.h 10;" d -WPS_DEV_CAMERA src/wps/wps_defs.h /^ WPS_DEV_CAMERA = 4,$/;" e enum:wps_dev_categ -WPS_DEV_CAMERA_DIGITAL_STILL_CAMERA src/wps/wps_defs.h /^ WPS_DEV_CAMERA_DIGITAL_STILL_CAMERA = 1,$/;" e enum:wps_dev_subcateg -WPS_DEV_COMPUTER src/wps/wps_defs.h /^ WPS_DEV_COMPUTER = 1,$/;" e enum:wps_dev_categ -WPS_DEV_COMPUTER_MEDIA_CENTER src/wps/wps_defs.h /^ WPS_DEV_COMPUTER_MEDIA_CENTER = 3,$/;" e enum:wps_dev_subcateg -WPS_DEV_COMPUTER_PC src/wps/wps_defs.h /^ WPS_DEV_COMPUTER_PC = 1,$/;" e enum:wps_dev_subcateg -WPS_DEV_COMPUTER_SERVER src/wps/wps_defs.h /^ WPS_DEV_COMPUTER_SERVER = 2,$/;" e enum:wps_dev_subcateg -WPS_DEV_DISPLAY src/wps/wps_defs.h /^ WPS_DEV_DISPLAY = 7,$/;" e enum:wps_dev_categ -WPS_DEV_DISPLAY_PICTURE_FRAME src/wps/wps_defs.h /^ WPS_DEV_DISPLAY_PICTURE_FRAME = 2,$/;" e enum:wps_dev_subcateg -WPS_DEV_DISPLAY_PROJECTOR src/wps/wps_defs.h /^ WPS_DEV_DISPLAY_PROJECTOR = 3,$/;" e enum:wps_dev_subcateg -WPS_DEV_DISPLAY_TV src/wps/wps_defs.h /^ WPS_DEV_DISPLAY_TV = 1,$/;" e enum:wps_dev_subcateg -WPS_DEV_GAMING src/wps/wps_defs.h /^ WPS_DEV_GAMING = 9,$/;" e enum:wps_dev_categ -WPS_DEV_GAMING_PLAYSTATION src/wps/wps_defs.h /^ WPS_DEV_GAMING_PLAYSTATION = 3,$/;" e enum:wps_dev_subcateg -WPS_DEV_GAMING_XBOX src/wps/wps_defs.h /^ WPS_DEV_GAMING_XBOX = 1,$/;" e enum:wps_dev_subcateg -WPS_DEV_GAMING_XBOX360 src/wps/wps_defs.h /^ WPS_DEV_GAMING_XBOX360 = 2,$/;" e enum:wps_dev_subcateg -WPS_DEV_INPUT src/wps/wps_defs.h /^ WPS_DEV_INPUT = 2,$/;" e enum:wps_dev_categ -WPS_DEV_MULTIMEDIA src/wps/wps_defs.h /^ WPS_DEV_MULTIMEDIA = 8,$/;" e enum:wps_dev_categ -WPS_DEV_MULTIMEDIA_DAR src/wps/wps_defs.h /^ WPS_DEV_MULTIMEDIA_DAR = 1,$/;" e enum:wps_dev_subcateg -WPS_DEV_MULTIMEDIA_MCX src/wps/wps_defs.h /^ WPS_DEV_MULTIMEDIA_MCX = 3,$/;" e enum:wps_dev_subcateg -WPS_DEV_MULTIMEDIA_PVR src/wps/wps_defs.h /^ WPS_DEV_MULTIMEDIA_PVR = 2,$/;" e enum:wps_dev_subcateg -WPS_DEV_NETWORK_INFRA src/wps/wps_defs.h /^ WPS_DEV_NETWORK_INFRA = 6,$/;" e enum:wps_dev_categ -WPS_DEV_NETWORK_INFRA_AP src/wps/wps_defs.h /^ WPS_DEV_NETWORK_INFRA_AP = 1,$/;" e enum:wps_dev_subcateg -WPS_DEV_NETWORK_INFRA_ROUTER src/wps/wps_defs.h /^ WPS_DEV_NETWORK_INFRA_ROUTER = 2,$/;" e enum:wps_dev_subcateg -WPS_DEV_NETWORK_INFRA_SWITCH src/wps/wps_defs.h /^ WPS_DEV_NETWORK_INFRA_SWITCH = 3,$/;" e enum:wps_dev_subcateg -WPS_DEV_OUI_WFA src/wps/wps_defs.h 278;" d -WPS_DEV_PHONE src/wps/wps_defs.h /^ WPS_DEV_PHONE = 10$/;" e enum:wps_dev_categ -WPS_DEV_PHONE_WINDOWS_MOBILE src/wps/wps_defs.h /^ WPS_DEV_PHONE_WINDOWS_MOBILE = 1$/;" e enum:wps_dev_subcateg -WPS_DEV_PRINTER src/wps/wps_defs.h /^ WPS_DEV_PRINTER = 3,$/;" e enum:wps_dev_categ -WPS_DEV_PRINTER_PRINTER src/wps/wps_defs.h /^ WPS_DEV_PRINTER_PRINTER = 1,$/;" e enum:wps_dev_subcateg -WPS_DEV_PRINTER_SCANNER src/wps/wps_defs.h /^ WPS_DEV_PRINTER_SCANNER = 2,$/;" e enum:wps_dev_subcateg -WPS_DEV_STORAGE src/wps/wps_defs.h /^ WPS_DEV_STORAGE = 5,$/;" e enum:wps_dev_categ -WPS_DEV_STORAGE_NAS src/wps/wps_defs.h /^ WPS_DEV_STORAGE_NAS = 1,$/;" e enum:wps_dev_subcateg -WPS_DEV_TYPE_BUFSIZE src/wps/wps.h 64;" d -WPS_DEV_TYPE_LEN src/wps/wps.h 63;" d -WPS_DH_GROUP src/wps/wps_defs.h 31;" d -WPS_DONE src/wps/wps.h /^ WPS_DONE,$/;" e enum:wps_process_res -WPS_EAP_EXT_VENDOR_TYPE src/wps/wps.h 1026;" d -WPS_EI_NO_ERROR src/wps/wps_defs.h /^ WPS_EI_NO_ERROR,$/;" e enum:wps_error_indication -WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED src/wps/wps_defs.h /^ WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED,$/;" e enum:wps_error_indication -WPS_EI_SECURITY_WEP_PROHIBITED src/wps/wps_defs.h /^ WPS_EI_SECURITY_WEP_PROHIBITED,$/;" e enum:wps_error_indication -WPS_EMSK_LEN src/wps/wps_defs.h 38;" d -WPS_ENCR_AES src/wps/wps_defs.h 202;" d -WPS_ENCR_NONE src/wps/wps_defs.h 199;" d -WPS_ENCR_TKIP src/wps/wps_defs.h 201;" d -WPS_ENCR_TYPES src/wps/wps_defs.h 203;" d -WPS_ENCR_WEP src/wps/wps_defs.h 200;" d -WPS_ER_SET_SEL_REG_DONE src/wps/wps.h /^ WPS_ER_SET_SEL_REG_DONE,$/;" e enum:wps_event_data::wps_event_er_set_selected_registrar::__anon54 -WPS_ER_SET_SEL_REG_FAILED src/wps/wps.h /^ WPS_ER_SET_SEL_REG_FAILED$/;" e enum:wps_event_data::wps_event_er_set_selected_registrar::__anon54 -WPS_ER_SET_SEL_REG_START src/wps/wps.h /^ WPS_ER_SET_SEL_REG_START,$/;" e enum:wps_event_data::wps_event_er_set_selected_registrar::__anon54 -WPS_EVENT_ACTIVE src/common/wpa_ctrl.h 95;" d -WPS_EVENT_AP_AVAILABLE src/common/wpa_ctrl.h 83;" d -WPS_EVENT_AP_AVAILABLE_AUTH src/common/wpa_ctrl.h 78;" d -WPS_EVENT_AP_AVAILABLE_PBC src/common/wpa_ctrl.h 76;" d -WPS_EVENT_AP_AVAILABLE_PIN src/common/wpa_ctrl.h 81;" d -WPS_EVENT_AP_PIN_DISABLED src/common/wpa_ctrl.h 162;" d -WPS_EVENT_AP_PIN_ENABLED src/common/wpa_ctrl.h 161;" d -WPS_EVENT_AP_SETUP_LOCKED src/common/wpa_ctrl.h 159;" d -WPS_EVENT_AP_SETUP_UNLOCKED src/common/wpa_ctrl.h 160;" d -WPS_EVENT_CRED_RECEIVED src/common/wpa_ctrl.h 85;" d -WPS_EVENT_DISABLE src/common/wpa_ctrl.h 97;" d -WPS_EVENT_ENROLLEE_SEEN src/common/wpa_ctrl.h 99;" d -WPS_EVENT_ER_AP_ADD src/common/wpa_ctrl.h 104;" d -WPS_EVENT_ER_AP_REMOVE src/common/wpa_ctrl.h 105;" d -WPS_EVENT_ER_AP_SETTINGS src/common/wpa_ctrl.h 108;" d -WPS_EVENT_ER_ENROLLEE_ADD src/common/wpa_ctrl.h 106;" d -WPS_EVENT_ER_ENROLLEE_REMOVE src/common/wpa_ctrl.h 107;" d -WPS_EVENT_ER_SET_SEL_REG src/common/wpa_ctrl.h 109;" d -WPS_EVENT_FAIL src/common/wpa_ctrl.h 89;" d -WPS_EVENT_M2D src/common/wpa_ctrl.h 87;" d -WPS_EVENT_NEW_AP_SETTINGS src/common/wpa_ctrl.h 157;" d -WPS_EVENT_OPEN_NETWORK src/common/wpa_ctrl.h 101;" d -WPS_EVENT_OVERLAP src/common/wpa_ctrl.h 74;" d -WPS_EVENT_PIN_NEEDED src/common/wpa_ctrl.h 156;" d -WPS_EVENT_REG_SUCCESS src/common/wpa_ctrl.h 158;" d -WPS_EVENT_SUCCESS src/common/wpa_ctrl.h 91;" d -WPS_EVENT_TIMEOUT src/common/wpa_ctrl.h 93;" d -WPS_EV_AP_PIN_SUCCESS src/wps/wps.h /^ WPS_EV_AP_PIN_SUCCESS$/;" e enum:wps_event -WPS_EV_ER_AP_ADD src/wps/wps.h /^ WPS_EV_ER_AP_ADD,$/;" e enum:wps_event -WPS_EV_ER_AP_REMOVE src/wps/wps.h /^ WPS_EV_ER_AP_REMOVE,$/;" e enum:wps_event -WPS_EV_ER_AP_SETTINGS src/wps/wps.h /^ WPS_EV_ER_AP_SETTINGS,$/;" e enum:wps_event -WPS_EV_ER_ENROLLEE_ADD src/wps/wps.h /^ WPS_EV_ER_ENROLLEE_ADD,$/;" e enum:wps_event -WPS_EV_ER_ENROLLEE_REMOVE src/wps/wps.h /^ WPS_EV_ER_ENROLLEE_REMOVE,$/;" e enum:wps_event -WPS_EV_ER_SET_SELECTED_REGISTRAR src/wps/wps.h /^ WPS_EV_ER_SET_SELECTED_REGISTRAR,$/;" e enum:wps_event -WPS_EV_FAIL src/wps/wps.h /^ WPS_EV_FAIL,$/;" e enum:wps_event -WPS_EV_M2D src/wps/wps.h /^ WPS_EV_M2D,$/;" e enum:wps_event -WPS_EV_PBC_OVERLAP src/wps/wps.h /^ WPS_EV_PBC_OVERLAP,$/;" e enum:wps_event -WPS_EV_PBC_TIMEOUT src/wps/wps.h /^ WPS_EV_PBC_TIMEOUT,$/;" e enum:wps_event -WPS_EV_PWD_AUTH_FAIL src/wps/wps.h /^ WPS_EV_PWD_AUTH_FAIL,$/;" e enum:wps_event -WPS_EV_SUCCESS src/wps/wps.h /^ WPS_EV_SUCCESS,$/;" e enum:wps_event -WPS_FAILURE src/wps/wps.h /^ WPS_FAILURE,$/;" e enum:wps_process_res -WPS_FINISHED src/wps/wps_i.h /^ RECV_M8, RECEIVED_M2D, WPS_MSG_DONE, RECV_ACK, WPS_FINISHED,$/;" e enum:wps_data::__anon53 -WPS_FRAGMENT src/wps/wps.h /^ WPS_FRAGMENT \/* Tim, send wsc fragment ack *\/$/;" e enum:wps_process_res -WPS_H src/wps/wps.h 10;" d -WPS_HASH_LEN src/wps/wps_defs.h 41;" d -WPS_IE_VENDOR_TYPE src/common/ieee802_11_defs.h 480;" d -WPS_IGNORE src/wps/wps.h /^ WPS_IGNORE, \/* snake, ignore the re-packge *\/$/;" e enum:wps_process_res -WPS_IGNORE_SEL_REG_MAX_CNT src/wps/wps_defs.h 338;" d -WPS_IGNORE_STATE src/wps/wps_enrollee.c 1235;" d file: -WPS_I_H src/wps/wps_i.h 10;" d -WPS_KEYWRAPKEY_LEN src/wps/wps_defs.h 37;" d -WPS_KWA_LEN src/wps/wps_defs.h 42;" d -WPS_M1 src/wps/wps_defs.h /^ WPS_M1 = 0x04,$/;" e enum:wps_msg_type -WPS_M2 src/wps/wps_defs.h /^ WPS_M2 = 0x05,$/;" e enum:wps_msg_type -WPS_M2D src/wps/wps_defs.h /^ WPS_M2D = 0x06,$/;" e enum:wps_msg_type -WPS_M3 src/wps/wps_defs.h /^ WPS_M3 = 0x07,$/;" e enum:wps_msg_type -WPS_M4 src/wps/wps_defs.h /^ WPS_M4 = 0x08,$/;" e enum:wps_msg_type -WPS_M5 src/wps/wps_defs.h /^ WPS_M5 = 0x09,$/;" e enum:wps_msg_type -WPS_M6 src/wps/wps_defs.h /^ WPS_M6 = 0x0a,$/;" e enum:wps_msg_type -WPS_M7 src/wps/wps_defs.h /^ WPS_M7 = 0x0b,$/;" e enum:wps_msg_type -WPS_M8 src/wps/wps_defs.h /^ WPS_M8 = 0x0c,$/;" e enum:wps_msg_type -WPS_MAX_AUTHORIZED_MACS src/wps/wps_defs.h 336;" d -WPS_MAX_DEVICE_NAME_LEN include/esp_supplicant/esp_wps.h 66;" d -WPS_MAX_DIS_AP_NUM src/wps/wps_defs.h 340;" d -WPS_MAX_MANUFACTURER_LEN include/esp_supplicant/esp_wps.h 63;" d -WPS_MAX_MODEL_NAME_LEN include/esp_supplicant/esp_wps.h 65;" d -WPS_MAX_MODEL_NUMBER_LEN include/esp_supplicant/esp_wps.h 64;" d -WPS_MAX_VENDOR_EXT_LEN src/wps/wps.h 69;" d -WPS_MGMTAUTHKEY_LEN src/wps/wps_defs.h 43;" d -WPS_MGMTENCKEY_LEN src/wps/wps_defs.h 44;" d -WPS_MGMT_KEY_ID_LEN src/wps/wps_defs.h 45;" d -WPS_MSG_DONE src/wps/wps_i.h /^ RECV_M8, RECEIVED_M2D, WPS_MSG_DONE, RECV_ACK, WPS_FINISHED,$/;" e enum:wps_data::__anon53 -WPS_MSG_FLAG_LEN src/wps/wps_defs.h /^ WPS_MSG_FLAG_LEN = 0x02$/;" e enum:wps_msg_flag -WPS_MSG_FLAG_MORE src/wps/wps_defs.h /^ WPS_MSG_FLAG_MORE = 0x01,$/;" e enum:wps_msg_flag -WPS_NONCE_LEN src/wps/wps_defs.h 34;" d -WPS_OOB_DEVICE_PASSWORD_LEN src/wps/wps_defs.h 47;" d -WPS_OOB_DEVICE_PASSWORD_MIN_LEN src/wps/wps_defs.h 46;" d -WPS_OOB_PUBKEY_HASH_LEN src/wps/wps_defs.h 48;" d -WPS_OUTBUF_SIZE src/wps/wps.h 1027;" d -WPS_PBC_WALK_TIME src/wps/wps_defs.h 334;" d -WPS_PENDING src/wps/wps.h /^ WPS_PENDING,$/;" e enum:wps_process_res -WPS_PSK_LEN src/wps/wps_defs.h 39;" d -WPS_ProbeRequest src/wps/wps_defs.h /^ WPS_ProbeRequest = 0x02,$/;" e enum:wps_msg_type -WPS_ProbeResponse src/wps/wps_defs.h /^ WPS_ProbeResponse = 0x03,$/;" e enum:wps_msg_type -WPS_REQ_ENROLLEE src/wps/wps_defs.h /^ WPS_REQ_ENROLLEE = 1,$/;" e enum:wps_request_type -WPS_REQ_ENROLLEE_INFO src/wps/wps_defs.h /^ WPS_REQ_ENROLLEE_INFO = 0,$/;" e enum:wps_request_type -WPS_REQ_REGISTRAR src/wps/wps_defs.h /^ WPS_REQ_REGISTRAR = 2,$/;" e enum:wps_request_type -WPS_REQ_WLAN_MANAGER_REGISTRAR src/wps/wps_defs.h /^ WPS_REQ_WLAN_MANAGER_REGISTRAR = 3$/;" e enum:wps_request_type -WPS_RESP_AP src/wps/wps_defs.h /^ WPS_RESP_AP = 3$/;" e enum:wps_response_type -WPS_RESP_ENROLLEE src/wps/wps_defs.h /^ WPS_RESP_ENROLLEE = 1,$/;" e enum:wps_response_type -WPS_RESP_ENROLLEE_INFO src/wps/wps_defs.h /^ WPS_RESP_ENROLLEE_INFO = 0,$/;" e enum:wps_response_type -WPS_RESP_REGISTRAR src/wps/wps_defs.h /^ WPS_RESP_REGISTRAR = 2,$/;" e enum:wps_response_type -WPS_RF_24GHZ src/wps/wps_defs.h 238;" d -WPS_RF_50GHZ src/wps/wps_defs.h 239;" d -WPS_SECRET_NONCE_LEN src/wps/wps_defs.h 40;" d -WPS_SEC_DEVICE_TYPES src/wps/wps.h 96;" d -WPS_SEC_DEV_TYPE_MAX_LEN src/wps/wps.h 65;" d -WPS_STATE_CONFIGURED src/wps/wps_defs.h /^ WPS_STATE_CONFIGURED = 2$/;" e enum:wps_state -WPS_STATE_NOT_CONFIGURED src/wps/wps_defs.h /^ WPS_STATE_NOT_CONFIGURED = 1,$/;" e enum:wps_state -WPS_STATUS_DISABLE src/esp_supplicant/esp_wifi_driver.h /^ WPS_STATUS_DISABLE = 0,$/;" e enum:wps_status -WPS_STATUS_MAX src/esp_supplicant/esp_wifi_driver.h /^ WPS_STATUS_MAX,$/;" e enum:wps_status -WPS_STATUS_PENDING src/esp_supplicant/esp_wifi_driver.h /^ WPS_STATUS_PENDING,$/;" e enum:wps_status -WPS_STATUS_SCANNING src/esp_supplicant/esp_wifi_driver.h /^ WPS_STATUS_SCANNING,$/;" e enum:wps_status -WPS_STATUS_SUCCESS src/esp_supplicant/esp_wifi_driver.h /^ WPS_STATUS_SUCCESS,$/;" e enum:wps_status -WPS_STATUS_t src/esp_supplicant/esp_wifi_driver.h /^} WPS_STATUS_t;$/;" t typeref:enum:wps_status -WPS_STRDUP src/wps/wps_registrar.c 281;" d file: -WPS_STRDUP src/wps/wps_registrar.c 290;" d file: -WPS_STRICT_WPS2 src/wps/wps_validate.c 16;" d file: -WPS_TASK_STACK_SIZE src/esp_supplicant/esp_wifi_driver.h 28;" d -WPS_TYPE_ALL_MAX include/esp_supplicant/esp_wps.h /^ WPS_TYPE_ALL_MAX,$/;" e enum:wps_type -WPS_TYPE_DISABLE include/esp_supplicant/esp_wps.h /^ WPS_TYPE_DISABLE = 0,$/;" e enum:wps_type -WPS_TYPE_DISPLAY include/esp_supplicant/esp_wps.h /^ WPS_TYPE_DISPLAY,$/;" e enum:wps_type -WPS_TYPE_E_MAX include/esp_supplicant/esp_wps.h /^ WPS_TYPE_E_MAX,$/;" e enum:wps_type -WPS_TYPE_PBC include/esp_supplicant/esp_wps.h /^ WPS_TYPE_PBC,$/;" e enum:wps_type -WPS_TYPE_PIN include/esp_supplicant/esp_wps.h /^ WPS_TYPE_PIN,$/;" e enum:wps_type -WPS_TYPE_R_DISPLAY include/esp_supplicant/esp_wps.h /^ WPS_TYPE_R_DISPLAY,$/;" e enum:wps_type -WPS_TYPE_R_MAX include/esp_supplicant/esp_wps.h /^ WPS_TYPE_R_MAX,$/;" e enum:wps_type -WPS_TYPE_R_PBC include/esp_supplicant/esp_wps.h /^ WPS_TYPE_R_PBC,$/;" e enum:wps_type -WPS_TYPE_R_PIN include/esp_supplicant/esp_wps.h /^ WPS_TYPE_R_PIN,$/;" e enum:wps_type -WPS_UUID_LEN src/wps/wps_defs.h 33;" d -WPS_VENDOR_ID_WFA src/wps/wps_defs.h 142;" d -WPS_VERSION src/wps/wps_defs.h 16;" d -WPS_VERSION src/wps/wps_defs.h 21;" d -WPS_VERSION src/wps/wps_defs.h 23;" d -WPS_WIFI_AUTH_OPEN src/wps/wps_defs.h 189;" d -WPS_WORKAROUNDS src/wps/wps_attr_parse.c 15;" d file: -WPS_WORKAROUNDS src/wps/wps_registrar.c 25;" d file: -WPS_WSC_ACK src/wps/wps_defs.h /^ WPS_WSC_ACK = 0x0d,$/;" e enum:wps_msg_type -WPS_WSC_DONE src/wps/wps_defs.h /^ WPS_WSC_DONE = 0x0f$/;" e enum:wps_msg_type -WPS_WSC_NACK src/wps/wps_defs.h /^ WPS_WSC_NACK = 0x0e,$/;" e enum:wps_msg_type -WSC_ACK src/wps/wps.h /^ WSC_ACK = 0x02,$/;" e enum:wsc_op_code -WSC_Done src/wps/wps.h /^ WSC_Done = 0x05,$/;" e enum:wsc_op_code -WSC_FRAG_ACK src/wps/wps.h /^ WSC_FRAG_ACK = 0x06$/;" e enum:wsc_op_code -WSC_MSG src/wps/wps.h /^ WSC_MSG = 0x04,$/;" e enum:wsc_op_code -WSC_NACK src/wps/wps.h /^ WSC_NACK = 0x03,$/;" e enum:wsc_op_code -WSC_Start src/wps/wps.h /^ WSC_Start = 0x01,$/;" e enum:wsc_op_code -WSC_UPnP src/wps/wps.h /^ WSC_UPnP = 0 \/* No OP Code in UPnP transport *\/,$/;" e enum:wsc_op_code -WePKEY_128_BYTES include/crypto/wepkey.h 5;" d -X509V3_H src/tls/x509v3.h 10;" d -X509_CERT_V1 src/tls/x509v3.h /^ enum { X509_CERT_V1 = 0, X509_CERT_V2 = 1, X509_CERT_V3 = 2 } version;$/;" e enum:x509_certificate::__anon41 -X509_CERT_V2 src/tls/x509v3.h /^ enum { X509_CERT_V1 = 0, X509_CERT_V2 = 1, X509_CERT_V3 = 2 } version;$/;" e enum:x509_certificate::__anon41 -X509_CERT_V3 src/tls/x509v3.h /^ enum { X509_CERT_V1 = 0, X509_CERT_V2 = 1, X509_CERT_V3 = 2 } version;$/;" e enum:x509_certificate::__anon41 -X509_EXT_BASIC_CONSTRAINTS src/tls/x509v3.h 66;" d -X509_EXT_ISSUER_ALT_NAME src/tls/x509v3.h 70;" d -X509_EXT_KEY_USAGE src/tls/x509v3.h 68;" d -X509_EXT_PATH_LEN_CONSTRAINT src/tls/x509v3.h 67;" d -X509_EXT_SUBJECT_ALT_NAME src/tls/x509v3.h 69;" d -X509_KEY_USAGE_CRL_SIGN src/tls/x509v3.h 84;" d -X509_KEY_USAGE_DATA_ENCIPHERMENT src/tls/x509v3.h 81;" d -X509_KEY_USAGE_DECIPHER_ONLY src/tls/x509v3.h 86;" d -X509_KEY_USAGE_DIGITAL_SIGNATURE src/tls/x509v3.h 78;" d -X509_KEY_USAGE_ENCIPHER_ONLY src/tls/x509v3.h 85;" d -X509_KEY_USAGE_KEY_AGREEMENT src/tls/x509v3.h 82;" d -X509_KEY_USAGE_KEY_CERT_SIGN src/tls/x509v3.h 83;" d -X509_KEY_USAGE_KEY_ENCIPHERMENT src/tls/x509v3.h 80;" d -X509_KEY_USAGE_NON_REPUDIATION src/tls/x509v3.h 79;" d -X509_MAX_NAME_ATTRIBUTES src/tls/x509v3.h 32;" d -X509_NAME_ATTR_C src/tls/x509v3.h /^ X509_NAME_ATTR_C,$/;" e enum:x509_name_attr::x509_name_attr_type -X509_NAME_ATTR_CN src/tls/x509v3.h /^ X509_NAME_ATTR_CN,$/;" e enum:x509_name_attr::x509_name_attr_type -X509_NAME_ATTR_DC src/tls/x509v3.h /^ X509_NAME_ATTR_DC,$/;" e enum:x509_name_attr::x509_name_attr_type -X509_NAME_ATTR_L src/tls/x509v3.h /^ X509_NAME_ATTR_L,$/;" e enum:x509_name_attr::x509_name_attr_type -X509_NAME_ATTR_NOT_USED src/tls/x509v3.h /^ X509_NAME_ATTR_NOT_USED,$/;" e enum:x509_name_attr::x509_name_attr_type -X509_NAME_ATTR_O src/tls/x509v3.h /^ X509_NAME_ATTR_O,$/;" e enum:x509_name_attr::x509_name_attr_type -X509_NAME_ATTR_OU src/tls/x509v3.h /^ X509_NAME_ATTR_OU$/;" e enum:x509_name_attr::x509_name_attr_type -X509_NAME_ATTR_ST src/tls/x509v3.h /^ X509_NAME_ATTR_ST,$/;" e enum:x509_name_attr::x509_name_attr_type -X509_VALIDATE_BAD_CERTIFICATE src/tls/x509v3.h /^ X509_VALIDATE_BAD_CERTIFICATE,$/;" e enum:__anon42 -X509_VALIDATE_CERTIFICATE_EXPIRED src/tls/x509v3.h /^ X509_VALIDATE_CERTIFICATE_EXPIRED,$/;" e enum:__anon42 -X509_VALIDATE_CERTIFICATE_REVOKED src/tls/x509v3.h /^ X509_VALIDATE_CERTIFICATE_REVOKED,$/;" e enum:__anon42 -X509_VALIDATE_CERTIFICATE_UNKNOWN src/tls/x509v3.h /^ X509_VALIDATE_CERTIFICATE_UNKNOWN,$/;" e enum:__anon42 -X509_VALIDATE_OK src/tls/x509v3.h /^ X509_VALIDATE_OK,$/;" e enum:__anon42 -X509_VALIDATE_UNKNOWN_CA src/tls/x509v3.h /^ X509_VALIDATE_UNKNOWN_CA$/;" e enum:__anon42 -X509_VALIDATE_UNSUPPORTED_CERTIFICATE src/tls/x509v3.h /^ X509_VALIDATE_UNSUPPORTED_CERTIFICATE,$/;" e enum:__anon42 -XFREE src/crypto/libtommath.h 81;" d -XFREE src/tls/libtommath.h 83;" d -XMALLOC src/crypto/libtommath.h 80;" d -XMALLOC src/tls/libtommath.h 82;" d -XREALLOC src/crypto/libtommath.h 82;" d -XREALLOC src/tls/libtommath.h 84;" d -_ENDIAN_H_ port/include/endian.h 30;" d -_ESP_WIFI_DRIVER_H_ src/esp_supplicant/esp_wifi_driver.h 16;" d -_UINT16_T_DECLARED port/include/endian.h 57;" d -_UINT16_T_DECLARED port/include/endian.h 60;" d -_UINT32_T_DECLARED port/include/endian.h 63;" d -_UINT32_T_DECLARED port/include/endian.h 66;" d -_UINT64_T_DECLARED port/include/endian.h 69;" d -_UINT64_T_DECLARED port/include/endian.h 72;" d -_UINT8_T_DECLARED port/include/endian.h 51;" d -_UINT8_T_DECLARED port/include/endian.h 54;" d -__BIG_ENDIAN include/utils/common.h 40;" d -__BIG_ENDIAN include/utils/common.h 82;" d -__BYTE_ORDER include/utils/common.h 38;" d -__BYTE_ORDER include/utils/common.h 84;" d -__ESP_WPA_PSK_H__ include/esp_supplicant/esp_wpa_psk.h 16;" d -__ESP_WPS_H__ include/esp_supplicant/esp_wps.h 16;" d -__LITTLE_ENDIAN include/utils/common.h 39;" d -__LITTLE_ENDIAN include/utils/common.h 81;" d -__bitwise include/utils/common.h 273;" d -__bitwise include/utils/common.h 276;" d -__bswap_16 port/include/byteswap.h /^__bswap_16 (unsigned short int __bsx)$/;" f -__bswap_16 port/include/byteswap.h 13;" d -__bswap_32 port/include/byteswap.h /^__bswap_32 (unsigned int __bsx)$/;" f -__bswap_32 port/include/byteswap.h 29;" d -__bswap_64 port/include/byteswap.h 57;" d -__bswap_constant_64 port/include/byteswap.h 47;" d -__force include/utils/common.h 272;" d -__force include/utils/common.h 275;" d -__func__ include/utils/common.h 234;" d -__must_check include/utils/common.h 288;" d -__must_check include/utils/common.h 290;" d -__packed src/eap_peer/eap_mschapv2.c /^} __packed;$/;" v typeref:struct:eap_mschapv2_hdr -__packed src/eap_peer/eap_mschapv2.c /^} __packed;$/;" v typeref:struct:ms_change_password -__packed src/eap_peer/eap_mschapv2.c /^} __packed;$/;" v typeref:struct:ms_response -__wpa_send_eapol src/ap/wpa_auth.c /^void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,$/;" f -_wpa_snprintf_hex src/utils/wpa_debug.c /^static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len, int uppercase)$/;" f file: -a_mpdu_params src/common/ieee802_11_defs.h /^ u8 a_mpdu_params;$/;" m struct:ieee80211_ht_capabilities -ac src/common/ieee802_11_defs.h /^ struct wmm_ac_parameter ac[4]; \/* AC_BE, AC_BK, AC_VI, AC_VO *\/$/;" m struct:wmm_parameter_element typeref:struct:wmm_parameter_element::wmm_ac_parameter -aci_aifsn src/common/ieee802_11_defs.h /^ u8 aci_aifsn; \/* AIFSN, ACM, ACI *\/$/;" m struct:wmm_ac_parameter -action src/common/ieee802_11_defs.h /^ u8 action; \/* *\/$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon83 -action src/common/ieee802_11_defs.h /^ u8 action;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon80 -action src/common/ieee802_11_defs.h /^ u8 action;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon81 -action src/common/ieee802_11_defs.h /^ u8 action;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon82 -action src/common/ieee802_11_defs.h /^ } STRUCT_PACKED action;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon76 -action src/eap_peer/eap_tlv_common.h /^ be16 action;$/;" m struct:eap_tlv_request_action_tlv -action_code src/common/ieee802_11_defs.h /^ u8 action_code;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon78 -action_code src/common/ieee802_11_defs.h /^ u8 action_code;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon79 -action_length src/ap/wpa_auth.h /^ le16 action_length; \/* little endian length of action_frame *\/$/;" m struct:ft_rrb_frame -add_sta src/ap/wpa_auth.h /^ struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);$/;" m struct:wpa_auth_callbacks typeref:struct:wpa_auth_callbacks::add_sta -add_tspec src/ap/wpa_auth.h /^ int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie,$/;" m struct:wpa_auth_callbacks -addr src/ap/ap_config.h /^ macaddr addr;$/;" m struct:mac_acl_entry -addr src/ap/ap_config.h /^ u8 addr[ETH_ALEN];$/;" m struct:hostapd_wpa_psk -addr src/ap/sta_info.h /^ u8 addr[6];$/;" m struct:sta_info -addr src/ap/wpa_auth.h /^ u8 addr[ETH_ALEN];$/;" m struct:ft_remote_r0kh -addr src/ap/wpa_auth.h /^ u8 addr[ETH_ALEN];$/;" m struct:ft_remote_r1kh -addr src/ap/wpa_auth_i.h /^ u8 addr[ETH_ALEN];$/;" m struct:wpa_authenticator -addr src/ap/wpa_auth_i.h /^ u8 addr[ETH_ALEN];$/;" m struct:wpa_state_machine -addr src/rsn_supp/wpa.h /^ u8 addr[ETH_ALEN];$/;" m struct:install_key -addr src/wps/wps.h /^ u8 addr[ETH_ALEN];$/;" m struct:upnp_pending_message -addr src/wps/wps_registrar.c /^ u8 addr[ETH_ALEN];$/;" m struct:wps_pbc_session file: -addr1 src/common/ieee802_11_defs.h /^ u8 addr1[6];$/;" m struct:ieee80211_hdr -addr2 src/common/ieee802_11_defs.h /^ u8 addr2[6];$/;" m struct:ieee80211_hdr -addr3 src/common/ieee802_11_defs.h /^ u8 addr3[6];$/;" m struct:ieee80211_hdr -aes src/crypto/crypto_internal-cipher.c /^ } aes;$/;" m union:crypto_cipher::__anon10 typeref:struct:crypto_cipher::__anon10::__anon12 file: -aes src/fast_crypto/fast_crypto_internal-cipher.c /^ } aes;$/;" m union:fast_crypto_cipher::__anon56 typeref:struct:fast_crypto_cipher::__anon56::__anon58 file: -aes_128_cbc_decrypt src/crypto/aes-cbc.c /^aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)$/;" f -aes_128_cbc_encrypt src/crypto/aes-cbc.c /^aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)$/;" f -aes_decrypt src/crypto/aes-internal-dec.c /^void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)$/;" f -aes_decrypt_deinit src/crypto/aes-internal-dec.c /^void aes_decrypt_deinit(void *ctx)$/;" f -aes_decrypt_init src/crypto/aes-internal-dec.c /^void * aes_decrypt_init(const u8 *key, size_t len)$/;" f -aes_encrypt src/crypto/aes-internal-enc.c /^void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)$/;" f -aes_encrypt_deinit src/crypto/aes-internal-enc.c /^void aes_encrypt_deinit(void *ctx)$/;" f -aes_encrypt_init src/crypto/aes-internal-enc.c /^void * aes_encrypt_init(const u8 *key, size_t len)$/;" f -aes_unwrap src/crypto/aes-unwrap.c /^aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)$/;" f -aes_wrap src/crypto/aes-wrap.c /^int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)$/;" f -aid src/ap/sta_info.h /^ u16 aid; \/* STA's unique AID (1 .. 2007) or 0 if not yet assigned *\/$/;" m struct:sta_info -aid src/common/ieee802_11_defs.h /^ le16 aid;$/;" m struct:ieee80211_mgmt::__anon66::__anon70 -alert src/tls/tls.h /^ } alert;$/;" m union:tls_event_data typeref:struct:tls_event_data::__anon36 -alert_description src/tls/tlsv1_client_i.h /^ u8 alert_description;$/;" m struct:tlsv1_client -alert_description src/tls/tlsv1_server_i.h /^ u8 alert_description;$/;" m struct:tlsv1_server -alert_level src/tls/tlsv1_client_i.h /^ u8 alert_level;$/;" m struct:tlsv1_client -alert_level src/tls/tlsv1_server_i.h /^ u8 alert_level;$/;" m struct:tlsv1_server -alg src/common/wpa_common.h /^ enum wpa_alg alg;$/;" m struct:wpa_gtk_data typeref:enum:wpa_gtk_data::wpa_alg -alg src/crypto/crypto_internal-cipher.c /^ enum crypto_cipher_alg alg;$/;" m struct:crypto_cipher typeref:enum:crypto_cipher::crypto_cipher_alg file: -alg src/crypto/crypto_internal.c /^ enum crypto_hash_alg alg;$/;" m struct:crypto_hash typeref:enum:crypto_hash::crypto_hash_alg file: -alg src/fast_crypto/fast_crypto_internal-cipher.c /^ enum crypto_cipher_alg alg;$/;" m struct:fast_crypto_cipher typeref:enum:fast_crypto_cipher::crypto_cipher_alg file: -alg src/fast_crypto/fast_crypto_internal.c /^ enum crypto_hash_alg alg;$/;" m struct:fast_crypto_hash typeref:enum:fast_crypto_hash::crypto_hash_alg file: -alg src/rsn_supp/wpa.h /^ enum wpa_alg alg;$/;" m struct:install_key typeref:enum:install_key::wpa_alg -alg src/tls/pkcs5.c /^ } alg;$/;" m struct:pkcs5_params typeref:enum:pkcs5_params::pkcs5_alg file: -alg src/tls/tlsv1_common.h /^ enum crypto_cipher_alg alg;$/;" m struct:tls_cipher_data typeref:enum:tls_cipher_data::crypto_cipher_alg -aliasing_hide_typecast include/utils/common.h 336;" d -alloc src/crypto/libtommath.h /^ int used, alloc, sign;$/;" m struct:__anon8 -alloc src/tls/libtommath.h /^ int used, alloc, sign;$/;" m struct:__anon40 -allowNotifications src/eap_peer/eap_i.h /^ Boolean allowNotifications;$/;" m struct:eap_method_ret -alt_email src/tls/x509v3.h /^ char *alt_email; \/* rfc822Name *\/$/;" m struct:x509_name -altsubject_match src/tls/tls.h /^ const char *altsubject_match;$/;" m struct:tls_connection_params -anonce src/common/wpa_common.h /^ u8 anonce[WPA_NONCE_LEN];$/;" m struct:rsn_ftie -anonce src/rsn_supp/wpa.h /^ u8 anonce[WPA_NONCE_LEN]; \/* ANonce from the last 1\/4 msg *\/$/;" m struct:wpa_sm -anonymous_identity src/eap_peer/eap_config.h /^ u8 *anonymous_identity;$/;" m struct:eap_peer_config -anonymous_identity_len src/eap_peer/eap_config.h /^ size_t anonymous_identity_len;$/;" m struct:eap_peer_config -ap src/wps/wps.h /^ int ap;$/;" m struct:wps_context -ap src/wps/wps.h /^ } ap;$/;" m union:wps_event_data typeref:struct:wps_event_data::wps_event_er_ap -ap_address src/ap/wpa_auth.h /^ u8 ap_address[ETH_ALEN];$/;" m struct:ft_r0kh_r1kh_pull_frame -ap_address src/ap/wpa_auth.h /^ u8 ap_address[ETH_ALEN];$/;" m struct:ft_r0kh_r1kh_push_frame -ap_address src/ap/wpa_auth.h /^ u8 ap_address[ETH_ALEN];$/;" m struct:ft_r0kh_r1kh_resp_frame -ap_address src/ap/wpa_auth.h /^ u8 ap_address[ETH_ALEN];$/;" m struct:ft_rrb_frame -ap_channel src/wps/wps.h /^ u16 ap_channel;$/;" m struct:wps_credential -ap_channel src/wps/wps_attr_parse.h /^ const u8 *ap_channel; \/* 2 octets *\/$/;" m struct:wps_parse_attr -ap_max_inactivity src/ap/ap_config.h /^ int ap_max_inactivity;$/;" m struct:hostapd_bss_config -ap_mlme src/ap/wpa_auth.h /^ int ap_mlme;$/;" m struct:wpa_auth_config -ap_nfc_dev_pw src/wps/wps.h /^ struct wpabuf *ap_nfc_dev_pw;$/;" m struct:wps_context typeref:struct:wps_context::wpabuf -ap_nfc_dev_pw_id src/wps/wps.h /^ u16 ap_nfc_dev_pw_id;$/;" m struct:wps_context -ap_nfc_dh_privkey src/wps/wps.h /^ struct wpabuf *ap_nfc_dh_privkey;$/;" m struct:wps_context typeref:struct:wps_context::wpabuf -ap_nfc_dh_pubkey src/wps/wps.h /^ struct wpabuf *ap_nfc_dh_pubkey;$/;" m struct:wps_context typeref:struct:wps_context::wpabuf -ap_notify_completed_rsne src/rsn_supp/wpa.h /^ bool ap_notify_completed_rsne;$/;" m struct:wpa_sm -ap_pin src/ap/ap_config.h /^ char *ap_pin;$/;" m struct:hostapd_bss_config -ap_pin_failures src/ap/hostapd.h /^ unsigned int ap_pin_failures;$/;" m struct:hostapd_data -ap_pin_failures_consecutive src/ap/hostapd.h /^ unsigned int ap_pin_failures_consecutive;$/;" m struct:hostapd_data -ap_pin_lockout_time src/ap/hostapd.h /^ unsigned int ap_pin_lockout_time;$/;" m struct:hostapd_data -ap_rsn_ie src/rsn_supp/wpa.h /^ u8 *ap_wpa_ie, *ap_rsn_ie;$/;" m struct:wpa_sm -ap_rsn_ie_len src/rsn_supp/wpa.h /^ size_t ap_wpa_ie_len, ap_rsn_ie_len;$/;" m struct:wpa_sm -ap_settings src/ap/ap_config.h /^ u8 *ap_settings;$/;" m struct:hostapd_bss_config -ap_settings src/wps/wps.h /^ u8 *ap_settings;$/;" m struct:wps_context -ap_settings src/wps/wps.h /^ } ap_settings;$/;" m union:wps_event_data typeref:struct:wps_event_data::wps_event_er_ap_settings -ap_settings_cb src/wps/wps_i.h /^ void (*ap_settings_cb)(void *ctx, const struct wps_credential *cred);$/;" m struct:wps_data -ap_settings_cb_ctx src/wps/wps_i.h /^ void *ap_settings_cb_ctx;$/;" m struct:wps_data -ap_settings_len src/ap/ap_config.h /^ size_t ap_settings_len;$/;" m struct:hostapd_bss_config -ap_settings_len src/wps/wps.h /^ size_t ap_settings_len;$/;" m struct:wps_context -ap_setup_locked src/ap/ap_config.h /^ int ap_setup_locked;$/;" m struct:hostapd_bss_config -ap_setup_locked src/wps/wps.h /^ int ap_setup_locked;$/;" m struct:wps_context -ap_setup_locked src/wps/wps_attr_parse.h /^ const u8 *ap_setup_locked; \/* 1 octet *\/$/;" m struct:wps_parse_attr -ap_sta_is_authorized src/ap/sta_info.h /^static inline int ap_sta_is_authorized(struct sta_info *sta)$/;" f -ap_table_expiration_time src/ap/ap_config.h /^ int ap_table_expiration_time;$/;" m struct:hostapd_config -ap_table_max_size src/ap/ap_config.h /^ int ap_table_max_size;$/;" m struct:hostapd_config -ap_wpa_ie src/rsn_supp/wpa.h /^ u8 *ap_wpa_ie, *ap_rsn_ie;$/;" m struct:wpa_sm -ap_wpa_ie_len src/rsn_supp/wpa.h /^ size_t ap_wpa_ie_len, ap_rsn_ie_len;$/;" m struct:wpa_sm -arg src/esp_supplicant/esp_wifi_driver.h /^ void *arg;$/;" m struct:__anon32 -arg src/esp_supplicant/esp_wps.c /^ void *arg;$/;" m struct:__anon33 file: -arg_size src/esp_supplicant/esp_wifi_driver.h /^ uint32_t arg_size;$/;" m struct:__anon32 -asel_capabilities src/common/ieee802_11_defs.h /^ u8 asel_capabilities;$/;" m struct:ieee80211_ht_capabilities -asn1_bit_string_to_long src/tls/asn1.c /^unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len)$/;" f -asn1_get_next src/tls/asn1.c /^int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)$/;" f -asn1_get_oid src/tls/asn1.c /^int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,$/;" f -asn1_hdr src/tls/asn1.h /^struct asn1_hdr {$/;" s -asn1_oid src/tls/asn1.h /^struct asn1_oid {$/;" s -asn1_oid_to_str src/tls/asn1.c /^void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len)$/;" f -asn1_parse_oid src/tls/asn1.c /^int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid)$/;" f -assoc_ie_buf src/rsn_supp/wpa.c /^u8 assoc_ie_buf[ASSOC_IE_LEN+2]; $/;" v -assoc_req src/common/ieee802_11_defs.h /^ } STRUCT_PACKED assoc_req;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon69 -assoc_resp src/common/ieee802_11_defs.h /^ } STRUCT_PACKED assoc_resp, reassoc_resp;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon70 -assoc_resp_ftie src/ap/wpa_auth_i.h /^ u8 *assoc_resp_ftie;$/;" m struct:wpa_state_machine -assoc_sa_query_max_timeout src/ap/ap_config.h /^ unsigned int assoc_sa_query_max_timeout;$/;" m struct:hostapd_bss_config -assoc_sa_query_retry_timeout src/ap/ap_config.h /^ int assoc_sa_query_retry_timeout;$/;" m struct:hostapd_bss_config -assoc_state src/wps/wps_attr_parse.h /^ const u8 *assoc_state; \/* 2 octets *\/$/;" m struct:wps_parse_attr -assoc_wpa_ie src/rsn_supp/wpa.h /^ u8 *assoc_wpa_ie; \/* Own WPA\/RSN IE from (Re)AssocReq *\/$/;" m struct:wpa_sm -assoc_wpa_ie_len src/rsn_supp/wpa.h /^ size_t assoc_wpa_ie_len;$/;" m struct:wpa_sm -assoc_wps_ie src/wps/wps.h /^ const struct wpabuf *assoc_wps_ie;$/;" m struct:wps_config typeref:struct:wps_config::wpabuf -attr src/tls/x509v3.h /^ struct x509_name_attr attr[X509_MAX_NAME_ATTRIBUTES];$/;" m struct:x509_name typeref:struct:x509_name::x509_name_attr -auth src/common/ieee802_11_defs.h /^ } STRUCT_PACKED auth;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon67 -auth src/common/wpa_common.h /^ } auth;$/;" m union:wpa_ptk::__anon62 typeref:struct:wpa_ptk::__anon62::__anon63 -auth_alg src/ap/sta_info.h /^ u16 auth_alg;$/;" m struct:sta_info -auth_alg src/common/ieee802_11_defs.h /^ le16 auth_alg;$/;" m struct:ieee80211_mgmt::__anon66::__anon67 -auth_algs src/ap/ap_config.h /^ int auth_algs; \/* bitfield of allowed IEEE 802.11 authentication$/;" m struct:hostapd_bss_config -auth_challenge src/eap_peer/eap_mschapv2.c /^ u8 *auth_challenge;$/;" m struct:eap_mschapv2_data file: -auth_response src/eap_peer/eap_mschapv2.c /^ u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN];$/;" m struct:eap_mschapv2_data file: -auth_response src/eap_peer/eap_ttls.c /^ u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN];$/;" m struct:eap_ttls_data file: -auth_response_valid src/eap_peer/eap_mschapv2.c /^ int auth_response_valid;$/;" m struct:eap_mschapv2_data file: -auth_response_valid src/eap_peer/eap_ttls.c /^ int auth_response_valid;$/;" m struct:eap_ttls_data file: -auth_transaction src/common/ieee802_11_defs.h /^ le16 auth_transaction;$/;" m struct:ieee80211_mgmt::__anon66::__anon67 -auth_type src/wps/wps.h /^ u16 auth_type;$/;" m struct:wps_credential -auth_type src/wps/wps_attr_parse.h /^ const u8 *auth_type; \/* 2 octets *\/$/;" m struct:wps_parse_attr -auth_type src/wps/wps_i.h /^ u16 auth_type;$/;" m struct:wps_data -auth_type_flags src/wps/wps_attr_parse.h /^ const u8 *auth_type_flags; \/* 2 octets *\/$/;" m struct:wps_parse_attr -auth_types src/wps/wps.h /^ u16 auth_types;$/;" m struct:wps_context -authenticator src/wps/wps_attr_parse.h /^ const u8 *authenticator; \/* WPS_AUTHENTICATOR_LEN (8) octets *\/$/;" m struct:wps_parse_attr -authkey src/wps/wps_i.h /^ u8 authkey[WPS_AUTHKEY_LEN];$/;" m struct:wps_data -authorized_macs src/wps/wps_attr_parse.h /^ const u8 *authorized_macs; \/* <= 30 octets *\/$/;" m struct:wps_parse_attr -authorized_macs src/wps/wps_registrar.c /^ u8 authorized_macs[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];$/;" m struct:wps_registrar file: -authorized_macs_len src/wps/wps_attr_parse.h /^ size_t authorized_macs_len;$/;" m struct:wps_parse_attr -authorized_macs_union src/wps/wps_registrar.c /^ u8 authorized_macs_union[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];$/;" m struct:wps_registrar file: -avp_code src/eap_peer/eap_ttls.h /^ be32 avp_code;$/;" m struct:ttls_avp -avp_code src/eap_peer/eap_ttls.h /^ be32 avp_code;$/;" m struct:ttls_avp_vendor -avp_length src/eap_peer/eap_ttls.h /^ be32 avp_length; \/* 8-bit flags, 24-bit length;$/;" m struct:ttls_avp -avp_length src/eap_peer/eap_ttls.h /^ be32 avp_length; \/* 8-bit flags, 24-bit length;$/;" m struct:ttls_avp_vendor -backend src/utils/ext_password.c /^ const struct ext_password_backend *backend;$/;" m struct:ext_password_data typeref:struct:ext_password_data::ext_password_backend file: -backends src/utils/ext_password.c /^static const struct ext_password_backend *backends[] = {$/;" v typeref:struct:ext_password_backend file: -base64_decode src/utils/base64.c /^unsigned char * base64_decode(const unsigned char *src, size_t len,$/;" f -base64_encode src/utils/base64.c /^unsigned char * base64_encode(const unsigned char *src, size_t len,$/;" f -base64_table src/utils/base64.c /^static const unsigned char base64_table[65] =$/;" v file: -basic_rates src/ap/ap_config.h /^ int *basic_rates;$/;" m struct:hostapd_config -basic_set src/common/ieee802_11_defs.h /^ u8 basic_set[16];$/;" m struct:ieee80211_ht_operation -be16 include/utils/common.h /^typedef u16 __bitwise be16;$/;" t -be16dec port/include/endian.h /^be16dec(const void *pp)$/;" f -be16enc port/include/endian.h /^be16enc(void *pp, uint16_t u)$/;" f -be16toh port/include/endian.h 109;" d -be16toh port/include/endian.h 94;" d -be32 include/utils/common.h /^typedef u32 __bitwise be32;$/;" t -be32dec port/include/endian.h /^be32dec(const void *pp)$/;" f -be32enc port/include/endian.h /^be32enc(void *pp, uint32_t u)$/;" f -be32toh port/include/endian.h 110;" d -be32toh port/include/endian.h 95;" d -be64 include/utils/common.h /^typedef u64 __bitwise be64;$/;" t -be64dec port/include/endian.h /^be64dec(const void *pp)$/;" f -be64enc port/include/endian.h /^be64enc(void *pp, uint64_t u)$/;" f -be64toh port/include/endian.h 111;" d -be64toh port/include/endian.h 96;" d -be_to_host16 include/utils/common.h 106;" d -be_to_host16 include/utils/common.h 65;" d -be_to_host16 include/utils/common.h 93;" d -be_to_host32 include/utils/common.h 109;" d -be_to_host32 include/utils/common.h 68;" d -be_to_host32 include/utils/common.h 97;" d -be_to_host64 include/utils/common.h 101;" d -be_to_host64 include/utils/common.h 113;" d -beacon src/common/ieee802_11_defs.h /^ } STRUCT_PACKED beacon;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon73 -beacon_int src/ap/ap_config.h /^ u16 beacon_int;$/;" m struct:hostapd_config -beacon_int src/common/ieee802_11_defs.h /^ le16 beacon_int;$/;" m struct:ieee80211_mgmt::__anon66::__anon73 -beacon_int src/common/ieee802_11_defs.h /^ le16 beacon_int;$/;" m struct:ieee80211_mgmt::__anon66::__anon75 -bigbyte src/crypto/des-internal.c /^static const u32 bigbyte[24] =$/;" v file: -bignum_add src/crypto/bignum.c /^bignum_add(const struct bignum *a, const struct bignum *b,$/;" f -bignum_add src/tls/bignum.c /^bignum_add(const struct bignum *a, const struct bignum *b,$/;" f -bignum_cmp src/crypto/bignum.c /^bignum_cmp(const struct bignum *a, const struct bignum *b)$/;" f -bignum_cmp src/tls/bignum.c /^bignum_cmp(const struct bignum *a, const struct bignum *b)$/;" f -bignum_cmp_d src/crypto/bignum.c /^bignum_cmp_d(const struct bignum *a, unsigned long b)$/;" f -bignum_cmp_d src/tls/bignum.c /^bignum_cmp_d(const struct bignum *a, unsigned long b)$/;" f -bignum_deinit src/crypto/bignum.c /^bignum_deinit(struct bignum *n)$/;" f -bignum_deinit src/tls/bignum.c /^bignum_deinit(struct bignum *n)$/;" f -bignum_exptmod src/crypto/bignum.c /^bignum_exptmod(const struct bignum *a, const struct bignum *b,$/;" f -bignum_exptmod src/tls/bignum.c /^bignum_exptmod(const struct bignum *a, const struct bignum *b,$/;" f -bignum_get_unsigned_bin src/crypto/bignum.c /^bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len)$/;" f -bignum_get_unsigned_bin src/tls/bignum.c /^bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len)$/;" f -bignum_get_unsigned_bin_len src/crypto/bignum.c /^bignum_get_unsigned_bin_len(struct bignum *n)$/;" f -bignum_get_unsigned_bin_len src/tls/bignum.c /^bignum_get_unsigned_bin_len(struct bignum *n)$/;" f -bignum_init src/crypto/bignum.c /^bignum_init(void)$/;" f -bignum_init src/tls/bignum.c /^bignum_init(void)$/;" f -bignum_mul src/crypto/bignum.c /^bignum_mul(const struct bignum *a, const struct bignum *b,$/;" f -bignum_mul src/tls/bignum.c /^bignum_mul(const struct bignum *a, const struct bignum *b,$/;" f -bignum_mulmod src/crypto/bignum.c /^bignum_mulmod(const struct bignum *a, const struct bignum *b,$/;" f -bignum_mulmod src/tls/bignum.c /^bignum_mulmod(const struct bignum *a, const struct bignum *b,$/;" f -bignum_set_unsigned_bin src/crypto/bignum.c /^bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len)$/;" f -bignum_set_unsigned_bin src/tls/bignum.c /^bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len)$/;" f -bignum_sub src/crypto/bignum.c /^bignum_sub(const struct bignum *a, const struct bignum *b,$/;" f -bignum_sub src/tls/bignum.c /^bignum_sub(const struct bignum *a, const struct bignum *b,$/;" f -binding_nonce src/eap_peer/eap_peap.c /^ u8 binding_nonce[32];$/;" m struct:eap_peap_data file: -bits src/crypto/md5_i.h /^ u32 bits[2];$/;" m struct:MD5Context -blk src/crypto/sha1-internal.c 142;" d file: -blk0 src/crypto/sha1-internal.c 137;" d file: -blk0 src/crypto/sha1-internal.c 140;" d file: -blob src/eap_peer/eap_i.h /^ struct wpa_config_blob blob[BLOB_NUM];$/;" m struct:eap_sm typeref:struct:eap_sm::wpa_config_blob -block_size src/tls/tlsv1_common.h /^ size_t block_size; \/* also iv_size *\/$/;" m struct:tls_cipher_data -bn_reverse src/crypto/libtommath.h /^bn_reverse (unsigned char *s, int len)$/;" f -bn_reverse src/tls/libtommath.h /^bn_reverse (unsigned char *s, int len)$/;" f -broadcast_ether_addr include/utils/common.h 320;" d -broadcast_key_idx_max src/ap/ap_config.h /^ int broadcast_key_idx_min, broadcast_key_idx_max;$/;" m struct:hostapd_bss_config -broadcast_key_idx_min src/ap/ap_config.h /^ int broadcast_key_idx_min, broadcast_key_idx_max;$/;" m struct:hostapd_bss_config -bss src/ap/ap_config.h /^ struct hostapd_bss_config *bss, *last_bss;$/;" m struct:hostapd_config typeref:struct:hostapd_config::hostapd_bss_config -bssid src/ap/ap_config.h /^ macaddr bssid;$/;" m struct:hostapd_bss_config -bssid src/common/ieee802_11_defs.h /^ u8 bssid[6];$/;" m struct:ieee80211_mgmt -bssid src/esp_supplicant/esp_wifi_driver.h /^ uint8_t *bssid;$/;" m struct:wps_scan_ie -bssid src/esp_supplicant/esp_wpa_enterprise.c /^ uint8_t *bssid;$/;" m struct:wpa2_rx_param file: -bssid src/rsn_supp/wpa.h /^ u8 bssid[ETH_ALEN];$/;" m struct:wpa_sm -bssid src/wps/wps.h /^ u8 bssid[6];$/;" m struct:discard_ap_list_t -bssid src/wps/wps.h /^ u8 bssid[ETH_ALEN];$/;" m struct:wps_sm -bswap16 port/include/endian.h 78;" d -bswap32 port/include/endian.h 79;" d -bswap64 port/include/endian.h 80;" d -bswap_16 include/utils/common.h 238;" d -bswap_32 include/utils/common.h 242;" d -buf src/crypto/md5_i.h /^ u32 buf[4];$/;" m struct:MD5Context -buf src/crypto/sha256-internal.c /^ u8 buf[SHA256_BLOCK_SIZE];$/;" m struct:sha256_state file: -buf src/esp_supplicant/esp_wpa_enterprise.c /^ u8 *buf;$/;" m struct:wpa2_rx_param file: -buf src/esp_supplicant/esp_wps.c /^ u8 *buf;$/;" m struct:wps_rx_param file: -buffer src/crypto/md4-internal.c /^ u8 buffer[MD4_BLOCK_LENGTH];$/;" m struct:MD4Context file: -buffer src/crypto/sha1_i.h /^ unsigned char buffer[64];$/;" m struct:SHA1Context -byteReverse src/crypto/md5-internal.c /^static void byteReverse(unsigned char *buf, unsigned longs)$/;" f file: -byteReverse src/crypto/md5-internal.c 70;" d file: -bytebit src/crypto/des-internal.c /^static const u32 bytebit[8] =$/;" v file: -ca src/tls/x509v3.h /^ int ca; \/* cA *\/$/;" m struct:x509_certificate -ca_cert src/eap_peer/eap_config.h /^ u8 *ca_cert;$/;" m struct:eap_peer_config -ca_cert src/tls/tls.h /^ const char *ca_cert;$/;" m struct:tls_connection_params -ca_cert2 src/eap_peer/eap_config.h /^ u8 *ca_cert2;$/;" m struct:eap_peer_config -ca_cert_blob src/tls/tls.h /^ const u8 *ca_cert_blob;$/;" m struct:tls_connection_params -ca_cert_blob_len src/tls/tls.h /^ size_t ca_cert_blob_len;$/;" m struct:tls_connection_params -ca_cert_id src/tls/tls.h /^ const char *ca_cert_id;$/;" m struct:tls_connection_params -ca_path src/eap_peer/eap_config.h /^ u8 *ca_path;$/;" m struct:eap_peer_config -ca_path src/tls/tls.h /^ const char *ca_path;$/;" m struct:tls_connection_params -ca_path2 src/eap_peer/eap_config.h /^ u8 *ca_path2;$/;" m struct:eap_peer_config -capab_info src/common/ieee802_11_defs.h /^ le16 capab_info;$/;" m struct:ieee80211_mgmt::__anon66::__anon69 -capab_info src/common/ieee802_11_defs.h /^ le16 capab_info;$/;" m struct:ieee80211_mgmt::__anon66::__anon70 -capab_info src/common/ieee802_11_defs.h /^ le16 capab_info;$/;" m struct:ieee80211_mgmt::__anon66::__anon71 -capab_info src/common/ieee802_11_defs.h /^ le16 capab_info;$/;" m struct:ieee80211_mgmt::__anon66::__anon73 -capab_info src/common/ieee802_11_defs.h /^ le16 capab_info;$/;" m struct:ieee80211_mgmt::__anon66::__anon75 -capabilities src/common/wpa_common.h /^ int capabilities;$/;" m struct:wpa_ie_data -capability src/ap/sta_info.h /^ u16 capability;$/;" m struct:sta_info -capinfo src/esp_supplicant/esp_wifi_driver.h /^ uint16_t capinfo;$/;" m struct:wps_scan_ie -category src/common/ieee802_11_defs.h /^ u8 category;$/;" m struct:ieee80211_mgmt::__anon66::__anon76 -cb src/ap/hostapd.h /^ int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid,$/;" m struct:hostapd_probereq_cb -cb_ctx src/tls/tls.h /^ void *cb_ctx;$/;" m struct:tls_config -cb_ctx src/wps/wps.h /^ void *cb_ctx;$/;" m struct:wps_context -cb_ctx src/wps/wps.h /^ void *cb_ctx;$/;" m struct:wps_registrar_config -cb_ctx src/wps/wps_registrar.c /^ void *cb_ctx;$/;" m struct:wps_registrar file: -cbc src/crypto/crypto_internal-cipher.c /^ u8 cbc[32];$/;" m struct:crypto_cipher::__anon10::__anon12 file: -cbc src/crypto/crypto_internal-cipher.c /^ u8 cbc[8];$/;" m struct:crypto_cipher::__anon10::__anon13 file: -cbc src/crypto/crypto_internal-cipher.c /^ u8 cbc[8];$/;" m struct:crypto_cipher::__anon10::__anon14 file: -cbc src/fast_crypto/fast_crypto_internal-cipher.c /^ uint32_t cbc[8];$/;" m struct:fast_crypto_cipher::__anon56::__anon60 file: -cbc src/fast_crypto/fast_crypto_internal-cipher.c /^ uint8_t cbc[32];$/;" m struct:fast_crypto_cipher::__anon56::__anon58 file: -cbc src/fast_crypto/fast_crypto_internal-cipher.c /^ uint8_t cbc[8];$/;" m struct:fast_crypto_cipher::__anon56::__anon59 file: -ccmp src/esp_supplicant/esp_wifi_driver.h /^struct wifi_cipher ccmp;$/;" v typeref:struct:wifi_cipher -cert src/tls/tls.h /^ const struct wpabuf *cert;$/;" m struct:tls_event_data::__anon34 typeref:struct:tls_event_data::__anon34::wpabuf -cert src/tls/tls.h /^ const struct wpabuf *cert;$/;" m struct:tls_event_data::__anon35 typeref:struct:tls_event_data::__anon35::wpabuf -cert src/tls/tlsv1_cred.h /^ struct x509_certificate *cert;$/;" m struct:tlsv1_credentials typeref:struct:tlsv1_credentials::x509_certificate -cert_fail src/tls/tls.h /^ } cert_fail;$/;" m union:tls_event_data typeref:struct:tls_event_data::__anon34 -cert_id src/tls/tls.h /^ const char *cert_id;$/;" m struct:tls_connection_params -cert_in_cb src/tls/tls.h /^ int cert_in_cb;$/;" m struct:tls_config -cert_len src/tls/x509v3.h /^ size_t cert_len;$/;" m struct:x509_certificate -cert_start src/tls/x509v3.h /^ const u8 *cert_start;$/;" m struct:x509_certificate -certificate_requested src/tls/tlsv1_client_i.h /^ unsigned int certificate_requested:1;$/;" m struct:tlsv1_client -challenge_hash src/crypto/ms_funcs.c /^static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,$/;" f file: -challenge_response src/crypto/ms_funcs.c /^void challenge_response(const u8 *challenge, const u8 *password_hash,$/;" f -chan src/esp_supplicant/esp_wifi_driver.h /^ uint8_t chan;$/;" m struct:wps_scan_ie -chan_switch src/common/ieee802_11_defs.h /^ } STRUCT_PACKED chan_switch;$/;" m union:ieee80211_mgmt::__anon66::__anon76::__anon77 typeref:struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon79 -changed src/ap/wpa_auth_i.h /^ Boolean changed;$/;" m struct:wpa_group -changed src/ap/wpa_auth_i.h /^ unsigned int changed:1;$/;" m struct:wpa_state_machine -channel src/ap/ap_config.h /^ u8 channel;$/;" m struct:hostapd_config -channel src/ap/hostapd.h /^ u32 channel;$/;" m struct:hostapd_frame_info -channel src/wps/wps.h /^ u8 channel;$/;" m struct:wps_sm -chap_md5 src/eap_peer/chap.c /^int chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge,$/;" f -check_crl src/tls/tls_internal.c /^ int check_crl;$/;" m struct:tls_global file: -cipher src/tls/tlsv1_common.h /^ tls_cipher cipher;$/;" m struct:tls_cipher_data -cipher src/tls/tlsv1_common.h /^ tls_cipher cipher;$/;" m struct:tls_cipher_suite -cipher_alg src/tls/tlsv1_record.h /^ enum crypto_cipher_alg cipher_alg;$/;" m struct:tlsv1_record_layer typeref:enum:tlsv1_record_layer::crypto_cipher_alg -cipher_suite src/tls/tlsv1_record.h /^ u16 cipher_suite;$/;" m struct:tlsv1_record_layer -cipher_suite src/tls/tlsv1_server_i.h /^ u16 cipher_suite;$/;" m struct:tlsv1_server -cipher_suites src/tls/tlsv1_client_i.h /^ u16 cipher_suites[MAX_CIPHER_COUNT];$/;" m struct:tlsv1_client -cipher_suites src/tls/tlsv1_server_i.h /^ u16 cipher_suites[MAX_CIPHER_COUNT];$/;" m struct:tlsv1_server -client src/tls/tls_internal.c /^ struct tlsv1_client *client;$/;" m struct:tls_connection typeref:struct:tls_connection::tlsv1_client file: -client_cert src/eap_peer/eap_config.h /^ u8 *client_cert;$/;" m struct:eap_peer_config -client_cert src/tls/tls.h /^ const char *client_cert;$/;" m struct:tls_connection_params -client_cert2 src/eap_peer/eap_config.h /^ u8 *client_cert2;$/;" m struct:eap_peer_config -client_cert_blob src/tls/tls.h /^ const u8 *client_cert_blob;$/;" m struct:tls_connection_params -client_cert_blob_len src/tls/tls.h /^ size_t client_cert_blob_len;$/;" m struct:tls_connection_params -client_hello_ext src/tls/tlsv1_client_i.h /^ u8 *client_hello_ext;$/;" m struct:tlsv1_client -client_hello_ext_len src/tls/tlsv1_client_i.h /^ size_t client_hello_ext_len;$/;" m struct:tlsv1_client -client_random src/tls/tls.h /^ const u8 *client_random;$/;" m struct:tls_keys -client_random src/tls/tlsv1_client_i.h /^ u8 client_random[TLS_RANDOM_LEN];$/;" m struct:tlsv1_client -client_random src/tls/tlsv1_server_i.h /^ u8 client_random[TLS_RANDOM_LEN];$/;" m struct:tlsv1_server -client_random_len src/tls/tls.h /^ size_t client_random_len;$/;" m struct:tls_keys -client_rsa_key src/tls/tlsv1_server_i.h /^ struct crypto_public_key *client_rsa_key;$/;" m struct:tlsv1_server typeref:struct:tlsv1_server::crypto_public_key -client_version src/tls/tlsv1_server_i.h /^ u16 client_version;$/;" m struct:tlsv1_server -cm_timer src/rsn_supp/wpa.h /^ ETSTimer cm_timer;$/;" m struct:wpa_sm -cmk src/eap_peer/eap_peap.c /^ u8 cmk[20];$/;" m struct:eap_peap_data file: -code src/eap_peer/eap_defs.h /^ u8 code;$/;" m struct:eap_hdr -compound_mac src/eap_peer/eap_tlv_common.h /^ u8 compound_mac[20];$/;" m struct:eap_tlv_crypto_binding_tlv -conf src/ap/hostapd.h /^ struct hostapd_bss_config *conf;$/;" m struct:hostapd_data typeref:struct:hostapd_data::hostapd_bss_config -conf src/ap/wpa_auth_i.h /^ struct wpa_auth_config conf;$/;" m struct:wpa_authenticator typeref:struct:wpa_authenticator::wpa_auth_config -config src/eap_peer/eap_i.h /^ struct eap_peer_config config;$/;" m struct:eap_sm typeref:struct:eap_sm::eap_peer_config -config src/wps/wps.h /^ wifi_sta_config_t config;$/;" m struct:wps_sm -config_assoc_ie src/rsn_supp/wpa.h /^ void (*config_assoc_ie) (u8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len);$/;" m struct:wpa_sm -config_error src/wps/wps.h /^ u16 config_error;$/;" m struct:wps_event_data::wps_event_fail -config_error src/wps/wps.h /^ u16 config_error;$/;" m struct:wps_event_data::wps_event_m2d -config_error src/wps/wps_attr_parse.h /^ const u8 *config_error; \/* 2 octets *\/$/;" m struct:wps_parse_attr -config_error src/wps/wps_i.h /^ u16 config_error;$/;" m struct:wps_data -config_methods src/ap/ap_config.h /^ char *config_methods;$/;" m struct:hostapd_bss_config -config_methods src/wps/wps.h /^ u16 config_methods;$/;" m struct:wps_event_data::wps_event_er_enrollee -config_methods src/wps/wps.h /^ u16 config_methods;$/;" m struct:wps_event_data::wps_event_m2d -config_methods src/wps/wps.h /^ u16 config_methods;$/;" m struct:wps_context -config_methods src/wps/wps.h /^ u16 config_methods;$/;" m struct:wps_device_data -config_methods src/wps/wps_attr_parse.h /^ const u8 *config_methods; \/* 2 octets *\/$/;" m struct:wps_parse_attr -config_read_cb src/ap/hostapd.h /^ struct hostapd_config * (*config_read_cb)(const char *config_fname);$/;" m struct:hapd_interfaces typeref:struct:hapd_interfaces::config_read_cb -conn src/eap_peer/eap_tls_common.h /^ struct tls_connection *conn;$/;" m struct:eap_ssl_data typeref:struct:eap_ssl_data::tls_connection -conn_type_flags src/wps/wps_attr_parse.h /^ const u8 *conn_type_flags; \/* 1 octet *\/$/;" m struct:wps_parse_attr -constructed src/tls/asn1.h /^ u8 identifier, class, constructed;$/;" m struct:asn1_hdr typeref:class:asn1_hdr:: -control_chan src/common/ieee802_11_defs.h /^ u8 control_chan;$/;" m struct:ieee80211_ht_operation -cookey src/crypto/des-internal.c /^static void cookey(const u32 *raw1, u32 *keyout)$/;" f file: -count src/ap/hostapd.h /^ size_t count;$/;" m struct:hapd_interfaces -count src/crypto/md4-internal.c /^ u64 count;$/;" m struct:MD4Context file: -count src/crypto/sha1_i.h /^ u32 count[2];$/;" m struct:SHA1Context -counter src/ap/wpa_auth_i.h /^ u8 counter[WPA_REPLAY_COUNTER_LEN];$/;" m struct:wpa_state_machine::wpa_key_replay_counter -countermeasures src/rsn_supp/wpa.h /^ int countermeasures; \/*TKIP countermeasures state flag, 1:in countermeasures state*\/$/;" m struct:wpa_sm -country src/ap/ap_config.h /^ char country[3]; \/* first two octets: country code as described in$/;" m struct:hostapd_config -cred src/tls/tlsv1_client_i.h /^ struct tlsv1_credentials *cred;$/;" m struct:tlsv1_client typeref:struct:tlsv1_client::tlsv1_credentials -cred src/tls/tlsv1_server_i.h /^ struct tlsv1_credentials *cred;$/;" m struct:tlsv1_server typeref:struct:tlsv1_server::tlsv1_credentials -cred src/wps/wps.h /^ const struct wps_credential *cred;$/;" m struct:wps_event_data::wps_event_er_ap_settings typeref:struct:wps_event_data::wps_event_er_ap_settings::wps_credential -cred src/wps/wps_attr_parse.h /^ const u8 *cred[MAX_CRED_COUNT];$/;" m struct:wps_parse_attr -cred src/wps/wps_i.h /^ struct wps_credential cred;$/;" m struct:wps_data typeref:struct:wps_data::wps_credential -cred_attr src/wps/wps.h /^ const u8 *cred_attr;$/;" m struct:wps_credential -cred_attr_len src/wps/wps.h /^ size_t cred_attr_len;$/;" m struct:wps_credential -cred_cb src/wps/wps.h /^ int (*cred_cb)(void *ctx, const struct wps_credential *cred);$/;" m struct:wps_context -cred_len src/wps/wps_attr_parse.h /^ size_t cred_len[MAX_CRED_COUNT];$/;" m struct:wps_parse_attr -crypto_bignum test/test_crypto.c /^typedef struct crypto_bignum crypto_bignum;$/;" t typeref:struct:crypto_bignum file: -crypto_bignum_add src/crypto/crypto_mbedtls.c /^int crypto_bignum_add(const struct crypto_bignum *a,$/;" f -crypto_bignum_bits src/crypto/crypto_mbedtls.c /^int crypto_bignum_bits(const struct crypto_bignum *a)$/;" f -crypto_bignum_cmp src/crypto/crypto_mbedtls.c /^int crypto_bignum_cmp(const struct crypto_bignum *a,$/;" f -crypto_bignum_deinit src/crypto/crypto_mbedtls.c /^void crypto_bignum_deinit(struct crypto_bignum *n, int clear)$/;" f -crypto_bignum_div src/crypto/crypto_mbedtls.c /^int crypto_bignum_div(const struct crypto_bignum *a,$/;" f -crypto_bignum_exptmod src/crypto/crypto_mbedtls.c /^int crypto_bignum_exptmod(const struct crypto_bignum *a,$/;" f -crypto_bignum_init src/crypto/crypto_mbedtls.c /^struct crypto_bignum *crypto_bignum_init(void)$/;" f -crypto_bignum_init_set src/crypto/crypto_mbedtls.c /^struct crypto_bignum *crypto_bignum_init_set(const u8 *buf, size_t len)$/;" f -crypto_bignum_inverse src/crypto/crypto_mbedtls.c /^int crypto_bignum_inverse(const struct crypto_bignum *a,$/;" f -crypto_bignum_is_one src/crypto/crypto_mbedtls.c /^int crypto_bignum_is_one(const struct crypto_bignum *a)$/;" f -crypto_bignum_is_zero src/crypto/crypto_mbedtls.c /^int crypto_bignum_is_zero(const struct crypto_bignum *a)$/;" f -crypto_bignum_legendre src/crypto/crypto_mbedtls.c /^int crypto_bignum_legendre(const struct crypto_bignum *a,$/;" f -crypto_bignum_mod src/crypto/crypto_mbedtls.c /^int crypto_bignum_mod(const struct crypto_bignum *a,$/;" f -crypto_bignum_mulmod src/crypto/crypto_mbedtls.c /^int crypto_bignum_mulmod(const struct crypto_bignum *a,$/;" f -crypto_bignum_sub src/crypto/crypto_mbedtls.c /^int crypto_bignum_sub(const struct crypto_bignum *a,$/;" f -crypto_bignum_to_bin src/crypto/crypto_mbedtls.c /^int crypto_bignum_to_bin(const struct crypto_bignum *a,$/;" f -crypto_binding src/eap_peer/eap_peap.c /^ enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;$/;" m struct:eap_peap_data typeref:enum:eap_peap_data::__anon7 file: -crypto_binding_used src/eap_peer/eap_peap.c /^ int crypto_binding_used;$/;" m struct:eap_peap_data file: -crypto_cipher src/crypto/crypto_internal-cipher.c /^struct crypto_cipher {$/;" s file: -crypto_cipher_alg include/crypto/crypto.h /^enum crypto_cipher_alg {$/;" g -crypto_cipher_decrypt src/crypto/crypto_internal-cipher.c /^int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,$/;" f -crypto_cipher_deinit src/crypto/crypto_internal-cipher.c /^void crypto_cipher_deinit(struct crypto_cipher *ctx)$/;" f -crypto_cipher_encrypt src/crypto/crypto_internal-cipher.c /^int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,$/;" f -crypto_cipher_init src/crypto/crypto_internal-cipher.c /^struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,$/;" f -crypto_ec src/crypto/crypto_mbedtls.c /^struct crypto_ec {$/;" s file: -crypto_ec_deinit src/crypto/crypto_mbedtls.c /^void crypto_ec_deinit(struct crypto_ec *e)$/;" f -crypto_ec_get_order src/crypto/crypto_mbedtls.c /^const struct crypto_bignum *crypto_ec_get_order(struct crypto_ec *e)$/;" f -crypto_ec_get_prime src/crypto/crypto_mbedtls.c /^const struct crypto_bignum *crypto_ec_get_prime(struct crypto_ec *e)$/;" f -crypto_ec_init src/crypto/crypto_mbedtls.c /^struct crypto_ec *crypto_ec_init(int group)$/;" f -crypto_ec_point_add src/crypto/crypto_mbedtls.c /^int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,$/;" f -crypto_ec_point_cmp src/crypto/crypto_mbedtls.c /^int crypto_ec_point_cmp(const struct crypto_ec *e,$/;" f -crypto_ec_point_compute_y_sqr src/crypto/crypto_mbedtls.c /^crypto_ec_point_compute_y_sqr(struct crypto_ec *e,$/;" f -crypto_ec_point_deinit src/crypto/crypto_mbedtls.c /^void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)$/;" f -crypto_ec_point_from_bin src/crypto/crypto_mbedtls.c /^struct crypto_ec_point *crypto_ec_point_from_bin(struct crypto_ec *e,$/;" f -crypto_ec_point_init src/crypto/crypto_mbedtls.c /^struct crypto_ec_point *crypto_ec_point_init(struct crypto_ec *e)$/;" f -crypto_ec_point_invert src/crypto/crypto_mbedtls.c /^int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p)$/;" f -crypto_ec_point_is_at_infinity src/crypto/crypto_mbedtls.c /^int crypto_ec_point_is_at_infinity(struct crypto_ec *e,$/;" f -crypto_ec_point_is_on_curve src/crypto/crypto_mbedtls.c /^int crypto_ec_point_is_on_curve(struct crypto_ec *e,$/;" f -crypto_ec_point_mul src/crypto/crypto_mbedtls.c /^int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,$/;" f -crypto_ec_point_solve_y_coord src/crypto/crypto_mbedtls.c /^int crypto_ec_point_solve_y_coord(struct crypto_ec *e,$/;" f -crypto_ec_point_to_bin src/crypto/crypto_mbedtls.c /^int crypto_ec_point_to_bin(struct crypto_ec *e,$/;" f -crypto_ec_prime_len src/crypto/crypto_mbedtls.c /^size_t crypto_ec_prime_len(struct crypto_ec *e)$/;" f -crypto_ec_prime_len_bits src/crypto/crypto_mbedtls.c /^size_t crypto_ec_prime_len_bits(struct crypto_ec *e)$/;" f -crypto_get_random src/crypto/crypto_mbedtls.c /^int crypto_get_random(void *buf, size_t len)$/;" f -crypto_global_deinit src/crypto/crypto_internal.c /^void crypto_global_deinit(void)$/;" f -crypto_global_init src/crypto/crypto_internal.c /^int crypto_global_init(void)$/;" f -crypto_hash src/crypto/crypto_internal.c /^struct crypto_hash {$/;" s file: -crypto_hash_alg include/crypto/crypto.h /^enum crypto_hash_alg {$/;" g -crypto_hash_finish src/crypto/crypto_internal.c /^int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)$/;" f -crypto_hash_init src/crypto/crypto_internal.c /^struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,$/;" f -crypto_hash_update src/crypto/crypto_internal.c /^void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)$/;" f -crypto_mod_exp src/crypto/crypto_internal-modexp.c /^crypto_mod_exp(const u8 *base, size_t base_len,$/;" f -crypto_private_key_decrypt_pkcs1_v15 src/crypto/crypto_internal-rsa.c /^int crypto_private_key_decrypt_pkcs1_v15(struct crypto_private_key *key,$/;" f -crypto_private_key_free src/crypto/crypto_internal-rsa.c /^void crypto_private_key_free(struct crypto_private_key *key)$/;" f -crypto_private_key_import src/crypto/crypto_internal-rsa.c /^struct crypto_private_key * crypto_private_key_import(const u8 *key,$/;" f -crypto_private_key_sign_pkcs1 src/crypto/crypto_internal-rsa.c /^int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,$/;" f -crypto_public_key_decrypt_pkcs1 src/crypto/crypto_internal-rsa.c /^int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,$/;" f -crypto_public_key_encrypt_pkcs1_v15 src/crypto/crypto_internal-rsa.c /^int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,$/;" f -crypto_public_key_free src/crypto/crypto_internal-rsa.c /^void crypto_public_key_free(struct crypto_public_key *key)$/;" f -crypto_public_key_from_cert src/crypto/crypto_internal-rsa.c /^struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,$/;" f -crypto_public_key_import src/crypto/crypto_internal-rsa.c /^struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)$/;" f -crypto_rsa_exptmod src/tls/rsa.c /^int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen,$/;" f -crypto_rsa_free src/tls/rsa.c /^void crypto_rsa_free(struct crypto_rsa_key *key)$/;" f -crypto_rsa_get_modulus_len src/tls/rsa.c /^size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key)$/;" f -crypto_rsa_import_private_key src/tls/rsa.c /^crypto_rsa_import_private_key(const u8 *buf, size_t len)$/;" f -crypto_rsa_import_public_key src/tls/rsa.c /^crypto_rsa_import_public_key(const u8 *buf, size_t len)$/;" f -crypto_rsa_key src/tls/rsa.c /^struct crypto_rsa_key {$/;" s file: -crypto_rsa_parse_integer src/tls/rsa.c /^static const u8 * crypto_rsa_parse_integer(const u8 *pos, const u8 *end,$/;" f file: -ctrl_iface_deinit src/ap/hostapd.h /^ void (*ctrl_iface_deinit)(struct hostapd_data *hapd);$/;" m struct:hapd_interfaces -ctrl_iface_init src/ap/hostapd.h /^ int (*ctrl_iface_init)(struct hostapd_data *hapd);$/;" m struct:hapd_interfaces -ctx src/ap/hostapd.h /^ void *ctx;$/;" m struct:hostapd_probereq_cb -ctx src/ap/wpa_auth.h /^ void *ctx;$/;" m struct:wpa_auth_callbacks -ctx_dec src/crypto/crypto_internal-cipher.c /^ void *ctx_dec;$/;" m struct:crypto_cipher::__anon10::__anon12 file: -ctx_dec src/fast_crypto/fast_crypto_internal-cipher.c /^ mbedtls_aes_context ctx_dec;$/;" m struct:fast_crypto_cipher::__anon56::__anon58 file: -ctx_enc src/crypto/crypto_internal-cipher.c /^ void *ctx_enc;$/;" m struct:crypto_cipher::__anon10::__anon12 file: -ctx_enc src/fast_crypto/fast_crypto_internal-cipher.c /^ mbedtls_aes_context ctx_enc;$/;" m struct:fast_crypto_cipher::__anon56::__anon58 file: -curlen src/crypto/sha256-internal.c /^ u32 state[8], curlen;$/;" m struct:sha256_state file: -current_ap src/common/ieee802_11_defs.h /^ u8 current_ap[6];$/;" m struct:ieee80211_mgmt::__anon66::__anon71 -current_identifier src/eap_peer/eap_i.h /^ u8 current_identifier;$/;" m struct:eap_sm -current_identifier src/wps/wps.h /^ u8 current_identifier;$/;" m struct:wps_sm -cw src/common/ieee802_11_defs.h /^ u8 cw; \/* ECWmin, ECWmax (CW = 2^ECW - 1) *\/$/;" m struct:wmm_ac_parameter -d src/tls/rsa.c /^ struct bignum *d; \/* private exponent *\/$/;" m struct:crypto_rsa_key typeref:struct:crypto_rsa_key::bignum file: -da src/common/ieee802_11_defs.h /^ u8 da[6];$/;" m struct:ieee80211_mgmt -data src/eap_peer/eap_config.h /^ const u8 *data;$/;" m struct:wpa_config_blob -data_length src/ap/wpa_auth.h /^ le16 data_length; \/* little endian length of data (44) *\/$/;" m struct:ft_r0kh_r1kh_pull_frame -data_length src/ap/wpa_auth.h /^ le16 data_length; \/* little endian length of data (76) *\/$/;" m struct:ft_r0kh_r1kh_resp_frame -data_length src/ap/wpa_auth.h /^ le16 data_length; \/* little endian length of data (88) *\/$/;" m struct:ft_r0kh_r1kh_push_frame -datarate src/ap/hostapd.h /^ u32 datarate;$/;" m struct:hostapd_frame_info -deauth src/common/ieee802_11_defs.h /^ } STRUCT_PACKED deauth;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon68 -decision src/eap_peer/eap_i.h /^ EapDecision decision;$/;" m struct:eap_method_ret -default_len src/ap/ap_config.h /^ size_t default_len; \/* key length used for dynamic key generation *\/$/;" m struct:hostapd_wep_keys -deinit src/eap_peer/eap_i.h /^ void (*deinit)(struct eap_sm *sm, void *priv);$/;" m struct:eap_method -deinit src/utils/ext_password_i.h /^ void (*deinit)(void *ctx);$/;" m struct:ext_password_backend -deinit_for_reauth src/eap_peer/eap_i.h /^ void (*deinit_for_reauth)(struct eap_sm *sm, void *priv);$/;" m struct:eap_method -delay_bound src/common/ieee802_11_defs.h /^ le32 delay_bound;$/;" m struct:wmm_tspec_element -depth src/tls/tls.h /^ int depth;$/;" m struct:tls_event_data::__anon34 -depth src/tls/tls.h /^ int depth;$/;" m struct:tls_event_data::__anon35 -des src/crypto/crypto_internal-cipher.c /^ } des;$/;" m union:crypto_cipher::__anon10 typeref:struct:crypto_cipher::__anon10::__anon14 file: -des src/fast_crypto/fast_crypto_internal-cipher.c /^ } des;$/;" m union:fast_crypto_cipher::__anon56 typeref:struct:fast_crypto_cipher::__anon56::__anon60 file: -des3 src/crypto/crypto_internal-cipher.c /^ } des3;$/;" m union:crypto_cipher::__anon10 typeref:struct:crypto_cipher::__anon10::__anon13 file: -des3 src/fast_crypto/fast_crypto_internal-cipher.c /^ } des3;$/;" m union:fast_crypto_cipher::__anon56 typeref:struct:fast_crypto_cipher::__anon56::__anon59 file: -des3_key_s src/crypto/des_i.h /^struct des3_key_s {$/;" s -des_encrypt src/crypto/des-internal.c /^void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)$/;" f -descr_count src/common/wpa_common.h /^ u8 descr_count;$/;" m struct:rsn_rdie -description src/tls/tls.h /^ const char *description;$/;" m struct:tls_event_data::__anon36 -desfunc src/crypto/des-internal.c /^static void desfunc(u32 *block, const u32 *keys)$/;" f file: -deskey src/crypto/des-internal.c /^static void deskey(const u8 *key, int decrypt, u32 *keyout)$/;" f file: -dev src/wps/wps.h /^ struct wps_device_data dev;$/;" m struct:wps_context typeref:struct:wps_context::wps_device_data -dev src/wps/wps.h /^ struct wps_device_data *dev;$/;" m struct:wps_sm typeref:struct:wps_sm::wps_device_data -dev src/wps/wps_registrar.c /^ struct wps_device_data dev;$/;" m struct:wps_registrar_device typeref:struct:wps_registrar_device::wps_device_data file: -dev_name src/wps/wps.h /^ const char *dev_name;$/;" m struct:wps_event_data::wps_event_er_enrollee -dev_name src/wps/wps.h /^ const u8 *dev_name;$/;" m struct:wps_event_data::wps_event_m2d -dev_name src/wps/wps_attr_parse.h /^ const u8 *dev_name;$/;" m struct:wps_parse_attr -dev_name_len src/wps/wps.h /^ size_t dev_name_len;$/;" m struct:wps_event_data::wps_event_m2d -dev_name_len src/wps/wps_attr_parse.h /^ size_t dev_name_len;$/;" m struct:wps_parse_attr -dev_passwd_id src/wps/wps.h /^ u16 dev_passwd_id;$/;" m struct:wps_event_data::wps_event_er_enrollee -dev_passwd_id src/wps/wps.h /^ u16 dev_passwd_id;$/;" m struct:wps_event_data::wps_event_er_set_selected_registrar -dev_password src/wps/wps_i.h /^ u8 *dev_password;$/;" m struct:wps_data -dev_password_id src/wps/wps.h /^ u16 dev_password_id;$/;" m struct:wps_event_data::wps_event_m2d -dev_password_id src/wps/wps_attr_parse.h /^ const u8 *dev_password_id; \/* 2 octets *\/$/;" m struct:wps_parse_attr -dev_password_len src/wps/wps_i.h /^ size_t dev_password_len;$/;" m struct:wps_data -dev_pw src/wps/wps_registrar.c /^ u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN];$/;" m struct:wps_nfc_pw_token file: -dev_pw_id src/wps/wps.h /^ u16 dev_pw_id;$/;" m struct:wps_config -dev_pw_id src/wps/wps_i.h /^ u16 dev_pw_id;$/;" m struct:wps_data -dev_pw_len src/wps/wps_registrar.c /^ size_t dev_pw_len;$/;" m struct:wps_nfc_pw_token file: -device_name include/esp_supplicant/esp_wps.h /^ char device_name[WPS_MAX_DEVICE_NAME_LEN]; \/*!< Device name, null-terminated string. The default device name is used if the string is empty *\/$/;" m struct:__anon89 -device_name src/ap/ap_config.h /^ char *device_name;$/;" m struct:hostapd_bss_config -device_name src/wps/wps.h /^ char *device_name;$/;" m struct:wps_device_data -device_type src/ap/ap_config.h /^ u8 device_type[WPS_DEV_TYPE_LEN];$/;" m struct:hostapd_bss_config -devices src/wps/wps_registrar.c /^ struct wps_registrar_device *devices;$/;" m struct:wps_registrar typeref:struct:wps_registrar::wps_registrar_device file: -dh5_derive_shared src/crypto/dh_group5.c /^dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,$/;" f -dh5_free src/crypto/dh_group5.c /^dh5_free(void *ctx)$/;" f -dh5_init src/crypto/dh_group5.c /^dh5_init(struct wpabuf **priv, struct wpabuf **publ)$/;" f -dh_blob src/tls/tls.h /^ const u8 *dh_blob;$/;" m struct:tls_connection_params -dh_blob_len src/tls/tls.h /^ size_t dh_blob_len;$/;" m struct:tls_connection_params -dh_ctx src/wps/wps.h /^ void *dh_ctx;$/;" m struct:wps_context -dh_ctx src/wps/wps_i.h /^ void *dh_ctx;$/;" m struct:wps_data -dh_derive_shared src/crypto/dh_groups.c /^dh_derive_shared(const struct wpabuf *peer_public,$/;" f -dh_file src/tls/tls.h /^ const char *dh_file;$/;" m struct:tls_connection_params -dh_g src/tls/tlsv1_client_i.h /^ u8 *dh_g;$/;" m struct:tlsv1_client -dh_g src/tls/tlsv1_cred.h /^ u8 *dh_g; \/* generator *\/$/;" m struct:tlsv1_credentials -dh_g_len src/tls/tlsv1_client_i.h /^ size_t dh_g_len;$/;" m struct:tlsv1_client -dh_g_len src/tls/tlsv1_cred.h /^ size_t dh_g_len;$/;" m struct:tlsv1_credentials -dh_group include/crypto/dh_groups.h /^struct dh_group {$/;" s -dh_group14_generator src/crypto/dh_groups.c /^static const u8 dh_group14_generator[1] = { 0x02 };$/;" v file: -dh_group14_prime src/crypto/dh_groups.c /^static const u8 dh_group14_prime[256] = {$/;" v file: -dh_group15_generator src/crypto/dh_groups.c /^static const u8 dh_group15_generator[1] = { 0x02 };$/;" v file: -dh_group15_prime src/crypto/dh_groups.c /^static const u8 dh_group15_prime[384] = {$/;" v file: -dh_group16_generator src/crypto/dh_groups.c /^static const u8 dh_group16_generator[1] = { 0x02 };$/;" v file: -dh_group16_prime src/crypto/dh_groups.c /^static const u8 dh_group16_prime[512] = {$/;" v file: -dh_group17_generator src/crypto/dh_groups.c /^static const u8 dh_group17_generator[1] = { 0x02 };$/;" v file: -dh_group17_prime src/crypto/dh_groups.c /^static const u8 dh_group17_prime[768] = {$/;" v file: -dh_group18_generator src/crypto/dh_groups.c /^static const u8 dh_group18_generator[1] = { 0x02 };$/;" v file: -dh_group18_prime src/crypto/dh_groups.c /^static const u8 dh_group18_prime[1024] = {$/;" v file: -dh_group1_generator src/crypto/dh_groups.c /^static const u8 dh_group1_generator[1] = { 0x02 };$/;" v file: -dh_group1_prime src/crypto/dh_groups.c /^static const u8 dh_group1_prime[96] = {$/;" v file: -dh_group2_generator src/crypto/dh_groups.c /^static const u8 dh_group2_generator[1] = { 0x02 };$/;" v file: -dh_group2_prime src/crypto/dh_groups.c /^static const u8 dh_group2_prime[128] = {$/;" v file: -dh_group5_generator src/crypto/dh_groups.c /^static const u8 dh_group5_generator[1] = { 0x02 };$/;" v file: -dh_group5_prime src/crypto/dh_groups.c /^static const u8 dh_group5_prime[192] = {$/;" v file: -dh_groups src/crypto/dh_groups.c /^static struct dh_group dh_groups[] = {$/;" v typeref:struct:dh_group file: -dh_groups_get src/crypto/dh_groups.c /^dh_groups_get(int id)$/;" f -dh_init src/crypto/dh_groups.c /^dh_init(const struct dh_group *dh, struct wpabuf **priv)$/;" f -dh_p src/tls/tlsv1_client_i.h /^ u8 *dh_p;$/;" m struct:tlsv1_client -dh_p src/tls/tlsv1_cred.h /^ u8 *dh_p; \/* prime *\/$/;" m struct:tlsv1_credentials -dh_p_len src/tls/tlsv1_client_i.h /^ size_t dh_p_len;$/;" m struct:tlsv1_client -dh_p_len src/tls/tlsv1_cred.h /^ size_t dh_p_len;$/;" m struct:tlsv1_credentials -dh_privkey src/wps/wps.h /^ struct wpabuf *dh_privkey;$/;" m struct:wps_context typeref:struct:wps_context::wpabuf -dh_privkey src/wps/wps_i.h /^ struct wpabuf *dh_privkey;$/;" m struct:wps_data typeref:struct:wps_data::wpabuf -dh_pubkey src/wps/wps.h /^ struct wpabuf *dh_pubkey;$/;" m struct:wps_context typeref:struct:wps_context::wpabuf -dh_pubkey_e src/wps/wps_i.h /^ struct wpabuf *dh_pubkey_e;$/;" m struct:wps_data typeref:struct:wps_data::wpabuf -dh_pubkey_r src/wps/wps_i.h /^ struct wpabuf *dh_pubkey_r;$/;" m struct:wps_data typeref:struct:wps_data::wpabuf -dh_secret src/tls/tlsv1_server_i.h /^ u8 *dh_secret;$/;" m struct:tlsv1_server -dh_secret_len src/tls/tlsv1_server_i.h /^ size_t dh_secret_len;$/;" m struct:tlsv1_server -dh_ys src/tls/tlsv1_client_i.h /^ u8 *dh_ys;$/;" m struct:tlsv1_client -dh_ys_len src/tls/tlsv1_client_i.h /^ size_t dh_ys_len;$/;" m struct:tlsv1_client -dialog_token src/common/ieee802_11_defs.h /^ u8 dialog_token;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon78 -dis_ap_list src/wps/wps.h /^ struct discard_ap_list_t dis_ap_list[WPS_MAX_DIS_AP_NUM];$/;" m struct:wps_sm typeref:struct:wps_sm::discard_ap_list_t -disable_auto_conf src/wps/wps.h /^ int disable_auto_conf;$/;" m struct:wps_registrar_config -disable_auto_conf src/wps/wps_registrar.c /^ int disable_auto_conf;$/;" m struct:wps_registrar file: -disable_dgaf src/ap/ap_config.h /^ int disable_dgaf;$/;" m struct:hostapd_bss_config -disable_gtk src/ap/wpa_auth.h /^ int disable_gtk;$/;" m struct:wpa_auth_config -disable_pmksa_caching src/ap/wpa_auth.h /^ int disable_pmksa_caching;$/;" m struct:wpa_auth_config -disable_time_checks src/tls/tlsv1_client_i.h /^ unsigned int disable_time_checks:1;$/;" m struct:tlsv1_client -disassoc src/common/ieee802_11_defs.h /^ } STRUCT_PACKED disassoc;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon72 -discard_ap_cnt src/wps/wps.h /^ u8 discard_ap_cnt;$/;" m struct:wps_sm -discard_ap_list_t src/wps/wps.h /^struct discard_ap_list_t{$/;" s -disconnect src/ap/wpa_auth.h /^ void (*disconnect)(void *ctx, const u8 *addr, u16 reason);$/;" m struct:wpa_auth_callbacks -discover_ssid_cnt src/wps/wps.h /^ u8 discover_ssid_cnt;$/;" m struct:wps_sm -dk src/crypto/crypto_internal-cipher.c /^ u32 dk[32];$/;" m struct:crypto_cipher::__anon10::__anon14 file: -dk src/crypto/des_i.h /^ u32 dk[3][32];$/;" m struct:des3_key_s -dk src/fast_crypto/fast_crypto_internal-cipher.c /^ uint32_t dk[32];$/;" m struct:fast_crypto_cipher::__anon56::__anon60 file: -dl_list src/utils/list.h /^struct dl_list {$/;" s -dl_list_add src/utils/list.h /^static inline void dl_list_add(struct dl_list *list, struct dl_list *item)$/;" f -dl_list_add_tail src/utils/list.h /^static inline void dl_list_add_tail(struct dl_list *list, struct dl_list *item)$/;" f -dl_list_del src/utils/list.h /^static inline void dl_list_del(struct dl_list *item)$/;" f -dl_list_empty src/utils/list.h /^static inline int dl_list_empty(struct dl_list *list)$/;" f -dl_list_entry src/utils/list.h 73;" d -dl_list_first src/utils/list.h 76;" d -dl_list_for_each src/utils/list.h 84;" d -dl_list_for_each_reverse src/utils/list.h 95;" d -dl_list_for_each_safe src/utils/list.h 89;" d -dl_list_init src/utils/list.h /^static inline void dl_list_init(struct dl_list *list)$/;" f -dl_list_last src/utils/list.h 80;" d -dl_list_len src/utils/list.h /^static inline unsigned int dl_list_len(struct dl_list *list)$/;" f -dmp1 src/tls/rsa.c /^ struct bignum *dmp1; \/* d mod (p - 1); CRT exponent *\/$/;" m struct:crypto_rsa_key typeref:struct:crypto_rsa_key::bignum file: -dmq1 src/tls/rsa.c /^ struct bignum *dmq1; \/* d mod (q - 1); CRT exponent *\/$/;" m struct:crypto_rsa_key typeref:struct:crypto_rsa_key::bignum file: -dns src/tls/x509v3.h /^ char *dns; \/* dNSName *\/$/;" m struct:x509_name -dot11RSNAConfigGroupUpdateCount src/ap/wpa_auth.c /^static const u32 dot11RSNAConfigGroupUpdateCount = 4;$/;" v file: -dot11RSNAConfigPairwiseUpdateCount src/ap/wpa_auth.c /^static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;$/;" v file: -dot1x_enabled src/wps/wps_attr_parse.h /^ const u8 *dot1x_enabled; \/* 1 octet (Bool) *\/$/;" m struct:wps_parse_attr -dp src/crypto/libtommath.h /^ mp_digit *dp;$/;" m struct:__anon8 -dp src/tls/libtommath.h /^ mp_digit *dp;$/;" m struct:__anon40 -driver src/ap/ap_config.h /^ const struct wpa_driver_ops *driver;$/;" m struct:hostapd_config typeref:struct:hostapd_config::wpa_driver_ops -driver_init src/ap/hostapd.h /^ int (*driver_init)(struct hostapd_iface *iface);$/;" m struct:hapd_interfaces -dtim_period src/ap/ap_config.h /^ int dtim_period;$/;" m struct:hostapd_bss_config -dualband src/wps/wps.h /^ int dualband;$/;" m struct:wps_registrar_config -dualband src/wps/wps_registrar.c /^ int dualband;$/;" m struct:wps_registrar file: -dump_msk_file src/ap/ap_config.h /^ char *dump_msk_file;$/;" m struct:hostapd_bss_config -dup_binstr src/utils/common.c /^char * dup_binstr(const void *src, size_t len)$/;" f -duration src/common/ieee802_11_defs.h /^ le16 duration;$/;" m struct:ieee80211_mgmt -duration_id src/common/ieee802_11_defs.h /^ le16 duration_id;$/;" m struct:ieee80211_hdr -e src/tls/rsa.c /^ struct bignum *e; \/* public exponent *\/$/;" m struct:crypto_rsa_key typeref:struct:crypto_rsa_key::bignum file: -e_hash1 src/wps/wps_attr_parse.h /^ const u8 *e_hash1; \/* WPS_HASH_LEN (32) octets *\/$/;" m struct:wps_parse_attr -e_hash2 src/wps/wps_attr_parse.h /^ const u8 *e_hash2; \/* WPS_HASH_LEN (32) octets *\/$/;" m struct:wps_parse_attr -e_snonce1 src/wps/wps_attr_parse.h /^ const u8 *e_snonce1; \/* WPS_SECRET_NONCE_LEN (16) octets *\/$/;" m struct:wps_parse_attr -e_snonce2 src/wps/wps_attr_parse.h /^ const u8 *e_snonce2; \/* WPS_SECRET_NONCE_LEN (16) octets *\/$/;" m struct:wps_parse_attr -eap src/eap_peer/eap_tls_common.h /^ struct eap_sm *eap;$/;" m struct:eap_ssl_data typeref:struct:eap_ssl_data::eap_sm -eapKeyData src/eap_peer/eap_i.h /^ u8 *eapKeyData;$/;" m struct:eap_sm -eapKeyDataLen src/eap_peer/eap_i.h /^ size_t eapKeyDataLen;$/;" m struct:eap_sm -eap_allowed_phase2_type src/eap_peer/eap.c /^eap_allowed_phase2_type(int vendor, int type)$/;" f file: -eap_deinit_prev_method src/eap_peer/eap.c /^void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)$/;" f -eap_expand src/eap_peer/eap_defs.h /^struct eap_expand {$/;" s -eap_get_config src/eap_peer/eap.c /^struct eap_peer_config * eap_get_config(struct eap_sm *sm)$/;" f -eap_get_config_blob src/eap_peer/eap.c /^const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm,$/;" f -eap_get_config_identity src/eap_peer/eap.c /^const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)$/;" f -eap_get_config_new_password src/eap_peer/eap.c /^const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len)$/;" f -eap_get_config_password src/eap_peer/eap.c /^const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)$/;" f -eap_get_config_password2 src/eap_peer/eap.c /^const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)$/;" f -eap_get_id src/eap_peer/eap_common.c /^u8 eap_get_id(const struct wpabuf *msg)$/;" f -eap_get_phase2_type src/eap_peer/eap.c /^u32 eap_get_phase2_type(const char *name, int *vendor)$/;" f -eap_get_phase2_types src/eap_peer/eap.c /^struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,$/;" f -eap_get_type src/eap_peer/eap_common.c /^EapType eap_get_type(const struct wpabuf *msg)$/;" f -eap_hdr src/eap_peer/eap_defs.h /^struct eap_hdr {$/;" s -eap_hdr_len_valid src/eap_peer/eap_common.c /^int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload)$/;" f -eap_hdr_validate src/eap_peer/eap_common.c /^const u8 * eap_hdr_validate(int vendor, EapType eap_type,$/;" f -eap_identity src/wps/wps_attr_parse.h /^ const u8 *eap_identity; \/* <= 64 octets *\/$/;" m struct:wps_parse_attr -eap_identity_len src/wps/wps_attr_parse.h /^ size_t eap_identity_len;$/;" m struct:wps_parse_attr -eap_len src/eap_peer/eap_ttls.c /^ size_t eap_len;$/;" m struct:ttls_parse_avp file: -eap_method src/eap_peer/eap_i.h /^struct eap_method {$/;" s -eap_method_priv src/eap_peer/eap_i.h /^ void *eap_method_priv;$/;" m struct:eap_sm -eap_method_ret src/eap_peer/eap_i.h /^struct eap_method_ret {$/;" s -eap_method_type src/eap_peer/eap.h /^struct eap_method_type {$/;" s -eap_methods src/eap_peer/eap.c /^static struct eap_method *eap_methods = NULL;$/;" v typeref:struct:eap_method file: -eap_methods src/eap_peer/eap_config.h /^ struct eap_method_type *eap_methods;$/;" m struct:eap_peer_config typeref:struct:eap_peer_config::eap_method_type -eap_mschapv2_challenge src/eap_peer/eap_mschapv2.c /^eap_mschapv2_challenge($/;" f file: -eap_mschapv2_challenge_reply src/eap_peer/eap_mschapv2.c /^eap_mschapv2_challenge_reply($/;" f file: -eap_mschapv2_change_password src/eap_peer/eap_mschapv2.c /^eap_mschapv2_change_password($/;" f file: -eap_mschapv2_check_config src/eap_peer/eap_mschapv2.c /^eap_mschapv2_check_config(struct eap_sm *sm)$/;" f file: -eap_mschapv2_check_mslen src/eap_peer/eap_mschapv2.c /^eap_mschapv2_check_mslen(struct eap_sm *sm, size_t len,$/;" f file: -eap_mschapv2_copy_challenge src/eap_peer/eap_mschapv2.c /^eap_mschapv2_copy_challenge(struct eap_mschapv2_data *data,$/;" f file: -eap_mschapv2_data src/eap_peer/eap_mschapv2.c /^struct eap_mschapv2_data {$/;" s file: -eap_mschapv2_deinit src/eap_peer/eap_mschapv2.c /^eap_mschapv2_deinit(struct eap_sm *sm, void *priv)$/;" f file: -eap_mschapv2_failure src/eap_peer/eap_mschapv2.c /^eap_mschapv2_failure(struct eap_sm *sm,$/;" f file: -eap_mschapv2_failure_txt src/eap_peer/eap_mschapv2.c /^eap_mschapv2_failure_txt(struct eap_sm *sm,$/;" f file: -eap_mschapv2_getKey src/eap_peer/eap_mschapv2.c /^eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)$/;" f file: -eap_mschapv2_hdr src/eap_peer/eap_mschapv2.c /^struct eap_mschapv2_hdr {$/;" s file: -eap_mschapv2_init src/eap_peer/eap_mschapv2.c /^eap_mschapv2_init(struct eap_sm *sm)$/;" f file: -eap_mschapv2_isKeyAvailable src/eap_peer/eap_mschapv2.c /^eap_mschapv2_isKeyAvailable(struct eap_sm *sm, void *priv)$/;" f file: -eap_mschapv2_password_changed src/eap_peer/eap_mschapv2.c /^eap_mschapv2_password_changed(struct eap_sm *sm,$/;" f file: -eap_mschapv2_process src/eap_peer/eap_mschapv2.c /^eap_mschapv2_process(struct eap_sm *sm, void *priv,$/;" f file: -eap_mschapv2_success src/eap_peer/eap_mschapv2.c /^eap_mschapv2_success(struct eap_sm *sm,$/;" f file: -eap_msg_alloc src/eap_peer/eap_common.c /^struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,$/;" f -eap_peap_data src/eap_peer/eap_peap.c /^struct eap_peap_data {$/;" s file: -eap_peap_decrypt src/eap_peer/eap_peap.c /^eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,$/;" f file: -eap_peap_deinit src/eap_peer/eap_peap.c /^eap_peap_deinit(struct eap_sm *sm, void *priv)$/;" f file: -eap_peap_deinit_for_reauth src/eap_peer/eap_peap.c /^eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)$/;" f file: -eap_peap_derive_cmk src/eap_peer/eap_peap.c /^eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)$/;" f file: -eap_peap_getKey src/eap_peer/eap_peap.c /^eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)$/;" f file: -eap_peap_get_isk src/eap_peer/eap_peap.c /^eap_peap_get_isk(struct eap_sm *sm, struct eap_peap_data *data,$/;" f file: -eap_peap_get_session_id src/eap_peer/eap_peap.c /^eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)$/;" f file: -eap_peap_get_status src/eap_peer/eap_peap.c /^eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf,$/;" f file: -eap_peap_has_reauth_data src/eap_peer/eap_peap.c /^eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)$/;" f file: -eap_peap_init src/eap_peer/eap_peap.c /^eap_peap_init(struct eap_sm *sm)$/;" f file: -eap_peap_init_for_reauth src/eap_peer/eap_peap.c /^eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)$/;" f file: -eap_peap_isKeyAvailable src/eap_peer/eap_peap.c /^eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv)$/;" f file: -eap_peap_parse_phase1 src/eap_peer/eap_peap.c /^eap_peap_parse_phase1(struct eap_peap_data *data,$/;" f file: -eap_peap_phase2_request src/eap_peer/eap_peap.c /^static int eap_peap_phase2_request(struct eap_sm *sm,$/;" f file: -eap_peap_process src/eap_peer/eap_peap.c /^eap_peap_process(struct eap_sm *sm, void *priv,$/;" f file: -eap_peapv2_tlv_eap_payload src/eap_peer/eap_peap.c /^eap_peapv2_tlv_eap_payload(struct wpabuf *buf)$/;" f file: -eap_peer_blob_deinit src/eap_peer/eap.c /^void eap_peer_blob_deinit(struct eap_sm *sm)$/;" f -eap_peer_blob_init src/eap_peer/eap.c /^int eap_peer_blob_init(struct eap_sm *sm)$/;" f -eap_peer_config src/eap_peer/eap_config.h /^struct eap_peer_config {$/;" s -eap_peer_config_deinit src/eap_peer/eap.c /^void eap_peer_config_deinit(struct eap_sm *sm)$/;" f -eap_peer_config_init src/eap_peer/eap.c /^int eap_peer_config_init($/;" f -eap_peer_get_eap_method src/eap_peer/eap.c /^const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method)$/;" f -eap_peer_get_methods src/eap_peer/eap.c /^const struct eap_method * eap_peer_get_methods(size_t *count)$/;" f -eap_peer_get_type src/eap_peer/eap.c /^EapType eap_peer_get_type(const char *name, int *vendor)$/;" f -eap_peer_method_alloc src/eap_peer/eap.c /^struct eap_method * eap_peer_method_alloc(int vendor, EapType method,$/;" f -eap_peer_method_free src/eap_peer/eap.c /^void eap_peer_method_free(struct eap_method *method)$/;" f -eap_peer_method_register src/eap_peer/eap.c /^int eap_peer_method_register(struct eap_method *method)$/;" f -eap_peer_mschapv2_register src/eap_peer/eap_mschapv2.c /^eap_peer_mschapv2_register(void)$/;" f -eap_peer_peap_register src/eap_peer/eap_peap.c /^eap_peer_peap_register(void)$/;" f -eap_peer_register_methods src/eap_peer/eap.c /^int eap_peer_register_methods(void)$/;" f -eap_peer_select_phase2_methods src/eap_peer/eap_tls_common.c /^int eap_peer_select_phase2_methods(struct eap_peer_config *config,$/;" f -eap_peer_sm_deinit src/esp_supplicant/esp_wpa_enterprise.c /^static void eap_peer_sm_deinit(void)$/;" f file: -eap_peer_sm_init src/esp_supplicant/esp_wpa_enterprise.c /^static int eap_peer_sm_init(void)$/;" f file: -eap_peer_tls_build_ack src/eap_peer/eap_tls_common.c /^struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,$/;" f -eap_peer_tls_data_reassemble src/eap_peer/eap_tls_common.c /^static const struct wpabuf * eap_peer_tls_data_reassemble($/;" f file: -eap_peer_tls_decrypt src/eap_peer/eap_tls_common.c /^int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data,$/;" f -eap_peer_tls_derive_key src/eap_peer/eap_tls_common.c /^u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,$/;" f -eap_peer_tls_derive_session_id src/eap_peer/eap_tls_common.c /^u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,$/;" f -eap_peer_tls_encrypt src/eap_peer/eap_tls_common.c /^int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,$/;" f -eap_peer_tls_phase2_nak src/eap_peer/eap_tls_common.c /^int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types,$/;" f -eap_peer_tls_process_helper src/eap_peer/eap_tls_common.c /^int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,$/;" f -eap_peer_tls_process_init src/eap_peer/eap_tls_common.c /^const u8 * eap_peer_tls_process_init(struct eap_sm *sm,$/;" f -eap_peer_tls_reassemble_fragment src/eap_peer/eap_tls_common.c /^static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data,$/;" f file: -eap_peer_tls_reauth_init src/eap_peer/eap_tls_common.c /^int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data)$/;" f -eap_peer_tls_register src/eap_peer/eap_tls.c /^int eap_peer_tls_register(void)$/;" f -eap_peer_tls_reset_input src/eap_peer/eap_tls_common.c /^void eap_peer_tls_reset_input(struct eap_ssl_data *data)$/;" f -eap_peer_tls_reset_output src/eap_peer/eap_tls_common.c /^void eap_peer_tls_reset_output(struct eap_ssl_data *data)$/;" f -eap_peer_tls_ssl_deinit src/eap_peer/eap_tls_common.c /^void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)$/;" f -eap_peer_tls_ssl_init src/eap_peer/eap_tls_common.c /^int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,$/;" f -eap_peer_tls_status src/eap_peer/eap_tls_common.c /^int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data,$/;" f -eap_peer_ttls_register src/eap_peer/eap_ttls.c /^int eap_peer_ttls_register(void)$/;" f -eap_peer_unregister_methods src/eap_peer/eap.c /^void eap_peer_unregister_methods(void)$/;" f -eap_sm src/eap_peer/eap_i.h /^struct eap_sm {$/;" s -eap_sm_abort src/eap_peer/eap.c /^void eap_sm_abort(struct eap_sm *sm)$/;" f -eap_sm_build_identity_resp src/eap_peer/eap.c /^struct wpabuf * eap_sm_build_identity_resp(struct eap_sm *sm, u8 id, int encrypted)$/;" f -eap_sm_build_nak src/eap_peer/eap.c /^struct wpabuf * eap_sm_build_nak(struct eap_sm *sm, EapType type, u8 id)$/;" f -eap_sm_process_request src/esp_supplicant/esp_wpa_enterprise.c /^int eap_sm_process_request(struct eap_sm *sm, struct wpabuf *reqData)$/;" f -eap_sm_send_eapol src/esp_supplicant/esp_wpa_enterprise.c /^int eap_sm_send_eapol(struct eap_sm *sm, struct wpabuf *resp)$/;" f -eap_ssl_data src/eap_peer/eap_tls_common.h /^struct eap_ssl_data {$/;" s -eap_tls_check_blob src/eap_peer/eap_tls_common.c /^static int eap_tls_check_blob(struct eap_sm *sm, const char **name,$/;" f file: -eap_tls_data src/eap_peer/eap_tls.c /^struct eap_tls_data {$/;" s file: -eap_tls_deinit src/eap_peer/eap_tls.c /^static void eap_tls_deinit(struct eap_sm *sm, void *priv)$/;" f file: -eap_tls_failure src/eap_peer/eap_tls.c /^static struct wpabuf * eap_tls_failure(struct eap_sm *sm,$/;" f file: -eap_tls_getKey src/eap_peer/eap_tls.c /^static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)$/;" f file: -eap_tls_init src/eap_peer/eap_tls.c /^static void * eap_tls_init(struct eap_sm *sm)$/;" f file: -eap_tls_init_connection src/eap_peer/eap_tls_common.c /^static int eap_tls_init_connection(struct eap_sm *sm,$/;" f file: -eap_tls_isKeyAvailable src/eap_peer/eap_tls.c /^static bool eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv)$/;" f file: -eap_tls_msg_alloc src/eap_peer/eap_tls_common.c /^static struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,$/;" f file: -eap_tls_params_flags src/eap_peer/eap_tls_common.c /^static void eap_tls_params_flags(struct tls_connection_params *params,$/;" f file: -eap_tls_params_from_conf src/eap_peer/eap_tls_common.c /^static int eap_tls_params_from_conf(struct eap_sm *sm,$/;" f file: -eap_tls_params_from_conf1 src/eap_peer/eap_tls_common.c /^static void eap_tls_params_from_conf1(struct tls_connection_params *params,$/;" f file: -eap_tls_process src/eap_peer/eap_tls.c /^static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,$/;" f file: -eap_tls_process_input src/eap_peer/eap_tls_common.c /^static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data,$/;" f file: -eap_tls_process_output src/eap_peer/eap_tls_common.c /^static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type,$/;" f file: -eap_tls_success src/eap_peer/eap_tls.c /^static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,$/;" f file: -eap_tlv_add_cryptobinding src/eap_peer/eap_peap.c /^eap_tlv_add_cryptobinding(struct eap_sm *sm,$/;" f file: -eap_tlv_build_nak src/eap_peer/eap_peap.c /^eap_tlv_build_nak(int id, u16 nak_type)$/;" f file: -eap_tlv_build_result src/eap_peer/eap_peap.c /^eap_tlv_build_result(struct eap_sm *sm,$/;" f file: -eap_tlv_crypto_binding_tlv src/eap_peer/eap_tlv_common.h /^struct eap_tlv_crypto_binding_tlv {$/;" s -eap_tlv_hdr src/eap_peer/eap_tlv_common.h /^struct eap_tlv_hdr {$/;" s -eap_tlv_intermediate_result_tlv src/eap_peer/eap_tlv_common.h /^struct eap_tlv_intermediate_result_tlv {$/;" s -eap_tlv_nak_tlv src/eap_peer/eap_tlv_common.h /^struct eap_tlv_nak_tlv {$/;" s -eap_tlv_pac_ack_tlv src/eap_peer/eap_tlv_common.h /^struct eap_tlv_pac_ack_tlv {$/;" s -eap_tlv_pac_type_tlv src/eap_peer/eap_tlv_common.h /^struct eap_tlv_pac_type_tlv {$/;" s -eap_tlv_process src/eap_peer/eap_peap.c /^eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data,$/;" f file: -eap_tlv_request_action_tlv src/eap_peer/eap_tlv_common.h /^struct eap_tlv_request_action_tlv {$/;" s -eap_tlv_result_tlv src/eap_peer/eap_tlv_common.h /^struct eap_tlv_result_tlv {$/;" s -eap_tlv_validate_cryptobinding src/eap_peer/eap_peap.c /^eap_tlv_validate_cryptobinding(struct eap_sm *sm,$/;" f file: -eap_ttls_avp_add src/eap_peer/eap_ttls.c /^static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code,$/;" f file: -eap_ttls_avp_hdr src/eap_peer/eap_ttls.c /^static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id,$/;" f file: -eap_ttls_check_auth_status src/eap_peer/eap_ttls.c /^static void eap_ttls_check_auth_status(struct eap_sm *sm, $/;" f file: -eap_ttls_data src/eap_peer/eap_ttls.c /^struct eap_ttls_data {$/;" s file: -eap_ttls_decrypt src/eap_peer/eap_ttls.c /^static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,$/;" f file: -eap_ttls_deinit src/eap_peer/eap_ttls.c /^static void eap_ttls_deinit(struct eap_sm *sm, void *priv)$/;" f file: -eap_ttls_deinit_for_reauth src/eap_peer/eap_ttls.c /^static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv)$/;" f file: -eap_ttls_encrypt_response src/eap_peer/eap_ttls.c /^static int eap_ttls_encrypt_response(struct eap_sm *sm,$/;" f file: -eap_ttls_fake_identity_request src/eap_peer/eap_ttls.c /^static u8 * eap_ttls_fake_identity_request(void)$/;" f file: -eap_ttls_getKey src/eap_peer/eap_ttls.c /^static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)$/;" f file: -eap_ttls_get_session_id src/eap_peer/eap_ttls.c /^static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)$/;" f file: -eap_ttls_get_status src/eap_peer/eap_ttls.c /^static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf,$/;" f file: -eap_ttls_has_reauth_data src/eap_peer/eap_ttls.c /^static bool eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv)$/;" f file: -eap_ttls_implicit_challenge src/eap_peer/eap_ttls.c /^static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,$/;" f file: -eap_ttls_implicit_identity_request src/eap_peer/eap_ttls.c /^static int eap_ttls_implicit_identity_request(struct eap_sm *sm,$/;" f file: -eap_ttls_init src/eap_peer/eap_ttls.c /^static void * eap_ttls_init(struct eap_sm *sm)$/;" f file: -eap_ttls_init_for_reauth src/eap_peer/eap_ttls.c /^static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv)$/;" f file: -eap_ttls_isKeyAvailable src/eap_peer/eap_ttls.c /^static bool eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv)$/;" f file: -eap_ttls_parse_attr_eap src/eap_peer/eap_ttls.c /^static int eap_ttls_parse_attr_eap(const u8 *dpos, size_t dlen,$/;" f file: -eap_ttls_parse_avp src/eap_peer/eap_ttls.c /^static int eap_ttls_parse_avp(u8 *pos, size_t left,$/;" f file: -eap_ttls_parse_avps src/eap_peer/eap_ttls.c /^static int eap_ttls_parse_avps(struct wpabuf *in_decrypted,$/;" f file: -eap_ttls_phase2_eap_deinit src/eap_peer/eap_ttls.c /^static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm,$/;" f file: -eap_ttls_phase2_request src/eap_peer/eap_ttls.c /^static int eap_ttls_phase2_request(struct eap_sm *sm,$/;" f file: -eap_ttls_phase2_request_mschapv2 src/eap_peer/eap_ttls.c /^static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,$/;" f file: -eap_ttls_phase2_start src/eap_peer/eap_ttls.c /^static int eap_ttls_phase2_start(struct eap_sm *sm, struct eap_ttls_data *data,$/;" f file: -eap_ttls_process src/eap_peer/eap_ttls.c /^static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv,$/;" f file: -eap_ttls_process_decrypted src/eap_peer/eap_ttls.c /^static int eap_ttls_process_decrypted(struct eap_sm *sm,$/;" f file: -eap_ttls_process_handshake src/eap_peer/eap_ttls.c /^static int eap_ttls_process_handshake(struct eap_sm *sm,$/;" f file: -eap_ttls_process_phase2_mschapv2 src/eap_peer/eap_ttls.c /^static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,$/;" f file: -eap_ttls_process_tnc_start src/eap_peer/eap_ttls.c /^static int eap_ttls_process_tnc_start(struct eap_sm *sm,$/;" f file: -eap_ttls_v0_derive_key src/eap_peer/eap_ttls.c /^static int eap_ttls_v0_derive_key(struct eap_sm *sm,$/;" f file: -eap_type src/eap_peer/eap_tls.c /^ u8 eap_type;$/;" m struct:eap_tls_data file: -eap_type src/eap_peer/eap_tls_common.h /^ u8 eap_type;$/;" m struct:eap_ssl_data -eap_type src/wps/wps_attr_parse.h /^ const u8 *eap_type; \/* <= 8 octets *\/$/;" m struct:wps_parse_attr -eap_type_len src/wps/wps_attr_parse.h /^ size_t eap_type_len;$/;" m struct:wps_parse_attr -eap_update_len src/eap_peer/eap_common.c /^void eap_update_len(struct wpabuf *msg)$/;" f -eapdata src/eap_peer/eap_ttls.c /^ u8 *eapdata;$/;" m struct:ttls_parse_avp file: -eapol_key_timeout_first src/ap/wpa_auth.c /^static const u32 eapol_key_timeout_first = 100; \/* ms *\/$/;" v file: -eapol_key_timeout_first_group src/ap/wpa_auth.c /^static const u32 eapol_key_timeout_first_group = 500; \/* ms *\/$/;" v file: -eapol_key_timeout_subseq src/ap/wpa_auth.c /^static const u32 eapol_key_timeout_subseq = 1000; \/* ms *\/$/;" v file: -eapol_sm_notify_eap_success src/rsn_supp/wpa.c /^void eapol_sm_notify_eap_success(Boolean success)$/;" f -eapol_txcb src/rsn_supp/wpa.c /^void eapol_txcb(void *eb)$/;" f -eapol_version src/ap/ap_config.h /^ int eapol_version;$/;" m struct:hostapd_bss_config -eapol_version src/ap/wpa_auth.h /^ int eapol_version;$/;" m struct:wpa_auth_config -eapol_version src/rsn_supp/wpa.h /^ u8 eapol_version;$/;" m struct:wpa_sm -eapol_version src/wps/wps.h /^ u8 eapol_version;$/;" m struct:wps_sm -ecp_mpi_load test/test_crypto.c /^static inline void ecp_mpi_load( mbedtls_mpi *X, const mbedtls_mpi_uint *p, size_t len )$/;" f file: -ecp_opp src/crypto/crypto_mbedtls.c /^static int ecp_opp( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_ecp_point *P)$/;" f file: -ecw2cw src/ap/ap_config.c 100;" d file: -ecw2cw src/ap/ap_config.c 124;" d file: -eid src/common/ieee802_11_defs.h /^ u8 eid; \/* 221 = 0xdd *\/$/;" m struct:wmm_tspec_element -ek src/crypto/crypto_internal-cipher.c /^ u32 ek[32];$/;" m struct:crypto_cipher::__anon10::__anon14 file: -ek src/crypto/des_i.h /^ u32 ek[3][32];$/;" m struct:des3_key_s -ek src/fast_crypto/fast_crypto_internal-cipher.c /^ uint32_t ek[32];$/;" m struct:fast_crypto_cipher::__anon56::__anon60 file: -elem_id src/common/wpa_common.h /^ u8 elem_id; \/* WLAN_EID_RSN *\/$/;" m struct:rsn_ie_hdr -elem_id src/common/wpa_common.h /^ u8 elem_id;$/;" m struct:wpa_ie_hdr -element_id src/common/ieee802_11_defs.h /^ u8 element_id;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon79 -eloop_cancel_timeout src/utils/wpa_debug.c /^int eloop_cancel_timeout(eloop_timeout_handler handler,$/;" f -eloop_register_timeout src/utils/wpa_debug.c /^int eloop_register_timeout(unsigned int secs, unsigned int usecs,$/;" f -eloop_timeout_handler include/utils/wpa_debug.h /^typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx);$/;" t -email src/tls/x509v3.h /^ char *email; \/* emailAddress *\/$/;" m struct:x509_name -emsk src/wps/wps_i.h /^ u8 emsk[WPS_EMSK_LEN];$/;" m struct:wps_data -encr_hash src/eap_peer/eap_mschapv2.c /^ u8 encr_hash[16];$/;" m struct:ms_change_password file: -encr_password src/eap_peer/eap_mschapv2.c /^ u8 encr_password[516];$/;" m struct:ms_change_password file: -encr_settings src/wps/wps_attr_parse.h /^ const u8 *encr_settings;$/;" m struct:wps_parse_attr -encr_settings_len src/wps/wps_attr_parse.h /^ size_t encr_settings_len;$/;" m struct:wps_parse_attr -encr_type src/wps/wps.h /^ u16 encr_type;$/;" m struct:wps_credential -encr_type src/wps/wps_attr_parse.h /^ const u8 *encr_type; \/* 2 octets *\/$/;" m struct:wps_parse_attr -encr_type src/wps/wps_i.h /^ u16 encr_type;$/;" m struct:wps_data -encr_type_flags src/wps/wps_attr_parse.h /^ const u8 *encr_type_flags; \/* 2 octets *\/$/;" m struct:wps_parse_attr -encr_types src/wps/wps.h /^ u16 encr_types;$/;" m struct:wps_context -encrypt_pw_block_with_password_hash src/crypto/ms_funcs.c /^int encrypt_pw_block_with_password_hash($/;" f -engine src/tls/tls.h /^ int engine;$/;" m struct:tls_connection_params -engine_id src/tls/tls.h /^ const char *engine_id;$/;" m struct:tls_connection_params -enrollee src/wps/wps.h /^ int enrollee;$/;" m struct:wps_event_data::wps_event_pwd_auth_fail -enrollee src/wps/wps.h /^ } enrollee;$/;" m union:wps_event_data typeref:struct:wps_event_data::wps_event_er_enrollee -enrollee_addr src/wps/wps_registrar.c /^ u8 enrollee_addr[ETH_ALEN];$/;" m struct:wps_uuid_pin file: -enrollee_nonce src/wps/wps_attr_parse.h /^ const u8 *enrollee_nonce; \/* WPS_NONCE_LEN (16) octets *\/$/;" m struct:wps_parse_attr -enrollee_seen_cb src/wps/wps.h /^ void (*enrollee_seen_cb)(void *ctx, const u8 *addr, const u8 *uuid_e,$/;" m struct:wps_registrar_config -enrollee_seen_cb src/wps/wps_registrar.c /^ void (*enrollee_seen_cb)(void *ctx, const u8 *addr, const u8 *uuid_e,$/;" m struct:wps_registrar file: -er src/wps/wps_i.h /^ int er;$/;" m struct:wps_data -error src/ap/wpa_auth_ie.h /^ const u8 *error;$/;" m struct:wpa_eapol_ie_parse -error src/rsn_supp/wpa_ie.h /^ const u8 *error;$/;" m struct:wpa_eapol_ie_parse -error_indication src/wps/wps.h /^ u16 error_indication;$/;" m struct:wps_event_data::wps_event_fail -error_indication src/wps/wps_i.h /^ u16 error_indication;$/;" m struct:wps_data -error_len src/ap/wpa_auth_ie.h /^ size_t error_len;$/;" m struct:wpa_eapol_ie_parse -error_len src/rsn_supp/wpa_ie.h /^ size_t error_len;$/;" m struct:wpa_eapol_ie_parse -error_type src/common/wpa_common.h /^ be16 error_type;$/;" m struct:rsn_error_kde -esp_supplicant_init src/esp_supplicant/esp_wpa_main.c /^int esp_supplicant_init(void)$/;" f -esp_wifi_sta_wpa2_ent_clear_ca_cert src/esp_supplicant/esp_wpa_enterprise.c /^void esp_wifi_sta_wpa2_ent_clear_ca_cert(void)$/;" f -esp_wifi_sta_wpa2_ent_clear_cert_key src/esp_supplicant/esp_wpa_enterprise.c /^void esp_wifi_sta_wpa2_ent_clear_cert_key(void)$/;" f -esp_wifi_sta_wpa2_ent_clear_identity src/esp_supplicant/esp_wpa_enterprise.c /^void esp_wifi_sta_wpa2_ent_clear_identity(void)$/;" f -esp_wifi_sta_wpa2_ent_clear_new_password src/esp_supplicant/esp_wpa_enterprise.c /^void esp_wifi_sta_wpa2_ent_clear_new_password(void)$/;" f -esp_wifi_sta_wpa2_ent_clear_password src/esp_supplicant/esp_wpa_enterprise.c /^void esp_wifi_sta_wpa2_ent_clear_password(void)$/;" f -esp_wifi_sta_wpa2_ent_clear_username src/esp_supplicant/esp_wpa_enterprise.c /^void esp_wifi_sta_wpa2_ent_clear_username(void)$/;" f -esp_wifi_sta_wpa2_ent_disable src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_disable(void)$/;" f -esp_wifi_sta_wpa2_ent_disable_fn src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_disable_fn(void *param)$/;" f -esp_wifi_sta_wpa2_ent_enable src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_enable(const esp_wpa2_config_t *config)$/;" f -esp_wifi_sta_wpa2_ent_enable_fn src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_enable_fn(const esp_wpa2_config_t *config)$/;" f -esp_wifi_sta_wpa2_ent_get_disable_time_check src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_get_disable_time_check(bool *disable)$/;" f -esp_wifi_sta_wpa2_ent_set_ca_cert src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_set_ca_cert(const unsigned char *ca_cert, int ca_cert_len)$/;" f -esp_wifi_sta_wpa2_ent_set_cert_key src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_set_cert_key(const unsigned char *client_cert, int client_cert_len, const unsigned char *private_key, int private_key_len, const unsigned char *private_key_passwd, int private_key_passwd_len)$/;" f -esp_wifi_sta_wpa2_ent_set_disable_time_check src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_set_disable_time_check(bool disable)$/;" f -esp_wifi_sta_wpa2_ent_set_identity src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_set_identity(const unsigned char *identity, int len)$/;" f -esp_wifi_sta_wpa2_ent_set_new_password src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_set_new_password(const unsigned char *new_password, int len)$/;" f -esp_wifi_sta_wpa2_ent_set_password src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_set_password(const unsigned char *password, int len)$/;" f -esp_wifi_sta_wpa2_ent_set_username src/esp_supplicant/esp_wpa_enterprise.c /^esp_err_t esp_wifi_sta_wpa2_ent_set_username(const unsigned char *username, int len)$/;" f -esp_wifi_wps_disable src/esp_supplicant/esp_wps.c /^int esp_wifi_wps_disable(void)$/;" f -esp_wifi_wps_enable src/esp_supplicant/esp_wps.c /^int esp_wifi_wps_enable(const esp_wps_config_t *config)$/;" f -esp_wifi_wps_start src/esp_supplicant/esp_wps.c /^int esp_wifi_wps_start(int timeout_ms)$/;" f -esp_wpa2_config_t include/esp_supplicant/esp_wpa_enterprise.h /^}esp_wpa2_config_t;$/;" t typeref:struct:__anon88 -esp_wps_config_t include/esp_supplicant/esp_wps.h /^} esp_wps_config_t;$/;" t typeref:struct:__anon90 -event_cb src/tls/tls.h /^ void (*event_cb)(void *ctx, enum tls_event ev,$/;" m struct:tls_config -event_cb src/wps/wps.h /^ void (*event_cb)(void *ctx, enum wps_event event,$/;" m struct:wps_context -expanded_key_material src/tls/tlsv1_common.h /^ size_t expanded_key_material;$/;" m struct:tls_cipher_data -expiration src/wps/wps_registrar.c /^ struct os_time expiration;$/;" m struct:wps_uuid_pin typeref:struct:wps_uuid_pin::os_time file: -ext_data include/utils/wpabuf.h /^ u8 *ext_data; \/* pointer to external data; NULL if data follows$/;" m struct:wpabuf -ext_password_alloc src/utils/ext_password.c /^struct wpabuf * ext_password_alloc(size_t len)$/;" f -ext_password_backend src/utils/ext_password_i.h /^struct ext_password_backend {$/;" s -ext_password_data src/utils/ext_password.c /^struct ext_password_data {$/;" s file: -ext_password_deinit src/utils/ext_password.c /^void ext_password_deinit(struct ext_password_data *data)$/;" f -ext_password_deinit src/utils/ext_password.h 27;" d -ext_password_free src/utils/ext_password.c /^void ext_password_free(struct wpabuf *pw)$/;" f -ext_password_free src/utils/ext_password.h 29;" d -ext_password_get src/utils/ext_password.c /^struct wpabuf * ext_password_get(struct ext_password_data *data,$/;" f -ext_password_get src/utils/ext_password.h 28;" d -ext_password_init src/utils/ext_password.c /^struct ext_password_data * ext_password_init(const char *backend,$/;" f -ext_password_init src/utils/ext_password.h 26;" d -ext_reg src/wps/wps_i.h /^ int ext_reg;$/;" m struct:wps_data -extensions_present src/tls/x509v3.h /^ unsigned int extensions_present;$/;" m struct:x509_certificate -extra_cred src/ap/ap_config.h /^ u8 *extra_cred;$/;" m struct:hostapd_bss_config -extra_cred src/wps/wps.h /^ const u8 *extra_cred;$/;" m struct:wps_registrar_config -extra_cred src/wps/wps_registrar.c /^ struct wpabuf *extra_cred;$/;" m struct:wps_registrar typeref:struct:wps_registrar::wpabuf file: -extra_cred_len src/ap/ap_config.h /^ size_t extra_cred_len;$/;" m struct:hostapd_bss_config -extra_cred_len src/wps/wps.h /^ size_t extra_cred_len;$/;" m struct:wps_registrar_config -factory_info include/esp_supplicant/esp_wps.h /^ wps_factory_information_t factory_info;$/;" m struct:__anon90 -fail src/wps/wps.h /^ } fail;$/;" m union:wps_event_data typeref:struct:wps_event_data::wps_event_fail -fast_aes_128_cbc_decrypt src/fast_crypto/fast_aes-cbc.c /^fast_aes_128_cbc_decrypt(const uint8_t *key, const uint8_t *iv, uint8_t *data, size_t data_len)$/;" f -fast_aes_128_cbc_encrypt src/fast_crypto/fast_aes-cbc.c /^fast_aes_128_cbc_encrypt(const uint8_t *key, const uint8_t *iv, uint8_t *data, size_t data_len)$/;" f -fast_aes_unwrap src/fast_crypto/fast_aes-unwrap.c /^fast_aes_unwrap(const uint8_t *kek, int n, const uint8_t *cipher, uint8_t *plain)$/;" f -fast_aes_wrap src/fast_crypto/fast_aes-wrap.c /^int fast_aes_wrap(const uint8_t *kek, int n, const uint8_t *plain, uint8_t *cipher)$/;" f -fast_crypto_cipher src/fast_crypto/fast_crypto_internal-cipher.c /^struct fast_crypto_cipher {$/;" s file: -fast_crypto_cipher_decrypt src/fast_crypto/fast_crypto_internal-cipher.c /^int fast_crypto_cipher_decrypt(struct crypto_cipher *ctx, const uint8_t *crypt,$/;" f -fast_crypto_cipher_deinit src/fast_crypto/fast_crypto_internal-cipher.c /^void fast_crypto_cipher_deinit(struct crypto_cipher *ctx)$/;" f -fast_crypto_cipher_encrypt src/fast_crypto/fast_crypto_internal-cipher.c /^int fast_crypto_cipher_encrypt(struct crypto_cipher *ctx, const uint8_t *plain,$/;" f -fast_crypto_cipher_init src/fast_crypto/fast_crypto_internal-cipher.c /^struct crypto_cipher * fast_crypto_cipher_init(enum crypto_cipher_alg alg,$/;" f -fast_crypto_hash src/fast_crypto/fast_crypto_internal.c /^struct fast_crypto_hash {$/;" s file: -fast_crypto_hash_finish src/fast_crypto/fast_crypto_internal.c /^int fast_crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)$/;" f -fast_crypto_hash_init src/fast_crypto/fast_crypto_internal.c /^struct crypto_hash * fast_crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,$/;" f -fast_crypto_hash_update src/fast_crypto/fast_crypto_internal.c /^void fast_crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)$/;" f -fast_crypto_mod_exp src/fast_crypto/fast_crypto_internal-modexp.c /^fast_crypto_mod_exp(const uint8_t *base, size_t base_len,$/;" f -fast_hmac_sha256 src/fast_crypto/fast_sha256.c /^fast_hmac_sha256(const uint8_t *key, size_t key_len, const uint8_t *data,$/;" f -fast_hmac_sha256_vector src/fast_crypto/fast_sha256.c /^fast_hmac_sha256_vector(const uint8_t *key, size_t key_len, size_t num_elem,$/;" f -fast_mp_montgomery_reduce src/crypto/libtommath.h /^fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)$/;" f -fast_mp_montgomery_reduce src/tls/libtommath.h /^fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)$/;" f -fast_s_mp_mul_digs src/crypto/libtommath.h /^fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)$/;" f -fast_s_mp_mul_digs src/tls/libtommath.h /^fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)$/;" f -fast_s_mp_sqr src/crypto/libtommath.h /^fast_s_mp_sqr (mp_int * a, mp_int * b)$/;" f -fast_s_mp_sqr src/tls/libtommath.h /^fast_s_mp_sqr (mp_int * a, mp_int * b)$/;" f -fast_sha256_prf src/fast_crypto/fast_sha256.c /^fast_sha256_prf(const uint8_t *key, size_t key_len, const char *label,$/;" f -fast_sha256_vector src/fast_crypto/fast_sha256-internal.c /^fast_sha256_vector(size_t num_elem, const uint8_t *addr[], const size_t *len,$/;" f -finish_state src/eap_peer/eap_i.h /^ u8 finish_state;$/;" m struct:eap_sm -fips_mode src/tls/tls.h /^ int fips_mode;$/;" m struct:tls_config -first_sta_seen src/ap/wpa_auth_i.h /^ Boolean first_sta_seen;$/;" m struct:wpa_group -flags src/ap/hostapd.h /^ int flags; \/* HOSTAPD_RATE_ flags *\/$/;" m struct:hostapd_rate_data -flags src/ap/sta_info.h /^ u32 flags; \/* Bitfield of WLAN_STA_* *\/$/;" m struct:sta_info -flags src/eap_peer/eap_config.h /^ u32 flags;$/;" m struct:eap_peer_config -flags src/eap_peer/eap_mschapv2.c /^ u8 flags;$/;" m struct:ms_response file: -flags src/eap_peer/eap_mschapv2.c /^ u8 flags[2];$/;" m struct:ms_change_password file: -flags src/tls/tls.h /^ unsigned int flags;$/;" m struct:tls_connection_params -flags src/wps/wps_registrar.c /^ int flags;$/;" m struct:wps_uuid_pin file: -fn src/esp_supplicant/esp_wifi_driver.h /^ wifi_ipc_fn_t fn;$/;" m struct:__anon32 -fn src/esp_supplicant/esp_wifi_driver.h /^ wifi_wpa2_fn_t fn;$/;" m struct:__anon31 -for_each_auth src/ap/wpa_auth.h /^ int (*for_each_auth)(void *ctx, int (*cb)(struct wpa_authenticator *a,$/;" m struct:wpa_auth_callbacks -for_each_interface src/ap/hostapd.h /^ int (*for_each_interface)(struct hapd_interfaces *interfaces,$/;" m struct:hapd_interfaces -for_each_sta src/ap/wpa_auth.h /^ int (*for_each_sta)(void *ctx, int (*cb)(struct wpa_state_machine *sm,$/;" m struct:wpa_auth_callbacks -force_new_label src/eap_peer/eap_peap.c /^ int peap_version, force_peap_version, force_new_label;$/;" m struct:eap_peap_data file: -force_pbc_overlap src/wps/wps_registrar.c /^ int force_pbc_overlap;$/;" m struct:wps_registrar file: -force_peap_version src/eap_peer/eap_peap.c /^ int peap_version, force_peap_version, force_new_label;$/;" m struct:eap_peap_data file: -fragm_threshold src/ap/ap_config.h /^ int fragm_threshold;$/;" m struct:hostapd_config -fragment_size src/eap_peer/eap_config.h /^ int fragment_size;$/;" m struct:eap_peer_config -frame_control src/common/ieee802_11_defs.h /^ le16 frame_control;$/;" m struct:ieee80211_hdr -frame_control src/common/ieee802_11_defs.h /^ le16 frame_control;$/;" m struct:ieee80211_mgmt -frame_type src/ap/wpa_auth.h /^ u8 frame_type; \/* RSN_REMOTE_FRAME_TYPE_FT_RRB *\/$/;" m struct:ft_r0kh_r1kh_pull_frame -frame_type src/ap/wpa_auth.h /^ u8 frame_type; \/* RSN_REMOTE_FRAME_TYPE_FT_RRB *\/$/;" m struct:ft_r0kh_r1kh_push_frame -frame_type src/ap/wpa_auth.h /^ u8 frame_type; \/* RSN_REMOTE_FRAME_TYPE_FT_RRB *\/$/;" m struct:ft_r0kh_r1kh_resp_frame -frame_type src/ap/wpa_auth.h /^ u8 frame_type; \/* RSN_REMOTE_FRAME_TYPE_FT_RRB *\/$/;" m struct:ft_rrb_frame -free src/eap_peer/eap_i.h /^ void (*free)(struct eap_method *method);$/;" m struct:eap_method -friendly_name src/ap/ap_config.h /^ char *friendly_name;$/;" m struct:hostapd_bss_config -friendly_name src/wps/wps.h /^ const char *friendly_name;$/;" m struct:wps_event_data::wps_event_er_ap -friendly_name src/wps/wps.h /^ char *friendly_name;$/;" m struct:wps_context -ft_action_req src/common/ieee802_11_defs.h /^ } STRUCT_PACKED ft_action_req;$/;" m union:ieee80211_mgmt::__anon66::__anon76::__anon77 typeref:struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon80 -ft_action_resp src/common/ieee802_11_defs.h /^ } STRUCT_PACKED ft_action_resp;$/;" m union:ieee80211_mgmt::__anon66::__anon76::__anon77 typeref:struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon81 -ft_capab src/common/wpa_common.h /^ u8 ft_capab;$/;" m struct:rsn_mdie -ft_check_msg_2_of_4 src/ap/wpa_auth.c /^static int ICACHE_FLASH_ATTR ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,$/;" f file: -ft_completed src/ap/wpa_auth_i.h /^ unsigned int ft_completed:1;$/;" m struct:wpa_state_machine -ft_over_ds src/ap/ap_config.h /^ int ft_over_ds;$/;" m struct:hostapd_bss_config -ft_over_ds src/ap/wpa_auth.h /^ int ft_over_ds;$/;" m struct:wpa_auth_config -ft_r0kh_r1kh_pull_frame src/ap/wpa_auth.h /^struct ft_r0kh_r1kh_pull_frame {$/;" s -ft_r0kh_r1kh_push_frame src/ap/wpa_auth.h /^struct ft_r0kh_r1kh_push_frame {$/;" s -ft_r0kh_r1kh_resp_frame src/ap/wpa_auth.h /^struct ft_r0kh_r1kh_resp_frame {$/;" s -ft_remote_r0kh src/ap/wpa_auth.h /^struct ft_remote_r0kh {$/;" s -ft_remote_r1kh src/ap/wpa_auth.h /^struct ft_remote_r1kh {$/;" s -ft_rrb_frame src/ap/wpa_auth.h /^struct ft_rrb_frame {$/;" s -ftie src/ap/wpa_auth_ie.h /^ const u8 *ftie;$/;" m struct:wpa_eapol_ie_parse -ftie src/rsn_supp/wpa_ie.h /^ const u8 *ftie;$/;" m struct:wpa_eapol_ie_parse -ftie_len src/ap/wpa_auth_ie.h /^ size_t ftie_len;$/;" m struct:wpa_eapol_ie_parse -ftie_len src/rsn_supp/wpa_ie.h /^ size_t ftie_len;$/;" m struct:wpa_eapol_ie_parse -full_dynamic_vlan src/ap/hostapd.h /^ struct full_dynamic_vlan *full_dynamic_vlan;$/;" m struct:hostapd_data typeref:struct:hostapd_data::full_dynamic_vlan -gEapSm src/esp_supplicant/esp_wpa_enterprise.c /^static struct eap_sm *gEapSm = NULL;$/;" v typeref:struct:eap_sm file: -gWpaSm src/rsn_supp/wpa.c /^ struct wpa_sm gWpaSm;$/;" v typeref:struct:wpa_sm -gWpsSm src/esp_supplicant/esp_wps.c /^struct wps_sm *gWpsSm = NULL;$/;" v typeref:struct:wps_sm -g_wifi_wpa2_sync_sem src/esp_supplicant/esp_wpa_enterprise.c /^static void *g_wifi_wpa2_sync_sem = NULL;$/;" v file: -g_wpa2_api_lock src/esp_supplicant/esp_wpa_enterprise.c /^static void *g_wpa2_api_lock = NULL;$/;" v file: -g_wpa2_state src/esp_supplicant/esp_wpa_enterprise.c /^static wpa2_state_t g_wpa2_state = WPA2_STATE_DISABLED;$/;" v file: -g_wpa_anonymous_identity src/eap_peer/eap.h /^u8 *g_wpa_anonymous_identity;$/;" v -g_wpa_anonymous_identity_len src/eap_peer/eap.h /^int g_wpa_anonymous_identity_len;$/;" v -g_wpa_ca_cert src/eap_peer/eap.h /^const u8 *g_wpa_ca_cert;$/;" v -g_wpa_ca_cert_len src/eap_peer/eap.h /^int g_wpa_ca_cert_len;$/;" v -g_wpa_client_cert src/eap_peer/eap.h /^const u8 *g_wpa_client_cert;$/;" v -g_wpa_client_cert_len src/eap_peer/eap.h /^int g_wpa_client_cert_len;$/;" v -g_wpa_new_password src/eap_peer/eap.h /^u8 *g_wpa_new_password;$/;" v -g_wpa_new_password_len src/eap_peer/eap.h /^int g_wpa_new_password_len;$/;" v -g_wpa_password src/eap_peer/eap.h /^u8 *g_wpa_password;$/;" v -g_wpa_password_len src/eap_peer/eap.h /^int g_wpa_password_len;$/;" v -g_wpa_private_key src/eap_peer/eap.h /^const u8 *g_wpa_private_key;$/;" v -g_wpa_private_key_len src/eap_peer/eap.h /^int g_wpa_private_key_len;$/;" v -g_wpa_private_key_passwd src/eap_peer/eap.h /^const u8 *g_wpa_private_key_passwd;$/;" v -g_wpa_private_key_passwd_len src/eap_peer/eap.h /^int g_wpa_private_key_passwd_len;$/;" v -g_wpa_username src/eap_peer/eap.h /^u8 *g_wpa_username;$/;" v -g_wpa_username_len src/eap_peer/eap.h /^int g_wpa_username_len;$/;" v -gas_dialog src/ap/sta_info.h /^ struct gas_dialog_info *gas_dialog;$/;" m struct:sta_info typeref:struct:sta_info::gas_dialog_info -gas_dialog_next src/ap/sta_info.h /^ u8 gas_dialog_next;$/;" m struct:sta_info -gas_frag_limit src/ap/hostapd.h /^ size_t gas_frag_limit;$/;" m struct:hostapd_data -gd src/rsn_supp/wpa.h /^ struct wpa_gtk_data gd; \/\/used for calllback save param$/;" m struct:wpa_sm typeref:struct:wpa_sm::wpa_gtk_data -generate_authenticator_response src/crypto/ms_funcs.c /^int generate_authenticator_response(const u8 *password, size_t password_len,$/;" f -generate_authenticator_response_pwhash src/crypto/ms_funcs.c /^int generate_authenticator_response_pwhash($/;" f -generate_nt_response src/crypto/ms_funcs.c /^int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,$/;" f -generate_nt_response_pwhash src/crypto/ms_funcs.c /^int generate_nt_response_pwhash(const u8 *auth_challenge,$/;" f -generator include/crypto/dh_groups.h /^ const u8 *generator;$/;" m struct:dh_group -generator_len include/crypto/dh_groups.h /^ size_t generator_len;$/;" m struct:dh_group -get src/utils/ext_password_i.h /^ struct wpabuf * (*get)(void *ctx, const char *name);$/;" m struct:ext_password_backend typeref:struct:ext_password_backend::get -getKey src/eap_peer/eap_i.h /^ u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len);$/;" m struct:eap_method -getSessionId src/eap_peer/eap_i.h /^ u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len);$/;" m struct:eap_method -get_asymetric_start_key src/crypto/ms_funcs.c /^int get_asymetric_start_key(const u8 *master_key, u8 *session_key,$/;" f -get_eapol src/ap/wpa_auth.h /^ int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);$/;" m struct:wpa_auth_callbacks -get_identity src/eap_peer/eap_i.h /^ const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len);$/;" m struct:eap_method -get_master_key src/crypto/ms_funcs.c /^int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,$/;" f -get_msk src/ap/wpa_auth.h /^ int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);$/;" m struct:wpa_auth_callbacks -get_ppkey src/rsn_supp/wpa.h /^ int (*get_ppkey) (uint8_t *ifx, int *alg, uint8_t *addr, int *key_idx,$/;" m struct:wpa_sm -get_psk src/ap/wpa_auth.h /^ const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *prev_psk);$/;" m struct:wpa_auth_callbacks -get_seqnum src/ap/wpa_auth.h /^ int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq);$/;" m struct:wpa_auth_callbacks -get_status src/eap_peer/eap_i.h /^ int (*get_status)(struct eap_sm *sm, void *priv, char *buf,$/;" m struct:eap_method -gl_disable_time_check src/esp_supplicant/esp_wpa_enterprise.c /^static bool gl_disable_time_check = true;$/;" v file: -global_ctrl_sock src/ap/hostapd.h /^ int global_ctrl_sock;$/;" m struct:hapd_interfaces -global_iface_name src/ap/hostapd.h /^ char *global_iface_name;$/;" m struct:hapd_interfaces -global_iface_path src/ap/hostapd.h /^ char *global_iface_path;$/;" m struct:hapd_interfaces -group src/ap/ap_config.h /^ int group;$/;" m struct:hostapd_wpa_psk -group src/ap/wpa_auth_i.h /^ struct wpa_group *group;$/;" m struct:wpa_authenticator typeref:struct:wpa_authenticator::wpa_group -group src/ap/wpa_auth_i.h /^ struct wpa_group *group;$/;" m struct:wpa_state_machine typeref:struct:wpa_state_machine::wpa_group -group src/crypto/crypto_mbedtls.c /^ mbedtls_ecp_group group;$/;" m struct:crypto_ec file: -group_cipher src/common/wpa_common.h /^ int group_cipher;$/;" m struct:wpa_ie_data -group_cipher src/rsn_supp/wpa.h /^ unsigned int group_cipher;$/;" m struct:wpa_sm -gtk src/ap/wpa_auth_ie.h /^ const u8 *gtk;$/;" m struct:wpa_eapol_ie_parse -gtk src/common/wpa_common.h /^ u8 gtk[32];$/;" m struct:wpa_gtk_data -gtk src/rsn_supp/wpa_ie.h /^ const u8 *gtk;$/;" m struct:wpa_eapol_ie_parse -gtk_len src/ap/wpa_auth_ie.h /^ size_t gtk_len;$/;" m struct:wpa_eapol_ie_parse -gtk_len src/common/wpa_common.h /^ int gtk_len;$/;" m struct:wpa_gtk_data -gtk_len src/rsn_supp/wpa_ie.h /^ size_t gtk_len;$/;" m struct:wpa_eapol_ie_parse -h_dest src/rsn_supp/wpa.h /^ u8 h_dest[ETH_ALEN];$/;" m struct:l2_ethhdr -h_proto src/rsn_supp/wpa.h /^ be16 h_proto;$/;" m struct:l2_ethhdr -h_source src/rsn_supp/wpa.h /^ u8 h_source[ETH_ALEN];$/;" m struct:l2_ethhdr -hapd_interfaces src/ap/hostapd.h /^struct hapd_interfaces {$/;" s -has_GTK src/ap/wpa_auth_i.h /^ Boolean has_GTK;$/;" m struct:wpa_state_machine -has_reauth_data src/eap_peer/eap_i.h /^ bool (*has_reauth_data)(struct eap_sm *sm, void *priv);$/;" m struct:eap_method -hash src/tls/tls.h /^ const u8 *hash;$/;" m struct:tls_event_data::__anon35 -hash src/tls/tlsv1_common.h /^ tls_hash hash;$/;" m struct:tls_cipher_suite -hash_alg src/tls/tlsv1_record.h /^ enum crypto_hash_alg hash_alg;$/;" m struct:tlsv1_record_layer typeref:enum:tlsv1_record_layer::crypto_hash_alg -hash_len src/tls/tls.h /^ size_t hash_len;$/;" m struct:tls_event_data::__anon35 -hash_nt_password_hash src/crypto/ms_funcs.c /^int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)$/;" f -hash_size src/tls/tlsv1_record.h /^ size_t hash_size;$/;" m struct:tlsv1_record_layer -hex2byte src/utils/common.c /^int hex2byte(const char *hex)$/;" f -hex2num src/utils/common.c /^static int hex2num(char c)$/;" f file: -hexstr2bin src/utils/common.c /^int hexstr2bin(const char *hex, u8 *buf, size_t len)$/;" f -hmac_md5 src/crypto/md5.c /^hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,$/;" f -hmac_md5_non_fips_allow include/crypto/md5.h 32;" d -hmac_md5_vector src/crypto/md5.c /^hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,$/;" f -hmac_md5_vector_non_fips_allow include/crypto/md5.h 31;" d -hmac_sha1 src/crypto/sha1.c /^hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,$/;" f -hmac_sha1_vector src/crypto/sha1.c /^hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,$/;" f -hmac_sha256 src/crypto/sha256.c /^hmac_sha256(const u8 *key, size_t key_len, const u8 *data,$/;" f -hmac_sha256_vector src/crypto/sha256.c /^hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,$/;" f -hnext src/ap/sta_info.h /^ struct sta_info *hnext; \/* next entry in hash table list *\/$/;" m struct:sta_info typeref:struct:sta_info::sta_info -host_to_be16 include/utils/common.h 107;" d -host_to_be16 include/utils/common.h 66;" d -host_to_be16 include/utils/common.h 94;" d -host_to_be32 include/utils/common.h 110;" d -host_to_be32 include/utils/common.h 69;" d -host_to_be32 include/utils/common.h 98;" d -host_to_be64 include/utils/common.h 102;" d -host_to_be64 include/utils/common.h 114;" d -host_to_le16 include/utils/common.h 105;" d -host_to_le16 include/utils/common.h 64;" d -host_to_le16 include/utils/common.h 92;" d -host_to_le32 include/utils/common.h 96;" d -host_to_le64 include/utils/common.h 100;" d -host_to_le64 include/utils/common.h 112;" d -hostap_deinit src/esp_supplicant/esp_hostap.c /^bool hostap_deinit(void *data)$/;" f -hostap_eapol_resend_process src/ap/wpa_auth.c /^void hostap_eapol_resend_process(void *timeout_ctx)$/;" f -hostap_init src/esp_supplicant/esp_hostap.c /^void* hostap_init(void)$/;" f -hostap_security_policy src/ap/ap_config.h /^typedef enum hostap_security_policy {$/;" g -hostapd_bss_config src/ap/ap_config.h /^struct hostapd_bss_config {$/;" s -hostapd_config src/ap/ap_config.h /^struct hostapd_config {$/;" s -hostapd_config_defaults src/ap/ap_config.c /^struct hostapd_config * hostapd_config_defaults(void)$/;" f -hostapd_config_defaults_bss src/ap/ap_config.c /^void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)$/;" f -hostapd_data src/ap/hostapd.h /^struct hostapd_data {$/;" s -hostapd_derive_psk src/ap/ap_config.c /^static int hostapd_derive_psk(struct hostapd_ssid *ssid)$/;" f file: -hostapd_frame_info src/ap/hostapd.h /^struct hostapd_frame_info {$/;" s -hostapd_get_psk src/ap/ap_config.c /^const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,$/;" f -hostapd_hw_mode src/common/defs.h /^enum hostapd_hw_mode {$/;" g -hostapd_mac_comp src/ap/ap_config.c /^int hostapd_mac_comp(const void *a, const void *b)$/;" f -hostapd_mac_comp_empty src/ap/ap_config.c /^int hostapd_mac_comp_empty(const void *a)$/;" f -hostapd_maclist_found src/ap/ap_config.c /^int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,$/;" f -hostapd_probereq_cb src/ap/hostapd.h /^struct hostapd_probereq_cb {$/;" s -hostapd_rate_data src/ap/hostapd.h /^struct hostapd_rate_data {$/;" s -hostapd_rate_found src/ap/ap_config.c /^int hostapd_rate_found(int *list, int rate)$/;" f -hostapd_setup_wpa_psk src/ap/ap_config.c /^int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)$/;" f -hostapd_ssid src/ap/ap_config.h /^struct hostapd_ssid {$/;" s -hostapd_sta_wpa_psk_short src/ap/ap_config.h /^struct hostapd_sta_wpa_psk_short {$/;" s -hostapd_wep_key_cmp src/ap/ap_config.c /^int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, struct hostapd_wep_keys *b)$/;" f -hostapd_wep_keys src/ap/ap_config.h /^struct hostapd_wep_keys {$/;" s -hostapd_wpa_psk src/ap/ap_config.h /^struct hostapd_wpa_psk {$/;" s -hs20 src/ap/ap_config.h /^ int hs20;$/;" m struct:hostapd_bss_config -hs20_connection_capability src/ap/ap_config.h /^ u8 *hs20_connection_capability;$/;" m struct:hostapd_bss_config -hs20_connection_capability_len src/ap/ap_config.h /^ size_t hs20_connection_capability_len;$/;" m struct:hostapd_bss_config -hs20_oper_friendly_name src/ap/ap_config.h /^ struct hostapd_lang_string *hs20_oper_friendly_name;$/;" m struct:hostapd_bss_config typeref:struct:hostapd_bss_config::hostapd_lang_string -hs20_oper_friendly_name_count src/ap/ap_config.h /^ unsigned int hs20_oper_friendly_name_count;$/;" m struct:hostapd_bss_config -hs20_operating_class src/ap/ap_config.h /^ u8 *hs20_operating_class;$/;" m struct:hostapd_bss_config -hs20_operating_class_len src/ap/ap_config.h /^ u8 hs20_operating_class_len;$/;" m struct:hostapd_bss_config -hs20_wan_metrics src/ap/ap_config.h /^ u8 *hs20_wan_metrics;$/;" m struct:hostapd_bss_config -ht_capab src/ap/ap_config.h /^ u16 ht_capab;$/;" m struct:hostapd_config -ht_capabilities_info src/common/ieee802_11_defs.h /^ le16 ht_capabilities_info;$/;" m struct:ieee80211_ht_capabilities -ht_extended_capabilities src/common/ieee802_11_defs.h /^ le16 ht_extended_capabilities;$/;" m struct:ieee80211_ht_capabilities -ht_op_mode_fixed src/ap/ap_config.h /^ int ht_op_mode_fixed;$/;" m struct:hostapd_config -ht_param src/common/ieee802_11_defs.h /^ u8 ht_param;$/;" m struct:ieee80211_ht_operation -htobe16 port/include/endian.h 102;" d -htobe16 port/include/endian.h 87;" d -htobe32 port/include/endian.h 103;" d -htobe32 port/include/endian.h 88;" d -htobe64 port/include/endian.h 104;" d -htobe64 port/include/endian.h 89;" d -htole16 port/include/endian.h 105;" d -htole16 port/include/endian.h 90;" d -htole32 port/include/endian.h 106;" d -htole32 port/include/endian.h 91;" d -htole64 port/include/endian.h 107;" d -htole64 port/include/endian.h 92;" d -hw_mode src/ap/ap_config.h /^ enum hostapd_hw_mode hw_mode; \/* HOSTAPD_MODE_IEEE80211A, .. *\/$/;" m struct:hostapd_config typeref:enum:hostapd_config::hostapd_hw_mode -ic_cipher src/esp_supplicant/esp_wifi_driver.h /^ u_int ic_cipher; \/* WIFI_CIPHER_* *\/$/;" m struct:wifi_cipher -ic_decap src/esp_supplicant/esp_wifi_driver.h /^ int (*ic_decap)(struct wifi_key *, void *, int);$/;" m struct:wifi_cipher -ic_encap src/esp_supplicant/esp_wifi_driver.h /^ int (*ic_encap)(struct wifi_key *, void *, uint8_t);$/;" m struct:wifi_cipher -ic_header src/esp_supplicant/esp_wifi_driver.h /^ u_int ic_header; \/* size of privacy header (bytes) *\/$/;" m struct:wifi_cipher -ic_miclen src/esp_supplicant/esp_wifi_driver.h /^ u_int ic_miclen; \/* size of mic trailer (bytes) *\/$/;" m struct:wifi_cipher -ic_trailer src/esp_supplicant/esp_wifi_driver.h /^ u_int ic_trailer; \/* size of privacy trailer (bytes) *\/$/;" m struct:wifi_cipher -iconf src/ap/hostapd.h /^ struct hostapd_config *iconf;$/;" m struct:hostapd_data typeref:struct:hostapd_data::hostapd_config -id include/crypto/dh_groups.h /^ int id;$/;" m struct:dh_group -id src/ap/wpa_auth.h /^ u8 id[FT_R0KH_ID_MAX_LEN];$/;" m struct:ft_remote_r0kh -id src/ap/wpa_auth.h /^ u8 id[FT_R1KH_ID_LEN];$/;" m struct:ft_remote_r1kh -id src/common/wpa_common.h /^ u8 id;$/;" m struct:rsn_rdie -id_len src/ap/wpa_auth.h /^ size_t id_len;$/;" m struct:ft_remote_r0kh -id_len src/eap_peer/eap_peap.c /^ size_t id_len;$/;" m struct:eap_peap_data file: -id_len src/eap_peer/eap_tls.c /^ size_t id_len;$/;" m struct:eap_tls_data file: -id_len src/eap_peer/eap_ttls.c /^ size_t id_len;$/;" m struct:eap_ttls_data file: -ident src/eap_peer/eap_ttls.c /^ u8 ident;$/;" m struct:eap_ttls_data file: -identifier src/eap_peer/eap_defs.h /^ u8 identifier;$/;" m struct:eap_hdr -identifier src/tls/asn1.h /^ u8 identifier, class, constructed;$/;" m struct:asn1_hdr -identity src/eap_peer/eap_config.h /^ u8 *identity;$/;" m struct:eap_peer_config -identity src/wps/wps.h /^ char identity[32];$/;" m struct:wps_sm -identity_len src/eap_peer/eap_config.h /^ size_t identity_len;$/;" m struct:eap_peer_config -identity_len src/wps/wps.h /^ u8 identity_len;$/;" m struct:wps_sm -idx src/ap/ap_config.h /^ u8 idx;$/;" m struct:hostapd_wep_keys -ie_data src/esp_supplicant/esp_wifi_driver.h /^ uint8_t ie_data[];$/;" m struct:wifi_appie -ie_len src/esp_supplicant/esp_wifi_driver.h /^ uint16_t ie_len;$/;" m struct:wifi_appie -ieee80211_hdr src/common/ieee802_11_defs.h /^struct ieee80211_hdr {$/;" s -ieee80211_ht_capabilities src/common/ieee802_11_defs.h /^struct ieee80211_ht_capabilities {$/;" s -ieee80211_ht_operation src/common/ieee802_11_defs.h /^struct ieee80211_ht_operation {$/;" s -ieee80211_mgmt src/common/ieee802_11_defs.h /^struct ieee80211_mgmt {$/;" s -ieee80211ac src/ap/ap_config.h /^ int ieee80211ac;$/;" m struct:hostapd_config -ieee80211d src/ap/ap_config.h /^ int ieee80211d;$/;" m struct:hostapd_config -ieee80211n src/ap/ap_config.h /^ int ieee80211n;$/;" m struct:hostapd_config -ieee80211w src/ap/ap_config.h /^ enum mfp_options ieee80211w;$/;" m struct:hostapd_bss_config typeref:enum:hostapd_bss_config::mfp_options -ieee80211w src/ap/wpa_auth.h /^ enum mfp_options ieee80211w;$/;" m struct:wpa_auth_config typeref:enum:wpa_auth_config::mfp_options -ieee80211w_kde_add src/ap/wpa_auth.c /^static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)$/;" f file: -ieee80211w_kde_len src/ap/wpa_auth.c /^static int ieee80211w_kde_len(struct wpa_state_machine *sm)$/;" f file: -ieee80211w_set_keys src/rsn_supp/wpa.c /^int ieee80211w_set_keys(struct wpa_sm *sm,$/;" f -ieee802_1x src/ap/ap_config.h /^ int ieee802_1x; \/* use IEEE 802.1X *\/$/;" m struct:hostapd_bss_config -ieee802_1x_eapol_key src/common/eapol_common.h /^struct ieee802_1x_eapol_key {$/;" s -ieee802_1x_hdr src/common/eapol_common.h /^struct ieee802_1x_hdr {$/;" s -ieee802_1x_receive src/ap/ieee802_1x.c /^void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,$/;" f -iface src/ap/hostapd.h /^ struct hostapd_iface **iface;$/;" m struct:hapd_interfaces typeref:struct:hapd_interfaces::hostapd_iface -ignore src/eap_peer/eap_i.h /^ Boolean ignore;$/;" m struct:eap_method_ret -ignore_broadcast_ssid src/ap/ap_config.h /^ int ignore_broadcast_ssid;$/;" m struct:hostapd_bss_config -ignore_sel_reg src/wps/wps.h /^ bool ignore_sel_reg;$/;" m struct:wps_sm -igtk src/ap/wpa_auth_ie.h /^ const u8 *igtk;$/;" m struct:wpa_eapol_ie_parse -igtk src/common/wpa_common.h /^ u8 igtk[WPA_IGTK_LEN];$/;" m struct:wpa_igtk_kde -igtk src/rsn_supp/wpa_ie.h /^ const u8 *igtk;$/;" m struct:wpa_eapol_ie_parse -igtk_len src/ap/wpa_auth_ie.h /^ size_t igtk_len;$/;" m struct:wpa_eapol_ie_parse -igtk_len src/rsn_supp/wpa_ie.h /^ size_t igtk_len;$/;" m struct:wpa_eapol_ie_parse -in src/crypto/md5_i.h /^ u8 in[64];$/;" m struct:MD5Context -in_step_loop src/ap/wpa_auth_i.h /^ unsigned int in_step_loop:1;$/;" m struct:wpa_state_machine -inactivity_interval src/common/ieee802_11_defs.h /^ le32 inactivity_interval;$/;" m struct:wmm_tspec_element -inc_byte_array src/utils/common.c /^void inc_byte_array(u8 *counter, size_t len)$/;" f -include_tls_length src/eap_peer/eap_tls_common.h /^ int include_tls_length;$/;" m struct:eap_ssl_data -index src/ap/wpa_auth_i.h /^ u32 index;$/;" m struct:wpa_state_machine -init src/eap_peer/eap_i.h /^ void * (*init)(struct eap_sm *sm);$/;" m struct:eap_method -init src/utils/ext_password_i.h /^ void * (*init)(const char *params);$/;" m struct:ext_password_backend -init_for_reauth src/eap_peer/eap_i.h /^ void * (*init_for_reauth)(struct eap_sm *sm, void *priv);$/;" m struct:eap_method -init_phase2 src/eap_peer/eap_i.h /^ int init_phase2;$/;" m struct:eap_sm -initiator src/ap/wpa_auth_i.h /^ u8 initiator[ETH_ALEN];$/;" m struct:wpa_stsl_negotiation -inline include/utils/common.h 228;" d -inline include/utils/common.h 230;" d -install_gtk src/rsn_supp/wpa.h /^ struct install_key install_gtk;$/;" m struct:wpa_sm typeref:struct:wpa_sm::install_key -install_key src/rsn_supp/wpa.h /^struct install_key {$/;" s -install_ppkey src/rsn_supp/wpa.h /^ void (*install_ppkey) (enum wpa_alg alg, u8 *addr, int key_idx, int set_tx,$/;" m struct:wpa_sm -install_ptk src/rsn_supp/wpa.h /^ struct install_key install_ptk;$/;" m struct:wpa_sm typeref:struct:wpa_sm::install_key -int_reg src/wps/wps_i.h /^ int int_reg;$/;" m struct:wps_data -interface_added src/ap/hostapd.h /^ int interface_added; \/* virtual interface added for this BSS *\/$/;" m struct:hostapd_data -ip src/tls/x509v3.h /^ u8 *ip; \/* iPAddress *\/$/;" m struct:x509_name -ip_len src/tls/x509v3.h /^ size_t ip_len; \/* IPv4: 4, IPv6: 16 *\/$/;" m struct:x509_name -ipmk src/eap_peer/eap_peap.c /^ u8 ipmk[40];$/;" m struct:eap_peap_data file: -iqmp src/tls/rsa.c /^ struct bignum *iqmp; \/* 1 \/ q mod p; CRT coefficient *\/$/;" m struct:crypto_rsa_key typeref:struct:crypto_rsa_key::bignum file: -isKeyAvailable src/eap_peer/eap_i.h /^ bool (*isKeyAvailable)(struct eap_sm *sm, void *priv);$/;" m struct:eap_method -is_local src/tls/tls.h /^ int is_local;$/;" m struct:tls_event_data::__anon36 -is_nil_uuid src/utils/uuid.c /^int is_nil_uuid(const u8 *uuid)$/;" f -is_selected_pin_registrar src/wps/wps.c /^static int is_selected_pin_registrar(struct wps_parse_attr *attr, u8 *bssid)$/;" f file: -is_wnmsleep src/ap/wpa_auth_i.h /^ unsigned int is_wnmsleep:1;$/;" m struct:wpa_state_machine -is_wps_scan src/wps/wps.h /^ bool is_wps_scan;$/;" m struct:wps_sm -is_zero_ether_addr include/utils/common.h /^static inline int is_zero_ether_addr(const u8 *a)$/;" f -issuer src/tls/x509v3.h /^ struct x509_name issuer;$/;" m struct:x509_certificate typeref:struct:x509_certificate::x509_name -iter_count src/tls/pkcs5.c /^ unsigned int iter_count;$/;" m struct:pkcs5_params file: -iv_size src/tls/tlsv1_record.h /^ size_t iv_size; \/* also block_size *\/$/;" m struct:tlsv1_record_layer -kck src/common/wpa_common.h /^ u8 kck[16]; \/* EAPOL-Key Key Confirmation Key (KCK) *\/$/;" m struct:wpa_ptk -kek src/common/wpa_common.h /^ u8 kek[16]; \/* EAPOL-Key Key Encryption Key (KEK) *\/$/;" m struct:wpa_ptk -key src/ap/ap_config.h /^ u8 *key[NUM_WEP_KEYS];$/;" m struct:hostapd_wep_keys -key src/ap/wpa_auth.h /^ u8 key[16];$/;" m struct:ft_remote_r0kh -key src/ap/wpa_auth.h /^ u8 key[16];$/;" m struct:ft_remote_r1kh -key src/crypto/crypto_internal-cipher.c /^ struct des3_key_s key;$/;" m struct:crypto_cipher::__anon10::__anon13 typeref:struct:crypto_cipher::__anon10::__anon13::des3_key_s file: -key src/crypto/crypto_internal-cipher.c /^ u8 key[16];$/;" m struct:crypto_cipher::__anon10::__anon11 file: -key src/crypto/crypto_internal.c /^ u8 key[64];$/;" m struct:crypto_hash file: -key src/fast_crypto/fast_crypto_internal-cipher.c /^ struct des3_key_s key;$/;" m struct:fast_crypto_cipher::__anon56::__anon59 typeref:struct:fast_crypto_cipher::__anon56::__anon59::des3_key_s file: -key src/fast_crypto/fast_crypto_internal-cipher.c /^ uint8_t key[16];$/;" m struct:fast_crypto_cipher::__anon56::__anon57 file: -key src/fast_crypto/fast_crypto_internal.c /^ u8 key[64];$/;" m struct:fast_crypto_hash file: -key src/rsn_supp/wpa.h /^ u8 key[32];$/;" m struct:install_key -key src/tls/tlsv1_cred.h /^ struct crypto_private_key *key;$/;" m struct:tlsv1_credentials typeref:struct:tlsv1_credentials::crypto_private_key -key src/wps/wps.h /^ u8 key[64];$/;" m struct:wps_credential -key src/wps/wps.h /^ char key[64];$/;" m struct:wps_sm -key_data src/eap_peer/eap_peap.c /^ u8 *key_data;$/;" m struct:eap_peap_data file: -key_data src/eap_peer/eap_tls.c /^ u8 *key_data;$/;" m struct:eap_tls_data file: -key_data src/eap_peer/eap_ttls.c /^ u8 *key_data;$/;" m struct:eap_ttls_data file: -key_data_length src/common/wpa_common.h /^ u8 key_data_length[2]; \/* big endian *\/$/;" m struct:wpa_eapol_key -key_entry_valid src/rsn_supp/wpa.h /^ int key_entry_valid; \/\/present current avaliable entry for bssid, for pairkey:0,5,10,15,20, gtk: pairkey_no+i (i:1~4)$/;" m struct:wpa_sm -key_exchange src/tls/tlsv1_common.h /^ tls_key_exchange key_exchange;$/;" m struct:tls_cipher_suite -key_id src/common/wpa_common.h /^ u8 key_id[8]; \/* Reserved in IEEE 802.11i\/RSN *\/$/;" m struct:wpa_eapol_key -key_id src/tls/tls.h /^ const char *key_id;$/;" m struct:tls_connection_params -key_idx src/rsn_supp/wpa.h /^ int key_idx;$/;" m struct:install_key -key_idx src/wps/wps.h /^ u8 key_idx;$/;" m struct:wps_credential -key_index src/common/eapol_common.h /^ u8 key_index; \/* key flag in the most significant bit:$/;" m struct:ieee802_1x_eapol_key -key_info src/common/wpa_common.h /^ u8 key_info[2]; \/* big endian *\/$/;" m struct:wpa_eapol_key -key_info src/rsn_supp/wpa.h /^ u16 key_info; \/\/used for txcallback param $/;" m struct:wpa_sm -key_install src/rsn_supp/wpa.h /^ bool key_install;$/;" m struct:wpa_sm -key_iv src/common/eapol_common.h /^ u8 key_iv[IEEE8021X_KEY_IV_LEN]; \/* cryptographically random number *\/$/;" m struct:ieee802_1x_eapol_key -key_iv src/common/wpa_common.h /^ u8 key_iv[16];$/;" m struct:wpa_eapol_key -key_len src/crypto/crypto_internal.c /^ size_t key_len;$/;" m struct:crypto_hash file: -key_len src/fast_crypto/fast_crypto_internal.c /^ size_t key_len;$/;" m struct:fast_crypto_hash file: -key_len src/wps/wps.h /^ size_t key_len;$/;" m struct:wps_credential -key_len src/wps/wps.h /^ u8 key_len;$/;" m struct:wps_sm -key_length src/common/eapol_common.h /^ u8 key_length[2];$/;" m struct:ieee802_1x_eapol_key -key_length src/common/wpa_common.h /^ u8 key_length[2]; \/* big endian *\/$/;" m struct:wpa_eapol_key -key_lifetime src/rsn_supp/wpa_ie.h /^ const u8 *key_lifetime;$/;" m struct:wpa_eapol_ie_parse -key_material src/tls/tlsv1_common.h /^ size_t key_material;$/;" m struct:tls_cipher_data -key_material_len src/tls/tlsv1_record.h /^ size_t key_material_len;$/;" m struct:tlsv1_record_layer -key_mgmt src/common/wpa_common.h /^ int key_mgmt;$/;" m struct:wpa_ie_data -key_mgmt src/rsn_supp/wpa.h /^ unsigned int key_mgmt;$/;" m struct:wpa_sm -key_mic src/common/wpa_common.h /^ u8 key_mic[16];$/;" m struct:wpa_eapol_key -key_nonce src/common/wpa_common.h /^ u8 key_nonce[WPA_NONCE_LEN];$/;" m struct:wpa_eapol_key -key_prov_auto src/wps/wps_attr_parse.h /^ const u8 *key_prov_auto; \/* 1 octet (Bool) *\/$/;" m struct:wps_parse_attr -key_replay src/ap/wpa_auth_i.h /^ } key_replay[RSNA_MAX_EAPOL_RETRIES],$/;" m struct:wpa_state_machine typeref:struct:wpa_state_machine::wpa_key_replay_counter -key_rsc src/common/wpa_common.h /^ u8 key_rsc[WPA_KEY_RSC_LEN];$/;" m struct:wpa_eapol_key -key_rsc_len src/common/wpa_common.h /^ int tx, key_rsc_len, keyidx;$/;" m struct:wpa_gtk_data -key_signature src/common/eapol_common.h /^ u8 key_signature[IEEE8021X_KEY_SIGN_LEN];$/;" m struct:ieee802_1x_eapol_key -key_usage src/tls/x509v3.h /^ unsigned long key_usage;$/;" m struct:x509_certificate -key_wrap_auth src/wps/wps_attr_parse.h /^ const u8 *key_wrap_auth; \/* WPS_KWA_LEN (8) octets *\/$/;" m struct:wps_parse_attr -key_wrap_extra src/ap/wpa_auth.h /^ u8 key_wrap_extra[8];$/;" m struct:ft_r0kh_r1kh_pull_frame -key_wrap_extra src/ap/wpa_auth.h /^ u8 key_wrap_extra[8];$/;" m struct:ft_r0kh_r1kh_push_frame -key_wrap_extra src/ap/wpa_auth.h /^ u8 key_wrap_extra[8];$/;" m struct:ft_r0kh_r1kh_resp_frame -keycount src/ap/wpa_auth_i.h /^ int keycount;$/;" m struct:wpa_state_machine -keyid src/common/wpa_common.h /^ u8 keyid[2];$/;" m struct:wpa_igtk_kde -keyidx src/common/wpa_common.h /^ int tx, key_rsc_len, keyidx;$/;" m struct:wpa_gtk_data -keylen src/crypto/crypto_internal-cipher.c /^ size_t keylen;$/;" m struct:crypto_cipher::__anon10::__anon11 file: -keylen src/fast_crypto/fast_crypto_internal-cipher.c /^ size_t keylen;$/;" m struct:fast_crypto_cipher::__anon56::__anon57 file: -keys_cleared src/rsn_supp/wpa.h /^ int keys_cleared;$/;" m struct:install_key -keys_set src/ap/ap_config.h /^ int keys_set;$/;" m struct:hostapd_wep_keys -keywrapkey src/wps/wps_i.h /^ u8 keywrapkey[WPS_KEYWRAPKEY_LEN];$/;" m struct:wps_data -l2_ethhdr src/rsn_supp/wpa.h /^struct l2_ethhdr {$/;" s -lastRespData src/eap_peer/eap_i.h /^ struct wpabuf *lastRespData;$/;" m struct:eap_sm typeref:struct:eap_sm::wpabuf -last_bss src/ap/ap_config.h /^ struct hostapd_bss_config *bss, *last_bss;$/;" m struct:hostapd_config typeref:struct:hostapd_config:: -last_msg src/wps/wps_i.h /^ struct wpabuf *last_msg;$/;" m struct:wps_data typeref:struct:wps_data::wpabuf -last_rx_eapol_key src/ap/wpa_auth_i.h /^ u8 *last_rx_eapol_key; \/* starting from IEEE 802.1X header *\/$/;" m struct:wpa_state_machine -last_rx_eapol_key_len src/ap/wpa_auth_i.h /^ size_t last_rx_eapol_key_len;$/;" m struct:wpa_state_machine -le16 include/utils/common.h /^typedef u16 __bitwise le16;$/;" t -le16dec port/include/endian.h /^le16dec(const void *pp)$/;" f -le16enc port/include/endian.h /^le16enc(void *pp, uint16_t u)$/;" f -le16toh port/include/endian.h 112;" d -le16toh port/include/endian.h 97;" d -le32 include/utils/common.h /^typedef u32 __bitwise le32;$/;" t -le32dec port/include/endian.h /^le32dec(const void *pp)$/;" f -le32enc port/include/endian.h /^le32enc(void *pp, uint32_t u)$/;" f -le32toh port/include/endian.h 113;" d -le32toh port/include/endian.h 98;" d -le64 include/utils/common.h /^typedef u64 __bitwise le64;$/;" t -le64dec port/include/endian.h /^le64dec(const void *pp)$/;" f -le64enc port/include/endian.h /^le64enc(void *pp, uint64_t u)$/;" f -le64toh port/include/endian.h 114;" d -le64toh port/include/endian.h 99;" d -le_to_host16 include/utils/common.h 104;" d -le_to_host16 include/utils/common.h 63;" d -le_to_host16 include/utils/common.h 91;" d -le_to_host32 include/utils/common.h 108;" d -le_to_host32 include/utils/common.h 67;" d -le_to_host32 include/utils/common.h 95;" d -le_to_host64 include/utils/common.h 111;" d -le_to_host64 include/utils/common.h 99;" d -len src/ap/ap_config.h /^ size_t len[NUM_WEP_KEYS];$/;" m struct:hostapd_wep_keys -len src/common/wpa_common.h /^ u8 len;$/;" m struct:rsn_ie_hdr -len src/common/wpa_common.h /^ u8 len;$/;" m struct:wpa_ie_hdr -len src/eap_peer/eap_config.h /^ size_t len;$/;" m struct:wpa_config_blob -len src/esp_supplicant/esp_wifi_driver.h /^ int len;$/;" m struct:wifi_ssid -len src/esp_supplicant/esp_wpa_enterprise.c /^ int len;$/;" m struct:wpa2_rx_param file: -len src/esp_supplicant/esp_wps.c /^ int len;$/;" m struct:wps_rx_param file: -len src/tls/asn1.h /^ size_t len;$/;" m struct:asn1_oid -length src/common/eapol_common.h /^ be16 length;$/;" m struct:ieee802_1x_hdr -length src/common/ieee802_11_defs.h /^ u8 length;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon79 -length src/common/ieee802_11_defs.h /^ u8 length; \/* 6 + 55 = 61 *\/$/;" m struct:wmm_tspec_element -length src/crypto/sha256-internal.c /^ u64 length;$/;" m struct:sha256_state file: -length src/eap_peer/eap_defs.h /^ be16 length; \/* including code and identifier; network byte order *\/$/;" m struct:eap_hdr -length src/eap_peer/eap_tlv_common.h /^ be16 length;$/;" m struct:eap_tlv_crypto_binding_tlv -length src/eap_peer/eap_tlv_common.h /^ be16 length;$/;" m struct:eap_tlv_hdr -length src/eap_peer/eap_tlv_common.h /^ be16 length;$/;" m struct:eap_tlv_intermediate_result_tlv -length src/eap_peer/eap_tlv_common.h /^ be16 length;$/;" m struct:eap_tlv_nak_tlv -length src/eap_peer/eap_tlv_common.h /^ be16 length;$/;" m struct:eap_tlv_pac_ack_tlv -length src/eap_peer/eap_tlv_common.h /^ be16 length;$/;" m struct:eap_tlv_pac_type_tlv -length src/eap_peer/eap_tlv_common.h /^ be16 length;$/;" m struct:eap_tlv_request_action_tlv -length src/eap_peer/eap_tlv_common.h /^ be16 length;$/;" m struct:eap_tlv_result_tlv -length src/tls/asn1.h /^ unsigned int tag, length;$/;" m struct:asn1_hdr -lifetime src/ap/wpa_auth_ie.h /^ const u8 *lifetime;$/;" m struct:wpa_eapol_ie_parse -lifetime src/rsn_supp/wpa_ie.h /^ const u8 *lifetime;$/;" m struct:wpa_eapol_ie_parse -lifetime_len src/ap/wpa_auth_ie.h /^ size_t lifetime_len;$/;" m struct:wpa_eapol_ie_parse -lifetime_len src/rsn_supp/wpa_ie.h /^ size_t lifetime_len;$/;" m struct:wpa_eapol_ie_parse -list src/wps/wps_registrar.c /^ struct dl_list list;$/;" m struct:wps_nfc_pw_token typeref:struct:wps_nfc_pw_token::dl_list file: -list src/wps/wps_registrar.c /^ struct dl_list list;$/;" m struct:wps_uuid_pin typeref:struct:wps_uuid_pin::dl_list file: -listen_interval src/ap/sta_info.h /^ u16 listen_interval; \/* or beacon_int for APs *\/$/;" m struct:sta_info -listen_interval src/common/ieee802_11_defs.h /^ le16 listen_interval;$/;" m struct:ieee80211_mgmt::__anon66::__anon69 -listen_interval src/common/ieee802_11_defs.h /^ le16 listen_interval;$/;" m struct:ieee80211_mgmt::__anon66::__anon71 -logger src/ap/wpa_auth.h /^ void (*logger)(void *ctx, const u8 *addr, logger_level level,$/;" m struct:wpa_auth_callbacks -logger_level src/ap/wpa_auth.h /^} logger_level;$/;" t typeref:enum:__anon20 -m src/eap_peer/eap_i.h /^ const struct eap_method *m;$/;" m struct:eap_sm typeref:struct:eap_sm::eap_method -m1_received src/wps/wps.h /^ int m1_received;$/;" m struct:wps_event_data::wps_event_er_enrollee -m2d src/wps/wps.h /^ } m2d;$/;" m union:wps_event_data typeref:struct:wps_event_data::wps_event_m2d -mac_acl_entry src/ap/ap_config.h /^struct mac_acl_entry {$/;" s -mac_addr src/ap/wpa_auth_ie.h /^ const u8 *mac_addr;$/;" m struct:wpa_eapol_ie_parse -mac_addr src/rsn_supp/wpa_ie.h /^ const u8 *mac_addr;$/;" m struct:wpa_eapol_ie_parse -mac_addr src/wps/wps.h /^ const u8 *mac_addr;$/;" m struct:wps_event_data::wps_event_er_ap -mac_addr src/wps/wps.h /^ const u8 *mac_addr;$/;" m struct:wps_event_data::wps_event_er_enrollee -mac_addr src/wps/wps.h /^ u8 mac_addr[ETH_ALEN];$/;" m struct:wps_credential -mac_addr src/wps/wps.h /^ u8 mac_addr[ETH_ALEN];$/;" m struct:wps_device_data -mac_addr src/wps/wps_attr_parse.h /^ const u8 *mac_addr; \/* ETH_ALEN (6) octets *\/$/;" m struct:wps_parse_attr -mac_addr_e src/wps/wps_i.h /^ u8 mac_addr_e[ETH_ALEN];$/;" m struct:wps_data -mac_addr_len src/ap/wpa_auth_ie.h /^ size_t mac_addr_len;$/;" m struct:wpa_eapol_ie_parse -mac_addr_len src/rsn_supp/wpa_ie.h /^ size_t mac_addr_len;$/;" m struct:wpa_eapol_ie_parse -macaddr src/ap/ap_config.h /^typedef u8 macaddr[ETH_ALEN];$/;" t -macaddr_acl src/ap/ap_config.h /^ } macaddr_acl;$/;" m struct:hostapd_bss_config typeref:enum:hostapd_bss_config::__anon17 -magic src/utils/wpabuf.c /^ unsigned int magic;$/;" m struct:wpabuf_trace file: -manufacturer include/esp_supplicant/esp_wps.h /^ char manufacturer[WPS_MAX_MANUFACTURER_LEN]; \/*!< Manufacturer, null-terminated string. The default manufcturer is used if the string is empty *\/$/;" m struct:__anon89 -manufacturer src/ap/ap_config.h /^ char *manufacturer;$/;" m struct:hostapd_bss_config -manufacturer src/wps/wps.h /^ const char *manufacturer;$/;" m struct:wps_event_data::wps_event_er_ap -manufacturer src/wps/wps.h /^ const char *manufacturer;$/;" m struct:wps_event_data::wps_event_er_enrollee -manufacturer src/wps/wps.h /^ const u8 *manufacturer;$/;" m struct:wps_event_data::wps_event_m2d -manufacturer src/wps/wps.h /^ char *manufacturer;$/;" m struct:wps_device_data -manufacturer src/wps/wps_attr_parse.h /^ const u8 *manufacturer;$/;" m struct:wps_parse_attr -manufacturer_len src/wps/wps.h /^ size_t manufacturer_len;$/;" m struct:wps_event_data::wps_event_m2d -manufacturer_len src/wps/wps_attr_parse.h /^ size_t manufacturer_len;$/;" m struct:wps_parse_attr -manufacturer_url src/ap/ap_config.h /^ char *manufacturer_url;$/;" m struct:hostapd_bss_config -manufacturer_url src/wps/wps.h /^ const char *manufacturer_url;$/;" m struct:wps_event_data::wps_event_er_ap -manufacturer_url src/wps/wps.h /^ char *manufacturer_url;$/;" m struct:wps_context -master_key src/eap_peer/eap_mschapv2.c /^ u8 master_key[MSCHAPV2_MASTER_KEY_LEN];$/;" m struct:eap_mschapv2_data file: -master_key src/eap_peer/eap_ttls.c /^ u8 master_key[MSCHAPV2_MASTER_KEY_LEN]; \/* MSCHAPv2 master key *\/$/;" m struct:eap_ttls_data file: -master_key src/tls/tls.h /^ const u8 *master_key; \/* TLS master secret *\/$/;" m struct:tls_keys -master_key_len src/tls/tls.h /^ size_t master_key_len;$/;" m struct:tls_keys -master_key_valid src/eap_peer/eap_mschapv2.c /^ int master_key_valid;$/;" m struct:eap_mschapv2_data file: -master_secret src/tls/tlsv1_client_i.h /^ u8 master_secret[TLS_MASTER_SECRET_LEN];$/;" m struct:tlsv1_client -master_secret src/tls/tlsv1_server_i.h /^ u8 master_secret[TLS_MASTER_SECRET_LEN];$/;" m struct:tlsv1_server -max_listen_interval src/ap/ap_config.h /^ u16 max_listen_interval;$/;" m struct:hostapd_bss_config -max_num_sta src/ap/ap_config.h /^ int max_num_sta; \/* maximum number of STAs in station table *\/$/;" m struct:hostapd_bss_config -maximum_burst_size src/common/ieee802_11_defs.h /^ le32 maximum_burst_size;$/;" m struct:wmm_tspec_element -maximum_msdu_size src/common/ieee802_11_defs.h /^ le16 maximum_msdu_size;$/;" m struct:wmm_tspec_element -maximum_service_interval src/common/ieee802_11_defs.h /^ le32 maximum_service_interval;$/;" m struct:wmm_tspec_element -md4_vector src/crypto/md4-internal.c /^int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)$/;" f -md5 src/crypto/crypto_internal.c /^ struct MD5Context md5;$/;" m union:crypto_hash::__anon9 typeref:struct:crypto_hash::__anon9::MD5Context file: -md5 src/fast_crypto/fast_crypto_internal.c /^ struct MD5Context md5;$/;" m union:fast_crypto_hash::__anon61 typeref:struct:fast_crypto_hash::__anon61::MD5Context file: -md5_cert src/tls/tlsv1_common.h /^ struct crypto_hash *md5_cert;$/;" m struct:tls_verify_hash typeref:struct:tls_verify_hash::crypto_hash -md5_client src/tls/tlsv1_common.h /^ struct crypto_hash *md5_client;$/;" m struct:tls_verify_hash typeref:struct:tls_verify_hash::crypto_hash -md5_server src/tls/tlsv1_common.h /^ struct crypto_hash *md5_server;$/;" m struct:tls_verify_hash typeref:struct:tls_verify_hash::crypto_hash -md5_vector src/crypto/md5-internal.c /^md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)$/;" f -md5_vector_non_fips_allow include/crypto/crypto.h 64;" d -mdie src/ap/wpa_auth_ie.h /^ const u8 *mdie;$/;" m struct:wpa_eapol_ie_parse -mdie src/rsn_supp/wpa_ie.h /^ const u8 *mdie;$/;" m struct:wpa_eapol_ie_parse -mdie_len src/ap/wpa_auth_ie.h /^ size_t mdie_len;$/;" m struct:wpa_eapol_ie_parse -mdie_len src/rsn_supp/wpa_ie.h /^ size_t mdie_len;$/;" m struct:wpa_eapol_ie_parse -mean_data_rate src/common/ieee802_11_defs.h /^ le32 mean_data_rate;$/;" m struct:wmm_tspec_element -medium_time src/common/ieee802_11_defs.h /^ le16 medium_time;$/;" m struct:wmm_tspec_element -method src/eap_peer/eap.h /^ EapType method;$/;" m struct:eap_method_type -method src/eap_peer/eap_i.h /^ EapType method; $/;" m struct:eap_method -methodState src/eap_peer/eap_i.h /^ EapMethodState methodState;$/;" m struct:eap_method_ret -mgmt_frame_prot src/ap/wpa_auth_i.h /^ unsigned int mgmt_frame_prot:1;$/;" m struct:wpa_state_machine -mgmt_group_cipher src/common/wpa_common.h /^ int mgmt_group_cipher;$/;" m struct:wpa_ie_data -mgmt_group_cipher src/rsn_supp/wpa.h /^ unsigned int mgmt_group_cipher;$/;" m struct:wpa_sm -mic src/common/wpa_common.h /^ u8 mic[16];$/;" m struct:rsn_ftie -mic_control src/common/wpa_common.h /^ u8 mic_control[2];$/;" m struct:rsn_ftie -mic_errors_seen src/rsn_supp/wpa.h /^ int mic_errors_seen; \/* Michael MIC errors with the current PTK *\/$/;" m struct:install_key -mic_failure_report src/ap/wpa_auth.h /^ int (*mic_failure_report)(void *ctx, const u8 *addr);$/;" m struct:wpa_auth_callbacks -minimum_data_rate src/common/ieee802_11_defs.h /^ le32 minimum_data_rate;$/;" m struct:wmm_tspec_element -minimum_phy_rate src/common/ieee802_11_defs.h /^ le32 minimum_phy_rate;$/;" m struct:wmm_tspec_element -minimum_service_interval src/common/ieee802_11_defs.h /^ le32 minimum_service_interval;$/;" m struct:wmm_tspec_element -mobility_domain src/ap/ap_config.h /^ u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];$/;" m struct:hostapd_bss_config -mobility_domain src/ap/wpa_auth.h /^ u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];$/;" m struct:wpa_auth_config -mobility_domain src/common/wpa_common.h /^ u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];$/;" m struct:rsn_mdie -model_description src/ap/ap_config.h /^ char *model_description;$/;" m struct:hostapd_bss_config -model_description src/wps/wps.h /^ const char *model_description;$/;" m struct:wps_event_data::wps_event_er_ap -model_description src/wps/wps.h /^ char *model_description;$/;" m struct:wps_context -model_name include/esp_supplicant/esp_wps.h /^ char model_name[WPS_MAX_MODEL_NAME_LEN]; \/*!< Model name, null-terminated string. The default model name is used if the string is empty *\/$/;" m struct:__anon89 -model_name src/ap/ap_config.h /^ char *model_name;$/;" m struct:hostapd_bss_config -model_name src/wps/wps.h /^ const char *model_name;$/;" m struct:wps_event_data::wps_event_er_ap -model_name src/wps/wps.h /^ const char *model_name;$/;" m struct:wps_event_data::wps_event_er_enrollee -model_name src/wps/wps.h /^ const u8 *model_name;$/;" m struct:wps_event_data::wps_event_m2d -model_name src/wps/wps.h /^ char *model_name;$/;" m struct:wps_device_data -model_name src/wps/wps_attr_parse.h /^ const u8 *model_name;$/;" m struct:wps_parse_attr -model_name_len src/wps/wps.h /^ size_t model_name_len;$/;" m struct:wps_event_data::wps_event_m2d -model_name_len src/wps/wps_attr_parse.h /^ size_t model_name_len;$/;" m struct:wps_parse_attr -model_number include/esp_supplicant/esp_wps.h /^ char model_number[WPS_MAX_MODEL_NUMBER_LEN]; \/*!< Model number, null-terminated string. The default model number is used if the string is empty *\/$/;" m struct:__anon89 -model_number src/ap/ap_config.h /^ char *model_number;$/;" m struct:hostapd_bss_config -model_number src/wps/wps.h /^ const char *model_number;$/;" m struct:wps_event_data::wps_event_er_ap -model_number src/wps/wps.h /^ const char *model_number;$/;" m struct:wps_event_data::wps_event_er_enrollee -model_number src/wps/wps.h /^ const u8 *model_number;$/;" m struct:wps_event_data::wps_event_m2d -model_number src/wps/wps.h /^ char *model_number;$/;" m struct:wps_device_data -model_number src/wps/wps_attr_parse.h /^ const u8 *model_number;$/;" m struct:wps_parse_attr -model_number_len src/wps/wps.h /^ size_t model_number_len;$/;" m struct:wps_event_data::wps_event_m2d -model_number_len src/wps/wps_attr_parse.h /^ size_t model_number_len;$/;" m struct:wps_parse_attr -model_url src/ap/ap_config.h /^ char *model_url;$/;" m struct:hostapd_bss_config -model_url src/wps/wps.h /^ const char *model_url;$/;" m struct:wps_event_data::wps_event_er_ap -model_url src/wps/wps.h /^ char *model_url;$/;" m struct:wps_context -mp_2expt src/crypto/libtommath.h /^mp_2expt (mp_int * a, int b)$/;" f -mp_2expt src/tls/libtommath.h /^mp_2expt (mp_int * a, int b)$/;" f -mp_abs src/crypto/libtommath.h /^mp_abs (mp_int * a, mp_int * b)$/;" f -mp_abs src/tls/libtommath.h /^mp_abs (mp_int * a, mp_int * b)$/;" f -mp_add src/crypto/libtommath.h /^mp_add (mp_int * a, mp_int * b, mp_int * c)$/;" f -mp_add src/tls/libtommath.h /^mp_add (mp_int * a, mp_int * b, mp_int * c)$/;" f -mp_clamp src/crypto/libtommath.h /^mp_clamp (mp_int * a)$/;" f -mp_clamp src/tls/libtommath.h /^mp_clamp (mp_int * a)$/;" f -mp_clear src/crypto/libtommath.h /^mp_clear (mp_int * a)$/;" f -mp_clear src/tls/libtommath.h /^mp_clear (mp_int * a)$/;" f -mp_clear_multi src/crypto/libtommath.h /^mp_clear_multi(mp_int *mp, ...) $/;" f -mp_clear_multi src/tls/libtommath.h /^mp_clear_multi(mp_int *mp, ...) $/;" f -mp_cmp src/crypto/libtommath.h /^mp_cmp (mp_int * a, mp_int * b)$/;" f -mp_cmp src/tls/libtommath.h /^mp_cmp (mp_int * a, mp_int * b)$/;" f -mp_cmp_d src/crypto/libtommath.h /^mp_cmp_d(mp_int * a, mp_digit b)$/;" f -mp_cmp_d src/tls/libtommath.h /^mp_cmp_d(mp_int * a, mp_digit b)$/;" f -mp_cmp_mag src/crypto/libtommath.h /^mp_cmp_mag (mp_int * a, mp_int * b)$/;" f -mp_cmp_mag src/tls/libtommath.h /^mp_cmp_mag (mp_int * a, mp_int * b)$/;" f -mp_copy src/crypto/libtommath.h /^mp_copy (mp_int * a, mp_int * b)$/;" f -mp_copy src/tls/libtommath.h /^mp_copy (mp_int * a, mp_int * b)$/;" f -mp_count_bits src/crypto/libtommath.h /^mp_count_bits (mp_int * a)$/;" f -mp_count_bits src/tls/libtommath.h /^mp_count_bits (mp_int * a)$/;" f -mp_digit src/crypto/libtommath.h /^typedef unsigned long mp_digit;$/;" t -mp_digit src/tls/libtommath.h /^typedef unsigned long mp_digit;$/;" t -mp_div src/crypto/libtommath.h /^mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)$/;" f -mp_div src/crypto/libtommath.h /^mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)$/;" f -mp_div src/tls/libtommath.h /^mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)$/;" f -mp_div src/tls/libtommath.h /^mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)$/;" f -mp_div_2 src/crypto/libtommath.h /^mp_div_2(mp_int * a, mp_int * b)$/;" f -mp_div_2 src/tls/libtommath.h /^mp_div_2(mp_int * a, mp_int * b)$/;" f -mp_div_2d src/crypto/libtommath.h /^mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)$/;" f -mp_div_2d src/tls/libtommath.h /^mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)$/;" f -mp_err src/crypto/libtommath.h /^typedef int mp_err;$/;" t -mp_err src/tls/libtommath.h /^typedef int mp_err;$/;" t -mp_exch src/crypto/libtommath.h /^mp_exch (mp_int * a, mp_int * b)$/;" f -mp_exch src/tls/libtommath.h /^mp_exch (mp_int * a, mp_int * b)$/;" f -mp_exptmod src/crypto/libtommath.h /^mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)$/;" f -mp_exptmod src/tls/libtommath.h /^mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)$/;" f -mp_exptmod_fast src/crypto/libtommath.h /^mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)$/;" f -mp_exptmod_fast src/tls/libtommath.h /^mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)$/;" f -mp_grow src/crypto/libtommath.h /^mp_grow (mp_int * a, int size)$/;" f -mp_grow src/tls/libtommath.h /^mp_grow (mp_int * a, int size)$/;" f -mp_init src/crypto/libtommath.h /^mp_init (mp_int * a)$/;" f -mp_init src/tls/libtommath.h /^mp_init (mp_int * a)$/;" f -mp_init_copy src/crypto/libtommath.h /^mp_init_copy (mp_int * a, mp_int * b)$/;" f -mp_init_copy src/tls/libtommath.h /^mp_init_copy (mp_int * a, mp_int * b)$/;" f -mp_init_multi src/crypto/libtommath.h /^mp_init_multi(mp_int *mp, ...) $/;" f -mp_init_multi src/tls/libtommath.h /^mp_init_multi(mp_int *mp, ...) $/;" f -mp_init_size src/crypto/libtommath.h /^mp_init_size (mp_int * a, int size)$/;" f -mp_init_size src/tls/libtommath.h /^mp_init_size (mp_int * a, int size)$/;" f -mp_int src/crypto/libtommath.h /^} mp_int;$/;" t typeref:struct:__anon8 -mp_int src/tls/libtommath.h /^} mp_int;$/;" t typeref:struct:__anon40 -mp_invmod src/crypto/libtommath.h /^mp_invmod (mp_int * a, mp_int * b, mp_int * c)$/;" f -mp_invmod src/tls/libtommath.h /^mp_invmod (mp_int * a, mp_int * b, mp_int * c)$/;" f -mp_invmod_slow src/crypto/libtommath.h /^mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)$/;" f -mp_invmod_slow src/tls/libtommath.h /^mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)$/;" f -mp_iseven src/crypto/libtommath.h 127;" d -mp_iseven src/tls/libtommath.h 129;" d -mp_isodd src/crypto/libtommath.h 128;" d -mp_isodd src/tls/libtommath.h 130;" d -mp_iszero src/crypto/libtommath.h 126;" d -mp_iszero src/tls/libtommath.h 128;" d -mp_lshd src/crypto/libtommath.h /^mp_lshd (mp_int * a, int b)$/;" f -mp_lshd src/tls/libtommath.h /^mp_lshd (mp_int * a, int b)$/;" f -mp_mod src/crypto/libtommath.h /^mp_mod (mp_int * a, mp_int * b, mp_int * c)$/;" f -mp_mod src/tls/libtommath.h /^mp_mod (mp_int * a, mp_int * b, mp_int * c)$/;" f -mp_mod_2d src/crypto/libtommath.h /^mp_mod_2d (mp_int * a, int b, mp_int * c)$/;" f -mp_mod_2d src/tls/libtommath.h /^mp_mod_2d (mp_int * a, int b, mp_int * c)$/;" f -mp_montgomery_calc_normalization src/crypto/libtommath.h /^mp_montgomery_calc_normalization (mp_int * a, mp_int * b)$/;" f -mp_montgomery_calc_normalization src/tls/libtommath.h /^mp_montgomery_calc_normalization (mp_int * a, mp_int * b)$/;" f -mp_montgomery_setup src/crypto/libtommath.h /^mp_montgomery_setup (mp_int * n, mp_digit * rho)$/;" f -mp_montgomery_setup src/tls/libtommath.h /^mp_montgomery_setup (mp_int * n, mp_digit * rho)$/;" f -mp_mul src/crypto/libtommath.h /^mp_mul (mp_int * a, mp_int * b, mp_int * c)$/;" f -mp_mul src/tls/libtommath.h /^mp_mul (mp_int * a, mp_int * b, mp_int * c)$/;" f -mp_mul_2 src/crypto/libtommath.h /^mp_mul_2(mp_int * a, mp_int * b)$/;" f -mp_mul_2 src/tls/libtommath.h /^mp_mul_2(mp_int * a, mp_int * b)$/;" f -mp_mul_2d src/crypto/libtommath.h /^mp_mul_2d (mp_int * a, int b, mp_int * c)$/;" f -mp_mul_2d src/tls/libtommath.h /^mp_mul_2d (mp_int * a, int b, mp_int * c)$/;" f -mp_mul_d src/crypto/libtommath.h /^mp_mul_d (mp_int * a, mp_digit b, mp_int * c)$/;" f -mp_mul_d src/tls/libtommath.h /^mp_mul_d (mp_int * a, mp_digit b, mp_int * c)$/;" f -mp_mulmod src/crypto/libtommath.h /^mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)$/;" f -mp_mulmod src/tls/libtommath.h /^mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)$/;" f -mp_read_unsigned_bin src/crypto/libtommath.h /^mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)$/;" f -mp_read_unsigned_bin src/tls/libtommath.h /^mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)$/;" f -mp_reduce src/crypto/libtommath.h /^mp_reduce (mp_int * x, mp_int * m, mp_int * mu)$/;" f -mp_reduce src/tls/libtommath.h /^mp_reduce (mp_int * x, mp_int * m, mp_int * mu)$/;" f -mp_reduce_2k_l src/crypto/libtommath.h /^mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)$/;" f -mp_reduce_2k_l src/tls/libtommath.h /^mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)$/;" f -mp_reduce_2k_setup_l src/crypto/libtommath.h /^mp_reduce_2k_setup_l(mp_int *a, mp_int *d)$/;" f -mp_reduce_2k_setup_l src/tls/libtommath.h /^mp_reduce_2k_setup_l(mp_int *a, mp_int *d)$/;" f -mp_reduce_setup src/crypto/libtommath.h /^mp_reduce_setup (mp_int * a, mp_int * b)$/;" f -mp_reduce_setup src/tls/libtommath.h /^mp_reduce_setup (mp_int * a, mp_int * b)$/;" f -mp_rshd src/crypto/libtommath.h /^mp_rshd (mp_int * a, int b)$/;" f -mp_rshd src/tls/libtommath.h /^mp_rshd (mp_int * a, int b)$/;" f -mp_set src/crypto/libtommath.h /^mp_set (mp_int * a, mp_digit b)$/;" f -mp_set src/tls/libtommath.h /^mp_set (mp_int * a, mp_digit b)$/;" f -mp_sqr src/crypto/libtommath.h /^mp_sqr (mp_int * a, mp_int * b)$/;" f -mp_sqr src/tls/libtommath.h /^mp_sqr (mp_int * a, mp_int * b)$/;" f -mp_sub src/crypto/libtommath.h /^mp_sub (mp_int * a, mp_int * b, mp_int * c)$/;" f -mp_sub src/tls/libtommath.h /^mp_sub (mp_int * a, mp_int * b, mp_int * c)$/;" f -mp_to_unsigned_bin src/crypto/libtommath.h /^mp_to_unsigned_bin (mp_int * a, unsigned char *b)$/;" f -mp_to_unsigned_bin src/tls/libtommath.h /^mp_to_unsigned_bin (mp_int * a, unsigned char *b)$/;" f -mp_unsigned_bin_size src/crypto/libtommath.h /^mp_unsigned_bin_size (mp_int * a)$/;" f -mp_unsigned_bin_size src/tls/libtommath.h /^mp_unsigned_bin_size (mp_int * a)$/;" f -mp_word src/crypto/libtommath.h /^typedef u64 mp_word;$/;" t -mp_word src/tls/libtommath.h /^typedef u64 mp_word;$/;" t -mp_zero src/crypto/libtommath.h /^mp_zero (mp_int * a)$/;" f -mp_zero src/tls/libtommath.h /^mp_zero (mp_int * a)$/;" f -ms_change_password src/eap_peer/eap_mschapv2.c /^struct ms_change_password {$/;" s file: -ms_length src/eap_peer/eap_mschapv2.c /^ u8 ms_length[2];$/;" m struct:eap_mschapv2_hdr file: -ms_response src/eap_peer/eap_mschapv2.c /^struct ms_response {$/;" s file: -mschapv2 src/eap_peer/eap_ttls.c /^ u8 *mschapv2;$/;" m struct:ttls_parse_avp file: -mschapv2_derive_response src/eap_peer/mschapv2.c /^int mschapv2_derive_response(const u8 *identity, size_t identity_len,$/;" f -mschapv2_error src/eap_peer/eap_ttls.c /^ int mschapv2_error;$/;" m struct:ttls_parse_avp file: -mschapv2_id src/eap_peer/eap_mschapv2.c /^ u8 mschapv2_id;$/;" m struct:eap_mschapv2_hdr file: -mschapv2_remove_domain src/eap_peer/mschapv2.c /^const u8 * mschapv2_remove_domain(const u8 *username, size_t *len)$/;" f -mschapv2_retry src/eap_peer/eap_config.h /^ int mschapv2_retry;$/;" m struct:eap_peer_config -mschapv2_verify_auth_response src/eap_peer/mschapv2.c /^int mschapv2_verify_auth_response(const u8 *auth_response,$/;" f -msg src/wps/wps.h /^ int msg;$/;" m struct:wps_event_data::wps_event_fail -msg src/wps/wps.h /^ struct wpabuf *msg;$/;" m struct:upnp_pending_message typeref:struct:upnp_pending_message::wpabuf -msg_type src/wps/wps_attr_parse.h /^ const u8 *msg_type; \/* 1 octet *\/$/;" m struct:wps_parse_attr -mui src/common/wpa_common.h /^ be16 mui;$/;" m struct:rsn_error_kde -n src/tls/rsa.c /^ struct bignum *n; \/* modulus (p * q) *\/$/;" m struct:crypto_rsa_key typeref:struct:crypto_rsa_key::bignum file: -nak_type src/eap_peer/eap_tlv_common.h /^ be16 nak_type;$/;" m struct:eap_tlv_nak_tlv -name src/eap_peer/eap_config.h /^ char *name;$/;" m struct:wpa_config_blob -name src/eap_peer/eap_i.h /^ const char *name;$/;" m struct:eap_method -name src/utils/ext_password_i.h /^ const char *name;$/;" m struct:ext_password_backend -network_idx src/wps/wps_attr_parse.h /^ const u8 *network_idx; \/* 1 octet *\/$/;" m struct:wps_parse_attr -network_key src/wps/wps.h /^ u8 *network_key;$/;" m struct:wps_context -network_key src/wps/wps_attr_parse.h /^ const u8 *network_key; \/* <= 64 octets *\/$/;" m struct:wps_parse_attr -network_key_idx src/wps/wps_attr_parse.h /^ const u8 *network_key_idx; \/* 1 octet *\/$/;" m struct:wps_parse_attr -network_key_len src/wps/wps.h /^ size_t network_key_len;$/;" m struct:wps_context -network_key_len src/wps/wps_attr_parse.h /^ size_t network_key_len;$/;" m struct:wps_parse_attr -network_key_shareable src/wps/wps_attr_parse.h /^ const u8 *network_key_shareable; \/* 1 octet (Bool) *\/$/;" m struct:wps_parse_attr -new_ap_settings src/wps/wps.h /^ const struct wps_credential *new_ap_settings;$/;" m struct:wps_config typeref:struct:wps_config::wps_credential -new_ap_settings src/wps/wps_i.h /^ struct wps_credential *new_ap_settings;$/;" m struct:wps_data typeref:struct:wps_data::wps_credential -new_chan src/common/ieee802_11_defs.h /^ u8 new_chan;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon79 -new_password src/eap_peer/eap_config.h /^ u8 *new_password;$/;" m struct:eap_peer_config -new_password_encrypted_with_old_nt_password_hash src/crypto/ms_funcs.c /^int new_password_encrypted_with_old_nt_password_hash($/;" f -new_password_len src/eap_peer/eap_config.h /^ size_t new_password_len;$/;" m struct:eap_peer_config -new_psk src/wps/wps_i.h /^ u8 *new_psk;$/;" m struct:wps_data -new_psk_cb src/wps/wps.h /^ int (*new_psk_cb)(void *ctx, const u8 *mac_addr, const u8 *psk,$/;" m struct:wps_registrar_config -new_psk_cb src/wps/wps_registrar.c /^ int (*new_psk_cb)(void *ctx, const u8 *mac_addr, const u8 *psk,$/;" m struct:wps_registrar file: -new_psk_len src/wps/wps_i.h /^ size_t new_psk_len;$/;" m struct:wps_data -next src/ap/ap_config.h /^ struct hostapd_sta_wpa_psk_short *next;$/;" m struct:hostapd_sta_wpa_psk_short typeref:struct:hostapd_sta_wpa_psk_short::hostapd_sta_wpa_psk_short -next src/ap/ap_config.h /^ struct hostapd_wpa_psk *next;$/;" m struct:hostapd_wpa_psk typeref:struct:hostapd_wpa_psk::hostapd_wpa_psk -next src/ap/sta_info.h /^ struct sta_info *next; \/* next entry in sta list *\/$/;" m struct:sta_info typeref:struct:sta_info::sta_info -next src/ap/wpa_auth.h /^ struct ft_remote_r0kh *next;$/;" m struct:ft_remote_r0kh typeref:struct:ft_remote_r0kh::ft_remote_r0kh -next src/ap/wpa_auth.h /^ struct ft_remote_r1kh *next;$/;" m struct:ft_remote_r1kh typeref:struct:ft_remote_r1kh::ft_remote_r1kh -next src/ap/wpa_auth_i.h /^ struct wpa_group *next;$/;" m struct:wpa_group typeref:struct:wpa_group::wpa_group -next src/ap/wpa_auth_i.h /^ struct wpa_stsl_negotiation *next;$/;" m struct:wpa_stsl_negotiation typeref:struct:wpa_stsl_negotiation::wpa_stsl_negotiation -next src/eap_peer/eap_config.h /^ struct wpa_config_blob *next;$/;" m struct:wpa_config_blob typeref:struct:wpa_config_blob::wpa_config_blob -next src/eap_peer/eap_i.h /^ struct eap_method *next;$/;" m struct:eap_method typeref:struct:eap_method::eap_method -next src/tls/x509v3.h /^ struct x509_certificate *next;$/;" m struct:x509_certificate typeref:struct:x509_certificate::x509_certificate -next src/utils/list.h /^ struct dl_list *next;$/;" m struct:dl_list typeref:struct:dl_list::dl_list -next src/wps/wps.h /^ struct upnp_pending_message *next;$/;" m struct:upnp_pending_message typeref:struct:upnp_pending_message::upnp_pending_message -next src/wps/wps_registrar.c /^ struct wps_pbc_session *next;$/;" m struct:wps_pbc_session typeref:struct:wps_pbc_session::wps_pbc_session file: -next src/wps/wps_registrar.c /^ struct wps_registrar_device *next;$/;" m struct:wps_registrar_device typeref:struct:wps_registrar_device::wps_registrar_device file: -nfc_pw_token src/wps/wps_i.h /^ struct wps_nfc_pw_token *nfc_pw_token;$/;" m struct:wps_data typeref:struct:wps_data::wps_nfc_pw_token -nfc_pw_tokens src/wps/wps_registrar.c /^ struct dl_list nfc_pw_tokens;$/;" m struct:wps_registrar typeref:struct:wps_registrar::dl_list file: -noa_duration src/ap/hostapd.h /^ int noa_duration;$/;" m struct:hostapd_data -noa_enabled src/ap/hostapd.h /^ int noa_enabled;$/;" m struct:hostapd_data -noa_start src/ap/hostapd.h /^ int noa_start;$/;" m struct:hostapd_data -nominal_msdu_size src/common/ieee802_11_defs.h /^ le16 nominal_msdu_size;$/;" m struct:wmm_tspec_element -nonce src/ap/wpa_auth.h /^ u8 nonce[16]; \/* copied from pull *\/$/;" m struct:ft_r0kh_r1kh_resp_frame -nonce src/ap/wpa_auth.h /^ u8 nonce[16];$/;" m struct:ft_r0kh_r1kh_pull_frame -nonce src/ap/wpa_auth_ie.h /^ const u8 *nonce;$/;" m struct:wpa_eapol_ie_parse -nonce src/eap_peer/eap_tlv_common.h /^ u8 nonce[32];$/;" m struct:eap_tlv_crypto_binding_tlv -nonce src/rsn_supp/wpa_ie.h /^ const u8 *nonce;$/;" m struct:wpa_eapol_ie_parse -nonce_e src/wps/wps_i.h /^ u8 nonce_e[WPS_NONCE_LEN];$/;" m struct:wps_data -nonce_len src/ap/wpa_auth_ie.h /^ size_t nonce_len;$/;" m struct:wpa_eapol_ie_parse -nonce_len src/rsn_supp/wpa_ie.h /^ size_t nonce_len;$/;" m struct:wpa_eapol_ie_parse -nonce_r src/wps/wps_i.h /^ u8 nonce_r[WPS_NONCE_LEN];$/;" m struct:wps_data -not_after src/tls/x509v3.h /^ os_time_t not_after;$/;" m struct:x509_certificate -not_before src/tls/x509v3.h /^ os_time_t not_before;$/;" m struct:x509_certificate -nt_challenge_response src/crypto/ms_funcs.c /^int nt_challenge_response(const u8 *challenge, const u8 *password,$/;" f -nt_password_hash src/crypto/ms_funcs.c /^int nt_password_hash(const u8 *password, size_t password_len,$/;" f -nt_password_hash_encrypted_with_block src/crypto/ms_funcs.c /^void nt_password_hash_encrypted_with_block(const u8 *password_hash,$/;" f -nt_response src/eap_peer/eap_mschapv2.c /^ u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN];$/;" m struct:ms_change_password file: -nt_response src/eap_peer/eap_mschapv2.c /^ u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN];$/;" m struct:ms_response file: -num_attr src/tls/x509v3.h /^ size_t num_attr;$/;" m struct:x509_name -num_bits_set src/wps/wps_validate.c /^static int num_bits_set(u16 val)$/;" f file: -num_bss src/ap/ap_config.h /^ size_t num_bss;$/;" m struct:hostapd_config -num_cipher_suites src/tls/tlsv1_client_i.h /^ size_t num_cipher_suites;$/;" m struct:tlsv1_client -num_cipher_suites src/tls/tlsv1_server_i.h /^ size_t num_cipher_suites;$/;" m struct:tlsv1_server -num_cred src/wps/wps_attr_parse.h /^ size_t num_cred;$/;" m struct:wps_parse_attr -num_phase2_eap_types src/eap_peer/eap_ttls.c /^ size_t num_phase2_eap_types;$/;" m struct:eap_ttls_data file: -num_phase2_types src/eap_peer/eap_peap.c /^ size_t num_phase2_types;$/;" m struct:eap_peap_data file: -num_pmkid src/common/wpa_common.h /^ size_t num_pmkid;$/;" m struct:wpa_ie_data -num_req_dev_type src/wps/wps_attr_parse.h /^ size_t num_req_dev_type;$/;" m struct:wps_parse_attr -num_sec_dev_types src/wps/wps.h /^ u8 num_sec_dev_types;$/;" m struct:wps_device_data -num_sta src/ap/hostapd.h /^ int num_sta; \/* number of entries in sta_list *\/$/;" m struct:hostapd_data -num_sta_no_p2p src/ap/hostapd.h /^ int num_sta_no_p2p;$/;" m struct:hostapd_data -num_vendor_ext src/wps/wps_attr_parse.h /^ size_t num_vendor_ext;$/;" m struct:wps_parse_attr -ocsp src/eap_peer/eap_config.h /^ int ocsp;$/;" m struct:eap_peer_config -ocsp_stapling_response src/tls/tls.h /^ const char *ocsp_stapling_response;$/;" m struct:tls_connection_params -offsetof src/utils/list.h 70;" d -oid src/tls/asn1.h /^ unsigned long oid[ASN1_MAX_OID_LEN];$/;" m struct:asn1_oid -oid src/tls/x509v3.h /^ struct asn1_oid oid;$/;" m struct:x509_algorithm_identifier typeref:struct:x509_algorithm_identifier::asn1_oid -okc src/ap/wpa_auth.h /^ int okc;$/;" m struct:wpa_auth_config -old_nt_password_hash_encrypted_with_new_nt_password_hash src/crypto/ms_funcs.c /^int old_nt_password_hash_encrypted_with_new_nt_password_hash($/;" f -oob_dev_password src/wps/wps_attr_parse.h /^ const u8 *oob_dev_password; \/* 38..54 octets *\/$/;" m struct:wps_parse_attr -oob_dev_password_len src/wps/wps_attr_parse.h /^ size_t oob_dev_password_len;$/;" m struct:wps_parse_attr -op_code src/eap_peer/eap_mschapv2.c /^ u8 op_code;$/;" m struct:eap_mschapv2_hdr file: -opcode src/eap_peer/eap_defs.h /^ u8 opcode;$/;" m struct:eap_expand -opensc_engine_path src/tls/tls.h /^ const char *opensc_engine_path;$/;" m struct:tls_config -operation_mode src/common/ieee802_11_defs.h /^ le16 operation_mode;$/;" m struct:ieee80211_ht_operation -os_bzero port/include/os.h 206;" d -os_free port/include/os.h 202;" d -os_get_random port/os_xtensa.c /^int os_get_random(unsigned char *buf, size_t len)$/;" f -os_get_time port/os_xtensa.c /^int os_get_time(struct os_time *t)$/;" f -os_malloc port/include/os.h 193;" d -os_memcmp port/include/os.h 229;" d -os_memcpy port/include/os.h 220;" d -os_memmove port/include/os.h 223;" d -os_memset port/include/os.h 226;" d -os_random port/os_xtensa.c /^unsigned long os_random(void)$/;" f -os_realloc port/include/os.h 196;" d -os_snprintf port/include/os.h 271;" d -os_snprintf port/include/os.h 273;" d -os_strcasecmp port/include/os.h 237;" d -os_strcasecmp port/include/os.h 239;" d -os_strchr port/include/os.h 250;" d -os_strcmp port/include/os.h 253;" d -os_strdup port/include/os.h 212;" d -os_strdup port/include/os.h 214;" d -os_strlen port/include/os.h 233;" d -os_strncasecmp port/include/os.h 244;" d -os_strncasecmp port/include/os.h 246;" d -os_strncmp port/include/os.h 256;" d -os_strncpy port/include/os.h 259;" d -os_strrchr port/include/os.h 263;" d -os_strstr port/include/os.h 266;" d -os_time port/include/os.h /^struct os_time {$/;" s -os_time_before port/include/os.h 48;" d -os_time_sub port/include/os.h 52;" d -os_time_t port/include/os.h /^typedef long os_time_t;$/;" t -os_version src/ap/ap_config.h /^ u8 os_version[4];$/;" m struct:hostapd_bss_config -os_version src/wps/wps.h /^ u32 os_version;$/;" m struct:wps_device_data -os_version src/wps/wps_attr_parse.h /^ const u8 *os_version; \/* 4 octets *\/$/;" m struct:wps_parse_attr -os_zalloc port/include/os.h 199;" d -oui src/common/ieee802_11_defs.h /^ u8 oui[3]; \/* 00:50:f2 *\/$/;" m struct:wmm_information_element -oui src/common/ieee802_11_defs.h /^ u8 oui[3]; \/* 00:50:f2 *\/$/;" m struct:wmm_parameter_element -oui src/common/ieee802_11_defs.h /^ u8 oui[3]; \/* 00:50:f2 *\/$/;" m struct:wmm_tspec_element -oui src/common/wpa_common.h /^ u8 oui[4]; \/* 24-bit OUI followed by 8-bit OUI type *\/$/;" m struct:wpa_ie_hdr -oui_subtype src/common/ieee802_11_defs.h /^ u8 oui_subtype; \/* 0 *\/$/;" m struct:wmm_information_element -oui_subtype src/common/ieee802_11_defs.h /^ u8 oui_subtype; \/* 1 *\/$/;" m struct:wmm_parameter_element -oui_subtype src/common/ieee802_11_defs.h /^ u8 oui_subtype; \/* 2 *\/$/;" m struct:wmm_tspec_element -oui_type src/common/ieee802_11_defs.h /^ u8 oui_type; \/* 2 *\/$/;" m struct:wmm_information_element -oui_type src/common/ieee802_11_defs.h /^ u8 oui_type; \/* 2 *\/$/;" m struct:wmm_parameter_element -oui_type src/common/ieee802_11_defs.h /^ u8 oui_type; \/* 2 *\/$/;" m struct:wmm_tspec_element -outbuf src/eap_peer/eap_i.h /^ struct pbuf *outbuf;$/;" m struct:eap_sm typeref:struct:eap_sm::pbuf -own_addr src/ap/hostapd.h /^ u8 own_addr[ETH_ALEN];$/;" m struct:hostapd_data -own_addr src/rsn_supp/wpa.h /^ u8 own_addr[ETH_ALEN];$/;" m struct:wpa_sm -ownaddr src/eap_peer/eap_i.h /^ u8 ownaddr[ETH_ALEN];$/;" m struct:eap_sm -ownaddr src/wps/wps.h /^ u8 ownaddr[ETH_ALEN];$/;" m struct:wps_sm -p src/tls/rsa.c /^ struct bignum *p; \/* prime p (factor of n) *\/$/;" m struct:crypto_rsa_key typeref:struct:crypto_rsa_key::bignum file: -p2p src/ap/hostapd.h /^ struct p2p_data *p2p;$/;" m struct:hostapd_data typeref:struct:hostapd_data::p2p_data -p2p src/wps/wps.h /^ int p2p;$/;" m struct:wps_device_data -p2p_beacon_ie src/ap/hostapd.h /^ struct wpabuf *p2p_beacon_ie;$/;" m struct:hostapd_data typeref:struct:hostapd_data::wpabuf -p2p_dev_addr src/wps/wps.h /^ const u8 *p2p_dev_addr;$/;" m struct:wps_config -p2p_dev_addr src/wps/wps_i.h /^ u8 p2p_dev_addr[ETH_ALEN]; \/* P2P Device Address of the client or$/;" m struct:wps_data -p2p_dev_addr src/wps/wps_registrar.c /^ u8 p2p_dev_addr[ETH_ALEN];$/;" m struct:wps_registrar file: -p2p_group src/ap/hostapd.h /^ struct p2p_group *p2p_group;$/;" m struct:hostapd_data typeref:struct:hostapd_data::p2p_group -p2p_probe_resp_ie src/ap/hostapd.h /^ struct wpabuf *p2p_probe_resp_ie;$/;" m struct:hostapd_data typeref:struct:hostapd_data::wpabuf -pac_len src/eap_peer/eap_tlv_common.h /^ be16 pac_len;$/;" m struct:eap_tlv_pac_ack_tlv -pac_type src/eap_peer/eap_tlv_common.h /^ be16 pac_type;$/;" m struct:eap_tlv_pac_ack_tlv -pac_type src/eap_peer/eap_tlv_common.h /^ be16 pac_type;$/;" m struct:eap_tlv_pac_type_tlv -packet_type src/ap/wpa_auth.h /^ u8 packet_type; \/* FT_PACKET_R0KH_R1KH_PULL *\/$/;" m struct:ft_r0kh_r1kh_pull_frame -packet_type src/ap/wpa_auth.h /^ u8 packet_type; \/* FT_PACKET_R0KH_R1KH_PUSH *\/$/;" m struct:ft_r0kh_r1kh_push_frame -packet_type src/ap/wpa_auth.h /^ u8 packet_type; \/* FT_PACKET_R0KH_R1KH_RESP *\/$/;" m struct:ft_r0kh_r1kh_resp_frame -packet_type src/ap/wpa_auth.h /^ u8 packet_type; \/* FT_PACKET_REQUEST\/FT_PACKET_RESPONSE *\/$/;" m struct:ft_rrb_frame -pad src/ap/wpa_auth.h /^ u8 pad[2]; \/* 8-octet boundary for AES key wrap *\/$/;" m struct:ft_r0kh_r1kh_resp_frame -pad src/ap/wpa_auth.h /^ u8 pad[4]; \/* 8-octet boundary for AES key wrap *\/$/;" m struct:ft_r0kh_r1kh_pull_frame -pad src/ap/wpa_auth.h /^ u8 pad[6]; \/* 8-octet boundary for AES key wrap *\/$/;" m struct:ft_r0kh_r1kh_push_frame -pairwise src/ap/wpa_auth.h /^ le16 pairwise;$/;" m struct:ft_r0kh_r1kh_push_frame -pairwise src/ap/wpa_auth.h /^ le16 pairwise;$/;" m struct:ft_r0kh_r1kh_resp_frame -pairwise src/ap/wpa_auth_i.h /^ int pairwise; \/* Pairwise cipher suite, WPA_CIPHER_* *\/$/;" m struct:wpa_state_machine -pairwise_cipher src/common/wpa_common.h /^ int pairwise_cipher;$/;" m struct:wpa_ie_data -pairwise_cipher src/rsn_supp/wpa.h /^ unsigned int pairwise_cipher;$/;" m struct:wpa_sm -pairwise_set src/ap/wpa_auth_i.h /^ Boolean pairwise_set;$/;" m struct:wpa_state_machine -param src/esp_supplicant/esp_wifi_driver.h /^ void *param;$/;" m struct:__anon31 -part src/wps/wps.h /^ int part;$/;" m struct:wps_event_data::wps_event_pwd_auth_fail -partial_input src/tls/tlsv1_client_i.h /^ struct wpabuf *partial_input;$/;" m struct:tlsv1_client typeref:struct:tlsv1_client::wpabuf -passwd_change_challenge src/eap_peer/eap_mschapv2.c /^ u8 passwd_change_challenge[PASSWD_CHANGE_CHAL_LEN];$/;" m struct:eap_mschapv2_data file: -passwd_change_challenge_valid src/eap_peer/eap_mschapv2.c /^ int passwd_change_challenge_valid;$/;" m struct:eap_mschapv2_data file: -passwd_change_version src/eap_peer/eap_mschapv2.c /^ int passwd_change_version;$/;" m struct:eap_mschapv2_data file: -password src/eap_peer/eap_config.h /^ u8 *password;$/;" m struct:eap_peer_config -password_len src/eap_peer/eap_config.h /^ size_t password_len;$/;" m struct:eap_peer_config -path_len_constraint src/tls/x509v3.h /^ unsigned long path_len_constraint; \/* pathLenConstraint *\/$/;" m struct:x509_certificate -payload src/tls/asn1.h /^ const u8 *payload;$/;" m struct:asn1_hdr -pbc src/wps/wps.h /^ int pbc;$/;" m struct:wps_config -pbc src/wps/wps_i.h /^ int pbc;$/;" m struct:wps_data -pbc src/wps/wps_registrar.c /^ int pbc;$/;" m struct:wps_registrar file: -pbc_ignore_start src/wps/wps_registrar.c /^ struct os_time pbc_ignore_start;$/;" m struct:wps_registrar typeref:struct:wps_registrar::os_time file: -pbc_ignore_uuid src/wps/wps_registrar.c /^ u8 pbc_ignore_uuid[WPS_UUID_LEN];$/;" m struct:wps_registrar file: -pbc_in_m1 src/wps/wps.h /^ int pbc_in_m1;$/;" m struct:wps_config -pbc_in_m1 src/wps/wps_i.h /^ int pbc_in_m1;$/;" m struct:wps_data -pbc_sessions src/wps/wps_registrar.c /^ struct wps_pbc_session *pbc_sessions;$/;" m struct:wps_registrar typeref:struct:wps_registrar::wps_pbc_session file: -pbkdf2_sha1 src/crypto/sha1-pbkdf2.c /^pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,$/;" f -pbkdf2_sha1_f src/crypto/sha1-pbkdf2.c /^pbkdf2_sha1_f(const char *passphrase, const char *ssid,$/;" f file: -pc1 src/crypto/des-internal.c /^static const u8 pc1[56] = {$/;" v file: -pc2 src/crypto/des-internal.c /^static const u8 pc2[48] = {$/;" v file: -peak_data_rate src/common/ieee802_11_defs.h /^ le32 peak_data_rate;$/;" m struct:wmm_tspec_element -peap_done src/eap_peer/eap_i.h /^ bool peap_done;$/;" m struct:eap_sm -peap_outer_success src/eap_peer/eap_peap.c /^ int peap_outer_success; \/* 0 = PEAP terminated on Phase 2 inner$/;" m struct:eap_peap_data file: -peap_prfplus src/eap_peer/eap_peap_common.c /^peap_prfplus(int version, const u8 *key, size_t key_len,$/;" f -peap_version src/eap_peer/eap_peap.c /^ int peap_version, force_peap_version, force_new_label;$/;" m struct:eap_peap_data file: -peer src/ap/wpa_auth_i.h /^ u8 peer[ETH_ALEN];$/;" m struct:wpa_stsl_negotiation -peer_addr src/wps/wps.h /^ const u8 *peer_addr;$/;" m struct:wps_config -peer_cert src/tls/tls.h /^ } peer_cert;$/;" m union:tls_event_data typeref:struct:tls_event_data::__anon35 -peer_challenge src/eap_peer/eap_mschapv2.c /^ u8 *peer_challenge;$/;" m struct:eap_mschapv2_data file: -peer_challenge src/eap_peer/eap_mschapv2.c /^ u8 peer_challenge[MSCHAPV2_CHAL_LEN];$/;" m struct:ms_change_password file: -peer_challenge src/eap_peer/eap_mschapv2.c /^ u8 peer_challenge[MSCHAPV2_CHAL_LEN];$/;" m struct:ms_response file: -peer_dev src/wps/wps_i.h /^ struct wps_device_data peer_dev;$/;" m struct:wps_data typeref:struct:wps_data::wps_device_data -peer_hash1 src/wps/wps_i.h /^ u8 peer_hash1[WPS_HASH_LEN];$/;" m struct:wps_data -peer_hash2 src/wps/wps_i.h /^ u8 peer_hash2[WPS_HASH_LEN];$/;" m struct:wps_data -peerkey src/ap/ap_config.h /^ int peerkey;$/;" m struct:hostapd_bss_config -peerkey src/ap/wpa_auth.h /^ int peerkey;$/;" m struct:wpa_auth_config -pem_cert_begin src/tls/tlsv1_cred.c /^static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";$/;" v file: -pem_cert_end src/tls/tlsv1_cred.c /^static const char *pem_cert_end = "-----END CERTIFICATE-----";$/;" v file: -pem_dhparams_begin src/tls/tlsv1_cred.c /^static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----";$/;" v file: -pem_dhparams_end src/tls/tlsv1_cred.c /^static const char *pem_dhparams_end = "-----END DH PARAMETERS-----";$/;" v file: -pem_key2_begin src/tls/tlsv1_cred.c /^static const char *pem_key2_begin = "-----BEGIN PRIVATE KEY-----";$/;" v file: -pem_key2_end src/tls/tlsv1_cred.c /^static const char *pem_key2_end = "-----END PRIVATE KEY-----";$/;" v file: -pem_key_begin src/tls/tlsv1_cred.c /^static const char *pem_key_begin = "-----BEGIN RSA PRIVATE KEY-----";$/;" v file: -pem_key_enc_begin src/tls/tlsv1_cred.c /^static const char *pem_key_enc_begin = "-----BEGIN ENCRYPTED PRIVATE KEY-----";$/;" v file: -pem_key_enc_end src/tls/tlsv1_cred.c /^static const char *pem_key_enc_end = "-----END ENCRYPTED PRIVATE KEY-----";$/;" v file: -pem_key_end src/tls/tlsv1_cred.c /^static const char *pem_key_end = "-----END RSA PRIVATE KEY-----";$/;" v file: -pending_1_of_4_timeout src/ap/wpa_auth_i.h /^ int pending_1_of_4_timeout;$/;" m struct:wpa_state_machine -pending_deinit src/ap/wpa_auth_i.h /^ unsigned int pending_deinit:1;$/;" m struct:wpa_state_machine -pending_phase2_req src/eap_peer/eap_peap.c /^ struct wpabuf *pending_phase2_req;$/;" m struct:eap_peap_data typeref:struct:eap_peap_data::wpabuf file: -pending_phase2_req src/eap_peer/eap_ttls.c /^ struct wpabuf *pending_phase2_req;$/;" m struct:eap_ttls_data typeref:struct:eap_ttls_data::wpabuf file: -phase1 src/eap_peer/eap_config.h /^ char *phase1;$/;" m struct:eap_peer_config -phase2 src/eap_peer/eap_config.h /^ char *phase2;$/;" m struct:eap_peer_config -phase2 src/eap_peer/eap_mschapv2.c /^ int phase2;$/;" m struct:eap_mschapv2_data file: -phase2 src/eap_peer/eap_tls_common.h /^ int phase2;$/;" m struct:eap_ssl_data -phase2_eap_started src/eap_peer/eap_peap.c /^ int phase2_eap_started;$/;" m struct:eap_peap_data file: -phase2_eap_success src/eap_peer/eap_peap.c /^ int phase2_eap_success;$/;" m struct:eap_peap_data file: -phase2_eap_type src/eap_peer/eap_ttls.c /^ struct eap_method_type phase2_eap_type;$/;" m struct:eap_ttls_data typeref:struct:eap_ttls_data::eap_method_type file: -phase2_eap_types src/eap_peer/eap_ttls.c /^ struct eap_method_type *phase2_eap_types;$/;" m struct:eap_ttls_data typeref:struct:eap_ttls_data::eap_method_type file: -phase2_method src/eap_peer/eap_peap.c /^ const struct eap_method *phase2_method;$/;" m struct:eap_peap_data typeref:struct:eap_peap_data::eap_method file: -phase2_method src/eap_peer/eap_ttls.c /^ const struct eap_method *phase2_method;$/;" m struct:eap_ttls_data typeref:struct:eap_ttls_data::eap_method file: -phase2_priv src/eap_peer/eap_peap.c /^ void *phase2_priv;$/;" m struct:eap_peap_data file: -phase2_priv src/eap_peer/eap_ttls.c /^ void *phase2_priv;$/;" m struct:eap_ttls_data file: -phase2_start src/eap_peer/eap_ttls.c /^ int phase2_start;$/;" m struct:eap_ttls_data file: -phase2_success src/eap_peer/eap_peap.c /^ int phase2_success;$/;" m struct:eap_peap_data file: -phase2_success src/eap_peer/eap_ttls.c /^ int phase2_success;$/;" m struct:eap_ttls_data file: -phase2_type src/eap_peer/eap_peap.c /^ struct eap_method_type phase2_type;$/;" m struct:eap_peap_data typeref:struct:eap_peap_data::eap_method_type file: -phase2_type src/eap_peer/eap_ttls.c /^ } phase2_type;$/;" m struct:eap_ttls_data typeref:enum:eap_ttls_data::phase2_types file: -phase2_types src/eap_peer/eap_peap.c /^ struct eap_method_type *phase2_types;$/;" m struct:eap_peap_data typeref:struct:eap_peap_data::eap_method_type file: -phase2_types src/eap_peer/eap_ttls.c /^ enum phase2_types {$/;" g struct:eap_ttls_data file: -pin src/eap_peer/eap_config.h /^ char *pin;$/;" m struct:eap_peer_config -pin src/tls/tls.h /^ const char *pin;$/;" m struct:tls_connection_params -pin src/wps/wps.h /^ const u8 *pin;$/;" m struct:wps_config -pin src/wps/wps_registrar.c /^ u8 *pin;$/;" m struct:wps_uuid_pin file: -pin_len src/wps/wps.h /^ size_t pin_len;$/;" m struct:wps_config -pin_len src/wps/wps_registrar.c /^ size_t pin_len;$/;" m struct:wps_uuid_pin file: -pin_needed_cb src/wps/wps.h /^ void (*pin_needed_cb)(void *ctx, const u8 *uuid_e,$/;" m struct:wps_registrar_config -pin_needed_cb src/wps/wps_registrar.c /^ void (*pin_needed_cb)(void *ctx, const u8 *uuid_e,$/;" m struct:wps_registrar file: -pins src/wps/wps_registrar.c /^ struct dl_list pins;$/;" m struct:wps_registrar typeref:struct:wps_registrar::dl_list file: -pkcs11_engine_path src/tls/tls.h /^ const char *pkcs11_engine_path;$/;" m struct:tls_config -pkcs11_module_path src/tls/tls.h /^ const char *pkcs11_module_path;$/;" m struct:tls_config -pkcs1_decrypt_public_key src/tls/pkcs1.c /^int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,$/;" f -pkcs1_encrypt src/tls/pkcs1.c /^int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key,$/;" f -pkcs1_generate_encryption_block src/tls/pkcs1.c /^static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,$/;" f file: -pkcs1_v15_private_key_decrypt src/tls/pkcs1.c /^int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key,$/;" f -pkcs5_alg src/tls/pkcs5.c /^ enum pkcs5_alg {$/;" g struct:pkcs5_params file: -pkcs5_crypto_init src/tls/pkcs5.c /^static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,$/;" f file: -pkcs5_decrypt src/tls/pkcs5.c /^u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len,$/;" f -pkcs5_get_alg src/tls/pkcs5.c /^static enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)$/;" f file: -pkcs5_get_params src/tls/pkcs5.c /^static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,$/;" f file: -pkcs5_params src/tls/pkcs5.c /^struct pkcs5_params {$/;" s file: -pkcs8_enc_key_import src/tls/pkcs8.c /^pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd)$/;" f -pkcs8_key_import src/tls/pkcs8.c /^struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)$/;" f -pmk src/rsn_supp/wpa.h /^ u8 pmk[PMK_LEN];$/;" m struct:wpa_sm -pmk_len src/rsn_supp/wpa.h /^ size_t pmk_len;$/;" m struct:wpa_sm -pmk_r0_name src/ap/wpa_auth.h /^ u8 pmk_r0_name[WPA_PMK_NAME_LEN];$/;" m struct:ft_r0kh_r1kh_pull_frame -pmk_r0_name src/ap/wpa_auth.h /^ u8 pmk_r0_name[WPA_PMK_NAME_LEN];$/;" m struct:ft_r0kh_r1kh_push_frame -pmk_r1 src/ap/wpa_auth.h /^ u8 pmk_r1[PMK_LEN];$/;" m struct:ft_r0kh_r1kh_push_frame -pmk_r1 src/ap/wpa_auth.h /^ u8 pmk_r1[PMK_LEN];$/;" m struct:ft_r0kh_r1kh_resp_frame -pmk_r1_name src/ap/wpa_auth.h /^ u8 pmk_r1_name[WPA_PMK_NAME_LEN];$/;" m struct:ft_r0kh_r1kh_push_frame -pmk_r1_name src/ap/wpa_auth.h /^ u8 pmk_r1_name[WPA_PMK_NAME_LEN];$/;" m struct:ft_r0kh_r1kh_resp_frame -pmk_r1_name src/ap/wpa_auth_i.h /^ u8 pmk_r1_name[WPA_PMK_NAME_LEN]; \/* PMKR1Name derived from FT Auth$/;" m struct:wpa_state_machine -pmk_r1_name_valid src/ap/wpa_auth_i.h /^ unsigned int pmk_r1_name_valid:1;$/;" m struct:wpa_state_machine -pmk_r1_push src/ap/ap_config.h /^ int pmk_r1_push;$/;" m struct:hostapd_bss_config -pmk_r1_push src/ap/wpa_auth.h /^ int pmk_r1_push;$/;" m struct:wpa_auth_config -pmkid src/ap/wpa_auth_ie.h /^ const u8 *pmkid;$/;" m struct:wpa_eapol_ie_parse -pmkid src/common/wpa_common.h /^ const u8 *pmkid;$/;" m struct:wpa_ie_data -pmkid src/rsn_supp/wpa_ie.h /^ const u8 *pmkid;$/;" m struct:wpa_eapol_ie_parse -pn src/common/wpa_common.h /^ u8 pn[6];$/;" m struct:wpa_igtk_kde -pp_michael_mic_failure src/rsn_supp/wpa.c /^pp_michael_mic_failure(u16 isunicast)$/;" f -preamble src/ap/ap_config.h /^ } preamble;$/;" m struct:hostapd_config typeref:enum:hostapd_config::__anon19 -prev src/utils/list.h /^ struct dl_list *prev;$/;" m struct:dl_list typeref:struct:dl_list::dl_list -prev_challenge src/eap_peer/eap_mschapv2.c /^ struct wpabuf *prev_challenge;$/;" m struct:eap_mschapv2_data typeref:struct:eap_mschapv2_data::wpabuf file: -prev_cipher_suite src/tls/tlsv1_client_i.h /^ u16 prev_cipher_suite;$/;" m struct:tlsv1_client -prev_error src/eap_peer/eap_mschapv2.c /^ int prev_error;$/;" m struct:eap_mschapv2_data file: -prev_key_replay src/ap/wpa_auth_i.h /^ prev_key_replay[RSNA_MAX_EAPOL_RETRIES];$/;" m struct:wpa_state_machine typeref:struct:wpa_state_machine::wpa_key_replay_counter -pri_dev_type src/wps/wps.h /^ const u8 *pri_dev_type;$/;" m struct:wps_event_data::wps_event_er_ap -pri_dev_type src/wps/wps.h /^ const u8 *pri_dev_type;$/;" m struct:wps_event_data::wps_event_er_enrollee -pri_dev_type src/wps/wps.h /^ u8 pri_dev_type[WPS_DEV_TYPE_LEN];$/;" m struct:wps_device_data -primary_dev_type src/wps/wps.h /^ const u8 *primary_dev_type; \/* 8 octets *\/$/;" m struct:wps_event_data::wps_event_m2d -primary_dev_type src/wps/wps_attr_parse.h /^ const u8 *primary_dev_type; \/* 8 octets *\/$/;" m struct:wps_parse_attr -prime include/crypto/dh_groups.h /^ const u8 *prime;$/;" m struct:dh_group -prime_len include/crypto/dh_groups.h /^ size_t prime_len;$/;" m struct:dh_group -priv src/utils/ext_password.c /^ void *priv;$/;" m struct:ext_password_data file: -private_key src/eap_peer/eap_config.h /^ u8 *private_key;$/;" m struct:eap_peer_config -private_key src/tls/rsa.c /^ int private_key; \/* whether private key is set *\/$/;" m struct:crypto_rsa_key file: -private_key src/tls/tls.h /^ const char *private_key;$/;" m struct:tls_connection_params -private_key2 src/eap_peer/eap_config.h /^ u8 *private_key2;$/;" m struct:eap_peer_config -private_key2_password src/eap_peer/eap_config.h /^ u8 *private_key2_password;$/;" m struct:eap_peer_config -private_key_blob src/tls/tls.h /^ const u8 *private_key_blob;$/;" m struct:tls_connection_params -private_key_blob_len src/tls/tls.h /^ size_t private_key_blob_len;$/;" m struct:tls_connection_params -private_key_passwd src/eap_peer/eap_config.h /^ const u8 *private_key_passwd;$/;" m struct:eap_peer_config -private_key_passwd src/tls/tls.h /^ const char *private_key_passwd;$/;" m struct:tls_connection_params -probe_req src/common/ieee802_11_defs.h /^ } STRUCT_PACKED probe_req;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon74 -probe_resp src/common/ieee802_11_defs.h /^ } STRUCT_PACKED probe_resp;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon75 -process src/eap_peer/eap_i.h /^ struct wpabuf * (*process)(struct eap_sm *sm, void *priv,$/;" m struct:eap_method typeref:struct:eap_method::process -proto src/common/wpa_common.h /^ int proto;$/;" m struct:wpa_ie_data -proto src/rsn_supp/wpa.h /^ unsigned int proto;$/;" m struct:wpa_sm -psk src/ap/ap_config.h /^ u8 psk[PMK_LEN];$/;" m struct:hostapd_sta_wpa_psk_short -psk src/ap/ap_config.h /^ u8 psk[PMK_LEN];$/;" m struct:hostapd_wpa_psk -psk src/wps/wps.h /^ u8 psk[32];$/;" m struct:wps_context -psk1 src/wps/wps_i.h /^ u8 psk1[WPS_PSK_LEN];$/;" m struct:wps_data -psk2 src/wps/wps_i.h /^ u8 psk2[WPS_PSK_LEN];$/;" m struct:wps_data -psk_set src/wps/wps.h /^ int psk_set;$/;" m struct:wps_context -ptk src/rsn_supp/wpa.h /^ struct wpa_ptk ptk, tptk;$/;" m struct:wpa_sm typeref:struct:wpa_sm::wpa_ptk -ptk_set src/rsn_supp/wpa.h /^ int ptk_set, tptk_set;$/;" m struct:wpa_sm -pubkey_hash src/wps/wps_registrar.c /^ u8 pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN];$/;" m struct:wps_nfc_pw_token file: -public_key src/tls/x509v3.h /^ u8 *public_key;$/;" m struct:x509_certificate -public_key src/wps/wps_attr_parse.h /^ const u8 *public_key;$/;" m struct:wps_parse_attr -public_key_alg src/tls/x509v3.h /^ struct x509_algorithm_identifier public_key_alg;$/;" m struct:x509_certificate typeref:struct:x509_certificate::x509_algorithm_identifier -public_key_len src/tls/x509v3.h /^ size_t public_key_len;$/;" m struct:x509_certificate -public_key_len src/wps/wps_attr_parse.h /^ size_t public_key_len;$/;" m struct:wps_parse_attr -pw_id src/wps/wps_registrar.c /^ u16 pw_id;$/;" m struct:wps_nfc_pw_token file: -pwd_auth_fail src/wps/wps.h /^ } pwd_auth_fail;$/;" m union:wps_event_data typeref:struct:wps_event_data::wps_event_pwd_auth_fail -q src/tls/rsa.c /^ struct bignum *q; \/* prime q (factor of n) *\/$/;" m struct:crypto_rsa_key typeref:struct:crypto_rsa_key::bignum file: -qos_info src/common/ieee802_11_defs.h /^ u8 qos_info; \/* AP\/STA specif QoS info *\/$/;" m struct:wmm_parameter_element -qos_info src/common/ieee802_11_defs.h /^ u8 qos_info; \/* AP\/STA specific QoS info *\/$/;" m struct:wmm_information_element -r0_key_holder src/ap/wpa_auth.h /^ u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];$/;" m struct:wpa_auth_config -r0_key_holder_len src/ap/wpa_auth.h /^ size_t r0_key_holder_len;$/;" m struct:wpa_auth_config -r0_key_lifetime src/ap/ap_config.h /^ u32 r0_key_lifetime;$/;" m struct:hostapd_bss_config -r0_key_lifetime src/ap/wpa_auth.h /^ u32 r0_key_lifetime;$/;" m struct:wpa_auth_config -r0kh_id src/ap/wpa_auth_i.h /^ u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; \/* R0KH-ID from FT Auth Request *\/$/;" m struct:wpa_state_machine -r0kh_id_len src/ap/wpa_auth_i.h /^ size_t r0kh_id_len;$/;" m struct:wpa_state_machine -r0kh_list src/ap/ap_config.h /^ struct ft_remote_r0kh *r0kh_list;$/;" m struct:hostapd_bss_config typeref:struct:hostapd_bss_config::ft_remote_r0kh -r0kh_list src/ap/wpa_auth.h /^ struct ft_remote_r0kh *r0kh_list;$/;" m struct:wpa_auth_config typeref:struct:wpa_auth_config::ft_remote_r0kh -r1_key_holder src/ap/ap_config.h /^ u8 r1_key_holder[FT_R1KH_ID_LEN];$/;" m struct:hostapd_bss_config -r1_key_holder src/ap/wpa_auth.h /^ u8 r1_key_holder[FT_R1KH_ID_LEN];$/;" m struct:wpa_auth_config -r1kh_id src/ap/wpa_auth.h /^ u8 r1kh_id[FT_R1KH_ID_LEN]; \/* copied from pull *\/$/;" m struct:ft_r0kh_r1kh_resp_frame -r1kh_id src/ap/wpa_auth.h /^ u8 r1kh_id[FT_R1KH_ID_LEN];$/;" m struct:ft_r0kh_r1kh_pull_frame -r1kh_id src/ap/wpa_auth.h /^ u8 r1kh_id[FT_R1KH_ID_LEN];$/;" m struct:ft_r0kh_r1kh_push_frame -r1kh_list src/ap/ap_config.h /^ struct ft_remote_r1kh *r1kh_list;$/;" m struct:hostapd_bss_config typeref:struct:hostapd_bss_config::ft_remote_r1kh -r1kh_list src/ap/wpa_auth.h /^ struct ft_remote_r1kh *r1kh_list;$/;" m struct:wpa_auth_config typeref:struct:wpa_auth_config::ft_remote_r1kh -r_hash1 src/wps/wps_attr_parse.h /^ const u8 *r_hash1; \/* WPS_HASH_LEN (32) octets *\/$/;" m struct:wps_parse_attr -r_hash2 src/wps/wps_attr_parse.h /^ const u8 *r_hash2; \/* WPS_HASH_LEN (32) octets *\/$/;" m struct:wps_parse_attr -r_snonce1 src/wps/wps_attr_parse.h /^ const u8 *r_snonce1; \/* WPS_SECRET_NONCE_LEN (16) octets *\/$/;" m struct:wps_parse_attr -r_snonce2 src/wps/wps_attr_parse.h /^ const u8 *r_snonce2; \/* WPS_SECRET_NONCE_LEN (16) octets *\/$/;" m struct:wps_parse_attr -random_add_randomness include/crypto/random.h 23;" d -random_deinit include/crypto/random.h 22;" d -random_get_bytes include/crypto/random.h 24;" d -random_init include/crypto/random.h 21;" d -random_mark_pool_ready include/crypto/random.h 26;" d -random_pool_ready include/crypto/random.h 25;" d -rate src/ap/hostapd.h /^ int rate; \/* rate in 100 kbps *\/$/;" m struct:hostapd_rate_data -rc4 src/crypto/crypto_internal-cipher.c /^ } rc4;$/;" m union:crypto_cipher::__anon10 typeref:struct:crypto_cipher::__anon10::__anon11 file: -rc4 src/fast_crypto/fast_crypto_internal-cipher.c /^ } rc4;$/;" m union:fast_crypto_cipher::__anon56 typeref:struct:fast_crypto_cipher::__anon56::__anon57 file: -rc4_skip src/crypto/rc4.c /^rc4_skip(const u8 *key, size_t keylen, size_t skip,$/;" f -rcon src/crypto/aes-internal.c /^const u32 rcon[] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v -rcons src/crypto/aes-internal.c /^const u8 rcons[] \/* ICACHE_RODATA_ATTR *\/ = {$/;" v -read_cbc src/tls/tlsv1_record.h /^ struct crypto_cipher *read_cbc;$/;" m struct:tlsv1_record_layer typeref:struct:tlsv1_record_layer::crypto_cipher -read_cipher_suite src/tls/tlsv1_record.h /^ u16 read_cipher_suite;$/;" m struct:tlsv1_record_layer -read_iv src/tls/tlsv1_record.h /^ u8 read_iv[TLS_MAX_IV_LEN];$/;" m struct:tlsv1_record_layer -read_key src/tls/tlsv1_record.h /^ u8 read_key[TLS_MAX_WRITE_KEY_LEN];$/;" m struct:tlsv1_record_layer -read_mac_secret src/tls/tlsv1_record.h /^ u8 read_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];$/;" m struct:tlsv1_record_layer -read_seq_num src/tls/tlsv1_record.h /^ u8 read_seq_num[TLS_SEQ_NUM_LEN];$/;" m struct:tlsv1_record_layer -ready_for_tnc src/eap_peer/eap_ttls.c /^ int ready_for_tnc;$/;" m struct:eap_ttls_data file: -reason src/tls/tls.h /^ enum tls_fail_reason reason;$/;" m struct:tls_event_data::__anon34 typeref:enum:tls_event_data::__anon34::tls_fail_reason -reason_code src/common/ieee802_11_defs.h /^ le16 reason_code;$/;" m struct:ieee80211_mgmt::__anon66::__anon68 -reason_code src/common/ieee802_11_defs.h /^ le16 reason_code;$/;" m struct:ieee80211_mgmt::__anon66::__anon72 -reason_txt src/tls/tls.h /^ const char *reason_txt;$/;" m struct:tls_event_data::__anon34 -reassoc_deadline src/rsn_supp/wpa_ie.h /^ const u8 *reassoc_deadline;$/;" m struct:wpa_eapol_ie_parse -reassoc_req src/common/ieee802_11_defs.h /^ } STRUCT_PACKED reassoc_req;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon71 -reassoc_resp src/common/ieee802_11_defs.h /^ } STRUCT_PACKED assoc_resp, reassoc_resp;$/;" m union:ieee80211_mgmt::__anon66 typeref:struct:ieee80211_mgmt::__anon66::__anon70 -reassociation_deadline src/ap/ap_config.h /^ u32 reassociation_deadline;$/;" m struct:hostapd_bss_config -reassociation_deadline src/ap/wpa_auth.h /^ u32 reassociation_deadline;$/;" m struct:wpa_auth_config -reauth src/eap_peer/eap_peap.c /^ int reauth; \/* reauthentication *\/$/;" m struct:eap_peap_data file: -reauth src/eap_peer/eap_ttls.c /^ int reauth; \/* reauthentication *\/$/;" m struct:eap_ttls_data file: -received_version src/eap_peer/eap_tlv_common.h /^ u8 received_version;$/;" m struct:eap_tlv_crypto_binding_tlv -reg_success_cb src/wps/wps.h /^ void (*reg_success_cb)(void *ctx, const u8 *mac_addr,$/;" m struct:wps_registrar_config -reg_success_cb src/wps/wps_registrar.c /^ void (*reg_success_cb)(void *ctx, const u8 *mac_addr,$/;" m struct:wps_registrar file: -registrar src/wps/wps.h /^ int registrar;$/;" m struct:wps_config -registrar src/wps/wps.h /^ struct wps_registrar *registrar;$/;" m struct:wps_context typeref:struct:wps_context::wps_registrar -registrar src/wps/wps_i.h /^ int registrar;$/;" m struct:wps_data -registrar_nonce src/wps/wps_attr_parse.h /^ const u8 *registrar_nonce; \/* WPS_NONCE_LEN (16) octets *\/$/;" m struct:wps_parse_attr -reject_4way_hs_for_entropy src/ap/wpa_auth_i.h /^ Boolean reject_4way_hs_for_entropy;$/;" m struct:wpa_group -reload_config src/ap/hostapd.h /^ int (*reload_config)(struct hostapd_iface *iface);$/;" m struct:hapd_interfaces -renew_snonce src/rsn_supp/wpa.h /^ int renew_snonce;$/;" m struct:wpa_sm -replay_counter src/common/eapol_common.h /^ u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];$/;" m struct:ieee802_1x_eapol_key -replay_counter src/common/wpa_common.h /^ u8 replay_counter[WPA_REPLAY_COUNTER_LEN];$/;" m struct:wpa_eapol_key -req_dev_type src/wps/wps_attr_parse.h /^ const u8 *req_dev_type[MAX_REQ_DEV_TYPE_COUNT];$/;" m struct:wps_parse_attr -req_replay_counter src/ap/wpa_auth_i.h /^ u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];$/;" m struct:wpa_state_machine -req_replay_counter_used src/ap/wpa_auth_i.h /^ int req_replay_counter_used;$/;" m struct:wpa_state_machine -request_counter src/rsn_supp/wpa.h /^ u8 request_counter[WPA_REPLAY_COUNTER_LEN];$/;" m struct:wpa_sm -request_to_enroll src/wps/wps_attr_parse.h /^ const u8 *request_to_enroll; \/* 1 octet (Bool) *\/$/;" m struct:wps_parse_attr -request_type src/wps/wps_attr_parse.h /^ const u8 *request_type; \/* 1 octet *\/$/;" m struct:wps_parse_attr -request_type src/wps/wps_i.h /^ u8 request_type;$/;" m struct:wps_data -require_ht src/ap/ap_config.h /^ int require_ht;$/;" m struct:hostapd_config -require_vht src/ap/ap_config.h /^ int require_vht;$/;" m struct:hostapd_config -resend_eapol src/ap/wpa_auth_i.h /^ ETSTimer resend_eapol;$/;" m struct:wpa_state_machine -resend_eapol_handle src/ap/wpa_auth.c /^void resend_eapol_handle(void *timeout_ctx)$/;" f -reserved src/common/ieee802_11_defs.h /^ u8 reserved; \/* 0 *\/$/;" m struct:wmm_parameter_element -reserved src/eap_peer/eap_mschapv2.c /^ u8 reserved[8];$/;" m struct:ms_change_password file: -reserved src/eap_peer/eap_mschapv2.c /^ u8 reserved[8];$/;" m struct:ms_response file: -reserved src/eap_peer/eap_tlv_common.h /^ u8 reserved;$/;" m struct:eap_tlv_crypto_binding_tlv -response_type src/wps/wps_attr_parse.h /^ const u8 *response_type; \/* 1 octet *\/$/;" m struct:wps_parse_attr -result src/eap_peer/eap_tlv_common.h /^ be16 result;$/;" m struct:eap_tlv_pac_ack_tlv -resuming src/eap_peer/eap_peap.c /^ int resuming; \/* starting a resumed session *\/$/;" m struct:eap_peap_data file: -resuming src/eap_peer/eap_ttls.c /^ int resuming; \/* starting a resumed session *\/$/;" m struct:eap_ttls_data file: -ret src/esp_supplicant/esp_wps.c /^ int ret; \/* return value *\/$/;" m struct:__anon33 file: -rf_bands src/wps/wps.h /^ u8 rf_bands;$/;" m struct:wps_device_data -rf_bands src/wps/wps_attr_parse.h /^ const u8 *rf_bands; \/* 1 octet *\/$/;" m struct:wps_parse_attr -rid src/tls/x509v3.h /^ struct asn1_oid rid; \/* registeredID *\/$/;" m struct:x509_name typeref:struct:x509_name::asn1_oid -rijndaelDecrypt src/crypto/aes-internal-dec.c /^static void rijndaelDecrypt(const u32 rk[\/*44*\/], int Nr, const u8 ct[16],$/;" f file: -rijndaelEncrypt src/crypto/aes-internal-enc.c /^void rijndaelEncrypt(const u32 rk[], int Nr, const u8 pt[16], u8 ct[16])$/;" f -rijndaelKeySetupDec src/crypto/aes-internal-dec.c /^static int rijndaelKeySetupDec(u32 rk[], const u8 cipherKey[], int keyBits)$/;" f file: -rijndaelKeySetupEnc src/crypto/aes-internal.c /^int rijndaelKeySetupEnc(u32 rk[], const u8 cipherKey[], int keyBits)$/;" f -rl src/tls/tlsv1_client_i.h /^ struct tlsv1_record_layer rl;$/;" m struct:tlsv1_client typeref:struct:tlsv1_client::tlsv1_record_layer -rl src/tls/tlsv1_server_i.h /^ struct tlsv1_record_layer rl;$/;" m struct:tlsv1_server typeref:struct:tlsv1_server::tlsv1_record_layer -rol src/crypto/sha1-internal.c 132;" d file: -rotate_bits src/tls/asn1.c /^static u8 rotate_bits(u8 octet)$/;" f file: -rotr src/crypto/aes_i.h /^static inline u32 rotr(u32 val, int bits)$/;" f -rsn src/esp_supplicant/esp_wifi_driver.h /^ uint8_t *rsn;$/;" m struct:wps_scan_ie -rsn_cipher_put_suites src/common/wpa_common.c /^int rsn_cipher_put_suites(u8 *pos, int ciphers)$/;" f -rsn_enabled src/rsn_supp/wpa.h /^ int rsn_enabled; \/* Whether RSN is enabled in configuration *\/$/;" m struct:wpa_sm -rsn_error_kde src/common/wpa_common.h /^struct rsn_error_kde {$/;" s -rsn_ftie src/common/wpa_common.h /^struct rsn_ftie {$/;" s -rsn_ie src/ap/wpa_auth_ie.h /^ const u8 *rsn_ie;$/;" m struct:wpa_eapol_ie_parse -rsn_ie src/rsn_supp/wpa_ie.h /^ const u8 *rsn_ie;$/;" m struct:wpa_eapol_ie_parse -rsn_ie_hdr src/common/wpa_common.h /^struct rsn_ie_hdr {$/;" s -rsn_ie_len src/ap/wpa_auth_ie.h /^ size_t rsn_ie_len;$/;" m struct:wpa_eapol_ie_parse -rsn_ie_len src/rsn_supp/wpa_ie.h /^ size_t rsn_ie_len;$/;" m struct:wpa_eapol_ie_parse -rsn_key_mgmt_to_bitfield src/common/wpa_common.c /^static int rsn_key_mgmt_to_bitfield(const u8 *s)$/;" f file: -rsn_mdie src/common/wpa_common.h /^struct rsn_mdie {$/;" s -rsn_pairwise src/ap/ap_config.h /^ int rsn_pairwise;$/;" m struct:hostapd_bss_config -rsn_pairwise src/ap/wpa_auth.h /^ int rsn_pairwise;$/;" m struct:wpa_auth_config -rsn_pmkid src/common/wpa_common.c /^void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,$/;" f -rsn_preauth src/ap/ap_config.h /^ int rsn_preauth;$/;" m struct:hostapd_bss_config -rsn_preauth src/ap/wpa_auth.h /^ int rsn_preauth;$/;" m struct:wpa_auth_config -rsn_preauth_interfaces src/ap/ap_config.h /^ char *rsn_preauth_interfaces;$/;" m struct:hostapd_bss_config -rsn_rdie src/common/wpa_common.h /^struct rsn_rdie {$/;" s -rsn_selector_to_bitfield src/common/wpa_common.c /^static int rsn_selector_to_bitfield(const u8 *s)$/;" f file: -rsn_testing src/ap/wpa_auth_ie.c /^int rsn_testing = 0;$/;" v -rts_threshold src/ap/ap_config.h /^ int rts_threshold;$/;" m struct:hostapd_config -rx_eapol_key_secure src/ap/wpa_auth_i.h /^ unsigned int rx_eapol_key_secure:1;$/;" m struct:wpa_state_machine -rx_mic_key src/common/wpa_common.h /^ u8 rx_mic_key[8];$/;" m struct:wpa_ptk::__anon62::__anon63 -rx_replay_counter src/rsn_supp/wpa.h /^ u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];$/;" m struct:wpa_sm -rx_replay_counter_set src/rsn_supp/wpa.h /^ int rx_replay_counter_set;$/;" m struct:wpa_sm -s16 include/utils/common.h /^typedef int16_t s16;$/;" t -s1kh_id src/ap/wpa_auth.h /^ u8 s1kh_id[ETH_ALEN]; \/* copied from pull *\/$/;" m struct:ft_r0kh_r1kh_resp_frame -s1kh_id src/ap/wpa_auth.h /^ u8 s1kh_id[ETH_ALEN];$/;" m struct:ft_r0kh_r1kh_pull_frame -s1kh_id src/ap/wpa_auth.h /^ u8 s1kh_id[ETH_ALEN];$/;" m struct:ft_r0kh_r1kh_push_frame -s32 include/utils/common.h /^typedef int32_t s32;$/;" t -s64 include/utils/common.h /^typedef int64_t s64;$/;" t -s8 include/utils/common.h /^typedef int8_t s8;$/;" t -s_factory_info src/esp_supplicant/esp_wps.c /^static wps_factory_information_t *s_factory_info = NULL;$/;" v file: -s_mp_add src/crypto/libtommath.h /^s_mp_add (mp_int * a, mp_int * b, mp_int * c)$/;" f -s_mp_add src/tls/libtommath.h /^s_mp_add (mp_int * a, mp_int * b, mp_int * c)$/;" f -s_mp_exptmod src/crypto/libtommath.h /^s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)$/;" f -s_mp_exptmod src/tls/libtommath.h /^s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)$/;" f -s_mp_mul src/crypto/libtommath.h 132;" d -s_mp_mul src/tls/libtommath.h 134;" d -s_mp_mul_digs src/crypto/libtommath.h /^s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)$/;" f -s_mp_mul_digs src/tls/libtommath.h /^s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)$/;" f -s_mp_mul_high_digs src/crypto/libtommath.h /^s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)$/;" f -s_mp_mul_high_digs src/tls/libtommath.h /^s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)$/;" f -s_mp_sqr src/crypto/libtommath.h /^s_mp_sqr (mp_int * a, mp_int * b)$/;" f -s_mp_sqr src/tls/libtommath.h /^s_mp_sqr (mp_int * a, mp_int * b)$/;" f -s_mp_sub src/crypto/libtommath.h /^s_mp_sub (mp_int * a, mp_int * b, mp_int * c)$/;" f -s_mp_sub src/tls/libtommath.h /^s_mp_sub (mp_int * a, mp_int * b, mp_int * c)$/;" f -s_sm_table src/ap/wpa_auth.c /^static void *s_sm_table[WPA_SM_MAX_INDEX];$/;" v file: -s_sm_valid_bitmap src/ap/wpa_auth.c /^static u32 s_sm_valid_bitmap = 0;$/;" v file: -s_wps_api_lock src/esp_supplicant/esp_wps.c /^static void *s_wps_api_lock = NULL; \/* Used in WPS public API only, never be freed *\/$/;" v file: -s_wps_api_sem src/esp_supplicant/esp_wps.c /^static void *s_wps_api_sem = NULL; \/* Sync semaphore used between WPS publi API caller task and WPS task *\/$/;" v file: -s_wps_data_lock src/esp_supplicant/esp_wps.c /^static void *s_wps_data_lock = NULL;$/;" v file: -s_wps_enabled src/esp_supplicant/esp_wps.c /^static bool s_wps_enabled = false;$/;" v file: -s_wps_sig_cnt src/esp_supplicant/esp_wps.c /^static uint8_t s_wps_sig_cnt[SIG_WPS_NUM] = {0};$/;" v file: -s_wps_task_create_sem src/esp_supplicant/esp_wps.c /^static void *s_wps_task_create_sem = NULL;$/;" v file: -sa src/common/ieee802_11_defs.h /^ u8 sa[6];$/;" m struct:ieee80211_mgmt -sa src/esp_supplicant/esp_wpa_enterprise.c /^ u8 sa[WPA_ADDR_LEN];$/;" m struct:wpa2_rx_param file: -sa src/esp_supplicant/esp_wps.c /^ u8 sa[WPS_ADDR_LEN];$/;" m struct:wps_rx_param file: -sa_query_count src/ap/sta_info.h /^ int sa_query_count; \/* number of pending SA Query requests;$/;" m struct:sta_info -sa_query_req src/common/ieee802_11_defs.h /^ } STRUCT_PACKED sa_query_req;$/;" m union:ieee80211_mgmt::__anon66::__anon76::__anon77 typeref:struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon82 -sa_query_resp src/common/ieee802_11_defs.h /^ } STRUCT_PACKED sa_query_resp;$/;" m union:ieee80211_mgmt::__anon66::__anon76::__anon77 typeref:struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon83 -sa_query_start src/ap/sta_info.h /^ struct os_time sa_query_start;$/;" m struct:sta_info typeref:struct:sta_info::os_time -sa_query_timed_out src/ap/sta_info.h /^ int sa_query_timed_out;$/;" m struct:sta_info -sa_query_trans_id src/ap/sta_info.h /^ u8 *sa_query_trans_id; \/* buffer of WLAN_SA_QUERY_TR_ID_LEN *$/;" m struct:sta_info -sae_send_confirm src/ap/sta_info.h /^ u16 sae_send_confirm;$/;" m struct:sta_info -sae_state src/ap/sta_info.h /^ enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state;$/;" m struct:sta_info typeref:enum:sta_info::__anon16 -salt src/tls/pkcs5.c /^ u8 salt[8];$/;" m struct:pkcs5_params file: -salt_len src/tls/pkcs5.c /^ size_t salt_len;$/;" m struct:pkcs5_params file: -scan_cnt src/wps/wps.h /^ u8 scan_cnt;$/;" m struct:wps_sm -search_tag src/tls/tlsv1_cred.c /^static const u8 * search_tag(const char *tag, const u8 *buf, size_t len)$/;" f file: -sec port/include/os.h /^ os_time_t sec;$/;" m struct:os_time -sec_dev_type src/wps/wps.h /^ u8 sec_dev_type[WPS_SEC_DEVICE_TYPES][WPS_DEV_TYPE_LEN];$/;" m struct:wps_device_data -sec_dev_type_list src/wps/wps_attr_parse.h /^ const u8 *sec_dev_type_list; \/* <= 128 octets *\/$/;" m struct:wps_parse_attr -sec_dev_type_list_len src/wps/wps_attr_parse.h /^ size_t sec_dev_type_list_len;$/;" m struct:wps_parse_attr -secondary_channel src/ap/ap_config.h /^ int secondary_channel;$/;" m struct:hostapd_config -secpolicy src/ap/ap_config.h /^} secpolicy;$/;" t typeref:enum:hostap_security_policy -sel_reg src/wps/wps.h /^ int sel_reg;$/;" m struct:wps_event_data::wps_event_er_set_selected_registrar -sel_reg_config_methods src/wps/wps.h /^ u16 sel_reg_config_methods;$/;" m struct:wps_event_data::wps_event_er_set_selected_registrar -sel_reg_config_methods src/wps/wps_attr_parse.h /^ const u8 *sel_reg_config_methods; \/* 2 octets *\/$/;" m struct:wps_parse_attr -sel_reg_config_methods_override src/wps/wps_registrar.c /^ int sel_reg_config_methods_override;$/;" m struct:wps_registrar file: -sel_reg_dev_password_id_override src/wps/wps_registrar.c /^ int sel_reg_dev_password_id_override;$/;" m struct:wps_registrar file: -sel_reg_union src/wps/wps_registrar.c /^ int sel_reg_union;$/;" m struct:wps_registrar file: -selected_registrar src/wps/wps_attr_parse.h /^ const u8 *selected_registrar; \/* 1 octet (Bool) *\/$/;" m struct:wps_parse_attr -selected_registrar src/wps/wps_registrar.c /^ int selected_registrar;$/;" m struct:wps_registrar file: -send_eapol src/ap/wpa_auth.h /^ int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data,$/;" m struct:wpa_auth_callbacks -send_ether src/ap/wpa_auth.h /^ int (*send_ether)(void *ctx, const u8 *dst, u16 proto, const u8 *data,$/;" m struct:wpa_auth_callbacks -send_ft_action src/ap/wpa_auth.h /^ int (*send_ft_action)(void *ctx, const u8 *dst,$/;" m struct:wpa_auth_callbacks -send_probe_response src/ap/ap_config.h /^ u8 send_probe_response;$/;" m struct:hostapd_config -sendto src/rsn_supp/wpa.h /^ void (* sendto) (void *buffer, uint16_t len);$/;" m struct:wpa_sm -seq src/rsn_supp/wpa.h /^ u8 seq[10];$/;" m struct:install_key -seq_ctrl src/common/ieee802_11_defs.h /^ le16 seq_ctrl;$/;" m struct:ieee80211_hdr -seq_ctrl src/common/ieee802_11_defs.h /^ le16 seq_ctrl;$/;" m struct:ieee80211_mgmt -serial_number src/ap/ap_config.h /^ char *serial_number;$/;" m struct:hostapd_bss_config -serial_number src/tls/x509v3.h /^ unsigned long serial_number;$/;" m struct:x509_certificate -serial_number src/wps/wps.h /^ const char *serial_number;$/;" m struct:wps_event_data::wps_event_er_ap -serial_number src/wps/wps.h /^ const char *serial_number;$/;" m struct:wps_event_data::wps_event_er_enrollee -serial_number src/wps/wps.h /^ const u8 *serial_number;$/;" m struct:wps_event_data::wps_event_m2d -serial_number src/wps/wps.h /^ char *serial_number;$/;" m struct:wps_device_data -serial_number src/wps/wps_attr_parse.h /^ const u8 *serial_number;$/;" m struct:wps_parse_attr -serial_number_len src/wps/wps.h /^ size_t serial_number_len;$/;" m struct:wps_event_data::wps_event_m2d -serial_number_len src/wps/wps_attr_parse.h /^ size_t serial_number_len;$/;" m struct:wps_parse_attr -server src/tls/tls_internal.c /^ int server;$/;" m struct:tls_global file: -server src/tls/tls_internal.c /^ struct tlsv1_server *server;$/;" m struct:tls_connection typeref:struct:tls_connection::tlsv1_server file: -server_cred src/tls/tls_internal.c /^ struct tlsv1_credentials *server_cred;$/;" m struct:tls_global typeref:struct:tls_global::tlsv1_credentials file: -server_random src/tls/tls.h /^ const u8 *server_random;$/;" m struct:tls_keys -server_random src/tls/tlsv1_client_i.h /^ u8 server_random[TLS_RANDOM_LEN];$/;" m struct:tlsv1_client -server_random src/tls/tlsv1_server_i.h /^ u8 server_random[TLS_RANDOM_LEN];$/;" m struct:tlsv1_server -server_random_len src/tls/tls.h /^ size_t server_random_len;$/;" m struct:tls_keys -server_rsa_key src/tls/tlsv1_client_i.h /^ struct crypto_public_key *server_rsa_key;$/;" m struct:tlsv1_client typeref:struct:tlsv1_client::crypto_public_key -service_start_time src/common/ieee802_11_defs.h /^ le32 service_start_time;$/;" m struct:wmm_tspec_element -session_id src/eap_peer/eap_peap.c /^ u8 *session_id;$/;" m struct:eap_peap_data file: -session_id src/eap_peer/eap_tls.c /^ u8 *session_id;$/;" m struct:eap_tls_data file: -session_id src/eap_peer/eap_ttls.c /^ u8 *session_id;$/;" m struct:eap_ttls_data file: -session_id src/tls/tlsv1_client_i.h /^ u8 session_id[TLS_SESSION_ID_MAX_LEN];$/;" m struct:tlsv1_client -session_id src/tls/tlsv1_server_i.h /^ u8 session_id[TLS_SESSION_ID_MAX_LEN];$/;" m struct:tlsv1_server -session_id_len src/tls/tlsv1_client_i.h /^ size_t session_id_len;$/;" m struct:tlsv1_client -session_id_len src/tls/tlsv1_server_i.h /^ size_t session_id_len;$/;" m struct:tlsv1_server -session_resumed src/tls/tlsv1_client_i.h /^ unsigned int session_resumed:1;$/;" m struct:tlsv1_client -session_ticket src/tls/tlsv1_server_i.h /^ u8 *session_ticket;$/;" m struct:tlsv1_server -session_ticket_cb src/tls/tlsv1_client_i.h /^ tlsv1_client_session_ticket_cb session_ticket_cb;$/;" m struct:tlsv1_client -session_ticket_cb src/tls/tlsv1_server_i.h /^ tlsv1_server_session_ticket_cb session_ticket_cb;$/;" m struct:tlsv1_server -session_ticket_cb_ctx src/tls/tlsv1_client_i.h /^ void *session_ticket_cb_ctx;$/;" m struct:tlsv1_client -session_ticket_cb_ctx src/tls/tlsv1_server_i.h /^ void *session_ticket_cb_ctx;$/;" m struct:tlsv1_server -session_ticket_included src/tls/tlsv1_client_i.h /^ unsigned int session_ticket_included:1;$/;" m struct:tlsv1_client -session_ticket_len src/tls/tlsv1_server_i.h /^ size_t session_ticket_len;$/;" m struct:tlsv1_server -set_assoc_ie src/rsn_supp/wpa.c /^set_assoc_ie(u8 * assoc_buf)$/;" f -set_eapol src/ap/wpa_auth.h /^ void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var,$/;" m struct:wpa_auth_callbacks -set_ie_cb src/wps/wps.h /^ int (*set_ie_cb)(void *ctx, struct wpabuf *beacon_ie,$/;" m struct:wps_registrar_config -set_ie_cb src/wps/wps_registrar.c /^ int (*set_ie_cb)(void *ctx, struct wpabuf *beacon_ie,$/;" m struct:wps_registrar file: -set_key src/ap/wpa_auth.h /^ int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg,$/;" m struct:wpa_auth_callbacks -set_sel_reg src/wps/wps.h /^ } set_sel_reg;$/;" m union:wps_event_data typeref:struct:wps_event_data::wps_event_er_set_selected_registrar -set_sel_reg_cb src/wps/wps.h /^ void (*set_sel_reg_cb)(void *ctx, int sel_reg, u16 dev_passwd_id,$/;" m struct:wps_registrar_config -set_sel_reg_cb src/wps/wps_registrar.c /^ void (*set_sel_reg_cb)(void *ctx, int sel_reg, u16 dev_passwd_id,$/;" m struct:wps_registrar file: -set_tx src/rsn_supp/wpa.h /^ int set_tx;$/;" m struct:install_key -settings_delay_time src/wps/wps_attr_parse.h /^ const u8 *settings_delay_time; \/* 1 octet *\/$/;" m struct:wps_parse_attr -sha1 src/crypto/crypto_internal.c /^ struct SHA1Context sha1;$/;" m union:crypto_hash::__anon9 typeref:struct:crypto_hash::__anon9::SHA1Context file: -sha1 src/fast_crypto/fast_crypto_internal.c /^ struct SHA1Context sha1;$/;" m union:fast_crypto_hash::__anon61 typeref:struct:fast_crypto_hash::__anon61::SHA1Context file: -sha1_cert src/tls/tlsv1_common.h /^ struct crypto_hash *sha1_cert;$/;" m struct:tls_verify_hash typeref:struct:tls_verify_hash::crypto_hash -sha1_client src/tls/tlsv1_common.h /^ struct crypto_hash *sha1_client;$/;" m struct:tls_verify_hash typeref:struct:tls_verify_hash::crypto_hash -sha1_prf src/crypto/sha1.c /^sha1_prf(const u8 *key, size_t key_len, const char *label,$/;" f -sha1_server src/tls/tlsv1_common.h /^ struct crypto_hash *sha1_server;$/;" m struct:tls_verify_hash typeref:struct:tls_verify_hash::crypto_hash -sha1_vector src/crypto/sha1-internal.c /^sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)$/;" f -sha256 src/crypto/crypto_internal.c /^ struct sha256_state sha256;$/;" m union:crypto_hash::__anon9 typeref:struct:crypto_hash::__anon9::sha256_state file: -sha256 src/fast_crypto/fast_crypto_internal.c /^ mbedtls_sha256_context sha256;$/;" m union:fast_crypto_hash::__anon61 file: -sha256_cert src/tls/tlsv1_common.h /^ struct crypto_hash *sha256_cert;$/;" m struct:tls_verify_hash typeref:struct:tls_verify_hash::crypto_hash -sha256_client src/tls/tlsv1_common.h /^ struct crypto_hash *sha256_client;$/;" m struct:tls_verify_hash typeref:struct:tls_verify_hash::crypto_hash -sha256_compress src/crypto/sha256-internal.c /^sha256_compress(struct sha256_state *md, unsigned char *buf)$/;" f file: -sha256_done src/crypto/sha256-internal.c /^sha256_done(struct sha256_state *md, unsigned char *out)$/;" f file: -sha256_init src/crypto/sha256-internal.c /^sha256_init(struct sha256_state *md)$/;" f file: -sha256_prf src/crypto/sha256.c /^sha256_prf(const u8 *key, size_t key_len, const char *label,$/;" f -sha256_process src/crypto/sha256-internal.c /^sha256_process(struct sha256_state *md, const unsigned char *in,$/;" f file: -sha256_server src/tls/tlsv1_common.h /^ struct crypto_hash *sha256_server;$/;" m struct:tls_verify_hash typeref:struct:tls_verify_hash::crypto_hash -sha256_state src/crypto/sha256-internal.c /^struct sha256_state {$/;" s file: -sha256_vector src/crypto/sha256-internal.c /^sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,$/;" f -sign src/crypto/libtommath.h /^ int used, alloc, sign;$/;" m struct:__anon8 -sign src/tls/libtommath.h /^ int used, alloc, sign;$/;" m struct:__anon40 -sign_value src/tls/x509v3.h /^ u8 *sign_value;$/;" m struct:x509_certificate -sign_value_len src/tls/x509v3.h /^ size_t sign_value_len;$/;" m struct:x509_certificate -signature src/tls/x509v3.h /^ struct x509_algorithm_identifier signature;$/;" m struct:x509_certificate typeref:struct:x509_certificate::x509_algorithm_identifier -signature_alg src/tls/x509v3.h /^ struct x509_algorithm_identifier signature_alg;$/;" m struct:x509_certificate typeref:struct:x509_certificate::x509_algorithm_identifier -size include/utils/wpabuf.h /^ size_t size; \/* total size of the allocated buffer *\/$/;" m struct:wpabuf -skip_cred_build src/ap/ap_config.h /^ int skip_cred_build;$/;" m struct:hostapd_bss_config -skip_cred_build src/wps/wps.h /^ int skip_cred_build;$/;" m struct:wps_registrar_config -skip_cred_build src/wps/wps_registrar.c /^ int skip_cred_build;$/;" m struct:wps_registrar file: -smk src/ap/wpa_auth_ie.h /^ const u8 *smk;$/;" m struct:wpa_eapol_ie_parse -smk src/rsn_supp/wpa_ie.h /^ const u8 *smk;$/;" m struct:wpa_eapol_ie_parse -smk_len src/ap/wpa_auth_ie.h /^ size_t smk_len;$/;" m struct:wpa_eapol_ie_parse -smk_len src/rsn_supp/wpa_ie.h /^ size_t smk_len;$/;" m struct:wpa_eapol_ie_parse -snonce src/common/wpa_common.h /^ u8 snonce[WPA_NONCE_LEN];$/;" m struct:rsn_ftie -snonce src/rsn_supp/wpa.h /^ u8 snonce[WPA_NONCE_LEN];$/;" m struct:wpa_sm -snonce src/wps/wps_i.h /^ u8 snonce[2 * WPS_SECRET_NONCE_LEN];$/;" m struct:wps_data -soh src/eap_peer/eap_peap.c /^ int soh; \/* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP)$/;" m struct:eap_peap_data file: -ssi_signal src/ap/hostapd.h /^ int ssi_signal; \/* dBm *\/$/;" m struct:hostapd_frame_info -ssid src/ap/ap_config.h /^ struct hostapd_ssid ssid;$/;" m struct:hostapd_bss_config typeref:struct:hostapd_bss_config::hostapd_ssid -ssid src/ap/ap_config.h /^ u8 ssid[HOSTAPD_MAX_SSID_LEN];$/;" m struct:hostapd_ssid -ssid src/ap/sta_info.h /^ struct hostapd_ssid *ssid; \/* SSID selection based on (Re)AssocReq *\/$/;" m struct:sta_info typeref:struct:sta_info::hostapd_ssid -ssid src/ap/wpa_auth.h /^ u8 ssid[SSID_LEN];$/;" m struct:wpa_auth_config -ssid src/esp_supplicant/esp_wifi_driver.h /^ uint8_t *ssid;$/;" m struct:wps_scan_ie -ssid src/esp_supplicant/esp_wifi_driver.h /^ uint8_t ssid[32];$/;" m struct:wifi_ssid -ssid src/wps/wps.h /^ u8 ssid[32];$/;" m struct:wps_context -ssid src/wps/wps.h /^ u8 ssid[32];$/;" m struct:wps_credential -ssid src/wps/wps.h /^ u8 ssid[32];$/;" m struct:wps_sm -ssid src/wps/wps_attr_parse.h /^ const u8 *ssid; \/* <= 32 octets *\/$/;" m struct:wps_parse_attr -ssid_len src/ap/ap_config.h /^ size_t ssid_len;$/;" m struct:hostapd_ssid -ssid_len src/ap/wpa_auth.h /^ size_t ssid_len;$/;" m struct:wpa_auth_config -ssid_len src/wps/wps.h /^ size_t ssid_len;$/;" m struct:wps_context -ssid_len src/wps/wps.h /^ size_t ssid_len;$/;" m struct:wps_credential -ssid_len src/wps/wps.h /^ u8 ssid_len;$/;" m struct:wps_sm -ssid_len src/wps/wps_attr_parse.h /^ size_t ssid_len;$/;" m struct:wps_parse_attr -ssid_set src/ap/ap_config.h /^ unsigned int ssid_set:1;$/;" m struct:hostapd_ssid -ssl src/eap_peer/eap_peap.c /^ struct eap_ssl_data ssl;$/;" m struct:eap_peap_data typeref:struct:eap_peap_data::eap_ssl_data file: -ssl src/eap_peer/eap_tls.c /^ struct eap_ssl_data ssl;$/;" m struct:eap_tls_data typeref:struct:eap_tls_data::eap_ssl_data file: -ssl src/eap_peer/eap_ttls.c /^ struct eap_ssl_data ssl;$/;" m struct:eap_ttls_data typeref:struct:eap_ttls_data::eap_ssl_data file: -ssl_ctx src/eap_peer/eap_i.h /^ void *ssl_ctx;$/;" m struct:eap_sm -ssl_ctx src/eap_peer/eap_tls.c /^ void *ssl_ctx;$/;" m struct:eap_tls_data file: -ssl_ctx src/eap_peer/eap_tls_common.h /^ void *ssl_ctx;$/;" m struct:eap_ssl_data -st_cb src/wps/wps.h /^ wps_st_cb_t st_cb;$/;" m struct:wps_sm -sta_addr src/common/ieee802_11_defs.h /^ u8 sta_addr[ETH_ALEN];$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon80 -sta_addr src/common/ieee802_11_defs.h /^ u8 sta_addr[ETH_ALEN];$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon81 -sta_info src/ap/sta_info.h /^struct sta_info {$/;" s -started src/ap/wpa_auth_i.h /^ unsigned int started:1;$/;" m struct:wpa_state_machine -state src/crypto/md4-internal.c /^ u32 state[4];$/;" m struct:MD4Context file: -state src/crypto/sha1_i.h /^ u32 state[5];$/;" m struct:SHA1Context -state src/crypto/sha256-internal.c /^ u32 state[8], curlen;$/;" m struct:sha256_state file: -state src/tls/tlsv1_client_i.h /^ } state;$/;" m struct:tlsv1_client typeref:enum:tlsv1_client::__anon43 -state src/tls/tlsv1_server_i.h /^ } state;$/;" m struct:tlsv1_server typeref:enum:tlsv1_server::__anon39 -state src/wps/wps.h /^ } state;$/;" m struct:wps_event_data::wps_event_er_set_selected_registrar typeref:enum:wps_event_data::wps_event_er_set_selected_registrar::__anon54 -state src/wps/wps_i.h /^ } state;$/;" m struct:wps_data typeref:enum:wps_data::__anon53 -static_wep_only src/wps/wps.h /^ int static_wep_only;$/;" m struct:wps_registrar_config -static_wep_only src/wps/wps_registrar.c /^ int static_wep_only;$/;" m struct:wps_registrar file: -status src/eap_peer/eap_tlv_common.h /^ be16 status;$/;" m struct:eap_tlv_intermediate_result_tlv -status src/eap_peer/eap_tlv_common.h /^ be16 status;$/;" m struct:eap_tlv_result_tlv -status_code src/common/ieee802_11_defs.h /^ le16 status_code;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon81 -status_code src/common/ieee802_11_defs.h /^ u8 status_code;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon78 -status_code src/common/ieee802_11_defs.h /^ le16 status_code;$/;" m struct:ieee80211_mgmt::__anon66::__anon67 -status_code src/common/ieee802_11_defs.h /^ le16 status_code;$/;" m struct:ieee80211_mgmt::__anon66::__anon70 -status_code src/common/wpa_common.h /^ le16 status_code;$/;" m struct:rsn_rdie -stbc_param src/common/ieee802_11_defs.h /^ le16 stbc_param;$/;" m struct:ieee80211_ht_operation -subject src/tls/tls.h /^ const char *subject;$/;" m struct:tls_event_data::__anon34 -subject src/tls/tls.h /^ const char *subject;$/;" m struct:tls_event_data::__anon35 -subject src/tls/x509v3.h /^ struct x509_name subject;$/;" m struct:x509_certificate typeref:struct:x509_certificate::x509_name -subject_match src/tls/tls.h /^ const char *subject_match;$/;" m struct:tls_connection_params -subtype src/eap_peer/eap_tlv_common.h /^ u8 subtype;$/;" m struct:eap_tlv_crypto_binding_tlv -success src/eap_peer/eap_mschapv2.c /^ int success;$/;" m struct:eap_mschapv2_data file: -suite src/tls/tlsv1_common.h /^ u16 suite;$/;" m struct:tls_cipher_suite -sup_pmk_r1_name src/ap/wpa_auth_i.h /^ u8 sup_pmk_r1_name[WPA_PMK_NAME_LEN]; \/* PMKR1Name from EAPOL-Key$/;" m struct:wpa_state_machine -supported_mcs_set src/common/ieee802_11_defs.h /^ u8 supported_mcs_set[16];$/;" m struct:ieee80211_ht_capabilities -supported_rates src/ap/ap_config.h /^ int *supported_rates;$/;" m struct:hostapd_config -supported_rates src/ap/sta_info.h /^ u8 supported_rates[WLAN_SUPP_RATES_MAX];$/;" m struct:sta_info -supported_rates_len src/ap/sta_info.h /^ int supported_rates_len;$/;" m struct:sta_info -surplus_bandwidth_allowance src/common/ieee802_11_defs.h /^ le16 surplus_bandwidth_allowance;$/;" m struct:wmm_tspec_element -suspension_interval src/common/ieee802_11_defs.h /^ le32 suspension_interval;$/;" m struct:wmm_tspec_element -switch_count src/common/ieee802_11_defs.h /^ u8 switch_count;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon79 -switch_mode src/common/ieee802_11_defs.h /^ u8 switch_mode;$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon79 -tag src/tls/asn1.h /^ unsigned int tag, length;$/;" m struct:asn1_hdr -target_ap_addr src/common/ieee802_11_defs.h /^ u8 target_ap_addr[ETH_ALEN];$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon80 -target_ap_addr src/common/ieee802_11_defs.h /^ u8 target_ap_addr[ETH_ALEN];$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon81 -tbs_cert_len src/tls/x509v3.h /^ size_t tbs_cert_len;$/;" m struct:x509_certificate -tbs_cert_start src/tls/x509v3.h /^ const u8 *tbs_cert_start;$/;" m struct:x509_certificate -timeout_next src/ap/sta_info.h /^ } timeout_next;$/;" m struct:sta_info typeref:enum:sta_info::__anon15 -timestamp src/ap/wpa_auth.h /^ u8 timestamp[4]; \/* current time in seconds since unix epoch, little$/;" m struct:ft_r0kh_r1kh_push_frame -timestamp src/common/ieee802_11_defs.h /^ u8 timestamp[8];$/;" m struct:ieee80211_mgmt::__anon66::__anon73 -timestamp src/common/ieee802_11_defs.h /^ u8 timestamp[8];$/;" m struct:ieee80211_mgmt::__anon66::__anon75 -timestamp src/wps/wps_registrar.c /^ struct os_time timestamp;$/;" m struct:wps_pbc_session typeref:struct:wps_pbc_session::os_time file: -tk1 src/common/wpa_common.h /^ u8 tk1[16]; \/* Temporal Key 1 (TK1) *\/$/;" m struct:wpa_ptk -tk2 src/common/wpa_common.h /^ u8 tk2[16]; \/* Temporal Key 2 (TK2) *\/$/;" m union:wpa_ptk::__anon62 -tls_alert src/tls/tlsv1_client.c /^void tls_alert(struct tlsv1_client *conn, u8 level, u8 description)$/;" f -tls_capabilities src/tls/tls_internal.c /^unsigned int tls_capabilities(void *tls_ctx)$/;" f -tls_cipher src/tls/tlsv1_common.h /^} tls_cipher;$/;" t typeref:enum:__anon50 -tls_cipher_data src/tls/tlsv1_common.h /^struct tls_cipher_data {$/;" s -tls_cipher_suite src/tls/tlsv1_common.h /^struct tls_cipher_suite {$/;" s -tls_cipher_suites src/tls/tlsv1_common.c /^static const struct tls_cipher_suite tls_cipher_suites[] = {$/;" v typeref:struct:tls_cipher_suite file: -tls_cipher_type src/tls/tlsv1_common.h /^} tls_cipher_type;$/;" t typeref:enum:__anon52 -tls_ciphers src/tls/tlsv1_common.c /^static const struct tls_cipher_data tls_ciphers[] = {$/;" v typeref:struct:tls_cipher_data file: -tls_client_cert_chain_der_len src/tls/tlsv1_client_write.c /^static size_t tls_client_cert_chain_der_len(struct tlsv1_client *conn)$/;" f file: -tls_config src/tls/tls.h /^struct tls_config {$/;" s -tls_connection src/tls/tls_internal.c /^struct tls_connection {$/;" s file: -tls_connection_client_hello_ext src/tls/tls_internal.c /^int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,$/;" f -tls_connection_decrypt src/tls/tls_internal.c /^struct wpabuf * tls_connection_decrypt(void *tls_ctx,$/;" f -tls_connection_decrypt2 src/tls/tls_internal.c /^struct wpabuf * tls_connection_decrypt2(void *tls_ctx,$/;" f -tls_connection_deinit src/tls/tls_internal.c /^void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)$/;" f -tls_connection_enable_workaround src/tls/tls_internal.c /^int tls_connection_enable_workaround(void *tls_ctx,$/;" f -tls_connection_encrypt src/tls/tls_internal.c /^struct wpabuf * tls_connection_encrypt(void *tls_ctx,$/;" f -tls_connection_established src/tls/tls_internal.c /^int tls_connection_established(void *tls_ctx, struct tls_connection *conn)$/;" f -tls_connection_get_failed src/tls/tls_internal.c /^int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)$/;" f -tls_connection_get_keyblock_size src/tls/tls_internal.c /^int tls_connection_get_keyblock_size(void *tls_ctx,$/;" f -tls_connection_get_keys src/tls/tls_internal.c /^int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,$/;" f -tls_connection_get_read_alerts src/tls/tls_internal.c /^int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)$/;" f -tls_connection_get_write_alerts src/tls/tls_internal.c /^int tls_connection_get_write_alerts(void *tls_ctx,$/;" f -tls_connection_handshake src/tls/tls_internal.c /^struct wpabuf * tls_connection_handshake(void *tls_ctx,$/;" f -tls_connection_handshake2 src/tls/tls_internal.c /^struct wpabuf * tls_connection_handshake2(void *tls_ctx,$/;" f -tls_connection_init src/tls/tls_internal.c /^struct tls_connection * tls_connection_init(void *tls_ctx)$/;" f -tls_connection_params src/tls/tls.h /^struct tls_connection_params {$/;" s -tls_connection_prf src/tls/tls_internal.c /^int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,$/;" f -tls_connection_resumed src/tls/tls_internal.c /^int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)$/;" f -tls_connection_server_handshake src/tls/tls_internal.c /^struct wpabuf * tls_connection_server_handshake(void *tls_ctx,$/;" f -tls_connection_set_cipher_list src/tls/tls_internal.c /^int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,$/;" f -tls_connection_set_params src/tls/tls_internal.c /^int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,$/;" f -tls_connection_set_session_ticket_cb src/tls/tls_internal.c /^int tls_connection_set_session_ticket_cb(void *tls_ctx,$/;" f -tls_connection_set_verify src/tls/tls_internal.c /^int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,$/;" f -tls_connection_shutdown src/tls/tls_internal.c /^int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)$/;" f -tls_deinit src/tls/tls_internal.c /^void tls_deinit(void *ssl_ctx)$/;" f -tls_derive_keys src/tls/tlsv1_client.c /^int tls_derive_keys(struct tlsv1_client *conn,$/;" f -tls_derive_pre_master_secret src/tls/tlsv1_client.c /^int tls_derive_pre_master_secret(u8 *pre_master_secret)$/;" f -tls_event src/tls/tls.h /^enum tls_event {$/;" g -tls_event_data src/tls/tls.h /^union tls_event_data {$/;" u -tls_fail_reason src/tls/tls.h /^enum tls_fail_reason {$/;" g -tls_get_cipher src/tls/tls_internal.c /^int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,$/;" f -tls_get_cipher_data src/tls/tlsv1_common.c /^const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher)$/;" f -tls_get_cipher_suite src/tls/tlsv1_common.c /^const struct tls_cipher_suite * tls_get_cipher_suite(u16 suite)$/;" f -tls_get_errors src/tls/tls_internal.c /^int tls_get_errors(void *tls_ctx)$/;" f -tls_global src/tls/tls_internal.c /^struct tls_global {$/;" s file: -tls_global_set_params src/tls/tls_internal.c /^int tls_global_set_params(void *tls_ctx,$/;" f -tls_global_set_verify src/tls/tls_internal.c /^int tls_global_set_verify(void *tls_ctx, int check_crl)$/;" f -tls_hash src/tls/tlsv1_common.h /^} tls_hash;$/;" t typeref:enum:__anon51 -tls_in src/eap_peer/eap_tls_common.h /^ struct wpabuf *tls_in;$/;" m struct:eap_ssl_data typeref:struct:eap_ssl_data::wpabuf -tls_in_left src/eap_peer/eap_tls_common.h /^ size_t tls_in_left;$/;" m struct:eap_ssl_data -tls_in_total src/eap_peer/eap_tls_common.h /^ size_t tls_in_total;$/;" m struct:eap_ssl_data -tls_init src/tls/tls_internal.c /^void * tls_init(void)$/;" f -tls_key_exchange src/tls/tlsv1_common.h /^} tls_key_exchange;$/;" t typeref:enum:__anon49 -tls_keys src/tls/tls.h /^struct tls_keys {$/;" s -tls_out src/eap_peer/eap_tls_common.h /^ struct wpabuf *tls_out;$/;" m struct:eap_ssl_data typeref:struct:eap_ssl_data::wpabuf -tls_out_limit src/eap_peer/eap_tls_common.h /^ size_t tls_out_limit;$/;" m struct:eap_ssl_data -tls_out_pos src/eap_peer/eap_tls_common.h /^ size_t tls_out_pos;$/;" m struct:eap_ssl_data -tls_parse_cert src/tls/tlsv1_common.c /^int tls_parse_cert(const u8 *buf, size_t len, struct crypto_public_key **pk)$/;" f -tls_prf src/tls/tlsv1_common.c /^int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,$/;" f -tls_prf_sha1_md5 src/tls/tls_internal.c /^int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,$/;" f -tls_process_application_data src/tls/tlsv1_client_read.c /^static int tls_process_application_data(struct tlsv1_client *conn, u8 ct,$/;" f file: -tls_process_certificate src/tls/tlsv1_client_read.c /^static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,$/;" f file: -tls_process_certificate src/tls/tlsv1_server_read.c /^static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,$/;" f file: -tls_process_certificate_request src/tls/tlsv1_client_read.c /^static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,$/;" f file: -tls_process_certificate_verify src/tls/tlsv1_server_read.c /^static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,$/;" f file: -tls_process_change_cipher_spec src/tls/tlsv1_server_read.c /^static int tls_process_change_cipher_spec(struct tlsv1_server *conn,$/;" f file: -tls_process_client_finished src/tls/tlsv1_server_read.c /^static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,$/;" f file: -tls_process_client_hello src/tls/tlsv1_server_read.c /^static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,$/;" f file: -tls_process_client_key_exchange src/tls/tlsv1_server_read.c /^static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,$/;" f file: -tls_process_client_key_exchange_dh_anon src/tls/tlsv1_server_read.c /^static int tls_process_client_key_exchange_dh_anon($/;" f file: -tls_process_client_key_exchange_rsa src/tls/tlsv1_server_read.c /^static int tls_process_client_key_exchange_rsa($/;" f file: -tls_process_server_change_cipher_spec src/tls/tlsv1_client_read.c /^static int tls_process_server_change_cipher_spec(struct tlsv1_client *conn,$/;" f file: -tls_process_server_finished src/tls/tlsv1_client_read.c /^static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,$/;" f file: -tls_process_server_hello src/tls/tlsv1_client_read.c /^static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,$/;" f file: -tls_process_server_hello_done src/tls/tlsv1_client_read.c /^static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,$/;" f file: -tls_process_server_key_exchange src/tls/tlsv1_client_read.c /^static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,$/;" f file: -tls_ref_count src/tls/tls_internal.c /^static int tls_ref_count = 0;$/;" v file: -tls_send_change_cipher_spec src/tls/tlsv1_client_write.c /^static u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn,$/;" f file: -tls_send_change_cipher_spec src/tls/tlsv1_server_write.c /^static u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn,$/;" f file: -tls_send_client_hello src/tls/tlsv1_client_write.c /^u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)$/;" f -tls_send_client_key_exchange src/tls/tlsv1_client_write.c /^static u8 * tls_send_client_key_exchange(struct tlsv1_client *conn,$/;" f file: -tls_send_server_hello src/tls/tlsv1_server_write.c /^static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)$/;" f file: -tls_server_cert_chain_der_len src/tls/tlsv1_server_write.c /^static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn)$/;" f file: -tls_server_key_exchange_allowed src/tls/tlsv1_common.c /^int tls_server_key_exchange_allowed(tls_cipher cipher)$/;" f -tls_session_ticket_cb src/tls/tls.h /^typedef int (*tls_session_ticket_cb)$/;" t -tls_verify_hash src/tls/tlsv1_common.h /^struct tls_verify_hash {$/;" s -tls_verify_hash_add src/tls/tlsv1_common.c /^void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,$/;" f -tls_verify_hash_free src/tls/tlsv1_common.c /^void tls_verify_hash_free(struct tls_verify_hash *verify)$/;" f -tls_verify_hash_init src/tls/tlsv1_common.c /^int tls_verify_hash_init(struct tls_verify_hash *verify)$/;" f -tls_version src/tls/tlsv1_record.h /^ u16 tls_version;$/;" m struct:tlsv1_record_layer -tls_version_ok src/tls/tlsv1_common.c /^int tls_version_ok(u16 ver)$/;" f -tls_version_str src/tls/tlsv1_common.c /^const char * tls_version_str(u16 ver)$/;" f -tls_write_client_certificate src/tls/tlsv1_client_write.c /^static int tls_write_client_certificate(struct tlsv1_client *conn,$/;" f file: -tls_write_client_certificate_verify src/tls/tlsv1_client_write.c /^static int tls_write_client_certificate_verify(struct tlsv1_client *conn,$/;" f file: -tls_write_client_change_cipher_spec src/tls/tlsv1_client_write.c /^static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn,$/;" f file: -tls_write_client_finished src/tls/tlsv1_client_write.c /^static int tls_write_client_finished(struct tlsv1_client *conn,$/;" f file: -tls_write_client_key_exchange src/tls/tlsv1_client_write.c /^static int tls_write_client_key_exchange(struct tlsv1_client *conn,$/;" f file: -tls_write_server_certificate src/tls/tlsv1_server_write.c /^static int tls_write_server_certificate(struct tlsv1_server *conn,$/;" f file: -tls_write_server_certificate_request src/tls/tlsv1_server_write.c /^static int tls_write_server_certificate_request(struct tlsv1_server *conn,$/;" f file: -tls_write_server_change_cipher_spec src/tls/tlsv1_server_write.c /^static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,$/;" f file: -tls_write_server_finished src/tls/tlsv1_server_write.c /^static int tls_write_server_finished(struct tlsv1_server *conn,$/;" f file: -tls_write_server_hello src/tls/tlsv1_server_write.c /^static int tls_write_server_hello(struct tlsv1_server *conn,$/;" f file: -tls_write_server_hello_done src/tls/tlsv1_server_write.c /^static int tls_write_server_hello_done(struct tlsv1_server *conn,$/;" f file: -tls_write_server_key_exchange src/tls/tlsv1_server_write.c /^static int tls_write_server_key_exchange(struct tlsv1_server *conn,$/;" f file: -tlsv1_add_cert src/tls/tlsv1_cred.c /^static int tlsv1_add_cert(struct x509_certificate **chain,$/;" f file: -tlsv1_add_cert_der src/tls/tlsv1_cred.c /^static int tlsv1_add_cert_der(struct x509_certificate **chain,$/;" f file: -tlsv1_client src/tls/tlsv1_client_i.h /^struct tlsv1_client {$/;" s -tlsv1_client_decrypt src/tls/tlsv1_client.c /^struct wpabuf * tlsv1_client_decrypt(struct tlsv1_client *conn,$/;" f -tlsv1_client_deinit src/tls/tlsv1_client.c /^void tlsv1_client_deinit(struct tlsv1_client *conn)$/;" f -tlsv1_client_encrypt src/tls/tlsv1_client.c /^int tlsv1_client_encrypt(struct tlsv1_client *conn,$/;" f -tlsv1_client_established src/tls/tlsv1_client.c /^int tlsv1_client_established(struct tlsv1_client *conn)$/;" f -tlsv1_client_free_dh src/tls/tlsv1_client.c /^void tlsv1_client_free_dh(struct tlsv1_client *conn)$/;" f -tlsv1_client_get_cipher src/tls/tlsv1_client.c /^int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,$/;" f -tlsv1_client_get_keyblock_size src/tls/tlsv1_client.c /^int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn)$/;" f -tlsv1_client_get_keys src/tls/tlsv1_client.c /^int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys)$/;" f -tlsv1_client_global_deinit src/tls/tlsv1_client.c /^void tlsv1_client_global_deinit(void)$/;" f -tlsv1_client_global_init src/tls/tlsv1_client.c /^int tlsv1_client_global_init(void)$/;" f -tlsv1_client_handshake src/tls/tlsv1_client.c /^u8 * tlsv1_client_handshake(struct tlsv1_client *conn,$/;" f -tlsv1_client_handshake_write src/tls/tlsv1_client_write.c /^u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len,$/;" f -tlsv1_client_hello_ext src/tls/tlsv1_client.c /^int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,$/;" f -tlsv1_client_init src/tls/tlsv1_client.c /^struct tlsv1_client * tlsv1_client_init(void)$/;" f -tlsv1_client_prf src/tls/tlsv1_client.c /^int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,$/;" f -tlsv1_client_process_handshake src/tls/tlsv1_client_read.c /^int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,$/;" f -tlsv1_client_resumed src/tls/tlsv1_client.c /^int tlsv1_client_resumed(struct tlsv1_client *conn)$/;" f -tlsv1_client_send_alert src/tls/tlsv1_client_write.c /^u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level,$/;" f -tlsv1_client_session_ticket_cb src/tls/tlsv1_client.h /^typedef int (*tlsv1_client_session_ticket_cb)$/;" t -tlsv1_client_set_cipher_list src/tls/tlsv1_client.c /^int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers)$/;" f -tlsv1_client_set_cred src/tls/tlsv1_client.c /^int tlsv1_client_set_cred(struct tlsv1_client *conn,$/;" f -tlsv1_client_set_session_ticket_cb src/tls/tlsv1_client.c /^void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,$/;" f -tlsv1_client_set_time_checks src/tls/tlsv1_client.c /^void tlsv1_client_set_time_checks(struct tlsv1_client *conn, int enabled)$/;" f -tlsv1_client_shutdown src/tls/tlsv1_client.c /^int tlsv1_client_shutdown(struct tlsv1_client *conn)$/;" f -tlsv1_cred_alloc src/tls/tlsv1_cred.c /^struct tlsv1_credentials * tlsv1_cred_alloc(void)$/;" f -tlsv1_cred_free src/tls/tlsv1_cred.c /^void tlsv1_cred_free(struct tlsv1_credentials *cred)$/;" f -tlsv1_credentials src/tls/tlsv1_cred.h /^struct tlsv1_credentials {$/;" s -tlsv1_key_x_anon_dh src/tls/tlsv1_client_write.c /^static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)$/;" f file: -tlsv1_key_x_rsa src/tls/tlsv1_client_write.c /^static int tlsv1_key_x_rsa(struct tlsv1_client *conn, u8 **pos, u8 *end)$/;" f file: -tlsv1_process_diffie_hellman src/tls/tlsv1_client_read.c /^static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,$/;" f file: -tlsv1_record_change_read_cipher src/tls/tlsv1_record.c /^int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)$/;" f -tlsv1_record_change_write_cipher src/tls/tlsv1_record.c /^int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl)$/;" f -tlsv1_record_layer src/tls/tlsv1_record.h /^struct tlsv1_record_layer {$/;" s -tlsv1_record_receive src/tls/tlsv1_record.c /^int tlsv1_record_receive(struct tlsv1_record_layer *rl,$/;" f -tlsv1_record_send src/tls/tlsv1_record.c /^int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,$/;" f -tlsv1_record_set_cipher_suite src/tls/tlsv1_record.c /^int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,$/;" f -tlsv1_server src/tls/tlsv1_server_i.h /^struct tlsv1_server {$/;" s -tlsv1_server_alert src/tls/tlsv1_server.c /^void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description)$/;" f -tlsv1_server_clear_data src/tls/tlsv1_server.c /^static void tlsv1_server_clear_data(struct tlsv1_server *conn)$/;" f file: -tlsv1_server_decrypt src/tls/tlsv1_server.c /^int tlsv1_server_decrypt(struct tlsv1_server *conn,$/;" f -tlsv1_server_deinit src/tls/tlsv1_server.c /^void tlsv1_server_deinit(struct tlsv1_server *conn)$/;" f -tlsv1_server_derive_keys src/tls/tlsv1_server.c /^int tlsv1_server_derive_keys(struct tlsv1_server *conn,$/;" f -tlsv1_server_encrypt src/tls/tlsv1_server.c /^int tlsv1_server_encrypt(struct tlsv1_server *conn,$/;" f -tlsv1_server_established src/tls/tlsv1_server.c /^int tlsv1_server_established(struct tlsv1_server *conn)$/;" f -tlsv1_server_get_cipher src/tls/tlsv1_server.c /^int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf,$/;" f -tlsv1_server_get_keyblock_size src/tls/tlsv1_server.c /^int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn)$/;" f -tlsv1_server_get_keys src/tls/tlsv1_server.c /^int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys)$/;" f -tlsv1_server_global_deinit src/tls/tlsv1_server.c /^void tlsv1_server_global_deinit(void)$/;" f -tlsv1_server_global_init src/tls/tlsv1_server.c /^int tlsv1_server_global_init(void)$/;" f -tlsv1_server_handshake src/tls/tlsv1_server.c /^u8 * tlsv1_server_handshake(struct tlsv1_server *conn,$/;" f -tlsv1_server_handshake_write src/tls/tlsv1_server_write.c /^u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len)$/;" f -tlsv1_server_init src/tls/tlsv1_server.c /^struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred)$/;" f -tlsv1_server_prf src/tls/tlsv1_server.c /^int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,$/;" f -tlsv1_server_process_handshake src/tls/tlsv1_server_read.c /^int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,$/;" f -tlsv1_server_resumed src/tls/tlsv1_server.c /^int tlsv1_server_resumed(struct tlsv1_server *conn)$/;" f -tlsv1_server_send_alert src/tls/tlsv1_server_write.c /^u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,$/;" f -tlsv1_server_session_ticket_cb src/tls/tlsv1_server.h /^typedef int (*tlsv1_server_session_ticket_cb)$/;" t -tlsv1_server_set_cipher_list src/tls/tlsv1_server.c /^int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers)$/;" f -tlsv1_server_set_session_ticket_cb src/tls/tlsv1_server.c /^void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,$/;" f -tlsv1_server_set_verify src/tls/tlsv1_server.c /^int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer)$/;" f -tlsv1_server_shutdown src/tls/tlsv1_server.c /^int tlsv1_server_shutdown(struct tlsv1_server *conn)$/;" f -tlsv1_set_ca_cert src/tls/tlsv1_cred.c /^int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,$/;" f -tlsv1_set_cert src/tls/tlsv1_cred.c /^int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,$/;" f -tlsv1_set_cert_chain src/tls/tlsv1_cred.c /^static int tlsv1_set_cert_chain(struct x509_certificate **chain,$/;" f file: -tlsv1_set_dhparams src/tls/tlsv1_cred.c /^int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,$/;" f -tlsv1_set_dhparams_blob src/tls/tlsv1_cred.c /^static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,$/;" f file: -tlsv1_set_dhparams_der src/tls/tlsv1_cred.c /^static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,$/;" f file: -tlsv1_set_key src/tls/tlsv1_cred.c /^static int tlsv1_set_key(struct tlsv1_credentials *cred,$/;" f file: -tlsv1_set_key_enc_pem src/tls/tlsv1_cred.c /^static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,$/;" f file: -tlsv1_set_key_pem src/tls/tlsv1_cred.c /^static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len)$/;" f file: -tlsv1_set_private_key src/tls/tlsv1_cred.c /^int tlsv1_set_private_key(struct tlsv1_credentials *cred,$/;" f -tlv_type src/eap_peer/eap_tlv_common.h /^ be16 tlv_type; \/* PAC_TYPE_PAC_TYPE *\/$/;" m struct:eap_tlv_pac_type_tlv -tlv_type src/eap_peer/eap_tlv_common.h /^ be16 tlv_type;$/;" m struct:eap_tlv_crypto_binding_tlv -tlv_type src/eap_peer/eap_tlv_common.h /^ be16 tlv_type;$/;" m struct:eap_tlv_hdr -tlv_type src/eap_peer/eap_tlv_common.h /^ be16 tlv_type;$/;" m struct:eap_tlv_intermediate_result_tlv -tlv_type src/eap_peer/eap_tlv_common.h /^ be16 tlv_type;$/;" m struct:eap_tlv_nak_tlv -tlv_type src/eap_peer/eap_tlv_common.h /^ be16 tlv_type;$/;" m struct:eap_tlv_pac_ack_tlv -tlv_type src/eap_peer/eap_tlv_common.h /^ be16 tlv_type;$/;" m struct:eap_tlv_request_action_tlv -tlv_type src/eap_peer/eap_tlv_common.h /^ be16 tlv_type;$/;" m struct:eap_tlv_result_tlv -tmp_eap_user src/ap/hostapd.h /^ struct hostapd_eap_user tmp_eap_user;$/;" m struct:hostapd_data typeref:struct:hostapd_data::hostapd_eap_user -tnc_started src/eap_peer/eap_ttls.c /^ int tnc_started;$/;" m struct:eap_ttls_data file: -totrot src/crypto/des-internal.c /^static const u8 totrot[16] = {$/;" v file: -tptk src/rsn_supp/wpa.h /^ struct wpa_ptk ptk, tptk;$/;" m struct:wpa_sm typeref:struct:wpa_sm:: -tptk_set src/rsn_supp/wpa.h /^ int ptk_set, tptk_set;$/;" m struct:wpa_sm -trans_id src/common/ieee802_11_defs.h /^ u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon82 -trans_id src/common/ieee802_11_defs.h /^ u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon83 -trusted_certs src/tls/tlsv1_cred.h /^ struct x509_certificate *trusted_certs;$/;" m struct:tlsv1_credentials typeref:struct:tlsv1_credentials::x509_certificate -ts_info src/common/ieee802_11_defs.h /^ u8 ts_info[3];$/;" m struct:wmm_tspec_element -ttls_avp src/eap_peer/eap_ttls.h /^struct ttls_avp {$/;" s -ttls_avp_vendor src/eap_peer/eap_ttls.h /^struct ttls_avp_vendor {$/;" s -ttls_parse_avp src/eap_peer/eap_ttls.c /^struct ttls_parse_avp {$/;" s file: -ttls_version src/eap_peer/eap_ttls.c /^ int ttls_version;$/;" m struct:eap_ttls_data file: -tx src/common/wpa_common.h /^ int tx, key_rsc_len, keyidx;$/;" m struct:wpa_gtk_data -tx_bf_capability_info src/common/ieee802_11_defs.h /^ le32 tx_bf_capability_info;$/;" m struct:ieee80211_ht_capabilities -tx_mic_key src/common/wpa_common.h /^ u8 tx_mic_key[8];$/;" m struct:wpa_ptk::__anon62::__anon63 -tx_status src/ap/wpa_auth.h /^ int tx_status;$/;" m struct:wpa_auth_config -txcb_flags src/rsn_supp/wpa.h /^ u16 txcb_flags;$/;" m struct:wpa_sm -txop_limit src/common/ieee802_11_defs.h /^ le16 txop_limit;$/;" m struct:wmm_ac_parameter -type src/common/eapol_common.h /^ u8 type;$/;" m struct:ieee802_1x_eapol_key -type src/common/eapol_common.h /^ u8 type;$/;" m struct:ieee802_1x_hdr -type src/common/wpa_common.h /^ u8 type;$/;" m struct:wpa_eapol_key -type src/tls/tls.h /^ const char *type;$/;" m struct:tls_event_data::__anon36 -type src/tls/tlsv1_common.h /^ tls_cipher_type type;$/;" m struct:tls_cipher_data -type src/tls/x509v3.h /^ } type;$/;" m struct:x509_name_attr typeref:enum:x509_name_attr::x509_name_attr_type -type src/wps/wps.h /^ enum wps_msg_type type;$/;" m struct:upnp_pending_message typeref:enum:upnp_pending_message::wps_msg_type -u src/common/ieee802_11_defs.h /^ } u;$/;" m struct:ieee80211_mgmt::__anon66::__anon76 typeref:union:ieee80211_mgmt::__anon66::__anon76::__anon77 -u src/common/ieee802_11_defs.h /^ } u;$/;" m struct:ieee80211_mgmt typeref:union:ieee80211_mgmt::__anon66 -u src/common/wpa_common.h /^ } u;$/;" m struct:wpa_ptk typeref:union:wpa_ptk::__anon62 -u src/crypto/crypto_internal-cipher.c /^ } u;$/;" m struct:crypto_cipher typeref:union:crypto_cipher::__anon10 file: -u src/crypto/crypto_internal.c /^ } u;$/;" m struct:crypto_hash typeref:union:crypto_hash::__anon9 file: -u src/fast_crypto/fast_crypto_internal-cipher.c /^ } u;$/;" m struct:fast_crypto_cipher typeref:union:fast_crypto_cipher::__anon56 file: -u src/fast_crypto/fast_crypto_internal.c /^ } u;$/;" m struct:fast_crypto_hash typeref:union:fast_crypto_hash::__anon61 file: -u16 include/utils/common.h /^typedef uint16_t u16;$/;" t -u32 include/utils/common.h /^typedef uint32_t u32;$/;" t -u64 include/utils/common.h /^typedef uint64_t u64;$/;" t -u8 include/utils/common.h /^typedef uint8_t u8;$/;" t -uint16_t port/include/endian.h /^typedef __uint16_t uint16_t;$/;" t -uint32_t port/include/endian.h /^typedef __uint32_t uint32_t;$/;" t -uint64_t port/include/endian.h /^typedef __uint64_t uint64_t;$/;" t -uint8_t port/include/endian.h /^typedef __uint8_t uint8_t;$/;" t -upc src/ap/ap_config.h /^ char *upc;$/;" m struct:hostapd_bss_config -upc src/wps/wps.h /^ const char *upc;$/;" m struct:wps_event_data::wps_event_er_ap -upc src/wps/wps.h /^ char *upc;$/;" m struct:wps_context -update_snonce src/ap/wpa_auth_i.h /^ unsigned int update_snonce:1;$/;" m struct:wpa_state_machine -upnp_iface src/ap/ap_config.h /^ char *upnp_iface;$/;" m struct:hostapd_bss_config -upnp_pending_message src/wps/wps.h /^struct upnp_pending_message {$/;" s -uri src/tls/x509v3.h /^ char *uri; \/* uniformResourceIdentifier *\/$/;" m struct:x509_name -use_cred src/wps/wps_i.h /^ struct wps_credential *use_cred;$/;" m struct:wps_data typeref:struct:wps_data::wps_credential -use_psk_key src/wps/wps.h /^ int use_psk_key;$/;" m struct:wps_config -use_psk_key src/wps/wps_i.h /^ int use_psk_key;$/;" m struct:wps_data -use_session_ticket src/tls/tlsv1_client_i.h /^ unsigned int use_session_ticket:1;$/;" m struct:tlsv1_client -use_session_ticket src/tls/tlsv1_server_i.h /^ int use_session_ticket;$/;" m struct:tlsv1_server -usec port/include/os.h /^ os_time_t usec;$/;" m struct:os_time -used include/utils/wpabuf.h /^ size_t used; \/* length of data in the buffer *\/$/;" m struct:wpabuf -used src/crypto/libtommath.h /^ int used, alloc, sign;$/;" m struct:__anon8 -used src/tls/libtommath.h /^ int used, alloc, sign;$/;" m struct:__anon40 -used_bytes src/crypto/crypto_internal-cipher.c /^ size_t used_bytes;$/;" m struct:crypto_cipher::__anon10::__anon11 file: -used_bytes src/fast_crypto/fast_crypto_internal-cipher.c /^ size_t used_bytes;$/;" m struct:fast_crypto_cipher::__anon56::__anon57 file: -utf8_ssid src/ap/ap_config.h /^ unsigned int utf8_ssid:1;$/;" m struct:hostapd_ssid -utf8_to_ucs2 src/crypto/ms_funcs.c /^static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,$/;" f file: -uuid src/ap/ap_config.h /^ u8 uuid[16];$/;" m struct:hostapd_bss_config -uuid src/wps/wps.h /^ const u8 *uuid;$/;" m struct:wps_event_data::wps_event_er_ap -uuid src/wps/wps.h /^ const u8 *uuid;$/;" m struct:wps_event_data::wps_event_er_ap_settings -uuid src/wps/wps.h /^ const u8 *uuid;$/;" m struct:wps_event_data::wps_event_er_enrollee -uuid src/wps/wps.h /^ const u8 *uuid;$/;" m struct:wps_event_data::wps_event_er_set_selected_registrar -uuid src/wps/wps.h /^ u8 uuid[16];$/;" m struct:wps_context -uuid src/wps/wps.h /^ u8 uuid[16];$/;" m struct:wps_sm -uuid src/wps/wps_registrar.c /^ u8 uuid[WPS_UUID_LEN];$/;" m struct:wps_registrar_device file: -uuid src/wps/wps_registrar.c /^ u8 uuid[WPS_UUID_LEN];$/;" m struct:wps_uuid_pin file: -uuid_bin2str src/utils/uuid.c /^int uuid_bin2str(const u8 *bin, char *str, size_t max_len)$/;" f -uuid_e src/wps/wps_attr_parse.h /^ const u8 *uuid_e; \/* WPS_UUID_LEN (16) octets *\/$/;" m struct:wps_parse_attr -uuid_e src/wps/wps_i.h /^ u8 uuid_e[WPS_UUID_LEN];$/;" m struct:wps_data -uuid_e src/wps/wps_registrar.c /^ u8 uuid_e[WPS_UUID_LEN];$/;" m struct:wps_pbc_session file: -uuid_gen_mac_addr src/wps/wps_common.c /^void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid)$/;" f -uuid_r src/wps/wps_attr_parse.h /^ const u8 *uuid_r; \/* WPS_UUID_LEN (16) octets *\/$/;" m struct:wps_parse_attr -uuid_r src/wps/wps_i.h /^ u8 uuid_r[WPS_UUID_LEN];$/;" m struct:wps_data -uuid_str2bin src/utils/uuid.c /^int uuid_str2bin(const char *str, u8 *bin)$/;" f -valid src/ap/wpa_auth_i.h /^ Boolean valid;$/;" m struct:wpa_state_machine::wpa_key_replay_counter -valid_config_methods src/wps/wps_validate.c /^static int valid_config_methods(u16 val, int wps2)$/;" f file: -value src/tls/x509v3.h /^ char *value;$/;" m struct:x509_name_attr -variable src/common/ieee802_11_defs.h /^ u8 variable[0]; \/* FT Request *\/$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon80 -variable src/common/ieee802_11_defs.h /^ u8 variable[0]; \/* FT Request *\/$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon81 -variable src/common/ieee802_11_defs.h /^ u8 variable[0];$/;" m struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon78 -variable src/common/ieee802_11_defs.h /^ u8 variable[0];$/;" m struct:ieee80211_mgmt::__anon66::__anon67 -variable src/common/ieee802_11_defs.h /^ u8 variable[0];$/;" m struct:ieee80211_mgmt::__anon66::__anon69 -variable src/common/ieee802_11_defs.h /^ u8 variable[0];$/;" m struct:ieee80211_mgmt::__anon66::__anon70 -variable src/common/ieee802_11_defs.h /^ u8 variable[0];$/;" m struct:ieee80211_mgmt::__anon66::__anon71 -variable src/common/ieee802_11_defs.h /^ u8 variable[0];$/;" m struct:ieee80211_mgmt::__anon66::__anon73 -variable src/common/ieee802_11_defs.h /^ u8 variable[0];$/;" m struct:ieee80211_mgmt::__anon66::__anon74 -variable src/common/ieee802_11_defs.h /^ u8 variable[0];$/;" m struct:ieee80211_mgmt::__anon66::__anon75 -vendor src/eap_peer/eap.h /^ int vendor;$/;" m struct:eap_method_type -vendor src/eap_peer/eap_i.h /^ int vendor;$/;" m struct:eap_method -vendor_ext src/wps/wps.h /^ struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];$/;" m struct:wps_device_data typeref:struct:wps_device_data::wpabuf -vendor_ext src/wps/wps_attr_parse.h /^ const u8 *vendor_ext[MAX_WPS_PARSE_VENDOR_EXT];$/;" m struct:wps_parse_attr -vendor_ext_len src/wps/wps_attr_parse.h /^ size_t vendor_ext_len[MAX_WPS_PARSE_VENDOR_EXT];$/;" m struct:wps_parse_attr -vendor_ext_m1 src/wps/wps.h /^ struct wpabuf *vendor_ext_m1;$/;" m struct:wps_device_data typeref:struct:wps_device_data::wpabuf -vendor_id src/eap_peer/eap_defs.h /^ u8 vendor_id[3];$/;" m struct:eap_expand -vendor_id src/eap_peer/eap_tlv_common.h /^ be32 vendor_id;$/;" m struct:eap_tlv_nak_tlv -vendor_id src/eap_peer/eap_ttls.h /^ be32 vendor_id;$/;" m struct:ttls_avp_vendor -vendor_type src/eap_peer/eap_defs.h /^ be32 vendor_type;$/;" m struct:eap_expand -verify src/tls/tlsv1_client_i.h /^ struct tls_verify_hash verify;$/;" m struct:tlsv1_client typeref:struct:tlsv1_client::tls_verify_hash -verify src/tls/tlsv1_server_i.h /^ struct tls_verify_hash verify;$/;" m struct:tlsv1_server typeref:struct:tlsv1_server::tls_verify_hash -verify_peer src/tls/tlsv1_server_i.h /^ int verify_peer;$/;" m struct:tlsv1_server -version src/common/eapol_common.h /^ u8 version;$/;" m struct:ieee802_1x_hdr -version src/common/ieee802_11_defs.h /^ u8 version; \/* 1 *\/$/;" m struct:wmm_tspec_element -version src/common/ieee802_11_defs.h /^ u8 version; \/* 1 for WMM version 1.0 *\/$/;" m struct:wmm_information_element -version src/common/ieee802_11_defs.h /^ u8 version; \/* 1 for WMM version 1.0 *\/$/;" m struct:wmm_parameter_element -version src/common/wpa_common.h /^ u8 version[2]; \/* little endian *\/$/;" m struct:rsn_ie_hdr -version src/common/wpa_common.h /^ u8 version[2]; \/* little endian *\/$/;" m struct:wpa_ie_hdr -version src/eap_peer/eap_tlv_common.h /^ u8 version;$/;" m struct:eap_tlv_crypto_binding_tlv -version src/tls/x509v3.h /^ enum { X509_CERT_V1 = 0, X509_CERT_V2 = 1, X509_CERT_V3 = 2 } version;$/;" m struct:x509_certificate typeref:enum:x509_certificate::__anon41 -version src/wps/wps_attr_parse.h /^ const u8 *version; \/* 1 octet *\/$/;" m struct:wps_parse_attr -version2 src/wps/wps_attr_parse.h /^ const u8 *version2; \/* 1 octet *\/$/;" m struct:wps_parse_attr -vht_capab src/ap/ap_config.h /^ u32 vht_capab;$/;" m struct:hostapd_config -vht_oper_centr_freq_seg0_idx src/ap/ap_config.h /^ u8 vht_oper_centr_freq_seg0_idx;$/;" m struct:hostapd_config -vht_oper_centr_freq_seg1_idx src/ap/ap_config.h /^ u8 vht_oper_centr_freq_seg1_idx;$/;" m struct:hostapd_config -vht_oper_chwidth src/ap/ap_config.h /^ u8 vht_oper_chwidth;$/;" m struct:hostapd_config -vlan_id src/ap/ap_config.h /^ int vlan_id;$/;" m struct:mac_acl_entry -vlan_id src/ap/wpa_auth_i.h /^ int vlan_id;$/;" m struct:wpa_group -wep src/ap/ap_config.h /^ struct hostapd_wep_keys wep;$/;" m struct:hostapd_ssid typeref:struct:hostapd_ssid::hostapd_wep_keys -wep_rekeying_period src/ap/ap_config.h /^ int wep_rekeying_period;$/;" m struct:hostapd_bss_config -wifi_appie src/esp_supplicant/esp_wifi_driver.h /^struct wifi_appie {$/;" s -wifi_cipher src/esp_supplicant/esp_wifi_driver.h /^struct wifi_cipher {$/;" s -wifi_ipc_config_t src/esp_supplicant/esp_wifi_driver.h /^} wifi_ipc_config_t;$/;" t typeref:struct:__anon32 -wifi_ipc_fn_t src/esp_supplicant/esp_wifi_driver.h /^typedef int (*wifi_ipc_fn_t)(void *);$/;" t -wifi_key src/esp_supplicant/esp_wifi_driver.h /^struct wifi_key {$/;" s -wifi_key_alg src/common/defs.h /^enum wifi_key_alg {$/;" g -wifi_keyix src/esp_supplicant/esp_wifi_driver.h /^typedef uint16_t wifi_keyix; \/* h\/w key index *\/$/;" t -wifi_set_wps_cb src/esp_supplicant/esp_wps.c /^wifi_set_wps_cb(wps_st_cb_t cb)$/;" f -wifi_ssid src/esp_supplicant/esp_wifi_driver.h /^struct wifi_ssid {$/;" s -wifi_sta_get_enterprise_disable_time_check src/esp_supplicant/esp_wpa_enterprise.c /^bool wifi_sta_get_enterprise_disable_time_check(void)$/;" f -wifi_station_wps_deinit src/esp_supplicant/esp_wps.c /^wifi_station_wps_deinit(void)$/;" f -wifi_station_wps_eapol_start_handle src/esp_supplicant/esp_wps.c /^void wifi_station_wps_eapol_start_handle(void)$/;" f -wifi_station_wps_eapol_start_handle_internal src/esp_supplicant/esp_wps.c /^void wifi_station_wps_eapol_start_handle_internal(void)$/;" f -wifi_station_wps_init src/esp_supplicant/esp_wps.c /^wifi_station_wps_init(void)$/;" f -wifi_station_wps_msg_timeout src/esp_supplicant/esp_wps.c /^void wifi_station_wps_msg_timeout(void)$/;" f -wifi_station_wps_msg_timeout_internal src/esp_supplicant/esp_wps.c /^wifi_station_wps_msg_timeout_internal(void)$/;" f -wifi_station_wps_start src/esp_supplicant/esp_wifi_driver.h /^ int (*wifi_station_wps_start)(void);$/;" m struct:wps_funcs -wifi_station_wps_start src/esp_supplicant/esp_wps.c /^int wifi_station_wps_start(void)$/;" f -wifi_station_wps_success src/esp_supplicant/esp_wps.c /^void wifi_station_wps_success(void)$/;" f -wifi_station_wps_success_internal src/esp_supplicant/esp_wps.c /^void wifi_station_wps_success_internal(void)$/;" f -wifi_station_wps_timeout src/esp_supplicant/esp_wps.c /^void wifi_station_wps_timeout(void)$/;" f -wifi_station_wps_timeout_internal src/esp_supplicant/esp_wps.c /^wifi_station_wps_timeout_internal(void)$/;" f -wifi_tx_cb_t src/esp_supplicant/esp_wifi_driver.h /^typedef void(* wifi_tx_cb_t)(void *);$/;" t -wifi_wpa2_fn_t src/esp_supplicant/esp_wifi_driver.h /^typedef esp_err_t (*wifi_wpa2_fn_t)(void *);$/;" t -wifi_wpa2_param_t src/esp_supplicant/esp_wifi_driver.h /^}wifi_wpa2_param_t;$/;" t typeref:struct:__anon31 -wifi_wps_disable_internal src/esp_supplicant/esp_wps.c /^int wifi_wps_disable_internal(void)$/;" f -wifi_wps_enable_internal src/esp_supplicant/esp_wps.c /^int wifi_wps_enable_internal(const esp_wps_config_t *config)$/;" f -wifi_wps_scan src/esp_supplicant/esp_wps.c /^void wifi_wps_scan(void)$/;" f -wifi_wps_scan_done src/esp_supplicant/esp_wps.c /^wifi_wps_scan_done(void *arg, STATUS status)$/;" f -wifi_wps_scan_internal src/esp_supplicant/esp_wps.c /^wifi_wps_scan_internal(void)$/;" f -wildcard_uuid src/wps/wps_registrar.c /^ int wildcard_uuid;$/;" m struct:wps_uuid_pin file: -wk_cipher src/esp_supplicant/esp_wifi_driver.h /^ const struct wifi_cipher *wk_cipher;$/;" m struct:wifi_key typeref:struct:wifi_key::wifi_cipher -wk_keyix src/esp_supplicant/esp_wifi_driver.h /^ wifi_keyix wk_keyix; \/* h\/w key index *\/$/;" m struct:wifi_key -wk_keyrsc src/esp_supplicant/esp_wifi_driver.h /^ uint64_t wk_keyrsc[WIFI_TID_SIZE];$/;" m struct:wifi_key -wk_keytsc src/esp_supplicant/esp_wifi_driver.h /^ uint64_t wk_keytsc; \/* key transmit sequence counter *\/$/;" m struct:wifi_key -wmm_ac_parameter src/common/ieee802_11_defs.h /^struct wmm_ac_parameter {$/;" s -wmm_action src/common/ieee802_11_defs.h /^ } STRUCT_PACKED wmm_action;$/;" m union:ieee80211_mgmt::__anon66::__anon76::__anon77 typeref:struct:ieee80211_mgmt::__anon66::__anon76::__anon77::__anon78 -wmm_enabled src/ap/ap_config.h /^ int wmm_enabled;$/;" m struct:hostapd_bss_config -wmm_enabled src/ap/wpa_auth.h /^ int wmm_enabled;$/;" m struct:wpa_auth_config -wmm_information_element src/common/ieee802_11_defs.h /^struct wmm_information_element {$/;" s -wmm_parameter_element src/common/ieee802_11_defs.h /^struct wmm_parameter_element {$/;" s -wmm_tspec_element src/common/ieee802_11_defs.h /^struct wmm_tspec_element {$/;" s -wmm_uapsd src/ap/ap_config.h /^ int wmm_uapsd;$/;" m struct:hostapd_bss_config -wmm_uapsd src/ap/wpa_auth.h /^ int wmm_uapsd;$/;" m struct:wpa_auth_config -workaround src/eap_peer/eap_i.h /^ unsigned int workaround;$/;" m struct:eap_sm -wpa src/ap/ap_config.h /^ int wpa; \/* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN *\/$/;" m struct:hostapd_bss_config -wpa src/ap/wpa_auth.h /^ int wpa;$/;" m struct:wpa_auth_config -wpa src/ap/wpa_auth_i.h /^ } wpa;$/;" m struct:wpa_state_machine typeref:enum:wpa_state_machine::__anon26 -wpa src/esp_supplicant/esp_wifi_driver.h /^ uint8_t *wpa;$/;" m struct:wps_scan_ie -wpa2Task src/esp_supplicant/esp_wpa_enterprise.c /^void wpa2Task(void *pvParameters )$/;" f -wpa2_api_lock src/esp_supplicant/esp_wpa_enterprise.c /^static void wpa2_api_lock(void)$/;" f file: -wpa2_api_unlock src/esp_supplicant/esp_wpa_enterprise.c /^static void wpa2_api_unlock(void)$/;" f file: -wpa2_deinit src/esp_supplicant/esp_wifi_driver.h /^ void (*wpa2_deinit)(void);$/;" m struct:wpa2_funcs -wpa2_ent_eap_state_t src/esp_supplicant/esp_wifi_driver.h /^} wpa2_ent_eap_state_t;$/;" t typeref:enum:__anon30 -wpa2_funcs src/esp_supplicant/esp_wifi_driver.h /^struct wpa2_funcs {$/;" s -wpa2_get_state src/esp_supplicant/esp_wifi_driver.h /^ u8 (*wpa2_get_state)(void);$/;" m struct:wpa2_funcs -wpa2_init src/esp_supplicant/esp_wifi_driver.h /^ int (*wpa2_init)(void);$/;" m struct:wpa2_funcs -wpa2_is_disabled src/esp_supplicant/esp_wpa_enterprise.c /^static bool inline wpa2_is_disabled(void)$/;" f file: -wpa2_is_enabled src/esp_supplicant/esp_wpa_enterprise.c /^static bool inline wpa2_is_enabled(void)$/;" f file: -wpa2_machine_start src/esp_supplicant/esp_wpa_enterprise.c /^uint8_t wpa2_machine_start = 0;$/;" v -wpa2_post src/esp_supplicant/esp_wpa_enterprise.c /^ETS_STATUS wpa2_post(ETSSignal sig, ETSParam par)$/;" f -wpa2_rx_param src/esp_supplicant/esp_wpa_enterprise.c /^struct wpa2_rx_param {$/;" s file: -wpa2_sendto_wrapper src/esp_supplicant/esp_wpa_enterprise.c /^static void wpa2_sendto_wrapper(void *buffer, uint16_t len)$/;" f file: -wpa2_set_eap_state src/esp_supplicant/esp_wpa_enterprise.c /^static void wpa2_set_eap_state(wpa2_ent_eap_state_t state)$/;" f file: -wpa2_set_state src/esp_supplicant/esp_wpa_enterprise.c /^static void inline wpa2_set_state(wpa2_state_t state)$/;" f file: -wpa2_sig_cnt src/eap_peer/eap_i.h /^ u8 wpa2_sig_cnt[SIG_WPA2_MAX];$/;" m struct:eap_sm -wpa2_sm_alloc_eapol src/esp_supplicant/esp_wpa_enterprise.c /^u8 *wpa2_sm_alloc_eapol(struct eap_sm *sm, u8 type,$/;" f -wpa2_sm_ether_send src/esp_supplicant/esp_wpa_enterprise.c /^static inline int wpa2_sm_ether_send(struct eap_sm *sm, const u8 *dest, u16 proto,$/;" f file: -wpa2_sm_free_eapol src/esp_supplicant/esp_wpa_enterprise.c /^void wpa2_sm_free_eapol(u8 *buffer)$/;" f -wpa2_sm_rx_eapol src/esp_supplicant/esp_wifi_driver.h /^ int (*wpa2_sm_rx_eapol)(u8 *src_addr, u8 *buf, u32 len, u8 *bssid);$/;" m struct:wpa2_funcs -wpa2_sm_rx_eapol src/esp_supplicant/esp_wpa_enterprise.c /^static int wpa2_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid)$/;" f file: -wpa2_sm_rx_eapol_internal src/esp_supplicant/esp_wpa_enterprise.c /^static int wpa2_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid)$/;" f file: -wpa2_start src/esp_supplicant/esp_wifi_driver.h /^ int (*wpa2_start)(void);$/;" m struct:wpa2_funcs -wpa2_start_eapol src/esp_supplicant/esp_wpa_enterprise.c /^static int wpa2_start_eapol(void)$/;" f file: -wpa2_start_eapol_internal src/esp_supplicant/esp_wpa_enterprise.c /^static int wpa2_start_eapol_internal(void)$/;" f file: -wpa2_state_t src/eap_peer/eap_i.h /^}wpa2_state_t;$/;" t typeref:enum:__anon3 -wpa2_task_delete src/esp_supplicant/esp_wpa_enterprise.c /^static inline void wpa2_task_delete(void *arg)$/;" f file: -wpa2_task_hdl src/esp_supplicant/esp_wpa_enterprise.c /^static void *wpa2_task_hdl = NULL;$/;" v file: -wpa_add_kde src/ap/wpa_auth_ie.c /^u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,$/;" f -wpa_alg src/common/defs.h /^enum wpa_alg {$/;" g -wpa_ap_deinit src/esp_supplicant/esp_wifi_driver.h /^ bool (*wpa_ap_deinit)(void* data);$/;" m struct:wpa_funcs -wpa_ap_get_wpa_ie src/esp_supplicant/esp_wifi_driver.h /^ uint8_t* (*wpa_ap_get_wpa_ie)(uint8_t *len);$/;" m struct:wpa_funcs -wpa_ap_get_wpa_ie src/esp_supplicant/esp_wpa_main.c /^uint8_t *wpa_ap_get_wpa_ie(uint8_t *ie_len)$/;" f -wpa_ap_init src/esp_supplicant/esp_wifi_driver.h /^ void* (*wpa_ap_init)(void);$/;" m struct:wpa_funcs -wpa_ap_join src/ap/wpa_auth.c /^bool wpa_ap_join(void** sm, uint8_t *bssid, uint8_t *wpa_ie, uint8_t wpa_ie_len)$/;" f -wpa_ap_join src/esp_supplicant/esp_wifi_driver.h /^ bool (*wpa_ap_join)(void** sm, u8 *bssid, u8 *wpa_ie, u8 wpa_ie_len);$/;" m struct:wpa_funcs -wpa_ap_remove src/ap/wpa_auth.c /^bool wpa_ap_remove(void* sm)$/;" f -wpa_ap_remove src/esp_supplicant/esp_wifi_driver.h /^ bool (*wpa_ap_remove)(void* sm);$/;" m struct:wpa_funcs -wpa_ap_rx_eapol src/esp_supplicant/esp_wifi_driver.h /^ bool (*wpa_ap_rx_eapol)(void* hapd_data, void *sm, u8 *data, size_t data_len);$/;" m struct:wpa_funcs -wpa_ap_rx_eapol src/esp_supplicant/esp_wpa_main.c /^bool wpa_ap_rx_eapol(void *hapd_data, void *sm_data, u8 *data, size_t data_len)$/;" f -wpa_attach src/esp_supplicant/esp_wpa_main.c /^void wpa_attach(void)$/;" f -wpa_auth src/ap/hostapd.h /^ struct wpa_authenticator *wpa_auth;$/;" m struct:hostapd_data typeref:struct:hostapd_data::wpa_authenticator -wpa_auth src/ap/wpa_auth_i.h /^ struct wpa_authenticator *wpa_auth;$/;" m struct:wpa_state_machine typeref:struct:wpa_state_machine::wpa_authenticator -wpa_auth_add_sm src/ap/wpa_auth.c /^static void wpa_auth_add_sm(struct wpa_state_machine *sm)$/;" f file: -wpa_auth_callbacks src/ap/wpa_auth.h /^struct wpa_auth_callbacks {$/;" s -wpa_auth_config src/ap/wpa_auth.h /^struct wpa_auth_config {$/;" s -wpa_auth_del_sm src/ap/wpa_auth.c /^static void wpa_auth_del_sm(struct wpa_state_machine *sm)$/;" f file: -wpa_auth_for_each_sta src/ap/wpa_auth.c /^int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,$/;" f -wpa_auth_gen_wpa_ie src/ap/wpa_auth_ie.c /^int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)$/;" f -wpa_auth_get_eapol src/ap/wpa_auth.c /^static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth,$/;" f file: -wpa_auth_get_msk src/ap/wpa_auth.c /^static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,$/;" f file: -wpa_auth_get_psk src/ap/wpa_auth.c /^static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,$/;" f file: -wpa_auth_get_seqnum src/ap/wpa_auth.c /^static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,$/;" f file: -wpa_auth_get_sm src/ap/wpa_auth.c /^static struct wpa_state_machine * wpa_auth_get_sm(u32 index)$/;" f file: -wpa_auth_logger include/utils/wpa_debug.h 161;" d -wpa_auth_mic_failure_report src/ap/wpa_auth.c /^static inline int wpa_auth_mic_failure_report($/;" f file: -wpa_auth_send_eapol src/ap/wpa_auth.c /^wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,$/;" f file: -wpa_auth_set_eapol src/ap/wpa_auth.c /^static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth,$/;" f file: -wpa_auth_set_key src/ap/wpa_auth.c /^static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,$/;" f file: -wpa_auth_sm_event src/ap/wpa_auth.c /^int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)$/;" f -wpa_auth_sta_associated src/ap/wpa_auth.c /^int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,$/;" f -wpa_auth_sta_deinit src/ap/wpa_auth.c /^void wpa_auth_sta_deinit(struct wpa_state_machine *sm)$/;" f -wpa_auth_sta_init src/ap/wpa_auth.c /^wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr)$/;" f -wpa_auth_sta_no_wpa src/ap/wpa_auth.c /^void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm)$/;" f -wpa_auth_uses_mfp src/ap/wpa_auth_ie.c /^int wpa_auth_uses_mfp(struct wpa_state_machine *sm)$/;" f -wpa_auth_vlogger include/utils/wpa_debug.h 162;" d -wpa_authenticator src/ap/wpa_auth_i.h /^struct wpa_authenticator {$/;" s -wpa_cipher src/common/defs.h /^enum wpa_cipher {$/;" g -wpa_cipher_key_len src/common/wpa_common.c /^int wpa_cipher_key_len(int cipher)$/;" f -wpa_cipher_put_suites src/common/wpa_common.c /^int wpa_cipher_put_suites(u8 *pos, int ciphers)$/;" f -wpa_cipher_to_alg src/common/wpa_common.c /^int wpa_cipher_to_alg(int cipher)$/;" f -wpa_cipher_to_suite src/common/wpa_common.c /^u32 wpa_cipher_to_suite(int proto, int cipher)$/;" f -wpa_cipher_txt src/common/wpa_common.c /^const char * wpa_cipher_txt(int cipher)$/;" f -wpa_compare_rsn_ie src/common/wpa_common.c /^int wpa_compare_rsn_ie(int ft_initial_assoc,$/;" f -wpa_config_assoc_ie src/esp_supplicant/esp_wpa_main.c /^void wpa_config_assoc_ie(u8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len)$/;" f -wpa_config_blob src/eap_peer/eap_config.h /^struct wpa_config_blob {$/;" s -wpa_config_bss src/esp_supplicant/esp_wpa_main.c /^void wpa_config_bss(uint8_t *bssid)$/;" f -wpa_config_parse_string src/utils/common.c /^char * wpa_config_parse_string(const char *value, size_t *len)$/;" f -wpa_config_profile src/esp_supplicant/esp_wpa_main.c /^void wpa_config_profile()$/;" f -wpa_deattach src/esp_supplicant/esp_wpa_main.c /^bool wpa_deattach(void)$/;" f -wpa_deauthenticate src/esp_supplicant/esp_wpa_main.c /^void wpa_deauthenticate(u8 reason_code)$/;" f -wpa_deauthenticate src/rsn_supp/wpa.h /^ void (*wpa_deauthenticate)(u8 reason_code);$/;" m struct:wpa_sm -wpa_debug_print_timestamp src/utils/wpa_debug.c /^void wpa_debug_print_timestamp(void)$/;" f -wpa_derive_ptk src/ap/wpa_auth.c /^static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk,$/;" f file: -wpa_derive_ptk src/rsn_supp/wpa.c /^int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,$/;" f -wpa_dump_mem src/utils/wpa_debug.c /^void wpa_dump_mem(char* desc, uint8_t *addr, uint16_t len)$/;" f -wpa_eapol_ie_parse src/ap/wpa_auth_ie.h /^struct wpa_eapol_ie_parse {$/;" s -wpa_eapol_ie_parse src/rsn_supp/wpa_ie.h /^struct wpa_eapol_ie_parse {$/;" s -wpa_eapol_key src/common/wpa_common.h /^struct wpa_eapol_key {$/;" s -wpa_eapol_key_dump src/rsn_supp/wpa.c /^ void wpa_eapol_key_dump(int level, const struct wpa_eapol_key *key)$/;" f -wpa_eapol_key_mic src/common/wpa_common.c /^int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,$/;" f -wpa_eapol_key_send src/rsn_supp/wpa.c /^void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,$/;" f -wpa_eapol_variable src/ap/wpa_auth.h /^} wpa_eapol_variable;$/;" t typeref:enum:__anon21 -wpa_event src/ap/wpa_auth.h /^} wpa_event;$/;" t typeref:enum:__anon23 -wpa_free_sta_sm src/ap/wpa_auth.c /^static void wpa_free_sta_sm(struct wpa_state_machine *sm)$/;" f file: -wpa_funcs src/esp_supplicant/esp_wifi_driver.h /^struct wpa_funcs {$/;" s -wpa_gen_wpa_ie src/rsn_supp/wpa_ie.c /^int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)$/;" f -wpa_gen_wpa_ie_rsn src/rsn_supp/wpa_ie.c /^static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,$/;" f file: -wpa_gen_wpa_ie_wpa src/rsn_supp/wpa_ie.c /^static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,$/;" f file: -wpa_get_key src/esp_supplicant/esp_wpa_main.c /^int wpa_get_key(uint8_t *ifx, int *alg, u8 *addr, int *key_idx,$/;" f -wpa_get_ntp_timestamp src/utils/common.c /^void wpa_get_ntp_timestamp(u8 *buf)$/;" f -wpa_gmk_rekey src/ap/ap_config.h /^ int wpa_gmk_rekey;$/;" m struct:hostapd_bss_config -wpa_gmk_rekey src/ap/wpa_auth.h /^ int wpa_gmk_rekey;$/;" m struct:wpa_auth_config -wpa_gmk_to_gtk src/ap/wpa_auth.c /^static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr,$/;" f file: -wpa_group src/ap/ap_config.h /^ int wpa_group;$/;" m struct:hostapd_bss_config -wpa_group src/ap/wpa_auth.h /^ int wpa_group;$/;" m struct:wpa_auth_config -wpa_group src/ap/wpa_auth_i.h /^struct wpa_group {$/;" s -wpa_group_config_group_keys src/ap/wpa_auth.c /^static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,$/;" f file: -wpa_group_ensure_init src/ap/wpa_auth.c /^static void wpa_group_ensure_init(struct wpa_authenticator *wpa_auth,$/;" f file: -wpa_group_gtk_init src/ap/wpa_auth.c /^static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,$/;" f file: -wpa_group_init src/ap/wpa_auth.c /^static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,$/;" f file: -wpa_group_init_gmk_and_counter src/ap/wpa_auth.c /^static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,$/;" f file: -wpa_group_rekey src/ap/ap_config.h /^ int wpa_group_rekey;$/;" m struct:hostapd_bss_config -wpa_group_rekey src/ap/wpa_auth.h /^ int wpa_group_rekey;$/;" m struct:wpa_auth_config -wpa_group_setkeys src/ap/wpa_auth.c /^static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,$/;" f file: -wpa_group_setkeysdone src/ap/wpa_auth.c /^static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,$/;" f file: -wpa_group_sm_step src/ap/wpa_auth.c /^static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,$/;" f file: -wpa_group_state src/ap/wpa_auth_i.h /^ } wpa_group_state;$/;" m struct:wpa_group typeref:enum:wpa_group::__anon27 -wpa_group_update_sta src/ap/wpa_auth.c /^static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)$/;" f file: -wpa_gtk_data src/common/wpa_common.h /^struct wpa_gtk_data {$/;" s -wpa_gtk_update src/ap/wpa_auth.c /^static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,$/;" f file: -wpa_hexdump include/utils/wpa_debug.h 153;" d -wpa_hexdump src/utils/wpa_debug.c /^void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)$/;" f -wpa_hexdump_ascii include/utils/wpa_debug.h /^static inline void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len)$/;" f -wpa_hexdump_ascii include/utils/wpa_debug.h 157;" d -wpa_hexdump_ascii_key include/utils/wpa_debug.h /^static inline void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, size_t len)$/;" f -wpa_hexdump_ascii_key include/utils/wpa_debug.h 158;" d -wpa_hexdump_buf include/utils/wpa_debug.h /^static inline void wpa_hexdump_buf(int level, const char *title,$/;" f -wpa_hexdump_buf include/utils/wpa_debug.h 154;" d -wpa_hexdump_buf_key include/utils/wpa_debug.h /^static inline void wpa_hexdump_buf_key(int level, const char *title,$/;" f -wpa_hexdump_buf_key include/utils/wpa_debug.h 156;" d -wpa_hexdump_key include/utils/wpa_debug.h 155;" d -wpa_hexdump_key src/utils/wpa_debug.c /^void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len)$/;" f -wpa_hook_deinit src/esp_supplicant/esp_wpa_main.c /^bool wpa_hook_deinit(void)$/;" f -wpa_ie src/ap/wpa_auth_i.h /^ u8 *wpa_ie;$/;" m struct:wpa_authenticator -wpa_ie src/ap/wpa_auth_i.h /^ u8 *wpa_ie;$/;" m struct:wpa_state_machine -wpa_ie src/ap/wpa_auth_ie.h /^ const u8 *wpa_ie;$/;" m struct:wpa_eapol_ie_parse -wpa_ie src/rsn_supp/wpa_ie.h /^ const u8 *wpa_ie;$/;" m struct:wpa_eapol_ie_parse -wpa_ie_data src/common/wpa_common.h /^struct wpa_ie_data {$/;" s -wpa_ie_hdr src/common/wpa_common.h /^struct wpa_ie_hdr {$/;" s -wpa_ie_len src/ap/wpa_auth_i.h /^ size_t wpa_ie_len;$/;" m struct:wpa_authenticator -wpa_ie_len src/ap/wpa_auth_i.h /^ size_t wpa_ie_len;$/;" m struct:wpa_state_machine -wpa_ie_len src/ap/wpa_auth_ie.h /^ size_t wpa_ie_len;$/;" m struct:wpa_eapol_ie_parse -wpa_ie_len src/rsn_supp/wpa_ie.h /^ size_t wpa_ie_len;$/;" m struct:wpa_eapol_ie_parse -wpa_igtk_kde src/common/wpa_common.h /^struct wpa_igtk_kde {$/;" s -wpa_init src/ap/wpa_auth.c /^struct wpa_authenticator * wpa_init(const u8 *addr,$/;" f -wpa_install_key src/esp_supplicant/esp_wpa_main.c /^void wpa_install_key(enum wpa_alg alg, u8 *addr, int key_idx, int set_tx,$/;" f -wpa_key_mgmt src/ap/ap_config.h /^ int wpa_key_mgmt;$/;" m struct:hostapd_bss_config -wpa_key_mgmt src/ap/wpa_auth.h /^ int wpa_key_mgmt;$/;" m struct:wpa_auth_config -wpa_key_mgmt src/ap/wpa_auth_i.h /^ int wpa_key_mgmt; \/* the selected WPA_KEY_MGMT_* *\/$/;" m struct:wpa_state_machine -wpa_key_mgmt src/common/defs.h /^enum wpa_key_mgmt {$/;" g -wpa_key_mgmt_ft src/common/defs.h /^static inline int wpa_key_mgmt_ft(int akm)$/;" f -wpa_key_mgmt_sha256 src/common/defs.h /^static inline int wpa_key_mgmt_sha256(int akm)$/;" f -wpa_key_mgmt_to_bitfield src/common/wpa_common.c /^static int wpa_key_mgmt_to_bitfield(const u8 *s)$/;" f file: -wpa_key_mgmt_wpa_ieee8021x src/common/defs.h /^static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)$/;" f -wpa_key_mgmt_wpa_psk src/common/defs.h /^static inline int wpa_key_mgmt_wpa_psk(int akm)$/;" f -wpa_key_replay_counter src/ap/wpa_auth_i.h /^ struct wpa_key_replay_counter {$/;" s struct:wpa_state_machine -wpa_msg_cb_func include/utils/wpa_debug.h /^typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt,$/;" t -wpa_neg_complete src/esp_supplicant/esp_wpa_main.c /^void wpa_neg_complete()$/;" f -wpa_neg_complete src/rsn_supp/wpa.h /^ void (*wpa_neg_complete)();$/;" m struct:wpa_sm -wpa_pairwise src/ap/ap_config.h /^ int wpa_pairwise;$/;" m struct:hostapd_bss_config -wpa_pairwise src/ap/wpa_auth.h /^ int wpa_pairwise;$/;" m struct:wpa_auth_config -wpa_parse_generic src/ap/wpa_auth_ie.c /^static int wpa_parse_generic(const u8 *pos, const u8 *end,$/;" f file: -wpa_parse_generic src/rsn_supp/wpa_ie.c /^static int wpa_parse_generic(const u8 *pos, const u8 *end,$/;" f file: -wpa_parse_kde_ies src/ap/wpa_auth_ie.c /^int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)$/;" f -wpa_parse_wpa_ie src/rsn_supp/wpa_ie.c /^int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,$/;" f -wpa_parse_wpa_ie_rsn src/common/wpa_common.c /^int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,$/;" f -wpa_parse_wpa_ie_wpa src/common/wpa_common.c /^int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,$/;" f -wpa_passphrase src/ap/ap_config.h /^ char *wpa_passphrase;$/;" m struct:hostapd_ssid -wpa_pmk_to_ptk src/common/wpa_common.c /^void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,$/;" f -wpa_printf include/utils/wpa_debug.h 152;" d -wpa_printf include/utils/wpa_debug.h 76;" d -wpa_psk src/ap/ap_config.h /^ struct hostapd_wpa_psk *wpa_psk;$/;" m struct:hostapd_ssid typeref:struct:hostapd_ssid::hostapd_wpa_psk -wpa_psk_radius src/ap/ap_config.h /^ } wpa_psk_radius;$/;" m struct:hostapd_bss_config typeref:enum:hostapd_bss_config::__anon18 -wpa_ptk src/common/wpa_common.h /^struct wpa_ptk {$/;" s -wpa_ptk_group_state src/ap/wpa_auth_i.h /^ } wpa_ptk_group_state;$/;" m struct:wpa_state_machine typeref:enum:wpa_state_machine::__anon25 -wpa_ptk_rekey src/ap/ap_config.h /^ int wpa_ptk_rekey;$/;" m struct:hostapd_bss_config -wpa_ptk_rekey src/ap/wpa_auth.h /^ int wpa_ptk_rekey;$/;" m struct:wpa_auth_config -wpa_ptk_rekey src/rsn_supp/wpa.h /^ int wpa_ptk_rekey;$/;" m struct:wpa_sm -wpa_ptk_state src/ap/wpa_auth_i.h /^ } wpa_ptk_state;$/;" m struct:wpa_state_machine typeref:enum:wpa_state_machine::__anon24 -wpa_receive src/ap/wpa_auth.c /^void wpa_receive(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, u8 *data, size_t data_len)$/;" f -wpa_receive_error_report src/ap/wpa_auth.c /^static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth,$/;" f file: -wpa_register src/rsn_supp/wpa.c /^void wpa_register(char * payload, WPA_SEND_FUNC snd_func,$/;" f -wpa_rekey_gtk src/ap/wpa_auth.c /^static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)$/;" f file: -wpa_rekey_ptk src/ap/wpa_auth.c /^static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx)$/;" f file: -wpa_remove_ptk src/ap/wpa_auth.c /^void wpa_remove_ptk(struct wpa_state_machine *sm)$/;" f -wpa_replay_counter_mark_invalid src/ap/wpa_auth.c /^static void wpa_replay_counter_mark_invalid(struct wpa_key_replay_counter *ctr,$/;" f file: -wpa_replay_counter_valid src/ap/wpa_auth.c /^static int wpa_replay_counter_valid(struct wpa_key_replay_counter *ctr,$/;" f file: -wpa_report_ie_mismatch src/rsn_supp/wpa.c /^void wpa_report_ie_mismatch(struct wpa_sm *sm,$/;" f -wpa_request_new_ptk src/ap/wpa_auth.c /^static void wpa_request_new_ptk(struct wpa_state_machine *sm)$/;" f file: -wpa_selector_to_bitfield src/common/wpa_common.c /^static int wpa_selector_to_bitfield(const u8 *s)$/;" f file: -wpa_send_eapol src/ap/wpa_auth.c /^static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,$/;" f file: -wpa_send_eapol_timeout src/ap/wpa_auth.c /^static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx)$/;" f file: -wpa_sendto_wrapper src/esp_supplicant/esp_wpa_main.c /^void wpa_sendto_wrapper(void *buffer, u16 len)$/;" f -wpa_set_bss src/rsn_supp/wpa.c /^wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, char *passphrase, u8 *ssid, size_t ssid_len)$/;" f -wpa_set_passphrase src/rsn_supp/wpa.c /^wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len)$/;" f -wpa_set_pmk src/rsn_supp/wpa.c /^void wpa_set_pmk(uint8_t *pmk)$/;" f -wpa_set_profile src/rsn_supp/wpa.c /^void wpa_set_profile(u32 wpa_proto, u8 auth_mode)$/;" f -wpa_set_wnmsleep src/ap/wpa_auth.c /^void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag)$/;" f -wpa_sm src/ap/sta_info.h /^ struct wpa_state_machine *wpa_sm;$/;" m struct:sta_info typeref:struct:sta_info::wpa_state_machine -wpa_sm src/rsn_supp/wpa.h /^struct wpa_sm {$/;" s -wpa_sm_alloc_eapol src/esp_supplicant/esp_wpas_glue.c /^u8 *wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type,$/;" f -wpa_sm_cancel_auth_timeout src/rsn_supp/wpa.c /^static inline void wpa_sm_cancel_auth_timeout(struct wpa_sm *sm)$/;" f file: -wpa_sm_deauthenticate src/esp_supplicant/esp_wpas_glue.c /^void wpa_sm_deauthenticate(struct wpa_sm *sm, u8 reason_code)$/;" f -wpa_sm_disassociate src/esp_supplicant/esp_wpas_glue.c /^void wpa_sm_disassociate(struct wpa_sm *sm, int reason_code)$/;" f -wpa_sm_ether_send src/rsn_supp/wpa.c /^static inline int wpa_sm_ether_send( struct wpa_sm *sm, const u8 *dest, u16 proto,$/;" f file: -wpa_sm_free_eapol src/esp_supplicant/esp_wpas_glue.c /^void wpa_sm_free_eapol(u8 *buffer)$/;" f -wpa_sm_get_beacon_ie src/esp_supplicant/esp_wpas_glue.c /^int wpa_sm_get_beacon_ie(struct wpa_sm *sm)$/;" f -wpa_sm_get_bssid src/rsn_supp/wpa.c /^static inline int wpa_sm_get_bssid(struct wpa_sm *sm, u8 *bssid)$/;" f file: -wpa_sm_get_key src/rsn_supp/wpa.c /^wpa_sm_get_key(uint8_t *ifx, int *alg, u8 *addr, int *key_idx, u8 *key, size_t key_len, int key_entry_valid)$/;" f -wpa_sm_get_state src/rsn_supp/wpa.c /^static inline enum wpa_states wpa_sm_get_state(struct wpa_sm *sm)$/;" f file: -wpa_sm_key_request src/rsn_supp/wpa.c /^void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)$/;" f -wpa_sm_mlme_setprotection src/esp_supplicant/esp_wpas_glue.c /^int wpa_sm_mlme_setprotection(struct wpa_sm *sm, const u8 *addr,$/;" f -wpa_sm_rekey_ptk src/rsn_supp/wpa.c /^ void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx)$/;" f -wpa_sm_rx_eapol src/rsn_supp/wpa.c /^int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len)$/;" f -wpa_sm_set_key src/rsn_supp/wpa.c /^wpa_sm_set_key(struct install_key *key_sm, enum wpa_alg alg,$/;" f -wpa_sm_set_seq src/rsn_supp/wpa.c /^ void wpa_sm_set_seq(struct wpa_sm *sm, struct wpa_eapol_key *key, u8 isptk)$/;" f -wpa_sm_set_state src/rsn_supp/wpa.c /^void wpa_sm_set_state(enum wpa_states state)$/;" f -wpa_sm_step src/ap/wpa_auth.c /^static int wpa_sm_step(struct wpa_state_machine *sm)$/;" f file: -wpa_snprintf_hex src/utils/wpa_debug.c /^int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)$/;" f -wpa_snprintf_hex_uppercase src/utils/wpa_debug.c /^int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, size_t len)$/;" f -wpa_sta_connect src/esp_supplicant/esp_wifi_driver.h /^ void (*wpa_sta_connect)(uint8_t *bssid);$/;" m struct:wpa_funcs -wpa_sta_connect src/esp_supplicant/esp_wpa_main.c /^void wpa_sta_connect(uint8_t *bssid)$/;" f -wpa_sta_deinit src/esp_supplicant/esp_wifi_driver.h /^ bool (*wpa_sta_deinit)(void);$/;" m struct:wpa_funcs -wpa_sta_disconnect src/ap/wpa_auth.c /^static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,$/;" f file: -wpa_sta_in_4way_handshake src/esp_supplicant/esp_wifi_driver.h /^ bool (*wpa_sta_in_4way_handshake)(void);$/;" m struct:wpa_funcs -wpa_sta_in_4way_handshake src/rsn_supp/wpa.c /^bool wpa_sta_in_4way_handshake(void)$/;" f -wpa_sta_init src/esp_supplicant/esp_wifi_driver.h /^ void (*wpa_sta_init)(void);$/;" m struct:wpa_funcs -wpa_sta_rx_eapol src/esp_supplicant/esp_wifi_driver.h /^ int (*wpa_sta_rx_eapol)(u8 *src_addr, u8 *buf, u32 len);$/;" m struct:wpa_funcs -wpa_state src/rsn_supp/wpa.h /^ enum wpa_states wpa_state;$/;" m struct:wpa_sm typeref:enum:wpa_sm::wpa_states -wpa_state_machine src/ap/wpa_auth_i.h /^struct wpa_state_machine {$/;" s -wpa_states src/common/defs.h /^enum wpa_states {$/;" g -wpa_strdup_tchar include/utils/common.h 308;" d -wpa_strict_rekey src/ap/ap_config.h /^ int wpa_strict_rekey;$/;" m struct:hostapd_bss_config -wpa_strict_rekey src/ap/wpa_auth.h /^ int wpa_strict_rekey;$/;" m struct:wpa_auth_config -wpa_stsl_negotiation src/ap/wpa_auth_i.h /^struct wpa_stsl_negotiation {$/;" s -wpa_supplicant_check_group_cipher src/rsn_supp/wpa.c /^int wpa_supplicant_check_group_cipher(int group_cipher,$/;" f -wpa_supplicant_clr_countermeasures src/rsn_supp/wpa.c /^void wpa_supplicant_clr_countermeasures(u16 *pisunicast)$/;" f -wpa_supplicant_decrypt_key_data src/rsn_supp/wpa.c /^ int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,$/;" f -wpa_supplicant_get_pmk src/rsn_supp/wpa.c /^int wpa_supplicant_get_pmk(struct wpa_sm *sm)$/;" f -wpa_supplicant_gtk_in_use src/rsn_supp/wpa.c /^bool wpa_supplicant_gtk_in_use(struct wpa_sm *sm, struct wpa_gtk_data *gd)$/;" f -wpa_supplicant_gtk_tx_bit_workaround src/rsn_supp/wpa.c /^int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm,$/;" f -wpa_supplicant_install_gtk src/rsn_supp/wpa.c /^int wpa_supplicant_install_gtk(struct wpa_sm *sm,$/;" f -wpa_supplicant_install_ptk src/rsn_supp/wpa.c /^int wpa_supplicant_install_ptk(struct wpa_sm *sm)$/;" f -wpa_supplicant_key_neg_complete src/rsn_supp/wpa.c /^void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,$/;" f -wpa_supplicant_pairwise_gtk src/rsn_supp/wpa.c /^int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,$/;" f -wpa_supplicant_parse_ies src/rsn_supp/wpa_ie.c /^int wpa_supplicant_parse_ies(const u8 *buf, size_t len,$/;" f -wpa_supplicant_process_1_of_2 src/rsn_supp/wpa.c /^ void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,$/;" f -wpa_supplicant_process_1_of_2_rsn src/rsn_supp/wpa.c /^ int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,$/;" f -wpa_supplicant_process_1_of_2_wpa src/rsn_supp/wpa.c /^ int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,$/;" f -wpa_supplicant_process_1_of_4 src/rsn_supp/wpa.c /^void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,$/;" f -wpa_supplicant_process_3_of_4 src/rsn_supp/wpa.c /^ void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,$/;" f -wpa_supplicant_send_2_of_2 src/rsn_supp/wpa.c /^ int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,$/;" f -wpa_supplicant_send_2_of_2_txcallback src/rsn_supp/wpa.c /^ int wpa_supplicant_send_2_of_2_txcallback(struct wpa_sm *sm)$/;" f -wpa_supplicant_send_2_of_4 src/rsn_supp/wpa.c /^int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,$/;" f -wpa_supplicant_send_4_of_4 src/rsn_supp/wpa.c /^ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,$/;" f -wpa_supplicant_send_4_of_4_txcallback src/rsn_supp/wpa.c /^ int wpa_supplicant_send_4_of_4_txcallback(struct wpa_sm *sm)$/;" f -wpa_supplicant_stop_countermeasures src/rsn_supp/wpa.c /^void wpa_supplicant_stop_countermeasures(u16 *pisunicast)$/;" f -wpa_supplicant_validate_ie src/rsn_supp/wpa.c /^ int wpa_supplicant_validate_ie(struct wpa_sm *sm,$/;" f -wpa_supplicant_verify_eapol_key_mic src/rsn_supp/wpa.c /^ int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,$/;" f -wpa_swap_16 include/utils/common.h /^static inline unsigned short wpa_swap_16(unsigned short v)$/;" f -wpa_swap_32 include/utils/common.h /^static inline unsigned int wpa_swap_32(unsigned int v)$/;" f -wpa_unicode2ascii_inplace include/utils/common.h 307;" d -wpa_use_aes_cmac src/ap/wpa_auth.c /^static int wpa_use_aes_cmac(struct wpa_state_machine *sm)$/;" f file: -wpa_validate_wpa_ie src/ap/wpa_auth_ie.c /^int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,$/;" f -wpa_verify_key_mic src/ap/wpa_auth.c /^static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len)$/;" f file: -wpa_wnmsleep_gtk_subelem src/ap/wpa_auth.c /^int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)$/;" f -wpa_wnmsleep_igtk_subelem src/ap/wpa_auth.c /^int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)$/;" f -wpa_wnmsleep_rekey_gtk src/ap/wpa_auth.c /^void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)$/;" f -wpa_write_rsn_ie src/ap/wpa_auth_ie.c /^int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,$/;" f -wpa_write_wpa_ie src/ap/wpa_auth_ie.c /^static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)$/;" f file: -wpabuf include/utils/wpabuf.h /^struct wpabuf {$/;" s -wpabuf_alloc src/utils/wpabuf.c /^struct wpabuf * wpabuf_alloc(size_t len)$/;" f -wpabuf_alloc_copy src/utils/wpabuf.c /^struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len)$/;" f -wpabuf_alloc_ext_data src/utils/wpabuf.c /^struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len)$/;" f -wpabuf_concat src/utils/wpabuf.c /^struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b)$/;" f -wpabuf_dup src/utils/wpabuf.c /^struct wpabuf * wpabuf_dup(const struct wpabuf *src)$/;" f -wpabuf_free src/utils/wpabuf.c /^void wpabuf_free(struct wpabuf *buf)$/;" f -wpabuf_get_trace src/utils/wpabuf.c /^static struct wpabuf_trace * wpabuf_get_trace(const struct wpabuf *buf)$/;" f file: -wpabuf_head include/utils/wpabuf.h /^static inline const void * wpabuf_head(const struct wpabuf *buf)$/;" f -wpabuf_head_u8 include/utils/wpabuf.h /^static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf)$/;" f -wpabuf_len include/utils/wpabuf.h /^static inline size_t wpabuf_len(const struct wpabuf *buf)$/;" f -wpabuf_mhead include/utils/wpabuf.h /^static inline void * wpabuf_mhead(struct wpabuf *buf)$/;" f -wpabuf_mhead_u8 include/utils/wpabuf.h /^static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf)$/;" f -wpabuf_overflow src/utils/wpabuf.c /^static void wpabuf_overflow(const struct wpabuf *buf, size_t len)$/;" f file: -wpabuf_printf src/utils/wpabuf.c /^void wpabuf_printf(struct wpabuf *buf, char *fmt, ...)$/;" f -wpabuf_put src/utils/wpabuf.c /^void * wpabuf_put(struct wpabuf *buf, size_t len)$/;" f -wpabuf_put_be16 include/utils/wpabuf.h /^static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data)$/;" f -wpabuf_put_be24 include/utils/wpabuf.h /^static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data)$/;" f -wpabuf_put_be32 include/utils/wpabuf.h /^static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data)$/;" f -wpabuf_put_buf include/utils/wpabuf.h /^static inline void wpabuf_put_buf(struct wpabuf *dst,$/;" f -wpabuf_put_data include/utils/wpabuf.h /^static inline void wpabuf_put_data(struct wpabuf *buf, const void *data,$/;" f -wpabuf_put_le16 include/utils/wpabuf.h /^static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data)$/;" f -wpabuf_put_le32 include/utils/wpabuf.h /^static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data)$/;" f -wpabuf_put_str include/utils/wpabuf.h /^static inline void wpabuf_put_str(struct wpabuf *dst, const char *str)$/;" f -wpabuf_put_u8 include/utils/wpabuf.h /^static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data)$/;" f -wpabuf_resize src/utils/wpabuf.c /^int wpabuf_resize(struct wpabuf **_buf, size_t add_len)$/;" f -wpabuf_set include/utils/wpabuf.h /^static inline void wpabuf_set(struct wpabuf *buf, const void *data, size_t len)$/;" f -wpabuf_size include/utils/wpabuf.h /^static inline size_t wpabuf_size(const struct wpabuf *buf)$/;" f -wpabuf_tailroom include/utils/wpabuf.h /^static inline size_t wpabuf_tailroom(const struct wpabuf *buf)$/;" f -wpabuf_trace src/utils/wpabuf.c /^struct wpabuf_trace {$/;" s file: -wpabuf_zeropad src/utils/wpabuf.c /^struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len)$/;" f -wps src/esp_supplicant/esp_wifi_driver.h /^ uint8_t *wps;$/;" m struct:wps_scan_ie -wps src/wps/wps.h /^ struct wps_context *wps;$/;" m struct:wps_config typeref:struct:wps_config::wps_context -wps src/wps/wps.h /^ struct wps_data *wps;$/;" m struct:wps_sm typeref:struct:wps_sm::wps_data -wps src/wps/wps_i.h /^ struct wps_context *wps;$/;" m struct:wps_data typeref:struct:wps_data::wps_context -wps src/wps/wps_registrar.c /^ struct wps_context *wps;$/;" m struct:wps_registrar typeref:struct:wps_registrar::wps_context file: -wpsTask src/esp_supplicant/esp_wps.c /^void wpsTask(void *pvParameters )$/;" f -wps_add_discard_ap src/esp_supplicant/esp_wps.c /^void wps_add_discard_ap(u8 *bssid)$/;" f -wps_ap_priority_compar src/wps/wps.c /^int wps_ap_priority_compar(const struct wpabuf *wps_a,$/;" f -wps_assoc_state src/wps/wps_defs.h /^enum wps_assoc_state {$/;" g -wps_attr_text src/wps/wps.c /^int wps_attr_text(struct wpabuf *data, char *buf, char *end)$/;" f -wps_attribute src/wps/wps_defs.h /^enum wps_attribute {$/;" g -wps_authorized_macs src/wps/wps_registrar.c /^const u8 * wps_authorized_macs(struct wps_registrar *reg, size_t *count)$/;" f -wps_build_ap_cred src/wps/wps_registrar.c /^static struct wpabuf * wps_build_ap_cred(struct wps_data *wps)$/;" f file: -wps_build_ap_settings src/wps/wps_enrollee.c /^static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *plain)$/;" f file: -wps_build_ap_settings src/wps/wps_registrar.c /^static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *msg)$/;" f file: -wps_build_ap_setup_locked src/wps/wps_registrar.c /^static int wps_build_ap_setup_locked(struct wps_context *wps,$/;" f file: -wps_build_assoc_req_ie src/wps/wps.c /^struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type)$/;" f -wps_build_assoc_resp_ie src/wps/wps.c /^struct wpabuf * wps_build_assoc_resp_ie(void)$/;" f -wps_build_assoc_state src/wps/wps_attr_build.c /^int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg)$/;" f -wps_build_auth_type_flags src/wps/wps_attr_build.c /^int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg)$/;" f -wps_build_authenticator src/wps/wps_attr_build.c /^int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg)$/;" f -wps_build_config_error src/wps/wps_attr_build.c /^int wps_build_config_error(struct wpabuf *msg, u16 err)$/;" f -wps_build_config_methods src/wps/wps_attr_build.c /^int wps_build_config_methods(struct wpabuf *msg, u16 methods)$/;" f -wps_build_config_methods_r src/wps/wps_registrar.c /^static int wps_build_config_methods_r(struct wps_registrar *reg,$/;" f file: -wps_build_conn_type_flags src/wps/wps_attr_build.c /^int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg)$/;" f -wps_build_cred src/wps/wps_registrar.c /^int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)$/;" f -wps_build_cred_auth_type src/wps/wps_enrollee.c /^static int wps_build_cred_auth_type(struct wps_data *wps, struct wpabuf *msg)$/;" f file: -wps_build_cred_auth_type src/wps/wps_registrar.c /^static int wps_build_cred_auth_type(struct wpabuf *msg,$/;" f file: -wps_build_cred_encr_type src/wps/wps_enrollee.c /^static int wps_build_cred_encr_type(struct wps_data *wps, struct wpabuf *msg)$/;" f file: -wps_build_cred_encr_type src/wps/wps_registrar.c /^static int wps_build_cred_encr_type(struct wpabuf *msg,$/;" f file: -wps_build_cred_mac_addr src/wps/wps_enrollee.c /^static int wps_build_cred_mac_addr(struct wps_data *wps, struct wpabuf *msg)$/;" f file: -wps_build_cred_mac_addr src/wps/wps_registrar.c /^static int wps_build_cred_mac_addr(struct wpabuf *msg,$/;" f file: -wps_build_cred_network_idx src/wps/wps_registrar.c /^static int wps_build_cred_network_idx(struct wpabuf *msg,$/;" f file: -wps_build_cred_network_key src/wps/wps_enrollee.c /^static int wps_build_cred_network_key(struct wps_data *wps, struct wpabuf *msg)$/;" f file: -wps_build_cred_network_key src/wps/wps_registrar.c /^static int wps_build_cred_network_key(struct wpabuf *msg,$/;" f file: -wps_build_cred_ssid src/wps/wps_enrollee.c /^static int wps_build_cred_ssid(struct wps_data *wps, struct wpabuf *msg)$/;" f file: -wps_build_cred_ssid src/wps/wps_registrar.c /^static int wps_build_cred_ssid(struct wpabuf *msg,$/;" f file: -wps_build_credential src/wps/wps_registrar.c /^static int wps_build_credential(struct wpabuf *msg,$/;" f file: -wps_build_credential_wrap src/wps/wps_registrar.c /^int wps_build_credential_wrap(struct wpabuf *msg,$/;" f -wps_build_dev_name src/wps/wps_dev_attr.c /^int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg)$/;" f -wps_build_dev_password_id src/wps/wps_attr_build.c /^int wps_build_dev_password_id(struct wpabuf *msg, u16 id)$/;" f -wps_build_device_attrs src/wps/wps_dev_attr.c /^int wps_build_device_attrs(struct wps_device_data *dev, struct wpabuf *msg)$/;" f -wps_build_e_hash src/wps/wps_enrollee.c /^static int wps_build_e_hash(struct wps_data *wps, struct wpabuf *msg)$/;" f file: -wps_build_e_snonce1 src/wps/wps_enrollee.c /^static int wps_build_e_snonce1(struct wps_data *wps, struct wpabuf *msg)$/;" f file: -wps_build_e_snonce2 src/wps/wps_enrollee.c /^static int wps_build_e_snonce2(struct wps_data *wps, struct wpabuf *msg)$/;" f file: -wps_build_encr_settings src/wps/wps_attr_build.c /^int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,$/;" f -wps_build_encr_type_flags src/wps/wps_attr_build.c /^int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg)$/;" f -wps_build_enrollee_nonce src/wps/wps_attr_build.c /^int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg)$/;" f -wps_build_ic_appie_wps_ar src/esp_supplicant/esp_wps.c /^wps_build_ic_appie_wps_ar(void)$/;" f file: -wps_build_ic_appie_wps_pr src/esp_supplicant/esp_wps.c /^wps_build_ic_appie_wps_pr(void)$/;" f file: -wps_build_key_wrap_auth src/wps/wps_attr_build.c /^int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg)$/;" f -wps_build_m1 src/wps/wps_enrollee.c /^static struct wpabuf * wps_build_m1(struct wps_data *wps)$/;" f file: -wps_build_m2 src/wps/wps_registrar.c /^static struct wpabuf * wps_build_m2(struct wps_data *wps)$/;" f file: -wps_build_m2d src/wps/wps_registrar.c /^static struct wpabuf * wps_build_m2d(struct wps_data *wps)$/;" f file: -wps_build_m3 src/wps/wps_enrollee.c /^static struct wpabuf * wps_build_m3(struct wps_data *wps)$/;" f file: -wps_build_m4 src/wps/wps_registrar.c /^static struct wpabuf * wps_build_m4(struct wps_data *wps)$/;" f file: -wps_build_m5 src/wps/wps_enrollee.c /^static struct wpabuf * wps_build_m5(struct wps_data *wps)$/;" f file: -wps_build_m6 src/wps/wps_registrar.c /^static struct wpabuf * wps_build_m6(struct wps_data *wps)$/;" f file: -wps_build_m7 src/wps/wps_enrollee.c /^static struct wpabuf * wps_build_m7(struct wps_data *wps)$/;" f file: -wps_build_m8 src/wps/wps_registrar.c /^static struct wpabuf * wps_build_m8(struct wps_data *wps)$/;" f file: -wps_build_mac_addr src/wps/wps_enrollee.c /^static int wps_build_mac_addr(struct wps_data *wps, struct wpabuf *msg) {$/;" f file: -wps_build_manufacturer src/wps/wps_dev_attr.c /^int wps_build_manufacturer(struct wps_device_data *dev, struct wpabuf *msg)$/;" f -wps_build_model_name src/wps/wps_dev_attr.c /^int wps_build_model_name(struct wps_device_data *dev, struct wpabuf *msg)$/;" f -wps_build_model_number src/wps/wps_dev_attr.c /^int wps_build_model_number(struct wps_device_data *dev, struct wpabuf *msg)$/;" f -wps_build_msg_type src/wps/wps_attr_build.c /^int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type)$/;" f -wps_build_nfc_pw_token src/wps/wps_common.c /^struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,$/;" f -wps_build_oob_dev_pw src/wps/wps_attr_build.c /^int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id,$/;" f -wps_build_os_version src/wps/wps_dev_attr.c /^int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg)$/;" f -wps_build_primary_dev_type src/wps/wps_dev_attr.c /^int wps_build_primary_dev_type(struct wps_device_data *dev, struct wpabuf *msg)$/;" f -wps_build_probe_config_methods src/wps/wps_registrar.c /^static int wps_build_probe_config_methods(struct wps_registrar *reg,$/;" f file: -wps_build_probe_req_ie src/wps/wps.c /^struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev,$/;" f -wps_build_public_key src/wps/wps_attr_build.c /^int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg, wps_key_mode_t mode)$/;" f -wps_build_r_hash src/wps/wps_registrar.c /^static int wps_build_r_hash(struct wps_data *wps, struct wpabuf *msg)$/;" f file: -wps_build_r_snonce1 src/wps/wps_registrar.c /^static int wps_build_r_snonce1(struct wps_data *wps, struct wpabuf *msg)$/;" f file: -wps_build_r_snonce2 src/wps/wps_registrar.c /^static int wps_build_r_snonce2(struct wps_data *wps, struct wpabuf *msg)$/;" f file: -wps_build_registrar_nonce src/wps/wps_attr_build.c /^int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg)$/;" f -wps_build_req_dev_type src/wps/wps_dev_attr.c /^int wps_build_req_dev_type(struct wps_device_data *dev, struct wpabuf *msg,$/;" f -wps_build_req_type src/wps/wps_attr_build.c /^int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type)$/;" f -wps_build_resp_type src/wps/wps_attr_build.c /^int wps_build_resp_type(struct wpabuf *msg, enum wps_response_type type)$/;" f -wps_build_rf_bands src/wps/wps_dev_attr.c /^int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg)$/;" f -wps_build_secondary_dev_type src/wps/wps_dev_attr.c /^int wps_build_secondary_dev_type(struct wps_device_data *dev,$/;" f -wps_build_sel_pbc_reg_uuid_e src/wps/wps_registrar.c /^static int wps_build_sel_pbc_reg_uuid_e(struct wps_registrar *reg,$/;" f file: -wps_build_sel_reg_config_methods src/wps/wps_registrar.c /^static int wps_build_sel_reg_config_methods(struct wps_registrar *reg,$/;" f file: -wps_build_sel_reg_dev_password_id src/wps/wps_registrar.c /^static int wps_build_sel_reg_dev_password_id(struct wps_registrar *reg,$/;" f file: -wps_build_selected_registrar src/wps/wps_registrar.c /^static int wps_build_selected_registrar(struct wps_registrar *reg,$/;" f file: -wps_build_serial_number src/wps/wps_dev_attr.c /^static int wps_build_serial_number(struct wps_device_data *dev,$/;" f file: -wps_build_uuid_e src/wps/wps_attr_build.c /^int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid)$/;" f -wps_build_uuid_r src/wps/wps_registrar.c /^static int wps_build_uuid_r(struct wps_data *wps, struct wpabuf *msg)$/;" f file: -wps_build_vendor_ext src/wps/wps_dev_attr.c /^int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg)$/;" f -wps_build_vendor_ext_m1 src/wps/wps_dev_attr.c /^int wps_build_vendor_ext_m1(struct wps_device_data *dev, struct wpabuf *msg)$/;" f -wps_build_version src/wps/wps_attr_build.c /^int wps_build_version(struct wpabuf *msg)$/;" f -wps_build_wfa_ext src/wps/wps_attr_build.c /^int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,$/;" f -wps_build_wps_state src/wps/wps_enrollee.c /^static int wps_build_wps_state(struct wps_data *wps, struct wpabuf *msg)$/;" f file: -wps_build_wps_state src/wps/wps_registrar.c /^static int wps_build_wps_state(struct wps_context *wps, struct wpabuf *msg)$/;" f file: -wps_build_wsc_ack src/wps/wps_common.c /^struct wpabuf * wps_build_wsc_ack(struct wps_data *wps)$/;" f -wps_build_wsc_done src/wps/wps_enrollee.c /^static struct wpabuf * wps_build_wsc_done(struct wps_data *wps)$/;" f file: -wps_build_wsc_nack src/wps/wps_common.c /^struct wpabuf * wps_build_wsc_nack(struct wps_data *wps)$/;" f -wps_calc_key_mode src/wps/wps_i.h /^typedef enum wps_calc_key_mode {$/;" g -wps_cb_new_psk src/wps/wps_registrar.c /^static int wps_cb_new_psk(struct wps_registrar *reg, const u8 *mac_addr,$/;" f file: -wps_cb_pin_needed src/wps/wps_registrar.c /^static void wps_cb_pin_needed(struct wps_registrar *reg, const u8 *uuid_e,$/;" f file: -wps_cb_reg_success src/wps/wps_registrar.c /^static void wps_cb_reg_success(struct wps_registrar *reg, const u8 *mac_addr,$/;" f file: -wps_cb_set_ie src/wps/wps_registrar.c /^static int wps_cb_set_ie(struct wps_registrar *reg, struct wpabuf *beacon_ie,$/;" f file: -wps_cb_set_sel_reg src/wps/wps_registrar.c /^static void wps_cb_set_sel_reg(struct wps_registrar *reg)$/;" f file: -wps_cb_status src/wps/wps.h /^enum wps_cb_status {$/;" g -wps_cfg src/wps/wps.h /^ struct wps_config *wps_cfg;$/;" m struct:wps_sm typeref:struct:wps_sm::wps_config -wps_check_wifi_mode src/esp_supplicant/esp_wps.c /^int wps_check_wifi_mode(void)$/;" f -wps_config src/wps/wps.h /^struct wps_config {$/;" s -wps_config_error src/wps/wps_defs.h /^enum wps_config_error {$/;" g -wps_config_methods_str2bin src/wps/wps_common.c /^u16 wps_config_methods_str2bin(const char *str)$/;" f -wps_context src/wps/wps.h /^struct wps_context {$/;" s -wps_cred_processing src/ap/ap_config.h /^ int wps_cred_processing;$/;" m struct:hostapd_bss_config -wps_cred_update src/wps/wps_registrar.c /^static void wps_cred_update(struct wps_credential *dst,$/;" f file: -wps_credential src/wps/wps.h /^struct wps_credential {$/;" s -wps_ctx src/wps/wps.h /^ struct wps_context *wps_ctx;$/;" m struct:wps_sm typeref:struct:wps_sm::wps_context -wps_data src/wps/wps_i.h /^struct wps_data {$/;" s -wps_decrypt_encr_settings src/wps/wps_common.c /^struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,$/;" f -wps_deinit src/esp_supplicant/esp_wps.c /^void wps_deinit(void)$/;" f -wps_delete_timer src/esp_supplicant/esp_wps.c /^int wps_delete_timer(void)$/;" f -wps_derive_keys src/wps/wps_common.c /^int wps_derive_keys(struct wps_data *wps)$/;" f -wps_derive_psk src/wps/wps_common.c /^void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,$/;" f -wps_dev_categ src/wps/wps_defs.h /^enum wps_dev_categ {$/;" g -wps_dev_deinit src/esp_supplicant/esp_wps.c /^int wps_dev_deinit(struct wps_device_data *dev)$/;" f -wps_dev_init src/esp_supplicant/esp_wps.c /^int wps_dev_init(void)$/;" f -wps_dev_password_id src/wps/wps_defs.h /^enum wps_dev_password_id {$/;" g -wps_dev_subcateg src/wps/wps_defs.h /^enum wps_dev_subcateg {$/;" g -wps_dev_type_bin2str src/wps/wps_common.c /^char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,$/;" f -wps_dev_type_str2bin src/wps/wps_common.c /^int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN])$/;" f -wps_device_clone_data src/wps/wps_registrar.c /^static void wps_device_clone_data(struct wps_device_data *dst,$/;" f file: -wps_device_data src/wps/wps.h /^struct wps_device_data {$/;" s -wps_device_data_dup src/wps/wps_dev_attr.c /^void wps_device_data_dup(struct wps_device_data *dst,$/;" f -wps_device_data_free src/wps/wps_dev_attr.c /^void wps_device_data_free(struct wps_device_data *dev)$/;" f -wps_device_get src/wps/wps_registrar.c /^static struct wps_registrar_device * wps_device_get(struct wps_registrar *reg,$/;" f file: -wps_device_store src/wps/wps_registrar.c /^int wps_device_store(struct wps_registrar *reg,$/;" f -wps_eapol_start_timer src/wps/wps.h /^ ETSTimer wps_eapol_start_timer;$/;" m struct:wps_sm -wps_enrollee_get_msg src/wps/wps_enrollee.c /^struct wpabuf * wps_enrollee_get_msg(struct wps_data *wps,$/;" f -wps_enrollee_process_msg src/wps/wps_enrollee.c /^enum wps_process_res wps_enrollee_process_msg(struct wps_data *wps,$/;" f -wps_enrollee_process_msg_frag src/esp_supplicant/esp_wps.c /^int wps_enrollee_process_msg_frag(struct wpabuf **buf, int tot_len, u8 *frag_data, int frag_len, u8 flag)$/;" f -wps_error_indication src/wps/wps_defs.h /^enum wps_error_indication {$/;" g -wps_event src/wps/wps.h /^enum wps_event {$/;" g -wps_event_data src/wps/wps.h /^union wps_event_data {$/;" u -wps_event_er_ap src/wps/wps.h /^ struct wps_event_er_ap {$/;" s union:wps_event_data -wps_event_er_ap_settings src/wps/wps.h /^ struct wps_event_er_ap_settings {$/;" s union:wps_event_data -wps_event_er_enrollee src/wps/wps.h /^ struct wps_event_er_enrollee {$/;" s union:wps_event_data -wps_event_er_set_selected_registrar src/wps/wps.h /^ struct wps_event_er_set_selected_registrar {$/;" s union:wps_event_data -wps_event_fail src/wps/wps.h /^ struct wps_event_fail {$/;" s union:wps_event_data -wps_event_m2d src/wps/wps.h /^ struct wps_event_m2d {$/;" s union:wps_event_data -wps_event_pwd_auth_fail src/wps/wps.h /^ struct wps_event_pwd_auth_fail {$/;" s union:wps_event_data -wps_factory_information_t include/esp_supplicant/esp_wps.h /^} wps_factory_information_t;$/;" t typeref:struct:__anon89 -wps_fail_event src/wps/wps_common.c /^void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,$/;" f -wps_finish src/esp_supplicant/esp_wps.c /^int wps_finish(void)$/;" f -wps_free_devices src/wps/wps_registrar.c /^static void wps_free_devices(struct wps_registrar_device *dev)$/;" f file: -wps_free_nfc_pw_tokens src/wps/wps_registrar.c /^static void wps_free_nfc_pw_tokens(struct dl_list *tokens, u16 pw_id)$/;" f file: -wps_free_nfc_pw_tokens src/wps/wps_registrar.c 70;" d file: -wps_free_pbc_sessions src/wps/wps_registrar.c /^static void wps_free_pbc_sessions(struct wps_pbc_session *pbc)$/;" f file: -wps_free_pending_msgs src/wps/wps.c /^void wps_free_pending_msgs(struct upnp_pending_message *msgs)$/;" f -wps_free_pin src/wps/wps_registrar.c /^static void wps_free_pin(struct wps_uuid_pin *pin)$/;" f file: -wps_free_pins src/wps/wps_registrar.c /^static void wps_free_pins(struct dl_list *pins)$/;" f file: -wps_funcs src/esp_supplicant/esp_wifi_driver.h /^struct wps_funcs {$/;" s -wps_generate_pin src/wps/wps_common.c /^unsigned int wps_generate_pin(void)$/;" f -wps_get_dev_password src/wps/wps_registrar.c /^static int wps_get_dev_password(struct wps_data *wps)$/;" f file: -wps_get_msg src/wps/wps.c /^struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code)$/;" f -wps_get_nfc_pw_token src/wps/wps_registrar.c /^static struct wps_nfc_pw_token * wps_get_nfc_pw_token(struct dl_list *tokens,$/;" f file: -wps_get_oob_cred src/wps/wps_common.c /^struct wpabuf * wps_get_oob_cred(struct wps_context *wps)$/;" f -wps_get_status src/esp_supplicant/esp_wps.c /^int wps_get_status(void)$/;" f -wps_get_type src/esp_supplicant/esp_wps.c /^int wps_get_type(void)$/;" f -wps_get_uuid_e src/wps/wps.c /^const u8 * wps_get_uuid_e(const struct wpabuf *msg)$/;" f -wps_ie_encapsulate src/wps/wps_attr_build.c /^struct wpabuf * wps_ie_encapsulate(struct wpabuf *data)$/;" f -wps_init src/esp_supplicant/esp_wps.c /^struct wps_data *wps_init(void)$/;" f -wps_ioctl_param_t src/esp_supplicant/esp_wps.c /^} wps_ioctl_param_t;$/;" t typeref:struct:__anon33 file: -wps_is_20 src/wps/wps.c /^int wps_is_20(const struct wpabuf *msg)$/;" f -wps_is_addr_authorized src/wps/wps.c /^int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,$/;" f -wps_is_selected_pbc_registrar src/wps/wps.c /^int wps_is_selected_pbc_registrar(const struct wpabuf *msg, u8 *bssid)$/;" f -wps_is_selected_pin_registrar src/wps/wps.c /^int wps_is_selected_pin_registrar(const struct wpabuf *msg, u8 *bssid)$/;" f -wps_kdf src/wps/wps_common.c /^void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,$/;" f -wps_key_mode_t src/wps/wps_i.h /^} wps_key_mode_t;$/;" t typeref:enum:wps_calc_key_mode -wps_key_save src/esp_supplicant/esp_wps.c /^wps_key_save(char *key, u8 key_len)$/;" f -wps_msg_flag src/wps/wps_defs.h /^enum wps_msg_flag {$/;" g -wps_msg_timeout_timer src/wps/wps.h /^ ETSTimer wps_msg_timeout_timer;$/;" m struct:wps_sm -wps_msg_type src/wps/wps_defs.h /^enum wps_msg_type {$/;" g -wps_nfc_dev_pw src/ap/ap_config.h /^ struct wpabuf *wps_nfc_dev_pw;$/;" m struct:hostapd_bss_config typeref:struct:hostapd_bss_config::wpabuf -wps_nfc_dev_pw_id src/ap/ap_config.h /^ int wps_nfc_dev_pw_id;$/;" m struct:hostapd_bss_config -wps_nfc_dh_privkey src/ap/ap_config.h /^ struct wpabuf *wps_nfc_dh_privkey;$/;" m struct:hostapd_bss_config typeref:struct:hostapd_bss_config::wpabuf -wps_nfc_dh_pubkey src/ap/ap_config.h /^ struct wpabuf *wps_nfc_dh_pubkey;$/;" m struct:hostapd_bss_config typeref:struct:hostapd_bss_config::wpabuf -wps_nfc_pw_token src/wps/wps_registrar.c /^struct wps_nfc_pw_token {$/;" s file: -wps_nfc_token_gen src/wps/wps_common.c /^struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,$/;" f -wps_oob_use_cred src/wps/wps_common.c /^int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr)$/;" f -wps_parse_attr src/wps/wps_attr_parse.h /^struct wps_parse_attr {$/;" s -wps_parse_msg src/wps/wps_attr_parse.c /^int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)$/;" f -wps_parse_scan_result src/esp_supplicant/esp_wifi_driver.h /^ bool (*wps_parse_scan_result)(struct wps_scan_ie *scan);$/;" m struct:wps_funcs -wps_parse_scan_result src/esp_supplicant/esp_wps.c /^wps_parse_scan_result(struct wps_scan_ie *scan)$/;" f file: -wps_parse_vendor_ext src/wps/wps_attr_parse.c /^static int wps_parse_vendor_ext(struct wps_parse_attr *attr, const u8 *pos,$/;" f file: -wps_parse_vendor_ext_wfa src/wps/wps_attr_parse.c /^static int wps_parse_vendor_ext_wfa(struct wps_parse_attr *attr, const u8 *pos,$/;" f file: -wps_pbc_overlap_event src/wps/wps_common.c /^void wps_pbc_overlap_event(struct wps_context *wps)$/;" f -wps_pbc_session src/wps/wps_registrar.c /^struct wps_pbc_session {$/;" s file: -wps_pbc_timeout_event src/wps/wps_common.c /^void wps_pbc_timeout_event(struct wps_context *wps)$/;" f -wps_pin_checksum src/wps/wps_common.c /^unsigned int wps_pin_checksum(unsigned int pin)$/;" f -wps_pin_requests src/ap/ap_config.h /^ char *wps_pin_requests;$/;" m struct:hostapd_bss_config -wps_pin_revealed src/wps/wps_i.h /^ int wps_pin_revealed;$/;" m struct:wps_data -wps_pin_str_valid src/wps/wps_common.c /^int wps_pin_str_valid(const char *pin)$/;" f -wps_pin_valid src/wps/wps_common.c /^unsigned int wps_pin_valid(unsigned int pin)$/;" f -wps_post src/esp_supplicant/esp_wps.c /^ETS_STATUS wps_post(ETSSignal sig, ETSParam par)$/;" f -wps_post_block src/esp_supplicant/esp_wps.c /^int wps_post_block(ETSSignal sig, void *arg)$/;" f -wps_process_ap_settings src/wps/wps_attr_process.c /^int wps_process_ap_settings(struct wps_parse_attr *attr,$/;" f -wps_process_ap_settings_e src/wps/wps_enrollee.c /^static int wps_process_ap_settings_e(struct wps_data *wps,$/;" f file: -wps_process_ap_settings_r src/wps/wps_registrar.c /^static int wps_process_ap_settings_r(struct wps_data *wps,$/;" f file: -wps_process_assoc_state src/wps/wps_registrar.c /^static int wps_process_assoc_state(struct wps_data *wps, const u8 *assoc)$/;" f file: -wps_process_auth_type_flags src/wps/wps_registrar.c /^static int wps_process_auth_type_flags(struct wps_data *wps, const u8 *auth)$/;" f file: -wps_process_authenticator src/wps/wps_attr_process.c /^int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,$/;" f -wps_process_config_error src/wps/wps_registrar.c /^static int wps_process_config_error(struct wps_data *wps, const u8 *err)$/;" f file: -wps_process_config_methods src/wps/wps_registrar.c /^static int wps_process_config_methods(struct wps_data *wps, const u8 *methods)$/;" f file: -wps_process_conn_type_flags src/wps/wps_registrar.c /^static int wps_process_conn_type_flags(struct wps_data *wps, const u8 *conn)$/;" f file: -wps_process_cred src/wps/wps_attr_process.c /^int wps_process_cred(struct wps_parse_attr *attr,$/;" f -wps_process_cred_802_1x_enabled src/wps/wps_attr_process.c /^static int wps_process_cred_802_1x_enabled(struct wps_credential *cred,$/;" f file: -wps_process_cred_ap_channel src/wps/wps_attr_process.c /^static int wps_process_cred_ap_channel(struct wps_credential *cred,$/;" f file: -wps_process_cred_auth_type src/wps/wps_attr_process.c /^static int wps_process_cred_auth_type(struct wps_credential *cred,$/;" f file: -wps_process_cred_e src/wps/wps_enrollee.c /^static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,$/;" f file: -wps_process_cred_eap_identity src/wps/wps_attr_process.c /^static int wps_process_cred_eap_identity(struct wps_credential *cred,$/;" f file: -wps_process_cred_eap_type src/wps/wps_attr_process.c /^static int wps_process_cred_eap_type(struct wps_credential *cred,$/;" f file: -wps_process_cred_encr_type src/wps/wps_attr_process.c /^static int wps_process_cred_encr_type(struct wps_credential *cred,$/;" f file: -wps_process_cred_key_prov_auto src/wps/wps_attr_process.c /^static int wps_process_cred_key_prov_auto(struct wps_credential *cred,$/;" f file: -wps_process_cred_mac_addr src/wps/wps_attr_process.c /^static int wps_process_cred_mac_addr(struct wps_credential *cred,$/;" f file: -wps_process_cred_network_idx src/wps/wps_attr_process.c /^static int wps_process_cred_network_idx(struct wps_credential *cred,$/;" f file: -wps_process_cred_network_key src/wps/wps_attr_process.c /^static int wps_process_cred_network_key(struct wps_credential *cred,$/;" f file: -wps_process_cred_network_key_idx src/wps/wps_attr_process.c /^static int wps_process_cred_network_key_idx(struct wps_credential *cred,$/;" f file: -wps_process_cred_ssid src/wps/wps_attr_process.c /^static int wps_process_cred_ssid(struct wps_credential *cred, const u8 *ssid,$/;" f file: -wps_process_creds src/wps/wps_enrollee.c /^static int wps_process_creds(struct wps_data *wps, const u8 *cred[],$/;" f file: -wps_process_dev_name src/wps/wps_dev_attr.c /^static int wps_process_dev_name(struct wps_device_data *dev, const u8 *str,$/;" f file: -wps_process_dev_password_id src/wps/wps_registrar.c /^static int wps_process_dev_password_id(struct wps_data *wps, const u8 *pw_id)$/;" f file: -wps_process_device_attrs src/wps/wps_dev_attr.c /^int wps_process_device_attrs(struct wps_device_data *dev,$/;" f -wps_process_e_hash1 src/wps/wps_registrar.c /^static int wps_process_e_hash1(struct wps_data *wps, const u8 *e_hash1)$/;" f file: -wps_process_e_hash2 src/wps/wps_registrar.c /^static int wps_process_e_hash2(struct wps_data *wps, const u8 *e_hash2)$/;" f file: -wps_process_e_snonce1 src/wps/wps_registrar.c /^static int wps_process_e_snonce1(struct wps_data *wps, const u8 *e_snonce1)$/;" f file: -wps_process_e_snonce2 src/wps/wps_registrar.c /^static int wps_process_e_snonce2(struct wps_data *wps, const u8 *e_snonce2)$/;" f file: -wps_process_encr_type_flags src/wps/wps_registrar.c /^static int wps_process_encr_type_flags(struct wps_data *wps, const u8 *encr)$/;" f file: -wps_process_enrollee_nonce src/wps/wps_enrollee.c /^static int wps_process_enrollee_nonce(struct wps_data *wps, const u8 *e_nonce)$/;" f file: -wps_process_enrollee_nonce src/wps/wps_registrar.c /^static int wps_process_enrollee_nonce(struct wps_data *wps, const u8 *e_nonce)$/;" f file: -wps_process_key_wrap_auth src/wps/wps_attr_process.c /^int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg,$/;" f -wps_process_m1 src/wps/wps_registrar.c /^static enum wps_process_res wps_process_m1(struct wps_data *wps,$/;" f file: -wps_process_m2 src/wps/wps_enrollee.c /^static enum wps_process_res wps_process_m2(struct wps_data *wps,$/;" f file: -wps_process_m2d src/wps/wps_enrollee.c /^static enum wps_process_res wps_process_m2d(struct wps_data *wps,$/;" f file: -wps_process_m3 src/wps/wps_registrar.c /^static enum wps_process_res wps_process_m3(struct wps_data *wps,$/;" f file: -wps_process_m4 src/wps/wps_enrollee.c /^static enum wps_process_res wps_process_m4(struct wps_data *wps,$/;" f file: -wps_process_m5 src/wps/wps_registrar.c /^static enum wps_process_res wps_process_m5(struct wps_data *wps,$/;" f file: -wps_process_m6 src/wps/wps_enrollee.c /^static enum wps_process_res wps_process_m6(struct wps_data *wps,$/;" f file: -wps_process_m7 src/wps/wps_registrar.c /^static enum wps_process_res wps_process_m7(struct wps_data *wps,$/;" f file: -wps_process_m8 src/wps/wps_enrollee.c /^static enum wps_process_res wps_process_m8(struct wps_data *wps,$/;" f file: -wps_process_mac_addr src/wps/wps_registrar.c /^static int wps_process_mac_addr(struct wps_data *wps, const u8 *mac_addr)$/;" f file: -wps_process_manufacturer src/wps/wps_dev_attr.c /^static int wps_process_manufacturer(struct wps_device_data *dev, const u8 *str,$/;" f file: -wps_process_model_name src/wps/wps_dev_attr.c /^static int wps_process_model_name(struct wps_device_data *dev, const u8 *str,$/;" f file: -wps_process_model_number src/wps/wps_dev_attr.c /^static int wps_process_model_number(struct wps_device_data *dev, const u8 *str,$/;" f file: -wps_process_msg src/wps/wps.c /^enum wps_process_res wps_process_msg(struct wps_data *wps,$/;" f -wps_process_os_version src/wps/wps_dev_attr.c /^int wps_process_os_version(struct wps_device_data *dev, const u8 *ver)$/;" f -wps_process_primary_dev_type src/wps/wps_dev_attr.c /^static int wps_process_primary_dev_type(struct wps_device_data *dev,$/;" f file: -wps_process_pubkey src/wps/wps_enrollee.c /^static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,$/;" f file: -wps_process_pubkey src/wps/wps_registrar.c /^static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,$/;" f file: -wps_process_r_hash1 src/wps/wps_enrollee.c /^static int wps_process_r_hash1(struct wps_data *wps, const u8 *r_hash1)$/;" f file: -wps_process_r_hash2 src/wps/wps_enrollee.c /^static int wps_process_r_hash2(struct wps_data *wps, const u8 *r_hash2)$/;" f file: -wps_process_r_snonce1 src/wps/wps_enrollee.c /^static int wps_process_r_snonce1(struct wps_data *wps, const u8 *r_snonce1)$/;" f file: -wps_process_r_snonce2 src/wps/wps_enrollee.c /^static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2)$/;" f file: -wps_process_registrar_nonce src/wps/wps_enrollee.c /^static int wps_process_registrar_nonce(struct wps_data *wps, const u8 *r_nonce)$/;" f file: -wps_process_registrar_nonce src/wps/wps_registrar.c /^static int wps_process_registrar_nonce(struct wps_data *wps, const u8 *r_nonce)$/;" f file: -wps_process_res src/wps/wps.h /^enum wps_process_res {$/;" g -wps_process_rf_bands src/wps/wps_dev_attr.c /^int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands)$/;" f -wps_process_serial_number src/wps/wps_dev_attr.c /^static int wps_process_serial_number(struct wps_device_data *dev,$/;" f file: -wps_process_uuid_e src/wps/wps_registrar.c /^static int wps_process_uuid_e(struct wps_data *wps, const u8 *uuid_e)$/;" f file: -wps_process_uuid_r src/wps/wps_enrollee.c /^static int wps_process_uuid_r(struct wps_data *wps, const u8 *uuid_r)$/;" f file: -wps_process_wps_mX_req src/esp_supplicant/esp_wps.c /^int wps_process_wps_mX_req(u8 *ubuf, int len, enum wps_process_res *res)$/;" f -wps_process_wps_state src/wps/wps_registrar.c /^static int wps_process_wps_state(struct wps_data *wps, const u8 *state)$/;" f file: -wps_process_wsc_ack src/wps/wps_enrollee.c /^static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,$/;" f file: -wps_process_wsc_ack src/wps/wps_registrar.c /^static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,$/;" f file: -wps_process_wsc_done src/wps/wps_registrar.c /^static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,$/;" f file: -wps_process_wsc_msg src/wps/wps_enrollee.c /^static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,$/;" f file: -wps_process_wsc_msg src/wps/wps_registrar.c /^static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,$/;" f file: -wps_process_wsc_nack src/wps/wps_enrollee.c /^static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,$/;" f file: -wps_process_wsc_nack src/wps/wps_registrar.c /^static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,$/;" f file: -wps_process_wsc_start src/wps/wps_enrollee.c /^static enum wps_process_res wps_process_wsc_start(struct wps_data *wps,$/;" f file: -wps_pwd_auth_fail_event src/wps/wps_common.c /^void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part)$/;" f -wps_registrar src/wps/wps_registrar.c /^struct wps_registrar {$/;" s file: -wps_registrar_add_authorized_mac src/wps/wps_registrar.c /^static void wps_registrar_add_authorized_mac(struct wps_registrar *reg,$/;" f file: -wps_registrar_add_nfc_password_token src/wps/wps_registrar.c /^int wps_registrar_add_nfc_password_token(struct wps_registrar *reg,$/;" f -wps_registrar_add_nfc_pw_token src/wps/wps_registrar.c /^int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,$/;" f -wps_registrar_add_pbc_session src/wps/wps_registrar.c /^static void wps_registrar_add_pbc_session(struct wps_registrar *reg,$/;" f file: -wps_registrar_add_pin src/wps/wps_registrar.c /^int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,$/;" f -wps_registrar_button_pushed src/wps/wps_registrar.c /^int wps_registrar_button_pushed(struct wps_registrar *reg,$/;" f -wps_registrar_complete src/wps/wps_registrar.c /^void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e,$/;" f -wps_registrar_config src/wps/wps.h /^struct wps_registrar_config {$/;" s -wps_registrar_config_ap src/wps/wps_registrar.c /^int wps_registrar_config_ap(struct wps_registrar *reg,$/;" f -wps_registrar_deinit src/wps/wps_registrar.c /^void wps_registrar_deinit(struct wps_registrar *reg)$/;" f -wps_registrar_device src/wps/wps_registrar.c /^struct wps_registrar_device {$/;" s file: -wps_registrar_expire_pins src/wps/wps_registrar.c /^static void wps_registrar_expire_pins(struct wps_registrar *reg)$/;" f file: -wps_registrar_free_pending_m2 src/wps/wps_registrar.c /^static void wps_registrar_free_pending_m2(struct wps_context *wps)$/;" f file: -wps_registrar_get_info src/wps/wps_registrar.c /^int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr,$/;" f -wps_registrar_get_msg src/wps/wps_registrar.c /^struct wpabuf * wps_registrar_get_msg(struct wps_data *wps,$/;" f -wps_registrar_get_pin src/wps/wps_registrar.c /^static const u8 * wps_registrar_get_pin(struct wps_registrar *reg,$/;" f file: -wps_registrar_init src/wps/wps_registrar.c /^struct wps_registrar * wps_registrar_init(struct wps_context *wps,$/;" f -wps_registrar_invalidate_pin src/wps/wps_registrar.c /^int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid)$/;" f -wps_registrar_invalidate_unused src/wps/wps_registrar.c /^static void wps_registrar_invalidate_unused(struct wps_registrar *reg)$/;" f file: -wps_registrar_invalidate_wildcard_pin src/wps/wps_registrar.c /^static int wps_registrar_invalidate_wildcard_pin(struct wps_registrar *reg,$/;" f file: -wps_registrar_p2p_dev_addr_match src/wps/wps_registrar.c /^static int wps_registrar_p2p_dev_addr_match(struct wps_data *wps)$/;" f file: -wps_registrar_pbc_completed src/wps/wps_registrar.c /^static void wps_registrar_pbc_completed(struct wps_registrar *reg)$/;" f file: -wps_registrar_pbc_overlap src/wps/wps_registrar.c /^int wps_registrar_pbc_overlap(struct wps_registrar *reg,$/;" f -wps_registrar_pbc_timeout src/wps/wps_registrar.c /^static void wps_registrar_pbc_timeout(void *eloop_ctx)$/;" f file: -wps_registrar_pin_completed src/wps/wps_registrar.c /^static void wps_registrar_pin_completed(struct wps_registrar *reg)$/;" f file: -wps_registrar_probe_req_rx src/wps/wps_registrar.c /^void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,$/;" f -wps_registrar_process_msg src/wps/wps_registrar.c /^enum wps_process_res wps_registrar_process_msg(struct wps_data *wps,$/;" f -wps_registrar_remove_authorized_mac src/wps/wps_registrar.c /^static void wps_registrar_remove_authorized_mac(struct wps_registrar *reg,$/;" f file: -wps_registrar_remove_nfc_pw_token src/wps/wps_registrar.c /^void wps_registrar_remove_nfc_pw_token(struct wps_registrar *reg,$/;" f -wps_registrar_remove_pbc_session src/wps/wps_registrar.c /^static void wps_registrar_remove_pbc_session(struct wps_registrar *reg,$/;" f file: -wps_registrar_remove_pin src/wps/wps_registrar.c /^static void wps_registrar_remove_pin(struct wps_registrar *reg,$/;" f file: -wps_registrar_sel_reg_add src/wps/wps_registrar.c /^static void wps_registrar_sel_reg_add(struct wps_registrar *reg,$/;" f file: -wps_registrar_sel_reg_union src/wps/wps_registrar.c /^static void wps_registrar_sel_reg_union(struct wps_registrar *reg)$/;" f file: -wps_registrar_selected_registrar_changed src/wps/wps_registrar.c /^void wps_registrar_selected_registrar_changed(struct wps_registrar *reg)$/;" f -wps_registrar_skip_overlap src/wps/wps_registrar.c /^static int wps_registrar_skip_overlap(struct wps_data *wps)$/;" f file: -wps_registrar_stop_pbc src/wps/wps_registrar.c /^static void wps_registrar_stop_pbc(struct wps_registrar *reg)$/;" f file: -wps_registrar_unlock_pin src/wps/wps_registrar.c /^int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid)$/;" f -wps_registrar_update_ie src/wps/wps_registrar.c /^int wps_registrar_update_ie(struct wps_registrar *reg)$/;" f -wps_registrar_wps_cancel src/wps/wps_registrar.c /^int wps_registrar_wps_cancel(struct wps_registrar *reg)$/;" f -wps_remove_nfc_pw_token src/wps/wps_registrar.c /^static void wps_remove_nfc_pw_token(struct wps_nfc_pw_token *token)$/;" f file: -wps_remove_pin src/wps/wps_registrar.c /^static void wps_remove_pin(struct wps_uuid_pin *pin)$/;" f file: -wps_request_type src/wps/wps_defs.h /^enum wps_request_type {$/;" g -wps_response_type src/wps/wps_defs.h /^enum wps_response_type {$/;" g -wps_rx_param src/esp_supplicant/esp_wps.c /^struct wps_rx_param {$/;" s file: -wps_scan_ie src/esp_supplicant/esp_wifi_driver.h /^struct wps_scan_ie {$/;" s -wps_scan_timer src/wps/wps.h /^ ETSTimer wps_scan_timer;$/;" m struct:wps_sm -wps_send_eap_identity_rsp src/esp_supplicant/esp_wps.c /^int wps_send_eap_identity_rsp(u8 id)$/;" f -wps_send_frag_ack src/esp_supplicant/esp_wps.c /^int wps_send_frag_ack(u8 id)$/;" f -wps_send_wps_mX_rsp src/esp_supplicant/esp_wps.c /^int wps_send_wps_mX_rsp(u8 id)$/;" f -wps_sendto_wrapper src/esp_supplicant/esp_wps.c /^static void wps_sendto_wrapper(void *buffer, uint16_t len)$/;" f file: -wps_set_attr src/wps/wps_attr_parse.c /^static int wps_set_attr(struct wps_parse_attr *attr, u16 type,$/;" f file: -wps_set_default_factory src/esp_supplicant/esp_wps.c /^int wps_set_default_factory(void)$/;" f -wps_set_factory_info src/esp_supplicant/esp_wps.c /^int wps_set_factory_info(const esp_wps_config_t *config)$/;" f -wps_set_ie src/wps/wps_registrar.c /^static int wps_set_ie(struct wps_registrar *reg)$/;" f file: -wps_set_pushbutton src/wps/wps_registrar.c /^static void wps_set_pushbutton(u16 *methods, u16 conf_methods)$/;" f file: -wps_set_status src/esp_supplicant/esp_wps.c /^int wps_set_status(uint32_t status)$/;" f -wps_set_type src/esp_supplicant/esp_wps.c /^int wps_set_type(uint32_t type)$/;" f -wps_set_vendor_ext_wfa_subelem src/wps/wps_attr_parse.c /^static int wps_set_vendor_ext_wfa_subelem(struct wps_parse_attr *attr,$/;" f file: -wps_sig_cnt src/wps/wps.h /^ u8 wps_sig_cnt[SIG_WPS_NUM];$/;" m struct:wps_sm -wps_sig_type src/wps/wps.h /^enum wps_sig_type {$/;" g -wps_sm src/wps/wps.h /^struct wps_sm {$/;" s -wps_sm_alloc_eapol src/esp_supplicant/esp_wps.c /^u8 *wps_sm_alloc_eapol(struct wps_sm *sm, u8 type,$/;" f -wps_sm_ether_send src/esp_supplicant/esp_wps.c /^static inline int wps_sm_ether_send(struct wps_sm *sm, const u8 *dest, u16 proto,$/;" f file: -wps_sm_free_eapol src/esp_supplicant/esp_wps.c /^void wps_sm_free_eapol(u8 *buffer)$/;" f -wps_sm_get src/esp_supplicant/esp_wps.c /^wps_sm_get(void)$/;" f -wps_sm_rx_eapol src/esp_supplicant/esp_wifi_driver.h /^ int (*wps_sm_rx_eapol)(u8 *src_addr, u8 *buf, u32 len);$/;" m struct:wps_funcs -wps_sm_rx_eapol src/esp_supplicant/esp_wps.c /^int wps_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len)$/;" f -wps_sm_rx_eapol_internal src/esp_supplicant/esp_wps.c /^int wps_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len)$/;" f -wps_ssid_save src/esp_supplicant/esp_wps.c /^wps_ssid_save(u8 *ssid, u8 ssid_len)$/;" f -wps_st_cb_t src/wps/wps.h /^typedef void (*wps_st_cb_t)(int status);$/;" t -wps_sta_cred_cb src/wps/wps_registrar.c /^static void wps_sta_cred_cb(struct wps_data *wps)$/;" f file: -wps_start src/esp_supplicant/esp_wps.c /^uint8_t wps_start = 0;$/;" v -wps_start_msg_timer src/esp_supplicant/esp_wps.c /^int wps_start_msg_timer(void)$/;" f -wps_start_pending src/esp_supplicant/esp_wifi_driver.h /^ int (*wps_start_pending)(void);$/;" m struct:wps_funcs -wps_start_pending src/esp_supplicant/esp_wps.c /^int wps_start_pending(void)$/;" f -wps_state src/wps/wps.h /^ u8 wps_state;$/;" m struct:wps_event_data::wps_event_er_ap -wps_state src/wps/wps.h /^ enum wps_state wps_state;$/;" m struct:wps_context typeref:enum:wps_context::wps_state -wps_state src/wps/wps_attr_parse.h /^ const u8 *wps_state; \/* 1 octet *\/$/;" m struct:wps_parse_attr -wps_state src/wps/wps_defs.h /^enum wps_state {$/;" g -wps_station_wps_register_cb src/esp_supplicant/esp_wps.c /^wps_station_wps_register_cb(wps_st_cb_t cb)$/;" f -wps_status src/esp_supplicant/esp_wifi_driver.h /^typedef enum wps_status {$/;" g -wps_stop_process src/esp_supplicant/esp_wps.c /^int wps_stop_process(system_event_sta_wps_fail_reason_t reason_code)$/;" f -wps_success_cb_timer src/wps/wps.h /^ ETSTimer wps_success_cb_timer;$/;" m struct:wps_sm -wps_success_event src/wps/wps_common.c /^void wps_success_event(struct wps_context *wps)$/;" f -wps_task_deinit src/esp_supplicant/esp_wps.c /^int wps_task_deinit(void)$/;" f -wps_task_hdl src/esp_supplicant/esp_wps.c /^static void *wps_task_hdl = NULL;$/;" v file: -wps_task_init src/esp_supplicant/esp_wps.c /^int wps_task_init(void)$/;" f -wps_testing_dummy_cred src/esp_supplicant/esp_wps.c /^int wps_testing_dummy_cred = 0;$/;" v -wps_timeout_timer src/wps/wps.h /^ ETSTimer wps_timeout_timer;$/;" m struct:wps_sm -wps_txStart src/esp_supplicant/esp_wps.c /^int wps_txStart(void)$/;" f -wps_type include/esp_supplicant/esp_wps.h /^ wps_type_t wps_type;$/;" m struct:__anon90 -wps_type include/esp_supplicant/esp_wps.h /^typedef enum wps_type {$/;" g -wps_type_t include/esp_supplicant/esp_wps.h /^} wps_type_t;$/;" t typeref:enum:wps_type -wps_upnp src/ap/hostapd.h /^ struct upnp_wps_device_sm *wps_upnp;$/;" m struct:hostapd_data typeref:struct:hostapd_data::upnp_wps_device_sm -wps_uuid_pin src/wps/wps_registrar.c /^struct wps_uuid_pin {$/;" s file: -wps_validate_ap_config_methods src/wps/wps_validate.c /^static int wps_validate_ap_config_methods(const u8 *config_methods, int wps2,$/;" f file: -wps_validate_ap_setup_locked src/wps/wps_validate.c /^static int wps_validate_ap_setup_locked(const u8 *ap_setup_locked,$/;" f file: -wps_validate_assoc_req src/wps/wps.h /^static inline int wps_validate_assoc_req(const struct wpabuf *wps_ie)$/;" f -wps_validate_assoc_req src/wps/wps_validate.c /^int wps_validate_assoc_req(const struct wpabuf *wps_ie)$/;" f -wps_validate_assoc_resp src/wps/wps.h /^static inline int wps_validate_assoc_resp(const struct wpabuf *wps_ie)$/;" f -wps_validate_assoc_resp src/wps/wps_validate.c /^int wps_validate_assoc_resp(const struct wpabuf *wps_ie)$/;" f -wps_validate_assoc_state src/wps/wps_validate.c /^static int wps_validate_assoc_state(const u8 *assoc_state, int mandatory)$/;" f file: -wps_validate_auth_type src/wps/wps_validate.c /^static int wps_validate_auth_type(const u8 *type, int mandatory)$/;" f file: -wps_validate_auth_type_flags src/wps/wps_validate.c /^static int wps_validate_auth_type_flags(const u8 *flags, int mandatory)$/;" f file: -wps_validate_authenticator src/wps/wps_validate.c /^static int wps_validate_authenticator(const u8 *authenticator, int mandatory)$/;" f file: -wps_validate_authorized_macs src/wps/wps_validate.c /^static int wps_validate_authorized_macs(const u8 *authorized_macs, size_t len,$/;" f file: -wps_validate_beacon src/wps/wps.h /^static inline int wps_validate_beacon(const struct wpabuf *wps_ie){$/;" f -wps_validate_beacon src/wps/wps_validate.c /^int wps_validate_beacon(const struct wpabuf *wps_ie)$/;" f -wps_validate_beacon_probe_resp src/wps/wps.h /^static inline int wps_validate_beacon_probe_resp(const struct wpabuf *wps_ie,$/;" f -wps_validate_beacon_probe_resp src/wps/wps_validate.c /^int wps_validate_beacon_probe_resp(const struct wpabuf *wps_ie, int probe,$/;" f -wps_validate_config_error src/wps/wps_validate.c /^static int wps_validate_config_error(const u8 *config_error, int mandatory)$/;" f file: -wps_validate_config_methods src/wps/wps_validate.c /^static int wps_validate_config_methods(const u8 *config_methods, int wps2,$/;" f file: -wps_validate_conn_type_flags src/wps/wps_validate.c /^static int wps_validate_conn_type_flags(const u8 *flags, int mandatory)$/;" f file: -wps_validate_cred src/wps/wps_validate.c /^static int wps_validate_cred(const u8 *cred, size_t len)$/;" f file: -wps_validate_credential src/wps/wps_validate.c /^static int wps_validate_credential(const u8 *cred[], size_t len[], size_t num,$/;" f file: -wps_validate_dev_name src/wps/wps_validate.c /^static int wps_validate_dev_name(const u8 *dev_name, size_t len,$/;" f file: -wps_validate_dev_password_id src/wps/wps_validate.c /^static int wps_validate_dev_password_id(const u8 *dev_password_id,$/;" f file: -wps_validate_e_hash1 src/wps/wps_validate.c /^static int wps_validate_e_hash1(const u8 *hash, int mandatory)$/;" f file: -wps_validate_e_hash2 src/wps/wps_validate.c /^static int wps_validate_e_hash2(const u8 *hash, int mandatory)$/;" f file: -wps_validate_e_snonce1 src/wps/wps_validate.c /^static int wps_validate_e_snonce1(const u8 *nonce, int mandatory)$/;" f file: -wps_validate_e_snonce2 src/wps/wps_validate.c /^static int wps_validate_e_snonce2(const u8 *nonce, int mandatory)$/;" f file: -wps_validate_encr_settings src/wps/wps_validate.c /^static int wps_validate_encr_settings(const u8 *encr_settings, size_t len,$/;" f file: -wps_validate_encr_type src/wps/wps_validate.c /^static int wps_validate_encr_type(const u8 *type, int mandatory)$/;" f file: -wps_validate_encr_type_flags src/wps/wps_validate.c /^static int wps_validate_encr_type_flags(const u8 *flags, int mandatory)$/;" f file: -wps_validate_enrollee_nonce src/wps/wps_validate.c /^static int wps_validate_enrollee_nonce(const u8 *enrollee_nonce, int mandatory)$/;" f file: -wps_validate_key_wrap_auth src/wps/wps_validate.c /^static int wps_validate_key_wrap_auth(const u8 *auth, int mandatory)$/;" f file: -wps_validate_m1 src/wps/wps.h /^static inline int wps_validate_m1(const struct wpabuf *tlvs)$/;" f -wps_validate_m1 src/wps/wps_validate.c /^int wps_validate_m1(const struct wpabuf *tlvs)$/;" f -wps_validate_m2 src/wps/wps.h /^static inline int wps_validate_m2(const struct wpabuf *tlvs)$/;" f -wps_validate_m2 src/wps/wps_validate.c /^int wps_validate_m2(const struct wpabuf *tlvs)$/;" f -wps_validate_m2d src/wps/wps.h /^static inline int wps_validate_m2d(const struct wpabuf *tlvs)$/;" f -wps_validate_m2d src/wps/wps_validate.c /^int wps_validate_m2d(const struct wpabuf *tlvs)$/;" f -wps_validate_m3 src/wps/wps.h /^static inline int wps_validate_m3(const struct wpabuf *tlvs)$/;" f -wps_validate_m3 src/wps/wps_validate.c /^int wps_validate_m3(const struct wpabuf *tlvs)$/;" f -wps_validate_m4 src/wps/wps.h /^static inline int wps_validate_m4(const struct wpabuf *tlvs)$/;" f -wps_validate_m4 src/wps/wps_validate.c /^int wps_validate_m4(const struct wpabuf *tlvs)$/;" f -wps_validate_m4_encr src/wps/wps.h /^static inline int wps_validate_m4_encr(const struct wpabuf *tlvs, int wps2)$/;" f -wps_validate_m4_encr src/wps/wps_validate.c /^int wps_validate_m4_encr(const struct wpabuf *tlvs, int wps2)$/;" f -wps_validate_m5 src/wps/wps.h /^static inline int wps_validate_m5(const struct wpabuf *tlvs)$/;" f -wps_validate_m5 src/wps/wps_validate.c /^int wps_validate_m5(const struct wpabuf *tlvs)$/;" f -wps_validate_m5_encr src/wps/wps.h /^static inline int wps_validate_m5_encr(const struct wpabuf *tlvs, int wps2)$/;" f -wps_validate_m5_encr src/wps/wps_validate.c /^int wps_validate_m5_encr(const struct wpabuf *tlvs, int wps2)$/;" f -wps_validate_m6 src/wps/wps.h /^static inline int wps_validate_m6(const struct wpabuf *tlvs)$/;" f -wps_validate_m6 src/wps/wps_validate.c /^int wps_validate_m6(const struct wpabuf *tlvs)$/;" f -wps_validate_m6_encr src/wps/wps.h /^static inline int wps_validate_m6_encr(const struct wpabuf *tlvs, int wps2)$/;" f -wps_validate_m6_encr src/wps/wps_validate.c /^int wps_validate_m6_encr(const struct wpabuf *tlvs, int wps2)$/;" f -wps_validate_m7 src/wps/wps.h /^static inline int wps_validate_m7(const struct wpabuf *tlvs)$/;" f -wps_validate_m7 src/wps/wps_validate.c /^int wps_validate_m7(const struct wpabuf *tlvs)$/;" f -wps_validate_m7_encr src/wps/wps.h /^static inline int wps_validate_m7_encr(const struct wpabuf *tlvs, int ap,$/;" f -wps_validate_m7_encr src/wps/wps_validate.c /^int wps_validate_m7_encr(const struct wpabuf *tlvs, int ap, int wps2)$/;" f -wps_validate_m8 src/wps/wps.h /^static inline int wps_validate_m8(const struct wpabuf *tlvs)$/;" f -wps_validate_m8 src/wps/wps_validate.c /^int wps_validate_m8(const struct wpabuf *tlvs)$/;" f -wps_validate_m8_encr src/wps/wps.h /^static inline int wps_validate_m8_encr(const struct wpabuf *tlvs, int ap,$/;" f -wps_validate_m8_encr src/wps/wps_validate.c /^int wps_validate_m8_encr(const struct wpabuf *tlvs, int ap, int wps2)$/;" f -wps_validate_mac_addr src/wps/wps_validate.c /^static int wps_validate_mac_addr(const u8 *mac_addr, int mandatory)$/;" f file: -wps_validate_manufacturer src/wps/wps_validate.c /^static int wps_validate_manufacturer(const u8 *manufacturer, size_t len,$/;" f file: -wps_validate_model_name src/wps/wps_validate.c /^static int wps_validate_model_name(const u8 *model_name, size_t len,$/;" f file: -wps_validate_model_number src/wps/wps_validate.c /^static int wps_validate_model_number(const u8 *model_number, size_t len,$/;" f file: -wps_validate_msg_type src/wps/wps_validate.c /^static int wps_validate_msg_type(const u8 *msg_type, int mandatory)$/;" f file: -wps_validate_network_idx src/wps/wps_validate.c /^static int wps_validate_network_idx(const u8 *idx, int mandatory)$/;" f file: -wps_validate_network_key src/wps/wps_validate.c /^static int wps_validate_network_key(const u8 *key, size_t key_len,$/;" f file: -wps_validate_network_key_index src/wps/wps_validate.c /^static int wps_validate_network_key_index(const u8 *idx, int mandatory)$/;" f file: -wps_validate_network_key_shareable src/wps/wps_validate.c /^static int wps_validate_network_key_shareable(const u8 *val, int mandatory)$/;" f file: -wps_validate_os_version src/wps/wps_validate.c /^static int wps_validate_os_version(const u8 *os_version, int mandatory)$/;" f file: -wps_validate_primary_dev_type src/wps/wps_validate.c /^static int wps_validate_primary_dev_type(const u8 *primary_dev_type,$/;" f file: -wps_validate_probe_req src/wps/wps.h /^static inline int wps_validate_probe_req(const struct wpabuf *wps_ie,$/;" f -wps_validate_probe_req src/wps/wps_validate.c /^int wps_validate_probe_req(const struct wpabuf *wps_ie, const u8 *addr)$/;" f -wps_validate_public_key src/wps/wps_validate.c /^static int wps_validate_public_key(const u8 *public_key, size_t len,$/;" f file: -wps_validate_r_hash1 src/wps/wps_validate.c /^static int wps_validate_r_hash1(const u8 *hash, int mandatory)$/;" f file: -wps_validate_r_hash2 src/wps/wps_validate.c /^static int wps_validate_r_hash2(const u8 *hash, int mandatory)$/;" f file: -wps_validate_r_snonce1 src/wps/wps_validate.c /^static int wps_validate_r_snonce1(const u8 *nonce, int mandatory)$/;" f file: -wps_validate_r_snonce2 src/wps/wps_validate.c /^static int wps_validate_r_snonce2(const u8 *nonce, int mandatory)$/;" f file: -wps_validate_registrar_nonce src/wps/wps_validate.c /^static int wps_validate_registrar_nonce(const u8 *registrar_nonce,$/;" f file: -wps_validate_req_dev_type src/wps/wps_validate.c /^static int wps_validate_req_dev_type(const u8 *req_dev_type[], size_t num,$/;" f file: -wps_validate_request_to_enroll src/wps/wps_validate.c /^static int wps_validate_request_to_enroll(const u8 *request_to_enroll,$/;" f file: -wps_validate_request_type src/wps/wps_validate.c /^static int wps_validate_request_type(const u8 *request_type, int mandatory)$/;" f file: -wps_validate_response_type src/wps/wps_validate.c /^static int wps_validate_response_type(const u8 *response_type, int mandatory)$/;" f file: -wps_validate_rf_bands src/wps/wps_validate.c /^static int wps_validate_rf_bands(const u8 *rf_bands, int mandatory)$/;" f file: -wps_validate_sel_reg_config_methods src/wps/wps_validate.c /^static int wps_validate_sel_reg_config_methods(const u8 *config_methods,$/;" f file: -wps_validate_selected_registrar src/wps/wps_validate.c /^static int wps_validate_selected_registrar(const u8 *selected_registrar,$/;" f file: -wps_validate_serial_number src/wps/wps_validate.c /^static int wps_validate_serial_number(const u8 *serial_number, size_t len,$/;" f file: -wps_validate_settings_delay_time src/wps/wps_validate.c /^static int wps_validate_settings_delay_time(const u8 *delay, int mandatory)$/;" f file: -wps_validate_ssid src/wps/wps_validate.c /^static int wps_validate_ssid(const u8 *ssid, size_t ssid_len, int mandatory)$/;" f file: -wps_validate_upnp_set_selected_registrar src/wps/wps.h /^static inline int wps_validate_upnp_set_selected_registrar($/;" f -wps_validate_upnp_set_selected_registrar src/wps/wps_validate.c /^int wps_validate_upnp_set_selected_registrar(const struct wpabuf *tlvs)$/;" f -wps_validate_uuid_e src/wps/wps_validate.c /^static int wps_validate_uuid_e(const u8 *uuid_e, int mandatory)$/;" f file: -wps_validate_uuid_r src/wps/wps_validate.c /^static int wps_validate_uuid_r(const u8 *uuid_r, int mandatory)$/;" f file: -wps_validate_version src/wps/wps_validate.c /^static int wps_validate_version(const u8 *version, int mandatory)$/;" f file: -wps_validate_version2 src/wps/wps_validate.c /^static int wps_validate_version2(const u8 *version2, int mandatory)$/;" f file: -wps_validate_wps_state src/wps/wps_validate.c /^static int wps_validate_wps_state(const u8 *wps_state, int mandatory)$/;" f file: -wps_validate_wsc_ack src/wps/wps.h /^static inline int wps_validate_wsc_ack(const struct wpabuf *tlvs)$/;" f -wps_validate_wsc_ack src/wps/wps_validate.c /^int wps_validate_wsc_ack(const struct wpabuf *tlvs)$/;" f -wps_validate_wsc_done src/wps/wps.h /^static inline int wps_validate_wsc_done(const struct wpabuf *tlvs)$/;" f -wps_validate_wsc_done src/wps/wps_validate.c /^int wps_validate_wsc_done(const struct wpabuf *tlvs)$/;" f -wps_validate_wsc_nack src/wps/wps.h /^static inline int wps_validate_wsc_nack(const struct wpabuf *tlvs)$/;" f -wps_validate_wsc_nack src/wps/wps_validate.c /^int wps_validate_wsc_nack(const struct wpabuf *tlvs)$/;" f -wps_vendor_ext src/ap/ap_config.h /^ struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];$/;" m struct:hostapd_bss_config typeref:struct:hostapd_bss_config::wpabuf -wps_version_number src/esp_supplicant/esp_wps.c /^int wps_version_number = 0x20;$/;" v -wps_workaround_cred_key src/wps/wps_attr_process.c /^static int wps_workaround_cred_key(struct wps_credential *cred)$/;" f file: -write_cbc src/tls/tlsv1_record.h /^ struct crypto_cipher *write_cbc;$/;" m struct:tlsv1_record_layer typeref:struct:tlsv1_record_layer::crypto_cipher -write_cipher_suite src/tls/tlsv1_record.h /^ u16 write_cipher_suite;$/;" m struct:tlsv1_record_layer -write_iv src/tls/tlsv1_record.h /^ u8 write_iv[TLS_MAX_IV_LEN];$/;" m struct:tlsv1_record_layer -write_key src/tls/tlsv1_record.h /^ u8 write_key[TLS_MAX_WRITE_KEY_LEN];$/;" m struct:tlsv1_record_layer -write_mac_secret src/tls/tlsv1_record.h /^ u8 write_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];$/;" m struct:tlsv1_record_layer -write_seq_num src/tls/tlsv1_record.h /^ u8 write_seq_num[TLS_SEQ_NUM_LEN];$/;" m struct:tlsv1_record_layer -wsc_op_code src/wps/wps.h /^enum wsc_op_code {$/;" g -x509_algorithm_identifier src/tls/x509v3.h /^struct x509_algorithm_identifier {$/;" s -x509_certificate src/tls/x509v3.h /^struct x509_certificate {$/;" s -x509_certificate_chain_free src/tls/x509v3.c /^void x509_certificate_chain_free(struct x509_certificate *cert)$/;" f -x509_certificate_chain_validate src/tls/x509v3.c /^int x509_certificate_chain_validate(struct x509_certificate *trusted,$/;" f -x509_certificate_check_signature src/tls/x509v3.c /^int x509_certificate_check_signature(struct x509_certificate *issuer,$/;" f -x509_certificate_free src/tls/x509v3.c /^void x509_certificate_free(struct x509_certificate *cert)$/;" f -x509_certificate_get_subject src/tls/x509v3.c /^x509_certificate_get_subject(struct x509_certificate *chain,$/;" f -x509_certificate_parse src/tls/x509v3.c /^struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len)$/;" f -x509_certificate_self_signed src/tls/x509v3.c /^int x509_certificate_self_signed(struct x509_certificate *cert)$/;" f -x509_digest_oid src/tls/x509v3.c /^static int x509_digest_oid(struct asn1_oid *oid)$/;" f file: -x509_free_name src/tls/x509v3.c /^static void x509_free_name(struct x509_name *name)$/;" f file: -x509_id_ce_oid src/tls/x509v3.c /^static int x509_id_ce_oid(struct asn1_oid *oid)$/;" f file: -x509_name src/tls/x509v3.h /^struct x509_name {$/;" s -x509_name_attr src/tls/x509v3.h /^struct x509_name_attr {$/;" s -x509_name_attr_str src/tls/x509v3.c /^static char * x509_name_attr_str(enum x509_name_attr_type type)$/;" f file: -x509_name_attr_type src/tls/x509v3.h /^ enum x509_name_attr_type {$/;" g struct:x509_name_attr -x509_name_compare src/tls/x509v3.c /^int x509_name_compare(struct x509_name *a, struct x509_name *b)$/;" f -x509_name_string src/tls/x509v3.c /^void x509_name_string(struct x509_name *name, char *buf, size_t len)$/;" f -x509_parse_algorithm_identifier src/tls/x509v3.c /^static int x509_parse_algorithm_identifier($/;" f file: -x509_parse_alt_name_dns src/tls/x509v3.c /^static int x509_parse_alt_name_dns(struct x509_name *name,$/;" f file: -x509_parse_alt_name_ip src/tls/x509v3.c /^static int x509_parse_alt_name_ip(struct x509_name *name,$/;" f file: -x509_parse_alt_name_rfc8222 src/tls/x509v3.c /^static int x509_parse_alt_name_rfc8222(struct x509_name *name,$/;" f file: -x509_parse_alt_name_rid src/tls/x509v3.c /^static int x509_parse_alt_name_rid(struct x509_name *name,$/;" f file: -x509_parse_alt_name_uri src/tls/x509v3.c /^static int x509_parse_alt_name_uri(struct x509_name *name,$/;" f file: -x509_parse_ext_alt_name src/tls/x509v3.c /^static int x509_parse_ext_alt_name(struct x509_name *name,$/;" f file: -x509_parse_ext_basic_constraints src/tls/x509v3.c /^static int x509_parse_ext_basic_constraints(struct x509_certificate *cert,$/;" f file: -x509_parse_ext_issuer_alt_name src/tls/x509v3.c /^static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert,$/;" f file: -x509_parse_ext_key_usage src/tls/x509v3.c /^static int x509_parse_ext_key_usage(struct x509_certificate *cert,$/;" f file: -x509_parse_ext_subject_alt_name src/tls/x509v3.c /^static int x509_parse_ext_subject_alt_name(struct x509_certificate *cert,$/;" f file: -x509_parse_extension src/tls/x509v3.c /^static int x509_parse_extension(struct x509_certificate *cert,$/;" f file: -x509_parse_extension_data src/tls/x509v3.c /^static int x509_parse_extension_data(struct x509_certificate *cert,$/;" f file: -x509_parse_extensions src/tls/x509v3.c /^static int x509_parse_extensions(struct x509_certificate *cert,$/;" f file: -x509_parse_name src/tls/x509v3.c /^static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,$/;" f file: -x509_parse_public_key src/tls/x509v3.c /^static int x509_parse_public_key(const u8 *buf, size_t len,$/;" f file: -x509_parse_tbs_certificate src/tls/x509v3.c /^static int x509_parse_tbs_certificate(const u8 *buf, size_t len,$/;" f file: -x509_parse_time src/tls/x509v3.c /^static int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag,$/;" f file: -x509_parse_validity src/tls/x509v3.c /^static int x509_parse_validity(const u8 *buf, size_t len,$/;" f file: -x509_pkcs_oid src/tls/x509v3.c /^static int x509_pkcs_oid(struct asn1_oid *oid)$/;" f file: -x509_rsadsi_oid src/tls/x509v3.c /^static int x509_rsadsi_oid(struct asn1_oid *oid)$/;" f file: -x509_sha1_oid src/tls/x509v3.c /^static int x509_sha1_oid(struct asn1_oid *oid)$/;" f file: -x509_sha256_oid src/tls/x509v3.c /^static int x509_sha256_oid(struct asn1_oid *oid)$/;" f file: -x509_str_compare src/tls/x509v3.c /^static int x509_str_compare(const char *a, const char *b)$/;" f file: -x509_str_strip_whitespace src/tls/x509v3.c /^static void x509_str_strip_whitespace(char *a)$/;" f file: -x509_valid_issuer src/tls/x509v3.c /^static int x509_valid_issuer(const struct x509_certificate *cert)$/;" f file: -x509_whitespace src/tls/x509v3.c /^static int x509_whitespace(char c)$/;" f file: -xWpa2Queue src/esp_supplicant/esp_wpa_enterprise.c /^static void *xWpa2Queue = NULL;$/;" v file: -xWpsQueue src/esp_supplicant/esp_wps.c /^static void *xWpsQueue = NULL;$/;" v file: -xxkey src/ap/wpa_auth_i.h /^ u8 xxkey[PMK_LEN]; \/* PSK or the second 256 bits of MSK *\/$/;" m struct:wpa_state_machine -xxkey_len src/ap/wpa_auth_i.h /^ size_t xxkey_len;$/;" m struct:wpa_state_machine From 181fd70a9afac1f63eb71d421ae07b71ff2eaa66 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Thu, 27 Jun 2019 19:11:15 +0800 Subject: [PATCH 267/486] ci: multichip build support for examples --- tools/ci/build_examples_cmake.sh | 16 ++++++++------- tools/ci/config/build.yml | 19 ++++++++++------- tools/ci/config/target-test.yml | 2 +- tools/ci/executable-list.txt | 1 + tools/ci/get_supported_examples.sh | 33 ++++++++++++++++++++++++++++++ 5 files changed, 56 insertions(+), 15 deletions(-) create mode 100755 tools/ci/get_supported_examples.sh diff --git a/tools/ci/build_examples_cmake.sh b/tools/ci/build_examples_cmake.sh index 3e76271d4a..6ec906b0dc 100755 --- a/tools/ci/build_examples_cmake.sh +++ b/tools/ci/build_examples_cmake.sh @@ -34,7 +34,7 @@ set -o pipefail # Exit if pipe failed. # Remove the initial space and instead use '\n'. IFS=$'\n\t' -export PATH="$IDF_PATH/tools:$PATH" # for idf.py +export PATH="$IDF_PATH/tools/ci:$IDF_PATH/tools:$PATH" # ----------------------------------------------------------------------------- @@ -49,7 +49,7 @@ die() { set -o nounset # Exit if variable not set. -echo "build_examples running in ${PWD}" +echo "build_examples running in ${PWD} for target $IDF_TARGET" # only 0 or 1 arguments [ $# -le 1 ] || die "Have to run as $(basename $0) []" @@ -66,7 +66,9 @@ LOG_SUSPECTED=${LOG_PATH}/common_log.txt touch ${LOG_SUSPECTED} SDKCONFIG_DEFAULTS_CI=sdkconfig.ci -EXAMPLE_PATHS=$( find ${IDF_PATH}/examples/ -type f -name CMakeLists.txt | grep -v "/components/" | grep -v "/common_components/" | grep -v "/main/" | grep -v "/idf_as_lib/stubs/" | sort ) +EXAMPLE_PATHS=$( get_supported_examples.sh $IDF_TARGET | sed "s#^#${IDF_PATH}\/examples\/#g" | awk '{print $0"/CmakeLists.txt"}' ) +echo "All examples found for target $IDF_TARGET:" +echo $EXAMPLE_PATHS if [ -z {CI_NODE_TOTAL} ] then @@ -103,10 +105,10 @@ build_example () { local EXAMPLE_DIR=$(dirname "${CMAKELISTS}") local EXAMPLE_NAME=$(basename "${EXAMPLE_DIR}") - echo "Building ${EXAMPLE_NAME} as ${ID}..." - mkdir -p "example_builds/${ID}" - cp -r "${EXAMPLE_DIR}" "example_builds/${ID}" - pushd "example_builds/${ID}/${EXAMPLE_NAME}" + echo "Building ${EXAMPLE_NAME} for ${IDF_TARGET} as ${ID}..." + mkdir -p "example_builds/${IDF_TARGET}/${ID}" + cp -r "${EXAMPLE_DIR}" "example_builds/${IDF_TARGET}/${ID}" + pushd "example_builds/${IDF_TARGET}/${ID}/${EXAMPLE_NAME}" # be stricter in the CI build than the default IDF settings export EXTRA_CFLAGS=${PEDANTIC_CFLAGS} export EXTRA_CXXFLAGS=${EXTRA_CFLAGS} diff --git a/tools/ci/config/build.yml b/tools/ci/config/build.yml index 1eb151c054..907492a52a 100644 --- a/tools/ci/config/build.yml +++ b/tools/ci/config/build.yml @@ -144,18 +144,18 @@ build_examples_make: - ${IDF_PATH}/tools/ci/build_examples.sh # same as above, but for CMake -build_examples_cmake: +.build_examples_cmake: &build_examples_cmake extends: .build_template parallel: 5 artifacts: when: always paths: - - build_examples_cmake/*/*/*/build/*.bin - - build_examples_cmake/*/*/*/sdkconfig - - build_examples_cmake/*/*/*/build/*.elf - - build_examples_cmake/*/*/*/build/*.map - - build_examples_cmake/*/*/*/build/flasher_args.json - - build_examples_cmake/*/*/*/build/bootloader/*.bin + - build_examples_cmake/*/*/*/*/build/*.bin + - build_examples_cmake/*/*/*/*/sdkconfig + - build_examples_cmake/*/*/*/*/build/*.elf + - build_examples_cmake/*/*/*/*/build/*.map + - build_examples_cmake/*/*/*/*/build/flasher_args.json + - build_examples_cmake/*/*/*/*/build/bootloader/*.bin - $LOG_PATH expire_in: 3 days variables: @@ -177,6 +177,11 @@ build_examples_cmake: - mkdir -p ${LOG_PATH} - ${IDF_PATH}/tools/ci/build_examples_cmake.sh +build_examples_cmake_esp32: + extends: .build_examples_cmake + variables: + IDF_TARGET: esp32 + # If you want to add new build example jobs, please add it into dependencies of `.example_test_template` build_docs: diff --git a/tools/ci/config/target-test.yml b/tools/ci/config/target-test.yml index 069a328895..c8c12a321e 100644 --- a/tools/ci/config/target-test.yml +++ b/tools/ci/config/target-test.yml @@ -22,7 +22,7 @@ dependencies: - assign_test - build_examples_make - - build_examples_cmake + - build_examples_cmake_esp32 artifacts: when: always paths: diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index e7b9715194..bad335f8a3 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -40,6 +40,7 @@ tools/ci/check_ut_cmake_make.sh tools/ci/checkout_project_ref.py tools/ci/envsubst.py tools/ci/get-full-sources.sh +tools/ci/get_supported_examples.sh tools/ci/mirror-submodule-update.sh tools/ci/multirun_with_pyenv.sh tools/ci/push_to_github.sh diff --git a/tools/ci/get_supported_examples.sh b/tools/ci/get_supported_examples.sh new file mode 100755 index 0000000000..1cae80b568 --- /dev/null +++ b/tools/ci/get_supported_examples.sh @@ -0,0 +1,33 @@ +#!/bin/bash +set -o errexit +set -o pipefail +set -o nounset + +DEBUG_SHELL=${DEBUG_SHELL:-"0"} +[ "${DEBUG_SHELL}" = "1" ] && set -x + +if [[ $# < 1 ]]; then + echo "no target specified!" >&2 + exit -1 +fi + +cd $IDF_PATH/examples +ALL_EXAMPLES=$( find . -type f -name CMakeLists.txt | grep -v "/components/" | grep -v "/common_components/" | grep -v "/main/" | grep -v "/idf_as_lib/stubs/" | sed "s/\/CMakeLists.txt//g" | sort ) +EXAMPLE_LIST=$( realpath --relative-to=. $ALL_EXAMPLES ) + +for EXAMPLE in $EXAMPLE_LIST +do + SEARCHED=$( grep -E "SUPPORTED_TARGETS" $EXAMPLE/CMakeLists.txt | sed "s/set\s*(\s*SUPPORTED_TARGETS//g" | sed "s/)//g" ) || true + if [[ $SEARCHED == "" ]]; then + #when SUPPORTED_TARGETS not set, allow all targets implicitly + echo "$EXAMPLE" + else + for TARGET in $SEARCHED + do + if [[ $TARGET == $1 ]]; then + echo "$EXAMPLE" + break + fi + done + fi +done From 2926cd09a24d2c79489d6fb4ff8e81e24526d495 Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Fri, 28 Jun 2019 16:24:05 +0300 Subject: [PATCH 268/486] gcov_example: Adds cmake target to generate report Closes IDF-727 --- components/app_trace/project_include.cmake | 23 ++++++++++++++++++++++ examples/system/gcov/CMakeLists.txt | 3 +++ examples/system/gcov/README.md | 10 ++++++++++ 3 files changed, 36 insertions(+) create mode 100644 components/app_trace/project_include.cmake diff --git a/components/app_trace/project_include.cmake b/components/app_trace/project_include.cmake new file mode 100644 index 0000000000..2278788f4e --- /dev/null +++ b/components/app_trace/project_include.cmake @@ -0,0 +1,23 @@ +# idf_create_lcov_report +# +# Create coverage report. +function(idf_create_coverage_report report_dir) + set(gcov_tool ${CONFIG_SDK_TOOLPREFIX}gcov) + idf_build_get_property(project_name PROJECT_NAME) + + add_custom_target(lcov-report + COMMENT "Generating coverage report in: ${report_dir}" + COMMAND ${CMAKE_COMMAND} -E echo "Using gcov: ${gcov_tool}" + COMMAND ${CMAKE_COMMAND} -E make_directory ${report_dir}/html + COMMAND lcov --gcov-tool ${gcov_tool} -c -d ${CMAKE_CURRENT_BINARY_DIR} -o ${report_dir}/${project_name}.info + COMMAND genhtml -o ${report_dir}/html ${report_dir}/${project_name}.info) +endfunction() + +# idf_clean_coverage_report +# +# Clean coverage report. +function(idf_clean_coverage_report report_dir) + add_custom_target(cov-data-clean + COMMENT "Clean coverage report in: ${report_dir}" + COMMAND ${CMAKE_COMMAND} -E remove_directory ${report_dir}) +endfunction() \ No newline at end of file diff --git a/examples/system/gcov/CMakeLists.txt b/examples/system/gcov/CMakeLists.txt index 8a1f715683..e40ee66d50 100644 --- a/examples/system/gcov/CMakeLists.txt +++ b/examples/system/gcov/CMakeLists.txt @@ -4,3 +4,6 @@ cmake_minimum_required(VERSION 3.5) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(gcov_example) + +idf_create_coverage_report(${CMAKE_CURRENT_BINARY_DIR}/coverage_report) +idf_clean_coverage_report(${CMAKE_CURRENT_BINARY_DIR}/coverage_report) diff --git a/examples/system/gcov/README.md b/examples/system/gcov/README.md index de20784184..ffb5fef3bd 100644 --- a/examples/system/gcov/README.md +++ b/examples/system/gcov/README.md @@ -127,6 +127,14 @@ cov-data-clean: .PHONY: lcov-report cov-data-clean ``` +For CMake-based build system, add the following lines to you project's `CMakeLists.txt` after the line including `project.cmake`: + +``` +include($ENV{IDF_PATH}/tools/cmake/gcov.cmake) +idf_create_coverage_report(${CMAKE_CURRENT_BINARY_DIR}/coverage_report) +idf_clean_coverage_report(${CMAKE_CURRENT_BINARY_DIR}/coverage_report) +``` + Those lines add two build targets: * `lcov-report` - generates html coverage report in `$(BUILD_DIR_BASE)/coverage_report/html` directory. * `cov-data-clean` - removes all coverage data files and reports. @@ -134,6 +142,8 @@ Those lines add two build targets: To generate report type the following command: `make lcov-report` + For CMake-based build system, type `cmake --build build/ --target lcov-report` + The sample output of the command is below: ``` From 98cf38ca9ce7aa694e652b43d0acbccedfabb4a3 Mon Sep 17 00:00:00 2001 From: Anurag Kar Date: Thu, 4 Jul 2019 12:06:30 +0530 Subject: [PATCH 269/486] cmake : Add CMakeLists.txt and update READMEs for re-compilation of proto files --- .../esp_local_ctrl/proto/CMakeLists.txt | 9 ++---- components/protocomm/proto/CMakeLists.txt | 29 +++++++++++++++++++ components/protocomm/proto/README.md | 20 +++++++++++-- .../wifi_provisioning/proto/CMakeLists.txt | 29 +++++++++++++++++++ components/wifi_provisioning/proto/README.md | 27 +++++++++++++++-- .../custom_provisioning/proto/CMakeLists.txt | 26 +++++++++++++++++ .../custom_provisioning/proto/README.md | 20 +++++++++++-- 7 files changed, 147 insertions(+), 13 deletions(-) create mode 100644 components/protocomm/proto/CMakeLists.txt create mode 100644 components/wifi_provisioning/proto/CMakeLists.txt create mode 100644 examples/provisioning/custom_config/components/custom_provisioning/proto/CMakeLists.txt diff --git a/components/esp_local_ctrl/proto/CMakeLists.txt b/components/esp_local_ctrl/proto/CMakeLists.txt index ffe6a54252..3bcc8e87df 100644 --- a/components/esp_local_ctrl/proto/CMakeLists.txt +++ b/components/esp_local_ctrl/proto/CMakeLists.txt @@ -6,19 +6,16 @@ set(C_OUT_PATH "${CMAKE_CURRENT_LIST_DIR}/../proto-c") set(PY_OUT_PATH "${CMAKE_CURRENT_LIST_DIR}/../python") set(PROTOCOMM_INCL_PATH "${CMAKE_CURRENT_LIST_DIR}/../../protocomm/proto") -file(GLOB PROTO_FILES - LIST_DIRECTORIES false - RELATIVE ${CMAKE_CURRENT_LIST_DIR} - "*.proto") +set(PROTO_SRCS "esp_local_ctrl.proto") add_custom_target(c_proto - COMMAND ${PROTO_C_COMPILER} --c_out=${C_OUT_PATH} -I . -I ${PROTOCOMM_INCL_PATH} ${PROTO_FILES} + COMMAND ${PROTO_C_COMPILER} --c_out=${C_OUT_PATH} -I . -I ${PROTOCOMM_INCL_PATH} ${PROTO_SRCS} VERBATIM WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} ) add_custom_target(python_proto - COMMAND ${PROTO_COMPILER} --python_out=${PY_OUT_PATH} -I . -I ${PROTOCOMM_INCL_PATH} ${PROTO_FILES} + COMMAND ${PROTO_COMPILER} --python_out=${PY_OUT_PATH} -I . -I ${PROTOCOMM_INCL_PATH} ${PROTO_SRCS} VERBATIM WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} ) diff --git a/components/protocomm/proto/CMakeLists.txt b/components/protocomm/proto/CMakeLists.txt new file mode 100644 index 0000000000..8d3e57d063 --- /dev/null +++ b/components/protocomm/proto/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.5) + +set(PROTO_COMPILER "protoc") +set(PROTO_C_COMPILER "protoc-c") +set(C_OUT_PATH "${CMAKE_CURRENT_LIST_DIR}/../proto-c") +set(PY_OUT_PATH "${CMAKE_CURRENT_LIST_DIR}/../python") + +set(PROTO_SRCS "constants.proto" + "sec0.proto" + "sec1.proto" + "session.proto") + +add_custom_target(c_proto + COMMAND ${PROTO_C_COMPILER} --c_out=${C_OUT_PATH} -I . ${PROTO_SRCS} + VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + ) + +add_custom_target(python_proto + COMMAND ${PROTO_COMPILER} --python_out=${PY_OUT_PATH} -I . ${PROTO_SRCS} + VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + ) + +add_custom_target(proto ALL + DEPENDS c_proto python_proto + VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + ) diff --git a/components/protocomm/proto/README.md b/components/protocomm/proto/README.md index 655e193a38..b77e3150fd 100644 --- a/components/protocomm/proto/README.md +++ b/components/protocomm/proto/README.md @@ -8,6 +8,22 @@ Protocomm uses Google Protobuf for language, transport and architecture agnostic Note : These proto files are not automatically compiled during the build process. -Run "make" (Optional) to generate the respective C and Python files. The generated C files are used by protocomm itself to create, delete and manipulate transaction packets. The generated Python files can be used by python based applications for implementing client side interface to protocomm layer. +# Compilation -Compilation requires protoc (Protobuf Compiler) and protoc-c (Protobuf C Compiler) installed. Since the generated files are to remain the same, as long as the proto files are not modified, therefore the generated files are already available under "protocomm/proto-c" and "protocomm/python" directories, and thus running make (and installing the Protobuf compilers) is optional. +Compilation requires protoc (Protobuf Compiler) and protoc-c (Protobuf C Compiler) installed. Since the generated files are to remain the same, as long as the proto files are not modified, therefore the generated files are already available under `components/protocomm/proto-c` and `components/protocomm/python` directories, and thus running cmake / make (and installing the Protobuf compilers) is optional. + +If using `cmake` follow the below steps. If using `make`, jump to Step 2 directly. + +## Step 1 (Only for cmake) + +When using cmake, first create a build directory and call cmake from inside: + +``` +mkdir build +cd build +cmake .. +``` + +## Step 2 + +Simply run `make` to generate the respective C and Python files. The newly created files will overwrite those under `components/protocomm/proto-c` and `components/protocomm/python` diff --git a/components/wifi_provisioning/proto/CMakeLists.txt b/components/wifi_provisioning/proto/CMakeLists.txt new file mode 100644 index 0000000000..316486eba6 --- /dev/null +++ b/components/wifi_provisioning/proto/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.5) + +set(PROTO_COMPILER "protoc") +set(PROTO_C_COMPILER "protoc-c") +set(C_OUT_PATH "${CMAKE_CURRENT_LIST_DIR}/../proto-c") +set(PY_OUT_PATH "${CMAKE_CURRENT_LIST_DIR}/../python") +set(PROTOCOMM_INCL_PATH "${CMAKE_CURRENT_LIST_DIR}/../../protocomm/proto") + +set(PROTO_SRCS "wifi_constants.proto" + "wifi_config.proto" + "wifi_scan.proto") + +add_custom_target(c_proto + COMMAND ${PROTO_C_COMPILER} --c_out=${C_OUT_PATH} -I . -I ${PROTOCOMM_INCL_PATH} ${PROTO_SRCS} + VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + ) + +add_custom_target(python_proto + COMMAND ${PROTO_COMPILER} --python_out=${PY_OUT_PATH} -I . -I ${PROTOCOMM_INCL_PATH} ${PROTO_SRCS} + VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + ) + +add_custom_target(proto ALL + DEPENDS c_proto python_proto + VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + ) diff --git a/components/wifi_provisioning/proto/README.md b/components/wifi_provisioning/proto/README.md index 10c428be72..68f9be2058 100644 --- a/components/wifi_provisioning/proto/README.md +++ b/components/wifi_provisioning/proto/README.md @@ -1,7 +1,28 @@ -# Protobuf files for defining Wi-Fi config-data packet structures +# Protobuf files for defining Wi-Fi provisioning packet structures + +`wifi_provisioning` uses Google Protobuf for language, transport and architecture agnostic protocol communication. These proto files define the protocomm packet structure, separated across multiple files: +* wifi_contants.proto - Defines the various enums for indicating state of Wi-Fi (connected / disconnect / connecting), diconnect reasons, auth modes, etc. +* wifi_config.proto - Defines Wi-Fi configuration structures and commands for setting credentials (SSID, passphrase, BSSID), applying credentials and getting connection state. +* wifi_scan.proto - Defines Wi-Fi scan commands and result structures Note : These proto files are not automatically compiled during the build process. -Run "make" (Optional) to generate the respective C and Python files. The generated C files are used by protocomm itself to create, delete and manipulate transaction packets. The generated Python files can be used by python based applications for implementing client side interface to protocomm layer. +# Compilation -Compilation requires protoc (Protobuf Compiler) and protoc-c (Protobuf C Compiler) installed. Since the generated files are to remain the same, as long as the proto files are not modified, therefore the generated files are already available under "protocomm/proto-c" and "protocomm/python" directories, and thus running make (and installing the Protobuf compilers) is optional. +Compilation requires protoc (Protobuf Compiler) and protoc-c (Protobuf C Compiler) installed. Since the generated files are to remain the same, as long as the proto files are not modified, therefore the generated files are already available under `components/wifi_provisioning/proto-c` and `components/wifi_provisioning/python` directories, and thus running cmake / make (and installing the Protobuf compilers) is optional. + +If using `cmake` follow the below steps. If using `make`, jump to Step 2 directly. + +## Step 1 (Only for cmake) + +When using cmake, first create a build directory and call cmake from inside: + +``` +mkdir build +cd build +cmake .. +``` + +## Step 2 + +Simply run `make` to generate the respective C and Python files. The newly created files will overwrite those under `components/wifi_provisioning/proto-c` and `components/wifi_provisioning/python` diff --git a/examples/provisioning/custom_config/components/custom_provisioning/proto/CMakeLists.txt b/examples/provisioning/custom_config/components/custom_provisioning/proto/CMakeLists.txt new file mode 100644 index 0000000000..153cfdceca --- /dev/null +++ b/examples/provisioning/custom_config/components/custom_provisioning/proto/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.5) + +set(PROTO_COMPILER "protoc") +set(PROTO_C_COMPILER "protoc-c") +set(C_OUT_PATH "${CMAKE_CURRENT_LIST_DIR}/../proto-c") +set(PY_OUT_PATH "${CMAKE_CURRENT_LIST_DIR}/../python") + +set(PROTO_SRCS "custom_config.proto") + +add_custom_target(c_proto + COMMAND ${PROTO_C_COMPILER} --c_out=${C_OUT_PATH} -I . ${PROTO_SRCS} + VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + ) + +add_custom_target(python_proto + COMMAND ${PROTO_COMPILER} --python_out=${PY_OUT_PATH} -I . ${PROTO_SRCS} + VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + ) + +add_custom_target(proto ALL + DEPENDS c_proto python_proto + VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + ) diff --git a/examples/provisioning/custom_config/components/custom_provisioning/proto/README.md b/examples/provisioning/custom_config/components/custom_provisioning/proto/README.md index 16d41538ad..933e82cbab 100644 --- a/examples/provisioning/custom_config/components/custom_provisioning/proto/README.md +++ b/examples/provisioning/custom_config/components/custom_provisioning/proto/README.md @@ -6,6 +6,22 @@ This is an example proto file defining custom configuration related data packet Note : These proto files are not automatically compiled during the build process. -Run "make" (Optional) to generate the respective C and Python files. The generated C files are used by protocomm itself to create, delete and manipulate transaction packets. The generated Python files can be used by python based applications for implementing client side interface to protocomm layer. +# Compilation -Compilation requires protoc (Protobuf Compiler) and protoc-c (Protobuf C Compiler) installed. Since the generated files are to remain the same, as long as the proto files are not modified, therefore the generated files are already available under "protocomm/proto-c" and "protocomm/python" directories, and thus running make (and installing the Protobuf compilers) is optional. +Compilation requires protoc (Protobuf Compiler) and protoc-c (Protobuf C Compiler) installed. Since the generated files are to remain the same, as long as the proto files are not modified, therefore the generated files are already available under `examples/provisioning/custom_config/components/custom_provisioning/proto-c` and `examples/provisioning/custom_config/components/custom_provisioning/python` directories, and thus running cmake / make (and installing the Protobuf compilers) is optional. + +If using `cmake` follow the below steps. If using `make`, jump to Step 2 directly. + +## Step 1 (Only for cmake) + +When using cmake, first create a build directory and call cmake from inside: + +``` +mkdir build +cd build +cmake .. +``` + +## Step 2 + +Simply run `make` to generate the respective C and Python files. The newly created files will overwrite those under `examples/provisioning/custom_config/components/custom_provisioning/proto-c` and `examples/provisioning/custom_config/components/custom_provisioning/python` From bd4591b05375c02a81b15a1e70e472d1d9c97b5f Mon Sep 17 00:00:00 2001 From: Oleg Antonyan Date: Thu, 23 May 2019 08:47:31 +0200 Subject: [PATCH 270/486] esp_http_client: separate buffer_size config option for transmit Merges https://github.com/espressif/esp-idf/pull/3528 Signed-off-by: Jitin George --- components/esp_http_client/esp_http_client.c | 42 +++++++++++-------- .../esp_http_client/include/esp_http_client.h | 5 ++- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/components/esp_http_client/esp_http_client.c b/components/esp_http_client/esp_http_client.c index 822a02b785..a77ebae0f8 100644 --- a/components/esp_http_client/esp_http_client.c +++ b/components/esp_http_client/esp_http_client.c @@ -110,7 +110,8 @@ struct esp_http_client { esp_http_state_t state; http_event_handle_cb event_handler; int timeout_ms; - int buffer_size; + int buffer_size_rx; + int buffer_size_tx; bool disable_auto_redirect; esp_http_client_event_t event; int data_written_index; @@ -312,11 +313,16 @@ static esp_err_t _set_config(esp_http_client_handle_t client, const esp_http_cli client->timeout_ms = config->timeout_ms; client->max_redirection_count = config->max_redirection_count; client->user_data = config->user_data; - client->buffer_size = config->buffer_size; + client->buffer_size_rx = config->buffer_size; + client->buffer_size_tx = config->buffer_size_tx; client->disable_auto_redirect = config->disable_auto_redirect; if (config->buffer_size == 0) { - client->buffer_size = DEFAULT_HTTP_BUF_SIZE; + client->buffer_size_rx = DEFAULT_HTTP_BUF_SIZE; + } + + if (config->buffer_size_tx == 0) { + client->buffer_size_tx = DEFAULT_HTTP_BUF_SIZE; } if (client->max_redirection_count == 0) { @@ -517,8 +523,8 @@ esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *co goto error; } _success = ( - (client->request->buffer->data = malloc(client->buffer_size)) && - (client->response->buffer->data = malloc(client->buffer_size)) + (client->request->buffer->data = malloc(client->buffer_size_tx)) && + (client->response->buffer->data = malloc(client->buffer_size_rx)) ); if (!_success) { @@ -762,7 +768,7 @@ static int esp_http_client_get_data(esp_http_client_handle_t client) ESP_LOGD(TAG, "data_process=%d, content_length=%d", client->response->data_process, client->response->content_length); - int rlen = esp_transport_read(client->transport, res_buffer->data, client->buffer_size, client->timeout_ms); + int rlen = esp_transport_read(client->transport, res_buffer->data, client->buffer_size_rx, client->timeout_ms); if (rlen >= 0) { http_parser_execute(client->parser, client->parser_settings, res_buffer->data, rlen); } @@ -797,8 +803,8 @@ int esp_http_client_read(esp_http_client_handle_t client, char *buffer, int len) break; } int byte_to_read = need_read; - if (byte_to_read > client->buffer_size) { - byte_to_read = client->buffer_size; + if (byte_to_read > client->buffer_size_rx) { + byte_to_read = client->buffer_size_rx; } rlen = esp_transport_read(client->transport, res_buffer->data, byte_to_read, client->timeout_ms); ESP_LOGD(TAG, "need_read=%d, byte_to_read=%d, rlen=%d, ridx=%d", need_read, byte_to_read, rlen, ridx); @@ -915,7 +921,7 @@ int esp_http_client_fetch_headers(esp_http_client_handle_t client) client->response->status_code = -1; while (client->state < HTTP_STATE_RES_COMPLETE_HEADER) { - buffer->len = esp_transport_read(client->transport, buffer->data, client->buffer_size, client->timeout_ms); + buffer->len = esp_transport_read(client->transport, buffer->data, client->buffer_size_rx, client->timeout_ms); if (buffer->len <= 0) { return ESP_FAIL; } @@ -993,26 +999,26 @@ static int http_client_prepare_first_line(esp_http_client_handle_t client, int w const char *method = HTTP_METHOD_MAPPING[client->connection_info.method]; int first_line_len = snprintf(client->request->buffer->data, - client->buffer_size, "%s %s", + client->buffer_size_tx, "%s %s", method, client->connection_info.path); - if (first_line_len >= client->buffer_size) { + if (first_line_len >= client->buffer_size_tx) { ESP_LOGE(TAG, "Out of buffer"); return -1; } if (client->connection_info.query) { first_line_len += snprintf(client->request->buffer->data + first_line_len, - client->buffer_size - first_line_len, "?%s", client->connection_info.query); - if (first_line_len >= client->buffer_size) { + client->buffer_size_tx - first_line_len, "?%s", client->connection_info.query); + if (first_line_len >= client->buffer_size_tx) { ESP_LOGE(TAG, "Out of buffer"); return -1; } } first_line_len += snprintf(client->request->buffer->data + first_line_len, - client->buffer_size - first_line_len, " %s\r\n", DEFAULT_HTTP_PROTOCOL); - if (first_line_len >= client->buffer_size) { + client->buffer_size_tx - first_line_len, " %s\r\n", DEFAULT_HTTP_PROTOCOL); + if (first_line_len >= client->buffer_size_tx) { ESP_LOGE(TAG, "Out of buffer"); return -1; } @@ -1047,7 +1053,7 @@ static esp_err_t esp_http_client_request_send(esp_http_client_handle_t client, i } } - int wlen = client->buffer_size - first_line_len; + int wlen = client->buffer_size_tx - first_line_len; while ((client->header_index = http_header_generate_string(client->request->headers, client->header_index, client->request->buffer->data + first_line_len, &wlen))) { if (wlen <= 0) { break; @@ -1071,7 +1077,7 @@ static esp_err_t esp_http_client_request_send(esp_http_client_handle_t client, i client->data_write_left -= wret; client->data_written_index += wret; } - wlen = client->buffer_size; + wlen = client->buffer_size_tx; } client->data_written_index = 0; @@ -1251,4 +1257,4 @@ void esp_http_client_add_auth(esp_http_client_handle_t client) client->connection_info.auth_type = HTTP_AUTH_TYPE_NONE; ESP_LOGW(TAG, "This request requires authentication, but does not provide header information for that"); } -} \ No newline at end of file +} diff --git a/components/esp_http_client/include/esp_http_client.h b/components/esp_http_client/include/esp_http_client.h index e01234a6f6..cc97cc0690 100644 --- a/components/esp_http_client/include/esp_http_client.h +++ b/components/esp_http_client/include/esp_http_client.h @@ -116,7 +116,8 @@ typedef struct { int max_redirection_count; /*!< Max redirection number, using default value if zero*/ http_event_handle_cb event_handler; /*!< HTTP Event Handle */ esp_http_client_transport_t transport_type; /*!< HTTP transport type, see `esp_http_client_transport_t` */ - int buffer_size; /*!< HTTP buffer size (both send and receive) */ + int buffer_size; /*!< HTTP receive buffer size */ + int buffer_size_tx; /*!< HTTP transmit buffer size */ void *user_data; /*!< HTTP user_data context */ bool is_async; /*!< Set asynchronous mode, only supported with HTTPS for now */ bool use_global_ca_store; /*!< Use a global ca_store for all the connections in which this bool is set. */ @@ -427,7 +428,7 @@ esp_http_client_transport_t esp_http_client_get_transport_type(esp_http_client_h * * @param[in] client The esp_http_client handle * - * @return + * @return * - ESP_OK * - ESP_FAIL */ From a272e7204d7004e0bb95e508496206652b0aa422 Mon Sep 17 00:00:00 2001 From: qiyuexia Date: Tue, 16 Apr 2019 18:13:13 +0800 Subject: [PATCH 271/486] mesh: use new event library --- components/esp_event/event_send.c | 7 - components/esp_wifi/include/esp_mesh.h | 34 +-- components/esp_wifi/lib_esp32 | 2 +- components/esp_wifi/src/mesh_event.c | 20 +- .../internal_communication/main/mesh_main.c | 255 ++++++++++-------- .../mesh/manual_networking/main/mesh_main.c | 164 ++++++----- 6 files changed, 237 insertions(+), 245 deletions(-) diff --git a/components/esp_event/event_send.c b/components/esp_event/event_send.c index 4472bb4743..2c31ee0f6c 100644 --- a/components/esp_event/event_send.c +++ b/components/esp_event/event_send.c @@ -20,7 +20,6 @@ esp_err_t esp_event_send_noop(system_event_t *event); extern esp_err_t esp_event_send_legacy(system_event_t *event) __attribute__((weak, alias("esp_event_send_noop"))); extern esp_err_t esp_event_send_to_default_loop(system_event_t *event) __attribute((weak, alias("esp_event_send_noop"))); -extern esp_err_t esp_event_mesh_hook(system_event_t* event) __attribute__((weak, alias("esp_event_send_noop"))); esp_err_t esp_event_send_noop(system_event_t *event) @@ -42,11 +41,5 @@ esp_err_t esp_event_send(system_event_t *event) return err; } - // send the event to mesh hook - err = esp_event_mesh_hook(event); - if (err != ESP_OK) { - return err; - } - return ESP_OK; } diff --git a/components/esp_wifi/include/esp_mesh.h b/components/esp_wifi/include/esp_mesh.h index e52e541ff8..0666b182e0 100644 --- a/components/esp_wifi/include/esp_mesh.h +++ b/components/esp_wifi/include/esp_mesh.h @@ -174,8 +174,6 @@ typedef enum { MESH_EVENT_ROOT_ADDRESS, /**< the root address is obtained. It is posted by mesh stack automatically. */ MESH_EVENT_ROOT_SWITCH_REQ, /**< root switch request sent from a new voted root candidate */ MESH_EVENT_ROOT_SWITCH_ACK, /**< root switch acknowledgment responds the above request sent from current root */ - MESH_EVENT_ROOT_GOT_IP, /**< the root obtains the IP address. It is posted by LwIP stack automatically */ - MESH_EVENT_ROOT_LOST_IP, /**< the root loses the IP address. It is posted by LwIP stack automatically */ MESH_EVENT_ROOT_ASKED_YIELD, /**< the root is asked yield by a more powerful existing root. If self organized is disabled and this device is specified to be a root by users, users should set a new parent for this device. if self organized is enabled, this device will find a new parent @@ -195,6 +193,9 @@ typedef enum { MESH_EVENT_MAX, } mesh_event_id_t; +/** @brief ESP-MESH event base declaration */ +ESP_EVENT_DECLARE_BASE(MESH_EVENT); + /** * @brief Device type */ @@ -427,21 +428,6 @@ typedef union { mesh_event_router_switch_t router_switch; /**< new router information */ } mesh_event_info_t; -/** - * @brief Mesh event - */ -typedef struct { - mesh_event_id_t id; /**< mesh event id */ - mesh_event_info_t info; /**< mesh event info */ -} mesh_event_t; - -/** - * @brief Mesh event callback handler prototype definition - * - * @param event mesh_event_t - */ -typedef void (*mesh_event_cb_t)(mesh_event_t event); - /** * @brief Mesh option */ @@ -492,7 +478,6 @@ typedef struct { uint8_t channel; /**< channel, the mesh network on */ bool allow_channel_switch; /**< if this value is set, when "fail" (mesh_attempts_t) times is reached, device will change to a full channel scan for a network that could join. The default value is false. */ - mesh_event_cb_t event_cb; /**< mesh event callback */ mesh_addr_t mesh_id; /**< mesh network identification */ mesh_router_t router; /**< router configuration */ mesh_ap_cfg_t mesh_ap; /**< mesh softAP configuration */ @@ -543,9 +528,6 @@ typedef struct { /* mesh IE crypto callback function */ extern const mesh_crypto_funcs_t g_wifi_default_mesh_crypto_funcs; -/* mesh event callback handler */ -extern mesh_event_cb_t g_mesh_event_cb; - #define MESH_INIT_CONFIG_DEFAULT() { \ .crypto_funcs = &g_wifi_default_mesh_crypto_funcs, \ } @@ -1303,16 +1285,6 @@ esp_err_t esp_mesh_set_root_healing_delay(int delay_ms); */ int esp_mesh_get_root_healing_delay(void); -/** - * @brief Set mesh event callback - * - * @param[in] event_cb mesh event call back - * - * @return - * - ESP_OK - */ -esp_err_t esp_mesh_set_event_cb(const mesh_event_cb_t event_cb); - /** * @brief Enable network Fixed Root Setting * - Enabling fixed root disables automatic election of the root node via voting. diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index b7bfeeccdb..414f9b279e 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit b7bfeeccdb63fd20cf6b4abc52d9185934af4cb8 +Subproject commit 414f9b279e772196e8f6cf343d19f2882a2e8741 diff --git a/components/esp_wifi/src/mesh_event.c b/components/esp_wifi/src/mesh_event.c index f0b90ae422..52c6cf56f6 100644 --- a/components/esp_wifi/src/mesh_event.c +++ b/components/esp_wifi/src/mesh_event.c @@ -14,24 +14,10 @@ #include #include "esp_event.h" -#include "esp_mesh.h" -/* mesh event callback handler */ -mesh_event_cb_t g_mesh_event_cb = NULL; +ESP_EVENT_DEFINE_BASE(MESH_EVENT); -esp_err_t esp_event_mesh_hook(system_event_t *event) +esp_err_t esp_mesh_send_event_internal(int32_t event_id, void* event_data, size_t event_data_size) { - if (event->event_id == SYSTEM_EVENT_STA_GOT_IP || event->event_id == SYSTEM_EVENT_STA_LOST_IP) { - if (g_mesh_event_cb) { - mesh_event_t mevent; - if (event->event_id == SYSTEM_EVENT_STA_GOT_IP) { - mevent.id = MESH_EVENT_ROOT_GOT_IP; - memcpy(&mevent.info.got_ip, &event->event_info.got_ip, sizeof(system_event_sta_got_ip_t)); - } else { - mevent.id = MESH_EVENT_ROOT_LOST_IP; - } - g_mesh_event_cb(mevent); - } - } - return ESP_OK; + return esp_event_post(MESH_EVENT, event_id, event_data, event_data_size, 0); } diff --git a/examples/mesh/internal_communication/main/mesh_main.c b/examples/mesh/internal_communication/main/mesh_main.c index e6ce6255c2..5b1c7d7e75 100644 --- a/examples/mesh/internal_communication/main/mesh_main.c +++ b/examples/mesh/internal_communication/main/mesh_main.c @@ -9,7 +9,7 @@ #include #include "esp_wifi.h" #include "esp_system.h" -#include "esp_event_loop.h" +#include "esp_event.h" #include "esp_log.h" #include "esp_mesh.h" #include "esp_mesh_internal.h" @@ -19,7 +19,6 @@ /******************************************************* * Macros *******************************************************/ -//#define MESH_P2P_TOS_OFF /******************************************************* * Constants @@ -71,11 +70,9 @@ void esp_mesh_p2p_tx_main(void *arg) data.data = tx_buf; data.size = sizeof(tx_buf); data.proto = MESH_PROTO_BIN; -#ifdef MESH_P2P_TOS_OFF - data.tos = MESH_TOS_DEF; -#endif /* MESH_P2P_TOS_OFF */ - + data.tos = MESH_TOS_P2P; is_running = true; + while (is_running) { /* non-root do nothing but print */ if (!esp_mesh_is_root()) { @@ -138,8 +135,8 @@ void esp_mesh_p2p_rx_main(void *arg) int flag = 0; data.data = rx_buf; data.size = RX_SIZE; - is_running = true; + while (is_running) { data.size = RX_SIZE; err = esp_mesh_recv(&from, &data, portMAX_DELAY, &flag, NULL, 0); @@ -178,53 +175,66 @@ esp_err_t esp_mesh_comm_p2p_start(void) return ESP_OK; } -void mesh_event_handler(mesh_event_t event) +void mesh_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) { mesh_addr_t id = {0,}; static uint8_t last_layer = 0; - ESP_LOGD(MESH_TAG, "esp_event_handler:%d", event.id); - switch (event.id) { - case MESH_EVENT_STARTED: + switch (event_id) { + case MESH_EVENT_STARTED: { esp_mesh_get_id(&id); - ESP_LOGI(MESH_TAG, "ID:"MACSTR"", MAC2STR(id.addr)); + ESP_LOGI(MESH_TAG, "ID:"MACSTR"", MAC2STR(id.addr)); is_mesh_connected = false; mesh_layer = esp_mesh_get_layer(); - break; - case MESH_EVENT_STOPPED: + } + break; + case MESH_EVENT_STOPPED: { ESP_LOGI(MESH_TAG, ""); is_mesh_connected = false; mesh_layer = esp_mesh_get_layer(); - break; - case MESH_EVENT_CHILD_CONNECTED: + } + break; + case MESH_EVENT_CHILD_CONNECTED: { + mesh_event_child_connected_t *child_connected = (mesh_event_child_connected_t *)event_data; ESP_LOGI(MESH_TAG, "aid:%d, "MACSTR"", - event.info.child_connected.aid, - MAC2STR(event.info.child_connected.mac)); - break; - case MESH_EVENT_CHILD_DISCONNECTED: + child_connected->aid, + MAC2STR(child_connected->mac)); + } + break; + case MESH_EVENT_CHILD_DISCONNECTED: { + mesh_event_child_disconnected_t *child_disconnected = (mesh_event_child_disconnected_t *)event_data; ESP_LOGI(MESH_TAG, "aid:%d, "MACSTR"", - event.info.child_disconnected.aid, - MAC2STR(event.info.child_disconnected.mac)); - break; - case MESH_EVENT_ROUTING_TABLE_ADD: + child_disconnected->aid, + MAC2STR(child_disconnected->mac)); + } + break; + case MESH_EVENT_ROUTING_TABLE_ADD: { + mesh_event_routing_table_change_t *routing_table = (mesh_event_routing_table_change_t *)event_data; ESP_LOGW(MESH_TAG, "add %d, new:%d", - event.info.routing_table.rt_size_change, - event.info.routing_table.rt_size_new); - break; - case MESH_EVENT_ROUTING_TABLE_REMOVE: + routing_table->rt_size_change, + routing_table->rt_size_new); + } + break; + case MESH_EVENT_ROUTING_TABLE_REMOVE: { + mesh_event_routing_table_change_t *routing_table = (mesh_event_routing_table_change_t *)event_data; ESP_LOGW(MESH_TAG, "remove %d, new:%d", - event.info.routing_table.rt_size_change, - event.info.routing_table.rt_size_new); - break; - case MESH_EVENT_NO_PARENT_FOUND: + routing_table->rt_size_change, + routing_table->rt_size_new); + } + break; + case MESH_EVENT_NO_PARENT_FOUND: { + mesh_event_no_parent_found_t *no_parent = (mesh_event_no_parent_found_t *)event_data; ESP_LOGI(MESH_TAG, "scan times:%d", - event.info.no_parent.scan_times); - /* TODO handler for the failure */ - break; - case MESH_EVENT_PARENT_CONNECTED: + no_parent->scan_times); + } + /* TODO handler for the failure */ + break; + case MESH_EVENT_PARENT_CONNECTED: { + mesh_event_connected_t *connected = (mesh_event_connected_t *)event_data; esp_mesh_get_id(&id); - mesh_layer = event.info.connected.self_layer; - memcpy(&mesh_parent_addr.addr, event.info.connected.connected.bssid, 6); + mesh_layer = connected->self_layer; + memcpy(&mesh_parent_addr.addr, connected->connected.bssid, 6); ESP_LOGI(MESH_TAG, "layer:%d-->%d, parent:"MACSTR"%s, ID:"MACSTR"", last_layer, mesh_layer, MAC2STR(mesh_parent_addr.addr), @@ -237,104 +247,129 @@ void mesh_event_handler(mesh_event_t event) tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA); } esp_mesh_comm_p2p_start(); - break; - case MESH_EVENT_PARENT_DISCONNECTED: + } + break; + case MESH_EVENT_PARENT_DISCONNECTED: { + mesh_event_disconnected_t *disconnected = (mesh_event_disconnected_t *)event_data; ESP_LOGI(MESH_TAG, "reason:%d", - event.info.disconnected.reason); + disconnected->reason); is_mesh_connected = false; mesh_disconnected_indicator(); mesh_layer = esp_mesh_get_layer(); - break; - case MESH_EVENT_LAYER_CHANGE: - mesh_layer = event.info.layer_change.new_layer; + } + break; + case MESH_EVENT_LAYER_CHANGE: { + mesh_event_layer_change_t *layer_change = (mesh_event_layer_change_t *)event_data; + mesh_layer = layer_change->new_layer; ESP_LOGI(MESH_TAG, "layer:%d-->%d%s", last_layer, mesh_layer, esp_mesh_is_root() ? "" : (mesh_layer == 2) ? "" : ""); last_layer = mesh_layer; mesh_connected_indicator(mesh_layer); - break; - case MESH_EVENT_ROOT_ADDRESS: + } + break; + case MESH_EVENT_ROOT_ADDRESS: { + mesh_event_root_address_t *root_addr = (mesh_event_root_address_t *)event_data; ESP_LOGI(MESH_TAG, "root address:"MACSTR"", - MAC2STR(event.info.root_addr.addr)); - break; - case MESH_EVENT_ROOT_GOT_IP: - /* root starts to connect to server */ - ESP_LOGI(MESH_TAG, - "sta ip: " IPSTR ", mask: " IPSTR ", gw: " IPSTR, - IP2STR(&event.info.got_ip.ip_info.ip), - IP2STR(&event.info.got_ip.ip_info.netmask), - IP2STR(&event.info.got_ip.ip_info.gw)); - break; - case MESH_EVENT_ROOT_LOST_IP: - ESP_LOGI(MESH_TAG, ""); - break; - case MESH_EVENT_VOTE_STARTED: + MAC2STR(root_addr->addr)); + } + break; + case MESH_EVENT_VOTE_STARTED: { + mesh_event_vote_started_t *vote_started = (mesh_event_vote_started_t *)event_data; ESP_LOGI(MESH_TAG, "attempts:%d, reason:%d, rc_addr:"MACSTR"", - event.info.vote_started.attempts, - event.info.vote_started.reason, - MAC2STR(event.info.vote_started.rc_addr.addr)); - break; - case MESH_EVENT_VOTE_STOPPED: + vote_started->attempts, + vote_started->reason, + MAC2STR(vote_started->rc_addr.addr)); + } + break; + case MESH_EVENT_VOTE_STOPPED: { ESP_LOGI(MESH_TAG, ""); break; - case MESH_EVENT_ROOT_SWITCH_REQ: + } + case MESH_EVENT_ROOT_SWITCH_REQ: { + mesh_event_root_switch_req_t *switch_req = (mesh_event_root_switch_req_t *)event_data; ESP_LOGI(MESH_TAG, "reason:%d, rc_addr:"MACSTR"", - event.info.switch_req.reason, - MAC2STR( event.info.switch_req.rc_addr.addr)); - break; - case MESH_EVENT_ROOT_SWITCH_ACK: + switch_req->reason, + MAC2STR( switch_req->rc_addr.addr)); + } + break; + case MESH_EVENT_ROOT_SWITCH_ACK: { /* new root */ mesh_layer = esp_mesh_get_layer(); esp_mesh_get_parent_bssid(&mesh_parent_addr); ESP_LOGI(MESH_TAG, "layer:%d, parent:"MACSTR"", mesh_layer, MAC2STR(mesh_parent_addr.addr)); - break; - case MESH_EVENT_TODS_STATE: - ESP_LOGI(MESH_TAG, "state:%d", - event.info.toDS_state); - break; - case MESH_EVENT_ROOT_FIXED: + } + break; + case MESH_EVENT_TODS_STATE: { + mesh_event_toDS_state_t *toDs_state = (mesh_event_toDS_state_t *)event_data; + ESP_LOGI(MESH_TAG, "state:%d", *toDs_state); + } + break; + case MESH_EVENT_ROOT_FIXED: { + mesh_event_root_fixed_t *root_fixed = (mesh_event_root_fixed_t *)event_data; ESP_LOGI(MESH_TAG, "%s", - event.info.root_fixed.is_fixed ? "fixed" : "not fixed"); - break; - case MESH_EVENT_ROOT_ASKED_YIELD: + root_fixed->is_fixed ? "fixed" : "not fixed"); + } + break; + case MESH_EVENT_ROOT_ASKED_YIELD: { + mesh_event_root_conflict_t *root_conflict = (mesh_event_root_conflict_t *)event_data; ESP_LOGI(MESH_TAG, ""MACSTR", rssi:%d, capacity:%d", - MAC2STR(event.info.root_conflict.addr), - event.info.root_conflict.rssi, - event.info.root_conflict.capacity); - break; - case MESH_EVENT_CHANNEL_SWITCH: - ESP_LOGI(MESH_TAG, "new channel:%d", event.info.channel_switch.channel); - break; - case MESH_EVENT_SCAN_DONE: + MAC2STR(root_conflict->addr), + root_conflict->rssi, + root_conflict->capacity); + } + break; + case MESH_EVENT_CHANNEL_SWITCH: { + mesh_event_channel_switch_t *channel_switch = (mesh_event_channel_switch_t *)event_data; + ESP_LOGI(MESH_TAG, "new channel:%d", channel_switch->channel); + } + break; + case MESH_EVENT_SCAN_DONE: { + mesh_event_scan_done_t *scan_done = (mesh_event_scan_done_t *)event_data; ESP_LOGI(MESH_TAG, "number:%d", - event.info.scan_done.number); - break; - case MESH_EVENT_NETWORK_STATE: + scan_done->number); + } + break; + case MESH_EVENT_NETWORK_STATE: { + mesh_event_network_state_t *network_state = (mesh_event_network_state_t *)event_data; ESP_LOGI(MESH_TAG, "is_rootless:%d", - event.info.network_state.is_rootless); - break; - case MESH_EVENT_STOP_RECONNECTION: + network_state->is_rootless); + } + break; + case MESH_EVENT_STOP_RECONNECTION: { ESP_LOGI(MESH_TAG, ""); - break; - case MESH_EVENT_FIND_NETWORK: + } + break; + case MESH_EVENT_FIND_NETWORK: { + mesh_event_find_network_t *find_network = (mesh_event_find_network_t *)event_data; ESP_LOGI(MESH_TAG, "new channel:%d, router BSSID:"MACSTR"", - event.info.find_network.channel, MAC2STR(event.info.find_network.router_bssid)); - break; - case MESH_EVENT_ROUTER_SWITCH: + find_network->channel, MAC2STR(find_network->router_bssid)); + } + break; + case MESH_EVENT_ROUTER_SWITCH: { + mesh_event_router_switch_t *router_switch = (mesh_event_router_switch_t *)event_data; ESP_LOGI(MESH_TAG, "new router:%s, channel:%d, "MACSTR"", - event.info.router_switch.ssid, event.info.router_switch.channel, MAC2STR(event.info.router_switch.bssid)); - break; + router_switch->ssid, router_switch->channel, MAC2STR(router_switch->bssid)); + } + break; default: - ESP_LOGI(MESH_TAG, "unknown id:%d", event.id); + ESP_LOGI(MESH_TAG, "unknown id:%d", event_id); break; } } +void ip_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data; + ESP_LOGI(MESH_TAG, "IP:%s", ip4addr_ntoa(&event->ip_info.ip)); +} + void app_main(void) { ESP_ERROR_CHECK(mesh_light_init()); @@ -347,33 +382,23 @@ void app_main(void) * */ ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP)); ESP_ERROR_CHECK(tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA)); -#if 0 - /* static ip settings */ - tcpip_adapter_ip_info_t sta_ip; - sta_ip.ip.addr = ipaddr_addr("192.168.1.102"); - sta_ip.gw.addr = ipaddr_addr("192.168.1.1"); - sta_ip.netmask.addr = ipaddr_addr("255.255.255.0"); - tcpip_adapter_set_ip_info(WIFI_IF_STA, &sta_ip); -#endif + /* event initialization */ + ESP_ERROR_CHECK(esp_event_loop_create_default()); /* wifi initialization */ - ESP_ERROR_CHECK(esp_event_loop_init(NULL, NULL)); wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&config)); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &ip_event_handler, NULL)); ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_FLASH)); ESP_ERROR_CHECK(esp_wifi_start()); /* mesh initialization */ ESP_ERROR_CHECK(esp_mesh_init()); + ESP_ERROR_CHECK(esp_event_handler_register(MESH_EVENT, ESP_EVENT_ANY_ID, &mesh_event_handler, NULL)); ESP_ERROR_CHECK(esp_mesh_set_max_layer(CONFIG_MESH_MAX_LAYER)); ESP_ERROR_CHECK(esp_mesh_set_vote_percentage(1)); ESP_ERROR_CHECK(esp_mesh_set_ap_assoc_expire(10)); -#ifdef MESH_FIX_ROOT - ESP_ERROR_CHECK(esp_mesh_fix_root(1)); -#endif mesh_cfg_t cfg = MESH_INIT_CONFIG_DEFAULT(); /* mesh ID */ memcpy((uint8_t *) &cfg.mesh_id, MESH_ID, 6); - /* mesh event callback */ - cfg.event_cb = &mesh_event_handler; /* router */ cfg.channel = CONFIG_MESH_CHANNEL; cfg.router.ssid_len = strlen(CONFIG_MESH_ROUTER_SSID); diff --git a/examples/mesh/manual_networking/main/mesh_main.c b/examples/mesh/manual_networking/main/mesh_main.c index 56df30ab6e..57629abe8b 100644 --- a/examples/mesh/manual_networking/main/mesh_main.c +++ b/examples/mesh/manual_networking/main/mesh_main.c @@ -9,7 +9,7 @@ #include #include "esp_wifi.h" #include "esp_system.h" -#include "esp_event_loop.h" +#include "esp_event.h" #include "esp_log.h" #include "esp_mesh.h" #include "esp_mesh_internal.h" @@ -40,7 +40,6 @@ static int mesh_layer = -1; /******************************************************* * Function Declarations *******************************************************/ -void mesh_event_handler(mesh_event_t event); void mesh_scan_done_handler(int num); /******************************************************* @@ -156,58 +155,70 @@ void mesh_scan_done_handler(int num) } } -void mesh_event_handler(mesh_event_t event) +void mesh_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) { mesh_addr_t id = {0,}; static uint8_t last_layer = 0; - ESP_LOGD(MESH_TAG, "esp_event_handler:%d", event.id); + wifi_scan_config_t scan_config = { 0 }; - switch (event.id) { - case MESH_EVENT_STARTED: + switch (event_id) { + case MESH_EVENT_STARTED: { esp_mesh_get_id(&id); ESP_LOGI(MESH_TAG, "ID:"MACSTR"", MAC2STR(id.addr)); mesh_layer = esp_mesh_get_layer(); ESP_ERROR_CHECK(esp_mesh_set_self_organized(0, 0)); esp_wifi_scan_stop(); - wifi_scan_config_t scan_config = { 0 }; /* mesh softAP is hidden */ scan_config.show_hidden = 1; scan_config.scan_type = WIFI_SCAN_TYPE_PASSIVE; ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config, 0)); - break; - case MESH_EVENT_STOPPED: + } + break; + case MESH_EVENT_STOPPED: { ESP_LOGI(MESH_TAG, ""); mesh_layer = esp_mesh_get_layer(); - break; - case MESH_EVENT_CHILD_CONNECTED: + } + break; + case MESH_EVENT_CHILD_CONNECTED: { + mesh_event_child_connected_t *child_connected = (mesh_event_child_connected_t *)event_data; ESP_LOGI(MESH_TAG, "aid:%d, "MACSTR"", - event.info.child_connected.aid, - MAC2STR(event.info.child_connected.mac)); - break; - case MESH_EVENT_CHILD_DISCONNECTED: + child_connected->aid, + MAC2STR(child_connected->mac)); + } + break; + case MESH_EVENT_CHILD_DISCONNECTED: { + mesh_event_child_disconnected_t *child_disconnected = (mesh_event_child_disconnected_t *)event_data; ESP_LOGI(MESH_TAG, "aid:%d, "MACSTR"", - event.info.child_disconnected.aid, - MAC2STR(event.info.child_disconnected.mac)); - break; - case MESH_EVENT_ROUTING_TABLE_ADD: + child_disconnected->aid, + MAC2STR(child_disconnected->mac)); + } + case MESH_EVENT_ROUTING_TABLE_ADD: { + mesh_event_routing_table_change_t *routing_table = (mesh_event_routing_table_change_t *)event_data; ESP_LOGW(MESH_TAG, "add %d, new:%d", - event.info.routing_table.rt_size_change, - event.info.routing_table.rt_size_new); - break; - case MESH_EVENT_ROUTING_TABLE_REMOVE: + routing_table->rt_size_change, + routing_table->rt_size_new); + } + break; + case MESH_EVENT_ROUTING_TABLE_REMOVE: { + mesh_event_routing_table_change_t *routing_table = (mesh_event_routing_table_change_t *)event_data; ESP_LOGW(MESH_TAG, "remove %d, new:%d", - event.info.routing_table.rt_size_change, - event.info.routing_table.rt_size_new); - break; - case MESH_EVENT_NO_PARENT_FOUND: + routing_table->rt_size_change, + routing_table->rt_size_new); + } + break; + case MESH_EVENT_NO_PARENT_FOUND: { + mesh_event_no_parent_found_t *no_parent = (mesh_event_no_parent_found_t *)event_data; ESP_LOGI(MESH_TAG, "scan times:%d", - event.info.no_parent.scan_times); - /* TODO handler for the failure */ - break; - case MESH_EVENT_PARENT_CONNECTED: + no_parent->scan_times); + } + /* TODO handler for the failure */ + break; + case MESH_EVENT_PARENT_CONNECTED: { + mesh_event_connected_t *connected = (mesh_event_connected_t *)event_data; esp_mesh_get_id(&id); - mesh_layer = event.info.connected.self_layer; - memcpy(&mesh_parent_addr.addr, event.info.connected.connected.bssid, 6); + mesh_layer = connected->self_layer; + memcpy(&mesh_parent_addr.addr, connected->connected.bssid, 6); ESP_LOGI(MESH_TAG, "layer:%d-->%d, parent:"MACSTR"%s, ID:"MACSTR"", last_layer, mesh_layer, MAC2STR(mesh_parent_addr.addr), @@ -218,59 +229,71 @@ void mesh_event_handler(mesh_event_t event) if (esp_mesh_is_root()) { tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA); } - break; - case MESH_EVENT_PARENT_DISCONNECTED: + } + break; + case MESH_EVENT_PARENT_DISCONNECTED: { + mesh_event_disconnected_t *disconnected = (mesh_event_disconnected_t *)event_data; ESP_LOGI(MESH_TAG, "reason:%d", - event.info.disconnected.reason); + disconnected->reason); mesh_disconnected_indicator(); mesh_layer = esp_mesh_get_layer(); - if (event.info.disconnected.reason == WIFI_REASON_ASSOC_TOOMANY) { + if (disconnected->reason == WIFI_REASON_ASSOC_TOOMANY) { esp_wifi_scan_stop(); scan_config.show_hidden = 1; scan_config.scan_type = WIFI_SCAN_TYPE_PASSIVE; ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config, 0)); } - break; - case MESH_EVENT_LAYER_CHANGE: - mesh_layer = event.info.layer_change.new_layer; + } + break; + case MESH_EVENT_LAYER_CHANGE: { + mesh_event_layer_change_t *layer_change = (mesh_event_layer_change_t *)event_data; + mesh_layer = layer_change->new_layer; ESP_LOGI(MESH_TAG, "layer:%d-->%d%s", last_layer, mesh_layer, esp_mesh_is_root() ? "" : (mesh_layer == 2) ? "" : ""); last_layer = mesh_layer; mesh_connected_indicator(mesh_layer); - break; - case MESH_EVENT_ROOT_ADDRESS: + } + break; + case MESH_EVENT_ROOT_ADDRESS: { + mesh_event_root_address_t *root_addr = (mesh_event_root_address_t *)event_data; ESP_LOGI(MESH_TAG, "root address:"MACSTR"", - MAC2STR(event.info.root_addr.addr)); - break; - case MESH_EVENT_ROOT_GOT_IP: - /* root starts to connect to server */ - ESP_LOGI(MESH_TAG, - "sta ip: " IPSTR ", mask: " IPSTR ", gw: " IPSTR, - IP2STR(&event.info.got_ip.ip_info.ip), - IP2STR(&event.info.got_ip.ip_info.netmask), - IP2STR(&event.info.got_ip.ip_info.gw)); - break; - case MESH_EVENT_ROOT_LOST_IP: - ESP_LOGI(MESH_TAG, ""); - break; - case MESH_EVENT_ROOT_FIXED: + MAC2STR(root_addr->addr)); + } + break; + case MESH_EVENT_TODS_STATE: { + mesh_event_toDS_state_t *toDs_state = (mesh_event_toDS_state_t *)event_data; + ESP_LOGI(MESH_TAG, "state:%d", *toDs_state); + } + break; + case MESH_EVENT_ROOT_FIXED: { + mesh_event_root_fixed_t *root_fixed = (mesh_event_root_fixed_t *)event_data; ESP_LOGI(MESH_TAG, "%s", - event.info.root_fixed.is_fixed ? "fixed" : "not fixed"); - break; - case MESH_EVENT_SCAN_DONE: + root_fixed->is_fixed ? "fixed" : "not fixed"); + } + break; + case MESH_EVENT_SCAN_DONE: { + mesh_event_scan_done_t *scan_done = (mesh_event_scan_done_t *)event_data; ESP_LOGI(MESH_TAG, "number:%d", - event.info.scan_done.number); - mesh_scan_done_handler(event.info.scan_done.number); - break; + scan_done->number); + mesh_scan_done_handler(scan_done->number); + } + break; default: - ESP_LOGI(MESH_TAG, "unknown id:%d", event.id); + ESP_LOGI(MESH_TAG, "unknown id:%d", event_id); break; } } +void ip_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data; + ESP_LOGI(MESH_TAG, "IP:%s", ip4addr_ntoa(&event->ip_info.ip)); +} + void app_main(void) { ESP_ERROR_CHECK(mesh_light_init()); @@ -283,28 +306,21 @@ void app_main(void) * */ ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP)); ESP_ERROR_CHECK(tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA)); -#if 0 - /* static ip settings */ - tcpip_adapter_ip_info_t sta_ip; - sta_ip.ip.addr = ipaddr_addr("192.168.1.102"); - sta_ip.gw.addr = ipaddr_addr("192.168.1.1"); - sta_ip.netmask.addr = ipaddr_addr("255.255.255.0"); - tcpip_adapter_set_ip_info(WIFI_IF_STA, &sta_ip); -#endif + /* event initialization */ + ESP_ERROR_CHECK(esp_event_loop_create_default()); /* wifi initialization */ - ESP_ERROR_CHECK(esp_event_loop_init(NULL, NULL)); wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&config)); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &ip_event_handler, NULL)); ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_FLASH)); ESP_ERROR_CHECK(esp_wifi_start()); /* mesh initialization */ ESP_ERROR_CHECK(esp_mesh_init()); + ESP_ERROR_CHECK(esp_event_handler_register(MESH_EVENT, ESP_EVENT_ANY_ID, &mesh_event_handler, NULL)); /* mesh enable IE crypto */ mesh_cfg_t cfg = MESH_INIT_CONFIG_DEFAULT(); /* mesh ID */ memcpy((uint8_t *) &cfg.mesh_id, MESH_ID, 6); - /* mesh event callback */ - cfg.event_cb = &mesh_event_handler; /* router */ cfg.channel = CONFIG_MESH_CHANNEL; cfg.router.ssid_len = strlen(CONFIG_MESH_ROUTER_SSID); From 068a2dcb3248d99497a9ba7a1eecf26463bc0015 Mon Sep 17 00:00:00 2001 From: qiyuexia Date: Thu, 18 Apr 2019 22:38:43 +0800 Subject: [PATCH 272/486] mesh: update mesh events demonstration --- docs/_static/mesh-events-delivery.png | Bin 16574 -> 62433 bytes docs/en/api-reference/network/esp_mesh.rst | 20 ++++++++---------- .../mesh/manual_networking/main/mesh_main.c | 1 + 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/docs/_static/mesh-events-delivery.png b/docs/_static/mesh-events-delivery.png index 40341bb1dd687eb0775a371a0cde9bf29cc4b3ef..ceedadf829f30ab0f66ade7a30c71d3d4cf7a352 100644 GIT binary patch literal 62433 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 F{Rc45t*QV3 literal 16574 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, MAC2STR(child_disconnected->mac)); } + break; case MESH_EVENT_ROUTING_TABLE_ADD: { mesh_event_routing_table_change_t *routing_table = (mesh_event_routing_table_change_t *)event_data; ESP_LOGW(MESH_TAG, "add %d, new:%d", From d6c40c7c1dcb5ce54b96d07669f169994942933c Mon Sep 17 00:00:00 2001 From: chenjianqiang Date: Thu, 9 May 2019 15:26:24 +0800 Subject: [PATCH 273/486] bugfix(flash): improve spi cs timing settings for flash cs setup time is recomemded to be 1.5T, and cs hold time is recommended to be 2.5T. (cs_setup = 1, cs_setup_time = 0; cs_hold = 1, cs_hold_time = 1) --- .../bootloader_support/include/bootloader_common.h | 8 ++++++++ .../bootloader_support/src/bootloader_common.c | 12 ++++++++++++ components/bootloader_support/src/bootloader_init.c | 3 +++ components/esp32/cpu_start.c | 3 +++ 4 files changed, 26 insertions(+) diff --git a/components/bootloader_support/include/bootloader_common.h b/components/bootloader_support/include/bootloader_common.h index 2475d842a5..bd32a8d7c1 100644 --- a/components/bootloader_support/include/bootloader_common.h +++ b/components/bootloader_support/include/bootloader_common.h @@ -146,6 +146,14 @@ esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t */ void bootloader_common_vddsdio_configure(); +/** + * @brief Set the flash CS setup and hold time. + * + * CS setup time is recomemded to be 1.5T, and CS hold time is recommended to be 2.5T. + * cs_setup = 1, cs_setup_time = 0; cs_hold = 1, cs_hold_time = 1 + */ +void bootloader_common_set_flash_cs_timing(); + #ifdef __cplusplus } #endif diff --git a/components/bootloader_support/src/bootloader_common.c b/components/bootloader_support/src/bootloader_common.c index ed0169a960..795a6c9f51 100644 --- a/components/bootloader_support/src/bootloader_common.c +++ b/components/bootloader_support/src/bootloader_common.c @@ -25,6 +25,8 @@ #include "bootloader_common.h" #include "soc/gpio_periph.h" #include "soc/rtc.h" +#include "soc/efuse_reg.h" +#include "soc/spi_reg.h" #include "esp_image_format.h" #include "bootloader_sha.h" #include "sys/param.h" @@ -270,3 +272,13 @@ void bootloader_common_vddsdio_configure() } #endif // CONFIG_BOOTLOADER_VDDSDIO_BOOST } + +void bootloader_common_set_flash_cs_timing() +{ + SET_PERI_REG_MASK(SPI_USER_REG(0), SPI_CS_HOLD_M | SPI_CS_SETUP_M); + SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S); + SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_SETUP_TIME_V, 0, SPI_SETUP_TIME_S); + SET_PERI_REG_MASK(SPI_USER_REG(1), SPI_CS_HOLD_M | SPI_CS_SETUP_M); + SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S); + SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_SETUP_TIME_V, 0, SPI_SETUP_TIME_S); +} diff --git a/components/bootloader_support/src/bootloader_init.c b/components/bootloader_support/src/bootloader_init.c index 6a94713d13..17c94f190d 100644 --- a/components/bootloader_support/src/bootloader_init.c +++ b/components/bootloader_support/src/bootloader_init.c @@ -394,6 +394,9 @@ static void IRAM_ATTR flash_gpio_configure(const esp_image_header_t* pfhdr) #endif } } + + // improve the flash cs timing. + bootloader_common_set_flash_cs_timing(); } static void uart_console_configure(void) diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 4b8c2d5c4b..460e350ed9 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -71,6 +71,7 @@ #include "trax.h" #include "esp_ota_ops.h" #include "esp_efuse.h" +#include "bootloader_common.h" #define STRINGIFY(s) STRINGIFY2(s) #define STRINGIFY2(s) #s @@ -172,6 +173,8 @@ void IRAM_ATTR call_start_cpu0() abort(); #endif } +# else // If psram is uninitialized, we need to improve the flash cs timing. + bootloader_common_set_flash_cs_timing(); #endif ESP_EARLY_LOGI(TAG, "Pro cpu up."); From ae46f04997a29a208459627d8b69c8f903c3c69c Mon Sep 17 00:00:00 2001 From: Sagar Bijwe Date: Wed, 19 Jun 2019 19:33:34 +0530 Subject: [PATCH 274/486] wpa_supplicant: Fix sprintf security bugs. Revert back to using os_snprintf instead of sprintf. Closes WIFI-624 --- components/wpa_supplicant/src/eap_peer/eap_tls_common.c | 3 +-- components/wpa_supplicant/src/tls/asn1.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/components/wpa_supplicant/src/eap_peer/eap_tls_common.c b/components/wpa_supplicant/src/eap_peer/eap_tls_common.c index 213cafa13f..7e032685ee 100644 --- a/components/wpa_supplicant/src/eap_peer/eap_tls_common.c +++ b/components/wpa_supplicant/src/eap_peer/eap_tls_common.c @@ -732,8 +732,7 @@ int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, if (tls_get_cipher(data->ssl_ctx, data->conn, name, sizeof(name)) == 0) { - //ret = os_snprintf(buf + len, buflen - len, - ret = sprintf(buf + len, + ret = os_snprintf(buf + len, buflen - len, "EAP TLS cipher=%s\n", name); if (ret < 0 || (size_t) ret >= buflen - len) return len; diff --git a/components/wpa_supplicant/src/tls/asn1.c b/components/wpa_supplicant/src/tls/asn1.c index 5023ec1db4..08d476254f 100644 --- a/components/wpa_supplicant/src/tls/asn1.c +++ b/components/wpa_supplicant/src/tls/asn1.c @@ -152,8 +152,7 @@ void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len) buf[0] = '\0'; for (i = 0; i < oid->len; i++) { - //ret = os_snprintf(pos, buf + len - pos, - ret = sprintf(pos, + ret = os_snprintf(pos, buf + len - pos, "%s%lu", i == 0 ? "" : ".", oid->oid[i]); if (ret < 0 || ret >= buf + len - pos) From f3d6219c463e21abb8402be4b2eb4f547df322d5 Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Sat, 6 Jul 2019 09:17:31 +0200 Subject: [PATCH 275/486] tools: Fix indentation in confgen.py --- tools/kconfig_new/confgen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/kconfig_new/confgen.py b/tools/kconfig_new/confgen.py index d3a27b517a..e58f55efbf 100755 --- a/tools/kconfig_new/confgen.py +++ b/tools/kconfig_new/confgen.py @@ -475,7 +475,7 @@ def write_json_menus(deprecated_options, config, filename): if kconfiglib.expr_value(cond_expr): base = 16 if sym.type == kconfiglib.HEX else 10 greatest_range = [int(min_range.str_value, base), int(max_range.str_value, base)] - break + break new_json = { "type": kconfiglib.TYPE_TO_STR[sym.type], From fa02598b5c978402c1013b22ca81919beded97f3 Mon Sep 17 00:00:00 2001 From: xueyunfei Date: Thu, 27 Jun 2019 17:13:44 +0800 Subject: [PATCH 276/486] lwip_2.1.2 for idf_4.0 --- components/coap/port/coap_io.c | 5 - .../coap/port/include/coap_config_posix.h | 1 - components/esp_http_server/src/httpd_txrx.c | 11 +- components/idf_test/include/idf_performance.h | 4 +- components/lwip/CMakeLists.txt | 1 - components/lwip/linker.lf | 117 +++++++++++------- components/lwip/lwip | 2 +- components/lwip/port/esp32/debug/lwip_debug.c | 1 - .../lwip/port/esp32/freertos/sys_arch.c | 43 +------ components/lwip/port/esp32/include/arch/cc.h | 2 +- .../lwip/port/esp32/include/arch/sys_arch.h | 2 +- components/lwip/port/esp32/include/lwipopts.h | 48 ++----- components/lwip/port/esp32/netif/wlanif.c | 2 - components/lwip/port/esp32/vfs_lwip.c | 10 +- components/newlib/include/sys/syslimits.h | 2 +- components/newlib/platform_include/net/if.h | 8 +- components/tcpip_adapter/tcpip_adapter_lwip.c | 16 ++- .../components/iperf/iperf.c | 15 +-- .../components/modem/src/esp_modem.c | 11 +- .../main/udp_multicast_example_main.c | 11 +- examples/wifi/iperf/components/iperf/iperf.c | 15 +-- 21 files changed, 129 insertions(+), 198 deletions(-) diff --git a/components/coap/port/coap_io.c b/components/coap/port/coap_io.c index 58391add6b..a8f35c180f 100644 --- a/components/coap/port/coap_io.c +++ b/components/coap/port/coap_io.c @@ -714,11 +714,6 @@ struct in6_pktinfo { unsigned int ipi6_ifindex; /* send/recv interface index */ }; -struct in_pktinfo { - int ipi_ifindex; - struct in_addr ipi_spec_dst; - struct in_addr ipi_addr; -}; #endif #if !defined(WITH_CONTIKI) && !defined(SOL_IP) diff --git a/components/coap/port/include/coap_config_posix.h b/components/coap/port/include/coap_config_posix.h index d675b7a583..8f5a5cfb10 100644 --- a/components/coap/port/include/coap_config_posix.h +++ b/components/coap/port/include/coap_config_posix.h @@ -27,7 +27,6 @@ #define HAVE_ARPA_INET_H #define HAVE_TIME_H -#define IP_PKTINFO IP_MULTICAST_IF #define IPV6_PKTINFO IPV6_V6ONLY #define PACKAGE_NAME "libcoap-posix" diff --git a/components/esp_http_server/src/httpd_txrx.c b/components/esp_http_server/src/httpd_txrx.c index ab96550c81..8f81ae2b1e 100644 --- a/components/esp_http_server/src/httpd_txrx.c +++ b/components/esp_http_server/src/httpd_txrx.c @@ -553,16 +553,9 @@ int httpd_req_to_sockfd(httpd_req_t *r) static int httpd_sock_err(const char *ctx, int sockfd) { int errval; - int sock_err; - size_t sock_err_len = sizeof(sock_err); + ESP_LOGW(TAG, LOG_FMT("error in %s : %d"), ctx, errno); - if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &sock_err, &sock_err_len) < 0) { - ESP_LOGE(TAG, LOG_FMT("error calling getsockopt : %d"), errno); - return HTTPD_SOCK_ERR_FAIL; - } - ESP_LOGW(TAG, LOG_FMT("error in %s : %d"), ctx, sock_err); - - switch(sock_err) { + switch(errno) { case EAGAIN: case EINTR: errval = HTTPD_SOCK_ERR_TIMEOUT; diff --git a/components/idf_test/include/idf_performance.h b/components/idf_test/include/idf_performance.h index 6cdb288236..137c1b74b3 100644 --- a/components/idf_test/include/idf_performance.h +++ b/components/idf_test/include/idf_performance.h @@ -15,9 +15,9 @@ #define IDF_PERFORMANCE_MAX_VFS_OPEN_WRITE_CLOSE_TIME 20000 #define IDF_PERFORMANCE_MAX_VFS_OPEN_WRITE_CLOSE_TIME_PSRAM 25000 // throughput performance by iperf -#define IDF_PERFORMANCE_MIN_TCP_RX_THROUGHPUT 50 +#define IDF_PERFORMANCE_MIN_TCP_RX_THROUGHPUT 45 #define IDF_PERFORMANCE_MIN_TCP_TX_THROUGHPUT 40 -#define IDF_PERFORMANCE_MIN_UDP_RX_THROUGHPUT 80 +#define IDF_PERFORMANCE_MIN_UDP_RX_THROUGHPUT 64 #define IDF_PERFORMANCE_MIN_UDP_TX_THROUGHPUT 50 // events dispatched per second by event loop library #define IDF_PERFORMANCE_MIN_EVENT_DISPATCH 25000 diff --git a/components/lwip/CMakeLists.txt b/components/lwip/CMakeLists.txt index 3e1419e681..81e8f15055 100644 --- a/components/lwip/CMakeLists.txt +++ b/components/lwip/CMakeLists.txt @@ -55,7 +55,6 @@ set(srcs "lwip/src/core/ipv6/mld6.c" "lwip/src/core/ipv6/nd6.c" "lwip/src/netif/ethernet.c" - "lwip/src/netif/ethernetif.c" "lwip/src/netif/lowpan6.c" "lwip/src/netif/slipif.c" "lwip/src/netif/ppp/auth.c" diff --git a/components/lwip/linker.lf b/components/lwip/linker.lf index b4d47cb546..157e4b88bc 100644 --- a/components/lwip/linker.lf +++ b/components/lwip/linker.lf @@ -2,10 +2,72 @@ archive: liblwip.a entries: if LWIP_IRAM_OPTIMIZATION = y: - ethernetif:ethernet_low_level_output (noflash_text) - ethernetif:ethernetif_input (noflash_text) - wlanif:low_level_output (noflash_text) - wlanif:wlanif_input (noflash_text) + sockets:get_socket (noflash_text) + sockets:tryget_socket (noflash_text) + sockets:tryget_socket_unconn (noflash_text) + sockets:sock_inc_used (noflash_text) + sockets:tryget_socket_unconn_nouse (noflash_text) + sockets:done_socket (noflash_text) + sockets:lwip_recvfrom (noflash_text) + sockets:lwip_recv_tcp (noflash_text) + sockets:lwip_recv_tcp_from (noflash_text) + sockets:lwip_recvfrom_udp_raw (noflash_text) + sockets:lwip_send (noflash_text) + sockets:lwip_sendto (noflash_text) + sockets:event_callback (noflash_text) + api_lib:netconn_apimsg (noflash_text) + api_lib:netconn_recv_data (noflash_text) + api_lib:netconn_tcp_recvd_msg (noflash_text) + api_lib:netconn_tcp_recvd (noflash_text) + api_lib:netconn_recv_data_tcp (noflash_text) + api_lib:netconn_recv_tcp_pbuf_flags (noflash_text) + api_lib:netconn_recv_udp_raw_netbuf_flags (noflash_text) + api_lib:netconn_recv (noflash_text) + api_lib:netconn_sendto (noflash_text) + api_lib:netconn_send (noflash_text) + api_lib:netconn_write_partly (noflash_text) + api_lib:netconn_write_vectors_partly (noflash_text) + api_msg:lwip_netconn_do_send (noflash_text) + api_msg:lwip_netconn_do_write (noflash_text) + netbuf:netbuf_alloc (noflash_text) + netbuf:netbuf_free (noflash_text) + tcpip:tcpip_thread (noflash_text) + tcpip:tcpip_thread_handle_msg (noflash_text) + tcpip:tcpip_inpkt (noflash_text) + tcpip:tcpip_input (noflash_text) + tcpip:tcpip_callback (noflash_text) + tcpip:tcpip_try_callback (noflash_text) + tcpip:tcpip_send_msg_wait_sem (noflash_text) + inet_chksum:inet_cksum_pseudo_base (noflash_text) + inet_chksum:inet_chksum_pseudo (noflash_text) + etharp:etharp_output_to_arp_index (noflash_text) + etharp:etharp_output (noflash_text) + ip4_addr:ip4_addr_isbroadcast_u32 (noflash_text) + ip4:ip4_route_src_hook (noflash_text) + ip4:ip4_route_src (noflash_text) + ip4:ip4_route (noflash_text) + ip4:ip4_input (noflash_text) + ip4:ip4_output_if (noflash_text) + ip4:ip4_output_if_opt (noflash_text) + ip4:ip4_output_if_src (noflash_text) + ip4:ip4_output_if_opt_src (noflash_text) + ip4:ip4_output (noflash_text) + pbuf:pbuf_alloc (noflash_text) + pbuf:pbuf_add_header_impl (noflash_text) + pbuf:pbuf_add_header (noflash_text) + pbuf:pbuf_remove_header (noflash_text) + pbuf:pbuf_header_impl (noflash_text) + pbuf:pbuf_header (noflash_text) + pbuf:pbuf_free (noflash_text) + timeouts:sys_timeouts_mbox_fetch (noflash_text) + udp:udp_input_local_match (noflash_text) + udp:udp_input (noflash_text) + udp:udp_send (noflash_text) + udp:udp_sendto (noflash_text) + udp:udp_sendto_if (noflash_text) + udp:udp_sendto_if_src (noflash_text) + ethernet:ethernet_input (noflash_text) + ethernet:ethernet_output (noflash_text) sys_arch:sys_mutex_lock (noflash_text) sys_arch:sys_mutex_unlock (noflash_text) sys_arch:sys_sem_signal (noflash_text) @@ -13,47 +75,10 @@ entries: sys_arch:sys_mbox_post (noflash_text) sys_arch:sys_mbox_trypost (noflash_text) sys_arch:sys_arch_mbox_fetch (noflash_text) - sockets:get_socket (noflash_text) - sockets:lwip_recvfrom (noflash_text) - sockets:lwip_sendto (noflash_text) - sockets:event_callback (noflash_text) - sockets:lwip_sendto_r (noflash_text) - sockets:lwip_recvfrom_r (noflash_text) - sockets:lwip_recv_r (noflash_text) - api_lib:netconn_apimsg (noflash_text) - api_lib:netconn_recv_data (noflash_text) - api_lib:netconn_recv_tcp_pbuf (noflash_text) - api_lib:netconn_recv (noflash_text) - api_lib:netconn_send (noflash_text) - api_lib:netconn_write_partly (noflash_text) - tcpip:tcpip_thread (noflash_text) - tcpip:tcpip_inpkt (noflash_text) - tcpip:tcpip_input (noflash_text) - tcpip:tcpip_send_msg_wait_sem (noflash_text) - netbuf:netbuf_alloc (noflash_text) - netbuf:netbuf_free (noflash_text) - timeouts:sys_timeouts_mbox_fetch (noflash_text) - inet_chksum:inet_cksum_pseudo_base (noflash_text) - inet_chksum:inet_chksum_pseudo (noflash_text) - inet_chksum:ip_chksum_pseudo (noflash_text) - etharp:etharp_output_to_arp_index (noflash_text) - etharp:etharp_output (noflash_text) - ip4_addr:ip4_addr_isbroadcast_u32 (noflash_text) - ip4:ip4_route_src (noflash_text) - ip4:ip4_route_src_hook (noflash_text) - ip4:ip4_route (noflash_text) - ip4:ip4_input (noflash_text) - ip4:ip4_output_if_src (noflash_text) - ip4:ip4_output_if_opt_src (noflash_text) - udp:udp_input_local_match (noflash_text) - udp:udp_input (noflash_text) - udp:udp_send (noflash_text) - udp:udp_sendto (noflash_text) - udp:udp_sendto_if (noflash_text) - udp:udp_sendto_if_src (noflash_text) - pbuf:pbuf_alloc (noflash_text) - pbuf:pbuf_header_impl (noflash_text) - pbuf:pbuf_header (noflash_text) - ethernet:ethernet_input (noflash_text) + ethernetif:ethernet_low_level_output (noflash_text) + ethernetif:ethernetif_input (noflash_text) + wlanif:low_level_output (noflash_text) + wlanif:wlanif_input (noflash_text) else: + * (default) diff --git a/components/lwip/lwip b/components/lwip/lwip index 5d9fce09e3..bafc54f69b 160000 --- a/components/lwip/lwip +++ b/components/lwip/lwip @@ -1 +1 @@ -Subproject commit 5d9fce09e352a7b11949b79f386c907ce8d09fa8 +Subproject commit bafc54f69b671f368d7b996d1668b7bd4be55193 diff --git a/components/lwip/port/esp32/debug/lwip_debug.c b/components/lwip/port/esp32/debug/lwip_debug.c index 8e1574548c..c6c71b5f83 100644 --- a/components/lwip/port/esp32/debug/lwip_debug.c +++ b/components/lwip/port/esp32/debug/lwip_debug.c @@ -191,7 +191,6 @@ void dbg_lwip_stats_show(void) IP6_FRAG_STATS_DISPLAY(); MLD6_STATS_DISPLAY(); ND6_STATS_DISPLAY(); - ESP_STATS_DROP_DISPLAY(); } #if (ESP_STATS_MEM == 1) diff --git a/components/lwip/port/esp32/freertos/sys_arch.c b/components/lwip/port/esp32/freertos/sys_arch.c index fec80d1b9d..a3776d59d7 100644 --- a/components/lwip/port/esp32/freertos/sys_arch.c +++ b/components/lwip/port/esp32/freertos/sys_arch.c @@ -320,7 +320,6 @@ sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) if (msg == NULL) { msg = &pvDummy; } - if (pdTRUE == xQueueReceive((*mbox)->os_mbox, &(*msg), 0)) { ulReturn = ERR_OK; } else { @@ -349,53 +348,13 @@ sys_mbox_set_owner(sys_mbox_t *mbox, void* owner) void sys_mbox_free(sys_mbox_t *mbox) { - uint32_t mbox_message_num = 0; - if ( (NULL == mbox) || (NULL == *mbox) ) { return; } - - mbox_message_num = uxQueueMessagesWaiting((*mbox)->os_mbox); - - LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("mbox free: mbox=%p os_mbox=%p owner=%p msg_num=%d\n", - *mbox, (*mbox)->os_mbox, (*mbox)->owner, mbox_message_num)); - -#if ESP_THREAD_SAFE - if ((*mbox)->owner) { - if (0 == mbox_message_num) { - /* - * If mbox->owner is not NULL, it indicates the mbox is recvmbox or acceptmbox, - * we need to post a NULL message to mbox in case some application tasks are blocked - * on this mbox - */ - if (sys_mbox_trypost(mbox, NULL) != ERR_OK) { - /* Should never be here because post a message to empty mbox should always be successful */ - ESP_LOGW(TAG, "WARNING: failed to post NULL msg to mbox\n"); - } else { - LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("mbox free: post null successfully\n")); - } - } - (*mbox)->owner = NULL; - } else { - if (mbox_message_num > 1) { - ESP_LOGW(TAG, "WARNING: mbox has %d message, potential memory leaking\n", mbox_message_num); - } - - if (mbox_message_num > 0) { - LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("mbox free: reset mbox queue\n")); - xQueueReset((*mbox)->os_mbox); - } - - /* For recvmbox or acceptmbox, free them in netconn_free() when all sockets' API are returned */ - vQueueDelete((*mbox)->os_mbox); - free(*mbox); - *mbox = NULL; - } -#else vQueueDelete((*mbox)->os_mbox); free(*mbox); *mbox = NULL; -#endif + } /*-----------------------------------------------------------------------------------*/ diff --git a/components/lwip/port/esp32/include/arch/cc.h b/components/lwip/port/esp32/include/arch/cc.h index 1841e3f45a..300291f3bf 100644 --- a/components/lwip/port/esp32/include/arch/cc.h +++ b/components/lwip/port/esp32/include/arch/cc.h @@ -52,7 +52,7 @@ typedef int16_t s16_t; typedef uint32_t u32_t; typedef int32_t s32_t; -typedef unsigned long mem_ptr_t; + typedef int sys_prot_t; #define S16_F "d" diff --git a/components/lwip/port/esp32/include/arch/sys_arch.h b/components/lwip/port/esp32/include/arch/sys_arch.h index 9638fdfd62..5fea8eb552 100644 --- a/components/lwip/port/esp32/include/arch/sys_arch.h +++ b/components/lwip/port/esp32/include/arch/sys_arch.h @@ -80,7 +80,7 @@ typedef struct sys_mbox_s { * However, if the sys_mbox_set_invalid() is not called after sys_mbox_free(), e.g. in netconn_alloc(), * we need to initialize the mbox to invalid explicitly since sys_mbox_set_invalid() now is empty. */ -#define sys_mbox_set_invalid( x ) +#define sys_mbox_set_invalid( x ) *x = NULL #define sys_sem_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE ) #define sys_sem_set_invalid( x ) ( ( *x ) = NULL ) diff --git a/components/lwip/port/esp32/include/lwipopts.h b/components/lwip/port/esp32/include/lwipopts.h index 713d3ff097..e37d272ccc 100644 --- a/components/lwip/port/esp32/include/lwipopts.h +++ b/components/lwip/port/esp32/include/lwipopts.h @@ -766,13 +766,18 @@ #define ESP_STATS_MEM CONFIG_LWIP_STATS #define ESP_STATS_DROP CONFIG_LWIP_STATS #define ESP_STATS_TCP 0 -#define ESP_DHCP_TIMER 1 #define ESP_DHCPS_TIMER 1 #define ESP_LWIP_LOGI(...) ESP_LOGI("lwip", __VA_ARGS__) #define ESP_PING 1 #define ESP_HAS_SELECT 1 #define ESP_AUTO_RECV 1 #define ESP_GRATUITOUS_ARP CONFIG_LWIP_ESP_GRATUITOUS_ARP +#define ESP_IP4_ROUTE 1 +#define ESP_AUTO_IP 1 +#define ESP_PBUF 1 +#define ESP_PPP 1 +#define ESP_IPV6 1 +#define ESP_SOCKET 1 #ifdef ESP_IRAM_ATTR #undef ESP_IRAM_ATTR @@ -787,44 +792,9 @@ #define ESP_LWIP_MLD6_TIMERS_ONDEMAND 0 #endif -#if ESP_PERF -#define DBG_PERF_PATH_SET(dir, point) -#define DBG_PERF_FILTER_LEN 1000 - -enum { - DBG_PERF_DIR_RX = 0, - DBG_PERF_DIR_TX, -}; - -enum { - DBG_PERF_POINT_INT = 0, - DBG_PERF_POINT_WIFI_IN = 1, - DBG_PERF_POINT_WIFI_OUT = 2, - DBG_PERF_POINT_LWIP_IN = 3, - DBG_PERF_POINT_LWIP_OUT = 4, - DBG_PERF_POINT_SOC_IN = 5, - DBG_PERF_POINT_SOC_OUT = 6, -}; - -#else -#define DBG_PERF_PATH_SET(dir, point) -#define DBG_PERF_FILTER_LEN 1000 -#endif - #define TCP_SND_BUF CONFIG_LWIP_TCP_SND_BUF_DEFAULT #define TCP_WND CONFIG_LWIP_TCP_WND_DEFAULT -#if ESP_PER_SOC_TCP_WND -#define TCP_WND_DEFAULT CONFIG_LWIP_TCP_WND_DEFAULT -#define TCP_SND_BUF_DEFAULT CONFIG_LWIP_TCP_SND_BUF_DEFAULT -#define TCP_WND(pcb) (pcb->per_soc_tcp_wnd) -#define TCP_SND_BUF(pcb) (pcb->per_soc_tcp_snd_buf) -#define TCP_SND_QUEUELEN(pcb) ((4 * (TCP_SND_BUF((pcb))) + (TCP_MSS - 1))/(TCP_MSS)) -#define TCP_SNDLOWAT(pcb) LWIP_MIN(LWIP_MAX(((TCP_SND_BUF((pcb)))/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF((pcb))) - 1) -#define TCP_SNDQUEUELOWAT(pcb) LWIP_MAX(((TCP_SND_QUEUELEN((pcb)))/2), 5) -#define TCP_WND_UPDATE_THRESHOLD(pcb) LWIP_MIN((TCP_WND((pcb)) / 4), (TCP_MSS * 4)) -#endif - /** * DHCP_DEBUG: Enable debugging in dhcp.c. */ @@ -849,6 +819,12 @@ enum { /* * SNTP update delay - in milliseconds */ +/** Set this to 1 to support DNS names (or IP address strings) to set sntp servers + * One server address/name can be defined as default if SNTP_SERVER_DNS == 1: + * \#define SNTP_SERVER_ADDRESS "pool.ntp.org" + */ +#define SNTP_SERVER_DNS 1 + #define SNTP_UPDATE_DELAY CONFIG_LWIP_SNTP_UPDATE_DELAY #define SNTP_SET_SYSTEM_TIME_US(sec, us) \ diff --git a/components/lwip/port/esp32/netif/wlanif.c b/components/lwip/port/esp32/netif/wlanif.c index cd2bdac8d7..11e1fc857f 100644 --- a/components/lwip/port/esp32/netif/wlanif.c +++ b/components/lwip/port/esp32/netif/wlanif.c @@ -154,7 +154,6 @@ wlanif_input(struct netif *netif, void *buffer, u16_t len, void* eb) #if (ESP_L2_TO_L3_COPY == 1) p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM); if (p == NULL) { - ESP_STATS_DROP_INC(esp.wlanif_input_pbuf_fail); esp_wifi_internal_free_rx_buffer(eb); return; } @@ -164,7 +163,6 @@ wlanif_input(struct netif *netif, void *buffer, u16_t len, void* eb) #else p = pbuf_alloc(PBUF_RAW, len, PBUF_REF); if (p == NULL){ - ESP_STATS_DROP_INC(esp.wlanif_input_pbuf_fail); esp_wifi_internal_free_rx_buffer(eb); return; } diff --git a/components/lwip/port/esp32/vfs_lwip.c b/components/lwip/port/esp32/vfs_lwip.c index 6b687a196c..ffd3e79e1f 100644 --- a/components/lwip/port/esp32/vfs_lwip.c +++ b/components/lwip/port/esp32/vfs_lwip.c @@ -49,23 +49,23 @@ static void *lwip_get_socket_select_semaphore() static int lwip_fcntl_r_wrapper(int fd, int cmd, int arg) { - return lwip_fcntl_r(fd, cmd, arg); + return lwip_fcntl(fd, cmd, arg); } static int lwip_ioctl_r_wrapper(int fd, int cmd, va_list args) { - return lwip_ioctl_r(fd, cmd, va_arg(args, void *)); + return lwip_ioctl(fd, cmd, va_arg(args, void *)); } void esp_vfs_lwip_sockets_register() { esp_vfs_t vfs = { .flags = ESP_VFS_FLAG_DEFAULT, - .write = &lwip_write_r, + .write = &lwip_write, .open = NULL, .fstat = NULL, - .close = &lwip_close_r, - .read = &lwip_read_r, + .close = &lwip_close, + .read = &lwip_read, .fcntl = &lwip_fcntl_r_wrapper, .ioctl = &lwip_ioctl_r_wrapper, .socket_select = &lwip_select, diff --git a/components/newlib/include/sys/syslimits.h b/components/newlib/include/sys/syslimits.h index c0bb3a2ce0..c778f0faf3 100644 --- a/components/newlib/include/sys/syslimits.h +++ b/components/newlib/include/sys/syslimits.h @@ -51,7 +51,7 @@ #endif #define PATH_MAX 1024 /* max bytes in pathname */ #define PIPE_BUF 512 /* max bytes for atomic pipe writes */ -#define IOV_MAX 1024 /* max elements in i/o vector */ + #define BC_BASE_MAX 99 /* max ibase/obase values in bc(1) */ #define BC_DIM_MAX 2048 /* max array elements in bc(1) */ diff --git a/components/newlib/platform_include/net/if.h b/components/newlib/platform_include/net/if.h index 8760bb156e..e3d0a601a0 100644 --- a/components/newlib/platform_include/net/if.h +++ b/components/newlib/platform_include/net/if.h @@ -14,6 +14,8 @@ #ifndef _ESP_PLATFORM_NET_IF_H_ #define _ESP_PLATFORM_NET_IF_H_ +#include "lwip/sockets.h" + #define MSG_DONTROUTE 0x4 /* send without using routing tables */ #define SOCK_SEQPACKET 5 /* sequenced packet stream */ #define MSG_EOR 0x8 /* data completes record */ @@ -29,12 +31,6 @@ #define NI_NUMERICSERV 0x00000008 #define NI_DGRAM 0x00000010 - -struct ipv6_mreq { - struct in6_addr ipv6mr_multiaddr; - unsigned int ipv6mr_interface; -}; - typedef u32_t socklen_t; diff --git a/components/tcpip_adapter/tcpip_adapter_lwip.c b/components/tcpip_adapter/tcpip_adapter_lwip.c index 8bc384e4ca..88413d3a95 100644 --- a/components/tcpip_adapter/tcpip_adapter_lwip.c +++ b/components/tcpip_adapter/tcpip_adapter_lwip.c @@ -157,13 +157,13 @@ static int tcpip_adapter_ipc_check(tcpip_adapter_api_msg_t *msg) static esp_err_t tcpip_adapter_update_default_netif(void) { - if (netif_is_up(esp_netif[TCPIP_ADAPTER_IF_STA])) { + if (esp_netif[TCPIP_ADAPTER_IF_STA] != NULL && netif_is_up(esp_netif[TCPIP_ADAPTER_IF_STA])) { netif_set_default(esp_netif[TCPIP_ADAPTER_IF_STA]); - } else if (netif_is_up(esp_netif[TCPIP_ADAPTER_IF_ETH])) { + } else if (esp_netif[TCPIP_ADAPTER_IF_ETH] != NULL && netif_is_up(esp_netif[TCPIP_ADAPTER_IF_ETH])) { netif_set_default(esp_netif[TCPIP_ADAPTER_IF_ETH]); - } else if (netif_is_up(esp_netif[TCPIP_ADAPTER_IF_AP])) { + } else if (esp_netif[TCPIP_ADAPTER_IF_AP] != NULL && netif_is_up(esp_netif[TCPIP_ADAPTER_IF_AP])) { netif_set_default(esp_netif[TCPIP_ADAPTER_IF_AP]); - } else if (netif_is_up(esp_netif[TCPIP_ADAPTER_IF_TEST])) { + } else if(esp_netif[TCPIP_ADAPTER_IF_TEST] != NULL && netif_is_up(esp_netif[TCPIP_ADAPTER_IF_TEST])) { netif_set_default(esp_netif[TCPIP_ADAPTER_IF_TEST]); } @@ -193,6 +193,7 @@ static esp_err_t tcpip_adapter_start(tcpip_adapter_if_t tcpip_if, uint8_t *mac, netif_init = tcpip_if_to_netif_init_fn(tcpip_if); assert(netif_init != NULL); netif_add(esp_netif[tcpip_if], &ip_info->ip, &ip_info->netmask, &ip_info->gw, args, netif_init, tcpip_input); + #if ESP_GRATUITOUS_ARP if (tcpip_if == TCPIP_ADAPTER_IF_STA || tcpip_if == TCPIP_ADAPTER_IF_ETH) { netif_set_garp_flag(esp_netif[tcpip_if]); @@ -767,6 +768,8 @@ esp_err_t tcpip_adapter_get_dns_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_ dns_param.dns_type = type; dns_param.dns_info = dns; + const ip_addr_t* dns_ip = NULL; + TCPIP_ADAPTER_IPC_CALL(tcpip_if, type, 0, &dns_param, tcpip_adapter_get_dns_info_api); if (!dns) { @@ -785,7 +788,10 @@ esp_err_t tcpip_adapter_get_dns_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_ } if (tcpip_if == TCPIP_ADAPTER_IF_STA || tcpip_if == TCPIP_ADAPTER_IF_ETH) { - dns->ip = dns_getserver(type); + dns_ip = dns_getserver(type); + if(dns_ip != NULL){ + dns->ip = *dns_ip; + } } else { dns->ip.u_addr.ip4 = dhcps_dns_getserver(); } diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/components/iperf/iperf.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/components/iperf/iperf.c index d9822a3772..70cfa272fe 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/components/iperf/iperf.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/components/iperf/iperf.c @@ -55,23 +55,12 @@ inline static bool iperf_is_tcp_server(void) int iperf_get_socket_error_code(int sockfd) { - uint32_t optlen = sizeof(int); - int result; - int err; - - err = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &result, &optlen); - if (err == -1) { - ESP_LOGE(TAG, "getsockopt failed: ret=%d", err); - return -1; - } - - return result; + return errno; } int iperf_show_socket_error_reason(const char *str, int sockfd) { - int err = iperf_get_socket_error_code(sockfd); - + int err = errno; if (err != 0) { ESP_LOGW(TAG, "%s error, error code: %d, reason: %s", str, err, strerror(err)); } diff --git a/examples/protocols/pppos_client/components/modem/src/esp_modem.c b/examples/protocols/pppos_client/components/modem/src/esp_modem.c index 148d67473c..979b73870a 100644 --- a/examples/protocols/pppos_client/components/modem/src/esp_modem.c +++ b/examples/protocols/pppos_client/components/modem/src/esp_modem.c @@ -454,6 +454,7 @@ esp_err_t esp_modem_remove_event_handler(modem_dte_t *dte, esp_event_handler_t h static void on_ppp_status_changed(ppp_pcb *pcb, int err_code, void *ctx) { struct netif *pppif = ppp_netif(pcb); + const ip_addr_t *dest_ip = NULL; modem_dte_t *dte = (modem_dte_t *)(ctx); esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent); ppp_client_ip_info_t ipinfo = {0}; @@ -462,8 +463,14 @@ static void on_ppp_status_changed(ppp_pcb *pcb, int err_code, void *ctx) ipinfo.ip = pppif->ip_addr.u_addr.ip4; ipinfo.gw = pppif->gw.u_addr.ip4; ipinfo.netmask = pppif->netmask.u_addr.ip4; - ipinfo.ns1 = dns_getserver(0).u_addr.ip4; - ipinfo.ns2 = dns_getserver(1).u_addr.ip4; + dest_ip = dns_getserver(0); + if(dest_ip != NULL){ + ipinfo.ns1 = (*dest_ip).u_addr.ip4; + } + dest_ip = dns_getserver(1); + if(dest_ip != NULL){ + ipinfo.ns2 = (*dest_ip).u_addr.ip4; + } esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, MODEM_EVENT_PPP_CONNECT, &ipinfo, sizeof(ipinfo), 0); break; case PPPERR_PARAM: diff --git a/examples/protocols/sockets/udp_multicast/main/udp_multicast_example_main.c b/examples/protocols/sockets/udp_multicast/main/udp_multicast_example_main.c index 03025125be..ee68788978 100644 --- a/examples/protocols/sockets/udp_multicast/main/udp_multicast_example_main.c +++ b/examples/protocols/sockets/udp_multicast/main/udp_multicast_example_main.c @@ -170,9 +170,10 @@ err: static int create_multicast_ipv6_socket() { struct sockaddr_in6 saddr = { 0 }; + u8_t netif_index = EXAMPLE_INTERFACE; struct in6_addr if_inaddr = { 0 }; struct ip6_addr if_ipaddr = { 0 }; - struct ip6_mreq v6imreq = { 0 }; + struct ipv6_mreq v6imreq = { 0 }; int sock = -1; int err = 0; @@ -211,8 +212,7 @@ static int create_multicast_ipv6_socket() #endif // LISTEN_ALL_IF // Assign the multicast source interface, via its IP - err = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &if_inaddr, - sizeof(struct in6_addr)); + err = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &netif_index,sizeof(uint8_t)); if (err < 0) { ESP_LOGE(V6TAG, "Failed to set IPV6_MULTICAST_IF. Error %d", errno); goto err; @@ -245,7 +245,8 @@ static int create_multicast_ipv6_socket() #if LISTEN_ALL_IF v6imreq.imr_interface.s_addr = IPADDR_ANY; #else - inet6_addr_from_ip6addr(&v6imreq.ipv6mr_interface, &if_ipaddr); + v6imreq.ipv6mr_interface = EXAMPLE_INTERFACE; + /* inet6_addr_from_ip6addr(&v6imreq.ipv6mr_interface, &if_ipaddr);*/ #endif // LISTEN_ALL_IF #ifdef CONFIG_EXAMPLE_IPV6 // Configure multicast address to listen to @@ -262,7 +263,7 @@ static int create_multicast_ipv6_socket() } err = setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, - &v6imreq, sizeof(struct ip6_mreq)); + &v6imreq, sizeof(struct ipv6_mreq)); if (err < 0) { ESP_LOGE(V6TAG, "Failed to set IPV6_ADD_MEMBERSHIP. Error %d", errno); goto err; diff --git a/examples/wifi/iperf/components/iperf/iperf.c b/examples/wifi/iperf/components/iperf/iperf.c index 52d2471372..71d09fee77 100644 --- a/examples/wifi/iperf/components/iperf/iperf.c +++ b/examples/wifi/iperf/components/iperf/iperf.c @@ -56,24 +56,13 @@ inline static bool iperf_is_tcp_server(void) static int iperf_get_socket_error_code(int sockfd) { - uint32_t optlen = sizeof(int); - int result; - int err; - /* get the error state, and clear it */ - err = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &result, &optlen); - if (err == -1) { - ESP_LOGE(TAG, "getsockopt failed: ret=%d", err); - return -1; - } - - return result; + return errno; } static int iperf_show_socket_error_reason(const char *str, int sockfd) { - int err = iperf_get_socket_error_code(sockfd); - + int err = errno; if (err != 0) { ESP_LOGW(TAG, "%s error, error code: %d, reason: %s", str, err, strerror(err)); } From 266baa883917379c0a263924f81fec89bae8d433 Mon Sep 17 00:00:00 2001 From: chenjianqiang Date: Thu, 27 Jun 2019 20:19:26 +0800 Subject: [PATCH 277/486] bugfix(flash): fix flash read error in DIO/26MHz mode --- components/bootloader_support/src/bootloader_init.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/bootloader_support/src/bootloader_init.c b/components/bootloader_support/src/bootloader_init.c index 6a94713d13..199ec7edad 100644 --- a/components/bootloader_support/src/bootloader_init.c +++ b/components/bootloader_support/src/bootloader_init.c @@ -335,6 +335,10 @@ static void IRAM_ATTR flash_gpio_configure(const esp_image_header_t* pfhdr) SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN_V, spi_cache_dummy + FLASH_IO_MATRIX_DUMMY_40M, SPI_USR_DUMMY_CYCLELEN_S); //DUMMY break; + case ESP_IMAGE_SPI_SPEED_26M: + case ESP_IMAGE_SPI_SPEED_20M: + SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN_V, spi_cache_dummy, SPI_USR_DUMMY_CYCLELEN_S); //DUMMY + break; default: break; } From 09a63cca5131ea9c5d58c0d2d5e1178443c56063 Mon Sep 17 00:00:00 2001 From: kooho <2229179028@qq.com> Date: Wed, 12 Jun 2019 16:20:19 +0800 Subject: [PATCH 278/486] bugfix(UART): fixed two UART issues: 1. uart_wait_tx_done works incorrect when sending a byte of data. 2. uart_set_rx_timeout sets an incorrect rx timeout value when ref_tick is enabled closes https://github.com/espressif/esp-idf/issues/3631 --- components/driver/uart.c | 60 ++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/components/driver/uart.c b/components/driver/uart.c index 9a26f6423f..20306c1287 100644 --- a/components/driver/uart.c +++ b/components/driver/uart.c @@ -709,9 +709,9 @@ esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_ //Hardware issue workaround: when using ref_tick, the rx timeout threshold needs increase to 10 times. //T_ref = T_apb * APB_CLK/(REF_TICK << CLKDIV_FRAG_BIT_WIDTH) if(UART[uart_num]->conf0.tick_ref_always_on == 0) { - UART[uart_num]->conf1.rx_tout_thrhd = ((intr_conf->rx_timeout_thresh * UART_TOUT_REF_FACTOR_DEFAULT) & UART_RX_TOUT_THRHD_V); + UART[uart_num]->conf1.rx_tout_thrhd = (intr_conf->rx_timeout_thresh * UART_TOUT_REF_FACTOR_DEFAULT); } else { - UART[uart_num]->conf1.rx_tout_thrhd = ((intr_conf->rx_timeout_thresh) & UART_RX_TOUT_THRHD_V); + UART[uart_num]->conf1.rx_tout_thrhd = intr_conf->rx_timeout_thresh; } UART[uart_num]->conf1.rx_tout_en = 1; } else { @@ -752,14 +752,19 @@ static void uart_rx_intr_handler_default(void *param) uart_obj_t *p_uart = (uart_obj_t*) param; uint8_t uart_num = p_uart->uart_num; uart_dev_t* uart_reg = UART[uart_num]; - int rx_fifo_len = uart_reg->status.rxfifo_cnt; + int rx_fifo_len = 0; uint8_t buf_idx = 0; - uint32_t uart_intr_status = UART[uart_num]->int_st.val; + uint32_t uart_intr_status = 0; uart_event_t uart_event; portBASE_TYPE HPTaskAwoken = 0; static uint8_t pat_flg = 0; - while(uart_intr_status != 0x0) { - buf_idx = 0; + while(1) { + uart_intr_status = uart_reg->int_st.val; + // The `continue statement` may cause the interrupt to loop infinitely + // we exit the interrupt here + if(uart_intr_status == 0) { + break; + } uart_event.type = UART_EVENT_MAX; if(uart_intr_status & UART_TXFIFO_EMPTY_INT_ST_M) { uart_clear_intr_status(uart_num, UART_TXFIFO_EMPTY_INT_CLR_M); @@ -771,15 +776,12 @@ static void uart_rx_intr_handler_default(void *param) if(p_uart->tx_waiting_fifo == true && p_uart->tx_buf_size == 0) { p_uart->tx_waiting_fifo = false; xSemaphoreGiveFromISR(p_uart->tx_fifo_sem, &HPTaskAwoken); - if(HPTaskAwoken == pdTRUE) { - portYIELD_FROM_ISR(); - } } else { //We don't use TX ring buffer, because the size is zero. if(p_uart->tx_buf_size == 0) { continue; } - int tx_fifo_rem = UART_FIFO_LEN - UART[uart_num]->status.txfifo_cnt; + int tx_fifo_rem = UART_FIFO_LEN - uart_reg->status.txfifo_cnt; bool en_tx_flg = false; //We need to put a loop here, in case all the buffer items are very short. //That would cause a watch_dog reset because empty interrupt happens so often. @@ -800,9 +802,6 @@ static void uart_rx_intr_handler_default(void *param) } //We have saved the data description from the 1st item, return buffer. vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &HPTaskAwoken); - if(HPTaskAwoken == pdTRUE) { - portYIELD_FROM_ISR(); - } }else if(p_uart->tx_ptr == NULL) { //Update the TX item pointer, we will need this to return item to buffer. p_uart->tx_ptr = (uint8_t*) p_uart->tx_head; @@ -835,9 +834,6 @@ static void uart_rx_intr_handler_default(void *param) if (p_uart->tx_len_cur == 0) { //Return item to ring buffer. vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &HPTaskAwoken); - if(HPTaskAwoken == pdTRUE) { - portYIELD_FROM_ISR(); - } p_uart->tx_head = NULL; p_uart->tx_ptr = NULL; //Sending item done, now we need to send break if there is a record. @@ -880,8 +876,8 @@ static void uart_rx_intr_handler_default(void *param) } if (p_uart->rx_buffer_full_flg == false) { //We have to read out all data in RX FIFO to clear the interrupt signal - while (buf_idx < rx_fifo_len) { - p_uart->rx_data_buf[buf_idx++] = uart_reg->fifo.rw_byte; + for(buf_idx = 0; buf_idx < rx_fifo_len; buf_idx++) { + p_uart->rx_data_buf[buf_idx] = uart_reg->fifo.rw_byte; } uint8_t pat_chr = uart_reg->at_cmd_char.data; int pat_num = uart_reg->at_cmd_char.char_num; @@ -941,9 +937,6 @@ static void uart_rx_intr_handler_default(void *param) p_uart->rx_buffered_len += p_uart->rx_stash_len; UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); } - if(HPTaskAwoken == pdTRUE) { - portYIELD_FROM_ISR(); - } } else { uart_disable_intr_mask_from_isr(uart_num, UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M); uart_clear_intr_status(uart_num, UART_RXFIFO_FULL_INT_CLR_M | UART_RXFIFO_TOUT_INT_CLR_M); @@ -999,9 +992,6 @@ static void uart_rx_intr_handler_default(void *param) p_uart->tx_waiting_brk = 0; } else { xSemaphoreGiveFromISR(p_uart->tx_brk_sem, &HPTaskAwoken); - if(HPTaskAwoken == pdTRUE) { - portYIELD_FROM_ISR(); - } } } else if(uart_intr_status & UART_TX_BRK_IDLE_DONE_INT_ST_M) { uart_disable_intr_mask_from_isr(uart_num, UART_TX_BRK_IDLE_DONE_INT_ENA_M); @@ -1032,9 +1022,6 @@ static void uart_rx_intr_handler_default(void *param) UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); } xSemaphoreGiveFromISR(p_uart_obj[uart_num]->tx_done_sem, &HPTaskAwoken); - if (HPTaskAwoken == pdTRUE) { - portYIELD_FROM_ISR(); - } } else { uart_reg->int_clr.val = uart_intr_status; /*simply clear all other intr status*/ uart_event.type = UART_EVENT_MAX; @@ -1044,11 +1031,10 @@ static void uart_rx_intr_handler_default(void *param) if (pdFALSE == xQueueSendFromISR(p_uart->xQueueUart, (void * )&uart_event, &HPTaskAwoken)) { ESP_EARLY_LOGV(UART_TAG, "UART event queue full"); } - if(HPTaskAwoken == pdTRUE) { - portYIELD_FROM_ISR(); - } } - uart_intr_status = uart_reg->int_st.val; + } + if(HPTaskAwoken == pdTRUE) { + portYIELD_FROM_ISR(); } } @@ -1065,7 +1051,9 @@ esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait) return ESP_ERR_TIMEOUT; } xSemaphoreTake(p_uart_obj[uart_num]->tx_done_sem, 0); - if(UART[uart_num]->status.txfifo_cnt == 0) { + typeof(UART0.status) status = UART[uart_num]->status; + //Wait txfifo_cnt = 0, and the transmitter state machine is in idle state. + if(status.txfifo_cnt == 0 && status.st_utx_out == 0) { xSemaphoreGive(p_uart_obj[uart_num]->tx_mux); return ESP_OK; } @@ -1568,7 +1556,13 @@ esp_err_t uart_set_rx_timeout(uart_port_t uart_num, const uint8_t tout_thresh) // The tout_thresh = 1, defines TOUT interrupt timeout equal to // transmission time of one symbol (~11 bit) on current baudrate if (tout_thresh > 0) { - UART[uart_num]->conf1.rx_tout_thrhd = (tout_thresh & UART_RX_TOUT_THRHD_V); + //Hardware issue workaround: when using ref_tick, the rx timeout threshold needs increase to 10 times. + //T_ref = T_apb * APB_CLK/(REF_TICK << CLKDIV_FRAG_BIT_WIDTH) + if(UART[uart_num]->conf0.tick_ref_always_on == 0) { + UART[uart_num]->conf1.rx_tout_thrhd = tout_thresh * UART_TOUT_REF_FACTOR_DEFAULT; + } else { + UART[uart_num]->conf1.rx_tout_thrhd = tout_thresh; + } UART[uart_num]->conf1.rx_tout_en = 1; } else { UART[uart_num]->conf1.rx_tout_en = 0; From 363f3e83119e89d182a2e4a6aafc7ffde86222bc Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Mon, 8 Jul 2019 13:19:56 +0800 Subject: [PATCH 279/486] docs: Remove building of zipped HTML docs from build process and consequently from Downloads as many users don't use that. We are still providing PDF documentation for people who prefer viewing docs off-line. Removal of this build step is expected to save almost 10 minutes of build time and resolve issue of build failures because of hitting 40 min build time limit on Read The Docs. --- .readthedocs.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 76f779bca7..4eeb372430 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -7,7 +7,6 @@ version: 2 # Optionally build your docs in additional formats such as PDF and ePub formats: - - htmlzip - pdf # Optionally set the version of Python and requirements required to build your docs From e0360bf15609179b4d7f9c7cf035c3bcfe9da449 Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Thu, 4 Jul 2019 12:18:43 +0800 Subject: [PATCH 280/486] temporarily work around for fixing eth2ap Closes https://github.com/espressif/esp-idf/issues/3726 Closes https://github.com/espressif/esp-idf/issues/3728 --- examples/ethernet/eth2ap/README.md | 2 ++ examples/ethernet/eth2ap/main/ethernet_example_main.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/ethernet/eth2ap/README.md b/examples/ethernet/eth2ap/README.md index 26d81db121..e2b3e03219 100644 --- a/examples/ethernet/eth2ap/README.md +++ b/examples/ethernet/eth2ap/README.md @@ -1,6 +1,8 @@ # eth2ap Example (See the README.md file in the upper level 'examples' directory for more information about examples. To try a more complex application about Ethernet to WiFi data forwarding, please go to [iot-solution](https://github.com/espressif/esp-iot-solution/tree/master/examples/eth2wifi).) +**Note:** This example uses some internal APIs (e.g. `esp_wifi_internal_tx`) which might get changed between minor versions of ESP-IDF. + ## Overview ![eth2ap](eth2ap.png) diff --git a/examples/ethernet/eth2ap/main/ethernet_example_main.c b/examples/ethernet/eth2ap/main/ethernet_example_main.c index 6ea43dd3b0..4796cd9a13 100644 --- a/examples/ethernet/eth2ap/main/ethernet_example_main.c +++ b/examples/ethernet/eth2ap/main/ethernet_example_main.c @@ -192,7 +192,8 @@ static void initialize_wifi(void) { ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler, NULL)); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_ERROR_CHECK(esp_wifi_init_internal(&cfg)); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + ESP_ERROR_CHECK(tcpip_adapter_clear_default_wifi_handlers()); ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); wifi_config_t wifi_config = { .ap = { From d6c2dad101d58c0d53cafbfdf3636b70cd975208 Mon Sep 17 00:00:00 2001 From: Martin Thierer Date: Sat, 6 Jul 2019 12:22:23 +0200 Subject: [PATCH 281/486] esp_partition_erase_range(): rename parameter "start_addr" to "offset" The name "start_addr" (which goes straight into the docs) implies it's an absolute address while in fact it's an offset into the partition like what's used in all the other esp_partition_* functions. So in order to avoid confusion make the name consistent with the parameter names used for the other partition functions and call it "offset". Merges https://github.com/espressif/esp-idf/pull/3750 --- components/spi_flash/include/esp_partition.h | 6 +++--- components/spi_flash/partition.c | 13 ++++++------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/components/spi_flash/include/esp_partition.h b/components/spi_flash/include/esp_partition.h index ade2e9eab8..42ac6777c9 100644 --- a/components/spi_flash/include/esp_partition.h +++ b/components/spi_flash/include/esp_partition.h @@ -249,8 +249,8 @@ esp_err_t esp_partition_write(const esp_partition_t* partition, * @param partition Pointer to partition structure obtained using * esp_partition_find_first or esp_partition_get. * Must be non-NULL. - * @param start_addr Address where erase operation should start. Must be aligned - * to 4 kilobytes. + * @param offset Offset from the beginning of partition where erase operation + * should start. Must be aligned to 4 kilobytes. * @param size Size of the range which should be erased, in bytes. * Must be divisible by 4 kilobytes. * @@ -260,7 +260,7 @@ esp_err_t esp_partition_write(const esp_partition_t* partition, * or one of error codes from lower-level flash driver. */ esp_err_t esp_partition_erase_range(const esp_partition_t* partition, - size_t start_addr, size_t size); + size_t offset, size_t size); /** * @brief Configure MMU to map partition into data memory diff --git a/components/spi_flash/partition.c b/components/spi_flash/partition.c index b598fcd5f2..f31705c81c 100644 --- a/components/spi_flash/partition.c +++ b/components/spi_flash/partition.c @@ -387,27 +387,26 @@ esp_err_t esp_partition_write(const esp_partition_t* partition, } esp_err_t esp_partition_erase_range(const esp_partition_t* partition, - size_t start_addr, size_t size) + size_t offset, size_t size) { assert(partition != NULL); - if (start_addr > partition->size) { + if (offset > partition->size) { return ESP_ERR_INVALID_ARG; } - if (start_addr + size > partition->size) { + if (offset + size > partition->size) { return ESP_ERR_INVALID_SIZE; } if (size % SPI_FLASH_SEC_SIZE != 0) { return ESP_ERR_INVALID_SIZE; } - if (start_addr % SPI_FLASH_SEC_SIZE != 0) { + if (offset % SPI_FLASH_SEC_SIZE != 0) { return ESP_ERR_INVALID_ARG; } #ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL - return esp_flash_erase_region(partition->flash_chip, partition->address + start_addr, size); + return esp_flash_erase_region(partition->flash_chip, partition->address + offset, size); #else - return spi_flash_erase_range(partition->address + start_addr, size); + return spi_flash_erase_range(partition->address + offset, size); #endif // CONFIG_SPI_FLASH_USE_LEGACY_IMPL - } /* From 47bbb107a8deaa80692ebc3b9369ae0618c3bc56 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Sun, 23 Jun 2019 11:54:31 +1000 Subject: [PATCH 282/486] build system: Use CMake-based build system as default when describing commands --- Kconfig | 6 +- README.md | 64 +++++++------------ components/esptool_py/Kconfig.projbuild | 11 ++-- components/nvs_flash/README.rst | 2 +- components/spi_flash/README.rst | 2 +- components/spi_flash/README_legacy.rst | 2 +- docs/TEMPLATE_EXAMPLE_README.md | 10 +-- docs/en/api-guides/console.rst | 2 +- docs/en/api-guides/core_dump.rst | 4 +- docs/en/api-guides/freertos-smp.rst | 13 ++-- docs/en/api-guides/partition-tables.rst | 18 +++--- docs/en/api-guides/tools/idf-monitor.rst | 24 ++----- docs/en/api-guides/ulp.rst | 2 +- docs/en/api-reference/kconfig.rst | 17 +++-- docs/en/api-reference/protocols/mqtt.rst | 8 +-- docs/en/api-reference/system/efuse.rst | 10 +-- .../system/freertos_additions.rst | 2 +- docs/en/api-reference/system/heap_debug.rst | 14 ++-- docs/en/api-reference/system/mem_alloc.rst | 4 +- docs/en/api-reference/system/system.rst | 9 +-- docs/en/api-reference/system/wdts.rst | 4 +- docs/en/security/flash-encryption.rst | 37 ++++++----- docs/en/security/secure-boot.rst | 18 +++--- docs/zh_CN/api-guides/console.rst | 2 +- .../jtag-debugging/tips-and-quirks.rst | 2 +- docs/zh_CN/api-guides/partition-tables.rst | 18 +++--- docs/zh_CN/api-guides/tools/idf-monitor.rst | 21 ++---- examples/README.md | 4 +- .../bluedroid/ble/ble_ibeacon/README.md | 8 +-- .../throughput_client/README.md | 8 +-- .../throughput_server/README.md | 8 +-- .../bluedroid/classic_bt/a2dp_sink/README.md | 8 +-- .../classic_bt/a2dp_source/README.md | 6 +- .../classic_bt/bt_discovery/README.rst | 2 +- .../classic_bt/bt_spp_acceptor/README.rst | 4 +- .../classic_bt/bt_spp_initiator/README.rst | 4 +- .../classic_bt/bt_spp_vfs_acceptor/README.rst | 4 +- .../bt_spp_vfs_initiator/README.rst | 4 +- examples/ethernet/eth2ap/README.md | 4 +- examples/get-started/blink/main/blink.c | 2 +- .../mesh/internal_communication/README.md | 2 +- examples/mesh/manual_networking/README.md | 2 +- examples/peripherals/adc/README.md | 2 +- examples/peripherals/adc2/README.md | 2 +- .../peripherals/i2c/i2c_self_test/README.md | 4 +- examples/peripherals/i2c/i2c_tools/README.md | 4 +- examples/peripherals/i2s/README.md | 2 +- examples/peripherals/i2s_adc_dac/README.md | 2 +- examples/peripherals/ledc/README.md | 2 +- examples/peripherals/pcnt/README.md | 2 +- examples/peripherals/rmt_nec_tx_rx/README.md | 2 +- examples/peripherals/rmt_tx/README.md | 2 +- .../uart/nmea0183_parser/README.md | 4 +- examples/protocols/README.md | 2 +- examples/protocols/asio/chat_client/README.md | 8 +-- examples/protocols/asio/chat_server/README.md | 6 +- .../protocols/asio/tcp_echo_server/README.md | 6 +- .../protocols/asio/udp_echo_server/README.md | 6 +- .../main/coap_client_example_main.c | 2 +- .../http_server/file_serving/README.md | 6 +- .../http_server/persistent_sockets/README.md | 6 +- .../http_server/restful_server/README.md | 4 +- .../protocols/http_server/simple/README.md | 6 +- examples/protocols/https_server/README.md | 2 +- examples/protocols/mdns/README.md | 6 +- .../protocols/mqtt/publish_test/README.md | 2 +- examples/protocols/mqtt/ssl/README.md | 2 +- .../protocols/mqtt/ssl_mutual_auth/README.md | 2 +- examples/protocols/mqtt/tcp/README.md | 2 +- examples/protocols/mqtt/ws/README.md | 2 +- examples/protocols/mqtt/wss/README.md | 2 +- examples/protocols/openssl_client/README.md | 2 +- .../main/openssl_client_example.h | 2 +- examples/protocols/openssl_server/README.md | 2 +- examples/protocols/pppos_client/README.md | 4 +- examples/protocols/sntp/README.md | 2 +- .../protocols/sockets/udp_multicast/README.md | 2 +- .../main/udp_multicast_example_main.c | 2 +- examples/storage/nvs_rw_blob/README.md | 14 +--- examples/storage/nvs_rw_value/README.md | 14 +--- examples/storage/sd_card/README.md | 14 +--- examples/storage/semihost_vfs/README.md | 14 +--- examples/storage/spiffs/README.md | 16 +---- examples/storage/spiffsgen/README.md | 8 +-- examples/storage/wear_levelling/README.md | 16 +---- examples/system/app_trace_to_host/README.md | 4 +- examples/system/cpp_exceptions/README.md | 12 ++-- examples/system/gcov/main/gcov_example.c | 4 +- examples/system/light_sleep/README.md | 8 +-- examples/system/ota/README.md | 8 +-- .../system/sysview_tracing_heap_log/README.md | 18 +----- examples/system/unit_test/README.md | 8 +-- .../softAP/main/softap_example_main.c | 2 +- .../station/main/station_example_main.c | 2 +- examples/wifi/scan/main/scan.c | 2 +- examples/wifi/simple_sniffer/README.md | 10 ++- .../main/wpa2_enterprise_main.c | 4 +- examples/wifi/wps/main/wps.c | 2 +- tools/esp_app_trace/test/sysview/blink.c | 4 +- tools/idf_monitor.py | 4 +- tools/unit-test-app/README.md | 20 +++--- 101 files changed, 300 insertions(+), 420 deletions(-) diff --git a/Kconfig b/Kconfig index e4c1a89b16..ad049f5dbf 100644 --- a/Kconfig +++ b/Kconfig @@ -46,11 +46,11 @@ mainmenu "Espressif IoT Development Framework Configuration" The executable name/path that is used to run python. On some systems Python 2.x may need to be invoked as python2. - (Note: This option is used with the GNU Make build system only, not idf.py - or CMake-based builds.) + (Note: This option is used with the legacy GNU Make build system only.) config SDK_MAKE_WARN_UNDEFINED_VARIABLES bool "'make' warns on undefined variables" + depends on !IDF_CMAKE default "y" help Adds --warn-undefined-variables to MAKEFLAGS. This causes make to @@ -60,6 +60,8 @@ mainmenu "Espressif IoT Development Framework Configuration" or otherwise missing, but it can be unwanted if you have Makefiles which depend on undefined variables expanding to an empty string. + (Note: this option is used with the legacy GNU Make build system only.) + endmenu # SDK tool configuration source "$COMPONENT_KCONFIGS_PROJBUILD" diff --git a/README.md b/README.md index bbb8d3a54b..19c9980dd2 100644 --- a/README.md +++ b/README.md @@ -33,9 +33,17 @@ To start your own project based on an example, copy the example project director See the Getting Started guide links above for a detailed setup guide. This is a quick reference for common commands when working with ESP-IDF projects: +## Setup Build Environment + +(See Getting Started guide for a full list of required steps with details.) + +* Install host build dependencies mentioned in Getting Started guide. +* Add `tools/` directory to the PATH +* Run `python -m pip install requirements.txt` to install Python dependencies + ## Configuring the Project -`make menuconfig` +`idf.py menuconfig` * Opens a text-based configuration menu for the project. * Use up & down arrow keys to navigate the menu. @@ -49,76 +57,48 @@ Once done configuring, press Escape multiple times to exit and say "Yes" to save ## Compiling the Project -`make -j4 all` +`idf.py build` ... will compile app, bootloader and generate a partition table based on the config. -NOTE: The `-j4` option causes `make` to run 4 parallel jobs. This is much faster than the default single job. The recommended number to pass to this option is `-j(number of CPUs + 1)`. - ## Flashing the Project When the build finishes, it will print a command line to use esptool.py to flash the chip. However you can also do this automatically by running: -`make -j4 flash` +`idf.py -p PORT flash` -This will flash the entire project (app, bootloader and partition table) to a new chip. The settings for serial port flashing can be configured with `make menuconfig`. +Replace PORT with the name of your serial port (like `COM3` on Windows, `/dev/ttyUSB0` on Linux, or `/dev/cu.usbserial-X` on MacOS. If the `-p` option is left out, `idf.py flash` will try to flash the first available serial port. -You don't need to run `make all` before running `make flash`, `make flash` will automatically rebuild anything which needs it. +This will flash the entire project (app, bootloader and partition table) to a new chip. The settings for serial port flashing can be configured with `idf.py menuconfig`. + +You don't need to run `idf.py build` before running `idf.py flash`, `idf.py flash` will automatically rebuild anything which needs it. ## Viewing Serial Output -The `make monitor` target uses the [idf_monitor tool](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/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](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/idf-monitor.html). +The `idf.py monitor` target uses the [idf_monitor tool](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/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](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/idf-monitor.html). Exit the monitor by typing Ctrl-]. To build, flash and monitor output in one pass, you can run: -`make -j4 flash monitor` +`idf.py flash monitor` ## Compiling & Flashing Only the App After the initial flash, you may just want to build and flash just your app, not the bootloader and partition table: -* `make app` - build just the app. -* `make app-flash` - flash just the app. +* `idf.py app` - build just the app. +* `idf.py app-flash` - flash just the app. -`make app-flash` will automatically rebuild the app if any source files have changed. +`idf.py app-flash` will automatically rebuild the app if any source files have changed. (In normal development there's no downside to reflashing the bootloader and partition table each time, if they haven't changed.) -## Parallel Builds - -ESP-IDF supports compiling multiple files in parallel, so all of the above commands can be run as `make -jN` where `N` is the number of parallel make processes to run (generally N should be equal to the number of CPU cores in your system, plus one.) - -Multiple make functions can be combined into one. For example: to build the app & bootloader using 5 jobs in parallel, then flash everything, and then display serial output from the ESP32 run: - -``` -make -j5 flash monitor -``` - - -## The Partition Table - -Once you've compiled your project, the "build" directory will contain a binary file with a name like "my_app.bin". This is an ESP32 image binary that can be loaded by the bootloader. - -A single ESP32's flash can contain multiple apps, as well as many different kinds of data (calibration data, filesystems, parameter storage, etc). For this reason a partition table is flashed to offset 0x8000 in the flash. - -Each entry in the partition table has a name (label), type (app, data, or something else), subtype and the offset in flash where the partition is loaded. - -The simplest way to use the partition table is to `make menuconfig` and choose one of the simple predefined partition tables: - -* "Single factory app, no OTA" -* "Factory app, two OTA definitions" - -In both cases the factory app is flashed at offset 0x10000. If you `make partition_table` then it will print a summary of the partition table. - -For more details about partition tables and how to create custom variations, view the [`docs/en/api-guides/partition-tables.rst`](docs/en/api-guides/partition-tables.rst) file. - ## Erasing Flash -The `make flash` target does not erase the entire flash contents. However it is sometimes useful to set the device back to a totally erased state, particularly when making partition table changes or OTA app updates. To erase the entire flash, run `make erase_flash`. +The `idf.py flash` target does not erase the entire flash contents. However it is sometimes useful to set the device back to a totally erased state, particularly when making partition table changes or OTA app updates. To erase the entire flash, run `idf.py erase_flash`. -This can be combined with other targets, ie `make erase_flash flash` will erase everything and then re-flash the new app, bootloader and partition table. +This can be combined with other targets, ie `idf.py -p PORT erase_flash flash` will erase everything and then re-flash the new app, bootloader and partition table. # Resources diff --git a/components/esptool_py/Kconfig.projbuild b/components/esptool_py/Kconfig.projbuild index 95919bd007..e11f9c7d50 100644 --- a/components/esptool_py/Kconfig.projbuild +++ b/components/esptool_py/Kconfig.projbuild @@ -135,8 +135,9 @@ menu "Serial flasher config" bool "Detect flash size when flashing bootloader" default y help - If this option is set, 'make flash' targets will automatically detect - the flash size and update the bootloader image when flashing. + If this option is set, flashing the project will automatically detect + the flash size of the target chip and update the bootloader image + before it is flashed. choice ESPTOOLPY_BEFORE prompt "Before flashing" @@ -181,11 +182,11 @@ menu "Serial flasher config" default "no_reset" if ESPTOOLPY_AFTER_NORESET choice ESPTOOLPY_MONITOR_BAUD - prompt "'make monitor' baud rate" + prompt "'idf.py monitor' baud rate" default ESPTOOLPY_MONITOR_BAUD_115200B help - Baud rate to use when running 'make monitor' to view serial output - from a running chip. + Baud rate to use when running 'idf.py monitor' or 'make monitor' + to view serial output from a running chip. Can override by setting the MONITORBAUD environment variable. diff --git a/components/nvs_flash/README.rst b/components/nvs_flash/README.rst index f8c2f4a1f6..4638b644bc 100644 --- a/components/nvs_flash/README.rst +++ b/components/nvs_flash/README.rst @@ -14,7 +14,7 @@ Currently, NVS uses a portion of main flash memory through ``spi_flash_{read|wri Future versions of this library may have other storage backends to keep data in another flash chip (SPI or I2C), RTC, FRAM, etc. -.. note:: if an NVS partition is truncated (for example, when the partition table layout is changed), its contents should be erased. ESP-IDF build system provides a ``make erase_flash`` target to erase all contents of the flash chip. +.. note:: if an NVS partition is truncated (for example, when the partition table layout is changed), its contents should be erased. ESP-IDF build system provides a ``idf.py erase_flash`` target to erase all contents of the flash chip. .. note:: NVS works best for storing many small values, rather than a few large values of the type 'string' and 'blob'. If you need to store large blobs or strings, consider using the facilities provided by the FAT filesystem on top of the wear levelling library. diff --git a/components/spi_flash/README.rst b/components/spi_flash/README.rst index 782dfbba96..f9c7ecaa09 100644 --- a/components/spi_flash/README.rst +++ b/components/spi_flash/README.rst @@ -73,7 +73,7 @@ SPI Flash Size The SPI flash size is configured by writing a field in the software bootloader image header, flashed at offset 0x1000. -By default, the SPI flash size is detected by esptool.py when this bootloader is written to flash, and the header is updated with the correct size. Alternatively, it is possible to generate a fixed flash size by setting :envvar:`CONFIG_ESPTOOLPY_FLASHSIZE` in ``make menuconfig``. +By default, the SPI flash size is detected by esptool.py when this bootloader is written to flash, and the header is updated with the correct size. Alternatively, it is possible to generate a fixed flash size by setting :envvar:`CONFIG_ESPTOOLPY_FLASHSIZE` in project configuration. If it is necessary to override the configured flash size at runtime, it is possible to set the ``chip_size`` member of the ``g_rom_flashchip`` structure. This size is used by ``esp_flash_*`` functions (in both software & ROM) to check the bounds. diff --git a/components/spi_flash/README_legacy.rst b/components/spi_flash/README_legacy.rst index a8e5da15a6..a9a2c69135 100644 --- a/components/spi_flash/README_legacy.rst +++ b/components/spi_flash/README_legacy.rst @@ -29,7 +29,7 @@ SPI Flash Size The SPI flash size is configured by writing a field in the software bootloader image header, flashed at offset 0x1000. -By default, the SPI flash size is detected by esptool.py when this bootloader is written to flash, and the header is updated with the correct size. Alternatively, it is possible to generate a fixed flash size by setting :envvar:`CONFIG_ESPTOOLPY_FLASHSIZE` in ``make menuconfig``. +By default, the SPI flash size is detected by esptool.py when this bootloader is written to flash, and the header is updated with the correct size. Alternatively, it is possible to generate a fixed flash size by setting :envvar:`CONFIG_ESPTOOLPY_FLASHSIZE` in project configuration. If it is necessary to override the configured flash size at runtime, it is possible to set the ``chip_size`` member of the ``g_rom_flashchip`` structure. This size is used by ``spi_flash_*`` functions (in both software & ROM) to check the bounds. diff --git a/docs/TEMPLATE_EXAMPLE_README.md b/docs/TEMPLATE_EXAMPLE_README.md index 81bf6b3421..c641f8d64d 100644 --- a/docs/TEMPLATE_EXAMPLE_README.md +++ b/docs/TEMPLATE_EXAMPLE_README.md @@ -23,21 +23,21 @@ _If any other items (server, BLE device, app, second chip, whatever) are needed, ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` -* Set serial port under Serial Flasher Options. - -* _If there is any menuconfig configuration that the user user must set for this example, mention this here._ +* _If there is any project configuration that the user must set for this example, mention this here._ ### Build and Flash Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` +(Replace PORT with the name of the serial port to use.) + (To exit the serial monitor, type ``Ctrl-]``.) See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. diff --git a/docs/en/api-guides/console.rst b/docs/en/api-guides/console.rst index 5119d3ae2f..3f10279db8 100644 --- a/docs/en/api-guides/console.rst +++ b/docs/en/api-guides/console.rst @@ -16,7 +16,7 @@ Line editing Line editing feature lets users compose commands by typing them, erasing symbols using 'backspace' key, navigating within the command using left/right keys, navigating to previously typed commands using up/down keys, and performing autocompletion using 'tab' key. -.. note:: This feature relies on ANSI escape sequence support in the terminal application. As such, serial monitors which display raw UART data can not be used together with the line editing library. If you see ``[6n`` or similar escape sequence when running get_started/console example instead of a command prompt (``[esp32]>``), it means that the serial monitor does not support escape sequences. Programs which are known to work are GNU screen, minicom, and idf_monitor.py (which can be invoked using ``make monitor`` from project directory). +.. note:: This feature relies on ANSI escape sequence support in the terminal application. As such, serial monitors which display raw UART data can not be used together with the line editing library. If you see ``[6n`` or similar escape sequence when running get_started/console example instead of a command prompt (``[esp32]>``), it means that the serial monitor does not support escape sequences. Programs which are known to work are GNU screen, minicom, and idf_monitor.py (which can be invoked using ``idf.py monitor`` from project directory). Here is an overview of functions provided by `linenoise`_ library. diff --git a/docs/en/api-guides/core_dump.rst b/docs/en/api-guides/core_dump.rst index 536d999efb..c590efeea7 100644 --- a/docs/en/api-guides/core_dump.rst +++ b/docs/en/api-guides/core_dump.rst @@ -16,7 +16,7 @@ ESP-IDF provides special script `espcoredump.py` to help users to retrieve and a Configuration ------------- -There are a number of core dump related configuration options which user can choose in configuration menu of the application (`make menuconfig`). +There are a number of core dump related configuration options which user can choose in project configuration menu (`idf.py menuconfig`). 1. Core dump data destination (`Components -> ESP32-specific config -> Core dump -> Data destination`): @@ -93,7 +93,7 @@ Generic command syntax: * --gdb,-g GDB. Path to gdb to use for data retrieval. * --core,-c CORE. Path to core dump file to use (if skipped core dump will be read from flash). * --core-format,-t CORE_FORMAT. Specifies that file passed with "-c" is an ELF ("elf"), dumped raw binary ("raw") or base64-encoded ("b64") format. - * --off,-o OFF. Offset of coredump partition in flash (type `make partition_table` to see it). + * --off,-o OFF. Offset of coredump partition in flash (type `idf.py partition_table` to see it). * --save-core,-s SAVE_CORE. Save core to file. Othwerwise temporary core file will be deleted. Ignored with "-c". * --rom-elf,-r ROM_ELF. Path to ROM ELF file to use (if skipped "esp32_rom.elf" is used). * --print-mem,-m Print memory dump. Used only with "info_corefile". diff --git a/docs/en/api-guides/freertos-smp.rst b/docs/en/api-guides/freertos-smp.rst index ac3a49ec84..558f43ecde 100644 --- a/docs/en/api-guides/freertos-smp.rst +++ b/docs/en/api-guides/freertos-smp.rst @@ -74,8 +74,9 @@ used to free memory pointed to by TLSP. Call Callbacks. :ref:`esp-idf-freertos-configuration`: Several aspects of ESP-IDF FreeRTOS can be -configured using ``make meunconfig`` such as running ESP-IDF in Unicore Mode, -or configuring the number of Thread Local Storage Pointers each task will have. +set in the project configuration (``idf.py menuconfig``) such as running ESP-IDF in +Unicore (single core) Mode, or configuring the number of Thread Local Storage Pointers +each task will have. .. _backported-features: @@ -478,10 +479,10 @@ For more details see :doc:`FreeRTOS API reference<../api-reference/system/freert Configuring ESP-IDF FreeRTOS ---------------------------- -The ESP-IDF FreeRTOS can be configured using ``make menuconfig`` under -``Component_Config/FreeRTOS``. The following section highlights some of the -ESP-IDF FreeRTOS configuration options. For a full list of ESP-IDF -FreeRTOS configurations, see :doc:`FreeRTOS <../api-reference/kconfig>` +The ESP-IDF FreeRTOS can be configured in the project configuration menu +(``idf.py menuconfig``) under ``Component Config/FreeRTOS``. The following section +highlights some of the ESP-IDF FreeRTOS configuration options. For a full list of +ESP-IDF FreeRTOS configurations, see :doc:`FreeRTOS <../api-reference/kconfig>` :ref:`CONFIG_FREERTOS_UNICORE` will run ESP-IDF FreeRTOS only on **PRO_CPU**. Note that this is **not equivalent to running vanilla diff --git a/docs/en/api-guides/partition-tables.rst b/docs/en/api-guides/partition-tables.rst index ecf2367925..91fe17e0e3 100644 --- a/docs/en/api-guides/partition-tables.rst +++ b/docs/en/api-guides/partition-tables.rst @@ -11,12 +11,12 @@ Partition table length is 0xC00 bytes (maximum 95 partition table entries). An M Each entry in the partition table has a name (label), type (app, data, or something else), subtype and the offset in flash where the partition is loaded. -The simplest way to use the partition table is to `make menuconfig` and choose one of the simple predefined partition tables: +The simplest way to use the partition table is to open the project configuration menu (``idf.py menuconfig``) and choose one of the simple predefined partition tables under :ref:`CONFIG_PARTITION_TABLE_TYPE`: * "Single factory app, no OTA" * "Factory app, two OTA definitions" -In both cases the factory app is flashed at offset 0x10000. If you `make partition_table` then it will print a summary of the partition table. +In both cases the factory app is flashed at offset 0x10000. If you execute `idf.py partition_table` then it will print a summary of the partition table. Built-in Partition Tables ------------------------- @@ -100,7 +100,7 @@ The 8-bit subtype field is specific to a given partition type. esp-idf currently - phy (1) is for storing PHY initialisation data. This allows PHY to be configured per-device, instead of in firmware. - In the default configuration, the phy partition is not used and PHY initialisation data is compiled into the app itself. As such, this partition can be removed from the partition table to save space. - - To load PHY data from this partition, run ``make menuconfig`` and enable :ref:`CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION` option. You will also need to flash your devices with phy init data as the esp-idf build system does not do this automatically. + - To load PHY data from this partition, open the project configuration menu (``idf.py menuconfig``) and enable :ref:`CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION` option. You will also need to flash your devices with phy init data as the esp-idf build system does not do this automatically. - nvs (2) is for the :doc:`Non-Volatile Storage (NVS) API <../api-reference/storage/nvs_flash>`. - NVS is used to store per-device PHY calibration data (different to initialisation data). @@ -138,7 +138,7 @@ Generating Binary Partition Table The partition table which is flashed to the ESP32 is in a binary format, not CSV. The tool :component_file:`partition_table/gen_esp32part.py` is used to convert between CSV and binary formats. -If you configure the partition table CSV name in ``make menuconfig`` and then ``make partition_table``, this conversion is done as part of the build process. +If you configure the partition table CSV name in the project configuration (``idf.py menuconfig``) and then build the project or run ``idf.py partition_table``, this conversion is done as part of the build process. To convert CSV to Binary manually:: @@ -148,7 +148,7 @@ To convert binary format back to CSV manually:: python gen_esp32part.py binary_partitions.bin input_partitions.csv -To display the contents of a binary partition table on stdout (this is how the summaries displayed when running `make partition_table` are generated:: +To display the contents of a binary partition table on stdout (this is how the summaries displayed when running ``idf.py partition_table`` are generated:: python gen_esp32part.py binary_partitions.bin @@ -162,12 +162,12 @@ The MD5 checksum generation can be disabled by the ``--disable-md5sum`` option o Flashing the partition table ---------------------------- -* ``make partition_table-flash``: will flash the partition table with esptool.py. -* ``make flash``: Will flash everything including the partition table. +* ``idf.py partition_table-flash``: will flash the partition table with esptool.py. +* ``idf.py flash``: Will flash everything including the partition table. -A manual flashing command is also printed as part of ``make partition_table``. +A manual flashing command is also printed as part of ``idf.py partition_table`` output. -Note that updating the partition table doesn't erase data that may have been stored according to the old partition table. You can use ``make erase_flash`` (or ``esptool.py erase_flash``) to erase the entire flash contents. +Note that updating the partition table doesn't erase data that may have been stored according to the old partition table. You can use ``idf.py erase_flash`` (or ``esptool.py erase_flash``) to erase the entire flash contents. Partition Tool (parttool.py) ---------------------------- diff --git a/docs/en/api-guides/tools/idf-monitor.rst b/docs/en/api-guides/tools/idf-monitor.rst index 88e89d8f22..cf5bd285ff 100644 --- a/docs/en/api-guides/tools/idf-monitor.rst +++ b/docs/en/api-guides/tools/idf-monitor.rst @@ -6,11 +6,9 @@ IDF Monitor The IDF monitor tool is mainly a serial terminal program which relays serial data to and from the target device's serial port. It also provides some IDF-specific features. -This tool can be launched by invoking in IDF the following target: - -- **For make**: ``make monitor`` -- **For cmake**: ``idf.py monitor`` +This tool can be launched from an IDF project by running ``idf.py monitor``. +(For the legacy GNU Make system, run ``make monitor``.) Keyboard Shortcuts ================== @@ -32,7 +30,7 @@ For easy interaction with IDF Monitor, use the keyboard shortcuts given in the t +-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | - Ctrl+R | Reset target board via RTS | Resets the target board and re-starts the application via the RTS line (if connected). | +-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| - Ctrl+F | Build and flash the project | Pauses idf_monitor to run the ``make flash`` (``idf.py flash``) target, then resumes idf_monitor. Any changed source files are recompiled and then re-flashed. | +| - Ctrl+F | Build and flash the project | Pauses idf_monitor to run the project ``flash`` target, then resumes idf_monitor. Any changed source files are recompiled and then re-flashed. | +-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | - Ctrl+A (or A) | Build and flash the app only | Pauses idf_monitor to run the ``app-flash`` target, then resumes idf_monitor. Similar to the ``flash`` target, but only the main app is built and re-flashed. | +-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -103,7 +101,7 @@ By default, if esp-idf crashes, the panic handler prints relevant registers and Optionally, the panic handler can be configured to run GDBStub, the tool which can communicate with GDB_ project debugger. GDBStub allows to read memory, examine call stack frames and variables, etc. It is not as versatile as JTAG debugging, but this method does not require any special hardware. -To enable GDBStub, run ``make menuconfig`` (for make) or ``idf.py menuconfig`` (for cmake) and set :ref:`CONFIG_ESP32_PANIC` to ``Invoke GDBStub``. +To enable GDBStub, open the project configuration menu (``idf.py menuconfig``) and set :ref:`CONFIG_ESP32_PANIC` to ``Invoke GDBStub``. In this case, if the panic handler is triggered, as soon as IDF Monitor sees that GDBStub has loaded, it automatically pauses serial monitoring and runs GDB with necessary arguments. After GDB exits, the board is reset via the RTS serial line. If this line is not connected, please reset the board manually by pressing its Reset button. @@ -115,7 +113,7 @@ In the background, IDF Monitor runs the following command:: Output Filtering ~~~~~~~~~~~~~~~~ -IDF monitor can be invoked as ``make monitor PRINT_FILTER=""`` (for make) or ``idf.py monitor --print-filter=""`` (for cmake), where ``PRINT_FILTER`` is the parameter for output filtering. The default value is an empty string, which means that everything is printed. +IDF monitor can be invoked as ``idf.py monitor --print-filter="xyz"``, where ``--print-filter`` is the parameter for output filtering. The default value is an empty string, which means that everything is printed. Restrictions on what to print can be specified as a series of ``:`` items where ```` is the tag string and ```` is a character from the set ``{N, E, W, I, D, V, *}`` referring to a level for :doc:`logging <../../api-reference/system/log>`. @@ -188,18 +186,6 @@ The captured output for the filtering options ``PRINT_FILTER="wifi esp_image:E l D (309) light_driver: [light_init, 74]:status: 1, mode: 2 -Simple Monitor -============== - -The earlier versions of ESP-IDF used the pySerial_ command line program miniterm_ as a serial console program. - -.. note:: This target only works in a build system based on GNU Make and cannot work in a CMake-based system. - -This program can still be run with the command ``make simple_monitor``. - -IDF Monitor is based on miniterm and shares the same basic keyboard shortcuts. - - Known Issues with IDF Monitor ============================= diff --git a/docs/en/api-guides/ulp.rst b/docs/en/api-guides/ulp.rst index e59c3cc751..8eee8cffd9 100644 --- a/docs/en/api-guides/ulp.rst +++ b/docs/en/api-guides/ulp.rst @@ -50,7 +50,7 @@ To compile ULP code as part of a component, the following steps must be taken: include $(IDF_PATH)/components/ulp/component_ulp_common.mk Includes common definitions of ULP build steps. Defines build targets for ULP object files, ELF file, binary file, etc. -3. Build the application as usual (e.g. `make app`) +3. Build the application as usual (e.g. ``idf.py build`` or ``idf.py app``) Inside, the build system will take the following steps to build ULP program: diff --git a/docs/en/api-reference/kconfig.rst b/docs/en/api-reference/kconfig.rst index a98de1e605..4fc49900b4 100644 --- a/docs/en/api-reference/kconfig.rst +++ b/docs/en/api-reference/kconfig.rst @@ -1,19 +1,28 @@ -Configuration Options +Project Configuration ********************* Introduction ============ -ESP-IDF uses Kconfig_ system to provide a compile-time configuration mechanism. Kconfig is based around options of several types: integer, string, boolean. Kconfig files specify dependencies between options, default values of the options, the way the options are grouped together, etc. +ESP-IDF uses Kconfig_ system to provide a compile-time project configuration mechanism. Kconfig is based around options of several types: integer, string, boolean. Kconfig files specify dependencies between options, default values of the options, the way the options are grouped together, etc. -Applications developers can use ``make menuconfig`` build target to edit components' configuration. This configuration is saved inside ``sdkconfig`` file in the project root directory. Based on ``sdkconfig``, application build targets will generate ``sdkconfig.h`` file in the build directory, and will make sdkconfig options available to component makefiles. +.. _project-configuration-menu: + +Project Configuration Menu +========================== + +Application developers can open a terminal-based project configuration menu with the ``idf.py menuconfig`` build target. + +After being updated, this configuration is saved inside ``sdkconfig`` file in the project root directory. Based on ``sdkconfig``, application build targets will generate ``sdkconfig.h`` file in the build directory, and will make sdkconfig options available to the project build system and source files. + +(For the legacy GNU Make build system, the project configuration menu is opened with ``make menuconfig``.) Using sdkconfig.defaults ======================== When updating ESP-IDF version, it is not uncommon to find that new Kconfig options are introduced. When this happens, application build targets will offer an interactive prompt to select values for the new options. New values are then written into ``sdkconfig`` file. To supress interactive prompts, applications can either define ``BATCH_BUILD`` environment variable, which will cause all prompts to be suppressed. This is the same effect as that of ``V`` or ``VERBOSE`` variables. Alternatively, ``defconfig`` build target can be used to update configuration for all new variables to the default values. -In some cases, such as when ``sdkconfig`` file is under revision control, the fact that ``sdkconfig`` file gets changed by the build system may be inconvenient. The build system offers a way to avoid this, in the form of ``sdkconfig.defaults`` file. This file is never touched by the build system, and must be created manually. It can contain all the options which matter for the given application. The format is the same as that of the ``sdkconfig`` file. Once ``sdkconfig.defaults`` is created, ``sdkconfig`` can be deleted and added to the ignore list of the revision control system (e.g. ``.gitignore`` file for git). Project build targets will automatically create ``sdkconfig`` file, populated with the settings from ``sdkconfig.defaults`` file, and the rest of the settings will be set to their default values. Note that when ``make defconfig`` is used, settings in sdkconfig will be overriden by the ones in ``sdkconfig.defaults``. For more information, see :ref:`custom-sdkconfig-defaults`. +In some cases, such as when ``sdkconfig`` file is under revision control, the fact that ``sdkconfig`` file gets changed by the build system may be inconvenient. The build system offers a way to avoid this, in the form of ``sdkconfig.defaults`` file. This file is never touched by the build system, and must be created manually. It can contain all the options which matter for the given application. The format is the same as that of the ``sdkconfig`` file. Once ``sdkconfig.defaults`` is created, ``sdkconfig`` can be deleted and added to the ignore list of the revision control system (e.g. ``.gitignore`` file for git). Project build targets will automatically create ``sdkconfig`` file, populated with the settings from ``sdkconfig.defaults`` file, and the rest of the settings will be set to their default values. Note that when ``idf.py defconfig`` is used, settings in sdkconfig will be overriden by the ones in ``sdkconfig.defaults``. For more information, see :ref:`custom-sdkconfig-defaults`. Kconfig Formatting Rules ======================== diff --git a/docs/en/api-reference/protocols/mqtt.rst b/docs/en/api-reference/protocols/mqtt.rst index 053159eba0..cb956755a6 100644 --- a/docs/en/api-reference/protocols/mqtt.rst +++ b/docs/en/api-reference/protocols/mqtt.rst @@ -94,12 +94,12 @@ SSL For more options on ``esp_mqtt_client_config_t``, please refer to API reference below -Change settings in ``menuconfig`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Change settings in Project Configuration Menu +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: - make menuconfig - -> Component config -> ESP-MQTT Configuration + idf.py menuconfig + -> Component config -> ESP-MQTT Configuration - :ref:`CONFIG_MQTT_PROTOCOL_311`: Enables 3.1.1 version of MQTT protocol diff --git a/docs/en/api-reference/system/efuse.rst b/docs/en/api-reference/system/efuse.rst index dd8c6bd993..87a9e1624d 100644 --- a/docs/en/api-reference/system/efuse.rst +++ b/docs/en/api-reference/system/efuse.rst @@ -31,8 +31,8 @@ The component has API functions for reading and writing fields. Access to the fi CSV files: -* common (`esp_efuse_table.csv`) - contains eFuse fields which are used inside the IDF. C-source generation should be done manually when changing this file (run command 'make efuse_common_table' or `idf.py efuse_common_table`). Note that changes in this file can lead to incorrect operation. -* custom - (optional and can be enabled by :envvar:`CONFIG_EFUSE_CUSTOM_TABLE`) contains eFuse fields that are used by the user in their application. C-source generation should be done manually when changing this file (run command 'make efuse_custom_table' or `idf.py efuse_custom_table`). +* common (`esp_efuse_table.csv`) - contains eFuse fields which are used inside the IDF. C-source generation should be done manually when changing this file (run command ``idf.py efuse_common_table``). Note that changes in this file can lead to incorrect operation. +* custom - (optional and can be enabled by :envvar:`CONFIG_EFUSE_CUSTOM_TABLE`) contains eFuse fields that are used by the user in their application. C-source generation should be done manually when changing this file and running ``idf.py efuse_custom_table``. Description CSV file @@ -84,7 +84,7 @@ efuse_table_gen.py tool The tool is designed to generate C-source files from CSV file and validate fields. First of all, the check is carried out on the uniqueness of the names and overlaps of the field bits. If an additional `custom` file is used, it will be checked with the existing `common` file (esp_efuse_table.csv). In case of errors, a message will be displayed and the string that caused the error. C-source files contain structures of type `esp_efuse_desc_t`. -To generate a `common` files, use the following command 'make efuse_common_table' or `idf.py efuse_common_table` or: +To generate a `common` files, use the following command ``idf.py efuse_common_table`` or: :: @@ -96,7 +96,7 @@ After generation in the folder `esp32` create: * `esp_efuse_table.c` file. * In `include` folder `esp_efuse_table.c` file. -To generate a `custom` files, use the following command 'make efuse_custom_table' or `idf.py efuse_custom_table` or: +To generate a `custom` files, use the following command ``idf.py efuse_custom_table`` or: :: @@ -170,7 +170,7 @@ For frequently used fields, special functions are made, like this :cpp:func:`esp How add a new field ------------------- -1. Find a free bits for field. Show `esp_efuse_table.csv` file or run ``make show_efuse_table`` or ``idf.py show_efuse_table`` or the next command: +1. Find a free bits for field. Show `esp_efuse_table.csv` file or run ``idf.py show_efuse_table`` or the next command: :: diff --git a/docs/en/api-reference/system/freertos_additions.rst b/docs/en/api-reference/system/freertos_additions.rst index 337bf3bb26..24c9cb25ea 100644 --- a/docs/en/api-reference/system/freertos_additions.rst +++ b/docs/en/api-reference/system/freertos_additions.rst @@ -420,7 +420,7 @@ Interrupt respectively. Vanilla FreeRTOS hooks are referred to as **Legacy Hooks** in ESP-IDF FreeRTOS. To enable legacy hooks, :ref:`CONFIG_FREERTOS_LEGACY_HOOKS` should be enabled -in ``make menuconfig``. +in :doc:`project configuration menu `. Due to vanilla FreeRTOS being designed for single core, ``vApplicationIdleHook()`` and ``vApplicationTickHook()`` can only be defined once. However, the ESP32 is dual core diff --git a/docs/en/api-reference/system/heap_debug.rst b/docs/en/api-reference/system/heap_debug.rst index 2f03907060..51caff1ba3 100644 --- a/docs/en/api-reference/system/heap_debug.rst +++ b/docs/en/api-reference/system/heap_debug.rst @@ -38,7 +38,7 @@ Heap corruption detection allows you to detect various types of heap memory erro Assertions ^^^^^^^^^^ -The heap implementation (``multi_heap.c``, etc.) includes a lot of assertions which will fail if the heap memory is corrupted. To detect heap corruption most effectively, ensure that assertions are enabled in ``make menuconfig`` under ``Compiler options``. +The heap implementation (``multi_heap.c``, etc.) includes a lot of assertions which will fail if the heap memory is corrupted. To detect heap corruption most effectively, ensure that assertions are enabled in the project configuration menu under ``Compiler options`` -> :ref:`CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL`. If a heap integrity assertion fails, a line will be printed like ``CORRUPT HEAP: multi_heap.c:225 detected at 0x3ffbb71c``. The memory address which is printed is the address of the heap structure which has corrupt content. @@ -62,7 +62,7 @@ Configuration Temporarily increasing the heap corruption detection level can give more detailed information about heap corruption errors. -In ``make menuconfig``, under ``Component config`` there is a menu ``Heap memory debugging``. The setting :ref:`CONFIG_HEAP_CORRUPTION_DETECTION` can be set to one of three levels: +In the project configuration menu, under ``Component config`` there is a menu ``Heap memory debugging``. The setting :ref:`CONFIG_HEAP_CORRUPTION_DETECTION` can be set to one of three levels: Basic (no poisoning) ++++++++++++++++++++ @@ -143,7 +143,7 @@ Standalone Mode Once you've identified the code which you think is leaking: -- Under ``make menuconfig``, navigate to ``Component settings`` -> ``Heap Memory Debugging`` -> ``Heap tracing`` and select ``Standalone`` option (see :ref:`CONFIG_HEAP_TRACING_DEST`). +- In the project configuration menu, navigate to ``Component settings`` -> ``Heap Memory Debugging`` -> ``Heap tracing`` and select ``Standalone`` option (see :ref:`CONFIG_HEAP_TRACING_DEST`). - Call the function :cpp:func:`heap_trace_init_standalone` early in the program, to register a buffer which can be used to record the memory trace. - Call the function :cpp:func:`heap_trace_start` to begin recording all mallocs/frees in the system. Call this immediately before the piece of code which you suspect is leaking memory. - Call the function :cpp:func:`heap_trace_stop` to stop the trace once the suspect piece of code has finished executing. @@ -205,7 +205,7 @@ In ``HEAP_TRACE_LEAKS`` mode, for each traced memory allocation which has not al - ``caller 0x...`` gives the call stack of the call to malloc()/free(), as a list of PC addresses. These can be decoded to source files and line numbers, as shown above. -The depth of the call stack recorded for each trace entry can be configured in ``make menuconfig``, under ``Heap Memory Debugging`` -> ``Enable heap tracing`` -> ``Heap tracing stack depth``. Up to 10 stack frames can be recorded for each allocation (the default is 2). Each additional stack frame increases the memory usage of each ``heap_trace_record_t`` record by eight bytes. +The depth of the call stack recorded for each trace entry can be configured in the project configuration menu, under ``Heap Memory Debugging`` -> ``Enable heap tracing`` -> ``Heap tracing stack depth``. Up to 10 stack frames can be recorded for each allocation (the default is 2). Each additional stack frame increases the memory usage of each ``heap_trace_record_t`` record by eight bytes. Finally, the total number of 'leaked' bytes (bytes allocated but not freed while trace was running) is printed, and the total number of allocations this represents. @@ -217,9 +217,9 @@ Host-Based Mode Once you've identified the code which you think is leaking: -- Under ``make menuconfig``, navigate to ``Component settings`` -> ``Heap Memory Debugging`` -> ``Heap tracing`` and select ``Host-Based`` option (see :ref:`CONFIG_HEAP_TRACING_DEST`). -- Under ``make menuconfig``, navigate to ``Component settings`` -> ``Application Level Tracing`` -> ``Data Destination`` and select ``Trace memory``. -- Under ``make menuconfig``, navigate to ``Component settings`` -> ``Application Level Tracing`` -> ``FreeRTOS SystemView Tracing`` and check ``SystemView Tracing Enable``. +- In the project configuration menu, navigate to ``Component settings`` -> ``Heap Memory Debugging`` -> :ref:`CONFIG_HEAP_TRACING_DEST` and select ``Host-Based``. +- In the project configuration menu, navigate to ``Component settings`` -> ``Application Level Tracing`` -> :ref:`CONFIG_ESP32_APPTRACE_DESTINATION` and select ``Trace memory``. +- In the project configuration menu, navigate to ``Component settings`` -> ``Application Level Tracing`` -> ``FreeRTOS SystemView Tracing`` and enable :ref:`CONFIG_SYSVIEW_ENABLE`. - Call the function :cpp:func:`heap_trace_init_tohost` early in the program, to initialize JTAG heap tracing module. - Call the function :cpp:func:`heap_trace_start` to begin recording all mallocs/frees in the system. Call this immediately before the piece of code which you suspect is leaking memory. In host-based mode argument to this function is ignored and heap tracing module behaves like ``HEAP_TRACE_ALL`` was passed: all allocations and deallocations are sent to the host. diff --git a/docs/en/api-reference/system/mem_alloc.rst b/docs/en/api-reference/system/mem_alloc.rst index 7114225405..cf6eb5020d 100644 --- a/docs/en/api-reference/system/mem_alloc.rst +++ b/docs/en/api-reference/system/mem_alloc.rst @@ -41,7 +41,7 @@ DRAM At startup, the DRAM heap contains all data memory which is not statically allocated by the app. Reducing statically allocated buffers will increase the amount of available free heap. -To find the amount of statically allocated memory, use the :ref:`make size ` or :ref:`idf.py size ` (for CMake) command. +To find the amount of statically allocated memory, use the :ref:`idf.py size ` command. .. note:: Due to a technical limitation, the maximum statically allocated DRAM usage is 160KB. The remaining 160KB (for a total of 320KB of DRAM) can only be allocated at runtime as heap. @@ -52,7 +52,7 @@ IRAM At startup, the IRAM heap contains all instruction memory which is not used by the app executable code. -The :ref:`make size ` and :ref:`idf.py size ` commands can be used to find the amount of IRAM used by the app. +The :ref:`idf.py size ` command can be used to find the amount of IRAM used by the app. D/IRAM ^^^^^^ diff --git a/docs/en/api-reference/system/system.rst b/docs/en/api-reference/system/system.rst index 184e38c68c..4d72c587fe 100644 --- a/docs/en/api-reference/system/system.rst +++ b/docs/en/api-reference/system/system.rst @@ -129,12 +129,13 @@ App version Application version is stored in :cpp:class:`esp_app_desc_t` structure. It is located in DROM sector and has a fixed offset from the beginning of the binary file. The structure is located after :cpp:class:`esp_image_header_t` and :cpp:class:`esp_image_segment_header_t` structures. The field version has string type and max length 32 chars. -To set version in your project manually you need to set ``PROJECT_VER`` variable in your project Makefile/CMakeLists.txt: +To set version in your project manually you need to set ``PROJECT_VER`` variable in your project CMakeLists.txt/Makefile: -* For Make build system: in application Makefile put ``PROJECT_VER = "0.1.0.1"`` before including project.mk -* For Cmake build system: in application CMakeLists.txt put ``set(PROJECT_VER "0.1.0.1")`` before including project.cmake. +* In application CMakeLists.txt put ``set(PROJECT_VER "0.1.0.1")`` before including ``project.cmake``. -If ``PROJECT_VER`` variable is not set in project Makefile/CMakeLists.txt then it will be retrieved from either ``$(PROJECT_PATH)/version.txt`` file (if present) else using git command ``git describe``. If neither is available then ``PROJECT_VER`` will be set to "1". Application can make use of this by calling :cpp:func:`esp_ota_get_app_description` or :cpp:func:`esp_ota_get_partition_description` functions. +(For legacy GNU Make build system: in application Makefile put ``PROJECT_VER = "0.1.0.1"`` before including ``project.mk``.) + +If ``PROJECT_VER`` variable is not set in the project then it will be retrieved from either ``$(PROJECT_PATH)/version.txt`` file (if present) else using git command ``git describe``. If neither is available then ``PROJECT_VER`` will be set to "1". Application can make use of this by calling :cpp:func:`esp_ota_get_app_description` or :cpp:func:`esp_ota_get_partition_description` functions. API Reference ------------- diff --git a/docs/en/api-reference/system/wdts.rst b/docs/en/api-reference/system/wdts.rst index 6f2f5cc4ec..5ba5b2fd1a 100644 --- a/docs/en/api-reference/system/wdts.rst +++ b/docs/en/api-reference/system/wdts.rst @@ -6,7 +6,7 @@ Overview The ESP-IDF has support for two types of watchdogs: The Interrupt Watchdog Timer and the Task Watchdog Timer (TWDT). The Interrupt Watchdog Timer and the TWDT -can both be enabled using ``make menuconfig``, however the TWDT can also be +can both be enabled using :ref:`project-configuration-menu`, however the TWDT can also be enabled during runtime. The Interrupt Watchdog is responsible for detecting instances where FreeRTOS task switching is blocked for a prolonged period of time. The TWDT is responsible for detecting instances of tasks running without @@ -63,7 +63,7 @@ longer call :cpp:func:`esp_task_wdt_reset`. Once all tasks have unsubscribed form the TWDT, the TWDT can be deinitialized by calling :cpp:func:`esp_task_wdt_deinit()`. -By default :ref:`CONFIG_ESP_TASK_WDT` in ``make menuconfig`` will be enabled causing +By default :ref:`CONFIG_ESP_TASK_WDT` in :ref:`project-configuration-menu` be enabled causing the TWDT to be initialized automatically during startup. Likewise :ref:`CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0` and :ref:`CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1` are also enabled by default causing diff --git a/docs/en/security/flash-encryption.rst b/docs/en/security/flash-encryption.rst index 17db90e27d..f13a27aa10 100644 --- a/docs/en/security/flash-encryption.rst +++ b/docs/en/security/flash-encryption.rst @@ -72,7 +72,7 @@ The flash encryption operation is controlled by various eFuses available on ESP3 encrypt flash at boot time Odd number of bits set (1, 3, 5, 7): do not encrypt flash at boot time - + Read and write access to above bits is controlled by appropriate bits in ``efuse_wr_disable`` and ``efuse_rd_disable`` registers. More information about ESP32 eFuse can be found at :doc:`eFuse manager <../api-reference/system/efuse>`. @@ -116,9 +116,9 @@ As mentioned above :ref:`flash_enc_development_mode` allows user to download as - Navigate to flash encryption sample application in ``$IDF_PATH/examples/security/flash_encryption`` folder. This sample application will print the status of flash encryption: enabled or disabled. It will print the ``FLASH_CRYPT_CNT`` eFuse value. -- Enable flash encryption support in second stage bootloader. In make menuconfig, navigate to “Security Features”. +- Enable flash encryption support in second stage bootloader. In :ref:`project-configuration-menu`, navigate to "Security Features". -- Select “Enable flash encryption on boot”. +- Select :ref:`Enable flash encryption on boot `. - By default the mode is set for **Development**. @@ -132,7 +132,7 @@ Build and flash the complete image including: bootloader, partition table and ap :: - make -j4 flash monitor + idf.py flash monitor Once the flashing is complete device will reset and on next boot second stage bootloader will encrypt the flash app partition and then reset. Now the sample application would get decrypted at runtime and executed. Below is a sample output when ESP32 boots after flash encryption is enabled for the first time. @@ -281,7 +281,7 @@ At this stage if user wants to update modified plaintext application image to fl :: - make -j4 encrypted-app-flash monitor + idf.py encrypted-app-flash monitor .. _encrypt_partitions: @@ -292,7 +292,7 @@ If all partitions needs to be updated in encrypted format, it can be done as :: - make -j4 encrypted-flash monitor + idf.py encrypted-flash monitor .. _pregenerated-flash-encryption-key: @@ -310,9 +310,9 @@ It is possible to pregenerate the flash encryption key on the host computer and espefuse.py --port PORT burn_key flash_encryption my_flash_encryption_key.bin -- Enable flash encryption support in second stage bootloader. In make menuconfig, navigate to “Security Features”. +- Enable flash encryption support in second stage bootloader. In :ref:`project-configuration-menu`, navigate to "Security Features". -- Select “Enable flash encryption on boot”. +- Select :ref:`Enable flash encryption on boot `. - By default the mode is set for **Development**. @@ -327,7 +327,7 @@ Build and flash the complete image including: bootloader, partition table and ap :: - make -j4 flash monitor + idf.py flash monitor On next boot second stage bootloader will encrypt the flash app partition and then reset. Now the sample application would get decrypted at runtime and executed. @@ -335,7 +335,7 @@ At this stage if user wants to update new plaintext application image to flash t :: - make -j4 encrypted-app-flash monitor + idf.py encrypted-app-flash monitor For reprogramming all partitions in encrypted format follow :ref:`encrypt_partitions`. @@ -348,10 +348,10 @@ Release Mode In Release mode UART bootloader can not perform flash encryption operations and new plaintext images can be downloaded ONLY using OTA scheme which will encrypt the plaintext image before writing to flash. - Ensure you have a ESP32 device with default flash encryption eFuse settings as shown in :ref:`flash-encryption-efuse`. - -- Enable flash encryption support in second stage bootloader. In make menuconfig, navigate to “Security Features”. -- Select “Enable flash encryption on boot”. +- Enable flash encryption support in second stage bootloader. In :ref:`project-configuration-menu`, navigate to "Security Features". + +- Select :ref:`Enable flash encryption on boot `. - Select **Release Mode**, by default the mode is set for **Development**. Please note **once the Release mode is selected the ``download_dis_encrypt`` and ``download_dis_decrypt`` eFuse bits will be programmed to disable UART bootloader access to flash contents**. @@ -365,7 +365,7 @@ Build and flash the complete image including: bootloader, partition table and ap :: - make -j4 flash monitor + idf.py flash monitor On next boot second stage bootloader will encrypt the flash app partition and then reset. Now the sample application should execute correctly. @@ -549,12 +549,11 @@ If you've accidentally enabled flash encryption for some reason, the next flash You can disable flash encryption again by writing ``FLASH_CRYPT_CNT`` eFuse (only in Development mode): -- First, run ``make menuconfig`` and uncheck "Enable flash encryption boot" under "Security Features". +- First, open :ref:`project-configuration-menu` and disable :ref:`Enable flash encryption boot ` under "Security Features". - Exit menuconfig and save the new configuration. -- Run ``make menuconfig`` again and double-check you really disabled this option! *If this option is left enabled, the bootloader will immediately re-enable encryption when it boots*. -- Run ``make flash`` to build and flash a new bootloader and app, without flash encryption enabled. +- Run ``idf.py menuconfig`` again and double-check you really disabled this option! *If this option is left enabled, the bootloader will immediately re-enable encryption when it boots*. +- Run ``idf.py flash`` to build and flash a new bootloader and app, without flash encryption enabled. - Run ``espefuse.py`` (in ``components/esptool_py/esptool``) to disable the FLASH_CRYPT_CNT:: - espefuse.py burn_efuse FLASH_CRYPT_CNT Reset the ESP32 and flash encryption should be disabled, the bootloader will boot as normal. @@ -584,7 +583,7 @@ Flash Encryption and Secure Boot It is recommended to use flash encryption and secure boot together. However, if Secure Boot is enabled then additional restrictions apply to reflashing the device: - :ref:`updating-encrypted-flash-ota` are not restricted (provided the new app is signed correctly with the Secure Boot signing key). -- :ref:`Plaintext serial flash updates ` are only possible if the :ref:`Reflashable ` Secure Boot mode is selected and a Secure Boot key was pre-generated and burned to the ESP32 (refer to :ref:`Secure Boot ` docs.). In this configuration, ``make bootloader`` will produce a pre-digested bootloader and secure boot digest file for flashing at offset 0x0. When following the plaintext serial reflashing steps it is necessary to re-flash this file before flashing other plaintext data. +- :ref:`Plaintext serial flash updates ` are only possible if the :ref:`Reflashable ` Secure Boot mode is selected and a Secure Boot key was pre-generated and burned to the ESP32 (refer to :ref:`Secure Boot ` docs.). In this configuration, ``idf.py bootloader`` will produce a pre-digested bootloader and secure boot digest file for flashing at offset 0x0. When following the plaintext serial reflashing steps it is necessary to re-flash this file before flashing other plaintext data. - :ref:`Reflashing via Pregenerated Flash Encryption Key ` is still possible, provided the bootloader is not reflashed. Reflashing the bootloader requires the same :ref:`Reflashable ` option to be enabled in the Secure Boot config. .. _flash-encryption-without-secure-boot: diff --git a/docs/en/security/secure-boot.rst b/docs/en/security/secure-boot.rst index 9a6f8a933a..3cd24d8036 100644 --- a/docs/en/security/secure-boot.rst +++ b/docs/en/security/secure-boot.rst @@ -25,7 +25,7 @@ Secure Boot Process Overview This is a high level overview of the secure boot process. Step by step instructions are supplied under :ref:`secure-boot-howto`. Further in-depth details are supplied under :ref:`secure-boot-technical-details`: -1. The options to enable secure boot are provided in the ``make menuconfig`` hierarchy, under "Secure Boot Configuration". +1. The options to enable secure boot are provided in the :ref:`project-configuration-menu`, under "Secure Boot Configuration". 2. Secure Boot defaults to signing images and partition table data during the build process. The "Secure boot private signing key" config item is a file path to a ECDSA public/private key pair in a PEM format file. @@ -76,7 +76,7 @@ Options to work around this are: How To Enable Secure Boot ------------------------- -1. Run ``make menuconfig``, navigate to "Secure Boot Configuration" and select the option "One-time Flash". (To understand the alternative "Reflashable" choice, see :ref:`secure-boot-reflashable`.) +1. Open the :ref:`project-configuration-menu`, navigate to "Secure Boot Configuration" and select the option "One-time Flash". (To understand the alternative "Reflashable" choice, see :ref:`secure-boot-reflashable`.) 2. Select a name for the secure boot signing key. This option will appear after secure boot is enabled. The file can be anywhere on your system. A relative path will be evaluated from the project directory. The file does not need to exist yet. @@ -90,15 +90,15 @@ How To Enable Secure Boot .. important:: For production environments, we recommend generating the keypair using openssl or another industry standard encryption program. See :ref:`secure-boot-generate-key` for more details. -5. Run ``make bootloader`` to build a secure boot enabled bootloader. The output of ``make`` will include a prompt for a flashing command, using ``esptool.py write_flash``. +5. Run ``idf.py bootloader`` to build a secure boot enabled bootloader. The build output will include a prompt for a flashing command, using ``esptool.py write_flash``. .. _secure-boot-resume-normal-flashing: 6. When you're ready to flash the bootloader, run the specified command (you have to enter it yourself, this step is not performed by make) and then wait for flashing to complete. **Remember this is a one time flash, you can't change the bootloader after this!**. -7. Run ``make flash`` to build and flash the partition table and the just-built app image. The app image will be signed using the signing key you generated in step 4. +7. Run ``idf.py flash`` to build and flash the partition table and the just-built app image. The app image will be signed using the signing key you generated in step 4. -.. note:: ``make flash`` doesn't flash the bootloader if secure boot is enabled. +.. note:: ``idf.py flash`` doesn't flash the bootloader if secure boot is enabled. 8. Reset the ESP32 and it will boot the software bootloader you flashed. The software bootloader will enable secure boot on the chip, and then it verifies the app image signature and boots the app. You should watch the serial console output from the ESP32 to verify that secure boot is enabled and no errors have occurred due to the build configuration. @@ -123,13 +123,13 @@ In the esp-idf build process, this 256-bit key file is derived from the app sign To enable a reflashable bootloader: -1. In the ``make menuconfig`` step, select "Bootloader Config" -> :ref:`CONFIG_SECURE_BOOT_ENABLED` -> :ref:`CONFIG_SECURE_BOOTLOADER_MODE` -> Reflashable. +1. In the :ref:`project-configuration-menu`, select "Bootloader Config" -> :ref:`CONFIG_SECURE_BOOT_ENABLED` -> :ref:`CONFIG_SECURE_BOOTLOADER_MODE` -> Reflashable. 2. If necessary, set the :ref:`CONFIG_SECURE_BOOTLOADER_KEY_ENCODING` based on the coding scheme used by the device. The coding scheme is shown in the ``Features`` line when ``esptool.py`` connects to the chip, or in the ``espefuse.py summary`` output. 2. Follow the steps shown above to choose a signing key file, and generate the key file. -3. Run ``make bootloader``. A binary key file will be created, derived from the private key that is used for signing. Two sets of flashing steps will be printed - the first set of steps includes an ``espefuse.py burn_key`` command which is used to write the bootloader key to efuse. (Flashing this key is a one-time-only process.) The second set of steps can be used to reflash the bootloader with a pre-calculated digest (generated during the build process). +3. Run ``idf.py bootloader``. A binary key file will be created, derived from the private key that is used for signing. Two sets of flashing steps will be printed - the first set of steps includes an ``espefuse.py burn_key`` command which is used to write the bootloader key to efuse. (Flashing this key is a one-time-only process.) The second set of steps can be used to reflash the bootloader with a pre-calculated digest (generated during the build process). 4. Resume from :ref:`Step 6 of the one-time flashing process `, to flash the bootloader and enable secure boot. Watch the console log output closely to ensure there were no errors in the secure boot configuration. @@ -244,7 +244,7 @@ Deterministic ECDSA as specified by `RFC 6979 Security features -> Enable "Require signed app images" +1. Open :ref:`project-configuration-menu` -> Security features -> Enable :ref:`CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT` 2. "Bootloader verifies app signatures" can be enabled, which verifies app on boot. diff --git a/docs/zh_CN/api-guides/console.rst b/docs/zh_CN/api-guides/console.rst index c7a6408acd..45872445f5 100644 --- a/docs/zh_CN/api-guides/console.rst +++ b/docs/zh_CN/api-guides/console.rst @@ -16,7 +16,7 @@ ESP-IDF 提供了 ``console`` 组件,它包含了开发基于串口的交互 行编辑功能允许用户通过按键输入来编辑命令,使用退格键删除符号,使用左/右键在命令中移动光标,使用上/下键导航到之前输入的命令,使用制表键(“Tab”)来自动补全命令。 -.. note:: 此功能依赖于终端应用程序对 ANSI 转移符的支持,显示原始 UART 数据的串口监视器不能与行编辑库一同使用。如果运行 get_started/console 示例程序的时候观察到的输出结果是 ``[6n`` 或者类似的转义字符而不是命令行提示符 ``[esp32]>`` 时,就表明当前的串口监视器不支持 ANSI 转移字符。已知可用的串口监视程序有 GNU screen,minicom 和 idf_monitor.py(可以通过在项目目录下执行 ``make monitor`` 来调用)。 +.. note:: 此功能依赖于终端应用程序对 ANSI 转移符的支持,显示原始 UART 数据的串口监视器不能与行编辑库一同使用。如果运行 get_started/console 示例程序的时候观察到的输出结果是 ``[6n`` 或者类似的转义字符而不是命令行提示符 ``[esp32]>`` 时,就表明当前的串口监视器不支持 ANSI 转移字符。已知可用的串口监视程序有 GNU screen,minicom 和 idf_monitor.py(可以通过在项目目录下执行 ``idf.py monitor`` 来调用)。 前往这里可以查看 `linenoise `_ 库提供的所有函数的描述。 diff --git a/docs/zh_CN/api-guides/jtag-debugging/tips-and-quirks.rst b/docs/zh_CN/api-guides/jtag-debugging/tips-and-quirks.rst index fe04714c81..2588c8aa16 100644 --- a/docs/zh_CN/api-guides/jtag-debugging/tips-and-quirks.rst +++ b/docs/zh_CN/api-guides/jtag-debugging/tips-and-quirks.rst @@ -57,7 +57,7 @@ ESP-IDF 有一些针对 OpenOCD 调试功能的选项可以在编译时进行设 * :ref:`CONFIG_ESP32_DEBUG_OCDAWARE` 默认会被使能。如果程序抛出了不可修复或者未处理的异常,并且此时已经连接上了 JTAG 调试器(即 OpenOCD 正在运行),那么 ESP-IDF 将会进入调试器工作模式。 * :ref:`CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK` 默认没有使能。在所有任务堆栈的末尾设置观察点,从 1 号开始索引。这是调试任务堆栈溢出的最准确的方式。 -更多有关设置编译时的选项的信息,请参阅 :ref:`make menuconfig `。 +更多有关设置编译时的选项的信息,请参阅 :ref:`idf.py menuconfig `。 .. _jtag-debugging-tip-freertos-support: diff --git a/docs/zh_CN/api-guides/partition-tables.rst b/docs/zh_CN/api-guides/partition-tables.rst index deff7c14c8..c4b84a6185 100644 --- a/docs/zh_CN/api-guides/partition-tables.rst +++ b/docs/zh_CN/api-guides/partition-tables.rst @@ -11,12 +11,12 @@ 分区表中的每个条目都包括以下几个部分:Name(标签)、Type(app、data 等)、SubType 以及在 flash 中的偏移量(分区的加载地址)。 -在使用分区表时,最简单的方法就是用 `make menuconfig` 选择一张预定义的分区表: +在使用分区表时,最简单的方法就是用 `idf.py menuconfig` 选择一张预定义的分区表: - "Single factory app, no OTA" - "Factory app, two OTA definitions" -在以上两种选项中,出厂应用程序均将被烧录至 flash 的 0x10000 偏移地址处。这时,运行 `make partition_table` ,即可以打印当前使用分区表的信息摘要。 +在以上两种选项中,出厂应用程序均将被烧录至 flash 的 0x10000 偏移地址处。这时,运行 `idf.py partition_table` ,即可以打印当前使用分区表的信息摘要。 内置分区表 ------------ @@ -102,7 +102,7 @@ SubType 字段长度为 8 bit,内容与具体 Type 有关。目前,esp-idf - phy (1) 分区用于存放 PHY 初始化数据,从而保证可以为每个设备单独配置 PHY,而非必须采用固件中的统一 PHY 初始化数据。 - 默认配置下,phy 分区并不启用,而是直接将 phy 初始化数据编译至应用程序中,从而节省分区表空间(直接将此分区删掉)。 - - 如果需要从此分区加载 phy 初始化数据,请运行 ``make menuconfig``,并且使能 :ref:`CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION` 选项。此时,您还需要手动将 phy 初始化数据烧至设备 flash(esp-idf 编译系统并不会自动完成该操作)。 + - 如果需要从此分区加载 phy 初始化数据,请运行 ``idf.py menuconfig``,并且使能 :ref:`CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION` 选项。此时,您还需要手动将 phy 初始化数据烧至设备 flash(esp-idf 编译系统并不会自动完成该操作)。 - nvs (2) 是专门给 :doc:`非易失性存储 (NVS) API <../api-reference/storage/nvs_flash>` 使用的分区。 - 用于存储每台设备的 PHY 校准数据(注意,并不是 PHY 初始化数据)。 @@ -142,7 +142,7 @@ Flags 字段 烧写到 ESP32 中的分区表采用二进制格式,而不是 CSV 文件本身。此时,:component_file:`partition_table/gen_esp32part.py` 工具可以实现 CSV 和二进制文件之间的转换。 -如果您在 ``make menuconfig`` 指定了分区表 CSV 文件的名称,然后执行 ``make partition_table``。这时,转换将在编译过程中自动完成。 +如果您在 ``idf.py menuconfig`` 指定了分区表 CSV 文件的名称,然后执行 ``idf.py partition_table``。这时,转换将在编译过程中自动完成。 手动将 CSV 文件转换为二进制文件: @@ -152,7 +152,7 @@ Flags 字段 python gen_esp32part.py binary_partitions.bin input_partitions.csv -在标准输出(stdout)上,打印二进制分区表的内容(在运行 ``make partition_table`` 时,我们正是这样打印上文展示的信息摘要的): +在标准输出(stdout)上,打印二进制分区表的内容(在运行 ``idf.py partition_table`` 时,我们正是这样打印上文展示的信息摘要的): python gen_esp32part.py binary_partitions.bin @@ -166,13 +166,13 @@ MD5 校验和 烧写分区表 ---------- -- ``make partition_table-flash`` :使用 esptool.py 工具烧写分区表。 -- ``make flash`` :会烧写所有内容,包括分区表。 +- ``idf.py partition_table-flash`` :使用 esptool.py 工具烧写分区表。 +- ``idf.py flash`` :会烧写所有内容,包括分区表。 -在执行 ``make partition_table`` 命令时,手动烧写分区表的命令也将打印在终端上。 +在执行 ``idf.py partition_table`` 命令时,手动烧写分区表的命令也将打印在终端上。 .. note:: - 分区表的更新并不会擦除根据之前分区表存储的数据。此时,您可以使用 ``make erase_flash`` 命令或者 ``esptool.py erase_flash`` 命令来擦除 flash 中的所有内容。 + 分区表的更新并不会擦除根据之前分区表存储的数据。此时,您可以使用 ``idf.py erase_flash`` 命令或者 ``esptool.py erase_flash`` 命令来擦除 flash 中的所有内容。 .. _secure boot: security/secure-boot.rst diff --git a/docs/zh_CN/api-guides/tools/idf-monitor.rst b/docs/zh_CN/api-guides/tools/idf-monitor.rst index d756422da4..72651108f2 100644 --- a/docs/zh_CN/api-guides/tools/idf-monitor.rst +++ b/docs/zh_CN/api-guides/tools/idf-monitor.rst @@ -8,8 +8,9 @@ IDF 监视器是一个串行终端程序,用于收发目标设备串口的串 在 IDF 中调用以下目标函数可以启用此监视器: -- **若使用 Make 编译系统,请调用**:``make monitor`` - **若使用 CMake 编译系统,则请调用**:``idf.py monitor`` +- **若使用传统 GNU Make 编译系统,请调用**:``make monitor`` + 操作快捷键 @@ -26,7 +27,7 @@ Ctrl+T 菜单退出键 - Ctrl+] 将 exit 字符发送至远程 - Ctrl+P 重置目标设备,进入 Bootloader,通过 RTS 线暂停应用程序 重置目标设备,通过 RTS 线(如已连接)进入 Bootloader,此时开发板不运行任何程序。等待其他设备启动时可以使用此操作。 - Ctrl+R 通过 RTS 线重置目标设备 重置设备,并通过 RTS 线(如已连接)重新启动应用程序。 -- Ctrl+F 编译并烧录此项目 暂停 idf_monitor,运行 ``make flash`` (``idf.py flash``) 目标,然后恢复 idf_monitor。任何改动的源文件都会被重新编译,然后重新烧录。 +- Ctrl+F 编译并烧录此项目 暂停 idf_monitor,运行 ``idf.py flash`` 目标,然后恢复 idf_monitor。任何改动的源文件都会被重新编译,然后重新烧录。 - Ctrl+A (A) 仅编译及烧录应用程序 暂停 idf_monitor,运行 ``app-flash`` 目标,然后恢复 idf_monitor。 这与 ``flash`` 类似,但只有主应用程序被编译并被重新烧录。 - Ctrl+Y 停止/恢复日志输出在屏幕上打印 激活时,会丢弃所有传入的串行数据。允许在不退出监视器的情况下快速暂停和检查日志输出。 - Ctrl+L 停止/恢复向文件写入日志输出 在工程目录下创建一个文件,用于写入日志输出。可使用快捷键停止/恢复该功能(退出 IDF 监视器也会终止该功能) @@ -91,7 +92,7 @@ IDF 监视器在后台运行以下命令,解码各地址:: 或者选择配置 panic 处理器以运行 GDBStub,GDBStub 工具可以与 GDB_ 项目调试器进行通信,允许读取内存、检查调用堆栈帧和变量等。GDBStub 虽然没有 JTAG 通用,但不需要使用特殊硬件。 -如需启用 GDBStub,请运行 ``make menuconfig`` (适用于 Make 编译系统)或 ``idf.py menuconfig`` (适用于 CMake 编译系统),并将 :ref:`CONFIG_ESP32_PANIC` 选项设置为 ``Invoke GDBStub``。 +如需启用 GDBStub,请运行 ``idf.py menuconfig`` (适用于 CMake 编译系统),并将 :ref:`CONFIG_ESP32_PANIC` 选项设置为 ``Invoke GDBStub``。 在这种情况下,如果 panic 处理器被触发,只要 IDF 监视器监控到 GDBStub 已经加载,panic 处理器就会自动暂停串行监控并使用必要的参数运行 GDB。GDB 退出后,通过 RTS 串口线复位开发板。如果未连接 RTS 串口线,请按复位键,手动复位开发板。 @@ -103,7 +104,7 @@ IDF 监控器在后台运行如下命令:: 输出筛选 ~~~~~~~~~~~~~~~~ -IDF 监视器有两种启用方式:运行 ``make monitor PRINT_FILTER=""`` (适用于 Make)或者 ``idf.py monitor --print-filter=""`` (适用于 CMake),其中,``PRINT_FILTER`` 是输出筛选的参数。参数默认值为空字符串,可打印任何内容。 +IDF 监视器有两种启用方式:运行 ``idf.py monitor PRINT_FILTER=""`` (适用于 CMake) 或者 ``make monitor PRINT_FILTER=""`` (适用于传统 GNU Make),其中,``--print-filter`` 是输出筛选的参数。参数默认值为空字符串,可打印任何内容。 若需对打印内容设置限制,可指定 ``:`` 等选项,其中 ```` 是标签字符串,```` 是 ``{N, E, W, I, D, V, *}`` 集合中的一个字母,指的是 :doc:`日志 <../../api-reference/system/log>` 级别。 @@ -159,18 +160,6 @@ IDF 监视器有两种启用方式:运行 ``make monitor PRINT_FILTER=""`` ( D (309) light_driver: [light_init, 74]:status: 1, mode: 2 -简单监视器 -============== - -较早版本的 ESP-IDF 使用 pySerial_ 命令行工具 miniterm_ 作为串行控制台程序。 - -.. note:: 仅适用于 Make 编译系统,不适用于 CMake 编译系统。 - -此程序仍然可以通过 ``make simple_monitor`` 运行。 - -IDF 监视器基于 miniterm,可使用相同的快捷键。 - - IDF 监视器已知问题 ============================= diff --git a/examples/README.md b/examples/README.md index af04945bfd..e5b4a0c4fc 100644 --- a/examples/README.md +++ b/examples/README.md @@ -25,9 +25,9 @@ Building an example is the same as building any other project: * Follow the Getting Started instructions which include building the "Hello World" example. * Change into the directory of the new example you'd like to build. -* `make menuconfig` to configure the example. Most examples have a project-specific "Example Configuration" section here (for example, to set the WiFi SSID & password to use). +* Run `idf.py menuconfig` to open the project configuration menu. Most examples have a project-specific "Example Configuration" section here (for example, to set the WiFi SSID & password to use). * `make` to build the example. -* Follow the printed instructions to flash, or run `make flash`. +* Follow the printed instructions to flash, or run `idf.py flash`. # Copying Examples diff --git a/examples/bluetooth/bluedroid/ble/ble_ibeacon/README.md b/examples/bluetooth/bluedroid/ble/ble_ibeacon/README.md index df698cf904..04b09711b1 100644 --- a/examples/bluetooth/bluedroid/ble/ble_ibeacon/README.md +++ b/examples/bluetooth/bluedroid/ble/ble_ibeacon/README.md @@ -21,10 +21,10 @@ Which demo will be run depends on the menuconfig, developers can set it in `iBea The default mode is iBeacon Sender. ### Menuconfig -Before compiling the demo,developers also need to configure the menuconfig: +Before compiling the demo,developers also need to configure the project: ```c -make menuconfig +idf.py menuconfig ``` And then enter `Component config->Bluetooth->Bluedroid Enable` @@ -49,7 +49,7 @@ switch (scan_result->scan_rst.search_evt) { Build each project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idp.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) @@ -110,4 +110,4 @@ I (329203) IBEACON_DEMO: ----------iBeacon Found---------- I (329203) IBEACON_DEMO: Device address:: 30 ae a4 00 42 82 I (329203) IBEACON_DEMO: Proximity UUID:: fd a5 06 93 a4 e2 4f b1 af cf c6 eb 07 64 78 25 ``` - \ No newline at end of file + diff --git a/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/README.md b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/README.md index 48b6b475ba..d38c4ca5ed 100644 --- a/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/README.md +++ b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/README.md @@ -4,10 +4,10 @@ ESP-IDF BLE throughput GATT CLIENT demo This is the demo used to test the BLE throughput, this demo should used with throughput server demo together. The throughput of BLE can up to 720-767 Kbps between to ESP32 board. Note: -1. In order to maximize throughput, we need to set the uart print baud rate at 921600 or more (make menuconfig --> Component config --> ESP32-specific --> UART console baud rate --> 921600(or 1500000)) and don't print too much log. +1. In order to maximize throughput, we need to set the uart print baud rate at 921600 or more (idf.py menuconfig --> Component config --> ESP32-specific --> UART console baud rate --> 921600(or 1500000)) and don't print too much log. 2. We can only test notify or write throughput at the same time, this demo default to test the notify throughput, if want to test the write throughput, -please set: make menuconfig --> Component config --> Example 'GATT CLIENT THROUGHPUT' Config ---> then select the 'test the gattc write throughput' option +please set: idf.py menuconfig --> Component config --> Example 'GATT CLIENT THROUGHPUT' Config ---> then select the 'test the gattc write throughput' option 3. This demo only test unidirectional throughput, if you want to test the bidirectional throughput please change the demo by yourself. -4. Should change the CPU frequency to 160MHZ or 240MHz in the make menuconfig --> Component config ---> ESP32-specific ---> CPU frequency (240 MHz or 160 MHz). -5. Should change the bluetooth controller and Bluedroid run in different Core in the make menuconfig --> Component config ---> Bluetooth ---> The cpu core which bluetooth controller run (Core 0 (PRO CPU)) & Bluedroid Enable ---> The cpu core which Bluedroid run (Core 1 (APP CPU)). +4. Should change the CPU frequency to 160MHZ or 240MHz in the idf.py menuconfig --> Component config ---> ESP32-specific ---> CPU frequency (240 MHz or 160 MHz). +5. Should change the bluetooth controller and Bluedroid run in different Core in the idf.py menuconfig --> Component config ---> Bluetooth ---> The cpu core which bluetooth controller run (Core 0 (PRO CPU)) & Bluedroid Enable ---> The cpu core which Bluedroid run (Core 1 (APP CPU)). 6. In order to maximize throughput, please test in a clean environment without many BLE devices working and both test devices are ESP32. diff --git a/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/README.md b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/README.md index 47c86410d9..1dc21211c8 100644 --- a/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/README.md +++ b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/README.md @@ -4,11 +4,11 @@ ESP-IDF BLE throughput GATT SERVER demo This is the demo used to test the BLE throughput, this demo should used with throughput client demo together. The throughput of BLE can up to 720-767 Kbps between to ESP32 board. Note: -1. In order to maximize throughput, we need to set the uart print baud rate at 921600 or more (make menuconfig --> Component config --> ESP32-specific --> UART console baud rate --> 921600(or 1500000)) and don't print too much log; +1. In order to maximize throughput, we need to set the uart print baud rate at 921600 or more (idf.py menuconfig --> Component config --> ESP32-specific --> UART console baud rate --> 921600(or 1500000)) and don't print too much log; 2. We can only test notify or write throughput at the same time, this demo default to test the notify throughput, if want to test the write throughput, -please set: make menuconfig --> Component config --> Example 'GATT SERVER THROUGHPUT' Config ---> then select the 'test the gattc write throughput' option +please set: idf.py menuconfig --> Component config --> Example 'GATT SERVER THROUGHPUT' Config ---> then select the 'test the gattc write throughput' option 3. This demo only test unidirectional throughput, if you want to test the bidirectional throughput please change the demo by yourself. -4. Should change the CPU frequency to 160MHz or 240MHz in the make menuconfig --> Component config ---> ESP32-specific ---> CPU frequency (160MHz or 240 MHz) -5. Should change the bluetooth controller and Bluedroid run in different Core in the make menuconfig --> Component config ---> Bluetooth ---> The cpu core which bluetooth controller run (Core 0 (PRO CPU)) & Bluedroid Enable ---> The cpu core which Bluedroid run (Core 1 (APP CPU)) +4. Should change the CPU frequency to 160MHz or 240MHz in the idf.py menuconfig --> Component config ---> ESP32-specific ---> CPU frequency (160MHz or 240 MHz) +5. Should change the bluetooth controller and Bluedroid run in different Core in the idf.py menuconfig --> Component config ---> Bluetooth ---> The cpu core which bluetooth controller run (Core 0 (PRO CPU)) & Bluedroid Enable ---> The cpu core which Bluedroid run (Core 1 (APP CPU)) 6. In order to maximize throughput, please test in a clean environment without many BLE devices working and both test devices are ESP32. diff --git a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/README.md b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/README.md index 9a3c5d611b..7d0889eccc 100644 --- a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/README.md +++ b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/README.md @@ -28,11 +28,9 @@ If the internal DAC is selected, analog audio will be available on GPIO25 and GP ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` -* Set serial port under Serial Flasher Options. - * Set the use of external I2S codec or internal DAC for audio output, and configure the output PINs under A2DP Example Configuration * Enable Classic Bluetooth and A2DP under Component config --> Bluetooth --> Bluedroid Enable @@ -42,7 +40,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output. ``` -make -j4 flash monitor +idf.py flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) @@ -72,4 +70,4 @@ Also, the sound will be heard if a loudspeaker is connected and possible externa ## Troubleshooting * For current stage, the supported audio codec in ESP32 A2DP is SBC. SBC data stream is transmitted to A2DP sink and then decoded into PCM samples as output. The PCM data format is normally of 44.1kHz sampling rate, two-channel 16-bit sample stream. Other decoder configurations in ESP32 A2DP sink is supported but need additional modifications of protocol stack settings. -* As a usage limitation, ESP32 A2DP sink can support at most one connection with remote A2DP source devices. Also, A2DP sink cannot be used together with A2DP source at the same time, but can be used with other profiles such as SPP and HFP. \ No newline at end of file +* As a usage limitation, ESP32 A2DP sink can support at most one connection with remote A2DP source devices. Also, A2DP sink cannot be used together with A2DP source at the same time, but can be used with other profiles such as SPP and HFP. diff --git a/examples/bluetooth/bluedroid/classic_bt/a2dp_source/README.md b/examples/bluetooth/bluedroid/classic_bt/a2dp_source/README.md index 4e9586ce98..05e0594dbc 100644 --- a/examples/bluetooth/bluedroid/classic_bt/a2dp_source/README.md +++ b/examples/bluetooth/bluedroid/classic_bt/a2dp_source/README.md @@ -14,11 +14,9 @@ This example is able to run on any commonly available ESP32 development board. A ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` -* Set serial port under Serial Flasher Options. - * Enable Classic Bluetooth and A2DP under Component config --> Bluetooth --> Bluedroid Enable ### Build and Flash @@ -26,7 +24,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output. ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/bluetooth/bluedroid/classic_bt/bt_discovery/README.rst b/examples/bluetooth/bluedroid/classic_bt/bt_discovery/README.rst index 29db5e73c1..d5c857344c 100644 --- a/examples/bluetooth/bluedroid/classic_bt/bt_discovery/README.rst +++ b/examples/bluetooth/bluedroid/classic_bt/bt_discovery/README.rst @@ -6,7 +6,7 @@ Demo of Classic Bluetooth Device and Service Discovery This is the demo for user to use ESP_APIs to perform inquiry to search for a target device and then performs service search via SDP. Options choose step: - 1. make menuconfig. + 1. idf.py menuconfig. 2. enter menuconfig "Component config", choose "Bluetooth" 3. enter menu Bluetooth, choose "Classic Bluetooth" and do not choose "Release DRAM from Classic BT controller" 4. choose your options. diff --git a/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/README.rst b/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/README.rst index b0a865e41d..d33e353672 100644 --- a/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/README.rst +++ b/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/README.rst @@ -6,11 +6,11 @@ Demo of SPP acceptor role This is the demo for user to use ESP_APIs to create a SPP acceptor. Options choose step: - 1. make menuconfig. + 1. idf.py menuconfig. 2. enter menuconfig "Component config", choose "Bluetooth" 3. enter menu Bluetooth, choose "Classic Bluetooth" and "SPP Profile" 4. choose your options. Then set SPP_SHOW_MODE as SPP_SHOW_DATA or SPP_SHOW_SPEED in code(should be same with bt_spp_initator). -After the program started, bt_spp_initator will connect it and send data. \ No newline at end of file +After the program started, bt_spp_initator will connect it and send data. diff --git a/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/README.rst b/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/README.rst index 4d298e18f8..07bf513a1c 100644 --- a/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/README.rst +++ b/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/README.rst @@ -6,11 +6,11 @@ Demo of SPP initator role This is the demo for user to use ESP_APIs to create a SPP initator. Options choose step: - 1. make menuconfig. + 1. idf.py menuconfig. 2. enter menuconfig "Component config", choose "Bluetooth" 3. enter menu Bluetooth, choose "Classic Bluetooth" and "SPP Profile" 4. choose your options. Then set SPP_SHOW_MODE as SPP_SHOW_DATA or SPP_SHOW_SPEED in code(should be same with bt_spp_acceptor). -After the program started, It will connect to bt_spp_acceptor and send data. \ No newline at end of file +After the program started, It will connect to bt_spp_acceptor and send data. diff --git a/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/README.rst b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/README.rst index 76571c45e3..b45593eb62 100644 --- a/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/README.rst +++ b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/README.rst @@ -6,9 +6,9 @@ Demo of SPP acceptor role This is the demo for user to use ESP_APIs to create a SPP acceptor. Options choose step: - 1. make menuconfig. + 1. idf.py menuconfig. 2. enter menuconfig "Component config", choose "Bluetooth" 3. enter menu Bluetooth, choose "Classic Bluetooth" and "SPP Profile" 4. choose your options. -After the program started, bt_spp_vfs_initator will connect it and send data. \ No newline at end of file +After the program started, bt_spp_vfs_initator will connect it and send data. diff --git a/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/README.rst b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/README.rst index efb2513d91..38d9804b9c 100644 --- a/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/README.rst +++ b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/README.rst @@ -6,9 +6,9 @@ Demo of SPP initator role This is the demo for user to use ESP_APIs to create a SPP initator. Options choose step: - 1. make menuconfig. + 1. idf.py menuconfig. 2. enter menuconfig "Component config", choose "Bluetooth" 3. enter menu Bluetooth, choose "Classic Bluetooth" and "SPP Profile" 4. choose your options. -After the program started, It will connect to bt_spp_vfs_acceptor and send data. \ No newline at end of file +After the program started, It will connect to bt_spp_vfs_acceptor and send data. diff --git a/examples/ethernet/eth2ap/README.md b/examples/ethernet/eth2ap/README.md index 26d81db121..8e0f425a62 100644 --- a/examples/ethernet/eth2ap/README.md +++ b/examples/ethernet/eth2ap/README.md @@ -18,7 +18,7 @@ To run this example, it's recommended that you have an official ESP32 Ethernet d ### Project configuration in menuconfig -Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you' are using CMake based build system. +Open the project configuration menu (`idf.py menuconfig`). 1. In the `Example Configuration` menu: * Set the SSID and password for Wi-Fi ap interface under `Wi-Fi SSID` and `Wi-Fi Password`. @@ -57,7 +57,7 @@ Enter `make menuconfig` if you are using GNU Make based build system or enter `i ### Build and Flash -To build and flash the example, enter `make -j4 flash monitor` if you are using GNU Make based build system or enter `idf.py build flash monitor` if you are using CMake based build system. +To build and flash the example, enter `idf.py -p PORT flash monitor`. (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/get-started/blink/main/blink.c b/examples/get-started/blink/main/blink.c index 20a0b94ebf..9c58645f9d 100644 --- a/examples/get-started/blink/main/blink.c +++ b/examples/get-started/blink/main/blink.c @@ -12,7 +12,7 @@ #include "driver/gpio.h" #include "sdkconfig.h" -/* Can run 'make menuconfig' to choose the GPIO to blink, +/* Can use project configuration menu (idf.py menuconfig) to choose the GPIO to blink, or you can edit the following line and set a number here. */ #define BLINK_GPIO CONFIG_BLINK_GPIO diff --git a/examples/mesh/internal_communication/README.md b/examples/mesh/internal_communication/README.md index 4131bef5aa..3c97dc427c 100644 --- a/examples/mesh/internal_communication/README.md +++ b/examples/mesh/internal_communication/README.md @@ -16,7 +16,7 @@ Features Demonstrated - other nodes receive -Run `make menuconfig` to configure the mesh network channel, router SSID, router password and mesh softAP settings. +Open project configuration menu (`idf.py menuconfig`) to configure the mesh network channel, router SSID, router password and mesh softAP settings. When the mesh network is established and if you happen to run this example on ESP-WROVER-KIT boards, the RGB light indicator will show you on which layer devices are. The pink reprents root; the yellow reprents layer 2; the red reprents layer 3; the blue reprents layer 4; the green reprents layer 5; the white reprents layer greater than 5. diff --git a/examples/mesh/manual_networking/README.md b/examples/mesh/manual_networking/README.md index 8615dbd6de..9b3ecd58cd 100644 --- a/examples/mesh/manual_networking/README.md +++ b/examples/mesh/manual_networking/README.md @@ -7,7 +7,7 @@ This example demonstrates how to scan a list of parent candidates, choose an app If no parent is found through this scan, enable the self-organized function to let the ESP-MESH handle it by itself. -Run `make menuconfig` to configure the mesh network channel, router SSID, router password and mesh softAP settings. +Open project configuration menu (`idf.py menuconfig`) to configure the mesh network channel, router SSID, router password and mesh softAP settings. When the mesh network is established and if you happen to run this example on ESP-WROVER-KIT boards, the RGB light indicator will show you on which layer devices are. The pink reprents root; the yellow reprents layer 2; the red reprents layer 3; the blue reprents layer 4; the green reprents layer 5; the white reprents layer greater than 5. diff --git a/examples/peripherals/adc/README.md b/examples/peripherals/adc/README.md index 657f01a1b9..47f58c94b9 100644 --- a/examples/peripherals/adc/README.md +++ b/examples/peripherals/adc/README.md @@ -48,7 +48,7 @@ Raw: 18 Voltage: 79mV * program upload failure - * Hardware connection is not correct: run `make monitor`, and reboot your board to see if there are any output logs. + * Hardware connection is not correct: run `idf.py monitor`, and reboot your board to see if there are any output logs. * The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again. For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/adc2/README.md b/examples/peripherals/adc2/README.md index 1d7ba206a6..32b94f68ed 100644 --- a/examples/peripherals/adc2/README.md +++ b/examples/peripherals/adc2/README.md @@ -59,7 +59,7 @@ start conversion. * program upload failure - * Hardware connection is not correct: run `make monitor`, and reboot your board to see if there are any output logs. + * Hardware connection is not correct: run `idf.py monitor`, and reboot your board to see if there are any output logs. * The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again. For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/i2c/i2c_self_test/README.md b/examples/peripherals/i2c/i2c_self_test/README.md index 499b35e3c0..66f64c2ffc 100644 --- a/examples/peripherals/i2c/i2c_self_test/README.md +++ b/examples/peripherals/i2c/i2c_self_test/README.md @@ -43,7 +43,7 @@ To run this example, you should have one ESP32 dev board (e.g. ESP32-WROVER Kit) ### Configure the project -Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you are using CMake based build system. Then go into `Example Configuration` menu. +Open the project configuration menu (`idf.py menuconfig`). Then go into `Example Configuration` menu. - In the `I2C Master` submenu, you can set the pin number of SDA/SCL according to your board. Also you can modify the I2C port number and freauency of the master. - In the `I2C Slave` submenu, you can set the pin number of SDA/SCL according to your board. Also you can modify the I2C port number and address of the slave. @@ -52,7 +52,7 @@ Enter `make menuconfig` if you are using GNU Make based build system or enter `i ### Build and Flash -Enter `make -j4 flash monitor` if you are using GNU Make based build system or enter `idf.py build flash monitor` if you' are using CMake based build system. +Enter `idf.py -p PORT flash monitor` to build, flash and monitor the project. (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/peripherals/i2c/i2c_tools/README.md b/examples/peripherals/i2c/i2c_tools/README.md index ca150d838b..40d6a2b69b 100644 --- a/examples/peripherals/i2c/i2c_tools/README.md +++ b/examples/peripherals/i2c/i2c_tools/README.md @@ -33,7 +33,7 @@ To run this example, you should have one ESP32 dev board (e.g. ESP32-WROVER Kit) ### Configure the project -Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you are using CMake based build system. Then go into `Example Configuration` menu. +Open the project configuration menu (`idf.py menuconfig`). Then go into `Example Configuration` menu. - You can choose whether or not to save command history into flash in `Store command history in flash` option. - You can set the maximum number of command line arguments under `Maximum number of command line arguments` option. @@ -41,7 +41,7 @@ Enter `make menuconfig` if you are using GNU Make based build system or enter `i ### Build and Flash -Enter `make -j4 flash monitor` if you are using GNU Make based build system or enter `idf.py build flash monitor` if you are using CMake based build system. +Run `idf.py -p PORT flash monitor` to build and flash the project.. (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/peripherals/i2s/README.md b/examples/peripherals/i2s/README.md index 8f16374f10..a02f3e5e60 100644 --- a/examples/peripherals/i2s/README.md +++ b/examples/peripherals/i2s/README.md @@ -61,7 +61,7 @@ If you have a logic analyzer, you can use a logic analyzer to grab online data. * Program upload failure - * Hardware connection is not correct: run `make monitor`, and reboot your board to see if there are any output logs. + * Hardware connection is not correct: run `idf.py monitor`, and reboot your board to see if there are any output logs. * The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again. For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/i2s_adc_dac/README.md b/examples/peripherals/i2s_adc_dac/README.md index 2d3b05bd94..7d43ef845a 100644 --- a/examples/peripherals/i2s_adc_dac/README.md +++ b/examples/peripherals/i2s_adc_dac/README.md @@ -85,7 +85,7 @@ I2S: PLL_D2: Req RATE: 16000, real rate: 1004.000, BITS: 16, CLKM: 83, BCK: 60, * Program upload failure - * Hardware connection is not correct: run `make monitor`, and reboot your board to see if there are any output logs. + * Hardware connection is not correct: run `idf.py monitor`, and reboot your board to see if there are any output logs. * The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again. For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/ledc/README.md b/examples/peripherals/ledc/README.md index dc8a25c2a3..c66fa19ddc 100644 --- a/examples/peripherals/ledc/README.md +++ b/examples/peripherals/ledc/README.md @@ -63,7 +63,7 @@ you can also see the following output log on the serial monitor: * Programming fail - * Hardware connection is not correct: run `make monitor`, and reboot your board to see if there are any output logs. + * Hardware connection is not correct: run `idf.py monitor`, and reboot your board to see if there are any output logs. * The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again. For any technical queries, please open an [issue] (https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/pcnt/README.md b/examples/peripherals/pcnt/README.md index 4ab5395eba..6e0beb6c07 100644 --- a/examples/peripherals/pcnt/README.md +++ b/examples/peripherals/pcnt/README.md @@ -68,7 +68,7 @@ Current counter value :-1 * program upload failure - * Hardware connection is not correct: run `make monitor`, and reboot your board to see if there are any output logs. + * Hardware connection is not correct: run `idf.py monitor`, and reboot your board to see if there are any output logs. * The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again. For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/rmt_nec_tx_rx/README.md b/examples/peripherals/rmt_nec_tx_rx/README.md index 85f861fdbe..073859111d 100644 --- a/examples/peripherals/rmt_nec_tx_rx/README.md +++ b/examples/peripherals/rmt_nec_tx_rx/README.md @@ -74,7 +74,7 @@ NEC: RMT RCV --- addr: 0xda25 cmd: 0xeb14 * Programming fail - * Hardware connection is not correct: run `make monitor`, and reboot your board to see if there is any output logs. + * Hardware connection is not correct: run `idf.py monitor`, and reboot your board to see if there is any output logs. * The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again. For any technical queries, please open an [issue] (https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/rmt_tx/README.md b/examples/peripherals/rmt_tx/README.md index 3b1cf4a43e..6b7f1ff171 100644 --- a/examples/peripherals/rmt_tx/README.md +++ b/examples/peripherals/rmt_tx/README.md @@ -61,7 +61,7 @@ RMT Tx: Sample transmission complete * Programming fail - * Hardware connection is not correct: run `make monitor`, and reboot your board to see if there is any output logs. + * Hardware connection is not correct: run `idf.py monitor`, and reboot your board to see if there is any output logs. * The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again. For any technical queries, please open an [issue] (https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/uart/nmea0183_parser/README.md b/examples/peripherals/uart/nmea0183_parser/README.md index 6a9ce7859f..105c6a626b 100644 --- a/examples/peripherals/uart/nmea0183_parser/README.md +++ b/examples/peripherals/uart/nmea0183_parser/README.md @@ -39,7 +39,7 @@ To run this example, you need an ESP32 dev board (e.g. ESP32-WROVER Kit) or ESP3 ### Configure the project -Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you are using CMake based build system. Then go into `Example Configuration` menu. +Open the project configuration menu (`idf.py menuconfig`). Then go into `Example Configuration` menu. - Set the size of ring buffer used by uart driver in `NMEA Parser Ring Buffer Size` option. - Set the stack size of the NMEA Parser task in `NMEA Parser Task Stack Size` option. @@ -48,7 +48,7 @@ Enter `make menuconfig` if you are using GNU Make based build system or enter `i ### Build and Flash -Enter `make -j4 flash monitor` if you are using GNU Make based build system or enter `idf.py build flash monitor` if you are using CMake based build system. +Run `idf.py -p PORT flash monitor` to build and flash the project.. (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/protocols/README.md b/examples/protocols/README.md index 0ab0a7628f..3e8570622b 100644 --- a/examples/protocols/README.md +++ b/examples/protocols/README.md @@ -14,7 +14,7 @@ The simple `example_connect()` function does not handle timeouts, does not grace ### Configuring the Example -To configure the example to use Wi-Fi or Ethernet connection, run `make menuconfig` (or `idf.py menuconfig` if using CMake build system) and navigate to "Example Connection Configuration" menu. Select either "Wi-Fi" or "Ethernet" in the "Connect using" choice. +To configure the example to use Wi-Fi or Ethernet connection, open the project configuration menu (`idf.py menuconfig`) and navigate to "Example Connection Configuration" menu. Select either "Wi-Fi" or "Ethernet" in the "Connect using" choice. When connecting using Wi-Fi, enter SSID and password of your Wi-Fi access point into the corresponding fields. If connecting to an open Wi-Fi network, keep the password field empty. diff --git a/examples/protocols/asio/chat_client/README.md b/examples/protocols/asio/chat_client/README.md index 951afad53b..edc4c71897 100644 --- a/examples/protocols/asio/chat_client/README.md +++ b/examples/protocols/asio/chat_client/README.md @@ -5,15 +5,15 @@ Simple Asio chat client using WiFi STA or Ethernet. ## Example workflow - Wi-Fi or Ethernet connection is established, and IP address is obtained. -- Asio chat client connects to the corresponding server whose port number and IP are defined through `make menuconfig`. -- Chat client receives all messages from other chat clients, also it sends message received from stdin using `make monitor`. +- Asio chat client connects to the corresponding server whose port number and IP are defined through the project configuration menu. +- Chat client receives all messages from other chat clients, also it sends message received from stdin using `idf.py monitor`. ## Running the example -- Run `make menuconfig` to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. +- Open the project configuration menu (`idf.py menuconfig`) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. - Set server IP address and port number in menuconfig, "Example configuration". - Start chat server either on host machine or as another ESP device running chat_server example. -- Run `make flash monitor` to build and upload the example to your board and connect to it's serial terminal. +- Run `idf.py -p PORT flash monitor` to build and upload the example to your board and connect to it's serial terminal. - Wait for the board to connect to WiFi or Ethernet. - Receive and send messages to/from other clients on stdin/stdout via serial terminal. diff --git a/examples/protocols/asio/chat_server/README.md b/examples/protocols/asio/chat_server/README.md index e043cba32c..ec8b3e76e3 100644 --- a/examples/protocols/asio/chat_server/README.md +++ b/examples/protocols/asio/chat_server/README.md @@ -5,14 +5,14 @@ Simple Asio chat server using WiFi STA or Ethernet. ## Example workflow - Wi-Fi or Ethernet connection is established, and IP address is obtained. -- Asio chat server is started on port number defined through `make menuconfig`. +- Asio chat server is started on port number defined through the project configuration. - Chat server echoes a message (received from any client) to all connected clients. ## Running the example -- Run `make menuconfig` to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. +- Open project configuration menu (`idf.py menuconfig`) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. - Set server port number in menuconfig, "Example configuration". -- Run `make flash monitor` to build and upload the example to your board and connect to it's serial terminal. +- Run `idf.py -p PORT flash monitor` to build and upload the example to your board and connect to it's serial terminal. - Wait for the board to connect to WiFi or Ethernet (note the IP address). - Connect to the server using multiple clients, for example using any option below. - build and run asi chat client on your host machine diff --git a/examples/protocols/asio/tcp_echo_server/README.md b/examples/protocols/asio/tcp_echo_server/README.md index f672027ef4..b2443a245e 100644 --- a/examples/protocols/asio/tcp_echo_server/README.md +++ b/examples/protocols/asio/tcp_echo_server/README.md @@ -5,14 +5,14 @@ Simple Asio TCP echo server using WiFi STA or Ethernet. ## Example workflow - Wi-Fi or Ethernet connection is established, and IP address is obtained. -- Asio TCP server is started on port number defined through `make menuconfig`. +- Asio TCP server is started on port number defined through the project configuration. - Server receives and echoes back messages transmitted from client. ## Running the example -- Run `make menuconfig` to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. +- Open the project configuration menu (`idf.py menuconfig`) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. - Set server port number in menuconfig, "Example configuration". -- Run `make flash monitor` to build and upload the example to your board and connect to it's serial terminal. +- Run `idf.py -p PORT flash monitor` to build and upload the example to your board and connect to it's serial terminal. - Wait for the board to connect to WiFi or Ethernet (note the IP address). - You can now send a TCP message and check it is repeated, for example using netcat `nc IP PORT`. diff --git a/examples/protocols/asio/udp_echo_server/README.md b/examples/protocols/asio/udp_echo_server/README.md index cc69fee08d..cc8a67e66c 100644 --- a/examples/protocols/asio/udp_echo_server/README.md +++ b/examples/protocols/asio/udp_echo_server/README.md @@ -5,14 +5,14 @@ Simple Asio UDP echo server using WiFi STA or Ethernet. ## Example workflow - Wi-Fi or Ethernet connection is established, and IP address is obtained. -- Asio UDP server is started on port number defined through `make menuconfig` +- Asio UDP server is started on port number defined through the project configuration - Server receives and echoes back messages transmitted from client ## Running the example -- Run `make menuconfig` to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. +- Open the project configuration menu (`idf.py menuconfig`) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. - Set server port number in menuconfig, "Example configuration". -- Run `make flash monitor` to build and upload the example to your board and connect to it's serial terminal. +- Run `idf.py -p PORT flash monitor` to build and upload the example to your board and connect to it's serial terminal. - Wait for the board to connect to WiFi or Ethernet (note the IP address). - You can now send a UDP message and check it is repeated, for example using netcat `nc -u IP PORT`. diff --git a/examples/protocols/coap_client/main/coap_client_example_main.c b/examples/protocols/coap_client/main/coap_client_example_main.c index 38761267f6..921541aef2 100644 --- a/examples/protocols/coap_client/main/coap_client_example_main.c +++ b/examples/protocols/coap_client/main/coap_client_example_main.c @@ -31,7 +31,7 @@ #define COAP_LOGGING_LEVEL 0 /* The examples use uri "coap://californium.eclipse.org" that - you can set via 'make menuconfig'. + you can set via the project configuration (idf.py menuconfig) If you'd rather not, just change the below entries to strings with the config you want - ie #define COAP_DEFAULT_DEMO_URI "coap://californium.eclipse.org" diff --git a/examples/protocols/http_server/file_serving/README.md b/examples/protocols/http_server/file_serving/README.md index 241e0808c5..475cd7b0c7 100644 --- a/examples/protocols/http_server/file_serving/README.md +++ b/examples/protocols/http_server/file_serving/README.md @@ -21,13 +21,13 @@ File server implementation can be found under `main/file_server.c` which uses SP ## Usage -* Configure the project using `make menuconfig` and goto `Example Configuration` -> +* Open the project configuration menu (`idf.py menuconfig`) go to `Example Configuration` -> 1. WIFI SSID: WIFI network to which your PC is also connected to. 2. WIFI Password: WIFI password * In order to test the file server demo : - 1. compile and burn the firmware `make flash` - 2. run `make monitor` and note down the IP assigned to your ESP module. The default port is 80 + 1. compile and burn the firmware `idf.py -p PORT flash` + 2. run `idf.py monitor` and note down the IP assigned to your ESP module. The default port is 80 3. test the example interactively on a web browser (assuming IP is 192.168.43.130): 1. open path `http://192.168.43.130/` or `http://192.168.43.130/index.html` to see an HTML web page with list of files on the server (initially empty) 2. use the file upload form on the webpage to select and upload a file to the server diff --git a/examples/protocols/http_server/persistent_sockets/README.md b/examples/protocols/http_server/persistent_sockets/README.md index ded2cfd6cf..24c82a18a8 100644 --- a/examples/protocols/http_server/persistent_sockets/README.md +++ b/examples/protocols/http_server/persistent_sockets/README.md @@ -3,11 +3,11 @@ The Example consists of HTTPD server persistent sockets demo. This sort of persistency enables the server to have independent sessions/contexts per client. -* Run `make menuconfig` (or `idf.py menuconfig` if using CMake build system) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. +* Open the project configuration menu (`idf.py menuconfig`) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. * In order to test the HTTPD server persistent sockets demo : - 1. compile and burn the firmware "make flash" - 2. run "make monitor" and note down the IP assigned to your ESP module. The default port is 80 + 1. compile and burn the firmware `idf.py -p PORT flash` + 2. run `idf.py -p PORT monitor` and note down the IP assigned to your ESP module. The default port is 80 3. run the test script "python2 scripts/adder.py \ \ \" * the provided test script sends (POST) numbers from 1 to N to the server which has a URI POST handler for adding these numbers into an accumulator that is valid throughout the lifetime of the connection socket, hence persistent * the script does a GET before closing and displays the final value of the accumulator diff --git a/examples/protocols/http_server/restful_server/README.md b/examples/protocols/http_server/restful_server/README.md index 0a2ad7d871..9923d4232c 100644 --- a/examples/protocols/http_server/restful_server/README.md +++ b/examples/protocols/http_server/restful_server/README.md @@ -57,7 +57,7 @@ Only if you deploy the website to SD card, then the following pin connection is ### Configure the project -Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you are using CMake based build system. +Open the project configuration menu (`idf.py menuconfig`). In the `Example Connection Configuration` menu: @@ -88,7 +88,7 @@ npm run build After a while, you will see a `dist` directory which contains all the website files (e.g. html, js, css, images). -Enter `make -j4 flash monitor` if you are using GNU Make based build system or enter `idf.py build flash monitor` if you are using CMake based build system. +Run `idf.py -p PORT flash monitor` to build and flash the project.. (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/protocols/http_server/simple/README.md b/examples/protocols/http_server/simple/README.md index 969c038363..d9e9207fb4 100644 --- a/examples/protocols/http_server/simple/README.md +++ b/examples/protocols/http_server/simple/README.md @@ -4,11 +4,11 @@ The Example consists of HTTPD server demo with demostration of URI handling : 1. URI \hello for GET command returns "Hello World!" message 2. URI \echo for POST command echoes back the POSTed message -* Run `make menuconfig` (or `idf.py menuconfig` if using CMake build system) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. +* Open the project configuration menu (`idf.py menuconfig`) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. * In order to test the HTTPD server persistent sockets demo : - 1. compile and burn the firmware "make flash" - 2. run "make monitor" and note down the IP assigned to your ESP module. The default port is 80 + 1. compile and burn the firmware `idf.py -p PORT flash` + 2. run `idf.py -p PORT monitor` and note down the IP assigned to your ESP module. The default port is 80 3. test the example : * run the test script : "python2 scripts/client.py \ \ \" * the provided test script first does a GET \hello and displays the response diff --git a/examples/protocols/https_server/README.md b/examples/protocols/https_server/README.md index be0ed0d587..088819d2c6 100644 --- a/examples/protocols/https_server/README.md +++ b/examples/protocols/https_server/README.md @@ -4,7 +4,7 @@ This example creates a SSL server that returns a simple HTML page when you visit See the `esp_https_server` component documentation for details. -Before using the example, run `make menuconfig` (or `idf.py menuconfig` if using CMake build system) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../README.md) for more details. +Before using the example, open the project configuration menu (`idf.py menuconfig`) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../README.md) for more details. ## Certificates diff --git a/examples/protocols/mdns/README.md b/examples/protocols/mdns/README.md index 2c35167647..2392699b60 100644 --- a/examples/protocols/mdns/README.md +++ b/examples/protocols/mdns/README.md @@ -4,15 +4,15 @@ Shows how to use mDNS to advertise lookup services and hosts ## Example workflow -- mDNS is initialized with host name and instance name defined through `make menuconfig` and `_http._tcp` service is added to be advertised -- WiFi STA is started and trying to connect to the access point defined through `make menuconfig` +- mDNS is initialized with host name and instance name defined through the project configuration and `_http._tcp` service is added to be advertised +- WiFi STA is started and trying to connect to the access point defined through the project configuration - The system event handler is used to pass the network events to mDNS so the service is aware when the interface comes up or down - GPIO0 (BOOT Button) is initialized as pulled-up input that can be monitored for button press - Example task is started to check if the button is pressed so it can execute the mDNS queries defined ### Configure the project -* Run `make menuconfig` (or `idf.py menuconfig` if using CMake build system) +* Open the project configuration menu (`idf.py menuconfig`) * Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../README.md) for more details. * When using Make build system, set `Default serial port` under `Serial flasher config`. diff --git a/examples/protocols/mqtt/publish_test/README.md b/examples/protocols/mqtt/publish_test/README.md index bdc2bc879d..d3db836410 100644 --- a/examples/protocols/mqtt/publish_test/README.md +++ b/examples/protocols/mqtt/publish_test/README.md @@ -22,7 +22,7 @@ This example can be executed on any ESP32 board, the only required interface is ### Configure the project -* Run `make menuconfig` (or `idf.py menuconfig` if using CMake build system) +* Open the project configuration menu (`idf.py menuconfig`) * Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. * When using Make build system, set `Default serial port` under `Serial flasher config`. * Set brokers for all 4 transports (TCP, SSL, WS, WSS), also set certificate if needed diff --git a/examples/protocols/mqtt/ssl/README.md b/examples/protocols/mqtt/ssl/README.md index 929257d404..5925c4001e 100644 --- a/examples/protocols/mqtt/ssl/README.md +++ b/examples/protocols/mqtt/ssl/README.md @@ -14,7 +14,7 @@ This example can be executed on any ESP32 board, the only required interface is ### Configure the project -* Run `make menuconfig` (or `idf.py menuconfig` if using CMake build system) +* Open the project configuration menu (`idf.py menuconfig`) * Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. * When using Make build system, set `Default serial port` under `Serial flasher config`. diff --git a/examples/protocols/mqtt/ssl_mutual_auth/README.md b/examples/protocols/mqtt/ssl_mutual_auth/README.md index 763e2671ac..9b20b37cad 100644 --- a/examples/protocols/mqtt/ssl_mutual_auth/README.md +++ b/examples/protocols/mqtt/ssl_mutual_auth/README.md @@ -14,7 +14,7 @@ This example can be executed on any ESP32 board, the only required interface is ### Configure the project -* Run `make menuconfig` (or `idf.py menuconfig` if using CMake build system) +* Open the project configuration menu (`idf.py menuconfig`) * Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. * When using Make build system, set `Default serial port` under `Serial flasher config`. diff --git a/examples/protocols/mqtt/tcp/README.md b/examples/protocols/mqtt/tcp/README.md index aea6630944..7247a7a228 100644 --- a/examples/protocols/mqtt/tcp/README.md +++ b/examples/protocols/mqtt/tcp/README.md @@ -14,7 +14,7 @@ This example can be executed on any ESP32 board, the only required interface is ### Configure the project -* Run `make menuconfig` (or `idf.py menuconfig` if using CMake build system) +* Open the project configuration menu (`idf.py menuconfig`) * Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. * When using Make build system, set `Default serial port` under `Serial flasher config`. diff --git a/examples/protocols/mqtt/ws/README.md b/examples/protocols/mqtt/ws/README.md index efe2efcb39..236521f90e 100644 --- a/examples/protocols/mqtt/ws/README.md +++ b/examples/protocols/mqtt/ws/README.md @@ -14,7 +14,7 @@ This example can be executed on any ESP32 board, the only required interface is ### Configure the project -* Run `make menuconfig` (or `idf.py menuconfig` if using CMake build system) +* Open the project configuration menu (`idf.py menuconfig`) * Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. * When using Make build system, set `Default serial port` under `Serial flasher config`. diff --git a/examples/protocols/mqtt/wss/README.md b/examples/protocols/mqtt/wss/README.md index 9433986a51..453d52f70f 100644 --- a/examples/protocols/mqtt/wss/README.md +++ b/examples/protocols/mqtt/wss/README.md @@ -13,7 +13,7 @@ This example can be executed on any ESP32 board, the only required interface is ### Configure the project -* Run `make menuconfig` (or `idf.py menuconfig` if using CMake build system) +* Open the project configuration menu (`idf.py menuconfig`) * Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. * When using Make build system, set `Default serial port` under `Serial flasher config`. diff --git a/examples/protocols/openssl_client/README.md b/examples/protocols/openssl_client/README.md index 07be757195..272060a60c 100644 --- a/examples/protocols/openssl_client/README.md +++ b/examples/protocols/openssl_client/README.md @@ -2,7 +2,7 @@ The Example contains of OpenSSL client demo. -To configure the project, run `make menuconfig` (or `idf.py menuconfig` if using CMake build system). +Open the project configuration menu (`idf.py menuconfig`): * Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../README.md) for more details. diff --git a/examples/protocols/openssl_client/main/openssl_client_example.h b/examples/protocols/openssl_client/main/openssl_client_example.h index 8d1645164a..206d9a91b0 100644 --- a/examples/protocols/openssl_client/main/openssl_client_example.h +++ b/examples/protocols/openssl_client/main/openssl_client_example.h @@ -11,7 +11,7 @@ #define _OPENSSL_EXAMPLE_H_ /* The examples use domain of "www.baidu.com" and port number of 433 that - you can set via 'make menuconfig'. + you can set via the project configuration menu. If you'd rather not, just change the below entries to strings with the config you want - ie #define OPENSSL_EXAMPLE_TARGET_NAME "www.baidu.com" diff --git a/examples/protocols/openssl_server/README.md b/examples/protocols/openssl_server/README.md index 6d4506e933..d304397039 100644 --- a/examples/protocols/openssl_server/README.md +++ b/examples/protocols/openssl_server/README.md @@ -2,7 +2,7 @@ The Example contains of OpenSSL server demo. -To configure the project, run `make menuconfig` (or `idf.py menuconfig` if using CMake build system). +Open the project configuration menu (`idf.py menuconfig`): * Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../README.md) for more details. diff --git a/examples/protocols/pppos_client/README.md b/examples/protocols/pppos_client/README.md index bcfb8e5034..a449a261c7 100644 --- a/examples/protocols/pppos_client/README.md +++ b/examples/protocols/pppos_client/README.md @@ -32,7 +32,7 @@ You can also try other modules as long as they embedded PPP protocol. ### Configure the project -Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you are using CMake based build system. Then go into `Example Configuration` menu. +Open the project configuration menu (`idf.py menuconfig`). Then go into `Example Configuration` menu. - Choose the modem module in `Choose supported modem device(DCE)` option, currently we only support BG96 and SIM800L. - Set the access point name in `Set Access Point Name(APN)` option, which should depend on the operator of your SIM card. @@ -44,7 +44,7 @@ Enter `make menuconfig` if you are using GNU Make based build system or enter `i ### Build and Flash -Enter `make -j4 flash monitor` if you are using GNU Make based build system or enter `idf.py build flash monitor` if you are using CMake based build system. +Run `idf.py -p PORT flash monitor` to build and flash the project.. (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/protocols/sntp/README.md b/examples/protocols/sntp/README.md index 1c3671f3f8..9a7078c47c 100644 --- a/examples/protocols/sntp/README.md +++ b/examples/protocols/sntp/README.md @@ -4,7 +4,7 @@ This example demonstrates the use of LwIP SNTP module to obtain time from Intern ## Configuring the Example -To configure the project, run `make menuconfig` (or `idf.py menuconfig` if using CMake build system). +Open the project configuration menu (`idf.py menuconfig`): * Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../README.md) for more details. diff --git a/examples/protocols/sockets/udp_multicast/README.md b/examples/protocols/sockets/udp_multicast/README.md index 7bc066db07..649bd61195 100644 --- a/examples/protocols/sockets/udp_multicast/README.md +++ b/examples/protocols/sockets/udp_multicast/README.md @@ -12,7 +12,7 @@ The behaviour of the example is: ## Configuration -Run `make menuconfig` (or `idf.py menuconfig` if using CMake build system). +Open the project configuration menu (`idf.py menuconfig`). Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. diff --git a/examples/protocols/sockets/udp_multicast/main/udp_multicast_example_main.c b/examples/protocols/sockets/udp_multicast/main/udp_multicast_example_main.c index ee68788978..ea438991aa 100644 --- a/examples/protocols/sockets/udp_multicast/main/udp_multicast_example_main.c +++ b/examples/protocols/sockets/udp_multicast/main/udp_multicast_example_main.c @@ -25,7 +25,7 @@ #include /* The examples use simple configuration that you can set via - 'make menuconfig'. + project configuration. If you'd rather not, just change the below entries to strings with the config you want - ie #define UDP_PORT 3333 diff --git a/examples/storage/nvs_rw_blob/README.md b/examples/storage/nvs_rw_blob/README.md index 90a8f8bfa9..620edd85e8 100644 --- a/examples/storage/nvs_rw_blob/README.md +++ b/examples/storage/nvs_rw_blob/README.md @@ -19,22 +19,10 @@ If not done already, consider checking simpler example *storage/nvs_rw_value*, t This example can be run on most common development boards which have an active button connected to GPIO0. On most boards, this button is labeled as "Boot". When pressed, the button connects GPIO0 to ground. -### Configure the project - -If using Make based build system, run `make menuconfig` and set serial port under Serial Flasher Options. - -If using CMake based build system, no configuration is required. - ### Build and flash Build the project and flash it to the board, then run monitor tool to view serial output: -``` -make -j4 flash monitor -``` - -Or, for CMake based build system (replace PORT with serial port name): - ``` idf.py -p PORT flash monitor ``` @@ -75,5 +63,5 @@ Run time: 2: 5860 ``` -To reset the counter and run time array, erase the contents of flash memory using `make erase_flash` (or `idf.py erase_flash`, if using CMake build system), then upload the program again as described above. +To reset the counter and run time array, erase the contents of flash memory using `idf.py erase_flash`, then upload the program again as described above. diff --git a/examples/storage/nvs_rw_value/README.md b/examples/storage/nvs_rw_value/README.md index 87d3405d45..df725b0e04 100644 --- a/examples/storage/nvs_rw_value/README.md +++ b/examples/storage/nvs_rw_value/README.md @@ -18,22 +18,10 @@ Check another example *storage/nvs_rw_blob*, which shows how to read and write v This example does not require any special hardware, and can be run on any common development board. -### Configure the project - -If using Make based build system, run `make menuconfig` and set serial port under Serial Flasher Options. - -If using CMake based build system, no configuration is required. - ### Build and flash Build the project and flash it to the board, then run monitor tool to view serial output: -``` -make -j4 flash monitor -``` - -Or, for CMake based build system (replace PORT with serial port name): - ``` idf.py -p PORT flash monitor ``` @@ -90,5 +78,5 @@ Restarting now. Restart counter will increment on each run. -To reset the counter, erase the contents of flash memory using `make erase_flash` (or `idf.py erase_flash`, if using CMake build system), then upload the program again as described above. +To reset the counter, erase the contents of flash memory using `idf.py erase_flash`, then upload the program again as described above. diff --git a/examples/storage/sd_card/README.md b/examples/storage/sd_card/README.md index 09fb2c0cd2..8901c343e9 100644 --- a/examples/storage/sd_card/README.md +++ b/examples/storage/sd_card/README.md @@ -68,12 +68,6 @@ This command will burn the `XPD_SDIO_TIEH`, `XPD_SDIO_FORCE`, and `XPD_SDIO_REG` ## How to use example -### Configure the project - -If using Make based build system, run `make menuconfig` and set serial port under Serial Flasher Options. - -If using CMake based build system, no configuration is required. - SD card can be used in various modes. See below on choosing the mode to be used. ### 4-line and 1-line SD modes @@ -96,16 +90,12 @@ By default, the example uses SDMMC Host peripheral to access the card using SD p Build the project and flash it to the board, then run monitor tool to view serial output: -``` -make -j4 flash monitor -``` - -Or, for CMake based build system (replace PORT with serial port name): - ``` idf.py -p PORT flash monitor ``` +(Replace PORT with serial port name.) + (To exit the serial monitor, type ``Ctrl-]``.) See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. diff --git a/examples/storage/semihost_vfs/README.md b/examples/storage/semihost_vfs/README.md index 4728f08662..d25ed1ab42 100644 --- a/examples/storage/semihost_vfs/README.md +++ b/examples/storage/semihost_vfs/README.md @@ -25,21 +25,9 @@ bin/openocd -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -c ' ``` This command also configures OpenOCD to expose example project `data` subdirectory to the target's semihosting VFS driver. -### Configure the project - -If using Make based build system, run `make menuconfig` and set serial port under Serial Flasher Options. - -If using CMake based build system, no configuration is required. - ### Build and flash -Build the project and flash it to the board, then run monitor tool to view serial output: - -``` -make -j4 flash monitor -``` - -Or, for CMake based build system (replace PORT with serial port name): +Replace PORT with serial port name: ``` idf.py -p PORT flash monitor diff --git a/examples/storage/spiffs/README.md b/examples/storage/spiffs/README.md index aacced044e..d568839563 100644 --- a/examples/storage/spiffs/README.md +++ b/examples/storage/spiffs/README.md @@ -20,21 +20,9 @@ SPIFFS partition size is set in partitions_example.csv file. See [Partition Tabl This example does not require any special hardware, and can be run on any common development board. -### Configure the project - -If using Make based build system, run `make menuconfig` and set serial port under Serial Flasher Options. - -If using CMake based build system, no configuration is required. - ### Build and flash -Build the project and flash it to the board, then run monitor tool to view serial output: - -``` -make -j4 flash monitor -``` - -Or, for CMake based build system (replace PORT with serial port name): +Replace PORT with serial port name: ``` idf.py -p PORT flash monitor @@ -60,4 +48,4 @@ I (19584) example: Read from file: 'Hello World!' I (19584) example: SPIFFS unmounted ``` -To erase the contents of SPIFFS partition, run `make erase_flash` command (or `idf.py erase_flash`, if using CMake build system). Then upload the example again as described above. +To erase the contents of SPIFFS partition, run `idf.py erase_flash` command. Then upload the example again as described above. diff --git a/examples/storage/spiffsgen/README.md b/examples/storage/spiffsgen/README.md index fcacb6bbdf..1176d343d5 100644 --- a/examples/storage/spiffsgen/README.md +++ b/examples/storage/spiffsgen/README.md @@ -4,7 +4,7 @@ This example demonstrates how to use the SPIFFS image generation tool [spiffsgen.py](../../../components/spiffs/spiffsgen.py) to automatically create a SPIFFS filesystem image from the contents of a host folder during build, with an option of -automatically flashing the created image on invocation of `idf.py flash` or `make flash`. +automatically flashing the created image on invocation of `idf.py flash`. For more information, see description of `spiffsgen.py` on the ESP-IDF Programming Guide under API Reference > Storage > SPIFFS Filesystem. The following gives an overview of the example: @@ -14,10 +14,10 @@ The following gives an overview of the example: 2. The function `spiffs_create_partition_image` is used to specify that a SPIFFS image should be created during build for the `storage` partition. For CMake, it is called from [the main component's CMakeLists.txt](./main/CMakeLists.txt); for Make, from the [project Makefile](./Makefile). `FLASH_IN_PROJECT` specifies that the created image -should be flashed on invocation of `idf.py flash` or `make flash` together with app, bootloader, partition table, etc. +should be flashed on invocation of `idf.py flash` together with app, bootloader, partition table, etc. For both build systems, the image is created on the example's build directory with the output filename `storage.bin`. -3. Upon invocation of `idf.py flash monitor` or `make flash monitor`, application loads and +3. Upon invocation of `idf.py flash monitor`, application loads and finds there is already a valid SPIFFS filesystem in the `storage` partition with files same as those in `spiffs_image` directory. The application is then able to read those files. @@ -56,4 +56,4 @@ I (330) example: Computed MD5 hash of alice.txt: deeb71f585cbb3ae5f7976d5127faf2 I (330) example: SPIFFS unmounted ``` -The logic of the example is contained in a [single source file](./main/spiffsgen_example_main.c), and it should be relatively simple to match points in its execution with the log outputs above. \ No newline at end of file +The logic of the example is contained in a [single source file](./main/spiffsgen_example_main.c), and it should be relatively simple to match points in its execution with the log outputs above. diff --git a/examples/storage/wear_levelling/README.md b/examples/storage/wear_levelling/README.md index 9bf11ded46..9578e16444 100644 --- a/examples/storage/wear_levelling/README.md +++ b/examples/storage/wear_levelling/README.md @@ -20,26 +20,16 @@ Wear levelling partition size is set in partitions_example.csv file. See [Partit This example does not require any special hardware, and can be run on any common development board. -### Configure the project - -If using Make based build system, run `make menuconfig` and set serial port under Serial Flasher Options. - -If using CMake based build system, no configuration is required. - ### Build and flash Build the project and flash it to the board, then run monitor tool to view serial output: -``` -make -j4 flash monitor -``` - -Or, for CMake based build system (replace PORT with serial port name): - ``` idf.py -p PORT flash monitor ``` +(Replace PORT with serial port name.) + (To exit the serial monitor, type ``Ctrl-]``.) See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. @@ -61,4 +51,4 @@ I (920) example: Unmounting FAT filesystem I (1000) example: Done ``` -To erase the contents of wear levelling partition, run `make erase_flash` command (or `idf.py erase_flash`, if using CMake build system). Then upload the example again as described above. +To erase the contents of wear levelling partition, run `idf.py erase_flash` command. Then upload the example again as described above. diff --git a/examples/system/app_trace_to_host/README.md b/examples/system/app_trace_to_host/README.md index 1abb8bde6a..aa5786242d 100644 --- a/examples/system/app_trace_to_host/README.md +++ b/examples/system/app_trace_to_host/README.md @@ -99,7 +99,7 @@ To run this example, you need an ESP32 dev board (e.g. [ESP-WROVER-KIT](https:// ### Configure the project -Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you are using CMake based build system. Then go into `Example Configuration` menu. +Open the project configuration menu (`idf.py menuconfig`). Then go into `Example Configuration` menu. - By default, the DAC will generate 130 Hz signal within 0V..3.1V. To get 50Hz, you need to set non-standard driver of RTC 8MHz clock to lower minimum CW (Cosine Waveform) generator's frequency in `Set custom RTC 8 MHz clock divider to lower CW frequency`. @@ -107,7 +107,7 @@ Enter `make menuconfig` if you are using GNU Make based build system or enter `i ### Build, Flash and Run -1. Enter `make -j4 flash monitor` if you are using GNU Make based build system or enter `idf.py build flash monitor` if you are using CMake based build system. (To exit the serial monitor, type ``Ctrl-]``.) +1. Run `idf.py -p PORT flash monitor` to build and flash the project.. (To exit the serial monitor, type ``Ctrl-]``.) See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects. 2. In the telnet session window, run the following command. This command will collect 9000 bytes of log data and save them to `adc.log` file in `~/esp/openocd-esp32` folder. diff --git a/examples/system/cpp_exceptions/README.md b/examples/system/cpp_exceptions/README.md index 2056379edf..0589d885df 100644 --- a/examples/system/cpp_exceptions/README.md +++ b/examples/system/cpp_exceptions/README.md @@ -12,17 +12,13 @@ Example source code declares a class which can throw exception from the construc ## How to use example -### Configure the project - -Run `make menuconfig` and set serial port under Serial Flasher Options. - ### Build and Flash -Build the project and flash it to the board, then run monitor tool to view serial output: +``` +idf.py -p PORT flash monitor +``` -``` -make -j4 flash monitor -``` +(Replace PORT with the name of the serial port.) (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/system/gcov/main/gcov_example.c b/examples/system/gcov/main/gcov_example.c index 1cfa9ea534..e6d7457680 100644 --- a/examples/system/gcov/main/gcov_example.c +++ b/examples/system/gcov/main/gcov_example.c @@ -13,8 +13,8 @@ #include "esp_app_trace.h" #include "sdkconfig.h" -/* Can run 'make menuconfig' to choose the GPIO to blink, - or you can edit the following line and set a number here. +/* Can use project configuration menu (idf.py menuconfig) to choose the GPIO + to blink, or you can edit the following line and set a number here. */ #define BLINK_GPIO CONFIG_BLINK_GPIO diff --git a/examples/system/light_sleep/README.md b/examples/system/light_sleep/README.md index 2fa545dae6..bdc107cf43 100644 --- a/examples/system/light_sleep/README.md +++ b/examples/system/light_sleep/README.md @@ -17,18 +17,16 @@ The example also prints time spent in light sleep mode to illustrate that timeke This example can be used with any ESP32 development board. Most boards have a button attached to GPIO0, often labelled "BOOT". If the board does not have such button, an external button can be connected, along with a 10k pull-up resistor, and a 100nF capacitor to ground for debouncing. -### Configure the Project - -Run `make menuconfig` and set serial port under Serial Flasher Options. - ### Build and Flash Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` +(Replace PORT with the name of the serial port to use.) + (To exit the serial monitor, type ``Ctrl-]``.) See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. diff --git a/examples/system/ota/README.md b/examples/system/ota/README.md index f9baa4c4bc..0baf9d048d 100644 --- a/examples/system/ota/README.md +++ b/examples/system/ota/README.md @@ -27,7 +27,7 @@ To run the OTA examples, you need an ESP32 dev board (e.g. ESP32-WROVER Kit) or ### Configure the project -Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you are using CMake based build system. +Open the project configuration menu (`idf.py menuconfig`). In the `Example Connection Configuration` menu: @@ -44,7 +44,7 @@ In the `Example Configuration` menu: ### Build and Flash -Enter `make -j4 flash monitor` if you are using GNU Make based build system or enter `idf.py build flash monitor` if you are using CMake based build system. This command will find if partition table has ota_data partition (as in our case) then ota_data will erase to initial. It allows to run the newly loaded app from a factory partition. +Run `idf.py -p PORT flash monitor` to build and flash the project.. This command will find if partition table has ota_data partition (as in our case) then ota_data will erase to initial. It allows to run the newly loaded app from a factory partition. (To exit the serial monitor, type ``Ctrl-]``.) @@ -85,7 +85,7 @@ When the example starts up, it will print "Starting OTA example" to the console 3. Write the image to flash, and configure the next boot from this image. 4. Reboot -If you want to rollback to factory app (or the first OTA partition when the factory partition do not exist) after the upgrade, then run the command `make erase_otadata` or `idf.py erase_otadata`. It can erase the ota_data partition to initial state. +If you want to rollback to factory app (or the first OTA partition when the factory partition do not exist) after the upgrade, then run the command `idf.py erase_otadata`. It can erase the ota_data partition to initial state. **Notes:** This assumes that the partition table of this project is the one that is on the device. @@ -127,4 +127,4 @@ In ``native_ota_example``, ``$PROJECT_PATH/version.txt`` is used to define the v If you see this error then check that the configured (and actual) flash size is large enough for the partitions in the partition table. The default "two OTA slots" partition table only works with 4MB flash size. To use OTA with smaller flash sizes, create a custom partition table CSV (look in components/partition_table) and configure it in menuconfig. -If changing partition layout, it is usually wise to run "make erase_flash" between steps. +If changing partition layout, it is usually wise to run "idf.py erase_flash" between steps. diff --git a/examples/system/sysview_tracing_heap_log/README.md b/examples/system/sysview_tracing_heap_log/README.md index 8d39311644..8e4dfad63e 100644 --- a/examples/system/sysview_tracing_heap_log/README.md +++ b/examples/system/sysview_tracing_heap_log/README.md @@ -19,26 +19,14 @@ when program hits breakpoint at `heap_trace_start`. Trace data will be saved to 3. [SEGGER SystemView tool](https://www.segger.com/products/development-tools/systemview/). By default SystemView shows only numeric values of IDs and parameters for IDF's heap messages in `Events` view. To make them pretty-looking you need to copy `SYSVIEW_FreeRTOS.txt` from the project's root directory to SystemView installation one. -### Configure the project - -If using Make based build system, run `make menuconfig` and set serial port under Serial Flasher Options. - -If using CMake based build system, no configuration is required. - ### Build and flash -Build the project and flash it to the board, then run monitor tool to view serial output: - -``` -make -j4 flash monitor -``` - -Or, for CMake based build system (replace PORT with serial port name): - ``` idf.py -p PORT flash monitor ``` +(Replace PORT with serial port name.) + (To exit the serial monitor, type ``Ctrl-]``.) See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. @@ -161,4 +149,4 @@ Processed 14 heap events. /home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1) Found 10 leaked bytes in 4 blocks. -``` \ No newline at end of file +``` diff --git a/examples/system/unit_test/README.md b/examples/system/unit_test/README.md index acea22d5cf..fbba3cf426 100644 --- a/examples/system/unit_test/README.md +++ b/examples/system/unit_test/README.md @@ -55,9 +55,7 @@ This example doesn't require any special hardware, and can run on any ESP32 deve As explained above, this example contains two projects: application project and test project. -When using Make based build system, run `make menuconfig` and set serial port under Serial Flasher Options, in each of these projects. - -For the test project, you can explore a few options related to Unity under Component Config, Unity unit testing library. +For the test project, you can open the project configuration menu (`idf.py menuconfig`) and explore a few options related to Unity under Component Config, Unity unit testing library. ### Build and flash @@ -65,12 +63,12 @@ As explained above, this example contains two projects: application project and 1. Application project calls an API defined in the component, and displays the results. It is not of much value to run. Application project is provided mainly to illustrate the layout of all the files. If you decide to run this project, the procedure is: - * Run `make -j4 flash monitor` in the current directory (`unit_test`), or `idf.py -p PORT flash monitor` if you are using CMake build system. + * Run `idf.py -p PORT flash monitor` in the current directory (`unit_test`). * Observe the output: a list of random numbers and their mean value. 2. Test project is responsible for running the tests. - * Enter `test` directory (`unit_test/test`), and run `make -j4 flash monitor`, or `idf.py -p PORT flash monitor` if you are using CMake build system. + * Enter `test` directory (`unit_test/test`), and run `idf.py -p PORT flash monitor`. * Observe the output: results of test case execution. diff --git a/examples/wifi/getting_started/softAP/main/softap_example_main.c b/examples/wifi/getting_started/softAP/main/softap_example_main.c index 515e3618ee..0102895545 100644 --- a/examples/wifi/getting_started/softAP/main/softap_example_main.c +++ b/examples/wifi/getting_started/softAP/main/softap_example_main.c @@ -18,7 +18,7 @@ #include "lwip/err.h" #include "lwip/sys.h" -/* The examples use WiFi configuration that you can set via 'make menuconfig'. +/* The examples use WiFi configuration that you can set via project configuration menu. If you'd rather not, just change the below entries to strings with the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid" diff --git a/examples/wifi/getting_started/station/main/station_example_main.c b/examples/wifi/getting_started/station/main/station_example_main.c index 917f53cdbb..ae6101f2d4 100644 --- a/examples/wifi/getting_started/station/main/station_example_main.c +++ b/examples/wifi/getting_started/station/main/station_example_main.c @@ -19,7 +19,7 @@ #include "lwip/err.h" #include "lwip/sys.h" -/* The examples use WiFi configuration that you can set via 'make menuconfig'. +/* The examples use WiFi configuration that you can set via project configuration menu If you'd rather not, just change the below entries to strings with the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid" diff --git a/examples/wifi/scan/main/scan.c b/examples/wifi/scan/main/scan.c index 9607d61147..f5b0d29fd5 100644 --- a/examples/wifi/scan/main/scan.c +++ b/examples/wifi/scan/main/scan.c @@ -28,7 +28,7 @@ #include "esp_event.h" #include "nvs_flash.h" -/*Set the SSID and Password via "make menuconfig"*/ +/* Set the SSID and Password via project configuration, or can set directly here */ #define DEFAULT_SSID CONFIG_EXAMPLE_WIFI_SSID #define DEFAULT_PWD CONFIG_EXAMPLE_WIFI_PASSWORD diff --git a/examples/wifi/simple_sniffer/README.md b/examples/wifi/simple_sniffer/README.md index bf38632507..7c8ba2d4a9 100644 --- a/examples/wifi/simple_sniffer/README.md +++ b/examples/wifi/simple_sniffer/README.md @@ -19,7 +19,7 @@ If you want to send packets to host, make sure to connect ESP32 to some kind of ### Configure the project -Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you are using CMake based build system. Then go into `Example Configuration` menu. +Open the project configuration menu (`idf.py menuconfig`). Then go into `Example Configuration` menu. - Check `Store command history in flash` if you want to save command history into flash (recommend). - Select where to save the pcap file in `Select destination to store pcap file` menu item. @@ -33,7 +33,11 @@ Enter `make menuconfig` if you are using GNU Make based build system or enter `i ### Build and Flash -Enter `make -j4 flash monitor` if you are using GNU Make based build system or enter `idf.py build flash monitor` if you' are using CMake based build system. +``` +idf.py -p PORT flash monitor +``` + +(Replace PORT with name of the serial port.) (To exit the serial monitor, type ``Ctrl-]``.) @@ -114,7 +118,7 @@ I (248800) example: Card unmounted ### Steps for sending packets to host via JTAG interface 1. Select `JTAG (App Trace)` as the destination of pcap files. -2. Build & Flash with `idf.py build flash` or `make flash`. +2. Build & Flash with `idf.py -p PORT flash` 3. Connect JTAG, run OpenOCD (for more information about how-to please refer to [JTAG Debugging](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/jtag-debugging/index.html)). 4. Telnet to localhost with 4444 port: `telnet localhost 4444`. 5. In the telnet session, run command like `esp32 apptrace start file://sniffer-esp32.pcap 1 -1 20` (more information about this command, please refer to [apptrace command](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/app_trace.html#openocd-application-level-tracing-commands)). diff --git a/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c b/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c index e2127d84ba..232065c4b5 100644 --- a/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c +++ b/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c @@ -30,12 +30,12 @@ #include "tcpip_adapter.h" /* The examples use simple WiFi configuration that you can set via - 'make menuconfig'. + project configuration menu. If you'd rather not, just change the below entries to strings with the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid" - You can choose EAP method via 'make menuconfig' according to the + You can choose EAP method via project configuration according to the configuration of AP. */ #define EXAMPLE_WIFI_SSID CONFIG_EXAMPLE_WIFI_SSID diff --git a/examples/wifi/wps/main/wps.c b/examples/wifi/wps/main/wps.c index 62465e2de6..5ac103b7f1 100644 --- a/examples/wifi/wps/main/wps.c +++ b/examples/wifi/wps/main/wps.c @@ -29,7 +29,7 @@ #include "nvs_flash.h" -/*set wps mode via "make menuconfig"*/ +/*set wps mode via project configuration */ #if CONFIG_EXAMPLE_WPS_TYPE_PBC #define WPS_MODE WPS_TYPE_PBC #elif CONFIG_EXAMPLE_WPS_TYPE_PIN diff --git a/tools/esp_app_trace/test/sysview/blink.c b/tools/esp_app_trace/test/sysview/blink.c index ecbdf64499..baa345be47 100644 --- a/tools/esp_app_trace/test/sysview/blink.c +++ b/tools/esp_app_trace/test/sysview/blink.c @@ -13,8 +13,8 @@ #include "sdkconfig.h" #include "esp_heap_trace.h" -/* Can run 'make menuconfig' to choose the GPIO to blink, - or you can edit the following line and set a number here. +/* Can use project configuration menu (idf.py menuconfig) to choose the GPIO + to blink or you can edit the following line and set a number here. */ #define BLINK_GPIO CONFIG_BLINK_GPIO diff --git a/tools/idf_monitor.py b/tools/idf_monitor.py index 4700980b0b..f68020613f 100755 --- a/tools/idf_monitor.py +++ b/tools/idf_monitor.py @@ -3,8 +3,8 @@ # 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 (or idf.py) flash" (Ctrl-T Ctrl-F) -# - Run "make (or idf.py) app-flash" (Ctrl-T Ctrl-A) +# - Run flash build target to rebuild and flash entire project (Ctrl-T Ctrl-F) +# - Run app-flash build target to rebuild and flash app only (Ctrl-T Ctrl-A) # - If gdbstub output is detected, gdb is automatically loaded # # Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD diff --git a/tools/unit-test-app/README.md b/tools/unit-test-app/README.md index 23ce65289b..0118fc624f 100644 --- a/tools/unit-test-app/README.md +++ b/tools/unit-test-app/README.md @@ -4,16 +4,6 @@ ESP-IDF unit tests are run using Unit Test App. The app can be built with the un # Building Unit Test App -## GNU Make - -* Follow the setup instructions in the top-level esp-idf README. -* Set IDF_PATH environment variable to point to the path to the esp-idf top-level directory. -* Change into `tools/unit-test-app` directory -* `make menuconfig` to configure the Unit Test App. -* `make TEST_COMPONENTS=` with `TEST_COMPONENTS` set to names of the components to be included in the test app. Or `make TESTS_ALL=1` to build the test app with all the tests for components having `test` subdirectory. -* Follow the printed instructions to flash, or run `make flash`. -* Unit test have a few preset sdkconfigs. It provides command `make ut-clean-config_name` and `make ut-build-config_name` (where `config_name` is the file name under `unit-test-app/configs` folder) to build with preset configs. For example, you can use `make ut-build-default TESTS_ALL=1` to build with config file `unit-test-app/configs/default`. Built binary for this config will be copied to `unit-test-app/output/config_name` folder. - ## CMake * Follow the setup instructions in the top-level esp-idf README. @@ -24,6 +14,16 @@ ESP-IDF unit tests are run using Unit Test App. The app can be built with the un * Follow the printed instructions to flash, or run `idf.py -p PORT flash`. * Unit test have a few preset sdkconfigs. It provides command `idf.py ut-clean-config_name` and `idf.py ut-build-config_name` (where `config_name` is the file name under `unit-test-app/configs` folder) to build with preset configs. For example, you can use `idf.py -T all ut-build-default` to build with config file `unit-test-app/configs/default`. Built binary for this config will be copied to `unit-test-app/output/config_name` folder. +## Legacy GNU Make + +* Follow the setup instructions in the top-level esp-idf README. +* Set IDF_PATH environment variable to point to the path to the esp-idf top-level directory. +* Change into `tools/unit-test-app` directory +* `make menuconfig` to configure the Unit Test App. +* `make TEST_COMPONENTS=` with `TEST_COMPONENTS` set to names of the components to be included in the test app. Or `make TESTS_ALL=1` to build the test app with all the tests for components having `test` subdirectory. +* Follow the printed instructions to flash, or run `make flash`. +* Unit test have a few preset sdkconfigs. It provides command `make ut-clean-config_name` and `make ut-build-config_name` (where `config_name` is the file name under `unit-test-app/configs` folder) to build with preset configs. For example, you can use `make ut-build-default TESTS_ALL=1` to build with config file `unit-test-app/configs/default`. Built binary for this config will be copied to `unit-test-app/output/config_name` folder. + # Flash Size The unit test partition table assumes a 4MB flash size. When testing `TESTS_ALL=1` (Make) or `-T all` (CMake), this additional factory app partition size is required. From 86dbe9299ae33524e6da543a9af9b4d29c2f9fa3 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Sun, 23 Jun 2019 12:07:06 +1000 Subject: [PATCH 283/486] docs: Load page redirects from a file instead of inline in config --- docs/conf_common.py | 28 +++++++++------------------- docs/page_redirects.txt | 25 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 19 deletions(-) create mode 100644 docs/page_redirects.txt diff --git a/docs/conf_common.py b/docs/conf_common.py index 8bd4eb988e..8fd13cbaf2 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -18,6 +18,7 @@ from __future__ import print_function from __future__ import unicode_literals import sys import os +import re import subprocess # Note: If extensions (or modules to document with autodoc) are in another directory, @@ -235,25 +236,14 @@ pygments_style = 'sphinx' # Custom added feature to allow redirecting old URLs # -# list of tuples (old_url, new_url) for pages to redirect -# (URLs should be relative to document root, only) -html_redirect_pages = [('api-reference/ethernet/index', 'api-reference/network/index'), - ('api-reference/ethernet/esp_eth', 'api-reference/network/esp_eth'), - ('api-reference/mesh/index', 'api-reference/network/index'), - ('api-reference/mesh/esp_mesh', 'api-reference/network/esp_mesh'), - ('api-reference/wifi/index', 'api-reference/network/index'), - ('api-reference/wifi/esp_now', 'api-reference/network/esp_now'), - ('api-reference/wifi/esp_smartconfig', 'api-reference/network/esp_smartconfig'), - ('api-reference/wifi/esp_wifi', 'api-reference/network/esp_wifi'), - ('api-reference/system/tcpip_adapter', 'api-reference/network/tcpip_adapter'), - ('get-started/idf-monitor', 'api-guides/tools/idf-monitor'), - ('get-started-cmake/idf-monitor', 'api-guides/tools/idf-monitor'), - ('get-started/get-started-devkitc', 'hw-reference/get-started-devkitc'), - ('get-started/get-started-wrover-kit', 'hw-reference/get-started-wrover-kit'), - ('get-started/get-started-pico-kit', 'hw-reference/get-started-pico-kit'), - ('get-started-cmake/get-started-devkitc', 'hw-reference/get-started-devkitc'), - ('get-started-cmake/get-started-wrover-kit', 'hw-reference/get-started-wrover-kit'), - ('get-started-cmake/get-started-pico-kit', 'hw-reference/get-started-pico-kit')] +# Redirects should be listed in page_redirects.xt +# +with open("../page_redirects.txt") as f: + lines = [re.sub(" +", " ", l.strip()) for l in f.readlines() if l.strip() != "" and not l.startswith("#")] + for line in lines: # check for well-formed entries + if len(line.split(' ')) != 2: + raise RuntimeError("Invalid line in page_redirects.txt: %s" % line) +html_redirect_pages = [tuple(l.split(' ')) for l in lines] # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. diff --git a/docs/page_redirects.txt b/docs/page_redirects.txt new file mode 100644 index 0000000000..c1ffdf1397 --- /dev/null +++ b/docs/page_redirects.txt @@ -0,0 +1,25 @@ +# Redirects from "old URL" "new URL" +# +# Space delimited +# +# New URL should be relative to document root, only) +# +# Empty lines and lines starting with # are ignored + +api-reference/ethernet/index api-reference/network/index +api-reference/ethernet/esp_eth api-reference/network/esp_eth +api-reference/mesh/index api-reference/network/index +api-reference/mesh/esp_mesh api-reference/network/esp_mesh +api-reference/wifi/index api-reference/network/index +api-reference/wifi/esp_now api-reference/network/esp_now +api-reference/wifi/esp_smartconfig api-reference/network/esp_smartconfig +api-reference/wifi/esp_wifi api-reference/network/esp_wifi +api-reference/system/tcpip_adapter api-reference/network/tcpip_adapter +get-started/idf-monitor api-guides/tools/idf-monitor +get-started-cmake/idf-monitor api-guides/tools/idf-monitor +get-started/get-started-devkitc hw-reference/get-started-devkitc +get-started/get-started-wrover-kit hw-reference/get-started-wrover-kit +get-started/get-started-pico-kit hw-reference/get-started-pico-kit +get-started-cmake/get-started-devkitc hw-reference/get-started-devkitc +get-started-cmake/get-started-wrover-kit hw-reference/get-started-wrover-kit +get-started-cmake/get-started-pico-kit hw-reference/get-started-pico-kit From 62ed221dafdd94077cd251d449c65de0b46502d5 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 25 Jun 2019 11:29:49 +1000 Subject: [PATCH 284/486] docs: Functional renaming commit for CMake-as-default Rename all the files which will be edited substantially in the next commit, without changing their contents Docs will not build for this ocmmit. This is done so that git doesn't decide we renamed xxx-cmake -> xxx-legacy in the next commit, which is what it will infer otherwise (and makes rebasing more of a pain than it should be) --- docs/en/api-guides/build-system-cmake.rst | 1311 ---------------- docs/en/api-guides/build-system-legacy.rst | 650 ++++++++ docs/en/api-guides/build-system.rst | 1387 ++++++++++++----- .../{ulp-cmake.rst => ulp-legacy.rst} | 52 +- docs/en/api-guides/ulp.rst | 52 +- ...-tests-cmake.rst => unit-tests-legacy.rst} | 57 +- docs/en/api-guides/unit-tests.rst | 57 +- .../add-idf_path-to-profile.rst | 3 - docs/en/get-started-cmake/eclipse-setup.rst | 12 - docs/en/get-started-cmake/index.rst | 491 ------ .../get-started-cmake/linux-setup-scratch.rst | 77 - docs/en/get-started-cmake/linux-setup.rst | 68 - .../get-started-cmake/macos-setup-scratch.rst | 88 -- docs/en/get-started-cmake/macos-setup.rst | 60 - .../windows-setup-scratch.rst | 122 -- docs/en/get-started-cmake/windows-setup.rst | 70 - .../get-started/add-idf_path-to-profile.rst | 65 + .../get-started/eclipse-setup.rst | 109 ++ .../establish-serial-connection.rst | 20 +- .../get-started-legacy/get-started/index.rst | 452 ++++++ .../get-started/linux-setup-scratch.rst | 75 + .../get-started/linux-setup.rst | 118 ++ .../get-started/macos-setup-scratch.rst | 72 + .../get-started/macos-setup.rst | 57 + .../get-started/make-project.rst | 0 .../get-started}/toolchain-setup-scratch.rst | 12 +- .../get-started/windows-setup-scratch.rst | 117 ++ .../get-started/windows-setup.rst | 70 + .../get-started/add-idf_path-to-profile.rst | 66 +- docs/en/get-started/eclipse-setup.rst | 109 +- .../establish-serial-connection.rst | 20 +- docs/en/get-started/index.rst | 359 +++-- docs/en/get-started/linux-setup-scratch.rst | 38 +- docs/en/get-started/linux-setup.rst | 78 +- docs/en/get-started/macos-setup-scratch.rst | 50 +- docs/en/get-started/macos-setup.rst | 69 +- .../get-started/toolchain-setup-scratch.rst | 12 +- docs/en/get-started/windows-setup-scratch.rst | 201 +-- .../windows-setup-update.rst | 0 docs/en/get-started/windows-setup.rst | 74 +- .../hw-reference/get-started-devkitc-v2.rst | 8 +- docs/en/hw-reference/get-started-devkitc.rst | 15 +- .../hw-reference/get-started-pico-kit-v3.rst | 6 +- docs/en/hw-reference/get-started-pico-kit.rst | 34 +- .../get-started-wrover-kit-v2.rst | 18 +- .../get-started-wrover-kit-v3.rst | 49 +- .../hw-reference/get-started-wrover-kit.rst | 48 +- 47 files changed, 3483 insertions(+), 3495 deletions(-) delete mode 100644 docs/en/api-guides/build-system-cmake.rst create mode 100644 docs/en/api-guides/build-system-legacy.rst rename docs/en/api-guides/{ulp-cmake.rst => ulp-legacy.rst} (80%) rename docs/en/api-guides/{unit-tests-cmake.rst => unit-tests-legacy.rst} (77%) delete mode 100644 docs/en/get-started-cmake/add-idf_path-to-profile.rst delete mode 100644 docs/en/get-started-cmake/eclipse-setup.rst delete mode 100644 docs/en/get-started-cmake/index.rst delete mode 100644 docs/en/get-started-cmake/linux-setup-scratch.rst delete mode 100644 docs/en/get-started-cmake/linux-setup.rst delete mode 100644 docs/en/get-started-cmake/macos-setup-scratch.rst delete mode 100644 docs/en/get-started-cmake/macos-setup.rst delete mode 100644 docs/en/get-started-cmake/windows-setup-scratch.rst delete mode 100644 docs/en/get-started-cmake/windows-setup.rst create mode 100644 docs/en/get-started-legacy/get-started/add-idf_path-to-profile.rst create mode 100644 docs/en/get-started-legacy/get-started/eclipse-setup.rst rename docs/en/{get-started-cmake => get-started-legacy/get-started}/establish-serial-connection.rst (84%) create mode 100644 docs/en/get-started-legacy/get-started/index.rst create mode 100644 docs/en/get-started-legacy/get-started/linux-setup-scratch.rst create mode 100644 docs/en/get-started-legacy/get-started/linux-setup.rst create mode 100644 docs/en/get-started-legacy/get-started/macos-setup-scratch.rst create mode 100644 docs/en/get-started-legacy/get-started/macos-setup.rst rename docs/en/{ => get-started-legacy}/get-started/make-project.rst (100%) rename docs/en/{get-started-cmake => get-started-legacy/get-started}/toolchain-setup-scratch.rst (72%) create mode 100644 docs/en/get-started-legacy/get-started/windows-setup-scratch.rst create mode 100644 docs/en/get-started-legacy/get-started/windows-setup.rst rename docs/en/{get-started-cmake => get-started}/windows-setup-update.rst (100%) diff --git a/docs/en/api-guides/build-system-cmake.rst b/docs/en/api-guides/build-system-cmake.rst deleted file mode 100644 index ec63c0fc41..0000000000 --- a/docs/en/api-guides/build-system-cmake.rst +++ /dev/null @@ -1,1311 +0,0 @@ -Build System (CMake) -******************** - -:link_to_translation:`zh_CN:[中文]` - -.. include:: ../cmake-warning.rst - -.. include:: ../cmake-pending-features.rst - -This document explains the implementation of the CMake-based ESP-IDF build system and the concept of "components". :doc:`Documentation for the GNU Make based build system ` is also available - -Read this document if you want to know how to organise and build a new ESP-IDF project or component using the CMake-based build system. - - -Overview -======== - -An ESP-IDF project can be seen as an amalgamation of a number of components. -For example, for a webserver that shows the current humidity, there could be: - -- The ESP32 base libraries (libc, ROM bindings, etc) -- The WiFi drivers -- A TCP/IP stack -- The FreeRTOS operating system -- A webserver -- A driver for the humidity sensor -- Main code tying it all together - -ESP-IDF makes these components explicit and configurable. To do that, -when a project is compiled, the build system will look up all the -components in the ESP-IDF directories, the project directories and -(optionally) in additional custom component directories. It then -allows the user to configure the ESP-IDF project using a a text-based -menu system to customize each component. After the components in the -project are configured, the build system will compile the project. - -Concepts --------- - -- A "project" is a directory that contains all the files and configuration to build a single "app" (executable), as well as additional supporting elements such as a partition table, data/filesystem partitions, and a bootloader. - -- "Project configuration" is held in a single file called ``sdkconfig`` in the root directory of the project. This configuration file is modified via ``idf.py menuconfig`` to customise the configuration of the project. A single project contains exactly one project configuration. - -- An "app" is an executable which is built by ESP-IDF. A single project will usually build two apps - a "project app" (the main executable, ie your custom firmware) and a "bootloader app" (the initial bootloader program which launches the project app). - -- "components" are modular pieces of standalone code which are compiled into static libraries (.a files) and linked into an app. Some are provided by ESP-IDF itself, others may be sourced from other places. - -- "Target" is the hardware for which an application is built. At the moment, ESP-IDF supports only one target, ``esp32``. - -Some things are not part of the project: - -- "ESP-IDF" is not part of the project. Instead it is standalone, and linked to the project via the ``IDF_PATH`` environment variable which holds the path of the ``esp-idf`` directory. This allows the IDF framework to be decoupled from your project. - -- The toolchain for compilation is not part of the project. The toolchain should be installed in the system command line PATH. - -Using the Build System -====================== - -.. _idf.py: - -idf.py ------- - -The ``idf.py`` command line tool provides a front-end for easily managing your project builds. It manages the following tools: - -- CMake_, which configures the project to be built -- A command line build tool (either Ninja_ build or `GNU Make`) -- `esptool.py`_ for flashing ESP32. - -The :ref:`getting started guide ` contains a brief introduction to how to set up ``idf.py`` to configure, build, and flash projects. - -``idf.py`` should be run in an ESP-IDF "project" directory, ie one containing a ``CMakeLists.txt`` file. Older style projects with a Makefile will not work with ``idf.py``. - -Type ``idf.py --help`` for a full list of commands. Here are a summary of the most useful ones: - -- ``idf.py menuconfig`` runs the "menuconfig" tool to configure the project. -- ``idf.py build`` will build the project found in the current directory. This can involve multiple steps: - - - Create the build directory if needed. The sub-directory ``build`` is used to hold build output, although this can be changed with the ``-B`` option. - - Run CMake_ as necessary to configure the project and generate build files for the main build tool. - - Run the main build tool (Ninja_ or `GNU Make`). By default, the build tool is automatically detected but it can be explicitly set by passing the ``-G`` option to ``idf.py``. - - Building is incremental so if no source files or configuration has changed since the last build, nothing will be done. -- ``idf.py clean`` will "clean" the project by deleting build output files from the build directory, forcing a "full rebuild" the next time the project is built. Cleaning doesn't delete CMake configuration output and some other files. -- ``idf.py fullclean`` will delete the entire "build" directory contents. This includes all CMake configuration output. The next time the project is built, CMake will configure it from scratch. Note that this option recursively deletes *all* files in the build directory, so use with care. Project configuration is not deleted. -- ``idf.py flash`` will automatically build the project if necessary, and then flash it to an ESP32. The ``-p`` and ``-b`` options can be used to set serial port name and flasher baud rate, respectively. -- ``idf.py monitor`` will display serial output from the ESP32. The ``-p`` option can be used to set the serial port name. Type ``Ctrl-]`` to exit the monitor. See :doc:`tools/idf-monitor` for more details about using the monitor. - -Multiple ``idf.py`` commands can be combined into one. For example, ``idf.py -p COM4 clean flash monitor`` will clean the source tree, then build the project and flash it to the ESP32 before running the serial monitor. - -.. note:: The environment variables ``ESPPORT`` and ``ESPBAUD`` can be used to set default values for the ``-p`` and ``-b`` options, respectively. Providing these options on the command line overrides the default. - -.. _idf.py-size: - -Advanced Commands -^^^^^^^^^^^^^^^^^ - -- ``idf.py app``, ``idf.py bootloader``, ``idf.py partition_table`` can be used to build only the app, bootloader, or partition table from the project as applicable. -- There are matching commands ``idf.py app-flash``, etc. to flash only that single part of the project to the ESP32. -- ``idf.py -p PORT erase_flash`` will use esptool.py to erase the ESP32's entire flash chip. -- ``idf.py size`` prints some size information about the app. ``size-components`` and ``size-files`` are similar commands which print more detailed per-component or per-source-file information, respectively. If you define variable ``-DOUTPUT_JSON=1`` when running CMake (or ``idf.py``), the output will be formatted as JSON not as human readable text. -- ``idf.py reconfigure`` re-runs CMake_ even if it doesn't seem to need re-running. This isn't necessary during normal usage, but can be useful after adding/removing files from the source tree, or when modifying CMake cache variables. For example, ``idf.py -DNAME='VALUE' reconfigure`` can be used to set variable ``NAME`` in CMake cache to value ``VALUE``. - -The order of multiple ``idf.py`` commands on the same invocation is not important, they will automatically be executed in the correct order for everything to take effect (ie building before flashing, erasing before flashing, etc.). - -Using CMake Directly --------------------- - -:ref:`idf.py` is a wrapper around CMake_ for convenience. However, you can also invoke CMake directly if you prefer. - -.. highlight:: bash - -When ``idf.py`` does something, it prints each command that it runs for easy reference. For example, the ``idf.py build`` command is the same as running these commands in a bash shell (or similar commands for Windows Command Prompt):: - - mkdir -p build - cd build - cmake .. -G Ninja # or 'Unix Makefiles' - ninja - -In the above list, the ``cmake`` command configures the project and generates build files for use with the final build tool. In this case the final build tool is Ninja_: running ``ninja`` actually builds the project. - -It's not necessary to run ``cmake`` more than once. After the first build, you only need to run ``ninja`` each time. ``ninja`` will automatically re-invoke ``cmake`` if the project needs reconfiguration. - -If using CMake with ``ninja`` or ``make``, there are also targets for more of the ``idf.py`` sub-commands - for example running ``make menuconfig`` or ``ninja menuconfig`` in the build directory will work the same as ``idf.py menuconfig``. - -.. note:: - If you're already familiar with CMake_, you may find the ESP-IDF CMake-based build system unusual because it wraps a lot of CMake's functionality to reduce boilerplate. See `writing pure CMake components`_ for some information about writing more "CMake style" components. - -.. _flash-with-ninja-or-make: - -Flashing with ninja or make -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -It's possible to build and flash directly from ninja or make by running a target like:: - - ninja flash - -Or:: - - make app-flash - -Available targets are: ``flash``, ``app-flash`` (app only), ``bootloader-flash`` (bootloader only). - -When flashing this way, optionally set the ``ESPPORT`` and ``ESPBAUD`` environment variables to specify the serial port and baud rate. You can set environment variables in your operating system or IDE project. Alternatively, set them directly on the command line:: - - ESPPORT=/dev/ttyUSB0 ninja flash - -.. note:: Providing environment variables at the start of the command like this is Bash shell Syntax. It will work on Linux and macOS. It won't work when using Windows Command Prompt, but it will work when using Bash-like shells on Windows. - -Or:: - - make -j3 app-flash ESPPORT=COM4 ESPBAUD=2000000 - -.. note:: Providing variables at the end of the command line is ``make`` syntax, and works for ``make`` on all platforms. - - -Using CMake in an IDE ---------------------- - -You can also use an IDE with CMake integration. The IDE will want to know the path to the project's ``CMakeLists.txt`` file. IDEs with CMake integration often provide their own build tools (CMake calls these "generators") to build the source files as part of the IDE. - -When adding custom non-build steps like "flash" to the IDE, it is recommended to execute ``idf.py`` for these "special" commands. - -For more detailed information about integrating ESP-IDF with CMake into an IDE, see `Build System Metadata`_. - -.. _setting-python-interpreter: - -Setting the Python Interpreter ------------------------------- - -Currently, ESP-IDF only works with Python 2.7. If you have a system where the default ``python`` interpreter is Python 3.x, this can lead to problems. - -If using ``idf.py``, running ``idf.py`` as ``python2 $IDF_PATH/tools/idf.py ...`` will work around this issue (``idf.py`` will tell other Python processes to use the same Python interpreter). You can set up a shell alias or another script to simplify the command. - -If using CMake directly, running ``cmake -D PYTHON=python2 ...`` will cause CMake to override the default Python interpreter. - -If using an IDE with CMake, setting the ``PYTHON`` value as a CMake cache override in the IDE UI will override the default Python interpreter. - -To manage the Python version more generally via the command line, check out the tools pyenv_ or virtualenv_. These let you change the default python version. - -.. _example-project-structure: - -Example Project -=============== - -.. highlight:: none - -An example project directory tree might look like this:: - - - myProject/ - - CMakeLists.txt - - sdkconfig - - components/ - component1/ - CMakeLists.txt - - Kconfig - - src1.c - - component2/ - CMakeLists.txt - - Kconfig - - src1.c - - include/ - component2.h - - main/ - src1.c - - src2.c - - - build/ - -This example "myProject" contains the following elements: - -- A top-level project CMakeLists.txt file. This is the primary file which CMake uses to learn how to build the project; and may set project-wide CMake variables. It includes the file :idf_file:`/tools/cmake/project.cmake` which - implements the rest of the build system. Finally, it sets the project name and defines the project. - -- "sdkconfig" project configuration file. This file is created/updated when ``idf.py menuconfig`` runs, and holds configuration for all of the components in the project (including ESP-IDF itself). The "sdkconfig" file may or may not be added to the source control system of the project. - -- Optional "components" directory contains components that are part of the project. A project does not have to contain custom components of this kind, but it can be useful for structuring reusable code or including third party components that aren't part of ESP-IDF. - -- "main" directory is a special "pseudo-component" that contains source code for the project itself. "main" is a default name, the CMake variable ``COMPONENT_DIRS`` includes this component but you can modify this variable. Alternatively, ``EXTRA_COMPONENT_DIRS`` can be set in the top-level CMakeLists.txt to look for components in other places. See the :ref:`renaming main ` section for more info. If you have a lot of source files in your project, we recommend grouping most into components instead of putting them all in "main". - -- "build" directory is where build output is created. This directory is created by ``idf.py`` if it doesn't already exist. CMake configures the project and generates interim build files in this directory. Then, after the main build process is run, this directory will also contain interim object files and libraries as well as final binary output files. This directory is usually not added to source control or distributed with the project source code. - -Component directories each contain a component ``CMakeLists.txt`` file. This file contains variable definitions -to control the build process of the component, and its integration into the overall project. See `Component CMakeLists Files`_ for more details. - -Each component may also include a ``Kconfig`` file defining the `component configuration`_ options that can be set via ``menuconfig``. Some components may also include ``Kconfig.projbuild`` and ``project_include.cmake`` files, which are special files for `overriding parts of the project`_. - -Project CMakeLists File -======================= - -Each project has a single top-level ``CMakeLists.txt`` file that contains build settings for the entire project. By default, the project CMakeLists can be quite minimal. - -Minimal Example CMakeLists --------------------------- - -.. highlight:: cmake - -Minimal project:: - - cmake_minimum_required(VERSION 3.5) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) - project(myProject) - - -.. _project-mandatory-parts: - -Mandatory Parts ---------------- - -The inclusion of these three lines, in the order shown above, is necessary for every project: - -- ``cmake_minimum_required(VERSION 3.5)`` tells CMake the minimum version that is required to build the project. ESP-IDF is designed to work with CMake 3.5 or newer. This line must be the first line in the CMakeLists.txt file. -- ``include($ENV{IDF_PATH}/tools/cmake/project.cmake)`` pulls in the rest of the CMake functionality to configure the project, discover all the components, etc. -- ``project(myProject)`` creates the project itself, and specifies the project name. The project name is used for the final binary output files of the app - ie ``myProject.elf``, ``myProject.bin``. Only one project can be defined per CMakeLists file. - - -Optional Project Variables --------------------------- - -These variables all have default values that can be overridden for custom behaviour. Look in :idf_file:`/tools/cmake/project.cmake` for all of the implementation details. - -- ``COMPONENT_DIRS``,``COMPONENTS_DIRS``: Directories to search for components. Defaults to `IDF_PATH/components`, `PROJECT_DIR/components`, and ``EXTRA_COMPONENT_DIRS``. Override this variable if you don't want to search for components in these places. -- ``EXTRA_COMPONENT_DIRS``, ``EXTRA_COMPONENTS_DIRS``: Optional list of additional directories to search for components. Paths can be relative to the project directory, or absolute. -- ``COMPONENTS``: A list of component names to build into the project. Defaults to all components found in the ``COMPONENT_DIRS`` directories. Use this variable to "trim down" the project for faster build times. Note that any component which "requires" another component via the REQUIRES or PRIV_REQUIRES arguments on component registration will automatically have it added to this list, so the ``COMPONENTS`` list can be very short. - -Any paths in these variables can be absolute paths, or set relative to the project directory. - -To set these variables, use the `cmake set command `_ ie ``set(VARIABLE "VALUE")``. The ``set()`` commands should be placed after the ``cmake_minimum(...)`` line but before the ``include(...)`` line. - -.. _rename-main-cmake: - -Renaming ``main`` component ----------------------------- - -The build system provides special treatment to the ``main`` component. It is a component that gets automatically added to the build provided -that it is in the expected location, PROJECT_DIR/main. All other components in the build are also added as its dependencies, -saving the user from hunting down dependencies and providing a build that works right out of the box. Renaming the ``main`` component -causes the loss of these behind-the-scences heavy lifting, requiring the user to specify the location of the newly renamed component -and manually specifying its dependencies. Specifically, the steps to renaming ``main`` are as follows: - -1. Rename ``main`` directory. -2. Set ``EXTRA_COMPONENT_DIRS`` in the project CMakeLists.txt to include the renamed ``main`` directory. -3. Specify the dependencies in the renamed component's CMakeLists.txt file via REQUIRES or PRIV_REQUIRES arguments :ref:`on component registration`. - -.. _component-directories-cmake: - -Component CMakeLists Files -========================== - -Each project contains one or more components. Components can be part of ESP-IDF, part of the project's own components directory, or added from custom component directories (:ref:`see above `). - -A component is any directory in the ``COMPONENT_DIRS`` list which contains a ``CMakeLists.txt`` file. - -Searching for Components ------------------------- - -The list of directories in ``COMPONENT_DIRS`` is searched for the project's components. Directories in this list can either be components themselves (ie they contain a `CMakeLists.txt` file), or they can be top-level directories whose sub-directories are components. - -When CMake runs to configure the project, it logs the components included in the build. This list can be useful for debugging the inclusion/exclusion of certain components. - -Multiple components with the same name --------------------------------------- - -When ESP-IDF is collecting all the components to compile, it will do this in the order specified by ``COMPONENT_DIRS``; by default, this means ESP-IDF's internal components first, then the project's components, and finally any components set in ``EXTRA_COMPONENT_DIRS``. If two or more of these directories -contain component sub-directories with the same name, the component in the last place searched is used. This allows, for example, overriding ESP-IDF components -with a modified version by copying that component from the ESP-IDF components directory to the project components directory and then modifying it there. -If used in this way, the ESP-IDF directory itself can remain untouched. - -.. _cmake_minimal_component_cmakelists: - -Minimal Component CMakeLists ----------------------------- - -.. highlight:: cmake - -The minimal component ``CMakeLists.txt`` file simply registers the component to the build system using ``idf_component_register``:: - - idf_component_register(SRCS "foo.c" "bar.c" - INCLUDE_DIRS "include") - -- ``SRCS`` is a list of source files (``*.c``, ``*.cpp``, ``*.cc``, ``*.S``). These source files will be compiled into the component library. -- ``INCLUDE_DIRS`` is a list of directories to add to the global include search path for any component which requires this component, and also the main source files. - -A library with the name of the component will be built and linked into the final app. -Directories are usually specified relative to the ``CMakeLists.txt`` file itself, although they can be absolute. - -There are other arguments that can be passed to ``idf_component_register``. These arguments -are discussed :ref:`here`. - -See `example component CMakeLists`_ for more complete component ``CMakeLists.txt`` examples. - -.. _component variables: - -Preset Component Variables --------------------------- - -The following component-specific variables are available for use inside component CMakeLists, but should not be modified: - -- ``COMPONENT_DIR``: The component directory. Evaluates to the absolute path of the directory containing ``CMakeLists.txt``. The component path cannot contain spaces. This is the same as the ``CMAKE_CURRENT_SOURCE_DIR`` variable. -- ``COMPONENT_NAME``: Name of the component. Same as the name of the component directory. -- ``COMPONENT_ALIAS``: Alias of the library created internally by the build system for the component. -- ``COMPONENT_LIB``: Name of the library created internally by the build system for the component. - -The following variables are set at the project level, but available for use in component CMakeLists: - -- ``CONFIG_*``: Each value in the project configuration has a corresponding variable available in cmake. All names begin with ``CONFIG_``. :doc:`More information here `. -- ``ESP_PLATFORM``: Set to 1 when the CMake file is processed within ESP-IDF build system. - -Build/Project Variables ------------------------- - -The following are some project/build variables that are available as build properties and whose values can be queried using ``idf_build_get_property`` -from the component CMakeLists.txt: - -- ``PROJECT_NAME``: Name of the project, as set in project CMakeLists.txt file. -- ``PROJECT_DIR``: Absolute path of the project directory containing the project CMakeLists. Same as the ``CMAKE_SOURCE_DIR`` variable. -- ``COMPONENTS``: Names of all components that are included in this build, formatted as a semicolon-delimited CMake list. -- ``IDF_VER``: Git version of ESP-IDF (produced by ``git describe``) -- ``IDF_VERSION_MAJOR``, ``IDF_VERSION_MINOR``, ``IDF_VERSION_PATCH``: Components of ESP-IDF version, to be used in conditional expressions. Note that this information is less precise than that provided by ``IDF_VER`` variable. ``v4.0-dev-*``, ``v4.0-beta1``, ``v4.0-rc1`` and ``v4.0`` will all have the same values of ``IDF_VERSION_*`` variables, but different ``IDF_VER`` values. -- ``IDF_TARGET``: Name of the target for which the project is being built. -- ``PROJECT_VER``: Project version. - - * If ``PROJECT_VER`` variable is set in project CMakeLists.txt file, its value will be used. - * Else, if the ``PROJECT_DIR/version.txt`` exists, its contents will be used as ``PROJECT_VER``. - * Else, if the project is located inside a Git repository, the output of git describe will be used. - * Otherwise, ``PROJECT_VER`` will be "1". - -Other build properties are listed :ref:`here`. - -Controlling Component Compilation ---------------------------------- - -.. highlight:: cmake - -To pass compiler options when compiling source files belonging to a particular component, use the ``target_compile_options`` function:: - - target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-variable) - -To apply the compilation flags to a single source file, use the CMake `set_source_files_properties`_ command:: - - set_source_files_properties(mysrc.c - PROPERTIES COMPILE_FLAGS - -Wno-unused-variable - ) - -This can be useful if there is upstream code that emits warnings. - -When using these commands, place them after the call to ``idf_component_register`` in the component CMakeLists file. - -.. _component-configuration-cmake: - -Component Configuration -======================= - -Each component can also have a ``Kconfig`` file, alongside ``CMakeLists.txt``. This contains -configuration settings to add to the configuration menu for this component. - -These settings are found under the "Component Settings" menu when menuconfig is run. - -To create a component Kconfig file, it is easiest to start with one of the Kconfig files distributed with ESP-IDF. - -For an example, see `Adding conditional configuration`_. - -Preprocessor Definitions -======================== - -The ESP-IDF build system adds the following C preprocessor definitions on the command line: - -- ``ESP_PLATFORM`` : Can be used to detect that build happens within ESP-IDF. -- ``IDF_VER`` : Defined to a git version string. E.g. ``v2.0`` for a tagged release or ``v1.0-275-g0efaa4f`` for an arbitrary commit. - -Component Requirements -====================== - -When compiling each component, the ESP-IDF build system recursively evaluates its components. - -Each component's source file is compiled with these include path directories, as specified in the passed arguments -to ``idf_component_register``: - -- The current component's ``INCLUDE_DIRS`` and ``PRIV_INCLUDE_DIRS``. -- The ``INCLUDE_DIRS`` set by all components in the current component's ``REQUIRES`` and ``PRIV_REQUIRES`` variables (ie all the current component's public and private dependencies). -- All of the ``REQUIRES`` of those components, evaluated recursively (ie all public dependencies of this component's dependencies, recursively expanded). - -When writing a component ------------------------- - -- ``REQUIRES`` should be set to all components whose header files are #included from the *public* header files of this component. -- ``PRIV_REQUIRES`` should be set to all components whose header files are #included from *any source files* of this component, unless already listed in ``COMPONENT_REQUIRES``. Or any component which is required to be linked in order for this component to function correctly. -- ``REQUIRES`` and/or ``PRIV_REQUIRES`` should be set before calling ``idf_component_register()``. -- The values of ``REQUIRES`` and ``PRIV_REQUIRES`` should not depend on any configuration choices (``CONFIG_xxx`` macros). This is because requirements are expanded before configuration is loaded. Other component variables (like include paths or source files) can depend on configuration choices. -- Not setting either or both ``REQUIRES`` variables is fine. If the component has no requirements except for the "common" components needed for RTOS, libc, etc (``COMPONENT_REQUIRES_COMMON``) then both variables can be empty or unset. - -Components which support only some targets (values of ``IDF_TARGET``) may specify ``REQUIRED_IDF_TARGETS`` in the ``idf_component_register`` call to express these requirements. In this case the build system will generate an error if the component is included into the build, but does not support selected target. - -When creating a project ------------------------ - -- By default, every component is included in the build. -- If you set the ``COMPONENTS`` variable to a minimal list of components used directly by your project, then the build will include: - - - Components mentioned explicitly in ``COMPONENTS``. - - Those components' requirements (evaluated recursively). - - The "common" components that every component depends on. -- Setting ``COMPONENTS`` to the minimal list of required components can significantly reduce compile times. - -.. _component-requirements-implementation: - -Requirements in the build system implementation ------------------------------------------------ - -- Very early in the CMake configuration process, the script ``expand_requirements.cmake`` is run. This script does a partial evaluation of all component CMakeLists.txt files and builds a graph of component requirements (this graph may have cycles). The graph is used to generate a file ``component_depends.cmake`` in the build directory. -- The main CMake process then includes this file and uses it to determine the list of components to include in the build (internal ``BUILD_COMPONENTS`` variable). The ``BUILD_COMPONENTS`` variable is sorted so dependencies are listed first, however as the component dependency graph has cycles this cannot be guaranteed for all components. The order should be deterministic given the same set of components and component dependencies. -- The value of ``BUILD_COMPONENTS`` is logged by CMake as "Component names: " -- Configuration is then evaluated for the components included in the build. -- Each component is included in the build normally and the CMakeLists.txt file is evaluated again to add the component libraries to the build. - -Component Dependency Order -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The order of components in the ``BUILD_COMPONENTS`` variable determines other orderings during the build: - -- Order that :ref:`project_include.cmake` files are included into the project. -- Order that the list of header paths is generated for compilation (via ``-I`` argument). (Note that for a given component's source files, only that component's dependency's header paths are passed to the compiler.) - -Build Process Internals -======================= - -For full details about CMake_ and CMake commands, see the `CMake v3.5 documentation`_. - -project.cmake contents ----------------------- - -When included from a project CMakeLists file, the ``project.cmake`` file defines some utility modules and global variables and then sets ``IDF_PATH`` if it was not set in the system environment. - -It also defines an overridden custom version of the built-in CMake_ ``project`` function. This function is overridden to add all of the ESP-IDF specific project functionality. - -project function ----------------- - -The custom ``project()`` function performs the following steps: - -- Determines the target (set by ``IDF_TARGET`` environment variable) and saves the target in CMake cache. If the target set in the environment does not match the one in cache, exits with an error. -- Evaluates component dependencies and builds the ``BUILD_COMPONENTS`` list of components to include in the build (see :ref:`above`). -- Finds all components in the project (searching ``COMPONENT_DIRS`` and filtering by ``COMPONENTS`` if this is set). -- Loads the project configuration from the ``sdkconfig`` file and generates a ``sdkconfig.cmake`` file and a ``sdkconfig.h`` header. These define configuration values in CMake and C/C++, respectively. If the project configuration changes, cmake will automatically be re-run to re-generate these files and re-configure the project. -- Sets the `CMAKE_TOOLCHAIN_FILE`_ variable to the correct toolchain file, depending on the target. -- Declares the actual cmake-level project by calling the `CMake project function `_. -- Loads the git version. This includes some magic which will automatically re-run CMake if a new revision is checked out in git. See `File Globbing & Incremental Builds`_. -- Includes :ref:`project_include.cmake` files from any components which have them. -- Adds each component to the build. Each component CMakeLists file calls ``idf_component_register``, calls the CMake `add_library `_ function to add a library and then adds source files, compile options, etc. -- Adds the final app executable to the build. -- Goes back and adds inter-component dependencies between components (ie adding the public header directories of each component to each other component). - -Browse the :idf_file:`/tools/cmake/project.cmake` file and supporting functions in :idf_file:`/tools/cmake/idf_functions.cmake` for more details. - -Debugging CMake ---------------- - -Some tips for debugging the ESP-IDF CMake-based build system: - -- When CMake runs, it prints quite a lot of diagnostic information including lists of components and component paths. -- Running ``cmake -DDEBUG=1`` will produce more verbose diagnostic output from the IDF build system. -- Running ``cmake`` with the ``--trace`` or ``--trace-expand`` options will give a lot of information about control flow. See the `cmake command line documentation`_. - -.. _warn-undefined-variables-cmake: - -Warning On Undefined Variables -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -By default, ``idf.py`` passes the ``--warn-uninitialized`` flag to CMake_ so it will print a warning if an undefined variable is referenced in the build. This can be very useful to find buggy CMake files. - -If you don't want this behaviour, it can be disabled by passing ``--no-warnings`` to ``idf.py``. - -Overriding Parts of the Project -------------------------------- - -.. _project_include.cmake: - -project_include.cmake -^^^^^^^^^^^^^^^^^^^^^ - -For components that have build requirements which must be evaluated before any component CMakeLists -files are evaluated, you can create a file called ``project_include.cmake`` in the -component directory. This CMake file is included when ``project.cmake`` is evaluating the entire project. - -``project_include.cmake`` files are used inside ESP-IDF, for defining project-wide build features such as ``esptool.py`` command line arguments and the ``bootloader`` "special app". - -Unlike component ``CMakeLists.txt`` files, when including a ``project_include.cmake`` file the current source directory (``CMAKE_CURRENT_SOURCE_DIR`` and working directory) is the project directory. Use the variable ``COMPONENT_DIR`` for the absolute directory of the component. - -Note that ``project_include.cmake`` isn't necessary for the most common component uses - such as adding include directories to the project, or ``LDFLAGS`` to the final linking step. These values can be customised via the ``CMakeLists.txt`` file itself. See `Optional Project Variables`_ for details. - -``project_include.cmake`` files are included in the order given in ``BUILD_COMPONENTS`` variable (as logged by CMake). This means that a component's ``project_include.cmake`` file will be included after it's all dependencies' ``project_include.cmake`` files, unless both components are part of a dependency cycle. This is important if a ``project_include.cmake`` file relies on variables set by another component. See also :ref:`above`. - -Take great care when setting variables or targets in a ``project_include.cmake`` file. As the values are included into the top-level project CMake pass, they can influence or break functionality across all components! - -KConfig.projbuild -^^^^^^^^^^^^^^^^^ - -This is an equivalent to ``project_include.cmake`` for :ref:`component-configuration-cmake` KConfig files. If you want to include -configuration options at the top-level of menuconfig, rather than inside the "Component Configuration" sub-menu, then these can be defined in the KConfig.projbuild file alongside the ``CMakeLists.txt`` file. - -Take care when adding configuration values in this file, as they will be included across the entire project configuration. Where possible, it's generally better to create a KConfig file for :ref:`component-configuration-cmake`. - - -Configuration-Only Components -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Special components which contain no source files, only ``Kconfig.projbuild`` and ``KConfig``, can have a one-line ``CMakeLists.txt`` file which calls the function ``idf_component_register()`` with no -arguments specified. This function will include the component in the project build, but no library will be built *and* no header files will be added to any include paths. - -Example Component CMakeLists -============================ - -Because the build environment tries to set reasonable defaults that will work most -of the time, component ``CMakeLists.txt`` can be very small or even empty (see `Minimal Component CMakeLists`_). However, overriding `component variables`_ is usually required for some functionality. - -Here are some more advanced examples of component CMakeLists files. - -Adding conditional configuration --------------------------------- - -The configuration system can be used to conditionally compile some files -depending on the options selected in the project configuration. - -.. highlight:: none - -``Kconfig``:: - - config FOO_ENABLE_BAR - bool "Enable the BAR feature." - help - This enables the BAR feature of the FOO component. - -``CMakeLists.txt``:: - - set(COMPONENT_SRCS "foo.c" "more_foo.c") - - if(CONFIG_FOO_ENABLE_BAR) - list(APPEND COMPONENT_SRCS "bar.c") - endif() - -This example makes use of the CMake `if `_ function and `list APPEND `_ function. - -This can also be used to select or stub out an implementation, as such: - -``Kconfig``:: - - config ENABLE_LCD_OUTPUT - bool "Enable LCD output." - help - Select this if your board has a LCD. - - config ENABLE_LCD_CONSOLE - bool "Output console text to LCD" - depends on ENABLE_LCD_OUTPUT - help - Select this to output debugging output to the lcd - - config ENABLE_LCD_PLOT - bool "Output temperature plots to LCD" - depends on ENABLE_LCD_OUTPUT - help - Select this to output temperature plots - -.. highlight:: cmake - -``CMakeLists.txt``:: - - if(CONFIG_ENABLE_LCD_OUTPUT) - set(COMPONENT_SRCS lcd-real.c lcd-spi.c) - else() - set(COMPONENT_SRCS lcd-dummy.c) - endif() - - # We need font if either console or plot is enabled - if(CONFIG_ENABLE_LCD_CONSOLE OR CONFIG_ENABLE_LCD_PLOT) - list(APPEND COMPONENT_SRCS "font.c") - endif() - - -Conditions which depend on the target -------------------------------------- - -The current target is available to CMake files via ``IDF_TARGET`` variable. - -In addition to that, if target ``xyz`` is used (``IDF_TARGET=xyz``), then Kconfig variable ``CONFIG_IDF_TARGET_XYZ`` will be set. - -Note that component dependencies may depend on ``IDF_TARGET`` variable, but not on Kconfig variables. Also one can not use Kconfig variables in ``include`` statements in CMake files, but ``IDF_TARGET`` can be used in such context. - - -Source Code Generation ----------------------- - -Some components will have a situation where a source file isn't -supplied with the component itself but has to be generated from -another file. Say our component has a header file that consists of the -converted binary data of a BMP file, converted using a hypothetical -tool called bmp2h. The header file is then included in as C source -file called graphics_lib.c:: - - add_custom_command(OUTPUT logo.h - COMMAND bmp2h -i ${COMPONENT_DIR}/logo.bmp -o log.h - DEPENDS ${COMPONENT_DIR}/logo.bmp - VERBATIM) - - add_custom_target(logo DEPENDS logo.h) - add_dependencies(${COMPONENT_LIB} logo) - - set_property(DIRECTORY "${COMPONENT_DIR}" APPEND PROPERTY - ADDITIONAL_MAKE_CLEAN_FILES logo.h) - -This answer is adapted from the `CMake FAQ entry `_, which contains some other examples that will also work with ESP-IDF builds. - -In this example, logo.h will be generated in the -current directory (the build directory) while logo.bmp comes with the -component and resides under the component path. Because logo.h is a -generated file, it should be cleaned when the project is cleaned. For this reason -it is added to the `ADDITIONAL_MAKE_CLEAN_FILES`_ property. - -.. note:: - - If generating files as part of the project CMakeLists.txt file, not a component CMakeLists.txt, then use build property ``PROJECT_DIR`` instead of ``${COMPONENT_DIR}`` and ``${PROJECT_NAME}.elf`` instead of ``${COMPONENT_LIB}``.) - -If a a source file from another component included ``logo.h``, then ``add_dependencies`` would need to be called to add a dependency between -the two components, to ensure that the component source files were always compiled in the correct order. - -.. _cmake_embed_data: - -Embedding Binary Data ---------------------- - -Sometimes you have a file with some binary or text data that you'd like to make available to your component - but you don't want to reformat the file as C source. - -You can specify argument ``COMPONENT_EMBED_FILES`` in the component registration, giving space-delimited names of the files to embed:: - - idf_component_register(... - EMBED_FILES server_root_cert.der) - - -Or if the file is a string, you can use the variable ``COMPONENT_EMBED_TXTFILES``. This will embed the contents of the text file as a null-terminated string:: - - idf_component_register(... - EMBED_TXTFILES server_root_cert.pem) - -.. highlight:: c - -The file's contents will be added to the .rodata section in flash, and are available via symbol names as follows:: - - 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"); - -The names are generated from the full name of the file, as given in ``COMPONENT_EMBED_FILES``. Characters /, ., etc. are replaced with underscores. The _binary prefix in the symbol name is added by objcopy and is the same for both text and binary files. - -.. highlight:: cmake - -To embed a file into a project, rather than a component, you can call the function ``target_add_binary_data`` like this:: - - target_add_binary_data(myproject.elf "main/data.bin" TEXT) - -Place this line after the ``project()`` line in your project CMakeLists.txt file. Replace ``myproject.elf`` with your project name. The final argument can be ``TEXT`` to embed a null-terminated string, or ``BINARY`` to embed the content as-is. - -For an example of using this technique, see :example:`protocols/https_request` - the certificate file contents are loaded from the text .pem file at compile time. - -Code and Data Placements ------------------------- - -ESP-IDF has a feature called linker script generation that enables components to define where its code and data will be placed in memory through -linker fragment files. These files are processed by the build system, and is used to augment the linker script used for linking -app binary. See :doc:`Linker Script Generation ` for a quick start guide as well as a detailed discussion -of the mechanism. - -.. _component-build-full-override: - -Fully Overriding The Component Build Process --------------------------------------------- - -.. highlight:: cmake - -Obviously, there are cases where all these recipes are insufficient for a -certain component, for example when the component is basically a wrapper -around another third-party component not originally intended to be -compiled under this build system. In that case, it's possible to forego -the ESP-IDF build system entirely by using a CMake feature called ExternalProject_. Example component CMakeLists:: - - # External build process for quirc, runs in source dir and - # produces libquirc.a - externalproject_add(quirc_build - PREFIX ${COMPONENT_DIR} - SOURCE_DIR ${COMPONENT_DIR}/quirc - CONFIGURE_COMMAND "" - BUILD_IN_SOURCE 1 - BUILD_COMMAND make CC=${CMAKE_C_COMPILER} libquirc.a - INSTALL_COMMAND "" - ) - - # Add libquirc.a to the build process - # - add_library(quirc STATIC IMPORTED GLOBAL) - add_dependencies(quirc quirc_build) - - set_target_properties(quirc PROPERTIES IMPORTED_LOCATION - ${COMPONENT_DIR}/quirc/libquirc.a) - set_target_properties(quirc PROPERTIES INTERFACE_INCLUDE_DIRECTORIES - ${COMPONENT_DIR}/quirc/lib) - - set_directory_properties( PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES - "${COMPONENT_DIR}/quirc/libquirc.a") - -(The above CMakeLists.txt can be used to create a component named ``quirc`` that builds the quirc_ project using its own Makefile.) - -- ``externalproject_add`` defines an external build system. - - - ``SOURCE_DIR``, ``CONFIGURE_COMMAND``, ``BUILD_COMMAND`` and ``INSTALL_COMMAND`` should always be set. ``CONFIGURE_COMMAND`` can be set to an empty string if the build system has no "configure" step. ``INSTALL_COMMAND`` will generally be empty for ESP-IDF builds. - - Setting ``BUILD_IN_SOURCE`` means the build directory is the same as the source directory. Otherwise you can set ``BUILD_DIR``. - - Consult the ExternalProject_ documentation for more details about ``externalproject_add()`` - -- The second set of commands adds a library target, which points to the "imported" library file built by the external system. Some properties need to be set in order to add include directories and tell CMake where this file is. -- Finally, the generated library is added to `ADDITIONAL_MAKE_CLEAN_FILES`_. This means ``make clean`` will delete this library. (Note that the other object files from the build won't be deleted.) - -.. note:: When using an external build process with PSRAM, remember to add ``-mfix-esp32-psram-cache-issue`` to the C compiler arguments. See :ref:`CONFIG_SPIRAM_CACHE_WORKAROUND` for details of this flag. - -.. _ADDITIONAL_MAKE_CLEAN_FILES_note: - -ExternalProject dependencies, clean builds -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -CMake has some unusual behaviour around external project builds: - -- `ADDITIONAL_MAKE_CLEAN_FILES`_ only works when "make" is used as the build system. If Ninja_ or an IDE build system is used, it won't delete these files when cleaning. -- However, the ExternalProject_ configure & build commands will *always* be re-run after a clean is run. -- Therefore, there are two alternative recommended ways to configure the external build command: - - 1. Have the external ``BUILD_COMMAND`` run a full clean compile of all sources. The build command will be run if any of the dependencies passed to ``externalproject_add`` with ``DEPENDS`` have changed, or if this is a clean build (ie any of ``idf.py clean``, ``ninja clean``, or ``make clean`` was run.) - 2. Have the external ``BUILD_COMMAND`` be an incremental build command. Pass the parameter ``BUILD_ALWAYS 1`` to ``externalproject_add``. This means the external project will be built each time a build is run, regardless of dependencies. This is only recommended if the external project has correct incremental build behaviour, and doesn't take too long to run. - -The best of these approaches for building an external project will depend on the project itself, its build system, and whether you anticipate needing to frequently recompile the project. - -.. _custom-sdkconfig-defaults-cmake: - -Custom sdkconfig defaults -========================= - -For example projects or other projects where you don't want to specify a full sdkconfig configuration, but you do want to override some key values from the ESP-IDF defaults, it is possible to create a file ``sdkconfig.defaults`` in the project directory. This file will be used when creating a new config from scratch, or when any new config value hasn't yet been set in the ``sdkconfig`` file. - -To override the name of this file, set the ``SDKCONFIG_DEFAULTS`` environment variable. - -Target-dependent sdkconfig defaults ------------------------------------ - -In addition to ``sdkconfig.defaults`` file, build system will also load defaults from ``sdkconfig.defaults.TARGET_NAME`` file, where ``TARGET_NAME`` is the value of ``IDF_TARGET``. For example, for ``esp32`` target, default settings will be taken from ``sdkconfig.defaults`` first, and then from ``sdkconfig.defaults.esp32``. - -If ``SDKCONFIG_DEFAULTS`` is used to override the name of defaults file, the name of target-specific defaults file will be derived from ``SDKCONFIG_DEFAULTS`` value. - - -Flash arguments -=============== - -There are some scenarios that we want to flash the target board without IDF. For this case we want to save the built binaries, esptool.py and esptool write_flash arguments. It's simple to write a script to save binaries and esptool.py. - -After running a project build, the build directory contains binary output files (``.bin`` files) for the project and also the following flashing data files: - -- ``flash_project_args`` contains arguments to flash the entire project (app, bootloader, partition table, PHY data if this is configured). -- ``flash_app_args`` contains arguments to flash only the app. -- ``flash_bootloader_args`` contains arguments to flash only the bootloader. - -.. highlight:: bash - -You can pass any of these flasher argument files to ``esptool.py`` as follows:: - - python esptool.py --chip esp32 write_flash @build/flash_project_args - -Alternatively, it is possible to manually copy the parameters from the argument file and pass them on the command line. - -The build directory also contains a generated file ``flasher_args.json`` which contains project flash information, in JSON format. This file is used by ``idf.py`` and can also be used by other tools which need information about the project build. - -Building the Bootloader -======================= - -The bootloader is built by default as part of ``idf.py build``, or can be built standalone via ``idf.py bootloader``. - -The bootloader is a special "subproject" inside :idf:`/components/bootloader/subproject`. It has its own project CMakeLists.txt file and builds separate .ELF and .BIN files to the main project. However it shares its configuration and build directory with the main project. - -The subproject is inserted as an external project from the top-level project, by the file :idf_file:`/components/bootloader/project_include.cmake`. The main build process runs CMake for the subproject, which includes discovering components (a subset of the main components) and generating a bootloader-specific config (derived from the main ``sdkconfig``). - -Selecting the Target -==================== - -Currently ESP-IDF supports one target, ``esp32``. It is used by default by the build system. Developers working on adding multiple target support can change the target as follows:: - - rm sdkconfig - idf.py -DIDF_TARGET=new_target reconfigure - - -Writing Pure CMake Components -============================= - -The ESP-IDF build system "wraps" CMake with the concept of "components", and helper functions to automatically integrate these components into a project build. - -However, underneath the concept of "components" is a full CMake build system. It is also possible to make a component which is pure CMake. - -.. highlight:: cmake - -Here is an example minimal "pure CMake" component CMakeLists file for a component named ``json``:: - - add_library(json STATIC - cJSON/cJSON.c - cJSON/cJSON_Utils.c) - - target_include_directories(json PUBLIC cJSON) - -- This is actually an equivalent declaration to the IDF ``json`` component :idf_file:`/components/json/CMakeLists.txt`. -- This file is quite simple as there are not a lot of source files. For components with a large number of files, the globbing behaviour of ESP-IDF's component logic can make the component CMakeLists style simpler.) -- Any time a component adds a library target with the component name, the ESP-IDF build system will automatically add this to the build, expose public include directories, etc. If a component wants to add a library target with a different name, dependencies will need to be added manually via CMake commands. - - -Using Third-Party CMake Projects with Components -================================================ - -CMake is used for a lot of open-source C and C++ projects — code that users can tap into for their applications. One of the benefits of having a CMake build system -is the ability to import these third-party projects, sometimes even without modification! This allows for users to be able to get functionality that may -not yet be provided by a component, or use another library for the same functionality. - -.. highlight:: cmake - -Importing a library might look like this for a hypothetical library ``foo`` to be used in the ``main`` component:: - - # Register the component - idf_component_register() - - # Set values of hypothetical variables that control the build of `foo` - set(FOO_BUILD_STATIC OFF) - set(FOO_BUILD_TESTS OFF) - - # Create and import the library targets - add_subdirectory(foo) - - # Link `foo` to `main` component - target_link_libraries(main foo) - -For an actual example, take a look at :example:`build_system/cmake/import_lib`. Take note that what needs to be done in order to import -the library may vary. It is recommended to read up on the library's documentation for instructions on how to -import it from other projects. Studying the library's CMakeLists.txt and build structure can also be helpful. - -It is also possible to wrap a third-party library to be used as a component in this manner. For example, the :component:`mbedtls` component is a wrapper for -Espressif's fork of `mbedtls `_. See its :component_file:`component CMakeLists.txt `. - -The CMake variable ``ESP_PLATFORM`` is set to 1 whenever the ESP-IDF build system is being used. Tests such as ``if (ESP_PLATFORM)`` can be used in generic CMake code if special IDF-specific logic is required. - - -Using ESP-IDF in Custom CMake Projects -====================================== - -ESP-IDF provides a template CMake project for easily creating an application. However, in some instances the user might already -have an existing CMake project or may want to create a custom one. In these cases it is desirable to be able to consume IDF components -as libraries to be linked to the user's targets (libraries/ executables). - -It is possible to do so by using the :ref:`build system APIs provided` by :idf_file:`tools/cmake/idf.cmake`. For example: - -.. code-block:: cmake - - cmake_minimum_required(VERSION 3.5) - project(my_custom_app C) - - # Include CMake file that provides ESP-IDF CMake build system APIs. - include($ENV{IDF_PATH}/tools/cmake/idf.cmake) - - # Include ESP-IDF components in the build, may be thought as an equivalent of - # add_subdirectory() but with some additional procesing and magic for ESP-IDF build - # specific build processes. - idf_build_process(esp32) - - # Create the project executable and plainly link the newlib component to it using - # its alias, idf::newlib. - add_executable(${CMAKE_PROJECT_NAME}.elf main.c) - target_link_libraries(${CMAKE_PROJECT_NAME}.elf idf::newlib) - - # Let the build system know what the project executable is to attach more targets, dependencies, etc. - idf_build_executable(${CMAKE_PROJECT_NAME}.elf) - -The example in :example:`build_system/cmake/idf_as_lib` demonstrates the creation of an application equivalent to :example:`hello world application ` -using a custom CMake project. - -.. note:: The IDF build system can only set compiler flags for source files that it builds. When an external CMakeLists.txt file is used and PSRAM is enabled, remember to add ``-mfix-esp32-psram-cache-issue`` to the C compiler arguments. See :ref:`CONFIG_SPIRAM_CACHE_WORKAROUND` for details of this flag. -.. _cmake_buildsystem_api: - -ESP-IDF CMake Build System API -============================== - -idf-build-commands ------------------- - -.. code-block:: none - - idf_build_get_property(var property [GENERATOR_EXPRESSION]) - -Retrieve a :ref:`build property` *property* and store it in *var* accessible from the current scope. Specifying -*GENERATOR_EXPRESSION* will retrieve the generator expression string for that property, instead of the actual value, which -can be used with CMake commands that support generator expressions. - -.. code-block:: none - - idf_build_set_property(property val [APPEND]) - -Set a :ref:`build property` *property* with value *val*. Specifying *APPEND* will append the specified value to the current -value of the property. If the property does not previously exist or it is currently empty, the specified value becomes -the first element/member instead. - -.. code-block:: none - - idf_build_component(component_dir) - -Present a directory *component_dir* that contains a component to the build system. Relative paths are converted to absolute paths with respect to current directory. -All calls to this command must be performed before `idf_build_process`. - -This command does not guarantee that the component will be processed during build (see the `COMPONENTS` argument description for `idf_build_process`) - -.. code-block:: none - - idf_build_process(target - [PROJECT_DIR project_dir] - [PROJECT_VER project_ver] - [PROJECT_NAME project_name] - [SDKCONFIG sdkconfig] - [SDKCONFIG_DEFAULTS sdkconfig_defaults] - [BUILD_DIR build_dir] - [COMPONENTS component1 component2 ...]) - -Performs the bulk of the behind-the-scenes magic for including ESP-IDF components such as component configuration, libraries creation, -dependency expansion and resolution. Among these functions, perhaps the most important -from a user's perspective is the libraries creation by calling each component's ``idf_component_register``. This command creates the libraries for each component, which are accessible using aliases in the form -idf::*component_name*. These aliases can be used to link the components to the user's own targets, either libraries -or executables. - -The call requires the target chip to be specified with *target* argument. Optional arguments for the call include: - -- PROJECT_DIR - directory of the project; defaults to CMAKE_SOURCE_DIR -- PROJECT_NAME - name of the project; defaults to CMAKE_PROJECT_NAME -- PROJECT_VER - version/revision of the project; defaults to "0.0.0" -- SDKCONFIG - output path of generated sdkconfig file; defaults to PROJECT_DIR/sdkconfig or CMAKE_SOURCE_DIR/sdkconfig depending if PROJECT_DIR is set -- SDKCONFIG_DEFAULTS - defaults file to use for the build; defaults to empty -- BUILD_DIR - directory to place ESP-IDF build-related artifacts, such as generated binaries, text files, components; defaults to CMAKE_BINARY_DIR -- COMPONENTS - select components to process among the components known by the build system (added via `idf_build_component`). This argument is used to trim the build. - Other components are automatically added if they are required in the dependency chain, i.e. - the public and private requirements of the components in this list are automatically added, and in turn the public and private requirements of those requirements, - so on and so forth. If not specified, all components known to the build system are processed. - -.. code-block:: none - - idf_build_executable(executable) - -Specify the executable *executable* for ESP-IDF build. This attaches additional targets such as dependencies related to -flashing, generating additional binary files, etc. Should be called after ``idf_build_process``. - -.. code-block:: none - - idf_build_get_config(var config [GENERATOR_EXPRESSION]) - -Get the value of the specified config. Much like build properties, specifying -*GENERATOR_EXPRESSION* will retrieve the generator expression string for that config, instead of the actual value, which -can be used with CMake commands that support generator expressions. Actual config values are only known after call to `idf_build_process`, however. - -.. _cmake-build-properties: - -idf-build-properties --------------------- - -These are properties that describe the build. Values of build properties can be retrieved by using the build command ``idf_build_get_property``. -For example, to get the Python interpreter used for the build: - -.. code-block: cmake - - idf_build_get_property(python PYTHON) - message(STATUS "The Python intepreter is: ${python}") - - - BUILD_DIR - build directory; set from ``idf_build_process`` BUILD_DIR argument - - BUILD_COMPONENTS - list of components (more specifically, component aliases) included in the build; set by ``idf_build_process`` - - C_COMPILE_OPTIONS - compile options applied to all components' C source files - - COMPILE_OPTIONS - compile options applied to all components' source files, regardless of it being C or C++ - - COMPILE_DEFINITIONS - compile definitions applied to all component source files - - CXX_COMPILE_OPTIONS - compile options applied to all components' C++ source files - - EXECUTABLE - project executable; set by call to ``idf_build_executable`` - - EXECUTABLE_NAME - name of project executable without extension; set by call to ``idf_build_executable`` - - IDF_PATH - ESP-IDF path; set from IDF_PATH environment variable, if not, inferred from the location of ``idf.cmake`` - - IDF_TARGET - target chip for the build; set from the required target argument for ``idf_build_process`` - - IDF_VER - ESP-IDF version; set from either a version file or the Git revision of the IDF_PATH repository - - INCLUDE_DIRECTORIES - include directories for all component source files - - KCONFIGS - list of Kconfig files found in components in build; set by ``idf_build_process`` - - KCONFIG_PROJBUILDS - list of Kconfig.projbuild diles found in components in build; set by ``idf_build_process`` - - PROJECT_NAME - name of the project; set from ``idf_build_process`` PROJECT_NAME argument - - PROJECT_DIR - directory of the project; set from ``idf_build_process`` PROJECT_DIR argument - - PROJECT_VER - version of the project; set from ``idf_build_process`` PROJECT_VER argument - - PYTHON - Python interpreter used for the build; set from PYTHON environment variable if available, if not "python" is used - - SDKCONFIG - full path to output config file; set from ``idf_build_process`` SDKCONFIG argument - - SDKCONFIG_DEFAULTS - full path to config defaults file; set from ``idf_build_process`` SDKCONFIG_DEFAULTS argument - - SDKCONFIG_HEADER - full path to C/C++ header file containing component configuration; set by ``idf_build_process`` - - SDKCONFIG_CMAKE - full path to CMake file containing component configuration; set by ``idf_build_process`` - - SDKCONFIG_JSON - full path to JSON file containing component configuration; set by ``idf_build_process`` - - SDKCONFIG_JSON_MENUS - full path to JSON file containing config menus; set by ``idf_build_process`` - -idf-component-commands ----------------------- - -.. code-block:: none - - idf_component_get_property(var component property [GENERATOR_EXPRESSION]) - -Retrieve a specified *component*'s :ref:`component property`, *property* and store it in *var* accessible from the current scope. Specifying -*GENERATOR_EXPRESSION* will retrieve the generator expression string for that property, instead of the actual value, which -can be used with CMake commands that support generator expressions. - -.. code-block:: none - - idf_component_set_property(property val [APPEND]) - -Set a specified *component*'s :ref:`component property`, *property* with value *val*. Specifying *APPEND* will append the specified value to the current -value of the property. If the property does not previously exist or it is currently empty, the specified value becomes -the first element/member instead. - -.. _cmake-component-register: - -.. code-block:: none - - idf_component_register([[SRCS src1 src2 ...] | [[SRC_DIRS dir1 dir2 ...] [EXCLUDE_SRCS src1 src2 ...]] - [INCLUDE_DIRS dir1 dir2 ...] - [PRIV_INCLUDE_DIRS dir1 dir2 ...] - [REQUIRES component1 component2 ...] - [PRIV_REQUIRES component1 component2 ...] - [LDFRAGMENTS ldfragment1 ldfragment2 ...] - [REQUIRED_IDF_TARGETS target1 target2 ...] - [EMBED_FILES file1 file2 ...] - [EMBED_TXTFILES file1 file2 ...]) - -Register a component to the build system. Much like the ``project()`` CMake command, this should be called from the component's -CMakeLists.txt directly (not through a function or macro) and is recommended to be called before any other command. Here are some -guidelines on what commands can **not** be called before ``idf_component_register``: - - - commands that are not valid in CMake script mode - - custom commands defined in project_include.cmake - - build system API commands except ``idf_build_get_property``; although consider whether the property may not have been set yet - -Commands that set and operate on variables are generally okay to call before ``idf_component_register``. - -The arguments for ``idf_component_register`` include: - - - SRCS - component source files used for creating a static library for the component; if not specified, component is a treated as a - config-only component and an interface library is created instead. - - SRC_DIRS, EXCLUDE_SRCS - used to glob source files (.c, .cpp, .S) by specifying directories, instead of specifying source files manually via SRCS. - Note that this is subject to the :ref:`limitations of globbing in CMake`. Source files specified in EXCLUDE_SRCS are removed from the globbed files. - - INCLUDE_DIRS - paths, relative to the component directory, which will be added to the include search path for all other components which require the current component - - PRIV_INCLUDE_DIRS - directory paths, must be relative to the component directory, which will be added to the include search path for this component's source files only - - REQUIRES - public component requirements for the component - - PRIV_REQUIRES - private component requirements for the component; ignored on config-only components - - LDFRAGMENTS - component linker fragment files - - REQUIRED_IDF_TARGETS - specify the only target the component supports - -The following are used for :ref:`embedding data into the component`, and is considered as source files -when determining if a component is config-only. This means that even if the component does not specify source files, a static library is still -created internally for the component if it specifies either: - - - EMBED_FILES - binary files to be embedded in the component - - EMBED_TXTFILES - text files to be embedded in the component - -.. _cmake-component-properties: - -idf-component-properties ------------------------- - -These are properties that describe a component. Values of component properties can be retrieved by using the build command ``idf_component_get_property``. -For example, to get the directory of the ``freertos`` component: - -.. code-block: cmake - - idf_component_get_property(dir freertos COMPONENT_DIR) - message(STATUS "The 'freertos' component directory is: ${dir}") - -- COMPONENT_ALIAS - alias for COMPONENT_LIB used for linking the component to external targets; set by ``idf_build_component`` and alias library itself - is created by ``idf_component_register`` -- COMPONENT_DIR - component directory; set by ``idf_build_component`` -- COMPONENT_LIB - name for created component static/interface library; set by ``idf_build_component`` and library itself - is created by ``idf_component_register`` -- COMPONENT_NAME - name of the component; set by ``idf_build_component`` based on the component directory name -- COMPONENT_TYPE - type of the component, whether LIBRARY or CONFIG_ONLY. A component is of type LIBRARY if it specifies - source files or embeds a file -- EMBED_FILES - list of files to embed in component; set from ``idf_component_register`` EMBED_FILES argument -- EMBED_TXTFILES - list of text files to embed in component; set from ``idf_component_register`` EMBED_TXTFILES argument -- INCLUDE_DIRS - list of component include directories; set from ``idf_component_register`` INCLUDE_DIRS argument -- KCONFIG - component Kconfig file; set by ``idf_build_component`` -- KCONFIG_PROJBUILD - component Kconfig.projbuild; set by ``idf_build_component`` -- LDFRAGMENTS - list of component linker fragment files; set from ``idf_component_register`` LDFRAGMENTS argument -- PRIV_INCLUDE_DIRS - list of component private include directories; set from ``idf_component_register`` PRIV_INCLUDE_DIRS on components of type LIBRARY -- PRIV_REQUIRES - list of private component dependentices; set from ``idf_component_register`` PRIV_REQUIRES argument -- REQUIRED_IDF_TARGETS - list of targets the component supports; set from ``idf_component_register`` EMBED_TXTFILES argument -- REQUIRES - list of public component dependencies; set from ``idf_component_register`` REQUIRES argument -- SRCS - list of component source files; set from SRCS or SRC_DIRS/EXCLUDE_SRCS argument of ``idf_component_register`` - -.. _cmake-file-globbing: - -File Globbing & Incremental Builds -================================== - -.. highlight:: cmake - -The preferred way to include source files in an ESP-IDF component is to list them manually via SRCS argument to ``idf_component_register``:: - - idf_component_register(SRCS library/a.c library/b.c platform/platform.c - ...) - -This preference reflects the `CMake best practice `_ of manually listing source files. This could, however, be inconvenient when there are lots of source files to add to the build. The ESP-IDF build system provides an alternative way for specifying source files using ``SRC_DIRS``:: - - idf_component_register(SRC_DIRS library platform - ...) - -This uses globbing behind the scenes to find source files in the specified directories. Be aware, however, that if a new source file is added and this method is used, then CMake won't know to automatically re-run and this file won't be added to the build. - -The trade-off is acceptable when you're adding the file yourself, because you can trigger a clean build or run ``idf.py reconfigure`` to manually re-run CMake_. However, the problem gets harder when you share your project with others who may check out a new version using a source control tool like Git... - -For components which are part of ESP-IDF, we use a third party Git CMake integration module (:idf_file:`/tools/cmake/third_party/GetGitRevisionDescription.cmake`) which automatically re-runs CMake any time the repository commit changes. This means if you check out a new ESP-IDF version, CMake will automatically rerun. - -For project components (not part of ESP-IDF), there are a few different options: - -- If keeping your project file in Git, ESP-IDF will automatically track the Git revision and re-run CMake if the revision changes. -- If some components are kept in a third git repository (not the project repository or ESP-IDF repository), you can add a call to the ``git_describe`` function in a component CMakeLists file in order to automatically trigger re-runs of CMake when the Git revision changes. -- If not using Git, remember to manually run ``idf.py reconfigure`` whenever a source file may change. -- To avoid this problem entirely, use ``COMPONENT_SRCS`` to list all source files in project components. - -The best option will depend on your particular project and its users. - -Build System Metadata -===================== - -For integration into IDEs and other build systems, when CMake runs the build process generates a number of metadata files in the ``build/`` directory. To regenerate these files, run ``cmake`` or ``idf.py reconfigure`` (or any other ``idf.py`` build command). - -- ``compile_commands.json`` is a standard format JSON file which describes every source file which is compiled in the project. A CMake feature generates this file, and many IDEs know how to parse it. -- ``project_description.json`` contains some general information about the ESP-IDF project, configured paths, etc. -- ``flasher_args.json`` contains esptool.py arguments to flash the project's binary files. There are also ``flash_*_args`` files which can be used directly with esptool.py. See `Flash arguments`_. -- ``CMakeCache.txt`` is the CMake cache file which contains other information about the CMake process, toolchain, etc. -- ``config/sdkconfig.json`` is a JSON-formatted version of the project configuration values. -- ``config/kconfig_menus.json`` is a JSON-formatted version of the menus shown in menuconfig, for use in external IDE UIs. - -JSON Configuration Server -------------------------- - -.. highlight :: json - -A tool called ``confserver.py`` is provided to allow IDEs to easily integrate with the configuration system logic. ``confserver.py`` is designed to run in the background and interact with a calling process by reading and writing JSON over process stdin & stdout. - -You can run ``confserver.py`` from a project via ``idf.py confserver`` or ``ninja confserver``, or a similar target triggered from a different build generator. - -The config server outputs human-readable errors and warnings on stderr and JSON on stdout. On startup, it will output the full values of each configuration item in the system as a JSON dictionary, and the available ranges for values which are range constrained. The same information is contained in ``sdkconfig.json``:: - - {"version": 1, "values": { "ITEM": "value", "ITEM_2": 1024, "ITEM_3": false }, "ranges" : { "ITEM_2" : [ 0, 32768 ] } } - -Only visible configuration items are sent. Invisible/disabled items can be parsed from the static ``kconfig_menus.json`` file which also contains the menu structure and other metadata (descriptions, types, ranges, etc.) - -The Configuration Server will then wait for input from the client. The client passes a request to change one or more values, as a JSON object followed by a newline:: - - {"version": "1", "set": {"SOME_NAME": false, "OTHER_NAME": true } } - -The Configuration Server will parse this request, update the project ``sdkconfig`` file, and return a full list of changes:: - - {"version": 1, "values": {"SOME_NAME": false, "OTHER_NAME": true , "DEPENDS_ON_SOME_NAME": null}} - -Items which are now invisible/disabled will return value ``null``. Any item which is newly visible will return its newly visible current value. - -If the range of a config item changes, due to conditional range depending on another value, then this is also sent:: - - {"version": 1, "values": {"OTHER_NAME": true }, "ranges" : { "HAS_RANGE" : [ 3, 4 ] } } - -If invalid data is passed, an "error" field is present on the object:: - - {"version": 1, "values": {}, "error": ["The following config symbol(s) were not visible so were not updated: NOT_VISIBLE_ITEM"]} - -By default, no config changes are written to the sdkconfig file. Changes are held in memory until a "save" command is sent:: - - {"version": 1, "save": null } - -To reload the config values from a saved file, discarding any changes in memory, a "load" command can be sent:: - - {"version": 1, "load": null } - -The value for both "load" and "save" can be a new pathname, or "null" to load/save the previous pathname. - -The response to a "load" command is always the full set of config values and ranges, the same as when the server is initially started. - -Any combination of "load", "set", and "save" can be sent in a single command and commands are executed in that order. Therefore it's possible to load config from a file, set some config item values and then save to a file in a single command. - -.. note:: The configuration server does not automatically load any changes which are applied externally to the ``sdkconfig`` file. Send a "load" command or restart the server if the file is externally edited. - -.. note:: The configuration server does not re-run CMake to regenerate other build files or metadata files after ``sdkconfig`` is updated. This will happen automatically the next time ``CMake`` or ``idf.py`` is run. - -.. _gnu-make-to-cmake: - -Migrating from ESP-IDF GNU Make System -====================================== - -Some aspects of the CMake-based ESP-IDF build system are very similar to the older GNU Make-based system. For example, to adapt a ``component.mk`` file to ``CMakeLists.txt`` variables like ``COMPONENT_ADD_INCLUDEDIRS`` and ``COMPONENT_SRCDIRS`` can stay the same and the syntax only needs changing to CMake syntax. - -Automatic Conversion Tool -------------------------- - -.. highlight:: bash - -An automatic project conversion tool is available in :idf_file:`/tools/cmake/convert_to_cmake.py`. Run this command line tool with the path to a project like this:: - - $IDF_PATH/tools/cmake/convert_to_cmake.py /path/to/project_dir - -The project directory must contain a Makefile, and GNU Make (``make``) must be installed and available on the PATH. - -The tool will convert the project Makefile and any component ``component.mk`` files to their equivalent ``CMakeLists.txt`` files. - -It does so by running ``make`` to expand the ESP-IDF build system variables which are set by the build, and then producing equivalent CMakelists files to set the same variables. - -The conversion tool is not capable of dealing with complex Makefile logic or unusual targets. These will need to be converted by hand. - -No Longer Available in CMake ----------------------------- - -Some features are significantly different or removed in the CMake-based system. The following variables no longer exist in the CMake-based build system: - -- ``COMPONENT_BUILD_DIR``: Use ``CMAKE_CURRENT_BINARY_DIR`` instead. -- ``COMPONENT_LIBRARY``: Defaulted to ``$(COMPONENT_NAME).a``, but the library name could be overriden by the component. The name of the component library can no longer be overriden by the component. -- ``CC``, ``LD``, ``AR``, ``OBJCOPY``: Full paths to each tool from the gcc xtensa cross-toolchain. Use ``CMAKE_C_COMPILER``, ``CMAKE_C_LINK_EXECUTABLE``, ``CMAKE_OBJCOPY``, etc instead. `Full list here `_. -- ``HOSTCC``, ``HOSTLD``, ``HOSTAR``: Full names of each tool from the host native toolchain. These are no longer provided, external projects should detect any required host toolchain manually. -- ``COMPONENT_ADD_LDFLAGS``: Used to override linker flags. Use the CMake `target_link_libraries`_ command instead. -- ``COMPONENT_ADD_LINKER_DEPS``: List of files that linking should depend on. `target_link_libraries`_ will usually infer these dependencies automatically. For linker scripts, use the provided custom CMake function ``target_linker_scripts``. -- ``COMPONENT_SUBMODULES``: No longer used, the build system will automatically enumerate all submodules in the ESP-IDF repository. -- ``COMPONENT_EXTRA_INCLUDES``: Used to be an alternative to ``COMPONENT_PRIV_INCLUDEDIRS`` for absolute paths. Use ``COMPONENT_PRIV_INCLUDEDIRS`` for all cases now (can be relative or absolute). -- ``COMPONENT_OBJS``: Previously, component sources could be specified as a list of object files. Now they can be specified as an list of source files via ``COMPONENT_SRCS``. -- ``COMPONENT_OBJEXCLUDE``: Has been replaced with ``COMPONENT_SRCEXCLUDE``. Specify source files (as absolute paths or relative to component directory), instead. -- ``COMPONENT_EXTRA_CLEAN``: Set property ``ADDITIONAL_MAKE_CLEAN_FILES`` instead but note :ref:`CMake has some restrictions around this functionality `. -- ``COMPONENT_OWNBUILDTARGET`` & ``COMPONENT_OWNCLEANTARGET``: Use CMake `ExternalProject`_ instead. See :ref:`component-build-full-override` for full details. -- ``COMPONENT_CONFIG_ONLY``: Call ``register_config_only_component()`` instead. See `Configuration-Only Components`_. -- ``CFLAGS``, ``CPPFLAGS``, ``CXXFLAGS``: Use equivalent CMake commands instead. See `Controlling Component Compilation`_. - - -No Default Values ------------------ - -The following variables no longer have default values: - -- ``COMPONENT_SRCDIRS`` -- ``COMPONENT_ADD_INCLUDEDIRS`` - -No Longer Necessary -------------------- - -It is no longer necessary to set ``COMPONENT_SRCDIRS`` if setting ``COMPONENT_SRCS`` (in fact, in the CMake-based system ``COMPONENT_SRCS`` is ignored if ``COMPONENT_SRCDIRS`` is set). - -Flashing from make ------------------- - -``make flash`` and similar targets still work to build and flash. However, project ``sdkconfig`` no longer specifies serial port and baud rate. Environment variables can be used to override these. See :ref:`flash-with-ninja-or-make` for more details. - -.. _esp-idf-template: https://github.com/espressif/esp-idf-template -.. _cmake: https://cmake.org -.. _ninja: https://ninja-build.org -.. _esptool.py: https://github.com/espressif/esptool/#readme -.. _CMake v3.5 documentation: https://cmake.org/cmake/help/v3.5/index.html -.. _cmake command line documentation: https://cmake.org/cmake/help/v3.5/manual/cmake.1.html#options -.. _cmake add_library: https://cmake.org/cmake/help/v3.5/command/add_library.html -.. _cmake if: https://cmake.org/cmake/help/v3.5/command/if.html -.. _cmake list: https://cmake.org/cmake/help/v3.5/command/list.html -.. _cmake project: https://cmake.org/cmake/help/v3.5/command/project.html -.. _cmake set: https://cmake.org/cmake/help/v3.5/command/set.html -.. _cmake string: https://cmake.org/cmake/help/v3.5/command/string.html -.. _cmake faq generated files: https://cmake.org/Wiki/CMake_FAQ#How_can_I_generate_a_source_file_during_the_build.3F -.. _ADDITIONAL_MAKE_CLEAN_FILES: https://cmake.org/cmake/help/v3.5/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.html -.. _ExternalProject: https://cmake.org/cmake/help/v3.5/module/ExternalProject.html -.. _cmake language variables: https://cmake.org/cmake/help/v3.5/manual/cmake-variables.7.html#variables-for-languages -.. _set_source_files_properties: https://cmake.org/cmake/help/v3.5/command/set_source_files_properties.html -.. _target_compile_options: https://cmake.org/cmake/help/v3.5/command/target_compile_options.html -.. _target_link_libraries: https://cmake.org/cmake/help/v3.5/command/target_link_libraries.html#command:target_link_libraries -.. _cmake_toolchain_file: https://cmake.org/cmake/help/v3.5/variable/CMAKE_TOOLCHAIN_FILE.html -.. _quirc: https://github.com/dlbeer/quirc -.. _pyenv: https://github.com/pyenv/pyenv#README -.. _virtualenv: https://virtualenv.pypa.io/en/stable/ diff --git a/docs/en/api-guides/build-system-legacy.rst b/docs/en/api-guides/build-system-legacy.rst new file mode 100644 index 0000000000..5f936c05f3 --- /dev/null +++ b/docs/en/api-guides/build-system-legacy.rst @@ -0,0 +1,650 @@ +Build System +************ +:link_to_translation:`zh_CN:[中文]` + +This document explains the Espressif IoT Development Framework build system and the +concept of "components" + +Read this document if you want to know how to organise a new ESP-IDF project. + +We recommend using the esp-idf-template_ project as a starting point for your project. + +Using the Build System +====================== + +The esp-idf README file contains a description of how to use the build system to build your project. + +Overview +======== + +An ESP-IDF project can be seen as an amalgamation of a number of components. +For example, for a webserver that shows the current humidity, there could be: + +- The ESP32 base libraries (libc, rom bindings etc) +- The WiFi drivers +- A TCP/IP stack +- The FreeRTOS operating system +- A webserver +- A driver for the humidity sensor +- Main code tying it all together + +ESP-IDF makes these components explicit and configurable. To do that, +when a project is compiled, the build environment will look up all the +components in the ESP-IDF directories, the project directories and +(optionally) in additional custom component directories. It then +allows the user to configure the ESP-IDF project using a a text-based +menu system to customize each component. After the components in the +project are configured, the build process will compile the project. + +Concepts +-------- + +- A "project" is a directory that contains all the files and configuration to build a single "app" (executable), as well as additional supporting output such as a partition table, data/filesystem partitions, and a bootloader. + +- "Project configuration" is held in a single file called sdkconfig in the root directory of the project. This configuration file is modified via ``make menuconfig`` to customise the configuration of the project. A single project contains exactly one project configuration. + +- An "app" is an executable which is built by esp-idf. A single project will usually build two apps - a "project app" (the main executable, ie your custom firmware) and a "bootloader app" (the initial bootloader program which launches the project app). + +- "components" are modular pieces of standalone code which are compiled into static libraries (.a files) and linked into an app. Some are provided by esp-idf itself, others may be sourced from other places. + +Some things are not part of the project: + +- "ESP-IDF" is not part of the project. Instead it is standalone, and linked to the project via the ``IDF_PATH`` environment variable which holds the path of the ``esp-idf`` directory. This allows the IDF framework to be decoupled from your project. + +- The toolchain for compilation is not part of the project. The toolchain should be installed in the system command line PATH, or the path to the toolchain can be set as part of the compiler prefix in the project configuration. + + +Example Project +--------------- + +An example project directory tree might look like this:: + + - myProject/ + - Makefile + - sdkconfig + - components/ - component1/ - component.mk + - Kconfig + - src1.c + - component2/ - component.mk + - Kconfig + - src1.c + - include/ - component2.h + - main/ - src1.c + - src2.c + - component.mk + + - build/ + +This example "myProject" contains the following elements: + +- A top-level project Makefile. This Makefile sets the ``PROJECT_NAME`` variable and (optionally) defines + other project-wide make variables. It includes the core ``$(IDF_PATH)/make/project.mk`` makefile which + implements the rest of the ESP-IDF build system. + +- "sdkconfig" project configuration file. This file is created/updated when "make menuconfig" runs, and holds configuration for all of the components in the project (including esp-idf itself). The "sdkconfig" file may or may not be added to the source control system of the project. + +- Optional "components" directory contains components that are part of the project. A project does not have to contain custom components of this kind, but it can be useful for structuring reusable code or including third party components that aren't part of ESP-IDF. + +- "main" directory is a special "pseudo-component" that contains source code for the project itself. "main" is a default name, the Makefile variable ``COMPONENT_DIRS`` includes this component but you can modify this variable (or set ``EXTRA_COMPONENT_DIRS``) to look for components in other places. + +- "build" directory is where build output is created. After the make process is run, this directory will contain interim object files and libraries as well as final binary output files. This directory is usually not added to source control or distributed with the project source code. + +Component directories contain a component makefile - ``component.mk``. This may contain variable definitions +to control the build process of the component, and its integration into the overall project. See `Component Makefiles`_ for more details. + +Each component may also include a ``Kconfig`` file defining the `component configuration` options that can be set via the project configuration. Some components may also include ``Kconfig.projbuild`` and ``Makefile.projbuild`` files, which are special files for `overriding parts of the project`. + +Project Makefiles +----------------- + +Each project has a single Makefile that contains build settings for the entire project. By default, the project Makefile can be quite minimal. + +Minimal Example Makefile +^^^^^^^^^^^^^^^^^^^^^^^^ + +:: + + PROJECT_NAME := myProject + + include $(IDF_PATH)/make/project.mk + + +Mandatory Project Variables +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- ``PROJECT_NAME``: Name of the project. Binary output files will use this name - ie myProject.bin, myProject.elf. + +Optional Project Variables +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +These variables all have default values that can be overridden for custom behaviour. Look in ``make/project.mk`` for all of the implementation details. + +- ``PROJECT_PATH``: Top-level project directory. Defaults to the directory containing the Makefile. Many other project variables are based on this variable. The project path cannot contain spaces. +- ``BUILD_DIR_BASE``: The build directory for all objects/libraries/binaries. Defaults to ``$(PROJECT_PATH)/build``. +- ``COMPONENT_DIRS``: Directories to search for components. Defaults to `$(IDF_PATH)/components`, `$(PROJECT_PATH)/components`, ``$(PROJECT_PATH)/main`` and ``EXTRA_COMPONENT_DIRS``. Override this variable if you don't want to search for components in these places. +- ``EXTRA_COMPONENT_DIRS``: Optional list of additional directories to search for components. +- ``COMPONENTS``: A list of component names to build into the project. Defaults to all components found in the COMPONENT_DIRS directories. +- ``EXCLUDE_COMPONENTS``: Optional list of component names to exclude during the build process. Note that this decreases build time, but not binary size. +- ``TEST_EXCLUDE_COMPONENTS``: Optional list of component names to exclude during the build process of unit tests. + +Any paths in these Makefile variables should be absolute paths. You can convert relative paths using ``$(PROJECT_PATH)/xxx``, ``$(IDF_PATH)/xxx``, or use the Make function ``$(abspath xxx)``. + +These variables should all be set before the line ``include $(IDF_PATH)/make/project.mk`` in the Makefile. + +Component Makefiles +------------------- + +Each project contains one or more components, which can either be part of esp-idf or added from other component directories. + +A component is any directory that contains a ``component.mk`` file. + +Searching for Components +------------------------ + +The list of directories in ``COMPONENT_DIRS`` is searched for the project's components. Directories in this list can either be components themselves (ie they contain a `component.mk` file), or they can be top-level directories whose subdirectories are components. + +Running the ``make list-components`` target dumps many of these variables and can help debug the discovery of component directories. + +Multiple components with the same name +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When esp-idf is collecting all the components to compile, it will do this in the order specified by ``COMPONENT_DIRS``; by default, this means the +idf components first, the project components second and optionally the components in ``EXTRA_COMPONENT_DIRS`` last. If two or more of these directories +contain component subdirectories with the same name, the component in the last place searched is used. This allows, for example, overriding esp-idf components +with a modified version by simply copying the component from the esp-idf component directory to the project component tree and then modifying it there. +If used in this way, the esp-idf directory itself can remain untouched. + +Minimal Component Makefile +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The minimal ``component.mk`` file is an empty file(!). If the file is empty, the default component behaviour is set: + +- All source files in the same directory as the makefile (``*.c``, ``*.cpp``, ``*.cc``, ``*.S``) will be compiled into the component library +- A sub-directory "include" will be added to the global include search path for all other components. +- The component library will be linked into the project app. + +See `example component makefiles`_ for more complete component makefile examples. + +Note that there is a difference between an empty ``component.mk`` file (which invokes default component build behaviour) and no ``component.mk`` file (which means no default component build behaviour will occur.) It is possible for a component to have no `component.mk` file, if it only contains other files which influence the project configuration or build process. + +.. component variables: + +Preset Component Variables +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following component-specific variables are available for use inside ``component.mk``, but should not be modified: + +- ``COMPONENT_PATH``: The component directory. Evaluates to the absolute path of the directory containing ``component.mk``. The component path cannot contain spaces. +- ``COMPONENT_NAME``: Name of the component. Defaults to the name of the component directory. +- ``COMPONENT_BUILD_DIR``: The component build directory. Evaluates to the absolute path of a directory inside `$(BUILD_DIR_BASE)` where this component's source files are to be built. This is also the Current Working Directory any time the component is being built, so relative paths in make targets, etc. will be relative to this directory. +- ``COMPONENT_LIBRARY``: Name of the static library file (relative to the component build directory) that will be built for this component. Defaults to ``$(COMPONENT_NAME).a``. + +The following variables are set at the project level, but exported for use in the component build: + +- ``PROJECT_NAME``: Name of the project, as set in project Makefile +- ``PROJECT_PATH``: Absolute path of the project directory containing the project Makefile. +- ``COMPONENTS``: Name of all components that are included in this build. +- ``CONFIG_*``: Each value in the project configuration has a corresponding variable available in make. All names begin with ``CONFIG_``. +- ``CC``, ``LD``, ``AR``, ``OBJCOPY``: Full paths to each tool from the gcc xtensa cross-toolchain. +- ``HOSTCC``, ``HOSTLD``, ``HOSTAR``: Full names of each tool from the host native toolchain. +- ``IDF_VER``: ESP-IDF version, retrieved from either ``$(IDF_PATH)/version.txt`` file (if present) else using git command ``git describe``. Recommended format here is single liner that specifies major IDF release version, e.g. ``v2.0`` for a tagged release or ``v2.0-275-g0efaa4f`` for an arbitrary commit. Application can make use of this by calling :cpp:func:`esp_get_idf_version`. +- ``IDF_VERSION_MAJOR``, ``IDF_VERSION_MINOR``, ``IDF_VERSION_PATCH``: Components of ESP-IDF version, to be used in conditional expressions. Note that this information is less precise than that provided by ``IDF_VER`` variable. ``v4.0-dev-*``, ``v4.0-beta1``, ``v4.0-rc1`` and ``v4.0`` will all have the same values of ``ESP_IDF_VERSION_*`` variables, but different ``IDF_VER`` values. +- ``PROJECT_VER``: Project version. + + * If ``PROJECT_VER`` variable is set in project Makefile file, its value will be used. + * Else, if the ``$PROJECT_PATH/version.txt`` exists, its contents will be used as ``PROJECT_VER``. + * Else, if the project is located inside a Git repository, the output of git describe will be used. + * Otherwise, ``PROJECT_VER`` will be "1". + +If you modify any of these variables inside ``component.mk`` then this will not prevent other components from building but it may make your component hard to build and/or debug. + +Optional Project-Wide Component Variables +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following variables can be set inside ``component.mk`` to control build settings across the entire project: + +- ``COMPONENT_ADD_INCLUDEDIRS``: Paths, relative to the component + directory, which will be added to the include search path for + all components in the project. Defaults to ``include`` if not overridden. If an include directory is only needed to compile + this specific component, add it to ``COMPONENT_PRIV_INCLUDEDIRS`` instead. +- ``COMPONENT_ADD_LDFLAGS``: Add linker arguments to the LDFLAGS for + the app executable. Defaults to ``-l$(COMPONENT_NAME)``. If + adding pre-compiled libraries to this directory, add them as + absolute paths - ie $(COMPONENT_PATH)/libwhatever.a +- ``COMPONENT_DEPENDS``: Optional list of component names that should + be compiled before this component. This is not necessary for + link-time dependencies, because all component include directories + are available at all times. It is necessary if one component + generates an include file which you then want to include in another + component. Most components do not need to set this variable. +- ``COMPONENT_ADD_LINKER_DEPS``: Optional list of component-relative paths + to files which should trigger a re-link of the ELF file if they change. + Typically used for linker script files and binary libraries. Most components do + not need to set this variable. + +The following variable only works for components that are part of esp-idf itself: + +- ``COMPONENT_SUBMODULES``: Optional list of git submodule paths + (relative to COMPONENT_PATH) used by the component. These will be + checked (and initialised if necessary) by the build process. This + variable is ignored if the component is outside the IDF_PATH + directory. + + +Optional Component-Specific Variables +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following variables can be set inside ``component.mk`` to control the build of that component: + +- ``COMPONENT_PRIV_INCLUDEDIRS``: Directory paths, must be relative to + the component directory, which will be added to the include search + path for this component's source files only. +- ``COMPONENT_EXTRA_INCLUDES``: Any extra include paths used when + compiling the component's source files. These will be prefixed with + '-I' and passed as-is to the compiler. Similar to the + ``COMPONENT_PRIV_INCLUDEDIRS`` variable, except these paths are not + expanded relative to the component directory. +- ``COMPONENT_SRCDIRS``: Directory paths, must be relative to the + component directory, which will be searched for source files (``*.cpp``, + ``*.c``, ``*.S``). Defaults to '.', ie the component directory + itself. Override this to specify a different list of directories + which contain source files. +- ``COMPONENT_OBJS``: Object files to compile. Default value is a .o + file for each source file that is found in ``COMPONENT_SRCDIRS``. + Overriding this list allows you to exclude source files in + ``COMPONENT_SRCDIRS`` that would otherwise be compiled. See + `Specifying source files` +- ``COMPONENT_EXTRA_CLEAN``: Paths, relative to the component build + directory, of any files that are generated using custom make rules + in the component.mk file and which need to be removed as part of + ``make clean``. See `Source Code Generation`_ for an example. +- ``COMPONENT_OWNBUILDTARGET`` & ``COMPONENT_OWNCLEANTARGET``: These + targets allow you to fully override the default build behaviour for + the component. See `Fully Overriding The Component Makefile`_ for + more details. +- ``COMPONENT_CONFIG_ONLY``: If set, this flag indicates that the component + produces no built output at all (ie ``COMPONENT_LIBRARY`` is not built), + and most other component variables are ignored. This flag is used for IDF + internal components which contain only ``KConfig.projbuild`` and/or + ``Makefile.projbuild`` files to configure the project, but no source files. +- ``CFLAGS``: Flags passed to the C compiler. A default set of + ``CFLAGS`` is defined based on project settings. Component-specific + additions can be made via ``CFLAGS +=``. It is also possible + (although not recommended) to override this variable completely for + a component. +- ``CPPFLAGS``: Flags passed to the C preprocessor (used for .c, .cpp + and .S files). A default set of ``CPPFLAGS`` is defined based on + project settings. Component-specific additions can be made via + ``CPPFLAGS +=``. It is also possible (although not recommended) to + override this variable completely for a component. +- ``CXXFLAGS``: Flags passed to the C++ compiler. A default set of + ``CXXFLAGS`` is defined based on project + settings. Component-specific additions can be made via ``CXXFLAGS + +=``. It is also possible (although not recommended) to override + this variable completely for a component. +- ``COMPONENT_ADD_LDFRAGMENTS``: Paths to linker fragment files for the linker + script generation functionality. See :doc:`Linker Script Generation `. + +To apply compilation flags to a single source file, you can add a variable override as a target, ie:: + + apps/dhcpserver.o: CFLAGS += -Wno-unused-variable + +This can be useful if there is upstream code that emits warnings. + +Component Configuration +----------------------- + +Each component can also have a Kconfig file, alongside ``component.mk``. This contains contains +configuration settings to add to the "make menuconfig" for this component. + +These settings are found under the "Component Settings" menu when menuconfig is run. + +To create a component KConfig file, it is easiest to start with one of the KConfig files distributed with esp-idf. + +For an example, see `Adding conditional configuration`_. + +Preprocessor Definitions +------------------------ + +ESP-IDF build systems adds the following C preprocessor definitions on the command line: + +- ``ESP_PLATFORM`` — Can be used to detect that build happens within ESP-IDF. +- ``IDF_VER`` — ESP-IDF version, see `Preset Component Variables`_ for more details. + +Build Process Internals +----------------------- + +Top Level: Project Makefile +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- "make" is always run from the project directory and the project makefile, typically named Makefile. +- The project makefile sets ``PROJECT_NAME`` and optionally customises other `optional project variables` +- The project makefile includes ``$(IDF_PATH)/make/project.mk`` which contains the project-level Make logic. +- ``project.mk`` fills in default project-level make variables and includes make variables from the project configuration. If the generated makefile containing project configuration is out of date, then it is regenerated (via targets in ``project_config.mk``) and then the make process restarts from the top. +- ``project.mk`` builds a list of components to build, based on the default component directories or a custom list of components set in `optional project variables`. +- Each component can set some `optional project-wide component variables`_. These are included via generated makefiles named ``component_project_vars.mk`` - there is one per component. These generated makefiles are included into ``project.mk``. If any are missing or out of date, they are regenerated (via a recursive make call to the component makefile) and then the make process restarts from the top. +- `Makefile.projbuild` files from components are included into the make process, to add extra targets or configuration. +- By default, the project makefile also generates top-level build & clean targets for each component and sets up `app` and `clean` targets to invoke all of these sub-targets. +- In order to compile each component, a recursive make is performed for the component makefile. + +To better understand the project make process, have a read through the ``project.mk`` file itself. + +Second Level: Component Makefiles +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Each call to a component makefile goes via the ``$(IDF_PATH)/make/component_wrapper.mk`` wrapper makefile. +- This component wrapper includes all component ``Makefile.componentbuild`` files, making any recipes, variables etc in these files available to every component. +- The ``component_wrapper.mk`` is called with the current directory set to the component build directory, and the ``COMPONENT_MAKEFILE`` variable is set to the absolute path to ``component.mk``. +- ``component_wrapper.mk`` sets default values for all `component variables`, then includes the `component.mk` file which can override or modify these. +- If ``COMPONENT_OWNBUILDTARGET`` and ``COMPONENT_OWNCLEANTARGET`` are not defined, default build and clean targets are created for the component's source files and the prerequisite ``COMPONENT_LIBRARY`` static library file. +- The ``component_project_vars.mk`` file has its own target in ``component_wrapper.mk``, which is evaluated from ``project.mk`` if this file needs to be rebuilt due to changes in the component makefile or the project configuration. + +To better understand the component make process, have a read through the ``component_wrapper.mk`` file and some of the ``component.mk`` files included with esp-idf. + +Running Make Non-Interactively +------------------------------ + +When running ``make`` in a situation where you don't want interactive prompts (for example: inside an IDE or an automated build system) append ``BATCH_BUILD=1`` to the make arguments (or set it as an environment variable). + +Setting ``BATCH_BUILD`` implies the following: + +- Verbose output (same as ``V=1``, see below). If you don't want verbose output, also set ``V=0``. +- If the project configuration is missing new configuration items (from new components or esp-idf updates) then the project use the default values, instead of prompting the user for each item. +- If the build system needs to invoke ``menuconfig``, an error is printed and the build fails. + +.. _make-size: + +Advanced Make Targets +--------------------- + +- ``make app``, ``make bootloader``, ``make partition table`` can be used to build only the app, bootloader, or partition table from the project as applicable. +- ``make erase_flash`` and ``make erase_ota`` will use esptool.py to erase the entire flash chip and the OTA selection setting from the flash chip, respectively. +- ``make size`` prints some size information about the app. ``make size-components`` and ``make size-files`` are similar targets which print more detailed per-component or per-source-file information, respectively. + + +Debugging The Make Process +-------------------------- + +Some tips for debugging the esp-idf build system: + +- Appending ``V=1`` to the make arguments (or setting it as an environment variable) will cause make to echo all commands executed, and also each directory as it is entered for a sub-make. +- Running ``make -w`` will cause make to echo each directory as it is entered for a sub-make - same as ``V=1`` but without also echoing all commands. +- Running ``make --trace`` (possibly in addition to one of the above arguments) will print out every target as it is built, and the dependency which caused it to be built. +- Running ``make -p`` prints a (very verbose) summary of every generated target in each makefile. + +For more debugging tips and general make information, see the `GNU Make Manual`. + +.. _warn-undefined-variables: + +Warning On Undefined Variables +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +By default, the build process will print a warning if an undefined variable is referenced (like ``$(DOES_NOT_EXIST)``). This can be useful to find errors in variable names. + +If you don't want this behaviour, it can be disabled in menuconfig's top level menu under `SDK tool configuration`. + +Note that this option doesn't trigger a warning if ``ifdef`` or ``ifndef`` are used in Makefiles. + +Overriding Parts of the Project +------------------------------- + +Makefile.projbuild +^^^^^^^^^^^^^^^^^^ + +For components that have build requirements that must be evaluated in the top-level +project make pass, you can create a file called ``Makefile.projbuild`` in the +component directory. This makefile is included when ``project.mk`` is evaluated. + +For example, if your component needs to add to CFLAGS for the entire +project (not just for its own source files) then you can set +``CFLAGS +=`` in Makefile.projbuild. + +``Makefile.projbuild`` files are used heavily inside esp-idf, for defining project-wide build features such as ``esptool.py`` command line arguments and the ``bootloader`` "special app". + +Note that ``Makefile.projbuild`` isn't necessary for the most common component uses - such as adding include directories to the project, or LDFLAGS to the final linking step. These values can be customised via the ``component.mk`` file itself. See `Optional Project-Wide Component Variables`_ for details. + +Take care when setting variables or targets in this file. As the values are included into the top-level project makefile pass, they can influence or break functionality across all components! + +KConfig.projbuild +^^^^^^^^^^^^^^^^^ + +This is an equivalent to ``Makefile.projbuild`` for `component configuration` KConfig files. If you want to include +configuration options at the top-level of menuconfig, rather than inside the "Component Configuration" sub-menu, then these can be defined in the KConfig.projbuild file alongside the ``component.mk`` file. + +Take care when adding configuration values in this file, as they will be included across the entire project configuration. Where possible, it's generally better to create a KConfig file for `component configuration`. + + +Makefile.componentbuild +^^^^^^^^^^^^^^^^^^^^^^^ + +For components that e.g. include tools to generate source files from other files, it is necessary to be able to add recipes, macros or variable definitions +into the component build process of every components. This is done by having a ``Makefile.componentbuild`` in a component directory. This file gets included +in ``component_wrapper.mk``, before the ``component.mk`` of the component is included. As with the Makefile.projbuild, take care with these files: as they're +included in each component build, a ``Makefile.componentbuild`` error may only show up when compiling an entirely different component. + +Configuration-Only Components +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Some special components which contain no source files, only ``Kconfig.projbuild`` and ``Makefile.projbuild``, may set the flag ``COMPONENT_CONFIG_ONLY`` in the component.mk file. If this flag is set, most other component variables are ignored and no build step is run for the component. + +Example Component Makefiles +--------------------------- + +Because the build environment tries to set reasonable defaults that will work most +of the time, component.mk can be very small or even empty (see `Minimal Component Makefile`_). However, overriding `component variables` is usually required for some functionality. + +Here are some more advanced examples of ``component.mk`` makefiles: + + +Adding source directories +^^^^^^^^^^^^^^^^^^^^^^^^^ + +By default, sub-directories are ignored. If your project has sources in sub-directories +instead of in the root of the component then you can tell that to the build +system by setting ``COMPONENT_SRCDIRS``:: + + COMPONENT_SRCDIRS := src1 src2 + +This will compile all source files in the src1/ and src2/ sub-directories +instead. + +Specifying source files +^^^^^^^^^^^^^^^^^^^^^^^ + +The standard component.mk logic adds all .S and .c files in the source +directories as sources to be compiled unconditionally. It is possible +to circumvent that logic and hard-code the objects to be compiled by +manually setting the ``COMPONENT_OBJS`` variable to the name of the +objects that need to be generated:: + + COMPONENT_OBJS := file1.o file2.o thing/filea.o thing/fileb.o anotherthing/main.o + COMPONENT_SRCDIRS := . thing anotherthing + +Note that ``COMPONENT_SRCDIRS`` must be set as well. + +Adding conditional configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The configuration system can be used to conditionally compile some files +depending on the options selected in ``make menuconfig``. For this, ESP-IDF +has the compile_only_if and compile_only_if_not macros: + +``Kconfig``:: + + config FOO_ENABLE_BAR + bool "Enable the BAR feature." + help + This enables the BAR feature of the FOO component. + +``component.mk``:: + + $(call compile_only_if,$(CONFIG_FOO_ENABLE_BAR),bar.o) + + +As can be seen in the example, the ``compile_only_if`` macro takes a condition and a +list of object files as parameters. If the condition is true (in this case: if the +BAR feature is enabled in menuconfig) the object files (in this case: bar.o) will +always be compiled. The opposite goes as well: if the condition is not true, bar.o +will never be compiled. ``compile_only_if_not`` does the opposite: compile if the +condition is false, not compile if the condition is true. + +This can also be used to select or stub out an implementation, as such: + +``Kconfig``:: + + config ENABLE_LCD_OUTPUT + bool "Enable LCD output." + help + Select this if your board has a LCD. + + config ENABLE_LCD_CONSOLE + bool "Output console text to LCD" + depends on ENABLE_LCD_OUTPUT + help + Select this to output debugging output to the lcd + + config ENABLE_LCD_PLOT + bool "Output temperature plots to LCD" + depends on ENABLE_LCD_OUTPUT + help + Select this to output temperature plots + + +``component.mk``:: + + # If LCD is enabled, compile interface to it, otherwise compile dummy interface + $(call compile_only_if,$(CONFIG_ENABLE_LCD_OUTPUT),lcd-real.o lcd-spi.o) + $(call compile_only_if_not,$(CONFIG_ENABLE_LCD_OUTPUT),lcd-dummy.o) + + #We need font if either console or plot is enabled + $(call compile_only_if,$(or $(CONFIG_ENABLE_LCD_CONSOLE),$(CONFIG_ENABLE_LCD_PLOT)), font.o) + +Note the use of the Make 'or' function to include the font file. Other substitution functions, +like 'and' and 'if' will also work here. Variables that do not come from menuconfig can also +be used: ESP-IDF uses the default Make policy of judging a variable which is empty or contains +only whitespace to be false while a variable with any non-whitespace in it is true. + +(Note: Older versions of this document advised conditionally adding object file names to +``COMPONENT_OBJS``. While this still is possible, this will only work when all object +files for a component are named explicitely, and will not clean up deselected object files +in a ``make clean`` pass.) + +Source Code Generation +^^^^^^^^^^^^^^^^^^^^^^ + +Some components will have a situation where a source file isn't +supplied with the component itself but has to be generated from +another file. Say our component has a header file that consists of the +converted binary data of a BMP file, converted using a hypothetical +tool called bmp2h. The header file is then included in as C source +file called graphics_lib.c:: + + COMPONENT_EXTRA_CLEAN := logo.h + + graphics_lib.o: logo.h + + logo.h: $(COMPONENT_PATH)/logo.bmp + bmp2h -i $^ -o $@ + + +In this example, graphics_lib.o and logo.h will be generated in the +current directory (the build directory) while logo.bmp comes with the +component and resides under the component path. Because logo.h is a +generated file, it needs to be cleaned when make clean is called which +why it is added to the COMPONENT_EXTRA_CLEAN variable. + +Cosmetic Improvements +^^^^^^^^^^^^^^^^^^^^^ + +Because logo.h is a generated file, it needs to be cleaned when make +clean is called which why it is added to the COMPONENT_EXTRA_CLEAN +variable. + +Adding logo.h to the ``graphics_lib.o`` dependencies causes it to be +generated before ``graphics_lib.c`` is compiled. + +If a a source file in another component included ``logo.h``, then this +component's name would have to be added to the other component's +``COMPONENT_DEPENDS`` list to ensure that the components were built +in-order. + +Embedding Binary Data +^^^^^^^^^^^^^^^^^^^^^ + +Sometimes you have a file with some binary or text data that you'd like to make available to your component - but you don't want to reformat the file as C source. + +You can set a variable COMPONENT_EMBED_FILES in component.mk, giving the names of the files to embed in this way:: + + COMPONENT_EMBED_FILES := server_root_cert.der + +Or if the file is a string, you can use the variable COMPONENT_EMBED_TXTFILES. This will embed the contents of the text file as a null-terminated string:: + + COMPONENT_EMBED_TXTFILES := server_root_cert.pem + +The file's contents will be added to the .rodata section in flash, and are available via symbol names as follows:: + + 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"); + +The names are generated from the full name of the file, as given in COMPONENT_EMBED_FILES. Characters /, ., etc. are replaced with underscores. The _binary prefix in the symbol name is added by objcopy and is the same for both text and binary files. + +For an example of using this technique, see :example:`protocols/https_request` - the certificate file contents are loaded from the text .pem file at compile time. + +Code and Data Placements +------------------------ + +ESP-IDF has a feature called linker script generation that enables components to define where its code and data will be placed in memory through +linker fragment files. These files are processed by the build system, and is used to augment the linker script used for linking +app binary. See :doc:`Linker Script Generation ` for a quick start guide as well as a detailed discussion +of the mechanism. + +Fully Overriding The Component Makefile +--------------------------------------- + +Obviously, there are cases where all these recipes are insufficient for a +certain component, for example when the component is basically a wrapper +around another third-party component not originally intended to be +compiled under this build system. In that case, it's possible to forego +the esp-idf build system entirely by setting COMPONENT_OWNBUILDTARGET and +possibly COMPONENT_OWNCLEANTARGET and defining your own targets named ``build`` and ``clean`` in ``component.mk`` +target. The build target can do anything as long as it creates +$(COMPONENT_LIBRARY) for the project make process to link into the app binary. + +(Actually, even this is not strictly necessary - if the COMPONENT_ADD_LDFLAGS variable +is overridden then the component can instruct the linker to link other binaries instead.) + +.. note:: When using an external build process with PSRAM, remember to add ``-mfix-esp32-psram-cache-issue`` to the C compiler arguments. See :ref:`CONFIG_SPIRAM_CACHE_WORKAROUND` for details of this flag. + +.. _esp-idf-template: https://github.com/espressif/esp-idf-template +.. _GNU Make Manual: https://www.gnu.org/software/make/manual/make.html + + +.. _custom-sdkconfig-defaults: + +Custom sdkconfig defaults +------------------------- + +For example projects or other projects where you don't want to specify a full sdkconfig configuration, but you do want to override some key values from the esp-idf defaults, it is possible to create a file ``sdkconfig.defaults`` in the project directory. This file will be used when running ``make defconfig``, or creating a new config from scratch. + +To override the name of this file, set the ``SDKCONFIG_DEFAULTS`` environment variable. + + +Save flash arguments +-------------------- + +There're some scenarios that we want to flash the target board without IDF. For this case we want to save the built binaries, esptool.py and esptool write_flash arguments. It's simple to write a script to save binaries and esptool.py. We can use command ``make print_flash_cmd``, it will print the flash arguments:: + + --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 bootloader/bootloader.bin 0x10000 example_app.bin 0x8000 partition_table_unit_test_app.bin + +Then use flash arguments as the arguemnts for esptool write_flash arguments:: + + python esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 bootloader/bootloader.bin 0x10000 example_app.bin 0x8000 partition_table_unit_test_app.bin + +Building the Bootloader +======================= + +The bootloader is built by default as part of "make all", or can be built standalone via "make bootloader-clean". There is also "make bootloader-list-components" to see the components included in the bootloader build. + +The component in IDF components/bootloader is special, as the second stage bootloader is a separate .ELF and .BIN file to the main project. However it shares its configuration and build directory with the main project. + +This is accomplished by adding a subproject under components/bootloader/subproject. This subproject has its own Makefile, but it expects to be called from the project's own Makefile via some glue in the components/bootloader/Makefile.projectbuild file. See these files for more details. diff --git a/docs/en/api-guides/build-system.rst b/docs/en/api-guides/build-system.rst index 5f936c05f3..ec63c0fc41 100644 --- a/docs/en/api-guides/build-system.rst +++ b/docs/en/api-guides/build-system.rst @@ -1,18 +1,16 @@ -Build System -************ +Build System (CMake) +******************** + :link_to_translation:`zh_CN:[中文]` -This document explains the Espressif IoT Development Framework build system and the -concept of "components" +.. include:: ../cmake-warning.rst -Read this document if you want to know how to organise a new ESP-IDF project. +.. include:: ../cmake-pending-features.rst -We recommend using the esp-idf-template_ project as a starting point for your project. +This document explains the implementation of the CMake-based ESP-IDF build system and the concept of "components". :doc:`Documentation for the GNU Make based build system ` is also available -Using the Build System -====================== +Read this document if you want to know how to organise and build a new ESP-IDF project or component using the CMake-based build system. -The esp-idf README file contains a description of how to use the build system to build your project. Overview ======== @@ -20,7 +18,7 @@ Overview An ESP-IDF project can be seen as an amalgamation of a number of components. For example, for a webserver that shows the current humidity, there could be: -- The ESP32 base libraries (libc, rom bindings etc) +- The ESP32 base libraries (libc, ROM bindings, etc) - The WiFi drivers - A TCP/IP stack - The FreeRTOS operating system @@ -29,445 +27,537 @@ For example, for a webserver that shows the current humidity, there could be: - Main code tying it all together ESP-IDF makes these components explicit and configurable. To do that, -when a project is compiled, the build environment will look up all the +when a project is compiled, the build system will look up all the components in the ESP-IDF directories, the project directories and (optionally) in additional custom component directories. It then allows the user to configure the ESP-IDF project using a a text-based menu system to customize each component. After the components in the -project are configured, the build process will compile the project. +project are configured, the build system will compile the project. Concepts -------- -- A "project" is a directory that contains all the files and configuration to build a single "app" (executable), as well as additional supporting output such as a partition table, data/filesystem partitions, and a bootloader. +- A "project" is a directory that contains all the files and configuration to build a single "app" (executable), as well as additional supporting elements such as a partition table, data/filesystem partitions, and a bootloader. -- "Project configuration" is held in a single file called sdkconfig in the root directory of the project. This configuration file is modified via ``make menuconfig`` to customise the configuration of the project. A single project contains exactly one project configuration. +- "Project configuration" is held in a single file called ``sdkconfig`` in the root directory of the project. This configuration file is modified via ``idf.py menuconfig`` to customise the configuration of the project. A single project contains exactly one project configuration. -- An "app" is an executable which is built by esp-idf. A single project will usually build two apps - a "project app" (the main executable, ie your custom firmware) and a "bootloader app" (the initial bootloader program which launches the project app). +- An "app" is an executable which is built by ESP-IDF. A single project will usually build two apps - a "project app" (the main executable, ie your custom firmware) and a "bootloader app" (the initial bootloader program which launches the project app). -- "components" are modular pieces of standalone code which are compiled into static libraries (.a files) and linked into an app. Some are provided by esp-idf itself, others may be sourced from other places. +- "components" are modular pieces of standalone code which are compiled into static libraries (.a files) and linked into an app. Some are provided by ESP-IDF itself, others may be sourced from other places. + +- "Target" is the hardware for which an application is built. At the moment, ESP-IDF supports only one target, ``esp32``. Some things are not part of the project: - "ESP-IDF" is not part of the project. Instead it is standalone, and linked to the project via the ``IDF_PATH`` environment variable which holds the path of the ``esp-idf`` directory. This allows the IDF framework to be decoupled from your project. -- The toolchain for compilation is not part of the project. The toolchain should be installed in the system command line PATH, or the path to the toolchain can be set as part of the compiler prefix in the project configuration. +- The toolchain for compilation is not part of the project. The toolchain should be installed in the system command line PATH. +Using the Build System +====================== + +.. _idf.py: + +idf.py +------ + +The ``idf.py`` command line tool provides a front-end for easily managing your project builds. It manages the following tools: + +- CMake_, which configures the project to be built +- A command line build tool (either Ninja_ build or `GNU Make`) +- `esptool.py`_ for flashing ESP32. + +The :ref:`getting started guide ` contains a brief introduction to how to set up ``idf.py`` to configure, build, and flash projects. + +``idf.py`` should be run in an ESP-IDF "project" directory, ie one containing a ``CMakeLists.txt`` file. Older style projects with a Makefile will not work with ``idf.py``. + +Type ``idf.py --help`` for a full list of commands. Here are a summary of the most useful ones: + +- ``idf.py menuconfig`` runs the "menuconfig" tool to configure the project. +- ``idf.py build`` will build the project found in the current directory. This can involve multiple steps: + + - Create the build directory if needed. The sub-directory ``build`` is used to hold build output, although this can be changed with the ``-B`` option. + - Run CMake_ as necessary to configure the project and generate build files for the main build tool. + - Run the main build tool (Ninja_ or `GNU Make`). By default, the build tool is automatically detected but it can be explicitly set by passing the ``-G`` option to ``idf.py``. + + Building is incremental so if no source files or configuration has changed since the last build, nothing will be done. +- ``idf.py clean`` will "clean" the project by deleting build output files from the build directory, forcing a "full rebuild" the next time the project is built. Cleaning doesn't delete CMake configuration output and some other files. +- ``idf.py fullclean`` will delete the entire "build" directory contents. This includes all CMake configuration output. The next time the project is built, CMake will configure it from scratch. Note that this option recursively deletes *all* files in the build directory, so use with care. Project configuration is not deleted. +- ``idf.py flash`` will automatically build the project if necessary, and then flash it to an ESP32. The ``-p`` and ``-b`` options can be used to set serial port name and flasher baud rate, respectively. +- ``idf.py monitor`` will display serial output from the ESP32. The ``-p`` option can be used to set the serial port name. Type ``Ctrl-]`` to exit the monitor. See :doc:`tools/idf-monitor` for more details about using the monitor. + +Multiple ``idf.py`` commands can be combined into one. For example, ``idf.py -p COM4 clean flash monitor`` will clean the source tree, then build the project and flash it to the ESP32 before running the serial monitor. + +.. note:: The environment variables ``ESPPORT`` and ``ESPBAUD`` can be used to set default values for the ``-p`` and ``-b`` options, respectively. Providing these options on the command line overrides the default. + +.. _idf.py-size: + +Advanced Commands +^^^^^^^^^^^^^^^^^ + +- ``idf.py app``, ``idf.py bootloader``, ``idf.py partition_table`` can be used to build only the app, bootloader, or partition table from the project as applicable. +- There are matching commands ``idf.py app-flash``, etc. to flash only that single part of the project to the ESP32. +- ``idf.py -p PORT erase_flash`` will use esptool.py to erase the ESP32's entire flash chip. +- ``idf.py size`` prints some size information about the app. ``size-components`` and ``size-files`` are similar commands which print more detailed per-component or per-source-file information, respectively. If you define variable ``-DOUTPUT_JSON=1`` when running CMake (or ``idf.py``), the output will be formatted as JSON not as human readable text. +- ``idf.py reconfigure`` re-runs CMake_ even if it doesn't seem to need re-running. This isn't necessary during normal usage, but can be useful after adding/removing files from the source tree, or when modifying CMake cache variables. For example, ``idf.py -DNAME='VALUE' reconfigure`` can be used to set variable ``NAME`` in CMake cache to value ``VALUE``. + +The order of multiple ``idf.py`` commands on the same invocation is not important, they will automatically be executed in the correct order for everything to take effect (ie building before flashing, erasing before flashing, etc.). + +Using CMake Directly +-------------------- + +:ref:`idf.py` is a wrapper around CMake_ for convenience. However, you can also invoke CMake directly if you prefer. + +.. highlight:: bash + +When ``idf.py`` does something, it prints each command that it runs for easy reference. For example, the ``idf.py build`` command is the same as running these commands in a bash shell (or similar commands for Windows Command Prompt):: + + mkdir -p build + cd build + cmake .. -G Ninja # or 'Unix Makefiles' + ninja + +In the above list, the ``cmake`` command configures the project and generates build files for use with the final build tool. In this case the final build tool is Ninja_: running ``ninja`` actually builds the project. + +It's not necessary to run ``cmake`` more than once. After the first build, you only need to run ``ninja`` each time. ``ninja`` will automatically re-invoke ``cmake`` if the project needs reconfiguration. + +If using CMake with ``ninja`` or ``make``, there are also targets for more of the ``idf.py`` sub-commands - for example running ``make menuconfig`` or ``ninja menuconfig`` in the build directory will work the same as ``idf.py menuconfig``. + +.. note:: + If you're already familiar with CMake_, you may find the ESP-IDF CMake-based build system unusual because it wraps a lot of CMake's functionality to reduce boilerplate. See `writing pure CMake components`_ for some information about writing more "CMake style" components. + +.. _flash-with-ninja-or-make: + +Flashing with ninja or make +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It's possible to build and flash directly from ninja or make by running a target like:: + + ninja flash + +Or:: + + make app-flash + +Available targets are: ``flash``, ``app-flash`` (app only), ``bootloader-flash`` (bootloader only). + +When flashing this way, optionally set the ``ESPPORT`` and ``ESPBAUD`` environment variables to specify the serial port and baud rate. You can set environment variables in your operating system or IDE project. Alternatively, set them directly on the command line:: + + ESPPORT=/dev/ttyUSB0 ninja flash + +.. note:: Providing environment variables at the start of the command like this is Bash shell Syntax. It will work on Linux and macOS. It won't work when using Windows Command Prompt, but it will work when using Bash-like shells on Windows. + +Or:: + + make -j3 app-flash ESPPORT=COM4 ESPBAUD=2000000 + +.. note:: Providing variables at the end of the command line is ``make`` syntax, and works for ``make`` on all platforms. + + +Using CMake in an IDE +--------------------- + +You can also use an IDE with CMake integration. The IDE will want to know the path to the project's ``CMakeLists.txt`` file. IDEs with CMake integration often provide their own build tools (CMake calls these "generators") to build the source files as part of the IDE. + +When adding custom non-build steps like "flash" to the IDE, it is recommended to execute ``idf.py`` for these "special" commands. + +For more detailed information about integrating ESP-IDF with CMake into an IDE, see `Build System Metadata`_. + +.. _setting-python-interpreter: + +Setting the Python Interpreter +------------------------------ + +Currently, ESP-IDF only works with Python 2.7. If you have a system where the default ``python`` interpreter is Python 3.x, this can lead to problems. + +If using ``idf.py``, running ``idf.py`` as ``python2 $IDF_PATH/tools/idf.py ...`` will work around this issue (``idf.py`` will tell other Python processes to use the same Python interpreter). You can set up a shell alias or another script to simplify the command. + +If using CMake directly, running ``cmake -D PYTHON=python2 ...`` will cause CMake to override the default Python interpreter. + +If using an IDE with CMake, setting the ``PYTHON`` value as a CMake cache override in the IDE UI will override the default Python interpreter. + +To manage the Python version more generally via the command line, check out the tools pyenv_ or virtualenv_. These let you change the default python version. + +.. _example-project-structure: Example Project ---------------- +=============== + +.. highlight:: none An example project directory tree might look like this:: - myProject/ - - Makefile + - CMakeLists.txt - sdkconfig - - components/ - component1/ - component.mk + - components/ - component1/ - CMakeLists.txt - Kconfig - src1.c - - component2/ - component.mk + - component2/ - CMakeLists.txt - Kconfig - src1.c - include/ - component2.h - main/ - src1.c - src2.c - - component.mk - build/ This example "myProject" contains the following elements: -- A top-level project Makefile. This Makefile sets the ``PROJECT_NAME`` variable and (optionally) defines - other project-wide make variables. It includes the core ``$(IDF_PATH)/make/project.mk`` makefile which - implements the rest of the ESP-IDF build system. +- A top-level project CMakeLists.txt file. This is the primary file which CMake uses to learn how to build the project; and may set project-wide CMake variables. It includes the file :idf_file:`/tools/cmake/project.cmake` which + implements the rest of the build system. Finally, it sets the project name and defines the project. -- "sdkconfig" project configuration file. This file is created/updated when "make menuconfig" runs, and holds configuration for all of the components in the project (including esp-idf itself). The "sdkconfig" file may or may not be added to the source control system of the project. +- "sdkconfig" project configuration file. This file is created/updated when ``idf.py menuconfig`` runs, and holds configuration for all of the components in the project (including ESP-IDF itself). The "sdkconfig" file may or may not be added to the source control system of the project. - Optional "components" directory contains components that are part of the project. A project does not have to contain custom components of this kind, but it can be useful for structuring reusable code or including third party components that aren't part of ESP-IDF. -- "main" directory is a special "pseudo-component" that contains source code for the project itself. "main" is a default name, the Makefile variable ``COMPONENT_DIRS`` includes this component but you can modify this variable (or set ``EXTRA_COMPONENT_DIRS``) to look for components in other places. +- "main" directory is a special "pseudo-component" that contains source code for the project itself. "main" is a default name, the CMake variable ``COMPONENT_DIRS`` includes this component but you can modify this variable. Alternatively, ``EXTRA_COMPONENT_DIRS`` can be set in the top-level CMakeLists.txt to look for components in other places. See the :ref:`renaming main ` section for more info. If you have a lot of source files in your project, we recommend grouping most into components instead of putting them all in "main". -- "build" directory is where build output is created. After the make process is run, this directory will contain interim object files and libraries as well as final binary output files. This directory is usually not added to source control or distributed with the project source code. +- "build" directory is where build output is created. This directory is created by ``idf.py`` if it doesn't already exist. CMake configures the project and generates interim build files in this directory. Then, after the main build process is run, this directory will also contain interim object files and libraries as well as final binary output files. This directory is usually not added to source control or distributed with the project source code. -Component directories contain a component makefile - ``component.mk``. This may contain variable definitions -to control the build process of the component, and its integration into the overall project. See `Component Makefiles`_ for more details. +Component directories each contain a component ``CMakeLists.txt`` file. This file contains variable definitions +to control the build process of the component, and its integration into the overall project. See `Component CMakeLists Files`_ for more details. -Each component may also include a ``Kconfig`` file defining the `component configuration` options that can be set via the project configuration. Some components may also include ``Kconfig.projbuild`` and ``Makefile.projbuild`` files, which are special files for `overriding parts of the project`. +Each component may also include a ``Kconfig`` file defining the `component configuration`_ options that can be set via ``menuconfig``. Some components may also include ``Kconfig.projbuild`` and ``project_include.cmake`` files, which are special files for `overriding parts of the project`_. -Project Makefiles ------------------ +Project CMakeLists File +======================= -Each project has a single Makefile that contains build settings for the entire project. By default, the project Makefile can be quite minimal. +Each project has a single top-level ``CMakeLists.txt`` file that contains build settings for the entire project. By default, the project CMakeLists can be quite minimal. -Minimal Example Makefile -^^^^^^^^^^^^^^^^^^^^^^^^ +Minimal Example CMakeLists +-------------------------- -:: +.. highlight:: cmake - PROJECT_NAME := myProject - - include $(IDF_PATH)/make/project.mk +Minimal project:: + + cmake_minimum_required(VERSION 3.5) + include($ENV{IDF_PATH}/tools/cmake/project.cmake) + project(myProject) -Mandatory Project Variables -^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. _project-mandatory-parts: + +Mandatory Parts +--------------- + +The inclusion of these three lines, in the order shown above, is necessary for every project: + +- ``cmake_minimum_required(VERSION 3.5)`` tells CMake the minimum version that is required to build the project. ESP-IDF is designed to work with CMake 3.5 or newer. This line must be the first line in the CMakeLists.txt file. +- ``include($ENV{IDF_PATH}/tools/cmake/project.cmake)`` pulls in the rest of the CMake functionality to configure the project, discover all the components, etc. +- ``project(myProject)`` creates the project itself, and specifies the project name. The project name is used for the final binary output files of the app - ie ``myProject.elf``, ``myProject.bin``. Only one project can be defined per CMakeLists file. -- ``PROJECT_NAME``: Name of the project. Binary output files will use this name - ie myProject.bin, myProject.elf. Optional Project Variables -^^^^^^^^^^^^^^^^^^^^^^^^^^ +-------------------------- -These variables all have default values that can be overridden for custom behaviour. Look in ``make/project.mk`` for all of the implementation details. +These variables all have default values that can be overridden for custom behaviour. Look in :idf_file:`/tools/cmake/project.cmake` for all of the implementation details. -- ``PROJECT_PATH``: Top-level project directory. Defaults to the directory containing the Makefile. Many other project variables are based on this variable. The project path cannot contain spaces. -- ``BUILD_DIR_BASE``: The build directory for all objects/libraries/binaries. Defaults to ``$(PROJECT_PATH)/build``. -- ``COMPONENT_DIRS``: Directories to search for components. Defaults to `$(IDF_PATH)/components`, `$(PROJECT_PATH)/components`, ``$(PROJECT_PATH)/main`` and ``EXTRA_COMPONENT_DIRS``. Override this variable if you don't want to search for components in these places. -- ``EXTRA_COMPONENT_DIRS``: Optional list of additional directories to search for components. -- ``COMPONENTS``: A list of component names to build into the project. Defaults to all components found in the COMPONENT_DIRS directories. -- ``EXCLUDE_COMPONENTS``: Optional list of component names to exclude during the build process. Note that this decreases build time, but not binary size. -- ``TEST_EXCLUDE_COMPONENTS``: Optional list of component names to exclude during the build process of unit tests. +- ``COMPONENT_DIRS``,``COMPONENTS_DIRS``: Directories to search for components. Defaults to `IDF_PATH/components`, `PROJECT_DIR/components`, and ``EXTRA_COMPONENT_DIRS``. Override this variable if you don't want to search for components in these places. +- ``EXTRA_COMPONENT_DIRS``, ``EXTRA_COMPONENTS_DIRS``: Optional list of additional directories to search for components. Paths can be relative to the project directory, or absolute. +- ``COMPONENTS``: A list of component names to build into the project. Defaults to all components found in the ``COMPONENT_DIRS`` directories. Use this variable to "trim down" the project for faster build times. Note that any component which "requires" another component via the REQUIRES or PRIV_REQUIRES arguments on component registration will automatically have it added to this list, so the ``COMPONENTS`` list can be very short. -Any paths in these Makefile variables should be absolute paths. You can convert relative paths using ``$(PROJECT_PATH)/xxx``, ``$(IDF_PATH)/xxx``, or use the Make function ``$(abspath xxx)``. +Any paths in these variables can be absolute paths, or set relative to the project directory. -These variables should all be set before the line ``include $(IDF_PATH)/make/project.mk`` in the Makefile. +To set these variables, use the `cmake set command `_ ie ``set(VARIABLE "VALUE")``. The ``set()`` commands should be placed after the ``cmake_minimum(...)`` line but before the ``include(...)`` line. -Component Makefiles -------------------- +.. _rename-main-cmake: -Each project contains one or more components, which can either be part of esp-idf or added from other component directories. +Renaming ``main`` component +---------------------------- -A component is any directory that contains a ``component.mk`` file. +The build system provides special treatment to the ``main`` component. It is a component that gets automatically added to the build provided +that it is in the expected location, PROJECT_DIR/main. All other components in the build are also added as its dependencies, +saving the user from hunting down dependencies and providing a build that works right out of the box. Renaming the ``main`` component +causes the loss of these behind-the-scences heavy lifting, requiring the user to specify the location of the newly renamed component +and manually specifying its dependencies. Specifically, the steps to renaming ``main`` are as follows: + +1. Rename ``main`` directory. +2. Set ``EXTRA_COMPONENT_DIRS`` in the project CMakeLists.txt to include the renamed ``main`` directory. +3. Specify the dependencies in the renamed component's CMakeLists.txt file via REQUIRES or PRIV_REQUIRES arguments :ref:`on component registration`. + +.. _component-directories-cmake: + +Component CMakeLists Files +========================== + +Each project contains one or more components. Components can be part of ESP-IDF, part of the project's own components directory, or added from custom component directories (:ref:`see above `). + +A component is any directory in the ``COMPONENT_DIRS`` list which contains a ``CMakeLists.txt`` file. Searching for Components ------------------------ -The list of directories in ``COMPONENT_DIRS`` is searched for the project's components. Directories in this list can either be components themselves (ie they contain a `component.mk` file), or they can be top-level directories whose subdirectories are components. +The list of directories in ``COMPONENT_DIRS`` is searched for the project's components. Directories in this list can either be components themselves (ie they contain a `CMakeLists.txt` file), or they can be top-level directories whose sub-directories are components. -Running the ``make list-components`` target dumps many of these variables and can help debug the discovery of component directories. +When CMake runs to configure the project, it logs the components included in the build. This list can be useful for debugging the inclusion/exclusion of certain components. Multiple components with the same name -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-------------------------------------- -When esp-idf is collecting all the components to compile, it will do this in the order specified by ``COMPONENT_DIRS``; by default, this means the -idf components first, the project components second and optionally the components in ``EXTRA_COMPONENT_DIRS`` last. If two or more of these directories -contain component subdirectories with the same name, the component in the last place searched is used. This allows, for example, overriding esp-idf components -with a modified version by simply copying the component from the esp-idf component directory to the project component tree and then modifying it there. -If used in this way, the esp-idf directory itself can remain untouched. +When ESP-IDF is collecting all the components to compile, it will do this in the order specified by ``COMPONENT_DIRS``; by default, this means ESP-IDF's internal components first, then the project's components, and finally any components set in ``EXTRA_COMPONENT_DIRS``. If two or more of these directories +contain component sub-directories with the same name, the component in the last place searched is used. This allows, for example, overriding ESP-IDF components +with a modified version by copying that component from the ESP-IDF components directory to the project components directory and then modifying it there. +If used in this way, the ESP-IDF directory itself can remain untouched. -Minimal Component Makefile -^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. _cmake_minimal_component_cmakelists: -The minimal ``component.mk`` file is an empty file(!). If the file is empty, the default component behaviour is set: +Minimal Component CMakeLists +---------------------------- -- All source files in the same directory as the makefile (``*.c``, ``*.cpp``, ``*.cc``, ``*.S``) will be compiled into the component library -- A sub-directory "include" will be added to the global include search path for all other components. -- The component library will be linked into the project app. +.. highlight:: cmake -See `example component makefiles`_ for more complete component makefile examples. +The minimal component ``CMakeLists.txt`` file simply registers the component to the build system using ``idf_component_register``:: -Note that there is a difference between an empty ``component.mk`` file (which invokes default component build behaviour) and no ``component.mk`` file (which means no default component build behaviour will occur.) It is possible for a component to have no `component.mk` file, if it only contains other files which influence the project configuration or build process. + idf_component_register(SRCS "foo.c" "bar.c" + INCLUDE_DIRS "include") -.. component variables: +- ``SRCS`` is a list of source files (``*.c``, ``*.cpp``, ``*.cc``, ``*.S``). These source files will be compiled into the component library. +- ``INCLUDE_DIRS`` is a list of directories to add to the global include search path for any component which requires this component, and also the main source files. + +A library with the name of the component will be built and linked into the final app. +Directories are usually specified relative to the ``CMakeLists.txt`` file itself, although they can be absolute. + +There are other arguments that can be passed to ``idf_component_register``. These arguments +are discussed :ref:`here`. + +See `example component CMakeLists`_ for more complete component ``CMakeLists.txt`` examples. + +.. _component variables: Preset Component Variables -^^^^^^^^^^^^^^^^^^^^^^^^^^ +-------------------------- -The following component-specific variables are available for use inside ``component.mk``, but should not be modified: +The following component-specific variables are available for use inside component CMakeLists, but should not be modified: -- ``COMPONENT_PATH``: The component directory. Evaluates to the absolute path of the directory containing ``component.mk``. The component path cannot contain spaces. -- ``COMPONENT_NAME``: Name of the component. Defaults to the name of the component directory. -- ``COMPONENT_BUILD_DIR``: The component build directory. Evaluates to the absolute path of a directory inside `$(BUILD_DIR_BASE)` where this component's source files are to be built. This is also the Current Working Directory any time the component is being built, so relative paths in make targets, etc. will be relative to this directory. -- ``COMPONENT_LIBRARY``: Name of the static library file (relative to the component build directory) that will be built for this component. Defaults to ``$(COMPONENT_NAME).a``. +- ``COMPONENT_DIR``: The component directory. Evaluates to the absolute path of the directory containing ``CMakeLists.txt``. The component path cannot contain spaces. This is the same as the ``CMAKE_CURRENT_SOURCE_DIR`` variable. +- ``COMPONENT_NAME``: Name of the component. Same as the name of the component directory. +- ``COMPONENT_ALIAS``: Alias of the library created internally by the build system for the component. +- ``COMPONENT_LIB``: Name of the library created internally by the build system for the component. -The following variables are set at the project level, but exported for use in the component build: +The following variables are set at the project level, but available for use in component CMakeLists: -- ``PROJECT_NAME``: Name of the project, as set in project Makefile -- ``PROJECT_PATH``: Absolute path of the project directory containing the project Makefile. -- ``COMPONENTS``: Name of all components that are included in this build. -- ``CONFIG_*``: Each value in the project configuration has a corresponding variable available in make. All names begin with ``CONFIG_``. -- ``CC``, ``LD``, ``AR``, ``OBJCOPY``: Full paths to each tool from the gcc xtensa cross-toolchain. -- ``HOSTCC``, ``HOSTLD``, ``HOSTAR``: Full names of each tool from the host native toolchain. -- ``IDF_VER``: ESP-IDF version, retrieved from either ``$(IDF_PATH)/version.txt`` file (if present) else using git command ``git describe``. Recommended format here is single liner that specifies major IDF release version, e.g. ``v2.0`` for a tagged release or ``v2.0-275-g0efaa4f`` for an arbitrary commit. Application can make use of this by calling :cpp:func:`esp_get_idf_version`. -- ``IDF_VERSION_MAJOR``, ``IDF_VERSION_MINOR``, ``IDF_VERSION_PATCH``: Components of ESP-IDF version, to be used in conditional expressions. Note that this information is less precise than that provided by ``IDF_VER`` variable. ``v4.0-dev-*``, ``v4.0-beta1``, ``v4.0-rc1`` and ``v4.0`` will all have the same values of ``ESP_IDF_VERSION_*`` variables, but different ``IDF_VER`` values. -- ``PROJECT_VER``: Project version. +- ``CONFIG_*``: Each value in the project configuration has a corresponding variable available in cmake. All names begin with ``CONFIG_``. :doc:`More information here `. +- ``ESP_PLATFORM``: Set to 1 when the CMake file is processed within ESP-IDF build system. - * If ``PROJECT_VER`` variable is set in project Makefile file, its value will be used. - * Else, if the ``$PROJECT_PATH/version.txt`` exists, its contents will be used as ``PROJECT_VER``. +Build/Project Variables +------------------------ + +The following are some project/build variables that are available as build properties and whose values can be queried using ``idf_build_get_property`` +from the component CMakeLists.txt: + +- ``PROJECT_NAME``: Name of the project, as set in project CMakeLists.txt file. +- ``PROJECT_DIR``: Absolute path of the project directory containing the project CMakeLists. Same as the ``CMAKE_SOURCE_DIR`` variable. +- ``COMPONENTS``: Names of all components that are included in this build, formatted as a semicolon-delimited CMake list. +- ``IDF_VER``: Git version of ESP-IDF (produced by ``git describe``) +- ``IDF_VERSION_MAJOR``, ``IDF_VERSION_MINOR``, ``IDF_VERSION_PATCH``: Components of ESP-IDF version, to be used in conditional expressions. Note that this information is less precise than that provided by ``IDF_VER`` variable. ``v4.0-dev-*``, ``v4.0-beta1``, ``v4.0-rc1`` and ``v4.0`` will all have the same values of ``IDF_VERSION_*`` variables, but different ``IDF_VER`` values. +- ``IDF_TARGET``: Name of the target for which the project is being built. +- ``PROJECT_VER``: Project version. + + * If ``PROJECT_VER`` variable is set in project CMakeLists.txt file, its value will be used. + * Else, if the ``PROJECT_DIR/version.txt`` exists, its contents will be used as ``PROJECT_VER``. * Else, if the project is located inside a Git repository, the output of git describe will be used. * Otherwise, ``PROJECT_VER`` will be "1". -If you modify any of these variables inside ``component.mk`` then this will not prevent other components from building but it may make your component hard to build and/or debug. +Other build properties are listed :ref:`here`. -Optional Project-Wide Component Variables -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Controlling Component Compilation +--------------------------------- -The following variables can be set inside ``component.mk`` to control build settings across the entire project: +.. highlight:: cmake -- ``COMPONENT_ADD_INCLUDEDIRS``: Paths, relative to the component - directory, which will be added to the include search path for - all components in the project. Defaults to ``include`` if not overridden. If an include directory is only needed to compile - this specific component, add it to ``COMPONENT_PRIV_INCLUDEDIRS`` instead. -- ``COMPONENT_ADD_LDFLAGS``: Add linker arguments to the LDFLAGS for - the app executable. Defaults to ``-l$(COMPONENT_NAME)``. If - adding pre-compiled libraries to this directory, add them as - absolute paths - ie $(COMPONENT_PATH)/libwhatever.a -- ``COMPONENT_DEPENDS``: Optional list of component names that should - be compiled before this component. This is not necessary for - link-time dependencies, because all component include directories - are available at all times. It is necessary if one component - generates an include file which you then want to include in another - component. Most components do not need to set this variable. -- ``COMPONENT_ADD_LINKER_DEPS``: Optional list of component-relative paths - to files which should trigger a re-link of the ELF file if they change. - Typically used for linker script files and binary libraries. Most components do - not need to set this variable. +To pass compiler options when compiling source files belonging to a particular component, use the ``target_compile_options`` function:: -The following variable only works for components that are part of esp-idf itself: + target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-variable) -- ``COMPONENT_SUBMODULES``: Optional list of git submodule paths - (relative to COMPONENT_PATH) used by the component. These will be - checked (and initialised if necessary) by the build process. This - variable is ignored if the component is outside the IDF_PATH - directory. +To apply the compilation flags to a single source file, use the CMake `set_source_files_properties`_ command:: - -Optional Component-Specific Variables -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The following variables can be set inside ``component.mk`` to control the build of that component: - -- ``COMPONENT_PRIV_INCLUDEDIRS``: Directory paths, must be relative to - the component directory, which will be added to the include search - path for this component's source files only. -- ``COMPONENT_EXTRA_INCLUDES``: Any extra include paths used when - compiling the component's source files. These will be prefixed with - '-I' and passed as-is to the compiler. Similar to the - ``COMPONENT_PRIV_INCLUDEDIRS`` variable, except these paths are not - expanded relative to the component directory. -- ``COMPONENT_SRCDIRS``: Directory paths, must be relative to the - component directory, which will be searched for source files (``*.cpp``, - ``*.c``, ``*.S``). Defaults to '.', ie the component directory - itself. Override this to specify a different list of directories - which contain source files. -- ``COMPONENT_OBJS``: Object files to compile. Default value is a .o - file for each source file that is found in ``COMPONENT_SRCDIRS``. - Overriding this list allows you to exclude source files in - ``COMPONENT_SRCDIRS`` that would otherwise be compiled. See - `Specifying source files` -- ``COMPONENT_EXTRA_CLEAN``: Paths, relative to the component build - directory, of any files that are generated using custom make rules - in the component.mk file and which need to be removed as part of - ``make clean``. See `Source Code Generation`_ for an example. -- ``COMPONENT_OWNBUILDTARGET`` & ``COMPONENT_OWNCLEANTARGET``: These - targets allow you to fully override the default build behaviour for - the component. See `Fully Overriding The Component Makefile`_ for - more details. -- ``COMPONENT_CONFIG_ONLY``: If set, this flag indicates that the component - produces no built output at all (ie ``COMPONENT_LIBRARY`` is not built), - and most other component variables are ignored. This flag is used for IDF - internal components which contain only ``KConfig.projbuild`` and/or - ``Makefile.projbuild`` files to configure the project, but no source files. -- ``CFLAGS``: Flags passed to the C compiler. A default set of - ``CFLAGS`` is defined based on project settings. Component-specific - additions can be made via ``CFLAGS +=``. It is also possible - (although not recommended) to override this variable completely for - a component. -- ``CPPFLAGS``: Flags passed to the C preprocessor (used for .c, .cpp - and .S files). A default set of ``CPPFLAGS`` is defined based on - project settings. Component-specific additions can be made via - ``CPPFLAGS +=``. It is also possible (although not recommended) to - override this variable completely for a component. -- ``CXXFLAGS``: Flags passed to the C++ compiler. A default set of - ``CXXFLAGS`` is defined based on project - settings. Component-specific additions can be made via ``CXXFLAGS - +=``. It is also possible (although not recommended) to override - this variable completely for a component. -- ``COMPONENT_ADD_LDFRAGMENTS``: Paths to linker fragment files for the linker - script generation functionality. See :doc:`Linker Script Generation `. - -To apply compilation flags to a single source file, you can add a variable override as a target, ie:: - - apps/dhcpserver.o: CFLAGS += -Wno-unused-variable + set_source_files_properties(mysrc.c + PROPERTIES COMPILE_FLAGS + -Wno-unused-variable + ) This can be useful if there is upstream code that emits warnings. -Component Configuration ------------------------ +When using these commands, place them after the call to ``idf_component_register`` in the component CMakeLists file. -Each component can also have a Kconfig file, alongside ``component.mk``. This contains contains -configuration settings to add to the "make menuconfig" for this component. +.. _component-configuration-cmake: + +Component Configuration +======================= + +Each component can also have a ``Kconfig`` file, alongside ``CMakeLists.txt``. This contains +configuration settings to add to the configuration menu for this component. These settings are found under the "Component Settings" menu when menuconfig is run. -To create a component KConfig file, it is easiest to start with one of the KConfig files distributed with esp-idf. +To create a component Kconfig file, it is easiest to start with one of the Kconfig files distributed with ESP-IDF. For an example, see `Adding conditional configuration`_. Preprocessor Definitions +======================== + +The ESP-IDF build system adds the following C preprocessor definitions on the command line: + +- ``ESP_PLATFORM`` : Can be used to detect that build happens within ESP-IDF. +- ``IDF_VER`` : Defined to a git version string. E.g. ``v2.0`` for a tagged release or ``v1.0-275-g0efaa4f`` for an arbitrary commit. + +Component Requirements +====================== + +When compiling each component, the ESP-IDF build system recursively evaluates its components. + +Each component's source file is compiled with these include path directories, as specified in the passed arguments +to ``idf_component_register``: + +- The current component's ``INCLUDE_DIRS`` and ``PRIV_INCLUDE_DIRS``. +- The ``INCLUDE_DIRS`` set by all components in the current component's ``REQUIRES`` and ``PRIV_REQUIRES`` variables (ie all the current component's public and private dependencies). +- All of the ``REQUIRES`` of those components, evaluated recursively (ie all public dependencies of this component's dependencies, recursively expanded). + +When writing a component ------------------------ -ESP-IDF build systems adds the following C preprocessor definitions on the command line: +- ``REQUIRES`` should be set to all components whose header files are #included from the *public* header files of this component. +- ``PRIV_REQUIRES`` should be set to all components whose header files are #included from *any source files* of this component, unless already listed in ``COMPONENT_REQUIRES``. Or any component which is required to be linked in order for this component to function correctly. +- ``REQUIRES`` and/or ``PRIV_REQUIRES`` should be set before calling ``idf_component_register()``. +- The values of ``REQUIRES`` and ``PRIV_REQUIRES`` should not depend on any configuration choices (``CONFIG_xxx`` macros). This is because requirements are expanded before configuration is loaded. Other component variables (like include paths or source files) can depend on configuration choices. +- Not setting either or both ``REQUIRES`` variables is fine. If the component has no requirements except for the "common" components needed for RTOS, libc, etc (``COMPONENT_REQUIRES_COMMON``) then both variables can be empty or unset. -- ``ESP_PLATFORM`` — Can be used to detect that build happens within ESP-IDF. -- ``IDF_VER`` — ESP-IDF version, see `Preset Component Variables`_ for more details. +Components which support only some targets (values of ``IDF_TARGET``) may specify ``REQUIRED_IDF_TARGETS`` in the ``idf_component_register`` call to express these requirements. In this case the build system will generate an error if the component is included into the build, but does not support selected target. -Build Process Internals +When creating a project ----------------------- -Top Level: Project Makefile -^^^^^^^^^^^^^^^^^^^^^^^^^^^ +- By default, every component is included in the build. +- If you set the ``COMPONENTS`` variable to a minimal list of components used directly by your project, then the build will include: -- "make" is always run from the project directory and the project makefile, typically named Makefile. -- The project makefile sets ``PROJECT_NAME`` and optionally customises other `optional project variables` -- The project makefile includes ``$(IDF_PATH)/make/project.mk`` which contains the project-level Make logic. -- ``project.mk`` fills in default project-level make variables and includes make variables from the project configuration. If the generated makefile containing project configuration is out of date, then it is regenerated (via targets in ``project_config.mk``) and then the make process restarts from the top. -- ``project.mk`` builds a list of components to build, based on the default component directories or a custom list of components set in `optional project variables`. -- Each component can set some `optional project-wide component variables`_. These are included via generated makefiles named ``component_project_vars.mk`` - there is one per component. These generated makefiles are included into ``project.mk``. If any are missing or out of date, they are regenerated (via a recursive make call to the component makefile) and then the make process restarts from the top. -- `Makefile.projbuild` files from components are included into the make process, to add extra targets or configuration. -- By default, the project makefile also generates top-level build & clean targets for each component and sets up `app` and `clean` targets to invoke all of these sub-targets. -- In order to compile each component, a recursive make is performed for the component makefile. + - Components mentioned explicitly in ``COMPONENTS``. + - Those components' requirements (evaluated recursively). + - The "common" components that every component depends on. +- Setting ``COMPONENTS`` to the minimal list of required components can significantly reduce compile times. -To better understand the project make process, have a read through the ``project.mk`` file itself. +.. _component-requirements-implementation: -Second Level: Component Makefiles -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Requirements in the build system implementation +----------------------------------------------- -- Each call to a component makefile goes via the ``$(IDF_PATH)/make/component_wrapper.mk`` wrapper makefile. -- This component wrapper includes all component ``Makefile.componentbuild`` files, making any recipes, variables etc in these files available to every component. -- The ``component_wrapper.mk`` is called with the current directory set to the component build directory, and the ``COMPONENT_MAKEFILE`` variable is set to the absolute path to ``component.mk``. -- ``component_wrapper.mk`` sets default values for all `component variables`, then includes the `component.mk` file which can override or modify these. -- If ``COMPONENT_OWNBUILDTARGET`` and ``COMPONENT_OWNCLEANTARGET`` are not defined, default build and clean targets are created for the component's source files and the prerequisite ``COMPONENT_LIBRARY`` static library file. -- The ``component_project_vars.mk`` file has its own target in ``component_wrapper.mk``, which is evaluated from ``project.mk`` if this file needs to be rebuilt due to changes in the component makefile or the project configuration. +- Very early in the CMake configuration process, the script ``expand_requirements.cmake`` is run. This script does a partial evaluation of all component CMakeLists.txt files and builds a graph of component requirements (this graph may have cycles). The graph is used to generate a file ``component_depends.cmake`` in the build directory. +- The main CMake process then includes this file and uses it to determine the list of components to include in the build (internal ``BUILD_COMPONENTS`` variable). The ``BUILD_COMPONENTS`` variable is sorted so dependencies are listed first, however as the component dependency graph has cycles this cannot be guaranteed for all components. The order should be deterministic given the same set of components and component dependencies. +- The value of ``BUILD_COMPONENTS`` is logged by CMake as "Component names: " +- Configuration is then evaluated for the components included in the build. +- Each component is included in the build normally and the CMakeLists.txt file is evaluated again to add the component libraries to the build. -To better understand the component make process, have a read through the ``component_wrapper.mk`` file and some of the ``component.mk`` files included with esp-idf. +Component Dependency Order +^^^^^^^^^^^^^^^^^^^^^^^^^^ -Running Make Non-Interactively ------------------------------- +The order of components in the ``BUILD_COMPONENTS`` variable determines other orderings during the build: -When running ``make`` in a situation where you don't want interactive prompts (for example: inside an IDE or an automated build system) append ``BATCH_BUILD=1`` to the make arguments (or set it as an environment variable). +- Order that :ref:`project_include.cmake` files are included into the project. +- Order that the list of header paths is generated for compilation (via ``-I`` argument). (Note that for a given component's source files, only that component's dependency's header paths are passed to the compiler.) -Setting ``BATCH_BUILD`` implies the following: +Build Process Internals +======================= -- Verbose output (same as ``V=1``, see below). If you don't want verbose output, also set ``V=0``. -- If the project configuration is missing new configuration items (from new components or esp-idf updates) then the project use the default values, instead of prompting the user for each item. -- If the build system needs to invoke ``menuconfig``, an error is printed and the build fails. +For full details about CMake_ and CMake commands, see the `CMake v3.5 documentation`_. -.. _make-size: +project.cmake contents +---------------------- -Advanced Make Targets ---------------------- +When included from a project CMakeLists file, the ``project.cmake`` file defines some utility modules and global variables and then sets ``IDF_PATH`` if it was not set in the system environment. -- ``make app``, ``make bootloader``, ``make partition table`` can be used to build only the app, bootloader, or partition table from the project as applicable. -- ``make erase_flash`` and ``make erase_ota`` will use esptool.py to erase the entire flash chip and the OTA selection setting from the flash chip, respectively. -- ``make size`` prints some size information about the app. ``make size-components`` and ``make size-files`` are similar targets which print more detailed per-component or per-source-file information, respectively. +It also defines an overridden custom version of the built-in CMake_ ``project`` function. This function is overridden to add all of the ESP-IDF specific project functionality. +project function +---------------- -Debugging The Make Process --------------------------- +The custom ``project()`` function performs the following steps: -Some tips for debugging the esp-idf build system: +- Determines the target (set by ``IDF_TARGET`` environment variable) and saves the target in CMake cache. If the target set in the environment does not match the one in cache, exits with an error. +- Evaluates component dependencies and builds the ``BUILD_COMPONENTS`` list of components to include in the build (see :ref:`above`). +- Finds all components in the project (searching ``COMPONENT_DIRS`` and filtering by ``COMPONENTS`` if this is set). +- Loads the project configuration from the ``sdkconfig`` file and generates a ``sdkconfig.cmake`` file and a ``sdkconfig.h`` header. These define configuration values in CMake and C/C++, respectively. If the project configuration changes, cmake will automatically be re-run to re-generate these files and re-configure the project. +- Sets the `CMAKE_TOOLCHAIN_FILE`_ variable to the correct toolchain file, depending on the target. +- Declares the actual cmake-level project by calling the `CMake project function `_. +- Loads the git version. This includes some magic which will automatically re-run CMake if a new revision is checked out in git. See `File Globbing & Incremental Builds`_. +- Includes :ref:`project_include.cmake` files from any components which have them. +- Adds each component to the build. Each component CMakeLists file calls ``idf_component_register``, calls the CMake `add_library `_ function to add a library and then adds source files, compile options, etc. +- Adds the final app executable to the build. +- Goes back and adds inter-component dependencies between components (ie adding the public header directories of each component to each other component). -- Appending ``V=1`` to the make arguments (or setting it as an environment variable) will cause make to echo all commands executed, and also each directory as it is entered for a sub-make. -- Running ``make -w`` will cause make to echo each directory as it is entered for a sub-make - same as ``V=1`` but without also echoing all commands. -- Running ``make --trace`` (possibly in addition to one of the above arguments) will print out every target as it is built, and the dependency which caused it to be built. -- Running ``make -p`` prints a (very verbose) summary of every generated target in each makefile. +Browse the :idf_file:`/tools/cmake/project.cmake` file and supporting functions in :idf_file:`/tools/cmake/idf_functions.cmake` for more details. -For more debugging tips and general make information, see the `GNU Make Manual`. +Debugging CMake +--------------- -.. _warn-undefined-variables: +Some tips for debugging the ESP-IDF CMake-based build system: + +- When CMake runs, it prints quite a lot of diagnostic information including lists of components and component paths. +- Running ``cmake -DDEBUG=1`` will produce more verbose diagnostic output from the IDF build system. +- Running ``cmake`` with the ``--trace`` or ``--trace-expand`` options will give a lot of information about control flow. See the `cmake command line documentation`_. + +.. _warn-undefined-variables-cmake: Warning On Undefined Variables ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -By default, the build process will print a warning if an undefined variable is referenced (like ``$(DOES_NOT_EXIST)``). This can be useful to find errors in variable names. +By default, ``idf.py`` passes the ``--warn-uninitialized`` flag to CMake_ so it will print a warning if an undefined variable is referenced in the build. This can be very useful to find buggy CMake files. -If you don't want this behaviour, it can be disabled in menuconfig's top level menu under `SDK tool configuration`. - -Note that this option doesn't trigger a warning if ``ifdef`` or ``ifndef`` are used in Makefiles. +If you don't want this behaviour, it can be disabled by passing ``--no-warnings`` to ``idf.py``. Overriding Parts of the Project ------------------------------- -Makefile.projbuild -^^^^^^^^^^^^^^^^^^ +.. _project_include.cmake: -For components that have build requirements that must be evaluated in the top-level -project make pass, you can create a file called ``Makefile.projbuild`` in the -component directory. This makefile is included when ``project.mk`` is evaluated. +project_include.cmake +^^^^^^^^^^^^^^^^^^^^^ -For example, if your component needs to add to CFLAGS for the entire -project (not just for its own source files) then you can set -``CFLAGS +=`` in Makefile.projbuild. +For components that have build requirements which must be evaluated before any component CMakeLists +files are evaluated, you can create a file called ``project_include.cmake`` in the +component directory. This CMake file is included when ``project.cmake`` is evaluating the entire project. -``Makefile.projbuild`` files are used heavily inside esp-idf, for defining project-wide build features such as ``esptool.py`` command line arguments and the ``bootloader`` "special app". +``project_include.cmake`` files are used inside ESP-IDF, for defining project-wide build features such as ``esptool.py`` command line arguments and the ``bootloader`` "special app". -Note that ``Makefile.projbuild`` isn't necessary for the most common component uses - such as adding include directories to the project, or LDFLAGS to the final linking step. These values can be customised via the ``component.mk`` file itself. See `Optional Project-Wide Component Variables`_ for details. +Unlike component ``CMakeLists.txt`` files, when including a ``project_include.cmake`` file the current source directory (``CMAKE_CURRENT_SOURCE_DIR`` and working directory) is the project directory. Use the variable ``COMPONENT_DIR`` for the absolute directory of the component. -Take care when setting variables or targets in this file. As the values are included into the top-level project makefile pass, they can influence or break functionality across all components! +Note that ``project_include.cmake`` isn't necessary for the most common component uses - such as adding include directories to the project, or ``LDFLAGS`` to the final linking step. These values can be customised via the ``CMakeLists.txt`` file itself. See `Optional Project Variables`_ for details. + +``project_include.cmake`` files are included in the order given in ``BUILD_COMPONENTS`` variable (as logged by CMake). This means that a component's ``project_include.cmake`` file will be included after it's all dependencies' ``project_include.cmake`` files, unless both components are part of a dependency cycle. This is important if a ``project_include.cmake`` file relies on variables set by another component. See also :ref:`above`. + +Take great care when setting variables or targets in a ``project_include.cmake`` file. As the values are included into the top-level project CMake pass, they can influence or break functionality across all components! KConfig.projbuild ^^^^^^^^^^^^^^^^^ -This is an equivalent to ``Makefile.projbuild`` for `component configuration` KConfig files. If you want to include -configuration options at the top-level of menuconfig, rather than inside the "Component Configuration" sub-menu, then these can be defined in the KConfig.projbuild file alongside the ``component.mk`` file. +This is an equivalent to ``project_include.cmake`` for :ref:`component-configuration-cmake` KConfig files. If you want to include +configuration options at the top-level of menuconfig, rather than inside the "Component Configuration" sub-menu, then these can be defined in the KConfig.projbuild file alongside the ``CMakeLists.txt`` file. -Take care when adding configuration values in this file, as they will be included across the entire project configuration. Where possible, it's generally better to create a KConfig file for `component configuration`. +Take care when adding configuration values in this file, as they will be included across the entire project configuration. Where possible, it's generally better to create a KConfig file for :ref:`component-configuration-cmake`. -Makefile.componentbuild -^^^^^^^^^^^^^^^^^^^^^^^ - -For components that e.g. include tools to generate source files from other files, it is necessary to be able to add recipes, macros or variable definitions -into the component build process of every components. This is done by having a ``Makefile.componentbuild`` in a component directory. This file gets included -in ``component_wrapper.mk``, before the ``component.mk`` of the component is included. As with the Makefile.projbuild, take care with these files: as they're -included in each component build, a ``Makefile.componentbuild`` error may only show up when compiling an entirely different component. - Configuration-Only Components ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Some special components which contain no source files, only ``Kconfig.projbuild`` and ``Makefile.projbuild``, may set the flag ``COMPONENT_CONFIG_ONLY`` in the component.mk file. If this flag is set, most other component variables are ignored and no build step is run for the component. +Special components which contain no source files, only ``Kconfig.projbuild`` and ``KConfig``, can have a one-line ``CMakeLists.txt`` file which calls the function ``idf_component_register()`` with no +arguments specified. This function will include the component in the project build, but no library will be built *and* no header files will be added to any include paths. -Example Component Makefiles ---------------------------- +Example Component CMakeLists +============================ Because the build environment tries to set reasonable defaults that will work most -of the time, component.mk can be very small or even empty (see `Minimal Component Makefile`_). However, overriding `component variables` is usually required for some functionality. +of the time, component ``CMakeLists.txt`` can be very small or even empty (see `Minimal Component CMakeLists`_). However, overriding `component variables`_ is usually required for some functionality. -Here are some more advanced examples of ``component.mk`` makefiles: - - -Adding source directories -^^^^^^^^^^^^^^^^^^^^^^^^^ - -By default, sub-directories are ignored. If your project has sources in sub-directories -instead of in the root of the component then you can tell that to the build -system by setting ``COMPONENT_SRCDIRS``:: - - COMPONENT_SRCDIRS := src1 src2 - -This will compile all source files in the src1/ and src2/ sub-directories -instead. - -Specifying source files -^^^^^^^^^^^^^^^^^^^^^^^ - -The standard component.mk logic adds all .S and .c files in the source -directories as sources to be compiled unconditionally. It is possible -to circumvent that logic and hard-code the objects to be compiled by -manually setting the ``COMPONENT_OBJS`` variable to the name of the -objects that need to be generated:: - - COMPONENT_OBJS := file1.o file2.o thing/filea.o thing/fileb.o anotherthing/main.o - COMPONENT_SRCDIRS := . thing anotherthing - -Note that ``COMPONENT_SRCDIRS`` must be set as well. +Here are some more advanced examples of component CMakeLists files. Adding conditional configuration -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-------------------------------- The configuration system can be used to conditionally compile some files -depending on the options selected in ``make menuconfig``. For this, ESP-IDF -has the compile_only_if and compile_only_if_not macros: +depending on the options selected in the project configuration. + +.. highlight:: none ``Kconfig``:: @@ -476,17 +566,15 @@ has the compile_only_if and compile_only_if_not macros: help This enables the BAR feature of the FOO component. -``component.mk``:: +``CMakeLists.txt``:: - $(call compile_only_if,$(CONFIG_FOO_ENABLE_BAR),bar.o) + set(COMPONENT_SRCS "foo.c" "more_foo.c") + if(CONFIG_FOO_ENABLE_BAR) + list(APPEND COMPONENT_SRCS "bar.c") + endif() -As can be seen in the example, the ``compile_only_if`` macro takes a condition and a -list of object files as parameters. If the condition is true (in this case: if the -BAR feature is enabled in menuconfig) the object files (in this case: bar.o) will -always be compiled. The opposite goes as well: if the condition is not true, bar.o -will never be compiled. ``compile_only_if_not`` does the opposite: compile if the -condition is false, not compile if the condition is true. +This example makes use of the CMake `if `_ function and `list APPEND `_ function. This can also be used to select or stub out an implementation, as such: @@ -509,28 +597,34 @@ This can also be used to select or stub out an implementation, as such: help Select this to output temperature plots +.. highlight:: cmake -``component.mk``:: +``CMakeLists.txt``:: - # If LCD is enabled, compile interface to it, otherwise compile dummy interface - $(call compile_only_if,$(CONFIG_ENABLE_LCD_OUTPUT),lcd-real.o lcd-spi.o) - $(call compile_only_if_not,$(CONFIG_ENABLE_LCD_OUTPUT),lcd-dummy.o) + if(CONFIG_ENABLE_LCD_OUTPUT) + set(COMPONENT_SRCS lcd-real.c lcd-spi.c) + else() + set(COMPONENT_SRCS lcd-dummy.c) + endif() - #We need font if either console or plot is enabled - $(call compile_only_if,$(or $(CONFIG_ENABLE_LCD_CONSOLE),$(CONFIG_ENABLE_LCD_PLOT)), font.o) + # We need font if either console or plot is enabled + if(CONFIG_ENABLE_LCD_CONSOLE OR CONFIG_ENABLE_LCD_PLOT) + list(APPEND COMPONENT_SRCS "font.c") + endif() -Note the use of the Make 'or' function to include the font file. Other substitution functions, -like 'and' and 'if' will also work here. Variables that do not come from menuconfig can also -be used: ESP-IDF uses the default Make policy of judging a variable which is empty or contains -only whitespace to be false while a variable with any non-whitespace in it is true. -(Note: Older versions of this document advised conditionally adding object file names to -``COMPONENT_OBJS``. While this still is possible, this will only work when all object -files for a component are named explicitely, and will not clean up deselected object files -in a ``make clean`` pass.) +Conditions which depend on the target +------------------------------------- + +The current target is available to CMake files via ``IDF_TARGET`` variable. + +In addition to that, if target ``xyz`` is used (``IDF_TARGET=xyz``), then Kconfig variable ``CONFIG_IDF_TARGET_XYZ`` will be set. + +Note that component dependencies may depend on ``IDF_TARGET`` variable, but not on Kconfig variables. Also one can not use Kconfig variables in ``include`` statements in CMake files, but ``IDF_TARGET`` can be used in such context. + Source Code Generation -^^^^^^^^^^^^^^^^^^^^^^ +---------------------- Some components will have a situation where a source file isn't supplied with the component itself but has to be generated from @@ -539,112 +633,679 @@ converted binary data of a BMP file, converted using a hypothetical tool called bmp2h. The header file is then included in as C source file called graphics_lib.c:: - COMPONENT_EXTRA_CLEAN := logo.h + add_custom_command(OUTPUT logo.h + COMMAND bmp2h -i ${COMPONENT_DIR}/logo.bmp -o log.h + DEPENDS ${COMPONENT_DIR}/logo.bmp + VERBATIM) - graphics_lib.o: logo.h + add_custom_target(logo DEPENDS logo.h) + add_dependencies(${COMPONENT_LIB} logo) - logo.h: $(COMPONENT_PATH)/logo.bmp - bmp2h -i $^ -o $@ + set_property(DIRECTORY "${COMPONENT_DIR}" APPEND PROPERTY + ADDITIONAL_MAKE_CLEAN_FILES logo.h) +This answer is adapted from the `CMake FAQ entry `_, which contains some other examples that will also work with ESP-IDF builds. -In this example, graphics_lib.o and logo.h will be generated in the +In this example, logo.h will be generated in the current directory (the build directory) while logo.bmp comes with the component and resides under the component path. Because logo.h is a -generated file, it needs to be cleaned when make clean is called which -why it is added to the COMPONENT_EXTRA_CLEAN variable. +generated file, it should be cleaned when the project is cleaned. For this reason +it is added to the `ADDITIONAL_MAKE_CLEAN_FILES`_ property. -Cosmetic Improvements -^^^^^^^^^^^^^^^^^^^^^ +.. note:: -Because logo.h is a generated file, it needs to be cleaned when make -clean is called which why it is added to the COMPONENT_EXTRA_CLEAN -variable. + If generating files as part of the project CMakeLists.txt file, not a component CMakeLists.txt, then use build property ``PROJECT_DIR`` instead of ``${COMPONENT_DIR}`` and ``${PROJECT_NAME}.elf`` instead of ``${COMPONENT_LIB}``.) -Adding logo.h to the ``graphics_lib.o`` dependencies causes it to be -generated before ``graphics_lib.c`` is compiled. +If a a source file from another component included ``logo.h``, then ``add_dependencies`` would need to be called to add a dependency between +the two components, to ensure that the component source files were always compiled in the correct order. -If a a source file in another component included ``logo.h``, then this -component's name would have to be added to the other component's -``COMPONENT_DEPENDS`` list to ensure that the components were built -in-order. +.. _cmake_embed_data: Embedding Binary Data -^^^^^^^^^^^^^^^^^^^^^ +--------------------- Sometimes you have a file with some binary or text data that you'd like to make available to your component - but you don't want to reformat the file as C source. -You can set a variable COMPONENT_EMBED_FILES in component.mk, giving the names of the files to embed in this way:: +You can specify argument ``COMPONENT_EMBED_FILES`` in the component registration, giving space-delimited names of the files to embed:: - COMPONENT_EMBED_FILES := server_root_cert.der + idf_component_register(... + EMBED_FILES server_root_cert.der) -Or if the file is a string, you can use the variable COMPONENT_EMBED_TXTFILES. This will embed the contents of the text file as a null-terminated string:: - COMPONENT_EMBED_TXTFILES := server_root_cert.pem +Or if the file is a string, you can use the variable ``COMPONENT_EMBED_TXTFILES``. This will embed the contents of the text file as a null-terminated string:: + + idf_component_register(... + EMBED_TXTFILES server_root_cert.pem) + +.. highlight:: c The file's contents will be added to the .rodata section in flash, and are available via symbol names as follows:: 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"); -The names are generated from the full name of the file, as given in COMPONENT_EMBED_FILES. Characters /, ., etc. are replaced with underscores. The _binary prefix in the symbol name is added by objcopy and is the same for both text and binary files. +The names are generated from the full name of the file, as given in ``COMPONENT_EMBED_FILES``. Characters /, ., etc. are replaced with underscores. The _binary prefix in the symbol name is added by objcopy and is the same for both text and binary files. + +.. highlight:: cmake + +To embed a file into a project, rather than a component, you can call the function ``target_add_binary_data`` like this:: + + target_add_binary_data(myproject.elf "main/data.bin" TEXT) + +Place this line after the ``project()`` line in your project CMakeLists.txt file. Replace ``myproject.elf`` with your project name. The final argument can be ``TEXT`` to embed a null-terminated string, or ``BINARY`` to embed the content as-is. For an example of using this technique, see :example:`protocols/https_request` - the certificate file contents are loaded from the text .pem file at compile time. Code and Data Placements ------------------------ -ESP-IDF has a feature called linker script generation that enables components to define where its code and data will be placed in memory through -linker fragment files. These files are processed by the build system, and is used to augment the linker script used for linking +ESP-IDF has a feature called linker script generation that enables components to define where its code and data will be placed in memory through +linker fragment files. These files are processed by the build system, and is used to augment the linker script used for linking app binary. See :doc:`Linker Script Generation ` for a quick start guide as well as a detailed discussion of the mechanism. -Fully Overriding The Component Makefile ---------------------------------------- +.. _component-build-full-override: + +Fully Overriding The Component Build Process +-------------------------------------------- + +.. highlight:: cmake Obviously, there are cases where all these recipes are insufficient for a certain component, for example when the component is basically a wrapper around another third-party component not originally intended to be compiled under this build system. In that case, it's possible to forego -the esp-idf build system entirely by setting COMPONENT_OWNBUILDTARGET and -possibly COMPONENT_OWNCLEANTARGET and defining your own targets named ``build`` and ``clean`` in ``component.mk`` -target. The build target can do anything as long as it creates -$(COMPONENT_LIBRARY) for the project make process to link into the app binary. +the ESP-IDF build system entirely by using a CMake feature called ExternalProject_. Example component CMakeLists:: -(Actually, even this is not strictly necessary - if the COMPONENT_ADD_LDFLAGS variable -is overridden then the component can instruct the linker to link other binaries instead.) + # External build process for quirc, runs in source dir and + # produces libquirc.a + externalproject_add(quirc_build + PREFIX ${COMPONENT_DIR} + SOURCE_DIR ${COMPONENT_DIR}/quirc + CONFIGURE_COMMAND "" + BUILD_IN_SOURCE 1 + BUILD_COMMAND make CC=${CMAKE_C_COMPILER} libquirc.a + INSTALL_COMMAND "" + ) + + # Add libquirc.a to the build process + # + add_library(quirc STATIC IMPORTED GLOBAL) + add_dependencies(quirc quirc_build) + + set_target_properties(quirc PROPERTIES IMPORTED_LOCATION + ${COMPONENT_DIR}/quirc/libquirc.a) + set_target_properties(quirc PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + ${COMPONENT_DIR}/quirc/lib) + + set_directory_properties( PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES + "${COMPONENT_DIR}/quirc/libquirc.a") + +(The above CMakeLists.txt can be used to create a component named ``quirc`` that builds the quirc_ project using its own Makefile.) + +- ``externalproject_add`` defines an external build system. + + - ``SOURCE_DIR``, ``CONFIGURE_COMMAND``, ``BUILD_COMMAND`` and ``INSTALL_COMMAND`` should always be set. ``CONFIGURE_COMMAND`` can be set to an empty string if the build system has no "configure" step. ``INSTALL_COMMAND`` will generally be empty for ESP-IDF builds. + - Setting ``BUILD_IN_SOURCE`` means the build directory is the same as the source directory. Otherwise you can set ``BUILD_DIR``. + - Consult the ExternalProject_ documentation for more details about ``externalproject_add()`` + +- The second set of commands adds a library target, which points to the "imported" library file built by the external system. Some properties need to be set in order to add include directories and tell CMake where this file is. +- Finally, the generated library is added to `ADDITIONAL_MAKE_CLEAN_FILES`_. This means ``make clean`` will delete this library. (Note that the other object files from the build won't be deleted.) .. note:: When using an external build process with PSRAM, remember to add ``-mfix-esp32-psram-cache-issue`` to the C compiler arguments. See :ref:`CONFIG_SPIRAM_CACHE_WORKAROUND` for details of this flag. -.. _esp-idf-template: https://github.com/espressif/esp-idf-template -.. _GNU Make Manual: https://www.gnu.org/software/make/manual/make.html +.. _ADDITIONAL_MAKE_CLEAN_FILES_note: +ExternalProject dependencies, clean builds +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. _custom-sdkconfig-defaults: +CMake has some unusual behaviour around external project builds: + +- `ADDITIONAL_MAKE_CLEAN_FILES`_ only works when "make" is used as the build system. If Ninja_ or an IDE build system is used, it won't delete these files when cleaning. +- However, the ExternalProject_ configure & build commands will *always* be re-run after a clean is run. +- Therefore, there are two alternative recommended ways to configure the external build command: + + 1. Have the external ``BUILD_COMMAND`` run a full clean compile of all sources. The build command will be run if any of the dependencies passed to ``externalproject_add`` with ``DEPENDS`` have changed, or if this is a clean build (ie any of ``idf.py clean``, ``ninja clean``, or ``make clean`` was run.) + 2. Have the external ``BUILD_COMMAND`` be an incremental build command. Pass the parameter ``BUILD_ALWAYS 1`` to ``externalproject_add``. This means the external project will be built each time a build is run, regardless of dependencies. This is only recommended if the external project has correct incremental build behaviour, and doesn't take too long to run. + +The best of these approaches for building an external project will depend on the project itself, its build system, and whether you anticipate needing to frequently recompile the project. + +.. _custom-sdkconfig-defaults-cmake: Custom sdkconfig defaults -------------------------- +========================= -For example projects or other projects where you don't want to specify a full sdkconfig configuration, but you do want to override some key values from the esp-idf defaults, it is possible to create a file ``sdkconfig.defaults`` in the project directory. This file will be used when running ``make defconfig``, or creating a new config from scratch. +For example projects or other projects where you don't want to specify a full sdkconfig configuration, but you do want to override some key values from the ESP-IDF defaults, it is possible to create a file ``sdkconfig.defaults`` in the project directory. This file will be used when creating a new config from scratch, or when any new config value hasn't yet been set in the ``sdkconfig`` file. To override the name of this file, set the ``SDKCONFIG_DEFAULTS`` environment variable. +Target-dependent sdkconfig defaults +----------------------------------- -Save flash arguments --------------------- +In addition to ``sdkconfig.defaults`` file, build system will also load defaults from ``sdkconfig.defaults.TARGET_NAME`` file, where ``TARGET_NAME`` is the value of ``IDF_TARGET``. For example, for ``esp32`` target, default settings will be taken from ``sdkconfig.defaults`` first, and then from ``sdkconfig.defaults.esp32``. -There're some scenarios that we want to flash the target board without IDF. For this case we want to save the built binaries, esptool.py and esptool write_flash arguments. It's simple to write a script to save binaries and esptool.py. We can use command ``make print_flash_cmd``, it will print the flash arguments:: +If ``SDKCONFIG_DEFAULTS`` is used to override the name of defaults file, the name of target-specific defaults file will be derived from ``SDKCONFIG_DEFAULTS`` value. - --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 bootloader/bootloader.bin 0x10000 example_app.bin 0x8000 partition_table_unit_test_app.bin -Then use flash arguments as the arguemnts for esptool write_flash arguments:: +Flash arguments +=============== - python esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 bootloader/bootloader.bin 0x10000 example_app.bin 0x8000 partition_table_unit_test_app.bin +There are some scenarios that we want to flash the target board without IDF. For this case we want to save the built binaries, esptool.py and esptool write_flash arguments. It's simple to write a script to save binaries and esptool.py. + +After running a project build, the build directory contains binary output files (``.bin`` files) for the project and also the following flashing data files: + +- ``flash_project_args`` contains arguments to flash the entire project (app, bootloader, partition table, PHY data if this is configured). +- ``flash_app_args`` contains arguments to flash only the app. +- ``flash_bootloader_args`` contains arguments to flash only the bootloader. + +.. highlight:: bash + +You can pass any of these flasher argument files to ``esptool.py`` as follows:: + + python esptool.py --chip esp32 write_flash @build/flash_project_args + +Alternatively, it is possible to manually copy the parameters from the argument file and pass them on the command line. + +The build directory also contains a generated file ``flasher_args.json`` which contains project flash information, in JSON format. This file is used by ``idf.py`` and can also be used by other tools which need information about the project build. Building the Bootloader ======================= -The bootloader is built by default as part of "make all", or can be built standalone via "make bootloader-clean". There is also "make bootloader-list-components" to see the components included in the bootloader build. +The bootloader is built by default as part of ``idf.py build``, or can be built standalone via ``idf.py bootloader``. -The component in IDF components/bootloader is special, as the second stage bootloader is a separate .ELF and .BIN file to the main project. However it shares its configuration and build directory with the main project. +The bootloader is a special "subproject" inside :idf:`/components/bootloader/subproject`. It has its own project CMakeLists.txt file and builds separate .ELF and .BIN files to the main project. However it shares its configuration and build directory with the main project. -This is accomplished by adding a subproject under components/bootloader/subproject. This subproject has its own Makefile, but it expects to be called from the project's own Makefile via some glue in the components/bootloader/Makefile.projectbuild file. See these files for more details. +The subproject is inserted as an external project from the top-level project, by the file :idf_file:`/components/bootloader/project_include.cmake`. The main build process runs CMake for the subproject, which includes discovering components (a subset of the main components) and generating a bootloader-specific config (derived from the main ``sdkconfig``). + +Selecting the Target +==================== + +Currently ESP-IDF supports one target, ``esp32``. It is used by default by the build system. Developers working on adding multiple target support can change the target as follows:: + + rm sdkconfig + idf.py -DIDF_TARGET=new_target reconfigure + + +Writing Pure CMake Components +============================= + +The ESP-IDF build system "wraps" CMake with the concept of "components", and helper functions to automatically integrate these components into a project build. + +However, underneath the concept of "components" is a full CMake build system. It is also possible to make a component which is pure CMake. + +.. highlight:: cmake + +Here is an example minimal "pure CMake" component CMakeLists file for a component named ``json``:: + + add_library(json STATIC + cJSON/cJSON.c + cJSON/cJSON_Utils.c) + + target_include_directories(json PUBLIC cJSON) + +- This is actually an equivalent declaration to the IDF ``json`` component :idf_file:`/components/json/CMakeLists.txt`. +- This file is quite simple as there are not a lot of source files. For components with a large number of files, the globbing behaviour of ESP-IDF's component logic can make the component CMakeLists style simpler.) +- Any time a component adds a library target with the component name, the ESP-IDF build system will automatically add this to the build, expose public include directories, etc. If a component wants to add a library target with a different name, dependencies will need to be added manually via CMake commands. + + +Using Third-Party CMake Projects with Components +================================================ + +CMake is used for a lot of open-source C and C++ projects — code that users can tap into for their applications. One of the benefits of having a CMake build system +is the ability to import these third-party projects, sometimes even without modification! This allows for users to be able to get functionality that may +not yet be provided by a component, or use another library for the same functionality. + +.. highlight:: cmake + +Importing a library might look like this for a hypothetical library ``foo`` to be used in the ``main`` component:: + + # Register the component + idf_component_register() + + # Set values of hypothetical variables that control the build of `foo` + set(FOO_BUILD_STATIC OFF) + set(FOO_BUILD_TESTS OFF) + + # Create and import the library targets + add_subdirectory(foo) + + # Link `foo` to `main` component + target_link_libraries(main foo) + +For an actual example, take a look at :example:`build_system/cmake/import_lib`. Take note that what needs to be done in order to import +the library may vary. It is recommended to read up on the library's documentation for instructions on how to +import it from other projects. Studying the library's CMakeLists.txt and build structure can also be helpful. + +It is also possible to wrap a third-party library to be used as a component in this manner. For example, the :component:`mbedtls` component is a wrapper for +Espressif's fork of `mbedtls `_. See its :component_file:`component CMakeLists.txt `. + +The CMake variable ``ESP_PLATFORM`` is set to 1 whenever the ESP-IDF build system is being used. Tests such as ``if (ESP_PLATFORM)`` can be used in generic CMake code if special IDF-specific logic is required. + + +Using ESP-IDF in Custom CMake Projects +====================================== + +ESP-IDF provides a template CMake project for easily creating an application. However, in some instances the user might already +have an existing CMake project or may want to create a custom one. In these cases it is desirable to be able to consume IDF components +as libraries to be linked to the user's targets (libraries/ executables). + +It is possible to do so by using the :ref:`build system APIs provided` by :idf_file:`tools/cmake/idf.cmake`. For example: + +.. code-block:: cmake + + cmake_minimum_required(VERSION 3.5) + project(my_custom_app C) + + # Include CMake file that provides ESP-IDF CMake build system APIs. + include($ENV{IDF_PATH}/tools/cmake/idf.cmake) + + # Include ESP-IDF components in the build, may be thought as an equivalent of + # add_subdirectory() but with some additional procesing and magic for ESP-IDF build + # specific build processes. + idf_build_process(esp32) + + # Create the project executable and plainly link the newlib component to it using + # its alias, idf::newlib. + add_executable(${CMAKE_PROJECT_NAME}.elf main.c) + target_link_libraries(${CMAKE_PROJECT_NAME}.elf idf::newlib) + + # Let the build system know what the project executable is to attach more targets, dependencies, etc. + idf_build_executable(${CMAKE_PROJECT_NAME}.elf) + +The example in :example:`build_system/cmake/idf_as_lib` demonstrates the creation of an application equivalent to :example:`hello world application ` +using a custom CMake project. + +.. note:: The IDF build system can only set compiler flags for source files that it builds. When an external CMakeLists.txt file is used and PSRAM is enabled, remember to add ``-mfix-esp32-psram-cache-issue`` to the C compiler arguments. See :ref:`CONFIG_SPIRAM_CACHE_WORKAROUND` for details of this flag. +.. _cmake_buildsystem_api: + +ESP-IDF CMake Build System API +============================== + +idf-build-commands +------------------ + +.. code-block:: none + + idf_build_get_property(var property [GENERATOR_EXPRESSION]) + +Retrieve a :ref:`build property` *property* and store it in *var* accessible from the current scope. Specifying +*GENERATOR_EXPRESSION* will retrieve the generator expression string for that property, instead of the actual value, which +can be used with CMake commands that support generator expressions. + +.. code-block:: none + + idf_build_set_property(property val [APPEND]) + +Set a :ref:`build property` *property* with value *val*. Specifying *APPEND* will append the specified value to the current +value of the property. If the property does not previously exist or it is currently empty, the specified value becomes +the first element/member instead. + +.. code-block:: none + + idf_build_component(component_dir) + +Present a directory *component_dir* that contains a component to the build system. Relative paths are converted to absolute paths with respect to current directory. +All calls to this command must be performed before `idf_build_process`. + +This command does not guarantee that the component will be processed during build (see the `COMPONENTS` argument description for `idf_build_process`) + +.. code-block:: none + + idf_build_process(target + [PROJECT_DIR project_dir] + [PROJECT_VER project_ver] + [PROJECT_NAME project_name] + [SDKCONFIG sdkconfig] + [SDKCONFIG_DEFAULTS sdkconfig_defaults] + [BUILD_DIR build_dir] + [COMPONENTS component1 component2 ...]) + +Performs the bulk of the behind-the-scenes magic for including ESP-IDF components such as component configuration, libraries creation, +dependency expansion and resolution. Among these functions, perhaps the most important +from a user's perspective is the libraries creation by calling each component's ``idf_component_register``. This command creates the libraries for each component, which are accessible using aliases in the form +idf::*component_name*. These aliases can be used to link the components to the user's own targets, either libraries +or executables. + +The call requires the target chip to be specified with *target* argument. Optional arguments for the call include: + +- PROJECT_DIR - directory of the project; defaults to CMAKE_SOURCE_DIR +- PROJECT_NAME - name of the project; defaults to CMAKE_PROJECT_NAME +- PROJECT_VER - version/revision of the project; defaults to "0.0.0" +- SDKCONFIG - output path of generated sdkconfig file; defaults to PROJECT_DIR/sdkconfig or CMAKE_SOURCE_DIR/sdkconfig depending if PROJECT_DIR is set +- SDKCONFIG_DEFAULTS - defaults file to use for the build; defaults to empty +- BUILD_DIR - directory to place ESP-IDF build-related artifacts, such as generated binaries, text files, components; defaults to CMAKE_BINARY_DIR +- COMPONENTS - select components to process among the components known by the build system (added via `idf_build_component`). This argument is used to trim the build. + Other components are automatically added if they are required in the dependency chain, i.e. + the public and private requirements of the components in this list are automatically added, and in turn the public and private requirements of those requirements, + so on and so forth. If not specified, all components known to the build system are processed. + +.. code-block:: none + + idf_build_executable(executable) + +Specify the executable *executable* for ESP-IDF build. This attaches additional targets such as dependencies related to +flashing, generating additional binary files, etc. Should be called after ``idf_build_process``. + +.. code-block:: none + + idf_build_get_config(var config [GENERATOR_EXPRESSION]) + +Get the value of the specified config. Much like build properties, specifying +*GENERATOR_EXPRESSION* will retrieve the generator expression string for that config, instead of the actual value, which +can be used with CMake commands that support generator expressions. Actual config values are only known after call to `idf_build_process`, however. + +.. _cmake-build-properties: + +idf-build-properties +-------------------- + +These are properties that describe the build. Values of build properties can be retrieved by using the build command ``idf_build_get_property``. +For example, to get the Python interpreter used for the build: + +.. code-block: cmake + + idf_build_get_property(python PYTHON) + message(STATUS "The Python intepreter is: ${python}") + + - BUILD_DIR - build directory; set from ``idf_build_process`` BUILD_DIR argument + - BUILD_COMPONENTS - list of components (more specifically, component aliases) included in the build; set by ``idf_build_process`` + - C_COMPILE_OPTIONS - compile options applied to all components' C source files + - COMPILE_OPTIONS - compile options applied to all components' source files, regardless of it being C or C++ + - COMPILE_DEFINITIONS - compile definitions applied to all component source files + - CXX_COMPILE_OPTIONS - compile options applied to all components' C++ source files + - EXECUTABLE - project executable; set by call to ``idf_build_executable`` + - EXECUTABLE_NAME - name of project executable without extension; set by call to ``idf_build_executable`` + - IDF_PATH - ESP-IDF path; set from IDF_PATH environment variable, if not, inferred from the location of ``idf.cmake`` + - IDF_TARGET - target chip for the build; set from the required target argument for ``idf_build_process`` + - IDF_VER - ESP-IDF version; set from either a version file or the Git revision of the IDF_PATH repository + - INCLUDE_DIRECTORIES - include directories for all component source files + - KCONFIGS - list of Kconfig files found in components in build; set by ``idf_build_process`` + - KCONFIG_PROJBUILDS - list of Kconfig.projbuild diles found in components in build; set by ``idf_build_process`` + - PROJECT_NAME - name of the project; set from ``idf_build_process`` PROJECT_NAME argument + - PROJECT_DIR - directory of the project; set from ``idf_build_process`` PROJECT_DIR argument + - PROJECT_VER - version of the project; set from ``idf_build_process`` PROJECT_VER argument + - PYTHON - Python interpreter used for the build; set from PYTHON environment variable if available, if not "python" is used + - SDKCONFIG - full path to output config file; set from ``idf_build_process`` SDKCONFIG argument + - SDKCONFIG_DEFAULTS - full path to config defaults file; set from ``idf_build_process`` SDKCONFIG_DEFAULTS argument + - SDKCONFIG_HEADER - full path to C/C++ header file containing component configuration; set by ``idf_build_process`` + - SDKCONFIG_CMAKE - full path to CMake file containing component configuration; set by ``idf_build_process`` + - SDKCONFIG_JSON - full path to JSON file containing component configuration; set by ``idf_build_process`` + - SDKCONFIG_JSON_MENUS - full path to JSON file containing config menus; set by ``idf_build_process`` + +idf-component-commands +---------------------- + +.. code-block:: none + + idf_component_get_property(var component property [GENERATOR_EXPRESSION]) + +Retrieve a specified *component*'s :ref:`component property`, *property* and store it in *var* accessible from the current scope. Specifying +*GENERATOR_EXPRESSION* will retrieve the generator expression string for that property, instead of the actual value, which +can be used with CMake commands that support generator expressions. + +.. code-block:: none + + idf_component_set_property(property val [APPEND]) + +Set a specified *component*'s :ref:`component property`, *property* with value *val*. Specifying *APPEND* will append the specified value to the current +value of the property. If the property does not previously exist or it is currently empty, the specified value becomes +the first element/member instead. + +.. _cmake-component-register: + +.. code-block:: none + + idf_component_register([[SRCS src1 src2 ...] | [[SRC_DIRS dir1 dir2 ...] [EXCLUDE_SRCS src1 src2 ...]] + [INCLUDE_DIRS dir1 dir2 ...] + [PRIV_INCLUDE_DIRS dir1 dir2 ...] + [REQUIRES component1 component2 ...] + [PRIV_REQUIRES component1 component2 ...] + [LDFRAGMENTS ldfragment1 ldfragment2 ...] + [REQUIRED_IDF_TARGETS target1 target2 ...] + [EMBED_FILES file1 file2 ...] + [EMBED_TXTFILES file1 file2 ...]) + +Register a component to the build system. Much like the ``project()`` CMake command, this should be called from the component's +CMakeLists.txt directly (not through a function or macro) and is recommended to be called before any other command. Here are some +guidelines on what commands can **not** be called before ``idf_component_register``: + + - commands that are not valid in CMake script mode + - custom commands defined in project_include.cmake + - build system API commands except ``idf_build_get_property``; although consider whether the property may not have been set yet + +Commands that set and operate on variables are generally okay to call before ``idf_component_register``. + +The arguments for ``idf_component_register`` include: + + - SRCS - component source files used for creating a static library for the component; if not specified, component is a treated as a + config-only component and an interface library is created instead. + - SRC_DIRS, EXCLUDE_SRCS - used to glob source files (.c, .cpp, .S) by specifying directories, instead of specifying source files manually via SRCS. + Note that this is subject to the :ref:`limitations of globbing in CMake`. Source files specified in EXCLUDE_SRCS are removed from the globbed files. + - INCLUDE_DIRS - paths, relative to the component directory, which will be added to the include search path for all other components which require the current component + - PRIV_INCLUDE_DIRS - directory paths, must be relative to the component directory, which will be added to the include search path for this component's source files only + - REQUIRES - public component requirements for the component + - PRIV_REQUIRES - private component requirements for the component; ignored on config-only components + - LDFRAGMENTS - component linker fragment files + - REQUIRED_IDF_TARGETS - specify the only target the component supports + +The following are used for :ref:`embedding data into the component`, and is considered as source files +when determining if a component is config-only. This means that even if the component does not specify source files, a static library is still +created internally for the component if it specifies either: + + - EMBED_FILES - binary files to be embedded in the component + - EMBED_TXTFILES - text files to be embedded in the component + +.. _cmake-component-properties: + +idf-component-properties +------------------------ + +These are properties that describe a component. Values of component properties can be retrieved by using the build command ``idf_component_get_property``. +For example, to get the directory of the ``freertos`` component: + +.. code-block: cmake + + idf_component_get_property(dir freertos COMPONENT_DIR) + message(STATUS "The 'freertos' component directory is: ${dir}") + +- COMPONENT_ALIAS - alias for COMPONENT_LIB used for linking the component to external targets; set by ``idf_build_component`` and alias library itself + is created by ``idf_component_register`` +- COMPONENT_DIR - component directory; set by ``idf_build_component`` +- COMPONENT_LIB - name for created component static/interface library; set by ``idf_build_component`` and library itself + is created by ``idf_component_register`` +- COMPONENT_NAME - name of the component; set by ``idf_build_component`` based on the component directory name +- COMPONENT_TYPE - type of the component, whether LIBRARY or CONFIG_ONLY. A component is of type LIBRARY if it specifies + source files or embeds a file +- EMBED_FILES - list of files to embed in component; set from ``idf_component_register`` EMBED_FILES argument +- EMBED_TXTFILES - list of text files to embed in component; set from ``idf_component_register`` EMBED_TXTFILES argument +- INCLUDE_DIRS - list of component include directories; set from ``idf_component_register`` INCLUDE_DIRS argument +- KCONFIG - component Kconfig file; set by ``idf_build_component`` +- KCONFIG_PROJBUILD - component Kconfig.projbuild; set by ``idf_build_component`` +- LDFRAGMENTS - list of component linker fragment files; set from ``idf_component_register`` LDFRAGMENTS argument +- PRIV_INCLUDE_DIRS - list of component private include directories; set from ``idf_component_register`` PRIV_INCLUDE_DIRS on components of type LIBRARY +- PRIV_REQUIRES - list of private component dependentices; set from ``idf_component_register`` PRIV_REQUIRES argument +- REQUIRED_IDF_TARGETS - list of targets the component supports; set from ``idf_component_register`` EMBED_TXTFILES argument +- REQUIRES - list of public component dependencies; set from ``idf_component_register`` REQUIRES argument +- SRCS - list of component source files; set from SRCS or SRC_DIRS/EXCLUDE_SRCS argument of ``idf_component_register`` + +.. _cmake-file-globbing: + +File Globbing & Incremental Builds +================================== + +.. highlight:: cmake + +The preferred way to include source files in an ESP-IDF component is to list them manually via SRCS argument to ``idf_component_register``:: + + idf_component_register(SRCS library/a.c library/b.c platform/platform.c + ...) + +This preference reflects the `CMake best practice `_ of manually listing source files. This could, however, be inconvenient when there are lots of source files to add to the build. The ESP-IDF build system provides an alternative way for specifying source files using ``SRC_DIRS``:: + + idf_component_register(SRC_DIRS library platform + ...) + +This uses globbing behind the scenes to find source files in the specified directories. Be aware, however, that if a new source file is added and this method is used, then CMake won't know to automatically re-run and this file won't be added to the build. + +The trade-off is acceptable when you're adding the file yourself, because you can trigger a clean build or run ``idf.py reconfigure`` to manually re-run CMake_. However, the problem gets harder when you share your project with others who may check out a new version using a source control tool like Git... + +For components which are part of ESP-IDF, we use a third party Git CMake integration module (:idf_file:`/tools/cmake/third_party/GetGitRevisionDescription.cmake`) which automatically re-runs CMake any time the repository commit changes. This means if you check out a new ESP-IDF version, CMake will automatically rerun. + +For project components (not part of ESP-IDF), there are a few different options: + +- If keeping your project file in Git, ESP-IDF will automatically track the Git revision and re-run CMake if the revision changes. +- If some components are kept in a third git repository (not the project repository or ESP-IDF repository), you can add a call to the ``git_describe`` function in a component CMakeLists file in order to automatically trigger re-runs of CMake when the Git revision changes. +- If not using Git, remember to manually run ``idf.py reconfigure`` whenever a source file may change. +- To avoid this problem entirely, use ``COMPONENT_SRCS`` to list all source files in project components. + +The best option will depend on your particular project and its users. + +Build System Metadata +===================== + +For integration into IDEs and other build systems, when CMake runs the build process generates a number of metadata files in the ``build/`` directory. To regenerate these files, run ``cmake`` or ``idf.py reconfigure`` (or any other ``idf.py`` build command). + +- ``compile_commands.json`` is a standard format JSON file which describes every source file which is compiled in the project. A CMake feature generates this file, and many IDEs know how to parse it. +- ``project_description.json`` contains some general information about the ESP-IDF project, configured paths, etc. +- ``flasher_args.json`` contains esptool.py arguments to flash the project's binary files. There are also ``flash_*_args`` files which can be used directly with esptool.py. See `Flash arguments`_. +- ``CMakeCache.txt`` is the CMake cache file which contains other information about the CMake process, toolchain, etc. +- ``config/sdkconfig.json`` is a JSON-formatted version of the project configuration values. +- ``config/kconfig_menus.json`` is a JSON-formatted version of the menus shown in menuconfig, for use in external IDE UIs. + +JSON Configuration Server +------------------------- + +.. highlight :: json + +A tool called ``confserver.py`` is provided to allow IDEs to easily integrate with the configuration system logic. ``confserver.py`` is designed to run in the background and interact with a calling process by reading and writing JSON over process stdin & stdout. + +You can run ``confserver.py`` from a project via ``idf.py confserver`` or ``ninja confserver``, or a similar target triggered from a different build generator. + +The config server outputs human-readable errors and warnings on stderr and JSON on stdout. On startup, it will output the full values of each configuration item in the system as a JSON dictionary, and the available ranges for values which are range constrained. The same information is contained in ``sdkconfig.json``:: + + {"version": 1, "values": { "ITEM": "value", "ITEM_2": 1024, "ITEM_3": false }, "ranges" : { "ITEM_2" : [ 0, 32768 ] } } + +Only visible configuration items are sent. Invisible/disabled items can be parsed from the static ``kconfig_menus.json`` file which also contains the menu structure and other metadata (descriptions, types, ranges, etc.) + +The Configuration Server will then wait for input from the client. The client passes a request to change one or more values, as a JSON object followed by a newline:: + + {"version": "1", "set": {"SOME_NAME": false, "OTHER_NAME": true } } + +The Configuration Server will parse this request, update the project ``sdkconfig`` file, and return a full list of changes:: + + {"version": 1, "values": {"SOME_NAME": false, "OTHER_NAME": true , "DEPENDS_ON_SOME_NAME": null}} + +Items which are now invisible/disabled will return value ``null``. Any item which is newly visible will return its newly visible current value. + +If the range of a config item changes, due to conditional range depending on another value, then this is also sent:: + + {"version": 1, "values": {"OTHER_NAME": true }, "ranges" : { "HAS_RANGE" : [ 3, 4 ] } } + +If invalid data is passed, an "error" field is present on the object:: + + {"version": 1, "values": {}, "error": ["The following config symbol(s) were not visible so were not updated: NOT_VISIBLE_ITEM"]} + +By default, no config changes are written to the sdkconfig file. Changes are held in memory until a "save" command is sent:: + + {"version": 1, "save": null } + +To reload the config values from a saved file, discarding any changes in memory, a "load" command can be sent:: + + {"version": 1, "load": null } + +The value for both "load" and "save" can be a new pathname, or "null" to load/save the previous pathname. + +The response to a "load" command is always the full set of config values and ranges, the same as when the server is initially started. + +Any combination of "load", "set", and "save" can be sent in a single command and commands are executed in that order. Therefore it's possible to load config from a file, set some config item values and then save to a file in a single command. + +.. note:: The configuration server does not automatically load any changes which are applied externally to the ``sdkconfig`` file. Send a "load" command or restart the server if the file is externally edited. + +.. note:: The configuration server does not re-run CMake to regenerate other build files or metadata files after ``sdkconfig`` is updated. This will happen automatically the next time ``CMake`` or ``idf.py`` is run. + +.. _gnu-make-to-cmake: + +Migrating from ESP-IDF GNU Make System +====================================== + +Some aspects of the CMake-based ESP-IDF build system are very similar to the older GNU Make-based system. For example, to adapt a ``component.mk`` file to ``CMakeLists.txt`` variables like ``COMPONENT_ADD_INCLUDEDIRS`` and ``COMPONENT_SRCDIRS`` can stay the same and the syntax only needs changing to CMake syntax. + +Automatic Conversion Tool +------------------------- + +.. highlight:: bash + +An automatic project conversion tool is available in :idf_file:`/tools/cmake/convert_to_cmake.py`. Run this command line tool with the path to a project like this:: + + $IDF_PATH/tools/cmake/convert_to_cmake.py /path/to/project_dir + +The project directory must contain a Makefile, and GNU Make (``make``) must be installed and available on the PATH. + +The tool will convert the project Makefile and any component ``component.mk`` files to their equivalent ``CMakeLists.txt`` files. + +It does so by running ``make`` to expand the ESP-IDF build system variables which are set by the build, and then producing equivalent CMakelists files to set the same variables. + +The conversion tool is not capable of dealing with complex Makefile logic or unusual targets. These will need to be converted by hand. + +No Longer Available in CMake +---------------------------- + +Some features are significantly different or removed in the CMake-based system. The following variables no longer exist in the CMake-based build system: + +- ``COMPONENT_BUILD_DIR``: Use ``CMAKE_CURRENT_BINARY_DIR`` instead. +- ``COMPONENT_LIBRARY``: Defaulted to ``$(COMPONENT_NAME).a``, but the library name could be overriden by the component. The name of the component library can no longer be overriden by the component. +- ``CC``, ``LD``, ``AR``, ``OBJCOPY``: Full paths to each tool from the gcc xtensa cross-toolchain. Use ``CMAKE_C_COMPILER``, ``CMAKE_C_LINK_EXECUTABLE``, ``CMAKE_OBJCOPY``, etc instead. `Full list here `_. +- ``HOSTCC``, ``HOSTLD``, ``HOSTAR``: Full names of each tool from the host native toolchain. These are no longer provided, external projects should detect any required host toolchain manually. +- ``COMPONENT_ADD_LDFLAGS``: Used to override linker flags. Use the CMake `target_link_libraries`_ command instead. +- ``COMPONENT_ADD_LINKER_DEPS``: List of files that linking should depend on. `target_link_libraries`_ will usually infer these dependencies automatically. For linker scripts, use the provided custom CMake function ``target_linker_scripts``. +- ``COMPONENT_SUBMODULES``: No longer used, the build system will automatically enumerate all submodules in the ESP-IDF repository. +- ``COMPONENT_EXTRA_INCLUDES``: Used to be an alternative to ``COMPONENT_PRIV_INCLUDEDIRS`` for absolute paths. Use ``COMPONENT_PRIV_INCLUDEDIRS`` for all cases now (can be relative or absolute). +- ``COMPONENT_OBJS``: Previously, component sources could be specified as a list of object files. Now they can be specified as an list of source files via ``COMPONENT_SRCS``. +- ``COMPONENT_OBJEXCLUDE``: Has been replaced with ``COMPONENT_SRCEXCLUDE``. Specify source files (as absolute paths or relative to component directory), instead. +- ``COMPONENT_EXTRA_CLEAN``: Set property ``ADDITIONAL_MAKE_CLEAN_FILES`` instead but note :ref:`CMake has some restrictions around this functionality `. +- ``COMPONENT_OWNBUILDTARGET`` & ``COMPONENT_OWNCLEANTARGET``: Use CMake `ExternalProject`_ instead. See :ref:`component-build-full-override` for full details. +- ``COMPONENT_CONFIG_ONLY``: Call ``register_config_only_component()`` instead. See `Configuration-Only Components`_. +- ``CFLAGS``, ``CPPFLAGS``, ``CXXFLAGS``: Use equivalent CMake commands instead. See `Controlling Component Compilation`_. + + +No Default Values +----------------- + +The following variables no longer have default values: + +- ``COMPONENT_SRCDIRS`` +- ``COMPONENT_ADD_INCLUDEDIRS`` + +No Longer Necessary +------------------- + +It is no longer necessary to set ``COMPONENT_SRCDIRS`` if setting ``COMPONENT_SRCS`` (in fact, in the CMake-based system ``COMPONENT_SRCS`` is ignored if ``COMPONENT_SRCDIRS`` is set). + +Flashing from make +------------------ + +``make flash`` and similar targets still work to build and flash. However, project ``sdkconfig`` no longer specifies serial port and baud rate. Environment variables can be used to override these. See :ref:`flash-with-ninja-or-make` for more details. + +.. _esp-idf-template: https://github.com/espressif/esp-idf-template +.. _cmake: https://cmake.org +.. _ninja: https://ninja-build.org +.. _esptool.py: https://github.com/espressif/esptool/#readme +.. _CMake v3.5 documentation: https://cmake.org/cmake/help/v3.5/index.html +.. _cmake command line documentation: https://cmake.org/cmake/help/v3.5/manual/cmake.1.html#options +.. _cmake add_library: https://cmake.org/cmake/help/v3.5/command/add_library.html +.. _cmake if: https://cmake.org/cmake/help/v3.5/command/if.html +.. _cmake list: https://cmake.org/cmake/help/v3.5/command/list.html +.. _cmake project: https://cmake.org/cmake/help/v3.5/command/project.html +.. _cmake set: https://cmake.org/cmake/help/v3.5/command/set.html +.. _cmake string: https://cmake.org/cmake/help/v3.5/command/string.html +.. _cmake faq generated files: https://cmake.org/Wiki/CMake_FAQ#How_can_I_generate_a_source_file_during_the_build.3F +.. _ADDITIONAL_MAKE_CLEAN_FILES: https://cmake.org/cmake/help/v3.5/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.html +.. _ExternalProject: https://cmake.org/cmake/help/v3.5/module/ExternalProject.html +.. _cmake language variables: https://cmake.org/cmake/help/v3.5/manual/cmake-variables.7.html#variables-for-languages +.. _set_source_files_properties: https://cmake.org/cmake/help/v3.5/command/set_source_files_properties.html +.. _target_compile_options: https://cmake.org/cmake/help/v3.5/command/target_compile_options.html +.. _target_link_libraries: https://cmake.org/cmake/help/v3.5/command/target_link_libraries.html#command:target_link_libraries +.. _cmake_toolchain_file: https://cmake.org/cmake/help/v3.5/variable/CMAKE_TOOLCHAIN_FILE.html +.. _quirc: https://github.com/dlbeer/quirc +.. _pyenv: https://github.com/pyenv/pyenv#README +.. _virtualenv: https://virtualenv.pypa.io/en/stable/ diff --git a/docs/en/api-guides/ulp-cmake.rst b/docs/en/api-guides/ulp-legacy.rst similarity index 80% rename from docs/en/api-guides/ulp-cmake.rst rename to docs/en/api-guides/ulp-legacy.rst index 0391ab73d1..8eee8cffd9 100644 --- a/docs/en/api-guides/ulp-cmake.rst +++ b/docs/en/api-guides/ulp-legacy.rst @@ -1,7 +1,5 @@ -ULP coprocessor programming (CMake) -=================================== - -:link_to_translation:`zh_CN:[中文]` +ULP coprocessor programming +=========================== .. toctree:: :maxdepth: 1 @@ -27,35 +25,39 @@ Compiling ULP code To compile ULP code as part of a component, the following steps must be taken: -1. ULP code, written in assembly, must be added to one or more files with `.S` extension. These files must be placed into a separate directory inside component directory, for instance `ulp/`. +1. ULP code, written in assembly, must be added to one or more files with `.S` extension. These files must be placed into a separate directory inside component directory, for instance `ulp/`. -.. note: This directory should not be added to the ``COMPONENT_SRCDIRS`` environment variable. The logic behind this is that the ESP-IDF build system will compile files found in ``COMPONENT_SRCDIRS`` based on their extensions. For ``.S`` files, ``xtensa-esp32-elf-as`` assembler is used. This is not desirable for ULP assembly files, so the easiest way to achieve the distinction is by placing ULP assembly files into a separate directory. The ULP assembly source files should also **not** be added to ``COMPONENT_SRCS`` for the same reason. See the step below for how to properly add ULP assembly source files. +.. note: This directory should not be added to the ``COMPONENT_SRCDIRS`` environment variable. The logic behind this is that the ESP-IDF build system will compile files found in ``COMPONENT_SRCDIRS`` based on their extensions. For ``.S`` files, ``xtensa-esp32-elf-as`` assembler is used. This is not desirable for ULP assembly files, so the easiest way to achieve the distinction is by placing ULP assembly files into a separate directory. -2. Call ``ulp_embed_binary`` from the component CMakeLists.txt after registration. For example:: +2. Modify the component makefile, adding the following:: - ... - register_component() + ULP_APP_NAME ?= ulp_$(COMPONENT_NAME) + ULP_S_SOURCES = $(COMPONENT_PATH)/ulp/ulp_source_file.S + ULP_EXP_DEP_OBJECTS := main.o + include $(IDF_PATH)/components/ulp/component_ulp_common.mk + + Here is each line explained: - set(ulp_app_name ulp_${COMPONENT_NAME}) - set(ulp_s_sources ulp/ulp_assembly_source_file.S) - set(ulp_exp_dep_srcs "ulp_c_source_file.c") + ULP_APP_NAME + Name of the generated ULP application, without an extension. This name is used for build products of the ULP application: ELF file, map file, binary file, generated header file, and generated linker export file. - ulp_embed_binary(${ulp_app_name} ${ulp_s_sources} ${ulp_exp_dep_srcs}) + ULP_S_SOURCES + List of assembly files to be passed to the ULP assembler. These must be absolute paths, i.e. start with ``$(COMPONENT_PATH)``. Consider using ``$(addprefix)`` function if more than one file needs to be listed. Paths are relative to component build directory, so prefixing them is not necessary. - The first argument to ``ulp_embed_binary`` specifies the ULP binary name. The name specified here will also be used other generated artifacts - such as the ELF file, map file, header file and linker export file. The second argument specifies the ULP assembly source files. - Finally, the third argument specifies the list of component source files which include the header file to be generated. - This list is needed to build the dependencies correctly and ensure that the generated header file is created before any of these files are compiled. - See section below explaining the concept of generated header files for ULP applications. + ULP_EXP_DEP_OBJECTS + List of object files names within the component which include the generated header file. This list is needed to build the dependencies correctly and ensure that the generated header file is created before any of these files are compiled. See section below explaining the concept of generated header files for ULP applications. -3. Build the application as usual (e.g. `idf.py app`) + include $(IDF_PATH)/components/ulp/component_ulp_common.mk + Includes common definitions of ULP build steps. Defines build targets for ULP object files, ELF file, binary file, etc. +3. Build the application as usual (e.g. ``idf.py build`` or ``idf.py app``) + Inside, the build system will take the following steps to build ULP program: - 1. **Run each assembly file (foo.S) through C preprocessor.** This step generates the preprocessed assembly files (foo.ulp.S) in the component build directory. This step also generates dependency files (foo.ulp.d). + 1. **Run each assembly file (foo.S) through C preprocessor.** This step generates the preprocessed assembly files (foo.ulp.pS) in the component build directory. This step also generates dependency files (foo.ulp.d). 2. **Run preprocessed assembly sources through assembler.** This produces objects (foo.ulp.o) and listing (foo.ulp.lst) files. Listing files are generated for debugging purposes and are not used at later stages of build process. - + 3. **Run linker script template through C preprocessor.** The template is located in components/ulp/ld directory. 4. **Link object files into an output ELF file** (ulp_app_name.elf). Map file (ulp_app_name.map) generated at this stage may be useful for debugging purposes. @@ -71,7 +73,7 @@ To compile ULP code as part of a component, the following steps must be taken: Accessing ULP program variables ------------------------------- -Global symbols defined in the ULP program may be used inside the main program. +Global symbols defined in the ULP program may be used inside the main program. For example, ULP program may define a variable ``measurement_count`` which will define the number of ADC measurements the program needs to make before waking up the chip from deep sleep:: @@ -82,10 +84,10 @@ For example, ULP program may define a variable ``measurement_count`` which will move r3, measurement_count ld r3, r3, 0 -Main program needs to initialize this variable before ULP program is started. Build system makes this possible by generating a ``${ULP_APP_NAME}.h`` and ``${ULP_APP_NAME}.ld`` files which define global symbols present in the ULP program. This files include each global symbol defined in the ULP program, prefixed with ``ulp_``. +Main program needs to initialize this variable before ULP program is started. Build system makes this possible by generating a ``$(ULP_APP_NAME).h`` and ``$(ULP_APP_NAME).ld`` files which define global symbols present in the ULP program. This files include each global symbol defined in the ULP program, prefixed with ``ulp_``. The header file contains declaration of the symbol:: - + extern uint32_t ulp_measurement_count; Note that all symbols (variables, arrays, functions) are declared as ``uint32_t``. For functions and arrays, take address of the symbol and cast to the appropriate type. @@ -136,7 +138,7 @@ Once the program is loaded into RTC memory, application can start it, passing th .. doxygenfunction:: ulp_run -Declaration of the entry point symbol comes from the above mentioned generated header file, ``${ULP_APP_NAME}.h``. In assembly source of the ULP application, this symbol must be marked as ``.global``:: +Declaration of the entry point symbol comes from the above mentioned generated header file, ``$(ULP_APP_NAME).h``. In assembly source of the ULP application, this symbol must be marked as ``.global``:: .global entry diff --git a/docs/en/api-guides/ulp.rst b/docs/en/api-guides/ulp.rst index 8eee8cffd9..0391ab73d1 100644 --- a/docs/en/api-guides/ulp.rst +++ b/docs/en/api-guides/ulp.rst @@ -1,5 +1,7 @@ -ULP coprocessor programming -=========================== +ULP coprocessor programming (CMake) +=================================== + +:link_to_translation:`zh_CN:[中文]` .. toctree:: :maxdepth: 1 @@ -25,39 +27,35 @@ Compiling ULP code To compile ULP code as part of a component, the following steps must be taken: -1. ULP code, written in assembly, must be added to one or more files with `.S` extension. These files must be placed into a separate directory inside component directory, for instance `ulp/`. +1. ULP code, written in assembly, must be added to one or more files with `.S` extension. These files must be placed into a separate directory inside component directory, for instance `ulp/`. -.. note: This directory should not be added to the ``COMPONENT_SRCDIRS`` environment variable. The logic behind this is that the ESP-IDF build system will compile files found in ``COMPONENT_SRCDIRS`` based on their extensions. For ``.S`` files, ``xtensa-esp32-elf-as`` assembler is used. This is not desirable for ULP assembly files, so the easiest way to achieve the distinction is by placing ULP assembly files into a separate directory. +.. note: This directory should not be added to the ``COMPONENT_SRCDIRS`` environment variable. The logic behind this is that the ESP-IDF build system will compile files found in ``COMPONENT_SRCDIRS`` based on their extensions. For ``.S`` files, ``xtensa-esp32-elf-as`` assembler is used. This is not desirable for ULP assembly files, so the easiest way to achieve the distinction is by placing ULP assembly files into a separate directory. The ULP assembly source files should also **not** be added to ``COMPONENT_SRCS`` for the same reason. See the step below for how to properly add ULP assembly source files. -2. Modify the component makefile, adding the following:: +2. Call ``ulp_embed_binary`` from the component CMakeLists.txt after registration. For example:: - ULP_APP_NAME ?= ulp_$(COMPONENT_NAME) - ULP_S_SOURCES = $(COMPONENT_PATH)/ulp/ulp_source_file.S - ULP_EXP_DEP_OBJECTS := main.o - include $(IDF_PATH)/components/ulp/component_ulp_common.mk - - Here is each line explained: + ... + register_component() - ULP_APP_NAME - Name of the generated ULP application, without an extension. This name is used for build products of the ULP application: ELF file, map file, binary file, generated header file, and generated linker export file. + set(ulp_app_name ulp_${COMPONENT_NAME}) + set(ulp_s_sources ulp/ulp_assembly_source_file.S) + set(ulp_exp_dep_srcs "ulp_c_source_file.c") - ULP_S_SOURCES - List of assembly files to be passed to the ULP assembler. These must be absolute paths, i.e. start with ``$(COMPONENT_PATH)``. Consider using ``$(addprefix)`` function if more than one file needs to be listed. Paths are relative to component build directory, so prefixing them is not necessary. + ulp_embed_binary(${ulp_app_name} ${ulp_s_sources} ${ulp_exp_dep_srcs}) - ULP_EXP_DEP_OBJECTS - List of object files names within the component which include the generated header file. This list is needed to build the dependencies correctly and ensure that the generated header file is created before any of these files are compiled. See section below explaining the concept of generated header files for ULP applications. + The first argument to ``ulp_embed_binary`` specifies the ULP binary name. The name specified here will also be used other generated artifacts + such as the ELF file, map file, header file and linker export file. The second argument specifies the ULP assembly source files. + Finally, the third argument specifies the list of component source files which include the header file to be generated. + This list is needed to build the dependencies correctly and ensure that the generated header file is created before any of these files are compiled. + See section below explaining the concept of generated header files for ULP applications. - include $(IDF_PATH)/components/ulp/component_ulp_common.mk - Includes common definitions of ULP build steps. Defines build targets for ULP object files, ELF file, binary file, etc. +3. Build the application as usual (e.g. `idf.py app`) -3. Build the application as usual (e.g. ``idf.py build`` or ``idf.py app``) - Inside, the build system will take the following steps to build ULP program: - 1. **Run each assembly file (foo.S) through C preprocessor.** This step generates the preprocessed assembly files (foo.ulp.pS) in the component build directory. This step also generates dependency files (foo.ulp.d). + 1. **Run each assembly file (foo.S) through C preprocessor.** This step generates the preprocessed assembly files (foo.ulp.S) in the component build directory. This step also generates dependency files (foo.ulp.d). 2. **Run preprocessed assembly sources through assembler.** This produces objects (foo.ulp.o) and listing (foo.ulp.lst) files. Listing files are generated for debugging purposes and are not used at later stages of build process. - + 3. **Run linker script template through C preprocessor.** The template is located in components/ulp/ld directory. 4. **Link object files into an output ELF file** (ulp_app_name.elf). Map file (ulp_app_name.map) generated at this stage may be useful for debugging purposes. @@ -73,7 +71,7 @@ To compile ULP code as part of a component, the following steps must be taken: Accessing ULP program variables ------------------------------- -Global symbols defined in the ULP program may be used inside the main program. +Global symbols defined in the ULP program may be used inside the main program. For example, ULP program may define a variable ``measurement_count`` which will define the number of ADC measurements the program needs to make before waking up the chip from deep sleep:: @@ -84,10 +82,10 @@ For example, ULP program may define a variable ``measurement_count`` which will move r3, measurement_count ld r3, r3, 0 -Main program needs to initialize this variable before ULP program is started. Build system makes this possible by generating a ``$(ULP_APP_NAME).h`` and ``$(ULP_APP_NAME).ld`` files which define global symbols present in the ULP program. This files include each global symbol defined in the ULP program, prefixed with ``ulp_``. +Main program needs to initialize this variable before ULP program is started. Build system makes this possible by generating a ``${ULP_APP_NAME}.h`` and ``${ULP_APP_NAME}.ld`` files which define global symbols present in the ULP program. This files include each global symbol defined in the ULP program, prefixed with ``ulp_``. The header file contains declaration of the symbol:: - + extern uint32_t ulp_measurement_count; Note that all symbols (variables, arrays, functions) are declared as ``uint32_t``. For functions and arrays, take address of the symbol and cast to the appropriate type. @@ -138,7 +136,7 @@ Once the program is loaded into RTC memory, application can start it, passing th .. doxygenfunction:: ulp_run -Declaration of the entry point symbol comes from the above mentioned generated header file, ``$(ULP_APP_NAME).h``. In assembly source of the ULP application, this symbol must be marked as ``.global``:: +Declaration of the entry point symbol comes from the above mentioned generated header file, ``${ULP_APP_NAME}.h``. In assembly source of the ULP application, this symbol must be marked as ``.global``:: .global entry diff --git a/docs/en/api-guides/unit-tests-cmake.rst b/docs/en/api-guides/unit-tests-legacy.rst similarity index 77% rename from docs/en/api-guides/unit-tests-cmake.rst rename to docs/en/api-guides/unit-tests-legacy.rst index e08b912f87..43346e4b41 100644 --- a/docs/en/api-guides/unit-tests-cmake.rst +++ b/docs/en/api-guides/unit-tests-legacy.rst @@ -1,9 +1,7 @@ -Unit Testing in ESP32 (CMake) -============================= +Unit Testing in ESP32 +===================== :link_to_translation:`zh_CN:[中文]` -.. include:: ../cmake-warning.rst - ESP-IDF comes with a unit test app based on Unity - unit test framework. Unit tests are integrated in the ESP-IDF repository and are placed in ``test`` subdirectory of each component respectively. Add normal test cases @@ -28,18 +26,9 @@ Identifiers are used to group related test, or tests with specific properties. There is no need to add a main function with ``UNITY_BEGIN()`` and ``​UNITY_END()`` in each test case. ``unity_platform.c`` will run ``UNITY_BEGIN()``, run the tests cases, and then call ``​UNITY_END()``. -The ``test`` subdirectory should contain a :ref:`component CMakeLists.txt `, since they are themselves, -components. ESP-IDF uses the test framework ``unity`` and should be specified as a requirement for the component. Normally, components -:ref:`should list their sources manually `; for component tests however, this requirement is relaxed and the -use of ``COMPONENT_SRCDIRS`` is advised. +Each `test` subdirectory needs to include component.mk file with at least the following line of code:: -Overall, the minimal ``test`` subdirectory CMakeLists.txt file may look like as follows: - -.. code:: cmake - - idf_component_register(SRC_DIRS "." - INCLUDE_DIRS "." - REQUIRES unity) + COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive See http://www.throwtheswitch.org/unity for more information about writing tests in Unity. @@ -87,13 +76,27 @@ As the secnario in the above example, slave should get GPIO level after master s DUT1 (master) console:: Waiting for signal: [output high level]! - Please press "Enter" key to once any board send this signal. + Please press "Enter" key once any board send this signal. DUT2 (slave) console:: Send signal: [output high level]! -Once the signal is set from DUT2, you need to press "Enter" on DUT1, then DUT1 unblocks from ``unity_wait_for_signal`` and starts to change GPIO level. +Once the signal is sent from DUT2, you need to press "Enter" on DUT1, then DUT1 unblocks from ``unity_wait_for_signal`` and starts to change GPIO level. + +Signals can also be used to pass parameters between multiple devices. For example, DUT1 want to know the MAC address of DUT2, so it can connect to DUT2. +In this case, ``unity_wait_for_signal_param`` and ``unity_send_signal_param`` can be used: + +DUT1 console:: + + Waiting for signal: [dut2 mac address]! + Please input parameter value from any board send this signal and press "Enter" key. + +DUT2 console:: + + Send signal: [dut2 mac address][10:20:30:40:50:60]! + +Once the signal is sent from DUT2, you need to input ``10:20:30:40:50:60`` on DUT1 and press "Enter". Then DUT1 will get the MAC address string of DUT2 and unblocks from ``unity_wait_for_signal_param``, start to connect to DUT2. Add multiple stages test cases @@ -128,15 +131,15 @@ Make sure that IDF_PATH environment variable is set to point to the path of esp- Change into tools/unit-test-app directory to configure and build it: -* `idf.py menuconfig` - configure unit test app. +* `make menuconfig` - configure unit test app. -* `idf.py -T all build` - build unit test app with tests for each component having tests in the ``test`` subdirectory. -* `idf.py -T xxx build` - build unit test app with tests for specific components. -* `idf.py -T all -E xxx build` - build unit test app with all unit tests, except for unit tests of some components. (For instance: `idf.py -T all -E ulp -E mbedtls build` - build all unit tests exludes ulp and mbedtls components). +* `make TESTS_ALL=1` - build unit test app with tests for each component having tests in the ``test`` subdirectory. +* `make TEST_COMPONENTS='xxx'` - build unit test app with tests for specific components. +* `make TESTS_ALL=1 TEST_EXCLUDE_COMPONENTS='xxx'` - build unit test app with all unit tests, except for unit tests of some components. (For instance: `make TESTS_ALL=1 TEST_EXCLUDE_COMPONENTS='ulp mbedtls'` - build all unit tests exludes ulp and mbedtls components). -When the build finishes, it will print instructions for flashing the chip. You can simply run ``idf.py flash`` to flash all build output. +When the build finishes, it will print instructions for flashing the chip. You can simply run ``make flash`` to flash all build output. -You can also run ``idf.py -T all flash`` or ``idf.py -T xxx flash`` to build and flash. Everything needed will be rebuilt automatically before flashing. +You can also run ``make flash TESTS_ALL=1`` or ``make TEST_COMPONENTS='xxx'`` to build and flash. Everything needed will be rebuilt automatically before flashing. Use menuconfig to set the serial port for flashing. @@ -177,13 +180,13 @@ Normal case will print the case name and description. Master slave cases will al Test cases can be run by inputting one of the following: -- Test case name in quotation marks to run a single test case +- Test case name in quotation marks (for example, ``"esp_ota_begin() verifies arguments"``) to run a single test case. -- Test case index to run a single test case +- Test case index (for example, ``1``) to run a single test case. -- Module name in square brackets to run all test cases for a specific module +- Module name in square brackets (for example, ``[cxx]``) to run all test cases for a specific module. -- An asterisk to run all test cases +- An asterisk (``*``) to run all test cases ``[multi_device]`` and ``[multi_stage]`` tags tell the test runner whether a test case is a multiple devices or multiple stages test case. These tags are automatically added by ```TEST_CASE_MULTIPLE_STAGES`` and ``TEST_CASE_MULTIPLE_DEVICES`` macros. diff --git a/docs/en/api-guides/unit-tests.rst b/docs/en/api-guides/unit-tests.rst index 43346e4b41..e08b912f87 100644 --- a/docs/en/api-guides/unit-tests.rst +++ b/docs/en/api-guides/unit-tests.rst @@ -1,7 +1,9 @@ -Unit Testing in ESP32 -===================== +Unit Testing in ESP32 (CMake) +============================= :link_to_translation:`zh_CN:[中文]` +.. include:: ../cmake-warning.rst + ESP-IDF comes with a unit test app based on Unity - unit test framework. Unit tests are integrated in the ESP-IDF repository and are placed in ``test`` subdirectory of each component respectively. Add normal test cases @@ -26,9 +28,18 @@ Identifiers are used to group related test, or tests with specific properties. There is no need to add a main function with ``UNITY_BEGIN()`` and ``​UNITY_END()`` in each test case. ``unity_platform.c`` will run ``UNITY_BEGIN()``, run the tests cases, and then call ``​UNITY_END()``. -Each `test` subdirectory needs to include component.mk file with at least the following line of code:: +The ``test`` subdirectory should contain a :ref:`component CMakeLists.txt `, since they are themselves, +components. ESP-IDF uses the test framework ``unity`` and should be specified as a requirement for the component. Normally, components +:ref:`should list their sources manually `; for component tests however, this requirement is relaxed and the +use of ``COMPONENT_SRCDIRS`` is advised. - COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive +Overall, the minimal ``test`` subdirectory CMakeLists.txt file may look like as follows: + +.. code:: cmake + + idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity) See http://www.throwtheswitch.org/unity for more information about writing tests in Unity. @@ -76,27 +87,13 @@ As the secnario in the above example, slave should get GPIO level after master s DUT1 (master) console:: Waiting for signal: [output high level]! - Please press "Enter" key once any board send this signal. + Please press "Enter" key to once any board send this signal. DUT2 (slave) console:: Send signal: [output high level]! -Once the signal is sent from DUT2, you need to press "Enter" on DUT1, then DUT1 unblocks from ``unity_wait_for_signal`` and starts to change GPIO level. - -Signals can also be used to pass parameters between multiple devices. For example, DUT1 want to know the MAC address of DUT2, so it can connect to DUT2. -In this case, ``unity_wait_for_signal_param`` and ``unity_send_signal_param`` can be used: - -DUT1 console:: - - Waiting for signal: [dut2 mac address]! - Please input parameter value from any board send this signal and press "Enter" key. - -DUT2 console:: - - Send signal: [dut2 mac address][10:20:30:40:50:60]! - -Once the signal is sent from DUT2, you need to input ``10:20:30:40:50:60`` on DUT1 and press "Enter". Then DUT1 will get the MAC address string of DUT2 and unblocks from ``unity_wait_for_signal_param``, start to connect to DUT2. +Once the signal is set from DUT2, you need to press "Enter" on DUT1, then DUT1 unblocks from ``unity_wait_for_signal`` and starts to change GPIO level. Add multiple stages test cases @@ -131,15 +128,15 @@ Make sure that IDF_PATH environment variable is set to point to the path of esp- Change into tools/unit-test-app directory to configure and build it: -* `make menuconfig` - configure unit test app. +* `idf.py menuconfig` - configure unit test app. -* `make TESTS_ALL=1` - build unit test app with tests for each component having tests in the ``test`` subdirectory. -* `make TEST_COMPONENTS='xxx'` - build unit test app with tests for specific components. -* `make TESTS_ALL=1 TEST_EXCLUDE_COMPONENTS='xxx'` - build unit test app with all unit tests, except for unit tests of some components. (For instance: `make TESTS_ALL=1 TEST_EXCLUDE_COMPONENTS='ulp mbedtls'` - build all unit tests exludes ulp and mbedtls components). +* `idf.py -T all build` - build unit test app with tests for each component having tests in the ``test`` subdirectory. +* `idf.py -T xxx build` - build unit test app with tests for specific components. +* `idf.py -T all -E xxx build` - build unit test app with all unit tests, except for unit tests of some components. (For instance: `idf.py -T all -E ulp -E mbedtls build` - build all unit tests exludes ulp and mbedtls components). -When the build finishes, it will print instructions for flashing the chip. You can simply run ``make flash`` to flash all build output. +When the build finishes, it will print instructions for flashing the chip. You can simply run ``idf.py flash`` to flash all build output. -You can also run ``make flash TESTS_ALL=1`` or ``make TEST_COMPONENTS='xxx'`` to build and flash. Everything needed will be rebuilt automatically before flashing. +You can also run ``idf.py -T all flash`` or ``idf.py -T xxx flash`` to build and flash. Everything needed will be rebuilt automatically before flashing. Use menuconfig to set the serial port for flashing. @@ -180,13 +177,13 @@ Normal case will print the case name and description. Master slave cases will al Test cases can be run by inputting one of the following: -- Test case name in quotation marks (for example, ``"esp_ota_begin() verifies arguments"``) to run a single test case. +- Test case name in quotation marks to run a single test case -- Test case index (for example, ``1``) to run a single test case. +- Test case index to run a single test case -- Module name in square brackets (for example, ``[cxx]``) to run all test cases for a specific module. +- Module name in square brackets to run all test cases for a specific module -- An asterisk (``*``) to run all test cases +- An asterisk to run all test cases ``[multi_device]`` and ``[multi_stage]`` tags tell the test runner whether a test case is a multiple devices or multiple stages test case. These tags are automatically added by ```TEST_CASE_MULTIPLE_STAGES`` and ``TEST_CASE_MULTIPLE_DEVICES`` macros. diff --git a/docs/en/get-started-cmake/add-idf_path-to-profile.rst b/docs/en/get-started-cmake/add-idf_path-to-profile.rst deleted file mode 100644 index cdaf9a5b88..0000000000 --- a/docs/en/get-started-cmake/add-idf_path-to-profile.rst +++ /dev/null @@ -1,3 +0,0 @@ -:orphan: - -.. Remove this file when the Chinese translation of CMake getting started guide is updated diff --git a/docs/en/get-started-cmake/eclipse-setup.rst b/docs/en/get-started-cmake/eclipse-setup.rst deleted file mode 100644 index 2e2b105bc2..0000000000 --- a/docs/en/get-started-cmake/eclipse-setup.rst +++ /dev/null @@ -1,12 +0,0 @@ -**************************************** -Build and Flash with Eclipse IDE (CMake) -**************************************** - -:link_to_translation:`zh_CN:[中文]` - -.. include:: ../cmake-warning.rst - -Documentation for Eclipse setup with CMake-based build system and Eclipse CDT is coming soon. - -.. _eclipse.org: https://www.eclipse.org/ - diff --git a/docs/en/get-started-cmake/index.rst b/docs/en/get-started-cmake/index.rst deleted file mode 100644 index e5f810c093..0000000000 --- a/docs/en/get-started-cmake/index.rst +++ /dev/null @@ -1,491 +0,0 @@ -******************* -Get Started (CMake) -******************* - -:link_to_translation:`zh_CN:[中文]` - -.. include:: ../cmake-warning.rst - -.. include:: ../cmake-pending-features.rst - -This document is intended to help you set up the software development environment for the hardware based on the ESP32 chip by Espressif. - -After that, a simple example will show you how to use ESP-IDF (Espressif IoT Development Framework) for menu configuration, then building, and flashing firmware onto an ESP32 board. - -.. include:: /_build/inc/version-note.inc - -Introduction -============ - -ESP32 is a system on a chip that integrates the following features: - -* Wi-Fi (2.4 GHz band) -* Bluetooth 4.2 -* Dual high performance cores -* Ultra Low Power co-processor -* Several peripherals - -Powered by 40 nm technology, ESP32 provides a robust, highly integrated platform, which helps meet the continuous demands for efficient power usage, compact design, security, high performance, and reliability. - -Espressif provides basic hardware and software resources to help application developers realize their ideas using the ESP32 series hardware. The software development framework by Espressif is intended for development of Internet-of-Things (IoT) applications with Wi-Fi, Bluetooth, power management and several other system features. - -What You Need -============= - -Hardware: - -* An **ESP32** board -* **USB cable** - USB A / micro USB B -* **Computer** running Windows, Linux, or macOS - -Software: - -* **Toolchain** to compile code for ESP32 -* **Build tools** - CMake and Ninja to build a full **Application** for ESP32 -* **ESP-IDF** that essentially contains API (software libraries and source code) for ESP32 and scripts to operate the **Toolchain** -* **Text editor** to write programs (**Projects**) in C, e.g., `Eclipse `_ - - -.. figure:: ../../_static/what-you-need-cmake.png - :align: center - :alt: Development of applications for ESP32 - :figclass: align-center - - Development of applications for ESP32 - - -Development Board Overviews -=========================== - -If you have one of ESP32 development boards listed below, you can click on the link to learn more about its hardware. - -.. toctree:: - :maxdepth: 1 - - ESP32-DevKitC <../hw-reference/get-started-devkitc> - ESP-WROVER-KIT <../hw-reference/get-started-wrover-kit> - ESP32-PICO-KIT <../hw-reference/get-started-pico-kit> - ESP32-Ethernet-Kit <../hw-reference/get-started-ethernet-kit> - - -.. _get-started-step-by-step-cmake: - -Installation Step by Step -========================= - -This is a detailed roadmap to walk you through the installation process. - -Setting up Development Environment -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* :ref:`get-started-get-prerequisites-cmake` for :doc:`Windows `, :doc:`Linux ` or :doc:`macOS ` -* :ref:`get-started-get-esp-idf-cmake` -* :ref:`get-started-set-up-tools-cmake` -* :ref:`get-started-set-up-env-cmake` - -Creating Your First Project -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* :ref:`get-started-start-project-cmake` -* :ref:`get-started-connect-cmake` -* :ref:`get-started-configure-cmake` -* :ref:`get-started-build-cmake` -* :ref:`get-started-flash-cmake` -* :ref:`get-started-build-monitor-cmake` - - -.. _get-started-get-prerequisites-cmake: - -Step 1. Install prerequisites -============================= - -Some tools need to be installed on the computer before proceeding to the next steps. Follow the links below for the instructions for your OS: - -.. toctree:: - :hidden: - - Windows - Linux - macOS - -* :doc:`windows-setup` -* :doc:`linux-setup` -* :doc:`macos-setup` - -.. _get-started-get-esp-idf-cmake: - -Step 2. Get ESP-IDF -=================== - -To build applications for the ESP32, you need the software libraries provided by Espressif in `ESP-IDF repository `_. - -Get ESP-IDF in accordance with your operating system. - -To get ESP-IDF, navigate to your installation directory and clone the repository with ``git clone``. - -.. note:: - - This guide uses the directory ``~/esp`` on Linux and macOS or ``%userprofile%\esp`` on Windows as an installation folder for ESP-IDF. You can use any directory, but you will need to adjust paths for the commands respectively. Keep in mind that ESP-IDF does not support spaces in paths. - -Linux and macOS -~~~~~~~~~~~~~~~ - -Open Terminal, and run the following commands: - -.. include:: /_build/inc/git-clone-bash.inc - -ESP-IDF will be downloaded into ``~/esp/esp-idf``. - -Consult :doc:`/versions` for information about which ESP-IDF version to use in a given situation. - -Windows -~~~~~~~ - -In addition to installing the tools, :ref:`get-started-cmake-windows-tools-installer` for Windows introduced in Step 1 can also download a copy of ESP-IDF. - -Consult :doc:`/versions` for information about which ESP-IDF version to use in a given situation. - -If you wish to download ESP-IDF without the help of ESP-IDF Tools Installer, refer to these :ref:`instructions `. - -.. _get-started-set-up-tools-cmake: - -Step 3. Set up the tools -======================== - -Aside from the ESP-IDF, you also need to install the tools used by ESP-IDF, such as the compiler, debugger, Python packages, etc. - -Windows -~~~~~~~ - -:ref:`get-started-cmake-windows-tools-installer` for Windows introduced in Step 1 installs all the required tools. - -If you want to install the tools without the help of ESP-IDF Tools Installer, open the Command Prompt and follow these steps: - -.. code-block:: batch - - cd %userprofile%\esp\esp-idf - install.bat - -Linux and macOS -~~~~~~~~~~~~~~~ - -.. code-block:: bash - - cd ~/esp/esp-idf - ./install.sh - -Customizing the tools installation path -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The scripts introduced in this step install compilation tools required by ESP-IDF inside the user home directory: ``$HOME/.espressif`` on Linux and macOS, ``%USERPROFILE%\.espressif`` on Windows. If you wish to install the tools into a different directory, set the environment variable ``IDF_TOOLS_PATH`` before running the installation scripts. Make sure that your user has sufficient permissions to read and write this path. - -If changing the ``IDF_TOOLS_PATH``, make sure it is set to the same value every time the ``install.bat``/``install.sh`` and ``export.bat``/``export.sh`` scripts are executed. - -.. _get-started-set-up-env-cmake: - -Step 4. Set up the environment variables -======================================== - -The installed tools are not yet added to the PATH environment variable. To make the tools usable from the command line, some environment variables must be set. ESP-IDF provides another script which does that. - -Windows -~~~~~~~ - -:ref:`get-started-cmake-windows-tools-installer` for Windows creates an "ESP-IDF Command Prompt" shortcut in the Start Menu. This shortcut opens the Command Prompt and sets up all the required environment variables. You can open this shortcut and proceed to the next step. - -Alternatively, if you want to use ESP-IDF in an existing Command Prompt window, you can run: - -.. code-block:: batch - - %userprofile%\esp\esp-idf\export.bat - -Linux and macOS -~~~~~~~~~~~~~~~ - -In the terminal where you are going to use ESP-IDF, run: - -.. code-block:: bash - - . $HOME/esp/esp-idf/export.sh - -Note the space between the leading dot and the path! - -You can also automate this step, making ESP-IDF tools available in every terminal, by adding this line to your ``.profile`` or ``.bash_profile`` script. - -.. _get-started-start-project-cmake: - -Step 5. Start a Project -======================= - -Now you are ready to prepare your application for ESP32. You can start with :example:`get-started/hello_world` project from :idf:`examples` directory in IDF. - -Copy :example:`get-started/hello_world` to ``~/esp`` directory: - -Linux and macOS -~~~~~~~~~~~~~~~ - -.. code-block:: bash - - cd ~/esp - cp -r $IDF_PATH/examples/get-started/hello_world . - -Windows -~~~~~~~ - -.. code-block:: batch - - cd %userprofile%\esp - xcopy /e /i %IDF_PATH%\examples\get-started\hello_world hello_world - -There is a range of example projects in the :idf:`examples` directory in ESP-IDF. You can copy any project in the same way as presented above and run it. - -It is also possible to build examples in-place, without copying them first. - -.. important:: - - The ESP-IDF build system does not support spaces in the paths to either ESP-IDF or to projects. - -.. _get-started-connect-cmake: - -Step 6. Connect Your Device -=========================== - -Now connect your ESP32 board to the computer and check under what serial port the board is visible. - -Serial ports have the following patterns in their names: - -- **Windows**: names like ``COM1`` -- **Linux**: starting with ``/dev/tty`` -- **macOS**: starting with ``/dev/cu.`` - -If you are not sure how to check the serial port name, please refer to :doc:`establish-serial-connection` for full details. - -.. note:: - - Keep the port name handy as you will need it in the next steps. - - -.. _get-started-configure-cmake: - -Step 7. Configure -================= - -Navigate to your ``hello_world`` directory from :ref:`get-started-start-project-cmake` and run the project configuration utility ``menuconfig``. - -Linux and macOS -~~~~~~~~~~~~~~~ - -.. code-block:: bash - - cd ~/esp/hello_world - idf.py menuconfig - -If your default version of Python is 3.x, you may need to run ``python2 $(which idf.py) menuconfig`` instead. - -Windows -~~~~~~~ - -.. code-block:: batch - - cd %userprofile%\esp\hello_world - idf.py menuconfig - -If the previous steps have been done correctly, the following menu appears: - -.. figure:: ../../_static/project-configuration.png - :align: center - :alt: Project configuration - Home window - :figclass: align-center - - Project configuration - Home window - -To navigate and use ``menuconfig``, press the following keys: - -* Arrow keys for navigation -* ``Enter`` to go into a submenu -* ``Esc`` to go up one level or exit -* ``?`` to see a help screen. Enter key exits the help screen -* ``Space``, or ``Y`` and ``N`` keys to enable (Yes) and disable (No) configuration items with checkboxes "``[*]``" -* ``?`` while highlighting a configuration item to display help about that item -* ``/`` to find configuration items - -.. attention:: - - If you use ESP32-DevKitC board with the **ESP32-SOLO-1** module, enable single core mode (:ref:`CONFIG_FREERTOS_UNICORE`) in menuconfig before flashing examples. - -.. _get-started-build-cmake: - -Step 8. Build the Project -========================= - -Build the project by running:: - - idf.py build - -This command will compile the application and all ESP-IDF components, then it will generate the bootloader, partition table, and application binaries. - -.. code-block:: none - - $ idf.py build - Running cmake in directory /path/to/hello_world/build - Executing "cmake -G Ninja --warn-uninitialized /path/to/hello_world"... - Warn about uninitialized values. - -- Found Git: /usr/bin/git (found version "2.17.0") - -- Building empty aws_iot component due to configuration - -- Component names: ... - -- Component paths: ... - - ... (more lines of build system output) - - [527/527] Generating hello-world.bin - esptool.py v2.3.1 - - Project build complete. To flash, run this command: - ../../../components/esptool_py/esptool/esptool.py -p (PORT) -b 921600 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x10000 build/hello-world.bin build 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin - or run 'idf.py -p PORT flash' - -If there are no errors, the build will finish by generating the firmware binary .bin file. - - -.. _get-started-flash-cmake: - -Step 9. Flash onto the Device -============================= - -Flash the binaries that you just built onto your ESP32 board by running:: - - idf.py -p PORT [-b BAUD] flash - -Replace PORT with your ESP32 board's serial port name from :ref:`get-started-connect-cmake`. - -You can also change the flasher baud rate by replacing BAUD with the baud rate you need. The default baud rate is ``460800``. - -For more information on idf.py arguments, see :ref:`idf.py`. - -.. note:: - - The option ``flash`` automatically builds and flashes the project, so running ``idf.py build`` is not necessary. - -.. code-block:: none - - Running esptool.py in directory [...]/esp/hello_world - Executing "python [...]/esp-idf/components/esptool_py/esptool/esptool.py -b 460800 write_flash @flash_project_args"... - esptool.py -b 460800 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x1000 bootloader/bootloader.bin 0x8000 partition_table/partition-table.bin 0x10000 hello-world.bin - esptool.py v2.3.1 - Connecting.... - Detecting chip type... ESP32 - Chip is ESP32D0WDQ6 (revision 1) - Features: WiFi, BT, Dual Core - Uploading stub... - Running stub... - Stub running... - Changing baud rate to 460800 - Changed. - Configuring flash size... - Auto-detected Flash size: 4MB - Flash params set to 0x0220 - Compressed 22992 bytes to 13019... - Wrote 22992 bytes (13019 compressed) at 0x00001000 in 0.3 seconds (effective 558.9 kbit/s)... - Hash of data verified. - Compressed 3072 bytes to 82... - Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 5789.3 kbit/s)... - Hash of data verified. - Compressed 136672 bytes to 67544... - Wrote 136672 bytes (67544 compressed) at 0x00010000 in 1.9 seconds (effective 567.5 kbit/s)... - Hash of data verified. - - Leaving... - Hard resetting via RTS pin... - -If there are no issues by the end of the flash process, the module will be reset and the “hello_world” application will be running. - -.. (Not currently supported) If you'd like to use the Eclipse IDE instead of running ``idf.py``, check out the :doc:`Eclipse guide `. - - -.. _get-started-build-monitor-cmake: - -Step 10. Monitor -================ - -To check if "hello_world" is indeed running, type ``idf.py -p PORT monitor`` (Do not forget to replace PORT with your serial port name). - -This command launches the :doc:`IDF Monitor <../api-guides/tools/idf-monitor>` application:: - - $ idf.py -p /dev/ttyUSB0 monitor - Running idf_monitor in directory [...]/esp/hello_world/build - Executing "python [...]/esp-idf/tools/idf_monitor.py -b 115200 [...]/esp/hello_world/build/hello-world.elf"... - --- idf_monitor on /dev/ttyUSB0 115200 --- - --- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- - ets Jun 8 2016 00:22:57 - - rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) - ets Jun 8 2016 00:22:57 - ... - -After startup and diagnostic logs scroll up, you should see "Hello world!" printed out by the application. - -.. code-block:: none - - ... - Hello world! - Restarting in 10 seconds... - I (211) cpu_start: Starting scheduler on APP CPU. - Restarting in 9 seconds... - Restarting in 8 seconds... - Restarting in 7 seconds... - -To exit IDF monitor use the shortcut ``Ctrl+]``. - -If IDF monitor fails shortly after the upload, or, if instead of the messages above, you see random garbage similar to what is given below, your board is likely using a 26MHz crystal. Most development board designs use 40MHz, so ESP-IDF uses this frequency as a default value. - -.. code-block:: none - - e���)(Xn@�y.!��(�PW+)��Hn9a؅/9�!�t5��P�~�k��e�ea�5�jA - ~zY��Y(1�,1�� e���)(Xn@�y.!Dr�zY(�jpi�|�+z5Ymvp - -If you have such a problem, do the following: - -1. Exit the monitor. -2. Go back to :ref:`menuconfig `. -3. Go to Component config --> ESP32-specific --> Main XTAL frequency, then change :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` to 26MHz. -4. After that, :ref:`build and flash ` the application again. - -.. note:: - - You can combine building, flashing and monitoring into one step by running:: - - idf.py -p PORT flash monitor - -See also: - -- :doc:`IDF Monitor <../api-guides/tools/idf-monitor>` for handy shortcuts and more details on using IDF monitor. -- :ref:`idf.py` for a full reference of ``idf.py`` commands and options. - -**That's all that you need to get started with ESP32!** - -Now you are ready to try some other :idf:`examples`, or go straight to developing your own applications. - -Updating ESP-IDF -================ - -You should update ESP-IDF from time to time, as newer versions fix bugs and provide new features. The simplest way to do the update is to delete the existing ``esp-idf`` folder and clone it again, as if performing the initial installation described in :ref:`get-started-get-esp-idf-cmake`. - -Another solution is to update only what has changed. :ref:`The update procedure depends on the version of ESP-IDF you are using `. - -After updating ESP-IDF, execute ``install.sh`` (``install.bat`` on Windows) again, in case the new ESP-IDF version requires different versions of tools. See instructions at :ref:`get-started-set-up-tools-cmake`. - -Once the new tools are installed, update the environment using ``export.sh`` (``export.bat`` on Windows). See instructions at :ref:`get-started-set-up-env-cmake`. - -Related Documents -================= - -.. toctree:: - :maxdepth: 1 - - establish-serial-connection - eclipse-setup - ../api-guides/tools/idf-monitor - toolchain-setup-scratch - -.. _Stable version: https://docs.espressif.com/projects/esp-idf/en/stable/ -.. _Releases page: https://github.com/espressif/esp-idf/releases \ No newline at end of file diff --git a/docs/en/get-started-cmake/linux-setup-scratch.rst b/docs/en/get-started-cmake/linux-setup-scratch.rst deleted file mode 100644 index 51abaf6fd3..0000000000 --- a/docs/en/get-started-cmake/linux-setup-scratch.rst +++ /dev/null @@ -1,77 +0,0 @@ -****************************************** -Setup Linux Toolchain from Scratch (CMake) -****************************************** - -:link_to_translation:`zh_CN:[中文]` - -.. include:: ../cmake-warning.rst - -The following instructions are alternative to downloading binary toolchain from Espressif website. To quickly setup the binary toolchain, instead of compiling it yourself, backup and proceed to section :doc:`linux-setup`. - -Install Prerequisites -===================== - -To compile with ESP-IDF you need to get the following packages: - -- CentOS 7:: - - sudo yum install git wget ncurses-devel flex bison gperf python pyserial python-pyelftools cmake ninja-build ccache - -- Ubuntu and Debian:: - - sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache - -- Arch:: - - sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-click python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache - -.. note:: - CMake version 3.5 or newer is required for use with ESP-IDF. Older Linux distributions may require updating, enabling of a "backports" repository, or installing of a "cmake3" package rather than "cmake". - -Compile the Toolchain from Source -================================= - -- Install dependencies: - - - CentOS 7:: - - sudo yum install gawk gperf grep gettext ncurses-devel python python-devel automake bison flex texinfo help2man libtool make - - - Ubuntu pre-16.04:: - - sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool make - - - Ubuntu 16.04 or newer:: - - sudo apt-get install gawk gperf grep gettext python python-dev automake bison flex texinfo help2man libtool libtool-bin make - - - Debian 9:: - - sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool libtool-bin make - - - Arch:: - - TODO - -Create the working directory and go into it:: - - mkdir -p ~/esp - cd ~/esp - -Download ``crosstool-NG`` and build it: - -.. include:: /_build/inc/scratch-build-code.inc - -Build the toolchain:: - - ./ct-ng xtensa-esp32-elf - ./ct-ng build - chmod -R u+w builds/xtensa-esp32-elf - -Toolchain will be built in ``~/esp/crosstool-NG/builds/xtensa-esp32-elf``. To use it, you need to add ``~/esp/crosstool-NG/builds/xtensa-esp32-elf/bin`` to ``PATH`` environment variable. - - -Next Steps -========== - -To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf-cmake`. diff --git a/docs/en/get-started-cmake/linux-setup.rst b/docs/en/get-started-cmake/linux-setup.rst deleted file mode 100644 index 429755b9bd..0000000000 --- a/docs/en/get-started-cmake/linux-setup.rst +++ /dev/null @@ -1,68 +0,0 @@ -*********************************************** -Installation of Prerequisites for Linux (CMake) -*********************************************** - -:link_to_translation:`zh_CN:[中文]` - -.. include:: ../cmake-warning.rst - -Install Prerequisites -===================== - -To compile with ESP-IDF you need to get the following packages: - -- CentOS 7:: - - sudo yum install git wget ncurses-devel flex bison gperf python pyserial python-pyelftools cmake ninja-build ccache - -- Ubuntu and Debian:: - - sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache - -- Arch:: - - sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pip python2-pyserial python2-click python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache - -.. note:: - CMake version 3.5 or newer is required for use with ESP-IDF. Older Linux distributions may require updating, enabling of a "backports" repository, or installing of a "cmake3" package rather than "cmake". - -Additional Tips -=============== - -Permission issues /dev/ttyUSB0 ------------------------------- - -With some Linux distributions you may get the ``Failed to open port /dev/ttyUSB0`` error message when flashing the ESP32. :ref:`This can be solved by adding the current user to the dialout group`. - - -Arch Linux Users ----------------- - -To run the precompiled gdb (xtensa-esp32-elf-gdb) in Arch Linux requires ncurses 5, but Arch uses ncurses 6. - -Backwards compatibility libraries are available in AUR_ for native and lib32 configurations: - -- https://aur.archlinux.org/packages/ncurses5-compat-libs/ -- https://aur.archlinux.org/packages/lib32-ncurses5-compat-libs/ - -Before installing these packages you might need to add the author's public key to your keyring as described in the "Comments" section at the links above. - -Alternatively, use crosstool-NG to compile a gdb that links against ncurses 6. - - -Next Steps -========== - -To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf-cmake`. - - -Related Documents -================= - -.. toctree:: - :maxdepth: 1 - - linux-setup-scratch - - -.. _AUR: https://wiki.archlinux.org/index.php/Arch_User_Repository diff --git a/docs/en/get-started-cmake/macos-setup-scratch.rst b/docs/en/get-started-cmake/macos-setup-scratch.rst deleted file mode 100644 index 45fa4238ca..0000000000 --- a/docs/en/get-started-cmake/macos-setup-scratch.rst +++ /dev/null @@ -1,88 +0,0 @@ -*********************************************** -Setup Toolchain for Mac OS from Scratch (CMake) -*********************************************** - -:link_to_translation:`zh_CN:[中文]` - -.. include:: ../cmake-warning.rst - -Package Manager -=============== - -To set up the toolchain from scratch, rather than :doc:`downloading a pre-compiled toolchain`, you will need to install either the MacPorts_ or homebrew_ package manager. - -MacPorts needs a full XCode installation, while homebrew only needs XCode command line tools. - - .. _homebrew: https://brew.sh/ - .. _MacPorts: https://www.macports.org/install.php - -See :ref:`Customized Setup of Toolchain ` section for some of the reasons why installing the toolchain from scratch may be necessary. - -Install Prerequisites -===================== - -- install pip:: - - sudo easy_install pip - -- install pyserial:: - - pip install --user pyserial - -- install CMake & Ninja build: - - - If you have HomeBrew, you can run:: - - brew install cmake ninja - - - If you have MacPorts, you can run:: - - sudo port install cmake ninja - -Compile the Toolchain from Source -================================= - -- Install dependencies: - - - with MacPorts:: - - sudo port install gsed gawk binutils gperf grep gettext wget libtool autoconf automake make - - - with homebrew:: - - brew install gnu-sed gawk binutils gperftools gettext wget help2man libtool autoconf automake make - -Create a case-sensitive filesystem image:: - - hdiutil create ~/esp/crosstool.dmg -volname "ctng" -size 10g -fs "Case-sensitive HFS+" - -Mount it:: - - hdiutil mount ~/esp/crosstool.dmg - -Create a symlink to your work directory:: - - mkdir -p ~/esp - ln -s /Volumes/ctng ~/esp/ctng-volume - -Go into the newly created directory:: - - cd ~/esp/ctng-volume - -Download ``crosstool-NG`` and build it: - -.. include:: /_build/inc/scratch-build-code.inc - -Build the toolchain:: - - ./ct-ng xtensa-esp32-elf - ./ct-ng build - chmod -R u+w builds/xtensa-esp32-elf - -Toolchain will be built in ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf``. To use it, you need to add ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf/bin`` to ``PATH`` environment variable. - - -Next Steps -========== - -To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf-cmake`. diff --git a/docs/en/get-started-cmake/macos-setup.rst b/docs/en/get-started-cmake/macos-setup.rst deleted file mode 100644 index 7926ea9d5f..0000000000 --- a/docs/en/get-started-cmake/macos-setup.rst +++ /dev/null @@ -1,60 +0,0 @@ -*********************************************** -Installation of Prerequisites for macOS (CMake) -*********************************************** - -:link_to_translation:`zh_CN:[中文]` - -.. include:: ../cmake-warning.rst - -Install Prerequisites -===================== - -ESP-IDF will use the version of Python installed by default on macOS. - -- install pip:: - - sudo easy_install pip - -- install pyserial:: - - pip install --user pyserial - -- install CMake & Ninja build: - - - If you have HomeBrew_, you can run:: - - brew install cmake ninja - - - If you have MacPorts_, you can run:: - - sudo port install cmake ninja - - - Otherwise, consult the CMake_ and Ninja_ home pages for macOS installation downloads. - -- It is strongly recommended to also install ccache_ for faster builds. If you have HomeBrew_, this can be done via ``brew install ccache`` or ``sudo port install ccache`` on MacPorts_. - -.. note:: - If an error like this is shown during any step:: - - xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun - - Then you will need to install the XCode command line tools to continue. You can install these by running ``xcode-select --install``. - -Next Steps -========== - -To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf-cmake`. - -Related Documents -================= - -.. toctree:: - :maxdepth: 1 - - macos-setup-scratch - -.. _cmake: https://cmake.org/ -.. _ninja: https://ninja-build.org/ -.. _ccache: https://ccache.samba.org/ -.. _homebrew: https://brew.sh/ -.. _MacPorts: https://www.macports.org/install.php diff --git a/docs/en/get-started-cmake/windows-setup-scratch.rst b/docs/en/get-started-cmake/windows-setup-scratch.rst deleted file mode 100644 index 4fa8168fef..0000000000 --- a/docs/en/get-started-cmake/windows-setup-scratch.rst +++ /dev/null @@ -1,122 +0,0 @@ -********************************** -Windows Setup from Scratch (CMake) -********************************** - -:link_to_translation:`zh_CN:[中文]` - -.. include:: ../cmake-warning.rst - -This is a step-by-step alternative to running the :doc:`ESP-IDF Tools Installer ` for the CMake-based build system. Installing all of the tools by hand allows more control over the process, and also provides the information for advanced users to customize the install. - -To quickly setup the toolchain and other tools in standard way, using the ESP-IDF Tools installer, proceed to section :doc:`windows-setup`. - -.. note:: - The GNU Make based build system requires the MSYS2_ Unix compatibility environment on Windows. The CMake-based build system does not require this environment. - -.. _get-esp-idf-windows-command-line-cmake: - -Get ESP-IDF -=========== - -.. note:: - - Previous versions of ESP-IDF used the **MSYS2 bash terminal** command line. The current cmake-based build system can run in the regular **Windows Command Prompt** which is used here. - - If you use a bash-based terminal or PowerShell, please note that some command syntax will be different to what is shown below. - -Open Command Prompt and run the following commands: - -.. include:: /_build/inc/git-clone-windows.inc - -ESP-IDF will be downloaded into ``%userprofile%\esp\esp-idf``. - -Consult :doc:`/versions` for information about which ESP-IDF version to use in a given situation. - -.. include:: /_build/inc/git-clone-notes.inc - -.. note:: - - Do not miss the ``--recursive`` option. If you have already cloned ESP-IDF without this option, run another command to get all the submodules:: - - cd esp-idf - git submodule update --init - - -Tools -===== - -cmake -^^^^^ - -Download the latest stable release of CMake_ for Windows and run the installer. - -When the installer asks for Install Options, choose either "Add CMake to the system PATH for all users" or "Add CMake to the system PATH for the current user". - -Ninja build -^^^^^^^^^^^ - -.. note:: - Ninja currently only provides binaries for 64-bit Windows. It is possible to use CMake and ``idf.py`` with other build tools, such as mingw-make, on 32-bit windows. However this is currently undocumented. - -Download the ninja_ latest stable Windows release from the (`download page `_). - -The Ninja for Windows download is a .zip file containing a single ``ninja.exe`` file which needs to be unzipped to a directory which is then `added to your Path `_ (or you can choose a directory which is already on your Path). - - -Python 2.x -^^^^^^^^^^ - -Download the latest Python_ 2.7 for Windows installer, and run it. - -The "Customise" step of the Python installer gives a list of options. The last option is "Add python.exe to Path". Change this option to select "Will be installed". - -Once Python is installed, open a Windows Command Prompt from the Start menu and run the following command:: - - pip install --user pyserial - -MConf for IDF -^^^^^^^^^^^^^ - -Download the configuration tool mconf-idf from the `kconfig-frontends releases page `_. This is the ``mconf`` configuration tool with some minor customizations for ESP-IDF. - -This tool will also need to be unzipped to a directory which is then `added to your Path `_. - -Toolchain Setup -=============== - -.. include:: /_build/inc/download-links.inc - -Download the precompiled Windows toolchain: - -|download_link_win32| - -Unzip the zip file to ``C:\Program Files`` (or some other location). The zip file contains a single directory ``xtensa-esp32-elf``. - -Next, the ``bin`` subdirectory of this directory must be `added to your Path `_. For example, the directory to add may be ``C:\Program Files\xtensa-esp32-elf\bin``. - -.. note:: - If you already have the MSYS2 environment (for use with the "GNU Make" build system) installed, you can skip the separate download and add the directory ``C:\msys32\opt\xtensa-esp32-elf\bin`` to the Path instead, as the toolchain is included in the MSYS2 environment. - - -.. _add-directory-windows-path-cmake: - -Adding Directory to Path -======================== - -To add any new directory to your Windows Path environment variable: - -Open the System control panel and navigate to the Environment Variables dialog. (On Windows 10, this is found under Advanced System Settings). - -Double-click the ``Path`` variable (either User or System Path, depending if you want other users to have this directory on their path.) Go to the end of the value, and append ``;``. - - -Next Steps -========== - -To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf-cmake`. - -.. _ninja: https://ninja-build.org/ -.. _Python: https://www.python.org/downloads/windows/ -.. _MSYS2: https://msys2.github.io/ -.. _Stable version: https://docs.espressif.com/projects/esp-idf/en/stable/ - diff --git a/docs/en/get-started-cmake/windows-setup.rst b/docs/en/get-started-cmake/windows-setup.rst deleted file mode 100644 index d226c5f0f7..0000000000 --- a/docs/en/get-started-cmake/windows-setup.rst +++ /dev/null @@ -1,70 +0,0 @@ -************************************************* -Installation of Prerequisites for Windows (CMake) -************************************************* - -:link_to_translation:`zh_CN:[中文]` - -.. include:: ../cmake-warning.rst - -.. note:: - The CMake-based build system is only supported on 64-bit versions of Windows. - -Introduction -============ - -ESP-IDF requires some prerequisite tools to be installed so you can build firmware for the ESP32. The prerequisite tools include Python, Git, cross-compilers, menuconfig tool, CMake and Ninja build tools. - -For this Getting Started we're going to use the Command Prompt, but after ESP-IDF is installed you can use :doc:`Eclipse ` or another graphical IDE with CMake support instead. - -.. note:: - The GNU Make based build system requires the MSYS2_ Unix compatibility environment on Windows. The CMake-based build system does not require this environment. - -.. _get-started-cmake-windows-tools-installer: - -ESP-IDF Tools Installer -======================= - -The easiest way to install ESP-IDF's prerequisites is to download the ESP-IDF Tools installer from this URL: - -https://dl.espressif.com/dl/esp-idf-tools-setup-2.0.exe - -The installer includes the cross-compilers, OpenOCD, cmake_ and Ninja_ build tool, and a configuration tool called mconf-idf_. The installer can also download and run installers for Python_ 3.7 and `Git For Windows`_ if they are not already installed on the computer. - -The installer also offers to download one of the ESP-IDF release versions. - -Using the Command Prompt -======================== - -For the remaining Getting Started steps, we're going to use the Windows Command Prompt. - -ESP-IDF Tools Installer creates a shortcut in the Start menu to launch the ESP-IDF Command Prompt. This shortcut launches the Command Prompt (cmd.exe) and runs ``export.bat`` script to set up the environment variables (``PATH``, ``IDF_PATH`` and others). Inside this command prompt, all the installed tools are available. - -Note that this shortcut is specific to the ESP-IDF directory selected in the ESP-IDF Tools Installer. If you have multiple ESP-IDF directories on the computer (for example, to work with different versions of ESP-IDF), you have two options to use them: - -1. Create a copy of the shortcut created by the ESP-IDF Tools Installer, and change the working directory of the new shortcut to the ESP-IDF directory you wish to use. - -2. Alternatively, run ``cmd.exe``, then change to the ESP-IDF directory you wish to use, and run ``export.bat``. Note that unlike the previous option, this way requires Python and Git to be present in ``PATH``. If you get errors related to Python or Git not being found, use the first option. - -Next Steps -========== - -If the ESP-IDF Tools Installer has finished successfully, then the development environment setup is complete. Proceed directly to :ref:`get-started-start-project-cmake`. - -Related Documents -================= - -For advanced users who want to customize the install process: - -.. toctree:: - :maxdepth: 1 - - windows-setup-scratch - windows-setup-update - -.. _MSYS2: https://msys2.github.io/ -.. _cmake: https://cmake.org/download/ -.. _ninja: https://ninja-build.org/ -.. _Python: https://www.python.org/downloads/windows/ -.. _Git for Windows: https://gitforwindows.org/ -.. _mconf-idf: https://github.com/espressif/kconfig-frontends/releases/ -.. _Github Desktop: https://desktop.github.com/ diff --git a/docs/en/get-started-legacy/get-started/add-idf_path-to-profile.rst b/docs/en/get-started-legacy/get-started/add-idf_path-to-profile.rst new file mode 100644 index 0000000000..8ce9a9ae6f --- /dev/null +++ b/docs/en/get-started-legacy/get-started/add-idf_path-to-profile.rst @@ -0,0 +1,65 @@ +Add IDF_PATH to User Profile +============================ +:link_to_translation:`zh_CN:[中文]` + +To preserve setting of ``IDF_PATH`` environment variable between system restarts, add it to the user profile, following instructions below. + + +.. _add-idf_path-to-profile-windows: + +Windows +------- + +The user profile scripts are contained in ``C:/msys32/etc/profile.d/`` directory. They are executed every time you open an MSYS2 window. + +#. Create a new script file in ``C:/msys32/etc/profile.d/`` directory. Name it ``export_idf_path.sh``. + +#. Identify the path to ESP-IDF directory. It is specific to your system configuration and may look something like ``C:\msys32\home\user-name\esp\esp-idf`` + +#. Add the ``export`` command to the script file, e.g.:: + + export IDF_PATH="C:/msys32/home/user-name/esp/esp-idf" + + Remember to replace back-slashes with forward-slashes in the original Windows path. + +#. Save the script file. + +#. Close MSYS2 window and open it again. Check if ``IDF_PATH`` is set, by typing:: + + printenv IDF_PATH + + The path previusly entered in the script file should be printed out. + +If you do not like to have ``IDF_PATH`` set up permanently in user profile, you should enter it manually on opening of an MSYS2 window:: + + export IDF_PATH="C:/msys32/home/user-name/esp/esp-idf" + +If you got here from section :ref:`get-started-setup-path`, while installing s/w for ESP32 development, then go back to section :ref:`get-started-start-project`. + + +.. _add-idf_path-to-profile-linux-macos: + +Linux and MacOS +--------------- + +Set up ``IDF_PATH`` by adding the following line to ``~/.profile`` file:: + + export IDF_PATH=~/esp/esp-idf + +Log off and log in back to make this change effective. + +.. note:: + + If you have ``/bin/bash`` set as login shell, and both ``.bash_profile`` and ``.profile`` exist, then update ``.bash_profile`` instead. + +Run the following command to check if ``IDF_PATH`` is set:: + + printenv IDF_PATH + +The path previously entered in ``~/.profile`` file (or set manually) should be printed out. + +If you do not like to have ``IDF_PATH`` set up permanently, you should enter it manually in terminal window on each restart or logout:: + + export IDF_PATH=~/esp/esp-idf + +If you got here from section :ref:`get-started-setup-path`, while installing s/w for ESP32 development, then go back to section :ref:`get-started-start-project`. diff --git a/docs/en/get-started-legacy/get-started/eclipse-setup.rst b/docs/en/get-started-legacy/get-started/eclipse-setup.rst new file mode 100644 index 0000000000..d03494ddd7 --- /dev/null +++ b/docs/en/get-started-legacy/get-started/eclipse-setup.rst @@ -0,0 +1,109 @@ +******************************** +Build and Flash with Eclipse IDE +******************************** +:link_to_translation:`zh_CN:[中文]` + +.. _eclipse-install-steps: + +Installing Eclipse IDE +====================== + +The Eclipse IDE gives you a graphical integrated development environment for writing, compiling and debugging ESP-IDF projects. + +* Start by installing the esp-idf for your platform (see files in this directory with steps for Windows, OS X, Linux). + +* We suggest building a project from the command line first, to get a feel for how that process works. You also need to use the command line to configure your esp-idf project (via ``make menuconfig``), this is not currently supported inside Eclipse. + +* Download the Eclipse Installer for your platform from eclipse.org_. + +* When running the Eclipse Installer, choose "Eclipse for C/C++ Development" (in other places you'll see this referred to as CDT.) + +Setting up Eclipse +================== + +Once your new Eclipse installation launches, follow these steps: + +Import New Project +------------------ + +* Eclipse makes use of the Makefile support in ESP-IDF. This means you need to start by creating an ESP-IDF project. You can use the idf-template project from github, or open one of the examples in the esp-idf examples subdirectory. + +* Once Eclipse is running, choose File -> Import... + +* In the dialog that pops up, choose "C/C++" -> "Existing Code as Makefile Project" and click Next. + +* On the next page, enter "Existing Code Location" to be the directory of your IDF project. Don't specify the path to the ESP-IDF directory itself (that comes later). The directory you specify should contain a file named "Makefile" (the project Makefile). + +* On the same page, under "Toolchain for Indexer Settings" choose "Cross GCC". Then click Finish. + + +Project Properties +------------------ + +* The new project will appear under Project Explorer. Right-click the project and choose Properties from the context menu. + +* Click on the "Environment" properties page under "C/C++ Build". Click "Add..." and enter name ``BATCH_BUILD`` and value ``1``. + +* Click "Add..." again, and enter name ``IDF_PATH``. The value should be the full path where ESP-IDF is installed. Windows users can copy the ``IDF_PATH`` from windows explorer. + +* Edit the ``PATH`` environment variable. Keep the current value, and append the path to the Xtensa toolchain installed as part of IDF setup, if this is not already listed on the PATH. A typical path to the toolchain looks like ``/home/user-name/esp/xtensa-esp32-elf/bin``. Note that you need to add a colon ``:`` before the appended path. Windows users will need to prepend ``C:\msys32\mingw32\bin;C:\msys32\opt\xtensa-esp32-elf\bin;C:\msys32\usr\bin`` to ``PATH`` environment variable (If you installed msys32 to a different directory then you’ll need to change these paths to match). + +* On macOS, add a ``PYTHONPATH`` environment variable and set it to ``/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages``. This is so that the system Python, which has pyserial installed as part of the setup steps, overrides any built-in Eclipse Python. + +**ADDITIONAL NOTE**: If either the IDF_PATH directory or the project directory is located outside ``C:\msys32\home`` directory, you will have to give custom build command in C/C++ Build properties as: ``python ${IDF_PATH}/tools/windows/eclipse_make.py`` (Please note that the build time may get significantly increased by this method.) + +Navigate to "C/C++ General" -> "Preprocessor Include Paths" property page: + +* Click the "Providers" tab + +* In the list of providers, click "CDT Cross GCC Built-in Compiler Settings". Change "Command to get compiler specs" to ``xtensa-esp32-elf-gcc ${FLAGS} -std=c++11 -E -P -v -dD "${INPUTS}"``. + +* In the list of providers, click "CDT GCC Build Output Parser" and change the "Compiler command pattern" to ``xtensa-esp32-elf-(gcc|g\+\+|c\+\+|cc|cpp|clang)`` + +Navigate to "C/C++ General" -> "Indexer" property page: + +* Check "Enable project specific settings" to enable the rest of the settings on this page. + +* Uncheck "Allow heuristic resolution of includes". When this option is enabled Eclipse sometimes fails to find correct header directories. + +Navigate to "C/C++ Build" -> "Behavior" property page: + +* Check "Enable parallel build" to enable multiple build jobs in parallel. + +.. _eclipse-build-project: + +Building in Eclipse +------------------- + +Before your project is first built, Eclipse may show a lot of errors and warnings about undefined values. This is because some source files are automatically generated as part of the esp-idf build process. These errors and warnings will go away after you build the project. + +* Click OK to close the Properties dialog in Eclipse. + +* Outside Eclipse, open a command line prompt. Navigate to your project directory, and run ``make menuconfig`` to configure your project's esp-idf settings. This step currently has to be run outside Eclipse. + +*If you try to build without running a configuration step first, esp-idf will prompt for configuration on the command line - but Eclipse is not able to deal with this, so the build will hang or fail.* + +* Back in Eclipse, choose Project -> Build to build your project. + +**TIP**: If your project had already been built outside Eclipse, you may need to do a Project -> Clean before choosing Project -> Build. This is so Eclipse can see the compiler arguments for all source files. It uses these to determine the header include paths. + +Flash from Eclipse +------------------ + +You can integrate the "make flash" target into your Eclipse project to flash using esptool.py from the Eclipse UI: + +* Right-click your project in Project Explorer (important to make sure you select the project, not a directory in the project, or Eclipse may find the wrong Makefile.) + +* Select Build Targets -> Create... from the context menu. + +* Type "flash" as the target name. Leave the other options as their defaults. + +* Now you can use Project -> Build Target -> Build (Shift+F9) to build the custom flash target, which will compile and flash the project. + +Note that you will need to use "make menuconfig" to set the serial port and other config options for flashing. "make menuconfig" still requires a command line terminal (see the instructions for your platform.) + +Follow the same steps to add ``bootloader`` and ``partition_table`` targets, if necessary. + + +.. _eclipse.org: https://www.eclipse.org/ + diff --git a/docs/en/get-started-cmake/establish-serial-connection.rst b/docs/en/get-started-legacy/get-started/establish-serial-connection.rst similarity index 84% rename from docs/en/get-started-cmake/establish-serial-connection.rst rename to docs/en/get-started-legacy/get-started/establish-serial-connection.rst index a02e04c88b..7e0e3a91e1 100644 --- a/docs/en/get-started-cmake/establish-serial-connection.rst +++ b/docs/en/get-started-legacy/get-started/establish-serial-connection.rst @@ -1,6 +1,5 @@ -Establish Serial Connection with ESP32 (CMake) -============================================== - +Establish Serial Connection with ESP32 +====================================== :link_to_translation:`zh_CN:[中文]` This section provides guidance how to establish serial connection between ESP32 and PC. @@ -11,7 +10,7 @@ Connect ESP32 to PC Connect the ESP32 board to the PC using the USB cable. If device driver does not install automatically, identify USB to serial converter chip on your ESP32 board (or external converter dongle), search for drivers in internet and install them. -Below are the links to drivers for ESP32 boards produced by Espressif: +Below are the links to drivers for ESP32 and other boards produced by Espressif: .. csv-table:: @@ -73,12 +72,8 @@ MacOS :: ls /dev/cu.* -.. note:: - MacOS users: if you don't see the serial port then check you have the USB/serial drivers installed as shown in the Getting Started guide for your particular development board. For MacOS High Sierra (10.13), you may also have to explicitly allow the drivers to load. Open System Preferences -> Security & Privacy -> General and check if there is a message shown here about "System Software from developer ..." where the developer name is Silicon Labs or FTDI. - - -.. _linux-dialout-group-cmake: +.. _linux-dialout-group: Adding user to ``dialout`` on Linux ----------------------------------- @@ -141,7 +136,7 @@ Then open serial port in terminal and check, if you see any log printed out by E ... -If you can see readable log output, it means serial connection is working and you are ready to proceed with installation and finally upload of application to ESP32. +If you see some legible log, it means serial connection is working and you are ready to proceed with installation and finally upload of application to ESP32. .. note:: @@ -149,8 +144,9 @@ If you can see readable log output, it means serial connection is working and yo .. note:: - Close serial terminal after verification that communication is working. In the next step we are going to use a different application to upload a new firmware to ESP32. This application will not be able to access serial port while it is open in terminal. + Close serial terminal after verification that communication is working. In next step we are going to use another application to upload ESP32. This application will not be able to access serial port while it is open in terminal. + +If you got here from section :ref:`get-started-connect` when installing s/w for ESP32 development, then go back to section :ref:`get-started-configure`. -If you got here from :ref:`get-started-connect-cmake` when installing s/w for ESP32 development, then you can continue with :ref:`get-started-configure-cmake`. .. _esptool documentation: https://github.com/espressif/esptool/wiki/ESP32-Boot-Mode-Selection#automatic-bootloader diff --git a/docs/en/get-started-legacy/get-started/index.rst b/docs/en/get-started-legacy/get-started/index.rst new file mode 100644 index 0000000000..12ab81c020 --- /dev/null +++ b/docs/en/get-started-legacy/get-started/index.rst @@ -0,0 +1,452 @@ +*********** +Get Started +*********** + +:link_to_translation:`zh_CN:[中文]` + +This document is intended to help you set up the software development environment for the hardware based on Espressif ESP32. + +After that, a simple example will show you how to use ESP-IDF (Espressif IoT Development Framework) for menu configuration, then how to build and flash firmware onto an ESP32 board. + +.. include:: /_build/inc/version-note.inc + +Introduction +============ + +ESP32 is a system on a chip that integrates the following features: + +* Wi-Fi (2.4 GHz band) +* Bluetooth 4.2 +* Dual high performance cores +* Ultra Low Power co-processor +* Several peripherals + +Powered by 40 nm technology, ESP32 provides a robust, highly integrated platform, which helps meet the continuous demands for efficient power usage, compact design, security, high performance, and reliability. + +Espressif provides basic hardware and software resources to help application developers realize their ideas using the ESP32 series hardware. The software development framework by Espressif is intended for development of Internet-of-Things (IoT) applications with Wi-Fi, Bluetooth, power management and several other system features. + +What You Need +============= + +Hardware: + +* An **ESP32** board +* **USB cable** - USB A / micro USB B +* **Computer** running Windows, Linux, or macOS + +Software: + +* **Toolchain** to build the **Application** for ESP32 +* **ESP-IDF** that essentially contains API (software libraries and source code) for ESP32 and scripts to operate the **Toolchain** +* **Text editor** to write programs (**Projects**) in C, e.g., `Eclipse `_ + + +.. figure:: ../../_static/what-you-need.png + :align: center + :alt: Development of applications for ESP32 + :figclass: align-center + + Development of applications for ESP32 + + +Development Board Overviews +=========================== + +If you have one of ESP32 development boards listed below, you can click on the link to learn more about its hardware. + +.. toctree:: + :maxdepth: 1 + + ESP32-DevKitC + ESP-WROVER-KIT + ESP32-PICO-KIT + ESP32-Ethernet-Kit <../hw-reference/get-started-ethernet-kit> + + +.. _get-started-step-by-step: + +Installation Step by Step +========================= + +This is a detailed roadmap to walk you through the installation process. + +Setting up Development Environment +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* :ref:`get-started-setup-toolchain` for :doc:`Windows `, :doc:`Linux ` or :doc:`MacOS ` +* :ref:`get-started-get-esp-idf` +* :ref:`get-started-setup-path` +* :ref:`get-started-get-packages` + +Creating Your First Project +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* :ref:`get-started-start-project` +* :ref:`get-started-connect` +* :ref:`get-started-configure` +* :ref:`get-started-build-and-flash` +* :ref:`get-started-monitor` + + +.. _get-started-setup-toolchain: + +Step 1. Set up the Toolchain +============================ + +The toolchain is a set of programs for compiling code and building applications. + +The quickest way to start development with ESP32 is by installing a prebuilt toolchain. Pick up your OS below and follow the provided instructions. + +.. toctree:: + :hidden: + + Windows + Linux + MacOS + ++-------------------+-------------------+-------------------+ +| |windows-logo| | |linux-logo| | |macos-logo| | ++-------------------+-------------------+-------------------+ +| `Windows`_ | `Linux`_ | `Mac OS`_ | ++-------------------+-------------------+-------------------+ + +.. |windows-logo| image:: ../../_static/windows-logo.png + :target: ../get-started/windows-setup.html + +.. |linux-logo| image:: ../../_static/linux-logo.png + :target: ../get-started/linux-setup.html + +.. |macos-logo| image:: ../../_static/macos-logo.png + :target: ../get-started/macos-setup.html + +.. _Windows: ../get-started/windows-setup.html +.. _Linux: ../get-started/linux-setup.html +.. _Mac OS: ../get-started/macos-setup.html + +.. note:: + + This guide uses the directory ``~/esp`` on Linux and macOS or ``%userprofile%\esp`` on Windows as an installation folder for ESP-IDF. You can use any directory, but you will need to adjust paths for the commands respectively. Keep in mind that ESP-IDF does not support spaces in paths. + +Depending on your experience and preferences, you may want to customize your environment instead of using a prebuilt toolchain. To set up the system your own way go to Section :ref:`get-started-customized-setup`. + + +.. _get-started-get-esp-idf: + +Step 2. Get ESP-IDF +=================== + +Besides the toolchain, you also need ESP32-specific API (software libraries and source code). They are provided by Espressif in `ESP-IDF repository `_. + +To get a local copy of ESP-IDF, navigate to your installation directory and clone the repository with ``git clone``. + +Open Terminal, and run the following commands: + +.. include:: /_build/inc/git-clone-bash.inc + +ESP-IDF will be downloaded into ``~/esp/esp-idf``. + +Consult :doc:`/versions` for information about which ESP-IDF version to use in a given situation. + +.. include:: /_build/inc/git-clone-notes.inc + +.. note:: + + Do not miss the ``--recursive`` option. If you have already cloned ESP-IDF without this option, run another command to get all the submodules:: + + cd esp-idf + git submodule update --init + + +.. _get-started-setup-path: + +Step 3. Set Environment Variables +================================= + +The toolchain uses the environment variable ``IDF_PATH`` to access the ESP-IDF directory. This variable should be set up on your computer, otherwise projects will not build. + +These variables can be set temporarily (per session) or permanently. Please follow the instructions specific to :ref:`Windows ` , :ref:`Linux and MacOS ` in Section :doc:`add-idf_path-to-profile`. + + +.. _get-started-get-packages: + +Step 4. Install the Required Python Packages +============================================ + +The python packages required by ESP-IDF are located in ``IDF_PATH/requirements.txt``. You can install them by running:: + + python -m pip install --user -r $IDF_PATH/requirements.txt + +.. note:: + + Please check the version of the Python interpreter that you will be using with ESP-IDF. For this, run + the command ``python --version`` and depending on the result, you might want to use ``python2``, ``python2.7`` + or similar instead of just ``python``, e.g.:: + + python2.7 -m pip install --user -r $IDF_PATH/requirements.txt + + +.. _get-started-start-project: + +Step 5. Start a Project +======================= + +Now you are ready to prepare your application for ESP32. You can start with :example:`get-started/hello_world` project from :idf:`examples` directory in IDF. + +Copy :example:`get-started/hello_world` to the ``~/esp`` directory: + +Linux and MacOS +~~~~~~~~~~~~~~~ + +.. code-block:: bash + + cd ~/esp + cp -r $IDF_PATH/examples/get-started/hello_world . + +Windows +~~~~~~~ + +.. code-block:: batch + + cd %userprofile%\esp + xcopy /e /i %IDF_PATH%\examples\get-started\hello_world hello_world + +There is a range of example projects in the :idf:`examples` directory in ESP-IDF. You can copy any project in the same way as presented above and run it. + +It is also possible to build examples in-place, without copying them first. + +.. important:: + + The esp-idf build system does not support spaces in the paths to either esp-idf or to projects. + +.. _get-started-connect: + +Step 6. Connect Your Device +=========================== + +Now connect your ESP32 board to the computer and check under what serial port the board is visible. + +Serial ports have the following patterns in their names: + +- **Windows**: names like ``COM1`` +- **Linux**: starting with ``/dev/tty`` +- **macOS**: starting with ``/dev/cu.`` + +If you are not sure how to check the serial port name, please refer to :doc:`establish-serial-connection` for full details. + +.. note:: + + Keep the port name handy as you will need it in the next steps. + + +.. _get-started-configure: + +Step 7. Configure +================= + +Navigate to your ``hello_world`` directory from :ref:`get-started-start-project` and run the project configuration utility ``menuconfig``. + +Linux and MacOS +~~~~~~~~~~~~~~~ + +.. code-block:: bash + + cd ~/esp/hello_world + make menuconfig + +Windows +~~~~~~~ + +.. code-block:: batch + + cd %userprofile%\esp\hello_world + make menuconfig + +If the previous steps have been done correctly, the following menu appears: + +.. figure:: ../../_static/project-configuration.png + :align: center + :alt: Project configuration - Home window + :figclass: align-center + + Project configuration - Home window + +In the menu, navigate to ``Serial flasher config`` > ``Default serial port`` to configure the serial port, where project will be loaded to. Confirm selection by pressing enter, save configuration by selecting ``< Save >`` and then exit ``menuconfig`` by selecting ``< Exit >``. + +To navigate and use ``menuconfig``, press the following keys: + +* Arrow keys for navigation +* ``Enter`` to go into a submenu +* ``Esc`` to go up one level or exit +* ``?`` to see a help screen. Enter key exits the help screen +* ``Space``, or ``Y`` and ``N`` keys to enable (Yes) and disable (No) configuration items with checkboxes "``[*]``" +* ``?`` while highlighting a configuration item to display help about that item +* ``/`` to find configuration items + +.. note:: + + If you are **Arch Linux** user, navigate to ``SDK tool configuration`` and change the name of ``Python 2 interpreter`` from ``python`` to ``python2``. + +.. attention:: + + If you use ESP32-DevKitC board with the **ESP32-SOLO-1** module, enable single core mode (:ref:`CONFIG_FREERTOS_UNICORE`) in menuconfig before flashing examples. + +.. _get-started-build-and-flash: + +Step 8. Build and Flash +======================= + +Build and flash the project by running:: + + make flash + +This command will compile the application and all ESP-IDF components, then it will generate the bootloader, partition table, and application binaries. After that, these binaries will be flashed onto your ESP32 board. + +If there are no issues by the end of the flash process, you will see messages (below) describing progress of the loading process. Then the board will be reset and the "hello_world" application will start up. + +.. highlight:: none + +:: + + esptool.py v2.0-beta2 + Flashing binaries to serial port /dev/ttyUSB0 (app at offset 0x10000)... + esptool.py v2.0-beta2 + Connecting........___ + Uploading stub... + Running stub... + Stub running... + Changing baud rate to 921600 + Changed. + Attaching SPI flash... + Configuring flash size... + Auto-detected Flash size: 4MB + Flash params set to 0x0220 + Compressed 11616 bytes to 6695... + Wrote 11616 bytes (6695 compressed) at 0x00001000 in 0.1 seconds (effective 920.5 kbit/s)... + Hash of data verified. + Compressed 408096 bytes to 171625... + Wrote 408096 bytes (171625 compressed) at 0x00010000 in 3.9 seconds (effective 847.3 kbit/s)... + Hash of data verified. + Compressed 3072 bytes to 82... + Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 8297.4 kbit/s)... + Hash of data verified. + + Leaving... + Hard resetting... + + +If you'd like to use the Eclipse IDE instead of running ``make``, check out the :doc:`Eclipse guide `. + + +.. _get-started-monitor: + +Step 9. Monitor +=============== + +To check if "hello_world" is indeed running, type ``make monitor``. + +This command launches the :doc:`IDF Monitor <../api-guides/tools/idf-monitor>` application:: + + $ make monitor + MONITOR + --- idf_monitor on /dev/ttyUSB0 115200 --- + --- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- + ets Jun 8 2016 00:22:57 + + rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + ets Jun 8 2016 00:22:57 + ... + +After startup and diagnostic logs scroll up, you should see "Hello world!" printed out by the application. + +.. code-block:: none + + ... + Hello world! + Restarting in 10 seconds... + I (211) cpu_start: Starting scheduler on APP CPU. + Restarting in 9 seconds... + Restarting in 8 seconds... + Restarting in 7 seconds... + +To exit IDF monitor use the shortcut ``Ctrl+]``. + +If IDF monitor fails shortly after the upload, or if instead of the messages above you see a random garbage similar to what is given below, your board is likely using a 26MHz crystal. Most development board designs use 40MHz, so ESP-IDF uses this frequency as a default value. + +.. code-block:: none + + e���)(Xn@�y.!��(�PW+)��Hn9a؅/9�!�t5��P�~�k��e�ea�5�jA + ~zY��Y(1�,1�� e���)(Xn@�y.!Dr�zY(�jpi�|�+z5Ymvp + +If you have such a problem, do the following: + +1. Exit the monitor. +2. Go back to :ref:`menuconfig `. +3. Go to Component config --> ESP32-specific --> Main XTAL frequency, then change :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` to 26MHz. +4. After that, :ref:`build and flash ` the application again. + +.. note:: + + You can combine building, flashing and monitoring into one step by running:: + + make flash monitor + +See also :doc:`IDF Monitor <../api-guides/tools/idf-monitor>` for handy shortcuts and more details on using IDF monitor. + +**That's all that you need to get started with ESP32!** + +Now you are ready to try some other :idf:`examples`, or go straight to developing your own applications. + + +Environment Variables +===================== + +Some environment variables can be specified whilst calling ``make`` allowing users to **override arguments without the need to reconfigure them using** ``make menuconfig``. + ++-----------------+--------------------------------------------------------------+ +| Variables | Description & Usage | ++=================+==============================================================+ +| ``ESPPORT`` | Overrides the serial port used in ``flash`` and ``monitor``. | +| | | +| | Examples: ``make flash ESPPORT=/dev/ttyUSB1``, | +| | ``make monitor ESPPORT=COM1`` | ++-----------------+--------------------------------------------------------------+ +| ``ESPBAUD`` | Overrides the serial baud rate when flashing the ESP32. | +| | | +| | Example: ``make flash ESPBAUD=9600`` | ++-----------------+--------------------------------------------------------------+ +| ``MONITORBAUD`` | Overrides the serial baud rate used when monitoring. | +| | | +| | Example: ``make monitor MONITORBAUD=9600`` | ++-----------------+--------------------------------------------------------------+ + +.. note:: + + You can export environment variables (e.g. ``export ESPPORT=/dev/ttyUSB1``). + All subsequent calls of ``make`` within the same terminal session will use + the exported value given that the variable is not simultaneously overridden. + + +Updating ESP-IDF +================ + +You should update ESP-IDF from time to time, as newer versions fix bugs and provide new features. The simplest way to do the update is to delete the existing ``esp-idf`` folder and clone it again, as if performing the initial installation described in :ref:`get-started-get-esp-idf`. + +If downloading to a new path, remember to :doc:`add-idf_path-to-profile` so that the toolchain scripts can find ESP-IDF in its release specific location. + +Another solution is to update only what has changed. :ref:`The update procedure depends on the version of ESP-IDF you are using `. + +Related Documents +================= + +.. toctree:: + :maxdepth: 1 + + add-idf_path-to-profile + establish-serial-connection + make-project + eclipse-setup + ../api-guides/tools/idf-monitor + toolchain-setup-scratch + +.. _Stable version: https://docs.espressif.com/projects/esp-idf/en/stable/ +.. _Releases page: https://github.com/espressif/esp-idf/releases diff --git a/docs/en/get-started-legacy/get-started/linux-setup-scratch.rst b/docs/en/get-started-legacy/get-started/linux-setup-scratch.rst new file mode 100644 index 0000000000..395458153f --- /dev/null +++ b/docs/en/get-started-legacy/get-started/linux-setup-scratch.rst @@ -0,0 +1,75 @@ +********************************** +Setup Linux Toolchain from Scratch +********************************** +:link_to_translation:`zh_CN:[中文]` + +.. note:: + + Standard process for installing the toolchain is described :doc:`here `. See :ref:`Customized Setup of Toolchain ` section for some of the reasons why installing the toolchain from scratch may be necessary. + +Install Prerequisites +===================== + +To compile with ESP-IDF you need to get the following packages: + +- Ubuntu and Debian:: + + sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing python-pyelftools + +- Arch:: + + sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing python2-pyelftools + +.. note:: + + Some older (pre-2014) Linux distributions may use ``pyserial`` version 2.x which is not supported by ESP-IDF. + In this case please install a supported version via ``pip`` as it is described in section + :ref:`get-started-get-packages`. + +Compile the Toolchain from Source +================================= + +- Install dependencies: + + - CentOS 7:: + + sudo yum install gawk gperf grep gettext ncurses-devel python python-devel automake bison flex texinfo help2man libtool + + - Ubuntu pre-16.04:: + + sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool + + - Ubuntu 16.04 or newer:: + + sudo apt-get install gawk gperf grep gettext python python-dev automake bison flex texinfo help2man libtool libtool-bin + + - Debian 9:: + + sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool libtool-bin + + - Arch:: + + TODO + +Create the working directory and go into it:: + + mkdir -p ~/esp + cd ~/esp + +Download ``crosstool-NG`` and build it: + +.. include:: /_build/inc/scratch-build-code.inc + +Build the toolchain:: + + ./ct-ng xtensa-esp32-elf + ./ct-ng build + chmod -R u+w builds/xtensa-esp32-elf + +Toolchain will be built in ``~/esp/crosstool-NG/builds/xtensa-esp32-elf``. Follow :ref:`instructions for standard setup ` to add the toolchain to your ``PATH``. + + +Next Steps +========== + +To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf`. diff --git a/docs/en/get-started-legacy/get-started/linux-setup.rst b/docs/en/get-started-legacy/get-started/linux-setup.rst new file mode 100644 index 0000000000..7484b4c624 --- /dev/null +++ b/docs/en/get-started-legacy/get-started/linux-setup.rst @@ -0,0 +1,118 @@ +************************************* +Standard Setup of Toolchain for Linux +************************************* +:link_to_translation:`zh_CN:[中文]` + +Install Prerequisites +===================== + +To compile with ESP-IDF you need to get the following packages: + +- CentOS 7:: + + sudo yum install gcc git wget make ncurses-devel flex bison gperf python python2-cryptography + +- Ubuntu and Debian:: + + sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing python-pyelftools + +- Arch:: + + sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing python2-pyelftools + +.. note:: + + Some older Linux distributions may be missing some of the Python packages listed above (or may use ``pyserial`` version 2.x which is not supported by ESP-IDF). It is possible to install these packages via ``pip`` instead - as described in section :ref:`get-started-get-packages`. + +Toolchain Setup +=============== + +.. include:: /_build/inc/download-links.inc + +ESP32 toolchain for Linux is available for download from Espressif website: + +- for 64-bit Linux: + + |download_link_linux64| + +- for 32-bit Linux: + + |download_link_linux32| + +1. Download this file, then extract it in ``~/esp`` directory: + + - for 64-bit Linux: + + .. include:: /_build/inc/unpack-code-linux64.inc + + - for 32-bit Linux: + + .. include:: /_build/inc/unpack-code-linux32.inc + +.. _setup-linux-toolchain-add-it-to-path: + +2. The toolchain will be extracted into ``~/esp/xtensa-esp32-elf/`` directory. + + To use it, you will need to update your ``PATH`` environment variable in ``~/.profile`` file. To make ``xtensa-esp32-elf`` available for all terminal sessions, add the following line to your ``~/.profile`` file:: + + export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH" + + Alternatively, you may create an alias for the above command. This way you can get the toolchain only when you need it. To do this, add different line to your ``~/.profile`` file:: + + alias get_esp32='export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH"' + + Then when you need the toolchain you can type ``get_esp32`` on the command line and the toolchain will be added to your ``PATH``. + + .. note:: + + If you have ``/bin/bash`` set as login shell, and both ``.bash_profile`` and ``.profile`` exist, then update ``.bash_profile`` instead. In CentOS, ``alias`` should set in ``.bashrc``. + +3. Log off and log in back to make the ``.profile`` changes effective. Run the following command to verify if ``PATH`` is correctly set:: + + printenv PATH + + You are looking for similar result containing toolchain's path at the beginning of displayed string:: + + $ printenv PATH + /home/user-name/esp/xtensa-esp32-elf/bin:/home/user-name/bin:/home/user-name/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin + + Instead of ``/home/user-name`` there should be a home path specific to your installation. + + +Permission issues /dev/ttyUSB0 +------------------------------ + +With some Linux distributions you may get the ``Failed to open port /dev/ttyUSB0`` error message when flashing the ESP32. :ref:`This can be solved by adding the current user to the dialout group`. + + +Arch Linux Users +---------------- + +To run the precompiled gdb (xtensa-esp32-elf-gdb) in Arch Linux requires ncurses 5, but Arch uses ncurses 6. + +Backwards compatibility libraries are available in AUR_ for native and lib32 configurations: + +- https://aur.archlinux.org/packages/ncurses5-compat-libs/ +- https://aur.archlinux.org/packages/lib32-ncurses5-compat-libs/ + +Before installing these packages you might need to add the author's public key to your keyring as described in the "Comments" section at the links above. + +Alternatively, use crosstool-NG to compile a gdb that links against ncurses 6. + + +Next Steps +========== + +To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf`. + + +Related Documents +================= + +.. toctree:: + :maxdepth: 1 + + linux-setup-scratch + + +.. _AUR: https://wiki.archlinux.org/index.php/Arch_User_Repository diff --git a/docs/en/get-started-legacy/get-started/macos-setup-scratch.rst b/docs/en/get-started-legacy/get-started/macos-setup-scratch.rst new file mode 100644 index 0000000000..a4dfe9d7f1 --- /dev/null +++ b/docs/en/get-started-legacy/get-started/macos-setup-scratch.rst @@ -0,0 +1,72 @@ +*************************************** +Setup Toolchain for Mac OS from Scratch +*************************************** +:link_to_translation:`zh_CN:[中文]` + +.. note:: + + Standard process for installing the toolchain is described :doc:`here `. See :ref:`Customized Setup of Toolchain ` section for some of the reasons why installing the toolchain from scratch may be necessary. + +Install Prerequisites +===================== + +- install pip:: + + sudo easy_install pip + +.. note:: + + ``pip`` will be used later for installing :ref:`the required Python packages `. + +Compile the Toolchain from Source +================================= + +- Install dependencies: + + - Install either MacPorts_ or homebrew_ package manager. MacPorts needs a full XCode installation, while homebrew only needs XCode command line tools. + + .. _homebrew: https://brew.sh/ + .. _MacPorts: https://www.macports.org/install.php + + - with MacPorts:: + + sudo port install gsed gawk binutils gperf grep gettext wget libtool autoconf automake + + - with homebrew:: + + brew install gnu-sed gawk binutils gperftools gettext wget help2man libtool autoconf automake + +Create a case-sensitive filesystem image:: + + hdiutil create ~/esp/crosstool.dmg -volname "ctng" -size 10g -fs "Case-sensitive HFS+" + +Mount it:: + + hdiutil mount ~/esp/crosstool.dmg + +Create a symlink to your work directory:: + + mkdir -p ~/esp + ln -s /Volumes/ctng ~/esp/ctng-volume + +Go into the newly created directory:: + + cd ~/esp/ctng-volume + +Download ``crosstool-NG`` and build it: + +.. include:: /_build/inc/scratch-build-code.inc + +Build the toolchain:: + + ./ct-ng xtensa-esp32-elf + ./ct-ng build + chmod -R u+w builds/xtensa-esp32-elf + +Toolchain will be built in ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf``. Follow :ref:`instructions for standard setup ` to add the toolchain to your ``PATH``. + + +Next Steps +========== + +To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf`. diff --git a/docs/en/get-started-legacy/get-started/macos-setup.rst b/docs/en/get-started-legacy/get-started/macos-setup.rst new file mode 100644 index 0000000000..7e1921a6c3 --- /dev/null +++ b/docs/en/get-started-legacy/get-started/macos-setup.rst @@ -0,0 +1,57 @@ +************************************** +Standard Setup of Toolchain for Mac OS +************************************** +:link_to_translation:`zh_CN:[中文]` + +Install Prerequisites +===================== + +- install pip:: + + sudo easy_install pip + +.. note:: + + ``pip`` will be used later for installing :ref:`the required Python packages `. + +Toolchain Setup +=============== + +.. include:: /_build/inc/download-links.inc + +ESP32 toolchain for macOS is available for download from Espressif website: + +|download_link_osx| + +Download this file, then extract it in ``~/esp`` directory: + +.. include:: /_build/inc/unpack-code-osx.inc + +.. _setup-macos-toolchain-add-it-to-path: + +The toolchain will be extracted into ``~/esp/xtensa-esp32-elf/`` directory. + +To use it, you will need to update your ``PATH`` environment variable in ``~/.profile`` file. To make ``xtensa-esp32-elf`` available for all terminal sessions, add the following line to your ``~/.profile`` file:: + + export PATH=$HOME/esp/xtensa-esp32-elf/bin:$PATH + +Alternatively, you may create an alias for the above command. This way you can get the toolchain only when you need it. To do this, add different line to your ``~/.profile`` file:: + + alias get_esp32="export PATH=$HOME/esp/xtensa-esp32-elf/bin:$PATH" + +Then when you need the toolchain you can type ``get_esp32`` on the command line and the toolchain will be added to your ``PATH``. + + +Next Steps +========== + +To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf`. + + +Related Documents +================= + +.. toctree:: + :maxdepth: 1 + + macos-setup-scratch diff --git a/docs/en/get-started/make-project.rst b/docs/en/get-started-legacy/get-started/make-project.rst similarity index 100% rename from docs/en/get-started/make-project.rst rename to docs/en/get-started-legacy/get-started/make-project.rst diff --git a/docs/en/get-started-cmake/toolchain-setup-scratch.rst b/docs/en/get-started-legacy/get-started/toolchain-setup-scratch.rst similarity index 72% rename from docs/en/get-started-cmake/toolchain-setup-scratch.rst rename to docs/en/get-started-legacy/get-started/toolchain-setup-scratch.rst index c7b0ee32d5..c5f2b5ae4a 100644 --- a/docs/en/get-started-cmake/toolchain-setup-scratch.rst +++ b/docs/en/get-started-legacy/get-started/toolchain-setup-scratch.rst @@ -1,12 +1,10 @@ -.. _get-started-customized-setup-cmake: +.. _get-started-customized-setup: -************************************* -Customized Setup of Toolchain (CMake) -************************************* +***************************** +Customized Setup of Toolchain +***************************** -:link_to_translation:`zh_CN:[中文]` - -Instead of downloading binary toolchain from Espressif website (see :ref:`get-started-set-up-tools-cmake`) you may build the toolchain yourself. +Instead of downloading binary toolchain from Espressif website (see :ref:`get-started-setup-toolchain`) you may build the toolchain yourself. If you can't think of a reason why you need to build it yourself, then probably it's better to stick with the binary version. However, here are some of the reasons why you might want to compile it from source: diff --git a/docs/en/get-started-legacy/get-started/windows-setup-scratch.rst b/docs/en/get-started-legacy/get-started/windows-setup-scratch.rst new file mode 100644 index 0000000000..fc64e2a233 --- /dev/null +++ b/docs/en/get-started-legacy/get-started/windows-setup-scratch.rst @@ -0,0 +1,117 @@ +************************************ +Setup Windows Toolchain from Scratch +************************************ + +Setting up the environment gives you some more control over the process, and also provides the information for advanced users to customize the install. The :doc:`pre-built environment `, addressed to less experienced users, has been prepared by following these steps. + +To quickly setup the toolchain in standard way, using a prebuilt environment, proceed to section :doc:`windows-setup`. + + +.. _configure-windows-toolchain-from-scratch: + +Configure Toolchain & Environment from Scratch +============================================== + +This process involves installing MSYS2_, then installing the MSYS2_ and Python packages which ESP-IDF uses, and finally downloading and installing the Xtensa toolchain. + +* Navigate to the MSYS2_ installer page and download the ``msys2-i686-xxxxxxx.exe`` installer executable (we only support a 32-bit MSYS environment, it works on both 32-bit and 64-bit Windows.) At time of writing, the latest installer is ``msys2-i686-20161025.exe``. + +* Run through the installer steps. **Uncheck the "Run MSYS2 32-bit now" checkbox at the end.** + +* Once the installer exits, open Start Menu and find "MSYS2 MinGW 32-bit" to run the terminal. + + *(Why launch this different terminal? MSYS2 has the concept of different kinds of environments. The default "MSYS" environment is Cygwin-like and uses a translation layer for all Windows API calls. We need the "MinGW" environment in order to have a native Python which supports COM ports.)* + +* The ESP-IDF repository on github contains a script in the tools directory titled ``windows_install_prerequisites.sh``. If you haven't got a local copy of the ESP-IDF yet, that's OK - you can just download that one file in Raw format from here: :idf_raw:`tools/windows/windows_install_prerequisites.sh`. Save it somewhere on your computer. + +* Type the path to the shell script into the MSYS2 terminal window. You can type it as a normal Windows path, but use forward-slashes instead of back-slashes. ie: ``C:/Users/myuser/Downloads/windows_install_prerequisites.sh``. You can read the script beforehand to check what it does. + +* The ``windows_install_prerequisites.sh`` script will download and install packages for ESP-IDF support, and the ESP32 toolchain. + + +Troubleshooting +~~~~~~~~~~~~~~~ + +* While the install script runs, MSYS may update itself into a state where it can no longer operate. You may see errors like the following:: + + *** fatal error - cygheap base mismatch detected - 0x612E5408/0x612E4408. This problem is probably due to using incompatible versions of the cygwin DLL. + + If you see errors like this, close the terminal window entirely (terminating the processes running there) and then re-open a new terminal. Re-run ``windows_install_prerequisites.sh`` (tip: use the up arrow key to see the last run command). The update process will resume after this step. + +* MSYS2 is a "rolling" distribution so running the installer script may install newer packages than what is used in the prebuilt environments. If you see any errors that appear to be related to installing MSYS2 packages, please check the `MSYS2-packages issues list`_ for known issues. If you don't see any relevant issues, please `raise an IDF issue`_. + + +MSYS2 Mirrors in China +~~~~~~~~~~~~~~~~~~~~~~ + +There are some (unofficial) MSYS2 mirrors inside China, which substantially improves download speeds inside China. + +To add these mirrors, edit the following two MSYS2 mirrorlist files before running the setup script. The mirrorlist files can be found in the ``/etc/pacman.d`` directory (i.e. ``c:\msys2\etc\pacman.d``). + +Add these lines at the top of ``mirrorlist.mingw32``:: + + Server = https://mirrors.ustc.edu.cn/msys2/mingw/i686/ + Server = http://mirror.bit.edu.cn/msys2/REPOS/MINGW/i686 + +Add these lines at the top of ``mirrorlist.msys``:: + + Server = http://mirrors.ustc.edu.cn/msys2/msys/$arch + Server = http://mirror.bit.edu.cn/msys2/REPOS/MSYS2/$arch + + +HTTP Proxy +~~~~~~~~~~ + +You can enable an HTTP proxy for MSYS and PIP downloads by setting the ``http_proxy`` variable in the terminal before running the setup script:: + + export http_proxy='http://http.proxy.server:PORT' + +Or with credentials:: + + export http_proxy='http://user:password@http.proxy.server:PORT' + +Add this line to ``/etc/profile`` in the MSYS directory in order to permanently enable the proxy when using MSYS. + + +Alternative Setup: Just download a toolchain +============================================ + +.. include:: /_build/inc/download-links.inc + +If you already have an MSYS2 install or want to do things differently, you can download just the toolchain here: + +|download_link_win32| + +.. note:: + + If you followed instructions :ref:`configure-windows-toolchain-from-scratch`, you already have the toolchain and you won't need this download. + +.. important:: + + Just having this toolchain is *not enough* to use ESP-IDF on Windows. You will need GNU make, bash, and sed at minimum. The above environments provide all this, plus a host compiler (required for menuconfig support). + + +Next Steps +========== + +To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf`. + +.. _updating-existing-windows-environment: + +Updating The Environment +======================== + +When IDF is updated, sometimes new toolchains are required or new system requirements are added to the Windows MSYS2 environment. + +Rather than setting up a new environment, you can update an existing Windows environment & toolchain: + +- Update IDF to the new version you want to use. +- Run the ``tools/windows/windows_install_prerequisites.sh`` script inside IDF. This will install any new software packages that weren't previously installed, and download and replace the toolchain with the latest version. + +The script to update MSYS2 may also fail with the same errors mentioned under Troubleshooting_. + +If you need to support multiple IDF versions concurrently, you can have different independent MSYS2 environments in different directories. Alternatively you can download multiple toolchains and unzip these to different directories, then use the PATH environment variable to set which one is the default. + +.. _MSYS2: https://msys2.github.io/ +.. _MSYS2-packages issues list: https://github.com/Alexpux/MSYS2-packages/issues/ +.. _raise an IDF issue: https://github.com/espressif/esp-idf/issues/new diff --git a/docs/en/get-started-legacy/get-started/windows-setup.rst b/docs/en/get-started-legacy/get-started/windows-setup.rst new file mode 100644 index 0000000000..d2a2678283 --- /dev/null +++ b/docs/en/get-started-legacy/get-started/windows-setup.rst @@ -0,0 +1,70 @@ +*************************************** +Standard Setup of Toolchain for Windows +*************************************** +:link_to_translation:`zh_CN:[中文]` + +Introduction +============ + +Windows doesn't have a built-in "make" environment, so as well as installing the toolchain you will need a GNU-compatible environment. We use the MSYS2_ environment to provide this. You don't need to use this environment all the time (you can use :doc:`Eclipse ` or some other front-end), but it runs behind the scenes. + + +Toolchain Setup +=============== + +The quick setup is to download the Windows all-in-one toolchain & MSYS2 zip file from dl.espressif.com: + +https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20190611.zip + +Unzip the zip file to ``C:\`` (or some other location, but this guide assumes ``C:\``) and it will create an ``msys32`` directory with a pre-prepared environment. + + +Check it Out +============ + +Open a MSYS2 MINGW32 terminal window by running ``C:\msys32\mingw32.exe``. The environment in this window is a bash shell. Create a directory named ``esp`` that is a default location to develop ESP32 applications. To do so, run the following shell command:: + + mkdir -p ~/esp + +By typing ``cd ~/esp`` you can then move to the newly created directory. If there are no error messages you are done with this step. + +.. figure:: ../../_static/msys2-terminal-window.png + :align: center + :alt: MSYS2 MINGW32 shell window + :figclass: align-center + + MSYS2 MINGW32 shell window + +Use this window in the following steps setting up development environment for ESP32. + + +Next Steps +========== + +To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf`. + +Updating The Environment +======================== + +When IDF is updated, sometimes new toolchains are required or new requirements are added to the Windows MSYS2 environment. To move any data from an old version of the precompiled environment to a new one: + +- Take the old MSYS2 environment (ie ``C:\msys32``) and move/rename it to a different directory (ie ``C:\msys32_old``). +- Download the new precompiled environment using the steps above. +- Unzip the new MSYS2 environment to ``C:\msys32`` (or another location). +- Find the old ``C:\msys32_old\home`` directory and move this into ``C:\msys32``. +- You can now delete the ``C:\msys32_old`` directory if you no longer need it. + +You can have independent different MSYS2 environments on your system, as long as they are in different directories. + +There are :ref:`also steps to update the existing environment without downloading a new one `, although this is more complex. + +Related Documents +================= + +.. toctree:: + :maxdepth: 1 + + windows-setup-scratch + + +.. _MSYS2: https://msys2.github.io/ diff --git a/docs/en/get-started/add-idf_path-to-profile.rst b/docs/en/get-started/add-idf_path-to-profile.rst index 8ce9a9ae6f..cdaf9a5b88 100644 --- a/docs/en/get-started/add-idf_path-to-profile.rst +++ b/docs/en/get-started/add-idf_path-to-profile.rst @@ -1,65 +1,3 @@ -Add IDF_PATH to User Profile -============================ -:link_to_translation:`zh_CN:[中文]` +:orphan: -To preserve setting of ``IDF_PATH`` environment variable between system restarts, add it to the user profile, following instructions below. - - -.. _add-idf_path-to-profile-windows: - -Windows -------- - -The user profile scripts are contained in ``C:/msys32/etc/profile.d/`` directory. They are executed every time you open an MSYS2 window. - -#. Create a new script file in ``C:/msys32/etc/profile.d/`` directory. Name it ``export_idf_path.sh``. - -#. Identify the path to ESP-IDF directory. It is specific to your system configuration and may look something like ``C:\msys32\home\user-name\esp\esp-idf`` - -#. Add the ``export`` command to the script file, e.g.:: - - export IDF_PATH="C:/msys32/home/user-name/esp/esp-idf" - - Remember to replace back-slashes with forward-slashes in the original Windows path. - -#. Save the script file. - -#. Close MSYS2 window and open it again. Check if ``IDF_PATH`` is set, by typing:: - - printenv IDF_PATH - - The path previusly entered in the script file should be printed out. - -If you do not like to have ``IDF_PATH`` set up permanently in user profile, you should enter it manually on opening of an MSYS2 window:: - - export IDF_PATH="C:/msys32/home/user-name/esp/esp-idf" - -If you got here from section :ref:`get-started-setup-path`, while installing s/w for ESP32 development, then go back to section :ref:`get-started-start-project`. - - -.. _add-idf_path-to-profile-linux-macos: - -Linux and MacOS ---------------- - -Set up ``IDF_PATH`` by adding the following line to ``~/.profile`` file:: - - export IDF_PATH=~/esp/esp-idf - -Log off and log in back to make this change effective. - -.. note:: - - If you have ``/bin/bash`` set as login shell, and both ``.bash_profile`` and ``.profile`` exist, then update ``.bash_profile`` instead. - -Run the following command to check if ``IDF_PATH`` is set:: - - printenv IDF_PATH - -The path previously entered in ``~/.profile`` file (or set manually) should be printed out. - -If you do not like to have ``IDF_PATH`` set up permanently, you should enter it manually in terminal window on each restart or logout:: - - export IDF_PATH=~/esp/esp-idf - -If you got here from section :ref:`get-started-setup-path`, while installing s/w for ESP32 development, then go back to section :ref:`get-started-start-project`. +.. Remove this file when the Chinese translation of CMake getting started guide is updated diff --git a/docs/en/get-started/eclipse-setup.rst b/docs/en/get-started/eclipse-setup.rst index d03494ddd7..2e2b105bc2 100644 --- a/docs/en/get-started/eclipse-setup.rst +++ b/docs/en/get-started/eclipse-setup.rst @@ -1,109 +1,12 @@ -******************************** -Build and Flash with Eclipse IDE -******************************** +**************************************** +Build and Flash with Eclipse IDE (CMake) +**************************************** + :link_to_translation:`zh_CN:[中文]` -.. _eclipse-install-steps: - -Installing Eclipse IDE -====================== - -The Eclipse IDE gives you a graphical integrated development environment for writing, compiling and debugging ESP-IDF projects. - -* Start by installing the esp-idf for your platform (see files in this directory with steps for Windows, OS X, Linux). - -* We suggest building a project from the command line first, to get a feel for how that process works. You also need to use the command line to configure your esp-idf project (via ``make menuconfig``), this is not currently supported inside Eclipse. - -* Download the Eclipse Installer for your platform from eclipse.org_. - -* When running the Eclipse Installer, choose "Eclipse for C/C++ Development" (in other places you'll see this referred to as CDT.) - -Setting up Eclipse -================== - -Once your new Eclipse installation launches, follow these steps: - -Import New Project ------------------- - -* Eclipse makes use of the Makefile support in ESP-IDF. This means you need to start by creating an ESP-IDF project. You can use the idf-template project from github, or open one of the examples in the esp-idf examples subdirectory. - -* Once Eclipse is running, choose File -> Import... - -* In the dialog that pops up, choose "C/C++" -> "Existing Code as Makefile Project" and click Next. - -* On the next page, enter "Existing Code Location" to be the directory of your IDF project. Don't specify the path to the ESP-IDF directory itself (that comes later). The directory you specify should contain a file named "Makefile" (the project Makefile). - -* On the same page, under "Toolchain for Indexer Settings" choose "Cross GCC". Then click Finish. - - -Project Properties ------------------- - -* The new project will appear under Project Explorer. Right-click the project and choose Properties from the context menu. - -* Click on the "Environment" properties page under "C/C++ Build". Click "Add..." and enter name ``BATCH_BUILD`` and value ``1``. - -* Click "Add..." again, and enter name ``IDF_PATH``. The value should be the full path where ESP-IDF is installed. Windows users can copy the ``IDF_PATH`` from windows explorer. - -* Edit the ``PATH`` environment variable. Keep the current value, and append the path to the Xtensa toolchain installed as part of IDF setup, if this is not already listed on the PATH. A typical path to the toolchain looks like ``/home/user-name/esp/xtensa-esp32-elf/bin``. Note that you need to add a colon ``:`` before the appended path. Windows users will need to prepend ``C:\msys32\mingw32\bin;C:\msys32\opt\xtensa-esp32-elf\bin;C:\msys32\usr\bin`` to ``PATH`` environment variable (If you installed msys32 to a different directory then you’ll need to change these paths to match). - -* On macOS, add a ``PYTHONPATH`` environment variable and set it to ``/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages``. This is so that the system Python, which has pyserial installed as part of the setup steps, overrides any built-in Eclipse Python. - -**ADDITIONAL NOTE**: If either the IDF_PATH directory or the project directory is located outside ``C:\msys32\home`` directory, you will have to give custom build command in C/C++ Build properties as: ``python ${IDF_PATH}/tools/windows/eclipse_make.py`` (Please note that the build time may get significantly increased by this method.) - -Navigate to "C/C++ General" -> "Preprocessor Include Paths" property page: - -* Click the "Providers" tab - -* In the list of providers, click "CDT Cross GCC Built-in Compiler Settings". Change "Command to get compiler specs" to ``xtensa-esp32-elf-gcc ${FLAGS} -std=c++11 -E -P -v -dD "${INPUTS}"``. - -* In the list of providers, click "CDT GCC Build Output Parser" and change the "Compiler command pattern" to ``xtensa-esp32-elf-(gcc|g\+\+|c\+\+|cc|cpp|clang)`` - -Navigate to "C/C++ General" -> "Indexer" property page: - -* Check "Enable project specific settings" to enable the rest of the settings on this page. - -* Uncheck "Allow heuristic resolution of includes". When this option is enabled Eclipse sometimes fails to find correct header directories. - -Navigate to "C/C++ Build" -> "Behavior" property page: - -* Check "Enable parallel build" to enable multiple build jobs in parallel. - -.. _eclipse-build-project: - -Building in Eclipse -------------------- - -Before your project is first built, Eclipse may show a lot of errors and warnings about undefined values. This is because some source files are automatically generated as part of the esp-idf build process. These errors and warnings will go away after you build the project. - -* Click OK to close the Properties dialog in Eclipse. - -* Outside Eclipse, open a command line prompt. Navigate to your project directory, and run ``make menuconfig`` to configure your project's esp-idf settings. This step currently has to be run outside Eclipse. - -*If you try to build without running a configuration step first, esp-idf will prompt for configuration on the command line - but Eclipse is not able to deal with this, so the build will hang or fail.* - -* Back in Eclipse, choose Project -> Build to build your project. - -**TIP**: If your project had already been built outside Eclipse, you may need to do a Project -> Clean before choosing Project -> Build. This is so Eclipse can see the compiler arguments for all source files. It uses these to determine the header include paths. - -Flash from Eclipse ------------------- - -You can integrate the "make flash" target into your Eclipse project to flash using esptool.py from the Eclipse UI: - -* Right-click your project in Project Explorer (important to make sure you select the project, not a directory in the project, or Eclipse may find the wrong Makefile.) - -* Select Build Targets -> Create... from the context menu. - -* Type "flash" as the target name. Leave the other options as their defaults. - -* Now you can use Project -> Build Target -> Build (Shift+F9) to build the custom flash target, which will compile and flash the project. - -Note that you will need to use "make menuconfig" to set the serial port and other config options for flashing. "make menuconfig" still requires a command line terminal (see the instructions for your platform.) - -Follow the same steps to add ``bootloader`` and ``partition_table`` targets, if necessary. +.. include:: ../cmake-warning.rst +Documentation for Eclipse setup with CMake-based build system and Eclipse CDT is coming soon. .. _eclipse.org: https://www.eclipse.org/ diff --git a/docs/en/get-started/establish-serial-connection.rst b/docs/en/get-started/establish-serial-connection.rst index 7e0e3a91e1..a02e04c88b 100644 --- a/docs/en/get-started/establish-serial-connection.rst +++ b/docs/en/get-started/establish-serial-connection.rst @@ -1,5 +1,6 @@ -Establish Serial Connection with ESP32 -====================================== +Establish Serial Connection with ESP32 (CMake) +============================================== + :link_to_translation:`zh_CN:[中文]` This section provides guidance how to establish serial connection between ESP32 and PC. @@ -10,7 +11,7 @@ Connect ESP32 to PC Connect the ESP32 board to the PC using the USB cable. If device driver does not install automatically, identify USB to serial converter chip on your ESP32 board (or external converter dongle), search for drivers in internet and install them. -Below are the links to drivers for ESP32 and other boards produced by Espressif: +Below are the links to drivers for ESP32 boards produced by Espressif: .. csv-table:: @@ -72,8 +73,12 @@ MacOS :: ls /dev/cu.* +.. note:: -.. _linux-dialout-group: + MacOS users: if you don't see the serial port then check you have the USB/serial drivers installed as shown in the Getting Started guide for your particular development board. For MacOS High Sierra (10.13), you may also have to explicitly allow the drivers to load. Open System Preferences -> Security & Privacy -> General and check if there is a message shown here about "System Software from developer ..." where the developer name is Silicon Labs or FTDI. + + +.. _linux-dialout-group-cmake: Adding user to ``dialout`` on Linux ----------------------------------- @@ -136,7 +141,7 @@ Then open serial port in terminal and check, if you see any log printed out by E ... -If you see some legible log, it means serial connection is working and you are ready to proceed with installation and finally upload of application to ESP32. +If you can see readable log output, it means serial connection is working and you are ready to proceed with installation and finally upload of application to ESP32. .. note:: @@ -144,9 +149,8 @@ If you see some legible log, it means serial connection is working and you are r .. note:: - Close serial terminal after verification that communication is working. In next step we are going to use another application to upload ESP32. This application will not be able to access serial port while it is open in terminal. - -If you got here from section :ref:`get-started-connect` when installing s/w for ESP32 development, then go back to section :ref:`get-started-configure`. + Close serial terminal after verification that communication is working. In the next step we are going to use a different application to upload a new firmware to ESP32. This application will not be able to access serial port while it is open in terminal. +If you got here from :ref:`get-started-connect-cmake` when installing s/w for ESP32 development, then you can continue with :ref:`get-started-configure-cmake`. .. _esptool documentation: https://github.com/espressif/esptool/wiki/ESP32-Boot-Mode-Selection#automatic-bootloader diff --git a/docs/en/get-started/index.rst b/docs/en/get-started/index.rst index ffcc6f0797..e5f810c093 100644 --- a/docs/en/get-started/index.rst +++ b/docs/en/get-started/index.rst @@ -1,12 +1,16 @@ -*********** -Get Started -*********** +******************* +Get Started (CMake) +******************* :link_to_translation:`zh_CN:[中文]` -This document is intended to help you set up the software development environment for the hardware based on Espressif ESP32. +.. include:: ../cmake-warning.rst -After that, a simple example will show you how to use ESP-IDF (Espressif IoT Development Framework) for menu configuration, then how to build and flash firmware onto an ESP32 board. +.. include:: ../cmake-pending-features.rst + +This document is intended to help you set up the software development environment for the hardware based on the ESP32 chip by Espressif. + +After that, a simple example will show you how to use ESP-IDF (Espressif IoT Development Framework) for menu configuration, then building, and flashing firmware onto an ESP32 board. .. include:: /_build/inc/version-note.inc @@ -36,12 +40,13 @@ Hardware: Software: -* **Toolchain** to build the **Application** for ESP32 +* **Toolchain** to compile code for ESP32 +* **Build tools** - CMake and Ninja to build a full **Application** for ESP32 * **ESP-IDF** that essentially contains API (software libraries and source code) for ESP32 and scripts to operate the **Toolchain** * **Text editor** to write programs (**Projects**) in C, e.g., `Eclipse `_ -.. figure:: ../../_static/what-you-need.png +.. figure:: ../../_static/what-you-need-cmake.png :align: center :alt: Development of applications for ESP32 :figclass: align-center @@ -61,9 +66,9 @@ If you have one of ESP32 development boards listed below, you can click on the l ESP-WROVER-KIT <../hw-reference/get-started-wrover-kit> ESP32-PICO-KIT <../hw-reference/get-started-pico-kit> ESP32-Ethernet-Kit <../hw-reference/get-started-ethernet-kit> + - -.. _get-started-step-by-step: +.. _get-started-step-by-step-cmake: Installation Step by Step ========================= @@ -73,71 +78,57 @@ This is a detailed roadmap to walk you through the installation process. Setting up Development Environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* :ref:`get-started-setup-toolchain` for :doc:`Windows `, :doc:`Linux ` or :doc:`MacOS ` -* :ref:`get-started-get-esp-idf` -* :ref:`get-started-setup-path` -* :ref:`get-started-get-packages` +* :ref:`get-started-get-prerequisites-cmake` for :doc:`Windows `, :doc:`Linux ` or :doc:`macOS ` +* :ref:`get-started-get-esp-idf-cmake` +* :ref:`get-started-set-up-tools-cmake` +* :ref:`get-started-set-up-env-cmake` Creating Your First Project ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* :ref:`get-started-start-project` -* :ref:`get-started-connect` -* :ref:`get-started-configure` -* :ref:`get-started-build-and-flash` -* :ref:`get-started-monitor` +* :ref:`get-started-start-project-cmake` +* :ref:`get-started-connect-cmake` +* :ref:`get-started-configure-cmake` +* :ref:`get-started-build-cmake` +* :ref:`get-started-flash-cmake` +* :ref:`get-started-build-monitor-cmake` -.. _get-started-setup-toolchain: +.. _get-started-get-prerequisites-cmake: -Step 1. Set up the Toolchain -============================ +Step 1. Install prerequisites +============================= -The toolchain is a set of programs for compiling code and building applications. - -The quickest way to start development with ESP32 is by installing a prebuilt toolchain. Pick up your OS below and follow the provided instructions. +Some tools need to be installed on the computer before proceeding to the next steps. Follow the links below for the instructions for your OS: .. toctree:: :hidden: Windows - Linux - MacOS + Linux + macOS -+-------------------+-------------------+-------------------+ -| |windows-logo| | |linux-logo| | |macos-logo| | -+-------------------+-------------------+-------------------+ -| `Windows`_ | `Linux`_ | `Mac OS`_ | -+-------------------+-------------------+-------------------+ +* :doc:`windows-setup` +* :doc:`linux-setup` +* :doc:`macos-setup` -.. |windows-logo| image:: ../../_static/windows-logo.png - :target: ../get-started/windows-setup.html +.. _get-started-get-esp-idf-cmake: -.. |linux-logo| image:: ../../_static/linux-logo.png - :target: ../get-started/linux-setup.html +Step 2. Get ESP-IDF +=================== -.. |macos-logo| image:: ../../_static/macos-logo.png - :target: ../get-started/macos-setup.html +To build applications for the ESP32, you need the software libraries provided by Espressif in `ESP-IDF repository `_. -.. _Windows: ../get-started/windows-setup.html -.. _Linux: ../get-started/linux-setup.html -.. _Mac OS: ../get-started/macos-setup.html +Get ESP-IDF in accordance with your operating system. + +To get ESP-IDF, navigate to your installation directory and clone the repository with ``git clone``. .. note:: This guide uses the directory ``~/esp`` on Linux and macOS or ``%userprofile%\esp`` on Windows as an installation folder for ESP-IDF. You can use any directory, but you will need to adjust paths for the commands respectively. Keep in mind that ESP-IDF does not support spaces in paths. -Depending on your experience and preferences, you may want to customize your environment instead of using a prebuilt toolchain. To set up the system your own way go to Section :ref:`get-started-customized-setup`. - - -.. _get-started-get-esp-idf: - -Step 2. Get ESP-IDF -=================== - -Besides the toolchain, you also need ESP32-specific API (software libraries and source code). They are provided by Espressif in `ESP-IDF repository `_. - -To get a local copy of ESP-IDF, navigate to your installation directory and clone the repository with ``git clone``. +Linux and macOS +~~~~~~~~~~~~~~~ Open Terminal, and run the following commands: @@ -147,54 +138,90 @@ ESP-IDF will be downloaded into ``~/esp/esp-idf``. Consult :doc:`/versions` for information about which ESP-IDF version to use in a given situation. -.. include:: /_build/inc/git-clone-notes.inc +Windows +~~~~~~~ -.. note:: +In addition to installing the tools, :ref:`get-started-cmake-windows-tools-installer` for Windows introduced in Step 1 can also download a copy of ESP-IDF. - Do not miss the ``--recursive`` option. If you have already cloned ESP-IDF without this option, run another command to get all the submodules:: +Consult :doc:`/versions` for information about which ESP-IDF version to use in a given situation. - cd esp-idf - git submodule update --init +If you wish to download ESP-IDF without the help of ESP-IDF Tools Installer, refer to these :ref:`instructions `. +.. _get-started-set-up-tools-cmake: -.. _get-started-setup-path: +Step 3. Set up the tools +======================== -Step 3. Set Environment Variables -================================= +Aside from the ESP-IDF, you also need to install the tools used by ESP-IDF, such as the compiler, debugger, Python packages, etc. -The toolchain uses the environment variable ``IDF_PATH`` to access the ESP-IDF directory. This variable should be set up on your computer, otherwise projects will not build. +Windows +~~~~~~~ -These variables can be set temporarily (per session) or permanently. Please follow the instructions specific to :ref:`Windows ` , :ref:`Linux and MacOS ` in Section :doc:`add-idf_path-to-profile`. +:ref:`get-started-cmake-windows-tools-installer` for Windows introduced in Step 1 installs all the required tools. +If you want to install the tools without the help of ESP-IDF Tools Installer, open the Command Prompt and follow these steps: -.. _get-started-get-packages: +.. code-block:: batch -Step 4. Install the Required Python Packages -============================================ + cd %userprofile%\esp\esp-idf + install.bat -The python packages required by ESP-IDF are located in ``IDF_PATH/requirements.txt``. You can install them by running:: +Linux and macOS +~~~~~~~~~~~~~~~ - python -m pip install --user -r $IDF_PATH/requirements.txt +.. code-block:: bash -.. note:: + cd ~/esp/esp-idf + ./install.sh - Please check the version of the Python interpreter that you will be using with ESP-IDF. For this, run - the command ``python --version`` and depending on the result, you might want to use ``python2``, ``python2.7`` - or similar instead of just ``python``, e.g.:: +Customizing the tools installation path +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - python2.7 -m pip install --user -r $IDF_PATH/requirements.txt +The scripts introduced in this step install compilation tools required by ESP-IDF inside the user home directory: ``$HOME/.espressif`` on Linux and macOS, ``%USERPROFILE%\.espressif`` on Windows. If you wish to install the tools into a different directory, set the environment variable ``IDF_TOOLS_PATH`` before running the installation scripts. Make sure that your user has sufficient permissions to read and write this path. +If changing the ``IDF_TOOLS_PATH``, make sure it is set to the same value every time the ``install.bat``/``install.sh`` and ``export.bat``/``export.sh`` scripts are executed. -.. _get-started-start-project: +.. _get-started-set-up-env-cmake: + +Step 4. Set up the environment variables +======================================== + +The installed tools are not yet added to the PATH environment variable. To make the tools usable from the command line, some environment variables must be set. ESP-IDF provides another script which does that. + +Windows +~~~~~~~ + +:ref:`get-started-cmake-windows-tools-installer` for Windows creates an "ESP-IDF Command Prompt" shortcut in the Start Menu. This shortcut opens the Command Prompt and sets up all the required environment variables. You can open this shortcut and proceed to the next step. + +Alternatively, if you want to use ESP-IDF in an existing Command Prompt window, you can run: + +.. code-block:: batch + + %userprofile%\esp\esp-idf\export.bat + +Linux and macOS +~~~~~~~~~~~~~~~ + +In the terminal where you are going to use ESP-IDF, run: + +.. code-block:: bash + + . $HOME/esp/esp-idf/export.sh + +Note the space between the leading dot and the path! + +You can also automate this step, making ESP-IDF tools available in every terminal, by adding this line to your ``.profile`` or ``.bash_profile`` script. + +.. _get-started-start-project-cmake: Step 5. Start a Project ======================= Now you are ready to prepare your application for ESP32. You can start with :example:`get-started/hello_world` project from :idf:`examples` directory in IDF. -Copy :example:`get-started/hello_world` to the ``~/esp`` directory: +Copy :example:`get-started/hello_world` to ``~/esp`` directory: -Linux and MacOS +Linux and macOS ~~~~~~~~~~~~~~~ .. code-block:: bash @@ -216,9 +243,9 @@ It is also possible to build examples in-place, without copying them first. .. important:: - The esp-idf build system does not support spaces in the paths to either esp-idf or to projects. + The ESP-IDF build system does not support spaces in the paths to either ESP-IDF or to projects. -.. _get-started-connect: +.. _get-started-connect-cmake: Step 6. Connect Your Device =========================== @@ -238,20 +265,22 @@ If you are not sure how to check the serial port name, please refer to :doc:`est Keep the port name handy as you will need it in the next steps. -.. _get-started-configure: +.. _get-started-configure-cmake: Step 7. Configure ================= -Navigate to your ``hello_world`` directory from :ref:`get-started-start-project` and run the project configuration utility ``menuconfig``. +Navigate to your ``hello_world`` directory from :ref:`get-started-start-project-cmake` and run the project configuration utility ``menuconfig``. -Linux and MacOS +Linux and macOS ~~~~~~~~~~~~~~~ .. code-block:: bash cd ~/esp/hello_world - make menuconfig + idf.py menuconfig + +If your default version of Python is 3.x, you may need to run ``python2 $(which idf.py) menuconfig`` instead. Windows ~~~~~~~ @@ -259,7 +288,7 @@ Windows .. code-block:: batch cd %userprofile%\esp\hello_world - make menuconfig + idf.py menuconfig If the previous steps have been done correctly, the following menu appears: @@ -270,8 +299,6 @@ If the previous steps have been done correctly, the following menu appears: Project configuration - Home window -In the menu, navigate to ``Serial flasher config`` > ``Default serial port`` to configure the serial port, where project will be loaded to. Confirm selection by pressing enter, save configuration by selecting ``< Save >`` and then exit ``menuconfig`` by selecting ``< Exit >``. - To navigate and use ``menuconfig``, press the following keys: * Arrow keys for navigation @@ -282,72 +309,111 @@ To navigate and use ``menuconfig``, press the following keys: * ``?`` while highlighting a configuration item to display help about that item * ``/`` to find configuration items -.. note:: - - If you are **Arch Linux** user, navigate to ``SDK tool configuration`` and change the name of ``Python 2 interpreter`` from ``python`` to ``python2``. - .. attention:: If you use ESP32-DevKitC board with the **ESP32-SOLO-1** module, enable single core mode (:ref:`CONFIG_FREERTOS_UNICORE`) in menuconfig before flashing examples. -.. _get-started-build-and-flash: +.. _get-started-build-cmake: -Step 8. Build and Flash -======================= +Step 8. Build the Project +========================= -Build and flash the project by running:: +Build the project by running:: - make flash + idf.py build -This command will compile the application and all ESP-IDF components, then it will generate the bootloader, partition table, and application binaries. After that, these binaries will be flashed onto your ESP32 board. +This command will compile the application and all ESP-IDF components, then it will generate the bootloader, partition table, and application binaries. -If there are no issues by the end of the flash process, you will see messages (below) describing progress of the loading process. Then the board will be reset and the "hello_world" application will start up. +.. code-block:: none -.. highlight:: none + $ idf.py build + Running cmake in directory /path/to/hello_world/build + Executing "cmake -G Ninja --warn-uninitialized /path/to/hello_world"... + Warn about uninitialized values. + -- Found Git: /usr/bin/git (found version "2.17.0") + -- Building empty aws_iot component due to configuration + -- Component names: ... + -- Component paths: ... + + ... (more lines of build system output) + + [527/527] Generating hello-world.bin + esptool.py v2.3.1 + + Project build complete. To flash, run this command: + ../../../components/esptool_py/esptool/esptool.py -p (PORT) -b 921600 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x10000 build/hello-world.bin build 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin + or run 'idf.py -p PORT flash' -:: +If there are no errors, the build will finish by generating the firmware binary .bin file. - esptool.py v2.0-beta2 - Flashing binaries to serial port /dev/ttyUSB0 (app at offset 0x10000)... - esptool.py v2.0-beta2 - Connecting........___ + +.. _get-started-flash-cmake: + +Step 9. Flash onto the Device +============================= + +Flash the binaries that you just built onto your ESP32 board by running:: + + idf.py -p PORT [-b BAUD] flash + +Replace PORT with your ESP32 board's serial port name from :ref:`get-started-connect-cmake`. + +You can also change the flasher baud rate by replacing BAUD with the baud rate you need. The default baud rate is ``460800``. + +For more information on idf.py arguments, see :ref:`idf.py`. + +.. note:: + + The option ``flash`` automatically builds and flashes the project, so running ``idf.py build`` is not necessary. + +.. code-block:: none + + Running esptool.py in directory [...]/esp/hello_world + Executing "python [...]/esp-idf/components/esptool_py/esptool/esptool.py -b 460800 write_flash @flash_project_args"... + esptool.py -b 460800 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x1000 bootloader/bootloader.bin 0x8000 partition_table/partition-table.bin 0x10000 hello-world.bin + esptool.py v2.3.1 + Connecting.... + Detecting chip type... ESP32 + Chip is ESP32D0WDQ6 (revision 1) + Features: WiFi, BT, Dual Core Uploading stub... Running stub... Stub running... - Changing baud rate to 921600 + Changing baud rate to 460800 Changed. - Attaching SPI flash... Configuring flash size... Auto-detected Flash size: 4MB Flash params set to 0x0220 - Compressed 11616 bytes to 6695... - Wrote 11616 bytes (6695 compressed) at 0x00001000 in 0.1 seconds (effective 920.5 kbit/s)... - Hash of data verified. - Compressed 408096 bytes to 171625... - Wrote 408096 bytes (171625 compressed) at 0x00010000 in 3.9 seconds (effective 847.3 kbit/s)... + Compressed 22992 bytes to 13019... + Wrote 22992 bytes (13019 compressed) at 0x00001000 in 0.3 seconds (effective 558.9 kbit/s)... Hash of data verified. Compressed 3072 bytes to 82... - Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 8297.4 kbit/s)... + Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 5789.3 kbit/s)... Hash of data verified. - + Compressed 136672 bytes to 67544... + Wrote 136672 bytes (67544 compressed) at 0x00010000 in 1.9 seconds (effective 567.5 kbit/s)... + Hash of data verified. + Leaving... - Hard resetting... + Hard resetting via RTS pin... + +If there are no issues by the end of the flash process, the module will be reset and the “hello_world” application will be running. + +.. (Not currently supported) If you'd like to use the Eclipse IDE instead of running ``idf.py``, check out the :doc:`Eclipse guide `. -If you'd like to use the Eclipse IDE instead of running ``make``, check out the :doc:`Eclipse guide `. +.. _get-started-build-monitor-cmake: +Step 10. Monitor +================ -.. _get-started-monitor: - -Step 9. Monitor -=============== - -To check if "hello_world" is indeed running, type ``make monitor``. +To check if "hello_world" is indeed running, type ``idf.py -p PORT monitor`` (Do not forget to replace PORT with your serial port name). This command launches the :doc:`IDF Monitor <../api-guides/tools/idf-monitor>` application:: - $ make monitor - MONITOR + $ idf.py -p /dev/ttyUSB0 monitor + Running idf_monitor in directory [...]/esp/hello_world/build + Executing "python [...]/esp-idf/tools/idf_monitor.py -b 115200 [...]/esp/hello_world/build/hello-world.elf"... --- idf_monitor on /dev/ttyUSB0 115200 --- --- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- ets Jun 8 2016 00:22:57 @@ -370,7 +436,7 @@ After startup and diagnostic logs scroll up, you should see "Hello world!" print To exit IDF monitor use the shortcut ``Ctrl+]``. -If IDF monitor fails shortly after the upload, or if instead of the messages above you see a random garbage similar to what is given below, your board is likely using a 26MHz crystal. Most development board designs use 40MHz, so ESP-IDF uses this frequency as a default value. +If IDF monitor fails shortly after the upload, or, if instead of the messages above, you see random garbage similar to what is given below, your board is likely using a 26MHz crystal. Most development board designs use 40MHz, so ESP-IDF uses this frequency as a default value. .. code-block:: none @@ -380,73 +446,46 @@ If IDF monitor fails shortly after the upload, or if instead of the messages abo If you have such a problem, do the following: 1. Exit the monitor. -2. Go back to :ref:`menuconfig `. +2. Go back to :ref:`menuconfig `. 3. Go to Component config --> ESP32-specific --> Main XTAL frequency, then change :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` to 26MHz. -4. After that, :ref:`build and flash ` the application again. +4. After that, :ref:`build and flash ` the application again. .. note:: You can combine building, flashing and monitoring into one step by running:: - make flash monitor + idf.py -p PORT flash monitor -See also :doc:`IDF Monitor <../api-guides/tools/idf-monitor>` for handy shortcuts and more details on using IDF monitor. +See also: + +- :doc:`IDF Monitor <../api-guides/tools/idf-monitor>` for handy shortcuts and more details on using IDF monitor. +- :ref:`idf.py` for a full reference of ``idf.py`` commands and options. **That's all that you need to get started with ESP32!** Now you are ready to try some other :idf:`examples`, or go straight to developing your own applications. - -Environment Variables -===================== - -Some environment variables can be specified whilst calling ``make`` allowing users to **override arguments without the need to reconfigure them using** ``make menuconfig``. - -+-----------------+--------------------------------------------------------------+ -| Variables | Description & Usage | -+=================+==============================================================+ -| ``ESPPORT`` | Overrides the serial port used in ``flash`` and ``monitor``. | -| | | -| | Examples: ``make flash ESPPORT=/dev/ttyUSB1``, | -| | ``make monitor ESPPORT=COM1`` | -+-----------------+--------------------------------------------------------------+ -| ``ESPBAUD`` | Overrides the serial baud rate when flashing the ESP32. | -| | | -| | Example: ``make flash ESPBAUD=9600`` | -+-----------------+--------------------------------------------------------------+ -| ``MONITORBAUD`` | Overrides the serial baud rate used when monitoring. | -| | | -| | Example: ``make monitor MONITORBAUD=9600`` | -+-----------------+--------------------------------------------------------------+ - -.. note:: - - You can export environment variables (e.g. ``export ESPPORT=/dev/ttyUSB1``). - All subsequent calls of ``make`` within the same terminal session will use - the exported value given that the variable is not simultaneously overridden. - - Updating ESP-IDF ================ -You should update ESP-IDF from time to time, as newer versions fix bugs and provide new features. The simplest way to do the update is to delete the existing ``esp-idf`` folder and clone it again, as if performing the initial installation described in :ref:`get-started-get-esp-idf`. - -If downloading to a new path, remember to :doc:`add-idf_path-to-profile` so that the toolchain scripts can find ESP-IDF in its release specific location. +You should update ESP-IDF from time to time, as newer versions fix bugs and provide new features. The simplest way to do the update is to delete the existing ``esp-idf`` folder and clone it again, as if performing the initial installation described in :ref:`get-started-get-esp-idf-cmake`. Another solution is to update only what has changed. :ref:`The update procedure depends on the version of ESP-IDF you are using `. +After updating ESP-IDF, execute ``install.sh`` (``install.bat`` on Windows) again, in case the new ESP-IDF version requires different versions of tools. See instructions at :ref:`get-started-set-up-tools-cmake`. + +Once the new tools are installed, update the environment using ``export.sh`` (``export.bat`` on Windows). See instructions at :ref:`get-started-set-up-env-cmake`. + Related Documents ================= .. toctree:: :maxdepth: 1 - add-idf_path-to-profile establish-serial-connection - make-project eclipse-setup ../api-guides/tools/idf-monitor toolchain-setup-scratch .. _Stable version: https://docs.espressif.com/projects/esp-idf/en/stable/ -.. _Releases page: https://github.com/espressif/esp-idf/releases +.. _Releases page: https://github.com/espressif/esp-idf/releases \ No newline at end of file diff --git a/docs/en/get-started/linux-setup-scratch.rst b/docs/en/get-started/linux-setup-scratch.rst index 395458153f..51abaf6fd3 100644 --- a/docs/en/get-started/linux-setup-scratch.rst +++ b/docs/en/get-started/linux-setup-scratch.rst @@ -1,30 +1,32 @@ -********************************** -Setup Linux Toolchain from Scratch -********************************** +****************************************** +Setup Linux Toolchain from Scratch (CMake) +****************************************** + :link_to_translation:`zh_CN:[中文]` -.. note:: - - Standard process for installing the toolchain is described :doc:`here `. See :ref:`Customized Setup of Toolchain ` section for some of the reasons why installing the toolchain from scratch may be necessary. +.. include:: ../cmake-warning.rst + +The following instructions are alternative to downloading binary toolchain from Espressif website. To quickly setup the binary toolchain, instead of compiling it yourself, backup and proceed to section :doc:`linux-setup`. Install Prerequisites ===================== To compile with ESP-IDF you need to get the following packages: +- CentOS 7:: + + sudo yum install git wget ncurses-devel flex bison gperf python pyserial python-pyelftools cmake ninja-build ccache + - Ubuntu and Debian:: - sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing python-pyelftools + sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache - Arch:: - sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing python2-pyelftools + sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-click python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache .. note:: - - Some older (pre-2014) Linux distributions may use ``pyserial`` version 2.x which is not supported by ESP-IDF. - In this case please install a supported version via ``pip`` as it is described in section - :ref:`get-started-get-packages`. + CMake version 3.5 or newer is required for use with ESP-IDF. Older Linux distributions may require updating, enabling of a "backports" repository, or installing of a "cmake3" package rather than "cmake". Compile the Toolchain from Source ================================= @@ -33,19 +35,19 @@ Compile the Toolchain from Source - CentOS 7:: - sudo yum install gawk gperf grep gettext ncurses-devel python python-devel automake bison flex texinfo help2man libtool + sudo yum install gawk gperf grep gettext ncurses-devel python python-devel automake bison flex texinfo help2man libtool make - Ubuntu pre-16.04:: - sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool + sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool make - Ubuntu 16.04 or newer:: - sudo apt-get install gawk gperf grep gettext python python-dev automake bison flex texinfo help2man libtool libtool-bin + sudo apt-get install gawk gperf grep gettext python python-dev automake bison flex texinfo help2man libtool libtool-bin make - Debian 9:: - sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool libtool-bin + sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool libtool-bin make - Arch:: @@ -66,10 +68,10 @@ Build the toolchain:: ./ct-ng build chmod -R u+w builds/xtensa-esp32-elf -Toolchain will be built in ``~/esp/crosstool-NG/builds/xtensa-esp32-elf``. Follow :ref:`instructions for standard setup ` to add the toolchain to your ``PATH``. +Toolchain will be built in ``~/esp/crosstool-NG/builds/xtensa-esp32-elf``. To use it, you need to add ``~/esp/crosstool-NG/builds/xtensa-esp32-elf/bin`` to ``PATH`` environment variable. Next Steps ========== -To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf`. +To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf-cmake`. diff --git a/docs/en/get-started/linux-setup.rst b/docs/en/get-started/linux-setup.rst index 7484b4c624..429755b9bd 100644 --- a/docs/en/get-started/linux-setup.rst +++ b/docs/en/get-started/linux-setup.rst @@ -1,8 +1,11 @@ -************************************* -Standard Setup of Toolchain for Linux -************************************* +*********************************************** +Installation of Prerequisites for Linux (CMake) +*********************************************** + :link_to_translation:`zh_CN:[中文]` +.. include:: ../cmake-warning.rst + Install Prerequisites ===================== @@ -10,85 +13,32 @@ To compile with ESP-IDF you need to get the following packages: - CentOS 7:: - sudo yum install gcc git wget make ncurses-devel flex bison gperf python python2-cryptography + sudo yum install git wget ncurses-devel flex bison gperf python pyserial python-pyelftools cmake ninja-build ccache - Ubuntu and Debian:: - sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing python-pyelftools + sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache - Arch:: - sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing python2-pyelftools + sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pip python2-pyserial python2-click python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache .. note:: + CMake version 3.5 or newer is required for use with ESP-IDF. Older Linux distributions may require updating, enabling of a "backports" repository, or installing of a "cmake3" package rather than "cmake". - Some older Linux distributions may be missing some of the Python packages listed above (or may use ``pyserial`` version 2.x which is not supported by ESP-IDF). It is possible to install these packages via ``pip`` instead - as described in section :ref:`get-started-get-packages`. - -Toolchain Setup +Additional Tips =============== -.. include:: /_build/inc/download-links.inc - -ESP32 toolchain for Linux is available for download from Espressif website: - -- for 64-bit Linux: - - |download_link_linux64| - -- for 32-bit Linux: - - |download_link_linux32| - -1. Download this file, then extract it in ``~/esp`` directory: - - - for 64-bit Linux: - - .. include:: /_build/inc/unpack-code-linux64.inc - - - for 32-bit Linux: - - .. include:: /_build/inc/unpack-code-linux32.inc - -.. _setup-linux-toolchain-add-it-to-path: - -2. The toolchain will be extracted into ``~/esp/xtensa-esp32-elf/`` directory. - - To use it, you will need to update your ``PATH`` environment variable in ``~/.profile`` file. To make ``xtensa-esp32-elf`` available for all terminal sessions, add the following line to your ``~/.profile`` file:: - - export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH" - - Alternatively, you may create an alias for the above command. This way you can get the toolchain only when you need it. To do this, add different line to your ``~/.profile`` file:: - - alias get_esp32='export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH"' - - Then when you need the toolchain you can type ``get_esp32`` on the command line and the toolchain will be added to your ``PATH``. - - .. note:: - - If you have ``/bin/bash`` set as login shell, and both ``.bash_profile`` and ``.profile`` exist, then update ``.bash_profile`` instead. In CentOS, ``alias`` should set in ``.bashrc``. - -3. Log off and log in back to make the ``.profile`` changes effective. Run the following command to verify if ``PATH`` is correctly set:: - - printenv PATH - - You are looking for similar result containing toolchain's path at the beginning of displayed string:: - - $ printenv PATH - /home/user-name/esp/xtensa-esp32-elf/bin:/home/user-name/bin:/home/user-name/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin - - Instead of ``/home/user-name`` there should be a home path specific to your installation. - - Permission issues /dev/ttyUSB0 ------------------------------ -With some Linux distributions you may get the ``Failed to open port /dev/ttyUSB0`` error message when flashing the ESP32. :ref:`This can be solved by adding the current user to the dialout group`. +With some Linux distributions you may get the ``Failed to open port /dev/ttyUSB0`` error message when flashing the ESP32. :ref:`This can be solved by adding the current user to the dialout group`. Arch Linux Users ---------------- -To run the precompiled gdb (xtensa-esp32-elf-gdb) in Arch Linux requires ncurses 5, but Arch uses ncurses 6. +To run the precompiled gdb (xtensa-esp32-elf-gdb) in Arch Linux requires ncurses 5, but Arch uses ncurses 6. Backwards compatibility libraries are available in AUR_ for native and lib32 configurations: @@ -103,7 +53,7 @@ Alternatively, use crosstool-NG to compile a gdb that links against ncurses 6. Next Steps ========== -To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf`. +To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf-cmake`. Related Documents diff --git a/docs/en/get-started/macos-setup-scratch.rst b/docs/en/get-started/macos-setup-scratch.rst index a4dfe9d7f1..45fa4238ca 100644 --- a/docs/en/get-started/macos-setup-scratch.rst +++ b/docs/en/get-started/macos-setup-scratch.rst @@ -1,11 +1,22 @@ -*************************************** -Setup Toolchain for Mac OS from Scratch -*************************************** +*********************************************** +Setup Toolchain for Mac OS from Scratch (CMake) +*********************************************** + :link_to_translation:`zh_CN:[中文]` -.. note:: - - Standard process for installing the toolchain is described :doc:`here `. See :ref:`Customized Setup of Toolchain ` section for some of the reasons why installing the toolchain from scratch may be necessary. +.. include:: ../cmake-warning.rst + +Package Manager +=============== + +To set up the toolchain from scratch, rather than :doc:`downloading a pre-compiled toolchain`, you will need to install either the MacPorts_ or homebrew_ package manager. + +MacPorts needs a full XCode installation, while homebrew only needs XCode command line tools. + + .. _homebrew: https://brew.sh/ + .. _MacPorts: https://www.macports.org/install.php + +See :ref:`Customized Setup of Toolchain ` section for some of the reasons why installing the toolchain from scratch may be necessary. Install Prerequisites ===================== @@ -14,27 +25,32 @@ Install Prerequisites sudo easy_install pip -.. note:: +- install pyserial:: - ``pip`` will be used later for installing :ref:`the required Python packages `. + pip install --user pyserial + +- install CMake & Ninja build: + + - If you have HomeBrew, you can run:: + + brew install cmake ninja + + - If you have MacPorts, you can run:: + + sudo port install cmake ninja Compile the Toolchain from Source ================================= - Install dependencies: - - Install either MacPorts_ or homebrew_ package manager. MacPorts needs a full XCode installation, while homebrew only needs XCode command line tools. - - .. _homebrew: https://brew.sh/ - .. _MacPorts: https://www.macports.org/install.php - - with MacPorts:: - sudo port install gsed gawk binutils gperf grep gettext wget libtool autoconf automake + sudo port install gsed gawk binutils gperf grep gettext wget libtool autoconf automake make - with homebrew:: - brew install gnu-sed gawk binutils gperftools gettext wget help2man libtool autoconf automake + brew install gnu-sed gawk binutils gperftools gettext wget help2man libtool autoconf automake make Create a case-sensitive filesystem image:: @@ -63,10 +79,10 @@ Build the toolchain:: ./ct-ng build chmod -R u+w builds/xtensa-esp32-elf -Toolchain will be built in ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf``. Follow :ref:`instructions for standard setup ` to add the toolchain to your ``PATH``. +Toolchain will be built in ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf``. To use it, you need to add ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf/bin`` to ``PATH`` environment variable. Next Steps ========== -To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf`. +To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf-cmake`. diff --git a/docs/en/get-started/macos-setup.rst b/docs/en/get-started/macos-setup.rst index 7e1921a6c3..7926ea9d5f 100644 --- a/docs/en/get-started/macos-setup.rst +++ b/docs/en/get-started/macos-setup.rst @@ -1,52 +1,49 @@ -************************************** -Standard Setup of Toolchain for Mac OS -************************************** +*********************************************** +Installation of Prerequisites for macOS (CMake) +*********************************************** + :link_to_translation:`zh_CN:[中文]` +.. include:: ../cmake-warning.rst + Install Prerequisites ===================== +ESP-IDF will use the version of Python installed by default on macOS. + - install pip:: sudo easy_install pip +- install pyserial:: + + pip install --user pyserial + +- install CMake & Ninja build: + + - If you have HomeBrew_, you can run:: + + brew install cmake ninja + + - If you have MacPorts_, you can run:: + + sudo port install cmake ninja + + - Otherwise, consult the CMake_ and Ninja_ home pages for macOS installation downloads. + +- It is strongly recommended to also install ccache_ for faster builds. If you have HomeBrew_, this can be done via ``brew install ccache`` or ``sudo port install ccache`` on MacPorts_. + .. note:: + If an error like this is shown during any step:: - ``pip`` will be used later for installing :ref:`the required Python packages `. - -Toolchain Setup -=============== - -.. include:: /_build/inc/download-links.inc - -ESP32 toolchain for macOS is available for download from Espressif website: - -|download_link_osx| - -Download this file, then extract it in ``~/esp`` directory: - -.. include:: /_build/inc/unpack-code-osx.inc - -.. _setup-macos-toolchain-add-it-to-path: - -The toolchain will be extracted into ``~/esp/xtensa-esp32-elf/`` directory. - -To use it, you will need to update your ``PATH`` environment variable in ``~/.profile`` file. To make ``xtensa-esp32-elf`` available for all terminal sessions, add the following line to your ``~/.profile`` file:: - - export PATH=$HOME/esp/xtensa-esp32-elf/bin:$PATH - -Alternatively, you may create an alias for the above command. This way you can get the toolchain only when you need it. To do this, add different line to your ``~/.profile`` file:: - - alias get_esp32="export PATH=$HOME/esp/xtensa-esp32-elf/bin:$PATH" - -Then when you need the toolchain you can type ``get_esp32`` on the command line and the toolchain will be added to your ``PATH``. + xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun + Then you will need to install the XCode command line tools to continue. You can install these by running ``xcode-select --install``. Next Steps ========== -To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf`. - +To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf-cmake`. Related Documents ================= @@ -55,3 +52,9 @@ Related Documents :maxdepth: 1 macos-setup-scratch + +.. _cmake: https://cmake.org/ +.. _ninja: https://ninja-build.org/ +.. _ccache: https://ccache.samba.org/ +.. _homebrew: https://brew.sh/ +.. _MacPorts: https://www.macports.org/install.php diff --git a/docs/en/get-started/toolchain-setup-scratch.rst b/docs/en/get-started/toolchain-setup-scratch.rst index c5f2b5ae4a..c7b0ee32d5 100644 --- a/docs/en/get-started/toolchain-setup-scratch.rst +++ b/docs/en/get-started/toolchain-setup-scratch.rst @@ -1,10 +1,12 @@ -.. _get-started-customized-setup: +.. _get-started-customized-setup-cmake: -***************************** -Customized Setup of Toolchain -***************************** +************************************* +Customized Setup of Toolchain (CMake) +************************************* -Instead of downloading binary toolchain from Espressif website (see :ref:`get-started-setup-toolchain`) you may build the toolchain yourself. +:link_to_translation:`zh_CN:[中文]` + +Instead of downloading binary toolchain from Espressif website (see :ref:`get-started-set-up-tools-cmake`) you may build the toolchain yourself. If you can't think of a reason why you need to build it yourself, then probably it's better to stick with the binary version. However, here are some of the reasons why you might want to compile it from source: diff --git a/docs/en/get-started/windows-setup-scratch.rst b/docs/en/get-started/windows-setup-scratch.rst index fc64e2a233..4fa8168fef 100644 --- a/docs/en/get-started/windows-setup-scratch.rst +++ b/docs/en/get-started/windows-setup-scratch.rst @@ -1,117 +1,122 @@ -************************************ -Setup Windows Toolchain from Scratch -************************************ +********************************** +Windows Setup from Scratch (CMake) +********************************** -Setting up the environment gives you some more control over the process, and also provides the information for advanced users to customize the install. The :doc:`pre-built environment `, addressed to less experienced users, has been prepared by following these steps. +:link_to_translation:`zh_CN:[中文]` -To quickly setup the toolchain in standard way, using a prebuilt environment, proceed to section :doc:`windows-setup`. +.. include:: ../cmake-warning.rst +This is a step-by-step alternative to running the :doc:`ESP-IDF Tools Installer ` for the CMake-based build system. Installing all of the tools by hand allows more control over the process, and also provides the information for advanced users to customize the install. -.. _configure-windows-toolchain-from-scratch: +To quickly setup the toolchain and other tools in standard way, using the ESP-IDF Tools installer, proceed to section :doc:`windows-setup`. -Configure Toolchain & Environment from Scratch -============================================== +.. note:: + The GNU Make based build system requires the MSYS2_ Unix compatibility environment on Windows. The CMake-based build system does not require this environment. -This process involves installing MSYS2_, then installing the MSYS2_ and Python packages which ESP-IDF uses, and finally downloading and installing the Xtensa toolchain. +.. _get-esp-idf-windows-command-line-cmake: -* Navigate to the MSYS2_ installer page and download the ``msys2-i686-xxxxxxx.exe`` installer executable (we only support a 32-bit MSYS environment, it works on both 32-bit and 64-bit Windows.) At time of writing, the latest installer is ``msys2-i686-20161025.exe``. - -* Run through the installer steps. **Uncheck the "Run MSYS2 32-bit now" checkbox at the end.** - -* Once the installer exits, open Start Menu and find "MSYS2 MinGW 32-bit" to run the terminal. - - *(Why launch this different terminal? MSYS2 has the concept of different kinds of environments. The default "MSYS" environment is Cygwin-like and uses a translation layer for all Windows API calls. We need the "MinGW" environment in order to have a native Python which supports COM ports.)* - -* The ESP-IDF repository on github contains a script in the tools directory titled ``windows_install_prerequisites.sh``. If you haven't got a local copy of the ESP-IDF yet, that's OK - you can just download that one file in Raw format from here: :idf_raw:`tools/windows/windows_install_prerequisites.sh`. Save it somewhere on your computer. - -* Type the path to the shell script into the MSYS2 terminal window. You can type it as a normal Windows path, but use forward-slashes instead of back-slashes. ie: ``C:/Users/myuser/Downloads/windows_install_prerequisites.sh``. You can read the script beforehand to check what it does. - -* The ``windows_install_prerequisites.sh`` script will download and install packages for ESP-IDF support, and the ESP32 toolchain. - - -Troubleshooting -~~~~~~~~~~~~~~~ - -* While the install script runs, MSYS may update itself into a state where it can no longer operate. You may see errors like the following:: - - *** fatal error - cygheap base mismatch detected - 0x612E5408/0x612E4408. This problem is probably due to using incompatible versions of the cygwin DLL. - - If you see errors like this, close the terminal window entirely (terminating the processes running there) and then re-open a new terminal. Re-run ``windows_install_prerequisites.sh`` (tip: use the up arrow key to see the last run command). The update process will resume after this step. - -* MSYS2 is a "rolling" distribution so running the installer script may install newer packages than what is used in the prebuilt environments. If you see any errors that appear to be related to installing MSYS2 packages, please check the `MSYS2-packages issues list`_ for known issues. If you don't see any relevant issues, please `raise an IDF issue`_. - - -MSYS2 Mirrors in China -~~~~~~~~~~~~~~~~~~~~~~ - -There are some (unofficial) MSYS2 mirrors inside China, which substantially improves download speeds inside China. - -To add these mirrors, edit the following two MSYS2 mirrorlist files before running the setup script. The mirrorlist files can be found in the ``/etc/pacman.d`` directory (i.e. ``c:\msys2\etc\pacman.d``). - -Add these lines at the top of ``mirrorlist.mingw32``:: - - Server = https://mirrors.ustc.edu.cn/msys2/mingw/i686/ - Server = http://mirror.bit.edu.cn/msys2/REPOS/MINGW/i686 - -Add these lines at the top of ``mirrorlist.msys``:: - - Server = http://mirrors.ustc.edu.cn/msys2/msys/$arch - Server = http://mirror.bit.edu.cn/msys2/REPOS/MSYS2/$arch - - -HTTP Proxy -~~~~~~~~~~ - -You can enable an HTTP proxy for MSYS and PIP downloads by setting the ``http_proxy`` variable in the terminal before running the setup script:: - - export http_proxy='http://http.proxy.server:PORT' - -Or with credentials:: - - export http_proxy='http://user:password@http.proxy.server:PORT' - -Add this line to ``/etc/profile`` in the MSYS directory in order to permanently enable the proxy when using MSYS. - - -Alternative Setup: Just download a toolchain -============================================ - -.. include:: /_build/inc/download-links.inc - -If you already have an MSYS2 install or want to do things differently, you can download just the toolchain here: - -|download_link_win32| +Get ESP-IDF +=========== .. note:: - If you followed instructions :ref:`configure-windows-toolchain-from-scratch`, you already have the toolchain and you won't need this download. + Previous versions of ESP-IDF used the **MSYS2 bash terminal** command line. The current cmake-based build system can run in the regular **Windows Command Prompt** which is used here. -.. important:: + If you use a bash-based terminal or PowerShell, please note that some command syntax will be different to what is shown below. - Just having this toolchain is *not enough* to use ESP-IDF on Windows. You will need GNU make, bash, and sed at minimum. The above environments provide all this, plus a host compiler (required for menuconfig support). +Open Command Prompt and run the following commands: + +.. include:: /_build/inc/git-clone-windows.inc + +ESP-IDF will be downloaded into ``%userprofile%\esp\esp-idf``. + +Consult :doc:`/versions` for information about which ESP-IDF version to use in a given situation. + +.. include:: /_build/inc/git-clone-notes.inc + +.. note:: + + Do not miss the ``--recursive`` option. If you have already cloned ESP-IDF without this option, run another command to get all the submodules:: + + cd esp-idf + git submodule update --init + + +Tools +===== + +cmake +^^^^^ + +Download the latest stable release of CMake_ for Windows and run the installer. + +When the installer asks for Install Options, choose either "Add CMake to the system PATH for all users" or "Add CMake to the system PATH for the current user". + +Ninja build +^^^^^^^^^^^ + +.. note:: + Ninja currently only provides binaries for 64-bit Windows. It is possible to use CMake and ``idf.py`` with other build tools, such as mingw-make, on 32-bit windows. However this is currently undocumented. + +Download the ninja_ latest stable Windows release from the (`download page `_). + +The Ninja for Windows download is a .zip file containing a single ``ninja.exe`` file which needs to be unzipped to a directory which is then `added to your Path `_ (or you can choose a directory which is already on your Path). + + +Python 2.x +^^^^^^^^^^ + +Download the latest Python_ 2.7 for Windows installer, and run it. + +The "Customise" step of the Python installer gives a list of options. The last option is "Add python.exe to Path". Change this option to select "Will be installed". + +Once Python is installed, open a Windows Command Prompt from the Start menu and run the following command:: + + pip install --user pyserial + +MConf for IDF +^^^^^^^^^^^^^ + +Download the configuration tool mconf-idf from the `kconfig-frontends releases page `_. This is the ``mconf`` configuration tool with some minor customizations for ESP-IDF. + +This tool will also need to be unzipped to a directory which is then `added to your Path `_. + +Toolchain Setup +=============== + +.. include:: /_build/inc/download-links.inc + +Download the precompiled Windows toolchain: + +|download_link_win32| + +Unzip the zip file to ``C:\Program Files`` (or some other location). The zip file contains a single directory ``xtensa-esp32-elf``. + +Next, the ``bin`` subdirectory of this directory must be `added to your Path `_. For example, the directory to add may be ``C:\Program Files\xtensa-esp32-elf\bin``. + +.. note:: + If you already have the MSYS2 environment (for use with the "GNU Make" build system) installed, you can skip the separate download and add the directory ``C:\msys32\opt\xtensa-esp32-elf\bin`` to the Path instead, as the toolchain is included in the MSYS2 environment. + + +.. _add-directory-windows-path-cmake: + +Adding Directory to Path +======================== + +To add any new directory to your Windows Path environment variable: + +Open the System control panel and navigate to the Environment Variables dialog. (On Windows 10, this is found under Advanced System Settings). + +Double-click the ``Path`` variable (either User or System Path, depending if you want other users to have this directory on their path.) Go to the end of the value, and append ``;``. Next Steps ========== -To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf`. - -.. _updating-existing-windows-environment: - -Updating The Environment -======================== - -When IDF is updated, sometimes new toolchains are required or new system requirements are added to the Windows MSYS2 environment. - -Rather than setting up a new environment, you can update an existing Windows environment & toolchain: - -- Update IDF to the new version you want to use. -- Run the ``tools/windows/windows_install_prerequisites.sh`` script inside IDF. This will install any new software packages that weren't previously installed, and download and replace the toolchain with the latest version. - -The script to update MSYS2 may also fail with the same errors mentioned under Troubleshooting_. - -If you need to support multiple IDF versions concurrently, you can have different independent MSYS2 environments in different directories. Alternatively you can download multiple toolchains and unzip these to different directories, then use the PATH environment variable to set which one is the default. +To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf-cmake`. +.. _ninja: https://ninja-build.org/ +.. _Python: https://www.python.org/downloads/windows/ .. _MSYS2: https://msys2.github.io/ -.. _MSYS2-packages issues list: https://github.com/Alexpux/MSYS2-packages/issues/ -.. _raise an IDF issue: https://github.com/espressif/esp-idf/issues/new +.. _Stable version: https://docs.espressif.com/projects/esp-idf/en/stable/ + diff --git a/docs/en/get-started-cmake/windows-setup-update.rst b/docs/en/get-started/windows-setup-update.rst similarity index 100% rename from docs/en/get-started-cmake/windows-setup-update.rst rename to docs/en/get-started/windows-setup-update.rst diff --git a/docs/en/get-started/windows-setup.rst b/docs/en/get-started/windows-setup.rst index d2a2678283..d226c5f0f7 100644 --- a/docs/en/get-started/windows-setup.rst +++ b/docs/en/get-started/windows-setup.rst @@ -1,70 +1,70 @@ -*************************************** -Standard Setup of Toolchain for Windows -*************************************** +************************************************* +Installation of Prerequisites for Windows (CMake) +************************************************* + :link_to_translation:`zh_CN:[中文]` +.. include:: ../cmake-warning.rst + +.. note:: + The CMake-based build system is only supported on 64-bit versions of Windows. + Introduction ============ -Windows doesn't have a built-in "make" environment, so as well as installing the toolchain you will need a GNU-compatible environment. We use the MSYS2_ environment to provide this. You don't need to use this environment all the time (you can use :doc:`Eclipse ` or some other front-end), but it runs behind the scenes. +ESP-IDF requires some prerequisite tools to be installed so you can build firmware for the ESP32. The prerequisite tools include Python, Git, cross-compilers, menuconfig tool, CMake and Ninja build tools. +For this Getting Started we're going to use the Command Prompt, but after ESP-IDF is installed you can use :doc:`Eclipse ` or another graphical IDE with CMake support instead. -Toolchain Setup -=============== +.. note:: + The GNU Make based build system requires the MSYS2_ Unix compatibility environment on Windows. The CMake-based build system does not require this environment. -The quick setup is to download the Windows all-in-one toolchain & MSYS2 zip file from dl.espressif.com: +.. _get-started-cmake-windows-tools-installer: -https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20190611.zip +ESP-IDF Tools Installer +======================= -Unzip the zip file to ``C:\`` (or some other location, but this guide assumes ``C:\``) and it will create an ``msys32`` directory with a pre-prepared environment. +The easiest way to install ESP-IDF's prerequisites is to download the ESP-IDF Tools installer from this URL: +https://dl.espressif.com/dl/esp-idf-tools-setup-2.0.exe -Check it Out -============ +The installer includes the cross-compilers, OpenOCD, cmake_ and Ninja_ build tool, and a configuration tool called mconf-idf_. The installer can also download and run installers for Python_ 3.7 and `Git For Windows`_ if they are not already installed on the computer. -Open a MSYS2 MINGW32 terminal window by running ``C:\msys32\mingw32.exe``. The environment in this window is a bash shell. Create a directory named ``esp`` that is a default location to develop ESP32 applications. To do so, run the following shell command:: +The installer also offers to download one of the ESP-IDF release versions. - mkdir -p ~/esp +Using the Command Prompt +======================== -By typing ``cd ~/esp`` you can then move to the newly created directory. If there are no error messages you are done with this step. +For the remaining Getting Started steps, we're going to use the Windows Command Prompt. -.. figure:: ../../_static/msys2-terminal-window.png - :align: center - :alt: MSYS2 MINGW32 shell window - :figclass: align-center +ESP-IDF Tools Installer creates a shortcut in the Start menu to launch the ESP-IDF Command Prompt. This shortcut launches the Command Prompt (cmd.exe) and runs ``export.bat`` script to set up the environment variables (``PATH``, ``IDF_PATH`` and others). Inside this command prompt, all the installed tools are available. - MSYS2 MINGW32 shell window +Note that this shortcut is specific to the ESP-IDF directory selected in the ESP-IDF Tools Installer. If you have multiple ESP-IDF directories on the computer (for example, to work with different versions of ESP-IDF), you have two options to use them: -Use this window in the following steps setting up development environment for ESP32. +1. Create a copy of the shortcut created by the ESP-IDF Tools Installer, and change the working directory of the new shortcut to the ESP-IDF directory you wish to use. +2. Alternatively, run ``cmd.exe``, then change to the ESP-IDF directory you wish to use, and run ``export.bat``. Note that unlike the previous option, this way requires Python and Git to be present in ``PATH``. If you get errors related to Python or Git not being found, use the first option. Next Steps ========== -To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf`. - -Updating The Environment -======================== - -When IDF is updated, sometimes new toolchains are required or new requirements are added to the Windows MSYS2 environment. To move any data from an old version of the precompiled environment to a new one: - -- Take the old MSYS2 environment (ie ``C:\msys32``) and move/rename it to a different directory (ie ``C:\msys32_old``). -- Download the new precompiled environment using the steps above. -- Unzip the new MSYS2 environment to ``C:\msys32`` (or another location). -- Find the old ``C:\msys32_old\home`` directory and move this into ``C:\msys32``. -- You can now delete the ``C:\msys32_old`` directory if you no longer need it. - -You can have independent different MSYS2 environments on your system, as long as they are in different directories. - -There are :ref:`also steps to update the existing environment without downloading a new one `, although this is more complex. +If the ESP-IDF Tools Installer has finished successfully, then the development environment setup is complete. Proceed directly to :ref:`get-started-start-project-cmake`. Related Documents ================= +For advanced users who want to customize the install process: + .. toctree:: :maxdepth: 1 windows-setup-scratch - + windows-setup-update .. _MSYS2: https://msys2.github.io/ +.. _cmake: https://cmake.org/download/ +.. _ninja: https://ninja-build.org/ +.. _Python: https://www.python.org/downloads/windows/ +.. _Git for Windows: https://gitforwindows.org/ +.. _mconf-idf: https://github.com/espressif/kconfig-frontends/releases/ +.. _Github Desktop: https://desktop.github.com/ diff --git a/docs/en/hw-reference/get-started-devkitc-v2.rst b/docs/en/hw-reference/get-started-devkitc-v2.rst index 2b558f6e91..bef33a2780 100644 --- a/docs/en/hw-reference/get-started-devkitc-v2.rst +++ b/docs/en/hw-reference/get-started-devkitc-v2.rst @@ -9,7 +9,7 @@ This guide shows how to start using the ESP32-DevKitC V2 development board. What You Need ------------- -* :ref:`ESP32-DevKitC V2 board ` +* ESP32-DevKitC V2 board * USB A / micro USB B cable * Computer running Windows, Linux, or macOS @@ -27,7 +27,7 @@ Functional Description The following figure and the table below describe the key components, interfaces and controls of the ESP32-DevKitC V2 board. -.. _get-started-esp32-devkitc-v2-board-front-cmake: +.. _get-started-esp32-devkitc-v2-board-front-make: .. figure:: ../../_static/esp32-devkitc-v2-functional-overview.png :align: center @@ -71,9 +71,7 @@ Start Application Development Before powering up your ESP32-DevKitC V2, please make sure that the board is in good condition with no obvious signs of damage. -After that, proceed to :doc:`../get-started-cmake/index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. - -If you prefer using an older GNU Make build system, then proceed to respective :ref:`get-started-step-by-step` for the GNU Make. +After that, proceed to :doc:`index`, where Section :ref:`get-started-step-by-step` will quickly help you set up the development environment and then flash an example project onto your board. Related Documents diff --git a/docs/en/hw-reference/get-started-devkitc.rst b/docs/en/hw-reference/get-started-devkitc.rst index d15807dbc8..3d10640252 100644 --- a/docs/en/hw-reference/get-started-devkitc.rst +++ b/docs/en/hw-reference/get-started-devkitc.rst @@ -1,5 +1,5 @@ ESP32-DevKitC V4 Getting Started Guide -============================================== +====================================== :link_to_translation:`zh_CN:[中文]` @@ -9,19 +9,19 @@ This guide shows how to start using the ESP32-DevKitC V4 development board. For What You Need ------------- -* :ref:`ESP32-DevKitC V4 board ` +* ESP32-DevKitC V4 board * USB A / micro USB B cable * Computer running Windows, Linux, or macOS You can skip the introduction sections and go directly to Section `Start Application Development`_. -.. _DevKitC-Overview-cmake: +.. _DevKitC-Overview: Overview -------- -ESP32-DevKitC V4 is a small-sized ESP32-based development board produced by `Espressif `_. Most of the I/O pins are broken out to the pin headers on both sides for easy interfacing. Developers can either connect peripherals with jumper wires or mount ESP32-DevKitC V4 on a breadboard. +ESP32-DevKitC V4 is a small-sized ESP32-based development board produced by `Espressif `_. Most of the I/O pins are broken out to the pin headers on both sides for easy interfacing. Developers can either connect peripherals with jumper wires or mount ESP32-DevKitC V4 on a breadboard. To cover a wide range of user requirements, the following versions of ESP32-DevKitC V4 are available: @@ -46,7 +46,7 @@ Functional Description The following figure and the table below describe the key components, interfaces and controls of the ESP32-DevKitC V4 board. -.. _get-started-esp32-devkitc-board-front-cmake: +.. _get-started-esp32-devkitc-board-front: .. figure:: ../../_static/esp32-devkitc-functional-overview.jpg :align: center @@ -107,6 +107,7 @@ The component C15 may cause the following issues on earlier ESP32-DevKitC V4 boa In case these issues occur, please remove the component. The figure below shows C15 highlighted in yellow. + .. figure:: ../../_static/esp32-devkitc-c15-location.png :align: center :alt: Location of C15 (colored yellow) on ESP32-DevKitC V4 board @@ -121,9 +122,7 @@ Start Application Development Before powering up your ESP32-DevKitC V4, please make sure that the board is in good condition with no obvious signs of damage. -After that, proceed to :doc:`../get-started-cmake/index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. - -If you prefer using an older GNU Make build system, then proceed to respective :ref:`get-started-step-by-step` for the GNU Make. +After that, proceed to :doc:`index`, where Section :ref:`get-started-step-by-step` will quickly help you set up the development environment and then flash an example project onto your board. Board Dimensions diff --git a/docs/en/hw-reference/get-started-pico-kit-v3.rst b/docs/en/hw-reference/get-started-pico-kit-v3.rst index a124582a56..b8b2366f61 100644 --- a/docs/en/hw-reference/get-started-pico-kit-v3.rst +++ b/docs/en/hw-reference/get-started-pico-kit-v3.rst @@ -1,5 +1,5 @@ ESP32-PICO-KIT V3 Getting Started Guide -=============================================== +======================================= :link_to_translation:`zh_CN:[中文]` This guide shows how to get started with the ESP32-PICO-KIT V3 mini development board. For the description of other ESP32-PICO-KIT versions, please check :doc:`../hw-reference/index`. @@ -65,9 +65,7 @@ Start Application Development Before powering up your ESP32-PICO-KIT V3, please make sure that the board is in good condition with no obvious signs of damage. -After that, proceed to :doc:`../get-started-cmake/index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. - -If you prefer using an older GNU Make build system, then proceed to respective :ref:`get-started-step-by-step` for the GNU Make. +After that, proceed to :doc:`index`, where Section :ref:`get-started-step-by-step` will quickly help you set up the development environment and then flash an example project onto your board. Related Documents diff --git a/docs/en/hw-reference/get-started-pico-kit.rst b/docs/en/hw-reference/get-started-pico-kit.rst index 7c7ff7304c..73c4b5ef65 100644 --- a/docs/en/hw-reference/get-started-pico-kit.rst +++ b/docs/en/hw-reference/get-started-pico-kit.rst @@ -10,7 +10,7 @@ This particular description covers ESP32-PICO-KIT V4 and V4.1. The difference is What You Need ------------- -* :ref:`ESP32-PICO-KIT mini development board ` +* :ref:`ESP32-PICO-KIT mini development board ` * USB 2.0 A to Micro B cable * Computer running Windows, Linux, or macOS @@ -58,7 +58,7 @@ Functional Description The following figure and the table below describe the key components, interfaces, and controls of the ESP32-PICO-KIT board. -.. _get-started-pico-kit-v4-board-front-cmake: +.. _get-started-pico-kit-v4-board-front: .. figure:: ../../_static/esp32-pico-kit-v4.1-f-layout.jpeg :align: center @@ -107,7 +107,7 @@ There are three mutually exclusive ways to provide power to the board: Pin Descriptions ---------------- -The two tables below provide the **Name** and **Function** of I/O header pins on both sides of the board, see :ref:`get-started-pico-kit-v4-board-front-cmake`. The pin numbering and header names are the same as in the schematic given in `Related Documents`_. +The two tables below provide the **Name** and **Function** of I/O header pins on both sides of the board, see :ref:`get-started-pico-kit-v4-board-front`. The pin numbering and header names are the same as in the schematic given in `Related Documents`_. Header J2 @@ -116,9 +116,9 @@ Header J2 ====== ================= ====== ====================================================== No. Name Type Function ====== ================= ====== ====================================================== -1 FLASH_SD1 (FSD1) I/O | GPIO8, SD_DATA1, SPID, HS1_DATA1 :ref:`(See 1) ` , U2CTS -2 FLASH_SD3 (FSD3) I/O | GPIO7, SD_DATA0, SPIQ, HS1_DATA0 :ref:`(See 1) ` , U2RTS -3 FLASH_CLK (FCLK) I/O | GPIO6, SD_CLK, SPICLK, HS1_CLK :ref:`(See 1) ` , U1CTS +1 FLASH_SD1 (FSD1) I/O | GPIO8, SD_DATA1, SPID, HS1_DATA1 :ref:`(See 1) ` , U2CTS +2 FLASH_SD3 (FSD3) I/O | GPIO7, SD_DATA0, SPIQ, HS1_DATA0 :ref:`(See 1) ` , U2RTS +3 FLASH_CLK (FCLK) I/O | GPIO6, SD_CLK, SPICLK, HS1_CLK :ref:`(See 1) ` , U1CTS 4 IO21 I/O | GPIO21, VSPIHD, EMAC_TX_EN 5 IO22 I/O | GPIO22, VSPIWP, U0RTS, EMAC_TXD1 6 IO19 I/O | GPIO19, VSPIQ, U0CTS, EMAC_TXD0 @@ -127,8 +127,8 @@ No. Name Type Function 9 IO5 I/O | GPIO5, VSPICS0, HS1_DATA6, EMAC_RX_CLK 10 IO10 I/O | GPIO10, SD_DATA3, SPIWP, HS1_DATA3, U1TXD 11 IO9 I/O | GPIO9, SD_DATA2, SPIHD, HS1_DATA2, U1RXD -12 RXD0 I/O | GPIO3, U0RXD :ref:`(See 3) ` , CLK_OUT2 -13 TXD0 I/O | GPIO1, U0TXD :ref:`(See 3) ` , CLK_OUT3, EMAC_RXD2 +12 RXD0 I/O | GPIO3, U0RXD :ref:`(See 3) ` , CLK_OUT2 +13 TXD0 I/O | GPIO1, U0TXD :ref:`(See 3) ` , CLK_OUT3, EMAC_RXD2 14 IO35 I | ADC1_CH7, RTC_GPIO5 15 IO34 I | ADC1_CH6, RTC_GPIO4 16 IO38 I | GPIO38, ADC1_CH2, RTC_GPIO2 @@ -145,20 +145,20 @@ Header J3 ====== ================= ====== ====================================================== No. Name Type Function ====== ================= ====== ====================================================== -1 FLASH_CS (FCS) I/O | GPIO16, HS1_DATA4 :ref:`(See 1) ` , U2RXD, EMAC_CLK_OUT -2 FLASH_SD0 (FSD0) I/O | GPIO17, HS1_DATA5 :ref:`(See 1) ` , U2TXD, EMAC_CLK_OUT_180 -3 FLASH_SD2 (FSD2) I/O | GPIO11, SD_CMD, SPICS0, HS1_CMD :ref:`(See 1) ` , U1RTS +1 FLASH_CS (FCS) I/O | GPIO16, HS1_DATA4 :ref:`(See 1) ` , U2RXD, EMAC_CLK_OUT +2 FLASH_SD0 (FSD0) I/O | GPIO17, HS1_DATA5 :ref:`(See 1) ` , U2TXD, EMAC_CLK_OUT_180 +3 FLASH_SD2 (FSD2) I/O | GPIO11, SD_CMD, SPICS0, HS1_CMD :ref:`(See 1) ` , U1RTS 4 SENSOR_VP (FSVP) I | GPIO36, ADC1_CH0, RTC_GPIO0 5 SENSOR_VN (FSVN) I | GPIO39, ADC1_CH3, RTC_GPIO3 6 IO25 I/O | GPIO25, DAC_1, ADC2_CH8, RTC_GPIO6, EMAC_RXD0 7 IO26 I/O | GPIO26, DAC_2, ADC2_CH9, RTC_GPIO7, EMAC_RXD1 -8 IO32 I/O | 32K_XP :ref:`(See 2a) ` , ADC1_CH4, TOUCH9, RTC_GPIO9 -9 IO33 I/O | 32K_XN :ref:`(See 2b) ` , ADC1_CH5, TOUCH8, RTC_GPIO8 +8 IO32 I/O | 32K_XP :ref:`(See 2a) ` , ADC1_CH4, TOUCH9, RTC_GPIO9 +9 IO33 I/O | 32K_XN :ref:`(See 2b) ` , ADC1_CH5, TOUCH8, RTC_GPIO8 10 IO27 I/O | GPIO27, ADC2_CH7, TOUCH7, RTC_GPIO17 | EMAC_RX_DV 11 IO14 I/O | ADC2_CH6, TOUCH6, RTC_GPIO16, MTMS, HSPICLK, | HS2_CLK, SD_CLK, EMAC_TXD2 -12 IO12 I/O | ADC2_CH5, TOUCH5, RTC_GPIO15, MTDI :ref:`(See 4) ` , HSPIQ, +12 IO12 I/O | ADC2_CH5, TOUCH5, RTC_GPIO15, MTDI :ref:`(See 4) ` , HSPIQ, | HS2_DATA2, SD_DATA2, EMAC_TXD3 13 IO13 I/O | ADC2_CH4, TOUCH4, RTC_GPIO14, MTCK, HSPID, | HS2_DATA3, SD_DATA3, EMAC_RX_ER @@ -176,7 +176,7 @@ No. Name Type Function ====== ================= ====== ====================================================== -.. _get-started-pico-kit-v4-pin-notes-cmake: +.. _get-started-pico-kit-v4-pin-notes: The following notes give more information about the items in the tables above. @@ -193,9 +193,7 @@ Start Application Development Before powering up your ESP32-PICO-KIT, please make sure that the board is in good condition with no obvious signs of damage. -After that, proceed to :doc:`../get-started-cmake/index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. - -If you prefer using an older GNU Make build system, then proceed to respective :ref:`get-started-step-by-step` for the GNU Make. +After that, proceed to :doc:`index`, where Section :ref:`get-started-step-by-step` will quickly help you set up the development environment and then flash an example project onto your board. Board Dimensions diff --git a/docs/en/hw-reference/get-started-wrover-kit-v2.rst b/docs/en/hw-reference/get-started-wrover-kit-v2.rst index 08da1d59f3..1aa0c6b595 100644 --- a/docs/en/hw-reference/get-started-wrover-kit-v2.rst +++ b/docs/en/hw-reference/get-started-wrover-kit-v2.rst @@ -1,5 +1,5 @@ ESP-WROVER-KIT V2 Getting Started Guide -=============================================== +======================================= :link_to_translation:`zh_CN:[中文]` This guide shows how to get started with the ESP-WROVER-KIT V2 development board and also provides information about its functionality and configuration options. For the description of other ESP-WROVER-KIT versions, please check :doc:`../hw-reference/index`. @@ -52,7 +52,7 @@ Functional Description The following two figures and the table below describe the key components, interfaces, and controls of the ESP-WROVER-KIT board. -.. _get-started-esp-wrover-kit-v2-board-front-cmake: +.. _get-started-esp-wrover-kit-v2-board-front: .. figure:: ../../_static/esp-wrover-kit-v2-layout-front.png :align: center @@ -61,7 +61,7 @@ The following two figures and the table below describe the key components, inter ESP-WROVER-KIT board layout - front -.. _get-started-esp-wrover-kit-v2-board-back-cmake: +.. _get-started-esp-wrover-kit-v2-board-back: .. figure:: ../../_static/esp-wrover-kit-v2-layout-back.png :align: center @@ -116,11 +116,11 @@ I/O All the pins on the ESP32 module are broken out to pin heade MicroSD Card MicroSD card slot for data storage: when ESP32 enters the download mode, GPIO2 cannot be held high. However, a pull-up resistor is required on GPIO2 to enable the MicroSD Card. By default, GPIO2 and the pull-up resistor R153 are disconnected. To enable the SD Card, use jumpers on JP1 as shown in Section `Setup Options`_. -LCD Support for mounting and interfacing a 3.2” SPI (standard 4-wire Serial Peripheral Interface) LCD, as shown on figure :ref:`get-started-esp-wrover-kit-v2-board-back-cmake`. +LCD Support for mounting and interfacing a 3.2” SPI (standard 4-wire Serial Peripheral Interface) LCD, as shown on figure :ref:`get-started-esp-wrover-kit-v2-board-back`. ================== ================================================================================================================================= -.. _get-started-esp-wrover-kit-v2-setup-options-cmake: +.. _get-started-esp-wrover-kit-v2-setup-options: Setup Options ------------- @@ -140,7 +140,7 @@ JP14 |jp14| Enable RTS/CTS flow control for serial communication ======= ================ ========================================================= -.. _get-started-esp-wrover-kit-v2-start-development-cmake: +.. _get-started-esp-wrover-kit-v2-start-development: Start Application Development ----------------------------- @@ -170,9 +170,7 @@ Turn the **Power Switch** to ON, the **5V Power On LED** should light up. Now to Development ^^^^^^^^^^^^^^^^^^ -Proceed to :doc:`../get-started-cmake/index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. - -If you prefer using an older GNU Make build system, then proceed to respective :ref:`get-started-step-by-step` for the GNU Make. +Please proceed to :doc:`index`, where Section :ref:`get-started-step-by-step` will quickly help you set up the development environment and then flash an example project onto your board. Related Documents @@ -194,4 +192,4 @@ Related Documents .. |jp11-tx-rx| image:: ../../_static/wrover-jp11-tx-rx.png .. |jp14| image:: ../../_static/wrover-jp14.png -.. _ESP-WROVER-KIT V2 schematic: https://dl.espressif.com/dl/schematics/ESP-WROVER-KIT_SCH-2.pdf \ No newline at end of file +.. _ESP-WROVER-KIT V2 schematic: https://dl.espressif.com/dl/schematics/ESP-WROVER-KIT_SCH-2.pdf diff --git a/docs/en/hw-reference/get-started-wrover-kit-v3.rst b/docs/en/hw-reference/get-started-wrover-kit-v3.rst index e64e50d7d9..276c6877ba 100644 --- a/docs/en/hw-reference/get-started-wrover-kit-v3.rst +++ b/docs/en/hw-reference/get-started-wrover-kit-v3.rst @@ -1,5 +1,6 @@ + ESP-WROVER-KIT V3 Getting Started Guide -=============================================== +======================================= :link_to_translation:`zh_CN:[中文]` This guide shows how to get started with the ESP-WROVER-KIT V3 development board and also provides information about its functionality and configuration options. For the description of other ESP-WROVER-KIT versions, please check :doc:`../hw-reference/index`. @@ -8,7 +9,7 @@ This guide shows how to get started with the ESP-WROVER-KIT V3 development board What You Need ------------- -* :ref:`ESP-WROVER-KIT V3 board ` +* :ref:`ESP-WROVER-KIT V3 board ` * USB 2.0 cable(A to Micro-B) * Computer running Windows, Linux, or macOS @@ -52,7 +53,7 @@ Functional Description The following two figures and the table below describe the key components, interfaces, and controls of the ESP-WROVER-KIT board. -.. _get-started-esp-wrover-kit-v3-board-front-cmake: +.. _get-started-esp-wrover-kit-v3-board-front: .. figure:: ../../_static/esp-wrover-kit-v3-layout-front.jpg :align: center @@ -61,7 +62,7 @@ The following two figures and the table below describe the key components, inter ESP-WROVER-KIT board layout - front -.. _get-started-esp-wrover-kit-v3-board-back-cmake: +.. _get-started-esp-wrover-kit-v3-board-back: .. figure:: ../../_static/esp-wrover-kit-v3-layout-back.jpg :align: center @@ -118,11 +119,11 @@ I/O All the pins on the ESP32 module are broken out to pin heade MicroSD Card Slot Useful for developing applications that access MicroSD card for data storage and retrieval. -LCD Support for mounting and interfacing a 3.2” SPI (standard 4-wire Serial Peripheral Interface) LCD, as shown on figure :ref:`get-started-esp-wrover-kit-v3-board-back-cmake`. +LCD Support for mounting and interfacing a 3.2” SPI (standard 4-wire Serial Peripheral Interface) LCD, as shown on figure :ref:`get-started-esp-wrover-kit-v3-board-back`. ================== ================================================================================================================================= -.. _get-started-esp-wrover-kit-v3-setup-options-cmake: +.. _get-started-esp-wrover-kit-v3-setup-options: Setup Options ------------- @@ -178,17 +179,17 @@ JTAG, MicroSD IO15 5V Legend: -* NC/XTAL - :ref:`32.768 kHz Oscillator ` -* JTAG - :ref:`JTAG / JP8 ` +* NC/XTAL - :ref:`32.768 kHz Oscillator ` +* JTAG - :ref:`JTAG / JP8 ` * Boot - Boot button / SW2 -* Camera - :ref:`Camera / JP4 ` -* LED - :ref:`RGB LED ` -* MicroSD - :ref:`MicroSD Card / J4 ` -* LCD - :ref:`LCD / U5 ` +* Camera - :ref:`Camera / JP4 ` +* LED - :ref:`RGB LED ` +* MicroSD - :ref:`MicroSD Card / J4 ` +* LCD - :ref:`LCD / U5 ` * PSRAM - only in case ESP32-WROVER is installed -.. _get-started-esp-wrover-kit-v3-xtal-cmake: +.. _get-started-esp-wrover-kit-v3-xtal: 32.768 kHz Oscillator ^^^^^^^^^^^^^^^^^^^^^ @@ -205,7 +206,7 @@ Legend: Since GPIO32 and GPIO33 are connected to the oscillator by default, they are not connected to the JP1 I/O connector to maintain signal integrity. This allocation may be changed from the oscillator to JP1 by desoldering the zero-ohm resistors from positions R11 / R23 and re-soldering them to positions R12 / R24. -.. _get-started-esp-wrover-kit-v3-spi-flash-header-cmake: +.. _get-started-esp-wrover-kit-v3-spi-flash-header: SPI Flash / JP13 ^^^^^^^^^^^^^^^^ @@ -223,10 +224,10 @@ SPI Flash / JP13 .. important:: - The module's flash bus is connected to the jumper block JP13 through zero-ohm resistors R140 ~ R145. If the flash memory needs to operate at the frequency of 80 MHz, for reasons such as improving the integrity of bus signals, you can disolder these resistors to disconnect the module's flash bus from the pin header JP13. + The module's flash bus is connected to the jumper block JP13 through zero-ohm resistors R140 ~ R145. If the flash memory needs to operate at the frequency of 80 MHz, for reasons such as improving the integrity of bus signals, you can desolder these resistors to disconnect the module's flash bus from the pin header JP13. -.. _get-started-esp-wrover-kit-v3-jtag-header-cmake: +.. _get-started-esp-wrover-kit-v3-jtag-header: JTAG / JP8 ^^^^^^^^^^ @@ -242,7 +243,7 @@ JTAG / JP8 ==== ============== ============= -.. _get-started-esp-wrover-kit-v3-camera-header-cmake: +.. _get-started-esp-wrover-kit-v3-camera-header: Camera / JP4 ^^^^^^^^^^^^ @@ -273,7 +274,7 @@ Camera / JP4 * Signals D0 .. D7 denote camera data bus -.. _get-started-esp-wrover-kit-v3-rgb-led-connections-cmake: +.. _get-started-esp-wrover-kit-v3-rgb-led-connections: RGB LED ^^^^^^^ @@ -287,7 +288,7 @@ RGB LED ==== ========== ========= -.. _get-started-esp-wrover-kit-v3-microsd-card-slot-cmake: +.. _get-started-esp-wrover-kit-v3-microsd-card-slot: MicroSD Card ^^^^^^^^^^^^ @@ -305,7 +306,7 @@ MicroSD Card ==== ============== =============== -.. _get-started-esp-wrover-kit-v3-lcd-connector-cmake: +.. _get-started-esp-wrover-kit-v3-lcd-connector: LCD / U5 ^^^^^^^^ @@ -323,7 +324,7 @@ LCD / U5 ==== ============== =============== -.. _get-started-esp-wrover-kit-v3-start-development-cmake: +.. _get-started-esp-wrover-kit-v3-start-development: Start Application Development ----------------------------- @@ -353,9 +354,7 @@ Turn the **Power Switch** to ON, the **5V Power On LED** should light up. Now to Development ^^^^^^^^^^^^^^^^^^ -Proceed to :doc:`../get-started-cmake/index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. - -If you prefer using an older GNU Make build system, then proceed to respective :ref:`get-started-step-by-step` for the GNU Make. +Please proceed to :doc:`index`, where Section :ref:`get-started-step-by-step` will quickly help you set up the development environment and then flash an example project onto your board. Related Documents @@ -379,4 +378,4 @@ Related Documents .. toctree:: :hidden: - get-started-wrover-kit-v2.rst \ No newline at end of file + get-started-wrover-kit-v2.rst diff --git a/docs/en/hw-reference/get-started-wrover-kit.rst b/docs/en/hw-reference/get-started-wrover-kit.rst index 5a40efeb56..0be4409762 100644 --- a/docs/en/hw-reference/get-started-wrover-kit.rst +++ b/docs/en/hw-reference/get-started-wrover-kit.rst @@ -1,5 +1,5 @@ ESP-WROVER-KIT V4.1 Getting Started Guide -================================================= +========================================= :link_to_translation:`zh_CN:[中文]` This guide shows how to get started with the ESP-WROVER-KIT V4.1 development board and also provides information about its functionality and configuration options. For the description of other ESP-WROVER-KIT versions, please check :doc:`../hw-reference/index`. @@ -8,7 +8,7 @@ This guide shows how to get started with the ESP-WROVER-KIT V4.1 development boa What You Need ------------- -* :ref:`ESP-WROVER-KIT V4.1 board ` +* :ref:`ESP-WROVER-KIT V4.1 board ` * USB 2.0 cable(A to Micro-B) * Computer running Windows, Linux, or macOS @@ -51,9 +51,9 @@ The block diagram below shows the main components of ESP-WROVER-KIT and their in Functional Description ---------------------- -The following two figures and the table below describe the key components, interfaces and controls of the ESP-WROVER-KIT board. +The following two figures and the table below describe the key components, interfaces, and controls of the ESP-WROVER-KIT board. -.. _get-started-esp-wrover-kit-v4.1-board-front-cmake: +.. _get-started-esp-wrover-kit-v4.1-board-front: .. figure:: ../../_static/esp-wrover-kit-v4.1-layout-front.png :align: center @@ -62,7 +62,7 @@ The following two figures and the table below describe the key components, inter ESP-WROVER-KIT board layout - front -.. _get-started-esp-wrover-kit-v4.1-board-back-cmake: +.. _get-started-esp-wrover-kit-v4.1-board-back: .. figure:: ../../_static/esp-wrover-kit-v4.1-layout-back.png :align: center @@ -123,11 +123,11 @@ I/O Connector All the pins on the ESP32 module are broken out to pin heade MicroSD Card Slot Useful for developing applications that access MicroSD card for data storage and retrieval. -LCD Support for mounting and interfacing a 3.2” SPI (standard 4-wire Serial Peripheral Interface) LCD, as shown on figure :ref:`get-started-esp-wrover-kit-v4.1-board-back-cmake`. +LCD Support for mounting and interfacing a 3.2” SPI (standard 4-wire Serial Peripheral Interface) LCD, as shown on figure :ref:`get-started-esp-wrover-kit-v4.1-board-back`. ================== ================================================================================================================================= -.. _get-started-esp-wrover-kit-v4.1-setup-options-cmake: +.. _get-started-esp-wrover-kit-v4.1-setup-options: Setup Options ------------- @@ -183,17 +183,17 @@ JTAG, MicroSD IO15 5V Legend: -* NC/XTAL - :ref:`32.768 kHz Oscillator ` -* JTAG - :ref:`JTAG / JP8 ` +* NC/XTAL - :ref:`32.768 kHz Oscillator ` +* JTAG - :ref:`JTAG / JP8 ` * Boot - Boot button / SW2 -* Camera - :ref:`Camera / JP4 ` -* LED - :ref:`RGB LED ` -* MicroSD - :ref:`MicroSD Card / J4 ` -* LCD - :ref:`LCD / U5 ` +* Camera - :ref:`Camera / JP4 ` +* LED - :ref:`RGB LED ` +* MicroSD - :ref:`MicroSD Card / J4 ` +* LCD - :ref:`LCD / U5 ` * PSRAM - ESP32-WROVER-B's PSRAM -.. _get-started-esp-wrover-kit-v4.1-xtal-cmake: +.. _get-started-esp-wrover-kit-v4.1-xtal: 32.768 kHz Oscillator ^^^^^^^^^^^^^^^^^^^^^ @@ -210,7 +210,7 @@ Legend: Since GPIO32 and GPIO33 are connected to the oscillator by default, they are not connected to the JP1 I/O connector to maintain signal integrity. This allocation may be changed from the oscillator to JP1 by desoldering the zero-ohm resistors from positions R11 / R23 and re-soldering them to positions R12 / R24. -.. _get-started-esp-wrover-kit-v4.1-spi-flash-header-cmake: +.. _get-started-esp-wrover-kit-v4.1-spi-flash-header: SPI Flash / JP2 ^^^^^^^^^^^^^^^ @@ -231,7 +231,7 @@ SPI Flash / JP2 The module's flash bus is connected to the jumper block JP2 through zero-ohm resistors R140 ~ R145. If the flash memory needs to operate at the frequency of 80 MHz, for reasons such as improving the integrity of bus signals, you can desolder these resistors to disconnect the module's flash bus from the pin header JP2. -.. _get-started-esp-wrover-kit-v4.1-jtag-header-cmake: +.. _get-started-esp-wrover-kit-v4.1-jtag-header: JTAG / JP2 ^^^^^^^^^^ @@ -247,7 +247,7 @@ JTAG / JP2 ==== ============== ============= -.. _get-started-esp-wrover-kit-v4.1-camera-header-cmake: +.. _get-started-esp-wrover-kit-v4.1-camera-header: Camera / JP4 ^^^^^^^^^^^^ @@ -278,7 +278,7 @@ Camera / JP4 * Signals D0 .. D7 denote camera data bus -.. _get-started-esp-wrover-kit-v4.1-rgb-led-connections-cmake: +.. _get-started-esp-wrover-kit-v4.1-rgb-led-connections: RGB LED ^^^^^^^ @@ -292,7 +292,7 @@ RGB LED ==== ========== ========= -.. _get-started-esp-wrover-kit-v4.1-microsd-card-slot-cmake: +.. _get-started-esp-wrover-kit-v4.1-microsd-card-slot: MicroSD Card ^^^^^^^^^^^^ @@ -310,7 +310,7 @@ MicroSD Card ==== ============== =============== -.. _get-started-esp-wrover-kit-v4.1-lcd-connector-cmake: +.. _get-started-esp-wrover-kit-v4.1-lcd-connector: LCD / U5 ^^^^^^^^ @@ -328,7 +328,7 @@ LCD / U5 ==== ============== =============== -.. _get-started-esp-wrover-kit-start-development-cmake: +.. _get-started-esp-wrover-kit-start-development: Start Application Development ----------------------------- @@ -358,9 +358,7 @@ Turn the **Power Switch** to ON, the **5V Power On LED** should light up. Now to Development ^^^^^^^^^^^^^^^^^^ -Proceed to :doc:`../get-started-cmake/index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. - -If you prefer using an older GNU Make build system, then proceed to respective :ref:`get-started-step-by-step` for the GNU Make. +Please proceed to :doc:`index`, where Section :ref:`get-started-step-by-step` will quickly help you set up the development environment and then flash an example project onto your board. Related Documents @@ -384,4 +382,4 @@ Related Documents :hidden: get-started-wrover-kit-v3.rst - get-started-wrover-kit-v2.rst \ No newline at end of file + get-started-wrover-kit-v2.rst From 2a5b02097ba6f073564dd9cd9e4acaa7c8ccc140 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Mon, 8 Jul 2019 19:14:28 +0800 Subject: [PATCH 285/486] cmake: do not force use of new signature for target_link_libraries --- tools/cmake/component.cmake | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tools/cmake/component.cmake b/tools/cmake/component.cmake index 39b45a738f..6959af26c2 100644 --- a/tools/cmake/component.cmake +++ b/tools/cmake/component.cmake @@ -295,7 +295,15 @@ macro(__component_set_dependencies reqs type) foreach(req ${reqs}) if(req IN_LIST build_component_targets) __component_get_property(req_lib ${req} COMPONENT_LIB) - target_link_libraries(${component_lib} ${type} ${req_lib}) + if("${type}" STREQUAL "PRIVATE") + set_property(TARGET ${component_lib} APPEND PROPERTY LINK_LIBRARIES ${req_lib}) + set_property(TARGET ${component_lib} APPEND PROPERTY INTERFACE_LINK_LIBRARIES $) + elseif("${type}" STREQUAL "PUBLIC") + set_property(TARGET ${component_lib} APPEND PROPERTY LINK_LIBRARIES ${req_lib}) + set_property(TARGET ${component_lib} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${req_lib}) + else() # INTERFACE + set_property(TARGET ${component_lib} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${req_lib}) + endif() endif() endforeach() endmacro() @@ -312,12 +320,7 @@ macro(__component_set_all_dependencies) __component_set_dependencies("${priv_reqs}" PRIVATE) else() __component_get_property(reqs ${component_target} __REQUIRES) - foreach(req ${reqs}) - if(req IN_LIST build_component_targets) - __component_get_property(req_lib ${req} COMPONENT_LIB) - target_link_libraries(${component_lib} INTERFACE ${req_lib}) - endif() - endforeach() + __component_set_dependencies("${reqs}" INTERFACE) endif() endmacro() From 222146845cf7b35ba3aad98452a47b6e552c627f Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 25 Jun 2019 11:26:53 +1000 Subject: [PATCH 286/486] docs: Make CMake build system default, mark GNU Make as legacy option All `-cmake` suffixes are removed Where a GNU Make option is renamed, the `-legacy` suffix is used --- docs/en/api-guides/app_trace.rst | 2 +- docs/en/api-guides/build-system-legacy.rst | 16 +- docs/en/api-guides/build-system.rst | 50 +- docs/en/api-guides/index.rst | 6 +- docs/en/api-guides/jtag-debugging/index.rst | 4 +- .../jtag-debugging/setup-openocd-windows.rst | 2 +- docs/en/api-guides/tools/idf-monitor.rst | 2 +- docs/en/api-guides/ulp-legacy.rst | 5 +- docs/en/api-guides/ulp.rst | 2 +- docs/en/api-guides/unit-tests-legacy.rst | 6 +- docs/en/api-guides/unit-tests.rst | 8 +- docs/en/api-reference/system/heap_debug.rst | 2 +- docs/en/api-reference/template.rst | 2 +- docs/en/cmake-pending-features.rst | 7 - docs/en/cmake-warning.rst | 4 - .../add-idf_path-to-profile.rst | 14 +- .../{get-started => }/eclipse-setup.rst | 12 +- .../establish-serial-connection.rst | 10 +- .../{get-started => }/index.rst | 91 +- .../{get-started => }/linux-setup-scratch.rst | 16 +- .../{get-started => }/linux-setup.rst | 16 +- .../{get-started => }/macos-setup-scratch.rst | 16 +- .../{get-started => }/macos-setup.rst | 14 +- .../{get-started => }/make-project.rst | 6 +- .../toolchain-setup-scratch.rst | 12 +- .../windows-setup-scratch.rst | 16 +- .../{get-started => }/windows-setup.rst | 12 +- .../get-started/add-idf_path-to-profile.rst | 2 +- docs/en/get-started/eclipse-setup.rst | 7 +- .../establish-serial-connection.rst | 6 +- docs/en/get-started/index.rst | 103 +- docs/en/get-started/linux-setup-scratch.rst | 8 +- docs/en/get-started/linux-setup.rst | 12 +- docs/en/get-started/macos-setup-scratch.rst | 6 +- docs/en/get-started/macos-setup.rst | 10 +- .../get-started/toolchain-setup-scratch.rst | 6 +- docs/en/get-started/windows-setup-scratch.rst | 14 +- docs/en/get-started/windows-setup-update.rst | 4 +- docs/en/get-started/windows-setup.rst | 14 +- docs/en/gnu-make-legacy.rst | 1 + docs/en/index.rst | 2 +- docs/page_redirects.txt | 33 +- docs/sphinx-known-warnings.txt | 9 +- docs/zh_CN/api-guides/app_trace.rst | 2 +- docs/zh_CN/api-guides/build-system-cmake.rst | 1083 -------------- docs/zh_CN/api-guides/build-system-legacy.rst | 542 +++++++ docs/zh_CN/api-guides/build-system.rst | 1257 ++++++++++++----- docs/zh_CN/api-guides/index.rst | 8 +- .../zh_CN/api-guides/jtag-debugging/index.rst | 2 +- .../jtag-debugging/setup-openocd-windows.rst | 2 +- docs/zh_CN/api-guides/ulp-cmake.rst | 167 --- docs/zh_CN/api-guides/ulp-legacy.rst | 1 + docs/zh_CN/api-guides/ulp.rst | 168 ++- ...-tests-cmake.rst => unit-tests-legacy.rst} | 60 +- docs/zh_CN/api-guides/unit-tests.rst | 56 +- docs/zh_CN/cmake-pending-features.rst | 10 - docs/zh_CN/cmake-warning.rst | 4 - .../add-idf_path-to-profile.rst | 75 - .../zh_CN/get-started-cmake/eclipse-setup.rst | 11 - .../establish-serial-connection.rst | 155 -- .../get-started-cmake/linux-setup-scratch.rst | 79 -- docs/zh_CN/get-started-cmake/linux-setup.rst | 119 -- .../get-started-cmake/macos-setup-scratch.rst | 88 -- docs/zh_CN/get-started-cmake/macos-setup.rst | 95 -- .../toolchain-setup-scratch.rst | 27 - .../windows-setup-scratch.rst | 94 -- .../windows-setup-update.rst | 3 - .../zh_CN/get-started-cmake/windows-setup.rst | 73 - .../add-idf_path-to-profile.rst | 66 + .../get-started-legacy/eclipse-setup.rst | 115 ++ .../establish-serial-connection.rst | 132 ++ .../index.rst | 335 ++--- .../linux-setup-scratch.rst | 78 + docs/zh_CN/get-started-legacy/linux-setup.rst | 108 ++ .../macos-setup-scratch.rst | 74 + docs/zh_CN/get-started-legacy/macos-setup.rst | 60 + .../make-project.rst | 6 +- .../toolchain-setup-scratch.rst | 1 + .../windows-setup-scratch.rst | 1 + .../get-started-legacy/windows-setup.rst | 69 + .../get-started/add-idf_path-to-profile.rst | 75 +- docs/zh_CN/get-started/eclipse-setup.rst | 114 +- .../establish-serial-connection.rst | 81 +- docs/zh_CN/get-started/index.rst | 268 ++-- .../zh_CN/get-started/linux-setup-scratch.rst | 53 +- docs/zh_CN/get-started/linux-setup.rst | 79 +- .../zh_CN/get-started/macos-setup-scratch.rst | 66 +- docs/zh_CN/get-started/macos-setup.rst | 69 +- .../get-started/toolchain-setup-scratch.rst | 28 +- .../get-started/windows-setup-scratch.rst | 93 +- .../get-started/windows-setup-update.rst | 3 + docs/zh_CN/get-started/windows-setup.rst | 75 +- docs/zh_CN/gnu-make-legacy.rst | 3 + .../hw-reference/get-started-ethernet-kit.rst | 2 +- docs/zh_CN/index.rst | 2 +- .../build_system/cmake/idf_as_lib/README.md | 2 +- .../build_system/cmake/import_lib/README.md | 2 +- tools/unit-test-app/README.md | 4 +- 98 files changed, 3429 insertions(+), 3406 deletions(-) delete mode 100644 docs/en/cmake-pending-features.rst delete mode 100644 docs/en/cmake-warning.rst rename docs/en/get-started-legacy/{get-started => }/add-idf_path-to-profile.rst (76%) rename docs/en/get-started-legacy/{get-started => }/eclipse-setup.rst (95%) rename docs/en/get-started-legacy/{get-started => }/establish-serial-connection.rst (94%) rename docs/en/get-started-legacy/{get-started => }/index.rst (86%) rename docs/en/get-started-legacy/{get-started => }/linux-setup-scratch.rst (80%) rename docs/en/get-started-legacy/{get-started => }/linux-setup.rst (91%) rename docs/en/get-started-legacy/{get-started => }/macos-setup-scratch.rst (75%) rename docs/en/get-started-legacy/{get-started => }/macos-setup.rst (78%) rename docs/en/get-started-legacy/{get-started => }/make-project.rst (95%) rename docs/en/get-started-legacy/{get-started => }/toolchain-setup-scratch.rst (70%) rename docs/en/get-started-legacy/{get-started => }/windows-setup-scratch.rst (93%) rename docs/en/get-started-legacy/{get-started => }/windows-setup.rst (89%) create mode 100644 docs/en/gnu-make-legacy.rst delete mode 100644 docs/zh_CN/api-guides/build-system-cmake.rst create mode 100644 docs/zh_CN/api-guides/build-system-legacy.rst delete mode 100644 docs/zh_CN/api-guides/ulp-cmake.rst create mode 100644 docs/zh_CN/api-guides/ulp-legacy.rst rename docs/zh_CN/api-guides/{unit-tests-cmake.rst => unit-tests-legacy.rst} (82%) delete mode 100644 docs/zh_CN/cmake-pending-features.rst delete mode 100644 docs/zh_CN/cmake-warning.rst delete mode 100644 docs/zh_CN/get-started-cmake/add-idf_path-to-profile.rst delete mode 100644 docs/zh_CN/get-started-cmake/eclipse-setup.rst delete mode 100644 docs/zh_CN/get-started-cmake/establish-serial-connection.rst delete mode 100644 docs/zh_CN/get-started-cmake/linux-setup-scratch.rst delete mode 100644 docs/zh_CN/get-started-cmake/linux-setup.rst delete mode 100644 docs/zh_CN/get-started-cmake/macos-setup-scratch.rst delete mode 100644 docs/zh_CN/get-started-cmake/macos-setup.rst delete mode 100644 docs/zh_CN/get-started-cmake/toolchain-setup-scratch.rst delete mode 100644 docs/zh_CN/get-started-cmake/windows-setup-scratch.rst delete mode 100644 docs/zh_CN/get-started-cmake/windows-setup-update.rst delete mode 100644 docs/zh_CN/get-started-cmake/windows-setup.rst create mode 100644 docs/zh_CN/get-started-legacy/add-idf_path-to-profile.rst create mode 100644 docs/zh_CN/get-started-legacy/eclipse-setup.rst create mode 100644 docs/zh_CN/get-started-legacy/establish-serial-connection.rst rename docs/zh_CN/{get-started-cmake => get-started-legacy}/index.rst (52%) create mode 100644 docs/zh_CN/get-started-legacy/linux-setup-scratch.rst create mode 100644 docs/zh_CN/get-started-legacy/linux-setup.rst create mode 100644 docs/zh_CN/get-started-legacy/macos-setup-scratch.rst create mode 100644 docs/zh_CN/get-started-legacy/macos-setup.rst rename docs/zh_CN/{get-started => get-started-legacy}/make-project.rst (94%) create mode 100644 docs/zh_CN/get-started-legacy/toolchain-setup-scratch.rst create mode 100644 docs/zh_CN/get-started-legacy/windows-setup-scratch.rst create mode 100644 docs/zh_CN/get-started-legacy/windows-setup.rst create mode 100644 docs/zh_CN/get-started/windows-setup-update.rst create mode 100644 docs/zh_CN/gnu-make-legacy.rst diff --git a/docs/en/api-guides/app_trace.rst b/docs/en/api-guides/app_trace.rst index f2e3484978..ccc9379de5 100644 --- a/docs/en/api-guides/app_trace.rst +++ b/docs/en/api-guides/app_trace.rst @@ -149,7 +149,7 @@ In general user should decide what type of data should be transferred in every d return res; } -2. The next step is to build the program image and download it to the target as described in :doc:`Build and Flash <../get-started/make-project>`. +2. The next step is to build the program image and download it to the target as described in the :ref:`Getting Started Guide `. 3. Run OpenOCD (see :doc:`JTAG Debugging <../api-guides/jtag-debugging/index>`). 4. Connect to OpenOCD telnet server. It can be done using the following command in terminal ``telnet 4444``. If telnet session is opened on the same machine which runs OpenOCD you can use ``localhost`` as ```` in the command above. 5. Start trace data collection using special OpenOCD command. This command will transfer tracing data and redirect them to specified file or socket (currently only files are supported as trace data destination). For description of the corresponding commands see `OpenOCD Application Level Tracing Commands`_. diff --git a/docs/en/api-guides/build-system-legacy.rst b/docs/en/api-guides/build-system-legacy.rst index 5f936c05f3..52ca8642c5 100644 --- a/docs/en/api-guides/build-system-legacy.rst +++ b/docs/en/api-guides/build-system-legacy.rst @@ -1,11 +1,13 @@ -Build System -************ +Build System (Legacy GNU Make) +****************************** :link_to_translation:`zh_CN:[中文]` -This document explains the Espressif IoT Development Framework build system and the +.. include:: ../gnu-make-legacy.rst + +This document explains the legacy GNU Make Espressif IoT Development Framework build system and the concept of "components" -Read this document if you want to know how to organise a new ESP-IDF project. +Read this document if you want to know how to organise an ESP-IDF project using GNU Make build system. We recommend using the esp-idf-template_ project as a starting point for your project. @@ -21,7 +23,7 @@ An ESP-IDF project can be seen as an amalgamation of a number of components. For example, for a webserver that shows the current humidity, there could be: - The ESP32 base libraries (libc, rom bindings etc) -- The WiFi drivers +- The Wi-Fi drivers - A TCP/IP stack - The FreeRTOS operating system - A webserver @@ -374,7 +376,7 @@ Some tips for debugging the esp-idf build system: For more debugging tips and general make information, see the `GNU Make Manual`. -.. _warn-undefined-variables: +.. _warn-undefined-variables-legacy: Warning On Undefined Variables ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -619,7 +621,7 @@ is overridden then the component can instruct the linker to link other binaries .. _GNU Make Manual: https://www.gnu.org/software/make/manual/make.html -.. _custom-sdkconfig-defaults: +.. _custom-sdkconfig-defaults-legacy: Custom sdkconfig defaults ------------------------- diff --git a/docs/en/api-guides/build-system.rst b/docs/en/api-guides/build-system.rst index ec63c0fc41..8a28a1e163 100644 --- a/docs/en/api-guides/build-system.rst +++ b/docs/en/api-guides/build-system.rst @@ -1,15 +1,11 @@ -Build System (CMake) -******************** +Build System +************ :link_to_translation:`zh_CN:[中文]` -.. include:: ../cmake-warning.rst +This document explains the implementation of the ESP-IDF build system and the concept of "components". Read this document if you want to know how to organise and build a new ESP-IDF project or component. -.. include:: ../cmake-pending-features.rst - -This document explains the implementation of the CMake-based ESP-IDF build system and the concept of "components". :doc:`Documentation for the GNU Make based build system ` is also available - -Read this document if you want to know how to organise and build a new ESP-IDF project or component using the CMake-based build system. +.. note:: This document describes the CMake-based build system, which is the default since ESP-IDF V4.0. ESP-IDF also supports a :doc:`legacy build system based on GNU Make `, which was the default before ESP-IDF V4.0. Overview @@ -67,7 +63,7 @@ The ``idf.py`` command line tool provides a front-end for easily managing your p - A command line build tool (either Ninja_ build or `GNU Make`) - `esptool.py`_ for flashing ESP32. -The :ref:`getting started guide ` contains a brief introduction to how to set up ``idf.py`` to configure, build, and flash projects. +The :ref:`getting started guide ` contains a brief introduction to how to set up ``idf.py`` to configure, build, and flash projects. ``idf.py`` should be run in an ESP-IDF "project" directory, ie one containing a ``CMakeLists.txt`` file. Older style projects with a Makefile will not work with ``idf.py``. @@ -211,7 +207,7 @@ This example "myProject" contains the following elements: - Optional "components" directory contains components that are part of the project. A project does not have to contain custom components of this kind, but it can be useful for structuring reusable code or including third party components that aren't part of ESP-IDF. -- "main" directory is a special "pseudo-component" that contains source code for the project itself. "main" is a default name, the CMake variable ``COMPONENT_DIRS`` includes this component but you can modify this variable. Alternatively, ``EXTRA_COMPONENT_DIRS`` can be set in the top-level CMakeLists.txt to look for components in other places. See the :ref:`renaming main ` section for more info. If you have a lot of source files in your project, we recommend grouping most into components instead of putting them all in "main". +- "main" directory is a special "pseudo-component" that contains source code for the project itself. "main" is a default name, the CMake variable ``COMPONENT_DIRS`` includes this component but you can modify this variable. Alternatively, ``EXTRA_COMPONENT_DIRS`` can be set in the top-level CMakeLists.txt to look for components in other places. See the :ref:`renaming main ` section for more info. If you have a lot of source files in your project, we recommend grouping most into components instead of putting them all in "main". - "build" directory is where build output is created. This directory is created by ``idf.py`` if it doesn't already exist. CMake configures the project and generates interim build files in this directory. Then, after the main build process is run, this directory will also contain interim object files and libraries as well as final binary output files. This directory is usually not added to source control or distributed with the project source code. @@ -262,7 +258,7 @@ Any paths in these variables can be absolute paths, or set relative to the proje To set these variables, use the `cmake set command `_ ie ``set(VARIABLE "VALUE")``. The ``set()`` commands should be placed after the ``cmake_minimum(...)`` line but before the ``include(...)`` line. -.. _rename-main-cmake: +.. _rename-main: Renaming ``main`` component ---------------------------- @@ -277,12 +273,12 @@ and manually specifying its dependencies. Specifically, the steps to renaming `` 2. Set ``EXTRA_COMPONENT_DIRS`` in the project CMakeLists.txt to include the renamed ``main`` directory. 3. Specify the dependencies in the renamed component's CMakeLists.txt file via REQUIRES or PRIV_REQUIRES arguments :ref:`on component registration`. -.. _component-directories-cmake: +.. _component-directories: Component CMakeLists Files ========================== -Each project contains one or more components. Components can be part of ESP-IDF, part of the project's own components directory, or added from custom component directories (:ref:`see above `). +Each project contains one or more components. Components can be part of ESP-IDF, part of the project's own components directory, or added from custom component directories (:ref:`see above `). A component is any directory in the ``COMPONENT_DIRS`` list which contains a ``CMakeLists.txt`` file. @@ -382,7 +378,7 @@ This can be useful if there is upstream code that emits warnings. When using these commands, place them after the call to ``idf_component_register`` in the component CMakeLists file. -.. _component-configuration-cmake: +.. _component-configuration: Component Configuration ======================= @@ -497,7 +493,11 @@ Some tips for debugging the ESP-IDF CMake-based build system: - Running ``cmake -DDEBUG=1`` will produce more verbose diagnostic output from the IDF build system. - Running ``cmake`` with the ``--trace`` or ``--trace-expand`` options will give a lot of information about control flow. See the `cmake command line documentation`_. -.. _warn-undefined-variables-cmake: +When included from a project CMakeLists file, the ``project.cmake`` file defines some utility modules and global variables and then sets ``IDF_PATH`` if it was not set in the system environment. + +It also defines an overridden custom version of the built-in CMake_ ``project`` function. This function is overridden to add all of the ESP-IDF specific project functionality. + +.. _warn-undefined-variables: Warning On Undefined Variables ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -506,6 +506,8 @@ By default, ``idf.py`` passes the ``--warn-uninitialized`` flag to CMake_ so it If you don't want this behaviour, it can be disabled by passing ``--no-warnings`` to ``idf.py``. +Browse the :idf_file:`/tools/cmake/project.cmake` file and supporting functions in :idf_file:`/tools/cmake/idf_functions.cmake` for more details. + Overriding Parts of the Project ------------------------------- @@ -531,11 +533,12 @@ Take great care when setting variables or targets in a ``project_include.cmake`` KConfig.projbuild ^^^^^^^^^^^^^^^^^ -This is an equivalent to ``project_include.cmake`` for :ref:`component-configuration-cmake` KConfig files. If you want to include +This is an equivalent to ``project_include.cmake`` for :ref:`component-configuration` KConfig files. If you want to include configuration options at the top-level of menuconfig, rather than inside the "Component Configuration" sub-menu, then these can be defined in the KConfig.projbuild file alongside the ``CMakeLists.txt`` file. -Take care when adding configuration values in this file, as they will be included across the entire project configuration. Where possible, it's generally better to create a KConfig file for :ref:`component-configuration-cmake`. +Take care when adding configuration values in this file, as they will be included across the entire project configuration. Where possible, it's generally better to create a KConfig file for :ref:`component-configuration`. +``project_include.cmake`` files are used inside ESP-IDF, for defining project-wide build features such as ``esptool.py`` command line arguments and the ``bootloader`` "special app". Configuration-Only Components ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -770,7 +773,7 @@ CMake has some unusual behaviour around external project builds: The best of these approaches for building an external project will depend on the project itself, its build system, and whether you anticipate needing to frequently recompile the project. -.. _custom-sdkconfig-defaults-cmake: +.. _custom-sdkconfig-defaults: Custom sdkconfig defaults ========================= @@ -1078,9 +1081,8 @@ Commands that set and operate on variables are generally okay to call before ``i The arguments for ``idf_component_register`` include: - SRCS - component source files used for creating a static library for the component; if not specified, component is a treated as a - config-only component and an interface library is created instead. - - SRC_DIRS, EXCLUDE_SRCS - used to glob source files (.c, .cpp, .S) by specifying directories, instead of specifying source files manually via SRCS. - Note that this is subject to the :ref:`limitations of globbing in CMake`. Source files specified in EXCLUDE_SRCS are removed from the globbed files. + config-only component and an interface library is created instead. + - SRC_DIRS, EXCLUDE_SRCS - used to glob source files (.c, .cpp, .S) by specifying directories, instead of specifying source files manually via SRCS. Note that this is subject to the :ref:`limitations of globbing in CMake`. Source files specified in EXCLUDE_SRCS are removed from the globbed files. - INCLUDE_DIRS - paths, relative to the component directory, which will be added to the include search path for all other components which require the current component - PRIV_INCLUDE_DIRS - directory paths, must be relative to the component directory, which will be added to the include search path for this component's source files only - REQUIRES - public component requirements for the component @@ -1109,13 +1111,13 @@ For example, to get the directory of the ``freertos`` component: message(STATUS "The 'freertos' component directory is: ${dir}") - COMPONENT_ALIAS - alias for COMPONENT_LIB used for linking the component to external targets; set by ``idf_build_component`` and alias library itself - is created by ``idf_component_register`` + is created by ``idf_component_register`` - COMPONENT_DIR - component directory; set by ``idf_build_component`` - COMPONENT_LIB - name for created component static/interface library; set by ``idf_build_component`` and library itself - is created by ``idf_component_register`` + is created by ``idf_component_register`` - COMPONENT_NAME - name of the component; set by ``idf_build_component`` based on the component directory name - COMPONENT_TYPE - type of the component, whether LIBRARY or CONFIG_ONLY. A component is of type LIBRARY if it specifies - source files or embeds a file + source files or embeds a file - EMBED_FILES - list of files to embed in component; set from ``idf_component_register`` EMBED_FILES argument - EMBED_TXTFILES - list of text files to embed in component; set from ``idf_component_register`` EMBED_TXTFILES argument - INCLUDE_DIRS - list of component include directories; set from ``idf_component_register`` INCLUDE_DIRS argument diff --git a/docs/en/api-guides/index.rst b/docs/en/api-guides/index.rst index 17ab34fed0..869f7c5d18 100644 --- a/docs/en/api-guides/index.rst +++ b/docs/en/api-guides/index.rst @@ -7,7 +7,7 @@ API Guides General Notes Build System - Build System (CMake) + Build System (Legacy GNU Make) Error Handling Fatal Errors Event Handling @@ -22,9 +22,9 @@ API Guides Partition Tables Secure Boot <../security/secure-boot> ULP Coprocessor - ULP Coprocessor (CMake) + ULP Coprocessor (Legacy GNU Make) Unit Testing - Unit Testing (CMake) + Unit Testing (Legacy GNU Make) Application Level Tracing Console Component ROM debug console diff --git a/docs/en/api-guides/jtag-debugging/index.rst b/docs/en/api-guides/jtag-debugging/index.rst index b65319928a..c7be7711f9 100644 --- a/docs/en/api-guides/jtag-debugging/index.rst +++ b/docs/en/api-guides/jtag-debugging/index.rst @@ -62,7 +62,7 @@ Debugging using JTAG and application loading / monitoring is integrated under th If the :doc:`ESP-WROVER-KIT <../../hw-reference/modules-and-boards>` is used, then connection from PC to ESP32 is done effectively with a single USB cable thanks to FT2232H chip installed on WROVER, which provides two USB channels, one for JTAG and the second for UART connection. -Depending on user preferences, both `debugger` and `make` can be operated directly from terminal / command line, instead from Eclipse. +Depending on user preferences, both `debugger` and `idf.py build` can be operated directly from terminal / command line, instead from Eclipse. .. _jtag-debugging-selecting-jtag-adapter: @@ -197,7 +197,7 @@ You should now see similar output (this log is for ESP-WROVER-KIT):: Upload application for debugging ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Build and upload your application to ESP32 as usual, see :ref:`get-started-build-and-flash`. +Build and upload your application to ESP32 as usual, see :ref:`get-started-build`. Another option is to write application image to flash using OpenOCD via JTAG with commands like this:: diff --git a/docs/en/api-guides/jtag-debugging/setup-openocd-windows.rst b/docs/en/api-guides/jtag-debugging/setup-openocd-windows.rst index fc77d702d1..67eca902a8 100644 --- a/docs/en/api-guides/jtag-debugging/setup-openocd-windows.rst +++ b/docs/en/api-guides/jtag-debugging/setup-openocd-windows.rst @@ -6,7 +6,7 @@ Set up OpenOCD for Windows IDF Tools Installer =================== -If you are using CMake build system and followed the :doc:`/get-started-cmake/windows-setup` with the ``ESP-IDF Tools Installer`` V1.2 or newer, then by default you will already have ``openocd`` installed. +If you are using CMake build system and followed the :doc:`/get-started/windows-setup` with the ``ESP-IDF Tools Installer`` V1.2 or newer, then by default you will already have ``openocd`` installed. ``ESP-IDF Tools Installer`` adds ``openocd`` to the ``PATH`` so that it can be run from any directory. diff --git a/docs/en/api-guides/tools/idf-monitor.rst b/docs/en/api-guides/tools/idf-monitor.rst index cf5bd285ff..c7da5f1e08 100644 --- a/docs/en/api-guides/tools/idf-monitor.rst +++ b/docs/en/api-guides/tools/idf-monitor.rst @@ -30,7 +30,7 @@ For easy interaction with IDF Monitor, use the keyboard shortcuts given in the t +-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | - Ctrl+R | Reset target board via RTS | Resets the target board and re-starts the application via the RTS line (if connected). | +-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| - Ctrl+F | Build and flash the project | Pauses idf_monitor to run the project ``flash`` target, then resumes idf_monitor. Any changed source files are recompiled and then re-flashed. | +| - Ctrl+F | Build and flash the project | Pauses idf_monitor to run the project ``flash`` target, then resumes idf_monitor. Any changed source files are recompiled and then re-flashed. | +-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | - Ctrl+A (or A) | Build and flash the app only | Pauses idf_monitor to run the ``app-flash`` target, then resumes idf_monitor. Similar to the ``flash`` target, but only the main app is built and re-flashed. | +-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/docs/en/api-guides/ulp-legacy.rst b/docs/en/api-guides/ulp-legacy.rst index 8eee8cffd9..658ee49e45 100644 --- a/docs/en/api-guides/ulp-legacy.rst +++ b/docs/en/api-guides/ulp-legacy.rst @@ -1,5 +1,5 @@ -ULP coprocessor programming -=========================== +ULP coprocessor (Legacy GNU Make) +================================= .. toctree:: :maxdepth: 1 @@ -7,6 +7,7 @@ ULP coprocessor programming Instruction set reference Programming using macros (legacy) +.. include:: ../gnu-make-legacy.rst ULP (Ultra Low Power) coprocessor is a simple FSM which is designed to perform measurements using ADC, temperature sensor, and external I2C sensors, while main processors are in deep sleep mode. ULP coprocessor can access RTC_SLOW_MEM memory region, and registers in RTC_CNTL, RTC_IO, and SARADC peripherals. ULP coprocessor uses fixed-width 32-bit instructions, 32-bit memory addressing, and has 4 general purpose 16-bit registers. diff --git a/docs/en/api-guides/ulp.rst b/docs/en/api-guides/ulp.rst index 0391ab73d1..df3b813c75 100644 --- a/docs/en/api-guides/ulp.rst +++ b/docs/en/api-guides/ulp.rst @@ -1,4 +1,4 @@ -ULP coprocessor programming (CMake) +ULP coprocessor programming =================================== :link_to_translation:`zh_CN:[中文]` diff --git a/docs/en/api-guides/unit-tests-legacy.rst b/docs/en/api-guides/unit-tests-legacy.rst index 43346e4b41..60e39bf857 100644 --- a/docs/en/api-guides/unit-tests-legacy.rst +++ b/docs/en/api-guides/unit-tests-legacy.rst @@ -1,7 +1,9 @@ -Unit Testing in ESP32 -===================== +Unit Testing (Legacy GNU Make) +============================== :link_to_translation:`zh_CN:[中文]` +.. include:: ../gnu-make-legacy.rst + ESP-IDF comes with a unit test app based on Unity - unit test framework. Unit tests are integrated in the ESP-IDF repository and are placed in ``test`` subdirectory of each component respectively. Add normal test cases diff --git a/docs/en/api-guides/unit-tests.rst b/docs/en/api-guides/unit-tests.rst index e08b912f87..f2b564aa68 100644 --- a/docs/en/api-guides/unit-tests.rst +++ b/docs/en/api-guides/unit-tests.rst @@ -1,9 +1,7 @@ -Unit Testing in ESP32 (CMake) +Unit Testing in ESP32 ============================= :link_to_translation:`zh_CN:[中文]` -.. include:: ../cmake-warning.rst - ESP-IDF comes with a unit test app based on Unity - unit test framework. Unit tests are integrated in the ESP-IDF repository and are placed in ``test`` subdirectory of each component respectively. Add normal test cases @@ -28,7 +26,7 @@ Identifiers are used to group related test, or tests with specific properties. There is no need to add a main function with ``UNITY_BEGIN()`` and ``​UNITY_END()`` in each test case. ``unity_platform.c`` will run ``UNITY_BEGIN()``, run the tests cases, and then call ``​UNITY_END()``. -The ``test`` subdirectory should contain a :ref:`component CMakeLists.txt `, since they are themselves, +The ``test`` subdirectory should contain a :ref:`component CMakeLists.txt `, since they are themselves, components. ESP-IDF uses the test framework ``unity`` and should be specified as a requirement for the component. Normally, components :ref:`should list their sources manually `; for component tests however, this requirement is relaxed and the use of ``COMPONENT_SRCDIRS`` is advised. @@ -132,7 +130,7 @@ Change into tools/unit-test-app directory to configure and build it: * `idf.py -T all build` - build unit test app with tests for each component having tests in the ``test`` subdirectory. * `idf.py -T xxx build` - build unit test app with tests for specific components. -* `idf.py -T all -E xxx build` - build unit test app with all unit tests, except for unit tests of some components. (For instance: `idf.py -T all -E ulp -E mbedtls build` - build all unit tests exludes ulp and mbedtls components). +* `idf.py -T all -E xxxbuild` - build unit test app with all unit tests, except for unit tests of some components. (For instance: `idf.py -T all -E ulp mbedtls build` - build all unit tests exludes ulp and mbedtls components). When the build finishes, it will print instructions for flashing the chip. You can simply run ``idf.py flash`` to flash all build output. diff --git a/docs/en/api-reference/system/heap_debug.rst b/docs/en/api-reference/system/heap_debug.rst index 51caff1ba3..0c49409bbc 100644 --- a/docs/en/api-reference/system/heap_debug.rst +++ b/docs/en/api-reference/system/heap_debug.rst @@ -250,7 +250,7 @@ An example:: To gather and analyse heap trace do the following on the host: -1. Build the program and download it to the target as described in :doc:`Build and Flash `. +1. Build the program and download it to the target as described in :ref:`Getting Started Guide `. 2. Run OpenOCD (see :doc:`JTAG Debugging `). diff --git a/docs/en/api-reference/template.rst b/docs/en/api-reference/template.rst index 3c14c19b23..ed749c0564 100644 --- a/docs/en/api-reference/template.rst +++ b/docs/en/api-reference/template.rst @@ -79,7 +79,7 @@ API Reference For example see :idf_file:`docs/en/api-reference/wifi/esp_wifi.rst` - 6. Optionally, rather that using ``*.inc`` files, you may want to describe API in you own way. See :idf_file:`docs/en/api-guides/ulp-cmake.rst` for example. + 6. Optionally, rather that using ``*.inc`` files, you may want to describe API in you own way. See :idf_file:`docs/en/api-guides/ulp.rst` for example. Below is the list of common ``.. doxygen...::`` directives: diff --git a/docs/en/cmake-pending-features.rst b/docs/en/cmake-pending-features.rst deleted file mode 100644 index 2223f5d4b7..0000000000 --- a/docs/en/cmake-pending-features.rst +++ /dev/null @@ -1,7 +0,0 @@ -.. important:: - The following features are not yet supported with the CMake-based build system: - - - Eclipse IDE Documentation - - Support for these features will be available before CMake becomes the default build system. - diff --git a/docs/en/cmake-warning.rst b/docs/en/cmake-warning.rst deleted file mode 100644 index 3f97614f45..0000000000 --- a/docs/en/cmake-warning.rst +++ /dev/null @@ -1,4 +0,0 @@ -.. note:: - This is documentation for the CMake-based build system which is currently in preview release. If you encounter any gaps or bugs, please report them in the `Issues `_ section of the ESP-IDF repository. - - The CMake-based build system will become the default build system in ESP-IDF V4.0. The existing GNU Make based build system will be deprecated in ESP-IDF V5.0. diff --git a/docs/en/get-started-legacy/get-started/add-idf_path-to-profile.rst b/docs/en/get-started-legacy/add-idf_path-to-profile.rst similarity index 76% rename from docs/en/get-started-legacy/get-started/add-idf_path-to-profile.rst rename to docs/en/get-started-legacy/add-idf_path-to-profile.rst index 8ce9a9ae6f..2745f7b0e6 100644 --- a/docs/en/get-started-legacy/get-started/add-idf_path-to-profile.rst +++ b/docs/en/get-started-legacy/add-idf_path-to-profile.rst @@ -1,11 +1,13 @@ -Add IDF_PATH to User Profile -============================ +Add IDF_PATH to User Profile (Legacy GNU Make) +============================================== :link_to_translation:`zh_CN:[中文]` +.. include:: ../gnu-make-legacy.rst + To preserve setting of ``IDF_PATH`` environment variable between system restarts, add it to the user profile, following instructions below. -.. _add-idf_path-to-profile-windows: +.. _add-idf_path-to-profile-windows-legacy: Windows ------- @@ -34,10 +36,10 @@ If you do not like to have ``IDF_PATH`` set up permanently in user profile, you export IDF_PATH="C:/msys32/home/user-name/esp/esp-idf" -If you got here from section :ref:`get-started-setup-path`, while installing s/w for ESP32 development, then go back to section :ref:`get-started-start-project`. +If you got here from section :ref:`get-started-setup-path-legacy`, while installing s/w for ESP32 development, then go back to section :ref:`get-started-start-project-legacy`. -.. _add-idf_path-to-profile-linux-macos: +.. _add-idf_path-to-profile-linux-macos-legacy: Linux and MacOS --------------- @@ -62,4 +64,4 @@ If you do not like to have ``IDF_PATH`` set up permanently, you should enter it export IDF_PATH=~/esp/esp-idf -If you got here from section :ref:`get-started-setup-path`, while installing s/w for ESP32 development, then go back to section :ref:`get-started-start-project`. +If you got here from section :ref:`get-started-setup-path-legacy`, while installing s/w for ESP32 development, then go back to section :ref:`get-started-start-project-legacy`. diff --git a/docs/en/get-started-legacy/get-started/eclipse-setup.rst b/docs/en/get-started-legacy/eclipse-setup.rst similarity index 95% rename from docs/en/get-started-legacy/get-started/eclipse-setup.rst rename to docs/en/get-started-legacy/eclipse-setup.rst index d03494ddd7..087ef51e33 100644 --- a/docs/en/get-started-legacy/get-started/eclipse-setup.rst +++ b/docs/en/get-started-legacy/eclipse-setup.rst @@ -1,9 +1,11 @@ -******************************** -Build and Flash with Eclipse IDE -******************************** +************************************************** +Build and Flash with Eclipse IDE (Legacy GNU Make) +************************************************** :link_to_translation:`zh_CN:[中文]` -.. _eclipse-install-steps: +.. include:: ../gnu-make-legacy.rst + +.. _eclipse-install-steps-legacy: Installing Eclipse IDE ====================== @@ -70,7 +72,7 @@ Navigate to "C/C++ Build" -> "Behavior" property page: * Check "Enable parallel build" to enable multiple build jobs in parallel. -.. _eclipse-build-project: +.. _eclipse-build-project-legacy: Building in Eclipse ------------------- diff --git a/docs/en/get-started-legacy/get-started/establish-serial-connection.rst b/docs/en/get-started-legacy/establish-serial-connection.rst similarity index 94% rename from docs/en/get-started-legacy/get-started/establish-serial-connection.rst rename to docs/en/get-started-legacy/establish-serial-connection.rst index 7e0e3a91e1..83a4f933be 100644 --- a/docs/en/get-started-legacy/get-started/establish-serial-connection.rst +++ b/docs/en/get-started-legacy/establish-serial-connection.rst @@ -1,7 +1,9 @@ -Establish Serial Connection with ESP32 -====================================== +Establish Serial Connection with ESP32 (Legacy GNU Make) +======================================================== :link_to_translation:`zh_CN:[中文]` +.. include:: ../gnu-make-legacy.rst + This section provides guidance how to establish serial connection between ESP32 and PC. @@ -73,7 +75,7 @@ MacOS :: ls /dev/cu.* -.. _linux-dialout-group: +.. _linux-dialout-group-legacy: Adding user to ``dialout`` on Linux ----------------------------------- @@ -146,7 +148,7 @@ If you see some legible log, it means serial connection is working and you are r Close serial terminal after verification that communication is working. In next step we are going to use another application to upload ESP32. This application will not be able to access serial port while it is open in terminal. -If you got here from section :ref:`get-started-connect` when installing s/w for ESP32 development, then go back to section :ref:`get-started-configure`. +If you got here from section :ref:`get-started-connect-legacy` when installing s/w for ESP32 development, then go back to section :ref:`get-started-configure-legacy`. .. _esptool documentation: https://github.com/espressif/esptool/wiki/ESP32-Boot-Mode-Selection#automatic-bootloader diff --git a/docs/en/get-started-legacy/get-started/index.rst b/docs/en/get-started-legacy/index.rst similarity index 86% rename from docs/en/get-started-legacy/get-started/index.rst rename to docs/en/get-started-legacy/index.rst index 12ab81c020..bd3d000ce1 100644 --- a/docs/en/get-started-legacy/get-started/index.rst +++ b/docs/en/get-started-legacy/index.rst @@ -1,9 +1,11 @@ -*********** -Get Started -*********** +***************************** +Get Started (Legacy GNU Make) +***************************** :link_to_translation:`zh_CN:[中文]` +.. include:: ../gnu-make-legacy.rst + This document is intended to help you set up the software development environment for the hardware based on Espressif ESP32. After that, a simple example will show you how to use ESP-IDF (Espressif IoT Development Framework) for menu configuration, then how to build and flash firmware onto an ESP32 board. @@ -57,13 +59,12 @@ If you have one of ESP32 development boards listed below, you can click on the l .. toctree:: :maxdepth: 1 - ESP32-DevKitC - ESP-WROVER-KIT - ESP32-PICO-KIT + ESP32-DevKitC <../hw-reference/get-started-devkitc> + ESP-WROVER-KIT <../hw-reference/get-started-wrover-kit> + ESP32-PICO-KIT <../hw-reference/get-started-pico-kit> ESP32-Ethernet-Kit <../hw-reference/get-started-ethernet-kit> - -.. _get-started-step-by-step: +.. _get-started-step-by-step-legacy: Installation Step by Step ========================= @@ -73,22 +74,22 @@ This is a detailed roadmap to walk you through the installation process. Setting up Development Environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* :ref:`get-started-setup-toolchain` for :doc:`Windows `, :doc:`Linux ` or :doc:`MacOS ` -* :ref:`get-started-get-esp-idf` -* :ref:`get-started-setup-path` -* :ref:`get-started-get-packages` +* :ref:`get-started-setup-toolchain-legacy` for :doc:`Windows `, :doc:`Linux ` or :doc:`MacOS ` +* :ref:`get-started-get-esp-idf-legacy` +* :ref:`get-started-setup-path-legacy` +* :ref:`get-started-get-packages-legacy` Creating Your First Project ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* :ref:`get-started-start-project` -* :ref:`get-started-connect` -* :ref:`get-started-configure` -* :ref:`get-started-build-and-flash` -* :ref:`get-started-monitor` +* :ref:`get-started-start-project-legacy` +* :ref:`get-started-connect-legacy` +* :ref:`get-started-configure-legacy` +* :ref:`get-started-build-and-flash-legacy` +* :ref:`get-started-monitor-legacy` -.. _get-started-setup-toolchain: +.. _get-started-setup-toolchain-legacy: Step 1. Set up the Toolchain ============================ @@ -101,36 +102,36 @@ The quickest way to start development with ESP32 is by installing a prebuilt too :hidden: Windows - Linux - MacOS + Linux + MacOS -+-------------------+-------------------+-------------------+ -| |windows-logo| | |linux-logo| | |macos-logo| | -+-------------------+-------------------+-------------------+ -| `Windows`_ | `Linux`_ | `Mac OS`_ | -+-------------------+-------------------+-------------------+ ++-----------------------------+-------------------------+----------------------------------+ +| |windows-logo| | |linux-logo| | |macos-logo| | ++-----------------------------+-------------------------+----------------------------------+ +| `Windows `_ | `Linux `_ | `Mac OS `_ | ++-----------------------------+-------------------------+----------------------------------+ .. |windows-logo| image:: ../../_static/windows-logo.png - :target: ../get-started/windows-setup.html + :target: ../get-started-legacy/windows-setup.html .. |linux-logo| image:: ../../_static/linux-logo.png - :target: ../get-started/linux-setup.html + :target: ../get-started-legacy/linux-setup.html .. |macos-logo| image:: ../../_static/macos-logo.png - :target: ../get-started/macos-setup.html + :target: ../get-started-legacy/macos-setup.html -.. _Windows: ../get-started/windows-setup.html -.. _Linux: ../get-started/linux-setup.html -.. _Mac OS: ../get-started/macos-setup.html +.. _Windows-legacy: ../get-started-legacy/windows-setup.html +.. _Linux-legacy: ../get-started-legacy/linux-setup.html +.. _Mac OS-legacy: ../get-started-legacy/macos-setup.html .. note:: This guide uses the directory ``~/esp`` on Linux and macOS or ``%userprofile%\esp`` on Windows as an installation folder for ESP-IDF. You can use any directory, but you will need to adjust paths for the commands respectively. Keep in mind that ESP-IDF does not support spaces in paths. -Depending on your experience and preferences, you may want to customize your environment instead of using a prebuilt toolchain. To set up the system your own way go to Section :ref:`get-started-customized-setup`. +Depending on your experience and preferences, you may want to customize your environment instead of using a prebuilt toolchain. To set up the system your own way go to Section :ref:`get-started-customized-setup-legacy`. -.. _get-started-get-esp-idf: +.. _get-started-get-esp-idf-legacy: Step 2. Get ESP-IDF =================== @@ -157,17 +158,17 @@ Consult :doc:`/versions` for information about which ESP-IDF version to use in a git submodule update --init -.. _get-started-setup-path: +.. _get-started-setup-path-legacy: Step 3. Set Environment Variables ================================= The toolchain uses the environment variable ``IDF_PATH`` to access the ESP-IDF directory. This variable should be set up on your computer, otherwise projects will not build. -These variables can be set temporarily (per session) or permanently. Please follow the instructions specific to :ref:`Windows ` , :ref:`Linux and MacOS ` in Section :doc:`add-idf_path-to-profile`. +These variables can be set temporarily (per session) or permanently. Please follow the instructions specific to :ref:`Windows ` , :ref:`Linux and MacOS ` in Section :doc:`add-idf_path-to-profile`. -.. _get-started-get-packages: +.. _get-started-get-packages-legacy: Step 4. Install the Required Python Packages ============================================ @@ -185,7 +186,7 @@ The python packages required by ESP-IDF are located in ``IDF_PATH/requirements.t python2.7 -m pip install --user -r $IDF_PATH/requirements.txt -.. _get-started-start-project: +.. _get-started-start-project-legacy: Step 5. Start a Project ======================= @@ -218,7 +219,7 @@ It is also possible to build examples in-place, without copying them first. The esp-idf build system does not support spaces in the paths to either esp-idf or to projects. -.. _get-started-connect: +.. _get-started-connect-legacy: Step 6. Connect Your Device =========================== @@ -238,12 +239,12 @@ If you are not sure how to check the serial port name, please refer to :doc:`est Keep the port name handy as you will need it in the next steps. -.. _get-started-configure: +.. _get-started-configure-legacy: Step 7. Configure ================= -Navigate to your ``hello_world`` directory from :ref:`get-started-start-project` and run the project configuration utility ``menuconfig``. +Navigate to your ``hello_world`` directory from :ref:`get-started-start-project-legacy` and run the project configuration utility ``menuconfig``. Linux and MacOS ~~~~~~~~~~~~~~~ @@ -290,7 +291,7 @@ To navigate and use ``menuconfig``, press the following keys: If you use ESP32-DevKitC board with the **ESP32-SOLO-1** module, enable single core mode (:ref:`CONFIG_FREERTOS_UNICORE`) in menuconfig before flashing examples. -.. _get-started-build-and-flash: +.. _get-started-build-and-flash-legacy: Step 8. Build and Flash ======================= @@ -337,7 +338,7 @@ If there are no issues by the end of the flash process, you will see messages (b If you'd like to use the Eclipse IDE instead of running ``make``, check out the :doc:`Eclipse guide `. -.. _get-started-monitor: +.. _get-started-monitor-legacy: Step 9. Monitor =============== @@ -380,9 +381,9 @@ If IDF monitor fails shortly after the upload, or if instead of the messages abo If you have such a problem, do the following: 1. Exit the monitor. -2. Go back to :ref:`menuconfig `. +2. Go back to :ref:`menuconfig `. 3. Go to Component config --> ESP32-specific --> Main XTAL frequency, then change :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` to 26MHz. -4. After that, :ref:`build and flash ` the application again. +4. After that, :ref:`build and flash ` the application again. .. note:: @@ -429,7 +430,7 @@ Some environment variables can be specified whilst calling ``make`` allowing use Updating ESP-IDF ================ -You should update ESP-IDF from time to time, as newer versions fix bugs and provide new features. The simplest way to do the update is to delete the existing ``esp-idf`` folder and clone it again, as if performing the initial installation described in :ref:`get-started-get-esp-idf`. +You should update ESP-IDF from time to time, as newer versions fix bugs and provide new features. The simplest way to do the update is to delete the existing ``esp-idf`` folder and clone it again, as if performing the initial installation described in :ref:`get-started-get-esp-idf-legacy`. If downloading to a new path, remember to :doc:`add-idf_path-to-profile` so that the toolchain scripts can find ESP-IDF in its release specific location. diff --git a/docs/en/get-started-legacy/get-started/linux-setup-scratch.rst b/docs/en/get-started-legacy/linux-setup-scratch.rst similarity index 80% rename from docs/en/get-started-legacy/get-started/linux-setup-scratch.rst rename to docs/en/get-started-legacy/linux-setup-scratch.rst index 395458153f..476448a42a 100644 --- a/docs/en/get-started-legacy/get-started/linux-setup-scratch.rst +++ b/docs/en/get-started-legacy/linux-setup-scratch.rst @@ -1,11 +1,13 @@ -********************************** -Setup Linux Toolchain from Scratch -********************************** +**************************************************** +Setup Linux Toolchain from Scratch (Legacy GNU Make) +**************************************************** :link_to_translation:`zh_CN:[中文]` +.. include:: ../gnu-make-legacy.rst + .. note:: - Standard process for installing the toolchain is described :doc:`here `. See :ref:`Customized Setup of Toolchain ` section for some of the reasons why installing the toolchain from scratch may be necessary. + Standard process for installing the toolchain is described :doc:`here `. See :ref:`Customized Setup of Toolchain ` section for some of the reasons why installing the toolchain from scratch may be necessary. Install Prerequisites ===================== @@ -24,7 +26,7 @@ To compile with ESP-IDF you need to get the following packages: Some older (pre-2014) Linux distributions may use ``pyserial`` version 2.x which is not supported by ESP-IDF. In this case please install a supported version via ``pip`` as it is described in section - :ref:`get-started-get-packages`. + :ref:`get-started-get-packages-legacy`. Compile the Toolchain from Source ================================= @@ -66,10 +68,10 @@ Build the toolchain:: ./ct-ng build chmod -R u+w builds/xtensa-esp32-elf -Toolchain will be built in ``~/esp/crosstool-NG/builds/xtensa-esp32-elf``. Follow :ref:`instructions for standard setup ` to add the toolchain to your ``PATH``. +Toolchain will be built in ``~/esp/crosstool-NG/builds/xtensa-esp32-elf``. Follow :ref:`instructions for standard setup ` to add the toolchain to your ``PATH``. Next Steps ========== -To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf`. +To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf-legacy`. diff --git a/docs/en/get-started-legacy/get-started/linux-setup.rst b/docs/en/get-started-legacy/linux-setup.rst similarity index 91% rename from docs/en/get-started-legacy/get-started/linux-setup.rst rename to docs/en/get-started-legacy/linux-setup.rst index 7484b4c624..6eb9c20573 100644 --- a/docs/en/get-started-legacy/get-started/linux-setup.rst +++ b/docs/en/get-started-legacy/linux-setup.rst @@ -1,8 +1,10 @@ -************************************* -Standard Setup of Toolchain for Linux -************************************* +******************************************************* +Standard Setup of Toolchain for Linux (Legacy GNU Make) +******************************************************* :link_to_translation:`zh_CN:[中文]` +.. include:: ../gnu-make-legacy.rst + Install Prerequisites ===================== @@ -22,7 +24,7 @@ To compile with ESP-IDF you need to get the following packages: .. note:: - Some older Linux distributions may be missing some of the Python packages listed above (or may use ``pyserial`` version 2.x which is not supported by ESP-IDF). It is possible to install these packages via ``pip`` instead - as described in section :ref:`get-started-get-packages`. + Some older Linux distributions may be missing some of the Python packages listed above (or may use ``pyserial`` version 2.x which is not supported by ESP-IDF). It is possible to install these packages via ``pip`` instead - as described in section :ref:`get-started-get-packages-legacy`. Toolchain Setup =============== @@ -49,7 +51,7 @@ ESP32 toolchain for Linux is available for download from Espressif website: .. include:: /_build/inc/unpack-code-linux32.inc -.. _setup-linux-toolchain-add-it-to-path: +.. _setup-linux-toolchain-add-it-to-path-legacy: 2. The toolchain will be extracted into ``~/esp/xtensa-esp32-elf/`` directory. @@ -82,7 +84,7 @@ ESP32 toolchain for Linux is available for download from Espressif website: Permission issues /dev/ttyUSB0 ------------------------------ -With some Linux distributions you may get the ``Failed to open port /dev/ttyUSB0`` error message when flashing the ESP32. :ref:`This can be solved by adding the current user to the dialout group`. +With some Linux distributions you may get the ``Failed to open port /dev/ttyUSB0`` error message when flashing the ESP32. :ref:`This can be solved by adding the current user to the dialout group`. Arch Linux Users @@ -103,7 +105,7 @@ Alternatively, use crosstool-NG to compile a gdb that links against ncurses 6. Next Steps ========== -To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf`. +To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf-legacy`. Related Documents diff --git a/docs/en/get-started-legacy/get-started/macos-setup-scratch.rst b/docs/en/get-started-legacy/macos-setup-scratch.rst similarity index 75% rename from docs/en/get-started-legacy/get-started/macos-setup-scratch.rst rename to docs/en/get-started-legacy/macos-setup-scratch.rst index a4dfe9d7f1..f96ab3bcdc 100644 --- a/docs/en/get-started-legacy/get-started/macos-setup-scratch.rst +++ b/docs/en/get-started-legacy/macos-setup-scratch.rst @@ -1,11 +1,13 @@ -*************************************** -Setup Toolchain for Mac OS from Scratch -*************************************** +********************************************************* +Setup Toolchain for Mac OS from Scratch (Legacy GNU Make) +********************************************************* :link_to_translation:`zh_CN:[中文]` +.. include:: ../gnu-make-legacy.rst + .. note:: - Standard process for installing the toolchain is described :doc:`here `. See :ref:`Customized Setup of Toolchain ` section for some of the reasons why installing the toolchain from scratch may be necessary. + Standard process for installing the toolchain is described :doc:`here `. See :ref:`Customized Setup of Toolchain ` section for some of the reasons why installing the toolchain from scratch may be necessary. Install Prerequisites ===================== @@ -16,7 +18,7 @@ Install Prerequisites .. note:: - ``pip`` will be used later for installing :ref:`the required Python packages `. + ``pip`` will be used later for installing :ref:`the required Python packages `. Compile the Toolchain from Source ================================= @@ -63,10 +65,10 @@ Build the toolchain:: ./ct-ng build chmod -R u+w builds/xtensa-esp32-elf -Toolchain will be built in ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf``. Follow :ref:`instructions for standard setup ` to add the toolchain to your ``PATH``. +Toolchain will be built in ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf``. Follow :ref:`instructions for standard setup ` to add the toolchain to your ``PATH``. Next Steps ========== -To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf`. +To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf-legacy`. diff --git a/docs/en/get-started-legacy/get-started/macos-setup.rst b/docs/en/get-started-legacy/macos-setup.rst similarity index 78% rename from docs/en/get-started-legacy/get-started/macos-setup.rst rename to docs/en/get-started-legacy/macos-setup.rst index 7e1921a6c3..555cdda05f 100644 --- a/docs/en/get-started-legacy/get-started/macos-setup.rst +++ b/docs/en/get-started-legacy/macos-setup.rst @@ -1,8 +1,10 @@ -************************************** -Standard Setup of Toolchain for Mac OS -************************************** +******************************************************** +Standard Setup of Toolchain for Mac OS (Legacy GNU Make) +******************************************************** :link_to_translation:`zh_CN:[中文]` +.. include:: ../gnu-make-legacy.rst + Install Prerequisites ===================== @@ -12,7 +14,7 @@ Install Prerequisites .. note:: - ``pip`` will be used later for installing :ref:`the required Python packages `. + ``pip`` will be used later for installing :ref:`the required Python packages `. Toolchain Setup =============== @@ -27,7 +29,7 @@ Download this file, then extract it in ``~/esp`` directory: .. include:: /_build/inc/unpack-code-osx.inc -.. _setup-macos-toolchain-add-it-to-path: +.. _setup-macos-toolchain-add-it-to-path-legacy: The toolchain will be extracted into ``~/esp/xtensa-esp32-elf/`` directory. @@ -45,7 +47,7 @@ Then when you need the toolchain you can type ``get_esp32`` on the command line Next Steps ========== -To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf`. +To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf-legacy`. Related Documents diff --git a/docs/en/get-started-legacy/get-started/make-project.rst b/docs/en/get-started-legacy/make-project.rst similarity index 95% rename from docs/en/get-started-legacy/get-started/make-project.rst rename to docs/en/get-started-legacy/make-project.rst index 8f27c89272..4a0e696806 100644 --- a/docs/en/get-started-legacy/get-started/make-project.rst +++ b/docs/en/get-started-legacy/make-project.rst @@ -1,7 +1,9 @@ -Build and Flash with Make -========================= +Build and Flash with Make (Legacy GNU Make) +=========================================== :link_to_translation:`zh_CN:[中文]` +.. include:: ../gnu-make-legacy.rst + Finding a project ----------------- diff --git a/docs/en/get-started-legacy/get-started/toolchain-setup-scratch.rst b/docs/en/get-started-legacy/toolchain-setup-scratch.rst similarity index 70% rename from docs/en/get-started-legacy/get-started/toolchain-setup-scratch.rst rename to docs/en/get-started-legacy/toolchain-setup-scratch.rst index c5f2b5ae4a..a191814315 100644 --- a/docs/en/get-started-legacy/get-started/toolchain-setup-scratch.rst +++ b/docs/en/get-started-legacy/toolchain-setup-scratch.rst @@ -1,10 +1,12 @@ -.. _get-started-customized-setup: +.. _get-started-customized-setup-legacy: -***************************** -Customized Setup of Toolchain -***************************** +*********************************************** +Customized Setup of Toolchain (Legacy GNU Make) +*********************************************** -Instead of downloading binary toolchain from Espressif website (see :ref:`get-started-setup-toolchain`) you may build the toolchain yourself. +Instead of downloading binary toolchain from Espressif website (see :ref:`get-started-setup-toolchain-legacy`) you may build the toolchain yourself. + +.. include:: ../gnu-make-legacy.rst If you can't think of a reason why you need to build it yourself, then probably it's better to stick with the binary version. However, here are some of the reasons why you might want to compile it from source: diff --git a/docs/en/get-started-legacy/get-started/windows-setup-scratch.rst b/docs/en/get-started-legacy/windows-setup-scratch.rst similarity index 93% rename from docs/en/get-started-legacy/get-started/windows-setup-scratch.rst rename to docs/en/get-started-legacy/windows-setup-scratch.rst index fc64e2a233..6f2a291e9d 100644 --- a/docs/en/get-started-legacy/get-started/windows-setup-scratch.rst +++ b/docs/en/get-started-legacy/windows-setup-scratch.rst @@ -1,13 +1,15 @@ -************************************ -Setup Windows Toolchain from Scratch -************************************ +****************************************************** +Setup Windows Toolchain from Scratch (Legacy GNU Make) +****************************************************** + +.. include:: ../gnu-make-legacy.rst Setting up the environment gives you some more control over the process, and also provides the information for advanced users to customize the install. The :doc:`pre-built environment `, addressed to less experienced users, has been prepared by following these steps. To quickly setup the toolchain in standard way, using a prebuilt environment, proceed to section :doc:`windows-setup`. -.. _configure-windows-toolchain-from-scratch: +.. _configure-windows-toolchain-from-scratch-legacy: Configure Toolchain & Environment from Scratch ============================================== @@ -84,7 +86,7 @@ If you already have an MSYS2 install or want to do things differently, you can d .. note:: - If you followed instructions :ref:`configure-windows-toolchain-from-scratch`, you already have the toolchain and you won't need this download. + If you followed instructions :ref:`configure-windows-toolchain-from-scratch-legacy`, you already have the toolchain and you won't need this download. .. important:: @@ -94,9 +96,9 @@ If you already have an MSYS2 install or want to do things differently, you can d Next Steps ========== -To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf`. +To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf-legacy`. -.. _updating-existing-windows-environment: +.. _updating-existing-windows-environment-legacy: Updating The Environment ======================== diff --git a/docs/en/get-started-legacy/get-started/windows-setup.rst b/docs/en/get-started-legacy/windows-setup.rst similarity index 89% rename from docs/en/get-started-legacy/get-started/windows-setup.rst rename to docs/en/get-started-legacy/windows-setup.rst index d2a2678283..79597ad399 100644 --- a/docs/en/get-started-legacy/get-started/windows-setup.rst +++ b/docs/en/get-started-legacy/windows-setup.rst @@ -1,8 +1,10 @@ -*************************************** -Standard Setup of Toolchain for Windows -*************************************** +********************************************************* +Standard Setup of Toolchain for Windows (Legacy GNU Make) +********************************************************* :link_to_translation:`zh_CN:[中文]` +.. include:: ../gnu-make-legacy.rst + Introduction ============ @@ -41,7 +43,7 @@ Use this window in the following steps setting up development environment for ES Next Steps ========== -To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf`. +To carry on with development environment setup, proceed to section :ref:`get-started-get-esp-idf-legacy`. Updating The Environment ======================== @@ -56,7 +58,7 @@ When IDF is updated, sometimes new toolchains are required or new requirements a You can have independent different MSYS2 environments on your system, as long as they are in different directories. -There are :ref:`also steps to update the existing environment without downloading a new one `, although this is more complex. +There are :ref:`also steps to update the existing environment without downloading a new one `, although this is more complex. Related Documents ================= diff --git a/docs/en/get-started/add-idf_path-to-profile.rst b/docs/en/get-started/add-idf_path-to-profile.rst index cdaf9a5b88..9d4fa4ff4c 100644 --- a/docs/en/get-started/add-idf_path-to-profile.rst +++ b/docs/en/get-started/add-idf_path-to-profile.rst @@ -1,3 +1,3 @@ :orphan: -.. Remove this file when the Chinese translation of CMake getting started guide is updated +.. Remove this file when the Chinese translation of getting started guide is updated diff --git a/docs/en/get-started/eclipse-setup.rst b/docs/en/get-started/eclipse-setup.rst index 2e2b105bc2..26c694e36a 100644 --- a/docs/en/get-started/eclipse-setup.rst +++ b/docs/en/get-started/eclipse-setup.rst @@ -1,12 +1,9 @@ **************************************** -Build and Flash with Eclipse IDE (CMake) +Build and Flash with Eclipse IDE **************************************** :link_to_translation:`zh_CN:[中文]` -.. include:: ../cmake-warning.rst - Documentation for Eclipse setup with CMake-based build system and Eclipse CDT is coming soon. -.. _eclipse.org: https://www.eclipse.org/ - +If you require Eclipse IDE support for this pre-release version of ESP-IDF, you can follow the :doc:`legacy GNU Make build system Getting Started guide ` which has steps for :doc:`Building and Flashing with Eclipse IDE `. diff --git a/docs/en/get-started/establish-serial-connection.rst b/docs/en/get-started/establish-serial-connection.rst index a02e04c88b..2b15682640 100644 --- a/docs/en/get-started/establish-serial-connection.rst +++ b/docs/en/get-started/establish-serial-connection.rst @@ -1,4 +1,4 @@ -Establish Serial Connection with ESP32 (CMake) +Establish Serial Connection with ESP32 ============================================== :link_to_translation:`zh_CN:[中文]` @@ -78,7 +78,7 @@ MacOS :: MacOS users: if you don't see the serial port then check you have the USB/serial drivers installed as shown in the Getting Started guide for your particular development board. For MacOS High Sierra (10.13), you may also have to explicitly allow the drivers to load. Open System Preferences -> Security & Privacy -> General and check if there is a message shown here about "System Software from developer ..." where the developer name is Silicon Labs or FTDI. -.. _linux-dialout-group-cmake: +.. _linux-dialout-group: Adding user to ``dialout`` on Linux ----------------------------------- @@ -151,6 +151,6 @@ If you can see readable log output, it means serial connection is working and yo Close serial terminal after verification that communication is working. In the next step we are going to use a different application to upload a new firmware to ESP32. This application will not be able to access serial port while it is open in terminal. -If you got here from :ref:`get-started-connect-cmake` when installing s/w for ESP32 development, then you can continue with :ref:`get-started-configure-cmake`. +If you got here from :ref:`get-started-connect` when installing s/w for ESP32 development, then you can continue with :ref:`get-started-configure`. .. _esptool documentation: https://github.com/espressif/esptool/wiki/ESP32-Boot-Mode-Selection#automatic-bootloader diff --git a/docs/en/get-started/index.rst b/docs/en/get-started/index.rst index e5f810c093..a60684e35b 100644 --- a/docs/en/get-started/index.rst +++ b/docs/en/get-started/index.rst @@ -1,13 +1,9 @@ -******************* -Get Started (CMake) -******************* +*********** +Get Started +*********** :link_to_translation:`zh_CN:[中文]` -.. include:: ../cmake-warning.rst - -.. include:: ../cmake-pending-features.rst - This document is intended to help you set up the software development environment for the hardware based on the ESP32 chip by Espressif. After that, a simple example will show you how to use ESP-IDF (Espressif IoT Development Framework) for menu configuration, then building, and flashing firmware onto an ESP32 board. @@ -46,7 +42,7 @@ Software: * **Text editor** to write programs (**Projects**) in C, e.g., `Eclipse `_ -.. figure:: ../../_static/what-you-need-cmake.png +.. figure:: ../../_static/what-you-need.png :align: center :alt: Development of applications for ESP32 :figclass: align-center @@ -68,7 +64,7 @@ If you have one of ESP32 development boards listed below, you can click on the l ESP32-Ethernet-Kit <../hw-reference/get-started-ethernet-kit> -.. _get-started-step-by-step-cmake: +.. _get-started-step-by-step: Installation Step by Step ========================= @@ -78,23 +74,23 @@ This is a detailed roadmap to walk you through the installation process. Setting up Development Environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* :ref:`get-started-get-prerequisites-cmake` for :doc:`Windows `, :doc:`Linux ` or :doc:`macOS ` -* :ref:`get-started-get-esp-idf-cmake` -* :ref:`get-started-set-up-tools-cmake` -* :ref:`get-started-set-up-env-cmake` +* :ref:`get-started-get-prerequisites` for :doc:`Windows `, :doc:`Linux ` or :doc:`macOS ` +* :ref:`get-started-get-esp-idf` +* :ref:`get-started-set-up-tools` +* :ref:`get-started-set-up-env` Creating Your First Project ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* :ref:`get-started-start-project-cmake` -* :ref:`get-started-connect-cmake` -* :ref:`get-started-configure-cmake` -* :ref:`get-started-build-cmake` -* :ref:`get-started-flash-cmake` -* :ref:`get-started-build-monitor-cmake` +* :ref:`get-started-start-project` +* :ref:`get-started-connect` +* :ref:`get-started-configure` +* :ref:`get-started-build` +* :ref:`get-started-flash` +* :ref:`get-started-build-monitor` -.. _get-started-get-prerequisites-cmake: +.. _get-started-get-prerequisites: Step 1. Install prerequisites ============================= @@ -108,20 +104,33 @@ Some tools need to be installed on the computer before proceeding to the next st Linux macOS -* :doc:`windows-setup` -* :doc:`linux-setup` -* :doc:`macos-setup` ++-------------------+-------------------+-------------------+ +| |windows-logo| | |linux-logo| | |macos-logo| | ++-------------------+-------------------+-------------------+ +| `Windows`_ | `Linux`_ | `Mac OS`_ | ++-------------------+-------------------+-------------------+ -.. _get-started-get-esp-idf-cmake: +.. |windows-logo| image:: ../../_static/windows-logo.png + :target: ../get-started/windows-setup.html + +.. |linux-logo| image:: ../../_static/linux-logo.png + :target: ../get-started/linux-setup.html + +.. |macos-logo| image:: ../../_static/macos-logo.png + :target: ../get-started/macos-setup.html + +.. _Windows: ../get-started/windows-setup.html +.. _Linux: ../get-started/linux-setup.html +.. _Mac OS: ../get-started/macos-setup.html + +.. _get-started-get-esp-idf: Step 2. Get ESP-IDF =================== To build applications for the ESP32, you need the software libraries provided by Espressif in `ESP-IDF repository `_. -Get ESP-IDF in accordance with your operating system. - -To get ESP-IDF, navigate to your installation directory and clone the repository with ``git clone``. +To get ESP-IDF, navigate to your installation directory and clone the repository with ``git clone``, following instructions below specific to your operating system. .. note:: @@ -141,13 +150,13 @@ Consult :doc:`/versions` for information about which ESP-IDF version to use in a Windows ~~~~~~~ -In addition to installing the tools, :ref:`get-started-cmake-windows-tools-installer` for Windows introduced in Step 1 can also download a copy of ESP-IDF. +In addition to installing the tools, :ref:`get-started-windows-tools-installer` for Windows introduced in Step 1 can also download a copy of ESP-IDF. Consult :doc:`/versions` for information about which ESP-IDF version to use in a given situation. -If you wish to download ESP-IDF without the help of ESP-IDF Tools Installer, refer to these :ref:`instructions `. +If you wish to download ESP-IDF without the help of ESP-IDF Tools Installer, refer to these :ref:`instructions `. -.. _get-started-set-up-tools-cmake: +.. _get-started-set-up-tools: Step 3. Set up the tools ======================== @@ -157,7 +166,7 @@ Aside from the ESP-IDF, you also need to install the tools used by ESP-IDF, such Windows ~~~~~~~ -:ref:`get-started-cmake-windows-tools-installer` for Windows introduced in Step 1 installs all the required tools. +:ref:`get-started-windows-tools-installer` for Windows introduced in Step 1 installs all the required tools. If you want to install the tools without the help of ESP-IDF Tools Installer, open the Command Prompt and follow these steps: @@ -181,7 +190,7 @@ The scripts introduced in this step install compilation tools required by ESP-ID If changing the ``IDF_TOOLS_PATH``, make sure it is set to the same value every time the ``install.bat``/``install.sh`` and ``export.bat``/``export.sh`` scripts are executed. -.. _get-started-set-up-env-cmake: +.. _get-started-set-up-env: Step 4. Set up the environment variables ======================================== @@ -191,7 +200,7 @@ The installed tools are not yet added to the PATH environment variable. To make Windows ~~~~~~~ -:ref:`get-started-cmake-windows-tools-installer` for Windows creates an "ESP-IDF Command Prompt" shortcut in the Start Menu. This shortcut opens the Command Prompt and sets up all the required environment variables. You can open this shortcut and proceed to the next step. +:ref:`get-started-windows-tools-installer` for Windows creates an "ESP-IDF Command Prompt" shortcut in the Start Menu. This shortcut opens the Command Prompt and sets up all the required environment variables. You can open this shortcut and proceed to the next step. Alternatively, if you want to use ESP-IDF in an existing Command Prompt window, you can run: @@ -212,7 +221,7 @@ Note the space between the leading dot and the path! You can also automate this step, making ESP-IDF tools available in every terminal, by adding this line to your ``.profile`` or ``.bash_profile`` script. -.. _get-started-start-project-cmake: +.. _get-started-start-project: Step 5. Start a Project ======================= @@ -245,7 +254,7 @@ It is also possible to build examples in-place, without copying them first. The ESP-IDF build system does not support spaces in the paths to either ESP-IDF or to projects. -.. _get-started-connect-cmake: +.. _get-started-connect: Step 6. Connect Your Device =========================== @@ -265,12 +274,12 @@ If you are not sure how to check the serial port name, please refer to :doc:`est Keep the port name handy as you will need it in the next steps. -.. _get-started-configure-cmake: +.. _get-started-configure: Step 7. Configure ================= -Navigate to your ``hello_world`` directory from :ref:`get-started-start-project-cmake` and run the project configuration utility ``menuconfig``. +Navigate to your ``hello_world`` directory from :ref:`get-started-start-project` and run the project configuration utility ``menuconfig``. Linux and macOS ~~~~~~~~~~~~~~~ @@ -313,7 +322,7 @@ To navigate and use ``menuconfig``, press the following keys: If you use ESP32-DevKitC board with the **ESP32-SOLO-1** module, enable single core mode (:ref:`CONFIG_FREERTOS_UNICORE`) in menuconfig before flashing examples. -.. _get-started-build-cmake: +.. _get-started-build: Step 8. Build the Project ========================= @@ -347,7 +356,7 @@ This command will compile the application and all ESP-IDF components, then it wi If there are no errors, the build will finish by generating the firmware binary .bin file. -.. _get-started-flash-cmake: +.. _get-started-flash: Step 9. Flash onto the Device ============================= @@ -356,7 +365,7 @@ Flash the binaries that you just built onto your ESP32 board by running:: idf.py -p PORT [-b BAUD] flash -Replace PORT with your ESP32 board's serial port name from :ref:`get-started-connect-cmake`. +Replace PORT with your ESP32 board's serial port name from :ref:`get-started-connect`. You can also change the flasher baud rate by replacing BAUD with the baud rate you need. The default baud rate is ``460800``. @@ -402,7 +411,7 @@ If there are no issues by the end of the flash process, the module will be reset .. (Not currently supported) If you'd like to use the Eclipse IDE instead of running ``idf.py``, check out the :doc:`Eclipse guide `. -.. _get-started-build-monitor-cmake: +.. _get-started-build-monitor: Step 10. Monitor ================ @@ -446,9 +455,9 @@ If IDF monitor fails shortly after the upload, or, if instead of the messages ab If you have such a problem, do the following: 1. Exit the monitor. -2. Go back to :ref:`menuconfig `. +2. Go back to :ref:`menuconfig `. 3. Go to Component config --> ESP32-specific --> Main XTAL frequency, then change :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` to 26MHz. -4. After that, :ref:`build and flash ` the application again. +4. After that, :ref:`build and flash ` the application again. .. note:: @@ -468,13 +477,13 @@ Now you are ready to try some other :idf:`examples`, or go straight to developin Updating ESP-IDF ================ -You should update ESP-IDF from time to time, as newer versions fix bugs and provide new features. The simplest way to do the update is to delete the existing ``esp-idf`` folder and clone it again, as if performing the initial installation described in :ref:`get-started-get-esp-idf-cmake`. +You should update ESP-IDF from time to time, as newer versions fix bugs and provide new features. The simplest way to do the update is to delete the existing ``esp-idf`` folder and clone it again, as if performing the initial installation described in :ref:`get-started-get-esp-idf`. Another solution is to update only what has changed. :ref:`The update procedure depends on the version of ESP-IDF you are using `. -After updating ESP-IDF, execute ``install.sh`` (``install.bat`` on Windows) again, in case the new ESP-IDF version requires different versions of tools. See instructions at :ref:`get-started-set-up-tools-cmake`. +After updating ESP-IDF, execute ``install.sh`` (``install.bat`` on Windows) again, in case the new ESP-IDF version requires different versions of tools. See instructions at :ref:`get-started-set-up-tools`. -Once the new tools are installed, update the environment using ``export.sh`` (``export.bat`` on Windows). See instructions at :ref:`get-started-set-up-env-cmake`. +Once the new tools are installed, update the environment using ``export.sh`` (``export.bat`` on Windows). See instructions at :ref:`get-started-set-up-env`. Related Documents ================= @@ -488,4 +497,4 @@ Related Documents toolchain-setup-scratch .. _Stable version: https://docs.espressif.com/projects/esp-idf/en/stable/ -.. _Releases page: https://github.com/espressif/esp-idf/releases \ No newline at end of file +.. _Releases page: https://github.com/espressif/esp-idf/releases diff --git a/docs/en/get-started/linux-setup-scratch.rst b/docs/en/get-started/linux-setup-scratch.rst index 51abaf6fd3..a96992c062 100644 --- a/docs/en/get-started/linux-setup-scratch.rst +++ b/docs/en/get-started/linux-setup-scratch.rst @@ -1,11 +1,9 @@ ****************************************** -Setup Linux Toolchain from Scratch (CMake) +Setup Linux Toolchain from Scratch ****************************************** :link_to_translation:`zh_CN:[中文]` -.. include:: ../cmake-warning.rst - The following instructions are alternative to downloading binary toolchain from Espressif website. To quickly setup the binary toolchain, instead of compiling it yourself, backup and proceed to section :doc:`linux-setup`. Install Prerequisites @@ -68,10 +66,10 @@ Build the toolchain:: ./ct-ng build chmod -R u+w builds/xtensa-esp32-elf -Toolchain will be built in ``~/esp/crosstool-NG/builds/xtensa-esp32-elf``. To use it, you need to add ``~/esp/crosstool-NG/builds/xtensa-esp32-elf/bin`` to ``PATH`` environment variable. +Toolchain will be built in ``~/esp/crosstool-NG/builds/xtensa-esp32-elf``. Follow `instructions for standard setup `_ to add the toolchain to your ``PATH``. Next Steps ========== -To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf-cmake`. +To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf`. diff --git a/docs/en/get-started/linux-setup.rst b/docs/en/get-started/linux-setup.rst index 429755b9bd..a9afdfc207 100644 --- a/docs/en/get-started/linux-setup.rst +++ b/docs/en/get-started/linux-setup.rst @@ -1,11 +1,9 @@ -*********************************************** -Installation of Prerequisites for Linux (CMake) -*********************************************** +********************************************* +Standard Setup of Toolchain for Linux +********************************************* :link_to_translation:`zh_CN:[中文]` -.. include:: ../cmake-warning.rst - Install Prerequisites ===================== @@ -32,7 +30,7 @@ Additional Tips Permission issues /dev/ttyUSB0 ------------------------------ -With some Linux distributions you may get the ``Failed to open port /dev/ttyUSB0`` error message when flashing the ESP32. :ref:`This can be solved by adding the current user to the dialout group`. +With some Linux distributions you may get the ``Failed to open port /dev/ttyUSB0`` error message when flashing the ESP32. :ref:`This can be solved by adding the current user to the dialout group`. Arch Linux Users @@ -53,7 +51,7 @@ Alternatively, use crosstool-NG to compile a gdb that links against ncurses 6. Next Steps ========== -To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf-cmake`. +To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf`. Related Documents diff --git a/docs/en/get-started/macos-setup-scratch.rst b/docs/en/get-started/macos-setup-scratch.rst index 45fa4238ca..faaeda54df 100644 --- a/docs/en/get-started/macos-setup-scratch.rst +++ b/docs/en/get-started/macos-setup-scratch.rst @@ -1,11 +1,9 @@ *********************************************** -Setup Toolchain for Mac OS from Scratch (CMake) +Setup Toolchain for Mac OS from Scratch *********************************************** :link_to_translation:`zh_CN:[中文]` -.. include:: ../cmake-warning.rst - Package Manager =============== @@ -85,4 +83,4 @@ Toolchain will be built in ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32- Next Steps ========== -To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf-cmake`. +To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf`. diff --git a/docs/en/get-started/macos-setup.rst b/docs/en/get-started/macos-setup.rst index 7926ea9d5f..caede42ece 100644 --- a/docs/en/get-started/macos-setup.rst +++ b/docs/en/get-started/macos-setup.rst @@ -1,11 +1,9 @@ -*********************************************** -Installation of Prerequisites for macOS (CMake) -*********************************************** +********************************************** +Standard Setup of Toolchain for Mac OS +********************************************** :link_to_translation:`zh_CN:[中文]` -.. include:: ../cmake-warning.rst - Install Prerequisites ===================== @@ -43,7 +41,7 @@ ESP-IDF will use the version of Python installed by default on macOS. Next Steps ========== -To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf-cmake`. +To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf`. Related Documents ================= diff --git a/docs/en/get-started/toolchain-setup-scratch.rst b/docs/en/get-started/toolchain-setup-scratch.rst index c7b0ee32d5..e65233f685 100644 --- a/docs/en/get-started/toolchain-setup-scratch.rst +++ b/docs/en/get-started/toolchain-setup-scratch.rst @@ -1,12 +1,12 @@ -.. _get-started-customized-setup-cmake: +.. _get-started-customized-setup: ************************************* -Customized Setup of Toolchain (CMake) +Customized Setup of Toolchain ************************************* :link_to_translation:`zh_CN:[中文]` -Instead of downloading binary toolchain from Espressif website (see :ref:`get-started-set-up-tools-cmake`) you may build the toolchain yourself. +Instead of downloading binary toolchain from Espressif website (see :ref:`get-started-set-up-tools`) you may build the toolchain yourself. If you can't think of a reason why you need to build it yourself, then probably it's better to stick with the binary version. However, here are some of the reasons why you might want to compile it from source: diff --git a/docs/en/get-started/windows-setup-scratch.rst b/docs/en/get-started/windows-setup-scratch.rst index 4fa8168fef..d0bef754df 100644 --- a/docs/en/get-started/windows-setup-scratch.rst +++ b/docs/en/get-started/windows-setup-scratch.rst @@ -1,11 +1,9 @@ -********************************** -Windows Setup from Scratch (CMake) -********************************** +******************************************** +Setup Windows Toolchain from Scratch +******************************************** :link_to_translation:`zh_CN:[中文]` -.. include:: ../cmake-warning.rst - This is a step-by-step alternative to running the :doc:`ESP-IDF Tools Installer ` for the CMake-based build system. Installing all of the tools by hand allows more control over the process, and also provides the information for advanced users to customize the install. To quickly setup the toolchain and other tools in standard way, using the ESP-IDF Tools installer, proceed to section :doc:`windows-setup`. @@ -13,7 +11,7 @@ To quickly setup the toolchain and other tools in standard way, using the ESP-ID .. note:: The GNU Make based build system requires the MSYS2_ Unix compatibility environment on Windows. The CMake-based build system does not require this environment. -.. _get-esp-idf-windows-command-line-cmake: +.. _get-esp-idf-windows-command-line: Get ESP-IDF =========== @@ -98,7 +96,7 @@ Next, the ``bin`` subdirectory of this directory must be `added to your Path `. Introduction ============ @@ -19,7 +17,7 @@ For this Getting Started we're going to use the Command Prompt, but after ESP-ID .. note:: The GNU Make based build system requires the MSYS2_ Unix compatibility environment on Windows. The CMake-based build system does not require this environment. -.. _get-started-cmake-windows-tools-installer: +.. _get-started-windows-tools-installer: ESP-IDF Tools Installer ======================= @@ -48,7 +46,7 @@ Note that this shortcut is specific to the ESP-IDF directory selected in the ESP Next Steps ========== -If the ESP-IDF Tools Installer has finished successfully, then the development environment setup is complete. Proceed directly to :ref:`get-started-start-project-cmake`. +If the ESP-IDF Tools Installer has finished successfully, then the development environment setup is complete. Proceed directly to :ref:`get-started-start-project`. Related Documents ================= diff --git a/docs/en/gnu-make-legacy.rst b/docs/en/gnu-make-legacy.rst new file mode 100644 index 0000000000..5257c87b88 --- /dev/null +++ b/docs/en/gnu-make-legacy.rst @@ -0,0 +1 @@ +.. note:: Since ESP-IDF V4.0, the default build system is based on CMake. This documentation is for the legacy build system based on GNU Make. Support for this build system may be removed in future major releases. diff --git a/docs/en/index.rst b/docs/en/index.rst index 5eb9493275..8ce586174f 100644 --- a/docs/en/index.rst +++ b/docs/en/index.rst @@ -39,7 +39,7 @@ This is the documentation for Espressif IoT Development Framework (`esp-idf - Get Started (CMake Preview) + Get Started (Legacy GNU Make) API Reference H/W Reference API Guides diff --git a/docs/page_redirects.txt b/docs/page_redirects.txt index c1ffdf1397..030b879798 100644 --- a/docs/page_redirects.txt +++ b/docs/page_redirects.txt @@ -18,8 +18,35 @@ api-reference/system/tcpip_adapter api-reference/network/tcpip_adapter get-started/idf-monitor api-guides/tools/idf-monitor get-started-cmake/idf-monitor api-guides/tools/idf-monitor get-started/get-started-devkitc hw-reference/get-started-devkitc +get-started/get-started-devkitc-v2 hw-reference/get-started-devkitc-v2 get-started/get-started-wrover-kit hw-reference/get-started-wrover-kit +get-started/get-started-wrover-kit-v2 hw-reference/get-started-wrover-kit-v2 +get-started/get-started-wrover-kit-v3 hw-reference/get-started-wrover-kit-v3 get-started/get-started-pico-kit hw-reference/get-started-pico-kit -get-started-cmake/get-started-devkitc hw-reference/get-started-devkitc -get-started-cmake/get-started-wrover-kit hw-reference/get-started-wrover-kit -get-started-cmake/get-started-pico-kit hw-reference/get-started-pico-kit +get-started/get-started-pico-kit-v3 hw-reference/get-started-pico-kit-v3 + +# The preview 'get-started-cmake' guides are now 'get-started' +get-started-cmake get-started +get-started-cmake/add-idf_path-to-profile get-started/add-idf_path-to-profile +get-started-cmake/eclipse-setup get-started/eclipse-setup +get-started-cmake/establish-serial-connection get-started/establish-serial-connection +get-started-cmake/index get-started/index +get-started-cmake/linux-setup get-started/linux-setup +get-started-cmake/linux-setup-scratch get-started/linux-setup-scratch +get-started-cmake/macos-setup get-started/macos-setup +get-started-cmake/macos-setup-scratch get-started/macos-setup-scratch +get-started-cmake/toolchain-setup-scratch get-started/toolchain-setup-scratch +get-started-cmake/windows-setup get-started/windows-setup +get-started-cmake/windows-setup-scratch get-started/windows-setup-scratch +get-started-cmake/get-started-devkitc hw-reference/get-started-devkitc +get-started-cmake/get-started-devkitc-v2 hw-reference/get-started-devkitc-v2 +get-started-cmake/get-started-wrover-kit hw-reference/get-started-wrover-kit +get-started-cmake/get-started-wrover-kit-v2 hw-reference/get-started-wrover-kit-v2 +get-started-cmake/get-started-wrover-kit-v3 hw-reference/get-started-wrover-kit-v3 +get-started-cmake/get-started-pico-kit hw-reference/get-started-pico-kit +get-started-cmake/get-started-pico-kit-v3 hw-reference/get-started-pico-kit-v3 + + +api-guide/build-system-cmake api-guide/build-system +api-guide/ulp-cmake api-guide/ulp + diff --git a/docs/sphinx-known-warnings.txt b/docs/sphinx-known-warnings.txt index fe496b067f..55e4564238 100644 --- a/docs/sphinx-known-warnings.txt +++ b/docs/sphinx-known-warnings.txt @@ -33,9 +33,12 @@ esp_bt_defs.inc:line: WARNING: Invalid definition: Expected identifier in nested # sphinx==1.8.4 # breathe==4.11.1 # -ulp-cmake.rst:line: WARNING: Duplicate declaration, esp_err_t ulp_load_binary(uint32_t load_addr, const uint8_t * program_binary, size_t program_size) -ulp-cmake.rst:line: WARNING: Duplicate declaration, esp_err_t ulp_run(uint32_t entry_point) -ulp-cmake.rst:line: WARNING: Duplicate declaration, esp_err_t ulp_set_wakeup_period(size_t period_index, uint32_t period_us) +ulp.rst:line: WARNING: Duplicate declaration, esp_err_t ulp_load_binary(uint32_t load_addr, const uint8_t * program_binary, size_t program_size) +ulp.rst:line: WARNING: Duplicate declaration, esp_err_t ulp_run(uint32_t entry_point) +ulp.rst:line: WARNING: Duplicate declaration, esp_err_t ulp_set_wakeup_period(size_t period_index, uint32_t period_us) +ulp-legacy.rst:line: WARNING: Duplicate declaration, esp_err_t ulp_load_binary(uint32_t load_addr, const uint8_t * program_binary, size_t program_size) +ulp-legacy.rst:line: WARNING: Duplicate declaration, esp_err_t ulp_run(uint32_t entry_point) +ulp-legacy.rst:line: WARNING: Duplicate declaration, esp_err_t ulp_set_wakeup_period(size_t period_index, uint32_t period_us) README.rst:line: WARNING: Duplicate declaration, esp_err_t ulp_run(uint32_t entry_point) # # Issue present only when building on msys2 / mingw32 START >>> diff --git a/docs/zh_CN/api-guides/app_trace.rst b/docs/zh_CN/api-guides/app_trace.rst index 69d408f73e..da295ade41 100644 --- a/docs/zh_CN/api-guides/app_trace.rst +++ b/docs/zh_CN/api-guides/app_trace.rst @@ -151,7 +151,7 @@ return res; } -2. 下一步是编译应用程序的镜像并将其下载到目标板上,这一步可以参考文档 :doc:`构建并烧写 <../get-started/make-project>`。 +2. 下一步是编译应用程序的镜像并将其下载到目标板上,这一步可以参考文档 :ref:`构建并烧写 `。 3. 运行 OpenOCD(参见 :doc:`JTAG 调试 <../api-guides/jtag-debugging/index>`)。 4. 连接到 OpenOCD 的 telnet 服务器,在终端执行如下命令 ``telnet 4444``。如果在运行 OpenOCD 的同一台机器上打开 telnet 会话,您可以使用 ``localhost`` 替换上面命令中的 ````。 diff --git a/docs/zh_CN/api-guides/build-system-cmake.rst b/docs/zh_CN/api-guides/build-system-cmake.rst deleted file mode 100644 index 6f9a9970fa..0000000000 --- a/docs/zh_CN/api-guides/build-system-cmake.rst +++ /dev/null @@ -1,1083 +0,0 @@ -构建系统(CMake 版) -******************** -:link_to_translation:`en:[English]` - -.. include:: ../cmake-warning.rst - -.. include:: ../cmake-pending-features.rst - -本文档将介绍基于 CMake 的 ESP-IDF 构建系统的实现原理以及 ``组件`` 等相关概念,此外 ESP-IDF 还支持 :doc:`基于 GNU Make 的构建系统 `。 - -如需您想了解如何使用 CMake 构建系统来组织和构建新的 ESP-IDF 项目或组件,请阅读本文档。 - -概述 -==== - -一个 ESP-IDF 项目可以看作是多个不同组件的集合,例如一个显示当前湿度的网页服务器会包含以下组件: - -- ESP32 基础库,包括 libc、ROM bindings 等 -- Wi-Fi 驱动 -- TCP/IP 协议栈 -- FreeRTOS 操作系统 -- 网页服务器 -- 湿度传感器的驱动 -- 负责将上述组件整合到一起的主程序 - -ESP-IDF 可以显式地指定和配置每个组件。在构建项目的时候,构建系统会前往 ESP-IDF 目录、项目目录和用户自定义目录(可选)中查找所有组件,允许用户通过文本菜单系统配置 ESP-IDF 项目中用到的每个组件。在所有组件配置结束后,构建系统开始编译整个项目。 - -概念 ----- - -- ``项目`` 特指一个目录,其中包含了构建可执行应用程序所需的全部文件和配置,以及其他支持型文件,例如分区表、数据/文件系统分区和引导程序。 -- ``项目配置`` 保存在项目根目录下名为 ``sdkconfig`` 的文件中,可以通过 ``idf.py menuconfig`` 进行修改,且一个项目只能包含一个项目配置。 -- ``应用程序`` 是由 ESP-IDF 构建得到的可执行文件。一个项目通常会构建两个应用程序:项目应用程序(可执行的主文件,即用户自定义的固件)和引导程序(启动并初始化项目应用程序)。 -- ``组件`` 是模块化且独立的代码,会被编译成静态库(.a 文件)并链接到应用程序。部分组件由 ESP-IDF 官方提供,其他组件则来源于其它开源项目。 -- ``目标`` 特指运行构建后应用程序的硬件设备。ESP-IDF 当前仅支持 ``ESP32`` 这一个硬件目标。 - -请注意,以下内容并不属于项目的组成部分: - -- ``ESP-IDF`` 并不是项目的一部分,它独立于项目,通过 ``IDF_PATH`` 环境变量(保存 ``esp-idf`` 目录的路径)链接到项目,从而将 IDF 框架与项目分离。 -- 交叉编译工具链并不是项目的组成部分,它应该被安装在系统 PATH 环境变量中。 - -使用构建系统 -============ - -.. _idf.py: - -idf.py ------- - -``idf.py`` 命令行工具提供了一个前端,可以帮助您轻松管理项目的构建过程,它管理了以下工具: - -- CMake_,配置待构建的系统 -- 命令行构建工具(Ninja_ 或 `GNU Make`) -- `esptool.py`_,烧录 ESP32 - -:ref:`入门指南 ` 简要介绍了如何设置 ``idf.py`` 用于配置、构建并烧录项目。 - -``idf.py`` 应运行在 ESP-IDF 的 ``项目`` 目录下,即包含 ``CMakeLists.txt`` 文件的目录。仅包含 Makefile 的老式项目并不支持 ``idf.py``。 - -运行 ``idf.py --help`` 查看完整的命令列表。下面总结了最常用的命令: - -- ``idf.py menuconfig`` 会运行 ``menuconfig`` 工具来配置项目。 -- ``idf.py build`` 会构建在当前目录下找到的项目,它包括以下步骤: - - - 根据需要创建 ``build`` 构建目录,它用于保存构建过程的输出文件,可以使用 ``-B`` 选项修改默认的构建目录。 - - 根据需要运行 CMake_ 配置命令,为主构建工具生成构建文件。 - - 运行主构建工具(Ninja_ 或 `GNU Make`)。默认情况下,构建工具会被自动检测,可以使用 ``-G`` 选项显式地指定构建工具。 - - 构建过程是增量式的,如果自上次构建以来源文件或项目配置没有发生改变,则不会执行任何操作。 - -- ``idf.py clean`` 会把构建输出的文件从构建目录中删除,从而清理整个项目。下次构建时会强制“重新完整构建”这个项目。清理时,不会删除 CMake 配置输出及其他文件。 -- ``idf.py fullclean`` 会将整个 ``build`` 目录下的内容全部删除,包括所有 CMake 的配置输出文件。下次构建项目时,CMake 会从头开始配置项目。请注意,该命令会递归删除构建目录下的 *所有文件*,请谨慎使用。项目配置文件不会被删除。 -- ``idf.py flash`` 会在必要时自动构建项目,并将生成的二进制程序烧录进 ESP32 设备中。``-p`` 和 ``-b`` 选项可分别设置串口的设备名和烧录时的波特率。 -- ``idf.py monitor`` 用于显示 ESP32 设备的串口输出。``-p`` 选项可用于设置主机端串口的设备名,按下 ``Ctrl-]`` 可退出监视器。更多有关监视器的详情,请参阅 :doc:`tools/idf-monitor`。 - -多个 ``idf.py`` 命令可合并成一个,例如,``idf.py -p COM4 clean flash monitor`` 会依次清理源码树,构建项目,烧录进 ESP32 设备,最后运行串口监视器。 - -.. Note:: 环境变量 ``ESPPORT`` 和 ``ESPBAUD`` 可分别用作 ``-p`` 和 ``-b`` 选项的默认值。在命令行中,重新为这两个选项赋值,会覆盖其默认值。 - -.. _idf.py-size: - -高级命令 -^^^^^^^^ - -- ``idf.py app``,``idf.py bootloader``,``idf.py partition_table`` 仅可用于从适用的项目中构建应用程序、引导程序或分区表。 -- ``idf.py app-flash`` 等匹配命令,仅将项目的特定部分烧录至 ESP32。 -- ``idf.py -p PORT erase_flash`` 会使用 esptool.py 擦除 ESP32 的整个 Flash。 -- ``idf.py size`` 会打印应用程序相关的大小信息,``idf.py size-components`` 和 ``idf.py size-files`` 这两个命令相似,分别用于打印每个组件或源文件的详细信息。 -- ``idf.py reconfigure`` 命令会重新运行 CMake_ (即便无需重新运行)。正常使用时,并不需要运行此命令,但当源码树中添加/删除文件后或更改 CMake cache 变量时,此命令会非常有用,例如,``idf.py -DNAME='VALUE' reconfigure`` 会将 CMake cache 中的变量 ``NAME`` 的值设置为 ``VALUE``。 - -同时调用多个 ``idf.py`` 命令时,命令的输入顺序并不重要,它们会按照正确的顺序依次执行,并保证每一条命令都生效(即先构建后烧录,先擦除后烧录等)。 - -直接使用 CMake --------------- - -为了方便,:ref:`idf.py` 已经封装了 CMake_ 命令,但是您愿意,也可以直接调用 CMake。 - -.. highlight:: bash - -当 ``idf.py`` 在执行某些操作时,它会打印出其运行的每条命令以便参考。例如运行 ``idf.py build`` 命令与在 bash shell(或者 Windows Command Prompt)中运行以下命令是相同的:: - - mkdir -p build - cd build - cmake .. -G Ninja # 或者 'Unix Makefiles' - ninja - -在上面的命令列表中,``cmake`` 命令对项目进行配置,并生成用于最终构建工具的构建文件。在这个例子中,最终构建工具是 Ninja_: 运行 ``ninja`` 来构建项目。 - -没有必要多次运行 ``cmake``。第一次构建后,往后每次只需运行 ``ninja`` 即可。如果项目需要重新配置,``ninja`` 会自动重新调用 ``cmake``。 - -若在 CMake 中使用 ``ninja`` 或 ``make``,则多数 ``idf.py`` 子命令也会有其对应的目标,例如在构建目录下运行 ``make menuconfig`` 或 ``ninja menuconfig`` 与运行 ``idf.py menuconfig`` 是相同的。 - -.. Note:: - 如果您已经熟悉了 CMake_,那么可能会发现 ESP-IDF 的 CMake 构建系统不同寻常,为了减少样板文件,该系统封装了 CMake 的许多功能。请参考 :ref:`write-pure-cmake-component` 以编写更多 ``CMake 风格`` 的组件。 - -.. _flash-with-ninja-or-make: - -使用 Ninja/Make 来烧录 -^^^^^^^^^^^^^^^^^^^^^^ - -您可以直接使用 ninja 或 make 运行如下命令来构建项目并烧录:: - - ninja flash - -或:: - - make app-flash - -可用的目标还包括:``flash``、``app-flash`` (仅用于 app)、``bootloader-flash`` (仅用于 bootloader)。 - -以这种方式烧录时,可以通过设置 ``ESPPORT`` 和 ``ESPBAUD`` 环境变量来指定串口设备和波特率。您可以在操作系统或 IDE 项目中设置该环境变量,或者直接在命令行中进行设置:: - - ESPPORT=/dev/ttyUSB0 ninja flash - -.. Note:: 在命令的开头为环境变量赋值属于 Bash shell 的语法,可在 Linux 、macOS 和 Windows 的类 Bash shell 中运行,但在 Windows Command Prompt 中无法运行。 - -或:: - - make -j3 app-flash ESPPORT=COM4 ESPBAUD=2000000 - -.. Note:: 在命令末尾为变量赋值属于 ``make`` 的语法,适用于所有平台的 ``make``。 - -在 IDE 中使用 CMake -------------------- - -您还可以使用集成了 CMake 的 IDE,仅需将项目 ``CMakeLists.txt`` 文件的路径告诉 IDE 即可。集成 CMake 的 IDE 通常会有自己的构建工具(CMake 称之为“生成器”),它是组成 IDE 的一部分,用来构建源文件。 - -向 IDE 中添加除 ``build`` 目标以外的自定义目标(如添加 “Flash” 目标到 IDE)时,建议调用 ``idf.py`` 命令来执行这些“特殊”的操作。 - -有关将ESP-IDF 同 CMake 集成到 IDE 中的详细信息,请参阅 :ref:`build_system_metadata`。 - -.. _setting-python-interpreter: - -设置 Python 解释器 ------------------- - -目前,ESP-IDF 仅适用于 Python 2.7,如果系统中默认的 ``python`` 解释器是 Python 3.x,可能会出现问题。 - -如果使用了 ``idf.py``,并以 ``python2 $IDF_PATH/tools/idf.py ...`` 的方式运行 ``idf.py`` 则会解决这个问题(``idf.py`` 会通知其余 Python 进程使用相同的 Python 解释器)。你可以通过设置 shell 别名或其他脚本来简化该命令。 - -如果直接使用 CMake,运行 ``cmake -D PYTHON=python2 ...``,CMake 会使用传入的值覆盖默认的 Python 解释器。 - -如果使用集成 CMake 的 IDE,可以在 IDE 的图形用户界面中给名为 ``PYTHON`` 的 CMake cache 变量设置新的值来覆盖默认的 Python 解释器。 - -如果想在命令行中更优雅地管理 Python 的各个版本,请查看 pyenv_ 或 virtualenv_ 工具,它们会帮助您更改默认的 python 版本。 - -.. _example-project-structure: - -示例项目 -======== - -.. highlight:: none - -示例项目的目录树结构可能如下所示:: - - - myProject/ - - CMakeLists.txt - - sdkconfig - - components/ - component1/ - CMakeLists.txt - - Kconfig - - src1.c - - component2/ - CMakeLists.txt - - Kconfig - - src1.c - - include/ - component2.h - - main/ - src1.c - - src2.c - - build/ - -该示例项目 ``myproject`` 包含以下组成部分: - -- 顶层项目 CMakeLists.txt 文件,这是 CMake 用于学习如何构建项目的主要文件,可以在这个文件中设置项目全局的 CMake 变量。顶层项目 CMakeLists.txt 文件会导入 :idf_file:`/tools/cmake/project.cmake` 文件,由它负责实现构建系统的其余部分。该文件最后会设置项目的名称,并定义该项目。 -- ``sdkconfig`` 项目配置文件,执行 ``idf.py menuconfig`` 时会创建或更新此文件,文件中保存了项目中所有组件(包括 ESP-IDF 本身)的配置信息。 ``sdkconfig`` 文件可能会也可能不会被添加到项目的源码管理系统中。 -- 可选的 ``component`` 目录中包含了项目的部分自定义组件,并不是每个项目都需要这种自定义组件,但它组件有助于构建可复用的代码或者导入第三方(不属于 ESP-IDF)的组件。 -- ``main`` 目录是一个特殊的 ``伪组件``,包含项目本身的源代码。``main`` 是默认名称,CMake 变量 ``COMPONENT_DIRS`` 默认包含此组件,但您可以修改此变量。或者,您也可以在顶层 CMakeLists.txt 中设置 ``EXTRA_COMPONENT_DIRS`` 变量以查找其他指定位置处的组件。有关详细信息,请参阅 :ref:`重命名 main 组件 `。如果项目中源文件较多,建议将其归于组件中,而不是全部放在 ``main`` 中。 -- ``build`` 目录是存放构建输出的地方,如果没有此目录,``idf.py`` 会自动创建。CMake 会配置项目,并在此目录下生成临时的构建文件。随后,在主构建进程的运行期间,该目录还会保存临时目标文件、库文件以及最终输出的二进制文件。此目录通常不会添加到项目的源码管理系统中,也不会随项目源码一同发布。 - -每个组件目录都包含一个 ``CMakeLists.txt`` 文件,里面会定义一些变量以控制该组件的构建过程,以及其与整个项目的集成。更多详细信息请参阅 :ref:`component-directories-cmake`。 - -每个组件还可以包含一个 ``Kconfig`` 文件,它用于定义 ``menuconfig`` 时展示的 :ref:`component-configuration-cmake` 选项。某些组件可能还会包含 ``Kconfig.projbuild`` 和 ``project_include.cmake`` 特殊文件,它们用于 :ref:`override_project_config`。 - -项目 CMakeLists 文件 -==================== - -每个项目都有一个顶层 ``CMakeLists.txt`` 文件,包含整个项目的构建设置。默认情况下,项目 CMakeLists 文件会非常小。 - -最小 CMakeLists 文件示例 ------------------------- - -.. highlight:: cmake - -最小项目:: - - cmake_minimum_required(VERSION 3.5) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) - project(myProject) - - -.. _project-mandatory-parts: - -必要部分 --------- - -每个项目都要按照上面显示的顺序添加上述三行代码: - -- ``cmake_minimum_required(VERSION 3.5)`` 必须放在 CMakeLists.txt 文件的第一行,它会告诉 CMake 构建该项目所需要的最小版本号。ESP-IDF 支持 CMake 3.5 或更高的版本。 -- ``include($ENV{IDF_PATH}/tools/cmake/project.cmake)`` 会导入 CMake 的其余功能来完成配置项目、检索组件等任务。 -- ``project(myProject)`` 会创建项目本身,并指定项目名称。该名称会作为最终输出的二进制文件的名字,即 ``myProject.elf`` 和 ``myProject.bin``。每个 CMakeLists 文件只能定义一个项目。 - -.. _optional_project_variable: - -可选的项目变量 --------------- - -以下这些变量都有默认值,用户可以覆盖这些变量值以自定义构建行为。更多实现细节,请参阅 :idf_file:`/tools/cmake/project.cmake` 文件。 - -- ``COMPONENT_DIRS``:组件的搜索目录,默认为 ``${IDF_PATH}/components``、``${PROJECT_PATH}/components`` 和 ``EXTRA_COMPONENT_DIRS``。如果您不想在这些位置搜索组件,请覆盖此变量。 -- ``EXTRA_COMPONENT_DIRS``:用于搜索组件的其它可选目录列表。路径可以是相对于项目目录的相对路径,也可以是绝对路径。 -- ``COMPONENTS``:要构建进项目中的组件名称列表,默认为 ``COMPONENT_DIRS`` 目录下检索到的所有组件。使用此变量可以“精简”项目以缩短构建时间。请注意,如果一个组件通过 ``COMPONENT_REQUIRES`` 指定了它依赖的另一个组件,则会自动将其添加到 ``COMPONENTS`` 中,所以 ``COMPONENTS`` 列表可能会非常短。 -- ``COMPONENT_REQUIRES_COMMON``:每个组件都需要的通用组件列表,这些通用组件会自动添加到每个组件的 ``COMPONENT_PRIV_REQUIRES`` 列表中以及项目的 ``COMPONENTS`` 列表中。默认情况下,此变量设置为 ESP-IDF 项目所需的最小核心“系统”组件集。通常您无需在项目中更改此变量。 - -以上变量中的路径可以是绝对路径,或者是相对于项目目录的相对路径。 - -请使用 `cmake 中的 set 命令 `_ 来设置这些变量,即 ``set(VARIABLE "VALUE")``。请注意,``set()`` 命令需放在 ``include(...)`` 之前,``cmake_minimum(...)`` 之后。 - -.. _rename-main-cmake: - -重命名 ``main`` 组件 --------------------- - -构建系统会对 ``main`` 组件进行特殊处理。假如 ``main`` 组件位于预期的位置(即 `${PROJECT_PATH}/main`),那么它会被自动添加到构建系统中。其他组件也会作为其依赖项被添加到构建系统中,这使用户免于处理依赖关系,并提供即时可用的构建功能。重命名 ``main`` 组件会减轻上述这些幕后工作量,但要求用户指定重命名后的组件位置,并手动为其添加依赖项。重命名 ``main`` 组件的步骤如下: - -1. 重命名 ``main`` 目录。 -2. 在项目 CMakeLists.txt 文件中设置 ``EXTRA_COMPONENT_DIRS``,并添加重命名后的 ``main`` 目录。 -3. 在组件的 CMakeLists.txt 文件中设置 ``COMPONENT_REQUIRES`` 或 ``COMPONENT_PRIV_REQUIRES`` 以指定依赖项。 - - -.. _component-directories-cmake: - -组件 CMakeLists 文件 -==================== - -每个项目都包含一个或多个组件,这些组件可以是 ESP-IDF 的一部分,可以是项目自身组件目录的一部分,也可以从自定义组件目录添加( :ref:`见上文 `)。 - -组件是 ``COMPONENT_DIRS`` 列表中包含 ``CMakeLists.txt`` 文件的任何目录。 - -搜索组件 --------- - -搜索 ``COMPONENT_DIRS`` 中的目录列表以查找项目的组件,此列表中的目录可以是组件自身(即包含 `CMakeLists.txt` 文件的目录),也可以是子目录为组件的顶级目录。 - -当 CMake 运行项目配置时,它会记录本次构建包含的组件列表,它可用于调试某些组件的添加/排除。 - -同名组件 --------- - -ESP-IDF 在搜索所有待构建的组件时,会按照 ``COMPONENT_DIRS`` 指定的顺序依次进行,这意味着在默认情况下,首先搜索 ESP-IDF 内部组件,然后是项目组件,最后是 ``EXTRA_COMPONENT_DIRS`` 中的组件。如果这些目录中的两个或者多个包含具有相同名字的组件,则使用搜索到的最后一个位置的组件。这就允许将组件复制到项目目录中再修改以覆盖 ESP-IDF 组件,如果使用这种方式,ESP-IDF 目录本身可以保持不变。 - -.. _minimum_cmakelists: - -最小的组件 CMakeLists 文件 --------------------------- - -.. highlight:: cmake - -最小组件 ``CMakeLists.txt`` 文件内容如下:: - - set(COMPONENT_SRCS "foo.c") - set(COMPONENT_ADD_INCLUDEDIRS "include") - register_component() - -- ``COMPONENT_SRCS`` 是用空格分隔的源文件列表(``*.c``,``*.cpp``,``*.cc``,``*.S``),里面所有的源文件都将会编译进组件库中。 -- ``COMPONENT_ADD_INCLUDEDIRS`` 是用空格分隔的目录列表,里面的路径会被添加到所有需要该组件的组件(包括 main 组件)全局 include 搜索路径中。 -- ``register_component()`` 使用上述设置的变量将组件添加到构建系统中,构建生成与组件同名的库,并最终被链接到应用程序中。如果因为使用了 `CMake 中的 if 命令 `_ 或类似命令而跳过了这一步,那么该组件将不会被添加到构建系统中。 - -上述目录通常设置为相对于 ``CMakeLists.txt`` 文件的相对路径,当然也可以设置为绝对路径。 - -有关更完整的 ``CMakeLists.txt`` 示例,请参阅 :ref:`component_cmakelists_example`。 - -.. _preset_component_variables: - -预设的组件变量 --------------- - -以下专用于组件的变量可以在组件 CMakeLists 中使用,但不建议修改: - -- ``COMPONENT_PATH``:组件目录,即包含 ``CMakeLists.txt`` 文件的绝对路径,它与 ``CMAKE_CURRENT_SOURCE_DIR`` 变量一样,路径中不能包含空格。 -- ``COMPONENT_NAME``:组件名,与组件目录名相同。 -- ``COMPONENT_TARGET``:库目标名,它由构建系统在内部为组件创建。 - -以下变量在项目级别中被设置,但可在组件 CMakeLists 中使用: - -- ``PROJECT_NAME``:项目名,在项目 CMakeLists.txt 文件中设置。 -- ``PROJECT_PATH``:项目目录(包含项目 CMakeLists 文件)的绝对路径,与 ``CMAKE_SOURCE_DIR`` 变量相同。 -- ``COMPONENTS``:此次构建中包含的所有组件的名称,具体格式为用分号隔开的 CMake 列表。 -- ``CONFIG_*``:项目配置中的每个值在 cmake 中都对应一个以 ``CONFIG_`` 开头的变量。更多详细信息请参阅 :doc:`Kconfig `。 -- ``IDF_VER``:ESP-IDF 的 git 版本号,由 ``git describe`` 命令生成。 -- ``IDF_VERSION_MAJOR``, ``IDF_VERSION_MINOR``, ``IDF_VERSION_PATCH``: ESP-IDF 的组件版本,可用于条件表达式。请注意这些信息的精确度不如 ``IDF_VER`` 变量,版本号 ``v4.0-dev-*``, ``v4.0-beta1``, ``v4.0-rc1`` 和 ``v4.0`` 对应的 ``IDF_VERSION_*`` 变量值是相同的,但是 ``IDF_VER`` 的值是不同的。 -- ``IDF_TARGET``:项目的硬件目标名称。 -- ``PROJECT_VER``:项目版本号。 - - * 如果在项目 CMakeLists.txt 文件中设置了 ``PROJECT_VER`` 变量,则该变量值可以使用。 - * 或者,如果 ``${PROJECT_PATH}/version.txt`` 文件存在,其内容会用作 ``PROJECT_VER`` 的值。 - * 或者,如果项目位于某个 Git 仓库中,则使用 ``git describe`` 命令的输出作为 ``PROJECT_VER`` 的值。 - * 否则,``PROJECT_VER`` 的值为空。 - -如果您在组件的 ``CMakeLists.txt`` 中修改以上变量,并不会影响其他组件的构建,但可能会使该组件变得难以构建或调试。 - -- ``COMPONENT_ADD_INCLUDEDIRS``:相对于组件目录的相对路径,为被添加到所有需要该组件的其他组件的全局 include 搜索路径中。如果某个 include 路径仅仅在编译当前组件时需要,请将其添加到 ``COMPONENT_PRIV_INCLUDEDIRS`` 中。 -- ``COMPONENT_REQUIRES`` 是一个用空格分隔的组件列表,列出了当前组件依赖的其他组件。如果当前组件有一个头文件位于 ``COMPONENT_ADD_INCLUDEDIRS`` 目录下,且该头文件包含了另一个组件的头文件,那么这个被依赖的组件需要在 ``COMPONENT_REQUIRES`` 中指出。这种依赖关系可以是递归的。 - - ``COMPONENT_REQUIRES`` 可以为空,因为所有的组件都需要一些常用的组件(如 newlib 组件提供的 libc 库、freertos 组件提供的 RTOS 功能),这些通用组件已经在项目级变量 ``COMPONENT_REQUIRES_COMMON`` 中被设置。 - - 如果一个组件仅需要额外组件的头文件来编译其源文件(而不是全局引入它们的头文件),则这些被依赖的组件需要在 ``COMPONENT_PRIV_REQUIRES`` 中指出。 - - 请参阅 :ref:`component_dependency`,查看详细信息。 - -可选的组件特定变量 ------------------- - -以下变量可在 ``CMakeLists.txt`` 中进行设置,用以控制该组件的构建行为: - -- ``COMPONENT_PRIV_INCLUDEDIRS``:相对于组件目录的相对路径,仅会被添加到该组件的 include 搜索路径中。 -- ``COMPONENT_PRIV_REQUIRES``:以空格分隔的组件列表,用于编译或链接当前组件的源文件。这些组件的头文件路径不会传递给其余需要它的组件,仅用于编译当前组件的源代码。更多详细信息请参阅 :ref:`component_dependency`。 -- ``COMPONENT_SRCS``:要编译进当前组件的源文件的路径,推荐使用此方法向构建系统中添加源文件。 -- ``COMPONENT_SRCDIRS``:相对于组件目录的源文件目录路径,用于搜索源文件(``*.cpp``,``*.c``,``*.S``)。匹配成功的源文件会替代 ``COMPONENT_SRCS`` 中指定的源文件,进而被编译进组件。即设置 ``COMPONENT_SRCDIRS`` 会导致 ``COMPONENT_SRCS`` 会被忽略。此方法可以很容易地将源文件整体导入到组件中,但并不推荐使用(详情请参阅 :ref:`cmake-file-globbing`)。 -- ``COMPONENT_SRCEXCLUDE``:需要从组件中剔除的源文件路径。当某个目录中有大量的源文件需要被导入组件中,但同时又有个别文件不需要导入时,可以配合 ``COMPONENT_SRCDIRS`` 变量一起设置。路径可以是相对于组件目录的相对路径,也可以是绝对路径。 -- ``COMPONENT_ADD_LDFRAGMENTS``:组件使用的链接片段文件的路径,用于自动生成链接器脚本文件。详细信息请参阅 :doc:`链接脚本生成机制 `。 - -.. Note:: - - 如果没有设置 ``COMPONENT_SRCDIRS`` 或 ``COMPONENT_SRCS``,组件不会被编译成库文件,但仍可以被添加到 include 路径中,以便在编译其他组件时使用。 - -.. _component_build_control: - -组件编译控制 ------------- - -.. highlight:: cmake - -在编译特定组件的源文件时,可以使用 ``target_compile_options`` 命令来传递编译器选项:: - - target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-variable) - -这条命令封装了 CMake 的 `target_compile_options`_ 命令。 - -如果给单个源文件指定编译器标志,可以使用 CMake 的 `set_source_files_properties`_ 命令:: - - set_source_files_properties(mysrc.c - PROPERTIES COMPILE_FLAGS - -Wno-unused-variable - ) - -如果上游代码在编译的时候发出了警告,那这么做可能会很有效。 - -请注意,上述两条命令只能在组件 CMakeLists 文件的 ``register_component()`` 命令之后调用。 - -.. _component-configuration-cmake: - -组件配置 -======== - -每个组件都可以包含一个 ``Kconfig`` 文件,和 ``CMakeLists.txt`` 放在同一目录下。``Kconfig`` 文件中包含要添加到该组件配置菜单中的一些配置设置信息。 - -运行 menuconfig 时,可以在 ``Component Settings`` 菜单栏下找到这些设置。 - -创建一个组件的 Kconfig 文件,最简单的方法就是使用 ESP-IDF 中现有的 Kconfig 文件作为模板,在这基础上进行修改。 - -有关示例请参阅 :ref:`add_conditional_config`。 - -预处理器定义 -============ - -ESP-IDF 构建系统会在命令行中添加以下 C 预处理器定义: - -- ``ESP_PLATFORM``:可以用来检测在 ESP-IDF 内发生了构建行为。 -- ``IDF_VER``:定义 git 版本字符串,例如:``v2.0`` 用于标记已发布的版本,``v1.0-275-g0efaa4f`` 则用于标记任意某次的提交记录。 -- ``PROJECT_VER``:项目版本号,详细信息请参阅 :ref:`preset_component_variables`。 -- ``PROJECT_NAME``:项目名称,定义在项目 CMakeLists.txt 文件中。 - -.. _component_dependency: - -组件依赖 -======== - -编译各个组件时,ESP-IDF 系统会递归评估其组件。 - -每个组件的源文件都会使用以下路径中的头文件进行编译: - -- 当前组件的 ``COMPONENT_ADD_INCLUDEDIRS`` 和 ``COMPONENT_PRIV_INCLUDEDIRS``。 -- 当前组件的 ``COMPONENT_REQUIRES`` 和 ``COMPONENT_PRIV_REQUIRES`` 变量指定的其他组件(即当前组件的所有公共和私有依赖项)所设置的 ``COMPONENT_ADD_INCLUDEDIRS``。 -- 所有组件的 ``COMPONENT_REQUIRES`` 做递归操作,即该组件递归运算后的所有公共依赖项。 - -编写组件 --------- - -- ``COMPONENT_REQUIRES`` 需要包含所有被当前组件的公共头文件 `#include` 的头文件所在的组件。 -- ``COMPONENT_PRIV_REQUIRES`` 需要包含被当前组件的源文件 `#include` 的头文件所在的组件(除非已经被设置在了 ``COMPONENT_PRIV_REQUIRES`` 中)。或者是当前组件正常工作必须要链接的组件。 -- ``COMPONENT_REQUIRES``、``COMPONENT_PRIV_REQUIRES`` 需要在调用 ``register_component()`` 之前设置。 -- ``COMPONENT_REQUIRES`` 和 ``COMPONENT_PRIV_REQUIRES`` 的值不能依赖于任何配置选项(``CONFIG_xxx``),这是因为在配置加载之前,依赖关系就已经被展开。其它组件变量(比如 ``COMPONENT_SRCS`` 和 ``COMPONENT_ADD_INCLUDEDIRS``)可以依赖配置选择。 -- 如果当前组件除了 ``COMPONENT_REQUIRES_COMMON`` 中设置的通用组件(比如 RTOS、libc 等)外,并不依赖其它组件,那么上述两个 ``REQUIRES`` 变量可以为空。 - -如果组件仅支持某些硬件目标(即依赖于特定的 ``IDF_TARGET``),则可以调用 ``require_idf_targets(NAMES...)`` CMake 函数来声明这个需求。在这种情况下,如果构建系统导入了不支持当前硬件目标的组件时就会报错。 - -创建项目 --------- - -- 默认情况下,每个组件都会包含在构建系统中。 -- 如果将 ``COMPONENTS`` 变量设置为项目直接使用的最小组件列表,那么构建系统会导入: - - * ``COMPONENTS`` 中明确提及的组件。 - * 这些组件的依赖项(以及递归运算后的组件)。 - * 每个组件都依赖的通用组件。 - -- 将 ``COMPONENTS`` 设置为所需组件的最小列表,可以显著减少项目的构建时间。 - -.. _component-requirements-implementation: - -构建系统中依赖处理的实现细节 ----------------------------- - -- 在 CMake 配置进程的早期阶段会运行 ``expand_requirements.cmake`` 脚本。该脚本会对所有组件的 CMakeLists.txt 文件进行局部的运算,得到一张组件依赖关系图(此图可能会有闭环)。此图用于在构建目录中生成 ``component_depends.cmake`` 文件。 -- CMake 主进程会导入该文件,并以此来确定要包含到构建系统中的组件列表(内部使用的 ``BUILD_COMPONENTS`` 变量)。``BUILD_COMPONENTS`` 变量已排好序,依赖组件会排在前面。由于组件依赖关系图中可能存在闭环,因此不能保证每个组件都满足该排序规则。如果给定相同的组件集和依赖关系,那么最终的排序结果应该是确定的。 -- CMake 会将 ``BUILD_COMPONENTS`` 的值以 “Component names:” 的形式打印出来。 -- 然后执行构建系统中包含的每个组件的配置。 -- 每个组件都被正常包含在构建系统中,然后再次执行 CMakeLists.txt 文件,将组件库加入构建系统。 - -组件依赖顺序 -^^^^^^^^^^^^ - -``BUILD_COMPONENTS`` 变量中组件的顺序决定了构建过程中的其它顺序,包括: - -- 项目导入 :ref:`project_include.cmake` 文件的顺序。 -- 生成用于编译(通过 ``-I`` 参数)的头文件路径列表的顺序。请注意,对于给定组件的源文件,仅需将该组件的依赖组件的头文件路径告知编译器。 - -构建的内部过程 -============== - -关于 CMake_ 以及 CMake 命令的详细信息,请参阅 `CMake v3.5 官方文档`_ 。 - -project.cmake 的内容 --------------------- - -当项目 CMakeLists 文件导入 ``project.cmake`` 文件时,``project.cmake`` 会定义一些实用的模块和全局变量。如果系统环境中没有设置 ``IDF_PATH``,那么它还会自动设置 ``IDF_PATH`` 变量。 - -``project.cmake`` 文件还重写了 CMake_ 内置的 ``project`` 函数,以添加所有 ESP-IDF 项目特有的功能。 - -project 函数 ------------- - -自定义的 ``project()`` 函数会执行以下步骤: - -- 确定硬件目标(由 ``IDF_TARGET`` 环境变量设置),并将其保存在 CMake cache 中。如果环境变量中设置的硬件目标与 CMake cache 中的不匹配,则会报错并退出。 -- 计算组件依赖,并构造 ``BUILD_COMPONENTS`` 变量,它是包含所有需要导入到构建系统中的组件列表(:ref:`详情请见上文`)。 -- 查找项目中所有的组件(搜索 ``COMPONENT_DIRS``,并按 ``COMPONENTS`` 进行过滤(前提是设置了该变量)。 -- 从 ``sdkconfig`` 文件中加载项目配置信息,生成 ``sdkconfig.cmake`` 和 ``sdkconfig.h`` 文件,分别用在 CMake 和 C/C++ 中定义配置项。如果项目配置发生了更改,CMake 会自动重新运行,重新生成上述两个文件,接着重新配置项目。 -- 根据硬件目标(``IDF_TARGET``)的值,将 `CMAKE_TOOLCHAIN_FILE`_ 变量设置为相应的工具链文件。 -- 调用 `CMake 的 project 函数 `_ 声明实际的 CMake-level 项目。 -- 加载 git 版本号。如果在 git 中检出了新的版本,就会使用一些技巧重新运行 CMake。详情请参考 :ref:`cmake-file-globbing`。 -- 从包含有 :ref:`project_include.cmake` 文件的组件中导入该文件。 -- 将每个组件都添加到构建系统中。每个组件的 CMakeLists 文件都会调用 ``register_component`` 函数,它会调用 CMake 的 `add_library `_ 函数来添加一个库,然后添加源文件、编译选项等。 -- 将最终的应用程序可执行文件添加到构建系统中。 -- 返回并为组件之间指定依赖关系(将每个组件的公共头文件目录添加到其他组件中)。 - -更多详细信息请参阅 :idf_file:`/tools/cmake/project.cmake` 文件和 :idf_file:`/tools/cmake/idf_functions.cmake` 文件。 - -CMake 调试 ----------- - -调试 ESP-IDF CMake 构建系统的一些技巧: - -- CMake 运行时,会打印大量诊断信息,包括组件列表和组件路径。 -- 运行 ``cmake -DDEBUG=1``,IDF 构建系统会生成更详细的诊断输出。 -- 运行 ``cmake`` 时指定 ``--trace`` 或 ``--trace-expand`` 选项会提供大量有关控制流信息。详情请参考 `CMake 命令行文档`_。 - -.. _warn-undefined-variables-cmake: - -警告未定义的变量 -^^^^^^^^^^^^^^^^ - -默认情况下,``idf.py`` 在调用 CMake_ 时会给它传递 ``--warn-uninitialized`` 标志,如果在构建的过程中引用了未定义的变量,CMake_ 会打印警告。这对查找有错误的 CMake 文件非常有用。 - -如果您不想启用此功能,可以给 ``idf.py`` 传递 ``--no-warnings`` 标志。 - -.. _override_project_config: - -覆盖项目的部分设置 ------------------- - -.. _project_include.cmake: - -project_include.cmake -^^^^^^^^^^^^^^^^^^^^^ - -如果组件的某些构建行为需要在组件 CMakeLists 文件之前被执行,您可以在组件目录下创建名为 ``project_include.cmake`` 的文件,``project.cmake`` 在运行过程中会导入此 CMake 文件。 - -``project_include.cmake`` 文件在 ESP-IDF 内部使用,以定义项目范围内的构建功能,比如 ``esptool.py`` 的命令行参数和 ``bootloader`` 这个特殊的应用程序。 - -与组件 ``CMakeLists.txt`` 文件有所不同,在导入``project_include.cmake`` 文件的时候,当前源文件目录(即 ``CMAKE_CURRENT_SOURCE_DIR``)和工作目录为项目目录。如果想获得当前组件的绝对路径,可以使用 ``COMPONENT_PATH`` 变量。 - -请注意,``project_include.cmake`` 对于大多数常见的组件并不是必需的。例如给项目添加 include 搜索目录,给最终的链接步骤添加 ``LDFLAGS`` 选项等等都可以通过 ``CMakeLists.txt`` 文件来自定义。详细信息请参考 :ref:`optional_project_variable`。 - -``project_include.cmake`` 文件会按照 ``BUILD_COMPONENTS`` 变量中组件的顺序(由 CMake 记录)依次导入。即只有在当前组件所有依赖组件的 ``project_include.cmake`` 文件都被导入后,当前组件的 ``project_include.cmake`` 文件才会被导入,除非两个组件在同一个依赖闭环中。如果某个 ``project_include.cmake`` 文件依赖于另一组件设置的变量,则要特别注意上述情况。更多详情请参阅 :ref:`component-requirements-implementation`。 - -在 ``project_include.cmake`` 文件中设置变量或目标时要格外小心,这些值被包含在项目的顶层 CMake 文件中,因此他们会影响或破坏所有组件的功能。 - -KConfig.projbuild -^^^^^^^^^^^^^^^^^ - -与 ``project_include.cmake`` 类似,也可以为组件定义一个 KConfig 文件以实现全局的 :ref:`component-configuration-cmake`。如果要在 menuconfig 的顶层添加配置选项,而不是在 “Component Configuration” 子菜单中,则可以在 ``CMakeLists.txt`` 文件所在目录的 KConfig.projbuild 文件中定义这些选项。 - -在此文件中添加配置时要小心,因为这些配置会包含在整个项目配置中。在可能的情况下,请为 :ref:`component-configuration-cmake` 创建 KConfig 文件。 - -.. _config_only_component: - -仅配置组件 -^^^^^^^^^^ - -仅配置组件是一类不包含源文件的特殊组件,仅包含 ``Kconfig.projbuild``、``KConfig`` 和 ``CMakeLists.txt`` 文件,该 ``CMakeLists.txt`` 文件仅有一行代码,调用了 ``register_config_only_component()`` 函数。此函数会将组件导入到项目构建中,但不会构建任何库,也不会将头文件添加到任何 include 搜索路径中。 - -如果 CMakeLists.txt 文件没有调用 ``register_component()`` 或 ``register_config_only_component()``,那么该文件将会被排除在项目构建之外。根据项目的配置,有时可能需要这么做。 - -.. _component_cmakelists_example: - -组件 CMakeLists 示例 -==================== - -因为构建环境试图设置大多数情况都能工作的合理默认值,所以组件 ``CMakeLists.txt`` 文件可能非常小,甚至是空的,请参考 :ref:`minimum_cmakelists`。但有些功能往往需要覆盖 :ref:`preset_component_variables` 才能实现。 - -以下是组件 CMakeLists 文件的更高级的示例。 - -.. _add_conditional_config: - -添加条件配置 ------------- - -配置系统可用于根据项目配置中选择的选项有条件地编译某些文件。 - -.. highlight:: none - -``Kconfig``:: - - config FOO_ENABLE_BAR - bool "Enable the BAR feature." - help - This enables the BAR feature of the FOO component. - -``CMakeLists.txt``:: - - set(COMPONENT_SRCS "foo.c" "more_foo.c") - - if(CONFIG_FOO_ENABLE_BAR) - list(APPEND COMPONENT_SRCS "bar.c") - endif() - -上述示例使用了 CMake 的 `if `_ 函数和 `list APPEND `_ 函数。 - -也可用于选择或删除某一实现,如下所示: - -``Kconfig``:: - - config ENABLE_LCD_OUTPUT - bool "Enable LCD output." - help - Select this if your board has a LCD. - - config ENABLE_LCD_CONSOLE - bool "Output console text to LCD" - depends on ENABLE_LCD_OUTPUT - help - Select this to output debugging output to the lcd - - config ENABLE_LCD_PLOT - bool "Output temperature plots to LCD" - depends on ENABLE_LCD_OUTPUT - help - Select this to output temperature plots - -.. highlight:: cmake - -``CMakeLists.txt``:: - - if(CONFIG_ENABLE_LCD_OUTPUT) - set(COMPONENT_SRCS lcd-real.c lcd-spi.c) - else() - set(COMPONENT_SRCS lcd-dummy.c) - endif() - - # 如果启用了控制台或绘图功能,则需要加入字体 - if(CONFIG_ENABLE_LCD_CONSOLE OR CONFIG_ENABLE_LCD_PLOT) - list(APPEND COMPONENT_SRCS "font.c") - endif() - - -硬件目标的的条件判断 --------------------- - -CMake 文件可以使用 ``IDF_TARGET`` 变量来获取当前的硬件目标。 - -此外,如果当前的硬件目标是 ``xyz``(即 ``IDF_TARGET=xyz``),那么 Kconfig 变量 ``CONFIG_IDF_TARGET_XYZ`` 同样也会被设置。 - -请注意,组件可以依赖 ``IDF_TARGET`` 变量,但不能依赖这个 Kconfig 变量。同样也不可在 CMake 文件的 ``include`` 语句中使用 Kconfig 变量,在这种上下文中可以使用 ``IDF_TARGET``。 - - -生成源代码 ----------- - -有些组件的源文件可能并不是由组件本身提供,而必须从另外的文件生成。假设组件需要一个头文件,该文件由 BMP 文件转换后(使用 bmp2h 工具)的二进制数据组成,然后将头文件包含在名为 graphics_lib.c 的文件中:: - - add_custom_command(OUTPUT logo.h - COMMAND bmp2h -i ${COMPONENT_DIR}/logo.bmp -o log.h - DEPENDS ${COMPONENT_DIR}/logo.bmp - VERBATIM) - - add_custom_target(logo DEPENDS logo.h) - add_dependencies(${COMPONENT_LIB} logo) - - set_property(DIRECTORY "${COMPONENT_DIR}" APPEND PROPERTY - ADDITIONAL_MAKE_CLEAN_FILES logo.h) - -这个示例改编自 `CMake 的一则 FAQ `_,其中还包含了一些同样适用于 ESP-IDF 构建系统的示例。 - -这个示例会在当前目录(构建目录)中生成 logo.h 文件,而 logo.bmp 会随组件一起提供在组件目录中。因为 logo.h 是一个新生成的文件,一旦项目需要清理,该文件也应该要被清除。因此,要将该文件添加到 `ADDITIONAL_MAKE_CLEAN_FILES`_ 属性中。 - -.. Note:: - - 如果需要生成文件作为项目 CMakeLists.txt 的一部分,而不是作为组件 CMakeLists.txt 的一部分,此时需要使用 ``${PROJECT_PATH}`` 替代 ``${COMPONENT_DIR}``,使用 ``${PROJECT_NAME}.elf`` 替代 ``${COMPONENT_LIB}``。 - -如果某个源文件是从其他组件中生成,且包含 ``logo.h`` 文件,则需要调用 ``add_dependencies``, 在这两个组件之间添加一个依赖项,以确保组件源文件按照正确顺序进行编译。 - -嵌入二进制数据 ---------------------- - -有时您的组件希望使用一个二进制文件或者文本文件,但是您又不希望将它们重新格式化为 C 源文件,这时,您可以在组件 CMakeLists 中添加 ``COMPONENT_EMBED_FILES`` 变量,指定要嵌入的文件名称(以空格分隔):: - - set(COMPONENT_EMBED_FILES server_root_cert.der) - -或者,如果文件是字符串,则可以设置 ``COMPONENT_EMBED_TXTFILES`` 变量,把文件的内容转成以 null 结尾的字符串嵌入:: - - set(COMPONENT_EMBED_TXTFILES server_root_cert.pem) - -.. highlight:: c - -文件的内容会被添加到 Flash 的 .rodata 段,用户可以通过符号名来访问,如下所示:: - - 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"); - -符号名会根据文件全名生成,如 ``COMPONENT_EMBED_FILES`` 中所示,字符 ``/``、``.`` 等都会被下划线替代。符号名称中的 _binary 前缀由 objcopy 命令添加,对文本文件和二进制文件都是如此。 - -.. highlight:: cmake - -如果要将文件嵌入到项目中,而非组件中,可以调用 ``target_add_binary_data`` 函数:: - - target_add_binary_data(myproject.elf "main/data.bin" TEXT) - -并这行代码放在项目 CMakeLists.txt 的 ``project()`` 命令之后,修改 ``myproject.elf`` 为你自己的项目名。如果最后一个参数是 ``TEXT``,那么构建系统会嵌入以 null 结尾的字符串,如果最后一个参数被设置为 ``BINARY``,则将文件内容按照原样嵌入。 - -有关使用此技术的示例,请参考 :example:`protocols/https_request`,证书文件的内容会在编译时从 .pem 文件中加载。 - -代码和数据的存放 ----------------- - -ESP-IDF 还支持自动生成链接脚本,它允许组件通过链接片段文件定义其代码和数据在内存中的存放位置。构建系统会处理这些链接片段文件,并将处理后的结果扩充进链接脚本,从而指导应用程序二进制文件的链接过程。更多详细信息与快速上手指南,请参阅 :doc:`链接脚本生成机制 `。 - -.. _component-build-full-override: - -完全覆盖组件的构建过程 ----------------------- - -.. highlight:: cmake - -当然,在有些情况下,上面提到的方法不一定够用。如果组件封装了另一个第三方组件,而这个第三方组件并不能直接在 ESP-IDF 的构建系统中工作,在这种情况下,就需要放弃 ESP-IDF 的构建系统,改为使用 CMake 的 ExternalProject_ 功能。组件 CMakeLists 示例如下:: - - # 用于 quirc 的外部构建过程,在源目录中运行并生成 libquirc.a - externalproject_add(quirc_build - PREFIX ${COMPONENT_DIR} - SOURCE_DIR ${COMPONENT_DIR}/quirc - CONFIGURE_COMMAND "" - BUILD_IN_SOURCE 1 - BUILD_COMMAND make CC=${CMAKE_C_COMPILER} libquirc.a - INSTALL_COMMAND "" - ) - - # 将 libquirc.a 添加到构建系统中 - add_library(quirc STATIC IMPORTED GLOBAL) - add_dependencies(quirc quirc_build) - - set_target_properties(quirc PROPERTIES IMPORTED_LOCATION - ${COMPONENT_DIR}/quirc/libquirc.a) - set_target_properties(quirc PROPERTIES INTERFACE_INCLUDE_DIRECTORIES - ${COMPONENT_DIR}/quirc/lib) - - set_directory_properties( PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES - "${COMPONENT_DIR}/quirc/libquirc.a") - -(上述 CMakeLists.txt 可用于创建名为 ``quirc`` 的组件,该组件使用自己的 Makefile 构建 quirc_ 项目。) - -- ``externalproject_add`` 定义了一个外部构建系统。 - - - 设置 ``SOURCE_DIR``、``CONFIGURE_COMMAND``、``BUILD_COMMAND`` 和 ``INSTALL_COMMAND``。如果外部构建系统没有配置这一步骤,可以将 ``CONFIGURE_COMMAND`` 设置为空字符串。在 ESP-IDF 的构建系统中,一般会将 ``INSTALL_COMMAND`` 变量设置为空。 - - 设置 ``BUILD_IN_SOURCE``,即构建目录与源目录相同。否则,您也可以设置 ``BUILD_DIR`` 变量。 - - 有关 ``externalproject_add()`` 命令的详细信息,请参阅 ExternalProject_。 - -- 第二组命令添加了一个目标库,指向外部构建系统生成的库文件。为了添加 include 目录,并告知 CMake 该文件的位置,需要再设置一些属性。 -- 最后,生成的库被添加到 `ADDITIONAL_MAKE_CLEAN_FILES`_ 中。即执行 ``make clean`` 后会删除该库。请注意,构建系统中的其他目标文件不会被删除。 - -.. note:: 当外部构建系统使用 PSRAM 时,请记得将 ``-mfix-esp32-psram-cache-issue`` 添加到 C 编译器的参数中。关于该标志的更多详细信息,请参考 :ref:`CONFIG_SPIRAM_CACHE_WORKAROUND`。 - -.. _ADDITIONAL_MAKE_CLEAN_FILES_note: - -ExternalProject 的依赖与构建清理 -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -对于外部项目的构建,CMake 会有一些不同寻常的行为: - -- `ADDITIONAL_MAKE_CLEAN_FILES`_ 仅在使用 Make 构建系统时有效。如果使用 Ninja_ 或 IDE 自带的构建系统,执行项目清理时,这些文件不会被删除。 -- ExternalProject_ 会在 clean 运行后自动重新运行配置和构建命令。 -- 可以采用以下两种方法来配置外部构建命令: - - 1. 将外部 ``BUILD_COMMAND`` 命令设置为对所有源代码完整的重新编译。如果传递给 ``externalproject_add`` 命令的 ``DEPENDS`` 的依赖项发生了改变,或者当前执行的是项目清理操作(即运行了 ``idf.py clean``、``ninja clean`` 或者 ``make clean``),那么就会执行该命令。 - 2. 将外部 ``BUILD_COMMAND`` 命令设置为增量式构建命令,并给 ``externalproject_add`` 传递 ``BUILD_ALWAYS 1`` 参数。即不管实际的依赖情况,每次构建时,都会构建外部项目。这种方式仅当外部构建系统具备增量式构建的能力,且运行时间不会很长时才推荐。 - -构建外部项目的最佳方法取决于项目本身、其构建系统,以及是否需要频繁重新编译项目。 - -.. _custom-sdkconfig-defaults-cmake: - -自定义 sdkconfig 的默认值 -========================= - -对于示例工程或者其他您不想指定完整 sdkconfig 配置的项目,但是您确实希望覆盖 ESP-IDF 默认值中的某些键值,则可以在项目中创建 ``sdkconfig.defaults`` 文件。重新创建新配置时将会用到此文件,另外在 ``sdkconfig`` 没有设置新配置值时,上述文件也会被用到。 - -如若需要覆盖此文件的名称,请设置 ``SDKCONFIG_DEFAULTS`` 环境变量。 - -依赖于硬件目标的 sdkconfig 默认值 ---------------------------------- - -除了 ``sdkconfig.defaults`` 之外,构建系统还将从 ``sdkconfig.defaults.TARGET_NAME`` 文件加载默认值,其中 ``IDF_TARGET`` 的值为 ``TARGET_NAME``。例如,对于 ``ESP32`` 这个硬件目标,sdkconfig 的默认值会首先从 ``sdkconfig.defaults`` 获取,然后再从 ``sdkconfig.defaults.esp32`` 获取。 - -如果使用 ``SDKCONFIG_DEFAULTS`` 覆盖了 sdkconfig 默认文件的名称,则硬件目标的 sdkconfig 默认文件名也会从 ``SDKCONFIG_DEFAULTS`` 值中派生。 - -.. _flash_parameters: - -Flash 参数 -========== - -有些情况下,我们希望在没有 IDF 时也能烧写目标板卡,为此,我们希望可以保存已构建的二进制文件、esptool.py 和 esptool write_flash 命令的参数。可以通过编写一段简单的脚本来保存二进制文件和 esptool.py。 - -运行项目构建之后,构建目录将包含项目二进制输出文件(``.bin`` 文件),同时也包含以下烧录数据文件: - -- ``flash_project_args`` 包含烧录整个项目的参数,包括应用程序 (app)、引导程序 (bootloader)、分区表,如果设置了 PHY 数据,也会包含此数据。 -- ``flash_app_args`` 只包含烧录应用程序的参数。 -- ``flash_bootloader_args`` 只包含烧录引导程序的参数。 - -.. highlight:: bash - -您可以参照如下命令将任意烧录参数文件传递给 ``esptool.py``:: - - python esptool.py --chip esp32 write_flash @build/flash_project_args - -也可以手动复制参数文件中的数据到命令行中执行。 - -构建目录中还包含生成的 ``flasher_args.json`` 文件,此文件包含 JSON 格式的项目烧录信息,可用于 ``idf.py`` 和其它需要项目构建信息的工具。 - -构建 Bootloader -=============== - -引导程序默认作为 ``idf.py build`` 的一部分被构建,也可以通过 ``idf.py bootloader`` 来单独构建。 - -引导程序是 :idf:`/components/bootloader/subproject` 内部独特的“子项目”,它有自己的项目 CMakeLists.txt 文件,能够构建独立于主项目的 ``.ELF`` 和 ``.BIN`` 文件,同时它又与主项目共享配置和构建目录。 - -子项目通过 :idf_file:`/components/bootloader/project_include.cmake` 文件作为外部项目插入到项目的顶层,主构建进程会运行子项目的 CMake,包括查找组件(主项目使用的组件的子集),生成引导程序专用的配置文件(从主 ``sdkconfig`` 文件中派生)。 - -选择硬件目标 -============ - -当前 ESP-IDF 仅支持一个硬件目标,即 ``esp32``,这也是构建系统默认的硬件目标。开发人员可以按照如下方法来添加对新硬件目标的支持:: - - rm sdkconfig - idf.py -DIDF_TARGET=new_target reconfigure - -.. _write-pure-cmake-component: - -编写纯 CMake 组件 -================= - -ESP-IDF 构建系统用“组件”的概念“封装”了 CMake,并提供了很多帮助函数来自动将这些组件集成到项目构建当中。 - -然而,“组件”概念的背后是一个完整的 CMake 构建系统,因此可以制作纯 CMake 组件。 - -.. highlight:: cmake - -下面是使用纯 CMake 语法为 ``json`` 组件编写的最小 CMakeLists 文件的示例:: - - add_library(json STATIC - cJSON/cJSON.c - cJSON/cJSON_Utils.c) - - target_include_directories(json PUBLIC cJSON) - -- 这实际上与 IDF 中的 :idf_file:`json 组件 ` 是等效的。 -- 因为组件中的源文件不多,所以这个 CMakeLists 文件非常简单。对于具有大量源文件的组件而言,ESP-IDF 支持的组件通配符,可以简化组件 CMakeLists 的样式。 -- 每当组件中新增一个与组件同名的库目标时,ESP-IDF 构建系统会自动将其添加到构建中,并公开公共的 include 目录。如果组件想要添加一个与组件不同名的库目标,就需要使用 CMake 命令手动添加依赖关系。 - -组件中使用第三方 CMake 项目 -=========================== - -CMake 在许多开源的 C/C++ 项目中广泛使用,用户可以在自己的应用程序中使用开源代码。CMake 构建系统的一大好处就是可以导入这些第三方的项目,有时候甚至不用做任何改动。这就允许用户使用当前 ESP-IDF 组件尚未提供的功能,或者使用其它库来实现相同的功能。 - -.. highlight:: cmake - -假设 ``main`` 组件需要导入一个假想库 ``foo``,相应的组件 CMakeLists 文件如下所示:: - - # 注册组件 - register_component() - - # 设置 `foo` 项目中的一些 CMake 变量,以控制 `foo` 的构建过程 - set(FOO_BUILD_STATIC OFF) - set(FOO_BUILD_TESTS OFF) - - # 创建并导入第三方库目标 - add_subdirectory(foo) - - # 将 IDF 全局的编译器设置、宏定义及其它选项传递给 `foo` 目标 - target_include_directories(foo ${IDF_INCLUDE_DIRECTORIES}) - target_compile_options(foo ${IDF_COMPILE_OPTIONS}) - target_compile_definitions(foo ${IDF_COMPILE_DEFINITIONS}) - - # 将 `foo` 目标链接至 `main` 组件 - target_link_libraries(main foo) - -实际的案例请参考 :example:`build_system/cmake/import_lib`。请注意,导入第三方库所需要做的工作可能会因库的不同而有所差异。建议仔细阅读第三方库的文档,了解如何将其导入到其它项目中。阅读第三方库的 CMakeLists.txt 文件以及构建结构也会有所帮助。 - -用这种方式还可以将第三方库封装成 ESP-IDF 的组件。例如 :component:`mbedtls` 组件就是封装了 `mbedtls 项目 `_ 得到的。详情请参考 :component_file:`mbedtls 组件的 CMakeLists.txt 文件 `。 - -每当使用 ESP-IDF 构建系统时,CMake 变量 ``ESP_PLATFORM`` 都会被设置为 1。如果要在通用的 CMake 代码加入 IDF 特定的代码时,可以采用 ``if (ESP_PLATFORM)`` 的形式加以分隔。 - -在自定义 CMake 项目中使用 ESP-IDF -================================= - -ESP-IDF 提供了一个模板 CMake 项目,可以基于此轻松创建应用程序。然而在有些情况下,用户可能已有一个现成的 CMake 项目,或者想自己创建一个 CMake 项目,此时就希望将 IDF 中的组件以库的形式链接到用户目标(库/可执行文件)。 - -.. highlight:: cmake - -使用 :idf_file:`tools/cmake/idf_functions.cmake` 中提供的 ``idf_import_components`` 和 ``idf_link_components`` 函数可以实现上述功能,例如:: - - cmake_minimum_required(VERSION 3.5) - project(my_custom_app C) - - # 源文件 main.c 包含有 app_main() 函数的定义 - add_executable(${CMAKE_PROJECT_NAME}.elf main.c) - - # 提供 idf_import_components 及 idf_link_components 函数 - include($ENV{IDF_PATH}/tools/cmake/idf_functions.cmake) - - # 为 idf_import_components 做一些配置 - # 使能创建构件(不是每个项目都必须) - set(IDF_BUILD_ARTIFACTS ON) - set(IDF_PROJECT_EXECUTABLE ${CMAKE_PROJECT_NAME}.elf) - set(IDF_BUILD_ARTIFACTS_DIR ${CMAKE_BINARY_DIR}) - - # idf_import_components 封装了 add_subdirectory(),为组件创建库目标,然后使用给定的变量接收“返回”的库目标。 - # 在本例中,返回的库目标被保存在“component”变量中。 - idf_import_components(components $ENV{IDF_PATH} esp-idf) - - # idf_link_components 封装了 target_link_libraries(),将被 idf_import_components 处理过的组件链接到目标 - idf_link_components(${CMAKE_PROJECT_NAME}.elf "${components}") - -上述代码片段导入了 ESP-IDF 目录下的所有组件,并使用了 KConfig 中的默认值,同时还允许创建其它一些构件(比如分区表、包含项目信息的 json 文件、引导程序等)。除此以外,用户还可以设置其它的构建参数,其完整列表如下: - -- ``IDF_BUILD_ARTIFACTS``:构建工件,例如引导加载程序、分区表二进制文件、分区二进制数据、将二进制文件烧录到目标芯片时所需的包含项目信息的 json 文件等。同时需要设置 ``IDF_PROJECT_EXECUTABLE`` 和 ``IDF_BUILD_ARTIFACTS_DIR`` 变量。 -- ``IDF_PROJECT_EXECUTABLE``:最终可执行文件的名称。某些工件在创建的时候需要此参数。 -- ``IDF_BUILD_ARTIFACTS_DIR``:创建的构件被存放的位置。 -- ``IDF_EXTRA_COMPONENTS_DIR``:在 :idf:`默认组件目录 ` 之外的组件搜索路径。 -- ``IDF_COMPONENTS``:要导入的组件列表,设置此变量可以精简导入的组件,仅导入需要的组件,加快构建的速度。如果没有设置该变量,将会导入默认组件目录以及 ``IDF_EXTRA_COMPONENTS_DIR`` (如果设置了该变量)中找到的所有组件。请注意,该列表中组件的依赖组件(除了 ``IDF_COMPONENT_REQUIRES_COMMON`` 之外)也会被加入到构建之中。 -- ``IDF_COMPONENT_REQUIRES_COMMON``:通用组件依赖列表。无论 ``IDF_COMPONENTS`` 的值是什么,此列表中的组件及其依赖组件都会被导入到构建中。默认情况下,此变量被设置为核心“系统”组件的最小集合。 -- ``IDF_SDKCONFIG_DEFAULTS``:配置文件的覆盖路径,如果未设置,组件将会使用默认的配置选项来构建。 -- ``IDF_BUILD_TESTS``:在构建中包含组件的测试。默认情况下,所有的组件测试都会被包含。组件测试可通过 ``IDF_TEST_COMPONENTS`` 和 ``IDF_TEST_EXCLUDE_COMPONENTS`` 进行过滤。 -- ``IDF_TEST_COMPONENTS``:如果设置了 ``IDF_BUILD_TESTS``,构建中只会包含此列表中的组件测试。如果没有设置 ``IDF_BUILD_TESTS``,请忽略此项。 -- ``IDF_TEST_EXCLUDE_COMPONENTS``:如果设置了 ``IDF_BUILD_TESTS``,此列表中的组件测试将不会包含在构建中。如果没有设置 ``IDF_BUILD_TESTS``,请忽略此项。该变量的优先级高于 ``IDF_TEST_COMPONENTS``,这意味着,即使 ``IDF_TEST_COMPONENTS`` 中也存在此列表中的组件测试,它也不会被包含到构建之中。 - -:example:`build_system/cmake/idf_as_lib` 中的示例演示了如何在自定义的 CMake 项目创建一个类似于 :example:`Hello World ` 的应用程序。 - -.. _cmake-file-globbing: - -文件通配符 & 增量构建 -===================== - -.. highlight:: cmake - -在 ESP-IDF 组件中添加源文件的首选方法是在 ``COMPONENT_SRCS`` 中手动列出它们:: - - set(COMPONENT_SRCS library/a.c library/b.c platform/platform.c) - -这是在 CMake 中手动列出源文件的 `最佳实践 `_。然而,当有许多源文件都需要添加到构建中时,这种方法就会很不方便。ESP-IDF 构建系统因此提供了另一种替代方法,即使用 ``COMPONENT_SRCDIRS`` 来指定源文件:: - - set(COMPONENT_SRCDIRS library platform) - -后台会使用通配符在指定的目录中查找源文件。但是请注意,在使用这种方法的时候,如果组件中添加了一个新的源文件,CMake 并不知道重新运行配置,最终该文件也没有被加入构建中。 - -如果是自己添加的源文件,这种折衷还是可以接受的,因为用户可以触发一次干净的构建,或者运行 ``idf.py reconfigure`` 来手动重启 CMake_。但是,如果你需要与其他使用 Git 等版本控制工具的开发人员共享项目时,问题就会变得更加困难,因为开发人员有可能会拉取新的版本。 - -ESP-IDF 中的组件使用了第三方的 Git CMake 集成模块(:idf_file:`/tools/cmake/third_party/GetGitRevisionDescription.cmake`),任何时候源码仓库的提交记录发生了改变,该模块就会自动重新运行 CMake。即只要 拉取了新的 ESP-IDF 版本,CMake 就会重新运行。 - -对于不属于 ESP-IDF 的项目组件,有以下几个选项供参考: - -- 如果项目文件保存在 Git 中,ESP-IDF 会自动跟踪 Git 修订版本,并在它发生变化时重新运行 CMake。 -- 如果一些组件保存在第三方 Git 仓库中(不在项目仓库或 ESP-IDF 仓库),则可以在组件 CMakeLists 文件中调用 ``git_describe`` 函数,以便在 Git 修订版本发生变化时自动重启 CMake。 -- 如果没有使用 Git,请记住在源文件发生变化时手动运行 ``idf.py reconfigure``。 -- 使用 ``COMPONENT_SRCS`` 在项目组件中列出所有源文件,可以完全避免这一问题。 - -具体选择哪一方式,就要取决于项目本身,以及项目用户。 - -.. _build_system_metadata: - -构建系统的元数据 -================ - -为了将 ESP-IDF 集成到 IDE 或者其它构建系统中,CMake 在构建的过程中会在 ``build/`` 目录下生成大量元数据文件。运行 ``cmake`` 或 ``idf.py reconfigure`` (或任何其它 ``idf.py`` 构建命令),可以重新生成这些元数据文件。 - -- ``compile_commands.json`` 是标准格式的 JSON 文件,它描述了在项目中参与编译的每个源文件。CMake 其中的一个功能就是生成此文件,许多 IDE 都知道如何解析此文件。 -- ``project_description.json`` 包含有关 ESP-IDF 项目、已配置路径等的一些常规信息。 -- ``flasher_args.json`` 包含 esptool.py 工具用于烧录项目二进制文件的参数,此外还有 ``flash_*_args`` 文件,可直接与 esptool.py 一起使用。更多详细信息请参阅 :ref:`flash_parameters`。 -- ``CMakeCache.txt`` 是 CMake 的缓存文件,包含 CMake 进程、工具链等其它信息。 -- ``config/sdkconfig.json`` 包含 JSON 格式的项目配置结果。 -- ``config/kconfig_menus.json`` 是在 menuconfig 中显示菜单的 JSON 格式版本,用于外部 IDE 的 UI。 - -JSON 配置服务器 ---------------- - -.. highlight :: json - -``confserver.py`` 工具可以帮助 IDE 轻松地与配置系统的逻辑进行集成,它运行在后台,通过使用 stdin 和 stdout 读写 JSON 文件的方式与调用进程交互。 - -您可以通过 ``idf.py confserver`` 或 ``ninja confserver`` 从项目中运行 ``confserver.py``,也可以使用不同的构建生成器来触发类似的目标。 - -配置服务器会向 stderr 输出方便阅读的错误和警告信息,向 stdout 输出 JSON 文件。启动时,配置服务器将以 JSON 字典的形式输出系统中每个配置项的完整值,以及范围受限的值的可用范围。``sdkconfig.json`` 中包含有相同的信息:: - - {"version": 1, "values": { "ITEM": "value", "ITEM_2": 1024, "ITEM_3": false }, "ranges" : { "ITEM_2" : [ 0, 32768 ] } } - -配置服务器仅发送可见的配置项,其它不可见的或者被禁用的配置项可从 ``kconfig_menus.json`` 静态文件中解析得到,此文件还包含菜单结构和其它元数据(描述、类型、范围等)。 - -然后配置服务器将等待客户端的输入,客户端会发起请求,要求更改一个或多个配置项的值,内容的格式是个 JSON 对象,后面跟一个换行符:: - - {"version": "1", "set": {"SOME_NAME": false, "OTHER_NAME": true } } - -配置服务器将解析此请求,更新 ``sdkconfig`` 文件,并返回完整的变更列表:: - - {"version": 1, "values": {"SOME_NAME": false, "OTHER_NAME": true , "DEPENDS_ON_SOME_NAME": null}} - -当前不可见或者禁用的配置项会返回 ``null``,任何新的可见配置项则会返回其当前新的可见值。 - -如果配置项的取值范围因另一个值的变化发生了改变,那么配置服务器会发送:: - - {"version": 1, "values": {"OTHER_NAME": true }, "ranges" : { "HAS_RANGE" : [ 3, 4 ] } } - -如果传递的数据无效,那么 JSON 对象中会有 ``error`` 字段:: - - {"version": 1, "values": {}, "error": ["The following config symbol(s) were not visible so were not updated: NOT_VISIBLE_ITEM"]} - -默认情况下,变更后的配置不会被写进 sdkconfig 文件。更改的内容在发出 “save” 命令之前会先储存在内存中:: - - {"version": 1, "save": null } - -若要从已保存的文件中重新加载配置值,并丢弃内存中的任何更改,可以发送 “load” 命令:: - - {"version": 1, "load": null } - -“load” 和 “save” 的值可以是新的路径名,也可以设置为 "null" 用以加载/保存之前使用的路径名。 - -配置服务器对 “load” 命令的响应始终是完整的配置值和取值范围的集合,这与服务器初始启动阶段的响应相同。 - -“load”、“set” 和 “save” 的任意组合可以在一条单独的命令中发送出去,服务器按照组合中的顺序执行命令。因此,可以使用一条命令实现从文件中加载配置,更新配置值,然后将其保存到文件中。 - -.. Note:: 配置服务器不会自动加载外部对 ``sdkconfig`` 文件的任何更改。如果文件被外部编辑,则需要发送 “load” 命令或重启服务器。 - -.. Note:: ``sdkconfig`` 文件更新后,配置服务器不会重新运行 CMake 来生成其它的构建文件和元数据文件。这些文件会在下一次运行 ``CMake`` 或 ``idf.py`` 时自动生成。 - -.. _gnu-make-to-cmake: - -从 ESP-IDF GNU Make 构建系统迁移到 CMake 构建系统 -================================================= - -ESP-IDF CMake 构建系统与旧版的 GNU Make 构建系统在某些方面非常相似,例如将 ``component.mk`` 文件改写 ``CMakeLists.txt``,像 ``COMPONENT_ADD_INCLUDEDIRS`` 和 ``COMPONENT_SRCDIRS`` 等变量可以保持不变,只需将语法改为 CMake 语法即可。 - -自动转换工具 ------------- - -.. highlight:: bash - -:idf_file:`/tools/cmake/convert_to_cmake.py` 中提供了一个项目自动转换工具。运行此命令时需要加上项目路径,如下所示:: - - $IDF_PATH/tools/cmake/convert_to_cmake.py /path/to/project_dir - -项目目录必须包含 Makefile 文件,并确保主机已安装 GNU Make (``make``) 工具,并且被添加到了 PATH 环境变量中。 - -该工具会将项目 Makefile 文件和所有组件的 ``component.mk`` 文件转换为对应的 ``CMakeLists.txt`` 文件。 - -转换过程如下:该工具首先运行 ``make`` 来展开 ESP-IDF 构建系统设置的变量,然后创建相应的 CMakelists 文件来设置相同的变量。 - -转换工具并不能处理复杂的 Makefile 逻辑或异常的目标,这些需要手动转换。 - -CMake 中不可用的功能 --------------------- - -有些功能已从 CMake 构建系统中移除,或者已经发生很大改变。GNU Make 构建系统中的以下变量已从 CMake 构建系统中删除: - -- ``COMPONENT_BUILD_DIR``:由 ``CMAKE_CURRENT_BINARY_DIR`` 替代。 -- ``COMPONENT_LIBRARY``:默认为 ``$(COMPONENT_NAME).a`` 但是库名可以被组件覆盖。在 CMake 构建系统中,组件库名称不可再被组件覆盖。 -- ``CC``、``LD``、``AR``、``OBJCOPY``:gcc xtensa 交叉工具链中每个工具的完整路径。CMake 使用 ``CMAKE_C_COMPILER``、``CMAKE_C_LINK_EXECUTABLE`` 和 ``CMAKE_OBJCOPY`` 进行替代。完整列表请参阅 `CMake 语言变量 `_。 -- ``HOSTCC``、``HOSTLD``、``HOSTAR``:宿主机本地工具链中每个工具的全名。CMake 系统不再提供此变量,外部项目需要手动检测所需的宿主机工具链。 -- ``COMPONENT_ADD_LDFLAGS``:用于覆盖链接标志。CMake 中使用 `target_link_libraries`_ 命令替代。 -- ``COMPONENT_ADD_LINKER_DEPS``:链接过程依赖的文件列表。`target_link_libraries`_ 通常会自动推断这些依赖。对于链接脚本,可以使用自定义的 CMake 函数 ``target_linker_scripts``。 -- ``COMPONENT_SUBMODULES``:不再使用。CMake 会自动枚举 ESP-IDF 仓库中所有的子模块。 -- ``COMPONENT_EXTRA_INCLUDES``:曾是 ``COMPONENT_PRIV_INCLUDEDIRS`` 变量的替代版本,仅支持绝对路径。CMake 系统中统一使用 ``COMPONENT_PRIV_INCLUDEDIRS`` (可以是相对路径,也可以是绝对路径)。 -- ``COMPONENT_OBJS``:以前,可以以目标文件列表的方式指定组件源,现在,可以通过 ``COMPONENT_SRCS`` 以源文件列表的形式指定组件源。 -- ``COMPONENT_OBJEXCLUDE``:已被 ``COMPONENT_SRCEXCLUDE`` 替换。用于指定源文件(绝对路径或组件目录的相对路径)。 -- ``COMPONENT_EXTRA_CLEAN``:已被 ``ADDITIONAL_MAKE_CLEAN_FILES`` 属性取代,注意,:ref:`CMake 对此项功能有部分限制 `。 -- ``COMPONENT_OWNBUILDTARGET`` & ``COMPONENT_OWNCLEANTARGET``:已被 CMake `外部项目 `_ 替代,详细内容请参阅 :ref:`component-build-full-override`。 -- ``COMPONENT_CONFIG_ONLY``:已被 ``register_config_only_component()`` 函数替代,请参阅 :ref:`config_only_component`。 -- ``CFLAGS``、``CPPFLAGS``、``CXXFLAGS``:已被相应的 CMake 命令替代,请参阅 :ref:`component_build_control`。 - -无默认值的变量 --------------- - -以下变量不再具有默认值: - -- ``COMPONENT_SRCDIRS`` -- ``COMPONENT_ADD_INCLUDEDIRS`` - -不再需要的变量 --------------- - -如果设置了 ``COMPONENT_SRCS``,就不需要再设置 ``COMPONENT_SRCDIRS``。实际上,CMake 构建系统中如果设置了 ``COMPONENT_SRCDIRS``,那么 ``COMPONENT_SRCS`` 就会被忽略。 - -从 Make 中烧录 --------------- - -仍然可以使用 ``make flash`` 或者类似的目标来构建和烧录,但是项目 ``sdkconfig`` 不能再用来指定串口和波特率。可以使用环境变量来覆盖串口和波特率的设置,详情请参阅 :ref:`flash-with-ninja-or-make`。 - -.. _esp-idf-template: https://github.com/espressif/esp-idf-template -.. _Cmake: https://cmake.org -.. _ninja: https://ninja-build.org -.. _esptool.py: https://github.com/espressif/esptool/#readme -.. _CMake v3.5 官方文档: https://cmake.org/cmake/help/v3.5/index.html -.. _cmake 命令行文档: https://cmake.org/cmake/help/v3.5/manual/cmake.1.html#options -.. _cmake add_library: https://cmake.org/cmake/help/v3.5/command/add_library.html -.. _cmake if: https://cmake.org/cmake/help/v3.5/command/if.html -.. _cmake list: https://cmake.org/cmake/help/v3.5/command/list.html -.. _cmake project: https://cmake.org/cmake/help/v3.5/command/project.html -.. _cmake set: https://cmake.org/cmake/help/v3.5/command/set.html -.. _cmake string: https://cmake.org/cmake/help/v3.5/command/string.html -.. _cmake faq generated files: https://cmake.org/Wiki/CMake_FAQ#How_can_I_generate_a_source_file_during_the_build.3F -.. _ADDITIONAL_MAKE_CLEAN_FILES: https://cmake.org/cmake/help/v3.5/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.html -.. _ExternalProject: https://cmake.org/cmake/help/v3.5/module/ExternalProject.html -.. _cmake language variables: https://cmake.org/cmake/help/v3.5/manual/cmake-variables.7.html#variables-for-languages -.. _set_source_files_properties: https://cmake.org/cmake/help/v3.5/command/set_source_files_properties.html -.. _target_compile_options: https://cmake.org/cmake/help/v3.5/command/target_compile_options.html -.. _target_link_libraries: https://cmake.org/cmake/help/v3.5/command/target_link_libraries.html#command:target_link_libraries -.. _cmake_toolchain_file: https://cmake.org/cmake/help/v3.5/variable/CMAKE_TOOLCHAIN_FILE.html -.. _quirc: https://github.com/dlbeer/quirc -.. _pyenv: https://github.com/pyenv/pyenv#README -.. _virtualenv: https://virtualenv.pypa.io/en/stable/ diff --git a/docs/zh_CN/api-guides/build-system-legacy.rst b/docs/zh_CN/api-guides/build-system-legacy.rst new file mode 100644 index 0000000000..cc72410057 --- /dev/null +++ b/docs/zh_CN/api-guides/build-system-legacy.rst @@ -0,0 +1,542 @@ +构建系统 (传统 GNU Make) +========================== +:link_to_translation:`en:[English]` + +.. include:: ../gnu-make-legacy.rst + +本文将介绍乐鑫物联网开发框架中的 ``构建系统`` 和 ``组件`` 的相关概念。 + +如果您想了解如何构建一个新的 ESP-IDF 项目,请阅读本文档。 + +我们建议您使用 `ESP-IDF 模板工程 `_ 来开始您的新项目。 + +使用构建系统 +------------ + +ESP-IDF 的 :idf_file:`README.md` 文件对如何使用构建系统来构建项目作了简要的说明。 + +概述 +---- + +一个 ESP-IDF 项目可以看作是许多不同组件的集合,例如对于一个展示当前湿度的网站服务器来说,它可能会包含如下一些组件: + +- ESP32 基础库(libc,rom bindings 等) +- WiFi 驱动库 +- TCP/IP 协议栈 +- FreeRTOS 操作系统 +- 网站服务器 +- 湿度传感器的驱动 +- 将上述组件组织在一起的主代码 + +ESP-IDF 可以显式地指定和配置每个组件。在构建项目的时候,构建系统会查找 ESP-IDF 目录、项目目录和用户自定义目录(可选)中所有的组件,然后使用基于文本的菜单系统让用户配置 ESP-IDF 项目中需要的每个组件。在配置结束后,构建系统开始编译整个项目。 + +概念 +~~~~ + +- ``项目`` 特指一个目录,其中包含了构建可执行文件的所有源文件和配置,还有其他的支持型输出文件,比如分区表、数据/文件系统分区和引导程序。 + +- ``项目配置`` 保存在项目根目录下名为 sdkconfig 的文件中,它可以通过 ``make menuconfig`` 进行修改,且一个项目只能包含一个项目配置。 + +- ``应用程序`` 是由 ESP-IDF 构建得到的可执行文件。一个项目通常会构建两个应用程序:项目应用程序(主可执行文件,即用户自定义的固件)和引导程序(启动并初始化项目应用程序的引导程序)。 + +- ``组件`` 是模块化的、独立的代码,它们被编译成静态库(.a 文件)后再链接成应用程序,有些组件是 ESP-IDF 官方提供的,有些则可能来自其它项目。 + +以下内容并不是项目的组成部分: + +- ``ESP-IDF`` 并不是项目的一部分,相反,它是独立的,并通过 IDF_PATH 环境变量链接到项目中,这样做就可以使 IDF 框架与您的项目分离,其中 IDF_PATH 变量保存了 ESP-IDF 目录的路径。 + +- 交叉编译工具链并不是项目的组成部分,它应该被安装在系统 PATH 环境变量中,或者可以在项目配置中显式指定工具链的前缀为本地的安装路径。 + +示例项目 +~~~~~~~~ + +示例项目的目录树结构可能如下所示: + +.. code:: + + - myProject/ + - Makefile + - sdkconfig + - components/ - component1/ - component.mk + - Kconfig + - src1.c + - component2/ - component.mk + - Kconfig + - src1.c + - include/ - component2.h + - main/ - src1.c + - src2.c + - component.mk + - build/ + +该示例项目 ``myProject`` 包含以下组成部分: + +- 项目顶层 Makefile,该 Makefile 设置了 ``PROJECT_NAME`` 变量,还可以定义作用于整个项目的其它 make 变量(可选)。顶层 Makefile 会导入核心 Makefile 文件 ``$(IDF_PATH)/make/project.mk`` ,由它负责实现 ESP-IDF 构建系统的剩余部分。 + +- 项目配置文件 sdkconfig,执行 ``make menuconfig`` 后会创建或更新此文件,该文件中保存了项目中所有组件的配置信息(包括 ESP-IDF 本身)。``sdkconfig`` 文件可能会也可能不会被添加到项目的源代码管理系统中。 + +- 可选的组件目录中包含了属于项目一部分的自定义组件,不是每一个项目都需要它,但它有助于构建可重用代码或者导入第三方组件。 + +- ``main`` 目录是一个特殊的 ``伪组件``,它包含项目本身的源代码。``main`` 是默认名称,Makefile 变量 ``COMPONENT_DIRS`` 默认会导入此组件,但您也可以修改此变量(或者设置 ``EXTRA_COMPONENT_DIRS`` )以查找其他位置的组件。 + +- ``build`` 目录在项目构建的时候创建或者更新,里面包含有构建生成的临时目标文件和库以及最终输出的二进制文件。此目录通常不会被添加到项目的源代码管理系统中,也不会随着项目源代码被发布。 + +组件目录中会包含组件自己的 Makefile 文件 ``component.mk`` ,里面会定义一些变量来控制该组件的构建过程,以及它与整个项目的集成。更多详细信息请参考 `组件 Makefiles <#component-makefiles>`_。 + +每个组件还可以包含一个 ``Kconfig`` 文件,它用于定义 ``menuconfig`` 时展示的组件配置信息的选项规则。某些组件还可能还会包含 ``Kconfig.projbuild`` 和 ``Makefile.projbuild`` 特殊文件,他们可以用来覆盖项目的部分配置。 + +项目 Makefiles +~~~~~~~~~~~~~~ + +每个项目都有一个 Makefile ,它包含整个项目的构建设置。默认情况下,项目 Makefile 可以非常小。 + +最小 Makefile 示例 +^^^^^^^^^^^^^^^^^^ + +.. code:: + + PROJECT_NAME := myProject + + include $(IDF_PATH)/make/project.mk + +必须设置的项目变量 +^^^^^^^^^^^^^^^^^^ + +- ``PROJECT_NAME``: 项目名称,最终输出的二进制文件也使用该名称,即 myProject.bin,myProject.elf 。 + +可选的项目变量 +^^^^^^^^^^^^^^ + +以下这些变量都有默认值,用户可以重写这些变量以自定义构建行为。查看 ``make/project.mk`` 文件可以获得所有的实现细节。 + +- ``PROJECT_PATH``: 顶层项目目录,默认是包含 Makefile 文件的目录,许多其他的项目变量都基于此变量。注意,项目路径中不能包含有空格。 +- ``BUILD_DIR_BASE``: 所有对象、库、二进制文件的输出目录,默认为 ``$(PROJECT_PATH)/build``。 +- ``COMPONENT_DIRS``: 组件的搜索目录,默认为 ``$(IDF_PATH)/components``,``$(PROJECT_PATH)/components``,``$(PROJECT_PATH)/main`` 和 ``EXTRA_COMPONENT_DIRS`` 。如果您不希望从这些目录中搜索组件,请重写此变量。 +- ``EXTRA_COMPONENT_DIRS``: 组件额外的搜索路径,可选。 +- ``COMPONENTS``: 要构建进项目中的组件列表,默认为 ``COMPONENT_DIRS`` 指定目录中所有的组件。 +- ``EXCLUDE_COMPONENTS``: 在构建的过程中需要剔除的组件列表,可选。请注意这只会减少构建的时间,并不会减少最终二进制文件的大小。 +- ``TEST_EXCLUDE_COMPONENTS``: 在构建单元测试的过程中需要剔除的组件列表,可选。 + +以上这些 Makefile 变量中的任何路径都要使用绝对路径,您可以使用 ``$(PROJECT_PATH)/xxx``,``$(IDF_PATH)/xxx``,或者使用 Make 内置函数 ``$(abspath xxx)`` 将相对路径转换为绝对路径。 + +以上这些变量要在 Makefile 中 ``include $(IDF_PATH)/make/project.mk`` 的前面进行设置。 + +.. _component-makefiles: + +组件 Makefiles +~~~~~~~~~~~~~~ + +每个项目都包含一个或者多个组件,这些组件可以是 ESP-IDF 的一部分,也可以从其他组件目录添加。 + +组件是包含 ``component.mk`` 文件的任何目录。 + +搜索组件 +~~~~~~~~ + +搜索 ``COMPONENT_DIRS`` 中指定的目录以查找项目会使用的组件,目录可以是组件本身(即他们包含 ``component.mk`` 文件),也可以是包含组件的上层目录。 + +运行 ``make list-components`` 命令可以查询这些变量的值,这有助于调试组件的搜索路径是否正确。 + +同名组件 +^^^^^^^^ + +ESP-IDF 搜索组件时,会按照 ``COMPONENT_DIRS`` 指定的顺序依次进行,这意味着在默认情况下,首先是 ESP-IDF 组件,然后是项目组件,最后是 ``EXTRA_COMPONENT_DIRS`` 中的组件。如果这些目录中的两个或者多个包含具有相同名字的组件,则使用搜索到的最后一个位置的组件。这就允许将组件复制到项目目录中再修改来覆盖 ESP-IDF 组件,如果使用这种方式,ESP-IDF 目录本身可以保持不变。 + +.. _minimal-component-makefile: + +最小组件 Makefile +^^^^^^^^^^^^^^^^^ + +最简单的 ``component.mk`` 文件可以是一个空文件,如果文件为空,则组件的默认构建行为会被设置为: + +- makefile 所在目录中的所有源文件(``*.c``,``*.cpp``,``*.cc``,``*.S``)将会被编译进组件库中。 +- 子目录 ``include`` 将被添加到其他组件的全局头文件搜索路径中。 +- 组件库将会被链接到项目的应用程序中。 + +更完整的组件 makefile 可以查看 `组件 Makefile 示例 <#example-component-makefile>`_。 + +请注意,空的 ``component.mk`` 文件同没有 ``component.mk`` 文件之间存在本质差异,前者会调用默认的组件构建行为,后者不会发生默认的组件构建行为。一个组件中如果只包含影响项目配置或构建过程的文件,那么它可以没有 ``component.mk`` 文件。 + +.. _preset-component-variables: + +预设的组件变量 +^^^^^^^^^^^^^^ + +以下特定于组件的变量可以在 ``component.mk`` 中使用,但不应该被修改。 + +- ``COMPONENT_PATH``: 组件的目录,即包含 ``component.mk`` 文件的绝对路径,路径中不能包含空格。 +- ``COMPONENT_NAME``: 组件的名字,默认为组件目录的名称。 +- ``COMPONENT_BUILD_DIR``: 组件的构建目录,即存放组件构建输出的绝对路径,它是 `$(BUILD_DIR_BASE)` 的子目录。该变量也是构建组件时的当前工作目录,所以 make 中的相对路径都以此目录为基础。 +- ``COMPONENT_LIBRARY``: 组件构建后的静态库文件(相对于组件的构建目录)的名字,默认为 ``$(COMPONENT_NAME).a``。 + +以下变量在项目顶层中设置,并被导出到组件中构建时使用: + +- ``PROJECT_NAME``: 项目名称,在项目的 Makefile 中设置。 +- ``PROJECT_PATH``: 包含项目 Makefile 的目录的绝对路径。 +- ``COMPONENTS``: 此次构建中包含的所有组件的名字。 +- ``CONFIG_*``: 项目配置中的每个值在 make 中都对应一个以 ``CONFIG_`` 开头的变量。 +- ``CC``,``LD``,``AR``,``OBJCOPY``: gcc xtensa 交叉编译工具链中每个工具的完整路径。 +- ``HOSTCC``,``HOSTLD``,``HOSTAR``: 主机本地工具链中每个工具的全名。 +- ``IDF_VER``: ESP-IDF 的版本号,可以通过检索 ``$(IDF_PATH)/version.txt`` 文件(假如存在的话)或者使用 git 命令 ``git describe`` 来获取。这里推荐的格式是在一行中指定主 IDF 的发布版本号,例如标记为 ``v2.0`` 的发布版本或者是标记任意一次提交记录的 ``v2.0-275-g0efaa4f``。应用程序可以通过调用 :cpp:func:`esp_get_idf_version` 函数来使用该变量。 +- ``IDF_VERSION_MAJOR``, ``IDF_VERSION_MINOR``, ``IDF_VERSION_PATCH``: ESP-IDF 的组件版本,可用于条件表达式。请注意这些信息的精确度不如 ``IDF_VER`` 变量,版本号 ``v4.0-dev-*``, ``v4.0-beta1``, ``v4.0-rc1`` 和 ``v4.0`` 对应的 ``IDF_VERSION_*`` 变量值是相同的,但是 ``IDF_VER`` 的值是不同的。 + +如果您在 ``component.mk`` 文件中修改这些变量,这并不会影响其它组件的构建,但可能会使您的组件变得难以构建或调试。 + +.. _optional-project-wide-component-variables: + +可选的项目通用组件变量 +^^^^^^^^^^^^^^^^^^^^^^ + +可以在 ``component.mk`` 中设置以下变量来控制整个项目的构建行为: + +- ``COMPONENT_ADD_INCLUDEDIRS``: 相对于组件目录的路径,将被添加到项目中所有组件的头文件搜索路径中。如果该变量未被覆盖,则默认为 ``include`` 目录。如果一个头文件路径仅仅为当前组件所用,那么应该将该路径添加到 ``COMPONENT_PRIV_INCLUDEDIRS`` 中。 +- ``COMPONENT_ADD_LDFLAGS``: 添加链接参数到全局 ``LDFLAGS`` 中用以指导链接最终的可执行文件,默认为 ``-l$(COMPONENT_NAME)``。如果将预编译好的库添加到此目录,请使用它们为绝对路径,即 ``$(COMPONENT_PATH)/libwhatever.a``。 +- ``COMPONENT_DEPENDS``: 需要在当前组件之前构建的组件列表,这对于处理链接时的依赖不是必需的,因为所有组件的头文件目录始终可用。如果一个组件会生成一个头文件,然后另外一个组件需要使用它,此时该变量就有必要进行设置。大多数的组件不需要设置此变量。 +- ``COMPONENT_ADD_LINKER_DEPS``: 保存一些文件的路径,当这些文件发生改变时,会触发 ELF 文件重新链接。该变量通常用于链接脚本文件和二进制文件,大多数的组件不需要设置此变量。 + +以下变量仅适用于属于 ESP-IDF 的组件: + +- ``COMPONENT_SUBMODULES``: 组件使用的 git 子模块的路径列表(相对于 ``COMPONENT_PATH``)。这些路径会在构建的过程中被检查(并在必要的时候初始化)。如果组件位于 ``IDF_PATH`` 目录之外,则忽略此变量。 + + +可选的组件特定变量 +^^^^^^^^^^^^^^^^^^ + +以下变量可以在 ``component.mk`` 中进行设置,用以控制该组件的构建行为: + +- ``COMPONENT_PRIV_INCLUDEDIRS``: 相对于组件目录的目录路径,该目录仅会被添加到该组件源文件的头文件搜索路径中。 +- ``COMPONENT_EXTRA_INCLUDES``: 编译组件的源文件时需要指定的额外的头文件搜索路径,这些路径将以 ``-l`` 为前缀传递给编译器。这和 ``COMPONENT_PRIV_INCLUDEDIRS`` 变量的功能有些类似,但是这些路径不会相对于组件目录进行扩展。 +- ``COMPONENT_SRCDIRS``: 相对于组件目录的目录路径,这些路径用于搜索源文件(``*.cpp``,``*.c``,``*.S``),默认为 ``.``,即组件目录本身。重写该变量可以指定包含源文件的不同目录列表。 +- ``COMPONENT_OBJS``: 要编译生成的目标文件,默认是 ``COMPONENT_SRCDIRS`` 中每个源文件的 .o 文件。重写该变量将允许您剔除 ``COMPONENT_SRCDIRS`` 中的某些源文件,否则他们将会被编译。相关示例请参阅 `指定需要编译的组件源文件 <#specify-source-files>`_。 +- ``COMPONENT_EXTRA_CLEAN``: 相对于组件构建目录的路径,指向 ``component.mk`` 文件中自定义 make 规则生成的任何文件,它们也是 ``make clean`` 命令需要删除的文件。相关示例请参阅 `源代码生成 <#source-code-generation>`_。 +- ``COMPONENT_OWNBUILDTARGET`` & ``COMPONENT_OWNCLEANTARGET``: 这些目标允许您完全覆盖组件的默认编译行为。有关详细信息,请参阅 `完全覆盖组件的 Makefile <#fully-overriding-component-makefile-legacy>`_。 +- ``COMPONENT_CONFIG_ONLY``: 如果设置了此标志,则表示组件根本不会产生构建输出(即不会构建得到 ``COMPONENT_LIBRARY``),并且会忽略大多数其它组件变量。此标志用于 IDF 内部组件,其中仅包含 ``KConfig.projbuild`` 和/或 ``Makefile.projbuild`` 文件来配置项目,但是没有源文件。 +- ``CFLAGS``: 传递给 C 编译器的标志。根据项目设置已经定义一组默认的 ``CFLAGS``,可以通过 ``CFLAGS +=`` 来为组件添加特定的标志,也可以完全重写该变量(尽管不推荐这么做)。 +- ``CPPFLAGS``: 传递给 C 预处理器的标志(用于 ``.c``,``.cpp`` 和 ``.S`` 文件)。根据项目设置已经定义一组默认的 ``CPPFLAGS`` ,可以通过 ``CPPFLAGS +=`` 来为组件添加特定的标志,也可以完全重写该变量(尽管不推荐这么做)。 +- ``CXXFLAGS``: 传递给 C++ 编译器的标志。根据项目设置已经定义一组默认的 ``CXXFLAGS`` ,可以通过 ``CXXFLAGS +=`` 来为组件添加特定的标志,也可以完全重写该变量(尽管不推荐这么做)。 + +如果要将编译标志应用于单个源文件,您可以将该源文件的目标规则覆盖,例如: + +.. code:: makefile + + apps/dhcpserver.o: CFLAGS += -Wno-unused-variable + +如果上游代码在编译的时候发出了警告,那这么做可能会很有效。 + +配置组件 +~~~~~~~~ + +每个组件都可以包含一个 Kconfig 文件,和 ``component.mk`` 放在同一个目录下。Kconfig 中包含此组件在 ``make menuconfig`` 时要展示的配置规则的设置。 + +运行 menuconfig 时,可以在 ``Component Settings`` 菜单栏下找到这些设置。 + +创建一个组件的 Kconfig 文件,最简单的方法就是使用 ESP-IDF 中现有的 Kconfig 文件作为模板,在这基础上进行修改。 + +有关示例请参阅 `添加条件配置 <#add-conditional-configuration>`_。 + +预处理器定义 +~~~~~~~~~~~~ + +ESP-IDF 构建系统会在命令行中添加以下 C 预处理定义: + +- ``ESP_PLATFORM`` — 可以用来检测在 ESP-IDF 内发生的构建行为。 +- ``IDF_VER`` — ESP-IDF 的版本,请参阅 `预设的组件变量 <#preset-component-variables>`_。 + +构建的内部过程 +~~~~~~~~~~~~~~ + +顶层:项目 Makefile +^^^^^^^^^^^^^^^^^^^ + +- ``make`` 始终从项目目录处运行,并且项目的 makefile 名字通常为 Makefile 。 +- 项目的 makefile 文件会设置 ``PROJECT_NAME`` ,并且可以自定义其他可选的项目变量。 +- 项目 makefile 文件会导入 ``$(IDF_PATH)/make/project.mk`` ,该文件中会导入项目级的 Make 逻辑。 +- ``project.mk`` 填写默认的项目级 make 变量,并导入项目配置中的 make 变量。如果生成的包含项目配置的 makefile 文件已经过期,那么它将会被重新生成(通过 ``project_config.mk`` 中的目标规则),然后 make 进程从顶层重新开始。 +- ``project.mk`` 根据默认组件目录或者可选项目变量中设置的自定义组件列表来编译组件。 +- 每个组件都可以设置一些 `可选的项目通用组件变量 <#optional-project-wide-component-variables>`_ ,他们会通过 ``component_project_vars.mk`` 被导入 ``project.mk`` 文件中。如果这些文件有缺失或者过期,他们会被重新生成(通过对组件 makefile 的递归调用),然后 make 进程从顶层重新开始。 +- 组件中的 Makefile.projbuild 文件被包含在了 make 的进程中,以添加额外的目标或者配置。 +- 默认情况下,项目 makefile 还为每个组件生成顶层的编译和清理目标,并设置 app 和 clean 目标来调用所有这些子目标。 +- 为了编译每个组件,对组件 makefile 执行递归构建。 + +为了更好地理解项目的构建过程,请通读 ``project.mk`` 文件。 + +第二层:组件 Makefile 文件 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- 每次调用组件 makefile 文件都是通过 ``$(IDF_PATH)/make/component_wrapper.mk`` 这个包装器进行的。 +- 此组件包装器包含了所有组件的 ``Makefile.componentbuild`` 文件,使这些文件中的任何配置,变量都可用于每个组件。 +- 调用 ``component_wrapper.mk`` 时将当前目录设置为组件构建目录,并将 ``COMPONENT_MAKEFILE`` 变量设置为 ``component.mk`` 的绝对路径。 +- ``component_wrapper.mk`` 为所有组件变量设置默认值,然后导入 ``component.mk`` 文件来覆盖或修改这些变量。 +- 如果未定义 ``COMPONENT_OWNBUILDTARGET`` 和 ``COMPONENT_OWNCLEANTARGET`` 文件,则会为组件的源文件和必备组件 ``COMPONENT_LIBRARY`` 静态库文件创建默认构建和清理目标。 +- ``component_project_vars.mk`` 文件在 ``component_wrapper.mk`` 中有自己的目标,如果由于组件的 makefile 或者项目配置的更改而需要重建此文件,则从 ``project.mk`` 文件中进行评估。 + +为了更好地理解组件制作过程,请阅读 ``component_wrapper.mk`` 文件和 ESP-IDF 中的 ``component.mk`` 文件。 + +以非交互的方式运行 Make +~~~~~~~~~~~~~~~~~~~~~~~ + +如果在运行 ``make`` 的时候不希望出现交互式提示(例如:在IDE或自动构建系统中),可以将 ``BATCH_BUILD=1`` 添加到make的参数中(或者将其设置为环境变量)。 + +设置 ``BATCH_BUILD`` 意味着: + +- 详细输出(与 ``V=1`` 相同,见下文),如果不需要详细输出,就设置 ``V=0`` 。 +- 如果项目配置缺少新配置项(来自新组件或者 ESP-IDF 更新),则项目使用默认值,而不是提示用户输入每个项目。 +- 如果构建系统需要调用 ``menuconfig`` ,则会打印错误并且构建失败。 + +.. _make-size: + +构建目标的进阶用法 +~~~~~~~~~~~~~~~~~~ + +- ``make app``,``make bootloader``,``make partition table`` 可以根据需要为项目单独构建生成应用程序文件、启动引导文件和分区表文件。 +- ``make erase_flash`` 和 ``make erase_ota`` 会调用 esptool.py 脚本分别擦除整块闪存芯片或者其中 OTA 分区的内容。 +- ``make size`` 会打印应用程序的大小信息。``make size-components`` 和 ``make size-files`` 两者功能相似,分别打印每个组件或者每个源文件大小的详细信息。 + +调试 Make 的过程 +~~~~~~~~~~~~~~~~ + +调试 ESP-IDF 构建系统的一些技巧: + +- 将 ``V=1`` 添加到 make 的参数中(或将其设置为环境变量)将使 make 回显所有已经执行的命令,以及为子 make 输入的每个目录。 +- 运行 ``make -w`` 将导致 make 在为子 make 输入时回显每个目录——与 ``V=1`` 相同但不回显所有命令。 +- 运行 ``make --trace`` (可能除了上述参数之一)将打印出构建时的每个目标,以及导致它构建的依赖项)。 +- 运行 ``make -p`` 会打印每个 makefile 中每个生成的目标的(非常详细的)摘要。 + +更多调试技巧和通用的构建信息,请参阅 `GNU 构建手册 `_。 + +.. _warn-undefined-variables-legacy: + +警告未定义的变量 +^^^^^^^^^^^^^^^^ + +默认情况下,如果引用了未定义的变量(如 ``$(DOES_NOT_EXIST)`` ,构建过程将会打印警告,这对于查找变量名称中的错误非常有用。 + +如果不想要此行为,可以在 menuconfig 顶层菜单下的 `SDK tool configuration` 中禁用它。 + +请注意,如果在 Makefile 中使用 ``ifdef`` 或者 ``ifndef`` ,则此选项不会出发警告。 + +覆盖项目的部分内容 +~~~~~~~~~~~~~~~~~~ + +Makefile.projbuild +^^^^^^^^^^^^^^^^^^ + +如果一个组件含有必须要在项目构建过程的顶层进行计算的变量,则可以在组件目录下创建名为 ``Makefile.projbuild`` 的文件,项目在执行 ``project.mk`` 的时候会导入此 makefile 。 + +例如,如果您的组件需要为整个项目添加 CFLAGS(不仅仅是为自身的源文件),那么可以在 ``Makefile.projbuild`` 中设置 ``CFLAGS +=`` 。 + +``Makefile.projbuild`` 文件在 ESP-IDF 中大量使用,用于定义项目范围的构建功能,例如 ``esptool.py`` 命令行参数和 ``bootloader`` 这个特殊的程序。 + +请注意, ``Makefile.projbuild`` 对于最常见的组件不是必需的 - 例如向项目中添加 include 目录,或者将 LDFLAGS 添加到最终链接步骤,同样可以通过 ``component.mk`` 文件来自定义这些值。有关详细信息,请参阅 `可选的项目通用组件变量 <#optional-project-wide-component-variables>`_ 。 + +.. warning:: + + 在此文件中设置变量或者目标时要小心,由于这些值包含在项目的顶层 makefile 中,因此他们可以影响或者破坏所有组件的功能! + +KConfig.projbuild +^^^^^^^^^^^^^^^^^ + +这相当于 ``Makefile.projbuild`` 的组件配置 KConfig 文件,如果要在 menuconfig 的顶层添加配置选项,而不是在 ``组件配置`` 子菜单中,则可以在 ``component.mk`` 文件所在目录中的 KConfig.projbuild 文件中定义这些选项。 + +在此文件中添加配置时要小心,因为他们将包含在整个项目配置中,在可能的情况下,通常最好为组件创建和配置 KConfig 文件。 + +Makefile.componentbuild +^^^^^^^^^^^^^^^^^^^^^^^ + +对于一些特殊的组件,比如它们会使用工具从其余文件中生成源文件,这时就有必要将配置、宏或者变量的定义添加到每个组件的构建过程中。这是通过在组件目录中包含 ``Makefile.componentbuild`` 文件来实现的。此文件在 ``component.mk`` 文件之前被导入 ``component_wrapper.mk`` 中。同 ``Makefile.projbuild`` 文件一样,请留意这些文件,因为他们包含在每个组件的构建中,所有只有在编译完全不同的组件时才会出现 ``Makefile.componentbuild`` 错误。 + +仅配置的组件 +^^^^^^^^^^^^ + +仅配置的组件是一类不包含源文件的特殊组件,只有 ``Kconfig.projbuild`` 和 ``Makefile.projbuild`` 文件,可以在 ``conponent.mk`` 文件中设置标志 ``COMPONENT_CONFIG_ONLY``。如果设置了此标志,则忽略大多数其他组件变量,并且不会为组件执行构建操作。 + +.. _example-component-makefile-legacy: + +组件 Makefile 示例 +~~~~~~~~~~~~~~~~~~ + +因为构建环境试图设置大多数情况都能工作的合理默认值,所以 ``component.mk`` 可能非常小,甚至是空的,请参考 `最小组件 Makefile <#minimal-component-makefile>`_。但是某些功能通常需要覆盖组件的变量。 + +以下是 ``component.mk`` 的一些更高级的示例: + +增加源文件目录 +^^^^^^^^^^^^^^ + +默认情况下,将忽略子目录。如果您的项目在子目录中而不是在组件的根目录中有源文件,那么您可以通过设置 ``COMPONENT_SRCDIRS`` 将其告知构建系统: + +.. code:: + + COMPONENT_SRCDIRS := src1 src2 + +构建系统将会编译 src1/ 和 src2/ 子目录中的所有源文件。 + +.. _specify-source-files-legacy: + +指定源文件 +^^^^^^^^^^ + +标准 ``component.mk`` 逻辑将源目录中的所有 .S 和 .c 文件添加为无条件编译的源。通过将 ``COMPONENT_OBJS`` 变量手动设置为需要生成的对象的名称,可以绕过该逻辑并对要编译的对象进行硬编码。 + +.. code:: + + COMPONENT_OBJS := file1.o file2.o thing/filea.o thing/fileb.o anotherthing/main.o + COMPONENT_SRCDIRS := . thing anotherthing + +请注意,还需要另外设置 ``COMPONENT_SRCDIRS`` 。 + +.. _add-conditional-configuration-legacy: + +添加条件配置 +^^^^^^^^^^^^ + +配置系统可用于有条件地编译某些文件,具体取决于 ``make menuconfig`` 中选择的选项。为此,ESP-IDF 具有 ``compile_only_if`` 和 ``compile_only_if_not`` 的宏: + +``Kconfig``: + +.. code:: + + config FOO_ENABLE_BAR + bool "Enable the BAR feature." + help + This enables the BAR feature of the FOO component. + +``component.mk``: + +.. code:: + + $(call compile_only_if,$(CONFIG_FOO_ENABLE_BAR),bar.o) + +从示例中可以看出, ``compile_only_if`` 宏将条件和目标文件列表作为参数。如果条件为真(在这种情况下:如果在 menuconfig 中启用了 BAR 功能),将始终编译目标文件(在本例中为 bar.o)。相反的情况也是如此,如果条件不成立,bar.o 将永远不会被编译。 ``compile_only_if_not`` 执行相反的操作,如果条件为 false 则编译,如果条件为 true 则不编译。 + +这也可以用于选择或者删除实现,如下所示: + +``Kconfig``: + +.. code:: + + config ENABLE_LCD_OUTPUT + bool "Enable LCD output." + help + Select this if your board has a LCD. + + config ENABLE_LCD_CONSOLE + bool "Output console text to LCD" + depends on ENABLE_LCD_OUTPUT + help + Select this to output debugging output to the lcd + + config ENABLE_LCD_PLOT + bool "Output temperature plots to LCD" + depends on ENABLE_LCD_OUTPUT + help + Select this to output temperature plots + +``component.mk``: + +.. code:: + + # If LCD is enabled, compile interface to it, otherwise compile dummy interface + $(call compile_only_if,$(CONFIG_ENABLE_LCD_OUTPUT),lcd-real.o lcd-spi.o) + $(call compile_only_if_not,$(CONFIG_ENABLE_LCD_OUTPUT),lcd-dummy.o) + + #We need font if either console or plot is enabled + $(call compile_only_if,$(or $(CONFIG_ENABLE_LCD_CONSOLE),$(CONFIG_ENABLE_LCD_PLOT)), font.o) + +请注意使用 Make 或者函数来包含字体文件。其他的替换函数,比如 ``and`` 和 ``if`` 也适用于此处。也可以使用不在 menuconfig 中定义的变量,ESP-IDF 使用默认的 Make 策略,将一个空的或者只包含空格的变量视为 false ,而其中任何非空格的比那辆都为 true 。 + +(注意:本文档的历史版本建议将目标文件添加到 ``COMPONENT_OBJS`` 中,虽然这仍然可行,但是只有当组件中的所有目标文件都明确命名时才会起作用,并且在 ``make clean`` 后并不会清除 make 中取消选择的目标文件)。 + +.. _source-code-generation-legacy: + +源代码生成 +^^^^^^^^^^ + +某些组件会出现源文件未随组件本身提供,而必须从另外一个文件生成的情况。假设我们的组件有一个头文件,该文件由 BMP 文件转换后的二进制数据组成,假设使用 bmp2h 的工具进行转换,然后将头文件包含在名为 graphics_lib.c 的文件中: + +.. code:: + + COMPONENT_EXTRA_CLEAN := logo.h + + graphics_lib.o: logo.h + + logo.h: $(COMPONENT_PATH)/logo.bmp + bmp2h -i $^ -o $@ + +这个示例会在当前目录(构建目录)中生成 graphics_lib.o 和 logo.h 文件,而 logo.bmp 随组件一起提供并位于组件路径下。因为 logo.h 是一个生成的文件,所以当调用 ``make clean`` 时需要清理它,这就是为什么要将它添加到 ``COMPONENT_EXTRA_CLEAN`` 变量中。 + +润色与改进 +^^^^^^^^^^ + +将 logo.h 添加作为 ``graphics_lib.o`` 的依赖项会导致在编译 ``graphics_lib.c`` 之前先生成它。 + +如果另一个组件中的源文件需要使用 logo.h,则必须将此组件的名称添加到另一个组件的 ``COMPONENT_DEPENDS`` 列表中,以确保组件按顺序编译。 + +嵌入二进制数据 +^^^^^^^^^^^^^^ + +有时您的组件希望使用一个二进制文件或者文本文件,但是您又不希望将它重新格式化为 C 源文件。 + +这时,您可以在 ``component.mk`` 文件中设置变量 ``COMPONENT_EMBED_FILES``,以这种方式指定要嵌入的文件的名称: + +.. code:: + + COMPONENT_EMBED_FILES := server_root_cert.der + +或者,如果文件是字符串,则可以使用变量 ``COMPONENT_EMBED_TXTFILES``,这将把文本文件的内容当成以 null 结尾的字符串嵌入: + +.. code:: + + COMPONENT_EMBED_TXTFILES := server_root_cert.pem + +文件的内容会被编译进 flash 中的 .rodata 段,并通过符号名称来访问,如下所示: + +.. code:: c + + 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"); + +符号名称是根据文件的全名生成的,如 ``COMPONENT_EMBED_FILES`` 中的所示,字符 / , . , 等都将会被下划线替代。符号名称中的 ``_binary`` 前缀由 ``objcopy`` 添加,对于文本和二进制文件都是相同的。 + +有关使用此技术的示例,请参考 :example:`protocols/https_request` - 证书文件的内容会在编译时从 .pem 文件中加载。 + +.. _fully-overriding-component-makefile: + +完全覆盖组件的 Makefile +~~~~~~~~~~~~~~~~~~~~~~~ + +显然,在某些情况下,所有这些配置都不足以满足某个组件,例如,当组件基本上是另一个第三方组件的包装器时,该第三方组件最初不打算在 ESP-IDF 构建系统下工作,在这种情况下,可以通过设置 ``COMPONENT_OWNBUILDTARGET`` 和可能的 ``COMPONENT_OWNCLEANTARGET``,并在 ``component.mk`` 中定义名为 ``build`` 和 ``clean`` 的目标。构建目标可以执行任何操作,只要它为项目生成了 ``$(COMPONENT_LIBRARY)`` ,并最终被链接到应用程序二进制文件中即可。 + +(实际上,这并不是必须的 - 如果 ``COMPONENT_ADD_LDFLAGS`` 变量被覆盖,那么组件可以指示链接器链接其他二进制文件。) + +.. _custom-sdkconfig-defaults-legacy: + +自定义 sdkconfig 的默认值 +~~~~~~~~~~~~~~~~~~~~~~~~~ + +对于示例工程或者其他您不想指定完整 sdkconfig 配置的项目,但是您确实希望覆盖 ESP-IDF 默认值中的某些键值,则可以在项目中创建文件 ``sdkconfig.defaults``,运行 ``make defconfig`` 或从头创建新配置时将会使用此文件。 + +要想覆盖此文件的名称,请设置 ``SDKCONFIG_DEFAULTS`` 环境变量。 + +保存 flash 参数 +~~~~~~~~~~~~~~~ + +在某些情况下,我们希望在没有 IDF 的情况下烧写目标板卡,对于这种情况,我们希望保存构建的二进制文件、esptool.py 和 esptool write_flash 命令的参数。可以简单编写一段脚本来保存二进制文件和 esptool.py,并且使用命令 ``make print_flash_cmd`` 来查看烧写 flash 时的参数。 + +.. code:: bash + + --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 bootloader/bootloader.bin 0x10000 example_app.bin 0x8000 partition_table_unit_test_app.bin + +然后使用这段 flash 参数作为 esptool write_flash 命令的参数: + +.. code:: bash + + python esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 bootloader/bootloader.bin 0x10000 example_app.bin 0x8000 partition_table_unit_test_app.bin + +构建 Bootloader +--------------- + +引导程序默认作为 ``make all`` 的一部分被构建,或者也可以通过 ``make bootloader-clean`` 来单独构建,此外还可以通过 ``make bootloader-list-components`` 来查看构建引导程序时包含的组件。 + +引导程序是一个特殊的组件,因为主项目中的二级引导程序拥有单独的 .EFL 和 .BIN 文件。但是它与主项目共享配置和构建目录。 + +这是通过在 components/bootloader/subproject 下添加子项目来完成的。这个子项目有自己的 Makefile,但它希望通过 components/bootloader/Makefile.projectbuild 文件中的一些配置使自己从主项目的 Makefile 被调用。有关详细信息,请参阅这些文件。 diff --git a/docs/zh_CN/api-guides/build-system.rst b/docs/zh_CN/api-guides/build-system.rst index 60bba24ef0..e9616ec0c3 100644 --- a/docs/zh_CN/api-guides/build-system.rst +++ b/docs/zh_CN/api-guides/build-system.rst @@ -1,540 +1,1079 @@ -构建系统 -======== +构建系统(CMake 版) +******************** :link_to_translation:`en:[English]` -本文将介绍乐鑫物联网开发框架中的 ``构建系统`` 和 ``组件`` 的相关概念。 +本文档将介绍基于 CMake 的 ESP-IDF 构建系统的实现原理以及 ``组件`` 等相关概念,此外 ESP-IDF 还支持 :doc:`基于 GNU Make 的构建系统 `。 -如果您想了解如何构建一个新的 ESP-IDF 项目,请阅读本文档。 - -我们建议您使用 `ESP-IDF 模板工程 `_ 来开始您的新项目。 - -使用构建系统 ------------- - -ESP-IDF 的 :idf_file:`README.md` 文件对如何使用构建系统来构建项目作了简要的说明。 +如需您想了解如何使用 CMake 构建系统来组织和构建新的 ESP-IDF 项目或组件,请阅读本文档。 概述 ----- +==== -一个 ESP-IDF 项目可以看作是许多不同组件的集合,例如对于一个展示当前湿度的网站服务器来说,它可能会包含如下一些组件: +一个 ESP-IDF 项目可以看作是多个不同组件的集合,例如一个显示当前湿度的网页服务器会包含以下组件: -- ESP32 基础库(libc,rom bindings 等) -- WiFi 驱动库 -- TCP/IP 协议栈 -- FreeRTOS 操作系统 -- 网站服务器 -- 湿度传感器的驱动 -- 将上述组件组织在一起的主代码 +- ESP32 基础库,包括 libc、ROM bindings 等 +- Wi-Fi 驱动 +- TCP/IP 协议栈 +- FreeRTOS 操作系统 +- 网页服务器 +- 湿度传感器的驱动 +- 负责将上述组件整合到一起的主程序 -ESP-IDF 可以显式地指定和配置每个组件。在构建项目的时候,构建系统会查找 ESP-IDF 目录、项目目录和用户自定义目录(可选)中所有的组件,然后使用基于文本的菜单系统让用户配置 ESP-IDF 项目中需要的每个组件。在配置结束后,构建系统开始编译整个项目。 +ESP-IDF 可以显式地指定和配置每个组件。在构建项目的时候,构建系统会前往 ESP-IDF 目录、项目目录和用户自定义目录(可选)中查找所有组件,允许用户通过文本菜单系统配置 ESP-IDF 项目中用到的每个组件。在所有组件配置结束后,构建系统开始编译整个项目。 概念 -~~~~ +---- -- ``项目`` 特指一个目录,其中包含了构建可执行文件的所有源文件和配置,还有其他的支持型输出文件,比如分区表、数据/文件系统分区和引导程序。 +- ``项目`` 特指一个目录,其中包含了构建可执行应用程序所需的全部文件和配置,以及其他支持型文件,例如分区表、数据/文件系统分区和引导程序。 +- ``项目配置`` 保存在项目根目录下名为 ``sdkconfig`` 的文件中,可以通过 ``idf.py menuconfig`` 进行修改,且一个项目只能包含一个项目配置。 +- ``应用程序`` 是由 ESP-IDF 构建得到的可执行文件。一个项目通常会构建两个应用程序:项目应用程序(可执行的主文件,即用户自定义的固件)和引导程序(启动并初始化项目应用程序)。 +- ``组件`` 是模块化且独立的代码,会被编译成静态库(.a 文件)并链接到应用程序。部分组件由 ESP-IDF 官方提供,其他组件则来源于其它开源项目。 +- ``目标`` 特指运行构建后应用程序的硬件设备。ESP-IDF 当前仅支持 ``ESP32`` 这一个硬件目标。 -- ``项目配置`` 保存在项目根目录下名为 sdkconfig 的文件中,它可以通过 ``make menuconfig`` 进行修改,且一个项目只能包含一个项目配置。 +请注意,以下内容并不属于项目的组成部分: -- ``应用程序`` 是由 ESP-IDF 构建得到的可执行文件。一个项目通常会构建两个应用程序:项目应用程序(主可执行文件,即用户自定义的固件)和引导程序(启动并初始化项目应用程序的引导程序)。 +- ``ESP-IDF`` 并不是项目的一部分,它独立于项目,通过 ``IDF_PATH`` 环境变量(保存 ``esp-idf`` 目录的路径)链接到项目,从而将 IDF 框架与项目分离。 +- 交叉编译工具链并不是项目的组成部分,它应该被安装在系统 PATH 环境变量中。 -- ``组件`` 是模块化的、独立的代码,它们被编译成静态库(.a 文件)后再链接成应用程序,有些组件是 ESP-IDF 官方提供的,有些则可能来自其它项目。 +使用构建系统 +============ -以下内容并不是项目的组成部分: +.. _idf.py: -- ``ESP-IDF`` 并不是项目的一部分,相反,它是独立的,并通过 IDF_PATH 环境变量链接到项目中,这样做就可以使 IDF 框架与您的项目分离,其中 IDF_PATH 变量保存了 ESP-IDF 目录的路径。 +idf.py +------ -- 交叉编译工具链并不是项目的组成部分,它应该被安装在系统 PATH 环境变量中,或者可以在项目配置中显式指定工具链的前缀为本地的安装路径。 +``idf.py`` 命令行工具提供了一个前端,可以帮助您轻松管理项目的构建过程,它管理了以下工具: -示例项目 -~~~~~~~~ +- CMake_,配置待构建的系统 +- 命令行构建工具(Ninja_ 或 `GNU Make`) +- `esptool.py`_,烧录 ESP32 -示例项目的目录树结构可能如下所示: +:ref:`入门指南 ` 简要介绍了如何设置 ``idf.py`` 用于配置、构建并烧录项目。 -.. code:: +``idf.py`` 应运行在 ESP-IDF 的 ``项目`` 目录下,即包含 ``CMakeLists.txt`` 文件的目录。仅包含 Makefile 的老式项目并不支持 ``idf.py``。 - - myProject/ - - Makefile - - sdkconfig - - components/ - component1/ - component.mk - - Kconfig - - src1.c - - component2/ - component.mk - - Kconfig - - src1.c - - include/ - component2.h - - main/ - src1.c - - src2.c - - component.mk - - build/ +运行 ``idf.py --help`` 查看完整的命令列表。下面总结了最常用的命令: -该示例项目 ``myProject`` 包含以下组成部分: +- ``idf.py menuconfig`` 会运行 ``menuconfig`` 工具来配置项目。 +- ``idf.py build`` 会构建在当前目录下找到的项目,它包括以下步骤: -- 项目顶层 Makefile,该 Makefile 设置了 ``PROJECT_NAME`` 变量,还可以定义作用于整个项目的其它 make 变量(可选)。顶层 Makefile 会导入核心 Makefile 文件 ``$(IDF_PATH)/make/project.mk`` ,由它负责实现 ESP-IDF 构建系统的剩余部分。 + - 根据需要创建 ``build`` 构建目录,它用于保存构建过程的输出文件,可以使用 ``-B`` 选项修改默认的构建目录。 + - 根据需要运行 CMake_ 配置命令,为主构建工具生成构建文件。 + - 运行主构建工具(Ninja_ 或 `GNU Make`)。默认情况下,构建工具会被自动检测,可以使用 ``-G`` 选项显式地指定构建工具。 -- 项目配置文件 sdkconfig,执行 ``make menuconfig`` 后会创建或更新此文件,该文件中保存了项目中所有组件的配置信息(包括 ESP-IDF 本身)。``sdkconfig`` 文件可能会也可能不会被添加到项目的源代码管理系统中。 + 构建过程是增量式的,如果自上次构建以来源文件或项目配置没有发生改变,则不会执行任何操作。 -- 可选的组件目录中包含了属于项目一部分的自定义组件,不是每一个项目都需要它,但它有助于构建可重用代码或者导入第三方组件。 +- ``idf.py clean`` 会把构建输出的文件从构建目录中删除,从而清理整个项目。下次构建时会强制“重新完整构建”这个项目。清理时,不会删除 CMake 配置输出及其他文件。 +- ``idf.py fullclean`` 会将整个 ``build`` 目录下的内容全部删除,包括所有 CMake 的配置输出文件。下次构建项目时,CMake 会从头开始配置项目。请注意,该命令会递归删除构建目录下的 *所有文件*,请谨慎使用。项目配置文件不会被删除。 +- ``idf.py flash`` 会在必要时自动构建项目,并将生成的二进制程序烧录进 ESP32 设备中。``-p`` 和 ``-b`` 选项可分别设置串口的设备名和烧录时的波特率。 +- ``idf.py monitor`` 用于显示 ESP32 设备的串口输出。``-p`` 选项可用于设置主机端串口的设备名,按下 ``Ctrl-]`` 可退出监视器。更多有关监视器的详情,请参阅 :doc:`tools/idf-monitor`。 -- ``main`` 目录是一个特殊的 ``伪组件``,它包含项目本身的源代码。``main`` 是默认名称,Makefile 变量 ``COMPONENT_DIRS`` 默认会导入此组件,但您也可以修改此变量(或者设置 ``EXTRA_COMPONENT_DIRS`` )以查找其他位置的组件。 +多个 ``idf.py`` 命令可合并成一个,例如,``idf.py -p COM4 clean flash monitor`` 会依次清理源码树,构建项目,烧录进 ESP32 设备,最后运行串口监视器。 -- ``build`` 目录在项目构建的时候创建或者更新,里面包含有构建生成的临时目标文件和库以及最终输出的二进制文件。此目录通常不会被添加到项目的源代码管理系统中,也不会随着项目源代码被发布。 +.. Note:: 环境变量 ``ESPPORT`` 和 ``ESPBAUD`` 可分别用作 ``-p`` 和 ``-b`` 选项的默认值。在命令行中,重新为这两个选项赋值,会覆盖其默认值。 -组件目录中会包含组件自己的 Makefile 文件 ``component.mk`` ,里面会定义一些变量来控制该组件的构建过程,以及它与整个项目的集成。更多详细信息请参考 `组件 Makefiles <#component-makefiles>`_。 +.. _idf.py-size: -每个组件还可以包含一个 ``Kconfig`` 文件,它用于定义 ``menuconfig`` 时展示的组件配置信息的选项规则。某些组件还可能还会包含 ``Kconfig.projbuild`` 和 ``Makefile.projbuild`` 特殊文件,他们可以用来覆盖项目的部分配置。 - -项目 Makefiles -~~~~~~~~~~~~~~ - -每个项目都有一个 Makefile ,它包含整个项目的构建设置。默认情况下,项目 Makefile 可以非常小。 - -最小 Makefile 示例 -^^^^^^^^^^^^^^^^^^ - -.. code:: - - PROJECT_NAME := myProject - - include $(IDF_PATH)/make/project.mk - -必须设置的项目变量 -^^^^^^^^^^^^^^^^^^ - -- ``PROJECT_NAME``: 项目名称,最终输出的二进制文件也使用该名称,即 myProject.bin,myProject.elf 。 - -可选的项目变量 -^^^^^^^^^^^^^^ - -以下这些变量都有默认值,用户可以重写这些变量以自定义构建行为。查看 ``make/project.mk`` 文件可以获得所有的实现细节。 - -- ``PROJECT_PATH``: 顶层项目目录,默认是包含 Makefile 文件的目录,许多其他的项目变量都基于此变量。注意,项目路径中不能包含有空格。 -- ``BUILD_DIR_BASE``: 所有对象、库、二进制文件的输出目录,默认为 ``$(PROJECT_PATH)/build``。 -- ``COMPONENT_DIRS``: 组件的搜索目录,默认为 ``$(IDF_PATH)/components``,``$(PROJECT_PATH)/components``,``$(PROJECT_PATH)/main`` 和 ``EXTRA_COMPONENT_DIRS`` 。如果您不希望从这些目录中搜索组件,请重写此变量。 -- ``EXTRA_COMPONENT_DIRS``: 组件额外的搜索路径,可选。 -- ``COMPONENTS``: 要构建进项目中的组件列表,默认为 ``COMPONENT_DIRS`` 指定目录中所有的组件。 -- ``EXCLUDE_COMPONENTS``: 在构建的过程中需要剔除的组件列表,可选。请注意这只会减少构建的时间,并不会减少最终二进制文件的大小。 -- ``TEST_EXCLUDE_COMPONENTS``: 在构建单元测试的过程中需要剔除的组件列表,可选。 - -以上这些 Makefile 变量中的任何路径都要使用绝对路径,您可以使用 ``$(PROJECT_PATH)/xxx``,``$(IDF_PATH)/xxx``,或者使用 Make 内置函数 ``$(abspath xxx)`` 将相对路径转换为绝对路径。 - -以上这些变量要在 Makefile 中 ``include $(IDF_PATH)/make/project.mk`` 的前面进行设置。 - -.. _component-makefiles: - -组件 Makefiles -~~~~~~~~~~~~~~ - -每个项目都包含一个或者多个组件,这些组件可以是 ESP-IDF 的一部分,也可以从其他组件目录添加。 - -组件是包含 ``component.mk`` 文件的任何目录。 - -搜索组件 -~~~~~~~~ - -搜索 ``COMPONENT_DIRS`` 中指定的目录以查找项目会使用的组件,目录可以是组件本身(即他们包含 ``component.mk`` 文件),也可以是包含组件的上层目录。 - -运行 ``make list-components`` 命令可以查询这些变量的值,这有助于调试组件的搜索路径是否正确。 - -同名组件 +高级命令 ^^^^^^^^ -ESP-IDF 搜索组件时,会按照 ``COMPONENT_DIRS`` 指定的顺序依次进行,这意味着在默认情况下,首先是 ESP-IDF 组件,然后是项目组件,最后是 ``EXTRA_COMPONENT_DIRS`` 中的组件。如果这些目录中的两个或者多个包含具有相同名字的组件,则使用搜索到的最后一个位置的组件。这就允许将组件复制到项目目录中再修改来覆盖 ESP-IDF 组件,如果使用这种方式,ESP-IDF 目录本身可以保持不变。 +- ``idf.py app``,``idf.py bootloader``,``idf.py partition_table`` 仅可用于从适用的项目中构建应用程序、引导程序或分区表。 +- ``idf.py app-flash`` 等匹配命令,仅将项目的特定部分烧录至 ESP32。 +- ``idf.py -p PORT erase_flash`` 会使用 esptool.py 擦除 ESP32 的整个 Flash。 +- ``idf.py size`` 会打印应用程序相关的大小信息,``idf.py size-components`` 和 ``idf.py size-files`` 这两个命令相似,分别用于打印每个组件或源文件的详细信息。 +- ``idf.py reconfigure`` 命令会重新运行 CMake_ (即便无需重新运行)。正常使用时,并不需要运行此命令,但当源码树中添加/删除文件后或更改 CMake cache 变量时,此命令会非常有用,例如,``idf.py -DNAME='VALUE' reconfigure`` 会将 CMake cache 中的变量 ``NAME`` 的值设置为 ``VALUE``。 -.. _minimal-component-makefile: +同时调用多个 ``idf.py`` 命令时,命令的输入顺序并不重要,它们会按照正确的顺序依次执行,并保证每一条命令都生效(即先构建后烧录,先擦除后烧录等)。 -最小组件 Makefile -^^^^^^^^^^^^^^^^^ +直接使用 CMake +-------------- -最简单的 ``component.mk`` 文件可以是一个空文件,如果文件为空,则组件的默认构建行为会被设置为: +为了方便,:ref:`idf.py` 已经封装了 CMake_ 命令,但是您愿意,也可以直接调用 CMake。 -- makefile 所在目录中的所有源文件(``*.c``,``*.cpp``,``*.cc``,``*.S``)将会被编译进组件库中。 -- 子目录 ``include`` 将被添加到其他组件的全局头文件搜索路径中。 -- 组件库将会被链接到项目的应用程序中。 +.. highlight:: bash -更完整的组件 makefile 可以查看 `组件 Makefile 示例 <#example-component-makefile>`_。 +当 ``idf.py`` 在执行某些操作时,它会打印出其运行的每条命令以便参考。例如运行 ``idf.py build`` 命令与在 bash shell(或者 Windows Command Prompt)中运行以下命令是相同的:: -请注意,空的 ``component.mk`` 文件同没有 ``component.mk`` 文件之间存在本质差异,前者会调用默认的组件构建行为,后者不会发生默认的组件构建行为。一个组件中如果只包含影响项目配置或构建过程的文件,那么它可以没有 ``component.mk`` 文件。 + mkdir -p build + cd build + cmake .. -G Ninja # 或者 'Unix Makefiles' + ninja -.. _preset-component-variables: +在上面的命令列表中,``cmake`` 命令对项目进行配置,并生成用于最终构建工具的构建文件。在这个例子中,最终构建工具是 Ninja_: 运行 ``ninja`` 来构建项目。 -预设的组件变量 -^^^^^^^^^^^^^^ +没有必要多次运行 ``cmake``。第一次构建后,往后每次只需运行 ``ninja`` 即可。如果项目需要重新配置,``ninja`` 会自动重新调用 ``cmake``。 -以下特定于组件的变量可以在 ``component.mk`` 中使用,但不应该被修改。 +若在 CMake 中使用 ``ninja`` 或 ``make``,则多数 ``idf.py`` 子命令也会有其对应的目标,例如在构建目录下运行 ``make menuconfig`` 或 ``ninja menuconfig`` 与运行 ``idf.py menuconfig`` 是相同的。 -- ``COMPONENT_PATH``: 组件的目录,即包含 ``component.mk`` 文件的绝对路径,路径中不能包含空格。 -- ``COMPONENT_NAME``: 组件的名字,默认为组件目录的名称。 -- ``COMPONENT_BUILD_DIR``: 组件的构建目录,即存放组件构建输出的绝对路径,它是 `$(BUILD_DIR_BASE)` 的子目录。该变量也是构建组件时的当前工作目录,所以 make 中的相对路径都以此目录为基础。 -- ``COMPONENT_LIBRARY``: 组件构建后的静态库文件(相对于组件的构建目录)的名字,默认为 ``$(COMPONENT_NAME).a``。 +.. Note:: + 如果您已经熟悉了 CMake_,那么可能会发现 ESP-IDF 的 CMake 构建系统不同寻常,为了减少样板文件,该系统封装了 CMake 的许多功能。请参考 :ref:`write-pure-component` 以编写更多 ``CMake 风格`` 的组件。 -以下变量在项目顶层中设置,并被导出到组件中构建时使用: +.. _flash-with-ninja-or-make: -- ``PROJECT_NAME``: 项目名称,在项目的 Makefile 中设置。 -- ``PROJECT_PATH``: 包含项目 Makefile 的目录的绝对路径。 -- ``COMPONENTS``: 此次构建中包含的所有组件的名字。 -- ``CONFIG_*``: 项目配置中的每个值在 make 中都对应一个以 ``CONFIG_`` 开头的变量。 -- ``CC``,``LD``,``AR``,``OBJCOPY``: gcc xtensa 交叉编译工具链中每个工具的完整路径。 -- ``HOSTCC``,``HOSTLD``,``HOSTAR``: 主机本地工具链中每个工具的全名。 -- ``IDF_VER``: ESP-IDF 的版本号,可以通过检索 ``$(IDF_PATH)/version.txt`` 文件(假如存在的话)或者使用 git 命令 ``git describe`` 来获取。这里推荐的格式是在一行中指定主 IDF 的发布版本号,例如标记为 ``v2.0`` 的发布版本或者是标记任意一次提交记录的 ``v2.0-275-g0efaa4f``。应用程序可以通过调用 :cpp:func:`esp_get_idf_version` 函数来使用该变量。 -- ``IDF_VERSION_MAJOR``, ``IDF_VERSION_MINOR``, ``IDF_VERSION_PATCH``: ESP-IDF 的组件版本,可用于条件表达式。请注意这些信息的精确度不如 ``IDF_VER`` 变量,版本号 ``v4.0-dev-*``, ``v4.0-beta1``, ``v4.0-rc1`` 和 ``v4.0`` 对应的 ``IDF_VERSION_*`` 变量值是相同的,但是 ``IDF_VER`` 的值是不同的。 - -如果您在 ``component.mk`` 文件中修改这些变量,这并不会影响其它组件的构建,但可能会使您的组件变得难以构建或调试。 - -.. _optional-project-wide-component-variables: - -可选的项目通用组件变量 +使用 Ninja/Make 来烧录 ^^^^^^^^^^^^^^^^^^^^^^ -可以在 ``component.mk`` 中设置以下变量来控制整个项目的构建行为: +您可以直接使用 ninja 或 make 运行如下命令来构建项目并烧录:: -- ``COMPONENT_ADD_INCLUDEDIRS``: 相对于组件目录的路径,将被添加到项目中所有组件的头文件搜索路径中。如果该变量未被覆盖,则默认为 ``include`` 目录。如果一个头文件路径仅仅为当前组件所用,那么应该将该路径添加到 ``COMPONENT_PRIV_INCLUDEDIRS`` 中。 -- ``COMPONENT_ADD_LDFLAGS``: 添加链接参数到全局 ``LDFLAGS`` 中用以指导链接最终的可执行文件,默认为 ``-l$(COMPONENT_NAME)``。如果将预编译好的库添加到此目录,请使用它们为绝对路径,即 ``$(COMPONENT_PATH)/libwhatever.a``。 -- ``COMPONENT_DEPENDS``: 需要在当前组件之前构建的组件列表,这对于处理链接时的依赖不是必需的,因为所有组件的头文件目录始终可用。如果一个组件会生成一个头文件,然后另外一个组件需要使用它,此时该变量就有必要进行设置。大多数的组件不需要设置此变量。 -- ``COMPONENT_ADD_LINKER_DEPS``: 保存一些文件的路径,当这些文件发生改变时,会触发 ELF 文件重新链接。该变量通常用于链接脚本文件和二进制文件,大多数的组件不需要设置此变量。 + ninja flash -以下变量仅适用于属于 ESP-IDF 的组件: +或:: -- ``COMPONENT_SUBMODULES``: 组件使用的 git 子模块的路径列表(相对于 ``COMPONENT_PATH``)。这些路径会在构建的过程中被检查(并在必要的时候初始化)。如果组件位于 ``IDF_PATH`` 目录之外,则忽略此变量。 + make app-flash +可用的目标还包括:``flash``、``app-flash`` (仅用于 app)、``bootloader-flash`` (仅用于 bootloader)。 + +以这种方式烧录时,可以通过设置 ``ESPPORT`` 和 ``ESPBAUD`` 环境变量来指定串口设备和波特率。您可以在操作系统或 IDE 项目中设置该环境变量,或者直接在命令行中进行设置:: + + ESPPORT=/dev/ttyUSB0 ninja flash + +.. Note:: 在命令的开头为环境变量赋值属于 Bash shell 的语法,可在 Linux 、macOS 和 Windows 的类 Bash shell 中运行,但在 Windows Command Prompt 中无法运行。 + +或:: + + make -j3 app-flash ESPPORT=COM4 ESPBAUD=2000000 + +.. Note:: 在命令末尾为变量赋值属于 ``make`` 的语法,适用于所有平台的 ``make``。 + +在 IDE 中使用 CMake +------------------- + +您还可以使用集成了 CMake 的 IDE,仅需将项目 ``CMakeLists.txt`` 文件的路径告诉 IDE 即可。集成 CMake 的 IDE 通常会有自己的构建工具(CMake 称之为“生成器”),它是组成 IDE 的一部分,用来构建源文件。 + +向 IDE 中添加除 ``build`` 目标以外的自定义目标(如添加 “Flash” 目标到 IDE)时,建议调用 ``idf.py`` 命令来执行这些“特殊”的操作。 + +有关将ESP-IDF 同 CMake 集成到 IDE 中的详细信息,请参阅 :ref:`build_system_metadata`。 + +.. _setting-python-interpreter: + +设置 Python 解释器 +------------------ + +目前,ESP-IDF 仅适用于 Python 2.7,如果系统中默认的 ``python`` 解释器是 Python 3.x,可能会出现问题。 + +如果使用了 ``idf.py``,并以 ``python2 $IDF_PATH/tools/idf.py ...`` 的方式运行 ``idf.py`` 则会解决这个问题(``idf.py`` 会通知其余 Python 进程使用相同的 Python 解释器)。你可以通过设置 shell 别名或其他脚本来简化该命令。 + +如果直接使用 CMake,运行 ``cmake -D PYTHON=python2 ...``,CMake 会使用传入的值覆盖默认的 Python 解释器。 + +如果使用集成 CMake 的 IDE,可以在 IDE 的图形用户界面中给名为 ``PYTHON`` 的 CMake cache 变量设置新的值来覆盖默认的 Python 解释器。 + +如果想在命令行中更优雅地管理 Python 的各个版本,请查看 pyenv_ 或 virtualenv_ 工具,它们会帮助您更改默认的 python 版本。 + +.. _example-project-structure: + +示例项目 +======== + +.. highlight:: none + +示例项目的目录树结构可能如下所示:: + + - myProject/ + - CMakeLists.txt + - sdkconfig + - components/ - component1/ - CMakeLists.txt + - Kconfig + - src1.c + - component2/ - CMakeLists.txt + - Kconfig + - src1.c + - include/ - component2.h + - main/ - src1.c + - src2.c + - build/ + +该示例项目 ``myproject`` 包含以下组成部分: + +- 顶层项目 CMakeLists.txt 文件,这是 CMake 用于学习如何构建项目的主要文件,可以在这个文件中设置项目全局的 CMake 变量。顶层项目 CMakeLists.txt 文件会导入 :idf_file:`/tools/cmake/project.cmake` 文件,由它负责实现构建系统的其余部分。该文件最后会设置项目的名称,并定义该项目。 +- ``sdkconfig`` 项目配置文件,执行 ``idf.py menuconfig`` 时会创建或更新此文件,文件中保存了项目中所有组件(包括 ESP-IDF 本身)的配置信息。 ``sdkconfig`` 文件可能会也可能不会被添加到项目的源码管理系统中。 +- 可选的 ``component`` 目录中包含了项目的部分自定义组件,并不是每个项目都需要这种自定义组件,但它组件有助于构建可复用的代码或者导入第三方(不属于 ESP-IDF)的组件。 +- ``main`` 目录是一个特殊的 ``伪组件``,包含项目本身的源代码。``main`` 是默认名称,CMake 变量 ``COMPONENT_DIRS`` 默认包含此组件,但您可以修改此变量。或者,您也可以在顶层 CMakeLists.txt 中设置 ``EXTRA_COMPONENT_DIRS`` 变量以查找其他指定位置处的组件。有关详细信息,请参阅 :ref:`重命名 main 组件 `。如果项目中源文件较多,建议将其归于组件中,而不是全部放在 ``main`` 中。 +- ``build`` 目录是存放构建输出的地方,如果没有此目录,``idf.py`` 会自动创建。CMake 会配置项目,并在此目录下生成临时的构建文件。随后,在主构建进程的运行期间,该目录还会保存临时目标文件、库文件以及最终输出的二进制文件。此目录通常不会添加到项目的源码管理系统中,也不会随项目源码一同发布。 + +每个组件目录都包含一个 ``CMakeLists.txt`` 文件,里面会定义一些变量以控制该组件的构建过程,以及其与整个项目的集成。更多详细信息请参阅 :ref:`component-directories`。 + +每个组件还可以包含一个 ``Kconfig`` 文件,它用于定义 ``menuconfig`` 时展示的 :ref:`component-configuration` 选项。某些组件可能还会包含 ``Kconfig.projbuild`` 和 ``project_include.cmake`` 特殊文件,它们用于 :ref:`override_project_config`。 + +项目 CMakeLists 文件 +==================== + +每个项目都有一个顶层 ``CMakeLists.txt`` 文件,包含整个项目的构建设置。默认情况下,项目 CMakeLists 文件会非常小。 + +最小 CMakeLists 文件示例 +------------------------ + +.. highlight:: cmake + +最小项目:: + + cmake_minimum_required(VERSION 3.5) + include($ENV{IDF_PATH}/tools/cmake/project.cmake) + project(myProject) + + +.. _project-mandatory-parts: + +必要部分 +-------- + +每个项目都要按照上面显示的顺序添加上述三行代码: + +- ``cmake_minimum_required(VERSION 3.5)`` 必须放在 CMakeLists.txt 文件的第一行,它会告诉 CMake 构建该项目所需要的最小版本号。ESP-IDF 支持 CMake 3.5 或更高的版本。 +- ``include($ENV{IDF_PATH}/tools/cmake/project.cmake)`` 会导入 CMake 的其余功能来完成配置项目、检索组件等任务。 +- ``project(myProject)`` 会创建项目本身,并指定项目名称。该名称会作为最终输出的二进制文件的名字,即 ``myProject.elf`` 和 ``myProject.bin``。每个 CMakeLists 文件只能定义一个项目。 + +.. _optional_project_variable: + +可选的项目变量 +-------------- + +以下这些变量都有默认值,用户可以覆盖这些变量值以自定义构建行为。更多实现细节,请参阅 :idf_file:`/tools/cmake/project.cmake` 文件。 + +- ``COMPONENT_DIRS``:组件的搜索目录,默认为 ``${IDF_PATH}/components``、``${PROJECT_PATH}/components`` 和 ``EXTRA_COMPONENT_DIRS``。如果您不想在这些位置搜索组件,请覆盖此变量。 +- ``EXTRA_COMPONENT_DIRS``:用于搜索组件的其它可选目录列表。路径可以是相对于项目目录的相对路径,也可以是绝对路径。 +- ``COMPONENTS``:要构建进项目中的组件名称列表,默认为 ``COMPONENT_DIRS`` 目录下检索到的所有组件。使用此变量可以“精简”项目以缩短构建时间。请注意,如果一个组件通过 ``COMPONENT_REQUIRES`` 指定了它依赖的另一个组件,则会自动将其添加到 ``COMPONENTS`` 中,所以 ``COMPONENTS`` 列表可能会非常短。 +- ``COMPONENT_REQUIRES_COMMON``:每个组件都需要的通用组件列表,这些通用组件会自动添加到每个组件的 ``COMPONENT_PRIV_REQUIRES`` 列表中以及项目的 ``COMPONENTS`` 列表中。默认情况下,此变量设置为 ESP-IDF 项目所需的最小核心“系统”组件集。通常您无需在项目中更改此变量。 + +以上变量中的路径可以是绝对路径,或者是相对于项目目录的相对路径。 + +请使用 `cmake 中的 set 命令 `_ 来设置这些变量,即 ``set(VARIABLE "VALUE")``。请注意,``set()`` 命令需放在 ``include(...)`` 之前,``cmake_minimum(...)`` 之后。 + +.. _rename-main: + +重命名 ``main`` 组件 +-------------------- + +构建系统会对 ``main`` 组件进行特殊处理。假如 ``main`` 组件位于预期的位置(即 `${PROJECT_PATH}/main`),那么它会被自动添加到构建系统中。其他组件也会作为其依赖项被添加到构建系统中,这使用户免于处理依赖关系,并提供即时可用的构建功能。重命名 ``main`` 组件会减轻上述这些幕后工作量,但要求用户指定重命名后的组件位置,并手动为其添加依赖项。重命名 ``main`` 组件的步骤如下: + +1. 重命名 ``main`` 目录。 +2. 在项目 CMakeLists.txt 文件中设置 ``EXTRA_COMPONENT_DIRS``,并添加重命名后的 ``main`` 目录。 +3. 在组件的 CMakeLists.txt 文件中设置 ``COMPONENT_REQUIRES`` 或 ``COMPONENT_PRIV_REQUIRES`` 以指定依赖项。 + + +.. _component-directories: + +组件 CMakeLists 文件 +==================== + +每个项目都包含一个或多个组件,这些组件可以是 ESP-IDF 的一部分,可以是项目自身组件目录的一部分,也可以从自定义组件目录添加( :ref:`见上文 `)。 + +组件是 ``COMPONENT_DIRS`` 列表中包含 ``CMakeLists.txt`` 文件的任何目录。 + +搜索组件 +-------- + +搜索 ``COMPONENT_DIRS`` 中的目录列表以查找项目的组件,此列表中的目录可以是组件自身(即包含 `CMakeLists.txt` 文件的目录),也可以是子目录为组件的顶级目录。 + +当 CMake 运行项目配置时,它会记录本次构建包含的组件列表,它可用于调试某些组件的添加/排除。 + +同名组件 +-------- + +ESP-IDF 在搜索所有待构建的组件时,会按照 ``COMPONENT_DIRS`` 指定的顺序依次进行,这意味着在默认情况下,首先搜索 ESP-IDF 内部组件,然后是项目组件,最后是 ``EXTRA_COMPONENT_DIRS`` 中的组件。如果这些目录中的两个或者多个包含具有相同名字的组件,则使用搜索到的最后一个位置的组件。这就允许将组件复制到项目目录中再修改以覆盖 ESP-IDF 组件,如果使用这种方式,ESP-IDF 目录本身可以保持不变。 + +.. _minimum_cmakelists: + +最小的组件 CMakeLists 文件 +-------------------------- + +.. highlight:: cmake + +最小组件 ``CMakeLists.txt`` 文件内容如下:: + + set(COMPONENT_SRCS "foo.c") + set(COMPONENT_ADD_INCLUDEDIRS "include") + register_component() + +- ``COMPONENT_SRCS`` 是用空格分隔的源文件列表(``*.c``,``*.cpp``,``*.cc``,``*.S``),里面所有的源文件都将会编译进组件库中。 +- ``COMPONENT_ADD_INCLUDEDIRS`` 是用空格分隔的目录列表,里面的路径会被添加到所有需要该组件的组件(包括 main 组件)全局 include 搜索路径中。 +- ``register_component()`` 使用上述设置的变量将组件添加到构建系统中,构建生成与组件同名的库,并最终被链接到应用程序中。如果因为使用了 `CMake 中的 if 命令 `_ 或类似命令而跳过了这一步,那么该组件将不会被添加到构建系统中。 + +上述目录通常设置为相对于 ``CMakeLists.txt`` 文件的相对路径,当然也可以设置为绝对路径。 + +有关更完整的 ``CMakeLists.txt`` 示例,请参阅 :ref:`component_cmakelists_example`。 + +.. _preset_component_variables: + +预设的组件变量 +-------------- + +以下专用于组件的变量可以在组件 CMakeLists 中使用,但不建议修改: + +- ``COMPONENT_PATH``:组件目录,即包含 ``CMakeLists.txt`` 文件的绝对路径,它与 ``CMAKE_CURRENT_SOURCE_DIR`` 变量一样,路径中不能包含空格。 +- ``COMPONENT_NAME``:组件名,与组件目录名相同。 +- ``COMPONENT_TARGET``:库目标名,它由构建系统在内部为组件创建。 + +以下变量在项目级别中被设置,但可在组件 CMakeLists 中使用: + +- ``PROJECT_NAME``:项目名,在项目 CMakeLists.txt 文件中设置。 +- ``PROJECT_PATH``:项目目录(包含项目 CMakeLists 文件)的绝对路径,与 ``CMAKE_SOURCE_DIR`` 变量相同。 +- ``COMPONENTS``:此次构建中包含的所有组件的名称,具体格式为用分号隔开的 CMake 列表。 +- ``CONFIG_*``:项目配置中的每个值在 cmake 中都对应一个以 ``CONFIG_`` 开头的变量。更多详细信息请参阅 :doc:`Kconfig `。 +- ``IDF_VER``:ESP-IDF 的 git 版本号,由 ``git describe`` 命令生成。 +- ``IDF_VERSION_MAJOR``, ``IDF_VERSION_MINOR``, ``IDF_VERSION_PATCH``: ESP-IDF 的组件版本,可用于条件表达式。请注意这些信息的精确度不如 ``IDF_VER`` 变量,版本号 ``v4.0-dev-*``, ``v4.0-beta1``, ``v4.0-rc1`` 和 ``v4.0`` 对应的 ``IDF_VERSION_*`` 变量值是相同的,但是 ``IDF_VER`` 的值是不同的。 +- ``IDF_TARGET``:项目的硬件目标名称。 +- ``PROJECT_VER``:项目版本号。 + + * 如果在项目 CMakeLists.txt 文件中设置了 ``PROJECT_VER`` 变量,则该变量值可以使用。 + * 或者,如果 ``${PROJECT_PATH}/version.txt`` 文件存在,其内容会用作 ``PROJECT_VER`` 的值。 + * 或者,如果项目位于某个 Git 仓库中,则使用 ``git describe`` 命令的输出作为 ``PROJECT_VER`` 的值。 + * 否则,``PROJECT_VER`` 的值为空。 + +如果您在组件的 ``CMakeLists.txt`` 中修改以上变量,并不会影响其他组件的构建,但可能会使该组件变得难以构建或调试。 + +- ``COMPONENT_ADD_INCLUDEDIRS``:相对于组件目录的相对路径,为被添加到所有需要该组件的其他组件的全局 include 搜索路径中。如果某个 include 路径仅仅在编译当前组件时需要,请将其添加到 ``COMPONENT_PRIV_INCLUDEDIRS`` 中。 +- ``COMPONENT_REQUIRES`` 是一个用空格分隔的组件列表,列出了当前组件依赖的其他组件。如果当前组件有一个头文件位于 ``COMPONENT_ADD_INCLUDEDIRS`` 目录下,且该头文件包含了另一个组件的头文件,那么这个被依赖的组件需要在 ``COMPONENT_REQUIRES`` 中指出。这种依赖关系可以是递归的。 + + ``COMPONENT_REQUIRES`` 可以为空,因为所有的组件都需要一些常用的组件(如 newlib 组件提供的 libc 库、freertos 组件提供的 RTOS 功能),这些通用组件已经在项目级变量 ``COMPONENT_REQUIRES_COMMON`` 中被设置。 + + 如果一个组件仅需要额外组件的头文件来编译其源文件(而不是全局引入它们的头文件),则这些被依赖的组件需要在 ``COMPONENT_PRIV_REQUIRES`` 中指出。 + + 请参阅 :ref:`component_dependency`,查看详细信息。 可选的组件特定变量 -^^^^^^^^^^^^^^^^^^ +------------------ -以下变量可以在 ``component.mk`` 中进行设置,用以控制该组件的构建行为: +以下变量可在 ``CMakeLists.txt`` 中进行设置,用以控制该组件的构建行为: -- ``COMPONENT_PRIV_INCLUDEDIRS``: 相对于组件目录的目录路径,该目录仅会被添加到该组件源文件的头文件搜索路径中。 -- ``COMPONENT_EXTRA_INCLUDES``: 编译组件的源文件时需要指定的额外的头文件搜索路径,这些路径将以 ``-l`` 为前缀传递给编译器。这和 ``COMPONENT_PRIV_INCLUDEDIRS`` 变量的功能有些类似,但是这些路径不会相对于组件目录进行扩展。 -- ``COMPONENT_SRCDIRS``: 相对于组件目录的目录路径,这些路径用于搜索源文件(``*.cpp``,``*.c``,``*.S``),默认为 ``.``,即组件目录本身。重写该变量可以指定包含源文件的不同目录列表。 -- ``COMPONENT_OBJS``: 要编译生成的目标文件,默认是 ``COMPONENT_SRCDIRS`` 中每个源文件的 .o 文件。重写该变量将允许您剔除 ``COMPONENT_SRCDIRS`` 中的某些源文件,否则他们将会被编译。相关示例请参阅 `指定需要编译的组件源文件 <#specify-source-files>`_。 -- ``COMPONENT_EXTRA_CLEAN``: 相对于组件构建目录的路径,指向 ``component.mk`` 文件中自定义 make 规则生成的任何文件,它们也是 ``make clean`` 命令需要删除的文件。相关示例请参阅 `源代码生成 <#source-code-generation>`_。 -- ``COMPONENT_OWNBUILDTARGET`` & ``COMPONENT_OWNCLEANTARGET``: 这些目标允许您完全覆盖组件的默认编译行为。有关详细信息,请参阅 `完全覆盖组件的 Makefile <#fully-overriding-component-makefile>`_。 -- ``COMPONENT_CONFIG_ONLY``: 如果设置了此标志,则表示组件根本不会产生构建输出(即不会构建得到 ``COMPONENT_LIBRARY``),并且会忽略大多数其它组件变量。此标志用于 IDF 内部组件,其中仅包含 ``KConfig.projbuild`` 和/或 ``Makefile.projbuild`` 文件来配置项目,但是没有源文件。 -- ``CFLAGS``: 传递给 C 编译器的标志。根据项目设置已经定义一组默认的 ``CFLAGS``,可以通过 ``CFLAGS +=`` 来为组件添加特定的标志,也可以完全重写该变量(尽管不推荐这么做)。 -- ``CPPFLAGS``: 传递给 C 预处理器的标志(用于 ``.c``,``.cpp`` 和 ``.S`` 文件)。根据项目设置已经定义一组默认的 ``CPPFLAGS`` ,可以通过 ``CPPFLAGS +=`` 来为组件添加特定的标志,也可以完全重写该变量(尽管不推荐这么做)。 -- ``CXXFLAGS``: 传递给 C++ 编译器的标志。根据项目设置已经定义一组默认的 ``CXXFLAGS`` ,可以通过 ``CXXFLAGS +=`` 来为组件添加特定的标志,也可以完全重写该变量(尽管不推荐这么做)。 +- ``COMPONENT_PRIV_INCLUDEDIRS``:相对于组件目录的相对路径,仅会被添加到该组件的 include 搜索路径中。 +- ``COMPONENT_PRIV_REQUIRES``:以空格分隔的组件列表,用于编译或链接当前组件的源文件。这些组件的头文件路径不会传递给其余需要它的组件,仅用于编译当前组件的源代码。更多详细信息请参阅 :ref:`component_dependency`。 +- ``COMPONENT_SRCS``:要编译进当前组件的源文件的路径,推荐使用此方法向构建系统中添加源文件。 +- ``COMPONENT_SRCDIRS``:相对于组件目录的源文件目录路径,用于搜索源文件(``*.cpp``,``*.c``,``*.S``)。匹配成功的源文件会替代 ``COMPONENT_SRCS`` 中指定的源文件,进而被编译进组件。即设置 ``COMPONENT_SRCDIRS`` 会导致 ``COMPONENT_SRCS`` 会被忽略。此方法可以很容易地将源文件整体导入到组件中,但并不推荐使用(详情请参阅 :ref:`cmake-file-globbing`)。 +- ``COMPONENT_SRCEXCLUDE``:需要从组件中剔除的源文件路径。当某个目录中有大量的源文件需要被导入组件中,但同时又有个别文件不需要导入时,可以配合 ``COMPONENT_SRCDIRS`` 变量一起设置。路径可以是相对于组件目录的相对路径,也可以是绝对路径。 +- ``COMPONENT_ADD_LDFRAGMENTS``:组件使用的链接片段文件的路径,用于自动生成链接器脚本文件。详细信息请参阅 :doc:`链接脚本生成机制 `。 -如果要将编译标志应用于单个源文件,您可以将该源文件的目标规则覆盖,例如: +.. Note:: -.. code:: makefile + 如果没有设置 ``COMPONENT_SRCDIRS`` 或 ``COMPONENT_SRCS``,组件不会被编译成库文件,但仍可以被添加到 include 路径中,以便在编译其他组件时使用。 - apps/dhcpserver.o: CFLAGS += -Wno-unused-variable +.. _component_build_control: + +组件编译控制 +------------ + +.. highlight:: cmake + +在编译特定组件的源文件时,可以使用 ``target_compile_options`` 命令来传递编译器选项:: + + target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-variable) + +这条命令封装了 CMake 的 `target_compile_options`_ 命令。 + +如果给单个源文件指定编译器标志,可以使用 CMake 的 `set_source_files_properties`_ 命令:: + + set_source_files_properties(mysrc.c + PROPERTIES COMPILE_FLAGS + -Wno-unused-variable + ) 如果上游代码在编译的时候发出了警告,那这么做可能会很有效。 -配置组件 -~~~~~~~~ +请注意,上述两条命令只能在组件 CMakeLists 文件的 ``register_component()`` 命令之后调用。 -每个组件都可以包含一个 Kconfig 文件,和 ``component.mk`` 放在同一个目录下。Kconfig 中包含此组件在 ``make menuconfig`` 时要展示的配置规则的设置。 +.. _component-configuration: + +组件配置 +======== + +每个组件都可以包含一个 ``Kconfig`` 文件,和 ``CMakeLists.txt`` 放在同一目录下。``Kconfig`` 文件中包含要添加到该组件配置菜单中的一些配置设置信息。 运行 menuconfig 时,可以在 ``Component Settings`` 菜单栏下找到这些设置。 创建一个组件的 Kconfig 文件,最简单的方法就是使用 ESP-IDF 中现有的 Kconfig 文件作为模板,在这基础上进行修改。 -有关示例请参阅 `添加条件配置 <#add-conditional-configuration>`_。 +有关示例请参阅 :ref:`add_conditional_config`。 预处理器定义 -~~~~~~~~~~~~ +============ -ESP-IDF 构建系统会在命令行中添加以下 C 预处理定义: +ESP-IDF 构建系统会在命令行中添加以下 C 预处理器定义: -- ``ESP_PLATFORM`` — 可以用来检测在 ESP-IDF 内发生的构建行为。 -- ``IDF_VER`` — ESP-IDF 的版本,请参阅 `预设的组件变量 <#preset-component-variables>`_。 +- ``ESP_PLATFORM``:可以用来检测在 ESP-IDF 内发生了构建行为。 +- ``IDF_VER``:定义 git 版本字符串,例如:``v2.0`` 用于标记已发布的版本,``v1.0-275-g0efaa4f`` 则用于标记任意某次的提交记录。 +- ``PROJECT_VER``:项目版本号,详细信息请参阅 :ref:`preset_component_variables`。 +- ``PROJECT_NAME``:项目名称,定义在项目 CMakeLists.txt 文件中。 + +.. _component_dependency: + +组件依赖 +======== + +编译各个组件时,ESP-IDF 系统会递归评估其组件。 + +每个组件的源文件都会使用以下路径中的头文件进行编译: + +- 当前组件的 ``COMPONENT_ADD_INCLUDEDIRS`` 和 ``COMPONENT_PRIV_INCLUDEDIRS``。 +- 当前组件的 ``COMPONENT_REQUIRES`` 和 ``COMPONENT_PRIV_REQUIRES`` 变量指定的其他组件(即当前组件的所有公共和私有依赖项)所设置的 ``COMPONENT_ADD_INCLUDEDIRS``。 +- 所有组件的 ``COMPONENT_REQUIRES`` 做递归操作,即该组件递归运算后的所有公共依赖项。 + +编写组件 +-------- + +- ``COMPONENT_REQUIRES`` 需要包含所有被当前组件的公共头文件 `#include` 的头文件所在的组件。 +- ``COMPONENT_PRIV_REQUIRES`` 需要包含被当前组件的源文件 `#include` 的头文件所在的组件(除非已经被设置在了 ``COMPONENT_PRIV_REQUIRES`` 中)。或者是当前组件正常工作必须要链接的组件。 +- ``COMPONENT_REQUIRES``、``COMPONENT_PRIV_REQUIRES`` 需要在调用 ``register_component()`` 之前设置。 +- ``COMPONENT_REQUIRES`` 和 ``COMPONENT_PRIV_REQUIRES`` 的值不能依赖于任何配置选项(``CONFIG_xxx``),这是因为在配置加载之前,依赖关系就已经被展开。其它组件变量(比如 ``COMPONENT_SRCS`` 和 ``COMPONENT_ADD_INCLUDEDIRS``)可以依赖配置选择。 +- 如果当前组件除了 ``COMPONENT_REQUIRES_COMMON`` 中设置的通用组件(比如 RTOS、libc 等)外,并不依赖其它组件,那么上述两个 ``REQUIRES`` 变量可以为空。 + +如果组件仅支持某些硬件目标(即依赖于特定的 ``IDF_TARGET``),则可以调用 ``require_idf_targets(NAMES...)`` CMake 函数来声明这个需求。在这种情况下,如果构建系统导入了不支持当前硬件目标的组件时就会报错。 + +创建项目 +-------- + +- 默认情况下,每个组件都会包含在构建系统中。 +- 如果将 ``COMPONENTS`` 变量设置为项目直接使用的最小组件列表,那么构建系统会导入: + + * ``COMPONENTS`` 中明确提及的组件。 + * 这些组件的依赖项(以及递归运算后的组件)。 + * 每个组件都依赖的通用组件。 + +- 将 ``COMPONENTS`` 设置为所需组件的最小列表,可以显著减少项目的构建时间。 + +.. _component-requirements-implementation: + +构建系统中依赖处理的实现细节 +---------------------------- + +- 在 CMake 配置进程的早期阶段会运行 ``expand_requirements.cmake`` 脚本。该脚本会对所有组件的 CMakeLists.txt 文件进行局部的运算,得到一张组件依赖关系图(此图可能会有闭环)。此图用于在构建目录中生成 ``component_depends.cmake`` 文件。 +- CMake 主进程会导入该文件,并以此来确定要包含到构建系统中的组件列表(内部使用的 ``BUILD_COMPONENTS`` 变量)。``BUILD_COMPONENTS`` 变量已排好序,依赖组件会排在前面。由于组件依赖关系图中可能存在闭环,因此不能保证每个组件都满足该排序规则。如果给定相同的组件集和依赖关系,那么最终的排序结果应该是确定的。 +- CMake 会将 ``BUILD_COMPONENTS`` 的值以 “Component names:” 的形式打印出来。 +- 然后执行构建系统中包含的每个组件的配置。 +- 每个组件都被正常包含在构建系统中,然后再次执行 CMakeLists.txt 文件,将组件库加入构建系统。 + +组件依赖顺序 +^^^^^^^^^^^^ + +``BUILD_COMPONENTS`` 变量中组件的顺序决定了构建过程中的其它顺序,包括: + +- 项目导入 :ref:`project_include.cmake` 文件的顺序。 +- 生成用于编译(通过 ``-I`` 参数)的头文件路径列表的顺序。请注意,对于给定组件的源文件,仅需将该组件的依赖组件的头文件路径告知编译器。 构建的内部过程 -~~~~~~~~~~~~~~ +============== -顶层:项目 Makefile -^^^^^^^^^^^^^^^^^^^ +关于 CMake_ 以及 CMake 命令的详细信息,请参阅 `CMake v3.5 官方文档`_ 。 -- ``make`` 始终从项目目录处运行,并且项目的 makefile 名字通常为 Makefile 。 -- 项目的 makefile 文件会设置 ``PROJECT_NAME`` ,并且可以自定义其他可选的项目变量。 -- 项目 makefile 文件会导入 ``$(IDF_PATH)/make/project.mk`` ,该文件中会导入项目级的 Make 逻辑。 -- ``project.mk`` 填写默认的项目级 make 变量,并导入项目配置中的 make 变量。如果生成的包含项目配置的 makefile 文件已经过期,那么它将会被重新生成(通过 ``project_config.mk`` 中的目标规则),然后 make 进程从顶层重新开始。 -- ``project.mk`` 根据默认组件目录或者可选项目变量中设置的自定义组件列表来编译组件。 -- 每个组件都可以设置一些 `可选的项目通用组件变量 <#optional-project-wide-component-variables>`_ ,他们会通过 ``component_project_vars.mk`` 被导入 ``project.mk`` 文件中。如果这些文件有缺失或者过期,他们会被重新生成(通过对组件 makefile 的递归调用),然后 make 进程从顶层重新开始。 -- 组件中的 Makefile.projbuild 文件被包含在了 make 的进程中,以添加额外的目标或者配置。 -- 默认情况下,项目 makefile 还为每个组件生成顶层的编译和清理目标,并设置 app 和 clean 目标来调用所有这些子目标。 -- 为了编译每个组件,对组件 makefile 执行递归构建。 +project.cmake 的内容 +-------------------- -为了更好地理解项目的构建过程,请通读 ``project.mk`` 文件。 +当项目 CMakeLists 文件导入 ``project.cmake`` 文件时,``project.cmake`` 会定义一些实用的模块和全局变量。如果系统环境中没有设置 ``IDF_PATH``,那么它还会自动设置 ``IDF_PATH`` 变量。 -第二层:组件 Makefile 文件 -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +``project.cmake`` 文件还重写了 CMake_ 内置的 ``project`` 函数,以添加所有 ESP-IDF 项目特有的功能。 -- 每次调用组件 makefile 文件都是通过 ``$(IDF_PATH)/make/component_wrapper.mk`` 这个包装器进行的。 -- 此组件包装器包含了所有组件的 ``Makefile.componentbuild`` 文件,使这些文件中的任何配置,变量都可用于每个组件。 -- 调用 ``component_wrapper.mk`` 时将当前目录设置为组件构建目录,并将 ``COMPONENT_MAKEFILE`` 变量设置为 ``component.mk`` 的绝对路径。 -- ``component_wrapper.mk`` 为所有组件变量设置默认值,然后导入 ``component.mk`` 文件来覆盖或修改这些变量。 -- 如果未定义 ``COMPONENT_OWNBUILDTARGET`` 和 ``COMPONENT_OWNCLEANTARGET`` 文件,则会为组件的源文件和必备组件 ``COMPONENT_LIBRARY`` 静态库文件创建默认构建和清理目标。 -- ``component_project_vars.mk`` 文件在 ``component_wrapper.mk`` 中有自己的目标,如果由于组件的 makefile 或者项目配置的更改而需要重建此文件,则从 ``project.mk`` 文件中进行评估。 +project 函数 +------------ -为了更好地理解组件制作过程,请阅读 ``component_wrapper.mk`` 文件和 ESP-IDF 中的 ``component.mk`` 文件。 +自定义的 ``project()`` 函数会执行以下步骤: -以非交互的方式运行 Make -~~~~~~~~~~~~~~~~~~~~~~~ +- 确定硬件目标(由 ``IDF_TARGET`` 环境变量设置),并将其保存在 CMake cache 中。如果环境变量中设置的硬件目标与 CMake cache 中的不匹配,则会报错并退出。 +- 计算组件依赖,并构造 ``BUILD_COMPONENTS`` 变量,它是包含所有需要导入到构建系统中的组件列表(:ref:`详情请见上文`)。 +- 查找项目中所有的组件(搜索 ``COMPONENT_DIRS``,并按 ``COMPONENTS`` 进行过滤(前提是设置了该变量)。 +- 从 ``sdkconfig`` 文件中加载项目配置信息,生成 ``sdkconfig.cmake`` 和 ``sdkconfig.h`` 文件,分别用在 CMake 和 C/C++ 中定义配置项。如果项目配置发生了更改,CMake 会自动重新运行,重新生成上述两个文件,接着重新配置项目。 +- 根据硬件目标(``IDF_TARGET``)的值,将 `CMAKE_TOOLCHAIN_FILE`_ 变量设置为相应的工具链文件。 +- 调用 `CMake 的 project 函数 `_ 声明实际的 CMake-level 项目。 +- 加载 git 版本号。如果在 git 中检出了新的版本,就会使用一些技巧重新运行 CMake。详情请参考 :ref:`cmake-file-globbing`。 +- 从包含有 :ref:`project_include.cmake` 文件的组件中导入该文件。 +- 将每个组件都添加到构建系统中。每个组件的 CMakeLists 文件都会调用 ``register_component`` 函数,它会调用 CMake 的 `add_library `_ 函数来添加一个库,然后添加源文件、编译选项等。 +- 将最终的应用程序可执行文件添加到构建系统中。 +- 返回并为组件之间指定依赖关系(将每个组件的公共头文件目录添加到其他组件中)。 -如果在运行 ``make`` 的时候不希望出现交互式提示(例如:在IDE或自动构建系统中),可以将 ``BATCH_BUILD=1`` 添加到make的参数中(或者将其设置为环境变量)。 +更多详细信息请参阅 :idf_file:`/tools/cmake/project.cmake` 文件和 :idf_file:`/tools/cmake/idf_functions.cmake` 文件。 -设置 ``BATCH_BUILD`` 意味着: +CMake 调试 +---------- -- 详细输出(与 ``V=1`` 相同,见下文),如果不需要详细输出,就设置 ``V=0`` 。 -- 如果项目配置缺少新配置项(来自新组件或者 ESP-IDF 更新),则项目使用默认值,而不是提示用户输入每个项目。 -- 如果构建系统需要调用 ``menuconfig`` ,则会打印错误并且构建失败。 +调试 ESP-IDF CMake 构建系统的一些技巧: -.. _make-size: - -构建目标的进阶用法 -~~~~~~~~~~~~~~~~~~ - -- ``make app``,``make bootloader``,``make partition table`` 可以根据需要为项目单独构建生成应用程序文件、启动引导文件和分区表文件。 -- ``make erase_flash`` 和 ``make erase_ota`` 会调用 esptool.py 脚本分别擦除整块闪存芯片或者其中 OTA 分区的内容。 -- ``make size`` 会打印应用程序的大小信息。``make size-components`` 和 ``make size-files`` 两者功能相似,分别打印每个组件或者每个源文件大小的详细信息。 - -调试 Make 的过程 -~~~~~~~~~~~~~~~~ - -调试 ESP-IDF 构建系统的一些技巧: - -- 将 ``V=1`` 添加到 make 的参数中(或将其设置为环境变量)将使 make 回显所有已经执行的命令,以及为子 make 输入的每个目录。 -- 运行 ``make -w`` 将导致 make 在为子 make 输入时回显每个目录——与 ``V=1`` 相同但不回显所有命令。 -- 运行 ``make --trace`` (可能除了上述参数之一)将打印出构建时的每个目标,以及导致它构建的依赖项)。 -- 运行 ``make -p`` 会打印每个 makefile 中每个生成的目标的(非常详细的)摘要。 - -更多调试技巧和通用的构建信息,请参阅 `GNU 构建手册 `_。 +- CMake 运行时,会打印大量诊断信息,包括组件列表和组件路径。 +- 运行 ``cmake -DDEBUG=1``,IDF 构建系统会生成更详细的诊断输出。 +- 运行 ``cmake`` 时指定 ``--trace`` 或 ``--trace-expand`` 选项会提供大量有关控制流信息。详情请参考 `CMake 命令行文档`_。 .. _warn-undefined-variables: 警告未定义的变量 ^^^^^^^^^^^^^^^^ -默认情况下,如果引用了未定义的变量(如 ``$(DOES_NOT_EXIST)`` ,构建过程将会打印警告,这对于查找变量名称中的错误非常有用。 +默认情况下,``idf.py`` 在调用 CMake_ 时会给它传递 ``--warn-uninitialized`` 标志,如果在构建的过程中引用了未定义的变量,CMake_ 会打印警告。这对查找有错误的 CMake 文件非常有用。 -如果不想要此行为,可以在 menuconfig 顶层菜单下的 `SDK tool configuration` 中禁用它。 +如果您不想启用此功能,可以给 ``idf.py`` 传递 ``--no-warnings`` 标志。 -请注意,如果在 Makefile 中使用 ``ifdef`` 或者 ``ifndef`` ,则此选项不会出发警告。 +.. _override_project_config: -覆盖项目的部分内容 -~~~~~~~~~~~~~~~~~~ +覆盖项目的部分设置 +------------------ -Makefile.projbuild -^^^^^^^^^^^^^^^^^^ +.. _project_include.cmake: -如果一个组件含有必须要在项目构建过程的顶层进行计算的变量,则可以在组件目录下创建名为 ``Makefile.projbuild`` 的文件,项目在执行 ``project.mk`` 的时候会导入此 makefile 。 +project_include.cmake +^^^^^^^^^^^^^^^^^^^^^ -例如,如果您的组件需要为整个项目添加 CFLAGS(不仅仅是为自身的源文件),那么可以在 ``Makefile.projbuild`` 中设置 ``CFLAGS +=`` 。 +如果组件的某些构建行为需要在组件 CMakeLists 文件之前被执行,您可以在组件目录下创建名为 ``project_include.cmake`` 的文件,``project.cmake`` 在运行过程中会导入此 CMake 文件。 -``Makefile.projbuild`` 文件在 ESP-IDF 中大量使用,用于定义项目范围的构建功能,例如 ``esptool.py`` 命令行参数和 ``bootloader`` 这个特殊的程序。 +``project_include.cmake`` 文件在 ESP-IDF 内部使用,以定义项目范围内的构建功能,比如 ``esptool.py`` 的命令行参数和 ``bootloader`` 这个特殊的应用程序。 -请注意, ``Makefile.projbuild`` 对于最常见的组件不是必需的 - 例如向项目中添加 include 目录,或者将 LDFLAGS 添加到最终链接步骤,同样可以通过 ``component.mk`` 文件来自定义这些值。有关详细信息,请参阅 `可选的项目通用组件变量 <#optional-project-wide-component-variables>`_ 。 +与组件 ``CMakeLists.txt`` 文件有所不同,在导入``project_include.cmake`` 文件的时候,当前源文件目录(即 ``CMAKE_CURRENT_SOURCE_DIR``)和工作目录为项目目录。如果想获得当前组件的绝对路径,可以使用 ``COMPONENT_PATH`` 变量。 -.. warning:: +请注意,``project_include.cmake`` 对于大多数常见的组件并不是必需的。例如给项目添加 include 搜索目录,给最终的链接步骤添加 ``LDFLAGS`` 选项等等都可以通过 ``CMakeLists.txt`` 文件来自定义。详细信息请参考 :ref:`optional_project_variable`。 - 在此文件中设置变量或者目标时要小心,由于这些值包含在项目的顶层 makefile 中,因此他们可以影响或者破坏所有组件的功能! +``project_include.cmake`` 文件会按照 ``BUILD_COMPONENTS`` 变量中组件的顺序(由 CMake 记录)依次导入。即只有在当前组件所有依赖组件的 ``project_include.cmake`` 文件都被导入后,当前组件的 ``project_include.cmake`` 文件才会被导入,除非两个组件在同一个依赖闭环中。如果某个 ``project_include.cmake`` 文件依赖于另一组件设置的变量,则要特别注意上述情况。更多详情请参阅 :ref:`component-requirements-implementation`。 + +在 ``project_include.cmake`` 文件中设置变量或目标时要格外小心,这些值被包含在项目的顶层 CMake 文件中,因此他们会影响或破坏所有组件的功能。 KConfig.projbuild ^^^^^^^^^^^^^^^^^ -这相当于 ``Makefile.projbuild`` 的组件配置 KConfig 文件,如果要在 menuconfig 的顶层添加配置选项,而不是在 ``组件配置`` 子菜单中,则可以在 ``component.mk`` 文件所在目录中的 KConfig.projbuild 文件中定义这些选项。 +与 ``project_include.cmake`` 类似,也可以为组件定义一个 KConfig 文件以实现全局的 :ref:`component-configuration`。如果要在 menuconfig 的顶层添加配置选项,而不是在 “Component Configuration” 子菜单中,则可以在 ``CMakeLists.txt`` 文件所在目录的 KConfig.projbuild 文件中定义这些选项。 -在此文件中添加配置时要小心,因为他们将包含在整个项目配置中,在可能的情况下,通常最好为组件创建和配置 KConfig 文件。 +在此文件中添加配置时要小心,因为这些配置会包含在整个项目配置中。在可能的情况下,请为 :ref:`component-configuration` 创建 KConfig 文件。 -Makefile.componentbuild -^^^^^^^^^^^^^^^^^^^^^^^ +.. _config_only_component: -对于一些特殊的组件,比如它们会使用工具从其余文件中生成源文件,这时就有必要将配置、宏或者变量的定义添加到每个组件的构建过程中。这是通过在组件目录中包含 ``Makefile.componentbuild`` 文件来实现的。此文件在 ``component.mk`` 文件之前被导入 ``component_wrapper.mk`` 中。同 ``Makefile.projbuild`` 文件一样,请留意这些文件,因为他们包含在每个组件的构建中,所有只有在编译完全不同的组件时才会出现 ``Makefile.componentbuild`` 错误。 - -仅配置的组件 -^^^^^^^^^^^^ - -仅配置的组件是一类不包含源文件的特殊组件,只有 ``Kconfig.projbuild`` 和 ``Makefile.projbuild`` 文件,可以在 ``conponent.mk`` 文件中设置标志 ``COMPONENT_CONFIG_ONLY``。如果设置了此标志,则忽略大多数其他组件变量,并且不会为组件执行构建操作。 - -.. _example-component-makefile: - -组件 Makefile 示例 -~~~~~~~~~~~~~~~~~~ - -因为构建环境试图设置大多数情况都能工作的合理默认值,所以 ``component.mk`` 可能非常小,甚至是空的,请参考 `最小组件 Makefile <#minimal-component-makefile>`_。但是某些功能通常需要覆盖组件的变量。 - -以下是 ``component.mk`` 的一些更高级的示例: - -增加源文件目录 -^^^^^^^^^^^^^^ - -默认情况下,将忽略子目录。如果您的项目在子目录中而不是在组件的根目录中有源文件,那么您可以通过设置 ``COMPONENT_SRCDIRS`` 将其告知构建系统: - -.. code:: - - COMPONENT_SRCDIRS := src1 src2 - -构建系统将会编译 src1/ 和 src2/ 子目录中的所有源文件。 - -.. _specify-source-files: - -指定源文件 +仅配置组件 ^^^^^^^^^^ -标准 ``component.mk`` 逻辑将源目录中的所有 .S 和 .c 文件添加为无条件编译的源。通过将 ``COMPONENT_OBJS`` 变量手动设置为需要生成的对象的名称,可以绕过该逻辑并对要编译的对象进行硬编码。 +仅配置组件是一类不包含源文件的特殊组件,仅包含 ``Kconfig.projbuild``、``KConfig`` 和 ``CMakeLists.txt`` 文件,该 ``CMakeLists.txt`` 文件仅有一行代码,调用了 ``register_config_only_component()`` 函数。此函数会将组件导入到项目构建中,但不会构建任何库,也不会将头文件添加到任何 include 搜索路径中。 -.. code:: +如果 CMakeLists.txt 文件没有调用 ``register_component()`` 或 ``register_config_only_component()``,那么该文件将会被排除在项目构建之外。根据项目的配置,有时可能需要这么做。 - COMPONENT_OBJS := file1.o file2.o thing/filea.o thing/fileb.o anotherthing/main.o - COMPONENT_SRCDIRS := . thing anotherthing +.. _component_cmakelists_example: -请注意,还需要另外设置 ``COMPONENT_SRCDIRS`` 。 +组件 CMakeLists 示例 +==================== -.. _add-conditional-configuration: +因为构建环境试图设置大多数情况都能工作的合理默认值,所以组件 ``CMakeLists.txt`` 文件可能非常小,甚至是空的,请参考 :ref:`minimum_cmakelists`。但有些功能往往需要覆盖 :ref:`preset_component_variables` 才能实现。 + +以下是组件 CMakeLists 文件的更高级的示例。 + +.. _add_conditional_config: 添加条件配置 -^^^^^^^^^^^^ +------------ -配置系统可用于有条件地编译某些文件,具体取决于 ``make menuconfig`` 中选择的选项。为此,ESP-IDF 具有 ``compile_only_if`` 和 ``compile_only_if_not`` 的宏: +配置系统可用于根据项目配置中选择的选项有条件地编译某些文件。 -``Kconfig``: +.. highlight:: none -.. code:: +``Kconfig``:: - config FOO_ENABLE_BAR - bool "Enable the BAR feature." - help - This enables the BAR feature of the FOO component. + config FOO_ENABLE_BAR + bool "Enable the BAR feature." + help + This enables the BAR feature of the FOO component. -``component.mk``: +``CMakeLists.txt``:: -.. code:: + set(COMPONENT_SRCS "foo.c" "more_foo.c") - $(call compile_only_if,$(CONFIG_FOO_ENABLE_BAR),bar.o) + if(CONFIG_FOO_ENABLE_BAR) + list(APPEND COMPONENT_SRCS "bar.c") + endif() -从示例中可以看出, ``compile_only_if`` 宏将条件和目标文件列表作为参数。如果条件为真(在这种情况下:如果在 menuconfig 中启用了 BAR 功能),将始终编译目标文件(在本例中为 bar.o)。相反的情况也是如此,如果条件不成立,bar.o 将永远不会被编译。 ``compile_only_if_not`` 执行相反的操作,如果条件为 false 则编译,如果条件为 true 则不编译。 +上述示例使用了 CMake 的 `if `_ 函数和 `list APPEND `_ 函数。 -这也可以用于选择或者删除实现,如下所示: +也可用于选择或删除某一实现,如下所示: -``Kconfig``: +``Kconfig``:: -.. code:: + config ENABLE_LCD_OUTPUT + bool "Enable LCD output." + help + Select this if your board has a LCD. - config ENABLE_LCD_OUTPUT - bool "Enable LCD output." - help - Select this if your board has a LCD. + config ENABLE_LCD_CONSOLE + bool "Output console text to LCD" + depends on ENABLE_LCD_OUTPUT + help + Select this to output debugging output to the lcd - config ENABLE_LCD_CONSOLE - bool "Output console text to LCD" - depends on ENABLE_LCD_OUTPUT - help - Select this to output debugging output to the lcd + config ENABLE_LCD_PLOT + bool "Output temperature plots to LCD" + depends on ENABLE_LCD_OUTPUT + help + Select this to output temperature plots - config ENABLE_LCD_PLOT - bool "Output temperature plots to LCD" - depends on ENABLE_LCD_OUTPUT - help - Select this to output temperature plots +.. highlight:: cmake -``component.mk``: +``CMakeLists.txt``:: -.. code:: + if(CONFIG_ENABLE_LCD_OUTPUT) + set(COMPONENT_SRCS lcd-real.c lcd-spi.c) + else() + set(COMPONENT_SRCS lcd-dummy.c) + endif() - # If LCD is enabled, compile interface to it, otherwise compile dummy interface - $(call compile_only_if,$(CONFIG_ENABLE_LCD_OUTPUT),lcd-real.o lcd-spi.o) - $(call compile_only_if_not,$(CONFIG_ENABLE_LCD_OUTPUT),lcd-dummy.o) + # 如果启用了控制台或绘图功能,则需要加入字体 + if(CONFIG_ENABLE_LCD_CONSOLE OR CONFIG_ENABLE_LCD_PLOT) + list(APPEND COMPONENT_SRCS "font.c") + endif() - #We need font if either console or plot is enabled - $(call compile_only_if,$(or $(CONFIG_ENABLE_LCD_CONSOLE),$(CONFIG_ENABLE_LCD_PLOT)), font.o) -请注意使用 Make 或者函数来包含字体文件。其他的替换函数,比如 ``and`` 和 ``if`` 也适用于此处。也可以使用不在 menuconfig 中定义的变量,ESP-IDF 使用默认的 Make 策略,将一个空的或者只包含空格的变量视为 false ,而其中任何非空格的比那辆都为 true 。 +硬件目标的的条件判断 +-------------------- -(注意:本文档的历史版本建议将目标文件添加到 ``COMPONENT_OBJS`` 中,虽然这仍然可行,但是只有当组件中的所有目标文件都明确命名时才会起作用,并且在 ``make clean`` 后并不会清除 make 中取消选择的目标文件)。 +CMake 文件可以使用 ``IDF_TARGET`` 变量来获取当前的硬件目标。 -.. _source-code-generation: +此外,如果当前的硬件目标是 ``xyz``(即 ``IDF_TARGET=xyz``),那么 Kconfig 变量 ``CONFIG_IDF_TARGET_XYZ`` 同样也会被设置。 -源代码生成 -^^^^^^^^^^ +请注意,组件可以依赖 ``IDF_TARGET`` 变量,但不能依赖这个 Kconfig 变量。同样也不可在 CMake 文件的 ``include`` 语句中使用 Kconfig 变量,在这种上下文中可以使用 ``IDF_TARGET``。 -某些组件会出现源文件未随组件本身提供,而必须从另外一个文件生成的情况。假设我们的组件有一个头文件,该文件由 BMP 文件转换后的二进制数据组成,假设使用 bmp2h 的工具进行转换,然后将头文件包含在名为 graphics_lib.c 的文件中: -.. code:: +生成源代码 +---------- - COMPONENT_EXTRA_CLEAN := logo.h +有些组件的源文件可能并不是由组件本身提供,而必须从另外的文件生成。假设组件需要一个头文件,该文件由 BMP 文件转换后(使用 bmp2h 工具)的二进制数据组成,然后将头文件包含在名为 graphics_lib.c 的文件中:: - graphics_lib.o: logo.h + add_custom_command(OUTPUT logo.h + COMMAND bmp2h -i ${COMPONENT_DIR}/logo.bmp -o log.h + DEPENDS ${COMPONENT_DIR}/logo.bmp + VERBATIM) - logo.h: $(COMPONENT_PATH)/logo.bmp - bmp2h -i $^ -o $@ + add_custom_target(logo DEPENDS logo.h) + add_dependencies(${COMPONENT_LIB} logo) -这个示例会在当前目录(构建目录)中生成 graphics_lib.o 和 logo.h 文件,而 logo.bmp 随组件一起提供并位于组件路径下。因为 logo.h 是一个生成的文件,所以当调用 ``make clean`` 时需要清理它,这就是为什么要将它添加到 ``COMPONENT_EXTRA_CLEAN`` 变量中。 + set_property(DIRECTORY "${COMPONENT_DIR}" APPEND PROPERTY + ADDITIONAL_MAKE_CLEAN_FILES logo.h) -润色与改进 -^^^^^^^^^^ +这个示例改编自 `CMake 的一则 FAQ `_,其中还包含了一些同样适用于 ESP-IDF 构建系统的示例。 -将 logo.h 添加作为 ``graphics_lib.o`` 的依赖项会导致在编译 ``graphics_lib.c`` 之前先生成它。 +这个示例会在当前目录(构建目录)中生成 logo.h 文件,而 logo.bmp 会随组件一起提供在组件目录中。因为 logo.h 是一个新生成的文件,一旦项目需要清理,该文件也应该要被清除。因此,要将该文件添加到 `ADDITIONAL_MAKE_CLEAN_FILES`_ 属性中。 -如果另一个组件中的源文件需要使用 logo.h,则必须将此组件的名称添加到另一个组件的 ``COMPONENT_DEPENDS`` 列表中,以确保组件按顺序编译。 +.. Note:: + + 如果需要生成文件作为项目 CMakeLists.txt 的一部分,而不是作为组件 CMakeLists.txt 的一部分,此时需要使用 ``${PROJECT_PATH}`` 替代 ``${COMPONENT_DIR}``,使用 ``${PROJECT_NAME}.elf`` 替代 ``${COMPONENT_LIB}``。 + +如果某个源文件是从其他组件中生成,且包含 ``logo.h`` 文件,则需要调用 ``add_dependencies``, 在这两个组件之间添加一个依赖项,以确保组件源文件按照正确顺序进行编译。 嵌入二进制数据 -^^^^^^^^^^^^^^ +--------------------- -有时您的组件希望使用一个二进制文件或者文本文件,但是您又不希望将它重新格式化为 C 源文件。 +有时您的组件希望使用一个二进制文件或者文本文件,但是您又不希望将它们重新格式化为 C 源文件,这时,您可以在组件 CMakeLists 中添加 ``COMPONENT_EMBED_FILES`` 变量,指定要嵌入的文件名称(以空格分隔):: -这时,您可以在 ``component.mk`` 文件中设置变量 ``COMPONENT_EMBED_FILES``,以这种方式指定要嵌入的文件的名称: + set(COMPONENT_EMBED_FILES server_root_cert.der) -.. code:: +或者,如果文件是字符串,则可以设置 ``COMPONENT_EMBED_TXTFILES`` 变量,把文件的内容转成以 null 结尾的字符串嵌入:: - COMPONENT_EMBED_FILES := server_root_cert.der + set(COMPONENT_EMBED_TXTFILES server_root_cert.pem) -或者,如果文件是字符串,则可以使用变量 ``COMPONENT_EMBED_TXTFILES``,这将把文本文件的内容当成以 null 结尾的字符串嵌入: +.. highlight:: c -.. code:: +文件的内容会被添加到 Flash 的 .rodata 段,用户可以通过符号名来访问,如下所示:: - COMPONENT_EMBED_TXTFILES := server_root_cert.pem + 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"); -文件的内容会被编译进 flash 中的 .rodata 段,并通过符号名称来访问,如下所示: +符号名会根据文件全名生成,如 ``COMPONENT_EMBED_FILES`` 中所示,字符 ``/``、``.`` 等都会被下划线替代。符号名称中的 _binary 前缀由 objcopy 命令添加,对文本文件和二进制文件都是如此。 -.. code:: c +.. highlight:: cmake - 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"); +如果要将文件嵌入到项目中,而非组件中,可以调用 ``target_add_binary_data`` 函数:: -符号名称是根据文件的全名生成的,如 ``COMPONENT_EMBED_FILES`` 中的所示,字符 / , . , 等都将会被下划线替代。符号名称中的 ``_binary`` 前缀由 ``objcopy`` 添加,对于文本和二进制文件都是相同的。 + target_add_binary_data(myproject.elf "main/data.bin" TEXT) -有关使用此技术的示例,请参考 :example:`protocols/https_request` - 证书文件的内容会在编译时从 .pem 文件中加载。 +并这行代码放在项目 CMakeLists.txt 的 ``project()`` 命令之后,修改 ``myproject.elf`` 为你自己的项目名。如果最后一个参数是 ``TEXT``,那么构建系统会嵌入以 null 结尾的字符串,如果最后一个参数被设置为 ``BINARY``,则将文件内容按照原样嵌入。 -.. _fully-overriding-component-makefile: +有关使用此技术的示例,请参考 :example:`protocols/https_request`,证书文件的内容会在编译时从 .pem 文件中加载。 -完全覆盖组件的 Makefile -~~~~~~~~~~~~~~~~~~~~~~~ +代码和数据的存放 +---------------- -显然,在某些情况下,所有这些配置都不足以满足某个组件,例如,当组件基本上是另一个第三方组件的包装器时,该第三方组件最初不打算在 ESP-IDF 构建系统下工作,在这种情况下,可以通过设置 ``COMPONENT_OWNBUILDTARGET`` 和可能的 ``COMPONENT_OWNCLEANTARGET``,并在 ``component.mk`` 中定义名为 ``build`` 和 ``clean`` 的目标。构建目标可以执行任何操作,只要它为项目生成了 ``$(COMPONENT_LIBRARY)`` ,并最终被链接到应用程序二进制文件中即可。 +ESP-IDF 还支持自动生成链接脚本,它允许组件通过链接片段文件定义其代码和数据在内存中的存放位置。构建系统会处理这些链接片段文件,并将处理后的结果扩充进链接脚本,从而指导应用程序二进制文件的链接过程。更多详细信息与快速上手指南,请参阅 :doc:`链接脚本生成机制 `。 -(实际上,这并不是必须的 - 如果 ``COMPONENT_ADD_LDFLAGS`` 变量被覆盖,那么组件可以指示链接器链接其他二进制文件。) +.. _component-build-full-override: + +完全覆盖组件的构建过程 +---------------------- + +.. highlight:: cmake + +当然,在有些情况下,上面提到的方法不一定够用。如果组件封装了另一个第三方组件,而这个第三方组件并不能直接在 ESP-IDF 的构建系统中工作,在这种情况下,就需要放弃 ESP-IDF 的构建系统,改为使用 CMake 的 ExternalProject_ 功能。组件 CMakeLists 示例如下:: + + # 用于 quirc 的外部构建过程,在源目录中运行并生成 libquirc.a + externalproject_add(quirc_build + PREFIX ${COMPONENT_DIR} + SOURCE_DIR ${COMPONENT_DIR}/quirc + CONFIGURE_COMMAND "" + BUILD_IN_SOURCE 1 + BUILD_COMMAND make CC=${CMAKE_C_COMPILER} libquirc.a + INSTALL_COMMAND "" + ) + + # 将 libquirc.a 添加到构建系统中 + add_library(quirc STATIC IMPORTED GLOBAL) + add_dependencies(quirc quirc_build) + + set_target_properties(quirc PROPERTIES IMPORTED_LOCATION + ${COMPONENT_DIR}/quirc/libquirc.a) + set_target_properties(quirc PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + ${COMPONENT_DIR}/quirc/lib) + + set_directory_properties( PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES + "${COMPONENT_DIR}/quirc/libquirc.a") + +(上述 CMakeLists.txt 可用于创建名为 ``quirc`` 的组件,该组件使用自己的 Makefile 构建 quirc_ 项目。) + +- ``externalproject_add`` 定义了一个外部构建系统。 + + - 设置 ``SOURCE_DIR``、``CONFIGURE_COMMAND``、``BUILD_COMMAND`` 和 ``INSTALL_COMMAND``。如果外部构建系统没有配置这一步骤,可以将 ``CONFIGURE_COMMAND`` 设置为空字符串。在 ESP-IDF 的构建系统中,一般会将 ``INSTALL_COMMAND`` 变量设置为空。 + - 设置 ``BUILD_IN_SOURCE``,即构建目录与源目录相同。否则,您也可以设置 ``BUILD_DIR`` 变量。 + - 有关 ``externalproject_add()`` 命令的详细信息,请参阅 ExternalProject_。 + +- 第二组命令添加了一个目标库,指向外部构建系统生成的库文件。为了添加 include 目录,并告知 CMake 该文件的位置,需要再设置一些属性。 +- 最后,生成的库被添加到 `ADDITIONAL_MAKE_CLEAN_FILES`_ 中。即执行 ``make clean`` 后会删除该库。请注意,构建系统中的其他目标文件不会被删除。 + +.. note:: 当外部构建系统使用 PSRAM 时,请记得将 ``-mfix-esp32-psram-cache-issue`` 添加到 C 编译器的参数中。关于该标志的更多详细信息,请参考 :ref:`CONFIG_SPIRAM_CACHE_WORKAROUND`。 + +.. _ADDITIONAL_MAKE_CLEAN_FILES_note: + +ExternalProject 的依赖与构建清理 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +对于外部项目的构建,CMake 会有一些不同寻常的行为: + +- `ADDITIONAL_MAKE_CLEAN_FILES`_ 仅在使用 Make 构建系统时有效。如果使用 Ninja_ 或 IDE 自带的构建系统,执行项目清理时,这些文件不会被删除。 +- ExternalProject_ 会在 clean 运行后自动重新运行配置和构建命令。 +- 可以采用以下两种方法来配置外部构建命令: + + 1. 将外部 ``BUILD_COMMAND`` 命令设置为对所有源代码完整的重新编译。如果传递给 ``externalproject_add`` 命令的 ``DEPENDS`` 的依赖项发生了改变,或者当前执行的是项目清理操作(即运行了 ``idf.py clean``、``ninja clean`` 或者 ``make clean``),那么就会执行该命令。 + 2. 将外部 ``BUILD_COMMAND`` 命令设置为增量式构建命令,并给 ``externalproject_add`` 传递 ``BUILD_ALWAYS 1`` 参数。即不管实际的依赖情况,每次构建时,都会构建外部项目。这种方式仅当外部构建系统具备增量式构建的能力,且运行时间不会很长时才推荐。 + +构建外部项目的最佳方法取决于项目本身、其构建系统,以及是否需要频繁重新编译项目。 .. _custom-sdkconfig-defaults: 自定义 sdkconfig 的默认值 -~~~~~~~~~~~~~~~~~~~~~~~~~ +========================= -对于示例工程或者其他您不想指定完整 sdkconfig 配置的项目,但是您确实希望覆盖 ESP-IDF 默认值中的某些键值,则可以在项目中创建文件 ``sdkconfig.defaults``,运行 ``make defconfig`` 或从头创建新配置时将会使用此文件。 +对于示例工程或者其他您不想指定完整 sdkconfig 配置的项目,但是您确实希望覆盖 ESP-IDF 默认值中的某些键值,则可以在项目中创建 ``sdkconfig.defaults`` 文件。重新创建新配置时将会用到此文件,另外在 ``sdkconfig`` 没有设置新配置值时,上述文件也会被用到。 -要想覆盖此文件的名称,请设置 ``SDKCONFIG_DEFAULTS`` 环境变量。 +如若需要覆盖此文件的名称,请设置 ``SDKCONFIG_DEFAULTS`` 环境变量。 -保存 flash 参数 -~~~~~~~~~~~~~~~ +依赖于硬件目标的 sdkconfig 默认值 +--------------------------------- -在某些情况下,我们希望在没有 IDF 的情况下烧写目标板卡,对于这种情况,我们希望保存构建的二进制文件、esptool.py 和 esptool write_flash 命令的参数。可以简单编写一段脚本来保存二进制文件和 esptool.py,并且使用命令 ``make print_flash_cmd`` 来查看烧写 flash 时的参数。 +除了 ``sdkconfig.defaults`` 之外,构建系统还将从 ``sdkconfig.defaults.TARGET_NAME`` 文件加载默认值,其中 ``IDF_TARGET`` 的值为 ``TARGET_NAME``。例如,对于 ``ESP32`` 这个硬件目标,sdkconfig 的默认值会首先从 ``sdkconfig.defaults`` 获取,然后再从 ``sdkconfig.defaults.esp32`` 获取。 -.. code:: bash +如果使用 ``SDKCONFIG_DEFAULTS`` 覆盖了 sdkconfig 默认文件的名称,则硬件目标的 sdkconfig 默认文件名也会从 ``SDKCONFIG_DEFAULTS`` 值中派生。 - --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 bootloader/bootloader.bin 0x10000 example_app.bin 0x8000 partition_table_unit_test_app.bin +.. _flash_parameters: -然后使用这段 flash 参数作为 esptool write_flash 命令的参数: +Flash 参数 +========== -.. code:: bash +有些情况下,我们希望在没有 IDF 时也能烧写目标板卡,为此,我们希望可以保存已构建的二进制文件、esptool.py 和 esptool write_flash 命令的参数。可以通过编写一段简单的脚本来保存二进制文件和 esptool.py。 - python esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 bootloader/bootloader.bin 0x10000 example_app.bin 0x8000 partition_table_unit_test_app.bin +运行项目构建之后,构建目录将包含项目二进制输出文件(``.bin`` 文件),同时也包含以下烧录数据文件: + +- ``flash_project_args`` 包含烧录整个项目的参数,包括应用程序 (app)、引导程序 (bootloader)、分区表,如果设置了 PHY 数据,也会包含此数据。 +- ``flash_app_args`` 只包含烧录应用程序的参数。 +- ``flash_bootloader_args`` 只包含烧录引导程序的参数。 + +.. highlight:: bash + +您可以参照如下命令将任意烧录参数文件传递给 ``esptool.py``:: + + python esptool.py --chip esp32 write_flash @build/flash_project_args + +也可以手动复制参数文件中的数据到命令行中执行。 + +构建目录中还包含生成的 ``flasher_args.json`` 文件,此文件包含 JSON 格式的项目烧录信息,可用于 ``idf.py`` 和其它需要项目构建信息的工具。 构建 Bootloader +=============== + +引导程序默认作为 ``idf.py build`` 的一部分被构建,也可以通过 ``idf.py bootloader`` 来单独构建。 + +引导程序是 :idf:`/components/bootloader/subproject` 内部独特的“子项目”,它有自己的项目 CMakeLists.txt 文件,能够构建独立于主项目的 ``.ELF`` 和 ``.BIN`` 文件,同时它又与主项目共享配置和构建目录。 + +子项目通过 :idf_file:`/components/bootloader/project_include.cmake` 文件作为外部项目插入到项目的顶层,主构建进程会运行子项目的 CMake,包括查找组件(主项目使用的组件的子集),生成引导程序专用的配置文件(从主 ``sdkconfig`` 文件中派生)。 + +选择硬件目标 +============ + +当前 ESP-IDF 仅支持一个硬件目标,即 ``esp32``,这也是构建系统默认的硬件目标。开发人员可以按照如下方法来添加对新硬件目标的支持:: + + rm sdkconfig + idf.py -DIDF_TARGET=new_target reconfigure + +.. _write-pure-component: + +编写纯 CMake 组件 +================= + +ESP-IDF 构建系统用“组件”的概念“封装”了 CMake,并提供了很多帮助函数来自动将这些组件集成到项目构建当中。 + +然而,“组件”概念的背后是一个完整的 CMake 构建系统,因此可以制作纯 CMake 组件。 + +.. highlight:: cmake + +下面是使用纯 CMake 语法为 ``json`` 组件编写的最小 CMakeLists 文件的示例:: + + add_library(json STATIC + cJSON/cJSON.c + cJSON/cJSON_Utils.c) + + target_include_directories(json PUBLIC cJSON) + +- 这实际上与 IDF 中的 :idf_file:`json 组件 ` 是等效的。 +- 因为组件中的源文件不多,所以这个 CMakeLists 文件非常简单。对于具有大量源文件的组件而言,ESP-IDF 支持的组件通配符,可以简化组件 CMakeLists 的样式。 +- 每当组件中新增一个与组件同名的库目标时,ESP-IDF 构建系统会自动将其添加到构建中,并公开公共的 include 目录。如果组件想要添加一个与组件不同名的库目标,就需要使用 CMake 命令手动添加依赖关系。 + +组件中使用第三方 CMake 项目 +=========================== + +CMake 在许多开源的 C/C++ 项目中广泛使用,用户可以在自己的应用程序中使用开源代码。CMake 构建系统的一大好处就是可以导入这些第三方的项目,有时候甚至不用做任何改动。这就允许用户使用当前 ESP-IDF 组件尚未提供的功能,或者使用其它库来实现相同的功能。 + +.. highlight:: cmake + +假设 ``main`` 组件需要导入一个假想库 ``foo``,相应的组件 CMakeLists 文件如下所示:: + + # 注册组件 + register_component() + + # 设置 `foo` 项目中的一些 CMake 变量,以控制 `foo` 的构建过程 + set(FOO_BUILD_STATIC OFF) + set(FOO_BUILD_TESTS OFF) + + # 创建并导入第三方库目标 + add_subdirectory(foo) + + # 将 IDF 全局的编译器设置、宏定义及其它选项传递给 `foo` 目标 + target_include_directories(foo ${IDF_INCLUDE_DIRECTORIES}) + target_compile_options(foo ${IDF_COMPILE_OPTIONS}) + target_compile_definitions(foo ${IDF_COMPILE_DEFINITIONS}) + + # 将 `foo` 目标链接至 `main` 组件 + target_link_libraries(main foo) + +实际的案例请参考 :example:`build_system/cmake/import_lib`。请注意,导入第三方库所需要做的工作可能会因库的不同而有所差异。建议仔细阅读第三方库的文档,了解如何将其导入到其它项目中。阅读第三方库的 CMakeLists.txt 文件以及构建结构也会有所帮助。 + +用这种方式还可以将第三方库封装成 ESP-IDF 的组件。例如 :component:`mbedtls` 组件就是封装了 `mbedtls 项目 `_ 得到的。详情请参考 :component_file:`mbedtls 组件的 CMakeLists.txt 文件 `。 + +每当使用 ESP-IDF 构建系统时,CMake 变量 ``ESP_PLATFORM`` 都会被设置为 1。如果要在通用的 CMake 代码加入 IDF 特定的代码时,可以采用 ``if (ESP_PLATFORM)`` 的形式加以分隔。 + +在自定义 CMake 项目中使用 ESP-IDF +================================= + +ESP-IDF 提供了一个模板 CMake 项目,可以基于此轻松创建应用程序。然而在有些情况下,用户可能已有一个现成的 CMake 项目,或者想自己创建一个 CMake 项目,此时就希望将 IDF 中的组件以库的形式链接到用户目标(库/可执行文件)。 + +.. highlight:: cmake + +使用 :idf_file:`tools/cmake/idf_functions.cmake` 中提供的 ``idf_import_components`` 和 ``idf_link_components`` 函数可以实现上述功能,例如:: + + cmake_minimum_required(VERSION 3.5) + project(my_custom_app C) + + # 源文件 main.c 包含有 app_main() 函数的定义 + add_executable(${CMAKE_PROJECT_NAME}.elf main.c) + + # 提供 idf_import_components 及 idf_link_components 函数 + include($ENV{IDF_PATH}/tools/cmake/idf_functions.cmake) + + # 为 idf_import_components 做一些配置 + # 使能创建构件(不是每个项目都必须) + set(IDF_BUILD_ARTIFACTS ON) + set(IDF_PROJECT_EXECUTABLE ${CMAKE_PROJECT_NAME}.elf) + set(IDF_BUILD_ARTIFACTS_DIR ${CMAKE_BINARY_DIR}) + + # idf_import_components 封装了 add_subdirectory(),为组件创建库目标,然后使用给定的变量接收“返回”的库目标。 + # 在本例中,返回的库目标被保存在“component”变量中。 + idf_import_components(components $ENV{IDF_PATH} esp-idf) + + # idf_link_components 封装了 target_link_libraries(),将被 idf_import_components 处理过的组件链接到目标 + idf_link_components(${CMAKE_PROJECT_NAME}.elf "${components}") + +上述代码片段导入了 ESP-IDF 目录下的所有组件,并使用了 KConfig 中的默认值,同时还允许创建其它一些构件(比如分区表、包含项目信息的 json 文件、引导程序等)。除此以外,用户还可以设置其它的构建参数,其完整列表如下: + +- ``IDF_BUILD_ARTIFACTS``:构建工件,例如引导加载程序、分区表二进制文件、分区二进制数据、将二进制文件烧录到目标芯片时所需的包含项目信息的 json 文件等。同时需要设置 ``IDF_PROJECT_EXECUTABLE`` 和 ``IDF_BUILD_ARTIFACTS_DIR`` 变量。 +- ``IDF_PROJECT_EXECUTABLE``:最终可执行文件的名称。某些工件在创建的时候需要此参数。 +- ``IDF_BUILD_ARTIFACTS_DIR``:创建的构件被存放的位置。 +- ``IDF_EXTRA_COMPONENTS_DIR``:在 :idf:`默认组件目录 ` 之外的组件搜索路径。 +- ``IDF_COMPONENTS``:要导入的组件列表,设置此变量可以精简导入的组件,仅导入需要的组件,加快构建的速度。如果没有设置该变量,将会导入默认组件目录以及 ``IDF_EXTRA_COMPONENTS_DIR`` (如果设置了该变量)中找到的所有组件。请注意,该列表中组件的依赖组件(除了 ``IDF_COMPONENT_REQUIRES_COMMON`` 之外)也会被加入到构建之中。 +- ``IDF_COMPONENT_REQUIRES_COMMON``:通用组件依赖列表。无论 ``IDF_COMPONENTS`` 的值是什么,此列表中的组件及其依赖组件都会被导入到构建中。默认情况下,此变量被设置为核心“系统”组件的最小集合。 +- ``IDF_SDKCONFIG_DEFAULTS``:配置文件的覆盖路径,如果未设置,组件将会使用默认的配置选项来构建。 +- ``IDF_BUILD_TESTS``:在构建中包含组件的测试。默认情况下,所有的组件测试都会被包含。组件测试可通过 ``IDF_TEST_COMPONENTS`` 和 ``IDF_TEST_EXCLUDE_COMPONENTS`` 进行过滤。 +- ``IDF_TEST_COMPONENTS``:如果设置了 ``IDF_BUILD_TESTS``,构建中只会包含此列表中的组件测试。如果没有设置 ``IDF_BUILD_TESTS``,请忽略此项。 +- ``IDF_TEST_EXCLUDE_COMPONENTS``:如果设置了 ``IDF_BUILD_TESTS``,此列表中的组件测试将不会包含在构建中。如果没有设置 ``IDF_BUILD_TESTS``,请忽略此项。该变量的优先级高于 ``IDF_TEST_COMPONENTS``,这意味着,即使 ``IDF_TEST_COMPONENTS`` 中也存在此列表中的组件测试,它也不会被包含到构建之中。 + +:example:`build_system/cmake/idf_as_lib` 中的示例演示了如何在自定义的 CMake 项目创建一个类似于 :example:`Hello World ` 的应用程序。 + +.. _cmake-file-globbing: + +文件通配符 & 增量构建 +===================== + +.. highlight:: cmake + +在 ESP-IDF 组件中添加源文件的首选方法是在 ``COMPONENT_SRCS`` 中手动列出它们:: + + set(COMPONENT_SRCS library/a.c library/b.c platform/platform.c) + +这是在 CMake 中手动列出源文件的 `最佳实践 `_。然而,当有许多源文件都需要添加到构建中时,这种方法就会很不方便。ESP-IDF 构建系统因此提供了另一种替代方法,即使用 ``COMPONENT_SRCDIRS`` 来指定源文件:: + + set(COMPONENT_SRCDIRS library platform) + +后台会使用通配符在指定的目录中查找源文件。但是请注意,在使用这种方法的时候,如果组件中添加了一个新的源文件,CMake 并不知道重新运行配置,最终该文件也没有被加入构建中。 + +如果是自己添加的源文件,这种折衷还是可以接受的,因为用户可以触发一次干净的构建,或者运行 ``idf.py reconfigure`` 来手动重启 CMake_。但是,如果你需要与其他使用 Git 等版本控制工具的开发人员共享项目时,问题就会变得更加困难,因为开发人员有可能会拉取新的版本。 + +ESP-IDF 中的组件使用了第三方的 Git CMake 集成模块(:idf_file:`/tools/cmake/third_party/GetGitRevisionDescription.cmake`),任何时候源码仓库的提交记录发生了改变,该模块就会自动重新运行 CMake。即只要 拉取了新的 ESP-IDF 版本,CMake 就会重新运行。 + +对于不属于 ESP-IDF 的项目组件,有以下几个选项供参考: + +- 如果项目文件保存在 Git 中,ESP-IDF 会自动跟踪 Git 修订版本,并在它发生变化时重新运行 CMake。 +- 如果一些组件保存在第三方 Git 仓库中(不在项目仓库或 ESP-IDF 仓库),则可以在组件 CMakeLists 文件中调用 ``git_describe`` 函数,以便在 Git 修订版本发生变化时自动重启 CMake。 +- 如果没有使用 Git,请记住在源文件发生变化时手动运行 ``idf.py reconfigure``。 +- 使用 ``COMPONENT_SRCS`` 在项目组件中列出所有源文件,可以完全避免这一问题。 + +具体选择哪一方式,就要取决于项目本身,以及项目用户。 + +.. _build_system_metadata: + +构建系统的元数据 +================ + +为了将 ESP-IDF 集成到 IDE 或者其它构建系统中,CMake 在构建的过程中会在 ``build/`` 目录下生成大量元数据文件。运行 ``cmake`` 或 ``idf.py reconfigure`` (或任何其它 ``idf.py`` 构建命令),可以重新生成这些元数据文件。 + +- ``compile_commands.json`` 是标准格式的 JSON 文件,它描述了在项目中参与编译的每个源文件。CMake 其中的一个功能就是生成此文件,许多 IDE 都知道如何解析此文件。 +- ``project_description.json`` 包含有关 ESP-IDF 项目、已配置路径等的一些常规信息。 +- ``flasher_args.json`` 包含 esptool.py 工具用于烧录项目二进制文件的参数,此外还有 ``flash_*_args`` 文件,可直接与 esptool.py 一起使用。更多详细信息请参阅 :ref:`flash_parameters`。 +- ``CMakeCache.txt`` 是 CMake 的缓存文件,包含 CMake 进程、工具链等其它信息。 +- ``config/sdkconfig.json`` 包含 JSON 格式的项目配置结果。 +- ``config/kconfig_menus.json`` 是在 menuconfig 中显示菜单的 JSON 格式版本,用于外部 IDE 的 UI。 + +JSON 配置服务器 --------------- -引导程序默认作为 ``make all`` 的一部分被构建,或者也可以通过 ``make bootloader-clean`` 来单独构建,此外还可以通过 ``make bootloader-list-components`` 来查看构建引导程序时包含的组件。 +.. highlight :: json -引导程序是一个特殊的组件,因为主项目中的二级引导程序拥有单独的 .EFL 和 .BIN 文件。但是它与主项目共享配置和构建目录。 +``confserver.py`` 工具可以帮助 IDE 轻松地与配置系统的逻辑进行集成,它运行在后台,通过使用 stdin 和 stdout 读写 JSON 文件的方式与调用进程交互。 -这是通过在 components/bootloader/subproject 下添加子项目来完成的。这个子项目有自己的 Makefile,但它希望通过 components/bootloader/Makefile.projectbuild 文件中的一些配置使自己从主项目的 Makefile 被调用。有关详细信息,请参阅这些文件。 +您可以通过 ``idf.py confserver`` 或 ``ninja confserver`` 从项目中运行 ``confserver.py``,也可以使用不同的构建生成器来触发类似的目标。 + +配置服务器会向 stderr 输出方便阅读的错误和警告信息,向 stdout 输出 JSON 文件。启动时,配置服务器将以 JSON 字典的形式输出系统中每个配置项的完整值,以及范围受限的值的可用范围。``sdkconfig.json`` 中包含有相同的信息:: + + {"version": 1, "values": { "ITEM": "value", "ITEM_2": 1024, "ITEM_3": false }, "ranges" : { "ITEM_2" : [ 0, 32768 ] } } + +配置服务器仅发送可见的配置项,其它不可见的或者被禁用的配置项可从 ``kconfig_menus.json`` 静态文件中解析得到,此文件还包含菜单结构和其它元数据(描述、类型、范围等)。 + +然后配置服务器将等待客户端的输入,客户端会发起请求,要求更改一个或多个配置项的值,内容的格式是个 JSON 对象,后面跟一个换行符:: + + {"version": "1", "set": {"SOME_NAME": false, "OTHER_NAME": true } } + +配置服务器将解析此请求,更新 ``sdkconfig`` 文件,并返回完整的变更列表:: + + {"version": 1, "values": {"SOME_NAME": false, "OTHER_NAME": true , "DEPENDS_ON_SOME_NAME": null}} + +当前不可见或者禁用的配置项会返回 ``null``,任何新的可见配置项则会返回其当前新的可见值。 + +如果配置项的取值范围因另一个值的变化发生了改变,那么配置服务器会发送:: + + {"version": 1, "values": {"OTHER_NAME": true }, "ranges" : { "HAS_RANGE" : [ 3, 4 ] } } + +如果传递的数据无效,那么 JSON 对象中会有 ``error`` 字段:: + + {"version": 1, "values": {}, "error": ["The following config symbol(s) were not visible so were not updated: NOT_VISIBLE_ITEM"]} + +默认情况下,变更后的配置不会被写进 sdkconfig 文件。更改的内容在发出 “save” 命令之前会先储存在内存中:: + + {"version": 1, "save": null } + +若要从已保存的文件中重新加载配置值,并丢弃内存中的任何更改,可以发送 “load” 命令:: + + {"version": 1, "load": null } + +“load” 和 “save” 的值可以是新的路径名,也可以设置为 "null" 用以加载/保存之前使用的路径名。 + +配置服务器对 “load” 命令的响应始终是完整的配置值和取值范围的集合,这与服务器初始启动阶段的响应相同。 + +“load”、“set” 和 “save” 的任意组合可以在一条单独的命令中发送出去,服务器按照组合中的顺序执行命令。因此,可以使用一条命令实现从文件中加载配置,更新配置值,然后将其保存到文件中。 + +.. Note:: 配置服务器不会自动加载外部对 ``sdkconfig`` 文件的任何更改。如果文件被外部编辑,则需要发送 “load” 命令或重启服务器。 + +.. Note:: ``sdkconfig`` 文件更新后,配置服务器不会重新运行 CMake 来生成其它的构建文件和元数据文件。这些文件会在下一次运行 ``CMake`` 或 ``idf.py`` 时自动生成。 + +.. _gnu-make-to: + +从 ESP-IDF GNU Make 构建系统迁移到 CMake 构建系统 +================================================= + +ESP-IDF CMake 构建系统与旧版的 GNU Make 构建系统在某些方面非常相似,例如将 ``component.mk`` 文件改写 ``CMakeLists.txt``,像 ``COMPONENT_ADD_INCLUDEDIRS`` 和 ``COMPONENT_SRCDIRS`` 等变量可以保持不变,只需将语法改为 CMake 语法即可。 + +自动转换工具 +------------ + +.. highlight:: bash + +:idf_file:`/tools/cmake/convert_to_cmake.py` 中提供了一个项目自动转换工具。运行此命令时需要加上项目路径,如下所示:: + + $IDF_PATH/tools/cmake/convert_to_cmake.py /path/to/project_dir + +项目目录必须包含 Makefile 文件,并确保主机已安装 GNU Make (``make``) 工具,并且被添加到了 PATH 环境变量中。 + +该工具会将项目 Makefile 文件和所有组件的 ``component.mk`` 文件转换为对应的 ``CMakeLists.txt`` 文件。 + +转换过程如下:该工具首先运行 ``make`` 来展开 ESP-IDF 构建系统设置的变量,然后创建相应的 CMakelists 文件来设置相同的变量。 + +转换工具并不能处理复杂的 Makefile 逻辑或异常的目标,这些需要手动转换。 + +CMake 中不可用的功能 +-------------------- + +有些功能已从 CMake 构建系统中移除,或者已经发生很大改变。GNU Make 构建系统中的以下变量已从 CMake 构建系统中删除: + +- ``COMPONENT_BUILD_DIR``:由 ``CMAKE_CURRENT_BINARY_DIR`` 替代。 +- ``COMPONENT_LIBRARY``:默认为 ``$(COMPONENT_NAME).a`` 但是库名可以被组件覆盖。在 CMake 构建系统中,组件库名称不可再被组件覆盖。 +- ``CC``、``LD``、``AR``、``OBJCOPY``:gcc xtensa 交叉工具链中每个工具的完整路径。CMake 使用 ``CMAKE_C_COMPILER``、``CMAKE_C_LINK_EXECUTABLE`` 和 ``CMAKE_OBJCOPY`` 进行替代。完整列表请参阅 `CMake 语言变量 `_。 +- ``HOSTCC``、``HOSTLD``、``HOSTAR``:宿主机本地工具链中每个工具的全名。CMake 系统不再提供此变量,外部项目需要手动检测所需的宿主机工具链。 +- ``COMPONENT_ADD_LDFLAGS``:用于覆盖链接标志。CMake 中使用 `target_link_libraries`_ 命令替代。 +- ``COMPONENT_ADD_LINKER_DEPS``:链接过程依赖的文件列表。`target_link_libraries`_ 通常会自动推断这些依赖。对于链接脚本,可以使用自定义的 CMake 函数 ``target_linker_scripts``。 +- ``COMPONENT_SUBMODULES``:不再使用。CMake 会自动枚举 ESP-IDF 仓库中所有的子模块。 +- ``COMPONENT_EXTRA_INCLUDES``:曾是 ``COMPONENT_PRIV_INCLUDEDIRS`` 变量的替代版本,仅支持绝对路径。CMake 系统中统一使用 ``COMPONENT_PRIV_INCLUDEDIRS`` (可以是相对路径,也可以是绝对路径)。 +- ``COMPONENT_OBJS``:以前,可以以目标文件列表的方式指定组件源,现在,可以通过 ``COMPONENT_SRCS`` 以源文件列表的形式指定组件源。 +- ``COMPONENT_OBJEXCLUDE``:已被 ``COMPONENT_SRCEXCLUDE`` 替换。用于指定源文件(绝对路径或组件目录的相对路径)。 +- ``COMPONENT_EXTRA_CLEAN``:已被 ``ADDITIONAL_MAKE_CLEAN_FILES`` 属性取代,注意,:ref:`CMake 对此项功能有部分限制 `。 +- ``COMPONENT_OWNBUILDTARGET`` & ``COMPONENT_OWNCLEANTARGET``:已被 CMake `外部项目 `_ 替代,详细内容请参阅 :ref:`component-build-full-override`。 +- ``COMPONENT_CONFIG_ONLY``:已被 ``register_config_only_component()`` 函数替代,请参阅 :ref:`config_only_component`。 +- ``CFLAGS``、``CPPFLAGS``、``CXXFLAGS``:已被相应的 CMake 命令替代,请参阅 :ref:`component_build_control`。 + +无默认值的变量 +-------------- + +以下变量不再具有默认值: + +- ``COMPONENT_SRCDIRS`` +- ``COMPONENT_ADD_INCLUDEDIRS`` + +不再需要的变量 +-------------- + +如果设置了 ``COMPONENT_SRCS``,就不需要再设置 ``COMPONENT_SRCDIRS``。实际上,CMake 构建系统中如果设置了 ``COMPONENT_SRCDIRS``,那么 ``COMPONENT_SRCS`` 就会被忽略。 + +从 Make 中烧录 +-------------- + +仍然可以使用 ``make flash`` 或者类似的目标来构建和烧录,但是项目 ``sdkconfig`` 不能再用来指定串口和波特率。可以使用环境变量来覆盖串口和波特率的设置,详情请参阅 :ref:`flash-with-ninja-or-make`。 + +.. _esp-idf-template: https://github.com/espressif/esp-idf-template +.. _Cmake: https://cmake.org +.. _ninja: https://ninja-build.org +.. _esptool.py: https://github.com/espressif/esptool/#readme +.. _CMake v3.5 官方文档: https://cmake.org/cmake/help/v3.5/index.html +.. _cmake 命令行文档: https://cmake.org/cmake/help/v3.5/manual/cmake.1.html#options +.. _cmake add_library: https://cmake.org/cmake/help/v3.5/command/add_library.html +.. _cmake if: https://cmake.org/cmake/help/v3.5/command/if.html +.. _cmake list: https://cmake.org/cmake/help/v3.5/command/list.html +.. _cmake project: https://cmake.org/cmake/help/v3.5/command/project.html +.. _cmake set: https://cmake.org/cmake/help/v3.5/command/set.html +.. _cmake string: https://cmake.org/cmake/help/v3.5/command/string.html +.. _cmake faq generated files: https://cmake.org/Wiki/CMake_FAQ#How_can_I_generate_a_source_file_during_the_build.3F +.. _ADDITIONAL_MAKE_CLEAN_FILES: https://cmake.org/cmake/help/v3.5/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.html +.. _ExternalProject: https://cmake.org/cmake/help/v3.5/module/ExternalProject.html +.. _cmake language variables: https://cmake.org/cmake/help/v3.5/manual/cmake-variables.7.html#variables-for-languages +.. _set_source_files_properties: https://cmake.org/cmake/help/v3.5/command/set_source_files_properties.html +.. _target_compile_options: https://cmake.org/cmake/help/v3.5/command/target_compile_options.html +.. _target_link_libraries: https://cmake.org/cmake/help/v3.5/command/target_link_libraries.html#command:target_link_libraries +.. _cmake_toolchain_file: https://cmake.org/cmake/help/v3.5/variable/CMAKE_TOOLCHAIN_FILE.html +.. _quirc: https://github.com/dlbeer/quirc +.. _pyenv: https://github.com/pyenv/pyenv#README +.. _virtualenv: https://virtualenv.pypa.io/en/stable/ diff --git a/docs/zh_CN/api-guides/index.rst b/docs/zh_CN/api-guides/index.rst index a454616787..03163469a2 100644 --- a/docs/zh_CN/api-guides/index.rst +++ b/docs/zh_CN/api-guides/index.rst @@ -7,7 +7,7 @@ API 指南 一般注意事项 构建系统 - 构建系统 (CMake) + 构建系统 (传统 GNU Make) 错误处理 严重错误 Event Handling @@ -21,10 +21,10 @@ API 指南 Bootloader 分区表 Secure Boot <../security/secure-boot> - ULP Coprocessor - ULP 协处理器 (CMake) + ULP 协处理器 + ULP ( CMake) 单元测试 - 单元测试 (CMake) + 单元测试 (传统 GNU Make) 应用层跟踪 控制台终端组件 ROM debug console diff --git a/docs/zh_CN/api-guides/jtag-debugging/index.rst b/docs/zh_CN/api-guides/jtag-debugging/index.rst index 32823497f3..8d525a77ca 100644 --- a/docs/zh_CN/api-guides/jtag-debugging/index.rst +++ b/docs/zh_CN/api-guides/jtag-debugging/index.rst @@ -194,7 +194,7 @@ JTAG 正常工作至少需要连接的信号线有:TDI,TDO,TCK,TMS 和 G 上传待调试的应用程序 ~~~~~~~~~~~~~~~~~~~~ -您可以像往常一样构建并上传 ESP32 应用程序,具体请参阅 :ref:`get-started-build-and-flash` 章节。 +您可以像往常一样构建并上传 ESP32 应用程序,具体请参阅 :ref:`get-started-build` 章节。 除此以外,还支持使用 OpenOCD 通过 JTAG 接口将应用程序镜像烧写到闪存中,命令如下:: diff --git a/docs/zh_CN/api-guides/jtag-debugging/setup-openocd-windows.rst b/docs/zh_CN/api-guides/jtag-debugging/setup-openocd-windows.rst index 740af5b5e6..6cd2e508c2 100644 --- a/docs/zh_CN/api-guides/jtag-debugging/setup-openocd-windows.rst +++ b/docs/zh_CN/api-guides/jtag-debugging/setup-openocd-windows.rst @@ -6,7 +6,7 @@ IDF 工具安装程序 ================ -如果您正在使用 CMake 构建系统,并遵循 :doc:`/get-started-cmake/windows-setup` 章节的指导使用了 ``ESP-IDF Tools Installer`` 的 V1.2 及其以上版本,那么默认情况下您已经安装好了 ``OpenOCD`` 软件。 +如果您正在使用 CMake 构建系统,并遵循 :doc:`/get-started/windows-setup` 章节的指导使用了 ``ESP-IDF Tools Installer`` 的 V1.2 及其以上版本,那么默认情况下您已经安装好了 ``OpenOCD`` 软件。 ``ESP-IDF Tools Installer`` 会将 ``OpenOCD`` 添加到环境变量 ``PATH`` 中,这样你就可以在任何目录运行它。 diff --git a/docs/zh_CN/api-guides/ulp-cmake.rst b/docs/zh_CN/api-guides/ulp-cmake.rst deleted file mode 100644 index 3450425884..0000000000 --- a/docs/zh_CN/api-guides/ulp-cmake.rst +++ /dev/null @@ -1,167 +0,0 @@ -ULP 协处理器编程 (CMake) -=================================== - -:link_to_translation:`en:[English]` - -.. toctree:: - :maxdepth: 1 - - 指令集参考 - 使用宏进行编程(遗留) - - -ULP(Ultra Low Power 超低功耗)协处理器是一种简单的有限状态机 (FSM),可以在主处理器处于深度睡眠模式时,使用 ADC、温度传感器和外部 I2C 传感器执行测量操作。ULP 协处理器可以访问 RTC_SLOW_MEM 内存区域及 RTC_CNTL、RTC_IO、SARADC 等外设寄存器。ULP 协处理器使用 32 位固定宽度的指令,32 位内存寻址,配备 4 个 16 位通用寄存器。 - -安装工具链 ------------------------- - -ULP 协处理器代码是用汇编语言编写的,并使用 `binutils-esp32ulp 工具链`_ 进行编译。 - -1. 从提供的网址中下载最新工具链的预编译二进制文件:https://github.com/espressif/binutils-esp32ulp/releases. - -2. 将工具链解压缩到一个目录中,并将工具链的 ``bin/`` 目录路径添加到 ``PATH`` 环境变量中。 - -编译 ULP 代码 ------------------- - -若需要将 ULP 代码编译为某组件的一部分,则必须执行以下步骤: - -1. 用汇编语言编写的 ULP 代码必须导入到一个或多个 .S 扩展文件中,且这些文件必须放在组件目录中一个独立的目录中,例如 `ulp/`。 - -.. note: - 该目录不要添加到 ``COMPONENT_SRCDIRS`` 环境变量中。因为 ESP-IDF 构建系统将基于文件扩展名编译在 ``COMPONENT_SRCDIRS`` 中搜索到的文件。对于 ``.S`` 文件,使用的是 ``xtensa-esp32-elf-as`` 汇编器。但这并不适用于 ULP 程序集文件,因此体现这种区别的最简单方法就是将 ULP 程序集文件放到单独的目录中。同样,ULP 程序集源文件也不应该添加到 ``COMPONENT_SRCS`` 中。请参考如下步骤,查看如何正确添加 ULP 程序集源文件。 - -2. 修改组件 CMakeLists.txt,添加必要的 ULP CMake 定义,示例如下:: - - set(ULP_APP_NAME ulp_${COMPONENT_NAME}) - set(ULP_S_SOURCES ulp/ulp_assembly_source_file.S) - set(ULP_EXP_DEP_SRCS "ulp_c_source_file.c") - include(${IDF_PATH}/components/ulp/component_ulp_common.cmake) - -代码解释如下: - -``set(ULP_APP_NAME ulp_${COMPONENT_NAME})`` - 为生成的 ULP 应用程序设置名称,不带扩展名。此名称用于 ULP 应用程序的构建输出:ELF 文件、.map 文件、二进制文件、生成的头文件和链接器导出文件。 - -``set(ULP_S_SOURCES "ulp/ulp_assembly_source_file_1.S ulp/ulp_assembly_source_file_2.S")`` - 设置要传递给 ULP 汇编器的程序集文件列表,用空格隔开,路径可以是绝对路径,也可以是组件 CMakeLists.txt 的相对路径。 - -``set(ULP_EXP_DEP_SRCS "ulp_c_source_file_1.c ulp_c_source_file_2.c")`` - 设置组件中源文件名称的列表。所有包含被生成的头文件的原文件都必须在列表里。此列表建立正确构建依赖项,并确保在构建过程会先生成才编译包含头文件的原文件。请参考下文,查看为 ULP 应用程序生成的头文件等相关概念。此列表需要用空格隔开,路径可以是组件 CMakeLists.txt 文件的相对路径,也可以是绝对路径。 - -``include(${IDF_PATH}/components/ulp/component_ulp_common.cmake)`` - 包含 ULP 编译步骤的通用定义。使用 ULP 工具链为 ULP 目标文件、ELF 文件、二进制文件等设置编译规则。 - -3. 使用常规方法(例如 `idf.py app`)编译应用程序 - - 在内部,编译系统将按照以下步骤编译 ULP 程序: - - 1. **通过 C 预处理器运行每个程序集文件 (foo.S)。** 此步骤在组件编译目录中生成预处理的程序集文件 (foo.ulp.S),同时生成依赖文件 (foo.ulp.d)。 - - 2. **通过汇编器运行预处理过的汇编源码。** 此步骤会生成目标文件 (foo.ulp.o) 和清单 (foo.ulp.lst)。清单文件仅用于调试,不用于编译进程的后续步骤。 - - 3. **通过 C 预处理器运行链接器脚本模板。** 模板位于 components/ulp/ld 目录中。 - - 4. **将目标文件链接到 ELF 输出文件** (ulp_app_name.elf)。此步骤生成的.map 文件 (ulp_app_name.map) 默认用于调试。 - - 5. **将 ELF 文件中的内容转储为二进制文件** (ulp_app_name.bin),以便嵌入到应用程序中。 - - 6. **使用 esp32ulp-elf-nm 在 ELF 文件中生成全局符号列表** (ulp_app_name.sym)。 - - 7. **创建 LD 导出脚本和头文件** (ulp_app_name.ld 和 ulp_app_name.h),包含来自 ulp_app_name.sym 的符号。此步骤可借助 esp32ulp_mapgen.py 工具来完成。 - - 8. **将生成的二进制文件添加到要嵌入应用程序的二进制文件列表中。** - -访问 ULP 程序变量 -------------------------------- - -在 ULP 程序中定义的全局符号也可以在主程序中使用。 - -例如,ULP 程序可以定义 ``measurement_count`` 变量,此变量可以定义程序从深度睡眠中唤醒芯片之前需要进行的 ADC 测量的次数:: - - .global measurement_count - measurement_count: .long 0 - - /* later, use measurement_count */ - move r3, measurement_count - ld r3, r3, 0 - -主程序需要在启动 ULP 程序之前初始化 ``measurement_count`` 变量,编译系统生成 ``${ULP_APP_NAME}.h`` 和 ``${ULP_APP_NAME}.ld`` 文件可以实现上述操作,这些文件在 ULP 编程中定义了全局符号,包含了在 ULP 程序中定义的所有全局符号,前缀为 ``ulp_``。 - -头文件包含对此类符号的声明:: - - extern uint32_t ulp_measurement_count; - -注意,所有符号(包括变量、数组、函数)均被声明为 ``uint32_t``。对于函数和数组,先获取符号地址,然后转换为适当的类型。 - -生成的链接器脚本文件定义了 RTC_SLOW_MEM 中的符号位置:: - - PROVIDE ( ulp_measurement_count = 0x50000060 ); - -如果要从主程序访问 ULP 程序变量,先包含生成的头文件,并使用上述变量,操作如下:: - - #include "ulp_app_name.h" - - // later - void init_ulp_vars() { - ulp_measurement_count = 64; - } - -注意,ULP 程序在 RTC 内存中只能使用 32 位字的低 16 位,因为寄存器是 16 位的,并且不具备从字的高位加载的指令。 - -同样,ULP 储存指令将寄存器值写入 32 位字的低 16 位中。高 16 位写入的值取决于储存指令的地址,因此在读取 ULP 写的变量时,主应用程序需要屏蔽高 16 位,例如:: - - printf("Last measurement value: %d\n", ulp_last_measurement & UINT16_MAX); - -启动 ULP 程序 ------------------------- - -要运行 ULP 程序,主应用程序需要调用 ``ulp_load_binary`` 函数将 ULP 程序加载到 RTC 内存中,然后调用 ``ulp_run`` 函数,启动 ULP 程序。 - -注意,在 menuconfig 中必须启用 "Enable Ultra Low Power (ULP) Coprocessor" 选项,以便为 ULP 预留内存。"RTC slow memory reserved for coprocessor" 选项设置的值必须足够储存 ULP 代码和数据。如果应用程序组件包含多个 ULP 程序,则 RTC 内存必须足以容纳最大的程序。 - -每个 ULP 程序均以二进制 BLOB 的形式嵌入到 ESP-IDF 应用程序中。应用程序可以引用此 BLOB,并以下面的方式加载此 BLOB (假设 ULP_APP_NAME 已被定义为 ``ulp_app_name``):: - - extern const uint8_t bin_start[] asm("_binary_ulp_app_name_bin_start"); - extern const uint8_t bin_end[] asm("_binary_ulp_app_name_bin_end"); - - void start_ulp_program() { - ESP_ERROR_CHECK( ulp_load_binary( - 0 /* load address, set to 0 when using default linker scripts */, - bin_start, - (bin_end - bin_start) / sizeof(uint32_t)) ); - } - -.. doxygenfunction:: ulp_load_binary - -一旦上述程序加载到 RTC 内存后,应用程序即可启动此程序,并将入口点的地址传递给 ``ulp_run`` 函数:: - - ESP_ERROR_CHECK( ulp_run(&ulp_entry - RTC_SLOW_MEM) ); - -.. doxygenfunction:: ulp_run - -上述生成的头文件 ``${ULP_APP_NAME}.h`` 声明了入口点符号。在 ULP 应用程序的汇编源代码中,此符号必须标记为 ``.global``:: - - - .global entry - entry: - /* code starts here */ - - -ULP 程序流 ----------------- - -ULP 协处理器由定时器启动,而调用 ``ulp_run`` 则可启动此定时器。定时器为 RTC_SLOW_CLK 的 Tick 事件计数(默认情况下,Tick 由内部 150 KHz 晶振器生成)。使用 ``SENS_ULP_CP_SLEEP_CYCx_REG`` 寄存器 (x = 0..4) 设置 Tick 数值。第一次启动 ULP 时,使用 ``SENS_ULP_CP_SLEEP_CYC0_REG`` 设置定时器 Tick 数值,之后,ULP 程序可以使用 ``sleep`` 指令来另外选择 ``SENS_ULP_CP_SLEEP_CYCx_REG`` 寄存器。 - -此应用程序可以调用 ``ulp_set_wakeup_period`` 函数来设置 ULP 定时器周期值 (SENS_ULP_CP_SLEEP_CYCx_REG, x = 0..4)。 - -.. doxygenfunction:: ulp_set_wakeup_period - -一旦定时器达到在所选的 ``SENS_ULP_CP_SLEEP_CYCx_REG`` 寄存器中设置的数值,ULP 协处理器就会启动,并调用 ``ulp_run`` 的入口点开始运行程序。 - -程序保持运行,直到遇到 ``halt`` 指令或非法指令。一旦程序停止,ULP 协处理器电源关闭,定时器再次启动。 - -如果想禁用定时器(有效防止 ULP 程序再次运行),请清除 ``RTC_CNTL_STATE0_REG`` 寄存器中的 ``RTC_CNTL_ULP_CP_SLP_TIMER_EN`` 位,可在 ULP 代码或主程序中进行以上操作。 - - -.. _binutils-esp32ulp 工具链: https://github.com/espressif/binutils-esp32ulp diff --git a/docs/zh_CN/api-guides/ulp-legacy.rst b/docs/zh_CN/api-guides/ulp-legacy.rst new file mode 100644 index 0000000000..976d6db286 --- /dev/null +++ b/docs/zh_CN/api-guides/ulp-legacy.rst @@ -0,0 +1 @@ +.. include:: ../../en/api-guides/ulp.rst \ No newline at end of file diff --git a/docs/zh_CN/api-guides/ulp.rst b/docs/zh_CN/api-guides/ulp.rst index 976d6db286..a6b8f9246d 100644 --- a/docs/zh_CN/api-guides/ulp.rst +++ b/docs/zh_CN/api-guides/ulp.rst @@ -1 +1,167 @@ -.. include:: ../../en/api-guides/ulp.rst \ No newline at end of file +ULP 协处理器编程 +=================================== + +:link_to_translation:`en:[English]` + +.. toctree:: + :maxdepth: 1 + + 指令集参考 + 使用宏进行编程(遗留) + + +ULP(Ultra Low Power 超低功耗)协处理器是一种简单的有限状态机 (FSM),可以在主处理器处于深度睡眠模式时,使用 ADC、温度传感器和外部 I2C 传感器执行测量操作。ULP 协处理器可以访问 RTC_SLOW_MEM 内存区域及 RTC_CNTL、RTC_IO、SARADC 等外设寄存器。ULP 协处理器使用 32 位固定宽度的指令,32 位内存寻址,配备 4 个 16 位通用寄存器。 + +安装工具链 +------------------------ + +ULP 协处理器代码是用汇编语言编写的,并使用 `binutils-esp32ulp 工具链`_ 进行编译。 + +1. 从提供的网址中下载最新工具链的预编译二进制文件:https://github.com/espressif/binutils-esp32ulp/releases. + +2. 将工具链解压缩到一个目录中,并将工具链的 ``bin/`` 目录路径添加到 ``PATH`` 环境变量中。 + +编译 ULP 代码 +------------------ + +若需要将 ULP 代码编译为某组件的一部分,则必须执行以下步骤: + +1. 用汇编语言编写的 ULP 代码必须导入到一个或多个 .S 扩展文件中,且这些文件必须放在组件目录中一个独立的目录中,例如 `ulp/`。 + +.. note: + 该目录不要添加到 ``COMPONENT_SRCDIRS`` 环境变量中。因为 ESP-IDF 构建系统将基于文件扩展名编译在 ``COMPONENT_SRCDIRS`` 中搜索到的文件。对于 ``.S`` 文件,使用的是 ``xtensa-esp32-elf-as`` 汇编器。但这并不适用于 ULP 程序集文件,因此体现这种区别的最简单方法就是将 ULP 程序集文件放到单独的目录中。同样,ULP 程序集源文件也不应该添加到 ``COMPONENT_SRCS`` 中。请参考如下步骤,查看如何正确添加 ULP 程序集源文件。 + +2. 修改组件 CMakeLists.txt,添加必要的 ULP CMake 定义,示例如下:: + + set(ULP_APP_NAME ulp_${COMPONENT_NAME}) + set(ULP_S_SOURCES ulp/ulp_assembly_source_file.S) + set(ULP_EXP_DEP_SRCS "ulp_c_source_file.c") + include(${IDF_PATH}/components/ulp/component_ulp_common.cmake) + +代码解释如下: + +``set(ULP_APP_NAME ulp_${COMPONENT_NAME})`` + 为生成的 ULP 应用程序设置名称,不带扩展名。此名称用于 ULP 应用程序的构建输出:ELF 文件、.map 文件、二进制文件、生成的头文件和链接器导出文件。 + +``set(ULP_S_SOURCES "ulp/ulp_assembly_source_file_1.S ulp/ulp_assembly_source_file_2.S")`` + 设置要传递给 ULP 汇编器的程序集文件列表,用空格隔开,路径可以是绝对路径,也可以是组件 CMakeLists.txt 的相对路径。 + +``set(ULP_EXP_DEP_SRCS "ulp_c_source_file_1.c ulp_c_source_file_2.c")`` + 设置组件中源文件名称的列表。所有包含被生成的头文件的原文件都必须在列表里。此列表建立正确构建依赖项,并确保在构建过程会先生成才编译包含头文件的原文件。请参考下文,查看为 ULP 应用程序生成的头文件等相关概念。此列表需要用空格隔开,路径可以是组件 CMakeLists.txt 文件的相对路径,也可以是绝对路径。 + +``include(${IDF_PATH}/components/ulp/component_ulp_common.cmake)`` + 包含 ULP 编译步骤的通用定义。使用 ULP 工具链为 ULP 目标文件、ELF 文件、二进制文件等设置编译规则。 + +3. 使用常规方法(例如 `idf.py app`)编译应用程序 + + 在内部,编译系统将按照以下步骤编译 ULP 程序: + + 1. **通过 C 预处理器运行每个程序集文件 (foo.S)。** 此步骤在组件编译目录中生成预处理的程序集文件 (foo.ulp.S),同时生成依赖文件 (foo.ulp.d)。 + + 2. **通过汇编器运行预处理过的汇编源码。** 此步骤会生成目标文件 (foo.ulp.o) 和清单 (foo.ulp.lst)。清单文件仅用于调试,不用于编译进程的后续步骤。 + + 3. **通过 C 预处理器运行链接器脚本模板。** 模板位于 components/ulp/ld 目录中。 + + 4. **将目标文件链接到 ELF 输出文件** (ulp_app_name.elf)。此步骤生成的.map 文件 (ulp_app_name.map) 默认用于调试。 + + 5. **将 ELF 文件中的内容转储为二进制文件** (ulp_app_name.bin),以便嵌入到应用程序中。 + + 6. **使用 esp32ulp-elf-nm 在 ELF 文件中生成全局符号列表** (ulp_app_name.sym)。 + + 7. **创建 LD 导出脚本和头文件** (ulp_app_name.ld 和 ulp_app_name.h),包含来自 ulp_app_name.sym 的符号。此步骤可借助 esp32ulp_mapgen.py 工具来完成。 + + 8. **将生成的二进制文件添加到要嵌入应用程序的二进制文件列表中。** + +访问 ULP 程序变量 +------------------------------- + +在 ULP 程序中定义的全局符号也可以在主程序中使用。 + +例如,ULP 程序可以定义 ``measurement_count`` 变量,此变量可以定义程序从深度睡眠中唤醒芯片之前需要进行的 ADC 测量的次数:: + + .global measurement_count + measurement_count: .long 0 + + /* later, use measurement_count */ + move r3, measurement_count + ld r3, r3, 0 + +主程序需要在启动 ULP 程序之前初始化 ``measurement_count`` 变量,编译系统生成 ``${ULP_APP_NAME}.h`` 和 ``${ULP_APP_NAME}.ld`` 文件可以实现上述操作,这些文件在 ULP 编程中定义了全局符号,包含了在 ULP 程序中定义的所有全局符号,前缀为 ``ulp_``。 + +头文件包含对此类符号的声明:: + + extern uint32_t ulp_measurement_count; + +注意,所有符号(包括变量、数组、函数)均被声明为 ``uint32_t``。对于函数和数组,先获取符号地址,然后转换为适当的类型。 + +生成的链接器脚本文件定义了 RTC_SLOW_MEM 中的符号位置:: + + PROVIDE ( ulp_measurement_count = 0x50000060 ); + +如果要从主程序访问 ULP 程序变量,先包含生成的头文件,并使用上述变量,操作如下:: + + #include "ulp_app_name.h" + + // later + void init_ulp_vars() { + ulp_measurement_count = 64; + } + +注意,ULP 程序在 RTC 内存中只能使用 32 位字的低 16 位,因为寄存器是 16 位的,并且不具备从字的高位加载的指令。 + +同样,ULP 储存指令将寄存器值写入 32 位字的低 16 位中。高 16 位写入的值取决于储存指令的地址,因此在读取 ULP 写的变量时,主应用程序需要屏蔽高 16 位,例如:: + + printf("Last measurement value: %d\n", ulp_last_measurement & UINT16_MAX); + +启动 ULP 程序 +------------------------ + +要运行 ULP 程序,主应用程序需要调用 ``ulp_load_binary`` 函数将 ULP 程序加载到 RTC 内存中,然后调用 ``ulp_run`` 函数,启动 ULP 程序。 + +注意,在 menuconfig 中必须启用 "Enable Ultra Low Power (ULP) Coprocessor" 选项,以便为 ULP 预留内存。"RTC slow memory reserved for coprocessor" 选项设置的值必须足够储存 ULP 代码和数据。如果应用程序组件包含多个 ULP 程序,则 RTC 内存必须足以容纳最大的程序。 + +每个 ULP 程序均以二进制 BLOB 的形式嵌入到 ESP-IDF 应用程序中。应用程序可以引用此 BLOB,并以下面的方式加载此 BLOB (假设 ULP_APP_NAME 已被定义为 ``ulp_app_name``):: + + extern const uint8_t bin_start[] asm("_binary_ulp_app_name_bin_start"); + extern const uint8_t bin_end[] asm("_binary_ulp_app_name_bin_end"); + + void start_ulp_program() { + ESP_ERROR_CHECK( ulp_load_binary( + 0 /* load address, set to 0 when using default linker scripts */, + bin_start, + (bin_end - bin_start) / sizeof(uint32_t)) ); + } + +.. doxygenfunction:: ulp_load_binary + +一旦上述程序加载到 RTC 内存后,应用程序即可启动此程序,并将入口点的地址传递给 ``ulp_run`` 函数:: + + ESP_ERROR_CHECK( ulp_run(&ulp_entry - RTC_SLOW_MEM) ); + +.. doxygenfunction:: ulp_run + +上述生成的头文件 ``${ULP_APP_NAME}.h`` 声明了入口点符号。在 ULP 应用程序的汇编源代码中,此符号必须标记为 ``.global``:: + + + .global entry + entry: + /* code starts here */ + + +ULP 程序流 +---------------- + +ULP 协处理器由定时器启动,而调用 ``ulp_run`` 则可启动此定时器。定时器为 RTC_SLOW_CLK 的 Tick 事件计数(默认情况下,Tick 由内部 150 KHz 晶振器生成)。使用 ``SENS_ULP_CP_SLEEP_CYCx_REG`` 寄存器 (x = 0..4) 设置 Tick 数值。第一次启动 ULP 时,使用 ``SENS_ULP_CP_SLEEP_CYC0_REG`` 设置定时器 Tick 数值,之后,ULP 程序可以使用 ``sleep`` 指令来另外选择 ``SENS_ULP_CP_SLEEP_CYCx_REG`` 寄存器。 + +此应用程序可以调用 ``ulp_set_wakeup_period`` 函数来设置 ULP 定时器周期值 (SENS_ULP_CP_SLEEP_CYCx_REG, x = 0..4)。 + +.. doxygenfunction:: ulp_set_wakeup_period + +一旦定时器达到在所选的 ``SENS_ULP_CP_SLEEP_CYCx_REG`` 寄存器中设置的数值,ULP 协处理器就会启动,并调用 ``ulp_run`` 的入口点开始运行程序。 + +程序保持运行,直到遇到 ``halt`` 指令或非法指令。一旦程序停止,ULP 协处理器电源关闭,定时器再次启动。 + +如果想禁用定时器(有效防止 ULP 程序再次运行),请清除 ``RTC_CNTL_STATE0_REG`` 寄存器中的 ``RTC_CNTL_ULP_CP_SLP_TIMER_EN`` 位,可在 ULP 代码或主程序中进行以上操作。 + + +.. _binutils-esp32ulp 工具链: https://github.com/espressif/binutils-esp32ulp diff --git a/docs/zh_CN/api-guides/unit-tests-cmake.rst b/docs/zh_CN/api-guides/unit-tests-legacy.rst similarity index 82% rename from docs/zh_CN/api-guides/unit-tests-cmake.rst rename to docs/zh_CN/api-guides/unit-tests-legacy.rst index 1f3453f994..82aba22581 100644 --- a/docs/zh_CN/api-guides/unit-tests-cmake.rst +++ b/docs/zh_CN/api-guides/unit-tests-legacy.rst @@ -1,7 +1,9 @@ -ESP32 中的单元测试 (CMake) -========================== +ESP32 中的单元测试 +================== :link_to_translation:`en:[English]` +.. include:: ../gnu-make-legacy.rst + ESP-IDF 中附带了一个基于 ``Unity`` 的单元测试应用程序框架,且所有的单元测试用例分别保存在 ESP-IDF 仓库中每个组件的 ``test`` 子目录中。 @@ -32,19 +34,12 @@ C 文件可以包含多个测试用例。测试文件的名字要以 “test” 来声明主函数的区域, ``unity_platform.c`` 会自动调用 ``UNITY_BEGIN()``\ , 然后运行测试用例,最后调用 ``UNITY_END()``\ 。 -``test`` 子目录需要包含 :ref:`组件 CMakeLists.txt `,因为他们本身就是一种组件。ESP-IDF 使用了 -``unity`` 测试框架,需要将其指定为组件的依赖项。通常,组件 -:ref:`需要手动指定待编译的源文件 `;但是,对于测试组件来说,这个要求被放宽了,仅仅是建议使用 “COMPONENT_SRCDIRS”。 +每一个测试子目录下都应该包含一个 +``component.mk``\ ,并且里面至少要包含如下的一行内容: -总的来说,``test`` 子目录下最简单的 CMakeLists.txt 文件可能如下所示: +.. code:: makefile -.. code:: cmake - - set(COMPONENT_SRCDIRS ".") - set(COMPONENT_ADD_INCLUDEDIRS ".") - set(COMPONENT_REQUIRES unity) - - register_component() + COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive 更多关于如何在 Unity 下编写测试用例的信息,请查阅 http://www.throwtheswitch.org/unity 。 @@ -117,6 +112,21 @@ DUT2(slave)终端: 一旦 DUT2 发送了该信号,您需要在 DUT2 的终端输入回车,然后 DUT1 会从 ``unity_wait_for_signal`` 函数中解除阻塞,并开始更改 GPIO 的电平。 +信号也可以用来在不同 DUT 之间传递参数。例如,DUT1 希望能够拿到 DUT2 的 MAC 地址,来进行蓝牙连接。 +这时,我们可以使用 ``unity_wait_for_signal_param`` 以及 ``unity_send_signal_param``。 + +DUT1 终端:: + + Waiting for signal: [dut2 mac address]! + Please input parameter value from any board send this signal and press "Enter" key. + + +DUT2 终端:: + + Send signal: [dut2 mac address][10:20:30:40:50:60]! + +一旦 DUT2 发送信号,您需要在 DUT1 输入 ``10:20:30:40:50:60`` 及回车,然后 DUT1 会从 ``unity_wait_for_signal_param`` 中获取到蓝牙地址的字符串,并解除阻塞开始蓝牙连接。 + 添加多阶段测试用例 ------------------ @@ -150,23 +160,23 @@ DUT2(slave)终端: 切换到 ``tools/unit-test-app`` 目录下进行配置和编译: -- ``idf.py menuconfig`` - 配置单元测试程序。 +- ``make menuconfig`` - 配置单元测试程序。 -- ``idf.py -T all build`` - 编译单元测试程序,测试每个组件 ``test`` +- ``make TESTS_ALL=1`` - 编译单元测试程序,测试每个组件 ``test`` 子目录下的用例。 -- ``idf.py -T xxx build`` - 编译单元测试程序,测试指定的组件。 +- ``make TEST_COMPONENTS='xxx'`` - 编译单元测试程序,测试指定的组件。 -- ``idf.py -T all -E xxx build`` - +- ``make TESTS_ALL=1 TEST_EXCLUDE_COMPONENTS='xxx'`` - 编译单元测试程序,测试所有(除开指定)的组件。例如 - ``idf.py -T all -E ulp mbedtls build`` - + ``make TESTS_ALL=1 TEST_EXCLUDE_COMPONENTS='ulp mbedtls'`` - 编译所有的单元测试,不包括 ``ulp`` 和 ``mbedtls``\ 组件。 -当编译完成时,它会打印出烧写芯片的指令。您只需要运行 ``idf.py flash`` +当编译完成时,它会打印出烧写芯片的指令。您只需要运行 ``make flash`` 即可烧写所有编译输出的文件。 -您还可以运行 ``idf.py -T all flash`` 或者 -``idf.py -T xxx flash`` +您还可以运行 ``make flash TESTS_ALL=1`` 或者 +``make TEST_COMPONENTS='xxx'`` 来编译并烧写,所有需要的文件都会在烧写之前自动重新编译。 使用 ``menuconfig`` 可以设置烧写测试程序所使用的串口。 @@ -211,13 +221,13 @@ DUT2(slave)终端: 可以输入以下任意一项来运行测试用例: -- 引号中的测试用例的名字,运行单个测试用例。 +- 引号中的测试用例的名字(例如 ``"esp_ota_begin() verifies arguments"``),运行单个测试用例。 -- 测试用例的序号,运行单个测试用例。 +- 测试用例的序号(例如 ``1``),运行单个测试用例。 -- 方括号中的模块名字,运行指定模块所有的测试用例。 +- 方括号中的模块名字(例如 ``[cxx]``),运行指定模块所有的测试用例。 -- 星号,运行所有测试用例。 +- 星号 (``*``),运行所有测试用例。 ``[multi_device]`` 和 ``[multi_stage]`` 标签告诉测试运行者该用例是多设备测试还是多阶段测试。这些标签由 diff --git a/docs/zh_CN/api-guides/unit-tests.rst b/docs/zh_CN/api-guides/unit-tests.rst index de8e52d3ef..960238e72f 100644 --- a/docs/zh_CN/api-guides/unit-tests.rst +++ b/docs/zh_CN/api-guides/unit-tests.rst @@ -1,5 +1,5 @@ ESP32 中的单元测试 -================== +========================== :link_to_translation:`en:[English]` ESP-IDF @@ -32,12 +32,19 @@ C 文件可以包含多个测试用例。测试文件的名字要以 “test” 来声明主函数的区域, ``unity_platform.c`` 会自动调用 ``UNITY_BEGIN()``\ , 然后运行测试用例,最后调用 ``UNITY_END()``\ 。 -每一个测试子目录下都应该包含一个 -``component.mk``\ ,并且里面至少要包含如下的一行内容: +``test`` 子目录需要包含 :ref:`组件 CMakeLists.txt `,因为他们本身就是一种组件。ESP-IDF 使用了 +``unity`` 测试框架,需要将其指定为组件的依赖项。通常,组件 +:ref:`需要手动指定待编译的源文件 `;但是,对于测试组件来说,这个要求被放宽了,仅仅是建议使用 “COMPONENT_SRCDIRS”。 -.. code:: makefile +总的来说,``test`` 子目录下最简单的 CMakeLists.txt 文件可能如下所示: - COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive +.. code:: cmake + + set(COMPONENT_SRCDIRS ".") + set(COMPONENT_ADD_INCLUDEDIRS ".") + set(COMPONENT_REQUIRES unity) + + register_component() 更多关于如何在 Unity 下编写测试用例的信息,请查阅 http://www.throwtheswitch.org/unity 。 @@ -110,21 +117,6 @@ DUT2(slave)终端: 一旦 DUT2 发送了该信号,您需要在 DUT2 的终端输入回车,然后 DUT1 会从 ``unity_wait_for_signal`` 函数中解除阻塞,并开始更改 GPIO 的电平。 -信号也可以用来在不同 DUT 之间传递参数。例如,DUT1 希望能够拿到 DUT2 的 MAC 地址,来进行蓝牙连接。 -这时,我们可以使用 ``unity_wait_for_signal_param`` 以及 ``unity_send_signal_param``。 - -DUT1 终端:: - - Waiting for signal: [dut2 mac address]! - Please input parameter value from any board send this signal and press "Enter" key. - - -DUT2 终端:: - - Send signal: [dut2 mac address][10:20:30:40:50:60]! - -一旦 DUT2 发送信号,您需要在 DUT1 输入 ``10:20:30:40:50:60`` 及回车,然后 DUT1 会从 ``unity_wait_for_signal_param`` 中获取到蓝牙地址的字符串,并解除阻塞开始蓝牙连接。 - 添加多阶段测试用例 ------------------ @@ -158,23 +150,23 @@ DUT2 终端:: 切换到 ``tools/unit-test-app`` 目录下进行配置和编译: -- ``make menuconfig`` - 配置单元测试程序。 +- ``idf.py menuconfig`` - 配置单元测试程序。 -- ``make TESTS_ALL=1`` - 编译单元测试程序,测试每个组件 ``test`` +- ``idf.py -T all build`` - 编译单元测试程序,测试每个组件 ``test`` 子目录下的用例。 -- ``make TEST_COMPONENTS='xxx'`` - 编译单元测试程序,测试指定的组件。 +- ``idf.py -T xxx build`` - 编译单元测试程序,测试指定的组件。 -- ``make TESTS_ALL=1 TEST_EXCLUDE_COMPONENTS='xxx'`` - +- ``idf.py -T all -E xxx build`` - 编译单元测试程序,测试所有(除开指定)的组件。例如 - ``make TESTS_ALL=1 TEST_EXCLUDE_COMPONENTS='ulp mbedtls'`` - + ``idf.py -T all -E ulp mbedtls build`` - 编译所有的单元测试,不包括 ``ulp`` 和 ``mbedtls``\ 组件。 -当编译完成时,它会打印出烧写芯片的指令。您只需要运行 ``make flash`` +当编译完成时,它会打印出烧写芯片的指令。您只需要运行 ``idf.py flash`` 即可烧写所有编译输出的文件。 -您还可以运行 ``make flash TESTS_ALL=1`` 或者 -``make TEST_COMPONENTS='xxx'`` +您还可以运行 ``idf.py -T all flash`` 或者 +``idf.py -T xxx flash`` 来编译并烧写,所有需要的文件都会在烧写之前自动重新编译。 使用 ``menuconfig`` 可以设置烧写测试程序所使用的串口。 @@ -219,13 +211,13 @@ DUT2 终端:: 可以输入以下任意一项来运行测试用例: -- 引号中的测试用例的名字(例如 ``"esp_ota_begin() verifies arguments"``),运行单个测试用例。 +- 引号中的测试用例的名字,运行单个测试用例。 -- 测试用例的序号(例如 ``1``),运行单个测试用例。 +- 测试用例的序号,运行单个测试用例。 -- 方括号中的模块名字(例如 ``[cxx]``),运行指定模块所有的测试用例。 +- 方括号中的模块名字,运行指定模块所有的测试用例。 -- 星号 (``*``),运行所有测试用例。 +- 星号,运行所有测试用例。 ``[multi_device]`` 和 ``[multi_stage]`` 标签告诉测试运行者该用例是多设备测试还是多阶段测试。这些标签由 diff --git a/docs/zh_CN/cmake-pending-features.rst b/docs/zh_CN/cmake-pending-features.rst deleted file mode 100644 index 5c11a1573a..0000000000 --- a/docs/zh_CN/cmake-pending-features.rst +++ /dev/null @@ -1,10 +0,0 @@ -.. important:: - 目前,CMake 编译系统尚不支持以下功能: - - - Eclipse IDE 文档 - - 安全启动 - - Flash 加密 - - 未来,CMake 编译系统将在 ESP-IDF v4.0 发布后取代现有基于 GNU Make 的编译系统,成为默认编译系统。我们会在 ESP-IDF v4.0 发布前逐步完善上述功能。 - - diff --git a/docs/zh_CN/cmake-warning.rst b/docs/zh_CN/cmake-warning.rst deleted file mode 100644 index 8815c8ae99..0000000000 --- a/docs/zh_CN/cmake-warning.rst +++ /dev/null @@ -1,4 +0,0 @@ -.. note:: - 本文档将介绍如何使用 CMake 编译系统。目前,CMake 编译系统仍处于预览发布阶段,如您在使用中遇到任何问题,请前往 ESP-IDF 提交 `Issues `_。 - - 未来,CMake 编译系统将在 ESP-IDF v4.0 发布后过渡为默认编译系统,现行基于 GNU Make 的编译系统将在 ESP-IDF v5.0 后弃用。 diff --git a/docs/zh_CN/get-started-cmake/add-idf_path-to-profile.rst b/docs/zh_CN/get-started-cmake/add-idf_path-to-profile.rst deleted file mode 100644 index ad19c54658..0000000000 --- a/docs/zh_CN/get-started-cmake/add-idf_path-to-profile.rst +++ /dev/null @@ -1,75 +0,0 @@ -在用户配置文件中添加 IDF_PATH 和 idf.py PATH (CMake) -========================================================================================================== - -:link_to_translation:`en:[英文]` - -.. include:: ../cmake-warning.rst - -使用基于 CMake 的构建系统和 idf.py 工具,用户需修改两处系统环境变量: - -- ``IDF_PATH`` 需设置为含有 ESP-IDF 目录的路径 -- 系统 ``PATH`` 变量需包括含有 ``idf.py`` 工具 (属于 ESP-IDF 一部分)的目录 - -为确保系统重启后仍保存之前的变量设置,请参照以下说明将变量设置添加到用户配置文件中。 - -.. note:: 使用 IDE 工具的情况下,你可以选择在 IDE 项目环境中设置环境变量,而不使用如下命令行。 - -.. note:: 如果你从未用过 ``idf.py`` 命令行工具,而是直接运行 cmake 或通过 IDE 工具运行 cmake,则无需设置 ``PATH`` 变量,只需设置 ``IDF_PATH`` 变量。不过,你也可以两个都设置。 - -.. note:: 如果你只用过 ``idf.py`` 命令行工具,从未直接运行 cmake 或通过 IDE 工具运行 cmake,则无需设置 ``IDF_PATH`` 变量。``idf.py`` 会搜索自身包含的目录,如果没有发现 ``IDF_PATH``,则会自行进行有关设置。 - -.. _add-paths-to-profile-windows-cmake: - -Windows 操作系统 ------------------------------------ - -在 Windows 10 操作系统下设置环境变量,用户应在开始菜单下搜索 "Edit Environment Variables"。 - -在较早版本的 Windows 操作系统下设置环境变量,用户应打开系统控制面板,选择“高级”,找到环境变量按钮。 - -你可以为本台电脑上的“所有用户”或“当前用户”设置环境变量,这取决于其他用户是否也需要使用 ESP-IDF。 - -- 点击 ``New...`` (新建...) 添加名为 ``IDF_PATH`` 的新系统变量,具体设置为包含 ESP-IDF 的目录,例如,``C:\Users\user-name\esp\esp-idf``。 -- 找到 ``Path`` 环境变量,双击进行编辑。在末尾添加 ``;%IDF_PATH%\tools``,这样你就可以通过 Windows 命令窗口运行 ``idf.py`` 等其他工具了。 - -如果你在安装 ESP32 硬件开发的软件环境时,从 :ref:`get-started-setup-path-cmake` 小节跳到了这里,请返回 :ref:`get-started-start-project-cmake` 小节开始阅读。 - - -.. _add-idf_path-to-profile-linux-macos-cmake: - -Linux 和 MacOS 操作系统 ------------------------------------- - -要设置 ``IDF_PATH``,并在 PATH 中添加 ``idf.py``,请将以下两行代码添加至你的 ``~/.profile`` 文件中:: - - export IDF_PATH=~/esp/esp-idf - export PATH="$IDF_PATH/tools:$PATH" - -.. note:: - - ``~/.profile`` 表示在你的电脑用户主目录中,后缀为 ``.profile`` 的文件。(``~`` 为 shell 中的缩写)。 - -请退出,并重新登录使更改生效。 - -.. note:: - - 并非所有 shell 都使用 ``.profile``,但是如果同时存在 ``/bin/bash`` 和 ``.bash_profile``,请更新此配置文件。如果存在 ``zsh``,请更新 ``.zprofile``。其他 shell 可能使用其他配置文件(详询有关 shell 的文档)。 - -运行以下命令来检查 ``IDF_PATH`` 设置是否正确:: - - printenv IDF_PATH - -此处应打印出此前在 ``~/.profile`` 文件中输入(或手动设置)的路径。 - -为确认 ``idf.py`` 目前是否在 ``PATH`` 中,你可以运行以下命令:: - - which idf.py - -这里,应打印出类似 ``${IDF_PATH}/tools/idf.py`` 的路径。 - -如果不想修改 ``IDF_PATH`` 或 ``PATH``,你可以在每次重启或退出后在终端中手动输入:: - - export IDF_PATH=~/esp/esp-idf - export PATH="$IDF_PATH/tools:$PATH" - -如果你在安装 ESP32 硬件开发的软件环境时,从 :ref:`get-started-setup-path-cmake` 小节跳到了这里,请返回 :ref:`get-started-start-project-cmake` 小节开始阅读。 diff --git a/docs/zh_CN/get-started-cmake/eclipse-setup.rst b/docs/zh_CN/get-started-cmake/eclipse-setup.rst deleted file mode 100644 index d0c4fb4d66..0000000000 --- a/docs/zh_CN/get-started-cmake/eclipse-setup.rst +++ /dev/null @@ -1,11 +0,0 @@ -**************************************** -Eclipse IDE 创建和烧录指南 (CMake) -**************************************** - -:link_to_translation:`en:[English]` - -.. include:: ../cmake-warning.rst - -有关基于 CMake-based 构建系统和 Eclipse CDT,进行 Eclipse 设置的相关文档即将发布。 - -.. _eclipse.org: https://www.eclipse.org/ diff --git a/docs/zh_CN/get-started-cmake/establish-serial-connection.rst b/docs/zh_CN/get-started-cmake/establish-serial-connection.rst deleted file mode 100644 index 278dfb6afb..0000000000 --- a/docs/zh_CN/get-started-cmake/establish-serial-connection.rst +++ /dev/null @@ -1,155 +0,0 @@ -与 ESP32 创建串口连接 (CMake) -============================================== - -:link_to_translation:`en:[English]` - -本章节主要介绍如何创建 ESP32 和 PC 之间的串口连接。 - - -连接 ESP32 和 PC --------------------- - -用 USB 线将 ESP32 开发板连接到 PC。如果设备驱动程序没有自动安装,请先确认 ESP32 开发板上的 USB 转串口芯片(或外部转串口适配器)型号,然后在网上搜索驱动程序,并进行手动安装。 - -以下是乐鑫 ESP32 开发板驱动程序的链接: - -.. csv-table:: - :header: 开发板, USB 驱动, 备注 - :widths: 40, 20, 40 - - :ref:`ESP32-DevKitC `, `CP210x`_ - `ESP32-LyraT `_, `CP210x`_ - `ESP32-LyraTD-MSC `_, `CP210x`_ - :ref:`ESP32-PICO-KIT `, `CP210x`_ - :ref:`ESP-WROVER-KIT `, `FTDI`_ - :ref:`ESP32 Demo 板 `, `FTDI`_ - `ESP-Prog`_, `FTDI`_, 编程板 (w/o ESP32) - `ESP32-MeshKit-Sense `_, n/a, 搭配 `ESP-Prog`_ 使用 - `ESP32-Sense Kit `_, n/a, 搭配 `ESP-Prog`_ 使用 - -.. _CP210x: https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers -.. _FTDI: http://www.ftdichip.com/Drivers/VCP.htm -.. _ESP-Prog: https://github.com/espressif/esp-iot-solution/blob/master/documents/evaluation_boards/ESP-Prog_guide_en.md#introduction-to-the-esp-prog-board - -* CP210x: `CP210x USB 至 UART 桥 VCP 驱动程序 `_ -* FTDI: `FTDI 虚拟 COM 端口驱动程序 `_ - -以上驱动仅用于参考。一般情况下,当上述任一 ESP32 开发板与 PC 连接时,对应驱动程序应该已经被打包在操作系统中,并已经自动安装。 - -在 Windows 上查看端口 ---------------------- - -检查 Windows 设备管理器中的 COM 端口列表。断开 ESP32 与 PC 的连接,然后重新连接,查看哪个端口从列表中消失,然后再次出现。 - -以下为 ESP32 DevKitC 和 ESP32 WROVER KIT 串口: - -.. figure:: ../../_static/esp32-devkitc-in-device-manager.png - :align: center - :alt: 设备管理器中 ESP32-DevKitC 的 USB 至 UART 桥 - :figclass: align-center - - 设备管理器中 ESP32-DevKitC 的 USB 至 UART 桥 - -.. figure:: ../../_static/esp32-wrover-kit-in-device-manager.png - :align: center - :alt: Windows 设备管理器中 ESP-WROVER-KIT 的两个 USB 串行端口 - :figclass: align-center - - Windows 设备管理器中 ESP-WROVER-KIT 的两个 USB 串行端口 - - -在 Linux 和 MacOS 上查看端口 ------------------------------ - -查看 ESP32 开发板(或外部转串口适配器)的串口设备名称,请运行两次以下命令。首先,断开开发板或适配器,第一次运行命令;然后,连接开发板或适配器,第二次运行命令。其中,第二次运行命令后出现的端口即是 ESP32 对应的串口: - -Linux :: - - ls /dev/tty* - -MacOS :: - - ls /dev/cu.* - -.. note:: - - 对于 MacOS 用户:若你没有看到串口,请检查你是否已按照《入门指南》安装了适用于你特定开发板的 USB/串口驱动程序。对于 MacOS High Sierra (10.13) 的用户,你可能还需要手动允许驱动程序的加载,具体可打开 ``系统偏好设置`` -> ``安全和隐私`` -> ``通用``,检查是否有信息显示:“来自开发人员的系统软件...”,其中开发人员的名称为 Silicon Labs 或 FTDI。 - -.. _linux-dialout-group-cmake: - -在 Linux 中添加用户到 ``dialout`` ------------------------------------ - -当前登录用户应当可以通过 USB 对串口进行读写操作。在多数 Linux 版本中,你都可以通过以下命令,将用户添加到 ``dialout`` 组,来获许读写权限:: - - sudo usermod -a -G dialout $USER - -在 Arch Linux 中,需要通过以下命令将用户添加到 ``uucp`` 组中:: - - sudo usermod -a -G uucp $USER - -请重新登录,确保串口读写权限可以生效。 - - -确认串口连接 ------------------------- - -现在,请使用串口终端程序,验证串口连接是否可用。在本示例中,我们将使用 `PuTTY SSH Client `_, `PuTTY SSH Client `_ 既可用于 Windows 也可用于 Linux。你也可以使用其他串口程序并设置如下的通信参数。 - -运行终端,配置串口:波特率 = 115200,数据位 = 8,停止位 = 1,奇偶校验 = N。以下截屏分别展示了在 Windows 和 Linux 中配置串口和上述通信参数(如 115200-8-1-N)。注意,这里一定要选择在上述步骤中确认的串口进行配置。 - -.. figure:: ../../_static/putty-settings-windows.png - :align: center - :alt: 在 Windows 操作系统中使用 PuTTY 设置串口通信参数 - :figclass: align-center - - 在 Windows 操作系统中使用 PuTTY 设置串口通信参数 - -.. figure:: ../../_static/putty-settings-linux.png - :align: center - :alt: 在 Linux 操作系统中使用 PuTTY 设置串口通信参数 - :figclass: align-center - - 在 Linux 操作系统中使用 PuTTY 设置串口通信参数 - - -然后,请检查 ESP32 是否有打印日志。如有,请在终端打开串口进行查看。这里,日志内容取决于加载到 ESP32 的应用程序,下图即为一个示例。 - -.. highlight:: none - -:: - - ets Jun 8 2016 00:22:57 - - rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) - ets Jun 8 2016 00:22:57 - - rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) - configsip: 0, SPIWP:0x00 - clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 - mode:DIO, clock div:2 - load:0x3fff0008,len:8 - load:0x3fff0010,len:3464 - load:0x40078000,len:7828 - load:0x40080000,len:252 - entry 0x40080034 - I (44) boot: ESP-IDF v2.0-rc1-401-gf9fba35 2nd stage bootloader - I (45) boot: compile time 18:48:10 - - ... - -如果打印出的日志是可读的(而不是乱码),则表示串口连接正常。此时,你可以继续进行安装,并最终将应用程序上载到 ESP32。 - -.. note:: - - 在某些串口接线方式下,在 ESP32 启动并开始打印串口日志前,需要在终端程序中禁用串口 RTS & DTR 引脚。该问题仅存在于将 RTS & DTR 引脚直接连接到 EN & GPIO0 引脚上的情况,绝大多数开发板(包括乐鑫所有的开发板)都没有这个问题。更多详细信息,参见 `esptool 文档`_。 - -.. note:: - - 请在验证完串口通信正常后,关闭串口终端。下一步,我们将使用另一个应用程序将新的固件上传到 ESP32。此时,如果串口被占用则无法成功。 - -如你在安装 ESP32 硬件开发的软件环境时,从 :ref:`get-started-connect-cmake` 跳转到了这里,请从 :ref:`get-started-configure-cmake` 继续阅读。 - - -.. _esptool 文档: https://github.com/espressif/esptool/wiki/ESP32-Boot-Mode-Selection#automatic-bootloader - diff --git a/docs/zh_CN/get-started-cmake/linux-setup-scratch.rst b/docs/zh_CN/get-started-cmake/linux-setup-scratch.rst deleted file mode 100644 index 967887f74d..0000000000 --- a/docs/zh_CN/get-started-cmake/linux-setup-scratch.rst +++ /dev/null @@ -1,79 +0,0 @@ -****************************************** -从零开始设置 Linux 环境下的工具链 (CMake) -****************************************** - -:link_to_translation:`en:[English]` - -.. include:: ../cmake-warning.rst - -除了从乐鑫官网直接下载已编译好的二进制工具链外,你还可以按照本文介绍,从头开始设置你自己的工具链。如需快速使用已编译好的二进制工具链,可回到 :doc:`linux-setup` 章节。 - -安装准备 -===================== - -编译 ESP-IDF 需要以下软件包: - -- CentOS 7:: - - sudo yum install git wget ncurses-devel flex bison gperf python pyserial python-pyelftools cmake ninja-build ccache - -- Ubuntu 和 Debian:: - - sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache - -- Arch:: - - sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-click python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache - - -.. note:: - 使用 ESP-IDF 需要 CMake 3.5 或以上版本。较早版本的 Linux 可能需要升级才能向后移植仓库,或安装 "cmake3" 软件包,而不是安装 "cmake"。 - -从源代码编译工具链 -================================= - -- 安装依赖: - - - CentOS 7:: - - sudo yum install gawk gperf grep gettext ncurses-devel python python-devel automake bison flex texinfo help2man libtool make - - - Ubuntu pre-16.04:: - - sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool make - - - Ubuntu 16.04 及以上:: - - sudo apt-get install gawk gperf grep gettext python python-dev automake bison flex texinfo help2man libtool libtool-bin make - - - Debian 9:: - - sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool libtool-bin make - - - Arch:: - - TODO - -创建工作目录,并进入该目录:: - - mkdir -p ~/esp - cd ~/esp - -下载并编译 ``crosstool-NG`` : - -.. include:: /_build/inc/scratch-build-code.inc - -编译工具链:: - - ./ct-ng xtensa-esp32-elf - ./ct-ng build - chmod -R u+w builds/xtensa-esp32-elf - -编译得到的工具链会被保存到 ``~/esp/crosstool-NG/builds/xtensa-esp32-elf``。请按照 :ref:`标准设置指南 ` 的介绍,将工具链添加到 ``PATH``。 - - -后续步骤 -========== - -继续设置开发环境,请前往 :ref:`get-started-get-esp-idf-cmake` 章节。 - diff --git a/docs/zh_CN/get-started-cmake/linux-setup.rst b/docs/zh_CN/get-started-cmake/linux-setup.rst deleted file mode 100644 index 82afb790b0..0000000000 --- a/docs/zh_CN/get-started-cmake/linux-setup.rst +++ /dev/null @@ -1,119 +0,0 @@ -******************************************************************* -Linux 平台工具链的标准设置 (CMake) -******************************************************************* - -:link_to_translation:`en:[英文]` - -.. include:: ../cmake-warning.rst - -安装前提 -===================== - -编译 ESP-IDF 需要以下软件包: - -- CentOS 7:: - - sudo yum install git wget ncurses-devel flex bison gperf python pyserial python-pyelftools cmake ninja-build ccache - -- Ubuntu 和 Debian:: - - sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache - -- Arch:: - - sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-click python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache - -.. note:: - 使用 ESP-IDF 需要 CMake 3.5 或以上版本。较早版本的 Linux 可能需要升级才能向后移植仓库,或安装 "cmake3" 软件包,而不是安装 "cmake"。 - -工具链的设置 -========================= - -.. include:: /_build/inc/download-links.inc - -Linux 版的 ESP32 工具链可以从 Espressif 的网站下载: - -- 64 位 Linux: - - |download_link_linux64| - -- 32 位 Linux: - - |download_link_linux32| - -1. 下载完成后,将它解压到 ``~/esp`` 目录: - - - for 64-bit Linux: - - .. include:: /_build/inc/unpack-code-linux64.inc - - - for 32-bit Linux: - - .. include:: /_build/inc/unpack-code-linux32.inc - -.. _setup-linux-toolchain-add-it-to-path-cmake: - -2. 工具链将会被解压到 ``~/esp/xtensa-esp32-elf/`` 目录。 - - 要使用工具链,你还需要在 ``~/.profile`` 文件中更新环境变量 ``PATH``。要使 ``xtensa-esp32-elf`` 在所有的终端会话中都有效,需要将下面这一行代码添加到你的 ``~/.profile`` 文件中::: - - export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH" - - 或者,你也可以给上面的命令创建一个别名。这样做的好处是,你仅在需要时才获取工具链,将下面这行代码添加到 ``~/.profile`` 文件中即可:: - - alias get_esp32='export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH"' - - 然后,当你需要使用工具链时,在命令行输入 ``get_esp32``,然后工具链会自动添加到你的 ``PATH`` 中。 - - .. note:: - - 如果将 ``/bin/bash`` 设置为登录 shell,且同时存在 ``.bash_profile`` 和 ``.profile``,则更新 ``.bash_profile``。 - -3. 退出并重新登录以使 ``.profile`` 更改生效。运行以下命令来检查 ``PATH`` 设置是否正确:: - - printenv PATH - - 检查字符串的开头是否包含类似的工具链路径:: - - $ printenv PATH - /home/user-name/esp/xtensa-esp32-elf/bin:/home/user-name/bin:/home/user-name/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin - - 除了 ``/home/user-name``,应该有具体的安装的主路径。 - - -权限问题 /dev/ttyUSB0 ----------------------------------------------- - -使用某些 Linux 版本向 ESP32 烧写固件时,可能会出现 ``Failed to open port /dev/ttyUSB0`` 错误消息。此时,可以将当前用户增加至 :ref:` Linux Dialout 组 ` - -Arch Linux 用户 --------------------------------- - -在 Arch Linux 中运行预编译的 gdb (xtensa-esp32-elf-gdb) 需要 ncurses 5,但是 Arch 使用的是 ncurses 6。 - -`AUR`_ 中存在向下兼容的库文件,可用于本地和 lib32 的配置: - -- https://aur.archlinux.org/packages/ncurses5-compat-libs/ -- https://aur.archlinux.org/packages/lib32-ncurses5-compat-libs/ - -在安装这些软件包之前,你可能需要将作者的公钥添加到你的密钥环中,具体见上方链接中的 "Comments" 部分的介绍。 - -或者,你也可以使用 crosstool-NG 编译一个链接到 ncurses 6 的 gdb。 - - -后续步骤 -================ - -后续开发环境设置,请参考 :ref:`get-started-get-esp-idf-cmake` 一节。 - - -相关文档 -================= - -.. toctree:: - :maxdepth: 1 - - linux-setup-scratch - - -.. _AUR: https://wiki.archlinux.org/index.php/Arch_User_Repository diff --git a/docs/zh_CN/get-started-cmake/macos-setup-scratch.rst b/docs/zh_CN/get-started-cmake/macos-setup-scratch.rst deleted file mode 100644 index 0080d81802..0000000000 --- a/docs/zh_CN/get-started-cmake/macos-setup-scratch.rst +++ /dev/null @@ -1,88 +0,0 @@ -********************************************************************* -从零开始设置 Mac OS 环境下的工具链 (CMake) -********************************************************************* - -:link_to_translation:`en:[英文]` - -.. include:: ../cmake-warning.rst - -软件包管理器 -====================== - -从零开始设置工具链,你需要安装 MacPorts_ 或 homebrew_ 包管理器。或者,你也可以直接 :doc:`下载预编译的工具链 `。 - -MacPorts_ 需要安装完整的 XCode 软件,而 homebrew_ 只需要安装 XCode 命令行工具即可。 - - .. _homebrew: https://brew.sh/ - .. _MacPorts: https://www.macports.org/install.php - -请参考 :ref:`工具链自定义设置 ` 章节,查看在哪些情景下需要从头开始设置工具链。 - -准备工作 -============================ - -- 安装 pip:: - - sudo easy_install pip - -- 安装 pyserial:: - - pip install --user pyserial - -- 安装 CMake 和 Ninja 编译工具: - - - 若使用 HomeBrew,你可以运行:: - - brew install cmake ninja - - - 若使用 MacPorts,你可以运行:: - - sudo port install cmake ninja - -从源代码编译工具链 -======================================== - -- 相关安装: - - - 对于 MacPorts:: - - sudo port install gsed gawk binutils gperf grep gettext wget libtool autoconf automake make - - - 对于 homebrew:: - - brew install gnu-sed gawk binutils gperftools gettext wget help2man libtool autoconf automake make - -创建一个文件系统镜像(区分大小写):: - - hdiutil create ~/esp/crosstool.dmg -volname "ctng" -size 10g -fs "Case-sensitive HFS+" - -挂载:: - - hdiutil mount ~/esp/crosstool.dmg - -创建指向你工作目录的符号链接:: - - mkdir -p ~/esp - ln -s /Volumes/ctng ~/esp/ctng-volume - -前往新创建的目录::: - - cd ~/esp/ctng-volume - -下载 ``crosstool-NG``,并开始编译: - -.. include:: /_build/inc/scratch-build-code.inc - -编译工具链::: - - ./ct-ng xtensa-esp32-elf - ./ct-ng build - chmod -R u+w builds/xtensa-esp32-elf - -编译后的工具链将保存在 ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf``。根据 :ref:`Mac OS 下设置环境变量的标准方法 ` 中的介绍,将工具链添加到 ``PATH`` 中。 - - -后续步骤 -================= - -继续设置开发环境,请前往 :ref:`获取 ESP-IDF ` 章节。 diff --git a/docs/zh_CN/get-started-cmake/macos-setup.rst b/docs/zh_CN/get-started-cmake/macos-setup.rst deleted file mode 100644 index adb0b1241e..0000000000 --- a/docs/zh_CN/get-started-cmake/macos-setup.rst +++ /dev/null @@ -1,95 +0,0 @@ -****************************************************************** -在 Mac OS 上安装 ESP32 工具链 (CMake) -****************************************************************** - -:link_to_translation:`en:[英文]` - -.. include:: ../cmake-warning.rst - -安装准备 -===================== - -ESP-IDF 将使用 Mac OS 上默认安装的 Python 版本。 - -- 安装 pip:: - - sudo easy_install pip - -- 安装 pyserial:: - - pip install --user pyserial - -- 安装 CMake 和 Ninja 编译工具: - - - 若有 HomeBrew_,你可以运行:: - - brew install cmake ninja - - - 若有 MacPorts_,你可以运行:: - - sudo port install cmake ninja - - - 若以上均不适用,请访问 CMake_ 和 Ninja_ 主页,查询有关 Mac OS 平台的下载安装问题。 - -- 强烈建议同时安装 ccache_ 以达到更快的编译速度。如有 HomeBrew_,可通过 MacPorts_ 上的 ``brew install ccache`` 或 ``sudo port install ccache`` 完成安装。 - -.. note:: - - 如在任一步骤中出现以下报错信息:: - - ``xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun`` - - 你需要安装 XCode 命令行工具才能继续,具体可运行 ``xcode-select --install`` 进行安装。 - -安装工具链 -====================== - -.. include:: /_build/inc/download-links.inc - -下载 MacOS 版本的 ESP32 工具链,请前往乐鑫官网: - -|download_link_osx| - -完成下载后,请在 ``~/esp`` 目录下进行解压: - -.. include:: /_build/inc/unpack-code-osx.inc - -.. _setup-macos-toolchain-add-it-to-path-cmake: - -此后,该工具链将解压至 ``~/esp/xtensa-esp32-elf/`` 目录。 - -为了开始使用工具链,你必须更新 ``~/.profile`` 文件中的 ``PATH`` 环境变量。为了让所有终端都可以使用 ``xtensa-esp32-elf``,请将下方命令增加至你的 ``~/.profile`` 文件::: - - export PATH=$HOME/esp/xtensa-esp32-elf/bin:$PATH - -此外,你可以为以上命令增加一个别名。这样,你就可以仅在有需要时获取工具链。具体方式是在 ``~/.profile`` 文件中增加下方命令:: - - alias get_esp32="export PATH=$HOME/esp/xtensa-esp32-elf/bin:$PATH" - -此时,你可以直接输入 ``get_esp32`` 命令,即可将工具链添加至你的 ``PATH``。 - -注意,这里需要退出并重新登陆,``.profile`` 更改才会生效。 - -此外,你可以使用以下命令,验证 ``PATH`` 是否设置正确:: - - printenv PATH - - -后续步骤 -================= - -前往 :ref:`get-started-get-esp-idf-cmake`,完成接下来的开发环境配置。 - -相关文档 -================= - -.. toctree:: - :maxdepth: 1 - - macos-setup-scratch - -.. _cmake: https://cmake.org/ -.. _ninja: https://ninja-build.org/ -.. _ccache: https://ccache.samba.org/ -.. _homebrew: https://brew.sh/ -.. _MacPorts: https://www.macports.org/install.php \ No newline at end of file diff --git a/docs/zh_CN/get-started-cmake/toolchain-setup-scratch.rst b/docs/zh_CN/get-started-cmake/toolchain-setup-scratch.rst deleted file mode 100644 index fc08a6f038..0000000000 --- a/docs/zh_CN/get-started-cmake/toolchain-setup-scratch.rst +++ /dev/null @@ -1,27 +0,0 @@ -.. _get-started-customized-setup-cmake: - -********************************************************* -工具链自定义设置 (CMake) -********************************************************* - -:link_to_translation:`en:[英文]` - -除了从乐鑫官网(请见 :ref:`get-started-setup-toolchain-cmake`)下载二进制工具链外,你还可以自行编译工具链。 - -如果没有特别需求,建议直接使用我们提供的预编译二进制工具链。不过,你也可能也会由于以下原因,编译你自己的工具链: - -- 需要定制工具链编译配置 -- 使用其他 GCC 版本(如 4.8.5) -- 需要破解 gcc、newlib 或 libstdc++ -- 有相关兴趣或时间充裕 -- 不信任从网站下载的 bin 文件 - -如需自行编译工具链,请查看以下文档: - -.. toctree:: - :maxdepth: 1 - - windows-setup-scratch - linux-setup-scratch - macos-setup-scratch - diff --git a/docs/zh_CN/get-started-cmake/windows-setup-scratch.rst b/docs/zh_CN/get-started-cmake/windows-setup-scratch.rst deleted file mode 100644 index 325de61efa..0000000000 --- a/docs/zh_CN/get-started-cmake/windows-setup-scratch.rst +++ /dev/null @@ -1,94 +0,0 @@ -****************************************************************** -从零开始设置 Windows 环境下的工具链 (CMake) -****************************************************************** - -:link_to_translation:`en:[英文]` - -.. include:: ../cmake-warning.rst - -本文就如何运行基于 CMake 构建系统中的 :doc:`ESP-IDF 工具安装器 ` 进行逐步详细说明。手动安装所有工具能更好地控制整个安装流程,同时也方便高阶用户进行自定义安装。 - -使用 ESP-IDF 工具安装器对工具链及其他工具进行快速标准设置,请参照 :doc:`windows-setup`。 - - -.. note:: - 基于 GNU Make 的构建系统要求 Windows 兼容 `MSYS2`_ Unix。基于 CMake 的构建系统则无此要求。 - -工具 -===== - -cmake -^^^^^ - -下载最新发布的 Windows 平台稳定版 `CMake`_,并运行安装器。 - -当安装器询问安装选项时,选择 "Add CMake to the system PATH for all users"(为所有用户的系统路径添加 CMake)或 "Add CMake to the system PATH for the current user"(为当前用户的系统路径添加 CMake)。 - -Ninja 编译工具 -^^^^^^^^^^^^^^^^^^^^ - -.. note:: - Ninja 目前仅为 64 位版本 Windows 提供 bin 文件。你也可以通过其他编译工具使用 CMake 和 ``idf.py``,如适用于 32 位 Windows 的 mingw-make,但是目前暂无关于此工具的说明文档。 - -从(`下载页面 `_)下载最新发布的 Windows 平台稳定版 `ninja`_。 - -适用于 Windows 平台的 Ninja 下载文件是一个 .zip 文件,包含一个 ``ninja.exe`` 文件。将其解压到目录,并 `添加到你的路径 `_ (或者选择你的路径中已有的目录)。 - - -Python 2.x -^^^^^^^^^^ - -下载并运行适用于 Windows 安装器的最新版 `Python`_ 2.7。 - -Python 安装的“自定义”那一步提供了一份选项列表,最后一个选项是 "Add python.exe to Path"(添加 python.exe 到路径中),更改该选项,选择 "Will be installed"(将会安装)。 - -Python 安装完成后,打开 Windows 开始菜单下的 Command Prompt,并运行以下命令:: - - pip install --user pyserial - -适用于 IDF 的 MConf -^^^^^^^^^^^^^^^^^^^^^^ - -从 `kconfig-frontends 发布页面 `_ 下载配置工具 mconf-idf。此为 ``mconf`` 配置工具,可针对 ESP-IDF 进行一些自定义操作。 - -你需将此工具解压到目录,然后 `添加到你的路径 `_。 - -工具链设置 -=============== - -.. include:: /_build/inc/download-links.inc - -下载预编译的 Windows 平台工具链: - -|download_link_win32| - -解压压缩包文件到 ``C:\Program Files`` (或其他地址)。压缩包文件包含 ``xtensa-esp32-elf`` 目录。 - -然后,须将该目录下的子目录 ``bin`` `添加到你的路径 `_。例如,``C:\Program Files\xtensa-esp32-elf\bin``。 - -.. note:: - - 如果你已安装 MSYS2 环境(适用 "GNU Make" 构建系统),你可以跳过下载那一步,直接添加目录 ``C:\msys32\opt\xtensa-esp32-elf\bin`` 到路径,因为 MSYS2 环境已包含工具链。 - - -.. _add-directory-windows-path-cmake: - -添加目录到路径 -======================== - -添加任何新目录到你的 Windows Path 环境变量: - -打开系统控制面板,找到环境变量对话框(对于 Windows 10,则在高级系统设置中查找对话框)。 - -双击 ``Path`` 变量(选择用户或系统路径,这取决于你是否希望其他用户路径中也存在该目录)。在最后数值那里新添 ``;``。 - - -后续步骤 -================ - -要继续设置开发环境,请参照 :ref:`get-started-get-esp-idf-cmake`。 - -.. _ninja: https://ninja-build.org/ -.. _Python: https://www.python.org/downloads/windows/ -.. _MSYS2: https://msys2.github.io/ - diff --git a/docs/zh_CN/get-started-cmake/windows-setup-update.rst b/docs/zh_CN/get-started-cmake/windows-setup-update.rst deleted file mode 100644 index cdaf9a5b88..0000000000 --- a/docs/zh_CN/get-started-cmake/windows-setup-update.rst +++ /dev/null @@ -1,3 +0,0 @@ -:orphan: - -.. Remove this file when the Chinese translation of CMake getting started guide is updated diff --git a/docs/zh_CN/get-started-cmake/windows-setup.rst b/docs/zh_CN/get-started-cmake/windows-setup.rst deleted file mode 100644 index e8d1290339..0000000000 --- a/docs/zh_CN/get-started-cmake/windows-setup.rst +++ /dev/null @@ -1,73 +0,0 @@ -********************************************************** -Windows 平台工具链的标准设置 (CMake) -********************************************************** - -:link_to_translation:`en:[英文]` - -.. include:: ../cmake-warning.rst - -.. note:: - 基于 CMake 的构建系统仅支持 64 位版本 Windows。 - -引言 -============ - -ESP-IDF 需要安装必要的工具,以编译 ESP32 固件,包括:Git,交叉编译器,以及 CMake 构建工具。本文将对这些工具一一说明。 - -在此入门指南中,我们通过命令提示符进行有关操作。不过,安装 ESP-IDF 后你还可以使用 :doc:`Eclipse ` 或支持 CMake 的图形化工具 IDE。 - -.. note:: - 基于 GNU Make 的构建系统要求 Windows 系统兼容 MSYS2_ Unix。基于 CMake 的构建系统则无此要求。 - -ESP-IDF 工具安装器 -======================= - -安装 ESP-IDF 必备工具最简易的方式是下载 ESP-IDF 工具安装器,地址如下: - -https://dl.espressif.com/dl/esp-idf-tools-setup-1.2.exe - -安装器会自动安装 ESP32 Xtensa gcc 工具链,Ninja_ 编译工具,以及名为 mconf-idf_ 的配置工具。此外,如果你的电脑还未安装有关 CMake_ 和 Python_ 2.7 的安装器,它还可以下载和运行与之对应的安装器。 - -安装器默认更新 Windows ``Path`` 环境变量,因而上述工具也可在其他环境中运行。如果禁止该选项,则需自行设置 ESP-IDF 所使用的环境(终端或所选 IDE),并配置正确的路径。 - -请注意,此安装器仅针对 ESP-IDF 工具包,并不包括 ESP-IDF。 - -安装 Git -============== - -ESP-IDF 工具安装器并不会安装 Git,因为快速入门指南默认你将以命令行的模式使用它。你可以通过 `Git For Windows`_ 下载和安装 Windows 平台的命令行 Git 工具(包括 "Git Bash" 终端)。 - -如果你想使用其他图形化 Git 客户端,如 `Github Desktop`, 你可以自行安装,但需要对本《入门指南》中相应的 Git 命令进行转换,以便用于你所选的 Git 客户端。 - -使用终端 -================ - -在本《入门指南》接下来的步骤说明中,我们将使用终端命令提示符进行有关操作。你也可以使用任何其他形式的命令提示符: - -- 比如,Windows 开始菜单下内置的命令提示符。本文档中的所有 Windows 命令行指令均为 Windows 命令提示符中所使用的 "batch" 命令。 -- 你还可以使用 `Git for Windows`_ 中的 "Git Bash" 终端,其所使用的 "bash" 命令提示符语法与 Mac OS 或 Linux 的既定语法相同。安装此终端后,你可以在开始菜单下找到命令提示符窗口。 -- 如果你已安装 MSYS2_ (通过 ESP-IDF 之前版本),你还可以使用 MSYS 终端。 - -后续步骤 -========== - -要继续设置开发环境,请参照 :ref:`get-started-get-esp-idf-cmake`。 - -相关文档 -================= - -想要自定义安装流程的高阶用户可参照: - -.. toctree:: - :maxdepth: 1 - - windows-setup-scratch - - -.. _MSYS2: https://msys2.github.io/ -.. _cmake: https://cmake.org/download/ -.. _ninja: https://ninja-build.org/ -.. _Python: https://www.python.org/downloads/windows/ -.. _Git for Windows: https://gitforwindows.org/ -.. _mconf-idf: https://github.com/espressif/kconfig-frontends/releases/ -.. _Github Desktop: https://desktop.github.com/ diff --git a/docs/zh_CN/get-started-legacy/add-idf_path-to-profile.rst b/docs/zh_CN/get-started-legacy/add-idf_path-to-profile.rst new file mode 100644 index 0000000000..a1f5a1825b --- /dev/null +++ b/docs/zh_CN/get-started-legacy/add-idf_path-to-profile.rst @@ -0,0 +1,66 @@ +在用户配置文件中添加 IDF_PATH (传统 GNU Make) +============================================= +:link_to_translation:`en:[English]` + +.. include:: ../gnu-make-legacy.rst + +为了在系统多次重新启动时保留 “IDF_PATH” 环境变量的设置,请按照以下说明将其添加到用户配置文件中。 + +.. _add-idf_path-to-profile-windows-legacy: + + +Windows +------- + +用户配置文件脚本存放在 ``C:/msys32/etc/profile.d/`` 目录中。每次打开 MSYS2 窗口时,系统都执行这些脚本。 + + +#. 在 ``C:/msys32/etc/profile.d/`` 目录下创建一个新的脚本文件。将其命名为 ``export_idf_path.sh``。 + +#. 确定 ESP-IDF 目录的路径。路径与系统配置有关,例如 ``C:\msys32\home\user-name\esp\esp-idf``。 +#. 在脚本中加入 ``export`` 命令,e.g.:: + + export IDF_PATH="C:/msys32/home/user-name/esp/esp-idf" + + 请将原始 Windows 路径中将反斜杠替换为正斜杠。 + +#. 保存脚本。 + +#. 关闭 MSYS2 窗口并再次打开。输入以下命令检查是否设置了 ``IDF_PATH``:: + + printenv IDF_PATH + +将此前在脚本文件中输入的路径打印出来。 + +如果您不想在用户配置文件中永久设置 ``IDF_PATH``,则应在打开 MSYS2 窗口时手动输入:: + + export IDF_PATH="C:/msys32/home/user-name/esp/esp-idf" + +如您在安装用于 ESP32 开发的软件时,从 :ref:`get-started-setup-path-legacy` 小节跳转到了这里,请返回到 :ref:`get-started-start-project-legacy` 小节。 + +.. _add-idf_path-to-profile-linux-macos-legacy: + +Linux and MacOS +--------------- + +在 ``~/.profile`` 文件中加入以下指令,创建 ``IDF_PATH``: + + export IDF_PATH=~/esp/esp-idf + +注销并重新登录以使此更改生效。 + +.. note:: + + 如果将 ``/bin/bash`` 已设为登录 shell,并且 ``.bash_profile`` 和 ``.profile`` 同时存在,则更新 ``.bash_profile``。 + +运行以下命令以确保 ``IDF_PATH`` 已经设置好:: + + printenv IDF_PATH + +此前在 ``~/.profile`` 文件中输入(或者手动设置)的路径应该被打印出来。 + +如果不想永久设置 ``IDF_PATH``,每次重启或者注销时在终端窗口中手动输入:: + + export IDF_PATH=~/esp/esp-idf + +如果您从 :ref:`get-started-setup-path-legacy` 小节跳转到了这里,在安装用于 ESP32 开发的软件时,返回到 :ref:`get-started-start-project-legacy` 小节。 diff --git a/docs/zh_CN/get-started-legacy/eclipse-setup.rst b/docs/zh_CN/get-started-legacy/eclipse-setup.rst new file mode 100644 index 0000000000..97dab2618a --- /dev/null +++ b/docs/zh_CN/get-started-legacy/eclipse-setup.rst @@ -0,0 +1,115 @@ +******************************************** +Eclipse IDE 的创建和烧录指南 (传统 GNU Make) +******************************************** +:link_to_translation:`en:[English]` + +.. include:: ../gnu-make-legacy.rst + +.. _eclipse-install-steps-legacy: + +安装 Eclipse IDE +================ + +Eclipse IDE 是一个可视化的集成开发环境,可用于编写、编译和调试 ESP-IDF 项目。 + +* 首先,请在您的平台上安装相应的 ESP-IDF,具体步骤请参考适用于 Windows、OS X 和 Linux 的相应安装步骤。 + +* 我们建议,您应首先使用命令行创建一个项目,大致熟悉项目的创建流程。此外,您还需要使用命令行 (``make menuconfig``) 对您的 ESP-IDF 项目进行配置。目前,Eclipse 尚不支持对 ESP-IDF 项目进行配置。 + +* 下载相应版本的 Eclipse Installer 至您的平台,点击 eclipse.org_。 + +* 运行 Eclipse Installer,选择 “Eclipse for C/C++ Development”(有的版本也可能显示为 CDT)。 + + +配置 Eclipse IDE +================= + +请打开安装好的 Eclipse IDE,并按照以下步骤进行操作: + +导入新项目 +---------- + +* Eclipse IDE 需使用 ESP-IDF 的 Makefile 功能。因此,在使用 Eclipse 前,您需要先创建一个 ESP-IDF 项目。在创建 ESP-IDF 项目时,您可以使用 GitHub 中的 idf-template 项目模版,或从 esp-idf 子目录中选择一个 example。 + +* 运行 Eclipse,选择 “File” -> “Import...”。 + +* 在弹出的对话框中选择 “C/C++” -> “Existing Code as Makefile Project”,然后点击 “Next”。 + +* 在下个界面中 “Existing Code Location” 位置输入您的 IDF 项目的路径。注意,这里应输入 ESP-IDF 项目的路径,而非 ESP-IDF 本身的路径(这个稍后再填)。此外,您指定的目标路径中应包含名为 ``Makefile`` (项目 Makefile)的文件。 + +* 在本界面,找到 “Toolchain for Indexer Settings”,选择 “Cross GCC”,最后点击 “Finish”。 + + +项目属性 +-------- + +* 新项目将出现在 “Project Explorer” 下。请右键选择该项目,并在菜单中选择 “Properties”。 + +* 点击 “C/C++ Build” 下的 “Environment” 属性页,选择 “Add...”,并在对应位置输入 ``BATCH_BUILD`` 和 ``1``。 + +* 再次点击 “Add...”,并在 “IDF_PATH” 中输入 ESP-IDF 所在的完整安装路径。 + +* 选择 “PATH” 环境变量,不要改变默认值。如果 Xtensa 工具链的路径尚不在 “PATH” 列表中,则应将该路径 (``something/xtensa-esp32-elf/bin``) 增加至列表,工具链的典型路径类似于 ``/home/user-name/esp/xtensa-esp32-elf/bin``。请注意您需要在附加路径前添加冒号 ``:``。Windows 用户需要将 ``C:\msys32\mingw32\bin;C:\msys32\opt\xtensa-esp32-elf\bin;C:\msys32\usr\bin`` 添加到 ``PATH`` 环境变量的靠前位置(如果您将 msys32 安装到了其它目录,则需要更改对应的路径以匹配您的本地环境)。 + +* 在 macOS 平台上,增加一个 “PYTHONPATH” 环境变量,并将其设置为 ``/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages``, 保证系统中预先安装的 Python (需安装 pyserial 模块)可以覆盖 Eclipse 内置的任何 Python。 + +* 前往 “C/C++ General” -> “Preprocessor Include Paths” 属性页面。 + + * 点击 “Providers” 选项卡。 + + * 从 “Providers” 列表中选择 “CDT Cross GCC Built-in Compiler Settings”,将 “Command to get compiler specs” 修改为 ``xtensa-esp32-elf-gcc ${FLAGS} -std=c++11 -E -P -v -dD "${INPUTS}"`` + + * 从 “Providers” 列表中选择 “CDT GCC Build Output Parser”,将 “Compiler command pattern” 修改为 ``xtensa-esp32-elf-(gcc|g\+\+|c\+\+|cc|cpp|clang)`` + +* 前往 “C/C++ General” -> “Indexer” 属性页面。 + + * 去除 "Allow heuristic resolution of includes" 勾选。启用此选项时,Eclipse 有时无法找到正确的头文件目录。 + +点击 “C/C++ General" -> "Indexer” 属性页。 + + * 选择 “Enable project specific settings” 以启用本页上的其他设置。 + +.. note:: + + 取消选中 “Allow heuristic resolution of includes”。因为启用此选项时,有时会导致 Eclipse 无法找到正确的头文件目录。 + +点击 “C/C++ Build” -> “Behavior” 属性页。 + +* 选中 “Enable parallel build” 以启用多任务并行构建。 + +.. _eclipse-build-project-legacy: + +在 Eclipse IDE 中创建项目 +-------------------------- + +在首次创建项目前,Eclipse IDE 可能会显示大量有关未定义值的错误和警告,主要原因在于项目编译过程中所需的一些源文件是在 ESP-IDF 项目创建过程中自动生成的。因此,这些错误和警告将在 ESP-IDF 项目生成完成后消失。 + +* 点击 “OK”,关闭 Eclipse IDE 中的 “Properties” 对话框。 + +* 在 Eclipse IDE 界面外,打开命令管理器。进入项目目录,并通过 ``make menuconfig`` 命令对您的 ESP-IDF 项目进行配置。现阶段,您还无法在 Eclipse 中完成本操作。 + +*如果您未进行最开始的配置步骤,ESP-IDF 将提示在命令行中进行配置 - 但由于 Eclipse 暂时不支持相关功能,因此该项目将挂起或创建失败。* + +* 返回 Eclipse IDE 界面中,选择 “Project” -> “Build” 创建您的项目。 + +**提示**:如果您已经在 Eclipse IDE 环境外创建了项目,则可能需要选择 “Project” -> “Clean before choosing Project” -> “Build”,允许 Eclipse 查看所有源文件的编译器参数,并借此确定头文件包含路径。 + +在 Eclipse IDE 中烧录项目 +-------------------------- + +您可以将 ``make flash`` 目标放在 Eclipse 项目中,通过 Eclipse UI 调用 ``esptool.py`` 进行烧录: + +* 打开 “Project Explorer”,并右击您的项目(请注意右击项目本身,而非项目下的子文件,否则 Eclipse 可能会找到错误的 ``Makefile``)。 + +* 从菜单中选择 “Build Targets” -> “Create”。 + +* 输入 “flash” 为目标名称,其他选项使用默认值。 + +* 选择 “Project” -> “Build Target” -> “Build (快捷键:Shift + F9)”,创建自定义烧录目标,用于编译、烧录项目。 + +注意,您将需要通过 ``make menuconfig``,设置串行端口和其他烧录选项。``make menuconfig`` 仍需通过命令行操作(请见平台的对应指南)。 + +如有需要,请按照相同步骤添加 ``bootloader`` 和 ``partition_table``。 + + +.. _eclipse.org: https://www.eclipse.org/ diff --git a/docs/zh_CN/get-started-legacy/establish-serial-connection.rst b/docs/zh_CN/get-started-legacy/establish-serial-connection.rst new file mode 100644 index 0000000000..21fafc3c71 --- /dev/null +++ b/docs/zh_CN/get-started-legacy/establish-serial-connection.rst @@ -0,0 +1,132 @@ +与 ESP32 创建串口连接 (传统 GNU Make) +======================================= +:link_to_translation:`en:[English]` + +.. include:: ../gnu-make-legacy.rst + +本章节介绍如何在 ESP32 和 PC 之间建立串口连接。 + +连接 ESP32 和 PC +-------------------- + +用 USB 线将 ESP32 开发板连接到 PC。如果设备驱动程序没有自动安装,确认 ESP32 开发板上的 USB 转串口芯片(或外部串口适配器)型号,在网上搜索驱动程序并进行安装。 + +以下是乐鑫 ESP32 开发板驱动程序的链接: + +* ESP32-PICO-KIT 和 ESP32-DevKitC - `CP210x USB to UART Bridge VCP Drivers `_ + +* ESP32-WROVER-KIT 和 ESP32 Demo Board - `FTDI Virtual COM Port Drivers `_ + +以上驱动仅用于参考。当您将上述 ESP32 开发板与 PC 连接时,对应驱动程序应该已经被打包在操作系统中并自动安装。 + +在 Windows 上查看端口 +--------------------- + +检查 Windows 设备管理器中的 COM 端口列表。断开 ESP32 与 PC 的连接,然后重新连接,查看哪个端口从列表中消失,然后再次显示。 + +以下为 ESP32 DevKitC 和 ESP32 WROVER KIT 串口: + +.. figure:: ../../_static/esp32-devkitc-in-device-manager.png + :align: center + :alt: USB to UART bridge of ESP32-DevKitC in Windows Device Manager + :figclass: align-center + + 设备管理器中 ESP32-DevKitC 的 USB 串口转换器 + +.. figure:: ../../_static/esp32-wrover-kit-in-device-manager.png + :align: center + :alt: Two USB Serial Ports of ESP-WROVER-KIT in Windows Device Manager + :figclass: align-center + + Windows 设备管理器中的两个 USB-WROVER-KIT 串行端口 + +在 Linux 和 MacOS 上检查串口 +----------------------------- + +要查看 ESP32 开发板(或外部串口适配器)的串口设备名称,运行以下命令两次,第一次先拔下开发板或适配器,第二次插入开发板或适配器之后再运行命令,第二次运行指令后出现的端口即是 ESP32 对应的串口: + +Linux :: + + ls /dev/tty* + +MacOS :: + + ls /dev/cu.* + + +.. _linux-dialout-group-legacy: + +在 Linux 添加用户到 ``dialout`` +----------------------------------- + +当前登录用户可以通过 USB 读写串口。在大多数 Linux 发行版中,这是通过以下命令将用户添加到 ``dialout`` 组来完成的:: + + sudo usermod -a -G dialout $USER + +在 Arch Linux 中,需要通过以下命令将用户添加到 ``uucp`` 组中:: + + sudo usermod -a -G uucp $USER + +重新登录以确保串行端口的读写权限被启用。 + + +确认串口连接 +------------------------ + +现在验证串口连接是可用的。您可以使用串口终端程序来执行此操作。在这个例子中,我们将使用 `PuTTY SSH Client `_ ,它有 Windows 和 Linux 等平台的版本。您也可以使用其他串口程序并设置如下的通信参数。 + +运行终端,设置串口:波特率 = 115200,数据位 = 8,停止位 = 1,奇偶校验 = N。以下是设置串口和在 Windows 和 Linux 上传输参数(如 115200-8-1-N)的一些截屏示例。注意选择上述步骤中确认的串口进行设置。 + +.. figure:: ../../_static/putty-settings-windows.png + :align: center + :alt: Setting Serial Communication in PuTTY on Windows + :figclass: align-center + + 在 Windows 上的 PuTTY 设置串口传输。 + +.. figure:: ../../_static/putty-settings-linux.png + :align: center + :alt: Setting Serial Communication in PuTTY on Linux + :figclass: align-center + + 在 Linux 上的 PuTTY 设置串口传输。 + +在终端打开串口,检查是否有任何打印出来的日志。日志内容取决于加载到 ESP32 的应用程序。下图为 ESP32 的一个示例日志。 + +.. highlight:: none + +:: + + ets Jun 8 2016 00:22:57 + + rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + ets Jun 8 2016 00:22:57 + + rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + configsip: 0, SPIWP:0x00 + clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 + mode:DIO, clock div:2 + load:0x3fff0008,len:8 + load:0x3fff0010,len:3464 + load:0x40078000,len:7828 + load:0x40080000,len:252 + entry 0x40080034 + I (44) boot: ESP-IDF v2.0-rc1-401-gf9fba35 2nd stage bootloader + I (45) boot: compile time 18:48:10 + + ... + +如果您看到一些清晰的日志,则表示串行连接正常,您可以继续安装,最后将应用程序上载到 ESP32。 + +.. note:: + + 对于某些串口接线配置,在 ESP32 启动并产生串行输出之前,需要在终端程序中禁用串行 RTS & DTR 引脚。这取决于串口适配器硬件本身,大多数开发板(包括所有乐鑫开发板)没有这个问题。此问题仅存在于将 RTS & DTR 引脚直接连接到 EN & GPIO0 引脚上的情况。更多详细信息,参见 `esptool documentation`_。 + +.. note:: + + 验证通讯正常后关闭串口终端。下一步,我们将使用另一个应用程序来上传 ESP32。此应用程序在终端打开时将无法访问串口。 + +如您在安装用于 ESP32 开发的软件时,从 :ref:`get-started-connect-legacy` 小节跳转到了这里,请返回到 :ref:`get-started-configure-legacy` 小节继续阅读。 + +.. _esptool documentation: https://github.com/espressif/esptool/wiki/ESP32-Boot-Mode-Selection#automatic-bootloader + diff --git a/docs/zh_CN/get-started-cmake/index.rst b/docs/zh_CN/get-started-legacy/index.rst similarity index 52% rename from docs/zh_CN/get-started-cmake/index.rst rename to docs/zh_CN/get-started-legacy/index.rst index 73d4f05940..ed569835ee 100644 --- a/docs/zh_CN/get-started-cmake/index.rst +++ b/docs/zh_CN/get-started-legacy/index.rst @@ -1,12 +1,9 @@ -******************* -快速入门(CMake) -******************* - +*************************** +快速入门 (传统 GNU Make) +*************************** :link_to_translation:`en:[English]` -.. include:: ../cmake-warning.rst - -.. include:: ../cmake-pending-features.rst +.. include:: ../gnu-make-legacy.rst 本文档旨在指导用户搭建 ESP32 硬件开发的软件环境, @@ -40,13 +37,12 @@ ESP32 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、 软件: -* 设置 **工具链**,用于编译 ESP32 代码; -* **编译工具** —— CMake 和 Ninja 编译工具,用于编译 ESP32 **应用程序**; +* 设置 **工具链**,用于编译 ESP32 **应用程序**; * 获取 **ESP-IDF** 软件开发框架。该框架已经基本包含 ESP32 使用的 API(软件库和源代码)和运行 **工具链** 的脚本; * 安装 C 语言编程(**工程**)的 **文本编辑器**,例如 `Eclipse `_。 -.. figure:: ../../_static/what-you-need-cmake.png +.. figure:: ../../_static/what-you-need.png :align: center :alt: ESP32 应用程序开发 :figclass: align-center @@ -68,36 +64,35 @@ ESP32 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、 ESP32-Ethernet-Kit <../hw-reference/get-started-ethernet-kit> -.. _get-started-step-by-step-cmake: +.. _get-started-step-by-step-legacy: 详细安装步骤 -============== +============ 请根据下方详细步骤,完成安装过程。 设置开发环境 -~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~ -* :ref:`get-started-setup-toolchain-cmake` -* :ref:`get-started-get-esp-idf-cmake` -* :ref:`get-started-setup-path-cmake` -* :ref:`get-started-get-packages-cmake` +* :ref:`get-started-setup-toolchain-legacy` +* :ref:`get-started-get-esp-idf-legacy` +* :ref:`get-started-setup-path-legacy` +* :ref:`get-started-get-packages-legacy` 创建您的第一个工程 -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~ -* :ref:`get-started-start-project-cmake` -* :ref:`get-started-connect-cmake` -* :ref:`get-started-configure-cmake` -* :ref:`get-started-build-cmake` -* :ref:`get-started-flash-cmake` -* :ref:`get-started-build-monitor-cmake` +* :ref:`get-started-start-project-legacy` +* :ref:`get-started-connect-legacy` +* :ref:`get-started-configure-legacy` +* :ref:`get-started-build-and-flash-legacy` +* :ref:`get-started-monitor-legacy` -.. _get-started-setup-toolchain-cmake: +.. _get-started-setup-toolchain-legacy: 第一步:设置工具链 -==================== +================== 工具链指一套用于编译代码和应用程序的程序。 @@ -107,49 +102,44 @@ ESP32 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、 :hidden: Windows - Linux - MacOS + Linux + MacOS -+-------------------+-------------------+-------------------+ -| |windows-logo| | |linux-logo| | |macos-logo| | -+-------------------+-------------------+-------------------+ -| `Windows`_ | `Linux`_ | `Mac OS`_ | -+-------------------+-------------------+-------------------+ ++-----------------------------+-------------------------+----------------------------------+ +| |windows-logo| | |linux-logo| | |macos-logo| | ++-----------------------------+-------------------------+----------------------------------+ +| `Windows `_ | `Linux `_ | `Mac OS `_ | ++-----------------------------+-------------------------+----------------------------------+ .. |windows-logo| image:: ../../_static/windows-logo.png - :target: ../get-started-cmake/windows-setup.html + :target: ../get-started-legacy/windows-setup.html .. |linux-logo| image:: ../../_static/linux-logo.png - :target: ../get-started-cmake/linux-setup.html + :target: ../get-started-legacy/linux-setup.html .. |macos-logo| image:: ../../_static/macos-logo.png - :target: ../get-started-cmake/macos-setup.html + :target: ../get-started-legacy/macos-setup.html -.. _Windows: ../get-started-cmake/windows-setup.html -.. _Linux: ../get-started-cmake/linux-setup.html -.. _Mac OS: ../get-started-cmake/macos-setup.html +.. _Windows-legacy: ../get-started-legacy/windows-setup.html +.. _Linux-legacy: ../get-started-legacy/linux-setup.html +.. _Mac OS-legacy: ../get-started-legacy/macos-setup.html .. note:: 在本文档中,Linux 和 MacOS 操作系统中 ESP-IDF 的默认安装路径为 ``~/esp``;Windows 操作系统的默认路径为 ``%userprofile%\esp``。您也可以将 ESP-IDF 安装在任何其他路径下,但请注意在使用命令行时进行相应替换。注意,ESP-IDF 不支持带有空格的路径。 -此外, 您也可以根据自身经验和实际需求,对环境进行个性化设置,而非使用预制工具链。此时,请前往 :ref:`工具链的个性化设置` 章节获取更多信息。 +此外, 您也可以根据自身经验和实际需求,对环境进行个性化设置,而非使用预制工具链。此时,请前往 :ref:`工具链的个性化设置` 章节获取更多信息。 -.. _get-started-get-esp-idf-cmake: +.. _get-started-get-esp-idf-legacy: 第二步:获取 ESP-IDF -=========================== +===================== 除了工具链,您还需要供 ESP32 使用的 API(软件库和源代码),具体请见 `ESP-IDF 仓库 `_。 -请将 ESP-IDF 下载到您的本地。 - 获取本地副本:打开终端,切换到你要存放 ESP-IDF 的工作目录,使用 ``git clone`` 命令克隆远程仓库。 -Linux 和 MacOS 操作系统 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 打开终端,后运行以下命令: .. include:: /_build/inc/git-clone-bash.inc @@ -158,23 +148,6 @@ ESP-IDF 将下载至 ``~/esp/esp-idf``。 请前往 :doc:`/versions`,查看 ESP-IDF 不同版本的具体适用场景。 -Windows 操作系统 -~~~~~~~~~~~~~~~~~~ - -.. note:: - - 较早版本 ESP-IDF 使用了 **MSYS2 bash 终端** 命令行。目前,基于 CMake 的编译系统可使用常见的 **Windows 命令窗口**,即本指南中使用的终端。 - -请注意,如果您使用基于 bash 的终端或 PowerShell 终端,一些命令语法将与下面描述有所不同。 - -打开命令提示符,后运行以下命令: - -.. include:: /_build/inc/git-clone-windows.inc - -ESP-IDF 将下载至 ``%userprofile%\esp\esp-idf``。 - -请前往 :doc:`/versions`,查看 ESP-IDF 不同版本的具体适用场景。 - .. include:: /_build/inc/git-clone-notes.inc .. note:: @@ -184,45 +157,44 @@ ESP-IDF 将下载至 ``%userprofile%\esp\esp-idf``。 cd esp-idf git submodule update --init -.. _get-started-setup-path-cmake: + +.. _get-started-setup-path-legacy: 第三步:设置环境变量 -=========================== +===================== -请在您的 PC 上设置以下环境变量,否则无法编译工程。 +工具链通过环境变量 ``IDF_PATH`` 获得 ESP-IDF 的目录。因此,您需要在 PC 中设置该环境变量,否则无法编译工程。 -- ``IDF_PATH`` 应设置为 ESP-IDF 根目录的路径。 -- ``PATH`` 应包括同一 ``IDF_PATH`` 目录下的 ``tools`` 目录路径。 - -您可以在每次重启会话时手动设置,也可以在用户配置中进行永久设置,具体请前往 :doc:`add-idf_path-to-profile` 章节,查看 :ref:`Windows ` 、:ref:`Linux 及 MacOS ` 操作系统的具体设置方式。 +您可以在每次重启会话时手动设置,也可以在用户配置中进行永久设置,具体请前往 :doc:`add-idf_path-to-profile` 章节,查看 :ref:`Windows ` 、:ref:`Linux 及 MacOS ` 操作系统的具体设置方式。 -.. _get-started-get-packages-cmake: +.. _get-started-get-packages-legacy: 第四步:安装 Python 软件包 -================================= - -ESP-IDF 所需的 Python 软件包位于 ``IDF_PATH/requirements.txt`` 中。您可以运行以下命令进行安装: :: +========================== +ESP-IDF 所需 Python 软件包位于 ``IDF_PATH/requirements.txt`` 中。您可以运行以下命令进行安装: :: + python -m pip install --user -r $IDF_PATH/requirements.txt .. note:: - 请注意查询您所使用的 Python 解释器的版本(运行命令 ``python --version``),并根据查询结果将上方命令中的 ``python`` 替换为 ``python2``, ``python2.7``,例如: + 请注意查询您所使用的 Python 解释器的版本(运行命令 ``python --version``),并根据查询结果将上方命令中的 ``python`` 替换为 ``python2``, ``python2.7``,例如: :: - ``python2.7 -m pip install --user -r $IDF_PATH/requirements.txt`` + python2.7 -m pip install --user -r $IDF_PATH/requirements.txt -.. _get-started-start-project-cmake: + +.. _get-started-start-project-legacy: 第五步:开始创建工程 -======================= +===================== 现在,您可以开始准备开发 ESP32 应用程序了。您可以从 ESP-IDF 中 :idf:`examples` 目录下的 :example:`get-started/hello_world` 工程开始。 将 :example:`get-started/hello_world` 复制至您本地的 ``~/esp`` 目录下: Linux 和 MacOS 操作系统 -~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: bash @@ -230,7 +202,7 @@ Linux 和 MacOS 操作系统 cp -r $IDF_PATH/examples/get-started/hello_world . Windows 操作系统 -~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~ .. code-block:: batch @@ -243,10 +215,10 @@ ESP-IDF 的 :idf:`examples` 目录下有一系列示例工程,都可以按照 ESP-IDF 编译系统不支持带有空格的路径。 -.. _get-started-connect-cmake: - +.. _get-started-connect-legacy: + 第六步:连接设备 -====================== +================== 现在,请将您的 ESP32 开发板连接到 PC,并查看开发板使用的串口。 @@ -263,36 +235,28 @@ ESP-IDF 的 :idf:`examples` 目录下有一系列示例工程,都可以按照 请记住串口名,您会在下面的步骤中用到。 -.. _get-started-configure-cmake: +.. _get-started-configure-legacy: 第七步:配置 -================= +============= -请进入 :ref:`get-started-start-project-cmake` 中提到的 ``hello_world`` 目录,并运行工程配置工具 ``menuconfig``。 +请进入 :ref:`get-started-start-project-legacy` 中提到的 ``hello_world`` 目录,并运行工程配置工具 ``menuconfig``。 Linux 和 MacOS 操作系统 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: bash cd ~/esp/hello_world - idf.py menuconfig - -如果您的默认 Python 版本为 3.0 以上,可能需要运行 ``python2 idf.py`` 。 + make menuconfig Windows 操作系统 -~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~ .. code-block:: batch cd %userprofile%\esp\hello_world - idf.py menuconfig - -Python 2.7 安装程序将尝试配置 Windows,将 ``.py`` 文件与 Python 2 关联起来。如果其他程序(比如 Visual Studio Python 工具)曾关联了其他版本 Python,则 ``idf.py`` 可能无法正常运行(文件将在 Visual Studio 中打开)。这种情况下,您可以选择每次都运行一遍 ``C:\Python27\python idf.py``,或更改 Windows 的 ``.py`` 关联文件设置。 - -.. note:: - - 如果出现 ``idf.py not found(无法找到 idf.py)`` 错误,请确保 ``PATH`` 环境变量设置无误,具体请参考 :ref:`get-started-setup-path-cmake`。如果 ``tools`` 目录下没有 ``idf.py`` 文件,请确保 CMake 预览的分支正确无误,具体请参考 :ref:`get-started-get-esp-idf-cmake`。 + make menuconfig 如果之前的步骤都正确,则会显示下面的菜单: @@ -303,6 +267,8 @@ Python 2.7 安装程序将尝试配置 Windows,将 ``.py`` 文件与 Python 2 工程配置 — 主窗口 +进入菜单后,选择 ``Serial flasher config`` > ``Default serial port`` 配置串口(设备将通过该串口加载工程)。按回车键确认选择,点击 ``< Save >`` 保存配置,然后点击 ``< Exit >`` 退出 ``menuconfig``。 + ``menuconfig`` 工具的常见操作见下。 * ``上下箭头``:移动 @@ -310,118 +276,77 @@ Python 2.7 安装程序将尝试配置 Windows,将 ``.py`` 文件与 Python 2 * ``ESC 键``:返回上级菜单或退出 * ``英文问号``:调出帮助菜单(退出帮助菜单,请按回车键)。 * ``空格``、``Y 键``或``N 键``:使能/禁用 ``[*]`` 配置选项 -* ``英文问号``:调出有关高亮选项的帮助菜单 +* ``英文问号`` :调出有关高亮选项的帮助菜单 * ``/ 键``:寻找配置项目 +.. note:: + + 如果您是 **Arch Linux** 用户,请前往 ``SDK tool configuration``,并将 ``Python 2 interpreter`` 的名称从 ``python`` 替换为 ``python2``。 + .. attention:: 如果您使用的是 ESP32-DevKitC(板载 ESP32-SOLO-1 模组),请在烧写示例程序前,前往 ``menuconfig`` 中使能单核模式(:ref:`CONFIG_FREERTOS_UNICORE`)。 -.. _get-started-build-cmake: +.. _get-started-build-and-flash-legacy: -第八步:编译工程 -================== - -请使用以下命令,编译烧录工程::: - - idf.py build - -运行以上命令可以编译应用程序和所有 ESP-IDF 组件,接着生成 bootloader、分区表和应用程序二进制文件。 - -.. code-block:: none - - $ idf.py build - Running cmake in directory /path/to/hello_world/build - Executing "cmake -G Ninja --warn-uninitialized /path/to/hello_world"... - Warn about uninitialized values. - -- Found Git: /usr/bin/git (found version "2.17.0") - -- Building empty aws_iot component due to configuration - -- Component names: ... - -- Component paths: ... - - ... (more lines of build system output) - - [527/527] Generating hello-world.bin - esptool.py v2.3.1 - - Project build complete. To flash, run this command: - ../../../components/esptool_py/esptool/esptool.py -p (PORT) -b 921600 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x10000 build/hello-world.bin build 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin - or run 'idf.py -p PORT flash' - -如果一切正常,编译完成后将生成 .bin 文件。 - - -.. _get-started-flash-cmake: - -第九步:烧录到设备 +第八步:编译和烧录 ==================== -请使用以下命令,将刚刚生成的二进制文件烧录至您的 ESP32 开发板: :: +请使用以下命令,编译烧录工程: :: - idf.py -p PORT [-b BAUD] flash + make flash -请将 PORT 替换为 ESP32 开发板的串口名称,具体可见 :ref:`get-started-connect-cmake`。 +运行以上命令可以编译应用程序和所有 ESP-IDF 组件,接着生成 bootloader、分区表和应用程序二进制文件。接着,这些二进制文件将被烧录至 ESP32 开发板。 -您还可以将 BAUD 替换为您希望的烧录波特率。默认波特率为 ``460800``。 +如果一切顺利,您可在烧录完成后看到类似下方的打印信息(代表加载进程)。接着,开发板将会复位,应用程序 "hello_world" 开始启动。 -更多有关 idf.py 参数的详情,请见 :ref:`idf.py`。 +.. highlight:: none -.. note:: +:: - 勾选 ``flash`` 选项将自动编译并烧录工程,因此无需再运行 ``idf.py build``。 - -.. code-block:: none - - Running esptool.py in directory [...]/esp/hello_world - Executing "python [...]/esp-idf/components/esptool_py/esptool/esptool.py -b 460800 write_flash @flash_project_args"... - esptool.py -b 460800 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x1000 bootloader/bootloader.bin 0x8000 partition_table/partition-table.bin 0x10000 hello-world.bin - esptool.py v2.3.1 - Connecting.... - Detecting chip type... ESP32 - Chip is ESP32D0WDQ6 (revision 1) - Features: WiFi, BT, Dual Core + esptool.py v2.0-beta2 + Flashing binaries to serial port /dev/ttyUSB0 (app at offset 0x10000)... + esptool.py v2.0-beta2 + Connecting........___ Uploading stub... Running stub... Stub running... - Changing baud rate to 460800 + Changing baud rate to 921600 Changed. + Attaching SPI flash... Configuring flash size... - Auto-detected Flash size: 4MB + Auto-detected Flash size:4MB Flash params set to 0x0220 - Compressed 22992 bytes to 13019... - Wrote 22992 bytes (13019 compressed) at 0x00001000 in 0.3 seconds (effective 558.9 kbit/s)... + Compressed 11616 bytes to 6695... + Wrote 11616 bytes (6695 compressed) at 0x00001000 in 0.1 seconds (effective 920.5 kbit/s)... + Hash of data verified. + Compressed 408096 bytes to 171625... + Wrote 408096 bytes (171625 compressed) at 0x00010000 in 3.9 seconds (effective 847.3 kbit/s)... Hash of data verified. Compressed 3072 bytes to 82... - Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 5789.3 kbit/s)... + Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 8297.4 kbit/s)... Hash of data verified. - Compressed 136672 bytes to 67544... - Wrote 136672 bytes (67544 compressed) at 0x00010000 in 1.9 seconds (effective 567.5 kbit/s)... - Hash of data verified. - + Leaving... - Hard resetting via RTS pin... - -如果一切顺利,烧录完成后,开发板将会复位,应用程序 "hello_world" 开始运行。 - -.. note:: - - (目前不支持)如果您希望使用 Eclipse IDE,而非 ``idf.py``,请参考 :doc:`Eclipse 指南 `。 + Hard resetting... -.. _get-started-build-monitor-cmake: +如果您希望使用 Eclipse IDE,而非 ``make`` 编译系统,请参考 :doc:`Eclipse 指南 `。 -第十步:监视器 -================== -您可以使用 ``make monitor`` 命令,监视 “hello_world” 的运行情况。注意,不要忘记将 PORT 替换为您的串口名称。 +.. _get-started-monitor-legacy: + +第九步:监视器 +=============== + +您可以使用 ``make monitor`` 命令,监视 “hello_world” 的运行情况。 运行该命令后,:doc:`IDF 监视器 <../api-guides/tools/idf-monitor>` 应用程序将启动: :: - $ idf.py -p /dev/ttyUSB0 monitor - Running idf_monitor in directory [...]/esp/hello_world/build - Executing "python [...]/esp-idf/tools/idf_monitor.py -b 115200 [...]/esp/hello_world/build/hello-world.elf"... + $ make monitor + MONITOR --- idf_monitor on /dev/ttyUSB0 115200 --- - --- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- + --- Quit:Ctrl+] | Menu:Ctrl+T | Help:Ctrl+T followed by Ctrl+H --- ets Jun 8 2016 00:22:57 rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) @@ -435,7 +360,7 @@ Python 2.7 安装程序将尝试配置 Windows,将 ``.py`` 文件与 Python 2 ... Hello world! Restarting in 10 seconds... - I (211) cpu_start: Starting scheduler on APP CPU. + I (211) cpu_start:Starting scheduler on APP CPU. Restarting in 9 seconds... Restarting in 8 seconds... Restarting in 7 seconds... @@ -452,45 +377,71 @@ Python 2.7 安装程序将尝试配置 Windows,将 ``.py`` 文件与 Python 2 此时,请您: 1. 退出监视器。 -2. 打开 :ref:`menuconfig `, +2. 打开 :ref:`menuconfig `, 3. 进入 ``Component config`` --> ``ESP32-specific`` --> ``Main XTAL frequency`` 进行配置,将 :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` 设置为 26 MHz。 -4. 然后,请重新 :ref:`编译和烧录 ` 应用程序。 +4. 然后,请重新 :ref:`编译和烧录 ` 应用程序。 .. note:: - 您也可以运行以下命令,一次性执行构建、烧录和监视过程: + 您也可以运行以下命令,一次性执行构建、烧录和监视过程: :: - ``idf.py -p PORT flash monitor`` + make flash monitor -此外, - -- 请前往 :doc:`IDF 监视器 <../api-guides/tools/idf-monitor>`,了解更多使用 IDF 监视器的快捷键和其他详情。 -- 请前往 :ref:`idf.py`,查看更多 ``idf.py`` 命令和选项。 +此外,请前往 :doc:`IDF 监视器 <../api-guides/tools/idf-monitor>`,了解更多使用 IDF 监视器的快捷键和其他详情。 **恭喜,您已完成 ESP32 的入门学习!** 现在,您可以尝试一些其他 :idf:`examples`,或者直接开发自己的应用程序。 -更新 ESP-IDF -================= -乐鑫会不时推出更新版本的 ESP-IDF,修复 bug 或提出新的特性。因此,您在使用时,也应注意更新您本地的版本。最简单的方法是:直接删除您本地的 ``esp-idf`` 文件夹,然后按照 :ref:`get-started-get-esp-idf-cmake` 中的指示,重新完成克隆。 +环境变量 +========= + +用户可以在使用 ``make`` 命令时 **直接设置** 部分环境变量,而无需进入 ``make menuconfig`` 进行重新配置。这些变量包括: + ++-----------------+-----------------------------------------------------------------------+ +| 变量 | 描述与使用方式 | ++-----------------+-----------------------------------------------------------------------+ +| ``ESPPORT`` | 覆盖 ``flash`` 和 ``monitor`` 命令使用的串口。 | ++ +-----------------------------------------------------------------------+ +| | 例:``make flash ESPPORT=/dev/ttyUSB1``, ``make monitor ESPPORT=COM1``| ++-----------------+-----------------------------------------------------------------------+ +| ``ESPBAUD`` | 覆盖烧录 ESP32 时使用的串口速率。 | ++ +-----------------------------------------------------------------------+ +| | 例:``make flash ESPBAUD=9600`` | ++-----------------+-----------------------------------------------------------------------+ +| ``MONITORBAUD`` | 覆盖监控时使用的串口速率。 | ++ +-----------------------------------------------------------------------+ +| | 例:``make monitor MONITORBAUD=9600`` | ++-----------------+-----------------------------------------------------------------------+ + +.. note:: + + 您可导出环境变量(例:``export ESPPORT=/dev/ttyUSB1``)。 + 在同一会话窗口中,如果未被同步覆盖,所有 ``make`` 命令均会使用导出的环境变量值。 + + +更新 ESP-IDF +============= + +乐鑫会不时推出更新版本的 ESP-IDF,修复 bug 或提出新的特性。因此,在使用时,您也应注意更新您本地的版本。最简单的方法是:直接删除您本地的 ``esp-idf`` 文件夹,然后按照 :ref:`get-started-get-esp-idf-legacy` 中的指示,重新完成克隆。 如果您希望将 ESP-IDF 克隆到新的路径下,请务必 :doc:`重新设置 IDF_PATH `。否则,工具链将无法找到 ESP-IDF。 此外,您可以仅更新变更部分。具体方式,请前往 :ref:`更新 ` 章节查看。 相关文档 -=========== +========= .. toctree:: :maxdepth: 1 add-idf_path-to-profile establish-serial-connection + make-project eclipse-setup ../api-guides/tools/idf-monitor toolchain-setup-scratch .. _Stable version: https://docs.espressif.com/projects/esp-idf/zh_CN/stable/ -.. _Releases page: https://github.com/espressif/esp-idf/releases \ No newline at end of file +.. _Releases page: https://github.com/espressif/esp-idf/releases diff --git a/docs/zh_CN/get-started-legacy/linux-setup-scratch.rst b/docs/zh_CN/get-started-legacy/linux-setup-scratch.rst new file mode 100644 index 0000000000..bcab391d53 --- /dev/null +++ b/docs/zh_CN/get-started-legacy/linux-setup-scratch.rst @@ -0,0 +1,78 @@ +***************************************************** +从零开始设置 Linux 环境下的工具链 (传统 GNU Make) +***************************************************** +:link_to_translation:`en:[English]` + +.. include:: ../gnu-make-legacy.rst + +.. note:: + + 安装工具链的标准流程可以通过阅读文档 :doc:`Linux 平台工具链的标准设置 ` 来获得,:ref:`工具链的自定义设置 ` 章节会介绍哪些情况下我们必须要重新定义工具链。 + + +安装必要的工具 +============== + +要想使用 ESP-IDF 进行编译,您需要获取以下软件包: + +- Ubuntu 和 Debian:: + + sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing python-pyelftools + +- Arch:: + + sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing python2-pyelftools + +.. note:: + + 一些旧的(2014年之前)Linux 发行版中使用的 ``pyserial`` 版本可能是 2.x , ESP-IDF并不支持。 + 在这种情况下,请参考 :ref:`安装依赖的 Python 软件包 ` 章节,通过 ``pip`` 工具来安装支持的版本。 + +从源代码编译工具链 +================== + +- 安装依赖: + + - CentOS 7:: + + sudo yum install gawk gperf grep gettext ncurses-devel python python-devel automake bison flex texinfo help2man libtool + + - Ubuntu pre-16.04:: + + sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool + + - Ubuntu 16.04:: + + sudo apt-get install gawk gperf grep gettext python python-dev automake bison flex texinfo help2man libtool libtool-bin + + - Debian 9:: + + sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool libtool-bin + + - Arch:: + + TODO + +新建工作目录,然后进入:: + + mkdir -p ~/esp + cd ~/esp + + +下载 ``crosstool-NG`` 然后编译: + +.. include:: /_build/inc/scratch-build-code.inc + +编译工具链:: + + ./ct-ng xtensa-esp32-elf + ./ct-ng build + chmod -R u+w builds/xtensa-esp32-elf + +编译得到的工具链会被保存到 ``~/esp/crosstool-NG/builds/xtensa-esp32-elf``。根据 :ref:`Linux 下设置环境变量的标准方法 ` 中的介绍,将工具链添加到 ``PATH`` 中。 + + +下一步 +====== + +继续设置开发环境,请前往 :ref:`获取 ESP-IDF ` 章节。 diff --git a/docs/zh_CN/get-started-legacy/linux-setup.rst b/docs/zh_CN/get-started-legacy/linux-setup.rst new file mode 100644 index 0000000000..b51adb6764 --- /dev/null +++ b/docs/zh_CN/get-started-legacy/linux-setup.rst @@ -0,0 +1,108 @@ +******************************************* +Linux 平台工具链的标准设置 (传统 GNU Make) +******************************************* +:link_to_translation:`en:[English]` + +.. include:: ../gnu-make-legacy.rst + +安装前提 +===================== + +编译 ESP-IDF 需要以下软件包: + +- CentOS 7:: + + sudo yum install gcc git wget make ncurses-devel flex bison gperf python pyserial python-pyelftools + +- Ubuntu and Debian:: + + sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing python-pyelftools + +- Arch:: + + sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing python2-pyelftools + +.. note:: + + 一些旧的(2014年之前)Linux 发行版中使用的 ``pyserial`` 版本可能是 2.x , ESP-IDF并不支持。 + 在这种情况下,请参考 :ref:`安装依赖的 Python 软件包 ` 章节,通过 ``pip`` 工具来安装支持的版本。 + +工具链的设置 +=============== + +.. include:: /_build/inc/download-links.inc + +Linux 版的 ESP32 工具链可以从 Espressif 的网站下载: + +- 64-bit Linux: + + |download_link_linux64| + +- 32-bit Linux: + + |download_link_linux32| + +1. 下载完成后,将它解压到 ``~/esp`` 目录: : + + - 64-bit Linux: + + .. include:: /_build/inc/unpack-code-linux64.inc + + - 32-bit Linux: + + .. include:: /_build/inc/unpack-code-linux32.inc + +.. _setup-linux-toolchain-add-it-to-path-legacy: + +2. 工具链将会被解压到 ``~/esp/xtensa-esp32-elf/`` 目录。 + + 要使用工具链,你还需要在 ``~/.profile`` 文件中更新环境变量 ``PATH``。要使 ``xtensa-esp32-elf`` 在所有的终端会话中都有效,需要将下面这一行代码添加到你的 ``~/.profile`` 文件中: :: + + export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH" + + 或者你也可以给上面的命令创建一个别名。这样做的好处是,你只在需要使用它的时候才获取工具链。将下面这行代码添加到 ``~/.profile`` 文件中即可: :: + + alias get_esp32='export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH"' + + 然后,当你需要使用工具链时,在命令行输入 ``get_esp32``,然后工具链会自动添加到你的 ``PATH`` 中。 + + .. note:: + + 如果将 ``/bin/bash`` 设置为登录 shell,且同时存在 ``.bash_profile`` 和 ``.profile``,则更新 ``.bash_profile`` 。在 CentOS 环境下, ``alias`` 需要添加到 ``.bashrc`` 文件中。 + +3. 退出并重新登录以使 ``.profile`` 更改生效。 运行以下命令来检查 ``PATH`` 设置是否正确: :: + + printenv PATH + + 检查字符串的开头是否包含类似的工具链路径:: + + $ printenv PATH + /home/user-name/esp/xtensa-esp32-elf/bin:/home/user-name/bin:/home/user-name/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin + + 除了 ``/home/user-name``,应该有具体的安装的主路径。 + +权限问题 /dev/ttyUSB0 +------------------------------ + +某些 Linux 版本可能在烧写 ESP32 时会出现 ``Failed to open port /dev/ttyUSB0`` 错误消息。 :ref:`可以通过将当前用户添加到拨出组来解决`。 + +Arch Linux 用户 +---------------- + +在 Arch 中运行预编译的 gdb (xtensa-esp32-elf-gdb) 需要 ncurses 5,但是 Arch 使用的是 ncurses 6。在 AUR_ 中向下兼容的库文件,可用于本地和 lib32 的配置: + +- https://aur.archlinux.org/packages/ncurses5-compat-libs/ +- https://aur.archlinux.org/packages/lib32-ncurses5-compat-libs/ + +在安装这些软件包之前,你可能需要将作者的公钥添加到你的钥匙圈中,上面链接中的“Comments”部分有所叙述。 + +或者,你也可以使用 crosstool-NG 编译一个链接 ncurses 6 的 gdb。 + +后续步骤 +========== + +要继续设置开发环境,请参考 :ref:`get-started-get-esp-idf-legacy` 一节。 + + +.. _AUR: https://wiki.archlinux.org/index.php/Arch_User_Repository + diff --git a/docs/zh_CN/get-started-legacy/macos-setup-scratch.rst b/docs/zh_CN/get-started-legacy/macos-setup-scratch.rst new file mode 100644 index 0000000000..fad2de3d60 --- /dev/null +++ b/docs/zh_CN/get-started-legacy/macos-setup-scratch.rst @@ -0,0 +1,74 @@ +************************************************** +从零开始设置 Mac OS 环境下的工具链 (传统 GNU Make) +************************************************** +:link_to_translation:`en:[English]` + +.. include:: ../gnu-make-legacy.rst + +.. note:: + + 安装工具链的标准流程可以通过阅读文档 :doc:`在 MacOS 上安装 ESP32 工具链 ` 来获得, :ref:`工具链的自定义设置 ` 章节会介绍哪些情况下我们必须要重新定义工具链。 + +安装必要的工具 +===================== + +- 安装 pip:: + + sudo easy_install pip + +.. note:: + + ``pip`` 稍后将用于安装 :ref:`必要的 Python 软件包 `。 + +从源代码编译工具链 +================== + +- 安装依赖: + + - 安装 MacPorts_ 或者 homebrew_ 包管理器。MacPorts 需要安装完整的 XCode 软件,但是 homebrew 只需要安装 XCode 命令行工具即可。 + + .. _homebrew: https://brew.sh/ + .. _MacPorts: https://www.macports.org/install.php + + - 对于 MacPorts:: + + sudo port install gsed gawk binutils gperf grep gettext wget libtool autoconf automake + + - 对于 homebrew:: + + brew install gnu-sed gawk binutils gperftools gettext wget help2man libtool autoconf automake + +创建大小写敏感的文件系统镜像:: + + hdiutil create ~/esp/crosstool.dmg -volname "ctng" -size 10g -fs "Case-sensitive HFS+" + +挂载:: + + hdiutil mount ~/esp/crosstool.dmg + +创建指向你工作目录的符号链接:: + + mkdir -p ~/esp + ln -s /Volumes/ctng ~/esp/ctng-volume + +进入新创建的工作目录:: + + cd ~/esp/ctng-volume + +下载 ``crosstool-NG`` 然后编译: + +.. include:: /_build/inc/scratch-build-code.inc + +编译工具链:: + + ./ct-ng xtensa-esp32-elf + ./ct-ng build + chmod -R u+w builds/xtensa-esp32-elf + +编译得到的工具链会被保存到 ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf``。根据 :ref:`Mac OS 下设置环境变量的标准方法 ` 中的介绍,将工具链添加到 ``PATH`` 中。 + + +下一步 +====== + +继续设置开发环境,请前往 :ref:`获取 ESP-IDF ` 章节。 diff --git a/docs/zh_CN/get-started-legacy/macos-setup.rst b/docs/zh_CN/get-started-legacy/macos-setup.rst new file mode 100644 index 0000000000..90f032897b --- /dev/null +++ b/docs/zh_CN/get-started-legacy/macos-setup.rst @@ -0,0 +1,60 @@ +************************************************ +在 Mac OS 上安装 ESP32 工具链 (传统 GNU Make) +************************************************ +:link_to_translation:`en:[English]` + +.. include:: ../gnu-make-legacy.rst + +安装准备 +================ + +- 安装 pip:: + + sudo easy_install pip + +.. note:: + + ``pip`` 稍后将用于安装 :ref:`必要的 Python 软件包 `。 + +安装工具链 +=============== + +.. include:: /_build/inc/download-links.inc + +Mac OS 版本的 ESP32 工具链可以从以下地址下载: + +|download_link_osx| + +下载压缩文件之后,解压到 ``~/esp`` 目录中: + +.. include:: /_build/inc/unpack-code-osx.inc + +.. _setup-macos-toolchain-add-it-to-path-legacy: + +工具链将被解压到 ``~/esp/xtensa-esp32-elf/`` 路径下。 + +在 ``~/.profile`` 文件中更新 ``PATH`` 环境变量以使用工具链。为了使 ``xtensa-esp32-elf`` 在各种终端会话中都可用,在 ``~/.profile`` 文件中加上以下指令:: + + export PATH=$HOME/esp/xtensa-esp32-elf/bin:$PATH + +或者,您可以为上述命令创建一个别名。这样只有执行以下指令时工具链才能被使用。将下面的指令添加到您的 ``〜/ .profile`` 文件中:: + + alias get_esp32="export PATH=$HOME/esp/xtensa-esp32-elf/bin:$PATH" + +当需要使用工具链时,在命令行里输入 ``get_esp32``,就可以将工具链添加到 ``PATH`` 中。 + + +下一步 +========== + +前往 :ref:`get-started-get-esp-idf-legacy` 继续配置开发环境。 + + +相关文档 +================= + +.. toctree:: + :maxdepth: 1 + + macos-setup-scratch + diff --git a/docs/zh_CN/get-started/make-project.rst b/docs/zh_CN/get-started-legacy/make-project.rst similarity index 94% rename from docs/zh_CN/get-started/make-project.rst rename to docs/zh_CN/get-started-legacy/make-project.rst index 6456d8ef09..cd4031b36e 100644 --- a/docs/zh_CN/get-started/make-project.rst +++ b/docs/zh_CN/get-started-legacy/make-project.rst @@ -1,7 +1,9 @@ -通过 make 指令创建和烧录项目 -============================= +通过 make 指令创建和烧录项目 (传统 GNU Make) +============================================ :link_to_translation:`en:[English]` +.. include:: ../gnu-make-legacy.rst + 寻找项目 ----------------- diff --git a/docs/zh_CN/get-started-legacy/toolchain-setup-scratch.rst b/docs/zh_CN/get-started-legacy/toolchain-setup-scratch.rst new file mode 100644 index 0000000000..c73c7e80da --- /dev/null +++ b/docs/zh_CN/get-started-legacy/toolchain-setup-scratch.rst @@ -0,0 +1 @@ +.. include:: ../../en/get-started-legacy/toolchain-setup-scratch.rst diff --git a/docs/zh_CN/get-started-legacy/windows-setup-scratch.rst b/docs/zh_CN/get-started-legacy/windows-setup-scratch.rst new file mode 100644 index 0000000000..02d164df02 --- /dev/null +++ b/docs/zh_CN/get-started-legacy/windows-setup-scratch.rst @@ -0,0 +1 @@ +.. include:: ../../en/get-started-legacy/windows-setup-scratch.rst diff --git a/docs/zh_CN/get-started-legacy/windows-setup.rst b/docs/zh_CN/get-started-legacy/windows-setup.rst new file mode 100644 index 0000000000..ab1bed7d36 --- /dev/null +++ b/docs/zh_CN/get-started-legacy/windows-setup.rst @@ -0,0 +1,69 @@ +********************************************** +Windows 平台工具链的标准设置 (传统 GNU Make) +********************************************** +:link_to_translation:`en:[English]` + +.. include:: ../gnu-make-legacy.rst + +引言 +============ + +Windows 没有内置的 "make" 环境,因此如果要安装工具链,你需要一个 GNU 兼容环境。我们这里使用 MSYS2_ 来提供该环境。你不需要一直使用这个环境(你可以使用 :doc:`Eclipse ` 或其它前端工具),但是它是在后台运行的。 + +工具链的设置 +=============== + +快速设置的方法是从 dl.espressif.com 下载集成在一起的工具链和 MSYS2 压缩文件: + +https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20181001.zip + +将 zip 压缩文件解压到 ``C:\`` (或其它路径,这里假设是 ``C:\``),它会使用预先准备的环境创建一个 ``msys32`` 目录。 + +检出 +============ + +运行 ``C:\msys32\mingw32.exe`` 打开一个 MSYS2 的终端窗口。该窗口的环境是一个 bash shell。创建一个 ``esp`` 目录作为开发 ESP32 应用的默认地址。运行指令 :: + + mkdir -p ~/esp + +输入 ``cd ~/esp`` 就进入到新创建的目录。如果没有错误信息出现则表明此步骤已完成。 + + +.. figure:: ../../_static/msys2-terminal-window.png + :align: center + :alt: MSYS2 MINGW32 shell window + :figclass: align-center + + MSYS2 终端窗口 + +后续步骤将会使用这个窗口来为 ESP32 设置开发环境。 + +后续步骤 +========== + +要继续设置开发环境,请参考 :ref:`get-started-get-esp-idf-legacy` 一节。 + +更新环境 +======================== + +当 IDF 更新时,有时需要新的工具链,或者将新的需求添加到 Windows MSYS2 环境中。要将旧版本的预编译环境中的数据移动到新版本: + +- 把旧的 MSYS2 环境(即 ``C:\msys32``)移动/重命名为不同的目录(即 ``C:\msys32_old``)。 +- 按照前文所述步骤下载新的预编译环境。 +- 将新的 MSYS2 环境解压缩到 ``C:\msys32`` (或其他位置)。 +- 找到旧的 ``C:\msys32_old\home`` 目录并把它移到 ``C:\msys32``。 +- 如果你不再需要 ``C:\msys32_old`` 可以将它删除。 + +你可以在系统上拥有独立的不同的 MSYS2 环境,前提是在不同的目录中。 + +相关文档 +================= + +.. toctree:: + :maxdepth: 1 + + windows-setup-scratch + + +.. _MSYS2: https://msys2.github.io/ + diff --git a/docs/zh_CN/get-started/add-idf_path-to-profile.rst b/docs/zh_CN/get-started/add-idf_path-to-profile.rst index 61e8d3dbb0..5c051fe533 100644 --- a/docs/zh_CN/get-started/add-idf_path-to-profile.rst +++ b/docs/zh_CN/get-started/add-idf_path-to-profile.rst @@ -1,64 +1,73 @@ -在用户配置文件中添加 IDF_PATH -============================== -:link_to_translation:`en:[English]` +在用户配置文件中添加 IDF_PATH 和 idf.py PATH +========================================================================================================== -为了在系统多次重新启动时保留 “IDF_PATH” 环境变量的设置,请按照以下说明将其添加到用户配置文件中。 +:link_to_translation:`en:[英文]` -.. _add-idf_path-to-profile-windows: +使用基于 CMake 的构建系统和 idf.py 工具,用户需修改两处系统环境变量: +- ``IDF_PATH`` 需设置为含有 ESP-IDF 目录的路径 +- 系统 ``PATH`` 变量需包括含有 ``idf.py`` 工具 (属于 ESP-IDF 一部分)的目录 -Windows -------- +为确保系统重启后仍保存之前的变量设置,请参照以下说明将变量设置添加到用户配置文件中。 -用户配置文件脚本存放在 ``C:/msys32/etc/profile.d/`` 目录中。每次打开 MSYS2 窗口时,系统都执行这些脚本。 +.. note:: 使用 IDE 工具的情况下,你可以选择在 IDE 项目环境中设置环境变量,而不使用如下命令行。 +.. note:: 如果你从未用过 ``idf.py`` 命令行工具,而是直接运行 cmake 或通过 IDE 工具运行 cmake,则无需设置 ``PATH`` 变量,只需设置 ``IDF_PATH`` 变量。不过,你也可以两个都设置。 -#. 在 ``C:/msys32/etc/profile.d/`` 目录下创建一个新的脚本文件。将其命名为 ``export_idf_path.sh``。 +.. note:: 如果你只用过 ``idf.py`` 命令行工具,从未直接运行 cmake 或通过 IDE 工具运行 cmake,则无需设置 ``IDF_PATH`` 变量。``idf.py`` 会搜索自身包含的目录,如果没有发现 ``IDF_PATH``,则会自行进行有关设置。 -#. 确定 ESP-IDF 目录的路径。路径与系统配置有关,例如 ``C:\msys32\home\user-name\esp\esp-idf``。 -#. 在脚本中加入 ``export`` 命令,e.g.:: +.. _add-paths-to-profile-windows: - export IDF_PATH="C:/msys32/home/user-name/esp/esp-idf" +Windows 操作系统 +----------------------------------- - 请将原始 Windows 路径中将反斜杠替换为正斜杠。 +在 Windows 10 操作系统下设置环境变量,用户应在开始菜单下搜索 "Edit Environment Variables"。 -#. 保存脚本。 +在较早版本的 Windows 操作系统下设置环境变量,用户应打开系统控制面板,选择“高级”,找到环境变量按钮。 -#. 关闭 MSYS2 窗口并再次打开。输入以下命令检查是否设置了 ``IDF_PATH``:: +你可以为本台电脑上的“所有用户”或“当前用户”设置环境变量,这取决于其他用户是否也需要使用 ESP-IDF。 - printenv IDF_PATH +- 点击 ``New...`` (新建...) 添加名为 ``IDF_PATH`` 的新系统变量,具体设置为包含 ESP-IDF 的目录,例如,``C:\Users\user-name\esp\esp-idf``。 +- 找到 ``Path`` 环境变量,双击进行编辑。在末尾添加 ``;%IDF_PATH%\tools``,这样你就可以通过 Windows 命令窗口运行 ``idf.py`` 等其他工具了。 -将此前在脚本文件中输入的路径打印出来。 +如果你在安装 ESP32 硬件开发的软件环境时,从 :ref:`get-started-setup-path` 小节跳到了这里,请返回 :ref:`get-started-start-project` 小节开始阅读。 -如果您不想在用户配置文件中永久设置 ``IDF_PATH``,则应在打开 MSYS2 窗口时手动输入:: - - export IDF_PATH="C:/msys32/home/user-name/esp/esp-idf" - -如您在安装用于 ESP32 开发的软件时,从 :ref:`get-started-setup-path` 小节跳转到了这里,请返回到 :ref:`get-started-start-project` 小节。 .. _add-idf_path-to-profile-linux-macos: -Linux and MacOS ---------------- +Linux 和 MacOS 操作系统 +------------------------------------ -在 ``~/.profile`` 文件中加入以下指令,创建 ``IDF_PATH``: +要设置 ``IDF_PATH``,并在 PATH 中添加 ``idf.py``,请将以下两行代码添加至你的 ``~/.profile`` 文件中:: export IDF_PATH=~/esp/esp-idf - -注销并重新登录以使此更改生效。 + export PATH="$IDF_PATH/tools:$PATH" .. note:: - 如果将 ``/bin/bash`` 已设为登录 shell,并且 ``.bash_profile`` 和 ``.profile`` 同时存在,则更新 ``.bash_profile``。 - -运行以下命令以确保 ``IDF_PATH`` 已经设置好:: + ``~/.profile`` 表示在你的电脑用户主目录中,后缀为 ``.profile`` 的文件。(``~`` 为 shell 中的缩写)。 + +请退出,并重新登录使更改生效。 + +.. note:: + + 并非所有 shell 都使用 ``.profile``,但是如果同时存在 ``/bin/bash`` 和 ``.bash_profile``,请更新此配置文件。如果存在 ``zsh``,请更新 ``.zprofile``。其他 shell 可能使用其他配置文件(详询有关 shell 的文档)。 + +运行以下命令来检查 ``IDF_PATH`` 设置是否正确:: printenv IDF_PATH -此前在 ``~/.profile`` 文件中输入(或者手动设置)的路径应该被打印出来。 +此处应打印出此前在 ``~/.profile`` 文件中输入(或手动设置)的路径。 -如果不想永久设置 ``IDF_PATH``,每次重启或者注销时在终端窗口中手动输入:: +为确认 ``idf.py`` 目前是否在 ``PATH`` 中,你可以运行以下命令:: + + which idf.py + +这里,应打印出类似 ``${IDF_PATH}/tools/idf.py`` 的路径。 + +如果不想修改 ``IDF_PATH`` 或 ``PATH``,你可以在每次重启或退出后在终端中手动输入:: export IDF_PATH=~/esp/esp-idf + export PATH="$IDF_PATH/tools:$PATH" -如果您从 :ref:`get-started-setup-path` 小节跳转到了这里,在安装用于 ESP32 开发的软件时,返回到 :ref:`get-started-start-project` 小节。 +如果你在安装 ESP32 硬件开发的软件环境时,从 :ref:`get-started-setup-path` 小节跳到了这里,请返回 :ref:`get-started-start-project` 小节开始阅读。 diff --git a/docs/zh_CN/get-started/eclipse-setup.rst b/docs/zh_CN/get-started/eclipse-setup.rst index 13e66b8269..0665447085 100644 --- a/docs/zh_CN/get-started/eclipse-setup.rst +++ b/docs/zh_CN/get-started/eclipse-setup.rst @@ -1,113 +1,9 @@ -**************************** -Eclipse IDE 的创建和烧录指南 -**************************** +**************************************** +Eclipse IDE 创建和烧录指南 +**************************************** + :link_to_translation:`en:[English]` -.. _eclipse-install-steps: - -安装 Eclipse IDE -================ - -Eclipse IDE 是一个可视化的集成开发环境,可用于编写、编译和调试 ESP-IDF 项目。 - -* 首先,请在您的平台上安装相应的 ESP-IDF,具体步骤请参考适用于 Windows、OS X 和 Linux 的相应安装步骤。 - -* 我们建议,您应首先使用命令行创建一个项目,大致熟悉项目的创建流程。此外,您还需要使用命令行 (``make menuconfig``) 对您的 ESP-IDF 项目进行配置。目前,Eclipse 尚不支持对 ESP-IDF 项目进行配置。 - -* 下载相应版本的 Eclipse Installer 至您的平台,点击 eclipse.org_。 - -* 运行 Eclipse Installer,选择 “Eclipse for C/C++ Development”(有的版本也可能显示为 CDT)。 - - -配置 Eclipse IDE -================= - -请打开安装好的 Eclipse IDE,并按照以下步骤进行操作: - -导入新项目 ----------- - -* Eclipse IDE 需使用 ESP-IDF 的 Makefile 功能。因此,在使用 Eclipse 前,您需要先创建一个 ESP-IDF 项目。在创建 ESP-IDF 项目时,您可以使用 GitHub 中的 idf-template 项目模版,或从 esp-idf 子目录中选择一个 example。 - -* 运行 Eclipse,选择 “File” -> “Import...”。 - -* 在弹出的对话框中选择 “C/C++” -> “Existing Code as Makefile Project”,然后点击 “Next”。 - -* 在下个界面中 “Existing Code Location” 位置输入您的 IDF 项目的路径。注意,这里应输入 ESP-IDF 项目的路径,而非 ESP-IDF 本身的路径(这个稍后再填)。此外,您指定的目标路径中应包含名为 ``Makefile`` (项目 Makefile)的文件。 - -* 在本界面,找到 “Toolchain for Indexer Settings”,选择 “Cross GCC”,最后点击 “Finish”。 - - -项目属性 --------- - -* 新项目将出现在 “Project Explorer” 下。请右键选择该项目,并在菜单中选择 “Properties”。 - -* 点击 “C/C++ Build” 下的 “Environment” 属性页,选择 “Add...”,并在对应位置输入 ``BATCH_BUILD`` 和 ``1``。 - -* 再次点击 “Add...”,并在 “IDF_PATH” 中输入 ESP-IDF 所在的完整安装路径。 - -* 选择 “PATH” 环境变量,不要改变默认值。如果 Xtensa 工具链的路径尚不在 “PATH” 列表中,则应将该路径 (``something/xtensa-esp32-elf/bin``) 增加至列表,工具链的典型路径类似于 ``/home/user-name/esp/xtensa-esp32-elf/bin``。请注意您需要在附加路径前添加冒号 ``:``。Windows 用户需要将 ``C:\msys32\mingw32\bin;C:\msys32\opt\xtensa-esp32-elf\bin;C:\msys32\usr\bin`` 添加到 ``PATH`` 环境变量的靠前位置(如果您将 msys32 安装到了其它目录,则需要更改对应的路径以匹配您的本地环境)。 - -* 在 macOS 平台上,增加一个 “PYTHONPATH” 环境变量,并将其设置为 ``/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages``, 保证系统中预先安装的 Python (需安装 pyserial 模块)可以覆盖 Eclipse 内置的任何 Python。 - -* 前往 “C/C++ General” -> “Preprocessor Include Paths” 属性页面。 - - * 点击 “Providers” 选项卡。 - - * 从 “Providers” 列表中选择 “CDT Cross GCC Built-in Compiler Settings”,将 “Command to get compiler specs” 修改为 ``xtensa-esp32-elf-gcc ${FLAGS} -std=c++11 -E -P -v -dD "${INPUTS}"`` - - * 从 “Providers” 列表中选择 “CDT GCC Build Output Parser”,将 “Compiler command pattern” 修改为 ``xtensa-esp32-elf-(gcc|g\+\+|c\+\+|cc|cpp|clang)`` - -* 前往 “C/C++ General” -> “Indexer” 属性页面。 - - * 去除 "Allow heuristic resolution of includes" 勾选。启用此选项时,Eclipse 有时无法找到正确的头文件目录。 - -点击 “C/C++ General" -> "Indexer” 属性页。 - - * 选择 “Enable project specific settings” 以启用本页上的其他设置。 - -.. note:: - - 取消选中 “Allow heuristic resolution of includes”。因为启用此选项时,有时会导致 Eclipse 无法找到正确的头文件目录。 - -点击 “C/C++ Build” -> “Behavior” 属性页。 - -* 选中 “Enable parallel build” 以启用多任务并行构建。 - -.. _eclipse-build-project: - -在 Eclipse IDE 中创建项目 --------------------------- - -在首次创建项目前,Eclipse IDE 可能会显示大量有关未定义值的错误和警告,主要原因在于项目编译过程中所需的一些源文件是在 ESP-IDF 项目创建过程中自动生成的。因此,这些错误和警告将在 ESP-IDF 项目生成完成后消失。 - -* 点击 “OK”,关闭 Eclipse IDE 中的 “Properties” 对话框。 - -* 在 Eclipse IDE 界面外,打开命令管理器。进入项目目录,并通过 ``make menuconfig`` 命令对您的 ESP-IDF 项目进行配置。现阶段,您还无法在 Eclipse 中完成本操作。 - -*如果您未进行最开始的配置步骤,ESP-IDF 将提示在命令行中进行配置 - 但由于 Eclipse 暂时不支持相关功能,因此该项目将挂起或创建失败。* - -* 返回 Eclipse IDE 界面中,选择 “Project” -> “Build” 创建您的项目。 - -**提示**:如果您已经在 Eclipse IDE 环境外创建了项目,则可能需要选择 “Project” -> “Clean before choosing Project” -> “Build”,允许 Eclipse 查看所有源文件的编译器参数,并借此确定头文件包含路径。 - -在 Eclipse IDE 中烧录项目 --------------------------- - -您可以将 ``make flash`` 目标放在 Eclipse 项目中,通过 Eclipse UI 调用 ``esptool.py`` 进行烧录: - -* 打开 “Project Explorer”,并右击您的项目(请注意右击项目本身,而非项目下的子文件,否则 Eclipse 可能会找到错误的 ``Makefile``)。 - -* 从菜单中选择 “Build Targets” -> “Create”。 - -* 输入 “flash” 为目标名称,其他选项使用默认值。 - -* 选择 “Project” -> “Build Target” -> “Build (快捷键:Shift + F9)”,创建自定义烧录目标,用于编译、烧录项目。 - -注意,您将需要通过 ``make menuconfig``,设置串行端口和其他烧录选项。``make menuconfig`` 仍需通过命令行操作(请见平台的对应指南)。 - -如有需要,请按照相同步骤添加 ``bootloader`` 和 ``partition_table``。 - +有关基于 CMake-based 构建系统和 Eclipse CDT,进行 Eclipse 设置的相关文档即将发布。 .. _eclipse.org: https://www.eclipse.org/ diff --git a/docs/zh_CN/get-started/establish-serial-connection.rst b/docs/zh_CN/get-started/establish-serial-connection.rst index b27c429625..0219250dd2 100644 --- a/docs/zh_CN/get-started/establish-serial-connection.rst +++ b/docs/zh_CN/get-started/establish-serial-connection.rst @@ -1,47 +1,67 @@ 与 ESP32 创建串口连接 -========================= +============================================== + :link_to_translation:`en:[English]` -本章节介绍如何在 ESP32 和 PC 之间建立串口连接。 +本章节主要介绍如何创建 ESP32 和 PC 之间的串口连接。 + 连接 ESP32 和 PC -------------------- -用 USB 线将 ESP32 开发板连接到 PC。如果设备驱动程序没有自动安装,确认 ESP32 开发板上的 USB 转串口芯片(或外部串口适配器)型号,在网上搜索驱动程序并进行安装。 +用 USB 线将 ESP32 开发板连接到 PC。如果设备驱动程序没有自动安装,请先确认 ESP32 开发板上的 USB 转串口芯片(或外部转串口适配器)型号,然后在网上搜索驱动程序,并进行手动安装。 以下是乐鑫 ESP32 开发板驱动程序的链接: -* ESP32-PICO-KIT 和 ESP32-DevKitC - `CP210x USB to UART Bridge VCP Drivers `_ +.. csv-table:: + :header: 开发板, USB 驱动, 备注 + :widths: 40, 20, 40 -* ESP32-WROVER-KIT 和 ESP32 Demo Board - `FTDI Virtual COM Port Drivers `_ + :ref:`ESP32-DevKitC `, `CP210x`_ + `ESP32-LyraT `_, `CP210x`_ + `ESP32-LyraTD-MSC `_, `CP210x`_ + :ref:`ESP32-PICO-KIT `, `CP210x`_ + :ref:`ESP-WROVER-KIT `, `FTDI`_ + :ref:`ESP32 Demo 板 `, `FTDI`_ + `ESP-Prog`_, `FTDI`_, 编程板 (w/o ESP32) + `ESP32-MeshKit-Sense `_, n/a, 搭配 `ESP-Prog`_ 使用 + `ESP32-Sense Kit `_, n/a, 搭配 `ESP-Prog`_ 使用 -以上驱动仅用于参考。当您将上述 ESP32 开发板与 PC 连接时,对应驱动程序应该已经被打包在操作系统中并自动安装。 +.. _CP210x: https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers +.. _FTDI: http://www.ftdichip.com/Drivers/VCP.htm +.. _ESP-Prog: https://github.com/espressif/esp-iot-solution/blob/master/documents/evaluation_boards/ESP-Prog_guide_en.md#introduction-to-the-esp-prog-board + +* CP210x: `CP210x USB 至 UART 桥 VCP 驱动程序 `_ +* FTDI: `FTDI 虚拟 COM 端口驱动程序 `_ + +以上驱动仅用于参考。一般情况下,当上述任一 ESP32 开发板与 PC 连接时,对应驱动程序应该已经被打包在操作系统中,并已经自动安装。 在 Windows 上查看端口 --------------------- -检查 Windows 设备管理器中的 COM 端口列表。断开 ESP32 与 PC 的连接,然后重新连接,查看哪个端口从列表中消失,然后再次显示。 +检查 Windows 设备管理器中的 COM 端口列表。断开 ESP32 与 PC 的连接,然后重新连接,查看哪个端口从列表中消失,然后再次出现。 以下为 ESP32 DevKitC 和 ESP32 WROVER KIT 串口: .. figure:: ../../_static/esp32-devkitc-in-device-manager.png :align: center - :alt: USB to UART bridge of ESP32-DevKitC in Windows Device Manager + :alt: 设备管理器中 ESP32-DevKitC 的 USB 至 UART 桥 :figclass: align-center - 设备管理器中 ESP32-DevKitC 的 USB 串口转换器 + 设备管理器中 ESP32-DevKitC 的 USB 至 UART 桥 .. figure:: ../../_static/esp32-wrover-kit-in-device-manager.png :align: center - :alt: Two USB Serial Ports of ESP-WROVER-KIT in Windows Device Manager + :alt: Windows 设备管理器中 ESP-WROVER-KIT 的两个 USB 串行端口 :figclass: align-center - Windows 设备管理器中的两个 USB-WROVER-KIT 串行端口 + Windows 设备管理器中 ESP-WROVER-KIT 的两个 USB 串行端口 -在 Linux 和 MacOS 上检查串口 + +在 Linux 和 MacOS 上查看端口 ----------------------------- -要查看 ESP32 开发板(或外部串口适配器)的串口设备名称,运行以下命令两次,第一次先拔下开发板或适配器,第二次插入开发板或适配器之后再运行命令,第二次运行指令后出现的端口即是 ESP32 对应的串口: +查看 ESP32 开发板(或外部转串口适配器)的串口设备名称,请运行两次以下命令。首先,断开开发板或适配器,第一次运行命令;然后,连接开发板或适配器,第二次运行命令。其中,第二次运行命令后出现的端口即是 ESP32 对应的串口: Linux :: @@ -51,13 +71,16 @@ MacOS :: ls /dev/cu.* +.. note:: + + 对于 MacOS 用户:若你没有看到串口,请检查你是否已按照《入门指南》安装了适用于你特定开发板的 USB/串口驱动程序。对于 MacOS High Sierra (10.13) 的用户,你可能还需要手动允许驱动程序的加载,具体可打开 ``系统偏好设置`` -> ``安全和隐私`` -> ``通用``,检查是否有信息显示:“来自开发人员的系统软件...”,其中开发人员的名称为 Silicon Labs 或 FTDI。 .. _linux-dialout-group: -在 Linux 添加用户到 ``dialout`` +在 Linux 中添加用户到 ``dialout`` ----------------------------------- -当前登录用户可以通过 USB 读写串口。在大多数 Linux 发行版中,这是通过以下命令将用户添加到 ``dialout`` 组来完成的:: +当前登录用户应当可以通过 USB 对串口进行读写操作。在多数 Linux 版本中,你都可以通过以下命令,将用户添加到 ``dialout`` 组,来获许读写权限:: sudo usermod -a -G dialout $USER @@ -65,31 +88,32 @@ MacOS :: sudo usermod -a -G uucp $USER -重新登录以确保串行端口的读写权限被启用。 +请重新登录,确保串口读写权限可以生效。 确认串口连接 ------------------------ -现在验证串口连接是可用的。您可以使用串口终端程序来执行此操作。在这个例子中,我们将使用 `PuTTY SSH Client `_ ,它有 Windows 和 Linux 等平台的版本。您也可以使用其他串口程序并设置如下的通信参数。 +现在,请使用串口终端程序,验证串口连接是否可用。在本示例中,我们将使用 `PuTTY SSH Client `_, `PuTTY SSH Client `_ 既可用于 Windows 也可用于 Linux。你也可以使用其他串口程序并设置如下的通信参数。 -运行终端,设置串口:波特率 = 115200,数据位 = 8,停止位 = 1,奇偶校验 = N。以下是设置串口和在 Windows 和 Linux 上传输参数(如 115200-8-1-N)的一些截屏示例。注意选择上述步骤中确认的串口进行设置。 +运行终端,配置串口:波特率 = 115200,数据位 = 8,停止位 = 1,奇偶校验 = N。以下截屏分别展示了在 Windows 和 Linux 中配置串口和上述通信参数(如 115200-8-1-N)。注意,这里一定要选择在上述步骤中确认的串口进行配置。 .. figure:: ../../_static/putty-settings-windows.png :align: center - :alt: Setting Serial Communication in PuTTY on Windows + :alt: 在 Windows 操作系统中使用 PuTTY 设置串口通信参数 :figclass: align-center - 在 Windows 上的 PuTTY 设置串口传输。 + 在 Windows 操作系统中使用 PuTTY 设置串口通信参数 .. figure:: ../../_static/putty-settings-linux.png :align: center - :alt: Setting Serial Communication in PuTTY on Linux + :alt: 在 Linux 操作系统中使用 PuTTY 设置串口通信参数 :figclass: align-center - 在 Linux 上的 PuTTY 设置串口传输。 + 在 Linux 操作系统中使用 PuTTY 设置串口通信参数 -在终端打开串口,检查是否有任何打印出来的日志。日志内容取决于加载到 ESP32 的应用程序。下图为 ESP32 的一个示例日志。 + +然后,请检查 ESP32 是否有打印日志。如有,请在终端打开串口进行查看。这里,日志内容取决于加载到 ESP32 的应用程序,下图即为一个示例。 .. highlight:: none @@ -114,17 +138,18 @@ MacOS :: ... -如果您看到一些清晰的日志,则表示串行连接正常,您可以继续安装,最后将应用程序上载到 ESP32。 +如果打印出的日志是可读的(而不是乱码),则表示串口连接正常。此时,你可以继续进行安装,并最终将应用程序上载到 ESP32。 .. note:: - 对于某些串口接线配置,在 ESP32 启动并产生串行输出之前,需要在终端程序中禁用串行 RTS & DTR 引脚。这取决于串口适配器硬件本身,大多数开发板(包括所有乐鑫开发板)没有这个问题。此问题仅存在于将 RTS & DTR 引脚直接连接到 EN & GPIO0 引脚上的情况。更多详细信息,参见 `esptool documentation`_。 + 在某些串口接线方式下,在 ESP32 启动并开始打印串口日志前,需要在终端程序中禁用串口 RTS & DTR 引脚。该问题仅存在于将 RTS & DTR 引脚直接连接到 EN & GPIO0 引脚上的情况,绝大多数开发板(包括乐鑫所有的开发板)都没有这个问题。更多详细信息,参见 `esptool 文档`_。 .. note:: - 验证通讯正常后关闭串口终端。下一步,我们将使用另一个应用程序来上传 ESP32。此应用程序在终端打开时将无法访问串口。 + 请在验证完串口通信正常后,关闭串口终端。下一步,我们将使用另一个应用程序将新的固件上传到 ESP32。此时,如果串口被占用则无法成功。 -如您在安装用于 ESP32 开发的软件时,从 :ref:`get-started-connect` 小节跳转到了这里,请返回到 :ref:`get-started-configure` 小节继续阅读。 +如你在安装 ESP32 硬件开发的软件环境时,从 :ref:`get-started-connect` 跳转到了这里,请从 :ref:`get-started-configure` 继续阅读。 -.. _esptool documentation: https://github.com/espressif/esptool/wiki/ESP32-Boot-Mode-Selection#automatic-bootloader + +.. _esptool 文档: https://github.com/espressif/esptool/wiki/ESP32-Boot-Mode-Selection#automatic-bootloader diff --git a/docs/zh_CN/get-started/index.rst b/docs/zh_CN/get-started/index.rst index 6afcc12e3c..9c3ea3d3b6 100644 --- a/docs/zh_CN/get-started/index.rst +++ b/docs/zh_CN/get-started/index.rst @@ -1,6 +1,6 @@ -******** -快速入门 -******** +******************* +快速入门(CMake) +******************* :link_to_translation:`en:[English]` @@ -36,7 +36,8 @@ ESP32 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、 软件: -* 设置 **工具链**,用于编译 ESP32 **应用程序**; +* 设置 **工具链**,用于编译 ESP32 代码; +* **编译工具** —— CMake 和 Ninja 编译工具,用于编译 ESP32 **应用程序**; * 获取 **ESP-IDF** 软件开发框架。该框架已经基本包含 ESP32 使用的 API(软件库和源代码)和运行 **工具链** 的脚本; * 安装 C 语言编程(**工程**)的 **文本编辑器**,例如 `Eclipse `_。 @@ -66,12 +67,12 @@ ESP32 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、 .. _get-started-step-by-step: 详细安装步骤 -============ +============== 请根据下方详细步骤,完成安装过程。 设置开发环境 -~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~ * :ref:`get-started-setup-toolchain` * :ref:`get-started-get-esp-idf` @@ -79,19 +80,20 @@ ESP32 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、 * :ref:`get-started-get-packages` 创建您的第一个工程 -~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~ * :ref:`get-started-start-project` * :ref:`get-started-connect` * :ref:`get-started-configure` -* :ref:`get-started-build-and-flash` -* :ref:`get-started-monitor` +* :ref:`get-started-build` +* :ref:`get-started-flash` +* :ref:`get-started-build-monitor` .. _get-started-setup-toolchain: 第一步:设置工具链 -================== +==================== 工具链指一套用于编译代码和应用程序的程序。 @@ -101,8 +103,8 @@ ESP32 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、 :hidden: Windows - Linux - MacOS + Linux + MacOS +-------------------+-------------------+-------------------+ | |windows-logo| | |linux-logo| | |macos-logo| | @@ -133,12 +135,17 @@ ESP32 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、 .. _get-started-get-esp-idf: 第二步:获取 ESP-IDF -===================== +=========================== 除了工具链,您还需要供 ESP32 使用的 API(软件库和源代码),具体请见 `ESP-IDF 仓库 `_。 +请将 ESP-IDF 下载到您的本地。 + 获取本地副本:打开终端,切换到你要存放 ESP-IDF 的工作目录,使用 ``git clone`` 命令克隆远程仓库。 +Linux 和 MacOS 操作系统 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 打开终端,后运行以下命令: .. include:: /_build/inc/git-clone-bash.inc @@ -147,6 +154,23 @@ ESP-IDF 将下载至 ``~/esp/esp-idf``。 请前往 :doc:`/versions`,查看 ESP-IDF 不同版本的具体适用场景。 +Windows 操作系统 +~~~~~~~~~~~~~~~~~~ + +.. note:: + + 较早版本 ESP-IDF 使用了 **MSYS2 bash 终端** 命令行。目前,基于 CMake 的编译系统可使用常见的 **Windows 命令窗口**,即本指南中使用的终端。 + +请注意,如果您使用基于 bash 的终端或 PowerShell 终端,一些命令语法将与下面描述有所不同。 + +打开命令提示符,后运行以下命令: + +.. include:: /_build/inc/git-clone-windows.inc + +ESP-IDF 将下载至 ``%userprofile%\esp\esp-idf``。 + +请前往 :doc:`/versions`,查看 ESP-IDF 不同版本的具体适用场景。 + .. include:: /_build/inc/git-clone-notes.inc .. note:: @@ -156,44 +180,45 @@ ESP-IDF 将下载至 ``~/esp/esp-idf``。 cd esp-idf git submodule update --init - .. _get-started-setup-path: 第三步:设置环境变量 -===================== +=========================== -工具链通过环境变量 ``IDF_PATH`` 获得 ESP-IDF 的目录。因此,您需要在 PC 中设置该环境变量,否则无法编译工程。 +请在您的 PC 上设置以下环境变量,否则无法编译工程。 -您可以在每次重启会话时手动设置,也可以在用户配置中进行永久设置,具体请前往 :doc:`add-idf_path-to-profile` 章节,查看 :ref:`Windows ` 、:ref:`Linux 及 MacOS ` 操作系统的具体设置方式。 +- ``IDF_PATH`` 应设置为 ESP-IDF 根目录的路径。 +- ``PATH`` 应包括同一 ``IDF_PATH`` 目录下的 ``tools`` 目录路径。 + +您可以在每次重启会话时手动设置,也可以在用户配置中进行永久设置,具体请前往 :doc:`add-idf_path-to-profile` 章节,查看 :ref:`Windows ` 、:ref:`Linux 及 MacOS ` 操作系统的具体设置方式。 .. _get-started-get-packages: 第四步:安装 Python 软件包 -========================== +================================= + +ESP-IDF 所需的 Python 软件包位于 ``IDF_PATH/requirements.txt`` 中。您可以运行以下命令进行安装: :: -ESP-IDF 所需 Python 软件包位于 ``IDF_PATH/requirements.txt`` 中。您可以运行以下命令进行安装: :: - python -m pip install --user -r $IDF_PATH/requirements.txt .. note:: - 请注意查询您所使用的 Python 解释器的版本(运行命令 ``python --version``),并根据查询结果将上方命令中的 ``python`` 替换为 ``python2``, ``python2.7``,例如: :: - - python2.7 -m pip install --user -r $IDF_PATH/requirements.txt + 请注意查询您所使用的 Python 解释器的版本(运行命令 ``python --version``),并根据查询结果将上方命令中的 ``python`` 替换为 ``python2``, ``python2.7``,例如: + ``python2.7 -m pip install --user -r $IDF_PATH/requirements.txt`` .. _get-started-start-project: 第五步:开始创建工程 -===================== +======================= 现在,您可以开始准备开发 ESP32 应用程序了。您可以从 ESP-IDF 中 :idf:`examples` 目录下的 :example:`get-started/hello_world` 工程开始。 将 :example:`get-started/hello_world` 复制至您本地的 ``~/esp`` 目录下: Linux 和 MacOS 操作系统 -~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: bash @@ -201,7 +226,7 @@ Linux 和 MacOS 操作系统 cp -r $IDF_PATH/examples/get-started/hello_world . Windows 操作系统 -~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: batch @@ -215,9 +240,9 @@ ESP-IDF 的 :idf:`examples` 目录下有一系列示例工程,都可以按照 ESP-IDF 编译系统不支持带有空格的路径。 .. _get-started-connect: - + 第六步:连接设备 -================== +====================== 现在,请将您的 ESP32 开发板连接到 PC,并查看开发板使用的串口。 @@ -237,25 +262,33 @@ ESP-IDF 的 :idf:`examples` 目录下有一系列示例工程,都可以按照 .. _get-started-configure: 第七步:配置 -============= +================= 请进入 :ref:`get-started-start-project` 中提到的 ``hello_world`` 目录,并运行工程配置工具 ``menuconfig``。 Linux 和 MacOS 操作系统 -~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: bash cd ~/esp/hello_world - make menuconfig + idf.py menuconfig + +如果您的默认 Python 版本为 3.0 以上,可能需要运行 ``python2 idf.py`` 。 Windows 操作系统 -~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~ .. code-block:: batch cd %userprofile%\esp\hello_world - make menuconfig + idf.py menuconfig + +Python 2.7 安装程序将尝试配置 Windows,将 ``.py`` 文件与 Python 2 关联起来。如果其他程序(比如 Visual Studio Python 工具)曾关联了其他版本 Python,则 ``idf.py`` 可能无法正常运行(文件将在 Visual Studio 中打开)。这种情况下,您可以选择每次都运行一遍 ``C:\Python27\python idf.py``,或更改 Windows 的 ``.py`` 关联文件设置。 + +.. note:: + + 如果出现 ``idf.py not found(无法找到 idf.py)`` 错误,请确保 ``PATH`` 环境变量设置无误,具体请参考 :ref:`get-started-setup-path`。如果 ``tools`` 目录下没有 ``idf.py`` 文件,请确保 CMake 预览的分支正确无误,具体请参考 :ref:`get-started-get-esp-idf`。 如果之前的步骤都正确,则会显示下面的菜单: @@ -266,8 +299,6 @@ Windows 操作系统 工程配置 — 主窗口 -进入菜单后,选择 ``Serial flasher config`` > ``Default serial port`` 配置串口(设备将通过该串口加载工程)。按回车键确认选择,点击 ``< Save >`` 保存配置,然后点击 ``< Exit >`` 退出 ``menuconfig``。 - ``menuconfig`` 工具的常见操作见下。 * ``上下箭头``:移动 @@ -275,77 +306,118 @@ Windows 操作系统 * ``ESC 键``:返回上级菜单或退出 * ``英文问号``:调出帮助菜单(退出帮助菜单,请按回车键)。 * ``空格``、``Y 键``或``N 键``:使能/禁用 ``[*]`` 配置选项 -* ``英文问号`` :调出有关高亮选项的帮助菜单 +* ``英文问号``:调出有关高亮选项的帮助菜单 * ``/ 键``:寻找配置项目 -.. note:: - - 如果您是 **Arch Linux** 用户,请前往 ``SDK tool configuration``,并将 ``Python 2 interpreter`` 的名称从 ``python`` 替换为 ``python2``。 - .. attention:: 如果您使用的是 ESP32-DevKitC(板载 ESP32-SOLO-1 模组),请在烧写示例程序前,前往 ``menuconfig`` 中使能单核模式(:ref:`CONFIG_FREERTOS_UNICORE`)。 -.. _get-started-build-and-flash: +.. _get-started-build: -第八步:编译和烧录 +第八步:编译工程 +================== + +请使用以下命令,编译烧录工程::: + + idf.py build + +运行以上命令可以编译应用程序和所有 ESP-IDF 组件,接着生成 bootloader、分区表和应用程序二进制文件。 + +.. code-block:: none + + $ idf.py build + Running cmake in directory /path/to/hello_world/build + Executing "cmake -G Ninja --warn-uninitialized /path/to/hello_world"... + Warn about uninitialized values. + -- Found Git: /usr/bin/git (found version "2.17.0") + -- Building empty aws_iot component due to configuration + -- Component names: ... + -- Component paths: ... + + ... (more lines of build system output) + + [527/527] Generating hello-world.bin + esptool.py v2.3.1 + + Project build complete. To flash, run this command: + ../../../components/esptool_py/esptool/esptool.py -p (PORT) -b 921600 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x10000 build/hello-world.bin build 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin + or run 'idf.py -p PORT flash' + +如果一切正常,编译完成后将生成 .bin 文件。 + + +.. _get-started-flash: + +第九步:烧录到设备 ==================== -请使用以下命令,编译烧录工程: :: +请使用以下命令,将刚刚生成的二进制文件烧录至您的 ESP32 开发板: :: - make flash + idf.py -p PORT [-b BAUD] flash -运行以上命令可以编译应用程序和所有 ESP-IDF 组件,接着生成 bootloader、分区表和应用程序二进制文件。接着,这些二进制文件将被烧录至 ESP32 开发板。 +请将 PORT 替换为 ESP32 开发板的串口名称,具体可见 :ref:`get-started-connect`。 -如果一切顺利,您可在烧录完成后看到类似下方的打印信息(代表加载进程)。接着,开发板将会复位,应用程序 "hello_world" 开始启动。 +您还可以将 BAUD 替换为您希望的烧录波特率。默认波特率为 ``460800``。 -.. highlight:: none +更多有关 idf.py 参数的详情,请见 :ref:`idf.py`。 -:: +.. note:: - esptool.py v2.0-beta2 - Flashing binaries to serial port /dev/ttyUSB0 (app at offset 0x10000)... - esptool.py v2.0-beta2 - Connecting........___ + 勾选 ``flash`` 选项将自动编译并烧录工程,因此无需再运行 ``idf.py build``。 + +.. code-block:: none + + Running esptool.py in directory [...]/esp/hello_world + Executing "python [...]/esp-idf/components/esptool_py/esptool/esptool.py -b 460800 write_flash @flash_project_args"... + esptool.py -b 460800 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x1000 bootloader/bootloader.bin 0x8000 partition_table/partition-table.bin 0x10000 hello-world.bin + esptool.py v2.3.1 + Connecting.... + Detecting chip type... ESP32 + Chip is ESP32D0WDQ6 (revision 1) + Features: WiFi, BT, Dual Core Uploading stub... Running stub... Stub running... - Changing baud rate to 921600 + Changing baud rate to 460800 Changed. - Attaching SPI flash... Configuring flash size... - Auto-detected Flash size:4MB + Auto-detected Flash size: 4MB Flash params set to 0x0220 - Compressed 11616 bytes to 6695... - Wrote 11616 bytes (6695 compressed) at 0x00001000 in 0.1 seconds (effective 920.5 kbit/s)... - Hash of data verified. - Compressed 408096 bytes to 171625... - Wrote 408096 bytes (171625 compressed) at 0x00010000 in 3.9 seconds (effective 847.3 kbit/s)... + Compressed 22992 bytes to 13019... + Wrote 22992 bytes (13019 compressed) at 0x00001000 in 0.3 seconds (effective 558.9 kbit/s)... Hash of data verified. Compressed 3072 bytes to 82... - Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 8297.4 kbit/s)... + Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 5789.3 kbit/s)... Hash of data verified. - + Compressed 136672 bytes to 67544... + Wrote 136672 bytes (67544 compressed) at 0x00010000 in 1.9 seconds (effective 567.5 kbit/s)... + Hash of data verified. + Leaving... - Hard resetting... + Hard resetting via RTS pin... + +如果一切顺利,烧录完成后,开发板将会复位,应用程序 "hello_world" 开始运行。 + +.. note:: + + (目前不支持)如果您希望使用 Eclipse IDE,而非 ``idf.py``,请参考 :doc:`Eclipse 指南 `。 -如果您希望使用 Eclipse IDE,而非 ``make`` 编译系统,请参考 :doc:`Eclipse 指南 `。 +.. _get-started-build-monitor: +第十步:监视器 +================== -.. _get-started-monitor: - -第九步:监视器 -=============== - -您可以使用 ``make monitor`` 命令,监视 “hello_world” 的运行情况。 +您可以使用 ``make monitor`` 命令,监视 “hello_world” 的运行情况。注意,不要忘记将 PORT 替换为您的串口名称。 运行该命令后,:doc:`IDF 监视器 <../api-guides/tools/idf-monitor>` 应用程序将启动: :: - $ make monitor - MONITOR + $ idf.py -p /dev/ttyUSB0 monitor + Running idf_monitor in directory [...]/esp/hello_world/build + Executing "python [...]/esp-idf/tools/idf_monitor.py -b 115200 [...]/esp/hello_world/build/hello-world.elf"... --- idf_monitor on /dev/ttyUSB0 115200 --- - --- Quit:Ctrl+] | Menu:Ctrl+T | Help:Ctrl+T followed by Ctrl+H --- + --- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- ets Jun 8 2016 00:22:57 rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) @@ -359,7 +431,7 @@ Windows 操作系统 ... Hello world! Restarting in 10 seconds... - I (211) cpu_start:Starting scheduler on APP CPU. + I (211) cpu_start: Starting scheduler on APP CPU. Restarting in 9 seconds... Restarting in 8 seconds... Restarting in 7 seconds... @@ -378,69 +450,43 @@ Windows 操作系统 1. 退出监视器。 2. 打开 :ref:`menuconfig `, 3. 进入 ``Component config`` --> ``ESP32-specific`` --> ``Main XTAL frequency`` 进行配置,将 :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` 设置为 26 MHz。 -4. 然后,请重新 :ref:`编译和烧录 ` 应用程序。 +4. 然后,请重新 :ref:`编译和烧录 ` 应用程序。 .. note:: - 您也可以运行以下命令,一次性执行构建、烧录和监视过程: :: + 您也可以运行以下命令,一次性执行构建、烧录和监视过程: - make flash monitor + ``idf.py -p PORT flash monitor`` -此外,请前往 :doc:`IDF 监视器 <../api-guides/tools/idf-monitor>`,了解更多使用 IDF 监视器的快捷键和其他详情。 +此外, + +- 请前往 :doc:`IDF 监视器 <../api-guides/tools/idf-monitor>`,了解更多使用 IDF 监视器的快捷键和其他详情。 +- 请前往 :ref:`idf.py`,查看更多 ``idf.py`` 命令和选项。 **恭喜,您已完成 ESP32 的入门学习!** 现在,您可以尝试一些其他 :idf:`examples`,或者直接开发自己的应用程序。 - -环境变量 -========= - -用户可以在使用 ``make`` 命令时 **直接设置** 部分环境变量,而无需进入 ``make menuconfig`` 进行重新配置。这些变量包括: - -+-----------------+-----------------------------------------------------------------------+ -| 变量 | 描述与使用方式 | -+-----------------+-----------------------------------------------------------------------+ -| ``ESPPORT`` | 覆盖 ``flash`` 和 ``monitor`` 命令使用的串口。 | -+ +-----------------------------------------------------------------------+ -| | 例:``make flash ESPPORT=/dev/ttyUSB1``, ``make monitor ESPPORT=COM1``| -+-----------------+-----------------------------------------------------------------------+ -| ``ESPBAUD`` | 覆盖烧录 ESP32 时使用的串口速率。 | -+ +-----------------------------------------------------------------------+ -| | 例:``make flash ESPBAUD=9600`` | -+-----------------+-----------------------------------------------------------------------+ -| ``MONITORBAUD`` | 覆盖监控时使用的串口速率。 | -+ +-----------------------------------------------------------------------+ -| | 例:``make monitor MONITORBAUD=9600`` | -+-----------------+-----------------------------------------------------------------------+ - -.. note:: - - 您可导出环境变量(例:``export ESPPORT=/dev/ttyUSB1``)。 - 在同一会话窗口中,如果未被同步覆盖,所有 ``make`` 命令均会使用导出的环境变量值。 - - 更新 ESP-IDF -============= +================= -乐鑫会不时推出更新版本的 ESP-IDF,修复 bug 或提出新的特性。因此,在使用时,您也应注意更新您本地的版本。最简单的方法是:直接删除您本地的 ``esp-idf`` 文件夹,然后按照 :ref:`get-started-get-esp-idf` 中的指示,重新完成克隆。 +乐鑫会不时推出更新版本的 ESP-IDF,修复 bug 或提出新的特性。因此,您在使用时,也应注意更新您本地的版本。最简单的方法是:直接删除您本地的 ``esp-idf`` 文件夹,然后按照 :ref:`get-started-get-esp-idf` 中的指示,重新完成克隆。 如果您希望将 ESP-IDF 克隆到新的路径下,请务必 :doc:`重新设置 IDF_PATH `。否则,工具链将无法找到 ESP-IDF。 此外,您可以仅更新变更部分。具体方式,请前往 :ref:`更新 ` 章节查看。 相关文档 -========= +=========== .. toctree:: :maxdepth: 1 add-idf_path-to-profile establish-serial-connection - make-project eclipse-setup ../api-guides/tools/idf-monitor toolchain-setup-scratch .. _Stable version: https://docs.espressif.com/projects/esp-idf/zh_CN/stable/ -.. _Releases page: https://github.com/espressif/esp-idf/releases \ No newline at end of file +.. _Releases page: https://github.com/espressif/esp-idf/releases diff --git a/docs/zh_CN/get-started/linux-setup-scratch.rst b/docs/zh_CN/get-started/linux-setup-scratch.rst index 4b58f2d082..1c37b35d37 100644 --- a/docs/zh_CN/get-started/linux-setup-scratch.rst +++ b/docs/zh_CN/get-started/linux-setup-scratch.rst @@ -1,63 +1,63 @@ -********************************** +****************************************** 从零开始设置 Linux 环境下的工具链 -********************************** +****************************************** + :link_to_translation:`en:[English]` -.. note:: +除了从乐鑫官网直接下载已编译好的二进制工具链外,你还可以按照本文介绍,从头开始设置你自己的工具链。如需快速使用已编译好的二进制工具链,可回到 :doc:`linux-setup` 章节。 - 安装工具链的标准流程可以通过阅读文档 :doc:`Linux 平台工具链的标准设置 ` 来获得,:ref:`工具链的自定义设置 ` 章节会介绍哪些情况下我们必须要重新定义工具链。 +安装准备 +===================== +编译 ESP-IDF 需要以下软件包: -安装必要的工具 -============== +- CentOS 7:: -要想使用 ESP-IDF 进行编译,您需要获取以下软件包: + sudo yum install git wget ncurses-devel flex bison gperf python pyserial python-pyelftools cmake ninja-build ccache - Ubuntu 和 Debian:: - sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing python-pyelftools + sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache - Arch:: - sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing python2-pyelftools + sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-click python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache + .. note:: - - 一些旧的(2014年之前)Linux 发行版中使用的 ``pyserial`` 版本可能是 2.x , ESP-IDF并不支持。 - 在这种情况下,请参考 :ref:`安装依赖的 Python 软件包 ` 章节,通过 ``pip`` 工具来安装支持的版本。 + 使用 ESP-IDF 需要 CMake 3.5 或以上版本。较早版本的 Linux 可能需要升级才能向后移植仓库,或安装 "cmake3" 软件包,而不是安装 "cmake"。 从源代码编译工具链 -================== +================================= -- 安装依赖: +- 安装依赖: - CentOS 7:: - sudo yum install gawk gperf grep gettext ncurses-devel python python-devel automake bison flex texinfo help2man libtool + sudo yum install gawk gperf grep gettext ncurses-devel python python-devel automake bison flex texinfo help2man libtool make - Ubuntu pre-16.04:: - sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool + sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool make - - Ubuntu 16.04:: + - Ubuntu 16.04 及以上:: - sudo apt-get install gawk gperf grep gettext python python-dev automake bison flex texinfo help2man libtool libtool-bin + sudo apt-get install gawk gperf grep gettext python python-dev automake bison flex texinfo help2man libtool libtool-bin make - Debian 9:: - sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool libtool-bin + sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool libtool-bin make - Arch:: TODO -新建工作目录,然后进入:: +创建工作目录,并进入该目录:: mkdir -p ~/esp cd ~/esp - -下载 ``crosstool-NG`` 然后编译: +下载并编译 ``crosstool-NG`` : .. include:: /_build/inc/scratch-build-code.inc @@ -67,10 +67,11 @@ ./ct-ng build chmod -R u+w builds/xtensa-esp32-elf -编译得到的工具链会被保存到 ``~/esp/crosstool-NG/builds/xtensa-esp32-elf``。根据 :ref:`Linux 下设置环境变量的标准方法 ` 中的介绍,将工具链添加到 ``PATH`` 中。 +编译得到的工具链会被保存到 ``~/esp/crosstool-NG/builds/xtensa-esp32-elf``。请按照 :ref:`标准设置指南 ` 的介绍,将工具链添加到 ``PATH``。 -下一步 -====== +后续步骤 +========== + +继续设置开发环境,请前往 :ref:`get-started-get-esp-idf` 章节。 -继续设置开发环境,请前往 :ref:`获取 ESP-IDF ` 章节。 diff --git a/docs/zh_CN/get-started/linux-setup.rst b/docs/zh_CN/get-started/linux-setup.rst index 72bcbfabc0..2a05e8fea7 100644 --- a/docs/zh_CN/get-started/linux-setup.rst +++ b/docs/zh_CN/get-started/linux-setup.rst @@ -1,9 +1,8 @@ -***************************** +******************************************************************* Linux 平台工具链的标准设置 -***************************** -:link_to_translation:`en:[English]` +******************************************************************* -.. important:: 对不起,CMake-based Build System Preview 还没有中文翻译。 +:link_to_translation:`en:[英文]` 安装前提 ===================== @@ -12,65 +11,63 @@ Linux 平台工具链的标准设置 - CentOS 7:: - sudo yum install gcc git wget make ncurses-devel flex bison gperf python pyserial python-pyelftools + sudo yum install git wget ncurses-devel flex bison gperf python pyserial python-pyelftools cmake ninja-build ccache -- Ubuntu and Debian:: +- Ubuntu 和 Debian:: - sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing python-pyelftools + sudo apt-get install git wget libncurses-dev flex bison gperf python python-click python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache - Arch:: - sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing python2-pyelftools + sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-click python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache .. note:: - - 一些旧的(2014年之前)Linux 发行版中使用的 ``pyserial`` 版本可能是 2.x , ESP-IDF并不支持。 - 在这种情况下,请参考 :ref:`安装依赖的 Python 软件包 ` 章节,通过 ``pip`` 工具来安装支持的版本。 + 使用 ESP-IDF 需要 CMake 3.5 或以上版本。较早版本的 Linux 可能需要升级才能向后移植仓库,或安装 "cmake3" 软件包,而不是安装 "cmake"。 工具链的设置 -=============== +========================= .. include:: /_build/inc/download-links.inc Linux 版的 ESP32 工具链可以从 Espressif 的网站下载: -- 64-bit Linux: +- 64 位 Linux: |download_link_linux64| -- 32-bit Linux: +- 32 位 Linux: |download_link_linux32| -1. 下载完成后,将它解压到 ``~/esp`` 目录: : +1. 下载完成后,将它解压到 ``~/esp`` 目录: - - 64-bit Linux: + - for 64-bit Linux: .. include:: /_build/inc/unpack-code-linux64.inc - - 32-bit Linux: + - for 32-bit Linux: .. include:: /_build/inc/unpack-code-linux32.inc .. _setup-linux-toolchain-add-it-to-path: -2. 工具链将会被解压到 ``~/esp/xtensa-esp32-elf/`` 目录。 +2. 工具链将会被解压到 ``~/esp/xtensa-esp32-elf/`` 目录。 - 要使用工具链,你还需要在 ``~/.profile`` 文件中更新环境变量 ``PATH``。要使 ``xtensa-esp32-elf`` 在所有的终端会话中都有效,需要将下面这一行代码添加到你的 ``~/.profile`` 文件中: :: + 要使用工具链,你还需要在 ``~/.profile`` 文件中更新环境变量 ``PATH``。要使 ``xtensa-esp32-elf`` 在所有的终端会话中都有效,需要将下面这一行代码添加到你的 ``~/.profile`` 文件中::: - export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH" + export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH" - 或者你也可以给上面的命令创建一个别名。这样做的好处是,你只在需要使用它的时候才获取工具链。将下面这行代码添加到 ``~/.profile`` 文件中即可: :: + 或者,你也可以给上面的命令创建一个别名。这样做的好处是,你仅在需要时才获取工具链,将下面这行代码添加到 ``~/.profile`` 文件中即可:: - alias get_esp32='export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH"' + alias get_esp32='export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH"' - 然后,当你需要使用工具链时,在命令行输入 ``get_esp32``,然后工具链会自动添加到你的 ``PATH`` 中。 + 然后,当你需要使用工具链时,在命令行输入 ``get_esp32``,然后工具链会自动添加到你的 ``PATH`` 中。 .. note:: - 如果将 ``/bin/bash`` 设置为登录 shell,且同时存在 ``.bash_profile`` 和 ``.profile``,则更新 ``.bash_profile`` 。在 CentOS 环境下, ``alias`` 需要添加到 ``.bashrc`` 文件中。 + 如果将 ``/bin/bash`` 设置为登录 shell,且同时存在 ``.bash_profile`` 和 ``.profile``,则更新 ``.bash_profile``。 -3. 退出并重新登录以使 ``.profile`` 更改生效。 运行以下命令来检查 ``PATH`` 设置是否正确: :: +3. 退出并重新登录以使 ``.profile`` 更改生效。运行以下命令来检查 ``PATH`` 设置是否正确:: printenv PATH @@ -81,28 +78,40 @@ Linux 版的 ESP32 工具链可以从 Espressif 的网站下载: 除了 ``/home/user-name``,应该有具体的安装的主路径。 -权限问题 /dev/ttyUSB0 ------------------------------- -某些 Linux 版本可能在烧写 ESP32 时会出现 ``Failed to open port /dev/ttyUSB0`` 错误消息。 :ref:`可以通过将当前用户添加到拨出组来解决`。 +权限问题 /dev/ttyUSB0 +---------------------------------------------- + +使用某些 Linux 版本向 ESP32 烧写固件时,可能会出现 ``Failed to open port /dev/ttyUSB0`` 错误消息。此时,可以将当前用户增加至 :ref:` Linux Dialout 组 ` Arch Linux 用户 ----------------- +-------------------------------- -在 Arch 中运行预编译的 gdb (xtensa-esp32-elf-gdb) 需要 ncurses 5,但是 Arch 使用的是 ncurses 6。在 AUR_ 中向下兼容的库文件,可用于本地和 lib32 的配置: +在 Arch Linux 中运行预编译的 gdb (xtensa-esp32-elf-gdb) 需要 ncurses 5,但是 Arch 使用的是 ncurses 6。 + +`AUR`_ 中存在向下兼容的库文件,可用于本地和 lib32 的配置: - https://aur.archlinux.org/packages/ncurses5-compat-libs/ - https://aur.archlinux.org/packages/lib32-ncurses5-compat-libs/ -在安装这些软件包之前,你可能需要将作者的公钥添加到你的钥匙圈中,上面链接中的“Comments”部分有所叙述。 +在安装这些软件包之前,你可能需要将作者的公钥添加到你的密钥环中,具体见上方链接中的 "Comments" 部分的介绍。 + +或者,你也可以使用 crosstool-NG 编译一个链接到 ncurses 6 的 gdb。 -或者,你也可以使用 crosstool-NG 编译一个链接 ncurses 6 的 gdb。 后续步骤 -========== +================ -要继续设置开发环境,请参考 :ref:`get-started-get-esp-idf` 一节。 +后续开发环境设置,请参考 :ref:`get-started-get-esp-idf` 一节。 + + +相关文档 +================= + +.. toctree:: + :maxdepth: 1 + + linux-setup-scratch .. _AUR: https://wiki.archlinux.org/index.php/Arch_User_Repository - diff --git a/docs/zh_CN/get-started/macos-setup-scratch.rst b/docs/zh_CN/get-started/macos-setup-scratch.rst index 1588c80c86..a5003ca94e 100644 --- a/docs/zh_CN/get-started/macos-setup-scratch.rst +++ b/docs/zh_CN/get-started/macos-setup-scratch.rst @@ -1,42 +1,56 @@ -********************************** +********************************************************************* 从零开始设置 Mac OS 环境下的工具链 -********************************** -:link_to_translation:`en:[English]` +********************************************************************* -.. note:: - - 安装工具链的标准流程可以通过阅读文档 :doc:`在 MacOS 上安装 ESP32 工具链 ` 来获得, :ref:`工具链的自定义设置 ` 章节会介绍哪些情况下我们必须要重新定义工具链。 +:link_to_translation:`en:[英文]` -安装必要的工具 -===================== +软件包管理器 +====================== + +从零开始设置工具链,你需要安装 MacPorts_ 或 homebrew_ 包管理器。或者,你也可以直接 :doc:`下载预编译的工具链 `。 + +MacPorts_ 需要安装完整的 XCode 软件,而 homebrew_ 只需要安装 XCode 命令行工具即可。 + + .. _homebrew: https://brew.sh/ + .. _MacPorts: https://www.macports.org/install.php + +请参考 :ref:`工具链自定义设置 ` 章节,查看在哪些情景下需要从头开始设置工具链。 + +准备工作 +============================ - 安装 pip:: sudo easy_install pip -.. note:: +- 安装 pyserial:: - ``pip`` 稍后将用于安装 :ref:`必要的 Python 软件包 `。 + pip install --user pyserial + +- 安装 CMake 和 Ninja 编译工具: + + - 若使用 HomeBrew,你可以运行:: + + brew install cmake ninja + + - 若使用 MacPorts,你可以运行:: + + sudo port install cmake ninja 从源代码编译工具链 -================== +======================================== -- 安装依赖: - - - 安装 MacPorts_ 或者 homebrew_ 包管理器。MacPorts 需要安装完整的 XCode 软件,但是 homebrew 只需要安装 XCode 命令行工具即可。 - - .. _homebrew: https://brew.sh/ - .. _MacPorts: https://www.macports.org/install.php +- 相关安装: - 对于 MacPorts:: - sudo port install gsed gawk binutils gperf grep gettext wget libtool autoconf automake + sudo port install gsed gawk binutils gperf grep gettext wget libtool autoconf automake make - 对于 homebrew:: - brew install gnu-sed gawk binutils gperftools gettext wget help2man libtool autoconf automake + brew install gnu-sed gawk binutils gperftools gettext wget help2man libtool autoconf automake make -创建大小写敏感的文件系统镜像:: +创建一个文件系统镜像(区分大小写):: hdiutil create ~/esp/crosstool.dmg -volname "ctng" -size 10g -fs "Case-sensitive HFS+" @@ -49,24 +63,24 @@ mkdir -p ~/esp ln -s /Volumes/ctng ~/esp/ctng-volume -进入新创建的工作目录:: +前往新创建的目录::: cd ~/esp/ctng-volume -下载 ``crosstool-NG`` 然后编译: +下载 ``crosstool-NG``,并开始编译: .. include:: /_build/inc/scratch-build-code.inc -编译工具链:: +编译工具链::: ./ct-ng xtensa-esp32-elf ./ct-ng build chmod -R u+w builds/xtensa-esp32-elf -编译得到的工具链会被保存到 ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf``。根据 :ref:`Mac OS 下设置环境变量的标准方法 ` 中的介绍,将工具链添加到 ``PATH`` 中。 +编译后的工具链将保存在 ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf``。根据 :ref:`Mac OS 下设置环境变量的标准方法 ` 中的介绍,将工具链添加到 ``PATH`` 中。 -下一步 -====== +后续步骤 +================= 继续设置开发环境,请前往 :ref:`获取 ESP-IDF ` 章节。 diff --git a/docs/zh_CN/get-started/macos-setup.rst b/docs/zh_CN/get-started/macos-setup.rst index 72596ead23..43d8a6684c 100644 --- a/docs/zh_CN/get-started/macos-setup.rst +++ b/docs/zh_CN/get-started/macos-setup.rst @@ -1,54 +1,82 @@ -************************************** +****************************************************************** 在 Mac OS 上安装 ESP32 工具链 -************************************** -:link_to_translation:`en:[English]` +****************************************************************** -.. important:: 对不起,CMake-based Build System Preview 还没有中文翻译。 +:link_to_translation:`en:[英文]` 安装准备 -================ +===================== + +ESP-IDF 将使用 Mac OS 上默认安装的 Python 版本。 - 安装 pip:: sudo easy_install pip +- 安装 pyserial:: + + pip install --user pyserial + +- 安装 CMake 和 Ninja 编译工具: + + - 若有 HomeBrew_,你可以运行:: + + brew install cmake ninja + + - 若有 MacPorts_,你可以运行:: + + sudo port install cmake ninja + + - 若以上均不适用,请访问 CMake_ 和 Ninja_ 主页,查询有关 Mac OS 平台的下载安装问题。 + +- 强烈建议同时安装 ccache_ 以达到更快的编译速度。如有 HomeBrew_,可通过 MacPorts_ 上的 ``brew install ccache`` 或 ``sudo port install ccache`` 完成安装。 + .. note:: - ``pip`` 稍后将用于安装 :ref:`必要的 Python 软件包 `。 + 如在任一步骤中出现以下报错信息:: + + ``xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun`` + + 你需要安装 XCode 命令行工具才能继续,具体可运行 ``xcode-select --install`` 进行安装。 安装工具链 -=============== +====================== .. include:: /_build/inc/download-links.inc -Mac OS 版本的 ESP32 工具链可以从以下地址下载: +下载 MacOS 版本的 ESP32 工具链,请前往乐鑫官网: |download_link_osx| -下载压缩文件之后,解压到 ``~/esp`` 目录中: +完成下载后,请在 ``~/esp`` 目录下进行解压: .. include:: /_build/inc/unpack-code-osx.inc .. _setup-macos-toolchain-add-it-to-path: -工具链将被解压到 ``~/esp/xtensa-esp32-elf/`` 路径下。 +此后,该工具链将解压至 ``~/esp/xtensa-esp32-elf/`` 目录。 -在 ``~/.profile`` 文件中更新 ``PATH`` 环境变量以使用工具链。为了使 ``xtensa-esp32-elf`` 在各种终端会话中都可用,在 ``~/.profile`` 文件中加上以下指令:: +为了开始使用工具链,你必须更新 ``~/.profile`` 文件中的 ``PATH`` 环境变量。为了让所有终端都可以使用 ``xtensa-esp32-elf``,请将下方命令增加至你的 ``~/.profile`` 文件::: - export PATH=$HOME/esp/xtensa-esp32-elf/bin:$PATH + export PATH=$HOME/esp/xtensa-esp32-elf/bin:$PATH -或者,您可以为上述命令创建一个别名。这样只有执行以下指令时工具链才能被使用。将下面的指令添加到您的 ``〜/ .profile`` 文件中:: +此外,你可以为以上命令增加一个别名。这样,你就可以仅在有需要时获取工具链。具体方式是在 ``~/.profile`` 文件中增加下方命令:: alias get_esp32="export PATH=$HOME/esp/xtensa-esp32-elf/bin:$PATH" -当需要使用工具链时,在命令行里输入 ``get_esp32``,就可以将工具链添加到 ``PATH`` 中。 +此时,你可以直接输入 ``get_esp32`` 命令,即可将工具链添加至你的 ``PATH``。 + +注意,这里需要退出并重新登陆,``.profile`` 更改才会生效。 + +此外,你可以使用以下命令,验证 ``PATH`` 是否设置正确:: + + printenv PATH -下一步 -========== - -前往 :ref:`get-started-get-esp-idf` 继续配置开发环境。 +后续步骤 +================= +前往 :ref:`get-started-get-esp-idf`,完成接下来的开发环境配置。 相关文档 ================= @@ -58,3 +86,8 @@ Mac OS 版本的 ESP32 工具链可以从以下地址下载: macos-setup-scratch +.. _cmake: https://cmake.org/ +.. _ninja: https://ninja-build.org/ +.. _ccache: https://ccache.samba.org/ +.. _homebrew: https://brew.sh/ +.. _MacPorts: https://www.macports.org/install.php diff --git a/docs/zh_CN/get-started/toolchain-setup-scratch.rst b/docs/zh_CN/get-started/toolchain-setup-scratch.rst index 43a8920c14..435fe177b0 100644 --- a/docs/zh_CN/get-started/toolchain-setup-scratch.rst +++ b/docs/zh_CN/get-started/toolchain-setup-scratch.rst @@ -1 +1,27 @@ -.. include:: ../../en/get-started/toolchain-setup-scratch.rst \ No newline at end of file +.. _get-started-customized-setup: + +********************************************************* +工具链自定义设置 +********************************************************* + +:link_to_translation:`en:[英文]` + +除了从乐鑫官网(请见 :ref:`get-started-setup-toolchain`)下载二进制工具链外,你还可以自行编译工具链。 + +如果没有特别需求,建议直接使用我们提供的预编译二进制工具链。不过,你也可能也会由于以下原因,编译你自己的工具链: + +- 需要定制工具链编译配置 +- 使用其他 GCC 版本(如 4.8.5) +- 需要破解 gcc、newlib 或 libstdc++ +- 有相关兴趣或时间充裕 +- 不信任从网站下载的 bin 文件 + +如需自行编译工具链,请查看以下文档: + +.. toctree:: + :maxdepth: 1 + + windows-setup-scratch + linux-setup-scratch + macos-setup-scratch + diff --git a/docs/zh_CN/get-started/windows-setup-scratch.rst b/docs/zh_CN/get-started/windows-setup-scratch.rst index 6ca82060e8..56f5d7d30a 100644 --- a/docs/zh_CN/get-started/windows-setup-scratch.rst +++ b/docs/zh_CN/get-started/windows-setup-scratch.rst @@ -1 +1,92 @@ -.. include:: ../../en/get-started/windows-setup-scratch.rst \ No newline at end of file +****************************************************************** +从零开始设置 Windows 环境下的工具链 +****************************************************************** + +:link_to_translation:`en:[英文]` + +本文就如何运行基于 CMake 构建系统中的 :doc:`ESP-IDF 工具安装器 ` 进行逐步详细说明。手动安装所有工具能更好地控制整个安装流程,同时也方便高阶用户进行自定义安装。 + +使用 ESP-IDF 工具安装器对工具链及其他工具进行快速标准设置,请参照 :doc:`windows-setup`。 + + +.. note:: + 基于 GNU Make 的构建系统要求 Windows 兼容 `MSYS2`_ Unix。基于 CMake 的构建系统则无此要求。 + +工具 +===== + +cmake +^^^^^ + +下载最新发布的 Windows 平台稳定版 `CMake`_,并运行安装器。 + +当安装器询问安装选项时,选择 "Add CMake to the system PATH for all users"(为所有用户的系统路径添加 CMake)或 "Add CMake to the system PATH for the current user"(为当前用户的系统路径添加 CMake)。 + +Ninja 编译工具 +^^^^^^^^^^^^^^^^^^^^ + +.. note:: + Ninja 目前仅为 64 位版本 Windows 提供 bin 文件。你也可以通过其他编译工具使用 CMake 和 ``idf.py``,如适用于 32 位 Windows 的 mingw-make,但是目前暂无关于此工具的说明文档。 + +从(`下载页面 `_)下载最新发布的 Windows 平台稳定版 `ninja`_。 + +适用于 Windows 平台的 Ninja 下载文件是一个 .zip 文件,包含一个 ``ninja.exe`` 文件。将其解压到目录,并 `添加到你的路径 `_ (或者选择你的路径中已有的目录)。 + + +Python 2.x +^^^^^^^^^^ + +下载并运行适用于 Windows 安装器的最新版 `Python`_ 2.7。 + +Python 安装的“自定义”那一步提供了一份选项列表,最后一个选项是 "Add python.exe to Path"(添加 python.exe 到路径中),更改该选项,选择 "Will be installed"(将会安装)。 + +Python 安装完成后,打开 Windows 开始菜单下的 Command Prompt,并运行以下命令:: + + pip install --user pyserial + +适用于 IDF 的 MConf +^^^^^^^^^^^^^^^^^^^^^^ + +从 `kconfig-frontends 发布页面 `_ 下载配置工具 mconf-idf。此为 ``mconf`` 配置工具,可针对 ESP-IDF 进行一些自定义操作。 + +你需将此工具解压到目录,然后 `添加到你的路径 `_。 + +工具链设置 +=============== + +.. include:: /_build/inc/download-links.inc + +下载预编译的 Windows 平台工具链: + +|download_link_win32| + +解压压缩包文件到 ``C:\Program Files`` (或其他地址)。压缩包文件包含 ``xtensa-esp32-elf`` 目录。 + +然后,须将该目录下的子目录 ``bin`` `添加到你的路径 `_。例如,``C:\Program Files\xtensa-esp32-elf\bin``。 + +.. note:: + + 如果你已安装 MSYS2 环境(适用 "GNU Make" 构建系统),你可以跳过下载那一步,直接添加目录 ``C:\msys32\opt\xtensa-esp32-elf\bin`` 到路径,因为 MSYS2 环境已包含工具链。 + + +.. _add-directory-windows-path: + +添加目录到路径 +======================== + +添加任何新目录到你的 Windows Path 环境变量: + +打开系统控制面板,找到环境变量对话框(对于 Windows 10,则在高级系统设置中查找对话框)。 + +双击 ``Path`` 变量(选择用户或系统路径,这取决于你是否希望其他用户路径中也存在该目录)。在最后数值那里新添 ``;``。 + + +后续步骤 +================ + +要继续设置开发环境,请参照 :ref:`get-started-get-esp-idf`。 + +.. _ninja: https://ninja-build.org/ +.. _Python: https://www.python.org/downloads/windows/ +.. _MSYS2: https://msys2.github.io/ + diff --git a/docs/zh_CN/get-started/windows-setup-update.rst b/docs/zh_CN/get-started/windows-setup-update.rst new file mode 100644 index 0000000000..9d4fa4ff4c --- /dev/null +++ b/docs/zh_CN/get-started/windows-setup-update.rst @@ -0,0 +1,3 @@ +:orphan: + +.. Remove this file when the Chinese translation of getting started guide is updated diff --git a/docs/zh_CN/get-started/windows-setup.rst b/docs/zh_CN/get-started/windows-setup.rst index 3c02077bd3..1bbb806fdc 100644 --- a/docs/zh_CN/get-started/windows-setup.rst +++ b/docs/zh_CN/get-started/windows-setup.rst @@ -1,64 +1,60 @@ -*************************************** +********************************************************** Windows 平台工具链的标准设置 -*************************************** -:link_to_translation:`en:[English]` +********************************************************** -.. important:: 对不起,CMake-based Build System Preview 还没有中文翻译。 +:link_to_translation:`en:[英文]` + +.. note:: + 基于 CMake 的构建系统仅支持 64 位版本 Windows。 引言 ============ -Windows 没有内置的 "make" 环境,因此如果要安装工具链,你需要一个 GNU 兼容环境。我们这里使用 MSYS2_ 来提供该环境。你不需要一直使用这个环境(你可以使用 :doc:`Eclipse ` 或其它前端工具),但是它是在后台运行的。 +ESP-IDF 需要安装必要的工具,以编译 ESP32 固件,包括:Git,交叉编译器,以及 CMake 构建工具。本文将对这些工具一一说明。 -工具链的设置 -=============== - -快速设置的方法是从 dl.espressif.com 下载集成在一起的工具链和 MSYS2 压缩文件: +在此入门指南中,我们通过命令提示符进行有关操作。不过,安装 ESP-IDF 后你还可以使用 :doc:`Eclipse ` 或支持 CMake 的图形化工具 IDE。 https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20190611.zip -将 zip 压缩文件解压到 ``C:\`` (或其它路径,这里假设是 ``C:\``),它会使用预先准备的环境创建一个 ``msys32`` 目录。 +ESP-IDF 工具安装器 +======================= -检出 -============ +安装 ESP-IDF 必备工具最简易的方式是下载 ESP-IDF 工具安装器,地址如下: -运行 ``C:\msys32\mingw32.exe`` 打开一个 MSYS2 的终端窗口。该窗口的环境是一个 bash shell。创建一个 ``esp`` 目录作为开发 ESP32 应用的默认地址。运行指令 :: +https://dl.espressif.com/dl/esp-idf-tools-setup-1.2.exe - mkdir -p ~/esp - -输入 ``cd ~/esp`` 就进入到新创建的目录。如果没有错误信息出现则表明此步骤已完成。 +安装器会自动安装 ESP32 Xtensa gcc 工具链,Ninja_ 编译工具,以及名为 mconf-idf_ 的配置工具。此外,如果你的电脑还未安装有关 CMake_ 和 Python_ 2.7 的安装器,它还可以下载和运行与之对应的安装器。 +安装器默认更新 Windows ``Path`` 环境变量,因而上述工具也可在其他环境中运行。如果禁止该选项,则需自行设置 ESP-IDF 所使用的环境(终端或所选 IDE),并配置正确的路径。 -.. figure:: ../../_static/msys2-terminal-window.png - :align: center - :alt: MSYS2 MINGW32 shell window - :figclass: align-center +请注意,此安装器仅针对 ESP-IDF 工具包,并不包括 ESP-IDF。 - MSYS2 终端窗口 +安装 Git +============== -后续步骤将会使用这个窗口来为 ESP32 设置开发环境。 +ESP-IDF 工具安装器并不会安装 Git,因为快速入门指南默认你将以命令行的模式使用它。你可以通过 `Git For Windows`_ 下载和安装 Windows 平台的命令行 Git 工具(包括 "Git Bash" 终端)。 + +如果你想使用其他图形化 Git 客户端,如 `Github Desktop`, 你可以自行安装,但需要对本《入门指南》中相应的 Git 命令进行转换,以便用于你所选的 Git 客户端。 + +使用终端 +================ + +在本《入门指南》接下来的步骤说明中,我们将使用终端命令提示符进行有关操作。你也可以使用任何其他形式的命令提示符: + +- 比如,Windows 开始菜单下内置的命令提示符。本文档中的所有 Windows 命令行指令均为 Windows 命令提示符中所使用的 "batch" 命令。 +- 你还可以使用 `Git for Windows`_ 中的 "Git Bash" 终端,其所使用的 "bash" 命令提示符语法与 Mac OS 或 Linux 的既定语法相同。安装此终端后,你可以在开始菜单下找到命令提示符窗口。 +- 如果你已安装 MSYS2_ (通过 ESP-IDF 之前版本),你还可以使用 MSYS 终端。 后续步骤 ========== -要继续设置开发环境,请参考 :ref:`get-started-get-esp-idf` 一节。 - -更新环境 -======================== - -当 IDF 更新时,有时需要新的工具链,或者将新的需求添加到 Windows MSYS2 环境中。要将旧版本的预编译环境中的数据移动到新版本: - -- 把旧的 MSYS2 环境(即 ``C:\msys32``)移动/重命名为不同的目录(即 ``C:\msys32_old``)。 -- 按照前文所述步骤下载新的预编译环境。 -- 将新的 MSYS2 环境解压缩到 ``C:\msys32`` (或其他位置)。 -- 找到旧的 ``C:\msys32_old\home`` 目录并把它移到 ``C:\msys32``。 -- 如果你不再需要 ``C:\msys32_old`` 可以将它删除。 - -你可以在系统上拥有独立的不同的 MSYS2 环境,前提是在不同的目录中。 +要继续设置开发环境,请参照 :ref:`get-started-get-esp-idf`。 相关文档 ================= +想要自定义安装流程的高阶用户可参照: + .. toctree:: :maxdepth: 1 @@ -66,4 +62,9 @@ https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20190611 .. _MSYS2: https://msys2.github.io/ - +.. _cmake: https://cmake.org/download/ +.. _ninja: https://ninja-build.org/ +.. _Python: https://www.python.org/downloads/windows/ +.. _Git for Windows: https://gitforwindows.org/ +.. _mconf-idf: https://github.com/espressif/kconfig-frontends/releases/ +.. _Github Desktop: https://desktop.github.com/ diff --git a/docs/zh_CN/gnu-make-legacy.rst b/docs/zh_CN/gnu-make-legacy.rst new file mode 100644 index 0000000000..c914555901 --- /dev/null +++ b/docs/zh_CN/gnu-make-legacy.rst @@ -0,0 +1,3 @@ +.. note:: Since ESP-IDF V4.0, the default build system is based on CMake. This documentation is for the legacy build system based on GNU Make. Support for this build system may be removed in future major releases. + + diff --git a/docs/zh_CN/hw-reference/get-started-ethernet-kit.rst b/docs/zh_CN/hw-reference/get-started-ethernet-kit.rst index c96d94ceeb..f11f7862d0 100644 --- a/docs/zh_CN/hw-reference/get-started-ethernet-kit.rst +++ b/docs/zh_CN/hw-reference/get-started-ethernet-kit.rst @@ -342,7 +342,7 @@ ESP32-Ethernet-Kit 上电前,请首先确认开发板完好无损。 正式开始开发 ^^^^^^^^^^^^^^^^^^ -现在,请前往 :doc:`../get-started-cmake/index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 +现在,请前往 :doc:`../get-started/index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 如需使用较早 GNU Make 编译系统,则请参考 :ref:`get-started-step-by-step` 章节。 diff --git a/docs/zh_CN/index.rst b/docs/zh_CN/index.rst index 438e8dd55a..1feb1c1e37 100644 --- a/docs/zh_CN/index.rst +++ b/docs/zh_CN/index.rst @@ -40,7 +40,7 @@ ESP-IDF 编程指南 :hidden: 快速入门 - 快速入门 (CMake 预览版本) + 快速入门 (传统 GNU Make) API 参考 H/W 参考 API 指南 diff --git a/examples/build_system/cmake/idf_as_lib/README.md b/examples/build_system/cmake/idf_as_lib/README.md index eda7ac0b4d..4ba61e0bdc 100644 --- a/examples/build_system/cmake/idf_as_lib/README.md +++ b/examples/build_system/cmake/idf_as_lib/README.md @@ -67,4 +67,4 @@ or --- -There is a discussion on using ESP-IDF in custom CMake projects in the programming guide under `API Guides` -> `Build System (CMake)` -> `Using ESP-IDF in Custom CMake Projects` +There is a discussion on using ESP-IDF in custom CMake projects in the programming guide under `API Guides` -> `Build System` -> `Using ESP-IDF in Custom CMake Projects` diff --git a/examples/build_system/cmake/import_lib/README.md b/examples/build_system/cmake/import_lib/README.md index e24090a87c..c6071c8db4 100644 --- a/examples/build_system/cmake/import_lib/README.md +++ b/examples/build_system/cmake/import_lib/README.md @@ -33,4 +33,4 @@ I (677) example: Example end ``` --- -There is a discussion on importing third-party CMake libraries in the programming guide under `API Guides` -> `Build System (CMake)` -> `Using Third-Party CMake Projects with Components` +There is a discussion on importing third-party CMake libraries in the programming guide under `API Guides` -> `Build System` -> `Using Third-Party CMake Projects with Components` diff --git a/tools/unit-test-app/README.md b/tools/unit-test-app/README.md index 0118fc624f..349a09eb02 100644 --- a/tools/unit-test-app/README.md +++ b/tools/unit-test-app/README.md @@ -26,9 +26,9 @@ ESP-IDF unit tests are run using Unit Test App. The app can be built with the un # Flash Size -The unit test partition table assumes a 4MB flash size. When testing `TESTS_ALL=1` (Make) or `-T all` (CMake), this additional factory app partition size is required. +The unit test partition table assumes a 4MB flash size. When testing `-T all` or `TESTS_ALL=1` (Legacy GNU Make) or, this additional factory app partition size is required. -If building unit tests to run on a smaller flash size, edit `partition_table_unit_tests_app.csv` and use `TEST_COMPONENTS=` (Make) or `-T ...` (CMake) instead of `TESTS_ALL` or `-T all` if tests don't fit in a smaller factory app partition (exact size will depend on configured options). +If building unit tests to run on a smaller flash size, edit `partition_table_unit_tests_app.csv` and use `-T ...` or `TEST_COMPONENTS=` (Legacy GNU Make) or instead of `-T all` or `TESTS_ALL` if tests don't fit in a smaller factory app partition (exact size will depend on configured options). # Running Unit Tests From 05ac8cfb6dcc01b85a0e0cff85b663ee363556b2 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 24 Jun 2019 12:09:34 +1000 Subject: [PATCH 287/486] docs: Update description for Eclipse+Cmake support not ready yet --- .../jtag-debugging/configure-wrover.rst | 2 +- .../jtag-debugging/tips-and-quirks.rst | 2 +- docs/en/get-started/eclipse-setup.rst | 11 +++-- .../hw-reference/get-started-ethernet-kit.rst | 4 +- docs/page_redirects.txt | 2 +- .../jtag-debugging/configure-wrover.rst | 2 +- .../hw-reference/get-started-devkitc-v2.rst | 8 ++-- .../hw-reference/get-started-devkitc.rst | 13 +++--- .../hw-reference/get-started-pico-kit-v3.rst | 4 +- .../hw-reference/get-started-pico-kit.rst | 34 +++++++-------- .../get-started-wrover-kit-v2.rst | 16 ++++--- .../get-started-wrover-kit-v3.rst | 42 +++++++++---------- .../hw-reference/get-started-wrover-kit.rst | 42 +++++++++---------- 13 files changed, 85 insertions(+), 97 deletions(-) diff --git a/docs/en/api-guides/jtag-debugging/configure-wrover.rst b/docs/en/api-guides/jtag-debugging/configure-wrover.rst index 0f1ca1f887..a851b9efad 100644 --- a/docs/en/api-guides/jtag-debugging/configure-wrover.rst +++ b/docs/en/api-guides/jtag-debugging/configure-wrover.rst @@ -8,7 +8,7 @@ All versions of ESP-WROVER-KIT boards have built-in JTAG functionality. Putting Configure Hardware ^^^^^^^^^^^^^^^^^^ -1. Enable on-board JTAG functionality by setting JP8 according to :doc:`../../hw-reference/get-started-wrover-kit`, Section :ref:`get-started-esp-wrover-kit-v4.1-setup-options-cmake`. +1. Enable on-board JTAG functionality by setting JP8 according to :doc:`../../hw-reference/get-started-wrover-kit`, Section :ref:`get-started-esp-wrover-kit-v4.1-setup-options`. 2. Verify if ESP32 pins used for JTAG communication are not connected to some other h/w that may disturb JTAG operation: diff --git a/docs/en/api-guides/jtag-debugging/tips-and-quirks.rst b/docs/en/api-guides/jtag-debugging/tips-and-quirks.rst index 3911191d79..d3a76940cc 100644 --- a/docs/en/api-guides/jtag-debugging/tips-and-quirks.rst +++ b/docs/en/api-guides/jtag-debugging/tips-and-quirks.rst @@ -58,7 +58,7 @@ ESP-IDF has some support options for OpenOCD debugging which can be set at compi * :ref:`CONFIG_ESP32_DEBUG_OCDAWARE` is enabled by default. If a panic or unhandled exception is thrown and a JTAG debugger is connected (ie OpenOCD is running), ESP-IDF will break into the debugger. * :ref:`CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK` (disabled by default) sets watchpoint index 1 (the second of two) at the end of any task stack. This is the most accurate way to debug task stack overflows. Click the link for more details. -Please see the :ref:`make menuconfig ` menu for more details on setting compile-time options. +Please see the :ref:`project configuration menu ` menu for more details on setting compile-time options. .. _jtag-debugging-tip-freertos-support: diff --git a/docs/en/get-started/eclipse-setup.rst b/docs/en/get-started/eclipse-setup.rst index 26c694e36a..08b46fcf65 100644 --- a/docs/en/get-started/eclipse-setup.rst +++ b/docs/en/get-started/eclipse-setup.rst @@ -1,9 +1,12 @@ -**************************************** +******************************** Build and Flash with Eclipse IDE -**************************************** - +******************************** :link_to_translation:`zh_CN:[中文]` -Documentation for Eclipse setup with CMake-based build system and Eclipse CDT is coming soon. +ESP-IDF V4.0 will be released with a new CMake-based build system as the default build system. + +Eclipse CDT IDE support for CMake-based build system will be available before the ESP-IDF V4.0 release but +is not available yet. We apologise for the inconvenience. If you require Eclipse IDE support for this pre-release version of ESP-IDF, you can follow the :doc:`legacy GNU Make build system Getting Started guide ` which has steps for :doc:`Building and Flashing with Eclipse IDE `. + diff --git a/docs/en/hw-reference/get-started-ethernet-kit.rst b/docs/en/hw-reference/get-started-ethernet-kit.rst index 7a315c1aa7..13f1d7848f 100644 --- a/docs/en/hw-reference/get-started-ethernet-kit.rst +++ b/docs/en/hw-reference/get-started-ethernet-kit.rst @@ -348,9 +348,7 @@ Initial Setup Now to Development ^^^^^^^^^^^^^^^^^^ -Proceed to :doc:`../get-started-cmake/index`, where Section :ref:`get-started-step-by-step-cmake` will quickly help you set up the development environment and then flash an example project onto your board. - -If you prefer using an older GNU Make build system, then proceed to respective :ref:`get-started-step-by-step` for the GNU Make. +Proceed to :doc:`../get-started/index`, where Section :ref:`get-started-step-by-step` will quickly help you set up the development environment and then flash an example project onto your board. Move on to the next section only if you have successfully completed all the above steps. diff --git a/docs/page_redirects.txt b/docs/page_redirects.txt index 030b879798..fc1cee7988 100644 --- a/docs/page_redirects.txt +++ b/docs/page_redirects.txt @@ -46,7 +46,7 @@ get-started-cmake/get-started-wrover-kit-v3 hw-reference/get-started-wrover-k get-started-cmake/get-started-pico-kit hw-reference/get-started-pico-kit get-started-cmake/get-started-pico-kit-v3 hw-reference/get-started-pico-kit-v3 - api-guide/build-system-cmake api-guide/build-system api-guide/ulp-cmake api-guide/ulp +api-guide/unit-tests-cmake api-guide/unit-tests diff --git a/docs/zh_CN/api-guides/jtag-debugging/configure-wrover.rst b/docs/zh_CN/api-guides/jtag-debugging/configure-wrover.rst index f440d3c5a1..f8d2f0843a 100644 --- a/docs/zh_CN/api-guides/jtag-debugging/configure-wrover.rst +++ b/docs/zh_CN/api-guides/jtag-debugging/configure-wrover.rst @@ -8,7 +8,7 @@ 配置硬件 ^^^^^^^^ -1. 根据 :doc:`../../hw-reference/get-started-wrover-kit` 文档中 :ref:`get-started-esp-wrover-kit-v4.1-setup-options-cmake` 章节所描述的信息,设置 JP8 便可以启用 JTAG 功能。 +1. 根据 :doc:`../../hw-reference/get-started-wrover-kit` 文档中 :ref:`get-started-esp-wrover-kit-v4.1-setup-options` 章节所描述的信息,设置 JP8 便可以启用 JTAG 功能。 2. 检查 ESP32 上用于 JTAG 通信的引脚是否被接到了其它硬件上,这可能会影响 JTAG 的工作。 diff --git a/docs/zh_CN/hw-reference/get-started-devkitc-v2.rst b/docs/zh_CN/hw-reference/get-started-devkitc-v2.rst index f0ca5c62cf..2cd1075866 100644 --- a/docs/zh_CN/hw-reference/get-started-devkitc-v2.rst +++ b/docs/zh_CN/hw-reference/get-started-devkitc-v2.rst @@ -9,7 +9,7 @@ ESP32-DevKitC V2 入门指南 准备工作 -------- -* :ref:`ESP32-DevKitC V2 开发板 ` +* :ref:`ESP32-DevKitC V2 开发板 ` * USB A / micro USB B 数据线 * PC(Windows、Linux 或 Mac OS) @@ -27,7 +27,7 @@ ESP32-DevKitC V2 是 `乐鑫 `_ 一款基于 ESP32 的小 ESP32-DevKitC V2 开发板的主要组件、接口及控制方式见下。 -.. _get-started-esp32-devkitc-v2-board-front-cmake: +.. _get-started-esp32-devkitc-v2-board-front: .. figure:: ../../_static/esp32-devkitc-v2-functional-overview.png :align: center @@ -71,9 +71,7 @@ ESP32-DevKitC V2 开发板 ESP32-DevKitC V2 上电前,请首先确认开发板完好无损。 -之后,请前往 :doc:`../get-started-cmake/index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 - -如需使用较早 GNU Make 编译系统,则请参考 :ref:`get-started-step-by-step` 章节。 +之后,请前往 :doc:`../get-started/index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 相关文档 diff --git a/docs/zh_CN/hw-reference/get-started-devkitc.rst b/docs/zh_CN/hw-reference/get-started-devkitc.rst index 5e0f160cff..f75b5f80ae 100644 --- a/docs/zh_CN/hw-reference/get-started-devkitc.rst +++ b/docs/zh_CN/hw-reference/get-started-devkitc.rst @@ -9,14 +9,14 @@ ESP32-DevKitC V4 入门指南 准备工作 ----------- -* :ref:`ESP32-DevKitC V4 开发板 ` +* :ref:`ESP32-DevKitC V4 开发板 ` * USB A / micro USB B 数据线 * PC(Windows、Linux 或 Mac OS) 您可以跳过介绍部分,直接前往 `应用程序开发`_ 章节。 -.. _DevKitC-Overview-cmake: +.. _DevKitC-Overview: 概述 ---- @@ -46,7 +46,7 @@ ESP32-DevKitC V4 是 `乐鑫 `_ 一款基于 ESP32 的小 ESP32-DevKitC V4 开发板的主要组件、接口及控制方式见下。 -.. _get-started-esp32-devkitc-board-front-cmake: +.. _get-started-esp32-devkitc-board-front: .. figure:: ../../_static/esp32-devkitc-functional-overview.jpg :align: center @@ -121,10 +121,7 @@ C15(黄色)在 ESP32-DevKitC V4 开发板上的位置 ESP32-DevKitC V4 上电前,请首先确认开发板完好无损。 -之后,请前往 :doc:`../get-started-cmake/index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 - -如需使用较早 GNU Make 编译系统,则请参考 :ref:`get-started-step-by-step` 章节。 - +之后,请前往 :doc:`../get-started/index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 开发板尺寸 ------------- @@ -151,4 +148,4 @@ ESP32-DevKitC 开发板尺寸 -- 仰视图 .. toctree:: :hidden: - get-started-devkitc-v2 \ No newline at end of file + get-started-devkitc-v2 diff --git a/docs/zh_CN/hw-reference/get-started-pico-kit-v3.rst b/docs/zh_CN/hw-reference/get-started-pico-kit-v3.rst index 99b70fe898..a63129f83c 100644 --- a/docs/zh_CN/hw-reference/get-started-pico-kit-v3.rst +++ b/docs/zh_CN/hw-reference/get-started-pico-kit-v3.rst @@ -65,9 +65,7 @@ EN 复位按键。 ESP32-PICO-KIT V3 上电前,请首先确认开发板完好无损。 -之后,请前往 :doc:`../get-started-cmake/index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 - -如需使用较早 GNU Make 编译系统,则请参考 :ref:`get-started-step-by-step` 章节。 +之后,请前往 :doc:`../get-started/index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 相关文档 diff --git a/docs/zh_CN/hw-reference/get-started-pico-kit.rst b/docs/zh_CN/hw-reference/get-started-pico-kit.rst index a07b5b5785..10299ea2db 100644 --- a/docs/zh_CN/hw-reference/get-started-pico-kit.rst +++ b/docs/zh_CN/hw-reference/get-started-pico-kit.rst @@ -10,7 +10,7 @@ ESP32-PICO-KIT V4/V4.1 入门指南 准备工作 -------- -* :ref:`ESP32-PICO-KIT 迷你开发板 ` +* :ref:`ESP32-PICO-KIT 迷你开发板 ` * USB 2.0 线(A 型转 Micro-B 型) * PC(Windows、Linux 或 Mac OS) @@ -56,7 +56,7 @@ ESP32-PICO-KIT 开发板的主要组件和连接方式见下。 ESP32-PICO-KIT 开发板的主要组件、接口及控制方式见下。 -.. _get-started-pico-kit-v4-board-front-cmake: +.. _get-started-pico-kit-v4-board-front: .. figure:: ../../_static/esp32-pico-kit-v4.1-f-layout.jpeg :align: center @@ -106,7 +106,7 @@ EN 复位按键。 管脚说明 ---------- -下表介绍了开发板 I/O 管脚的 **名称** 和 **功能**,具体布局请见 `相关文档`_ 中的原理图。请参考 :ref:`get-started-pico-kit-v4-board-front-cmake`。 +下表介绍了开发板 I/O 管脚的 **名称** 和 **功能**,具体布局请见 `相关文档`_ 中的原理图。请参考 :ref:`get-started-pico-kit-v4-board-front`。 Header J2 @@ -115,9 +115,9 @@ Header J2 ====== ================= ====== ====================================================== 编号 名称 类型 功能 ====== ================= ====== ====================================================== -1 FLASH_SD1 (FSD1) I/O | GPIO8, SD_DATA1, SPID, HS1_DATA1 :ref:`(见说明 1) ` , U2CTS -2 FLASH_SD3 (FSD3) I/O | GPIO7, SD_DATA0, SPIQ, HS1_DATA0 :ref:`(见说明 1) ` , U2RTS -3 FLASH_CLK (FCLK) I/O | GPIO6, SD_CLK, SPICLK, HS1_CLK :ref:`(见说明 1) ` , U1CTS +1 FLASH_SD1 (FSD1) I/O | GPIO8, SD_DATA1, SPID, HS1_DATA1 :ref:`(见说明 1) ` , U2CTS +2 FLASH_SD3 (FSD3) I/O | GPIO7, SD_DATA0, SPIQ, HS1_DATA0 :ref:`(见说明 1) ` , U2RTS +3 FLASH_CLK (FCLK) I/O | GPIO6, SD_CLK, SPICLK, HS1_CLK :ref:`(见说明 1) ` , U1CTS 4 IO21 I/O | GPIO21, VSPIHD, EMAC_TX_EN 5 IO22 I/O | GPIO22, VSPIWP, U0RTS, EMAC_TXD1 6 IO19 I/O | GPIO19, VSPIQ, U0CTS, EMAC_TXD0 @@ -126,8 +126,8 @@ Header J2 9 IO5 I/O | GPIO5, VSPICS0, HS1_DATA6, EMAC_RX_CLK 10 IO10 I/O | GPIO10, SD_DATA3, SPIWP, HS1_DATA3, U1TXD 11 IO9 I/O | GPIO9, SD_DATA2, SPIHD, HS1_DATA2, U1RXD -12 RXD0 I/O | GPIO3, U0RXD :ref:`(见说明 3) ` , CLK_OUT2 -13 TXD0 I/O | GPIO1, U0TXD :ref:`(见说明 3) ` , CLK_OUT3, EMAC_RXD2 +12 RXD0 I/O | GPIO3, U0RXD :ref:`(见说明 3) ` , CLK_OUT2 +13 TXD0 I/O | GPIO1, U0TXD :ref:`(见说明 3) ` , CLK_OUT3, EMAC_RXD2 14 IO35 I | ADC1_CH7, RTC_GPIO5 15 IO34 I | ADC1_CH6, RTC_GPIO4 16 IO38 I | GPIO38, ADC1_CH2, RTC_GPIO2 @@ -144,20 +144,20 @@ Header J3 ====== ================= ====== ====================================================== No. Name Type Function ====== ================= ====== ====================================================== -1 FLASH_CS (FCS) I/O | GPIO16, HS1_DATA4 :ref:`(见说明 1) ` , U2RXD, EMAC_CLK_OUT -2 FLASH_SD0 (FSD0) I/O | GPIO17, HS1_DATA5 :ref:`(见说明 1) ` , U2TXD, EMAC_CLK_OUT_180 -3 FLASH_SD2 (FSD2) I/O | GPIO11, SD_CMD, SPICS0, HS1_CMD :ref:`(见说明 1) ` , U1RTS +1 FLASH_CS (FCS) I/O | GPIO16, HS1_DATA4 :ref:`(见说明 1) ` , U2RXD, EMAC_CLK_OUT +2 FLASH_SD0 (FSD0) I/O | GPIO17, HS1_DATA5 :ref:`(见说明 1) ` , U2TXD, EMAC_CLK_OUT_180 +3 FLASH_SD2 (FSD2) I/O | GPIO11, SD_CMD, SPICS0, HS1_CMD :ref:`(见说明 1) ` , U1RTS 4 SENSOR_VP (FSVP) I | GPIO36, ADC1_CH0, RTC_GPIO0 5 SENSOR_VN (FSVN) I | GPIO39, ADC1_CH3, RTC_GPIO3 6 IO25 I/O | GPIO25, DAC_1, ADC2_CH8, RTC_GPIO6, EMAC_RXD0 7 IO26 I/O | GPIO26, DAC_2, ADC2_CH9, RTC_GPIO7, EMAC_RXD1 -8 IO32 I/O | 32K_XP :ref:`(见说明 2a) ` , ADC1_CH4, TOUCH9, RTC_GPIO9 -9 IO33 I/O | 32K_XN :ref:`(见说明 2b) ` , ADC1_CH5, TOUCH8, RTC_GPIO8 +8 IO32 I/O | 32K_XP :ref:`(见说明 2a) ` , ADC1_CH4, TOUCH9, RTC_GPIO9 +9 IO33 I/O | 32K_XN :ref:`(见说明 2b) ` , ADC1_CH5, TOUCH8, RTC_GPIO8 10 IO27 I/O | GPIO27, ADC2_CH7, TOUCH7, RTC_GPIO17 | EMAC_RX_DV 11 IO14 I/O | ADC2_CH6, TOUCH6, RTC_GPIO16, MTMS, HSPICLK, | HS2_CLK, SD_CLK, EMAC_TXD2 -12 IO12 I/O | ADC2_CH5, TOUCH5, RTC_GPIO15, MTDI :ref:`(见说明 4) ` , HSPIQ, +12 IO12 I/O | ADC2_CH5, TOUCH5, RTC_GPIO15, MTDI :ref:`(见说明 4) ` , HSPIQ, | HS2_DATA2, SD_DATA2, EMAC_TXD3 13 IO13 I/O | ADC2_CH4, TOUCH4, RTC_GPIO14, MTCK, HSPID, | HS2_DATA3, SD_DATA3, EMAC_RX_ER @@ -175,7 +175,7 @@ No. Name Type Function ====== ================= ====== ====================================================== -.. _get-started-pico-kit-v4-pin-notes-cmake: +.. _get-started-pico-kit-v4-pin-notes: 有关上表的说明: @@ -190,9 +190,7 @@ No. Name Type Function ESP32-PICO-KIT 上电前,请首先确认开发板完好无损。 -之后,请前往 :doc:`../get-started-cmake/index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 - -如需使用较早 GNU Make 编译系统,则请参考 :ref:`get-started-step-by-step` 章节。 +之后,请前往 :doc:`../get-started/index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 开发板尺寸 diff --git a/docs/zh_CN/hw-reference/get-started-wrover-kit-v2.rst b/docs/zh_CN/hw-reference/get-started-wrover-kit-v2.rst index 1dcce65b90..c93c6f7833 100644 --- a/docs/zh_CN/hw-reference/get-started-wrover-kit-v2.rst +++ b/docs/zh_CN/hw-reference/get-started-wrover-kit-v2.rst @@ -52,7 +52,7 @@ ESP-WROVER-KIT 开发板的主要组件和连接方式如下图所示。 ESP-WROVER-KIT 开发板的主要组件、接口及控制方式见下。 -.. _get-started-esp-wrover-kit-v2-board-front-cmake: +.. _get-started-esp-wrover-kit-v2-board-front: .. figure:: ../../_static/esp-wrover-kit-v2-layout-front.png :align: center @@ -61,7 +61,7 @@ ESP-WROVER-KIT 开发板的主要组件、接口及控制方式见下。 ESP-WROVER-KIT 开发板布局 -- 俯视图 -.. _get-started-esp-wrover-kit-v2-board-back-cmake: +.. _get-started-esp-wrover-kit-v2-board-back: .. figure:: ../../_static/esp-wrover-kit-v2-layout-back.png :align: center @@ -113,11 +113,11 @@ I/O 板上模组的所有管脚均已引出至开发板的排 MicroSD 卡槽 MicroSD 卡槽,可扩充存储空间:当 ESP32 进入下载模式时,GPIO2 不可处于高电平。然而,为了使能 MicroSD 卡功能,需为 GPIO2 增加一个上拉电阻。默认情况下,GPIO2 和上拉电阻 R153 处于断开状态。为了使能 MicroSD 卡,请按照 `设置选项`_ 章节的要求,连接 JP1 连接器。 -LCD 显示屏 支持贴装一款 3.2” 的 SPI(标准四线串行外设接口)LCD 显示器,请见 :ref:`get-started-esp-wrover-kit-v2-board-back-cmake`。 +LCD 显示屏 支持贴装一款 3.2” 的 SPI(标准四线串行外设接口)LCD 显示器,请见 :ref:`get-started-esp-wrover-kit-v2-board-back`。 ==================== ====================================================================================================================================================================================================================================================================================================================================== -.. _get-started-esp-wrover-kit-v2-setup-options-cmake: +.. _get-started-esp-wrover-kit-v2-setup-options: 设置选项 ------------- @@ -137,7 +137,7 @@ JP14 |jp14| 使能 RTS/CTS 串口流控 ======= ================ ===================================================================================== -.. _get-started-esp-wrover-kit-v2-start-development-cmake: +.. _get-started-esp-wrover-kit-v2-start-development: 应用程序开发 ----------------------------- @@ -167,9 +167,7 @@ USB 供电 使能 UART 通信 正式开始开发 ^^^^^^^^^^^^^^^^^^ -请前往 :doc:`../get-started-cmake/index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 - -如需使用较早 GNU Make 编译系统,则请参考 :ref:`get-started-step-by-step` 章节。 +请前往 :doc:`../get-started/index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 相关文档 @@ -191,4 +189,4 @@ USB 供电 使能 UART 通信 .. |jp11-tx-rx| image:: ../../_static/wrover-jp11-tx-rx.png .. |jp14| image:: ../../_static/wrover-jp14.png -.. _ESP-WROVER-KIT V2 原理图: https://dl.espressif.com/dl/schematics/ESP-WROVER-KIT_SCH-2.pdf \ No newline at end of file +.. _ESP-WROVER-KIT V2 原理图: https://dl.espressif.com/dl/schematics/ESP-WROVER-KIT_SCH-2.pdf diff --git a/docs/zh_CN/hw-reference/get-started-wrover-kit-v3.rst b/docs/zh_CN/hw-reference/get-started-wrover-kit-v3.rst index 57a72931b0..0bf1349394 100644 --- a/docs/zh_CN/hw-reference/get-started-wrover-kit-v3.rst +++ b/docs/zh_CN/hw-reference/get-started-wrover-kit-v3.rst @@ -8,7 +8,7 @@ ESP-WROVER-KIT V3 入门指南 准备工作 ------------- -* :ref:`ESP-WROVER-KIT V3 开发板 ` +* :ref:`ESP-WROVER-KIT V3 开发板 ` * USB 数据线(A 转 Micro-B) * PC(Windows、Linux 或 macOS) @@ -52,7 +52,7 @@ ESP-WROVER-KIT 开发板的主要组件和连接方式如下图所示。 ESP-WROVER-KIT 开发板的主要组件、接口及控制方式见下。 -.. _get-started-esp-wrover-kit-v3-board-front-cmake: +.. _get-started-esp-wrover-kit-v3-board-front: .. figure:: ../../_static/esp-wrover-kit-v3-layout-front.jpg :align: center @@ -61,7 +61,7 @@ ESP-WROVER-KIT 开发板的主要组件、接口及控制方式见下。 ESP-WROVER-KIT 开发板布局 -- 俯视图 -.. _get-started-esp-wrover-kit-v3-board-back-cmake: +.. _get-started-esp-wrover-kit-v3-board-back: .. figure:: ../../_static/esp-wrover-kit-v3-layout-back.jpg :align: center @@ -115,11 +115,11 @@ I/O 板上模组的所有管脚均已引出至开发板的 MicroSD 卡槽 适用于需要扩充数据存储空间或进行备份的应用开发场景。 -LCD 显示屏 支持贴装一款 3.2” 的 SPI(标准四线串行外设接口)LCD 显示器,请见 :ref:`get-started-esp-wrover-kit-v3-board-back-cmake`。 +LCD 显示屏 支持贴装一款 3.2” 的 SPI(标准四线串行外设接口)LCD 显示器,请见 :ref:`get-started-esp-wrover-kit-v3-board-back`。 ==================== ====================================================================================================================================================================================================================================================================================================================================== -.. _get-started-esp-wrover-kit-v3-setup-options-cmake: +.. _get-started-esp-wrover-kit-v3-setup-options: 设置选项 ------------- @@ -175,17 +175,17 @@ JTAG,MicroSD IO15 5V 说明: -* NC/XTAL - :ref:`32.768 kHz Oscillator ` -* JTAG - :ref:`JTAG / JP8 ` +* NC/XTAL - :ref:`32.768 kHz Oscillator ` +* JTAG - :ref:`JTAG / JP8 ` * Boot - Boot 按键 / SW2 -* 摄像头 - :ref:`摄像头 / JP4 ` -* LED - :ref:`RGB LED ` -* MicroSD - :ref:`MicroSD Card / J4 ` -* LCD - :ref:`LCD / U5 ` +* 摄像头 - :ref:`摄像头 / JP4 ` +* LED - :ref:`RGB LED ` +* MicroSD - :ref:`MicroSD Card / J4 ` +* LCD - :ref:`LCD / U5 ` * PSRAM - 仅适用于选贴 ESP32-WROVER 的情况。 -.. _get-started-esp-wrover-kit-v3-xtal-cmake: +.. _get-started-esp-wrover-kit-v3-xtal: 32.768 kHz 晶振 ^^^^^^^^^^^^^^^^^^^^^ @@ -202,7 +202,7 @@ JTAG,MicroSD IO15 5V 默认情况下,管脚 GPIO32 和 GPIO33 已连接至晶振。因此,为了保证信号的完整性,这两个管脚并未连接至 JP1 I/O 连接器。用户可通过将 R11/R23 处的 0 欧电阻移至 R12/R24 处,以将 GP1O32 和 GPIO33 的连接从晶振移至 JP1。 -.. _get-started-esp-wrover-kit-v3-spi-flash-header-cmake: +.. _get-started-esp-wrover-kit-v3-spi-flash-header: SPI Flash / JP13 ^^^^^^^^^^^^^^^^ @@ -224,7 +224,7 @@ SPI Flash / JP13 -.. _get-started-esp-wrover-kit-v3-jtag-header-cmake: +.. _get-started-esp-wrover-kit-v3-jtag-header: JTAG / JP8 ^^^^^^^^^^ @@ -240,7 +240,7 @@ JTAG / JP8 ==== ============== ============= -.. _get-started-esp-wrover-kit-v3-camera-header-cmake: +.. _get-started-esp-wrover-kit-v3-camera-header: 摄像头 / JP4 ^^^^^^^^^^^^ @@ -271,7 +271,7 @@ JTAG / JP8 * D0 到 D7 为摄像头的数据总线 -.. _get-started-esp-wrover-kit-v3-rgb-led-connections-cmake: +.. _get-started-esp-wrover-kit-v3-rgb-led-connections: RGB LED ^^^^^^^ @@ -285,7 +285,7 @@ RGB LED ==== ========== ========= -.. _get-started-esp-wrover-kit-v3-microsd-card-slot-cmake: +.. _get-started-esp-wrover-kit-v3-microsd-card-slot: MicroSD 卡 ^^^^^^^^^^^^ @@ -303,7 +303,7 @@ MicroSD 卡 ==== ============== =============== -.. _get-started-esp-wrover-kit-v3-lcd-connector-cmake: +.. _get-started-esp-wrover-kit-v3-lcd-connector: LCD / U5 ^^^^^^^^ @@ -321,7 +321,7 @@ LCD / U5 ==== ============== =============== -.. _get-started-esp-wrover-kit-v3-start-development-cmake: +.. _get-started-esp-wrover-kit-v3-start-development: 应用程序开发 ----------------------------- @@ -351,9 +351,7 @@ USB 供电 使能 UART 通信 正式开始开发 ^^^^^^^^^^^^^^^^^^ -请前往 :doc:`../get-started-cmake/index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 - -如需使用较早 GNU Make 编译系统,则请参考 :ref:`get-started-step-by-step` 章节。 +请前往 :doc:`../get-started/index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 相关文档 diff --git a/docs/zh_CN/hw-reference/get-started-wrover-kit.rst b/docs/zh_CN/hw-reference/get-started-wrover-kit.rst index b08547841d..98ffae468f 100644 --- a/docs/zh_CN/hw-reference/get-started-wrover-kit.rst +++ b/docs/zh_CN/hw-reference/get-started-wrover-kit.rst @@ -8,7 +8,7 @@ ESP-WROVER-KIT V4.1 入门指南 准备工作 ------------- -* :ref:`ESP-WROVER-KIT V4.1 开发板 ` +* :ref:`ESP-WROVER-KIT V4.1 开发板 ` * USB 数据线(A 转 Micro-B) * PC(Windows、Linux 或 macOS) @@ -53,7 +53,7 @@ ESP-WROVER-KIT 开发板的主要组件和连接方式如下图所示。 ESP-WROVER-KIT 开发板的主要组件、接口及控制方式见下。 -.. _get-started-esp-wrover-kit-v4.1-board-front-cmake: +.. _get-started-esp-wrover-kit-v4.1-board-front: .. figure:: ../../_static/esp-wrover-kit-v4.1-layout-front.png :align: center @@ -62,7 +62,7 @@ ESP-WROVER-KIT 开发板的主要组件、接口及控制方式见下。 ESP-WROVER-KIT 开发板布局 -- 俯视图 -.. _get-started-esp-wrover-kit-v4.1-board-back-cmake: +.. _get-started-esp-wrover-kit-v4.1-board-back: .. figure:: ../../_static/esp-wrover-kit-v4.1-layout-back.png :align: center @@ -120,11 +120,11 @@ I/O 连接器 板上模组的所有管脚均已引出至开发板 MicroSD 卡槽 适用于需要扩充数据存储空间或进行备份的应用开发场景。 -LCD 显示屏 支持贴装一款 3.2” 的 SPI(标准四线串行外设接口)LCD 显示器,请见 :ref:`get-started-esp-wrover-kit-v4.1-board-back-cmake`。 +LCD 显示屏 支持贴装一款 3.2” 的 SPI(标准四线串行外设接口)LCD 显示器,请见 :ref:`get-started-esp-wrover-kit-v4.1-board-back`。 ==================== ====================================================================================================================================================================================================================================================================================================================================== -.. _get-started-esp-wrover-kit-v4.1-setup-options-cmake: +.. _get-started-esp-wrover-kit-v4.1-setup-options: 设置选项 ------------- @@ -180,17 +180,17 @@ JTAG,MicroSD IO15 5V 说明: -* NC/XTAL - :ref:`32.768 kHz 晶振 ` -* JTAG - :ref:`JTAG / JP8 ` +* NC/XTAL - :ref:`32.768 kHz 晶振 ` +* JTAG - :ref:`JTAG / JP8 ` * Boot - Boot 按键 / SW2 -* 摄像头 - :ref:`摄像头 / JP4 ` -* LED - :ref:`RGB LED ` -* MicroSD - :ref:`MicroSD Card / J4 ` -* LCD - :ref:`LCD / U5 ` +* 摄像头 - :ref:`摄像头 / JP4 ` +* LED - :ref:`RGB LED ` +* MicroSD - :ref:`MicroSD Card / J4 ` +* LCD - :ref:`LCD / U5 ` * PSRAM - ESP32-WROVER-B 的 PSRAM -.. _get-started-esp-wrover-kit-v4.1-xtal-cmake: +.. _get-started-esp-wrover-kit-v4.1-xtal: 32.768 kHz 晶振 ^^^^^^^^^^^^^^^^^^^^^ @@ -207,7 +207,7 @@ JTAG,MicroSD IO15 5V 默认情况下,管脚 GPIO32 和 GPIO33 已连接至晶振。因此,为了保证信号的完整性,这两个管脚并未连接至 JP1 I/O 连接器。用户可通过将 R11/R23 处的 0 欧电阻移至 R12/R24 处,以将 GP1O32 和 GPIO33 的连接从晶振移至 JP1。 -.. _get-started-esp-wrover-kit-v4.1-spi-flash-header-cmake: +.. _get-started-esp-wrover-kit-v4.1-spi-flash-header: SPI Flash / JP2 ^^^^^^^^^^^^^^^ @@ -229,7 +229,7 @@ SPI Flash / JP2 -.. _get-started-esp-wrover-kit-v4.1-jtag-header-cmake: +.. _get-started-esp-wrover-kit-v4.1-jtag-header: JTAG / JP2 ^^^^^^^^^^ @@ -245,7 +245,7 @@ JTAG / JP2 ==== ============== ============= -.. _get-started-esp-wrover-kit-v4.1-camera-header-cmake: +.. _get-started-esp-wrover-kit-v4.1-camera-header: 摄像头 / JP4 ^^^^^^^^^^^^ @@ -276,7 +276,7 @@ JTAG / JP2 * D0 到 D7 为摄像头的数据总线 -.. _get-started-esp-wrover-kit-v4.1-rgb-led-connections-cmake: +.. _get-started-esp-wrover-kit-v4.1-rgb-led-connections: RGB LED ^^^^^^^ @@ -290,7 +290,7 @@ RGB LED ==== ========== ========= -.. _get-started-esp-wrover-kit-v4.1-microsd-card-slot-cmake: +.. _get-started-esp-wrover-kit-v4.1-microsd-card-slot: MicroSD 卡 ^^^^^^^^^^^^ @@ -308,7 +308,7 @@ MicroSD 卡 ==== ============== =============== -.. _get-started-esp-wrover-kit-v4.1-lcd-connector-cmake: +.. _get-started-esp-wrover-kit-v4.1-lcd-connector: LCD / U5 ^^^^^^^^ @@ -326,7 +326,7 @@ LCD / U5 ==== ============== =============== -.. _get-started-esp-wrover-kit-start-development-cmake: +.. _get-started-esp-wrover-kit-start-development: 应用程序开发 ----------------------------- @@ -356,7 +356,7 @@ USB 供电 使能 UART 通信 正式开始开发 ^^^^^^^^^^^^^^^^^^ -请前往 :doc:`../get-started-cmake/index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 +请前往 :doc:`../get-started/index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 如需使用较早 GNU Make 编译系统,则请参考 :ref:`get-started-step-by-step` 章节。 @@ -382,4 +382,4 @@ USB 供电 使能 UART 通信 :hidden: get-started-wrover-kit-v3.rst - get-started-wrover-kit-v2.rst \ No newline at end of file + get-started-wrover-kit-v2.rst From 9583c8d037236d9ae9bf8d884dbbf0a6491ecd17 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 5 Jul 2019 16:25:40 +1000 Subject: [PATCH 288/486] docs: Rephrase the warning about not requiring MSYS2 on Windows --- docs/en/get-started/windows-setup.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/get-started/windows-setup.rst b/docs/en/get-started/windows-setup.rst index 0ff57c7198..9dccad8dc5 100644 --- a/docs/en/get-started/windows-setup.rst +++ b/docs/en/get-started/windows-setup.rst @@ -15,7 +15,7 @@ ESP-IDF requires some prerequisite tools to be installed so you can build firmwa For this Getting Started we're going to use the Command Prompt, but after ESP-IDF is installed you can use :doc:`Eclipse ` or another graphical IDE with CMake support instead. .. note:: - The GNU Make based build system requires the MSYS2_ Unix compatibility environment on Windows. The CMake-based build system does not require this environment. + Previous versions of ESP-IDF used the :doc:`Legacy GNU Make Build System<../get-started-legacy/windows-setup>` and MSYS2_ Unix compatibility environment. This is no longer required, ESP-IDF can be used from the Windows Command Prompt. .. _get-started-windows-tools-installer: From f8c107fbe3ba1ab9825973b8b52941f4577db88e Mon Sep 17 00:00:00 2001 From: baohongde Date: Tue, 9 Jul 2019 17:50:43 +0800 Subject: [PATCH 289/486] components/bt: Fix compile error with new toolchain Closes https://github.com/espressif/esp-idf/issues/3331 Closes https://github.com/espressif/esp-idf/issues/3734 --- components/bt/common/osi/config.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/bt/common/osi/config.c b/components/bt/common/osi/config.c index c1d9a8ad58..b1dcfeca56 100644 --- a/components/bt/common/osi/config.c +++ b/components/bt/common/osi/config.c @@ -440,8 +440,9 @@ bool config_save(const config_t *config, const char *filename) goto error; } }else { - uint count = (w_cnt_total / CONFIG_FILE_MAX_SIZE); - for (int i = 0; i <= count; i++) + int count = (w_cnt_total / CONFIG_FILE_MAX_SIZE); + assert(count <= 0xFF); + for (uint8_t i = 0; i <= count; i++) { snprintf(keyname, keyname_bufsz, "%s%d", CONFIG_KEY, i); if (i == count) { From 80e9faaf1c1463f3800d864d8c4e42ed92d4d768 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 9 Jul 2019 20:35:34 +1000 Subject: [PATCH 290/486] docs: Move Legacy Get Started guide to the Related Documents section --- docs/en/get-started/index.rst | 1 + docs/en/index.rst | 1 - docs/zh_CN/get-started/index.rst | 1 + docs/zh_CN/index.rst | 1 - 4 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/get-started/index.rst b/docs/en/get-started/index.rst index a60684e35b..51b87fa32c 100644 --- a/docs/en/get-started/index.rst +++ b/docs/en/get-started/index.rst @@ -495,6 +495,7 @@ Related Documents eclipse-setup ../api-guides/tools/idf-monitor toolchain-setup-scratch + ../get-started-legacy/index .. _Stable version: https://docs.espressif.com/projects/esp-idf/en/stable/ .. _Releases page: https://github.com/espressif/esp-idf/releases diff --git a/docs/en/index.rst b/docs/en/index.rst index 8ce586174f..d8a10c1d45 100644 --- a/docs/en/index.rst +++ b/docs/en/index.rst @@ -39,7 +39,6 @@ This is the documentation for Espressif IoT Development Framework (`esp-idf - Get Started (Legacy GNU Make) API Reference H/W Reference API Guides diff --git a/docs/zh_CN/get-started/index.rst b/docs/zh_CN/get-started/index.rst index 9c3ea3d3b6..1baf28fcbb 100644 --- a/docs/zh_CN/get-started/index.rst +++ b/docs/zh_CN/get-started/index.rst @@ -487,6 +487,7 @@ Python 2.7 安装程序将尝试配置 Windows,将 ``.py`` 文件与 Python 2 eclipse-setup ../api-guides/tools/idf-monitor toolchain-setup-scratch + ../get-started-legacy/index .. _Stable version: https://docs.espressif.com/projects/esp-idf/zh_CN/stable/ .. _Releases page: https://github.com/espressif/esp-idf/releases diff --git a/docs/zh_CN/index.rst b/docs/zh_CN/index.rst index 1feb1c1e37..dfdd2da239 100644 --- a/docs/zh_CN/index.rst +++ b/docs/zh_CN/index.rst @@ -40,7 +40,6 @@ ESP-IDF 编程指南 :hidden: 快速入门 - 快速入门 (传统 GNU Make) API 参考 H/W 参考 API 指南 From 896d6752485e3c9c9aa689c4a7fa63371c573fe1 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 9 Jul 2019 13:00:16 +0200 Subject: [PATCH 291/486] idf_tools.py: add another platform string to handle Windows x86 --- tools/idf_tools.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/idf_tools.py b/tools/idf_tools.py index c005ecd6f4..7cdd182366 100755 --- a/tools/idf_tools.py +++ b/tools/idf_tools.py @@ -96,6 +96,7 @@ PLATFORM_FROM_NAME = { # Windows PLATFORM_WIN32: PLATFORM_WIN32, 'Windows-i686': PLATFORM_WIN32, + 'Windows-x86': PLATFORM_WIN32, PLATFORM_WIN64: PLATFORM_WIN64, 'Windows-x86_64': PLATFORM_WIN64, 'Windows-AMD64': PLATFORM_WIN64, From 76dc87e9adb6ed9026c71ab2f32d0b4b25d9bb95 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 9 Jul 2019 14:10:00 +0200 Subject: [PATCH 292/486] idf_exe: fix NULL pointer passed to WriteFile For an unknown reason, passing NULL pointer instead of &written worked on Windows 10 and on Windows 7 when stdout is not redirected. Closes https://github.com/espressif/esp-idf/issues/3740 --- tools/windows/idf_exe/idf_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/windows/idf_exe/idf_main.c b/tools/windows/idf_exe/idf_main.c index a8d1aec541..f17fc7f41b 100644 --- a/tools/windows/idf_exe/idf_main.c +++ b/tools/windows/idf_exe/idf_main.c @@ -48,7 +48,8 @@ int main(int argc, LPTSTR argv[]) (StrCmp(argv[1], TEXT("--version")) == 0 || StrCmp(argv[1], TEXT("-v")) == 0)) { LPCSTR msg = VERSION "\n"; - WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msg, lstrlen(msg), NULL, NULL); + DWORD written; + WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msg, lstrlen(msg), &written, NULL); return 0; } From 15bcb79712c1c2b3607fa4ab82e5bc24ebabfed0 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 9 Jul 2019 14:10:05 +0200 Subject: [PATCH 293/486] idf_exe: bump version to 1.0.1 --- tools/windows/idf_exe/CMakeLists.txt | 3 ++- tools/windows/idf_exe/idf_main.c | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/windows/idf_exe/CMakeLists.txt b/tools/windows/idf_exe/CMakeLists.txt index ba7e940af7..7693412e91 100644 --- a/tools/windows/idf_exe/CMakeLists.txt +++ b/tools/windows/idf_exe/CMakeLists.txt @@ -1,10 +1,11 @@ cmake_minimum_required(VERSION 3.5) project(idfexe) -set(VERSION 1.0) +set(VERSION 1.0.1) set(ARCHIVE_NAME idf-exe-v${VERSION}.zip) add_executable(idf idf_main.c) +target_compile_definitions(idf PRIVATE -DVERSION=\"${VERSION}\") set_target_properties(idf PROPERTIES C_STANDARD 99) target_link_libraries(idf "-lshlwapi") diff --git a/tools/windows/idf_exe/idf_main.c b/tools/windows/idf_exe/idf_main.c index f17fc7f41b..3a8e6dcfbb 100644 --- a/tools/windows/idf_exe/idf_main.c +++ b/tools/windows/idf_exe/idf_main.c @@ -18,7 +18,6 @@ #include #define LINESIZE 1024 -#define VERSION "1.0" static void fail(LPCSTR message, ...) __attribute__((noreturn)); From e6e17929463b4f154ba9fd4dcfef2fb9e36425ef Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 9 Jul 2019 13:11:53 +0200 Subject: [PATCH 294/486] tools: update idf_exe to 1.0.1 --- tools/tools.json | 14 +++++++------- tools/windows/tool_setup/tools_fallback.json | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tools/tools.json b/tools/tools.json index 54249d7dcc..5bbed7e8b7 100644 --- a/tools/tools.json +++ b/tools/tools.json @@ -334,17 +334,17 @@ "version_regex": "([0-9.]+)", "versions": [ { - "name": "1.0", + "name": "1.0.1", "status": "recommended", "win32": { - "sha256": "83a83ac7a246cbae93884db7c5f2ef9a7607d602340b1cf1e64ec2a925071748", - "size": 11289, - "url": "https://dl.espressif.com/dl/idf-exe-v1.0.zip" + "sha256": "53eb6aaaf034cc7ed1a97d5c577afa0f99815b7793905e9408e74012d357d04a", + "size": 11297, + "url": "https://dl.espressif.com/dl/idf-exe-v1.0.1.zip" }, "win64": { - "sha256": "83a83ac7a246cbae93884db7c5f2ef9a7607d602340b1cf1e64ec2a925071748", - "size": 11289, - "url": "https://dl.espressif.com/dl/idf-exe-v1.0.zip" + "sha256": "53eb6aaaf034cc7ed1a97d5c577afa0f99815b7793905e9408e74012d357d04a", + "size": 11297, + "url": "https://dl.espressif.com/dl/idf-exe-v1.0.1.zip" } } ] diff --git a/tools/windows/tool_setup/tools_fallback.json b/tools/windows/tool_setup/tools_fallback.json index 6b1585c8a4..2422f2f4e4 100644 --- a/tools/windows/tool_setup/tools_fallback.json +++ b/tools/windows/tool_setup/tools_fallback.json @@ -333,17 +333,17 @@ "version_regex": "([0-9.]+)", "versions": [ { - "name": "1.0", + "name": "1.0.1", "status": "recommended", "win32": { - "sha256": "83a83ac7a246cbae93884db7c5f2ef9a7607d602340b1cf1e64ec2a925071748", - "size": 11289, - "url": "https://dl.espressif.com/dl/idf-exe-v1.0.zip" + "sha256": "53eb6aaaf034cc7ed1a97d5c577afa0f99815b7793905e9408e74012d357d04a", + "size": 11297, + "url": "https://dl.espressif.com/dl/idf-exe-v1.0.1.zip" }, "win64": { - "sha256": "83a83ac7a246cbae93884db7c5f2ef9a7607d602340b1cf1e64ec2a925071748", - "size": 11289, - "url": "https://dl.espressif.com/dl/idf-exe-v1.0.zip" + "sha256": "53eb6aaaf034cc7ed1a97d5c577afa0f99815b7793905e9408e74012d357d04a", + "size": 11297, + "url": "https://dl.espressif.com/dl/idf-exe-v1.0.1.zip" } } ] From 900df445462b8a8103f96b1a8161623808d5520e Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Wed, 3 Jul 2019 17:39:52 +0530 Subject: [PATCH 295/486] wpa_supplicant: Cleanup fast_xxx modules that use duplicate code wpa_supplicant is using MbedTLS API's for crypto algorithms. For calling them a duplicate set of modules is maintained prepended with 'fast_'. Remove these and use flag USE_MBEDTLS_CRYPTO instead to separate modules calling MbedTLS API's from native implementation. --- components/esp_wifi/CMakeLists.txt | 2 +- .../src/{fast_crypto_ops.c => crypto_ops.c} | 21 +- components/wpa_supplicant/CMakeLists.txt | 8 - components/wpa_supplicant/Kconfig | 6 + components/wpa_supplicant/component.mk | 2 +- .../wpa_supplicant/include/crypto/aes_wrap.h | 6 - .../wpa_supplicant/include/crypto/crypto.h | 139 --------- .../wpa_supplicant/include/crypto/sha256.h | 6 - .../port/include/supplicant_opt.h | 4 + components/wpa_supplicant/src/ap/wpa_auth.c | 4 +- .../wpa_supplicant/src/common/wpa_common.c | 4 +- .../wpa_supplicant/src/crypto/aes-cbc.c | 86 +++++- .../wpa_supplicant/src/crypto/aes-unwrap.c | 41 +++ .../wpa_supplicant/src/crypto/aes-wrap.c | 42 +++ .../src/crypto/crypto_internal-cipher.c | 48 +++ .../src/crypto/crypto_internal-modexp.c | 59 ++++ .../src/crypto/crypto_internal.c | 64 ++++ .../wpa_supplicant/src/crypto/dh_groups.c | 4 +- .../src/crypto/sha256-internal.c | 62 ++++ components/wpa_supplicant/src/crypto/sha256.c | 15 + .../src/fast_crypto/fast_aes-cbc.c | 78 ----- .../src/fast_crypto/fast_aes-unwrap.c | 84 ----- .../src/fast_crypto/fast_aes-wrap.c | 83 ----- .../fast_crypto/fast_crypto_internal-cipher.c | 287 ------------------ .../fast_crypto/fast_crypto_internal-modexp.c | 59 ---- .../src/fast_crypto/fast_crypto_internal.c | 278 ----------------- .../src/fast_crypto/fast_sha256-internal.c | 58 ---- .../src/fast_crypto/fast_sha256.c | 165 ---------- components/wpa_supplicant/src/rsn_supp/wpa.c | 4 +- components/wpa_supplicant/src/tls/pkcs5.c | 12 +- .../src/tls/tlsv1_client_read.c | 2 +- .../src/tls/tlsv1_client_write.c | 4 +- .../wpa_supplicant/src/tls/tlsv1_common.c | 18 +- .../wpa_supplicant/src/tls/tlsv1_record.c | 36 +-- .../src/tls/tlsv1_server_read.c | 2 +- .../src/tls/tlsv1_server_write.c | 2 +- components/wpa_supplicant/src/tls/x509v3.c | 2 +- .../wpa_supplicant/src/wps/wps_attr_build.c | 10 +- .../wpa_supplicant/src/wps/wps_attr_process.c | 4 +- .../wpa_supplicant/src/wps/wps_common.c | 12 +- .../wpa_supplicant/src/wps/wps_enrollee.c | 8 +- .../wpa_supplicant/src/wps/wps_registrar.c | 10 +- 42 files changed, 506 insertions(+), 1335 deletions(-) rename components/esp_wifi/src/{fast_crypto_ops.c => crypto_ops.c} (69%) delete mode 100644 components/wpa_supplicant/src/fast_crypto/fast_aes-cbc.c delete mode 100644 components/wpa_supplicant/src/fast_crypto/fast_aes-unwrap.c delete mode 100644 components/wpa_supplicant/src/fast_crypto/fast_aes-wrap.c delete mode 100644 components/wpa_supplicant/src/fast_crypto/fast_crypto_internal-cipher.c delete mode 100644 components/wpa_supplicant/src/fast_crypto/fast_crypto_internal-modexp.c delete mode 100644 components/wpa_supplicant/src/fast_crypto/fast_crypto_internal.c delete mode 100644 components/wpa_supplicant/src/fast_crypto/fast_sha256-internal.c delete mode 100644 components/wpa_supplicant/src/fast_crypto/fast_sha256.c diff --git a/components/esp_wifi/CMakeLists.txt b/components/esp_wifi/CMakeLists.txt index 469497f699..4994e19dc3 100644 --- a/components/esp_wifi/CMakeLists.txt +++ b/components/esp_wifi/CMakeLists.txt @@ -5,7 +5,7 @@ if(NOT CONFIG_ESP32_NO_BLOBS) endif() idf_component_register(SRCS "src/coexist.c" - "src/fast_crypto_ops.c" + "src/crypto_ops.c" "src/lib_printf.c" "src/mesh_event.c" "src/phy_init.c" diff --git a/components/esp_wifi/src/fast_crypto_ops.c b/components/esp_wifi/src/crypto_ops.c similarity index 69% rename from components/esp_wifi/src/fast_crypto_ops.c rename to components/esp_wifi/src/crypto_ops.c index c8146b47e3..fdef5ca57e 100644 --- a/components/esp_wifi/src/fast_crypto_ops.c +++ b/components/esp_wifi/src/crypto_ops.c @@ -22,19 +22,18 @@ #include "crypto/dh_group5.h" #include "esp_wifi_crypto_types.h" /* - * The parameters is used to set the cyrpto callback function for station connect when in security mode, - * every callback function can register as fast_xxx or normal one, i.e, fast_aes_wrap or aes_wrap, the - * difference between them is the normal API is calculate by software, the fast one use the hardware - * crypto in it, can be faster than the normal one, so the callback function register in default is which - * we recommend, so as the API in WPS default and WPA2 default. + * This structure is used to set the cyrpto callback function for station to connect when in security mode. + * These functions either call MbedTLS API's if USE_MBEDTLS_CRYPTO flag is set through Kconfig, or native + * API's otherwise. We recommend setting the flag since MbedTLS API's utilize hardware acceleration while + * native API's are use software implementations. */ const wpa_crypto_funcs_t g_wifi_default_wpa_crypto_funcs = { .size = sizeof(wpa_crypto_funcs_t), .version = ESP_WIFI_CRYPTO_VERSION, - .aes_wrap = (esp_aes_wrap_t)fast_aes_wrap, - .aes_unwrap = (esp_aes_unwrap_t)fast_aes_unwrap, - .hmac_sha256_vector = (esp_hmac_sha256_vector_t)fast_hmac_sha256_vector, - .sha256_prf = (esp_sha256_prf_t)fast_sha256_prf, + .aes_wrap = (esp_aes_wrap_t)aes_wrap, + .aes_unwrap = (esp_aes_unwrap_t)aes_unwrap, + .hmac_sha256_vector = (esp_hmac_sha256_vector_t)hmac_sha256_vector, + .sha256_prf = (esp_sha256_prf_t)sha256_prf, .hmac_md5 = (esp_hmac_md5_t)hmac_md5, .hamc_md5_vector = (esp_hmac_md5_vector_t)hmac_md5_vector, .hmac_sha1 = (esp_hmac_sha1_t)hmac_sha1, @@ -53,6 +52,6 @@ const wpa_crypto_funcs_t g_wifi_default_wpa_crypto_funcs = { }; const mesh_crypto_funcs_t g_wifi_default_mesh_crypto_funcs = { - .aes_128_encrypt = (esp_aes_128_encrypt_t)fast_aes_128_cbc_encrypt, - .aes_128_decrypt = (esp_aes_128_decrypt_t)fast_aes_128_cbc_decrypt, + .aes_128_encrypt = (esp_aes_128_encrypt_t)aes_128_cbc_encrypt, + .aes_128_decrypt = (esp_aes_128_decrypt_t)aes_128_cbc_decrypt, }; diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index b7d2958e2b..2b7e14924f 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -29,14 +29,6 @@ set(srcs "port/os_xtensa.c" "src/crypto/sha1.c" "src/crypto/sha256-internal.c" "src/crypto/sha256.c" - "src/fast_crypto/fast_aes-cbc.c" - "src/fast_crypto/fast_aes-unwrap.c" - "src/fast_crypto/fast_aes-wrap.c" - "src/fast_crypto/fast_crypto_internal-cipher.c" - "src/fast_crypto/fast_crypto_internal-modexp.c" - "src/fast_crypto/fast_crypto_internal.c" - "src/fast_crypto/fast_sha256-internal.c" - "src/fast_crypto/fast_sha256.c" "src/eap_peer/chap.c" "src/eap_peer/eap.c" "src/eap_peer/eap_common.c" diff --git a/components/wpa_supplicant/Kconfig b/components/wpa_supplicant/Kconfig index efcf5ecc56..3d57c76e08 100644 --- a/components/wpa_supplicant/Kconfig +++ b/components/wpa_supplicant/Kconfig @@ -27,4 +27,10 @@ menu "Supplicant" help Select this option to support EAP-PEAP. + config WPA_MBEDTLS_CRYPTO + bool "Use MbedTLS crypto API's" + default y + help + Select this option to use MbedTLS crypto API's which utilize hardware acceleration. + endmenu diff --git a/components/wpa_supplicant/component.mk b/components/wpa_supplicant/component.mk index dfc2f17dfd..1320854b95 100644 --- a/components/wpa_supplicant/component.mk +++ b/components/wpa_supplicant/component.mk @@ -1,5 +1,5 @@ COMPONENT_ADD_INCLUDEDIRS := include port/include include/esp_supplicant COMPONENT_PRIV_INCLUDEDIRS := src -COMPONENT_SRCDIRS := port src/ap src/common src/crypto src/eap_peer src/fast_crypto src/rsn_supp src/tls src/utils src/esp_supplicant src/wps +COMPONENT_SRCDIRS := port src/ap src/common src/crypto src/eap_peer src/rsn_supp src/tls src/utils src/esp_supplicant src/wps CFLAGS += -DESP_SUPPLICANT -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_MSCHAPv2 -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DCONFIG_ECC -D__ets__ -Wno-strict-aliasing diff --git a/components/wpa_supplicant/include/crypto/aes_wrap.h b/components/wpa_supplicant/include/crypto/aes_wrap.h index 933031e4ba..e6912054f0 100644 --- a/components/wpa_supplicant/include/crypto/aes_wrap.h +++ b/components/wpa_supplicant/include/crypto/aes_wrap.h @@ -44,10 +44,4 @@ int __must_check aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len); int __must_check aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len); -int __must_check fast_aes_wrap(const uint8_t *kek, int n, const uint8_t *plain, uint8_t *cipher); -int __must_check fast_aes_unwrap(const uint8_t *kek, int n, const uint8_t *cipher, uint8_t *plain); -int __must_check fast_aes_128_cbc_encrypt(const uint8_t *key, const uint8_t *iv, uint8_t *data, - size_t data_len); -int __must_check fast_aes_128_cbc_decrypt(const uint8_t *key, const uint8_t *iv, uint8_t *data, - size_t data_len); #endif /* AES_WRAP_H */ diff --git a/components/wpa_supplicant/include/crypto/crypto.h b/components/wpa_supplicant/include/crypto/crypto.h index fd69dc9682..9c57c50db1 100644 --- a/components/wpa_supplicant/include/crypto/crypto.h +++ b/components/wpa_supplicant/include/crypto/crypto.h @@ -102,17 +102,6 @@ int __must_check fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); -/** - * fast_sha256_vector - fast SHA256 hash for data vector - * @num_elem: Number of elements in the data vector - * @addr: Pointers to the data areas - * @len: Lengths of the data blocks - * @mac: Buffer for the hash - * Returns: 0 on success, -1 on failure - */ -int fast_sha256_vector(size_t num_elem, const uint8_t *addr[], const size_t *len, - uint8_t *mac); - /** * des_encrypt - Encrypt one block with DES * @clear: 8 octets (in) @@ -189,21 +178,6 @@ struct crypto_hash; struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, size_t key_len); -/** - * fast_crypto_hash_init - Initialize hash/HMAC function - * @alg: Hash algorithm - * @key: Key for keyed hash (e.g., HMAC) or %NULL if not needed - * @key_len: Length of the key in bytes - * Returns: Pointer to hash context to use with other hash functions or %NULL - * on failure - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -struct crypto_hash * fast_crypto_hash_init(enum crypto_hash_alg alg, const uint8_t *key, - size_t key_len); - /** * crypto_hash_update - Add data to hash calculation * @ctx: Context pointer from crypto_hash_init() @@ -216,18 +190,6 @@ struct crypto_hash * fast_crypto_hash_init(enum crypto_hash_alg alg, const uint8 */ void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len); -/** - * fast_crypto_hash_update - Add data to hash calculation - * @ctx: Context pointer from crypto_hash_init() - * @data: Data buffer to add - * @len: Length of the buffer - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -void fast_crypto_hash_update(struct crypto_hash *ctx, const uint8_t *data, size_t len); - /** * crypto_hash_finish - Complete hash calculation * @ctx: Context pointer from crypto_hash_init() @@ -247,26 +209,6 @@ void fast_crypto_hash_update(struct crypto_hash *ctx, const uint8_t *data, size_ */ int crypto_hash_finish(struct crypto_hash *ctx, u8 *hash, size_t *len); -/** - * fast_crypto_hash_finish - Complete hash calculation - * @ctx: Context pointer from crypto_hash_init() - * @hash: Buffer for hash value or %NULL if caller is just freeing the hash - * context - * @len: Pointer to length of the buffer or %NULL if caller is just freeing the - * hash context; on return, this is set to the actual length of the hash value - * Returns: 0 on success, -1 if buffer is too small (len set to needed length), - * or -2 on other failures (including failed crypto_hash_update() operations) - * - * This function calculates the hash value and frees the context buffer that - * was used for hash calculation. - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -int fast_crypto_hash_finish(struct crypto_hash *ctx, uint8_t *hash, size_t *len); - - enum crypto_cipher_alg { CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES, CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4 @@ -291,22 +233,6 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, const u8 *iv, const u8 *key, size_t key_len); -/** - * fast_crypto_cipher_init - Initialize block/stream cipher function - * @alg: Cipher algorithm - * @iv: Initialization vector for block ciphers or %NULL for stream ciphers - * @key: Cipher key - * @key_len: Length of key in bytes - * Returns: Pointer to cipher context to use with other cipher functions or - * %NULL on failure - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -struct crypto_cipher * fast_crypto_cipher_init(enum crypto_cipher_alg alg, - const uint8_t *iv, const uint8_t *key, - size_t key_len); /** * crypto_cipher_encrypt - Cipher encrypt * @ctx: Context pointer from crypto_cipher_init() @@ -322,21 +248,6 @@ struct crypto_cipher * fast_crypto_cipher_init(enum crypto_cipher_alg alg, int __must_check crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, u8 *crypt, size_t len); -/** - * fast_crypto_cipher_encrypt - Cipher encrypt - * @ctx: Context pointer from crypto_cipher_init() - * @plain: Plaintext to cipher - * @crypt: Resulting ciphertext - * @len: Length of the plaintext - * Returns: 0 on success, -1 on failure - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -int __must_check fast_crypto_cipher_encrypt(struct crypto_cipher *ctx, - const uint8_t *plain, uint8_t *crypt, size_t len); - /** * crypto_cipher_decrypt - Cipher decrypt * @ctx: Context pointer from crypto_cipher_init() @@ -352,21 +263,6 @@ int __must_check fast_crypto_cipher_encrypt(struct crypto_cipher *ctx, int __must_check crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, u8 *plain, size_t len); -/** - * fast_crypto_cipher_decrypt - Cipher decrypt - * @ctx: Context pointer from crypto_cipher_init() - * @crypt: Ciphertext to decrypt - * @plain: Resulting plaintext - * @len: Length of the cipher text - * Returns: 0 on success, -1 on failure - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -int __must_check fast_crypto_cipher_decrypt(struct crypto_cipher *ctx, - const uint8_t *crypt, uint8_t *plain, size_t len); - /** * crypto_cipher_decrypt - Free cipher context * @ctx: Context pointer from crypto_cipher_init() @@ -377,16 +273,6 @@ int __must_check fast_crypto_cipher_decrypt(struct crypto_cipher *ctx, */ void crypto_cipher_deinit(struct crypto_cipher *ctx); -/** - * fast_crypto_cipher_decrypt - Free cipher context - * @ctx: Context pointer from crypto_cipher_init() - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -void fast_crypto_cipher_deinit(struct crypto_cipher *ctx); - struct crypto_public_key; struct crypto_private_key; @@ -565,31 +451,6 @@ int __must_check crypto_mod_exp(const u8 *base, size_t base_len, const u8 *modulus, size_t modulus_len, u8 *result, size_t *result_len); -/** - * fast_crypto_mod_exp - Modular exponentiation of large integers - * @base: Base integer (big endian byte array) - * @base_len: Length of base integer in bytes - * @power: Power integer (big endian byte array) - * @power_len: Length of power integer in bytes - * @modulus: Modulus integer (big endian byte array) - * @modulus_len: Length of modulus integer in bytes - * @result: Buffer for the result - * @result_len: Result length (max buffer size on input, real len on output) - * Returns: 0 on success, -1 on failure - * - * This function calculates result = base ^ power mod modulus. modules_len is - * used as the maximum size of modulus buffer. It is set to the used size on - * success. - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -int __must_check fast_crypto_mod_exp(const uint8_t *base, size_t base_len, - const uint8_t *power, size_t power_len, - const uint8_t *modulus, size_t modulus_len, - uint8_t *result, size_t *result_len); - /** * rc4_skip - XOR RC4 stream to given data with skip-stream-start * @key: RC4 key diff --git a/components/wpa_supplicant/include/crypto/sha256.h b/components/wpa_supplicant/include/crypto/sha256.h index 8025a29de3..dc597f09b5 100644 --- a/components/wpa_supplicant/include/crypto/sha256.h +++ b/components/wpa_supplicant/include/crypto/sha256.h @@ -24,10 +24,4 @@ void hmac_sha256(const u8 *key, size_t key_len, const u8 *data, void sha256_prf(const u8 *key, size_t key_len, const char *label, const u8 *data, size_t data_len, u8 *buf, size_t buf_len); -void fast_hmac_sha256_vector(const uint8_t *key, size_t key_len, size_t num_elem, - const uint8_t *addr[], const size_t *len, uint8_t *mac); -void fast_hmac_sha256(const uint8_t *key, size_t key_len, const uint8_t *data, - size_t data_len, uint8_t *mac); -void fast_sha256_prf(const uint8_t *key, size_t key_len, const char *label, - const uint8_t *data, size_t data_len, uint8_t *buf, size_t buf_len); #endif /* SHA256_H */ diff --git a/components/wpa_supplicant/port/include/supplicant_opt.h b/components/wpa_supplicant/port/include/supplicant_opt.h index 4267a71c91..446dda0b07 100644 --- a/components/wpa_supplicant/port/include/supplicant_opt.h +++ b/components/wpa_supplicant/port/include/supplicant_opt.h @@ -29,4 +29,8 @@ #define EAP_PEAP 1 #endif +#if CONFIG_WPA_MBEDTLS_CRYPTO +#define USE_MBEDTLS_CRYPTO 1 +#endif + #endif /* _SUPPLICANT_OPT_H */ diff --git a/components/wpa_supplicant/src/ap/wpa_auth.c b/components/wpa_supplicant/src/ap/wpa_auth.c index 5ee342e74b..58625bb553 100644 --- a/components/wpa_supplicant/src/ap/wpa_auth.c +++ b/components/wpa_supplicant/src/ap/wpa_auth.c @@ -932,7 +932,7 @@ static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr, ret = -1; #ifdef CONFIG_IEEE80211W - fast_sha256_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len); + sha256_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len); #else /* CONFIG_IEEE80211W */ if (sha1_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len) < 0) ret = -1; @@ -1064,7 +1064,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, buf, key_data_len); if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || version == WPA_KEY_INFO_TYPE_AES_128_CMAC) { - if (fast_aes_wrap(sm->PTK.kek, (key_data_len - 8) / 8, buf, + if (aes_wrap(sm->PTK.kek, (key_data_len - 8) / 8, buf, (u8 *) (key + 1))) { os_free(hdr); os_free(buf); diff --git a/components/wpa_supplicant/src/common/wpa_common.c b/components/wpa_supplicant/src/common/wpa_common.c index 2685cc38aa..c04307052d 100644 --- a/components/wpa_supplicant/src/common/wpa_common.c +++ b/components/wpa_supplicant/src/common/wpa_common.c @@ -507,7 +507,7 @@ void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, #ifdef CONFIG_IEEE80211W if (use_sha256) { - fast_sha256_prf(pmk, pmk_len, label, data, sizeof(data), + sha256_prf(pmk, pmk_len, label, data, sizeof(data), ptk, ptk_len); } else @@ -549,7 +549,7 @@ void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, #ifdef CONFIG_IEEE80211W if (use_sha256) { - fast_hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash); + hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash); } else #endif /* CONFIG_IEEE80211W */ diff --git a/components/wpa_supplicant/src/crypto/aes-cbc.c b/components/wpa_supplicant/src/crypto/aes-cbc.c index b592279098..24c5670090 100644 --- a/components/wpa_supplicant/src/crypto/aes-cbc.c +++ b/components/wpa_supplicant/src/crypto/aes-cbc.c @@ -12,6 +12,21 @@ * * See README and COPYING for more details. */ +/* + * 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 + * + * Hardware crypto support Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD + * + * 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 "utils/includes.h" @@ -19,6 +34,9 @@ #include "crypto/aes.h" #include "crypto/aes_wrap.h" +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/aes.h" + /** * aes_128_cbc_encrypt - AES-128 CBC encryption * @key: Encryption key @@ -27,7 +45,70 @@ * @data_len: Length of data in bytes (must be divisible by 16) * Returns: 0 on success, -1 on failure */ -int +int +aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) +{ + int ret = 0; + mbedtls_aes_context ctx; + u8 cbc[AES_BLOCK_SIZE]; + + mbedtls_aes_init(&ctx); + + ret = mbedtls_aes_setkey_enc(&ctx, key, 128); + if(ret < 0) { + mbedtls_aes_free(&ctx); + return ret; + } + + os_memcpy(cbc, iv, AES_BLOCK_SIZE); + ret = mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, data_len, cbc, data, data); + mbedtls_aes_free(&ctx); + + return ret; +} + + +/** + * aes_128_cbc_decrypt - AES-128 CBC decryption + * @key: Decryption key + * @iv: Decryption IV for CBC mode (16 bytes) + * @data: Data to decrypt in-place + * @data_len: Length of data in bytes (must be divisible by 16) + * Returns: 0 on success, -1 on failure + */ +int +aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) +{ + int ret = 0; + mbedtls_aes_context ctx; + u8 cbc[AES_BLOCK_SIZE]; + + mbedtls_aes_init(&ctx); + + ret = mbedtls_aes_setkey_dec(&ctx, key, 128); + if(ret < 0) { + mbedtls_aes_free(&ctx); + return ret; + } + + os_memcpy(cbc, iv, AES_BLOCK_SIZE); + ret = mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, data_len, cbc, data, data); + mbedtls_aes_free(&ctx); + + return ret; + +} +#else /* USE_MBEDTLS_CRYPTO */ + +/** + * aes_128_cbc_encrypt - AES-128 CBC encryption + * @key: Encryption key + * @iv: Encryption IV for CBC mode (16 bytes) + * @data: Data to encrypt in-place + * @data_len: Length of data in bytes (must be divisible by 16) + * Returns: 0 on success, -1 on failure + */ +int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) { void *ctx; @@ -61,7 +142,7 @@ aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) * @data_len: Length of data in bytes (must be divisible by 16) * Returns: 0 on success, -1 on failure */ -int +int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) { void *ctx; @@ -86,3 +167,4 @@ aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) aes_decrypt_deinit(ctx); return 0; } +#endif /* USE_MBEDTLS_CRYPTO */ diff --git a/components/wpa_supplicant/src/crypto/aes-unwrap.c b/components/wpa_supplicant/src/crypto/aes-unwrap.c index 2e5a0a1c5f..9f513b0ac5 100644 --- a/components/wpa_supplicant/src/crypto/aes-unwrap.c +++ b/components/wpa_supplicant/src/crypto/aes-unwrap.c @@ -12,12 +12,31 @@ * * See README and COPYING for more details. */ +/* + * 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 + * + * Hardware crypto support Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD + * + * 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 "utils/includes.h" #include "utils/common.h" +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/aes.h" +#else /* USE_MBEDTLS_CRYPTO */ #include "crypto/aes.h" #include "crypto/aes_wrap.h" +#endif /* USE_MBEDTLS_CRYPTO */ /** * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) @@ -33,16 +52,30 @@ aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain) { u8 a[8], *r, b[16]; int i, j; +#ifdef USE_MBEDTLS_CRYPTO + int32_t ret = 0; + mbedtls_aes_context ctx; +#else /* USE_MBEDTLS_CRYPTO */ void *ctx; +#endif /* USE_MBEDTLS_CRYPTO */ /* 1) Initialize variables. */ os_memcpy(a, cipher, 8); r = plain; os_memcpy(r, cipher + 8, 8 * n); +#ifdef USE_MBEDTLS_CRYPTO + mbedtls_aes_init(&ctx); + ret = mbedtls_aes_setkey_dec(&ctx, kek, 128); + if (ret < 0) { + mbedtls_aes_free(&ctx); + return ret; + } +#else /* USE_MBEDTLS_CRYPTO */ ctx = aes_decrypt_init(kek, 16); if (ctx == NULL) return -1; +#endif /* USE_MBEDTLS_CRYPTO */ /* 2) Compute intermediate values. * For j = 5 to 0 @@ -58,13 +91,21 @@ aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain) b[7] ^= n * j + i; os_memcpy(b + 8, r, 8); +#ifdef USE_MBEDTLS_CRYPTO + ret = mbedtls_internal_aes_decrypt(&ctx, b, b); +#else /* USE_MBEDTLS_CRYPTO */ aes_decrypt(ctx, b, b); +#endif /* USE_MBEDTLS_CRYPTO */ os_memcpy(a, b, 8); os_memcpy(r, b + 8, 8); r -= 8; } } +#ifdef USE_MBEDTLS_CRYPTO + mbedtls_aes_free(&ctx); +#else /* USE_MBEDTLS_CRYPTO */ aes_decrypt_deinit(ctx); +#endif /* USE_MBEDTLS_CRYPTO */ /* 3) Output results. * diff --git a/components/wpa_supplicant/src/crypto/aes-wrap.c b/components/wpa_supplicant/src/crypto/aes-wrap.c index 40eb98c546..9d180f5222 100644 --- a/components/wpa_supplicant/src/crypto/aes-wrap.c +++ b/components/wpa_supplicant/src/crypto/aes-wrap.c @@ -6,12 +6,30 @@ * This software may be distributed under the terms of the BSD license. * See README for more details. */ +/* + * 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 + * + * Hardware crypto support Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD + * + * 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 "utils/includes.h" #include "utils/common.h" #include "crypto/aes.h" #include "crypto/aes_wrap.h" +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/aes.h" +#endif /* USE_MBEDTLS_CRYPTO */ /** * aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) @@ -26,7 +44,12 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher) { u8 *a, *r, b[16]; int i, j; +#ifdef USE_MBEDTLS_CRYPTO + int32_t ret = 0; + mbedtls_aes_context ctx; +#else /* USE_MBEDTLS_CRYPTO */ void *ctx; +#endif /* USE_MBEDTLS_CRYPTO */ a = cipher; r = cipher + 8; @@ -35,9 +58,18 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher) os_memset(a, 0xa6, 8); os_memcpy(r, plain, 8 * n); +#ifdef USE_MBEDTLS_CRYPTO + mbedtls_aes_init(&ctx); + ret = mbedtls_aes_setkey_enc(&ctx, kek, 128); + if (ret < 0) { + mbedtls_aes_free(&ctx); + return ret; + } +#else /* USE_MBEDTLS_CRYPTO */ ctx = aes_encrypt_init(kek, 16); if (ctx == NULL) return -1; +#endif /* USE_MBEDTLS_CRYPTO */ /* 2) Calculate intermediate values. * For j = 0 to 5 @@ -51,14 +83,24 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher) for (i = 1; i <= n; i++) { os_memcpy(b, a, 8); os_memcpy(b + 8, r, 8); +#ifdef USE_MBEDTLS_CRYPTO + ret = mbedtls_internal_aes_encrypt(&ctx, b, b); + if (ret != 0) + break; +#else /* USE_MBEDTLS_CRYPTO */ aes_encrypt(ctx, b, b); +#endif /* USE_MBEDTLS_CRYPTO */ os_memcpy(a, b, 8); a[7] ^= n * j + i; os_memcpy(r, b + 8, 8); r += 8; } } +#ifdef USE_MBEDTLS_CRYPTO + mbedtls_aes_free(&ctx); +#else /* USE_MBEDTLS_CRYPTO */ aes_encrypt_deinit(ctx); +#endif /* USE_MBEDTLS_CRYPTO */ /* 3) Output the results. * diff --git a/components/wpa_supplicant/src/crypto/crypto_internal-cipher.c b/components/wpa_supplicant/src/crypto/crypto_internal-cipher.c index f197aa35e2..3fe2412e10 100644 --- a/components/wpa_supplicant/src/crypto/crypto_internal-cipher.c +++ b/components/wpa_supplicant/src/crypto/crypto_internal-cipher.c @@ -5,13 +5,32 @@ * This software may be distributed under the terms of the BSD license. * See README for more details. */ +/* + * 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 + * + * Hardware crypto support Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD + * + * 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 "utils/common.h" +#include "utils/includes.h" #include "crypto/crypto.h" #include "crypto/aes.h" #if defined(CONFIG_DES) || defined(CONFIG_DES3) #include "crypto/des_i.h" #endif +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/aes.h" +#endif /* USE_MBEDTLS_CRYPTO */ struct crypto_cipher { enum crypto_cipher_alg alg; @@ -23,8 +42,13 @@ struct crypto_cipher { } rc4; struct { u8 cbc[32]; +#ifdef USE_MBEDTLS_CRYPTO + mbedtls_aes_context ctx_enc; + mbedtls_aes_context ctx_dec; +#else /* USE_MBEDTLS_CRYPTO */ void *ctx_enc; void *ctx_dec; +#endif /* USE_MBEDTLS_CRYPTO */ } aes; #ifdef CONFIG_DES3 struct { @@ -65,6 +89,12 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, os_memcpy(ctx->u.rc4.key, key, key_len); break; case CRYPTO_CIPHER_ALG_AES: +#ifdef USE_MBEDTLS_CRYPTO + mbedtls_aes_init(&(ctx->u.aes.ctx_enc)); + mbedtls_aes_setkey_enc(&(ctx->u.aes.ctx_enc), key, key_len * 8); + mbedtls_aes_init(&(ctx->u.aes.ctx_dec)); + mbedtls_aes_setkey_dec(&(ctx->u.aes.ctx_dec), key, key_len * 8); +#else /* USE_MBEDTLS_CRYPTO */ ctx->u.aes.ctx_enc = aes_encrypt_init(key, key_len); if (ctx->u.aes.ctx_enc == NULL) { os_free(ctx); @@ -76,6 +106,7 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, os_free(ctx); return NULL; } +#endif /* USE_MBEDTLS_CRYPTO */ os_memcpy(ctx->u.aes.cbc, iv, AES_BLOCK_SIZE); break; #ifdef CONFIG_DES3 @@ -127,8 +158,14 @@ int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, for (i = 0; i < blocks; i++) { for (j = 0; j < AES_BLOCK_SIZE; j++) ctx->u.aes.cbc[j] ^= plain[j]; +#ifdef USE_MBEDTLS_CRYPTO + if (mbedtls_internal_aes_encrypt(&(ctx->u.aes.ctx_enc), + ctx->u.aes.cbc, ctx->u.aes.cbc) != 0) + return -1; +#else /* USE_MBEDTLS_CRYPTO */ aes_encrypt(ctx->u.aes.ctx_enc, ctx->u.aes.cbc, ctx->u.aes.cbc); +#endif /* USE_MBEDTLS_CRYPTO */ os_memcpy(crypt, ctx->u.aes.cbc, AES_BLOCK_SIZE); plain += AES_BLOCK_SIZE; crypt += AES_BLOCK_SIZE; @@ -194,7 +231,13 @@ int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, blocks = len / AES_BLOCK_SIZE; for (i = 0; i < blocks; i++) { os_memcpy(tmp, crypt, AES_BLOCK_SIZE); +#ifdef USE_MBEDTLS_CRYPTO + if (mbedtls_internal_aes_decrypt(&(ctx->u.aes.ctx_dec), + crypt, plain) != 0) + return -1; +#else /* USE_MBEDTLS_CRYPTO */ aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain); +#endif /* USE_MBEDTLS_CRYPTO */ for (j = 0; j < AES_BLOCK_SIZE; j++) plain[j] ^= ctx->u.aes.cbc[j]; os_memcpy(ctx->u.aes.cbc, tmp, AES_BLOCK_SIZE); @@ -246,8 +289,13 @@ void crypto_cipher_deinit(struct crypto_cipher *ctx) { switch (ctx->alg) { case CRYPTO_CIPHER_ALG_AES: +#ifdef USE_MBEDTLS_CRYPTO + mbedtls_aes_free(&(ctx->u.aes.ctx_enc)); + mbedtls_aes_free(&(ctx->u.aes.ctx_dec)); +#else /* USE_MBEDTLS_CRYPTO */ aes_encrypt_deinit(ctx->u.aes.ctx_enc); aes_decrypt_deinit(ctx->u.aes.ctx_dec); +#endif /* USE_MBEDTLS_CRYPTO */ break; #ifdef CONFIG_DES3 case CRYPTO_CIPHER_ALG_3DES: diff --git a/components/wpa_supplicant/src/crypto/crypto_internal-modexp.c b/components/wpa_supplicant/src/crypto/crypto_internal-modexp.c index 2bf67df34c..f37139ba19 100644 --- a/components/wpa_supplicant/src/crypto/crypto_internal-modexp.c +++ b/components/wpa_supplicant/src/crypto/crypto_internal-modexp.c @@ -11,14 +11,72 @@ * * See README and COPYING for more details. */ +/* + * Hardware crypto support Copyright 2017-2019 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 "utils/includes.h" #include "utils/common.h" +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/bignum.h" +#else /* USE_MBEDTLS_CRYPTO */ #include "bignum.h" +#endif /* USE_MBEDTLS_CRYPTO */ #include "crypto/crypto.h" +#ifdef USE_MBEDTLS_CRYPTO +int +crypto_mod_exp(const uint8_t *base, size_t base_len, + const uint8_t *power, size_t power_len, + const uint8_t *modulus, size_t modulus_len, + uint8_t *result, size_t *result_len) +{ + mbedtls_mpi bn_base, bn_exp, bn_modulus, bn_result, bn_rinv; + int ret = 0; + mbedtls_mpi_init(&bn_base); + mbedtls_mpi_init(&bn_exp); + mbedtls_mpi_init(&bn_modulus); + mbedtls_mpi_init(&bn_result); + mbedtls_mpi_init(&bn_rinv); + mbedtls_mpi_read_binary(&bn_base, base, base_len); + mbedtls_mpi_read_binary(&bn_exp, power, power_len); + mbedtls_mpi_read_binary(&bn_modulus, modulus, modulus_len); + + ret = mbedtls_mpi_exp_mod(&bn_result, &bn_base, &bn_exp, &bn_modulus, &bn_rinv); + if (ret < 0) { + mbedtls_mpi_free(&bn_base); + mbedtls_mpi_free(&bn_exp); + mbedtls_mpi_free(&bn_modulus); + mbedtls_mpi_free(&bn_result); + mbedtls_mpi_free(&bn_rinv); + return ret; + } + + ret = mbedtls_mpi_write_binary(&bn_result, result, *result_len); + + mbedtls_mpi_free(&bn_base); + mbedtls_mpi_free(&bn_exp); + mbedtls_mpi_free(&bn_modulus); + mbedtls_mpi_free(&bn_result); + mbedtls_mpi_free(&bn_rinv); + + return ret; +} +#else /* USE_MBEDTLS_CRYPTO */ int crypto_mod_exp(const u8 *base, size_t base_len, const u8 *power, size_t power_len, @@ -54,3 +112,4 @@ error: bignum_deinit(bn_result); return ret; } +#endif /* USE_MBEDTLS_CRYPTO */ diff --git a/components/wpa_supplicant/src/crypto/crypto_internal.c b/components/wpa_supplicant/src/crypto/crypto_internal.c index 5a1d5951ce..4622cfcb89 100644 --- a/components/wpa_supplicant/src/crypto/crypto_internal.c +++ b/components/wpa_supplicant/src/crypto/crypto_internal.c @@ -5,12 +5,30 @@ * This software may be distributed under the terms of the BSD license. * See README for more details. */ +/* + * 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 + * + * Hardware crypto support Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD + * + * 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 "utils/includes.h" #include "utils/common.h" #include "crypto/crypto.h" #include "crypto/sha1_i.h" #include "crypto/md5_i.h" +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/sha256.h" +#endif struct crypto_hash { enum crypto_hash_alg alg; @@ -18,7 +36,11 @@ struct crypto_hash { struct MD5Context md5; struct SHA1Context sha1; #ifdef CONFIG_SHA256 +#ifdef USE_MBEDTLS_CRYPTO + mbedtls_sha256_context sha256; +#else /* USE_MBEDTLS_CRYPTO */ struct sha256_state sha256; +#endif /* USE_MBEDTLS_CRYPTO */ #endif /* CONFIG_SHA256 */ } u; u8 key[64]; @@ -49,7 +71,12 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, break; #ifdef CONFIG_SHA256 case CRYPTO_HASH_ALG_SHA256: +#ifdef USE_MBEDTLS_CRYPTO + mbedtls_sha256_init(&ctx->u.sha256); + mbedtls_sha256_starts(&ctx->u.sha256, 0); +#else /* USE_MBEDTLS_CRYPTO */ sha256_init(&ctx->u.sha256); +#endif /* USE_MBEDTLS_CRYPTO */ break; #endif /* CONFIG_SHA256 */ case CRYPTO_HASH_ALG_HMAC_MD5: @@ -93,9 +120,17 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, #ifdef CONFIG_SHA256 case CRYPTO_HASH_ALG_HMAC_SHA256: if (key_len > sizeof(k_pad)) { +#ifdef USE_MBEDTLS_CRYPTO + mbedtls_sha256_init(&ctx->u.sha256); + mbedtls_sha256_starts(&ctx->u.sha256, 0); + mbedtls_sha256_update(&ctx->u.sha256, key, key_len); + mbedtls_sha256_finish(&ctx->u.sha256, tk); + mbedtls_sha256_free(&ctx->u.sha256); +#else /* USE_MBEDTLS_CRYPTO */ sha256_init(&ctx->u.sha256); sha256_process(&ctx->u.sha256, key, key_len); sha256_done(&ctx->u.sha256, tk); +#endif /* USE_MBEDTLS_CRYPTO */ key = tk; key_len = 32; } @@ -107,8 +142,14 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); for (i = 0; i < sizeof(k_pad); i++) k_pad[i] ^= 0x36; +#ifdef USE_MBEDTLS_CRYPTO + mbedtls_sha256_init(&ctx->u.sha256); + mbedtls_sha256_starts(&ctx->u.sha256, 0); + mbedtls_sha256_update(&ctx->u.sha256, k_pad, sizeof(k_pad)); +#else /* USE_MBEDTLS_CRYPTO */ sha256_init(&ctx->u.sha256); sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad)); +#endif /* USE_MBEDTLS_CRYPTO */ break; #endif /* CONFIG_SHA256 */ default: @@ -137,7 +178,11 @@ void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) #ifdef CONFIG_SHA256 case CRYPTO_HASH_ALG_SHA256: case CRYPTO_HASH_ALG_HMAC_SHA256: +#ifdef USE_MBEDTLS_CRYPTO + mbedtls_sha256_update(&ctx->u.sha256, data, len); +#else /* USE_MBEDTLS_CRYPTO */ sha256_process(&ctx->u.sha256, data, len); +#endif /* USE_MBEDTLS_CRYPTO */ break; #endif /* CONFIG_SHA256 */ default: @@ -186,7 +231,12 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) return -1; } *len = 32; +#ifdef USE_MBEDTLS_CRYPTO + mbedtls_sha256_finish(&ctx->u.sha256, mac); + mbedtls_sha256_free(&ctx->u.sha256); +#else /* USE_MBEDTLS_CRYPTO */ sha256_done(&ctx->u.sha256, mac); +#endif /* USE_MBEDTLS_CRYPTO */ break; #endif /* CONFIG_SHA256 */ case CRYPTO_HASH_ALG_HMAC_MD5: @@ -238,17 +288,31 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) } *len = 32; +#ifdef USE_MBEDTLS_CRYPTO + mbedtls_sha256_finish(&ctx->u.sha256, mac); + mbedtls_sha256_free(&ctx->u.sha256); +#else /* USE_MBEDTLS_CRYPTO */ sha256_done(&ctx->u.sha256, mac); +#endif /* USE_MBEDTLS_CRYPTO */ os_memcpy(k_pad, ctx->key, ctx->key_len); os_memset(k_pad + ctx->key_len, 0, sizeof(k_pad) - ctx->key_len); for (i = 0; i < sizeof(k_pad); i++) k_pad[i] ^= 0x5c; +#ifdef USE_MBEDTLS_CRYPTO + mbedtls_sha256_init(&ctx->u.sha256); + mbedtls_sha256_starts(&ctx->u.sha256, 0); + mbedtls_sha256_update(&ctx->u.sha256, k_pad, sizeof(k_pad)); + mbedtls_sha256_update(&ctx->u.sha256, mac, 32); + mbedtls_sha256_finish(&ctx->u.sha256, mac); + mbedtls_sha256_free(&ctx->u.sha256); +#else /* USE_MBEDTLS_CRYPTO */ sha256_init(&ctx->u.sha256); sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad)); sha256_process(&ctx->u.sha256, mac, 32); sha256_done(&ctx->u.sha256, mac); +#endif /* USE_MBEDTLS_CRYPTO */ break; #endif /* CONFIG_SHA256 */ default: diff --git a/components/wpa_supplicant/src/crypto/dh_groups.c b/components/wpa_supplicant/src/crypto/dh_groups.c index 9f85846034..e3c7519ece 100644 --- a/components/wpa_supplicant/src/crypto/dh_groups.c +++ b/components/wpa_supplicant/src/crypto/dh_groups.c @@ -586,7 +586,7 @@ dh_init(const struct dh_group *dh, struct wpabuf **priv) if (pv == NULL) return NULL; - if (fast_crypto_mod_exp(dh->generator, dh->generator_len, + if (crypto_mod_exp(dh->generator, dh->generator_len, wpabuf_head(*priv), wpabuf_len(*priv), dh->prime, dh->prime_len, wpabuf_mhead(pv), &pv_len)) { @@ -624,7 +624,7 @@ dh_derive_shared(const struct wpabuf *peer_public, if (shared == NULL) return NULL; - if (fast_crypto_mod_exp(wpabuf_head(peer_public), wpabuf_len(peer_public), + if (crypto_mod_exp(wpabuf_head(peer_public), wpabuf_len(peer_public), wpabuf_head(own_private), wpabuf_len(own_private), dh->prime, dh->prime_len, wpabuf_mhead(shared), &shared_len)) { diff --git a/components/wpa_supplicant/src/crypto/sha256-internal.c b/components/wpa_supplicant/src/crypto/sha256-internal.c index 376dbd98f2..df0706b5c1 100644 --- a/components/wpa_supplicant/src/crypto/sha256-internal.c +++ b/components/wpa_supplicant/src/crypto/sha256-internal.c @@ -11,12 +11,73 @@ * * See README and COPYING for more details. */ +/* + * Hardware crypto support Copyright 2017-2019 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 "utils/includes.h" #include "utils/common.h" +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/sha256.h" +#else /* USE_MBEDTLS_CRYPTO */ #include "crypto/sha256.h" #include "crypto/crypto.h" +#endif /* USE_MBEDTLS_CRYPTO */ + +#ifdef USE_MBEDTLS_CRYPTO +/** + * sha256_vector - SHA256 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 of failure + */ +int +sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac) +{ + int ret = 0; + mbedtls_sha256_context ctx; + + mbedtls_sha256_init(&ctx); + + if (mbedtls_sha256_starts_ret(&ctx, 0) != 0) { + ret = -1; + goto out; + } + + for(size_t index = 0; index < num_elem; index++) { + if (mbedtls_sha256_update_ret(&ctx, addr[index], len[index]) != 0) { + ret = -1; + goto out; + } + } + + if (mbedtls_sha256_finish_ret(&ctx, mac) != 0) { + ret = -1; + goto out; + } + +out: + mbedtls_sha256_free(&ctx); + + return ret; +} +#else /* USE_MBEDTLS_CRYPTO */ #define SHA256_BLOCK_SIZE 64 @@ -245,5 +306,6 @@ sha256_done(struct sha256_state *md, unsigned char *out) return 0; } +#endif /* USE_MBEDTLS_CRYPTO */ /* ===== end - public domain SHA256 implementation ===== */ diff --git a/components/wpa_supplicant/src/crypto/sha256.c b/components/wpa_supplicant/src/crypto/sha256.c index 49f248c334..6380897e42 100644 --- a/components/wpa_supplicant/src/crypto/sha256.c +++ b/components/wpa_supplicant/src/crypto/sha256.c @@ -11,6 +11,21 @@ * * See README and COPYING for more details. */ +/* + * 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 + * + * Hardware crypto support Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD + * + * 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 "utils/includes.h" diff --git a/components/wpa_supplicant/src/fast_crypto/fast_aes-cbc.c b/components/wpa_supplicant/src/fast_crypto/fast_aes-cbc.c deleted file mode 100644 index feccba9e42..0000000000 --- a/components/wpa_supplicant/src/fast_crypto/fast_aes-cbc.c +++ /dev/null @@ -1,78 +0,0 @@ -// Hardware crypto support Copyright 2017 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); - - -#include "utils/includes.h" -#include "utils/common.h" -#include "crypto/aes.h" -#include "crypto/aes_wrap.h" -#include "mbedtls/aes.h" - -/** - * fast_aes_128_cbc_encrypt - AES-128 CBC encryption - * @key: Encryption key - * @iv: Encryption IV for CBC mode (16 bytes) - * @data: Data to encrypt in-place - * @data_len: Length of data in bytes (must be divisible by 16) - * Returns: 0 on success, -1 on failure - */ -int -fast_aes_128_cbc_encrypt(const uint8_t *key, const uint8_t *iv, uint8_t *data, size_t data_len) -{ - int ret = 0; - mbedtls_aes_context ctx; - uint8_t cbc[AES_BLOCK_SIZE]; - - mbedtls_aes_init(&ctx); - - ret = mbedtls_aes_setkey_enc(&ctx, key, 128); - - if(ret < 0) { - mbedtls_aes_free(&ctx); - return ret; - } - - os_memcpy(cbc, iv, AES_BLOCK_SIZE); - - ret = mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, data_len, cbc, data, data); - - mbedtls_aes_free(&ctx); - - return ret; -} - - -/** - * fast_aes_128_cbc_decrypt - AES-128 CBC decryption - * @key: Decryption key - * @iv: Decryption IV for CBC mode (16 bytes) - * @data: Data to decrypt in-place - * @data_len: Length of data in bytes (must be divisible by 16) - * Returns: 0 on success, -1 on failure - */ -int -fast_aes_128_cbc_decrypt(const uint8_t *key, const uint8_t *iv, uint8_t *data, size_t data_len) -{ - int ret = 0; - mbedtls_aes_context ctx; - uint8_t cbc[AES_BLOCK_SIZE]; - - mbedtls_aes_init(&ctx); - - ret = mbedtls_aes_setkey_dec(&ctx, key, 128); - - if(ret < 0) { - mbedtls_aes_free(&ctx); - return ret; - } - - os_memcpy(cbc, iv, AES_BLOCK_SIZE); - - ret = mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, data_len, cbc, data, data); - - mbedtls_aes_free(&ctx); - - return ret; - -} diff --git a/components/wpa_supplicant/src/fast_crypto/fast_aes-unwrap.c b/components/wpa_supplicant/src/fast_crypto/fast_aes-unwrap.c deleted file mode 100644 index b4b9403147..0000000000 --- a/components/wpa_supplicant/src/fast_crypto/fast_aes-unwrap.c +++ /dev/null @@ -1,84 +0,0 @@ -// 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 -// -// Hardware crypto support Copyright 2017 Espressif Systems (Shanghai) PTE LTD -// -// 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 "utils/includes.h" -#include "utils/common.h" -#include "mbedtls/aes.h" - -/** - * fast_aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) - * @kek: Key encryption key (KEK) - * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16 - * bytes - * @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bits - * @plain: Plaintext key, n * 64 bits - * Returns: 0 on success, -1 on failure (e.g., integrity verification failed) - */ -int -fast_aes_unwrap(const uint8_t *kek, int n, const uint8_t *cipher, uint8_t *plain) -{ - uint8_t a[8], *r, b[16]; - int32_t i, j; - int32_t ret = 0; - mbedtls_aes_context ctx; - - /* 1) Initialize variables. */ - os_memcpy(a, cipher, 8); - r = plain; - os_memcpy(r, cipher + 8, 8 * n); - - mbedtls_aes_init(&ctx); - ret = mbedtls_aes_setkey_dec(&ctx, kek, 128); - if (ret < 0) { - mbedtls_aes_free(&ctx); - return ret; - } - - /* 2) Compute intermediate values. - * For j = 5 to 0 - * For i = n to 1 - * B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i - * A = MSB(64, B) - * R[i] = LSB(64, B) - */ - for (j = 5; j >= 0; j--) { - r = plain + (n - 1) * 8; - for (i = n; i >= 1; i--) { - os_memcpy(b, a, 8); - b[7] ^= n * j + i; - os_memcpy(b + 8, r, 8); - ret = mbedtls_internal_aes_decrypt(&ctx, b, b); - if (ret != 0) { - break; - } - os_memcpy(a, b, 8); - os_memcpy(r, b + 8, 8); - r -= 8; - } - } - mbedtls_aes_free(&ctx); - - /* 3) Output results. - * - * These are already in @plain due to the location of temporary - * variables. Just verify that the IV matches with the expected value. - */ - for (i = 0; i < 8; i++) { - if (a[i] != 0xa6) { - return -1; - } - } - - return ret; -} diff --git a/components/wpa_supplicant/src/fast_crypto/fast_aes-wrap.c b/components/wpa_supplicant/src/fast_crypto/fast_aes-wrap.c deleted file mode 100644 index ea15d8bc28..0000000000 --- a/components/wpa_supplicant/src/fast_crypto/fast_aes-wrap.c +++ /dev/null @@ -1,83 +0,0 @@ -// 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 -// -// Hardware crypto support Copyright 2017 Espressif Systems (Shanghai) PTE LTD -// -// 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 "utils/includes.h" - -#include "utils/common.h" -#include "crypto/aes.h" -#include "crypto/aes_wrap.h" -#include "mbedtls/aes.h" - -/** - * fast_aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) - * @kek: 16-octet Key encryption key (KEK) - * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16 - * bytes - * @plain: Plaintext key to be wrapped, n * 64 bits - * @cipher: Wrapped key, (n + 1) * 64 bits - * Returns: 0 on success, -1 on failure - */ -int fast_aes_wrap(const uint8_t *kek, int n, const uint8_t *plain, uint8_t *cipher) -{ - uint8_t *a, *r, b[16]; - int32_t i, j; - int32_t ret = 0; - mbedtls_aes_context ctx; - - a = cipher; - r = cipher + 8; - - /* 1) Initialize variables. */ - os_memset(a, 0xa6, 8); - os_memcpy(r, plain, 8 * n); - - mbedtls_aes_init(&ctx); - ret = mbedtls_aes_setkey_enc(&ctx, kek, 128); - if (ret < 0) { - mbedtls_aes_free(&ctx); - return ret; - } - - /* 2) Calculate intermediate values. - * For j = 0 to 5 - * For i=1 to n - * B = AES(K, A | R[i]) - * A = MSB(64, B) ^ t where t = (n*j)+i - * R[i] = LSB(64, B) - */ - for (j = 0; j <= 5; j++) { - r = cipher + 8; - for (i = 1; i <= n; i++) { - os_memcpy(b, a, 8); - os_memcpy(b + 8, r, 8); - ret = mbedtls_internal_aes_encrypt(&ctx, b, b); - if (ret != 0) { - break; - } - os_memcpy(a, b, 8); - a[7] ^= n * j + i; - os_memcpy(r, b + 8, 8); - r += 8; - } - } - mbedtls_aes_free(&ctx); - - /* 3) Output the results. - * - * These are already in @cipher due to the location of temporary - * variables. - */ - - return ret; -} diff --git a/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal-cipher.c b/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal-cipher.c deleted file mode 100644 index 667a886d13..0000000000 --- a/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal-cipher.c +++ /dev/null @@ -1,287 +0,0 @@ -// 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 -// -// Hardware crypto support Copyright 2017 Espressif Systems (Shanghai) PTE LTD -// -// 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 "utils/includes.h" - -//#include "utils/common.h" -#include "utils/common.h" -#include "crypto/crypto.h" -#include "crypto/aes.h" -#if defined(CONFIG_DES) || defined(CONFIG_DES3) -#include "crypto/des_i.h" -#endif -#include "mbedtls/aes.h" - -struct fast_crypto_cipher { - enum crypto_cipher_alg alg; - union { - struct { - size_t used_bytes; - uint8_t key[16]; - size_t keylen; - } rc4; - struct { - uint8_t cbc[32]; - mbedtls_aes_context ctx_enc; - mbedtls_aes_context ctx_dec; - } aes; -#ifdef CONFIG_DES3 - struct { - struct des3_key_s key; - uint8_t cbc[8]; - } des3; -#endif -#ifdef CONFIG_DES - struct { - uint32_t ek[32]; - uint32_t dk[32]; - uint32_t cbc[8]; - } des; -#endif - } u; -}; - - -struct crypto_cipher * fast_crypto_cipher_init(enum crypto_cipher_alg alg, - const uint8_t *iv, const uint8_t *key, - size_t key_len) -{ - struct fast_crypto_cipher *ctx; - - ctx = (struct fast_crypto_cipher *)os_zalloc(sizeof(*ctx)); - if (ctx == NULL) { - return NULL; - } - - ctx->alg = alg; - - switch (alg) { - case CRYPTO_CIPHER_ALG_RC4: - if (key_len > sizeof(ctx->u.rc4.key)) { - os_free(ctx); - return NULL; - } - ctx->u.rc4.keylen = key_len; - os_memcpy(ctx->u.rc4.key, key, key_len); - break; - case CRYPTO_CIPHER_ALG_AES: - mbedtls_aes_init(&(ctx->u.aes.ctx_enc)); - mbedtls_aes_setkey_enc(&(ctx->u.aes.ctx_enc), key, key_len * 8); - mbedtls_aes_init(&(ctx->u.aes.ctx_dec)); - mbedtls_aes_setkey_dec(&(ctx->u.aes.ctx_dec), key, key_len * 8); - os_memcpy(ctx->u.aes.cbc, iv, AES_BLOCK_SIZE); - break; -#ifdef CONFIG_DES3 - case CRYPTO_CIPHER_ALG_3DES: - if (key_len != 24) { - os_free(ctx); - return NULL; - } - des3_key_setup(key, &ctx->u.des3.key); - os_memcpy(ctx->u.des3.cbc, iv, 8); - break; -#endif -#ifdef CONFIG_DES - case CRYPTO_CIPHER_ALG_DES: - if (key_len != 8) { - os_free(ctx); - return NULL; - } - des_key_setup(key, ctx->u.des.ek, ctx->u.des.dk); - os_memcpy(ctx->u.des.cbc, iv, 8); - break; -#endif - default: - os_free(ctx); - return NULL; - } - - return (struct crypto_cipher *)ctx; -} - - -int fast_crypto_cipher_encrypt(struct crypto_cipher *ctx, const uint8_t *plain, - uint8_t *crypt, size_t len) -{ - size_t i, j, blocks; - struct fast_crypto_cipher *fast_ctx; - - fast_ctx = (struct fast_crypto_cipher *)ctx; - - switch (fast_ctx->alg) { - case CRYPTO_CIPHER_ALG_RC4: - if (plain != crypt) { - os_memcpy(crypt, plain, len); - } - rc4_skip(fast_ctx->u.rc4.key, fast_ctx->u.rc4.keylen, - fast_ctx->u.rc4.used_bytes, crypt, len); - fast_ctx->u.rc4.used_bytes += len; - break; - case CRYPTO_CIPHER_ALG_AES: - if (len % AES_BLOCK_SIZE) { - return -1; - } - blocks = len / AES_BLOCK_SIZE; - for (i = 0; i < blocks; i++) { - for (j = 0; j < AES_BLOCK_SIZE; j++) - fast_ctx->u.aes.cbc[j] ^= plain[j]; - if (mbedtls_internal_aes_encrypt(&(fast_ctx->u.aes.ctx_enc), fast_ctx->u.aes.cbc, fast_ctx->u.aes.cbc) != 0) { - return -1; - } - os_memcpy(crypt, fast_ctx->u.aes.cbc, AES_BLOCK_SIZE); - plain += AES_BLOCK_SIZE; - crypt += AES_BLOCK_SIZE; - } - break; -#ifdef CONFIG_DES3 - case CRYPTO_CIPHER_ALG_3DES: - if (len % 8) { - return -1; - } - blocks = len / 8; - for (i = 0; i < blocks; i++) { - for (j = 0; j < 8; j++) - fast_ctx->u.des3.cbc[j] ^= plain[j]; - des3_encrypt(fast_ctx->u.des3.cbc, &fast_ctx->u.des3.key, - fast_ctx->u.des3.cbc); - os_memcpy(crypt, fast_ctx->u.des3.cbc, 8); - plain += 8; - crypt += 8; - } - break; -#endif -#ifdef CONFIG_DES - case CRYPTO_CIPHER_ALG_DES: - if (len % 8) { - return -1; - } - blocks = len / 8; - for (i = 0; i < blocks; i++) { - for (j = 0; j < 8; j++) - fast_ctx->u.des3.cbc[j] ^= plain[j]; - des_block_encrypt(fast_ctx->u.des.cbc, fast_ctx->u.des.ek, - fast_ctx->u.des.cbc); - os_memcpy(crypt, fast_ctx->u.des.cbc, 8); - plain += 8; - crypt += 8; - } - break; -#endif - default: - return -1; - } - - return 0; -} - - -int fast_crypto_cipher_decrypt(struct crypto_cipher *ctx, const uint8_t *crypt, - uint8_t *plain, size_t len) -{ - size_t i, j, blocks; - uint8_t tmp[32]; - struct fast_crypto_cipher *fast_ctx; - - fast_ctx = (struct fast_crypto_cipher *)ctx; - - switch (fast_ctx->alg) { - case CRYPTO_CIPHER_ALG_RC4: - if (plain != crypt) { - os_memcpy(plain, crypt, len); - } - rc4_skip(fast_ctx->u.rc4.key, fast_ctx->u.rc4.keylen, - fast_ctx->u.rc4.used_bytes, plain, len); - fast_ctx->u.rc4.used_bytes += len; - break; - case CRYPTO_CIPHER_ALG_AES: - if (len % AES_BLOCK_SIZE) { - return -1; - } - blocks = len / AES_BLOCK_SIZE; - for (i = 0; i < blocks; i++) { - os_memcpy(tmp, crypt, AES_BLOCK_SIZE); - if (mbedtls_internal_aes_decrypt(&(fast_ctx->u.aes.ctx_dec), crypt, plain) != 0) { - return -1; - } - for (j = 0; j < AES_BLOCK_SIZE; j++) - plain[j] ^= fast_ctx->u.aes.cbc[j]; - os_memcpy(fast_ctx->u.aes.cbc, tmp, AES_BLOCK_SIZE); - plain += AES_BLOCK_SIZE; - crypt += AES_BLOCK_SIZE; - } - break; -#ifdef CONFIG_DES3 - case CRYPTO_CIPHER_ALG_3DES: - if (len % 8) { - return -1; - } - blocks = len / 8; - for (i = 0; i < blocks; i++) { - os_memcpy(tmp, crypt, 8); - des3_decrypt(crypt, &fast_ctx->u.des3.key, plain); - for (j = 0; j < 8; j++) { - plain[j] ^= fast_ctx->u.des3.cbc[j]; - } - os_memcpy(fast_ctx->u.des3.cbc, tmp, 8); - plain += 8; - crypt += 8; - } - break; -#endif -#ifdef CONFIG_DES - case CRYPTO_CIPHER_ALG_DES: - if (len % 8) { - return -1; - } - blocks = len / 8; - for (i = 0; i < blocks; i++) { - os_memcpy(tmp, crypt, 8); - des_block_decrypt(crypt, fast_ctx->u.des.dk, plain); - for (j = 0; j < 8; j++) { - plain[j] ^= fast_ctx->u.des.cbc[j]; - } - os_memcpy(fast_ctx->u.des.cbc, tmp, 8); - plain += 8; - crypt += 8; - } - break; -#endif - default: - return -1; -} - -return 0; -} - - -void fast_crypto_cipher_deinit(struct crypto_cipher *ctx) -{ - struct fast_crypto_cipher *fast_ctx; - - fast_ctx = (struct fast_crypto_cipher *)ctx; - - switch (fast_ctx->alg) { - case CRYPTO_CIPHER_ALG_AES: - mbedtls_aes_free(&(fast_ctx->u.aes.ctx_enc)); - mbedtls_aes_free(&(fast_ctx->u.aes.ctx_dec)); - break; -#ifdef CONFIG_DES3 - case CRYPTO_CIPHER_ALG_3DES: - break; -#endif - default: - break; - } - os_free(ctx); -} diff --git a/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal-modexp.c b/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal-modexp.c deleted file mode 100644 index 2c869ce780..0000000000 --- a/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal-modexp.c +++ /dev/null @@ -1,59 +0,0 @@ -// Hardware crypto support Copyright 2017 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 "utils/includes.h" - -#include "utils/common.h" -#include "crypto/crypto.h" -#include "mbedtls/bignum.h" - -int -fast_crypto_mod_exp(const uint8_t *base, size_t base_len, - const uint8_t *power, size_t power_len, - const uint8_t *modulus, size_t modulus_len, - uint8_t *result, size_t *result_len) -{ - mbedtls_mpi bn_base, bn_exp, bn_modulus, bn_result, bn_rinv; - int32_t ret = 0; - mbedtls_mpi_init(&bn_base); - mbedtls_mpi_init(&bn_exp); - mbedtls_mpi_init(&bn_modulus); - mbedtls_mpi_init(&bn_result); - mbedtls_mpi_init(&bn_rinv); - - mbedtls_mpi_read_binary(&bn_base, base, base_len); - mbedtls_mpi_read_binary(&bn_exp, power, power_len); - mbedtls_mpi_read_binary(&bn_modulus, modulus, modulus_len); - - ret = mbedtls_mpi_exp_mod(&bn_result, &bn_base, &bn_exp, &bn_modulus, &bn_rinv); - if (ret < 0) { - mbedtls_mpi_free(&bn_base); - mbedtls_mpi_free(&bn_exp); - mbedtls_mpi_free(&bn_modulus); - mbedtls_mpi_free(&bn_result); - mbedtls_mpi_free(&bn_rinv); - return ret; - } - - ret = mbedtls_mpi_write_binary(&bn_result, result, *result_len); - - - mbedtls_mpi_free(&bn_base); - mbedtls_mpi_free(&bn_exp); - mbedtls_mpi_free(&bn_modulus); - mbedtls_mpi_free(&bn_result); - mbedtls_mpi_free(&bn_rinv); - - return ret; -} diff --git a/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal.c b/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal.c deleted file mode 100644 index cb5e988cbc..0000000000 --- a/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal.c +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Crypto wrapper for internal crypto implementation - * Copyright (c) 2006-2011, Jouni Malinen - * - * Hardware crypto support Copyright 2017 Espressif Systems (Shanghai) PTE LTD - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" -#include "utils/common.h" -#include "crypto/crypto.h" -#include "crypto/sha1_i.h" -#include "crypto/md5_i.h" -#include "mbedtls/sha256.h" - - -struct fast_crypto_hash { - enum crypto_hash_alg alg; - union { - struct MD5Context md5; - struct SHA1Context sha1; -#ifdef CONFIG_SHA256 - mbedtls_sha256_context sha256; -#endif /* CONFIG_SHA256 */ - } u; - u8 key[64]; - size_t key_len; -}; - -struct crypto_hash * fast_crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, - size_t key_len) -{ - struct fast_crypto_hash *ctx; - u8 k_pad[64]; - u8 tk[32]; - size_t i; - - ctx = (struct fast_crypto_hash *)os_zalloc(sizeof(*ctx)); - if (ctx == NULL) - return NULL; - - ctx->alg = alg; - - switch (alg) { - case CRYPTO_HASH_ALG_MD5: - MD5Init(&ctx->u.md5); - break; - case CRYPTO_HASH_ALG_SHA1: - SHA1Init(&ctx->u.sha1); - break; -#ifdef CONFIG_SHA256 - case CRYPTO_HASH_ALG_SHA256: - mbedtls_sha256_init(&ctx->u.sha256); - mbedtls_sha256_starts(&ctx->u.sha256, 0); - break; -#endif /* CONFIG_SHA256 */ - case CRYPTO_HASH_ALG_HMAC_MD5: - if (key_len > sizeof(k_pad)) { - MD5Init(&ctx->u.md5); - MD5Update(&ctx->u.md5, key, key_len); - MD5Final(tk, &ctx->u.md5); - key = tk; - key_len = 16; - } - os_memcpy(ctx->key, key, key_len); - ctx->key_len = key_len; - - os_memcpy(k_pad, key, key_len); - if (key_len < sizeof(k_pad)) - os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); - for (i = 0; i < sizeof(k_pad); i++) - k_pad[i] ^= 0x36; - MD5Init(&ctx->u.md5); - MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad)); - break; - case CRYPTO_HASH_ALG_HMAC_SHA1: - if (key_len > sizeof(k_pad)) { - SHA1Init(&ctx->u.sha1); - SHA1Update(&ctx->u.sha1, key, key_len); - SHA1Final(tk, &ctx->u.sha1); - key = tk; - key_len = 20; - } - os_memcpy(ctx->key, key, key_len); - ctx->key_len = key_len; - - os_memcpy(k_pad, key, key_len); - if (key_len < sizeof(k_pad)) - os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); - for (i = 0; i < sizeof(k_pad); i++) - k_pad[i] ^= 0x36; - SHA1Init(&ctx->u.sha1); - SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad)); - break; -#ifdef CONFIG_SHA256 - case CRYPTO_HASH_ALG_HMAC_SHA256: - if (key_len > sizeof(k_pad)) { - mbedtls_sha256_init(&ctx->u.sha256); - mbedtls_sha256_starts(&ctx->u.sha256, 0); - mbedtls_sha256_update(&ctx->u.sha256, key, key_len); - mbedtls_sha256_finish(&ctx->u.sha256, tk); - mbedtls_sha256_free(&ctx->u.sha256); - key = tk; - key_len = 32; - } - os_memcpy(ctx->key, key, key_len); - ctx->key_len = key_len; - - os_memcpy(k_pad, key, key_len); - if (key_len < sizeof(k_pad)) - os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); - for (i = 0; i < sizeof(k_pad); i++) - k_pad[i] ^= 0x36; - mbedtls_sha256_init(&ctx->u.sha256); - mbedtls_sha256_starts(&ctx->u.sha256, 0); - mbedtls_sha256_update(&ctx->u.sha256, k_pad, sizeof(k_pad)); - break; -#endif /* CONFIG_SHA256 */ - default: - os_free(ctx); - return NULL; - } - - return (struct crypto_hash *)ctx; -} - - -void fast_crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) -{ - - struct fast_crypto_hash *fast_ctx; - fast_ctx = (struct fast_crypto_hash *)ctx; - - if (fast_ctx == NULL) - return; - - switch (fast_ctx->alg) { - case CRYPTO_HASH_ALG_MD5: - case CRYPTO_HASH_ALG_HMAC_MD5: - MD5Update(&fast_ctx->u.md5, data, len); - break; - case CRYPTO_HASH_ALG_SHA1: - case CRYPTO_HASH_ALG_HMAC_SHA1: - SHA1Update(&fast_ctx->u.sha1, data, len); - break; -#ifdef CONFIG_SHA256 - case CRYPTO_HASH_ALG_SHA256: - case CRYPTO_HASH_ALG_HMAC_SHA256: - mbedtls_sha256_update(&fast_ctx->u.sha256, data, len); - break; -#endif /* CONFIG_SHA256 */ - default: - break; - } -} - - -int fast_crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) -{ - u8 k_pad[64]; - size_t i; - struct fast_crypto_hash *fast_ctx; - - if (ctx == NULL) - return -2; - - fast_ctx = (struct fast_crypto_hash *)ctx; - - if (mac == NULL || len == NULL) { - os_free(fast_ctx); - return 0; - } - - switch (fast_ctx->alg) { - case CRYPTO_HASH_ALG_MD5: - if (*len < 16) { - *len = 16; - os_free(fast_ctx); - return -1; - } - *len = 16; - MD5Final(mac, &fast_ctx->u.md5); - break; - case CRYPTO_HASH_ALG_SHA1: - if (*len < 20) { - *len = 20; - os_free(fast_ctx); - return -1; - } - *len = 20; - SHA1Final(mac, &fast_ctx->u.sha1); - break; -#ifdef CONFIG_SHA256 - case CRYPTO_HASH_ALG_SHA256: - if (*len < 32) { - *len = 32; - os_free(fast_ctx); - return -1; - } - *len = 32; - mbedtls_sha256_finish(&fast_ctx->u.sha256, mac); - mbedtls_sha256_free(&fast_ctx->u.sha256); - break; -#endif /* CONFIG_SHA256 */ - case CRYPTO_HASH_ALG_HMAC_MD5: - if (*len < 16) { - *len = 16; - os_free(fast_ctx); - return -1; - } - *len = 16; - - MD5Final(mac, &fast_ctx->u.md5); - - os_memcpy(k_pad, fast_ctx->key, fast_ctx->key_len); - os_memset(k_pad + fast_ctx->key_len, 0, - sizeof(k_pad) - fast_ctx->key_len); - for (i = 0; i < sizeof(k_pad); i++) - k_pad[i] ^= 0x5c; - MD5Init(&fast_ctx->u.md5); - MD5Update(&fast_ctx->u.md5, k_pad, sizeof(k_pad)); - MD5Update(&fast_ctx->u.md5, mac, 16); - MD5Final(mac, &fast_ctx->u.md5); - break; - case CRYPTO_HASH_ALG_HMAC_SHA1: - if (*len < 20) { - *len = 20; - os_free(ctx); - return -1; - } - *len = 20; - - SHA1Final(mac, &fast_ctx->u.sha1); - os_memcpy(k_pad, fast_ctx->key, fast_ctx->key_len); - os_memset(k_pad + fast_ctx->key_len, 0, - sizeof(k_pad) - fast_ctx->key_len); - for (i = 0; i < sizeof(k_pad); i++) - k_pad[i] ^= 0x5c; - SHA1Init(&fast_ctx->u.sha1); - SHA1Update(&fast_ctx->u.sha1, k_pad, sizeof(k_pad)); - SHA1Update(&fast_ctx->u.sha1, mac, 20); - SHA1Final(mac, &fast_ctx->u.sha1); - break; -#ifdef CONFIG_SHA256 - case CRYPTO_HASH_ALG_HMAC_SHA256: - if (*len < 32) { - *len = 32; - os_free(fast_ctx); - return -1; - } - *len = 32; - mbedtls_sha256_finish(&fast_ctx->u.sha256, mac); - mbedtls_sha256_free(&fast_ctx->u.sha256); - - os_memcpy(k_pad, fast_ctx->key, fast_ctx->key_len); - os_memset(k_pad + fast_ctx->key_len, 0, - sizeof(k_pad) - fast_ctx->key_len); - for (i = 0; i < sizeof(k_pad); i++) - k_pad[i] ^= 0x5c; - mbedtls_sha256_init(&fast_ctx->u.sha256); - mbedtls_sha256_starts(&fast_ctx->u.sha256, 0); - mbedtls_sha256_update(&fast_ctx->u.sha256, k_pad, sizeof(k_pad)); - mbedtls_sha256_update(&fast_ctx->u.sha256, mac, 32); - mbedtls_sha256_finish(&fast_ctx->u.sha256, mac); - mbedtls_sha256_free(&fast_ctx->u.sha256); - break; -#endif /* CONFIG_SHA256 */ - default: - os_free(fast_ctx); - return -1; - } - - os_free(fast_ctx); - - return 0; -} diff --git a/components/wpa_supplicant/src/fast_crypto/fast_sha256-internal.c b/components/wpa_supplicant/src/fast_crypto/fast_sha256-internal.c deleted file mode 100644 index cdbd072106..0000000000 --- a/components/wpa_supplicant/src/fast_crypto/fast_sha256-internal.c +++ /dev/null @@ -1,58 +0,0 @@ -// Hardware crypto support Copyright 2017 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 "utils/includes.h" -#include "utils/common.h" -#include "mbedtls/sha256.h" - -/** - * fast_sha256_vector - SHA256 hash for data vector - * @num_elem: Number of elements in the data vector - * @addr: Pointers to the data areas - * @len: Lengths of the data blocks - * @mac: Buffer for the hash - * Returns: 0 on success, -1 of failure - */ -int -fast_sha256_vector(size_t num_elem, const uint8_t *addr[], const size_t *len, - uint8_t *mac) -{ - int ret = 0; - mbedtls_sha256_context ctx; - - mbedtls_sha256_init(&ctx); - - if (mbedtls_sha256_starts_ret(&ctx, 0) != 0) { - ret = -1; - goto out; - } - - for(size_t index = 0; index < num_elem; index++) { - if (mbedtls_sha256_update_ret(&ctx, addr[index], len[index]) != 0) { - ret = -1; - goto out; - } - } - - if (mbedtls_sha256_finish_ret(&ctx, mac) != 0) { - ret = -1; - goto out; - } - -out: - mbedtls_sha256_free(&ctx); - - return ret; -} - diff --git a/components/wpa_supplicant/src/fast_crypto/fast_sha256.c b/components/wpa_supplicant/src/fast_crypto/fast_sha256.c deleted file mode 100644 index 0f0a785b1a..0000000000 --- a/components/wpa_supplicant/src/fast_crypto/fast_sha256.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * SHA-256 hash implementation and interface functions - * Copyright (c) 2003-2007, Jouni Malinen - * - * Hardware crypto support Copyright 2017 Espressif Systems (Shanghai) PTE LTD - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "crypto/sha256.h" -#include "crypto/crypto.h" - - -/** - * fast_hmac_sha256_vector - HMAC-SHA256 over data vector (RFC 2104) - * @key: Key for HMAC operations - * @key_len: Length of the key in bytes - * @num_elem: Number of elements in the data vector - * @addr: Pointers to the data areas - * @len: Lengths of the data blocks - * @mac: Buffer for the hash (32 bytes) - */ -void -fast_hmac_sha256_vector(const uint8_t *key, size_t key_len, size_t num_elem, - const uint8_t *addr[], const size_t *len, uint8_t *mac) -{ - uint8_t k_pad[64]; /* padding - key XORd with ipad/opad */ - uint8_t tk[32]; - const uint8_t *_addr[6]; - size_t _len[6], i; - - if (num_elem > 5) { - /* - * Fixed limit on the number of fragments to avoid having to - * allocate memory (which could fail). - */ - return; - } - - /* if key is longer than 64 bytes reset it to key = SHA256(key) */ - if (key_len > 64) { - fast_sha256_vector(1, &key, &key_len, tk); - key = tk; - key_len = 32; - } - - /* the HMAC_SHA256 transform looks like: - * - * SHA256(K XOR opad, SHA256(K XOR ipad, text)) - * - * where K is an n byte key - * ipad is the byte 0x36 repeated 64 times - * opad is the byte 0x5c repeated 64 times - * and text is the data being protected - */ - - /* start out by storing key in ipad */ - os_memset(k_pad, 0, sizeof(k_pad)); - os_memcpy(k_pad, key, key_len); - /* XOR key with ipad values */ - for (i = 0; i < 64; i++) { - k_pad[i] ^= 0x36; - } - - /* perform inner SHA256 */ - _addr[0] = k_pad; - _len[0] = 64; - for (i = 0; i < num_elem; i++) { - _addr[i + 1] = addr[i]; - _len[i + 1] = len[i]; - } - fast_sha256_vector(1 + num_elem, _addr, _len, mac); - - os_memset(k_pad, 0, sizeof(k_pad)); - os_memcpy(k_pad, key, key_len); - /* XOR key with opad values */ - for (i = 0; i < 64; i++) { - k_pad[i] ^= 0x5c; - } - - /* perform outer SHA256 */ - _addr[0] = k_pad; - _len[0] = 64; - _addr[1] = mac; - _len[1] = SHA256_MAC_LEN; - fast_sha256_vector(2, _addr, _len, mac); -} - - -/** - * fast_hmac_sha256 - HMAC-SHA256 over data buffer (RFC 2104) - * @key: Key for HMAC operations - * @key_len: Length of the key in bytes - * @data: Pointers to the data area - * @data_len: Length of the data area - * @mac: Buffer for the hash (20 bytes) - */ -void -fast_hmac_sha256(const uint8_t *key, size_t key_len, const uint8_t *data, - size_t data_len, uint8_t *mac) -{ - fast_hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac); -} - - -/** - * fast_sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2) - * @key: Key for PRF - * @key_len: Length of the key in bytes - * @label: A unique label for each purpose of the PRF - * @data: Extra data to bind into the key - * @data_len: Length of the data - * @buf: Buffer for the generated pseudo-random key - * @buf_len: Number of bytes of key to generate - * - * This function is used to derive new, cryptographically separate keys from a - * given key. - */ -void -fast_sha256_prf(const uint8_t *key, size_t key_len, const char *label, - const uint8_t *data, size_t data_len, uint8_t *buf, size_t buf_len) -{ - uint16_t counter = 1; - size_t pos, plen; - uint8_t hash[SHA256_MAC_LEN]; - const uint8_t *addr[4]; - size_t len[4]; - uint8_t counter_le[2], length_le[2]; - - addr[0] = counter_le; - len[0] = 2; - addr[1] = (uint8_t *) label; - len[1] = os_strlen(label); - addr[2] = data; - len[2] = data_len; - addr[3] = length_le; - len[3] = sizeof(length_le); - - WPA_PUT_LE16(length_le, buf_len * 8); - pos = 0; - while (pos < buf_len) { - plen = buf_len - pos; - WPA_PUT_LE16(counter_le, counter); - if (plen >= SHA256_MAC_LEN) { - fast_hmac_sha256_vector(key, key_len, 4, addr, len, - &buf[pos]); - pos += SHA256_MAC_LEN; - } else { - fast_hmac_sha256_vector(key, key_len, 4, addr, len, hash); - os_memcpy(&buf[pos], hash, plen); - break; - } - counter++; - } -} diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.c b/components/wpa_supplicant/src/rsn_supp/wpa.c index c5b5c86375..29d79bbc67 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -1179,7 +1179,7 @@ failed: #endif return -1; } - if (fast_aes_unwrap(sm->ptk.kek, maxkeylen / 8, + if (aes_unwrap(sm->ptk.kek, maxkeylen / 8, (const u8 *) (key + 1), gd->gtk)) { #ifdef DEBUG_PRINT wpa_printf(MSG_DEBUG, "WPA: AES unwrap " @@ -1424,7 +1424,7 @@ failed: return -1; } */ - if (fast_aes_unwrap(sm->ptk.kek, keydatalen / 8, + if (aes_unwrap(sm->ptk.kek, keydatalen / 8, (u8 *) (key + 1), buf)) { #ifdef DEBUG_PRINT wpa_printf(MSG_DEBUG, "WPA: AES unwrap failed - " diff --git a/components/wpa_supplicant/src/tls/pkcs5.c b/components/wpa_supplicant/src/tls/pkcs5.c index 734a033681..4697074074 100644 --- a/components/wpa_supplicant/src/tls/pkcs5.c +++ b/components/wpa_supplicant/src/tls/pkcs5.c @@ -165,7 +165,7 @@ static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params, wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES key", hash, 8); wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES IV", hash + 8, 8); - return fast_crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8); + return crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8); } @@ -194,24 +194,24 @@ u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len, if (enc_data_len < 16 || enc_data_len % 8) { wpa_printf(MSG_INFO, "PKCS #5: invalid length of ciphertext " "%d", (int) enc_data_len); - fast_crypto_cipher_deinit(ctx); + crypto_cipher_deinit(ctx); return NULL; } eb = os_malloc(enc_data_len); if (eb == NULL) { - fast_crypto_cipher_deinit(ctx); + crypto_cipher_deinit(ctx); return NULL; } - if ((int)fast_crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) { + if ((int)crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) { wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB"); - fast_crypto_cipher_deinit(ctx); + crypto_cipher_deinit(ctx); os_free(eb); return NULL; } - fast_crypto_cipher_deinit(ctx); + crypto_cipher_deinit(ctx); pad = eb[enc_data_len - 1]; if (pad > 8) { diff --git a/components/wpa_supplicant/src/tls/tlsv1_client_read.c b/components/wpa_supplicant/src/tls/tlsv1_client_read.c index 89b25e149b..a585f20603 100644 --- a/components/wpa_supplicant/src/tls/tlsv1_client_read.c +++ b/components/wpa_supplicant/src/tls/tlsv1_client_read.c @@ -816,7 +816,7 @@ static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct, if (conn->rl.tls_version >= TLS_VERSION_1_2) { hlen = SHA256_MAC_LEN; if (conn->verify.sha256_server == NULL || - fast_crypto_hash_finish(conn->verify.sha256_server, hash, &hlen) < 0) { + crypto_hash_finish(conn->verify.sha256_server, hash, &hlen) < 0) { tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); conn->verify.sha256_server = NULL; return -1; diff --git a/components/wpa_supplicant/src/tls/tlsv1_client_write.c b/components/wpa_supplicant/src/tls/tlsv1_client_write.c index 6f4f887528..53a1b33881 100644 --- a/components/wpa_supplicant/src/tls/tlsv1_client_write.c +++ b/components/wpa_supplicant/src/tls/tlsv1_client_write.c @@ -476,7 +476,7 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn, if (conn->rl.tls_version == TLS_VERSION_1_2) { hlen = SHA256_MAC_LEN; if (conn->verify.sha256_cert == NULL || - fast_crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) < + crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) < 0) { conn->verify.sha256_cert = NULL; tls_alert(conn, TLS_ALERT_LEVEL_FATAL, @@ -654,7 +654,7 @@ static int tls_write_client_finished(struct tlsv1_client *conn, if (conn->rl.tls_version >= TLS_VERSION_1_2) { hlen = SHA256_MAC_LEN; if (conn->verify.sha256_client == NULL || - fast_crypto_hash_finish(conn->verify.sha256_client, hash, &hlen) + crypto_hash_finish(conn->verify.sha256_client, hash, &hlen) < 0) { tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); diff --git a/components/wpa_supplicant/src/tls/tlsv1_common.c b/components/wpa_supplicant/src/tls/tlsv1_common.c index 5380df8769..f0ba62f270 100644 --- a/components/wpa_supplicant/src/tls/tlsv1_common.c +++ b/components/wpa_supplicant/src/tls/tlsv1_common.c @@ -221,9 +221,9 @@ int tls_verify_hash_init(struct tls_verify_hash *verify) return -1; } #ifdef CONFIG_TLSV12 - verify->sha256_client = fast_crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0); - verify->sha256_server = fast_crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0); - verify->sha256_cert = fast_crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0); + verify->sha256_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0); + verify->sha256_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0); + verify->sha256_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0); if (verify->sha256_client == NULL || verify->sha256_server == NULL || @@ -253,11 +253,11 @@ void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf, } #ifdef CONFIG_TLSV12 if (verify->sha256_client) - fast_crypto_hash_update(verify->sha256_client, buf, len); + crypto_hash_update(verify->sha256_client, buf, len); if (verify->sha256_server) - fast_crypto_hash_update(verify->sha256_server, buf, len); + crypto_hash_update(verify->sha256_server, buf, len); if (verify->sha256_cert) - fast_crypto_hash_update(verify->sha256_cert, buf, len); + crypto_hash_update(verify->sha256_cert, buf, len); #endif /* CONFIG_TLSV12 */ } @@ -277,9 +277,9 @@ void tls_verify_hash_free(struct tls_verify_hash *verify) verify->sha1_server = NULL; verify->sha1_cert = NULL; #ifdef CONFIG_TLSV12 - fast_crypto_hash_finish(verify->sha256_client, NULL, NULL); - fast_crypto_hash_finish(verify->sha256_server, NULL, NULL); - fast_crypto_hash_finish(verify->sha256_cert, NULL, NULL); + crypto_hash_finish(verify->sha256_client, NULL, NULL); + crypto_hash_finish(verify->sha256_server, NULL, NULL); + crypto_hash_finish(verify->sha256_cert, NULL, NULL); verify->sha256_client = NULL; verify->sha256_server = NULL; verify->sha256_cert = NULL; diff --git a/components/wpa_supplicant/src/tls/tlsv1_record.c b/components/wpa_supplicant/src/tls/tlsv1_record.c index 12b14e79b8..8e3077d873 100644 --- a/components/wpa_supplicant/src/tls/tlsv1_record.c +++ b/components/wpa_supplicant/src/tls/tlsv1_record.c @@ -81,12 +81,12 @@ int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl) os_memset(rl->write_seq_num, 0, TLS_SEQ_NUM_LEN); if (rl->write_cbc) { - fast_crypto_cipher_deinit(rl->write_cbc); + crypto_cipher_deinit(rl->write_cbc); rl->write_cbc = NULL; } if (rl->cipher_alg != CRYPTO_CIPHER_NULL) { - rl->write_cbc = fast_crypto_cipher_init(rl->cipher_alg, + rl->write_cbc = crypto_cipher_init(rl->cipher_alg, rl->write_iv, rl->write_key, rl->key_material_len); @@ -117,12 +117,12 @@ int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl) os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN); if (rl->read_cbc) { - fast_crypto_cipher_deinit(rl->read_cbc); + crypto_cipher_deinit(rl->read_cbc); rl->read_cbc = NULL; } if (rl->cipher_alg != CRYPTO_CIPHER_NULL) { - rl->read_cbc = fast_crypto_cipher_init(rl->cipher_alg, + rl->read_cbc = crypto_cipher_init(rl->cipher_alg, rl->read_iv, rl->read_key, rl->key_material_len); if (rl->read_cbc == NULL) { @@ -208,26 +208,26 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf, * TLSCompressed.version + TLSCompressed.length + * TLSCompressed.fragment */ - hmac = fast_crypto_hash_init(rl->hash_alg, rl->write_mac_secret, rl->hash_size); + hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret, rl->hash_size); if (hmac == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " "to initialize HMAC"); return -1; } - fast_crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN); + crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN); /* type + version + length + fragment */ - fast_crypto_hash_update(hmac, ct_start, TLS_RECORD_HEADER_LEN); - fast_crypto_hash_update(hmac, payload, payload_len); + crypto_hash_update(hmac, ct_start, TLS_RECORD_HEADER_LEN); + crypto_hash_update(hmac, payload, payload_len); clen = buf + buf_size - pos; if (clen < rl->hash_size) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not " "enough room for MAC"); - fast_crypto_hash_finish(hmac, NULL, NULL); + crypto_hash_finish(hmac, NULL, NULL); return -1; } - if ((int)fast_crypto_hash_finish(hmac, pos, &clen) < 0) { + if ((int)crypto_hash_finish(hmac, pos, &clen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed to calculate HMAC"); return -1; } @@ -250,7 +250,7 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf, pos += pad + 1; } - if ((int)fast_crypto_cipher_encrypt(rl->write_cbc, cpayload, + if ((int)crypto_cipher_encrypt(rl->write_cbc, cpayload, cpayload, pos - cpayload) < 0) return -1; } @@ -358,7 +358,7 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl, if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) { size_t plen; - if ((int)fast_crypto_cipher_decrypt(rl->read_cbc, in_data, + if ((int)crypto_cipher_decrypt(rl->read_cbc, in_data, out_data, in_len) < 0) { *alert = TLS_ALERT_DECRYPTION_FAILED; return -1; @@ -438,7 +438,7 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl, plen -= rl->hash_size; - hmac = fast_crypto_hash_init(rl->hash_alg, rl->read_mac_secret, rl->hash_size); + hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret, rl->hash_size); if (hmac == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " @@ -447,15 +447,15 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl, return -1; } - fast_crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN); + crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN); /* type + version + length + fragment */ - fast_crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3); + crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3); WPA_PUT_BE16(len, plen); - fast_crypto_hash_update(hmac, len, 2); - fast_crypto_hash_update(hmac, out_data, plen); + crypto_hash_update(hmac, len, 2); + crypto_hash_update(hmac, out_data, plen); hlen = sizeof(hash); - if ((int)fast_crypto_hash_finish(hmac, hash, &hlen) < 0) { + if ((int)crypto_hash_finish(hmac, hash, &hlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed to calculate HMAC"); *alert = TLS_ALERT_INTERNAL_ERROR; return -1; diff --git a/components/wpa_supplicant/src/tls/tlsv1_server_read.c b/components/wpa_supplicant/src/tls/tlsv1_server_read.c index 28d1e27295..cc42662689 100644 --- a/components/wpa_supplicant/src/tls/tlsv1_server_read.c +++ b/components/wpa_supplicant/src/tls/tlsv1_server_read.c @@ -871,7 +871,7 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct, hlen = SHA256_MAC_LEN; if (conn->verify.sha256_cert == NULL || - fast_crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) < + crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) < 0) { conn->verify.sha256_cert = NULL; tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, diff --git a/components/wpa_supplicant/src/tls/tlsv1_server_write.c b/components/wpa_supplicant/src/tls/tlsv1_server_write.c index 39413e8347..3d393bc9c7 100644 --- a/components/wpa_supplicant/src/tls/tlsv1_server_write.c +++ b/components/wpa_supplicant/src/tls/tlsv1_server_write.c @@ -588,7 +588,7 @@ static int tls_write_server_finished(struct tlsv1_server *conn, if (conn->rl.tls_version >= TLS_VERSION_1_2) { hlen = SHA256_MAC_LEN; if (conn->verify.sha256_server == NULL || - fast_crypto_hash_finish(conn->verify.sha256_server, hash, &hlen) + crypto_hash_finish(conn->verify.sha256_server, hash, &hlen) < 0) { conn->verify.sha256_server = NULL; tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, diff --git a/components/wpa_supplicant/src/tls/x509v3.c b/components/wpa_supplicant/src/tls/x509v3.c index d4f4652ff0..2a5b5f3b48 100644 --- a/components/wpa_supplicant/src/tls/x509v3.c +++ b/components/wpa_supplicant/src/tls/x509v3.c @@ -1688,7 +1688,7 @@ skip_digest_oid: hash, hash_len); break; case 11: /* sha256WithRSAEncryption */ - fast_sha256_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, + sha256_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, hash); hash_len = 32; wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA256)", diff --git a/components/wpa_supplicant/src/wps/wps_attr_build.c b/components/wpa_supplicant/src/wps/wps_attr_build.c index d57096af11..bd2aa5e947 100644 --- a/components/wpa_supplicant/src/wps/wps_attr_build.c +++ b/components/wpa_supplicant/src/wps/wps_attr_build.c @@ -166,7 +166,7 @@ int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg) len[0] = wpabuf_len(wps->last_msg); addr[1] = wpabuf_head(msg); len[1] = wpabuf_len(msg); - fast_hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash); + hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash); wpa_printf(MSG_DEBUG, "WPS: * Authenticator"); wpabuf_put_be16(msg, ATTR_AUTHENTICATOR); wpabuf_put_be16(msg, WPS_AUTHENTICATOR_LEN); @@ -324,7 +324,7 @@ int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg) u8 hash[SHA256_MAC_LEN]; wpa_printf(MSG_DEBUG, "WPS: * Key Wrap Authenticator"); - fast_hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg), + hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg), wpabuf_len(msg), hash); wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH); wpabuf_put_be16(msg, WPS_KWA_LEN); @@ -356,7 +356,7 @@ int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg, data = wpabuf_put(msg, 0); wpabuf_put_buf(msg, plain); wpa_printf(MSG_DEBUG, "WPS: * AES 128 Encrypted Settings"); - if (fast_aes_128_cbc_encrypt(wps->keywrapkey, iv, data, wpabuf_len(plain))) + if (aes_128_cbc_encrypt(wps->keywrapkey, iv, data, wpabuf_len(plain))) return -1; return 0; } @@ -373,7 +373,7 @@ int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id, addr[0] = wpabuf_head(pubkey); hash_len = wpabuf_len(pubkey); - fast_sha256_vector(1, addr, &hash_len, pubkey_hash); + sha256_vector(1, addr, &hash_len, pubkey_hash); wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD); wpabuf_put_be16(msg, WPS_OOB_PUBKEY_HASH_LEN + 2 + dev_pw_len); wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN); @@ -414,4 +414,4 @@ struct wpabuf * wps_ie_encapsulate(struct wpabuf *data) wpabuf_free(data); return ie; -} \ No newline at end of file +} diff --git a/components/wpa_supplicant/src/wps/wps_attr_process.c b/components/wpa_supplicant/src/wps/wps_attr_process.c index 15df0360a5..112d683a3f 100644 --- a/components/wpa_supplicant/src/wps/wps_attr_process.c +++ b/components/wpa_supplicant/src/wps/wps_attr_process.c @@ -38,7 +38,7 @@ int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator, len[0] = wpabuf_len(wps->last_msg); addr[1] = wpabuf_head(msg); len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN; - fast_hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash); + hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash); if (os_memcmp(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) { wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator"); return -1; @@ -68,7 +68,7 @@ int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg, return -1; } - fast_hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash); + hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash); if (os_memcmp(hash, key_wrap_auth, WPS_KWA_LEN) != 0) { wpa_printf(MSG_DEBUG, "WPS: Invalid KWA"); return -1; diff --git a/components/wpa_supplicant/src/wps/wps_common.c b/components/wpa_supplicant/src/wps/wps_common.c index 8eaf3e9c12..e37a35b273 100644 --- a/components/wpa_supplicant/src/wps/wps_common.c +++ b/components/wpa_supplicant/src/wps/wps_common.c @@ -46,7 +46,7 @@ void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len, for (i = 1; i <= iter; i++) { WPA_PUT_BE32(i_buf, i); - fast_hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, len, hash); + hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, len, hash); if (i < iter) { os_memcpy(opos, hash, SHA256_MAC_LEN); opos += SHA256_MAC_LEN; @@ -103,7 +103,7 @@ int wps_derive_keys(struct wps_data *wps) addr[0] = wpabuf_head(dh_shared); len[0] = wpabuf_len(dh_shared); - fast_sha256_vector(1, addr, len, dhkey); + sha256_vector(1, addr, len, dhkey); wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey)); wpabuf_free(dh_shared); @@ -114,7 +114,7 @@ int wps_derive_keys(struct wps_data *wps) len[1] = ETH_ALEN; addr[2] = wps->nonce_r; len[2] = WPS_NONCE_LEN; - fast_hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk); + hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk); wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk)); wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation", @@ -139,10 +139,10 @@ void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd, { u8 hash[SHA256_MAC_LEN]; - fast_hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd, + hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd, (dev_passwd_len + 1) / 2, hash); os_memcpy(wps->psk1, hash, WPS_PSK_LEN); - fast_hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, + hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd + (dev_passwd_len + 1) / 2, dev_passwd_len / 2, hash); os_memcpy(wps->psk2, hash, WPS_PSK_LEN); @@ -177,7 +177,7 @@ struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr, wpa_hexdump(MSG_MSGDUMP, "WPS: Encrypted Settings", encr, encr_len); wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size); wpa_printf(MSG_DEBUG, "WPS: AES Decrypt setting"); - if (fast_aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted), + if (aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted), wpabuf_len(decrypted))) { wpabuf_free(decrypted); return NULL; diff --git a/components/wpa_supplicant/src/wps/wps_enrollee.c b/components/wpa_supplicant/src/wps/wps_enrollee.c index ffe4d5789b..7a30836577 100644 --- a/components/wpa_supplicant/src/wps/wps_enrollee.c +++ b/components/wpa_supplicant/src/wps/wps_enrollee.c @@ -74,7 +74,7 @@ static int wps_build_e_hash(struct wps_data *wps, struct wpabuf *msg) len[2] = wpabuf_len(wps->dh_pubkey_e); addr[3] = wpabuf_head(wps->dh_pubkey_r); len[3] = wpabuf_len(wps->dh_pubkey_r); - fast_hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); + hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); wpa_hexdump(MSG_DEBUG, "WPS: E-Hash1", hash, SHA256_MAC_LEN); wpa_printf(MSG_DEBUG, "WPS: * E-Hash2"); @@ -84,7 +84,7 @@ static int wps_build_e_hash(struct wps_data *wps, struct wpabuf *msg) /* E-Hash2 = HMAC_AuthKey(E-S2 || PSK2 || PK_E || PK_R) */ addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN; addr[1] = wps->psk2; - fast_hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); + hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); wpa_hexdump(MSG_DEBUG, "WPS: E-Hash2", hash, SHA256_MAC_LEN); return 0; @@ -593,7 +593,7 @@ static int wps_process_r_snonce1(struct wps_data *wps, const u8 *r_snonce1) addr[3] = wpabuf_head(wps->dh_pubkey_r); len[3] = wpabuf_len(wps->dh_pubkey_r); - fast_hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); + hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) { wpa_printf(MSG_DEBUG, "WPS: R-Hash1 derived from R-S1 does " "not match with the pre-committed value"); @@ -633,7 +633,7 @@ static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2) addr[3] = wpabuf_head(wps->dh_pubkey_r); len[3] = wpabuf_len(wps->dh_pubkey_r); - fast_hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); + hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) { wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does " diff --git a/components/wpa_supplicant/src/wps/wps_registrar.c b/components/wpa_supplicant/src/wps/wps_registrar.c index 3293ef6263..e197dfdc06 100644 --- a/components/wpa_supplicant/src/wps/wps_registrar.c +++ b/components/wpa_supplicant/src/wps/wps_registrar.c @@ -1427,7 +1427,7 @@ static int wps_build_r_hash(struct wps_data *wps, struct wpabuf *msg) len[2] = wpabuf_len(wps->dh_pubkey_e); addr[3] = wpabuf_head(wps->dh_pubkey_r); len[3] = wpabuf_len(wps->dh_pubkey_r); - fast_hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); + hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); wpa_hexdump(MSG_DEBUG, "WPS: R-Hash1", hash, SHA256_MAC_LEN); wpa_printf(MSG_DEBUG, "WPS: * R-Hash2"); @@ -1437,7 +1437,7 @@ static int wps_build_r_hash(struct wps_data *wps, struct wpabuf *msg) /* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */ addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN; addr[1] = wps->psk2; - fast_hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); + hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); wpa_hexdump(MSG_DEBUG, "WPS: R-Hash2", hash, SHA256_MAC_LEN); return 0; @@ -2170,7 +2170,7 @@ static int wps_process_e_snonce1(struct wps_data *wps, const u8 *e_snonce1) len[2] = wpabuf_len(wps->dh_pubkey_e); addr[3] = wpabuf_head(wps->dh_pubkey_r); len[3] = wpabuf_len(wps->dh_pubkey_r); - fast_hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); + hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) { wpa_printf(MSG_DEBUG, "WPS: E-Hash1 derived from E-S1 does " "not match with the pre-committed value"); @@ -2210,7 +2210,7 @@ static int wps_process_e_snonce2(struct wps_data *wps, const u8 *e_snonce2) addr[3] = wpabuf_head(wps->dh_pubkey_r); len[3] = wpabuf_len(wps->dh_pubkey_r); - fast_hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); + hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) { wpa_printf(MSG_DEBUG, "WPS: E-Hash2 derived from E-S2 does " "not match with the pre-committed value"); @@ -2547,7 +2547,7 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps, wps->nfc_pw_token = token; addr[0] = attr->public_key; - fast_sha256_vector(1, addr, &attr->public_key_len, hash); + sha256_vector(1, addr, &attr->public_key_len, hash); if (os_memcmp(hash, wps->nfc_pw_token->pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN) != 0) { wpa_printf(MSG_ERROR, "WPS: Public Key hash " From aa0c5f03be241be4f5a4720a11eaa3fb2e692513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Christian=20Madsen?= Date: Thu, 27 Jun 2019 14:54:04 +0200 Subject: [PATCH 296/486] Add --baud option to parttool Closes https://github.com/espressif/esp-idf/pull/3753 --- components/partition_table/parttool.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/components/partition_table/parttool.py b/components/partition_table/parttool.py index f82b90c3fa..84a0d1eaf4 100755 --- a/components/partition_table/parttool.py +++ b/components/partition_table/parttool.py @@ -67,9 +67,10 @@ PARTITION_BOOT_DEFAULT = _PartitionId() class ParttoolTarget(): - def __init__(self, port=None, partition_table_offset=PARTITION_TABLE_OFFSET, partition_table_file=None, + def __init__(self, port=None, baud=None, partition_table_offset=PARTITION_TABLE_OFFSET, partition_table_file=None, esptool_args=[], esptool_write_args=[], esptool_read_args=[], esptool_erase_args=[]): self.port = port + self.baud = baud gen.offset_part_table = partition_table_offset @@ -118,6 +119,9 @@ class ParttoolTarget(): if self.port: esptool_args += ["--port", self.port] + if self.baud: + esptool_args += ["--baud", str(self.baud)] + esptool_args += args with open(os.devnull, "w") as null_file: @@ -220,6 +224,7 @@ def main(): # is specified, that is used instead. parser.add_argument("--port", "-p", help="port where the target device of the command is connected to; the partition table is sourced from this device \ when the partition table file is not defined") + parser.add_argument("--baud", "-b", help="baudrate to use", type=int) parser.add_argument("--partition-table-offset", "-o", help="offset to read the partition table from", type=str) parser.add_argument("--partition-table-file", "-f", help="file (CSV/binary) to read the partition table from; \ @@ -282,6 +287,9 @@ def main(): if args.port: target_args["port"] = args.port + if args.baud: + target_args["baud"] = args.baud + if args.partition_table_file: target_args["partition_table_file"] = args.partition_table_file From 3f47269211cd81af2045af5d81d9379a993ee9ae Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Wed, 10 Jul 2019 08:41:47 +0200 Subject: [PATCH 297/486] app_update: Fix argument of ParttoolTarget --- components/app_update/otatool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/app_update/otatool.py b/components/app_update/otatool.py index 9bc392c39e..302ebd08a3 100755 --- a/components/app_update/otatool.py +++ b/components/app_update/otatool.py @@ -53,7 +53,7 @@ class OtatoolTarget(): def __init__(self, port=None, partition_table_offset=PARTITION_TABLE_OFFSET, partition_table_file=None, spi_flash_sec_size=SPI_FLASH_SEC_SIZE, esptool_args=[], esptool_write_args=[], esptool_read_args=[], esptool_erase_args=[]): - self.target = ParttoolTarget(port, partition_table_offset, partition_table_file, esptool_args, + self.target = ParttoolTarget(port, None, partition_table_offset, partition_table_file, esptool_args, esptool_write_args, esptool_read_args, esptool_erase_args) self.spi_flash_sec_size = spi_flash_sec_size From 3552ca4d6a1260df8699b6c278c186137c4f59f1 Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Wed, 10 Jul 2019 14:11:12 +0200 Subject: [PATCH 298/486] app_update: Add the baud option into otatool --- components/app_update/otatool.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/components/app_update/otatool.py b/components/app_update/otatool.py index 302ebd08a3..20f69fa923 100755 --- a/components/app_update/otatool.py +++ b/components/app_update/otatool.py @@ -50,10 +50,10 @@ class OtatoolTarget(): OTADATA_PARTITION = PartitionType("data", "ota") - def __init__(self, port=None, partition_table_offset=PARTITION_TABLE_OFFSET, partition_table_file=None, + def __init__(self, port=None, baud=None, partition_table_offset=PARTITION_TABLE_OFFSET, partition_table_file=None, spi_flash_sec_size=SPI_FLASH_SEC_SIZE, esptool_args=[], esptool_write_args=[], esptool_read_args=[], esptool_erase_args=[]): - self.target = ParttoolTarget(port, None, partition_table_offset, partition_table_file, esptool_args, + self.target = ParttoolTarget(port, baud, partition_table_offset, partition_table_file, esptool_args, esptool_write_args, esptool_read_args, esptool_erase_args) self.spi_flash_sec_size = spi_flash_sec_size @@ -263,6 +263,8 @@ def main(): # or a partition table CSV/binary file. These sources are mutually exclusive. parser.add_argument("--port", "-p", help="port where the device to read the partition table from is attached") + parser.add_argument("--baud", "-b", help="baudrate to use", type=int) + parser.add_argument("--partition-table-offset", "-o", help="offset to read the partition table from", type=str) parser.add_argument("--partition-table-file", "-f", help="file (CSV/binary) to read the partition table from; \ @@ -331,6 +333,9 @@ def main(): if args.esptool_erase_args: target_args["esptool_erase_args"] = args.esptool_erase_args + if args.baud: + target_args["baud"] = args.baud + target = OtatoolTarget(**target_args) # Create the operation table and execute the operation From 41b6811f453b97b512bbdbc9cd2983b5edd2d04f Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 10 Jul 2019 13:20:17 +0200 Subject: [PATCH 299/486] unit-test-app: split default, release, single_core configs --- tools/unit-test-app/configs/default | 2 +- tools/unit-test-app/configs/default_2 | 1 + tools/unit-test-app/configs/release | 2 +- tools/unit-test-app/configs/release_2 | 3 +++ tools/unit-test-app/configs/single_core | 2 +- tools/unit-test-app/configs/single_core_2 | 4 ++++ 6 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 tools/unit-test-app/configs/default_2 create mode 100644 tools/unit-test-app/configs/release_2 create mode 100644 tools/unit-test-app/configs/single_core_2 diff --git a/tools/unit-test-app/configs/default b/tools/unit-test-app/configs/default index f7f508a43e..572b6cd8b8 100644 --- a/tools/unit-test-app/configs/default +++ b/tools/unit-test-app/configs/default @@ -1 +1 @@ -TEST_EXCLUDE_COMPONENTS=libsodium bt app_update \ No newline at end of file +TEST_COMPONENTS=freertos esp32 driver heap pthread soc spi_flash vfs \ No newline at end of file diff --git a/tools/unit-test-app/configs/default_2 b/tools/unit-test-app/configs/default_2 new file mode 100644 index 0000000000..c02ec4789c --- /dev/null +++ b/tools/unit-test-app/configs/default_2 @@ -0,0 +1 @@ +TEST_EXCLUDE_COMPONENTS=libsodium bt app_update freertos esp32 driver heap pthread soc spi_flash vfs \ No newline at end of file diff --git a/tools/unit-test-app/configs/release b/tools/unit-test-app/configs/release index d58d949976..75da1aa803 100644 --- a/tools/unit-test-app/configs/release +++ b/tools/unit-test-app/configs/release @@ -1,3 +1,3 @@ -TEST_EXCLUDE_COMPONENTS=bt app_update +TEST_COMPONENTS=freertos esp32 driver heap pthread soc spi_flash vfs CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y diff --git a/tools/unit-test-app/configs/release_2 b/tools/unit-test-app/configs/release_2 new file mode 100644 index 0000000000..c3e1046759 --- /dev/null +++ b/tools/unit-test-app/configs/release_2 @@ -0,0 +1,3 @@ +TEST_EXCLUDE_COMPONENTS=libsodium bt app_update freertos esp32 driver heap pthread soc spi_flash vfs +CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y diff --git a/tools/unit-test-app/configs/single_core b/tools/unit-test-app/configs/single_core index 9c85abae62..40f7e98f21 100644 --- a/tools/unit-test-app/configs/single_core +++ b/tools/unit-test-app/configs/single_core @@ -1,4 +1,4 @@ -TEST_EXCLUDE_COMPONENTS=libsodium bt app_update +TEST_COMPONENTS=freertos esp32 driver heap pthread soc spi_flash vfs CONFIG_MEMMAP_SMP=n CONFIG_FREERTOS_UNICORE=y CONFIG_ESP32_RTCDATA_IN_FAST_MEM=y diff --git a/tools/unit-test-app/configs/single_core_2 b/tools/unit-test-app/configs/single_core_2 new file mode 100644 index 0000000000..17910a0668 --- /dev/null +++ b/tools/unit-test-app/configs/single_core_2 @@ -0,0 +1,4 @@ +TEST_EXCLUDE_COMPONENTS=libsodium bt app_update freertos esp32 driver heap pthread soc spi_flash vfs +CONFIG_MEMMAP_SMP=n +CONFIG_FREERTOS_UNICORE=y +CONFIG_ESP32_RTCDATA_IN_FAST_MEM=y From 56e3f2780d997b78844a7b3ccc5ea45d6fa7dcad Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 10 Jul 2019 14:19:13 +0200 Subject: [PATCH 300/486] ci: add unit test job --- tools/ci/config/target-test.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/ci/config/target-test.yml b/tools/ci/config/target-test.yml index c8c12a321e..6aa25316ea 100644 --- a/tools/ci/config/target-test.yml +++ b/tools/ci/config/target-test.yml @@ -203,6 +203,9 @@ UT_001: - ESP32_IDF - UT_T1_1 +# Max. allowed value of 'parallel' is 50. +# See UT_030 below if you want to add more unit test jobs. + UT_002: extends: .unit_test_template parallel: 18 @@ -404,7 +407,7 @@ UT_029: # Gitlab parallel max value is 50. We need to create another UT job if parallel is larger than 50. UT_030: extends: .unit_test_template - parallel: 5 + parallel: 6 tags: - ESP32_IDF - UT_T1_1 From edd7f90b776759ecdb75409463c7f23a43e027ea Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 10 Jul 2019 17:16:53 +0200 Subject: [PATCH 301/486] ci: don't build examples with Make on pushes Still build the examples with make on: - triggered pipelines - master, release branches, tags - scheduled and manual (web) pipelines --- tools/ci/config/build.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/ci/config/build.yml b/tools/ci/config/build.yml index 907492a52a..5e6b3cde03 100644 --- a/tools/ci/config/build.yml +++ b/tools/ci/config/build.yml @@ -127,12 +127,21 @@ build_examples_make: variables: LOG_PATH: "$CI_PROJECT_DIR/log_examples_make" only: + # Here both 'variables' and 'refs' conditions are given. They are combined with "AND" logic. variables: - $BOT_TRIGGER_WITH_LABEL == null - $BOT_LABEL_BUILD - $BOT_LABEL_EXAMPLE_TEST - $BOT_LABEL_REGULAR_TEST - $BOT_LABEL_WEEKEND_TEST + refs: + - master + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ + - triggers + - schedules + - pipelines + - web script: # it's not possible to build 100% out-of-tree and have the "artifacts" # mechanism work, but this is the next best thing From 663ed11509ca839d2aef97d6b2ee281161d57dee Mon Sep 17 00:00:00 2001 From: He Yin Ling Date: Wed, 10 Jul 2019 23:00:25 +0800 Subject: [PATCH 302/486] unit-test-app: use stripped config name in test case ID: We could split cases of same config into multiple binaries as we have limited rom space. So we should regard those configs like `default` and `default_2` as the same config. --- tools/unit-test-app/tools/UnitTestParser.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/tools/unit-test-app/tools/UnitTestParser.py b/tools/unit-test-app/tools/UnitTestParser.py index 0058a65741..cf94eb0ae1 100644 --- a/tools/unit-test-app/tools/UnitTestParser.py +++ b/tools/unit-test-app/tools/UnitTestParser.py @@ -43,6 +43,7 @@ class Parser(object): UT_CONFIG_FOLDER = os.path.join("tools", "unit-test-app", "configs") ELF_FILE = "unit-test-app.elf" SDKCONFIG_FILE = "sdkconfig" + STRIP_CONFIG_PATTERN = re.compile(r"(.+?)(_\d+)?$") def __init__(self, idf_path=os.getenv("IDF_PATH")): self.test_env_tags = {} @@ -73,6 +74,12 @@ class Parser(object): table = CreateSectionTable.SectionTable("section_table.tmp") tags = self.parse_tags(os.path.join(config_output_folder, self.SDKCONFIG_FILE)) test_cases = [] + + # we could split cases of same config into multiple binaries as we have limited rom space + # we should regard those configs like `default` and `default_2` as the same config + match = self.STRIP_CONFIG_PATTERN.match(config_name) + stripped_config_name = match.group(1) + with open("case_address.tmp", "rb") as f: for line in f: # process symbol table like: "3ffb4310 l O .dram0.data 00000018 test_desc_33$5010" @@ -87,17 +94,17 @@ class Parser(object): name = table.get_string("any", name_addr) desc = table.get_string("any", desc_addr) file_name = table.get_string("any", file_name_addr) - tc = self.parse_one_test_case(name, desc, file_name, config_name, tags) + tc = self.parse_one_test_case(name, desc, file_name, config_name, stripped_config_name, tags) # check if duplicated case names # we need to use it to select case, # if duplicated IDs, Unity could select incorrect case to run # and we need to check all cases no matter if it's going te be executed by CI # also add app_name here, we allow same case for different apps - if (tc["summary"] + config_name) in self.test_case_names: + if (tc["summary"] + stripped_config_name) in self.test_case_names: self.parsing_errors.append("duplicated test case ID: " + tc["summary"]) else: - self.test_case_names.add(tc["summary"] + config_name) + self.test_case_names.add(tc["summary"] + stripped_config_name) test_group_included = True if test_groups is not None and tc["group"] not in test_groups: @@ -226,13 +233,14 @@ class Parser(object): return match.group(1).split(' ') return None - def parse_one_test_case(self, name, description, file_name, config_name, tags): + def parse_one_test_case(self, name, description, file_name, config_name, stripped_config_name, tags): """ parse one test case :param name: test case name (summary) :param description: test case description (tag string) :param file_name: the file defines this test case :param config_name: built unit test app name + :param stripped_config_name: strip suffix from config name because they're the same except test components :param tags: tags to select runners :return: parsed test case """ @@ -243,7 +251,7 @@ class Parser(object): "module": self.module_map[prop["module"]]['module'], "group": prop["group"], "CI ready": "No" if prop["ignore"] == "Yes" else "Yes", - "ID": name, + "ID": "[{}] {}".format(stripped_config_name, name), "test point 2": prop["module"], "steps": name, "test environment": prop["test_env"], From 41062bea99a2289dd674b4bcbb2ebe97f1e94c6c Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Mon, 1 Jul 2019 11:08:57 +0200 Subject: [PATCH 303/486] VFS: Implement pread() and pwrite() Closes https://github.com/espressif/esp-idf/issues/3515 --- components/fatfs/test/test_fatfs_common.c | 84 +++++++++++++++++++++ components/fatfs/test/test_fatfs_common.h | 4 + components/fatfs/test/test_fatfs_sdmmc.c | 14 ++++ components/fatfs/test/test_fatfs_spiflash.c | 15 ++++ components/fatfs/vfs/vfs_fat.c | 82 ++++++++++++++++++++ components/newlib/CMakeLists.txt | 2 + components/newlib/pread.c | 21 ++++++ components/newlib/pwrite.c | 21 ++++++ components/vfs/include/esp_vfs.h | 37 +++++++++ components/vfs/vfs.c | 27 +++++++ 10 files changed, 307 insertions(+) create mode 100644 components/newlib/pread.c create mode 100644 components/newlib/pwrite.c diff --git a/components/fatfs/test/test_fatfs_common.c b/components/fatfs/test/test_fatfs_common.c index 77e53707c5..09e2938268 100644 --- a/components/fatfs/test/test_fatfs_common.c +++ b/components/fatfs/test/test_fatfs_common.c @@ -16,8 +16,10 @@ #include #include #include +#include #include #include +#include #include #include #include "unity.h" @@ -98,6 +100,88 @@ void test_fatfs_read_file_utf_8(const char* filename) TEST_ASSERT_EQUAL(0, fclose(f)); } +void test_fatfs_pread_file(const char* filename) +{ + char buf[32] = { 0 }; + const int fd = open(filename, O_RDONLY); + TEST_ASSERT_NOT_EQUAL(-1, fd); + + int r = pread(fd, buf, sizeof(buf), 0); // it is a regular read() with offset==0 + TEST_ASSERT_EQUAL(0, strcmp(fatfs_test_hello_str, buf)); + TEST_ASSERT_EQUAL(strlen(fatfs_test_hello_str), r); + + memset(buf, 0, sizeof(buf)); + r = pread(fd, buf, sizeof(buf), 1); // offset==1 + TEST_ASSERT_EQUAL(0, strcmp(fatfs_test_hello_str + 1, buf)); + TEST_ASSERT_EQUAL(strlen(fatfs_test_hello_str) - 1, r); + + memset(buf, 0, sizeof(buf)); + r = pread(fd, buf, sizeof(buf), 5); // offset==5 + TEST_ASSERT_EQUAL(0, strcmp(fatfs_test_hello_str + 5, buf)); + TEST_ASSERT_EQUAL(strlen(fatfs_test_hello_str) - 5, r); + + // regular read() should work now because pread() should not affect the current position in file + + memset(buf, 0, sizeof(buf)); + r = read(fd, buf, sizeof(buf)); // note that this is read() and not pread() + TEST_ASSERT_EQUAL(0, strcmp(fatfs_test_hello_str, buf)); + TEST_ASSERT_EQUAL(strlen(fatfs_test_hello_str), r); + + memset(buf, 0, sizeof(buf)); + r = pread(fd, buf, sizeof(buf), 10); // offset==10 + TEST_ASSERT_EQUAL(0, strcmp(fatfs_test_hello_str + 10, buf)); + TEST_ASSERT_EQUAL(strlen(fatfs_test_hello_str) - 10, r); + + memset(buf, 0, sizeof(buf)); + r = pread(fd, buf, sizeof(buf), strlen(fatfs_test_hello_str) + 1); // offset to EOF + TEST_ASSERT_EQUAL(0, r); + + TEST_ASSERT_EQUAL(0, close(fd)); +} + +static void test_pwrite(const char *filename, off_t offset, const char *msg) +{ + const int fd = open(filename, O_WRONLY); + TEST_ASSERT_NOT_EQUAL(-1, fd); + + const off_t current_pos = lseek(fd, 0, SEEK_END); // O_APPEND is not the same - jumps to the end only before write() + + const int r = pwrite(fd, msg, strlen(msg), offset); + TEST_ASSERT_EQUAL(strlen(msg), r); + + TEST_ASSERT_EQUAL(current_pos, lseek(fd, 0, SEEK_CUR)); // pwrite should not move the pointer + + TEST_ASSERT_EQUAL(0, close(fd)); +} + +static void test_file_content(const char *filename, const char *msg) +{ + char buf[32] = { 0 }; + const int fd = open(filename, O_RDONLY); + TEST_ASSERT_NOT_EQUAL(-1, fd); + + int r = read(fd, buf, sizeof(buf)); + TEST_ASSERT_NOT_EQUAL(-1, r); + TEST_ASSERT_EQUAL(0, strcmp(msg, buf)); + + TEST_ASSERT_EQUAL(0, close(fd)); +} + +void test_fatfs_pwrite_file(const char *filename) +{ + int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC); + TEST_ASSERT_NOT_EQUAL(-1, fd); + TEST_ASSERT_EQUAL(0, close(fd)); + + test_pwrite(filename, 0, "Hello"); + test_file_content(filename, "Hello"); + + test_pwrite(filename, strlen("Hello"), ", world!"); + test_file_content(filename, "Hello, world!"); + test_pwrite(filename, strlen("Hello, "), "Dolly"); + test_file_content(filename, "Hello, Dolly!"); +} + void test_fatfs_open_max_files(const char* filename_prefix, size_t files_count) { FILE** files = calloc(files_count, sizeof(FILE*)); diff --git a/components/fatfs/test/test_fatfs_common.h b/components/fatfs/test/test_fatfs_common.h index ba330b6b6b..0a792434b1 100644 --- a/components/fatfs/test/test_fatfs_common.h +++ b/components/fatfs/test/test_fatfs_common.h @@ -41,6 +41,10 @@ void test_fatfs_read_file(const char* filename); void test_fatfs_read_file_utf_8(const char* filename); +void test_fatfs_pread_file(const char* filename); + +void test_fatfs_pwrite_file(const char* filename); + void test_fatfs_open_max_files(const char* filename_prefix, size_t files_count); void test_fatfs_lseek(const char* filename); diff --git a/components/fatfs/test/test_fatfs_sdmmc.c b/components/fatfs/test/test_fatfs_sdmmc.c index b2df8f0105..50e1eb5a08 100644 --- a/components/fatfs/test/test_fatfs_sdmmc.c +++ b/components/fatfs/test/test_fatfs_sdmmc.c @@ -86,6 +86,20 @@ TEST_CASE("(SD) can read file", "[fatfs][test_env=UT_T1_SDMODE]") test_teardown(); } +TEST_CASE("(SD) can read file with pread()", "[fatfs][test_env=UT_T1_SDMODE]") +{ + test_setup(); + test_fatfs_create_file_with_text(test_filename, fatfs_test_hello_str); + test_fatfs_pread_file(test_filename); + test_teardown(); +} + +TEST_CASE("(SD) pwrite() works well", "[fatfs][test_env=UT_T1_SDMODE]") +{ + test_setup(); + test_fatfs_pwrite_file(test_filename); + test_teardown(); +} TEST_CASE("(SD) overwrite and append file", "[fatfs][sd][test_env=UT_T1_SDMODE]") { diff --git a/components/fatfs/test/test_fatfs_spiflash.c b/components/fatfs/test/test_fatfs_spiflash.c index 6c33559395..f848c31ca8 100644 --- a/components/fatfs/test/test_fatfs_spiflash.c +++ b/components/fatfs/test/test_fatfs_spiflash.c @@ -70,6 +70,21 @@ TEST_CASE("(WL) can read file", "[fatfs][wear_levelling]") test_teardown(); } +TEST_CASE("(WL) can read file with pread", "[fatfs][wear_levelling]") +{ + test_setup(); + test_fatfs_create_file_with_text("/spiflash/hello.txt", fatfs_test_hello_str); + test_fatfs_pread_file("/spiflash/hello.txt"); + test_teardown(); +} + +TEST_CASE("(WL) pwrite() works well", "[fatfs][wear_levelling]") +{ + test_setup(); + test_fatfs_pwrite_file("/spiflash/hello.txt"); + test_teardown(); +} + TEST_CASE("(WL) can open maximum number of files", "[fatfs][wear_levelling]") { size_t max_files = FOPEN_MAX - 3; /* account for stdin, stdout, stderr */ diff --git a/components/fatfs/vfs/vfs_fat.c b/components/fatfs/vfs/vfs_fat.c index 1ee2695903..511be8c56e 100644 --- a/components/fatfs/vfs/vfs_fat.c +++ b/components/fatfs/vfs/vfs_fat.c @@ -68,6 +68,8 @@ static const char* TAG = "vfs_fat"; static ssize_t vfs_fat_write(void* p, int fd, const void * data, size_t size); static off_t vfs_fat_lseek(void* p, int fd, off_t size, int mode); static ssize_t vfs_fat_read(void* ctx, int fd, void * dst, size_t size); +static ssize_t vfs_fat_pread(void *ctx, int fd, void *dst, size_t size, off_t offset); +static ssize_t vfs_fat_pwrite(void *ctx, int fd, const void *src, size_t size, off_t offset); static int vfs_fat_open(void* ctx, const char * path, int flags, int mode); static int vfs_fat_close(void* ctx, int fd); static int vfs_fat_fstat(void* ctx, int fd, struct stat * st); @@ -129,6 +131,8 @@ esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, siz .write_p = &vfs_fat_write, .lseek_p = &vfs_fat_lseek, .read_p = &vfs_fat_read, + .pread_p = &vfs_fat_pread, + .pwrite_p = &vfs_fat_pwrite, .open_p = &vfs_fat_open, .close_p = &vfs_fat_close, .fstat_p = &vfs_fat_fstat, @@ -373,6 +377,84 @@ static ssize_t vfs_fat_read(void* ctx, int fd, void * dst, size_t size) return read; } +static ssize_t vfs_fat_pread(void *ctx, int fd, void *dst, size_t size, off_t offset) +{ + ssize_t ret = -1; + vfs_fat_ctx_t *fat_ctx = (vfs_fat_ctx_t *) ctx; + _lock_acquire(&fat_ctx->lock); + FIL *file = &fat_ctx->files[fd]; + const off_t prev_pos = f_tell(file); + + FRESULT f_res = f_lseek(file, offset); + if (f_res != FR_OK) { + ESP_LOGD(TAG, "%s: fresult=%d", __func__, f_res); + errno = fresult_to_errno(f_res); + goto pread_release; + } + + unsigned read = 0; + f_res = f_read(file, dst, size, &read); + if (f_res == FR_OK) { + ret = read; + } else { + ESP_LOGD(TAG, "%s: fresult=%d", __func__, f_res); + errno = fresult_to_errno(f_res); + // No return yet - need to restore previous position + } + + f_res = f_lseek(file, prev_pos); + if (f_res != FR_OK) { + ESP_LOGD(TAG, "%s: fresult=%d", __func__, f_res); + if (ret >= 0) { + errno = fresult_to_errno(f_res); + } // else f_read failed so errno shouldn't be overwritten + ret = -1; // in case the read was successful but the seek wasn't + } + +pread_release: + _lock_release(&fat_ctx->lock); + return ret; +} + +static ssize_t vfs_fat_pwrite(void *ctx, int fd, const void *src, size_t size, off_t offset) +{ + ssize_t ret = -1; + vfs_fat_ctx_t *fat_ctx = (vfs_fat_ctx_t *) ctx; + _lock_acquire(&fat_ctx->lock); + FIL *file = &fat_ctx->files[fd]; + const off_t prev_pos = f_tell(file); + + FRESULT f_res = f_lseek(file, offset); + if (f_res != FR_OK) { + ESP_LOGD(TAG, "%s: fresult=%d", __func__, f_res); + errno = fresult_to_errno(f_res); + goto pwrite_release; + } + + unsigned wr = 0; + f_res = f_write(file, src, size, &wr); + if (f_res == FR_OK) { + ret = wr; + } else { + ESP_LOGD(TAG, "%s: fresult=%d", __func__, f_res); + errno = fresult_to_errno(f_res); + // No return yet - need to restore previous position + } + + f_res = f_lseek(file, prev_pos); + if (f_res != FR_OK) { + ESP_LOGD(TAG, "%s: fresult=%d", __func__, f_res); + if (ret >= 0) { + errno = fresult_to_errno(f_res); + } // else f_write failed so errno shouldn't be overwritten + ret = -1; // in case the write was successful but the seek wasn't + } + +pwrite_release: + _lock_release(&fat_ctx->lock); + return ret; +} + static int vfs_fat_fsync(void* ctx, int fd) { vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx; diff --git a/components/newlib/CMakeLists.txt b/components/newlib/CMakeLists.txt index 47b7c368b3..ccd5a76693 100644 --- a/components/newlib/CMakeLists.txt +++ b/components/newlib/CMakeLists.txt @@ -2,6 +2,8 @@ set(srcs "heap.c" "locks.c" "poll.c" + "pread.c" + "pwrite.c" "pthread.c" "random.c" "reent_init.c" diff --git a/components/newlib/pread.c b/components/newlib/pread.c new file mode 100644 index 0000000000..d14bd7257d --- /dev/null +++ b/components/newlib/pread.c @@ -0,0 +1,21 @@ +// Copyright 2019 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 +#include "esp_vfs.h" + +ssize_t pread(int fd, void *dst, size_t size, off_t offset) +{ + return esp_vfs_pread(fd, dst, size, offset); +} diff --git a/components/newlib/pwrite.c b/components/newlib/pwrite.c new file mode 100644 index 0000000000..78fd0b85ce --- /dev/null +++ b/components/newlib/pwrite.c @@ -0,0 +1,21 @@ +// Copyright 2019 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 +#include "esp_vfs.h" + +ssize_t pwrite(int fd, const void *src, size_t size, off_t offset) +{ + return esp_vfs_pwrite(fd, src, size, offset); +} diff --git a/components/vfs/include/esp_vfs.h b/components/vfs/include/esp_vfs.h index 3e711f2540..4d9396c1c4 100644 --- a/components/vfs/include/esp_vfs.h +++ b/components/vfs/include/esp_vfs.h @@ -112,6 +112,14 @@ typedef struct ssize_t (*read_p)(void* ctx, int fd, void * dst, size_t size); ssize_t (*read)(int fd, void * dst, size_t size); }; + union { + ssize_t (*pread_p)(void *ctx, int fd, void * dst, size_t size, off_t offset); + ssize_t (*pread)(int fd, void * dst, size_t size, off_t offset); + }; + union { + ssize_t (*pwrite_p)(void *ctx, int fd, const void *src, size_t size, off_t offset); + ssize_t (*pwrite)(int fd, const void *src, size_t size, off_t offset); + }; union { int (*open_p)(void* ctx, const char * path, int flags, int mode); int (*open)(const char * path, int flags, int mode); @@ -414,6 +422,35 @@ void esp_vfs_select_triggered_isr(esp_vfs_select_sem_t sem, BaseType_t *woken); */ int esp_vfs_poll(struct pollfd *fds, nfds_t nfds, int timeout); + +/** + * + * @brief Implements the VFS layer of POSIX pread() + * + * @param fd File descriptor used for read + * @param dst Pointer to the buffer where the output will be written + * @param size Number of bytes to be read + * @param offset Starting offset of the read + * + * @return A positive return value indicates the number of bytes read. -1 is return on failure and errno is + * set accordingly. + */ +ssize_t esp_vfs_pread(int fd, void *dst, size_t size, off_t offset); + +/** + * + * @brief Implements the VFS layer of POSIX pwrite() + * + * @param fd File descriptor used for write + * @param src Pointer to the buffer from where the output will be read + * @param size Number of bytes to write + * @param offset Starting offset of the write + * + * @return A positive return value indicates the number of bytes written. -1 is return on failure and errno is + * set accordingly. + */ +ssize_t esp_vfs_pwrite(int fd, const void *src, size_t size, off_t offset); + #ifdef __cplusplus } // extern "C" #endif diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index ecbaf6acf1..0fc5aead31 100644 --- a/components/vfs/vfs.c +++ b/components/vfs/vfs.c @@ -447,6 +447,33 @@ ssize_t esp_vfs_read(struct _reent *r, int fd, void * dst, size_t size) return ret; } +ssize_t esp_vfs_pread(int fd, void *dst, size_t size, off_t offset) +{ + struct _reent *r = __getreent(); + const vfs_entry_t* vfs = get_vfs_for_fd(fd); + const int local_fd = get_local_fd(vfs, fd); + if (vfs == NULL || local_fd < 0) { + __errno_r(r) = EBADF; + return -1; + } + ssize_t ret; + CHECK_AND_CALL(ret, r, vfs, pread, local_fd, dst, size, offset); + return ret; +} + +ssize_t esp_vfs_pwrite(int fd, const void *src, size_t size, off_t offset) +{ + struct _reent *r = __getreent(); + const vfs_entry_t* vfs = get_vfs_for_fd(fd); + const int local_fd = get_local_fd(vfs, fd); + if (vfs == NULL || local_fd < 0) { + __errno_r(r) = EBADF; + return -1; + } + ssize_t ret; + CHECK_AND_CALL(ret, r, vfs, pwrite, local_fd, src, size, offset); + return ret; +} int esp_vfs_close(struct _reent *r, int fd) { From 6c865a84ff729e3f94933b94241c9544a444aee2 Mon Sep 17 00:00:00 2001 From: xiehang Date: Fri, 5 Jul 2019 10:27:20 +0800 Subject: [PATCH 304/486] 1, Fix wps memory leak. 2, Add a queue to save wps rx eapol frame. 3, Add data lock protect wpa2_sig_cnt. 4, Add a queue to save wpa2 rx rapol frame. --- .../src/esp_supplicant/esp_wpa2.c | 89 +++++++++++++++++-- .../src/esp_supplicant/esp_wps.c | 77 +++++++++++++--- 2 files changed, 145 insertions(+), 21 deletions(-) diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c index a79502a1df..de7a3552a8 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c @@ -48,6 +48,11 @@ #define WPA2_VERSION "v2.0" +#define DATA_MUTEX_TAKE() xSemaphoreTakeRecursive(s_wpa2_data_lock,portMAX_DELAY) +#define DATA_MUTEX_GIVE() xSemaphoreGiveRecursive(s_wpa2_data_lock) + +static void *s_wpa2_data_lock = NULL; + static struct eap_sm *gEapSm = NULL; static int eap_peer_sm_init(void); @@ -134,7 +139,48 @@ struct wpa2_rx_param { u8 sa[WPA_ADDR_LEN]; u8 *buf; int len; + STAILQ_ENTRY(wpa2_rx_param) bqentry; }; +static STAILQ_HEAD(, wpa2_rx_param) s_wpa2_rxq; + +static void wpa2_rxq_init(void) +{ + DATA_MUTEX_TAKE(); + STAILQ_INIT(&s_wpa2_rxq); + DATA_MUTEX_GIVE(); +} + +static void wpa2_rxq_enqueue(struct wpa2_rx_param *param) +{ + DATA_MUTEX_TAKE(); + STAILQ_INSERT_TAIL(&s_wpa2_rxq,param, bqentry); + DATA_MUTEX_GIVE(); +} + +static struct wpa2_rx_param * wpa2_rxq_dequeue(void) +{ + struct wpa2_rx_param *param = NULL; + DATA_MUTEX_TAKE(); + if ((param = STAILQ_FIRST(&s_wpa2_rxq)) != NULL) { + STAILQ_REMOVE_HEAD(&s_wpa2_rxq, bqentry); + STAILQ_NEXT(param,bqentry) = NULL; + } + DATA_MUTEX_GIVE(); + return param; +} + +static void wpa2_rxq_deinit(void) +{ + struct wpa2_rx_param *param = NULL; + DATA_MUTEX_TAKE(); + while ((param = STAILQ_FIRST(&s_wpa2_rxq)) != NULL) { + STAILQ_REMOVE_HEAD(&s_wpa2_rxq, bqentry); + STAILQ_NEXT(param,bqentry) = NULL; + os_free(param->buf); + os_free(param); + } + DATA_MUTEX_GIVE(); +} void wpa2_task(void *pvParameters ) { @@ -150,20 +196,26 @@ void wpa2_task(void *pvParameters ) for (;;) { if ( pdPASS == xQueueReceive(s_wpa2_queue, &e, portMAX_DELAY) ) { sig = e->sig; + if (e->sig < SIG_WPA2_MAX) { + DATA_MUTEX_TAKE(); + if(sm->wpa2_sig_cnt[e->sig]) { + sm->wpa2_sig_cnt[e->sig]--; + } else { + wpa_printf(MSG_ERROR, "wpa2_task: invalid sig cnt, sig=%d cnt=%d", e->sig, sm->wpa2_sig_cnt[e->sig]); + } + DATA_MUTEX_GIVE(); + } switch (e->sig) { case SIG_WPA2_TASK_DEL: task_del = true; break; case SIG_WPA2_START: - sm->wpa2_sig_cnt[e->sig]--; wpa2_start_eapol_internal(); break; case SIG_WPA2_RX: { - struct wpa2_rx_param *param; + struct wpa2_rx_param *param = NULL; - sm->wpa2_sig_cnt[e->sig]--; - param = (struct wpa2_rx_param *)(e->par); - if (param) { + while ((param = wpa2_rxq_dequeue()) != NULL){ wpa2_sm_rx_eapol_internal(param->sa, param->buf, param->len, param->bssid); os_free(param->buf); os_free(param); @@ -211,15 +263,19 @@ int wpa2_post(uint32_t sig, uint32_t par) return ESP_FAIL; } + DATA_MUTEX_TAKE(); if (sm->wpa2_sig_cnt[sig]) { + DATA_MUTEX_GIVE(); return ESP_OK; } else { ETSEvent *evt = (ETSEvent *)os_malloc(sizeof(ETSEvent)); if (evt == NULL) { wpa_printf(MSG_ERROR, "WPA2: E N M\n"); + DATA_MUTEX_GIVE(); return ESP_FAIL; } sm->wpa2_sig_cnt[sig]++; + DATA_MUTEX_GIVE(); evt->sig = sig; evt->par = par; if ( xQueueSend(s_wpa2_queue, &evt, 10 / portTICK_PERIOD_MS ) != pdPASS) { @@ -302,8 +358,8 @@ void wpa2_sm_free_eapol(u8 *buffer) { if (buffer != NULL) { buffer = buffer - sizeof(struct l2_ethhdr); + os_free(buffer); } - os_free(buffer); } @@ -480,7 +536,8 @@ static int wpa2_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid) param->len = len; memcpy(param->sa, src_addr, WPA_ADDR_LEN); - return wpa2_post(SIG_WPA2_RX, (uint32_t)param); + wpa2_rxq_enqueue(param); + return wpa2_post(SIG_WPA2_RX, 0); } #else @@ -656,6 +713,12 @@ static int eap_peer_sm_init(void) return ESP_ERR_NO_MEM; } + s_wpa2_data_lock = xSemaphoreCreateRecursiveMutex(); + if (!s_wpa2_data_lock) { + wpa_printf(MSG_ERROR, "wpa2 eap_peer_sm_init: failed to alloc data lock"); + return ESP_ERR_NO_MEM; + } + wpa2_set_eap_state(WPA2_ENT_EAP_STATE_NOT_START); sm->current_identifier = 0xff; esp_wifi_get_macaddr_internal(WIFI_IF_STA, sm->ownaddr); @@ -684,6 +747,7 @@ static int eap_peer_sm_init(void) return ESP_FAIL; } + wpa2_rxq_init(); gEapSm = sm; #ifdef USE_WPA2_TASK @@ -724,11 +788,22 @@ static void eap_peer_sm_deinit(void) #ifdef USE_WPA2_TASK wpa2_task_delete(0); #endif + + if (STAILQ_FIRST((&s_wpa2_rxq)) != NULL) { + wpa2_rxq_deinit(); + } + if (s_wifi_wpa2_sync_sem) { vSemaphoreDelete(s_wifi_wpa2_sync_sem); } s_wifi_wpa2_sync_sem = NULL; + if (s_wpa2_data_lock) { + vSemaphoreDelete(s_wpa2_data_lock); + s_wpa2_data_lock = NULL; + wpa_printf(MSG_DEBUG, "wpa2 eap_peer_sm_deinit: free data lock"); + } + os_free(sm); gEapSm = NULL; } diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wps.c b/components/wpa_supplicant/src/esp_supplicant/esp_wps.c index 03ed6e8587..c666de3059 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wps.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wps.c @@ -52,7 +52,9 @@ struct wps_rx_param { u8 sa[WPS_ADDR_LEN]; u8 *buf; int len; + STAILQ_ENTRY(wps_rx_param) bqentry; }; +static STAILQ_HEAD(,wps_rx_param) s_wps_rxq; typedef struct { void *arg; @@ -111,6 +113,45 @@ int wps_set_status(uint32_t status) return esp_wifi_set_wps_status_internal(status); } +static void wps_rxq_init(void) +{ + DATA_MUTEX_TAKE(); + STAILQ_INIT(&s_wps_rxq); + DATA_MUTEX_GIVE(); +} + +static void wps_rxq_enqueue(struct wps_rx_param *param) +{ + DATA_MUTEX_TAKE(); + STAILQ_INSERT_TAIL(&s_wps_rxq,param, bqentry); + DATA_MUTEX_GIVE(); +} + +static struct wps_rx_param * wps_rxq_dequeue(void) +{ + struct wps_rx_param *param = NULL; + DATA_MUTEX_TAKE(); + if ((param = STAILQ_FIRST(&s_wps_rxq)) != NULL) { + STAILQ_REMOVE_HEAD(&s_wps_rxq, bqentry); + STAILQ_NEXT(param,bqentry) = NULL; + } + DATA_MUTEX_GIVE(); + return param; +} + +static void wps_rxq_deinit(void) +{ + struct wps_rx_param *param = NULL; + DATA_MUTEX_TAKE(); + while ((param = STAILQ_FIRST(&s_wps_rxq)) != NULL) { + STAILQ_REMOVE_HEAD(&s_wps_rxq, bqentry); + STAILQ_NEXT(param,bqentry) = NULL; + os_free(param->buf); + os_free(param); + } + DATA_MUTEX_GIVE(); +} + #ifdef USE_WPS_TASK void wps_task(void *pvParameters ) { @@ -161,10 +202,8 @@ void wps_task(void *pvParameters ) break; case SIG_WPS_RX: { - struct wps_rx_param *param; - - param = (struct wps_rx_param *)(e->par); - if (param) { + struct wps_rx_param *param = NULL; + while ((param = wps_rxq_dequeue()) != NULL) { wps_sm_rx_eapol_internal(param->sa, param->buf, param->len); os_free(param->buf); os_free(param); @@ -311,9 +350,10 @@ u8 *wps_sm_alloc_eapol(struct wps_sm *sm, u8 type, void wps_sm_free_eapol(u8 *buffer) { - buffer = buffer - sizeof(struct l2_ethhdr); - os_free(buffer); - + if (buffer != NULL) { + buffer = buffer - sizeof(struct l2_ethhdr); + os_free(buffer); + } } @@ -658,6 +698,7 @@ int wps_send_frag_ack(u8 id) } ret = wps_sm_ether_send(sm, bssid, ETH_P_EAPOL, buf, len); + wps_sm_free_eapol(buf); if (ret) { ret = ESP_ERR_NO_MEM; goto _err; @@ -835,6 +876,7 @@ int wps_send_wps_mX_rsp(u8 id) } ret = wps_sm_ether_send(sm, bssid, ETH_P_EAPOL, buf, len); + wps_sm_free_eapol(buf); if (ret) { ret = ESP_FAIL; goto _err; @@ -1055,7 +1097,8 @@ int wps_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len) param->len = len; memcpy(param->sa, src_addr, WPS_ADDR_LEN); - return wps_post(SIG_WPS_RX, (uint32_t)param); + wps_rxq_enqueue(param); + return wps_post(SIG_WPS_RX, 0); } #else return wps_sm_rx_eapol_internal(src_addr, buf, len); @@ -1828,12 +1871,6 @@ int wps_task_deinit(void) { wpa_printf(MSG_DEBUG, "wps task deinit"); - if (s_wps_data_lock) { - vSemaphoreDelete(s_wps_data_lock); - s_wps_data_lock = NULL; - wpa_printf(MSG_DEBUG, "wps task deinit: free data lock"); - } - if (s_wps_api_sem) { vSemaphoreDelete(s_wps_api_sem); s_wps_api_sem = NULL; @@ -1858,6 +1895,16 @@ int wps_task_deinit(void) wpa_printf(MSG_DEBUG, "wps task deinit: free task"); } + if (STAILQ_FIRST(&s_wps_rxq) != NULL){ + wps_rxq_deinit(); + } + + if (s_wps_data_lock) { + vSemaphoreDelete(s_wps_data_lock); + s_wps_data_lock = NULL; + wpa_printf(MSG_DEBUG, "wps task deinit: free data lock"); + } + return ESP_OK; } @@ -1894,6 +1941,8 @@ int wps_task_init(void) goto _wps_no_mem; } + wps_rxq_init(); + ret = xTaskCreate(wps_task, "wpsT", WPS_TASK_STACK_SIZE, NULL, 2, &s_wps_task_hdl); if (pdPASS != ret) { wpa_printf(MSG_ERROR, "wps enable: failed to create task"); From 0f27c38855ef470374d8e6e20ecca3dc230d6086 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 12 Jul 2019 11:09:00 +1000 Subject: [PATCH 305/486] docs: Add notes about thread safety and using heap from ISRs Closes https://github.com/espressif/esp-idf/issues/3768 --- docs/en/api-reference/system/mem_alloc.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/en/api-reference/system/mem_alloc.rst b/docs/en/api-reference/system/mem_alloc.rst index cf6eb5020d..d2e5222f40 100644 --- a/docs/en/api-reference/system/mem_alloc.rst +++ b/docs/en/api-reference/system/mem_alloc.rst @@ -113,6 +113,13 @@ API Reference - Heap Allocation .. include:: /_build/inc/esp_heap_caps.inc +Thread Safety +^^^^^^^^^^^^^ + +Heap functions are thread safe, meaning they can be called from different tasks simultaneously without any limitations. + +It is technically possible to call ``malloc``, ``free``, and related functions from interrupt handler (ISR) context. However this is not recommended, as heap function calls may delay other interrupts. It is strongly recommended to refactor applications so that any buffers used by an ISR are pre-allocated outside of the ISR. Support for calling heap functions from ISRs may be removed in a future update. + Heap Tracing & Debugging ------------------------ From 8795f1ac866dad5e656f714cd0c159f7923a3ea7 Mon Sep 17 00:00:00 2001 From: Ramesh <38435057+rmshub@users.noreply.github.com> Date: Wed, 10 Jul 2019 08:55:36 +0530 Subject: [PATCH 306/486] Fixed the bug that the malloc memory size is smaller than the actual required. Merges https://github.com/espressif/esp-idf/pull/3757 --- .../mcpwm_basic_config/main/mcpwm_basic_config_example.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/peripherals/mcpwm/mcpwm_basic_config/main/mcpwm_basic_config_example.c b/examples/peripherals/mcpwm/mcpwm_basic_config/main/mcpwm_basic_config_example.c index 58fe18889a..7853c14905 100644 --- a/examples/peripherals/mcpwm/mcpwm_basic_config/main/mcpwm_basic_config_example.c +++ b/examples/peripherals/mcpwm/mcpwm_basic_config/main/mcpwm_basic_config_example.c @@ -137,8 +137,8 @@ static void gpio_test_signal(void *arg) */ static void disp_captured_signal(void *arg) { - uint32_t *current_cap_value = (uint32_t *)malloc(sizeof(CAP_SIG_NUM)); - uint32_t *previous_cap_value = (uint32_t *)malloc(sizeof(CAP_SIG_NUM)); + uint32_t *current_cap_value = (uint32_t *)malloc(CAP_SIG_NUM*sizeof(uint32_t)); + uint32_t *previous_cap_value = (uint32_t *)malloc(CAP_SIG_NUM*sizeof(uint32_t)); capture evt; while (1) { xQueueReceive(cap_queue, &evt, portMAX_DELAY); From 1dec976fba8c00ef25b519370d1990573abd4194 Mon Sep 17 00:00:00 2001 From: "hemal.gujarathi" Date: Wed, 26 Jun 2019 15:21:30 +0530 Subject: [PATCH 307/486] Update esp_config and add new feature Closes https://github.com/espressif/esp-idf/issues/3372 --- components/mbedtls/port/esp32/aes.c | 44 + components/mbedtls/port/include/aes_alt.h | 3 + components/mbedtls/port/include/esp32/aes.h | 25 + .../mbedtls/port/include/mbedtls/config.h | 9 - .../mbedtls/port/include/mbedtls/esp_config.h | 930 +++++------------- 5 files changed, 323 insertions(+), 688 deletions(-) delete mode 100644 components/mbedtls/port/include/mbedtls/config.h diff --git a/components/mbedtls/port/esp32/aes.c b/components/mbedtls/port/esp32/aes.c index 0cf6c4257d..3925f13e47 100644 --- a/components/mbedtls/port/esp32/aes.c +++ b/components/mbedtls/port/esp32/aes.c @@ -408,6 +408,50 @@ int esp_aes_crypt_ctr( esp_aes_context *ctx, return 0; } +/* + * AES-OFB (Output Feedback Mode) buffer encryption/decryption + */ +int esp_aes_crypt_ofb( esp_aes_context *ctx, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int ret = 0; + size_t n; + + if ( ctx == NULL || iv_off == NULL || iv == NULL || + input == NULL || output == NULL ) { + return MBEDTLS_ERR_AES_BAD_INPUT_DATA; + } + + n = *iv_off; + + if( n > 15 ) { + return( MBEDTLS_ERR_AES_BAD_INPUT_DATA ); + } + + esp_aes_acquire_hardware(); + + esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); + + while( length-- ) { + if( n == 0 ) { + esp_aes_block( iv, iv ); + } + *output++ = *input++ ^ iv[n]; + + n = ( n + 1 ) & 0x0F; + } + + *iv_off = n; + + esp_aes_release_hardware(); + + return( ret ); +} + /* Below XTS implementation is copied aes.c of mbedtls library. * When MBEDTLS_AES_ALT is defined mbedtls expects alternate * definition of XTS functions to be available. Even if this diff --git a/components/mbedtls/port/include/aes_alt.h b/components/mbedtls/port/include/aes_alt.h index 2f6813729d..993d0689e3 100644 --- a/components/mbedtls/port/include/aes_alt.h +++ b/components/mbedtls/port/include/aes_alt.h @@ -47,6 +47,9 @@ typedef esp_aes_context mbedtls_aes_context; #if defined(MBEDTLS_CIPHER_MODE_CTR) #define mbedtls_aes_crypt_ctr esp_aes_crypt_ctr #endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) +#define mbedtls_aes_crypt_ofb esp_aes_crypt_ofb +#endif #if defined(MBEDTLS_CIPHER_MODE_XTS) typedef esp_aes_xts_context mbedtls_aes_xts_context; #define mbedtls_aes_xts_init esp_aes_xts_init diff --git a/components/mbedtls/port/include/esp32/aes.h b/components/mbedtls/port/include/esp32/aes.h index 6f5c1ff54e..962e148066 100644 --- a/components/mbedtls/port/include/esp32/aes.h +++ b/components/mbedtls/port/include/esp32/aes.h @@ -281,6 +281,31 @@ int esp_aes_xts_setkey_enc( esp_aes_xts_context *ctx, const unsigned char *key, unsigned int keybits ); +/** + * \brief This function performs an AES-OFB (Output Feedback Mode) + * encryption or decryption operation. + * + * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. + * \param length The length of the input data. + * \param iv_off The offset in IV (updated after use). + * It must point to a valid \c size_t. + * \param iv The initialization vector (updated after use). + * It must be a readable and writeable buffer of \c 16 Bytes. + * \param input The buffer holding the input data. + * It must be readable and of size \p length Bytes. + * \param output The buffer holding the output data. + * It must be writeable and of size \p length Bytes. + * + * \return \c 0 on success. + */ +int esp_aes_crypt_ofb( esp_aes_context *ctx, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + /** * \brief This function prepares an XTS context for decryption and * sets the decryption key. diff --git a/components/mbedtls/port/include/mbedtls/config.h b/components/mbedtls/port/include/mbedtls/config.h deleted file mode 100644 index cf3d904de0..0000000000 --- a/components/mbedtls/port/include/mbedtls/config.h +++ /dev/null @@ -1,9 +0,0 @@ -/* This shim header is added so that any application code - which includes "mbedtls/config.h" directly gets the correct - config. */ -#pragma once -#if !defined(MBEDTLS_CONFIG_FILE) -#include_next "mbedtls/config.h" -#else -#include MBEDTLS_CONFIG_FILE -#endif diff --git a/components/mbedtls/port/include/mbedtls/esp_config.h b/components/mbedtls/port/include/mbedtls/esp_config.h index 40ae3ae368..bdb9bf61a7 100644 --- a/components/mbedtls/port/include/mbedtls/esp_config.h +++ b/components/mbedtls/port/include/mbedtls/esp_config.h @@ -24,14 +24,11 @@ * This file is part of mbed TLS (https://tls.mbed.org) */ -#ifndef MBEDTLS_CONFIG_H -#define MBEDTLS_CONFIG_H +#ifndef ESP_CONFIG_H +#define ESP_CONFIG_H #include "sdkconfig.h" - -#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) -#define _CRT_SECURE_NO_DEPRECATE 1 -#endif +#include "mbedtls/config.h" /** * \name SECTION: System support @@ -40,31 +37,6 @@ * \{ */ -/** - * \def MBEDTLS_HAVE_ASM - * - * The compiler has support for asm(). - * - * Requires support for asm() in compiler. - * - * Used in: - * library/timing.c - * library/padlock.c - * include/mbedtls/bn_mul.h - * - * Comment to disable the use of assembly code. - */ -#define MBEDTLS_HAVE_ASM - -/** - * \def MBEDTLS_HAVE_SSE2 - * - * CPU supports SSE2 instruction set. - * - * Uncomment if the CPU supports SSE2 (IA-32 specific). - */ -//#define MBEDTLS_HAVE_SSE2 - /** * \def MBEDTLS_HAVE_TIME * @@ -76,6 +48,8 @@ */ #ifdef CONFIG_MBEDTLS_HAVE_TIME #define MBEDTLS_HAVE_TIME +#else +#undef MBEDTLS_HAVE_TIME #endif /** @@ -90,6 +64,8 @@ */ #ifdef CONFIG_MBEDTLS_HAVE_TIME_DATE #define MBEDTLS_HAVE_TIME_DATE +#else +#undef MBEDTLS_HAVE_TIME_DATE #endif /** @@ -123,78 +99,6 @@ #define MBEDTLS_PLATFORM_STD_FREE esp_mbedtls_mem_free #endif -/** - * \def MBEDTLS_PLATFORM_NO_STD_FUNCTIONS - * - * Do not assign standard functions in the platform layer (e.g. calloc() to - * MBEDTLS_PLATFORM_STD_CALLOC and printf() to MBEDTLS_PLATFORM_STD_PRINTF) - * - * This makes sure there are no linking errors on platforms that do not support - * these functions. You will HAVE to provide alternatives, either at runtime - * via the platform_set_xxx() functions or at compile time by setting - * the MBEDTLS_PLATFORM_STD_XXX defines, or enabling a - * MBEDTLS_PLATFORM_XXX_MACRO. - * - * Requires: MBEDTLS_PLATFORM_C - * - * Uncomment to prevent default assignment of standard functions in the - * platform layer. - */ -//#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS - -/** - * \def MBEDTLS_PLATFORM_EXIT_ALT - * - * MBEDTLS_PLATFORM_XXX_ALT: Uncomment a macro to let mbed TLS support the - * function in the platform abstraction layer. - * - * Example: In case you uncomment MBEDTLS_PLATFORM_PRINTF_ALT, mbed TLS will - * provide a function "mbedtls_platform_set_printf()" that allows you to set an - * alternative printf function pointer. - * - * All these define require MBEDTLS_PLATFORM_C to be defined! - * - * \note MBEDTLS_PLATFORM_SNPRINTF_ALT is required on Windows; - * it will be enabled automatically by check_config.h - * - * \warning MBEDTLS_PLATFORM_XXX_ALT cannot be defined at the same time as - * MBEDTLS_PLATFORM_XXX_MACRO! - * - * Uncomment a macro to enable alternate implementation of specific base - * platform function - */ -//#define MBEDTLS_PLATFORM_EXIT_ALT -//#define MBEDTLS_PLATFORM_FPRINTF_ALT -//#define MBEDTLS_PLATFORM_PRINTF_ALT -//#define MBEDTLS_PLATFORM_SNPRINTF_ALT - -/** - * \def MBEDTLS_DEPRECATED_WARNING - * - * Mark deprecated functions so that they generate a warning if used. - * Functions deprecated in one version will usually be removed in the next - * version. You can enable this to help you prepare the transition to a new - * major version by making sure your code is not using these functions. - * - * This only works with GCC and Clang. With other compilers, you may want to - * use MBEDTLS_DEPRECATED_REMOVED - * - * Uncomment to get warnings on using deprecated functions. - */ -//#define MBEDTLS_DEPRECATED_WARNING - -/** - * \def MBEDTLS_DEPRECATED_REMOVED - * - * Remove deprecated functions so that they generate an error if used. - * Functions deprecated in one version will usually be removed in the next - * version. You can enable this to help you prepare the transition to a new - * major version by making sure your code is not using these functions. - * - * Uncomment to get errors on using deprecated functions. - */ -//#define MBEDTLS_DEPRECATED_REMOVED - /* \} name SECTION: System support */ /** @@ -205,53 +109,13 @@ * \{ */ -/** - * \def MBEDTLS_TIMING_ALT - * - * Uncomment to provide your own alternate implementation for mbedtls_timing_hardclock(), - * mbedtls_timing_get_timer(), mbedtls_set_alarm(), mbedtls_set/get_delay() - * - * Only works if you have MBEDTLS_TIMING_C enabled. - * - * You will need to provide a header "timing_alt.h" and an implementation at - * compile time. - */ -//#define MBEDTLS_TIMING_ALT - -/** - * \def MBEDTLS_AES_ALT - * - * MBEDTLS__MODULE_NAME__ALT: Uncomment a macro to let mbed TLS use your - * alternate core implementation of a symmetric crypto or hash module (e.g. - * platform specific assembly optimized implementations). Keep in mind that - * the function prototypes should remain the same. - * - * This replaces the whole module. If you only want to replace one of the - * functions, use one of the MBEDTLS__FUNCTION_NAME__ALT flags. - * - * Example: In case you uncomment MBEDTLS_AES_ALT, mbed TLS will no longer - * provide the "struct mbedtls_aes_context" definition and omit the base function - * declarations and implementations. "aes_alt.h" will be included from - * "aes.h" to include the new function definitions. - * - * Uncomment a macro to enable alternate implementation of the corresponding - * module. - */ -//#define MBEDTLS_ARC4_ALT -//#define MBEDTLS_BLOWFISH_ALT -//#define MBEDTLS_CAMELLIA_ALT -//#define MBEDTLS_DES_ALT -//#define MBEDTLS_XTEA_ALT -//#define MBEDTLS_MD2_ALT -//#define MBEDTLS_MD4_ALT -//#define MBEDTLS_MD5_ALT -//#define MBEDTLS_RIPEMD160_ALT - /* The following units have ESP32 hardware support, uncommenting each _ALT macro will use the hardware-accelerated implementation. */ #ifdef CONFIG_MBEDTLS_HARDWARE_AES #define MBEDTLS_AES_ALT +#else +#undef MBEDTLS_AES_ALT #endif /* MBEDTLS_SHAxx_ALT to enable hardware SHA support @@ -261,6 +125,10 @@ #define MBEDTLS_SHA1_ALT #define MBEDTLS_SHA256_ALT #define MBEDTLS_SHA512_ALT +#else +#undef MBEDTLS_SHA1_ALT +#undef MBEDTLS_SHA256_ALT +#undef MBEDTLS_SHA512_ALT #endif /* The following MPI (bignum) functions have ESP32 hardware support, @@ -270,46 +138,11 @@ #ifdef CONFIG_MBEDTLS_HARDWARE_MPI #define MBEDTLS_MPI_EXP_MOD_ALT #define MBEDTLS_MPI_MUL_MPI_ALT +#else +#undef MBEDTLS_MPI_EXP_MOD_ALT +#undef MBEDTLS_MPI_MUL_MPI_ALT #endif -/** - * \def MBEDTLS_MD2_PROCESS_ALT - * - * MBEDTLS__FUNCTION_NAME__ALT: Uncomment a macro to let mbed TLS use you - * alternate core implementation of symmetric crypto or hash function. Keep in - * mind that function prototypes should remain the same. - * - * This replaces only one function. The header file from mbed TLS is still - * used, in contrast to the MBEDTLS__MODULE_NAME__ALT flags. - * - * Example: In case you uncomment MBEDTLS_SHA256_PROCESS_ALT, mbed TLS will - * no longer provide the mbedtls_sha1_process() function, but it will still provide - * the other function (using your mbedtls_sha1_process() function) and the definition - * of mbedtls_sha1_context, so your implementation of mbedtls_sha1_process must be compatible - * with this definition. - * - * Note: if you use the AES_xxx_ALT macros, then is is recommended to also set - * MBEDTLS_AES_ROM_TABLES in order to help the linker garbage-collect the AES - * tables. - * - * Uncomment a macro to enable alternate implementation of the corresponding - * function. - */ -//#define MBEDTLS_MD2_PROCESS_ALT -//#define MBEDTLS_MD4_PROCESS_ALT -//#define MBEDTLS_MD5_PROCESS_ALT -//#define MBEDTLS_RIPEMD160_PROCESS_ALT -//#define MBEDTLS_SHA1_PROCESS_ALT -//#define MBEDTLS_SHA256_PROCESS_ALT -//#define MBEDTLS_SHA512_PROCESS_ALT -//#define MBEDTLS_DES_SETKEY_ALT -//#define MBEDTLS_DES_CRYPT_ECB_ALT -//#define MBEDTLS_DES3_CRYPT_ECB_ALT -//#define MBEDTLS_AES_SETKEY_ENC_ALT -//#define MBEDTLS_AES_SETKEY_DEC_ALT -//#define MBEDTLS_AES_ENCRYPT_ALT -//#define MBEDTLS_AES_DECRYPT_ALT - /** * \def MBEDTLS_ENTROPY_HARDWARE_ALT * @@ -332,15 +165,6 @@ */ #define MBEDTLS_AES_ROM_TABLES -/** - * \def MBEDTLS_CAMELLIA_SMALL_MEMORY - * - * Use less ROM for the Camellia implementation (saves about 768 bytes). - * - * Uncomment this macro to use less memory for Camellia. - */ -//#define MBEDTLS_CAMELLIA_SMALL_MEMORY - /** * \def MBEDTLS_CIPHER_MODE_CBC * @@ -362,6 +186,13 @@ */ #define MBEDTLS_CIPHER_MODE_CTR +/** + * \def MBEDTLS_CIPHER_MODE_OFB + * + * Enable Output Feedback mode (OFB) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_OFB + /** * \def MBEDTLS_CIPHER_MODE_XTS * @@ -369,39 +200,6 @@ */ #define MBEDTLS_CIPHER_MODE_XTS -/** - * \def MBEDTLS_CIPHER_NULL_CIPHER - * - * Enable NULL cipher. - * Warning: Only do so when you know what you are doing. This allows for - * encryption or channels without any security! - * - * Requires MBEDTLS_ENABLE_WEAK_CIPHERSUITES as well to enable - * the following ciphersuites: - * MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA - * MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA - * MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA - * MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA - * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384 - * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256 - * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA - * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384 - * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256 - * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA - * MBEDTLS_TLS_RSA_WITH_NULL_SHA256 - * MBEDTLS_TLS_RSA_WITH_NULL_SHA - * MBEDTLS_TLS_RSA_WITH_NULL_MD5 - * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384 - * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256 - * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA - * MBEDTLS_TLS_PSK_WITH_NULL_SHA384 - * MBEDTLS_TLS_PSK_WITH_NULL_SHA256 - * MBEDTLS_TLS_PSK_WITH_NULL_SHA - * - * Uncomment this macro to enable the NULL cipher and ciphersuites - */ -//#define MBEDTLS_CIPHER_NULL_CIPHER - /** * \def MBEDTLS_CIPHER_PADDING_PKCS7 * @@ -419,24 +217,24 @@ #define MBEDTLS_CIPHER_PADDING_ZEROS /** - * \def MBEDTLS_ENABLE_WEAK_CIPHERSUITES + * \def MBEDTLS_REMOVE_ARC4_CIPHERSUITES & MBEDTLS_ARC4_C + * + * MBEDTLS_ARC4_C + * Enable the ARCFOUR stream cipher. * - * Enable weak ciphersuites in SSL / TLS. - * Warning: Only do so when you know what you are doing. This allows for - * channels with virtually no security at all! + * This module enables/disables the following ciphersuites + * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 + * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA * - * This enables the following ciphersuites: - * MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA - * MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA - * - * Uncomment this macro to enable weak ciphersuites - */ -//#define MBEDTLS_ENABLE_WEAK_CIPHERSUITES - -/** - * \def MBEDTLS_REMOVE_ARC4_CIPHERSUITES - * - * Remove RC4 ciphersuites by default in SSL / TLS. + * MBEDTLS_REMOVE_ARC4_CIPHERSUITES * This flag removes the ciphersuites based on RC4 from the default list as * returned by mbedtls_ssl_list_ciphersuites(). However, it is still possible to * enable (some of) them with mbedtls_ssl_conf_ciphersuites() by including them @@ -445,6 +243,13 @@ * Uncomment this macro to remove RC4 ciphersuites by default. */ #ifdef CONFIG_MBEDTLS_RC4_ENABLED +#define MBEDTLS_ARC4_C +#undef MBEDTLS_REMOVE_ARC4_CIPHERSUITES +#elif defined CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT +#define MBEDTLS_ARC4_C +#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES +#else +#undef MBEDTLS_ARC4_C #define MBEDTLS_REMOVE_ARC4_CIPHERSUITES #endif @@ -458,39 +263,67 @@ */ #ifdef CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED #define MBEDTLS_ECP_DP_SECP192R1_ENABLED +#else +#undef MBEDTLS_ECP_DP_SECP192R1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED #define MBEDTLS_ECP_DP_SECP224R1_ENABLED +#else +#undef MBEDTLS_ECP_DP_SECP224R1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED #define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#else +#undef MBEDTLS_ECP_DP_SECP256R1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED #define MBEDTLS_ECP_DP_SECP384R1_ENABLED +#else +#undef MBEDTLS_ECP_DP_SECP384R1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED #define MBEDTLS_ECP_DP_SECP521R1_ENABLED +#else +#undef MBEDTLS_ECP_DP_SECP521R1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED #define MBEDTLS_ECP_DP_SECP192K1_ENABLED +#else +#undef MBEDTLS_ECP_DP_SECP192K1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED #define MBEDTLS_ECP_DP_SECP224K1_ENABLED +#else +#undef MBEDTLS_ECP_DP_SECP224K1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED #define MBEDTLS_ECP_DP_SECP256K1_ENABLED +#else +#undef MBEDTLS_ECP_DP_SECP256K1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED #define MBEDTLS_ECP_DP_BP256R1_ENABLED +#else +#undef MBEDTLS_ECP_DP_BP256R1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED #define MBEDTLS_ECP_DP_BP384R1_ENABLED +#else +#undef MBEDTLS_ECP_DP_BP384R1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED #define MBEDTLS_ECP_DP_BP512R1_ENABLED +#else +#undef MBEDTLS_ECP_DP_BP512R1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED #define MBEDTLS_ECP_DP_CURVE25519_ENABLED +#else +#undef MBEDTLS_ECP_DP_CURVE25519_ENABLED +#endif + +#ifdef MBEDTLS_ECP_DP_CURVE448_ENABLED +#undef MBEDTLS_ECP_DP_CURVE448_ENABLED #endif /** @@ -504,6 +337,8 @@ */ #ifdef CONFIG_MBEDTLS_ECP_NIST_OPTIM #define MBEDTLS_ECP_NIST_OPTIM +#else +#undef MBEDTLS_ECP_NIST_OPTIM #endif /** @@ -542,6 +377,8 @@ */ #ifdef CONFIG_MBEDTLS_KEY_EXCHANGE_PSK #define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED +#else +#undef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED #endif /** @@ -568,6 +405,8 @@ */ #ifdef CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_PSK #define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED +#else +#undef MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED #endif /** @@ -590,6 +429,8 @@ */ #ifdef CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_PSK #define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED +#else +#undef MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED #endif /** @@ -617,6 +458,8 @@ */ #ifdef CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_PSK #define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED +#else +#undef MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED #endif /** @@ -647,6 +490,8 @@ */ #ifdef CONFIG_MBEDTLS_KEY_EXCHANGE_RSA #define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +#else +#undef MBEDTLS_KEY_EXCHANGE_RSA_ENABLED #endif /** @@ -675,6 +520,8 @@ */ #ifdef CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA #define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED +#else +#undef MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED #endif /** @@ -702,6 +549,8 @@ */ #ifdef CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA #define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +#else +#undef MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED #endif /** @@ -728,6 +577,8 @@ */ #ifdef CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA #define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +#else +#undef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED #endif /** @@ -754,6 +605,8 @@ */ #ifdef CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA #define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED +#else +#undef MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED #endif /** @@ -780,27 +633,10 @@ */ #ifdef CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA #define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED +#else +#undef MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED #endif -/** - * \def MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED - * - * Enable the ECJPAKE based ciphersuite modes in SSL / TLS. - * - * \warning This is currently experimental. EC J-PAKE support is based on the - * Thread v1.0.0 specification; incompatible changes to the specification - * might still happen. For this reason, this is disabled by default. - * - * Requires: MBEDTLS_ECJPAKE_C - * MBEDTLS_SHA256_C - * MBEDTLS_ECP_DP_SECP256R1_ENABLED - * - * This enables the following ciphersuites (if other requisites are - * enabled as well): - * MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 - */ -//#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED - /** * \def MBEDTLS_PK_PARSE_EC_EXTENDED * @@ -846,19 +682,6 @@ */ #define MBEDTLS_FS_IO -/** - * \def MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES - * - * Do not add default entropy sources. These are the platform specific, - * mbedtls_timing_hardclock and HAVEGE based poll functions. - * - * This is useful to have more control over the added entropy sources in an - * application. - * - * Uncomment this macro to prevent loading of default entropy functions. - */ -//#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES - /** * \def MBEDTLS_NO_PLATFORM_ENTROPY * @@ -870,47 +693,6 @@ */ #define MBEDTLS_NO_PLATFORM_ENTROPY -/** - * \def MBEDTLS_ENTROPY_FORCE_SHA256 - * - * Force the entropy accumulator to use a SHA-256 accumulator instead of the - * default SHA-512 based one (if both are available). - * - * Requires: MBEDTLS_SHA256_C - * - * On 32-bit systems SHA-256 can be much faster than SHA-512. Use this option - * if you have performance concerns. - * - * This option is only useful if both MBEDTLS_SHA256_C and - * MBEDTLS_SHA512_C are defined. Otherwise the available hash module is used. - */ -//#define MBEDTLS_ENTROPY_FORCE_SHA256 - -/** - * \def MBEDTLS_MEMORY_DEBUG - * - * Enable debugging of buffer allocator memory issues. Automatically prints - * (to stderr) all (fatal) messages on memory allocation issues. Enables - * function for 'debug output' of allocated memory. - * - * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C - * - * Uncomment this macro to let the buffer allocator print out error messages. - */ -//#define MBEDTLS_MEMORY_DEBUG - -/** - * \def MBEDTLS_MEMORY_BACKTRACE - * - * Include backtrace information with each allocated block. - * - * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C - * GLIBC-compatible backtrace() an backtrace_symbols() support - * - * Uncomment this macro to include backtrace information - */ -//#define MBEDTLS_MEMORY_BACKTRACE - /** * \def MBEDTLS_PK_RSA_ALT_SUPPORT * @@ -942,16 +724,6 @@ */ #define MBEDTLS_PKCS1_V21 -/** - * \def MBEDTLS_RSA_NO_CRT - * - * Do not use the Chinese Remainder Theorem for the RSA private operation. - * - * Uncomment this macro to disable the use of CRT in RSA. - * - */ -//#define MBEDTLS_RSA_NO_CRT - /** * \def MBEDTLS_SELF_TEST * @@ -959,34 +731,6 @@ */ #define MBEDTLS_SELF_TEST -/** - * \def MBEDTLS_SHA256_SMALLER - * - * Enable an implementation of SHA-256 that has lower ROM footprint but also - * lower performance. - * - * The default implementation is meant to be a reasonnable compromise between - * performance and size. This version optimizes more aggressively for size at - * the expense of performance. Eg on Cortex-M4 it reduces the size of - * mbedtls_sha256_process() from ~2KB to ~0.5KB for a performance hit of about - * 30%. - * - * Uncomment to enable the smaller implementation of SHA256. - */ -//#define MBEDTLS_SHA256_SMALLER - -/** - * \def MBEDTLS_SSL_AEAD_RANDOM_IV - * - * Generate a random IV rather than using the record sequence number as a - * nonce for ciphersuites using and AEAD algorithm (GCM or CCM). - * - * Using the sequence number is generally recommended. - * - * Uncomment this macro to always use random IVs with AEAD ciphersuites. - */ -//#define MBEDTLS_SSL_AEAD_RANDOM_IV - /** * \def MBEDTLS_SSL_ALL_ALERT_MESSAGES * @@ -1001,22 +745,6 @@ */ #define MBEDTLS_SSL_ALL_ALERT_MESSAGES -/** - * \def MBEDTLS_SSL_DEBUG_ALL - * - * Enable the debug messages in SSL module for all issues. - * Debug messages have been disabled in some places to prevent timing - * attacks due to (unbalanced) debugging function calls. - * - * If you need all error reporting you should enable this during debugging, - * but remove this for production servers that should log as well. - * - * Uncomment this macro to report all debug messages on errors introducing - * a timing side-channel. - * - */ -//#define MBEDTLS_SSL_DEBUG_ALL - /** \def MBEDTLS_SSL_ENCRYPT_THEN_MAC * * Enable support for Encrypt-then-MAC, RFC 7366. @@ -1035,6 +763,8 @@ */ #ifdef CONFIG_MBEDTLS_TLS_ENABLED #define MBEDTLS_SSL_ENCRYPT_THEN_MAC +#else +#undef MBEDTLS_SSL_ENCRYPT_THEN_MAC #endif /** \def MBEDTLS_SSL_EXTENDED_MASTER_SECRET @@ -1055,6 +785,8 @@ */ #ifdef CONFIG_MBEDTLS_TLS_ENABLED #define MBEDTLS_SSL_EXTENDED_MASTER_SECRET +#else +#undef MBEDTLS_SSL_EXTENDED_MASTER_SECRET #endif /** @@ -1075,14 +807,36 @@ #define MBEDTLS_SSL_FALLBACK_SCSV /** - * \def MBEDTLS_SSL_HW_RECORD_ACCEL + * \def MBEDTLS_SSL_PROTO_TLS1 * - * Enable hooking functions in SSL module for hardware acceleration of - * individual records. + * Enable support for TLS 1.0. * - * Uncomment this macro to enable hooking functions. + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.0 */ -//#define MBEDTLS_SSL_HW_RECORD_ACCEL +#ifdef CONFIG_MBEDTLS_SSL_PROTO_TLS1 +#define MBEDTLS_SSL_PROTO_TLS1 +#else +#undef MBEDTLS_SSL_PROTO_TLS1 +#endif + +/** + * \def MBEDTLS_SSL_PROTO_SSL3 + * + * Enable support for SSL 3.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for SSL 3.0 + */ +#ifdef CONFIG_MBEDTLS_SSL_PROTO_SSL3 +#define MBEDTLS_SSL_PROTO_SSL3 +#else +#undef MBEDTLS_SSL_PROTO_SSL3 +#endif /** * \def MBEDTLS_SSL_CBC_RECORD_SPLITTING @@ -1096,6 +850,8 @@ */ #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) #define MBEDTLS_SSL_CBC_RECORD_SPLITTING +#else +#undef MBEDTLS_SSL_CBC_RECORD_SPLITTING #endif /** @@ -1113,28 +869,10 @@ */ #ifdef CONFIG_MBEDTLS_SSL_RENEGOTIATION #define MBEDTLS_SSL_RENEGOTIATION +#else +#undef MBEDTLS_SSL_RENEGOTIATION #endif -/** - * \def MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO - * - * Enable support for receiving and parsing SSLv2 Client Hello messages for the - * SSL Server module (MBEDTLS_SSL_SRV_C). - * - * Uncomment this macro to enable support for SSLv2 Client Hello messages. - */ -//#define MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO - -/** - * \def MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE - * - * Pick the ciphersuite according to the client's preferences rather than ours - * in the SSL Server module (MBEDTLS_SSL_SRV_C). - * - * Uncomment this macro to respect client's ciphersuite order - */ -//#define MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE - /** * \def MBEDTLS_SSL_MAX_FRAGMENT_LENGTH * @@ -1144,34 +882,6 @@ */ #define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH -/** - * \def MBEDTLS_SSL_PROTO_SSL3 - * - * Enable support for SSL 3.0. - * - * Requires: MBEDTLS_MD5_C - * MBEDTLS_SHA1_C - * - * Comment this macro to disable support for SSL 3.0 - */ -#ifdef CONFIG_MBEDTLS_SSL_PROTO_SSL3 -#define MBEDTLS_SSL_PROTO_SSL3 -#endif - -/** - * \def MBEDTLS_SSL_PROTO_TLS1 - * - * Enable support for TLS 1.0. - * - * Requires: MBEDTLS_MD5_C - * MBEDTLS_SHA1_C - * - * Comment this macro to disable support for TLS 1.0 - */ -#ifdef CONFIG_MBEDTLS_SSL_PROTO_TLS1 -#define MBEDTLS_SSL_PROTO_TLS1 -#endif - /** * \def MBEDTLS_SSL_PROTO_TLS1_1 * @@ -1198,6 +908,8 @@ */ #ifdef CONFIG_MBEDTLS_SSL_PROTO_TLS1_2 #define MBEDTLS_SSL_PROTO_TLS1_2 +#else +#undef MBEDTLS_SSL_PROTO_TLS1_2 #endif /** @@ -1215,6 +927,8 @@ */ #ifdef CONFIG_MBEDTLS_SSL_PROTO_DTLS #define MBEDTLS_SSL_PROTO_DTLS +#else +#undef MBEDTLS_SSL_PROTO_DTLS #endif /** @@ -1226,6 +940,8 @@ */ #ifdef CONFIG_MBEDTLS_SSL_ALPN #define MBEDTLS_SSL_ALPN +#else +#undef MBEDTLS_SSL_ALPN #endif /** @@ -1243,6 +959,8 @@ */ #ifdef CONFIG_MBEDTLS_SSL_PROTO_DTLS #define MBEDTLS_SSL_DTLS_ANTI_REPLAY +#else +#undef MBEDTLS_SSL_DTLS_ANTI_REPLAY #endif /** @@ -1263,6 +981,8 @@ */ #ifdef CONFIG_MBEDTLS_SSL_PROTO_DTLS #define MBEDTLS_SSL_DTLS_HELLO_VERIFY +#else +#undef MBEDTLS_SSL_DTLS_HELLO_VERIFY #endif /** @@ -1281,6 +1001,8 @@ */ #ifdef CONFIG_MBEDTLS_SSL_PROTO_DTLS #define MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE +#else +#undef MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE #endif /** @@ -1294,6 +1016,8 @@ */ #ifdef CONFIG_MBEDTLS_SSL_PROTO_DTLS #define MBEDTLS_SSL_DTLS_BADMAC_LIMIT +#else +#undef MBEDTLS_SSL_DTLS_BADMAC_LIMIT #endif /** @@ -1310,6 +1034,8 @@ */ #ifdef CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS #define MBEDTLS_SSL_SESSION_TICKETS +#else +#undef MBEDTLS_SSL_SESSION_TICKETS #endif /** @@ -1342,28 +1068,6 @@ */ #define MBEDTLS_SSL_TRUNCATED_HMAC -/** - * \def MBEDTLS_THREADING_ALT - * - * Provide your own alternate threading implementation. - * - * Requires: MBEDTLS_THREADING_C - * - * Uncomment this to allow your own alternate threading implementation. - */ -//#define MBEDTLS_THREADING_ALT - -/** - * \def MBEDTLS_THREADING_PTHREAD - * - * Enable the pthread wrapper layer for the threading layer. - * - * Requires: MBEDTLS_THREADING_C - * - * Uncomment this to enable pthread mutexes. - */ -//#define MBEDTLS_THREADING_PTHREAD - /** * \def MBEDTLS_VERSION_FEATURES * @@ -1377,28 +1081,6 @@ */ #define MBEDTLS_VERSION_FEATURES -/** - * \def MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 - * - * If set, the X509 parser will not break-off when parsing an X509 certificate - * and encountering an extension in a v1 or v2 certificate. - * - * Uncomment to prevent an error. - */ -//#define MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 - -/** - * \def MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION - * - * If set, the X509 parser will not break-off when parsing an X509 certificate - * and encountering an unknown critical extension. - * - * \warning Depending on your PKI use, enabling this can be a security risk! - * - * Uncomment to prevent an error. - */ -//#define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION - /** * \def MBEDTLS_X509_CHECK_KEY_USAGE * @@ -1436,27 +1118,7 @@ */ #define MBEDTLS_X509_RSASSA_PSS_SUPPORT -/** - * \def MBEDTLS_ZLIB_SUPPORT - * - * If set, the SSL/TLS module uses ZLIB to support compression and - * decompression of packet data. - * - * \warning TLS-level compression MAY REDUCE SECURITY! See for example the - * CRIME attack. Before enabling this option, you should examine with care if - * CRIME or similar exploits may be a applicable to your use case. - * - * \note Currently compression can't be used with DTLS. - * - * Used in: library/ssl_tls.c - * library/ssl_cli.c - * library/ssl_srv.c - * - * This feature requires zlib library and headers to be present. - * - * Uncomment to enable use of ZLIB - */ -//#define MBEDTLS_ZLIB_SUPPORT + /* \} name SECTION: mbed TLS feature support */ /** @@ -1555,31 +1217,8 @@ */ #ifdef CONFIG_MBEDTLS_AES_C #define MBEDTLS_AES_C -#endif - -/** - * \def MBEDTLS_ARC4_C - * - * Enable the ARCFOUR stream cipher. - * - * Module: library/arc4.c - * Caller: library/ssl_tls.c - * - * This module enables the following ciphersuites (if other requisites are - * enabled as well): - * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA - * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA - * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA - * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA - * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA - * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA - * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA - * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 - * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA - * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA - */ -#if defined(CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT) || defined(CONFIG_MBEDTLS_RC4_ENABLED) -#define MBEDTLS_ARC4_C +#else +#undef MBEDTLS_AES_C #endif /** @@ -1647,6 +1286,8 @@ */ #ifdef CONFIG_MBEDTLS_BLOWFISH_C #define MBEDTLS_BLOWFISH_C +#else +#undef MBEDTLS_BLOWFISH_C #endif /** @@ -1704,6 +1345,8 @@ */ #ifdef CONFIG_MBEDTLS_CAMELLIA_C #define MBEDTLS_CAMELLIA_C +#else +#undef MBEDTLS_CAMELLIA_C #endif /** @@ -1720,6 +1363,8 @@ */ #ifdef CONFIG_MBEDTLS_CCM_C #define MBEDTLS_CCM_C +#else +#undef MBEDTLS_CCM_C #endif /** @@ -1734,6 +1379,30 @@ */ #define MBEDTLS_CERTS_C +/** + * \def MBEDTLS_CHACHA20_C + * + * Disable the ChaCha20 stream cipher. + * + * Module: library/chacha20.c + */ +#ifdef MBEDTLS_CHACHA20_C +#undef MBEDTLS_CHACHA20_C +#endif + +/** + * \def MBEDTLS_CHACHAPOLY_C + * + * Disable the ChaCha20-Poly1305 AEAD algorithm. + * + * Module: library/chachapoly.c + * + * This module requires: MBEDTLS_CHACHA20_C, MBEDTLS_POLY1305_C + */ +#ifdef MBEDTLS_CHACHAPOLY_C +#undef MBEDTLS_CHACHAPOLY_C +#endif + /** * \def MBEDTLS_CIPHER_C * @@ -1774,6 +1443,8 @@ */ #if CONFIG_MBEDTLS_DEBUG #define MBEDTLS_DEBUG_C +#else +#undef MBEDTLS_DEBUG_C #endif /** @@ -1802,6 +1473,8 @@ */ #ifdef CONFIG_MBEDTLS_DES_C #define MBEDTLS_DES_C +#else +#undef MBEDTLS_DES_C #endif /** @@ -1834,6 +1507,8 @@ */ #ifdef CONFIG_MBEDTLS_ECDH_C #define MBEDTLS_ECDH_C +#else +#undef MBEDTLS_ECDH_C #endif /** @@ -1851,6 +1526,8 @@ */ #ifdef CONFIG_MBEDTLS_ECDSA_C #define MBEDTLS_ECDSA_C +#else +#undef MBEDTLS_ECDSA_C #endif /** @@ -1886,6 +1563,8 @@ */ #ifdef CONFIG_MBEDTLS_ECP_C #define MBEDTLS_ECP_C +#else +#undef MBEDTLS_ECP_C #endif /** @@ -1928,30 +1607,26 @@ */ #ifdef CONFIG_MBEDTLS_GCM_C #define MBEDTLS_GCM_C +#else +#undef MBEDTLS_GCM_C #endif /** - * \def MBEDTLS_HAVEGE_C + * \def MBEDTLS_HKDF_C * - * Enable the HAVEGE random generator. + * Disable the HKDF algorithm (RFC 5869). * - * Warning: the HAVEGE random generator is not suitable for virtualized - * environments - * - * Warning: the HAVEGE random generator is dependent on timing and specific - * processor traits. It is therefore not advised to use HAVEGE as - * your applications primary random generator or primary entropy pool - * input. As a secondary input to your entropy pool, it IS able add - * the (limited) extra entropy it provides. - * - * Module: library/havege.c + * Module: library/hkdf.c * Caller: * - * Requires: MBEDTLS_TIMING_C + * Requires: MBEDTLS_MD_C * - * Uncomment to enable the HAVEGE random generator. + * This module adds support for the Hashed Message Authentication Code + * (HMAC)-based key derivation function (HKDF). */ -//#define MBEDTLS_HAVEGE_C +#ifdef MBEDTLS_HKDF_C +#undef MBEDTLS_HKDF_C +#endif /** * \def MBEDTLS_HMAC_DRBG_C @@ -1979,30 +1654,6 @@ */ #define MBEDTLS_MD_C -/** - * \def MBEDTLS_MD2_C - * - * Enable the MD2 hash algorithm. - * - * Module: library/mbedtls_md2.c - * Caller: - * - * Uncomment to enable support for (rare) MD2-signed X.509 certs. - */ -//#define MBEDTLS_MD2_C - -/** - * \def MBEDTLS_MD4_C - * - * Enable the MD4 hash algorithm. - * - * Module: library/mbedtls_md4.c - * Caller: - * - * Uncomment to enable support for (rare) MD4-signed X.509 certs. - */ -//#define MBEDTLS_MD4_C - /** * \def MBEDTLS_MD5_C * @@ -2018,22 +1669,6 @@ */ #define MBEDTLS_MD5_C -/** - * \def MBEDTLS_MEMORY_BUFFER_ALLOC_C - * - * Enable the buffer allocator implementation that makes use of a (stack) - * based buffer to 'allocate' dynamic memory. (replaces calloc() and free() - * calls) - * - * Module: library/memory_buffer_alloc.c - * - * Requires: MBEDTLS_PLATFORM_C - * MBEDTLS_PLATFORM_MEMORY (to use it within mbed TLS) - * - * Enable this module to enable the buffer memory allocator. - */ -//#define MBEDTLS_MEMORY_BUFFER_ALLOC_C - /** * \def MBEDTLS_NET_C * @@ -2043,7 +1678,9 @@ * * This module provides TCP/IP networking routines. */ -//#define MBEDTLS_NET_C +#ifdef MBEDTLS_NET_C +#undef MBEDTLS_NET_C +#endif /** * \def MBEDTLS_OID_C @@ -2100,6 +1737,8 @@ */ #ifdef CONFIG_MBEDTLS_PEM_PARSE_C #define MBEDTLS_PEM_PARSE_C +#else +#undef MBEDTLS_PEM_PARSE_C #endif /** @@ -2118,6 +1757,8 @@ */ #ifdef CONFIG_MBEDTLS_PEM_WRITE_C #define MBEDTLS_PEM_WRITE_C +#else +#undef MBEDTLS_PEM_WRITE_C #endif /** @@ -2178,21 +1819,6 @@ */ #define MBEDTLS_PKCS5_C -/** - * \def MBEDTLS_PKCS11_C - * - * Enable wrapper for PKCS#11 smartcard support. - * - * Module: library/pkcs11.c - * Caller: library/pk.c - * - * Requires: MBEDTLS_PK_C - * - * This module enables SSL/TLS PKCS #11 smartcard support. - * Requires the presence of the PKCS#11 helper library (libpkcs11-helper) - */ -//#define MBEDTLS_PKCS11_C - /** * \def MBEDTLS_PKCS12_C * @@ -2229,6 +1855,18 @@ */ #define MBEDTLS_PLATFORM_C +/** + * \def MBEDTLS_POLY1305_C + * + * Disable the Poly1305 MAC algorithm. + * + * Module: library/poly1305.c + * Caller: library/chachapoly.c + */ +#ifdef MBEDTLS_POLY1305_C +#undef MBEDTLS_POLY1305_C +#endif + /** * \def MBEDTLS_RIPEMD160_C * @@ -2240,6 +1878,8 @@ */ #ifdef CONFIG_MBEDTLS_RIPEMD160_C #define MBEDTLS_RIPEMD160_C +#else +#undef MBEDTLS_RIPEMD160_C #endif /** @@ -2342,6 +1982,8 @@ */ #ifdef CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS #define MBEDTLS_SSL_TICKET_C +#else +#undef MBEDTLS_SSL_TICKET_C #endif /** @@ -2358,6 +2000,8 @@ */ #ifdef CONFIG_MBEDTLS_TLS_CLIENT #define MBEDTLS_SSL_CLI_C +#else +#undef MBEDTLS_SSL_CLI_C #endif /** @@ -2374,6 +2018,8 @@ */ #ifdef CONFIG_MBEDTLS_TLS_SERVER #define MBEDTLS_SSL_SRV_C +#else +#undef MBEDTLS_SSL_SRV_C #endif /** @@ -2392,40 +2038,34 @@ */ #ifdef CONFIG_MBEDTLS_TLS_ENABLED #define MBEDTLS_SSL_TLS_C +#else +#undef MBEDTLS_SSL_TLS_C #endif -/** - * \def MBEDTLS_THREADING_C - * - * Enable the threading abstraction layer. - * By default mbed TLS assumes it is used in a non-threaded environment or that - * contexts are not shared between threads. If you do intend to use contexts - * between threads, you will need to enable this layer to prevent race - * conditions. - * - * Module: library/threading.c - * - * This allows different threading implementations (self-implemented or - * provided). - * - * You will have to enable either MBEDTLS_THREADING_ALT or - * MBEDTLS_THREADING_PTHREAD. - * - * Enable this layer to allow use of mutexes within mbed TLS - */ -//#define MBEDTLS_THREADING_C - /** * \def MBEDTLS_TIMING_C * - * Enable the portable timing interface. + * Enable the semi-portable timing interface. + * + * \note The provided implementation only works on POSIX/Unix (including Linux, + * BSD and OS X) and Windows. On other platforms, you can either disable that + * module and provide your own implementations of the callbacks needed by + * \c mbedtls_ssl_set_timer_cb() for DTLS, or leave it enabled and provide + * your own implementation of the whole module by setting + * \c MBEDTLS_TIMING_ALT in the current file. + * + * \note See also our Knowledge Base article about porting to a new + * environment: + * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS * * Module: library/timing.c * Caller: library/havege.c * * This module is used by the HAVEGE random number generator. */ -//#define MBEDTLS_TIMING_C +#ifdef MBEDTLS_TIMING_C +#undef MBEDTLS_TIMING_C +#endif /** * \def MBEDTLS_VERSION_C @@ -2485,6 +2125,8 @@ */ #ifdef CONFIG_MBEDTLS_X509_CRL_PARSE_C #define MBEDTLS_X509_CRL_PARSE_C +#else +#undef MBEDTLS_X509_CRL_PARSE_C #endif /** @@ -2501,6 +2143,8 @@ */ #ifdef CONFIG_MBEDTLS_X509_CSR_PARSE_C #define MBEDTLS_X509_CSR_PARSE_C +#else +#undef MBEDTLS_X509_CSR_PARSE_C #endif /** @@ -2552,6 +2196,8 @@ */ #ifdef CONFIG_MBEDTLS_XTEA_C #define MBEDTLS_XTEA_C +#else +#undef MBEDTLS_XTEA_C #endif /* \} name SECTION: mbed TLS modules */ @@ -2571,59 +2217,6 @@ * \{ */ -/* MPI / BIGNUM options */ -//#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ -//#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ - -/* CTR_DRBG options */ -//#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */ -//#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ -//#define MBEDTLS_CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ -//#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ -//#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ - -/* HMAC_DRBG options */ -//#define MBEDTLS_HMAC_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ -//#define MBEDTLS_HMAC_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ -//#define MBEDTLS_HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ -//#define MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ - -/* ECP options */ -//#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ -//#define MBEDTLS_ECP_WINDOW_SIZE 6 /**< Maximum window size used */ -//#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up */ - -/* Entropy options */ -//#define MBEDTLS_ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ -//#define MBEDTLS_ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ - -/* Memory buffer allocator options */ -//#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */ - -/* Platform options */ -//#define MBEDTLS_PLATFORM_STD_MEM_HDR /**< Header to include if MBEDTLS_PLATFORM_NO_STD_FUNCTIONS is defined. Don't define if no header is needed. */ -//#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< Default allocator to use, can be undefined */ -//#define MBEDTLS_PLATFORM_STD_FREE free /**< Default free to use, can be undefined */ -//#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default exit to use, can be undefined */ -//#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use, can be undefined */ -//#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use, can be undefined */ -/* Note: your snprintf must correclty zero-terminate the buffer! */ -//#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< Default snprintf to use, can be undefined */ - -/* To Use Function Macros MBEDTLS_PLATFORM_C must be enabled */ -/* MBEDTLS_PLATFORM_XXX_MACRO and MBEDTLS_PLATFORM_XXX_ALT cannot both be defined */ -//#define MBEDTLS_PLATFORM_CALLOC_MACRO calloc /**< Default allocator macro to use, can be undefined */ -//#define MBEDTLS_PLATFORM_FREE_MACRO free /**< Default free macro to use, can be undefined */ -//#define MBEDTLS_PLATFORM_EXIT_MACRO exit /**< Default exit macro to use, can be undefined */ -//#define MBEDTLS_PLATFORM_FPRINTF_MACRO fprintf /**< Default fprintf macro to use, can be undefined */ -//#define MBEDTLS_PLATFORM_PRINTF_MACRO printf /**< Default printf macro to use, can be undefined */ -/* Note: your snprintf must correclty zero-terminate the buffer! */ -//#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf /**< Default snprintf macro to use, can be undefined */ - -/* SSL Cache options */ -//#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */ -//#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */ - /* SSL options */ #ifndef CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN @@ -2665,27 +2258,6 @@ #endif /* !CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN */ -//#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ -//#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ -//#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ - -/** - * Complete list of ciphersuites to use, in order of preference. - * - * \warning No dependency checking is done on that field! This option can only - * be used to restrict the set of available ciphersuites. It is your - * responsibility to make sure the needed modules are active. - * - * Use this to save a few hundred bytes of ROM (default ordering of all - * available ciphersuites) and a few to a few hundred bytes of RAM. - * - * The value below is only an example, not the default. - */ -//#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - -/* X509 options */ -//#define MBEDTLS_X509_MAX_INTERMEDIATE_CA 8 /**< Maximum number of intermediate CAs in a verification chain. */ - /** * Allow SHA-1 in the default TLS configuration for TLS 1.2 handshake * signature and ciphersuite selection. Without this build-time option, SHA-1 From d3e814fe195dee14f372d05ff943bc1954b87d6d Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Fri, 12 Jul 2019 16:02:47 +0800 Subject: [PATCH 308/486] cmake: set COMPONENT_DIR in early expansion Gives same treatment to COMPONENT_DIR as COMPONENT_PATH in https://gitlab.espressif.cn:6688/espressif/esp-idf/merge_requests/4557 Closes https://github.com/espressif/esp-idf/issues/3771 --- CMakeLists.txt | 2 +- tools/cmake/scripts/component_get_requirements.cmake | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8facf36a29..1b48106487 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,7 +70,7 @@ foreach(component_target ${build_component_targets}) set(COMPONENT_NAME ${_name}) set(COMPONENT_DIR ${dir}) set(COMPONENT_ALIAS ${alias}) - set(COMPONENT_PATH ${dir}) # also deprecated, see comment in previous loop + set(COMPONENT_PATH ${dir}) # for backward compatibility only, COMPONENT_DIR is preferred idf_build_get_property(build_prefix __PREFIX) set(__idf_component_context 1) if(NOT prefix STREQUAL build_prefix) diff --git a/tools/cmake/scripts/component_get_requirements.cmake b/tools/cmake/scripts/component_get_requirements.cmake index 0b0d18727e..24637008bd 100644 --- a/tools/cmake/scripts/component_get_requirements.cmake +++ b/tools/cmake/scripts/component_get_requirements.cmake @@ -53,6 +53,10 @@ function(__component_get_requirements) # and set by the included CMakeLists.txt does not bleed into the next inclusion. # We are only interested in the public and private requirements of components __component_get_property(__component_dir ${__component_target} COMPONENT_DIR) + __component_get_property(__component_name ${__component_target} COMPONENT_NAME) + set(COMPONENT_NAME ${__component_name}) + set(COMPONENT_DIR ${__component_dir}) + set(COMPONENT_PATH ${__component_dir}) # for backward compatibility only, COMPONENT_DIR is preferred include(${__component_dir}/CMakeLists.txt OPTIONAL) spaces2list(__component_requires) From d1bf08d4ad9ba7132a14e2aca3e52b4e10c75532 Mon Sep 17 00:00:00 2001 From: zhangyanjiao Date: Fri, 12 Jul 2019 20:07:10 +0800 Subject: [PATCH 309/486] coexist: fix the watchdog bug during WiFi scan and BLE scan --- components/esp_wifi/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index 414f9b279e..11d6683dc3 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit 414f9b279e772196e8f6cf343d19f2882a2e8741 +Subproject commit 11d6683dc3ad699f2e8b022f01c49774d5e337cd From 0e07b85d2f17fcc8e4214a5f0476e028e72b8425 Mon Sep 17 00:00:00 2001 From: Anurag Kar Date: Sat, 13 Jul 2019 15:48:23 +0530 Subject: [PATCH 310/486] wifi_prov_mgr : Added missing esp_event_post() for WIFI_PROV_END events --- components/wifi_provisioning/src/manager.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/components/wifi_provisioning/src/manager.c b/components/wifi_provisioning/src/manager.c index 3d7a8355cb..7959885399 100644 --- a/components/wifi_provisioning/src/manager.c +++ b/components/wifi_provisioning/src/manager.c @@ -512,6 +512,10 @@ static void prov_stop_task(void *arg) if (app_cb) { app_cb(app_data, WIFI_PROV_END, NULL); } + if (esp_event_post(WIFI_PROV_EVENT, WIFI_PROV_END, NULL, 0, portMAX_DELAY) != ESP_OK) { + ESP_LOGE(TAG, "Failed to post event WIFI_PROV_END"); + } + vTaskDelete(NULL); } } @@ -1346,6 +1350,9 @@ void wifi_prov_mgr_deinit(void) if (app_cb) { app_cb(app_data, WIFI_PROV_END, NULL); } + if (esp_event_post(WIFI_PROV_EVENT, WIFI_PROV_END, NULL, 0, portMAX_DELAY) != ESP_OK) { + ESP_LOGE(TAG, "Failed to post event WIFI_PROV_END"); + } } ESP_LOGD(TAG, "execute_event_cb : %d", WIFI_PROV_DEINIT); @@ -1357,7 +1364,9 @@ void wifi_prov_mgr_deinit(void) if (app_cb) { app_cb(app_data, WIFI_PROV_DEINIT, NULL); } - esp_event_post(WIFI_PROV_EVENT, WIFI_PROV_DEINIT, NULL, 0, portMAX_DELAY); + if (esp_event_post(WIFI_PROV_EVENT, WIFI_PROV_DEINIT, NULL, 0, portMAX_DELAY) != ESP_OK) { + ESP_LOGE(TAG, "Failed to post event WIFI_PROV_DEINIT"); + } } esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const char *pop, From 8f2d13d9dbce9f3e94593d4f9e67c8d243b58fee Mon Sep 17 00:00:00 2001 From: xiehang Date: Mon, 8 Jul 2019 11:26:18 +0800 Subject: [PATCH 311/486] WiFi: Modify the wifi_country struct in VNC to keep it consistent with IDF. 1, Modfy wifi_country struct 2, Add md5 check esp_wifi_types.h 3, Add md5 check esp_wifi.h --- .../include/esp_private/esp_wifi_private.h | 25 +++++++++ .../esp_private/esp_wifi_types_private.h | 25 +++++++++ .../esp_wifi/include/esp_private/wifi.h | 23 ++++++++ .../esp_wifi/include/esp_private/wifi_types.h | 54 +++++++++++++++++++ components/esp_wifi/include/esp_wifi.h | 31 ++++++----- components/esp_wifi/include/esp_wifi_types.h | 35 +----------- components/esp_wifi/lib_esp32 | 2 +- components/esp_wifi/test/CMakeLists.txt | 10 ++++ components/esp_wifi/test/component.mk | 8 +++ .../esp_wifi/test/test_header_files_md5.c | 26 +++++++-- 10 files changed, 185 insertions(+), 54 deletions(-) create mode 100644 components/esp_wifi/include/esp_private/esp_wifi_private.h create mode 100644 components/esp_wifi/include/esp_private/esp_wifi_types_private.h create mode 100644 components/esp_wifi/include/esp_private/wifi_types.h diff --git a/components/esp_wifi/include/esp_private/esp_wifi_private.h b/components/esp_wifi/include/esp_private/esp_wifi_private.h new file mode 100644 index 0000000000..80828aa886 --- /dev/null +++ b/components/esp_wifi/include/esp_private/esp_wifi_private.h @@ -0,0 +1,25 @@ +// Copyright 2015-2019 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. + +#ifndef _ESP_WIFI_PRIVATE_H +#define _ESP_WIFI_PRIVATE_H + +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "sys/queue.h" +#include "sdkconfig.h" +#include "esp_wifi_crypto_types.h" +#include "esp_private/wifi_os_adapter.h" + + +#endif /* _ESP_WIFI_PRIVATE_H */ diff --git a/components/esp_wifi/include/esp_private/esp_wifi_types_private.h b/components/esp_wifi/include/esp_private/esp_wifi_types_private.h new file mode 100644 index 0000000000..3a1eebac61 --- /dev/null +++ b/components/esp_wifi/include/esp_private/esp_wifi_types_private.h @@ -0,0 +1,25 @@ +// Copyright 2015-2019 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. + +#ifndef _ESP_WIFI_TYPES_PRIVATE_H +#define _ESP_WIFI_TYPES_PRIVATE_H + +#include +#include +#include "sys/queue.h" +#include "esp_err.h" +#include "esp_interface.h" +#include "esp_event_base.h" + +#endif diff --git a/components/esp_wifi/include/esp_private/wifi.h b/components/esp_wifi/include/esp_private/wifi.h index ee0654f8bf..04195632fa 100644 --- a/components/esp_wifi/include/esp_private/wifi.h +++ b/components/esp_wifi/include/esp_private/wifi.h @@ -37,6 +37,7 @@ #include "esp_event.h" #include "esp_wifi.h" #include "esp_smartconfig.h" +#include "wifi_types.h" #ifdef __cplusplus extern "C" { @@ -232,6 +233,28 @@ esp_err_t esp_wifi_internal_osi_funcs_md5_check(const char *md5); */ esp_err_t esp_wifi_internal_crypto_funcs_md5_check(const char *md5); +/** + * @brief Check the MD5 values of the esp_wifi_types.h in IDF and WiFi library + * + * @attention 1. It is used for internal CI version check + * + * @return + * - ESP_OK : succeed + * - ESP_WIFI_INVALID_ARG : MD5 check fail + */ +esp_err_t esp_wifi_internal_wifi_type_md5_check(const char *md5); + +/** + * @brief Check the MD5 values of the esp_wifi.h in IDF and WiFi library + * + * @attention 1. It is used for internal CI version check + * + * @return + * - ESP_OK : succeed + * - ESP_WIFI_INVALID_ARG : MD5 check fail + */ +esp_err_t esp_wifi_internal_esp_wifi_md5_check(const char *md5); + /** * @brief Check the git commit id of WiFi library * diff --git a/components/esp_wifi/include/esp_private/wifi_types.h b/components/esp_wifi/include/esp_private/wifi_types.h new file mode 100644 index 0000000000..4542492c8f --- /dev/null +++ b/components/esp_wifi/include/esp_private/wifi_types.h @@ -0,0 +1,54 @@ +// Copyright 2015-2019 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. + +#ifndef _WIFI_TYPES_H +#define _WIFI_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief WiFi ioctl command type + * + */ +typedef enum { + WIFI_IOCTL_SET_STA_HT2040_COEX = 1, /**< Set the configuration of STA's HT2040 coexist management */ + WIFI_IOCTL_GET_STA_HT2040_COEX, /**< Get the configuration of STA's HT2040 coexist management */ + WIFI_IOCTL_MAX, +} wifi_ioctl_cmd_t; + +/** + * @brief Configuration for STA's HT2040 coexist management + * + */ +typedef struct { + int enable; /**< Indicate whether STA's HT2040 coexist management is enabled or not */ +} wifi_ht2040_coex_t; + +/** + * @brief Configuration for WiFi ioctl + * + */ +typedef struct { + union { + wifi_ht2040_coex_t ht2040_coex; /**< Configuration of STA's HT2040 coexist management */ + } data; /**< Configuration of ioctl command */ +} wifi_ioctl_config_t; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/esp_wifi/include/esp_wifi.h b/components/esp_wifi/include/esp_wifi.h index 5ee1e4d53c..57014b8d9a 100644 --- a/components/esp_wifi/include/esp_wifi.h +++ b/components/esp_wifi/include/esp_wifi.h @@ -59,15 +59,10 @@ #include #include -#include "freertos/FreeRTOS.h" -#include "freertos/queue.h" -#include "sys/queue.h" -#include "sdkconfig.h" #include "esp_err.h" #include "esp_wifi_types.h" -#include "esp_wifi_crypto_types.h" #include "esp_event.h" -#include "esp_private/wifi_os_adapter.h" +#include "esp_private/esp_wifi_private.h" #ifdef __cplusplus extern "C" { @@ -89,6 +84,10 @@ extern "C" { #define ESP_ERR_WIFI_WOULD_BLOCK (ESP_ERR_WIFI_BASE + 14) /*!< The caller would block */ #define ESP_ERR_WIFI_NOT_CONNECT (ESP_ERR_WIFI_BASE + 15) /*!< Station still in disconnect status */ +#define ESP_ERR_WIFI_POST (ESP_ERR_WIFI_BASE + 18) /*!< Failed to post the event to WiFi task */ +#define ESP_ERR_WIFI_INIT_STATE (ESP_ERR_WIFI_BASE + 19) /*!< Invalod WiFi state when init/deinit is called */ +#define ESP_ERR_WIFI_STOP_STATE (ESP_ERR_WIFI_BASE + 20) /*!< Returned when WiFi is stopping */ + /** * @brief WiFi stack configuration parameters passed to esp_wifi_init call. */ @@ -840,6 +839,16 @@ esp_err_t esp_wifi_set_auto_connect(bool en) __attribute__ ((deprecated)); */ esp_err_t esp_wifi_get_auto_connect(bool *en) __attribute__ ((deprecated)); +/** + * @brief Function signature for received Vendor-Specific Information Element callback. + * @param ctx Context argument, as passed to esp_wifi_set_vendor_ie_cb() when registering callback. + * @param type Information element type, based on frame type received. + * @param sa Source 802.11 address. + * @param vnd_ie Pointer to the vendor specific element data received. + * @param rssi Received signal strength indication. + */ +typedef void (*esp_vendor_ie_cb_t) (void *ctx, wifi_vendor_ie_type_t type, const uint8_t sa[6], const vendor_ie_data_t *vnd_ie, int rssi); + /** * @brief Set 802.11 Vendor-Specific Information Element * @@ -858,16 +867,6 @@ esp_err_t esp_wifi_get_auto_connect(bool *en) __attribute__ ((deprecated)); */ esp_err_t esp_wifi_set_vendor_ie(bool enable, wifi_vendor_ie_type_t type, wifi_vendor_ie_id_t idx, const void *vnd_ie); -/** - * @brief Function signature for received Vendor-Specific Information Element callback. - * @param ctx Context argument, as passed to esp_wifi_set_vendor_ie_cb() when registering callback. - * @param type Information element type, based on frame type received. - * @param sa Source 802.11 address. - * @param vnd_ie Pointer to the vendor specific element data received. - * @param rssi Received signal strength indication. - */ -typedef void (*esp_vendor_ie_cb_t) (void *ctx, wifi_vendor_ie_type_t type, const uint8_t sa[6], const vendor_ie_data_t *vnd_ie, int rssi); - /** * @brief Register Vendor-Specific Information Element monitoring callback. * diff --git a/components/esp_wifi/include/esp_wifi_types.h b/components/esp_wifi/include/esp_wifi_types.h index 3217332adc..57b916ec79 100644 --- a/components/esp_wifi/include/esp_wifi_types.h +++ b/components/esp_wifi/include/esp_wifi_types.h @@ -16,12 +16,7 @@ #ifndef __ESP_WIFI_TYPES_H__ #define __ESP_WIFI_TYPES_H__ -#include -#include -#include "sys/queue.h" -#include "esp_err.h" -#include "esp_interface.h" -#include "esp_event_base.h" +#include "esp_private/esp_wifi_types_private.h" #ifdef __cplusplus extern "C" { @@ -583,34 +578,6 @@ typedef struct { uint8_t mac[6]; /**< MAC address of the station which send probe request */ } wifi_event_ap_probe_req_rx_t; -/** - * @brief WiFi ioctl command type - * - */ -typedef enum { - WIFI_IOCTL_SET_STA_HT2040_COEX = 1, /**< Set the configuration of STA's HT2040 coexist management */ - WIFI_IOCTL_GET_STA_HT2040_COEX, /**< Get the configuration of STA's HT2040 coexist management */ - WIFI_IOCTL_MAX, -} wifi_ioctl_cmd_t; - -/** - * @brief Configuration for STA's HT2040 coexist management - * - */ -typedef struct { - int enable; /**< Indicate whether STA's HT2040 coexist management is enabled or not */ -} wifi_ht2040_coex_t; - -/** - * @brief Configuration for WiFi ioctl - * - */ -typedef struct { - union { - wifi_ht2040_coex_t ht2040_coex; /**< Configuration of STA's HT2040 coexist management */ - } data; /**< Configuration of ioctl command */ -} wifi_ioctl_config_t; - #ifdef __cplusplus } #endif diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index 11d6683dc3..15c50f3925 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit 11d6683dc3ad699f2e8b022f01c49774d5e337cd +Subproject commit 15c50f392523d4dab32a0a5ab3cec7fd611ea471 diff --git a/components/esp_wifi/test/CMakeLists.txt b/components/esp_wifi/test/CMakeLists.txt index cf98dd8137..e7cf4b12c8 100644 --- a/components/esp_wifi/test/CMakeLists.txt +++ b/components/esp_wifi/test/CMakeLists.txt @@ -16,6 +16,16 @@ string(SUBSTRING "${WIFI_CRYPTO_MD5}" 0 7 WIFI_CRYPTO_MD5) file(MD5 ${esp_wifi_dir}/include/esp_coexist_adapter.h COEX_ADAPTER_MD5) string(SUBSTRING "${COEX_ADAPTER_MD5}" 0 7 COEX_ADAPTER_MD5) +# Calculate MD5 value of header file esp_wifi_types.h +file(MD5 ${esp_wifi_dir}/include/esp_wifi_types.h WIFI_TYPE_MD5) +string(SUBSTRING "${WIFI_TYPE_MD5}" 0 7 WIFI_TYPE_MD5) + +# Calculate MD5 value of header file esp_wifi.h +file(MD5 ${esp_wifi_dir}/include/esp_wifi.h WIFI_ESP_WIFI_MD5) +string(SUBSTRING "${WIFI_ESP_WIFI_MD5}" 0 7 WIFI_ESP_WIFI_MD5) + add_definitions(-DWIFI_OS_ADAPTER_MD5=\"${WIFI_OS_ADAPTER_MD5}\") add_definitions(-DWIFI_CRYPTO_MD5=\"${WIFI_CRYPTO_MD5}\") add_definitions(-DCOEX_ADAPTER_MD5=\"${COEX_ADAPTER_MD5}\") +add_definitions(-DWIFI_TYPE_MD5=\"${WIFI_TYPE_MD5}\") +add_definitions(-DWIFI_ESP_WIFI_MD5=\"${WIFI_ESP_WIFI_MD5}\") diff --git a/components/esp_wifi/test/component.mk b/components/esp_wifi/test/component.mk index 88f939f810..7dbb988dd0 100644 --- a/components/esp_wifi/test/component.mk +++ b/components/esp_wifi/test/component.mk @@ -17,3 +17,11 @@ CFLAGS+=-DWIFI_CRYPTO_MD5=$(WIFI_CRYPTO_MD5_VAL) # Calculate MD5 value of header file esp_coexist_adapter.h COEX_ADAPTER_MD5_VAL=\"$(shell md5sum $(IDF_PATH)/components/esp_wifi/include/esp_coexist_adapter.h | cut -c 1-7)\" CFLAGS+=-DCOEX_ADAPTER_MD5=$(COEX_ADAPTER_MD5_VAL) + +# Calculate MD5 value of header file esp_wifi_types.h +WIFI_TYPE_MD5_VAL=\"$(shell md5sum $(IDF_PATH)/components/esp_wifi/include/esp_wifi_types.h | cut -c 1-7)\" +CFLAGS+=-DWIFI_TYPE_MD5=$(WIFI_TYPE_MD5_VAL) + +# Calculate MD5 value of header file esp_wifi.h +WIFI_ESP_WIFI_MD5_VAL=\"$(shell md5sum $(IDF_PATH)/components/esp_wifi/include/esp_wifi.h | cut -c 1-7)\" +CFLAGS+=-DWIFI_ESP_WIFI_MD5=$(WIFI_ESP_WIFI_MD5_VAL) diff --git a/components/esp_wifi/test/test_header_files_md5.c b/components/esp_wifi/test/test_header_files_md5.c index 17b0cc3b94..eb431051ac 100644 --- a/components/esp_wifi/test/test_header_files_md5.c +++ b/components/esp_wifi/test/test_header_files_md5.c @@ -12,7 +12,7 @@ TEST_CASE("wifi os adapter MD5","[wifi]") { const char *test_wifi_os_funcs_md5 = WIFI_OS_ADAPTER_MD5; - ESP_LOGI(TAG, "test wifi os adapter MD5..."); + ESP_LOGI(TAG, "test esp_wifi_os_adapter.h MD5..."); TEST_ESP_OK(esp_wifi_internal_osi_funcs_md5_check(test_wifi_os_funcs_md5)); ESP_LOGI(TAG, "test passed..."); @@ -22,7 +22,7 @@ TEST_CASE("wifi crypto types MD5","[wifi]") { const char *test_wifi_crypto_funcs_md5 = WIFI_CRYPTO_MD5; - ESP_LOGI(TAG, "test wifi crypto adapter MD5..."); + ESP_LOGI(TAG, "test esp_wifi_crypto_types.h MD5..."); TEST_ESP_OK(esp_wifi_internal_crypto_funcs_md5_check(test_wifi_crypto_funcs_md5)); ESP_LOGI(TAG, "test passed..."); @@ -32,8 +32,28 @@ TEST_CASE("coexist adapter MD5","[coex]") { const char *test_coex_adapter_funcs_md5 = COEX_ADAPTER_MD5; - ESP_LOGI(TAG, "test coexist adapter MD5..."); + ESP_LOGI(TAG, "test esp_coexist_adapter.h MD5..."); TEST_ESP_OK(esp_coex_adapter_funcs_md5_check(test_coex_adapter_funcs_md5)); ESP_LOGI(TAG, "test passed..."); } + +TEST_CASE("wifi type MD5","[wifi]") +{ + const char *test_wifi_type_md5 = WIFI_TYPE_MD5; + + ESP_LOGI(TAG, "test esp_wifi_types.h MD5..."); + TEST_ESP_OK(esp_wifi_internal_wifi_type_md5_check(test_wifi_type_md5)); + + ESP_LOGI(TAG, "test passed..."); +} + +TEST_CASE("esp wifi MD5","[wifi]") +{ + const char *test_esp_wifi_md5 = WIFI_ESP_WIFI_MD5; + + ESP_LOGI(TAG, "test esp_wifi.h MD5..."); + TEST_ESP_OK(esp_wifi_internal_esp_wifi_md5_check(test_esp_wifi_md5)); + + ESP_LOGI(TAG, "test passed..."); +} From 3eda52f6cda9162e21d67a16c67f10943b1a4222 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 12 Jun 2019 14:55:58 +0200 Subject: [PATCH 312/486] mqtt: update example documentation on generating a certificate for ssl authentication to hosts Closes https://github.com/espressif/esp-idf/issues/3593 --- examples/protocols/mqtt/ssl/README.md | 9 +++++++-- examples/protocols/mqtt/ssl_mutual_auth/README.md | 1 + examples/protocols/mqtt/tcp/README.md | 2 ++ examples/protocols/mqtt/ws/README.md | 1 + examples/protocols/mqtt/wss/README.md | 8 +++++++- 5 files changed, 18 insertions(+), 3 deletions(-) diff --git a/examples/protocols/mqtt/ssl/README.md b/examples/protocols/mqtt/ssl/README.md index 5925c4001e..db711fdcf1 100644 --- a/examples/protocols/mqtt/ssl/README.md +++ b/examples/protocols/mqtt/ssl/README.md @@ -3,6 +3,7 @@ (See the README.md file in the upper level 'examples' directory for more information about examples.) This example connects to the broker iot.eclipse.org using ssl transport and as a demonstration subscribes/unsubscribes and send a message on certain topic. +(Please note that the public broker is maintained by the community so may not be always available, for details please see this [disclaimer](https://iot.eclipse.org/getting-started/#sandboxes)) It uses ESP-MQTT library which implements mqtt client to connect to mqtt broker. @@ -18,10 +19,14 @@ This example can be executed on any ESP32 board, the only required interface is * Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. * When using Make build system, set `Default serial port` under `Serial flasher config`. -Note how to create a PEM certificate for iot.eclipse.org: +PEM certificate for this example could be extracted from an openssl `s_client` command connecting to iot.eclipse.org. +In case a host operating system has `openssl` and `sed` packages installed, one could execute the following command to download and save the root certificate to a file (Note for Windows users: Both Linux like environment or Windows native packages may be used). ``` -openssl s_client -showcerts -connect iot.eclipse.org:8883 /dev/null|openssl x509 -outform PEM >iot_eclipse_org.pem +echo "" | openssl s_client -showcerts -connect iot.eclipse.org:8883 | sed -n "1,/Root/d; /BEGIN/,/END/p" | openssl x509 -outform PEM >iot_eclipse_org.pem ``` +Please note that this is not a general command for downloading a root certificate for an arbitrary host; +this command works with iot.eclipse.org as the site provides root certificate in the chain, which then could be extracted +with text operation. ### Build and Flash diff --git a/examples/protocols/mqtt/ssl_mutual_auth/README.md b/examples/protocols/mqtt/ssl_mutual_auth/README.md index 9b20b37cad..bf5b57d704 100644 --- a/examples/protocols/mqtt/ssl_mutual_auth/README.md +++ b/examples/protocols/mqtt/ssl_mutual_auth/README.md @@ -3,6 +3,7 @@ (See the README.md file in the upper level 'examples' directory for more information about examples.) This example connects to the broker test.mosquitto.org using ssl transport with client certificate and as a demonstration subscribes/unsubscribes and send a message on certain topic. +(Please note that the public broker is maintained by the community so may not be always available, for details please visit http://test.mosquitto.org) It uses ESP-MQTT library which implements mqtt client to connect to mqtt broker. diff --git a/examples/protocols/mqtt/tcp/README.md b/examples/protocols/mqtt/tcp/README.md index 7247a7a228..7920a75e9e 100644 --- a/examples/protocols/mqtt/tcp/README.md +++ b/examples/protocols/mqtt/tcp/README.md @@ -2,6 +2,8 @@ (See the README.md file in the upper level 'examples' directory for more information about examples.) This example connects to the broker URI selected using `make menuconfig` (using mqtt tcp transport) and as a demonstration subscribes/unsubscribes and send a message on certain topic. +(Please note that the public broker is maintained by the community so may not be always available, for details please see this [disclaimer](https://iot.eclipse.org/getting-started/#sandboxes)) + Note: If the URI equals `FROM_STDIN` then the broker address is read from stdin upon application startup (used for testing) It uses ESP-MQTT library which implements mqtt client to connect to mqtt broker. diff --git a/examples/protocols/mqtt/ws/README.md b/examples/protocols/mqtt/ws/README.md index 236521f90e..d0eff6be29 100644 --- a/examples/protocols/mqtt/ws/README.md +++ b/examples/protocols/mqtt/ws/README.md @@ -3,6 +3,7 @@ (See the README.md file in the upper level 'examples' directory for more information about examples.) This example connects to the broker iot.eclipse.org over web sockets as a demonstration subscribes/unsubscribes and send a message on certain topic. +(Please note that the public broker is maintained by the community so may not be always available, for details please see this [disclaimer](https://iot.eclipse.org/getting-started/#sandboxes)) It uses ESP-MQTT library which implements mqtt client to connect to mqtt broker. diff --git a/examples/protocols/mqtt/wss/README.md b/examples/protocols/mqtt/wss/README.md index 453d52f70f..1877979308 100644 --- a/examples/protocols/mqtt/wss/README.md +++ b/examples/protocols/mqtt/wss/README.md @@ -2,6 +2,7 @@ (See the README.md file in the upper level 'examples' directory for more information about examples.) This example connects to the broker iot.eclipse.org over secure websockets and as a demonstration subscribes/unsubscribes and send a message on certain topic. +(Please note that the public broker is maintained by the community so may not be always available, for details please see this [disclaimer](https://iot.eclipse.org/getting-started/#sandboxes)) It uses ESP-MQTT library which implements mqtt client to connect to mqtt broker. @@ -19,9 +20,14 @@ This example can be executed on any ESP32 board, the only required interface is Note how to create a PEM certificate for iot.eclipse.org: +PEM certificate for this example could be extracted from an openssl `s_client` command connecting to iot.eclipse.org. +In case a host operating system has `openssl` and `sed` packages installed, one could execute the following command to download and save the root certificate to a file (Note for Windows users: Both Linux like environment or Windows native packages may be used). ``` -openssl s_client -showcerts -connect iot.eclipse.org:8883 /dev/null|openssl x509 -outform PEM >iot_eclipse_org.pem +echo "" | openssl s_client -showcerts -connect iot.eclipse.org:443 | sed -n "1,/Root/d; /BEGIN/,/END/p" | openssl x509 -outform PEM >iot_eclipse_org.pem ``` +Please note that this is not a general command for downloading a root certificate for an arbitrary host; +this command works with iot.eclipse.org as the site provides root certificate in the chain, which then could be extracted +with text operation. ### Build and Flash From 034440b85d534e59fb7ba8b0d2026b9e6cc6217b Mon Sep 17 00:00:00 2001 From: liu zhifu Date: Thu, 11 Jul 2019 18:00:40 +0800 Subject: [PATCH 313/486] esp_wifi: fix smartconfig crash when no AP is found Fix the bug that smartconfig crashes when no AP is found during smartconfig scan. --- components/esp_wifi/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index 15c50f3925..13169fc77b 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit 15c50f392523d4dab32a0a5ab3cec7fd611ea471 +Subproject commit 13169fc77b7d9a7d1d740c44905444275b6557ad From 9b507c45c86cf491466d705cd7896c6f6e500d0d Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 20 Jun 2019 17:48:11 +0200 Subject: [PATCH 314/486] ws_client: fix double delete issue in ws client initialization --- .../esp_websocket_client.c | 26 +++---------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/components/esp_websocket_client/esp_websocket_client.c b/components/esp_websocket_client/esp_websocket_client.c index e545559dc8..a066c288c9 100644 --- a/components/esp_websocket_client/esp_websocket_client.c +++ b/components/esp_websocket_client/esp_websocket_client.c @@ -153,42 +153,24 @@ static esp_err_t esp_websocket_client_set_config(esp_websocket_client_handle_t c if (config->username) { free(cfg->username); cfg->username = strdup(config->username); - ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->username, { - free(cfg->host); - return ESP_ERR_NO_MEM; - }); + ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->username, return ESP_ERR_NO_MEM); } if (config->password) { free(cfg->password); cfg->password = strdup(config->password); - ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->password, { - free(cfg->host); - free(cfg->username); - return ESP_ERR_NO_MEM; - }); + ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->password, return ESP_ERR_NO_MEM); } if (config->uri) { free(cfg->uri); cfg->uri = strdup(config->uri); - ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->uri, { - free(cfg->host); - free(cfg->username); - free(cfg->password); - return ESP_ERR_NO_MEM; - }); + ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->uri, return ESP_ERR_NO_MEM); } if (config->path) { free(cfg->path); cfg->path = strdup(config->path); - ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->path, { - free(cfg->uri); - free(cfg->host); - free(cfg->username); - free(cfg->password); - return ESP_ERR_NO_MEM; - }); + ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->path, return ESP_ERR_NO_MEM); } cfg->network_timeout_ms = WEBSOCKET_NETWORK_TIMEOUT_MS; From 632b01602850ba71d2f2a5dab66cc23dbc2d066b Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Tue, 25 Jun 2019 19:23:10 +0800 Subject: [PATCH 315/486] esp32: Dis interrupts up to 5 lvl for DPORT Disable interrupts for both DPORT workarounds up to 5 lvl. Closes: https://esp32.com/viewtopic.php?f=2&t=10981&sid=d125cec233070ed4d2c5410bf5d3d74a Closes: IDF-728 --- components/esp32/Kconfig | 7 +++++++ components/esp32/dport_access.c | 2 +- components/esp32/dport_panic_highint_hdl.S | 9 +++++++-- components/esp32/include/esp32/dport_access.h | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 6fdfcc3e2a..847560fe05 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -741,6 +741,13 @@ menu "ESP32-specific" Please note that the actual length will be reduced by BT_RESERVE_DRAM if Bluetooth controller is enabled. + config ESP32_DPORT_DIS_INTERRUPT_LVL + int "Disable the interrupt level for the DPORT workarounds" + default 5 + help + To prevent interrupting DPORT workarounds, + need to disable interrupt with a maximum used level in the system. + endmenu # ESP32-Specific menu "Power Management" diff --git a/components/esp32/dport_access.c b/components/esp32/dport_access.c index de828eb061..2c83583350 100644 --- a/components/esp32/dport_access.c +++ b/components/esp32/dport_access.c @@ -256,7 +256,7 @@ uint32_t IRAM_ATTR esp_dport_access_reg_read(uint32_t reg) unsigned int intLvl; __asm__ __volatile__ (\ "movi %[APB], "XTSTR(0x3ff40078)"\n"\ - "rsil %[LVL], "XTSTR(3)"\n"\ + "rsil %[LVL], "XTSTR(CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL)"\n"\ "l32i %[APB], %[APB], 0\n"\ "l32i %[REG], %[REG], 0\n"\ "wsr %[LVL], "XTSTR(PS)"\n"\ diff --git a/components/esp32/dport_panic_highint_hdl.S b/components/esp32/dport_panic_highint_hdl.S index 924d77b2f0..7291628635 100644 --- a/components/esp32/dport_panic_highint_hdl.S +++ b/components/esp32/dport_panic_highint_hdl.S @@ -31,9 +31,10 @@ Interrupt , a high-priority interrupt, is used for several things: */ -#define L4_INTR_STACK_SIZE 8 +#define L4_INTR_STACK_SIZE 12 #define L4_INTR_A2_OFFSET 0 #define L4_INTR_A3_OFFSET 4 +#define L4_INTR_A4_OFFSET 8 .data _l4_intr_stack: .space L4_INTR_STACK_SIZE @@ -145,10 +146,11 @@ xt_highint4: movi a0, (1< Date: Fri, 28 Jun 2019 13:34:19 +0800 Subject: [PATCH 316/486] esp32: Add UTs for DPORT and Hi-interrupt --- components/esp32/test/CMakeLists.txt | 2 + components/esp32/test/component.mk | 3 +- components/esp32/test/test_dport.c | 93 ++++++++++++++++++- .../esp32/test/test_dport_xt_highint5.S | 80 ++++++++++++++++ 4 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 components/esp32/test/test_dport_xt_highint5.S diff --git a/components/esp32/test/CMakeLists.txt b/components/esp32/test/CMakeLists.txt index b36af1bd1d..624f11d598 100644 --- a/components/esp32/test/CMakeLists.txt +++ b/components/esp32/test/CMakeLists.txt @@ -12,3 +12,5 @@ add_custom_target(esp32_test_logo DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/test_tjpg add_dependencies(${COMPONENT_LIB} esp32_test_logo) idf_build_set_property(COMPILE_DEFINITIONS "-DESP_TIMER_DYNAMIC_OVERFLOW_VAL" APPEND) + +target_link_libraries(${COMPONENT_LIB} INTERFACE "-u ld_include_test_dport_xt_highint5") diff --git a/components/esp32/test/component.mk b/components/esp32/test/component.mk index eefb592ac2..d4b5a9012f 100644 --- a/components/esp32/test/component.mk +++ b/components/esp32/test/component.mk @@ -4,7 +4,8 @@ COMPONENT_EXTRA_CLEAN := test_tjpgd_logo.h -COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive +COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive \ + -u ld_include_test_dport_xt_highint5 \ COMPONENT_SRCDIRS := . diff --git a/components/esp32/test/test_dport.c b/components/esp32/test/test_dport.c index ac8498631a..fc485436d5 100644 --- a/components/esp32/test/test_dport.c +++ b/components/esp32/test/test_dport.c @@ -1,5 +1,7 @@ #include #include +#include "xtensa/core-macros.h" +#include "xtensa/hal.h" #include "esp_types.h" #include "esp32/clk.h" @@ -14,11 +16,14 @@ #include "soc/uart_periph.h" #include "soc/dport_reg.h" #include "soc/rtc.h" +#include "esp_intr_alloc.h" +#include "driver/timer.h" #define MHZ (1000000) static volatile bool exit_flag; static bool dport_test_result; static bool apb_test_result; +uint32_t volatile apb_intr_test_result; static void accessDPORT(void *pvParameters) { @@ -60,6 +65,7 @@ static void accessAPB(void *pvParameters) void run_tasks(const char *task1_description, void (* task1_func)(void *), const char *task2_description, void (* task2_func)(void *), uint32_t delay_ms) { + apb_intr_test_result = 1; int i; TaskHandle_t th[2]; xSemaphoreHandle exit_sema[2]; @@ -94,7 +100,7 @@ void run_tasks(const char *task1_description, void (* task1_func)(void *), const vSemaphoreDelete(exit_sema[i]); } } - TEST_ASSERT(dport_test_result == true && apb_test_result == true); + TEST_ASSERT(dport_test_result == true && apb_test_result == true && apb_intr_test_result == 1); } TEST_CASE("access DPORT and APB at same time", "[esp32]") @@ -324,3 +330,88 @@ TEST_CASE("BENCHMARK for DPORT access performance", "[freertos]") } BENCHMARK_END("_DPORT_REG_READ"); } + +uint32_t xt_highint5_read_apb; + +#ifndef CONFIG_FREERTOS_UNICORE +timer_isr_handle_t inth; +xSemaphoreHandle sync_sema; + +static void init_hi_interrupt(void *arg) +{ + printf("init hi_interrupt on CPU%d \n", xPortGetCoreID()); + TEST_ESP_OK(esp_intr_alloc(ETS_INTERNAL_TIMER2_INTR_SOURCE, ESP_INTR_FLAG_LEVEL5 | ESP_INTR_FLAG_IRAM, NULL, NULL, &inth)); + while (exit_flag == false); + esp_intr_free(inth); + printf("disable hi_interrupt on CPU%d \n", xPortGetCoreID()); + vTaskDelete(NULL); +} + +static void accessDPORT2_stall_other_cpu(void *pvParameters) +{ + xSemaphoreHandle *sema = (xSemaphoreHandle *) pvParameters; + dport_test_result = true; + while (exit_flag == false) { + DPORT_STALL_OTHER_CPU_START(); + XTHAL_SET_CCOMPARE(2, XTHAL_GET_CCOUNT()); + xt_highint5_read_apb = 1; + for (int i = 0; i < 200; ++i) { + if (_DPORT_REG_READ(DPORT_DATE_REG) != _DPORT_REG_READ(DPORT_DATE_REG)) { + apb_test_result = false; + break; + } + } + xt_highint5_read_apb = 0; + DPORT_STALL_OTHER_CPU_END(); + } + printf("accessDPORT2_stall_other_cpu finish\n"); + + xSemaphoreGive(*sema); + vTaskDelete(NULL); +} + +TEST_CASE("Check stall workaround DPORT and Hi-interrupt", "[esp32]") +{ + xt_highint5_read_apb = 0; + dport_test_result = false; + apb_test_result = true; + TEST_ASSERT(xTaskCreatePinnedToCore(&init_hi_interrupt, "init_hi_intr", 2048, NULL, 6, NULL, 1) == pdTRUE); + // Access DPORT(stall other cpu method) - CPU0 + // STALL - CPU1 + // Hi-interrupt - CPU1 + run_tasks("accessDPORT2_stall_other_cpu", accessDPORT2_stall_other_cpu, " - ", NULL, 10000); +} + +static void accessDPORT2(void *pvParameters) +{ + xSemaphoreHandle *sema = (xSemaphoreHandle *) pvParameters; + dport_test_result = true; + + TEST_ESP_OK(esp_intr_alloc(ETS_INTERNAL_TIMER2_INTR_SOURCE, ESP_INTR_FLAG_LEVEL5 | ESP_INTR_FLAG_IRAM, NULL, NULL, &inth)); + + while (exit_flag == false) { + XTHAL_SET_CCOMPARE(2, XTHAL_GET_CCOUNT() + 21); + for (int i = 0; i < 200; ++i) { + if (DPORT_REG_READ(DPORT_DATE_REG) != DPORT_REG_READ(DPORT_DATE_REG)) { + dport_test_result = false; + break; + } + } + } + esp_intr_free(inth); + printf("accessDPORT2 finish\n"); + + xSemaphoreGive(*sema); + vTaskDelete(NULL); +} + +TEST_CASE("Check pre-read workaround DPORT and Hi-interrupt", "[esp32]") +{ + xt_highint5_read_apb = 0; + dport_test_result = false; + apb_test_result = true; + // Access DPORT(pre-read method) - CPU1 + // Hi-interrupt - CPU1 + run_tasks("accessAPB", accessAPB, "accessDPORT2", accessDPORT2, 10000); +} +#endif // CONFIG_FREERTOS_UNICORE diff --git a/components/esp32/test/test_dport_xt_highint5.S b/components/esp32/test/test_dport_xt_highint5.S new file mode 100644 index 0000000000..d2d1acabed --- /dev/null +++ b/components/esp32/test/test_dport_xt_highint5.S @@ -0,0 +1,80 @@ +#include +#include +#include +#include "freertos/xtensa_context.h" +#include "esp_private/panic_reason.h" +#include "sdkconfig.h" +#include "soc/soc.h" +#include "soc/dport_reg.h" + +#ifndef CONFIG_FREERTOS_UNICORE + +#define L5_INTR_STACK_SIZE 12 +#define L5_INTR_A2_OFFSET 0 +#define L5_INTR_A3_OFFSET 4 +#define L5_INTR_A4_OFFSET 8 + .data +_l5_intr_stack: + .space L5_INTR_STACK_SIZE + + .section .iram1,"ax" + .global xt_highint5 + .type xt_highint5,@function + .align 4 +xt_highint5: + + movi a0, xt_highint5_read_apb + l32i a0, a0, 0 + bnez a0, .read_apb_reg + +// Short interrupt + esync + rsr a0, CCOUNT + addi a0, a0, 27 + wsr a0, CCOMPARE2 + esync + + rsr a0, EXCSAVE_5 // restore a0 + rfi 5 + + + +// read APB reg 10 time. +.read_apb_reg: + movi a0, _l5_intr_stack + s32i a2, a0, L5_INTR_A2_OFFSET + s32i a3, a0, L5_INTR_A3_OFFSET + s32i a4, a0, L5_INTR_A4_OFFSET + + movi a4, 10 // count of reading + movi a0, 0x3ff40078 // read APB reg + l32i a2, a0, 0 +.loop_read_apb_reg: + l32i a3, a0, 0 + bne a3, a2, .need_set_apb_test_result + addi a4, a4, -1 + l32i a2, a0, 0 + bnez a4, .loop_read_apb_reg + j 1f +.need_set_apb_test_result: + movi a0, apb_intr_test_result // set fail + movi a2, 0 + s32i a2, a0, 0 + memw +1: + movi a0, _l5_intr_stack + l32i a2, a0, L5_INTR_A2_OFFSET + l32i a3, a0, L5_INTR_A3_OFFSET + l32i a4, a0, L5_INTR_A4_OFFSET + rsync +.L_xt_highint5_exit: + rsr a0, EXCSAVE_5 // restore a0 + rfi 5 + +/* The linker has no reason to link in this file; all symbols it exports are already defined + (weakly!) in the default int handler. Define a symbol here so we can use it to have the + linker inspect this anyway. */ + + .global ld_include_test_dport_xt_highint5 +ld_include_test_dport_xt_highint5: +#endif // CONFIG_FREERTOS_UNICORE From b7d6aa74dd701349bf956be29ad0085de201acd6 Mon Sep 17 00:00:00 2001 From: liu zhifu Date: Tue, 16 Jul 2019 14:09:47 +0800 Subject: [PATCH 317/486] esp_wifi: fix WiFi stop bug Fix the bug that WiFi stop causes esp_wifi_internal_reg_rxcb() fails. --- components/esp_wifi/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index 13169fc77b..e37154f44f 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit 13169fc77b7d9a7d1d740c44905444275b6557ad +Subproject commit e37154f44f7d613e05f094ebb060dffd4f1c6bd7 From 8fc02e860a2842a0ce023076a4bb1e42323f68d4 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 16 Jul 2019 09:47:18 +0200 Subject: [PATCH 318/486] tcp_tansport: websocket layer modifies in-buffer data (for masked transports). This fix reverts the data back to original rather then making a copy. Closes https://github.com/espressif/esp-idf/issues/3774 --- components/tcp_transport/transport_ws.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/components/tcp_transport/transport_ws.c b/components/tcp_transport/transport_ws.c index 599457b895..12aaa3d232 100644 --- a/components/tcp_transport/transport_ws.c +++ b/components/tcp_transport/transport_ws.c @@ -208,7 +208,17 @@ static int _ws_write(esp_transport_handle_t t, int opcode, int mask_flag, const if (len == 0) { return 0; } - return esp_transport_write(ws->parent, buffer, len, timeout_ms); + + int ret = esp_transport_write(ws->parent, buffer, len, timeout_ms); + // in case of masked transport we have to revert back to the original data, as ws layer + // does not create its own copy of data to be sent + if (mask_flag) { + mask = &ws_header[header_len-4]; + for (i = 0; i < len; ++i) { + buffer[i] = (buffer[i] ^ mask[i % 4]); + } + } + return ret; } static int ws_write(esp_transport_handle_t t, const char *b, int len, int timeout_ms) From f29ff2c5520b941e0e9b874b32bb1a7cda5fa48b Mon Sep 17 00:00:00 2001 From: xueyunfei Date: Wed, 10 Jul 2019 03:29:32 -0400 Subject: [PATCH 319/486] Modify IPv6 functionality compatible with lwip2.1.2 --- components/lwip/lwip | 2 +- .../tcpip_adapter/include/tcpip_adapter.h | 8 ++++++++ components/tcpip_adapter/tcpip_adapter_lwip.c | 9 +++++++++ .../udp_multicast/main/Kconfig.projbuild | 3 ++- .../main/udp_multicast_example_main.c | 19 +++++++++---------- 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/components/lwip/lwip b/components/lwip/lwip index bafc54f69b..61d840ff47 160000 --- a/components/lwip/lwip +++ b/components/lwip/lwip @@ -1 +1 @@ -Subproject commit bafc54f69b671f368d7b996d1668b7bd4be55193 +Subproject commit 61d840ff4778f4946c8743f7e412345abcd537f1 diff --git a/components/tcpip_adapter/include/tcpip_adapter.h b/components/tcpip_adapter/include/tcpip_adapter.h index 11f2daaa4a..4c0a4af4fd 100644 --- a/components/tcpip_adapter/include/tcpip_adapter.h +++ b/components/tcpip_adapter/include/tcpip_adapter.h @@ -740,6 +740,14 @@ esp_err_t tcpip_adapter_set_default_wifi_handlers(); */ esp_err_t tcpip_adapter_clear_default_wifi_handlers(); +/** + * @brief Search nefit index through netif interface + * @param[in] tcpip_if Interface to search for netif index + * @return + * - netif_index on success + * - -1 if an invalid parameter is supplied + */ +int tcpip_adapter_get_netif_index(tcpip_adapter_if_t tcpip_if); #ifdef __cplusplus } diff --git a/components/tcpip_adapter/tcpip_adapter_lwip.c b/components/tcpip_adapter/tcpip_adapter_lwip.c index 88413d3a95..237b082a34 100644 --- a/components/tcpip_adapter/tcpip_adapter_lwip.c +++ b/components/tcpip_adapter/tcpip_adapter_lwip.c @@ -29,6 +29,7 @@ #include "lwip/netif.h" #if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ #include "lwip/dns.h" +#include "lwip/netif.h" #endif #include "netif/wlanif.h" #include "netif/ethernetif.h" @@ -1258,4 +1259,12 @@ bool tcpip_adapter_is_netif_up(tcpip_adapter_if_t tcpip_if) } } +int tcpip_adapter_get_netif_index(tcpip_adapter_if_t tcpip_if) +{ + if (tcpip_if >= TCPIP_ADAPTER_IF_MAX || esp_netif[tcpip_if] == NULL) { + return -1; + } + return netif_get_index(esp_netif[tcpip_if]); +} + #endif /* CONFIG_TCPIP_LWIP */ diff --git a/examples/protocols/sockets/udp_multicast/main/Kconfig.projbuild b/examples/protocols/sockets/udp_multicast/main/Kconfig.projbuild index 99e01387b3..dcf9b0f4ed 100644 --- a/examples/protocols/sockets/udp_multicast/main/Kconfig.projbuild +++ b/examples/protocols/sockets/udp_multicast/main/Kconfig.projbuild @@ -71,7 +71,8 @@ menu "Example Configuration" Multicast socket can bind to default interface, or all interfaces. config EXAMPLE_MULTICAST_LISTEN_ALL_IF - bool "All interfaces" + bool "All interfaces (IPV4 only)" + depends on !EXAMPLE_IPV6_ONLY config EXAMPLE_MULTICAST_LISTEN_DEFAULT_IF bool "Default interface" diff --git a/examples/protocols/sockets/udp_multicast/main/udp_multicast_example_main.c b/examples/protocols/sockets/udp_multicast/main/udp_multicast_example_main.c index ea438991aa..bd2a4cbedf 100644 --- a/examples/protocols/sockets/udp_multicast/main/udp_multicast_example_main.c +++ b/examples/protocols/sockets/udp_multicast/main/udp_multicast_example_main.c @@ -170,7 +170,7 @@ err: static int create_multicast_ipv6_socket() { struct sockaddr_in6 saddr = { 0 }; - u8_t netif_index = EXAMPLE_INTERFACE; + int netif_index; struct in6_addr if_inaddr = { 0 }; struct ip6_addr if_ipaddr = { 0 }; struct ipv6_mreq v6imreq = { 0 }; @@ -211,6 +211,12 @@ static int create_multicast_ipv6_socket() } #endif // LISTEN_ALL_IF + // search for netif index + netif_index = tcpip_adapter_get_netif_index(EXAMPLE_INTERFACE); + if(netif_index < 0) { + ESP_LOGE(V6TAG, "Failed to get netif index"); + goto err; + } // Assign the multicast source interface, via its IP err = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &netif_index,sizeof(uint8_t)); if (err < 0) { @@ -240,14 +246,6 @@ static int create_multicast_ipv6_socket() // this is also a listening socket, so add it to the multicast // group for listening... - - // Configure source interface -#if LISTEN_ALL_IF - v6imreq.imr_interface.s_addr = IPADDR_ANY; -#else - v6imreq.ipv6mr_interface = EXAMPLE_INTERFACE; - /* inet6_addr_from_ip6addr(&v6imreq.ipv6mr_interface, &if_ipaddr);*/ -#endif // LISTEN_ALL_IF #ifdef CONFIG_EXAMPLE_IPV6 // Configure multicast address to listen to err = inet6_aton(MULTICAST_IPV6_ADDR, &v6imreq.ipv6mr_multiaddr); @@ -261,7 +259,8 @@ static int create_multicast_ipv6_socket() if (!ip6_addr_ismulticast(&multi_addr)) { ESP_LOGW(V6TAG, "Configured IPV6 multicast address '%s' is not a valid multicast address. This will probably not work.", MULTICAST_IPV6_ADDR); } - + // Configure source interface + v6imreq.ipv6mr_interface = (unsigned int)netif_index; err = setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &v6imreq, sizeof(struct ipv6_mreq)); if (err < 0) { From f048be924cbaf2d3ef43b21063d251a4d4e7a1ad Mon Sep 17 00:00:00 2001 From: baohongde Date: Fri, 5 Jul 2019 19:53:56 +0800 Subject: [PATCH 320/486] components/bt: Fix AVRCP command will not be executed while playing music --- components/bt/common/btc/core/btc_task.c | 4 +- .../btc/profile/std/a2dp/btc_a2dp_sink.c | 4 +- .../btc/profile/std/a2dp/btc_a2dp_source.c | 4 +- .../classic_bt/a2dp_sink/main/bt_app_av.c | 5 +- .../classic_bt/a2dp_sink/main/bt_app_core.c | 51 +++++++++++++++++++ .../classic_bt/a2dp_sink/main/bt_app_core.h | 6 +++ .../coex/a2dp_gatts_coex/main/bt_app_av.c | 5 +- .../coex/a2dp_gatts_coex/main/bt_app_core.c | 51 +++++++++++++++++++ .../coex/a2dp_gatts_coex/main/bt_app_core.h | 6 +++ 9 files changed, 126 insertions(+), 10 deletions(-) diff --git a/components/bt/common/btc/core/btc_task.c b/components/bt/common/btc/core/btc_task.c index bd70ec6db7..4ac156555b 100644 --- a/components/bt/common/btc/core/btc_task.c +++ b/components/bt/common/btc/core/btc_task.c @@ -166,7 +166,7 @@ static bt_status_t btc_task_post(btc_msg_t *msg, uint32_t timeout) memcpy(lmsg, msg, sizeof(btc_msg_t)); - if (osi_thread_post(btc_thread, btc_thread_handler, lmsg, 2, timeout) == false) { + if (osi_thread_post(btc_thread, btc_thread_handler, lmsg, 0, timeout) == false) { return BT_STATUS_BUSY; } @@ -359,7 +359,7 @@ void btc_deinit(void) bool btc_check_queue_is_congest(void) { - if (osi_thread_queue_wait_size(btc_thread, 2) >= BT_QUEUE_CONGEST_SIZE) { + if (osi_thread_queue_wait_size(btc_thread, 0) >= BT_QUEUE_CONGEST_SIZE) { return true; } diff --git a/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c index 1a65fbbdcf..9ef243231c 100644 --- a/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c +++ b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c @@ -182,7 +182,7 @@ static bool btc_a2dp_sink_ctrl_post(uint32_t sig, void *param) evt->sig = sig; evt->param = param; - return osi_thread_post(a2dp_sink_local_param.btc_aa_snk_task_hdl, btc_a2dp_sink_ctrl_handler, evt, 0, OSI_THREAD_MAX_TIMEOUT); + return osi_thread_post(a2dp_sink_local_param.btc_aa_snk_task_hdl, btc_a2dp_sink_ctrl_handler, evt, 1, OSI_THREAD_MAX_TIMEOUT); } static void btc_a2dp_sink_ctrl_handler(void *arg) @@ -322,7 +322,7 @@ void btc_a2dp_sink_on_suspended(tBTA_AV_SUSPEND *p_av) static void btc_a2dp_sink_data_post(void) { - osi_thread_post(a2dp_sink_local_param.btc_aa_snk_task_hdl, btc_a2dp_sink_data_ready, NULL, 1, OSI_THREAD_MAX_TIMEOUT); + osi_thread_post(a2dp_sink_local_param.btc_aa_snk_task_hdl, btc_a2dp_sink_data_ready, NULL, 2, OSI_THREAD_MAX_TIMEOUT); } /******************************************************************************* diff --git a/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c index 7f1ef366be..aff5521139 100644 --- a/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c +++ b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c @@ -249,7 +249,7 @@ static bool btc_a2dp_source_ctrl_post(uint32_t sig, void *param) evt->sig = sig; evt->param = param; - return osi_thread_post(a2dp_source_local_param.btc_aa_src_task_hdl, btc_a2dp_source_ctrl_handler, evt, 0, OSI_THREAD_MAX_TIMEOUT); + return osi_thread_post(a2dp_source_local_param.btc_aa_src_task_hdl, btc_a2dp_source_ctrl_handler, evt, 1, OSI_THREAD_MAX_TIMEOUT); } static void btc_a2dp_source_ctrl_handler(void *arg) @@ -421,7 +421,7 @@ void btc_a2dp_source_on_suspended(tBTA_AV_SUSPEND *p_av) static void btc_a2dp_source_data_post(void) { - osi_thread_post(a2dp_source_local_param.btc_aa_src_task_hdl, btc_a2dp_source_handle_timer, NULL, 1, OSI_THREAD_MAX_TIMEOUT); + osi_thread_post(a2dp_source_local_param.btc_aa_src_task_hdl, btc_a2dp_source_handle_timer, NULL, 2, OSI_THREAD_MAX_TIMEOUT); } static UINT64 time_now_us() diff --git a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_av.c b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_av.c index 8c2c59924d..17c2edbb3c 100644 --- a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_av.c +++ b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_av.c @@ -69,8 +69,7 @@ void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param) void bt_app_a2d_data_cb(const uint8_t *data, uint32_t len) { - size_t bytes_written; - i2s_write(0, data, len, &bytes_written, portMAX_DELAY); + write_ringbuf(data, len); if (++s_pkt_cnt % 100 == 0) { ESP_LOGI(BT_AV_TAG, "Audio packet count %u", s_pkt_cnt); } @@ -134,8 +133,10 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param) s_a2d_conn_state_str[a2d->conn_stat.state], bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) { esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE); + bt_i2s_task_shut_down(); } else if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTED){ esp_bt_gap_set_scan_mode(ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE); + bt_i2s_task_start_up(); } break; } diff --git a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_core.c b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_core.c index cd9aa99d5f..a46c60050f 100644 --- a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_core.c +++ b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_core.c @@ -16,6 +16,8 @@ #include "freertos/task.h" #include "esp_log.h" #include "bt_app_core.h" +#include "driver/i2s.h" +#include "freertos/ringbuf.h" static void bt_app_task_handler(void *arg); static bool bt_app_send_msg(bt_app_msg_t *msg); @@ -23,6 +25,8 @@ static void bt_app_work_dispatched(bt_app_msg_t *msg); static xQueueHandle s_bt_app_task_queue = NULL; static xTaskHandle s_bt_app_task_handle = NULL; +static xTaskHandle s_bt_i2s_task_handle = NULL; +static RingbufHandle_t ringbuf_i2s = NULL;; bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback) { @@ -111,3 +115,50 @@ void bt_app_task_shut_down(void) s_bt_app_task_queue = NULL; } } + +static void bt_i2s_task_handler(void *arg) +{ + uint8_t *data = NULL; + size_t item_size = 0; + size_t bytes_written = 0; + + for (;;) { + data = (uint8_t *)xRingbufferReceive(ringbuf_i2s, &item_size, (portTickType)portMAX_DELAY); + if (item_size != 0){ + i2s_write(0, data, item_size, &bytes_written, portMAX_DELAY); + vRingbufferReturnItem(ringbuf_i2s,(void *)data); + } + } +} + +void bt_i2s_task_start_up(void) +{ + ringbuf_i2s = xRingbufferCreate(8 * 1024, RINGBUF_TYPE_BYTEBUF); + if(ringbuf_i2s == NULL){ + return; + } + + xTaskCreate(bt_i2s_task_handler, "BtI2ST", 1024, NULL, configMAX_PRIORITIES - 3, &s_bt_i2s_task_handle); + return; +} + +void bt_i2s_task_shut_down(void) +{ + if (s_bt_i2s_task_handle) { + vTaskDelete(s_bt_i2s_task_handle); + s_bt_i2s_task_handle = NULL; + } + + vRingbufferDelete(ringbuf_i2s); + ringbuf_i2s = NULL; +} + +size_t write_ringbuf(const uint8_t *data, size_t size) +{ + BaseType_t done = xRingbufferSend(ringbuf_i2s, (void *)data, size, (portTickType)portMAX_DELAY); + if(done){ + return size; + } else { + return 0; + } +} \ No newline at end of file diff --git a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_core.h b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_core.h index 4415058a71..eaa390de94 100644 --- a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_core.h +++ b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_core.h @@ -44,4 +44,10 @@ void bt_app_task_start_up(void); void bt_app_task_shut_down(void); +void bt_i2s_task_start_up(void); + +void bt_i2s_task_shut_down(void); + +size_t write_ringbuf(const uint8_t *data, size_t size); + #endif /* __BT_APP_CORE_H__ */ diff --git a/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_av.c b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_av.c index 8c2c59924d..17c2edbb3c 100644 --- a/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_av.c +++ b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_av.c @@ -69,8 +69,7 @@ void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param) void bt_app_a2d_data_cb(const uint8_t *data, uint32_t len) { - size_t bytes_written; - i2s_write(0, data, len, &bytes_written, portMAX_DELAY); + write_ringbuf(data, len); if (++s_pkt_cnt % 100 == 0) { ESP_LOGI(BT_AV_TAG, "Audio packet count %u", s_pkt_cnt); } @@ -134,8 +133,10 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param) s_a2d_conn_state_str[a2d->conn_stat.state], bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) { esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE); + bt_i2s_task_shut_down(); } else if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTED){ esp_bt_gap_set_scan_mode(ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE); + bt_i2s_task_start_up(); } break; } diff --git a/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_core.c b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_core.c index cd9aa99d5f..a46c60050f 100644 --- a/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_core.c +++ b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_core.c @@ -16,6 +16,8 @@ #include "freertos/task.h" #include "esp_log.h" #include "bt_app_core.h" +#include "driver/i2s.h" +#include "freertos/ringbuf.h" static void bt_app_task_handler(void *arg); static bool bt_app_send_msg(bt_app_msg_t *msg); @@ -23,6 +25,8 @@ static void bt_app_work_dispatched(bt_app_msg_t *msg); static xQueueHandle s_bt_app_task_queue = NULL; static xTaskHandle s_bt_app_task_handle = NULL; +static xTaskHandle s_bt_i2s_task_handle = NULL; +static RingbufHandle_t ringbuf_i2s = NULL;; bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback) { @@ -111,3 +115,50 @@ void bt_app_task_shut_down(void) s_bt_app_task_queue = NULL; } } + +static void bt_i2s_task_handler(void *arg) +{ + uint8_t *data = NULL; + size_t item_size = 0; + size_t bytes_written = 0; + + for (;;) { + data = (uint8_t *)xRingbufferReceive(ringbuf_i2s, &item_size, (portTickType)portMAX_DELAY); + if (item_size != 0){ + i2s_write(0, data, item_size, &bytes_written, portMAX_DELAY); + vRingbufferReturnItem(ringbuf_i2s,(void *)data); + } + } +} + +void bt_i2s_task_start_up(void) +{ + ringbuf_i2s = xRingbufferCreate(8 * 1024, RINGBUF_TYPE_BYTEBUF); + if(ringbuf_i2s == NULL){ + return; + } + + xTaskCreate(bt_i2s_task_handler, "BtI2ST", 1024, NULL, configMAX_PRIORITIES - 3, &s_bt_i2s_task_handle); + return; +} + +void bt_i2s_task_shut_down(void) +{ + if (s_bt_i2s_task_handle) { + vTaskDelete(s_bt_i2s_task_handle); + s_bt_i2s_task_handle = NULL; + } + + vRingbufferDelete(ringbuf_i2s); + ringbuf_i2s = NULL; +} + +size_t write_ringbuf(const uint8_t *data, size_t size) +{ + BaseType_t done = xRingbufferSend(ringbuf_i2s, (void *)data, size, (portTickType)portMAX_DELAY); + if(done){ + return size; + } else { + return 0; + } +} \ No newline at end of file diff --git a/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_core.h b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_core.h index 4415058a71..eaa390de94 100644 --- a/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_core.h +++ b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_core.h @@ -44,4 +44,10 @@ void bt_app_task_start_up(void); void bt_app_task_shut_down(void); +void bt_i2s_task_start_up(void); + +void bt_i2s_task_shut_down(void); + +size_t write_ringbuf(const uint8_t *data, size_t size); + #endif /* __BT_APP_CORE_H__ */ From 45dd6175cddc5a9103a89566df995a522cbe6703 Mon Sep 17 00:00:00 2001 From: liu zhifu Date: Tue, 16 Jul 2019 10:17:48 +0800 Subject: [PATCH 321/486] esp_wifi: optimize wifi rx --- components/esp_wifi/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index e37154f44f..95edac5610 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit e37154f44f7d613e05f094ebb060dffd4f1c6bd7 +Subproject commit 95edac56107deb9a19366e4566678764cdf8af1a From bd219609556b8ee016d2ae27c25c9fb2acb92adf Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Tue, 16 Jul 2019 16:39:12 +0200 Subject: [PATCH 322/486] tools: Support sdkconfig.rename files from outside IDF in confgen.py --- docs/conf_common.py | 3 ++ make/project_config.mk | 5 +++ tools/cmake/kconfig.cmake | 11 ++++++ tools/kconfig_new/confgen.py | 59 +++++++++++++++------------------ tools/kconfig_new/config.env.in | 1 + tools/kconfig_new/confserver.py | 12 +++++-- 6 files changed, 56 insertions(+), 35 deletions(-) diff --git a/docs/conf_common.py b/docs/conf_common.py index 8fd13cbaf2..505dab8a0c 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -93,13 +93,16 @@ temp_sdkconfig_path = '{}/sdkconfig.tmp'.format(builddir) kconfigs = find_component_files("../../components", "Kconfig") kconfig_projbuilds = find_component_files("../../components", "Kconfig.projbuild") +sdkconfig_renames = find_component_files("../../components", "sdkconfig.rename") confgen_args = [sys.executable, "../../tools/kconfig_new/confgen.py", "--kconfig", "../../Kconfig", + "--sdkconfig-rename", "../../sdkconfig.rename", "--config", temp_sdkconfig_path, "--env", "COMPONENT_KCONFIGS={}".format(" ".join(kconfigs)), "--env", "COMPONENT_KCONFIGS_PROJBUILD={}".format(" ".join(kconfig_projbuilds)), + "--env", "COMPONENT_SDKCONFIG_RENAMES={}".format(" ".join(sdkconfig_renames)), "--env", "IDF_PATH={}".format(idf_path), "--output", "docs", kconfig_inc_path + '.in' ] diff --git a/make/project_config.mk b/make/project_config.mk index e590b401f4..7eede5ebbc 100644 --- a/make/project_config.mk +++ b/make/project_config.mk @@ -3,6 +3,7 @@ #Find all Kconfig files for all components COMPONENT_KCONFIGS := $(foreach component,$(COMPONENT_PATHS),$(wildcard $(component)/Kconfig)) COMPONENT_KCONFIGS_PROJBUILD := $(foreach component,$(COMPONENT_PATHS),$(wildcard $(component)/Kconfig.projbuild)) +COMPONENT_SDKCONFIG_RENAMES := $(foreach component,$(COMPONENT_PATHS),$(wildcard $(component)/sdkconfig.rename)) ifeq ($(OS),Windows_NT) # kconfiglib requires Windows-style paths for kconfig files @@ -17,6 +18,8 @@ KCONFIG_TOOL_DIR=$(IDF_PATH)/tools/kconfig # unless it's overriden (happens for bootloader) SDKCONFIG ?= $(PROJECT_PATH)/sdkconfig +SDKCONFIG_RENAME ?= $(IDF_PATH)/sdkconfig.rename + # SDKCONFIG_DEFAULTS is an optional file containing default # overrides (usually used for esp-idf examples) SDKCONFIG_DEFAULTS ?= $(PROJECT_PATH)/sdkconfig.defaults @@ -48,8 +51,10 @@ define RunConfGen $(PYTHON) $(IDF_PATH)/tools/kconfig_new/confgen.py \ --kconfig $(IDF_PATH)/Kconfig \ --config $(SDKCONFIG) \ + --sdkconfig-rename $(SDKCONFIG_RENAME) \ --env "COMPONENT_KCONFIGS=$(strip $(COMPONENT_KCONFIGS))" \ --env "COMPONENT_KCONFIGS_PROJBUILD=$(strip $(COMPONENT_KCONFIGS_PROJBUILD))" \ + --env "COMPONENT_SDKCONFIG_RENAMES=$(strip $(COMPONENT_SDKCONFIG_RENAMES))" \ --env "IDF_CMAKE=n" \ --output config ${SDKCONFIG} \ --output makefile $(SDKCONFIG_MAKEFILE) \ diff --git a/tools/cmake/kconfig.cmake b/tools/cmake/kconfig.cmake index 561c95ccd2..d1d34234d4 100644 --- a/tools/cmake/kconfig.cmake +++ b/tools/cmake/kconfig.cmake @@ -72,6 +72,7 @@ function(__kconfig_init) idf_build_get_property(idf_path IDF_PATH) idf_build_set_property(__ROOT_KCONFIG ${idf_path}/Kconfig) + idf_build_set_property(__ROOT_SDKCONFIG_RENAME ${idf_path}/sdkconfig.rename) idf_build_set_property(__OUTPUT_SDKCONFIG 1) endfunction() @@ -86,6 +87,8 @@ function(__kconfig_component_init component_target) __component_set_property(${component_target} KCONFIG "${kconfig}") file(GLOB kconfig "${component_dir}/Kconfig.projbuild") __component_set_property(${component_target} KCONFIG_PROJBUILD "${kconfig}") + file(GLOB sdkconfig_rename "${component_dir}/sdkconfig.rename") + __component_set_property(${component_target} SDKCONFIG_RENAME "${sdkconfig_rename}") endfunction() # @@ -100,12 +103,16 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) if(component_target IN_LIST build_component_targets) __component_get_property(kconfig ${component_target} KCONFIG) __component_get_property(kconfig_projbuild ${component_target} KCONFIG_PROJBUILD) + __component_get_property(sdkconfig_rename ${component_target} SDKCONFIG_RENAME) if(kconfig) list(APPEND kconfigs ${kconfig}) endif() if(kconfig_projbuild) list(APPEND kconfig_projbuilds ${kconfig_projbuild}) endif() + if(sdkconfig_rename) + list(APPEND sdkconfig_renames ${sdkconfig_rename}) + endif() endif() endforeach() @@ -118,6 +125,7 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) string(REPLACE ";" " " kconfigs "${kconfigs}") string(REPLACE ";" " " kconfig_projbuilds "${kconfig_projbuilds}") + string(REPLACE ";" " " sdkconfig_renames "${sdkconfig_renames}") # Place config-related environment arguments into config.env file # to work around command line length limits for execute_process @@ -135,11 +143,13 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) endif() idf_build_get_property(root_kconfig __ROOT_KCONFIG) + idf_build_get_property(root_sdkconfig_rename __ROOT_SDKCONFIG_RENAME) idf_build_get_property(python PYTHON) set(confgen_basecommand ${python} ${idf_path}/tools/kconfig_new/confgen.py --kconfig ${root_kconfig} + --sdkconfig-rename ${root_sdkconfig_rename} --config ${sdkconfig} ${defaults_arg} --env-file ${config_env_path}) @@ -231,6 +241,7 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) COMMAND ${PYTHON} ${IDF_PATH}/tools/kconfig_new/confserver.py --env-file ${config_env_path} --kconfig ${IDF_PATH}/Kconfig + --sdkconfig-rename ${root_sdkconfig_rename} --config ${sdkconfig} VERBATIM USES_TERMINAL) diff --git a/tools/kconfig_new/confgen.py b/tools/kconfig_new/confgen.py index e58f55efbf..0af2be1bcc 100755 --- a/tools/kconfig_new/confgen.py +++ b/tools/kconfig_new/confgen.py @@ -22,7 +22,6 @@ # limitations under the License. from __future__ import print_function import argparse -import fnmatch import json import os import os.path @@ -46,15 +45,15 @@ class DeprecatedOptions(object): _RE_DEP_OP_BEGIN = re.compile(_DEP_OP_BEGIN) _RE_DEP_OP_END = re.compile(_DEP_OP_END) - def __init__(self, config_prefix, path_rename_files, ignore_dirs=()): + def __init__(self, config_prefix, path_rename_files=[]): self.config_prefix = config_prefix # r_dic maps deprecated options to new options; rev_r_dic maps in the opposite direction - self.r_dic, self.rev_r_dic = self._parse_replacements(path_rename_files, ignore_dirs) + self.r_dic, self.rev_r_dic = self._parse_replacements(path_rename_files) # note the '=' at the end of regex for not getting partial match of configs self._RE_CONFIG = re.compile(r'{}(\w+)='.format(self.config_prefix)) - def _parse_replacements(self, repl_dir, ignore_dirs): + def _parse_replacements(self, repl_paths): rep_dic = {} rev_rep_dic = {} @@ -64,31 +63,24 @@ class DeprecatedOptions(object): raise RuntimeError('Error in {} (line {}): Config {} is not prefixed with {}' ''.format(rep_path, line_number, string, self.config_prefix)) - for root, dirnames, filenames in os.walk(repl_dir): - for filename in fnmatch.filter(filenames, self._REN_FILE): - rep_path = os.path.join(root, filename) + for rep_path in repl_paths: + with open(rep_path) as f_rep: + for line_number, line in enumerate(f_rep, start=1): + sp_line = line.split() + if len(sp_line) == 0 or sp_line[0].startswith('#'): + # empty line or comment + continue + if len(sp_line) != 2 or not all(x.startswith(self.config_prefix) for x in sp_line): + raise RuntimeError('Syntax error in {} (line {})'.format(rep_path, line_number)) + if sp_line[0] in rep_dic: + raise RuntimeError('Error in {} (line {}): Replacement {} exist for {} and new ' + 'replacement {} is defined'.format(rep_path, line_number, + rep_dic[sp_line[0]], sp_line[0], + sp_line[1])) - if rep_path.startswith(ignore_dirs): - print('Ignoring: {}'.format(rep_path)) - continue - - with open(rep_path) as f_rep: - for line_number, line in enumerate(f_rep, start=1): - sp_line = line.split() - if len(sp_line) == 0 or sp_line[0].startswith('#'): - # empty line or comment - continue - if len(sp_line) != 2 or not all(x.startswith(self.config_prefix) for x in sp_line): - raise RuntimeError('Syntax error in {} (line {})'.format(rep_path, line_number)) - if sp_line[0] in rep_dic: - raise RuntimeError('Error in {} (line {}): Replacement {} exist for {} and new ' - 'replacement {} is defined'.format(rep_path, line_number, - rep_dic[sp_line[0]], sp_line[0], - sp_line[1])) - - (dep_opt, new_opt) = (remove_config_prefix(x) for x in sp_line) - rep_dic[dep_opt] = new_opt - rev_rep_dic[new_opt] = dep_opt + (dep_opt, new_opt) = (remove_config_prefix(x) for x in sp_line) + rep_dic[dep_opt] = new_opt + rev_rep_dic[new_opt] = dep_opt return rep_dic, rev_rep_dic def get_deprecated_option(self, new_option): @@ -190,6 +182,10 @@ def main(): help='KConfig file with config item definitions', required=True) + parser.add_argument('--sdkconfig-rename', + help='File with deprecated Kconfig options', + required=False) + parser.add_argument('--output', nargs=2, action='append', help='Write output file (format and output filename)', metavar=('FORMAT', 'FILENAME'), @@ -235,10 +231,9 @@ def main(): raise RuntimeError("Defaults file not found: %s" % name) config.load_config(name, replace=False) - # don't collect rename options from examples because those are separate projects and no need to "stay compatible" - # with example projects - deprecated_options = DeprecatedOptions(config.config_prefix, path_rename_files=os.environ["IDF_PATH"], - ignore_dirs=(os.path.join(os.environ["IDF_PATH"], 'examples'))) + sdkconfig_renames = [args.sdkconfig_rename] if args.sdkconfig_rename else [] + sdkconfig_renames += os.environ.get("COMPONENT_SDKCONFIG_RENAMES", "").split() + deprecated_options = DeprecatedOptions(config.config_prefix, path_rename_files=sdkconfig_renames) # If config file previously exists, load it if args.config and os.path.exists(args.config): diff --git a/tools/kconfig_new/config.env.in b/tools/kconfig_new/config.env.in index d685c85d06..a066b47431 100644 --- a/tools/kconfig_new/config.env.in +++ b/tools/kconfig_new/config.env.in @@ -1,6 +1,7 @@ { "COMPONENT_KCONFIGS": "${kconfigs}", "COMPONENT_KCONFIGS_PROJBUILD": "${kconfig_projbuilds}", + "COMPONENT_SDKCONFIG_RENAMES": "${sdkconfig_renames}", "IDF_CMAKE": "y", "IDF_TARGET": "${idf_target}", "IDF_PATH": "${idf_path}" diff --git a/tools/kconfig_new/confserver.py b/tools/kconfig_new/confserver.py index 914a2dd735..2e0d24ad7e 100755 --- a/tools/kconfig_new/confserver.py +++ b/tools/kconfig_new/confserver.py @@ -29,6 +29,10 @@ def main(): help='KConfig file with config item definitions', required=True) + parser.add_argument('--sdkconfig-rename', + help='File with deprecated Kconfig options', + required=False) + parser.add_argument('--env', action='append', default=[], help='Environment to set when evaluating the config file', metavar='NAME=VAL') @@ -62,12 +66,14 @@ def main(): env = json.load(args.env_file) os.environ.update(env) - run_server(args.kconfig, args.config) + run_server(args.kconfig, args.config, args.sdkconfig_rename) -def run_server(kconfig, sdkconfig, default_version=MAX_PROTOCOL_VERSION): +def run_server(kconfig, sdkconfig, sdkconfig_rename, default_version=MAX_PROTOCOL_VERSION): config = kconfiglib.Kconfig(kconfig) - deprecated_options = confgen.DeprecatedOptions(config.config_prefix, path_rename_files=os.environ["IDF_PATH"]) + sdkconfig_renames = [sdkconfig_rename] if sdkconfig_rename else [] + sdkconfig_renames += os.environ.get("COMPONENT_SDKCONFIG_RENAMES", "").split() + deprecated_options = confgen.DeprecatedOptions(config.config_prefix, path_rename_files=sdkconfig_renames) with tempfile.NamedTemporaryFile(mode='w+b') as f_o: with open(sdkconfig, mode='rb') as f_i: f_o.write(f_i.read()) From 4a0733c33c3fc7d4203a0a7c3f0982307472bc4a Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 17 Jul 2019 12:24:29 +1000 Subject: [PATCH 323/486] test: Set timeout of libsodium ed25519_convert test to 60s Test takes 28s-29s to run in some configs, can fail in CI. --- components/libsodium/test/test_sodium.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/libsodium/test/test_sodium.c b/components/libsodium/test/test_sodium.c index 7a9f096dad..5ab4b0edc4 100644 --- a/components/libsodium/test/test_sodium.c +++ b/components/libsodium/test/test_sodium.c @@ -39,7 +39,7 @@ TEST_CASE("box tests", "[libsodium]") extern int ed25519_convert_xmain(); -TEST_CASE("ed25519_convert tests", "[libsodium]") +TEST_CASE("ed25519_convert tests", "[libsodium][timeout=60]") { printf("Running ed25519_convert\n"); TEST_ASSERT_EQUAL(0, ed25519_convert_xmain() ); From 17791d538441accd75bf5aaf2576413c151eba1c Mon Sep 17 00:00:00 2001 From: KonstantinKondrashov Date: Wed, 17 Jul 2019 10:28:50 +0800 Subject: [PATCH 324/486] app_update: Add [timeout=90] --- components/app_update/test/test_switch_ota.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/components/app_update/test/test_switch_ota.c b/components/app_update/test/test_switch_ota.c index 5622f1e057..bfa7b25bee 100644 --- a/components/app_update/test/test_switch_ota.c +++ b/components/app_update/test/test_switch_ota.c @@ -296,7 +296,7 @@ static void test_flow1(void) // 3 Stage: run OTA0 -> check it -> copy OTA0 to OTA1 -> reboot --//-- // 4 Stage: run OTA1 -> check it -> copy OTA1 to OTA0 -> reboot --//-- // 5 Stage: run OTA0 -> check it -> erase OTA_DATA for next tests -> PASS -TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, OTA1, OTA0", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow1, test_flow1, test_flow1, test_flow1); +TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, OTA1, OTA0", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow1, test_flow1, test_flow1, test_flow1); static void test_flow2(void) { @@ -333,7 +333,7 @@ static void test_flow2(void) // 2 Stage: run factory -> check it -> copy factory to OTA0 -> reboot --//-- // 3 Stage: run OTA0 -> check it -> corrupt ota data -> reboot --//-- // 4 Stage: run factory -> check it -> erase OTA_DATA for next tests -> PASS -TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, corrupt ota_sec1, factory", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow2, test_flow2, test_flow2); +TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, corrupt ota_sec1, factory", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow2, test_flow2, test_flow2); static void test_flow3(void) { @@ -377,7 +377,7 @@ static void test_flow3(void) // 3 Stage: run OTA0 -> check it -> copy OTA0 to OTA1 -> reboot --//-- // 3 Stage: run OTA1 -> check it -> corrupt ota sector2 -> reboot --//-- // 4 Stage: run OTA0 -> check it -> erase OTA_DATA for next tests -> PASS -TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, OTA1, currupt ota_sec2, OTA0", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow3, test_flow3, test_flow3, test_flow3); +TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, OTA1, currupt ota_sec2, OTA0", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow3, test_flow3, test_flow3, test_flow3); #ifdef CONFIG_BOOTLOADER_FACTORY_RESET #define STORAGE_NAMESPACE "update_ota" @@ -444,7 +444,7 @@ static void test_flow4(void) // 2 Stage: run factory -> check it -> copy factory to OTA0 -> reboot --//-- // 3 Stage: run OTA0 -> check it -> set_pin_factory_reset -> reboot --//-- // 4 Stage: run factory -> check it -> erase OTA_DATA for next tests -> PASS -TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, sets pin_factory_reset, factory", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow4, test_flow4, test_flow4); +TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, sets pin_factory_reset, factory", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow4, test_flow4, test_flow4); #endif #ifdef CONFIG_BOOTLOADER_APP_TEST @@ -487,7 +487,7 @@ static void test_flow5(void) // 2 Stage: run factory -> check it -> copy factory to Test and set pin_test_app -> reboot --//-- // 3 Stage: run test -> check it -> reset pin_test_app -> reboot --//-- // 4 Stage: run factory -> check it -> erase OTA_DATA for next tests -> PASS -TEST_CASE_MULTIPLE_STAGES("Switching between factory, test, factory", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow5, test_flow5, test_flow5); +TEST_CASE_MULTIPLE_STAGES("Switching between factory, test, factory", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow5, test_flow5, test_flow5); #endif static const esp_partition_t* app_update(void) @@ -581,7 +581,7 @@ static void test_rollback1_1(void) // 3 Stage: run OTA0 -> check it -> esp_ota_mark_app_valid_cancel_rollback() -> reboot --//-- // 4 Stage: run OTA0 -> check it -> esp_ota_mark_app_invalid_rollback_and_reboot() -> reboot // 5 Stage: run factory -> check it -> erase OTA_DATA for next tests -> PASS -TEST_CASE_MULTIPLE_STAGES("Test rollback. factory, OTA0, OTA0, rollback -> factory", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, SW_CPU_RESET]", start_test, test_rollback1, test_rollback1, test_rollback1, test_rollback1_1); +TEST_CASE_MULTIPLE_STAGES("Test rollback. factory, OTA0, OTA0, rollback -> factory", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, SW_CPU_RESET]", start_test, test_rollback1, test_rollback1, test_rollback1, test_rollback1_1); static void test_rollback2(void) { @@ -679,7 +679,7 @@ static void test_rollback2_1(void) // 3 Stage: run OTA0 -> check it -> esp_ota_mark_app_valid_cancel_rollback(), copy to next app slot -> reboot --//-- // 4 Stage: run OTA1 -> check it -> PENDING_VERIFY/esp_ota_mark_app_invalid_rollback_and_reboot() -> reboot // 5 Stage: run OTA0(rollback) -> check it -> erase OTA_DATA for next tests -> PASS -TEST_CASE_MULTIPLE_STAGES("Test rollback. factory, OTA0, OTA1, rollback -> OTA0", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, SW_CPU_RESET]", start_test, test_rollback2, test_rollback2, test_rollback2, test_rollback2_1); +TEST_CASE_MULTIPLE_STAGES("Test rollback. factory, OTA0, OTA1, rollback -> OTA0", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, SW_CPU_RESET]", start_test, test_rollback2, test_rollback2, test_rollback2, test_rollback2_1); static void test_erase_last_app_flow(void) { @@ -730,4 +730,4 @@ static void test_erase_last_app_rollback(void) // 3 Stage: run OTA0 -> check it -> copy factory to OTA1 -> reboot --//-- // 4 Stage: run OTA1 -> check it -> erase OTA0 and rollback -> reboot // 5 Stage: run factory -> check it -> erase OTA_DATA for next tests -> PASS -TEST_CASE_MULTIPLE_STAGES("Test erase_last_boot_app_partition. factory, OTA1, OTA0, factory", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, SW_CPU_RESET]", start_test, test_erase_last_app_flow, test_erase_last_app_flow, test_erase_last_app_flow, test_erase_last_app_rollback); +TEST_CASE_MULTIPLE_STAGES("Test erase_last_boot_app_partition. factory, OTA1, OTA0, factory", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, SW_CPU_RESET]", start_test, test_erase_last_app_flow, test_erase_last_app_flow, test_erase_last_app_flow, test_erase_last_app_rollback); From 4dd75184e4faef899a4ecb1ce5c7ac341fac4fc8 Mon Sep 17 00:00:00 2001 From: chenyudong Date: Mon, 8 Jul 2019 20:37:49 +0800 Subject: [PATCH 325/486] mesh: fix esp_mesh_stop not return --- components/esp_wifi/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index 95edac5610..7044aba469 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit 95edac56107deb9a19366e4566678764cdf8af1a +Subproject commit 7044aba469592f1eb087f414d0d975984f6694a5 From 7feea264044097c6ba5c0ece33a9fb346b0c54f2 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 16 Jul 2019 17:03:20 +0200 Subject: [PATCH 326/486] docs: getting-started: fix broken links --- docs/en/get-started-legacy/index.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/en/get-started-legacy/index.rst b/docs/en/get-started-legacy/index.rst index bd3d000ce1..fa8791d9af 100644 --- a/docs/en/get-started-legacy/index.rst +++ b/docs/en/get-started-legacy/index.rst @@ -103,13 +103,13 @@ The quickest way to start development with ESP32 is by installing a prebuilt too Windows Linux - MacOS + macOS -+-----------------------------+-------------------------+----------------------------------+ -| |windows-logo| | |linux-logo| | |macos-logo| | -+-----------------------------+-------------------------+----------------------------------+ -| `Windows `_ | `Linux `_ | `Mac OS `_ | -+-----------------------------+-------------------------+----------------------------------+ ++-----------------+---------------+---------------+ +| |windows-logo| | |linux-logo| | |macos-logo| | ++-----------------+---------------+---------------+ +| Windows_ | Linux_ | `macOS`_ | ++-----------------+---------------+---------------+ .. |windows-logo| image:: ../../_static/windows-logo.png :target: ../get-started-legacy/windows-setup.html @@ -120,9 +120,9 @@ The quickest way to start development with ESP32 is by installing a prebuilt too .. |macos-logo| image:: ../../_static/macos-logo.png :target: ../get-started-legacy/macos-setup.html -.. _Windows-legacy: ../get-started-legacy/windows-setup.html -.. _Linux-legacy: ../get-started-legacy/linux-setup.html -.. _Mac OS-legacy: ../get-started-legacy/macos-setup.html +.. _Windows: ../get-started-legacy/windows-setup.html +.. _Linux: ../get-started-legacy/linux-setup.html +.. _macOS: ../get-started-legacy/macos-setup.html .. note:: From e431bfd6c28371a4d9f2fd840a654bc8de501fb5 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 17 Jul 2019 08:31:35 +0200 Subject: [PATCH 327/486] docs: getting-started: correct style of "macOS" name --- docs/en/get-started-legacy/index.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/en/get-started-legacy/index.rst b/docs/en/get-started-legacy/index.rst index fa8791d9af..25292d5d65 100644 --- a/docs/en/get-started-legacy/index.rst +++ b/docs/en/get-started-legacy/index.rst @@ -74,7 +74,7 @@ This is a detailed roadmap to walk you through the installation process. Setting up Development Environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* :ref:`get-started-setup-toolchain-legacy` for :doc:`Windows `, :doc:`Linux ` or :doc:`MacOS ` +* :ref:`get-started-setup-toolchain-legacy` for :doc:`Windows `, :doc:`Linux ` or :doc:`macOS ` * :ref:`get-started-get-esp-idf-legacy` * :ref:`get-started-setup-path-legacy` * :ref:`get-started-get-packages-legacy` @@ -165,7 +165,7 @@ Step 3. Set Environment Variables The toolchain uses the environment variable ``IDF_PATH`` to access the ESP-IDF directory. This variable should be set up on your computer, otherwise projects will not build. -These variables can be set temporarily (per session) or permanently. Please follow the instructions specific to :ref:`Windows ` , :ref:`Linux and MacOS ` in Section :doc:`add-idf_path-to-profile`. +These variables can be set temporarily (per session) or permanently. Please follow the instructions specific to :ref:`Windows ` , :ref:`Linux and macOS ` in Section :doc:`add-idf_path-to-profile`. .. _get-started-get-packages-legacy: @@ -195,7 +195,7 @@ Now you are ready to prepare your application for ESP32. You can start with :exa Copy :example:`get-started/hello_world` to the ``~/esp`` directory: -Linux and MacOS +Linux and macOS ~~~~~~~~~~~~~~~ .. code-block:: bash @@ -246,7 +246,7 @@ Step 7. Configure Navigate to your ``hello_world`` directory from :ref:`get-started-start-project-legacy` and run the project configuration utility ``menuconfig``. -Linux and MacOS +Linux and macOS ~~~~~~~~~~~~~~~ .. code-block:: bash From 7982ed9a7dab214fa4a13cf7279d269ec951f416 Mon Sep 17 00:00:00 2001 From: raldone01 Date: Tue, 16 Jul 2019 17:52:04 +0200 Subject: [PATCH 328/486] newlib: Move _gettimeofday_r call in clock_gettime Signed-off-by: KonstantinKondrashov Merges: https://github.com/espressif/esp-idf/pull/3789 --- components/newlib/time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/newlib/time.c b/components/newlib/time.c index 2eb8b4b271..7fb60e94ac 100644 --- a/components/newlib/time.c +++ b/components/newlib/time.c @@ -414,10 +414,10 @@ int clock_gettime (clockid_t clock_id, struct timespec *tp) return -1; } struct timeval tv; - _gettimeofday_r(NULL, &tv, NULL); uint64_t monotonic_time_us = 0; switch (clock_id) { case CLOCK_REALTIME: + _gettimeofday_r(NULL, &tv, NULL); tp->tv_sec = tv.tv_sec; tp->tv_nsec = tv.tv_usec * 1000L; break; From e9faf132b46d29e4a2ceb5042d4cd8e68882264a Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Wed, 17 Jul 2019 15:53:23 +0300 Subject: [PATCH 329/486] tools: Update recommended OpenOCD version to v0.10.0-esp32-20190708 --- tools/tools.json | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tools/tools.json b/tools/tools.json index 5bbed7e8b7..17ee68efeb 100644 --- a/tools/tools.json +++ b/tools/tools.json @@ -190,26 +190,26 @@ "versions": [ { "linux-amd64": { - "sha256": "e5b5579edffde090e426b4995b346e281843bf84394f8e68c8e41bd1e4c576bd", - "size": 1681596, - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.10.0-esp32-20190313/openocd-esp32-linux64-0.10.0-esp32-20190313.tar.gz" + "sha256": "038affba6cb2874098f6b70e61ce139afdf056f926ea6aefcf4d90a6ccf05bc3", + "size": 1675213, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.10.0-esp32-20190708/openocd-esp32-linux64-0.10.0-esp32-20190708.tar.gz" }, "macos": { - "sha256": "09504eea5aa92646a117f16573c95b34e04b4010791a2f8fefcd2bd8c430f081", - "size": 1760536, - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.10.0-esp32-20190313/openocd-esp32-macos-0.10.0-esp32-20190313.tar.gz" + "sha256": "840c94ce6208c5b21d0ba6c3113a06405daf6b27085a287cfbb6c9d21e80bd70", + "size": 1760060, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.10.0-esp32-20190708/openocd-esp32-macos-0.10.0-esp32-20190708.tar.gz" }, - "name": "v0.10.0-esp32-20190313", + "name": "v0.10.0-esp32-20190708", "status": "recommended", "win32": { - "sha256": "b86a7f9f39dfc4d8e289fc819375bbb7a5e9fcb8895805ba2b5faf67b8b25ce2", - "size": 2098513, - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.10.0-esp32-20190313/openocd-esp32-win32-0.10.0-esp32-20190313.zip" + "sha256": "a3a6f288a501c2992d2950c1b2c502e479e16aedda21b626602933c75f027a13", + "size": 2098530, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.10.0-esp32-20190708/openocd-esp32-win32-0.10.0-esp32-20190708.zip" }, "win64": { - "sha256": "b86a7f9f39dfc4d8e289fc819375bbb7a5e9fcb8895805ba2b5faf67b8b25ce2", - "size": 2098513, - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.10.0-esp32-20190313/openocd-esp32-win32-0.10.0-esp32-20190313.zip" + "sha256": "a3a6f288a501c2992d2950c1b2c502e479e16aedda21b626602933c75f027a13", + "size": 2098530, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.10.0-esp32-20190708/openocd-esp32-win32-0.10.0-esp32-20190708.zip" } } ] From c6c6cd71796105724c8a632fe51f1d6bc58debd3 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 31 May 2019 15:36:00 +0200 Subject: [PATCH 330/486] rtc: fix minor malloc issues found by static analyzer --- components/driver/rtc_module.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/components/driver/rtc_module.c b/components/driver/rtc_module.c index eae2871993..1be5c645ca 100644 --- a/components/driver/rtc_module.c +++ b/components/driver/rtc_module.c @@ -980,25 +980,30 @@ esp_err_t touch_pad_filter_start(uint32_t filter_period_ms) RTC_MODULE_CHECK(filter_period_ms >= portTICK_PERIOD_MS, "Touch pad filter period error", ESP_ERR_INVALID_ARG); RTC_MODULE_CHECK(rtc_touch_mux != NULL, "Touch pad not initialized", ESP_ERR_INVALID_STATE); - esp_err_t ret = ESP_OK; xSemaphoreTake(rtc_touch_mux, portMAX_DELAY); if (s_touch_pad_filter == NULL) { s_touch_pad_filter = (touch_pad_filter_t *) calloc(1, sizeof(touch_pad_filter_t)); if (s_touch_pad_filter == NULL) { - ret = ESP_ERR_NO_MEM; + goto err_no_mem; } } if (s_touch_pad_filter->timer == NULL) { s_touch_pad_filter->timer = xTimerCreate("filter_tmr", filter_period_ms / portTICK_PERIOD_MS, pdFALSE, NULL, touch_pad_filter_cb); if (s_touch_pad_filter->timer == NULL) { - ret = ESP_ERR_NO_MEM; + free(s_touch_pad_filter); + s_touch_pad_filter = NULL; + goto err_no_mem; } s_touch_pad_filter->period = filter_period_ms; } xSemaphoreGive(rtc_touch_mux); touch_pad_filter_cb(NULL); - return ret; + return ESP_OK; + +err_no_mem: + xSemaphoreGive(rtc_touch_mux); + return ESP_ERR_NO_MEM; } esp_err_t touch_pad_filter_stop() From 69504bd9c5572a3a03a6cf1e95fdcf552f5e63a1 Mon Sep 17 00:00:00 2001 From: zhangyanjiao Date: Thu, 18 Jul 2019 11:00:18 +0800 Subject: [PATCH 331/486] phy change for WiFi scan BLE scan watchdog --- components/esp_wifi/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index 7044aba469..7c7c2e3f97 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit 7044aba469592f1eb087f414d0d975984f6694a5 +Subproject commit 7c7c2e3f978ddaeadb1365a0f8fbbcb423886d97 From 8cd04c80f6c524119c373688a14e272c410d3ead Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 11 Apr 2019 21:06:15 +0800 Subject: [PATCH 332/486] efuse: set timing configuration before writing --- components/efuse/src/esp_efuse_utility.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/components/efuse/src/esp_efuse_utility.c b/components/efuse/src/esp_efuse_utility.c index 03ea260840..a4a4d6d87e 100644 --- a/components/efuse/src/esp_efuse_utility.c +++ b/components/efuse/src/esp_efuse_utility.c @@ -15,6 +15,7 @@ #include "esp_efuse_utility.h" #include "soc/efuse_periph.h" +#include "esp32/clk.h" #include "esp_log.h" #include "assert.h" #include "sdkconfig.h" @@ -209,6 +210,25 @@ void esp_efuse_utility_burn_efuses(void) } } #else + // Update Efuse timing configuration + uint32_t apb_freq_mhz = esp_clk_apb_freq() / 1000000; + uint32_t clk_sel0, clk_sel1, dac_clk_div; + if (apb_freq_mhz <= 26) { + clk_sel0 = 250; + clk_sel1 = 255; + dac_clk_div = 52; + } else if (apb_freq_mhz <= 40) { + clk_sel0 = 160; + clk_sel1 = 255; + dac_clk_div = 80; + } else { + clk_sel0 = 80; + clk_sel1 = 128; + dac_clk_div = 100; + } + REG_SET_FIELD(EFUSE_DAC_CONF_REG, EFUSE_DAC_CLK_DIV, dac_clk_div); + REG_SET_FIELD(EFUSE_CLK_REG, EFUSE_CLK_SEL0, clk_sel0); + REG_SET_FIELD(EFUSE_CLK_REG, EFUSE_CLK_SEL1, clk_sel1); // Permanently update values written to the efuse write registers REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_WRITE); REG_WRITE(EFUSE_CMD_REG, EFUSE_CMD_PGM); From e1ef0faccd97c4c38685152c76915b784828e066 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 18 Jul 2019 15:09:17 +1000 Subject: [PATCH 333/486] esptool: Bump to v2.7 https://github.com/espressif/esptool/releases/tag/v2.7 --- components/esptool_py/esptool | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esptool_py/esptool b/components/esptool_py/esptool index b4c418a5d9..1319c49adb 160000 --- a/components/esptool_py/esptool +++ b/components/esptool_py/esptool @@ -1 +1 @@ -Subproject commit b4c418a5d90c94863b44c8661b9332cf229b08b7 +Subproject commit 1319c49adb2fe99d2981151ff781930d6ed62729 From dd443f61e872a3f04c7adfd284e32f381ef157c0 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 2 Jul 2019 18:36:12 +0200 Subject: [PATCH 334/486] tools: add Dockerfile --- tools/ci/executable-list.txt | 1 + tools/docker/Dockerfile | 62 ++++++++++++++++++++++++++++++++++++ tools/docker/entrypoint.sh | 6 ++++ 3 files changed, 69 insertions(+) create mode 100644 tools/docker/Dockerfile create mode 100755 tools/docker/entrypoint.sh diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index bad335f8a3..9ae3ae702e 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -49,6 +49,7 @@ tools/ci/test_build_system_cmake.sh tools/ci/test_configure_ci_environment.sh tools/cmake/convert_to_cmake.py tools/cmake/run_cmake_lint.sh +tools/docker/entrypoint.sh tools/elf_to_ld.sh tools/esp_app_trace/logtrace_proc.py tools/esp_app_trace/sysviewtrace_proc.py diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile new file mode 100644 index 0000000000..05db8cb89b --- /dev/null +++ b/tools/docker/Dockerfile @@ -0,0 +1,62 @@ +FROM ubuntu:18.04 + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y \ + apt-utils \ + bison \ + ca-certificates \ + ccache \ + check \ + cmake \ + curl \ + flex \ + git \ + gperf \ + lcov \ + libncurses-dev \ + libusb-1.0-0-dev \ + make \ + ninja-build \ + python3 \ + python3-pip \ + unzip \ + wget \ + xz-utils \ + zip \ + && apt-get autoremove -y \ + && rm -rf /var/lib/apt/lists/* \ + && update-alternatives --install /usr/bin/python python /usr/bin/python3 10 + +RUN python -m pip install --upgrade pip virtualenv + +# To build the image for a branch or a tag of IDF, pass --build-arg IDF_CLONE_BRANCH_OR_TAG=name. +# To build the image with a specific commit ID of IDF, pass --build-arg IDF_CHECKOUT_REF=commit-id. +# It is possibe to combine both, e.g.: +# IDF_CLONE_BRANCH_OR_TAG=release/vX.Y +# IDF_CHECKOUT_REF=. + +ARG IDF_CLONE_URL=https://github.com/espressif/esp-idf.git +ARG IDF_CLONE_BRANCH_OR_TAG=master +ARG IDF_CHECKOUT_REF= + +ENV IDF_PATH=/opt/esp/idf +ENV IDF_TOOLS_PATH=/opt/esp + +RUN echo IDF_CHECKOUT_REF=$IDF_CHECKOUT_REF IDF_CLONE_BRANCH_OR_TAG=$IDF_CLONE_BRANCH_OR_TAG && \ + git clone --recursive \ + ${IDF_CLONE_BRANCH_OR_TAG:+-b $IDF_CLONE_BRANCH_OR_TAG} \ + $IDF_CLONE_URL $IDF_PATH && \ + if [ -n "$IDF_CHECKOUT_REF" ]; then \ + cd $IDF_PATH && \ + git checkout $IDF_CHECKOUT_REF && \ + git submodule update --init --recursive; \ + fi + +RUN $IDF_PATH/install.sh && \ + rm -rf $IDF_TOOLS_PATH/dist + +COPY entrypoint.sh /opt/esp/entrypoint.sh + +ENTRYPOINT [ "/opt/esp/entrypoint.sh" ] +CMD [ "/bin/bash" ] diff --git a/tools/docker/entrypoint.sh b/tools/docker/entrypoint.sh new file mode 100755 index 0000000000..bb1d3e65a5 --- /dev/null +++ b/tools/docker/entrypoint.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -e + +. $IDF_PATH/export.sh + +exec "$@" From 024176c509684a6da0634c97730c2e9feded0f9f Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 8 Jul 2019 18:42:46 +0200 Subject: [PATCH 335/486] ci: build IDF docker image in CI --- tools/ci/config/build.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tools/ci/config/build.yml b/tools/ci/config/build.yml index 5e6b3cde03..215f5117e7 100644 --- a/tools/ci/config/build.yml +++ b/tools/ci/config/build.yml @@ -259,3 +259,26 @@ test_build_system_cmake: - mkdir test_build_system - cd test_build_system - ${IDF_PATH}/tools/ci/test_build_system_cmake.sh + +build_docker: + stage: build + image: espressif/docker-builder:1 + tags: + - build_docker_amd64_brno + only: + refs: + - master + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ + - schedules + variables: + DOCKER_TMP_IMAGE_NAME: "idf_tmp_image" + before_script: [] + script: + - export DOCKER_BUILD_ARGS="--build-arg IDF_CLONE_URL=${CI_REPOSITORY_URL} --build-arg IDF_CLONE_BRANCH_OR_TAG=${CI_COMMIT_REF_NAME} --build-arg IDF_CHECKOUT_REF=${CI_COMMIT_TAG:-$CI_COMMIT_SHA}" + # Build + - docker build --tag ${DOCKER_TMP_IMAGE_NAME} ${DOCKER_BUILD_ARGS} tools/docker/ + # We can't mount $PWD/examples/get-started/blink into the container, see https://gitlab.com/gitlab-org/gitlab-ce/issues/41227. + # The workaround mentioned there works, but leaves around directories which need to be cleaned up manually. + # Therefore, build a copy of the example located inside the container. + - docker run --rm --workdir /opt/esp/idf/examples/get-started/blink ${DOCKER_TMP_IMAGE_NAME} idf.py build From 83277fe0f2351922df172a4d0a15180b7a12f03d Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 17 Jul 2019 11:35:28 +0200 Subject: [PATCH 336/486] docs: add tools section and IDF docker image page --- docs/en/api-guides/index.rst | 1 + docs/en/api-guides/tools/idf-docker-image.rst | 96 +++++++++++++++++++ docs/en/api-guides/tools/index.rst | 8 ++ docs/zh_CN/api-guides/index.rst | 1 + .../api-guides/tools/idf-docker-image.rst | 1 + docs/zh_CN/api-guides/tools/index.rst | 8 ++ 6 files changed, 115 insertions(+) create mode 100644 docs/en/api-guides/tools/idf-docker-image.rst create mode 100644 docs/en/api-guides/tools/index.rst create mode 100644 docs/zh_CN/api-guides/tools/idf-docker-image.rst create mode 100644 docs/zh_CN/api-guides/tools/index.rst diff --git a/docs/en/api-guides/index.rst b/docs/en/api-guides/index.rst index 869f7c5d18..cc762d3b33 100644 --- a/docs/en/api-guides/index.rst +++ b/docs/en/api-guides/index.rst @@ -34,3 +34,4 @@ API Guides BluFi External SPI-connected RAM Linker Script Generation + Tools diff --git a/docs/en/api-guides/tools/idf-docker-image.rst b/docs/en/api-guides/tools/idf-docker-image.rst new file mode 100644 index 0000000000..2fdaa779e8 --- /dev/null +++ b/docs/en/api-guides/tools/idf-docker-image.rst @@ -0,0 +1,96 @@ +**************** +IDF Docker Image +**************** + +.. highlight:: bash + +IDF Docker image (``espressif/idf``) is intended for building applications and libraries with specific versions of ESP-IDF, when doing automated builds. + +The image contains: + +- Common utilities such as git, wget, curl, zip. +- Python 3.6 or newer. +- A copy of a specific version of ESP-IDF (see below for information about versions). ``IDF_PATH`` environment variable is set, and points to ESP-IDF location in the container. +- All the build tools required for the specific version of ESP-IDF: CMake, make, ninja, cross-compiler toolchains, etc. +- All Python packages required by ESP-IDF are installed in a virtual environment. + +The image entrypoint sets up ``PATH`` environment variable to point to the correct version of tools, and activates the Python virtual environment. As a result, the environment is ready to use the ESP-IDF build system. + +The image can also be used as a base for custom images, if additional utilities are required. + +Tags +==== + +Multiple tags of this image are maintained: + +- ``latest``: tracks ``master`` branch of ESP-IDF +- ``vX.Y``: corresponds to ESP-IDF release ``vX.Y`` +- ``release-vX.Y``: tracks ``release/vX.Y`` branch of ESP-IDF + +.. note:: + + Versions of ESP-IDF released before this feature was introduced do not have corresponding Docker image versions. You can check the up-to-date list of available tags at https://hub.docker.com/r/espressif/idf/tags. + +Usage +===== + +Setting up Docker +~~~~~~~~~~~~~~~~~ + +Before using the ``espressif/idf`` Docker image locally, make sure you have Docker installed. Follow the instructions at https://docs.docker.com/install/, if it is not installed yet. + +If using the image in CI environment, consult the documentation of your CI service on how to specify the image used for the build process. + +Building a project with CMake +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the project directory, run:: + + docker run --rm -v $PWD:/project -w /project espressif/idf idf.py build + + +The above command explained: + +- ``docker run``: runs a Docker image. It is a shorter form of the command ``docker container run``. +- ``--rm``: removes the container when the build is finished +- ``-v $PWD:/project``: mounts the current directory on the host (``$PWD``) as ``/project`` directory in the container +- ``espressif/idf``: uses Docker image ``espressif/idf`` with tag ``latest`` (implicitly added by Docker when no tag is specified) +- ``idf.py build``: runs this command inside the container + +To build with a specific docker image tag, specify it as ``espressif/idf:TAG``:: + + docker run --rm -v $PWD:/project -w /project espressif/idf:v4.0 idf.py build + +.. note:: + + At the time of writing, v4.0 release of ESP-IDF does not exist, yet, so the above command will not work. You can check the up-to-date list of available tags at https://hub.docker.com/r/espressif/idf/tags. + + +Building a project with GNU Make +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Same as for CMake, except that the build command is different:: + + docker run --rm -v $PWD:/project -w /project espressif/idf make defconfig all -j4 + + +.. note:: + + If the ``sdkconfig`` file does not exist, the default behavior of GNU Make build system is to open the menuconfig UI. This may be not desired in automated build environments. To ensure that the ``sdkconfig`` file exists, ``defconfig`` target is added before ``all``. + +Using the image interactively +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is also possible to do builds interactively, to debug build issues or test the automated build scripts. Start the container with `-i -t` flags:: + + docker run --rm -v $PWD:/project -w /project -it espressif/idf + + +Then inside the container, use ``idf.py`` as usual:: + + idf.py menuconfig + idf.py build + +.. note:: + + Commands which communicate with the development board, such as ``idf.py flash`` and ``idf.py monitor`` will not work in the container unless the serial port is passed through into the container. However currently this is not possible with Docker for Windows (https://github.com/docker/for-win/issues/1018) and Docker for Mac (https://github.com/docker/for-mac/issues/900). diff --git a/docs/en/api-guides/tools/index.rst b/docs/en/api-guides/tools/index.rst new file mode 100644 index 0000000000..80f496fee9 --- /dev/null +++ b/docs/en/api-guides/tools/index.rst @@ -0,0 +1,8 @@ +Tools +***** + +.. toctree:: + :maxdepth: 1 + + IDF Monitor + IDF Docker image diff --git a/docs/zh_CN/api-guides/index.rst b/docs/zh_CN/api-guides/index.rst index 03163469a2..c3a1d10035 100644 --- a/docs/zh_CN/api-guides/index.rst +++ b/docs/zh_CN/api-guides/index.rst @@ -34,3 +34,4 @@ API 指南 BluFi External SPI-connected RAM 链接脚本生成机制 + Tools diff --git a/docs/zh_CN/api-guides/tools/idf-docker-image.rst b/docs/zh_CN/api-guides/tools/idf-docker-image.rst new file mode 100644 index 0000000000..c9e0dde98a --- /dev/null +++ b/docs/zh_CN/api-guides/tools/idf-docker-image.rst @@ -0,0 +1 @@ +.. include:: ../../../en/api-guides/tools/idf-docker-image.rst diff --git a/docs/zh_CN/api-guides/tools/index.rst b/docs/zh_CN/api-guides/tools/index.rst new file mode 100644 index 0000000000..37d559c5d3 --- /dev/null +++ b/docs/zh_CN/api-guides/tools/index.rst @@ -0,0 +1,8 @@ +工具 +***** + +.. toctree:: + :maxdepth: 1 + + IDF 监视器 + IDF Docker image From d77c74770a879fa25058bea78719d5e66ab34bdd Mon Sep 17 00:00:00 2001 From: chenjianqiang Date: Fri, 5 Jul 2019 20:21:36 +0800 Subject: [PATCH 337/486] bugfix(flash): add flash config in app startup We fixed some flash bugs in bootloader, but for the users used the old vrsion bootloader, they can not fix these bugs via OTA, the solution is add these updates in app startup. These updates include: 1. SPI flash gpio matrix and drive strength configuration 2. SPI flash clock configuration 3. SPI flash read dummy configuration 4. SPI flash cs timing configuration 5. Update flash id of g_rom_flashchip --- components/bootloader_support/CMakeLists.txt | 1 + .../include/bootloader_common.h | 8 - .../include/bootloader_flash_config.h | 71 ++++++++ .../src/bootloader_common.c | 12 -- .../src/bootloader_flash_config.c | 165 ++++++++++++++++++ .../bootloader_support/src/bootloader_init.c | 119 +------------ components/esp32/cpu_start.c | 15 +- components/esp32/spiram_psram.c | 13 +- .../esp_rom/include/esp32/rom/spi_flash.h | 19 +- 9 files changed, 274 insertions(+), 149 deletions(-) create mode 100644 components/bootloader_support/include/bootloader_flash_config.h create mode 100644 components/bootloader_support/src/bootloader_flash_config.c diff --git a/components/bootloader_support/CMakeLists.txt b/components/bootloader_support/CMakeLists.txt index a49f2699c2..038a2aec07 100644 --- a/components/bootloader_support/CMakeLists.txt +++ b/components/bootloader_support/CMakeLists.txt @@ -2,6 +2,7 @@ set(srcs "src/bootloader_clock.c" "src/bootloader_common.c" "src/bootloader_flash.c" + "src/bootloader_flash_config.c" "src/bootloader_random.c" "src/bootloader_utility.c" "src/esp_image_format.c" diff --git a/components/bootloader_support/include/bootloader_common.h b/components/bootloader_support/include/bootloader_common.h index bd32a8d7c1..2475d842a5 100644 --- a/components/bootloader_support/include/bootloader_common.h +++ b/components/bootloader_support/include/bootloader_common.h @@ -146,14 +146,6 @@ esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t */ void bootloader_common_vddsdio_configure(); -/** - * @brief Set the flash CS setup and hold time. - * - * CS setup time is recomemded to be 1.5T, and CS hold time is recommended to be 2.5T. - * cs_setup = 1, cs_setup_time = 0; cs_hold = 1, cs_hold_time = 1 - */ -void bootloader_common_set_flash_cs_timing(); - #ifdef __cplusplus } #endif diff --git a/components/bootloader_support/include/bootloader_flash_config.h b/components/bootloader_support/include/bootloader_flash_config.h new file mode 100644 index 0000000000..2f716cce2a --- /dev/null +++ b/components/bootloader_support/include/bootloader_flash_config.h @@ -0,0 +1,71 @@ +// Copyright 2018 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 + +#include "esp_image_format.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Update the flash id in g_rom_flashchip(global esp_rom_spiflash_chip_t structure). + * + * @return None + */ +void bootloader_flash_update_id(); + +/** + * @brief Set the flash CS setup and hold time. + * + * @note CS setup time is recomemded to be 1.5T, and CS hold time is recommended to be 2.5T. + * cs_setup = 1, cs_setup_time = 0; cs_hold = 1, cs_hold_time = 1. + * + * @return None + */ +void bootloader_flash_cs_timing_config(); + +/** + * @brief Configure SPI flash clock. + * + * @note This function only set clock frequency for SPI0. + * + * @param pfhdr Pointer to App image header, from where to fetch flash settings. + * + * @return None + */ +void bootloader_flash_clock_config(const esp_image_header_t* pfhdr); + +/** + * @brief Configure SPI flash gpio, include the IO matrix and drive strength configuration. + * + * @param pfhdr Pointer to App image header, from where to fetch flash settings. + * + * @return None + */ +void bootloader_flash_gpio_config(const esp_image_header_t* pfhdr); + +/** + * @brief Configure SPI flash read dummy based on different mode and frequency. + * + * @param pfhdr Pointer to App image header, from where to fetch flash settings. + * + * @return None + */ +void bootloader_flash_dummy_config(const esp_image_header_t* pfhdr); + +#ifdef __cplusplus +} +#endif diff --git a/components/bootloader_support/src/bootloader_common.c b/components/bootloader_support/src/bootloader_common.c index 795a6c9f51..ed0169a960 100644 --- a/components/bootloader_support/src/bootloader_common.c +++ b/components/bootloader_support/src/bootloader_common.c @@ -25,8 +25,6 @@ #include "bootloader_common.h" #include "soc/gpio_periph.h" #include "soc/rtc.h" -#include "soc/efuse_reg.h" -#include "soc/spi_reg.h" #include "esp_image_format.h" #include "bootloader_sha.h" #include "sys/param.h" @@ -272,13 +270,3 @@ void bootloader_common_vddsdio_configure() } #endif // CONFIG_BOOTLOADER_VDDSDIO_BOOST } - -void bootloader_common_set_flash_cs_timing() -{ - SET_PERI_REG_MASK(SPI_USER_REG(0), SPI_CS_HOLD_M | SPI_CS_SETUP_M); - SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S); - SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_SETUP_TIME_V, 0, SPI_SETUP_TIME_S); - SET_PERI_REG_MASK(SPI_USER_REG(1), SPI_CS_HOLD_M | SPI_CS_SETUP_M); - SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S); - SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_SETUP_TIME_V, 0, SPI_SETUP_TIME_S); -} diff --git a/components/bootloader_support/src/bootloader_flash_config.c b/components/bootloader_support/src/bootloader_flash_config.c new file mode 100644 index 0000000000..53360848a3 --- /dev/null +++ b/components/bootloader_support/src/bootloader_flash_config.c @@ -0,0 +1,165 @@ +// Copyright 2018 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 +#include +#include "string.h" +#include "sdkconfig.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp32/rom/gpio.h" +#include "esp32/rom/spi_flash.h" +#include "esp32/rom/efuse.h" +#include "soc/gpio_periph.h" +#include "soc/efuse_reg.h" +#include "soc/spi_reg.h" +#include "soc/spi_caps.h" +#include "flash_qio_mode.h" +#include "bootloader_flash_config.h" + +void bootloader_flash_update_id() +{ + g_rom_flashchip.device_id = bootloader_read_flash_id(); +} + +void IRAM_ATTR bootloader_flash_cs_timing_config() +{ + SET_PERI_REG_MASK(SPI_USER_REG(0), SPI_CS_HOLD_M | SPI_CS_SETUP_M); + SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S); + SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_SETUP_TIME_V, 0, SPI_SETUP_TIME_S); + SET_PERI_REG_MASK(SPI_USER_REG(1), SPI_CS_HOLD_M | SPI_CS_SETUP_M); + SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S); + SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_SETUP_TIME_V, 0, SPI_SETUP_TIME_S); +} + +void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t* pfhdr) +{ + uint32_t spi_clk_div = 0; + switch (pfhdr->spi_speed) { + case ESP_IMAGE_SPI_SPEED_80M: + spi_clk_div = 1; + break; + case ESP_IMAGE_SPI_SPEED_40M: + spi_clk_div = 2; + break; + case ESP_IMAGE_SPI_SPEED_26M: + spi_clk_div = 3; + break; + case ESP_IMAGE_SPI_SPEED_20M: + spi_clk_div = 4; + break; + default: + break; + } + esp_rom_spiflash_config_clk(spi_clk_div, 0); +} + +void IRAM_ATTR bootloader_flash_gpio_config(const esp_image_header_t* pfhdr) +{ + uint32_t drv = 2; + if (pfhdr->spi_speed == ESP_IMAGE_SPI_SPEED_80M) { + drv = 3; + } + + uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG); + uint32_t pkg_ver = chip_ver & 0x7; + + if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5) { + // For ESP32D2WD the SPI pins are already configured + // flash clock signal should come from IO MUX. + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK); + SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S); + } else if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2) { + // For ESP32PICOD2 the SPI pins are already configured + // flash clock signal should come from IO MUX. + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK); + SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S); + } else if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) { + // For ESP32PICOD4 the SPI pins are already configured + // flash clock signal should come from IO MUX. + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK); + SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S); + } else { + const uint32_t spiconfig = ets_efuse_get_spiconfig(); + if (spiconfig == EFUSE_SPICONFIG_SPI_DEFAULTS) { + gpio_matrix_out(SPI_IOMUX_PIN_NUM_CS, SPICS0_OUT_IDX, 0, 0); + gpio_matrix_out(SPI_IOMUX_PIN_NUM_MISO, SPIQ_OUT_IDX, 0, 0); + gpio_matrix_in(SPI_IOMUX_PIN_NUM_MISO, SPIQ_IN_IDX, 0); + gpio_matrix_out(SPI_IOMUX_PIN_NUM_MOSI, SPID_OUT_IDX, 0, 0); + gpio_matrix_in(SPI_IOMUX_PIN_NUM_MOSI, SPID_IN_IDX, 0); + gpio_matrix_out(SPI_IOMUX_PIN_NUM_WP, SPIWP_OUT_IDX, 0, 0); + gpio_matrix_in(SPI_IOMUX_PIN_NUM_WP, SPIWP_IN_IDX, 0); + gpio_matrix_out(SPI_IOMUX_PIN_NUM_HD, SPIHD_OUT_IDX, 0, 0); + gpio_matrix_in(SPI_IOMUX_PIN_NUM_HD, SPIHD_IN_IDX, 0); + //select pin function gpio + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, PIN_FUNC_GPIO); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, PIN_FUNC_GPIO); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA2_U, PIN_FUNC_GPIO); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U, PIN_FUNC_GPIO); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, PIN_FUNC_GPIO); + // flash clock signal should come from IO MUX. + // set drive ability for clock + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK); + SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S); + + uint32_t flash_id = g_rom_flashchip.device_id; + if (flash_id == FLASH_ID_GD25LQ32C) { + // Set drive ability for 1.8v flash in 80Mhz. + SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA0_U, FUN_DRV, 3, FUN_DRV_S); + SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA1_U, FUN_DRV, 3, FUN_DRV_S); + SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA2_U, FUN_DRV, 3, FUN_DRV_S); + SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA3_U, FUN_DRV, 3, FUN_DRV_S); + SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CMD_U, FUN_DRV, 3, FUN_DRV_S); + SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, 3, FUN_DRV_S); + } + } + } +} + +void IRAM_ATTR bootloader_flash_dummy_config(const esp_image_header_t* pfhdr) +{ + int spi_cache_dummy = 0; + uint32_t modebit = READ_PERI_REG(SPI_CTRL_REG(0)); + if (modebit & SPI_FASTRD_MODE) { + if (modebit & SPI_FREAD_QIO) { //SPI mode is QIO + spi_cache_dummy = SPI0_R_QIO_DUMMY_CYCLELEN; + } else if (modebit & SPI_FREAD_DIO) { //SPI mode is DIO + spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN; + SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_ADDR_BITLEN_V, SPI0_R_DIO_ADDR_BITSLEN, SPI_USR_ADDR_BITLEN_S); + } else if(modebit & (SPI_FREAD_QUAD | SPI_FREAD_DUAL)) { //SPI mode is QOUT or DIO + spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN; + } + } + + extern uint8_t g_rom_spiflash_dummy_len_plus[]; + switch (pfhdr->spi_speed) { + case ESP_IMAGE_SPI_SPEED_80M: + g_rom_spiflash_dummy_len_plus[0] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_80M; + g_rom_spiflash_dummy_len_plus[1] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_80M; + break; + case ESP_IMAGE_SPI_SPEED_40M: + g_rom_spiflash_dummy_len_plus[0] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_40M; + g_rom_spiflash_dummy_len_plus[1] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_40M; + break; + case ESP_IMAGE_SPI_SPEED_26M: + case ESP_IMAGE_SPI_SPEED_20M: + g_rom_spiflash_dummy_len_plus[0] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_20M; + g_rom_spiflash_dummy_len_plus[1] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_20M; + break; + default: + break; + } + + SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN_V, spi_cache_dummy + g_rom_spiflash_dummy_len_plus[0], + SPI_USR_DUMMY_CYCLELEN_S); +} \ No newline at end of file diff --git a/components/bootloader_support/src/bootloader_init.c b/components/bootloader_support/src/bootloader_init.c index 1c6da1836c..67ec3626c9 100644 --- a/components/bootloader_support/src/bootloader_init.c +++ b/components/bootloader_support/src/bootloader_init.c @@ -50,6 +50,7 @@ #include "bootloader_config.h" #include "bootloader_clock.h" #include "bootloader_common.h" +#include "bootloader_flash_config.h" #include "flash_qio_mode.h" @@ -63,7 +64,7 @@ static const char* TAG = "boot"; static esp_err_t bootloader_main(); static void print_flash_info(const esp_image_header_t* pfhdr); static void update_flash_config(const esp_image_header_t* pfhdr); -static void flash_gpio_configure(const esp_image_header_t* pfhdr); +static void bootloader_init_flash_configure(const esp_image_header_t* pfhdr); static void uart_console_configure(void); static void wdt_reset_check(void); @@ -126,7 +127,7 @@ static esp_err_t bootloader_main() ESP_LOGE(TAG, "failed to load bootloader header!"); return ESP_FAIL; } - flash_gpio_configure(&fhdr); + bootloader_init_flash_configure(&fhdr); #if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ == 240) //Check if ESP32 is rated for a CPU frequency of 160MHz only if (REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_CPU_FREQ_RATED) && @@ -286,121 +287,15 @@ static void print_flash_info(const esp_image_header_t* phdr) #endif } -#define FLASH_CLK_IO 6 -#define FLASH_CS_IO 11 -#define FLASH_SPIQ_IO 7 -#define FLASH_SPID_IO 8 -#define FLASH_SPIWP_IO 10 -#define FLASH_SPIHD_IO 9 -#define FLASH_IO_MATRIX_DUMMY_40M 1 -#define FLASH_IO_MATRIX_DUMMY_80M 2 -#define FLASH_IO_DRIVE_GD_WITH_1V8PSRAM 3 - /* * Bootloader reads SPI configuration from bin header, so that * the burning configuration can be different with compiling configuration. */ -static void IRAM_ATTR flash_gpio_configure(const esp_image_header_t* pfhdr) +static void IRAM_ATTR bootloader_init_flash_configure(const esp_image_header_t* pfhdr) { - int spi_cache_dummy = 0; - int drv = 2; - switch (pfhdr->spi_mode) { - case ESP_IMAGE_SPI_MODE_QIO: - spi_cache_dummy = SPI0_R_QIO_DUMMY_CYCLELEN; - break; - case ESP_IMAGE_SPI_MODE_DIO: - spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN; - SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_ADDR_BITLEN_V, SPI0_R_DIO_ADDR_BITSLEN, SPI_USR_ADDR_BITLEN_S); - break; - case ESP_IMAGE_SPI_MODE_QOUT: - case ESP_IMAGE_SPI_MODE_DOUT: - default: - spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN; - break; - } - - /* dummy_len_plus values defined in ROM for SPI flash configuration */ - extern uint8_t g_rom_spiflash_dummy_len_plus[]; - switch (pfhdr->spi_speed) { - case ESP_IMAGE_SPI_SPEED_80M: - g_rom_spiflash_dummy_len_plus[0] = FLASH_IO_MATRIX_DUMMY_80M; - g_rom_spiflash_dummy_len_plus[1] = FLASH_IO_MATRIX_DUMMY_80M; - SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN_V, spi_cache_dummy + FLASH_IO_MATRIX_DUMMY_80M, - SPI_USR_DUMMY_CYCLELEN_S); //DUMMY - drv = 3; - break; - case ESP_IMAGE_SPI_SPEED_40M: - g_rom_spiflash_dummy_len_plus[0] = FLASH_IO_MATRIX_DUMMY_40M; - g_rom_spiflash_dummy_len_plus[1] = FLASH_IO_MATRIX_DUMMY_40M; - SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN_V, spi_cache_dummy + FLASH_IO_MATRIX_DUMMY_40M, - SPI_USR_DUMMY_CYCLELEN_S); //DUMMY - break; - case ESP_IMAGE_SPI_SPEED_26M: - case ESP_IMAGE_SPI_SPEED_20M: - SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN_V, spi_cache_dummy, SPI_USR_DUMMY_CYCLELEN_S); //DUMMY - break; - default: - break; - } - - uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG); - uint32_t pkg_ver = chip_ver & 0x7; - - if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5) { - // For ESP32D2WD the SPI pins are already configured - // flash clock signal should come from IO MUX. - PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK); - SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S); - } else if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2) { - // For ESP32PICOD2 the SPI pins are already configured - // flash clock signal should come from IO MUX. - PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK); - SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S); - } else if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) { - // For ESP32PICOD4 the SPI pins are already configured - // flash clock signal should come from IO MUX. - PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK); - SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S); - } else { - const uint32_t spiconfig = ets_efuse_get_spiconfig(); - if (spiconfig == EFUSE_SPICONFIG_SPI_DEFAULTS) { - gpio_matrix_out(FLASH_CS_IO, SPICS0_OUT_IDX, 0, 0); - gpio_matrix_out(FLASH_SPIQ_IO, SPIQ_OUT_IDX, 0, 0); - gpio_matrix_in(FLASH_SPIQ_IO, SPIQ_IN_IDX, 0); - gpio_matrix_out(FLASH_SPID_IO, SPID_OUT_IDX, 0, 0); - gpio_matrix_in(FLASH_SPID_IO, SPID_IN_IDX, 0); - gpio_matrix_out(FLASH_SPIWP_IO, SPIWP_OUT_IDX, 0, 0); - gpio_matrix_in(FLASH_SPIWP_IO, SPIWP_IN_IDX, 0); - gpio_matrix_out(FLASH_SPIHD_IO, SPIHD_OUT_IDX, 0, 0); - gpio_matrix_in(FLASH_SPIHD_IO, SPIHD_IN_IDX, 0); - //select pin function gpio - PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, PIN_FUNC_GPIO); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, PIN_FUNC_GPIO); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA2_U, PIN_FUNC_GPIO); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U, PIN_FUNC_GPIO); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, PIN_FUNC_GPIO); - // flash clock signal should come from IO MUX. - // set drive ability for clock - PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK); - SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S); - - #if CONFIG_SPIRAM_TYPE_ESPPSRAM32 - uint32_t flash_id = g_rom_flashchip.device_id; - if (flash_id == FLASH_ID_GD25LQ32C) { - // Set drive ability for 1.8v flash in 80Mhz. - SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA0_U, FUN_DRV, 3, FUN_DRV_S); - SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA1_U, FUN_DRV, 3, FUN_DRV_S); - SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA2_U, FUN_DRV, 3, FUN_DRV_S); - SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA3_U, FUN_DRV, 3, FUN_DRV_S); - SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CMD_U, FUN_DRV, 3, FUN_DRV_S); - SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, 3, FUN_DRV_S); - } - #endif - } - } - - // improve the flash cs timing. - bootloader_common_set_flash_cs_timing(); + bootloader_flash_gpio_config(pfhdr); + bootloader_flash_dummy_config(pfhdr); + bootloader_flash_cs_timing_config(); } static void uart_console_configure(void) diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 460e350ed9..f93e4cdf00 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -71,7 +71,7 @@ #include "trax.h" #include "esp_ota_ops.h" #include "esp_efuse.h" -#include "bootloader_common.h" +#include "bootloader_flash_config.h" #define STRINGIFY(s) STRINGIFY2(s) #define STRINGIFY2(s) #s @@ -173,8 +173,6 @@ void IRAM_ATTR call_start_cpu0() abort(); #endif } -# else // If psram is uninitialized, we need to improve the flash cs timing. - bootloader_common_set_flash_cs_timing(); #endif ESP_EARLY_LOGI(TAG, "Pro cpu up."); @@ -435,6 +433,17 @@ void start_cpu0_default(void) esp_coex_adapter_register(&g_coex_adapter_funcs); #endif + bootloader_flash_update_id(); +#if !CONFIG_SPIRAM_BOOT_INIT // If psram is uninitialized, we need to improve some flash configuration. + esp_image_header_t fhdr; + const esp_partition_t *partition = esp_ota_get_running_partition(); + spi_flash_read(partition->address, &fhdr, sizeof(esp_image_header_t)); + bootloader_flash_clock_config(&fhdr); + bootloader_flash_gpio_config(&fhdr); + bootloader_flash_dummy_config(&fhdr); + bootloader_flash_cs_timing_config(); +#endif + portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main", ESP_TASK_MAIN_STACK, NULL, ESP_TASK_MAIN_PRIO, NULL, 0); diff --git a/components/esp32/spiram_psram.c b/components/esp32/spiram_psram.c index 692ef619b8..ee393618ab 100644 --- a/components/esp32/spiram_psram.c +++ b/components/esp32/spiram_psram.c @@ -31,6 +31,7 @@ #include "esp32/rom/efuse.h" #include "soc/dport_reg.h" #include "soc/efuse_periph.h" +#include "soc/spi_caps.h" #include "driver/gpio.h" #include "driver/spi_common.h" #include "driver/periph_ctrl.h" @@ -94,8 +95,6 @@ typedef enum { // WARNING: PSRAM shares all but the CS and CLK pins with the flash, so these defines // hardcode the flash pins as well, making this code incompatible with either a setup // that has the flash on non-standard pins or ESP32s with built-in flash. -#define FLASH_CLK_IO 6 -#define FLASH_CS_IO 11 #define PSRAM_SPIQ_SD0_IO 7 #define PSRAM_SPID_SD1_IO 8 #define PSRAM_SPIWP_SD3_IO 10 @@ -134,8 +133,8 @@ typedef struct { #define PSRAM_INTERNAL_IO_28 28 #define PSRAM_INTERNAL_IO_29 29 -#define PSRAM_IO_MATRIX_DUMMY_40M 1 -#define PSRAM_IO_MATRIX_DUMMY_80M 2 +#define PSRAM_IO_MATRIX_DUMMY_40M ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_40M +#define PSRAM_IO_MATRIX_DUMMY_80M ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_80M #define _SPI_CACHE_PORT 0 #define _SPI_FLASH_PORT 1 @@ -568,7 +567,7 @@ static void IRAM_ATTR psram_gpio_config(psram_io_t *psram_io, psram_cache_mode_t gpio_matrix_in(psram_io->psram_spihd_sd2_io, SPIHD_IN_IDX, 0); //select pin function gpio - if ((psram_io->flash_clk_io == FLASH_CLK_IO) && (psram_io->flash_clk_io != psram_io->psram_clk_io)) { + if ((psram_io->flash_clk_io == SPI_IOMUX_PIN_NUM_CLK) && (psram_io->flash_clk_io != psram_io->psram_clk_io)) { //flash clock signal should come from IO MUX. PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[psram_io->flash_clk_io], FUNC_SD_CLK_SPICLK); } else { @@ -649,8 +648,8 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad const uint32_t spiconfig = ets_efuse_get_spiconfig(); if (spiconfig == EFUSE_SPICONFIG_SPI_DEFAULTS) { - psram_io.flash_clk_io = FLASH_CLK_IO; - psram_io.flash_cs_io = FLASH_CS_IO; + psram_io.flash_clk_io = SPI_IOMUX_PIN_NUM_CLK; + psram_io.flash_cs_io = SPI_IOMUX_PIN_NUM_CS; psram_io.psram_spiq_sd0_io = PSRAM_SPIQ_SD0_IO; psram_io.psram_spid_sd1_io = PSRAM_SPID_SD1_IO; psram_io.psram_spiwp_sd3_io = PSRAM_SPIWP_SD3_IO; diff --git a/components/esp_rom/include/esp32/rom/spi_flash.h b/components/esp_rom/include/esp32/rom/spi_flash.h index ea995e3499..b78a6130aa 100644 --- a/components/esp_rom/include/esp32/rom/spi_flash.h +++ b/components/esp_rom/include/esp32/rom/spi_flash.h @@ -114,13 +114,18 @@ extern "C" { #define ESP_ROM_SPIFLASH_BUFF_BYTE_READ_BITS 0x3f //SPI status register -#define ESP_ROM_SPIFLASH_BUSY_FLAG BIT0 -#define ESP_ROM_SPIFLASH_WRENABLE_FLAG BIT1 -#define ESP_ROM_SPIFLASH_BP0 BIT2 -#define ESP_ROM_SPIFLASH_BP1 BIT3 -#define ESP_ROM_SPIFLASH_BP2 BIT4 -#define ESP_ROM_SPIFLASH_WR_PROTECT (ESP_ROM_SPIFLASH_BP0|ESP_ROM_SPIFLASH_BP1|ESP_ROM_SPIFLASH_BP2) -#define ESP_ROM_SPIFLASH_QE BIT9 +#define ESP_ROM_SPIFLASH_BUSY_FLAG BIT0 +#define ESP_ROM_SPIFLASH_WRENABLE_FLAG BIT1 +#define ESP_ROM_SPIFLASH_BP0 BIT2 +#define ESP_ROM_SPIFLASH_BP1 BIT3 +#define ESP_ROM_SPIFLASH_BP2 BIT4 +#define ESP_ROM_SPIFLASH_WR_PROTECT (ESP_ROM_SPIFLASH_BP0|ESP_ROM_SPIFLASH_BP1|ESP_ROM_SPIFLASH_BP2) +#define ESP_ROM_SPIFLASH_QE BIT9 + +//Extra dummy for flash read +#define ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_20M 0 +#define ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_40M 1 +#define ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_80M 2 #define FLASH_ID_GD25LQ32C 0xC86016 From ffca1825e674f3b09fb888b30fbe2765b9b8ecaa Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 28 Jun 2019 14:12:10 +0200 Subject: [PATCH 338/486] lwip fuzzer: supplied dummy dns server entry to work with internal packet processing functionwhich is exercised in fuzzer tests, disable CTYPE as recent newlib is not compatible with AFL --- components/lwip/test_afl_host/Makefile | 2 +- components/lwip/test_afl_host/network_mock.c | 2 +- components/lwip/test_afl_host/test_dns.c | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/components/lwip/test_afl_host/Makefile b/components/lwip/test_afl_host/Makefile index 7c5cf49f3a..b236b327a8 100644 --- a/components/lwip/test_afl_host/Makefile +++ b/components/lwip/test_afl_host/Makefile @@ -1,6 +1,6 @@ COMPONENTS_DIR=../.. CFLAGS=-std=gnu99 -Og -ggdb -ffunction-sections -fdata-sections -nostdlib -Wall -Werror=all -Wno-int-to-pointer-cast -Wno-error=unused-function -Wno-error=unused-variable -Wno-error=deprecated-declarations -Wextra \ --Wno-unused-parameter -Wno-sign-compare -Wno-address -Wno-unused-variable -DESP_PLATFORM -D IDF_VER=\"v3.1\" -MMD -MP -DWITH_POSIX +-Wno-unused-parameter -Wno-sign-compare -Wno-address -Wno-unused-variable -DESP_PLATFORM -D IDF_VER=\"v3.1\" -MMD -MP -DWITH_POSIX -DLWIP_NO_CTYPE_H=1 INC_DIRS=-I . -I ./build/config -I $(COMPONENTS_DIR)/newlib/platform_include -I $(COMPONENTS_DIR)/newlib/include -I $(COMPONENTS_DIR)/driver/include -I $(COMPONENTS_DIR)/esp32/include -I $(COMPONENTS_DIR)/ethernet/include -I $(COMPONENTS_DIR)/freertos/include -I $(COMPONENTS_DIR)/heap/include -I $(COMPONENTS_DIR)/lwip/lwip/src/include -I $(COMPONENTS_DIR)/lwip/include/apps -I $(COMPONENTS_DIR)/lwip/lwip/src/include/netif -I $(COMPONENTS_DIR)/lwip/lwip/src/include/posix -I $(COMPONENTS_DIR)/lwip/port/esp32/include -I $(COMPONENTS_DIR)/lwip/lwip/src/include/posix -I $(COMPONENTS_DIR)/lwip/include/apps/ping -I $(COMPONENTS_DIR)/lwip/include/apps/sntp -I $(COMPONENTS_DIR)/soc/esp32/include -I $(COMPONENTS_DIR)/soc/include -I $(COMPONENTS_DIR)/tcpip_adapter/include -I $(COMPONENTS_DIR)/esp_rom/include -I $(COMPONENTS_DIR)/esp_common/include -I $(COMPONENTS_DIR)/xtensa/include -I $(COMPONENTS_DIR)/xtensa/esp32/include -I $(COMPONENTS_DIR)/esp_wifi/include -I $(COMPONENTS_DIR)/esp_event/include TEST_NAME=test FUZZ=afl-fuzz diff --git a/components/lwip/test_afl_host/network_mock.c b/components/lwip/test_afl_host/network_mock.c index 947b6b22b2..aeaad72d32 100644 --- a/components/lwip/test_afl_host/network_mock.c +++ b/components/lwip/test_afl_host/network_mock.c @@ -94,7 +94,7 @@ struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) p = (struct pbuf *)malloc(MEMP_PBUF_POOL); p->tot_len = length; p->next = NULL; - p->type = PBUF_POOL; + p->type_internal = PBUF_POOL; p->len = length; p->payload = malloc(length); return p; diff --git a/components/lwip/test_afl_host/test_dns.c b/components/lwip/test_afl_host/test_dns.c index 131a8b3ed7..1e9a588150 100644 --- a/components/lwip/test_afl_host/test_dns.c +++ b/components/lwip/test_afl_host/test_dns.c @@ -66,6 +66,8 @@ int main(int argc, char** argv) p->next = NULL; // Pretend that the response is from our pending querries + IP4_ADDR(&server_ip, 8, 8, 8, 8); + dns_setserver(0, &server_ip); dns_test_inject_port_and_txid(1024, (buf[0]<<8) + buf[1]); dns_test_dns_enqueue("test", 4, NULL, NULL, 0); From 6289a26596309f3aa4761d383203dfdc74a8eb50 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 17 Jul 2019 20:52:53 +0200 Subject: [PATCH 339/486] mqtt: referenced esp-mqtt master to close disconnection issues and fix static analysis warnings closes https://github.com/espressif/esp-idf/issues/3619 including mqtt commit https://github.com/espressif/esp-mqtt/commit/7223302deb3ffefe60cc645c6d792fd5e4d6259c closes https://github.com/espressif/esp-idf/issues/3215 including mqtt commit https://github.com/espressif/esp-mqtt/commit/caf5007b99df985b330683dfe2fa454c94633018 --- components/mqtt/esp-mqtt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mqtt/esp-mqtt b/components/mqtt/esp-mqtt index 0cc4077bd3..dc37d3a065 160000 --- a/components/mqtt/esp-mqtt +++ b/components/mqtt/esp-mqtt @@ -1 +1 @@ -Subproject commit 0cc4077bd3e10bb93456ff2785309ec9237a5906 +Subproject commit dc37d3a065f345a7358b8ff4553db0baceeb8ad6 From d8b367679713ae0cf15097486aec0bb3305041ca Mon Sep 17 00:00:00 2001 From: Kirill Chalov Date: Wed, 19 Jun 2019 19:27:17 +0800 Subject: [PATCH 340/486] Review the file api-reference/peripherals/ledc.rst --- docs/en/api-reference/peripherals/ledc.rst | 104 +++++++++++---------- 1 file changed, 53 insertions(+), 51 deletions(-) diff --git a/docs/en/api-reference/peripherals/ledc.rst b/docs/en/api-reference/peripherals/ledc.rst index 61ad949b92..6d2c9413ce 100644 --- a/docs/en/api-reference/peripherals/ledc.rst +++ b/docs/en/api-reference/peripherals/ledc.rst @@ -4,23 +4,23 @@ LED Control Introduction ------------ -The LED control (LEDC) module is primarily designed to control the intensity of LEDs, although it can be used to generate PWM signals for other purposes as well. It has 16 channels which can generate independent waveforms, that can be used to drive e.g. RGB LED devices. +The LED control (LEDC) peripheral is primarily designed to control the intensity of LEDs, although it can also be used to generate PWM signals for other purposes as well. It has 16 channels which can generate independent waveforms that can be used, for example, to drive RGB LED devices. -Half of all LEDC's channels provide high speed mode of operation. This mode offers implemented in hardware, automatic and glitch free change of PWM duty cycle. The other half of channels operate in a low speed mode, where the moment of change depends on the application software. Each group of channels is also able to use different clock sources but this feature is not implemented in the API. +A half of LEDC's channels operate in high speed mode. This mode is implemented in hardware and offers automatic and glitch-free changing of the PWM duty cycle. The other half of channels operate in low speed mode, where the moment of change depends on the application software. Each group of channels is also able to use different clock sources, but this feature is not yet supported in the LEDC driver. -The PWM controller also has the ability to automatically increase or decrease the duty cycle gradually, allowing for fades without any processor interference. +The PWM controller can automatically increase or decrease the duty cycle gradually, allowing for fades without any processor interference. Functionality Overview ---------------------- -Getting LEDC to work on specific channel in either :ref:`high or low speed mode ` is done in three steps: +Getting LEDC to work on a specific channel in either :ref:`high or low speed mode ` is done in three steps: -1. :ref:`ledc-api-configure-timer` to determine PWM signal's frequency and the a number (resolution of duty range). +1. :ref:`ledc-api-configure-timer` by specifying the PWM signal's frequency and duty cycle resolution. 2. :ref:`ledc-api-configure-channel` by associating it with the timer and GPIO to output the PWM signal. -3. :ref:`ledc-api-change-pwm-signal` that drives the output to change LED's intensity. This may be done under full control by software or with help of hardware fading functions. +3. :ref:`ledc-api-change-pwm-signal` that drives the output in order to change LED's intensity. This can be done under the full control of software or with hardware fading functions. -In an optional step it is also possible to set up an interrupt on the fade end. +As an optional step, it is also possible to set up an interrupt on the fade end. .. figure:: ../../../_static/ledc-api-settings.jpg :align: center @@ -35,12 +35,14 @@ In an optional step it is also possible to set up an interrupt on the fade end. Configure Timer ^^^^^^^^^^^^^^^ -Setting of the timer is done by calling function :cpp:func:`ledc_timer_config`. This function should be provided with a data structure :cpp:type:`ledc_timer_config_t` that contains the following configuration settings: +Setting the timer is done by calling the function :cpp:func:`ledc_timer_config` and passing to it a data structure :cpp:type:`ledc_timer_config_t` that contains the following configuration settings: - * The timer number :cpp:type:`ledc_timer_t` and a speed mode :cpp:type:`ledc_mode_t`. - * The PWM signal's frequency and resolution of PWM's duty value changes. + - Timer number :cpp:type:`ledc_timer_t` + - Speed mode :cpp:type:`ledc_mode_t` + - PWM signal frequency + - Resolution of PWM duty -The frequency and the duty resolution are interdependent. The higher the PWM frequency, the lower duty resolution is available and vice versa. This relationship may became important, if you are planning to use this API for purposes other that changing intensity of LEDs. Check section :ref:`ledc-api-supported-range-frequency-duty-resolution` for more details. +The frequency and the duty resolution are interdependent. The higher the PWM frequency, the lower duty resolution is available, and vice versa. This relationship might be important if you are planning to use this API for purposes other than changing the intensity of LEDs. For more details, see Section :ref:`ledc-api-supported-range-frequency-duty-resolution`. .. _ledc-api-configure-channel: @@ -48,11 +50,11 @@ The frequency and the duty resolution are interdependent. The higher the PWM fre Configure Channel ^^^^^^^^^^^^^^^^^ -Having set up the timer, the next step is to configure selected channel (one out of :cpp:type:`ledc_channel_t`). This is done by calling function :cpp:func:`ledc_channel_config`. +When the timer is set up, configure a selected channel (one out of :cpp:type:`ledc_channel_t`). This is done by calling the function :cpp:func:`ledc_channel_config`. -In similar way, like with the timer configuration, the channel setup function should be provided with specific structure :cpp:type:`ledc_channel_config_t`, that contains channel's configuration parameters. +Similar to the timer configuration, the channel setup function should be passed a structure :cpp:type:`ledc_channel_config_t` that contains the channel's configuration parameters. -At this point channel should became operational and start generating PWM signal of frequency determined by the timer settings and the duty on selected GPIO, as configured in :cpp:type:`ledc_channel_config_t`. The channel operation / the signal generation may be suspended at any time by calling function :cpp:func:`ledc_stop`. +At this point, the channel should start operating and generating the PWM signal on the selected GPIO, as configured in :cpp:type:`ledc_channel_config_t`, with the frequency specified in the timer settings and the given duty cycle. The channel operation (signal generation) can be suspended at any time by calling the function :cpp:func:`ledc_stop`. .. _ledc-api-change-pwm-signal: @@ -60,23 +62,25 @@ At this point channel should became operational and start generating PWM signal Change PWM Signal ^^^^^^^^^^^^^^^^^ -Once the channel is operational and generating the PWM signal of constant duty and frequency, there are couple of ways to change this signal. When driving LEDs we are changing primarily the duty to vary the light intensity. See the two section below how to change the duty by software or with hardware fading. If required, we can change signal's frequency as well and this is covered in section :ref:`ledc-api-change-pwm-frequency`. +Once the channel starts operating and generating the PWM signal with the constant duty cycle and frequency, there are a couple of ways to change this signal. When driving LEDs, primarily the duty cycle is changed to vary the light intensity. + +The following two sections describe how to change the duty cycle using software and hardware fading. If required, the signal's frequency can also be changed; it is covered in Section :ref:`ledc-api-change-pwm-frequency`. -Change PWM Duty by Software -""""""""""""""""""""""""""" - -Setting of the duty is done by first calling dedicated function :cpp:func:`ledc_set_duty` and then calling :cpp:func:`ledc_update_duty` to make the change effective. To check the value currently set, there is a corresponding ``_get_`` function :cpp:func:`ledc_get_duty`. - -Another way to set the duty, and some other channel parameters as well, is by calling :cpp:func:`ledc_channel_config` discussed in the previous section. - -The range of the duty value entered into functions depends on selected ``duty_resolution`` and should be from 0 to (2 ** duty_resolution) - 1. For example, if selected duty resolution is 10, then the duty range is from 0 to 1023. This provides the resolution of ~0.1%. - - -Change PWM Duty with Hardware Fading +Change PWM Duty Cycle Using Software """""""""""""""""""""""""""""""""""" -The LEDC hardware provides the means to gradually fade from one duty value to another. To use this functionality first enable fading with :cpp:func:`ledc_fade_func_install`. Then configure it by calling one of available fading functions: +To set the duty cycle, use the dedicated function :cpp:func:`ledc_set_duty`. After that, call :cpp:func:`ledc_update_duty` to activeate the changes. To check the currently set value, use the corresponding ``_get_`` function :cpp:func:`ledc_get_duty`. + +Another way to set the duty cycle, as well as some other channel parameters, is by calling :cpp:func:`ledc_channel_config` covered in Section :ref:`ledc-api-configure-channel`. + +The range of the duty cycle values passed to functions depends on selected ``duty_resolution`` and should be from ``0`` to ``(2 ** duty_resolution) - 1``. For example, if the selected duty resolution is 10, then the duty cycle values can range from 0 to 1023. This provides the resolution of ~0.1%. + + +Change PWM Duty Cycle using Hardware +"""""""""""""""""""""""""""""""""""" + +The LEDC hardware provides the means to gradually transition from one duty cycle value to another. To use this functionality, enable fading with :cpp:func:`ledc_fade_func_install` and then configure it by calling one of the available fading functions: * :cpp:func:`ledc_set_fade_with_time` * :cpp:func:`ledc_set_fade_with_step` @@ -84,7 +88,7 @@ The LEDC hardware provides the means to gradually fade from one duty value to an Finally start fading with :cpp:func:`ledc_fade_start`. -If not required anymore, fading and associated interrupt may be disabled with :cpp:func:`ledc_fade_func_uninstall`. +If not required anymore, fading and an associated interrupt can be disabled with :cpp:func:`ledc_fade_func_uninstall`. .. _ledc-api-change-pwm-frequency: @@ -92,34 +96,32 @@ If not required anymore, fading and associated interrupt may be disabled with :c Change PWM Frequency """""""""""""""""""" -The LEDC API provides several means to change the PWM frequency "on the fly". +The LEDC API provides several ways to change the PWM frequency "on the fly": - * One of options is to call :cpp:func:`ledc_set_freq`. There is a corresponding function :cpp:func:`ledc_get_freq` to check what frequency is currently set. - - * Another option to change the frequency, and the duty resolution as well, is by calling :cpp:func:`ledc_bind_channel_timer` to bind other timer to the channel. - - * Finally the channel's timer may be changed by calling :cpp:func:`ledc_channel_config`. + * Set the frequency by calling :cpp:func:`ledc_set_freq`. There is a corresponding function :cpp:func:`ledc_get_freq` to check the current frequency. + * Change the frequency and the duty resolution by calling :cpp:func:`ledc_bind_channel_timer` to bind some other timer to the channel. + * Change the channel's timer by calling :cpp:func:`ledc_channel_config`. More Control Over PWM """"""""""""""""""""" -There are couple of lower level timer specific functions, that may be used to provide additional means to change the PWM settings: +There are several lower level timer-specific functions that can be used to change PWM settings: * :cpp:func:`ledc_timer_set` * :cpp:func:`ledc_timer_rst` * :cpp:func:`ledc_timer_pause` * :cpp:func:`ledc_timer_resume` -The first two functions are called "behind the scenes" by :cpp:func:`ledc_channel_config` to provide "clean" start up of a timer after is it configured. +The first two functions are called "behind the scenes" by :cpp:func:`ledc_channel_config` to provide a "clean" startup of a timer after it is configured. Use Interrupts ^^^^^^^^^^^^^^ -When configuring a LEDC channel, one of parameters selected within :cpp:type:`ledc_channel_config_t` is :cpp:type:`ledc_intr_type_t` and allows to enable an interrupt on fade completion. +When configuring an LEDC channel, one of the parameters selected within :cpp:type:`ledc_channel_config_t` is :cpp:type:`ledc_intr_type_t` which triggers an interrupt on fade completion. -Registration of a handler to service this interrupt is done by calling :cpp:func:`ledc_isr_register`. +For registration of a handler to address this interrupt, call :cpp:func:`ledc_isr_register`. .. _ledc-api-high_low_speed_mode: @@ -127,39 +129,39 @@ Registration of a handler to service this interrupt is done by calling :cpp:func LEDC High and Low Speed Mode ---------------------------- -Out of the total 8 timers and 16 channels available in the LED PWM Controller, half of them are dedicated to operate in the high speed mode and the other half in the low speed mode. Selection of the low or high speed "capable" timer or the channel is done with parameter :cpp:type:`ledc_mode_t` that is present in applicable function calls. +Of the total 8 timers and 16 channels available in the LED PWM Controller, half of them are dedicated to operation in high speed mode and the other half in low speed mode. Selection of a low or high speed timer or channel is done with the parameter :cpp:type:`ledc_mode_t` that can be found in applicable function calls. -The advantage of the high speed mode is h/w supported, glitch-free changeover of the timer settings. This means that if the timer settings are modified, the changes will be applied automatically after the next overflow interrupt of the timer. In contrast, when updating the low-speed timer, the change of settings should be specifically triggered by software. The LEDC API is doing it "behind the scenes", e.g. when :cpp:func:`ledc_timer_config` or :cpp:func:`ledc_timer_set` is called. +The advantage of high speed mode is hardware-supported, glitch-free changeover of the timer settings. This means that if the timer settings are modified, the changes will be applied automatically on the next overflow interrupt of the timer. In contrast, when updating the low-speed timer, the change of settings should be explicitly triggered by software. The LEDC driver handles it in the background, e.g., when :cpp:func:`ledc_timer_config` or :cpp:func:`ledc_timer_set` is called. -For additional details regarding speed modes please refer to `ESP32 Technical Reference Manual `_ (PDF). Note that support for ``SLOW_CLOCK`` mentioned in this manual is not implemented in the LEDC API. +For additional details regarding speed modes, refer to `ESP32 Technical Reference Manual `_ (PDF). Please note that the support for ``SLOW_CLOCK`` mentioned in this manual is not yet supported in the LEDC driver. .. _ledc-api-supported-range-frequency-duty-resolution: -Supported Range of Frequency and Duty Resolution ------------------------------------------------- +Supported Range of Frequency and Duty Resolutions +------------------------------------------------- -The LED PWM Controller is designed primarily to drive LEDs and provides wide resolution of PWM duty settings. For instance for the PWM frequency at 5 kHz, the maximum duty resolution is 13 bits. It means that the duty may be set anywhere from 0 to 100% with resolution of ~0.012% (2 ** 13 = 8192 discrete levels of the LED intensity). +The LED PWM Controller is designed primarily to drive LEDs. It provides a wide resolution for PWM duty cycle settings. For instance, the PWM frequency of 5 kHz can have the maximum duty resolution of 13 bits. It means that the duty can be set anywhere from 0 to 100% with a resolution of ~0.012% (2 ** 13 = 8192 discrete levels of the LED intensity). -The LEDC may be used for providing signals at much higher frequencies to clock other devices, e.g. a digital camera module. In such a case the maximum available frequency is 40 MHz with duty resolution of 1 bit. This means that duty is fixed at 50% and cannot be adjusted. +The LEDC can be used for generating signals at much higher frequencies that are sufficient enough to clock other devices, e.g., a digital camera module. In this case, the maximum available frequency is 40 MHz with duty resolution of 1 bit. This means that the duty cycle is fixed at 50% and cannot be adjusted. -The API is designed to report an error when trying to set a frequency and a duty resolution that is out of the range of LEDC's hardware. For example, an attempt to set the frequency at 20 MHz and the duty resolution of 3 bits will result in the following error reported on a serial monitor: +The LEDC API is designed to report an error when trying to set a frequency and a duty resolution that exceed the range of LEDC's hardware. For example, an attempt to set the frequency to 20 MHz and the duty resolution to 3 bits will result in the following error reported on a serial monitor: .. highlight:: none :: - E (196) ledc: requested frequency and duty resolution can not be achieved, try reducing freq_hz or duty_resolution. div_param=128 + E (196) ledc: requested frequency and duty resolution cannot be achieved, try reducing freq_hz or duty_resolution. div_param=128 -In such a case either the duty resolution or the frequency should be reduced. For example setting the duty resolution at 2 will resolve this issue and provide possibility to set the duty with 25% steps, i.e. at 25%, 50% or 75%. +In such a situation, either the duty resolution or the frequency must be reduced. For example, setting the duty resolution to 2 will resolve this issue and will make it possible to set the duty cycle at 25% steps, i.e., at 25%, 50% or 75%. -The LEDC API will also capture and report an attempt to configure frequency / duty resolution combination that is below the supported minimum, e.g.: +The LEDC driver will also capture and report attempts to configure frequency / duty resolution combinations that are below the supported minimum, e.g.: :: - E (196) ledc: requested frequency and duty resolution can not be achieved, try increasing freq_hz or duty_resolution. div_param=128000000 + E (196) ledc: requested frequency and duty resolution cannot be achieved, try increasing freq_hz or duty_resolution. div_param=128000000 -Setting of the duty resolution is normally done using :cpp:type:`ledc_timer_bit_t`. This enumeration covers the range from 10 to 15 bits. If a smaller duty resolution is required (below 10 down to 1), enter the equivalent numeric values directly. +The duty resolution is normally set using :cpp:type:`ledc_timer_bit_t`. This enumeration covers the range from 10 to 15 bits. If a smaller duty resolution is required (from 10 down to 1), enter the equivalent numeric values directly. Application Example From f3f08fa713190ad527dcf7bcb4113b82f809f4bf Mon Sep 17 00:00:00 2001 From: liu zhifu Date: Mon, 8 Jul 2019 16:23:33 +0800 Subject: [PATCH 341/486] esp_wifi/supplicant: fix some supplicant bugs Closes IDFGH-1455 Closes IDF-774 --- components/esp_wifi/lib_esp32 | 2 +- components/wpa_supplicant/Kconfig | 27 ------------------- components/wpa_supplicant/component.mk | 2 +- .../port/include/supplicant_opt.h | 12 --------- .../src/esp_supplicant/esp_wifi_driver.h | 4 ++- .../src/esp_supplicant/esp_wpa2.c | 4 --- .../src/esp_supplicant/esp_wps.c | 6 ++--- components/wpa_supplicant/src/rsn_supp/wpa.c | 7 ++--- 8 files changed, 11 insertions(+), 53 deletions(-) diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index 7c7c2e3f97..e214daa325 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit 7c7c2e3f978ddaeadb1365a0f8fbbcb423886d97 +Subproject commit e214daa325ede0981d0bd380306d4edd5a9fcc80 diff --git a/components/wpa_supplicant/Kconfig b/components/wpa_supplicant/Kconfig index 3d57c76e08..927dc0165a 100644 --- a/components/wpa_supplicant/Kconfig +++ b/components/wpa_supplicant/Kconfig @@ -1,32 +1,5 @@ menu "Supplicant" - config WPA_ENTERPRISE - bool "Enable WPA/WPA2-Enterprise" - default n - help - Select this option to enable WiFi WPA/WPA2-Enterprise authentication. - - config WPA_EAP_TLS - bool "Enable EAP-TLS" - depends on WPA_ENTERPRISE - default y - help - Select this option to support EAP-TLS. - - config WPA_EAP_TTLS - bool "Enable EAP-TTLS" - depends on WPA_ENTERPRISE - default y - help - Select this option to support EAP-TTLS. - - config WPA_EAP_PEAP - bool "Enable EAP-PEAP" - depends on WPA_ENTERPRISE - default y - help - Select this option to support EAP-PEAP. - config WPA_MBEDTLS_CRYPTO bool "Use MbedTLS crypto API's" default y diff --git a/components/wpa_supplicant/component.mk b/components/wpa_supplicant/component.mk index 1320854b95..e85e9979fb 100644 --- a/components/wpa_supplicant/component.mk +++ b/components/wpa_supplicant/component.mk @@ -2,4 +2,4 @@ COMPONENT_ADD_INCLUDEDIRS := include port/include include/esp_supplicant COMPONENT_PRIV_INCLUDEDIRS := src COMPONENT_SRCDIRS := port src/ap src/common src/crypto src/eap_peer src/rsn_supp src/tls src/utils src/esp_supplicant src/wps -CFLAGS += -DESP_SUPPLICANT -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_MSCHAPv2 -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DCONFIG_ECC -D__ets__ -Wno-strict-aliasing +CFLAGS += -DESP_SUPPLICANT -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_TLS -DEAP_TTLS -DEAP_PEAP -DEAP_MSCHAPv2 -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DCONFIG_ECC -D__ets__ -Wno-strict-aliasing diff --git a/components/wpa_supplicant/port/include/supplicant_opt.h b/components/wpa_supplicant/port/include/supplicant_opt.h index 446dda0b07..12d607add3 100644 --- a/components/wpa_supplicant/port/include/supplicant_opt.h +++ b/components/wpa_supplicant/port/include/supplicant_opt.h @@ -17,18 +17,6 @@ #include "sdkconfig.h" -#if CONFIG_WPA_EAP_TLS -#define EAP_TLS 1 -#endif - -#if CONFIG_WPA_EAP_TTLS -#define EAP_TTLS 1 -#endif - -#if CONFIG_WPA_EAP_PEAP -#define EAP_PEAP 1 -#endif - #if CONFIG_WPA_MBEDTLS_CRYPTO #define USE_MBEDTLS_CRYPTO 1 #endif diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h index fdef1d350b..62d2d6246e 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h @@ -168,7 +168,6 @@ struct wifi_ssid *esp_wifi_ap_get_prof_ap_ssid_internal(void); uint8_t esp_wifi_ap_get_prof_authmode_internal(void); uint8_t esp_wifi_sta_get_prof_authmode_internal(void); uint8_t *esp_wifi_ap_get_prof_password_internal(void); -uint8_t *esp_wifi_sta_get_prof_pmk_internal(void); struct wifi_ssid *esp_wifi_sta_get_prof_ssid_internal(void); uint8_t esp_wifi_sta_get_reset_param_internal(void); uint8_t esp_wifi_sta_get_pairwise_cipher_internal(void); @@ -216,5 +215,8 @@ bool esp_wifi_enable_sta_privacy_internal(void); uint8_t esp_wifi_get_user_init_flag_internal(void); esp_err_t esp_wifi_send_event_internal(system_event_t *evt); esp_err_t esp_wifi_internal_supplicant_header_md5_check(const char *md5); +int esp_wifi_sta_update_ap_info_internal(void); +uint8_t *esp_wifi_sta_get_ap_info_prof_pmk_internal(void); +esp_err_t esp_wifi_set_wps_start_flag_internal(bool start); #endif /* _ESP_WIFI_DRIVER_H_ */ diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c index de7a3552a8..584b2acc1b 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c @@ -808,8 +808,6 @@ static void eap_peer_sm_deinit(void) gEapSm = NULL; } -uint8_t wpa2_machine_start = 0; - esp_err_t esp_wifi_sta_wpa2_ent_enable_fn(void *arg) { struct wpa2_funcs *wpa2_cb; @@ -837,7 +835,6 @@ esp_err_t esp_wifi_sta_wpa2_ent_enable_fn(void *arg) wpa_printf(MSG_ERROR, "Register EAP Peer methods Failure\n"); } #endif - wpa2_machine_start = 1; return ESP_OK; } @@ -886,7 +883,6 @@ esp_err_t esp_wifi_sta_wpa2_ent_disable_fn(void *param) eap_peer_unregister_methods(); #endif - wpa2_machine_start = 0; return ESP_OK; } diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wps.c b/components/wpa_supplicant/src/esp_supplicant/esp_wps.c index c666de3059..cbcd351973 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wps.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wps.c @@ -1831,7 +1831,6 @@ void wifi_wps_scan(void) #endif } -uint8_t wps_start = 0; int wifi_station_wps_start(void) { struct wps_sm *sm = wps_sm_get(); @@ -1862,8 +1861,7 @@ int wifi_station_wps_start(void) default: break; } - wps_start = 1; - + esp_wifi_set_wps_start_flag_internal(true); return ESP_OK; } @@ -2125,7 +2123,7 @@ int esp_wifi_wps_disable(void) } esp_wifi_disconnect(); - wps_start = 0; + esp_wifi_set_wps_start_flag_internal(false); wps_task_deinit(); s_wps_enabled = false; API_MUTEX_GIVE(); diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.c b/components/wpa_supplicant/src/rsn_supp/wpa.c index 29d79bbc67..2ce7bbebe5 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -1778,18 +1778,19 @@ wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len) if (esp_wifi_sta_get_reset_param_internal() != 0) { // check it's psk if (strlen((char *)esp_wifi_sta_get_prof_password_internal()) == 64) { - hexstr2bin((char *)esp_wifi_sta_get_prof_password_internal(), esp_wifi_sta_get_prof_pmk_internal(), PMK_LEN); + hexstr2bin((char *)esp_wifi_sta_get_prof_password_internal(), esp_wifi_sta_get_ap_info_prof_pmk_internal(), PMK_LEN); } else { pbkdf2_sha1((char *)esp_wifi_sta_get_prof_password_internal(), (char *)sta_ssid->ssid, (size_t)sta_ssid->len, - 4096, esp_wifi_sta_get_prof_pmk_internal(), PMK_LEN); + 4096, esp_wifi_sta_get_ap_info_prof_pmk_internal(), PMK_LEN); } + esp_wifi_sta_update_ap_info_internal(); esp_wifi_sta_set_reset_param_internal(0); } if (sm->key_mgmt == WPA_KEY_MGMT_IEEE8021X) { /* TODO nothing */ } else { - memcpy(sm->pmk, esp_wifi_sta_get_prof_pmk_internal(), PMK_LEN); + memcpy(sm->pmk, esp_wifi_sta_get_ap_info_prof_pmk_internal(), PMK_LEN); } sm->pmk_len = PMK_LEN; } From 54b16b7f5a5778c195e26369a3aa8bcb67f52b4b Mon Sep 17 00:00:00 2001 From: Martin Vychodil Date: Tue, 16 Jul 2019 15:38:40 +0200 Subject: [PATCH 342/486] tools: added realpath_int() for MacOS script path resolution JIRA IDF-790 --- export.sh | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/export.sh b/export.sh index a136ab2856..9f8f98f5aa 100644 --- a/export.sh +++ b/export.sh @@ -1,5 +1,16 @@ # This script should be sourced, not executed. +function realpath_int() { + wdir="$PWD"; [ "$PWD" = "/" ] && wdir="" + case "$0" in + /*) scriptdir="${0}";; + *) scriptdir="$wdir/${0#./}";; + esac + scriptdir="${scriptdir%/*}" + echo "$scriptdir" +} + + function idf_export_main() { # The file doesn't have executable permissions, so this shouldn't really happen. # Doing this in case someone tries to chmod +x it and execute... @@ -14,8 +25,13 @@ function idf_export_main() { # If using bash, try to guess IDF_PATH from script location if [[ -n "${BASH_SOURCE}" ]] then - script_name="$(readlink -f $BASH_SOURCE)" - export IDF_PATH="$(dirname ${script_name})" + if [[ "$OSTYPE" == "darwin"* ]]; then + script_dir="$(realpath_int $BASH_SOURCE)" + else + script_name="$(readlink -f $BASH_SOURCE)" + script_dir="$(dirname $script_name)" + fi + export IDF_PATH="${script_dir}" else echo "IDF_PATH must be set before sourcing this script" return 1 @@ -67,6 +83,7 @@ function idf_export_main() { unset path_entry unset IDF_ADD_PATHS_EXTRAS unset idf_exports + # Not unsetting IDF_PYTHON_ENV_PATH, it can be used by IDF build system # to check whether we are using a private Python environment @@ -79,4 +96,5 @@ function idf_export_main() { idf_export_main +unset realpath_int unset idf_export_main From 18df3dd5ed43ee54f3d162e9b365dad3d49b95e4 Mon Sep 17 00:00:00 2001 From: chenyudong Date: Tue, 9 Jul 2019 15:55:05 +0800 Subject: [PATCH 343/486] test: move wifi library check to esp32-wifi-lib ci --- components/esp_wifi/include/esp_private/wifi.h | 11 ----------- components/esp_wifi/lib_esp32 | 2 +- components/esp_wifi/test/test_wifi_lib_git_commit.c | 12 ------------ 3 files changed, 1 insertion(+), 24 deletions(-) delete mode 100644 components/esp_wifi/test/test_wifi_lib_git_commit.c diff --git a/components/esp_wifi/include/esp_private/wifi.h b/components/esp_wifi/include/esp_private/wifi.h index 04195632fa..8671d1705a 100644 --- a/components/esp_wifi/include/esp_private/wifi.h +++ b/components/esp_wifi/include/esp_private/wifi.h @@ -255,17 +255,6 @@ esp_err_t esp_wifi_internal_wifi_type_md5_check(const char *md5); */ esp_err_t esp_wifi_internal_esp_wifi_md5_check(const char *md5); -/** - * @brief Check the git commit id of WiFi library - * - * @attention 1. It is used for internal CI WiFi library check - * - * @return - * - ESP_OK : succeed - * - ESP_FAIL : fail - */ -esp_err_t esp_wifi_internal_git_commit_id_check(void); - /** * @brief Allocate a chunk of memory for WiFi driver * diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index e214daa325..74e3b96630 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit e214daa325ede0981d0bd380306d4edd5a9fcc80 +Subproject commit 74e3b9663078d0eea8419efd73334b242bf308cd diff --git a/components/esp_wifi/test/test_wifi_lib_git_commit.c b/components/esp_wifi/test/test_wifi_lib_git_commit.c deleted file mode 100644 index f8e6f3940d..0000000000 --- a/components/esp_wifi/test/test_wifi_lib_git_commit.c +++ /dev/null @@ -1,12 +0,0 @@ -/* - Tests for the Wi-Fi -*/ -#include "unity.h" -#include "esp_log.h" -#include "esp_private/wifi.h" - -TEST_CASE("wifi lib git commit id","[wifi]") -{ - TEST_ESP_OK( esp_wifi_internal_git_commit_id_check() ); -} - From c75240a939206892c133b3a46d405a691083384f Mon Sep 17 00:00:00 2001 From: Hrishikesh Dhayagude Date: Fri, 19 Jul 2019 14:34:57 +0800 Subject: [PATCH 344/486] NimBLE: Give an option to configuration no of bonds and CCCD's to save through menuconfig --- components/bt/host/nimble/Kconfig.in | 14 ++++++++++++++ .../bt/host/nimble/port/include/esp_nimble_cfg.h | 4 ++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/components/bt/host/nimble/Kconfig.in b/components/bt/host/nimble/Kconfig.in index 24d969e747..2fcbf91c78 100644 --- a/components/bt/host/nimble/Kconfig.in +++ b/components/bt/host/nimble/Kconfig.in @@ -7,6 +7,20 @@ config BT_NIMBLE_MAX_CONNECTIONS help Defines maximum number of concurrent BLE connections +config BT_NIMBLE_MAX_BONDS + int "Maximum number of bonds to save across reboots" + default 3 + depends on BT_NIMBLE_ENABLED + help + Defines maximum number of bonds to save for peer security and our security + +config BT_NIMBLE_MAX_CCCDS + int "Maximum number of CCC descriptors to save across reboots" + default 8 + depends on BT_NIMBLE_ENABLED + help + Defines maximum number of CCC descriptors to save + config BT_NIMBLE_L2CAP_COC_MAX_NUM int "Maximum number of connection oriented channels" range 0 10 diff --git a/components/bt/host/nimble/port/include/esp_nimble_cfg.h b/components/bt/host/nimble/port/include/esp_nimble_cfg.h index 5208f733d5..7b9da75217 100644 --- a/components/bt/host/nimble/port/include/esp_nimble_cfg.h +++ b/components/bt/host/nimble/port/include/esp_nimble_cfg.h @@ -568,11 +568,11 @@ #endif #ifndef MYNEWT_VAL_BLE_STORE_MAX_BONDS -#define MYNEWT_VAL_BLE_STORE_MAX_BONDS (3) +#define MYNEWT_VAL_BLE_STORE_MAX_BONDS CONFIG_BT_NIMBLE_MAX_BONDS #endif #ifndef MYNEWT_VAL_BLE_STORE_MAX_CCCDS -#define MYNEWT_VAL_BLE_STORE_MAX_CCCDS (8) +#define MYNEWT_VAL_BLE_STORE_MAX_CCCDS CONFIG_BT_NIMBLE_MAX_CCCDS #endif #ifndef MYNEWT_VAL_BLE_STORE_CONFIG_PERSIST From 75d7ca4b6009e89320b17f0a58bc202b49a3bc18 Mon Sep 17 00:00:00 2001 From: Kirill Chalov Date: Fri, 19 Jul 2019 15:06:52 +0800 Subject: [PATCH 345/486] Review the file api-reference/peripherals/timer.rst --- docs/en/api-reference/peripherals/timer.rst | 72 +++++++++++---------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/docs/en/api-reference/peripherals/timer.rst b/docs/en/api-reference/peripherals/timer.rst index 03f093da77..77eb64028d 100644 --- a/docs/en/api-reference/peripherals/timer.rst +++ b/docs/en/api-reference/peripherals/timer.rst @@ -1,21 +1,21 @@ -TIMER +Timer ===== Introduction ------------ -The ESP32 chip contains two hardware timer groups. Each group has two general-purpose hardware timers. They are all 64-bit generic timers based on 16-bit prescalers and 64-bit auto-reload-capable up / down counters. +The ESP32 chip contains two hardware timer groups. Each group has two general-purpose hardware timers. They are all 64-bit generic timers based on 16-bit prescalers and 64-bit up / down counters which are capable of being auto-reloaded. Functional Overview ------------------- -Typical steps to configure an operate the timer are described in the following sections: +The following sections of this document cover the typical steps to configure and operate a timer: -* :ref:`timer-api-timer-initialization` - what parameters should be set up to get the timer working and what specific functionality is provided depending on the set up. -* :ref:`timer-api-timer-control` - how to read the timer's value, pause / start the timer, and change how it operates. -* :ref:`timer-api-alarms` - setting and using alarms. -* :ref:`timer-api-interrupts`- how to enable and use interrupts. +* :ref:`timer-api-timer-initialization` - covers which parameters should be set up to get the timer working, and also what specific functionality is provided depending on the timer configuration. +* :ref:`timer-api-timer-control` - describes how to read a timer's value, pause or start a timer, and change how it operates. +* :ref:`timer-api-alarms` - shows how to set and use alarms. +* :ref:`timer-api-interrupts`- explains how to enable and use interrupts. .. _timer-api-timer-initialization: @@ -23,18 +23,18 @@ Typical steps to configure an operate the timer are described in the following s Timer Initialization ^^^^^^^^^^^^^^^^^^^^ -The two timer groups on-board of the ESP32 are identified using :cpp:type:`timer_group_t`. Individual timers in a group are identified with :cpp:type:`timer_idx_t`. The two groups, each having two timers, provide the total of four individual timers to our disposal. +The two ESP32 timer groups, with two timers in each, provide the total of four individual timers for use. An ESP32 timer group should be identified using :cpp:type:`timer_group_t`. An individual timer in a group should be identified with :cpp:type:`timer_idx_t`. -Before starting the timer, it should be initialized by calling :cpp:func:`timer_init`. This function should be provided with a structure :cpp:type:`timer_config_t` to define how timer should operate. In particular the following timer's parameters may be set: +First of all, the timer should be initialized by calling the function :cpp:func:`timer_init` and passing a structure :cpp:type:`timer_config_t` to it to define how the timer should operate. In particular, the following timer parameters can be set: - * **Divider**: How quickly the timer's counter is "ticking". This depends on the setting of :cpp:member:`divider`, that will be used as divisor of the incoming 80 MHz APB_CLK clock. - * **Mode**: If the the counter is incrementing or decrementing, defined using :cpp:member:`counter_dir` by selecting one of values from :cpp:type:`timer_count_dir_t`. - * **Counter Enable**: If the counter is enabled, then it will start incrementing / decrementing immediately after calling :cpp:func:`timer_init`. This action is set using :cpp:member:`counter_en` by selecting one of vales from :cpp:type:`timer_start_t`. - * **Alarm Enable**: Determined by the setting of :cpp:member:`alarm_en`. - * **Auto Reload**: Whether the counter should :cpp:member:`auto_reload` a specific initial value on the timer's alarm, or continue incrementing or decrementing. - * **Interrupt Type**: Whether an interrupt is triggered on timer's alarm. Set the value defined in :cpp:type:`timer_intr_mode_t`. + * **Divider**: Sets how quickly the timer's counter is "ticking". The setting :cpp:member:`divider` is used as a divisor of the incoming 80 MHz APB_CLK clock. + * **Mode**: Sets if the counter should be incrementing or decrementing. It can be defined using :cpp:member:`counter_dir` by selecting one of the values from :cpp:type:`timer_count_dir_t`. + * **Counter Enable**: If the counter is enabled, it will start incrementing / decrementing immediately after calling :cpp:func:`timer_init`. You can change the behavior with :cpp:member:`counter_en` by selecting one of the values from :cpp:type:`timer_start_t`. + * **Alarm Enable**: Can be set using :cpp:member:`alarm_en`. + * **Auto Reload**: Sets if the counter should :cpp:member:`auto_reload` the initial counter value on the timer's alarm or continue incrementing or decrementing. + * **Interrupt Type**: Select which interrupt type should be triggered on the timer's alarm. Set the value defined in :cpp:type:`timer_intr_mode_t`. -To get the current values of the timers settings, use function :cpp:func:`timer_get_config`. +To get the current values of the timer's settings, use the function :cpp:func:`timer_get_config`. .. _timer-api-timer-control: @@ -42,35 +42,40 @@ To get the current values of the timers settings, use function :cpp:func:`timer_ Timer Control ^^^^^^^^^^^^^ -Once the timer is configured and enabled, it is already "ticking". To check it's current value call :cpp:func:`timer_get_counter_value` or :cpp:func:`timer_get_counter_time_sec`. To set the timer to specific starting value call :cpp:func:`timer_set_counter_value`. +Once the timer is enabled, its counter starts running. To enable the timer, call the function :cpp:func:`timer_init` with :cpp:member:`counter_en` set to ``true``, or call :cpp:func:`timer_start`. You can specify the timer's initial counter value by calling :cpp:func:`timer_set_counter_value`. To check the timer's current value, call :cpp:func:`timer_get_counter_value` or :cpp:func:`timer_get_counter_time_sec`. -The timer may be paused at any time by calling :cpp:func:`timer_pause`. To start it again call :cpp:func:`timer_start`. +To pause the timer at any time, call :cpp:func:`timer_pause`. To resume it, call :cpp:func:`timer_start`. -To change how the timer operates you can call once more :cpp:func:`timer_init` described in section :ref:`timer-api-timer-initialization`. Another option is to use dedicated functions to change individual settings: +To reconfigure the timer, you can call :cpp:func:`timer_init`. This function is described in Section :ref:`timer-api-timer-initialization`. - * **Divider** value - :cpp:func:`timer_set_divider`. **Note:** the timer should be paused when changing the divider to avoid unpredictable results. If the timer is already running, :cpp:func:`timer_set_divider` will first pause the timer, change the divider, and finally start the timer again. - * **Mode** (whether the counter incrementing or decrementing) - :cpp:func:`timer_set_counter_mode` - * **Auto Reload** counter on alarm - :cpp:func:`timer_set_auto_reload` +You can also reconfigure the timer by using dedicated functions to change individual settings: +============= =================================== ========================================================================== +Setting Dedicated Function Description +============= =================================== ========================================================================== +Divider :cpp:func:`timer_set_divider` Change the rate of ticking. To avoid unpredictable results, the timer should be paused when changing the divider. If the timer is running, :cpp:func:`timer_set_divider` pauses it, change the setting, and start the timer again. +Mode :cpp:func:`timer_set_counter_mode` Set if the counter should be incrementing or decrementing +Auto Reload :cpp:func:`timer_set_auto_reload` Set if the initial counter value should be reloaded on the timer's alarm +============= =================================== ========================================================================== .. _timer-api-alarms: Alarms ^^^^^^ -To set an alarm, call function :cpp:func:`timer_set_alarm_value` and then enable it with :cpp:func:`timer_set_alarm`. The alarm may be also enabled during the timer initialization stage, when :cpp:func:`timer_init` is called. +To set an alarm, call the function :cpp:func:`timer_set_alarm_value` and then enable the alarm using :cpp:func:`timer_set_alarm`. The alarm can also be enabled during the timer initialization stage, when :cpp:func:`timer_init` is called. -After the alarm is enabled and the timer reaches the alarm value, depending on configuration, the following two actions may happen: +After the alarm is enabled, and the timer reaches the alarm value, the following two actions can occur depending on the configuration: - * An interrupt will be triggered, if previously configured. See section :ref:`timer-api-interrupts` how to configure interrupts. - * When :cpp:member:`auto_reload` is enabled, the timer's counter will be reloaded to start counting from specific initial value. The value to start should be set in advance with :cpp:func:`timer_set_counter_value`. + * An interrupt will be triggered if previously configured. See Section :ref:`timer-api-interrupts` on how to configure interrupts. + * When :cpp:member:`auto_reload` is enabled, the timer's counter will automatically be reloaded to start counting again from a previously configured value. This value should be set in advance with :cpp:func:`timer_set_counter_value`. .. note:: - * The alarm will be triggered immediately, if an alarm value is set and the timer has already passed this value. - * Once triggered the alarm will be disabled automatically and needs to be re-armed to trigger again. + * If an alarm value is set and the timer has already reached this value, the alarm is triggered immediately. + * Once triggered, the alarm is disabled automatically and needs to be re-enabled to trigger again. -To check what alarm value has been set up, call :cpp:func:`timer_get_alarm_value`. +To check the specified alarm value, call :cpp:func:`timer_get_alarm_value`. .. _timer-api-interrupts: @@ -78,15 +83,16 @@ To check what alarm value has been set up, call :cpp:func:`timer_get_alarm_value Interrupts ^^^^^^^^^^ -Registration of the interrupt handler for a specific timer group and timer is done be calling :cpp:func:`timer_isr_register`. +Registration of the interrupt handler for a specific timer or a timer group can be done by calling :cpp:func:`timer_isr_register`. -To enable interrupts for a timer group call :cpp:func:`timer_group_intr_enable`. To do it for a specific timer, call :cpp:func:`timer_enable_intr`. Disabling of interrupts is done with corresponding functions :cpp:func:`timer_group_intr_disable` and :cpp:func:`timer_disable_intr`. +To enable interrupts for a timer group, call :cpp:func:`timer_group_intr_enable`, for a specific timer call :cpp:func:`timer_enable_intr`. +To disable interrupts for a timer group, call :cpp:func:`timer_group_intr_disable`, for a specified timer, call :cpp:func:`timer_disable_intr`. -When servicing an interrupt within an ISR, the interrupt need to explicitly cleared. To do so, set the ``TIMERGN.int_clr_timers.tM`` structure defined in :component_file:`soc/esp32/include/soc/timer_group_struct.h`, where N is the timer group number [0, 1] and M is the timer number [0, 1]. For example to clear an interrupt for the timer 1 in the timer group 0, call the following:: +When handling an interrupt within an interrupt serivce routine (ISR), the interrupt status bit needs to be explicitly cleared. To do that, set the ``TIMERGN.int_clr_timers.tM`` structure, defined in :component_file:`soc/esp32/include/soc/timer_group_struct.h`. In this structure, ``N`` is the timer group number [0, 1], ``M`` is the timer number [0, 1]. For example, to clear an interrupt status bit for the timer 1 in the timer group 0, call the following:: TIMERG0.int_clr_timers.t1 = 1 -See the application example below how to use interrupts. +For more information on how to use interrupts, please see the application example below. Application Example From d767e0edc7074b035e8448b44dd87b7dea22ab9a Mon Sep 17 00:00:00 2001 From: Wang Ning Date: Fri, 19 Jul 2019 19:04:44 +0800 Subject: [PATCH 346/486] Add Chinese translation to api-reference/network/esp_smartconfig.rst --- docs/en/api-reference/network/esp_smartconfig.rst | 6 ++++-- docs/zh_CN/api-reference/network/esp_smartconfig.rst | 10 +++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/en/api-reference/network/esp_smartconfig.rst b/docs/en/api-reference/network/esp_smartconfig.rst index 7ad26f5fbc..f21453aa57 100644 --- a/docs/en/api-reference/network/esp_smartconfig.rst +++ b/docs/en/api-reference/network/esp_smartconfig.rst @@ -1,5 +1,7 @@ -Smart Config -============ +SmartConfig +=========== + +:link_to_translation:`zh_CN:[中文]` API Reference ------------- diff --git a/docs/zh_CN/api-reference/network/esp_smartconfig.rst b/docs/zh_CN/api-reference/network/esp_smartconfig.rst index 00a8e6f660..dd99c84e93 100644 --- a/docs/zh_CN/api-reference/network/esp_smartconfig.rst +++ b/docs/zh_CN/api-reference/network/esp_smartconfig.rst @@ -1 +1,9 @@ -.. include:: ../../../en/api-reference/network/esp_smartconfig.rst +SmartConfig +=========== + +:link_to_translation:`en:[English]` + +API 参考 +------------- + +.. include:: /_build/inc/esp_smartconfig.inc From aaf3dcbda01e8c22da88184922465155441cd20a Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 22 Jul 2019 08:56:43 +0200 Subject: [PATCH 347/486] tools: installer: fix quoting of IDF_TOOLS_PATH IDF_TOOLS_PATH may contain spaces, so needs to be properly quoted. Closes https://github.com/espressif/esp-idf/issues/3807 --- tools/windows/tool_setup/idf_cmd_init.bat | 6 +++--- tools/windows/tool_setup/idf_setup.iss.inc | 10 ++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/tools/windows/tool_setup/idf_cmd_init.bat b/tools/windows/tool_setup/idf_cmd_init.bat index 853dcf4da7..039266e7b9 100644 --- a/tools/windows/tool_setup/idf_cmd_init.bat +++ b/tools/windows/tool_setup/idf_cmd_init.bat @@ -18,8 +18,8 @@ if "%~2"=="" ( goto :end ) -set IDF_PYTHON_DIR=%1 -set IDF_GIT_DIR=%2 +set "IDF_PYTHON_DIR=%1" +set "IDF_GIT_DIR=%2" :: Strip quoutes set "IDF_PYTHON_DIR=%IDF_PYTHON_DIR:"=%" @@ -69,7 +69,7 @@ echo Adding ESP-IDF tools to PATH... :: It is possible to do this without a temporary file (running idf_tools.py from for /r command), :: but that way it is impossible to get the exit code of idf_tools.py. set "IDF_TOOLS_EXPORTS_FILE=%TEMP%\idf_export_vars.tmp" -python.exe %IDF_TOOLS_PY_PATH% --tools-json %IDF_TOOLS_JSON_PATH% export --format key-value >"%IDF_TOOLS_EXPORTS_FILE%" +python.exe "%IDF_TOOLS_PY_PATH%" --tools-json "%IDF_TOOLS_JSON_PATH%" export --format key-value >"%IDF_TOOLS_EXPORTS_FILE%" if %errorlevel% neq 0 goto :end for /f "usebackq tokens=1,2 eol=# delims==" %%a in ("%IDF_TOOLS_EXPORTS_FILE%") do ( diff --git a/tools/windows/tool_setup/idf_setup.iss.inc b/tools/windows/tool_setup/idf_setup.iss.inc index 30c626a8dc..c1dd9e1139 100644 --- a/tools/windows/tool_setup/idf_setup.iss.inc +++ b/tools/windows/tool_setup/idf_setup.iss.inc @@ -142,7 +142,7 @@ begin end; ExtractTemporaryFile('7za.exe') - CmdLine := ExpandConstant('{tmp}\7za.exe x -o' + ExpandConstant('{tmp}') + ' -r -aoa ' + IDFZIPFileName); + CmdLine := ExpandConstant('{tmp}\7za.exe x -o' + ExpandConstant('{tmp}') + ' -r -aoa "' + IDFZIPFileName + '"'); IDFTempPath := ExpandConstant('{tmp}\esp-idf-') + IDFZIPFileVersion; Log('Extracting ESP-IDF reference repository: ' + CmdLine); Log('Reference repository path: ' + IDFTempPath); @@ -212,9 +212,9 @@ begin end else begin Log('idf_tools.py does not exist in IDF directory, using a fallback version'); IDFToolsPyCmd := ExpandConstant(PythonExecutablePath - + ' {app}\idf_tools_fallback.py' + + ' "{app}\idf_tools_fallback.py"' + ' --idf-path ' + IDFPath - + ' --tools {app}\tools_fallback.json'); + + ' --tools "{app}\tools_fallback.json"'); end; Log('idf_tools.py command: ' + IDFToolsPyCmd); @@ -238,7 +238,9 @@ begin ForceDirectories(ExpandConstant('{group}')); Destination := ExpandConstant('{group}\{#IDFCmdExeShortcutFile}'); Description := '{#IDFCmdExeShortcutDescription}'; - Command := ExpandConstant('/k {app}\idf_cmd_init.bat "') + PythonPath + '" "' + GitPath + '"'; + { If cmd.exe command argument starts with a quote, the first and last quote chars in the command + will be removed by cmd.exe; each argument needs to be surrounded by quotes as well. } + Command := ExpandConstant('/k ""{app}\idf_cmd_init.bat" "') + PythonPath + '" "' + GitPath + '""'; Log('CreateShellLink Destination=' + Destination + ' Description=' + Description + ' Command=' + Command) try CreateShellLink( From 9c5284e7b580a757ad7ecc3ef814a269d5f58eb9 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 22 Jul 2019 08:57:21 +0200 Subject: [PATCH 348/486] tools: installer: verify that IDF_PATH doesn't contain spaces --- tools/windows/tool_setup/idf_download_page.iss.inc | 9 ++++++++- tools/windows/tool_setup/idf_page.iss.inc | 7 +++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/tools/windows/tool_setup/idf_download_page.iss.inc b/tools/windows/tool_setup/idf_download_page.iss.inc index 3636123e7e..6f501c059f 100644 --- a/tools/windows/tool_setup/idf_download_page.iss.inc +++ b/tools/windows/tool_setup/idf_download_page.iss.inc @@ -102,6 +102,7 @@ var Page: TInputOptionWizardPage; IDFPath: String; begin + Result := False; Page := TInputOptionWizardPage(Sender); Log('OnIDFDownloadPageValidate index=' + IntToStr(Page.SelectedValueIndex)); @@ -110,7 +111,13 @@ begin begin MsgBox('Directory already exists and is not empty:' + #13#10 + IDFPath + #13#10 + 'Please choose a different directory.', mbError, MB_OK); - Result := False; + exit; + end; + + if Pos(' ', IDFPath) <> 0 then + begin + MsgBox('ESP-IDF build system does not support spaces in paths.' + #13#10 + 'Please choose a different directory.', mbError, MB_OK); exit; end; diff --git a/tools/windows/tool_setup/idf_page.iss.inc b/tools/windows/tool_setup/idf_page.iss.inc index 87cc5c5d07..e6baef9c8f 100644 --- a/tools/windows/tool_setup/idf_page.iss.inc +++ b/tools/windows/tool_setup/idf_page.iss.inc @@ -75,6 +75,13 @@ begin exit; end; + if Pos(' ', IDFPath) <> 0 then + begin + MsgBox('ESP-IDF build system does not support spaces in paths.' + #13#10 + 'Please choose a different directory.', mbError, MB_OK); + exit; + end; + IDFPyPath := IDFPath + '\tools\idf.py'; if not FileExists(IDFPyPath) then begin From af78311975e30198f126243c1eaf2e7b2ed6ac32 Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Thu, 11 Jul 2019 10:47:17 +0800 Subject: [PATCH 349/486] ethernet: malloc hal together with driver context --- components/esp_eth/src/esp_eth_mac_esp32.c | 79 ++++++++++------------ components/esp_eth/test/test_emac.c | 2 +- components/soc/esp32/emac_hal.c | 2 +- 3 files changed, 39 insertions(+), 44 deletions(-) diff --git a/components/esp_eth/src/esp_eth_mac_esp32.c b/components/esp_eth/src/esp_eth_mac_esp32.c index 1c1fbcc90c..cb83e220ea 100644 --- a/components/esp_eth/src/esp_eth_mac_esp32.c +++ b/components/esp_eth/src/esp_eth_mac_esp32.c @@ -46,7 +46,7 @@ static const char *TAG = "emac_esp32"; typedef struct { esp_eth_mac_t parent; esp_eth_mediator_t *eth; - emac_hal_context_t *hal; + emac_hal_context_t hal; intr_handle_t intr_hdl; SemaphoreHandle_t rx_counting_sem; TaskHandle_t rx_task_hdl; @@ -72,15 +72,15 @@ static esp_err_t emac_esp32_write_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, { esp_err_t ret = ESP_OK; emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); - MAC_CHECK(!emac_hal_is_mii_busy(emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE); - emac_hal_set_phy_data(emac->hal, reg_value); - emac_hal_set_phy_cmd(emac->hal, phy_addr, phy_reg, true); + MAC_CHECK(!emac_hal_is_mii_busy(&emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE); + emac_hal_set_phy_data(&emac->hal, reg_value); + emac_hal_set_phy_cmd(&emac->hal, phy_addr, phy_reg, true); /* polling the busy flag */ uint32_t to = 0; bool busy = true; do { ets_delay_us(100); - busy = emac_hal_is_mii_busy(emac->hal); + busy = emac_hal_is_mii_busy(&emac->hal); to += 100; } while (busy && to < PHY_OPERATION_TIMEOUT_US); MAC_CHECK(!busy, "phy is busy", err, ESP_ERR_TIMEOUT); @@ -94,19 +94,19 @@ static esp_err_t emac_esp32_read_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, esp_err_t ret = ESP_OK; MAC_CHECK(reg_value, "can't set reg_value to null", err, ESP_ERR_INVALID_ARG); emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); - MAC_CHECK(!emac_hal_is_mii_busy(emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE); - emac_hal_set_phy_cmd(emac->hal, phy_addr, phy_reg, false); + MAC_CHECK(!emac_hal_is_mii_busy(&emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE); + emac_hal_set_phy_cmd(&emac->hal, phy_addr, phy_reg, false); /* polling the busy flag */ uint32_t to = 0; bool busy = true; do { ets_delay_us(100); - busy = emac_hal_is_mii_busy(emac->hal); + busy = emac_hal_is_mii_busy(&emac->hal); to += 100; } while (busy && to < PHY_OPERATION_TIMEOUT_US); MAC_CHECK(!busy, "phy is busy", err, ESP_ERR_TIMEOUT); /* Store value */ - *reg_value = emac_hal_get_phy_data(emac->hal); + *reg_value = emac_hal_get_phy_data(&emac->hal); return ESP_OK; err: return ret; @@ -118,7 +118,7 @@ static esp_err_t emac_esp32_set_addr(esp_eth_mac_t *mac, uint8_t *addr) MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG); emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); memcpy(emac->addr, addr, 6); - emac_hal_set_address(emac->hal, emac->addr); + emac_hal_set_address(&emac->hal, emac->addr); return ESP_OK; err: return ret; @@ -142,11 +142,11 @@ static esp_err_t emac_esp32_set_link(esp_eth_mac_t *mac, eth_link_t link) switch (link) { case ETH_LINK_UP: MAC_CHECK(esp_intr_enable(emac->intr_hdl) == ESP_OK, "enable interrupt failed", err, ESP_FAIL); - emac_hal_start(emac->hal); + emac_hal_start(&emac->hal); break; case ETH_LINK_DOWN: MAC_CHECK(esp_intr_disable(emac->intr_hdl) == ESP_OK, "disable interrupt failed", err, ESP_FAIL); - emac_hal_stop(emac->hal); + emac_hal_stop(&emac->hal); break; default: MAC_CHECK(false, "unknown link status", err, ESP_ERR_INVALID_ARG); @@ -163,10 +163,10 @@ static esp_err_t emac_esp32_set_speed(esp_eth_mac_t *mac, eth_speed_t speed) emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); switch (speed) { case ETH_SPEED_10M: - emac_hal_set_speed(emac->hal, EMAC_SPEED_10M); + emac_hal_set_speed(&emac->hal, EMAC_SPEED_10M); break; case ETH_SPEED_100M: - emac_hal_set_speed(emac->hal, EMAC_SPEED_100M); + emac_hal_set_speed(&emac->hal, EMAC_SPEED_100M); break; default: MAC_CHECK(false, "unknown speed", err, ESP_ERR_INVALID_ARG); @@ -183,10 +183,10 @@ static esp_err_t emac_esp32_set_duplex(esp_eth_mac_t *mac, eth_duplex_t duplex) emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); switch (duplex) { case ETH_DUPLEX_HALF: - emac_hal_set_duplex(emac->hal, EMAC_DUPLEX_HALF); + emac_hal_set_duplex(&emac->hal, EMAC_DUPLEX_HALF); break; case ETH_DUPLEX_FULL: - emac_hal_set_duplex(emac->hal, EMAC_DUPLEX_FULL); + emac_hal_set_duplex(&emac->hal, EMAC_DUPLEX_FULL); break; default: MAC_CHECK(false, "unknown duplex", err, ESP_ERR_INVALID_ARG); @@ -200,7 +200,7 @@ err: static esp_err_t emac_esp32_set_promiscuous(esp_eth_mac_t *mac, bool enable) { emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); - emac_hal_set_promiscuous(emac->hal, enable); + emac_hal_set_promiscuous(&emac->hal, enable); return ESP_OK; } @@ -211,9 +211,9 @@ static esp_err_t emac_esp32_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint32_t MAC_CHECK(buf, "can't set buf to null", err, ESP_ERR_INVALID_ARG); MAC_CHECK(length, "buf length can't be zero", err, ESP_ERR_INVALID_ARG); /* Check if the descriptor is owned by the Ethernet DMA (when 1) or CPU (when 0) */ - MAC_CHECK(emac_hal_get_tx_desc_owner(emac->hal) == EMAC_DMADESC_OWNER_CPU, + MAC_CHECK(emac_hal_get_tx_desc_owner(&emac->hal) == EMAC_DMADESC_OWNER_CPU, "CPU doesn't own the Tx Descriptor", err, ESP_ERR_INVALID_STATE); - emac_hal_transmit_frame(emac->hal, buf, length); + emac_hal_transmit_frame(&emac->hal, buf, length); return ESP_OK; err: return ret; @@ -224,7 +224,7 @@ static esp_err_t emac_esp32_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t * esp_err_t ret = ESP_OK; emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); MAC_CHECK(buf && length, "can't set buf and length to null", err, ESP_ERR_INVALID_ARG); - *length = emac_hal_receive_frame(emac->hal, buf, &emac->frames_remain); + *length = emac_hal_receive_frame(&emac->hal, buf, &emac->frames_remain); return ESP_OK; err: return ret; @@ -274,7 +274,7 @@ static esp_err_t emac_esp32_init(esp_eth_mac_t *mac) /* enable peripheral clock */ periph_module_enable(PERIPH_EMAC_MODULE); /* enable clock, config gpio, etc */ - emac_hal_lowlevel_init(emac->hal); + emac_hal_lowlevel_init(&emac->hal); /* init gpio used by gpio */ emac_esp32_init_smi_gpio(); #if CONFIG_ETH_PHY_USE_RST @@ -284,27 +284,27 @@ static esp_err_t emac_esp32_init(esp_eth_mac_t *mac) #endif MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL) == ESP_OK, "lowlevel init failed", err, ESP_FAIL); /* software reset */ - emac_hal_reset(emac->hal); + emac_hal_reset(&emac->hal); uint32_t to = 0; for (to = 0; to < emac->sw_reset_timeout_ms / 10; to++) { - if (emac_hal_is_reset_done(emac->hal)) { + if (emac_hal_is_reset_done(&emac->hal)) { break; } vTaskDelay(pdMS_TO_TICKS(10)); } MAC_CHECK(to < emac->sw_reset_timeout_ms / 10, "reset timeout", err, ESP_ERR_TIMEOUT); /* set smi clock */ - emac_hal_set_csr_clock_range(emac->hal); + emac_hal_set_csr_clock_range(&emac->hal); /* reset descriptor chain */ - emac_hal_reset_desc_chain(emac->hal); + emac_hal_reset_desc_chain(&emac->hal); /* init mac registers by default */ - emac_hal_init_mac_default(emac->hal); + emac_hal_init_mac_default(&emac->hal); /* init dma registers by default */ - emac_hal_init_dma_default(emac->hal); + emac_hal_init_dma_default(&emac->hal); /* get emac address from efuse */ MAC_CHECK(esp_read_mac(emac->addr, ESP_MAC_ETH) == ESP_OK, "fetch ethernet mac address failed", err, ESP_FAIL); /* set MAC address to emac register */ - emac_hal_set_address(emac->hal, emac->addr); + emac_hal_set_address(&emac->hal, emac->addr); return ESP_OK; err: eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL); @@ -319,7 +319,7 @@ static esp_err_t emac_esp32_deinit(esp_eth_mac_t *mac) #if CONFIG_ETH_PHY_USE_RST gpio_set_level(CONFIG_ETH_PHY_RST_GPIO, 0); #endif - emac_hal_stop(emac->hal); + emac_hal_stop(&emac->hal); eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL); periph_module_disable(PERIPH_EMAC_MODULE); return ESP_OK; @@ -333,13 +333,12 @@ static esp_err_t emac_esp32_del(esp_eth_mac_t *mac) vSemaphoreDelete(emac->rx_counting_sem); int i = 0; for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { - free(emac->hal->rx_buf[i]); + free(emac->hal.rx_buf[i]); } for (i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { - free(emac->hal->tx_buf[i]); + free(emac->hal.tx_buf[i]); } - free(emac->hal->descriptors); - free(emac->hal); + free(emac->hal.descriptors); free(emac); return ESP_OK; } @@ -355,8 +354,6 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config) CONFIG_ETH_DMA_TX_BUFFER_NUM * sizeof(eth_dma_tx_descriptor_t); void *descriptors = heap_caps_calloc(1, desc_size, MALLOC_CAP_DMA); MAC_CHECK(descriptors, "calloc descriptors failed", err_desc, NULL); - emac->hal = (emac_hal_context_t *)calloc(1, sizeof(emac_hal_context_t)); - MAC_CHECK(emac->hal, "calloc emac hal failed", err_hal, NULL); int i = 0; /* alloc memory for ethernet dma buffer */ for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { @@ -387,7 +384,7 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config) goto err_buffer; } /* initialize hal layer driver */ - emac_hal_init(emac->hal, descriptors, emac->rx_buf, emac->tx_buf); + emac_hal_init(&emac->hal, descriptors, emac->rx_buf, emac->tx_buf); emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms; emac->parent.set_mediator = emac_esp32_set_mediator; emac->parent.init = emac_esp32_init; @@ -427,8 +424,6 @@ err_intr: free(emac->rx_buf[i]); } err_buffer: - free(emac->hal); -err_hal: free(descriptors); err_desc: free(emac); @@ -438,8 +433,8 @@ err: void emac_hal_rx_complete_cb(void *arg) { - emac_hal_context_t **hal_addr = (emac_hal_context_t **)arg; - emac_esp32_t *emac = __containerof(hal_addr, emac_esp32_t, hal); + emac_hal_context_t *hal = (emac_hal_context_t *)arg; + emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal); BaseType_t high_task_wakeup; /* send message to rx thread */ xSemaphoreGiveFromISR(emac->rx_counting_sem, &high_task_wakeup); @@ -450,8 +445,8 @@ void emac_hal_rx_complete_cb(void *arg) void emac_hal_rx_unavail_cb(void *arg) { - emac_hal_context_t **hal_addr = (emac_hal_context_t **)arg; - emac_esp32_t *emac = __containerof(hal_addr, emac_esp32_t, hal); + emac_hal_context_t *hal = (emac_hal_context_t *)arg; + emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal); BaseType_t high_task_wakeup; /* send message to rx thread */ xSemaphoreGiveFromISR(emac->rx_counting_sem, &high_task_wakeup); diff --git a/components/esp_eth/test/test_emac.c b/components/esp_eth/test/test_emac.c index 141bf3e1da..2ebe98b023 100644 --- a/components/esp_eth/test/test_emac.c +++ b/components/esp_eth/test/test_emac.c @@ -76,7 +76,7 @@ TEST_CASE("esp32 emac io test", "[ethernet][ignore]") TEST_CASE("ethernet tcpip_adapter", "[ethernet][ignore]") { - tcpip_adapter_init(); + test_case_uses_tcpip(); TEST_ESP_OK(esp_event_loop_create_default()); TEST_ESP_OK(tcpip_adapter_set_default_eth_handlers()); TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL)); diff --git a/components/soc/esp32/emac_hal.c b/components/soc/esp32/emac_hal.c index 4722ee4ecf..509b66b502 100644 --- a/components/soc/esp32/emac_hal.c +++ b/components/soc/esp32/emac_hal.c @@ -521,7 +521,7 @@ uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t void emac_hal_isr(void *arg) { - emac_hal_context_t *hal = *(emac_hal_context_t **)arg; + emac_hal_context_t *hal = (emac_hal_context_t *)arg; typeof(hal->dma_regs->dmastatus) dma_status = hal->dma_regs->dmastatus; /* DMA Normal Interrupt */ if (dma_status.norm_int_summ) { From cfbf8c5d07d0ece7adbe5eb32c97410223491f16 Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Thu, 11 Jul 2019 11:01:51 +0800 Subject: [PATCH 350/486] ethernet: task yield at the end of isr handler --- components/esp_eth/linker.lf | 1 + components/esp_eth/src/esp_eth_mac_esp32.c | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/components/esp_eth/linker.lf b/components/esp_eth/linker.lf index 69f864d8d6..64969708d9 100644 --- a/components/esp_eth/linker.lf +++ b/components/esp_eth/linker.lf @@ -7,5 +7,6 @@ entries: esp_eth_mac_esp32:emac_hal_rx_complete_cb (noflash_text) esp_eth_mac_esp32:emac_hal_rx_early_cb (noflash_text) esp_eth_mac_esp32:emac_hal_rx_unavail_cb (noflash_text) + esp_eth_mac_esp32:emac_esp32_isr_handler (noflash_text) if ETH_SPI_ETHERNET_DM9051 = y: esp_eth_mac_dm9051:dm9051_isr_handler (noflash_text) diff --git a/components/esp_eth/src/esp_eth_mac_esp32.c b/components/esp_eth/src/esp_eth_mac_esp32.c index cb83e220ea..cea8868a3b 100644 --- a/components/esp_eth/src/esp_eth_mac_esp32.c +++ b/components/esp_eth/src/esp_eth_mac_esp32.c @@ -55,6 +55,7 @@ typedef struct { uint8_t addr[6]; uint8_t *rx_buf[CONFIG_ETH_DMA_RX_BUFFER_NUM]; uint8_t *tx_buf[CONFIG_ETH_DMA_TX_BUFFER_NUM]; + bool isr_need_yield; } emac_esp32_t; static esp_err_t emac_esp32_set_mediator(esp_eth_mac_t *mac, esp_eth_mediator_t *eth) @@ -343,6 +344,17 @@ static esp_err_t emac_esp32_del(esp_eth_mac_t *mac) return ESP_OK; } +void emac_esp32_isr_handler(void *args) +{ + emac_hal_context_t *hal = (emac_hal_context_t *)args; + emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal); + emac_hal_isr(args); + if (emac->isr_need_yield) { + emac->isr_need_yield = false; + portYIELD_FROM_ISR(); + } +} + esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config) { esp_eth_mac_t *ret = NULL; @@ -401,7 +413,7 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config) emac->parent.transmit = emac_esp32_transmit; emac->parent.receive = emac_esp32_receive; /* Interrupt configuration */ - MAC_CHECK(esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, ESP_INTR_FLAG_IRAM, emac_hal_isr, + MAC_CHECK(esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, ESP_INTR_FLAG_IRAM, emac_esp32_isr_handler, &emac->hal, &(emac->intr_hdl)) == ESP_OK, "alloc emac interrupt failed", err_intr, NULL); /* create counting semaphore */ @@ -438,8 +450,8 @@ void emac_hal_rx_complete_cb(void *arg) BaseType_t high_task_wakeup; /* send message to rx thread */ xSemaphoreGiveFromISR(emac->rx_counting_sem, &high_task_wakeup); - if (high_task_wakeup != pdFALSE) { - portYIELD_FROM_ISR(); + if (high_task_wakeup == pdTRUE) { + emac->isr_need_yield = true; } } @@ -450,7 +462,7 @@ void emac_hal_rx_unavail_cb(void *arg) BaseType_t high_task_wakeup; /* send message to rx thread */ xSemaphoreGiveFromISR(emac->rx_counting_sem, &high_task_wakeup); - if (high_task_wakeup != pdFALSE) { - portYIELD_FROM_ISR(); + if (high_task_wakeup == pdTRUE) { + emac->isr_need_yield = true; } } From 97ad2bcb86eb7328229bf3d2a44b4a8be39a1238 Mon Sep 17 00:00:00 2001 From: Tomer Shefler Date: Thu, 11 Jul 2019 21:01:28 +0300 Subject: [PATCH 351/486] ethernet: support giving 50mhz rmii clock with both 40mhz and 26 mhz rtc xtal Merges https://github.com/espressif/esp-idf/pull/3769 Closes https://github.com/espressif/esp-idf/pull/3704 --- components/soc/esp32/emac_hal.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/components/soc/esp32/emac_hal.c b/components/soc/esp32/emac_hal.c index 509b66b502..121bc53269 100644 --- a/components/soc/esp32/emac_hal.c +++ b/components/soc/esp32/emac_hal.c @@ -20,6 +20,34 @@ #define ETH_CRC_LENGTH (4) +#if CONFIG_ETH_RMII_CLK_OUTPUT +static void emac_config_apll_clock(void) +{ + /* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) */ + rtc_xtal_freq_t rtc_xtal_freq = rtc_clk_xtal_freq_get(); + switch (rtc_xtal_freq) { + case RTC_XTAL_FREQ_40M: // Recommended + /* 50 MHz = 40MHz * (4 + 6) / (2 * (2 + 2) = 50.000 */ + /* sdm0 = 0, sdm1 = 0, sdm2 = 6, o_div = 2 */ + rtc_clk_apll_enable(true, 0, 0, 6, 2); + break; + case RTC_XTAL_FREQ_26M: + /* 50 MHz = 26MHz * (4 + 15 + 118 / 256 + 39/65536) / ((3 + 2) * 2) = 49.999992 */ + /* sdm0 = 39, sdm1 = 118, sdm2 = 15, o_div = 3 */ + rtc_clk_apll_enable(true, 39, 118, 15, 3); + break; + case RTC_XTAL_FREQ_24M: + /* 50 MHz = 24MHz * (4 + 12 + 255 / 256 + 255/65536) / ((2 + 2) * 2) = 49.499977 */ + /* sdm0 = 255, sdm1 = 255, sdm2 = 12, o_div = 2 */ + rtc_clk_apll_enable(true, 255, 255, 12, 2); + break; + default: // Assume we have a 40M xtal + rtc_clk_apll_enable(true, 0, 0, 6, 2); + break; + } +} +#endif + void emac_hal_init(emac_hal_context_t *hal, void *descriptors, uint8_t **rx_buf, uint8_t **tx_buf) { @@ -91,10 +119,7 @@ void emac_hal_lowlevel_init(emac_hal_context_t *hal) hal->ext_regs->ex_clk_ctrl.ext_en = 0; hal->ext_regs->ex_clk_ctrl.int_en = 1; hal->ext_regs->ex_oscclk_conf.clk_sel = 0; - /* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) */ - /* 50 MHz = 40MHz * (4 + 6) / (2 * (2 + 2) = 400MHz / 8 */ - /* sdm2 = 6, sdm1 = 0, sdm0 = 0, o_div = 2 */ - rtc_clk_apll_enable(true, 0, 0, 6, 2); + emac_config_apll_clock(); hal->ext_regs->ex_clkout_conf.div_num = 0; hal->ext_regs->ex_clkout_conf.h_div_num = 0; #if CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0 From 018de8101fb8356dd5ed17a02535d0f78673a5bc Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Fri, 12 Jul 2019 17:58:45 +0800 Subject: [PATCH 352/486] ethernet: can build without enable esp32 emac Closes https://github.com/espressif/esp-idf/issues/3770 --- components/esp_eth/CMakeLists.txt | 2 +- components/esp_eth/component.mk | 2 +- components/soc/esp32/component.mk | 4 ++++ components/soc/esp32/sources.cmake | 2 +- components/soc/linker.lf | 13 +++++++------ 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/components/esp_eth/CMakeLists.txt b/components/esp_eth/CMakeLists.txt index 7f41a8409e..3829df1885 100644 --- a/components/esp_eth/CMakeLists.txt +++ b/components/esp_eth/CMakeLists.txt @@ -4,7 +4,7 @@ set(esp_eth_srcs "src/esp_eth.c" "src/esp_eth_phy_lan8720.c" "src/esp_eth_phy_rtl8201.c") -if(CONFIG_IDF_TARGET_ESP32) +if(CONFIG_ETH_USE_ESP32_EMAC) list(APPEND esp_eth_srcs "src/esp_eth_mac_esp32.c") endif() diff --git a/components/esp_eth/component.mk b/components/esp_eth/component.mk index 2a5ba23b38..3a768fdf8c 100644 --- a/components/esp_eth/component.mk +++ b/components/esp_eth/component.mk @@ -5,7 +5,7 @@ COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_SRCDIRS := src COMPONENT_ADD_LDFRAGMENTS += linker.lf -ifndef CONFIG_IDF_TARGET_ESP32 +ifndef CONFIG_ETH_USE_ESP32_EMAC COMPONENT_OBJEXCLUDE += src/esp_eth_mac_esp32.o endif diff --git a/components/soc/esp32/component.mk b/components/soc/esp32/component.mk index 83a2ef722e..52c33c8d24 100644 --- a/components/soc/esp32/component.mk +++ b/components/soc/esp32/component.mk @@ -1 +1,5 @@ +ifndef CONFIG_ETH_USE_ESP32_EMAC + COMPONENT_OBJEXCLUDE += esp32/emac_hal.o +endif + esp32/rtc_clk.o: CFLAGS += -fno-jump-tables -fno-tree-switch-conversion diff --git a/components/soc/esp32/sources.cmake b/components/soc/esp32/sources.cmake index ea4201cc0d..a5471b6b36 100644 --- a/components/soc/esp32/sources.cmake +++ b/components/soc/esp32/sources.cmake @@ -13,7 +13,7 @@ set(SOC_SRCS "cpu_util.c" "soc_memory_layout.c" "spi_periph.c") -if(NOT BOOTLOADER_BUILD) +if(NOT BOOTLOADER_BUILD AND CONFIG_ETH_USE_ESP32_EMAC) list(APPEND SOC_SRCS "emac_hal.c") endif() diff --git a/components/soc/linker.lf b/components/soc/linker.lf index 2d0918a8bb..21aa0a0331 100644 --- a/components/soc/linker.lf +++ b/components/soc/linker.lf @@ -14,9 +14,10 @@ entries: spi_slave_hal_iram (noflash_text) spi_flash_hal_iram (noflash) lldesc (noflash_text) - emac_hal:emac_hal_isr (noflash_text) - emac_hal:emac_hal_tx_complete_cb (noflash_text) - emac_hal:emac_hal_tx_unavail_cb (noflash_text) - emac_hal:emac_hal_rx_complete_cb (noflash_text) - emac_hal:emac_hal_rx_early_cb (noflash_text) - emac_hal:emac_hal_rx_unavail_cb (noflash_text) + if ETH_USE_ESP32_EMAC = y: + emac_hal:emac_hal_isr (noflash_text) + emac_hal:emac_hal_tx_complete_cb (noflash_text) + emac_hal:emac_hal_tx_unavail_cb (noflash_text) + emac_hal:emac_hal_rx_complete_cb (noflash_text) + emac_hal:emac_hal_rx_early_cb (noflash_text) + emac_hal:emac_hal_rx_unavail_cb (noflash_text) From f38c1c18a871e3d587aac48da6f9d0c0ba79e0b7 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 23 Jul 2019 06:20:52 +0200 Subject: [PATCH 353/486] tools: install.bat: bail out if idf_tools.py call fails Makes installation errors easier to spot. --- install.bat | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/install.bat b/install.bat index fdb9771a46..784fd850cd 100644 --- a/install.bat +++ b/install.bat @@ -10,10 +10,13 @@ set IDF_PATH=%IDF_PATH:~0,-1% echo Installing ESP-IDF tools python.exe %IDF_PATH%\tools\idf_tools.py install +if %errorlevel% neq 0 goto :end echo Setting up Python environment python.exe %IDF_PATH%\tools\idf_tools.py install-python-env +if %errorlevel% neq 0 goto :end echo All done! You can now run: echo export.bat -:: Clean up + +:end From b70ac4deb7e6fa27aa2a930cd7db0963a29515f7 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 23 Jul 2019 06:55:30 +0200 Subject: [PATCH 354/486] tools: idf_tools.py: improve error message when no downloads found ...for the given platform. Previously would raise AssertionError. --- tools/idf_tools.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/idf_tools.py b/tools/idf_tools.py index 7cdd182366..b5cfb08038 100755 --- a/tools/idf_tools.py +++ b/tools/idf_tools.py @@ -441,6 +441,9 @@ class IDFTool(object): def get_install_type(self): return self._current_options.install + def compatible_with_platform(self): + return any([v.compatible_with_platform() for v in self.versions.values()]) + def get_recommended_version(self): recommended_versions = [k for k, v in self.versions.items() if v.status == IDFToolVersion.STATUS_RECOMMENDED @@ -1030,6 +1033,9 @@ def action_install(args): fatal('unknown tool name: {}'.format(tool_name)) raise SystemExit(1) tool_obj = tools_info[tool_name] + if not tool_obj.compatible_with_platform(): + fatal('tool {} does not have versions compatible with platform {}'.format(tool_name, CURRENT_PLATFORM)) + raise SystemExit(1) if tool_version is not None and tool_version not in tool_obj.versions: fatal('unknown version for tool {}: {}'.format(tool_name, tool_version)) raise SystemExit(1) From 1271008dd80a75dd564e425bc76f3e6684692830 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 23 Jul 2019 06:57:36 +0200 Subject: [PATCH 355/486] tools: tools.json: don't require ulp-binutils and openocd on x86 Linux Fixes https://esp32.com/viewtopic.php?f=13&t=11540 --- tools/tools.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tools/tools.json b/tools/tools.json index 5bbed7e8b7..3204ec3ad9 100644 --- a/tools/tools.json +++ b/tools/tools.json @@ -69,6 +69,15 @@ "install": "always", "license": "GPL-2.0-or-later", "name": "esp32ulp-elf", + "platform_overrides": [ + { + "install": "on_request", + "platforms": [ + "linux-armel", + "linux-i686" + ] + } + ], "version_cmd": [ "esp32ulp-elf-as", "--version" @@ -182,6 +191,15 @@ "install": "always", "license": "GPL-2.0-only", "name": "openocd-esp32", + "platform_overrides": [ + { + "install": "on_request", + "platforms": [ + "linux-armel", + "linux-i686" + ] + } + ], "version_cmd": [ "openocd", "--version" From 639687f92bf489a0e2dab4f4ed464e06420ad3ad Mon Sep 17 00:00:00 2001 From: Kirill Chalov Date: Tue, 23 Jul 2019 17:45:41 +0800 Subject: [PATCH 356/486] Replace gif images on EN and zh_CN index pages with identical png images for successful building of PDFs on ReadTheDocs. --- docs/_static/api-guides.gif | Bin 3285 -> 0 bytes docs/_static/api-guides.png | Bin 0 -> 7875 bytes docs/_static/api-reference.gif | Bin 3100 -> 0 bytes docs/_static/api-reference.png | Bin 0 -> 6986 bytes docs/_static/contribute.gif | Bin 3377 -> 0 bytes docs/_static/contribute.png | Bin 0 -> 6437 bytes docs/_static/esp32-pico-kit-v4.1-layout.jpg | Bin 90612 -> 0 bytes docs/_static/get-started-garbled-output.png | Bin 0 -> 17717 bytes docs/_static/get-started.gif | Bin 2865 -> 0 bytes docs/_static/get-started.png | Bin 0 -> 6625 bytes docs/_static/hw-reference.gif | Bin 3032 -> 0 bytes docs/_static/hw-reference.png | Bin 0 -> 6567 bytes docs/_static/resources.gif | Bin 2454 -> 0 bytes docs/_static/resources.png | Bin 0 -> 4482 bytes docs/en/get-started-legacy/index.rst | 8 +- docs/en/get-started/index.rst | 8 +- docs/en/index.rst | 12 +- docs/zh_CN/get-started-legacy/index.rst | 894 +++++++++--------- docs/zh_CN/get-started/index.rst | 986 ++++++++++---------- docs/zh_CN/index.rst | 12 +- 20 files changed, 960 insertions(+), 960 deletions(-) delete mode 100644 docs/_static/api-guides.gif create mode 100644 docs/_static/api-guides.png delete mode 100644 docs/_static/api-reference.gif create mode 100644 docs/_static/api-reference.png delete mode 100644 docs/_static/contribute.gif create mode 100644 docs/_static/contribute.png delete mode 100644 docs/_static/esp32-pico-kit-v4.1-layout.jpg create mode 100644 docs/_static/get-started-garbled-output.png delete mode 100644 docs/_static/get-started.gif create mode 100644 docs/_static/get-started.png delete mode 100644 docs/_static/hw-reference.gif create mode 100644 docs/_static/hw-reference.png delete mode 100644 docs/_static/resources.gif create mode 100644 docs/_static/resources.png diff --git a/docs/_static/api-guides.gif b/docs/_static/api-guides.gif deleted file mode 100644 index bc9dd36dba1f4c17e6cda59528cf28c8d66bc67e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3285 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 diff --git a/docs/_static/api-guides.png b/docs/_static/api-guides.png new file mode 100644 index 0000000000000000000000000000000000000000..885e36bba1300f1d83220cfe9cc79a6a435267a2 GIT binary patch literal 7875 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 H4Ez59?Tp%x diff --git a/docs/_static/api-reference.png b/docs/_static/api-reference.png new file mode 100644 index 0000000000000000000000000000000000000000..91b09ad6e747923218a309ae366baa3eda09a727 GIT binary patch literal 6986 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 i|34Y-lsn==pJS_!d2W7aBa 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 S1`CKvl8Z`7!_d;wy!^q- diff --git a/docs/_static/contribute.png b/docs/_static/contribute.png new file mode 100644 index 0000000000000000000000000000000000000000..1984736545fb6090fddeb65c71e57aac2e075d57 GIT binary patch literal 6437 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 No7ZZu%H&Nx{|`-9U~K>Z literal 0 HcmV?d00001 diff --git a/docs/_static/esp32-pico-kit-v4.1-layout.jpg b/docs/_static/esp32-pico-kit-v4.1-layout.jpg deleted file mode 100644 index 3c9e64fcf51da1ddf764b4ce198a763c386f9b7b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 90612 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 BRIdO4 diff --git a/docs/_static/get-started-garbled-output.png b/docs/_static/get-started-garbled-output.png new file mode 100644 index 0000000000000000000000000000000000000000..2e6dd68ca388d8dc958f03aa305a47e11dc94d7c GIT binary patch literal 17717 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 P|4vDZD~MH!82J4^%w0@h literal 0 HcmV?d00001 diff --git a/docs/_static/get-started.gif b/docs/_static/get-started.gif deleted file mode 100644 index 7a7a8023b694b3fe0baaeaaa00a8110de2181795..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2865 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 diff --git a/docs/_static/get-started.png b/docs/_static/get-started.png new file mode 100644 index 0000000000000000000000000000000000000000..3444635115adc3cfbddfb098cbea231747f79567 GIT binary patch literal 6625 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 OSUMW|>UFAi@&5x4yHHO6 literal 0 HcmV?d00001 diff --git a/docs/_static/hw-reference.gif b/docs/_static/hw-reference.gif deleted file mode 100644 index 0b969c209988a8f8993dbc3e79e42588e12d6313..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3032 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 jE&gNQ)7xsu6>TGgWNaWur}o1J_h0Q diff --git a/docs/_static/hw-reference.png b/docs/_static/hw-reference.png new file mode 100644 index 0000000000000000000000000000000000000000..ec31ab52b9796f9adcc0eb88086b4c3bfc5a5839 GIT binary patch literal 6567 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 MQt4~O7vsSH0W}+RlmGw# literal 0 HcmV?d00001 diff --git a/docs/_static/resources.gif b/docs/_static/resources.gif deleted file mode 100644 index cde4bd80946ced3c907e931d3c66f7aa3c1b0845..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2454 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 PRp|6}jJ0uE4pILBOVc!_ literal 0 HcmV?d00001 diff --git a/docs/en/get-started-legacy/index.rst b/docs/en/get-started-legacy/index.rst index bd3d000ce1..7e8f93ca0b 100644 --- a/docs/en/get-started-legacy/index.rst +++ b/docs/en/get-started-legacy/index.rst @@ -373,10 +373,10 @@ To exit IDF monitor use the shortcut ``Ctrl+]``. If IDF monitor fails shortly after the upload, or if instead of the messages above you see a random garbage similar to what is given below, your board is likely using a 26MHz crystal. Most development board designs use 40MHz, so ESP-IDF uses this frequency as a default value. -.. code-block:: none - - e���)(Xn@�y.!��(�PW+)��Hn9a؅/9�!�t5��P�~�k��e�ea�5�jA - ~zY��Y(1�,1�� e���)(Xn@�y.!Dr�zY(�jpi�|�+z5Ymvp +.. figure:: ../../_static/get-started-garbled-output.png + :align: center + :alt: Garbled output + :figclass: align-center If you have such a problem, do the following: diff --git a/docs/en/get-started/index.rst b/docs/en/get-started/index.rst index 51b87fa32c..713362bb72 100644 --- a/docs/en/get-started/index.rst +++ b/docs/en/get-started/index.rst @@ -447,10 +447,10 @@ To exit IDF monitor use the shortcut ``Ctrl+]``. If IDF monitor fails shortly after the upload, or, if instead of the messages above, you see random garbage similar to what is given below, your board is likely using a 26MHz crystal. Most development board designs use 40MHz, so ESP-IDF uses this frequency as a default value. -.. code-block:: none - - e���)(Xn@�y.!��(�PW+)��Hn9a؅/9�!�t5��P�~�k��e�ea�5�jA - ~zY��Y(1�,1�� e���)(Xn@�y.!Dr�zY(�jpi�|�+z5Ymvp +.. figure:: ../../_static/get-started-garbled-output.png + :align: center + :alt: Garbled output + :figclass: align-center If you have such a problem, do the following: diff --git a/docs/en/index.rst b/docs/en/index.rst index d8a10c1d45..2a2f3382a2 100644 --- a/docs/en/index.rst +++ b/docs/en/index.rst @@ -14,24 +14,24 @@ This is the documentation for Espressif IoT Development Framework (`esp-idf `_。 - - -.. figure:: ../../_static/what-you-need.png - :align: center - :alt: ESP32 应用程序开发 - :figclass: align-center - - ESP32 应用程序开发 - - -开发板简介 -========== - -请点击下方连接,了解有关具体开发板的详细信息。 - -.. toctree:: - :maxdepth: 1 - - ESP32-DevKitC <../hw-reference/get-started-devkitc> - ESP-WROVER-KIT <../hw-reference/get-started-wrover-kit> - ESP32-PICO-KIT <../hw-reference/get-started-pico-kit> - ESP32-Ethernet-Kit <../hw-reference/get-started-ethernet-kit> - - -.. _get-started-step-by-step-legacy: - -详细安装步骤 -============ - -请根据下方详细步骤,完成安装过程。 - -设置开发环境 -~~~~~~~~~~~~ - -* :ref:`get-started-setup-toolchain-legacy` -* :ref:`get-started-get-esp-idf-legacy` -* :ref:`get-started-setup-path-legacy` -* :ref:`get-started-get-packages-legacy` - -创建您的第一个工程 -~~~~~~~~~~~~~~~~~~ - -* :ref:`get-started-start-project-legacy` -* :ref:`get-started-connect-legacy` -* :ref:`get-started-configure-legacy` -* :ref:`get-started-build-and-flash-legacy` -* :ref:`get-started-monitor-legacy` - - -.. _get-started-setup-toolchain-legacy: - -第一步:设置工具链 -================== - -工具链指一套用于编译代码和应用程序的程序。 - -为了加快开发进度,您可以直接使用乐鑫提供的预制工具链。请根据您的操作系统,点击下方对应的链接,并按照链接中的指导进行安装。 - -.. toctree:: - :hidden: - - Windows - Linux - MacOS - -+-----------------------------+-------------------------+----------------------------------+ -| |windows-logo| | |linux-logo| | |macos-logo| | -+-----------------------------+-------------------------+----------------------------------+ -| `Windows `_ | `Linux `_ | `Mac OS `_ | -+-----------------------------+-------------------------+----------------------------------+ - -.. |windows-logo| image:: ../../_static/windows-logo.png - :target: ../get-started-legacy/windows-setup.html - -.. |linux-logo| image:: ../../_static/linux-logo.png - :target: ../get-started-legacy/linux-setup.html - -.. |macos-logo| image:: ../../_static/macos-logo.png - :target: ../get-started-legacy/macos-setup.html - -.. _Windows-legacy: ../get-started-legacy/windows-setup.html -.. _Linux-legacy: ../get-started-legacy/linux-setup.html -.. _Mac OS-legacy: ../get-started-legacy/macos-setup.html - -.. note:: - - 在本文档中,Linux 和 MacOS 操作系统中 ESP-IDF 的默认安装路径为 ``~/esp``;Windows 操作系统的默认路径为 ``%userprofile%\esp``。您也可以将 ESP-IDF 安装在任何其他路径下,但请注意在使用命令行时进行相应替换。注意,ESP-IDF 不支持带有空格的路径。 - -此外, 您也可以根据自身经验和实际需求,对环境进行个性化设置,而非使用预制工具链。此时,请前往 :ref:`工具链的个性化设置` 章节获取更多信息。 - - -.. _get-started-get-esp-idf-legacy: - -第二步:获取 ESP-IDF -===================== - -除了工具链,您还需要供 ESP32 使用的 API(软件库和源代码),具体请见 `ESP-IDF 仓库 `_。 - -获取本地副本:打开终端,切换到你要存放 ESP-IDF 的工作目录,使用 ``git clone`` 命令克隆远程仓库。 - -打开终端,后运行以下命令: - -.. include:: /_build/inc/git-clone-bash.inc - -ESP-IDF 将下载至 ``~/esp/esp-idf``。 - -请前往 :doc:`/versions`,查看 ESP-IDF 不同版本的具体适用场景。 - -.. include:: /_build/inc/git-clone-notes.inc - -.. note:: - - 在克隆远程仓库时,不要忘记加上 ``--recursive`` 选项。否则,请接着运行以下命令,获取所有子模块: :: - - cd esp-idf - git submodule update --init - - -.. _get-started-setup-path-legacy: - -第三步:设置环境变量 -===================== - -工具链通过环境变量 ``IDF_PATH`` 获得 ESP-IDF 的目录。因此,您需要在 PC 中设置该环境变量,否则无法编译工程。 - -您可以在每次重启会话时手动设置,也可以在用户配置中进行永久设置,具体请前往 :doc:`add-idf_path-to-profile` 章节,查看 :ref:`Windows ` 、:ref:`Linux 及 MacOS ` 操作系统的具体设置方式。 - - -.. _get-started-get-packages-legacy: - -第四步:安装 Python 软件包 -========================== - -ESP-IDF 所需 Python 软件包位于 ``IDF_PATH/requirements.txt`` 中。您可以运行以下命令进行安装: :: - - python -m pip install --user -r $IDF_PATH/requirements.txt - -.. note:: - - 请注意查询您所使用的 Python 解释器的版本(运行命令 ``python --version``),并根据查询结果将上方命令中的 ``python`` 替换为 ``python2``, ``python2.7``,例如: :: - - python2.7 -m pip install --user -r $IDF_PATH/requirements.txt - - -.. _get-started-start-project-legacy: - -第五步:开始创建工程 -===================== - -现在,您可以开始准备开发 ESP32 应用程序了。您可以从 ESP-IDF 中 :idf:`examples` 目录下的 :example:`get-started/hello_world` 工程开始。 - -将 :example:`get-started/hello_world` 复制至您本地的 ``~/esp`` 目录下: - -Linux 和 MacOS 操作系统 -~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: bash - - cd ~/esp - cp -r $IDF_PATH/examples/get-started/hello_world . - -Windows 操作系统 -~~~~~~~~~~~~~~~~~~ - -.. code-block:: batch - - cd %userprofile%\esp - xcopy /e /i %IDF_PATH%\examples\get-started\hello_world hello_world - -ESP-IDF 的 :idf:`examples` 目录下有一系列示例工程,都可以按照上面的方法进行创建。您可以按照上述方法复制并运行其中的任何示例,也可以直接编译示例,无需进行复制。 - -.. important:: - - ESP-IDF 编译系统不支持带有空格的路径。 - -.. _get-started-connect-legacy: - -第六步:连接设备 -================== - -现在,请将您的 ESP32 开发板连接到 PC,并查看开发板使用的串口。 - -通常,串口在不同操作系统下显示的名称有所不同: - -- **Windows 操作系统:** ``COM1`` 等 -- **Linux 操作系统:** 以 ``/dev/tty`` 开始 -- **MacOS 操作系统:** 以 ``/dev/cu.`` 开始 - -有关如何查看串口名称的详细信息,请见 :doc:`establish-serial-connection`。 - -.. note:: - - 请记住串口名,您会在下面的步骤中用到。 - - -.. _get-started-configure-legacy: - -第七步:配置 -============= - -请进入 :ref:`get-started-start-project-legacy` 中提到的 ``hello_world`` 目录,并运行工程配置工具 ``menuconfig``。 - -Linux 和 MacOS 操作系统 -~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: bash - - cd ~/esp/hello_world - make menuconfig - -Windows 操作系统 -~~~~~~~~~~~~~~~~~~~ - -.. code-block:: batch - - cd %userprofile%\esp\hello_world - make menuconfig - -如果之前的步骤都正确,则会显示下面的菜单: - -.. figure:: ../../_static/project-configuration.png - :align: center - :alt: 工程配置 — 主窗口 - :figclass: align-center - - 工程配置 — 主窗口 - -进入菜单后,选择 ``Serial flasher config`` > ``Default serial port`` 配置串口(设备将通过该串口加载工程)。按回车键确认选择,点击 ``< Save >`` 保存配置,然后点击 ``< Exit >`` 退出 ``menuconfig``。 - -``menuconfig`` 工具的常见操作见下。 - -* ``上下箭头``:移动 -* ``回车``:进入子菜单 -* ``ESC 键``:返回上级菜单或退出 -* ``英文问号``:调出帮助菜单(退出帮助菜单,请按回车键)。 -* ``空格``、``Y 键``或``N 键``:使能/禁用 ``[*]`` 配置选项 -* ``英文问号`` :调出有关高亮选项的帮助菜单 -* ``/ 键``:寻找配置项目 - -.. note:: - - 如果您是 **Arch Linux** 用户,请前往 ``SDK tool configuration``,并将 ``Python 2 interpreter`` 的名称从 ``python`` 替换为 ``python2``。 - -.. attention:: - - 如果您使用的是 ESP32-DevKitC(板载 ESP32-SOLO-1 模组),请在烧写示例程序前,前往 ``menuconfig`` 中使能单核模式(:ref:`CONFIG_FREERTOS_UNICORE`)。 - -.. _get-started-build-and-flash-legacy: - -第八步:编译和烧录 -==================== - -请使用以下命令,编译烧录工程: :: - - make flash - -运行以上命令可以编译应用程序和所有 ESP-IDF 组件,接着生成 bootloader、分区表和应用程序二进制文件。接着,这些二进制文件将被烧录至 ESP32 开发板。 - -如果一切顺利,您可在烧录完成后看到类似下方的打印信息(代表加载进程)。接着,开发板将会复位,应用程序 "hello_world" 开始启动。 - -.. highlight:: none - -:: - - esptool.py v2.0-beta2 - Flashing binaries to serial port /dev/ttyUSB0 (app at offset 0x10000)... - esptool.py v2.0-beta2 - Connecting........___ - Uploading stub... - Running stub... - Stub running... - Changing baud rate to 921600 - Changed. - Attaching SPI flash... - Configuring flash size... - Auto-detected Flash size:4MB - Flash params set to 0x0220 - Compressed 11616 bytes to 6695... - Wrote 11616 bytes (6695 compressed) at 0x00001000 in 0.1 seconds (effective 920.5 kbit/s)... - Hash of data verified. - Compressed 408096 bytes to 171625... - Wrote 408096 bytes (171625 compressed) at 0x00010000 in 3.9 seconds (effective 847.3 kbit/s)... - Hash of data verified. - Compressed 3072 bytes to 82... - Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 8297.4 kbit/s)... - Hash of data verified. - - Leaving... - Hard resetting... - - -如果您希望使用 Eclipse IDE,而非 ``make`` 编译系统,请参考 :doc:`Eclipse 指南 `。 - - -.. _get-started-monitor-legacy: - -第九步:监视器 -=============== - -您可以使用 ``make monitor`` 命令,监视 “hello_world” 的运行情况。 - -运行该命令后,:doc:`IDF 监视器 <../api-guides/tools/idf-monitor>` 应用程序将启动: :: - - $ make monitor - MONITOR - --- idf_monitor on /dev/ttyUSB0 115200 --- - --- Quit:Ctrl+] | Menu:Ctrl+T | Help:Ctrl+T followed by Ctrl+H --- - ets Jun 8 2016 00:22:57 - - rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) - ets Jun 8 2016 00:22:57 - ... - -此时,您就可以在启动日志和诊断日志之后,看到打印的 “Hello world!” 了。 - -.. code-block:: none - - ... - Hello world! - Restarting in 10 seconds... - I (211) cpu_start:Starting scheduler on APP CPU. - Restarting in 9 seconds... - Restarting in 8 seconds... - Restarting in 7 seconds... - -您可使用快捷键 ``Ctrl+]``,退出 IDF 监视器。 - -如果 IDF 监视器在烧录后很快发生错误,或打印信息全是乱码(见下),很有可能是因为您的开发板选用了 26 MHz 晶振,而 ESP-IDF 默认支持大多数开发板使用的 40 MHz 晶振。 - -.. code-block:: none - - e���)(Xn@�y.!��(�PW+)��Hn9a؅/9�!�t5��P�~�k��e�ea�5�jA - ~zY��Y(1�,1�� e���)(Xn@�y.!Dr�zY(�jpi�|�+z5Ymvp - -此时,请您: - -1. 退出监视器。 -2. 打开 :ref:`menuconfig `, -3. 进入 ``Component config`` --> ``ESP32-specific`` --> ``Main XTAL frequency`` 进行配置,将 :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` 设置为 26 MHz。 -4. 然后,请重新 :ref:`编译和烧录 ` 应用程序。 - -.. note:: - - 您也可以运行以下命令,一次性执行构建、烧录和监视过程: :: - - make flash monitor - -此外,请前往 :doc:`IDF 监视器 <../api-guides/tools/idf-monitor>`,了解更多使用 IDF 监视器的快捷键和其他详情。 - -**恭喜,您已完成 ESP32 的入门学习!** - -现在,您可以尝试一些其他 :idf:`examples`,或者直接开发自己的应用程序。 - - -环境变量 -========= - -用户可以在使用 ``make`` 命令时 **直接设置** 部分环境变量,而无需进入 ``make menuconfig`` 进行重新配置。这些变量包括: - -+-----------------+-----------------------------------------------------------------------+ -| 变量 | 描述与使用方式 | -+-----------------+-----------------------------------------------------------------------+ -| ``ESPPORT`` | 覆盖 ``flash`` 和 ``monitor`` 命令使用的串口。 | -+ +-----------------------------------------------------------------------+ -| | 例:``make flash ESPPORT=/dev/ttyUSB1``, ``make monitor ESPPORT=COM1``| -+-----------------+-----------------------------------------------------------------------+ -| ``ESPBAUD`` | 覆盖烧录 ESP32 时使用的串口速率。 | -+ +-----------------------------------------------------------------------+ -| | 例:``make flash ESPBAUD=9600`` | -+-----------------+-----------------------------------------------------------------------+ -| ``MONITORBAUD`` | 覆盖监控时使用的串口速率。 | -+ +-----------------------------------------------------------------------+ -| | 例:``make monitor MONITORBAUD=9600`` | -+-----------------+-----------------------------------------------------------------------+ - -.. note:: - - 您可导出环境变量(例:``export ESPPORT=/dev/ttyUSB1``)。 - 在同一会话窗口中,如果未被同步覆盖,所有 ``make`` 命令均会使用导出的环境变量值。 - - -更新 ESP-IDF -============= - -乐鑫会不时推出更新版本的 ESP-IDF,修复 bug 或提出新的特性。因此,在使用时,您也应注意更新您本地的版本。最简单的方法是:直接删除您本地的 ``esp-idf`` 文件夹,然后按照 :ref:`get-started-get-esp-idf-legacy` 中的指示,重新完成克隆。 - -如果您希望将 ESP-IDF 克隆到新的路径下,请务必 :doc:`重新设置 IDF_PATH `。否则,工具链将无法找到 ESP-IDF。 - -此外,您可以仅更新变更部分。具体方式,请前往 :ref:`更新 ` 章节查看。 - -相关文档 -========= - -.. toctree:: - :maxdepth: 1 - - add-idf_path-to-profile - establish-serial-connection - make-project - eclipse-setup - ../api-guides/tools/idf-monitor - toolchain-setup-scratch - -.. _Stable version: https://docs.espressif.com/projects/esp-idf/zh_CN/stable/ -.. _Releases page: https://github.com/espressif/esp-idf/releases +*************************** +快速入门 (传统 GNU Make) +*************************** +:link_to_translation:`en:[English]` + +.. include:: ../gnu-make-legacy.rst + +本文档旨在指导用户搭建 ESP32 硬件开发的软件环境, + +通过一个简单的示例展示如何使用 ESP-IDF (Espressif IoT Development Framework) 配置菜单,并编译、下载固件至 ESP32 开发板等步骤。 + +.. include:: /_build/inc/version-note.inc + +概述 +==== + +ESP32 SoC 芯片支持以下功能: + +* 2.4 GHz Wi-Fi +* 蓝牙 4.2 标准 +* 高性能双核 +* 超低功耗协处理器 +* 多种外设 + +ESP32 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、稳定性、通用性和可靠性,适用于各种应用场景和不同功耗需求。 + +乐鑫为用户提供完整的软、硬件资源,进行 ESP32 硬件设备的开发。其中,乐鑫的软件开发环境 ESP-IDF 旨在协助用户快速开发物联网 (IoT) 应用,可满足用户对 Wi-Fi、蓝牙、低功耗等方面的要求。 + +准备工作 +======== + +硬件: + +* 一款 **ESP32** 开发板 +* **USB 数据线** (USB A/Micro USB B) +* PC(Windows、Linux 或 Mac OS) + +软件: + +* 设置 **工具链**,用于编译 ESP32 **应用程序**; +* 获取 **ESP-IDF** 软件开发框架。该框架已经基本包含 ESP32 使用的 API(软件库和源代码)和运行 **工具链** 的脚本; +* 安装 C 语言编程(**工程**)的 **文本编辑器**,例如 `Eclipse `_。 + + +.. figure:: ../../_static/what-you-need.png + :align: center + :alt: ESP32 应用程序开发 + :figclass: align-center + + ESP32 应用程序开发 + + +开发板简介 +========== + +请点击下方连接,了解有关具体开发板的详细信息。 + +.. toctree:: + :maxdepth: 1 + + ESP32-DevKitC <../hw-reference/get-started-devkitc> + ESP-WROVER-KIT <../hw-reference/get-started-wrover-kit> + ESP32-PICO-KIT <../hw-reference/get-started-pico-kit> + ESP32-Ethernet-Kit <../hw-reference/get-started-ethernet-kit> + + +.. _get-started-step-by-step-legacy: + +详细安装步骤 +============ + +请根据下方详细步骤,完成安装过程。 + +设置开发环境 +~~~~~~~~~~~~ + +* :ref:`get-started-setup-toolchain-legacy` +* :ref:`get-started-get-esp-idf-legacy` +* :ref:`get-started-setup-path-legacy` +* :ref:`get-started-get-packages-legacy` + +创建您的第一个工程 +~~~~~~~~~~~~~~~~~~ + +* :ref:`get-started-start-project-legacy` +* :ref:`get-started-connect-legacy` +* :ref:`get-started-configure-legacy` +* :ref:`get-started-build-and-flash-legacy` +* :ref:`get-started-monitor-legacy` + + +.. _get-started-setup-toolchain-legacy: + +第一步:设置工具链 +================== + +工具链指一套用于编译代码和应用程序的程序。 + +为了加快开发进度,您可以直接使用乐鑫提供的预制工具链。请根据您的操作系统,点击下方对应的链接,并按照链接中的指导进行安装。 + +.. toctree:: + :hidden: + + Windows + Linux + MacOS + ++-----------------------------+-------------------------+----------------------------------+ +| |windows-logo| | |linux-logo| | |macos-logo| | ++-----------------------------+-------------------------+----------------------------------+ +| `Windows `_ | `Linux `_ | `Mac OS `_ | ++-----------------------------+-------------------------+----------------------------------+ + +.. |windows-logo| image:: ../../_static/windows-logo.png + :target: ../get-started-legacy/windows-setup.html + +.. |linux-logo| image:: ../../_static/linux-logo.png + :target: ../get-started-legacy/linux-setup.html + +.. |macos-logo| image:: ../../_static/macos-logo.png + :target: ../get-started-legacy/macos-setup.html + +.. _Windows-legacy: ../get-started-legacy/windows-setup.html +.. _Linux-legacy: ../get-started-legacy/linux-setup.html +.. _Mac OS-legacy: ../get-started-legacy/macos-setup.html + +.. note:: + + 在本文档中,Linux 和 MacOS 操作系统中 ESP-IDF 的默认安装路径为 ``~/esp``;Windows 操作系统的默认路径为 ``%userprofile%\esp``。您也可以将 ESP-IDF 安装在任何其他路径下,但请注意在使用命令行时进行相应替换。注意,ESP-IDF 不支持带有空格的路径。 + +此外, 您也可以根据自身经验和实际需求,对环境进行个性化设置,而非使用预制工具链。此时,请前往 :ref:`工具链的个性化设置` 章节获取更多信息。 + + +.. _get-started-get-esp-idf-legacy: + +第二步:获取 ESP-IDF +===================== + +除了工具链,您还需要供 ESP32 使用的 API(软件库和源代码),具体请见 `ESP-IDF 仓库 `_。 + +获取本地副本:打开终端,切换到你要存放 ESP-IDF 的工作目录,使用 ``git clone`` 命令克隆远程仓库。 + +打开终端,后运行以下命令: + +.. include:: /_build/inc/git-clone-bash.inc + +ESP-IDF 将下载至 ``~/esp/esp-idf``。 + +请前往 :doc:`/versions`,查看 ESP-IDF 不同版本的具体适用场景。 + +.. include:: /_build/inc/git-clone-notes.inc + +.. note:: + + 在克隆远程仓库时,不要忘记加上 ``--recursive`` 选项。否则,请接着运行以下命令,获取所有子模块: :: + + cd esp-idf + git submodule update --init + + +.. _get-started-setup-path-legacy: + +第三步:设置环境变量 +===================== + +工具链通过环境变量 ``IDF_PATH`` 获得 ESP-IDF 的目录。因此,您需要在 PC 中设置该环境变量,否则无法编译工程。 + +您可以在每次重启会话时手动设置,也可以在用户配置中进行永久设置,具体请前往 :doc:`add-idf_path-to-profile` 章节,查看 :ref:`Windows ` 、:ref:`Linux 及 MacOS ` 操作系统的具体设置方式。 + + +.. _get-started-get-packages-legacy: + +第四步:安装 Python 软件包 +========================== + +ESP-IDF 所需 Python 软件包位于 ``IDF_PATH/requirements.txt`` 中。您可以运行以下命令进行安装: :: + + python -m pip install --user -r $IDF_PATH/requirements.txt + +.. note:: + + 请注意查询您所使用的 Python 解释器的版本(运行命令 ``python --version``),并根据查询结果将上方命令中的 ``python`` 替换为 ``python2``, ``python2.7``,例如: :: + + python2.7 -m pip install --user -r $IDF_PATH/requirements.txt + + +.. _get-started-start-project-legacy: + +第五步:开始创建工程 +===================== + +现在,您可以开始准备开发 ESP32 应用程序了。您可以从 ESP-IDF 中 :idf:`examples` 目录下的 :example:`get-started/hello_world` 工程开始。 + +将 :example:`get-started/hello_world` 复制至您本地的 ``~/esp`` 目录下: + +Linux 和 MacOS 操作系统 +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: bash + + cd ~/esp + cp -r $IDF_PATH/examples/get-started/hello_world . + +Windows 操作系统 +~~~~~~~~~~~~~~~~~~ + +.. code-block:: batch + + cd %userprofile%\esp + xcopy /e /i %IDF_PATH%\examples\get-started\hello_world hello_world + +ESP-IDF 的 :idf:`examples` 目录下有一系列示例工程,都可以按照上面的方法进行创建。您可以按照上述方法复制并运行其中的任何示例,也可以直接编译示例,无需进行复制。 + +.. important:: + + ESP-IDF 编译系统不支持带有空格的路径。 + +.. _get-started-connect-legacy: + +第六步:连接设备 +================== + +现在,请将您的 ESP32 开发板连接到 PC,并查看开发板使用的串口。 + +通常,串口在不同操作系统下显示的名称有所不同: + +- **Windows 操作系统:** ``COM1`` 等 +- **Linux 操作系统:** 以 ``/dev/tty`` 开始 +- **MacOS 操作系统:** 以 ``/dev/cu.`` 开始 + +有关如何查看串口名称的详细信息,请见 :doc:`establish-serial-connection`。 + +.. note:: + + 请记住串口名,您会在下面的步骤中用到。 + + +.. _get-started-configure-legacy: + +第七步:配置 +============= + +请进入 :ref:`get-started-start-project-legacy` 中提到的 ``hello_world`` 目录,并运行工程配置工具 ``menuconfig``。 + +Linux 和 MacOS 操作系统 +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: bash + + cd ~/esp/hello_world + make menuconfig + +Windows 操作系统 +~~~~~~~~~~~~~~~~~~~ + +.. code-block:: batch + + cd %userprofile%\esp\hello_world + make menuconfig + +如果之前的步骤都正确,则会显示下面的菜单: + +.. figure:: ../../_static/project-configuration.png + :align: center + :alt: 工程配置 — 主窗口 + :figclass: align-center + + 工程配置 — 主窗口 + +进入菜单后,选择 ``Serial flasher config`` > ``Default serial port`` 配置串口(设备将通过该串口加载工程)。按回车键确认选择,点击 ``< Save >`` 保存配置,然后点击 ``< Exit >`` 退出 ``menuconfig``。 + +``menuconfig`` 工具的常见操作见下。 + +* ``上下箭头``:移动 +* ``回车``:进入子菜单 +* ``ESC 键``:返回上级菜单或退出 +* ``英文问号``:调出帮助菜单(退出帮助菜单,请按回车键)。 +* ``空格``、``Y 键``或``N 键``:使能/禁用 ``[*]`` 配置选项 +* ``英文问号`` :调出有关高亮选项的帮助菜单 +* ``/ 键``:寻找配置项目 + +.. note:: + + 如果您是 **Arch Linux** 用户,请前往 ``SDK tool configuration``,并将 ``Python 2 interpreter`` 的名称从 ``python`` 替换为 ``python2``。 + +.. attention:: + + 如果您使用的是 ESP32-DevKitC(板载 ESP32-SOLO-1 模组),请在烧写示例程序前,前往 ``menuconfig`` 中使能单核模式(:ref:`CONFIG_FREERTOS_UNICORE`)。 + +.. _get-started-build-and-flash-legacy: + +第八步:编译和烧录 +==================== + +请使用以下命令,编译烧录工程: :: + + make flash + +运行以上命令可以编译应用程序和所有 ESP-IDF 组件,接着生成 bootloader、分区表和应用程序二进制文件。接着,这些二进制文件将被烧录至 ESP32 开发板。 + +如果一切顺利,您可在烧录完成后看到类似下方的打印信息(代表加载进程)。接着,开发板将会复位,应用程序 "hello_world" 开始启动。 + +.. highlight:: none + +:: + + esptool.py v2.0-beta2 + Flashing binaries to serial port /dev/ttyUSB0 (app at offset 0x10000)... + esptool.py v2.0-beta2 + Connecting........___ + Uploading stub... + Running stub... + Stub running... + Changing baud rate to 921600 + Changed. + Attaching SPI flash... + Configuring flash size... + Auto-detected Flash size:4MB + Flash params set to 0x0220 + Compressed 11616 bytes to 6695... + Wrote 11616 bytes (6695 compressed) at 0x00001000 in 0.1 seconds (effective 920.5 kbit/s)... + Hash of data verified. + Compressed 408096 bytes to 171625... + Wrote 408096 bytes (171625 compressed) at 0x00010000 in 3.9 seconds (effective 847.3 kbit/s)... + Hash of data verified. + Compressed 3072 bytes to 82... + Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 8297.4 kbit/s)... + Hash of data verified. + + Leaving... + Hard resetting... + + +如果您希望使用 Eclipse IDE,而非 ``make`` 编译系统,请参考 :doc:`Eclipse 指南 `。 + + +.. _get-started-monitor-legacy: + +第九步:监视器 +=============== + +您可以使用 ``make monitor`` 命令,监视 “hello_world” 的运行情况。 + +运行该命令后,:doc:`IDF 监视器 <../api-guides/tools/idf-monitor>` 应用程序将启动: :: + + $ make monitor + MONITOR + --- idf_monitor on /dev/ttyUSB0 115200 --- + --- Quit:Ctrl+] | Menu:Ctrl+T | Help:Ctrl+T followed by Ctrl+H --- + ets Jun 8 2016 00:22:57 + + rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + ets Jun 8 2016 00:22:57 + ... + +此时,您就可以在启动日志和诊断日志之后,看到打印的 “Hello world!” 了。 + +.. code-block:: none + + ... + Hello world! + Restarting in 10 seconds... + I (211) cpu_start:Starting scheduler on APP CPU. + Restarting in 9 seconds... + Restarting in 8 seconds... + Restarting in 7 seconds... + +您可使用快捷键 ``Ctrl+]``,退出 IDF 监视器。 + +如果 IDF 监视器在烧录后很快发生错误,或打印信息全是乱码(见下),很有可能是因为您的开发板选用了 26 MHz 晶振,而 ESP-IDF 默认支持大多数开发板使用的 40 MHz 晶振。 + +.. figure:: ../../_static/get-started-garbled-output.png + :align: center + :alt: 乱码输出 + :figclass: align-center + +此时,请您: + +1. 退出监视器。 +2. 打开 :ref:`menuconfig `, +3. 进入 ``Component config`` --> ``ESP32-specific`` --> ``Main XTAL frequency`` 进行配置,将 :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` 设置为 26 MHz。 +4. 然后,请重新 :ref:`编译和烧录 ` 应用程序。 + +.. note:: + + 您也可以运行以下命令,一次性执行构建、烧录和监视过程: :: + + make flash monitor + +此外,请前往 :doc:`IDF 监视器 <../api-guides/tools/idf-monitor>`,了解更多使用 IDF 监视器的快捷键和其他详情。 + +**恭喜,您已完成 ESP32 的入门学习!** + +现在,您可以尝试一些其他 :idf:`examples`,或者直接开发自己的应用程序。 + + +环境变量 +========= + +用户可以在使用 ``make`` 命令时 **直接设置** 部分环境变量,而无需进入 ``make menuconfig`` 进行重新配置。这些变量包括: + ++-----------------+-----------------------------------------------------------------------+ +| 变量 | 描述与使用方式 | ++-----------------+-----------------------------------------------------------------------+ +| ``ESPPORT`` | 覆盖 ``flash`` 和 ``monitor`` 命令使用的串口。 | ++ +-----------------------------------------------------------------------+ +| | 例:``make flash ESPPORT=/dev/ttyUSB1``, ``make monitor ESPPORT=COM1``| ++-----------------+-----------------------------------------------------------------------+ +| ``ESPBAUD`` | 覆盖烧录 ESP32 时使用的串口速率。 | ++ +-----------------------------------------------------------------------+ +| | 例:``make flash ESPBAUD=9600`` | ++-----------------+-----------------------------------------------------------------------+ +| ``MONITORBAUD`` | 覆盖监控时使用的串口速率。 | ++ +-----------------------------------------------------------------------+ +| | 例:``make monitor MONITORBAUD=9600`` | ++-----------------+-----------------------------------------------------------------------+ + +.. note:: + + 您可导出环境变量(例:``export ESPPORT=/dev/ttyUSB1``)。 + 在同一会话窗口中,如果未被同步覆盖,所有 ``make`` 命令均会使用导出的环境变量值。 + + +更新 ESP-IDF +============= + +乐鑫会不时推出更新版本的 ESP-IDF,修复 bug 或提出新的特性。因此,在使用时,您也应注意更新您本地的版本。最简单的方法是:直接删除您本地的 ``esp-idf`` 文件夹,然后按照 :ref:`get-started-get-esp-idf-legacy` 中的指示,重新完成克隆。 + +如果您希望将 ESP-IDF 克隆到新的路径下,请务必 :doc:`重新设置 IDF_PATH `。否则,工具链将无法找到 ESP-IDF。 + +此外,您可以仅更新变更部分。具体方式,请前往 :ref:`更新 ` 章节查看。 + +相关文档 +========= + +.. toctree:: + :maxdepth: 1 + + add-idf_path-to-profile + establish-serial-connection + make-project + eclipse-setup + ../api-guides/tools/idf-monitor + toolchain-setup-scratch + +.. _Stable version: https://docs.espressif.com/projects/esp-idf/zh_CN/stable/ +.. _Releases page: https://github.com/espressif/esp-idf/releases diff --git a/docs/zh_CN/get-started/index.rst b/docs/zh_CN/get-started/index.rst index 1baf28fcbb..9f0a9ee900 100644 --- a/docs/zh_CN/get-started/index.rst +++ b/docs/zh_CN/get-started/index.rst @@ -1,493 +1,493 @@ -******************* -快速入门(CMake) -******************* - -:link_to_translation:`en:[English]` - -本文档旨在指导用户搭建 ESP32 硬件开发的软件环境, - -通过一个简单的示例展示如何使用 ESP-IDF (Espressif IoT Development Framework) 配置菜单,并编译、下载固件至 ESP32 开发板等步骤。 - -.. include:: /_build/inc/version-note.inc - -概述 -==== - -ESP32 SoC 芯片支持以下功能: - -* 2.4 GHz Wi-Fi -* 蓝牙 4.2 标准 -* 高性能双核 -* 超低功耗协处理器 -* 多种外设 - -ESP32 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、稳定性、通用性和可靠性,适用于各种应用场景和不同功耗需求。 - -乐鑫为用户提供完整的软、硬件资源,进行 ESP32 硬件设备的开发。其中,乐鑫的软件开发环境 ESP-IDF 旨在协助用户快速开发物联网 (IoT) 应用,可满足用户对 Wi-Fi、蓝牙、低功耗等方面的要求。 - -准备工作 -======== - -硬件: - -* 一款 **ESP32** 开发板 -* **USB 数据线** (USB A/Micro USB B) -* PC(Windows、Linux 或 Mac OS) - -软件: - -* 设置 **工具链**,用于编译 ESP32 代码; -* **编译工具** —— CMake 和 Ninja 编译工具,用于编译 ESP32 **应用程序**; -* 获取 **ESP-IDF** 软件开发框架。该框架已经基本包含 ESP32 使用的 API(软件库和源代码)和运行 **工具链** 的脚本; -* 安装 C 语言编程(**工程**)的 **文本编辑器**,例如 `Eclipse `_。 - - -.. figure:: ../../_static/what-you-need.png - :align: center - :alt: ESP32 应用程序开发 - :figclass: align-center - - ESP32 应用程序开发 - - -开发板简介 -========== - -请点击下方连接,了解有关具体开发板的详细信息。 - -.. toctree:: - :maxdepth: 1 - - ESP32-DevKitC <../hw-reference/get-started-devkitc> - ESP-WROVER-KIT <../hw-reference/get-started-wrover-kit> - ESP32-PICO-KIT <../hw-reference/get-started-pico-kit> - ESP32-Ethernet-Kit <../hw-reference/get-started-ethernet-kit> - - -.. _get-started-step-by-step: - -详细安装步骤 -============== - -请根据下方详细步骤,完成安装过程。 - -设置开发环境 -~~~~~~~~~~~~~~~~ - -* :ref:`get-started-setup-toolchain` -* :ref:`get-started-get-esp-idf` -* :ref:`get-started-setup-path` -* :ref:`get-started-get-packages` - -创建您的第一个工程 -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* :ref:`get-started-start-project` -* :ref:`get-started-connect` -* :ref:`get-started-configure` -* :ref:`get-started-build` -* :ref:`get-started-flash` -* :ref:`get-started-build-monitor` - - -.. _get-started-setup-toolchain: - -第一步:设置工具链 -==================== - -工具链指一套用于编译代码和应用程序的程序。 - -为了加快开发进度,您可以直接使用乐鑫提供的预制工具链。请根据您的操作系统,点击下方对应的链接,并按照链接中的指导进行安装。 - -.. toctree:: - :hidden: - - Windows - Linux - MacOS - -+-------------------+-------------------+-------------------+ -| |windows-logo| | |linux-logo| | |macos-logo| | -+-------------------+-------------------+-------------------+ -| `Windows`_ | `Linux`_ | `Mac OS`_ | -+-------------------+-------------------+-------------------+ - -.. |windows-logo| image:: ../../_static/windows-logo.png - :target: ../get-started/windows-setup.html - -.. |linux-logo| image:: ../../_static/linux-logo.png - :target: ../get-started/linux-setup.html - -.. |macos-logo| image:: ../../_static/macos-logo.png - :target: ../get-started/macos-setup.html - -.. _Windows: ../get-started/windows-setup.html -.. _Linux: ../get-started/linux-setup.html -.. _Mac OS: ../get-started/macos-setup.html - -.. note:: - - 在本文档中,Linux 和 MacOS 操作系统中 ESP-IDF 的默认安装路径为 ``~/esp``;Windows 操作系统的默认路径为 ``%userprofile%\esp``。您也可以将 ESP-IDF 安装在任何其他路径下,但请注意在使用命令行时进行相应替换。注意,ESP-IDF 不支持带有空格的路径。 - -此外, 您也可以根据自身经验和实际需求,对环境进行个性化设置,而非使用预制工具链。此时,请前往 :ref:`工具链的个性化设置` 章节获取更多信息。 - - -.. _get-started-get-esp-idf: - -第二步:获取 ESP-IDF -=========================== - -除了工具链,您还需要供 ESP32 使用的 API(软件库和源代码),具体请见 `ESP-IDF 仓库 `_。 - -请将 ESP-IDF 下载到您的本地。 - -获取本地副本:打开终端,切换到你要存放 ESP-IDF 的工作目录,使用 ``git clone`` 命令克隆远程仓库。 - -Linux 和 MacOS 操作系统 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -打开终端,后运行以下命令: - -.. include:: /_build/inc/git-clone-bash.inc - -ESP-IDF 将下载至 ``~/esp/esp-idf``。 - -请前往 :doc:`/versions`,查看 ESP-IDF 不同版本的具体适用场景。 - -Windows 操作系统 -~~~~~~~~~~~~~~~~~~ - -.. note:: - - 较早版本 ESP-IDF 使用了 **MSYS2 bash 终端** 命令行。目前,基于 CMake 的编译系统可使用常见的 **Windows 命令窗口**,即本指南中使用的终端。 - -请注意,如果您使用基于 bash 的终端或 PowerShell 终端,一些命令语法将与下面描述有所不同。 - -打开命令提示符,后运行以下命令: - -.. include:: /_build/inc/git-clone-windows.inc - -ESP-IDF 将下载至 ``%userprofile%\esp\esp-idf``。 - -请前往 :doc:`/versions`,查看 ESP-IDF 不同版本的具体适用场景。 - -.. include:: /_build/inc/git-clone-notes.inc - -.. note:: - - 在克隆远程仓库时,不要忘记加上 ``--recursive`` 选项。否则,请接着运行以下命令,获取所有子模块: :: - - cd esp-idf - git submodule update --init - -.. _get-started-setup-path: - -第三步:设置环境变量 -=========================== - -请在您的 PC 上设置以下环境变量,否则无法编译工程。 - -- ``IDF_PATH`` 应设置为 ESP-IDF 根目录的路径。 -- ``PATH`` 应包括同一 ``IDF_PATH`` 目录下的 ``tools`` 目录路径。 - -您可以在每次重启会话时手动设置,也可以在用户配置中进行永久设置,具体请前往 :doc:`add-idf_path-to-profile` 章节,查看 :ref:`Windows ` 、:ref:`Linux 及 MacOS ` 操作系统的具体设置方式。 - - -.. _get-started-get-packages: - -第四步:安装 Python 软件包 -================================= - -ESP-IDF 所需的 Python 软件包位于 ``IDF_PATH/requirements.txt`` 中。您可以运行以下命令进行安装: :: - - python -m pip install --user -r $IDF_PATH/requirements.txt - -.. note:: - - 请注意查询您所使用的 Python 解释器的版本(运行命令 ``python --version``),并根据查询结果将上方命令中的 ``python`` 替换为 ``python2``, ``python2.7``,例如: - - ``python2.7 -m pip install --user -r $IDF_PATH/requirements.txt`` - -.. _get-started-start-project: - -第五步:开始创建工程 -======================= - -现在,您可以开始准备开发 ESP32 应用程序了。您可以从 ESP-IDF 中 :idf:`examples` 目录下的 :example:`get-started/hello_world` 工程开始。 - -将 :example:`get-started/hello_world` 复制至您本地的 ``~/esp`` 目录下: - -Linux 和 MacOS 操作系统 -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: bash - - cd ~/esp - cp -r $IDF_PATH/examples/get-started/hello_world . - -Windows 操作系统 -~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: batch - - cd %userprofile%\esp - xcopy /e /i %IDF_PATH%\examples\get-started\hello_world hello_world - -ESP-IDF 的 :idf:`examples` 目录下有一系列示例工程,都可以按照上面的方法进行创建。您可以按照上述方法复制并运行其中的任何示例,也可以直接编译示例,无需进行复制。 - -.. important:: - - ESP-IDF 编译系统不支持带有空格的路径。 - -.. _get-started-connect: - -第六步:连接设备 -====================== - -现在,请将您的 ESP32 开发板连接到 PC,并查看开发板使用的串口。 - -通常,串口在不同操作系统下显示的名称有所不同: - -- **Windows 操作系统:** ``COM1`` 等 -- **Linux 操作系统:** 以 ``/dev/tty`` 开始 -- **MacOS 操作系统:** 以 ``/dev/cu.`` 开始 - -有关如何查看串口名称的详细信息,请见 :doc:`establish-serial-connection`。 - -.. note:: - - 请记住串口名,您会在下面的步骤中用到。 - - -.. _get-started-configure: - -第七步:配置 -================= - -请进入 :ref:`get-started-start-project` 中提到的 ``hello_world`` 目录,并运行工程配置工具 ``menuconfig``。 - -Linux 和 MacOS 操作系统 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: bash - - cd ~/esp/hello_world - idf.py menuconfig - -如果您的默认 Python 版本为 3.0 以上,可能需要运行 ``python2 idf.py`` 。 - -Windows 操作系统 -~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: batch - - cd %userprofile%\esp\hello_world - idf.py menuconfig - -Python 2.7 安装程序将尝试配置 Windows,将 ``.py`` 文件与 Python 2 关联起来。如果其他程序(比如 Visual Studio Python 工具)曾关联了其他版本 Python,则 ``idf.py`` 可能无法正常运行(文件将在 Visual Studio 中打开)。这种情况下,您可以选择每次都运行一遍 ``C:\Python27\python idf.py``,或更改 Windows 的 ``.py`` 关联文件设置。 - -.. note:: - - 如果出现 ``idf.py not found(无法找到 idf.py)`` 错误,请确保 ``PATH`` 环境变量设置无误,具体请参考 :ref:`get-started-setup-path`。如果 ``tools`` 目录下没有 ``idf.py`` 文件,请确保 CMake 预览的分支正确无误,具体请参考 :ref:`get-started-get-esp-idf`。 - -如果之前的步骤都正确,则会显示下面的菜单: - -.. figure:: ../../_static/project-configuration.png - :align: center - :alt: 工程配置 — 主窗口 - :figclass: align-center - - 工程配置 — 主窗口 - -``menuconfig`` 工具的常见操作见下。 - -* ``上下箭头``:移动 -* ``回车``:进入子菜单 -* ``ESC 键``:返回上级菜单或退出 -* ``英文问号``:调出帮助菜单(退出帮助菜单,请按回车键)。 -* ``空格``、``Y 键``或``N 键``:使能/禁用 ``[*]`` 配置选项 -* ``英文问号``:调出有关高亮选项的帮助菜单 -* ``/ 键``:寻找配置项目 - -.. attention:: - - 如果您使用的是 ESP32-DevKitC(板载 ESP32-SOLO-1 模组),请在烧写示例程序前,前往 ``menuconfig`` 中使能单核模式(:ref:`CONFIG_FREERTOS_UNICORE`)。 - -.. _get-started-build: - -第八步:编译工程 -================== - -请使用以下命令,编译烧录工程::: - - idf.py build - -运行以上命令可以编译应用程序和所有 ESP-IDF 组件,接着生成 bootloader、分区表和应用程序二进制文件。 - -.. code-block:: none - - $ idf.py build - Running cmake in directory /path/to/hello_world/build - Executing "cmake -G Ninja --warn-uninitialized /path/to/hello_world"... - Warn about uninitialized values. - -- Found Git: /usr/bin/git (found version "2.17.0") - -- Building empty aws_iot component due to configuration - -- Component names: ... - -- Component paths: ... - - ... (more lines of build system output) - - [527/527] Generating hello-world.bin - esptool.py v2.3.1 - - Project build complete. To flash, run this command: - ../../../components/esptool_py/esptool/esptool.py -p (PORT) -b 921600 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x10000 build/hello-world.bin build 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin - or run 'idf.py -p PORT flash' - -如果一切正常,编译完成后将生成 .bin 文件。 - - -.. _get-started-flash: - -第九步:烧录到设备 -==================== - -请使用以下命令,将刚刚生成的二进制文件烧录至您的 ESP32 开发板: :: - - idf.py -p PORT [-b BAUD] flash - -请将 PORT 替换为 ESP32 开发板的串口名称,具体可见 :ref:`get-started-connect`。 - -您还可以将 BAUD 替换为您希望的烧录波特率。默认波特率为 ``460800``。 - -更多有关 idf.py 参数的详情,请见 :ref:`idf.py`。 - -.. note:: - - 勾选 ``flash`` 选项将自动编译并烧录工程,因此无需再运行 ``idf.py build``。 - -.. code-block:: none - - Running esptool.py in directory [...]/esp/hello_world - Executing "python [...]/esp-idf/components/esptool_py/esptool/esptool.py -b 460800 write_flash @flash_project_args"... - esptool.py -b 460800 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x1000 bootloader/bootloader.bin 0x8000 partition_table/partition-table.bin 0x10000 hello-world.bin - esptool.py v2.3.1 - Connecting.... - Detecting chip type... ESP32 - Chip is ESP32D0WDQ6 (revision 1) - Features: WiFi, BT, Dual Core - Uploading stub... - Running stub... - Stub running... - Changing baud rate to 460800 - Changed. - Configuring flash size... - Auto-detected Flash size: 4MB - Flash params set to 0x0220 - Compressed 22992 bytes to 13019... - Wrote 22992 bytes (13019 compressed) at 0x00001000 in 0.3 seconds (effective 558.9 kbit/s)... - Hash of data verified. - Compressed 3072 bytes to 82... - Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 5789.3 kbit/s)... - Hash of data verified. - Compressed 136672 bytes to 67544... - Wrote 136672 bytes (67544 compressed) at 0x00010000 in 1.9 seconds (effective 567.5 kbit/s)... - Hash of data verified. - - Leaving... - Hard resetting via RTS pin... - -如果一切顺利,烧录完成后,开发板将会复位,应用程序 "hello_world" 开始运行。 - -.. note:: - - (目前不支持)如果您希望使用 Eclipse IDE,而非 ``idf.py``,请参考 :doc:`Eclipse 指南 `。 - - -.. _get-started-build-monitor: - -第十步:监视器 -================== - -您可以使用 ``make monitor`` 命令,监视 “hello_world” 的运行情况。注意,不要忘记将 PORT 替换为您的串口名称。 - -运行该命令后,:doc:`IDF 监视器 <../api-guides/tools/idf-monitor>` 应用程序将启动: :: - - $ idf.py -p /dev/ttyUSB0 monitor - Running idf_monitor in directory [...]/esp/hello_world/build - Executing "python [...]/esp-idf/tools/idf_monitor.py -b 115200 [...]/esp/hello_world/build/hello-world.elf"... - --- idf_monitor on /dev/ttyUSB0 115200 --- - --- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- - ets Jun 8 2016 00:22:57 - - rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) - ets Jun 8 2016 00:22:57 - ... - -此时,您就可以在启动日志和诊断日志之后,看到打印的 “Hello world!” 了。 - -.. code-block:: none - - ... - Hello world! - Restarting in 10 seconds... - I (211) cpu_start: Starting scheduler on APP CPU. - Restarting in 9 seconds... - Restarting in 8 seconds... - Restarting in 7 seconds... - -您可使用快捷键 ``Ctrl+]``,退出 IDF 监视器。 - -如果 IDF 监视器在烧录后很快发生错误,或打印信息全是乱码(见下),很有可能是因为您的开发板选用了 26 MHz 晶振,而 ESP-IDF 默认支持大多数开发板使用的 40 MHz 晶振。 - -.. code-block:: none - - e���)(Xn@�y.!��(�PW+)��Hn9a؅/9�!�t5��P�~�k��e�ea�5�jA - ~zY��Y(1�,1�� e���)(Xn@�y.!Dr�zY(�jpi�|�+z5Ymvp - -此时,请您: - -1. 退出监视器。 -2. 打开 :ref:`menuconfig `, -3. 进入 ``Component config`` --> ``ESP32-specific`` --> ``Main XTAL frequency`` 进行配置,将 :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` 设置为 26 MHz。 -4. 然后,请重新 :ref:`编译和烧录 ` 应用程序。 - -.. note:: - - 您也可以运行以下命令,一次性执行构建、烧录和监视过程: - - ``idf.py -p PORT flash monitor`` - -此外, - -- 请前往 :doc:`IDF 监视器 <../api-guides/tools/idf-monitor>`,了解更多使用 IDF 监视器的快捷键和其他详情。 -- 请前往 :ref:`idf.py`,查看更多 ``idf.py`` 命令和选项。 - -**恭喜,您已完成 ESP32 的入门学习!** - -现在,您可以尝试一些其他 :idf:`examples`,或者直接开发自己的应用程序。 - -更新 ESP-IDF -================= - -乐鑫会不时推出更新版本的 ESP-IDF,修复 bug 或提出新的特性。因此,您在使用时,也应注意更新您本地的版本。最简单的方法是:直接删除您本地的 ``esp-idf`` 文件夹,然后按照 :ref:`get-started-get-esp-idf` 中的指示,重新完成克隆。 - -如果您希望将 ESP-IDF 克隆到新的路径下,请务必 :doc:`重新设置 IDF_PATH `。否则,工具链将无法找到 ESP-IDF。 - -此外,您可以仅更新变更部分。具体方式,请前往 :ref:`更新 ` 章节查看。 - -相关文档 -=========== - -.. toctree:: - :maxdepth: 1 - - add-idf_path-to-profile - establish-serial-connection - eclipse-setup - ../api-guides/tools/idf-monitor - toolchain-setup-scratch - ../get-started-legacy/index - -.. _Stable version: https://docs.espressif.com/projects/esp-idf/zh_CN/stable/ -.. _Releases page: https://github.com/espressif/esp-idf/releases +******************* +快速入门(CMake) +******************* + +:link_to_translation:`en:[English]` + +本文档旨在指导用户搭建 ESP32 硬件开发的软件环境, + +通过一个简单的示例展示如何使用 ESP-IDF (Espressif IoT Development Framework) 配置菜单,并编译、下载固件至 ESP32 开发板等步骤。 + +.. include:: /_build/inc/version-note.inc + +概述 +==== + +ESP32 SoC 芯片支持以下功能: + +* 2.4 GHz Wi-Fi +* 蓝牙 4.2 标准 +* 高性能双核 +* 超低功耗协处理器 +* 多种外设 + +ESP32 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、稳定性、通用性和可靠性,适用于各种应用场景和不同功耗需求。 + +乐鑫为用户提供完整的软、硬件资源,进行 ESP32 硬件设备的开发。其中,乐鑫的软件开发环境 ESP-IDF 旨在协助用户快速开发物联网 (IoT) 应用,可满足用户对 Wi-Fi、蓝牙、低功耗等方面的要求。 + +准备工作 +======== + +硬件: + +* 一款 **ESP32** 开发板 +* **USB 数据线** (USB A/Micro USB B) +* PC(Windows、Linux 或 Mac OS) + +软件: + +* 设置 **工具链**,用于编译 ESP32 代码; +* **编译工具** —— CMake 和 Ninja 编译工具,用于编译 ESP32 **应用程序**; +* 获取 **ESP-IDF** 软件开发框架。该框架已经基本包含 ESP32 使用的 API(软件库和源代码)和运行 **工具链** 的脚本; +* 安装 C 语言编程(**工程**)的 **文本编辑器**,例如 `Eclipse `_。 + + +.. figure:: ../../_static/what-you-need.png + :align: center + :alt: ESP32 应用程序开发 + :figclass: align-center + + ESP32 应用程序开发 + + +开发板简介 +========== + +请点击下方连接,了解有关具体开发板的详细信息。 + +.. toctree:: + :maxdepth: 1 + + ESP32-DevKitC <../hw-reference/get-started-devkitc> + ESP-WROVER-KIT <../hw-reference/get-started-wrover-kit> + ESP32-PICO-KIT <../hw-reference/get-started-pico-kit> + ESP32-Ethernet-Kit <../hw-reference/get-started-ethernet-kit> + + +.. _get-started-step-by-step: + +详细安装步骤 +============== + +请根据下方详细步骤,完成安装过程。 + +设置开发环境 +~~~~~~~~~~~~~~~~ + +* :ref:`get-started-setup-toolchain` +* :ref:`get-started-get-esp-idf` +* :ref:`get-started-setup-path` +* :ref:`get-started-get-packages` + +创建您的第一个工程 +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* :ref:`get-started-start-project` +* :ref:`get-started-connect` +* :ref:`get-started-configure` +* :ref:`get-started-build` +* :ref:`get-started-flash` +* :ref:`get-started-build-monitor` + + +.. _get-started-setup-toolchain: + +第一步:设置工具链 +==================== + +工具链指一套用于编译代码和应用程序的程序。 + +为了加快开发进度,您可以直接使用乐鑫提供的预制工具链。请根据您的操作系统,点击下方对应的链接,并按照链接中的指导进行安装。 + +.. toctree:: + :hidden: + + Windows + Linux + MacOS + ++-------------------+-------------------+-------------------+ +| |windows-logo| | |linux-logo| | |macos-logo| | ++-------------------+-------------------+-------------------+ +| `Windows`_ | `Linux`_ | `Mac OS`_ | ++-------------------+-------------------+-------------------+ + +.. |windows-logo| image:: ../../_static/windows-logo.png + :target: ../get-started/windows-setup.html + +.. |linux-logo| image:: ../../_static/linux-logo.png + :target: ../get-started/linux-setup.html + +.. |macos-logo| image:: ../../_static/macos-logo.png + :target: ../get-started/macos-setup.html + +.. _Windows: ../get-started/windows-setup.html +.. _Linux: ../get-started/linux-setup.html +.. _Mac OS: ../get-started/macos-setup.html + +.. note:: + + 在本文档中,Linux 和 MacOS 操作系统中 ESP-IDF 的默认安装路径为 ``~/esp``;Windows 操作系统的默认路径为 ``%userprofile%\esp``。您也可以将 ESP-IDF 安装在任何其他路径下,但请注意在使用命令行时进行相应替换。注意,ESP-IDF 不支持带有空格的路径。 + +此外, 您也可以根据自身经验和实际需求,对环境进行个性化设置,而非使用预制工具链。此时,请前往 :ref:`工具链的个性化设置` 章节获取更多信息。 + + +.. _get-started-get-esp-idf: + +第二步:获取 ESP-IDF +=========================== + +除了工具链,您还需要供 ESP32 使用的 API(软件库和源代码),具体请见 `ESP-IDF 仓库 `_。 + +请将 ESP-IDF 下载到您的本地。 + +获取本地副本:打开终端,切换到你要存放 ESP-IDF 的工作目录,使用 ``git clone`` 命令克隆远程仓库。 + +Linux 和 MacOS 操作系统 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +打开终端,后运行以下命令: + +.. include:: /_build/inc/git-clone-bash.inc + +ESP-IDF 将下载至 ``~/esp/esp-idf``。 + +请前往 :doc:`/versions`,查看 ESP-IDF 不同版本的具体适用场景。 + +Windows 操作系统 +~~~~~~~~~~~~~~~~~~ + +.. note:: + + 较早版本 ESP-IDF 使用了 **MSYS2 bash 终端** 命令行。目前,基于 CMake 的编译系统可使用常见的 **Windows 命令窗口**,即本指南中使用的终端。 + +请注意,如果您使用基于 bash 的终端或 PowerShell 终端,一些命令语法将与下面描述有所不同。 + +打开命令提示符,后运行以下命令: + +.. include:: /_build/inc/git-clone-windows.inc + +ESP-IDF 将下载至 ``%userprofile%\esp\esp-idf``。 + +请前往 :doc:`/versions`,查看 ESP-IDF 不同版本的具体适用场景。 + +.. include:: /_build/inc/git-clone-notes.inc + +.. note:: + + 在克隆远程仓库时,不要忘记加上 ``--recursive`` 选项。否则,请接着运行以下命令,获取所有子模块: :: + + cd esp-idf + git submodule update --init + +.. _get-started-setup-path: + +第三步:设置环境变量 +=========================== + +请在您的 PC 上设置以下环境变量,否则无法编译工程。 + +- ``IDF_PATH`` 应设置为 ESP-IDF 根目录的路径。 +- ``PATH`` 应包括同一 ``IDF_PATH`` 目录下的 ``tools`` 目录路径。 + +您可以在每次重启会话时手动设置,也可以在用户配置中进行永久设置,具体请前往 :doc:`add-idf_path-to-profile` 章节,查看 :ref:`Windows ` 、:ref:`Linux 及 MacOS ` 操作系统的具体设置方式。 + + +.. _get-started-get-packages: + +第四步:安装 Python 软件包 +================================= + +ESP-IDF 所需的 Python 软件包位于 ``IDF_PATH/requirements.txt`` 中。您可以运行以下命令进行安装: :: + + python -m pip install --user -r $IDF_PATH/requirements.txt + +.. note:: + + 请注意查询您所使用的 Python 解释器的版本(运行命令 ``python --version``),并根据查询结果将上方命令中的 ``python`` 替换为 ``python2``, ``python2.7``,例如: + + ``python2.7 -m pip install --user -r $IDF_PATH/requirements.txt`` + +.. _get-started-start-project: + +第五步:开始创建工程 +======================= + +现在,您可以开始准备开发 ESP32 应用程序了。您可以从 ESP-IDF 中 :idf:`examples` 目录下的 :example:`get-started/hello_world` 工程开始。 + +将 :example:`get-started/hello_world` 复制至您本地的 ``~/esp`` 目录下: + +Linux 和 MacOS 操作系统 +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: bash + + cd ~/esp + cp -r $IDF_PATH/examples/get-started/hello_world . + +Windows 操作系统 +~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: batch + + cd %userprofile%\esp + xcopy /e /i %IDF_PATH%\examples\get-started\hello_world hello_world + +ESP-IDF 的 :idf:`examples` 目录下有一系列示例工程,都可以按照上面的方法进行创建。您可以按照上述方法复制并运行其中的任何示例,也可以直接编译示例,无需进行复制。 + +.. important:: + + ESP-IDF 编译系统不支持带有空格的路径。 + +.. _get-started-connect: + +第六步:连接设备 +====================== + +现在,请将您的 ESP32 开发板连接到 PC,并查看开发板使用的串口。 + +通常,串口在不同操作系统下显示的名称有所不同: + +- **Windows 操作系统:** ``COM1`` 等 +- **Linux 操作系统:** 以 ``/dev/tty`` 开始 +- **MacOS 操作系统:** 以 ``/dev/cu.`` 开始 + +有关如何查看串口名称的详细信息,请见 :doc:`establish-serial-connection`。 + +.. note:: + + 请记住串口名,您会在下面的步骤中用到。 + + +.. _get-started-configure: + +第七步:配置 +================= + +请进入 :ref:`get-started-start-project` 中提到的 ``hello_world`` 目录,并运行工程配置工具 ``menuconfig``。 + +Linux 和 MacOS 操作系统 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: bash + + cd ~/esp/hello_world + idf.py menuconfig + +如果您的默认 Python 版本为 3.0 以上,可能需要运行 ``python2 idf.py`` 。 + +Windows 操作系统 +~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: batch + + cd %userprofile%\esp\hello_world + idf.py menuconfig + +Python 2.7 安装程序将尝试配置 Windows,将 ``.py`` 文件与 Python 2 关联起来。如果其他程序(比如 Visual Studio Python 工具)曾关联了其他版本 Python,则 ``idf.py`` 可能无法正常运行(文件将在 Visual Studio 中打开)。这种情况下,您可以选择每次都运行一遍 ``C:\Python27\python idf.py``,或更改 Windows 的 ``.py`` 关联文件设置。 + +.. note:: + + 如果出现 ``idf.py not found(无法找到 idf.py)`` 错误,请确保 ``PATH`` 环境变量设置无误,具体请参考 :ref:`get-started-setup-path`。如果 ``tools`` 目录下没有 ``idf.py`` 文件,请确保 CMake 预览的分支正确无误,具体请参考 :ref:`get-started-get-esp-idf`。 + +如果之前的步骤都正确,则会显示下面的菜单: + +.. figure:: ../../_static/project-configuration.png + :align: center + :alt: 工程配置 — 主窗口 + :figclass: align-center + + 工程配置 — 主窗口 + +``menuconfig`` 工具的常见操作见下。 + +* ``上下箭头``:移动 +* ``回车``:进入子菜单 +* ``ESC 键``:返回上级菜单或退出 +* ``英文问号``:调出帮助菜单(退出帮助菜单,请按回车键)。 +* ``空格``、``Y 键``或``N 键``:使能/禁用 ``[*]`` 配置选项 +* ``英文问号``:调出有关高亮选项的帮助菜单 +* ``/ 键``:寻找配置项目 + +.. attention:: + + 如果您使用的是 ESP32-DevKitC(板载 ESP32-SOLO-1 模组),请在烧写示例程序前,前往 ``menuconfig`` 中使能单核模式(:ref:`CONFIG_FREERTOS_UNICORE`)。 + +.. _get-started-build: + +第八步:编译工程 +================== + +请使用以下命令,编译烧录工程::: + + idf.py build + +运行以上命令可以编译应用程序和所有 ESP-IDF 组件,接着生成 bootloader、分区表和应用程序二进制文件。 + +.. code-block:: none + + $ idf.py build + Running cmake in directory /path/to/hello_world/build + Executing "cmake -G Ninja --warn-uninitialized /path/to/hello_world"... + Warn about uninitialized values. + -- Found Git: /usr/bin/git (found version "2.17.0") + -- Building empty aws_iot component due to configuration + -- Component names: ... + -- Component paths: ... + + ... (more lines of build system output) + + [527/527] Generating hello-world.bin + esptool.py v2.3.1 + + Project build complete. To flash, run this command: + ../../../components/esptool_py/esptool/esptool.py -p (PORT) -b 921600 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x10000 build/hello-world.bin build 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin + or run 'idf.py -p PORT flash' + +如果一切正常,编译完成后将生成 .bin 文件。 + + +.. _get-started-flash: + +第九步:烧录到设备 +==================== + +请使用以下命令,将刚刚生成的二进制文件烧录至您的 ESP32 开发板: :: + + idf.py -p PORT [-b BAUD] flash + +请将 PORT 替换为 ESP32 开发板的串口名称,具体可见 :ref:`get-started-connect`。 + +您还可以将 BAUD 替换为您希望的烧录波特率。默认波特率为 ``460800``。 + +更多有关 idf.py 参数的详情,请见 :ref:`idf.py`。 + +.. note:: + + 勾选 ``flash`` 选项将自动编译并烧录工程,因此无需再运行 ``idf.py build``。 + +.. code-block:: none + + Running esptool.py in directory [...]/esp/hello_world + Executing "python [...]/esp-idf/components/esptool_py/esptool/esptool.py -b 460800 write_flash @flash_project_args"... + esptool.py -b 460800 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x1000 bootloader/bootloader.bin 0x8000 partition_table/partition-table.bin 0x10000 hello-world.bin + esptool.py v2.3.1 + Connecting.... + Detecting chip type... ESP32 + Chip is ESP32D0WDQ6 (revision 1) + Features: WiFi, BT, Dual Core + Uploading stub... + Running stub... + Stub running... + Changing baud rate to 460800 + Changed. + Configuring flash size... + Auto-detected Flash size: 4MB + Flash params set to 0x0220 + Compressed 22992 bytes to 13019... + Wrote 22992 bytes (13019 compressed) at 0x00001000 in 0.3 seconds (effective 558.9 kbit/s)... + Hash of data verified. + Compressed 3072 bytes to 82... + Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 5789.3 kbit/s)... + Hash of data verified. + Compressed 136672 bytes to 67544... + Wrote 136672 bytes (67544 compressed) at 0x00010000 in 1.9 seconds (effective 567.5 kbit/s)... + Hash of data verified. + + Leaving... + Hard resetting via RTS pin... + +如果一切顺利,烧录完成后,开发板将会复位,应用程序 "hello_world" 开始运行。 + +.. note:: + + (目前不支持)如果您希望使用 Eclipse IDE,而非 ``idf.py``,请参考 :doc:`Eclipse 指南 `。 + + +.. _get-started-build-monitor: + +第十步:监视器 +================== + +您可以使用 ``make monitor`` 命令,监视 “hello_world” 的运行情况。注意,不要忘记将 PORT 替换为您的串口名称。 + +运行该命令后,:doc:`IDF 监视器 <../api-guides/tools/idf-monitor>` 应用程序将启动: :: + + $ idf.py -p /dev/ttyUSB0 monitor + Running idf_monitor in directory [...]/esp/hello_world/build + Executing "python [...]/esp-idf/tools/idf_monitor.py -b 115200 [...]/esp/hello_world/build/hello-world.elf"... + --- idf_monitor on /dev/ttyUSB0 115200 --- + --- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- + ets Jun 8 2016 00:22:57 + + rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + ets Jun 8 2016 00:22:57 + ... + +此时,您就可以在启动日志和诊断日志之后,看到打印的 “Hello world!” 了。 + +.. code-block:: none + + ... + Hello world! + Restarting in 10 seconds... + I (211) cpu_start: Starting scheduler on APP CPU. + Restarting in 9 seconds... + Restarting in 8 seconds... + Restarting in 7 seconds... + +您可使用快捷键 ``Ctrl+]``,退出 IDF 监视器。 + +如果 IDF 监视器在烧录后很快发生错误,或打印信息全是乱码(见下),很有可能是因为您的开发板选用了 26 MHz 晶振,而 ESP-IDF 默认支持大多数开发板使用的 40 MHz 晶振。 + +.. figure:: ../../_static/get-started-garbled-output.png + :align: center + :alt: 乱码输出 + :figclass: align-center + +此时,请您: + +1. 退出监视器。 +2. 打开 :ref:`menuconfig `, +3. 进入 ``Component config`` --> ``ESP32-specific`` --> ``Main XTAL frequency`` 进行配置,将 :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` 设置为 26 MHz。 +4. 然后,请重新 :ref:`编译和烧录 ` 应用程序。 + +.. note:: + + 您也可以运行以下命令,一次性执行构建、烧录和监视过程: + + ``idf.py -p PORT flash monitor`` + +此外, + +- 请前往 :doc:`IDF 监视器 <../api-guides/tools/idf-monitor>`,了解更多使用 IDF 监视器的快捷键和其他详情。 +- 请前往 :ref:`idf.py`,查看更多 ``idf.py`` 命令和选项。 + +**恭喜,您已完成 ESP32 的入门学习!** + +现在,您可以尝试一些其他 :idf:`examples`,或者直接开发自己的应用程序。 + +更新 ESP-IDF +================= + +乐鑫会不时推出更新版本的 ESP-IDF,修复 bug 或提出新的特性。因此,您在使用时,也应注意更新您本地的版本。最简单的方法是:直接删除您本地的 ``esp-idf`` 文件夹,然后按照 :ref:`get-started-get-esp-idf` 中的指示,重新完成克隆。 + +如果您希望将 ESP-IDF 克隆到新的路径下,请务必 :doc:`重新设置 IDF_PATH `。否则,工具链将无法找到 ESP-IDF。 + +此外,您可以仅更新变更部分。具体方式,请前往 :ref:`更新 ` 章节查看。 + +相关文档 +=========== + +.. toctree:: + :maxdepth: 1 + + add-idf_path-to-profile + establish-serial-connection + eclipse-setup + ../api-guides/tools/idf-monitor + toolchain-setup-scratch + ../get-started-legacy/index + +.. _Stable version: https://docs.espressif.com/projects/esp-idf/zh_CN/stable/ +.. _Releases page: https://github.com/espressif/esp-idf/releases diff --git a/docs/zh_CN/index.rst b/docs/zh_CN/index.rst index dfdd2da239..5cd11e5f06 100644 --- a/docs/zh_CN/index.rst +++ b/docs/zh_CN/index.rst @@ -15,24 +15,24 @@ ESP-IDF 编程指南 ================== ================== ================== -.. |快速入门| image:: ../_static/get-started.gif +.. |快速入门| image:: ../_static/get-started.png .. _快速入门: get-started/index.html -.. |API 参考| image:: ../_static/api-reference.gif +.. |API 参考| image:: ../_static/api-reference.png .. _API 参考: api-reference/index.html -.. |H/W 参考| image:: ../_static/hw-reference.gif +.. |H/W 参考| image:: ../_static/hw-reference.png .. _H/W 参考: hw-reference/index.html -.. |API 指南| image:: ../_static/api-guides.gif +.. |API 指南| image:: ../_static/api-guides.png .. _API 指南: api-guides/index.html .. _Libraries and Frameworks: libraries-and-frameworks/index.html -.. |贡献代码| image:: ../_static/contribute.gif +.. |贡献代码| image:: ../_static/contribute.png .. _贡献代码: contribute/index.html -.. |相关资源| image:: ../_static/resources.gif +.. |相关资源| image:: ../_static/resources.png .. _相关资源: resources.html From e36a76d94076aeeadb60f0e2f0c068a94db19d0e Mon Sep 17 00:00:00 2001 From: Sergei Silnov Date: Fri, 21 Jun 2019 10:45:13 +0200 Subject: [PATCH 357/486] idf_ext.py: don't rerun reconfig for tests when possible --- tools/idf.py | 2 - tools/unit-test-app/idf_ext.py | 116 +++++++++++++-------------------- 2 files changed, 45 insertions(+), 73 deletions(-) diff --git a/tools/idf.py b/tools/idf.py index 669a18898e..1083d1d026 100755 --- a/tools/idf.py +++ b/tools/idf.py @@ -180,8 +180,6 @@ def _new_cmakecache_entries(cache_path, new_cache_entries): if not os.path.exists(cache_path): return True - current_cache = parse_cmakecache(cache_path) - if new_cache_entries: current_cache = parse_cmakecache(cache_path) diff --git a/tools/unit-test-app/idf_ext.py b/tools/unit-test-app/idf_ext.py index 39973dc1c5..9fea430466 100644 --- a/tools/unit-test-app/idf_ext.py +++ b/tools/unit-test-app/idf_ext.py @@ -22,29 +22,34 @@ def action_extensions(base_actions, project_path=os.getcwd()): BUILDS_DIR = os.path.join(project_path, "builds") BINARIES_DIR = os.path.join(project_path, "output") + def parse_file_to_dict(path, regex): + """ + Parse the config file at 'path' + + Returns a dict of name:value. + """ + compiled_regex = re.compile(regex) + result = {} + with open(path) as f: + for line in f: + m = compiled_regex.match(line) + if m: + result[m.group(1)] = m.group(2) + return result + + def parse_config(path): + """ + Expected format with default regex is "key=value" + """ + + return parse_file_to_dict(path, r"^([^=]+)=(.+)$") + def ut_apply_config(ut_apply_config_name, ctx, args): config_name = re.match(r"ut-apply-config-(.*)", ut_apply_config_name).group(1) - - def set_config_build_variables(prop, defval=None): - property_value = re.findall(r"^%s=(.+)" % prop, config_file_content, re.MULTILINE) - if property_value: - property_value = property_value[0] - else: - property_value = defval - - if property_value: - try: - args.define_cache_entry.append("%s=" % prop + property_value) - except AttributeError: - args.define_cache_entry = ["%s=" % prop + property_value] - - return property_value - - sdkconfig_set = None - - if args.define_cache_entry: - sdkconfig_set = filter(lambda s: "SDKCONFIG=" in s, args.define_cache_entry) - + # Make sure that define_cache_entry is list + args.define_cache_entry = list(args.define_cache_entry) + new_cache_values = {} + sdkconfig_set = list(filter(lambda s: "SDKCONFIG=" in s, args.define_cache_entry)) sdkconfig_path = os.path.join(args.project_dir, "sdkconfig") if sdkconfig_set: @@ -58,27 +63,13 @@ def action_extensions(base_actions, project_path=os.getcwd()): if config_name in CONFIG_NAMES: # Parse the sdkconfig for components to be included/excluded and tests to be run - config = os.path.join(project_path, "configs", config_name) + config_path = os.path.join(project_path, "configs", config_name) + config = parse_config(config_path) - with open(config, "r") as config_file: - config_file_content = config_file.read() - - set_config_build_variables("EXCLUDE_COMPONENTS", "''") - - test_components = set_config_build_variables("TEST_COMPONENTS", "''") - - tests_all = None - if test_components == "''": - tests_all = "TESTS_ALL=1" - else: - tests_all = "TESTS_ALL=0" - - try: - args.define_cache_entry.append(tests_all) - except AttributeError: - args.define_cache_entry = [tests_all] - - set_config_build_variables("TEST_EXCLUDE_COMPONENTS", "''") + new_cache_values["EXCLUDE_COMPONENTS"] = config.get("EXCLUDE_COMPONENTS", "''") + new_cache_values["TEST_EXCLUDE_COMPONENTS"] = config.get("TEST_EXCLUDE_COMPONENTS", "''") + new_cache_values["TEST_COMPONENTS"] = config.get("TEST_COMPONENTS", "''") + new_cache_values["TESTS_ALL"] = int(new_cache_values["TEST_COMPONENTS"] == "''") with tempfile.NamedTemporaryFile() as sdkconfig_temp: # Use values from the combined defaults and the values from @@ -94,17 +85,12 @@ def action_extensions(base_actions, project_path=os.getcwd()): sdkconfig_temp.write(sdkconfig_config_file.read()) sdkconfig_temp.flush() + new_cache_values["SDKCONFIG_DEFAULTS"] = sdkconfig_temp.name - try: - args.define_cache_entry.append("SDKCONFIG_DEFAULTS=" + sdkconfig_temp.name) - except AttributeError: - args.define_cache_entry = ["SDKCONFIG_DEFAULTS=" + sdkconfig_temp.name] + args.define_cache_entry.extend(["%s=%s" % (k, v) for k, v in new_cache_values.items()]) reconfigure = base_actions["actions"]["reconfigure"]["callback"] reconfigure(None, ctx, args) - else: - if not config_name == "all-configs": - print("unknown unit test app config for action '%s'" % ut_apply_config_name) # This target builds the configuration. It does not currently track dependencies, # but is good enough for CI builds if used together with clean-all-configs. @@ -177,46 +163,33 @@ def action_extensions(base_actions, project_path=os.getcwd()): for binary in binaries: shutil.copyfile(os.path.join(src, binary), os.path.join(dest, binary)) - else: - if not config_name == "all-configs": - print("unknown unit test app config for action '%s'" % ut_build_name) - def ut_clean(ut_clean_name, ctx, args): config_name = re.match(r"ut-clean-(.*)", ut_clean_name).group(1) if config_name in CONFIG_NAMES: shutil.rmtree(os.path.join(BUILDS_DIR, config_name), ignore_errors=True) shutil.rmtree(os.path.join(BINARIES_DIR, config_name), ignore_errors=True) - else: - if not config_name == "all-configs": - print("unknown unit test app config for action '%s'" % ut_clean_name) def test_component_callback(ctx, global_args, tasks): """ Convert the values passed to the -T and -E parameter to corresponding cache entry definitions TESTS_ALL and TEST_COMPONENTS """ test_components = global_args.test_components test_exclude_components = global_args.test_exclude_components - cache_entries = [] + cache_entries = {} if test_components: if "all" in test_components: - cache_entries.append("TESTS_ALL=1") - cache_entries.append("TEST_COMPONENTS=''") + cache_entries["TESTS_ALL"] = 1 + cache_entries["TEST_COMPONENTS"] = "''" else: - cache_entries.append("TESTS_ALL=0") - cache_entries.append("TEST_COMPONENTS='%s'" % " ".join(test_components)) + cache_entries["TESTS_ALL"] = 0 + cache_entries["TEST_COMPONENTS"] = " ".join(test_components) if test_exclude_components: - cache_entries.append("TEST_EXCLUDE_COMPONENTS='%s'" % " ".join(test_exclude_components)) + cache_entries["TEST_EXCLUDE_COMPONENTS"] = " ".join(test_exclude_components) if cache_entries: global_args.define_cache_entry = list(global_args.define_cache_entry) - global_args.define_cache_entry.extend(cache_entries) - - # Brute force add reconfigure at the very beginning - reconfigure_task = ctx.invoke(ctx.command.get_command(ctx, "reconfigure")) - # Strip arguments from the task - reconfigure_task.action_args = {} - tasks.insert(0, reconfigure_task) + global_args.define_cache_entry.extend(["%s=%s" % (k, v) for k, v in cache_entries.items()]) # Add global options extensions = { @@ -248,8 +221,9 @@ def action_extensions(base_actions, project_path=os.getcwd()): "callback": ut_build, "help": - ("Build unit-test-app with configuration provided in configs/%s. " - "Build directory will be builds/%s/, output binaries will be under output/%s/" % (config, config, config)), + "Build unit-test-app with configuration provided in configs/NAME. " + + "Build directory will be builds/%s/, " % config_build_action_name + + "output binaries will be under output/%s/" % config_build_action_name, } extensions["actions"][config_clean_action_name] = { @@ -261,7 +235,7 @@ def action_extensions(base_actions, project_path=os.getcwd()): "callback": ut_apply_config, "help": - "Generates configuration based on configs/%s in sdkconfig file. " % config_apply_config_action_name + + "Generates configuration based on configs/%s in sdkconfig file." % config_apply_config_action_name + "After this, normal all/flash targets can be used. Useful for development/debugging.", } From 80ad09f230acae80a6a7b3dce4b89b0204ca472e Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 24 Jul 2019 06:44:30 +0200 Subject: [PATCH 358/486] tools: installer: allow changing installation path Installation path can now be changed in a subsequent install, without uninstalling and logging out. The default value of the installation path is set to IDF_TOOLS_PATH environment variable, if it was already set by the previous installation, or by the user. Closes https://github.com/espressif/esp-idf/issues/3806 --- tools/windows/tool_setup/idf_tool_setup.iss | 3 ++- tools/windows/tool_setup/main.iss.inc | 22 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/tools/windows/tool_setup/idf_tool_setup.iss b/tools/windows/tool_setup/idf_tool_setup.iss index 7fd8b2f735..13869feaec 100644 --- a/tools/windows/tool_setup/idf_tool_setup.iss +++ b/tools/windows/tool_setup/idf_tool_setup.iss @@ -35,6 +35,7 @@ AppPublisherURL={#MyAppURL} AppSupportURL={#MyAppURL} AppUpdatesURL={#MyAppURL} DefaultDirName={%USERPROFILE}\.espressif +UsePreviousAppDir=no DirExistsWarning=no DefaultGroupName=ESP-IDF DisableProgramGroupPage=yes @@ -78,7 +79,7 @@ Filename: "{group}\{#IDFCmdExeShortcutFile}"; Flags: postinstall shellexec; Desc [Registry] Root: HKCU; Subkey: "Environment"; ValueType: string; ValueName: "IDF_TOOLS_PATH"; \ - ValueData: "{app}"; Flags: preservestringtype createvalueifdoesntexist; + ValueData: "{app}"; Flags: preservestringtype createvalueifdoesntexist uninsdeletevalue deletevalue; [Code] diff --git a/tools/windows/tool_setup/main.iss.inc b/tools/windows/tool_setup/main.iss.inc index 857f448796..a023f14d6d 100644 --- a/tools/windows/tool_setup/main.iss.inc +++ b/tools/windows/tool_setup/main.iss.inc @@ -17,6 +17,23 @@ begin idpDownloadAfter(wpReady); end; +{ If IDF_TOOLS_PATH is set in the environment, + set the default installation directory accordingly. + Note: here we read IDF_TOOLS_PATH using GetEnv rather than + by getting it from registry, in case the user has set + IDF_TOOLS_PATH as a system environment variable manually. } + +procedure UpdateInstallDir(); +var + EnvToolsPath: String; +begin + EnvToolsPath := GetEnv('IDF_TOOLS_PATH'); + if EnvToolsPath <> '' then + begin + WizardForm.DirEdit.Text := EnvToolsPath; + end; +end; + function PreInstallSteps(CurPageID: Integer): Boolean; var @@ -75,6 +92,11 @@ begin Log('Setting PATH for this process: ' + EnvPath); SetEnvironmentVariable('PATH', EnvPath); + { Set IDF_TOOLS_PATH variable, in case it was set to a different value in the environment. + The installer will set the variable to the new value in the registry, but we also need the + new value to be visible to this process. } + SetEnvironmentVariable('IDF_TOOLS_PATH', ExpandConstant('{app}')) + { Log and clear PYTHONPATH variable, as it might point to libraries of another Python version} PythonLibPath := GetEnv('PYTHONPATH') Log('PYTHONPATH=' + PythonLibPath) From a7ddb0327423ff581a67025ef3542386255ff929 Mon Sep 17 00:00:00 2001 From: chenyudong Date: Fri, 19 Jul 2019 20:02:09 +0800 Subject: [PATCH 359/486] mesh: fix scan done crash caused by uint8_t overflow --- components/esp_wifi/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index 74e3b96630..57e1fd11f2 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit 74e3b9663078d0eea8419efd73334b242bf308cd +Subproject commit 57e1fd11f2f2e17c39ce9612e5fd87d687bcf133 From dd26caf7799a7414596d71d1bc4ee39634480a62 Mon Sep 17 00:00:00 2001 From: xiehang Date: Fri, 19 Jul 2019 15:32:05 +0800 Subject: [PATCH 360/486] esp_wifi: ESP32_WIFI_RX_BA_WIN should be less than ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM --- components/esp_wifi/src/wifi_init.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/esp_wifi/src/wifi_init.c b/components/esp_wifi/src/wifi_init.c index b91614983e..6564acc903 100644 --- a/components/esp_wifi/src/wifi_init.c +++ b/components/esp_wifi/src/wifi_init.c @@ -20,6 +20,14 @@ #include "soc/rtc.h" #include "esp_wpa.h" +#if (CONFIG_ESP32_WIFI_RX_BA_WIN > CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM) +#error "WiFi configuration check: WARNING, WIFI_RX_BA_WIN should not be larger than WIFI_DYNAMIC_RX_BUFFER_NUM!" +#endif + +#if (CONFIG_ESP32_WIFI_RX_BA_WIN > (CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM << 1)) +#error "WiFi configuration check: WARNING, WIFI_RX_BA_WIN should not be larger than double of the WIFI_STATIC_RX_BUFFER_NUM!" +#endif + ESP_EVENT_DEFINE_BASE(WIFI_EVENT); #ifdef CONFIG_PM_ENABLE From 89ee7b5dfb49e454703707aca121645607dd9001 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 18 Jul 2019 15:25:06 +0200 Subject: [PATCH 361/486] examples: add FATFS in external Flash example Demonstrates the usage of the new spi_bus_add_flash_device, esp_flash_init, esp_partition_register_external functions. --- .../storage/ext_flash_fatfs/CMakeLists.txt | 6 + examples/storage/ext_flash_fatfs/Makefile | 9 + examples/storage/ext_flash_fatfs/README.md | 68 +++++++ .../ext_flash_fatfs/main/CMakeLists.txt | 1 + .../storage/ext_flash_fatfs/main/component.mk | 4 + .../main/ext_flash_fatfs_example_main.c | 174 ++++++++++++++++++ examples/storage/wear_levelling/README.md | 2 +- 7 files changed, 263 insertions(+), 1 deletion(-) create mode 100644 examples/storage/ext_flash_fatfs/CMakeLists.txt create mode 100644 examples/storage/ext_flash_fatfs/Makefile create mode 100644 examples/storage/ext_flash_fatfs/README.md create mode 100644 examples/storage/ext_flash_fatfs/main/CMakeLists.txt create mode 100644 examples/storage/ext_flash_fatfs/main/component.mk create mode 100644 examples/storage/ext_flash_fatfs/main/ext_flash_fatfs_example_main.c diff --git a/examples/storage/ext_flash_fatfs/CMakeLists.txt b/examples/storage/ext_flash_fatfs/CMakeLists.txt new file mode 100644 index 0000000000..51f1129ba3 --- /dev/null +++ b/examples/storage/ext_flash_fatfs/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(ext_flash_fatfs) diff --git a/examples/storage/ext_flash_fatfs/Makefile b/examples/storage/ext_flash_fatfs/Makefile new file mode 100644 index 0000000000..7377085972 --- /dev/null +++ b/examples/storage/ext_flash_fatfs/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := ext_flash_fatfs + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/storage/ext_flash_fatfs/README.md b/examples/storage/ext_flash_fatfs/README.md new file mode 100644 index 0000000000..787ec690a8 --- /dev/null +++ b/examples/storage/ext_flash_fatfs/README.md @@ -0,0 +1,68 @@ +# FAT FS on External Flash example + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example is similar to the [wear levelling](../wear_levelling/README.md) example, except that it uses an external SPI Flash chip. This can be useful if you need to add more storage to a module with only 4 MB flash size. + +The flow of the example is as follows: + +1. Initialize the SPI bus and configure the pins. In this example, VSPI peripheral is used. The pins chosen in this example correspond to IOMUX pins for the VSPI peripheral. If the pin assignment is changed, SPI driver will instead connect the peripheral to the pins using the GPIO Matrix. + +2. Initialize the SPI flash chip. This involves creating a run-time object which describes the flash chip (`esp_flash_t`), probing the flash chip, and configuring it for the selected read mode. By default this example uses "Fast Read" mode, which only requires 4 pins (MOSI, MISO, SCLK, CS). For modes such as DIO, QIO, additional pins must be connected. + +3. Register the entire area of the Flash chip as a *partition* (`esp_partition_t`). This allows other components (FATFS, SPIFFS, NVS, etc) to use the storage provided by the external flash chip. + +4. Do some read and write operations using C standard library functions: create a file, write to it, open it for reading, print the contents to the console. + +## How to use example + +### Hardware required + +This example needs an SPI NOR Flash chip connected to the ESP32. The SPI Flash chip must have 3.3V logic levels. The example has been tested with Winbond W25Q32 SPI Flash chip. + +Use the following pin assignments: + +ESP32 pin | SPI bus signal | SPI Flash pin +--------------|----------------|---------------- +GPIO23 | MOSI | DI +GPIO19 | MISO | DO +GPIO18 | SCLK | CLK +GPIO5 | CS | CMD +unconnected | | WP +unconnected | | HOLD +GND | | GND +VCC | | VCC + +### Build and flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +idf.py -p PORT flash monitor +``` + +(Replace PORT with serial port name.) + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example output + +Here is a typical example console output. + +``` +I (328) example: Initializing external SPI Flash +I (338) example: Pin assignments: +I (338) example: MOSI: 23 MISO: 19 SCLK: 18 CS: 5 +I (348) spi_flash: detected chip: generic +I (348) spi_flash: flash io: fastrd +I (348) example: Initialized external Flash, size=4096 KB, ID=0xef4016 +I (358) example: Adding external Flash as a partition, label="storage", size=4096 KB +I (368) example: Mounting FAT filesystem +I (378) example: FAT FS: 4024 kB total, 4020 kB free +I (378) example: Opening file +I (958) example: File written +I (958) example: Reading file +I (958) example: Read from file: 'Written using ESP-IDF v4.0-dev-1301-g0a1160468' +``` diff --git a/examples/storage/ext_flash_fatfs/main/CMakeLists.txt b/examples/storage/ext_flash_fatfs/main/CMakeLists.txt new file mode 100644 index 0000000000..c8a5c30e46 --- /dev/null +++ b/examples/storage/ext_flash_fatfs/main/CMakeLists.txt @@ -0,0 +1 @@ +idf_component_register(SRCS "ext_flash_fatfs_example_main.c") diff --git a/examples/storage/ext_flash_fatfs/main/component.mk b/examples/storage/ext_flash_fatfs/main/component.mk new file mode 100644 index 0000000000..a98f634eae --- /dev/null +++ b/examples/storage/ext_flash_fatfs/main/component.mk @@ -0,0 +1,4 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/storage/ext_flash_fatfs/main/ext_flash_fatfs_example_main.c b/examples/storage/ext_flash_fatfs/main/ext_flash_fatfs_example_main.c new file mode 100644 index 0000000000..c64fb76ad1 --- /dev/null +++ b/examples/storage/ext_flash_fatfs/main/ext_flash_fatfs_example_main.c @@ -0,0 +1,174 @@ +/* Example of FAT filesystem on external Flash. + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. + + This sample shows how to store files inside a FAT filesystem. + FAT filesystem is stored in a partition inside SPI flash, using the + flash wear levelling library. +*/ + +#include +#include +#include +#include "esp_flash.h" +#include "esp_flash_spi_init.h" +#include "esp_partition.h" +#include "esp_vfs.h" +#include "esp_vfs_fat.h" +#include "esp_system.h" + +static const char *TAG = "example"; + +// Handle of the wear levelling library instance +static wl_handle_t s_wl_handle = WL_INVALID_HANDLE; + +// Mount path for the partition +const char *base_path = "/extflash"; + +static esp_flash_t* example_init_ext_flash(); +static const esp_partition_t* example_add_partition(esp_flash_t* ext_flash, const char* partition_label); +static bool example_mount_fatfs(const char* partition_label); +static void example_get_fatfs_usage(size_t* out_total_bytes, size_t* out_free_bytes); + +void app_main(void) +{ + // Set up SPI bus and initialize the external SPI Flash chip + esp_flash_t* flash = example_init_ext_flash(); + if (flash == NULL) { + return; + } + + // Add the entire external flash chip as a partition + const char *partition_label = "storage"; + example_add_partition(flash, partition_label); + + // Initialize FAT FS in the partition + if (!example_mount_fatfs(partition_label)) { + return; + } + + // Print FAT FS size information + size_t bytes_total, bytes_free; + example_get_fatfs_usage(&bytes_total, &bytes_free); + ESP_LOGI(TAG, "FAT FS: %d kB total, %d kB free", bytes_total / 1024, bytes_free / 1024); + + // Create a file in FAT FS + ESP_LOGI(TAG, "Opening file"); + FILE *f = fopen("/extflash/hello.txt", "wb"); + if (f == NULL) { + ESP_LOGE(TAG, "Failed to open file for writing"); + return; + } + fprintf(f, "Written using ESP-IDF %s\n", esp_get_idf_version()); + fclose(f); + ESP_LOGI(TAG, "File written"); + + // Open file for reading + ESP_LOGI(TAG, "Reading file"); + f = fopen("/extflash/hello.txt", "rb"); + if (f == NULL) { + ESP_LOGE(TAG, "Failed to open file for reading"); + return; + } + char line[128]; + fgets(line, sizeof(line), f); + fclose(f); + // strip newline + char *pos = strchr(line, '\n'); + if (pos) { + *pos = '\0'; + } + ESP_LOGI(TAG, "Read from file: '%s'", line); +} + +static esp_flash_t* example_init_ext_flash() +{ + const spi_bus_config_t bus_config = { + .mosi_io_num = VSPI_IOMUX_PIN_NUM_MOSI, + .miso_io_num = VSPI_IOMUX_PIN_NUM_MISO, + .sclk_io_num = VSPI_IOMUX_PIN_NUM_CLK, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + }; + + const esp_flash_spi_device_config_t device_config = { + .host_id = VSPI_HOST, + .cs_id = 0, + .cs_io_num = VSPI_IOMUX_PIN_NUM_CS, + .io_mode = SPI_FLASH_FASTRD, + .speed = ESP_FLASH_40MHZ + }; + + ESP_LOGI(TAG, "Initializing external SPI Flash"); + ESP_LOGI(TAG, "Pin assignments:"); + ESP_LOGI(TAG, "MOSI: %2d MISO: %2d SCLK: %2d CS: %2d", + bus_config.mosi_io_num, bus_config.miso_io_num, + bus_config.sclk_io_num, device_config.cs_io_num + ); + + // Initialize the SPI bus + ESP_ERROR_CHECK(spi_bus_initialize(VSPI_HOST, &bus_config, 1)); + + // Add device to the SPI bus + esp_flash_t* ext_flash; + ESP_ERROR_CHECK(spi_bus_add_flash_device(&ext_flash, &device_config)); + + // Probe the Flash chip and initialize it + esp_err_t err = esp_flash_init(ext_flash); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to initialize external Flash: %s (0x%x)", esp_err_to_name(err), err); + return NULL; + } + + // Print out the ID and size + uint32_t id; + ESP_ERROR_CHECK(esp_flash_read_id(ext_flash, &id)); + ESP_LOGI(TAG, "Initialized external Flash, size=%d KB, ID=0x%x", ext_flash->size / 1024, id); + + return ext_flash; +} + +static const esp_partition_t* example_add_partition(esp_flash_t* ext_flash, const char* partition_label) +{ + ESP_LOGI(TAG, "Adding external Flash as a partition, label=\"%s\", size=%d KB", partition_label, ext_flash->size / 1024); + const esp_partition_t* fat_partition; + ESP_ERROR_CHECK(esp_partition_register_external(ext_flash, 0, ext_flash->size, partition_label, ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_FAT, &fat_partition)); + return fat_partition; +} + +static bool example_mount_fatfs(const char* partition_label) +{ + ESP_LOGI(TAG, "Mounting FAT filesystem"); + const esp_vfs_fat_mount_config_t mount_config = { + .max_files = 4, + .format_if_mount_failed = true, + .allocation_unit_size = CONFIG_WL_SECTOR_SIZE + }; + esp_err_t err = esp_vfs_fat_spiflash_mount(base_path, partition_label, &mount_config, &s_wl_handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err)); + return false; + } + return true; +} + +static void example_get_fatfs_usage(size_t* out_total_bytes, size_t* out_free_bytes) +{ + FATFS *fs; + size_t free_clusters; + int res = f_getfree("0:", &free_clusters, &fs); + assert(res == FR_OK); + size_t total_sectors = (fs->n_fatent - 2) * fs->csize; + size_t free_sectors = free_clusters * fs->csize; + + // assuming the total size is < 4GiB, should be true for SPI Flash + if (out_total_bytes != NULL) { + *out_total_bytes = total_sectors * fs->ssize; + } + if (out_free_bytes != NULL) { + *out_free_bytes = free_sectors * fs->ssize; + } +} diff --git a/examples/storage/wear_levelling/README.md b/examples/storage/wear_levelling/README.md index 9578e16444..f3e5c420f7 100644 --- a/examples/storage/wear_levelling/README.md +++ b/examples/storage/wear_levelling/README.md @@ -36,7 +36,7 @@ See the Getting Started Guide for full steps to configure and use ESP-IDF to bui ## Example output -Here is an typical example console output. +Here is a typical example console output. ``` I (280) example: Mounting FAT filesystem From d1f774bc0a3c1de72b575ff980c7152725a510a3 Mon Sep 17 00:00:00 2001 From: baohongde Date: Fri, 26 Jul 2019 14:39:50 +0800 Subject: [PATCH 362/486] component/bt: Avoid PLC to use unallocated memory Closes https://github.com/espressif/esp-idf/pull/3799 --- .../btc/profile/std/hf_client/bta_hf_client_co.c | 10 ++++++++-- .../bt/host/bluedroid/stack/include/stack/btm_api.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/components/bt/host/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c b/components/bt/host/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c index b8b2ea40c7..99b9280304 100644 --- a/components/bt/host/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c +++ b/components/bt/host/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c @@ -73,8 +73,8 @@ static bta_hf_client_co_cb_t *bta_hf_client_co_cb_ptr; #define bta_hf_client_co_cb (*bta_hf_client_co_cb_ptr) #endif /* HFP_DYNAMIC_MEMORY == FALSE */ -static UINT8 hf_air_mode; -static UINT8 hf_inout_pkt_size; +static UINT8 hf_air_mode = BTM_SCO_AIR_MODE_UNKNOWN; +static UINT8 hf_inout_pkt_size = 0; /******************************************************************************* ** @@ -223,6 +223,9 @@ void bta_hf_client_sco_co_open(UINT16 handle, UINT8 air_mode, UINT8 inout_pkt_si #if (HFP_DYNAMIC_MEMORY == TRUE) error_exit:; + hf_air_mode = BTM_SCO_AIR_MODE_UNKNOWN; + hf_inout_pkt_size = 0; + if (bta_hf_client_co_cb_ptr) { osi_free(bta_hf_client_co_cb_ptr); bta_hf_client_co_cb_ptr = NULL; @@ -271,6 +274,9 @@ void bta_hf_client_sco_co_close(void) } else { // Nothing to do } + + hf_air_mode = BTM_SCO_AIR_MODE_UNKNOWN; + hf_inout_pkt_size = 0; } /******************************************************************************* diff --git a/components/bt/host/bluedroid/stack/include/stack/btm_api.h b/components/bt/host/bluedroid/stack/include/stack/btm_api.h index b51ecb0069..641dd93f52 100644 --- a/components/bt/host/bluedroid/stack/include/stack/btm_api.h +++ b/components/bt/host/bluedroid/stack/include/stack/btm_api.h @@ -983,6 +983,7 @@ typedef UINT16 tBTM_SCO_CODEC_TYPE; #define BTM_SCO_AIR_MODE_A_LAW 1 #define BTM_SCO_AIR_MODE_CVSD 2 #define BTM_SCO_AIR_MODE_TRANSPNT 3 +#define BTM_SCO_AIR_MODE_UNKNOWN 0xFF typedef UINT8 tBTM_SCO_AIR_MODE_TYPE; /******************* From 2d1d747cbb915a0b6037954af040eccce3b634df Mon Sep 17 00:00:00 2001 From: baohongde Date: Fri, 26 Jul 2019 11:17:06 +0800 Subject: [PATCH 363/486] component/bt: Avoid A2DP demo to use unallocated memory --- .../classic_bt/a2dp_sink/main/bt_app_core.c | 18 ++++++++++-------- .../coex/a2dp_gatts_coex/main/bt_app_core.c | 18 ++++++++++-------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_core.c b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_core.c index a46c60050f..7dee9e7f40 100644 --- a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_core.c +++ b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_core.c @@ -26,7 +26,7 @@ static void bt_app_work_dispatched(bt_app_msg_t *msg); static xQueueHandle s_bt_app_task_queue = NULL; static xTaskHandle s_bt_app_task_handle = NULL; static xTaskHandle s_bt_i2s_task_handle = NULL; -static RingbufHandle_t ringbuf_i2s = NULL;; +static RingbufHandle_t s_ringbuf_i2s = NULL;; bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback) { @@ -123,18 +123,18 @@ static void bt_i2s_task_handler(void *arg) size_t bytes_written = 0; for (;;) { - data = (uint8_t *)xRingbufferReceive(ringbuf_i2s, &item_size, (portTickType)portMAX_DELAY); + data = (uint8_t *)xRingbufferReceive(s_ringbuf_i2s, &item_size, (portTickType)portMAX_DELAY); if (item_size != 0){ i2s_write(0, data, item_size, &bytes_written, portMAX_DELAY); - vRingbufferReturnItem(ringbuf_i2s,(void *)data); + vRingbufferReturnItem(s_ringbuf_i2s,(void *)data); } } } void bt_i2s_task_start_up(void) { - ringbuf_i2s = xRingbufferCreate(8 * 1024, RINGBUF_TYPE_BYTEBUF); - if(ringbuf_i2s == NULL){ + s_ringbuf_i2s = xRingbufferCreate(8 * 1024, RINGBUF_TYPE_BYTEBUF); + if(s_ringbuf_i2s == NULL){ return; } @@ -149,13 +149,15 @@ void bt_i2s_task_shut_down(void) s_bt_i2s_task_handle = NULL; } - vRingbufferDelete(ringbuf_i2s); - ringbuf_i2s = NULL; + if (s_ringbuf_i2s) { + vRingbufferDelete(s_ringbuf_i2s); + s_ringbuf_i2s = NULL; + } } size_t write_ringbuf(const uint8_t *data, size_t size) { - BaseType_t done = xRingbufferSend(ringbuf_i2s, (void *)data, size, (portTickType)portMAX_DELAY); + BaseType_t done = xRingbufferSend(s_ringbuf_i2s, (void *)data, size, (portTickType)portMAX_DELAY); if(done){ return size; } else { diff --git a/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_core.c b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_core.c index a46c60050f..7dee9e7f40 100644 --- a/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_core.c +++ b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_core.c @@ -26,7 +26,7 @@ static void bt_app_work_dispatched(bt_app_msg_t *msg); static xQueueHandle s_bt_app_task_queue = NULL; static xTaskHandle s_bt_app_task_handle = NULL; static xTaskHandle s_bt_i2s_task_handle = NULL; -static RingbufHandle_t ringbuf_i2s = NULL;; +static RingbufHandle_t s_ringbuf_i2s = NULL;; bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback) { @@ -123,18 +123,18 @@ static void bt_i2s_task_handler(void *arg) size_t bytes_written = 0; for (;;) { - data = (uint8_t *)xRingbufferReceive(ringbuf_i2s, &item_size, (portTickType)portMAX_DELAY); + data = (uint8_t *)xRingbufferReceive(s_ringbuf_i2s, &item_size, (portTickType)portMAX_DELAY); if (item_size != 0){ i2s_write(0, data, item_size, &bytes_written, portMAX_DELAY); - vRingbufferReturnItem(ringbuf_i2s,(void *)data); + vRingbufferReturnItem(s_ringbuf_i2s,(void *)data); } } } void bt_i2s_task_start_up(void) { - ringbuf_i2s = xRingbufferCreate(8 * 1024, RINGBUF_TYPE_BYTEBUF); - if(ringbuf_i2s == NULL){ + s_ringbuf_i2s = xRingbufferCreate(8 * 1024, RINGBUF_TYPE_BYTEBUF); + if(s_ringbuf_i2s == NULL){ return; } @@ -149,13 +149,15 @@ void bt_i2s_task_shut_down(void) s_bt_i2s_task_handle = NULL; } - vRingbufferDelete(ringbuf_i2s); - ringbuf_i2s = NULL; + if (s_ringbuf_i2s) { + vRingbufferDelete(s_ringbuf_i2s); + s_ringbuf_i2s = NULL; + } } size_t write_ringbuf(const uint8_t *data, size_t size) { - BaseType_t done = xRingbufferSend(ringbuf_i2s, (void *)data, size, (portTickType)portMAX_DELAY); + BaseType_t done = xRingbufferSend(s_ringbuf_i2s, (void *)data, size, (portTickType)portMAX_DELAY); if(done){ return size; } else { From f77a5851bb6e84ca46d3befcd46aa3c4fb507792 Mon Sep 17 00:00:00 2001 From: baohongde Date: Fri, 26 Jul 2019 11:18:42 +0800 Subject: [PATCH 364/486] component/bt: Fix BLE SMP free without init --- components/bt/host/bluedroid/stack/btu/btu_init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/bt/host/bluedroid/stack/btu/btu_init.c b/components/bt/host/bluedroid/stack/btu/btu_init.c index 52ce3a6e15..80678bef82 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_init.c +++ b/components/bt/host/bluedroid/stack/btu/btu_init.c @@ -129,12 +129,12 @@ void btu_free_core(void) #if (defined(GATT_INCLUDED) && GATT_INCLUDED == true) gatt_free(); #endif - btm_ble_free(); -#endif - btm_free(); #if SMP_INCLUDED == TRUE SMP_Free(); #endif + btm_ble_free(); +#endif + btm_free(); } /***************************************************************************** From a8535767e46c153078a22c27664ab4cdcda5d195 Mon Sep 17 00:00:00 2001 From: Mahavir Jain Date: Tue, 9 Jul 2019 12:08:31 +0530 Subject: [PATCH 365/486] esp_event: add missing header include Required header was indirectly getting resolved through lwip includes, apparently does not work if application is not using lwip networking stack. --- components/esp_event/default_event_loop.c | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esp_event/default_event_loop.c b/components/esp_event/default_event_loop.c index 5b402c0bde..01418c72a5 100644 --- a/components/esp_event/default_event_loop.c +++ b/components/esp_event/default_event_loop.c @@ -14,6 +14,7 @@ #include "esp_event.h" #include "esp_event_internal.h" +#include "esp_task.h" /* ------------------------- Static Variables ------------------------------- */ From 26800ed71e287f51666874e83b5dae782cc11e52 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sat, 27 Jul 2019 10:27:38 +0200 Subject: [PATCH 366/486] global: update note in the partition tables The build system automatically determines offsets of partitions from the partition table, so no manual changes are needed. Instead, add a note that partition offsets may need to be updated when increasing the bootloader size. --- components/fatfs/test_fatfs_host/partition_table.csv | 2 +- components/partition_table/partitions_singleapp.csv | 2 +- components/partition_table/partitions_singleapp_coredump.csv | 2 +- components/partition_table/partitions_two_ota.csv | 2 +- components/partition_table/partitions_two_ota_coredump.csv | 2 +- components/spiffs/test_spiffs_host/partition_table.csv | 2 +- components/wear_levelling/test_wl_host/partition_table.csv | 2 +- docs/en/api-guides/bootloader.rst | 2 +- docs/en/api-guides/core_dump.rst | 2 +- .../bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/partitions.csv | 2 +- examples/build_system/cmake/import_lib/partitions_example.csv | 2 +- examples/ethernet/iperf/partitions_example.csv | 2 +- examples/peripherals/i2c/i2c_tools/partitions_example.csv | 2 +- examples/peripherals/i2s_adc_dac/partitions_adc_dac_example.csv | 2 +- .../protocols/http_server/file_serving/partitions_example.csv | 2 +- .../protocols/http_server/restful_server/partitions_example.csv | 2 +- examples/provisioning/ble_prov/partitions.csv | 2 +- examples/provisioning/manager/partitions.csv | 2 +- examples/storage/partition_api/partition_find/README.md | 2 +- .../storage/partition_api/partition_find/partitions_example.csv | 2 +- .../storage/partition_api/partition_mmap/partitions_example.csv | 2 +- .../storage/partition_api/partition_ops/partitions_example.csv | 2 +- examples/storage/parttool/partitions_example.csv | 2 +- examples/storage/spiffs/partitions_example.csv | 2 +- examples/storage/spiffsgen/partitions_example.csv | 2 +- examples/storage/wear_levelling/partitions_example.csv | 2 +- examples/system/console/partitions_example.csv | 2 +- examples/wifi/simple_sniffer/partitions_example.csv | 2 +- tools/unit-test-app/partition_table_unit_test_app.csv | 2 +- 29 files changed, 29 insertions(+), 29 deletions(-) diff --git a/components/fatfs/test_fatfs_host/partition_table.csv b/components/fatfs/test_fatfs_host/partition_table.csv index cb7fccd87b..9b4dbd1ba5 100644 --- a/components/fatfs/test_fatfs_host/partition_table.csv +++ b/components/fatfs/test_fatfs_host/partition_table.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, diff --git a/components/partition_table/partitions_singleapp.csv b/components/partition_table/partitions_singleapp.csv index 22cf97bacb..5156e827b4 100644 --- a/components/partition_table/partitions_singleapp.csv +++ b/components/partition_table/partitions_singleapp.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, , 0x6000, phy_init, data, phy, , 0x1000, factory, app, factory, , 1M, diff --git a/components/partition_table/partitions_singleapp_coredump.csv b/components/partition_table/partitions_singleapp_coredump.csv index 8bcf89c20f..bbb55e2b47 100644 --- a/components/partition_table/partitions_singleapp_coredump.csv +++ b/components/partition_table/partitions_singleapp_coredump.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, , 0x6000 phy_init, data, phy, , 0x1000 factory, app, factory, , 1M diff --git a/components/partition_table/partitions_two_ota.csv b/components/partition_table/partitions_two_ota.csv index 0a325b2f5a..7aee909cd1 100644 --- a/components/partition_table/partitions_two_ota.csv +++ b/components/partition_table/partitions_two_ota.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, , 0x4000, otadata, data, ota, , 0x2000, phy_init, data, phy, , 0x1000, diff --git a/components/partition_table/partitions_two_ota_coredump.csv b/components/partition_table/partitions_two_ota_coredump.csv index 3a2143690b..2e1af0eca6 100644 --- a/components/partition_table/partitions_two_ota_coredump.csv +++ b/components/partition_table/partitions_two_ota_coredump.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, , 0x4000 otadata, data, ota, , 0x2000 phy_init, data, phy, , 0x1000 diff --git a/components/spiffs/test_spiffs_host/partition_table.csv b/components/spiffs/test_spiffs_host/partition_table.csv index d02771b51b..3c2903a70d 100644 --- a/components/spiffs/test_spiffs_host/partition_table.csv +++ b/components/spiffs/test_spiffs_host/partition_table.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, diff --git a/components/wear_levelling/test_wl_host/partition_table.csv b/components/wear_levelling/test_wl_host/partition_table.csv index af5bc831eb..f6383e46d4 100644 --- a/components/wear_levelling/test_wl_host/partition_table.csv +++ b/components/wear_levelling/test_wl_host/partition_table.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, diff --git a/docs/en/api-guides/bootloader.rst b/docs/en/api-guides/bootloader.rst index aea98d6c91..2671b353fc 100644 --- a/docs/en/api-guides/bootloader.rst +++ b/docs/en/api-guides/bootloader.rst @@ -33,7 +33,7 @@ Partitions of type "app" cannot be specified here. Partition table.:: # Name, Type, SubType, Offset, Size, Flags - # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild + # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x4000 otadata, data, ota, 0xd000, 0x2000 phy_init, data, phy, 0xf000, 0x1000 diff --git a/docs/en/api-guides/core_dump.rst b/docs/en/api-guides/core_dump.rst index c590efeea7..f96d4e2cb0 100644 --- a/docs/en/api-guides/core_dump.rst +++ b/docs/en/api-guides/core_dump.rst @@ -37,7 +37,7 @@ allocates necessary space on flash, But if user wants to use its own layout file as it is shown below:: # Name, Type, SubType, Offset, Size - # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild + # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000 phy_init, data, phy, 0xf000, 0x1000 factory, app, factory, 0x10000, 1M diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/partitions.csv b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/partitions.csv index 96141670f3..24200e5b33 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/partitions.csv +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/partitions.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 16k otadata, data, ota, 0xd000, 8k phy_init, data, phy, 0xf000, 4k diff --git a/examples/build_system/cmake/import_lib/partitions_example.csv b/examples/build_system/cmake/import_lib/partitions_example.csv index 3e9543311e..3337f31642 100644 --- a/examples/build_system/cmake/import_lib/partitions_example.csv +++ b/examples/build_system/cmake/import_lib/partitions_example.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, diff --git a/examples/ethernet/iperf/partitions_example.csv b/examples/ethernet/iperf/partitions_example.csv index 7e28b5668c..ac18e080c8 100644 --- a/examples/ethernet/iperf/partitions_example.csv +++ b/examples/ethernet/iperf/partitions_example.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, diff --git a/examples/peripherals/i2c/i2c_tools/partitions_example.csv b/examples/peripherals/i2c/i2c_tools/partitions_example.csv index 7e28b5668c..ac18e080c8 100644 --- a/examples/peripherals/i2c/i2c_tools/partitions_example.csv +++ b/examples/peripherals/i2c/i2c_tools/partitions_example.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, diff --git a/examples/peripherals/i2s_adc_dac/partitions_adc_dac_example.csv b/examples/peripherals/i2s_adc_dac/partitions_adc_dac_example.csv index c9a081314e..85bc43e33c 100644 --- a/examples/peripherals/i2s_adc_dac/partitions_adc_dac_example.csv +++ b/examples/peripherals/i2s_adc_dac/partitions_adc_dac_example.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, diff --git a/examples/protocols/http_server/file_serving/partitions_example.csv b/examples/protocols/http_server/file_serving/partitions_example.csv index 6d9ee2e745..0eebc192ae 100644 --- a/examples/protocols/http_server/file_serving/partitions_example.csv +++ b/examples/protocols/http_server/file_serving/partitions_example.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, diff --git a/examples/protocols/http_server/restful_server/partitions_example.csv b/examples/protocols/http_server/restful_server/partitions_example.csv index ca4898e596..a5b16e199b 100644 --- a/examples/protocols/http_server/restful_server/partitions_example.csv +++ b/examples/protocols/http_server/restful_server/partitions_example.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, diff --git a/examples/provisioning/ble_prov/partitions.csv b/examples/provisioning/ble_prov/partitions.csv index e382463f94..d01414b8a9 100644 --- a/examples/provisioning/ble_prov/partitions.csv +++ b/examples/provisioning/ble_prov/partitions.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1200000, diff --git a/examples/provisioning/manager/partitions.csv b/examples/provisioning/manager/partitions.csv index e382463f94..d01414b8a9 100644 --- a/examples/provisioning/manager/partitions.csv +++ b/examples/provisioning/manager/partitions.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1200000, diff --git a/examples/storage/partition_api/partition_find/README.md b/examples/storage/partition_api/partition_find/README.md index 03b71cbc5c..a05152850e 100644 --- a/examples/storage/partition_api/partition_find/README.md +++ b/examples/storage/partition_api/partition_find/README.md @@ -20,7 +20,7 @@ The iterator is obtained using `esp_partition_find` and is released after its us I (310) example: Printing partition table csv file contents for reference... # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, diff --git a/examples/storage/partition_api/partition_find/partitions_example.csv b/examples/storage/partition_api/partition_find/partitions_example.csv index a0ff092cc1..f3c3b68e56 100644 --- a/examples/storage/partition_api/partition_find/partitions_example.csv +++ b/examples/storage/partition_api/partition_find/partitions_example.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, diff --git a/examples/storage/partition_api/partition_mmap/partitions_example.csv b/examples/storage/partition_api/partition_mmap/partitions_example.csv index 52a5fce840..a70efe6a75 100644 --- a/examples/storage/partition_api/partition_mmap/partitions_example.csv +++ b/examples/storage/partition_api/partition_mmap/partitions_example.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, diff --git a/examples/storage/partition_api/partition_ops/partitions_example.csv b/examples/storage/partition_api/partition_ops/partitions_example.csv index 52a5fce840..a70efe6a75 100644 --- a/examples/storage/partition_api/partition_ops/partitions_example.csv +++ b/examples/storage/partition_api/partition_ops/partitions_example.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, diff --git a/examples/storage/parttool/partitions_example.csv b/examples/storage/parttool/partitions_example.csv index f76d1ca37a..f49ae3c602 100644 --- a/examples/storage/parttool/partitions_example.csv +++ b/examples/storage/parttool/partitions_example.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, diff --git a/examples/storage/spiffs/partitions_example.csv b/examples/storage/spiffs/partitions_example.csv index 6d9ee2e745..0eebc192ae 100644 --- a/examples/storage/spiffs/partitions_example.csv +++ b/examples/storage/spiffs/partitions_example.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, diff --git a/examples/storage/spiffsgen/partitions_example.csv b/examples/storage/spiffsgen/partitions_example.csv index 6d9ee2e745..0eebc192ae 100644 --- a/examples/storage/spiffsgen/partitions_example.csv +++ b/examples/storage/spiffsgen/partitions_example.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, diff --git a/examples/storage/wear_levelling/partitions_example.csv b/examples/storage/wear_levelling/partitions_example.csv index 7e28b5668c..ac18e080c8 100644 --- a/examples/storage/wear_levelling/partitions_example.csv +++ b/examples/storage/wear_levelling/partitions_example.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, diff --git a/examples/system/console/partitions_example.csv b/examples/system/console/partitions_example.csv index 7e28b5668c..ac18e080c8 100644 --- a/examples/system/console/partitions_example.csv +++ b/examples/system/console/partitions_example.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, diff --git a/examples/wifi/simple_sniffer/partitions_example.csv b/examples/wifi/simple_sniffer/partitions_example.csv index 7e28b5668c..ac18e080c8 100644 --- a/examples/wifi/simple_sniffer/partitions_example.csv +++ b/examples/wifi/simple_sniffer/partitions_example.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, diff --git a/tools/unit-test-app/partition_table_unit_test_app.csv b/tools/unit-test-app/partition_table_unit_test_app.csv index f4bd924310..948f00c5c1 100644 --- a/tools/unit-test-app/partition_table_unit_test_app.csv +++ b/tools/unit-test-app/partition_table_unit_test_app.csv @@ -1,7 +1,7 @@ # Special partition table for unit test app # # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x4000 otadata, data, ota, 0xd000, 0x2000 phy_init, data, phy, 0xf000, 0x1000 From 7cb3a57b9c7c75fc0313b3f79db5b5e8cc007e7d Mon Sep 17 00:00:00 2001 From: Dmitry Plotnikov Date: Thu, 4 Jul 2019 11:02:20 +0400 Subject: [PATCH 367/486] build_system: add -freorder-blocks option for release config --- CMakeLists.txt | 3 ++- make/project.mk | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b48106487..a0ef70d15f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,7 @@ unset(compile_definitions) if(CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE) list(APPEND compile_options "-Os") + list(APPEND compile_options "-freorder-blocks") else() list(APPEND compile_options "-Og") endif() @@ -79,4 +80,4 @@ foreach(component_target ${build_component_targets}) add_subdirectory(${dir} ${_name}) endif() set(__idf_component_context 0) -endforeach() \ No newline at end of file +endforeach() diff --git a/make/project.mk b/make/project.mk index 32d8862e4f..e146acc42f 100644 --- a/make/project.mk +++ b/make/project.mk @@ -418,7 +418,7 @@ endif # Optimization flags are set based on menuconfig choice ifdef CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE -OPTIMIZATION_FLAGS = -Os +OPTIMIZATION_FLAGS = -Os -freorder-blocks else OPTIMIZATION_FLAGS = -Og endif From 3e17c69e4fa0b90a95884672f339568c80b071ae Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 18 Jul 2019 17:20:40 +0200 Subject: [PATCH 368/486] tools: idf_tools.py: allow downloading for a different platform --- tools/idf_tools.py | 93 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 16 deletions(-) diff --git a/tools/idf_tools.py b/tools/idf_tools.py index b5cfb08038..9ad9f019d2 100755 --- a/tools/idf_tools.py +++ b/tools/idf_tools.py @@ -53,6 +53,7 @@ import zipfile import errno import shutil import functools +import copy from collections import OrderedDict, namedtuple try: @@ -372,12 +373,19 @@ class IDFTool(object): self.options = IDFToolOptions(version_cmd, version_regex, version_regex_replace, [], OrderedDict(), install, info_url, license, strip_container_dirs) self.platform_overrides = [] + self._platform = CURRENT_PLATFORM self._update_current_options() + def copy_for_platform(self, platform): + result = copy.deepcopy(self) + result._platform = platform + result._update_current_options() + return result + def _update_current_options(self): self._current_options = IDFToolOptions(*self.options) for override in self.platform_overrides: - if CURRENT_PLATFORM not in override['platforms']: + if self._platform not in override['platforms']: continue override_dict = override.copy() del override_dict['platforms'] @@ -422,6 +430,8 @@ class IDFTool(object): Returns 'unknown' if tool returns something from which version string can not be extracted. """ + # this function can not be called for a different platform + assert self._platform == CURRENT_PLATFORM cmd = self._current_options.version_cmd try: version_cmd_result = run_cmd_check_output(cmd, None, extra_paths) @@ -447,7 +457,7 @@ class IDFTool(object): def get_recommended_version(self): recommended_versions = [k for k, v in self.versions.items() if v.status == IDFToolVersion.STATUS_RECOMMENDED - and v.compatible_with_platform()] + and v.compatible_with_platform(self._platform)] assert len(recommended_versions) <= 1 if recommended_versions: return recommended_versions[0] @@ -456,7 +466,7 @@ class IDFTool(object): def get_preferred_installed_version(self): recommended_versions = [k for k in self.versions_installed if self.versions[k].status == IDFToolVersion.STATUS_RECOMMENDED - and self.versions[k].compatible_with_platform()] + and self.versions[k].compatible_with_platform(self._platform)] assert len(recommended_versions) <= 1 if recommended_versions: return recommended_versions[0] @@ -467,6 +477,8 @@ class IDFTool(object): Checks whether the tool can be found in PATH and in global_idf_tools_path. Writes results to self.version_in_path and self.versions_installed. """ + # this function can not be called for a different platform + assert self._platform == CURRENT_PLATFORM # First check if the tool is in system PATH try: ver_str = self.check_version() @@ -504,9 +516,9 @@ class IDFTool(object): def download(self, version): assert(version in self.versions) - download_obj = self.versions[version].get_download_for_platform(PYTHON_PLATFORM) + download_obj = self.versions[version].get_download_for_platform(self._platform) if not download_obj: - fatal('No packages for tool {} platform {}!'.format(self.name, PYTHON_PLATFORM)) + fatal('No packages for tool {} platform {}!'.format(self.name, self._platform)) raise DownloadError() url = download_obj.url @@ -543,7 +555,7 @@ class IDFTool(object): # Currently this is called after calling 'download' method, so here are a few asserts # for the conditions which should be true once that method is done. assert (version in self.versions) - download_obj = self.versions[version].get_download_for_platform(PYTHON_PLATFORM) + download_obj = self.versions[version].get_download_for_platform(self._platform) assert (download_obj is not None) archive_name = os.path.basename(download_obj.url) archive_path = os.path.join(global_idf_tools_path, 'dist', archive_name) @@ -985,7 +997,7 @@ def action_export(args): raise SystemExit(1) -def apply_mirror_prefix_map(args, tool_obj, tool_version): +def apply_mirror_prefix_map(args, tool_download_obj): """Rewrite URL for given tool_obj, given tool_version, and current platform, if --mirror-prefix-map flag or IDF_MIRROR_PREFIX_MAP environment variable is given. """ @@ -998,21 +1010,62 @@ def apply_mirror_prefix_map(args, tool_obj, tool_version): warn('Both IDF_MIRROR_PREFIX_MAP environment variable and --mirror-prefix-map flag are specified, ' + 'will use the value from the command line.') mirror_prefix_map = args.mirror_prefix_map - download_obj = tool_obj.versions[tool_version].get_download_for_platform(PYTHON_PLATFORM) - if mirror_prefix_map and download_obj: + if mirror_prefix_map and tool_download_obj: for item in mirror_prefix_map: if URL_PREFIX_MAP_SEPARATOR not in item: warn('invalid mirror-prefix-map item (missing \'{}\') {}'.format(URL_PREFIX_MAP_SEPARATOR, item)) continue search, replace = item.split(URL_PREFIX_MAP_SEPARATOR, 1) - old_url = download_obj.url + old_url = tool_download_obj.url new_url = re.sub(search, replace, old_url) if new_url != old_url: info('Changed download URL: {} => {}'.format(old_url, new_url)) - download_obj.url = new_url + tool_download_obj.url = new_url break +def action_download(args): + tools_info = load_tools_info() + tools_spec = args.tools + + if args.platform not in PLATFORM_FROM_NAME: + fatal('unknown platform: {}' % args.platform) + raise SystemExit(1) + platform = PLATFORM_FROM_NAME[args.platform] + + tools_info_for_platform = OrderedDict() + for name, tool_obj in tools_info.items(): + tool_for_platform = tool_obj.copy_for_platform(platform) + tools_info_for_platform[name] = tool_for_platform + + if 'all' in tools_spec: + tools_spec = [k for k, v in tools_info_for_platform.items() if v.get_install_type() != IDFTool.INSTALL_NEVER] + info('Downloading tools for {}: {}'.format(platform, ', '.join(tools_spec))) + + for tool_spec in tools_spec: + if '@' not in tool_spec: + tool_name = tool_spec + tool_version = None + else: + tool_name, tool_version = tool_spec.split('@', 1) + if tool_name not in tools_info_for_platform: + fatal('unknown tool name: {}'.format(tool_name)) + raise SystemExit(1) + tool_obj = tools_info_for_platform[tool_name] + if tool_version is not None and tool_version not in tool_obj.versions: + fatal('unknown version for tool {}: {}'.format(tool_name, tool_version)) + raise SystemExit(1) + if tool_version is None: + tool_version = tool_obj.get_recommended_version() + assert tool_version is not None + tool_spec = '{}@{}'.format(tool_name, tool_version) + + info('Downloading {}'.format(tool_spec)) + apply_mirror_prefix_map(args, tool_obj.versions[tool_version].get_download_for_platform(platform)) + + tool_obj.download(tool_version) + + def action_install(args): tools_info = load_tools_info() tools_spec = args.tools @@ -1049,7 +1102,7 @@ def action_install(args): continue info('Installing {}'.format(tool_spec)) - apply_mirror_prefix_map(args, tool_obj, tool_version) + apply_mirror_prefix_map(args, tool_obj.versions[tool_version].get_download_for_platform(PYTHON_PLATFORM)) tool_obj.download(tool_version) tool_obj.install(tool_version) @@ -1174,14 +1227,22 @@ def main(argv): 'will be used instead. If this flag is given, the version in PATH ' + 'will be used.', action='store_true') install = subparsers.add_parser('install', help='Download and install tools into the tools directory') - if IDF_MAINTAINER: - install.add_argument('--mirror-prefix-map', nargs='*', - help='Pattern to rewrite download URLs, with source and replacement separated by comma.' + - ' E.g. http://foo.com,http://test.foo.com') install.add_argument('tools', nargs='*', help='Tools to install. ' + 'To install a specific version use tool_name@version syntax.' + 'Use \'all\' to install all tools, including the optional ones.') + download = subparsers.add_parser('download', help='Download the tools into the dist directory') + download.add_argument('--platform', help='Platform to download the tools for') + download.add_argument('tools', nargs='+', help='Tools to download. ' + + 'To download a specific version use tool_name@version syntax.' + + 'Use \'all\' to download all tools, including the optional ones.') + + if IDF_MAINTAINER: + for subparser in [download, install]: + subparser.add_argument('--mirror-prefix-map', nargs='*', + help='Pattern to rewrite download URLs, with source and replacement separated by comma.' + + ' E.g. http://foo.com,http://test.foo.com') + install_python_env = subparsers.add_parser('install-python-env', help='Create Python virtual environment and install the ' + 'required Python packages') From 98c179ed4757a94e6e9c39a89b83a2e373eb5ff5 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sun, 28 Jul 2019 07:48:21 +0200 Subject: [PATCH 369/486] esp32: also add -mfix-esp32-psram-cache-issue to LDFLAGS xtensa-esp32-elf-gcc selects among the multilib configurations based on the presence of -mfix-esp32-psram-cache-issue flag. Pass this flag in LDFLAGS so that the correct libraries are linked. Reported in https://github.com/espressif/esp-idf/issues/3624 --- components/esp32/Makefile.projbuild | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esp32/Makefile.projbuild b/components/esp32/Makefile.projbuild index 0ae77a69d2..cf8746f268 100644 --- a/components/esp32/Makefile.projbuild +++ b/components/esp32/Makefile.projbuild @@ -2,6 +2,7 @@ ifdef CONFIG_SPIRAM_CACHE_WORKAROUND CFLAGS+=-mfix-esp32-psram-cache-issue CXXFLAGS+=-mfix-esp32-psram-cache-issue +LDFLAGS+=-mfix-esp32-psram-cache-issue endif # Enable dynamic esp_timer overflow value if building unit tests From 3f9fc97de71d4666c488b08c04cda6681de289d8 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sun, 28 Jul 2019 10:04:36 +0200 Subject: [PATCH 370/486] tools: export.sh: fix ESP-IDF path detection on macos The argument passed to the function is in $1; $0 contains `-bash`. Before this fix, IDF_PATH would be set to $PWD instead of the correct path. --- export.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/export.sh b/export.sh index 9f8f98f5aa..0408a76bb3 100644 --- a/export.sh +++ b/export.sh @@ -2,9 +2,10 @@ function realpath_int() { wdir="$PWD"; [ "$PWD" = "/" ] && wdir="" - case "$0" in - /*) scriptdir="${0}";; - *) scriptdir="$wdir/${0#./}";; + arg=$1 + case "$arg" in + /*) scriptdir="${arg}";; + *) scriptdir="$wdir/${arg#./}";; esac scriptdir="${scriptdir%/*}" echo "$scriptdir" From 8d35744a3366efec2087164afb2888424e89da44 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sun, 28 Jul 2019 10:14:04 +0200 Subject: [PATCH 371/486] examples: ext_flash_fatfs: use DIO mode by default DIO works with the same connections as Fast Read, so use it by default. Also correct the note in README.md which says that DIO requires additional pins. --- examples/storage/ext_flash_fatfs/README.md | 4 ++-- .../ext_flash_fatfs/main/ext_flash_fatfs_example_main.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/storage/ext_flash_fatfs/README.md b/examples/storage/ext_flash_fatfs/README.md index 787ec690a8..fcc54e76fa 100644 --- a/examples/storage/ext_flash_fatfs/README.md +++ b/examples/storage/ext_flash_fatfs/README.md @@ -8,7 +8,7 @@ The flow of the example is as follows: 1. Initialize the SPI bus and configure the pins. In this example, VSPI peripheral is used. The pins chosen in this example correspond to IOMUX pins for the VSPI peripheral. If the pin assignment is changed, SPI driver will instead connect the peripheral to the pins using the GPIO Matrix. -2. Initialize the SPI flash chip. This involves creating a run-time object which describes the flash chip (`esp_flash_t`), probing the flash chip, and configuring it for the selected read mode. By default this example uses "Fast Read" mode, which only requires 4 pins (MOSI, MISO, SCLK, CS). For modes such as DIO, QIO, additional pins must be connected. +2. Initialize the SPI flash chip. This involves creating a run-time object which describes the flash chip (`esp_flash_t`), probing the flash chip, and configuring it for the selected read mode. By default this example uses DIO mode, which only requires 4 pins (MOSI, MISO, SCLK, CS). For modes such as QIO and QOUT, additional pins must be connected. 3. Register the entire area of the Flash chip as a *partition* (`esp_partition_t`). This allows other components (FATFS, SPIFFS, NVS, etc) to use the storage provided by the external flash chip. @@ -56,7 +56,7 @@ I (328) example: Initializing external SPI Flash I (338) example: Pin assignments: I (338) example: MOSI: 23 MISO: 19 SCLK: 18 CS: 5 I (348) spi_flash: detected chip: generic -I (348) spi_flash: flash io: fastrd +I (348) spi_flash: flash io: dio I (348) example: Initialized external Flash, size=4096 KB, ID=0xef4016 I (358) example: Adding external Flash as a partition, label="storage", size=4096 KB I (368) example: Mounting FAT filesystem diff --git a/examples/storage/ext_flash_fatfs/main/ext_flash_fatfs_example_main.c b/examples/storage/ext_flash_fatfs/main/ext_flash_fatfs_example_main.c index c64fb76ad1..4a930bf8af 100644 --- a/examples/storage/ext_flash_fatfs/main/ext_flash_fatfs_example_main.c +++ b/examples/storage/ext_flash_fatfs/main/ext_flash_fatfs_example_main.c @@ -98,7 +98,7 @@ static esp_flash_t* example_init_ext_flash() .host_id = VSPI_HOST, .cs_id = 0, .cs_io_num = VSPI_IOMUX_PIN_NUM_CS, - .io_mode = SPI_FLASH_FASTRD, + .io_mode = SPI_FLASH_DIO, .speed = ESP_FLASH_40MHZ }; From b98b4c38863f70e105e575f065d3ab7adbcc58cd Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Fri, 12 Jul 2019 13:20:04 +0800 Subject: [PATCH 372/486] sdmmc_io: support to print CIS information Currently only ESP slaves can be parsed correctly. --- components/driver/include/driver/sdmmc_defs.h | 24 +- components/sdmmc/include/sdmmc_cmd.h | 49 +++ components/sdmmc/sdmmc_io.c | 278 ++++++++++++++++++ .../peripherals/sdio/host/main/app_main.c | 45 ++- 4 files changed, 383 insertions(+), 13 deletions(-) diff --git a/components/driver/include/driver/sdmmc_defs.h b/components/driver/include/driver/sdmmc_defs.h index dd4c426411..4f1e6ddc6b 100644 --- a/components/driver/include/driver/sdmmc_defs.h +++ b/components/driver/include/driver/sdmmc_defs.h @@ -458,15 +458,23 @@ static inline uint32_t MMC_RSP_BITS(uint32_t *src, int start, int len) #define SD_IO_CIS_SIZE 0x17000 /* CIS tuple codes (based on PC Card 16) */ -#define SD_IO_CISTPL_NULL 0x00 -#define SD_IO_CISTPL_VERS_1 0x15 -#define SD_IO_CISTPL_MANFID 0x20 -#define SD_IO_CISTPL_FUNCID 0x21 -#define SD_IO_CISTPL_FUNCE 0x22 -#define SD_IO_CISTPL_END 0xff +#define CISTPL_CODE_NULL 0x00 +#define CISTPL_CODE_DEVICE 0x01 +#define CISTPL_CODE_CHKSUM 0x10 +#define CISTPL_CODE_VERS1 0x15 +#define CISTPL_CODE_ALTSTR 0x16 +#define CISTPL_CODE_CONFIG 0x1A +#define CISTPL_CODE_CFTABLE_ENTRY 0x1B +#define CISTPL_CODE_MANFID 0x20 +#define CISTPL_CODE_FUNCID 0x21 +#define TPLFID_FUNCTION_SDIO 0x0c +#define CISTPL_CODE_FUNCE 0x22 +#define CISTPL_CODE_VENDER_BEGIN 0x80 +#define CISTPL_CODE_VENDER_END 0x8F +#define CISTPL_CODE_SDIO_STD 0x91 +#define CISTPL_CODE_SDIO_EXT 0x92 +#define CISTPL_CODE_END 0xFF -/* CISTPL_FUNCID codes */ -#define TPLFID_FUNCTION_SDIO 0x0c /* Timing */ #define SDMMC_TIMING_LEGACY 0 diff --git a/components/sdmmc/include/sdmmc_cmd.h b/components/sdmmc/include/sdmmc_cmd.h index aa12a4477a..666f35560d 100644 --- a/components/sdmmc/include/sdmmc_cmd.h +++ b/components/sdmmc/include/sdmmc_cmd.h @@ -220,6 +220,55 @@ esp_err_t sdmmc_io_enable_int(sdmmc_card_t* card); */ esp_err_t sdmmc_io_wait_int(sdmmc_card_t* card, TickType_t timeout_ticks); +/** + * Get the data of CIS region of a SDIO card. + * + * You may provide a buffer not sufficient to store all the CIS data. In this + * case, this functions store as much data into your buffer as possible. Also, + * this function will try to get and return the size required for you. + * + * @param card pointer to card information structure previously initialized + * using sdmmc_card_init + * @param out_buffer Output buffer of the CIS data + * @param buffer_size Size of the buffer. + * @param inout_cis_size Mandatory, pointer to a size, input and output. + * - input: Limitation of maximum searching range, should be 0 or larger than + * buffer_size. The function searches for CIS_CODE_END until this range. Set to + * 0 to search infinitely. + * - output: The size required to store all the CIS data, if CIS_CODE_END is found. + * + * @return + * - ESP_OK: on success + * - ESP_ERR_INVALID_RESPONSE: if the card does not (correctly) support CIS. + * - ESP_ERR_INVALID_SIZE: CIS_CODE_END found, but buffer_size is less than + * required size, which is stored in the inout_cis_size then. + * - ESP_ERR_NOT_FOUND: if the CIS_CODE_END not found. Increase input value of + * inout_cis_size or set it to 0, if you still want to search for the end; + * output value of inout_cis_size is invalid in this case. + * - and other error code return from sdmmc_io_read_bytes + */ +esp_err_t sdmmc_io_get_cis_data(sdmmc_card_t* card, uint8_t* out_buffer, size_t buffer_size, size_t* inout_cis_size); + +/** + * Parse and print the CIS information of a SDIO card. + * + * @note Not all the CIS codes and all kinds of tuples are supported. If you + * see some unresolved code, you can add the parsing of these code in + * sdmmc_io.c and contribute to the IDF through the Github repository. + * + * using sdmmc_card_init + * @param buffer Buffer to parse + * @param buffer_size Size of the buffer. + * @param fp File pointer to print to, set to NULL to print to stdout. + * + * @return + * - ESP_OK: on success + * - ESP_ERR_NOT_SUPPORTED: if the value from the card is not supported to be parsed. + * - ESP_ERR_INVALID_SIZE: if the CIS size fields are not correct. + */ +esp_err_t sdmmc_io_print_cis_info(uint8_t* buffer, size_t buffer_size, FILE* fp); + + #ifdef __cplusplus } #endif diff --git a/components/sdmmc/sdmmc_io.c b/components/sdmmc/sdmmc_io.c index 7229f18983..e77623a17a 100644 --- a/components/sdmmc/sdmmc_io.c +++ b/components/sdmmc/sdmmc_io.c @@ -16,9 +16,50 @@ */ #include "sdmmc_common.h" +#include "esp_attr.h" + + +#define CIS_TUPLE(NAME) (cis_tuple_t) {.code=CISTPL_CODE_##NAME, .name=#NAME, .func=&cis_tuple_func_default, } +#define CIS_TUPLE_WITH_FUNC(NAME, FUNC) (cis_tuple_t) {.code=CISTPL_CODE_##NAME, .name=#NAME, .func=&(FUNC), } + +#define CIS_CHECK_SIZE(SIZE, MINIMAL) do {int store_size = (SIZE); if((store_size) < (MINIMAL)) return ESP_ERR_INVALID_SIZE;} while(0) +#define CIS_CHECK_UNSUPPORTED(COND) do {if(!(COND)) return ESP_ERR_NOT_SUPPORTED;} while(0) +#define CIS_GET_MINIMAL_SIZE 32 + +typedef esp_err_t (*cis_tuple_info_func_t)(const void* tuple_info, uint8_t* data, FILE* fp); + +typedef struct { + int code; + const char *name; + cis_tuple_info_func_t func; +} cis_tuple_t; static const char* TAG = "sdmmc_io"; +static esp_err_t cis_tuple_func_default(const void* p, uint8_t* data, FILE* fp); +static esp_err_t cis_tuple_func_manfid(const void* p, uint8_t* data, FILE* fp); +static esp_err_t cis_tuple_func_cftable_entry(const void* p, uint8_t* data, FILE* fp); +static esp_err_t cis_tuple_func_end(const void* p, uint8_t* data, FILE* fp); + +static const cis_tuple_t cis_table[] = { + CIS_TUPLE(NULL), + CIS_TUPLE(DEVICE), + CIS_TUPLE(CHKSUM), + CIS_TUPLE(VERS1), + CIS_TUPLE(ALTSTR), + CIS_TUPLE(CONFIG), + CIS_TUPLE_WITH_FUNC(CFTABLE_ENTRY, cis_tuple_func_cftable_entry), + CIS_TUPLE_WITH_FUNC(MANFID, cis_tuple_func_manfid), + CIS_TUPLE(FUNCID), + CIS_TUPLE(FUNCE), + CIS_TUPLE(VENDER_BEGIN), + CIS_TUPLE(VENDER_END), + CIS_TUPLE(SDIO_STD), + CIS_TUPLE(SDIO_EXT), + CIS_TUPLE_WITH_FUNC(END, cis_tuple_func_end), +}; + + esp_err_t sdmmc_io_reset(sdmmc_card_t* card) { uint8_t sdio_reset = CCCR_CTL_RES; @@ -352,3 +393,240 @@ esp_err_t sdmmc_io_wait_int(sdmmc_card_t* card, TickType_t timeout_ticks) } return (*card->host.io_int_wait)(card->host.slot, timeout_ticks); } + + +/* + * Print the CIS information of a CIS card, currently only ESP slave supported. + */ + +static esp_err_t cis_tuple_func_default(const void* p, uint8_t* data, FILE* fp) +{ + const cis_tuple_t* tuple = (const cis_tuple_t*)p; + uint8_t code = *(data++); + int size = *(data++); + if (tuple) { + fprintf(fp, "TUPLE: %s, size: %d: ", tuple->name, size); + } else { + fprintf(fp, "TUPLE: unknown(%02X), size: %d: ", code, size); + } + for (int i = 0; i < size; i++) fprintf(fp, "%02X ", *(data++)); + fprintf(fp, "\n"); + return ESP_OK; +} + +static esp_err_t cis_tuple_func_manfid(const void* p, uint8_t* data, FILE* fp) +{ + const cis_tuple_t* tuple = (const cis_tuple_t*)p; + data++; + int size = *(data++); + fprintf(fp, "TUPLE: %s, size: %d\n", tuple->name, size); + CIS_CHECK_SIZE(size, 4); + fprintf(fp, " MANF: %04X, CARD: %04X\n", *(uint16_t*)(data), *(uint16_t*)(data+2)); + return ESP_OK; +} + +static esp_err_t cis_tuple_func_end(const void* p, uint8_t* data, FILE* fp) +{ + const cis_tuple_t* tuple = (const cis_tuple_t*)p; + data++; + fprintf(fp, "TUPLE: %s\n", tuple->name); + return ESP_OK; +} + +static esp_err_t cis_tuple_func_cftable_entry(const void* p, uint8_t* data, FILE* fp) +{ + const cis_tuple_t* tuple = (const cis_tuple_t*)p; + data++; + int size = *(data++); + fprintf(fp, "TUPLE: %s, size: %d\n", tuple->name, size); + CIS_CHECK_SIZE(size, 2); + + CIS_CHECK_SIZE(size--, 1); + bool interface = data[0] & BIT(7); + bool def = data[0] & BIT(6); + int conf_ent_num = data[0] & 0x3F; + fprintf(fp, " INDX: %02X, Intface: %d, Default: %d, Conf-Entry-Num: %d\n", *(data++), interface, def, conf_ent_num); + + if (interface) { + CIS_CHECK_SIZE(size--, 1); + fprintf(fp, " IF: %02X\n", *(data++)); + } + + CIS_CHECK_SIZE(size--, 1); + bool misc = data[0] & BIT(7); + int mem_space = (data[0] >> 5 )&(0x3); + bool irq = data[0] & BIT(4); + bool io_sp = data[0] & BIT(3); + bool timing = data[0] & BIT(2); + int power = data[0] & 3; + fprintf(fp, " FS: %02X, misc: %d, mem_space: %d, irq: %d, io_space: %d, timing: %d, power: %d\n", *(data++), misc, mem_space, irq, io_sp, timing, power); + + CIS_CHECK_UNSUPPORTED(power == 0); //power descriptor is not handled yet + CIS_CHECK_UNSUPPORTED(!timing); //timing descriptor is not handled yet + CIS_CHECK_UNSUPPORTED(!io_sp); //io space descriptor is not handled yet + + if (irq) { + CIS_CHECK_SIZE(size--, 1); + bool mask = data[0] & BIT(4); + fprintf(fp, " IR: %02X, mask: %d, ",*(data++), mask); + if (mask) { + CIS_CHECK_SIZE(size, 2); + size-=2; + fprintf(fp, " IRQ: %02X %02X\n", data[0], data[1]); + data+=2; + } + } + + if (mem_space) { + CIS_CHECK_SIZE(size, 2); + size-=2; + CIS_CHECK_UNSUPPORTED(mem_space==1); //other cases not handled yet + int len = *(uint16_t*)data; + fprintf(fp, " LEN: %04X\n", len); + data+=2; + } + + CIS_CHECK_UNSUPPORTED(misc==0); //misc descriptor is not handled yet + return ESP_OK; +} + +static const cis_tuple_t* get_tuple(uint8_t code) +{ + for (int i = 0; i < sizeof(cis_table)/sizeof(cis_tuple_t); i++) { + if (code == cis_table[i].code) return &cis_table[i]; + } + return NULL; +} + +esp_err_t sdmmc_io_print_cis_info(uint8_t* buffer, size_t buffer_size, FILE* fp) +{ + ESP_LOG_BUFFER_HEXDUMP("CIS", buffer, buffer_size, ESP_LOG_DEBUG); + if (!fp) fp = stdout; + + uint8_t* cis = buffer; + do { + const cis_tuple_t* tuple = get_tuple(cis[0]); + int size = cis[1]; + esp_err_t ret = ESP_OK; + if (tuple) { + ret = tuple->func(tuple, cis, fp); + } else { + ret = cis_tuple_func_default(NULL, cis, fp); + } + if (ret != ESP_OK) return ret; + cis += 2 + size; + if (tuple && tuple->code == CISTPL_CODE_END) break; + } while (cis < buffer + buffer_size) ; + return ESP_OK; +} + +/** + * Check tuples in the buffer. + * + * @param buf Buffer to check + * @param buffer_size Size of the buffer + * @param inout_cis_offset + * - input: the last cis_offset, relative to the beginning of the buf. -1 if + * this buffer begin with the tuple length, otherwise should be no smaller than + * zero. + * - output: when the end tuple found, output offset of the CISTPL_CODE_END + * byte + 1 (relative to the beginning of the buffer; when not found, output + * the address of next tuple code. + * + * @return true if found, false if haven't. + */ +static bool check_tuples_in_buffer(uint8_t* buf, int buffer_size, int* inout_cis_offset) +{ + int cis_offset = *inout_cis_offset; + if (cis_offset == -1) { + //the CIS code is checked in the last buffer, skip to next tuple + cis_offset += buf[0] + 2; + } + assert(cis_offset >= 0); + while (1) { + if (cis_offset < buffer_size) { + //A CIS code in the buffer, check it + if (buf[cis_offset] == CISTPL_CODE_END) { + *inout_cis_offset = cis_offset + 1; + return true; + } + } + if (cis_offset + 1 < buffer_size) { + cis_offset += buf[cis_offset+1] + 2; + } else { + break; + } + } + *inout_cis_offset = cis_offset; + return false; +} + +esp_err_t sdmmc_io_get_cis_data(sdmmc_card_t* card, uint8_t* out_buffer, size_t buffer_size, size_t* inout_cis_size) +{ + esp_err_t ret = ESP_OK; + WORD_ALIGNED_ATTR uint8_t buf[CIS_GET_MINIMAL_SIZE]; + + /* + * CIS region exist in 0x1000~0x17FFF of FUNC 0, get the start address of it + * from CCCR register. + */ + uint32_t addr; + ret = sdmmc_io_read_bytes(card, 0, 9, &addr, 3); + if (ret != ESP_OK) return ret; + //the sdmmc_io driver reads 4 bytes, the most significant byte is not the address. + addr &= 0xffffff; + if (addr < 0x1000 || addr > 0x17FFF) { + return ESP_ERR_INVALID_RESPONSE; + } + + /* + * To avoid reading too long, take the input value as limitation if + * existing. + */ + size_t max_reading = UINT32_MAX; + if (inout_cis_size && *inout_cis_size != 0) { + max_reading = *inout_cis_size; + } + + /* + * Parse the length while reading. If find the end tuple, or reaches the + * limitation, read no more and return both the data and the size already + * read. + */ + int buffer_offset = 0; + int cur_cis_offset = 0; + bool end_tuple_found = false; + do { + ret = sdmmc_io_read_bytes(card, 0, addr + buffer_offset, &buf, CIS_GET_MINIMAL_SIZE); + if (ret != ESP_OK) return ret; + + //calculate relative to the beginning of the buffer + int offset = cur_cis_offset - buffer_offset; + bool finish = check_tuples_in_buffer(buf, CIS_GET_MINIMAL_SIZE, &offset); + + int remain_size = buffer_size - buffer_offset; + int copy_len; + if (finish) { + copy_len = MIN(offset, remain_size); + end_tuple_found = true; + } else { + copy_len = MIN(CIS_GET_MINIMAL_SIZE, remain_size); + } + if (copy_len > 0) { + memcpy(out_buffer + buffer_offset, buf, copy_len); + } + cur_cis_offset = buffer_offset + offset; + buffer_offset += CIS_GET_MINIMAL_SIZE; + } while (!end_tuple_found && buffer_offset < max_reading); + + if (end_tuple_found) { + *inout_cis_size = cur_cis_offset; + if (cur_cis_offset > buffer_size) { + return ESP_ERR_INVALID_SIZE; + } else { + return ESP_OK; + } + } else { + return ESP_ERR_NOT_FOUND; + } +} diff --git a/examples/peripherals/sdio/host/main/app_main.c b/examples/peripherals/sdio/host/main/app_main.c index 5015048f72..b0b62d15df 100644 --- a/examples/peripherals/sdio/host/main/app_main.c +++ b/examples/peripherals/sdio/host/main/app_main.c @@ -25,6 +25,7 @@ #include "driver/sdmmc_host.h" #include "driver/sdspi_host.h" + /* * For SDIO master-slave board, we have 3 pins controlling power of 3 different * slaves individially. We only enable one at a time. @@ -134,6 +135,36 @@ static void gpio_d2_set_high() } #endif +static esp_err_t print_sdio_cis_information(sdmmc_card_t* card) +{ + const size_t cis_buffer_size = 256; + uint8_t cis_buffer[cis_buffer_size]; + size_t cis_data_len = 1024; //specify maximum searching range to avoid infinite loop + esp_err_t ret = ESP_OK; + + ret = sdmmc_io_get_cis_data(card, cis_buffer, cis_buffer_size, &cis_data_len); + if (ret == ESP_ERR_INVALID_SIZE) { + int temp_buf_size = cis_data_len; + uint8_t* temp_buf = malloc(temp_buf_size); + assert(temp_buf); + + ESP_LOGW(TAG, "CIS data longer than expected, temporary buffer allocated."); + ret = sdmmc_io_get_cis_data(card, temp_buf, temp_buf_size, &cis_data_len); + ESP_ERROR_CHECK(ret); + + sdmmc_io_print_cis_info(temp_buf, cis_data_len, NULL); + + free(temp_buf); + } else if (ret == ESP_OK) { + sdmmc_io_print_cis_info(cis_buffer, cis_data_len, NULL); + } else { + //including ESP_ERR_NOT_FOUND + ESP_LOGE(TAG, "failed to get the entire CIS data."); + abort(); + } + return ESP_OK; +} + //host use this to initialize the slave card as well as SDIO registers esp_err_t slave_init(esp_slave_context_t *context) { @@ -164,10 +195,10 @@ esp_err_t slave_init(esp_slave_context_t *context) */ //slot_config.flags = SDMMC_SLOT_FLAG_INTERNAL_PULLUP; err = sdmmc_host_init(); - assert(err==ESP_OK); + ESP_ERROR_CHECK(err); err = sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config); - assert(err==ESP_OK); + ESP_ERROR_CHECK(err); #else //over SPI sdmmc_host_t config = SDSPI_HOST_DEFAULT(); @@ -179,12 +210,12 @@ esp_err_t slave_init(esp_slave_context_t *context) slot_config.gpio_int = SDIO_SLAVE_SLOT1_IOMUX_PIN_NUM_D1; err = gpio_install_isr_service(0); - assert(err == ESP_OK); + ESP_ERROR_CHECK(err); err = sdspi_host_init(); - assert(err==ESP_OK); + ESP_ERROR_CHECK(err); err = sdspi_host_init_slot(HSPI_HOST, &slot_config); - assert(err==ESP_OK); + ESP_ERROR_CHECK(err); ESP_LOGI(TAG, "Probe using SPI...\n"); //we have to pull up all the slave pins even when the pin is not used @@ -218,10 +249,14 @@ esp_err_t slave_init(esp_slave_context_t *context) *context = ESP_SLAVE_DEFAULT_CONTEXT(card); esp_err_t ret = esp_slave_init_io(context); + ESP_ERROR_CHECK(ret); + ret = print_sdio_cis_information(card); + ESP_ERROR_CHECK(ret); return ret; } + void slave_power_on() { #ifdef SLAVE_PWR_GPIO From 661769527c16d6f3269b6a6254f0576135c8673d Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sun, 28 Jul 2019 11:22:08 +0200 Subject: [PATCH 373/486] pthread: force linking pthread implementation from IDF Force linking pthread implementation from IDF, instead of the weak functions provided by gthread library. Previously this would either work or not depending on the linking order. Thanks @bpietsch for suggesting the fix. Closes https://github.com/espressif/esp-idf/issues/3709 --- components/pthread/CMakeLists.txt | 10 ++++++++++ components/pthread/component.mk | 8 ++++++++ components/pthread/pthread.c | 5 +++++ components/pthread/pthread_cond_var.c | 5 +++++ components/pthread/pthread_local_storage.c | 5 +++++ 5 files changed, 33 insertions(+) diff --git a/components/pthread/CMakeLists.txt b/components/pthread/CMakeLists.txt index d488c92a9d..136bf9cf1c 100644 --- a/components/pthread/CMakeLists.txt +++ b/components/pthread/CMakeLists.txt @@ -3,6 +3,16 @@ idf_component_register(SRCS "pthread.c" "pthread_local_storage.c" INCLUDE_DIRS include) +if(GCC_NOT_5_2_0) + set(extra_link_flags "-u pthread_include_pthread_impl") + list(APPEND extra_link_flags "-u pthread_include_pthread_cond_impl") + list(APPEND extra_link_flags "-u pthread_include_pthread_local_storage_impl") +endif() + if(CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP) target_link_libraries(${COMPONENT_LIB} "-Wl,--wrap=vPortCleanUpTCB") endif() + +if(extra_link_flags) + target_link_libraries(${COMPONENT_LIB} INTERFACE "${extra_link_flags}") +endif() diff --git a/components/pthread/component.mk b/components/pthread/component.mk index 9c3eececf5..c5793fded6 100644 --- a/components/pthread/component.mk +++ b/components/pthread/component.mk @@ -11,3 +11,11 @@ COMPONENT_ADD_LDFLAGS := -lpthread ifdef CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP COMPONENT_ADD_LDFLAGS += -Wl,--wrap=vPortCleanUpTCB endif + +ifeq ($(GCC_NOT_5_2_0), 1) +# Forces the linker to include pthread implementation from this component, +# instead of the weak implementations provided by libgcc. +COMPONENT_ADD_LDFLAGS += -u pthread_include_pthread_impl +COMPONENT_ADD_LDFLAGS += -u pthread_include_pthread_cond_impl +COMPONENT_ADD_LDFLAGS += -u pthread_include_pthread_local_storage_impl +endif # GCC_NOT_5_2_0 diff --git a/components/pthread/pthread.c b/components/pthread/pthread.c index 84997c9aad..f4fe4ded7d 100644 --- a/components/pthread/pthread.c +++ b/components/pthread/pthread.c @@ -820,3 +820,8 @@ int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) } return EINVAL; } + +/* Hook function to force linking this file */ +void pthread_include_pthread_impl() +{ +} diff --git a/components/pthread/pthread_cond_var.c b/components/pthread/pthread_cond_var.c index fe3144512d..8db28ae5e1 100644 --- a/components/pthread/pthread_cond_var.c +++ b/components/pthread/pthread_cond_var.c @@ -198,3 +198,8 @@ int pthread_cond_destroy(pthread_cond_t *cv) return ret; } + +/* Hook function to force linking this file */ +void pthread_include_pthread_cond_var_impl() +{ +} diff --git a/components/pthread/pthread_local_storage.c b/components/pthread/pthread_local_storage.c index 5e2dbafd21..ecf252e4cc 100644 --- a/components/pthread/pthread_local_storage.c +++ b/components/pthread/pthread_local_storage.c @@ -255,3 +255,8 @@ int pthread_setspecific(pthread_key_t key, const void *value) return 0; } + +/* Hook function to force linking this file */ +void pthread_include_pthread_local_storage_impl() +{ +} From e9de7b1df327034dac2bef21ab4cf4cb422cf463 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sun, 28 Jul 2019 11:22:51 +0200 Subject: [PATCH 374/486] pthread: remove ESP32_ prefix from Kconfig options pthread implementation is not chip-specific, so this prefix is not needed. --- components/pthread/Kconfig | 26 ++++++++++++------------ components/pthread/include/esp_pthread.h | 2 +- components/pthread/pthread.c | 18 ++++++++-------- components/pthread/sdkconfig.rename | 9 +++++++- tools/ldgen/samples/sdkconfig | 4 ++-- 5 files changed, 33 insertions(+), 26 deletions(-) diff --git a/components/pthread/Kconfig b/components/pthread/Kconfig index 61fa8a33e6..20e3f6123f 100644 --- a/components/pthread/Kconfig +++ b/components/pthread/Kconfig @@ -1,46 +1,46 @@ menu "PThreads" - config ESP32_PTHREAD_TASK_PRIO_DEFAULT + config PTHREAD_TASK_PRIO_DEFAULT int "Default task priority" range 0 255 default 5 help Priority used to create new tasks with default pthread parameters. - config ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT + config PTHREAD_TASK_STACK_SIZE_DEFAULT int "Default task stack size" default 3072 help Stack size used to create new tasks with default pthread parameters. - config ESP32_PTHREAD_STACK_MIN + config PTHREAD_STACK_MIN int "Minimum allowed pthread stack size" default 768 help Minimum allowed pthread stack size set in attributes passed to pthread_create - choice ESP32_PTHREAD_TASK_CORE_DEFAULT + choice PTHREAD_TASK_CORE_DEFAULT bool "Default pthread core affinity" - default ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY + default PTHREAD_DEFAULT_CORE_NO_AFFINITY depends on !FREERTOS_UNICORE help The default core to which pthreads are pinned. - config ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY + config PTHREAD_DEFAULT_CORE_NO_AFFINITY bool "No affinity" - config ESP32_DEFAULT_PTHREAD_CORE_0 + config PTHREAD_DEFAULT_CORE_0 bool "Core 0" - config ESP32_DEFAULT_PTHREAD_CORE_1 + config PTHREAD_DEFAULT_CORE_1 bool "Core 1" endchoice - config ESP32_PTHREAD_TASK_CORE_DEFAULT + config PTHREAD_TASK_CORE_DEFAULT int - default -1 if ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY || FREERTOS_UNICORE - default 0 if ESP32_DEFAULT_PTHREAD_CORE_0 - default 1 if ESP32_DEFAULT_PTHREAD_CORE_1 + default -1 if PTHREAD_DEFAULT_CORE_NO_AFFINITY || FREERTOS_UNICORE + default 0 if PTHREAD_DEFAULT_CORE_0 + default 1 if PTHREAD_DEFAULT_CORE_1 - config ESP32_PTHREAD_TASK_NAME_DEFAULT + config PTHREAD_TASK_NAME_DEFAULT string "Default name of pthreads" default "pthread" help diff --git a/components/pthread/include/esp_pthread.h b/components/pthread/include/esp_pthread.h index ca93c9c380..76f45a32ab 100644 --- a/components/pthread/include/esp_pthread.h +++ b/components/pthread/include/esp_pthread.h @@ -22,7 +22,7 @@ extern "C" { #endif #ifndef PTHREAD_STACK_MIN -#define PTHREAD_STACK_MIN CONFIG_ESP32_PTHREAD_STACK_MIN +#define PTHREAD_STACK_MIN CONFIG_PTHREAD_STACK_MIN #endif /** pthread configuration structure that influences pthread creation */ diff --git a/components/pthread/pthread.c b/components/pthread/pthread.c index f4fe4ded7d..ce0c064ce3 100644 --- a/components/pthread/pthread.c +++ b/components/pthread/pthread.c @@ -170,14 +170,14 @@ esp_err_t esp_pthread_get_cfg(esp_pthread_cfg_t *p) static int get_default_pthread_core() { - return CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT == -1 ? tskNO_AFFINITY : CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT; + return CONFIG_PTHREAD_TASK_CORE_DEFAULT == -1 ? tskNO_AFFINITY : CONFIG_PTHREAD_TASK_CORE_DEFAULT; } esp_pthread_cfg_t esp_pthread_get_default_config() { esp_pthread_cfg_t cfg = { - .stack_size = CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT, - .prio = CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT, + .stack_size = CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT, + .prio = CONFIG_PTHREAD_TASK_PRIO_DEFAULT, .inherit_cfg = false, .thread_name = NULL, .pin_to_core = get_default_pthread_core() @@ -233,10 +233,10 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr, return ENOMEM; } - uint32_t stack_size = CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT; - BaseType_t prio = CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT; + uint32_t stack_size = CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT; + BaseType_t prio = CONFIG_PTHREAD_TASK_PRIO_DEFAULT; BaseType_t core_id = get_default_pthread_core(); - const char *task_name = CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT; + const char *task_name = CONFIG_PTHREAD_TASK_NAME_DEFAULT; esp_pthread_cfg_t *pthread_cfg = pthread_getspecific(s_pthread_cfg_key); if (pthread_cfg) { @@ -256,7 +256,7 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr, task_name = pthread_cfg->thread_name; } } else if (pthread_cfg->thread_name == NULL) { - task_name = CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT; + task_name = CONFIG_PTHREAD_TASK_NAME_DEFAULT; } else { task_name = pthread_cfg->thread_name; } @@ -758,7 +758,7 @@ int pthread_attr_init(pthread_attr_t *attr) { if (attr) { /* Nothing to allocate. Set everything to default */ - attr->stacksize = CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT; + attr->stacksize = CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT; attr->detachstate = PTHREAD_CREATE_JOINABLE; return 0; } @@ -769,7 +769,7 @@ int pthread_attr_destroy(pthread_attr_t *attr) { if (attr) { /* Nothing to deallocate. Reset everything to default */ - attr->stacksize = CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT; + attr->stacksize = CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT; attr->detachstate = PTHREAD_CREATE_JOINABLE; return 0; } diff --git a/components/pthread/sdkconfig.rename b/components/pthread/sdkconfig.rename index b72b647076..fb5c0ff34c 100644 --- a/components/pthread/sdkconfig.rename +++ b/components/pthread/sdkconfig.rename @@ -1,4 +1,11 @@ # sdkconfig replacement configurations for deprecated options formatted as # CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION -CONFIG_PTHREAD_STACK_MIN CONFIG_ESP32_PTHREAD_STACK_MIN +CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT CONFIG_PTHREAD_TASK_PRIO_DEFAULT +CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT +CONFIG_ESP32_PTHREAD_STACK_MIN CONFIG_PTHREAD_STACK_MIN +CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT CONFIG_PTHREAD_TASK_CORE_DEFAULT +CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY +CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0 CONFIG_PTHREAD_DEFAULT_CORE_0 +CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1 CONFIG_PTHREAD_DEFAULT_CORE_1 +CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT CONFIG_PTHREAD_TASK_NAME_DEFAULT diff --git a/tools/ldgen/samples/sdkconfig b/tools/ldgen/samples/sdkconfig index 8fbfd61586..1bcf44ecfb 100644 --- a/tools/ldgen/samples/sdkconfig +++ b/tools/ldgen/samples/sdkconfig @@ -485,8 +485,8 @@ CONFIG_OPENSSL_ASSERT_EXIT= # # PThreads # -CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5 -CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 # # SPI Flash driver From 3c63f495914cae7cac8add82b4373b37436d7410 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Fri, 26 Jul 2019 14:36:21 +0200 Subject: [PATCH 375/486] examples: remove non-existent options from sdkconfig.defaults --- examples/build_system/cmake/import_lib/sdkconfig.defaults | 2 -- examples/ethernet/iperf/sdkconfig.defaults | 1 - examples/protocols/http_server/file_serving/sdkconfig.defaults | 2 -- .../protocols/http_server/restful_server/sdkconfig.defaults | 1 - .../storage/partition_api/partition_find/sdkconfig.defaults | 2 -- .../storage/partition_api/partition_mmap/sdkconfig.defaults | 2 -- examples/storage/partition_api/partition_ops/sdkconfig.defaults | 2 -- examples/storage/parttool/sdkconfig.defaults | 2 -- examples/storage/spiffs/sdkconfig.defaults | 2 -- examples/storage/spiffsgen/sdkconfig.defaults | 2 -- examples/storage/wear_levelling/sdkconfig.defaults | 2 -- examples/system/console/sdkconfig.defaults | 2 -- tools/ldgen/samples/sdkconfig | 2 -- 13 files changed, 24 deletions(-) diff --git a/examples/build_system/cmake/import_lib/sdkconfig.defaults b/examples/build_system/cmake/import_lib/sdkconfig.defaults index f30f322c62..b9bb0c0a5d 100644 --- a/examples/build_system/cmake/import_lib/sdkconfig.defaults +++ b/examples/build_system/cmake/import_lib/sdkconfig.defaults @@ -1,5 +1,3 @@ CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv" -CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000 CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv" -CONFIG_APP_OFFSET=0x10000 diff --git a/examples/ethernet/iperf/sdkconfig.defaults b/examples/ethernet/iperf/sdkconfig.defaults index 085e6f3138..1bdcdc7208 100644 --- a/examples/ethernet/iperf/sdkconfig.defaults +++ b/examples/ethernet/iperf/sdkconfig.defaults @@ -4,7 +4,6 @@ CONFIG_ESP_MAIN_TASK_STACK_SIZE=7168 # Enable filesystem CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv" -CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000 CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv" # Enable FreeRTOS stats formatting functions, needed for 'tasks' command diff --git a/examples/protocols/http_server/file_serving/sdkconfig.defaults b/examples/protocols/http_server/file_serving/sdkconfig.defaults index e64150b079..30306931f3 100644 --- a/examples/protocols/http_server/file_serving/sdkconfig.defaults +++ b/examples/protocols/http_server/file_serving/sdkconfig.defaults @@ -1,6 +1,4 @@ CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv" -CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000 CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv" -CONFIG_APP_OFFSET=0x10000 CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024 diff --git a/examples/protocols/http_server/restful_server/sdkconfig.defaults b/examples/protocols/http_server/restful_server/sdkconfig.defaults index 599472d848..87b6ea1e57 100644 --- a/examples/protocols/http_server/restful_server/sdkconfig.defaults +++ b/examples/protocols/http_server/restful_server/sdkconfig.defaults @@ -5,5 +5,4 @@ CONFIG_FATFS_LFN_HEAP=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv" -CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000 CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv" diff --git a/examples/storage/partition_api/partition_find/sdkconfig.defaults b/examples/storage/partition_api/partition_find/sdkconfig.defaults index 61aebc7e90..b9bb0c0a5d 100644 --- a/examples/storage/partition_api/partition_find/sdkconfig.defaults +++ b/examples/storage/partition_api/partition_find/sdkconfig.defaults @@ -1,5 +1,3 @@ CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv" -CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000 CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv" -CONFIG_APP_OFFSET=0x10000 \ No newline at end of file diff --git a/examples/storage/partition_api/partition_mmap/sdkconfig.defaults b/examples/storage/partition_api/partition_mmap/sdkconfig.defaults index 61aebc7e90..b9bb0c0a5d 100644 --- a/examples/storage/partition_api/partition_mmap/sdkconfig.defaults +++ b/examples/storage/partition_api/partition_mmap/sdkconfig.defaults @@ -1,5 +1,3 @@ CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv" -CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000 CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv" -CONFIG_APP_OFFSET=0x10000 \ No newline at end of file diff --git a/examples/storage/partition_api/partition_ops/sdkconfig.defaults b/examples/storage/partition_api/partition_ops/sdkconfig.defaults index 61aebc7e90..b9bb0c0a5d 100644 --- a/examples/storage/partition_api/partition_ops/sdkconfig.defaults +++ b/examples/storage/partition_api/partition_ops/sdkconfig.defaults @@ -1,5 +1,3 @@ CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv" -CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000 CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv" -CONFIG_APP_OFFSET=0x10000 \ No newline at end of file diff --git a/examples/storage/parttool/sdkconfig.defaults b/examples/storage/parttool/sdkconfig.defaults index 61aebc7e90..b9bb0c0a5d 100644 --- a/examples/storage/parttool/sdkconfig.defaults +++ b/examples/storage/parttool/sdkconfig.defaults @@ -1,5 +1,3 @@ CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv" -CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000 CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv" -CONFIG_APP_OFFSET=0x10000 \ No newline at end of file diff --git a/examples/storage/spiffs/sdkconfig.defaults b/examples/storage/spiffs/sdkconfig.defaults index f30f322c62..b9bb0c0a5d 100644 --- a/examples/storage/spiffs/sdkconfig.defaults +++ b/examples/storage/spiffs/sdkconfig.defaults @@ -1,5 +1,3 @@ CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv" -CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000 CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv" -CONFIG_APP_OFFSET=0x10000 diff --git a/examples/storage/spiffsgen/sdkconfig.defaults b/examples/storage/spiffsgen/sdkconfig.defaults index f30f322c62..b9bb0c0a5d 100644 --- a/examples/storage/spiffsgen/sdkconfig.defaults +++ b/examples/storage/spiffsgen/sdkconfig.defaults @@ -1,5 +1,3 @@ CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv" -CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000 CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv" -CONFIG_APP_OFFSET=0x10000 diff --git a/examples/storage/wear_levelling/sdkconfig.defaults b/examples/storage/wear_levelling/sdkconfig.defaults index b09d670fdb..47363c32d5 100644 --- a/examples/storage/wear_levelling/sdkconfig.defaults +++ b/examples/storage/wear_levelling/sdkconfig.defaults @@ -1,6 +1,4 @@ CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv" -CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000 CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv" -CONFIG_APP_OFFSET=0x10000 CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y diff --git a/examples/system/console/sdkconfig.defaults b/examples/system/console/sdkconfig.defaults index 5e4c72ae84..49c3225d69 100644 --- a/examples/system/console/sdkconfig.defaults +++ b/examples/system/console/sdkconfig.defaults @@ -8,9 +8,7 @@ CONFIG_ESP_MAIN_TASK_STACK_SIZE=7168 # Enable filesystem CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv" -CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000 CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv" -CONFIG_APP_OFFSET=0x10000 # Enable FreeRTOS stats formatting functions, needed for 'tasks' command CONFIG_FREERTOS_USE_TRACE_FACILITY=y diff --git a/tools/ldgen/samples/sdkconfig b/tools/ldgen/samples/sdkconfig index 8fbfd61586..075841ea81 100644 --- a/tools/ldgen/samples/sdkconfig +++ b/tools/ldgen/samples/sdkconfig @@ -76,9 +76,7 @@ CONFIG_PARTITION_TABLE_SINGLE_APP=y CONFIG_PARTITION_TABLE_TWO_OTA= CONFIG_PARTITION_TABLE_CUSTOM= CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" -CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000 CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv" -CONFIG_APP_OFFSET=0x10000 CONFIG_PARTITION_TABLE_MD5=y # From fa555e3109e5491688f6ffc4c3e7349c09854b5d Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Sun, 7 Jul 2019 18:11:02 +0800 Subject: [PATCH 376/486] esp_flash: fix a compatibility issue working with the ROM The esp_flash API has a side effects: it modifies the clock control registers, and this makes the clock inconsistent with the ROM variable `g_rom_spiflash_dummy_len_plus`. This commit helps the ROM to get the correct dummy cycles required by the latest clock settings. Every device on the SPI1 bus will update the ROM variable when it modifies the clock registers. --- components/soc/src/hal/spi_flash_hal_iram.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/components/soc/src/hal/spi_flash_hal_iram.c b/components/soc/src/hal/spi_flash_hal_iram.c index ddd2c7d5f3..56a525baac 100644 --- a/components/soc/src/hal/spi_flash_hal_iram.c +++ b/components/soc/src/hal/spi_flash_hal_iram.c @@ -38,6 +38,17 @@ esp_err_t spi_flash_hal_device_config(spi_flash_host_driver_t *driver) spi_flash_ll_reset(dev); spi_flash_ll_set_cs_pin(dev, drv_data->cs_num); spi_flash_ll_set_clock(dev, &drv_data->clock_conf); + + /* + * workaround for the ROM: the ROM, as well as the OpenOCD, don't know the + * clock registers and the dummy are modified this help the ROM to read and + * write correctly according to the new dummy len. + */ + if (dev == &SPI1) { + //0 for cache, 1 for SPI1 + extern uint8_t g_rom_spiflash_dummy_len_plus[]; + g_rom_spiflash_dummy_len_plus[1] = drv_data->extra_dummy; + } return ESP_OK; } From 6cff19adb6f73fb270c281e4370f8ede752e1f80 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 18 Jul 2019 17:34:36 +0200 Subject: [PATCH 377/486] ci: add jobs to build idf_exe, cmdlinerunner, tools installer --- tools/ci/config/build.yml | 79 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/tools/ci/config/build.yml b/tools/ci/config/build.yml index 215f5117e7..c5dab206d9 100644 --- a/tools/ci/config/build.yml +++ b/tools/ci/config/build.yml @@ -282,3 +282,82 @@ build_docker: # The workaround mentioned there works, but leaves around directories which need to be cleaned up manually. # Therefore, build a copy of the example located inside the container. - docker run --rm --workdir /opt/esp/idf/examples/get-started/blink ${DOCKER_TMP_IMAGE_NAME} idf.py build + +build_idf_exe: + stage: build + image: $CI_DOCKER_REGISTRY/esp32-toolchain-win-cross + tags: + - build + only: + refs: + - master + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ + - schedules + before_script: [] + artifacts: + paths: + - tools/windows/idf_exe/build/idf-exe-v*.zip + expire_in: 3 days + script: + - cd tools/windows/idf_exe/ + - mkdir build + - cd build + - cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain-i686-w64-mingw32.cmake -DCMAKE_BUILD_TYPE=Release .. + - cmake --build . + +build_cmdlinerunner: + stage: build + image: $CI_DOCKER_REGISTRY/esp32-toolchain-win-cross + tags: + - build + only: + refs: + - master + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ + - schedules + before_script: [] + artifacts: + paths: + - tools/windows/tool_setup/cmdlinerunner/build/cmdlinerunner.dll + expire_in: 3 days + script: + - cd tools/windows/tool_setup/cmdlinerunner + - mkdir build + - cd build + - cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain-i686-w64-mingw32.cmake -DCMAKE_BUILD_TYPE=Release .. + - cmake --build . + +build_installer: + # using a different stage here to be able to use artifacts from build_cmdlinerunner job + stage: host_test + image: $CI_DOCKER_REGISTRY/wine-innosetup:1 + tags: + - build + only: + refs: + - master + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ + - schedules + dependencies: + - build_cmdlinerunner + before_script: [] + script: + - mkdir idf_tools_tmp + - export IDF_TOOLS_PATH=$PWD/idf_tools_tmp + - tools/idf_tools.py --non-interactive download --platform Windows-x86_64 all + - tools/idf_tools.py --tools-json tools/windows/tool_setup/tools_fallback.json --non-interactive download --platform Windows-x86_64 all + - mkdir tools/windows/tool_setup/dist + - mv idf_tools_tmp/dist/* tools/windows/tool_setup/dist/ + + - cd tools/windows/tool_setup/ + - mkdir unzip + - cd unzip + - wget --no-verbose https://www.7-zip.org/a/7z1900-extra.7z + - 7zr e -y 7z1900-extra.7z + - cd .. + + - wget --no-verbose https://dl.espressif.com/dl/esp-idf/idf_versions.txt + - iscc idf_tool_setup.iss From 62bb107b31c98f604effcd4209562a5e5fa305fc Mon Sep 17 00:00:00 2001 From: zhangyanjiao Date: Mon, 29 Jul 2019 14:55:17 +0800 Subject: [PATCH 378/486] docs: fix the bug in wifi doc --- components/esp_wifi/include/esp_wifi_types.h | 2 +- docs/en/api-guides/wifi.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/esp_wifi/include/esp_wifi_types.h b/components/esp_wifi/include/esp_wifi_types.h index 57b916ec79..fea3f14676 100644 --- a/components/esp_wifi/include/esp_wifi_types.h +++ b/components/esp_wifi/include/esp_wifi_types.h @@ -225,7 +225,7 @@ typedef struct { uint8_t channel; /**< channel of target AP. Set to 1~13 to scan starting from the specified channel before connecting to AP. If the channel of AP is unknown, set it to 0.*/ uint16_t listen_interval; /**< Listen interval for ESP32 station to receive beacon when WIFI_PS_MAX_MODEM is set. Units: AP beacon intervals. Defaults to 3 if set to 0. */ wifi_sort_method_t sort_method; /**< sort the connect AP in the list by rssi or security mode */ - wifi_scan_threshold_t threshold; /**< When scan_method is set, only APs which have an auth mode that is more secure than the selected auth mode and a signal stronger than the minimum RSSI will be used. */ + wifi_scan_threshold_t threshold; /**< When sort_method is set, only APs which have an auth mode that is more secure than the selected auth mode and a signal stronger than the minimum RSSI will be used. */ } wifi_sta_config_t; /** @brief Configuration data for ESP32 AP or STA. diff --git a/docs/en/api-guides/wifi.rst b/docs/en/api-guides/wifi.rst index 209f272231..b6afd63779 100644 --- a/docs/en/api-guides/wifi.rst +++ b/docs/en/api-guides/wifi.rst @@ -1407,7 +1407,7 @@ In maximum power save mode, station wakes up every listen interval to receive be Call ``esp_wifi_set_ps(WIFI_PS_MIN_MODEM)`` to enable Modem-sleep minimum power save mode or ``esp_wifi_set_ps(WIFI_PS_MAX_MODEM)`` to enable Modem-sleep maximum power save mode after calling :cpp:func:`esp_wifi_init`. When station connects to AP, Modem-sleep will start. When station disconnects from AP, Modem-sleep will stop. -Call `esp_wifi_set_ps(WIFI_PS_MIN_MODEM)` to disable modem sleep entirely. This has much higher power consumption, but provides minimum latency for receiving Wi-Fi data in real time. When modem sleep is enabled, received Wi-Fi data can be delayed for as long as the DTIM period (minimum power save mode) or the listen interval (maximum power save mode). +Call ``esp_wifi_set_ps(WIFI_PS_NONE)`` to disable modem sleep entirely. This has much higher power consumption, but provides minimum latency for receiving Wi-Fi data in real time. When modem sleep is enabled, received Wi-Fi data can be delayed for as long as the DTIM period (minimum power save mode) or the listen interval (maximum power save mode). The default Modem-sleep mode is WIFI_PS_MIN_MODEM. @@ -1697,7 +1697,7 @@ ESP32 supports Wi-Fi bandwidth HT20 or HT40, it doesn't support HT20/40 coexist. In station mode, the actual bandwidth is firstly negotiated during the Wi-Fi connection. It is HT40 only if both the station and the connected AP support HT40, otherwise it's HT20. If the bandwidth of connected AP is changes, the actual bandwidth is negotiated again without Wi-Fi disconnecting. -Similarly, in AP mode, the actual bandwidth is negotiated between AP and the stations that connect to the AP. It's HT40 only if the AP and all the stations support HT40, otherwise it's HT40. +Similarly, in AP mode, the actual bandwidth is negotiated between AP and the stations that connect to the AP. It's HT40 if the AP and one of the stations support HT40, otherwise it's HT20. In station/AP coexist mode, the station/AP can configure HT20/40 seperately. If both station and AP are negotiated to HT40, the HT40 channel should be the channel of station because the station always has higher priority than AP in ESP32. E.g. the configured bandwidth of AP is HT40, the configured primary channel is 6 and the configured secondary channel is 10. The station is connected to an router whose primary channel is 6 and secondary channel is 2, then the actual channel of AP is changed to primary 6 and secondary 2 automatically. From 1f0d682406a00216c7cf1e1b961dde22c00d6ff3 Mon Sep 17 00:00:00 2001 From: Prasad Alatkar Date: Mon, 29 Jul 2019 19:00:21 +0800 Subject: [PATCH 379/486] NimBLE: Update submodule to fix bug in delete bond procedure - Fixes bug in `get_nvs_db_attribute` related to getting correct index while deleting bond in NVS. - MR raised on esp-nimble branch: https://gitlab.espressif.cn:6688/espressif/esp-nimble/merge_requests/12 --- components/bt/host/nimble/nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 30480fdb5d..7600a6f603 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 30480fdb5d11547bba8c34647dbfc629c6fdb74c +Subproject commit 7600a6f60308c77fec755a024d51ab2fb7d11553 From 64f81aefaedcf31779f1366bea04cd625b79a95e Mon Sep 17 00:00:00 2001 From: kooho <2229179028@qq.com> Date: Thu, 18 Jul 2019 11:34:49 +0800 Subject: [PATCH 380/486] bugfix(GPIO): Fixed the bug that GPIO enables interrupts on one core, but registers interrupt service routines on another core closes https://github.com/espressif/esp-idf/issues/2808 closes https://github.com/espressif/esp-idf/issues/2845 --- components/driver/gpio.c | 56 +++++++++++-- components/driver/test/test_gpio.c | 125 +++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+), 8 deletions(-) diff --git a/components/driver/gpio.c b/components/driver/gpio.c index 2cb6512c52..f9ae07c370 100644 --- a/components/driver/gpio.c +++ b/components/driver/gpio.c @@ -20,21 +20,34 @@ #include "soc/soc.h" #include "soc/gpio_periph.h" #include "esp_log.h" +#include "esp_ipc.h" -static const char* GPIO_TAG = "gpio"; #define GPIO_CHECK(a, str, ret_val) \ if (!(a)) { \ ESP_LOGE(GPIO_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \ return (ret_val); \ } +#define GPIO_ISR_CORE_ID_UNINIT (3) typedef struct { gpio_isr_t fn; /*!< isr function */ void* args; /*!< isr function args */ } gpio_isr_func_t; +// Used by the IPC call to register the interrupt service routine. +typedef struct { + int source; /*!< ISR source */ + int intr_alloc_flags; /*!< ISR alloc flag */ + void (*fn)(void*); /*!< ISR function */ + void *arg; /*!< ISR function args*/ + void *handle; /*!< ISR handle */ + esp_err_t ret; +} gpio_isr_alloc_t; + +static const char* GPIO_TAG = "gpio"; static gpio_isr_func_t* gpio_isr_func = NULL; static gpio_isr_handle_t gpio_isr_handle; +static uint32_t isr_core_id = GPIO_ISR_CORE_ID_UNINIT; static portMUX_TYPE gpio_spinlock = portMUX_INITIALIZER_UNLOCKED; esp_err_t gpio_pullup_en(gpio_num_t gpio_num) @@ -100,7 +113,6 @@ static void gpio_intr_status_clr(gpio_num_t gpio_num) static esp_err_t gpio_intr_enable_on_core (gpio_num_t gpio_num, uint32_t core_id) { - GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); gpio_intr_status_clr(gpio_num); if (core_id == 0) { GPIO.pin[gpio_num].int_ena = GPIO_PRO_CPU_INTR_ENA; //enable pro cpu intr @@ -112,7 +124,13 @@ static esp_err_t gpio_intr_enable_on_core (gpio_num_t gpio_num, uint32_t core_id esp_err_t gpio_intr_enable(gpio_num_t gpio_num) { - return gpio_intr_enable_on_core (gpio_num, xPortGetCoreID()); + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + portENTER_CRITICAL(&gpio_spinlock); + if(isr_core_id == GPIO_ISR_CORE_ID_UNINIT) { + isr_core_id = xPortGetCoreID(); + } + portEXIT_CRITICAL(&gpio_spinlock); + return gpio_intr_enable_on_core (gpio_num, isr_core_id); } esp_err_t gpio_intr_disable(gpio_num_t gpio_num) @@ -342,16 +360,15 @@ static void IRAM_ATTR gpio_intr_service(void* arg) if (gpio_isr_func == NULL) { return; } - //read status to get interrupt status for GPIO0-31 - const uint32_t gpio_intr_status = GPIO.status; + const uint32_t gpio_intr_status = (isr_core_id == 0) ? GPIO.pcpu_int : GPIO.acpu_int; if (gpio_intr_status) { gpio_isr_loop(gpio_intr_status, 0); GPIO.status_w1tc = gpio_intr_status; } //read status1 to get interrupt status for GPIO32-39 - const uint32_t gpio_intr_status_h = GPIO.status1.intr_st; + const uint32_t gpio_intr_status_h = (isr_core_id == 0) ? GPIO.pcpu_int1.intr : GPIO.acpu_int1.intr; if (gpio_intr_status_h) { gpio_isr_loop(gpio_intr_status_h, 32); GPIO.status1_w1tc.intr_st = gpio_intr_status_h; @@ -393,12 +410,12 @@ esp_err_t gpio_install_isr_service(int intr_alloc_flags) esp_err_t ret; portENTER_CRITICAL(&gpio_spinlock); gpio_isr_func = (gpio_isr_func_t*) calloc(GPIO_NUM_MAX, sizeof(gpio_isr_func_t)); + portEXIT_CRITICAL(&gpio_spinlock); if (gpio_isr_func == NULL) { ret = ESP_ERR_NO_MEM; } else { ret = gpio_isr_register(gpio_intr_service, NULL, intr_alloc_flags, &gpio_isr_handle); } - portEXIT_CRITICAL(&gpio_spinlock); return ret; } @@ -411,14 +428,37 @@ void gpio_uninstall_isr_service() esp_intr_free(gpio_isr_handle); free(gpio_isr_func); gpio_isr_func = NULL; + isr_core_id = GPIO_ISR_CORE_ID_UNINIT; portEXIT_CRITICAL(&gpio_spinlock); return; } +static void gpio_isr_register_on_core_static(void *param) +{ + gpio_isr_alloc_t *p = (gpio_isr_alloc_t *)param; + //We need to check the return value. + p->ret = esp_intr_alloc(p->source, p->intr_alloc_flags, p->fn, p->arg, p->handle); +} + esp_err_t gpio_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags, gpio_isr_handle_t *handle) { GPIO_CHECK(fn, "GPIO ISR null", ESP_ERR_INVALID_ARG); - return esp_intr_alloc(ETS_GPIO_INTR_SOURCE, intr_alloc_flags, fn, arg, handle); + gpio_isr_alloc_t p; + p.source = ETS_GPIO_INTR_SOURCE; + p.intr_alloc_flags = intr_alloc_flags; + p.fn = fn; + p.arg = arg; + p.handle = handle; + portENTER_CRITICAL(&gpio_spinlock); + if(isr_core_id == GPIO_ISR_CORE_ID_UNINIT) { + isr_core_id = xPortGetCoreID(); + } + portEXIT_CRITICAL(&gpio_spinlock); + esp_err_t ret = esp_ipc_call_blocking(isr_core_id, gpio_isr_register_on_core_static, (void *)&p); + if(ret != ESP_OK || p.ret != ESP_OK) { + return ESP_ERR_NOT_FOUND; + } + return ESP_OK; } esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type) diff --git a/components/driver/test/test_gpio.c b/components/driver/test/test_gpio.c index ee07484bea..c40815683c 100644 --- a/components/driver/test/test_gpio.c +++ b/components/driver/test/test_gpio.c @@ -616,3 +616,128 @@ TEST_CASE("GPIO drive capability test", "[gpio][ignore]") drive_capability_set_get(GPIO_OUTPUT_IO, GPIO_DRIVE_CAP_3); prompt_to_continue("If this test finishes"); } + +#if !CONFIG_FREERTOS_UNICORE +void gpio_enable_task(void *param) +{ + int gpio_num = (int)param; + TEST_ESP_OK(gpio_intr_enable(gpio_num)); + vTaskDelete(NULL); +} + +/** Test the GPIO Interrupt Enable API with dual core enabled. The GPIO ISR service routine is registered on one core. + * When the GPIO interrupt on another core is enabled, the GPIO interrupt will be lost. + * First on the core 0, Do the following steps: + * 1. Configure the GPIO18 input_output mode, and enable the rising edge interrupt mode. + * 2. Trigger the GPIO18 interrupt and check if the interrupt responds correctly. + * 3. Disable the GPIO18 interrupt + * Then on the core 1, Do the following steps: + * 1. Enable the GPIO18 interrupt again. + * 2. Trigger the GPIO18 interrupt and check if the interrupt responds correctly. + * + */ +TEST_CASE("GPIO Enable/Disable interrupt on multiple cores", "[gpio][ignore]") +{ + const int test_io18 = GPIO_NUM_18; + gpio_config_t io_conf; + io_conf.intr_type = GPIO_INTR_NEGEDGE; + io_conf.mode = GPIO_MODE_INPUT_OUTPUT; + io_conf.pin_bit_mask = (1ULL << test_io18); + io_conf.pull_down_en = 0; + io_conf.pull_up_en = 1; + TEST_ESP_OK(gpio_config(&io_conf)); + TEST_ESP_OK(gpio_set_level(test_io18, 0)); + TEST_ESP_OK(gpio_install_isr_service(0)); + TEST_ESP_OK(gpio_isr_handler_add(test_io18, gpio_isr_edge_handler, (void*) test_io18)); + vTaskDelay(1000 / portTICK_RATE_MS); + TEST_ESP_OK(gpio_set_level(test_io18, 1)); + vTaskDelay(100 / portTICK_RATE_MS); + TEST_ESP_OK(gpio_set_level(test_io18, 0)); + vTaskDelay(100 / portTICK_RATE_MS); + TEST_ESP_OK(gpio_intr_disable(test_io18)); + TEST_ASSERT(edge_intr_times == 1); + xTaskCreatePinnedToCore(gpio_enable_task, "gpio_enable_task", 1024*4, (void*)test_io18, 8, NULL, (xPortGetCoreID() == 0)); + vTaskDelay(1000 / portTICK_RATE_MS); + TEST_ESP_OK(gpio_set_level(test_io18, 1)); + vTaskDelay(100 / portTICK_RATE_MS); + TEST_ESP_OK(gpio_set_level(test_io18, 0)); + vTaskDelay(100 / portTICK_RATE_MS); + TEST_ESP_OK(gpio_intr_disable(test_io18)); + TEST_ESP_OK(gpio_isr_handler_remove(test_io18)); + gpio_uninstall_isr_service(); + TEST_ASSERT(edge_intr_times == 2); +} +#endif + +typedef struct { + int gpio_num; + int isr_cnt; +} gpio_isr_param_t; + +static void gpio_isr_handler(void* arg) +{ + gpio_isr_param_t *param = (gpio_isr_param_t *)arg; + ets_printf("GPIO[%d] intr, val: %d\n", param->gpio_num, gpio_get_level(param->gpio_num)); + param->isr_cnt++; +} + +/** The previous GPIO interrupt service routine polls the interrupt raw status register to find the GPIO that triggered the interrupt. + * But this will incorrectly handle the interrupt disabled GPIOs, because the raw interrupt status register can still be set when + * the trigger signal arrives, even if the interrupt is disabled. + * First on the core 0: + * 1. Configure the GPIO18 and GPIO19 input_output mode. + * 2. Enable GPIO18 dual edge triggered interrupt, enable GPIO19 falling edge triggered interrupt. + * 3. Trigger GPIO18 interrupt, than disable the GPIO8 interrupt, and than trigger GPIO18 again(This time will not respond to the interrupt). + * 4. Trigger GPIO19 interrupt. + * If the bug is not fixed, you will see, in the step 4, the interrupt of GPIO18 will also respond. + */ +TEST_CASE("GPIO ISR service test", "[gpio][ignore]") +{ + const int test_io18 = GPIO_NUM_18; + const int test_io19 = GPIO_NUM_19; + static gpio_isr_param_t io18_param = { + .gpio_num = GPIO_NUM_18, + .isr_cnt = 0, + }; + static gpio_isr_param_t io19_param = { + .gpio_num = GPIO_NUM_19, + .isr_cnt = 0, + }; + gpio_config_t io_conf; + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.mode = GPIO_MODE_INPUT_OUTPUT; + io_conf.pin_bit_mask = (1ULL << test_io18) | (1ULL << test_io19); + io_conf.pull_down_en = 0; + io_conf.pull_up_en = 1; + TEST_ESP_OK(gpio_config(&io_conf)); + TEST_ESP_OK(gpio_set_level(test_io18, 0)); + TEST_ESP_OK(gpio_set_level(test_io19, 0)); + TEST_ESP_OK(gpio_install_isr_service(0)); + TEST_ESP_OK(gpio_set_intr_type(test_io18, GPIO_INTR_ANYEDGE)); + TEST_ESP_OK(gpio_set_intr_type(test_io19, GPIO_INTR_NEGEDGE)); + TEST_ESP_OK(gpio_isr_handler_add(test_io18, gpio_isr_handler, (void*)&io18_param)); + TEST_ESP_OK(gpio_isr_handler_add(test_io19, gpio_isr_handler, (void*)&io19_param)); + printf("Triggering the interrupt of GPIO18\n"); + vTaskDelay(1000 / portTICK_RATE_MS); + //Rising edge + TEST_ESP_OK(gpio_set_level(test_io18, 1)); + printf("Disable the interrupt of GPIO18"); + vTaskDelay(100 / portTICK_RATE_MS); + //Disable GPIO18 interrupt, GPIO18 will not respond to the next falling edge interrupt. + TEST_ESP_OK(gpio_intr_disable(test_io18)); + vTaskDelay(100 / portTICK_RATE_MS); + //Falling edge + TEST_ESP_OK(gpio_set_level(test_io18, 0)); + + printf("Triggering the interrupt of GPIO19\n"); + vTaskDelay(100 / portTICK_RATE_MS); + TEST_ESP_OK(gpio_set_level(test_io19, 1)); + vTaskDelay(100 / portTICK_RATE_MS); + //Falling edge + TEST_ESP_OK(gpio_set_level(test_io19, 0)); + vTaskDelay(100 / portTICK_RATE_MS); + TEST_ESP_OK(gpio_isr_handler_remove(test_io18)); + TEST_ESP_OK(gpio_isr_handler_remove(test_io19)); + gpio_uninstall_isr_service(); + TEST_ASSERT((io18_param.isr_cnt == 1) && (io19_param.isr_cnt == 1)); +} \ No newline at end of file From 15e0a327865ddd732f2ec4dd83a9de2781916a2a Mon Sep 17 00:00:00 2001 From: Mahavir Jain Date: Tue, 30 Jul 2019 16:49:53 +0530 Subject: [PATCH 381/486] lwip: remove duplicate (and stale) changelog and version files --- components/lwip/CHANGELOG | 4044 ------------------------------------- components/lwip/VERSION | 1 - 2 files changed, 4045 deletions(-) delete mode 100644 components/lwip/CHANGELOG delete mode 100644 components/lwip/VERSION diff --git a/components/lwip/CHANGELOG b/components/lwip/CHANGELOG deleted file mode 100644 index 21a85c94c3..0000000000 --- a/components/lwip/CHANGELOG +++ /dev/null @@ -1,4044 +0,0 @@ -HISTORY - -(git master) - - * [Enter new changes just after this line - do not remove this line] - - ++ New features: - - 2016-02-22: Ivan Delamer: - * Initial 6LoWPAN support - - 2015-12-26: Martin Hentschel and Dirk Ziegelmeier - * Rewrite SNMP agent - - 2015-11-12: Dirk Ziegelmeier - * Decouple SNMP stack from lwIP core and move stack to apps/ directory. - Breaking change: Users have to call snmp_init() now! - - 2015-11-12: Dirk Ziegelmeier - * Implement possibility to declare private memory pools. This is useful to - decouple some apps from the core (SNMP stack) or make contrib app useage - simpler (httpserver_raw) - - 2015-10-09: Simon Goldschmidt - * started to move "private" header files containing implementation details to - "lwip/priv/" include directory to seperate the API from the implementation. - - 2015-10-07: Simon Goldschmidt - * added sntp client as first "supported" application layer protocol implementation - added 'apps' folder - - 2015-09-30: Dirk Ziegelmeier - * snmp_structs.h, mib_structs.c, mib2.c: snmp: fixed ugly inheritance - implementation by aggregating the "base class" (struct mib_node) in all - derived node classes to get more type-safe code - - 2015-09-23: Simon Goldschmidt - * netif.h/.c, nd6.c: task #13729: Convert netif addresses (IPv4 & IPv6) to - ip_addr_t (so they can be used without conversion/temporary storage) - - 2015-09-08: Dirk Ziegelmeier - * snmp: Separate mib2 counter/table callbacks from snmp agent. This both cleans - up the code and should allow integration of a 3rd party agent/mib2. Simple - counters are kept in MIB2_STATS, tree/table change function prototypes moved to - snmp_mib2.h. - - 2015-09-03: Simon Goldschmidt - * opt.h, dns.h/.c: DNS/IPv6: added support for AAAA records - - 2015-09-01: Simon Goldschmidt - * task #12178: hardware checksum capabilities can be configured per netif - (use NETIF_SET_CHECKSUM_CTRL() in your netif's init function) - - 2015-08-30: Simon Goldschmidt - * PBUF_REF with "custom" pbufs is now supported for RX pbufs (see pcapif in - contrib for an example, LWIP_SUPPORT_CUSTOM_PBUF is required) - - 2015-08-30: Simon Goldschmidt - * support IPv4 source based routing: define LWIP_HOOK_IP4_ROUTE_SRC to point - to a routing function - - 2015-08-05: Simon Goldschmidt - * many files: allow multicast socket options IP_MULTICAST_TTL, IP_MULTICAST_IF - and IP_MULTICAST_LOOP to be used without IGMP - - 2015-04-24: Simon Goldschmidt - * dhcp.h/c, autoip.h/.c: added functions dhcp/autoip_supplied_address() to - check for the source of address assignment (replacement for NETIF_FLAG_DHCP) - - 2015-04-10: Simon Goldschmidt - * many files: task #13480: added LWIP_IPV4 define - IPv4 can be disabled, - leaving an IPv6-only stack - - 2015-04-09: Simon Goldschmidt - * nearly all files: task #12722 (improve IPv4/v6 address handling): renamed - ip_addr_t to ip4_addr_t, renamed ipX_addr_t to ip_addr_t and added IP - version; ip_addr_t is used for all generic IP addresses for the API, - ip(4/6)_addr_t are only used internally or when initializing netifs or when - calling version-related functions - - 2015-03-24: Simon Goldschmidt - * opt.h, ip4_addr.h, ip4.c, ip6.c: loopif is not required for loopback traffic - any more but passed through any netif (ENABLE_LOOPBACK has to be enabled) - - 2015-03-23: Simon Goldschmidt - * opt.h, etharp.c: with ETHARP_TABLE_MATCH_NETIF== 1, duplicate (Auto)-IP - addresses on multiple netifs should now be working correctly (if correctly - addressed by routing, that is) - - 2015-03-23: Simon Goldschmidt - * etharp.c: Stable etharp entries that are about to expire are now refreshed - using unicast to prevent unnecessary broadcast. Only if no answer is received - after 15 seconds, broadcast is used. - - 2015-03-06: Philip Gladstone - * netif.h/.c: patch #8359 (Provide utility function to add an IPv6 address to - an interface) - - 2015-03-05: Simon Goldschmidt - * netif.c, ip4.c, dhcp.c, autoip.c: fixed bug #37068 (netif up/down handling - is unclear): correclty separated administrative status of a netif (up/down) - from 'valid address' status - ATTENTION: netif_set_up() now always has to be called, even when dhcp/autoip - is used! - - 2015-02-26: patch by TabascoEye - * netif.c, udp.h/.c: fixed bug #40753 (re-bind UDP pcbs on change of IP address) - - 2015-02-22: chrysn, Simon Goldschmidt - * *.*: Changed nearly all functions taking 'ip(X)_addr_t' pointer to take - const pointers (changed user callbacks: raw_recv_fn, udp_recv_fn; changed - port callbacks: netif_output_fn, netif_igmp_mac_filter_fn) - - 2015-02-19: Ivan Delamer - * netif.h, dhcp.c: Removed unused netif flag for DHCP. The preferred way to evaluate - if DHCP is active is through netif->dhcp field. - - 2015-02-19: Ivan Delamer - * netif.h, slipif.c, ppp.c: Removed unused netif flag for point to point connections - - 2015-02-18: Simon Goldschmidt - * api_lib.c: fixed bug #37958 "netconn API doesn't handle correctly - connections half-closed by peer" - - 2015-02-18: Simon Goldschmidt - * tcp.c: tcp_alloc() prefers killing CLOSING/LAST_ACK over active connections - (see bug #39565) - - 2015-02-16: Claudius Zingerli, Sergio Caprile - * opt.h, dhcp.h/.c: patch #8361 "Add support for NTP option in DHCP" - - 2015-02-14: Simon Goldschmidt - * opt.h, snmp*: added support for write-access community and dedicated - community for sending traps - - 2015-02-13: Simon Goldschmidt - * opt.h, memp.c: added hook LWIP_HOOK_MEMP_AVAILABLE() to get informed when - a memp pool was empty and an item is now available - - 2015-02-13: Simon Goldschmidt - * opt.h, pbuf.h/.c, etharp.c: Added the option PBUF_LINK_ENCAPSULATION_HLEN to - allocate additional header space for TX on netifs requiring additional headers - - 2015-02-12: chrysn - * timers.h/.c: introduce sys_timeouts_sleeptime (returns the time left before - the next timeout is due, for NO_SYS==1) - - 2015-02-11: Nick van Ijzendoorn - * opt.h, sockets.h/c: patch #7702 "Include ability to increase the socket number - with defined offset" - - 2015-02-11: Frederick Baksik - * opt.h, def.h, others: patch #8423 "arch/perf.h" should be made an optional item - - 2015-02-11: Simon Goldschmidt - * api_msg.c, opt.h: started to implement fullduplex sockets/netconns - (note that this is highly unstable yet!) - - 2015-01-17: Simon Goldschmidt - * api: allow enabling socket API without (public) netconn API - netconn API is - still used by sockets, but keeping it private (static) should allow better - compiler optimizations - - 2015-01-16: Simon Goldschmidt - * tcp_in.c: fixed bug #20506 "Initial congestion window is very small" again - by implementing the calculation formula from RFC3390 - - 2014-12-10: Simon Goldschmidt - * api: added option LWIP_NETCONN_SEM_PER_THREAD to use a semaphore per thread - instead of using one per netconn and per select call - - 2014-12-08: Simon Goldschmidt - * ip6.h: fixed bug #43778: IPv6 header version not set on 16-bit platform - (macro IP6H_VTCFL_SET()) - - 2014-12-08: Simon Goldschmidt - * icmp.c, ip4.c, pbuf.c, udp.c, pbuf.h: task #11472 Support PBUF_REF for RX - (IPv6 and IPv4/v6 reassembly might not work yet) - - 2014-11-06: Simon Goldschmidt - * sockets.c/.h, init.c: lwip_socket_init() is not needed any more - -> compatibility define - - 2014-09-16: Simon Goldschmidt - * dns.c, opt.h: reduced ram usage by parsing DNS responses in place - - 2014-09-16: Simon Goldschmidt - * pbuf.h/.c: added pbuf_take_at() and pbuf_put_at() - - 2014-09-15: Simon Goldschmidt - * dns.c: added source port randomization to make the DNS client more robust - (see bug #43144) - - 2013-09-02: Simon Goldschmidt - * arch.h and many other files: added optional macros PACK_STRUCT_FLD_8() and - PACK_STRUCT_FLD_S() to prevent gcc 4 from warning about struct members that - do not need packing - - 2013-08-19: Simon Goldschmidt - * netif.h: bug #42998: made NETIF_MAX_HWADDR_LEN overridable for some special - networks - - 2013-03-17: Simon Goldschmidt (patch by Ghobad Emadi) - * opt.h, etharp.c: Added LWIP_HOOK_ETHARP_GET_GW to implement IPv4 routing with - multiple gateways - - 2013-04-20: Fatih Asici - * opt.h, etharp.h/.c: patch #7993: Added support for transmitting packets - with VLAN headers via hook function LWIP_HOOK_VLAN_SET and to check them - via hook function LWIP_HOOK_VLAN_CHECK - - 2014-02-20: Simon Goldschmidt (based on patch by Artem Pisarenko) - * patch #7885: modification of api modules to support FreeRTOS-MPU - (don't pass stack-pointers to other threads) - - 2014-02-05: Simon Goldschmidt (patch by "xtian" and "alex_ab") - * patch #6537/#7858: TCP window scaling support - - 2014-01-17: Jiri Engelthaler - * icmp, icmp6, opt.h: patch #8027: Completed HW checksuming for IPv4 and - IPv6 ICMP's - - 2012-08-22: Sylvain Rochet - * New PPP stack for lwIP, developed in ppp-new branch. - Based from pppd 2.4.5, released 2009-11-17, with huge changes to match - code size and memory requirements for embedded devices, including: - - Gluing together the previous low-level PPP code in lwIP to pppd 2.4.5, which - is more or less what pppd sys-* files are, so that we get something working - using the unix port. - - Merged some patchs from lwIP Git repository which add interesting features - or fix bugs. - - Merged some patchs from Debian pppd package which add interesting features - or fix bugs. - - Ported PPP timeout handling to the lwIP timers system - - Disabled all the PPP code using filesystem access, replaced in necessary cases - to configuration variables. - - Disabled all the PPP code forking processes. - - Removed IPX support, lwIP does not support IPX. - - Ported and improved random module from the previous PPP port. - - Removed samba TDB (file-driven database) usage, because it needs a filesystem. - - MS-CHAP required a DES implementation, we added the latest PolarSSL DES - implementation which is under a BSD-ish license. - - Also switched to PolarSSL MD4,MD5,SHA1 implementations, which are meant to be - used in embedded devices with reduced memory footprint. - - Removed PPP configuration file parsing support. - - Added macro definition EAP_SUPPORT to make EAP support optional. - - Added macro definition CHAP_SUPPORT to make CHAP support optional. - - Added macro definition MSCHAP_SUPPORT to make MSCHAP support optional. - - Added macro definition PAP_SUPPORT to make PAP support optional. - - Cleared all Linux syscall calls. - - Disabled demand support using a macro, so that it can be ported later. - - Disabled ECP support using a macro, so that it can be ported later. - - Disabled CCP support using a macro, so that it can be ported later. - - Disabled CBCP support using a macro, so that it can be ported later. - - Disabled LQR support using a macro, so that it can be ported later. - - Print packet debug feature optional, through PRINTPKT_SUPPORT - - Removed POSIX signal usage. - - Fully ported PPPoS code from the previous port. - - Fully ported PPPoE code from the previous port. - - Fully ported VJ compression protocol code from the previous port. - - Removed all malloc()/free() use from PPP, replaced by stack usage or PBUF. - - Disabled PPP server support using a macro, so that it can be ported later. - - Switched all PPP debug to lwIP debug system. - - Created PPP Control Block (PPP PCB), removed PPP unit integer everywhere, - removed all global variables everywhere, did everything necessary for - the PPP stack to support more than one PPP session (pppd only support - one session per process). - - Removed the statically allocated output buffer, now using PBUF. - - Improved structure size of all PPP modules, deep analyze of code to reduce - variables size to the bare minimum. Switched all boolean type (char type in - most architecture) to compiler generated bitfields. - - Added PPP IPv6 support, glued lwIP IPv6 support to PPP. - - Now using a persistent netif interface which can then be used in lwIP - functions requiring a netif. - - Now initializing PPP in lwip_init() function. - - Reworked completely the PPP state machine, so that we don't end up in - anymore in inconsistent state, especially with PPPoE. - - Improved the way we handle PPP reconnection after disconnect, cleaning - everything required so that we start the PPP connection again from a - clean state. - - Added PPP holdoff support, allow the lwIP user to wait a little bit before - reconnecting, prevents connection flood, especially when using PPPoL2TP. - - Added PPPoL2TP LAC support (a.k.a. UDP tunnels), adding a VPN client - feature to lwIP, L2TP being a widely used tunnel protocol. - - Switched all used PPP types to lwIP types (u8t, u16t, u32t, ...) - - Added PPP API "sequential" thread-safe API, based from NETIFAPI. - - 2011-07-21: Simon Goldschmidt - * sockets.c, opt.h: (bug #30185): added LWIP_FIONREAD_LINUXMODE that makes - ioctl/FIONREAD return the size of the next pending datagram. - - 2011-05-25: Simon Goldschmidt - * again nearly the whole stack, renamed ip.c to ip4.c, ip_addr.c to ip4_addr.c, - combined ipv4/ipv6 inet_chksum.c, added ip.h, ip_addr.h: Combined IPv4 - and IPv6 code where possible, added defines to access IPv4/IPv6 in non-IP - code so that the code is more readable. - - 2011-05-17: Patch by Ivan Delamer (only checked in by Simon Goldschmidt) - * nearly the whole stack: Finally, we got decent IPv6 support, big thanks to - Ivan! (this is work in progress: we're just post release anyway :-) - - - ++ Bugfixes: - - 2016-03-05: Simon Goldschmidt - * err.h/.c, sockets.c: ERR_IF is not necessarily a fatal error - - 2015-11-19: fix by Kerem Hadimli - * sockets.c: fixed bug #46471: lwip_accept() leaks socket descriptors if new - netconn was already closed because of peer behavior - - 2015-11-12: fix by Valery Ushakov - * tcp_in.c: fixed bug #46365 tcp_accept_null() should call tcp_abort() - - 2015-10-02: Dirk Ziegelmeier/Simon Goldschmidt - * snmp: cleaned up snmp structs API (fixed race conditions from bug #46089, - reduce ram/rom usage of tables): incompatible change for private MIBs - - 2015-09-30: Simon Goldschmidt - * ip4_addr.c: fixed bug #46072: ip4addr_aton() does not check the number range - of all address parts - - 2015-08-28: Simon Goldschmidt - * tcp.c, tcp_in.c: fixed bug #44023: TCP ssthresh value is unclear: ssthresh - is set to the full send window for active open, too, and is updated once - after SYN to ensure the correct send window is used - - 2015-08-28: Simon Goldschmidt - * tcp: fixed bug #45559: Window scaling casts u32_t to u16_t without checks - - 2015-08-26: Simon Goldschmidt - * ip6_frag.h/.c: fixed bug bug #41009: IPv6 reassembly broken on 64-bit platforms: - define IPV6_FRAG_COPYHEADER==1 on these platforms to copy the IPv6 header - instead of referencing it, which gives more room for struct ip6_reass_helper - - 2015-08-25: Simon Goldschmidt - * sockets.c: fixed bug #45827: recvfrom: TCP window is updated with MSG_PEEK - - 2015-08-20: Manoj Kumar - * snmp_msg.h, msg_in.c: fixed bug #43790: Sending octet string of Length >255 - from SNMP agent - - 2015-08-19: Jens Nielsen - * icmp.c, ip4.c, tcp_in.c, udp.c, raw.c: fixed bug #45120: Broadcast & multiple - interfaces handling - - 2015-08-19: Simon Goldschmidt (patch by "Sandra") - * dns.c: fixed bug #45004: dns response without answer might be discarded - - 2015-08-18: Chrysn - * timers.c: patch #8704 fix sys_timeouts_sleeptime function - - 2015-07-01: Erik Ekman - * puf.c: fixed bug #45454 (pbuf_take_at() skips write and returns OK if offset - is at start of pbuf in chain) - - 2015-05-19: Simon Goldschmidt - * dhcp.h/.c: fixed bugs #45140 and #45141 (dhcp was not stopped correctly after - fixing bug #38204) - - 2015-03-21: Simon Goldschmidt (patch by Homyak) - * tcp_in.c: fixed bug #44766 (LWIP_WND_SCALE: tcphdr->wnd was not scaled in - two places) - - 2015-03-21: Simon Goldschmidt - * tcp_impl.h, tcp.c, tcp_in.c: fixed bug #41318 (Bad memory ref in tcp_input() - after tcp_close()) - - 2015-03-21: Simon Goldschmidt - * tcp_in.c: fixed bug #38468 (tcp_sent() not called on half-open connection for - data ACKed with the same ack as FIN) - - 2015-03-21: Simon Goldschmidt (patch by Christoffer Lind) - * dhcp.h/.c: fixed bug #38204 (DHCP lease time not handled correctly) - - 2015-03-20: Simon Goldschmidt - * dhcp.c: fixed bug #38714 (Missing option and client address in DHCPRELEASE message) - - 2015-03-19: Simon Goldschmidt - * api.h, tcpip.h, api_lib.c, api_msg.c: fixed race conditions in assigning - netconn->last_err (fixed bugs #38121 and #37676) - - 2015-03-09: Simon Goldschmidt - * ip4.c: fixed the IPv4 part of bug #43904 (ip_route() must detect linkup status) - - 2015-03-04: Simon Goldschmidt - * nd6.c: fixed bug #43784 (a host should send at least one Router Solicitation) - - 2015-03-04: Valery Ushakov - * ip6.c: fixed bug #41094 (Byte-order bug in IPv6 fragmentation header test) - - 2015-03-04: Zach Smith - * nd6.c: fixed bug #38153 (nd6_input() byte order issues) - - 2015-02-26: Simon Goldschmidt - * netif.c, tcp.h/.c: fixed bug #44378 (TCP connections are not aborted on netif - remove) - - 2015-02-25: Simon Goldschmidt - * ip4.c, etharp.c: fixed bug #40177 (System hangs when dealing with corrupted - packets), implemented task #12357 (Ensure that malicious packets don't - assert-fail): improved some pbuf_header calls to not assert-fail. - - 2015-02-25: patch by Joel Cunningham - * udp.h/.c, sockets.c: fixed bug #43028 (IP_MULTICAST_TTL affects unicast - datagrams) - - 2015-02-25: patch by Greg Renda - * ip4_frag.c: fixed bug #38210 (ip reassembly while remove oldest datagram) - - 2015-02-25: Simon Goldschmidt - * sockets.c: fixed bug #38165 (socket with mulicast): ensure igmp membership - are dropped when socket (not netconn!) is closed. - - 2015-02-25: Simon Goldschmidt - * ip4.h/.c, udp.c: fixed bug #38061 (wrong multicast routing in IPv4) by - adding an optional default netif for multicast routing - - 2015-02-25: Simon Goldschmidt - * netconn API: fixed that netconn_connect still used message passing for - LWIP_TCPIP_CORE_LOCKING==1 - - 2015-02-22: patch by Jens Nielsen - * icmp.c: fixed bug #38803 (Source address in broadcast ping reply) - - 2015-02-22: Simon Goldschmidt - * udp.h, sockets.c: added proper accessor functions for pcb->multicast_ip - (previously used by get/setsockopt only) - - 2015-02-18: Simon Goldschmidt - * sockets.c: Fixed select not reporting received FIN as 'readable' in certain - rare cases (bug #43779: select(), close(), and TCP retransmission error) - - 2015-02-17: Simon Goldschmidt - * err.h, sockets.c, api_msg.c: fixed bug #38853 "connect() use a wrong errno": - return ERR_ALREADY/EALRADY during connect, ERR_ISCONN/EISCONN when already - connected - - 2015-02-17: Simon Goldschmidt - * tcp_impl.h, tcp_out.c, tcp.c, api_msg.c: fixed bug #37614 "Errors from - ipX_output are not processed". Now tcp_output(_segment) checks for the return - value of ipX_output and does not try to send more on error. A netif driver - can call tcp_txnow() (from tcpip_thread!) to try to send again if TX buffers - are available again. - - 2015-02-14: patches by Freddie Chopin - * snmp*: made community writable, fixed some const pointers - - 2015-02-13: Simon Goldschmidt - * msg_in.c: fixed bug #22070 "MIB_OBJECT_WRITE_ONLY not implemented in SNMP" - - 2015-02-12: Simon Goldschmidt - * ip.h, ip4.c, ip6.c: fixed bug #36403 "ip4_input() and ip6_input() always pass - inp to higher layers": now the accepting netif is passed up, but the input - netif is available through ip_current_input_netif() if required. - - 2015-02-11: patch by hichard - * tcpip.c: fixed bug #43094 "The function tcpip_input() forget to handle IPv6" - - 2015-02-10: Simon Goldschmidt - * netconn API: fixed that netconn_close/netconn_delete still used message passing - for LWIP_TCPIP_CORE_LOCKING==1 - - 2015-02-10: Simon Goldschmidt - * netconn/socket api: fixed bug #44225 "closing TCP socket should time out - eventually", implemented task #6930 "Implement SO_LINGER": closing TCP sockets - times out after 20 seconds or after the configured SND_TIMEOUT or depending - on the linger settings. - - 2015-01-27: Simon Goldschmidt - * api_msg.c: fixed that SHUT_RD followed by SHUT_WR was different to SHUT_RDWR, - fixed return value of lwip_netconn_do_close on unconnected netconns - - 2015-01-17: Simon Goldschmidt - * sockets.c: fixed bug #43361 select() crashes with stale FDs - - 2015-01-17: Simon Goldschmidt - * sockets.c/.h, memp_std.h: fixed bug #40788 "lwip_setsockopt_internal() crashes" - by rewriting set/getsockopt functions to combine checks with the actual code - and add more NULL checks; this also fixes that CORE_LOCKING used message - passing for set/getsockopt. - - 2014-12-19: Simon Goldschmidt - * opt.h, dhcp.h/.c: prevent dhcp from starting when netif link is down (only - when LWIP_DHCP_CHECK_LINK_UP==1, which is disabled by default for - compatibility reasons) - - 2014-12-17: Simon Goldschmidt - * tcp_out.c: fixed bug #43840 Checksum error for TCP_CHECKSUM_ON_COPY==1 for - no-copy data with odd length - - 2014-12-10: Simon Goldschmidt - * sockets.c, tcp.c, others: fixed bug #43797 set/getsockopt: SO_SNDTIMEO/SO_RCVTIMEO - take int as option but should take timeval (LWIP_SO_SNDRCVTIMEO_STANDARD==0 can - be used to revert to the old 'winsock' style behaviour) - Fixed implementation of SO_ACCEPTCONN to just look at the pcb state - - 2014-12-09: Simon Goldschmidt - * ip4.c: fixed bug #43596 IGMP queries from 0.0.0.0 are discarded - - 2014-10-21: Simon Goldschmidt (patch by Joel Cunningham and Albert Huitsing) - * sockts.c: fixed bugs #41495 Possible threading issue in select() and #43278 - event_callback() handle context switch when calling sys_sem_signal() - - 2014-10-21: Simon Goldschmidt - * api_msg.c: fixed bug #38219 Assert on TCP netconn_write with sndtimeout set - - 2014-09-16: Kevin Cernekee - * dns.c: patch #8480 Fix handling of dns_seqno wraparound - - 2014-09-16: Simon Goldschmidt - * tcp_out.c: fixed bug #43192 tcp_enqueue_flags() should not check TCP_SND_QUEUELEN - when sending FIN - - 2014-09-03: Simon Goldschmidt - * msg_in.c: fixed bug #39355 SNMP Memory Leak in case of error - - 2014-09-02: Simon Goldschmidt - * err.h/.c, sockets.c, api_msg.c: fixed bug #43110 call getpeername() before - listen() will cause a error - - 2014-09-02: Simon Goldschmidt - * sockets.c: fixed bug #42117 lwip_fcntl does not set errno - - 2014-09-02: Simon Goldschmidt - * tcp.c: fixed bug #42299 tcp_abort() leaves freed pcb on tcp_bound_pcbs list - - 2014-08-20: Simon Goldschmidt - * dns.c: fixed bug #42987 lwIP is vulnerable to DNS cache poisoning due to - non-randomized TXIDs - - 2014-06-03: Simon Goldschmidt - * tcp_impl.h, tcp_in.c: fixed bug #37969 SYN packet dropped as short packet in - tcp_input function - - 2014-05-20: Simon Goldschmidt - * tcp_out.c: fixed bug #37184 tcp_write problem for pcbs in the SYN_SENT state - - 2014-05-19: Simon Goldschmidt - * *.h: Fixed bug #35874 reserved identifier violation (removed leading underscores - from header include guards) - - 2014-04-08: Simon Goldschmidt - * tcp.c: Fixed bug #36167 tcp server crash when client closes (maximum window) - - 2014-04-06: Simon Goldschmidt - * tcp_in.c: Fixed bug #36210 lwIP does not elicit an empty ACK when received - unacceptable ACK - - 2014-04-06: Simon Goldschmidt - * dhcp.c, ip4.c/.h, ip6.c/.h, udp.c/.h, ip.h: Fixed bug #41787 DHCP Discovery - is invalid when an IP is set to thet netif. - - 2014-03-14: Simon Goldschmidt - * tcp_out.c: Fixed bug #36153 TCP Cheksum error if LWIP_CHECKSUM_ON_COPY=1 - - 2014-03-11: Simon Goldschmidt (patch by Mason) - * opt.h, sockets.c: fixed bug #35928 BSD sockets functions must set errno for - POSIX-compliance - - 2014-02-27: Simon Goldschmidt - * dhcp.c: fixed bug #40303 DHCP xid renewed when sending a DHCPREQUEST - - 2014-02-27: Simon Goldschmidt - * raw.c: fixed bug #41680 raw socket can not receive IPv6 packet when - IP_SOF_BROADCAST_RECV==1 - - 2014-02-27: Simon Goldschmidt - * api_msg.c, sockets.c: fixed bug #38404 getpeeraddr returns success on - unconnected/listening TCP sockets - - 2014-02-27: Simon Goldschmidt - * sockets.c: fixed bug #41729 Some socket functions return Exyz instead of -1 - - 2014-02-25: Simon Goldschmidt - * ip4.c: fixed bug #39514 ip_route() may return an IPv6-only interface - - 2014-02-25: Simon Goldschmidt, patch by Fatih Asici - * pbuf.c: fixed bug #39356 Wrong increment in pbuf_memfind() - - 2014-02-25: Simon Goldschmidt - * netif.c/.h, udp.c: fixed bug #39225 udp.c uses netif_matches_ip6_addr() incorrectly; - renamed function netif_matches_ip6_addr() to netif_get_ip6_addr_match() - - 2014-02-25: Simon Goldschmidt - * igmp.c: fixed bug #39145 IGMP membership report for 224.0.0.1 - - 2014-02-22: Simon Goldschmidt (patch by Amir Shalem) - * etharp.c, opt.h: fixed bug #34681 Limit ARP queue length by ARP_QUEUE_LEN (=3) - - 2014-02-22: Simon Goldschmidt (patch by Amir Shalem) - * etharp.h/.c: fixed bug #34682 Limit ARP request flood for unresolved entry - - 2014-02-20: Simon Goldschmidt - * tcp_out.c: fixed bug #39683 Assertion "seg->tcphdr not aligned" failed with - MEM_ALIGNMENT = 8 - - 2014-02-20: Simon Goldschmidt - * sockets.c: fixed bug #39882 No function shall set errno to 0 - - 2014-02-20: Simon Goldschmidt - * mib_structs.c: fixed bug #40050 SNMP problem with MIB arrays > 255 - - 2014-02-20: Simon Goldschmidt - * api.h, sockets.c: fixed bug #41499 netconn::recv_avail can overflow - - 2014-01-08: Stathis Voukelatos - * memp_std.h: patch #7928 Fixed size calculation in MALLOC memory pool - creation macro - - 2014-01-18: Brian Fahs - * tcp_out.c: patch #8237: tcp_rexmit_rto fails to update pcb->unsent_oversize - when necessary - - 2014-01-17: Grant Erickson, Jay Logue, Simon Goldschmidt - * ipv6.c, netif.c: patch #7913 Enable Support for IPv6 Loopback - - 2014-01-16: Stathis Voukelatos - * netif.c: patch #7902 Fixed netif_poll() operation when LWIP_LOOPBACK_MAX_PBUFS > 0 - - 2014-01-14: "Freddie Chopin" - * snmp.h, mib2.c: fixed constness and spelling of sysdescr - - 2014-01-14: Simon Goldschmidt (patch by Thomas Faber) - * tcpip.c: patch #8241: Fix implicit declaration of ip_input with - LWIP_TCPIP_CORE_LOCKING_INPUT disabled - - 2014-01-14: chrysn - * timers.c: patch #8244 make timeouts usable reliably from outside of the - timeout routine - - 2014-01-10: Simon Goldschmidt - * ip_frag.c, ip6_frag.c: fixed bug #41041 Potential use-after-free in IPv6 reassembly - - 2014-01-10: Simon Goldschmidt - * memp.c: fixed bug #41188 Alignment error in memp_init() when MEMP_SEPARATE_POOLS==1 - - 2014-01-10: Simon Goldschmidt - * tcp.c: fixed bug #39898 tcp_fasttmr() possible lock due to infinte queue process loop - - 2013-06-29: Simon Goldschmidt - * inet.h, sockets.h: partially fixed bug #37585: IPv6 compatibility (in socket structs) - - 2013-06-29: Simon Goldschmidt - * inet6.h: bug #37585/task #12600: fixed struct in6_addr.s6_addr to conform to spec - - 2013-04-24: patch by Liam - * api_msg.c: patch #8008 Fix a potential null pointer dereference in assert - - 2013-04-24: Simon Goldschmidt - * igmp.c: fixed possible division by zero - - 2013-04-24: Simon Goldschmidt - * ip6.h, some ipv6 C files: fixed bug #38526 Coverity: Recursive Header Inclusion in ip6.h - - 2013-04-24: Simon Goldschmidt (patch by Emil Ljungdahl): - * netif.c: fixed bug #38586 netif_loop_output() "deadlocks" - - 2013-01-15: Simon Goldschmidt - * ip4.c: fixed bug #37665 ip_canforward operates on address in wrong byte order - - 2013-01-15: Simon Goldschmidt - * pbuf.h: fixed bug #38097 pbuf_free_ooseq() warning - - 2013-01-14: Simon Goldschmidt - * dns.c: fixed bug #37705 Possible memory corruption in DNS query - - 2013-01-11: Simon Goldschmidt - * raw.c: fixed bug #38066 Raw pcbs can alter packet without eating it - - 2012-08-22: Simon Goldschmidt - * memp.c: fixed bug #37166: memp_sanity check loops itself - - 2012-08-13: Simon Goldschmidt - * dhcp.c: fixed bug #36645: Calling dhcp_release before dhcp_start - dereferences NULL - - 2012-08-13: Simon Goldschmidt - * msg_out.c: fixed bug #36840 snmp_send_trap() NULL de-reference if traps - configured but no interfaces available - - 2012-08-13: Simon Goldschmidt - * dns.c: fixed bug #36899 DNS TTL 0 is cached for a long time - - 2012-05-11: Simon Goldschmidt (patch by Marty) - * memp.c: fixed bug #36412: memp.c does not compile when - MEMP_OVERFLOW_CHECK > zero and MEMP_SEPARATE_POOLS == 1 - - 2012-05-03: Simon Goldschmidt (patch by Sylvain Rochet) - * ppp.c: fixed bug #36283 (PPP struct used on header size computation and - not packed) - - 2012-05-03: Simon Goldschmidt (patch by David Empson) - * ppp.c: fixed bug #36388 (PPP: checksum-only in last pbuf leads to pbuf with - zero length) - - 2012-03-25: Simon Goldschmidt - * api_msg.c: Fixed bug #35817: do_connect() invalidly signals op_completed - for UDP/RAW with LWIP_TCPIP_CORE_LOCKING==1 - - 2012-03-25: Simon Goldschmidt - * api_msg.h, api_lib.c, api_msg.c, netifapi.c: fixed bug #35931: Name space - pollution in api_msg.c and netifapi.c - - 2011-08-24: Simon Goldschmidt - * inet6.h: fixed bug #34124 struct in6_addr does not conform to the standard - - - -(STABLE-1.4.1) - - ++ New features: - - 2012-03-25: Simon Goldschmidt (idea by Mason) - * posix/*: added posix-compatibility include files posix/netdb.h and posix/sys/socket.h - which are a simple wrapper to the correct lwIP include files. - - 2012-01-16: Simon Goldschmidt - * opt.h, icmp.c: Added option CHECKSUM_GEN_ICMP - - 2011-12-17: Simon Goldschmidt - * ip.h: implemented API functions to access so_options of IP pcbs (UDP, TCP, RAW) - (fixes bug #35061) - - 2011-09-27: Simon Goldschmidt - * opt.h, tcp.c, tcp_in.c: Implemented limiting data on ooseq queue (task #9989) - (define TCP_OOSEQ_MAX_BYTES / TCP_OOSEQ_MAX_PBUFS in lwipopts.h) - - 2011-09-21: Simon Goldschmidt - * opt.h, api.h, api_lib.c, api_msg.h/.c, sockets.c: Implemented timeout on - send (TCP only, bug #33820) - - 2011-09-21: Simon Goldschmidt - * init.c: Converted runtime-sanity-checks into compile-time checks that can - be disabled (since runtime checks can often not be seen on embedded targets) - - 2011-09-11: Simon Goldschmidt - * ppp.h, ppp_impl.h: splitted ppp.h to an internal and external header file - to get a clear separation of which functions an application or port may use - (task #11281) - - 2011-09-11: Simon Goldschmidt - * opt.h, tcp_impl.h, tcp.c, udp.h/.c: Added a config option to randomize - initial local TCP/UDP ports (so that different port ranges are used after - a reboot; bug #33818; this one added tcp_init/udp_init functions again) - - 2011-09-03: Simon Goldschmidt - * dhcp.c: DHCP uses LWIP_RAND() for xid's (bug #30302) - - 2011-08-24: Simon Goldschmidt - * opt.h, netif.h/.c: added netif remove callback (bug #32397) - - 2011-07-26: Simon Goldschmidt - * etharp.c: ETHARP_SUPPORT_VLAN: add support for an external VLAN filter - function instead of only checking for one VLAN (define ETHARP_VLAN_CHECK_FN) - - 2011-07-21: Simon Goldschmidt (patch by hanhui) - * ip4.c, etharp.c, pbuf.h: bug #33634 ip_forward() have a faulty behaviour: - Added pbuf flags to mark incoming packets as link-layer broadcast/multicast. - Also added code to allow ip_forward() to forward non-broadcast packets to - the input netif (set IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1). - - 2011-06-26: Simon Goldschmidt (patch by Cameron Gutman) - * tcp.c, tcp_out.c: bug #33604: added some more asserts to check that - pcb->state != LISTEN - - 2011-05-14: Simon Goldschmidt (patch by Stéphane Lesage) - * tcpip.c/.h: patch #7449 allow tcpip callback from interrupt with static - memory message - - - ++ Bugfixes: - - 2012-09-26: Simon Goldschmidt - * api_msg.c: fixed bug #37405 'err_tcp()' uses already freed 'netconn' object - - 2012-09-26: patch by Henrik Persson - * dhcp.c: patch #7843 Fix corner case with dhcp timeouts - - 2012-09-26: patch by Henrik Persson - * dhcp.c: patch #7840 Segfault in dhcp_parse_reply if no end marker in dhcp packet - - 2012-08-22: Simon Goldschmidt - * memp.c: fixed bug #37166: memp_sanity check loops itself - - 2012-05-08: Simon Goldschmidt - * tcp_out.c: fixed bug: #36380 unsent_oversize mismatch in 1.4.1RC1 (this was - a debug-check issue only) - - 2012-03-27: Simon Goldschmidt - * vj.c: fixed bug #35756 header length calculation problem in ppp/vj.c - - 2012-03-27: Simon Goldschmidt (patch by Mason) - * tcp_out.c: fixed bug #35945: SYN packet should provide the recv MSS not the - send MSS - - 2012-03-22: Simon Goldschmidt - * ip4.c: fixed bug #35927: missing refragmentaion in ip_forward - - 2012-03-20: Simon Goldschmidt (patch by Mason) - * netdb.c: fixed bug #35907: lwip_gethostbyname_r returns an invalid h_addr_list - - 2012-03-12: Simon Goldschmidt (patch by Bostjan Meglic) - * ppp.c: fixed bug #35809: PPP GetMask(): Compiler warning on big endian, - possible bug on little endian system - - 2012-02-23: Simon Goldschmidt - * etharp.c: fixed bug #35595: Impossible to send broadcast without a gateway - (introduced when fixing bug# 33551) - - 2012-02-16: Simon Goldschmidt - * ppp.c: fixed pbuf leak when PPP session is aborted through pppSigHUP() - (bug #35541: PPP Memory Leak) - - 2012-02-16: Simon Goldschmidt - * etharp.c: fixed bug #35531: Impossible to send multicast without a gateway - (introduced when fixing bug# 33551) - - 2012-02-16: Simon Goldschmidt (patch by Stéphane Lesage) - * msg_in.c, msg_out.c: fixed bug #35536 SNMP: error too big response is malformed - - 2012-02-15: Simon Goldschmidt - * init.c: fixed bug #35537: MEMP_NUM_* sanity checks should be disabled with - MEMP_MEM_MALLOC==1 - - 2012-02-12: Simon Goldschmidt - * tcp.h, tcp_in.c, tcp_out.c: partly fixed bug #25882: TCP hangs on - MSS > pcb->snd_wnd (by not creating segments bigger than half the window) - - 2012-02-11: Simon Goldschmidt - * tcp.c: fixed bug #35435: No pcb state check before adding it to time-wait - queue while closing - - 2012-01-22: Simon Goldschmidt - * tcp.c, tcp_in.c: fixed bug #35305: pcb may be freed too early on shutdown(WR) - - 2012-01-21: Simon Goldschmidt - * tcp.c: fixed bug #34636: FIN_WAIT_2 - Incorrect shutdown of TCP pcb - - 2012-01-20: Simon Goldschmidt - * dhcp.c: fixed bug #35151: DHCP asserts on incoming option lengths - - 2012-01-20: Simon Goldschmidt - * pbuf.c: fixed bug #35291: NULL pointer in pbuf_copy - - 2011-11-25: Simon Goldschmidt - * tcp.h/.c, tcp_impl.h, tcp_in.c: fixed bug #31177: tcp timers can corrupt - tcp_active_pcbs in some cases - - 2011-11-23: Simon Goldschmidt - * sys.c: fixed bug #34884: sys_msleep() body needs to be surrounded with - '#ifndef sys_msleep' - - 2011-11-22: Simon Goldschmidt - * netif.c, etharp.h/.c: fixed bug #34684: Clear the arp table cache when - netif is brought down - - 2011-10-28: Simon Goldschmidt - * tcp_in.c: fixed bug #34638: Dead code in tcp_receive - pcb->dupacks - - 2011-10-23: Simon Goldschmidt - * mem.c: fixed bug #34429: possible memory corruption with - LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT set to 1 - - 2011-10-18: Simon Goldschmidt - * arch.h, netdb.c: fixed bug #34592: lwip_gethostbyname_r uses nonstandard - error value - - 2011-10-18: Simon Goldschmidt - * opt.h: fixed default values of TCP_SNDLOWAT and TCP_SNDQUEUELOWAT for small - windows (bug #34176 select after non-blocking send times out) - - 2011-10-18: Simon Goldschmidt - * tcp_impl.h, tcp_out.c: fixed bug #34587: TCP_BUILD_MSS_OPTION doesn't - consider netif->mtu, causes slow network - - 2011-10-18: Simon Goldschmidt - * sockets.c: fixed bug #34581 missing parentheses in udplite sockets code - - 2011-10-18: Simon Goldschmidt - * sockets.h: fixed bug #34580 fcntl() is missing in LWIP_COMPAT_SOCKETS - - 2011-10-17: Simon Goldschmidt - * api_msg.c: fixed bug #34569: shutdown(SHUT_WR) crashes netconn/socket api - - 2011-10-13: Simon Goldschmidt - * tcp_in.c, tcp_out.c: fixed bug #34517 (persist timer is started although no - zero window is received) by starting the persist timer when a zero window is - received, not when we have more data queued for sending than fits into the - window - - 2011-10-13: Simon Goldschmidt - * def.h, timers.c: fixed bug #34541: LWIP_U32_DIFF is unnecessarily complex - - 2011-10-13: Simon Goldschmidt - * sockets.c, api_lib.c: fixed bug #34540: compiler error when CORE_LOCKING is - used and not all protocols are enabled - - 2011-10-12: Simon Goldschmidt - * pbuf.c: fixed bug #34534: Error in sending fragmented IP if MEM_ALIGNMENT > 4 - - 2011-10-09: Simon Goldschmidt - * tcp_out.c: fixed bug #34426: tcp_zero_window_probe() transmits incorrect - byte value when pcb->unacked != NULL - - 2011-10-09: Simon Goldschmidt - * ip4.c: fixed bug #34447 LWIP_IP_ACCEPT_UDP_PORT(dst_port) wrong - - 2011-09-27: Simon Goldschmidt - * tcp_in.c, tcp_out.c: Reset pcb->unsent_oversize in 2 more places... - - 2011-09-27: Simon Goldschmidt - * tcp_in.c: fixed bug #28288: Data after FIN in oos queue - - 2011-09-27: Simon Goldschmidt - * dhcp.c: fixed bug #34406 dhcp_option_hostname() can overflow the pbuf - - 2011-09-24: Simon Goldschmidt - * mem.h: fixed bug #34377 MEM_SIZE_F is not defined if MEM_LIBC_MALLOC==1 - - 2011-09-23: Simon Goldschmidt - * pbuf.h, tcp.c, tcp_in.c: fixed bug #33871: rejecting TCP_EVENT_RECV() for - the last packet including FIN can lose data - - 2011-09-22: Simon Goldschmidt - * tcp_impl.h: fixed bug #34355: nagle does not take snd_buf/snd_queuelen into - account - - 2011-09-21: Simon Goldschmidt - * opt.h: fixed default value of TCP_SND_BUF to not violate the sanity checks - in init.c - - 2011-09-20: Simon Goldschmidt - * timers.c: fixed bug #34337 (possible NULL pointer in sys_check_timeouts) - - 2011-09-11: Simon Goldschmidt - * tcp_out.c: use pcb->mss instead of TCP_MSS for preallocate mss-sized pbufs - (bug #34019) - - 2011-09-09: Simon Goldschmidt - * udp.c: fixed bug #34072: UDP broadcast is received from wrong UDP pcb if - udp port matches - - 2011-09-03: Simon Goldschmidt - * tcp_in.c: fixed bug #33952 PUSH flag in incoming packet is lost when packet - is aggregated and sent to application - - 2011-09-01: Simon Goldschmidt - * opt.h: fixed bug #31809 LWIP_EVENT_API in opts.h is inconsistent compared - to other options - - 2011-09-01: Simon Goldschmidt - * tcp_in.c: fixed bug #34111 RST for ACK to listening pcb has wrong seqno - - 2011-08-24: Simon Goldschmidt - * api_msg.c, sockets.c: fixed bug #33956 Wrong error returned when calling - accept() on UDP connections - - 2011-08-24: Simon Goldschmidt - * sockets.h: fixed bug #34057 socklen_t should be a typedef - - 2011-08-24: Simon Goldschmidt - * pbuf.c: fixed bug #34112 Odd check in pbuf_alloced_custom (typo) - - 2011-08-24: Simon Goldschmidt - * dhcp.c: fixed bug #34122 dhcp: hostname can overflow - - 2011-08-24: Simon Goldschmidt - * netif.c: fixed bug #34121 netif_add/netif_set_ipaddr fail on NULL ipaddr - - 2011-08-22: Simon Goldschmidt - * tcp_out.c: fixed bug #33962 TF_FIN not always set after FIN is sent. (This - merely prevents nagle from not transmitting fast after closing.) - - 2011-07-22: Simon Goldschmidt - * api_lib.c, api_msg.c, sockets.c, api.h: fixed bug #31084 (socket API returns - always EMSGSIZE on non-blocking sockets if data size > send buffers) -> now - lwip_send() sends as much as possible for non-blocking sockets - - 2011-07-22: Simon Goldschmidt - * pbuf.c/.h, timers.c: freeing ooseq pbufs when the pbuf pool is empty implemented - for NO_SYS==1: when not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ() - at regular intervals from main level. - - 2011-07-21: Simon Goldschmidt - * etharp.c: fixed bug #33551 (ARP entries may time out although in use) by - sending an ARP request when an ARP entry is used in the last minute before - it would time out. - - 2011-07-04: Simon Goldschmidt - * sys_arch.txt: Fixed documentation after changing sys arch prototypes for 1.4.0. - - 2011-06-26: Simon Goldschmidt - * tcp.c: fixed bug #31723 (tcp_kill_prio() kills pcbs with the same prio) by - updating its documentation only. - - 2011-06-26: Simon Goldschmidt - * mem.c: fixed bug #33545: With MEM_USE_POOLS==1, mem_malloc can return an - unaligned pointer. - - 2011-06-26: Simon Goldschmidt - * mem.c: fixed bug #33544 "warning in mem.c in lwip 1.4.0 with NO_SYS=1" - - 2011-05-25: Simon Goldschmidt - * tcp.c: fixed bug #33398 (pointless conversion when checking TCP port range) - - - -(STABLE-1.4.0) - - ++ New features: - - 2011-03-27: Simon Goldschmidt - * tcp_impl.h, tcp_in.c, tcp_out.c: Removed 'dataptr' from 'struct tcp_seg' and - calculate it in tcp_zero_window_probe (the only place where it was used). - - 2010-11-21: Simon Goldschmidt - * dhcp.c/.h: Added a function to deallocate the struct dhcp from a netif - (fixes bug #31525). - - 2010-07-12: Simon Goldschmidt (patch by Stephane Lesage) - * ip.c, udp.c/.h, pbuf.h, sockets.c: task #10495: Added support for - IP_MULTICAST_LOOP at socket- and raw-API level. - - 2010-06-16: Simon Goldschmidt - * ip.c: Added an optional define (LWIP_IP_ACCEPT_UDP_PORT) that can allow - link-layer-addressed UDP traffic to be received while a netif is down (just - like DHCP during configuration) - - 2010-05-22: Simon Goldschmidt - * many many files: bug #27352: removed packing from ip_addr_t, the packed - version is now only used in protocol headers. Added global storage for - current src/dest IP address while in input functions. - - 2010-05-16: Simon Goldschmidt - * def.h: task #10391: Add preprocessor-macros for compile-time htonl - calculation (and use them throughout the stack where applicable) - - 2010-05-16: Simon Goldschmidt - * opt.h, memp_std.h, memp.c, ppp_oe.h/.c: PPPoE now uses its own MEMP pool - instead of the heap (moved struct pppoe_softc from ppp_oe.c to ppp_oe.h) - - 2010-05-16: Simon Goldschmidt - * opt.h, memp_std.h, dns.h/.c: DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses its own - MEMP pool instead of the heap - - 2010-05-13: Simon Goldschmidt - * tcp.c, udp.c: task #6995: Implement SO_REUSEADDR (correctly), added - new option SO_REUSE_RXTOALL to pass received UDP broadcast/multicast - packets to more than one pcb. - - 2010-05-02: Simon Goldschmidt - * netbuf.h/.c, sockets.c, api_msg.c: use checksum-on-copy for sending - UDP data for LWIP_NETIF_TX_SINGLE_PBUF==1 - - 2010-04-30: Simon Goldschmidt - * udp.h/.c, pbuf.h/.c: task #6849: added udp_send(_to/_if) functions that - take a precalculated checksum, added pbuf_fill_chksum() to copy data - into a pbuf and at the same time calculating the checksum for that data - - 2010-04-29: Simon Goldschmidt - * ip_addr.h, etharp.h/.c, autoip.c: Create overridable macros for copying - 2-byte-aligned IP addresses and MAC addresses - - 2010-04-28: Patch by Bill Auerbach - * ip.c: Inline generating IP checksum to save a function call - - 2010-04-14: Simon Goldschmidt - * tcpip.h/.c, timers.c: Added an overridable define to get informed when the - tcpip_thread processes messages or timeouts to implement a watchdog. - - 2010-03-28: Simon Goldschmidt - * ip_frag.c: create a new (contiguous) PBUF_RAM for every outgoing - fragment if LWIP_NETIF_TX_SINGLE_PBUF==1 - - 2010-03-27: Simon Goldschmidt - * etharp.c: Speedup TX by moving code from find_entry to etharp_output/ - etharp_query to prevent unnecessary function calls (inspired by - patch #7135). - - 2010-03-20: Simon Goldschmidt - * opt.h, tcpip.c/.h: Added an option to disable tcpip_(un)timeout code - since the linker cannot do this automatically to save space. - - 2010-03-20: Simon Goldschmidt - * opt.h, etharp.c/.h: Added support for static ARP table entries - - 2010-03-14: Simon Goldschmidt - * tcp_impl.h, tcp_out.c, inet_chksum.h/.c: task #6849: Calculate checksum - when creating TCP segments, not when (re-)transmitting them. - - 2010-03-07: Simon Goldschmidt - * sockets.c: bug #28775 (select/event_callback: only check select_cb_list - on change) plus use SYS_LIGHTWEIGHT_PROT to protect the select code. - This should speed up receiving data on sockets as the select code in - event_callback is only executed when select is waiting. - - 2010-03-06: Simon Goldschmidt - * tcp_out.c: task #7013 (Create option to have all packets delivered to - netif->output in one piece): Always copy to try to create single pbufs - in tcp_write. - - 2010-03-06: Simon Goldschmidt - * api.h, api_lib.c, sockets.c: task #10167 (sockets: speed up TCP recv - by not allocating a netbuf): added function netconn_recv_tcp_pbuf() - for tcp netconns to receive pbufs, not netbufs; use that function - for tcp sockets. - - 2010-03-05: Jakob Ole Stoklundsen / Simon Goldschmidt - * opt.h, tcp.h, tcp_impl.h, tcp.c, tcp_in.c, tcp_out.c: task #7040: - Work on tcp_enqueue: Don't waste memory when chaining segments, - added option TCP_OVERSIZE to prevent creating many small pbufs when - calling tcp_write with many small blocks of data. Instead, pbufs are - allocated larger than needed and the space is used for later calls to - tcp_write. - - 2010-02-21: Simon Goldschmidt - * stats.c/.h: Added const char* name to mem- and memp-stats for easier - debugging. - - 2010-02-21: Simon Goldschmidt - * tcp.h (and usages), added tcp_impl.h: Splitted API and internal - implementation of tcp to make API usage cleare to application programmers - - 2010-02-14: Simon Goldschmidt/Stephane Lesage - * ip_addr.h: Improved some defines working on ip addresses, added faster - macro to copy addresses that cannot be NULL - - 2010-02-13: Simon Goldschmidt - * api.h, api_lib.c, api_msg.c, sockets.c: task #7865 (implement non- - blocking send operation) - - 2010-02-12: Simon Goldschmidt - * sockets.c/.h: Added a minimal version of posix fctl() to have a - standardised way to set O_NONBLOCK for nonblocking sockets. - - 2010-02-12: Simon Goldschmidt - * dhcp.c/.h, autoip.c/.h: task #10139 (Prefer statically allocated - memory): added autoip_set_struct() and dhcp_set_struct() to let autoip - and dhcp work with user-allocated structs instead of callin mem_malloc - - 2010-02-12: Simon Goldschmidt/Jeff Barber - * tcp.c/h: patch #6865 (SO_REUSEADDR for TCP): if pcb.so_options has - SOF_REUSEADDR set, allow binding to endpoint in TIME_WAIT - - 2010-02-12: Simon Goldschmidt - * sys layer: task #10139 (Prefer statically allocated memory): converted - mbox and semaphore functions to take pointers to sys_mbox_t/sys_sem_t; - converted sys_mbox_new/sys_sem_new to take pointers and return err_t; - task #7212: Add Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX - to let sys.h use binary semaphores instead of mutexes - as before) - - 2010-02-09: Simon Goldschmidt (Simon Kallweit) - * timers.c/.h: Added function sys_restart_timeouts() from patch #7085 - (Restart system timeout handling) - - 2010-02-09: Simon Goldschmidt - * netif.c/.h, removed loopif.c/.h: task #10153 (Integrate loopif into - netif.c) - loopif does not have to be created by the port any more, - just define LWIP_HAVE_LOOPIF to 1. - - 2010-02-08: Simon Goldschmidt - * inet.h, ip_addr.c/.h: Added reentrant versions of inet_ntoa/ipaddr_ntoa - inet_ntoa_r/ipaddr_ntoa_r - - 2010-02-08: Simon Goldschmidt - * netif.h: Added netif_s/get_igmp_mac_filter() macros - - 2010-02-05: Simon Goldschmidt - * netif.h: Added function-like macros to get/set the hostname on a netif - - 2010-02-04: Simon Goldschmidt - * nearly every file: Replaced struct ip_addr by typedef ip_addr_t to - make changing the actual implementation behind the typedef easier. - - 2010-02-01: Simon Goldschmidt - * opt.h, memp_std.h, dns.h, netdb.c, memp.c: Let netdb use a memp pool - for allocating memory when getaddrinfo() is called. - - 2010-01-31: Simon Goldschmidt - * dhcp.h, dhcp.c: Reworked the code that parses DHCP options: parse - them once instead of parsing for every option. This also removes - the need for mem_malloc from dhcp_recv and makes it possible to - correctly retrieve the BOOTP file. - - 2010-01-30: simon Goldschmidt - * sockets.c: Use SYS_LIGHTWEIGHT_PROT instead of a semaphore to protect - the sockets array. - - 2010-01-29: Simon Goldschmidt (patch by Laura Garrett) - * api.h, api_msg.c, sockets.c: Added except set support in select - (patch #6860) - - 2010-01-29: Simon Goldschmidt (patch by Laura Garrett) - * api.h, sockets.h, err.h, api_lib.c, api_msg.c, sockets.c, err.c: - Add non-blocking support for connect (partly from patch #6860), - plus many cleanups in socket & netconn API. - - 2010-01-27: Simon Goldschmidt - * opt.h, tcp.h, init.c, api_msg.c: Added TCP_SNDQUEUELOWAT corresponding - to TCP_SNDLOWAT and added tcp_sndqueuelen() - this fixes bug #28605 - - 2010-01-26: Simon Goldschmidt - * snmp: Use memp pools for snmp instead of the heap; added 4 new pools. - - 2010-01-14: Simon Goldschmidt - * ppp.c/.h: Fixed bug #27856: PPP: Set netif link- and status-callback - by adding ppp_set_netif_statuscallback()/ppp_set_netif_linkcallback() - - 2010-01-13: Simon Goldschmidt - * mem.c: The heap now may be moved to user-defined memory by defining - LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address - (patch #6966 and bug #26133) - - 2010-01-10: Simon Goldschmidt (Bill Auerbach) - * opt.h, memp.c: patch #6822 (Add option to place memory pools in - separate arrays) - - 2010-01-10: Simon Goldschmidt - * init.c, igmp.c: patch #6463 (IGMP - Adding Random Delay): added define - LWIP_RAND() for lwip-wide randomization (to be defined in cc.h) - - 2009-12-31: Simon Goldschmidt - * tcpip.c, init.c, memp.c, sys.c, memp_std.h, sys.h, tcpip.h - added timers.c/.h: Separated timer implementation from semaphore/mbox - implementation, moved timer implementation to timers.c/.h, timers are - now only called from tcpip_thread or by explicitly checking them. - (TASK#7235) - - 2009-12-27: Simon Goldschmidt - * opt.h, etharp.h/.c, init.c, tcpip.c: Added an additional option - LWIP_ETHERNET to support ethernet without ARP (necessary for pure PPPoE) - - - ++ Bugfixes: - - 2011-04-20: Simon Goldschmidt - * sys_arch.txt: sys_arch_timeouts() is not needed any more. - - 2011-04-13: Simon Goldschmidt - * tcp.c, udp.c: Fixed bug #33048 (Bad range for IP source port numbers) by - using ports in the IANA private/dynamic range (49152 through 65535). - - 2011-03-29: Simon Goldschmidt, patch by Emil Lhungdahl: - * etharp.h/.c: Fixed broken VLAN support. - - 2011-03-27: Simon Goldschmidt - * tcp.c: Fixed bug #32926 (TCP_RMV(&tcp_bound_pcbs) is called on unbound tcp - pcbs) by checking if the pcb was bound (local_port != 0). - - 2011-03-27: Simon Goldschmidt - * ppp.c: Fixed bug #32280 (ppp: a pbuf is freed twice) - - 2011-03-27: Simon Goldschmidt - * sockets.c: Fixed bug #32906: lwip_connect+lwip_send did not work for udp and - raw pcbs with LWIP_TCPIP_CORE_LOCKING==1. - - 2011-03-27: Simon Goldschmidt - * tcp_out.c: Fixed bug #32820 (Outgoing TCP connections created before route - is present never times out) by starting retransmission timer before checking - route. - - 2011-03-22: Simon Goldschmidt - * ppp.c: Fixed bug #32648 (PPP code crashes when terminating a link) by only - calling sio_read_abort() if the file descriptor is valid. - - 2011-03-14: Simon Goldschmidt - * err.h/.c, sockets.c, api_msg.c: fixed bug #31748 (Calling non-blocking connect - more than once can render a socket useless) since it mainly involves changing - "FATAL" classification of error codes: ERR_USE and ERR_ISCONN just aren't fatal. - - 2011-03-13: Simon Goldschmidt - * sockets.c: fixed bug #32769 (ESHUTDOWN is linux-specific) by fixing - err_to_errno_table (ERR_CLSD: ENOTCONN instead of ESHUTDOWN), ERR_ISCONN: - use EALRADY instead of -1 - - 2011-03-13: Simon Goldschmidt - * api_lib.c: netconn_accept: return ERR_ABRT instead of ERR_CLSD if the - connection has been aborted by err_tcp (since this is not a normal closing - procedure). - - 2011-03-13: Simon Goldschmidt - * tcp.c: tcp_bind: return ERR_VAL instead of ERR_ISCONN when trying to bind - with pcb->state != CLOSED - - 2011-02-17: Simon Goldschmidt - * rawapi.txt: Fixed bug #32561 tcp_poll argument definition out-of-order in - documentation - - 2011-02-17: Simon Goldschmidt - * many files: Added missing U/UL modifiers to fix 16-bit-arch portability. - - 2011-01-24: Simon Goldschmidt - * sockets.c: Fixed bug #31741: lwip_select seems to have threading problems - - 2010-12-02: Simon Goldschmidt - * err.h: Fixed ERR_IS_FATAL so that ERR_WOULDBLOCK is not fatal. - - 2010-11-23: Simon Goldschmidt - * api.h, api_lib.c, api_msg.c, sockets.c: netconn.recv_avail is only used for - LWIP_SO_RCVBUF and ioctl/FIONREAD. - - 2010-11-23: Simon Goldschmidt - * etharp.c: Fixed bug #31720: ARP-queueing: RFC 1122 recommends to queue at - least 1 packet -> ARP_QUEUEING==0 now queues the most recent packet. - - 2010-11-23: Simon Goldschmidt - * tcp_in.c: Fixed bug #30577: tcp_input: don't discard ACK-only packets after - refusing 'refused_data' again. - - 2010-11-22: Simon Goldschmidt - * sockets.c: Fixed bug #31590: getsockopt(... SO_ERROR ...) gives EINPROGRESS - after a successful nonblocking connection. - - 2010-11-22: Simon Goldschmidt - * etharp.c: Fixed bug #31722: IP packets sent with an AutoIP source addr - must be sent link-local - - 2010-11-22: Simon Goldschmidt - * timers.c: patch #7329: tcp_timer_needed prototype was ifdef'ed out for - LWIP_TIMERS==0 - - 2010-11-20: Simon Goldschmidt - * sockets.c: Fixed bug #31170: lwip_setsockopt() does not set socket number - - 2010-11-20: Simon Goldschmidt - * sockets.h: Fixed bug #31304: Changed SHUT_RD, SHUT_WR and SHUT_RDWR to - resemble other stacks. - - 2010-11-20: Simon Goldschmidt - * dns.c: Fixed bug #31535: TCP_SND_QUEUELEN must be at least 2 or else - no-copy TCP writes will never succeed. - - 2010-11-20: Simon Goldschmidt - * dns.c: Fixed bug #31701: Error return value from dns_gethostbyname() does - not match documentation: return ERR_ARG instead of ERR_VAL if not - initialized or wrong argument. - - 2010-10-20: Simon Goldschmidt - * sockets.h: Fixed bug #31385: sizeof(struct sockaddr) is 30 but should be 16 - - 2010-10-05: Simon Goldschmidt - * dhcp.c: Once again fixed #30038: DHCP/AutoIP cooperation failed when - replugging the network cable after an AutoIP address was assigned. - - 2010-08-10: Simon Goldschmidt - * tcp.c: Fixed bug #30728: tcp_new_port() did not check listen pcbs - - 2010-08-03: Simon Goldschmidt - * udp.c, raw.c: Don't chain empty pbufs when sending them (fixes bug #30625) - - 2010-08-01: Simon Goldschmidt (patch by Greg Renda) - * ppp.c: Applied patch #7264 (PPP protocols are rejected incorrectly on big - endian architectures) - - 2010-07-28: Simon Goldschmidt - * api_lib.c, api_msg.c, sockets.c, mib2.c: Fixed compilation with TCP or UDP - disabled. - - 2010-07-27: Simon Goldschmidt - * tcp.c: Fixed bug #30565 (tcp_connect() check bound list): that check did no - harm but never did anything - - 2010-07-21: Simon Goldschmidt - * ip.c: Fixed invalid fix for bug #30402 (CHECKSUM_GEN_IP_INLINE does not - add IP options) - - 2010-07-16: Kieran Mansley - * msg_in.c: Fixed SNMP ASN constant defines to not use ! operator - - 2010-07-10: Simon Goldschmidt - * ip.c: Fixed bug #30402: CHECKSUM_GEN_IP_INLINE does not add IP options - - 2010-06-30: Simon Goldschmidt - * api_msg.c: fixed bug #30300 (shutdown parameter was not initialized in - netconn_delete) - - 2010-06-28: Kieran Mansley - * timers.c remove unportable printing of C function pointers - - 2010-06-24: Simon Goldschmidt - * init.c, timers.c/.h, opt.h, memp_std.h: From patch #7221: added flag - NO_SYS_NO_TIMERS to drop timer support for NO_SYS==1 for easier upgrading - - 2010-06-24: Simon Goldschmidt - * api(_lib).c/.h, api_msg.c/.h, sockets.c/.h: Fixed bug #10088: Correctly - implemented shutdown at socket level. - - 2010-06-21: Simon Goldschmidt - * pbuf.c/.h, ip_frag.c/.h, opt.h, memp_std.h: Fixed bug #29361 (ip_frag has - problems with zero-copy DMA MACs) by adding custom pbufs and implementing - custom pbufs that reference other (original) pbufs. Additionally set - IP_FRAG_USES_STATIC_BUF=0 as default to be on the safe side. - - 2010-06-15: Simon Goldschmidt - * dhcp.c: Fixed bug #29970: DHCP endian issue parsing option responses - - 2010-06-14: Simon Goldschmidt - * autoip.c: Fixed bug #30039: AutoIP does not reuse previous addresses - - 2010-06-12: Simon Goldschmidt - * dhcp.c: Fixed bug #30038: dhcp_network_changed doesn't reset AUTOIP coop - state - - 2010-05-17: Simon Goldschmidt - * netdb.c: Correctly NULL-terminate h_addr_list - - 2010-05-16: Simon Goldschmidt - * def.h/.c: changed the semantics of LWIP_PREFIX_BYTEORDER_FUNCS to prevent - "symbol already defined" i.e. when linking to winsock - - 2010-05-05: Simon Goldschmidt - * def.h, timers.c: Fixed bug #29769 (sys_check_timeouts: sys_now() may - overflow) - - 2010-04-21: Simon Goldschmidt - * api_msg.c: Fixed bug #29617 (sometime cause stall on delete listening - connection) - - 2010-03-28: Luca Ceresoli - * ip_addr.c/.h: patch #7143: Add a few missing const qualifiers - - 2010-03-27: Luca Ceresoli - * mib2.c: patch #7130: remove meaningless const qualifiers - - 2010-03-26: Simon Goldschmidt - * tcp_out.c: Make LWIP_NETIF_TX_SINGLE_PBUF work for TCP, too - - 2010-03-26: Simon Goldschmidt - * various files: Fixed compiling with different options disabled (TCP/UDP), - triggered by bug #29345; don't allocate acceptmbox if LWIP_TCP is disabled - - 2010-03-25: Simon Goldschmidt - * sockets.c: Fixed bug #29332: lwip_select() processes readset incorrectly - - 2010-03-25: Simon Goldschmidt - * tcp_in.c, test_tcp_oos.c: Fixed bug #29080: Correctly handle remote side - overrunning our rcv_wnd in ooseq case. - - 2010-03-22: Simon Goldschmidt - * tcp.c: tcp_listen() did not copy the pcb's prio. - - 2010-03-19: Simon Goldschmidt - * snmp_msg.c: Fixed bug #29256: SNMP Trap address was not correctly set - - 2010-03-14: Simon Goldschmidt - * opt.h, etharp.h: Fixed bug #29148 (Incorrect PBUF_POOL_BUFSIZE for ports - where ETH_PAD_SIZE > 0) by moving definition of ETH_PAD_SIZE to opt.h - and basing PBUF_LINK_HLEN on it. - - 2010-03-08: Simon Goldschmidt - * netif.c, ipv4/ip.c: task #10241 (AutoIP: don't break existing connections - when assiging routable address): when checking incoming packets and - aborting existing connection on address change, filter out link-local - addresses. - - 2010-03-06: Simon Goldschmidt - * sockets.c: Fixed LWIP_NETIF_TX_SINGLE_PBUF for LWIP_TCPIP_CORE_LOCKING - - 2010-03-06: Simon Goldschmidt - * ipv4/ip.c: Don't try to forward link-local addresses - - 2010-03-06: Simon Goldschmidt - * etharp.c: Fixed bug #29087: etharp: don't send packets for LinkLocal- - addresses to gw - - 2010-03-05: Simon Goldschmidt - * dhcp.c: Fixed bug #29072: Correctly set ciaddr based on message-type - and state. - - 2010-03-05: Simon Goldschmidt - * api_msg.c: Correctly set TCP_WRITE_FLAG_MORE when netconn_write is split - into multiple calls to tcp_write. - - 2010-02-21: Simon Goldschmidt - * opt.h, mem.h, dns.c: task #10140: Remove DNS_USES_STATIC_BUF (keep - the implementation of DNS_USES_STATIC_BUF==1) - - 2010-02-20: Simon Goldschmidt - * tcp.h, tcp.c, tcp_in.c, tcp_out.c: Task #10088: Correctly implement - close() vs. shutdown(). Now the application does not get any more - recv callbacks after calling tcp_close(). Added tcp_shutdown(). - - 2010-02-19: Simon Goldschmidt - * mem.c/.h, pbuf.c: Renamed mem_realloc() to mem_trim() to prevent - confusion with realloc() - - 2010-02-15: Simon Goldschmidt/Stephane Lesage - * netif.c/.h: Link status does not depend on LWIP_NETIF_LINK_CALLBACK - (fixes bug #28899) - - 2010-02-14: Simon Goldschmidt - * netif.c: Fixed bug #28877 (Duplicate ARP gratuitous packet with - LWIP_NETIF_LINK_CALLBACK set on) by only sending if both link- and - admin-status of a netif are up - - 2010-02-14: Simon Goldschmidt - * opt.h: Disable ETHARP_TRUST_IP_MAC by default since it slows down packet - reception and is not really necessary - - 2010-02-14: Simon Goldschmidt - * etharp.c/.h: Fixed ARP input processing: only add a new entry if a - request was directed as us (RFC 826, Packet Reception), otherwise - only update existing entries; internalized some functions - - 2010-02-14: Simon Goldschmidt - * netif.h, etharp.c, tcpip.c: Fixed bug #28183 (ARP and TCP/IP cannot be - disabled on netif used for PPPoE) by adding a new netif flag - (NETIF_FLAG_ETHERNET) that tells the stack the device is an ethernet - device but prevents usage of ARP (so that ethernet_input can be used - for PPPoE). - - 2010-02-12: Simon Goldschmidt - * netif.c: netif_set_link_up/down: only do something if the link state - actually changes - - 2010-02-12: Simon Goldschmidt/Stephane Lesage - * api_msg.c: Fixed bug #28865 (Cannot close socket/netconn in non-blocking - connect) - - 2010-02-12: Simon Goldschmidt - * mem.h: Fixed bug #28866 (mem_realloc function defined in mem.h) - - 2010-02-09: Simon Goldschmidt - * api_lib.c, api_msg.c, sockets.c, api.h, api_msg.h: Fixed bug #22110 - (recv() makes receive window update for data that wasn't received by - application) - - 2010-02-09: Simon Goldschmidt/Stephane Lesage - * sockets.c: Fixed bug #28853 (lwip_recvfrom() returns 0 on receive time-out - or any netconn_recv() error) - - 2010-02-09: Simon Goldschmidt - * ppp.c: task #10154 (PPP: Update snmp in/out counters for tx/rx packets) - - 2010-02-09: Simon Goldschmidt - * netif.c: For loopback packets, adjust the stats- and snmp-counters - for the loopback netif. - - 2010-02-08: Simon Goldschmidt - * igmp.c/.h, ip.h: Moved most defines from igmp.h to igmp.c for clarity - since they are not used anywhere else. - - 2010-02-08: Simon Goldschmidt (Stéphane Lesage) - * igmp.c, igmp.h, stats.c, stats.h: Improved IGMP stats - (patch from bug #28798) - - 2010-02-08: Simon Goldschmidt (Stéphane Lesage) - * igmp.c: Fixed bug #28798 (Error in "Max Response Time" processing) and - another bug when LWIP_RAND() returns zero. - - 2010-02-04: Simon Goldschmidt - * nearly every file: Use macros defined in ip_addr.h (some of them new) - to work with IP addresses (preparation for bug #27352 - Change ip_addr - from struct to typedef (u32_t) - and better code). - - 2010-01-31: Simon Goldschmidt - * netif.c: Don't call the link-callback from netif_set_up/down() since - this invalidly retriggers DHCP. - - 2010-01-29: Simon Goldschmidt - * ip_addr.h, inet.h, def.h, inet.c, def.c, more: Cleanly separate the - portability file inet.h and its contents from the stack: moved htonX- - functions to def.h (and the new def.c - they are not ipv4 dependent), - let inet.h depend on ip_addr.h and not the other way round. - This fixes bug #28732. - - 2010-01-28: Kieran Mansley - * tcp.c: Ensure ssthresh >= 2*MSS - - 2010-01-27: Simon Goldschmidt - * tcp.h, tcp.c, tcp_in.c: Fixed bug #27871: Calling tcp_abort() in recv - callback can lead to accessing unallocated memory. As a consequence, - ERR_ABRT means the application has called tcp_abort()! - - 2010-01-25: Simon Goldschmidt - * snmp_structs.h, msg_in.c: Partly fixed bug #22070 (MIB_OBJECT_WRITE_ONLY - not implemented in SNMP): write-only or not-accessible are still - returned by getnext (though not by get) - - 2010-01-24: Simon Goldschmidt - * snmp: Renamed the private mib node from 'private' to 'mib_private' to - not use reserved C/C++ keywords - - 2010-01-23: Simon Goldschmidt - * sockets.c: Fixed bug #28716: select() returns 0 after waiting for less - than 1 ms - - 2010-01-21: Simon Goldschmidt - * tcp.c, api_msg.c: Fixed bug #28651 (tcp_connect: no callbacks called - if tcp_enqueue fails) both in raw- and netconn-API - - 2010-01-19: Simon Goldschmidt - * api_msg.c: Fixed bug #27316: netconn: Possible deadlock in err_tcp - - 2010-01-18: Iordan Neshev/Simon Goldschmidt - * src/netif/ppp: reorganised PPP sourcecode to 2.3.11 including some - bugfix backports from 2.4.x. - - 2010-01-18: Simon Goldschmidt - * mem.c: Fixed bug #28679: mem_realloc calculates mem_stats wrong - - 2010-01-17: Simon Goldschmidt - * api_lib.c, api_msg.c, (api_msg.h, api.h, sockets.c, tcpip.c): - task #10102: "netconn: clean up conn->err threading issues" by adding - error return value to struct api_msg_msg - - 2010-01-17: Simon Goldschmidt - * api.h, api_lib.c, sockets.c: Changed netconn_recv() and netconn_accept() - to return err_t (bugs #27709 and #28087) - - 2010-01-14: Simon Goldschmidt - * ...: Use typedef for function prototypes throughout the stack. - - 2010-01-13: Simon Goldschmidt - * api_msg.h/.c, api_lib.c: Fixed bug #26672 (close connection when receive - window = 0) by correctly draining recvmbox/acceptmbox - - 2010-01-11: Simon Goldschmidt - * pap.c: Fixed bug #13315 (PPP PAP authentication can result in - erroneous callbacks) by copying the code from recent pppd - - 2010-01-10: Simon Goldschmidt - * raw.c: Fixed bug #28506 (raw_bind should filter received packets) - - 2010-01-10: Simon Goldschmidt - * tcp.h/.c: bug #28127 (remove call to tcp_output() from tcp_ack(_now)()) - - 2010-01-08: Simon Goldschmidt - * sockets.c: Fixed bug #28519 (lwip_recvfrom bug with len > 65535) - - 2010-01-08: Simon Goldschmidt - * dns.c: Copy hostname for DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1 since string - passed to dns_local_addhost() might be volatile - - 2010-01-07: Simon Goldschmidt - * timers.c, tcp.h: Call tcp_timer_needed() with NO_SYS==1, too - - 2010-01-06: Simon Goldschmidt - * netdb.h: Fixed bug #28496: missing include guards in netdb.h - - 2009-12-31: Simon Goldschmidt - * many ppp files: Reorganised PPP source code from ucip structure to pppd - structure to easily compare our code against the pppd code (around v2.3.1) - - 2009-12-27: Simon Goldschmidt - * tcp_in.c: Another fix for bug #28241 (ooseq processing) and adapted - unit test - - -(STABLE-1.3.2) - - ++ New features: - - 2009-10-27 Simon Goldschmidt/Stephan Lesage - * netifapi.c/.h: Added netifapi_netif_set_addr() - - 2009-10-07 Simon Goldschmidt/Fabian Koch - * api_msg.c, netbuf.c/.h, opt.h: patch #6888: Patch for UDP Netbufs to - support dest-addr and dest-port (optional: LWIP_NETBUF_RECVINFO) - - 2009-08-26 Simon Goldschmidt/Simon Kallweit - * slipif.c/.h: bug #26397: SLIP polling support - - 2009-08-25 Simon Goldschmidt - * opt.h, etharp.h/.c: task #9033: Support IEEE 802.1q tagged frame (VLAN), - New configuration options ETHARP_SUPPORT_VLAN and ETHARP_VLAN_CHECK. - - 2009-08-25 Simon Goldschmidt - * ip_addr.h, netdb.c: patch #6900: added define ip_ntoa(struct ip_addr*) - - 2009-08-24 Jakob Stoklund Olesen - * autoip.c, dhcp.c, netif.c: patch #6725: Teach AutoIP and DHCP to respond - to netif_set_link_up(). - - 2009-08-23 Simon Goldschmidt - * tcp.h/.c: Added function tcp_debug_state_str() to convert a tcp state - to a human-readable string. - - ++ Bugfixes: - - 2009-12-24: Kieran Mansley - * tcp_in.c Apply patches from Oleg Tyshev to improve OOS processing - (BUG#28241) - - 2009-12-06: Simon Goldschmidt - * ppp.h/.c: Fixed bug #27079 (Yet another leak in PPP): outpacket_buf can - be statically allocated (like in ucip) - - 2009-12-04: Simon Goldschmidt (patch by Ioardan Neshev) - * pap.c: patch #6969: PPP: missing PAP authentication UNTIMEOUT - - 2009-12-03: Simon Goldschmidt - * tcp.h, tcp_in.c, tcp_out.c: Fixed bug #28106: dup ack for fast retransmit - could have non-zero length - - 2009-12-02: Simon Goldschmidt - * tcp_in.c: Fixed bug #27904: TCP sends too many ACKs: delay resetting - tcp_input_pcb until after calling the pcb's callbacks - - 2009-11-29: Simon Goldschmidt - * tcp_in.c: Fixed bug #28054: Two segments with FIN flag on the out-of- - sequence queue, also fixed PBUF_POOL leak in the out-of-sequence code - - 2009-11-29: Simon Goldschmidt - * pbuf.c: Fixed bug #28064: pbuf_alloc(PBUF_POOL) is not thread-safe by - queueing a call into tcpip_thread to free ooseq-bufs if the pool is empty - - 2009-11-26: Simon Goldschmidt - * tcp.h: Fixed bug #28098: Nagle can prevent fast retransmit from sending - segment - - 2009-11-26: Simon Goldschmidt - * tcp.h, sockets.c: Fixed bug #28099: API required to disable Nagle - algorithm at PCB level - - 2009-11-22: Simon Goldschmidt - * tcp_out.c: Fixed bug #27905: FIN isn't combined with data on unsent - - 2009-11-22: Simon Goldschmidt (suggested by Bill Auerbach) - * tcp.c: tcp_alloc: prevent increasing stats.err for MEMP_TCP_PCB when - reusing time-wait pcb - - 2009-11-20: Simon Goldschmidt (patch by Albert Bartel) - * sockets.c: Fixed bug #28062: Data received directly after accepting - does not wake up select - - 2009-11-11: Simon Goldschmidt - * netdb.h: Fixed bug #27994: incorrect define for freeaddrinfo(addrinfo) - - 2009-10-30: Simon Goldschmidt - * opt.h: Increased default value for TCP_MSS to 536, updated default - value for TCP_WND to 4*TCP_MSS to keep delayed ACK working. - - 2009-10-28: Kieran Mansley - * tcp_in.c, tcp_out.c, tcp.h: re-work the fast retransmission code - to follow algorithm from TCP/IP Illustrated - - 2009-10-27: Kieran Mansley - * tcp_in.c: fix BUG#27445: grow cwnd with every duplicate ACK - - 2009-10-25: Simon Goldschmidt - * tcp.h: bug-fix in the TCP_EVENT_RECV macro (has to call tcp_recved if - pcb->recv is NULL to keep rcv_wnd correct) - - 2009-10-25: Simon Goldschmidt - * tcp_in.c: Fixed bug #26251: RST process in TIME_WAIT TCP state - - 2009-10-23: Simon Goldschmidt (David Empson) - * tcp.c: Fixed bug #27783: Silly window avoidance for small window sizes - - 2009-10-21: Simon Goldschmidt - * tcp_in.c: Fixed bug #27215: TCP sent() callback gives leading and - trailing 1 byte len (SYN/FIN) - - 2009-10-21: Simon Goldschmidt - * tcp_out.c: Fixed bug #27315: zero window probe and FIN - - 2009-10-19: Simon Goldschmidt - * dhcp.c/.h: Minor code simplification (don't store received pbuf, change - conditional code to assert where applicable), check pbuf length before - testing for valid reply - - 2009-10-19: Simon Goldschmidt - * dhcp.c: Removed most calls to udp_connect since they aren't necessary - when using udp_sendto_if() - always stay connected to IP_ADDR_ANY. - - 2009-10-16: Simon Goldschmidt - * ip.c: Fixed bug #27390: Source IP check in ip_input() causes it to drop - valid DHCP packets -> allow 0.0.0.0 as source address when LWIP_DHCP is - enabled - - 2009-10-15: Simon Goldschmidt (Oleg Tyshev) - * tcp_in.c: Fixed bug #27329: dupacks by unidirectional data transmit - - 2009-10-15: Simon Goldschmidt - * api_lib.c: Fixed bug #27709: conn->err race condition on netconn_recv() - timeout - - 2009-10-15: Simon Goldschmidt - * autoip.c: Fixed bug #27704: autoip starts with wrong address - LWIP_AUTOIP_CREATE_SEED_ADDR() returned address in host byte order instead - of network byte order - - 2009-10-11 Simon Goldschmidt (Jörg Kesten) - * tcp_out.c: Fixed bug #27504: tcp_enqueue wrongly concatenates segments - which are not consecutive when retransmitting unacked segments - - 2009-10-09 Simon Goldschmidt - * opt.h: Fixed default values of some stats to only be enabled if used - Fixes bug #27338: sys_stats is defined when NO_SYS = 1 - - 2009-08-30 Simon Goldschmidt - * ip.c: Fixed bug bug #27345: "ip_frag() does not use the LWIP_NETIF_LOOPBACK - function" by checking for loopback before calling ip_frag - - 2009-08-25 Simon Goldschmidt - * dhcp.c: fixed invalid dependency to etharp_query if DHCP_DOES_ARP_CHECK==0 - - 2009-08-23 Simon Goldschmidt - * ppp.c: bug #27078: Possible memory leak in pppInit() - - 2009-08-23 Simon Goldschmidt - * netdb.c, dns.c: bug #26657: DNS, if host name is "localhost", result - is error. - - 2009-08-23 Simon Goldschmidt - * opt.h, init.c: bug #26649: TCP fails when TCP_MSS > TCP_SND_BUF - Fixed wrong parenthesis, added check in init.c - - 2009-08-23 Simon Goldschmidt - * ppp.c: bug #27266: wait-state debug message in pppMain occurs every ms - - 2009-08-23 Simon Goldschmidt - * many ppp files: bug #27267: Added include to string.h where needed - - 2009-08-23 Simon Goldschmidt - * tcp.h: patch #6843: tcp.h macro optimization patch (for little endian) - - -(STABLE-1.3.1) - - ++ New features: - - 2009-05-10 Simon Goldschmidt - * opt.h, sockets.c, pbuf.c, netbuf.h, pbuf.h: task #7013: Added option - LWIP_NETIF_TX_SINGLE_PBUF to try to create transmit packets from only - one pbuf to help MACs that don't support scatter-gather DMA. - - 2009-05-09 Simon Goldschmidt - * icmp.h, icmp.c: Shrinked ICMP code, added option to NOT check icoming - ECHO pbuf for size (just use it): LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN - - 2009-05-05 Simon Goldschmidt, Jakob Stoklund Olesen - * ip.h, ip.c: Added ip_current_netif() & ip_current_header() to receive - extended info about the currently received packet. - - 2009-04-27 Simon Goldschmidt - * sys.h: Made SYS_LIGHTWEIGHT_PROT and sys_now() work with NO_SYS=1 - - 2009-04-25 Simon Goldschmidt - * mem.c, opt.h: Added option MEM_USE_POOLS_TRY_BIGGER_POOL to try the next - bigger malloc pool if one is empty (only usable with MEM_USE_POOLS). - - 2009-04-21 Simon Goldschmidt - * dns.c, init.c, dns.h, opt.h: task #7507, patch #6786: DNS supports static - hosts table. New configuration options DNS_LOCAL_HOSTLIST and - DNS_LOCAL_HOSTLIST_IS_DYNAMIC. Also, DNS_LOOKUP_LOCAL_EXTERN() can be defined - as an external function for lookup. - - 2009-04-15 Simon Goldschmidt - * dhcp.c: patch #6763: Global DHCP XID can be redefined to something more unique - - 2009-03-31 Kieran Mansley - * tcp.c, tcp_out.c, tcp_in.c, sys.h, tcp.h, opts.h: add support for - TCP timestamp options, off by default. Rework tcp_enqueue() to - take option flags rather than specified option data - - 2009-02-18 Simon Goldschmidt - * cc.h: Added printf formatter for size_t: SZT_F - - 2009-02-16 Simon Goldschmidt (patch by Rishi Khan) - * icmp.c, opt.h: patch #6539: (configurable) response to broadcast- and multicast - pings - - 2009-02-12 Simon Goldschmidt - * init.h: Added LWIP_VERSION to get the current version of the stack - - 2009-02-11 Simon Goldschmidt (suggested by Gottfried Spitaler) - * opt.h, memp.h/.c: added MEMP_MEM_MALLOC to use mem_malloc/mem_free instead - of the pool allocator (can save code size with MEM_LIBC_MALLOC if libc-malloc - is otherwise used) - - 2009-01-28 Jonathan Larmour (suggested by Bill Bauerbach) - * ipv4/inet_chksum.c, ipv4/lwip/inet_chksum.h: inet_chksum_pseudo_partial() - is only used by UDPLITE at present, so conditionalise it. - - 2008-12-03 Simon Goldschmidt (base on patch from Luca Ceresoli) - * autoip.c: checked in (slightly modified) patch #6683: Customizable AUTOIP - "seed" address. This should reduce AUTOIP conflicts if - LWIP_AUTOIP_CREATE_SEED_ADDR is overridden. - - 2008-10-02 Jonathan Larmour and Rishi Khan - * sockets.c (lwip_accept): Return EWOULDBLOCK if would block on non-blocking - socket. - - 2008-06-30 Simon Goldschmidt - * mem.c, opt.h, stats.h: fixed bug #21433: Calling mem_free/pbuf_free from - interrupt context isn't safe: LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT allows - mem_free to run between mem_malloc iterations. Added illegal counter for - mem stats. - - 2008-06-27 Simon Goldschmidt - * stats.h/.c, some other files: patch #6483: stats module improvement: - Added defines to display each module's statistic individually, added stats - defines for MEM, MEMP and SYS modules, removed (unused) rexmit counter. - - 2008-06-17 Simon Goldschmidt - * err.h: patch #6459: Made err_t overridable to use a more efficient type - (define LWIP_ERR_T in cc.h) - - 2008-06-17 Simon Goldschmidt - * slipif.c: patch #6480: Added a configuration option for slipif for symmetry - to loopif - - 2008-06-17 Simon Goldschmidt (patch by Luca Ceresoli) - * netif.c, loopif.c, ip.c, netif.h, loopif.h, opt.h: Checked in slightly - modified version of patch # 6370: Moved loopif code to netif.c so that - loopback traffic is supported on all netifs (all local IPs). - Added option to limit loopback packets for each netifs. - - - ++ Bugfixes: - 2009-08-12 Kieran Mansley - * tcp_in.c, tcp.c: Fix bug #27209: handle trimming of segments when - out of window or out of order properly - - 2009-08-12 Kieran Mansley - * tcp_in.c: Fix bug #27199: use snd_wl2 instead of snd_wl1 - - 2009-07-28 Simon Goldschmidt - * mem.h: Fixed bug #27105: "realloc() cannot replace mem_realloc()"s - - 2009-07-27 Kieran Mansley - * api.h api_msg.h netdb.h sockets.h: add missing #include directives - - 2009-07-09 Kieran Mansley - * api_msg.c, sockets.c, api.h: BUG23240 use signed counters for - recv_avail and don't increment counters until message successfully - sent to mbox - - 2009-06-25 Kieran Mansley - * api_msg.c api.h: BUG26722: initialise netconn write variables - in netconn_alloc - - 2009-06-25 Kieran Mansley - * tcp.h: BUG26879: set ret value in TCP_EVENT macros when function is not set - - 2009-06-25 Kieran Mansley - * tcp.c, tcp_in.c, tcp_out.c, tcp.h: BUG26301 and BUG26267: correct - simultaneous close behaviour, and make snd_nxt have the same meaning - as in the RFCs. - - 2009-05-12 Simon Goldschmidt - * etharp.h, etharp.c, netif.c: fixed bug #26507: "Gratuitous ARP depends on - arp_table / uses etharp_query" by adding etharp_gratuitous() - - 2009-05-12 Simon Goldschmidt - * ip.h, ip.c, igmp.c: bug #26487: Added ip_output_if_opt that can add IP options - to the IP header (used by igmp_ip_output_if) - - 2009-05-06 Simon Goldschmidt - * inet_chksum.c: On little endian architectures, use LWIP_PLATFORM_HTONS (if - defined) for SWAP_BYTES_IN_WORD to speed up checksumming. - - 2009-05-05 Simon Goldschmidt - * sockets.c: bug #26405: Prematurely released semaphore causes lwip_select() - to crash - - 2009-05-04 Simon Goldschmidt - * init.c: snmp was not initialized in lwip_init() - - 2009-05-04 Frédéric Bernon - * dhcp.c, netbios.c: Changes if IP_SOF_BROADCAST is enabled. - - 2009-05-03 Simon Goldschmidt - * tcp.h: bug #26349: Nagle algorithm doesn't send although segment is full - (and unsent->next == NULL) - - 2009-05-02 Simon Goldschmidt - * tcpip.h, tcpip.c: fixed tcpip_untimeout (does not need the time, broken after - 1.3.0 in CVS only) - fixes compilation of ppp_oe.c - - 2009-05-02 Simon Goldschmidt - * msg_in.c: fixed bug #25636: SNMPSET value is ignored for integer fields - - 2009-05-01 Simon Goldschmidt - * pap.c: bug #21680: PPP upap_rauthnak() drops legal NAK packets - - 2009-05-01 Simon Goldschmidt - * ppp.c: bug #24228: Memory corruption with PPP and DHCP - - 2009-04-29 Frédéric Bernon - * raw.c, udp.c, init.c, opt.h, ip.h, sockets.h: bug #26309: Implement the - SO(F)_BROADCAST filter for all API layers. Avoid the unindented reception - of broadcast packets even when this option wasn't set. Port maintainers - which want to enable this filter have to set IP_SOF_BROADCAST=1 in opt.h. - If you want this option also filter broadcast on recv operations, you also - have to set IP_SOF_BROADCAST_RECV=1 in opt.h. - - 2009-04-28 Simon Goldschmidt, Jakob Stoklund Olesen - * dhcp.c: patch #6721, bugs #25575, #25576: Some small fixes to DHCP and - DHCP/AUTOIP cooperation - - 2009-04-25 Simon Goldschmidt, Oleg Tyshev - * tcp_out.c: bug #24212: Deadlocked tcp_retransmit due to exceeded pcb->cwnd - Fixed by sorting the unsent and unacked queues (segments are inserted at the - right place in tcp_output and tcp_rexmit). - - 2009-04-25 Simon Goldschmidt - * memp.c, mem.c, memp.h, mem_std.h: bug #26213 "Problem with memory allocation - when debugging": memp_sizes contained the wrong sizes (including sanity - regions); memp pools for MEM_USE_POOLS were too small - - 2009-04-24 Simon Goldschmidt, Frédéric Bernon - * inet.c: patch #6765: Fix a small problem with the last changes (incorrect - behavior, with with ip address string not ended by a '\0', a space or a - end of line) - - 2009-04-19 Simon Goldschmidt - * rawapi.txt: Fixed bug #26069: Corrected documentation: if tcp_connect fails, - pcb->err is called, not pcb->connected (with an error code). - - 2009-04-19 Simon Goldschmidt - * tcp_out.c: Fixed bug #26236: "TCP options (timestamp) don't work with - no-copy-tcpwrite": deallocate option data, only concat segments with same flags - - 2009-04-19 Simon Goldschmidt - * tcp_out.c: Fixed bug #25094: "Zero-length pbuf" (options are now allocated - in the header pbuf, not the data pbuf) - - 2009-04-18 Simon Goldschmidt - * api_msg.c: fixed bug #25695: Segmentation fault in do_writemore() - - 2009-04-15 Simon Goldschmidt - * sockets.c: tried to fix bug #23559: lwip_recvfrom problem with tcp - - 2009-04-15 Simon Goldschmidt - * dhcp.c: task #9192: mem_free of dhcp->options_in and dhcp->msg_in - - 2009-04-15 Simon Goldschmidt - * ip.c, ip6.c, tcp_out.c, ip.h: patch #6808: Add a utility function - ip_hinted_output() (for smaller code mainly) - - 2009-04-15 Simon Goldschmidt - * inet.c: patch #6765: Supporting new line characters in inet_aton() - - 2009-04-15 Simon Goldschmidt - * dhcp.c: patch #6764: DHCP rebind and renew did not send hostnam option; - Converted constant OPTION_MAX_MSG_SIZE to netif->mtu, check if netif->mtu - is big enough in dhcp_start - - 2009-04-15 Simon Goldschmidt - * netbuf.c: bug #26027: netbuf_chain resulted in pbuf memory leak - - 2009-04-15 Simon Goldschmidt - * sockets.c, ppp.c: bug #25763: corrected 4 occurrences of SMEMCPY to MEMCPY - - 2009-04-15 Simon Goldschmidt - * sockets.c: bug #26121: set_errno can be overridden - - 2009-04-09 Kieran Mansley (patch from Luca Ceresoli ) - * init.c, opt.h: Patch#6774 TCP_QUEUE_OOSEQ breaks compilation when - LWIP_TCP==0 - - 2009-04-09 Kieran Mansley (patch from Roy Lee ) - * tcp.h: Patch#6802 Add do-while-clauses to those function like - macros in tcp.h - - 2009-03-31 Kieran Mansley - * tcp.c, tcp_in.c, tcp_out.c, tcp.h, opt.h: Rework the way window - updates are calculated and sent (BUG20515) - - * tcp_in.c: cope with SYN packets received during established states, - and retransmission of initial SYN. - - * tcp_out.c: set push bit correctly when tcp segments are merged - - 2009-03-27 Kieran Mansley - * tcp_out.c set window correctly on probes (correcting change made - yesterday) - - 2009-03-26 Kieran Mansley - * tcp.c, tcp_in.c, tcp.h: add tcp_abandon() to cope with dropping - connections where no reset required (bug #25622) - - * tcp_out.c: set TCP_ACK flag on keepalive and zero window probes - (bug #20779) - - 2009-02-18 Simon Goldschmidt (Jonathan Larmour and Bill Auerbach) - * ip_frag.c: patch #6528: the buffer used for IP_FRAG_USES_STATIC_BUF could be - too small depending on MEM_ALIGNMENT - - 2009-02-16 Simon Goldschmidt - * sockets.h/.c, api_*.h/.c: fixed arguments of socket functions to match the standard; - converted size argument of netconn_write to 'size_t' - - 2009-02-16 Simon Goldschmidt - * tcp.h, tcp.c: fixed bug #24440: TCP connection close problem on 64-bit host - by moving accept callback function pointer to TCP_PCB_COMMON - - 2009-02-12 Simon Goldschmidt - * dhcp.c: fixed bug #25345 (DHCPDECLINE is sent with "Maximum message size" - option) - - 2009-02-11 Simon Goldschmidt - * dhcp.c: fixed bug #24480 (releasing old udp_pdb and pbuf in dhcp_start) - - 2009-02-11 Simon Goldschmidt - * opt.h, api_msg.c: added configurable default valud for netconn->recv_bufsize: - RECV_BUFSIZE_DEFAULT (fixes bug #23726: pbuf pool exhaustion on slow recv()) - - 2009-02-10 Simon Goldschmidt - * tcp.c: fixed bug #25467: Listen backlog is not reset on timeout in SYN_RCVD: - Accepts_pending is decrease on a corresponding listen pcb when a connection - in state SYN_RCVD is close. - - 2009-01-28 Jonathan Larmour - * pbuf.c: reclaim pbufs from TCP out-of-sequence segments if we run - out of pool pbufs. - - 2008-12-19 Simon Goldschmidt - * many files: patch #6699: fixed some warnings on platform where sizeof(int) == 2 - - 2008-12-10 Tamas Somogyi, Frédéric Bernon - * sockets.c: fixed bug #25051: lwip_recvfrom problem with udp: fromaddr and - port uses deleted netbuf. - - 2008-10-18 Simon Goldschmidt - * tcp_in.c: fixed bug ##24596: Vulnerability on faulty TCP options length - in tcp_parseopt - - 2008-10-15 Simon Goldschmidt - * ip_frag.c: fixed bug #24517: IP reassembly crashes on unaligned IP headers - by packing the struct ip_reass_helper. - - 2008-10-03 David Woodhouse, Jonathan Larmour - * etharp.c (etharp_arp_input): Fix type aliasing problem copying ip address. - - 2008-10-02 Jonathan Larmour - * dns.c: Hard-code structure sizes, to avoid issues on some compilers where - padding is included. - - 2008-09-30 Jonathan Larmour - * sockets.c (lwip_accept): check addr isn't NULL. If it's valid, do an - assertion check that addrlen isn't NULL. - - 2008-09-30 Jonathan Larmour - * tcp.c: Fix bug #24227, wrong error message in tcp_bind. - - 2008-08-26 Simon Goldschmidt - * inet.h, ip_addr.h: fixed bug #24132: Cross-dependency between ip_addr.h and - inet.h -> moved declaration of struct in_addr from ip_addr.h to inet.h - - 2008-08-14 Simon Goldschmidt - * api_msg.c: fixed bug #23847: do_close_internal references freed memory (when - tcp_close returns != ERR_OK) - - 2008-07-08 Frédéric Bernon - * stats.h: Fix some build bugs introduced with patch #6483 (missing some parameters - in macros, mainly if MEM_STATS=0 and MEMP_STATS=0). - - 2008-06-24 Jonathan Larmour - * tcp_in.c: Fix for bug #23693 as suggested by Art R. Ensure cseg is unused - if tcp_seg_copy fails. - - 2008-06-17 Simon Goldschmidt - * inet_chksum.c: Checked in some ideas of patch #6460 (loop optimizations) - and created defines for swapping bytes and folding u32 to u16. - - 2008-05-30 Kieran Mansley - * tcp_in.c Remove redundant "if" statement, and use real rcv_wnd - rather than rcv_ann_wnd when deciding if packets are in-window. - Contributed by - - 2008-05-30 Kieran Mansley - * mem.h: Fix BUG#23254. Change macro definition of mem_* to allow - passing as function pointers when MEM_LIBC_MALLOC is defined. - - 2008-05-09 Jonathan Larmour - * err.h, err.c, sockets.c: Fix bug #23119: Reorder timeout error code to - stop it being treated as a fatal error. - - 2008-04-15 Simon Goldschmidt - * dhcp.c: fixed bug #22804: dhcp_stop doesn't clear NETIF_FLAG_DHCP - (flag now cleared) - - 2008-03-27 Simon Goldschmidt - * mem.c, tcpip.c, tcpip.h, opt.h: fixed bug #21433 (Calling mem_free/pbuf_free - from interrupt context isn't safe): set LWIP_USE_HEAP_FROM_INTERRUPT to 1 - in lwipopts.h or use pbuf_free_callback(p)/mem_free_callback(m) to free pbufs - or heap memory from interrupt context - - 2008-03-26 Simon Goldschmidt - * tcp_in.c, tcp.c: fixed bug #22249: division by zero could occur if a remote - host sent a zero mss as TCP option. - - -(STABLE-1.3.0) - - ++ New features: - - 2008-03-10 Jonathan Larmour - * inet_chksum.c: Allow choice of one of the sample algorithms to be - made from lwipopts.h. Fix comment on how to override LWIP_CHKSUM. - - 2008-01-22 Frédéric Bernon - * tcp.c, tcp_in.c, tcp.h, opt.h: Rename LWIP_CALCULATE_EFF_SEND_MSS in - TCP_CALCULATE_EFF_SEND_MSS to have coherent TCP options names. - - 2008-01-14 Frédéric Bernon - * rawapi.txt, api_msg.c, tcp.c, tcp_in.c, tcp.h: changes for task #7675 "Enable - to refuse data on a TCP_EVENT_RECV call". Important, behavior changes for the - tcp_recv callback (see rawapi.txt). - - 2008-01-14 Frédéric Bernon, Marc Chaland - * ip.c: Integrate patch #6369" ip_input : checking before realloc". - - 2008-01-12 Frédéric Bernon - * tcpip.h, tcpip.c, api.h, api_lib.c, api_msg.c, sockets.c: replace the field - netconn::sem per netconn::op_completed like suggested for the task #7490 - "Add return value to sys_mbox_post". - - 2008-01-12 Frédéric Bernon - * api_msg.c, opt.h: replace DEFAULT_RECVMBOX_SIZE per DEFAULT_TCP_RECVMBOX_SIZE, - DEFAULT_UDP_RECVMBOX_SIZE and DEFAULT_RAW_RECVMBOX_SIZE (to optimize queues - sizes), like suggested for the task #7490 "Add return value to sys_mbox_post". - - 2008-01-10 Frédéric Bernon - * tcpip.h, tcpip.c: add tcpip_callback_with_block function for the task #7490 - "Add return value to sys_mbox_post". tcpip_callback is always defined as - "blocking" ("block" parameter = 1). - - 2008-01-10 Frédéric Bernon - * tcpip.h, tcpip.c, api.h, api_lib.c, api_msg.c, sockets.c: replace the field - netconn::mbox (sys_mbox_t) per netconn::sem (sys_sem_t) for the task #7490 - "Add return value to sys_mbox_post". - - 2008-01-05 Frédéric Bernon - * sys_arch.txt, api.h, api_lib.c, api_msg.h, api_msg.c, tcpip.c, sys.h, opt.h: - Introduce changes for task #7490 "Add return value to sys_mbox_post" with some - modifications in the sys_mbox api: sys_mbox_new take a "size" parameters which - indicate the number of pointers query by the mailbox. There is three defines - in opt.h to indicate sizes for tcpip::mbox, netconn::recvmbox, and for the - netconn::acceptmbox. Port maintainers, you can decide to just add this new - parameter in your implementation, but to ignore it to keep the previous behavior. - The new sys_mbox_trypost function return a value to know if the mailbox is - full or if the message is posted. Take a look to sys_arch.txt for more details. - This new function is used in tcpip_input (so, can be called in an interrupt - context since the function is not blocking), and in recv_udp and recv_raw. - - 2008-01-04 Frédéric Bernon, Simon Goldschmidt, Jonathan Larmour - * rawapi.txt, api.h, api_lib.c, api_msg.h, api_msg.c, sockets.c, tcp.h, tcp.c, - tcp_in.c, init.c, opt.h: rename backlog options with TCP_ prefix, limit the - "backlog" parameter in an u8_t, 0 is interpreted as "smallest queue", add - documentation in the rawapi.txt file. - - 2007-12-31 Kieran Mansley (based on patch from Per-Henrik Lundbolm) - * tcp.c, tcp_in.c, tcp_out.c, tcp.h: Add TCP persist timer - - 2007-12-31 Frédéric Bernon, Luca Ceresoli - * autoip.c, etharp.c: ip_addr.h: Integrate patch #6348: "Broadcast ARP packets - in autoip". The change in etharp_raw could be removed, since all calls to - etharp_raw use ethbroadcast for the "ethdst_addr" parameter. But it could be - wrong in the future. - - 2007-12-30 Frédéric Bernon, Tom Evans - * ip.c: Fix bug #21846 "LwIP doesn't appear to perform any IP Source Address - Filtering" reported by Tom Evans. - - 2007-12-21 Frédéric Bernon, Simon Goldschmidt, Jonathan Larmour - * tcp.h, opt.h, api.h, api_msg.h, tcp.c, tcp_in.c, api_lib.c, api_msg.c, - sockets.c, init.c: task #7252: Implement TCP listen backlog: Warning: raw API - applications have to call 'tcp_accepted(pcb)' in their accept callback to - keep accepting new connections. - - 2007-12-13 Frédéric Bernon - * api_msg.c, err.h, err.c, sockets.c, dns.c, dns.h: replace "enum dns_result" - by err_t type. Add a new err_t code "ERR_INPROGRESS". - - 2007-12-12 Frédéric Bernon - * dns.h, dns.c, opt.h: move DNS options to the "right" place. Most visibles - are the one which have ram usage. - - 2007-12-05 Frédéric Bernon - * netdb.c: add a LWIP_DNS_API_HOSTENT_STORAGE option to decide to use a static - set of variables (=0) or a local one (=1). In this last case, your port should - provide a function "struct hostent* sys_thread_hostent( struct hostent* h)" - which have to do a copy of "h" and return a pointer ont the "per-thread" copy. - - 2007-12-03 Simon Goldschmidt - * ip.c: ip_input: check if a packet is for inp first before checking all other - netifs on netif_list (speeds up packet receiving in most cases) - - 2007-11-30 Simon Goldschmidt - * udp.c, raw.c: task #7497: Sort lists (pcb, netif, ...) for faster access - UDP: move a (connected) pcb selected for input to the front of the list of - pcbs so that it is found faster next time. Same for RAW pcbs that have eaten - a packet. - - 2007-11-28 Simon Goldschmidt - * etharp.c, stats.c, stats.h, opt.h: Introduced ETHARP_STATS - - 2007-11-25 Simon Goldschmidt - * dhcp.c: dhcp_unfold_reply() uses pbuf_copy_partial instead of its own copy - algorithm. - - 2007-11-24 Simon Goldschmidt - * netdb.h, netdb.c, sockets.h/.c: Moved lwip_gethostbyname from sockets.c - to the new file netdb.c; included lwip_getaddrinfo. - - 2007-11-21 Simon Goldschmidt - * tcp.h, opt.h, tcp.c, tcp_in.c: implemented calculating the effective send-mss - based on the MTU of the netif used to send. Enabled by default. Disable by - setting LWIP_CALCULATE_EFF_SEND_MSS to 0. This fixes bug #21492. - - 2007-11-19 Frédéric Bernon - * api_msg.c, dns.h, dns.c: Implement DNS_DOES_NAME_CHECK option (check if name - received match the name query), implement DNS_USES_STATIC_BUF (the place where - copy dns payload to parse the response), return an error if there is no place - for a new query, and fix some minor problems. - - 2007-11-16 Simon Goldschmidt - * new files: ipv4/inet.c, ipv4/inet_chksum.c, ipv6/inet6.c - removed files: core/inet.c, core/inet6.c - Moved inet files into ipv4/ipv6 directory; splitted inet.c/inet.h into - inet and chksum part; changed includes in all lwIP files as appropriate - - 2007-11-16 Simon Goldschmidt - * api.h, api_msg.h, api_lib.c, api_msg.c, socket.h, socket.c: Added sequential - dns resolver function for netconn api (netconn_gethostbyname) and socket api - (gethostbyname/gethostbyname_r). - - 2007-11-15 Jim Pettinato, Frédéric Bernon - * opt.h, init.c, tcpip.c, dhcp.c, dns.h, dns.c: add DNS client for simple name - requests with RAW api interface. Initialization is done in lwip_init() with - build time options. DNS timer is added in tcpip_thread context. DHCP can set - DNS server ip addresses when options are received. You need to set LWIP_DNS=1 - in your lwipopts.h file (LWIP_DNS=0 in opt.h). DNS_DEBUG can be set to get - some traces with LWIP_DEBUGF. Sanity check have been added. There is a "todo" - list with points to improve. - - 2007-11-06 Simon Goldschmidt - * opt.h, mib2.c: Patch #6215: added ifAdminStatus write support (if explicitly - enabled by defining SNMP_SAFE_REQUESTS to 0); added code to check link status - for ifOperStatus if LWIP_NETIF_LINK_CALLBACK is defined. - - 2007-11-06 Simon Goldschmidt - * api.h, api_msg.h and dependent files: Task #7410: Removed the need to include - core header files in api.h (ip/tcp/udp/raw.h) to hide the internal - implementation from netconn api applications. - - 2007-11-03 Frédéric Bernon - * api.h, api_lib.c, api_msg.c, sockets.c, opt.h: add SO_RCVBUF option for UDP & - RAW netconn. You need to set LWIP_SO_RCVBUF=1 in your lwipopts.h (it's disabled - by default). Netconn API users can use the netconn_recv_bufsize macro to access - it. This is a first release which have to be improve for TCP. Note it used the - netconn::recv_avail which need to be more "thread-safe" (note there is already - the problem for FIONREAD with lwip_ioctl/ioctlsocket). - - 2007-11-01 Frédéric Bernon, Marc Chaland - * sockets.h, sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c, tcp.h, tcp_out.c: - Integrate "patch #6250 : MSG_MORE flag for send". MSG_MORE is used at socket api - layer, NETCONN_MORE at netconn api layer, and TCP_WRITE_FLAG_MORE at raw api - layer. This option enable to delayed TCP PUSH flag on multiple "write" calls. - Note that previous "copy" parameter for "write" APIs is now called "apiflags". - - 2007-10-24 Frédéric Bernon - * api.h, api_lib.c, api_msg.c: Add macro API_EVENT in the same spirit than - TCP_EVENT_xxx macros to get a code more readable. It could also help to remove - some code (like we have talk in "patch #5919 : Create compile switch to remove - select code"), but it could be done later. - - 2007-10-08 Simon Goldschmidt - * many files: Changed initialization: many init functions are not needed any - more since we now rely on the compiler initializing global and static - variables to zero! - - 2007-10-06 Simon Goldschmidt - * ip_frag.c, memp.c, mib2.c, ip_frag.h, memp_std.h, opt.h: Changed IP_REASSEMBLY - to enqueue the received pbufs so that multiple packets can be reassembled - simultaneously and no static reassembly buffer is needed. - - 2007-10-05 Simon Goldschmidt - * tcpip.c, etharp.h, etharp.c: moved ethernet_input from tcpip.c to etharp.c so - all netifs (or ports) can use it. - - 2007-10-05 Frédéric Bernon - * netifapi.h, netifapi.c: add function netifapi_netif_set_default. Change the - common function to reduce a little bit the footprint (for all functions using - only the "netif" parameter). - - 2007-10-03 Frédéric Bernon - * netifapi.h, netifapi.c: add functions netifapi_netif_set_up, netifapi_netif_set_down, - netifapi_autoip_start and netifapi_autoip_stop. Use a common function to reduce - a little bit the footprint (for all functions using only the "netif" parameter). - - 2007-09-15 Frédéric Bernon - * udp.h, udp.c, sockets.c: Changes for "#20503 IGMP Improvement". Add IP_MULTICAST_IF - option in socket API, and a new field "multicast_ip" in "struct udp_pcb" (for - netconn and raw API users), only if LWIP_IGMP=1. Add getsockopt processing for - IP_MULTICAST_TTL and IP_MULTICAST_IF. - - 2007-09-10 Frédéric Bernon - * snmp.h, mib2.c: enable to remove SNMP timer (which consumne several cycles - even when it's not necessary). snmp_agent.txt tell to call snmp_inc_sysuptime() - each 10ms (but, it's intrusive if you use sys_timeout feature). Now, you can - decide to call snmp_add_sysuptime(100) each 1000ms (which is bigger "step", but - call to a lower frequency). Or, you can decide to not call snmp_inc_sysuptime() - or snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro. - This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside - snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only - when it's queried (any direct call to "sysuptime" is changed by a call to - snmp_get_sysuptime). - - 2007-09-09 Frédéric Bernon, Bill Florac - * igmp.h, igmp.c, netif.h, netif.c, ip.c: To enable to have interfaces with IGMP, - and others without it, there is a new NETIF_FLAG_IGMP flag to set in netif->flags - if you want IGMP on an interface. igmp_stop() is now called inside netif_remove(). - igmp_report_groups() is now called inside netif_set_link_up() (need to have - LWIP_NETIF_LINK_CALLBACK=1) to resend reports once the link is up (avoid to wait - the next query message to receive the matching multicast streams). - - 2007-09-08 Frédéric Bernon - * sockets.c, ip.h, api.h, tcp.h: declare a "struct ip_pcb" which only contains - IP_PCB. Add in the netconn's "pcb" union a "struct ip_pcb *ip;" (no size change). - Use this new field to access to common pcb fields (ttl, tos, so_options, etc...). - Enable to access to these fields with LWIP_TCP=0. - - 2007-09-05 Frédéric Bernon - * udp.c, ipv4/icmp.c, ipv4/ip.c, ipv6/icmp.c, ipv6/ip6.c, ipv4/icmp.h, - ipv6/icmp.h, opt.h: Integrate "task #7272 : LWIP_ICMP option". The new option - LWIP_ICMP enable/disable ICMP module inside the IP stack (enable per default). - Be careful, disabling ICMP make your product non-compliant to RFC1122, but - help to reduce footprint, and to reduce "visibility" on the Internet. - - 2007-09-05 Frédéric Bernon, Bill Florac - * opt.h, sys.h, tcpip.c, slipif.c, ppp.c, sys_arch.txt: Change parameters list - for sys_thread_new (see "task #7252 : Create sys_thread_new_ex()"). Two new - parameters have to be provided: a task name, and a task stack size. For this - one, since it's platform dependant, you could define the best one for you in - your lwipopts.h. For port maintainers, you can just add these new parameters - in your sys_arch.c file, and but it's not mandatory, use them in your OS - specific functions. - - 2007-09-05 Frédéric Bernon - * inet.c, autoip.c, msg_in.c, msg_out.c, init.c: Move some build time checkings - inside init.c for task #7142 "Sanity check user-configurable values". - - 2007-09-04 Frédéric Bernon, Bill Florac - * igmp.h, igmp.c, memp_std.h, memp.c, init.c, opt.h: Replace mem_malloc call by - memp_malloc, and use a new MEMP_NUM_IGMP_GROUP option (see opt.h to define the - value). It will avoid potential fragmentation problems, use a counter to know - how many times a group is used on an netif, and free it when all applications - leave it. MEMP_NUM_IGMP_GROUP got 8 as default value (and init.c got a sanity - check if LWIP_IGMP!=0). - - 2007-09-03 Frédéric Bernon - * igmp.h, igmp.c, sockets.c, api_msg.c: Changes for "#20503 IGMP Improvement". - Initialize igmp_mac_filter to NULL in netif_add (this field should be set in - the netif's "init" function). Use the "imr_interface" field (for socket layer) - and/or the "interface" field (for netconn layer), for join/leave operations. - The igmp_join/leavegroup first parameter change from a netif to an ipaddr. - This field could be a netif's ipaddr, or "any" (same meaning than ip_addr_isany). - - 2007-08-30 Frédéric Bernon - * Add netbuf.h, netbuf.c, Change api.h, api_lib.c: #7249 "Split netbuf functions - from api/api_lib". Now netbuf API is independant of netconn, and can be used - with other API (application based on raw API, or future "socket2" API). Ports - maintainers just have to add src/api/netbuf.c in their makefile/projects. - - 2007-08-30 Frédéric Bernon, Jonathan Larmour - * init.c: Add first version of lwip_sanity_check for task #7142 "Sanity check - user-configurable values". - - 2007-08-29 Frédéric Bernon - * igmp.h, igmp.c, tcpip.c, init.c, netif.c: change igmp_init and add igmp_start. - igmp_start is call inside netif_add. Now, igmp initialization is in the same - spirit than the others modules. Modify some IGMP debug traces. - - 2007-08-29 Frédéric Bernon - * Add init.h, init.c, Change opt.h, tcpip.c: Task #7213 "Add a lwip_init function" - Add lwip_init function to regroup all modules initializations, and to provide - a place to add code for task #7142 "Sanity check user-configurable values". - Ports maintainers should remove direct initializations calls from their code, - and add init.c in their makefiles. Note that lwip_init() function is called - inside tcpip_init, but can also be used by raw api users since all calls are - disabled when matching options are disabled. Also note that their is new options - in opt.h, you should configure in your lwipopts.h (they are enabled per default). - - 2007-08-26 Marc Boucher - * api_msg.c: do_close_internal(): Reset the callbacks and arg (conn) to NULL - since they can under certain circumstances be called with an invalid conn - pointer after the connection has been closed (and conn has been freed). - - 2007-08-25 Frédéric Bernon (Artem Migaev's Patch) - * netif.h, netif.c: Integrate "patch #6163 : Function to check if link layer is up". - Add a netif_is_link_up() function if LWIP_NETIF_LINK_CALLBACK option is set. - - 2007-08-22 Frédéric Bernon - * netif.h, netif.c, opt.h: Rename LWIP_NETIF_CALLBACK in LWIP_NETIF_STATUS_CALLBACK - to be coherent with new LWIP_NETIF_LINK_CALLBACK option before next release. - - 2007-08-22 Frédéric Bernon - * tcpip.h, tcpip.c, ethernetif.c, opt.h: remove options ETHARP_TCPIP_INPUT & - ETHARP_TCPIP_ETHINPUT, now, only "ethinput" code is supported, even if the - name is tcpip_input (we keep the name of 1.2.0 function). - - 2007-08-17 Jared Grubb - * memp_std.h, memp.h, memp.c, mem.c, stats.c: (Task #7136) Centralize mempool - settings into new memp_std.h and optional user file lwippools.h. This adds - more dynamic mempools, and allows the user to create an arbitrary number of - mempools for mem_malloc. - - 2007-08-16 Marc Boucher - * api_msg.c: Initialize newconn->state to NETCONN_NONE in accept_function; - otherwise it was left to NETCONN_CLOSE and sent_tcp() could prematurely - close the connection. - - 2007-08-16 Marc Boucher - * sockets.c: lwip_accept(): check netconn_peer() error return. - - 2007-08-16 Marc Boucher - * mem.c, mem.h: Added mem_calloc(). - - 2007-08-16 Marc Boucher - * tcpip.c, tcpip.h memp.c, memp.h: Added distinct memp (MEMP_TCPIP_MSG_INPKT) - for input packets to prevent floods from consuming all of MEMP_TCPIP_MSG - and starving other message types. - Renamed MEMP_TCPIP_MSG to MEMP_TCPIP_MSG_API - - 2007-08-16 Marc Boucher - * pbuf.c, pbuf.h, etharp.c, tcp_in.c, sockets.c: Split pbuf flags in pbuf - type and flgs (later renamed to flags). - Use enum pbuf_flag as pbuf_type. Renumber PBUF_FLAG_*. - Improved lwip_recvfrom(). TCP push now propagated. - - 2007-08-16 Marc Boucher - * ethernetif.c, contrib/ports/various: ethbroadcast now a shared global - provided by etharp. - - 2007-08-16 Marc Boucher - * ppp_oe.c ppp_oe.h, auth.c chap.c fsm.c lcp.c ppp.c ppp.h, - etharp.c ethernetif.c, etharp.h, opt.h tcpip.h, tcpip.c: - Added PPPoE support and various PPP improvements. - - 2007-07-25 Simon Goldschmidt - * api_lib.c, ip_frag.c, pbuf.c, api.h, pbuf.h: Introduced pbuf_copy_partial, - making netbuf_copy_partial use this function. - - 2007-07-25 Simon Goldschmidt - * tcp_in.c: Fix bug #20506: Slow start / initial congestion window starts with - 2 * mss (instead of 1 * mss previously) to comply with some newer RFCs and - other stacks. - - 2007-07-13 Jared Grubb (integrated by Frédéric Bernon) - * opt.h, netif.h, netif.c, ethernetif.c: Add new configuration option to add - a link callback in the netif struct, and functions to handle it. Be carefull - for port maintainers to add the NETIF_FLAG_LINK_UP flag (like in ethernetif.c) - if you want to be sure to be compatible with future changes... - - 2007-06-30 Frédéric Bernon - * sockets.h, sockets.c: Implement MSG_PEEK flag for recv/recvfrom functions. - - 2007-06-21 Simon Goldschmidt - * etharp.h, etharp.c: Combined etharp_request with etharp_raw for both - LWIP_AUTOIP =0 and =1 to remove redundant code. - - 2007-06-21 Simon Goldschmidt - * mem.c, memp.c, mem.h, memp.h, opt.h: task #6863: Introduced the option - MEM_USE_POOLS to use 4 pools with different sized elements instead of a - heap. This both prevents memory fragmentation and gives a higher speed - at the cost of more memory consumption. Turned off by default. - - 2007-06-21 Simon Goldschmidt - * api_lib.c, api_msg.c, api.h, api_msg.h: Converted the length argument of - netconn_write (and therefore also api_msg_msg.msg.w.len) from u16_t into - int to be able to send a bigger buffer than 64K with one time (mainly - used from lwip_send). - - 2007-06-21 Simon Goldschmidt - * tcp.h, api_msg.c: Moved the nagle algorithm from netconn_write/do_write - into a define (tcp_output_nagle) in tcp.h to provide it to raw api users, too. - - 2007-06-21 Simon Goldschmidt - * api.h, api_lib.c, api_msg.c: Fixed bug #20021: Moved sendbuf-processing in - netconn_write from api_lib.c to api_msg.c to also prevent multiple context- - changes on low memory or empty send-buffer. - - 2007-06-18 Simon Goldschmidt - * etharp.c, etharp.h: Changed etharp to use a defined hardware address length - of 6 to avoid loading netif->hwaddr_len every time (since this file is only - used for ethernet and struct eth_addr already had a defined length of 6). - - 2007-06-17 Simon Goldschmidt - * sockets.c, sockets.h: Implemented socket options SO_NO_CHECK for UDP sockets - to disable UDP checksum generation on transmit. - - 2007-06-13 Frédéric Bernon, Simon Goldschmidt - * debug.h, api_msg.c: change LWIP_ERROR to use it to check errors like invalid - pointers or parameters, and let the possibility to redefined it in cc.h. Use - this macro to check "conn" parameter in api_msg.c functions. - - 2007-06-11 Simon Goldschmidt - * sockets.c, sockets.h: Added UDP lite support for sockets - - 2007-06-10 Simon Goldschmidt - * udp.h, opt.h, api_msg.c, ip.c, udp.c: Included switch LWIP_UDPLITE (enabled - by default) to switch off UDP-Lite support if not needed (reduces udp.c code - size) - - 2007-06-09 Dominik Spies (integrated by Frédéric Bernon) - * autoip.h, autoip.c, dhcp.h, dhcp.c, netif.h, netif.c, etharp.h, etharp.c, opt.h: - AutoIP implementation available for IPv4, with new options LWIP_AUTOIP and - LWIP_DHCP_AUTOIP_COOP if you want to cooperate with DHCP. Some tips to adapt - (see TODO mark in the source code). - - 2007-06-09 Simon Goldschmidt - * etharp.h, etharp.c, ethernetif.c: Modified order of parameters for - etharp_output() to match netif->output so etharp_output() can be used - directly as netif->output to save one function call. - - 2007-06-08 Simon Goldschmidt - * netif.h, ethernetif.c, slipif.c, loopif.c: Added define - NETIF_INIT_SNMP(netif, type, speed) to initialize per-netif snmp variables, - added initialization of those to ethernetif, slipif and loopif. - - 2007-05-18 Simon Goldschmidt - * opt.h, ip_frag.c, ip_frag.h, ip.c: Added option IP_FRAG_USES_STATIC_BUF - (defaulting to off for now) that can be set to 0 to send fragmented - packets by passing PBUF_REFs down the stack. - - 2007-05-23 Frédéric Bernon - * api_lib.c: Implement SO_RCVTIMEO for accept and recv on TCP - connections, such present in patch #5959. - - 2007-05-23 Frédéric Bernon - * api.h, api_lib.c, api_msg.c, sockets.c: group the different NETCONN_UDPxxx - code in only one part... - - 2007-05-18 Simon Goldschmidt - * opt.h, memp.h, memp.c: Added option MEMP_OVERFLOW_CHECK to check for memp - elements to overflow. This is achieved by adding some bytes before and after - each pool element (increasing their size, of course), filling them with a - prominent value and checking them on freeing the element. - Set it to 2 to also check every element in every pool each time memp_malloc() - or memp_free() is called (slower but more helpful). - - 2007-05-10 Simon Goldschmidt - * opt.h, memp.h, memp.c, pbuf.c (see task #6831): use a new memp pool for - PBUF_POOL pbufs instead of the old pool implementation in pbuf.c to reduce - code size. - - 2007-05-11 Frédéric Bernon - * sockets.c, api_lib.c, api_msg.h, api_msg.c, netifapi.h, netifapi.c, tcpip.c: - Include a function pointer instead of a table index in the message to reduce - footprint. Disable some part of lwip_send and lwip_sendto if some options are - not set (LWIP_TCP, LWIP_UDP, LWIP_RAW). - - 2007-05-10 Simon Goldschmidt - * *.h (except netif/ppp/*.h): Included patch #5448: include '#ifdef __cplusplus - \ extern "C" {' in all header files. Now you can write your application using - the lwIP stack in C++ and simply #include the core files. Note I have left - out the netif/ppp/*h header files for now, since I don't know which files are - included by applications and which are for internal use only. - - 2007-05-09 Simon Goldschmidt - * opt.h, *.c/*.h: Included patch #5920: Create define to override C-library - memcpy. 2 Defines are created: MEMCPY() for normal memcpy, SMEMCPY() for - situations where some compilers might inline the copy and save a function - call. Also replaced all calls to memcpy() with calls to (S)MEMCPY(). - - 2007-05-08 Simon Goldschmidt - * mem.h: If MEM_LIBC_MALLOC==1, allow the defines (e.g. mem_malloc() -> malloc()) - to be overriden in case the C-library malloc implementation is not protected - against concurrent access. - - 2007-05-04 Simon Goldschmidt (Atte Kojo) - * etharp.c: Introduced fast one-entry-cache to speed up ARP lookup when sending - multiple packets to the same host. - - 2007-05-04 Frédéric Bernon, Jonathan Larmour - * sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c: Fix bug #19162 "lwip_sento: a possible - to corrupt remote addr/port connection state". Reduce problems "not enought memory" with - netbuf (if we receive lot of datagrams). Improve lwip_sendto (only one exchange between - sockets api and api_msg which run in tcpip_thread context). Add netconn_sento function. - Warning, if you directly access to "fromaddr" & "fromport" field from netbuf struct, - these fields are now renamed "addr" & "port". - - 2007-04-11 Jonathan Larmour - * sys.h, api_lib.c: Provide new sys_mbox_tryfetch function. Require ports to provide new - sys_arch_mbox_tryfetch function to get a message if one is there, otherwise return - with SYS_MBOX_EMPTY. sys_arch_mbox_tryfetch can be implemented as a function-like macro - by the port in sys_arch.h if desired. - - 2007-04-06 Frédéric Bernon, Simon Goldschmidt - * opt.h, tcpip.h, tcpip.c, netifapi.h, netifapi.c: New configuration option LWIP_NETIF_API - allow to use thread-safe functions to add/remove netif in list, and to start/stop dhcp - clients, using new functions from netifapi.h. Disable as default (no port change to do). - - 2007-04-05 Frédéric Bernon - * sockets.c: remplace ENOBUFS errors on alloc_socket by ENFILE to be more BSD compliant. - - 2007-04-04 Simon Goldschmidt - * arch.h, api_msg.c, dhcp.c, msg_in.c, sockets.c: Introduced #define LWIP_UNUSED_ARG(x) - use this for and architecture-independent form to tell the compiler you intentionally - are not using this variable. Can be overriden in cc.h. - - 2007-03-28 Frédéric Bernon - * opt.h, netif.h, dhcp.h, dhcp.c: New configuration option LWIP_NETIF_HOSTNAME allow to - define a hostname in netif struct (this is just a pointer, so, you can use a hardcoded - string, point on one of your's ethernetif field, or alloc a string you will free yourself). - It will be used by DHCP to register a client hostname, but can also be use when you call - snmp_set_sysname. - - 2007-03-28 Frédéric Bernon - * netif.h, netif.c: A new NETIF_FLAG_ETHARP flag is defined in netif.h, to allow to - initialize a network interface's flag with. It tell this interface is an ethernet - device, and we can use ARP with it to do a "gratuitous ARP" (RFC 3220 "IP Mobility - Support for IPv4" section 4.6) when interface is "up" with netif_set_up(). - - 2007-03-26 Frédéric Bernon, Jonathan Larmour - * opt.h, tcpip.c: New configuration option LWIP_ARP allow to disable ARP init at build - time if you only use PPP or SLIP. The default is enable. Note we don't have to call - etharp_init in your port's initilization sequence if you use tcpip.c, because this call - is done in tcpip_init function. - - 2007-03-22 Frédéric Bernon - * stats.h, stats.c, msg_in.c: Stats counters can be change to u32_t if necessary with the - new option LWIP_STATS_LARGE. If you need this option, define LWIP_STATS_LARGE to 1 in - your lwipopts.h. More, unused counters are not defined in the stats structs, and not - display by stats_display(). Note that some options (SYS_STATS and RAW_STATS) are defined - but never used. Fix msg_in.c with the correct #if test for a stat display. - - 2007-03-21 Kieran Mansley - * netif.c, netif.h: Apply patch#4197 with some changes (originator: rireland@hmgsl.com). - Provides callback on netif up/down state change. - - 2007-03-11 Frédéric Bernon, Mace Gael, Steve Reynolds - * sockets.h, sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c, igmp.h, igmp.c, - ip.c, netif.h, tcpip.c, opt.h: - New configuration option LWIP_IGMP to enable IGMP processing. Based on only one - filter per all network interfaces. Declare a new function in netif to enable to - control the MAC filter (to reduce lwIP traffic processing). - - 2007-03-11 Frédéric Bernon - * tcp.h, tcp.c, sockets.c, tcp_out.c, tcp_in.c, opt.h: Keepalive values can - be configured at run time with LWIP_TCP_KEEPALIVE, but don't change this - unless you know what you're doing (default are RFC1122 compliant). Note - that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set in seconds. - - 2007-03-08 Frédéric Bernon - * tcp.h: Keepalive values can be configured at compile time, but don't change - this unless you know what you're doing (default are RFC1122 compliant). - - 2007-03-08 Frédéric Bernon - * sockets.c, api.h, api_lib.c, tcpip.c, sys.h, sys.c, err.c, opt.h: - Implement LWIP_SO_RCVTIMEO configuration option to enable/disable SO_RCVTIMEO - on UDP sockets/netconn. - - 2007-03-08 Simon Goldschmidt - * snmp_msg.h, msg_in.c: SNMP UDP ports can be configured at compile time. - - 2007-03-06 Frédéric Bernon - * api.h, api_lib.c, sockets.h, sockets.c, tcpip.c, sys.h, sys.c, err.h: - Implement SO_RCVTIMEO on UDP sockets/netconn. - - 2007-02-28 Kieran Mansley (based on patch from Simon Goldschmidt) - * api_lib.c, tcpip.c, memp.c, memp.h: make API msg structs allocated - on the stack and remove the API msg type from memp - - 2007-02-26 Jonathan Larmour (based on patch from Simon Goldschmidt) - * sockets.h, sockets.c: Move socket initialization to new - lwip_socket_init() function. - NOTE: this changes the API with ports. Ports will have to be - updated to call lwip_socket_init() now. - - 2007-02-26 Jonathan Larmour (based on patch from Simon Goldschmidt) - * api_lib.c: Use memcpy in netbuf_copy_partial. - - - ++ Bug fixes: - - 2008-03-17 Frédéric Bernon, Ed Kerekes - * igmp.h, igmp.c: Fix bug #22613 "IGMP iphdr problem" (could have - some problems to fill the IP header on some targets, use now the - ip.h macros to do it). - - 2008-03-13 Frédéric Bernon - * sockets.c: Fix bug #22435 "lwip_recvfrom with TCP break;". Using - (lwip_)recvfrom with valid "from" and "fromlen" parameters, on a - TCP connection caused a crash. Note that using (lwip_)recvfrom - like this is a bit slow and that using (lwip)getpeername is the - good lwip way to do it (so, using recv is faster on tcp sockets). - - 2008-03-12 Frédéric Bernon, Jonathan Larmour - * api_msg.c, contrib/apps/ping.c: Fix bug #22530 "api_msg.c's - recv_raw() does not consume data", and the ping sample (with - LWIP_SOCKET=1, the code did the wrong supposition that lwip_recvfrom - returned the IP payload, without the IP header). - - 2008-03-04 Jonathan Larmour - * mem.c, stats.c, mem.h: apply patch #6414 to avoid compiler errors - and/or warnings on some systems where mem_size_t and size_t differ. - * pbuf.c, ppp.c: Fix warnings on some systems with mem_malloc. - - 2008-03-04 Kieran Mansley (contributions by others) - * Numerous small compiler error/warning fixes from contributions to - mailing list after 1.3.0 release candidate made. - - 2008-01-25 Cui hengbin (integrated by Frédéric Bernon) - * dns.c: Fix bug #22108 "DNS problem" caused by unaligned structures. - - 2008-01-15 Kieran Mansley - * tcp_out.c: BUG20511. Modify persist timer to start when we are - prevented from sending by a small send window, not just a zero - send window. - - 2008-01-09 Jonathan Larmour - * opt.h, ip.c: Rename IP_OPTIONS define to IP_OPTIONS_ALLOWED to avoid - conflict with Linux system headers. - - 2008-01-06 Jonathan Larmour - * dhcp.c: fix bug #19927: "DHCP NACK problem" by clearing any existing set IP - address entirely on receiving a DHCPNAK, and restarting discovery. - - 2007-12-21 Simon Goldschmidt - * sys.h, api_lib.c, api_msg.c, sockets.c: fix bug #21698: "netconn->recv_avail - is not protected" by using new macros for interlocked access to modify/test - netconn->recv_avail. - - 2007-12-20 Kieran Mansley (based on patch from Oleg Tyshev) - * tcp_in.c: fix bug# 21535 (nrtx not reset correctly in SYN_SENT state) - - 2007-12-20 Kieran Mansley (based on patch from Per-Henrik Lundbolm) - * tcp.c, tcp_in.c, tcp_out.c, tcp.h: fix bug #20199 (better handling - of silly window avoidance and prevent lwIP from shrinking the window) - - 2007-12-04 Simon Goldschmidt - * tcp.c, tcp_in.c: fix bug #21699 (segment leak in ooseq processing when last - data packet was lost): add assert that all segment lists are empty in - tcp_pcb_remove before setting pcb to CLOSED state; don't directly set CLOSED - state from LAST_ACK in tcp_process - - 2007-12-02 Simon Goldschmidt - * sockets.h: fix bug #21654: exclude definition of struct timeval from #ifndef FD_SET - If including for system-struct timeval, LWIP_TIMEVAL_PRIVATE now - has to be set to 0 in lwipopts.h - - 2007-12-02 Simon Goldschmidt - * api_msg.c, api_lib.c: fix bug #21656 (recvmbox problem in netconn API): always - allocate a recvmbox in netconn_new_with_proto_and_callback. For a tcp-listen - netconn, this recvmbox is later freed and a new mbox is allocated for acceptmbox. - This is a fix for thread-safety and allocates all items needed for a netconn - when the netconn is created. - - 2007-11-30 Simon Goldschmidt - * udp.c: first attempt to fix bug #21655 (DHCP doesn't work reliably with multiple - netifs): if LWIP_DHCP is enabled, UDP packets to DHCP_CLIENT_PORT are passed - to netif->dhcp->pcb only (if that exists) and not to any other pcb for the same - port (only solution to let UDP pcbs 'bind' to a netif instead of an IP address) - - 2007-11-27 Simon Goldschmidt - * ip.c: fixed bug #21643 (udp_send/raw_send don't fail if netif is down) by - letting ip_route only use netifs that are up. - - 2007-11-27 Simon Goldschmidt - * err.h, api_lib.c, api_msg.c, sockets.c: Changed error handling: ERR_MEM, ERR_BUF - and ERR_RTE are seen as non-fatal, all other errors are fatal. netconns and - sockets block most operations once they have seen a fatal error. - - 2007-11-27 Simon Goldschmidt - * udp.h, udp.c, dhcp.c: Implemented new function udp_sendto_if which takes the - netif to send as an argument (to be able to send on netifs that are down). - - 2007-11-26 Simon Goldschmidt - * tcp_in.c: Fixed bug #21582: pcb->acked accounting can be wrong when ACKs - arrive out-of-order - - 2007-11-21 Simon Goldschmidt - * tcp.h, tcp_out.c, api_msg.c: Fixed bug #20287: tcp_output_nagle sends too early - Fixed the nagle algorithm; nagle now also works for all raw API applications - and has to be explicitly disabled with 'tcp_pcb->flags |= TF_NODELAY' - - 2007-11-12 Frédéric Bernon - * sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c: Fixed bug #20900. Now, most - of the netconn_peer and netconn_addr processing is done inside tcpip_thread - context in do_getaddr. - - 2007-11-10 Simon Goldschmidt - * etharp.c: Fixed bug: assert fired when MEMP_ARP_QUEUE was empty (which can - happen any time). Now the packet simply isn't enqueued when out of memory. - - 2007-11-01 Simon Goldschmidt - * tcp.c, tcp_in.c: Fixed bug #21494: The send mss (pcb->mss) is set to 536 (or - TCP_MSS if that is smaller) as long as no MSS option is received from the - remote host. - - 2007-11-01 Simon Goldschmidt - * tcp.h, tcp.c, tcp_in.c: Fixed bug #21491: The MSS option sent (with SYN) - is now based on TCP_MSS instead of pcb->mss (on passive open now effectively - sending our configured TCP_MSS instead of the one received). - - 2007-11-01 Simon Goldschmidt - * tcp_in.c: Fixed bug #21181: On active open, the initial congestion window was - calculated based on the configured TCP_MSS, not on the MSS option received - with SYN+ACK. - - 2007-10-09 Simon Goldschmidt - * udp.c, inet.c, inet.h: Fixed UDPLite: send: Checksum was always generated too - short and also was generated wrong if checksum coverage != tot_len; - receive: checksum was calculated wrong if checksum coverage != tot_len - - 2007-10-08 Simon Goldschmidt - * mem.c: lfree was not updated in mem_realloc! - - 2007-10-07 Frédéric Bernon - * sockets.c, api.h, api_lib.c: First step to fix "bug #20900 : Potential - crash error problem with netconn_peer & netconn_addr". VERY IMPORTANT: - this change cause an API breakage for netconn_addr, since a parameter - type change. Any compiler should cause an error without any changes in - yours netconn_peer calls (so, it can't be a "silent change"). It also - reduce a little bit the footprint for socket layer (lwip_getpeername & - lwip_getsockname use now a common lwip_getaddrname function since - netconn_peer & netconn_addr have the same parameters). - - 2007-09-20 Simon Goldschmidt - * tcp.c: Fixed bug #21080 (tcp_bind without check pcbs in TIME_WAIT state) - by checking tcp_tw_pcbs also - - 2007-09-19 Simon Goldschmidt - * icmp.c: Fixed bug #21107 (didn't reset IP TTL in ICMP echo replies) - - 2007-09-15 Mike Kleshov - * mem.c: Fixed bug #21077 (inaccuracy in calculation of lwip_stat.mem.used) - - 2007-09-06 Frédéric Bernon - * several-files: replace some #include "arch/cc.h" by "lwip/arch.h", or simply remove - it as long as "lwip/opt.h" is included before (this one include "lwip/debug.h" which - already include "lwip/arch.h"). Like that, default defines are provided by "lwip/arch.h" - if they are not defined in cc.h, in the same spirit than "lwip/opt.h" for lwipopts.h. - - 2007-08-30 Frédéric Bernon - * igmp.h, igmp.c: Some changes to remove some redundant code, add some traces, - and fix some coding style. - - 2007-08-28 Frédéric Bernon - * tcpip.c: Fix TCPIP_MSG_INPKT processing: now, tcpip_input can be used for any - kind of packets. These packets are considered like Ethernet packets (payload - pointing to ethhdr) if the netif got the NETIF_FLAG_ETHARP flag. Else, packets - are considered like IP packets (payload pointing to iphdr). - - 2007-08-27 Frédéric Bernon - * api.h, api_lib.c, api_msg.c: First fix for "bug #20900 : Potential crash error - problem with netconn_peer & netconn_addr". Introduce NETCONN_LISTEN netconn_state - and remove obsolete ones (NETCONN_RECV & NETCONN_ACCEPT). - - 2007-08-24 Kieran Mansley - * inet.c Modify (acc >> 16) test to ((acc >> 16) != 0) to help buggy - compiler (Paradigm C++) - - 2007-08-09 Frédéric Bernon, Bill Florac - * stats.h, stats.c, igmp.h, igmp.c, opt.h: Fix for bug #20503 : IGMP Improvement. - Introduce IGMP_STATS to centralize statistics management. - - 2007-08-09 Frédéric Bernon, Bill Florac - * udp.c: Fix for bug #20503 : IGMP Improvement. Enable to receive a multicast - packet on a udp pcb binded on an netif's IP address, and not on "any". - - 2007-08-09 Frédéric Bernon, Bill Florac - * igmp.h, igmp.c, ip.c: Fix minor changes from bug #20503 : IGMP Improvement. - This is mainly on using lookup/lookfor, and some coding styles... - - 2007-07-26 Frédéric Bernon (and "thedoctor") - * igmp.c: Fix bug #20595 to accept IGMPv3 "Query" messages. - - 2007-07-25 Simon Goldschmidt - * api_msg.c, tcp.c: Another fix for bug #20021: by not returning an error if - tcp_output fails in tcp_close, the code in do_close_internal gets simpler - (tcp_output is called again later from tcp timers). - - 2007-07-25 Simon Goldschmidt - * ip_frag.c: Fixed bug #20429: use the new pbuf_copy_partial instead of the old - copy_from_pbuf, which illegally modified the given pbuf. - - 2007-07-25 Simon Goldschmidt - * tcp_out.c: tcp_enqueue: pcb->snd_queuelen didn't work for chaine PBUF_RAMs: - changed snd_queuelen++ to snd_queuelen += pbuf_clen(p). - - 2007-07-24 Simon Goldschmidt - * api_msg.c, tcp.c: Fix bug #20480: Check the pcb passed to tcp_listen() for the - correct state (must be CLOSED). - - 2007-07-13 Thomas Taranowski (commited by Jared Grubb) - * memp.c: Fix bug #20478: memp_malloc returned NULL+MEMP_SIZE on failed - allocation. It now returns NULL. - - 2007-07-13 Frédéric Bernon - * api_msg.c: Fix bug #20318: api_msg "recv" callbacks don't call pbuf_free in - all error cases. - - 2007-07-13 Frédéric Bernon - * api_msg.c: Fix bug #20315: possible memory leak problem if tcp_listen failed, - because current code doesn't follow rawapi.txt documentation. - - 2007-07-13 Kieran Mansley - * src/core/tcp_in.c Apply patch#5741 from Oleg Tyshev to fix bug in - out of sequence processing of received packets - - 2007-07-03 Simon Goldschmidt - * nearly-all-files: Added assertions where PBUF_RAM pbufs are used and an - assumption is made that this pbuf is in one piece (i.e. not chained). These - assumptions clash with the possibility of converting to fully pool-based - pbuf implementations, where PBUF_RAM pbufs might be chained. - - 2007-07-03 Simon Goldschmidt - * api.h, api_lib.c, api_msg.c: Final fix for bug #20021 and some other problems - when closing tcp netconns: removed conn->sem, less context switches when - closing, both netconn_close and netconn_delete should safely close tcp - connections. - - 2007-07-02 Simon Goldschmidt - * ipv4/ip.h, ipv6/ip.h, opt.h, netif.h, etharp.h, ipv4/ip.c, netif.c, raw.c, - tcp_out.c, udp.c, etharp.c: Added option LWIP_NETIF_HWADDRHINT (default=off) - to cache ARP table indices with each pcb instead of single-entry cache for - the complete stack. - - 2007-07-02 Simon Goldschmidt - * tcp.h, tcp.c, tcp_in.c, tcp_out.c: Added some ASSERTS and casts to prevent - warnings when assigning to smaller types. - - 2007-06-28 Simon Goldschmidt - * tcp_out.c: Added check to prevent tcp_pcb->snd_queuelen from overflowing. - - 2007-06-28 Simon Goldschmidt - * tcp.h: Fixed bug #20287: Fixed nagle algorithm (sending was done too early if - a segment contained chained pbufs) - - 2007-06-28 Frédéric Bernon - * autoip.c: replace most of rand() calls by a macro LWIP_AUTOIP_RAND which compute - a "pseudo-random" value based on netif's MAC and some autoip fields. It's always - possible to define this macro in your own lwipopts.h to always use C library's - rand(). Note that autoip_create_rand_addr doesn't use this macro. - - 2007-06-28 Frédéric Bernon - * netifapi.h, netifapi.c, tcpip.h, tcpip.c: Update code to handle the option - LWIP_TCPIP_CORE_LOCKING, and do some changes to be coherent with last modifications - in api_lib/api_msg (use pointers and not type with table, etc...) - - 2007-06-26 Simon Goldschmidt - * udp.h: Fixed bug #20259: struct udp_hdr was lacking the packin defines. - - 2007-06-25 Simon Goldschmidt - * udp.c: Fixed bug #20253: icmp_dest_unreach was called with a wrong p->payload - for udp packets with no matching pcb. - - 2007-06-25 Simon Goldschmidt - * udp.c: Fixed bug #20220: UDP PCB search in udp_input(): a non-local match - could get udp input packets if the remote side matched. - - 2007-06-13 Simon Goldschmidt - * netif.c: Fixed bug #20180 (TCP pcbs listening on IP_ADDR_ANY could get - changed in netif_set_ipaddr if previous netif->ip_addr.addr was 0. - - 2007-06-13 Simon Goldschmidt - * api_msg.c: pcb_new sets conn->err if protocol is not implemented - -> netconn_new_..() does not allocate a new connection for unsupported - protocols. - - 2007-06-13 Frédéric Bernon, Simon Goldschmidt - * api_lib.c: change return expression in netconn_addr and netconn_peer, because - conn->err was reset to ERR_OK without any reasons (and error was lost)... - - 2007-06-13 Frédéric Bernon, Matthias Weisser - * opt.h, mem.h, mem.c, memp.c, pbuf.c, ip_frag.c, vj.c: Fix bug #20162. Rename - MEM_ALIGN in LWIP_MEM_ALIGN and MEM_ALIGN_SIZE in LWIP_MEM_ALIGN_SIZE to avoid - some macro names collision with some OS macros. - - 2007-06-11 Simon Goldschmidt - * udp.c: UDP Lite: corrected the use of chksum_len (based on RFC3828: if it's 0, - create checksum over the complete packet. On RX, if it's < 8 (and not 0), - discard the packet. Also removed the duplicate 'udphdr->chksum = 0' for both - UDP & UDP Lite. - - 2007-06-11 Srinivas Gollakota & Oleg Tyshev - * tcp_out.c: Fix for bug #20075 : "A problem with keep-alive timer and TCP flags" - where TCP flags wasn't initialized in tcp_keepalive. - - 2007-06-03 Simon Goldschmidt - * udp.c: udp_input(): Input pbuf was not freed if pcb had no recv function - registered, p->payload was modified without modifying p->len if sending - icmp_dest_unreach() (had no negative effect but was definitively wrong). - - 2007-06-03 Simon Goldschmidt - * icmp.c: Corrected bug #19937: For responding to an icmp echo request, icmp - re-used the input pbuf even if that didn't have enough space to include the - link headers. Now the space is tested and a new pbuf is allocated for the - echo response packet if the echo request pbuf isn't big enough. - - 2007-06-01 Simon Goldschmidt - * sockets.c: Checked in patch #5914: Moved sockopt processing into tcpip_thread. - - 2007-05-23 Frédéric Bernon - * api_lib.c, sockets.c: Fixed bug #5958 for netconn_listen (acceptmbox only - allocated by do_listen if success) and netconn_accept errors handling. In - most of api_lib functions, we replace some errors checkings like "if (conn==NULL)" - by ASSERT, except for netconn_delete. - - 2007-05-23 Frédéric Bernon - * api_lib.c: Fixed bug #5957 "Safe-thread problem inside netconn_recv" to return - an error code if it's impossible to fetch a pbuf on a TCP connection (and not - directly close the recvmbox). - - 2007-05-22 Simon Goldschmidt - * tcp.c: Fixed bug #1895 (tcp_bind not correct) by introducing a list of - bound but unconnected (and non-listening) tcp_pcbs. - - 2007-05-22 Frédéric Bernon - * sys.h, sys.c, api_lib.c, tcpip.c: remove sys_mbox_fetch_timeout() (was only - used for LWIP_SO_RCVTIMEO option) and use sys_arch_mbox_fetch() instead of - sys_mbox_fetch() in api files. Now, users SHOULD NOT use internal lwIP features - like "sys_timeout" in their application threads. - - 2007-05-22 Frédéric Bernon - * api.h, api_lib.c, api_msg.h, api_msg.c: change the struct api_msg_msg to see - which parameters are used by which do_xxx function, and to avoid "misusing" - parameters (patch #5938). - - 2007-05-22 Simon Goldschmidt - * api_lib.c, api_msg.c, raw.c, api.h, api_msg.h, raw.h: Included patch #5938: - changed raw_pcb.protocol from u16_t to u8_t since for IPv4 and IPv6, proto - is only 8 bits wide. This affects the api, as there, the protocol was - u16_t, too. - - 2007-05-18 Simon Goldschmidt - * memp.c: addition to patch #5913: smaller pointer was returned but - memp_memory was the same size -> did not save memory. - - 2007-05-16 Simon Goldschmidt - * loopif.c, slipif.c: Fix bug #19729: free pbuf if netif->input() returns - != ERR_OK. - - 2007-05-16 Simon Goldschmidt - * api_msg.c, udp.c: If a udp_pcb has a local_ip set, check if it is the same - as the one of the netif used for sending to prevent sending from old - addresses after a netif address gets changed (partly fixes bug #3168). - - 2007-05-16 Frédéric Bernon - * tcpip.c, igmp.h, igmp.c: Fixed bug "#19800 : IGMP: igmp_tick() will not work - with NO_SYS=1". Note that igmp_init is always in tcpip_thread (and not in - tcpip_init) because we have to be sure that network interfaces are already - added (mac filter is updated only in igmp_init for the moment). - - 2007-05-16 Simon Goldschmidt - * mem.c, memp.c: Removed semaphores from memp, changed sys_sem_wait calls - into sys_arch_sem_wait calls to prevent timers from running while waiting - for the heap. This fixes bug #19167. - - 2007-05-13 Simon Goldschmidt - * tcp.h, sockets.h, sockets.c: Fixed bug from patch #5865 by moving the defines - for socket options (lwip_set/-getsockopt) used with level IPPROTO_TCP from - tcp.h to sockets.h. - - 2007-05-07 Simon Goldschmidt - * mem.c: Another attempt to fix bug #17922. - - 2007-05-04 Simon Goldschmidt - * pbuf.c, pbuf.h, etharp.c: Further update to ARP queueing: Changed pbuf_copy() - implementation so that it can be reused (don't allocate the target - pbuf inside pbuf_copy()). - - 2007-05-04 Simon Goldschmidt - * memp.c: checked in patch #5913: in memp_malloc() we can return memp as mem - to save a little RAM (next pointer of memp is not used while not in pool). - - 2007-05-03 "maq" - * sockets.c: Fix ioctl FIONREAD when some data remains from last recv. - (patch #3574). - - 2007-04-23 Simon Goldschmidt - * loopif.c, loopif.h, opt.h, src/netif/FILES: fix bug #2595: "loopif results - in NULL reference for incoming TCP packets". Loopif has to be configured - (using LWIP_LOOPIF_MULTITHREADING) to directly call netif->input() - (multithreading environments, e.g. netif->input() = tcpip_input()) or - putting packets on a list that is fed to the stack by calling loopif_poll() - (single-thread / NO_SYS / polling environment where e.g. - netif->input() = ip_input). - - 2007-04-17 Jonathan Larmour - * pbuf.c: Use s32_t in pbuf_realloc(), as an s16_t can't reliably hold - the difference between two u16_t's. - * sockets.h: FD_SETSIZE needs to match number of sockets, which is - MEMP_NUM_NETCONN in sockets.c right now. - - 2007-04-12 Jonathan Larmour - * icmp.c: Reset IP header TTL in ICMP ECHO responses (bug #19580). - - 2007-04-12 Kieran Mansley - * tcp.c, tcp_in.c, tcp_out.c, tcp.h: Modify way the retransmission - timer is reset to fix bug#19434, with help from Oleg Tyshev. - - 2007-04-11 Simon Goldschmidt - * etharp.c, pbuf.c, pbuf.h: 3rd fix for bug #11400 (arp-queuing): More pbufs than - previously thought need to be copied (everything but PBUF_ROM!). Cleaned up - pbuf.c: removed functions no needed any more (by etharp). - - 2007-04-11 Kieran Mansley - * inet.c, ip_addr.h, sockets.h, sys.h, tcp.h: Apply patch #5745: Fix - "Constant is long" warnings with 16bit compilers. Contributed by - avatar@mmlab.cse.yzu.edu.tw - - 2007-04-05 Frédéric Bernon, Jonathan Larmour - * api_msg.c: Fix bug #16830: "err_tcp() posts to connection mailbox when no pend on - the mailbox is active". Now, the post is only done during a connect, and do_send, - do_write and do_join_leave_group don't do anything if a previous error was signaled. - - 2007-04-03 Frédéric Bernon - * ip.c: Don't set the IP_DF ("Don't fragment") flag in the IP header in IP output - packets. See patch #5834. - - 2007-03-30 Frédéric Bernon - * api_msg.c: add a "pcb_new" helper function to avoid redundant code, and to add - missing pcb allocations checking (in do_bind, and for each raw_new). Fix style. - - 2007-03-30 Frédéric Bernon - * most of files: prefix all debug.h define with "LWIP_" to avoid any conflict with - others environment defines (these were too "generic"). - - 2007-03-28 Frédéric Bernon - * api.h, api_lib.c, sockets.c: netbuf_ref doesn't check its internal pbuf_alloc call - result and can cause a crash. lwip_send now check netbuf_ref result. - - 2007-03-28 Simon Goldschmidt - * sockets.c Remove "#include " from sockets.c to avoid multiple - definition of macros (in errno.h and lwip/arch.h) if LWIP_PROVIDE_ERRNO is - defined. This is the way it should have been already (looking at - doc/sys_arch.txt) - - 2007-03-28 Kieran Mansley - * opt.h Change default PBUF_POOL_BUFSIZE (again) to accomodate default MSS + - IP and TCP headers *and* physical link headers - - 2007-03-26 Frédéric Bernon (based on patch from Dmitry Potapov) - * api_lib.c: patch for netconn_write(), fixes a possible race condition which cause - to send some garbage. It is not a definitive solution, but the patch does solve - the problem for most cases. - - 2007-03-22 Frédéric Bernon - * api_msg.h, api_msg.c: Remove obsolete API_MSG_ACCEPT and do_accept (never used). - - 2007-03-22 Frédéric Bernon - * api_lib.c: somes resources couldn't be freed if there was errors during - netconn_new_with_proto_and_callback. - - 2007-03-22 Frédéric Bernon - * ethernetif.c: update netif->input calls to check return value. In older ports, - it's a good idea to upgrade them, even if before, there could be another problem - (access to an uninitialized mailbox). - - 2007-03-21 Simon Goldschmidt - * sockets.c: fixed bug #5067 (essentialy a signed/unsigned warning fixed - by casting to unsigned). - - 2007-03-21 Frédéric Bernon - * api_lib.c, api_msg.c, tcpip.c: integrate sys_mbox_fetch(conn->mbox, NULL) calls from - api_lib.c to tcpip.c's tcpip_apimsg(). Now, use a local variable and not a - dynamic one from memp to send tcpip_msg to tcpip_thread in a synchrone call. - Free tcpip_msg from tcpip_apimsg is not done in tcpip_thread. This give a - faster and more reliable communication between api_lib and tcpip. - - 2007-03-21 Frédéric Bernon - * opt.h: Add LWIP_NETIF_CALLBACK (to avoid compiler warning) and set it to 0. - - 2007-03-21 Frédéric Bernon - * api_msg.c, igmp.c, igmp.h: Fix C++ style comments - - 2007-03-21 Kieran Mansley - * opt.h Change default PBUF_POOL_BUFSIZE to accomodate default MSS + - IP and TCP headers - - 2007-03-21 Kieran Mansley - * Fix all uses of pbuf_header to check the return value. In some - cases just assert if it fails as I'm not sure how to fix them, but - this is no worse than before when they would carry on regardless - of the failure. - - 2007-03-21 Kieran Mansley - * sockets.c, igmp.c, igmp.h, memp.h: Fix C++ style comments and - comment out missing header include in icmp.c - - 2007-03-20 Frédéric Bernon - * memp.h, stats.c: Fix stats_display function where memp_names table wasn't - synchronized with memp.h. - - 2007-03-20 Frédéric Bernon - * tcpip.c: Initialize tcpip's mbox, and verify if initialized in tcpip_input, - tcpip_ethinput, tcpip_callback, tcpip_apimsg, to fix a init problem with - network interfaces. Also fix a compiler warning. - - 2007-03-20 Kieran Mansley - * udp.c: Only try and use pbuf_header() to make space for headers if - not a ROM or REF pbuf. - - 2007-03-19 Frédéric Bernon - * api_msg.h, api_msg.c, tcpip.h, tcpip.c: Add return types to tcpip_apimsg() - and api_msg_post(). - - 2007-03-19 Frédéric Bernon - * Remove unimplemented "memp_realloc" function from memp.h. - - 2007-03-11 Simon Goldschmidt - * pbuf.c: checked in patch #5796: pbuf_alloc: len field claculation caused - memory corruption. - - 2007-03-11 Simon Goldschmidt (based on patch from Dmitry Potapov) - * api_lib.c, sockets.c, api.h, api_msg.h, sockets.h: Fixed bug #19251 - (missing `const' qualifier in socket functions), to get more compatible to - standard POSIX sockets. - - 2007-03-11 Frédéric Bernon (based on patch from Dmitry Potapov) - * sockets.c: Add asserts inside bind, connect and sendto to check input - parameters. Remove excessive set_errno() calls after get_socket(), because - errno is set inside of get_socket(). Move last sock_set_errno() inside - lwip_close. - - 2007-03-09 Simon Goldschmidt - * memp.c: Fixed bug #11400: New etharp queueing introduced bug: memp_memory - was allocated too small. - - 2007-03-06 Simon Goldschmidt - * tcpip.c: Initialize dhcp timers in tcpip_thread (if LWIP_DHCP) to protect - the stack from concurrent access. - - 2007-03-06 Frédéric Bernon, Dmitry Potapov - * tcpip.c, ip_frag.c, ethernetif.c: Fix some build problems, and a redundancy - call to "lwip_stats.link.recv++;" in low_level_input() & ethernetif_input(). - - 2007-03-06 Simon Goldschmidt - * ip_frag.c, ip_frag.h: Reduce code size: don't include code in those files - if IP_FRAG == 0 and IP_REASSEMBLY == 0 - - 2007-03-06 Frédéric Bernon, Simon Goldschmidt - * opt.h, ip_frag.h, tcpip.h, tcpip.c, ethernetif.c: add new configuration - option named ETHARP_TCPIP_ETHINPUT, which enable the new tcpip_ethinput. - Allow to do ARP processing for incoming packets inside tcpip_thread - (protecting ARP layer against concurrent access). You can also disable - old code using tcp_input with new define ETHARP_TCPIP_INPUT set to 0. - Older ports have to use tcpip_ethinput. - - 2007-03-06 Simon Goldschmidt (based on patch from Dmitry Potapov) - * err.h, err.c: fixed compiler warning "initialization dircards qualifiers - from pointer target type" - - 2007-03-05 Frédéric Bernon - * opt.h, sockets.h: add new configuration options (LWIP_POSIX_SOCKETS_IO_NAMES, - ETHARP_TRUST_IP_MAC, review SO_REUSE) - - 2007-03-04 Frédéric Bernon - * api_msg.c: Remove some compiler warnings : parameter "pcb" was never - referenced. - - 2007-03-04 Frédéric Bernon - * api_lib.c: Fix "[patch #5764] api_lib.c cleanup: after patch #5687" (from - Dmitry Potapov). - The api_msg struct stay on the stack (not moved to netconn struct). - - 2007-03-04 Simon Goldschmidt (based on patch from Dmitry Potapov) - * pbuf.c: Fix BUG#19168 - pbuf_free can cause deadlock (if - SYS_LIGHTWEIGHT_PROT=1 & freeing PBUF_RAM when mem_sem is not available) - Also fixed cast warning in pbuf_alloc() - - 2007-03-04 Simon Goldschmidt - * etharp.c, etharp.h, memp.c, memp.h, opt.h: Fix BUG#11400 - don't corrupt - existing pbuf chain when enqueuing multiple pbufs to a pending ARP request - - 2007-03-03 Frédéric Bernon - * udp.c: remove obsolete line "static struct udp_pcb *pcb_cache = NULL;" - It is static, and never used in udp.c except udp_init(). - - 2007-03-02 Simon Goldschmidt - * tcpip.c: Moved call to ip_init(), udp_init() and tcp_init() from - tcpip_thread() to tcpip_init(). This way, raw API connections can be - initialized before tcpip_thread is running (e.g. before OS is started) - - 2007-03-02 Frédéric Bernon - * rawapi.txt: Fix documentation mismatch with etharp.h about etharp_tmr's call - interval. - - 2007-02-28 Kieran Mansley - * pbuf.c: Fix BUG#17645 - ensure pbuf payload pointer is not moved - outside the region of the pbuf by pbuf_header() - - 2007-02-28 Kieran Mansley - * sockets.c: Fix BUG#19161 - ensure milliseconds timeout is non-zero - when supplied timeout is also non-zero - -(STABLE-1.2.0) - - 2006-12-05 Leon Woestenberg - * CHANGELOG: Mention STABLE-1.2.0 release. - - ++ New features: - - 2006-12-01 Christiaan Simons - * mem.h, opt.h: Added MEM_LIBC_MALLOC option. - Note this is a workaround. Currently I have no other options left. - - 2006-10-26 Christiaan Simons (accepted patch by Jonathan Larmour) - * ipv4/ip_frag.c: rename MAX_MTU to IP_FRAG_MAX_MTU and move define - to include/lwip/opt.h. - * ipv4/lwip/ip_frag.h: Remove unused IP_REASS_INTERVAL. - Move IP_REASS_MAXAGE and IP_REASS_BUFSIZE to include/lwip/opt.h. - * opt.h: Add above new options. - - 2006-08-18 Christiaan Simons - * tcp_{in,out}.c: added SNMP counters. - * ipv4/ip.c: added SNMP counters. - * ipv4/ip_frag.c: added SNMP counters. - - 2006-08-08 Christiaan Simons - * etharp.{c,h}: added etharp_find_addr() to read - (stable) ethernet/IP address pair from ARP table - - 2006-07-14 Christiaan Simons - * mib_structs.c: added - * include/lwip/snmp_structs.h: added - * netif.{c,h}, netif/ethernetif.c: added SNMP statistics to netif struct - - 2006-07-06 Christiaan Simons - * snmp/asn1_{enc,dec}.c added - * snmp/mib2.c added - * snmp/msg_{in,out}.c added - * include/lwip/snmp_asn1.h added - * include/lwip/snmp_msg.h added - * doc/snmp_agent.txt added - - 2006-03-29 Christiaan Simons - * inet.c, inet.h: Added platform byteswap support. - Added LWIP_PLATFORM_BYTESWAP define (defaults to 0) and - optional LWIP_PLATFORM_HTONS(), LWIP_PLATFORM_HTONL() macros. - - ++ Bug fixes: - - 2006-11-30 Christiaan Simons - * dhcp.c: Fixed false triggers of request_timeout. - - 2006-11-28 Christiaan Simons - * netif.c: In netif_add() fixed missing clear of ip_addr, netmask, gw and flags. - - 2006-10-11 Christiaan Simons - * api_lib.c etharp.c, ip.c, memp.c, stats.c, sys.{c,h} tcp.h: - Partially accepted patch #5449 for ANSI C compatibility / build fixes. - * ipv4/lwip/ip.h ipv6/lwip/ip.h: Corrected UDP-Lite protocol - identifier from 170 to 136 (bug #17574). - - 2006-10-10 Christiaan Simons - * api_msg.c: Fixed Nagle algorithm as reported by Bob Grice. - - 2006-08-17 Christiaan Simons - * udp.c: Fixed bug #17200, added check for broadcast - destinations for PCBs bound to a unicast address. - - 2006-08-07 Christiaan Simons - * api_msg.c: Flushing TCP output in do_close() (bug #15926). - - 2006-06-27 Christiaan Simons - * api_msg.c: Applied patch for cold case (bug #11135). - In accept_function() ensure newconn->callback is always initialized. - - 2006-06-15 Christiaan Simons - * mem.h: added MEM_SIZE_F alias to fix an ancient cold case (bug #1748), - facilitate printing of mem_size_t and u16_t statistics. - - 2006-06-14 Christiaan Simons - * api_msg.c: Applied patch #5146 to handle allocation failures - in accept() by Kevin Lawson. - - 2006-05-26 Christiaan Simons - * api_lib.c: Removed conn->sem creation and destruction - from netconn_write() and added sys_sem_new to netconn_new_*. - -(STABLE-1_1_1) - - 2006-03-03 Christiaan Simons - * ipv4/ip_frag.c: Added bound-checking assertions on ip_reassbitmap - access and added pbuf_alloc() return value checks. - - 2006-01-01 Leon Woestenberg - * tcp_{in,out}.c, tcp_out.c: Removed 'even sndbuf' fix in TCP, which is - now handled by the checksum routine properly. - - 2006-02-27 Leon Woestenberg - * pbuf.c: Fix alignment; pbuf_init() would not work unless - pbuf_pool_memory[] was properly aligned. (Patch by Curt McDowell.) - - 2005-12-20 Leon Woestenberg - * tcp.c: Remove PCBs which stay in LAST_ACK state too long. Patch - submitted by Mitrani Hiroshi. - - 2005-12-15 Christiaan Simons - * inet.c: Disabled the added summing routine to preserve code space. - - 2005-12-14 Leon Woestenberg - * tcp_in.c: Duplicate FIN ACK race condition fix by Kelvin Lawson. - Added Curt McDowell's optimized checksumming routine for future - inclusion. Need to create test case for unaliged, aligned, odd, - even length combination of cases on various endianess machines. - - 2005-12-09 Christiaan Simons - * inet.c: Rewrote standard checksum routine in proper portable C. - - 2005-11-25 Christiaan Simons - * udp.c tcp.c: Removed SO_REUSE hack. Should reside in socket code only. - * *.c: introduced cc.h LWIP_DEBUG formatters matching the u16_t, s16_t, - u32_t, s32_t typedefs. This solves most debug word-length assumes. - - 2005-07-17 Leon Woestenberg - * inet.c: Fixed unaligned 16-bit access in the standard checksum - routine by Peter Jolasson. - * slipif.c: Fixed implementation assumption of single-pbuf datagrams. - - 2005-02-04 Leon Woestenberg - * tcp_out.c: Fixed uninitialized 'queue' referenced in memerr branch. - * tcp_{out|in}.c: Applied patch fixing unaligned access. - - 2005-01-04 Leon Woestenberg - * pbuf.c: Fixed missing semicolon after LWIP_DEBUG statement. - - 2005-01-03 Leon Woestenberg - * udp.c: UDP pcb->recv() was called even when it was NULL. - -(STABLE-1_1_0) - - 2004-12-28 Leon Woestenberg - * etharp.*: Disabled multiple packets on the ARP queue. - This clashes with TCP queueing. - - 2004-11-28 Leon Woestenberg - * etharp.*: Fixed race condition from ARP request to ARP timeout. - Halved the ARP period, doubled the period counts. - ETHARP_MAX_PENDING now should be at least 2. This prevents - the counter from reaching 0 right away (which would allow - too little time for ARP responses to be received). - - 2004-11-25 Leon Woestenberg - * dhcp.c: Decline messages were not multicast but unicast. - * etharp.c: ETHARP_CREATE is renamed to ETHARP_TRY_HARD. - Do not try hard to insert arbitrary packet's source address, - etharp_ip_input() now calls etharp_update() without ETHARP_TRY_HARD. - etharp_query() now always DOES call ETHARP_TRY_HARD so that users - querying an address will see it appear in the cache (DHCP could - suffer from this when a server invalidly gave an in-use address.) - * ipv4/ip_addr.h: Renamed ip_addr_maskcmp() to _netcmp() as we are - comparing network addresses (identifiers), not the network masks - themselves. - * ipv4/ip_addr.c: ip_addr_isbroadcast() now checks that the given - IP address actually belongs to the network of the given interface. - - 2004-11-24 Kieran Mansley - * tcp.c: Increment pcb->snd_buf when ACK is received in SYN_SENT state. - -(STABLE-1_1_0-RC1) - - 2004-10-16 Kieran Mansley - * tcp.c: Add code to tcp_recved() to send an ACK (window update) immediately, - even if one is already pending, if the rcv_wnd is above a threshold - (currently TCP_WND/2). This avoids waiting for a timer to expire to send a - delayed ACK in order to open the window if the stack is only receiving data. - - 2004-09-12 Kieran Mansley - * tcp*.*: Retransmit time-out handling improvement by Sam Jansen. - - 2004-08-20 Tony Mountifield - * etharp.c: Make sure the first pbuf queued on an ARP entry - is properly ref counted. - - 2004-07-27 Tony Mountifield - * debug.h: Added (int) cast in LWIP_DEBUGF() to avoid compiler - warnings about comparison. - * pbuf.c: Stopped compiler complaining of empty if statement - when LWIP_DEBUGF() empty. Closed an unclosed comment. - * tcp.c: Stopped compiler complaining of empty if statement - when LWIP_DEBUGF() empty. - * ip.h Corrected IPH_TOS() macro: returns a byte, so doesn't need htons(). - * inet.c: Added a couple of casts to quiet the compiler. - No need to test isascii(c) before isdigit(c) or isxdigit(c). - - 2004-07-22 Tony Mountifield - * inet.c: Made data types consistent in inet_ntoa(). - Added casts for return values of checksum routines, to pacify compiler. - * ip_frag.c, tcp_out.c, sockets.c, pbuf.c - Small corrections to some debugging statements, to pacify compiler. - - 2004-07-21 Tony Mountifield - * etharp.c: Removed spurious semicolon and added missing end-of-comment. - * ethernetif.c Updated low_level_output() to match prototype for - netif->linkoutput and changed low_level_input() similarly for consistency. - * api_msg.c: Changed recv_raw() from int to u8_t, to match prototype - of raw_recv() in raw.h and so avoid compiler error. - * sockets.c: Added trivial (int) cast to keep compiler happier. - * ip.c, netif.c Changed debug statements to use the tidier ip4_addrN() macros. - -(STABLE-1_0_0) - - ++ Changes: - - 2004-07-05 Leon Woestenberg - * sockets.*: Restructured LWIP_PRIVATE_TIMEVAL. Make sure - your cc.h file defines this either 1 or 0. If non-defined, - defaults to 1. - * .c: Added and includes where used. - * etharp.c: Made some array indices unsigned. - - 2004-06-27 Leon Woestenberg - * netif.*: Added netif_set_up()/down(). - * dhcp.c: Changes to restart program flow. - - 2004-05-07 Leon Woestenberg - * etharp.c: In find_entry(), instead of a list traversal per candidate, do a - single-pass lookup for different candidates. Should exploit locality. - - 2004-04-29 Leon Woestenberg - * tcp*.c: Cleaned up source comment documentation for Doxygen processing. - * opt.h: ETHARP_ALWAYS_INSERT option removed to comply with ARP RFC. - * etharp.c: update_arp_entry() only adds new ARP entries when adviced to by - the caller. This deprecates the ETHARP_ALWAYS_INSERT overrule option. - - ++ Bug fixes: - - 2004-04-27 Leon Woestenberg - * etharp.c: Applied patch of bug #8708 by Toni Mountifield with a solution - suggested by Timmy Brolin. Fix for 32-bit processors that cannot access - non-aligned 32-bit words, such as soms 32-bit TCP/IP header fields. Fix - is to prefix the 14-bit Ethernet headers with two padding bytes. - - 2004-04-23 Leon Woestenberg - * ip_addr.c: Fix in the ip_addr_isbroadcast() check. - * etharp.c: Fixed the case where the packet that initiates the ARP request - is not queued, and gets lost. Fixed the case where the packets destination - address is already known; we now always queue the packet and perform an ARP - request. - -(STABLE-0_7_0) - - ++ Bug fixes: - - * Fixed TCP bug for SYN_SENT to ESTABLISHED state transition. - * Fixed TCP bug in dequeueing of FIN from out of order segment queue. - * Fixed two possible NULL references in rare cases. - -(STABLE-0_6_6) - - ++ Bug fixes: - - * Fixed DHCP which did not include the IP address in DECLINE messages. - - ++ Changes: - - * etharp.c has been hauled over a bit. - -(STABLE-0_6_5) - - ++ Bug fixes: - - * Fixed TCP bug induced by bad window resizing with unidirectional TCP traffic. - * Packets sent from ARP queue had invalid source hardware address. - - ++ Changes: - - * Pass-by ARP requests do now update the cache. - - ++ New features: - - * No longer dependent on ctype.h. - * New socket options. - * Raw IP pcb support. - -(STABLE-0_6_4) - - ++ Bug fixes: - - * Some debug formatters and casts fixed. - * Numereous fixes in PPP. - - ++ Changes: - - * DEBUGF now is LWIP_DEBUGF - * pbuf_dechain() has been re-enabled. - * Mentioned the changed use of CVS branches in README. - -(STABLE-0_6_3) - - ++ Bug fixes: - - * Fixed pool pbuf memory leak in pbuf_alloc(). - Occured if not enough PBUF_POOL pbufs for a packet pbuf chain. - Reported by Savin Zlobec. - - * PBUF_POOL chains had their tot_len field not set for non-first - pbufs. Fixed in pbuf_alloc(). - - ++ New features: - - * Added PPP stack contributed by Marc Boucher - - ++ Changes: - - * Now drops short packets for ICMP/UDP/TCP protocols. More robust. - - * ARP queueuing now queues the latest packet instead of the first. - This is the RFC recommended behaviour, but can be overridden in - lwipopts.h. - -(0.6.2) - - ++ Bugfixes: - - * TCP has been fixed to deal with the new use of the pbuf->ref - counter. - - * DHCP dhcp_inform() crash bug fixed. - - ++ Changes: - - * Removed pbuf_pool_free_cache and pbuf_pool_alloc_cache. Also removed - pbuf_refresh(). This has sped up pbuf pool operations considerably. - Implemented by David Haas. - -(0.6.1) - - ++ New features: - - * The packet buffer implementation has been enhanced to support - zero-copy and copy-on-demand for packet buffers which have their - payloads in application-managed memory. - Implemented by David Haas. - - Use PBUF_REF to make a pbuf refer to RAM. lwIP will use zero-copy - if an outgoing packet can be directly sent on the link, or perform - a copy-on-demand when necessary. - - The application can safely assume the packet is sent, and the RAM - is available to the application directly after calling udp_send() - or similar function. - - ++ Bugfixes: - - * ARP_QUEUEING should now correctly work for all cases, including - PBUF_REF. - Implemented by Leon Woestenberg. - - ++ Changes: - - * IP_ADDR_ANY is no longer a NULL pointer. Instead, it is a pointer - to a '0.0.0.0' IP address. - - * The packet buffer implementation is changed. The pbuf->ref counter - meaning has changed, and several pbuf functions have been - adapted accordingly. - - * netif drivers have to be changed to set the hardware address length field - that must be initialized correctly by the driver (hint: 6 for Ethernet MAC). - See the contrib/ports/c16x cs8900 driver as a driver example. - - * netif's have a dhcp field that must be initialized to NULL by the driver. - See the contrib/ports/c16x cs8900 driver as a driver example. - -(0.5.x) This file has been unmaintained up to 0.6.1. All changes are - logged in CVS but have not been explained here. - -(0.5.3) Changes since version 0.5.2 - - ++ Bugfixes: - - * memp_malloc(MEMP_API_MSG) could fail with multiple application - threads because it wasn't protected by semaphores. - - ++ Other changes: - - * struct ip_addr now packed. - - * The name of the time variable in arp.c has been changed to ctime - to avoid conflicts with the time() function. - -(0.5.2) Changes since version 0.5.1 - - ++ New features: - - * A new TCP function, tcp_tmr(), now handles both TCP timers. - - ++ Bugfixes: - - * A bug in tcp_parseopt() could cause the stack to hang because of a - malformed TCP option. - - * The address of new connections in the accept() function in the BSD - socket library was not handled correctly. - - * pbuf_dechain() did not update the ->tot_len field of the tail. - - * Aborted TCP connections were not handled correctly in all - situations. - - ++ Other changes: - - * All protocol header structs are now packed. - - * The ->len field in the tcp_seg structure now counts the actual - amount of data, and does not add one for SYN and FIN segments. - -(0.5.1) Changes since version 0.5.0 - - ++ New features: - - * Possible to run as a user process under Linux. - - * Preliminary support for cross platform packed structs. - - * ARP timer now implemented. - - ++ Bugfixes: - - * TCP output queue length was badly initialized when opening - connections. - - * TCP delayed ACKs were not sent correctly. - - * Explicit initialization of BSS segment variables. - - * read() in BSD socket library could drop data. - - * Problems with memory alignment. - - * Situations when all TCP buffers were used could lead to - starvation. - - * TCP MSS option wasn't parsed correctly. - - * Problems with UDP checksum calculation. - - * IP multicast address tests had endianess problems. - - * ARP requests had wrong destination hardware address. - - ++ Other changes: - - * struct eth_addr changed from u16_t[3] array to u8_t[6]. - - * A ->linkoutput() member was added to struct netif. - - * TCP and UDP ->dest_* struct members where changed to ->remote_*. - - * ntoh* macros are now null definitions for big endian CPUs. - -(0.5.0) Changes since version 0.4.2 - - ++ New features: - - * Redesigned operating system emulation layer to make porting easier. - - * Better control over TCP output buffers. - - * Documenation added. - - ++ Bugfixes: - - * Locking issues in buffer management. - - * Bugfixes in the sequential API. - - * IP forwarding could cause memory leakage. This has been fixed. - - ++ Other changes: - - * Directory structure somewhat changed; the core/ tree has been - collapsed. - -(0.4.2) Changes since version 0.4.1 - - ++ New features: - - * Experimental ARP implementation added. - - * Skeleton Ethernet driver added. - - * Experimental BSD socket API library added. - - ++ Bugfixes: - - * In very intense situations, memory leakage could occur. This has - been fixed. - - ++ Other changes: - - * Variables named "data" and "code" have been renamed in order to - avoid name conflicts in certain compilers. - - * Variable++ have in appliciable cases been translated to ++variable - since some compilers generate better code in the latter case. - -(0.4.1) Changes since version 0.4 - - ++ New features: - - * TCP: Connection attempts time out earlier than data - transmissions. Nagle algorithm implemented. Push flag set on the - last segment in a burst. - - * UDP: experimental support for UDP-Lite extensions. - - ++ Bugfixes: - - * TCP: out of order segments were in some cases handled incorrectly, - and this has now been fixed. Delayed acknowledgements was broken - in 0.4, has now been fixed. Binding to an address that is in use - now results in an error. Reset connections sometimes hung an - application; this has been fixed. - - * Checksum calculation sometimes failed for chained pbufs with odd - lengths. This has been fixed. - - * API: a lot of bug fixes in the API. The UDP API has been improved - and tested. Error reporting and handling has been - improved. Logical flaws and race conditions for incoming TCP - connections has been found and removed. - - * Memory manager: alignment issues. Reallocating memory sometimes - failed, this has been fixed. - - * Generic library: bcopy was flawed and has been fixed. - - ++ Other changes: - - * API: all datatypes has been changed from generic ones such as - ints, to specified ones such as u16_t. Functions that return - errors now have the correct type (err_t). - - * General: A lot of code cleaned up and debugging code removed. Many - portability issues have been fixed. - - * The license was changed; the advertising clause was removed. - - * C64 port added. - - * Thanks: Huge thanks go to Dagan Galarneau, Horst Garnetzke, Petri - Kosunen, Mikael Caleres, and Frits Wilmink for reporting and - fixing bugs! - -(0.4) Changes since version 0.3.1 - - * Memory management has been radically changed; instead of - allocating memory from a shared heap, memory for objects that are - rapidly allocated and deallocated is now kept in pools. Allocation - and deallocation from those memory pools is very fast. The shared - heap is still present but is used less frequently. - - * The memory, memory pool, and packet buffer subsystems now support - 4-, 2-, or 1-byte alignment. - - * "Out of memory" situations are handled in a more robust way. - - * Stack usage has been reduced. - - * Easier configuration of lwIP parameters such as memory usage, - TTLs, statistics gathering, etc. All configuration parameters are - now kept in a single header file "lwipopts.h". - - * The directory structure has been changed slightly so that all - architecture specific files are kept under the src/arch - hierarchy. - - * Error propagation has been improved, both in the protocol modules - and in the API. - - * The code for the RTXC architecture has been implemented, tested - and put to use. - - * Bugs have been found and corrected in the TCP, UDP, IP, API, and - the Internet checksum modules. - - * Bugs related to porting between a 32-bit and a 16-bit architecture - have been found and corrected. - - * The license has been changed slightly to conform more with the - original BSD license, including the advertisement clause. - -(0.3.1) Changes since version 0.3 - - * Fix of a fatal bug in the buffer management. Pbufs with allocated - RAM never returned the RAM when the pbuf was deallocated. - - * TCP congestion control, window updates and retransmissions did not - work correctly. This has now been fixed. - - * Bugfixes in the API. - -(0.3) Changes since version 0.2 - - * New and improved directory structure. All include files are now - kept in a dedicated include/ directory. - - * The API now has proper error handling. A new function, - netconn_err(), now returns an error code for the connection in - case of errors. - - * Improvements in the memory management subsystem. The system now - keeps a pointer to the lowest free memory block. A new function, - mem_malloc2() tries to allocate memory once, and if it fails tries - to free some memory and retry the allocation. - - * Much testing has been done with limited memory - configurations. lwIP now does a better job when overloaded. - - * Some bugfixes and improvements to the buffer (pbuf) subsystem. - - * Many bugfixes in the TCP code: - - - Fixed a bug in tcp_close(). - - - The TCP receive window was incorrectly closed when out of - sequence segments was received. This has been fixed. - - - Connections are now timed-out of the FIN-WAIT-2 state. - - - The initial congestion window could in some cases be too - large. This has been fixed. - - - The retransmission queue could in some cases be screwed up. This - has been fixed. - - - TCP RST flag now handled correctly. - - - Out of sequence data was in some cases never delivered to the - application. This has been fixed. - - - Retransmitted segments now contain the correct acknowledgment - number and advertised window. - - - TCP retransmission timeout backoffs are not correctly computed - (ala BSD). After a number of retransmissions, TCP now gives up - the connection. - - * TCP connections now are kept on three lists, one for active - connections, one for listening connections, and one for - connections that are in TIME-WAIT. This greatly speeds up the fast - timeout processing for sending delayed ACKs. - - * TCP now provides proper feedback to the application when a - connection has been successfully set up. - - * More comments have been added to the code. The code has also been - somewhat cleaned up. - -(0.2) Initial public release. diff --git a/components/lwip/VERSION b/components/lwip/VERSION deleted file mode 100644 index 4276fd51ac..0000000000 --- a/components/lwip/VERSION +++ /dev/null @@ -1 +0,0 @@ -bf7fc41e \ No newline at end of file From c0491fc6f11a9a5937cf5a7cd2cd3155294a0f4f Mon Sep 17 00:00:00 2001 From: Hrishikesh Dhayagude Date: Wed, 31 Jul 2019 15:33:03 +0800 Subject: [PATCH 382/486] Minor: Fix some typos in Bluetooth examples --- examples/bluetooth/ble_ancs/main/ble_ancs_demo.c | 4 ++-- .../gatt_security_server/main/example_ble_sec_gatts_demo.c | 4 ++-- .../bt_spp_acceptor/main/example_spp_acceptor_demo.c | 4 ++-- .../bt_spp_initiator/main/example_spp_initiator_demo.c | 4 ++-- .../bt_spp_vfs_acceptor/main/example_spp_vfs_acceptor_demo.c | 4 ++-- .../main/example_spp_vfs_initiator_demo.c | 4 ++-- examples/bluetooth/nimble/blehr/main/main.c | 2 +- examples/bluetooth/nimble/bleprph/main/main.c | 4 ++-- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/examples/bluetooth/ble_ancs/main/ble_ancs_demo.c b/examples/bluetooth/ble_ancs/main/ble_ancs_demo.c index 28ca4629fc..294a8a1061 100644 --- a/examples/bluetooth/ble_ancs/main/ble_ancs_demo.c +++ b/examples/bluetooth/ble_ancs/main/ble_ancs_demo.c @@ -24,7 +24,7 @@ #include "ble_ancs.h" #define BLE_ANCS_TAG "BLE_ANCS" -#define EXCAMPLE_DEVICE_NAME "ESP_BLE_ANCS" +#define EXAMPLE_DEVICE_NAME "ESP_BLE_ANCS" #define PROFILE_A_APP_ID 0 #define PROFILE_NUM 1 #define ADV_CONFIG_FLAG (1 << 0) @@ -331,7 +331,7 @@ static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_ switch (event) { case ESP_GATTC_REG_EVT: ESP_LOGI(BLE_ANCS_TAG, "REG_EVT"); - esp_ble_gap_set_device_name(EXCAMPLE_DEVICE_NAME); + esp_ble_gap_set_device_name(EXAMPLE_DEVICE_NAME); esp_ble_gap_config_local_icon (ESP_BLE_APPEARANCE_GENERIC_WATCH); //generate a resolvable random address esp_ble_gap_config_local_privacy(true); diff --git a/examples/bluetooth/bluedroid/ble/gatt_security_server/main/example_ble_sec_gatts_demo.c b/examples/bluetooth/bluedroid/ble/gatt_security_server/main/example_ble_sec_gatts_demo.c index 2c1a8186f7..a7c80182fd 100644 --- a/examples/bluetooth/bluedroid/ble/gatt_security_server/main/example_ble_sec_gatts_demo.c +++ b/examples/bluetooth/bluedroid/ble/gatt_security_server/main/example_ble_sec_gatts_demo.c @@ -25,7 +25,7 @@ #define HEART_PROFILE_NUM 1 #define HEART_PROFILE_APP_IDX 0 #define ESP_HEART_RATE_APP_ID 0x55 -#define EXCAMPLE_DEVICE_NAME "ESP_BLE_SECURITY" +#define EXAMPLE_DEVICE_NAME "ESP_BLE_SECURITY" #define HEART_RATE_SVC_INST_ID 0 #define GATTS_DEMO_CHAR_VAL_LEN_MAX 0x40 @@ -400,7 +400,7 @@ static void gatts_profile_event_handler(esp_gatts_cb_event_t event, ESP_LOGV(GATTS_TABLE_TAG, "event = %x\n",event); switch (event) { case ESP_GATTS_REG_EVT: - esp_ble_gap_set_device_name(EXCAMPLE_DEVICE_NAME); + esp_ble_gap_set_device_name(EXAMPLE_DEVICE_NAME); //generate a resolvable random address esp_ble_gap_config_local_privacy(true); esp_ble_gatts_create_attr_tab(heart_rate_gatt_db, gatts_if, diff --git a/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/main/example_spp_acceptor_demo.c b/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/main/example_spp_acceptor_demo.c index feadac1521..cf82c2724e 100644 --- a/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/main/example_spp_acceptor_demo.c +++ b/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/main/example_spp_acceptor_demo.c @@ -26,7 +26,7 @@ #define SPP_TAG "SPP_ACCEPTOR_DEMO" #define SPP_SERVER_NAME "SPP_SERVER" -#define EXCAMPLE_DEVICE_NAME "ESP_SPP_ACCEPTOR" +#define EXAMPLE_DEVICE_NAME "ESP_SPP_ACCEPTOR" #define SPP_SHOW_DATA 0 #define SPP_SHOW_SPEED 1 #define SPP_SHOW_MODE SPP_SHOW_SPEED /*Choose show mode: show data or speed*/ @@ -56,7 +56,7 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param) switch (event) { case ESP_SPP_INIT_EVT: ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT"); - esp_bt_dev_set_device_name(EXCAMPLE_DEVICE_NAME); + esp_bt_dev_set_device_name(EXAMPLE_DEVICE_NAME); esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE); esp_spp_start_srv(sec_mask,role_slave, 0, SPP_SERVER_NAME); break; diff --git a/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/example_spp_initiator_demo.c b/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/example_spp_initiator_demo.c index a805b73e8b..cd4365996c 100644 --- a/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/example_spp_initiator_demo.c +++ b/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/example_spp_initiator_demo.c @@ -25,7 +25,7 @@ #include "sys/time.h" #define SPP_TAG "SPP_INITIATOR_DEMO" -#define EXCAMPLE_DEVICE_NAME "ESP_SPP_INITIATOR" +#define EXAMPLE_DEVICE_NAME "ESP_SPP_INITIATOR" #define SPP_SHOW_DATA 0 #define SPP_SHOW_SPEED 1 @@ -103,7 +103,7 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param) switch (event) { case ESP_SPP_INIT_EVT: ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT"); - esp_bt_dev_set_device_name(EXCAMPLE_DEVICE_NAME); + esp_bt_dev_set_device_name(EXAMPLE_DEVICE_NAME); esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE); esp_bt_gap_start_discovery(inq_mode, inq_len, inq_num_rsps); diff --git a/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/example_spp_vfs_acceptor_demo.c b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/example_spp_vfs_acceptor_demo.c index a24d691ecf..092756b724 100644 --- a/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/example_spp_vfs_acceptor_demo.c +++ b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/example_spp_vfs_acceptor_demo.c @@ -38,7 +38,7 @@ #define SPP_TAG "SPP_ACCEPTOR_DEMO" #define SPP_SERVER_NAME "SPP_SERVER" -#define EXCAMPLE_DEVICE_NAME "ESP_SPP_ACCEPTOR" +#define EXAMPLE_DEVICE_NAME "ESP_SPP_ACCEPTOR" static const esp_spp_mode_t esp_spp_mode = ESP_SPP_MODE_VFS; @@ -75,7 +75,7 @@ static void esp_spp_cb(uint16_t e, void *p) switch (event) { case ESP_SPP_INIT_EVT: ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT"); - esp_bt_dev_set_device_name(EXCAMPLE_DEVICE_NAME); + esp_bt_dev_set_device_name(EXAMPLE_DEVICE_NAME); esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE); esp_spp_start_srv(sec_mask,role_slave, 0, SPP_SERVER_NAME); break; diff --git a/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/example_spp_vfs_initiator_demo.c b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/example_spp_vfs_initiator_demo.c index ea8e79987c..fc34a8f024 100644 --- a/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/example_spp_vfs_initiator_demo.c +++ b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/example_spp_vfs_initiator_demo.c @@ -37,7 +37,7 @@ #include "sys/unistd.h" #define SPP_TAG "SPP_INITIATOR_DEMO" -#define EXCAMPLE_DEVICE_NAME "ESP_SPP_INITIATOR" +#define EXAMPLE_DEVICE_NAME "ESP_SPP_INITIATOR" static const esp_spp_mode_t esp_spp_mode = ESP_SPP_MODE_VFS; @@ -113,7 +113,7 @@ static void esp_spp_cb(uint16_t e, void *p) switch (event) { case ESP_SPP_INIT_EVT: ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT"); - esp_bt_dev_set_device_name(EXCAMPLE_DEVICE_NAME); + esp_bt_dev_set_device_name(EXAMPLE_DEVICE_NAME); esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE); esp_bt_gap_start_discovery(inq_mode, inq_len, inq_num_rsps); diff --git a/examples/bluetooth/nimble/blehr/main/main.c b/examples/bluetooth/nimble/blehr/main/main.c index ca5b8d4df9..f1b7180af8 100644 --- a/examples/bluetooth/nimble/blehr/main/main.c +++ b/examples/bluetooth/nimble/blehr/main/main.c @@ -134,7 +134,7 @@ blehr_tx_hrate_stop(void) xTimerStop( blehr_tx_timer, 1000 / portTICK_PERIOD_MS ); } -/* Reset heartrate measurment */ +/* Reset heart rate measurement */ static void blehr_tx_hrate_reset(void) { diff --git a/examples/bluetooth/nimble/bleprph/main/main.c b/examples/bluetooth/nimble/bleprph/main/main.c index 58fc39a347..917e2246ca 100644 --- a/examples/bluetooth/nimble/bleprph/main/main.c +++ b/examples/bluetooth/nimble/bleprph/main/main.c @@ -93,7 +93,7 @@ bleprph_advertise(void) BLE_HS_ADV_F_BREDR_UNSUP; /* Indicate that the TX power level field should be included; have the - * stack fill this value automatically. This is done by assiging the + * stack fill this value automatically. This is done by assigning the * special value BLE_HS_ADV_TX_PWR_LVL_AUTO. */ fields.tx_pwr_lvl_is_present = 1; @@ -135,7 +135,7 @@ bleprph_advertise(void) * * @param event The type of event being signalled. * @param ctxt Various information pertaining to the event. - * @param arg Application-specified argument; unuesd by + * @param arg Application-specified argument; unused by * bleprph. * * @return 0 if the application successfully handled the From ff325e84b65e88547ed5508ae1de82232f2d8f43 Mon Sep 17 00:00:00 2001 From: redchenjs Date: Mon, 1 Jul 2019 19:48:47 +0800 Subject: [PATCH 383/486] Bugfix(i2s): fixed i2s left/right channels swapped issue. The right channel data is in the high position, so the I2S_TX_MSB_RIGHT & I2S_RX_MSB_RIGHT bits should be set. Merges https://github.com/espressif/esp-idf/pull/3717 closes https://github.com/espressif/esp-idf/issues/3399 --- components/driver/i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/driver/i2s.c b/components/driver/i2s.c index 56c418d153..d0c9831b87 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -944,7 +944,7 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co I2S[i2s_num]->conf.rx_start = 0; if (i2s_config->mode & I2S_MODE_TX) { - I2S[i2s_num]->conf.tx_msb_right = 0; + I2S[i2s_num]->conf.tx_msb_right = 1; I2S[i2s_num]->conf.tx_right_first = 0; I2S[i2s_num]->conf.tx_slave_mod = 0; // Master @@ -956,7 +956,7 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co } if (i2s_config->mode & I2S_MODE_RX) { - I2S[i2s_num]->conf.rx_msb_right = 0; + I2S[i2s_num]->conf.rx_msb_right = 1; I2S[i2s_num]->conf.rx_right_first = 0; I2S[i2s_num]->conf.rx_slave_mod = 0; // Master I2S[i2s_num]->fifo_conf.rx_fifo_mod_force_en = 1; From a2155ff52dc627027bd6147ba6be90632f02f7b3 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Sat, 6 Jul 2019 12:43:35 +0800 Subject: [PATCH 384/486] idf_monitor: improve the responding of console commands --- tools/idf_monitor.py | 301 +++++++++++++++++++++++++++---------------- 1 file changed, 191 insertions(+), 110 deletions(-) diff --git a/tools/idf_monitor.py b/tools/idf_monitor.py index f68020613f..5320149dbe 100755 --- a/tools/idf_monitor.py +++ b/tools/idf_monitor.py @@ -52,6 +52,7 @@ import ctypes import types from distutils.version import StrictVersion from io import open +import textwrap key_description = miniterm.key_description @@ -67,6 +68,15 @@ CTRL_P = '\x10' CTRL_L = '\x0c' CTRL_RBRACKET = '\x1d' # Ctrl+] +# Command parsed from console inputs +CMD_STOP = 1 +CMD_RESET = 2 +CMD_MAKE = 3 +CMD_APP_FLASH = 4 +CMD_OUTPUT_TOGGLE = 5 +CMD_TOGGLE_LOGGING = 6 +CMD_ENTER_BOOT = 7 + # ANSI terminal codes (if changed, regular expressions in LineMatcher need to be udpated) ANSI_RED = '\033[1;31m' ANSI_YELLOW = '\033[0;33m' @@ -92,6 +102,7 @@ __version__ = "1.1" TAG_KEY = 0 TAG_SERIAL = 1 TAG_SERIAL_FLUSH = 2 +TAG_CMD = 3 # regex matches an potential PC value (0x4xxxxxxx) MATCH_PCADDR = re.compile(r'0x4[0-9a-f]{7}', re.IGNORECASE) @@ -149,10 +160,12 @@ class ConsoleReader(StoppableThread): """ Read input keys from the console and push them to the queue, until stopped. """ - def __init__(self, console, event_queue, test_mode): + def __init__(self, console, event_queue, cmd_queue, parser, test_mode): super(ConsoleReader, self).__init__() self.console = console self.event_queue = event_queue + self.cmd_queue = cmd_queue + self.parser = parser self.test_mode = test_mode def run(self): @@ -181,7 +194,15 @@ class ConsoleReader(StoppableThread): except KeyboardInterrupt: c = '\x03' if c is not None: - self.event_queue.put((TAG_KEY, c), False) + ret = self.parser.parse(c) + if ret is not None: + (tag, cmd) = ret + # stop command should be executed last + if tag == TAG_CMD and cmd != CMD_STOP: + self.cmd_queue.put(ret) + else: + self.event_queue.put(ret) + finally: self.console.cleanup() @@ -204,6 +225,110 @@ class ConsoleReader(StoppableThread): fcntl.ioctl(self.console.fd, termios.TIOCSTI, b'\0') +class ConsoleParser(object): + + def __init__(self, eol="CRLF"): + self.translate_eol = { + "CRLF": lambda c: c.replace("\n", "\r\n"), + "CR": lambda c: c.replace("\n", "\r"), + "LF": lambda c: c.replace("\r", "\n"), + }[eol] + self.menu_key = CTRL_T + self.exit_key = CTRL_RBRACKET + self._pressed_menu_key = False + + def parse(self, key): + ret = None + if self._pressed_menu_key: + ret = self._handle_menu_key(key) + elif key == self.menu_key: + self._pressed_menu_key = True + elif key == self.exit_key: + ret = (TAG_CMD, CMD_STOP) + else: + key = self.translate_eol(key) + ret = (TAG_KEY, key) + return ret + + def _handle_menu_key(self, c): + ret = None + if c == self.exit_key or c == self.menu_key: # send verbatim + ret = (TAG_KEY, c) + elif c in [CTRL_H, 'h', 'H', '?']: + red_print(self.get_help_text()) + elif c == CTRL_R: # Reset device via RTS + ret = (TAG_CMD, CMD_RESET) + elif c == CTRL_F: # Recompile & upload + ret = (TAG_CMD, CMD_MAKE) + elif c in [CTRL_A, 'a', 'A']: # Recompile & upload app only + # "CTRL-A" cannot be captured with the default settings of the Windows command line, therefore, "A" can be used + # instead + ret = (TAG_CMD, CMD_APP_FLASH) + elif c == CTRL_Y: # Toggle output display + ret = (TAG_CMD, CMD_OUTPUT_TOGGLE) + elif c == CTRL_L: # Toggle saving output into file + ret = (TAG_CMD, CMD_TOGGLE_LOGGING) + elif c == CTRL_P: + yellow_print("Pause app (enter bootloader mode), press Ctrl-T Ctrl-R to restart") + # to fast trigger pause without press menu key + ret = (TAG_CMD, CMD_ENTER_BOOT) + else: + red_print('--- unknown menu character {} --'.format(key_description(c))) + + self._pressed_menu_key = False + return ret + + def get_help_text(self): + text = """\ + --- 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:14} Send the menu character itself to remote + --- {exit:14} Send the exit character itself to remote + --- {reset:14} Reset target board via RTS line + --- {makecmd:14} Build & flash project + --- {appmake:14} Build & flash app only + --- {output:14} Toggle output display + --- {log:14} Toggle saving output into file + --- {pause:14} Reset target into bootloader to pause app via RTS line + """.format(version=__version__, + exit=key_description(self.exit_key), + menu=key_description(self.menu_key), + reset=key_description(CTRL_R), + makecmd=key_description(CTRL_F), + appmake=key_description(CTRL_A) + ' (or A)', + output=key_description(CTRL_Y), + log=key_description(CTRL_L), + pause=key_description(CTRL_P)) + return textwrap.dedent(text) + + def get_next_action_text(self): + text = """\ + --- Press {} to exit monitor. + --- Press {} to build & flash project. + --- Press {} to build & flash app. + --- Press any other key to resume monitor (resets target). + """.format(key_description(self.exit_key), + key_description(CTRL_F), + key_description(CTRL_A)) + return textwrap.dedent(text) + + def parse_next_action_key(self, c): + ret = None + if c == self.exit_key: + ret = (TAG_CMD, CMD_STOP) + elif c == CTRL_F: # Recompile & upload + ret = (TAG_CMD, CMD_MAKE) + elif c in [CTRL_A, 'a', 'A']: # Recompile & upload app only + # "CTRL-A" cannot be captured with the default settings of the Windows command line, therefore, "A" can be used + # instead + ret = (TAG_CMD, CMD_APP_FLASH) + return ret + + class SerialReader(StoppableThread): """ Read serial data from the serial port and push to the event queue, until stopped. @@ -313,6 +438,7 @@ class Monitor(object): def __init__(self, serial_instance, elf_file, print_filter, make="make", toolchain_prefix=DEFAULT_TOOLCHAIN_PREFIX, eol="CRLF"): super(Monitor, self).__init__() self.event_queue = queue.Queue() + self.cmd_queue = queue.Queue() self.console = miniterm.Console() if os.name == 'nt': sys.stderr = ANSIColorConverter(sys.stderr, decode_output=True) @@ -331,7 +457,8 @@ class Monitor(object): socket_mode = serial_instance.port.startswith("socket://") # testing hook - data from serial can make exit the monitor self.serial = serial_instance - self.console_reader = ConsoleReader(self.console, self.event_queue, socket_mode) + self.console_parser = ConsoleParser(eol) + self.console_reader = ConsoleReader(self.console, self.event_queue, self.cmd_queue, self.console_parser, socket_mode) self.serial_reader = SerialReader(self.serial, self.event_queue) self.elf_file = elf_file if not os.path.exists(make): @@ -339,17 +466,8 @@ class Monitor(object): else: self.make = make self.toolchain_prefix = toolchain_prefix - self.menu_key = CTRL_T - self.exit_key = CTRL_RBRACKET - - self.translate_eol = { - "CRLF": lambda c: c.replace("\n", "\r\n"), - "CR": lambda c: c.replace("\n", "\r"), - "LF": lambda c: c.replace("\r", "\n"), - }[eol] # internal state - self._pressed_menu_key = False self._last_line_part = b"" self._gdb_buffer = b"" self._pc_address_buffer = b"" @@ -368,9 +486,24 @@ class Monitor(object): 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) + try: + item = self.cmd_queue.get_nowait() + except queue.Empty: + try: + item = self.event_queue.get(False, 0.001) + except queue.Empty: + continue + + (event_tag, data) = item + if event_tag == TAG_CMD: + self.handle_commands(data) + elif event_tag == TAG_KEY: + try: + self.serial.write(codecs.encode(data)) + except serial.SerialException: + pass # this shouldn't happen, but sometimes port has closed in serial thread + except UnicodeEncodeError: + pass # this can happen if a non-ascii character was passed, ignoring elif event_tag == TAG_SERIAL: self.handle_serial_input(data) if self._invoke_processing_last_line_timer is not None: @@ -400,24 +533,6 @@ class Monitor(object): 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: - key = self.translate_eol(key) - self.serial.write(codecs.encode(key)) - except serial.SerialException: - pass # this shouldn't happen, but sometimes port has closed in serial thread - except UnicodeEncodeError: - pass # this can happen if a non-ascii character was passed, ignoring - def handle_serial_input(self, data, finalize_line=False): sp = data.split(b'\n') if self._last_line_part != b"": @@ -429,7 +544,7 @@ class Monitor(object): self._last_line_part = sp.pop() for line in sp: if line != b"": - if self._serial_check_exit and line == self.exit_key.encode('latin-1'): + if self._serial_check_exit and line == self.console_parser.exit_key.encode('latin-1'): raise SerialStopException() if self._force_line_print or self._line_matcher.match(line.decode(errors="ignore")): self._print(line + b'\n') @@ -465,65 +580,6 @@ class Monitor(object): for m in re.finditer(MATCH_PCADDR, line.decode(errors="ignore")): 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', '?']: - red_print(self.get_help_text()) - elif c == CTRL_R: # Reset device via RTS - self.serial.setRTS(True) - time.sleep(0.2) - self.serial.setRTS(False) - self.output_enable(True) - elif c == CTRL_F: # Recompile & upload - self.run_make("flash") - elif c in [CTRL_A, 'a', 'A']: # Recompile & upload app only - # "CTRL-A" cannot be captured with the default settings of the Windows command line, therefore, "A" can be used - # instead - self.run_make("app-flash") - elif c == CTRL_Y: # Toggle output display - self.output_toggle() - elif c == CTRL_L: # Toggle saving output into file - self.toggle_logging() - elif c == CTRL_P: - yellow_print("Pause app (enter bootloader mode), press Ctrl-T Ctrl-R to restart") - # to fast trigger pause without press menu key - self.serial.setDTR(False) # IO0=HIGH - self.serial.setRTS(True) # EN=LOW, chip in reset - time.sleep(1.3) # timeouts taken from esptool.py, includes esp32r0 workaround. defaults: 0.1 - self.serial.setDTR(True) # IO0=LOW - self.serial.setRTS(False) # EN=HIGH, chip out of reset - time.sleep(0.45) # timeouts taken from esptool.py, includes esp32r0 workaround. defaults: 0.05 - self.serial.setDTR(False) # IO0=HIGH, done - else: - red_print('--- unknown menu character {} --'.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:14} Send the menu character itself to remote ---- {exit:14} Send the exit character itself to remote ---- {reset:14} Reset target board via RTS line ---- {makecmd:14} Build & flash project ---- {appmake:14} Build & flash app only ---- {output:14} Toggle output display ---- {log:14} Toggle saving output into file ---- {pause:14} Reset target into bootloader to pause app via RTS line -""".format(version=__version__, - exit=key_description(self.exit_key), - menu=key_description(self.menu_key), - reset=key_description(CTRL_R), - makecmd=key_description(CTRL_F), - appmake=key_description(CTRL_A) + ' (or A)', - output=key_description(CTRL_Y), - log=key_description(CTRL_L), - pause=key_description(CTRL_P)) - def __enter__(self): """ Use 'with self' to temporarily disable monitoring behaviour """ self.serial_reader.stop() @@ -537,25 +593,22 @@ class Monitor(object): def prompt_next_action(self, reason): self.console.setup() # set up console to trap input characters try: - red_print(""" ---- {} ---- Press {} to exit monitor. ---- Press {} to build & flash project. ---- Press {} to build & flash app. ---- Press any other key to resume monitor (resets target).""".format(reason, - key_description(self.exit_key), - key_description(CTRL_F), - key_description(CTRL_A))) + red_print("--- {}".format(reason)) + red_print(self.console_parser.get_next_action_text()) + k = CTRL_T # ignore CTRL-T here, so people can muscle-memory Ctrl-T Ctrl-F, etc. while k == CTRL_T: 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)) + ret = self.console_parser.parse_next_action_key(k) + if ret is not None: + cmd = ret[1] + if cmd == CMD_STOP: + # the stop command should be handled last + self.event_queue.put(ret) + else: + self.cmd_queue.put(ret) def run_make(self, target): with self: @@ -676,6 +729,34 @@ class Monitor(object): # don't fill-up the screen with the previous errors (probably consequent prints would fail also) self.stop_logging() + def handle_commands(self, cmd): + if cmd == CMD_STOP: + self.console_reader.stop() + self.serial_reader.stop() + elif cmd == CMD_RESET: + self.serial.setRTS(True) + time.sleep(0.2) + self.serial.setRTS(False) + self.output_enable(True) + elif cmd == CMD_MAKE: + self.run_make("flash") + elif cmd == CMD_APP_FLASH: + self.run_make("app-flash") + elif cmd == CMD_OUTPUT_TOGGLE: + self.output_toggle() + elif cmd == CMD_TOGGLE_LOGGING: + self.toggle_logging() + elif cmd == CMD_ENTER_BOOT: + self.serial.setDTR(False) # IO0=HIGH + self.serial.setRTS(True) # EN=LOW, chip in reset + time.sleep(1.3) # timeouts taken from esptool.py, includes esp32r0 workaround. defaults: 0.1 + self.serial.setDTR(True) # IO0=LOW + self.serial.setRTS(False) # EN=HIGH, chip out of reset + time.sleep(0.45) # timeouts taken from esptool.py, includes esp32r0 workaround. defaults: 0.05 + self.serial.setDTR(False) # IO0=HIGH, done + else: + raise RuntimeError("Bad command data %d" % (cmd)) + def main(): parser = argparse.ArgumentParser("idf_monitor - a serial output monitor for esp-idf") @@ -748,9 +829,9 @@ def main(): yellow_print('--- idf_monitor on {p.name} {p.baudrate} ---'.format( p=serial_instance)) yellow_print('--- Quit: {} | Menu: {} | Help: {} followed by {} ---'.format( - key_description(monitor.exit_key), - key_description(monitor.menu_key), - key_description(monitor.menu_key), + key_description(monitor.console_parser.exit_key), + key_description(monitor.console_parser.menu_key), + key_description(monitor.console_parser.menu_key), key_description(CTRL_H))) if args.print_filter != DEFAULT_PRINT_FILTER: yellow_print('--- Print filter: {} ---'.format(args.print_filter)) From 50629eec271e5815614f607c35a85381a18a734a Mon Sep 17 00:00:00 2001 From: Anton Maklakov Date: Tue, 16 Jul 2019 13:49:27 +0700 Subject: [PATCH 385/486] tools: Add a script to fix up empty prototypes --- tools/ci/executable-list.txt | 1 + tools/ci/fix_empty_prototypes.sh | 50 ++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100755 tools/ci/fix_empty_prototypes.sh diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index 9ae3ae702e..4e580c5a85 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -39,6 +39,7 @@ tools/ci/check_idf_version.sh tools/ci/check_ut_cmake_make.sh tools/ci/checkout_project_ref.py tools/ci/envsubst.py +tools/ci/fix_empty_prototypes.sh tools/ci/get-full-sources.sh tools/ci/get_supported_examples.sh tools/ci/mirror-submodule-update.sh diff --git a/tools/ci/fix_empty_prototypes.sh b/tools/ci/fix_empty_prototypes.sh new file mode 100755 index 0000000000..0aade7861b --- /dev/null +++ b/tools/ci/fix_empty_prototypes.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +# This script finds and fixes up empty prototypes, to satisfy `-Wstrict-prototypes` and to сomply the C Standard + +set -o errexit +set -o pipefail +set -o nounset + +ctags -R -f - --c-kinds=pf --languages="c" --langmap=c:.c.h | grep "([[:space:]]*)" > tmp_ctags.txt || : + +ctags -R -f - --c-kinds=pf --languages="c++" --langmap=c++:.cpp | grep "([[:space:]]*)" | grep -F 'extern "C"' >> tmp_ctags.txt || : + +while read TAGLINE; do + + # a format of ctags: + # https://en.wikipedia.org/wiki/Ctags + + # a 2nd column, + FILENAME=$(printf "$TAGLINE" | sed -E "s/([^[:space:]]+)[[:space:]]([^[:space:]]+)[[:space:]](.+)\;\".*/\2/g") + + # a 3rd column + # a pattern + # /^ void sdmmc_host_dma_stop ( );$/ + OLDLINE=$(printf "$TAGLINE" | sed -E "s/([^[:space:]]+)[[:space:]]([^[:space:]]+)[[:space:]](.+)\;\".*/\3/g") + + # remove leading and trailng '/'-s + OLDLINE="${OLDLINE#/}" + OLDLINE="${OLDLINE%/}" + + # remove leading '^' and trailing '$' + OLDLINE="${OLDLINE#^}" + OLDLINE="${OLDLINE%$}" + + + OLDBRACERS=$(printf "$OLDLINE" | sed "s/.*\(([[:space:]]*)\).*/\1/") + NEWBRACERS="(void)" + + NEWLINE=${OLDLINE/$OLDBRACERS/$NEWBRACERS} + + # escaping + OLDLINE=$(printf "%q" "$OLDLINE") + NEWLINE=$(printf "%q" "$NEWLINE") + + sed -i -E 's,'"^$OLDLINE\$"','"$NEWLINE"',' $FILENAME + +done < tmp_ctags.txt + +echo "+++" +echo "Also 'git grep -E \"^.*\([^\)]+\) *\(\).*$\"' will help to find some callback declarations" +echo "+++" From afbaf74007e89d016dbade4072bf2e7a3874139a Mon Sep 17 00:00:00 2001 From: Anton Maklakov Date: Tue, 16 Jul 2019 16:33:30 +0700 Subject: [PATCH 386/486] tools: Mass fixing of empty prototypes (for -Wstrict-prototypes) --- components/app_trace/app_trace.c | 20 ++--- components/app_trace/gcov/gcov_rtio.c | 2 +- components/app_trace/heap_trace_tohost.c | 2 +- components/app_trace/include/esp_app_trace.h | 2 +- .../sys_view/Config/SEGGER_RTT_Conf.h | 4 +- .../sys_view/Config/SEGGER_SYSVIEW_Conf.h | 2 +- .../Config/SEGGER_SYSVIEW_Config_FreeRTOS.c | 10 +-- components/app_trace/test/test_trace.c | 6 +- components/app_update/esp_ota_ops.c | 6 +- components/app_update/include/esp_ota_ops.h | 6 +- components/app_update/test/test_switch_ota.c | 2 +- .../subproject/main/bootloader_start.c | 4 +- .../include/bootloader_common.h | 2 +- .../include/bootloader_flash_config.h | 4 +- .../include/esp_flash_encrypt.h | 4 +- .../include_bootloader/bootloader_flash.h | 2 +- .../include_bootloader/bootloader_init.h | 2 +- .../include_bootloader/bootloader_sha.h | 2 +- .../include_bootloader/flash_qio_mode.h | 2 +- .../bootloader_support/src/bootloader_clock.c | 2 +- .../src/bootloader_common.c | 2 +- .../bootloader_support/src/bootloader_flash.c | 4 +- .../src/bootloader_flash_config.c | 4 +- .../bootloader_support/src/bootloader_init.c | 8 +- .../src/esp32/bootloader_sha.c | 2 +- .../src/esp32/flash_encrypt.c | 4 +- .../src/esp32/secure_boot.c | 2 +- .../bootloader_support/src/flash_encrypt.c | 4 +- .../bootloader_support/src/flash_qio_mode.c | 18 ++--- .../src/idf/bootloader_sha.c | 2 +- .../bt/host/bluedroid/api/esp_spp_api.c | 4 +- .../bluedroid/api/include/api/esp_spp_api.h | 2 +- .../bt/host/bluedroid/bta/dm/bta_dm_main.c | 4 +- .../bt/host/bluedroid/bta/dm/bta_dm_pm.c | 4 +- .../bt/host/bluedroid/bta/gatt/bta_gattc_co.c | 2 +- .../bta/hf_client/bta_hf_client_at.c | 6 +- .../bta/hf_client/include/bta_hf_client_int.h | 2 +- .../bluedroid/bta/include/bta/bta_gatt_api.h | 2 +- .../bt/host/bluedroid/bta/jv/bta_jv_act.c | 2 +- .../bluedroid/btc/core/btc_profile_queue.c | 2 +- .../btc/profile/std/a2dp/btc_a2dp_source.c | 2 +- .../btc/profile/std/smp/esp_app_sec.c | 2 +- .../bluedroid/btc/profile/std/spp/btc_spp.c | 2 +- .../bt/host/bluedroid/device/controller.c | 2 +- .../device/include/device/controller.h | 2 +- components/bt/host/bluedroid/hci/hci_hal_h4.c | 4 +- components/bt/host/bluedroid/hci/hci_layer.c | 4 +- .../host/bluedroid/hci/hci_packet_factory.c | 2 +- .../bt/host/bluedroid/hci/hci_packet_parser.c | 2 +- .../bluedroid/hci/include/hci/hci_layer.h | 2 +- .../hci/include/hci/hci_packet_factory.h | 2 +- .../hci/include/hci/hci_packet_parser.h | 2 +- .../hci/include/hci/packet_fragmenter.h | 2 +- .../bt/host/bluedroid/hci/packet_fragmenter.c | 6 +- components/bt/host/bluedroid/main/bte_main.c | 4 +- .../bt/host/bluedroid/stack/avdt/avdt_api.c | 4 +- .../bluedroid/stack/btm/btm_ble_adv_filter.c | 2 +- .../host/bluedroid/stack/btm/btm_ble_bgconn.c | 6 +- .../bt/host/bluedroid/stack/btm/btm_ble_gap.c | 4 +- .../bluedroid/stack/btm/btm_ble_multi_adv.c | 2 +- .../stack/include/stack/btm_ble_api.h | 6 +- components/coap/port/coap_io.c | 2 +- components/console/commands.c | 4 +- components/console/esp_console.h | 4 +- components/console/linenoise/linenoise.c | 8 +- components/console/linenoise/linenoise.h | 2 +- components/cxx/cxx_guards.cpp | 4 +- components/driver/adc1_i2s_private.h | 8 +- components/driver/can.c | 28 +++---- components/driver/gpio.c | 2 +- components/driver/i2c.c | 2 +- components/driver/i2s.c | 2 +- components/driver/include/driver/adc.h | 8 +- .../include/driver/adc2_wifi_internal.h | 4 +- components/driver/include/driver/can.h | 12 +-- components/driver/include/driver/dac.h | 4 +- components/driver/include/driver/gpio.h | 2 +- components/driver/include/driver/i2c.h | 2 +- components/driver/include/driver/ledc.h | 2 +- components/driver/include/driver/rtc_io.h | 2 +- components/driver/include/driver/sdio_slave.h | 10 +-- components/driver/include/driver/sdmmc_host.h | 4 +- components/driver/include/driver/sdspi_host.h | 4 +- components/driver/include/driver/spi_common.h | 2 +- components/driver/include/driver/touch_pad.h | 18 ++--- .../driver/include/driver/uart_select.h | 2 +- components/driver/ledc.c | 2 +- components/driver/rmt.c | 2 +- components/driver/rtc_module.c | 50 ++++++------ components/driver/sdio_slave.c | 78 +++++++++---------- components/driver/sdmmc_host.c | 18 ++--- components/driver/sdmmc_private.h | 12 +-- components/driver/sdmmc_transaction.c | 12 +-- components/driver/sdspi_host.c | 4 +- components/driver/spi_common.c | 2 +- components/driver/test/test_i2c.c | 20 ++--- components/driver/test/test_rmt.c | 4 +- components/driver/test/test_spi_sio.c | 4 +- components/driver/test/test_spi_slave.c | 2 +- components/driver/test/test_timer.c | 4 +- components/driver/test/test_uart.c | 6 +- components/driver/uart.c | 2 +- components/efuse/include/esp_efuse.h | 2 +- components/efuse/src/esp_efuse_fields.c | 4 +- components/efuse/src/esp_efuse_utility.c | 10 +-- components/efuse/src/esp_efuse_utility.h | 8 +- components/esp-tls/esp_tls.c | 8 +- components/esp-tls/esp_tls.h | 8 +- components/esp32/brownout.c | 4 +- components/esp32/cache_err_int.c | 4 +- components/esp32/clk.c | 2 +- components/esp32/cpu_start.c | 8 +- components/esp32/crosscore_int.c | 4 +- components/esp32/esp_clk_internal.h | 2 +- components/esp32/esp_himem.c | 8 +- components/esp32/esp_timer_esp32.c | 14 ++-- components/esp32/include/esp32/brownout.h | 2 +- .../esp32/include/esp32/cache_err_int.h | 4 +- components/esp32/include/esp32/clk.h | 4 +- components/esp32/include/esp32/himem.h | 6 +- components/esp32/include/esp32/spiram.h | 14 ++-- components/esp32/include/esp_intr_alloc.h | 4 +- components/esp32/include/esp_sleep.h | 16 ++-- components/esp32/int_wdt.c | 4 +- components/esp32/intr_alloc.c | 4 +- components/esp32/panic.c | 16 ++-- components/esp32/pm_esp32.c | 18 ++--- components/esp32/pm_trace.c | 2 +- components/esp32/reset_reason.c | 4 +- components/esp32/sleep_modes.c | 38 ++++----- components/esp32/spiram.c | 20 ++--- components/esp32/spiram_psram.c | 2 +- components/esp32/spiram_psram.h | 2 +- components/esp32/system_api.c | 6 +- components/esp32/task_wdt.c | 8 +- components/esp32/test/test_4mpsram.c | 2 +- components/esp32/test/test_ahb_arb.c | 4 +- components/esp32/test/test_esp_timer.c | 8 +- components/esp32/test/test_intr_alloc.c | 2 +- components/esp32/test/test_pm.c | 4 +- components/esp32/test/test_reset_reason.c | 36 ++++----- components/esp32/test/test_sleep.c | 20 ++--- components/esp32/test/test_stack_check.c | 2 +- components/esp_adc_cal/esp_adc_cal.c | 6 +- components/esp_common/include/esp_int_wdt.h | 4 +- .../include/esp_private/crosscore_int.h | 2 +- .../include/esp_private/esp_timer_impl.h | 10 +-- .../esp_common/include/esp_private/pm_impl.h | 10 +-- .../esp_common/include/esp_private/pm_trace.h | 2 +- .../include/esp_private/system_internal.h | 2 +- components/esp_common/include/esp_task_wdt.h | 6 +- components/esp_common/include/esp_timer.h | 8 +- components/esp_common/src/dbg_stubs.c | 2 +- components/esp_common/src/esp_timer.c | 16 ++-- components/esp_common/src/freertos_hooks.c | 4 +- components/esp_common/src/ipc.c | 4 +- components/esp_event/default_event_loop.c | 4 +- components/esp_event/esp_event.c | 2 +- components/esp_event/event_loop_legacy.c | 2 +- components/esp_event/include/esp_event.h | 4 +- .../esp_event/include/esp_event_legacy.h | 4 +- .../private_include/esp_event_private.h | 2 +- components/esp_event/test/test_event.c | 8 +- components/esp_gdbstub/esp32/gdbstub_esp32.c | 4 +- .../private_include/esp_gdbstub_common.h | 8 +- components/esp_gdbstub/src/gdbstub.c | 12 +-- components/esp_gdbstub/src/packet.c | 4 +- components/esp_http_client/lib/http_header.c | 2 +- .../esp_http_client/lib/include/http_header.h | 2 +- components/esp_http_server/src/httpd_sess.c | 2 +- .../esp_http_server/src/port/esp32/osal.h | 4 +- .../esp_local_ctrl/include/esp_local_ctrl.h | 4 +- components/esp_ringbuf/test/test_ringbuf.c | 10 +-- .../esp_rom/include/esp32/rom/tbconsole.h | 2 +- .../esp_websocket_client.c | 2 +- components/esp_wifi/include/esp_phy_init.h | 2 +- components/esp_wifi/include/phy.h | 2 +- components/esp_wifi/src/phy_init.c | 4 +- components/esp_wifi/src/wifi_init.c | 4 +- components/esp_wifi/test/test_phy_rtc.c | 4 +- .../espcoredump/include/esp_core_dump.h | 2 +- .../include_core_dump/esp_core_dump_priv.h | 2 +- components/espcoredump/src/core_dump_common.c | 2 +- components/espcoredump/src/core_dump_flash.c | 2 +- components/espcoredump/src/core_dump_uart.c | 2 +- components/espcoredump/test/test_core_dump.c | 4 +- components/fatfs/test/test_fatfs_rawflash.c | 2 +- components/fatfs/test/test_fatfs_spiflash.c | 4 +- components/fatfs/vfs/esp_vfs_fat.h | 4 +- components/fatfs/vfs/vfs_fat.c | 4 +- components/fatfs/vfs/vfs_fat_sdmmc.c | 2 +- .../freemodbus/common/esp_modbus_master.c | 4 +- .../freemodbus/common/esp_modbus_slave.c | 4 +- components/freemodbus/port/port.c | 4 +- components/freemodbus/port/port.h | 4 +- components/freemodbus/port/portserial.c | 4 +- components/freemodbus/port/portserial_m.c | 4 +- components/freemodbus/port/porttimer.c | 6 +- components/freemodbus/port/porttimer_m.c | 10 +-- .../modbus_controller/mbc_serial_slave.c | 2 +- .../freertos/include/freertos/portable.h | 6 +- .../freertos/include/freertos/portmacro.h | 6 +- components/freertos/port.c | 6 +- components/freertos/tasks.c | 2 +- .../test/test_freertos_backported_functions.c | 2 +- .../freertos/test/test_freertos_eventgroups.c | 6 +- .../freertos/test/test_freertos_task_notify.c | 2 +- .../freertos/test/test_task_suspend_resume.c | 6 +- components/heap/heap_caps.c | 2 +- components/heap/heap_caps_init.c | 4 +- components/heap/include/esp_heap_caps.h | 2 +- components/heap/include/esp_heap_caps_init.h | 4 +- components/heap/test/test_malloc.c | 4 +- components/heap/test/test_malloc_caps.c | 2 +- components/libsodium/test/test_sodium.c | 14 ++-- components/log/log.c | 10 +-- components/lwip/apps/dhcpserver/dhcpserver.c | 2 +- .../lwip/include/apps/dhcpserver/dhcpserver.h | 2 +- .../lwip/port/esp32/include/arch/vfs_lwip.h | 2 +- components/lwip/port/esp32/vfs_lwip.c | 4 +- components/lwip/test_afl_host/dhcp_di.h | 2 +- components/lwip/test_afl_host/dhcpserver_di.h | 2 +- components/lwip/test_afl_host/dns_di.h | 2 +- .../lwip/test_afl_host/test_dhcp_client.c | 2 +- .../lwip/test_afl_host/test_dhcp_server.c | 2 +- components/lwip/test_afl_host/test_dns.c | 2 +- components/mbedtls/port/esp_bignum.c | 2 +- .../mbedtls/test/test_apb_dport_access.c | 8 +- .../mbedtls/test/test_apb_dport_access.h | 4 +- components/mdns/include/mdns.h | 6 +- components/mdns/include/mdns_console.h | 2 +- components/mdns/mdns.c | 30 +++---- components/mdns/mdns_console.c | 40 +++++----- components/mdns/mdns_networking.c | 6 +- .../mdns/test_afl_fuzz_host/esp32_compat.h | 2 +- .../mdns/test_afl_fuzz_host/esp32_mock.c | 4 +- .../mdns/test_afl_fuzz_host/esp32_mock.h | 2 +- components/mdns/test_afl_fuzz_host/mdns_di.h | 2 +- components/mdns/test_afl_fuzz_host/test.c | 4 +- components/newlib/heap.c | 6 +- components/newlib/locks.c | 2 +- .../newlib/platform_include/esp_newlib.h | 8 +- components/newlib/pthread.c | 2 +- components/newlib/reent_init.c | 6 +- components/newlib/syscall_table.c | 2 +- components/newlib/syscalls.c | 2 +- components/newlib/time.c | 16 ++-- components/nvs_flash/src/nvs_api.cpp | 2 +- .../openssl/include/internal/ssl_x509.h | 2 +- components/openssl/library/ssl_x509.c | 2 +- .../protocomm/include/common/protocomm.h | 2 +- components/protocomm/src/common/protocomm.c | 2 +- .../protocomm/src/simple_ble/simple_ble.c | 6 +- .../protocomm/src/simple_ble/simple_ble.h | 6 +- components/pthread/include/esp_pthread.h | 2 +- components/pthread/pthread.c | 6 +- components/pthread/pthread_cond_var.c | 2 +- components/pthread/pthread_internal.h | 2 +- components/pthread/pthread_local_storage.c | 4 +- components/sdmmc/test/test_sd.c | 4 +- components/sdmmc/test/test_sdio.c | 2 +- components/soc/esp32/cpu_util.c | 2 +- components/soc/esp32/include/soc/cpu.h | 8 +- components/soc/esp32/include/soc/rtc.h | 28 +++---- components/soc/esp32/rtc_clk.c | 36 ++++----- components/soc/esp32/rtc_clk_init.c | 4 +- components/soc/esp32/rtc_init.c | 2 +- components/soc/esp32/rtc_pm.c | 8 +- components/soc/esp32/rtc_time.c | 4 +- components/soc/esp32/rtc_wdt.c | 16 ++-- components/soc/esp32/test/test_rtc_clk.c | 2 +- components/soc/include/soc/rtc_wdt.h | 16 ++-- .../soc/include/soc/soc_memory_layout.h | 2 +- components/soc/src/memory_layout_utils.c | 4 +- components/spi_flash/cache_utils.c | 30 +++---- components/spi_flash/cache_utils.h | 14 ++-- components/spi_flash/esp_flash_api.c | 2 +- components/spi_flash/esp_flash_spi_init.c | 4 +- components/spi_flash/flash_mmap.c | 6 +- components/spi_flash/flash_ops.c | 24 +++--- components/spi_flash/include/esp_flash.h | 4 +- components/spi_flash/include/esp_spi_flash.h | 16 ++-- components/spi_flash/partition.c | 4 +- components/spi_flash/sim/flash_mock.cpp | 2 +- components/spi_flash/sim/flash_mock_util.c | 16 ++-- components/spi_flash/sim/stubs/log/log.c | 2 +- components/spi_flash/spi_flash_rom_patch.c | 6 +- components/spi_flash/test/test_esp_flash.c | 2 +- .../spi_flash/test/test_flash_encryption.c | 2 +- components/spi_flash/test/test_mmap.c | 2 +- components/spi_flash/test/test_read_write.c | 2 +- components/spiffs/test/test_spiffs.c | 4 +- .../tcp_transport/include/esp_transport.h | 4 +- .../tcp_transport/include/esp_transport_ssl.h | 2 +- .../tcp_transport/include/esp_transport_tcp.h | 2 +- components/tcp_transport/transport.c | 4 +- components/tcp_transport/transport_ssl.c | 2 +- components/tcp_transport/transport_tcp.c | 2 +- components/tcpip_adapter/event_handlers.c | 8 +- .../tcpip_adapter/include/tcpip_adapter.h | 8 +- components/unity/include/unity_test_runner.h | 4 +- components/unity/unity_port_esp32.c | 2 +- components/unity/unity_runner.c | 4 +- components/vfs/include/esp_vfs_dev.h | 2 +- components/vfs/test/test_vfs_access.c | 4 +- components/vfs/test/test_vfs_select.c | 6 +- components/vfs/test/test_vfs_uart.c | 2 +- components/vfs/vfs.c | 2 +- components/vfs/vfs_uart.c | 6 +- .../src/esp_supplicant/esp_wpa_main.c | 4 +- .../bluetooth/ble_ancs/main/ble_ancs_demo.c | 2 +- .../main/ble_compatibility_test.c | 2 +- .../ble_eddystone/main/esp_eddystone_demo.c | 2 +- .../main/ble_hidd_demo_main.c | 2 +- .../ble/ble_ibeacon/main/ibeacon_demo.c | 2 +- .../ble/ble_spp_client/main/spp_client_demo.c | 2 +- .../ble_spp_server/main/ble_spp_server_demo.c | 2 +- .../main/example_ble_client_throughput.c | 2 +- .../main/example_ble_server_throughput.c | 2 +- .../ble/blufi/main/blufi_example_main.c | 2 +- .../ble/gatt_client/main/gattc_demo.c | 2 +- .../main/example_ble_sec_gattc_demo.c | 2 +- .../main/example_ble_sec_gatts_demo.c | 2 +- .../ble/gatt_server/main/gatts_demo.c | 2 +- .../main/gatts_table_creat_demo.c | 2 +- .../main/gattc_multi_connect.c | 2 +- .../classic_bt/a2dp_sink/main/main.c | 2 +- .../classic_bt/a2dp_source/main/main.c | 2 +- .../bt_discovery/main/bt_discovery.c | 2 +- .../main/example_spp_acceptor_demo.c | 2 +- .../main/example_spp_initiator_demo.c | 2 +- .../main/example_spp_vfs_acceptor_demo.c | 2 +- .../main/example_spp_vfs_initiator_demo.c | 2 +- .../coex/a2dp_gatts_coex/main/main.c | 2 +- .../gattc_gatts_coex/main/gattc_gatts_coex.c | 2 +- .../main/controller_hci_uart_demo.c | 2 +- .../hci/controller_vhci_ble_adv/main/app_bt.c | 2 +- .../ble_mesh_node/main/ble_mesh_adapter.c | 6 +- .../ble_mesh_node/main/ble_mesh_adapter.h | 6 +- .../main/ble_mesh_console_decl.h | 10 +-- .../main/ble_mesh_console_main.c | 4 +- .../main/ble_mesh_console_system.c | 14 ++-- .../main/ble_mesh_register_node_cmd.c | 10 +-- .../main/ble_mesh_register_server_cmd.c | 6 +- .../ble_mesh_node/main/register_bluetooth.c | 8 +- .../main/ble_mesh_adapter.c | 8 +- .../main/ble_mesh_adapter.h | 8 +- .../main/ble_mesh_console_decl.h | 14 ++-- .../main/ble_mesh_console_main.c | 4 +- .../main/ble_mesh_console_system.c | 14 ++-- .../main/ble_mesh_reg_cfg_client_cmd.c | 6 +- .../main/ble_mesh_reg_gen_onoff_client_cmd.c | 6 +- .../main/ble_mesh_reg_test_perf_client_cmd.c | 6 +- .../main/ble_mesh_register_node_cmd.c | 8 +- .../main/ble_mesh_register_provisioner_cmd.c | 8 +- .../main/register_bluetooth.c | 6 +- .../components/iperf/cmd_wifi.c | 2 +- .../main/ble_mesh_demo_main.c | 2 +- .../bluetooth/nimble/blemesh/main/app_mesh.c | 2 +- examples/bluetooth/nimble/bleprph/main/scli.c | 4 +- examples/build_system/cmake/idf_as_lib/main.c | 2 +- .../cmake/idf_as_lib/stubs/esp32/cpu_start.c | 4 +- .../cmake/idf_as_lib/stubs/esp32/flash_ops.c | 2 +- .../stubs/spi_flash/esp_spi_flash.h | 2 +- .../protocol_examples_common/connect.c | 16 ++-- .../include/protocol_examples_common.h | 6 +- .../protocol_examples_common/stdin_out.c | 2 +- .../basic/main/ethernet_example_main.c | 2 +- .../eth2ap/main/ethernet_example_main.c | 2 +- examples/ethernet/iperf/main/cmd_ethernet.c | 2 +- examples/ethernet/iperf/main/cmd_ethernet.h | 2 +- .../iperf/main/ethernet_example_main.c | 8 +- examples/get-started/blink/main/blink.c | 2 +- .../hello_world/main/hello_world_main.c | 2 +- .../peripherals/adc/main/adc1_example_main.c | 4 +- .../can_alert_and_recovery_example_main.c | 2 +- .../can_network_example_listen_only_main.c | 2 +- .../main/can_network_example_master_main.c | 2 +- .../main/can_network_example_slave_main.c | 2 +- .../main/can_self_test_example_main.c | 2 +- .../peripherals/gpio/main/gpio_example_main.c | 2 +- .../i2c/i2c_self_test/main/i2c_example_main.c | 6 +- .../i2c/i2c_tools/main/cmd_i2ctools.c | 2 +- .../i2c_tools/main/i2ctools_example_main.c | 8 +- .../peripherals/i2s/main/i2s_example_main.c | 2 +- .../peripherals/i2s_adc_dac/main/app_main.c | 10 +-- .../peripherals/ledc/main/ledc_example_main.c | 2 +- .../main/mcpwm_basic_config_example.c | 6 +- .../mcpwm_bldc_control_hall_sensor_example.c | 6 +- .../main/mcpwm_brushed_dc_control_example.c | 4 +- .../main/mcpwm_servo_control_example.c | 4 +- .../peripherals/pcnt/main/pcnt_example_main.c | 2 +- .../rmt_nec_tx_rx/main/infrared_nec_main.c | 10 +-- .../peripherals/rmt_tx/main/rmt_tx_main.c | 2 +- .../peripherals/sdio/host/main/app_main.c | 6 +- .../peripherals/sdio/slave/main/app_main.c | 8 +- .../sigmadelta/main/sigmadelta_example_main.c | 2 +- .../spi_master/main/pretty_effect.c | 2 +- .../spi_master/main/pretty_effect.h | 2 +- .../spi_master/main/spi_master_example_main.c | 2 +- .../spi_slave/receiver/main/app_main.c | 2 +- .../spi_slave/sender/main/app_main.c | 2 +- .../main/timer_group_example_main.c | 2 +- .../main/tp_interrupt_main.c | 4 +- .../touch_pad_read/main/tp_read_main.c | 4 +- .../main/nmea_parser_example_main.c | 2 +- .../main/uart_async_rxtxtasks_main.c | 8 +- .../uart_echo/main/uart_echo_example_main.c | 4 +- .../uart/uart_echo_rs485/main/rs485_example.c | 4 +- .../main/uart_events_example_main.c | 2 +- .../main/uart_select_example_main.c | 4 +- .../asio/chat_client/main/chat_client.cpp | 2 +- .../asio/chat_server/main/chat_server.cpp | 2 +- .../asio/tcp_echo_server/main/echo_server.cpp | 2 +- .../udp_echo_server/main/udp_echo_server.cpp | 2 +- .../main/esp_http_client_example.c | 30 +++---- .../protocols/esp_local_ctrl/main/app_main.c | 4 +- .../main/http2_request_example_main.c | 2 +- .../main/http_request_example_main.c | 2 +- .../http_server/advanced_tests/main/main.c | 2 +- .../http_server/advanced_tests/main/tests.c | 4 +- .../http_server/file_serving/main/main.c | 2 +- .../persistent_sockets/main/main.c | 2 +- .../restful_server/main/esp_rest_main.c | 2 +- .../protocols/http_server/simple/main/main.c | 2 +- .../main/https_mbedtls_example_main.c | 2 +- .../main/https_request_example_main.c | 2 +- examples/protocols/https_server/main/main.c | 2 +- .../protocols/mdns/main/mdns_example_main.c | 6 +- .../modbus_master/main/include/sense_modbus.h | 2 +- .../protocols/modbus_master/main/sense_main.c | 4 +- .../modbus_master/main/sense_modbus.c | 4 +- .../protocols/modbus_slave/main/freemodbus.c | 4 +- .../mqtt/publish_test/main/publish_test.c | 2 +- examples/protocols/mqtt/ssl/main/app_main.c | 2 +- .../mqtt/ssl_mutual_auth/main/app_main.c | 2 +- examples/protocols/mqtt/tcp/main/app_main.c | 2 +- examples/protocols/mqtt/ws/main/app_main.c | 2 +- examples/protocols/mqtt/wss/main/app_main.c | 2 +- .../pppos_client/main/pppos_client_main.c | 2 +- .../protocols/sntp/main/sntp_example_main.c | 2 +- .../sockets/tcp_client/main/tcp_client.c | 2 +- .../sockets/tcp_server/main/tcp_server.c | 2 +- .../sockets/udp_client/main/udp_client.c | 2 +- .../main/udp_multicast_example_main.c | 6 +- .../sockets/udp_server/main/udp_server.c | 2 +- .../websocket/main/websocket_example.c | 2 +- .../provisioning/ble_prov/main/app_main.c | 8 +- .../provisioning/console_prov/main/app_main.c | 6 +- .../custom_config/main/app_main.c | 6 +- examples/provisioning/manager/main/app_main.c | 4 +- .../provisioning/softap_prov/main/app_main.c | 6 +- .../main/flash_encrypt_main.c | 2 +- .../main/ext_flash_fatfs_example_main.c | 4 +- .../nvs_rw_blob/main/nvs_blob_example_main.c | 2 +- .../main/nvs_value_example_main.c | 2 +- .../spiffsgen/main/spiffsgen_example_main.c | 4 +- .../main/app_trace_to_host_example_main.c | 2 +- .../main/base_mac_address_example_main.c | 2 +- .../console/components/cmd_nvs/cmd_nvs.c | 2 +- .../console/components/cmd_nvs/cmd_nvs.h | 2 +- .../components/cmd_system/cmd_system.c | 30 +++---- .../components/cmd_system/cmd_system.h | 2 +- examples/system/console/main/cmd_wifi.c | 2 +- examples/system/console/main/cmd_wifi.h | 2 +- .../console/main/console_example_main.c | 8 +- .../main/exception_example_main.cpp | 2 +- .../system/cpp_pthread/main/cpp_pthread.cpp | 2 +- .../deep_sleep/main/deep_sleep_example_main.c | 6 +- .../esp_timer/main/esp_timer_example_main.c | 2 +- .../freertos/real_time_stats/main/main.c | 2 +- examples/system/gcov/main/gcov_example.c | 2 +- examples/system/himem/main/himem_test_main.c | 2 +- .../main/light_sleep_example_main.c | 2 +- .../system/network_tests/main/net_suite.c | 2 +- .../main/advanced_https_ota_example.c | 2 +- .../main/native_ota_example.c | 4 +- .../system/ota/otatool/main/otatool_main.c | 2 +- .../main/simple_ota_example.c | 2 +- examples/system/select/main/select_example.c | 10 +-- .../sysview_tracing/main/sysview_tracing.c | 2 +- .../main/sysview_heap_log.c | 2 +- .../main/task_watchdog_example_main.c | 2 +- examples/system/ulp/main/ulp_example_main.c | 10 +-- .../ulp_adc/main/ulp_adc_example_main.c | 10 +-- .../test/main/example_unit_test_test.c | 2 +- .../wifi/espnow/main/espnow_example_main.c | 2 +- .../softAP/main/softap_example_main.c | 4 +- .../station/main/station_example_main.c | 4 +- examples/wifi/iperf/main/cmd_wifi.c | 2 +- examples/wifi/iperf/main/iperf_example_main.c | 2 +- examples/wifi/power_save/main/power_save.c | 2 +- examples/wifi/scan/main/scan.c | 2 +- .../wifi/simple_sniffer/main/cmd_sniffer.c | 4 +- .../wifi/simple_sniffer/main/cmd_sniffer.h | 2 +- .../main/simple_sniffer_example_main.c | 12 +-- .../wifi/smart_config/main/smartconfig_main.c | 2 +- .../main/wpa2_enterprise_main.c | 2 +- examples/wifi/wps/main/wps.c | 2 +- tools/esp_app_trace/test/sysview/blink.c | 2 +- tools/kconfig/nconf.gui.c | 2 +- .../test_utils/include/test_utils.h | 10 +-- .../components/test_utils/ref_clock.c | 6 +- .../components/test_utils/test_runner.c | 4 +- .../components/test_utils/test_utils.c | 4 +- tools/unit-test-app/main/app_main.c | 2 +- .../tool_setup/cmdlinerunner/cmdlinerunner.c | 4 +- 507 files changed, 1295 insertions(+), 1295 deletions(-) diff --git a/components/app_trace/app_trace.c b/components/app_trace/app_trace.c index 5a577a70dc..c85ad6a2ac 100644 --- a/components/app_trace/app_trace.c +++ b/components/app_trace/app_trace.c @@ -360,7 +360,7 @@ static esp_apptrace_hw_t s_trace_hw[ESP_APPTRACE_HW_MAX] = { } }; -static inline int esp_apptrace_log_lock() +static inline int esp_apptrace_log_lock(void) { #if ESP_APPTRACE_PRINT_LOCK esp_apptrace_tmo_t tmo; @@ -372,14 +372,14 @@ static inline int esp_apptrace_log_lock() #endif } -static inline void esp_apptrace_log_unlock() +static inline void esp_apptrace_log_unlock(void) { #if ESP_APPTRACE_PRINT_LOCK esp_apptrace_lock_give(&s_log_lock); #endif } -static inline esp_err_t esp_apptrace_lock_initialize() +static inline esp_err_t esp_apptrace_lock_initialize(void) { #if CONFIG_ESP32_APPTRACE_LOCK_ENABLE esp_apptrace_lock_init(&s_trace_buf.lock); @@ -387,7 +387,7 @@ static inline esp_err_t esp_apptrace_lock_initialize() return ESP_OK; } -static inline esp_err_t esp_apptrace_lock_cleanup() +static inline esp_err_t esp_apptrace_lock_cleanup(void) { return ESP_OK; } @@ -403,7 +403,7 @@ esp_err_t esp_apptrace_lock(esp_apptrace_tmo_t *tmo) return ESP_OK; } -esp_err_t esp_apptrace_unlock() +esp_err_t esp_apptrace_unlock(void) { esp_err_t ret = ESP_OK; #if CONFIG_ESP32_APPTRACE_LOCK_ENABLE @@ -413,7 +413,7 @@ esp_err_t esp_apptrace_unlock() } #if CONFIG_ESP32_APPTRACE_DEST_TRAX -static void esp_apptrace_trax_init() +static void esp_apptrace_trax_init(void) { // Stop trace, if any (on the current CPU) eri_write(ERI_TRAX_TRAXCTRL, TRAXCTRL_TRSTP); @@ -449,7 +449,7 @@ static void esp_apptrace_trax_pend_chunk_sz_update(uint16_t size) } } -static uint16_t esp_apptrace_trax_pend_chunk_sz_get() +static uint16_t esp_apptrace_trax_pend_chunk_sz_get(void) { uint16_t ch_sz; ESP_APPTRACE_LOGD("Get chunk enter %d w-r-s %d-%d-%d", s_trace_buf.trax.cur_pending_chunk_sz, @@ -467,7 +467,7 @@ static uint16_t esp_apptrace_trax_pend_chunk_sz_get() #endif // assumed to be protected by caller from multi-core/thread access -static esp_err_t esp_apptrace_trax_block_switch() +static esp_err_t esp_apptrace_trax_block_switch(void) { int prev_block_num = s_trace_buf.trax.state.in_block % 2; int new_block_num = prev_block_num ? (0) : (1); @@ -845,7 +845,7 @@ static esp_err_t esp_apptrace_trax_status_reg_get(uint32_t *val) return ESP_OK; } -static esp_err_t esp_apptrace_trax_dest_init() +static esp_err_t esp_apptrace_trax_dest_init(void) { for (int i = 0; i < ESP_APPTRACE_TRAX_BLOCKS_NUM; i++) { s_trace_buf.trax.blocks[i].start = (uint8_t *)s_trax_blocks[i]; @@ -874,7 +874,7 @@ static esp_err_t esp_apptrace_trax_dest_init() } #endif -esp_err_t esp_apptrace_init() +esp_err_t esp_apptrace_init(void) { int res; diff --git a/components/app_trace/gcov/gcov_rtio.c b/components/app_trace/gcov/gcov_rtio.c index 41306b2881..d01d7c6b6b 100644 --- a/components/app_trace/gcov/gcov_rtio.c +++ b/components/app_trace/gcov/gcov_rtio.c @@ -114,7 +114,7 @@ static int esp_dbg_stub_gcov_entry(void) #endif } -void esp_gcov_dump() +void esp_gcov_dump(void) { // disable IRQs on this CPU, other CPU is halted by OpenOCD unsigned irq_state = portENTER_CRITICAL_NESTED(); diff --git a/components/app_trace/heap_trace_tohost.c b/components/app_trace/heap_trace_tohost.c index 764022aba4..41dd92a65e 100644 --- a/components/app_trace/heap_trace_tohost.c +++ b/components/app_trace/heap_trace_tohost.c @@ -32,7 +32,7 @@ static bool s_tracing; -esp_err_t heap_trace_init_tohost() +esp_err_t heap_trace_init_tohost(void) { if (s_tracing) { return ESP_ERR_INVALID_STATE; diff --git a/components/app_trace/include/esp_app_trace.h b/components/app_trace/include/esp_app_trace.h index a623ada7fa..822b698ee9 100644 --- a/components/app_trace/include/esp_app_trace.h +++ b/components/app_trace/include/esp_app_trace.h @@ -33,7 +33,7 @@ typedef enum { * * @return ESP_OK on success, otherwise see esp_err_t */ -esp_err_t esp_apptrace_init(); +esp_err_t esp_apptrace_init(void); /** * @brief Configures down buffer. diff --git a/components/app_trace/sys_view/Config/SEGGER_RTT_Conf.h b/components/app_trace/sys_view/Config/SEGGER_RTT_Conf.h index 2325944e5a..a468797800 100644 --- a/components/app_trace/sys_view/Config/SEGGER_RTT_Conf.h +++ b/components/app_trace/sys_view/Config/SEGGER_RTT_Conf.h @@ -285,12 +285,12 @@ Revision: $Rev: 5626 $ * RTT lock configuration fallback */ #ifndef SEGGER_RTT_LOCK - void SEGGER_SYSVIEW_X_RTT_Lock(); + void SEGGER_SYSVIEW_X_RTT_Lock(void); #define SEGGER_RTT_LOCK() SEGGER_SYSVIEW_X_RTT_Lock() // Lock RTT (nestable) (i.e. disable interrupts) #endif #ifndef SEGGER_RTT_UNLOCK - void SEGGER_SYSVIEW_X_RTT_Unlock(); + void SEGGER_SYSVIEW_X_RTT_Unlock(void); #define SEGGER_RTT_UNLOCK() SEGGER_SYSVIEW_X_RTT_Unlock() // Unlock RTT (nestable) (i.e. enable previous interrupt lock state) #endif diff --git a/components/app_trace/sys_view/Config/SEGGER_SYSVIEW_Conf.h b/components/app_trace/sys_view/Config/SEGGER_SYSVIEW_Conf.h index 2968c6e021..aee813a3b1 100644 --- a/components/app_trace/sys_view/Config/SEGGER_SYSVIEW_Conf.h +++ b/components/app_trace/sys_view/Config/SEGGER_SYSVIEW_Conf.h @@ -166,7 +166,7 @@ Revision: $Rev: 5927 $ #define SEGGER_SYSVIEW_GET_INTERRUPT_ID() SEGGER_SYSVIEW_X_GetInterruptId() // Get the currently active interrupt Id from the user-provided function. #endif -unsigned SEGGER_SYSVIEW_X_SysView_Lock(); +unsigned SEGGER_SYSVIEW_X_SysView_Lock(void); void SEGGER_SYSVIEW_X_SysView_Unlock(unsigned int_state); // to be recursive save IRQ status on the stack of the caller #define SEGGER_SYSVIEW_LOCK() unsigned _SYSVIEW_int_state = SEGGER_SYSVIEW_X_SysView_Lock() diff --git a/components/app_trace/sys_view/Sample/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c b/components/app_trace/sys_view/Sample/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c index 90db930d55..b1e9fc14e1 100644 --- a/components/app_trace/sys_view/Sample/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c +++ b/components/app_trace/sys_view/Sample/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c @@ -244,7 +244,7 @@ static void _cbSendSystemDesc(void) { * ********************************************************************** */ -static void SEGGER_SYSVIEW_TS_Init() +static void SEGGER_SYSVIEW_TS_Init(void) { /* We only need to initialize something if we use Timer Group. * esp_timer and ccount can be used as is. @@ -316,7 +316,7 @@ void SEGGER_SYSVIEW_Conf(void) { SEGGER_SYSVIEW_DisableEvents(disable_evts); } -U32 SEGGER_SYSVIEW_X_GetTimestamp() +U32 SEGGER_SYSVIEW_X_GetTimestamp(void) { #if TS_USE_TIMERGROUP uint64_t ts = 0; @@ -329,15 +329,15 @@ U32 SEGGER_SYSVIEW_X_GetTimestamp() #endif } -void SEGGER_SYSVIEW_X_RTT_Lock() +void SEGGER_SYSVIEW_X_RTT_Lock(void) { } -void SEGGER_SYSVIEW_X_RTT_Unlock() +void SEGGER_SYSVIEW_X_RTT_Unlock(void) { } -unsigned SEGGER_SYSVIEW_X_SysView_Lock() +unsigned SEGGER_SYSVIEW_X_SysView_Lock(void) { esp_apptrace_tmo_t tmo; esp_apptrace_tmo_init(&tmo, SEGGER_LOCK_WAIT_TMO); diff --git a/components/app_trace/test/test_trace.c b/components/app_trace/test/test_trace.c index 6d95a87c55..3037ab4315 100644 --- a/components/app_trace/test/test_trace.c +++ b/components/app_trace/test/test_trace.c @@ -125,7 +125,7 @@ typedef struct { static SemaphoreHandle_t s_print_lock; #endif -static uint64_t esp_apptrace_test_ts_get(); +static uint64_t esp_apptrace_test_ts_get(void); static void esp_apptrace_test_timer_isr(void *arg) { @@ -383,7 +383,7 @@ static void esp_apptrace_test_task_crash(void *p) static int s_ts_timer_group, s_ts_timer_idx; -static uint64_t esp_apptrace_test_ts_get() +static uint64_t esp_apptrace_test_ts_get(void) { uint64_t ts = 0; timer_get_counter_value(s_ts_timer_group, s_ts_timer_idx, &ts); @@ -413,7 +413,7 @@ static void esp_apptrace_test_ts_init(int timer_group, int timer_idx) timer_start(timer_group, timer_idx); } -static void esp_apptrace_test_ts_cleanup() +static void esp_apptrace_test_ts_cleanup(void) { timer_config_t config; diff --git a/components/app_update/esp_ota_ops.c b/components/app_update/esp_ota_ops.c index df6d8a9066..7ef5c68c58 100644 --- a/components/app_update/esp_ota_ops.c +++ b/components/app_update/esp_ota_ops.c @@ -687,12 +687,12 @@ static esp_err_t esp_ota_current_ota_is_workable(bool valid) return ESP_OK; } -esp_err_t esp_ota_mark_app_valid_cancel_rollback() +esp_err_t esp_ota_mark_app_valid_cancel_rollback(void) { return esp_ota_current_ota_is_workable(true); } -esp_err_t esp_ota_mark_app_invalid_rollback_and_reboot() +esp_err_t esp_ota_mark_app_invalid_rollback_and_reboot(void) { return esp_ota_current_ota_is_workable(false); } @@ -715,7 +715,7 @@ static int get_last_invalid_otadata(const esp_ota_select_entry_t *two_otadata) return num_invalid_otadata; } -const esp_partition_t* esp_ota_get_last_invalid_partition() +const esp_partition_t* esp_ota_get_last_invalid_partition(void) { esp_ota_select_entry_t otadata[2]; if (read_otadata(otadata) == NULL) { diff --git a/components/app_update/include/esp_ota_ops.h b/components/app_update/include/esp_ota_ops.h index 73ca8a3028..4dc2b80fec 100644 --- a/components/app_update/include/esp_ota_ops.h +++ b/components/app_update/include/esp_ota_ops.h @@ -221,7 +221,7 @@ esp_err_t esp_ota_get_partition_description(const esp_partition_t *partition, es * @return * - ESP_OK: if successful. */ -esp_err_t esp_ota_mark_app_valid_cancel_rollback(); +esp_err_t esp_ota_mark_app_valid_cancel_rollback(void); /** * @brief This function is called to roll back to the previously workable app with reboot. @@ -233,14 +233,14 @@ esp_err_t esp_ota_mark_app_valid_cancel_rollback(); * - ESP_FAIL: if not successful. * - ESP_ERR_OTA_ROLLBACK_FAILED: The rollback is not possible due to flash does not have any apps. */ -esp_err_t esp_ota_mark_app_invalid_rollback_and_reboot(); +esp_err_t esp_ota_mark_app_invalid_rollback_and_reboot(void); /** * @brief Returns last partition with invalid state (ESP_OTA_IMG_INVALID or ESP_OTA_IMG_ABORTED). * * @return partition. */ -const esp_partition_t* esp_ota_get_last_invalid_partition(); +const esp_partition_t* esp_ota_get_last_invalid_partition(void); /** * @brief Returns state for given partition. diff --git a/components/app_update/test/test_switch_ota.c b/components/app_update/test/test_switch_ota.c index bfa7b25bee..232bfbc88e 100644 --- a/components/app_update/test/test_switch_ota.c +++ b/components/app_update/test/test_switch_ota.c @@ -118,7 +118,7 @@ static void reboot_as_deep_sleep(void) /* @brief Copies a current app to next partition (OTA0-15), after that ESP is rebooting and run this (the next) OTAx. */ -static void copy_current_app_to_next_part_and_reboot() +static void copy_current_app_to_next_part_and_reboot(void) { const esp_partition_t *cur_app = esp_ota_get_running_partition(); copy_current_app_to_next_part(cur_app, get_next_update_partition()); diff --git a/components/bootloader/subproject/main/bootloader_start.c b/components/bootloader/subproject/main/bootloader_start.c index 7a7e76aa6b..e9bd32d881 100644 --- a/components/bootloader/subproject/main/bootloader_start.c +++ b/components/bootloader/subproject/main/bootloader_start.c @@ -34,7 +34,7 @@ static int selected_boot_partition(const bootloader_state_t *bs); * The hardware is mostly uninitialized, flash cache is down and the app CPU is in reset. * We do have a stack, so we can do the initialization in C. */ -void __attribute__((noreturn)) call_start_cpu0() +void __attribute__((noreturn)) call_start_cpu0(void) { // 1. Hardware initialization if (bootloader_init() != ESP_OK) { @@ -113,7 +113,7 @@ static int selected_boot_partition(const bootloader_state_t *bs) } // Return global reent struct if any newlib functions are linked to bootloader -struct _reent* __getreent() { +struct _reent* __getreent(void) { return _GLOBAL_REENT; } diff --git a/components/bootloader_support/include/bootloader_common.h b/components/bootloader_support/include/bootloader_common.h index 2475d842a5..4b887f55f9 100644 --- a/components/bootloader_support/include/bootloader_common.h +++ b/components/bootloader_support/include/bootloader_common.h @@ -144,7 +144,7 @@ esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t /** * @brief Configure VDDSDIO, call this API to rise VDDSDIO to 1.9V when VDDSDIO regulator is enabled as 1.8V mode. */ -void bootloader_common_vddsdio_configure(); +void bootloader_common_vddsdio_configure(void); #ifdef __cplusplus } diff --git a/components/bootloader_support/include/bootloader_flash_config.h b/components/bootloader_support/include/bootloader_flash_config.h index 2f716cce2a..98c169f48a 100644 --- a/components/bootloader_support/include/bootloader_flash_config.h +++ b/components/bootloader_support/include/bootloader_flash_config.h @@ -25,7 +25,7 @@ extern "C" { * * @return None */ -void bootloader_flash_update_id(); +void bootloader_flash_update_id(void); /** * @brief Set the flash CS setup and hold time. @@ -35,7 +35,7 @@ void bootloader_flash_update_id(); * * @return None */ -void bootloader_flash_cs_timing_config(); +void bootloader_flash_cs_timing_config(void); /** * @brief Configure SPI flash clock. diff --git a/components/bootloader_support/include/esp_flash_encrypt.h b/components/bootloader_support/include/esp_flash_encrypt.h index c0de5ca173..028842d97e 100644 --- a/components/bootloader_support/include/esp_flash_encrypt.h +++ b/components/bootloader_support/include/esp_flash_encrypt.h @@ -122,7 +122,7 @@ esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length); * serial re-flashing of an unauthorised code in absence of secure boot. * */ -void esp_flash_write_protect_crypt_cnt(); +void esp_flash_write_protect_crypt_cnt(void); /** @brief Return the flash encryption mode * @@ -131,7 +131,7 @@ void esp_flash_write_protect_crypt_cnt(); * * @return */ -esp_flash_enc_mode_t esp_get_flash_encryption_mode(); +esp_flash_enc_mode_t esp_get_flash_encryption_mode(void); #ifdef __cplusplus } diff --git a/components/bootloader_support/include_bootloader/bootloader_flash.h b/components/bootloader_support/include_bootloader/bootloader_flash.h index 6ac7246462..18baad594b 100644 --- a/components/bootloader_support/include_bootloader/bootloader_flash.h +++ b/components/bootloader_support/include_bootloader/bootloader_flash.h @@ -35,7 +35,7 @@ * * @return Number of free pages */ -uint32_t bootloader_mmap_get_free_pages(); +uint32_t bootloader_mmap_get_free_pages(void); /** * @brief Map a region of flash to data memory diff --git a/components/bootloader_support/include_bootloader/bootloader_init.h b/components/bootloader_support/include_bootloader/bootloader_init.h index 443a207cf5..9c1f8719af 100644 --- a/components/bootloader_support/include_bootloader/bootloader_init.h +++ b/components/bootloader_support/include_bootloader/bootloader_init.h @@ -25,4 +25,4 @@ * @return ESP_OK - If the setting is successful. * ESP_FAIL - If the setting is not successful. */ -esp_err_t bootloader_init(); +esp_err_t bootloader_init(void); diff --git a/components/bootloader_support/include_bootloader/bootloader_sha.h b/components/bootloader_support/include_bootloader/bootloader_sha.h index 3bfefb9f51..99db64b999 100644 --- a/components/bootloader_support/include_bootloader/bootloader_sha.h +++ b/components/bootloader_support/include_bootloader/bootloader_sha.h @@ -26,7 +26,7 @@ typedef void *bootloader_sha256_handle_t; -bootloader_sha256_handle_t bootloader_sha256_start(); +bootloader_sha256_handle_t bootloader_sha256_start(void); void bootloader_sha256_data(bootloader_sha256_handle_t handle, const void *data, size_t data_len); diff --git a/components/bootloader_support/include_bootloader/flash_qio_mode.h b/components/bootloader_support/include_bootloader/flash_qio_mode.h index 98e2fd22a1..7f70d5bb08 100644 --- a/components/bootloader_support/include_bootloader/flash_qio_mode.h +++ b/components/bootloader_support/include_bootloader/flash_qio_mode.h @@ -30,7 +30,7 @@ void bootloader_enable_qio_mode(void); * mfg_id = (ID >> 16) & 0xFF; flash_id = ID & 0xffff; */ -uint32_t bootloader_read_flash_id(); +uint32_t bootloader_read_flash_id(void); #ifdef __cplusplus } diff --git a/components/bootloader_support/src/bootloader_clock.c b/components/bootloader_support/src/bootloader_clock.c index fda86b2073..3befda16dd 100644 --- a/components/bootloader_support/src/bootloader_clock.c +++ b/components/bootloader_support/src/bootloader_clock.c @@ -18,7 +18,7 @@ #include "soc/dport_reg.h" #include "soc/efuse_periph.h" -void bootloader_clock_configure() +void bootloader_clock_configure(void) { // ROM bootloader may have put a lot of text into UART0 FIFO. // Wait for it to be printed. diff --git a/components/bootloader_support/src/bootloader_common.c b/components/bootloader_support/src/bootloader_common.c index ed0169a960..a10fb2f2ac 100644 --- a/components/bootloader_support/src/bootloader_common.c +++ b/components/bootloader_support/src/bootloader_common.c @@ -256,7 +256,7 @@ esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t return ESP_OK; } -void bootloader_common_vddsdio_configure() +void bootloader_common_vddsdio_configure(void) { #if CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V rtc_vddsdio_config_t cfg = rtc_vddsdio_get_config(); diff --git a/components/bootloader_support/src/bootloader_flash.c b/components/bootloader_support/src/bootloader_flash.c index 6b25addf22..09ed73deba 100644 --- a/components/bootloader_support/src/bootloader_flash.c +++ b/components/bootloader_support/src/bootloader_flash.c @@ -25,7 +25,7 @@ static const char *TAG = "bootloader_mmap"; static spi_flash_mmap_handle_t map; -uint32_t bootloader_mmap_get_free_pages() +uint32_t bootloader_mmap_get_free_pages(void) { return spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA); } @@ -103,7 +103,7 @@ static bool mapped; // Current bootloader mapping (ab)used for bootloader_read() static uint32_t current_read_mapping = UINT32_MAX; -uint32_t bootloader_mmap_get_free_pages() +uint32_t bootloader_mmap_get_free_pages(void) { /** * Allow mapping up to 50 of the 51 available MMU blocks (last one used for reads) diff --git a/components/bootloader_support/src/bootloader_flash_config.c b/components/bootloader_support/src/bootloader_flash_config.c index 53360848a3..091727e337 100644 --- a/components/bootloader_support/src/bootloader_flash_config.c +++ b/components/bootloader_support/src/bootloader_flash_config.c @@ -27,12 +27,12 @@ #include "flash_qio_mode.h" #include "bootloader_flash_config.h" -void bootloader_flash_update_id() +void bootloader_flash_update_id(void) { g_rom_flashchip.device_id = bootloader_read_flash_id(); } -void IRAM_ATTR bootloader_flash_cs_timing_config() +void IRAM_ATTR bootloader_flash_cs_timing_config(void) { SET_PERI_REG_MASK(SPI_USER_REG(0), SPI_CS_HOLD_M | SPI_CS_SETUP_M); SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S); diff --git a/components/bootloader_support/src/bootloader_init.c b/components/bootloader_support/src/bootloader_init.c index 67ec3626c9..26b8fd0b39 100644 --- a/components/bootloader_support/src/bootloader_init.c +++ b/components/bootloader_support/src/bootloader_init.c @@ -61,7 +61,7 @@ extern int _data_end; static const char* TAG = "boot"; -static esp_err_t bootloader_main(); +static esp_err_t bootloader_main(void); static void print_flash_info(const esp_image_header_t* pfhdr); static void update_flash_config(const esp_image_header_t* pfhdr); static void bootloader_init_flash_configure(const esp_image_header_t* pfhdr); @@ -69,7 +69,7 @@ static void uart_console_configure(void); static void wdt_reset_check(void); -esp_err_t bootloader_init() +esp_err_t bootloader_init(void) { cpu_configure_region_protection(); cpu_init_memctl(); @@ -117,7 +117,7 @@ esp_err_t bootloader_init() return ESP_OK; } -static esp_err_t bootloader_main() +static esp_err_t bootloader_main(void) { bootloader_common_vddsdio_configure(); /* Read and keep flash ID, for further use. */ @@ -434,7 +434,7 @@ void __assert_func(const char *file, int line, const char *func, const char *exp while(1) {} } -void abort() +void abort(void) { #if !CONFIG_ESP32_PANIC_SILENT_REBOOT ets_printf("abort() was called at PC 0x%08x\r\n", (intptr_t)__builtin_return_address(0) - 3); diff --git a/components/bootloader_support/src/esp32/bootloader_sha.c b/components/bootloader_support/src/esp32/bootloader_sha.c index f42c8b6634..6ebbab8757 100644 --- a/components/bootloader_support/src/esp32/bootloader_sha.c +++ b/components/bootloader_support/src/esp32/bootloader_sha.c @@ -27,7 +27,7 @@ static const size_t BLOCK_WORDS = (64 / sizeof(uint32_t)); // Words in final SHA256 digest static const size_t DIGEST_WORDS = (32 / sizeof(uint32_t)); -bootloader_sha256_handle_t bootloader_sha256_start() +bootloader_sha256_handle_t bootloader_sha256_start(void) { // Enable SHA hardware ets_sha_enable(); diff --git a/components/bootloader_support/src/esp32/flash_encrypt.c b/components/bootloader_support/src/esp32/flash_encrypt.c index 7b816e2921..41925de272 100644 --- a/components/bootloader_support/src/esp32/flash_encrypt.c +++ b/components/bootloader_support/src/esp32/flash_encrypt.c @@ -38,7 +38,7 @@ static const char *TAG = "flash_encrypt"; /* Static functions for stages of flash encryption */ static esp_err_t initialise_flash_encryption(void); static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_crypt_wr_dis); -static esp_err_t encrypt_bootloader(); +static esp_err_t encrypt_bootloader(void); static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions); static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition); @@ -223,7 +223,7 @@ static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_cry return ESP_OK; } -static esp_err_t encrypt_bootloader() +static esp_err_t encrypt_bootloader(void) { esp_err_t err; uint32_t image_length; diff --git a/components/bootloader_support/src/esp32/secure_boot.c b/components/bootloader_support/src/esp32/secure_boot.c index 65fda09564..023d281426 100644 --- a/components/bootloader_support/src/esp32/secure_boot.c +++ b/components/bootloader_support/src/esp32/secure_boot.c @@ -95,7 +95,7 @@ static bool secure_boot_generate(uint32_t image_len){ } /* Burn values written to the efuse write registers */ -static inline void burn_efuses() +static inline void burn_efuses(void) { esp_efuse_burn_new_values(); } diff --git a/components/bootloader_support/src/flash_encrypt.c b/components/bootloader_support/src/flash_encrypt.c index 606cb79fb6..d64d2fd9d7 100644 --- a/components/bootloader_support/src/flash_encrypt.c +++ b/components/bootloader_support/src/flash_encrypt.c @@ -17,7 +17,7 @@ #include "esp_efuse_table.h" #include "esp_flash_encrypt.h" -void esp_flash_write_protect_crypt_cnt() +void esp_flash_write_protect_crypt_cnt(void) { uint8_t flash_crypt_cnt_wr_dis = 0; esp_efuse_read_field_blob(ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT, &flash_crypt_cnt_wr_dis, 1); @@ -26,7 +26,7 @@ void esp_flash_write_protect_crypt_cnt() } } -esp_flash_enc_mode_t esp_get_flash_encryption_mode() +esp_flash_enc_mode_t esp_get_flash_encryption_mode(void) { uint8_t efuse_flash_crypt_cnt_wr_protected = 0; uint8_t dis_dl_enc = 0, dis_dl_dec = 0, dis_dl_cache = 0; diff --git a/components/bootloader_support/src/flash_qio_mode.c b/components/bootloader_support/src/flash_qio_mode.c index db486c73e3..06a8fcada4 100644 --- a/components/bootloader_support/src/flash_qio_mode.c +++ b/components/bootloader_support/src/flash_qio_mode.c @@ -53,11 +53,11 @@ typedef struct __attribute__((packed)) { } qio_info_t; /* Read 8 bit status using RDSR command */ -static unsigned read_status_8b_rdsr(); +static unsigned read_status_8b_rdsr(void); /* Read 8 bit status (second byte) using RDSR2 command */ -static unsigned read_status_8b_rdsr2(); +static unsigned read_status_8b_rdsr2(void); /* read 16 bit status using RDSR & RDSR2 (low and high bytes) */ -static unsigned read_status_16b_rdsr_rdsr2(); +static unsigned read_status_16b_rdsr_rdsr2(void); /* Write 8 bit status using WRSR */ static void write_status_8b_wrsr(unsigned new_status); @@ -67,7 +67,7 @@ static void write_status_8b_wrsr2(unsigned new_status); static void write_status_16b_wrsr(unsigned new_status); /* Read 8 bit status of XM25QU64A */ -static unsigned read_status_8b_xmc25qu64a(); +static unsigned read_status_8b_xmc25qu64a(void); /* Write 8 bit status of XM25QU64A */ static void write_status_8b_xmc25qu64a(unsigned new_status); @@ -121,7 +121,7 @@ static uint32_t execute_flash_command(uint8_t command, uint32_t mosi_data, uint8 /* dummy_len_plus values defined in ROM for SPI flash configuration */ extern uint8_t g_rom_spiflash_dummy_len_plus[]; -uint32_t bootloader_read_flash_id() +uint32_t bootloader_read_flash_id(void) { uint32_t id = execute_flash_command(CMD_RDID, 0, 0, 24); id = ((id & 0xff) << 16) | ((id >> 16) & 0xff) | (id & 0xff00); @@ -223,17 +223,17 @@ static esp_err_t enable_qio_mode(read_status_fn_t read_status_fn, return ESP_OK; } -static unsigned read_status_8b_rdsr() +static unsigned read_status_8b_rdsr(void) { return execute_flash_command(CMD_RDSR, 0, 0, 8); } -static unsigned read_status_8b_rdsr2() +static unsigned read_status_8b_rdsr2(void) { return execute_flash_command(CMD_RDSR2, 0, 0, 8); } -static unsigned read_status_16b_rdsr_rdsr2() +static unsigned read_status_16b_rdsr_rdsr2(void) { return execute_flash_command(CMD_RDSR, 0, 0, 8) | (execute_flash_command(CMD_RDSR2, 0, 0, 8) << 8); } @@ -253,7 +253,7 @@ static void write_status_16b_wrsr(unsigned new_status) execute_flash_command(CMD_WRSR, new_status, 16, 0); } -static unsigned read_status_8b_xmc25qu64a() +static unsigned read_status_8b_xmc25qu64a(void) { execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */ esp_rom_spiflash_wait_idle(&g_rom_flashchip); diff --git a/components/bootloader_support/src/idf/bootloader_sha.c b/components/bootloader_support/src/idf/bootloader_sha.c index 7dc4f74299..849c86b387 100644 --- a/components/bootloader_support/src/idf/bootloader_sha.c +++ b/components/bootloader_support/src/idf/bootloader_sha.c @@ -18,7 +18,7 @@ #include #include -bootloader_sha256_handle_t bootloader_sha256_start() +bootloader_sha256_handle_t bootloader_sha256_start(void) { mbedtls_sha256_context *ctx = (mbedtls_sha256_context *)malloc(sizeof(mbedtls_sha256_context)); if (!ctx) { diff --git a/components/bt/host/bluedroid/api/esp_spp_api.c b/components/bt/host/bluedroid/api/esp_spp_api.c index 57c2e317ae..d68511cf4b 100644 --- a/components/bt/host/bluedroid/api/esp_spp_api.c +++ b/components/bt/host/bluedroid/api/esp_spp_api.c @@ -54,7 +54,7 @@ esp_err_t esp_spp_init(esp_spp_mode_t mode) return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_spp_deinit() +esp_err_t esp_spp_deinit(void) { btc_msg_t msg; btc_spp_args_t arg; @@ -164,7 +164,7 @@ esp_err_t esp_spp_write(uint32_t handle, int len, uint8_t *p_data) return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), btc_spp_arg_deep_copy) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_spp_vfs_register() +esp_err_t esp_spp_vfs_register(void) { ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); diff --git a/components/bt/host/bluedroid/api/include/api/esp_spp_api.h b/components/bt/host/bluedroid/api/include/api/esp_spp_api.h index 31bcf1c687..1b96cbbe04 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_spp_api.h +++ b/components/bt/host/bluedroid/api/include/api/esp_spp_api.h @@ -205,7 +205,7 @@ esp_err_t esp_spp_init(esp_spp_mode_t mode); * - ESP_OK: success * - other: failed */ -esp_err_t esp_spp_deinit(); +esp_err_t esp_spp_deinit(void); /** diff --git a/components/bt/host/bluedroid/bta/dm/bta_dm_main.c b/components/bt/host/bluedroid/bta/dm/bta_dm_main.c index d62974ea2e..aa4b3250df 100644 --- a/components/bt/host/bluedroid/bta/dm/bta_dm_main.c +++ b/components/bt/host/bluedroid/bta/dm/bta_dm_main.c @@ -360,7 +360,7 @@ const tBTA_DM_ST_TBL bta_dm_search_st_tbl[] = { ** Returns void ** *******************************************************************************/ -void bta_dm_sm_disable( ) +void bta_dm_sm_disable(void) { bta_sys_deregister( BTA_ID_DM ); } @@ -412,7 +412,7 @@ BOOLEAN bta_dm_sm_execute(BT_HDR *p_msg) ** Returns void ** *******************************************************************************/ -void bta_dm_search_sm_disable( ) +void bta_dm_search_sm_disable(void) { bta_sys_deregister( BTA_ID_DM_SEARCH ); diff --git a/components/bt/host/bluedroid/bta/dm/bta_dm_pm.c b/components/bt/host/bluedroid/bta/dm/bta_dm_pm.c index 5b0978bf59..ff42a65a17 100644 --- a/components/bt/host/bluedroid/bta/dm/bta_dm_pm.c +++ b/components/bt/host/bluedroid/bta/dm/bta_dm_pm.c @@ -46,7 +46,7 @@ static void bta_dm_pm_timer_cback(void *p_tle); static void bta_dm_pm_btm_cback(BD_ADDR bd_addr, tBTM_PM_STATUS status, UINT16 value, UINT8 hci_status); static BOOLEAN bta_dm_pm_park(BD_ADDR peer_addr); static BOOLEAN bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE *p_peer_dev, UINT8 index); -static BOOLEAN bta_dm_pm_is_sco_active (); +static BOOLEAN bta_dm_pm_is_sco_active (void); static void bta_dm_pm_hid_check(BOOLEAN bScoActive); static void bta_dm_pm_set_sniff_policy(tBTA_DM_PEER_DEVICE *p_dev, BOOLEAN bDisable); static void bta_dm_pm_stop_timer_by_index(tBTA_PM_TIMER *p_timer, @@ -1001,7 +1001,7 @@ void bta_dm_pm_timer(tBTA_DM_MSG *p_data) ** Returns BOOLEAN. TRUE if SCO active, else FALSE ** *******************************************************************************/ -static BOOLEAN bta_dm_pm_is_sco_active () +static BOOLEAN bta_dm_pm_is_sco_active (void) { int j; BOOLEAN bScoActive = FALSE; diff --git a/components/bt/host/bluedroid/bta/gatt/bta_gattc_co.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_co.c index a336c23147..0573b7bf77 100644 --- a/components/bt/host/bluedroid/bta/gatt/bta_gattc_co.c +++ b/components/bt/host/bluedroid/bta/gatt/bta_gattc_co.c @@ -48,7 +48,7 @@ static void getFilename(char *buffer, BD_ADDR bda) , bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); } -static void cacheClose() +static void cacheClose(void) { if (sCacheFD != 0) { fclose(sCacheFD); diff --git a/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c index 33ae293483..43a2af6abe 100644 --- a/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c +++ b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c @@ -94,7 +94,7 @@ UINT32 service_index = 0; BOOLEAN service_availability = TRUE; /* helper functions for handling AT commands queueing */ -static void bta_hf_client_handle_ok(); +static void bta_hf_client_handle_ok(void); static void bta_hf_client_clear_queued_at(void) { @@ -268,7 +268,7 @@ static void bta_hf_client_start_at_hold_timer(void) ** No buffer parsing is being done here. *******************************************************************************/ -static void bta_hf_client_handle_ok() +static void bta_hf_client_handle_ok(void) { APPL_TRACE_DEBUG("%s", __FUNCTION__); @@ -342,7 +342,7 @@ static void bta_hf_client_handle_error(tBTA_HF_CLIENT_AT_RESULT_TYPE type, UINT1 bta_hf_client_send_queued_at(); } -static void bta_hf_client_handle_ring() +static void bta_hf_client_handle_ring(void) { APPL_TRACE_DEBUG("%s", __FUNCTION__); bta_hf_client_evt_val(BTA_HF_CLIENT_RING_INDICATION, 0); diff --git a/components/bt/host/bluedroid/bta/hf_client/include/bta_hf_client_int.h b/components/bt/host/bluedroid/bta/hf_client/include/bta_hf_client_int.h index 60dfc759c3..fd52b3aef7 100644 --- a/components/bt/host/bluedroid/bta/hf_client/include/bta_hf_client_int.h +++ b/components/bt/host/bluedroid/bta/hf_client/include/bta_hf_client_int.h @@ -212,7 +212,7 @@ extern void bta_hf_client_sm_execute(UINT16 event, extern void bta_hf_client_slc_seq(BOOLEAN error); extern void bta_hf_client_collision_cback (tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr); -extern void bta_hf_client_resume_open (); +extern void bta_hf_client_resume_open (void); /* SDP functions */ extern BOOLEAN bta_hf_client_add_record(char *p_service_name, diff --git a/components/bt/host/bluedroid/bta/include/bta/bta_gatt_api.h b/components/bt/host/bluedroid/bta/include/bta/bta_gatt_api.h index 664536ddd1..d2d89f0789 100644 --- a/components/bt/host/bluedroid/bta/include/bta/bta_gatt_api.h +++ b/components/bt/host/bluedroid/bta/include/bta/bta_gatt_api.h @@ -1205,7 +1205,7 @@ extern void BTA_GATTC_ConfigureMTU (UINT16 conn_id); ** Returns None ** *******************************************************************************/ -extern void BTA_GATTS_Init(); +extern void BTA_GATTS_Init(void); /******************************************************************************* ** diff --git a/components/bt/host/bluedroid/bta/jv/bta_jv_act.c b/components/bt/host/bluedroid/bta/jv/bta_jv_act.c index ecef90b122..eca76c9a43 100644 --- a/components/bt/host/bluedroid/bta/jv/bta_jv_act.c +++ b/components/bt/host/bluedroid/bta/jv/bta_jv_act.c @@ -683,7 +683,7 @@ void bta_jv_disable (tBTA_JV_MSG *p_data) * list. * If no free PSMs exist, 0 will be returned. */ -static UINT16 bta_jv_get_free_psm() +static UINT16 bta_jv_get_free_psm(void) { const int cnt = sizeof(bta_jv_cb.free_psm_list) / sizeof(bta_jv_cb.free_psm_list[0]); for (int i = 0; i < cnt; i++) { diff --git a/components/bt/host/bluedroid/btc/core/btc_profile_queue.c b/components/bt/host/bluedroid/btc/core/btc_profile_queue.c index 6d01b0d19f..3e5603db83 100644 --- a/components/bt/host/bluedroid/btc/core/btc_profile_queue.c +++ b/components/bt/host/bluedroid/btc/core/btc_profile_queue.c @@ -60,7 +60,7 @@ static void queue_int_add(connect_node_t *p_param) list_append(connect_queue, p_node); } -static void queue_int_advance() +static void queue_int_advance(void) { if (connect_queue && !list_is_empty(connect_queue)) { list_remove(connect_queue, list_front(connect_queue)); diff --git a/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c index aff5521139..9cf21b91a1 100644 --- a/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c +++ b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c @@ -424,7 +424,7 @@ static void btc_a2dp_source_data_post(void) osi_thread_post(a2dp_source_local_param.btc_aa_src_task_hdl, btc_a2dp_source_handle_timer, NULL, 2, OSI_THREAD_MAX_TIMEOUT); } -static UINT64 time_now_us() +static UINT64 time_now_us(void) { #if _POSIX_TIMERS struct timespec ts_now; diff --git a/components/bt/host/bluedroid/btc/profile/std/smp/esp_app_sec.c b/components/bt/host/bluedroid/btc/profile/std/smp/esp_app_sec.c index e1ec079b4a..c6bbadea7f 100644 --- a/components/bt/host/bluedroid/btc/profile/std/smp/esp_app_sec.c +++ b/components/bt/host/bluedroid/btc/profile/std/smp/esp_app_sec.c @@ -79,7 +79,7 @@ void app_ble_sec_gen_ltk(UINT8 key_size) ** Returns NULL ** *******************************************************************************/ -void app_ble_sec_init() +void app_ble_sec_init(void) { // Reset Security Environment memset(&app_sec_env, 0, sizeof(app_sec_env)); diff --git a/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c index 93636ef71c..912c57035a 100644 --- a/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c +++ b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c @@ -837,7 +837,7 @@ static ssize_t spp_vfs_read(int fd, void * dst, size_t size) return item_size; } -esp_err_t btc_spp_vfs_register() +esp_err_t btc_spp_vfs_register(void) { esp_vfs_t vfs = { .flags = ESP_VFS_FLAG_DEFAULT, diff --git a/components/bt/host/bluedroid/device/controller.c b/components/bt/host/bluedroid/device/controller.c index 96c773ebe2..2c2ac129f2 100644 --- a/components/bt/host/bluedroid/device/controller.c +++ b/components/bt/host/bluedroid/device/controller.c @@ -544,7 +544,7 @@ static const controller_t interface = { #endif /* (BTM_SCO_HCI_INCLUDED == TRUE) */ }; -const controller_t *controller_get_interface() +const controller_t *controller_get_interface(void) { static bool loaded = false; if (!loaded) { diff --git a/components/bt/host/bluedroid/device/include/device/controller.h b/components/bt/host/bluedroid/device/include/device/controller.h index 704b456d7f..bb09863528 100644 --- a/components/bt/host/bluedroid/device/include/device/controller.h +++ b/components/bt/host/bluedroid/device/include/device/controller.h @@ -86,6 +86,6 @@ typedef struct controller_t { #endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE) */ } controller_t; -const controller_t *controller_get_interface(); +const controller_t *controller_get_interface(void); #endif /*_CONTROLLER_H_*/ diff --git a/components/bt/host/bluedroid/hci/hci_hal_h4.c b/components/bt/host/bluedroid/hci/hci_hal_h4.c index 031d2c028a..85d3598dc1 100644 --- a/components/bt/host/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/host/bluedroid/hci/hci_hal_h4.c @@ -121,7 +121,7 @@ static bool hal_open(const hci_hal_callbacks_t *upper_callbacks, void *task_thre return true; } -static void hal_close() +static void hal_close(void) { hci_hal_env_deinit(); @@ -367,7 +367,7 @@ static const hci_hal_t interface = { transmit_data, }; -const hci_hal_t *hci_hal_h4_get_interface() +const hci_hal_t *hci_hal_h4_get_interface(void) { return &interface; } diff --git a/components/bt/host/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c index 6c285339cc..2068062bf9 100644 --- a/components/bt/host/bluedroid/hci/hci_layer.c +++ b/components/bt/host/bluedroid/hci/hci_layer.c @@ -535,7 +535,7 @@ static waiting_command_t *get_waiting_command(command_opcode_t opcode) return NULL; } -static void init_layer_interface() +static void init_layer_interface(void) { if (!interface_created) { interface.transmit_command = transmit_command; @@ -555,7 +555,7 @@ static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks = { fragmenter_transmit_finished }; -const hci_t *hci_layer_get_interface() +const hci_t *hci_layer_get_interface(void) { hal = hci_hal_h4_get_interface(); packet_fragmenter = packet_fragmenter_get_interface(); diff --git a/components/bt/host/bluedroid/hci/hci_packet_factory.c b/components/bt/host/bluedroid/hci/hci_packet_factory.c index 19641d1046..0145a138b4 100644 --- a/components/bt/host/bluedroid/hci/hci_packet_factory.c +++ b/components/bt/host/bluedroid/hci/hci_packet_factory.c @@ -273,7 +273,7 @@ static const hci_packet_factory_t interface = { make_write_default_erroneous_data_report, }; -const hci_packet_factory_t *hci_packet_factory_get_interface() +const hci_packet_factory_t *hci_packet_factory_get_interface(void) { return &interface; } diff --git a/components/bt/host/bluedroid/hci/hci_packet_parser.c b/components/bt/host/bluedroid/hci/hci_packet_parser.c index eb4dc72f0b..a99ef8b0d1 100644 --- a/components/bt/host/bluedroid/hci/hci_packet_parser.c +++ b/components/bt/host/bluedroid/hci/hci_packet_parser.c @@ -250,7 +250,7 @@ static const hci_packet_parser_t interface = { parse_ble_read_suggested_default_data_length_response }; -const hci_packet_parser_t *hci_packet_parser_get_interface() +const hci_packet_parser_t *hci_packet_parser_get_interface(void) { return &interface; } diff --git a/components/bt/host/bluedroid/hci/include/hci/hci_layer.h b/components/bt/host/bluedroid/hci/include/hci/hci_layer.h index 8fa5165e9f..6bfacdff5c 100644 --- a/components/bt/host/bluedroid/hci/include/hci/hci_layer.h +++ b/components/bt/host/bluedroid/hci/include/hci/hci_layer.h @@ -92,7 +92,7 @@ typedef struct hci_t { void (*transmit_downward)(uint16_t type, void *data); } hci_t; -const hci_t *hci_layer_get_interface(); +const hci_t *hci_layer_get_interface(void); int hci_start_up(void); void hci_shut_down(void); diff --git a/components/bt/host/bluedroid/hci/include/hci/hci_packet_factory.h b/components/bt/host/bluedroid/hci/include/hci/hci_packet_factory.h index fd8731fbc2..37ced06be3 100644 --- a/components/bt/host/bluedroid/hci/include/hci/hci_packet_factory.h +++ b/components/bt/host/bluedroid/hci/include/hci/hci_packet_factory.h @@ -48,6 +48,6 @@ typedef struct { BT_HDR *(*make_write_default_erroneous_data_report)(uint8_t enable); } hci_packet_factory_t; -const hci_packet_factory_t *hci_packet_factory_get_interface(); +const hci_packet_factory_t *hci_packet_factory_get_interface(void); #endif /*_HCI_PACKET_FACTORY_H_*/ diff --git a/components/bt/host/bluedroid/hci/include/hci/hci_packet_parser.h b/components/bt/host/bluedroid/hci/include/hci/hci_packet_parser.h index b0cc4b3b49..e20e52fb5e 100644 --- a/components/bt/host/bluedroid/hci/include/hci/hci_packet_parser.h +++ b/components/bt/host/bluedroid/hci/include/hci/hci_packet_parser.h @@ -97,6 +97,6 @@ typedef struct { ); } hci_packet_parser_t; -const hci_packet_parser_t *hci_packet_parser_get_interface(); +const hci_packet_parser_t *hci_packet_parser_get_interface(void); #endif /*_HCI_PACKET_PARSER_H_*/ diff --git a/components/bt/host/bluedroid/hci/include/hci/packet_fragmenter.h b/components/bt/host/bluedroid/hci/include/hci/packet_fragmenter.h index 2855554275..02a13fb956 100644 --- a/components/bt/host/bluedroid/hci/include/hci/packet_fragmenter.h +++ b/components/bt/host/bluedroid/hci/include/hci/packet_fragmenter.h @@ -57,6 +57,6 @@ typedef struct packet_fragmenter_t { void (*reassemble_and_dispatch)(BT_HDR *packet); } packet_fragmenter_t; -const packet_fragmenter_t *packet_fragmenter_get_interface(); +const packet_fragmenter_t *packet_fragmenter_get_interface(void); #endif /* _PACKET_FRAGMENTER_H_ */ diff --git a/components/bt/host/bluedroid/hci/packet_fragmenter.c b/components/bt/host/bluedroid/hci/packet_fragmenter.c index 87cb99c74f..53c6b77212 100644 --- a/components/bt/host/bluedroid/hci/packet_fragmenter.c +++ b/components/bt/host/bluedroid/hci/packet_fragmenter.c @@ -55,14 +55,14 @@ static void init(const packet_fragmenter_callbacks_t *result_callbacks) partial_packets = hash_map_new(NUMBER_OF_BUCKETS, hash_function_naive, NULL, NULL, NULL); } -static void cleanup() +static void cleanup(void) { if (partial_packets) { hash_map_free(partial_packets); } } -static BT_HDR *fragment_get_current_packet() +static BT_HDR *fragment_get_current_packet(void) { return current_fragment_packet; } @@ -224,7 +224,7 @@ static const packet_fragmenter_t interface = { reassemble_and_dispatch }; -const packet_fragmenter_t *packet_fragmenter_get_interface() +const packet_fragmenter_t *packet_fragmenter_get_interface(void) { controller = controller_get_interface(); return &interface; diff --git a/components/bt/host/bluedroid/main/bte_main.c b/components/bt/host/bluedroid/main/bte_main.c index 61c30e2824..c47bdc15f9 100644 --- a/components/bt/host/bluedroid/main/bte_main.c +++ b/components/bt/host/bluedroid/main/bte_main.c @@ -195,7 +195,7 @@ void bte_main_enable_lpm(BOOLEAN enable) ** Returns None ** ******************************************************************************/ -void bte_main_lpm_allow_bt_device_sleep() +void bte_main_lpm_allow_bt_device_sleep(void) { /**/ //hci->send_low_power_command(LPM_WAKE_DEASSERT); @@ -210,7 +210,7 @@ void bte_main_lpm_allow_bt_device_sleep() ** Returns None ** ******************************************************************************/ -void bte_main_lpm_wake_bt_device() +void bte_main_lpm_wake_bt_device(void) { //hci->send_low_power_command(LPM_WAKE_ASSERT); } diff --git a/components/bt/host/bluedroid/stack/avdt/avdt_api.c b/components/bt/host/bluedroid/stack/avdt/avdt_api.c index 88d3741306..c0adc07e6f 100644 --- a/components/bt/host/bluedroid/stack/avdt/avdt_api.c +++ b/components/bt/host/bluedroid/stack/avdt/avdt_api.c @@ -171,7 +171,7 @@ void AVDT_Deregister(void) ** Returns void. ** *******************************************************************************/ -void AVDT_SINK_Activate() +void AVDT_SINK_Activate(void) { tAVDT_SCB *p_scb = &avdt_cb.scb[0]; int i; @@ -200,7 +200,7 @@ void AVDT_SINK_Activate() ** Returns void. ** *******************************************************************************/ -void AVDT_SINK_Deactivate() +void AVDT_SINK_Deactivate(void) { tAVDT_SCB *p_scb = &avdt_cb.scb[0]; int i; diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_adv_filter.c b/components/bt/host/bluedroid/stack/btm/btm_ble_adv_filter.c index 438485359f..54cdc189f8 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_adv_filter.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_adv_filter.c @@ -90,7 +90,7 @@ static UINT8 btm_ble_cs_update_pf_counter(tBTM_BLE_SCAN_COND_OP action, ** Returns status ** *******************************************************************************/ -tBTM_STATUS btm_ble_obtain_vsc_details() +tBTM_STATUS btm_ble_obtain_vsc_details(void) { tBTM_STATUS st = BTM_SUCCESS; diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_bgconn.c b/components/bt/host/bluedroid/stack/btm/btm_ble_bgconn.c index 3721471f80..9fd3bd26fb 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_bgconn.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_bgconn.c @@ -60,7 +60,7 @@ static bool bdaddr_equality_fn(const void *x, const void *y) return bdaddr_equals((bt_bdaddr_t *)x, (bt_bdaddr_t *)y); } -static void background_connections_lazy_init() +static void background_connections_lazy_init(void) { if (!background_connections) { background_connections = hash_map_new(background_connection_buckets, @@ -91,7 +91,7 @@ static BOOLEAN background_connection_remove(bt_bdaddr_t *address) return FALSE; } -static void background_connections_clear() +static void background_connections_clear(void) { if (background_connections) { hash_map_clear(background_connections); @@ -110,7 +110,7 @@ static bool background_connections_pending_cb(hash_map_entry_t *hash_entry, void return true; } -static bool background_connections_pending() +static bool background_connections_pending(void) { bool pending_connections = false; if (background_connections) { diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c index caacad51c9..c18d941a1a 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c @@ -2017,7 +2017,7 @@ UINT8 *BTM_CheckAdvData( UINT8 *p_adv, UINT8 type, UINT8 *p_length) ** BTM_BLE_GENRAL_DISCOVERABLE ** *******************************************************************************/ -UINT16 BTM_BleReadDiscoverability() +UINT16 BTM_BleReadDiscoverability(void) { BTM_TRACE_API("%s\n", __FUNCTION__); @@ -2034,7 +2034,7 @@ UINT16 BTM_BleReadDiscoverability() ** Returns BTM_BLE_NON_CONNECTABLE or BTM_BLE_CONNECTABLE ** *******************************************************************************/ -UINT16 BTM_BleReadConnectability() +UINT16 BTM_BleReadConnectability(void) { BTM_TRACE_API ("%s\n", __FUNCTION__); diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_multi_adv.c b/components/bt/host/bluedroid/stack/btm/btm_ble_multi_adv.c index a3ad604437..b18d68e39a 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_multi_adv.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_multi_adv.c @@ -769,7 +769,7 @@ void btm_ble_multi_adv_vse_cback(UINT8 len, UINT8 *p) ** Returns void ** *******************************************************************************/ -void btm_ble_multi_adv_init() +void btm_ble_multi_adv_init(void) { #if BTM_DYNAMIC_MEMORY == TRUE btm_multi_adv_cb_ptr = (tBTM_BLE_MULTI_ADV_CB *)osi_malloc(sizeof(tBTM_BLE_MULTI_ADV_CB)); diff --git a/components/bt/host/bluedroid/stack/include/stack/btm_ble_api.h b/components/bt/host/bluedroid/stack/include/stack/btm_ble_api.h index 2ac01ea2eb..a8900ec321 100644 --- a/components/bt/host/bluedroid/stack/include/stack/btm_ble_api.h +++ b/components/bt/host/bluedroid/stack/include/stack/btm_ble_api.h @@ -1626,7 +1626,7 @@ BOOLEAN BTM_BleGetCurrentAddress(BD_ADDR addr, uint8_t *addr_type); ** BTM_BLE_GENRAL_DISCOVERABLE ** *******************************************************************************/ -UINT16 BTM_BleReadDiscoverability(); +UINT16 BTM_BleReadDiscoverability(void); /******************************************************************************* ** @@ -1639,7 +1639,7 @@ UINT16 BTM_BleReadDiscoverability(); ** *******************************************************************************/ //extern -UINT16 BTM_BleReadConnectability (); +UINT16 BTM_BleReadConnectability (void); void BTM_Recovery_Pre_State(void); @@ -1755,7 +1755,7 @@ void BTM_BleEnableMixedPrivacyMode(BOOLEAN mixed_on); ** *******************************************************************************/ //extern -UINT8 BTM_BleMaxMultiAdvInstanceCount(); +UINT8 BTM_BleMaxMultiAdvInstanceCount(void); /******************************************************************************* ** diff --git a/components/coap/port/coap_io.c b/components/coap/port/coap_io.c index a8f35c180f..00c0ad1d38 100644 --- a/components/coap/port/coap_io.c +++ b/components/coap/port/coap_io.c @@ -80,7 +80,7 @@ void coap_free_endpoint(coap_endpoint_t *ep); static int ep_initialized = 0; struct coap_endpoint_t * - coap_malloc_endpoint() { + coap_malloc_endpoint(void) { static struct coap_endpoint_t ep; if (ep_initialized) { diff --git a/components/console/commands.c b/components/console/commands.c index 52d1675a17..de5cf8edb9 100644 --- a/components/console/commands.c +++ b/components/console/commands.c @@ -70,7 +70,7 @@ esp_err_t esp_console_init(const esp_console_config_t *config) return ESP_OK; } -esp_err_t esp_console_deinit() +esp_err_t esp_console_deinit(void) { if (!s_tmp_line_buf) { return ESP_ERR_INVALID_STATE; @@ -232,7 +232,7 @@ static int help_command(int argc, char **argv) } -esp_err_t esp_console_register_help_command() +esp_err_t esp_console_register_help_command(void) { esp_console_cmd_t command = { .command = "help", diff --git a/components/console/esp_console.h b/components/console/esp_console.h index 45a10b7a2e..e4865d29f9 100644 --- a/components/console/esp_console.h +++ b/components/console/esp_console.h @@ -52,7 +52,7 @@ esp_err_t esp_console_init(const esp_console_config_t* config); * - ESP_OK on success * - ESP_ERR_INVALID_STATE if not initialized yet */ -esp_err_t esp_console_deinit(); +esp_err_t esp_console_deinit(void); /** @@ -185,7 +185,7 @@ const char *esp_console_get_hint(const char *buf, int *color, int *bold); * - ESP_OK on success * - ESP_ERR_INVALID_STATE, if esp_console_init wasn't called */ -esp_err_t esp_console_register_help_command(); +esp_err_t esp_console_register_help_command(void); #ifdef __cplusplus } diff --git a/components/console/linenoise/linenoise.c b/components/console/linenoise/linenoise.c index f88a24620a..f78e238af5 100644 --- a/components/console/linenoise/linenoise.c +++ b/components/console/linenoise/linenoise.c @@ -205,7 +205,7 @@ void linenoiseSetDumbMode(int set) { /* Use the ESC [6n escape sequence to query the horizontal cursor position * and return it. On error -1 is returned, on success the position of the * cursor. */ -static int getCursorPosition() { +static int getCursorPosition(void) { char buf[32]; int cols, rows; unsigned int i = 0; @@ -228,7 +228,7 @@ static int getCursorPosition() { /* Try to get the number of columns in the current terminal, or assume 80 * if it fails. */ -static int getColumns() { +static int getColumns(void) { int start, cols; /* Get the initial position so we can restore it later. */ @@ -887,7 +887,7 @@ static int linenoiseEdit(char *buf, size_t buflen, const char *prompt) return l.len; } -int linenoiseProbe() { +int linenoiseProbe(void) { /* Switch to non-blocking mode */ int flags = fcntl(STDIN_FILENO, F_GETFL); flags |= O_NONBLOCK; @@ -1000,7 +1000,7 @@ void linenoiseFree(void *ptr) { /* ================================ History ================================= */ -void linenoiseHistoryFree() { +void linenoiseHistoryFree(void) { if (history) { for (int j = 0; j < history_len; j++) { free(history[j]); diff --git a/components/console/linenoise/linenoise.h b/components/console/linenoise/linenoise.h index a82701f835..04c6f8b0cc 100644 --- a/components/console/linenoise/linenoise.h +++ b/components/console/linenoise/linenoise.h @@ -63,7 +63,7 @@ int linenoiseHistoryAdd(const char *line); int linenoiseHistorySetMaxLen(int len); int linenoiseHistorySave(const char *filename); int linenoiseHistoryLoad(const char *filename); -void linenoiseHistoryFree(); +void linenoiseHistoryFree(void); void linenoiseClearScreen(void); void linenoiseSetMultiLine(int ml); void linenoiseSetDumbMode(int set); diff --git a/components/cxx/cxx_guards.cpp b/components/cxx/cxx_guards.cpp index 48819a7ab5..640cf17756 100644 --- a/components/cxx/cxx_guards.cpp +++ b/components/cxx/cxx_guards.cpp @@ -36,7 +36,7 @@ static size_t s_static_init_max_waiting_count = 0; //!< maximum ever va extern "C" int __cxa_guard_acquire(__guard* pg); extern "C" void __cxa_guard_release(__guard* pg); extern "C" void __cxa_guard_abort(__guard* pg); -extern "C" void __cxa_guard_dummy(); +extern "C" void __cxa_guard_dummy(void); /** * Layout of the guard object (defined by the ABI). @@ -215,6 +215,6 @@ extern "C" void __cxa_guard_abort(__guard* pg) * Dummy function used to force linking this file instead of the same one in libstdc++. * This works via -u __cxa_guard_dummy flag in component.mk */ -extern "C" void __cxa_guard_dummy() +extern "C" void __cxa_guard_dummy(void) { } diff --git a/components/driver/adc1_i2s_private.h b/components/driver/adc1_i2s_private.h index cc592ffe1d..76da3da028 100644 --- a/components/driver/adc1_i2s_private.h +++ b/components/driver/adc1_i2s_private.h @@ -29,7 +29,7 @@ extern "C" { * This is an internal API for I2S module to call to enable I2S-ADC function. * Note that adc_power_off() can still power down ADC. */ -void adc_power_always_on(); +void adc_power_always_on(void); /** * @brief For I2S dma to claim the usage of ADC1. @@ -41,7 +41,7 @@ void adc_power_always_on(); * - ESP_OK success * - ESP_ERR_TIMEOUT reserved for future use. Currently the function will wait until success. */ -esp_err_t adc1_i2s_mode_acquire(); +esp_err_t adc1_i2s_mode_acquire(void); /** * @brief For ADC1 to claim the usage of ADC1. @@ -53,7 +53,7 @@ esp_err_t adc1_i2s_mode_acquire(); * - ESP_OK success * - ESP_ERR_TIMEOUT reserved for future use. Currently the function will wait until success. */ -esp_err_t adc1_adc_mode_acquire(); +esp_err_t adc1_adc_mode_acquire(void); /** * @brief to let other tasks use the ADC1 when I2S is not work. @@ -63,7 +63,7 @@ esp_err_t adc1_adc_mode_acquire(); * * @return always return ESP_OK. */ -esp_err_t adc1_lock_release(); +esp_err_t adc1_lock_release(void); #ifdef __cplusplus } diff --git a/components/driver/can.c b/components/driver/can.c index 0ddf892968..ec843e4920 100644 --- a/components/driver/can.c +++ b/components/driver/can.c @@ -141,7 +141,7 @@ static portMUX_TYPE can_spinlock = portMUX_INITIALIZER_UNLOCKED; /* ------------------- Configuration Register Functions---------------------- */ -static inline esp_err_t can_enter_reset_mode() +static inline esp_err_t can_enter_reset_mode(void) { /* Enter reset mode (required to write to configuration registers). Reset mode also prevents all CAN activity on the current module and is automatically @@ -151,7 +151,7 @@ static inline esp_err_t can_enter_reset_mode() return ESP_OK; } -static inline esp_err_t can_exit_reset_mode() +static inline esp_err_t can_exit_reset_mode(void) { /* Exiting reset mode will return the CAN module to operating mode. Reset mode must also be exited in order to trigger BUS-OFF recovery sequence. */ @@ -160,7 +160,7 @@ static inline esp_err_t can_exit_reset_mode() return ESP_OK; } -static inline void can_config_pelican() +static inline void can_config_pelican(void) { //Use PeliCAN address layout. Exposes extra registers CAN.clock_divider_reg.can_mode = 1; @@ -286,23 +286,23 @@ static void can_set_tx_buffer_and_transmit(can_frame_t *frame) can_set_command(command); } -static inline uint32_t can_get_status() +static inline uint32_t can_get_status(void) { return CAN.status_reg.val; } -static inline uint32_t can_get_interrupt_reason() +static inline uint32_t can_get_interrupt_reason(void) { return CAN.interrupt_reg.val; } -static inline uint32_t can_get_arbitration_lost_capture() +static inline uint32_t can_get_arbitration_lost_capture(void) { return CAN.arbitration_lost_captue_reg.val; //Todo: ALC read only to re-arm arb lost interrupt. Add function to decode ALC } -static inline uint32_t can_get_error_code_capture() +static inline uint32_t can_get_error_code_capture(void) { return CAN.error_code_capture_reg.val; //Todo: ECC read only to re-arm bus error interrupt. Add function to decode ECC @@ -328,7 +328,7 @@ static inline void can_get_rx_buffer_and_clear(can_frame_t *frame) can_set_command(CMD_RELEASE_RX_BUFF); } -static inline uint32_t can_get_rx_message_counter() +static inline uint32_t can_get_rx_message_counter(void) { return CAN.rx_message_counter_reg.val; } @@ -725,7 +725,7 @@ esp_err_t can_driver_install(const can_general_config_t *g_config, const can_tim return ret; } -esp_err_t can_driver_uninstall() +esp_err_t can_driver_uninstall(void) { can_obj_t *p_can_obj_dummy; @@ -761,7 +761,7 @@ esp_err_t can_driver_uninstall() return ESP_OK; } -esp_err_t can_start() +esp_err_t can_start(void) { //Check state CAN_ENTER_CRITICAL(); @@ -791,7 +791,7 @@ esp_err_t can_start() return ESP_OK; } -esp_err_t can_stop() +esp_err_t can_stop(void) { //Check state CAN_ENTER_CRITICAL(); @@ -928,7 +928,7 @@ esp_err_t can_reconfigure_alerts(uint32_t alerts_enabled, uint32_t *current_aler return ESP_OK; } -esp_err_t can_initiate_recovery() +esp_err_t can_initiate_recovery(void) { CAN_ENTER_CRITICAL(); //Check state @@ -982,7 +982,7 @@ esp_err_t can_get_status_info(can_status_info_t *status_info) return ESP_OK; } -esp_err_t can_clear_transmit_queue() +esp_err_t can_clear_transmit_queue(void) { //Check State CAN_CHECK(p_can_obj != NULL, ESP_ERR_INVALID_STATE); @@ -997,7 +997,7 @@ esp_err_t can_clear_transmit_queue() return ESP_OK; } -esp_err_t can_clear_receive_queue() +esp_err_t can_clear_receive_queue(void) { //Check State CAN_CHECK(p_can_obj != NULL, ESP_ERR_INVALID_STATE); diff --git a/components/driver/gpio.c b/components/driver/gpio.c index f9ae07c370..96fc7a6658 100644 --- a/components/driver/gpio.c +++ b/components/driver/gpio.c @@ -419,7 +419,7 @@ esp_err_t gpio_install_isr_service(int intr_alloc_flags) return ret; } -void gpio_uninstall_isr_service() +void gpio_uninstall_isr_service(void) { if (gpio_isr_func == NULL) { return; diff --git a/components/driver/i2c.c b/components/driver/i2c.c index aeadfaadaa..556dcdf1ff 100644 --- a/components/driver/i2c.c +++ b/components/driver/i2c.c @@ -942,7 +942,7 @@ esp_err_t i2c_set_pin(i2c_port_t i2c_num, int sda_io_num, int scl_io_num, gpio_p return ESP_OK; } -i2c_cmd_handle_t i2c_cmd_link_create() +i2c_cmd_handle_t i2c_cmd_link_create(void) { #if !CONFIG_SPIRAM_USE_MALLOC i2c_cmd_desc_t* cmd_desc = (i2c_cmd_desc_t*) calloc(1, sizeof(i2c_cmd_desc_t)); diff --git a/components/driver/i2s.c b/components/driver/i2s.c index d0c9831b87..fe90c9c78b 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -740,7 +740,7 @@ esp_err_t i2s_set_dac_mode(i2s_dac_mode_t dac_mode) return ESP_OK; } -static esp_err_t _i2s_adc_mode_recover() +static esp_err_t _i2s_adc_mode_recover(void) { I2S_CHECK(((_i2s_adc_unit != -1) && (_i2s_adc_channel != -1)), "i2s ADC recover error, not initialized...", ESP_ERR_INVALID_ARG); return adc_i2s_mode_init(_i2s_adc_unit, _i2s_adc_channel); diff --git a/components/driver/include/driver/adc.h b/components/driver/include/driver/adc.h index 91eb18fd2f..df166b1c8d 100644 --- a/components/driver/include/driver/adc.h +++ b/components/driver/include/driver/adc.h @@ -229,13 +229,13 @@ int adc1_get_voltage(adc1_channel_t channel) __attribute__((deprecated)); /** * @brief Enable ADC power */ -void adc_power_on(); +void adc_power_on(void); /** * @brief Power off SAR ADC * This function will force power down for ADC */ -void adc_power_off(); +void adc_power_off(void); /** * @brief Initialize ADC pad @@ -292,7 +292,7 @@ esp_err_t adc_i2s_mode_init(adc_unit_t adc_unit, adc_channel_t channel); * Note that adc1_config_channel_atten, adc1_config_width functions need * to be called to configure ADC1 channels, before ADC1 is used by the ULP. */ -void adc1_ulp_enable(); +void adc1_ulp_enable(void); /** * @brief Read Hall Sensor @@ -313,7 +313,7 @@ void adc1_ulp_enable(); * * @return The hall sensor reading. */ -int hall_sensor_read(); +int hall_sensor_read(void); /** * @brief Get the gpio number of a specific ADC2 channel. diff --git a/components/driver/include/driver/adc2_wifi_internal.h b/components/driver/include/driver/adc2_wifi_internal.h index ba5c32ead9..833d97d96f 100644 --- a/components/driver/include/driver/adc2_wifi_internal.h +++ b/components/driver/include/driver/adc2_wifi_internal.h @@ -31,7 +31,7 @@ extern "C" { * - ESP_OK success * - ESP_ERR_TIMEOUT reserved for future use. Currently the function will wait until success. */ -esp_err_t adc2_wifi_acquire(); +esp_err_t adc2_wifi_acquire(void); /** @@ -42,7 +42,7 @@ esp_err_t adc2_wifi_acquire(); * * @return always return ESP_OK. */ -esp_err_t adc2_wifi_release(); +esp_err_t adc2_wifi_release(void); #ifdef __cplusplus } diff --git a/components/driver/include/driver/can.h b/components/driver/include/driver/can.h index 8c1d4200f4..074ead3808 100644 --- a/components/driver/include/driver/can.h +++ b/components/driver/include/driver/can.h @@ -238,7 +238,7 @@ esp_err_t can_driver_install(const can_general_config_t *g_config, const can_tim * - ESP_OK: Successfully uninstalled CAN driver * - ESP_ERR_INVALID_STATE: Driver is not in stopped/bus-off state, or is not installed */ -esp_err_t can_driver_uninstall(); +esp_err_t can_driver_uninstall(void); /** * @brief Start the CAN driver @@ -253,7 +253,7 @@ esp_err_t can_driver_uninstall(); * - ESP_OK: CAN driver is now running * - ESP_ERR_INVALID_STATE: Driver is not in stopped state, or is not installed */ -esp_err_t can_start(); +esp_err_t can_start(void); /** * @brief Stop the CAN driver @@ -272,7 +272,7 @@ esp_err_t can_start(); * - ESP_OK: CAN driver is now Stopped * - ESP_ERR_INVALID_STATE: Driver is not in running state, or is not installed */ -esp_err_t can_stop(); +esp_err_t can_stop(void); /** * @brief Transmit a CAN message @@ -379,7 +379,7 @@ esp_err_t can_reconfigure_alerts(uint32_t alerts_enabled, uint32_t *current_aler * - ESP_OK: Bus recovery started * - ESP_ERR_INVALID_STATE: CAN driver is not in the bus-off state, or is not installed */ -esp_err_t can_initiate_recovery(); +esp_err_t can_initiate_recovery(void); /** * @brief Get current status information of the CAN driver @@ -405,7 +405,7 @@ esp_err_t can_get_status_info(can_status_info_t *status_info); * - ESP_OK: Transmit queue cleared * - ESP_ERR_INVALID_STATE: CAN driver is not installed or TX queue is disabled */ -esp_err_t can_clear_transmit_queue(); +esp_err_t can_clear_transmit_queue(void); /** * @brief Clear the receive queue @@ -419,7 +419,7 @@ esp_err_t can_clear_transmit_queue(); * - ESP_OK: Transmit queue cleared * - ESP_ERR_INVALID_STATE: CAN driver is not installed */ -esp_err_t can_clear_receive_queue(); +esp_err_t can_clear_receive_queue(void); #ifdef __cplusplus } diff --git a/components/driver/include/driver/dac.h b/components/driver/include/driver/dac.h index 1e60263c2f..5ed96e201f 100644 --- a/components/driver/include/driver/dac.h +++ b/components/driver/include/driver/dac.h @@ -99,12 +99,12 @@ esp_err_t dac_output_disable(dac_channel_t channel); /** * @brief Enable DAC output data from I2S */ -esp_err_t dac_i2s_enable(); +esp_err_t dac_i2s_enable(void); /** * @brief Disable DAC output data from I2S */ -esp_err_t dac_i2s_disable(); +esp_err_t dac_i2s_disable(void); #ifdef __cplusplus } #endif diff --git a/components/driver/include/driver/gpio.h b/components/driver/include/driver/gpio.h index 9933cba814..11425201d4 100644 --- a/components/driver/include/driver/gpio.h +++ b/components/driver/include/driver/gpio.h @@ -475,7 +475,7 @@ esp_err_t gpio_install_isr_service(int intr_alloc_flags); /** * @brief Uninstall the driver's GPIO ISR service, freeing related resources. */ -void gpio_uninstall_isr_service(); +void gpio_uninstall_isr_service(void); /** * @brief Add ISR handler for the corresponding GPIO pin. diff --git a/components/driver/include/driver/i2c.h b/components/driver/include/driver/i2c.h index 0bd0e2aaec..57204cc60e 100644 --- a/components/driver/include/driver/i2c.h +++ b/components/driver/include/driver/i2c.h @@ -224,7 +224,7 @@ esp_err_t i2c_set_pin(i2c_port_t i2c_num, int sda_io_num, int scl_io_num, * * @return i2c command link handler */ -i2c_cmd_handle_t i2c_cmd_link_create(); +i2c_cmd_handle_t i2c_cmd_link_create(void); /** * @brief Free I2C command link diff --git a/components/driver/include/driver/ledc.h b/components/driver/include/driver/ledc.h index 6a82c19a2f..17875783fb 100644 --- a/components/driver/include/driver/ledc.h +++ b/components/driver/include/driver/ledc.h @@ -435,7 +435,7 @@ esp_err_t ledc_fade_func_install(int intr_alloc_flags); * @brief Uninstall LEDC fade function. * */ -void ledc_fade_func_uninstall(); +void ledc_fade_func_uninstall(void); /** * @brief Start LEDC fading. diff --git a/components/driver/include/driver/rtc_io.h b/components/driver/include/driver/rtc_io.h index c636f61cc1..a2f37a3e7d 100644 --- a/components/driver/include/driver/rtc_io.h +++ b/components/driver/include/driver/rtc_io.h @@ -219,7 +219,7 @@ esp_err_t rtc_gpio_isolate(gpio_num_t gpio_num); * Force hold signal is enabled before going into deep sleep for pins which * are used for EXT1 wakeup. */ -void rtc_gpio_force_hold_dis_all(); +void rtc_gpio_force_hold_dis_all(void); /** * @brief Set RTC GPIO pad drive capability diff --git a/components/driver/include/driver/sdio_slave.h b/components/driver/include/driver/sdio_slave.h index 93f08d94ae..005e469cdc 100644 --- a/components/driver/include/driver/sdio_slave.h +++ b/components/driver/include/driver/sdio_slave.h @@ -111,7 +111,7 @@ esp_err_t sdio_slave_initialize(sdio_slave_config_t *config); /** De-initialize the sdio slave driver to release the resources. */ -void sdio_slave_deinit(); +void sdio_slave_deinit(void); /** Start hardware for sending and receiving, as well as set the IOREADY1 to 1. * @@ -122,19 +122,19 @@ void sdio_slave_deinit(); * - ESP_ERR_INVALID_STATE if already started. * - ESP_OK otherwise. */ -esp_err_t sdio_slave_start(); +esp_err_t sdio_slave_start(void); /** Stop hardware from sending and receiving, also set IOREADY1 to 0. * * @note this will not clear the data already in the driver, and also not reset the PKT_LEN and TOKEN1 counting. Call ``sdio_slave_reset`` to do that. */ -void sdio_slave_stop(); +void sdio_slave_stop(void); /** Clear the data still in the driver, as well as reset the PKT_LEN and TOKEN1 counting. * * @return always return ESP_OK. */ -esp_err_t sdio_slave_reset(); +esp_err_t sdio_slave_reset(void); /*--------------------------------------------------------------------------- * Receive @@ -263,7 +263,7 @@ esp_err_t sdio_slave_write_reg(int pos, uint8_t reg); * * @return the interrupt mask. */ -sdio_slave_hostint_t sdio_slave_get_host_intena(); +sdio_slave_hostint_t sdio_slave_get_host_intena(void); /** Set the interrupt enable for host. * diff --git a/components/driver/include/driver/sdmmc_host.h b/components/driver/include/driver/sdmmc_host.h index 4e2db09946..8cd403d859 100644 --- a/components/driver/include/driver/sdmmc_host.h +++ b/components/driver/include/driver/sdmmc_host.h @@ -91,7 +91,7 @@ typedef struct { * - ESP_ERR_INVALID_STATE if sdmmc_host_init was already called * - ESP_ERR_NO_MEM if memory can not be allocated */ -esp_err_t sdmmc_host_init(); +esp_err_t sdmmc_host_init(void); /** * @brief Initialize given slot of SDMMC peripheral @@ -218,7 +218,7 @@ esp_err_t sdmmc_host_io_int_wait(int slot, TickType_t timeout_ticks); * - ESP_OK on success * - ESP_ERR_INVALID_STATE if sdmmc_host_init function has not been called */ -esp_err_t sdmmc_host_deinit(); +esp_err_t sdmmc_host_deinit(void); /** * @brief Enable the pull-ups of sd pins. diff --git a/components/driver/include/driver/sdspi_host.h b/components/driver/include/driver/sdspi_host.h index 605cd76240..8cb922803f 100644 --- a/components/driver/include/driver/sdspi_host.h +++ b/components/driver/include/driver/sdspi_host.h @@ -91,7 +91,7 @@ typedef struct { * - ESP_OK on success * - other error codes may be returned in future versions */ -esp_err_t sdspi_host_init(); +esp_err_t sdspi_host_init(void); /** * @brief Initialize SD SPI driver for the specific SPI controller @@ -159,7 +159,7 @@ esp_err_t sdspi_host_set_card_clk(int slot, uint32_t freq_khz); * - ESP_OK on success * - ESP_ERR_INVALID_STATE if sdspi_host_init function has not been called */ -esp_err_t sdspi_host_deinit(); +esp_err_t sdspi_host_deinit(void); /** * @brief Enable SDIO interrupt. diff --git a/components/driver/include/driver/spi_common.h b/components/driver/include/driver/spi_common.h index b441595461..8f7c97f3d5 100644 --- a/components/driver/include/driver/spi_common.h +++ b/components/driver/include/driver/spi_common.h @@ -381,7 +381,7 @@ bool spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void * * @return True when a DMA reset is requested but hasn't completed yet. False otherwise. */ -bool spicommon_dmaworkaround_reset_in_progress(); +bool spicommon_dmaworkaround_reset_in_progress(void); /** diff --git a/components/driver/include/driver/touch_pad.h b/components/driver/include/driver/touch_pad.h index 0c3884ded9..53d5b37389 100644 --- a/components/driver/include/driver/touch_pad.h +++ b/components/driver/include/driver/touch_pad.h @@ -117,7 +117,7 @@ typedef intr_handle_t touch_isr_handle_t; * - ESP_OK Success * - ESP_FAIL Touch pad init error */ -esp_err_t touch_pad_init(); +esp_err_t touch_pad_init(void); /** * @brief Un-install touch pad driver. @@ -126,7 +126,7 @@ esp_err_t touch_pad_init(); * - ESP_OK Success * - ESP_FAIL Touch pad driver not initialized */ -esp_err_t touch_pad_deinit(); +esp_err_t touch_pad_deinit(void); /** * @brief Configure touch pad interrupt threshold. @@ -364,7 +364,7 @@ esp_err_t touch_pad_get_fsm_mode(touch_fsm_mode_t *mode); * @return * - ESP_OK on success */ -esp_err_t touch_pad_sw_start(); +esp_err_t touch_pad_sw_start(void); /** * @brief Set touch sensor interrupt threshold @@ -468,28 +468,28 @@ esp_err_t touch_pad_clear_group_mask(uint16_t set1_mask, uint16_t set2_mask, uin * @return * - ESP_OK on success */ -esp_err_t touch_pad_clear_status(); +esp_err_t touch_pad_clear_status(void); /** * @brief Get the touch sensor status, usually used in ISR to decide which pads are 'touched'. * @return * - touch status */ -uint32_t touch_pad_get_status(); +uint32_t touch_pad_get_status(void); /** * @brief To enable touch pad interrupt * @return * - ESP_OK on success */ -esp_err_t touch_pad_intr_enable(); +esp_err_t touch_pad_intr_enable(void); /** * @brief To disable touch pad interrupt * @return * - ESP_OK on success */ -esp_err_t touch_pad_intr_disable(); +esp_err_t touch_pad_intr_disable(void); /** * @brief set touch pad filter calibration period, in ms. @@ -539,7 +539,7 @@ esp_err_t touch_pad_filter_start(uint32_t filter_period_ms); * - ESP_OK Success * - ESP_ERR_INVALID_STATE driver state error */ -esp_err_t touch_pad_filter_stop(); +esp_err_t touch_pad_filter_stop(void); /** * @brief delete touch pad filter driver and release the memory @@ -548,7 +548,7 @@ esp_err_t touch_pad_filter_stop(); * - ESP_OK Success * - ESP_ERR_INVALID_STATE driver state error */ -esp_err_t touch_pad_filter_delete(); +esp_err_t touch_pad_filter_delete(void); /** * @brief Get the touch pad which caused wakeup from sleep diff --git a/components/driver/include/driver/uart_select.h b/components/driver/include/driver/uart_select.h index 24f06c1de6..f7a21a315b 100644 --- a/components/driver/include/driver/uart_select.h +++ b/components/driver/include/driver/uart_select.h @@ -40,7 +40,7 @@ void uart_set_select_notif_callback(uart_port_t uart_num, uart_select_notif_call /** * @brief Get mutex guarding select() notifications */ -portMUX_TYPE *uart_get_selectlock(); +portMUX_TYPE *uart_get_selectlock(void); #ifdef __cplusplus } diff --git a/components/driver/ledc.c b/components/driver/ledc.c index 92a055cbc0..ff992d1474 100644 --- a/components/driver/ledc.c +++ b/components/driver/ledc.c @@ -712,7 +712,7 @@ esp_err_t ledc_fade_func_install(int intr_alloc_flags) return ledc_isr_register(ledc_fade_isr, NULL, intr_alloc_flags | ESP_INTR_FLAG_IRAM, &s_ledc_fade_isr_handle); } -void ledc_fade_func_uninstall() +void ledc_fade_func_uninstall(void) { if (s_ledc_fade_rec == NULL) { return; diff --git a/components/driver/rmt.c b/components/driver/rmt.c index 10605d2e24..38380da30a 100644 --- a/components/driver/rmt.c +++ b/components/driver/rmt.c @@ -321,7 +321,7 @@ esp_err_t rmt_get_status(rmt_channel_t channel, uint32_t* status) return ESP_OK; } -rmt_data_mode_t rmt_get_data_mode() +rmt_data_mode_t rmt_get_data_mode(void) { return (rmt_data_mode_t) (RMT.apb_conf.fifo_mask); } diff --git a/components/driver/rtc_module.c b/components/driver/rtc_module.c index 1be5c645ca..d5954c9e6d 100644 --- a/components/driver/rtc_module.c +++ b/components/driver/rtc_module.c @@ -368,7 +368,7 @@ esp_err_t rtc_gpio_isolate(gpio_num_t gpio_num) return ESP_OK; } -void rtc_gpio_force_hold_dis_all() +void rtc_gpio_force_hold_dis_all(void) { for (int gpio = 0; gpio < GPIO_PIN_COUNT; ++gpio) { const rtc_gpio_desc_t* desc = &rtc_gpio_desc[gpio]; @@ -657,7 +657,7 @@ esp_err_t touch_pad_get_fsm_mode(touch_fsm_mode_t *mode) return ESP_OK; } -esp_err_t touch_pad_sw_start() +esp_err_t touch_pad_sw_start(void) { portENTER_CRITICAL(&rtc_spinlock); SENS.sar_touch_ctrl2.touch_start_en = 0; @@ -772,13 +772,13 @@ esp_err_t touch_pad_clear_group_mask(uint16_t set1_mask, uint16_t set2_mask, uin return ESP_OK; } -uint32_t IRAM_ATTR touch_pad_get_status() +uint32_t IRAM_ATTR touch_pad_get_status(void) { uint32_t status = SENS.sar_touch_ctrl2.touch_meas_en; return TOUCH_BITS_SWAP(status); } -esp_err_t IRAM_ATTR touch_pad_clear_status() +esp_err_t IRAM_ATTR touch_pad_clear_status(void) { portENTER_CRITICAL(&rtc_spinlock); SENS.sar_touch_ctrl2.touch_meas_en_clr = 1; @@ -786,7 +786,7 @@ esp_err_t IRAM_ATTR touch_pad_clear_status() return ESP_OK; } -esp_err_t touch_pad_intr_enable() +esp_err_t touch_pad_intr_enable(void) { portENTER_CRITICAL(&rtc_spinlock); RTCCNTL.int_ena.rtc_touch = 1; @@ -794,7 +794,7 @@ esp_err_t touch_pad_intr_enable() return ESP_OK; } -esp_err_t touch_pad_intr_disable() +esp_err_t touch_pad_intr_disable(void) { portENTER_CRITICAL(&rtc_spinlock); RTCCNTL.int_ena.rtc_touch = 0; @@ -834,7 +834,7 @@ esp_err_t touch_pad_config(touch_pad_t touch_num, uint16_t threshold) return ESP_OK; } -esp_err_t touch_pad_init() +esp_err_t touch_pad_init(void) { if (rtc_touch_mux == NULL) { rtc_touch_mux = xSemaphoreCreateMutex(); @@ -852,7 +852,7 @@ esp_err_t touch_pad_init() return ESP_OK; } -esp_err_t touch_pad_deinit() +esp_err_t touch_pad_deinit(void) { RTC_MODULE_CHECK(rtc_touch_mux != NULL, "Touch pad not initialized", ESP_FAIL); if (s_touch_pad_filter != NULL) { @@ -1006,7 +1006,7 @@ err_no_mem: return ESP_ERR_NO_MEM; } -esp_err_t touch_pad_filter_stop() +esp_err_t touch_pad_filter_stop(void) { RTC_MODULE_CHECK(s_touch_pad_filter != NULL, "Touch pad filter not initialized", ESP_ERR_INVALID_STATE); RTC_MODULE_CHECK(rtc_touch_mux != NULL, "Touch pad not initialized", ESP_ERR_INVALID_STATE); @@ -1022,7 +1022,7 @@ esp_err_t touch_pad_filter_stop() return ret; } -esp_err_t touch_pad_filter_delete() +esp_err_t touch_pad_filter_delete(void) { RTC_MODULE_CHECK(s_touch_pad_filter != NULL, "Touch pad filter not initialized", ESP_ERR_INVALID_STATE); RTC_MODULE_CHECK(rtc_touch_mux != NULL, "Touch pad not initialized", ESP_ERR_INVALID_STATE); @@ -1143,14 +1143,14 @@ static esp_err_t adc_set_atten(adc_unit_t adc_unit, adc_channel_t channel, adc_a return ESP_OK; } -void adc_power_always_on() +void adc_power_always_on(void) { portENTER_CRITICAL(&rtc_spinlock); SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PU; portEXIT_CRITICAL(&rtc_spinlock); } -void adc_power_on() +void adc_power_on(void) { portENTER_CRITICAL(&rtc_spinlock); //The power FSM controlled mode saves more power, while the ADC noise may get increased. @@ -1168,7 +1168,7 @@ void adc_power_on() portEXIT_CRITICAL(&rtc_spinlock); } -void adc_power_off() +void adc_power_off(void) { portENTER_CRITICAL(&rtc_spinlock); //Bit1 0:Fsm 1: SW mode @@ -1474,7 +1474,7 @@ esp_err_t adc1_config_width(adc_bits_width_t width_bit) return ESP_OK; } -static inline void adc1_fsm_disable() +static inline void adc1_fsm_disable(void) { //channel is set in the convert function SENS.sar_meas_wait2.force_xpd_amp = SENS_FORCE_XPD_AMP_PD; @@ -1487,7 +1487,7 @@ static inline void adc1_fsm_disable() SENS.sar_meas_wait2.sar_amp_wait3 = 1; } -esp_err_t adc1_i2s_mode_acquire() +esp_err_t adc1_i2s_mode_acquire(void) { //lazy initialization //for i2s, block until acquire the lock @@ -1501,7 +1501,7 @@ esp_err_t adc1_i2s_mode_acquire() return ESP_OK; } -esp_err_t adc1_adc_mode_acquire() +esp_err_t adc1_adc_mode_acquire(void) { //lazy initialization //for adc1, block until acquire the lock @@ -1517,7 +1517,7 @@ esp_err_t adc1_adc_mode_acquire() return ESP_OK; } -esp_err_t adc1_lock_release() +esp_err_t adc1_lock_release(void) { RTC_MODULE_CHECK((uint32_t*)adc1_i2s_lock != NULL, "adc1 lock release called before acquire", ESP_ERR_INVALID_STATE ); // for now the WiFi would use ADC2 and set xpd_sar force on. @@ -1548,7 +1548,7 @@ int adc1_get_raw(adc1_channel_t channel) return adc_value; } -int adc1_get_voltage(adc1_channel_t channel) //Deprecated. Use adc1_get_raw() instead +int adc1_get_voltage(adc1_channel_t channel) //Deprecated. Use adc1_get_raw(void) instead { return adc1_get_raw(channel); } @@ -1611,7 +1611,7 @@ esp_err_t adc2_pad_get_io_num(adc2_channel_t channel, gpio_num_t *gpio_num) return ESP_OK; } -esp_err_t adc2_wifi_acquire() +esp_err_t adc2_wifi_acquire(void) { //lazy initialization //for wifi, block until acquire the lock @@ -1620,7 +1620,7 @@ esp_err_t adc2_wifi_acquire() return ESP_OK; } -esp_err_t adc2_wifi_release() +esp_err_t adc2_wifi_release(void) { RTC_MODULE_CHECK((uint32_t*)adc2_wifi_lock != NULL, "wifi release called before acquire", ESP_ERR_INVALID_STATE ); @@ -1878,7 +1878,7 @@ esp_err_t dac_out_voltage(dac_channel_t channel, uint8_t dac_value) return ESP_OK; } -esp_err_t dac_i2s_enable() +esp_err_t dac_i2s_enable(void) { portENTER_CRITICAL(&rtc_spinlock); SET_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_DAC_DIG_FORCE_M | SENS_DAC_CLK_INV_M); @@ -1886,7 +1886,7 @@ esp_err_t dac_i2s_enable() return ESP_OK; } -esp_err_t dac_i2s_disable() +esp_err_t dac_i2s_disable(void) { portENTER_CRITICAL(&rtc_spinlock); CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_DAC_DIG_FORCE_M | SENS_DAC_CLK_INV_M); @@ -1903,7 +1903,7 @@ static inline void adc1_hall_enable(bool enable) RTCIO.hall_sens.xpd_hall = enable; } -static int hall_sensor_get_value() //hall sensor without LNA +static int hall_sensor_get_value(void) //hall sensor without LNA { int Sens_Vp0; int Sens_Vn0; @@ -1932,7 +1932,7 @@ static int hall_sensor_get_value() //hall sensor without LNA return hall_value; } -int hall_sensor_read() +int hall_sensor_read(void) { adc_gpio_init(ADC_UNIT_1, ADC1_CHANNEL_0); adc_gpio_init(ADC_UNIT_1, ADC1_CHANNEL_3); @@ -1974,7 +1974,7 @@ static void rtc_isr(void* arg) REG_WRITE(RTC_CNTL_INT_CLR_REG, status); } -static esp_err_t rtc_isr_ensure_installed() +static esp_err_t rtc_isr_ensure_installed(void) { esp_err_t err = ESP_OK; portENTER_CRITICAL(&s_rtc_isr_handler_list_lock); diff --git a/components/driver/sdio_slave.c b/components/driver/sdio_slave.c index 12d106ae59..0d639d8029 100644 --- a/components/driver/sdio_slave.c +++ b/components/driver/sdio_slave.c @@ -215,17 +215,17 @@ static void sdio_intr_host(void*); static void sdio_intr_send(void*); static void sdio_intr_recv(void*); -static esp_err_t send_flush_data(); -static esp_err_t send_reset_counter(); -static void recv_flush_data(); -static void recv_reset_counter(); +static esp_err_t send_flush_data(void); +static esp_err_t send_reset_counter(void); +static void recv_flush_data(void); +static void recv_reset_counter(void); -static esp_err_t send_start(); -static void send_stop(); -static esp_err_t recv_start(); -static void recv_stop(); +static esp_err_t send_start(void); +static void send_stop(void); +static esp_err_t recv_start(void); +static void recv_stop(void); -static void deinit_context(); +static void deinit_context(void); /**************** Ring buffer for SDIO use *****************/ @@ -395,7 +395,7 @@ static void __attribute((unused)) dump_ll(lldesc_t *queue) ESP_EARLY_LOGI(TAG, "total: %d", cnt); } -static inline void deinit_context() +static inline void deinit_context(void) { context.config = (sdio_slave_config_t){}; for(int i = 0; i < 9; i++) { @@ -417,7 +417,7 @@ esp_err_t link_desc_to_last(uint8_t* desc, void* arg) return ESP_OK; } -static esp_err_t init_ringbuf() +static esp_err_t init_ringbuf(void) { esp_err_t ret = sdio_ringbuf_init(&context.sendbuf, sizeof(buf_desc_t), context.config.send_queue_size); if (ret != ESP_OK) return ret; @@ -591,7 +591,7 @@ esp_err_t sdio_slave_initialize(sdio_slave_config_t *config) return ESP_OK; } -void sdio_slave_deinit() +void sdio_slave_deinit(void) { esp_err_t ret = esp_intr_free(context.intr_handle); assert(ret==ESP_OK); @@ -599,7 +599,7 @@ void sdio_slave_deinit() deinit_context(); } -esp_err_t sdio_slave_start() +esp_err_t sdio_slave_start(void) { esp_err_t ret; HOST.slc0_int_clr.val = UINT32_MAX;//clear all interrupts @@ -611,7 +611,7 @@ esp_err_t sdio_slave_start() return ESP_OK; } -esp_err_t sdio_slave_reset() +esp_err_t sdio_slave_reset(void) { send_flush_data(); send_reset_counter(); @@ -620,7 +620,7 @@ esp_err_t sdio_slave_reset() return ESP_OK; } -void sdio_slave_stop() +void sdio_slave_stop(void) { HINF.cfg_data1.sdio_ioready1 = 0; //set IO ready to 1 to stop host from using send_stop(); @@ -696,7 +696,7 @@ esp_err_t sdio_slave_write_reg(int pos, uint8_t reg) return ESP_OK; } -sdio_slave_hostint_t sdio_slave_get_host_intena() +sdio_slave_hostint_t sdio_slave_get_host_intena(void) { return HOST.slc0_func1_int_ena.val; } @@ -742,12 +742,12 @@ static inline void send_start_transmission(const void* desc) SLC.slc0_rx_link.start = 1; } -static inline void send_stop_ll_operation() +static inline void send_stop_ll_operation(void) { SLC.slc0_rx_link.stop = 1; } -static inline uint32_t send_length_read() +static inline uint32_t send_length_read(void) { return HOST.pkt_len.reg_slc0_len; } @@ -760,7 +760,7 @@ DMA_ATTR static const buf_desc_t start_desc = { .eof = 1, }; -static inline void send_isr_invoker_enable() +static inline void send_isr_invoker_enable(void) { //force trigger rx_done interrupt. the interrupt is abused to invoke ISR from the app by the enable bit and never cleared. send_start_transmission(&start_desc); @@ -770,29 +770,29 @@ static inline void send_isr_invoker_enable() send_stop_ll_operation(); } -static inline void send_isr_invoker_disable() +static inline void send_isr_invoker_disable(void) { SLC.slc0_int_clr.rx_done = 1; } -static inline void send_intr_enable() +static inline void send_intr_enable(void) { SLC.slc0_int_ena.rx_eof = 1; send_isr_invoker_enable(); } -static inline void send_intr_disable() +static inline void send_intr_disable(void) { send_isr_invoker_disable(); SLC.slc0_int_ena.rx_eof = 0; } -static inline void send_isr_invoke() +static inline void send_isr_invoke(void) { SLC.slc0_int_ena.rx_done = 1; } -static inline send_state_t send_get_state() +static inline send_state_t send_get_state(void) { return context.send_state; } @@ -803,7 +803,7 @@ static inline void send_set_state(send_state_t state) } //start hw operation with existing data (if exist) -static esp_err_t send_start() +static esp_err_t send_start(void) { SDIO_SLAVE_CHECK(send_get_state() == STATE_IDLE, "already started", ESP_ERR_INVALID_STATE); @@ -814,7 +814,7 @@ static esp_err_t send_start() } //only stop hw operations, no touch to data as well as counter -static void send_stop() +static void send_stop(void) { SLC.slc0_rx_link.stop = 1; send_intr_disable(); @@ -866,7 +866,7 @@ static inline esp_err_t send_isr_check_new_pkt(portBASE_TYPE *yield) return ESP_OK; } -static inline esp_err_t send_isr_new_packet() +static inline esp_err_t send_isr_new_packet(void) { // since eof is changed, we have to stop and reset the link list, // and restart new link list operation @@ -973,7 +973,7 @@ esp_err_t sdio_slave_transmit(uint8_t* addr, size_t len) } //clear data but keep counter -static esp_err_t send_flush_data() +static esp_err_t send_flush_data(void) { //only works in idle state / wait to send state SDIO_SLAVE_CHECK(send_get_state() == STATE_IDLE, @@ -1019,7 +1019,7 @@ static esp_err_t send_flush_data() } //clear counter but keep data -static esp_err_t send_reset_counter() +static esp_err_t send_reset_counter(void) { SDIO_SLAVE_CHECK(send_get_state() == STATE_IDLE, "reset counter when transmission started", ESP_ERR_INVALID_STATE); @@ -1061,28 +1061,28 @@ static esp_err_t send_reset_counter() #define CHECK_HANDLE_IDLE(desc) do { if (desc == NULL || !desc->not_receiving) {\ return ESP_ERR_INVALID_ARG; } } while(0) -static inline void critical_enter_recv() +static inline void critical_enter_recv(void) { portENTER_CRITICAL(&context.recv_spinlock); } -static inline void critical_exit_recv() +static inline void critical_exit_recv(void) { portEXIT_CRITICAL(&context.recv_spinlock); } -static inline void recv_size_inc() +static inline void recv_size_inc(void) { // fields wdata and inc_more should be written by the same instruction. SLC.slc0_token1.val = FIELD_TO_VALUE2(SLC_SLC0_TOKEN1_WDATA, 1) | FIELD_TO_VALUE2(SLC_SLC0_TOKEN1_INC_MORE, 1); } -static inline void recv_size_reset() +static inline void recv_size_reset(void) { SLC.slc0_token1.val = FIELD_TO_VALUE2(SLC_SLC0_TOKEN1_WDATA, 0) | FIELD_TO_VALUE2(SLC_SLC0_TOKEN1_WR, 1); } -static inline buf_desc_t* recv_get_first_empty_buf() +static inline buf_desc_t* recv_get_first_empty_buf(void) { buf_stailq_t *const queue = &context.recv_link_list; buf_desc_t *desc = STAILQ_FIRST(queue); @@ -1092,7 +1092,7 @@ static inline buf_desc_t* recv_get_first_empty_buf() return desc; } -static esp_err_t recv_start() +static esp_err_t recv_start(void) { SLC.conf0.slc0_tx_rst = 1; SLC.conf0.slc0_tx_rst = 0; @@ -1113,14 +1113,14 @@ static esp_err_t recv_start() return ESP_OK; } -static void recv_stop() +static void recv_stop(void) { SLC.slc0_tx_link.stop = 1; SLC.slc0_int_ena.tx_done = 0; } // reset the counter, but keep the data -static void recv_reset_counter() +static void recv_reset_counter(void) { recv_size_reset(); @@ -1135,7 +1135,7 @@ static void recv_reset_counter() } // remove data, still increase the counter -static void recv_flush_data() +static void recv_flush_data(void) { buf_stailq_t *const queue = &context.recv_link_list; @@ -1276,7 +1276,7 @@ uint8_t* sdio_slave_recv_get_buf(sdio_slave_buf_handle_t handle, size_t *len_o) return desc->buf; } -static void __attribute((unused)) sdio_slave_recv_get_loaded_buffer_num() +static void __attribute((unused)) sdio_slave_recv_get_loaded_buffer_num(void) { buf_stailq_t *const queue = &context.recv_link_list; dump_queue(queue); diff --git a/components/driver/sdmmc_host.c b/components/driver/sdmmc_host.c index 7a8969fd21..c1361829bc 100644 --- a/components/driver/sdmmc_host.c +++ b/components/driver/sdmmc_host.c @@ -30,7 +30,7 @@ static void sdmmc_isr(void* arg); -static void sdmmc_host_dma_init(); +static void sdmmc_host_dma_init(void); static const char* TAG = "sdmmc_periph"; @@ -40,7 +40,7 @@ static SemaphoreHandle_t s_io_intr_event; size_t s_slot_width[2] = {1,1}; -void sdmmc_host_reset() +void sdmmc_host_reset(void) { // Set reset bits SDMMC.ctrl.controller_reset = 1; @@ -97,7 +97,7 @@ static void sdmmc_host_set_clk_div(int div) ets_delay_us(10); } -static void sdmmc_host_input_clk_disable() +static void sdmmc_host_input_clk_disable(void) { SDMMC.clock.val = 0; } @@ -216,7 +216,7 @@ esp_err_t sdmmc_host_start_command(int slot, sdmmc_hw_cmd_t cmd, uint32_t arg) { return ESP_OK; } -esp_err_t sdmmc_host_init() +esp_err_t sdmmc_host_init(void) { if (s_intr_handle) { return ESP_ERR_INVALID_STATE; @@ -402,7 +402,7 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t* slot_config) return ESP_OK; } -esp_err_t sdmmc_host_deinit() +esp_err_t sdmmc_host_deinit(void) { if (!s_intr_handle) { return ESP_ERR_INVALID_STATE; @@ -490,7 +490,7 @@ esp_err_t sdmmc_host_set_bus_ddr_mode(int slot, bool ddr_enabled) return ESP_OK; } -static void sdmmc_host_dma_init() +static void sdmmc_host_dma_init(void) { SDMMC.ctrl.dma_enable = 1; SDMMC.bmod.val = 0; @@ -501,7 +501,7 @@ static void sdmmc_host_dma_init() } -void sdmmc_host_dma_stop() +void sdmmc_host_dma_stop(void) { SDMMC.ctrl.use_internal_dma = 0; SDMMC.ctrl.dma_reset = 1; @@ -524,12 +524,12 @@ void sdmmc_host_dma_prepare(sdmmc_desc_t* desc, size_t block_size, size_t data_s sdmmc_host_dma_resume(); } -void sdmmc_host_dma_resume() +void sdmmc_host_dma_resume(void) { SDMMC.pldmnd = 1; } -bool sdmmc_host_card_busy() +bool sdmmc_host_card_busy(void) { return SDMMC.status.data_busy == 1; } diff --git a/components/driver/sdmmc_private.h b/components/driver/sdmmc_private.h index 9223dce319..94cea52d1b 100644 --- a/components/driver/sdmmc_private.h +++ b/components/driver/sdmmc_private.h @@ -26,7 +26,7 @@ typedef struct { uint32_t dma_status; ///< masked DMA interrupt status } sdmmc_event_t; -void sdmmc_host_reset(); +void sdmmc_host_reset(void); esp_err_t sdmmc_host_start_command(int slot, sdmmc_hw_cmd_t cmd, uint32_t arg); @@ -34,13 +34,13 @@ esp_err_t sdmmc_host_wait_for_event(int tick_count, sdmmc_event_t* out_event); void sdmmc_host_dma_prepare(sdmmc_desc_t* desc, size_t block_size, size_t data_size); -void sdmmc_host_dma_stop(); +void sdmmc_host_dma_stop(void); -void sdmmc_host_dma_resume(); +void sdmmc_host_dma_resume(void); -bool sdmmc_host_card_busy(); +bool sdmmc_host_card_busy(void); -esp_err_t sdmmc_host_transaction_handler_init(); +esp_err_t sdmmc_host_transaction_handler_init(void); -void sdmmc_host_transaction_handler_deinit(); +void sdmmc_host_transaction_handler_deinit(void); diff --git a/components/driver/sdmmc_transaction.c b/components/driver/sdmmc_transaction.c index 6cddd4b8e0..b2f0874b3f 100644 --- a/components/driver/sdmmc_transaction.c +++ b/components/driver/sdmmc_transaction.c @@ -72,7 +72,7 @@ static bool s_is_app_cmd; // This flag is set if the next command is an APP co static esp_pm_lock_handle_t s_pm_lock; #endif -static esp_err_t handle_idle_state_events(); +static esp_err_t handle_idle_state_events(void); static sdmmc_hw_cmd_t make_hw_cmd(sdmmc_command_t* cmd); static esp_err_t handle_event(sdmmc_command_t* cmd, sdmmc_req_state_t* state, sdmmc_event_t* unhandled_events); @@ -80,10 +80,10 @@ static esp_err_t process_events(sdmmc_event_t evt, sdmmc_command_t* cmd, sdmmc_req_state_t* pstate, sdmmc_event_t* unhandled_events); static void process_command_response(uint32_t status, sdmmc_command_t* cmd); static void fill_dma_descriptors(size_t num_desc); -static size_t get_free_descriptors_count(); +static size_t get_free_descriptors_count(void); static bool wait_for_busy_cleared(int timeout_ms); -esp_err_t sdmmc_host_transaction_handler_init() +esp_err_t sdmmc_host_transaction_handler_init(void) { assert(s_request_mutex == NULL); s_request_mutex = xSemaphoreCreateMutex(); @@ -102,7 +102,7 @@ esp_err_t sdmmc_host_transaction_handler_init() return ESP_OK; } -void sdmmc_host_transaction_handler_deinit() +void sdmmc_host_transaction_handler_deinit(void) { assert(s_request_mutex); #ifdef CONFIG_PM_ENABLE @@ -182,7 +182,7 @@ out: return ret; } -static size_t get_free_descriptors_count() +static size_t get_free_descriptors_count(void) { const size_t next = s_cur_transfer.next_desc; size_t count = 0; @@ -234,7 +234,7 @@ static void fill_dma_descriptors(size_t num_desc) } } -static esp_err_t handle_idle_state_events() +static esp_err_t handle_idle_state_events(void) { /* Handle any events which have happened in between transfers. * Under current assumptions (no SDIO support) only card detect events diff --git a/components/driver/sdspi_host.c b/components/driver/sdspi_host.c index 3a36ed7698..d3e37489f8 100644 --- a/components/driver/sdspi_host.c +++ b/components/driver/sdspi_host.c @@ -225,12 +225,12 @@ static esp_err_t init_spi_dev(int slot, int clock_speed_hz) return spi_bus_add_device((spi_host_device_t) slot, &devcfg, &s_slots[slot].handle); } -esp_err_t sdspi_host_init() +esp_err_t sdspi_host_init(void) { return ESP_OK; } -esp_err_t sdspi_host_deinit() +esp_err_t sdspi_host_deinit(void) { for (size_t i = 0; i < sizeof(s_slots)/sizeof(s_slots[0]); ++i) { if (s_slots[i].handle) { diff --git a/components/driver/spi_common.c b/components/driver/spi_common.c index ff7501eafe..a8954d07c9 100644 --- a/components/driver/spi_common.c +++ b/components/driver/spi_common.c @@ -394,7 +394,7 @@ bool IRAM_ATTR spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t return ret; } -bool IRAM_ATTR spicommon_dmaworkaround_reset_in_progress() +bool IRAM_ATTR spicommon_dmaworkaround_reset_in_progress(void) { return (dmaworkaround_waiting_for_chan != 0); } diff --git a/components/driver/test/test_i2c.c b/components/driver/test/test_i2c.c index 2d8bb922f7..bde591cb3f 100644 --- a/components/driver/test/test_i2c.c +++ b/components/driver/test/test_i2c.c @@ -75,7 +75,7 @@ static void disp_buf(uint8_t *buf, int len) printf("\n"); } -static i2c_config_t i2c_master_init() +static i2c_config_t i2c_master_init(void) { i2c_config_t conf_master = { .mode = I2C_MODE_MASTER, @@ -88,7 +88,7 @@ static i2c_config_t i2c_master_init() return conf_master; } -static i2c_config_t i2c_slave_init() +static i2c_config_t i2c_slave_init(void) { i2c_config_t conf_slave = { .mode = I2C_MODE_SLAVE, @@ -252,7 +252,7 @@ TEST_CASE("I2C driver memory leaking check", "[i2c]") TEST_ASSERT_INT_WITHIN(100, size, esp_get_free_heap_size()); } -static void i2c_master_write_test() +static void i2c_master_write_test(void) { uint8_t *data_wr = (uint8_t *) malloc(DATA_LENGTH); int i; @@ -276,7 +276,7 @@ static void i2c_master_write_test() TEST_ESP_OK(i2c_driver_delete(I2C_MASTER_NUM)); } -static void i2c_slave_read_test() +static void i2c_slave_read_test(void) { uint8_t *data_rd = (uint8_t *) malloc(DATA_LENGTH); int size_rd = 0; @@ -308,7 +308,7 @@ static void i2c_slave_read_test() TEST_CASE_MULTIPLE_DEVICES("I2C master write slave test", "[i2c][test_env=UT_T2_I2C][timeout=150]", i2c_master_write_test, i2c_slave_read_test); -static void master_read_slave_test() +static void master_read_slave_test(void) { uint8_t *data_rd = (uint8_t *) malloc(DATA_LENGTH); memset(data_rd, 0, DATA_LENGTH); @@ -340,7 +340,7 @@ static void master_read_slave_test() i2c_driver_delete(I2C_MASTER_NUM); } -static void slave_write_buffer_test() +static void slave_write_buffer_test(void) { uint8_t *data_wr = (uint8_t *) malloc(DATA_LENGTH); int size_rd; @@ -367,7 +367,7 @@ static void slave_write_buffer_test() TEST_CASE_MULTIPLE_DEVICES("I2C master read slave test", "[i2c][test_env=UT_T2_I2C][timeout=150]", master_read_slave_test, slave_write_buffer_test); -static void i2c_master_write_read_test() +static void i2c_master_write_read_test(void) { uint8_t *data_rd = (uint8_t *) malloc(DATA_LENGTH); memset(data_rd, 0, DATA_LENGTH); @@ -409,7 +409,7 @@ static void i2c_master_write_read_test() i2c_driver_delete(I2C_MASTER_NUM); } -static void i2c_slave_read_write_test() +static void i2c_slave_read_write_test(void) { uint8_t *data_rd = (uint8_t *) malloc(DATA_LENGTH); memset(data_rd, 0, DATA_LENGTH); @@ -445,7 +445,7 @@ static void i2c_slave_read_write_test() TEST_CASE_MULTIPLE_DEVICES("I2C read and write test", "[i2c][test_env=UT_T2_I2C][timeout=150]", i2c_master_write_read_test, i2c_slave_read_write_test); -static void i2c_master_repeat_write() +static void i2c_master_repeat_write(void) { uint8_t *data_wr = (uint8_t *) malloc(DATA_LENGTH); int times = 3; @@ -471,7 +471,7 @@ static void i2c_master_repeat_write() i2c_driver_delete(I2C_MASTER_NUM); } -static void i2c_slave_repeat_read() +static void i2c_slave_repeat_read(void) { int size_rd = 0; int times = 3; diff --git a/components/driver/test/test_rmt.c b/components/driver/test/test_rmt.c index 7b186b2c5b..a3014401cb 100644 --- a/components/driver/test/test_rmt.c +++ b/components/driver/test/test_rmt.c @@ -262,7 +262,7 @@ static int get_rx_data(RingbufHandle_t rb) /** * @brief RMT transmitter initialization */ -static void tx_init() +static void tx_init(void) { // the sender once it send something, its frq is 38kHz, and the duty cycle is 50% rmt_tx_config_t tx_cfg = { @@ -289,7 +289,7 @@ static void tx_init() /** * @brief RMT receiver initialization */ -static void rx_init() +static void rx_init(void) { rmt_rx_config_t rx_cfg = { .filter_en = true, diff --git a/components/driver/test/test_spi_sio.c b/components/driver/test/test_spi_sio.c index 37d4065df1..cb6964f6b8 100644 --- a/components/driver/test/test_spi_sio.c +++ b/components/driver/test/test_spi_sio.c @@ -154,7 +154,7 @@ void test_sio_master_round(bool test_mosi) master_free_device_bus(spi); } -void test_sio_master() +void test_sio_master(void) { test_sio_master_round(true); unity_send_signal("master ready"); @@ -210,7 +210,7 @@ void test_sio_slave_round(bool test_mosi) spi_slave_free(TEST_SLAVE_HOST); } -void test_sio_slave() +void test_sio_slave(void) { test_sio_slave_round(true); unity_wait_for_signal("master ready"); diff --git a/components/driver/test/test_spi_slave.c b/components/driver/test/test_spi_slave.c index 668b78d29c..c1e913c480 100644 --- a/components/driver/test/test_spi_slave.c +++ b/components/driver/test/test_spi_slave.c @@ -51,7 +51,7 @@ static void master_init_nodma( spi_device_handle_t* spi) TEST_ASSERT(ret==ESP_OK); } -static void slave_init() +static void slave_init(void) { //Configuration for the SPI bus spi_bus_config_t buscfg={ diff --git a/components/driver/test/test_timer.c b/components/driver/test/test_timer.c index 7f1d3c37fb..bc5f3ae750 100644 --- a/components/driver/test/test_timer.c +++ b/components/driver/test/test_timer.c @@ -127,7 +127,7 @@ static void all_timer_init(timer_config_t config, bool flag) } // start all of timer -static void all_timer_start() +static void all_timer_start(void) { esp_err_t ret; ret = timer_start(TIMER_GROUP_0, TIMER_0); @@ -153,7 +153,7 @@ static void all_timer_set_counter_value(uint64_t set_timer_val) TEST_ASSERT(ret == ESP_OK); } -static void all_timer_pause() +static void all_timer_pause(void) { esp_err_t ret; ret = timer_pause(TIMER_GROUP_0, TIMER_0); diff --git a/components/driver/test/test_uart.c b/components/driver/test/test_uart.c index 8ef579c802..0196044032 100644 --- a/components/driver/test/test_uart.c +++ b/components/driver/test/test_uart.c @@ -244,7 +244,7 @@ static uint16_t buffer_fill_random(uint8_t *buffer, size_t length) return crc; } -static void rs485_init() +static void rs485_init(void) { uart_config_t uart_config = { .baud_rate = UART_BAUD_115200, @@ -288,7 +288,7 @@ static esp_err_t print_packet_data(const char *str, uint8_t *buffer, uint16_t bu } // Slave test case for multi device -static void rs485_slave() +static void rs485_slave(void) { rs485_init(); uint8_t* slave_data = (uint8_t*) malloc(BUF_SIZE); @@ -327,7 +327,7 @@ static void rs485_slave() // Master test of multi device test case. // It forms packet with random data, apply generated CRC16 and sends to slave. // If response recieved correctly from slave means RS485 channel works. -static void rs485_master() +static void rs485_master(void) { uint16_t err_count = 0, good_count = 0; rs485_init(); diff --git a/components/driver/uart.c b/components/driver/uart.c index 20306c1287..3367d1d04a 100644 --- a/components/driver/uart.c +++ b/components/driver/uart.c @@ -1484,7 +1484,7 @@ void uart_set_select_notif_callback(uart_port_t uart_num, uart_select_notif_call } } -portMUX_TYPE *uart_get_selectlock() +portMUX_TYPE *uart_get_selectlock(void) { return &uart_selectlock; } diff --git a/components/efuse/include/esp_efuse.h b/components/efuse/include/esp_efuse.h index b2afdbd9a6..0d7ed8373a 100644 --- a/components/efuse/include/esp_efuse.h +++ b/components/efuse/include/esp_efuse.h @@ -322,7 +322,7 @@ void esp_efuse_write_random_key(uint32_t blk_wdata0_reg); /* @brief Return secure_version from efuse field. * @return Secure version from efuse field */ -uint32_t esp_efuse_read_secure_version(); +uint32_t esp_efuse_read_secure_version(void); /* @brief Check secure_version from app and secure_version and from efuse field. * diff --git a/components/efuse/src/esp_efuse_fields.c b/components/efuse/src/esp_efuse_fields.c index 5d440f383b..01ed585d89 100644 --- a/components/efuse/src/esp_efuse_fields.c +++ b/components/efuse/src/esp_efuse_fields.c @@ -130,7 +130,7 @@ void esp_efuse_init(uint32_t offset, uint32_t size) esp_efuse_flash_size = size; } -static uint32_t emulate_secure_version_read() +static uint32_t emulate_secure_version_read(void) { uint32_t secure_version; uint32_t offset = esp_efuse_flash_offset; @@ -170,7 +170,7 @@ static void emulate_secure_version_write(uint32_t secure_version) #define EFUSE_BLK_RD_ANTI_ROLLBACK EFUSE_BLK3_RDATA4_REG #define EFUSE_BLK_WR_ANTI_ROLLBACK EFUSE_BLK3_WDATA4_REG -uint32_t esp_efuse_read_secure_version() +uint32_t esp_efuse_read_secure_version(void) { #ifdef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK uint32_t secure_version; diff --git a/components/efuse/src/esp_efuse_utility.c b/components/efuse/src/esp_efuse_utility.c index 03ea260840..e3154b1881 100644 --- a/components/efuse/src/esp_efuse_utility.c +++ b/components/efuse/src/esp_efuse_utility.c @@ -34,7 +34,7 @@ static const char *TAG = "efuse"; static uint32_t virt_blocks[COUNT_EFUSE_BLOCKS][COUNT_EFUSE_REG_PER_BLOCK]; /* Call the update function to seed virtual efuses during initialization */ -__attribute__((constructor)) void esp_efuse_utility_update_virt_blocks(); +__attribute__((constructor)) void esp_efuse_utility_update_virt_blocks(void); #endif @@ -222,7 +222,7 @@ void esp_efuse_utility_burn_efuses(void) // Erase the virt_blocks array. -void esp_efuse_utility_erase_virt_blocks() +void esp_efuse_utility_erase_virt_blocks(void) { #ifdef CONFIG_EFUSE_VIRTUAL memset(virt_blocks, 0, sizeof(virt_blocks)); @@ -230,7 +230,7 @@ void esp_efuse_utility_erase_virt_blocks() } // Fills the virt_blocks array by values from efuse_Rdata. -void esp_efuse_utility_update_virt_blocks() +void esp_efuse_utility_update_virt_blocks(void) { #ifdef CONFIG_EFUSE_VIRTUAL ESP_LOGI(TAG, "Loading virtual efuse blocks from real efuses"); @@ -247,7 +247,7 @@ void esp_efuse_utility_update_virt_blocks() } // Prints efuse values for all registers. -void esp_efuse_utility_debug_dump_blocks() +void esp_efuse_utility_debug_dump_blocks(void) { printf("EFUSE_BLKx:\n"); #ifdef CONFIG_EFUSE_VIRTUAL @@ -454,7 +454,7 @@ static void read_r_data(esp_efuse_block_t num_block, uint32_t* buf_r_data) // After esp_efuse_write.. functions EFUSE_BLKx_WDATAx_REG were filled is not coded values. // This function reads EFUSE_BLKx_WDATAx_REG registers, applies coding scheme and writes encoded values back to EFUSE_BLKx_WDATAx_REG. -esp_err_t esp_efuse_utility_apply_new_coding_scheme() +esp_err_t esp_efuse_utility_apply_new_coding_scheme(void) { uint8_t buf_w_data[COUNT_EFUSE_REG_PER_BLOCK * 4]; uint8_t buf_r_data[COUNT_EFUSE_REG_PER_BLOCK * 4]; diff --git a/components/efuse/src/esp_efuse_utility.h b/components/efuse/src/esp_efuse_utility.h index 18d8b58860..eadd80e02f 100644 --- a/components/efuse/src/esp_efuse_utility.h +++ b/components/efuse/src/esp_efuse_utility.h @@ -112,17 +112,17 @@ void esp_efuse_utility_reset(void); /** * @brief Fills the virt_blocks array by values from efuse_Rdata. */ -void esp_efuse_utility_update_virt_blocks(); +void esp_efuse_utility_update_virt_blocks(void); /** * @brief Prints efuse values for all registers. */ -void esp_efuse_utility_debug_dump_blocks(); +void esp_efuse_utility_debug_dump_blocks(void); /** * @brief Erase the virt_blocks array. */ -void esp_efuse_utility_erase_virt_blocks(); +void esp_efuse_utility_erase_virt_blocks(void); /** * @brief Apply coding_scheme to write registers. @@ -131,7 +131,7 @@ void esp_efuse_utility_erase_virt_blocks(); * - ESP_OK: The operation was successfully completed. * - ESP_ERR_CODING: Error range of data does not match the coding scheme. */ -esp_err_t esp_efuse_utility_apply_new_coding_scheme(); +esp_err_t esp_efuse_utility_apply_new_coding_scheme(void); #ifdef __cplusplus } diff --git a/components/esp-tls/esp_tls.c b/components/esp-tls/esp_tls.c index 65cd789f39..cd9bd02575 100644 --- a/components/esp-tls/esp_tls.c +++ b/components/esp-tls/esp_tls.c @@ -158,7 +158,7 @@ err_freeaddr: return ret; } -esp_err_t esp_tls_init_global_ca_store() +esp_err_t esp_tls_init_global_ca_store(void) { if (global_cacert == NULL) { global_cacert = (mbedtls_x509_crt *)calloc(1, sizeof(mbedtls_x509_crt)); @@ -197,12 +197,12 @@ esp_err_t esp_tls_set_global_ca_store(const unsigned char *cacert_pem_buf, const return ESP_OK; } -mbedtls_x509_crt *esp_tls_get_global_ca_store() +mbedtls_x509_crt *esp_tls_get_global_ca_store(void) { return global_cacert; } -void esp_tls_free_global_ca_store() +void esp_tls_free_global_ca_store(void) { if (global_cacert) { mbedtls_x509_crt_free(global_cacert); @@ -797,7 +797,7 @@ void esp_tls_server_session_delete(esp_tls_t *tls) }; #endif /* ! CONFIG_ESP_TLS_SERVER */ -esp_tls_t *esp_tls_init() +esp_tls_t *esp_tls_init(void) { esp_tls_t *tls = (esp_tls_t *)calloc(1, sizeof(esp_tls_t)); if (!tls) { diff --git a/components/esp-tls/esp_tls.h b/components/esp-tls/esp_tls.h index 1c2f785ea5..0c4caabaa4 100644 --- a/components/esp-tls/esp_tls.h +++ b/components/esp-tls/esp_tls.h @@ -229,7 +229,7 @@ typedef struct esp_tls { * @return tls Pointer to esp-tls as esp-tls handle if successfully initialized, * NULL if allocation error */ -esp_tls_t *esp_tls_init(); +esp_tls_t *esp_tls_init(void); @@ -402,7 +402,7 @@ ssize_t esp_tls_get_bytes_avail(esp_tls_t *tls); * - ESP_OK if creating global CA store was successful. * - ESP_ERR_NO_MEM if an error occured when allocating the mbedTLS resources. */ -esp_err_t esp_tls_init_global_ca_store(); +esp_err_t esp_tls_init_global_ca_store(void); /** * @brief Set the global CA store with the buffer provided in pem format. @@ -435,7 +435,7 @@ esp_err_t esp_tls_set_global_ca_store(const unsigned char *cacert_pem_buf, const * - Pointer to the global CA store currently being used if successful. * - NULL if there is no global CA store set. */ -mbedtls_x509_crt *esp_tls_get_global_ca_store(); +mbedtls_x509_crt *esp_tls_get_global_ca_store(void); /** * @brief Free the global CA store currently being used. @@ -443,7 +443,7 @@ mbedtls_x509_crt *esp_tls_get_global_ca_store(); * The memory being used by the global CA store to store all the parsed certificates is * freed up. The application can call this API if it no longer needs the global CA store. */ -void esp_tls_free_global_ca_store(); +void esp_tls_free_global_ca_store(void); /** * @brief Returns last error in esp_tls with detailed mbedtls related error codes. diff --git a/components/esp32/brownout.c b/components/esp32/brownout.c index 35589330fb..89f821c503 100644 --- a/components/esp32/brownout.c +++ b/components/esp32/brownout.c @@ -31,7 +31,7 @@ #define BROWNOUT_DET_LVL 0 #endif //CONFIG_ESP32_BROWNOUT_DET_LVL -static void rtc_brownout_isr_handler() +static void rtc_brownout_isr_handler(void) { /* Normally RTC ISR clears the interrupt flag after the application-supplied * handler returns. Since restart is called here, the flag needs to be @@ -47,7 +47,7 @@ static void rtc_brownout_isr_handler() esp_restart_noos(); } -void esp_brownout_init() +void esp_brownout_init(void) { REG_WRITE(RTC_CNTL_BROWN_OUT_REG, RTC_CNTL_BROWN_OUT_ENA /* Enable BOD */ diff --git a/components/esp32/cache_err_int.c b/components/esp32/cache_err_int.c index 079812023e..30b294848a 100644 --- a/components/esp32/cache_err_int.c +++ b/components/esp32/cache_err_int.c @@ -30,7 +30,7 @@ #include "soc/dport_reg.h" #include "sdkconfig.h" -void esp_cache_err_int_init() +void esp_cache_err_int_init(void) { uint32_t core_id = xPortGetCoreID(); ESP_INTR_DISABLE(ETS_CACHEERR_INUM); @@ -70,7 +70,7 @@ void esp_cache_err_int_init() ESP_INTR_ENABLE(ETS_CACHEERR_INUM); } -int IRAM_ATTR esp_cache_err_get_cpuid() +int IRAM_ATTR esp_cache_err_get_cpuid(void) { esp_dport_access_int_pause(); const uint32_t pro_mask = diff --git a/components/esp32/clk.c b/components/esp32/clk.c index 69f6057b42..fd5c477618 100644 --- a/components/esp32/clk.c +++ b/components/esp32/clk.c @@ -210,7 +210,7 @@ static void select_rtc_slow_clk(slow_clk_sel_t slow_clk) esp_clk_slowclk_cal_set(cal_val); } -void rtc_clk_select_rtc_slow_clk() +void rtc_clk_select_rtc_slow_clk(void) { select_rtc_slow_clk(RTC_SLOW_FREQ_32K_XTAL); } diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index f93e4cdf00..1dfa5c2466 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -79,7 +79,7 @@ void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))) __attribute__((noreturn)); void start_cpu0_default(void) IRAM_ATTR __attribute__((noreturn)); #if !CONFIG_FREERTOS_UNICORE -static void IRAM_ATTR call_start_cpu1() __attribute__((noreturn)); +static void IRAM_ATTR call_start_cpu1(void) __attribute__((noreturn)); void start_cpu1(void) __attribute__((weak, alias("start_cpu1_default"))) __attribute__((noreturn)); void start_cpu1_default(void) IRAM_ATTR __attribute__((noreturn)); static bool app_cpu_started = false; @@ -117,7 +117,7 @@ static bool s_spiram_okay=true; * and the app CPU is in reset. We do have a stack, so we can do the initialization in C. */ -void IRAM_ATTR call_start_cpu0() +void IRAM_ATTR call_start_cpu0(void) { #if CONFIG_FREERTOS_UNICORE RESET_REASON rst_reas[1]; @@ -277,7 +277,7 @@ static void wdt_reset_cpu1_info_enable(void) DPORT_REG_CLR_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_RECORD_ENABLE); } -void IRAM_ATTR call_start_cpu1() +void IRAM_ATTR call_start_cpu1(void) { asm volatile (\ "wsr %0, vecbase\n" \ @@ -484,7 +484,7 @@ void start_cpu1_default(void) #endif //!CONFIG_FREERTOS_UNICORE #ifdef CONFIG_COMPILER_CXX_EXCEPTIONS -size_t __cxx_eh_arena_size_get() +size_t __cxx_eh_arena_size_get(void) { return CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE; } diff --git a/components/esp32/crosscore_int.c b/components/esp32/crosscore_int.c index 746060e446..24bb3fb26a 100644 --- a/components/esp32/crosscore_int.c +++ b/components/esp32/crosscore_int.c @@ -43,7 +43,7 @@ static volatile uint32_t reason[ portNUM_PROCESSORS ]; ToDo: There is a small chance the CPU already has yielded when this ISR is serviced. In that case, it's running the intended task but the ISR will cause it to switch _away_ from it. portYIELD_FROM_ISR will probably just schedule the task again, but have to check that. */ -static inline void IRAM_ATTR esp_crosscore_isr_handle_yield() +static inline void IRAM_ATTR esp_crosscore_isr_handle_yield(void) { portYIELD_FROM_ISR(); } @@ -79,7 +79,7 @@ static void IRAM_ATTR esp_crosscore_isr(void *arg) { //Initialize the crosscore interrupt on this core. Call this once //on each active core. -void esp_crosscore_int_init() { +void esp_crosscore_int_init(void) { portENTER_CRITICAL(&reason_spinlock); reason[xPortGetCoreID()]=0; portEXIT_CRITICAL(&reason_spinlock); diff --git a/components/esp32/esp_clk_internal.h b/components/esp32/esp_clk_internal.h index 53af81c284..f1f8964573 100644 --- a/components/esp32/esp_clk_internal.h +++ b/components/esp32/esp_clk_internal.h @@ -41,4 +41,4 @@ void esp_perip_clk_init(void); /* Selects an external clock source (32 kHz) for RTC. * Only internal use in unit test. */ -void rtc_clk_select_rtc_slow_clk(); +void rtc_clk_select_rtc_slow_clk(void); diff --git a/components/esp32/esp_himem.c b/components/esp32/esp_himem.c index 7053af341b..c9c6a2631f 100644 --- a/components/esp32/esp_himem.c +++ b/components/esp32/esp_himem.c @@ -117,13 +117,13 @@ static void set_bank(int virt_bank, int phys_bank, int ct) assert(r == 0); } -size_t esp_himem_get_phys_size() +size_t esp_himem_get_phys_size(void) { int paddr_start = (4096 * 1024) - (CACHE_BLOCKSIZE * SPIRAM_BANKSWITCH_RESERVE); return esp_spiram_get_size()-paddr_start; } -size_t esp_himem_get_free_size() +size_t esp_himem_get_free_size(void) { size_t ret=0; for (int i = 0; i < s_ramblockcnt; i++) { @@ -132,12 +132,12 @@ size_t esp_himem_get_free_size() return ret; } -size_t esp_himem_reserved_area_size() { +size_t esp_himem_reserved_area_size(void) { return CACHE_BLOCKSIZE * SPIRAM_BANKSWITCH_RESERVE; } -void __attribute__((constructor)) esp_himem_init() +void __attribute__((constructor)) esp_himem_init(void) { if (SPIRAM_BANKSWITCH_RESERVE == 0) return; int maxram=esp_spiram_get_size(); diff --git a/components/esp32/esp_timer_esp32.c b/components/esp32/esp_timer_esp32.c index cac4b819be..541ddc7401 100644 --- a/components/esp32/esp_timer_esp32.c +++ b/components/esp32/esp_timer_esp32.c @@ -150,7 +150,7 @@ portMUX_TYPE s_time_update_lock = portMUX_INITIALIZER_UNLOCKED; #define TIMER_IS_AFTER_OVERFLOW(a) (ALARM_OVERFLOW_VAL < (a) && (a) <= FRC_TIMER_LOAD_VALUE(1)) // Check if timer overflow has happened (but was not handled by ISR yet) -static inline bool IRAM_ATTR timer_overflow_happened() +static inline bool IRAM_ATTR timer_overflow_happened(void) { if (s_overflow_happened) { return true; @@ -176,17 +176,17 @@ static inline void IRAM_ATTR timer_count_reload(void) REG_WRITE(FRC_TIMER_LOAD_REG(1), REG_READ(FRC_TIMER_COUNT_REG(1)) - ALARM_OVERFLOW_VAL); } -void esp_timer_impl_lock() +void esp_timer_impl_lock(void) { portENTER_CRITICAL(&s_time_update_lock); } -void esp_timer_impl_unlock() +void esp_timer_impl_unlock(void) { portEXIT_CRITICAL(&s_time_update_lock); } -uint64_t IRAM_ATTR esp_timer_impl_get_time() +uint64_t IRAM_ATTR esp_timer_impl_get_time(void) { uint32_t timer_val; uint64_t time_base; @@ -371,7 +371,7 @@ esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler) return ESP_OK; } -void esp_timer_impl_deinit() +void esp_timer_impl_deinit(void) { esp_intr_disable(s_timer_interrupt_handle); @@ -386,13 +386,13 @@ void esp_timer_impl_deinit() // FIXME: This value is safe for 80MHz APB frequency. // Should be modified to depend on clock frequency. -uint64_t IRAM_ATTR esp_timer_impl_get_min_period_us() +uint64_t IRAM_ATTR esp_timer_impl_get_min_period_us(void) { return 50; } #ifdef ESP_TIMER_DYNAMIC_OVERFLOW_VAL -uint32_t esp_timer_impl_get_overflow_val() +uint32_t esp_timer_impl_get_overflow_val(void) { return s_alarm_overflow_val; } diff --git a/components/esp32/include/esp32/brownout.h b/components/esp32/include/esp32/brownout.h index 5a0b1aec00..dafba8dd79 100644 --- a/components/esp32/include/esp32/brownout.h +++ b/components/esp32/include/esp32/brownout.h @@ -16,6 +16,6 @@ #ifndef __ESP_BROWNOUT_H #define __ESP_BROWNOUT_H -void esp_brownout_init(); +void esp_brownout_init(void); #endif \ No newline at end of file diff --git a/components/esp32/include/esp32/cache_err_int.h b/components/esp32/include/esp32/cache_err_int.h index bcbd63e799..8881291a2d 100644 --- a/components/esp32/include/esp32/cache_err_int.h +++ b/components/esp32/include/esp32/cache_err_int.h @@ -20,7 +20,7 @@ * to interrupt input number ETS_CACHEERR_INUM (see soc/soc.h). It is called * from the startup code. */ -void esp_cache_err_int_init(); +void esp_cache_err_int_init(void); /** @@ -30,4 +30,4 @@ void esp_cache_err_int_init(); * - APP_CPU_NUM, if APP_CPU has caused cache IA interrupt * - (-1) otherwise */ -int esp_cache_err_get_cpuid(); +int esp_cache_err_get_cpuid(void); diff --git a/components/esp32/include/esp32/clk.h b/components/esp32/include/esp32/clk.h index 9393fc1f5d..4e32fd16eb 100644 --- a/components/esp32/include/esp32/clk.h +++ b/components/esp32/include/esp32/clk.h @@ -29,7 +29,7 @@ * * @return the calibration value obtained using rtc_clk_cal, at startup time */ -uint32_t esp_clk_slowclk_cal_get(); +uint32_t esp_clk_slowclk_cal_get(void); /** * @brief Update the calibration value of RTC slow clock @@ -84,4 +84,4 @@ int esp_clk_xtal_freq(void); * * @return Value or RTC counter, expressed in microseconds */ -uint64_t esp_clk_rtc_time(); +uint64_t esp_clk_rtc_time(void); diff --git a/components/esp32/include/esp32/himem.h b/components/esp32/include/esp32/himem.h index 099d926015..0297725a19 100644 --- a/components/esp32/include/esp32/himem.h +++ b/components/esp32/include/esp32/himem.h @@ -125,14 +125,14 @@ esp_err_t esp_himem_unmap(esp_himem_rangehandle_t range, void *ptr, size_t len); * * @returns Amount of memory, in bytes */ -size_t esp_himem_get_phys_size(); +size_t esp_himem_get_phys_size(void); /** * @brief Get free amount of memory under control of himem API * * @returns Amount of free memory, in bytes */ -size_t esp_himem_get_free_size(); +size_t esp_himem_get_free_size(void); /** @@ -143,7 +143,7 @@ size_t esp_himem_get_free_size(); * * @returns Amount of reserved area, in bytes */ -size_t esp_himem_reserved_area_size(); +size_t esp_himem_reserved_area_size(void); #ifdef __cplusplus diff --git a/components/esp32/include/esp32/spiram.h b/components/esp32/include/esp32/spiram.h index a55872cd4d..ccbca2c0b8 100644 --- a/components/esp32/include/esp32/spiram.h +++ b/components/esp32/include/esp32/spiram.h @@ -34,14 +34,14 @@ typedef enum { * - ESP_SPIRAM_SIZE_INVALID if SPI RAM not enabled or not valid * - SPI RAM size */ -esp_spiram_size_t esp_spiram_get_chip_size(); +esp_spiram_size_t esp_spiram_get_chip_size(void); /** * @brief Initialize spiram interface/hardware. Normally called from cpu_start.c. * * @return ESP_OK on success */ -esp_err_t esp_spiram_init(); +esp_err_t esp_spiram_init(void); /** * @brief Configure Cache/MMU for access to external SPI RAM. @@ -52,7 +52,7 @@ esp_err_t esp_spiram_init(); * * @attention this function must be called with flash cache disabled. */ -void esp_spiram_init_cache(); +void esp_spiram_init_cache(void); /** @@ -63,13 +63,13 @@ void esp_spiram_init_cache(); * * @return true on success, false on failed memory test */ -bool esp_spiram_test(); +bool esp_spiram_test(void); /** * @brief Add the initialized SPI RAM to the heap allocator. */ -esp_err_t esp_spiram_add_to_heapalloc(); +esp_err_t esp_spiram_add_to_heapalloc(void); /** @@ -77,7 +77,7 @@ esp_err_t esp_spiram_add_to_heapalloc(); * * @return Size in bytes, or 0 if no external RAM chip support compiled in. */ -size_t esp_spiram_get_size(); +size_t esp_spiram_get_size(void); /** @@ -87,7 +87,7 @@ size_t esp_spiram_get_size(); * * This is meant for use from within the SPI flash code. */ -void esp_spiram_writeback_cache(); +void esp_spiram_writeback_cache(void); diff --git a/components/esp32/include/esp_intr_alloc.h b/components/esp32/include/esp_intr_alloc.h index d6893a07a2..cafc178bfc 100644 --- a/components/esp32/include/esp_intr_alloc.h +++ b/components/esp32/include/esp_intr_alloc.h @@ -282,13 +282,13 @@ esp_err_t esp_intr_set_in_iram(intr_handle_t handle, bool is_in_iram); /** * @brief Disable interrupts that aren't specifically marked as running from IRAM */ -void esp_intr_noniram_disable(); +void esp_intr_noniram_disable(void); /** * @brief Re-enable interrupts disabled by esp_intr_noniram_disable */ -void esp_intr_noniram_enable(); +void esp_intr_noniram_enable(void); /**@}*/ diff --git a/components/esp32/include/esp_sleep.h b/components/esp32/include/esp_sleep.h index 7791de6f79..7101bda078 100644 --- a/components/esp32/include/esp_sleep.h +++ b/components/esp32/include/esp_sleep.h @@ -98,7 +98,7 @@ esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source); * - ESP_ERR_NOT_SUPPORTED if additional current by touch (CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT) is enabled. * - ESP_ERR_INVALID_STATE if ULP co-processor is not enabled or if wakeup triggers conflict */ -esp_err_t esp_sleep_enable_ulp_wakeup(); +esp_err_t esp_sleep_enable_ulp_wakeup(void); /** * @brief Enable wakeup by timer @@ -125,7 +125,7 @@ esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us); * - ESP_ERR_NOT_SUPPORTED if additional current by touch (CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT) is enabled. * - ESP_ERR_INVALID_STATE if wakeup triggers conflict */ -esp_err_t esp_sleep_enable_touchpad_wakeup(); +esp_err_t esp_sleep_enable_touchpad_wakeup(void); /** * @brief Get the touch pad which caused wakeup @@ -134,7 +134,7 @@ esp_err_t esp_sleep_enable_touchpad_wakeup(); * * @return touch pad which caused wakeup */ -touch_pad_t esp_sleep_get_touchpad_wakeup_status(); +touch_pad_t esp_sleep_get_touchpad_wakeup_status(void); /** * @brief Enable wakeup using a pin @@ -213,7 +213,7 @@ esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t mask, esp_sleep_ext1_wakeup_mode * - ESP_OK on success * - ESP_ERR_INVALID_STATE if wakeup triggers conflict */ -esp_err_t esp_sleep_enable_gpio_wakeup(); +esp_err_t esp_sleep_enable_gpio_wakeup(void); /** * @brief Enable wakeup from light sleep using UART @@ -239,7 +239,7 @@ esp_err_t esp_sleep_enable_uart_wakeup(int uart_num); * * @return bit mask, if GPIOn caused wakeup, BIT(n) will be set */ -uint64_t esp_sleep_get_ext1_wakeup_status(); +uint64_t esp_sleep_get_ext1_wakeup_status(void); /** * @brief Set power down mode for an RTC power domain in sleep mode @@ -260,7 +260,7 @@ esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain, * * This function does not return. */ -void esp_deep_sleep_start() __attribute__((noreturn)); +void esp_deep_sleep_start(void) __attribute__((noreturn)); /** * @brief Enter light sleep with the configured wakeup options @@ -269,7 +269,7 @@ void esp_deep_sleep_start() __attribute__((noreturn)); * - ESP_OK on success (returned after wakeup) * - ESP_ERR_INVALID_STATE if WiFi or BT is not stopped */ -esp_err_t esp_light_sleep_start(); +esp_err_t esp_light_sleep_start(void); /** * @brief Enter deep-sleep mode @@ -311,7 +311,7 @@ void system_deep_sleep(uint64_t time_in_us) __attribute__((noreturn, deprecated) * * @return cause of wake up from last sleep (deep sleep or light sleep) */ -esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(); +esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(void); /** diff --git a/components/esp32/int_wdt.c b/components/esp32/int_wdt.c index f42b987739..8f18f7157e 100644 --- a/components/esp32/int_wdt.c +++ b/components/esp32/int_wdt.c @@ -69,7 +69,7 @@ static void IRAM_ATTR tick_hook(void) { #endif -void esp_int_wdt_init() { +void esp_int_wdt_init(void) { periph_module_enable(PERIPH_TIMG1_MODULE); TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; TIMERG1.wdt_config0.sys_reset_length=7; //3.2uS @@ -89,7 +89,7 @@ void esp_int_wdt_init() { timer_group_intr_enable(TIMER_GROUP_1, TIMG_WDT_INT_ENA_M); } -void esp_int_wdt_cpu_init() +void esp_int_wdt_cpu_init(void) { esp_register_freertos_tick_hook_for_cpu(tick_hook, xPortGetCoreID()); ESP_INTR_DISABLE(WDT_INT_NUM); diff --git a/components/esp32/intr_alloc.c b/components/esp32/intr_alloc.c index b74c4f9293..6256f6a8be 100644 --- a/components/esp32/intr_alloc.c +++ b/components/esp32/intr_alloc.c @@ -854,7 +854,7 @@ esp_err_t IRAM_ATTR esp_intr_disable(intr_handle_t handle) } -void IRAM_ATTR esp_intr_noniram_disable() +void IRAM_ATTR esp_intr_noniram_disable(void) { int oldint; int cpu=xPortGetCoreID(); @@ -873,7 +873,7 @@ void IRAM_ATTR esp_intr_noniram_disable() non_iram_int_disabled[cpu]=oldint&non_iram_int_mask[cpu]; } -void IRAM_ATTR esp_intr_noniram_enable() +void IRAM_ATTR esp_intr_noniram_enable(void) { int cpu=xPortGetCoreID(); int intmask=non_iram_int_disabled[cpu]; diff --git a/components/esp32/panic.c b/components/esp32/panic.c index e7ed6540e2..4a104f0290 100644 --- a/components/esp32/panic.c +++ b/components/esp32/panic.c @@ -139,7 +139,7 @@ esp_reset_reason_t __attribute__((weak)) esp_reset_reason_get_hint(void) static bool abort_called; -static __attribute__((noreturn)) inline void invoke_abort() +static __attribute__((noreturn)) inline void invoke_abort(void) { abort_called = true; #if CONFIG_ESP32_APPTRACE_ENABLE @@ -158,7 +158,7 @@ static __attribute__((noreturn)) inline void invoke_abort() } } -void abort() +void abort(void) { #if !CONFIG_ESP32_PANIC_SILENT_REBOOT ets_printf("abort() was called at PC 0x%08x on core %d\r\n", (intptr_t)__builtin_return_address(0) - 3, xPortGetCoreID()); @@ -189,12 +189,12 @@ static const char *edesc[] = { #define NUM_EDESCS (sizeof(edesc) / sizeof(char *)) static void commonErrorHandler(XtExcFrame *frame); -static inline void disableAllWdts(); +static inline void disableAllWdts(void); static void illegal_instruction_helper(XtExcFrame *frame); //The fact that we've panic'ed probably means the other CPU is now running wild, possibly //messing up the serial output, so we stall it here. -static void haltOtherCore() +static void haltOtherCore(void) { esp_cpu_stall( xPortGetCoreID() == 0 ? 1 : 0 ); } @@ -399,7 +399,7 @@ static void illegal_instruction_helper(XtExcFrame *frame) all watchdogs except the timer group 0 watchdog, and it reconfigures that to reset the chip after one second. */ -static void reconfigureAllWdts() +static void reconfigureAllWdts(void) { TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE; TIMERG0.wdt_feed = 1; @@ -419,7 +419,7 @@ static void reconfigureAllWdts() /* This disables all the watchdogs for when we call the gdbstub. */ -static inline void disableAllWdts() +static inline void disableAllWdts(void) { TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE; TIMERG0.wdt_config0.en = 0; @@ -429,9 +429,9 @@ static inline void disableAllWdts() TIMERG1.wdt_wprotect = 0; } -static void esp_panic_dig_reset() __attribute__((noreturn)); +static void esp_panic_dig_reset(void) __attribute__((noreturn)); -static void esp_panic_dig_reset() +static void esp_panic_dig_reset(void) { // make sure all the panic handler output is sent from UART FIFO uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); diff --git a/components/esp32/pm_esp32.c b/components/esp32/pm_esp32.c index 746a1ca400..f1b29189ad 100644 --- a/components/esp32/pm_esp32.c +++ b/components/esp32/pm_esp32.c @@ -145,9 +145,9 @@ static const char* s_mode_names[] = { static const char* TAG = "pm_esp32"; -static void update_ccompare(); +static void update_ccompare(void); static void do_switch(pm_mode_t new_mode); -static void leave_idle(); +static void leave_idle(void); static void on_freq_update(uint32_t old_ticks_per_us, uint32_t ticks_per_us); @@ -246,7 +246,7 @@ esp_err_t esp_pm_configure(const void* vconfig) return ESP_OK; } -static pm_mode_t IRAM_ATTR get_lowest_allowed_mode() +static pm_mode_t IRAM_ATTR get_lowest_allowed_mode(void) { /* TODO: optimize using ffs/clz */ if (s_mode_mask >= BIT(PM_MODE_CPU_MAX)) { @@ -418,7 +418,7 @@ static void IRAM_ATTR do_switch(pm_mode_t new_mode) * would happen without the frequency change. * Assumes that the new_frequency = old_frequency * s_ccount_mul / s_ccount_div. */ -static void IRAM_ATTR update_ccompare() +static void IRAM_ATTR update_ccompare(void) { uint32_t ccount = XTHAL_GET_CCOUNT(); uint32_t ccompare = XTHAL_GET_CCOMPARE(XT_TIMER_INDEX); @@ -432,7 +432,7 @@ static void IRAM_ATTR update_ccompare() } } -static void IRAM_ATTR leave_idle() +static void IRAM_ATTR leave_idle(void) { int core_id = xPortGetCoreID(); if (s_core_idle[core_id]) { @@ -442,7 +442,7 @@ static void IRAM_ATTR leave_idle() } } -void esp_pm_impl_idle_hook() +void esp_pm_impl_idle_hook(void) { int core_id = xPortGetCoreID(); uint32_t state = portENTER_CRITICAL_NESTED(); @@ -454,7 +454,7 @@ void esp_pm_impl_idle_hook() ESP_PM_TRACE_ENTER(IDLE, core_id); } -void IRAM_ATTR esp_pm_impl_isr_hook() +void IRAM_ATTR esp_pm_impl_isr_hook(void) { int core_id = xPortGetCoreID(); ESP_PM_TRACE_ENTER(ISR_HOOK, core_id); @@ -476,7 +476,7 @@ void IRAM_ATTR esp_pm_impl_isr_hook() ESP_PM_TRACE_EXIT(ISR_HOOK, core_id); } -void esp_pm_impl_waiti() +void esp_pm_impl_waiti(void) { #if CONFIG_FREERTOS_USE_TICKLESS_IDLE int core_id = xPortGetCoreID(); @@ -595,7 +595,7 @@ void esp_pm_impl_dump_stats(FILE* out) } #endif // WITH_PROFILING -void esp_pm_impl_init() +void esp_pm_impl_init(void) { #ifdef CONFIG_PM_TRACE esp_pm_trace_init(); diff --git a/components/esp32/pm_trace.c b/components/esp32/pm_trace.c index 02a636211b..5cdb666d67 100644 --- a/components/esp32/pm_trace.c +++ b/components/esp32/pm_trace.c @@ -29,7 +29,7 @@ static const int DRAM_ATTR s_trace_io[] = { BIT(27), BIT(27), // ESP_PM_TRACE_SLEEP }; -void esp_pm_trace_init() +void esp_pm_trace_init(void) { for (size_t i = 0; i < sizeof(s_trace_io)/sizeof(s_trace_io[0]); ++i) { int io = __builtin_ffs(s_trace_io[i]); diff --git a/components/esp32/reset_reason.c b/components/esp32/reset_reason.c index 0b291b12cc..a0667b6c19 100644 --- a/components/esp32/reset_reason.c +++ b/components/esp32/reset_reason.c @@ -17,7 +17,7 @@ #include "esp_private/system_internal.h" #include "soc/rtc_periph.h" -static void esp_reset_reason_clear_hint(); +static void esp_reset_reason_clear_hint(void); static esp_reset_reason_t s_reset_reason; @@ -119,7 +119,7 @@ esp_reset_reason_t IRAM_ATTR esp_reset_reason_get_hint(void) } return (esp_reset_reason_t) low; } -static void esp_reset_reason_clear_hint() +static void esp_reset_reason_clear_hint(void) { REG_WRITE(RTC_RESET_CAUSE_REG, 0); } diff --git a/components/esp32/sleep_modes.c b/components/esp32/sleep_modes.c index 04179d3791..6e60119893 100644 --- a/components/esp32/sleep_modes.c +++ b/components/esp32/sleep_modes.c @@ -89,10 +89,10 @@ static _lock_t lock_rtc_memory_crc; static const char* TAG = "sleep"; -static uint32_t get_power_down_flags(); -static void ext0_wakeup_prepare(); -static void ext1_wakeup_prepare(); -static void timer_wakeup_prepare(); +static uint32_t get_power_down_flags(void); +static void ext0_wakeup_prepare(void); +static void ext1_wakeup_prepare(void); +static void timer_wakeup_prepare(void); /* Wake from deep sleep stub See esp_deepsleep.h esp_wake_deep_sleep() comments for details. @@ -148,14 +148,14 @@ void esp_deep_sleep(uint64_t time_in_us) esp_deep_sleep_start(); } -static void IRAM_ATTR flush_uarts() +static void IRAM_ATTR flush_uarts(void) { for (int i = 0; i < 3; ++i) { uart_tx_wait_idle(i); } } -static void IRAM_ATTR suspend_uarts() +static void IRAM_ATTR suspend_uarts(void) { for (int i = 0; i < 3; ++i) { REG_SET_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XOFF); @@ -165,7 +165,7 @@ static void IRAM_ATTR suspend_uarts() } } -static void IRAM_ATTR resume_uarts() +static void IRAM_ATTR resume_uarts(void) { for (int i = 0; i < 3; ++i) { REG_CLR_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XOFF); @@ -222,7 +222,7 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags) return result; } -void IRAM_ATTR esp_deep_sleep_start() +void IRAM_ATTR esp_deep_sleep_start(void) { // record current RTC time s_config.rtc_ticks_at_sleep_start = rtc_time_get(); @@ -277,7 +277,7 @@ static esp_err_t esp_light_sleep_inner(uint32_t pd_flags, return err; } -esp_err_t esp_light_sleep_start() +esp_err_t esp_light_sleep_start(void) { static portMUX_TYPE light_sleep_lock = portMUX_INITIALIZER_UNLOCKED; portENTER_CRITICAL(&light_sleep_lock); @@ -399,7 +399,7 @@ esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source) return ESP_OK; } -esp_err_t esp_sleep_enable_ulp_wakeup() +esp_err_t esp_sleep_enable_ulp_wakeup(void) { #ifdef CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT return ESP_ERR_NOT_SUPPORTED; @@ -423,7 +423,7 @@ esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us) return ESP_OK; } -static void timer_wakeup_prepare() +static void timer_wakeup_prepare(void) { uint32_t period = esp_clk_slowclk_cal_get(); int64_t sleep_duration = (int64_t) s_config.sleep_duration - (int64_t) s_config.sleep_time_adjustment; @@ -435,7 +435,7 @@ static void timer_wakeup_prepare() rtc_sleep_set_wakeup_time(s_config.rtc_ticks_at_sleep_start + rtc_count_delta); } -esp_err_t esp_sleep_enable_touchpad_wakeup() +esp_err_t esp_sleep_enable_touchpad_wakeup(void) { #ifdef CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT return ESP_ERR_NOT_SUPPORTED; @@ -448,7 +448,7 @@ esp_err_t esp_sleep_enable_touchpad_wakeup() return ESP_OK; } -touch_pad_t esp_sleep_get_touchpad_wakeup_status() +touch_pad_t esp_sleep_get_touchpad_wakeup_status(void) { if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_TOUCHPAD) { return TOUCH_PAD_MAX; @@ -477,7 +477,7 @@ esp_err_t esp_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level) return ESP_OK; } -static void ext0_wakeup_prepare() +static void ext0_wakeup_prepare(void) { int rtc_gpio_num = s_config.ext0_rtc_gpio_num; // Set GPIO to be used for wakeup @@ -520,7 +520,7 @@ esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t mask, esp_sleep_ext1_wakeup_mode return ESP_OK; } -static void ext1_wakeup_prepare() +static void ext1_wakeup_prepare(void) { // Configure all RTC IOs selected as ext1 wakeup inputs uint32_t rtc_gpio_mask = s_config.ext1_rtc_gpio_mask; @@ -556,7 +556,7 @@ static void ext1_wakeup_prepare() s_config.ext1_trigger_mode, RTC_CNTL_EXT_WAKEUP1_LV_S); } -uint64_t esp_sleep_get_ext1_wakeup_status() +uint64_t esp_sleep_get_ext1_wakeup_status(void) { if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_EXT1) { return 0; @@ -577,7 +577,7 @@ uint64_t esp_sleep_get_ext1_wakeup_status() return gpio_mask; } -esp_err_t esp_sleep_enable_gpio_wakeup() +esp_err_t esp_sleep_enable_gpio_wakeup(void) { if (s_config.wakeup_triggers & (RTC_TOUCH_TRIG_EN | RTC_ULP_TRIG_EN)) { ESP_LOGE(TAG, "Conflicting wake-up triggers: touch / ULP"); @@ -600,7 +600,7 @@ esp_err_t esp_sleep_enable_uart_wakeup(int uart_num) return ESP_OK; } -esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause() +esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(void) { if (rtc_get_reset_reason(0) != DEEPSLEEP_RESET && !s_light_sleep_wakeup) { return ESP_SLEEP_WAKEUP_UNDEFINED; @@ -636,7 +636,7 @@ esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain, return ESP_OK; } -static uint32_t get_power_down_flags() +static uint32_t get_power_down_flags(void) { // Where needed, convert AUTO options to ON. Later interpret AUTO as OFF. diff --git a/components/esp32/spiram.c b/components/esp32/spiram.c index fc4a9a619f..37ae07e2c0 100644 --- a/components/esp32/spiram.c +++ b/components/esp32/spiram.c @@ -69,12 +69,12 @@ static bool spiram_inited=false; //If no function in esp_himem.c is used, this function will be linked into the //binary instead of the one in esp_himem.c, automatically making sure no memory //is reserved if no himem function is used. -size_t __attribute__((weak)) esp_himem_reserved_area_size() { +size_t __attribute__((weak)) esp_himem_reserved_area_size(void) { return 0; } -static int spiram_size_usable_for_malloc() +static int spiram_size_usable_for_malloc(void) { int s=esp_spiram_get_size(); if (s>4*1024*1024) s=4*1024*1024; //we can map at most 4MiB @@ -87,7 +87,7 @@ static int spiram_size_usable_for_malloc() true when RAM seems OK, false when test fails. WARNING: Do not run this before the 2nd cpu has been initialized (in a two-core system) or after the heap allocator has taken ownership of the memory. */ -bool esp_spiram_test() +bool esp_spiram_test(void) { volatile int *spiram=(volatile int*)SOC_EXTRAM_DATA_LOW; size_t p; @@ -112,7 +112,7 @@ bool esp_spiram_test() } } -void IRAM_ATTR esp_spiram_init_cache() +void IRAM_ATTR esp_spiram_init_cache(void) { //Enable external RAM in MMU cache_sram_mmu_set( 0, 0, SOC_EXTRAM_DATA_LOW, 0, 32, 128 ); @@ -123,7 +123,7 @@ void IRAM_ATTR esp_spiram_init_cache() #endif } -esp_spiram_size_t esp_spiram_get_chip_size() +esp_spiram_size_t esp_spiram_get_chip_size(void) { if (!spiram_inited) { ESP_EARLY_LOGE(TAG, "SPI RAM not initialized"); @@ -142,7 +142,7 @@ esp_spiram_size_t esp_spiram_get_chip_size() } } -esp_err_t esp_spiram_init() +esp_err_t esp_spiram_init(void) { esp_err_t r; r = psram_enable(PSRAM_SPEED, PSRAM_MODE); @@ -174,7 +174,7 @@ esp_err_t esp_spiram_init() } -esp_err_t esp_spiram_add_to_heapalloc() +esp_err_t esp_spiram_add_to_heapalloc(void) { //Add entire external RAM region to heap allocator. Heap allocator knows the capabilities of this type of memory, so there's //no need to explicitly specify them. @@ -213,7 +213,7 @@ esp_err_t esp_spiram_reserve_dma_pool(size_t size) { return ESP_OK; } -size_t esp_spiram_get_size() +size_t esp_spiram_get_size(void) { psram_size_t size=esp_spiram_get_chip_size(); if (size==PSRAM_SIZE_16MBITS) return 2*1024*1024; @@ -228,7 +228,7 @@ size_t esp_spiram_get_size() Note that this routine assumes some unique mapping for the first 2 banks of the PSRAM memory range, as well as the 2 banks after the 2 MiB mark. */ -void IRAM_ATTR esp_spiram_writeback_cache() +void IRAM_ATTR esp_spiram_writeback_cache(void) { int x; volatile int i=0; @@ -289,7 +289,7 @@ void IRAM_ATTR esp_spiram_writeback_cache() * @return true SPI RAM has been initialized successfully * @return false SPI RAM hasn't been initialized or initialized failed */ -bool esp_spiram_is_initialized() +bool esp_spiram_is_initialized(void) { return spiram_inited; } diff --git a/components/esp32/spiram_psram.c b/components/esp32/spiram_psram.c index ee393618ab..1ac19a97dc 100644 --- a/components/esp32/spiram_psram.c +++ b/components/esp32/spiram_psram.c @@ -596,7 +596,7 @@ static void IRAM_ATTR psram_gpio_config(psram_io_t *psram_io, psram_cache_mode_t } } -psram_size_t psram_get_size() +psram_size_t psram_get_size(void) { if ((PSRAM_SIZE_ID(s_psram_id) == PSRAM_EID_SIZE_64MBITS) || PSRAM_IS_64MBIT_TRIAL(s_psram_id)) { return PSRAM_SIZE_64MBITS; diff --git a/components/esp32/spiram_psram.h b/components/esp32/spiram_psram.h index 5a5f147bf5..14f06cb41d 100644 --- a/components/esp32/spiram_psram.h +++ b/components/esp32/spiram_psram.h @@ -53,7 +53,7 @@ typedef enum { * - PSRAM_SIZE_MAX if psram not enabled or not valid * - PSRAM size */ -psram_size_t psram_get_size(); +psram_size_t psram_get_size(void); /** * @brief psram cache enable function diff --git a/components/esp32/system_api.c b/components/esp32/system_api.c index bd81a82db7..570c0997a3 100644 --- a/components/esp32/system_api.c +++ b/components/esp32/system_api.c @@ -46,7 +46,7 @@ static uint8_t base_mac_addr[6] = { 0 }; #define SHUTDOWN_HANDLERS_NO 2 static shutdown_handler_t shutdown_handlers[SHUTDOWN_HANDLERS_NO]; -void system_init() +void system_init(void) { } @@ -232,7 +232,7 @@ esp_err_t esp_unregister_shutdown_handler(shutdown_handler_t handler) return ESP_ERR_INVALID_STATE; } -void esp_restart_noos() __attribute__ ((noreturn)); +void esp_restart_noos(void) __attribute__ ((noreturn)); void IRAM_ATTR esp_restart(void) { @@ -253,7 +253,7 @@ void IRAM_ATTR esp_restart(void) * core are already stopped. Stalls other core, resets hardware, * triggers restart. */ -void IRAM_ATTR esp_restart_noos() +void IRAM_ATTR esp_restart_noos(void) { // Disable interrupts xt_ints_off(0xFFFFFFFF); diff --git a/components/esp32/task_wdt.c b/components/esp32/task_wdt.c index 86610be94a..6675a1a98a 100644 --- a/components/esp32/task_wdt.c +++ b/components/esp32/task_wdt.c @@ -104,7 +104,7 @@ static twdt_task_t *find_task_in_twdt_list(TaskHandle_t handle, bool *all_reset) * Resets the hardware timer and has_reset flags of each task on the list. * Called within critical */ -static void reset_hw_timer() +static void reset_hw_timer(void) { //All tasks have reset; time to reset the hardware timer. TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; @@ -229,7 +229,7 @@ esp_err_t esp_task_wdt_init(uint32_t timeout, bool panic) return ESP_OK; } -esp_err_t esp_task_wdt_deinit() +esp_err_t esp_task_wdt_deinit(void) { portENTER_CRITICAL(&twdt_spinlock); //TWDT must already be initialized @@ -297,7 +297,7 @@ esp_err_t esp_task_wdt_add(TaskHandle_t handle) return ESP_OK; } -esp_err_t esp_task_wdt_reset() +esp_err_t esp_task_wdt_reset(void) { portENTER_CRITICAL(&twdt_spinlock); //TWDT must already be initialized @@ -385,7 +385,7 @@ esp_err_t esp_task_wdt_status(TaskHandle_t handle) return ESP_ERR_NOT_FOUND; } -void esp_task_wdt_feed() +void esp_task_wdt_feed(void) { portENTER_CRITICAL(&twdt_spinlock); //Return immediately if TWDT has not been initialized diff --git a/components/esp32/test/test_4mpsram.c b/components/esp32/test/test_4mpsram.c index da173a19bf..9e86882144 100644 --- a/components/esp32/test/test_4mpsram.c +++ b/components/esp32/test/test_4mpsram.c @@ -7,7 +7,7 @@ static const char TAG[] = "test_psram"; #ifdef CONFIG_ESP32_SPIRAM_SUPPORT -static void test_psram_content() +static void test_psram_content(void) { const int test_size = 2048; uint32_t *test_area = heap_caps_malloc(test_size, MALLOC_CAP_SPIRAM); diff --git a/components/esp32/test/test_ahb_arb.c b/components/esp32/test/test_ahb_arb.c index 185bbb3ddb..a4a8f87fd9 100644 --- a/components/esp32/test/test_ahb_arb.c +++ b/components/esp32/test/test_ahb_arb.c @@ -31,7 +31,7 @@ to copy bytes over from one memory location to another. DO NOT USE the i2s routi the point where they happened to do what I want. */ -static void lcdIfaceInit() +static void lcdIfaceInit(void) { DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); @@ -99,7 +99,7 @@ static void lcdIfaceInit() static volatile lldesc_t dmaDesc[2]; -static void finishDma() +static void finishDma(void) { //No need to finish if no DMA transfer going on if (!(READ_PERI_REG(I2S_FIFO_CONF_REG(0))&I2S_DSCR_EN)) { diff --git a/components/esp32/test/test_esp_timer.c b/components/esp32/test/test_esp_timer.c index e3444503a1..52265fb829 100644 --- a/components/esp32/test/test_esp_timer.c +++ b/components/esp32/test/test_esp_timer.c @@ -16,12 +16,12 @@ #define WITH_PROFILING 1 #endif -extern uint32_t esp_timer_impl_get_overflow_val(); +extern uint32_t esp_timer_impl_get_overflow_val(void); extern void esp_timer_impl_set_overflow_val(uint32_t overflow_val); static uint32_t s_old_overflow_val; -static void setup_overflow() +static void setup_overflow(void) { s_old_overflow_val = esp_timer_impl_get_overflow_val(); /* Overflow every 0.1 sec. @@ -31,7 +31,7 @@ static void setup_overflow() esp_timer_impl_set_overflow_val(8000000); } -static void teardown_overflow() +static void teardown_overflow(void) { esp_timer_impl_set_overflow_val(s_old_overflow_val); } @@ -409,7 +409,7 @@ TEST_CASE("esp_timer_get_time call takes less than 1us", "[esp_timer]") TEST_PERFORMANCE_LESS_THAN(ESP_TIMER_GET_TIME_PER_CALL, "%dns", ns_per_call); } -static int64_t IRAM_ATTR __attribute__((noinline)) get_clock_diff() +static int64_t IRAM_ATTR __attribute__((noinline)) get_clock_diff(void) { uint64_t hs_time = esp_timer_get_time(); uint64_t ref_time = ref_clock_get(); diff --git a/components/esp32/test/test_intr_alloc.c b/components/esp32/test/test_intr_alloc.c index 8255388e98..85654c1ae0 100644 --- a/components/esp32/test/test_intr_alloc.c +++ b/components/esp32/test/test_intr_alloc.c @@ -144,7 +144,7 @@ void int_timer_handler(void *arg) { int_timer_ctr++; } -void local_timer_test() +void local_timer_test(void) { intr_handle_t ih; esp_err_t r; diff --git a/components/esp32/test/test_pm.c b/components/esp32/test/test_pm.c index cf031ab59c..e74a214d7e 100644 --- a/components/esp32/test/test_pm.c +++ b/components/esp32/test/test_pm.c @@ -58,7 +58,7 @@ TEST_CASE("Can switch frequency using esp_pm_configure", "[pm]") #if CONFIG_FREERTOS_USE_TICKLESS_IDLE -static void light_sleep_enable() +static void light_sleep_enable(void) { const esp_pm_config_esp32_t pm_config = { .max_cpu_freq = rtc_clk_cpu_freq_get(), @@ -68,7 +68,7 @@ static void light_sleep_enable() ESP_ERROR_CHECK( esp_pm_configure(&pm_config) ); } -static void light_sleep_disable() +static void light_sleep_disable(void) { const esp_pm_config_esp32_t pm_config = { .max_cpu_freq = rtc_clk_cpu_freq_get(), diff --git a/components/esp32/test/test_reset_reason.c b/components/esp32/test/test_reset_reason.c index 78d051358e..da03e8c1e3 100644 --- a/components/esp32/test/test_reset_reason.c +++ b/components/esp32/test/test_reset_reason.c @@ -24,7 +24,7 @@ static RTC_FAST_ATTR uint32_t s_rtc_force_fast_val; static RTC_SLOW_ATTR uint32_t s_rtc_force_slow_val; -static void setup_values() +static void setup_values(void) { s_noinit_val = CHECK_VALUE; s_rtc_noinit_val = CHECK_VALUE; @@ -44,14 +44,14 @@ TEST_CASE("reset reason ESP_RST_POWERON", "[reset][ignore]") TEST_ASSERT_EQUAL(ESP_RST_POWERON, esp_reset_reason()); } -static void do_deep_sleep() +static void do_deep_sleep(void) { setup_values(); esp_sleep_enable_timer_wakeup(10000); esp_deep_sleep_start(); } -static void check_reset_reason_deep_sleep() +static void check_reset_reason_deep_sleep(void) { TEST_ASSERT_EQUAL(ESP_RST_DEEPSLEEP, esp_reset_reason()); @@ -67,19 +67,19 @@ TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_DEEPSLEEP", "[reset_reason][rese do_deep_sleep, check_reset_reason_deep_sleep); -static void do_exception() +static void do_exception(void) { setup_values(); *(int*) (0x40000001) = 0; } -static void do_abort() +static void do_abort(void) { setup_values(); abort(); } -static void check_reset_reason_panic() +static void check_reset_reason_panic(void) { TEST_ASSERT_EQUAL(ESP_RST_PANIC, esp_reset_reason()); @@ -100,14 +100,14 @@ TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_PANIC after abort", "[reset_reas do_abort, check_reset_reason_panic); -static void do_restart() +static void do_restart(void) { setup_values(); esp_restart(); } #if portNUM_PROCESSORS > 1 -static void do_restart_from_app_cpu() +static void do_restart_from_app_cpu(void) { setup_values(); xTaskCreatePinnedToCore((TaskFunction_t) &do_restart, "restart", 2048, NULL, 5, NULL, 1); @@ -115,7 +115,7 @@ static void do_restart_from_app_cpu() } #endif -static void check_reset_reason_sw() +static void check_reset_reason_sw(void) { TEST_ASSERT_EQUAL(ESP_RST_SW, esp_reset_reason()); @@ -139,21 +139,21 @@ TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_SW after restart from APP CPU", #endif -static void do_int_wdt() +static void do_int_wdt(void) { setup_values(); portENTER_CRITICAL_NESTED(); while(1); } -static void do_int_wdt_hw() +static void do_int_wdt_hw(void) { setup_values(); XTOS_SET_INTLEVEL(XCHAL_NMILEVEL); while(1); } -static void check_reset_reason_int_wdt() +static void check_reset_reason_int_wdt(void) { TEST_ASSERT_EQUAL(ESP_RST_INT_WDT, esp_reset_reason()); TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val); @@ -169,7 +169,7 @@ TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_INT_WDT after interrupt watchdog do_int_wdt_hw, check_reset_reason_int_wdt); -static void do_task_wdt() +static void do_task_wdt(void) { setup_values(); esp_task_wdt_init(1, true); @@ -177,7 +177,7 @@ static void do_task_wdt() while(1); } -static void check_reset_reason_task_wdt() +static void check_reset_reason_task_wdt(void) { TEST_ASSERT_EQUAL(ESP_RST_TASK_WDT, esp_reset_reason()); @@ -195,7 +195,7 @@ TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_TASK_WDT after task watchdog", do_task_wdt, check_reset_reason_task_wdt); -static void do_rtc_wdt() +static void do_rtc_wdt(void) { setup_values(); WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE); @@ -206,7 +206,7 @@ static void do_rtc_wdt() while(1); } -static void check_reset_reason_any_wdt() +static void check_reset_reason_any_wdt(void) { TEST_ASSERT_EQUAL(ESP_RST_WDT, esp_reset_reason()); TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val); @@ -218,14 +218,14 @@ TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_WDT after RTC watchdog", check_reset_reason_any_wdt); -static void do_brownout() +static void do_brownout(void) { setup_values(); printf("Manual test: lower the supply voltage to cause brownout\n"); vTaskSuspend(NULL); } -static void check_reset_reason_brownout() +static void check_reset_reason_brownout(void) { TEST_ASSERT_EQUAL(ESP_RST_BROWNOUT, esp_reset_reason()); diff --git a/components/esp32/test/test_sleep.c b/components/esp32/test/test_sleep.c index 8712bdfd06..12e268e358 100644 --- a/components/esp32/test/test_sleep.c +++ b/components/esp32/test/test_sleep.c @@ -29,7 +29,7 @@ static void deep_sleep_task(void *arg) esp_deep_sleep_start(); } -static void do_deep_sleep_from_app_cpu() +static void do_deep_sleep_from_app_cpu(void) { xTaskCreatePinnedToCore(&deep_sleep_task, "ds", 2048, NULL, 5, NULL, 1); @@ -204,20 +204,20 @@ TEST_CASE("enter deep sleep on APP CPU and wake up using timer", "[deepsleep][re } #endif -static void do_deep_sleep() +static void do_deep_sleep(void) { esp_sleep_enable_timer_wakeup(100000); esp_deep_sleep_start(); } -static void check_sleep_reset_and_sleep() +static void check_sleep_reset_and_sleep(void) { TEST_ASSERT_EQUAL(ESP_RST_DEEPSLEEP, esp_reset_reason()); esp_sleep_enable_timer_wakeup(100000); esp_deep_sleep_start(); } -static void check_sleep_reset() +static void check_sleep_reset(void) { TEST_ASSERT_EQUAL(ESP_RST_DEEPSLEEP, esp_reset_reason()); } @@ -228,12 +228,12 @@ TEST_CASE_MULTIPLE_STAGES("enter deep sleep more than once", "[deepsleep][reset= check_sleep_reset_and_sleep, check_sleep_reset); -static void do_abort() +static void do_abort(void) { abort(); } -static void check_abort_reset_and_sleep() +static void check_abort_reset_and_sleep(void) { TEST_ASSERT_EQUAL(ESP_RST_PANIC, esp_reset_reason()); esp_sleep_enable_timer_wakeup(100000); @@ -247,20 +247,20 @@ TEST_CASE_MULTIPLE_STAGES("enter deep sleep after abort", "[deepsleep][reset=abo static RTC_DATA_ATTR uint32_t s_wake_stub_var; -static RTC_IRAM_ATTR void wake_stub() +static RTC_IRAM_ATTR void wake_stub(void) { esp_default_wake_deep_sleep(); s_wake_stub_var = (uint32_t) &wake_stub; } -static void prepare_wake_stub() +static void prepare_wake_stub(void) { esp_set_deep_sleep_wake_stub(&wake_stub); esp_sleep_enable_timer_wakeup(100000); esp_deep_sleep_start(); } -static void check_wake_stub() +static void check_wake_stub(void) { TEST_ASSERT_EQUAL(ESP_RST_DEEPSLEEP, esp_reset_reason()); TEST_ASSERT_EQUAL_HEX32((uint32_t) &wake_stub, s_wake_stub_var); @@ -336,7 +336,7 @@ static float get_time_ms(void) return fabs(dt); } -static uint32_t get_cause() +static uint32_t get_cause(void) { uint32_t wakeup_cause = REG_GET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, \ RTC_CNTL_WAKEUP_CAUSE); diff --git a/components/esp32/test/test_stack_check.c b/components/esp32/test/test_stack_check.c index 0fa6c7bfed..abc36047b9 100644 --- a/components/esp32/test/test_stack_check.c +++ b/components/esp32/test/test_stack_check.c @@ -2,7 +2,7 @@ #if CONFIG_COMPILER_STACK_CHECK -static void recur_and_smash() +static void recur_and_smash(void) { static int cnt; volatile uint8_t buf[50]; diff --git a/components/esp_adc_cal/esp_adc_cal.c b/components/esp_adc_cal/esp_adc_cal.c index f71c086376..75146b37c9 100644 --- a/components/esp_adc_cal/esp_adc_cal.c +++ b/components/esp_adc_cal/esp_adc_cal.c @@ -110,13 +110,13 @@ static const uint32_t lut_adc2_high[LUT_POINTS] = {2657, 2698, 2738, 2774, 2807, 2971, 2996, 3020, 3043, 3067, 3092, 3116, 3139, 3162, 3185}; /* ----------------------- EFuse Access Functions --------------------------- */ -static bool check_efuse_vref() +static bool check_efuse_vref(void) { //Check if Vref is burned in eFuse return (REG_GET_FIELD(VREF_REG, EFUSE_RD_ADC_VREF) != 0) ? true : false; } -static bool check_efuse_tp() +static bool check_efuse_tp(void) { //Check if Two Point values are burned in eFuse if (CHECK_BLK3_FLAG && (REG_GET_FIELD(BLK3_RESERVED_REG, EFUSE_RD_BLK3_PART_RESERVE) == 0)) { @@ -150,7 +150,7 @@ static inline int decode_bits(uint32_t bits, uint32_t mask, bool is_twos_compl) return ret; } -static uint32_t read_efuse_vref() +static uint32_t read_efuse_vref(void) { //eFuse stores deviation from ideal reference voltage uint32_t ret = VREF_OFFSET; //Ideal vref diff --git a/components/esp_common/include/esp_int_wdt.h b/components/esp_common/include/esp_int_wdt.h index f581d939ad..87cc23ec1e 100644 --- a/components/esp_common/include/esp_int_wdt.h +++ b/components/esp_common/include/esp_int_wdt.h @@ -43,7 +43,7 @@ This uses the TIMERG1 WDT. * is enabled in menuconfig. * */ -void esp_int_wdt_init(); +void esp_int_wdt_init(void); /** * @brief Enable the interrupt watchdog on the current CPU. This is called @@ -51,7 +51,7 @@ void esp_int_wdt_init(); * in menuconfig. * */ -void esp_int_wdt_cpu_init(); +void esp_int_wdt_cpu_init(void); diff --git a/components/esp_common/include/esp_private/crosscore_int.h b/components/esp_common/include/esp_private/crosscore_int.h index 2f1c5b3bec..d0e3cadc13 100644 --- a/components/esp_common/include/esp_private/crosscore_int.h +++ b/components/esp_common/include/esp_private/crosscore_int.h @@ -24,7 +24,7 @@ * called automatically by the startup code and should not * be called manually. */ -void esp_crosscore_int_init(); +void esp_crosscore_int_init(void); /** diff --git a/components/esp_common/include/esp_private/esp_timer_impl.h b/components/esp_common/include/esp_private/esp_timer_impl.h index adc98bc42f..bee1d07568 100644 --- a/components/esp_common/include/esp_private/esp_timer_impl.h +++ b/components/esp_common/include/esp_private/esp_timer_impl.h @@ -38,7 +38,7 @@ esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler); /** * @brief Deinitialize platform specific layer of esp_timer */ -void esp_timer_impl_deinit(); +void esp_timer_impl_deinit(void); /** * @brief Set up the timer interrupt to fire at a particular time @@ -73,7 +73,7 @@ void esp_timer_impl_advance(int64_t time_us); * @brief Get time, in microseconds, since esp_timer_impl_init was called * @return timestamp in microseconds */ -uint64_t esp_timer_impl_get_time(); +uint64_t esp_timer_impl_get_time(void); /** * @brief Get minimal timer period, in microseconds @@ -83,7 +83,7 @@ uint64_t esp_timer_impl_get_time(); * callback, preventing other tasks from running. * @return minimal period of periodic timer, in microseconds */ -uint64_t esp_timer_impl_get_min_period_us(); +uint64_t esp_timer_impl_get_min_period_us(void); /** * @brief obtain internal critical section used esp_timer implementation @@ -92,10 +92,10 @@ uint64_t esp_timer_impl_get_min_period_us(); * the calls. Should be treated in the same way as a spinlock. * Call esp_timer_impl_unlock to release the lock */ -void esp_timer_impl_lock(); +void esp_timer_impl_lock(void); /** * @brief counterpart of esp_timer_impl_lock */ -void esp_timer_impl_unlock(); +void esp_timer_impl_unlock(void); diff --git a/components/esp_common/include/esp_private/pm_impl.h b/components/esp_common/include/esp_private/pm_impl.h index 134e874e5e..f0cf914f7b 100644 --- a/components/esp_common/include/esp_private/pm_impl.h +++ b/components/esp_common/include/esp_private/pm_impl.h @@ -80,19 +80,19 @@ void esp_pm_impl_switch_mode(pm_mode_t mode, pm_mode_switch_t lock_or_unlock, pm /** * @brief Call once at startup to initialize pm implementation */ -void esp_pm_impl_init(); +void esp_pm_impl_init(void); /** * @brief Hook function for the idle task * Must be called from the IDLE task on each CPU before entering waiti state. */ -void esp_pm_impl_idle_hook(); +void esp_pm_impl_idle_hook(void); /** * @brief Hook function for the interrupt dispatcher * Must be called soon after entering the ISR */ -void esp_pm_impl_isr_hook(); +void esp_pm_impl_isr_hook(void); /** * @brief Dump the information about time spent in each of the pm modes. @@ -107,14 +107,14 @@ void esp_pm_impl_dump_stats(FILE* out); /** * @brief Hook function implementing `waiti` instruction, should be invoked from idle task context */ -void esp_pm_impl_waiti(); +void esp_pm_impl_waiti(void); #ifdef CONFIG_PM_PROFILING #define WITH_PROFILING #endif #ifdef WITH_PROFILING -static inline pm_time_t IRAM_ATTR pm_get_time() +static inline pm_time_t IRAM_ATTR pm_get_time(void) { return esp_timer_get_time(); } diff --git a/components/esp_common/include/esp_private/pm_trace.h b/components/esp_common/include/esp_private/pm_trace.h index d1cf7e3363..24e6719076 100644 --- a/components/esp_common/include/esp_private/pm_trace.h +++ b/components/esp_common/include/esp_private/pm_trace.h @@ -26,7 +26,7 @@ typedef enum { ESP_PM_TRACE_TYPE_MAX } esp_pm_trace_event_t; -void esp_pm_trace_init(); +void esp_pm_trace_init(void); void esp_pm_trace_enter(esp_pm_trace_event_t event, int core_id); void esp_pm_trace_exit(esp_pm_trace_event_t event, int core_id); diff --git a/components/esp_common/include/esp_private/system_internal.h b/components/esp_common/include/esp_private/system_internal.h index 5bda73fb7a..e0d95d2f71 100644 --- a/components/esp_common/include/esp_private/system_internal.h +++ b/components/esp_common/include/esp_private/system_internal.h @@ -29,7 +29,7 @@ extern "C" { * This is an internal function called by esp_restart. It is called directly * by the panic handler and brownout detector interrupt. */ -void esp_restart_noos() __attribute__ ((noreturn)); +void esp_restart_noos(void) __attribute__ ((noreturn)); /** * @brief Internal function to set reset reason hint diff --git a/components/esp_common/include/esp_task_wdt.h b/components/esp_common/include/esp_task_wdt.h index 60b0e5e5c9..554aa34974 100644 --- a/components/esp_common/include/esp_task_wdt.h +++ b/components/esp_common/include/esp_task_wdt.h @@ -56,7 +56,7 @@ esp_err_t esp_task_wdt_init(uint32_t timeout, bool panic); * - ESP_ERR_INVALID_STATE: Error, tasks are still subscribed to the TWDT * - ESP_ERR_NOT_FOUND: Error, TWDT has already been deinitialized */ -esp_err_t esp_task_wdt_deinit(); +esp_err_t esp_task_wdt_deinit(void); /** * @brief Subscribe a task to the Task Watchdog Timer (TWDT) @@ -102,7 +102,7 @@ esp_err_t esp_task_wdt_add(TaskHandle_t handle); * to the TWDT * - ESP_ERR_INVALID_STATE: Error, the TWDT has not been initialized yet */ -esp_err_t esp_task_wdt_reset(); +esp_err_t esp_task_wdt_reset(void); /** * @brief Unsubscribes a task from the Task Watchdog Timer (TWDT) @@ -155,7 +155,7 @@ esp_err_t esp_task_wdt_status(TaskHandle_t handle); * function, then proceed to reset the TWDT on subsequent calls of this * function. */ -void esp_task_wdt_feed() __attribute__ ((deprecated)); +void esp_task_wdt_feed(void) __attribute__ ((deprecated)); #ifdef __cplusplus diff --git a/components/esp_common/include/esp_timer.h b/components/esp_common/include/esp_timer.h index ff5c13ab4c..769c9fe298 100644 --- a/components/esp_common/include/esp_timer.h +++ b/components/esp_common/include/esp_timer.h @@ -95,7 +95,7 @@ typedef struct { * - ESP_ERR_INVALID_STATE if already initialized * - other errors from interrupt allocator */ -esp_err_t esp_timer_init(); +esp_err_t esp_timer_init(void); /** * @brief De-initialize esp_timer library @@ -106,7 +106,7 @@ esp_err_t esp_timer_init(); * - ESP_OK on success * - ESP_ERR_INVALID_STATE if not yet initialized */ -esp_err_t esp_timer_deinit(); +esp_err_t esp_timer_deinit(void); /** * @brief Create an esp_timer instance @@ -187,14 +187,14 @@ esp_err_t esp_timer_delete(esp_timer_handle_t timer); * @return number of microseconds since esp_timer_init was called (this normally * happens early during application startup). */ -int64_t esp_timer_get_time(); +int64_t esp_timer_get_time(void); /** * @brief Get the timestamp when the next timeout is expected to occur * @return Timestamp of the nearest timer event, in microseconds. * The timebase is the same as for the values returned by esp_timer_get_time. */ -int64_t esp_timer_get_next_alarm(); +int64_t esp_timer_get_next_alarm(void); /** * @brief Dump the list of timers to a stream diff --git a/components/esp_common/src/dbg_stubs.c b/components/esp_common/src/dbg_stubs.c index 3def85c3f7..e0389ce1d6 100644 --- a/components/esp_common/src/dbg_stubs.c +++ b/components/esp_common/src/dbg_stubs.c @@ -69,7 +69,7 @@ static void esp_dbg_stubs_data_free(void *addr) ESP_LOGV(TAG, "%s EXIT %p", __func__, addr); } -void esp_dbg_stubs_init() +void esp_dbg_stubs_init(void) { s_dbg_stubs_ctl_data.tramp_addr = (uint32_t)s_stub_code_buf; s_dbg_stubs_ctl_data.min_stack_addr = (uint32_t)s_stub_min_stack; diff --git a/components/esp_common/src/esp_timer.c b/components/esp_common/src/esp_timer.c index 82a2d0b85b..034f77fcca 100644 --- a/components/esp_common/src/esp_timer.c +++ b/components/esp_common/src/esp_timer.c @@ -60,12 +60,12 @@ struct esp_timer { LIST_ENTRY(esp_timer) list_entry; }; -static bool is_initialized(); +static bool is_initialized(void); static esp_err_t timer_insert(esp_timer_handle_t timer); static esp_err_t timer_remove(esp_timer_handle_t timer); static bool timer_armed(esp_timer_handle_t timer); -static void timer_list_lock(); -static void timer_list_unlock(); +static void timer_list_lock(void); +static void timer_list_unlock(void); #if WITH_PROFILING static void timer_insert_inactive(esp_timer_handle_t timer); @@ -247,12 +247,12 @@ static IRAM_ATTR bool timer_armed(esp_timer_handle_t timer) return timer->alarm > 0; } -static IRAM_ATTR void timer_list_lock() +static IRAM_ATTR void timer_list_lock(void) { portENTER_CRITICAL(&s_timer_lock); } -static IRAM_ATTR void timer_list_unlock() +static IRAM_ATTR void timer_list_unlock(void) { portEXIT_CRITICAL(&s_timer_lock); } @@ -323,7 +323,7 @@ static void IRAM_ATTR timer_alarm_handler(void* arg) } } -static IRAM_ATTR bool is_initialized() +static IRAM_ATTR bool is_initialized(void) { return s_timer_task != NULL; } @@ -474,7 +474,7 @@ esp_err_t esp_timer_dump(FILE* stream) return ESP_OK; } -int64_t IRAM_ATTR esp_timer_get_next_alarm() +int64_t IRAM_ATTR esp_timer_get_next_alarm(void) { int64_t next_alarm = INT64_MAX; timer_list_lock(); @@ -486,7 +486,7 @@ int64_t IRAM_ATTR esp_timer_get_next_alarm() return next_alarm; } -int64_t IRAM_ATTR esp_timer_get_time() +int64_t IRAM_ATTR esp_timer_get_time(void) { return (int64_t) esp_timer_impl_get_time(); } diff --git a/components/esp_common/src/freertos_hooks.c b/components/esp_common/src/freertos_hooks.c index d60411dc73..58c42b8542 100644 --- a/components/esp_common/src/freertos_hooks.c +++ b/components/esp_common/src/freertos_hooks.c @@ -32,7 +32,7 @@ static portMUX_TYPE hooks_spinlock = portMUX_INITIALIZER_UNLOCKED; static esp_freertos_idle_cb_t idle_cb[portNUM_PROCESSORS][MAX_HOOKS]={0}; static esp_freertos_tick_cb_t tick_cb[portNUM_PROCESSORS][MAX_HOOKS]={0}; -void IRAM_ATTR esp_vApplicationTickHook() +void IRAM_ATTR esp_vApplicationTickHook(void) { int n; int core = xPortGetCoreID(); @@ -43,7 +43,7 @@ void IRAM_ATTR esp_vApplicationTickHook() } } -void esp_vApplicationIdleHook() +void esp_vApplicationIdleHook(void) { bool can_go_idle=true; int core = xPortGetCoreID(); diff --git a/components/esp_common/src/ipc.c b/components/esp_common/src/ipc.c index 927db9087c..c68a488519 100644 --- a/components/esp_common/src/ipc.c +++ b/components/esp_common/src/ipc.c @@ -82,9 +82,9 @@ static void IRAM_ATTR ipc_task(void* arg) * woken up to execute the callback provided to esp_ipc_call_nonblocking or * esp_ipc_call_blocking. */ -static void esp_ipc_init() __attribute__((constructor)); +static void esp_ipc_init(void) __attribute__((constructor)); -static void esp_ipc_init() +static void esp_ipc_init(void) { s_ipc_mutex = xSemaphoreCreateMutex(); s_ipc_ack = xSemaphoreCreateBinary(); diff --git a/components/esp_event/default_event_loop.c b/components/esp_event/default_event_loop.c index 01418c72a5..9b5b8e8b63 100644 --- a/components/esp_event/default_event_loop.c +++ b/components/esp_event/default_event_loop.c @@ -70,7 +70,7 @@ esp_err_t esp_event_isr_post(esp_event_base_t event_base, int32_t event_id, #endif -esp_err_t esp_event_loop_create_default() +esp_err_t esp_event_loop_create_default(void) { if (s_default_loop) { return ESP_ERR_INVALID_STATE; @@ -94,7 +94,7 @@ esp_err_t esp_event_loop_create_default() return ESP_OK; } -esp_err_t esp_event_loop_delete_default() +esp_err_t esp_event_loop_delete_default(void) { if (!s_default_loop) { return ESP_ERR_INVALID_STATE; diff --git a/components/esp_event/esp_event.c b/components/esp_event/esp_event.c index 99a3cf70bb..557cfba0d3 100644 --- a/components/esp_event/esp_event.c +++ b/components/esp_event/esp_event.c @@ -60,7 +60,7 @@ static portMUX_TYPE s_event_loops_spinlock = portMUX_INITIALIZER_UNLOCKED; #ifdef CONFIG_ESP_EVENT_LOOP_PROFILING -static int esp_event_dump_prepare() +static int esp_event_dump_prepare(void) { esp_event_loop_instance_t* loop_it; esp_event_loop_node_t *loop_node_it; diff --git a/components/esp_event/event_loop_legacy.c b/components/esp_event/event_loop_legacy.c index f5e737d203..3b80387bfc 100644 --- a/components/esp_event/event_loop_legacy.c +++ b/components/esp_event/event_loop_legacy.c @@ -76,7 +76,7 @@ esp_err_t esp_event_loop_init(system_event_cb_t cb, void *ctx) return ESP_OK; } -esp_err_t esp_event_loop_deinit() +esp_err_t esp_event_loop_deinit(void) { if (!s_initialized) { ESP_LOGE(TAG, "system event loop not initialized"); diff --git a/components/esp_event/include/esp_event.h b/components/esp_event/include/esp_event.h index c78636415a..8282122a02 100644 --- a/components/esp_event/include/esp_event.h +++ b/components/esp_event/include/esp_event.h @@ -74,7 +74,7 @@ esp_err_t esp_event_loop_delete(esp_event_loop_handle_t event_loop); * - ESP_FAIL: Failed to create task loop * - Others: Fail */ -esp_err_t esp_event_loop_create_default(); +esp_err_t esp_event_loop_create_default(void); /** * @brief Delete the default event loop @@ -83,7 +83,7 @@ esp_err_t esp_event_loop_create_default(); * - ESP_OK: Success * - Others: Fail */ -esp_err_t esp_event_loop_delete_default(); +esp_err_t esp_event_loop_delete_default(void); /** * @brief Dispatch events posted to an event loop. diff --git a/components/esp_event/include/esp_event_legacy.h b/components/esp_event/include/esp_event_legacy.h index 44e95546a1..9509ce6a75 100644 --- a/components/esp_event/include/esp_event_legacy.h +++ b/components/esp_event/include/esp_event_legacy.h @@ -160,14 +160,14 @@ esp_err_t esp_event_process_default(system_event_t *event); * @note This API is part of the legacy event system. New code should use event library API in esp_event.h * */ -void esp_event_set_default_eth_handlers(); +void esp_event_set_default_eth_handlers(void); /** * @brief Install default event handlers for Wi-Fi interfaces (station and AP) * * @note This API is part of the legacy event system. New code should use event library API in esp_event.h */ -void esp_event_set_default_wifi_handlers(); +void esp_event_set_default_wifi_handlers(void); /** * @brief Application specified event callback function diff --git a/components/esp_event/private_include/esp_event_private.h b/components/esp_event/private_include/esp_event_private.h index 990d51872e..d96f66e2df 100644 --- a/components/esp_event/private_include/esp_event_private.h +++ b/components/esp_event/private_include/esp_event_private.h @@ -45,7 +45,7 @@ bool esp_event_is_handler_registered(esp_event_loop_handle_t event_loop, esp_eve * - ESP_OK: Success * - Others: Fail */ -esp_err_t esp_event_loop_deinit(); +esp_err_t esp_event_loop_deinit(void); #ifdef __cplusplus } // extern "C" diff --git a/components/esp_event/test/test_event.c b/components/esp_event/test/test_event.c index 0efc2d4920..6560bdc5f5 100644 --- a/components/esp_event/test/test_event.c +++ b/components/esp_event/test/test_event.c @@ -103,7 +103,7 @@ enum { TEST_EVENT_BASE2_MAX }; -static BaseType_t test_event_get_core() +static BaseType_t test_event_get_core(void) { static int calls = 0; @@ -114,7 +114,7 @@ static BaseType_t test_event_get_core() } } -static esp_event_loop_args_t test_event_get_default_loop_args() +static esp_event_loop_args_t test_event_get_default_loop_args(void) { esp_event_loop_args_t loop_config = { .queue_size = CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE, @@ -263,13 +263,13 @@ static void test_post_from_handler_loop_task(void* args) } } -static void test_setup() +static void test_setup(void) { TEST_ASSERT_TRUE(TEST_CONFIG_TASKS_TO_SPAWN >= 2); TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_create_default()); } -static void test_teardown() +static void test_teardown(void) { TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_delete_default()); } diff --git a/components/esp_gdbstub/esp32/gdbstub_esp32.c b/components/esp_gdbstub/esp32/gdbstub_esp32.c index 3fe393a0db..98a6454acd 100644 --- a/components/esp_gdbstub/esp32/gdbstub_esp32.c +++ b/components/esp_gdbstub/esp32/gdbstub_esp32.c @@ -19,11 +19,11 @@ #define UART_NUM CONFIG_CONSOLE_UART_NUM -void esp_gdbstub_target_init() +void esp_gdbstub_target_init(void) { } -int esp_gdbstub_getchar() +int esp_gdbstub_getchar(void) { while (REG_GET_FIELD(UART_STATUS_REG(UART_NUM), UART_RXFIFO_CNT) == 0) { ; diff --git a/components/esp_gdbstub/private_include/esp_gdbstub_common.h b/components/esp_gdbstub/private_include/esp_gdbstub_common.h index 75674ff026..43c35dcabd 100644 --- a/components/esp_gdbstub/private_include/esp_gdbstub_common.h +++ b/components/esp_gdbstub/private_include/esp_gdbstub_common.h @@ -98,13 +98,13 @@ void esp_gdbstub_tcb_to_regfile(TaskHandle_t tcb, esp_gdbstub_gdb_regfile_t *dst * Do target-specific initialization before gdbstub can start communicating. * This may involve, for example, configuring the UART. */ -void esp_gdbstub_target_init(); +void esp_gdbstub_target_init(void); /** * Receive a byte from the GDB client. Blocks until a byte is available. * @return received byte */ -int esp_gdbstub_getchar(); +int esp_gdbstub_getchar(void); /** * Send a byte to the GDB client @@ -123,7 +123,7 @@ int esp_gdbstub_readmem(intptr_t addr); /**** GDB packet related functions ****/ /** Begin a packet */ -void esp_gdbstub_send_start(); +void esp_gdbstub_send_start(void); /** Send a character as part of the packet */ void esp_gdbstub_send_char(char c); @@ -135,7 +135,7 @@ void esp_gdbstub_send_str(const char *s); void esp_gdbstub_send_hex(int val, int bits); /** Finish sending the packet */ -void esp_gdbstub_send_end(); +void esp_gdbstub_send_end(void); /** Send a packet with a string as content */ void esp_gdbstub_send_str_packet(const char* str); diff --git a/components/esp_gdbstub/src/gdbstub.c b/components/esp_gdbstub/src/gdbstub.c index 4d1f4cf54c..fbb3d26bf1 100644 --- a/components/esp_gdbstub/src/gdbstub.c +++ b/components/esp_gdbstub/src/gdbstub.c @@ -19,12 +19,12 @@ #ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS -static void init_task_info(); -static void find_paniced_task_index(); +static void init_task_info(void); +static void find_paniced_task_index(void); static int handle_task_commands(unsigned char *cmd, int len); #endif -static void send_reason(); +static void send_reason(void); static esp_gdbstub_scratch_t s_scratch; @@ -77,7 +77,7 @@ void esp_gdbstub_panic_handler(esp_gdbstub_frame_t *frame) } -static void send_reason() +static void send_reason(void) { esp_gdbstub_send_start(); esp_gdbstub_send_char('T'); @@ -162,7 +162,7 @@ int esp_gdbstub_handle_command(unsigned char *cmd, int len) #ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS -static void init_task_info() +static void init_task_info(void) { unsigned tcb_size; s_scratch.task_count = uxTaskGetSnapshotAll(s_scratch.tasks, GDBSTUB_TASKS_NUM, &tcb_size); @@ -178,7 +178,7 @@ static bool get_task_handle(size_t index, TaskHandle_t *handle) } /** Get the index of the task running on the current CPU, and save the result */ -static void find_paniced_task_index() +static void find_paniced_task_index(void) { TaskHandle_t cur_handle = xTaskGetCurrentTaskHandleForCPU(xPortGetCoreID()); TaskHandle_t handle; diff --git a/components/esp_gdbstub/src/packet.c b/components/esp_gdbstub/src/packet.c index 9bf0c5d5a7..39e0c68831 100644 --- a/components/esp_gdbstub/src/packet.c +++ b/components/esp_gdbstub/src/packet.c @@ -21,7 +21,7 @@ static unsigned char s_cmd[GDBSTUB_CMD_BUFLEN]; static char s_chsum; // Send the start of a packet; reset checksum calculation. -void esp_gdbstub_send_start() +void esp_gdbstub_send_start(void) { s_chsum = 0; esp_gdbstub_putchar('$'); @@ -60,7 +60,7 @@ void esp_gdbstub_send_hex(int val, int bits) } // Finish sending a packet. -void esp_gdbstub_send_end() +void esp_gdbstub_send_end(void) { esp_gdbstub_putchar('#'); esp_gdbstub_send_hex(s_chsum, 8); diff --git a/components/esp_http_client/lib/http_header.c b/components/esp_http_client/lib/http_header.c index b771f6f6e9..65d7aa0ded 100644 --- a/components/esp_http_client/lib/http_header.c +++ b/components/esp_http_client/lib/http_header.c @@ -37,7 +37,7 @@ typedef struct http_header_item { STAILQ_HEAD(http_header, http_header_item); -http_header_handle_t http_header_init() +http_header_handle_t http_header_init(void) { http_header_handle_t header = calloc(1, sizeof(struct http_header)); HTTP_MEM_CHECK(TAG, header, return NULL); diff --git a/components/esp_http_client/lib/include/http_header.h b/components/esp_http_client/lib/include/http_header.h index 0a15372225..9d8ea3ad8d 100644 --- a/components/esp_http_client/lib/include/http_header.h +++ b/components/esp_http_client/lib/include/http_header.h @@ -32,7 +32,7 @@ typedef struct http_header_item *http_header_item_handle_t; * - http_header_handle_t * - NULL if any errors */ -http_header_handle_t http_header_init(); +http_header_handle_t http_header_init(void); /** * @brief Cleanup and free all http header pairs diff --git a/components/esp_http_server/src/httpd_sess.c b/components/esp_http_server/src/httpd_sess.c index c56c22efa2..8109475b4c 100644 --- a/components/esp_http_server/src/httpd_sess.c +++ b/components/esp_http_server/src/httpd_sess.c @@ -199,7 +199,7 @@ static int fd_is_valid(int fd) return fcntl(fd, F_GETFD) != -1 || errno != EBADF; } -static inline uint64_t httpd_sess_get_lru_counter() +static inline uint64_t httpd_sess_get_lru_counter(void) { static uint64_t lru_counter = 0; return lru_counter++; diff --git a/components/esp_http_server/src/port/esp32/osal.h b/components/esp_http_server/src/port/esp32/osal.h index 84dfb8c27a..f59c2bd311 100644 --- a/components/esp_http_server/src/port/esp32/osal.h +++ b/components/esp_http_server/src/port/esp32/osal.h @@ -43,7 +43,7 @@ static inline int httpd_os_thread_create(othread_t *thread, } /* Only self delete is supported */ -static inline void httpd_os_thread_delete() +static inline void httpd_os_thread_delete(void) { vTaskDelete(xTaskGetCurrentTaskHandle()); } @@ -53,7 +53,7 @@ static inline void httpd_os_thread_sleep(int msecs) vTaskDelay(msecs / portTICK_RATE_MS); } -static inline othread_t httpd_os_thread_handle() +static inline othread_t httpd_os_thread_handle(void) { return xTaskGetCurrentTaskHandle(); } diff --git a/components/esp_local_ctrl/include/esp_local_ctrl.h b/components/esp_local_ctrl/include/esp_local_ctrl.h index 53d062b104..9f4f89daa3 100644 --- a/components/esp_local_ctrl/include/esp_local_ctrl.h +++ b/components/esp_local_ctrl/include/esp_local_ctrl.h @@ -183,12 +183,12 @@ typedef struct esp_local_ctrl_transport esp_local_ctrl_transport_t; /** * @brief Function for obtaining BLE transport mode */ -const esp_local_ctrl_transport_t *esp_local_ctrl_get_transport_ble(); +const esp_local_ctrl_transport_t *esp_local_ctrl_get_transport_ble(void); /** * @brief Function for obtaining HTTPD transport mode */ -const esp_local_ctrl_transport_t *esp_local_ctrl_get_transport_httpd(); +const esp_local_ctrl_transport_t *esp_local_ctrl_get_transport_httpd(void); #define ESP_LOCAL_CTRL_TRANSPORT_BLE esp_local_ctrl_get_transport_ble() #define ESP_LOCAL_CTRL_TRANSPORT_HTTPD esp_local_ctrl_get_transport_httpd() diff --git a/components/esp_ringbuf/test/test_ringbuf.c b/components/esp_ringbuf/test/test_ringbuf.c index 376b119a78..62ca3c9b14 100644 --- a/components/esp_ringbuf/test/test_ringbuf.c +++ b/components/esp_ringbuf/test/test_ringbuf.c @@ -395,7 +395,7 @@ static void ringbuffer_isr(void *arg) } } -static void setup_timer() +static void setup_timer(void) { //Setup timer for ISR int timer_group = TIMER_GROUP; @@ -416,7 +416,7 @@ static void setup_timer() timer_isr_register(timer_group, timer_idx, ringbuffer_isr, NULL, 0, &ringbuffer_isr_handle); //Set ISR handler } -static void cleanup_timer() +static void cleanup_timer(void) { timer_disable_intr(TIMER_GROUP, TIMER_NUMBER); esp_intr_free(ringbuffer_isr_handle); @@ -570,7 +570,7 @@ static void rec_task(void *args) vTaskDelete(NULL); } -static void setup() +static void setup(void) { ets_printf("Size of test data: %d\n", CONT_DATA_LEN); tx_done = xSemaphoreCreateBinary(); //Semaphore to indicate send is done for a particular iteration @@ -579,7 +579,7 @@ static void setup() srand(SRAND_SEED); //Seed RNG } -static void cleanup() +static void cleanup(void) { //Cleanup vSemaphoreDelete(tx_done); @@ -669,7 +669,7 @@ TEST_CASE("Test static ring buffer SMP", "[esp_ringbuf]") /* -------------------------- Test ring buffer IRAM ------------------------- */ -static IRAM_ATTR __attribute__((noinline)) bool iram_ringbuf_test() +static IRAM_ATTR __attribute__((noinline)) bool iram_ringbuf_test(void) { bool result = true; diff --git a/components/esp_rom/include/esp32/rom/tbconsole.h b/components/esp_rom/include/esp32/rom/tbconsole.h index 891c2732a5..d6ca069cc7 100644 --- a/components/esp_rom/include/esp32/rom/tbconsole.h +++ b/components/esp_rom/include/esp32/rom/tbconsole.h @@ -18,7 +18,7 @@ extern "C" { #endif -void start_tb_console(); +void start_tb_console(void); #ifdef __cplusplus } diff --git a/components/esp_websocket_client/esp_websocket_client.c b/components/esp_websocket_client/esp_websocket_client.c index a066c288c9..cc77267d0a 100644 --- a/components/esp_websocket_client/esp_websocket_client.c +++ b/components/esp_websocket_client/esp_websocket_client.c @@ -92,7 +92,7 @@ struct esp_websocket_client { int buffer_size; }; -static uint64_t _tick_get_ms() +static uint64_t _tick_get_ms(void) { return esp_timer_get_time()/1000; } diff --git a/components/esp_wifi/include/esp_phy_init.h b/components/esp_wifi/include/esp_phy_init.h index 6783ff54b4..7f06bcb2e1 100644 --- a/components/esp_wifi/include/esp_phy_init.h +++ b/components/esp_wifi/include/esp_phy_init.h @@ -103,7 +103,7 @@ typedef enum{ * * @return pointer to PHY init data structure */ -const esp_phy_init_data_t* esp_phy_get_init_data(); +const esp_phy_init_data_t* esp_phy_get_init_data(void); /** * @brief Release PHY init data diff --git a/components/esp_wifi/include/phy.h b/components/esp_wifi/include/phy.h index 37066d00f9..1ee3f37dc5 100644 --- a/components/esp_wifi/include/phy.h +++ b/components/esp_wifi/include/phy.h @@ -44,7 +44,7 @@ int register_chipv7_phy(const esp_phy_init_data_t* init_data, esp_phy_calibratio * @brief Get the format version of calibration data used by PHY library. * @return Format version number, OR'ed with BIT(16) if PHY is in WIFI only mode. */ -uint32_t phy_get_rf_cal_version(); +uint32_t phy_get_rf_cal_version(void); /** * @brief Set RF/BB for only WIFI mode or coexist(WIFI & BT) mode diff --git a/components/esp_wifi/src/phy_init.c b/components/esp_wifi/src/phy_init.c index b36b5754f3..ae8da2f5dd 100644 --- a/components/esp_wifi/src/phy_init.c +++ b/components/esp_wifi/src/phy_init.c @@ -376,7 +376,7 @@ esp_err_t esp_modem_sleep_deregister(modem_sleep_module_t module) #if CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION #include "esp_partition.h" -const esp_phy_init_data_t* esp_phy_get_init_data() +const esp_phy_init_data_t* esp_phy_get_init_data(void) { const esp_partition_t* partition = esp_partition_find_first( ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_PHY, NULL); @@ -416,7 +416,7 @@ void esp_phy_release_init_data(const esp_phy_init_data_t* init_data) // phy_init_data.h will declare static 'phy_init_data' variable initialized with default init data -const esp_phy_init_data_t* esp_phy_get_init_data() +const esp_phy_init_data_t* esp_phy_get_init_data(void) { ESP_LOGD(TAG, "loading PHY init data from application binary"); return &phy_init_data; diff --git a/components/esp_wifi/src/wifi_init.c b/components/esp_wifi/src/wifi_init.c index 6564acc903..5082a77e48 100644 --- a/components/esp_wifi/src/wifi_init.c +++ b/components/esp_wifi/src/wifi_init.c @@ -39,7 +39,7 @@ wifi_mac_time_update_cb_t s_wifi_mac_time_update_cb = NULL; static const char* TAG = "wifi_init"; -static void __attribute__((constructor)) s_set_default_wifi_log_level() +static void __attribute__((constructor)) s_set_default_wifi_log_level(void) { /* WiFi libraries aren't compiled to know CONFIG_LOG_DEFAULT_LEVEL, so set it at runtime startup. Done here not in esp_wifi_init() to allow @@ -49,7 +49,7 @@ static void __attribute__((constructor)) s_set_default_wifi_log_level() esp_log_level_set("mesh", CONFIG_LOG_DEFAULT_LEVEL); } -static void esp_wifi_set_debug_log() +static void esp_wifi_set_debug_log(void) { /* set WiFi log level and module */ #if CONFIG_ESP32_WIFI_DEBUG_LOG_ENABLE diff --git a/components/esp_wifi/test/test_phy_rtc.c b/components/esp_wifi/test/test_phy_rtc.c index 9506599248..133a62c355 100644 --- a/components/esp_wifi/test/test_phy_rtc.c +++ b/components/esp_wifi/test/test_phy_rtc.c @@ -15,8 +15,8 @@ //Function just extern, need not test extern void bt_bb_init_cmplx(void); -extern void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu(); -extern void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu(); +extern void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu(void); +extern void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu(void); //Functions in librtc.a called by WIFI or Blutooth directly in ISR extern void bt_bb_init_cmplx_reg(void); diff --git a/components/espcoredump/include/esp_core_dump.h b/components/espcoredump/include/esp_core_dump.h index e19b45c98a..0e8020086e 100644 --- a/components/espcoredump/include/esp_core_dump.h +++ b/components/espcoredump/include/esp_core_dump.h @@ -27,7 +27,7 @@ * * @note Should be called at system startup. */ -void esp_core_dump_init(); +void esp_core_dump_init(void); /** * @brief Saves core dump to flash. diff --git a/components/espcoredump/include_core_dump/esp_core_dump_priv.h b/components/espcoredump/include_core_dump/esp_core_dump_priv.h index a13dd1707d..59568e0043 100644 --- a/components/espcoredump/include_core_dump/esp_core_dump_priv.h +++ b/components/espcoredump/include_core_dump/esp_core_dump_priv.h @@ -82,7 +82,7 @@ typedef struct _core_dump_task_header_t #if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH // Core dump flash init function -void esp_core_dump_flash_init(); +void esp_core_dump_flash_init(void); #endif diff --git a/components/espcoredump/src/core_dump_common.c b/components/espcoredump/src/core_dump_common.c index bbd3e29ce1..056f3417b7 100644 --- a/components/espcoredump/src/core_dump_common.c +++ b/components/espcoredump/src/core_dump_common.c @@ -153,7 +153,7 @@ inline void esp_core_dump_write(void *frame, core_dump_write_config_t *write_cfg #endif -void esp_core_dump_init() +void esp_core_dump_init(void) { #if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH esp_core_dump_flash_init(); diff --git a/components/espcoredump/src/core_dump_flash.c b/components/espcoredump/src/core_dump_flash.c index dd48d5ba8e..9c2ac78766 100644 --- a/components/espcoredump/src/core_dump_flash.c +++ b/components/espcoredump/src/core_dump_flash.c @@ -50,7 +50,7 @@ static inline core_dump_crc_t esp_core_dump_calc_flash_config_crc(void) return crc32_le(0, (uint8_t const *)&s_core_flash_config.partition, sizeof(s_core_flash_config.partition)); } -void esp_core_dump_flash_init() +void esp_core_dump_flash_init(void) { const esp_partition_t *core_part; diff --git a/components/espcoredump/src/core_dump_uart.c b/components/espcoredump/src/core_dump_uart.c index d3afbe5d05..2a2aa2d5fa 100644 --- a/components/espcoredump/src/core_dump_uart.c +++ b/components/espcoredump/src/core_dump_uart.c @@ -81,7 +81,7 @@ static esp_err_t esp_core_dump_uart_write_data(void *priv, void * data, uint32_t return err; } -static int esp_core_dump_uart_get_char() { +static int esp_core_dump_uart_get_char(void) { int i; uint32_t reg = (READ_PERI_REG(UART_STATUS_REG(0)) >> UART_RXFIFO_CNT_S) & UART_RXFIFO_CNT; if (reg) { diff --git a/components/espcoredump/test/test_core_dump.c b/components/espcoredump/test/test_core_dump.c index 024d2301db..ad6758b672 100644 --- a/components/espcoredump/test/test_core_dump.c +++ b/components/espcoredump/test/test_core_dump.c @@ -20,7 +20,7 @@ volatile unsigned long crash_flags = TCI_UNALIGN_PTR; -void bad_ptr_func() +void bad_ptr_func(void) { unsigned long *ptr = (unsigned long *)0; volatile int cnt = 0; @@ -47,7 +47,7 @@ void bad_ptr_task(void *pvParameter) fflush(stdout); } -void recur_func() +void recur_func(void) { static int rec_cnt; unsigned short *ptr = (unsigned short *)0x5; diff --git a/components/fatfs/test/test_fatfs_rawflash.c b/components/fatfs/test/test_fatfs_rawflash.c index 66412451a3..ca949e1ab5 100644 --- a/components/fatfs/test/test_fatfs_rawflash.c +++ b/components/fatfs/test/test_fatfs_rawflash.c @@ -60,7 +60,7 @@ static void test_setup(size_t max_files) TEST_ESP_OK(esp_vfs_fat_rawflash_mount("/spiflash", "flash_test", &mount_config)); } -static void test_teardown() +static void test_teardown(void) { TEST_ESP_OK(esp_vfs_fat_rawflash_unmount("/spiflash","flash_test")); } diff --git a/components/fatfs/test/test_fatfs_spiflash.c b/components/fatfs/test/test_fatfs_spiflash.c index f848c31ca8..64dbe4ff0d 100644 --- a/components/fatfs/test/test_fatfs_spiflash.c +++ b/components/fatfs/test/test_fatfs_spiflash.c @@ -32,7 +32,7 @@ static wl_handle_t s_test_wl_handle; -static void test_setup() +static void test_setup(void) { esp_vfs_fat_sdmmc_mount_config_t mount_config = { .format_if_mount_failed = true, @@ -42,7 +42,7 @@ static void test_setup() TEST_ESP_OK(esp_vfs_fat_spiflash_mount("/spiflash", NULL, &mount_config, &s_test_wl_handle)); } -static void test_teardown() +static void test_teardown(void) { TEST_ESP_OK(esp_vfs_fat_spiflash_unmount("/spiflash", s_test_wl_handle)); } diff --git a/components/fatfs/vfs/esp_vfs_fat.h b/components/fatfs/vfs/esp_vfs_fat.h index a2a05951e1..d3f9caa688 100644 --- a/components/fatfs/vfs/esp_vfs_fat.h +++ b/components/fatfs/vfs/esp_vfs_fat.h @@ -63,7 +63,7 @@ esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, * - ESP_OK on success * - ESP_ERR_INVALID_STATE if FATFS is not registered in VFS */ -esp_err_t esp_vfs_fat_unregister() __attribute__((deprecated)); +esp_err_t esp_vfs_fat_unregister(void) __attribute__((deprecated)); /** * @brief Un-register FATFS from VFS @@ -160,7 +160,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, * - ESP_OK on success * - ESP_ERR_INVALID_STATE if esp_vfs_fat_sdmmc_mount hasn't been called */ -esp_err_t esp_vfs_fat_sdmmc_unmount(); +esp_err_t esp_vfs_fat_sdmmc_unmount(void); /** * @brief Convenience function to initialize FAT filesystem in SPI flash and register it in VFS diff --git a/components/fatfs/vfs/vfs_fat.c b/components/fatfs/vfs/vfs_fat.c index 511be8c56e..e4be415169 100644 --- a/components/fatfs/vfs/vfs_fat.c +++ b/components/fatfs/vfs/vfs_fat.c @@ -104,7 +104,7 @@ static size_t find_context_index_by_path(const char* base_path) return FF_VOLUMES; } -static size_t find_unused_context_index() +static size_t find_unused_context_index(void) { for(size_t i=0; istart(); // Disables flash cache diff --git a/components/libsodium/test/test_sodium.c b/components/libsodium/test/test_sodium.c index 7a9f096dad..5c2e26b238 100644 --- a/components/libsodium/test/test_sodium.c +++ b/components/libsodium/test/test_sodium.c @@ -9,7 +9,7 @@ internal filesystem storage. */ -extern int aead_chacha20poly1305_xmain(); +extern int aead_chacha20poly1305_xmain(void); TEST_CASE("aead_chacha20poly1305 test vectors", "[libsodium]") { @@ -17,7 +17,7 @@ TEST_CASE("aead_chacha20poly1305 test vectors", "[libsodium]") TEST_ASSERT_EQUAL(0, aead_chacha20poly1305_xmain()); } -extern int chacha20_xmain(); +extern int chacha20_xmain(void); TEST_CASE("chacha20 test vectors", "[libsodium]") { @@ -25,8 +25,8 @@ TEST_CASE("chacha20 test vectors", "[libsodium]") TEST_ASSERT_EQUAL(0, chacha20_xmain()); } -extern int box_xmain(); -extern int box2_xmain(); +extern int box_xmain(void); +extern int box2_xmain(void); TEST_CASE("box tests", "[libsodium]") { @@ -37,7 +37,7 @@ TEST_CASE("box tests", "[libsodium]") TEST_ASSERT_EQUAL(0, box2_xmain()); } -extern int ed25519_convert_xmain(); +extern int ed25519_convert_xmain(void); TEST_CASE("ed25519_convert tests", "[libsodium]") { @@ -45,7 +45,7 @@ TEST_CASE("ed25519_convert tests", "[libsodium]") TEST_ASSERT_EQUAL(0, ed25519_convert_xmain() ); } -extern int sign_xmain(); +extern int sign_xmain(void); TEST_CASE("sign tests", "[libsodium]") { @@ -53,7 +53,7 @@ TEST_CASE("sign tests", "[libsodium]") TEST_ASSERT_EQUAL(0, sign_xmain() ); } -extern int hash_xmain(); +extern int hash_xmain(void); TEST_CASE("hash tests", "[libsodium]") { diff --git a/components/log/log.c b/components/log/log.c index c59469cc02..fbbdf24062 100644 --- a/components/log/log.c +++ b/components/log/log.c @@ -104,7 +104,7 @@ static inline void add_to_cache(const char* tag, esp_log_level_t level); static void heap_bubble_down(int index); static inline void heap_swap(int i, int j); static inline bool should_output(esp_log_level_t level_for_message, esp_log_level_t level_for_tag); -static inline void clear_log_level_list(); +static inline void clear_log_level_list(void); vprintf_like_t esp_log_set_vprintf(vprintf_like_t func) { @@ -172,7 +172,7 @@ void esp_log_level_set(const char* tag, esp_log_level_t level) xSemaphoreGive(s_log_mutex); } -void clear_log_level_list() +void clear_log_level_list(void) { uncached_tag_entry_t *it; while((it = SLIST_FIRST(&s_log_tags)) != NULL) { @@ -325,14 +325,14 @@ static inline void heap_swap(int i, int j) //as a workaround before the interface for this variable extern uint32_t g_ticks_per_us_pro; -uint32_t ATTR esp_log_early_timestamp() +uint32_t ATTR esp_log_early_timestamp(void) { return xthal_get_ccount() / (g_ticks_per_us_pro * 1000); } #ifndef BOOTLOADER_BUILD -uint32_t IRAM_ATTR esp_log_timestamp() +uint32_t IRAM_ATTR esp_log_timestamp(void) { if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) { return esp_log_early_timestamp(); @@ -346,7 +346,7 @@ uint32_t IRAM_ATTR esp_log_timestamp() #else -uint32_t esp_log_timestamp() __attribute__((alias("esp_log_early_timestamp"))); +uint32_t esp_log_timestamp(void) __attribute__((alias("esp_log_early_timestamp"))); #endif //BOOTLOADER_BUILD diff --git a/components/lwip/apps/dhcpserver/dhcpserver.c b/components/lwip/apps/dhcpserver/dhcpserver.c index df6a2af022..48adc3b98d 100644 --- a/components/lwip/apps/dhcpserver/dhcpserver.c +++ b/components/lwip/apps/dhcpserver/dhcpserver.c @@ -1322,7 +1322,7 @@ dhcps_dns_setserver(const ip_addr_t *dnsserver) * Returns : ip4_addr_t *******************************************************************************/ ip4_addr_t -dhcps_dns_getserver() +dhcps_dns_getserver(void) { return dns_server; } diff --git a/components/lwip/include/apps/dhcpserver/dhcpserver.h b/components/lwip/include/apps/dhcpserver/dhcpserver.h index a6ad51d995..1aef8aaca2 100644 --- a/components/lwip/include/apps/dhcpserver/dhcpserver.h +++ b/components/lwip/include/apps/dhcpserver/dhcpserver.h @@ -88,7 +88,7 @@ void *dhcps_option_info(u8_t op_id, u32_t opt_len); void dhcps_set_option_info(u8_t op_id, void *opt_info, u32_t opt_len); bool dhcp_search_ip_on_mac(u8_t *mac, ip4_addr_t *ip); void dhcps_dns_setserver(const ip_addr_t *dnsserver); -ip4_addr_t dhcps_dns_getserver(); +ip4_addr_t dhcps_dns_getserver(void); void dhcps_set_new_lease_cb(dhcps_cb_t cb); #endif diff --git a/components/lwip/port/esp32/include/arch/vfs_lwip.h b/components/lwip/port/esp32/include/arch/vfs_lwip.h index 1957304b9f..8a037c6ff2 100644 --- a/components/lwip/port/esp32/include/arch/vfs_lwip.h +++ b/components/lwip/port/esp32/include/arch/vfs_lwip.h @@ -16,7 +16,7 @@ extern "C" { #endif -void esp_vfs_lwip_sockets_register(); +void esp_vfs_lwip_sockets_register(void); #ifdef __cplusplus } diff --git a/components/lwip/port/esp32/vfs_lwip.c b/components/lwip/port/esp32/vfs_lwip.c index ffd3e79e1f..9ef74784cc 100644 --- a/components/lwip/port/esp32/vfs_lwip.c +++ b/components/lwip/port/esp32/vfs_lwip.c @@ -39,7 +39,7 @@ static void lwip_stop_socket_select_isr(void *sem, BaseType_t *woken) } } -static void *lwip_get_socket_select_semaphore() +static void *lwip_get_socket_select_semaphore(void) { /* Calling this from the same process as select() will ensure that the semaphore won't be allocated from * ISR (lwip_stop_socket_select_isr). @@ -57,7 +57,7 @@ static int lwip_ioctl_r_wrapper(int fd, int cmd, va_list args) return lwip_ioctl(fd, cmd, va_arg(args, void *)); } -void esp_vfs_lwip_sockets_register() +void esp_vfs_lwip_sockets_register(void) { esp_vfs_t vfs = { .flags = ESP_VFS_FLAG_DEFAULT, diff --git a/components/lwip/test_afl_host/dhcp_di.h b/components/lwip/test_afl_host/dhcp_di.h index c37a3e1b61..2f3b2cc558 100644 --- a/components/lwip/test_afl_host/dhcp_di.h +++ b/components/lwip/test_afl_host/dhcp_di.h @@ -23,7 +23,7 @@ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_a void (*dhcp_test_static_dhcp_recv)(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) = NULL; -void dhcp_test_init_di() +void dhcp_test_init_di(void) { dhcp_test_static_dhcp_recv = dhcp_recv; } diff --git a/components/lwip/test_afl_host/dhcpserver_di.h b/components/lwip/test_afl_host/dhcpserver_di.h index 48cce58f63..a05a885787 100644 --- a/components/lwip/test_afl_host/dhcpserver_di.h +++ b/components/lwip/test_afl_host/dhcpserver_di.h @@ -13,7 +13,7 @@ static void handle_dhcp(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip void (*dhcp_test_static_handle_hdcp)(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) = NULL; -void dhcp_test_init_di() +void dhcp_test_init_di(void) { dhcp_test_static_handle_hdcp = handle_dhcp; } diff --git a/components/lwip/test_afl_host/dns_di.h b/components/lwip/test_afl_host/dns_di.h index 0479f36a8d..a02b464aae 100644 --- a/components/lwip/test_afl_host/dns_di.h +++ b/components/lwip/test_afl_host/dns_di.h @@ -35,7 +35,7 @@ static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, const ip_addr void (*dns_test_static_dns_recv)(void *s, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) = NULL; err_t (*dns_test_static_dns_enqueue)(const char *name, size_t hostnamelen, dns_found_callback found, void *callback_arg, u8_t dns_addrtype) = NULL; -void dns_test_init_di() +void dns_test_init_di(void) { dns_test_static_dns_recv = dns_recv; dns_test_static_dns_enqueue = dns_enqueue; diff --git a/components/lwip/test_afl_host/test_dhcp_client.c b/components/lwip/test_afl_host/test_dhcp_client.c index fee5d01b19..681189ea00 100644 --- a/components/lwip/test_afl_host/test_dhcp_client.c +++ b/components/lwip/test_afl_host/test_dhcp_client.c @@ -22,7 +22,7 @@ ip4_addr_t server_ip; // // Dependency injected test functions void dhcp_test_dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); -void dhcp_test_init_di(); +void dhcp_test_init_di(void); // // Test starts here diff --git a/components/lwip/test_afl_host/test_dhcp_server.c b/components/lwip/test_afl_host/test_dhcp_server.c index e19cf28e7b..dc8995280e 100644 --- a/components/lwip/test_afl_host/test_dhcp_server.c +++ b/components/lwip/test_afl_host/test_dhcp_server.c @@ -14,7 +14,7 @@ void dhcp_test_dhcps_cb (u8_t client_ip[4]) {} // Dependency injected static function to pass the packet into parser void dhcp_test_handle_dhcp(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); -void dhcp_test_init_di(); +void dhcp_test_init_di(void); // // Test starts here diff --git a/components/lwip/test_afl_host/test_dns.c b/components/lwip/test_afl_host/test_dns.c index 1e9a588150..df74d7d86d 100644 --- a/components/lwip/test_afl_host/test_dns.c +++ b/components/lwip/test_afl_host/test_dns.c @@ -21,7 +21,7 @@ ip4_addr_t server_ip; void dns_test_dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); void dns_test_inject_port_and_txid(int port, int txid); -void dns_test_init_di(); +void dns_test_init_di(void); err_t dns_test_dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found, void *callback_arg, u8_t dns_addrtype); // diff --git a/components/mbedtls/port/esp_bignum.c b/components/mbedtls/port/esp_bignum.c index 50e1d9f364..09bb774b99 100644 --- a/components/mbedtls/port/esp_bignum.c +++ b/components/mbedtls/port/esp_bignum.c @@ -73,7 +73,7 @@ static IRAM_ATTR void rsa_complete_isr(void *arg) } } -static void rsa_isr_initialise() +static void rsa_isr_initialise(void) { if (op_complete_sem == NULL) { op_complete_sem = xSemaphoreCreateBinary(); diff --git a/components/mbedtls/test/test_apb_dport_access.c b/components/mbedtls/test/test_apb_dport_access.c index 392effc91f..07203ac1ea 100644 --- a/components/mbedtls/test/test_apb_dport_access.c +++ b/components/mbedtls/test/test_apb_dport_access.c @@ -17,7 +17,7 @@ static void apb_access_loop_task(void *ignore); static volatile bool apb_access_corrupt; static TaskHandle_t apb_task_handle; -void start_apb_access_loop() +void start_apb_access_loop(void) { apb_access_corrupt = false; xTaskCreatePinnedToCore(apb_access_loop_task, "accessAPB", 2048, NULL, @@ -25,7 +25,7 @@ void start_apb_access_loop() &apb_task_handle, !UNITY_FREERTOS_CPU); } -void verify_apb_access_loop() +void verify_apb_access_loop(void) { vTaskDelete(apb_task_handle); apb_task_handle = NULL; @@ -45,11 +45,11 @@ static void apb_access_loop_task(void *ignore) #else /*CONFIG_FREERTOS_UNICORE */ -void start_apb_access_loop() +void start_apb_access_loop(void) { } -void verify_apb_access_loop() +void verify_apb_access_loop(void) { } diff --git a/components/mbedtls/test/test_apb_dport_access.h b/components/mbedtls/test/test_apb_dport_access.h index a974c2d424..8f30e0465a 100644 --- a/components/mbedtls/test/test_apb_dport_access.h +++ b/components/mbedtls/test/test_apb_dport_access.h @@ -10,9 +10,9 @@ Does nothing in unicore mode. */ -void start_apb_access_loop(); +void start_apb_access_loop(void); /* verify_apb_access_loop() kills the task started by start_apb_access_loop() and verifies that none of the APB reads were corrupted by unsafe DPORT reads. */ -void verify_apb_access_loop(); +void verify_apb_access_loop(void); diff --git a/components/mdns/include/mdns.h b/components/mdns/include/mdns.h index 4370969d70..a30534640d 100644 --- a/components/mdns/include/mdns.h +++ b/components/mdns/include/mdns.h @@ -85,13 +85,13 @@ typedef struct mdns_result_s { * - ESP_ERR_NO_MEM on memory error * - ESP_FAIL when failed to start mdns task */ -esp_err_t mdns_init(); +esp_err_t mdns_init(void); /** * @brief Stop and free mDNS server * */ -void mdns_free(); +void mdns_free(void); /** * @brief Set the hostname for mDNS server @@ -235,7 +235,7 @@ esp_err_t mdns_service_txt_item_remove(const char * service_type, const char * p * - ESP_OK success * - ESP_ERR_INVALID_ARG Parameter error */ -esp_err_t mdns_service_remove_all(); +esp_err_t mdns_service_remove_all(void); /** * @brief Query mDNS for host or service diff --git a/components/mdns/include/mdns_console.h b/components/mdns/include/mdns_console.h index 5c8b0b5a49..059e03de5a 100644 --- a/components/mdns/include/mdns_console.h +++ b/components/mdns/include/mdns_console.h @@ -17,6 +17,6 @@ /** * @brief Register MDNS functions with the console component */ -void mdns_console_register(); +void mdns_console_register(void); #endif /* _MDNS_CONSOLE_H_ */ diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 92909e2deb..7331353d26 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -32,7 +32,7 @@ static const char *TAG = "MDNS"; static volatile TaskHandle_t _mdns_service_task_handle = NULL; static SemaphoreHandle_t _mdns_service_semaphore = NULL; -static void _mdns_search_finish_done(); +static void _mdns_search_finish_done(void); static mdns_search_once_t * _mdns_search_find_from(mdns_search_once_t * search, mdns_name_t * name, uint16_t type, tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); static void _mdns_search_result_add_ip(mdns_search_once_t * search, const char * hostname, ip_addr_t * ip, tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); static void _mdns_search_result_add_srv(mdns_search_once_t * search, const char * hostname, uint16_t port, tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); @@ -1010,7 +1010,7 @@ static void _mdns_schedule_tx_packet(mdns_tx_packet_t * packet, uint32_t ms_afte /** * @brief free all packets scheduled for sending */ -static void _mdns_clear_tx_queue_head() +static void _mdns_clear_tx_queue_head(void) { mdns_tx_packet_t * q; while (_mdns_server->tx_queue_head) { @@ -1699,7 +1699,7 @@ static void _mdns_send_final_bye(bool include_ip) /** * @brief Stop the responder on all services without instance */ -static void _mdns_send_bye_all_pcbs_no_instance() +static void _mdns_send_bye_all_pcbs_no_instance(void) { size_t srv_count = 0; mdns_srv_item_t * a = _mdns_server->services; @@ -1727,7 +1727,7 @@ static void _mdns_send_bye_all_pcbs_no_instance() /** * @brief Restart the responder on all services without instance */ -static void _mdns_restart_all_pcbs_no_instance() +static void _mdns_restart_all_pcbs_no_instance(void) { size_t srv_count = 0; mdns_srv_item_t * a = _mdns_server->services; @@ -1755,7 +1755,7 @@ static void _mdns_restart_all_pcbs_no_instance() /** * @brief Restart the responder on all active PCBs */ -static void _mdns_restart_all_pcbs() +static void _mdns_restart_all_pcbs(void) { _mdns_clear_tx_queue_head(); size_t srv_count = 0; @@ -3209,7 +3209,7 @@ static void _mdns_search_add(mdns_search_once_t * search) /** * @brief Called from parser to finish any searches that have reached maximum results */ -static void _mdns_search_finish_done() +static void _mdns_search_finish_done(void) { mdns_search_once_t * search = _mdns_server->search_once; mdns_search_once_t * s = NULL; @@ -3931,7 +3931,7 @@ static esp_err_t _mdns_send_search_action(mdns_action_type_t type, mdns_search_o * if it is scheduled to be transmitted, then pushes the packet to action queue to be handled. * */ -static void _mdns_scheduler_run() +static void _mdns_scheduler_run(void) { MDNS_SERVICE_LOCK(); mdns_tx_packet_t * p = _mdns_server->tx_queue_head; @@ -3966,7 +3966,7 @@ static void _mdns_scheduler_run() /** * @brief Called from timer task to run active searches */ -static void _mdns_search_run() +static void _mdns_search_run(void) { MDNS_SERVICE_LOCK(); mdns_search_once_t * s = _mdns_server->search_once; @@ -4025,7 +4025,7 @@ static void _mdns_timer_cb(void * arg) _mdns_search_run(); } -static esp_err_t _mdns_start_timer(){ +static esp_err_t _mdns_start_timer(void){ esp_timer_create_args_t timer_conf = { .callback = _mdns_timer_cb, .arg = NULL, @@ -4039,7 +4039,7 @@ static esp_err_t _mdns_start_timer(){ return esp_timer_start_periodic(_mdns_server->timer_handle, MDNS_TIMER_PERIOD_US); } -static esp_err_t _mdns_stop_timer(){ +static esp_err_t _mdns_stop_timer(void){ esp_err_t err = ESP_OK; if (_mdns_server->timer_handle) { err = esp_timer_stop(_mdns_server->timer_handle); @@ -4058,7 +4058,7 @@ static esp_err_t _mdns_stop_timer(){ * - ESP_OK on success * - ESP_FAIL on error */ -static esp_err_t _mdns_service_task_start() +static esp_err_t _mdns_service_task_start(void) { if (!_mdns_service_semaphore) { _mdns_service_semaphore = xSemaphoreCreateMutex(); @@ -4091,7 +4091,7 @@ static esp_err_t _mdns_service_task_start() * @return * - ESP_OK */ -static esp_err_t _mdns_service_task_stop() +static esp_err_t _mdns_service_task_stop(void) { _mdns_stop_timer(); if (_mdns_service_task_handle) { @@ -4146,7 +4146,7 @@ static void event_handler(void* arg, esp_event_base_t event_base, } } -esp_err_t mdns_init() +esp_err_t mdns_init(void) { esp_err_t err = ESP_OK; @@ -4222,7 +4222,7 @@ free_server: return err; } -void mdns_free() +void mdns_free(void) { uint8_t i, j; if (!_mdns_server) { @@ -4571,7 +4571,7 @@ esp_err_t mdns_service_remove(const char * service, const char * proto) return ESP_OK; } -esp_err_t mdns_service_remove_all() +esp_err_t mdns_service_remove_all(void) { if (!_mdns_server) { return ESP_ERR_INVALID_ARG; diff --git a/components/mdns/mdns_console.c b/components/mdns/mdns_console.c index 17bffa55b7..adbbf0b8f1 100644 --- a/components/mdns/mdns_console.c +++ b/components/mdns/mdns_console.c @@ -99,7 +99,7 @@ static int cmd_mdns_query_a(int argc, char** argv) return 0; } -static void register_mdns_query_a() +static void register_mdns_query_a(void) { mdns_query_a_args.hostname = arg_str1(NULL, NULL, "", "Hostname that is searched for"); mdns_query_a_args.timeout = arg_int0("t", "timeout", "", "Timeout for this query"); @@ -156,7 +156,7 @@ static int cmd_mdns_query_aaaa(int argc, char** argv) return 0; } -static void register_mdns_query_aaaa() +static void register_mdns_query_aaaa(void) { mdns_query_a_args.hostname = arg_str1(NULL, NULL, "", "Hostname that is searched for"); mdns_query_a_args.timeout = arg_int0("t", "timeout", "", "Timeout for this query"); @@ -215,7 +215,7 @@ static int cmd_mdns_query_srv(int argc, char** argv) return 0; } -static void register_mdns_query_srv() +static void register_mdns_query_srv(void) { mdns_query_srv_args.instance = arg_str1(NULL, NULL, "", "Instance to search for"); mdns_query_srv_args.service = arg_str1(NULL, NULL, "", "Service to search for (ex. _http, _smb, etc.)"); @@ -277,7 +277,7 @@ static int cmd_mdns_query_txt(int argc, char** argv) return 0; } -static void register_mdns_query_txt() +static void register_mdns_query_txt(void) { mdns_query_txt_args.instance = arg_str1(NULL, NULL, "", "Instance to search for"); mdns_query_txt_args.service = arg_str1(NULL, NULL, "", "Service to search for (ex. _http, _smb, etc.)"); @@ -343,7 +343,7 @@ static int cmd_mdns_query_ptr(int argc, char** argv) return 0; } -static void register_mdns_query_ptr() +static void register_mdns_query_ptr(void) { mdns_query_ptr_args.service = arg_str1(NULL, NULL, "", "Service to search for (ex. _http, _smb, etc.)"); mdns_query_ptr_args.proto = arg_str1(NULL, NULL, "", "Protocol to search for (_tcp, _udp, etc.)"); @@ -412,7 +412,7 @@ static int cmd_mdns_query_ip(int argc, char** argv) return 0; } -static void register_mdns_query_ip() +static void register_mdns_query_ip(void) { mdns_query_ip_args.hostname = arg_str1(NULL, NULL, "", "Hostname that is searched for"); mdns_query_ip_args.timeout = arg_int0("t", "timeout", "", "Timeout for this query"); @@ -479,7 +479,7 @@ static int cmd_mdns_query_svc(int argc, char** argv) return 0; } -static void register_mdns_query_svc() +static void register_mdns_query_svc(void) { mdns_query_svc_args.instance = arg_str1(NULL, NULL, "", "Instance to search for"); mdns_query_svc_args.service = arg_str1(NULL, NULL, "", "Service to search for (ex. _http, _smb, etc.)"); @@ -528,7 +528,7 @@ static int cmd_mdns_init(int argc, char** argv) return 0; } -static void register_mdns_init() +static void register_mdns_init(void) { mdns_init_args.hostname = arg_str0("h", "hostname", "", "Hostname that the server will advertise"); mdns_init_args.instance = arg_str0("i", "instance", "", "Default instance name for services"); @@ -551,7 +551,7 @@ static int cmd_mdns_free(int argc, char** argv) return 0; } -static void register_mdns_free() +static void register_mdns_free(void) { const esp_console_cmd_t cmd_free = { .command = "mdns_free", @@ -586,7 +586,7 @@ static int cmd_mdns_set_hostname(int argc, char** argv) return 0; } -static void register_mdns_set_hostname() +static void register_mdns_set_hostname(void) { mdns_set_hostname_args.hostname = arg_str1(NULL, NULL, "", "Hostname that the server will advertise"); mdns_set_hostname_args.end = arg_end(2); @@ -624,7 +624,7 @@ static int cmd_mdns_set_instance(int argc, char** argv) return 0; } -static void register_mdns_set_instance() +static void register_mdns_set_instance(void) { mdns_set_instance_args.instance = arg_str1(NULL, NULL, "", "Default instance name for services"); mdns_set_instance_args.end = arg_end(2); @@ -733,7 +733,7 @@ static int cmd_mdns_service_add(int argc, char** argv) return 0; } -static void register_mdns_service_add() +static void register_mdns_service_add(void) { mdns_add_args.service = arg_str1(NULL, NULL, "", "MDNS Service"); mdns_add_args.proto = arg_str1(NULL, NULL, "", "IP Protocol"); @@ -776,7 +776,7 @@ static int cmd_mdns_service_remove(int argc, char** argv) return 0; } -static void register_mdns_service_remove() +static void register_mdns_service_remove(void) { mdns_remove_args.service = arg_str1(NULL, NULL, "", "MDNS Service"); mdns_remove_args.proto = arg_str1(NULL, NULL, "", "IP Protocol"); @@ -817,7 +817,7 @@ static int cmd_mdns_service_instance_set(int argc, char** argv) return 0; } -static void register_mdns_service_instance_set() +static void register_mdns_service_instance_set(void) { mdns_service_instance_set_args.service = arg_str1(NULL, NULL, "", "MDNS Service"); mdns_service_instance_set_args.proto = arg_str1(NULL, NULL, "", "IP Protocol"); @@ -858,7 +858,7 @@ static int cmd_mdns_service_port_set(int argc, char** argv) { return 0; } -static void register_mdns_service_port_set() +static void register_mdns_service_port_set(void) { mdns_service_port_set_args.service = arg_str1(NULL, NULL, "", "MDNS Service"); mdns_service_port_set_args.proto = arg_str1(NULL, NULL, "", "IP Protocol"); @@ -910,7 +910,7 @@ static int cmd_mdns_service_txt_replace(int argc, char** argv) return 0; } -static void register_mdns_service_txt_replace() +static void register_mdns_service_txt_replace(void) { mdns_txt_replace_args.service = arg_str1(NULL, NULL, "", "MDNS Service"); mdns_txt_replace_args.proto = arg_str1(NULL, NULL, "", "IP Protocol"); @@ -953,7 +953,7 @@ static int cmd_mdns_service_txt_set(int argc, char** argv) return 0; } -static void register_mdns_service_txt_set() +static void register_mdns_service_txt_set(void) { mdns_txt_set_args.service = arg_str1(NULL, NULL, "", "MDNS Service"); mdns_txt_set_args.proto = arg_str1(NULL, NULL, "", "IP Protocol"); @@ -996,7 +996,7 @@ static int cmd_mdns_service_txt_remove(int argc, char** argv) return 0; } -static void register_mdns_service_txt_remove() +static void register_mdns_service_txt_remove(void) { mdns_txt_remove_args.service = arg_str1(NULL, NULL, "", "MDNS Service"); mdns_txt_remove_args.proto = arg_str1(NULL, NULL, "", "IP Protocol"); @@ -1020,7 +1020,7 @@ static int cmd_mdns_service_remove_all(int argc, char** argv) return 0; } -static void register_mdns_service_remove_all() +static void register_mdns_service_remove_all(void) { const esp_console_cmd_t cmd_free = { .command = "mdns_service_remove_all", @@ -1033,7 +1033,7 @@ static void register_mdns_service_remove_all() ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_free) ); } -void mdns_console_register() +void mdns_console_register(void) { register_mdns_init(); register_mdns_free(); diff --git a/components/mdns/mdns_networking.c b/components/mdns/mdns_networking.c index bb3400f0af..ac69b093dc 100644 --- a/components/mdns/mdns_networking.c +++ b/components/mdns/mdns_networking.c @@ -23,7 +23,7 @@ static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip /** * @brief Low level UDP PCB Initialize */ -static esp_err_t _udp_pcb_main_init() +static esp_err_t _udp_pcb_main_init(void) { if(_pcb_main) { return ESP_OK; @@ -47,7 +47,7 @@ static esp_err_t _udp_pcb_main_init() /** * @brief Low level UDP PCB Free */ -static void _udp_pcb_main_deinit() +static void _udp_pcb_main_deinit(void) { if(_pcb_main){ udp_recv(_pcb_main, NULL, NULL); @@ -177,7 +177,7 @@ static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip /** * @brief Check if any of the interfaces is up */ -static bool _udp_pcb_is_in_use(){ +static bool _udp_pcb_is_in_use(void){ int i, p; for (i=0; isize); } -extern "C" esp_err_t nvs_flash_erase() +extern "C" esp_err_t nvs_flash_erase(void) { return nvs_flash_erase_partition(NVS_DEFAULT_PART_NAME); } diff --git a/components/openssl/include/internal/ssl_x509.h b/components/openssl/include/internal/ssl_x509.h index 877c4fbb77..e58439724c 100644 --- a/components/openssl/include/internal/ssl_x509.h +++ b/components/openssl/include/internal/ssl_x509.h @@ -159,7 +159,7 @@ BIO *BIO_new(void * method); /** * @brief get the memory BIO method function */ -void *BIO_s_mem(); +void *BIO_s_mem(void); /** * @brief free a BIO object diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index 0b49bb8fed..91c2a64efa 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -409,7 +409,7 @@ failed: /** * @brief get the memory BIO method function */ -void *BIO_s_mem() { +void *BIO_s_mem(void) { return NULL; } diff --git a/components/protocomm/include/common/protocomm.h b/components/protocomm/include/common/protocomm.h index cb11a0b132..b5c57992cc 100644 --- a/components/protocomm/include/common/protocomm.h +++ b/components/protocomm/include/common/protocomm.h @@ -52,7 +52,7 @@ typedef struct protocomm protocomm_t; * - protocomm_t* : On success * - NULL : No memory for allocating new instance */ -protocomm_t *protocomm_new(); +protocomm_t *protocomm_new(void); /** * @brief Delete a protocomm instance diff --git a/components/protocomm/src/common/protocomm.c b/components/protocomm/src/common/protocomm.c index e55ad7b890..683e360903 100644 --- a/components/protocomm/src/common/protocomm.c +++ b/components/protocomm/src/common/protocomm.c @@ -26,7 +26,7 @@ static const char *TAG = "protocomm"; -protocomm_t *protocomm_new() +protocomm_t *protocomm_new(void) { protocomm_t *pc; diff --git a/components/protocomm/src/simple_ble/simple_ble.c b/components/protocomm/src/simple_ble/simple_ble.c index ff57b95950..e4f2a8f8de 100644 --- a/components/protocomm/src/simple_ble/simple_ble.c +++ b/components/protocomm/src/simple_ble/simple_ble.c @@ -178,7 +178,7 @@ static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_ } } -simple_ble_cfg_t *simple_ble_init() +simple_ble_cfg_t *simple_ble_init(void) { simple_ble_cfg_t *ble_cfg_p = (simple_ble_cfg_t *) malloc(sizeof(simple_ble_cfg_t)); if (ble_cfg_p == NULL) { @@ -188,7 +188,7 @@ simple_ble_cfg_t *simple_ble_init() return ble_cfg_p; } -esp_err_t simple_ble_deinit() +esp_err_t simple_ble_deinit(void) { free(g_ble_cfg_p->gatt_db); free(g_ble_cfg_p); @@ -262,7 +262,7 @@ esp_err_t simple_ble_start(simple_ble_cfg_t *cfg) return ESP_OK; } -esp_err_t simple_ble_stop() +esp_err_t simple_ble_stop(void) { esp_err_t err; ESP_LOGD(TAG, "Free mem at start of simple_ble_stop %d", esp_get_free_heap_size()); diff --git a/components/protocomm/src/simple_ble/simple_ble.h b/components/protocomm/src/simple_ble/simple_ble.h index d4f927b61d..46f37f6d46 100644 --- a/components/protocomm/src/simple_ble/simple_ble.h +++ b/components/protocomm/src/simple_ble/simple_ble.h @@ -67,7 +67,7 @@ typedef struct { * * @return simple_ble_cfg_t* Pointer to configuration structure */ -simple_ble_cfg_t *simple_ble_init(); +simple_ble_cfg_t *simple_ble_init(void); /** Deallocates memory * @@ -75,7 +75,7 @@ simple_ble_cfg_t *simple_ble_init(); * * @return ESP_OK */ -esp_err_t simple_ble_deinit(); +esp_err_t simple_ble_deinit(void); /** Starts BLE service * @@ -97,7 +97,7 @@ esp_err_t simple_ble_start(simple_ble_cfg_t *cfg); * * @return ESP_OK on success, and appropriate error code for failure */ -esp_err_t simple_ble_stop(); +esp_err_t simple_ble_stop(void); /** Convert handle to 128 bit UUID of characteristic * diff --git a/components/pthread/include/esp_pthread.h b/components/pthread/include/esp_pthread.h index 76f45a32ab..6d24d3ea99 100644 --- a/components/pthread/include/esp_pthread.h +++ b/components/pthread/include/esp_pthread.h @@ -41,7 +41,7 @@ typedef struct { * @return * A default configuration structure. */ -esp_pthread_cfg_t esp_pthread_get_default_config(); +esp_pthread_cfg_t esp_pthread_get_default_config(void); /** * @brief Configure parameters for creating pthread diff --git a/components/pthread/pthread.c b/components/pthread/pthread.c index ce0c064ce3..40caf9e12e 100644 --- a/components/pthread/pthread.c +++ b/components/pthread/pthread.c @@ -168,12 +168,12 @@ esp_err_t esp_pthread_get_cfg(esp_pthread_cfg_t *p) return ESP_ERR_NOT_FOUND; } -static int get_default_pthread_core() +static int get_default_pthread_core(void) { return CONFIG_PTHREAD_TASK_CORE_DEFAULT == -1 ? tskNO_AFFINITY : CONFIG_PTHREAD_TASK_CORE_DEFAULT; } -esp_pthread_cfg_t esp_pthread_get_default_config() +esp_pthread_cfg_t esp_pthread_get_default_config(void) { esp_pthread_cfg_t cfg = { .stack_size = CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT, @@ -822,6 +822,6 @@ int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) } /* Hook function to force linking this file */ -void pthread_include_pthread_impl() +void pthread_include_pthread_impl(void) { } diff --git a/components/pthread/pthread_cond_var.c b/components/pthread/pthread_cond_var.c index 8db28ae5e1..bb3a883c46 100644 --- a/components/pthread/pthread_cond_var.c +++ b/components/pthread/pthread_cond_var.c @@ -200,6 +200,6 @@ int pthread_cond_destroy(pthread_cond_t *cv) } /* Hook function to force linking this file */ -void pthread_include_pthread_cond_var_impl() +void pthread_include_pthread_cond_var_impl(void) { } diff --git a/components/pthread/pthread_internal.h b/components/pthread/pthread_internal.h index 6ed2fe45e4..a4e4cfd55d 100644 --- a/components/pthread/pthread_internal.h +++ b/components/pthread/pthread_internal.h @@ -13,4 +13,4 @@ // limitations under the License. #pragma once -void pthread_internal_local_storage_destructor_callback(); +void pthread_internal_local_storage_destructor_callback(void); diff --git a/components/pthread/pthread_local_storage.c b/components/pthread/pthread_local_storage.c index ecf252e4cc..5572768470 100644 --- a/components/pthread/pthread_local_storage.c +++ b/components/pthread/pthread_local_storage.c @@ -166,7 +166,7 @@ void __wrap_vPortCleanUpTCB(void *tcb) #endif /* this function called from pthread_task_func for "early" cleanup of TLS in a pthread */ -void pthread_internal_local_storage_destructor_callback() +void pthread_internal_local_storage_destructor_callback(void) { void *tls = pvTaskGetThreadLocalStoragePointer(NULL, PTHREAD_TLS_INDEX); if (tls != NULL) { @@ -257,6 +257,6 @@ int pthread_setspecific(pthread_key_t key, const void *value) } /* Hook function to force linking this file */ -void pthread_include_pthread_local_storage_impl() +void pthread_include_pthread_local_storage_impl(void) { } diff --git a/components/sdmmc/test/test_sd.c b/components/sdmmc/test/test_sd.c index b1b418c95c..29ce04a283 100644 --- a/components/sdmmc/test/test_sd.c +++ b/components/sdmmc/test/test_sd.c @@ -48,7 +48,7 @@ #define CD_WP_TEST_GPIO 18 -static void sd_test_board_power_on() +static void sd_test_board_power_on(void) { gpio_set_direction(SD_TEST_BOARD_VSEL_GPIO, GPIO_MODE_OUTPUT); gpio_set_level(SD_TEST_BOARD_VSEL_GPIO, SD_TEST_BOARD_VSEL_3V3); @@ -59,7 +59,7 @@ static void sd_test_board_power_on() usleep(SD_TEST_BOARD_PWR_ON_DELAY_MS * 1000); } -static void sd_test_board_power_off() +static void sd_test_board_power_off(void) { gpio_set_level(SD_TEST_BOARD_VSEL_EN_GPIO, 0); gpio_set_direction(SD_TEST_BOARD_VSEL_GPIO, GPIO_MODE_INPUT); diff --git a/components/sdmmc/test/test_sdio.c b/components/sdmmc/test/test_sdio.c index 56213d7136..0e5be1d6fd 100644 --- a/components/sdmmc/test/test_sdio.c +++ b/components/sdmmc/test/test_sdio.c @@ -126,7 +126,7 @@ static esp_err_t slave_slc_reg_write(sdmmc_card_t* card, uint32_t addr, uint32_t } /** Reset and put slave into download mode */ -static void reset_slave() +static void reset_slave(void) { const int pin_en = 18; const int pin_io0 = 19; diff --git a/components/soc/esp32/cpu_util.c b/components/soc/esp32/cpu_util.c index 83ae830b94..ed2c6361ef 100644 --- a/components/soc/esp32/cpu_util.c +++ b/components/soc/esp32/cpu_util.c @@ -50,7 +50,7 @@ void IRAM_ATTR esp_cpu_reset(int cpu_id) cpu_id == 0 ? RTC_CNTL_SW_PROCPU_RST_M : RTC_CNTL_SW_APPCPU_RST_M); } -bool IRAM_ATTR esp_cpu_in_ocd_debug_mode() +bool IRAM_ATTR esp_cpu_in_ocd_debug_mode(void) { #if CONFIG_ESP32_DEBUG_OCDAWARE int dcr; diff --git a/components/soc/esp32/include/soc/cpu.h b/components/soc/esp32/include/soc/cpu.h index 190786a433..57ccd6e17d 100644 --- a/components/soc/esp32/include/soc/cpu.h +++ b/components/soc/esp32/include/soc/cpu.h @@ -30,7 +30,7 @@ /** @brief Read current stack pointer address * */ -static inline void *get_sp() +static inline void *get_sp(void) { void *sp; asm volatile ("mov %0, sp;" : "=r" (sp)); @@ -52,7 +52,7 @@ static inline void cpu_write_itlb(unsigned vpn, unsigned attr) asm volatile ("witlb %1, %0; isync\n" :: "r" (vpn), "r" (attr)); } -static inline void cpu_init_memctl() +static inline void cpu_init_memctl(void) { #if XCHAL_ERRATUM_572 uint32_t memctl = XCHAL_CACHE_MEMCTL_DEFAULT; @@ -71,7 +71,7 @@ static inline void cpu_init_memctl() * 15 — no access, raise exception */ -static inline void cpu_configure_region_protection() +static inline void cpu_configure_region_protection(void) { const uint32_t pages_to_protect[] = {0x00000000, 0x80000000, 0xa0000000, 0xc0000000, 0xe0000000}; for (int i = 0; i < sizeof(pages_to_protect)/sizeof(pages_to_protect[0]); ++i) { @@ -108,7 +108,7 @@ void esp_cpu_reset(int cpu_id); * @note If "Make exception and panic handlers JTAG/OCD aware" * is disabled, this function always returns false. */ -bool esp_cpu_in_ocd_debug_mode(); +bool esp_cpu_in_ocd_debug_mode(void); /** * @brief Convert the PC register value to its true address diff --git a/components/soc/esp32/include/soc/rtc.h b/components/soc/esp32/include/soc/rtc.h index 4dd0db6e2e..22d3601d33 100644 --- a/components/soc/esp32/include/soc/rtc.h +++ b/components/soc/esp32/include/soc/rtc.h @@ -176,7 +176,7 @@ void rtc_clk_init(rtc_clk_config_t cfg); * * @return XTAL frequency, one of rtc_xtal_freq_t */ -rtc_xtal_freq_t rtc_clk_xtal_freq_get(); +rtc_xtal_freq_t rtc_clk_xtal_freq_get(void); /** * @brief Update XTAL frequency @@ -197,13 +197,13 @@ void rtc_clk_32k_enable(bool en); /** * @brief Configure 32 kHz XTAL oscillator to accept external clock signal */ -void rtc_clk_32k_enable_external(); +void rtc_clk_32k_enable_external(void); /** * @brief Get the state of 32k XTAL oscillator * @return true if 32k XTAL oscillator has been enabled */ -bool rtc_clk_32k_enabled(); +bool rtc_clk_32k_enabled(void); /** * @brief Enable 32k oscillator, configuring it for fast startup time. @@ -239,13 +239,13 @@ void rtc_clk_8m_enable(bool clk_8m_en, bool d256_en); * @brief Get the state of 8 MHz internal oscillator * @return true if the oscillator is enabled */ -bool rtc_clk_8m_enabled(); +bool rtc_clk_8m_enabled(void); /** * @brief Get the state of /256 divider which is applied to 8MHz clock * @return true if the divided output is enabled */ -bool rtc_clk_8md256_enabled(); +bool rtc_clk_8md256_enabled(void); /** * @brief Enable or disable APLL @@ -276,7 +276,7 @@ void rtc_clk_slow_freq_set(rtc_slow_freq_t slow_freq); * @brief Get the RTC_SLOW_CLK source * @return currently selected clock source (one of rtc_slow_freq_t values) */ -rtc_slow_freq_t rtc_clk_slow_freq_get(); +rtc_slow_freq_t rtc_clk_slow_freq_get(void); /** * @brief Get the approximate frequency of RTC_SLOW_CLK, in Hz @@ -290,7 +290,7 @@ rtc_slow_freq_t rtc_clk_slow_freq_get(); * * @return RTC_SLOW_CLK frequency, in Hz */ -uint32_t rtc_clk_slow_freq_get_hz(); +uint32_t rtc_clk_slow_freq_get_hz(void); /** * @brief Select source for RTC_FAST_CLK @@ -302,7 +302,7 @@ void rtc_clk_fast_freq_set(rtc_fast_freq_t fast_freq); * @brief Get the RTC_FAST_CLK source * @return currently selected clock source (one of rtc_fast_freq_t values) */ -rtc_fast_freq_t rtc_clk_fast_freq_get(); +rtc_fast_freq_t rtc_clk_fast_freq_get(void); /** * @brief Switch CPU frequency @@ -355,7 +355,7 @@ void rtc_clk_cpu_freq_set_fast(rtc_cpu_freq_t cpu_freq) __attribute__((deprecate * * @return CPU frequency (one of rtc_cpu_freq_t values) */ -rtc_cpu_freq_t rtc_clk_cpu_freq_get() __attribute__((deprecated)); +rtc_cpu_freq_t rtc_clk_cpu_freq_get(void) __attribute__((deprecated)); /** * @brief Get corresponding frequency value for rtc_cpu_freq_t enum value @@ -444,7 +444,7 @@ uint32_t rtc_clk_cpu_freq_value(rtc_cpu_freq_t cpu_freq) __attribute__((depreca * rtc_clk_cpu_freq_set_config when a switch to XTAL is needed. * Assumes that XTAL frequency has been determined — don't call in startup code. */ - void rtc_clk_cpu_freq_set_xtal(); + void rtc_clk_cpu_freq_set_xtal(void); /** @@ -465,7 +465,7 @@ void rtc_clk_apb_freq_update(uint32_t apb_freq); * @brief Get the current stored APB frequency. * @return The APB frequency value as last set via rtc_clk_apb_freq_update(), in Hz. */ -uint32_t rtc_clk_apb_freq_get(); +uint32_t rtc_clk_apb_freq_get(void); #define RTC_CLK_CAL_FRACT 19 //!< Number of fractional bits in values returned by rtc_clk_cal @@ -522,7 +522,7 @@ uint64_t rtc_time_slowclk_to_us(uint64_t rtc_cycles, uint32_t period); * * @return current value of RTC counter */ -uint64_t rtc_time_get(); +uint64_t rtc_time_get(void); /** * @brief Busy loop until next RTC_SLOW_CLK cycle @@ -531,7 +531,7 @@ uint64_t rtc_time_get(); * In some cases (e.g. when RTC_SLOW_CLK cycle is very close), it may return * one RTC_SLOW_CLK cycle later. */ -void rtc_clk_wait_for_slow_cycle(); +void rtc_clk_wait_for_slow_cycle(void); /** * @brief sleep configuration for rtc_sleep_init function @@ -710,7 +710,7 @@ typedef struct rtc_vddsdio_config_s { * Otherwise, use default values and the level of MTDI bootstrapping pin. * @return currently used VDDSDIO configuration */ -rtc_vddsdio_config_t rtc_vddsdio_get_config(); +rtc_vddsdio_config_t rtc_vddsdio_get_config(void); /** * Set new VDDSDIO configuration using RTC registers. diff --git a/components/soc/esp32/rtc_clk.c b/components/soc/esp32/rtc_clk.c index 80a749b22e..42640b32f2 100644 --- a/components/soc/esp32/rtc_clk.c +++ b/components/soc/esp32/rtc_clk.c @@ -100,9 +100,9 @@ #define RTC_PLL_FREQ_320M 320 #define RTC_PLL_FREQ_480M 480 -static void rtc_clk_cpu_freq_to_8m(); -static void rtc_clk_bbpll_disable(); -static void rtc_clk_bbpll_enable(); +static void rtc_clk_cpu_freq_to_8m(void); +static void rtc_clk_bbpll_disable(void); +static void rtc_clk_bbpll_enable(void); static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz); static bool rtc_clk_cpu_freq_from_mhz_internal(int mhz, rtc_cpu_freq_t* out_val); @@ -161,7 +161,7 @@ void rtc_clk_32k_enable(bool enable) } } -void rtc_clk_32k_enable_external() +void rtc_clk_32k_enable_external(void) { rtc_clk_32k_enable_common(XTAL_32K_EXT_DAC_VAL, XTAL_32K_EXT_DRES_VAL, XTAL_32K_EXT_DBIAS_VAL); } @@ -201,7 +201,7 @@ void rtc_clk_32k_bootstrap(uint32_t cycle) XTAL_32K_BOOTSTRAP_DRES_VAL, XTAL_32K_BOOTSTRAP_DBIAS_VAL); } -bool rtc_clk_32k_enabled() +bool rtc_clk_32k_enabled(void) { return GET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K) != 0; } @@ -224,12 +224,12 @@ void rtc_clk_8m_enable(bool clk_8m_en, bool d256_en) } } -bool rtc_clk_8m_enabled() +bool rtc_clk_8m_enabled(void) { return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M) == 0; } -bool rtc_clk_8md256_enabled() +bool rtc_clk_8md256_enabled(void) { return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV) == 0; } @@ -284,12 +284,12 @@ void rtc_clk_slow_freq_set(rtc_slow_freq_t slow_freq) ets_delay_us(DELAY_SLOW_CLK_SWITCH); } -rtc_slow_freq_t rtc_clk_slow_freq_get() +rtc_slow_freq_t rtc_clk_slow_freq_get(void) { return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL); } -uint32_t rtc_clk_slow_freq_get_hz() +uint32_t rtc_clk_slow_freq_get_hz(void) { switch(rtc_clk_slow_freq_get()) { case RTC_SLOW_FREQ_RTC: return RTC_SLOW_CLK_FREQ_150K; @@ -305,7 +305,7 @@ void rtc_clk_fast_freq_set(rtc_fast_freq_t fast_freq) ets_delay_us(DELAY_FAST_CLK_SWITCH); } -rtc_fast_freq_t rtc_clk_fast_freq_get() +rtc_fast_freq_t rtc_clk_fast_freq_get(void) { return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL); } @@ -435,7 +435,7 @@ void rtc_clk_cpu_freq_to_xtal(int freq, int div) } } -static void rtc_clk_cpu_freq_to_8m() +static void rtc_clk_cpu_freq_to_8m(void) { ets_update_cpu_frequency(8); REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_XTAL); @@ -444,7 +444,7 @@ static void rtc_clk_cpu_freq_to_8m() rtc_clk_apb_freq_update(RTC_FAST_CLK_FREQ_8M); } -static void rtc_clk_bbpll_disable() +static void rtc_clk_bbpll_disable(void) { SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD | RTC_CNTL_BBPLL_FORCE_PD | @@ -459,7 +459,7 @@ static void rtc_clk_bbpll_disable() } } -static void rtc_clk_bbpll_enable() +static void rtc_clk_bbpll_enable(void) { CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FORCE_PD | RTC_CNTL_BB_I2C_FORCE_PD | @@ -516,7 +516,7 @@ void rtc_clk_cpu_freq_set_fast(rtc_cpu_freq_t cpu_freq) rtc_clk_cpu_freq_set_config_fast(&config); } -void rtc_clk_cpu_freq_set_xtal() +void rtc_clk_cpu_freq_set_xtal(void) { int freq_mhz = (int) rtc_clk_xtal_freq_get(); @@ -525,7 +525,7 @@ void rtc_clk_cpu_freq_set_xtal() rtc_clk_bbpll_disable(); } -rtc_cpu_freq_t rtc_clk_cpu_freq_get() +rtc_cpu_freq_t rtc_clk_cpu_freq_get(void) { rtc_cpu_freq_config_t config; rtc_clk_cpu_freq_get_config(&config); @@ -766,7 +766,7 @@ void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t* config) } } -rtc_xtal_freq_t rtc_clk_xtal_freq_get() +rtc_xtal_freq_t rtc_clk_xtal_freq_get(void) { /* We may have already written XTAL value into RTC_XTAL_FREQ_REG */ uint32_t xtal_freq_reg = READ_PERI_REG(RTC_XTAL_FREQ_REG); @@ -790,7 +790,7 @@ void rtc_clk_apb_freq_update(uint32_t apb_freq) WRITE_PERI_REG(RTC_APB_FREQ_REG, clk_val_to_reg_val(apb_freq >> 12)); } -uint32_t rtc_clk_apb_freq_get() +uint32_t rtc_clk_apb_freq_get(void) { uint32_t freq_hz = reg_val_to_clk_val(READ_PERI_REG(RTC_APB_FREQ_REG)) << 12; // round to the nearest MHz @@ -802,4 +802,4 @@ uint32_t rtc_clk_apb_freq_get() /* Name used in libphy.a:phy_chip_v7.o * TODO: update the library to use rtc_clk_xtal_freq_get */ -rtc_xtal_freq_t rtc_get_xtal() __attribute__((alias("rtc_clk_xtal_freq_get"))); +rtc_xtal_freq_t rtc_get_xtal(void) __attribute__((alias("rtc_clk_xtal_freq_get"))); diff --git a/components/soc/esp32/rtc_clk_init.c b/components/soc/esp32/rtc_clk_init.c index a675d53f39..d1f128ffa3 100644 --- a/components/soc/esp32/rtc_clk_init.c +++ b/components/soc/esp32/rtc_clk_init.c @@ -36,7 +36,7 @@ */ #define XTAL_FREQ_EST_CYCLES 10 -static rtc_xtal_freq_t rtc_clk_xtal_freq_estimate(); +static rtc_xtal_freq_t rtc_clk_xtal_freq_estimate(void); static const char* TAG = "rtc_clk_init"; @@ -140,7 +140,7 @@ void rtc_clk_init(rtc_clk_config_t cfg) rtc_clk_slow_freq_set(cfg.slow_freq); } -static rtc_xtal_freq_t rtc_clk_xtal_freq_estimate() +static rtc_xtal_freq_t rtc_clk_xtal_freq_estimate(void) { /* Enable 8M/256 clock if needed */ const bool clk_8m_enabled = rtc_clk_8m_enabled(); diff --git a/components/soc/esp32/rtc_init.c b/components/soc/esp32/rtc_init.c index e0cd4ba4a3..942b9409a7 100644 --- a/components/soc/esp32/rtc_init.c +++ b/components/soc/esp32/rtc_init.c @@ -97,7 +97,7 @@ void rtc_init(rtc_config_t cfg) } } -rtc_vddsdio_config_t rtc_vddsdio_get_config() +rtc_vddsdio_config_t rtc_vddsdio_get_config(void) { rtc_vddsdio_config_t result; uint32_t sdio_conf_reg = REG_READ(RTC_CNTL_SDIO_CONF_REG); diff --git a/components/soc/esp32/rtc_pm.c b/components/soc/esp32/rtc_pm.c index f951ee1078..47baedf952 100644 --- a/components/soc/esp32/rtc_pm.c +++ b/components/soc/esp32/rtc_pm.c @@ -29,14 +29,14 @@ typedef enum{ /* These MAC-related functions are defined in the closed source part of * RTC library */ -extern void pm_mac_init(); -extern int pm_check_mac_idle(); -extern void pm_mac_deinit(); +extern void pm_mac_init(void); +extern int pm_check_mac_idle(void); +extern void pm_mac_deinit(void); /* This sleep-related function is called from the closed source part of RTC * library. */ -pm_sw_reject_t pm_set_sleep_mode(pm_sleep_mode_t sleep_mode, void(*pmac_save_params)()) +pm_sw_reject_t pm_set_sleep_mode(pm_sleep_mode_t sleep_mode, void(*pmac_save_params)(void)) { (void) pmac_save_params; /* unused */ diff --git a/components/soc/esp32/rtc_time.c b/components/soc/esp32/rtc_time.c index e644775645..a7dfdb2485 100644 --- a/components/soc/esp32/rtc_time.c +++ b/components/soc/esp32/rtc_time.c @@ -140,7 +140,7 @@ uint64_t rtc_time_slowclk_to_us(uint64_t rtc_cycles, uint32_t period) return (rtc_cycles * period) >> RTC_CLK_CAL_FRACT; } -uint64_t rtc_time_get() +uint64_t rtc_time_get(void) { SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE); while (GET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_VALID) == 0) { @@ -152,7 +152,7 @@ uint64_t rtc_time_get() return t; } -void rtc_clk_wait_for_slow_cycle() +void rtc_clk_wait_for_slow_cycle(void) { REG_CLR_BIT(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING | TIMG_RTC_CALI_START); REG_CLR_BIT(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_RDY); diff --git a/components/soc/esp32/rtc_wdt.c b/components/soc/esp32/rtc_wdt.c index 1b01ce3046..facf8d4449 100644 --- a/components/soc/esp32/rtc_wdt.c +++ b/components/soc/esp32/rtc_wdt.c @@ -16,34 +16,34 @@ #include "soc/rtc.h" -bool rtc_wdt_get_protect_status() +bool rtc_wdt_get_protect_status(void) { return READ_PERI_REG(RTC_CNTL_WDTWPROTECT_REG) != RTC_CNTL_WDT_WKEY_VALUE; } -void rtc_wdt_protect_off() +void rtc_wdt_protect_off(void) { WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE); } -void rtc_wdt_protect_on() +void rtc_wdt_protect_on(void) { WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0); } -void rtc_wdt_enable() +void rtc_wdt_enable(void) { REG_SET_BIT(RTC_CNTL_WDTFEED_REG, RTC_CNTL_WDT_FEED); SET_PERI_REG_MASK(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN | RTC_CNTL_WDT_PAUSE_IN_SLP); } -void rtc_wdt_flashboot_mode_enable() +void rtc_wdt_flashboot_mode_enable(void) { REG_SET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN); } -void rtc_wdt_disable() +void rtc_wdt_disable(void) { bool protect = rtc_wdt_get_protect_status(); if (protect) { @@ -61,7 +61,7 @@ void rtc_wdt_disable() } } -void rtc_wdt_feed() +void rtc_wdt_feed(void) { bool protect = rtc_wdt_get_protect_status(); if (protect) { @@ -145,7 +145,7 @@ esp_err_t rtc_wdt_set_length_of_reset_signal(rtc_wdt_reset_sig_t reset_src, rtc_ return ESP_OK; } -bool rtc_wdt_is_on() +bool rtc_wdt_is_on(void) { return (REG_GET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN) != 0) || (REG_GET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN) != 0); } diff --git a/components/soc/esp32/test/test_rtc_clk.c b/components/soc/esp32/test/test_rtc_clk.c index 6983035580..1c21a1af11 100644 --- a/components/soc/esp32/test/test_rtc_clk.c +++ b/components/soc/esp32/test/test_rtc_clk.c @@ -141,7 +141,7 @@ TEST_CASE("Test fast switching between PLL and XTAL", "[rtc_clk]") #define COUNT_TEST 3 #define TIMEOUT_TEST_MS (5 + CONFIG_ESP32_RTC_CLK_CAL_CYCLES / 16) -void stop_rtc_external_quartz(){ +void stop_rtc_external_quartz(void){ const uint8_t pin_32 = 32; const uint8_t pin_33 = 33; const uint8_t mask_32 = (1 << (pin_32 - 32)); diff --git a/components/soc/include/soc/rtc_wdt.h b/components/soc/include/soc/rtc_wdt.h index aae54530aa..0ed2c9a7b1 100644 --- a/components/soc/include/soc/rtc_wdt.h +++ b/components/soc/include/soc/rtc_wdt.h @@ -99,22 +99,22 @@ typedef enum { * @return * - True if the protect of RTC_WDT is set */ -bool rtc_wdt_get_protect_status(); +bool rtc_wdt_get_protect_status(void); /** * @brief Set protect of rtc_wdt. */ -void rtc_wdt_protect_on(); +void rtc_wdt_protect_on(void); /** * @brief Reset protect of rtc_wdt. */ -void rtc_wdt_protect_off(); +void rtc_wdt_protect_off(void); /** * @brief Enable rtc_wdt. */ -void rtc_wdt_enable(); +void rtc_wdt_enable(void); /** * @brief Enable the flash boot protection procedure for WDT. @@ -123,19 +123,19 @@ void rtc_wdt_enable(); * This function was added to be compatibility with the old bootloaders. * This mode is disabled in bootloader or using rtc_wdt_disable() function. */ -void rtc_wdt_flashboot_mode_enable(); +void rtc_wdt_flashboot_mode_enable(void); /** * @brief Disable rtc_wdt. */ -void rtc_wdt_disable(); +void rtc_wdt_disable(void); /** * @brief Reset counter rtc_wdt. * * It returns to stage 0 and its expiry counter restarts from 0. */ -void rtc_wdt_feed(); +void rtc_wdt_feed(void); /** * @brief Set time for required stage. @@ -191,7 +191,7 @@ esp_err_t rtc_wdt_set_length_of_reset_signal(rtc_wdt_reset_sig_t reset_src, rtc_ * @return * - True rtc_wdt is enabled */ -bool rtc_wdt_is_on(); +bool rtc_wdt_is_on(void); #ifdef __cplusplus } diff --git a/components/soc/include/soc/soc_memory_layout.h b/components/soc/include/soc/soc_memory_layout.h index de7c449d51..15556fcde1 100644 --- a/components/soc/include/soc/soc_memory_layout.h +++ b/components/soc/include/soc/soc_memory_layout.h @@ -138,7 +138,7 @@ size_t soc_get_available_memory_regions(soc_memory_region_t *regions); * returned by soc_get_available_memory_regions(). Used to size the * array passed to that function. */ -size_t soc_get_available_memory_region_max_count(); +size_t soc_get_available_memory_region_max_count(void); inline static bool IRAM_ATTR esp_ptr_dma_capable(const void *p) { diff --git a/components/soc/src/memory_layout_utils.c b/components/soc/src/memory_layout_utils.c index b43865fd65..29f752b9da 100644 --- a/components/soc/src/memory_layout_utils.c +++ b/components/soc/src/memory_layout_utils.c @@ -34,14 +34,14 @@ extern int _data_start, _static_data_end, _iram_start, _iram_end; /* static DRAM & IRAM chunks */ static const size_t EXTRA_RESERVED_REGIONS = 2; -static size_t s_get_num_reserved_regions() +static size_t s_get_num_reserved_regions(void) { return ( ( &soc_reserved_memory_region_end - &soc_reserved_memory_region_start ) + EXTRA_RESERVED_REGIONS ); } -size_t soc_get_available_memory_region_max_count() +size_t soc_get_available_memory_region_max_count(void) { /* Worst-case: each reserved memory region splits an available region in two, so the maximum possible number of regions diff --git a/components/spi_flash/cache_utils.c b/components/spi_flash/cache_utils.c index b27b968ad6..25f937d749 100644 --- a/components/spi_flash/cache_utils.c +++ b/components/spi_flash/cache_utils.c @@ -45,18 +45,18 @@ static volatile bool s_flash_op_complete = false; static volatile int s_flash_op_cpu = -1; #endif -void spi_flash_init_lock() +void spi_flash_init_lock(void) { s_flash_op_mutex = xSemaphoreCreateRecursiveMutex(); assert(s_flash_op_mutex != NULL); } -void spi_flash_op_lock() +void spi_flash_op_lock(void) { xSemaphoreTakeRecursive(s_flash_op_mutex, portMAX_DELAY); } -void spi_flash_op_unlock() +void spi_flash_op_unlock(void) { xSemaphoreGiveRecursive(s_flash_op_mutex); } @@ -90,7 +90,7 @@ void IRAM_ATTR spi_flash_op_block_func(void* arg) xTaskResumeAll(); } -void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu() +void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu(void) { spi_flash_op_lock(); @@ -141,7 +141,7 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu() spi_flash_disable_cache(other_cpuid, &s_flash_op_cache_state[other_cpuid]); } -void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu() +void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu(void) { const uint32_t cpuid = xPortGetCoreID(); const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0; @@ -178,7 +178,7 @@ void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu() spi_flash_op_unlock(); } -void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os() +void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os(void) { const uint32_t cpuid = xPortGetCoreID(); const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0; @@ -191,7 +191,7 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os() spi_flash_disable_cache(cpuid, &s_flash_op_cache_state[cpuid]); } -void IRAM_ATTR spi_flash_enable_interrupts_caches_no_os() +void IRAM_ATTR spi_flash_enable_interrupts_caches_no_os(void) { const uint32_t cpuid = xPortGetCoreID(); @@ -203,36 +203,36 @@ void IRAM_ATTR spi_flash_enable_interrupts_caches_no_os() #else // CONFIG_FREERTOS_UNICORE -void spi_flash_init_lock() +void spi_flash_init_lock(void) { } -void spi_flash_op_lock() +void spi_flash_op_lock(void) { vTaskSuspendAll(); } -void spi_flash_op_unlock() +void spi_flash_op_unlock(void) { xTaskResumeAll(); } -void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu() +void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu(void) { spi_flash_op_lock(); esp_intr_noniram_disable(); spi_flash_disable_cache(0, &s_flash_op_cache_state[0]); } -void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu() +void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu(void) { spi_flash_restore_cache(0, s_flash_op_cache_state[0]); esp_intr_noniram_enable(); spi_flash_op_unlock(); } -void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os() +void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os(void) { // Kill interrupts that aren't located in IRAM esp_intr_noniram_disable(); @@ -240,7 +240,7 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os() spi_flash_disable_cache(0, &s_flash_op_cache_state[0]); } -void IRAM_ATTR spi_flash_enable_interrupts_caches_no_os() +void IRAM_ATTR spi_flash_enable_interrupts_caches_no_os(void) { // Re-enable cache on this CPU spi_flash_restore_cache(0, s_flash_op_cache_state[0]); @@ -291,7 +291,7 @@ static void IRAM_ATTR spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_sta } -IRAM_ATTR bool spi_flash_cache_enabled() +IRAM_ATTR bool spi_flash_cache_enabled(void) { bool result = (DPORT_REG_GET_BIT(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_CACHE_ENABLE) != 0); #if portNUM_PROCESSORS == 2 diff --git a/components/spi_flash/cache_utils.h b/components/spi_flash/cache_utils.h index d482c4da79..9b272009ff 100644 --- a/components/spi_flash/cache_utils.h +++ b/components/spi_flash/cache_utils.h @@ -23,30 +23,30 @@ */ // Init mutex protecting access to spi_flash_* APIs -void spi_flash_init_lock(); +void spi_flash_init_lock(void); // Take mutex protecting access to spi_flash_* APIs -void spi_flash_op_lock(); +void spi_flash_op_lock(void); // Release said mutex -void spi_flash_op_unlock(); +void spi_flash_op_unlock(void); // Suspend the scheduler on both CPUs, disable cache. // Contrary to its name this doesn't do anything with interrupts, yet. // Interrupt disabling capability will be added once we implement // interrupt allocation API. -void spi_flash_disable_interrupts_caches_and_other_cpu(); +void spi_flash_disable_interrupts_caches_and_other_cpu(void); // Enable cache, enable interrupts (to be added in future), resume scheduler -void spi_flash_enable_interrupts_caches_and_other_cpu(); +void spi_flash_enable_interrupts_caches_and_other_cpu(void); // Disables non-IRAM interrupt handlers on current CPU and caches on both CPUs. // This function is implied to be called when other CPU is not running or running code from IRAM. -void spi_flash_disable_interrupts_caches_and_other_cpu_no_os(); +void spi_flash_disable_interrupts_caches_and_other_cpu_no_os(void); // Enable cache, enable interrupts on current CPU. // This function is implied to be called when other CPU is not running or running code from IRAM. -void spi_flash_enable_interrupts_caches_no_os(); +void spi_flash_enable_interrupts_caches_no_os(void); // Flushes cache if address range has corresponding valid cache mappings // Recommended to use post flash program operation (erase or write) diff --git a/components/spi_flash/esp_flash_api.c b/components/spi_flash/esp_flash_api.c index 1ce52e47b2..f064bcbdb0 100644 --- a/components/spi_flash/esp_flash_api.c +++ b/components/spi_flash/esp_flash_api.c @@ -664,7 +664,7 @@ esp_err_t spi_flash_read(size_t src, void *dstv, size_t size) return spi_flash_translate_rc(err); } -esp_err_t spi_flash_unlock() +esp_err_t spi_flash_unlock(void) { esp_err_t err = esp_flash_set_chip_write_protect(NULL, false); return spi_flash_translate_rc(err); diff --git a/components/spi_flash/esp_flash_spi_init.c b/components/spi_flash/esp_flash_spi_init.c index ecd5666860..c554f4a292 100644 --- a/components/spi_flash/esp_flash_spi_init.c +++ b/components/spi_flash/esp_flash_spi_init.c @@ -174,7 +174,7 @@ static DRAM_ATTR esp_flash_t default_chip = { esp_flash_t *esp_flash_default_chip = NULL; -esp_err_t esp_flash_init_default_chip() +esp_err_t esp_flash_init_default_chip(void) { memspi_host_config_t cfg = ESP_FLASH_HOST_CONFIG_DEFAULT(); //the host is already initialized, only do init for the data and load it to the host @@ -200,7 +200,7 @@ esp_err_t esp_flash_init_default_chip() return ESP_OK; } -esp_err_t esp_flash_app_init() +esp_err_t esp_flash_app_init(void) { return esp_flash_init_os_functions(&default_chip, 0); } diff --git a/components/spi_flash/flash_mmap.c b/components/spi_flash/flash_mmap.c index 76e2d025c2..4af8012924 100644 --- a/components/spi_flash/flash_mmap.c +++ b/components/spi_flash/flash_mmap.c @@ -62,7 +62,7 @@ static uint8_t s_mmap_page_refcnt[REGIONS_COUNT * PAGES_PER_REGION] = {0}; static uint32_t s_mmap_last_handle = 0; -static void IRAM_ATTR spi_flash_mmap_init() +static void IRAM_ATTR spi_flash_mmap_init(void) { if (s_mmap_page_refcnt[0] != 0) { return; /* mmap data already initialised */ @@ -268,7 +268,7 @@ void IRAM_ATTR spi_flash_munmap(spi_flash_mmap_handle_t handle) free(it); } -static void IRAM_ATTR NOINLINE_ATTR spi_flash_protected_mmap_init() +static void IRAM_ATTR NOINLINE_ATTR spi_flash_protected_mmap_init(void) { spi_flash_disable_interrupts_caches_and_other_cpu(); spi_flash_mmap_init(); @@ -284,7 +284,7 @@ static uint32_t IRAM_ATTR NOINLINE_ATTR spi_flash_protected_read_mmu_entry(int i return value; } -void spi_flash_mmap_dump() +void spi_flash_mmap_dump(void) { spi_flash_protected_mmap_init(); diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index 1b06447b1c..41405c8d08 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -123,7 +123,7 @@ static __attribute__((unused)) bool is_safe_write_address(size_t addr, size_t si } -void spi_flash_init() +void spi_flash_init(void) { spi_flash_init_lock(); #if CONFIG_SPI_FLASH_ENABLE_COUNTERS @@ -136,38 +136,38 @@ void IRAM_ATTR spi_flash_guard_set(const spi_flash_guard_funcs_t *funcs) s_flash_guard_ops = funcs; } -const spi_flash_guard_funcs_t *IRAM_ATTR spi_flash_guard_get() +const spi_flash_guard_funcs_t *IRAM_ATTR spi_flash_guard_get(void) { return s_flash_guard_ops; } -size_t IRAM_ATTR spi_flash_get_chip_size() +size_t IRAM_ATTR spi_flash_get_chip_size(void) { return g_rom_flashchip.chip_size; } -static inline void IRAM_ATTR spi_flash_guard_start() +static inline void IRAM_ATTR spi_flash_guard_start(void) { if (s_flash_guard_ops && s_flash_guard_ops->start) { s_flash_guard_ops->start(); } } -static inline void IRAM_ATTR spi_flash_guard_end() +static inline void IRAM_ATTR spi_flash_guard_end(void) { if (s_flash_guard_ops && s_flash_guard_ops->end) { s_flash_guard_ops->end(); } } -static inline void IRAM_ATTR spi_flash_guard_op_lock() +static inline void IRAM_ATTR spi_flash_guard_op_lock(void) { if (s_flash_guard_ops && s_flash_guard_ops->op_lock) { s_flash_guard_ops->op_lock(); } } -static inline void IRAM_ATTR spi_flash_guard_op_unlock() +static inline void IRAM_ATTR spi_flash_guard_op_unlock(void) { if (s_flash_guard_ops && s_flash_guard_ops->op_unlock) { s_flash_guard_ops->op_unlock(); @@ -175,7 +175,7 @@ static inline void IRAM_ATTR spi_flash_guard_op_unlock() } #ifdef CONFIG_SPI_FLASH_USE_LEGACY_IMPL -static esp_rom_spiflash_result_t IRAM_ATTR spi_flash_unlock() +static esp_rom_spiflash_result_t IRAM_ATTR spi_flash_unlock(void) { static bool unlocked = false; if (!unlocked) { @@ -190,7 +190,7 @@ static esp_rom_spiflash_result_t IRAM_ATTR spi_flash_unlock() return ESP_ROM_SPIFLASH_RESULT_OK; } #else -static esp_rom_spiflash_result_t IRAM_ATTR spi_flash_unlock() +static esp_rom_spiflash_result_t IRAM_ATTR spi_flash_unlock(void) { esp_err_t err = esp_flash_set_chip_write_protect(NULL, false); if (err != ESP_OK) { @@ -677,17 +677,17 @@ static inline void dump_counter(spi_flash_counter_t *counter, const char *name) counter->count, counter->time, counter->bytes); } -const spi_flash_counters_t *spi_flash_get_counters() +const spi_flash_counters_t *spi_flash_get_counters(void) { return &s_flash_stats; } -void spi_flash_reset_counters() +void spi_flash_reset_counters(void) { memset(&s_flash_stats, 0, sizeof(s_flash_stats)); } -void spi_flash_dump_counters() +void spi_flash_dump_counters(void) { dump_counter(&s_flash_stats.read, "read "); dump_counter(&s_flash_stats.write, "write"); diff --git a/components/spi_flash/include/esp_flash.h b/components/spi_flash/include/esp_flash.h index 86737f791a..efcfccc247 100644 --- a/components/spi_flash/include/esp_flash.h +++ b/components/spi_flash/include/esp_flash.h @@ -271,7 +271,7 @@ extern esp_flash_t *esp_flash_default_chip; * * Called by OS startup code. You do not need to call this in your own applications. */ -esp_err_t esp_flash_init_default_chip(); +esp_err_t esp_flash_init_default_chip(void); /** * Enable OS-level SPI flash protections in IDF @@ -280,7 +280,7 @@ esp_err_t esp_flash_init_default_chip(); * * @return ESP_OK if success, otherwise failed. See return value of ``esp_flash_init_os_functions``. */ -esp_err_t esp_flash_app_init(); +esp_err_t esp_flash_app_init(void); /** * Enable OS-level SPI flash for a specific chip. diff --git a/components/spi_flash/include/esp_spi_flash.h b/components/spi_flash/include/esp_spi_flash.h index 795142f4a1..33bdc4d83c 100644 --- a/components/spi_flash/include/esp_spi_flash.h +++ b/components/spi_flash/include/esp_spi_flash.h @@ -41,7 +41,7 @@ extern "C" { * no need to call it from application code. * */ -void spi_flash_init(); +void spi_flash_init(void); /** * @brief Get flash chip size, as set in binary image header @@ -50,7 +50,7 @@ void spi_flash_init(); * * @return size of flash chip, in bytes */ -size_t spi_flash_get_chip_size(); +size_t spi_flash_get_chip_size(void); /** * @brief Erase the Flash sector. @@ -238,7 +238,7 @@ void spi_flash_munmap(spi_flash_mmap_handle_t handle); * of pages allocated to each handle. It also lists all non-zero entries of * MMU table and corresponding reference counts. */ -void spi_flash_mmap_dump(); +void spi_flash_mmap_dump(void); /** * @brief get free pages number which can be mmap @@ -293,7 +293,7 @@ const void *spi_flash_phys2cache(size_t phys_offs, spi_flash_mmap_memory_t memor * * @return true if both CPUs have flash cache enabled, false otherwise. */ -bool spi_flash_cache_enabled(); +bool spi_flash_cache_enabled(void); /** * @brief SPI flash critical section enter function. @@ -374,7 +374,7 @@ void spi_flash_guard_set(const spi_flash_guard_funcs_t* funcs); * @return The guard functions that were set via spi_flash_guard_set(). These functions * can be called if implementing custom low-level SPI flash operations. */ -const spi_flash_guard_funcs_t *spi_flash_guard_get(); +const spi_flash_guard_funcs_t *spi_flash_guard_get(void); /** * @brief Default OS-aware flash access guard functions @@ -409,12 +409,12 @@ typedef struct { /** * @brief Reset SPI flash operation counters */ -void spi_flash_reset_counters(); +void spi_flash_reset_counters(void); /** * @brief Print SPI flash operation counters */ -void spi_flash_dump_counters(); +void spi_flash_dump_counters(void); /** * @brief Return current SPI flash operation counters @@ -422,7 +422,7 @@ void spi_flash_dump_counters(); * @return pointer to the spi_flash_counters_t structure holding values * of the operation counters */ -const spi_flash_counters_t* spi_flash_get_counters(); +const spi_flash_counters_t* spi_flash_get_counters(void); #endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS diff --git a/components/spi_flash/partition.c b/components/spi_flash/partition.c index f31705c81c..14de32c9f5 100644 --- a/components/spi_flash/partition.c +++ b/components/spi_flash/partition.c @@ -54,7 +54,7 @@ typedef struct esp_partition_iterator_opaque_ { static esp_partition_iterator_opaque_t* iterator_create(esp_partition_type_t type, esp_partition_subtype_t subtype, const char* label); -static esp_err_t load_partitions(); +static esp_err_t load_partitions(void); static SLIST_HEAD(partition_list_head_, partition_list_item_) s_partition_list = @@ -146,7 +146,7 @@ static esp_partition_iterator_opaque_t* iterator_create(esp_partition_type_t typ // Create linked list of partition_list_item_t structures. // This function is called only once, with s_partition_list_lock taken. -static esp_err_t load_partitions() +static esp_err_t load_partitions(void) { const uint32_t* ptr; spi_flash_mmap_handle_t handle; diff --git a/components/spi_flash/sim/flash_mock.cpp b/components/spi_flash/sim/flash_mock.cpp index 1a275d5180..b089e22dc8 100644 --- a/components/spi_flash/sim/flash_mock.cpp +++ b/components/spi_flash/sim/flash_mock.cpp @@ -65,7 +65,7 @@ extern "C" void spi_flash_munmap(spi_flash_mmap_handle_t handle) return; } -extern "C" int spi_flash_get_total_erase_cycles() +extern "C" int spi_flash_get_total_erase_cycles(void) { return spiflash.get_total_erase_cycles(); } diff --git a/components/spi_flash/sim/flash_mock_util.c b/components/spi_flash/sim/flash_mock_util.c index a22b2854cc..770600e642 100644 --- a/components/spi_flash/sim/flash_mock_util.c +++ b/components/spi_flash/sim/flash_mock_util.c @@ -16,42 +16,42 @@ bool spi_flash_check_and_flush_cache(size_t start_addr, size_t length) return true; } -esp_rom_spiflash_result_t esp_rom_spiflash_unlock() +esp_rom_spiflash_result_t esp_rom_spiflash_unlock(void) { return ESP_ROM_SPIFLASH_RESULT_OK; } -void spi_flash_init_lock() +void spi_flash_init_lock(void) { return; } -void spi_flash_op_lock() +void spi_flash_op_lock(void) { return; } -void spi_flash_op_unlock() +void spi_flash_op_unlock(void) { return; } -void spi_flash_disable_interrupts_caches_and_other_cpu() +void spi_flash_disable_interrupts_caches_and_other_cpu(void) { return; } -void spi_flash_enable_interrupts_caches_and_other_cpu() +void spi_flash_enable_interrupts_caches_and_other_cpu(void) { return; } -void spi_flash_disable_interrupts_caches_and_other_cpu_no_os() +void spi_flash_disable_interrupts_caches_and_other_cpu_no_os(void) { return; } -void spi_flash_enable_interrupts_caches_no_os() +void spi_flash_enable_interrupts_caches_no_os(void) { return; } diff --git a/components/spi_flash/sim/stubs/log/log.c b/components/spi_flash/sim/stubs/log/log.c index 5d606d357f..4c8dc78023 100644 --- a/components/spi_flash/sim/stubs/log/log.c +++ b/components/spi_flash/sim/stubs/log/log.c @@ -15,7 +15,7 @@ void esp_log_write(esp_log_level_t level, va_end(arg); } -uint32_t esp_log_timestamp() +uint32_t esp_log_timestamp(void) { return 0; } diff --git a/components/spi_flash/spi_flash_rom_patch.c b/components/spi_flash/spi_flash_rom_patch.c index adf62fa572..af3d5d47df 100644 --- a/components/spi_flash/spi_flash_rom_patch.c +++ b/components/spi_flash/spi_flash_rom_patch.c @@ -53,7 +53,7 @@ esp_rom_spiflash_result_t esp_rom_spiflash_wait_idle(esp_rom_spiflash_chip_t *sp about interrupts, CPU coordination, flash mapping. However some of the functions in esp_spi_flash.c call it. */ -esp_rom_spiflash_result_t esp_rom_spiflash_unlock() +esp_rom_spiflash_result_t esp_rom_spiflash_unlock(void) { uint32_t status; @@ -349,7 +349,7 @@ static void spi_cache_mode_switch(uint32_t modebit) } -esp_rom_spiflash_result_t esp_rom_spiflash_lock() +esp_rom_spiflash_result_t esp_rom_spiflash_lock(void) { uint32_t status; @@ -401,7 +401,7 @@ esp_rom_spiflash_result_t esp_rom_spiflash_config_readmode(esp_rom_spiflash_read return ESP_ROM_SPIFLASH_RESULT_OK; } -esp_rom_spiflash_result_t esp_rom_spiflash_erase_chip() +esp_rom_spiflash_result_t esp_rom_spiflash_erase_chip(void) { if ( ESP_ROM_SPIFLASH_RESULT_OK != esp_rom_spiflash_enable_write(&g_rom_spiflash_chip)) { return ESP_ROM_SPIFLASH_RESULT_ERR; diff --git a/components/spi_flash/test/test_esp_flash.c b/components/spi_flash/test/test_esp_flash.c index bf13845453..49d144c9c1 100644 --- a/components/spi_flash/test/test_esp_flash.c +++ b/components/spi_flash/test/test_esp_flash.c @@ -147,7 +147,7 @@ static void setup_new_chip(esp_flash_read_mode_t io_mode, esp_flash_speed_t spee TEST_ESP_OK(err); } -void teardown_test_chip() +void teardown_test_chip(void) { spi_bus_remove_flash_device(test_chip); test_chip = NULL; diff --git a/components/spi_flash/test/test_flash_encryption.c b/components/spi_flash/test/test_flash_encryption.c index 16579930c6..ea647f3360 100644 --- a/components/spi_flash/test/test_flash_encryption.c +++ b/components/spi_flash/test/test_flash_encryption.c @@ -14,7 +14,7 @@ static void verify_erased_flash(size_t offset, size_t length); static size_t start; -static void setup_tests() +static void setup_tests(void) { if (start == 0) { const esp_partition_t *part = get_test_data_partition(); diff --git a/components/spi_flash/test/test_mmap.c b/components/spi_flash/test/test_mmap.c index fe14a8be05..52a5be1f3a 100644 --- a/components/spi_flash/test/test_mmap.c +++ b/components/spi_flash/test/test_mmap.c @@ -21,7 +21,7 @@ static uint32_t end; static spi_flash_mmap_handle_t handle1, handle2, handle3; -static void setup_mmap_tests() +static void setup_mmap_tests(void) { if (start == 0) { const esp_partition_t *part = get_test_data_partition(); diff --git a/components/spi_flash/test/test_read_write.c b/components/spi_flash/test/test_read_write.c index febe95bf80..e780b6e2fe 100644 --- a/components/spi_flash/test/test_read_write.c +++ b/components/spi_flash/test/test_read_write.c @@ -31,7 +31,7 @@ /* Base offset in flash for tests. */ static size_t start; -static void setup_tests() +static void setup_tests(void) { if (start == 0) { const esp_partition_t *part = get_test_data_partition(); diff --git a/components/spiffs/test/test_spiffs.c b/components/spiffs/test/test_spiffs.c index b5dc129e31..34a2de8745 100644 --- a/components/spiffs/test/test_spiffs.c +++ b/components/spiffs/test/test_spiffs.c @@ -448,7 +448,7 @@ void test_spiffs_concurrent(const char* filename_prefix) } -static void test_setup() +static void test_setup(void) { esp_vfs_spiffs_conf_t conf = { .base_path = "/spiffs", @@ -460,7 +460,7 @@ static void test_setup() TEST_ESP_OK(esp_vfs_spiffs_register(&conf)); } -static void test_teardown() +static void test_teardown(void) { TEST_ESP_OK(esp_vfs_spiffs_unregister(spiffs_test_partition_label)); } diff --git a/components/tcp_transport/include/esp_transport.h b/components/tcp_transport/include/esp_transport.h index 9dd7ff4495..39e694f058 100644 --- a/components/tcp_transport/include/esp_transport.h +++ b/components/tcp_transport/include/esp_transport.h @@ -40,7 +40,7 @@ typedef struct esp_tls_last_error* esp_tls_error_handle_t; * * @return A handle can hold all transports */ -esp_transport_list_handle_t esp_transport_list_init(); +esp_transport_list_handle_t esp_transport_list_init(void); /** * @brief Cleanup and free all transports, include itself, @@ -93,7 +93,7 @@ esp_transport_handle_t esp_transport_list_get_transport(esp_transport_list_handl * * @return The transport handle */ -esp_transport_handle_t esp_transport_init(); +esp_transport_handle_t esp_transport_init(void); /** * @brief Cleanup and free memory the transport diff --git a/components/tcp_transport/include/esp_transport_ssl.h b/components/tcp_transport/include/esp_transport_ssl.h index 0f83c1d6e4..330b68518b 100644 --- a/components/tcp_transport/include/esp_transport_ssl.h +++ b/components/tcp_transport/include/esp_transport_ssl.h @@ -27,7 +27,7 @@ extern "C" { * * @return the allocated esp_transport_handle_t, or NULL if the handle can not be allocated */ -esp_transport_handle_t esp_transport_ssl_init(); +esp_transport_handle_t esp_transport_ssl_init(void); /** * @brief Set SSL certificate data (as PEM format). diff --git a/components/tcp_transport/include/esp_transport_tcp.h b/components/tcp_transport/include/esp_transport_tcp.h index 57ad453309..7a283fe9d5 100644 --- a/components/tcp_transport/include/esp_transport_tcp.h +++ b/components/tcp_transport/include/esp_transport_tcp.h @@ -26,7 +26,7 @@ extern "C" { * * @return the allocated esp_transport_handle_t, or NULL if the handle can not be allocated */ -esp_transport_handle_t esp_transport_tcp_init(); +esp_transport_handle_t esp_transport_tcp_init(void); #ifdef __cplusplus diff --git a/components/tcp_transport/transport.c b/components/tcp_transport/transport.c index b48acf908d..d5bc57bb48 100644 --- a/components/tcp_transport/transport.c +++ b/components/tcp_transport/transport.c @@ -70,7 +70,7 @@ static esp_transport_handle_t esp_transport_get_default_parent(esp_transport_han return t; } -esp_transport_list_handle_t esp_transport_list_init() +esp_transport_list_handle_t esp_transport_list_init(void) { esp_transport_list_handle_t transport = calloc(1, sizeof(esp_transport_internal_t)); ESP_TRANSPORT_MEM_CHECK(TAG, transport, return NULL); @@ -131,7 +131,7 @@ esp_err_t esp_transport_list_clean(esp_transport_list_handle_t h) return ESP_OK; } -esp_transport_handle_t esp_transport_init() +esp_transport_handle_t esp_transport_init(void) { esp_transport_handle_t t = calloc(1, sizeof(struct esp_transport_item_t)); ESP_TRANSPORT_MEM_CHECK(TAG, t, return NULL); diff --git a/components/tcp_transport/transport_ssl.c b/components/tcp_transport/transport_ssl.c index 1651a2f87f..e05802930a 100644 --- a/components/tcp_transport/transport_ssl.c +++ b/components/tcp_transport/transport_ssl.c @@ -204,7 +204,7 @@ void esp_transport_ssl_skip_common_name_check(esp_transport_handle_t t) } } -esp_transport_handle_t esp_transport_ssl_init() +esp_transport_handle_t esp_transport_ssl_init(void) { esp_transport_handle_t t = esp_transport_init(); transport_ssl_t *ssl = calloc(1, sizeof(transport_ssl_t)); diff --git a/components/tcp_transport/transport_tcp.c b/components/tcp_transport/transport_tcp.c index ff6925b2d1..6de1d22379 100644 --- a/components/tcp_transport/transport_tcp.c +++ b/components/tcp_transport/transport_tcp.c @@ -153,7 +153,7 @@ static esp_err_t tcp_destroy(esp_transport_handle_t t) return 0; } -esp_transport_handle_t esp_transport_tcp_init() +esp_transport_handle_t esp_transport_tcp_init(void) { esp_transport_handle_t t = esp_transport_init(); transport_tcp_t *tcp = calloc(1, sizeof(transport_tcp_t)); diff --git a/components/tcpip_adapter/event_handlers.c b/components/tcpip_adapter/event_handlers.c index d22d18a051..5e3717c568 100644 --- a/components/tcpip_adapter/event_handlers.c +++ b/components/tcpip_adapter/event_handlers.c @@ -198,7 +198,7 @@ static void handle_sta_disconnected(void *arg, esp_event_base_t base, int32_t ev } -esp_err_t tcpip_adapter_set_default_wifi_handlers() +esp_err_t tcpip_adapter_set_default_wifi_handlers(void) { esp_err_t err; err = esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_START, handle_sta_start, NULL); @@ -248,7 +248,7 @@ fail: return err; } -esp_err_t tcpip_adapter_clear_default_wifi_handlers() +esp_err_t tcpip_adapter_clear_default_wifi_handlers(void) { esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_START, handle_sta_start); esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_STOP, handle_sta_stop); @@ -262,7 +262,7 @@ esp_err_t tcpip_adapter_clear_default_wifi_handlers() return ESP_OK; } -esp_err_t tcpip_adapter_set_default_eth_handlers() +esp_err_t tcpip_adapter_set_default_eth_handlers(void) { esp_err_t err; err = esp_event_handler_register(ETH_EVENT, ETHERNET_EVENT_START, handle_eth_start, NULL); @@ -297,7 +297,7 @@ fail: return err; } -esp_err_t tcpip_adapter_clear_default_eth_handlers() +esp_err_t tcpip_adapter_clear_default_eth_handlers(void) { esp_event_handler_unregister(ETH_EVENT, ETHERNET_EVENT_START, handle_eth_start); esp_event_handler_unregister(ETH_EVENT, ETHERNET_EVENT_STOP, handle_eth_stop); diff --git a/components/tcpip_adapter/include/tcpip_adapter.h b/components/tcpip_adapter/include/tcpip_adapter.h index 4c0a4af4fd..f880511f71 100644 --- a/components/tcpip_adapter/include/tcpip_adapter.h +++ b/components/tcpip_adapter/include/tcpip_adapter.h @@ -714,7 +714,7 @@ esp_err_t tcpip_adapter_test_start(uint8_t *mac, tcpip_adapter_ip_info_t *ip_inf * - ESP_OK on success * - one of the errors from esp_event on failure */ -esp_err_t tcpip_adapter_set_default_eth_handlers(); +esp_err_t tcpip_adapter_set_default_eth_handlers(void); /** * @brief Uninstall default event handlers for Ethernet interface @@ -722,7 +722,7 @@ esp_err_t tcpip_adapter_set_default_eth_handlers(); * - ESP_OK on success * - one of the errors from esp_event on failure */ -esp_err_t tcpip_adapter_clear_default_eth_handlers(); +esp_err_t tcpip_adapter_clear_default_eth_handlers(void); /** * @brief Install default event handlers for Wi-Fi interfaces (station and AP) @@ -730,7 +730,7 @@ esp_err_t tcpip_adapter_clear_default_eth_handlers(); * - ESP_OK on success * - one of the errors from esp_event on failure */ -esp_err_t tcpip_adapter_set_default_wifi_handlers(); +esp_err_t tcpip_adapter_set_default_wifi_handlers(void); /** * @brief Uninstall default event handlers for Wi-Fi interfaces (station and AP) @@ -738,7 +738,7 @@ esp_err_t tcpip_adapter_set_default_wifi_handlers(); * - ESP_OK on success * - one of the errors from esp_event on failure */ -esp_err_t tcpip_adapter_clear_default_wifi_handlers(); +esp_err_t tcpip_adapter_clear_default_wifi_handlers(void); /** * @brief Search nefit index through netif interface diff --git a/components/unity/include/unity_test_runner.h b/components/unity/include/unity_test_runner.h index 8f41eb83d7..a9a1fae49d 100644 --- a/components/unity/include/unity_test_runner.h +++ b/components/unity/include/unity_test_runner.h @@ -168,7 +168,7 @@ void unity_run_test_by_name(const char *name); void unity_run_tests_by_tag(const char *tag, bool invert); -void unity_run_all_tests(); +void unity_run_all_tests(void); -void unity_run_menu(); +void unity_run_menu(void); diff --git a/components/unity/unity_port_esp32.c b/components/unity/unity_port_esp32.c index 9c13700078..2517cd94c0 100644 --- a/components/unity/unity_port_esp32.c +++ b/components/unity/unity_port_esp32.c @@ -31,7 +31,7 @@ void unity_putc(int c) } } -void unity_flush() +void unity_flush(void) { uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); } diff --git a/components/unity/unity_runner.c b/components/unity/unity_runner.c index e88840d2fd..3c07b250f6 100644 --- a/components/unity/unity_runner.c +++ b/components/unity/unity_runner.c @@ -178,7 +178,7 @@ void unity_run_test_by_name(const char *name) } } -void unity_run_all_tests() +void unity_run_all_tests(void) { for (const test_desc_t *test = s_unity_tests_first; test != NULL; test = test->next) { unity_run_single_test(test); @@ -265,7 +265,7 @@ static int get_test_count(void) return test_counter; } -void unity_run_menu() +void unity_run_menu(void) { UNITY_PRINT_EOL(); UNITY_PRINT_EOL(); diff --git a/components/vfs/include/esp_vfs_dev.h b/components/vfs/include/esp_vfs_dev.h index b330b4c565..95daaa61fd 100644 --- a/components/vfs/include/esp_vfs_dev.h +++ b/components/vfs/include/esp_vfs_dev.h @@ -34,7 +34,7 @@ typedef enum { * * This function is called from startup code to enable serial output */ -void esp_vfs_dev_uart_register(); +void esp_vfs_dev_uart_register(void); /** * @brief Set the line endings expected to be received on UART diff --git a/components/vfs/test/test_vfs_access.c b/components/vfs/test/test_vfs_access.c index 02e7d56f82..ed691f998b 100644 --- a/components/vfs/test/test_vfs_access.c +++ b/components/vfs/test/test_vfs_access.c @@ -58,7 +58,7 @@ TEST_CASE("Can use access() for UART", "[vfs]") uart_driver_delete(UART_NUM_2); } -static inline void test_spi_flash_setup() +static inline void test_spi_flash_setup(void) { esp_vfs_fat_sdmmc_mount_config_t mount_config = { .format_if_mount_failed = true, @@ -68,7 +68,7 @@ static inline void test_spi_flash_setup() TEST_ESP_OK(esp_vfs_fat_spiflash_mount("/spiflash", NULL, &mount_config, &test_wl_handle)); } -static inline void test_spi_flash_teardown() +static inline void test_spi_flash_teardown(void) { TEST_ESP_OK(esp_vfs_fat_spiflash_unmount("/spiflash", test_wl_handle)); } diff --git a/components/vfs/test/test_vfs_select.c b/components/vfs/test/test_vfs_select.c index c8ff500da2..bea17242e1 100644 --- a/components/vfs/test/test_vfs_select.c +++ b/components/vfs/test/test_vfs_select.c @@ -33,7 +33,7 @@ typedef struct { static const char message[] = "Hello world!"; -static int open_dummy_socket() +static int open_dummy_socket(void) { const struct addrinfo hints = { .ai_family = AF_INET, @@ -51,7 +51,7 @@ static int open_dummy_socket() return dummy_socket_fd; } -static int socket_init() +static int socket_init(void) { const struct addrinfo hints = { .ai_family = AF_INET, @@ -83,7 +83,7 @@ static int socket_init() return socket_fd; } -static void uart1_init() +static void uart1_init(void) { uart_config_t uart_config = { .baud_rate = 115200, diff --git a/components/vfs/test/test_vfs_uart.c b/components/vfs/test/test_vfs_uart.c index 5c3d3f1d60..262eb4f086 100644 --- a/components/vfs/test/test_vfs_uart.c +++ b/components/vfs/test/test_vfs_uart.c @@ -39,7 +39,7 @@ static void fwrite_str_loopback(const char* str, size_t size) UART0.conf0.loopback = 0; } -static void flush_stdin_stdout() +static void flush_stdin_stdout(void) { vTaskDelay(10 / portTICK_PERIOD_MS); char *bitbucket = (char*) 0x3f000000; diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index 0fc5aead31..c604b09738 100644 --- a/components/vfs/vfs.c +++ b/components/vfs/vfs.c @@ -1249,7 +1249,7 @@ int esp_vfs_poll(struct pollfd *fds, nfds_t nfds, int timeout) return ret; } -void vfs_include_syscalls_impl() +void vfs_include_syscalls_impl(void) { // Linker hook function, exists to make the linker examine this fine } diff --git a/components/vfs/vfs_uart.c b/components/vfs/vfs_uart.c index 5cb179a4a6..d996e9eebd 100644 --- a/components/vfs/vfs_uart.c +++ b/components/vfs/vfs_uart.c @@ -123,7 +123,7 @@ static fd_set *_writefds_orig = NULL; static fd_set *_errorfds_orig = NULL; -static void uart_end_select(); +static void uart_end_select(void); static int uart_open(const char * path, int flags, int mode) @@ -432,7 +432,7 @@ static esp_err_t uart_start_select(int nfds, fd_set *readfds, fd_set *writefds, return ESP_OK; } -static void uart_end_select() +static void uart_end_select(void) { portENTER_CRITICAL(uart_get_selectlock()); for (int i = 0; i < UART_NUM; ++i) { @@ -915,7 +915,7 @@ static int uart_tcflush(int fd, int select) } #endif // CONFIG_VFS_SUPPORT_TERMIOS -void esp_vfs_dev_uart_register() +void esp_vfs_dev_uart_register(void) { esp_vfs_t vfs = { .flags = ESP_VFS_FLAG_DEFAULT, diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c index d565cd1cba..6f37b18500 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c @@ -71,7 +71,7 @@ void wpa_deauthenticate(u8 reason_code) esp_wifi_deauthenticate_internal(reason_code); } -void wpa_config_profile() +void wpa_config_profile(void) { if (esp_wifi_sta_prof_is_wpa_internal()) { wpa_set_profile(WPA_PROTO_WPA, esp_wifi_sta_get_prof_authmode_internal()); @@ -102,7 +102,7 @@ void wpa_config_assoc_ie(u8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len) } } -void wpa_neg_complete() +void wpa_neg_complete(void) { esp_wifi_auth_done_internal(); } diff --git a/examples/bluetooth/ble_ancs/main/ble_ancs_demo.c b/examples/bluetooth/ble_ancs/main/ble_ancs_demo.c index 294a8a1061..4dc89b83ac 100644 --- a/examples/bluetooth/ble_ancs/main/ble_ancs_demo.c +++ b/examples/bluetooth/ble_ancs/main/ble_ancs_demo.c @@ -596,7 +596,7 @@ void init_timer(void) ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer)); } -void app_main() +void app_main(void) { esp_err_t ret; diff --git a/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.c b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.c index fca661d2c1..7c1ca1c0b4 100644 --- a/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.c +++ b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.c @@ -615,7 +615,7 @@ static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_ } while (0); } -void app_main() +void app_main(void) { esp_err_t ret; diff --git a/examples/bluetooth/bluedroid/ble/ble_eddystone/main/esp_eddystone_demo.c b/examples/bluetooth/bluedroid/ble/ble_eddystone/main/esp_eddystone_demo.c index 525bcd2ae3..f41ebf6c13 100644 --- a/examples/bluetooth/bluedroid/ble/ble_eddystone/main/esp_eddystone_demo.c +++ b/examples/bluetooth/bluedroid/ble/ble_eddystone/main/esp_eddystone_demo.c @@ -160,7 +160,7 @@ void esp_eddystone_init(void) esp_eddystone_appRegister(); } -void app_main() +void app_main(void) { ESP_ERROR_CHECK(nvs_flash_init()); ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)); diff --git a/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/ble_hidd_demo_main.c b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/ble_hidd_demo_main.c index e26fa38d9f..b7584735a9 100644 --- a/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/ble_hidd_demo_main.c +++ b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/ble_hidd_demo_main.c @@ -183,7 +183,7 @@ void hid_demo_task(void *pvParameters) } -void app_main() +void app_main(void) { esp_err_t ret; diff --git a/examples/bluetooth/bluedroid/ble/ble_ibeacon/main/ibeacon_demo.c b/examples/bluetooth/bluedroid/ble/ble_ibeacon/main/ibeacon_demo.c index dcad4dd4a2..7aa8ae26dc 100644 --- a/examples/bluetooth/bluedroid/ble/ble_ibeacon/main/ibeacon_demo.c +++ b/examples/bluetooth/bluedroid/ble/ble_ibeacon/main/ibeacon_demo.c @@ -163,7 +163,7 @@ void ble_ibeacon_init(void) ble_ibeacon_appRegister(); } -void app_main() +void app_main(void) { ESP_ERROR_CHECK(nvs_flash_init()); ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)); diff --git a/examples/bluetooth/bluedroid/ble/ble_spp_client/main/spp_client_demo.c b/examples/bluetooth/bluedroid/ble/ble_spp_client/main/spp_client_demo.c index ae3da8e1c6..f1a91e9bdd 100644 --- a/examples/bluetooth/bluedroid/ble/ble_spp_client/main/spp_client_demo.c +++ b/examples/bluetooth/bluedroid/ble/ble_spp_client/main/spp_client_demo.c @@ -604,7 +604,7 @@ static void spp_uart_init(void) xTaskCreate(uart_task, "uTask", 2048, (void*)UART_NUM_0, 8, NULL); } -void app_main() +void app_main(void) { esp_err_t ret; diff --git a/examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.c b/examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.c index 999b047e78..f1eaba16bc 100644 --- a/examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.c +++ b/examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.c @@ -648,7 +648,7 @@ static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_ } while (0); } -void app_main() +void app_main(void) { esp_err_t ret; esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); diff --git a/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/main/example_ble_client_throughput.c b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/main/example_ble_client_throughput.c index b0ca2daa9b..6ae2cee937 100644 --- a/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/main/example_ble_client_throughput.c +++ b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/main/example_ble_client_throughput.c @@ -510,7 +510,7 @@ static void throughput_client_task(void *param) } } -void app_main() +void app_main(void) { // Initialize NVS. esp_err_t ret = nvs_flash_init(); diff --git a/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/main/example_ble_server_throughput.c b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/main/example_ble_server_throughput.c index 3467104f34..b8a8f621cf 100644 --- a/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/main/example_ble_server_throughput.c +++ b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/main/example_ble_server_throughput.c @@ -640,7 +640,7 @@ void throughput_server_task(void *param) } } -void app_main() +void app_main(void) { esp_err_t ret; diff --git a/examples/bluetooth/bluedroid/ble/blufi/main/blufi_example_main.c b/examples/bluetooth/bluedroid/ble/blufi/main/blufi_example_main.c index 4106dd24eb..bd3b86e219 100644 --- a/examples/bluetooth/bluedroid/ble/blufi/main/blufi_example_main.c +++ b/examples/bluetooth/bluedroid/ble/blufi/main/blufi_example_main.c @@ -375,7 +375,7 @@ static void example_gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_ } } -void app_main() +void app_main(void) { esp_err_t ret; diff --git a/examples/bluetooth/bluedroid/ble/gatt_client/main/gattc_demo.c b/examples/bluetooth/bluedroid/ble/gatt_client/main/gattc_demo.c index 2bd7798362..e53d85d338 100644 --- a/examples/bluetooth/bluedroid/ble/gatt_client/main/gattc_demo.c +++ b/examples/bluetooth/bluedroid/ble/gatt_client/main/gattc_demo.c @@ -436,7 +436,7 @@ static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp } while (0); } -void app_main() +void app_main(void) { // Initialize NVS. esp_err_t ret = nvs_flash_init(); diff --git a/examples/bluetooth/bluedroid/ble/gatt_security_client/main/example_ble_sec_gattc_demo.c b/examples/bluetooth/bluedroid/ble/gatt_security_client/main/example_ble_sec_gattc_demo.c index fa9e8914bf..365fb40d8d 100644 --- a/examples/bluetooth/bluedroid/ble/gatt_security_client/main/example_ble_sec_gattc_demo.c +++ b/examples/bluetooth/bluedroid/ble/gatt_security_client/main/example_ble_sec_gattc_demo.c @@ -509,7 +509,7 @@ static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp } while (0); } -void app_main() +void app_main(void) { // Initialize NVS. esp_err_t ret = nvs_flash_init(); diff --git a/examples/bluetooth/bluedroid/ble/gatt_security_server/main/example_ble_sec_gatts_demo.c b/examples/bluetooth/bluedroid/ble/gatt_security_server/main/example_ble_sec_gatts_demo.c index a7c80182fd..6cbfb71820 100644 --- a/examples/bluetooth/bluedroid/ble/gatt_security_server/main/example_ble_sec_gatts_demo.c +++ b/examples/bluetooth/bluedroid/ble/gatt_security_server/main/example_ble_sec_gatts_demo.c @@ -497,7 +497,7 @@ static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_ } while (0); } -void app_main() +void app_main(void) { esp_err_t ret; diff --git a/examples/bluetooth/bluedroid/ble/gatt_server/main/gatts_demo.c b/examples/bluetooth/bluedroid/ble/gatt_server/main/gatts_demo.c index 6770d8f862..ea140e8ccc 100644 --- a/examples/bluetooth/bluedroid/ble/gatt_server/main/gatts_demo.c +++ b/examples/bluetooth/bluedroid/ble/gatt_server/main/gatts_demo.c @@ -671,7 +671,7 @@ static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_ } while (0); } -void app_main() +void app_main(void) { esp_err_t ret; diff --git a/examples/bluetooth/bluedroid/ble/gatt_server_service_table/main/gatts_table_creat_demo.c b/examples/bluetooth/bluedroid/ble/gatt_server_service_table/main/gatts_table_creat_demo.c index e583578652..b6a9abffaf 100644 --- a/examples/bluetooth/bluedroid/ble/gatt_server_service_table/main/gatts_table_creat_demo.c +++ b/examples/bluetooth/bluedroid/ble/gatt_server_service_table/main/gatts_table_creat_demo.c @@ -512,7 +512,7 @@ static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_ } while (0); } -void app_main() +void app_main(void) { esp_err_t ret; diff --git a/examples/bluetooth/bluedroid/ble/gattc_multi_connect/main/gattc_multi_connect.c b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/main/gattc_multi_connect.c index b6499a7668..175c0f98e6 100644 --- a/examples/bluetooth/bluedroid/ble/gattc_multi_connect/main/gattc_multi_connect.c +++ b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/main/gattc_multi_connect.c @@ -883,7 +883,7 @@ static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp } while (0); } -void app_main() +void app_main(void) { esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { diff --git a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c index adaf8ff43b..c5a90f0892 100644 --- a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c +++ b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c @@ -42,7 +42,7 @@ enum { static void bt_av_hdl_stack_evt(uint16_t event, void *p_param); -void app_main() +void app_main(void) { /* Initialize NVS — it is used to store PHY calibration data */ esp_err_t err = nvs_flash_init(); diff --git a/examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/main.c b/examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/main.c index a3971f8cdb..25f66c90fc 100644 --- a/examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/main.c +++ b/examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/main.c @@ -107,7 +107,7 @@ static char *bda2str(esp_bd_addr_t bda, char *str, size_t size) return str; } -void app_main() +void app_main(void) { // Initialize NVS. esp_err_t ret = nvs_flash_init(); diff --git a/examples/bluetooth/bluedroid/classic_bt/bt_discovery/main/bt_discovery.c b/examples/bluetooth/bluedroid/classic_bt/bt_discovery/main/bt_discovery.c index af753cb09e..cb8a687f02 100644 --- a/examples/bluetooth/bluedroid/classic_bt/bt_discovery/main/bt_discovery.c +++ b/examples/bluetooth/bluedroid/classic_bt/bt_discovery/main/bt_discovery.c @@ -269,7 +269,7 @@ void bt_app_gap_start_up(void) esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0); } -void app_main() +void app_main(void) { /* Initialize NVS — it is used to store PHY calibration data */ esp_err_t ret = nvs_flash_init(); diff --git a/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/main/example_spp_acceptor_demo.c b/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/main/example_spp_acceptor_demo.c index cf82c2724e..c654d86167 100644 --- a/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/main/example_spp_acceptor_demo.c +++ b/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/main/example_spp_acceptor_demo.c @@ -154,7 +154,7 @@ void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param) return; } -void app_main() +void app_main(void) { esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { diff --git a/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/example_spp_initiator_demo.c b/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/example_spp_initiator_demo.c index cd4365996c..39705a9901 100644 --- a/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/example_spp_initiator_demo.c +++ b/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/example_spp_initiator_demo.c @@ -235,7 +235,7 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa } } -void app_main() +void app_main(void) { for (int i = 0; i < SPP_DATA_LEN; ++i) { spp_data[i] = i; diff --git a/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/example_spp_vfs_acceptor_demo.c b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/example_spp_vfs_acceptor_demo.c index 092756b724..d24ea1053b 100644 --- a/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/example_spp_vfs_acceptor_demo.c +++ b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/example_spp_vfs_acceptor_demo.c @@ -159,7 +159,7 @@ void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param) return; } -void app_main() +void app_main(void) { esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { diff --git a/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/example_spp_vfs_initiator_demo.c b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/example_spp_vfs_initiator_demo.c index fc34a8f024..9be627fe6d 100644 --- a/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/example_spp_vfs_initiator_demo.c +++ b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/example_spp_vfs_initiator_demo.c @@ -223,7 +223,7 @@ static void esp_spp_stack_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param spp_task_work_dispatch(esp_spp_cb, event, param, sizeof(esp_spp_cb_param_t), NULL); } -void app_main() +void app_main(void) { for (int i = 0; i < SPP_DATA_LEN; ++i) { spp_data[i] = i; diff --git a/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c index 466a2ce8d6..b69fada106 100644 --- a/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c +++ b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c @@ -669,7 +669,7 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param) } } -void app_main() +void app_main(void) { /* Initialize NVS — it is used to store PHY calibration data */ esp_err_t err = nvs_flash_init(); diff --git a/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/main/gattc_gatts_coex.c b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/main/gattc_gatts_coex.c index 3e4989372c..00172ebd9b 100644 --- a/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/main/gattc_gatts_coex.c +++ b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/main/gattc_gatts_coex.c @@ -942,7 +942,7 @@ static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_ } while (0); } -void app_main() +void app_main(void) { esp_err_t ret; diff --git a/examples/bluetooth/bluedroid/hci/controller_hci_uart/main/controller_hci_uart_demo.c b/examples/bluetooth/bluedroid/hci/controller_hci_uart/main/controller_hci_uart_demo.c index 0eb7ef7781..6214dec136 100644 --- a/examples/bluetooth/bluedroid/hci/controller_hci_uart/main/controller_hci_uart_demo.c +++ b/examples/bluetooth/bluedroid/hci/controller_hci_uart/main/controller_hci_uart_demo.c @@ -31,7 +31,7 @@ static void uart_gpio_reset(void) #endif } -void app_main() +void app_main(void) { esp_err_t ret; diff --git a/examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/main/app_bt.c b/examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/main/app_bt.c index 0a67c32468..09f78064cf 100644 --- a/examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/main/app_bt.c +++ b/examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/main/app_bt.c @@ -210,7 +210,7 @@ void bleAdvtTask(void *pvParameters) } } -void app_main() +void app_main(void) { /* Initialize NVS — it is used to store PHY calibration data */ esp_err_t ret = nvs_flash_init(); diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.c index 5cf017bdca..b8d1775b34 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.c @@ -72,7 +72,7 @@ esp_ble_mesh_comp_t *ble_mesh_get_component(uint16_t model_id) return comp; } -void ble_mesh_node_init() +void ble_mesh_node_init(void) { uint16_t i; @@ -100,7 +100,7 @@ void ble_mesh_set_node_prestore_params(uint16_t netkey_index, uint16_t unicast_a xSemaphoreGive(ble_mesh_node_sema); } -void ble_mesh_node_statistics_get() +void ble_mesh_node_statistics_get(void) { xSemaphoreTake(ble_mesh_node_sema, portMAX_DELAY); ESP_LOGI(TAG, "statistics:%d,%d\n", ble_mesh_node_statistics.statistics, ble_mesh_node_statistics.package_num); @@ -156,7 +156,7 @@ int ble_mesh_node_statistics_init(uint16_t package_num) return 0; } -void ble_mesh_node_statistics_destroy() +void ble_mesh_node_statistics_destroy(void) { if (ble_mesh_node_statistics.package_index != NULL) { free(ble_mesh_node_statistics.package_index); diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.h index 06c876fd64..d7feee5fe4 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.h +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.h @@ -85,13 +85,13 @@ extern SemaphoreHandle_t ble_mesh_node_sema; } \ }while(0) \ -void ble_mesh_node_init(); +void ble_mesh_node_init(void); void ble_mesh_set_node_prestore_params(uint16_t netkey_index, uint16_t unicast_addr); esp_ble_mesh_model_t *ble_mesh_get_model(uint16_t model_id); esp_ble_mesh_comp_t *ble_mesh_get_component(uint16_t model_id); -void ble_mesh_node_statistics_get(); +void ble_mesh_node_statistics_get(void); int ble_mesh_node_statistics_accumultate(uint8_t *data, uint32_t value, uint16_t type); int ble_mesh_node_statistics_init(uint16_t package_num); -void ble_mesh_node_statistics_destroy(); +void ble_mesh_node_statistics_destroy(void); #endif //_BLE_MESH_ADAOTER_H_ diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_decl.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_decl.h index 22ab3a7f59..2e983265d3 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_decl.h +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_decl.h @@ -11,18 +11,18 @@ #include "esp_ble_mesh_defs.h" // Register system functions -void register_system(); +void register_system(void); // Register blutooth -void register_bluetooth(); +void register_bluetooth(void); // Register mesh node cmd -void ble_mesh_register_mesh_node(); +void ble_mesh_register_mesh_node(void); // Register mesh config server and generic server operation cmd -void ble_mesh_register_server(); +void ble_mesh_register_server(void); #if (CONFIG_BLE_MESH_CFG_CLI) // Register mesh config client operation cmd -void ble_mesh_register_configuration_client_model(); +void ble_mesh_register_configuration_client_model(void); #endif diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c index f1f9635526..25857bc96d 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c @@ -36,7 +36,7 @@ #define MOUNT_PATH "/data" #define HISTORY_PATH MOUNT_PATH "/history.txt" -static void initialize_filesystem() +static void initialize_filesystem(void) { static wl_handle_t wl_handle; const esp_vfs_fat_mount_config_t mount_config = { @@ -51,7 +51,7 @@ static void initialize_filesystem() } #endif // CONFIG_STORE_HISTORY -static void initialize_console() +static void initialize_console(void) { /* Disable buffering on stdin and stdout */ setvbuf(stdin, NULL, _IONBF, 0); diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_system.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_system.c index cc8805dbf2..88c0a6a0a9 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_system.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_system.c @@ -28,11 +28,11 @@ #define CONFIG_ESPTOOLPY_PORT "Which is choosen by Users for CMake" #endif -static void register_free(); -static void register_restart(); -static void register_make(); +static void register_free(void); +static void register_restart(void); +static void register_make(void); -void register_system() +void register_system(void) { register_free(); register_restart(); @@ -47,7 +47,7 @@ static int restart(int argc, char **argv) esp_restart(); } -static void register_restart() +static void register_restart(void) { const esp_console_cmd_t cmd = { .command = "restart", @@ -66,7 +66,7 @@ static int free_mem(int argc, char **argv) return 0; } -static void register_free() +static void register_free(void) { const esp_console_cmd_t cmd = { .command = "free", @@ -169,7 +169,7 @@ R"(MONITOR return 0; } -static void register_make() +static void register_make(void) { const esp_console_cmd_t cmd = { .command = "make", diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c index 919e69f777..6dc356cdab 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c @@ -86,18 +86,18 @@ ble_mesh_node_status node_status = { SemaphoreHandle_t ble_mesh_node_sema; -void ble_mesh_register_node_cmd(); +void ble_mesh_register_node_cmd(void); // Register callback function void ble_mesh_prov_cb(esp_ble_mesh_prov_cb_event_t event, esp_ble_mesh_prov_cb_param_t *param); void ble_mesh_model_cb(esp_ble_mesh_model_cb_event_t event, esp_ble_mesh_model_cb_param_t *param); -void ble_mesh_register_mesh_node() +void ble_mesh_register_mesh_node(void) { ble_mesh_register_node_cmd(); } -int ble_mesh_register_node_cb() +int ble_mesh_register_node_cb(void) { ESP_LOGD(TAG, "enter %s\n", __func__); ble_mesh_node_init(); @@ -364,7 +364,7 @@ int ble_mesh_node_enable_bearer(int argc, char **argv) return err; } -int ble_mesh_node_reset() +int ble_mesh_node_reset(void) { esp_err_t err; ESP_LOGD(TAG, "enter %s\n", __func__); @@ -437,7 +437,7 @@ int ble_mesh_node_enter_network_auto(int argc, char **argv) return err; } -void ble_mesh_register_node_cmd() +void ble_mesh_register_node_cmd(void) { const esp_console_cmd_t register_cmd = { .command = "bmreg", diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_server_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_server_cmd.c index e2ae583bf8..6fcb41d4f5 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_server_cmd.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_server_cmd.c @@ -18,7 +18,7 @@ #include "ble_mesh_console_lib.h" #include "ble_mesh_adapter.h" -void ble_mesh_register_server_operation(); +void ble_mesh_register_server_operation(void); typedef struct { struct arg_str *data; @@ -29,7 +29,7 @@ typedef struct { } ble_mesh_publish_message; ble_mesh_publish_message msg_publish; -void ble_mesh_register_server() +void ble_mesh_register_server(void) { ble_mesh_register_server_operation(); } @@ -63,7 +63,7 @@ int ble_mesh_module_publish_message(int argc, char **argv) return err; } -void ble_mesh_register_server_operation() +void ble_mesh_register_server_operation(void) { msg_publish.data = arg_str1("d", NULL, "", "message data"); msg_publish.opcode = arg_int1("o", NULL, "", "operation opcode"); diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c index e6b03ed590..0489388ec1 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c @@ -18,21 +18,21 @@ #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" -void register_ble_address(); +void register_ble_address(void); -void register_bluetooth() +void register_bluetooth(void) { register_ble_address(); } -int bt_mac() +int bt_mac(void) { const uint8_t *mac = esp_bt_dev_get_address(); printf("+BTMAC:"MACSTR"\n", MAC2STR(mac)); return 0; } -void register_ble_address() +void register_ble_address(void) { const esp_console_cmd_t cmd = { .command = "btmac", diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.c index 754b0115fa..eded5787bb 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.c @@ -77,7 +77,7 @@ esp_ble_mesh_comp_t *ble_mesh_get_component(uint16_t model_id) return comp; } -void ble_mesh_node_init() +void ble_mesh_node_init(void) { uint16_t i; @@ -129,7 +129,7 @@ void ble_mesh_create_send_data(char *data, uint16_t byte_num, uint16_t sequence_ } } -void ble_mesh_test_performance_client_model_get() +void ble_mesh_test_performance_client_model_get(void) { uint32_t i, j; uint32_t sum_time = 0; @@ -155,7 +155,7 @@ void ble_mesh_test_performance_client_model_get() xSemaphoreGive(ble_mesh_test_perf_sema); } -void ble_mesh_test_performance_client_model_get_received_percent() +void ble_mesh_test_performance_client_model_get_received_percent(void) { uint32_t i, j; uint32_t max_time = 1400; @@ -283,7 +283,7 @@ int ble_mesh_test_performance_client_model_init(uint16_t node_num, uint32_t test return 0; } -void ble_mesh_test_performance_client_model_destroy() +void ble_mesh_test_performance_client_model_destroy(void) { if (test_perf_statistics.time != NULL) { free(test_perf_statistics.time); diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.h index bdc083a215..305026c1a9 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.h +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.h @@ -106,18 +106,18 @@ extern SemaphoreHandle_t ble_mesh_test_perf_sema; } \ }while(0) \ -void ble_mesh_node_init(); +void ble_mesh_node_init(void); void ble_mesh_set_node_prestore_params(uint16_t netkey_index, uint16_t unicast_addr); esp_ble_mesh_model_t *ble_mesh_get_model(uint16_t model_id); esp_ble_mesh_comp_t *ble_mesh_get_component(uint16_t model_id); void ble_mesh_create_send_data(char *data, uint16_t byte_num, uint16_t sequence_num, uint32_t opcode); -void ble_mesh_test_performance_client_model_get(); -void ble_mesh_test_performance_client_model_get_received_percent(); +void ble_mesh_test_performance_client_model_get(void); +void ble_mesh_test_performance_client_model_get_received_percent(void); void ble_mesh_test_performance_client_model_accumulate_statistics(uint32_t value); int ble_mesh_test_performance_client_model_accumulate_time(uint16_t time, uint8_t *data, uint8_t ack_ttl, uint16_t length); int ble_mesh_test_performance_client_model_init(uint16_t node_num, uint32_t test_num, uint8_t ttl); -void ble_mesh_test_performance_client_model_destroy(); +void ble_mesh_test_performance_client_model_destroy(void); #endif //_BLE_MESH_ADAPTER_H_ \ No newline at end of file diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_decl.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_decl.h index 90e52a61d9..3ba4f496db 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_decl.h +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_decl.h @@ -11,28 +11,28 @@ #include "esp_ble_mesh_defs.h" // Register system functions -void register_system(); +void register_system(void); // Register bluetooth -void register_bluetooth(); +void register_bluetooth(void); // Register mesh node cmd -void ble_mesh_register_mesh_node(); +void ble_mesh_register_mesh_node(void); // Register Test Perf client cmd -void ble_mesh_register_mesh_test_performance_client(); +void ble_mesh_register_mesh_test_performance_client(void); #if (CONFIG_BLE_MESH_CFG_CLI) // Register mesh config client operation cmd -void ble_mesh_register_configuration_client_model(); +void ble_mesh_register_configuration_client_model(void); #endif #if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI) // Register mesh client operation cmd -void ble_mesh_register_gen_onoff_client(); +void ble_mesh_register_gen_onoff_client(void); #endif #if CONFIG_BLE_MESH_PROVISIONER // Regitster mesh provisioner cmd -void ble_mesh_register_mesh_provisioner(); +void ble_mesh_register_mesh_provisioner(void); #endif diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c index d9d4a9e4e9..4618e14b57 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c @@ -39,7 +39,7 @@ #define MOUNT_PATH "/data" #define HISTORY_PATH MOUNT_PATH "/history.txt" -static void initialize_filesystem() +static void initialize_filesystem(void) { static wl_handle_t wl_handle; const esp_vfs_fat_mount_config_t mount_config = { @@ -54,7 +54,7 @@ static void initialize_filesystem() } #endif // CONFIG_STORE_HISTORY -static void initialize_console() +static void initialize_console(void) { /* Disable buffering on stdin and stdout */ setvbuf(stdin, NULL, _IONBF, 0); diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_system.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_system.c index d3dc6c12f9..de76b11ae7 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_system.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_system.c @@ -24,11 +24,11 @@ #define CONFIG_ESPTOOLPY_PORT "Which is choosen by Users for CMake" #endif -static void register_free(); -static void register_restart(); -static void register_make(); +static void register_free(void); +static void register_restart(void); +static void register_make(void); -void register_system() +void register_system(void) { register_free(); register_restart(); @@ -43,7 +43,7 @@ static int restart(int argc, char **argv) esp_restart(); } -static void register_restart() +static void register_restart(void) { const esp_console_cmd_t cmd = { .command = "restart", @@ -62,7 +62,7 @@ static int free_mem(int argc, char **argv) return 0; } -static void register_free() +static void register_free(void) { const esp_console_cmd_t cmd = { .command = "free", @@ -165,7 +165,7 @@ R"(MONITOR return 0; } -static void register_make() +static void register_make(void) { const esp_console_cmd_t cmd = { .command = "make", diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_cfg_client_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_cfg_client_cmd.c index 53a10d38d1..59bae35ced 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_cfg_client_cmd.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_cfg_client_cmd.c @@ -33,11 +33,11 @@ typedef struct { } ble_mesh_client_get_set_state_t; ble_mesh_client_get_set_state_t configuration_client_model_operation; -void ble_mesh_register_configuration_client_model_command(); +void ble_mesh_register_configuration_client_model_command(void); void ble_mesh_configuration_client_model_cb(esp_ble_mesh_cfg_client_cb_event_t event, esp_ble_mesh_cfg_client_cb_param_t *param); -void ble_mesh_register_configuration_client_model() +void ble_mesh_register_configuration_client_model(void) { ble_mesh_register_configuration_client_model_command(); } @@ -362,7 +362,7 @@ int ble_mesh_configuration_client_model_operation(int argc, char **argv) } -void ble_mesh_register_configuration_client_model_command() +void ble_mesh_register_configuration_client_model_command(void) { configuration_client_model_operation.action_type = arg_str1("z", NULL, "", "action type"); configuration_client_model_operation.set_state = arg_str0("x", NULL, "", "set state"); diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_gen_onoff_client_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_gen_onoff_client_cmd.c index 6f34a1b271..f9caa8931b 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_gen_onoff_client_cmd.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_gen_onoff_client_cmd.c @@ -32,11 +32,11 @@ typedef struct { } ble_mesh_gen_onoff_state_t; ble_mesh_gen_onoff_state_t gen_onoff_state; -void ble_mesh_register_gen_onoff_client_command(); +void ble_mesh_register_gen_onoff_client_command(void); void ble_mesh_generic_onoff_client_model_cb(esp_ble_mesh_generic_client_cb_event_t event, esp_ble_mesh_generic_client_cb_param_t *param); -void ble_mesh_register_gen_onoff_client() +void ble_mesh_register_gen_onoff_client(void) { ble_mesh_register_gen_onoff_client_command(); } @@ -152,7 +152,7 @@ int ble_mesh_generic_onoff_client_model(int argc, char **argv) return err; } -void ble_mesh_register_gen_onoff_client_command() +void ble_mesh_register_gen_onoff_client_command(void) { gen_onoff_state.action_type = arg_str1("z", NULL, "", "action type"); gen_onoff_state.opcode = arg_int0("o", NULL, "", "message opcode"); diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_test_perf_client_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_test_perf_client_cmd.c index e46efc8eca..b6b4c898f0 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_test_perf_client_cmd.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_test_perf_client_cmd.c @@ -47,9 +47,9 @@ typedef struct { } ble_mesh_test_perf_client_model_statistics_t; ble_mesh_test_perf_client_model_statistics_t test_perf_client_model_statistics; -void ble_mesh_performance_client_model_command(); +void ble_mesh_performance_client_model_command(void); -void ble_mesh_register_mesh_test_performance_client() +void ble_mesh_register_mesh_test_performance_client(void) { ble_mesh_performance_client_model_command(); } @@ -177,7 +177,7 @@ int ble_mesh_test_performance_client_model_performance(int argc, char **argv) return 0; } -void ble_mesh_performance_client_model_command() +void ble_mesh_performance_client_model_command(void) { test_perf_client_model.action_type = arg_str1("z", NULL, "", "action type"); test_perf_client_model.playload_byte = arg_int0("p", NULL, "", "playload byte"); diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c index 0e0775acaf..dc96f79079 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c @@ -65,18 +65,18 @@ ble_mesh_node_status node_status = { SemaphoreHandle_t ble_mesh_node_sema; -void ble_mesh_register_node_cmd(); +void ble_mesh_register_node_cmd(void); // Register callback function void ble_mesh_prov_cb(esp_ble_mesh_prov_cb_event_t event, esp_ble_mesh_prov_cb_param_t *param); void ble_mesh_model_cb(esp_ble_mesh_model_cb_event_t event, esp_ble_mesh_model_cb_param_t *param); -void ble_mesh_register_mesh_node() +void ble_mesh_register_mesh_node(void) { ble_mesh_register_node_cmd(); } -int ble_mesh_register_node_cb() +int ble_mesh_register_node_cb(void) { ESP_LOGD(TAG, "enter %s\n", __func__); ble_mesh_node_init(); @@ -405,7 +405,7 @@ int ble_mesh_provisioner_enable_bearer(int argc, char **argv) return err; } -void ble_mesh_register_node_cmd() +void ble_mesh_register_node_cmd(void) { const esp_console_cmd_t register_cmd = { .command = "bmreg", diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c index 2df3ec5b7a..4c95d45b28 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c @@ -80,12 +80,12 @@ typedef struct { } ble_mesh_provisioner_add_key_t; ble_mesh_provisioner_add_key_t provisioner_add_key; -void ble_mesh_regist_provisioner_cmd(); +void ble_mesh_regist_provisioner_cmd(void); void ble_mesh_prov_adv_cb(const esp_bd_addr_t addr, const esp_ble_addr_type_t addr_type, const uint8_t adv_type, const uint8_t *dev_uuid, uint16_t oob_info, esp_ble_mesh_prov_bearer_t bearer); -void ble_mesh_register_mesh_provisioner() +void ble_mesh_register_mesh_provisioner(void) { ble_mesh_regist_provisioner_cmd(); } @@ -101,7 +101,7 @@ void ble_mesh_prov_adv_cb(const esp_bd_addr_t addr, const esp_ble_addr_type_t ad ESP_LOGD(TAG, "exit %s\n", __func__); } -int ble_mesh_provisioner_register() +int ble_mesh_provisioner_register(void) { ESP_LOGD(TAG, "enter %s \n", __func__); // esp_ble_mesh_register_unprov_adv_pkt_callback(ble_mesh_prov_adv_cb); @@ -322,7 +322,7 @@ int ble_mesh_provision_bind_local_model(int argc, char **argv) return err; } -void ble_mesh_regist_provisioner_cmd() +void ble_mesh_regist_provisioner_cmd(void) { const esp_console_cmd_t prov_register = { .command = "bmpreg", diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/register_bluetooth.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/register_bluetooth.c index 6b856c30f4..129617e7e2 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/register_bluetooth.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/register_bluetooth.c @@ -18,9 +18,9 @@ #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" -void register_ble_address(); +void register_ble_address(void); -void register_bluetooth() +void register_bluetooth(void) { register_ble_address(); } @@ -32,7 +32,7 @@ int bt_mac(int argc, char** argv) return 0; } -void register_ble_address() +void register_ble_address(void) { const esp_console_cmd_t cmd = { .command = "btmac", diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/components/iperf/cmd_wifi.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/components/iperf/cmd_wifi.c index 8d258dc923..15ebcb21cc 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/components/iperf/cmd_wifi.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/components/iperf/cmd_wifi.c @@ -389,7 +389,7 @@ static int heap_size(int argc, char **argv) return 0; } -void register_wifi() +void register_wifi(void) { sta_args.ssid = arg_str1(NULL, NULL, "", "SSID of AP"); sta_args.password = arg_str0(NULL, NULL, "", "password of AP"); diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/ble_mesh_demo_main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/ble_mesh_demo_main.c index cdb2635add..b68253c382 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/ble_mesh_demo_main.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/ble_mesh_demo_main.c @@ -829,7 +829,7 @@ static esp_err_t bluetooth_init(void) #define WIFI_CONNECTED_BIT BIT0 -static void initialize_console() +static void initialize_console(void) { /* Disable buffering on stdin and stdout */ setvbuf(stdin, NULL, _IONBF, 0); diff --git a/examples/bluetooth/nimble/blemesh/main/app_mesh.c b/examples/bluetooth/nimble/blemesh/main/app_mesh.c index 6910192658..82dde7ec29 100644 --- a/examples/bluetooth/nimble/blemesh/main/app_mesh.c +++ b/examples/bluetooth/nimble/blemesh/main/app_mesh.c @@ -420,7 +420,7 @@ void blemesh_host_task(void *param) nimble_port_run(); } -void app_main() +void app_main(void) { /* Initialize NVS — it is used to store PHY calibration data */ esp_err_t ret = nvs_flash_init(); diff --git a/examples/bluetooth/nimble/bleprph/main/scli.c b/examples/bluetooth/nimble/bleprph/main/scli.c index d5a2fe9558..ec47a104c1 100644 --- a/examples/bluetooth/nimble/bleprph/main/scli.c +++ b/examples/bluetooth/nimble/bleprph/main/scli.c @@ -80,7 +80,7 @@ static esp_console_cmd_t cmds[] = { }, }; -static int ble_register_cli() +static int ble_register_cli(void) { int cmds_num = sizeof(cmds) / sizeof(esp_console_cmd_t); int i; @@ -144,7 +144,7 @@ static void scli_task(void *arg) vTaskDelete(NULL); } -int scli_init() +int scli_init(void) { /* Register CLI "key " to accept input from user during pairing */ ble_register_cli(); diff --git a/examples/build_system/cmake/idf_as_lib/main.c b/examples/build_system/cmake/idf_as_lib/main.c index 59f0aa0f56..9eb73f55ef 100644 --- a/examples/build_system/cmake/idf_as_lib/main.c +++ b/examples/build_system/cmake/idf_as_lib/main.c @@ -12,7 +12,7 @@ #include "esp_system.h" #include "esp_spi_flash.h" -void app_main() +void app_main(void) { printf("Hello world!\n"); diff --git a/examples/build_system/cmake/idf_as_lib/stubs/esp32/cpu_start.c b/examples/build_system/cmake/idf_as_lib/stubs/esp32/cpu_start.c index 44eedcb421..4aa606c8a7 100644 --- a/examples/build_system/cmake/idf_as_lib/stubs/esp32/cpu_start.c +++ b/examples/build_system/cmake/idf_as_lib/stubs/esp32/cpu_start.c @@ -1,10 +1,10 @@ #include #include -extern void app_main(); +extern void app_main(void); jmp_buf buf; -int main() +int main(void) { setjmp(buf); app_main(); diff --git a/examples/build_system/cmake/idf_as_lib/stubs/esp32/flash_ops.c b/examples/build_system/cmake/idf_as_lib/stubs/esp32/flash_ops.c index 175e84b6e2..72d5b6e4b4 100644 --- a/examples/build_system/cmake/idf_as_lib/stubs/esp32/flash_ops.c +++ b/examples/build_system/cmake/idf_as_lib/stubs/esp32/flash_ops.c @@ -1,6 +1,6 @@ #include "esp_spi_flash.h" -int spi_flash_get_chip_size() +int spi_flash_get_chip_size(void) { return (1024 * 1024 * 1024); } \ No newline at end of file diff --git a/examples/build_system/cmake/idf_as_lib/stubs/spi_flash/esp_spi_flash.h b/examples/build_system/cmake/idf_as_lib/stubs/spi_flash/esp_spi_flash.h index 544f3611bc..4ca6ae9402 100644 --- a/examples/build_system/cmake/idf_as_lib/stubs/spi_flash/esp_spi_flash.h +++ b/examples/build_system/cmake/idf_as_lib/stubs/spi_flash/esp_spi_flash.h @@ -2,4 +2,4 @@ #include -int spi_flash_get_chip_size(); \ No newline at end of file +int spi_flash_get_chip_size(void); \ No newline at end of file diff --git a/examples/common_components/protocol_examples_common/connect.c b/examples/common_components/protocol_examples_common/connect.c index 68895905a4..8ee8aea9d4 100644 --- a/examples/common_components/protocol_examples_common/connect.c +++ b/examples/common_components/protocol_examples_common/connect.c @@ -41,10 +41,10 @@ static ip6_addr_t s_ipv6_addr; static const char *TAG = "example_connect"; /* set up connection, Wi-Fi or Ethernet */ -static void start(); +static void start(void); /* tear down connection, release resources */ -static void stop(); +static void stop(void); static void on_got_ip(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) @@ -66,7 +66,7 @@ static void on_got_ipv6(void *arg, esp_event_base_t event_base, #endif // CONFIG_EXAMPLE_CONNECT_IPV6 -esp_err_t example_connect() +esp_err_t example_connect(void) { if (s_connect_event_group != NULL) { return ESP_ERR_INVALID_STATE; @@ -82,7 +82,7 @@ esp_err_t example_connect() return ESP_OK; } -esp_err_t example_disconnect() +esp_err_t example_disconnect(void) { if (s_connect_event_group == NULL) { return ESP_ERR_INVALID_STATE; @@ -114,7 +114,7 @@ static void on_wifi_connect(void *arg, esp_event_base_t event_base, #endif // CONFIG_EXAMPLE_CONNECT_IPV6 -static void start() +static void start(void) { wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); @@ -141,7 +141,7 @@ static void start() s_connection_name = CONFIG_EXAMPLE_WIFI_SSID; } -static void stop() +static void stop(void) { ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &on_wifi_disconnect)); ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &on_got_ip)); @@ -178,7 +178,7 @@ static esp_eth_handle_t s_eth_handle = NULL; static esp_eth_mac_t *s_mac = NULL; static esp_eth_phy_t *s_phy = NULL; -static void start() +static void start(void) { ESP_ERROR_CHECK(tcpip_adapter_set_default_eth_handlers()); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &on_got_ip, NULL)); @@ -229,7 +229,7 @@ static void start() s_connection_name = "Ethernet"; } -static void stop() +static void stop(void) { ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, &on_got_ip)); #ifdef CONFIG_EXAMPLE_CONNECT_IPV6 diff --git a/examples/common_components/protocol_examples_common/include/protocol_examples_common.h b/examples/common_components/protocol_examples_common/include/protocol_examples_common.h index e250db14d5..d4f6e1fbbb 100644 --- a/examples/common_components/protocol_examples_common/include/protocol_examples_common.h +++ b/examples/common_components/protocol_examples_common/include/protocol_examples_common.h @@ -39,12 +39,12 @@ extern "C" { * * @return ESP_OK on successful connection */ -esp_err_t example_connect(); +esp_err_t example_connect(void); /** * Counterpart to example_connect, de-initializes Wi-Fi or Ethernet */ -esp_err_t example_disconnect(); +esp_err_t example_disconnect(void); /** * @brief Configure stdin and stdout to use blocking I/O @@ -52,7 +52,7 @@ esp_err_t example_disconnect(); * This helper function is used in ASIO examples. It wraps installing the * UART driver and configuring VFS layer to use UART driver for console I/O. */ -esp_err_t example_configure_stdin_stdout(); +esp_err_t example_configure_stdin_stdout(void); #ifdef __cplusplus } diff --git a/examples/common_components/protocol_examples_common/stdin_out.c b/examples/common_components/protocol_examples_common/stdin_out.c index cb2220db4b..10cc2167fe 100644 --- a/examples/common_components/protocol_examples_common/stdin_out.c +++ b/examples/common_components/protocol_examples_common/stdin_out.c @@ -13,7 +13,7 @@ #include "driver/uart.h" #include "sdkconfig.h" -esp_err_t example_configure_stdin_stdout() +esp_err_t example_configure_stdin_stdout(void) { // Initialize VFS & UART so we can use std::cout/cin setvbuf(stdin, NULL, _IONBF, 0); diff --git a/examples/ethernet/basic/main/ethernet_example_main.c b/examples/ethernet/basic/main/ethernet_example_main.c index ed794a32b3..a58bab806f 100644 --- a/examples/ethernet/basic/main/ethernet_example_main.c +++ b/examples/ethernet/basic/main/ethernet_example_main.c @@ -62,7 +62,7 @@ static void got_ip_event_handler(void *arg, esp_event_base_t event_base, ESP_LOGI(TAG, "~~~~~~~~~~~"); } -void app_main() +void app_main(void) { tcpip_adapter_init(); diff --git a/examples/ethernet/eth2ap/main/ethernet_example_main.c b/examples/ethernet/eth2ap/main/ethernet_example_main.c index 4796cd9a13..3b540fad05 100644 --- a/examples/ethernet/eth2ap/main/ethernet_example_main.c +++ b/examples/ethernet/eth2ap/main/ethernet_example_main.c @@ -226,7 +226,7 @@ static esp_err_t initialize_flow_control(void) return ESP_OK; } -void app_main() +void app_main(void) { esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { diff --git a/examples/ethernet/iperf/main/cmd_ethernet.c b/examples/ethernet/iperf/main/cmd_ethernet.c index 832d049b04..d148b5a285 100644 --- a/examples/ethernet/iperf/main/cmd_ethernet.c +++ b/examples/ethernet/iperf/main/cmd_ethernet.c @@ -173,7 +173,7 @@ static void event_handler(void *arg, esp_event_base_t event_base, } } -void register_ethernet() +void register_ethernet(void) { eth_event_group = xEventGroupCreate(); tcpip_adapter_init(); diff --git a/examples/ethernet/iperf/main/cmd_ethernet.h b/examples/ethernet/iperf/main/cmd_ethernet.h index bd619c7ffe..e99615151e 100644 --- a/examples/ethernet/iperf/main/cmd_ethernet.h +++ b/examples/ethernet/iperf/main/cmd_ethernet.h @@ -13,7 +13,7 @@ extern "C" { #endif // Register Ethernet functions -void register_ethernet(); +void register_ethernet(void); #ifdef __cplusplus } diff --git a/examples/ethernet/iperf/main/ethernet_example_main.c b/examples/ethernet/iperf/main/ethernet_example_main.c index 1f0718fd03..0d881fa5d5 100644 --- a/examples/ethernet/iperf/main/ethernet_example_main.c +++ b/examples/ethernet/iperf/main/ethernet_example_main.c @@ -29,7 +29,7 @@ static const char *TAG = "eth_example"; #define MOUNT_PATH "/data" #define HISTORY_PATH MOUNT_PATH "/history.txt" -static void initialize_filesystem() +static void initialize_filesystem(void) { static wl_handle_t wl_handle; const esp_vfs_fat_mount_config_t mount_config = { @@ -44,7 +44,7 @@ static void initialize_filesystem() } #endif // CONFIG_EXAMPLE_STORE_HISTORY -static void initialize_nvs() +static void initialize_nvs(void) { esp_err_t err = nvs_flash_init(); if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { @@ -54,7 +54,7 @@ static void initialize_nvs() ESP_ERROR_CHECK(err); } -static void initialize_console() +static void initialize_console(void) { /* Disable buffering on stdin */ setvbuf(stdin, NULL, _IONBF, 0); @@ -109,7 +109,7 @@ static void initialize_console() #endif } -void app_main() +void app_main(void) { initialize_nvs(); diff --git a/examples/get-started/blink/main/blink.c b/examples/get-started/blink/main/blink.c index 9c58645f9d..610ac85145 100644 --- a/examples/get-started/blink/main/blink.c +++ b/examples/get-started/blink/main/blink.c @@ -17,7 +17,7 @@ */ #define BLINK_GPIO CONFIG_BLINK_GPIO -void app_main() +void app_main(void) { /* Configure the IOMUX register for pad BLINK_GPIO (some pads are muxed to GPIO on reset already, but some default to other diff --git a/examples/get-started/hello_world/main/hello_world_main.c b/examples/get-started/hello_world/main/hello_world_main.c index c17eb1b201..7bb54d2fde 100644 --- a/examples/get-started/hello_world/main/hello_world_main.c +++ b/examples/get-started/hello_world/main/hello_world_main.c @@ -13,7 +13,7 @@ #include "esp_spi_flash.h" -void app_main() +void app_main(void) { printf("Hello world!\n"); diff --git a/examples/peripherals/adc/main/adc1_example_main.c b/examples/peripherals/adc/main/adc1_example_main.c index 00de0ab8bf..d0f20a6e60 100644 --- a/examples/peripherals/adc/main/adc1_example_main.c +++ b/examples/peripherals/adc/main/adc1_example_main.c @@ -22,7 +22,7 @@ static const adc_channel_t channel = ADC_CHANNEL_6; //GPIO34 if ADC1, GPIO14 static const adc_atten_t atten = ADC_ATTEN_DB_0; static const adc_unit_t unit = ADC_UNIT_1; -static void check_efuse() +static void check_efuse(void) { //Check TP is burned into eFuse if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) { @@ -50,7 +50,7 @@ static void print_char_val_type(esp_adc_cal_value_t val_type) } } -void app_main() +void app_main(void) { //Check if Two Point or Vref are burned into eFuse check_efuse(); diff --git a/examples/peripherals/can/can_alert_and_recovery/main/can_alert_and_recovery_example_main.c b/examples/peripherals/can/can_alert_and_recovery/main/can_alert_and_recovery_example_main.c index fab6d4bb0d..ea4ac360e8 100644 --- a/examples/peripherals/can/can_alert_and_recovery/main/can_alert_and_recovery_example_main.c +++ b/examples/peripherals/can/can_alert_and_recovery/main/can_alert_and_recovery_example_main.c @@ -127,7 +127,7 @@ static void ctrl_task(void *arg) vTaskDelete(NULL); } -void app_main() +void app_main(void) { tx_task_sem = xSemaphoreCreateBinary(); ctrl_task_sem = xSemaphoreCreateBinary(); diff --git a/examples/peripherals/can/can_network/can_network_listen_only/main/can_network_example_listen_only_main.c b/examples/peripherals/can/can_network/can_network_listen_only/main/can_network_example_listen_only_main.c index 5309bbd0b1..2bfc8281ab 100644 --- a/examples/peripherals/can/can_network/can_network_listen_only/main/can_network_example_listen_only_main.c +++ b/examples/peripherals/can/can_network/can_network_listen_only/main/can_network_example_listen_only_main.c @@ -97,7 +97,7 @@ static void can_receive_task(void *arg) vTaskDelete(NULL); } -void app_main() +void app_main(void) { rx_sem = xSemaphoreCreateBinary(); xTaskCreatePinnedToCore(can_receive_task, "CAN_rx", 4096, NULL, RX_TASK_PRIO, NULL, tskNO_AFFINITY); diff --git a/examples/peripherals/can/can_network/can_network_master/main/can_network_example_master_main.c b/examples/peripherals/can/can_network/can_network_master/main/can_network_example_master_main.c index 7372e7f77d..f744072d83 100644 --- a/examples/peripherals/can/can_network/can_network_master/main/can_network_example_master_main.c +++ b/examples/peripherals/can/can_network/can_network_master/main/can_network_example_master_main.c @@ -205,7 +205,7 @@ static void can_control_task(void *arg) vTaskDelete(NULL); } -void app_main() +void app_main(void) { //Create tasks, queues, and semaphores rx_task_queue = xQueueCreate(1, sizeof(rx_task_action_t)); diff --git a/examples/peripherals/can/can_network/can_network_slave/main/can_network_example_slave_main.c b/examples/peripherals/can/can_network/can_network_slave/main/can_network_example_slave_main.c index 7c4a793bdd..17ad07b8b4 100644 --- a/examples/peripherals/can/can_network/can_network_slave/main/can_network_example_slave_main.c +++ b/examples/peripherals/can/can_network/can_network_slave/main/can_network_example_slave_main.c @@ -225,7 +225,7 @@ static void can_control_task(void *arg) vTaskDelete(NULL); } -void app_main() +void app_main(void) { //Add short delay to allow master it to initialize first for (int i = 3; i > 0; i--) { diff --git a/examples/peripherals/can/can_self_test/main/can_self_test_example_main.c b/examples/peripherals/can/can_self_test/main/can_self_test_example_main.c index bb17722cc6..e3a12522c3 100644 --- a/examples/peripherals/can/can_self_test/main/can_self_test_example_main.c +++ b/examples/peripherals/can/can_self_test/main/can_self_test_example_main.c @@ -107,7 +107,7 @@ static void can_control_task(void *arg) vTaskDelete(NULL); } -void app_main() +void app_main(void) { //Create tasks and synchronization primitives tx_sem = xSemaphoreCreateBinary(); diff --git a/examples/peripherals/gpio/main/gpio_example_main.c b/examples/peripherals/gpio/main/gpio_example_main.c index b6e71339ec..9609daf799 100644 --- a/examples/peripherals/gpio/main/gpio_example_main.c +++ b/examples/peripherals/gpio/main/gpio_example_main.c @@ -57,7 +57,7 @@ static void gpio_task_example(void* arg) } } -void app_main() +void app_main(void) { gpio_config_t io_conf; //disable interrupt diff --git a/examples/peripherals/i2c/i2c_self_test/main/i2c_example_main.c b/examples/peripherals/i2c/i2c_self_test/main/i2c_example_main.c index 9b108a9aa6..7fe6e0ffc4 100644 --- a/examples/peripherals/i2c/i2c_self_test/main/i2c_example_main.c +++ b/examples/peripherals/i2c/i2c_self_test/main/i2c_example_main.c @@ -141,7 +141,7 @@ static esp_err_t i2c_master_sensor_test(i2c_port_t i2c_num, uint8_t *data_h, uin /** * @brief i2c master initialization */ -static esp_err_t i2c_master_init() +static esp_err_t i2c_master_init(void) { int i2c_master_port = I2C_MASTER_NUM; i2c_config_t conf; @@ -160,7 +160,7 @@ static esp_err_t i2c_master_init() /** * @brief i2c slave initialization */ -static esp_err_t i2c_slave_init() +static esp_err_t i2c_slave_init(void) { int i2c_slave_port = I2C_SLAVE_NUM; i2c_config_t conf_slave; @@ -281,7 +281,7 @@ static void i2c_test_task(void *arg) vTaskDelete(NULL); } -void app_main() +void app_main(void) { print_mux = xSemaphoreCreateMutex(); ESP_ERROR_CHECK(i2c_slave_init()); diff --git a/examples/peripherals/i2c/i2c_tools/main/cmd_i2ctools.c b/examples/peripherals/i2c/i2c_tools/main/cmd_i2ctools.c index b9c87369c8..1030f4387e 100644 --- a/examples/peripherals/i2c/i2c_tools/main/cmd_i2ctools.c +++ b/examples/peripherals/i2c/i2c_tools/main/cmd_i2ctools.c @@ -48,7 +48,7 @@ static esp_err_t i2c_get_port(int port, i2c_port_t *i2c_port) return ESP_OK; } -static esp_err_t i2c_master_driver_initialize() +static esp_err_t i2c_master_driver_initialize(void) { i2c_config_t conf = { .mode = I2C_MODE_MASTER, diff --git a/examples/peripherals/i2c/i2c_tools/main/i2ctools_example_main.c b/examples/peripherals/i2c/i2c_tools/main/i2ctools_example_main.c index ea79a854db..0cffbafd68 100644 --- a/examples/peripherals/i2c/i2c_tools/main/i2ctools_example_main.c +++ b/examples/peripherals/i2c/i2c_tools/main/i2ctools_example_main.c @@ -29,7 +29,7 @@ static const char *TAG = "i2c-tools"; #define MOUNT_PATH "/data" #define HISTORY_PATH MOUNT_PATH "/history.txt" -static void initialize_filesystem() +static void initialize_filesystem(void) { static wl_handle_t wl_handle; const esp_vfs_fat_mount_config_t mount_config = { @@ -44,7 +44,7 @@ static void initialize_filesystem() } #endif // CONFIG_EXAMPLE_STORE_HISTORY -static void initialize_nvs() +static void initialize_nvs(void) { esp_err_t err = nvs_flash_init(); if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { @@ -54,7 +54,7 @@ static void initialize_nvs() ESP_ERROR_CHECK(err); } -static void initialize_console() +static void initialize_console(void) { /* Disable buffering on stdin */ setvbuf(stdin, NULL, _IONBF, 0); @@ -109,7 +109,7 @@ static void initialize_console() #endif } -void app_main() +void app_main(void) { initialize_nvs(); diff --git a/examples/peripherals/i2s/main/i2s_example_main.c b/examples/peripherals/i2s/main/i2s_example_main.c index 36bbabc18b..04c90261df 100644 --- a/examples/peripherals/i2s/main/i2s_example_main.c +++ b/examples/peripherals/i2s/main/i2s_example_main.c @@ -77,7 +77,7 @@ static void setup_triangle_sine_waves(int bits) free(samples_data); } -void app_main() +void app_main(void) { //for 36Khz sample rates, we create 100Hz sine wave, every cycle need 36000/100 = 360 samples (4-bytes or 8-bytes each sample) //depend on bits_per_sample diff --git a/examples/peripherals/i2s_adc_dac/main/app_main.c b/examples/peripherals/i2s_adc_dac/main/app_main.c index 9d3018b4bf..44bdea4efa 100644 --- a/examples/peripherals/i2s_adc_dac/main/app_main.c +++ b/examples/peripherals/i2s_adc_dac/main/app_main.c @@ -56,7 +56,7 @@ static const char* TAG = "ad/da"; /** * @brief I2S ADC/DAC mode init. */ -void example_i2s_init() +void example_i2s_init(void) { int i2s_num = EXAMPLE_I2S_NUM; i2s_config_t i2s_config = { @@ -81,7 +81,7 @@ void example_i2s_init() /* * @brief erase flash for recording */ -void example_erase_flash() +void example_erase_flash(void) { #if RECORD_IN_FLASH_EN printf("Erasing flash \n"); @@ -118,7 +118,7 @@ void example_disp_buf(uint8_t* buf, int length) /** * @brief Reset i2s clock and mode */ -void example_reset_play_mode() +void example_reset_play_mode(void) { i2s_set_clk(EXAMPLE_I2S_NUM, EXAMPLE_I2S_SAMPLE_RATE, EXAMPLE_I2S_SAMPLE_BITS, EXAMPLE_I2S_CHANNEL_NUM); } @@ -126,7 +126,7 @@ void example_reset_play_mode() /** * @brief Set i2s clock for example audio file */ -void example_set_file_play_mode() +void example_set_file_play_mode(void) { i2s_set_clk(EXAMPLE_I2S_NUM, 16000, EXAMPLE_I2S_SAMPLE_BITS, 1); } @@ -280,7 +280,7 @@ void adc_read_task(void* arg) } } -esp_err_t app_main() +esp_err_t app_main(void) { example_i2s_init(); esp_log_level_set("I2S", ESP_LOG_INFO); diff --git a/examples/peripherals/ledc/main/ledc_example_main.c b/examples/peripherals/ledc/main/ledc_example_main.c index d61e73fba6..3a0cd5e97b 100644 --- a/examples/peripherals/ledc/main/ledc_example_main.c +++ b/examples/peripherals/ledc/main/ledc_example_main.c @@ -51,7 +51,7 @@ #define LEDC_TEST_DUTY (4000) #define LEDC_TEST_FADE_TIME (3000) -void app_main() +void app_main(void) { int ch; diff --git a/examples/peripherals/mcpwm/mcpwm_basic_config/main/mcpwm_basic_config_example.c b/examples/peripherals/mcpwm/mcpwm_basic_config/main/mcpwm_basic_config_example.c index 7853c14905..ef750de1ac 100644 --- a/examples/peripherals/mcpwm/mcpwm_basic_config/main/mcpwm_basic_config_example.c +++ b/examples/peripherals/mcpwm/mcpwm_basic_config/main/mcpwm_basic_config_example.c @@ -62,7 +62,7 @@ xQueueHandle cap_queue; static mcpwm_dev_t *MCPWM[2] = {&MCPWM0, &MCPWM1}; #endif -static void mcpwm_example_gpio_initialize() +static void mcpwm_example_gpio_initialize(void) { printf("initializing mcpwm gpio...\n"); #if MCPWM_GPIO_INIT @@ -167,7 +167,7 @@ static void disp_captured_signal(void *arg) /** * @brief this is ISR handler function, here we check for interrupt that triggers rising edge on CAP0 signal and according take action */ -static void IRAM_ATTR isr_handler() +static void IRAM_ATTR isr_handler(void) { uint32_t mcpwm_intr_status; capture evt; @@ -282,7 +282,7 @@ static void mcpwm_example_config(void *arg) vTaskDelete(NULL); } -void app_main() +void app_main(void) { printf("Testing MCPWM...\n"); cap_queue = xQueueCreate(1, sizeof(capture)); //comment if you don't want to use capture module diff --git a/examples/peripherals/mcpwm/mcpwm_bldc_control/main/mcpwm_bldc_control_hall_sensor_example.c b/examples/peripherals/mcpwm/mcpwm_bldc_control/main/mcpwm_bldc_control_hall_sensor_example.c index ecef139cc6..c8bfe00010 100644 --- a/examples/peripherals/mcpwm/mcpwm_bldc_control/main/mcpwm_bldc_control_hall_sensor_example.c +++ b/examples/peripherals/mcpwm/mcpwm_bldc_control/main/mcpwm_bldc_control_hall_sensor_example.c @@ -58,7 +58,7 @@ xQueueHandle cap_queue; static mcpwm_dev_t *MCPWM[2] = {&MCPWM0, &MCPWM1}; -static void mcpwm_example_gpio_initialize() +static void mcpwm_example_gpio_initialize(void) { printf("initializing mcpwm bldc control gpio...\n"); #if MCPWM_GPIO_INIT @@ -162,7 +162,7 @@ static void disp_captured_signal(void *arg) /** * @brief this is ISR handler function, here we check for interrupt that triggers rising edge on CAP0 signal and according take action */ -static void IRAM_ATTR isr_handler() +static void IRAM_ATTR isr_handler(void) { uint32_t mcpwm_intr_status; capture evt; @@ -307,7 +307,7 @@ static void mcpwm_example_bldc_control(void *arg) } } -void app_main() +void app_main(void) { printf("Testing MCPWM BLDC Control...\n"); #if CHANGE_DUTY_CONTINUOUSLY diff --git a/examples/peripherals/mcpwm/mcpwm_brushed_dc_control/main/mcpwm_brushed_dc_control_example.c b/examples/peripherals/mcpwm/mcpwm_brushed_dc_control/main/mcpwm_brushed_dc_control_example.c index 2c721e77a2..ee35fcc60a 100644 --- a/examples/peripherals/mcpwm/mcpwm_brushed_dc_control/main/mcpwm_brushed_dc_control_example.c +++ b/examples/peripherals/mcpwm/mcpwm_brushed_dc_control/main/mcpwm_brushed_dc_control_example.c @@ -25,7 +25,7 @@ #define GPIO_PWM0A_OUT 15 //Set GPIO 15 as PWM0A #define GPIO_PWM0B_OUT 16 //Set GPIO 16 as PWM0B -static void mcpwm_example_gpio_initialize() +static void mcpwm_example_gpio_initialize(void) { printf("initializing mcpwm gpio...\n"); mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_PWM0A_OUT); @@ -88,7 +88,7 @@ static void mcpwm_example_brushed_motor_control(void *arg) } } -void app_main() +void app_main(void) { printf("Testing brushed motor...\n"); xTaskCreate(mcpwm_example_brushed_motor_control, "mcpwm_examlpe_brushed_motor_control", 4096, NULL, 5, NULL); diff --git a/examples/peripherals/mcpwm/mcpwm_servo_control/main/mcpwm_servo_control_example.c b/examples/peripherals/mcpwm/mcpwm_servo_control/main/mcpwm_servo_control_example.c index 2a944e5daf..88841f252f 100644 --- a/examples/peripherals/mcpwm/mcpwm_servo_control/main/mcpwm_servo_control_example.c +++ b/examples/peripherals/mcpwm/mcpwm_servo_control/main/mcpwm_servo_control_example.c @@ -20,7 +20,7 @@ #define SERVO_MAX_PULSEWIDTH 2000 //Maximum pulse width in microsecond #define SERVO_MAX_DEGREE 90 //Maximum angle in degree upto which servo can rotate -static void mcpwm_example_gpio_initialize() +static void mcpwm_example_gpio_initialize(void) { printf("initializing mcpwm servo control gpio......\n"); mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, 18); //Set GPIO 18 as PWM0A, to which servo is connected @@ -70,7 +70,7 @@ void mcpwm_example_servo_control(void *arg) } } -void app_main() +void app_main(void) { printf("Testing servo motor.......\n"); xTaskCreate(mcpwm_example_servo_control, "mcpwm_example_servo_control", 4096, NULL, 5, NULL); diff --git a/examples/peripherals/pcnt/main/pcnt_example_main.c b/examples/peripherals/pcnt/main/pcnt_example_main.c index f734501fcc..89a3703634 100644 --- a/examples/peripherals/pcnt/main/pcnt_example_main.c +++ b/examples/peripherals/pcnt/main/pcnt_example_main.c @@ -167,7 +167,7 @@ static void pcnt_example_init(void) pcnt_counter_resume(PCNT_TEST_UNIT); } -void app_main() +void app_main(void) { /* Initialize LEDC to generate sample pulse signal */ ledc_init(); diff --git a/examples/peripherals/rmt_nec_tx_rx/main/infrared_nec_main.c b/examples/peripherals/rmt_nec_tx_rx/main/infrared_nec_main.c index cebffbcaeb..1dc28e5acc 100644 --- a/examples/peripherals/rmt_nec_tx_rx/main/infrared_nec_main.c +++ b/examples/peripherals/rmt_nec_tx_rx/main/infrared_nec_main.c @@ -235,7 +235,7 @@ static int nec_build_items(int channel, rmt_item32_t* item, int item_num, uint16 /* * @brief RMT transmitter initialization */ -static void nec_tx_init() +static void nec_tx_init(void) { rmt_config_t rmt_tx; rmt_tx.channel = RMT_TX_CHANNEL; @@ -257,7 +257,7 @@ static void nec_tx_init() /* * @brief RMT receiver initialization */ -static void nec_rx_init() +static void nec_rx_init(void) { rmt_config_t rmt_rx; rmt_rx.channel = RMT_RX_CHANNEL; @@ -276,7 +276,7 @@ static void nec_rx_init() * @brief RMT receiver demo, this task will print each received NEC data. * */ -static void rmt_example_nec_rx_task() +static void rmt_example_nec_rx_task(void) { int channel = RMT_RX_CHANNEL; nec_rx_init(); @@ -317,7 +317,7 @@ static void rmt_example_nec_rx_task() * @brief RMT transmitter demo, this task will periodically send NEC data. (100 * 32 bits each time.) * */ -static void rmt_example_nec_tx_task() +static void rmt_example_nec_tx_task(void) { vTaskDelay(10); nec_tx_init(); @@ -355,7 +355,7 @@ static void rmt_example_nec_tx_task() vTaskDelete(NULL); } -void app_main() +void app_main(void) { xTaskCreate(rmt_example_nec_rx_task, "rmt_nec_rx_task", 2048, NULL, 10, NULL); xTaskCreate(rmt_example_nec_tx_task, "rmt_nec_tx_task", 2048, NULL, 10, NULL); diff --git a/examples/peripherals/rmt_tx/main/rmt_tx_main.c b/examples/peripherals/rmt_tx/main/rmt_tx_main.c index ad6e4f6f65..c366722067 100644 --- a/examples/peripherals/rmt_tx/main/rmt_tx_main.c +++ b/examples/peripherals/rmt_tx/main/rmt_tx_main.c @@ -84,7 +84,7 @@ static void IRAM_ATTR u8_to_rmt(const void* src, rmt_item32_t* dest, size_t src_ /* * Initialize the RMT Tx channel */ -static void rmt_tx_int() +static void rmt_tx_int(void) { rmt_config_t config; config.rmt_mode = RMT_MODE_TX; diff --git a/examples/peripherals/sdio/host/main/app_main.c b/examples/peripherals/sdio/host/main/app_main.c index b0b62d15df..b12f186776 100644 --- a/examples/peripherals/sdio/host/main/app_main.c +++ b/examples/peripherals/sdio/host/main/app_main.c @@ -123,7 +123,7 @@ esp_err_t slave_reset(esp_slave_context_t *context) } #ifdef CONFIG_EXAMPLE_SDIO_OVER_SPI -static void gpio_d2_set_high() +static void gpio_d2_set_high(void) { gpio_config_t d2_config = { .pin_bit_mask = BIT(SDIO_SLAVE_SLOT1_IOMUX_PIN_NUM_D2), @@ -257,7 +257,7 @@ esp_err_t slave_init(esp_slave_context_t *context) } -void slave_power_on() +void slave_power_on(void) { #ifdef SLAVE_PWR_GPIO int level_active; @@ -410,7 +410,7 @@ void job_getint(esp_slave_context_t *context) slave_inform_job(context, JOB_SEND_INT); } -void app_main() +void app_main(void) { esp_slave_context_t context; esp_err_t err; diff --git a/examples/peripherals/sdio/slave/main/app_main.c b/examples/peripherals/sdio/slave/main/app_main.c index dd7a73a61b..147f4aba49 100644 --- a/examples/peripherals/sdio/slave/main/app_main.c +++ b/examples/peripherals/sdio/slave/main/app_main.c @@ -85,7 +85,7 @@ static const char job_desc[][32] = { //reset counters of the slave hardware, and clean the receive buffer (normally they should be sent back to the host) -static esp_err_t slave_reset() +static esp_err_t slave_reset(void) { esp_err_t ret; sdio_slave_stop(); @@ -106,7 +106,7 @@ static esp_err_t slave_reset() } //sent interrupts to the host in turns -static esp_err_t task_hostint() +static esp_err_t task_hostint(void) { for(int i = 0; i < 8; i++) { ESP_LOGV(TAG, "send intr: %d", i); @@ -120,7 +120,7 @@ static esp_err_t task_hostint() //read the value in a specified register set by the host, and set other register according to this. //the host will read these registers later -static esp_err_t task_write_reg() +static esp_err_t task_write_reg(void) { //the host write REG1, the slave should write its registers according to value of REG1 uint8_t read = sdio_slave_read_reg(1); @@ -157,7 +157,7 @@ static void event_cb(uint8_t pos) DMA_ATTR uint8_t buffer[BUFFER_NUM][BUFFER_SIZE] = {}; //Main application -void app_main() +void app_main(void) { esp_err_t ret; diff --git a/examples/peripherals/sigmadelta/main/sigmadelta_example_main.c b/examples/peripherals/sigmadelta/main/sigmadelta_example_main.c index 38bf2c0991..4dee4ad17d 100644 --- a/examples/peripherals/sigmadelta/main/sigmadelta_example_main.c +++ b/examples/peripherals/sigmadelta/main/sigmadelta_example_main.c @@ -35,7 +35,7 @@ static void sigmadelta_example_init(void) * Perform the sigma-delta modulation test * by changing the duty of the output signal. */ -void app_main() +void app_main(void) { sigmadelta_example_init(); diff --git a/examples/peripherals/spi_master/main/pretty_effect.c b/examples/peripherals/spi_master/main/pretty_effect.c index 9cd58c0667..56903a38c7 100644 --- a/examples/peripherals/spi_master/main/pretty_effect.c +++ b/examples/peripherals/spi_master/main/pretty_effect.c @@ -55,7 +55,7 @@ void pretty_effect_calc_lines(uint16_t *dest, int line, int frame, int linect) } -esp_err_t pretty_effect_init() +esp_err_t pretty_effect_init(void) { return decode_image(&pixels); } diff --git a/examples/peripherals/spi_master/main/pretty_effect.h b/examples/peripherals/spi_master/main/pretty_effect.h index 7f54a32456..00f000c048 100644 --- a/examples/peripherals/spi_master/main/pretty_effect.h +++ b/examples/peripherals/spi_master/main/pretty_effect.h @@ -19,4 +19,4 @@ void pretty_effect_calc_lines(uint16_t *dest, int line, int frame, int linect); * * @return ESP_OK on success, an error from the jpeg decoder otherwise. */ -esp_err_t pretty_effect_init(); +esp_err_t pretty_effect_init(void); diff --git a/examples/peripherals/spi_master/main/spi_master_example_main.c b/examples/peripherals/spi_master/main/spi_master_example_main.c index 3d4d304ea7..0e4cea3457 100644 --- a/examples/peripherals/spi_master/main/spi_master_example_main.c +++ b/examples/peripherals/spi_master/main/spi_master_example_main.c @@ -386,7 +386,7 @@ static void display_pretty_colors(spi_device_handle_t spi) } } -void app_main() +void app_main(void) { esp_err_t ret; spi_device_handle_t spi; diff --git a/examples/peripherals/spi_slave/receiver/main/app_main.c b/examples/peripherals/spi_slave/receiver/main/app_main.c index 1a51c653a4..3071e77d29 100644 --- a/examples/peripherals/spi_slave/receiver/main/app_main.c +++ b/examples/peripherals/spi_slave/receiver/main/app_main.c @@ -69,7 +69,7 @@ void my_post_trans_cb(spi_slave_transaction_t *trans) { } //Main application -void app_main() +void app_main(void) { int n=0; esp_err_t ret; diff --git a/examples/peripherals/spi_slave/sender/main/app_main.c b/examples/peripherals/spi_slave/sender/main/app_main.c index af7dc22752..66323dad55 100644 --- a/examples/peripherals/spi_slave/sender/main/app_main.c +++ b/examples/peripherals/spi_slave/sender/main/app_main.c @@ -81,7 +81,7 @@ static void IRAM_ATTR gpio_handshake_isr_handler(void* arg) } //Main application -void app_main() +void app_main(void) { esp_err_t ret; spi_device_handle_t handle; diff --git a/examples/peripherals/timer_group/main/timer_group_example_main.c b/examples/peripherals/timer_group/main/timer_group_example_main.c index 572e35e61d..403f9c0a0f 100644 --- a/examples/peripherals/timer_group/main/timer_group_example_main.c +++ b/examples/peripherals/timer_group/main/timer_group_example_main.c @@ -163,7 +163,7 @@ static void timer_example_evt_task(void *arg) /* * In this example, we will test hardware timer0 and timer1 of timer group0. */ -void app_main() +void app_main(void) { timer_queue = xQueueCreate(10, sizeof(timer_event_t)); example_tg0_timer_init(TIMER_0, TEST_WITHOUT_RELOAD, TIMER_INTERVAL0_SEC); diff --git a/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c b/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c index 1ed6bcabd3..7b3f244ce5 100644 --- a/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c +++ b/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c @@ -137,7 +137,7 @@ static void tp_example_rtc_intr(void * arg) /* * Before reading touch pad, we need to initialize the RTC IO. */ -static void tp_example_touch_pad_init() +static void tp_example_touch_pad_init(void) { for (int i = 0;i< TOUCH_PAD_MAX;i++) { //init RTC IO and mode for touch pad. @@ -145,7 +145,7 @@ static void tp_example_touch_pad_init() } } -void app_main() +void app_main(void) { // Initialize touch pad peripheral, it will start a timer to run a filter ESP_LOGI(TAG, "Initializing touch pad"); diff --git a/examples/peripherals/touch_pad_read/main/tp_read_main.c b/examples/peripherals/touch_pad_read/main/tp_read_main.c index 85334c900d..3f442d7eb2 100644 --- a/examples/peripherals/touch_pad_read/main/tp_read_main.c +++ b/examples/peripherals/touch_pad_read/main/tp_read_main.c @@ -45,14 +45,14 @@ static void tp_example_read_task(void *pvParameter) } } -static void tp_example_touch_pad_init() +static void tp_example_touch_pad_init(void) { for (int i = 0;i< TOUCH_PAD_MAX;i++) { touch_pad_config(i, TOUCH_THRESH_NO_USE); } } -void app_main() +void app_main(void) { // Initialize touch pad peripheral. // The default fsm mode is software trigger mode. diff --git a/examples/peripherals/uart/nmea0183_parser/main/nmea_parser_example_main.c b/examples/peripherals/uart/nmea0183_parser/main/nmea_parser_example_main.c index 3b7c98705b..34154a541d 100644 --- a/examples/peripherals/uart/nmea0183_parser/main/nmea_parser_example_main.c +++ b/examples/peripherals/uart/nmea0183_parser/main/nmea_parser_example_main.c @@ -52,7 +52,7 @@ static void gps_event_handler(void *event_handler_arg, esp_event_base_t event_ba } } -void app_main() +void app_main(void) { /* NMEA parser configuration */ nmea_parser_config_t config = NMEA_PARSER_CONFIG_DEFAULT(); diff --git a/examples/peripherals/uart/uart_async_rxtxtasks/main/uart_async_rxtxtasks_main.c b/examples/peripherals/uart/uart_async_rxtxtasks/main/uart_async_rxtxtasks_main.c index 1933b0621e..f4f4eb18da 100644 --- a/examples/peripherals/uart/uart_async_rxtxtasks/main/uart_async_rxtxtasks_main.c +++ b/examples/peripherals/uart/uart_async_rxtxtasks/main/uart_async_rxtxtasks_main.c @@ -19,7 +19,7 @@ static const int RX_BUF_SIZE = 1024; #define TXD_PIN (GPIO_NUM_4) #define RXD_PIN (GPIO_NUM_5) -void init() { +void init(void) { const uart_config_t uart_config = { .baud_rate = 115200, .data_bits = UART_DATA_8_BITS, @@ -41,7 +41,7 @@ int sendData(const char* logName, const char* data) return txBytes; } -static void tx_task() +static void tx_task(void) { static const char *TX_TASK_TAG = "TX_TASK"; esp_log_level_set(TX_TASK_TAG, ESP_LOG_INFO); @@ -51,7 +51,7 @@ static void tx_task() } } -static void rx_task() +static void rx_task(void) { static const char *RX_TASK_TAG = "RX_TASK"; esp_log_level_set(RX_TASK_TAG, ESP_LOG_INFO); @@ -67,7 +67,7 @@ static void rx_task() free(data); } -void app_main() +void app_main(void) { init(); xTaskCreate(rx_task, "uart_rx_task", 1024*2, NULL, configMAX_PRIORITIES, NULL); diff --git a/examples/peripherals/uart/uart_echo/main/uart_echo_example_main.c b/examples/peripherals/uart/uart_echo/main/uart_echo_example_main.c index 50885eeee7..6e6a77a749 100644 --- a/examples/peripherals/uart/uart_echo/main/uart_echo_example_main.c +++ b/examples/peripherals/uart/uart_echo/main/uart_echo_example_main.c @@ -31,7 +31,7 @@ #define BUF_SIZE (1024) -static void echo_task() +static void echo_task(void) { /* Configure parameters of an UART driver, * communication pins and install the driver */ @@ -57,7 +57,7 @@ static void echo_task() } } -void app_main() +void app_main(void) { xTaskCreate(echo_task, "uart_echo_task", 1024, NULL, 10, NULL); } diff --git a/examples/peripherals/uart/uart_echo_rs485/main/rs485_example.c b/examples/peripherals/uart/uart_echo_rs485/main/rs485_example.c index 22204b73fe..c68c22edf0 100644 --- a/examples/peripherals/uart/uart_echo_rs485/main/rs485_example.c +++ b/examples/peripherals/uart/uart_echo_rs485/main/rs485_example.c @@ -52,7 +52,7 @@ static const char *TAG = "RS485_ECHO_APP"; // An example of echo test with hardware flow control on UART -static void echo_task() +static void echo_task(void) { const int uart_num = ECHO_UART_PORT; uart_config_t uart_config = { @@ -118,7 +118,7 @@ static void echo_task() } } -void app_main() +void app_main(void) { //A uart read/write example without event queue; xTaskCreate(echo_task, "uart_echo_task", ECHO_TASK_STACK_SIZE, NULL, ECHO_TASK_PRIO, NULL); diff --git a/examples/peripherals/uart/uart_events/main/uart_events_example_main.c b/examples/peripherals/uart/uart_events/main/uart_events_example_main.c index 8c9f545cb1..f749da0b14 100644 --- a/examples/peripherals/uart/uart_events/main/uart_events_example_main.c +++ b/examples/peripherals/uart/uart_events/main/uart_events_example_main.c @@ -117,7 +117,7 @@ static void uart_event_task(void *pvParameters) vTaskDelete(NULL); } -void app_main() +void app_main(void) { esp_log_level_set(TAG, ESP_LOG_INFO); diff --git a/examples/peripherals/uart/uart_select/main/uart_select_example_main.c b/examples/peripherals/uart/uart_select/main/uart_select_example_main.c index 717042f27a..2c46a3d114 100644 --- a/examples/peripherals/uart/uart_select/main/uart_select_example_main.c +++ b/examples/peripherals/uart/uart_select/main/uart_select_example_main.c @@ -20,7 +20,7 @@ static const char* TAG = "uart_select_example"; -static void uart_select_task() +static void uart_select_task(void) { uart_config_t uart_config = { .baud_rate = 115200, @@ -87,7 +87,7 @@ static void uart_select_task() vTaskDelete(NULL); } -void app_main() +void app_main(void) { xTaskCreate(uart_select_task, "uart_select_task", 4*1024, NULL, 5, NULL); } diff --git a/examples/protocols/asio/chat_client/main/chat_client.cpp b/examples/protocols/asio/chat_client/main/chat_client.cpp index d4a1110573..0b0f7097f0 100644 --- a/examples/protocols/asio/chat_client/main/chat_client.cpp +++ b/examples/protocols/asio/chat_client/main/chat_client.cpp @@ -134,7 +134,7 @@ private: void read_line(char * line, int max_chars); -extern "C" void app_main() +extern "C" void app_main(void) { ESP_ERROR_CHECK(nvs_flash_init()); tcpip_adapter_init(); diff --git a/examples/protocols/asio/chat_server/main/chat_server.cpp b/examples/protocols/asio/chat_server/main/chat_server.cpp index 56a447e05f..c1838b53f0 100644 --- a/examples/protocols/asio/chat_server/main/chat_server.cpp +++ b/examples/protocols/asio/chat_server/main/chat_server.cpp @@ -202,7 +202,7 @@ private: //---------------------------------------------------------------------- -extern "C" void app_main() +extern "C" void app_main(void) { ESP_ERROR_CHECK(nvs_flash_init()); tcpip_adapter_init(); diff --git a/examples/protocols/asio/tcp_echo_server/main/echo_server.cpp b/examples/protocols/asio/tcp_echo_server/main/echo_server.cpp index 008ec6ed79..d1ed69e05f 100644 --- a/examples/protocols/asio/tcp_echo_server/main/echo_server.cpp +++ b/examples/protocols/asio/tcp_echo_server/main/echo_server.cpp @@ -84,7 +84,7 @@ private: }; -extern "C" void app_main() +extern "C" void app_main(void) { ESP_ERROR_CHECK(nvs_flash_init()); tcpip_adapter_init(); diff --git a/examples/protocols/asio/udp_echo_server/main/udp_echo_server.cpp b/examples/protocols/asio/udp_echo_server/main/udp_echo_server.cpp index 06ac3fec92..68adf41482 100644 --- a/examples/protocols/asio/udp_echo_server/main/udp_echo_server.cpp +++ b/examples/protocols/asio/udp_echo_server/main/udp_echo_server.cpp @@ -66,7 +66,7 @@ private: char data_[max_length]; }; -extern "C" void app_main() +extern "C" void app_main(void) { ESP_ERROR_CHECK(nvs_flash_init()); tcpip_adapter_init(); diff --git a/examples/protocols/esp_http_client/main/esp_http_client_example.c b/examples/protocols/esp_http_client/main/esp_http_client_example.c index 6a642a73f4..348471a615 100644 --- a/examples/protocols/esp_http_client/main/esp_http_client_example.c +++ b/examples/protocols/esp_http_client/main/esp_http_client_example.c @@ -76,7 +76,7 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt) return ESP_OK; } -static void http_rest_with_url() +static void http_rest_with_url(void) { esp_http_client_config_t config = { .url = "http://httpbin.org/get", @@ -160,7 +160,7 @@ static void http_rest_with_url() esp_http_client_cleanup(client); } -static void http_rest_with_hostname_path() +static void http_rest_with_hostname_path(void) { esp_http_client_config_t config = { .host = "httpbin.org", @@ -247,7 +247,7 @@ static void http_rest_with_hostname_path() } -static void http_auth_basic() +static void http_auth_basic(void) { esp_http_client_config_t config = { .url = "http://user:passwd@httpbin.org/basic-auth/user/passwd", @@ -267,7 +267,7 @@ static void http_auth_basic() esp_http_client_cleanup(client); } -static void http_auth_basic_redirect() +static void http_auth_basic_redirect(void) { esp_http_client_config_t config = { .url = "http://user:passwd@httpbin.org/basic-auth/user/passwd", @@ -286,7 +286,7 @@ static void http_auth_basic_redirect() esp_http_client_cleanup(client); } -static void http_auth_digest() +static void http_auth_digest(void) { esp_http_client_config_t config = { .url = "http://user:passwd@httpbin.org/digest-auth/auth/user/passwd/MD5/never", @@ -305,7 +305,7 @@ static void http_auth_digest() esp_http_client_cleanup(client); } -static void https_with_url() +static void https_with_url(void) { esp_http_client_config_t config = { .url = "https://www.howsmyssl.com", @@ -325,7 +325,7 @@ static void https_with_url() esp_http_client_cleanup(client); } -static void https_with_hostname_path() +static void https_with_hostname_path(void) { esp_http_client_config_t config = { .host = "www.howsmyssl.com", @@ -347,7 +347,7 @@ static void https_with_hostname_path() esp_http_client_cleanup(client); } -static void http_relative_redirect() +static void http_relative_redirect(void) { esp_http_client_config_t config = { .url = "http://httpbin.org/relative-redirect/3", @@ -366,7 +366,7 @@ static void http_relative_redirect() esp_http_client_cleanup(client); } -static void http_absolute_redirect() +static void http_absolute_redirect(void) { esp_http_client_config_t config = { .url = "http://httpbin.org/absolute-redirect/3", @@ -385,7 +385,7 @@ static void http_absolute_redirect() esp_http_client_cleanup(client); } -static void http_redirect_to_https() +static void http_redirect_to_https(void) { esp_http_client_config_t config = { .url = "http://httpbin.org/redirect-to?url=https%3A%2F%2Fwww.howsmyssl.com", @@ -405,7 +405,7 @@ static void http_redirect_to_https() } -static void http_download_chunk() +static void http_download_chunk(void) { esp_http_client_config_t config = { .url = "http://httpbin.org/stream-bytes/8912", @@ -424,7 +424,7 @@ static void http_download_chunk() esp_http_client_cleanup(client); } -static void http_perform_as_stream_reader() +static void http_perform_as_stream_reader(void) { char *buffer = malloc(MAX_HTTP_RECV_BUFFER + 1); if (buffer == NULL) { @@ -460,7 +460,7 @@ static void http_perform_as_stream_reader() free(buffer); } -static void https_async() +static void https_async(void) { esp_http_client_config_t config = { .url = "https://postman-echo.com/post", @@ -492,7 +492,7 @@ static void https_async() esp_http_client_cleanup(client); } -static void https_with_invalid_url() +static void https_with_invalid_url(void) { esp_http_client_config_t config = { .url = "https://not.existent.url", @@ -533,7 +533,7 @@ static void http_test_task(void *pvParameters) vTaskDelete(NULL); } -void app_main() +void app_main(void) { esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { diff --git a/examples/protocols/esp_local_ctrl/main/app_main.c b/examples/protocols/esp_local_ctrl/main/app_main.c index d19feffda1..a550903839 100644 --- a/examples/protocols/esp_local_ctrl/main/app_main.c +++ b/examples/protocols/esp_local_ctrl/main/app_main.c @@ -62,7 +62,7 @@ static void event_handler(void* arg, esp_event_base_t event_base, } } -void wifi_init_sta() +void wifi_init_sta(void) { s_wifi_event_group = xEventGroupCreate(); @@ -95,7 +95,7 @@ void wifi_init_sta() * See local_ctrl_service.c for implementation */ extern void start_esp_local_ctrl_service(void); -void app_main() +void app_main(void) { //Initialize NVS esp_err_t ret = nvs_flash_init(); diff --git a/examples/protocols/http2_request/main/http2_request_example_main.c b/examples/protocols/http2_request/main/http2_request_example_main.c index 180b8b9348..9b6bb739ec 100644 --- a/examples/protocols/http2_request/main/http2_request_example_main.c +++ b/examples/protocols/http2_request/main/http2_request_example_main.c @@ -128,7 +128,7 @@ static void http2_task(void *args) vTaskDelete(NULL); } -void app_main() +void app_main(void) { ESP_ERROR_CHECK( nvs_flash_init() ); tcpip_adapter_init(); diff --git a/examples/protocols/http_request/main/http_request_example_main.c b/examples/protocols/http_request/main/http_request_example_main.c index 20f1b667f6..5626ae7961 100644 --- a/examples/protocols/http_request/main/http_request_example_main.c +++ b/examples/protocols/http_request/main/http_request_example_main.c @@ -119,7 +119,7 @@ static void http_get_task(void *pvParameters) } } -void app_main() +void app_main(void) { ESP_ERROR_CHECK( nvs_flash_init() ); tcpip_adapter_init(); diff --git a/examples/protocols/http_server/advanced_tests/main/main.c b/examples/protocols/http_server/advanced_tests/main/main.c index d203c48820..af9ae1a87d 100644 --- a/examples/protocols/http_server/advanced_tests/main/main.c +++ b/examples/protocols/http_server/advanced_tests/main/main.c @@ -41,7 +41,7 @@ static void connect_handler(void* arg, esp_event_base_t event_base, } } -void app_main() +void app_main(void) { static httpd_handle_t server = NULL; diff --git a/examples/protocols/http_server/advanced_tests/main/tests.c b/examples/protocols/http_server/advanced_tests/main/tests.c index c41810e612..dd4a973155 100644 --- a/examples/protocols/http_server/advanced_tests/main/tests.c +++ b/examples/protocols/http_server/advanced_tests/main/tests.c @@ -270,7 +270,7 @@ static void register_basic_handlers(httpd_handle_t hd) ESP_LOGI(TAG, "Success"); } -static httpd_handle_t test_httpd_start() +static httpd_handle_t test_httpd_start(void) { pre_start_mem = esp_get_free_heap_size(); httpd_handle_t hd; @@ -299,7 +299,7 @@ static void test_httpd_stop(httpd_handle_t hd) ESP_LOGI(TAG, "HTTPD Stop: Current free memory: %d", post_stop_mem); } -httpd_handle_t start_tests() +httpd_handle_t start_tests(void) { httpd_handle_t hd = test_httpd_start(); if (hd) { diff --git a/examples/protocols/http_server/file_serving/main/main.c b/examples/protocols/http_server/file_serving/main/main.c index 8515f61334..421355da33 100644 --- a/examples/protocols/http_server/file_serving/main/main.c +++ b/examples/protocols/http_server/file_serving/main/main.c @@ -64,7 +64,7 @@ static esp_err_t init_spiffs(void) * file_server.c */ esp_err_t start_file_server(const char *base_path); -void app_main() +void app_main(void) { ESP_ERROR_CHECK(nvs_flash_init()); tcpip_adapter_init(); diff --git a/examples/protocols/http_server/persistent_sockets/main/main.c b/examples/protocols/http_server/persistent_sockets/main/main.c index 3d551fe268..725de62e10 100644 --- a/examples/protocols/http_server/persistent_sockets/main/main.c +++ b/examples/protocols/http_server/persistent_sockets/main/main.c @@ -211,7 +211,7 @@ static void connect_handler(void* arg, esp_event_base_t event_base, } -void app_main() +void app_main(void) { static httpd_handle_t server = NULL; diff --git a/examples/protocols/http_server/restful_server/main/esp_rest_main.c b/examples/protocols/http_server/restful_server/main/esp_rest_main.c index dc885fa5b2..ee13bfa354 100644 --- a/examples/protocols/http_server/restful_server/main/esp_rest_main.c +++ b/examples/protocols/http_server/restful_server/main/esp_rest_main.c @@ -121,7 +121,7 @@ esp_err_t init_fs(void) } #endif -void app_main() +void app_main(void) { ESP_ERROR_CHECK(nvs_flash_init()); tcpip_adapter_init(); diff --git a/examples/protocols/http_server/simple/main/main.c b/examples/protocols/http_server/simple/main/main.c index 270c939410..d7bec44662 100644 --- a/examples/protocols/http_server/simple/main/main.c +++ b/examples/protocols/http_server/simple/main/main.c @@ -267,7 +267,7 @@ static void connect_handler(void* arg, esp_event_base_t event_base, } -void app_main() +void app_main(void) { static httpd_handle_t server = NULL; diff --git a/examples/protocols/https_mbedtls/main/https_mbedtls_example_main.c b/examples/protocols/https_mbedtls/main/https_mbedtls_example_main.c index 29c97e831e..ce5823f60f 100644 --- a/examples/protocols/https_mbedtls/main/https_mbedtls_example_main.c +++ b/examples/protocols/https_mbedtls/main/https_mbedtls_example_main.c @@ -271,7 +271,7 @@ static void https_get_task(void *pvParameters) } } -void app_main() +void app_main(void) { ESP_ERROR_CHECK( nvs_flash_init() ); tcpip_adapter_init(); diff --git a/examples/protocols/https_request/main/https_request_example_main.c b/examples/protocols/https_request/main/https_request_example_main.c index 742a4657e1..4e07c128a8 100644 --- a/examples/protocols/https_request/main/https_request_example_main.c +++ b/examples/protocols/https_request/main/https_request_example_main.c @@ -148,7 +148,7 @@ static void https_get_task(void *pvParameters) } } -void app_main() +void app_main(void) { ESP_ERROR_CHECK( nvs_flash_init() ); tcpip_adapter_init(); diff --git a/examples/protocols/https_server/main/main.c b/examples/protocols/https_server/main/main.c index 7cebabfb96..a71f44e598 100644 --- a/examples/protocols/https_server/main/main.c +++ b/examples/protocols/https_server/main/main.c @@ -98,7 +98,7 @@ static void connect_handler(void* arg, esp_event_base_t event_base, } } -void app_main() +void app_main(void) { static httpd_handle_t server = NULL; diff --git a/examples/protocols/mdns/main/mdns_example_main.c b/examples/protocols/mdns/main/mdns_example_main.c index 11bee313b0..a406b74d1b 100644 --- a/examples/protocols/mdns/main/mdns_example_main.c +++ b/examples/protocols/mdns/main/mdns_example_main.c @@ -27,7 +27,7 @@ #define EXAMPLE_BUTTON_GPIO 0 static const char *TAG = "mdns-test"; -static char* generate_hostname(); +static char* generate_hostname(void); static void initialise_mdns(void) { @@ -176,7 +176,7 @@ static void mdns_example_task(void *pvParameters) } } -void app_main() +void app_main(void) { ESP_ERROR_CHECK(nvs_flash_init()); tcpip_adapter_init(); @@ -197,7 +197,7 @@ void app_main() /** Generate host name based on sdkconfig, optionally adding a portion of MAC address to it. * @return host name string allocated from the heap */ -static char* generate_hostname() +static char* generate_hostname(void) { #ifndef CONFIG_MDNS_ADD_MAC_TO_HOSTNAME return strdup(CONFIG_MDNS_HOSTNAME); diff --git a/examples/protocols/modbus_master/main/include/sense_modbus.h b/examples/protocols/modbus_master/main/include/sense_modbus.h index 9860c40575..4c13391da1 100644 --- a/examples/protocols/modbus_master/main/include/sense_modbus.h +++ b/examples/protocols/modbus_master/main/include/sense_modbus.h @@ -47,7 +47,7 @@ typedef struct uint64_t timestamp; /*!< Time stamp of last access to parameter */ } characteristic_descriptor_t; -esp_err_t sense_modbus_init(); +esp_err_t sense_modbus_init(void); esp_err_t sense_modbus_get_characteristics(characteristic_descriptor_t** cid_table, uint16_t* table_size); esp_err_t sense_modbus_read_value(uint16_t cid, void* value); esp_err_t sense_modbus_send_value(uint16_t cid, void* value); diff --git a/examples/protocols/modbus_master/main/sense_main.c b/examples/protocols/modbus_master/main/sense_main.c index 00158336db..13d52a9839 100644 --- a/examples/protocols/modbus_master/main/sense_main.c +++ b/examples/protocols/modbus_master/main/sense_main.c @@ -137,13 +137,13 @@ static void trigger_operation_task(void *arg) vTaskDelete(NULL); } -static void sense_device_init() +static void sense_device_init(void) { // Initialize and start Modbus controller sense_modbus_init(); } -void app_main() +void app_main(void) { esp_err_t result = ESP_OK; diff --git a/examples/protocols/modbus_master/main/sense_modbus.c b/examples/protocols/modbus_master/main/sense_modbus.c index f8b77539f7..8d1ab3539c 100644 --- a/examples/protocols/modbus_master/main/sense_modbus.c +++ b/examples/protocols/modbus_master/main/sense_modbus.c @@ -81,14 +81,14 @@ static void* sense_modbus_get_param_data(const mb_parameter_descriptor_t* param_ } // The helper function to get time stamp in microseconds -static uint64_t sense_modbus_get_time_stamp_us() +static uint64_t sense_modbus_get_time_stamp_us(void) { uint64_t time_stamp = esp_timer_get_time(); return time_stamp; } // Initialization of Modbus stack -esp_err_t sense_modbus_init() +esp_err_t sense_modbus_init(void) { mb_communication_info_t comm = { .port = MB_PORTNUM, diff --git a/examples/protocols/modbus_slave/main/freemodbus.c b/examples/protocols/modbus_slave/main/freemodbus.c index e29492c506..abca71999a 100644 --- a/examples/protocols/modbus_slave/main/freemodbus.c +++ b/examples/protocols/modbus_slave/main/freemodbus.c @@ -35,7 +35,7 @@ static const char *TAG = "MODBUS_SLAVE_APP"; // Set register values into known state -static void setup_reg_data() +static void setup_reg_data(void) { // Define initial state of parameters discrete_reg_params.discrete_input1 = 1; @@ -64,7 +64,7 @@ static void setup_reg_data() // See deviceparams.h file for more information about assigned Modbus parameters. // These parameters can be accessed from main application and also can be changed // by external Modbus master host. -void app_main() +void app_main(void) { mb_param_info_t reg_info; // keeps the Modbus registers access information mb_communication_info_t comm_info; // Modbus communication parameters diff --git a/examples/protocols/mqtt/publish_test/main/publish_test.c b/examples/protocols/mqtt/publish_test/main/publish_test.c index 15cd2b09bf..9183bbb8bb 100644 --- a/examples/protocols/mqtt/publish_test/main/publish_test.c +++ b/examples/protocols/mqtt/publish_test/main/publish_test.c @@ -151,7 +151,7 @@ static void get_string(char *line, size_t size) } } -void app_main() +void app_main(void) { char line[256]; char pattern[32]; diff --git a/examples/protocols/mqtt/ssl/main/app_main.c b/examples/protocols/mqtt/ssl/main/app_main.c index e819c8fdc8..fd0a49d7bf 100644 --- a/examples/protocols/mqtt/ssl/main/app_main.c +++ b/examples/protocols/mqtt/ssl/main/app_main.c @@ -110,7 +110,7 @@ static void mqtt_app_start(void) esp_mqtt_client_start(client); } -void app_main() +void app_main(void) { ESP_LOGI(TAG, "[APP] Startup.."); ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); diff --git a/examples/protocols/mqtt/ssl_mutual_auth/main/app_main.c b/examples/protocols/mqtt/ssl_mutual_auth/main/app_main.c index 21c76ff44d..5c6eab7ee5 100644 --- a/examples/protocols/mqtt/ssl_mutual_auth/main/app_main.c +++ b/examples/protocols/mqtt/ssl_mutual_auth/main/app_main.c @@ -97,7 +97,7 @@ static void mqtt_app_start(void) esp_mqtt_client_start(client); } -void app_main() +void app_main(void) { ESP_LOGI(TAG, "[APP] Startup.."); ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); diff --git a/examples/protocols/mqtt/tcp/main/app_main.c b/examples/protocols/mqtt/tcp/main/app_main.c index 9e24a37705..7acd685360 100644 --- a/examples/protocols/mqtt/tcp/main/app_main.c +++ b/examples/protocols/mqtt/tcp/main/app_main.c @@ -123,7 +123,7 @@ static void mqtt_app_start(void) esp_mqtt_client_start(client); } -void app_main() +void app_main(void) { ESP_LOGI(TAG, "[APP] Startup.."); ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); diff --git a/examples/protocols/mqtt/ws/main/app_main.c b/examples/protocols/mqtt/ws/main/app_main.c index cb45759ef8..cacea73e9d 100644 --- a/examples/protocols/mqtt/ws/main/app_main.c +++ b/examples/protocols/mqtt/ws/main/app_main.c @@ -95,7 +95,7 @@ static void mqtt_app_start(void) esp_mqtt_client_start(client); } -void app_main() +void app_main(void) { ESP_LOGI(TAG, "[APP] Startup.."); ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); diff --git a/examples/protocols/mqtt/wss/main/app_main.c b/examples/protocols/mqtt/wss/main/app_main.c index dca752b999..a9de24455a 100644 --- a/examples/protocols/mqtt/wss/main/app_main.c +++ b/examples/protocols/mqtt/wss/main/app_main.c @@ -105,7 +105,7 @@ static void mqtt_app_start(void) esp_mqtt_client_start(client); } -void app_main() +void app_main(void) { ESP_LOGI(TAG, "[APP] Startup.."); ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); diff --git a/examples/protocols/pppos_client/main/pppos_client_main.c b/examples/protocols/pppos_client/main/pppos_client_main.c index bd706f6fd6..4f376ea68f 100644 --- a/examples/protocols/pppos_client/main/pppos_client_main.c +++ b/examples/protocols/pppos_client/main/pppos_client_main.c @@ -179,7 +179,7 @@ static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event) return ESP_OK; } -void app_main() +void app_main(void) { tcpip_adapter_init(); event_group = xEventGroupCreate(); diff --git a/examples/protocols/sntp/main/sntp_example_main.c b/examples/protocols/sntp/main/sntp_example_main.c index 157d260634..59d22d7fec 100644 --- a/examples/protocols/sntp/main/sntp_example_main.c +++ b/examples/protocols/sntp/main/sntp_example_main.c @@ -46,7 +46,7 @@ void time_sync_notification_cb(struct timeval *tv) ESP_LOGI(TAG, "Notification of a time synchronization event"); } -void app_main() +void app_main(void) { ++boot_count; ESP_LOGI(TAG, "Boot count: %d", boot_count); diff --git a/examples/protocols/sockets/tcp_client/main/tcp_client.c b/examples/protocols/sockets/tcp_client/main/tcp_client.c index 96657d7981..5e98718df5 100644 --- a/examples/protocols/sockets/tcp_client/main/tcp_client.c +++ b/examples/protocols/sockets/tcp_client/main/tcp_client.c @@ -109,7 +109,7 @@ static void tcp_client_task(void *pvParameters) vTaskDelete(NULL); } -void app_main() +void app_main(void) { ESP_ERROR_CHECK(nvs_flash_init()); tcpip_adapter_init(); diff --git a/examples/protocols/sockets/tcp_server/main/tcp_server.c b/examples/protocols/sockets/tcp_server/main/tcp_server.c index 1e71096dce..062268ebd3 100644 --- a/examples/protocols/sockets/tcp_server/main/tcp_server.c +++ b/examples/protocols/sockets/tcp_server/main/tcp_server.c @@ -128,7 +128,7 @@ static void tcp_server_task(void *pvParameters) vTaskDelete(NULL); } -void app_main() +void app_main(void) { ESP_ERROR_CHECK(nvs_flash_init()); tcpip_adapter_init(); diff --git a/examples/protocols/sockets/udp_client/main/udp_client.c b/examples/protocols/sockets/udp_client/main/udp_client.c index 6639082a1d..bb31755795 100644 --- a/examples/protocols/sockets/udp_client/main/udp_client.c +++ b/examples/protocols/sockets/udp_client/main/udp_client.c @@ -108,7 +108,7 @@ static void udp_client_task(void *pvParameters) vTaskDelete(NULL); } -void app_main() +void app_main(void) { ESP_ERROR_CHECK(nvs_flash_init()); tcpip_adapter_init(); diff --git a/examples/protocols/sockets/udp_multicast/main/udp_multicast_example_main.c b/examples/protocols/sockets/udp_multicast/main/udp_multicast_example_main.c index bd2a4cbedf..e20ce9fd37 100644 --- a/examples/protocols/sockets/udp_multicast/main/udp_multicast_example_main.c +++ b/examples/protocols/sockets/udp_multicast/main/udp_multicast_example_main.c @@ -107,7 +107,7 @@ static int socket_add_ipv4_multicast_group(int sock, bool assign_source_if) #endif /* CONFIG_EXAMPLE_IPV4 */ #ifdef CONFIG_EXAMPLE_IPV4_ONLY -static int create_multicast_ipv4_socket() +static int create_multicast_ipv4_socket(void) { struct sockaddr_in saddr = { 0 }; int sock = -1; @@ -167,7 +167,7 @@ err: #endif /* CONFIG_EXAMPLE_IPV4_ONLY */ #ifdef CONFIG_EXAMPLE_IPV6 -static int create_multicast_ipv6_socket() +static int create_multicast_ipv6_socket(void) { struct sockaddr_in6 saddr = { 0 }; int netif_index; @@ -481,7 +481,7 @@ static void mcast_example_task(void *pvParameters) } -void app_main() +void app_main(void) { ESP_ERROR_CHECK(nvs_flash_init()); tcpip_adapter_init(); diff --git a/examples/protocols/sockets/udp_server/main/udp_server.c b/examples/protocols/sockets/udp_server/main/udp_server.c index ce82168323..262d2b2137 100644 --- a/examples/protocols/sockets/udp_server/main/udp_server.c +++ b/examples/protocols/sockets/udp_server/main/udp_server.c @@ -109,7 +109,7 @@ static void udp_server_task(void *pvParameters) vTaskDelete(NULL); } -void app_main() +void app_main(void) { ESP_ERROR_CHECK(nvs_flash_init()); tcpip_adapter_init(); diff --git a/examples/protocols/websocket/main/websocket_example.c b/examples/protocols/websocket/main/websocket_example.c index 120a5b4fdf..6b64ef25d0 100644 --- a/examples/protocols/websocket/main/websocket_example.c +++ b/examples/protocols/websocket/main/websocket_example.c @@ -80,7 +80,7 @@ static void websocket_app_start(void) esp_websocket_client_destroy(client); } -void app_main() +void app_main(void) { ESP_LOGI(TAG, "[APP] Startup.."); ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); diff --git a/examples/provisioning/ble_prov/main/app_main.c b/examples/provisioning/ble_prov/main/app_main.c index 6ce1184c26..1b96f5d125 100644 --- a/examples/provisioning/ble_prov/main/app_main.c +++ b/examples/provisioning/ble_prov/main/app_main.c @@ -25,7 +25,7 @@ static const char *TAG = "app"; -static void start_ble_provisioning(); +static void start_ble_provisioning(void); static void event_handler(void* arg, esp_event_base_t event_base, int event_id, void* event_data) @@ -76,7 +76,7 @@ static void event_handler(void* arg, esp_event_base_t event_base, } } -static void wifi_init_sta() +static void wifi_init_sta(void) { /* Set our event handling */ ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, event_handler, NULL)); @@ -87,7 +87,7 @@ static void wifi_init_sta() ESP_ERROR_CHECK(esp_wifi_start()); } -static void start_ble_provisioning() +static void start_ble_provisioning(void) { /* Security version */ int security = 0; @@ -110,7 +110,7 @@ static void start_ble_provisioning() ESP_ERROR_CHECK(app_prov_start_ble_provisioning(security, pop)); } -void app_main() +void app_main(void) { /* Initialize networking stack */ tcpip_adapter_init(); diff --git a/examples/provisioning/console_prov/main/app_main.c b/examples/provisioning/console_prov/main/app_main.c index 35b3d575e9..6d5ef38836 100644 --- a/examples/provisioning/console_prov/main/app_main.c +++ b/examples/provisioning/console_prov/main/app_main.c @@ -47,7 +47,7 @@ static void event_handler(void* arg, esp_event_base_t event_base, } } -static void wifi_init_sta() +static void wifi_init_sta(void) { /* Set our event handling */ ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, event_handler, NULL)); @@ -58,7 +58,7 @@ static void wifi_init_sta() ESP_ERROR_CHECK(esp_wifi_start()); } -static void start_console_provisioning() +static void start_console_provisioning(void) { /* Security version */ int security = 0; @@ -81,7 +81,7 @@ static void start_console_provisioning() ESP_ERROR_CHECK(app_prov_start_console_provisioning(security, pop)); } -void app_main() +void app_main(void) { /* Initialize networking stack */ tcpip_adapter_init(); diff --git a/examples/provisioning/custom_config/main/app_main.c b/examples/provisioning/custom_config/main/app_main.c index 7b23c883c9..072e7b5aaa 100644 --- a/examples/provisioning/custom_config/main/app_main.c +++ b/examples/provisioning/custom_config/main/app_main.c @@ -47,7 +47,7 @@ static void event_handler(void* arg, esp_event_base_t event_base, } } -static void wifi_init_sta() +static void wifi_init_sta(void) { /* Set our event handling */ ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, event_handler, NULL)); @@ -58,7 +58,7 @@ static void wifi_init_sta() ESP_ERROR_CHECK(esp_wifi_start()); } -static void start_softap_provisioning() +static void start_softap_provisioning(void) { /* Security version */ int security = 0; @@ -82,7 +82,7 @@ static void start_softap_provisioning() CONFIG_EXAMPLE_SSID, CONFIG_EXAMPLE_PASS, security, pop)); } -void app_main() +void app_main(void) { /* Initialize networking stack */ tcpip_adapter_init(); diff --git a/examples/provisioning/manager/main/app_main.c b/examples/provisioning/manager/main/app_main.c index 96634fa71a..065b6f8fcf 100644 --- a/examples/provisioning/manager/main/app_main.c +++ b/examples/provisioning/manager/main/app_main.c @@ -77,7 +77,7 @@ static void event_handler(void* arg, esp_event_base_t event_base, } } -static void wifi_init_sta() +static void wifi_init_sta(void) { /* Start Wi-Fi in station mode */ ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); @@ -93,7 +93,7 @@ static void get_device_service_name(char *service_name, size_t max) ssid_prefix, eth_mac[3], eth_mac[4], eth_mac[5]); } -void app_main() +void app_main(void) { /* Initialize NVS partition */ esp_err_t ret = nvs_flash_init(); diff --git a/examples/provisioning/softap_prov/main/app_main.c b/examples/provisioning/softap_prov/main/app_main.c index a775f7a2f1..8ee7ae679c 100644 --- a/examples/provisioning/softap_prov/main/app_main.c +++ b/examples/provisioning/softap_prov/main/app_main.c @@ -47,7 +47,7 @@ static void event_handler(void* arg, esp_event_base_t event_base, } } -static void wifi_init_sta() +static void wifi_init_sta(void) { /* Set our event handling */ ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, event_handler, NULL)); @@ -58,7 +58,7 @@ static void wifi_init_sta() ESP_ERROR_CHECK(esp_wifi_start()); } -static void start_softap_provisioning() +static void start_softap_provisioning(void) { /* Security version */ int security = 0; @@ -97,7 +97,7 @@ static void start_softap_provisioning() ssid, CONFIG_EXAMPLE_PASS, security, pop)); } -void app_main() +void app_main(void) { /* Initialize networking stack */ tcpip_adapter_init(); diff --git a/examples/security/flash_encryption/main/flash_encrypt_main.c b/examples/security/flash_encryption/main/flash_encrypt_main.c index 63fd480bab..73ab39afe5 100644 --- a/examples/security/flash_encryption/main/flash_encrypt_main.c +++ b/examples/security/flash_encryption/main/flash_encrypt_main.c @@ -16,7 +16,7 @@ #include "esp_flash_encrypt.h" #include "esp_efuse_table.h" -void app_main() +void app_main(void) { uint32_t flash_crypt_cnt = 0; esp_flash_enc_mode_t mode; diff --git a/examples/storage/ext_flash_fatfs/main/ext_flash_fatfs_example_main.c b/examples/storage/ext_flash_fatfs/main/ext_flash_fatfs_example_main.c index c64fb76ad1..e0698dccf9 100644 --- a/examples/storage/ext_flash_fatfs/main/ext_flash_fatfs_example_main.c +++ b/examples/storage/ext_flash_fatfs/main/ext_flash_fatfs_example_main.c @@ -28,7 +28,7 @@ static wl_handle_t s_wl_handle = WL_INVALID_HANDLE; // Mount path for the partition const char *base_path = "/extflash"; -static esp_flash_t* example_init_ext_flash(); +static esp_flash_t* example_init_ext_flash(void); static const esp_partition_t* example_add_partition(esp_flash_t* ext_flash, const char* partition_label); static bool example_mount_fatfs(const char* partition_label); static void example_get_fatfs_usage(size_t* out_total_bytes, size_t* out_free_bytes); @@ -84,7 +84,7 @@ void app_main(void) ESP_LOGI(TAG, "Read from file: '%s'", line); } -static esp_flash_t* example_init_ext_flash() +static esp_flash_t* example_init_ext_flash(void) { const spi_bus_config_t bus_config = { .mosi_io_num = VSPI_IOMUX_PIN_NUM_MOSI, diff --git a/examples/storage/nvs_rw_blob/main/nvs_blob_example_main.c b/examples/storage/nvs_rw_blob/main/nvs_blob_example_main.c index f6b74766e5..431752147f 100644 --- a/examples/storage/nvs_rw_blob/main/nvs_blob_example_main.c +++ b/examples/storage/nvs_rw_blob/main/nvs_blob_example_main.c @@ -150,7 +150,7 @@ esp_err_t print_what_saved(void) } -void app_main() +void app_main(void) { esp_err_t err = nvs_flash_init(); if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { diff --git a/examples/storage/nvs_rw_value/main/nvs_value_example_main.c b/examples/storage/nvs_rw_value/main/nvs_value_example_main.c index 757eeeb303..47abd43a6e 100644 --- a/examples/storage/nvs_rw_value/main/nvs_value_example_main.c +++ b/examples/storage/nvs_rw_value/main/nvs_value_example_main.c @@ -16,7 +16,7 @@ #include "nvs_flash.h" #include "nvs.h" -void app_main() +void app_main(void) { // Initialize NVS esp_err_t err = nvs_flash_init(); diff --git a/examples/storage/spiffsgen/main/spiffsgen_example_main.c b/examples/storage/spiffsgen/main/spiffsgen_example_main.c index fde74dcdc0..5c67c47c5e 100644 --- a/examples/storage/spiffsgen/main/spiffsgen_example_main.c +++ b/examples/storage/spiffsgen/main/spiffsgen_example_main.c @@ -18,7 +18,7 @@ static const char *TAG = "example"; -static void read_hello_txt() +static void read_hello_txt(void) { ESP_LOGI(TAG, "Reading hello.txt"); @@ -38,7 +38,7 @@ static void read_hello_txt() ESP_LOGI(TAG, "Read from hello.txt: %s", buf); } -static void compute_alice_txt_md5() +static void compute_alice_txt_md5(void) { ESP_LOGI(TAG, "Computing alice.txt MD5 hash"); diff --git a/examples/system/app_trace_to_host/main/app_trace_to_host_example_main.c b/examples/system/app_trace_to_host/main/app_trace_to_host_example_main.c index bedeeb35c7..f2b382df9a 100644 --- a/examples/system/app_trace_to_host/main/app_trace_to_host_example_main.c +++ b/examples/system/app_trace_to_host/main/app_trace_to_host_example_main.c @@ -85,7 +85,7 @@ static int adc1_sample_and_show(int sampling_period) * and logging results with application tracing to the host * as well as for comparison printing out sampling result to UART */ -void app_main() +void app_main(void) { ESP_LOGI(TAG, "Enabling ADC1 on channel 6 / GPIO34."); adc1_config_width(ADC_WIDTH_BIT_12); diff --git a/examples/system/base_mac_address/main/base_mac_address_example_main.c b/examples/system/base_mac_address/main/base_mac_address_example_main.c index c7a114bfef..7353ad76bf 100644 --- a/examples/system/base_mac_address/main/base_mac_address_example_main.c +++ b/examples/system/base_mac_address/main/base_mac_address_example_main.c @@ -30,7 +30,7 @@ static esp_err_t external_storage_mac_get(uint8_t *mac) } #endif//CONFIG_BASE_MAC_STORED_OTHER_EXTERNAL_STORAGE -void app_main() +void app_main(void) { #if defined(CONFIG_BASE_MAC_STORED_EFUSE_BLK3) || defined(CONFIG_BASE_MAC_STORED_OTHER_EXTERNAL_STORAGE) uint8_t mac_addr[8] = {0}; diff --git a/examples/system/console/components/cmd_nvs/cmd_nvs.c b/examples/system/console/components/cmd_nvs/cmd_nvs.c index 21d128ecd0..3878702eb4 100644 --- a/examples/system/console/components/cmd_nvs/cmd_nvs.c +++ b/examples/system/console/components/cmd_nvs/cmd_nvs.c @@ -507,7 +507,7 @@ static int list_entries(int argc, char **argv) return list(part, name, type); } -void register_nvs() +void register_nvs(void) { set_args.key = arg_str1(NULL, NULL, "", "key of the value to be set"); set_args.type = arg_str1(NULL, NULL, "", ARG_TYPE_STR); diff --git a/examples/system/console/components/cmd_nvs/cmd_nvs.h b/examples/system/console/components/cmd_nvs/cmd_nvs.h index 6d0de50dcf..d18c2b41fe 100644 --- a/examples/system/console/components/cmd_nvs/cmd_nvs.h +++ b/examples/system/console/components/cmd_nvs/cmd_nvs.h @@ -13,7 +13,7 @@ extern "C" { #endif // Register NVS functions -void register_nvs(); +void register_nvs(void); #ifdef __cplusplus } diff --git a/examples/system/console/components/cmd_system/cmd_system.c b/examples/system/console/components/cmd_system/cmd_system.c index 50fe5ec09c..caf8d70f23 100644 --- a/examples/system/console/components/cmd_system/cmd_system.c +++ b/examples/system/console/components/cmd_system/cmd_system.c @@ -30,17 +30,17 @@ static const char *TAG = "cmd_system"; -static void register_free(); -static void register_heap(); -static void register_version(); -static void register_restart(); -static void register_deep_sleep(); -static void register_light_sleep(); +static void register_free(void); +static void register_heap(void); +static void register_version(void); +static void register_restart(void); +static void register_deep_sleep(void); +static void register_light_sleep(void); #if WITH_TASKS_INFO -static void register_tasks(); +static void register_tasks(void); #endif -void register_system() +void register_system(void) { register_free(); register_heap(); @@ -72,7 +72,7 @@ static int get_version(int argc, char **argv) return 0; } -static void register_version() +static void register_version(void) { const esp_console_cmd_t cmd = { .command = "version", @@ -91,7 +91,7 @@ static int restart(int argc, char **argv) esp_restart(); } -static void register_restart() +static void register_restart(void) { const esp_console_cmd_t cmd = { .command = "restart", @@ -110,7 +110,7 @@ static int free_mem(int argc, char **argv) return 0; } -static void register_free() +static void register_free(void) { const esp_console_cmd_t cmd = { .command = "free", @@ -129,7 +129,7 @@ static int heap_size(int argc, char **argv) return 0; } -static void register_heap() +static void register_heap(void) { const esp_console_cmd_t heap_cmd = { .command = "heap", @@ -163,7 +163,7 @@ static int tasks_info(int argc, char **argv) return 0; } -static void register_tasks() +static void register_tasks(void) { const esp_console_cmd_t cmd = { .command = "tasks", @@ -221,7 +221,7 @@ static int deep_sleep(int argc, char **argv) esp_deep_sleep_start(); } -static void register_deep_sleep() +static void register_deep_sleep(void) { deep_sleep_args.wakeup_time = arg_int0("t", "time", "", "Wake up time, ms"); @@ -314,7 +314,7 @@ static int light_sleep(int argc, char **argv) return 0; } -static void register_light_sleep() +static void register_light_sleep(void) { light_sleep_args.wakeup_time = arg_int0("t", "time", "", "Wake up time, ms"); diff --git a/examples/system/console/components/cmd_system/cmd_system.h b/examples/system/console/components/cmd_system/cmd_system.h index be746a2276..9af96a8ae5 100644 --- a/examples/system/console/components/cmd_system/cmd_system.h +++ b/examples/system/console/components/cmd_system/cmd_system.h @@ -13,7 +13,7 @@ extern "C" { #endif // Register system functions -void register_system(); +void register_system(void); #ifdef __cplusplus } diff --git a/examples/system/console/main/cmd_wifi.c b/examples/system/console/main/cmd_wifi.c index eb2024dabe..b9c24f0cd1 100644 --- a/examples/system/console/main/cmd_wifi.c +++ b/examples/system/console/main/cmd_wifi.c @@ -109,7 +109,7 @@ static int connect(int argc, char **argv) return 0; } -void register_wifi() +void register_wifi(void) { join_args.timeout = arg_int0(NULL, "timeout", "", "Connection timeout, ms"); join_args.ssid = arg_str1(NULL, NULL, "", "SSID of AP"); diff --git a/examples/system/console/main/cmd_wifi.h b/examples/system/console/main/cmd_wifi.h index a1a1655e45..5259dd72ff 100644 --- a/examples/system/console/main/cmd_wifi.h +++ b/examples/system/console/main/cmd_wifi.h @@ -13,7 +13,7 @@ extern "C" { #endif // Register WiFi functions -void register_wifi(); +void register_wifi(void); #ifdef __cplusplus } diff --git a/examples/system/console/main/console_example_main.c b/examples/system/console/main/console_example_main.c index e0e48b4308..e89196c4b8 100644 --- a/examples/system/console/main/console_example_main.c +++ b/examples/system/console/main/console_example_main.c @@ -32,7 +32,7 @@ static const char* TAG = "example"; #define MOUNT_PATH "/data" #define HISTORY_PATH MOUNT_PATH "/history.txt" -static void initialize_filesystem() +static void initialize_filesystem(void) { static wl_handle_t wl_handle; const esp_vfs_fat_mount_config_t mount_config = { @@ -47,7 +47,7 @@ static void initialize_filesystem() } #endif // CONFIG_STORE_HISTORY -static void initialize_nvs() +static void initialize_nvs(void) { esp_err_t err = nvs_flash_init(); if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { @@ -57,7 +57,7 @@ static void initialize_nvs() ESP_ERROR_CHECK(err); } -static void initialize_console() +static void initialize_console(void) { /* Disable buffering on stdin */ setvbuf(stdin, NULL, _IONBF, 0); @@ -115,7 +115,7 @@ static void initialize_console() #endif } -void app_main() +void app_main(void) { initialize_nvs(); diff --git a/examples/system/cpp_exceptions/main/exception_example_main.cpp b/examples/system/cpp_exceptions/main/exception_example_main.cpp index 24ada9de68..29045beb4c 100644 --- a/examples/system/cpp_exceptions/main/exception_example_main.cpp +++ b/examples/system/cpp_exceptions/main/exception_example_main.cpp @@ -36,7 +36,7 @@ protected: }; /* Inside .cpp file, app_main function must be declared with C linkage */ -extern "C" void app_main() +extern "C" void app_main(void) { cout << "app_main starting" << endl; diff --git a/examples/system/cpp_pthread/main/cpp_pthread.cpp b/examples/system/cpp_pthread/main/cpp_pthread.cpp index 59b0870d07..d39ea91f3e 100644 --- a/examples/system/cpp_pthread/main/cpp_pthread.cpp +++ b/examples/system/cpp_pthread/main/cpp_pthread.cpp @@ -82,7 +82,7 @@ esp_pthread_cfg_t create_config(const char *name, int core_id, int stack, int pr return cfg; } -extern "C" void app_main() +extern "C" void app_main(void) { // Create a thread using deafult values that can run on any core auto cfg = esp_pthread_get_default_config(); diff --git a/examples/system/deep_sleep/main/deep_sleep_example_main.c b/examples/system/deep_sleep/main/deep_sleep_example_main.c index 5843e64aa9..22bfad4b50 100644 --- a/examples/system/deep_sleep/main/deep_sleep_example_main.c +++ b/examples/system/deep_sleep/main/deep_sleep_example_main.c @@ -45,7 +45,7 @@ _Static_assert(ULP_DATA_OFFSET < CONFIG_ESP32_ULP_COPROC_RESERVE_MEM/4 - 6, * The program monitors on-chip temperature sensor and wakes up the SoC when * the temperature goes lower or higher than certain thresholds. */ -static void start_ulp_temperature_monitoring(); +static void start_ulp_temperature_monitoring(void); /** * @brief Utility function which reads data written by ULP program @@ -76,7 +76,7 @@ static inline void ulp_data_write(size_t offset, uint16_t value) static void calibrate_touch_pad(touch_pad_t pad); #endif -void app_main() +void app_main(void) { struct timeval now; gettimeofday(&now, NULL); @@ -210,7 +210,7 @@ static void calibrate_touch_pad(touch_pad_t pad) #endif // CONFIG_ENABLE_TOUCH_WAKEUP #ifdef CONFIG_ENABLE_ULP_TEMPERATURE_WAKEUP -static void start_ulp_temperature_monitoring() +static void start_ulp_temperature_monitoring(void) { /* * This ULP program monitors the on-chip temperature sensor and wakes the chip up when diff --git a/examples/system/esp_timer/main/esp_timer_example_main.c b/examples/system/esp_timer/main/esp_timer_example_main.c index ab6a697c2b..9750423991 100644 --- a/examples/system/esp_timer/main/esp_timer_example_main.c +++ b/examples/system/esp_timer/main/esp_timer_example_main.c @@ -20,7 +20,7 @@ static void oneshot_timer_callback(void* arg); static const char* TAG = "example"; -void app_main() +void app_main(void) { /* Create two timers: * 1. a periodic timer which will run every 0.5s, and print a message diff --git a/examples/system/freertos/real_time_stats/main/main.c b/examples/system/freertos/real_time_stats/main/main.c index 96a199bfec..9b3b9ce87d 100644 --- a/examples/system/freertos/real_time_stats/main/main.c +++ b/examples/system/freertos/real_time_stats/main/main.c @@ -165,7 +165,7 @@ static void stats_task(void *arg) } } -void app_main() +void app_main(void) { //Allow other core to finish initialization vTaskDelay(pdMS_TO_TICKS(100)); diff --git a/examples/system/gcov/main/gcov_example.c b/examples/system/gcov/main/gcov_example.c index e6d7457680..5ded23b0d1 100644 --- a/examples/system/gcov/main/gcov_example.c +++ b/examples/system/gcov/main/gcov_example.c @@ -52,7 +52,7 @@ static void blink_task(void *pvParameter) } } -void app_main() +void app_main(void) { xTaskCreate(&blink_task, "blink_task", configMINIMAL_STACK_SIZE, NULL, 5, NULL); } diff --git a/examples/system/himem/main/himem_test_main.c b/examples/system/himem/main/himem_test_main.c index 5a83482cc5..955046b2de 100644 --- a/examples/system/himem/main/himem_test_main.c +++ b/examples/system/himem/main/himem_test_main.c @@ -87,7 +87,7 @@ static bool test_region(int check_size, int seed) } -void app_main() +void app_main(void) { size_t memcnt=esp_himem_get_phys_size(); size_t memfree=esp_himem_get_free_size(); diff --git a/examples/system/light_sleep/main/light_sleep_example_main.c b/examples/system/light_sleep/main/light_sleep_example_main.c index 36003c68ff..8fb02b47bb 100644 --- a/examples/system/light_sleep/main/light_sleep_example_main.c +++ b/examples/system/light_sleep/main/light_sleep_example_main.c @@ -27,7 +27,7 @@ /* "Boot" button on GPIO0 is active low */ #define BUTTON_WAKEUP_LEVEL_DEFAULT 0 -void app_main() +void app_main(void) { /* Configure the button GPIO as input, enable wakeup */ const int button_gpio_num = BUTTON_GPIO_NUM_DEFAULT; diff --git a/examples/system/network_tests/main/net_suite.c b/examples/system/network_tests/main/net_suite.c index 2fae24835b..9b9dfe2d02 100644 --- a/examples/system/network_tests/main/net_suite.c +++ b/examples/system/network_tests/main/net_suite.c @@ -130,7 +130,7 @@ static size_t process_line(char* line, char* packet) return count; } -void app_main() +void app_main(void) { char packet[128]; diff --git a/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c b/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c index c2b01e1444..0387e3e681 100644 --- a/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c +++ b/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c @@ -103,7 +103,7 @@ ota_end: } } -void app_main() +void app_main(void) { // Initialize NVS. esp_err_t err = nvs_flash_init(); diff --git a/examples/system/ota/native_ota_example/main/native_ota_example.c b/examples/system/ota/native_ota_example/main/native_ota_example.c index 6387438929..fc42b7f3b0 100644 --- a/examples/system/ota/native_ota_example/main/native_ota_example.c +++ b/examples/system/ota/native_ota_example/main/native_ota_example.c @@ -37,7 +37,7 @@ static void http_cleanup(esp_http_client_handle_t client) esp_http_client_cleanup(client); } -static void __attribute__((noreturn)) task_fatal_error() +static void __attribute__((noreturn)) task_fatal_error(void) { ESP_LOGE(TAG, "Exiting task due to fatal error..."); (void)vTaskDelete(NULL); @@ -219,7 +219,7 @@ static bool diagnostic(void) return diagnostic_is_ok; } -void app_main() +void app_main(void) { uint8_t sha_256[HASH_LEN] = { 0 }; esp_partition_t partition; diff --git a/examples/system/ota/otatool/main/otatool_main.c b/examples/system/ota/otatool/main/otatool_main.c index 50ea3f2ec4..86b7a82042 100644 --- a/examples/system/ota/otatool/main/otatool_main.c +++ b/examples/system/ota/otatool/main/otatool_main.c @@ -13,7 +13,7 @@ static const char *TAG = "example"; -void app_main() +void app_main(void) { ESP_LOGI(TAG, "OTA Tool Example"); diff --git a/examples/system/ota/simple_ota_example/main/simple_ota_example.c b/examples/system/ota/simple_ota_example/main/simple_ota_example.c index 9d7c44e3a1..9d0187f3bc 100644 --- a/examples/system/ota/simple_ota_example/main/simple_ota_example.c +++ b/examples/system/ota/simple_ota_example/main/simple_ota_example.c @@ -95,7 +95,7 @@ void simple_ota_example_task(void *pvParameter) } } -void app_main() +void app_main(void) { // Initialize NVS. esp_err_t err = nvs_flash_init(); diff --git a/examples/system/select/main/select_example.c b/examples/system/select/main/select_example.c index 57daf8fd83..9629024295 100644 --- a/examples/system/select/main/select_example.c +++ b/examples/system/select/main/select_example.c @@ -27,13 +27,13 @@ static const char* TAG = "uart_select_example"; static int uart_fd = -1; static int socket_fd = -1; -static void socket_deinit() +static void socket_deinit(void) { close(socket_fd); socket_fd = -1; } -static void socket_init() +static void socket_init(void) { const struct addrinfo hints = { .ai_family = AF_INET, @@ -81,7 +81,7 @@ static void socket_init() freeaddrinfo(res); } -static void uart1_deinit() +static void uart1_deinit(void) { close(uart_fd); uart_fd = -1; @@ -89,7 +89,7 @@ static void uart1_deinit() UART1.conf0.loopback = 0; } -static void uart1_init() +static void uart1_init(void) { uart_config_t uart_config = { .baud_rate = 115200, @@ -198,7 +198,7 @@ static void select_task(void *param) vTaskDelete(NULL); } -void app_main() +void app_main(void) { xTaskCreate(uart1_write_task, "uart1_write_task", 4*1024, NULL, 5, NULL); xTaskCreate(socket_write_task, "socket_write_task", 4*1024, NULL, 5, NULL); diff --git a/examples/system/sysview_tracing/main/sysview_tracing.c b/examples/system/sysview_tracing/main/sysview_tracing.c index c422d9e46a..3436b4cbcb 100644 --- a/examples/system/sysview_tracing/main/sysview_tracing.c +++ b/examples/system/sysview_tracing/main/sysview_tracing.c @@ -181,7 +181,7 @@ static void example_task(void *p) } } -void app_main() +void app_main(void) { static example_event_data_t event_data[portNUM_PROCESSORS] = { { diff --git a/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c b/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c index d34c93de61..9d38fcf70e 100644 --- a/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c +++ b/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c @@ -57,7 +57,7 @@ static void alloc_task(void *p) while(1); } -void app_main() +void app_main(void) { // redirect log messages to the host using SystemView tracing module esp_log_set_vprintf(&esp_sysview_vprintf); diff --git a/examples/system/task_watchdog/main/task_watchdog_example_main.c b/examples/system/task_watchdog/main/task_watchdog_example_main.c index a5eed91ceb..89bce16f00 100644 --- a/examples/system/task_watchdog/main/task_watchdog_example_main.c +++ b/examples/system/task_watchdog/main/task_watchdog_example_main.c @@ -42,7 +42,7 @@ void reset_task(void *arg) } } -void app_main() +void app_main(void) { printf("Initialize TWDT\n"); //Initialize or reinitialize TWDT diff --git a/examples/system/ulp/main/ulp_example_main.c b/examples/system/ulp/main/ulp_example_main.c index 6682294d59..fa6e1eead2 100644 --- a/examples/system/ulp/main/ulp_example_main.c +++ b/examples/system/ulp/main/ulp_example_main.c @@ -22,10 +22,10 @@ extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start"); extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end"); -static void init_ulp_program(); -static void update_pulse_count(); +static void init_ulp_program(void); +static void update_pulse_count(void); -void app_main() +void app_main(void) { esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); if (cause != ESP_SLEEP_WAKEUP_ULP) { @@ -41,7 +41,7 @@ void app_main() esp_deep_sleep_start(); } -static void init_ulp_program() +static void init_ulp_program(void) { esp_err_t err = ulp_load_binary(0, ulp_main_bin_start, (ulp_main_bin_end - ulp_main_bin_start) / sizeof(uint32_t)); @@ -91,7 +91,7 @@ static void init_ulp_program() ESP_ERROR_CHECK(err); } -static void update_pulse_count() +static void update_pulse_count(void) { const char* namespace = "plusecnt"; const char* count_key = "count"; diff --git a/examples/system/ulp_adc/main/ulp_adc_example_main.c b/examples/system/ulp_adc/main/ulp_adc_example_main.c index 80f9fc1ebf..c7be925ca5 100644 --- a/examples/system/ulp_adc/main/ulp_adc_example_main.c +++ b/examples/system/ulp_adc/main/ulp_adc_example_main.c @@ -27,14 +27,14 @@ extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end"); /* This function is called once after power-on reset, to load ULP program into * RTC memory and configure the ADC. */ -static void init_ulp_program(); +static void init_ulp_program(void); /* This function is called every time before going into deep sleep. * It starts the ULP program and resets measurement counter. */ -static void start_ulp_program(); +static void start_ulp_program(void); -void app_main() +void app_main(void) { esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); if (cause != ESP_SLEEP_WAKEUP_ULP) { @@ -54,7 +54,7 @@ void app_main() esp_deep_sleep_start(); } -static void init_ulp_program() +static void init_ulp_program(void) { esp_err_t err = ulp_load_binary(0, ulp_main_bin_start, (ulp_main_bin_end - ulp_main_bin_start) / sizeof(uint32_t)); @@ -83,7 +83,7 @@ static void init_ulp_program() esp_deep_sleep_disable_rom_logging(); // suppress boot messages } -static void start_ulp_program() +static void start_ulp_program(void) { /* Reset sample counter */ ulp_sample_counter = 0; diff --git a/examples/system/unit_test/test/main/example_unit_test_test.c b/examples/system/unit_test/test/main/example_unit_test_test.c index a634ce8da9..92f2f038a9 100644 --- a/examples/system/unit_test/test/main/example_unit_test_test.c +++ b/examples/system/unit_test/test/main/example_unit_test_test.c @@ -13,7 +13,7 @@ static void print_banner(const char* text); -void app_main() +void app_main(void) { /* These are the different ways of running registered tests. * In practice, only one of them is usually needed. diff --git a/examples/wifi/espnow/main/espnow_example_main.c b/examples/wifi/espnow/main/espnow_example_main.c index 4d76a5beae..fbfde5780c 100644 --- a/examples/wifi/espnow/main/espnow_example_main.c +++ b/examples/wifi/espnow/main/espnow_example_main.c @@ -361,7 +361,7 @@ static void example_espnow_deinit(example_espnow_send_param_t *send_param) esp_now_deinit(); } -void app_main() +void app_main(void) { // Initialize NVS esp_err_t ret = nvs_flash_init(); diff --git a/examples/wifi/getting_started/softAP/main/softap_example_main.c b/examples/wifi/getting_started/softAP/main/softap_example_main.c index 0102895545..624e020ed6 100644 --- a/examples/wifi/getting_started/softAP/main/softap_example_main.c +++ b/examples/wifi/getting_started/softAP/main/softap_example_main.c @@ -43,7 +43,7 @@ static void wifi_event_handler(void* arg, esp_event_base_t event_base, } } -void wifi_init_softap() +void wifi_init_softap(void) { tcpip_adapter_init(); ESP_ERROR_CHECK(esp_event_loop_create_default()); @@ -74,7 +74,7 @@ void wifi_init_softap() EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS); } -void app_main() +void app_main(void) { //Initialize NVS esp_err_t ret = nvs_flash_init(); diff --git a/examples/wifi/getting_started/station/main/station_example_main.c b/examples/wifi/getting_started/station/main/station_example_main.c index ae6101f2d4..869b614ce5 100644 --- a/examples/wifi/getting_started/station/main/station_example_main.c +++ b/examples/wifi/getting_started/station/main/station_example_main.c @@ -61,7 +61,7 @@ static void event_handler(void* arg, esp_event_base_t event_base, } } -void wifi_init_sta() +void wifi_init_sta(void) { s_wifi_event_group = xEventGroupCreate(); @@ -90,7 +90,7 @@ void wifi_init_sta() EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS); } -void app_main() +void app_main(void) { //Initialize NVS esp_err_t ret = nvs_flash_init(); diff --git a/examples/wifi/iperf/main/cmd_wifi.c b/examples/wifi/iperf/main/cmd_wifi.c index a6fbdaa162..8bd3819a18 100644 --- a/examples/wifi/iperf/main/cmd_wifi.c +++ b/examples/wifi/iperf/main/cmd_wifi.c @@ -369,7 +369,7 @@ static int wifi_cmd_iperf(int argc, char** argv) return 0; } -void register_wifi() +void register_wifi(void) { sta_args.ssid = arg_str1(NULL, NULL, "", "SSID of AP"); sta_args.password = arg_str0(NULL, NULL, "", "password of AP"); diff --git a/examples/wifi/iperf/main/iperf_example_main.c b/examples/wifi/iperf/main/iperf_example_main.c index 797d749619..d3e2eb7c93 100644 --- a/examples/wifi/iperf/main/iperf_example_main.c +++ b/examples/wifi/iperf/main/iperf_example_main.c @@ -26,7 +26,7 @@ #define WIFI_CONNECTED_BIT BIT0 -static void initialize_console() +static void initialize_console(void) { /* Disable buffering on stdin */ setvbuf(stdin, NULL, _IONBF, 0); diff --git a/examples/wifi/power_save/main/power_save.c b/examples/wifi/power_save/main/power_save.c index 04f60cb66d..c24dfdaa56 100644 --- a/examples/wifi/power_save/main/power_save.c +++ b/examples/wifi/power_save/main/power_save.c @@ -79,7 +79,7 @@ static void wifi_power_save(void) esp_wifi_set_ps(DEFAULT_PS_MODE); } -void app_main() +void app_main(void) { // Initialize NVS esp_err_t ret = nvs_flash_init(); diff --git a/examples/wifi/scan/main/scan.c b/examples/wifi/scan/main/scan.c index f5b0d29fd5..0f54d8e3eb 100644 --- a/examples/wifi/scan/main/scan.c +++ b/examples/wifi/scan/main/scan.c @@ -109,7 +109,7 @@ static void wifi_scan(void) ESP_ERROR_CHECK(esp_wifi_start()); } -void app_main() +void app_main(void) { // Initialize NVS esp_err_t ret = nvs_flash_init(); diff --git a/examples/wifi/simple_sniffer/main/cmd_sniffer.c b/examples/wifi/simple_sniffer/main/cmd_sniffer.c index e41f9941fc..579a1c0697 100644 --- a/examples/wifi/simple_sniffer/main/cmd_sniffer.c +++ b/examples/wifi/simple_sniffer/main/cmd_sniffer.c @@ -80,7 +80,7 @@ static uint32_t hash_func(const char *str, uint32_t max_num) return ret % max_num; } -static void create_wifi_filter_hashtable() +static void create_wifi_filter_hashtable(void) { char *wifi_filter_keys[SNIFFER_WLAN_FILTER_MAX] = {"mgmt", "data", "ctrl", "misc", "mpdu", "ampdu"}; uint32_t wifi_filter_values[SNIFFER_WLAN_FILTER_MAX] = {WIFI_PROMIS_FILTER_MASK_MGMT, WIFI_PROMIS_FILTER_MASK_DATA, @@ -372,7 +372,7 @@ static int do_sniffer_cmd(int argc, char **argv) return 0; } -void register_sniffer() +void register_sniffer(void) { sniffer_args.file = arg_str0("f", "file", "", "name of the file storing the packets in pcap format"); diff --git a/examples/wifi/simple_sniffer/main/cmd_sniffer.h b/examples/wifi/simple_sniffer/main/cmd_sniffer.h index c98f857d63..10d6f21f43 100644 --- a/examples/wifi/simple_sniffer/main/cmd_sniffer.h +++ b/examples/wifi/simple_sniffer/main/cmd_sniffer.h @@ -34,7 +34,7 @@ typedef enum { SNIFFER_WLAN_FILTER_MAX } sniffer_wlan_filter_t; -void register_sniffer(); +void register_sniffer(void); #ifdef __cplusplus } diff --git a/examples/wifi/simple_sniffer/main/simple_sniffer_example_main.c b/examples/wifi/simple_sniffer/main/simple_sniffer_example_main.c index 1b664b0396..e1a78a42ce 100644 --- a/examples/wifi/simple_sniffer/main/simple_sniffer_example_main.c +++ b/examples/wifi/simple_sniffer/main/simple_sniffer_example_main.c @@ -36,7 +36,7 @@ static const char *TAG = "example"; #if CONFIG_SNIFFER_STORE_HISTORY /* Initialize filesystem for command history store */ -static void initialize_filesystem() +static void initialize_filesystem(void) { static wl_handle_t wl_handle; const esp_vfs_fat_mount_config_t mount_config = { @@ -51,7 +51,7 @@ static void initialize_filesystem() } #endif -static void initialize_nvs() +static void initialize_nvs(void) { esp_err_t err = nvs_flash_init(); if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { @@ -62,7 +62,7 @@ static void initialize_nvs() } /* Initialize wifi with tcp/ip adapter */ -static void initialize_wifi() +static void initialize_wifi(void) { tcpip_adapter_init(); ESP_ERROR_CHECK(esp_event_loop_create_default()); @@ -73,7 +73,7 @@ static void initialize_wifi() } /* Initialize console component */ -static void initialize_console() +static void initialize_console(void) { /* Disable buffering on stdin */ setvbuf(stdin, NULL, _IONBF, 0); @@ -172,7 +172,7 @@ static int mount(int argc, char **argv) return 0; } -static void register_mount() +static void register_mount(void) { mount_args.device = arg_str1(NULL, NULL, "", "choose a proper device to mount/unmount"); mount_args.end = arg_end(1); @@ -204,7 +204,7 @@ static int unmount(int argc, char **argv) return 0; } -static void register_unmount() +static void register_unmount(void) { mount_args.device = arg_str1(NULL, NULL, "", "choose a proper device to mount/unmount"); mount_args.end = arg_end(1); diff --git a/examples/wifi/smart_config/main/smartconfig_main.c b/examples/wifi/smart_config/main/smartconfig_main.c index 0819f256da..65e7c50331 100644 --- a/examples/wifi/smart_config/main/smartconfig_main.c +++ b/examples/wifi/smart_config/main/smartconfig_main.c @@ -112,7 +112,7 @@ static void smartconfig_example_task(void * parm) } } -void app_main() +void app_main(void) { ESP_ERROR_CHECK( nvs_flash_init() ); initialise_wifi(); diff --git a/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c b/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c index 232065c4b5..1cd210c66f 100644 --- a/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c +++ b/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c @@ -143,7 +143,7 @@ static void wpa2_enterprise_example_task(void *pvParameters) } } -void app_main() +void app_main(void) { ESP_ERROR_CHECK( nvs_flash_init() ); initialise_wifi(); diff --git a/examples/wifi/wps/main/wps.c b/examples/wifi/wps/main/wps.c index 5ac103b7f1..4e1af5d03d 100644 --- a/examples/wifi/wps/main/wps.c +++ b/examples/wifi/wps/main/wps.c @@ -115,7 +115,7 @@ static void start_wps(void) ESP_ERROR_CHECK(esp_wifi_wps_start(0)); } -void app_main() +void app_main(void) { /* Initialize NVS — it is used to store PHY calibration data */ esp_err_t ret = nvs_flash_init(); diff --git a/tools/esp_app_trace/test/sysview/blink.c b/tools/esp_app_trace/test/sysview/blink.c index baa345be47..66fb4d31f0 100644 --- a/tools/esp_app_trace/test/sysview/blink.c +++ b/tools/esp_app_trace/test/sysview/blink.c @@ -82,7 +82,7 @@ void blink_task(void *pvParameter) } } -void app_main() +void app_main(void) { xTaskCreatePinnedToCore(&blink_task, "blink_task", 2048, NULL, 5, NULL, 0); } diff --git a/tools/kconfig/nconf.gui.c b/tools/kconfig/nconf.gui.c index 8275f0e551..4c964e3776 100644 --- a/tools/kconfig/nconf.gui.c +++ b/tools/kconfig/nconf.gui.c @@ -129,7 +129,7 @@ static void no_colors_theme(void) mkattrn(FUNCTION_TEXT, A_REVERSE); } -void set_colors() +void set_colors(void) { start_color(); use_default_colors(); diff --git a/tools/unit-test-app/components/test_utils/include/test_utils.h b/tools/unit-test-app/components/test_utils/include/test_utils.h index eb95f34f7f..f9901bb9ca 100644 --- a/tools/unit-test-app/components/test_utils/include/test_utils.h +++ b/tools/unit-test-app/components/test_utils/include/test_utils.h @@ -54,7 +54,7 @@ /* Return the 'flash_test' custom data partition (type 0x55) defined in the custom partition table. */ -const esp_partition_t *get_test_data_partition(); +const esp_partition_t *get_test_data_partition(void); /** * @brief Initialize reference clock @@ -62,26 +62,26 @@ const esp_partition_t *get_test_data_partition(); * Reference clock provides timestamps at constant 1 MHz frequency, even when * the APB frequency is changing. */ -void ref_clock_init(); +void ref_clock_init(void); /** * @brief Deinitialize reference clock */ -void ref_clock_deinit(); +void ref_clock_deinit(void); /** * @brief Get reference clock timestamp * @return number of microseconds since the reference clock was initialized */ -uint64_t ref_clock_get(); +uint64_t ref_clock_get(void); /** * @brief Entry point of the test application * * Starts Unity test runner in a separate task and returns. */ -void test_main(); +void test_main(void); /** * @brief Reset automatic leak checking which happens in unit tests. diff --git a/tools/unit-test-app/components/test_utils/ref_clock.c b/tools/unit-test-app/components/test_utils/ref_clock.c index c66ff28b9e..afafd42b53 100644 --- a/tools/unit-test-app/components/test_utils/ref_clock.c +++ b/tools/unit-test-app/components/test_utils/ref_clock.c @@ -54,7 +54,7 @@ static intr_handle_t s_intr_handle; static portMUX_TYPE s_lock = portMUX_INITIALIZER_UNLOCKED; static volatile uint32_t s_milliseconds; -void ref_clock_init() +void ref_clock_init(void) { assert(s_intr_handle == NULL && "already initialized"); @@ -134,7 +134,7 @@ static void IRAM_ATTR pcnt_isr(void* arg) portEXIT_CRITICAL_ISR(&s_lock); } -void ref_clock_deinit() +void ref_clock_deinit(void) { assert(s_intr_handle && "deinit called without init"); @@ -153,7 +153,7 @@ void ref_clock_deinit() periph_module_disable(PERIPH_PCNT_MODULE); } -uint64_t ref_clock_get() +uint64_t ref_clock_get(void) { portENTER_CRITICAL(&s_lock); uint32_t microseconds = PCNT.cnt_unit[REF_CLOCK_PCNT_UNIT].cnt_val; diff --git a/tools/unit-test-app/components/test_utils/test_runner.c b/tools/unit-test-app/components/test_utils/test_runner.c index 33247904c3..1f00a0168b 100644 --- a/tools/unit-test-app/components/test_utils/test_runner.c +++ b/tools/unit-test-app/components/test_utils/test_runner.c @@ -37,7 +37,7 @@ static void unity_task(void *pvParameters) unity_run_menu(); /* Doesn't return */ } -void test_main() +void test_main(void) { // Note: if unpinning this task, change the way run times are calculated in // unity_port_esp32.c @@ -95,7 +95,7 @@ static void check_leak(size_t before_free, size_t after_free, const char *type) TEST_ASSERT_MESSAGE(leaked <= critical_leak_threshold, "The test leaked too much memory"); } -static bool leak_check_required() +static bool leak_check_required(void) { warn_leak_threshold = test_utils_get_leak_level(TYPE_LEAK_WARNING, COMP_LEAK_ALL); critical_leak_threshold = test_utils_get_leak_level(TYPE_LEAK_CRITICAL, COMP_LEAK_ALL); diff --git a/tools/unit-test-app/components/test_utils/test_utils.c b/tools/unit-test-app/components/test_utils/test_utils.c index fc16db9f03..9216a70fd8 100644 --- a/tools/unit-test-app/components/test_utils/test_utils.c +++ b/tools/unit-test-app/components/test_utils/test_utils.c @@ -22,7 +22,7 @@ #include "tcpip_adapter.h" #include "lwip/sockets.h" -const esp_partition_t *get_test_data_partition() +const esp_partition_t *get_test_data_partition(void) { /* This finds "flash_test" partition defined in partition_table_unit_test_app.csv */ const esp_partition_t *result = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, @@ -31,7 +31,7 @@ const esp_partition_t *get_test_data_partition() return result; } -void test_case_uses_tcpip() +void test_case_uses_tcpip(void) { // Can be called more than once, does nothing on subsequent calls tcpip_adapter_init(); diff --git a/tools/unit-test-app/main/app_main.c b/tools/unit-test-app/main/app_main.c index 4385b3b0eb..f9df657da2 100644 --- a/tools/unit-test-app/main/app_main.c +++ b/tools/unit-test-app/main/app_main.c @@ -1,6 +1,6 @@ #include "test_utils.h" -void app_main() +void app_main(void) { test_main(); } diff --git a/tools/windows/tool_setup/cmdlinerunner/cmdlinerunner.c b/tools/windows/tool_setup/cmdlinerunner/cmdlinerunner.c index 0688ea4302..c5ee95e3ed 100644 --- a/tools/windows/tool_setup/cmdlinerunner/cmdlinerunner.c +++ b/tools/windows/tool_setup/cmdlinerunner/cmdlinerunner.c @@ -35,7 +35,7 @@ struct proc_instance_s { }; #ifdef WITH_DEBUG -static void print_last_error() +static void print_last_error(void) { DWORD dw; TCHAR errmsg[LINESIZE]; @@ -51,7 +51,7 @@ static void print_last_error() #define PRINT_LAST_ERROR() #endif -static proc_instance_t *proc_instance_allocate() +static proc_instance_t *proc_instance_allocate(void) { return (proc_instance_t*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(proc_instance_t)); } From 74a459dd3ddd8c203835d2a78cd07ff6d31dee69 Mon Sep 17 00:00:00 2001 From: Michael Zimmermann Date: Fri, 11 Jan 2019 09:43:11 +0100 Subject: [PATCH 387/486] make code conform to Wstrict-prototypes Merges https://github.com/espressif/esp-idf/pull/2937 --- components/bootloader_support/src/flash_qio_mode.c | 2 +- components/esp_common/include/esp_freertos_hooks.h | 4 ++-- components/vfs/include/esp_vfs.h | 4 ++-- components/xtensa/include/xtensa/xtruntime.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/bootloader_support/src/flash_qio_mode.c b/components/bootloader_support/src/flash_qio_mode.c index 06a8fcada4..adf536893d 100644 --- a/components/bootloader_support/src/flash_qio_mode.c +++ b/components/bootloader_support/src/flash_qio_mode.c @@ -39,7 +39,7 @@ static const char *TAG = "qio_mode"; -typedef unsigned (*read_status_fn_t)(); +typedef unsigned (*read_status_fn_t)(void); typedef void (*write_status_fn_t)(unsigned); typedef struct __attribute__((packed)) { diff --git a/components/esp_common/include/esp_freertos_hooks.h b/components/esp_common/include/esp_freertos_hooks.h index 5f24bc35a6..47db07ce9d 100644 --- a/components/esp_common/include/esp_freertos_hooks.h +++ b/components/esp_common/include/esp_freertos_hooks.h @@ -26,8 +26,8 @@ extern "C" /* Definitions for the tickhook and idlehook callbacks */ -typedef bool (*esp_freertos_idle_cb_t)(); -typedef void (*esp_freertos_tick_cb_t)(); +typedef bool (*esp_freertos_idle_cb_t)(void); +typedef void (*esp_freertos_tick_cb_t)(void); /** * @brief Register a callback to be called from the specified core's idle hook. diff --git a/components/vfs/include/esp_vfs.h b/components/vfs/include/esp_vfs.h index 4d9396c1c4..e4eafb417c 100644 --- a/components/vfs/include/esp_vfs.h +++ b/components/vfs/include/esp_vfs.h @@ -244,9 +244,9 @@ typedef struct /** stop_socket_select which can be called from ISR; set only for the socket driver */ void (*stop_socket_select_isr)(void *sem, BaseType_t *woken); /** end_select is called to stop the I/O multiplexing and deinitialize the environment created by start_select for the given VFS */ - void* (*get_socket_select_semaphore)(); + void* (*get_socket_select_semaphore)(void); /** get_socket_select_semaphore returns semaphore allocated in the socket driver; set only for the socket driver */ - void (*end_select)(); + void (*end_select)(void); } esp_vfs_t; diff --git a/components/xtensa/include/xtensa/xtruntime.h b/components/xtensa/include/xtensa/xtruntime.h index 9dae1f4b23..f4e1184ed8 100644 --- a/components/xtensa/include/xtensa/xtruntime.h +++ b/components/xtensa/include/xtensa/xtruntime.h @@ -58,7 +58,7 @@ extern "C" { #ifdef __cplusplus typedef void (_xtos_handler_func)(...); #else -typedef void (_xtos_handler_func)(); +typedef void (_xtos_handler_func)(void); #endif typedef _xtos_handler_func *_xtos_handler; From e8191912c8348464f173423502c17410f2ad4fb7 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 19 Mar 2019 16:02:35 +0800 Subject: [PATCH 388/486] Add -Wstrict-prototypes check in CI --- tools/ci/build_examples.sh | 2 +- tools/ci/build_examples_cmake.sh | 2 +- tools/ci/config/build.yml | 23 ++++++++++++++++------- tools/ci/configure_ci_environment.sh | 5 ++++- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/tools/ci/build_examples.sh b/tools/ci/build_examples.sh index c300452e75..7393cb3024 100755 --- a/tools/ci/build_examples.sh +++ b/tools/ci/build_examples.sh @@ -116,7 +116,7 @@ build_example () { pushd "example_builds/${ID}/${EXAMPLE_DIR_REL}" # be stricter in the CI build than the default IDF settings export EXTRA_CFLAGS=${PEDANTIC_CFLAGS} - export EXTRA_CXXFLAGS=${EXTRA_CFLAGS} + export EXTRA_CXXFLAGS=${PEDANTIC_CXXFLAGS} # sdkconfig files are normally not checked into git, but may be present when # a developer runs this script locally diff --git a/tools/ci/build_examples_cmake.sh b/tools/ci/build_examples_cmake.sh index 6ec906b0dc..da15bae725 100755 --- a/tools/ci/build_examples_cmake.sh +++ b/tools/ci/build_examples_cmake.sh @@ -111,7 +111,7 @@ build_example () { pushd "example_builds/${IDF_TARGET}/${ID}/${EXAMPLE_NAME}" # be stricter in the CI build than the default IDF settings export EXTRA_CFLAGS=${PEDANTIC_CFLAGS} - export EXTRA_CXXFLAGS=${EXTRA_CFLAGS} + export EXTRA_CXXFLAGS=${PEDANTIC_CXXFLAGS} # sdkconfig files are normally not checked into git, but may be present when # a developer runs this script locally diff --git a/tools/ci/config/build.yml b/tools/ci/config/build.yml index c5dab206d9..43bf408149 100644 --- a/tools/ci/config/build.yml +++ b/tools/ci/config/build.yml @@ -38,11 +38,13 @@ build_template_app: # Set the variable for 'esp-idf-template' testing - ESP_IDF_TEMPLATE_GIT=${ESP_IDF_TEMPLATE_GIT:-"https://github.com/espressif/esp-idf-template.git"} - git clone ${ESP_IDF_TEMPLATE_GIT} + # Try to use the same branch name for esp-idf-template that we're + # using on esp-idf. If it doesn't exist then just stick to the default branch - python $CHECKOUT_REF_SCRIPT esp-idf-template esp-idf-template - cd esp-idf-template - # Try to use the same branch name for esp-idf-template that we're - # using on esp-idf. If it doesn't exist then just stick to the default - # branch + - export PATH="$IDF_PATH/tools:$PATH" + - export EXTRA_CFLAGS=${PEDANTIC_CFLAGS} + - export EXTRA_CXXFLAGS=${PEDANTIC_CXXFLAGS} - make defconfig # Test debug build (default) - make all V=1 @@ -51,10 +53,17 @@ build_template_app: - sed -i.bak -e's/CONFIG_OPTIMIZATION_LEVEL_DEBUG\=y/CONFIG_OPTIMIZATION_LEVEL_RELEASE=y/' sdkconfig - make all V=1 # Check if there are any stray printf/ets_printf references in WiFi libs - - cd ../components/esp_wifi/lib_esp32 + - pushd ../components/esp_wifi/lib_esp32 - test $(xtensa-esp32-elf-nm *.a | grep -w printf | wc -l) -eq 0 - test $(xtensa-esp32-elf-nm *.a | grep -w ets_printf | wc -l) -eq 0 - + - popd + # Repeat the build using CMake + - rm -rf build sdkconfig + # Debug build + - idf.py build + # Release build + - sed -i.bak -e's/CONFIG_OPTIMIZATION_LEVEL_DEBUG\=y/CONFIG_OPTIMIZATION_LEVEL_RELEASE=y/' sdkconfig + - idf.py build build_ssc: extends: .build_template @@ -81,7 +90,7 @@ build_esp_idf_tests_make: extends: .build_esp_idf_unit_test_template script: - export EXTRA_CFLAGS=${PEDANTIC_CFLAGS} - - export EXTRA_CXXFLAGS=${EXTRA_CFLAGS} + - export EXTRA_CXXFLAGS=${PEDANTIC_CXXFLAGS} - cd $CI_PROJECT_DIR/tools/unit-test-app - MAKEFLAGS= make help # make sure kconfig tools are built in single process - make ut-clean-all-configs @@ -97,7 +106,7 @@ build_esp_idf_tests_cmake: script: - export PATH="$IDF_PATH/tools:$PATH" - export EXTRA_CFLAGS=${PEDANTIC_CFLAGS} - - export EXTRA_CXXFLAGS=${EXTRA_CFLAGS} + - export EXTRA_CXXFLAGS=${PEDANTIC_CXXFLAGS} - cd $CI_PROJECT_DIR/tools/unit-test-app - idf.py ut-clean-all-configs - idf.py ut-build-all-configs diff --git a/tools/ci/configure_ci_environment.sh b/tools/ci/configure_ci_environment.sh index 9a664c1ce9..d16e80500e 100644 --- a/tools/ci/configure_ci_environment.sh +++ b/tools/ci/configure_ci_environment.sh @@ -15,4 +15,7 @@ DEBUG_SHELL=${DEBUG_SHELL:-"0"} # Compiler flags to thoroughly check the IDF code in some CI jobs # (Depends on default options '-Wno-error=XXX' used in the IDF build system) -export PEDANTIC_CFLAGS="-DIDF_CI_BUILD -Werror -Werror=deprecated-declarations -Werror=unused-variable -Werror=unused-but-set-variable -Werror=unused-function" + +PEDANTIC_FLAGS="-DIDF_CI_BUILD -Werror -Werror=deprecated-declarations -Werror=unused-variable -Werror=unused-but-set-variable -Werror=unused-function" +export PEDANTIC_CFLAGS="${PEDANTIC_FLAGS} -Wstrict-prototypes" +export PEDANTIC_CXXFLAGS="${PEDANTIC_FLAGS}" From d4c098f5a93998e8fd0f46286f714c11a07929ee Mon Sep 17 00:00:00 2001 From: Michael Zimmermann Date: Fri, 11 Jan 2019 09:42:36 +0100 Subject: [PATCH 389/486] brownout: fix rtc_brownout_isr_handler signature Merges https://github.com/espressif/esp-idf/pull/2937 --- components/esp32/brownout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp32/brownout.c b/components/esp32/brownout.c index 89f821c503..c3db402717 100644 --- a/components/esp32/brownout.c +++ b/components/esp32/brownout.c @@ -31,7 +31,7 @@ #define BROWNOUT_DET_LVL 0 #endif //CONFIG_ESP32_BROWNOUT_DET_LVL -static void rtc_brownout_isr_handler(void) +static void rtc_brownout_isr_handler(void *arg) { /* Normally RTC ISR clears the interrupt flag after the application-supplied * handler returns. Since restart is called here, the flag needs to be From c2764f6fe85681cfaf5dbbe168295284f09c09cd Mon Sep 17 00:00:00 2001 From: Michael Zimmermann Date: Fri, 11 Jan 2019 09:40:34 +0100 Subject: [PATCH 390/486] mdns: mdns_service_remove_all doesn't take an argument Merges https://github.com/espressif/esp-idf/pull/2937 --- components/mdns/mdns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 7331353d26..095651634e 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -4228,7 +4228,7 @@ void mdns_free(void) if (!_mdns_server) { return; } - mdns_service_remove_all(_mdns_server); + mdns_service_remove_all(); _mdns_service_task_stop(); for (i=0; i Date: Wed, 31 Jul 2019 11:31:59 +0700 Subject: [PATCH 391/486] NimBLE: Update submodule to fix -Wstrict-prototypes warnings --- components/bt/host/nimble/nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 7600a6f603..4839d84f61 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 7600a6f60308c77fec755a024d51ab2fb7d11553 +Subproject commit 4839d84f61296b7d7479350ebb92908b0fdb1329 From 75c0066f93d054cdd16000c428aded6e119c78d7 Mon Sep 17 00:00:00 2001 From: Anton Maklakov Date: Tue, 30 Jul 2019 11:53:48 +0700 Subject: [PATCH 392/486] Fix remaining -Wstrict-prototypes warnings --- components/app_trace/app_trace.c | 4 ++-- components/app_update/test/test_switch_ota.c | 14 +++++++------- .../driver/test/param_test/include/param_test.h | 4 ++-- components/fatfs/vfs/vfs_fat_sdmmc.c | 2 +- .../include/freertos/deprecated_definitions.h | 8 ++++---- components/freertos/tasks.c | 2 +- .../test/test_freertos_backported_functions.c | 2 +- .../freertos/test/test_freertos_eventgroups.c | 2 +- .../freertos/test/test_freertos_task_notify.c | 2 +- components/unity/include/unity_test_runner.h | 6 +++--- components/wpa_supplicant/src/rsn_supp/wpa_i.h | 4 ++-- .../main/ble_mesh_register_node_cmd.c | 4 ++-- .../ble_mesh_node/main/register_bluetooth.c | 4 ++-- .../main/ble_mesh_register_node_cmd.c | 2 +- .../main/ble_mesh_register_provisioner_cmd.c | 2 +- .../main/mcpwm_bldc_control_hall_sensor_example.c | 2 +- .../rmt_nec_tx_rx/main/infrared_nec_main.c | 4 ++-- .../main/uart_async_rxtxtasks_main.c | 4 ++-- .../uart/uart_echo/main/uart_echo_example_main.c | 2 +- .../uart/uart_echo_rs485/main/rs485_example.c | 2 +- .../uart_select/main/uart_select_example_main.c | 2 +- examples/system/select/main/select_example.c | 2 +- 22 files changed, 40 insertions(+), 40 deletions(-) diff --git a/components/app_trace/app_trace.c b/components/app_trace/app_trace.c index c85ad6a2ac..bc0d0c20b5 100644 --- a/components/app_trace/app_trace.c +++ b/components/app_trace/app_trace.c @@ -379,10 +379,10 @@ static inline void esp_apptrace_log_unlock(void) #endif } -static inline esp_err_t esp_apptrace_lock_initialize(void) +static inline esp_err_t esp_apptrace_lock_initialize(esp_apptrace_lock_t *lock) { #if CONFIG_ESP32_APPTRACE_LOCK_ENABLE - esp_apptrace_lock_init(&s_trace_buf.lock); + esp_apptrace_lock_init(lock); #endif return ESP_OK; } diff --git a/components/app_update/test/test_switch_ota.c b/components/app_update/test/test_switch_ota.c index 232bfbc88e..f0d056d9bd 100644 --- a/components/app_update/test/test_switch_ota.c +++ b/components/app_update/test/test_switch_ota.c @@ -264,19 +264,19 @@ static void test_flow1(void) case 2: ESP_LOGI(TAG, "Factory"); TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype); - copy_current_app_to_next_part_and_reboot(cur_app); + copy_current_app_to_next_part_and_reboot(); break; case 3: ESP_LOGI(TAG, "OTA0"); TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_0, cur_app->subtype); mark_app_valid(); - copy_current_app_to_next_part_and_reboot(cur_app); + copy_current_app_to_next_part_and_reboot(); break; case 4: ESP_LOGI(TAG, "OTA1"); TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_1, cur_app->subtype); mark_app_valid(); - copy_current_app_to_next_part_and_reboot(cur_app); + copy_current_app_to_next_part_and_reboot(); break; case 5: ESP_LOGI(TAG, "OTA0"); @@ -307,7 +307,7 @@ static void test_flow2(void) case 2: ESP_LOGI(TAG, "Factory"); TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype); - copy_current_app_to_next_part_and_reboot(cur_app); + copy_current_app_to_next_part_and_reboot(); break; case 3: ESP_LOGI(TAG, "OTA0"); @@ -344,13 +344,13 @@ static void test_flow3(void) case 2: ESP_LOGI(TAG, "Factory"); TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype); - copy_current_app_to_next_part_and_reboot(cur_app); + copy_current_app_to_next_part_and_reboot(); break; case 3: ESP_LOGI(TAG, "OTA0"); TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_0, cur_app->subtype); mark_app_valid(); - copy_current_app_to_next_part_and_reboot(cur_app); + copy_current_app_to_next_part_and_reboot(); break; case 4: ESP_LOGI(TAG, "OTA1"); @@ -402,7 +402,7 @@ static void test_flow4(void) nvs_close(handle); nvs_flash_deinit(); - copy_current_app_to_next_part_and_reboot(cur_app); + copy_current_app_to_next_part_and_reboot(); break; case 3: ESP_LOGI(TAG, "OTA0"); diff --git a/components/driver/test/param_test/include/param_test.h b/components/driver/test/param_test/include/param_test.h index 879e2e5e92..e04a2bee6f 100644 --- a/components/driver/test/param_test/include/param_test.h +++ b/components/driver/test/param_test/include/param_test.h @@ -159,6 +159,6 @@ void test_serializer(const param_group_t *param_group, const ptest_func_t* test_ * @param slave_func ``ptest_func_t`` to be executed by slave. */ #define TEST_MASTER_SLAVE(name, param_group, tag, master_func, slave_func) \ - static void PTEST_MASTER_NAME(name) () { test_serializer(&PGROUP_NAME(param_group), master_func); } \ - static void PTEST_SLAVE_NAME(name) () { test_serializer(&PGROUP_NAME(param_group), slave_func); } \ + static void PTEST_MASTER_NAME(name) (void) { test_serializer(&PGROUP_NAME(param_group), master_func); } \ + static void PTEST_SLAVE_NAME(name) (void) { test_serializer(&PGROUP_NAME(param_group), slave_func); } \ TEST_CASE_MULTIPLE_DEVICES("master slave test: "#name, tag, PTEST_MASTER_NAME(name), PTEST_SLAVE_NAME(name)) diff --git a/components/fatfs/vfs/vfs_fat_sdmmc.c b/components/fatfs/vfs/vfs_fat_sdmmc.c index ac1a37a7fa..83cc0aee5b 100644 --- a/components/fatfs/vfs/vfs_fat_sdmmc.c +++ b/components/fatfs/vfs/vfs_fat_sdmmc.c @@ -171,7 +171,7 @@ esp_err_t esp_vfs_fat_sdmmc_unmount(void) char drv[3] = {(char)('0' + s_pdrv), ':', 0}; f_mount(0, drv, 0); // release SD driver - esp_err_t (*host_deinit)() = s_card->host.deinit; + esp_err_t (*host_deinit)(void) = s_card->host.deinit; ff_diskio_unregister(s_pdrv); free(s_card); s_card = NULL; diff --git a/components/freertos/include/freertos/deprecated_definitions.h b/components/freertos/include/freertos/deprecated_definitions.h index fb031cdde6..dc061f33f3 100644 --- a/components/freertos/include/freertos/deprecated_definitions.h +++ b/components/freertos/include/freertos/deprecated_definitions.h @@ -82,12 +82,12 @@ projects should not use them. */ #ifdef OPEN_WATCOM_INDUSTRIAL_PC_PORT #include "..\..\Source\portable\owatcom\16bitdos\pc\portmacro.h" - typedef void ( __interrupt __far *pxISR )(); + typedef void ( __interrupt __far *pxISR )(void); #endif #ifdef OPEN_WATCOM_FLASH_LITE_186_PORT #include "..\..\Source\portable\owatcom\16bitdos\flsh186\portmacro.h" - typedef void ( __interrupt __far *pxISR )(); + typedef void ( __interrupt __far *pxISR )(void); #endif #ifdef GCC_MEGA_AVR @@ -255,7 +255,7 @@ projects should not use them. */ FreeRTOSConfig.h when using the Borland compiler. */ #include "frconfig.h" #include "..\portable\BCC\16BitDOS\PC\prtmacro.h" - typedef void ( __interrupt __far *pxISR )(); + typedef void ( __interrupt __far *pxISR )(void); #endif #ifdef BCC_FLASH_LITE_186_PORT @@ -263,7 +263,7 @@ projects should not use them. */ FreeRTOSConfig.h when using the Borland compiler. */ #include "frconfig.h" #include "..\portable\BCC\16BitDOS\flsh186\prtmacro.h" - typedef void ( __interrupt __far *pxISR )(); + typedef void ( __interrupt __far *pxISR )(void); #endif #ifdef __GNUC__ diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index 8c4fd61a36..634e64e486 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -2149,7 +2149,7 @@ void vTaskSuspendAll( void ) #if ( portNUM_PROCESSORS > 1 ) - static BaseType_t xHaveReadyTasks() + static BaseType_t xHaveReadyTasks( void ) { for (int i = tskIDLE_PRIORITY + 1; i < configMAX_PRIORITIES; ++i) { diff --git a/components/freertos/test/test_freertos_backported_functions.c b/components/freertos/test/test_freertos_backported_functions.c index 5071ce1fe9..f3fab9a8e6 100644 --- a/components/freertos/test/test_freertos_backported_functions.c +++ b/components/freertos/test/test_freertos_backported_functions.c @@ -221,7 +221,7 @@ static void del_cb(int index, void *ptr) *((uint32_t *)ptr) = (TLSP_DEL_BASE << index); //Indicate deletion by setting task storage element to a unique value } -static void task_cb(void) +static void task_cb(void *arg) { int core = xPortGetCoreID(); for(int i = 0; i < NO_OF_TLSP; i++){ diff --git a/components/freertos/test/test_freertos_eventgroups.c b/components/freertos/test/test_freertos_eventgroups.c index c2672fe27c..9b86f759fb 100644 --- a/components/freertos/test/test_freertos_eventgroups.c +++ b/components/freertos/test/test_freertos_eventgroups.c @@ -135,7 +135,7 @@ static timer_isr_handle_t isr_handle; static bool test_set_bits; static bool test_clear_bits; -static void IRAM_ATTR event_group_isr(void) +static void IRAM_ATTR event_group_isr(void *arg) { portBASE_TYPE task_woken = pdFALSE; TIMERG0.int_clr_timers.t0 = 1; diff --git a/components/freertos/test/test_freertos_task_notify.c b/components/freertos/test/test_freertos_task_notify.c index fd230d1623..8179cef9b4 100644 --- a/components/freertos/test/test_freertos_task_notify.c +++ b/components/freertos/test/test_freertos_task_notify.c @@ -94,7 +94,7 @@ static void receiver_task (void* arg){ vTaskDelete(NULL); } -static void IRAM_ATTR sender_ISR (void) +static void IRAM_ATTR sender_ISR (void *arg) { int curcore = xPortGetCoreID(); if(curcore == 0){ //Clear timer interrupt diff --git a/components/unity/include/unity_test_runner.h b/components/unity/include/unity_test_runner.h index a9a1fae49d..e9e46ebd43 100644 --- a/components/unity/include/unity_test_runner.h +++ b/components/unity/include/unity_test_runner.h @@ -84,7 +84,7 @@ void unity_testcase_register(test_desc_t* desc); #define TEST_CASE(name_, desc_) \ static void UNITY_TEST_UID(test_func_) (void); \ - static void __attribute__((constructor)) UNITY_TEST_UID(test_reg_helper_) () \ + static void __attribute__((constructor)) UNITY_TEST_UID(test_reg_helper_) (void) \ { \ static test_func test_fn_[] = {&UNITY_TEST_UID(test_func_)}; \ static test_desc_t UNITY_TEST_UID(test_desc_) = { \ @@ -115,7 +115,7 @@ void unity_testcase_register(test_desc_t* desc); #define TEST_CASE_MULTIPLE_STAGES(name_, desc_, ...) \ UNITY_TEST_FN_SET(__VA_ARGS__); \ - static void __attribute__((constructor)) UNITY_TEST_UID(test_reg_helper_) () \ + static void __attribute__((constructor)) UNITY_TEST_UID(test_reg_helper_) (void) \ { \ static test_desc_t UNITY_TEST_UID(test_desc_) = { \ .name = name_, \ @@ -140,7 +140,7 @@ void unity_testcase_register(test_desc_t* desc); #define TEST_CASE_MULTIPLE_DEVICES(name_, desc_, ...) \ UNITY_TEST_FN_SET(__VA_ARGS__); \ - static void __attribute__((constructor)) UNITY_TEST_UID(test_reg_helper_) () \ + static void __attribute__((constructor)) UNITY_TEST_UID(test_reg_helper_) (void) \ { \ static test_desc_t UNITY_TEST_UID(test_desc_) = { \ .name = name_, \ diff --git a/components/wpa_supplicant/src/rsn_supp/wpa_i.h b/components/wpa_supplicant/src/rsn_supp/wpa_i.h index 3a09eff1d2..69fc1a5e3d 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa_i.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa_i.h @@ -81,7 +81,7 @@ struct wpa_sm { int (*get_ppkey) (uint8_t *ifx, int *alg, uint8_t *addr, int *key_idx, uint8_t *key, size_t key_len, int key_entry_valid); void (*wpa_deauthenticate)(u8 reason_code); - void (*wpa_neg_complete)(); + void (*wpa_neg_complete)(void); struct wpa_gtk_data gd; //used for calllback save param u16 key_info; //used for txcallback param u16 txcb_flags; @@ -145,7 +145,7 @@ typedef int (*WPA_GET_KEY) (u8 *ifx, int *alg, u8 *addt, int *keyidx, u8 *key, s typedef void (*WPA_DEAUTH_FUNC)(u8 reason_code); -typedef void (*WPA_NEG_COMPLETE)(); +typedef void (*WPA_NEG_COMPLETE)(void); void wpa_register(char * payload, WPA_SEND_FUNC snd_func, \ WPA_SET_ASSOC_IE set_assoc_ie_func, \ diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c index 6dc356cdab..375c224c6c 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c @@ -97,7 +97,7 @@ void ble_mesh_register_mesh_node(void) ble_mesh_register_node_cmd(); } -int ble_mesh_register_node_cb(void) +int ble_mesh_register_node_cb(int argc, char** argv) { ESP_LOGD(TAG, "enter %s\n", __func__); ble_mesh_node_init(); @@ -364,7 +364,7 @@ int ble_mesh_node_enable_bearer(int argc, char **argv) return err; } -int ble_mesh_node_reset(void) +int ble_mesh_node_reset(int argc, char** argv) { esp_err_t err; ESP_LOGD(TAG, "enter %s\n", __func__); diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c index 0489388ec1..64358ba606 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c @@ -25,7 +25,7 @@ void register_bluetooth(void) register_ble_address(); } -int bt_mac(void) +int bt_mac(int argc, char** argv) { const uint8_t *mac = esp_bt_dev_get_address(); printf("+BTMAC:"MACSTR"\n", MAC2STR(mac)); @@ -38,7 +38,7 @@ void register_ble_address(void) .command = "btmac", .help = "get BT mac address", .hint = NULL, - .func = (esp_console_cmd_func_t)&bt_mac, + .func = &bt_mac, }; ESP_ERROR_CHECK(esp_console_cmd_register(&cmd)); } diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c index dc96f79079..b9bd565c40 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_node_cmd.c @@ -76,7 +76,7 @@ void ble_mesh_register_mesh_node(void) ble_mesh_register_node_cmd(); } -int ble_mesh_register_node_cb(void) +int ble_mesh_register_node_cb(int argc, char** argv) { ESP_LOGD(TAG, "enter %s\n", __func__); ble_mesh_node_init(); diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c index 4c95d45b28..6b74255d37 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_register_provisioner_cmd.c @@ -101,7 +101,7 @@ void ble_mesh_prov_adv_cb(const esp_bd_addr_t addr, const esp_ble_addr_type_t ad ESP_LOGD(TAG, "exit %s\n", __func__); } -int ble_mesh_provisioner_register(void) +int ble_mesh_provisioner_register(int argc, char** argv) { ESP_LOGD(TAG, "enter %s \n", __func__); // esp_ble_mesh_register_unprov_adv_pkt_callback(ble_mesh_prov_adv_cb); diff --git a/examples/peripherals/mcpwm/mcpwm_bldc_control/main/mcpwm_bldc_control_hall_sensor_example.c b/examples/peripherals/mcpwm/mcpwm_bldc_control/main/mcpwm_bldc_control_hall_sensor_example.c index c8bfe00010..6784b63991 100644 --- a/examples/peripherals/mcpwm/mcpwm_bldc_control/main/mcpwm_bldc_control_hall_sensor_example.c +++ b/examples/peripherals/mcpwm/mcpwm_bldc_control/main/mcpwm_bldc_control_hall_sensor_example.c @@ -162,7 +162,7 @@ static void disp_captured_signal(void *arg) /** * @brief this is ISR handler function, here we check for interrupt that triggers rising edge on CAP0 signal and according take action */ -static void IRAM_ATTR isr_handler(void) +static void IRAM_ATTR isr_handler(void *arg) { uint32_t mcpwm_intr_status; capture evt; diff --git a/examples/peripherals/rmt_nec_tx_rx/main/infrared_nec_main.c b/examples/peripherals/rmt_nec_tx_rx/main/infrared_nec_main.c index 1dc28e5acc..df5a6b08d9 100644 --- a/examples/peripherals/rmt_nec_tx_rx/main/infrared_nec_main.c +++ b/examples/peripherals/rmt_nec_tx_rx/main/infrared_nec_main.c @@ -276,7 +276,7 @@ static void nec_rx_init(void) * @brief RMT receiver demo, this task will print each received NEC data. * */ -static void rmt_example_nec_rx_task(void) +static void rmt_example_nec_rx_task(void *arg) { int channel = RMT_RX_CHANNEL; nec_rx_init(); @@ -317,7 +317,7 @@ static void rmt_example_nec_rx_task(void) * @brief RMT transmitter demo, this task will periodically send NEC data. (100 * 32 bits each time.) * */ -static void rmt_example_nec_tx_task(void) +static void rmt_example_nec_tx_task(void *arg) { vTaskDelay(10); nec_tx_init(); diff --git a/examples/peripherals/uart/uart_async_rxtxtasks/main/uart_async_rxtxtasks_main.c b/examples/peripherals/uart/uart_async_rxtxtasks/main/uart_async_rxtxtasks_main.c index f4f4eb18da..3b4a5872ea 100644 --- a/examples/peripherals/uart/uart_async_rxtxtasks/main/uart_async_rxtxtasks_main.c +++ b/examples/peripherals/uart/uart_async_rxtxtasks/main/uart_async_rxtxtasks_main.c @@ -41,7 +41,7 @@ int sendData(const char* logName, const char* data) return txBytes; } -static void tx_task(void) +static void tx_task(void *arg) { static const char *TX_TASK_TAG = "TX_TASK"; esp_log_level_set(TX_TASK_TAG, ESP_LOG_INFO); @@ -51,7 +51,7 @@ static void tx_task(void) } } -static void rx_task(void) +static void rx_task(void *arg) { static const char *RX_TASK_TAG = "RX_TASK"; esp_log_level_set(RX_TASK_TAG, ESP_LOG_INFO); diff --git a/examples/peripherals/uart/uart_echo/main/uart_echo_example_main.c b/examples/peripherals/uart/uart_echo/main/uart_echo_example_main.c index 6e6a77a749..c9b5dbc7b3 100644 --- a/examples/peripherals/uart/uart_echo/main/uart_echo_example_main.c +++ b/examples/peripherals/uart/uart_echo/main/uart_echo_example_main.c @@ -31,7 +31,7 @@ #define BUF_SIZE (1024) -static void echo_task(void) +static void echo_task(void *arg) { /* Configure parameters of an UART driver, * communication pins and install the driver */ diff --git a/examples/peripherals/uart/uart_echo_rs485/main/rs485_example.c b/examples/peripherals/uart/uart_echo_rs485/main/rs485_example.c index c68c22edf0..e2d53dac4d 100644 --- a/examples/peripherals/uart/uart_echo_rs485/main/rs485_example.c +++ b/examples/peripherals/uart/uart_echo_rs485/main/rs485_example.c @@ -52,7 +52,7 @@ static const char *TAG = "RS485_ECHO_APP"; // An example of echo test with hardware flow control on UART -static void echo_task(void) +static void echo_task(void *arg) { const int uart_num = ECHO_UART_PORT; uart_config_t uart_config = { diff --git a/examples/peripherals/uart/uart_select/main/uart_select_example_main.c b/examples/peripherals/uart/uart_select/main/uart_select_example_main.c index 2c46a3d114..d7b3c88491 100644 --- a/examples/peripherals/uart/uart_select/main/uart_select_example_main.c +++ b/examples/peripherals/uart/uart_select/main/uart_select_example_main.c @@ -20,7 +20,7 @@ static const char* TAG = "uart_select_example"; -static void uart_select_task(void) +static void uart_select_task(void *arg) { uart_config_t uart_config = { .baud_rate = 115200, diff --git a/examples/system/select/main/select_example.c b/examples/system/select/main/select_example.c index 9629024295..5da28c7dde 100644 --- a/examples/system/select/main/select_example.c +++ b/examples/system/select/main/select_example.c @@ -128,7 +128,7 @@ static void uart1_write_task(void *param) } } - uart1_deinit(uart_fd); + uart1_deinit(); vTaskDelete(NULL); } From 12403e39b43ead17e97336033407a74649c9fb5d Mon Sep 17 00:00:00 2001 From: Anton Maklakov Date: Tue, 30 Jul 2019 21:26:43 +0700 Subject: [PATCH 393/486] tools: Fix the build examples script to run locally --- tools/ci/build_examples.sh | 5 ++++- tools/ci/build_examples_cmake.sh | 18 +++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/tools/ci/build_examples.sh b/tools/ci/build_examples.sh index 7393cb3024..9be1525b3f 100755 --- a/tools/ci/build_examples.sh +++ b/tools/ci/build_examples.sh @@ -62,9 +62,12 @@ SDKCONFIG_DEFAULTS_CI=sdkconfig.ci EXAMPLE_PATHS=$( find ${IDF_PATH}/examples/ -type f -name Makefile | grep -v "/build_system/cmake/" | sort ) -if [ -z {CI_NODE_TOTAL} ] +if [ -z "${CI_NODE_TOTAL:-}" ] then START_NUM=0 + if [ "${1:-}" ]; then + START_NUM=$1 + fi END_NUM=999 else JOB_NUM=${CI_NODE_INDEX} diff --git a/tools/ci/build_examples_cmake.sh b/tools/ci/build_examples_cmake.sh index da15bae725..cc5f3adc00 100755 --- a/tools/ci/build_examples_cmake.sh +++ b/tools/ci/build_examples_cmake.sh @@ -52,7 +52,7 @@ set -o nounset # Exit if variable not set. echo "build_examples running in ${PWD} for target $IDF_TARGET" # only 0 or 1 arguments -[ $# -le 1 ] || die "Have to run as $(basename $0) []" +[ $# -le 1 ] || die "Have to run as $(basename $0) []" export BATCH_BUILD=1 export V=0 # only build verbose if there's an error @@ -67,22 +67,26 @@ touch ${LOG_SUSPECTED} SDKCONFIG_DEFAULTS_CI=sdkconfig.ci EXAMPLE_PATHS=$( get_supported_examples.sh $IDF_TARGET | sed "s#^#${IDF_PATH}\/examples\/#g" | awk '{print $0"/CmakeLists.txt"}' ) +NUM_OF_EXAMPLES=$( echo "${EXAMPLE_PATHS}" | wc -l ) +# just a plausibility check +[ ${NUM_OF_EXAMPLES} -lt 100 ] && die "NUM_OF_EXAMPLES is bad" + echo "All examples found for target $IDF_TARGET:" echo $EXAMPLE_PATHS +echo "Number of examples: $NUM_OF_EXAMPLES" -if [ -z {CI_NODE_TOTAL} ] +if [ -z "${CI_NODE_TOTAL:-}" ] then START_NUM=0 - END_NUM=999 + if [ "${1:-}" ]; then + START_NUM=$1 + fi + END_NUM=${NUM_OF_EXAMPLES} else JOB_NUM=${CI_NODE_INDEX} # count number of the jobs NUM_OF_JOBS=${CI_NODE_TOTAL} - # count number of examples - NUM_OF_EXAMPLES=$( echo "${EXAMPLE_PATHS}" | wc -l ) - [ ${NUM_OF_EXAMPLES} -lt 100 ] && die "NUM_OF_EXAMPLES is bad" - # separate intervals #57 / 5 == 12 NUM_OF_EX_PER_JOB=$(( (${NUM_OF_EXAMPLES} + ${NUM_OF_JOBS} - 1) / ${NUM_OF_JOBS} )) From ec94ee80f72aacd2c078e6ce13c5355a8cf6c461 Mon Sep 17 00:00:00 2001 From: Anton Maklakov Date: Thu, 1 Aug 2019 11:23:41 +0700 Subject: [PATCH 394/486] Fix a build issue with replacing init_spi_flash() in the host tests --- components/fatfs/test_fatfs_host/Makefile | 1 - components/fatfs/test_fatfs_host/test_fatfs.cpp | 4 ++-- components/fatfs/test_fatfs_host/test_utils.c | 7 ------- components/spi_flash/sim/flash_mock_util.c | 7 ------- .../sim/stubs/freertos/include/freertos/FreeRTOS.h | 4 ---- components/spiffs/test_spiffs_host/Makefile | 1 - components/spiffs/test_spiffs_host/test_spiffs.cpp | 6 +++--- components/spiffs/test_spiffs_host/test_utils.c | 7 ------- components/wear_levelling/test_wl_host/Makefile | 1 - components/wear_levelling/test_wl_host/test_utils.c | 7 ------- components/wear_levelling/test_wl_host/test_wl.cpp | 6 +++--- 11 files changed, 8 insertions(+), 43 deletions(-) delete mode 100644 components/fatfs/test_fatfs_host/test_utils.c delete mode 100644 components/spiffs/test_spiffs_host/test_utils.c delete mode 100644 components/wear_levelling/test_wl_host/test_utils.c diff --git a/components/fatfs/test_fatfs_host/Makefile b/components/fatfs/test_fatfs_host/Makefile index 4c43e16aab..3d17e5ac1a 100644 --- a/components/fatfs/test_fatfs_host/Makefile +++ b/components/fatfs/test_fatfs_host/Makefile @@ -81,7 +81,6 @@ $(foreach cxxfile, $(CPPFILES), $(eval $(call COMPILE_CPP, $(cxxfile)))) TEST_SOURCE_FILES = \ test_fatfs.cpp \ main.cpp \ - test_utils.c TEST_OBJ_FILES = $(filter %.o, $(TEST_SOURCE_FILES:.cpp=.o) $(TEST_SOURCE_FILES:.c=.o)) diff --git a/components/fatfs/test_fatfs_host/test_fatfs.cpp b/components/fatfs/test_fatfs_host/test_fatfs.cpp index fcbbe55945..d1f7119e61 100644 --- a/components/fatfs/test_fatfs_host/test_fatfs.cpp +++ b/components/fatfs/test_fatfs_host/test_fatfs.cpp @@ -9,11 +9,11 @@ #include "catch.hpp" -extern "C" void init_spi_flash(const char* chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin); +extern "C" void _spi_flash_init(const char* chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin); TEST_CASE("create volume, open file, write and read back data", "[fatfs]") { - init_spi_flash(CONFIG_ESPTOOLPY_FLASHSIZE, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin"); + _spi_flash_init(CONFIG_ESPTOOLPY_FLASHSIZE, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin"); FRESULT fr_result; BYTE pdrv; diff --git a/components/fatfs/test_fatfs_host/test_utils.c b/components/fatfs/test_fatfs_host/test_utils.c deleted file mode 100644 index 3e4b05758a..0000000000 --- a/components/fatfs/test_fatfs_host/test_utils.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "esp_spi_flash.h" -#include "esp_partition.h" - -void init_spi_flash(const char* chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin) -{ - spi_flash_init(chip_size, block_size, sector_size, page_size, partition_bin); -} diff --git a/components/spi_flash/sim/flash_mock_util.c b/components/spi_flash/sim/flash_mock_util.c index 770600e642..2db51c58ae 100644 --- a/components/spi_flash/sim/flash_mock_util.c +++ b/components/spi_flash/sim/flash_mock_util.c @@ -4,13 +4,6 @@ #include "esp_err.h" #include "esp32/rom/spi_flash.h" -extern void _spi_flash_init(const char* chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin); - -void spi_flash_init(const char* chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin) -{ - _spi_flash_init(chip_size, block_size, sector_size, page_size, partition_bin); -} - bool spi_flash_check_and_flush_cache(size_t start_addr, size_t length) { return true; diff --git a/components/spi_flash/sim/stubs/freertos/include/freertos/FreeRTOS.h b/components/spi_flash/sim/stubs/freertos/include/freertos/FreeRTOS.h index 9abd0dd8ba..5bafa772df 100644 --- a/components/spi_flash/sim/stubs/freertos/include/freertos/FreeRTOS.h +++ b/components/spi_flash/sim/stubs/freertos/include/freertos/FreeRTOS.h @@ -2,7 +2,3 @@ #include "projdefs.h" #include "semphr.h" - -// Avoid redefinition compile error. Put here since this is included -// in flash_ops.c. -#define spi_flash_init() overriden_spi_flash_init() diff --git a/components/spiffs/test_spiffs_host/Makefile b/components/spiffs/test_spiffs_host/Makefile index 4d016f7b4d..15b327acf1 100644 --- a/components/spiffs/test_spiffs_host/Makefile +++ b/components/spiffs/test_spiffs_host/Makefile @@ -79,7 +79,6 @@ $(foreach cxxfile, $(CPPFILES), $(eval $(call COMPILE_CPP, $(cxxfile)))) TEST_SOURCE_FILES = \ test_spiffs.cpp \ main.cpp \ - test_utils.c TEST_OBJ_FILES = $(filter %.o, $(TEST_SOURCE_FILES:.cpp=.o) $(TEST_SOURCE_FILES:.c=.o)) diff --git a/components/spiffs/test_spiffs_host/test_spiffs.cpp b/components/spiffs/test_spiffs_host/test_spiffs.cpp index a523f06a73..868ce45809 100644 --- a/components/spiffs/test_spiffs_host/test_spiffs.cpp +++ b/components/spiffs/test_spiffs_host/test_spiffs.cpp @@ -12,7 +12,7 @@ #include "catch.hpp" -extern "C" void init_spi_flash(const char* chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin); +extern "C" void _spi_flash_init(const char* chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin); static void init_spiffs(spiffs *fs, uint32_t max_files) { @@ -152,7 +152,7 @@ static void check_spiffs_files(spiffs *fs, const char *base_path, char* cur_path TEST_CASE("format disk, open file, write and read file", "[spiffs]") { - init_spi_flash(CONFIG_ESPTOOLPY_FLASHSIZE, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin"); + _spi_flash_init(CONFIG_ESPTOOLPY_FLASHSIZE, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin"); spiffs fs; s32_t spiffs_res; @@ -204,7 +204,7 @@ TEST_CASE("format disk, open file, write and read file", "[spiffs]") TEST_CASE("can read spiffs image", "[spiffs]") { - init_spi_flash(CONFIG_ESPTOOLPY_FLASHSIZE, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin"); + _spi_flash_init(CONFIG_ESPTOOLPY_FLASHSIZE, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin"); spiffs fs; s32_t spiffs_res; diff --git a/components/spiffs/test_spiffs_host/test_utils.c b/components/spiffs/test_spiffs_host/test_utils.c deleted file mode 100644 index 3e4b05758a..0000000000 --- a/components/spiffs/test_spiffs_host/test_utils.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "esp_spi_flash.h" -#include "esp_partition.h" - -void init_spi_flash(const char* chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin) -{ - spi_flash_init(chip_size, block_size, sector_size, page_size, partition_bin); -} diff --git a/components/wear_levelling/test_wl_host/Makefile b/components/wear_levelling/test_wl_host/Makefile index 5d94990cc2..40e517445a 100644 --- a/components/wear_levelling/test_wl_host/Makefile +++ b/components/wear_levelling/test_wl_host/Makefile @@ -80,7 +80,6 @@ $(foreach cxxfile, $(CPPFILES), $(eval $(call COMPILE_CPP, $(cxxfile)))) TEST_SOURCE_FILES = \ test_wl.cpp \ main.cpp \ - test_utils.c TEST_OBJ_FILES = $(filter %.o, $(TEST_SOURCE_FILES:.cpp=.o) $(TEST_SOURCE_FILES:.c=.o)) diff --git a/components/wear_levelling/test_wl_host/test_utils.c b/components/wear_levelling/test_wl_host/test_utils.c deleted file mode 100644 index 3e4b05758a..0000000000 --- a/components/wear_levelling/test_wl_host/test_utils.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "esp_spi_flash.h" -#include "esp_partition.h" - -void init_spi_flash(const char* chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin) -{ - spi_flash_init(chip_size, block_size, sector_size, page_size, partition_bin); -} diff --git a/components/wear_levelling/test_wl_host/test_wl.cpp b/components/wear_levelling/test_wl_host/test_wl.cpp index 2589024391..32993876ca 100644 --- a/components/wear_levelling/test_wl_host/test_wl.cpp +++ b/components/wear_levelling/test_wl_host/test_wl.cpp @@ -12,14 +12,14 @@ #include "sdkconfig.h" -extern "C" void init_spi_flash(const char* chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin); +extern "C" void _spi_flash_init(const char* chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin); extern SpiFlash spiflash; #define TEST_COUNT_MAX 100 TEST_CASE("write and read back data", "[wear_levelling]") { - init_spi_flash(CONFIG_ESPTOOLPY_FLASHSIZE, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin"); + _spi_flash_init(CONFIG_ESPTOOLPY_FLASHSIZE, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin"); esp_err_t result; wl_handle_t wl_handle; @@ -92,7 +92,7 @@ TEST_CASE("write and read back data", "[wear_levelling]") TEST_CASE("power down test", "[wear_levelling]") { - init_spi_flash(CONFIG_ESPTOOLPY_FLASHSIZE, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin"); + _spi_flash_init(CONFIG_ESPTOOLPY_FLASHSIZE, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin"); esp_err_t result; wl_handle_t wl_handle; From e639d5cb84fb9aa92a40375dd370145e2e784568 Mon Sep 17 00:00:00 2001 From: RevoluPowered Date: Sun, 16 Jun 2019 15:15:48 +0100 Subject: [PATCH 395/486] CMake: Added git ignore for cache files generated by cmake Merges https://github.com/espressif/esp-idf/pull/3639 --- .gitignore | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 48ee2b0f16..dedb5745d9 100644 --- a/.gitignore +++ b/.gitignore @@ -63,8 +63,12 @@ test_multi_heap_host # VS Code Settings .vscode/ +# Clion IDE CMake build & config +.idea/ +cmake-build-*/ + # Results for the checking of the Python coding style flake8_output.txt -# ESP-IDF library +# ESP-IDF default build directory name build From 017a60a69da670d998c7b7b803041b27a1916bd2 Mon Sep 17 00:00:00 2001 From: zhangyanjiao Date: Thu, 1 Aug 2019 11:27:32 +0800 Subject: [PATCH 396/486] fix the wrong comment in esp_wifi_types.h --- components/esp_wifi/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index 57e1fd11f2..2e36381461 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit 57e1fd11f2f2e17c39ce9612e5fd87d687bcf133 +Subproject commit 2e3638146130970f9eec473f39817921d42320d7 From 9f9d8767991193651526fc552dc603cfd2f815bd Mon Sep 17 00:00:00 2001 From: zhangyanjiao Date: Fri, 2 Aug 2019 10:22:20 +0800 Subject: [PATCH 397/486] wifi: fix wifi bugs for authmode and multi ssid --- components/esp_wifi/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index 2e36381461..8e2ed075db 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit 2e3638146130970f9eec473f39817921d42320d7 +Subproject commit 8e2ed075db7f4d5f942b5ea354070d6273c01638 From 02e5266778a11caeff893d6dd675f9f03aa3692e Mon Sep 17 00:00:00 2001 From: zhangyanjiao Date: Fri, 2 Aug 2019 10:22:46 +0800 Subject: [PATCH 398/486] modify WIFI_CONN_0101 case for wrong authmode of AP --- .../idf_test/integration_test/TC_IT_WIFI_CONN.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/idf_test/integration_test/TC_IT_WIFI_CONN.yml b/components/idf_test/integration_test/TC_IT_WIFI_CONN.yml index 7086310cdb..7195a32cc3 100644 --- a/components/idf_test/integration_test/TC_IT_WIFI_CONN.yml +++ b/components/idf_test/integration_test/TC_IT_WIFI_CONN.yml @@ -28,20 +28,20 @@ test cases: - - SSC SSC2 sta -C -s -p - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() - - SSC SSC1 ap -S -s -p -t 1 - - - R SSC1 C +SAP:OK + - - R SSC1 C +SAP:ERROR - - SSC SSC2 sta -D - - R SSC2 C +QAP:OK - - SSC SSC2 sta -S - - R SSC2 RE "\+SCAN:%%s,.+,0,\d+"%%() C +SCANDONE - - - SSC SSC1 ap -S -s -p -t 5 - - - R SSC1 C +SAP:OK + - - SSC SSC1 ap -S -s -p -t 6 + - - R SSC1 C +SAP:ERROR - - SSC SSC2 sta -S - - R SSC2 RE "\+SCAN:%%s,.+,0,\d+"%%() C +SCANDONE execution time: 0.0 expected result: "1.target1 set AP,open, \n2.target 2 jap succeed\n3.target1 set AP,wpa_psk \n4.target 2 jap succeed\n5.target1 set AP, wpa2_psk \n6.target 2 jap succeed\n7.target1 set AP,wap_wpa2_psk\n8.target 2 jap succeed\n9.target1 set - AP,加密方式为t 1\n10.target 2 上查询到target_ssid\n11.target1 set AP,加密方式为t 5\n12.target + AP,加密方式为t 1\n10.target 2 上查询到target_ssid\n11.target1 set AP,加密方式为t 6\n12.target 2 上查询到target_ssid" initial condition: T2_1 level: Integration @@ -50,7 +50,7 @@ test cases: 和pwd,加密方式 wpa_psk \n4.target2 jap target1\n5.target1下设置ssid 和pwd,加密方式 wpa2_psk \n6.target 2 jap target1\n7.target1下设置ssid 和pwd,加密方式 wap_wpa2_psk\n8.target2 jap target1\n9.target1下设置ssid 和pwd,加密方式 wep \n10.target2上查询target_ssid\n11.target1下设置ssid - 和pwd,加密方式 t 5 错误的加密方式\n12.target2上查询 target_ssid" + 和pwd,加密方式 t 6 错误的加密方式\n12.target2上查询 target_ssid" sub module: WIFI Connect summary: station SAP+JAP test, different encryption test environment: SSC_T2_5 From 73624e856066b069cfd81a8a3ca65540ee080bf2 Mon Sep 17 00:00:00 2001 From: Henning Fleddermann Date: Mon, 15 Jul 2019 17:51:25 +0200 Subject: [PATCH 399/486] modify comments on esp_tls_cfg, to clarify that other formats besides PEM (such as DER) might be used as well depending on mbedtls-support Signed-off-by: David Cermak --- components/esp-tls/esp_tls.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/components/esp-tls/esp_tls.h b/components/esp-tls/esp_tls.h index 1c2f785ea5..ebdffa49e2 100644 --- a/components/esp-tls/esp_tls.h +++ b/components/esp-tls/esp_tls.h @@ -90,22 +90,28 @@ typedef struct esp_tls_cfg { - where 'h2' is the protocol name */ const unsigned char *cacert_pem_buf; /*!< Certificate Authority's certificate in a buffer. - This buffer should be NULL terminated */ + Format may be PEM or DER, depending on mbedtls-support + This buffer should be NULL terminated in case of PEM */ unsigned int cacert_pem_bytes; /*!< Size of Certificate Authority certificate - pointed to by cacert_pem_buf */ + pointed to by cacert_pem_buf + (including NULL-terminator in case of PEM format) */ const unsigned char *clientcert_pem_buf;/*!< Client certificate in a buffer - This buffer should be NULL terminated */ + Format may be PEM or DER, depending on mbedtls-support + This buffer should be NULL terminated in case of PEM */ unsigned int clientcert_pem_bytes; /*!< Size of client certificate pointed to by - clientcert_pem_buf */ + clientcert_pem_buf + (including NULL-terminator in case of PEM format) */ const unsigned char *clientkey_pem_buf; /*!< Client key in a buffer - This buffer should be NULL terminated */ + Format may be PEM or DER, depending on mbedtls-support + This buffer should be NULL terminated in case of PEM */ unsigned int clientkey_pem_bytes; /*!< Size of client key pointed to by - clientkey_pem_buf */ + clientkey_pem_buf + (including NULL-terminator in case of PEM format) */ const unsigned char *clientkey_password;/*!< Client key decryption password string */ From 546b6254335435cc01ce26cded765855af8c4144 Mon Sep 17 00:00:00 2001 From: Henning Fleddermann Date: Mon, 15 Jul 2019 17:53:39 +0200 Subject: [PATCH 400/486] add _der variants for esp_transport_ssl_set_(client_cert|client_key|cert_data) Signed-off-by: David Cermak Merges https://github.com/espressif/esp-idf/pull/3783 --- .../tcp_transport/include/esp_transport_ssl.h | 33 +++++++++++++++++++ components/tcp_transport/transport_ssl.c | 27 +++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/components/tcp_transport/include/esp_transport_ssl.h b/components/tcp_transport/include/esp_transport_ssl.h index 0f83c1d6e4..3e2bfb42da 100644 --- a/components/tcp_transport/include/esp_transport_ssl.h +++ b/components/tcp_transport/include/esp_transport_ssl.h @@ -40,6 +40,17 @@ esp_transport_handle_t esp_transport_ssl_init(); */ void esp_transport_ssl_set_cert_data(esp_transport_handle_t t, const char *data, int len); +/** + * @brief Set SSL certificate data (as DER format). + * Note that, this function stores the pointer to data, rather than making a copy. + * So this data must remain valid until after the connection is cleaned up + * + * @param t ssl transport + * @param[in] data The der data + * @param[in] len The length + */ +void esp_transport_ssl_set_cert_data_der(esp_transport_handle_t t, const char *data, int len); + /** * @brief Enable global CA store for SSL connection * @@ -58,6 +69,17 @@ void esp_transport_ssl_enable_global_ca_store(esp_transport_handle_t t); */ void esp_transport_ssl_set_client_cert_data(esp_transport_handle_t t, const char *data, int len); +/** + * @brief Set SSL client certificate data for mutual authentication (as DER format). + * Note that, this function stores the pointer to data, rather than making a copy. + * So this data must remain valid until after the connection is cleaned up + * + * @param t ssl transport + * @param[in] data The der data + * @param[in] len The length + */ +void esp_transport_ssl_set_client_cert_data_der(esp_transport_handle_t t, const char *data, int len); + /** * @brief Set SSL client key data for mutual authentication (as PEM format). * Note that, this function stores the pointer to data, rather than making a copy. @@ -69,6 +91,17 @@ void esp_transport_ssl_set_client_cert_data(esp_transport_handle_t t, const char */ void esp_transport_ssl_set_client_key_data(esp_transport_handle_t t, const char *data, int len); +/** + * @brief Set SSL client key data for mutual authentication (as DER format). + * Note that, this function stores the pointer to data, rather than making a copy. + * So this data must remain valid until after the connection is cleaned up + * + * @param t ssl transport + * @param[in] data The der data + * @param[in] len The length + */ +void esp_transport_ssl_set_client_key_data_der(esp_transport_handle_t t, const char *data, int len); + /** * @brief Skip validation of certificate's common name field * diff --git a/components/tcp_transport/transport_ssl.c b/components/tcp_transport/transport_ssl.c index 1651a2f87f..b8a2e7281e 100644 --- a/components/tcp_transport/transport_ssl.c +++ b/components/tcp_transport/transport_ssl.c @@ -178,6 +178,15 @@ void esp_transport_ssl_set_cert_data(esp_transport_handle_t t, const char *data, } } +void esp_transport_ssl_set_cert_data_der(esp_transport_handle_t t, const char *data, int len) +{ + transport_ssl_t *ssl = esp_transport_get_context_data(t); + if (t && ssl) { + ssl->cfg.cacert_pem_buf = (void *)data; + ssl->cfg.cacert_pem_bytes = len; + } +} + void esp_transport_ssl_set_client_cert_data(esp_transport_handle_t t, const char *data, int len) { transport_ssl_t *ssl = esp_transport_get_context_data(t); @@ -187,6 +196,15 @@ void esp_transport_ssl_set_client_cert_data(esp_transport_handle_t t, const char } } +void esp_transport_ssl_set_client_cert_data_der(esp_transport_handle_t t, const char *data, int len) +{ + transport_ssl_t *ssl = esp_transport_get_context_data(t); + if (t && ssl) { + ssl->cfg.clientcert_pem_buf = (void *)data; + ssl->cfg.clientcert_pem_bytes = len; + } +} + void esp_transport_ssl_set_client_key_data(esp_transport_handle_t t, const char *data, int len) { transport_ssl_t *ssl = esp_transport_get_context_data(t); @@ -196,6 +214,15 @@ void esp_transport_ssl_set_client_key_data(esp_transport_handle_t t, const char } } +void esp_transport_ssl_set_client_key_data_der(esp_transport_handle_t t, const char *data, int len) +{ + transport_ssl_t *ssl = esp_transport_get_context_data(t); + if (t && ssl) { + ssl->cfg.clientkey_pem_buf = (void *)data; + ssl->cfg.clientkey_pem_bytes = len; + } +} + void esp_transport_ssl_skip_common_name_check(esp_transport_handle_t t) { transport_ssl_t *ssl = esp_transport_get_context_data(t); From 25dd5e39afba5f66fe571ed235270b3972223679 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 2 Aug 2019 09:20:02 +0200 Subject: [PATCH 401/486] esp-tls: Naming variables refering to certificates and keys in a neutral way to suggest that both PEM and DER format could be used, added comments descibing important details about using these formats --- components/esp-tls/esp_tls.c | 34 ++++----- components/esp-tls/esp_tls.h | 74 +++++++++++++++---- .../esp_https_server/src/https_server.c | 26 +++---- components/tcp_transport/transport_ssl.c | 12 +-- .../main/https_request_example_main.c | 4 +- 5 files changed, 98 insertions(+), 52 deletions(-) diff --git a/components/esp-tls/esp_tls.c b/components/esp-tls/esp_tls.c index 65cd789f39..e2d33cb0e9 100644 --- a/components/esp-tls/esp_tls.c +++ b/components/esp-tls/esp_tls.c @@ -339,8 +339,8 @@ static esp_err_t set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls) } #endif - if (cfg->cacert_pem_buf != NULL) { - esp_ret = set_ca_cert(tls, cfg->cacert_pem_buf, cfg->cacert_pem_bytes); + if (cfg->cacert_buf != NULL) { + esp_ret = set_ca_cert(tls, cfg->cacert_buf, cfg->cacert_bytes); if (esp_ret != ESP_OK) { return esp_ret; } @@ -348,14 +348,14 @@ static esp_err_t set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls) mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE); } - if (cfg->servercert_pem_buf != NULL && cfg->serverkey_pem_buf != NULL) { + if (cfg->servercert_buf != NULL && cfg->serverkey_buf != NULL) { esp_tls_pki_t pki = { .public_cert = &tls->servercert, .pk_key = &tls->serverkey, - .publiccert_pem_buf = cfg->servercert_pem_buf, - .publiccert_pem_bytes = cfg->servercert_pem_bytes, - .privkey_pem_buf = cfg->serverkey_pem_buf, - .privkey_pem_bytes = cfg->serverkey_pem_bytes, + .publiccert_pem_buf = cfg->servercert_buf, + .publiccert_pem_bytes = cfg->servercert_bytes, + .privkey_pem_buf = cfg->serverkey_buf, + .privkey_pem_bytes = cfg->serverkey_bytes, .privkey_password = cfg->serverkey_password, .privkey_password_len = cfg->serverkey_password_len, }; @@ -421,8 +421,8 @@ static esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls if (esp_ret != ESP_OK) { return esp_ret; } - } else if (cfg->cacert_pem_buf != NULL) { - esp_err_t esp_ret = set_ca_cert(tls, cfg->cacert_pem_buf, cfg->cacert_pem_bytes); + } else if (cfg->cacert_buf != NULL) { + esp_err_t esp_ret = set_ca_cert(tls, cfg->cacert_buf, cfg->cacert_bytes); if (esp_ret != ESP_OK) { return esp_ret; } @@ -430,14 +430,14 @@ static esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE); } - if (cfg->clientcert_pem_buf != NULL && cfg->clientkey_pem_buf != NULL) { + if (cfg->clientcert_buf != NULL && cfg->clientkey_buf != NULL) { esp_tls_pki_t pki = { .public_cert = &tls->clientcert, .pk_key = &tls->clientkey, - .publiccert_pem_buf = cfg->clientcert_pem_buf, - .publiccert_pem_bytes = cfg->clientcert_pem_bytes, - .privkey_pem_buf = cfg->clientkey_pem_buf, - .privkey_pem_bytes = cfg->clientkey_pem_bytes, + .publiccert_pem_buf = cfg->clientcert_buf, + .publiccert_pem_bytes = cfg->clientcert_bytes, + .privkey_pem_buf = cfg->clientkey_buf, + .privkey_pem_bytes = cfg->clientkey_bytes, .privkey_password = cfg->clientkey_password, .privkey_password_len = cfg->clientkey_password_len, }; @@ -446,8 +446,8 @@ static esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls ESP_LOGE(TAG, "Failed to set server pki context"); return esp_ret; } - } else if (cfg->clientcert_pem_buf != NULL || cfg->clientkey_pem_buf != NULL) { - ESP_LOGE(TAG, "You have to provide both clientcert_pem_buf and clientkey_pem_buf for mutual authentication"); + } else if (cfg->clientcert_buf != NULL || cfg->clientkey_buf != NULL) { + ESP_LOGE(TAG, "You have to provide both clientcert_buf and clientkey_buf for mutual authentication"); return ESP_ERR_INVALID_STATE; } return ESP_OK; @@ -628,7 +628,7 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c ESP_LOGE(TAG, "mbedtls_ssl_handshake returned -0x%x", -ret); ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED); - if (cfg->cacert_pem_buf != NULL || cfg->use_global_ca_store == true) { + if (cfg->cacert_buf != NULL || cfg->use_global_ca_store == true) { /* This is to check whether handshake failed due to invalid certificate*/ verify_certificate(tls); } diff --git a/components/esp-tls/esp_tls.h b/components/esp-tls/esp_tls.h index ebdffa49e2..ee7fe49de7 100644 --- a/components/esp-tls/esp_tls.h +++ b/components/esp-tls/esp_tls.h @@ -78,6 +78,16 @@ typedef enum esp_tls_role { /** * @brief ESP-TLS configuration parameters + * + * @note Note about format of certificates: + * - This structure includes certificates of a Certificate Authority, of client or server as well + * as private keys, which may be of PEM or DER format. In case of PEM format, the buffer must be + * NULL terminated (with NULL character included in certificate size). + * - Certificate Authority's certificate may be a chain of certificates in case of PEM format, + * but could be only one certificate in case of DER format + * - Variables names of certificates and private key buffers and sizes are defined as unions providing + * backward compatibility for legacy *_pem_buf and *_pem_bytes names which suggested only PEM format + * was supported. It is encouraged to use generic names such as cacert_buf and cacert_bytes. */ typedef struct esp_tls_cfg { const char **alpn_protos; /*!< Application protocols required for HTTP2. @@ -89,29 +99,47 @@ typedef struct esp_tls_cfg { const char **alpn_protos = { "h2", NULL }; - where 'h2' is the protocol name */ - const unsigned char *cacert_pem_buf; /*!< Certificate Authority's certificate in a buffer. + union { + const unsigned char *cacert_buf; /*!< Certificate Authority's certificate in a buffer. Format may be PEM or DER, depending on mbedtls-support This buffer should be NULL terminated in case of PEM */ - - unsigned int cacert_pem_bytes; /*!< Size of Certificate Authority certificate - pointed to by cacert_pem_buf + const unsigned char *cacert_pem_buf; /*!< CA certificate buffer legacy name */ + }; + + union { + unsigned int cacert_bytes; /*!< Size of Certificate Authority certificate + pointed to by cacert_buf (including NULL-terminator in case of PEM format) */ + unsigned int cacert_pem_bytes; /*!< Size of Certificate Authority certificate legacy name */ + }; - const unsigned char *clientcert_pem_buf;/*!< Client certificate in a buffer + union { + const unsigned char *clientcert_buf; /*!< Client certificate in a buffer Format may be PEM or DER, depending on mbedtls-support This buffer should be NULL terminated in case of PEM */ + const unsigned char *clientcert_pem_buf; /*!< Client certificate legacy name */ + }; - unsigned int clientcert_pem_bytes; /*!< Size of client certificate pointed to by + union { + unsigned int clientcert_bytes; /*!< Size of client certificate pointed to by clientcert_pem_buf (including NULL-terminator in case of PEM format) */ + unsigned int clientcert_pem_bytes; /*!< Size of client certificate legacy name */ + }; - const unsigned char *clientkey_pem_buf; /*!< Client key in a buffer + union { + const unsigned char *clientkey_buf; /*!< Client key in a buffer Format may be PEM or DER, depending on mbedtls-support This buffer should be NULL terminated in case of PEM */ + const unsigned char *clientkey_pem_buf; /*!< Client key legacy name */ + }; - unsigned int clientkey_pem_bytes; /*!< Size of client key pointed to by + union { + unsigned int clientkey_bytes; /*!< Size of client key pointed to by clientkey_pem_buf (including NULL-terminator in case of PEM format) */ + unsigned int clientkey_pem_bytes; /*!< Size of client key legacy name */ + }; const unsigned char *clientkey_password;/*!< Client key decryption password string */ @@ -144,23 +172,41 @@ typedef struct esp_tls_cfg_server { const char **alpn_protos = { "h2", NULL }; - where 'h2' is the protocol name */ - const unsigned char *cacert_pem_buf; /*!< Client CA certificate in a buffer. + union { + const unsigned char *cacert_buf; /*!< Client CA certificate in a buffer. This buffer should be NULL terminated */ + const unsigned char *cacert_pem_buf; /*!< Client CA certificate legacy name */ + }; - unsigned int cacert_pem_bytes; /*!< Size of client CA certificate + union { + unsigned int cacert_bytes; /*!< Size of client CA certificate pointed to by cacert_pem_buf */ + unsigned int cacert_pem_bytes; /*!< Size of client CA certificate legacy name */ + }; - const unsigned char *servercert_pem_buf; /*!< Server certificate in a buffer + union { + const unsigned char *servercert_buf; /*!< Server certificate in a buffer This buffer should be NULL terminated */ + const unsigned char *servercert_pem_buf; /*!< Server certificate legacy name */ + }; - unsigned int servercert_pem_bytes; /*!< Size of server certificate pointed to by + union { + unsigned int servercert_bytes; /*!< Size of server certificate pointed to by servercert_pem_buf */ + unsigned int servercert_pem_bytes; /*!< Size of server certificate legacy name */ + }; - const unsigned char *serverkey_pem_buf; /*!< Server key in a buffer + union { + const unsigned char *serverkey_buf; /*!< Server key in a buffer This buffer should be NULL terminated */ + const unsigned char *serverkey_pem_buf; /*!< Server key legacy name */ + }; - unsigned int serverkey_pem_bytes; /*!< Size of server key pointed to by + union { + unsigned int serverkey_bytes; /*!< Size of server key pointed to by serverkey_pem_buf */ + unsigned int serverkey_pem_bytes; /*!< Size of server key legacy name */ + }; const unsigned char *serverkey_password; /*!< Server key decryption password string */ diff --git a/components/esp_https_server/src/https_server.c b/components/esp_https_server/src/https_server.c index f012ffec8e..47c2abcb0f 100644 --- a/components/esp_https_server/src/https_server.c +++ b/components/esp_https_server/src/https_server.c @@ -135,11 +135,11 @@ static void free_secure_context(void *ctx) assert(ctx != NULL); esp_tls_cfg_server_t *cfg = (esp_tls_cfg_server_t *)ctx; ESP_LOGI(TAG, "Server shuts down, releasing SSL context"); - if (cfg->servercert_pem_buf) { - free((void *)cfg->servercert_pem_buf); + if (cfg->servercert_buf) { + free((void *)cfg->servercert_buf); } - if (cfg->serverkey_pem_buf) { - free((void *)cfg->serverkey_pem_buf); + if (cfg->serverkey_buf) { + free((void *)cfg->serverkey_buf); } free(cfg); } @@ -150,22 +150,22 @@ static esp_tls_cfg_server_t *create_secure_context(const struct httpd_ssl_config if (!cfg) { return NULL; } - cfg->servercert_pem_buf = (unsigned char *)malloc(config->cacert_len); - if (!cfg->servercert_pem_buf) { + cfg->servercert_buf = (unsigned char *)malloc(config->cacert_len); + if (!cfg->servercert_buf) { free(cfg); return NULL; } - memcpy((char *)cfg->servercert_pem_buf, config->cacert_pem, config->cacert_len); - cfg->servercert_pem_bytes = config->cacert_len; + memcpy((char *)cfg->servercert_buf, config->cacert_pem, config->cacert_len); + cfg->servercert_bytes = config->cacert_len; - cfg->serverkey_pem_buf = (unsigned char *)malloc(config->prvtkey_len); - if (!cfg->serverkey_pem_buf) { - free((void *)cfg->servercert_pem_buf); + cfg->serverkey_buf = (unsigned char *)malloc(config->prvtkey_len); + if (!cfg->serverkey_buf) { + free((void *)cfg->servercert_buf); free(cfg); return NULL; } - memcpy((char *)cfg->serverkey_pem_buf, config->prvtkey_pem, config->prvtkey_len); - cfg->serverkey_pem_bytes = config->prvtkey_len; + memcpy((char *)cfg->serverkey_buf, config->prvtkey_pem, config->prvtkey_len); + cfg->serverkey_bytes = config->prvtkey_len; return cfg; } diff --git a/components/tcp_transport/transport_ssl.c b/components/tcp_transport/transport_ssl.c index b8a2e7281e..b576d1a487 100644 --- a/components/tcp_transport/transport_ssl.c +++ b/components/tcp_transport/transport_ssl.c @@ -182,8 +182,8 @@ void esp_transport_ssl_set_cert_data_der(esp_transport_handle_t t, const char *d { transport_ssl_t *ssl = esp_transport_get_context_data(t); if (t && ssl) { - ssl->cfg.cacert_pem_buf = (void *)data; - ssl->cfg.cacert_pem_bytes = len; + ssl->cfg.cacert_buf = (void *)data; + ssl->cfg.cacert_bytes = len; } } @@ -200,8 +200,8 @@ void esp_transport_ssl_set_client_cert_data_der(esp_transport_handle_t t, const { transport_ssl_t *ssl = esp_transport_get_context_data(t); if (t && ssl) { - ssl->cfg.clientcert_pem_buf = (void *)data; - ssl->cfg.clientcert_pem_bytes = len; + ssl->cfg.clientcert_buf = (void *)data; + ssl->cfg.clientcert_bytes = len; } } @@ -218,8 +218,8 @@ void esp_transport_ssl_set_client_key_data_der(esp_transport_handle_t t, const c { transport_ssl_t *ssl = esp_transport_get_context_data(t); if (t && ssl) { - ssl->cfg.clientkey_pem_buf = (void *)data; - ssl->cfg.clientkey_pem_bytes = len; + ssl->cfg.clientkey_buf = (void *)data; + ssl->cfg.clientkey_bytes = len; } } diff --git a/examples/protocols/https_request/main/https_request_example_main.c b/examples/protocols/https_request/main/https_request_example_main.c index 742a4657e1..0cd31ec21a 100644 --- a/examples/protocols/https_request/main/https_request_example_main.c +++ b/examples/protocols/https_request/main/https_request_example_main.c @@ -75,8 +75,8 @@ static void https_get_task(void *pvParameters) while(1) { esp_tls_cfg_t cfg = { - .cacert_pem_buf = server_root_cert_pem_start, - .cacert_pem_bytes = server_root_cert_pem_end - server_root_cert_pem_start, + .cacert_buf = server_root_cert_pem_start, + .cacert_bytes = server_root_cert_pem_end - server_root_cert_pem_start, }; struct esp_tls *tls = esp_tls_conn_http_new(WEB_URL, &cfg); From d163b9e6150ce8409aaba9cb80ba4e58419de178 Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Fri, 2 Aug 2019 17:09:33 +0800 Subject: [PATCH 402/486] Fix broken links in 'Getting Started' gudes --- docs/en/get-started/linux-setup-scratch.rst | 2 +- docs/en/get-started/windows-setup-scratch.rst | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/en/get-started/linux-setup-scratch.rst b/docs/en/get-started/linux-setup-scratch.rst index a96992c062..56e590c54a 100644 --- a/docs/en/get-started/linux-setup-scratch.rst +++ b/docs/en/get-started/linux-setup-scratch.rst @@ -66,7 +66,7 @@ Build the toolchain:: ./ct-ng build chmod -R u+w builds/xtensa-esp32-elf -Toolchain will be built in ``~/esp/crosstool-NG/builds/xtensa-esp32-elf``. Follow `instructions for standard setup `_ to add the toolchain to your ``PATH``. +Toolchain will be built in ``~/esp/crosstool-NG/builds/xtensa-esp32-elf``. Follow :ref:`instructions for standard setup ` to add the toolchain to your ``PATH``. Next Steps diff --git a/docs/en/get-started/windows-setup-scratch.rst b/docs/en/get-started/windows-setup-scratch.rst index d0bef754df..3e35f916ea 100644 --- a/docs/en/get-started/windows-setup-scratch.rst +++ b/docs/en/get-started/windows-setup-scratch.rst @@ -56,9 +56,9 @@ Ninja build .. note:: Ninja currently only provides binaries for 64-bit Windows. It is possible to use CMake and ``idf.py`` with other build tools, such as mingw-make, on 32-bit windows. However this is currently undocumented. -Download the ninja_ latest stable Windows release from the (`download page `_). +Download the ninja_ latest stable Windows release from the (`download page `_). -The Ninja for Windows download is a .zip file containing a single ``ninja.exe`` file which needs to be unzipped to a directory which is then `added to your Path `_ (or you can choose a directory which is already on your Path). +The Ninja for Windows download is a .zip file containing a single ``ninja.exe`` file which needs to be unzipped to a directory which is then :ref:`added to your Path ` (or you can choose a directory which is already on your Path). Python 2.x @@ -77,7 +77,7 @@ MConf for IDF Download the configuration tool mconf-idf from the `kconfig-frontends releases page `_. This is the ``mconf`` configuration tool with some minor customizations for ESP-IDF. -This tool will also need to be unzipped to a directory which is then `added to your Path `_. +This tool will also need to be unzipped to a directory which is then :ref:`added to your Path `. Toolchain Setup =============== @@ -90,7 +90,7 @@ Download the precompiled Windows toolchain: Unzip the zip file to ``C:\Program Files`` (or some other location). The zip file contains a single directory ``xtensa-esp32-elf``. -Next, the ``bin`` subdirectory of this directory must be `added to your Path `_. For example, the directory to add may be ``C:\Program Files\xtensa-esp32-elf\bin``. +Next, the ``bin`` subdirectory of this directory must be :ref:`added to your Path `. For example, the directory to add may be ``C:\Program Files\xtensa-esp32-elf\bin``. .. note:: If you already have the MSYS2 environment (for use with the "GNU Make" build system) installed, you can skip the separate download and add the directory ``C:\msys32\opt\xtensa-esp32-elf\bin`` to the Path instead, as the toolchain is included in the MSYS2 environment. @@ -114,6 +114,7 @@ Next Steps To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf`. .. _ninja: https://ninja-build.org/ +.. _ninja-dl: https://github.com/ninja-build/ninja/releases .. _Python: https://www.python.org/downloads/windows/ .. _MSYS2: https://msys2.github.io/ .. _Stable version: https://docs.espressif.com/projects/esp-idf/en/stable/ From 164fd5ad2984a0be2ad49720f5ac7b9e95a6aa69 Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Fri, 2 Aug 2019 17:58:08 +0800 Subject: [PATCH 403/486] More link corrections --- docs/en/get-started/windows-setup-scratch.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/en/get-started/windows-setup-scratch.rst b/docs/en/get-started/windows-setup-scratch.rst index 3e35f916ea..1c59b9648d 100644 --- a/docs/en/get-started/windows-setup-scratch.rst +++ b/docs/en/get-started/windows-setup-scratch.rst @@ -75,7 +75,7 @@ Once Python is installed, open a Windows Command Prompt from the Start menu and MConf for IDF ^^^^^^^^^^^^^ -Download the configuration tool mconf-idf from the `kconfig-frontends releases page `_. This is the ``mconf`` configuration tool with some minor customizations for ESP-IDF. +Download the configuration tool mconf-idf from the `kconfig-frontends releases page`_. This is the ``mconf`` configuration tool with some minor customizations for ESP-IDF. This tool will also need to be unzipped to a directory which is then :ref:`added to your Path `. @@ -113,9 +113,11 @@ Next Steps To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf`. +.. _CMake: https://cmake.org/download/ .. _ninja: https://ninja-build.org/ .. _ninja-dl: https://github.com/ninja-build/ninja/releases .. _Python: https://www.python.org/downloads/windows/ .. _MSYS2: https://msys2.github.io/ +.. _kconfig-frontends releases page: https://github.com/espressif/kconfig-frontends/releases .. _Stable version: https://docs.espressif.com/projects/esp-idf/en/stable/ From 146f120f794532b4fdd3709fc4e870c46c06c0a4 Mon Sep 17 00:00:00 2001 From: Hrishikesh Dhayagude Date: Fri, 2 Aug 2019 18:01:58 +0800 Subject: [PATCH 404/486] examples/bluetooth: Move the demos to the appropriate locations --- .../bluetooth/{ => bluedroid/ble}/ble_ancs/CMakeLists.txt | 0 examples/bluetooth/{ => bluedroid/ble}/ble_ancs/Makefile | 0 examples/bluetooth/{ => bluedroid/ble}/ble_ancs/README.md | 0 .../{ => bluedroid/ble}/ble_ancs/main/CMakeLists.txt | 0 .../bluetooth/{ => bluedroid/ble}/ble_ancs/main/ble_ancs.c | 0 .../bluetooth/{ => bluedroid/ble}/ble_ancs/main/ble_ancs.h | 0 .../{ => bluedroid/ble}/ble_ancs/main/ble_ancs_demo.c | 0 .../bluetooth/{ => bluedroid/ble}/ble_ancs/main/component.mk | 0 .../bluetooth/{ => bluedroid/ble}/ble_ancs/sdkconfig.defaults | 0 .../{ => bluedroid/ble}/ble_compatibility_test/README.md | 4 ++-- 10 files changed, 2 insertions(+), 2 deletions(-) rename examples/bluetooth/{ => bluedroid/ble}/ble_ancs/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_ancs/Makefile (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_ancs/README.md (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_ancs/main/CMakeLists.txt (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_ancs/main/ble_ancs.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_ancs/main/ble_ancs.h (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_ancs/main/ble_ancs_demo.c (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_ancs/main/component.mk (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_ancs/sdkconfig.defaults (100%) rename examples/bluetooth/{ => bluedroid/ble}/ble_compatibility_test/README.md (68%) diff --git a/examples/bluetooth/ble_ancs/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_ancs/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_ancs/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_ancs/CMakeLists.txt diff --git a/examples/bluetooth/ble_ancs/Makefile b/examples/bluetooth/bluedroid/ble/ble_ancs/Makefile similarity index 100% rename from examples/bluetooth/ble_ancs/Makefile rename to examples/bluetooth/bluedroid/ble/ble_ancs/Makefile diff --git a/examples/bluetooth/ble_ancs/README.md b/examples/bluetooth/bluedroid/ble/ble_ancs/README.md similarity index 100% rename from examples/bluetooth/ble_ancs/README.md rename to examples/bluetooth/bluedroid/ble/ble_ancs/README.md diff --git a/examples/bluetooth/ble_ancs/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_ancs/main/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_ancs/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_ancs/main/CMakeLists.txt diff --git a/examples/bluetooth/ble_ancs/main/ble_ancs.c b/examples/bluetooth/bluedroid/ble/ble_ancs/main/ble_ancs.c similarity index 100% rename from examples/bluetooth/ble_ancs/main/ble_ancs.c rename to examples/bluetooth/bluedroid/ble/ble_ancs/main/ble_ancs.c diff --git a/examples/bluetooth/ble_ancs/main/ble_ancs.h b/examples/bluetooth/bluedroid/ble/ble_ancs/main/ble_ancs.h similarity index 100% rename from examples/bluetooth/ble_ancs/main/ble_ancs.h rename to examples/bluetooth/bluedroid/ble/ble_ancs/main/ble_ancs.h diff --git a/examples/bluetooth/ble_ancs/main/ble_ancs_demo.c b/examples/bluetooth/bluedroid/ble/ble_ancs/main/ble_ancs_demo.c similarity index 100% rename from examples/bluetooth/ble_ancs/main/ble_ancs_demo.c rename to examples/bluetooth/bluedroid/ble/ble_ancs/main/ble_ancs_demo.c diff --git a/examples/bluetooth/ble_ancs/main/component.mk b/examples/bluetooth/bluedroid/ble/ble_ancs/main/component.mk similarity index 100% rename from examples/bluetooth/ble_ancs/main/component.mk rename to examples/bluetooth/bluedroid/ble/ble_ancs/main/component.mk diff --git a/examples/bluetooth/ble_ancs/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/ble_ancs/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_ancs/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/ble_ancs/sdkconfig.defaults diff --git a/examples/bluetooth/ble_compatibility_test/README.md b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/README.md similarity index 68% rename from examples/bluetooth/ble_compatibility_test/README.md rename to examples/bluetooth/bluedroid/ble/ble_compatibility_test/README.md index 928a4b6a77..3102fc5e57 100644 --- a/examples/bluetooth/ble_compatibility_test/README.md +++ b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/README.md @@ -7,10 +7,10 @@ This demo is to test the compatibility of Bluetooth and mobile phones. * IDF version: 7c29a39d6f9f2dfbefc49d34d34e9267afc7200d -* [Test case](https://github.com/espressif/esp-idf/blob/master/examples/bluetooth/ble_compatibility_test/ble_compatibility_test_case.md) +* [Test case](https://github.com/espressif/esp-idf/blob/master/examples/bluetooth/bluedroid/ble/ble_compatibility_test/ble_compatibility_test_case.md) * Test APK: LightBlue V1.1.3 -* [Test report](https://github.com/espressif/esp-idf/blob/master/examples/bluetooth/ble_compatibility_test/esp_ble_compatibility_test_report.md) +* [Test report](https://github.com/espressif/esp-idf/blob/master/examples/bluetooth/bluedroid/ble/ble_compatibility_test/esp_ble_compatibility_test_report.md) From e7dba7d7bc6218eea440dfe6f55592b8c21f6083 Mon Sep 17 00:00:00 2001 From: Mahavir Jain Date: Fri, 2 Aug 2019 09:01:20 +0530 Subject: [PATCH 405/486] examples: change default build instructions in docs to CMake --- examples/README.md | 4 ++-- examples/bluetooth/bluedroid/ble/ble_spp_client/README.md | 2 +- .../bluetooth/bluedroid/classic_bt/a2dp_sink/README.md | 2 +- .../ble_mesh_fast_prov_server/tutorial/EspBleMesh.md | 4 ++-- examples/bluetooth/esp_ble_mesh/ble_mesh_node/README.md | 4 ++-- .../tutorial/Ble_Mesh_Node_Example_Walkthrough.md | 8 ++++---- .../tutorial/ble_mesh_wifi_coexist.md | 6 +++--- examples/bluetooth/nimble/blecent/README.md | 4 ++-- examples/bluetooth/nimble/blehr/README.md | 4 ++-- examples/bluetooth/nimble/blemesh/README.md | 4 ++-- examples/bluetooth/nimble/bleprph/README.md | 4 ++-- examples/ethernet/basic/README.md | 4 ++-- examples/ethernet/iperf/README.md | 4 ++-- examples/peripherals/adc/README.md | 6 +++--- examples/peripherals/adc2/README.md | 6 +++--- examples/peripherals/i2s/README.md | 6 +++--- examples/peripherals/i2s_adc_dac/README.md | 6 +++--- examples/peripherals/ledc/README.md | 6 +++--- examples/peripherals/pcnt/README.md | 6 +++--- examples/peripherals/rmt_nec_tx_rx/README.md | 6 +++--- examples/peripherals/rmt_tx/README.md | 6 +++--- examples/peripherals/sigmadelta/README.md | 4 ++-- examples/peripherals/uart/uart_async_rxtxtasks/README.md | 6 +++--- examples/peripherals/uart/uart_echo/README.md | 6 +++--- examples/peripherals/uart/uart_echo_rs485/README.md | 6 +++--- examples/peripherals/uart/uart_events/README.md | 6 +++--- examples/peripherals/uart/uart_select/README.md | 6 +++--- examples/protocols/asio/chat_client/README.md | 2 +- examples/protocols/coap_client/README.md | 4 ++-- examples/protocols/coap_server/README.md | 4 ++-- examples/protocols/esp_local_ctrl/README.md | 2 +- examples/protocols/esp_local_ctrl/main/app_main.c | 2 +- examples/protocols/http_server/file_serving/README.md | 2 +- examples/protocols/mdns/README.md | 2 +- examples/protocols/modbus_master/README.md | 4 ++-- examples/protocols/modbus_slave/README.md | 4 ++-- examples/protocols/mqtt/publish_test/README.md | 2 +- examples/protocols/mqtt/ssl/README.md | 2 +- examples/protocols/mqtt/ssl_mutual_auth/README.md | 2 +- examples/protocols/mqtt/tcp/README.md | 4 ++-- examples/protocols/mqtt/ws/README.md | 2 +- examples/protocols/mqtt/wss/README.md | 2 +- examples/protocols/sockets/README.md | 4 ++-- examples/protocols/sockets/tcp_client/README.md | 4 ++-- examples/protocols/sockets/tcp_server/README.md | 4 ++-- examples/protocols/sockets/udp_client/README.md | 4 ++-- examples/protocols/sockets/udp_server/README.md | 4 ++-- examples/provisioning/ble_prov/README.md | 6 +++--- examples/provisioning/console_prov/README.md | 6 +++--- examples/provisioning/custom_config/README.md | 6 +++--- examples/provisioning/manager/README.md | 4 ++-- examples/provisioning/softap_prov/README.md | 6 +++--- examples/security/flash_encryption/README.md | 8 ++++---- examples/storage/spiffsgen/README.md | 8 ++++---- examples/storage/spiffsgen/main/CMakeLists.txt | 2 +- examples/system/freertos/real_time_stats/README.md | 4 ++-- examples/system/himem/README.md | 4 ++-- examples/system/network_tests/README.md | 5 ++--- examples/wifi/espnow/README.md | 4 ++-- examples/wifi/getting_started/softAP/README.md | 4 ++-- examples/wifi/getting_started/station/README.md | 4 ++-- examples/wifi/power_save/main/power_save.c | 2 +- examples/wifi/smart_config/README.md | 4 ++-- 63 files changed, 136 insertions(+), 137 deletions(-) diff --git a/examples/README.md b/examples/README.md index e5b4a0c4fc..9728c32166 100644 --- a/examples/README.md +++ b/examples/README.md @@ -26,8 +26,8 @@ Building an example is the same as building any other project: * Follow the Getting Started instructions which include building the "Hello World" example. * Change into the directory of the new example you'd like to build. * Run `idf.py menuconfig` to open the project configuration menu. Most examples have a project-specific "Example Configuration" section here (for example, to set the WiFi SSID & password to use). -* `make` to build the example. -* Follow the printed instructions to flash, or run `idf.py flash`. +* `idf.py build` to build the example. +* Follow the printed instructions to flash, or run `idf.py -p PORT flash`. # Copying Examples diff --git a/examples/bluetooth/bluedroid/ble/ble_spp_client/README.md b/examples/bluetooth/bluedroid/ble/ble_spp_client/README.md index afae60f766..a384731266 100644 --- a/examples/bluetooth/bluedroid/ble/ble_spp_client/README.md +++ b/examples/bluetooth/bluedroid/ble/ble_spp_client/README.md @@ -81,7 +81,7 @@ Build each project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/README.md b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/README.md index 7d0889eccc..cd57b59d7e 100644 --- a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/README.md +++ b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/README.md @@ -40,7 +40,7 @@ idf.py menuconfig Build the project and flash it to the board, then run monitor tool to view serial output. ``` -idf.py flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/EspBleMesh.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/EspBleMesh.md index 0d087ce2d9..8039d6672c 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/EspBleMesh.md +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/tutorial/EspBleMesh.md @@ -16,7 +16,7 @@ A video of this demo can be seen > 1. Please flash the [`ble_mesh_fast_prov_server`](https://glab.espressif.cn/ble_mesh/esp-ble-mesh-v0.6/tree/ble_mesh_release/esp-ble-mesh-v0.6/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server) to your boards first; > 2. To have a better understanding of the performance of the BLE Mesh network, we recommend that at least 3 devices should be added in your network. > 3. We recommend that you solder LED indicators if your development board does not come with lights. -> 4. Please check the type of board and LED pin definition enabled in `Example BLE Mesh Config` by running `make menuconfig` +> 4. Please check the type of board and LED pin definition enabled in `Example BLE Mesh Config` by running `idf.py menuconfig` ![Board](images/device.png) @@ -30,7 +30,7 @@ examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_serve ![Checkenvironment](images/picture1.png) -4. Run `make -j4 flash` to compile codes and flash the codes to the device. +4. Run `idf.py -p PORT flash` to compile codes and flash the codes to the device. ![compiledcode](images/picture2.png) diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_node/README.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_node/README.md index c84d2dfd00..85b2147ee5 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_node/README.md +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_node/README.md @@ -8,9 +8,9 @@ This demo shows how BLE Mesh device can be set up as a node with the following f - **Configuration Server model**: The role of this model is mainly to configure Provisioner device’s AppKey and set up its relay function, TTL size, subscription, etc. - **OnOff Server model**: This model implements the most basic function of turning the lights on and off. -The default purpose of this demo is to enable the advertising function with 20-ms non-connectable interval in BLE 5.0. You can disable this function through menuconfig: `make menuconfig --> Example Configuration --> This option facilitates sending with 20ms non-connectable interval...` +The default purpose of this demo is to enable the advertising function with 20-ms non-connectable interval in BLE 5.0. You can disable this function through menuconfig: `idf.py menuconfig --> Example Configuration --> This option facilitates sending with 20ms non-connectable interval...` For a better demonstration effect, an RGB LED can be soldered onto the ESP32-DevKitC board, by connecting their corresponding GPIO pins are GPIO\_NUM\_25, GPIO\_NUM\_26, GPIO\_NUM\_27. Then you need to select the following option in menuconfig: - `make menuconfig --> Example Configuration --> Board selection for BLE Mesh --> ESP-WROOM-32` + `idf.py menuconfig --> Example Configuration --> Board selection for BLE Mesh --> ESP-WROOM-32` Please check the [tutorial](tutorial/Ble_Mesh_Node_Example_Walkthrough.md) for more information about this example. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_node/tutorial/Ble_Mesh_Node_Example_Walkthrough.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_node/tutorial/Ble_Mesh_Node_Example_Walkthrough.md index 8776590045..cdde9bfdb1 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_node/tutorial/Ble_Mesh_Node_Example_Walkthrough.md +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_node/tutorial/Ble_Mesh_Node_Example_Walkthrough.md @@ -27,9 +27,9 @@ $ tree examples/bluetooth/esp_ble_mesh/ble_mesh/ble_mesh_node ├── README.md /* Quick start guide */ ├── build ├── main /* Stores the `.c` and `.h` application code files for this demo */ -├── sdkconfig /* Current parameters of `make menuconfig` */ -├── sdkconfig.defaults /* Default parameters of `make menuconfig` */ -├── sdkconfig.old /* Previously saved parameters of `make menuconfig` */ +├── sdkconfig /* Current parameters of `idf.py menuconfig` */ +├── sdkconfig.defaults /* Default parameters of `idf.py menuconfig` */ +├── sdkconfig.old /* Previously saved parameters of `idf.py menuconfig` */ └── tutorial /* More in-depth information about the demo */ ``` @@ -381,7 +381,7 @@ These variables should be set to `0` for this demo, as it uses the most basic au To be functional across different applications, the BLE Mesh menuconfig is specifically designed to offer a variety of configuration options, which can be helpful in tailoring your own configuration. -The list of configuration options in BLE Mesh menuconfig is stored in `Component config` ---> `[]Bluetooth Mesh support` and can be accessed with the command `make menuconfig`. This configuration option list is shown below. +The list of configuration options in BLE Mesh menuconfig is stored in `Component config` ---> `[]Bluetooth Mesh support` and can be accessed with the command `idf.py menuconfig`. This configuration option list is shown below. ``` —— Bluetooth Mesh support diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/tutorial/ble_mesh_wifi_coexist.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/tutorial/ble_mesh_wifi_coexist.md index e60446ca72..2acdb4764c 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/tutorial/ble_mesh_wifi_coexist.md +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/tutorial/ble_mesh_wifi_coexist.md @@ -40,9 +40,9 @@ $ tree examples/bluetooth/esp_ble_mesh/ble_mesh/ble_mesh_wifi_coexist ├── Makefile /* Compiling parameters for the demo */ ├── README.md /* Quick start guide */ ├── build -├── sdkconfig /* Current parameters of `make menuconfig` */ -├── sdkconfig.defaults /* Default parameters of `make menuconfig` */ -├── sdkconfig.old /* Previously saved parameters of `make menuconfig` */ +├── sdkconfig /* Current parameters of `idf.py menuconfig` */ +├── sdkconfig.defaults /* Default parameters of `idf.py menuconfig` */ +├── sdkconfig.old /* Previously saved parameters of `idf.py menuconfig` */ └── tutorial /* More in-depth information about the demo */ ``` diff --git a/examples/bluetooth/nimble/blecent/README.md b/examples/bluetooth/nimble/blecent/README.md index 4b531f9787..7724aba48f 100644 --- a/examples/bluetooth/nimble/blecent/README.md +++ b/examples/bluetooth/nimble/blecent/README.md @@ -32,7 +32,7 @@ Note : ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -42,7 +42,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/bluetooth/nimble/blehr/README.md b/examples/bluetooth/nimble/blehr/README.md index af4b0581f6..067769dccc 100644 --- a/examples/bluetooth/nimble/blehr/README.md +++ b/examples/bluetooth/nimble/blehr/README.md @@ -23,7 +23,7 @@ Note : ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -33,7 +33,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/bluetooth/nimble/blemesh/README.md b/examples/bluetooth/nimble/blemesh/README.md index 0f991b5996..9c44bbb254 100644 --- a/examples/bluetooth/nimble/blemesh/README.md +++ b/examples/bluetooth/nimble/blemesh/README.md @@ -20,7 +20,7 @@ To test this demo, any BLE mesh provisioner app can be used. ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -32,7 +32,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/bluetooth/nimble/bleprph/README.md b/examples/bluetooth/nimble/bleprph/README.md index 6f0d96e8a5..b518c81f82 100644 --- a/examples/bluetooth/nimble/bleprph/README.md +++ b/examples/bluetooth/nimble/bleprph/README.md @@ -24,7 +24,7 @@ Note : ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -38,7 +38,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/ethernet/basic/README.md b/examples/ethernet/basic/README.md index 57f4b472cd..8f5552dcf0 100644 --- a/examples/ethernet/basic/README.md +++ b/examples/ethernet/basic/README.md @@ -21,7 +21,7 @@ To run this example, it's recommended that you have an official ESP32 Ethernet d ### Project configuration in menuconfig -Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you' are using CMake based build system. +Enter `idf.py menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you' are using CMake based build system. 1. In the `Example Configuration` menu: * Choose the kind of Ethernet this example will run on under `Ethernet Type`. @@ -59,7 +59,7 @@ Enter `make menuconfig` if you are using GNU Make based build system or enter `i ### Build and Flash -Enter `make -j4 flash monitor` if you are using GNU Make based build system or enter `idf.py build flash monitor` if you' are using CMake based build system. +Enter `idf.py -p PORT flash monitor` if you are using GNU Make based build system or enter `idf.py build flash monitor` if you' are using CMake based build system. (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/ethernet/iperf/README.md b/examples/ethernet/iperf/README.md index c75e90096a..b33bab61d7 100644 --- a/examples/ethernet/iperf/README.md +++ b/examples/ethernet/iperf/README.md @@ -25,7 +25,7 @@ To run this example, it's recommended that you have an official ESP32 Ethernet d ### Project configuration in menuconfig -Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you' are using CMake based build system. +Enter `idf.py menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you' are using CMake based build system. 1. In the `Example Configuration` menu: * Enable storing history commands in flash under `Store command history in flash`. @@ -63,7 +63,7 @@ Enter `make menuconfig` if you are using GNU Make based build system or enter `i ### Build and Flash -Enter `make -j4 flash monitor` if you are using GNU Make based build system or enter `idf.py build flash monitor` if you' are using CMake based build system. +Enter `idf.py -p PORT flash monitor` if you are using GNU Make based build system or enter `idf.py build flash monitor` if you' are using CMake based build system. (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/peripherals/adc/README.md b/examples/peripherals/adc/README.md index 47f58c94b9..b392e99570 100644 --- a/examples/peripherals/adc/README.md +++ b/examples/peripherals/adc/README.md @@ -16,7 +16,7 @@ In this example, we use `ADC_UNIT_1` by default, we need to connect a voltage so ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -26,7 +26,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) @@ -48,7 +48,7 @@ Raw: 18 Voltage: 79mV * program upload failure - * Hardware connection is not correct: run `idf.py monitor`, and reboot your board to see if there are any output logs. + * Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs. * The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again. For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/adc2/README.md b/examples/peripherals/adc2/README.md index 32b94f68ed..3130072b57 100644 --- a/examples/peripherals/adc2/README.md +++ b/examples/peripherals/adc2/README.md @@ -16,7 +16,7 @@ We use ADC1_CHANNEL_7 (GPIO27) and DAC_CHANNEL_1 (GPIO25) by default, you need t ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -27,7 +27,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) @@ -59,7 +59,7 @@ start conversion. * program upload failure - * Hardware connection is not correct: run `idf.py monitor`, and reboot your board to see if there are any output logs. + * Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs. * The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again. For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/i2s/README.md b/examples/peripherals/i2s/README.md index a02f3e5e60..11c881dfa6 100644 --- a/examples/peripherals/i2s/README.md +++ b/examples/peripherals/i2s/README.md @@ -14,7 +14,7 @@ In this example, we generate a 100Hz triangle and sine wave and send it out from ### Configure the Project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -24,7 +24,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) @@ -61,7 +61,7 @@ If you have a logic analyzer, you can use a logic analyzer to grab online data. * Program upload failure - * Hardware connection is not correct: run `idf.py monitor`, and reboot your board to see if there are any output logs. + * Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs. * The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again. For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/i2s_adc_dac/README.md b/examples/peripherals/i2s_adc_dac/README.md index 7d43ef845a..c3c85b6c74 100644 --- a/examples/peripherals/i2s_adc_dac/README.md +++ b/examples/peripherals/i2s_adc_dac/README.md @@ -35,7 +35,7 @@ The following is the hardware connection: ### Configure the Project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options, the flash size should be set to 4 MB. @@ -48,7 +48,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) @@ -85,7 +85,7 @@ I2S: PLL_D2: Req RATE: 16000, real rate: 1004.000, BITS: 16, CLKM: 83, BCK: 60, * Program upload failure - * Hardware connection is not correct: run `idf.py monitor`, and reboot your board to see if there are any output logs. + * Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs. * The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again. For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/ledc/README.md b/examples/peripherals/ledc/README.md index c66fa19ddc..542d0b3762 100644 --- a/examples/peripherals/ledc/README.md +++ b/examples/peripherals/ledc/README.md @@ -23,7 +23,7 @@ Connect four LEDs to the following LEDC channels / individual GPIOs: ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -33,7 +33,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) @@ -63,7 +63,7 @@ you can also see the following output log on the serial monitor: * Programming fail - * Hardware connection is not correct: run `idf.py monitor`, and reboot your board to see if there are any output logs. + * Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs. * The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again. For any technical queries, please open an [issue] (https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/pcnt/README.md b/examples/peripherals/pcnt/README.md index 6e0beb6c07..84721c562b 100644 --- a/examples/peripherals/pcnt/README.md +++ b/examples/peripherals/pcnt/README.md @@ -20,7 +20,7 @@ Pin connection: ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -30,7 +30,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) @@ -68,7 +68,7 @@ Current counter value :-1 * program upload failure - * Hardware connection is not correct: run `idf.py monitor`, and reboot your board to see if there are any output logs. + * Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs. * The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again. For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/rmt_nec_tx_rx/README.md b/examples/peripherals/rmt_nec_tx_rx/README.md index 073859111d..e5a15025de 100644 --- a/examples/peripherals/rmt_nec_tx_rx/README.md +++ b/examples/peripherals/rmt_nec_tx_rx/README.md @@ -25,7 +25,7 @@ The TX pin and RX pin can be modified in top of the main/infrared_nec_main.c fil ### Configure the Project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -35,7 +35,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) @@ -74,7 +74,7 @@ NEC: RMT RCV --- addr: 0xda25 cmd: 0xeb14 * Programming fail - * Hardware connection is not correct: run `idf.py monitor`, and reboot your board to see if there is any output logs. + * Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there is any output logs. * The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again. For any technical queries, please open an [issue] (https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/rmt_tx/README.md b/examples/peripherals/rmt_tx/README.md index 6b7f1ff171..cd32a7e2b7 100644 --- a/examples/peripherals/rmt_tx/README.md +++ b/examples/peripherals/rmt_tx/README.md @@ -30,7 +30,7 @@ GPIO18 +----/\/\/\----+------|>|-----+ GND ### Configure the Project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -40,7 +40,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) @@ -61,7 +61,7 @@ RMT Tx: Sample transmission complete * Programming fail - * Hardware connection is not correct: run `idf.py monitor`, and reboot your board to see if there is any output logs. + * Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there is any output logs. * The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again. For any technical queries, please open an [issue] (https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/sigmadelta/README.md b/examples/peripherals/sigmadelta/README.md index 23af6cf8de..14e0dacfef 100644 --- a/examples/peripherals/sigmadelta/README.md +++ b/examples/peripherals/sigmadelta/README.md @@ -24,7 +24,7 @@ By default the GPIO output is 4. To change it, edit the line with `GPIO_NUM_4` i ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` Set serial port under Serial Flasher Options and save the configuration. @@ -35,7 +35,7 @@ Set serial port under Serial Flasher Options and save the configuration. Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/peripherals/uart/uart_async_rxtxtasks/README.md b/examples/peripherals/uart/uart_async_rxtxtasks/README.md index d103ccf541..3bc54d5784 100644 --- a/examples/peripherals/uart/uart_async_rxtxtasks/README.md +++ b/examples/peripherals/uart/uart_async_rxtxtasks/README.md @@ -24,7 +24,7 @@ order to receive back the same data which were sent out. ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` or ``` @@ -38,11 +38,11 @@ idf.py menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` or ``` -idf.py flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/peripherals/uart/uart_echo/README.md b/examples/peripherals/uart/uart_echo/README.md index 797393a85d..6da7c5c6e9 100644 --- a/examples/peripherals/uart/uart_echo/README.md +++ b/examples/peripherals/uart/uart_echo/README.md @@ -36,7 +36,7 @@ UART1 driver to use the hardware flow control by setting `.flow_ctrl = UART_HW_F ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` or ``` @@ -50,11 +50,11 @@ idf.py menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` or ``` -idf.py flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/peripherals/uart/uart_echo_rs485/README.md b/examples/peripherals/uart/uart_echo_rs485/README.md index f2c23f7c9b..97c3373ba0 100644 --- a/examples/peripherals/uart/uart_echo_rs485/README.md +++ b/examples/peripherals/uart/uart_echo_rs485/README.md @@ -45,7 +45,7 @@ Connect USB to RS485 adapter to computer and connect its D+, D- output lines wit ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` or ``` @@ -56,11 +56,11 @@ idf.py menuconfig ### Build and Flash Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` or ``` -idf.py flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/peripherals/uart/uart_events/README.md b/examples/peripherals/uart/uart_events/README.md index 677ffe4b00..5cd3898e70 100644 --- a/examples/peripherals/uart/uart_events/README.md +++ b/examples/peripherals/uart/uart_events/README.md @@ -14,7 +14,7 @@ The example can be used with any ESP32 development board connected to a computer ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` or ``` @@ -28,11 +28,11 @@ idf.py menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` or ``` -idf.py flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/peripherals/uart/uart_select/README.md b/examples/peripherals/uart/uart_select/README.md index f02f6b7f4e..ffe87895c2 100644 --- a/examples/peripherals/uart/uart_select/README.md +++ b/examples/peripherals/uart/uart_select/README.md @@ -26,7 +26,7 @@ through UART. ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` or ``` @@ -40,11 +40,11 @@ idf.py menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` or ``` -idf.py flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/protocols/asio/chat_client/README.md b/examples/protocols/asio/chat_client/README.md index edc4c71897..bcc2bd4d5e 100644 --- a/examples/protocols/asio/chat_client/README.md +++ b/examples/protocols/asio/chat_client/README.md @@ -6,7 +6,7 @@ Simple Asio chat client using WiFi STA or Ethernet. - Wi-Fi or Ethernet connection is established, and IP address is obtained. - Asio chat client connects to the corresponding server whose port number and IP are defined through the project configuration menu. -- Chat client receives all messages from other chat clients, also it sends message received from stdin using `idf.py monitor`. +- Chat client receives all messages from other chat clients, also it sends message received from stdin using `idf.py -p PORT monitor`. ## Running the example diff --git a/examples/protocols/coap_client/README.md b/examples/protocols/coap_client/README.md index d058e3c311..bc3159dbb7 100644 --- a/examples/protocols/coap_client/README.md +++ b/examples/protocols/coap_client/README.md @@ -16,7 +16,7 @@ please refer to [RFC7252](https://www.rfc-editor.org/rfc/pdfrfc/rfc7252.txt.pdf) ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher config @@ -29,7 +29,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/protocols/coap_server/README.md b/examples/protocols/coap_server/README.md index 44366936d0..cf00279a49 100644 --- a/examples/protocols/coap_server/README.md +++ b/examples/protocols/coap_server/README.md @@ -16,7 +16,7 @@ please refer to [RFC7252](https://www.rfc-editor.org/rfc/pdfrfc/rfc7252.txt.pdf) ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set default serial port under Serial Flasher config @@ -28,7 +28,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/protocols/esp_local_ctrl/README.md b/examples/protocols/esp_local_ctrl/README.md index 81abdea2e8..b16b485470 100644 --- a/examples/protocols/esp_local_ctrl/README.md +++ b/examples/protocols/esp_local_ctrl/README.md @@ -4,7 +4,7 @@ This example creates a `esp_local_ctrl` service over HTTPS transport, for secure See the `esp_local_ctrl` component documentation for details. -Before using the example, run `make menuconfig` (or `idf.py menuconfig` if using CMake build system) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../README.md) for more details. +Before using the example, run `idf.py menuconfig` (or `idf.py menuconfig` if using CMake build system) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../README.md) for more details. ## Client Side Implementation diff --git a/examples/protocols/esp_local_ctrl/main/app_main.c b/examples/protocols/esp_local_ctrl/main/app_main.c index d19feffda1..521be92b5d 100644 --- a/examples/protocols/esp_local_ctrl/main/app_main.c +++ b/examples/protocols/esp_local_ctrl/main/app_main.c @@ -20,7 +20,7 @@ #include "lwip/err.h" #include "lwip/sys.h" -/* The examples use WiFi configuration that you can set via 'make menuconfig'. +/* The examples use WiFi configuration that you can set via 'idf.py menuconfig'. If you'd rather not, just change the below entries to strings with the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid" diff --git a/examples/protocols/http_server/file_serving/README.md b/examples/protocols/http_server/file_serving/README.md index 475cd7b0c7..e4a891dd41 100644 --- a/examples/protocols/http_server/file_serving/README.md +++ b/examples/protocols/http_server/file_serving/README.md @@ -27,7 +27,7 @@ File server implementation can be found under `main/file_server.c` which uses SP * In order to test the file server demo : 1. compile and burn the firmware `idf.py -p PORT flash` - 2. run `idf.py monitor` and note down the IP assigned to your ESP module. The default port is 80 + 2. run `idf.py -p PORT monitor` and note down the IP assigned to your ESP module. The default port is 80 3. test the example interactively on a web browser (assuming IP is 192.168.43.130): 1. open path `http://192.168.43.130/` or `http://192.168.43.130/index.html` to see an HTML web page with list of files on the server (initially empty) 2. use the file upload form on the webpage to select and upload a file to the server diff --git a/examples/protocols/mdns/README.md b/examples/protocols/mdns/README.md index 2392699b60..2b99f2d4c2 100644 --- a/examples/protocols/mdns/README.md +++ b/examples/protocols/mdns/README.md @@ -24,7 +24,7 @@ Shows how to use mDNS to advertise lookup services and hosts Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` - Wait for WiFi to connect to your access point diff --git a/examples/protocols/modbus_master/README.md b/examples/protocols/modbus_master/README.md index bcd24b2946..c700f4b29b 100644 --- a/examples/protocols/modbus_master/README.md +++ b/examples/protocols/modbus_master/README.md @@ -72,7 +72,7 @@ ESP32 WROVER KIT 1 | | RS-485 side | | Exter ### Configure the application Configure the UART pins used for modbus communication using command and table below. ``` -make menuconfig +idf.py menuconfig ``` ``` @@ -98,7 +98,7 @@ Other option is to have the modbus_slave example flashed into ESP32 WROVER KIT b ### Build and flash software of master device Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/protocols/modbus_slave/README.md b/examples/protocols/modbus_slave/README.md index 6ef854836b..6d671781f1 100644 --- a/examples/protocols/modbus_slave/README.md +++ b/examples/protocols/modbus_slave/README.md @@ -30,7 +30,7 @@ ESP32 WROVER KIT 1 | | RS-485 side | | Modbus ### Configure the application Configure the UART pins used for modbus communication using command and table below. ``` -make menuconfig +idf.py menuconfig ``` ``` @@ -53,7 +53,7 @@ As an example the Modbus Poll application can be used with this example. ### Build and flash software Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/protocols/mqtt/publish_test/README.md b/examples/protocols/mqtt/publish_test/README.md index d3db836410..ee377d5a64 100644 --- a/examples/protocols/mqtt/publish_test/README.md +++ b/examples/protocols/mqtt/publish_test/README.md @@ -33,7 +33,7 @@ This example can be executed on any ESP32 board, the only required interface is Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/protocols/mqtt/ssl/README.md b/examples/protocols/mqtt/ssl/README.md index db711fdcf1..e2693729d4 100644 --- a/examples/protocols/mqtt/ssl/README.md +++ b/examples/protocols/mqtt/ssl/README.md @@ -33,7 +33,7 @@ with text operation. Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/protocols/mqtt/ssl_mutual_auth/README.md b/examples/protocols/mqtt/ssl_mutual_auth/README.md index bf5b57d704..0696a4e16e 100644 --- a/examples/protocols/mqtt/ssl_mutual_auth/README.md +++ b/examples/protocols/mqtt/ssl_mutual_auth/README.md @@ -43,7 +43,7 @@ Please note, that the supplied files `client.crt` and `client.key` in the `main` Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/protocols/mqtt/tcp/README.md b/examples/protocols/mqtt/tcp/README.md index 7920a75e9e..7fe788cd1a 100644 --- a/examples/protocols/mqtt/tcp/README.md +++ b/examples/protocols/mqtt/tcp/README.md @@ -1,7 +1,7 @@ # ESP-MQTT sample application (See the README.md file in the upper level 'examples' directory for more information about examples.) -This example connects to the broker URI selected using `make menuconfig` (using mqtt tcp transport) and as a demonstration subscribes/unsubscribes and send a message on certain topic. +This example connects to the broker URI selected using `idf.py menuconfig` (using mqtt tcp transport) and as a demonstration subscribes/unsubscribes and send a message on certain topic. (Please note that the public broker is maintained by the community so may not be always available, for details please see this [disclaimer](https://iot.eclipse.org/getting-started/#sandboxes)) Note: If the URI equals `FROM_STDIN` then the broker address is read from stdin upon application startup (used for testing) @@ -25,7 +25,7 @@ This example can be executed on any ESP32 board, the only required interface is Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/protocols/mqtt/ws/README.md b/examples/protocols/mqtt/ws/README.md index d0eff6be29..c0526b0735 100644 --- a/examples/protocols/mqtt/ws/README.md +++ b/examples/protocols/mqtt/ws/README.md @@ -24,7 +24,7 @@ This example can be executed on any ESP32 board, the only required interface is Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/protocols/mqtt/wss/README.md b/examples/protocols/mqtt/wss/README.md index 1877979308..9851d54337 100644 --- a/examples/protocols/mqtt/wss/README.md +++ b/examples/protocols/mqtt/wss/README.md @@ -34,7 +34,7 @@ with text operation. Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/protocols/sockets/README.md b/examples/protocols/sockets/README.md index 9fbc850db9..9d52415321 100644 --- a/examples/protocols/sockets/README.md +++ b/examples/protocols/sockets/README.md @@ -79,7 +79,7 @@ This example can be run on any commonly available ESP32 development board. ## Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -91,7 +91,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/protocols/sockets/tcp_client/README.md b/examples/protocols/sockets/tcp_client/README.md index 415dea814e..af3348ed39 100644 --- a/examples/protocols/sockets/tcp_client/README.md +++ b/examples/protocols/sockets/tcp_client/README.md @@ -35,7 +35,7 @@ This example can be run on any commonly available ESP32 development board. ## Configure the project ``` -make menuconfig +idf.py menuconfig ``` Set following parameter under Serial Flasher Options: @@ -59,7 +59,7 @@ Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See " Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/protocols/sockets/tcp_server/README.md b/examples/protocols/sockets/tcp_server/README.md index ce47646c98..ca72ff01bc 100644 --- a/examples/protocols/sockets/tcp_server/README.md +++ b/examples/protocols/sockets/tcp_server/README.md @@ -37,7 +37,7 @@ This example can be run on any commonly available ESP32 development board. ## Configure the project ``` -make menuconfig +idf.py menuconfig ``` Set following parameter under Serial Flasher Options: @@ -57,7 +57,7 @@ Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See " Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/protocols/sockets/udp_client/README.md b/examples/protocols/sockets/udp_client/README.md index 7232fb9f45..85bdaa8304 100644 --- a/examples/protocols/sockets/udp_client/README.md +++ b/examples/protocols/sockets/udp_client/README.md @@ -45,7 +45,7 @@ This example can be run on any commonly available ESP32 development board. ## Configure the project ``` -make menuconfig +idf.py menuconfig ``` Set following parameter under Serial Flasher Options: @@ -70,7 +70,7 @@ Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See " Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/protocols/sockets/udp_server/README.md b/examples/protocols/sockets/udp_server/README.md index 3bf1fe370a..bbfbd60327 100644 --- a/examples/protocols/sockets/udp_server/README.md +++ b/examples/protocols/sockets/udp_server/README.md @@ -47,7 +47,7 @@ This example can be run on any commonly available ESP32 development board. ## Configure the project ``` -make menuconfig +idf.py menuconfig ``` Set following parameter under Serial Flasher Options: @@ -67,7 +67,7 @@ Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See " Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/provisioning/ble_prov/README.md b/examples/provisioning/ble_prov/README.md index fa49ba8e4d..1c871e6572 100644 --- a/examples/provisioning/ble_prov/README.md +++ b/examples/provisioning/ble_prov/README.md @@ -47,7 +47,7 @@ There are various applications, specific to Windows and macOS platform which can ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -61,7 +61,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) @@ -140,7 +140,7 @@ It means the Wi-Fi credentials were already set by some other application flashe ``` make erase_flash -make -j4 flash monitor +idf.py -p PORT flash monitor ``` Or, enable `Reset Provisioning` option under `Example Configuration` under menuconfig. But this will erase the saved Wi-Fi credentials every time the device boots, so this is not the preferred solution. diff --git a/examples/provisioning/console_prov/README.md b/examples/provisioning/console_prov/README.md index 0732c54505..685fdf66c5 100644 --- a/examples/provisioning/console_prov/README.md +++ b/examples/provisioning/console_prov/README.md @@ -30,7 +30,7 @@ To provision the device running this example, the `esp_prov.py` script needs to ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -44,7 +44,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) @@ -202,7 +202,7 @@ It means the Wi-Fi credentials were already set by some other application flashe ``` make erase_flash -make -j4 flash monitor +idf.py -p PORT flash monitor ``` Or, enable `Reset Provisioning` option under `Example Configuration` under menuconfig. But this will erase the saved Wi-Fi credentials every time the device boots, so this is not the preferred solution. diff --git a/examples/provisioning/custom_config/README.md b/examples/provisioning/custom_config/README.md index 82ed6ffe31..dba1854a61 100644 --- a/examples/provisioning/custom_config/README.md +++ b/examples/provisioning/custom_config/README.md @@ -29,7 +29,7 @@ To provision the device running this example, the `esp_prov.py` script needs to ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -45,7 +45,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) @@ -138,7 +138,7 @@ It means the Wi-Fi credentials were already set by some other application flashe ``` make erase_flash -make -j4 flash monitor +idf.py -p PORT flash monitor ``` Or, enable `Reset Provisioning` option under `Example Configuration` under menuconfig. But this will erase the saved Wi-Fi credentials every time the device boots, so this is not the preferred solution. diff --git a/examples/provisioning/manager/README.md b/examples/provisioning/manager/README.md index b59f83710b..d514d7bdec 100644 --- a/examples/provisioning/manager/README.md +++ b/examples/provisioning/manager/README.md @@ -47,7 +47,7 @@ There are various applications, specific to Windows and macOS platform which can ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -57,7 +57,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/provisioning/softap_prov/README.md b/examples/provisioning/softap_prov/README.md index 56d092dbfa..086a18e633 100644 --- a/examples/provisioning/softap_prov/README.md +++ b/examples/provisioning/softap_prov/README.md @@ -42,7 +42,7 @@ To provision the device running this example, the `esp_prov.py` script needs to ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -58,7 +58,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) @@ -145,7 +145,7 @@ It means the Wi-Fi credentials were already set by some other application flashe ``` make erase_flash -make -j4 flash monitor +idf.py -p PORT flash monitor ``` Or, enable `Reset Provisioning` option under `Example Configuration` under menuconfig. But this will erase the saved Wi-Fi credentials every time the device boots, so this is not the preferred solution. diff --git a/examples/security/flash_encryption/README.md b/examples/security/flash_encryption/README.md index f65d1bb163..750ee2a7b8 100644 --- a/examples/security/flash_encryption/README.md +++ b/examples/security/flash_encryption/README.md @@ -8,7 +8,7 @@ The example checks if the flash encryption feature is enabled/disabled and if en ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -24,7 +24,7 @@ make menuconfig When building the project and flashing it to the board FOR THE FIRST TIME after enabling flash encryption feature in menuconfig, run following command to program ESP32 and monitor the output ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) @@ -34,13 +34,13 @@ See the Getting Started Guide for full steps to configure and use ESP-IDF to bui When reprogramming the device subsequently use following command for encrypted write of new plaintext application ``` -make -j4 encrypted-app-flash monitor +idf.py encrypted-app-flash monitor ``` Please note above command programs only the app partition. In order to reprogram all partitions (bootloader, partition table and application) in encrypted form use ``` -make -j4 encrypted-flash monitor +idf.py encrypted-flash monitor ``` ## Example Output diff --git a/examples/storage/spiffsgen/README.md b/examples/storage/spiffsgen/README.md index 1176d343d5..b1d34048ba 100644 --- a/examples/storage/spiffsgen/README.md +++ b/examples/storage/spiffsgen/README.md @@ -4,7 +4,7 @@ This example demonstrates how to use the SPIFFS image generation tool [spiffsgen.py](../../../components/spiffs/spiffsgen.py) to automatically create a SPIFFS filesystem image from the contents of a host folder during build, with an option of -automatically flashing the created image on invocation of `idf.py flash`. +automatically flashing the created image on invocation of `idf.py -p PORT flash`. For more information, see description of `spiffsgen.py` on the ESP-IDF Programming Guide under API Reference > Storage > SPIFFS Filesystem. The following gives an overview of the example: @@ -14,10 +14,10 @@ The following gives an overview of the example: 2. The function `spiffs_create_partition_image` is used to specify that a SPIFFS image should be created during build for the `storage` partition. For CMake, it is called from [the main component's CMakeLists.txt](./main/CMakeLists.txt); for Make, from the [project Makefile](./Makefile). `FLASH_IN_PROJECT` specifies that the created image -should be flashed on invocation of `idf.py flash` together with app, bootloader, partition table, etc. +should be flashed on invocation of `idf.py -p PORT flash` together with app, bootloader, partition table, etc. For both build systems, the image is created on the example's build directory with the output filename `storage.bin`. -3. Upon invocation of `idf.py flash monitor`, application loads and +3. Upon invocation of `idf.py -p PORT flash monitor`, application loads and finds there is already a valid SPIFFS filesystem in the `storage` partition with files same as those in `spiffs_image` directory. The application is then able to read those files. @@ -34,7 +34,7 @@ make flash monitor or ```CMake # CMake -idf.py flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/storage/spiffsgen/main/CMakeLists.txt b/examples/storage/spiffsgen/main/CMakeLists.txt index 6153893c3c..3c74aed1b3 100644 --- a/examples/storage/spiffsgen/main/CMakeLists.txt +++ b/examples/storage/spiffsgen/main/CMakeLists.txt @@ -4,5 +4,5 @@ idf_component_register(SRCS "spiffsgen_example_main.c" # Create a SPIFFS image from the contents of the 'spiffs_image' directory # that fits the partition named 'storage'. FLASH_IN_PROJECT indicates that # the generated image should be flashed when the entire project is flashed to -# the target with 'idf.py flash'. +# the target with 'idf.py -p PORT flash'. spiffs_create_partition_image(storage ../spiffs_image FLASH_IN_PROJECT) diff --git a/examples/system/freertos/real_time_stats/README.md b/examples/system/freertos/real_time_stats/README.md index 1ee73a34f1..51e49832e1 100644 --- a/examples/system/freertos/real_time_stats/README.md +++ b/examples/system/freertos/real_time_stats/README.md @@ -15,7 +15,7 @@ This example should be able to run on any commonly available ESP32 development b ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -29,7 +29,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/system/himem/README.md b/examples/system/himem/README.md index 0bc8a624c2..7eba56c40c 100644 --- a/examples/system/himem/README.md +++ b/examples/system/himem/README.md @@ -29,7 +29,7 @@ a setup does not make much sense. ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -43,7 +43,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/system/network_tests/README.md b/examples/system/network_tests/README.md index c9aefd8d34..3c2581972b 100644 --- a/examples/system/network_tests/README.md +++ b/examples/system/network_tests/README.md @@ -23,9 +23,8 @@ Note: TTCN3 engine works reliably only on Linux and Windows. ``` cd $IDF_PATH/examples/system/network_tests -make defconfig -make -j4 -make flash +idf.py build +idf.py -p PORT flash ``` ## Run test diff --git a/examples/wifi/espnow/README.md b/examples/wifi/espnow/README.md index 047cf85a4a..5b375c99ba 100644 --- a/examples/wifi/espnow/README.md +++ b/examples/wifi/espnow/README.md @@ -31,7 +31,7 @@ to make ESPNOW data more safe and more reliable. ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -53,7 +53,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/wifi/getting_started/softAP/README.md b/examples/wifi/getting_started/softAP/README.md index 8d831d29bd..4b030e01c3 100644 --- a/examples/wifi/getting_started/softAP/README.md +++ b/examples/wifi/getting_started/softAP/README.md @@ -8,7 +8,7 @@ ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -20,7 +20,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/wifi/getting_started/station/README.md b/examples/wifi/getting_started/station/README.md index 6666da5345..e992df2607 100644 --- a/examples/wifi/getting_started/station/README.md +++ b/examples/wifi/getting_started/station/README.md @@ -8,7 +8,7 @@ ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -20,7 +20,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) diff --git a/examples/wifi/power_save/main/power_save.c b/examples/wifi/power_save/main/power_save.c index 04f60cb66d..efa7f41c54 100644 --- a/examples/wifi/power_save/main/power_save.c +++ b/examples/wifi/power_save/main/power_save.c @@ -20,7 +20,7 @@ #include "esp_pm.h" #include "nvs_flash.h" -/*set the ssid and password via "make menuconfig"*/ +/*set the ssid and password via "idf.py menuconfig"*/ #define DEFAULT_SSID CONFIG_EXAMPLE_WIFI_SSID #define DEFAULT_PWD CONFIG_EXAMPLE_WIFI_PASSWORD diff --git a/examples/wifi/smart_config/README.md b/examples/wifi/smart_config/README.md index 7f8ee90c7d..c8bdbeb9e8 100644 --- a/examples/wifi/smart_config/README.md +++ b/examples/wifi/smart_config/README.md @@ -13,7 +13,7 @@ Download ESPTOUCH APP from app store: ### Configure the project ``` -make menuconfig +idf.py menuconfig ``` * Set serial port under Serial Flasher Options. @@ -23,7 +23,7 @@ make menuconfig Build the project and flash it to the board, then run monitor tool to view serial output: ``` -make -j4 flash monitor +idf.py -p PORT flash monitor ``` (To exit the serial monitor, type ``Ctrl-]``.) From d4091f7cda3b17ba35a291396373a8142b972f7f Mon Sep 17 00:00:00 2001 From: Hrudaynath Dhabe Date: Fri, 2 Aug 2019 19:18:44 +0800 Subject: [PATCH 406/486] esp_http_client: Add support to check the binary length of the recieved stream and compare it with the size mentioned in the header. While downloading OTA firmware, if their is a Origin Respnse Timeout or the binary is only partially downloaded, OTA failure is observed. Checking binary size can also be helpful for simple http client applications. Closes https://github.com/espressif/esp-idf/issues/3004 --- components/esp_http_client/esp_http_client.c | 22 ++++++++++++++++++- .../esp_http_client/include/esp_http_client.h | 11 ++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/components/esp_http_client/esp_http_client.c b/components/esp_http_client/esp_http_client.c index 76f6eec016..2dab9da1a7 100644 --- a/components/esp_http_client/esp_http_client.c +++ b/components/esp_http_client/esp_http_client.c @@ -775,6 +775,22 @@ static int esp_http_client_get_data(esp_http_client_handle_t client) return rlen; } +bool esp_http_client_is_complete_data_received(esp_http_client_handle_t client) +{ + if (client->response->is_chunked) { + if (!client->is_chunk_complete) { + ESP_LOGI(TAG, "Chunks were not completely read"); + return false; + } + } else { + if (client->response->data_process != client->response->content_length) { + ESP_LOGI(TAG, "Data processed %d != Data specified in content length %d", client->response->data_process, client->response->content_length); + return false; + } + } + return true; +} + int esp_http_client_read(esp_http_client_handle_t client, char *buffer, int len) { esp_http_buffer_t *res_buffer = client->response->buffer; @@ -798,7 +814,7 @@ int esp_http_client_read(esp_http_client_handle_t client, char *buffer, int len) } else { is_data_remain = client->response->data_process < client->response->content_length; } - ESP_LOGD(TAG, "is_data_remain=%d, is_chunked=%d", is_data_remain, client->response->is_chunked); + ESP_LOGD(TAG, "is_data_remain=%d, is_chunked=%d, content_length=%d", is_data_remain, client->response->is_chunked, client->response->content_length); if (!is_data_remain) { break; } @@ -806,10 +822,14 @@ int esp_http_client_read(esp_http_client_handle_t client, char *buffer, int len) if (byte_to_read > client->buffer_size_rx) { byte_to_read = client->buffer_size_rx; } + errno = 0; rlen = esp_transport_read(client->transport, res_buffer->data, byte_to_read, client->timeout_ms); ESP_LOGD(TAG, "need_read=%d, byte_to_read=%d, rlen=%d, ridx=%d", need_read, byte_to_read, rlen, ridx); if (rlen <= 0) { + if (errno != 0) { + ESP_LOGW(TAG, "esp_transport_read returned : %d and errno : %d ", rlen, errno); + } return ridx; } res_buffer->output_ptr = buffer + ridx; diff --git a/components/esp_http_client/include/esp_http_client.h b/components/esp_http_client/include/esp_http_client.h index cc97cc0690..2021d6edd5 100644 --- a/components/esp_http_client/include/esp_http_client.h +++ b/components/esp_http_client/include/esp_http_client.h @@ -445,6 +445,17 @@ esp_err_t esp_http_client_set_redirection(esp_http_client_handle_t client); */ void esp_http_client_add_auth(esp_http_client_handle_t client); +/** + * @brief Checks if entire data in the response has been read without any error. + * + * @param[in] client The esp_http_client handle + * + * @return + * - true + * - false + */ +bool esp_http_client_is_complete_data_received(esp_http_client_handle_t client); + #ifdef __cplusplus } #endif From a9dfae66ea2a35dc0de2bed350f0d86cf9f1cae7 Mon Sep 17 00:00:00 2001 From: Tian Hao Date: Sat, 27 Jul 2019 17:47:33 +0800 Subject: [PATCH 407/486] bugfix btdm sleep twice after wakeup request This problem may cause HCI send command timeout. When host call VHCI api to do btdm_wakeup_request, then controller wakeup process will be handled in ISR and controller task context. As host task priority is lower than controller task and ISR, it will cause an incorrect behavior that before VHCI take the rx_flow_on_semaphore, controller sleep again, then VHCI cannot take the semaphore and has to wait the automatic wakeup. --- components/bt/controller/bt.c | 17 +++++++++++++---- components/bt/controller/lib | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/components/bt/controller/bt.c b/components/bt/controller/bt.c index db19faea22..0453a102e4 100644 --- a/components/bt/controller/bt.c +++ b/components/bt/controller/bt.c @@ -203,7 +203,8 @@ extern void btdm_controller_enable_sleep(bool enable); extern void btdm_controller_set_sleep_mode(uint8_t mode); extern uint8_t btdm_controller_get_sleep_mode(void); extern bool btdm_power_state_active(void); -extern void btdm_wakeup_request(void); +extern void btdm_wakeup_request(bool request_lock); +extern void btdm_wakeup_request_end(void); /* Low Power Clock */ extern bool btdm_lpclk_select_src(uint32_t sel); extern bool btdm_lpclk_set_div(uint32_t div); @@ -893,6 +894,8 @@ bool esp_vhci_host_check_send_available(void) void esp_vhci_host_send_packet(uint8_t *data, uint16_t len) { + bool do_wakeup_request = false; + if (!btdm_power_state_active()) { #if CONFIG_PM_ENABLE if (semphr_take_wrapper(s_pm_lock_sem, 0)) { @@ -900,9 +903,15 @@ void esp_vhci_host_send_packet(uint8_t *data, uint16_t len) } esp_timer_stop(s_btdm_slp_tmr); #endif - btdm_wakeup_request(); + do_wakeup_request = true; + btdm_wakeup_request(true); } + API_vhci_host_send_packet(data, len); + + if (do_wakeup_request) { + btdm_wakeup_request_end(); + } } esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback) @@ -1328,7 +1337,7 @@ esp_err_t esp_bt_controller_disable(void) if (btdm_controller_get_sleep_mode() == BTDM_MODEM_SLEEP_MODE_ORIG) { btdm_controller_enable_sleep(false); if (!btdm_power_state_active()) { - btdm_wakeup_request(); + btdm_wakeup_request(false); } while (!btdm_power_state_active()) { ets_delay_us(1000); @@ -1466,7 +1475,7 @@ void esp_bt_controller_wakeup_request(void) return; } - btdm_wakeup_request(); + btdm_wakeup_request(false); } esp_err_t esp_bredr_sco_datapath_set(esp_sco_data_path_t data_path) diff --git a/components/bt/controller/lib b/components/bt/controller/lib index cc2fd1177d..717f0c6ec7 160000 --- a/components/bt/controller/lib +++ b/components/bt/controller/lib @@ -1 +1 @@ -Subproject commit cc2fd1177d97f1a4b9e0d819035ddf52ba77079d +Subproject commit 717f0c6ec71a016a0b292acffeacf239d007b8ff From 91ce5db1727972ec793eccc0182cce10e6f5213c Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Wed, 10 Jul 2019 14:08:21 +0200 Subject: [PATCH 408/486] VFS: Support concurrent VFS select calls Closes https://github.com/espressif/esp-idf/issues/3392 --- components/vfs/include/esp_vfs.h | 4 +- components/vfs/test/test_vfs_select.c | 148 ++++++++++++----- components/vfs/vfs.c | 25 ++- components/vfs/vfs_uart.c | 231 ++++++++++++++------------ 4 files changed, 253 insertions(+), 155 deletions(-) diff --git a/components/vfs/include/esp_vfs.h b/components/vfs/include/esp_vfs.h index e4eafb417c..2f39ca62f5 100644 --- a/components/vfs/include/esp_vfs.h +++ b/components/vfs/include/esp_vfs.h @@ -236,7 +236,7 @@ typedef struct #endif // CONFIG_VFS_SUPPORT_TERMIOS /** start_select is called for setting up synchronous I/O multiplexing of the desired file descriptors in the given VFS */ - esp_err_t (*start_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, esp_vfs_select_sem_t sem); + esp_err_t (*start_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, esp_vfs_select_sem_t sem, void **end_select_args); /** socket select function for socket FDs with the functionality of POSIX select(); this should be set only for the socket VFS */ int (*socket_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout); /** called by VFS to interrupt the socket_select call when select is activated from a non-socket VFS driver; set only for the socket driver */ @@ -246,7 +246,7 @@ typedef struct /** end_select is called to stop the I/O multiplexing and deinitialize the environment created by start_select for the given VFS */ void* (*get_socket_select_semaphore)(void); /** get_socket_select_semaphore returns semaphore allocated in the socket driver; set only for the socket driver */ - void (*end_select)(void); + esp_err_t (*end_select)(void *end_select_args); } esp_vfs_t; diff --git a/components/vfs/test/test_vfs_select.c b/components/vfs/test/test_vfs_select.c index bea17242e1..2ce2270b8a 100644 --- a/components/vfs/test/test_vfs_select.c +++ b/components/vfs/test/test_vfs_select.c @@ -31,6 +31,16 @@ typedef struct { xSemaphoreHandle sem; } test_task_param_t; +typedef struct { + fd_set *rdfds; + fd_set *wrfds; + fd_set *errfds; + int maxfds; + struct timeval *tv; + int select_ret; + xSemaphoreHandle sem; +} test_select_task_param_t; + static const char message[] = "Hello world!"; static int open_dummy_socket(void) @@ -420,73 +430,121 @@ TEST_CASE("poll() timeout", "[vfs]") deinit(uart_fd, socket_fd); } -static void select_task(void *param) +static void select_task(void *task_param) { - const test_task_param_t *test_task_param = param; - struct timeval tv = { - .tv_sec = 0, - .tv_usec = 100000, - }; + const test_select_task_param_t *param = task_param; - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(test_task_param->fd, &rfds); + int s = select(param->maxfds, param->rdfds, param->wrfds, param->errfds, param->tv); + TEST_ASSERT_EQUAL(param->select_ret, s); - int s = select(test_task_param->fd + 1, &rfds, NULL, NULL, &tv); - TEST_ASSERT_EQUAL(0, s); //timeout - - if (test_task_param->sem) { - xSemaphoreGive(test_task_param->sem); + if (param->sem) { + xSemaphoreGive(param->sem); } vTaskDelete(NULL); } -TEST_CASE("concurent selects work", "[vfs]") +static void inline start_select_task(test_select_task_param_t *param) { - struct timeval tv = { - .tv_sec = 0, - .tv_usec = 100000,//irrelevant - }; + xTaskCreate(select_task, "select_task", 4*1024, (void *) param, 5, NULL); +} +TEST_CASE("concurrent selects work", "[vfs]") +{ int uart_fd, socket_fd; init(&uart_fd, &socket_fd); - const int dummy_socket_fd = open_dummy_socket(); - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(uart_fd, &rfds); + { + // Two tasks will wait for the same UART FD for reading and they will time-out - test_task_param_t test_task_param = { - .fd = uart_fd, - .sem = xSemaphoreCreateBinary(), - }; - TEST_ASSERT_NOT_NULL(test_task_param.sem); + struct timeval tv = { + .tv_sec = 0, + .tv_usec = 100000, + }; - xTaskCreate(select_task, "select_task", 4*1024, (void *) &test_task_param, 5, NULL); - vTaskDelay(10 / portTICK_PERIOD_MS); //make sure the task has started and waits in select() + fd_set rdfds1; + FD_ZERO(&rdfds1); + FD_SET(uart_fd, &rdfds1); - int s = select(uart_fd + 1, &rfds, NULL, NULL, &tv); - TEST_ASSERT_EQUAL(-1, s); //this select should fail because two selects are accessing UART - //(the other one is waiting for the timeout) - TEST_ASSERT_EQUAL(EINTR, errno); + test_select_task_param_t param = { + .rdfds = &rdfds1, + .wrfds = NULL, + .errfds = NULL, + .maxfds = uart_fd + 1, + .tv = &tv, + .select_ret = 0, // expected timeout + .sem = xSemaphoreCreateBinary(), + }; + TEST_ASSERT_NOT_NULL(param.sem); - TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(test_task_param.sem, 1000 / portTICK_PERIOD_MS)); + fd_set rdfds2; + FD_ZERO(&rdfds2); + FD_SET(uart_fd, &rdfds2); + FD_SET(socket_fd, &rdfds2); + FD_SET(dummy_socket_fd, &rdfds2); - FD_ZERO(&rfds); - FD_SET(socket_fd, &rfds); + start_select_task(¶m); + vTaskDelay(10 / portTICK_PERIOD_MS); //make sure the task has started and waits in select() - test_task_param.fd = dummy_socket_fd; + int s = select(MAX(MAX(uart_fd, dummy_socket_fd), socket_fd) + 1, &rdfds2, NULL, NULL, &tv); + TEST_ASSERT_EQUAL(0, s); // timeout here as well - xTaskCreate(select_task, "select_task", 4*1024, (void *) &test_task_param, 5, NULL); - vTaskDelay(10 / portTICK_PERIOD_MS); //make sure the task has started and waits in select() + TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(param.sem, 1000 / portTICK_PERIOD_MS)); + vSemaphoreDelete(param.sem); + } - s = select(socket_fd + 1, &rfds, NULL, NULL, &tv); - TEST_ASSERT_EQUAL(0, s); //this select should timeout as well as the concurrent one because - //concurrent socket select should work + { + // One tasks waits for UART reading and one for writing. The former will be successful and latter will + // time-out. - TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(test_task_param.sem, 1000 / portTICK_PERIOD_MS)); - vSemaphoreDelete(test_task_param.sem); + struct timeval tv = { + .tv_sec = 0, + .tv_usec = 100000, + }; + + fd_set wrfds1; + FD_ZERO(&wrfds1); + FD_SET(uart_fd, &wrfds1); + + test_select_task_param_t param = { + .rdfds = NULL, + .wrfds = &wrfds1, + .errfds = NULL, + .maxfds = uart_fd + 1, + .tv = &tv, + .select_ret = 0, // expected timeout + .sem = xSemaphoreCreateBinary(), + }; + TEST_ASSERT_NOT_NULL(param.sem); + + start_select_task(¶m); + + fd_set rdfds2; + FD_ZERO(&rdfds2); + FD_SET(uart_fd, &rdfds2); + FD_SET(socket_fd, &rdfds2); + FD_SET(dummy_socket_fd, &rdfds2); + + const test_task_param_t send_param = { + .fd = uart_fd, + .delay_ms = 50, + .sem = xSemaphoreCreateBinary(), + }; + TEST_ASSERT_NOT_NULL(send_param.sem); + start_task(&send_param); // This task will write to UART which will be detected by select() + + int s = select(MAX(MAX(uart_fd, dummy_socket_fd), socket_fd) + 1, &rdfds2, NULL, NULL, &tv); + TEST_ASSERT_EQUAL(1, s); + TEST_ASSERT(FD_ISSET(uart_fd, &rdfds2)); + TEST_ASSERT_UNLESS(FD_ISSET(socket_fd, &rdfds2)); + TEST_ASSERT_UNLESS(FD_ISSET(dummy_socket_fd, &rdfds2)); + + TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(param.sem, 1000 / portTICK_PERIOD_MS)); + vSemaphoreDelete(param.sem); + + TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(send_param.sem, 1000 / portTICK_PERIOD_MS)); + vSemaphoreDelete(send_param.sem); + } deinit(uart_fd, socket_fd); close(dummy_socket_fd); diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index c604b09738..ed4db5e7ed 100644 --- a/components/vfs/vfs.c +++ b/components/vfs/vfs.c @@ -794,13 +794,16 @@ int truncate(const char *path, off_t length) return ret; } -static void call_end_selects(int end_index, const fds_triple_t *vfs_fds_triple) +static void call_end_selects(int end_index, const fds_triple_t *vfs_fds_triple, void **driver_args) { for (int i = 0; i < end_index; ++i) { const vfs_entry_t *vfs = get_vfs_for_index(i); const fds_triple_t *item = &vfs_fds_triple[i]; if (vfs && vfs->vfs.end_select && item->isset) { - vfs->vfs.end_select(); + esp_err_t err = vfs->vfs.end_select(driver_args[i]); + if (err != ESP_OK) { + ESP_LOGD(TAG, "end_select failed: %s", esp_err_to_name(err)); + } } } } @@ -947,6 +950,15 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds } } + void **driver_args = calloc(s_vfs_count, sizeof(void *)); + + if (driver_args == NULL) { + free(vfs_fds_triple); + __errno_r(r) = ENOMEM; + ESP_LOGD(TAG, "calloc is unsuccessful for driver args"); + return -1; + } + for (int i = 0; i < s_vfs_count; ++i) { const vfs_entry_t *vfs = get_vfs_for_index(i); fds_triple_t *item = &vfs_fds_triple[i]; @@ -958,16 +970,18 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds esp_vfs_log_fd_set("readfds", &item->readfds); esp_vfs_log_fd_set("writefds", &item->writefds); esp_vfs_log_fd_set("errorfds", &item->errorfds); - esp_err_t err = vfs->vfs.start_select(nfds, &item->readfds, &item->writefds, &item->errorfds, sel_sem); + esp_err_t err = vfs->vfs.start_select(nfds, &item->readfds, &item->writefds, &item->errorfds, sel_sem, + driver_args + i); if (err != ESP_OK) { - call_end_selects(i, vfs_fds_triple); + call_end_selects(i, vfs_fds_triple, driver_args); (void) set_global_fd_sets(vfs_fds_triple, s_vfs_count, readfds, writefds, errorfds); if (sel_sem.is_sem_local && sel_sem.sem) { vSemaphoreDelete(sel_sem.sem); sel_sem.sem = NULL; } free(vfs_fds_triple); + free(driver_args); __errno_r(r) = EINTR; ESP_LOGD(TAG, "start_select failed: %s", esp_err_to_name(err)); return -1; @@ -1006,7 +1020,7 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds xSemaphoreTake(sel_sem.sem, ticks_to_wait); } - call_end_selects(s_vfs_count, vfs_fds_triple); // for VFSs for start_select was called before + call_end_selects(s_vfs_count, vfs_fds_triple, driver_args); // for VFSs for start_select was called before if (ret >= 0) { ret += set_global_fd_sets(vfs_fds_triple, s_vfs_count, readfds, writefds, errorfds); } @@ -1015,6 +1029,7 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds sel_sem.sem = NULL; } free(vfs_fds_triple); + free(driver_args); ESP_LOGD(TAG, "esp_vfs_select returns %d", ret); esp_vfs_log_fd_set("readfds", readfds); diff --git a/components/vfs/vfs_uart.c b/components/vfs/vfs_uart.c index d996e9eebd..f1513ae1dc 100644 --- a/components/vfs/vfs_uart.c +++ b/components/vfs/vfs_uart.c @@ -111,20 +111,21 @@ static vfs_uart_context_t* s_ctx[UART_NUM] = { #endif }; -/* Lock ensuring that uart_select is used from only one task at the time */ -static _lock_t s_one_select_lock; +typedef struct { + esp_vfs_select_sem_t select_sem; + fd_set *readfds; + fd_set *writefds; + fd_set *errorfds; + fd_set readfds_orig; + fd_set writefds_orig; + fd_set errorfds_orig; +} uart_select_args_t; -static esp_vfs_select_sem_t _select_sem = {.sem = NULL}; -static fd_set *_readfds = NULL; -static fd_set *_writefds = NULL; -static fd_set *_errorfds = NULL; -static fd_set *_readfds_orig = NULL; -static fd_set *_writefds_orig = NULL; -static fd_set *_errorfds_orig = NULL; - - -static void uart_end_select(void); +static uart_select_args_t **s_registered_selects = NULL; +static int s_registered_select_num = 0; +static portMUX_TYPE s_registered_select_lock = portMUX_INITIALIZER_UNLOCKED; +static esp_err_t uart_end_select(void *end_select_args); static int uart_open(const char * path, int flags, int mode) { @@ -335,132 +336,156 @@ static int uart_fsync(int fd) return 0; } -static void select_notif_callback(uart_port_t uart_num, uart_select_notif_t uart_select_notif, BaseType_t *task_woken) +static esp_err_t register_select(uart_select_args_t *args) { - switch (uart_select_notif) { - case UART_SELECT_READ_NOTIF: - if (FD_ISSET(uart_num, _readfds_orig)) { - FD_SET(uart_num, _readfds); - esp_vfs_select_triggered_isr(_select_sem, task_woken); - } - break; - case UART_SELECT_WRITE_NOTIF: - if (FD_ISSET(uart_num, _writefds_orig)) { - FD_SET(uart_num, _writefds); - esp_vfs_select_triggered_isr(_select_sem, task_woken); - } - break; - case UART_SELECT_ERROR_NOTIF: - if (FD_ISSET(uart_num, _errorfds_orig)) { - FD_SET(uart_num, _errorfds); - esp_vfs_select_triggered_isr(_select_sem, task_woken); - } - break; + esp_err_t ret = ESP_ERR_INVALID_ARG; + + if (args) { + portENTER_CRITICAL(&s_registered_select_lock); + const int new_size = s_registered_select_num + 1; + if ((s_registered_selects = realloc(s_registered_selects, new_size * sizeof(uart_select_args_t *))) == NULL) { + ret = ESP_ERR_NO_MEM; + } else { + s_registered_selects[s_registered_select_num] = args; + s_registered_select_num = new_size; + ret = ESP_OK; + } + portEXIT_CRITICAL(&s_registered_select_lock); } + + return ret; } -static esp_err_t uart_start_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, esp_vfs_select_sem_t select_sem) +static esp_err_t unregister_select(uart_select_args_t *args) { - if (_lock_try_acquire(&s_one_select_lock)) { - return ESP_ERR_INVALID_STATE; + esp_err_t ret = ESP_OK; + if (args) { + ret = ESP_ERR_INVALID_STATE; + portENTER_CRITICAL(&s_registered_select_lock); + for (int i = 0; i < s_registered_select_num; ++i) { + if (s_registered_selects[i] == args) { + const int new_size = s_registered_select_num - 1; + // The item is removed by overwriting it with the last item. The subsequent rellocation will drop the + // last item. + s_registered_selects[i] = s_registered_selects[new_size]; + s_registered_selects = realloc(s_registered_selects, new_size * sizeof(uart_select_args_t *)); + if (s_registered_selects || new_size == 0) { + s_registered_select_num = new_size; + ret = ESP_OK; + } else { + ret = ESP_ERR_NO_MEM; + } + break; + } + } + portEXIT_CRITICAL(&s_registered_select_lock); } + return ret; +} - const int max_fds = MIN(nfds, UART_NUM); - - portENTER_CRITICAL(uart_get_selectlock()); - - if (_readfds || _writefds || _errorfds || _readfds_orig || _writefds_orig || _errorfds_orig || _select_sem.sem) { - portEXIT_CRITICAL(uart_get_selectlock()); - uart_end_select(); - return ESP_ERR_INVALID_STATE; - } - - if ((_readfds_orig = malloc(sizeof(fd_set))) == NULL) { - portEXIT_CRITICAL(uart_get_selectlock()); - uart_end_select(); - return ESP_ERR_NO_MEM; - } - - if ((_writefds_orig = malloc(sizeof(fd_set))) == NULL) { - portEXIT_CRITICAL(uart_get_selectlock()); - uart_end_select(); - return ESP_ERR_NO_MEM; - } - - if ((_errorfds_orig = malloc(sizeof(fd_set))) == NULL) { - portEXIT_CRITICAL(uart_get_selectlock()); - uart_end_select(); - return ESP_ERR_NO_MEM; - } - - //uart_set_select_notif_callback set the callbacks in UART ISR - for (int i = 0; i < max_fds; ++i) { - if (FD_ISSET(i, readfds) || FD_ISSET(i, writefds) || FD_ISSET(i, exceptfds)) { - uart_set_select_notif_callback(i, select_notif_callback); +static void select_notif_callback_isr(uart_port_t uart_num, uart_select_notif_t uart_select_notif, BaseType_t *task_woken) +{ + portENTER_CRITICAL_ISR(&s_registered_select_lock); + for (int i = 0; i < s_registered_select_num; ++i) { + uart_select_args_t *args = s_registered_selects[i]; + if (args) { + switch (uart_select_notif) { + case UART_SELECT_READ_NOTIF: + if (FD_ISSET(uart_num, &args->readfds_orig)) { + FD_SET(uart_num, args->readfds); + esp_vfs_select_triggered_isr(args->select_sem, task_woken); + } + break; + case UART_SELECT_WRITE_NOTIF: + if (FD_ISSET(uart_num, &args->writefds_orig)) { + FD_SET(uart_num, args->writefds); + esp_vfs_select_triggered_isr(args->select_sem, task_woken); + } + break; + case UART_SELECT_ERROR_NOTIF: + if (FD_ISSET(uart_num, &args->errorfds_orig)) { + FD_SET(uart_num, args->errorfds); + esp_vfs_select_triggered_isr(args->select_sem, task_woken); + } + break; + } } } + portEXIT_CRITICAL_ISR(&s_registered_select_lock); +} - _select_sem = select_sem; +static esp_err_t uart_start_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + esp_vfs_select_sem_t select_sem, void **end_select_args) +{ + const int max_fds = MIN(nfds, UART_NUM); + *end_select_args = NULL; - _readfds = readfds; - _writefds = writefds; - _errorfds = exceptfds; + uart_select_args_t *args = malloc(sizeof(uart_select_args_t)); - *_readfds_orig = *readfds; - *_writefds_orig = *writefds; - *_errorfds_orig = *exceptfds; + if (args == NULL) { + return ESP_ERR_NO_MEM; + } + args->select_sem = select_sem; + args->readfds = readfds; + args->writefds = writefds; + args->errorfds = exceptfds; + args->readfds_orig = *readfds; // store the original values because they will be set to zero + args->writefds_orig = *writefds; + args->errorfds_orig = *exceptfds; FD_ZERO(readfds); FD_ZERO(writefds); FD_ZERO(exceptfds); + portENTER_CRITICAL(uart_get_selectlock()); + + //uart_set_select_notif_callback sets the callbacks in UART ISR for (int i = 0; i < max_fds; ++i) { - if (FD_ISSET(i, _readfds_orig)) { + if (FD_ISSET(i, &args->readfds_orig) || FD_ISSET(i, &args->writefds_orig) || FD_ISSET(i, &args->errorfds_orig)) { + uart_set_select_notif_callback(i, select_notif_callback_isr); + } + } + + for (int i = 0; i < max_fds; ++i) { + if (FD_ISSET(i, &args->readfds_orig)) { size_t buffered_size; if (uart_get_buffered_data_len(i, &buffered_size) == ESP_OK && buffered_size > 0) { // signalize immediately when data is buffered - FD_SET(i, _readfds); - esp_vfs_select_triggered(_select_sem); + FD_SET(i, readfds); + esp_vfs_select_triggered(args->select_sem); } } } - portEXIT_CRITICAL(uart_get_selectlock()); - // s_one_select_lock is not released on successfull exit - will be - // released in uart_end_select() + esp_err_t ret = register_select(args); + if (ret != ESP_OK) { + portEXIT_CRITICAL(uart_get_selectlock()); + free(args); + return ret; + } + portEXIT_CRITICAL(uart_get_selectlock()); + + *end_select_args = args; return ESP_OK; } -static void uart_end_select(void) +static esp_err_t uart_end_select(void *end_select_args) { + uart_select_args_t *args = end_select_args; + + if (args) { + free(args); + } + portENTER_CRITICAL(uart_get_selectlock()); + esp_err_t ret = unregister_select(args); for (int i = 0; i < UART_NUM; ++i) { uart_set_select_notif_callback(i, NULL); } - - _select_sem.sem = NULL; - - _readfds = NULL; - _writefds = NULL; - _errorfds = NULL; - - if (_readfds_orig) { - free(_readfds_orig); - _readfds_orig = NULL; - } - - if (_writefds_orig) { - free(_writefds_orig); - _writefds_orig = NULL; - } - - if (_errorfds_orig) { - free(_errorfds_orig); - _errorfds_orig = NULL; - } portEXIT_CRITICAL(uart_get_selectlock()); - _lock_release(&s_one_select_lock); + + return ret; } #ifdef CONFIG_VFS_SUPPORT_TERMIOS From 2211039b6d243e6c124d807b15f49443c9001764 Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Wed, 17 Jul 2019 09:59:21 +0200 Subject: [PATCH 409/486] docs: Correct and extend the documentation about VFS select() --- components/vfs/README.rst | 82 ++++++++++++++++++++++++++++++++------- components/vfs/vfs.c | 2 + 2 files changed, 69 insertions(+), 15 deletions(-) diff --git a/components/vfs/README.rst b/components/vfs/README.rst index 20bc9770e7..c296e81a68 100644 --- a/components/vfs/README.rst +++ b/components/vfs/README.rst @@ -66,9 +66,29 @@ Case 2: API functions are declared with an extra context pointer (the FS driver Synchronous input/output multiplexing ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -If you want to use synchronous input/output multiplexing by :cpp:func:`select` -then you need to register VFS with the functions :cpp:func:`start_select` and -:cpp:func:`end_select` similar to the following example: +Synchronous input/output multiplexing by :cpp:func:`select` is supported in the VFS component. The implementation +works in the following way. + +1. :cpp:func:`select` is called with file descriptors which could belong to various VFS drivers. +2. The file descriptors are divided into groups each belonging to one VFS driver. +3. The file descriptors belonging to non-socket VFS drivers are handed over to the given VFS drivers by :cpp:func:`start_select` + described later on this page. This function represents the driver-specific implementation of :cpp:func:`select` for + the given driver. This should be a non-blocking call which means the function should immediately return after setting up + the environment for checking events related to the given file descriptors. +4. The file descriptors belonging to the socket VFS driver are handed over to the socket driver by + :cpp:func:`socket_select` described later on this page. This is a blocking call which means that it will return only + if there is an event related to socket file descriptors or a non-socket driver signals :cpp:func:`socket_select` + to exit. +5. Results are collected from each VFS driver and all drivers are stopped by deinitiazation + of the environment for checking events. +6. The :cpp:func:`select` call ends and returns the appropriate results. + +Non-socket VFS drivers +"""""""""""""""""""""" + +If you want to use :cpp:func:`select` with a file descriptor belonging to a non-socket VFS driver +then you need to register the driver with functions :cpp:func:`start_select` and +:cpp:func:`end_select` similarly to the following example: .. highlight:: c @@ -81,25 +101,57 @@ then you need to register VFS with the functions :cpp:func:`start_select` and :cpp:func:`start_select` is called for setting up the environment for detection of read/write/error conditions on file descriptors belonging to the -given VFS. :cpp:func:`end_select` is called to stop/deinitialize/free the -environment which was setup by :cpp:func:`start_select`. Please refer to the +given VFS driver. + +:cpp:func:`end_select` is called to stop/deinitialize/free the +environment which was setup by :cpp:func:`start_select`. + +Please refer to the reference implementation for the UART peripheral in :component_file:`vfs/vfs_uart.c` and most particularly to the functions :cpp:func:`esp_vfs_dev_uart_register`, :cpp:func:`uart_start_select`, and -:cpp:func:`uart_end_select`. +:cpp:func:`uart_end_select` for more information. Please check the following examples that demonstrate the use of :cpp:func:`select` with VFS file descriptors: -- :example:`peripherals/uart_select` -- :example:`system/select` + - :example:`peripherals/uart/uart_select` + - :example:`system/select` -<<<<<<< HEAD -If :cpp:func:`select` is used for socket file descriptors only then one can -enable the :envvar:`CONFIG_LWIP_USE_ONLY_LWIP_SELECT` option which can reduce the code -======= -If you use :cpp:func:`select` for socket file descriptors, you can enable the :envvar:`CONFIG_LWIP_USE_ONLY_LWIP_SELECT` option to reduce the code ->>>>>>> afc2fdf27... Review all the files in the esp-idf's api_ref/storage directory -size and improve performance. +Socket VFS drivers +"""""""""""""""""" +A socket VFS driver is using its own internal implementation of :cpp:func:`select` and non-socket VFS drivers notify +it upon read/write/error conditions. + +A socket VFS driver needs to be registered with the following functions defined: + +.. highlight:: c + +:: + + // In definition of esp_vfs_t: + .socket_select = &lwip_select, + .get_socket_select_semaphore = &lwip_get_socket_select_semaphore, + .stop_socket_select = &lwip_stop_socket_select, + .stop_socket_select_isr = &lwip_stop_socket_select_isr, + // ... other members initialized + +:cpp:func:`socket_select` is the internal implementation of :cpp:func:`select` for the socket driver. It works only +with file descriptors belonging to the socket VFS. + +:cpp:func:`get_socket_select_semaphore` returns the signalization object (semaphore) which will be used in non-socket +drivers to stop the waiting in :cpp:func:`socket_select`. + +:cpp:func:`stop_socket_select` call is used to stop the waiting in :cpp:func:`socket_select` by passing the object +returned by :cpp:func:`get_socket_select_semaphore`. + +:cpp:func:`stop_socket_select_isr` has the same functionality as :cpp:func:`stop_socket_select` but it can be used +from ISR. + +Please see :component_file:`lwip/port/esp32/vfs_lwip.c` for a reference socket driver implementation using LWIP. + +.. note:: + If you use :cpp:func:`select` for socket file descriptors only then you can enable the + :envvar:`CONFIG_LWIP_USE_ONLY_LWIP_SELECT` option to reduce the code size and improve performance. Paths ----- diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index ed4db5e7ed..681a9ec614 100644 --- a/components/vfs/vfs.c +++ b/components/vfs/vfs.c @@ -858,6 +858,8 @@ static void esp_vfs_log_fd_set(const char *fds_name, const fd_set *fds) int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout) { + // NOTE: Please see the "Synchronous input/output multiplexing" section of the ESP-IDF Programming Guide + // (API Reference -> Storage -> Virtual Filesystem) for a general overview of the implementation of VFS select(). int ret = 0; struct _reent* r = __getreent(); From 26fc858ea4f6142d80eead64b743d3ef9eddb71b Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Thu, 1 Aug 2019 13:54:31 +0800 Subject: [PATCH 410/486] spi_common: remove deprecated spi_common_periph_claim macros --- components/driver/include/driver/spi_common.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/components/driver/include/driver/spi_common.h b/components/driver/include/driver/spi_common.h index 8f7c97f3d5..9c8bf75460 100644 --- a/components/driver/include/driver/spi_common.h +++ b/components/driver/include/driver/spi_common.h @@ -143,18 +143,6 @@ esp_err_t spi_bus_free(spi_host_device_t host); */ bool spicommon_periph_claim(spi_host_device_t host, const char* source); -// The macro is to keep the back-compatibility of IDF v3.2 and before -// In this way we can call spicommon_periph_claim with two arguments, or the host with the source set to the calling function name -// When two arguments (host, func) are given, __spicommon_periph_claim2 is called -// or if only one arguments (host) is given, __spicommon_periph_claim1 is called -#define spicommon_periph_claim(host...) __spicommon_periph_claim(host, 2, 1) -#define __spicommon_periph_claim(host, source, n, ...) __spicommon_periph_claim ## n(host, source) -#define __spicommon_periph_claim1(host, _) ({ \ - char* warning_str = "calling spicommon_periph_claim without source string is deprecated.";\ - spicommon_periph_claim(host, __FUNCTION__); }) - -#define __spicommon_periph_claim2(host, func) spicommon_periph_claim(host, func) - /** * @brief Check whether the spi periph is in use. * From 8d8ea6f698123fdc0464aa719f3e0c8f0fe1279a Mon Sep 17 00:00:00 2001 From: Wang Fang Date: Mon, 5 Aug 2019 21:25:15 +0800 Subject: [PATCH 411/486] Add Chinese translation for modules-and-boards.rst in hw-reference folder. Note: Also modify the table in en version --- docs/en/hw-reference/modules-and-boards.rst | 14 +- .../zh_CN/hw-reference/modules-and-boards.rst | 311 +++++++++++++++++- 2 files changed, 317 insertions(+), 8 deletions(-) diff --git a/docs/en/hw-reference/modules-and-boards.rst b/docs/en/hw-reference/modules-and-boards.rst index 838348e252..caacbc8e40 100644 --- a/docs/en/hw-reference/modules-and-boards.rst +++ b/docs/en/hw-reference/modules-and-boards.rst @@ -4,6 +4,8 @@ ESP32 Modules and Boards ************************ +:link_to_translation:`zh_CN:[中文]` + Espressif designs and manufactures different modules and development boards to help users evaluate the potential of the ESP32 family of chips. This document provides description of modules and development boards currently available from Espressif. @@ -22,8 +24,6 @@ This is a family of ESP32-based modules with some integrated key components, inc The key characteristics of these modules are summarized in the table below. Some additional details are covered in the following sections. =================== ============ =========== ========= ==== =============== - Key Components -------------------- ------------------------------------------ --------------- Module Chip Flash, MB PSRAM, MB Ant. Dimensions, mm =================== ============ =========== ========= ==== =============== ESP32-WROOM-32 ESP32-D0WDQ6 4 -- MIFA 18 × 25.5 × 3.1 @@ -133,7 +133,7 @@ This series consists of a few modifications of ESP32-WROOM-32x modules, which am For details, see the table in Section :ref:`esp-wroom-solo-wrover-modules` and `Espressif Products Ordering Information`_. * **ESP32-WROVER (PCB)** and **ESP32-WROVER (IPEX)** have PSRAM that operates at 1.8 V and supports up to 144 MHz clock rate. -* **ESP32-WROVER-B** and **ESP32-WROVER-IB** have PSRAM that operates at 3.3 V and can supports up to 133 MHz clock rate. +* **ESP32-WROVER-B** and **ESP32-WROVER-IB** have PSRAM that operates at 3.3 V and supports up to 133 MHz clock rate. The picture below shows an ESP32-WROVER module with a PCB antenna. @@ -179,7 +179,7 @@ Depending on the intended functionality, different development boards feature: - Access to different ESP32 GPIO pins. - Different interfaces: USB, JTAG. -- Different peripherals: touchpads, LCD screens, SD card slots, headers for camera modules, etc. +- Different peripherals: touchpads, LCD screens, SD card slots, female headers for camera modules, etc. .. _esp-modules-and-boards-esp32-pico-kit: @@ -257,12 +257,12 @@ ESP-WROVER-KIT V4.1 This board features: -- dual port USB-to-serial converter for programming +- Dual port USB-to-serial converter for programming - JTAG interface for debugging - MicroSD card slot - 3.2” SPI LCD screen -- header for a camera module -- RGB diode for diagnostics +- Female headers for a camera module +- RGB LED for diagnostics - 32.768 kHz XTAL for internal RTC to operate it in low power modes Power can be supplied either via USB or via a standard 5 mm power supply jack. A power source can be selected with a jumper and can be turned on/off with a separate switch. diff --git a/docs/zh_CN/hw-reference/modules-and-boards.rst b/docs/zh_CN/hw-reference/modules-and-boards.rst index 311e160fea..eeeb746d23 100644 --- a/docs/zh_CN/hw-reference/modules-and-boards.rst +++ b/docs/zh_CN/hw-reference/modules-and-boards.rst @@ -1 +1,310 @@ -.. include:: ../../en/hw-reference/modules-and-boards.rst \ No newline at end of file +.. _esp-modules-and-boards: + +***************************** +ESP32 系列模组和开发板 +***************************** + +:link_to_translation:`en:[English]` + +乐鑫设计并提供多种模组和开发板以供用户体验 ESP32 系列芯片的强大功能。 + +本文档主要介绍了当前乐鑫所提供的各种模组和开发板。 + +.. note:: + + 如需了解较早版本或已停产的模组和开发板,请参考 :ref:`esp-modules-and-boards-previous`。 + +.. _esp-wroom-solo-wrover-modules: + +WROOM、SOLO、WROVER 和 PICO 系列模组 +===================================== + +WROOM、SOLO、WROVER 和 PICO 系列模组内置 ESP32 芯片并集成了晶振、天线匹配电路等重要组件,可直接集成到终端产品中。如果再结合一些其他组件,例如编程接口、Bootstrapping 电阻和排针,您就可以体验 ESP32 的强大功能了。 + +下表总结了上述系列模组的主要特点,详细信息见后续章节。 + ++---------------------+--------------+-------------+-------------+------+-----------------+ +| 模组 | 芯片 | Flash (MB) | PSRAM (MB) | 天线 | 尺寸 (mm) | ++---------------------+--------------+-------------+-------------+------+-----------------+ +| ESP32-WROOM-32 | ESP32-D0WDQ6 | 4 | – | MIFA | 18 × 25.5 × 3.1 | ++---------------------+--------------+-------------+-------------+------+-----------------+ +| ESP32-WROOM-32D | ESP32-D0WD | 4、8 或 16 | – | MIFA | 18 × 25.5 × 3.1 | ++---------------------+--------------+-------------+-------------+------+-----------------+ +| ESP32-WROOM-32U | ESP32-D0WD | 4、8 或 16 | – | U.FL | 18 × 19.2 × 3.1 | ++---------------------+--------------+-------------+-------------+------+-----------------+ +| ESP32-SOLO-1 | ESP32-S0WD | 4 | – | MIFA | 18 × 25.5 × 3.1 | ++---------------------+--------------+-------------+-------------+------+-----------------+ +| ESP32-WROVER (PCB) | ESP32-D0WDQ6 | 4 | 8 | MIFA | 18 × 31.4 × 3.3 | ++---------------------+--------------+-------------+-------------+------+-----------------+ +| ESP32-WROVER (IPEX) | ESP32-D0WDQ6 | 4 | 8 | U.FL | 18 × 31.4 × 3.3 | ++---------------------+--------------+-------------+-------------+------+-----------------+ +| ESP32-WROVER-B | ESP32-D0WD | 4、8 或 16 | 8 | MIFA | 18 × 31.4 × 3.3 | ++---------------------+--------------+-------------+-------------+------+-----------------+ +| ESP32-WROVER-IB | ESP32-D0WD | 4、8 或 16 | 8 | U.FL | 18 × 31.4 × 3.3 | ++---------------------+--------------+-------------+-------------+------+-----------------+ + + +* ESP32-**D**.. 代表双核芯片,ESP32-**S**.. 代表单核芯片; +* MIFA - 蛇形倒 F 天线; +* U.FL - U.FL/IPEX 天线连接器; +* ESP32-WROOM-32x、ESP32-WROVER-B 和 ESP32-WROVER-IB 模组默认内置 4 MB flash,客户可定制 8 MB 和 16 MB flash,详情见 `乐鑫产品订购信息`_ (PDF) 和《`ESP32 技术规格书 `_》(PDF); +* 最初发布的 ESP32-WROVER 模组内置 4 MB PSRAM; +* *ESP-WROOM-32* 是 *ESP32-WROOM-32* 的曾用名。 + +.. _esp-modules-and-boards-esp32-wroom-32: + +ESP32-WROOM-32 模组 +-------------------- + +ESP32-WROOM-32 模组是 WROOM/WROVER 系列最先发布的模组,内置 ESP32-D0WDQ6 芯片,是一款基础且常用的 ESP32 模组。 + +有关该模组的详细信息,请查看 :ref:`esp-wroom-solo-wrover-modules` 章节中的表格。 + +.. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-wroom-32-front-back.jpg + :align: center + :alt: ESP32-WROOM-32 module (front and back) + :width: 45% + + ESP32-WROOM-32 模组(正反面图) + +相关文档 +^^^^^^^^^^^^^ + +* 《`ESP32-WROOM-32 技术规格书 `_》(PDF); +* `ESP32-WROOM-32 参考设计 `_,包括原理图(由 OrCAD Capture 绘制)、PCB 布局(由 Mentor PADS 绘制)、GERBER 文件和 BOM 清单。 + +.. _esp-modules-and-boards-esp32-wroom-32d-and-u: + +ESP32-WROOM-32D/ESP32-WROOM-32U 模组 +-------------------------------------- + +两款模组均集成了 ESP32-D0WD 芯片,与 :ref:`esp-modules-and-boards-esp32-wroom-32` 集成的 ESP32-D0WDQ6 相比,ESP32-D0WD 芯片的封装更小,在 PCB 上占用的面积更小。 + +有关这两款模组的详细信息,请查看 :ref:`esp-wroom-solo-wrover-modules` 中的表格和 `乐鑫产品订购信息`_。 + +ESP32-WROOM-32U 是整个 WROOM/WROVER 模组系列中最小的模组。 + +.. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-wroom-32d-front-back.jpg + :align: center + :alt: ESP32-WROOM-32D module (front and back) + :width: 45% + + ESP32-WROOM-32D 模组(正反面图) + +.. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-wroom-32u-front-back.jpg + :align: center + :alt: ESP32-WROOM-32U module (front and back) + :width: 45% + + ESP32-WROOM-32U 模组(正反面图) + +相关文档 +^^^^^^^^^^^^^ + +* 《`ESP32-WROOM-32D/ESP32-WROOM-32U 技术规格书 `_》(PDF) + + +.. _esp-modules-and-boards-esp32-solo-1: + +ESP32-SOLO-1 模组 +----------------- + +ESP32-SOLO-1 模组是 ESP32-WROOM-32D 模组的简化版本,内置一个 ESP32 单核芯片,支持高达 160 MHz 的时钟频率。 + +有关此模组的详细信息,请查看 :ref:`esp-wroom-solo-wrover-modules` 章节中的表格和 `乐鑫产品订购信息`_。 + +.. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-solo-1-front-back.jpg + :align: center + :alt: ESP32-SOLO-1 module (front and back) + :width: 45% + + ESP32-SOLO-1 模组(正反面图) + +相关文档 +^^^^^^^^^^^^^ + +* 《`ESP32-SOLO-1 技术规格书 `__》(PDF) + +.. _esp-modules-and-boards-esp32-wrover: + +ESP32-WROVER 系列模组 +------------------------- + +ESP32-WROVER 系列模组在 ESP32-WROOM-32x 模组的基础上进行了一些修改,其中包含一些功能升级,并新增 8 MB SPI PSRAM(伪静态 RAM)。 + +有关该模组的详细信息,请查看 :ref:`esp-wroom-solo-wrover-modules` 章节中的表格和 `乐鑫产品订购信息`_。 + +* **ESP32-WROVER (PCB)** 模组和 **ESP32-WROVER (IPEX)** 模组内置 1.8 V PSRAM,支持 144 MHz 时钟频率。 +* **ESP32-WROVER-B** 模组和 **ESP32-WROVER-IB** 模组内置 3.3 V PSRAM,支持 133 MHz 时钟频率。 + +下图为配备有 PCB 天线的 ESP32-WROVER 模组: + +.. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-wrover.jpg + :align: center + :alt: ESP32-WROVER module (front and back) + :width: 40% + + ESP32-WROVER 模组(正反面图) + +相关文档 +^^^^^^^^^^^^^ + +* 《`ESP32-WROVER 技术规格书 `__》(PDF) +* 《`ESP32-WROVER-B 技术规格书 `__》(PDF) +* 《`ESP-PSRAM64 & ESP-PSRAM64H 技术规格书 `__》(PDF) +* `ESP32-WROVER 参考设计 `_ 包含原理图(由 OrCAD Capture 绘制)、PCB 布局(由 Mentor PADS 绘制)、GERBER 文件和 BOM 清单。 + +ESP32-PICO-D4 模组 +------------------ + +ESP32-PICO-D4 模组是一款 SiP 模组,无缝集成了所有外设,包括: + +- 4 MB flash +- 晶振 +- 滤波电容 +- RF 匹配电路 + +有关该模组的详细信息,请查看 `乐鑫产品订购信息`_。 + +相关文档 +^^^^^^^^^^^^^ + +* 《`ESP32-PICO-D4 技术规格书 `__》(PDF) + +ESP32 开发板 +================== + +ESP32 系列开发板功能各异,具体有以下不同点: + +- 访问的 ESP32 GPIO 管脚不同; +- 接口不同,包括 USB 和 JTAG; +- 外设不同,包括 TouchPad、LCD 显示屏、SD 卡槽和相机模组排母等。 + +.. _esp-modules-and-boards-esp32-pico-kit: + +ESP32-PICO-KIT V4.1 开发板 +--------------------------- +ESP32-PICO-KIT V4.1 开发板是基于 ESP32 的最小开发板,内置连接至电脑 USB 端口所需的所有组件,同时设有排针,可直接将此开发板插接于迷你面包板。 + +ESP32-PICO-KIT V4.1 开发板集成了 `ESP32-PICO-D4 模组`_,只需在 PCB (20 x 52 mm) 上添加少许外部组件即可构成一个功能齐全的开发板。这部分外部组件包括天线、LDO、USB 至 UART 桥接器、一个重置按钮和一个固件下载模式激活按钮。 + + +.. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-pico-kit-v4.1.jpg + :align: center + :alt: ESP32-PICO-KIT V4.1 board + :width: 50% + + ESP32-PICO-KIT V4.1 开发板 + +与 ESP32-PICO-KIT V4 相比,ESP32-PICO-KIT V4.1 开发板支持 CP2102N USB 至 UART 桥接器,可提供高达 3 Mbps 的传输速率。 + +相关文档 +^^^^^^^^^^^^^ + +* :doc:`../hw-reference/get-started-pico-kit` +* `ESP32-PICO-KIT V4.1 原理图 `_ (PDF) +* `ESP32-PICO-KIT 参考设计 `_,包含原理图(由 OrCAD Capture 绘制)、PCB 布局(由 Mentor PADS 绘制)、GERBER 文件和 BOM 清单。 +* 《`ESP32-PICO-D4 技术规格书 `_》(PDF) + +较早版本开发板 +^^^^^^^^^^^^^^^^^ + +* :ref:`esp-modules-and-boards-esp32-pico-kit-v4` +* :ref:`esp-modules-and-boards-esp32-pico-kit-v3` + + +.. _esp-modules-and-boards-esp32-devkitc: + +ESP32 DevKitC V4 开发板 +------------------------------ + +ESP32 DevKitC V4 开发板是一款小巧实用的开发板,具备以下特色功能: + +- 集成了 :ref:`esp-modules-and-boards-esp32-wroom-32` +- USB 转串口编程接口同时可为开发板供电 +- 设有排针 +- 设有重置按钮和固件下载模式激活按钮 +- 以及其他组件 + +与较早版本的 :ref:`esp-modules-and-boards-esp32-devkitc-v2` 相比,ESP32 DevKitC V4 开发板集成了 :ref:`esp-modules-and-boards-esp32-wrover` (而非 ESP32-WROOM-32 模组),同时内置 CP2102N 芯片,支持更高波特率。 + +.. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-devkitc-v4-front.jpg + :align: center + :alt: ESP32 DevKitC V4 board + :width: 50% + + ESP32 DevKitC V4 开发板 + +相关文档 +^^^^^^^^^^^^^ + +* :doc:`../hw-reference/get-started-devkitc` +* `ESP32-DevKitC 原理图 `_ (PDF) +* `ESP32-DevKitC 参考设计 `_,包含原理图(由 OrCAD Capture 绘制)、PCB 布局(由 Mentor PADS 绘制)、GERBER 文件和 BOM 清单。 +* `CP210x USB 至 UART 桥 VCP 驱动器 `_ + +较早版本开发板 +^^^^^^^^^^^^^^^^^ + +* :ref:`esp-modules-and-boards-esp32-devkitc-v2` + + +.. _esp-modules-and-boards-esp-wrover-kit: + +ESP-WROVER-KIT V4.1 开发板 +------------------------------- + +ESP-WROVER-KIT V4.1 开发板具备以下特色功能: + +- USB 转双串口转换器(用于后续编程) +- JTAG 调试接口 +- MicroSD 卡槽 +- 3.2” SPI LCD 显示屏 +- 相机模组排母 +- RGB 发光二极管 +- 支持 32.768 kHz 晶振输入用于 RTC 及低功耗模式操作 + +ESP-WROVER-KIT V4.1 开发板支持 USB 供电或标准的 5 毫米电源插座供电,可使用跳线选择电源,或使用独立的开关控制电源。 + +ESP-WROVER-KIT V4.1 开发板集成了 ESP-WROVER-B 模组,该模组集成了 8 MB PSRAM,方便用户灵活扩展存储空间,增强数据处理能力。ESP-WROVER-KIT V4.1 开发板还可以集成 :ref:`esp-wroom-solo-wrover-modules` 中所述的 ESP 其他版本模组。 + +与 :ref:`esp-modules-and-boards-esp-wrover-kit-v3` 相比,ESP-WROVER-KIT V4.1 开发板在设计上有以下改动: + +- JP8、JP11 和 JP13 合并成了一个 JP2。 +- USB 连接器的固定脚改为直插式,并移至板子右下角。 +- R61 已变更为零欧姆电阻。 +- 基于测试结果和采购选择,部分组件已由功能对等组件替代,例如 EN 和 Boot 按钮。 + +.. figure:: https://dl.espressif.com/dl/schematics/pictures/esp-wrover-kit-v4.1-front.jpg + :align: center + :alt: ESP-WROVER-KIT V4.1 board + :width: 90% + + ESP-WROVER-KIT V4.1 开发板 + +上图所示开发板集成了 ESP32-WROVER-B 模组。 + +相关文档 +^^^^^^^^^^^^^ + +* :doc:`../hw-reference/get-started-wrover-kit` +* `ESP-WROVER-KIT V4.1 原理图 `__ (PDF) +* :doc:`../api-guides/jtag-debugging/index` +* `FTDI 虚拟 COM 端口驱动`_ + +较早版本开发板 +^^^^^^^^^^^^^^^^^ + +* :ref:`esp-modules-and-boards-esp-wrover-kit-v3` +* :ref:`esp-modules-and-boards-esp-wrover-kit-v2` +* :ref:`esp-modules-and-boards-esp-wrover-kit-v1` + + +相关文档 +================= + +* :doc:`modules-and-boards-previous` + + +.. _FTDI 虚拟 COM 端口驱动: http://www.ftdichip.com/Drivers/VCP.htm +.. _乐鑫产品订购信息: https://www.espressif.com/sites/default/files/documentation/espressif_products_ordering_information_cn.pdf From 40e808c63b7c944faf81f85c6b2ae35981f1c447 Mon Sep 17 00:00:00 2001 From: xueyunfei Date: Mon, 5 Aug 2019 17:33:37 +0800 Subject: [PATCH 412/486] Try to allocate some LWIP memories in SPIRAM first. If failed, try to allocate in internal RAM then --- components/lwip/lwip | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lwip/lwip b/components/lwip/lwip index 61d840ff47..663b2fdb41 160000 --- a/components/lwip/lwip +++ b/components/lwip/lwip @@ -1 +1 @@ -Subproject commit 61d840ff4778f4946c8743f7e412345abcd537f1 +Subproject commit 663b2fdb41177c82f2aa5939e41aef54427d15cd From 3753283ef31f60d6142957ec00e08c1a221fe06f Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Thu, 1 Aug 2019 10:40:10 +0800 Subject: [PATCH 413/486] idf_tool: fix unicode decode error Closes https://github.com/espressif/esp-idf/issues/3841 --- tools/idf_tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/idf_tools.py b/tools/idf_tools.py index 9ad9f019d2..3d23412371 100755 --- a/tools/idf_tools.py +++ b/tools/idf_tools.py @@ -442,7 +442,7 @@ class IDFTool(object): raise ToolExecError('Command {} has returned non-zero exit code ({})\n'.format( ' '.join(self._current_options.version_cmd), e.returncode)) - in_str = version_cmd_result.decode() + in_str = version_cmd_result.decode("utf-8") match = re.search(self._current_options.version_regex, in_str) if not match: return UNKNOWN_VERSION From 1aaec808da079e5d5ad887e6973bbe3505456924 Mon Sep 17 00:00:00 2001 From: Jon Shallow Date: Sat, 13 Apr 2019 12:15:28 +0100 Subject: [PATCH 414/486] Add DTLS support to libcoap using MbedTLS This update supports DTLS, TLS is a future TODO components/coap/CMakeLists.txt: components/coap/component.mk: Add in the new files that have to be built Replace libcoap/src/coap_notls.c with libcoap/src/coap_mbedtls.c components/coap/libcoap: Update the version to include the current version for supporting MbedTLS components/coap/port/coap_debug.c: components/coap/port/coap_mbedtls.c: components/coap/port/include/coap/coap_dtls.h: New port files for DTLS components/coap/port/include/coap_config_posix.h: Include building with MbedTLS examples/protocols/coap_client/README.md: examples/protocols/coap_client/main/CMakeLists.txt: examples/protocols/coap_client/main/Kconfig.projbuild: examples/protocols/coap_client/main/coap_client_example_main.c: examples/protocols/coap_client/main/component.mk: Update CoAP client to support DTLS examples/protocols/coap_client/main/coap_ca.pem examples/protocols/coap_client/main/coap_client.crt examples/protocols/coap_client/main/coap_client.key New PKI Certs for CoAP client (copied from wpa2_enterprise example) examples/protocols/coap_server/README.md: examples/protocols/coap_server/main/CMakeLists.txt: examples/protocols/coap_server/main/Kconfig.projbuild: examples/protocols/coap_server/main/coap_server_example_main.c: examples/protocols/coap_server/main/component.mk: Update CoAP server to support DTLS Change "no data" to "Hello World!" to prevent confusion examples/protocols/coap_server/main/coap_ca.pem examples/protocols/coap_server/main/coap_server.crt examples/protocols/coap_server/main/coap_server.key New PKI Certs for CoAP server (copied from wpa2_enterprise example) Closes https://github.com/espressif/esp-idf/pull/3345 Closes https://github.com/espressif/esp-idf/issues/1379 --- components/coap/CMakeLists.txt | 8 +- components/coap/component.mk | 4 +- components/coap/libcoap | 2 +- components/coap/port/coap_debug.c | 888 ++++++++ components/coap/port/coap_io.c | 1417 ------------- components/coap/port/coap_mbedtls.c | 1796 +++++++++++++++++ components/coap/port/include/coap/coap_dtls.h | 631 ++++++ .../coap/port/include/coap_config_posix.h | 11 +- components/mbedtls/CMakeLists.txt | 3 +- components/mbedtls/port/esp_timing.c | 102 + examples/protocols/coap_client/README.md | 54 +- .../protocols/coap_client/main/CMakeLists.txt | 4 +- .../coap_client/main/Kconfig.projbuild | 91 +- .../protocols/coap_client/main/coap_ca.pem | 23 + .../coap_client/main/coap_client.crt | 70 + .../coap_client/main/coap_client.key | 27 + .../main/coap_client_example_main.c | 226 ++- .../protocols/coap_client/main/component.mk | 5 + examples/protocols/coap_server/README.md | 52 +- .../protocols/coap_server/main/CMakeLists.txt | 3 +- .../coap_server/main/Kconfig.projbuild | 74 + .../protocols/coap_server/main/coap_ca.pem | 23 + .../coap_server/main/coap_server.crt | 70 + .../coap_server/main/coap_server.key | 27 + .../main/coap_server_example_main.c | 176 +- .../protocols/coap_server/main/component.mk | 5 + 26 files changed, 4292 insertions(+), 1500 deletions(-) create mode 100644 components/coap/port/coap_debug.c delete mode 100644 components/coap/port/coap_io.c create mode 100644 components/coap/port/coap_mbedtls.c create mode 100644 components/coap/port/include/coap/coap_dtls.h create mode 100644 components/mbedtls/port/esp_timing.c create mode 100644 examples/protocols/coap_client/main/coap_ca.pem create mode 100644 examples/protocols/coap_client/main/coap_client.crt create mode 100644 examples/protocols/coap_client/main/coap_client.key create mode 100644 examples/protocols/coap_server/main/Kconfig.projbuild create mode 100644 examples/protocols/coap_server/main/coap_ca.pem create mode 100644 examples/protocols/coap_server/main/coap_server.crt create mode 100644 examples/protocols/coap_server/main/coap_server.key diff --git a/components/coap/CMakeLists.txt b/components/coap/CMakeLists.txt index aef9d31682..6d7dbb4517 100644 --- a/components/coap/CMakeLists.txt +++ b/components/coap/CMakeLists.txt @@ -8,7 +8,7 @@ set(srcs "libcoap/src/coap_hashkey.c" "libcoap/src/coap_session.c" "libcoap/src/coap_time.c" - "libcoap/src/coap_debug.c" + "port/coap_debug.c" "libcoap/src/encode.c" "libcoap/src/mem.c" "libcoap/src/net.c" @@ -18,8 +18,8 @@ set(srcs "libcoap/src/str.c" "libcoap/src/subscribe.c" "libcoap/src/uri.c" - "libcoap/src/coap_notls.c" - "port/coap_io.c") + "libcoap/src/coap_io.c" + "port/coap_mbedtls.c") set(COMPONENT_REQUIRES lwip) @@ -28,7 +28,7 @@ idf_component_register(SRCS "${srcs}" REQUIRES lwip) # Silence format truncation warning, until it is fixed upstream -set_source_files_properties(libcoap/src/coap_debug.c PROPERTIES COMPILE_FLAGS -Wno-format-truncation) +set_source_files_properties(port/coap_debug.c PROPERTIES COMPILE_FLAGS -Wno-format-truncation) # Needed for coap headers in public builds, also. # diff --git a/components/coap/component.mk b/components/coap/component.mk index 2eb07afd2c..46f7039870 100644 --- a/components/coap/component.mk +++ b/components/coap/component.mk @@ -4,11 +4,11 @@ COMPONENT_ADD_INCLUDEDIRS := port/include port/include/coap libcoap/include libcoap/include/coap2 -COMPONENT_OBJS = libcoap/src/address.o libcoap/src/async.o libcoap/src/block.o libcoap/src/coap_event.o libcoap/src/coap_hashkey.o libcoap/src/coap_session.o libcoap/src/coap_time.o libcoap/src/coap_debug.o libcoap/src/encode.o libcoap/src/mem.o libcoap/src/net.o libcoap/src/option.o libcoap/src/pdu.o libcoap/src/resource.o libcoap/src/str.o libcoap/src/subscribe.o libcoap/src/uri.o libcoap/src/coap_notls.o port/coap_io.o +COMPONENT_OBJS = libcoap/src/address.o libcoap/src/async.o libcoap/src/block.o libcoap/src/coap_event.o libcoap/src/coap_hashkey.o libcoap/src/coap_session.o libcoap/src/coap_time.o port/coap_debug.o libcoap/src/encode.o libcoap/src/mem.o libcoap/src/net.o libcoap/src/option.o libcoap/src/pdu.o libcoap/src/resource.o libcoap/src/str.o libcoap/src/subscribe.o libcoap/src/uri.o port/coap_mbedtls.o libcoap/src/coap_io.o COMPONENT_SRCDIRS := libcoap/src libcoap port COMPONENT_SUBMODULES += libcoap # Silence format truncation warning, until it is fixed upstream -libcoap/src/coap_debug.o: CFLAGS += -Wno-format-truncation +port/coap_debug.o: CFLAGS += -Wno-format-truncation diff --git a/components/coap/libcoap b/components/coap/libcoap index cfec0d072c..98954eb30a 160000 --- a/components/coap/libcoap +++ b/components/coap/libcoap @@ -1 +1 @@ -Subproject commit cfec0d072c5b99ed3e54828ca50ea2f6b91e1f50 +Subproject commit 98954eb30a2e728e172a6cd29430ae5bc999b585 diff --git a/components/coap/port/coap_debug.c b/components/coap/port/coap_debug.c new file mode 100644 index 0000000000..64d6a01800 --- /dev/null +++ b/components/coap/port/coap_debug.c @@ -0,0 +1,888 @@ +/* debug.c -- debug utilities + * + * Copyright (C) 2010--2012,2014--2019 Olaf Bergmann and others + * + * This file is part of the CoAP library libcoap. Please see + * README for terms of use. + */ + +#include "coap_config.h" + +#if defined(HAVE_STRNLEN) && defined(__GNUC__) && !defined(_GNU_SOURCE) +#define _GNU_SOURCE 1 +#endif + +#if defined(HAVE_ASSERT_H) && !defined(assert) +# include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_WS2TCPIP_H +#include +#endif + +#ifdef HAVE_TIME_H +#include +#endif + +#include "libcoap.h" +#include "coap_dtls.h" +#include "block.h" +#include "coap_debug.h" +#include "encode.h" +#include "net.h" +#include "coap_mutex.h" + +#ifdef WITH_LWIP +# define fprintf(fd, ...) LWIP_PLATFORM_DIAG((__VA_ARGS__)) +# define fflush(...) +#endif + +#ifdef WITH_CONTIKI +# ifndef DEBUG +# define DEBUG DEBUG_PRINT +# endif /* DEBUG */ +#include "net/ip/uip-debug.h" +#endif + +static coap_log_t maxlog = LOG_WARNING; /* default maximum log level */ + +static int use_fprintf_for_show_pdu = 1; /* non zero to output with fprintf */ + +const char *coap_package_name(void) { + return PACKAGE_NAME; +} + +const char *coap_package_version(void) { + return PACKAGE_STRING; +} + +void +coap_set_show_pdu_output(int use_fprintf) { + use_fprintf_for_show_pdu = use_fprintf; +} + +coap_log_t +coap_get_log_level(void) { + return maxlog; +} + +void +coap_set_log_level(coap_log_t level) { + maxlog = level; +} + +/* this array has the same order as the type log_t */ +static const char *loglevels[] = { + "EMRG", "ALRT", "CRIT", "ERR ", "WARN", "NOTE", "INFO", "DEBG" +}; + +#ifdef HAVE_TIME_H + +COAP_STATIC_INLINE size_t +print_timestamp(char *s, size_t len, coap_tick_t t) { + struct tm *tmp; + time_t now = coap_ticks_to_rt(t); + tmp = localtime(&now); + return strftime(s, len, "%b %d %H:%M:%S", tmp); +} + +#else /* alternative implementation: just print the timestamp */ + +COAP_STATIC_INLINE size_t +print_timestamp(char *s, size_t len, coap_tick_t t) { +#ifdef HAVE_SNPRINTF + return snprintf(s, len, "%u.%03u", + (unsigned int)coap_ticks_to_rt(t), + (unsigned int)(t % COAP_TICKS_PER_SECOND)); +#else /* HAVE_SNPRINTF */ + /* @todo do manual conversion of timestamp */ + return 0; +#endif /* HAVE_SNPRINTF */ +} + +#endif /* HAVE_TIME_H */ + +#ifndef HAVE_STRNLEN +/** + * A length-safe strlen() fake. + * + * @param s The string to count characters != 0. + * @param maxlen The maximum length of @p s. + * + * @return The length of @p s. + */ +static inline size_t +strnlen(const char *s, size_t maxlen) { + size_t n = 0; + while(*s++ && n < maxlen) + ++n; + return n; +} +#endif /* HAVE_STRNLEN */ + +static size_t +print_readable( const uint8_t *data, size_t len, + unsigned char *result, size_t buflen, int encode_always ) { + const uint8_t hex[] = "0123456789ABCDEF"; + size_t cnt = 0; + assert(data || len == 0); + + if (buflen == 0) { /* there is nothing we can do here but return */ + return 0; + } + + while (len) { + if (!encode_always && isprint(*data)) { + if (cnt+1 < buflen) { /* keep one byte for terminating zero */ + *result++ = *data; + ++cnt; + } else { + break; + } + } else { + if (cnt+4 < buflen) { /* keep one byte for terminating zero */ + *result++ = '\\'; + *result++ = 'x'; + *result++ = hex[(*data & 0xf0) >> 4]; + *result++ = hex[*data & 0x0f]; + cnt += 4; + } else + break; + } + + ++data; --len; + } + + *result = '\0'; /* add a terminating zero */ + return cnt; +} + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +size_t +coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t len) { +#if defined( HAVE_ARPA_INET_H ) || defined( HAVE_WS2TCPIP_H ) + const void *addrptr = NULL; + in_port_t port; + unsigned char *p = buf; + size_t need_buf; + + switch (addr->addr.sa.sa_family) { + case AF_INET: + addrptr = &addr->addr.sin.sin_addr; + port = ntohs(addr->addr.sin.sin_port); + need_buf = INET_ADDRSTRLEN; + break; + case AF_INET6: + if (len < 7) /* do not proceed if buffer is even too short for [::]:0 */ + return 0; + + *p++ = '['; + + addrptr = &addr->addr.sin6.sin6_addr; + port = ntohs(addr->addr.sin6.sin6_port); + need_buf = INET6_ADDRSTRLEN; + + break; + default: + memcpy(buf, "(unknown address type)", min(22, len)); + return min(22, len); + } + + /* Cast needed for Windows, since it doesn't have the correct API signature. */ + if (inet_ntop(addr->addr.sa.sa_family, addrptr, (char *)p, + min(len, need_buf)) == 0) { + perror("coap_print_addr"); + return 0; + } + + p += strnlen((char *)p, len); + + if (addr->addr.sa.sa_family == AF_INET6) { + if (p < buf + len) { + *p++ = ']'; + } else + return 0; + } + + p += snprintf((char *)p, buf + len - p + 1, ":%d", port); + + return buf + len - p; +#else /* HAVE_ARPA_INET_H */ +# if WITH_CONTIKI + unsigned char *p = buf; + uint8_t i; +# if NETSTACK_CONF_WITH_IPV6 + const uint8_t hex[] = "0123456789ABCDEF"; + + if (len < 41) + return 0; + + *p++ = '['; + + for (i=0; i < 16; i += 2) { + if (i) { + *p++ = ':'; + } + *p++ = hex[(addr->addr.u8[i] & 0xf0) >> 4]; + *p++ = hex[(addr->addr.u8[i] & 0x0f)]; + *p++ = hex[(addr->addr.u8[i+1] & 0xf0) >> 4]; + *p++ = hex[(addr->addr.u8[i+1] & 0x0f)]; + } + *p++ = ']'; +# else /* WITH_UIP6 */ +# warning "IPv4 network addresses will not be included in debug output" + + if (len < 21) + return 0; +# endif /* WITH_UIP6 */ + if (buf + len - p < 6) + return 0; + +#ifdef HAVE_SNPRINTF + p += snprintf((char *)p, buf + len - p + 1, ":%d", uip_htons(addr->port)); +#else /* HAVE_SNPRINTF */ + /* @todo manual conversion of port number */ +#endif /* HAVE_SNPRINTF */ + + return p - buf; +# else /* WITH_CONTIKI */ + /* TODO: output addresses manually */ +# warning "inet_ntop() not available, network addresses will not be included in debug output" +# endif /* WITH_CONTIKI */ + return 0; +#endif +} + +#ifdef WITH_CONTIKI +# define fprintf(fd, ...) PRINTF(__VA_ARGS__) +# define fflush(...) + +# ifdef HAVE_VPRINTF +# define vfprintf(fd, ...) vprintf(__VA_ARGS__) +# else /* HAVE_VPRINTF */ +# define vfprintf(fd, ...) PRINTF(__VA_ARGS__) +# endif /* HAVE_VPRINTF */ +#endif /* WITH_CONTIKI */ + +/** Returns a textual description of the message type @p t. */ +static const char * +msg_type_string(uint16_t t) { + static const char *types[] = { "CON", "NON", "ACK", "RST", "???" }; + + return types[min(t, sizeof(types)/sizeof(char *) - 1)]; +} + +/** Returns a textual description of the method or response code. */ +static const char * +msg_code_string(uint16_t c) { + static const char *methods[] = { "0.00", "GET", "POST", "PUT", "DELETE", + "FETCH", "PATCH", "iPATCH" }; + static const char *signals[] = { "7.00", "CSM", "Ping", "Pong", "Release", + "Abort" }; + static char buf[5]; + + if (c < sizeof(methods)/sizeof(const char *)) { + return methods[c]; + } else if (c >= 224 && c - 224 < (int)(sizeof(signals)/sizeof(const char *))) { + return signals[c-224]; + } else { + snprintf(buf, sizeof(buf), "%u.%02u", (c >> 5) & 0x7, c & 0x1f); + return buf; + } +} + +/** Returns a textual description of the option name. */ +static const char * +msg_option_string(uint8_t code, uint16_t option_type) { + struct option_desc_t { + uint16_t type; + const char *name; + }; + + static struct option_desc_t options[] = { + { COAP_OPTION_IF_MATCH, "If-Match" }, + { COAP_OPTION_URI_HOST, "Uri-Host" }, + { COAP_OPTION_ETAG, "ETag" }, + { COAP_OPTION_IF_NONE_MATCH, "If-None-Match" }, + { COAP_OPTION_OBSERVE, "Observe" }, + { COAP_OPTION_URI_PORT, "Uri-Port" }, + { COAP_OPTION_LOCATION_PATH, "Location-Path" }, + { COAP_OPTION_URI_PATH, "Uri-Path" }, + { COAP_OPTION_CONTENT_FORMAT, "Content-Format" }, + { COAP_OPTION_MAXAGE, "Max-Age" }, + { COAP_OPTION_URI_QUERY, "Uri-Query" }, + { COAP_OPTION_ACCEPT, "Accept" }, + { COAP_OPTION_LOCATION_QUERY, "Location-Query" }, + { COAP_OPTION_BLOCK2, "Block2" }, + { COAP_OPTION_BLOCK1, "Block1" }, + { COAP_OPTION_PROXY_URI, "Proxy-Uri" }, + { COAP_OPTION_PROXY_SCHEME, "Proxy-Scheme" }, + { COAP_OPTION_SIZE1, "Size1" }, + { COAP_OPTION_SIZE2, "Size2" }, + { COAP_OPTION_NORESPONSE, "No-Response" } + }; + + static struct option_desc_t options_csm[] = { + { COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE, "Max-Message-Size" }, + { COAP_SIGNALING_OPTION_BLOCK_WISE_TRANSFER, "Block-wise-Transfer" } + }; + + static struct option_desc_t options_pingpong[] = { + { COAP_SIGNALING_OPTION_CUSTODY, "Custody" } + }; + + static struct option_desc_t options_release[] = { + { COAP_SIGNALING_OPTION_ALTERNATIVE_ADDRESS, "Alternative-Address" }, + { COAP_SIGNALING_OPTION_HOLD_OFF, "Hold-Off" } + }; + + static struct option_desc_t options_abort[] = { + { COAP_SIGNALING_OPTION_BAD_CSM_OPTION, "Bad-CSM-Option" } + }; + + static char buf[6]; + size_t i; + + if (code == COAP_SIGNALING_CSM) { + for (i = 0; i < sizeof(options_csm)/sizeof(struct option_desc_t); i++) { + if (option_type == options_csm[i].type) { + return options_csm[i].name; + } + } + } else if (code == COAP_SIGNALING_PING || code == COAP_SIGNALING_PONG) { + for (i = 0; i < sizeof(options_pingpong)/sizeof(struct option_desc_t); i++) { + if (option_type == options_pingpong[i].type) { + return options_pingpong[i].name; + } + } + } else if (code == COAP_SIGNALING_RELEASE) { + for (i = 0; i < sizeof(options_release)/sizeof(struct option_desc_t); i++) { + if (option_type == options_release[i].type) { + return options_release[i].name; + } + } + } else if (code == COAP_SIGNALING_ABORT) { + for (i = 0; i < sizeof(options_abort)/sizeof(struct option_desc_t); i++) { + if (option_type == options_abort[i].type) { + return options_abort[i].name; + } + } + } else { + /* search option_type in list of known options */ + for (i = 0; i < sizeof(options)/sizeof(struct option_desc_t); i++) { + if (option_type == options[i].type) { + return options[i].name; + } + } + } + /* unknown option type, just print to buf */ + snprintf(buf, sizeof(buf), "%u", option_type); + return buf; +} + +static unsigned int +print_content_format(unsigned int format_type, + unsigned char *result, unsigned int buflen) { + struct desc_t { + unsigned int type; + const char *name; + }; + + static struct desc_t formats[] = { + { COAP_MEDIATYPE_TEXT_PLAIN, "text/plain" }, + { COAP_MEDIATYPE_APPLICATION_LINK_FORMAT, "application/link-format" }, + { COAP_MEDIATYPE_APPLICATION_XML, "application/xml" }, + { COAP_MEDIATYPE_APPLICATION_OCTET_STREAM, "application/octet-stream" }, + { COAP_MEDIATYPE_APPLICATION_EXI, "application/exi" }, + { COAP_MEDIATYPE_APPLICATION_JSON, "application/json" }, + { COAP_MEDIATYPE_APPLICATION_CBOR, "application/cbor" }, + { COAP_MEDIATYPE_APPLICATION_COSE_SIGN, "application/cose; cose-type=\"cose-sign\"" }, + { COAP_MEDIATYPE_APPLICATION_COSE_SIGN1, "application/cose; cose-type=\"cose-sign1\"" }, + { COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT, "application/cose; cose-type=\"cose-encrypt\"" }, + { COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT0, "application/cose; cose-type=\"cose-encrypt0\"" }, + { COAP_MEDIATYPE_APPLICATION_COSE_MAC, "application/cose; cose-type=\"cose-mac\"" }, + { COAP_MEDIATYPE_APPLICATION_COSE_MAC0, "application/cose; cose-type=\"cose-mac0\"" }, + { COAP_MEDIATYPE_APPLICATION_COSE_KEY, "application/cose-key" }, + { COAP_MEDIATYPE_APPLICATION_COSE_KEY_SET, "application/cose-key-set" }, + { COAP_MEDIATYPE_APPLICATION_SENML_JSON, "application/senml+json" }, + { COAP_MEDIATYPE_APPLICATION_SENSML_JSON, "application/sensml+json" }, + { COAP_MEDIATYPE_APPLICATION_SENML_CBOR, "application/senml+cbor" }, + { COAP_MEDIATYPE_APPLICATION_SENSML_CBOR, "application/sensml+cbor" }, + { COAP_MEDIATYPE_APPLICATION_SENML_EXI, "application/senml-exi" }, + { COAP_MEDIATYPE_APPLICATION_SENSML_EXI, "application/sensml-exi" }, + { COAP_MEDIATYPE_APPLICATION_SENML_XML, "application/senml+xml" }, + { COAP_MEDIATYPE_APPLICATION_SENSML_XML, "application/sensml+xml" }, + { 75, "application/dcaf+cbor" } + }; + + size_t i; + + /* search format_type in list of known content formats */ + for (i = 0; i < sizeof(formats)/sizeof(struct desc_t); i++) { + if (format_type == formats[i].type) { + return snprintf((char *)result, buflen, "%s", formats[i].name); + } + } + + /* unknown content format, just print numeric value to buf */ + return snprintf((char *)result, buflen, "%d", format_type); +} + +/** + * Returns 1 if the given @p content_format is either unknown or known + * to carry binary data. The return value @c 0 hence indicates + * printable data which is also assumed if @p content_format is @c 01. + */ +COAP_STATIC_INLINE int +is_binary(int content_format) { + return !(content_format == -1 || + content_format == COAP_MEDIATYPE_TEXT_PLAIN || + content_format == COAP_MEDIATYPE_APPLICATION_LINK_FORMAT || + content_format == COAP_MEDIATYPE_APPLICATION_XML || + content_format == COAP_MEDIATYPE_APPLICATION_JSON); +} + +#define COAP_DO_SHOW_OUTPUT_LINE \ + do { \ + if (use_fprintf_for_show_pdu) { \ + fprintf(COAP_DEBUG_FD, "%s", outbuf); \ + } \ + else { \ + coap_log(level, "%s", outbuf); \ + } \ + } while (0) + +void +coap_show_pdu(coap_log_t level, const coap_pdu_t *pdu) { +#if COAP_CONSTRAINED_STACK + static coap_mutex_t static_show_pdu_mutex = COAP_MUTEX_INITIALIZER; + static unsigned char buf[1024]; /* need some space for output creation */ + static char outbuf[COAP_DEBUG_BUF_SIZE]; +#else /* ! COAP_CONSTRAINED_STACK */ + unsigned char buf[1024]; /* need some space for output creation */ + char outbuf[COAP_DEBUG_BUF_SIZE]; +#endif /* ! COAP_CONSTRAINED_STACK */ + size_t buf_len = 0; /* takes the number of bytes written to buf */ + int encode = 0, have_options = 0, i; + coap_opt_iterator_t opt_iter; + coap_opt_t *option; + int content_format = -1; + size_t data_len; + unsigned char *data; + int outbuflen = 0; + + /* Save time if not needed */ + if (level > coap_get_log_level()) + return; + +#if COAP_CONSTRAINED_STACK + coap_mutex_lock(&static_show_pdu_mutex); +#endif /* COAP_CONSTRAINED_STACK */ + + snprintf(outbuf, sizeof(outbuf), "v:%d t:%s c:%s i:%04x {", + COAP_DEFAULT_VERSION, msg_type_string(pdu->type), + msg_code_string(pdu->code), pdu->tid); + + for (i = 0; i < pdu->token_length; i++) { + outbuflen = strlen(outbuf); + snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, + "%02x", pdu->token[i]); + } + outbuflen = strlen(outbuf); + snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, "}"); + + /* show options, if any */ + coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL); + + outbuflen = strlen(outbuf); + snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, " ["); + while ((option = coap_option_next(&opt_iter))) { + if (!have_options) { + have_options = 1; + } else { + outbuflen = strlen(outbuf); + snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, ","); + } + + if (pdu->code == COAP_SIGNALING_CSM) switch(opt_iter.type) { + case COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE: + buf_len = snprintf((char *)buf, sizeof(buf), "%u", + coap_decode_var_bytes(coap_opt_value(option), + coap_opt_length(option))); + break; + default: + buf_len = 0; + break; + } else if (pdu->code == COAP_SIGNALING_PING + || pdu->code == COAP_SIGNALING_PONG) { + buf_len = 0; + } else if (pdu->code == COAP_SIGNALING_RELEASE) switch(opt_iter.type) { + case COAP_SIGNALING_OPTION_ALTERNATIVE_ADDRESS: + buf_len = print_readable(coap_opt_value(option), + coap_opt_length(option), + buf, sizeof(buf), 0); + break; + case COAP_SIGNALING_OPTION_HOLD_OFF: + buf_len = snprintf((char *)buf, sizeof(buf), "%u", + coap_decode_var_bytes(coap_opt_value(option), + coap_opt_length(option))); + break; + default: + buf_len = 0; + break; + } else if (pdu->code == COAP_SIGNALING_ABORT) switch(opt_iter.type) { + case COAP_SIGNALING_OPTION_BAD_CSM_OPTION: + buf_len = snprintf((char *)buf, sizeof(buf), "%u", + coap_decode_var_bytes(coap_opt_value(option), + coap_opt_length(option))); + break; + default: + buf_len = 0; + break; + } else switch (opt_iter.type) { + case COAP_OPTION_CONTENT_FORMAT: + content_format = (int)coap_decode_var_bytes(coap_opt_value(option), + coap_opt_length(option)); + + buf_len = print_content_format(content_format, buf, sizeof(buf)); + break; + + case COAP_OPTION_BLOCK1: + case COAP_OPTION_BLOCK2: + /* split block option into number/more/size where more is the + * letter M if set, the _ otherwise */ + buf_len = snprintf((char *)buf, sizeof(buf), "%u/%c/%u", + coap_opt_block_num(option), /* block number */ + COAP_OPT_BLOCK_MORE(option) ? 'M' : '_', /* M bit */ + (1 << (COAP_OPT_BLOCK_SZX(option) + 4))); /* block size */ + + break; + + case COAP_OPTION_URI_PORT: + case COAP_OPTION_MAXAGE: + case COAP_OPTION_OBSERVE: + case COAP_OPTION_SIZE1: + case COAP_OPTION_SIZE2: + /* show values as unsigned decimal value */ + buf_len = snprintf((char *)buf, sizeof(buf), "%u", + coap_decode_var_bytes(coap_opt_value(option), + coap_opt_length(option))); + break; + + default: + /* generic output function for all other option types */ + if (opt_iter.type == COAP_OPTION_URI_PATH || + opt_iter.type == COAP_OPTION_PROXY_URI || + opt_iter.type == COAP_OPTION_URI_HOST || + opt_iter.type == COAP_OPTION_LOCATION_PATH || + opt_iter.type == COAP_OPTION_LOCATION_QUERY || + opt_iter.type == COAP_OPTION_URI_QUERY) { + encode = 0; + } else { + encode = 1; + } + + buf_len = print_readable(coap_opt_value(option), + coap_opt_length(option), + buf, sizeof(buf), encode); + } + + outbuflen = strlen(outbuf); + snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, + " %s:%.*s", msg_option_string(pdu->code, opt_iter.type), + (int)buf_len, buf); + } + + outbuflen = strlen(outbuf); + snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, " ]"); + + if (coap_get_data(pdu, &data_len, &data)) { + + outbuflen = strlen(outbuf); + snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, " :: "); + + if (is_binary(content_format)) { + int keep_data_len = data_len; + uint8_t *keep_data = data; + + outbuflen = strlen(outbuf); + snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, + "binary data length %zu\n", data_len); + COAP_DO_SHOW_OUTPUT_LINE; + /* + * Output hex dump of binary data as a continuous entry + */ + outbuf[0] = '\000'; + snprintf(outbuf, sizeof(outbuf), "<<"); + while (data_len--) { + outbuflen = strlen(outbuf); + snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, + "%02x", *data++); + } + outbuflen = strlen(outbuf); + snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, ">>"); + data_len = keep_data_len; + data = keep_data; + outbuflen = strlen(outbuf); + snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, "\n"); + COAP_DO_SHOW_OUTPUT_LINE; + /* + * Output ascii readable (if possible), immediately under the + * hex value of the character output above to help binary debugging + */ + outbuf[0] = '\000'; + snprintf(outbuf, sizeof(outbuf), "<<"); + while (data_len--) { + outbuflen = strlen(outbuf); + snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, + "%c ", isprint (*data) ? *data : '.'); + data++; + } + outbuflen = strlen(outbuf); + snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, ">>"); + } else { + if (print_readable(data, data_len, buf, sizeof(buf), 0)) { + outbuflen = strlen(outbuf); + snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, "'%s'", buf); + } + } + } + + outbuflen = strlen(outbuf); + snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, "\n"); + COAP_DO_SHOW_OUTPUT_LINE; + +#if COAP_CONSTRAINED_STACK + coap_mutex_unlock(&static_show_pdu_mutex); +#endif /* COAP_CONSTRAINED_STACK */ +} + +void coap_show_tls_version(coap_log_t level) +{ + char buffer[64]; + coap_string_tls_version(buffer, sizeof(buffer)); + coap_log(level, "%s\n", buffer); +} + +char *coap_string_tls_version(char *buffer, size_t bufsize) +{ + coap_tls_version_t *tls_version = coap_get_tls_library_version(); + char beta[8]; + char sub[2]; + char b_beta[8]; + char b_sub[2]; + + switch (tls_version->type) { + case COAP_TLS_LIBRARY_NOTLS: + snprintf(buffer, bufsize, "TLS Library: None"); + break; + case COAP_TLS_LIBRARY_TINYDTLS: + snprintf(buffer, bufsize, "TLS Library: TinyDTLS - runtime %lu.%lu.%lu, " + "libcoap built for %lu.%lu.%lu", + (unsigned long)(tls_version->version >> 16), + (unsigned long)((tls_version->version >> 8) & 0xff), + (unsigned long)(tls_version->version & 0xff), + (unsigned long)(tls_version->built_version >> 16), + (unsigned long)((tls_version->built_version >> 8) & 0xff), + (unsigned long)(tls_version->built_version & 0xff)); + break; + case COAP_TLS_LIBRARY_OPENSSL: + switch (tls_version->version &0xf) { + case 0: + strcpy(beta, "-dev"); + break; + case 0xf: + strcpy(beta, ""); + break; + default: + strcpy(beta, "-beta"); + beta[5] = (tls_version->version &0xf) + '0'; + beta[6] = '\000'; + break; + } + sub[0] = ((tls_version->version >> 4) & 0xff) ? + ((tls_version->version >> 4) & 0xff) + 'a' -1 : '\000'; + sub[1] = '\000'; + switch (tls_version->built_version &0xf) { + case 0: + strcpy(b_beta, "-dev"); + break; + case 0xf: + strcpy(b_beta, ""); + break; + default: + strcpy(b_beta, "-beta"); + b_beta[5] = (tls_version->built_version &0xf) + '0'; + b_beta[6] = '\000'; + break; + } + b_sub[0] = ((tls_version->built_version >> 4) & 0xff) ? + ((tls_version->built_version >> 4) & 0xff) + 'a' -1 : '\000'; + b_sub[1] = '\000'; + snprintf(buffer, bufsize, "TLS Library: OpenSSL - runtime " + "%lu.%lu.%lu%s%s, libcoap built for %lu.%lu.%lu%s%s", + (unsigned long)(tls_version->version >> 28), + (unsigned long)((tls_version->version >> 20) & 0xff), + (unsigned long)((tls_version->version >> 12) & 0xff), sub, beta, + (unsigned long)(tls_version->built_version >> 28), + (unsigned long)((tls_version->built_version >> 20) & 0xff), + (unsigned long)((tls_version->built_version >> 12) & 0xff), + b_sub, b_beta); + break; + case COAP_TLS_LIBRARY_GNUTLS: + snprintf(buffer, bufsize, "TLS Library: GnuTLS - runtime %lu.%lu.%lu, " + "libcoap built for %lu.%lu.%lu", + (unsigned long)(tls_version->version >> 16), + (unsigned long)((tls_version->version >> 8) & 0xff), + (unsigned long)(tls_version->version & 0xff), + (unsigned long)(tls_version->built_version >> 16), + (unsigned long)((tls_version->built_version >> 8) & 0xff), + (unsigned long)(tls_version->built_version & 0xff)); + break; + case COAP_TLS_LIBRARY_MBEDTLS: + snprintf(buffer, bufsize, "TLS Library: MbedTLS - runtime %lu.%lu.%lu, " + "libcoap built for %lu.%lu.%lu", + (unsigned long)(tls_version->version >> 24), + (unsigned long)((tls_version->version >> 16) & 0xff), + (unsigned long)((tls_version->version >> 8) & 0xff), + (unsigned long)(tls_version->built_version >> 24), + (unsigned long)((tls_version->built_version >> 16) & 0xff), + (unsigned long)((tls_version->built_version >> 8) & 0xff)); + break; + default: + snprintf(buffer, bufsize, "Library type %d unknown", tls_version->type); + break; + } + return buffer; +} + +static coap_log_handler_t log_handler = NULL; + +void coap_set_log_handler(coap_log_handler_t handler) { + log_handler = handler; +} + +void +coap_log_impl(coap_log_t level, const char *format, ...) { + + if (maxlog < level) + return; + + if (log_handler) { +#if COAP_CONSTRAINED_STACK + static coap_mutex_t static_log_mutex = COAP_MUTEX_INITIALIZER; + static char message[COAP_DEBUG_BUF_SIZE]; +#else /* ! COAP_CONSTRAINED_STACK */ + char message[COAP_DEBUG_BUF_SIZE]; +#endif /* ! COAP_CONSTRAINED_STACK */ + va_list ap; + va_start(ap, format); +#if COAP_CONSTRAINED_STACK + coap_mutex_lock(&static_log_mutex); +#endif /* COAP_CONSTRAINED_STACK */ + + vsnprintf( message, sizeof(message), format, ap); + va_end(ap); + log_handler(level, message); +#if COAP_CONSTRAINED_STACK + coap_mutex_unlock(&static_log_mutex); +#endif /* COAP_CONSTRAINED_STACK */ + } else { + char timebuf[32]; + coap_tick_t now; + va_list ap; + FILE *log_fd; + + log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD; + + coap_ticks(&now); + if (print_timestamp(timebuf,sizeof(timebuf), now)) + fprintf(log_fd, "%s ", timebuf); + + if (level <= LOG_DEBUG) + fprintf(log_fd, "%s ", loglevels[level]); + + va_start(ap, format); + vfprintf(log_fd, format, ap); + va_end(ap); + fflush(log_fd); + } +} + +static struct packet_num_interval { + int start; + int end; +} packet_loss_intervals[10]; +static int num_packet_loss_intervals = 0; +static int packet_loss_level = 0; +static int send_packet_count = 0; + +int coap_debug_set_packet_loss(const char *loss_level) { + const char *p = loss_level; + char *end = NULL; + int n = (int)strtol(p, &end, 10), i = 0; + if (end == p || n < 0) + return 0; + if (*end == '%') { + if (n > 100) + n = 100; + packet_loss_level = n * 65536 / 100; + coap_log(LOG_DEBUG, "packet loss level set to %d%%\n", n); + } else { + if (n <= 0) + return 0; + while (i < 10) { + packet_loss_intervals[i].start = n; + if (*end == '-') { + p = end + 1; + n = (int)strtol(p, &end, 10); + if (end == p || n <= 0) + return 0; + } + packet_loss_intervals[i++].end = n; + if (*end == 0) + break; + if (*end != ',') + return 0; + p = end + 1; + n = (int)strtol(p, &end, 10); + if (end == p || n <= 0) + return 0; + } + if (i == 10) + return 0; + num_packet_loss_intervals = i; + } + send_packet_count = 0; + return 1; +} + +int coap_debug_send_packet(void) { + ++send_packet_count; + if (num_packet_loss_intervals > 0) { + int i; + for (i = 0; i < num_packet_loss_intervals; i++) { + if (send_packet_count >= packet_loss_intervals[i].start + && send_packet_count <= packet_loss_intervals[i].end) + return 0; + } + } + if ( packet_loss_level > 0 ) { + uint16_t r = 0; + prng( (uint8_t*)&r, 2 ); + if ( r < packet_loss_level ) + return 0; + } + return 1; +} diff --git a/components/coap/port/coap_io.c b/components/coap/port/coap_io.c deleted file mode 100644 index 00c0ad1d38..0000000000 --- a/components/coap/port/coap_io.c +++ /dev/null @@ -1,1417 +0,0 @@ -/* coap_io.c -- Default network I/O functions for libcoap - * - * Copyright (C) 2012,2014,2016-2019 Olaf Bergmann and others - * - * This file is part of the CoAP library libcoap. Please see - * README for terms of use. - */ - -#include "coap_config.h" - -#ifdef HAVE_STDIO_H -# include -#endif - -#ifdef HAVE_SYS_SELECT_H -# include -#endif -#ifdef HAVE_SYS_SOCKET_H -# include -# define OPTVAL_T(t) (t) -# define OPTVAL_GT(t) (t) -#endif -#ifdef HAVE_SYS_IOCTL_H - #include -#endif -#ifdef HAVE_NETINET_IN_H -# include -#endif -#ifdef HAVE_WS2TCPIP_H -#include -# define OPTVAL_T(t) (const char*)(t) -# define OPTVAL_GT(t) (char*)(t) -# undef CMSG_DATA -# define CMSG_DATA WSA_CMSG_DATA -#endif -#ifdef HAVE_SYS_UIO_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif -#include - -#ifdef WITH_CONTIKI -# include "uip.h" -#endif - -#include "libcoap.h" -#include "coap_debug.h" -#include "mem.h" -#include "net.h" -#include "coap_io.h" -#include "pdu.h" -#include "utlist.h" -#include "resource.h" - -#if !defined(WITH_CONTIKI) - /* define generic PKTINFO for IPv4 */ -#if defined(IP_PKTINFO) -# define GEN_IP_PKTINFO IP_PKTINFO -#elif defined(IP_RECVDSTADDR) -# define GEN_IP_PKTINFO IP_RECVDSTADDR -#else -# error "Need IP_PKTINFO or IP_RECVDSTADDR to request ancillary data from OS." -#endif /* IP_PKTINFO */ - -/* define generic KTINFO for IPv6 */ -#ifdef IPV6_RECVPKTINFO -# define GEN_IPV6_PKTINFO IPV6_RECVPKTINFO -#elif defined(IPV6_PKTINFO) -# define GEN_IPV6_PKTINFO IPV6_PKTINFO -#else -# error "Need IPV6_PKTINFO or IPV6_RECVPKTINFO to request ancillary data from OS." -#endif /* IPV6_RECVPKTINFO */ -#endif - -void coap_free_endpoint(coap_endpoint_t *ep); - -#ifdef WITH_CONTIKI -static int ep_initialized = 0; - -struct coap_endpoint_t * - coap_malloc_endpoint(void) { - static struct coap_endpoint_t ep; - - if (ep_initialized) { - return NULL; - } else { - ep_initialized = 1; - return &ep; - } -} - -void -coap_mfree_endpoint(struct coap_endpoint_t *ep) { - ep_initialized = 0; - coap_session_mfree(&ep->hello); -} - -int -coap_socket_bind_udp(coap_socket_t *sock, - const coap_address_t *listen_addr, - coap_address_t *bound_addr) { - sock->conn = udp_new(NULL, 0, NULL); - - if (!sock->conn) { - coap_log(LOG_WARNING, "coap_socket_bind_udp"); - return 0; - } - - coap_address_init(bound_addr); - uip_ipaddr_copy(&bound_addr->addr, &listen_addr->addr); - bound_addr->port = listen_addr->port; - udp_bind((struct uip_udp_conn *)sock->conn, bound_addr->port); - return 1; -} - -int -coap_socket_connect_udp(coap_socket_t *sock, - const coap_address_t *local_if, - const coap_address_t *server, - int default_port, - coap_address_t *local_addr, - coap_address_t *remote_addr) { - return 0; -} - -int -coap_socket_connect_tcp1(coap_socket_t *sock, - const coap_address_t *local_if, - const coap_address_t *server, - int default_port, - coap_address_t *local_addr, - coap_address_t *remote_addr) { - return 0; -} - -int -coap_socket_connect_tcp2(coap_socket_t *sock, - coap_address_t *local_addr, - coap_address_t *remote_addr) { - return 0; -} - -int -coap_socket_bind_tcp(coap_socket_t *sock, - const coap_address_t *listen_addr, - coap_address_t *bound_addr) { - return 0; -} - -int -coap_socket_accept_tcp(coap_socket_t *server, - coap_socket_t *new_client, - coap_address_t *local_addr, - coap_address_t *remote_addr) { - return 0; -} - -ssize_t -coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len) { - return -1; -} - -ssize_t -coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len) { - return -1; -} - -void coap_socket_close(coap_socket_t *sock) { - if (sock->conn) - uip_udp_remove((struct uip_udp_conn *)sock->conn); - sock->flags = COAP_SOCKET_EMPTY; -} - -#else - -static const char *coap_socket_format_errno( int error ); - -struct coap_endpoint_t * - coap_malloc_endpoint(void) { - return (struct coap_endpoint_t *)coap_malloc_type(COAP_ENDPOINT, sizeof(struct coap_endpoint_t)); -} - -void -coap_mfree_endpoint(struct coap_endpoint_t *ep) { - coap_session_mfree(&ep->hello); - coap_free_type(COAP_ENDPOINT, ep); -} - -int -coap_socket_bind_udp(coap_socket_t *sock, - const coap_address_t *listen_addr, - coap_address_t *bound_addr) { - int on = 1, off = 0; -#ifdef _WIN32 - u_long u_on = 1; -#endif - - sock->fd = socket(listen_addr->addr.sa.sa_family, SOCK_DGRAM, 0); - - if (sock->fd == COAP_INVALID_SOCKET) { - coap_log(LOG_WARNING, - "coap_socket_bind_udp: socket: %s\n", coap_socket_strerror()); - goto error; - } - -#ifdef _WIN32 - if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) { -#else - if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) { -#endif - coap_log(LOG_WARNING, - "coap_socket_bind_udp: ioctl FIONBIO: %s\n", coap_socket_strerror()); - } - - if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR) - coap_log(LOG_WARNING, - "coap_socket_bind_udp: setsockopt SO_REUSEADDR: %s\n", - coap_socket_strerror()); - - switch (listen_addr->addr.sa.sa_family) { - case AF_INET: - if (setsockopt(sock->fd, IPPROTO_IP, GEN_IP_PKTINFO, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR) - coap_log(LOG_ALERT, - "coap_socket_bind_udp: setsockopt IP_PKTINFO: %s\n", - coap_socket_strerror()); - break; - case AF_INET6: - /* Configure the socket as dual-stacked */ - if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off), sizeof(off)) == COAP_SOCKET_ERROR) - coap_log(LOG_ALERT, - "coap_socket_bind_udp: setsockopt IPV6_V6ONLY: %s\n", - coap_socket_strerror()); - if (setsockopt(sock->fd, IPPROTO_IPV6, GEN_IPV6_PKTINFO, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR) - coap_log(LOG_ALERT, - "coap_socket_bind_udp: setsockopt IPV6_PKTINFO: %s\n", - coap_socket_strerror()); - setsockopt(sock->fd, IPPROTO_IP, GEN_IP_PKTINFO, OPTVAL_T(&on), sizeof(on)); /* ignore error, because the likely cause is that IPv4 is disabled at the os level */ - break; - default: - coap_log(LOG_ALERT, "coap_socket_bind_udp: unsupported sa_family\n"); - break; - } - - if (bind(sock->fd, &listen_addr->addr.sa, listen_addr->size) == COAP_SOCKET_ERROR) { - coap_log(LOG_WARNING, "coap_socket_bind_udp: bind: %s\n", - coap_socket_strerror()); - goto error; - } - - bound_addr->size = (socklen_t)sizeof(*bound_addr); - if (getsockname(sock->fd, &bound_addr->addr.sa, &bound_addr->size) < 0) { - coap_log(LOG_WARNING, - "coap_socket_bind_udp: getsockname: %s\n", - coap_socket_strerror()); - goto error; - } - - return 1; - -error: - coap_socket_close(sock); - return 0; -} - -int -coap_socket_connect_tcp1(coap_socket_t *sock, - const coap_address_t *local_if, - const coap_address_t *server, - int default_port, - coap_address_t *local_addr, - coap_address_t *remote_addr) { - int on = 1, off = 0; -#ifdef _WIN32 - u_long u_on = 1; -#endif - coap_address_t connect_addr; - coap_address_copy( &connect_addr, server ); - - sock->flags &= ~COAP_SOCKET_CONNECTED; - sock->fd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0); - - if (sock->fd == COAP_INVALID_SOCKET) { - coap_log(LOG_WARNING, - "coap_socket_connect_tcp1: socket: %s\n", - coap_socket_strerror()); - goto error; - } - -#ifdef _WIN32 - if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) { -#else - if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) { -#endif - coap_log(LOG_WARNING, - "coap_socket_connect_tcp1: ioctl FIONBIO: %s\n", - coap_socket_strerror()); - } - - switch (server->addr.sa.sa_family) { - case AF_INET: - if (connect_addr.addr.sin.sin_port == 0) - connect_addr.addr.sin.sin_port = htons(default_port); - break; - case AF_INET6: - if (connect_addr.addr.sin6.sin6_port == 0) - connect_addr.addr.sin6.sin6_port = htons(default_port); - /* Configure the socket as dual-stacked */ - if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off), sizeof(off)) == COAP_SOCKET_ERROR) - coap_log(LOG_WARNING, - "coap_socket_connect_tcp1: setsockopt IPV6_V6ONLY: %s\n", - coap_socket_strerror()); - break; - default: - coap_log(LOG_ALERT, "coap_socket_connect_tcp1: unsupported sa_family\n"); - break; - } - - if (local_if && local_if->addr.sa.sa_family) { - coap_address_copy(local_addr, local_if); - if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR) - coap_log(LOG_WARNING, - "coap_socket_connect_tcp1: setsockopt SO_REUSEADDR: %s\n", - coap_socket_strerror()); - if (bind(sock->fd, &local_if->addr.sa, local_if->size) == COAP_SOCKET_ERROR) { - coap_log(LOG_WARNING, "coap_socket_connect_tcp1: bind: %s\n", - coap_socket_strerror()); - goto error; - } - } else { - local_addr->addr.sa.sa_family = server->addr.sa.sa_family; - } - - if (connect(sock->fd, &connect_addr.addr.sa, connect_addr.size) == COAP_SOCKET_ERROR) { -#ifdef _WIN32 - if (WSAGetLastError() == WSAEWOULDBLOCK) { -#else - if (errno == EINPROGRESS) { -#endif - /* - * COAP_SOCKET_CONNECTED needs to be set here as there will be reads/writes - * by underlying TLS libraries during connect() and we do not want to - * assert() in coap_read_session() or coap_write_session() when called by coap_read() - */ - sock->flags |= COAP_SOCKET_WANT_CONNECT | COAP_SOCKET_CONNECTED; - return 1; - } - coap_log(LOG_WARNING, "coap_socket_connect_tcp1: connect: %s\n", - coap_socket_strerror()); - goto error; - } - - if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) { - coap_log(LOG_WARNING, "coap_socket_connect_tcp1: getsockname: %s\n", - coap_socket_strerror()); - } - - if (getpeername(sock->fd, &remote_addr->addr.sa, &remote_addr->size) == COAP_SOCKET_ERROR) { - coap_log(LOG_WARNING, "coap_socket_connect_tcp1: getpeername: %s\n", - coap_socket_strerror()); - } - - sock->flags |= COAP_SOCKET_CONNECTED; - return 1; - -error: - coap_socket_close(sock); - return 0; -} - -int -coap_socket_connect_tcp2(coap_socket_t *sock, - coap_address_t *local_addr, - coap_address_t *remote_addr) { - int error = 0; -#ifdef _WIN32 - int optlen = (int)sizeof( error ); -#else - socklen_t optlen = (socklen_t)sizeof( error ); -#endif - - sock->flags &= ~(COAP_SOCKET_WANT_CONNECT | COAP_SOCKET_CAN_CONNECT); - - if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, OPTVAL_GT(&error), - &optlen) == COAP_SOCKET_ERROR) { - coap_log(LOG_WARNING, "coap_socket_finish_connect_tcp: getsockopt: %s\n", - coap_socket_strerror()); - } - - if (error) { - coap_log(LOG_WARNING, - "coap_socket_finish_connect_tcp: connect failed: %s\n", - coap_socket_format_errno(error)); - coap_socket_close(sock); - return 0; - } - - if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) { - coap_log(LOG_WARNING, "coap_socket_connect_tcp: getsockname: %s\n", - coap_socket_strerror()); - } - - if (getpeername(sock->fd, &remote_addr->addr.sa, &remote_addr->size) == COAP_SOCKET_ERROR) { - coap_log(LOG_WARNING, "coap_socket_connect_tcp: getpeername: %s\n", - coap_socket_strerror()); - } - - return 1; -} - -int -coap_socket_bind_tcp(coap_socket_t *sock, - const coap_address_t *listen_addr, - coap_address_t *bound_addr) { - int on = 1, off = 0; -#ifdef _WIN32 - u_long u_on = 1; -#endif - - sock->fd = socket(listen_addr->addr.sa.sa_family, SOCK_STREAM, 0); - - if (sock->fd == COAP_INVALID_SOCKET) { - coap_log(LOG_WARNING, "coap_socket_bind_tcp: socket: %s\n", - coap_socket_strerror()); - goto error; - } - -#ifdef _WIN32 - if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) { -#else - if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) { -#endif - coap_log(LOG_WARNING, "coap_socket_bind_tcp: ioctl FIONBIO: %s\n", - coap_socket_strerror()); - } - if (setsockopt (sock->fd, SOL_SOCKET, SO_KEEPALIVE, OPTVAL_T(&on), - sizeof (on)) == COAP_SOCKET_ERROR) - coap_log(LOG_WARNING, - "coap_socket_bind_tcp: setsockopt SO_KEEPALIVE: %s\n", - coap_socket_strerror()); - - if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), - sizeof(on)) == COAP_SOCKET_ERROR) - coap_log(LOG_WARNING, - "coap_socket_bind_tcp: setsockopt SO_REUSEADDR: %s\n", - coap_socket_strerror()); - - switch (listen_addr->addr.sa.sa_family) { - case AF_INET: - break; - case AF_INET6: - /* Configure the socket as dual-stacked */ - if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off), sizeof(off)) == COAP_SOCKET_ERROR) - coap_log(LOG_ALERT, - "coap_socket_bind_tcp: setsockopt IPV6_V6ONLY: %s\n", - coap_socket_strerror()); - break; - default: - coap_log(LOG_ALERT, "coap_socket_bind_tcp: unsupported sa_family\n"); - } - - if (bind(sock->fd, &listen_addr->addr.sa, listen_addr->size) == COAP_SOCKET_ERROR) { - coap_log(LOG_ALERT, "coap_socket_bind_tcp: bind: %s\n", - coap_socket_strerror()); - goto error; - } - - bound_addr->size = (socklen_t)sizeof(*bound_addr); - if (getsockname(sock->fd, &bound_addr->addr.sa, &bound_addr->size) < 0) { - coap_log(LOG_WARNING, "coap_socket_bind_tcp: getsockname: %s\n", - coap_socket_strerror()); - goto error; - } - - if (listen(sock->fd, 5) == COAP_SOCKET_ERROR) { - coap_log(LOG_ALERT, "coap_socket_bind_tcp: listen: %s\n", - coap_socket_strerror()); - goto error; - } - - return 1; - -error: - coap_socket_close(sock); - return 0; -} - -int -coap_socket_accept_tcp(coap_socket_t *server, - coap_socket_t *new_client, - coap_address_t *local_addr, - coap_address_t *remote_addr) { -#ifdef _WIN32 - u_long u_on = 1; -#else - int on = 1; -#endif - - server->flags &= ~COAP_SOCKET_CAN_ACCEPT; - - new_client->fd = accept(server->fd, &remote_addr->addr.sa, - &remote_addr->size); - if (new_client->fd == COAP_INVALID_SOCKET) { - coap_log(LOG_WARNING, "coap_socket_accept_tcp: accept: %s\n", - coap_socket_strerror()); - return 0; - } - - if (getsockname( new_client->fd, &local_addr->addr.sa, &local_addr->size) < 0) - coap_log(LOG_WARNING, "coap_socket_accept_tcp: getsockname: %s\n", - coap_socket_strerror()); - - #ifdef _WIN32 - if (ioctlsocket(new_client->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) { -#else - if (ioctl(new_client->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) { -#endif - coap_log(LOG_WARNING, "coap_socket_accept_tcp: ioctl FIONBIO: %s\n", - coap_socket_strerror()); - } - - return 1; -} - -int -coap_socket_connect_udp(coap_socket_t *sock, - const coap_address_t *local_if, - const coap_address_t *server, - int default_port, - coap_address_t *local_addr, - coap_address_t *remote_addr) { - int on = 1, off = 0; -#ifdef _WIN32 - u_long u_on = 1; -#endif - coap_address_t connect_addr; - int is_mcast = coap_is_mcast(server); - coap_address_copy(&connect_addr, server); - - sock->flags &= ~(COAP_SOCKET_CONNECTED | COAP_SOCKET_MULTICAST); - sock->fd = socket(connect_addr.addr.sa.sa_family, SOCK_DGRAM, 0); - - if (sock->fd == COAP_INVALID_SOCKET) { - coap_log(LOG_WARNING, "coap_socket_connect_udp: socket: %s\n", - coap_socket_strerror()); - goto error; - } - -#ifdef _WIN32 - if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) { -#else - if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) { -#endif - coap_log(LOG_WARNING, "coap_socket_connect_udp: ioctl FIONBIO: %s\n", - coap_socket_strerror()); - } - - switch (connect_addr.addr.sa.sa_family) { - case AF_INET: - if (connect_addr.addr.sin.sin_port == 0) - connect_addr.addr.sin.sin_port = htons(default_port); - break; - case AF_INET6: - if (connect_addr.addr.sin6.sin6_port == 0) - connect_addr.addr.sin6.sin6_port = htons(default_port); - /* Configure the socket as dual-stacked */ - if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off), sizeof(off)) == COAP_SOCKET_ERROR) - coap_log(LOG_WARNING, - "coap_socket_connect_udp: setsockopt IPV6_V6ONLY: %s\n", - coap_socket_strerror()); - break; - default: - coap_log(LOG_ALERT, "coap_socket_connect_udp: unsupported sa_family\n"); - break; - } - - if (local_if && local_if->addr.sa.sa_family) { - if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR) - coap_log(LOG_WARNING, - "coap_socket_connect_udp: setsockopt SO_REUSEADDR: %s\n", - coap_socket_strerror()); - if (bind(sock->fd, &local_if->addr.sa, local_if->size) == COAP_SOCKET_ERROR) { - coap_log(LOG_WARNING, "coap_socket_connect_udp: bind: %s\n", - coap_socket_strerror()); - goto error; - } - } - - /* special treatment for sockets that are used for multicast communication */ - if (is_mcast) { - if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) { - coap_log(LOG_WARNING, - "coap_socket_connect_udp: getsockname for multicast socket: %s\n", - coap_socket_strerror()); - } - coap_address_copy(remote_addr, &connect_addr); - sock->flags |= COAP_SOCKET_MULTICAST; - return 1; - } - - if (connect(sock->fd, &connect_addr.addr.sa, connect_addr.size) == COAP_SOCKET_ERROR) { - coap_log(LOG_WARNING, "coap_socket_connect_udp: connect: %s\n", - coap_socket_strerror()); - goto error; - } - - if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) { - coap_log(LOG_WARNING, "coap_socket_connect_udp: getsockname: %s\n", - coap_socket_strerror()); - } - - if (getpeername(sock->fd, &remote_addr->addr.sa, &remote_addr->size) == COAP_SOCKET_ERROR) { - coap_log(LOG_WARNING, "coap_socket_connect_udp: getpeername: %s\n", - coap_socket_strerror()); - } - - sock->flags |= COAP_SOCKET_CONNECTED; - return 1; - -error: - coap_socket_close(sock); - return 0; -} - -void coap_socket_close(coap_socket_t *sock) { - if (sock->fd != COAP_INVALID_SOCKET) { - coap_closesocket(sock->fd); - sock->fd = COAP_INVALID_SOCKET; - } - sock->flags = COAP_SOCKET_EMPTY; -} - -ssize_t -coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len) { - ssize_t r; - - sock->flags &= ~(COAP_SOCKET_WANT_WRITE | COAP_SOCKET_CAN_WRITE); -#ifdef _WIN32 - r = send(sock->fd, (const char *)data, (int)data_len, 0); -#else - r = send(sock->fd, data, data_len, 0); -#endif - if (r == COAP_SOCKET_ERROR) { -#ifdef _WIN32 - if (WSAGetLastError() == WSAEWOULDBLOCK) { -#elif EAGAIN != EWOULDBLOCK - if (errno==EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { -#else - if (errno==EAGAIN || errno == EINTR) { -#endif - sock->flags |= COAP_SOCKET_WANT_WRITE; - return 0; - } - coap_log(LOG_WARNING, "coap_socket_write: send: %s\n", - coap_socket_strerror()); - return -1; - } - if (r < (ssize_t)data_len) - sock->flags |= COAP_SOCKET_WANT_WRITE; - return r; -} - -ssize_t -coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len) { - ssize_t r; -#ifdef _WIN32 - int error; -#endif - -#ifdef _WIN32 - r = recv(sock->fd, (char *)data, (int)data_len, 0); -#else - r = recv(sock->fd, data, data_len, 0); -#endif - if (r == 0) { - /* graceful shutdown */ - sock->flags &= ~COAP_SOCKET_CAN_READ; - return -1; - } else if (r == COAP_SOCKET_ERROR) { - sock->flags &= ~COAP_SOCKET_CAN_READ; -#ifdef _WIN32 - error = WSAGetLastError(); - if (error == WSAEWOULDBLOCK) { -#elif EAGAIN != EWOULDBLOCK - if (errno==EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { -#else - if (errno==EAGAIN || errno == EINTR) { -#endif - return 0; - } -#ifdef _WIN32 - if (error != WSAECONNRESET) -#else - if (errno != ECONNRESET) -#endif - coap_log(LOG_WARNING, "coap_socket_read: recv: %s\n", - coap_socket_strerror()); - return -1; - } - if (r < (ssize_t)data_len) - sock->flags &= ~COAP_SOCKET_CAN_READ; - return r; -} - -#endif /* WITH_CONTIKI */ - -#if (!defined(WITH_CONTIKI)) != ( defined(HAVE_NETINET_IN_H) || defined(HAVE_WS2TCPIP_H) ) -/* define struct in6_pktinfo and struct in_pktinfo if not available - FIXME: check with configure -*/ -struct in6_pktinfo { - struct in6_addr ipi6_addr; /* src/dst IPv6 address */ - unsigned int ipi6_ifindex; /* send/recv interface index */ -}; - -#endif - -#if !defined(WITH_CONTIKI) && !defined(SOL_IP) -/* Solaris expects level IPPROTO_IP for ancillary data. */ -#define SOL_IP IPPROTO_IP -#endif - -#ifdef __GNUC__ -#define UNUSED_PARAM __attribute__ ((unused)) -#else /* not a GCC */ -#define UNUSED_PARAM -#endif /* GCC */ - -#if defined(_WIN32) -#include -static __declspec(thread) LPFN_WSARECVMSG lpWSARecvMsg = NULL; -/* Map struct WSABUF fields to their posix counterpart */ -#define msghdr _WSAMSG -#define msg_name name -#define msg_namelen namelen -#define msg_iov lpBuffers -#define msg_iovlen dwBufferCount -#define msg_control Control.buf -#define msg_controllen Control.len -#define iovec _WSABUF -#define iov_base buf -#define iov_len len -#define iov_len_t u_long -#undef CMSG_DATA -#define CMSG_DATA WSA_CMSG_DATA -#define ipi_spec_dst ipi_addr -#else -#define iov_len_t size_t -#endif - -ssize_t -coap_network_send(coap_socket_t *sock, const coap_session_t *session, const uint8_t *data, size_t datalen) { - ssize_t bytes_written = 0; - - if (!coap_debug_send_packet()) { - bytes_written = (ssize_t)datalen; -#ifndef WITH_CONTIKI - } else if (sock->flags & COAP_SOCKET_CONNECTED) { -#ifdef _WIN32 - bytes_written = send(sock->fd, (const char *)data, (int)datalen, 0); -#else - bytes_written = send(sock->fd, data, datalen, 0); -#endif -#endif - } else { -#ifndef WITH_CONTIKI -#ifdef _WIN32 - DWORD dwNumberOfBytesSent = 0; - int r; -#endif -#ifndef COAP_BAD_RECVMSG - /* a buffer large enough to hold all packet info types, ipv6 is the largest */ - char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; - struct msghdr mhdr; - struct iovec iov[1]; - const void *addr = &session->remote_addr.addr; - - assert(session); - - memcpy (&iov[0].iov_base, &data, sizeof (iov[0].iov_base)); - iov[0].iov_len = (iov_len_t)datalen; - - memset(buf, 0, sizeof (buf)); - - memset(&mhdr, 0, sizeof(struct msghdr)); - memcpy (&mhdr.msg_name, &addr, sizeof (mhdr.msg_name)); - mhdr.msg_namelen = session->remote_addr.size; - - mhdr.msg_iov = iov; - mhdr.msg_iovlen = 1; - - if (!coap_address_isany(&session->local_addr) && !coap_is_mcast(&session->local_addr)) switch (session->local_addr.addr.sa.sa_family) { - case AF_INET6: - { - struct cmsghdr *cmsg; - - if (IN6_IS_ADDR_V4MAPPED(&session->local_addr.addr.sin6.sin6_addr)) { -#if defined(IP_PKTINFO) - struct in_pktinfo *pktinfo; - mhdr.msg_control = buf; - mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo)); - - cmsg = CMSG_FIRSTHDR(&mhdr); - cmsg->cmsg_level = SOL_IP; - cmsg->cmsg_type = IP_PKTINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); - - pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg); - - pktinfo->ipi_ifindex = session->ifindex; - memcpy(&pktinfo->ipi_spec_dst, session->local_addr.addr.sin6.sin6_addr.s6_addr + 12, sizeof(pktinfo->ipi_spec_dst)); -#elif defined(IP_SENDSRCADDR) - mhdr.msg_control = buf; - mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_addr)); - - cmsg = CMSG_FIRSTHDR(&mhdr); - cmsg->cmsg_level = IPPROTO_IP; - cmsg->cmsg_type = IP_SENDSRCADDR; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); - - memcpy(CMSG_DATA(cmsg), session->local_addr.addr.sin6.sin6_addr.s6_addr + 12, sizeof(struct in_addr)); -#endif /* IP_PKTINFO */ - } else { - struct in6_pktinfo *pktinfo; - mhdr.msg_control = buf; - mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); - - cmsg = CMSG_FIRSTHDR(&mhdr); - cmsg->cmsg_level = IPPROTO_IPV6; - cmsg->cmsg_type = IPV6_PKTINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); - - pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg); - - pktinfo->ipi6_ifindex = session->ifindex; - memcpy(&pktinfo->ipi6_addr, &session->local_addr.addr.sin6.sin6_addr, sizeof(pktinfo->ipi6_addr)); - } - break; - } - case AF_INET: - { -#if defined(IP_PKTINFO) - struct cmsghdr *cmsg; - struct in_pktinfo *pktinfo; - - mhdr.msg_control = buf; - mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo)); - - cmsg = CMSG_FIRSTHDR(&mhdr); - cmsg->cmsg_level = SOL_IP; - cmsg->cmsg_type = IP_PKTINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); - - pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg); - - pktinfo->ipi_ifindex = session->ifindex; - memcpy(&pktinfo->ipi_spec_dst, &session->local_addr.addr.sin.sin_addr, sizeof(pktinfo->ipi_spec_dst)); -#elif defined(IP_SENDSRCADDR) - struct cmsghdr *cmsg; - mhdr.msg_control = buf; - mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_addr)); - - cmsg = CMSG_FIRSTHDR(&mhdr); - cmsg->cmsg_level = IPPROTO_IP; - cmsg->cmsg_type = IP_SENDSRCADDR; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); - - memcpy(CMSG_DATA(cmsg), &session->local_addr.addr.sin.sin_addr, sizeof(struct in_addr)); -#endif /* IP_PKTINFO */ - break; - } - default: - /* error */ - coap_log(LOG_WARNING, "protocol not supported\n"); - bytes_written = -1; - } -#endif /* ! COAP_BAD_RECVMSG */ - -#ifdef _WIN32 - r = WSASendMsg(sock->fd, &mhdr, 0 /*dwFlags*/, &dwNumberOfBytesSent, NULL /*lpOverlapped*/, NULL /*lpCompletionRoutine*/); - if (r == 0) - bytes_written = (ssize_t)dwNumberOfBytesSent; - else - bytes_written = -1; -#else -#ifndef COAP_BAD_RECVMSG - bytes_written = sendmsg(sock->fd, &mhdr, 0); -#else /* COAP_BAD_RECVMSG */ - bytes_written = sendto(sock->fd, data, datalen, 0, &session->remote_addr.addr.sa, session->remote_addr.size); -#endif /* COAP_BAD_RECVMSG */ -#endif -#else /* WITH_CONTIKI */ - /* FIXME: untested */ - /* FIXME: is there a way to check if send was successful? */ - (void)datalen; - (void)data; - uip_udp_packet_sendto((struct uip_udp_conn *)sock->conn, data, datalen, - &session->remote_addr.addr, session->remote_addr.port); - bytes_written = datalen; -#endif /* WITH_CONTIKI */ - } - - if (bytes_written < 0) - coap_log(LOG_CRIT, "coap_network_send: %s\n", coap_socket_strerror()); - - return bytes_written; -} - -#define SIN6(A) ((struct sockaddr_in6 *)(A)) - -void -coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length) { - *address = packet->payload; - *length = packet->length; -} - -void coap_packet_set_addr(coap_packet_t *packet, const coap_address_t *src, const coap_address_t *dst) { - coap_address_copy(&packet->src, src); - coap_address_copy(&packet->dst, dst); -} - -ssize_t -coap_network_read(coap_socket_t *sock, coap_packet_t *packet) { - ssize_t len = -1; - - assert(sock); - assert(packet); - - if ((sock->flags & COAP_SOCKET_CAN_READ) == 0) { - return -1; - } else { - /* clear has-data flag */ - sock->flags &= ~COAP_SOCKET_CAN_READ; - } - -#ifndef WITH_CONTIKI - if (sock->flags & COAP_SOCKET_CONNECTED) { -#ifdef _WIN32 - len = recv(sock->fd, (char *)packet->payload, COAP_RXBUFFER_SIZE, 0); -#else - len = recv(sock->fd, packet->payload, COAP_RXBUFFER_SIZE, 0); -#endif - if (len < 0) { -#ifdef _WIN32 - if (WSAGetLastError() == WSAECONNRESET) { -#else - if (errno == ECONNREFUSED) { -#endif - /* client-side ICMP destination unreachable, ignore it */ - coap_log(LOG_WARNING, "coap_network_read: unreachable\n"); - return -2; - } - coap_log(LOG_WARNING, "coap_network_read: %s\n", coap_socket_strerror()); - goto error; - } else if (len > 0) { - packet->length = (size_t)len; - } - } else { -#endif /* WITH_CONTIKI */ -#if defined(_WIN32) - DWORD dwNumberOfBytesRecvd = 0; - int r; -#endif -#if !defined(WITH_CONTIKI) -#ifndef COAP_BAD_RECVMSG - /* a buffer large enough to hold all packet info types, ipv6 is the largest */ - char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; - struct msghdr mhdr; - struct iovec iov[1]; - - iov[0].iov_base = packet->payload; - iov[0].iov_len = (iov_len_t)COAP_RXBUFFER_SIZE; - - memset(&mhdr, 0, sizeof(struct msghdr)); - - mhdr.msg_name = (struct sockaddr*)&packet->src.addr; - mhdr.msg_namelen = sizeof(packet->src.addr); - - mhdr.msg_iov = iov; - mhdr.msg_iovlen = 1; - - mhdr.msg_control = buf; - mhdr.msg_controllen = sizeof(buf); - -#if defined(_WIN32) - if (!lpWSARecvMsg) { - GUID wsaid = WSAID_WSARECVMSG; - DWORD cbBytesReturned = 0; - if (WSAIoctl(sock->fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &wsaid, sizeof(wsaid), &lpWSARecvMsg, sizeof(lpWSARecvMsg), &cbBytesReturned, NULL, NULL) != 0) { - coap_log(LOG_WARNING, "coap_network_read: no WSARecvMsg\n"); - return -1; - } - } - r = lpWSARecvMsg(sock->fd, &mhdr, &dwNumberOfBytesRecvd, NULL /* LPWSAOVERLAPPED */, NULL /* LPWSAOVERLAPPED_COMPLETION_ROUTINE */); - if (r == 0) - len = (ssize_t)dwNumberOfBytesRecvd; -#else - len = recvmsg(sock->fd, &mhdr, 0); -#endif - -#else /* COAP_BAD_RECVMSG */ - packet->src.size = packet->src.size; - len = recvfrom(sock->fd, packet->payload, COAP_RXBUFFER_SIZE, 0, &packet->src.addr.sa, &packet->src.size); -#endif /* COAP_BAD_RECVMSG */ - - if (len < 0) { -#ifdef _WIN32 - if (WSAGetLastError() == WSAECONNRESET) { -#else - if (errno == ECONNREFUSED) { -#endif - /* server-side ICMP destination unreachable, ignore it. The destination address is in msg_name. */ - return 0; - } - coap_log(LOG_WARNING, "coap_network_read: %s\n", coap_socket_strerror()); - goto error; - } else { -#ifndef COAP_BAD_RECVMSG - struct cmsghdr *cmsg; - - packet->src.size = mhdr.msg_namelen; - packet->length = (size_t)len; - - /* Walk through ancillary data records until the local interface - * is found where the data was received. */ - for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg; cmsg = CMSG_NXTHDR(&mhdr, cmsg)) { - - /* get the local interface for IPv6 */ - if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) { - union { - uint8_t *c; - struct in6_pktinfo *p; - } u; - u.c = CMSG_DATA(cmsg); - packet->ifindex = (int)(u.p->ipi6_ifindex); - memcpy(&packet->dst.addr.sin6.sin6_addr, &u.p->ipi6_addr, sizeof(struct in6_addr)); - break; - } - - /* local interface for IPv4 */ -#if defined(IP_PKTINFO) - if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) { - union { - uint8_t *c; - struct in_pktinfo *p; - } u; - u.c = CMSG_DATA(cmsg); - packet->ifindex = u.p->ipi_ifindex; - if (packet->dst.addr.sa.sa_family == AF_INET6) { - memset(packet->dst.addr.sin6.sin6_addr.s6_addr, 0, 10); - packet->dst.addr.sin6.sin6_addr.s6_addr[10] = 0xff; - packet->dst.addr.sin6.sin6_addr.s6_addr[11] = 0xff; - memcpy(packet->dst.addr.sin6.sin6_addr.s6_addr + 12, &u.p->ipi_addr, sizeof(struct in_addr)); - } else { - memcpy(&packet->dst.addr.sin.sin_addr, &u.p->ipi_addr, sizeof(struct in_addr)); - } - break; - } -#elif defined(IP_RECVDSTADDR) - if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) { - packet->ifindex = 0; - memcpy(&packet->dst.addr.sin.sin_addr, CMSG_DATA(cmsg), sizeof(struct in_addr)); - break; - } -#endif /* IP_PKTINFO */ - } -#else /* COAP_BAD_RECVMSG */ - packet->length = (size_t)len; - packet->ifindex = 0; - if (getsockname(sock->fd, &packet->dst.addr.sa, &packet->dst.size) < 0) { - coap_log(LOG_DEBUG, "Cannot determine local port\n"); - goto error; - } -#endif /* COAP_BAD_RECVMSG */ - } -#endif /* !defined(WITH_CONTIKI) */ -#ifdef WITH_CONTIKI - /* FIXME: untested, make this work */ -#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) -#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN]) - - if (uip_newdata()) { - uip_ipaddr_copy(&packet->src.addr, &UIP_IP_BUF->srcipaddr); - packet->src.port = UIP_UDP_BUF->srcport; - uip_ipaddr_copy(&(packet)->dst.addr, &UIP_IP_BUF->destipaddr); - packet->dst.port = UIP_UDP_BUF->destport; - - len = uip_datalen(); - - if (len > COAP_RXBUFFER_SIZE) { - /* FIXME: we might want to send back a response */ - coap_log(LOG_WARNING, "discarded oversized packet\n"); - return -1; - } - - ((char *)uip_appdata)[len] = 0; -#ifndef NDEBUG - if (LOG_DEBUG <= coap_get_log_level()) { -#ifndef INET6_ADDRSTRLEN -#define INET6_ADDRSTRLEN 40 -#endif - unsigned char addr_str[INET6_ADDRSTRLEN + 8]; - - if (coap_print_addr(&packet->src, addr_str, INET6_ADDRSTRLEN + 8)) { - coap_log(LOG_DEBUG, "received %zd bytes from %s\n", len, addr_str); - } - } -#endif /* NDEBUG */ - - packet->length = len; - memcpy(&packet->payload, uip_appdata, len); - } - -#undef UIP_IP_BUF -#undef UIP_UDP_BUF -#endif /* WITH_CONTIKI */ -#ifndef WITH_CONTIKI - } -#endif /* WITH_CONTIKI */ - - if (len >= 0) - return len; -#if !defined(WITH_CONTIKI) -error: -#endif - return -1; -} - -#if !defined(WITH_CONTIKI) - -unsigned int -coap_write(coap_context_t *ctx, - coap_socket_t *sockets[], - unsigned int max_sockets, - unsigned int *num_sockets, - coap_tick_t now) -{ - coap_queue_t *nextpdu; - coap_endpoint_t *ep; - coap_session_t *s; - coap_tick_t session_timeout; - coap_tick_t timeout = 0; - coap_session_t *tmp; - - *num_sockets = 0; - - /* Check to see if we need to send off any Observe requests */ - coap_check_notify(ctx); - - if (ctx->session_timeout > 0) - session_timeout = ctx->session_timeout * COAP_TICKS_PER_SECOND; - else - session_timeout = COAP_DEFAULT_SESSION_TIMEOUT * COAP_TICKS_PER_SECOND; - - LL_FOREACH(ctx->endpoint, ep) { - if (ep->sock.flags & (COAP_SOCKET_WANT_READ | COAP_SOCKET_WANT_WRITE | COAP_SOCKET_WANT_ACCEPT)) { - if (*num_sockets < max_sockets) - sockets[(*num_sockets)++] = &ep->sock; - } - LL_FOREACH_SAFE(ep->sessions, s, tmp) { - if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 && - s->delayqueue == NULL && - (s->last_rx_tx + session_timeout <= now || - s->state == COAP_SESSION_STATE_NONE)) { - coap_session_free(s); - } else { - if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 && s->delayqueue == NULL) { - coap_tick_t s_timeout = (s->last_rx_tx + session_timeout) - now; - if (timeout == 0 || s_timeout < timeout) - timeout = s_timeout; - } - if (s->sock.flags & (COAP_SOCKET_WANT_READ | COAP_SOCKET_WANT_WRITE)) { - if (*num_sockets < max_sockets) - sockets[(*num_sockets)++] = &s->sock; - } - } - } - } - LL_FOREACH_SAFE(ctx->sessions, s, tmp) { - if ( - s->type == COAP_SESSION_TYPE_CLIENT - && COAP_PROTO_RELIABLE(s->proto) - && s->state == COAP_SESSION_STATE_ESTABLISHED - && ctx->ping_timeout > 0 - ) { - coap_tick_t s_timeout; - if (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND <= now) { - if ((s->last_ping > 0 && s->last_pong < s->last_ping) - || coap_session_send_ping(s) == COAP_INVALID_TID) - { - /* Make sure the session object is not deleted in the callback */ - coap_session_reference(s); - coap_session_disconnected(s, COAP_NACK_NOT_DELIVERABLE); - coap_session_release(s); - continue; - } - s->last_rx_tx = now; - s->last_ping = now; - } - s_timeout = (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND) - now; - if (timeout == 0 || s_timeout < timeout) - timeout = s_timeout; - } - - if ( - s->type == COAP_SESSION_TYPE_CLIENT - && COAP_PROTO_RELIABLE(s->proto) - && s->state == COAP_SESSION_STATE_CSM - && ctx->csm_timeout > 0 - ) { - coap_tick_t s_timeout; - if (s->csm_tx == 0) { - s->csm_tx = now; - } else if (s->csm_tx + ctx->csm_timeout * COAP_TICKS_PER_SECOND <= now) { - /* Make sure the session object is not deleted in the callback */ - coap_session_reference(s); - coap_session_disconnected(s, COAP_NACK_NOT_DELIVERABLE); - coap_session_release(s); - continue; - } - s_timeout = (s->csm_tx + ctx->csm_timeout * COAP_TICKS_PER_SECOND) - now; - if (timeout == 0 || s_timeout < timeout) - timeout = s_timeout; - } - - if (s->sock.flags & (COAP_SOCKET_WANT_READ | COAP_SOCKET_WANT_WRITE | COAP_SOCKET_WANT_CONNECT)) { - if (*num_sockets < max_sockets) - sockets[(*num_sockets)++] = &s->sock; - } - } - - nextpdu = coap_peek_next(ctx); - - while (nextpdu && now >= ctx->sendqueue_basetime && nextpdu->t <= now - ctx->sendqueue_basetime) { - coap_retransmit(ctx, coap_pop_next(ctx)); - nextpdu = coap_peek_next(ctx); - } - - if (nextpdu && (timeout == 0 || nextpdu->t - ( now - ctx->sendqueue_basetime ) < timeout)) - timeout = nextpdu->t - (now - ctx->sendqueue_basetime); - - if (ctx->dtls_context) { - if (coap_dtls_is_context_timeout()) { - coap_tick_t tls_timeout = coap_dtls_get_context_timeout(ctx->dtls_context); - if (tls_timeout > 0) { - if (tls_timeout < now + COAP_TICKS_PER_SECOND / 10) - tls_timeout = now + COAP_TICKS_PER_SECOND / 10; - coap_log(LOG_DEBUG, "** DTLS global timeout set to %dms\n", - (int)((tls_timeout - now) * 1000 / COAP_TICKS_PER_SECOND)); - if (timeout == 0 || tls_timeout - now < timeout) - timeout = tls_timeout - now; - } - } else { - LL_FOREACH(ctx->endpoint, ep) { - if (ep->proto == COAP_PROTO_DTLS) { - LL_FOREACH(ep->sessions, s) { - if (s->proto == COAP_PROTO_DTLS && s->tls) { - coap_tick_t tls_timeout = coap_dtls_get_timeout(s); - while (tls_timeout > 0 && tls_timeout <= now) { - coap_log(LOG_DEBUG, "** %s: DTLS retransmit timeout\n", - coap_session_str(s)); - coap_dtls_handle_timeout(s); - if (s->tls) - tls_timeout = coap_dtls_get_timeout(s); - else { - tls_timeout = 0; - timeout = 1; - } - } - if (tls_timeout > 0 && (timeout == 0 || tls_timeout - now < timeout)) - timeout = tls_timeout - now; - } - } - } - } - LL_FOREACH(ctx->sessions, s) { - if (s->proto == COAP_PROTO_DTLS && s->tls) { - coap_tick_t tls_timeout = coap_dtls_get_timeout(s); - while (tls_timeout > 0 && tls_timeout <= now) { - coap_log(LOG_DEBUG, "** %s: DTLS retransmit timeout\n", coap_session_str(s)); - coap_dtls_handle_timeout(s); - if (s->tls) - tls_timeout = coap_dtls_get_timeout(s); - else { - tls_timeout = 0; - timeout = 1; - } - } - if (tls_timeout > 0 && (timeout == 0 || tls_timeout - now < timeout)) - timeout = tls_timeout - now; - } - } - } - } - - return (unsigned int)((timeout * 1000 + COAP_TICKS_PER_SECOND - 1) / COAP_TICKS_PER_SECOND); -} - -int -coap_run_once(coap_context_t *ctx, unsigned timeout_ms) { - fd_set readfds, writefds, exceptfds; - coap_fd_t nfds = 0; - struct timeval tv; - coap_tick_t before, now; - int result; - coap_socket_t *sockets[64]; - unsigned int num_sockets = 0, i, timeout; - - coap_ticks(&before); - - timeout = coap_write(ctx, sockets, (unsigned int)(sizeof(sockets) / sizeof(sockets[0])), &num_sockets, before); - if (timeout == 0 || timeout_ms < timeout) - timeout = timeout_ms; - - FD_ZERO(&readfds); - FD_ZERO(&writefds); - FD_ZERO(&exceptfds); - for (i = 0; i < num_sockets; i++) { - if (sockets[i]->fd + 1 > nfds) - nfds = sockets[i]->fd + 1; - if (sockets[i]->flags & COAP_SOCKET_WANT_READ) - FD_SET(sockets[i]->fd, &readfds); - if (sockets[i]->flags & COAP_SOCKET_WANT_WRITE) - FD_SET(sockets[i]->fd, &writefds); - if (sockets[i]->flags & COAP_SOCKET_WANT_ACCEPT) - FD_SET(sockets[i]->fd, &readfds); - if (sockets[i]->flags & COAP_SOCKET_WANT_CONNECT) { - FD_SET(sockets[i]->fd, &writefds); - FD_SET(sockets[i]->fd, &exceptfds); - } - } - - if ( timeout > 0 ) { - tv.tv_usec = (timeout % 1000) * 1000; - tv.tv_sec = (long)(timeout / 1000); - } - - result = select(nfds, &readfds, &writefds, &exceptfds, timeout > 0 ? &tv : NULL); - - if (result < 0) { /* error */ -#ifdef _WIN32 - if (WSAGetLastError() != WSAEINVAL) { /* May happen because of ICMP */ -#else - if (errno != EINTR) { -#endif - coap_log(LOG_DEBUG, "%s", coap_socket_strerror()); - return -1; - } - } - - if (result > 0) { - for (i = 0; i < num_sockets; i++) { - if ((sockets[i]->flags & COAP_SOCKET_WANT_READ) && FD_ISSET(sockets[i]->fd, &readfds)) - sockets[i]->flags |= COAP_SOCKET_CAN_READ; - if ((sockets[i]->flags & COAP_SOCKET_WANT_ACCEPT) && FD_ISSET(sockets[i]->fd, &readfds)) - sockets[i]->flags |= COAP_SOCKET_CAN_ACCEPT; - if ((sockets[i]->flags & COAP_SOCKET_WANT_WRITE) && FD_ISSET(sockets[i]->fd, &writefds)) - sockets[i]->flags |= COAP_SOCKET_CAN_WRITE; - if ((sockets[i]->flags & COAP_SOCKET_WANT_CONNECT) && (FD_ISSET(sockets[i]->fd, &writefds) || FD_ISSET(sockets[i]->fd, &exceptfds))) - sockets[i]->flags |= COAP_SOCKET_CAN_CONNECT; - } - } - - coap_ticks(&now); - coap_read(ctx, now); - - return (int)(((now - before) * 1000) / COAP_TICKS_PER_SECOND); -} - -#else -int coap_run_once(coap_context_t *ctx, unsigned int timeout_ms) { - return -1; -} - -unsigned int -coap_write(coap_context_t *ctx, - coap_socket_t *sockets[], - unsigned int max_sockets, - unsigned int *num_sockets, - coap_tick_t now) -{ - *num_sockets = 0; - return 0; -} -#endif - -#ifdef _WIN32 -static const char *coap_socket_format_errno(int error) { - static char szError[256]; - if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, (DWORD)error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)szError, (DWORD)sizeof(szError), NULL) == 0) - strcpy(szError, "Unknown error"); - return szError; -} - -const char *coap_socket_strerror(void) { - return coap_socket_format_errno(WSAGetLastError()); -} -#else -#ifndef WITH_CONTIKI -static const char *coap_socket_format_errno(int error) { - return strerror(error); -} -#endif /* WITH_CONTIKI */ - -const char *coap_socket_strerror(void) { - return strerror(errno); -} -#endif - -ssize_t -coap_socket_send(coap_socket_t *sock, coap_session_t *session, - const uint8_t *data, size_t data_len) { - return session->context->network_send(sock, session, data, data_len); -} - -#undef SIN6 diff --git a/components/coap/port/coap_mbedtls.c b/components/coap/port/coap_mbedtls.c new file mode 100644 index 0000000000..9f8c1fab98 --- /dev/null +++ b/components/coap/port/coap_mbedtls.c @@ -0,0 +1,1796 @@ +/* +* coap_mbedtls.c -- mbedTLS Datagram Transport Layer Support for libcoap +* +* Copyright (C) 2019 Jon Shallow +* 2019 Jitin George +* +* This file is part of the CoAP library libcoap. Please see README for terms +* of use. +*/ + +/* + * Naming used to prevent confusion between coap sessions, mbedtls sessions etc. + * when reading the code. + * + * c_context A coap_context_t * + * c_session A coap_session_t * + * m_context A coap_mbedtls_context_t * (held in c_context->dtls_context) + * m_env A coap_mbedtls_env_t * (held in c_session->tls) + */ + +#include "coap_config.h" + +#ifdef HAVE_MBEDTLS + +/* + * Once PS #335 has been merged in, then code following a rebase needs to be + * updated removing sections that are "#ifndef PSK2_PR", and then remove all + * references to PSK2_PR. + */ +#undef PSK2_PR + +#include "libcoap.h" +#include "coap_dtls.h" +#include "net.h" +#include "mem.h" +#include "coap_debug.h" +#include "prng.h" +#include "coap_mutex.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(ESPIDF_VERSION) && defined(CONFIG_MBEDTLS_DEBUG) +#include +#endif /* ESPIDF_VERSION && CONFIG_MBEDTLS_DEBUG */ +#include +#include + +#define mbedtls_malloc(a) malloc(a) +#define mbedtls_realloc(a,b) realloc(a,b) +#define mbedtls_strdup(a) strdup(a) + +#ifdef __GNUC__ +#define UNUSED __attribute__((unused)) +#else /* __GNUC__ */ +#define UNUSED +#endif /* __GNUC__ */ + +#define IS_PSK (1 << 0) +#define IS_PKI (1 << 1) +#define IS_CLIENT (1 << 6) +#define IS_SERVER (1 << 7) + +typedef struct coap_ssl_t { + const uint8_t *pdu; + unsigned pdu_len; + unsigned peekmode; + coap_tick_t timeout; +} coap_ssl_t; + +/* + * This structure encapsulates the mbedTLS session object. + * It handles both TLS and DTLS. + * c_session->tls points to this. + */ +typedef struct coap_mbedtls_env_t { + mbedtls_ssl_context ssl; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_ssl_config conf; + mbedtls_timing_delay_context timer; + mbedtls_x509_crt cacert; + mbedtls_x509_crt public_cert; + mbedtls_pk_context private_key; + mbedtls_ssl_cookie_ctx cookie_ctx; + /* If not set, need to do do_mbedtls_handshake */ + int established; + int seen_client_hello; + coap_ssl_t coap_ssl_data; +} coap_mbedtls_env_t; + +typedef struct pki_sni_entry { + char *sni; + coap_dtls_key_t pki_key; + mbedtls_x509_crt cacert; + mbedtls_x509_crt public_cert; + mbedtls_pk_context private_key; +} pki_sni_entry; + +#ifdef PSK2_PR +typedef struct psk_sni_entry { + coap_string_t sni; + coap_dtls_spsk_info_t psk_info; +} psk_sni_entry; +#endif /* PSK2_PR */ + +typedef struct coap_mbedtls_context_t { + coap_dtls_pki_t setup_data; + size_t pki_sni_count; + pki_sni_entry *pki_sni_entry_list; +#ifdef PSK2_PR + size_t psk_sni_count; + psk_sni_entry *psk_sni_entry_list; +#endif /* PSK2_PR */ + char *root_ca_file; + char *root_ca_path; + int psk_pki_enabled; +} coap_mbedtls_context_t; + +static int coap_dgram_read(void *ctx, unsigned char *out, size_t outl) +{ + ssize_t ret = 0; + coap_session_t *c_session = (struct coap_session_t *)ctx; + coap_ssl_t *data = &((coap_mbedtls_env_t *)c_session->tls)->coap_ssl_data; + + if (!c_session->tls) { + errno = EAGAIN; + return MBEDTLS_ERR_SSL_WANT_READ; + } + + if (out != NULL) { + if (data != NULL && data->pdu_len > 0) { + if (outl < data->pdu_len) { + memcpy(out, data->pdu, outl); + ret = outl; + data->pdu += outl; + data->pdu_len -= outl; + } + else { + memcpy(out, data->pdu, data->pdu_len); + ret = data->pdu_len; + if (!data->peekmode) { + data->pdu_len = 0; + data->pdu = NULL; + } + } + } + else { + ret = MBEDTLS_ERR_SSL_WANT_READ; + errno = EAGAIN; + return ret; + } + } + return ret; +} + +/* + * return +ve data amount + * 0 no more + * -1 error (error in errno) + */ +/* callback function given to mbedtls for sending data over socket */ +static int +coap_dgram_write(void *ctx, const unsigned char *send_buffer, + size_t send_buffer_length) +{ + ssize_t result = -1; + coap_session_t *c_session = (struct coap_session_t *)ctx; + + if (c_session) { + result = coap_session_send(c_session, send_buffer, send_buffer_length); + if (result != (int)send_buffer_length) { + coap_log(LOG_WARNING, "coap_network_send failed (%zd != %zd)\n", + result, send_buffer_length); + result = 0; + } + } else { + result = 0; + } + return result; +} + +#if !defined(ESPIDF_VERSION) || defined(CONFIG_MBEDTLS_SSL_PROTO_DTLS) +static char* +get_ip_addr(const struct coap_address_t *addr) +{ + const void *addrptr = NULL; + size_t buf_len; + + if (!addr) { + return NULL; + } + switch (addr->addr.sa.sa_family) { + case AF_INET: + addrptr = &addr->addr.sin.sin_addr; + buf_len = INET_ADDRSTRLEN; + break; + case AF_INET6: + addrptr = &addr->addr.sin6.sin6_addr; + buf_len = INET6_ADDRSTRLEN; + break; + default: + return NULL; + } + char *str = (char *)mbedtls_calloc(1, buf_len); + if (!str) { + coap_log(LOG_ERR, "Memory allocation failed\n"); + return NULL; + } + if (inet_ntop(addr->addr.sa.sa_family, addrptr, str, + buf_len) == 0) { + perror("coap_print_addr"); + return 0; + } + return str; +} +#endif /* !ESPIDF_VERSION || CONFIG_MBEDTLS_SSL_PROTO_DTLS */ + +#if !defined(ESPIDF_VERSION) || (defined(CONFIG_MBEDTLS_SSL_PROTO_DTLS) && defined(CONFIG_MBEDTLS_PSK_MODES)) +/* + * Server side PSK callback + */ +static int psk_server_callback(void *p_info, mbedtls_ssl_context *ssl, + const unsigned char *name, size_t name_len ) +{ + coap_session_t *c_session = + (coap_session_t *)p_info; + uint8_t buf[128]; + size_t psk_len; +#ifdef PSK2_PR + coap_dtls_spsk_t *setup_data; +#endif /* PSK2_PR */ + coap_mbedtls_env_t *m_env; + + coap_log(LOG_DEBUG, "got psk_identity: '%.*s'\n", + (int)name_len, name); + + if (c_session == NULL || c_session->context == NULL || + c_session->context->get_server_psk == NULL) { + return -1; + } + m_env = (coap_mbedtls_env_t *)c_session->tls; +#ifdef PSK2_PR + setup_data = &c_session->context->spsk_setup_data; + + if (setup_data->validate_id_call_back) { + coap_bin_const_t lidentity; + lidentity.length = name_len; + lidentity.s = (const uint8_t*)name; + const coap_bin_const_t *psk_key = + setup_data->validate_id_call_back(&lidentity, + c_session, + setup_data->id_call_back_arg); + + if (psk_key == NULL) + return -1; + mbedtls_ssl_set_hs_psk(ssl, psk_key->s, psk_key->length); + coap_session_refresh_psk_key(c_session, psk_key); + m_env->seen_client_hello = 1; + return 0; + } +#endif /* PSK2_PR */ + + psk_len = c_session->context->get_server_psk(c_session, + (const uint8_t*)name, + name_len, + (uint8_t*)buf, sizeof(buf)); + m_env->seen_client_hello = 1; + mbedtls_ssl_set_hs_psk(ssl, buf, psk_len); + return 0; +} +#endif /* !ESPIDF_VERSION || CONFIG_MBEDTLS_SSL_PROTO_DTLS */ + +static char* +get_san_or_cn_from_cert(mbedtls_x509_crt *crt) +{ + if (crt) { +#if COAP_CONSTRAINED_STACK + static coap_mutex_t a_static_mutex = COAP_MUTEX_INITIALIZER; + static char buf[1024]; +#else /* ! COAP_CONSTRAINED_STACK */ + char buf[1024]; +#endif /* ! COAP_CONSTRAINED_STACK */ + char *cn; + char *cp; + char *tcp; + int n; + +#if COAP_CONSTRAINED_STACK + coap_mutex_lock(&a_static_mutex); +#endif /* COAP_CONSTRAINED_STACK */ + + mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "", crt ); + + /* Look first to see if Subject Alt Name is defined */ + cp = strstr(buf, "subject alt name"); + if (cp) { + cp = strchr(cp, ':'); + if (cp) { + cp++; + while (*cp == ' ') cp++; + tcp = strchr(cp, '\n'); + if (tcp) + *tcp = '\000'; + /* Take only the first entry */ + tcp = strchr(cp, ','); + if (tcp) + *tcp = '\000'; + /* Return the Subject Alt Name */ +#if COAP_CONSTRAINED_STACK + coap_mutex_unlock(&a_static_mutex); +#endif /* COAP_CONSTRAINED_STACK */ + return mbedtls_strdup(cp); + } + } + + /* Pull CN= out of subject name */ + cp = strstr(buf, "subject name"); + if (cp) { + cp = strchr(cp, ':'); + if (cp) { + cp++; + while (*cp == ' ') cp++; + tcp = strchr(cp, '\n'); + if (tcp) + *tcp = '\000'; + + /* Need to emulate strcasestr() here. Looking for CN= */ + n = strlen(cp) - 3; + cn = cp; + while (n > 0) { + if (((cn[0] == 'C') || (cn[0] == 'c')) && + ((cn[1] == 'N') || (cn[1] == 'n')) && + (cn[2] == '=')) { + cn += 3; + break; + } + cn++; + n--; + } + if (n > 0) { + tcp = strchr(cn, ','); + if (tcp) + *tcp = '\000'; +#if COAP_CONSTRAINED_STACK + coap_mutex_unlock(&a_static_mutex); +#endif /* COAP_CONSTRAINED_STACK */ + return mbedtls_strdup(cn); + } + } + } +#if COAP_CONSTRAINED_STACK + coap_mutex_unlock(&a_static_mutex); +#endif /* COAP_CONSTRAINED_STACK */ + } + return NULL; +} + +/* + * return 0 All OK + * -ve Error Code + */ +static int +cert_verify_callback_mbedtls(void *data, mbedtls_x509_crt *crt, + int depth, uint32_t *flags) +{ + coap_session_t *c_session = (coap_session_t*)data; + coap_mbedtls_context_t *m_context = + (coap_mbedtls_context_t *)c_session->context->dtls_context; + coap_dtls_pki_t *setup_data = &m_context->setup_data; + char *cn = NULL; + + if (*flags == 0) + return 0; + + if (!setup_data->verify_peer_cert) { + /* Nothing is being checked */ + *flags = 0; + return 0; + } + + cn = get_san_or_cn_from_cert(crt); + + if (*flags & MBEDTLS_X509_BADCERT_EXPIRED) { + if (setup_data->allow_expired_certs) { + *flags &= ~MBEDTLS_X509_BADCERT_EXPIRED; + coap_log(LOG_WARNING, + " %s: %s: overridden: '%s' depth %d\n", + coap_session_str(c_session), + "The certificate has expired", cn ? cn : "?", depth); + } + } + if (*flags & MBEDTLS_X509_BADCERT_FUTURE) { + if (setup_data->allow_expired_certs) { + *flags &= ~MBEDTLS_X509_BADCERT_FUTURE; + coap_log(LOG_WARNING, + " %s: %s: overridden: '%s' depth %d\n", + coap_session_str(c_session), + "The certificate has a future date", cn ? cn : "?", depth); + } + } + if (*flags & MBEDTLS_X509_BADCERT_BAD_MD) { + if (setup_data->allow_bad_md_hash) { + *flags &= ~MBEDTLS_X509_BADCERT_BAD_MD; + coap_log(LOG_WARNING, + " %s: %s: overridden: '%s' depth %d\n", + coap_session_str(c_session), + "The certificate has a bad MD hash", cn ? cn : "?", depth); + } + } + if (*flags & MBEDTLS_X509_BADCERT_BAD_KEY) { + if (setup_data->allow_short_rsa_length) { + *flags &= ~MBEDTLS_X509_BADCERT_BAD_KEY; + coap_log(LOG_WARNING, + " %s: %s: overridden: '%s' depth %d\n", + coap_session_str(c_session), + "The certificate has a short RSA length", cn ? cn : "?", depth); + } + } + if (*flags & MBEDTLS_X509_BADCRL_EXPIRED) { + if (setup_data->check_cert_revocation && setup_data->allow_expired_crl) { + *flags &= ~MBEDTLS_X509_BADCRL_EXPIRED; + coap_log(LOG_WARNING, + " %s: %s: overridden: '%s' depth %d\n", + coap_session_str(c_session), + "The certificate's CRL has expired", cn ? cn : "?", depth); + } + else if (!setup_data->check_cert_revocation) { + *flags &= ~MBEDTLS_X509_BADCRL_EXPIRED; + } + } + if (*flags & MBEDTLS_X509_BADCRL_FUTURE) { + if (setup_data->check_cert_revocation && setup_data->allow_expired_crl) { + *flags &= ~MBEDTLS_X509_BADCRL_FUTURE; + coap_log(LOG_WARNING, + " %s: %s: overridden: '%s' depth %d\n", + coap_session_str(c_session), + "The certificate's CRL has a future date", cn ? cn : "?", depth); + } + else if (!setup_data->check_cert_revocation) { + *flags &= ~MBEDTLS_X509_BADCRL_FUTURE; + } + } + + if (*flags & MBEDTLS_X509_BADCERT_CN_MISMATCH) { + *flags &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH; + } + if (setup_data->validate_cn_call_back) { + if (!setup_data->validate_cn_call_back(cn, + crt->raw.p, + crt->raw.len, + c_session, + depth, + *flags == 0, + setup_data->cn_call_back_arg)) { + *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; + } + } + if (*flags != 0) { + char buf[128]; + char *tcp; + + mbedtls_x509_crt_verify_info(buf, sizeof(buf), "", *flags); + tcp = strchr(buf, '\n'); + while (tcp) { + *tcp = '\000'; + coap_log(LOG_WARNING, + " %s: %s: issue 0x%x: '%s' depth %d\n", + coap_session_str(c_session), + buf, *flags, cn ? cn : "?", depth); + tcp = strchr(tcp+1, '\n'); + } + } + + if (cn) + mbedtls_free(cn); + + return 0; +} + +static int +setup_pki_credentials(mbedtls_x509_crt *cacert, + mbedtls_x509_crt *public_cert, + mbedtls_pk_context *private_key, + coap_mbedtls_env_t *m_env, + coap_mbedtls_context_t *m_context, + coap_session_t *c_session, + coap_dtls_pki_t *setup_data, + coap_dtls_role_t role) +{ + int ret; + + switch (setup_data->pki_key.key_type) { + case COAP_PKI_KEY_PEM: + if (setup_data->pki_key.key.pem.public_cert && + setup_data->pki_key.key.pem.public_cert[0] && + setup_data->pki_key.key.pem.private_key && + setup_data->pki_key.key.pem.private_key[0]) { + + mbedtls_x509_crt_init(public_cert); + mbedtls_pk_init(private_key); + + ret = mbedtls_x509_crt_parse_file(public_cert, + setup_data->pki_key.key.pem.public_cert); + if (ret < 0) { + coap_log(LOG_ERR, "mbedtls_x509_crt_parse_file returned -0x%x\n\n", + -ret); + return ret; + } + + ret = mbedtls_pk_parse_keyfile(private_key, + setup_data->pki_key.key.pem.private_key, NULL); + if (ret < 0) { + coap_log(LOG_ERR, "mbedtls_pk_parse_keyfile returned -0x%x\n\n", -ret); + return ret; + } + + ret = mbedtls_ssl_conf_own_cert(&m_env->conf, public_cert, private_key); + if (ret < 0) { + coap_log(LOG_ERR, "mbedtls_ssl_conf_own_cert returned -0x%x\n\n", -ret); + return ret; + } + } + else if (role == COAP_DTLS_ROLE_SERVER) { + coap_log(LOG_ERR, + "***setup_pki: (D)TLS: No %s Certificate + Private " + "Key defined\n", + role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); + return -1; + } + + if (setup_data->pki_key.key.pem.ca_file && + setup_data->pki_key.key.pem.ca_file[0]) { + mbedtls_x509_crt_init(cacert); + ret = mbedtls_x509_crt_parse_file(cacert, + setup_data->pki_key.key.pem.ca_file); + if (ret < 0) { + coap_log(LOG_ERR, "mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); + return ret; + } + mbedtls_ssl_conf_authmode(&m_env->conf, setup_data->require_peer_cert ? + MBEDTLS_SSL_VERIFY_REQUIRED : + MBEDTLS_SSL_VERIFY_OPTIONAL); + mbedtls_ssl_conf_ca_chain(&m_env->conf, cacert, NULL); + } + break; + case COAP_PKI_KEY_PEM_BUF: + if (setup_data->pki_key.key.pem_buf.public_cert && + setup_data->pki_key.key.pem_buf.public_cert_len && + setup_data->pki_key.key.pem_buf.private_key && + setup_data->pki_key.key.pem_buf.private_key_len > 0) { + mbedtls_x509_crt_init(public_cert); + mbedtls_pk_init(private_key); + ret = mbedtls_x509_crt_parse(public_cert, + (const unsigned char *)setup_data->pki_key.key.pem_buf.public_cert, + setup_data->pki_key.key.pem_buf.public_cert_len); + if (ret < 0) { + coap_log(LOG_ERR, "mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); + return ret; + } + + ret = mbedtls_pk_parse_key(private_key, + (const unsigned char *)setup_data->pki_key.key.pem_buf.private_key, + setup_data->pki_key.key.pem_buf.private_key_len, NULL, 0); + if (ret < 0) { + coap_log(LOG_ERR, "mbedtls_pk_parse_keyfile returned -0x%x\n\n", -ret); + return ret; + } + + ret = mbedtls_ssl_conf_own_cert(&m_env->conf, public_cert, private_key); + if (ret < 0) { + coap_log(LOG_ERR, "mbedtls_ssl_conf_own_cert returned -0x%x\n\n", -ret); + return ret; + } + } else if (role == COAP_DTLS_ROLE_SERVER) { + coap_log(LOG_ERR, + "***setup_pki: (D)TLS: No %s Certificate + Private " + "Key defined\n", + role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); + return -1; + } + + if (setup_data->pki_key.key.pem_buf.ca_cert && + setup_data->pki_key.key.pem_buf.ca_cert_len > 0) { + mbedtls_x509_crt_init(cacert); + ret = mbedtls_x509_crt_parse(cacert, + (const unsigned char *)setup_data->pki_key.key.pem_buf.ca_cert, + setup_data->pki_key.key.pem_buf.ca_cert_len); + if (ret < 0) { + coap_log(LOG_ERR, "mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); + return ret; + } + mbedtls_ssl_conf_authmode(&m_env->conf, setup_data->require_peer_cert ? + MBEDTLS_SSL_VERIFY_REQUIRED : + MBEDTLS_SSL_VERIFY_OPTIONAL); + mbedtls_ssl_conf_ca_chain(&m_env->conf, cacert, NULL); + } + break; + case COAP_PKI_KEY_ASN1: + if (setup_data->pki_key.key.asn1.public_cert && + setup_data->pki_key.key.asn1.public_cert_len && + setup_data->pki_key.key.asn1.private_key && + setup_data->pki_key.key.asn1.private_key_len > 0) { + + mbedtls_x509_crt_init(public_cert); + mbedtls_pk_init(private_key); + ret = mbedtls_x509_crt_parse(public_cert, + (const unsigned char *)setup_data->pki_key.key.asn1.public_cert, + setup_data->pki_key.key.asn1.public_cert_len); + if (ret < 0) { + coap_log(LOG_ERR, "mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); + return ret; + } + + ret = mbedtls_pk_parse_key(private_key, + (const unsigned char *)setup_data->pki_key.key.asn1.private_key, + setup_data->pki_key.key.asn1.private_key_len, NULL, 0); + if (ret < 0) { + coap_log(LOG_ERR, "mbedtls_pk_parse_keyfile returned -0x%x\n\n", -ret); + return ret; + } + + ret = mbedtls_ssl_conf_own_cert(&m_env->conf, public_cert, private_key); + if (ret < 0) { + coap_log(LOG_ERR, "mbedtls_ssl_conf_own_cert returned -0x%x\n\n", -ret); + return ret; + } + } else if (role == COAP_DTLS_ROLE_SERVER) { + coap_log(LOG_ERR, + "***setup_pki: (D)TLS: No %s Certificate + Private " + "Key defined\n", + role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); + return -1; + } + + if (setup_data->pki_key.key.asn1.ca_cert && + setup_data->pki_key.key.asn1.ca_cert_len > 0) { + mbedtls_x509_crt_init(cacert); + ret = mbedtls_x509_crt_parse(cacert, + (const unsigned char *)setup_data->pki_key.key.asn1.ca_cert, + setup_data->pki_key.key.asn1.ca_cert_len); + if (ret < 0) { + coap_log(LOG_ERR, "mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); + return ret; + } + mbedtls_ssl_conf_authmode(&m_env->conf, setup_data->require_peer_cert ? + MBEDTLS_SSL_VERIFY_REQUIRED : + MBEDTLS_SSL_VERIFY_OPTIONAL); + mbedtls_ssl_conf_ca_chain(&m_env->conf, cacert, NULL); + } + break; + default: + coap_log(LOG_ERR, + "***setup_pki: (D)TLS: Unknown key type %d\n", + setup_data->pki_key.key_type); + return -1; + } + + if (m_context->root_ca_file) { + ret = mbedtls_x509_crt_parse_file(cacert, m_context->root_ca_file); + if (ret < 0) { + coap_log(LOG_ERR, "mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); + return ret; + } + mbedtls_ssl_conf_ca_chain(&m_env->conf, cacert, NULL); + } + if (m_context->root_ca_path) { + ret = mbedtls_x509_crt_parse_file(cacert, m_context->root_ca_path); + if (ret < 0) { + coap_log(LOG_ERR, "mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); + return ret; + } + mbedtls_ssl_conf_ca_chain(&m_env->conf, cacert, NULL); + } + + /* + * Verify Peer. + * Need to do all checking, even if setup_data->verify_peer_cert is not set + */ + mbedtls_ssl_conf_verify(&m_env->conf, + cert_verify_callback_mbedtls, c_session); + + return 0; +} + +/* + * PKI SNI callback. + */ +static int +pki_sni_callback(void *p_info, mbedtls_ssl_context *ssl, + const unsigned char *uname, size_t name_len) +{ + unsigned int i; + coap_dtls_pki_t sni_setup_data; + coap_session_t *c_session = (coap_session_t *)p_info; + coap_mbedtls_env_t *m_env = (coap_mbedtls_env_t *)c_session->tls; + coap_mbedtls_context_t *m_context = + (coap_mbedtls_context_t *)c_session->context->dtls_context; + int ret = 0; + + /* Is this a cached entry? */ + for (i = 0; i < m_context->pki_sni_count; i++) { + if (name_len == strlen(m_context->pki_sni_entry_list[i].sni) && + memcmp(uname, m_context->pki_sni_entry_list[i].sni, name_len) == 0) { + break; + } + } + if (i == m_context->pki_sni_count) { + /* + * New PKI SNI request + */ + char *name; + coap_dtls_key_t *new_entry; + + name = mbedtls_malloc(name_len+1); + memcpy(name, uname, name_len); + name[name_len] = '\000'; + new_entry = + m_context->setup_data.validate_sni_call_back(name, + m_context->setup_data.sni_call_back_arg); + if (!new_entry) { + ret = -1; + mbedtls_free(name); + goto end; + } + + m_context->pki_sni_entry_list = + mbedtls_realloc(m_context->pki_sni_entry_list, + (i+1)*sizeof(pki_sni_entry)); + m_context->pki_sni_entry_list[i].sni = name; + m_context->pki_sni_entry_list[i].pki_key = *new_entry; + sni_setup_data = m_context->setup_data; + sni_setup_data.pki_key = *new_entry; + if ((ret = setup_pki_credentials(&m_context->pki_sni_entry_list[i].cacert, + &m_context->pki_sni_entry_list[i].public_cert, + &m_context->pki_sni_entry_list[i].private_key, + m_env, + m_context, + c_session, + &sni_setup_data, COAP_DTLS_ROLE_SERVER)) < 0) { + ret = -1; + mbedtls_free(name); + goto end; + } + m_context->pki_sni_count++; + } + +end: + if (ret != -1) { + mbedtls_ssl_set_hs_ca_chain(ssl, &m_context->pki_sni_entry_list[i].cacert, + NULL); + return mbedtls_ssl_set_hs_own_cert(ssl, + &m_context->pki_sni_entry_list[i].public_cert, + &m_context->pki_sni_entry_list[i].private_key); + } + return ret; +} + +#ifdef PSK2_PR +/* + * PSK SNI callback. + */ +static int +psk_sni_callback(void *p_info, mbedtls_ssl_context *ssl, + const unsigned char *uname, size_t name_len) +{ + unsigned int i; + coap_dtls_spsk_t sni_setup_data; + coap_session_t *c_session = (coap_session_t *)p_info; + coap_mbedtls_context_t *m_context = + (coap_mbedtls_context_t *)c_session->context->dtls_context; + int ret = 0; + + /* Is this a cached entry? */ + for (i = 0; i < m_context->psk_sni_count; i++) { + if (name_len == m_context->psk_sni_entry_list[i].sni.length && + memcmp(uname, m_context->psk_sni_entry_list[i].sni.s, name_len) == 0) { + break; + } + } + if (i == m_context->psk_sni_count) { + /* + * New PSK SNI request + */ + coap_str_const_t lsni; + uint8_t *name; + const coap_dtls_spsk_info_t *new_entry; + + name = mbedtls_malloc(name_len+1); + memcpy(name, uname, name_len); + name[name_len] = '\000'; + + lsni.s = name; + lsni.length = name_len; + new_entry = + c_session->context->spsk_setup_data.validate_sni_call_back(&lsni, + c_session, + c_session->context->spsk_setup_data.sni_call_back_arg); + if (!new_entry) { + ret = -1; + mbedtls_free(name); + goto end; + } + + m_context->psk_sni_entry_list = + mbedtls_realloc(m_context->psk_sni_entry_list, + (i+1)*sizeof(psk_sni_entry)); + + m_context->psk_sni_entry_list[i].sni.s = name; + m_context->psk_sni_entry_list[i].sni.length = name_len; + m_context->psk_sni_entry_list[i].psk_info = *new_entry; + sni_setup_data = c_session->context->spsk_setup_data; + sni_setup_data.psk_info = *new_entry; + m_context->psk_sni_count++; + } + +end: + if (ret != -1) { + coap_session_refresh_psk_hint(c_session, + &m_context->psk_sni_entry_list[i].psk_info.hint); + coap_session_refresh_psk_key(c_session, + &m_context->psk_sni_entry_list[i].psk_info.key); + return mbedtls_ssl_set_hs_psk(ssl, + m_context->psk_sni_entry_list[i].psk_info.key.s, + m_context->psk_sni_entry_list[i].psk_info.key.length); + } + return ret; +} +#endif /* PSK2_PR */ + +static int setup_server_ssl_session(coap_session_t *c_session, + coap_mbedtls_env_t *m_env) +{ + coap_mbedtls_context_t *m_context = + (coap_mbedtls_context_t *)c_session->context->dtls_context; + int ret = 0; + m_context->psk_pki_enabled |= IS_SERVER; + + mbedtls_ssl_cookie_init(&m_env->cookie_ctx); + if ((ret = mbedtls_ssl_config_defaults(&m_env->conf, + MBEDTLS_SSL_IS_SERVER, + c_session->proto == COAP_PROTO_DTLS ? + MBEDTLS_SSL_TRANSPORT_DATAGRAM : + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { + coap_log(LOG_ERR, "mbedtls_ssl_config_defaults returned -0x%x\n", -ret); + goto fail; + } + + mbedtls_ssl_conf_rng(&m_env->conf, mbedtls_ctr_drbg_random, &m_env->ctr_drbg); + +#if !defined(ESPIDF_VERSION) || defined(CONFIG_MBEDTLS_SSL_PROTO_DTLS) + mbedtls_ssl_conf_handshake_timeout(&m_env->conf, 1000, 60000); + + if (m_context->psk_pki_enabled & IS_PSK) { +#if !defined(ESPIDF_VERSION) || defined(CONFIG_MBEDTLS_PSK_MODES) + mbedtls_ssl_conf_psk_cb(&m_env->conf, psk_server_callback, c_session); +#ifdef PSK2_PR + if (c_session->context->spsk_setup_data.validate_sni_call_back) { + mbedtls_ssl_conf_sni(&m_env->conf, psk_sni_callback, c_session); + } +#endif /* PSK2_PR */ +#endif /* !ESPIDF_VERSION || CONFIG_MBEDTLS_PSK_MODES */ + } +#endif /* !ESPIDF_VERSION || CONFIG_MBEDTLS_SSL_PROTO_DTLS */ + + if (m_context->psk_pki_enabled & IS_PKI) { + ret = setup_pki_credentials(&m_env->cacert, &m_env->public_cert, + &m_env->private_key, m_env, m_context, + c_session, &m_context->setup_data, + COAP_DTLS_ROLE_SERVER); + if (ret < 0) { + coap_log(LOG_ERR, "PKI setup failed\n"); + return ret; + } + if (m_context->setup_data.validate_sni_call_back) { + mbedtls_ssl_conf_sni(&m_env->conf, pki_sni_callback, c_session); + } + } + + if ((ret = mbedtls_ssl_cookie_setup(&m_env->cookie_ctx, + mbedtls_ctr_drbg_random, + &m_env->ctr_drbg)) != 0) { + coap_log(LOG_ERR, "mbedtls_ssl_cookie_setup: returned -0x%x\n", -ret); + goto fail; + } + +#if !defined(ESPIDF_VERSION) || defined(CONFIG_MBEDTLS_SSL_PROTO_DTLS) + mbedtls_ssl_conf_dtls_cookies(&m_env->conf, mbedtls_ssl_cookie_write, + mbedtls_ssl_cookie_check, + &m_env->cookie_ctx ); + mbedtls_ssl_set_mtu(&m_env->ssl, c_session->mtu); +#endif /* !ESPIDF_VERSION || CONFIG_MBEDTLS_SSL_PROTO_DTLS */ +fail: + return ret; +} + +#define MAX_CIPHERS 100 +static int psk_ciphers[MAX_CIPHERS]; +static int pki_ciphers[MAX_CIPHERS]; +static int processed_ciphers = 0; + +static void +set_ciphersuites(mbedtls_ssl_config *conf, int is_psk) +{ + if (!processed_ciphers) { + const int *list = mbedtls_ssl_list_ciphersuites(); + int *psk_list = psk_ciphers; + int *pki_list = pki_ciphers; + + while (*list) { + const mbedtls_ssl_ciphersuite_t *cur = + mbedtls_ssl_ciphersuite_from_id(*list); + + if (cur) { + if (mbedtls_ssl_ciphersuite_uses_psk(cur)) { + if (&psk_ciphers[MAX_CIPHERS] - psk_list > 1) { + *psk_list = *list; + psk_list++; + } + else { + static int done = 0; + + if (!done) { + done = 1; + coap_log(LOG_ERR, "psk_ciphers[MAX_CIPHERS] insufficient\n"); + } + } + } + else { + if (&pki_ciphers[MAX_CIPHERS] - pki_list > 1) { + *pki_list = *list; + pki_list++; + } + else { + static int done = 0; + + if (!done) { + done = 1; + coap_log(LOG_ERR, "pki_ciphers[MAX_CIPHERS] insufficient\n"); + } + } + } + } + list++; + } + /* zero terminate */ + *psk_list = 0; + *pki_list = 0; + processed_ciphers = 1; + } + mbedtls_ssl_conf_ciphersuites(conf, is_psk ? psk_ciphers : pki_ciphers); +} + +static int setup_client_ssl_session(coap_session_t *c_session, + coap_mbedtls_env_t *m_env) +{ + int ret; + + coap_mbedtls_context_t *m_context = + (coap_mbedtls_context_t *)c_session->context->dtls_context; + + m_context->psk_pki_enabled |= IS_CLIENT; + + if ((ret = mbedtls_ssl_config_defaults(&m_env->conf, + MBEDTLS_SSL_IS_CLIENT, + c_session->proto == COAP_PROTO_DTLS ? + MBEDTLS_SSL_TRANSPORT_DATAGRAM : + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { + coap_log(LOG_ERR, "mbedtls_ssl_config_defaults returned -0x%x", -ret); + goto fail; + } + +#if !defined(ESPIDF_VERSION) || defined(CONFIG_MBEDTLS_SSL_PROTO_DTLS) + mbedtls_ssl_conf_handshake_timeout(&m_env->conf, 1000, 60000); +#endif /* !ESPIDF_VERSION || CONFIG_MBEDTLS_SSL_PROTO_DTLS */ + + mbedtls_ssl_conf_authmode(&m_env->conf, MBEDTLS_SSL_VERIFY_REQUIRED); + mbedtls_ssl_conf_rng(&m_env->conf, mbedtls_ctr_drbg_random, &m_env->ctr_drbg); + + if (m_context->psk_pki_enabled & IS_PSK) { +#if !defined(ESPIDF_VERSION) || defined(CONFIG_MBEDTLS_PSK_MODES) + uint8_t identity[64]; + size_t identity_len; + uint8_t psk_key[64]; + size_t psk_len; + size_t max_identity_len = sizeof(identity); + + coap_log(LOG_INFO, "Setting PSK key\n"); + psk_len = c_session->context->get_client_psk(c_session, + NULL, + 0, + identity, + &identity_len, + max_identity_len, + psk_key, + sizeof(psk_key)); + assert(identity_len < sizeof(identity)); + mbedtls_ssl_conf_psk(&m_env->conf, (const unsigned char *)psk_key, + psk_len, (const unsigned char *)identity, + identity_len); +#ifdef PSK2_PR + if (c_session->cpsk_setup_data.client_sni) { + mbedtls_ssl_set_hostname(&m_env->ssl, + c_session->cpsk_setup_data.client_sni); + } +#if 0 +/* Identity Hint currently not supported in MbedTLS */ + if (c_session->cpsk_setup_data.validate_ih_call_back) { + coap_log(LOG_DEBUG, + "CoAP Client restricted to (D)TLS1.2 with Identity Hint callback\n"); + mbedtls_ssl_conf_max_version(&m_env->conf, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_3); + } +#endif +#endif /* PSK2_PR */ + set_ciphersuites(&m_env->conf, 1); +#endif /* !ESPIDF_VERSION || CONFIG_MBEDTLS_PSK_MODES */ + } + else if ((m_context->psk_pki_enabled & IS_PKI) || + (m_context->psk_pki_enabled & (IS_PSK | IS_PKI)) == 0) { + /* + * If neither PSK or PKI have been set up, use PKI basics. + * This works providing COAP_PKI_KEY_PEM has a value of 0. + */ + if ((m_context->psk_pki_enabled & (IS_PSK | IS_PKI)) == 0) { + mbedtls_ssl_conf_authmode(&m_env->conf, MBEDTLS_SSL_VERIFY_OPTIONAL); + } + ret = setup_pki_credentials(&m_env->cacert, &m_env->public_cert, + &m_env->private_key, m_env, m_context, + c_session, &m_context->setup_data, + COAP_DTLS_ROLE_CLIENT); + if (ret < 0) { + coap_log(LOG_ERR, "PKI setup failed\n"); + return ret; + } + if (c_session->proto == COAP_PROTO_TLS) { + const char *alpn_list[2]; + + memset(alpn_list, 0, sizeof(alpn_list)); + alpn_list[0] = "coap"; + ret = mbedtls_ssl_conf_alpn_protocols(&m_env->conf, alpn_list); + if (ret != 0) { + coap_log(LOG_ERR, "ALPN setup failed %d)\n", ret); + } + } + if (m_context->setup_data.client_sni) { + mbedtls_ssl_set_hostname(&m_env->ssl, m_context->setup_data.client_sni); + } +#if !defined(ESPIDF_VERSION) || defined(CONFIG_MBEDTLS_SSL_PROTO_DTLS) + mbedtls_ssl_set_mtu(&m_env->ssl, c_session->mtu); +#endif /* !ESPIDF_VERSION || CONFIG_MBEDTLS_SSL_PROTO_DTLS */ + set_ciphersuites(&m_env->conf, 0); + } + return 0; + +fail: + return ret; +} + +static void mbedtls_cleanup(coap_mbedtls_env_t *m_env) +{ + if (!m_env) { + return; + } + + mbedtls_x509_crt_free(&m_env->cacert); + mbedtls_x509_crt_free(&m_env->public_cert); + mbedtls_pk_free(&m_env->private_key); + mbedtls_entropy_free(&m_env->entropy); + mbedtls_ssl_config_free(&m_env->conf); + mbedtls_ctr_drbg_free(&m_env->ctr_drbg); + mbedtls_ssl_free(&m_env->ssl); + mbedtls_ssl_cookie_free(&m_env->cookie_ctx); +} + +static void +coap_dtls_free_mbedtls_env(coap_mbedtls_env_t *m_env) { + if (m_env) { + mbedtls_cleanup(m_env); + free(m_env); + } +} + +/* + * return -1 failure + * 0 not completed + * 1 established + */ +static int do_mbedtls_handshake(coap_session_t *c_session, + coap_mbedtls_env_t *m_env) { + int ret; + char buf[128]; + + ret = mbedtls_ssl_handshake(&m_env->ssl); + switch (ret) { + case 0: + m_env->established = 1; + coap_log(LOG_DEBUG, "* %s: MbedTLS established\n", + coap_session_str(c_session)); + ret = 1; + break; + case MBEDTLS_ERR_SSL_WANT_READ: + case MBEDTLS_ERR_SSL_WANT_WRITE: + errno = EAGAIN; + ret = 0; + break; + case MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED: + coap_log(LOG_INFO, "hello verification requested\n"); + ret = -1; + mbedtls_ssl_session_reset(&m_env->ssl); + break; + case MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE: + c_session->dtls_event = COAP_EVENT_DTLS_CLOSED; + ret = -1; + break; + default: + mbedtls_strerror(ret, buf, sizeof(buf)); + coap_log(LOG_WARNING, + "do_mbedtls_handshake: session establish " + "returned -0x%x: '%s'\n", + -ret, buf); + ret = -1; + break; + } + return ret; +} + +static void +mbedtls_debug_out(void *ctx UNUSED, int level, + const char *file, int line, const char *str) { + int log_level; + + switch (level) { + case 4: + case 3: + case 2: + log_level = LOG_DEBUG; + break; + case 1: + log_level = LOG_ERR; + break; + case 0: + default: + log_level = 0; + break; + } + coap_log(log_level, "%s:%04d: %s", file, line, str); +} + +static coap_mbedtls_env_t *coap_dtls_new_mbedtls_env(coap_session_t *c_session, + coap_dtls_role_t role) +{ + int ret = 0; + coap_mbedtls_env_t *m_env = (coap_mbedtls_env_t *)c_session->tls; + + if (m_env) + return m_env; + + m_env = (coap_mbedtls_env_t *)calloc(1, sizeof(coap_mbedtls_env_t)); + if (!m_env) { + return NULL; + } + + mbedtls_ssl_init(&m_env->ssl); + mbedtls_ctr_drbg_init(&m_env->ctr_drbg); + mbedtls_ssl_config_init(&m_env->conf); + mbedtls_entropy_init(&m_env->entropy); + +#if defined(ESPIDF_VERSION) && defined(CONFIG_MBEDTLS_DEBUG) + mbedtls_esp_enable_debug_log(&m_env->conf, CONFIG_MBEDTLS_DEBUG_LEVEL); +#endif /* ESPIDF_VERSION && CONFIG_MBEDTLS_DEBUG */ + if ((ret = mbedtls_ctr_drbg_seed(&m_env->ctr_drbg, + mbedtls_entropy_func, &m_env->entropy, NULL, 0)) != 0) { + coap_log(LOG_ERR, "mbedtls_ctr_drbg_seed returned -0x%x", -ret); + goto fail; + } + + if (role == COAP_DTLS_ROLE_CLIENT) { + if (setup_client_ssl_session(c_session, m_env) != 0) { + goto fail; + } + } else if (role == COAP_DTLS_ROLE_SERVER) { + if (setup_server_ssl_session(c_session, m_env) != 0) { + goto fail; + } + } else { + goto fail; + } + + if ((ret = mbedtls_ssl_setup(&m_env->ssl, &m_env->conf)) != 0) { + goto fail; + } + mbedtls_ssl_set_bio(&m_env->ssl, c_session, coap_dgram_write, + coap_dgram_read, NULL); + mbedtls_ssl_set_timer_cb(&m_env->ssl, &m_env->timer, + mbedtls_timing_set_delay, + mbedtls_timing_get_delay); + + mbedtls_ssl_conf_dbg(&m_env->conf, mbedtls_debug_out, stdout); + return m_env; + +fail: + if (m_env) { + free(m_env); + } + return NULL; +} + +int coap_dtls_is_supported(void) { +#if !defined(ESPIDF_VERSION) || defined(CONFIG_MBEDTLS_SSL_PROTO_DTLS) + return 1; +#else /* ESPIDF_VERSION && !CONFIG_MBEDTLS_SSL_PROTO_DTLS */ + coap_log(LOG_EMERG, + "libcoap not compiled for DTLS with MbedTLS" + " - update MbedTLS to include DTLS\n"); + return 0; +#endif /* ESPIDF_VERSION && !CONFIG_MBEDTLS_SSL_PROTO_DTLS */ +} + +int coap_tls_is_supported(void) +{ + return 0; +} + +void *coap_dtls_new_context(struct coap_context_t *c_context) +{ + coap_mbedtls_context_t *m_context; + (void)c_context; + + m_context = (coap_mbedtls_context_t *)calloc(1, sizeof(coap_mbedtls_context_t)); + if (m_context) { + memset(m_context, 0, sizeof(coap_mbedtls_context_t)); + } + return m_context; +} + +#ifndef PSK2_PR +int coap_dtls_context_set_psk(struct coap_context_t *c_context, + const char *identity_hint UNUSED, + coap_dtls_role_t role UNUSED) +{ + coap_mbedtls_context_t *m_context = + ((coap_mbedtls_context_t *)c_context->dtls_context); + m_context->psk_pki_enabled |= IS_PSK; + return 1; +} +#else /* PSK2_PR */ +/* + * return 0 failed + * 1 passed + */ +int +coap_dtls_context_set_spsk(coap_context_t *c_context, + coap_dtls_spsk_t *setup_data +) { + coap_mbedtls_context_t *m_context = + ((coap_mbedtls_context_t *)c_context->dtls_context); + + if (!m_context || !setup_data) + return 0; + + m_context->psk_pki_enabled |= IS_PSK; + return 1; +} + +/* + * return 0 failed + * 1 passed + */ +int +coap_dtls_context_set_cpsk(coap_context_t *c_context, + coap_dtls_cpsk_t *setup_data +) { + coap_mbedtls_context_t *m_context = + ((coap_mbedtls_context_t *)c_context->dtls_context); + + if (!m_context || !setup_data) + return 0; + + if (setup_data->validate_ih_call_back) { + coap_log(LOG_WARNING, + "CoAP Client with MbedTLS does not support Identity Hint selection\n"); + } + m_context->psk_pki_enabled |= IS_PSK; + return 1; +} + +#endif /* PSK2_PR */ + +int coap_dtls_context_set_pki(struct coap_context_t *c_context, + coap_dtls_pki_t *setup_data, + coap_dtls_role_t role UNUSED) +{ + coap_mbedtls_context_t *m_context = + ((coap_mbedtls_context_t *)c_context->dtls_context); + + m_context->setup_data = *setup_data; + m_context->psk_pki_enabled |= IS_PKI; + return 1; +} + +int coap_dtls_context_set_pki_root_cas(struct coap_context_t *c_context, + const char *ca_file, + const char *ca_path) +{ + coap_mbedtls_context_t *m_context = + ((coap_mbedtls_context_t *)c_context->dtls_context); + if (!m_context) { + coap_log(LOG_WARNING, + "coap_context_set_pki_root_cas: (D)TLS environment " + "not set up\n"); + return 0; + } + + if (ca_file == NULL && ca_path == NULL) { + coap_log(LOG_WARNING, + "coap_context_set_pki_root_cas: ca_file and/or ca_path " + "not defined\n"); + return 0; + } + if (m_context->root_ca_file) { + free(m_context->root_ca_file); + m_context->root_ca_file = NULL; + } + + if (ca_file) { + m_context->root_ca_file = mbedtls_strdup(ca_file); + } + + if (m_context->root_ca_path) { + free(m_context->root_ca_path); + m_context->root_ca_path = NULL; + } + + if (ca_path) { + m_context->root_ca_path = mbedtls_strdup(ca_path); + } + return 1; +} + +int coap_dtls_context_check_keys_enabled(struct coap_context_t *c_context) +{ + coap_mbedtls_context_t *m_context = + ((coap_mbedtls_context_t *)c_context->dtls_context); + return m_context->psk_pki_enabled ? 1 : 0; +} + +void coap_dtls_free_context(void *dtls_context) +{ + coap_mbedtls_context_t *m_context = (coap_mbedtls_context_t *)dtls_context; + unsigned int i; + + for (i = 0; i < m_context->pki_sni_count; i++) { + mbedtls_free(m_context->pki_sni_entry_list[i].sni); + + mbedtls_x509_crt_free(&m_context->pki_sni_entry_list[i].public_cert); + + mbedtls_pk_free(&m_context->pki_sni_entry_list[i].private_key); + + mbedtls_x509_crt_free(&m_context->pki_sni_entry_list[i].cacert); + } +#ifdef PSK2_PR + for (i = 0; i < m_context->psk_sni_count; i++) { + mbedtls_free(m_context->psk_sni_entry_list[i].sni.s); + } + if (m_context->psk_sni_entry_list) + mbedtls_free(m_context->pki_sni_entry_list); + +#endif /* PSK2_PR */ + + free(m_context); +} + +void *coap_dtls_new_client_session(coap_session_t *c_session) +{ + coap_mbedtls_env_t *m_env = coap_dtls_new_mbedtls_env(c_session, + COAP_DTLS_ROLE_CLIENT); + int ret; + + if (m_env) { + ret = do_mbedtls_handshake(c_session, m_env); + if (ret == -1) { + coap_dtls_free_mbedtls_env(m_env); + return NULL; + } + } + return m_env; +} + +void *coap_dtls_new_server_session(coap_session_t *c_session) +{ + coap_mbedtls_env_t *m_env = + (coap_mbedtls_env_t *)c_session->tls; + if (m_env) { + m_env->seen_client_hello = 1; +#if !defined(ESPIDF_VERSION) || defined(CONFIG_MBEDTLS_SSL_PROTO_DTLS) + mbedtls_ssl_set_mtu(&m_env->ssl, c_session->mtu); +#endif /* !ESPIDF_VERSION || CONFIG_MBEDTLS_SSL_PROTO_DTLS */ + } + return m_env; +} + +void coap_dtls_free_session(coap_session_t *c_session) +{ + if (c_session && c_session->context) { + coap_dtls_free_mbedtls_env(c_session->tls); + c_session->tls = NULL; + } + return; +} + +void coap_dtls_session_update_mtu(coap_session_t *c_session) +{ +#if !defined(ESPIDF_VERSION) || defined(CONFIG_MBEDTLS_SSL_PROTO_DTLS) + coap_mbedtls_env_t *m_env = + (coap_mbedtls_env_t *)c_session->tls; + if (m_env) { + mbedtls_ssl_set_mtu(&m_env->ssl, c_session->mtu); + } +#endif /* !ESPIDF_VERSION || CONFIG_MBEDTLS_SSL_PROTO_DTLS */ +} + +int coap_dtls_send(coap_session_t *c_session, + const uint8_t *data, + size_t data_len) +{ + int ret; + coap_mbedtls_env_t *m_env = (coap_mbedtls_env_t *)c_session->tls; + char buf[128]; + + assert(m_env != NULL); + + if (!m_env) { + return -1; + } + c_session->dtls_event = -1; + if (m_env->established) { + ret = mbedtls_ssl_write(&m_env->ssl, (const unsigned char*) data, data_len); + if (ret <= 0) { + switch (ret) { + case MBEDTLS_ERR_SSL_WANT_READ: + case MBEDTLS_ERR_SSL_WANT_WRITE: + ret = 0; + break; + case MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE: + c_session->dtls_event = COAP_EVENT_DTLS_CLOSED; + ret = -1; + break; + default: + mbedtls_strerror(ret, buf, sizeof(buf)); + coap_log(LOG_WARNING, + "coap_dtls_send: " + "returned -0x%x: '%s'\n", + -ret, buf); + ret = -1; + break; + } + if (ret == -1) { + coap_log(LOG_WARNING, "coap_dtls_send: cannot send PDU\n"); + } + } + } else { + ret = do_mbedtls_handshake(c_session, m_env); + if (ret == 1) { + /* Just connected, so send the data */ + return coap_dtls_send(c_session, data, data_len); + } + ret = -1; + } + + if (c_session->dtls_event >= 0) { + coap_handle_event(c_session->context, c_session->dtls_event, c_session); + if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR || + c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) { + coap_session_disconnected(c_session, COAP_NACK_TLS_FAILED); + ret = -1; + } + } + return ret; +} + +int coap_dtls_is_context_timeout(void) +{ + return 0; +} + +coap_tick_t coap_dtls_get_context_timeout(void *dtls_context UNUSED) +{ + return 0; +} + +coap_tick_t coap_dtls_get_timeout(coap_session_t *c_session, coap_tick_t now) +{ + coap_mbedtls_env_t *m_env = (coap_mbedtls_env_t *)c_session->tls; + int ret = mbedtls_timing_get_delay(&m_env->timer); + + switch (ret) { + case 0: + case 1: + /* int_ms has timed out, but not fin_ms */ + return now + 1; + case 2: + /* fin_ms has timed out - time for a retry */ + return now; + default: + break; + } + + return 0; +} + +void coap_dtls_handle_timeout(coap_session_t *c_session) +{ + coap_mbedtls_env_t *m_env = (coap_mbedtls_env_t *)c_session->tls; + + assert(m_env != NULL); + if (((c_session->state == COAP_SESSION_STATE_HANDSHAKE) && + (++c_session->dtls_timeout_count > c_session->max_retransmit)) || + (do_mbedtls_handshake(c_session, m_env) < 0)) { + /* Too many retries */ + coap_session_disconnected(c_session, COAP_NACK_TLS_FAILED); + } + return; +} + +int coap_dtls_receive(coap_session_t *c_session, + const uint8_t *data, + size_t data_len) +{ + int ret = 1; + + c_session->dtls_event = -1; + coap_mbedtls_env_t *m_env = (coap_mbedtls_env_t *)c_session->tls; + assert(m_env != NULL); + + coap_ssl_t *ssl_data = &m_env->coap_ssl_data; + if (ssl_data->pdu_len) { + coap_log(LOG_INFO, "** %s: Previous data not read %u bytes\n", + coap_session_str(c_session), ssl_data->pdu_len); + } + ssl_data->pdu = data; + ssl_data->pdu_len = (unsigned)data_len; + + if (m_env->established) { +#if COAP_CONSTRAINED_STACK + static coap_mutex_t b_static_mutex = COAP_MUTEX_INITIALIZER; + static uint8_t pdu[COAP_RXBUFFER_SIZE]; +#else /* ! COAP_CONSTRAINED_STACK */ + uint8_t pdu[COAP_RXBUFFER_SIZE]; +#endif /* ! COAP_CONSTRAINED_STACK */ + +#if COAP_CONSTRAINED_STACK + coap_mutex_lock(&b_static_mutex); +#endif /* COAP_CONSTRAINED_STACK */ + + if (c_session->state == COAP_SESSION_STATE_HANDSHAKE) { + coap_handle_event(c_session->context, COAP_EVENT_DTLS_CONNECTED, + c_session); + coap_session_connected(c_session); + } + + ret = mbedtls_ssl_read(&m_env->ssl, pdu, (int)sizeof(pdu)); + if (ret > 0) { + ret = coap_handle_dgram(c_session->context, c_session, pdu, (size_t)ret); +#if COAP_CONSTRAINED_STACK + coap_mutex_unlock(&b_static_mutex); +#endif /* COAP_CONSTRAINED_STACK */ + return ret; + } + else if (ret == 0 || ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { + c_session->dtls_event = COAP_EVENT_DTLS_CLOSED; + } + else if (ret != MBEDTLS_ERR_SSL_WANT_READ) { + char buf[128]; + + mbedtls_strerror(ret, buf, sizeof(buf)); + coap_log(LOG_WARNING, + "coap_dtls_receive: " + "returned -0x%x: '%s' (length %zd)\n", + -ret, buf, data_len); + } +#if COAP_CONSTRAINED_STACK + coap_mutex_unlock(&b_static_mutex); +#endif /* COAP_CONSTRAINED_STACK */ + ret = -1; + } + else { + ret = do_mbedtls_handshake(c_session, m_env); + if (ret == 1) { + /* Just connected, so send the data */ + coap_session_connected(c_session); + } else { + if (ssl_data->pdu_len) { + /* Do the handshake again incase of internal timeout */ + ret = do_mbedtls_handshake(c_session, m_env); + if (ret == 1) { + /* Just connected, so send the data */ + coap_session_connected(c_session); + } else { + ret = -1; + } + } + ret = -1; + } + } + if (c_session->dtls_event >= 0) { + coap_handle_event(c_session->context, c_session->dtls_event, c_session); + if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR || + c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) { + coap_session_disconnected(c_session, COAP_NACK_TLS_FAILED); + ret = -1; + } + } + return ret; +} + +int coap_dtls_hello(coap_session_t *c_session, + const uint8_t *data, + size_t data_len) +{ +#if defined(ESPIDF_VERSION) && !defined(CONFIG_MBEDTLS_SSL_PROTO_DTLS) + (void)c_session; + (void)data; + (void)data_len; + return -1; +#else /* !ESPIDF_VERSION) || CONFIG_MBEDTLS_SSL_PROTO_DTLS */ + coap_mbedtls_env_t *m_env = (coap_mbedtls_env_t *)c_session->tls; + coap_ssl_t *ssl_data = m_env ? &m_env->coap_ssl_data : NULL; + int ret; + + if (m_env) { + char *str = get_ip_addr(&c_session->remote_addr); + if (!str) { + return -1; + } + if((ret = mbedtls_ssl_set_client_transport_id(&m_env->ssl, + (unsigned char *)str, strlen(str))) != 0) { + coap_log(LOG_ERR, + "mbedtls_ssl_set_client_transport_id() returned -0x%x\n\n", + -ret); + free(str); + return -1; + } + free(str); + } + + if (!m_env) { + m_env = coap_dtls_new_mbedtls_env(c_session, COAP_DTLS_ROLE_SERVER); + if (m_env) { + c_session->tls = m_env; + ssl_data = &m_env->coap_ssl_data; + ssl_data->pdu = data; + ssl_data->pdu_len = (unsigned)data_len; + char *str = get_ip_addr(&c_session->remote_addr); + if (!str) { + return -1; + } + if((ret = mbedtls_ssl_set_client_transport_id(&m_env->ssl, + (unsigned char *)str, strlen(str)) ) != 0) { + coap_log(LOG_ERR, + "mbedtls_ssl_set_client_transport_id() returned -0x%x\n", + -ret); + free(str); + return -1; + } + ret = do_mbedtls_handshake(c_session, m_env); + if (ret == 0 || m_env->seen_client_hello) { + m_env->seen_client_hello = 0; + free(str); + return 1; + } + free(str); + } + return 0; + } + + ssl_data->pdu = data; + ssl_data->pdu_len = (unsigned)data_len; + ret = do_mbedtls_handshake(c_session, m_env); + if (ret == 0 || m_env->seen_client_hello) { + /* The test for seen_client_hello gives the ability to setup a new + c_session to continue the do_mbedtls_handshake past the client hello + and safely allow updating of the m_env and separately + letting a new session cleanly start up. + */ + m_env->seen_client_hello = 0; + return 1; + } + return 0; +#endif /* !ESPIDF_VERSION || CONFIG_MBEDTLS_SSL_PROTO_DTLS */ +} + +unsigned int coap_dtls_get_overhead(coap_session_t *c_session UNUSED) +{ + return 13 + 8 + 8; +} + +void *coap_tls_new_client_session(coap_session_t *c_session UNUSED, int *connected UNUSED) +{ + return NULL; +} + +void *coap_tls_new_server_session(coap_session_t *c_session UNUSED, int *connected UNUSED) +{ + return NULL; +} + +void coap_tls_free_session( coap_session_t *c_session UNUSED) +{ + return; +} + +ssize_t coap_tls_write(coap_session_t *c_session UNUSED, + const uint8_t *data UNUSED, + size_t data_len UNUSED + ) +{ + return 0; +} + +ssize_t coap_tls_read(coap_session_t *c_session UNUSED, + uint8_t *data UNUSED, + size_t data_len UNUSED + ) +{ + return 0; +} + +void coap_dtls_startup(void) +{ + return; +} + +static int keep_log_level = 0; + +void coap_dtls_set_log_level(int level) +{ +#if !defined(ESPIDF_VERSION) + int use_level; + /* + * MbedTLS debug levels filter + * 0 No debug + * 1 Error + * 2 State change + * 3 Informational + * 4 Verbose + */ + + if (level <= LOG_ERR) { + use_level = 1; + } + else { + use_level = (level >= LOG_DEBUG) ? level - LOG_DEBUG + 2 : 0; + } + mbedtls_debug_set_threshold(use_level); +#endif /* !ESPIDF_VERSION) */ + keep_log_level = level; + return; +} + +int coap_dtls_get_log_level(void) +{ + return keep_log_level; +} + +coap_tls_version_t * coap_get_tls_library_version(void) +{ + static coap_tls_version_t version; + version.version = mbedtls_version_get_number(); + version.built_version = MBEDTLS_VERSION_NUMBER; + version.type = COAP_TLS_LIBRARY_MBEDTLS; + return &version; +} + +#else /* !HAVE_MBEDTLS */ + +#ifdef __clang__ +/* Make compilers happy that do not like empty modules. As this function is + * never used, we ignore -Wunused-function at the end of compiling this file + */ +#pragma GCC diagnostic ignored "-Wunused-function" +#endif +static inline void dummy(void) { +} + +#endif /* HAVE_MBEDTLS */ diff --git a/components/coap/port/include/coap/coap_dtls.h b/components/coap/port/include/coap/coap_dtls.h new file mode 100644 index 0000000000..2dd0e88d2e --- /dev/null +++ b/components/coap/port/include/coap/coap_dtls.h @@ -0,0 +1,631 @@ +/* + * coap_dtls.h -- (Datagram) Transport Layer Support for libcoap + * + * Copyright (C) 2016 Olaf Bergmann + * Copyright (C) 2017 Jean-Claude Michelou + * + * This file is part of the CoAP library libcoap. Please see README for terms + * of use. + */ + +#ifndef COAP_DTLS_H_ +#define COAP_DTLS_H_ + +#include "coap_time.h" +#include "str.h" + +struct coap_context_t; +struct coap_session_t; +struct coap_dtls_pki_t; + +/** + * @defgroup dtls DTLS Support + * API functions for interfacing with DTLS libraries. + * @{ + */ + +/** + * Check whether DTLS is available. + * + * @return @c 1 if support for DTLS is enabled, or @c 0 otherwise. + */ +int coap_dtls_is_supported(void); + +/** + * Check whether TLS is available. + * + * @return @c 1 if support for TLS is enabled, or @c 0 otherwise. + */ +int coap_tls_is_supported(void); + +typedef enum coap_tls_library_t { + COAP_TLS_LIBRARY_NOTLS = 0, /**< No DTLS library */ + COAP_TLS_LIBRARY_TINYDTLS, /**< Using TinyDTLS library */ + COAP_TLS_LIBRARY_OPENSSL, /**< Using OpenSSL library */ + COAP_TLS_LIBRARY_GNUTLS, /**< Using GnuTLS library */ + COAP_TLS_LIBRARY_MBEDTLS, /**< Using MbedTLS library */ +} coap_tls_library_t; + +/** + * The structure used for returning the underlying (D)TLS library + * information. + */ +typedef struct coap_tls_version_t { + uint64_t version; /**< (D)TLS runtime Library Version */ + coap_tls_library_t type; /**< Library type. One of COAP_TLS_LIBRARY_* */ + uint64_t built_version; /**< (D)TLS Built against Library Version */ +} coap_tls_version_t; + +/** + * Determine the type and version of the underlying (D)TLS library. + * + * @return The version and type of library libcoap was compiled against. + */ +coap_tls_version_t *coap_get_tls_library_version(void); + +/** + * Additional Security setup handler that can be set up by + * coap_context_set_pki(). + * Invoked when libcoap has done the validation checks at the TLS level, + * but the application needs to do some additional checks/changes/updates. + * + * @param tls_session The security session definition - e.g. SSL * for OpenSSL. + * NULL if server call-back. + * This will be dependent on the underlying TLS library - + * see coap_get_tls_library_version() + * @param setup_data A structure containing setup data originally passed into + * coap_context_set_pki() or coap_new_client_session_pki(). + * + * @return @c 1 if successful, else @c 0. + */ +typedef int (*coap_dtls_security_setup_t)(void* tls_session, + struct coap_dtls_pki_t *setup_data); + +/** + * CN Validation call-back that can be set up by coap_context_set_pki(). + * Invoked when libcoap has done the validation checks at the TLS level, + * but the application needs to check that the CN is allowed. + * CN is the SubjectAltName in the cert, if not present, then the leftmost + * Common Name (CN) component of the subject name. + * + * @param cn The determined CN from the certificate + * @param asn1_public_cert The ASN.1 DER encoded X.509 certificate + * @param asn1_length The ASN.1 length + * @param coap_session The CoAP session associated with the certificate update + * @param depth Depth in cert chain. If 0, then client cert, else a CA + * @param validated TLS layer can find no issues if 1 + * @param arg The same as was passed into coap_context_set_pki() + * in setup_data->cn_call_back_arg + * + * @return @c 1 if accepted, else @c 0 if to be rejected. + */ +typedef int (*coap_dtls_cn_callback_t)(const char *cn, + const uint8_t *asn1_public_cert, + size_t asn1_length, + struct coap_session_t *coap_session, + unsigned depth, + int validated, + void *arg); + +/** + * The enum used for determining the provided PKI ASN.1 (DER) Private Key + * formats. + */ +typedef enum coap_asn1_privatekey_type_t { + COAP_ASN1_PKEY_NONE, /**< NONE */ + COAP_ASN1_PKEY_RSA, /**< RSA type */ + COAP_ASN1_PKEY_RSA2, /**< RSA2 type */ + COAP_ASN1_PKEY_DSA, /**< DSA type */ + COAP_ASN1_PKEY_DSA1, /**< DSA1 type */ + COAP_ASN1_PKEY_DSA2, /**< DSA2 type */ + COAP_ASN1_PKEY_DSA3, /**< DSA3 type */ + COAP_ASN1_PKEY_DSA4, /**< DSA4 type */ + COAP_ASN1_PKEY_DH, /**< DH type */ + COAP_ASN1_PKEY_DHX, /**< DHX type */ + COAP_ASN1_PKEY_EC, /**< EC type */ + COAP_ASN1_PKEY_HMAC, /**< HMAC type */ + COAP_ASN1_PKEY_CMAC, /**< CMAC type */ + COAP_ASN1_PKEY_TLS1_PRF, /**< TLS1_PRF type */ + COAP_ASN1_PKEY_HKDF /**< HKDF type */ +} coap_asn1_privatekey_type_t; + +/** + * The enum used for determining the PKI key formats. + */ +typedef enum coap_pki_key_t { + COAP_PKI_KEY_PEM = 0, /**< The PKI key type is PEM file */ + COAP_PKI_KEY_ASN1, /**< The PKI key type is ASN.1 (DER) */ + COAP_PKI_KEY_PEM_BUF, /**< The PKI key type is PEM buffer */ +} coap_pki_key_t; + +/** + * The structure that holds the PKI PEM definitions. + */ +typedef struct coap_pki_key_pem_t { + const char *ca_file; /**< File location of Common CA in PEM format */ + const char *public_cert; /**< File location of Public Cert in PEM format */ + const char *private_key; /**< File location of Private Key in PEM format */ +} coap_pki_key_pem_t; + +/** + * The structure that holds the PKI PEM buffer definitions. + */ +typedef struct coap_pki_key_pem_buf_t { + const uint8_t *ca_cert; /**< PEM buffer Common CA Cert */ + const uint8_t *public_cert; /**< PEM buffer Public Cert */ + const uint8_t *private_key; /**< PEM buffer Private Key */ + size_t ca_cert_len; /**< PEM buffer CA Cert length */ + size_t public_cert_len; /**< PEM buffer Public Cert length */ + size_t private_key_len; /**< PEM buffer Private Key length */ +} coap_pki_key_pem_buf_t; + +/** + * The structure that holds the PKI ASN.1 (DER) definitions. + */ +typedef struct coap_pki_key_asn1_t { + const uint8_t *ca_cert; /**< ASN1 (DER) Common CA Cert */ + const uint8_t *public_cert; /**< ASN1 (DER) Public Cert */ + const uint8_t *private_key; /**< ASN1 (DER) Private Key */ + size_t ca_cert_len; /**< ASN1 CA Cert length */ + size_t public_cert_len; /**< ASN1 Public Cert length */ + size_t private_key_len; /**< ASN1 Private Key length */ + coap_asn1_privatekey_type_t private_key_type; /**< Private Key Type */ +} coap_pki_key_asn1_t; + +/** + * The structure that holds the PKI key information. + */ +typedef struct coap_dtls_key_t { + coap_pki_key_t key_type; /**< key format type */ + union { + coap_pki_key_pem_t pem; /**< for PEM file keys */ + coap_pki_key_pem_buf_t pem_buf; /**< for PEM memory keys */ + coap_pki_key_asn1_t asn1; /**< for ASN.1 (DER) file keys */ + } key; +} coap_dtls_key_t; + +/** + * Server Name Indication (SNI) Validation call-back that can be set up by + * coap_context_set_pki(). + * Invoked if the SNI is not previously seen and prior to sending a certificate + * set back to the client so that the appropriate certificate set can be used + * based on the requesting SNI. + * + * @param sni The requested SNI + * @param arg The same as was passed into coap_context_set_pki() + * in setup_data->sni_call_back_arg + * + * @return New set of certificates to use, or @c NULL if SNI is to be rejected. + */ +typedef coap_dtls_key_t *(*coap_dtls_sni_callback_t)(const char *sni, + void* arg); + + +#define COAP_DTLS_PKI_SETUP_VERSION 1 /**< Latest PKI setup version */ + +/** + * The structure used for defining the PKI setup data to be used. + */ +typedef struct coap_dtls_pki_t { + uint8_t version; /** Set to 1 to support this version of the struct */ + + /* Options to enable different TLS functionality in libcoap */ + uint8_t verify_peer_cert; /**< 1 if peer cert is to be verified */ + uint8_t require_peer_cert; /**< 1 if peer cert is required */ + uint8_t allow_self_signed; /**< 1 if self signed certs are allowed */ + uint8_t allow_expired_certs; /**< 1 if expired certs are allowed */ + uint8_t cert_chain_validation; /**< 1 if to check cert_chain_verify_depth */ + uint8_t cert_chain_verify_depth; /**< recommended depth is 3 */ + uint8_t check_cert_revocation; /**< 1 if revocation checks wanted */ + uint8_t allow_no_crl; /**< 1 ignore if CRL not there */ + uint8_t allow_expired_crl; /**< 1 if expired crl is allowed */ + uint8_t allow_bad_md_hash; /**< 1 if expired certs are allowed */ + uint8_t allow_short_rsa_length; /**< 1 if expired certs are allowed */ + uint8_t reserved[4]; /**< Reserved - must be set to 0 for + future compatibility */ + /* Size of 4 chosen to align to next + * parameter, so if newly defined option + * it can use one of the reserverd slot so + * no need to change + * COAP_DTLS_PKI_SETUP_VERSION and just + * decrement the reserved[] count. + */ + + /** CN check call-back function. + * If not NULL, is called when the TLS connection has passed the configured + * TLS options above for the application to verify if the CN is valid. + */ + coap_dtls_cn_callback_t validate_cn_call_back; + void *cn_call_back_arg; /**< Passed in to the CN call-back function */ + + /** SNI check call-back function. + * If not @p NULL, called if the SNI is not previously seen and prior to + * sending a certificate set back to the client so that the appropriate + * certificate set can be used based on the requesting SNI. + */ + coap_dtls_sni_callback_t validate_sni_call_back; + void *sni_call_back_arg; /**< Passed in to the sni call-back function */ + + /** Additional Security call-back handler that is invoked when libcoap has + * done the standerd, defined validation checks at the TLS level, + * If not @p NULL, called from within the TLS Client Hello connection + * setup. + */ + coap_dtls_security_setup_t additional_tls_setup_call_back; + + char* client_sni; /**< If not NULL, SNI to use in client TLS setup. + Owned by the client app and must remain valid + during the call to coap_new_client_session_pki() */ + + coap_dtls_key_t pki_key; /**< PKI key definition */ +} coap_dtls_pki_t; + +/** @} */ + +/** + * @defgroup dtls_internal DTLS Support (Internal) + * Internal API functions for interfacing with DTLS libraries. + * @{ + */ + +/** + * Creates a new DTLS context for the given @p coap_context. This function + * returns a pointer to a new DTLS context object or @c NULL on error. + * + * Internal function. + * + * @param coap_context The CoAP context where the DTLS object shall be used. + * + * @return A DTLS context object or @c NULL on error. + */ +void * +coap_dtls_new_context(struct coap_context_t *coap_context); + +typedef enum coap_dtls_role_t { + COAP_DTLS_ROLE_CLIENT, /**< Internal function invoked for client */ + COAP_DTLS_ROLE_SERVER /**< Internal function invoked for server */ +} coap_dtls_role_t; + +/** + * Set the DTLS context's default PSK information. + * This does the PSK specifics following coap_dtls_new_context(). + * If @p COAP_DTLS_ROLE_SERVER, then identity hint will also get set. + * If @p COAP_DTLS_ROLE_SERVER, then the information will get put into the + * TLS library's context (from which sessions are derived). + * If @p COAP_DTLS_ROLE_CLIENT, then the information will get put into the + * TLS library's session. + * + * Internal function. + * + * @param coap_context The CoAP context. + * @param identity_hint The default PSK server identity hint sent to a client. + * Required parameter. If @p NULL, will be set to "". + * Empty string is a valid hint. + * This parameter is ignored if COAP_DTLS_ROLE_CLIENT + * @param role One of @p COAP_DTLS_ROLE_CLIENT or @p COAP_DTLS_ROLE_SERVER + * + * @return @c 1 if successful, else @c 0. + */ + +int +coap_dtls_context_set_psk(struct coap_context_t *coap_context, + const char *identity_hint, + coap_dtls_role_t role); + +/** + * Set the DTLS context's default server PKI information. + * This does the PKI specifics following coap_dtls_new_context(). + * If @p COAP_DTLS_ROLE_SERVER, then the information will get put into the + * TLS library's context (from which sessions are derived). + * If @p COAP_DTLS_ROLE_CLIENT, then the information will get put into the + * TLS library's session. + * + * Internal function. + * + * @param coap_context The CoAP context. + * @param setup_data Setup information defining how PKI is to be setup. + * Required parameter. If @p NULL, PKI will not be + * set up. + * @param role One of @p COAP_DTLS_ROLE_CLIENT or @p COAP_DTLS_ROLE_SERVER + * + * @return @c 1 if successful, else @c 0. + */ + +int +coap_dtls_context_set_pki(struct coap_context_t *coap_context, + coap_dtls_pki_t *setup_data, + coap_dtls_role_t role); + +/** + * Set the dtls context's default Root CA information for a client or server. + * + * Internal function. + * + * @param coap_context The current coap_context_t object. + * @param ca_file If not @p NULL, is the full path name of a PEM encoded + * file containing all the Root CAs to be used. + * @param ca_dir If not @p NULL, points to a directory containing PEM + * encoded files containing all the Root CAs to be used. + * + * @return @c 1 if successful, else @c 0. + */ + +int +coap_dtls_context_set_pki_root_cas(struct coap_context_t *coap_context, + const char *ca_file, + const char *ca_dir); + +/** + * Check whether one of the coap_dtls_context_set_{psk|pki}() functions have + * been called. + * + * Internal function. + * + * @param coap_context The current coap_context_t object. + * + * @return @c 1 if coap_dtls_context_set_{psk|pki}() called, else @c 0. + */ + +int coap_dtls_context_check_keys_enabled(struct coap_context_t *coap_context); + +/** + * Releases the storage allocated for @p dtls_context. + * + * Internal function. + * + * @param dtls_context The DTLS context as returned by coap_dtls_new_context(). + */ +void coap_dtls_free_context(void *dtls_context); + +/** + * Create a new client-side session. This should send a HELLO to the server. + * + * Internal function. + * + * @param coap_session The CoAP session. + * + * @return Opaque handle to underlying TLS library object containing security + * parameters for the session. +*/ +void *coap_dtls_new_client_session(struct coap_session_t *coap_session); + +/** + * Create a new DTLS server-side session. + * Called after coap_dtls_hello() has returned @c 1, signalling that a validated + * HELLO was received from a client. + * This should send a HELLO to the server. + * + * Internal function. + * + * @param coap_session The CoAP session. + * + * @return Opaque handle to underlying TLS library object containing security + * parameters for the DTLS session. + */ +void *coap_dtls_new_server_session(struct coap_session_t *coap_session); + +/** + * Terminates the DTLS session (may send an ALERT if necessary) then frees the + * underlying TLS library object containing security parameters for the session. + * + * Internal function. + * + * @param coap_session The CoAP session. + */ +void coap_dtls_free_session(struct coap_session_t *coap_session); + +/** + * Notify of a change in the CoAP session's MTU, for example after + * a PMTU update. + * + * Internal function. + * + * @param coap_session The CoAP session. + */ +void coap_dtls_session_update_mtu(struct coap_session_t *coap_session); + +/** + * Send data to a DTLS peer. + * + * Internal function. + * + * @param coap_session The CoAP session. + * @param data pointer to data. + * @param data_len Number of bytes to send. + * + * @return @c 0 if this would be blocking, @c -1 if there is an error or the + * number of cleartext bytes sent. + */ +int coap_dtls_send(struct coap_session_t *coap_session, + const uint8_t *data, + size_t data_len); + +/** + * Check if timeout is handled per CoAP session or per CoAP context. + * + * Internal function. + * + * @return @c 1 of timeout and retransmit is per context, @c 0 if it is + * per session. + */ +int coap_dtls_is_context_timeout(void); + +/** + * Do all pending retransmits and get next timeout + * + * Internal function. + * + * @param dtls_context The DTLS context. + * + * @return @c 0 if no event is pending or date of the next retransmit. + */ +coap_tick_t coap_dtls_get_context_timeout(void *dtls_context); + +/** + * Get next timeout for this session. + * + * Internal function. + * + * @param coap_session The CoAP session. + * @param now The current time in ticks. + * + * @return @c 0 If no event is pending or ticks time of the next retransmit. + */ +coap_tick_t coap_dtls_get_timeout(struct coap_session_t *coap_session, + coap_tick_t now); + +/** + * Handle a DTLS timeout expiration. + * + * Internal function. + * + * @param coap_session The CoAP session. + */ +void coap_dtls_handle_timeout(struct coap_session_t *coap_session); + +/** + * Handling incoming data from a DTLS peer. + * + * Internal function. + * + * @param coap_session The CoAP session. + * @param data Encrypted datagram. + * @param data_len Encrypted datagram size. + * + * @return Result of coap_handle_dgram on the decrypted CoAP PDU + * or @c -1 for error. + */ +int coap_dtls_receive(struct coap_session_t *coap_session, + const uint8_t *data, + size_t data_len); + +/** + * Handling client HELLO messages from a new candiate peer. + * Note that session->tls is empty. + * + * Internal function. + * + * @param coap_session The CoAP session. + * @param data Encrypted datagram. + * @param data_len Encrypted datagram size. + * + * @return @c 0 if a cookie verification message has been sent, @c 1 if the + * HELLO contains a valid cookie and a server session should be created, + * @c -1 if the message is invalid. + */ +int coap_dtls_hello(struct coap_session_t *coap_session, + const uint8_t *data, + size_t data_len); + +/** + * Get DTLS overhead over cleartext PDUs. + * + * Internal function. + * + * @param coap_session The CoAP session. + * + * @return Maximum number of bytes added by DTLS layer. + */ +unsigned int coap_dtls_get_overhead(struct coap_session_t *coap_session); + +/** + * Create a new TLS client-side session. + * + * Internal function. + * + * @param coap_session The CoAP session. + * @param connected Updated with whether the connection is connected yet or not. + * @c 0 is not connected, @c 1 is connected. + * + * @return Opaque handle to underlying TLS library object containing security + * parameters for the session. +*/ +void *coap_tls_new_client_session(struct coap_session_t *coap_session, int *connected); + +/** + * Create a TLS new server-side session. + * + * Internal function. + * + * @param coap_session The CoAP session. + * @param connected Updated with whether the connection is connected yet or not. + * @c 0 is not connected, @c 1 is connected. + * + * @return Opaque handle to underlying TLS library object containing security + * parameters for the session. + */ +void *coap_tls_new_server_session(struct coap_session_t *coap_session, int *connected); + +/** + * Terminates the TLS session (may send an ALERT if necessary) then frees the + * underlying TLS library object containing security parameters for the session. + * + * Internal function. + * + * @param coap_session The CoAP session. + */ +void coap_tls_free_session( struct coap_session_t *coap_session ); + +/** + * Send data to a TLS peer, with implicit flush. + * + * Internal function. + * + * @param coap_session The CoAP session. + * @param data Pointer to data. + * @param data_len Number of bytes to send. + * + * @return @c 0 if this should be retried, @c -1 if there is an error + * or the number of cleartext bytes sent. + */ +ssize_t coap_tls_write(struct coap_session_t *coap_session, + const uint8_t *data, + size_t data_len + ); + +/** + * Read some data from a TLS peer. + * + * Internal function. + * + * @param coap_session The CoAP session. + * @param data Pointer to data. + * @param data_len Maximum number of bytes to read. + * + * @return @c 0 if this should be retried, @c -1 if there is an error + * or the number of cleartext bytes read. + */ +ssize_t coap_tls_read(struct coap_session_t *coap_session, + uint8_t *data, + size_t data_len + ); + +/** + * Initialize the underlying (D)TLS Library layer. + * + * Internal function. + * + */ +void coap_dtls_startup(void); + +/** @} */ + +/** + * @ingroup logging + * Sets the (D)TLS logging level to the specified @p level. + * Note: coap_log_level() will influence output if at a specified level. + * + * @param level The logging level to use - LOG_* + */ +void coap_dtls_set_log_level(int level); + +/** + * @ingroup logging + * Get the current (D)TLS logging. + * + * @return The current log level (one of LOG_*). + */ +int coap_dtls_get_log_level(void); + + +#endif /* COAP_DTLS_H */ diff --git a/components/coap/port/include/coap_config_posix.h b/components/coap/port/include/coap_config_posix.h index 8f5a5cfb10..dc1166090d 100644 --- a/components/coap/port/include/coap_config_posix.h +++ b/components/coap/port/include/coap_config_posix.h @@ -21,18 +21,27 @@ #ifdef WITH_POSIX #include +#include #define HAVE_SYS_SOCKET_H #define HAVE_MALLOC #define HAVE_ARPA_INET_H #define HAVE_TIME_H +#define HAVE_NETDB_H +#define HAVE_NETINET_IN_H #define IPV6_PKTINFO IPV6_V6ONLY #define PACKAGE_NAME "libcoap-posix" #define PACKAGE_VERSION "?" -#define COAP_BAD_RECVMSG +#define HAVE_MBEDTLS +#define COAP_CONSTRAINED_STACK 1 +#define ESPIDF_VERSION + +#define _POSIX_TIMERS 1 + +#define gai_strerror(x) "gai_strerror() not supported" #endif /* WITH_POSIX */ #endif /* COAP_CONFIG_POSIX_H_ */ diff --git a/components/mbedtls/CMakeLists.txt b/components/mbedtls/CMakeLists.txt index 5cfac4d9ba..b37269f02b 100644 --- a/components/mbedtls/CMakeLists.txt +++ b/components/mbedtls/CMakeLists.txt @@ -25,6 +25,7 @@ target_sources(mbedtls PRIVATE "${COMPONENT_DIR}/port/esp_bignum.c" "${COMPONENT_DIR}/port/esp_sha1.c" "${COMPONENT_DIR}/port/esp_sha256.c" "${COMPONENT_DIR}/port/esp_sha512.c" + "${COMPONENT_DIR}/port/esp_timing.c" "${COMPONENT_DIR}/port/mbedtls_debug.c" "${COMPONENT_DIR}/port/net_sockets.c" "${COMPONENT_DIR}/port/esp32/aes.c" @@ -36,4 +37,4 @@ foreach(target ${mbedtls_targets}) endforeach() # Link mbedtls libraries to component library -target_link_libraries(${COMPONENT_LIB} INTERFACE ${mbedtls_targets}) \ No newline at end of file +target_link_libraries(${COMPONENT_LIB} INTERFACE ${mbedtls_targets}) diff --git a/components/mbedtls/port/esp_timing.c b/components/mbedtls/port/esp_timing.c new file mode 100644 index 0000000000..93a34f5fa8 --- /dev/null +++ b/components/mbedtls/port/esp_timing.c @@ -0,0 +1,102 @@ +/* + * Portable interface to the CPU cycle counter + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * mbedtls_timing_get_timer()m mbedtls_timing_set_delay() and + * mbedtls_timing_set_delay only abstracted from mbedtls/library/timing.c + * as that does not build on ESP-IDF but these 2 functions are needed for + * DTLS (in particular mbedtls_ssl_set_timer_cb() must be called for DTLS + * which requires these 2 delay functions). + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if !defined(MBEDTLS_ESP_TIMING_C) + +#include +#include "mbedtls/timing.h" + +struct _hr_time +{ + struct timeval start; +}; + +unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) +{ + struct _hr_time *t = (struct _hr_time *) val; + + if( reset ) + { + gettimeofday( &t->start, NULL ); + return( 0 ); + } + else + { + unsigned long delta; + struct timeval now; + gettimeofday( &now, NULL ); + delta = ( now.tv_sec - t->start.tv_sec ) * 1000ul + + ( now.tv_usec - t->start.tv_usec ) / 1000; + return( delta ); + } +} + +/* + * Set delays to watch + */ +void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms ) +{ + mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data; + + ctx->int_ms = int_ms; + ctx->fin_ms = fin_ms; + + if( fin_ms != 0 ) + (void) mbedtls_timing_get_timer( &ctx->timer, 1 ); +} + +/* + * Get number of delays expired + */ +int mbedtls_timing_get_delay( void *data ) +{ + mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data; + unsigned long elapsed_ms; + + if( ctx->fin_ms == 0 ) + return( -1 ); + + elapsed_ms = mbedtls_timing_get_timer( &ctx->timer, 0 ); + + if( elapsed_ms >= ctx->fin_ms ) + return( 2 ); + + if( elapsed_ms >= ctx->int_ms ) + return( 1 ); + + return( 0 ); +} + +#endif /* MBEDTLS_ESP_TIMING_C */ diff --git a/examples/protocols/coap_client/README.md b/examples/protocols/coap_client/README.md index bc3159dbb7..7c317dddda 100644 --- a/examples/protocols/coap_client/README.md +++ b/examples/protocols/coap_client/README.md @@ -2,14 +2,27 @@ # CoAP client example (See the README.md file in the upper level 'examples' directory for more information about examples.) -this CoAP client example is adaptation of one of the [libcoap](https://github.com/obgm/libcoap) example. +This CoAP client example is very simplified adaptation of one of the +[libcoap](https://github.com/obgm/libcoap) examples. -CoAP client example would connect your ESP32 device to any CoAP server, fetch data from CoAP server and upstream data to CoAP server. +CoAP client example will connect your ESP32 device to a CoAP server, send off a GET request and +fetch the response data from CoAP server. The client can be extended to PUT / POST / DELETE requests, +as well as supporting the Observer extensions [RFC7641](https://tools.ietf.org/html/rfc7641). -The Constrained Application Protocol (CoAP) is a specialized web transfer protocol for use with constrained nodes and constrained networks in the Internet of Things. -The protocol is designed for machine-to-machine (M2M) applications such as smart energy and building automation. +If the URI is prefixed with coaps:// instead of coap://, then the CoAP client will attempt to use +the DTLS protocol using the defined Pre-Shared Keys(PSK) or Public Key Infrastructure (PKI) which the +CoAP server needs to know about. -please refer to [RFC7252](https://www.rfc-editor.org/rfc/pdfrfc/rfc7252.txt.pdf) for more details. +If the URI is prefixed with coap+tcp://, then the CoAP will try to use TCP for the communication. + +NOTE: coaps+tcp:// is not currently supported, even though both libcoap and MbedTLS support it. + +The Constrained Application Protocol (CoAP) is a specialized web transfer protocol for use with +constrained nodes and constrained networks in the Internet of Things. +The protocol is designed for machine-to-machine (M2M) applications such as smart energy and +building automation. + +Please refer to [RFC7252](https://www.rfc-editor.org/rfc/pdfrfc/rfc7252.txt.pdf) for more details. ## How to use example @@ -19,16 +32,29 @@ please refer to [RFC7252](https://www.rfc-editor.org/rfc/pdfrfc/rfc7252.txt.pdf) idf.py menuconfig ``` -* Set serial port under Serial Flasher config -* Set Target Uri under Example Configuration -* Set WiFi SSID under Example Configuration -* Set WiFi Password under Example Configuration +Example Connection Configuration ---> + * Set WiFi SSID under Example Configuration + * Set WiFi Password under Example Configuration +Example CoAP Client Configuration ---> + * Set CoAP Target Uri + * Set encryption method definitions (None, PSK or PKI) + * If PSK Set CoAP Preshared Key to use in connection to the server + * If PSK Set CoAP PSK Client identity (username) + Enable CoAP debugging if required +Component config ---> + mbedTLS ---> + [*] Enable mbedtls certificate expiry check + TLS Key Exchange Methods ---> + [*] Enable pre-shared-key ciphersuites + [*] Enable PSK based ciphersuite modes + [*] Support DTLS protocol (all versions) ### Build and Flash Build the project and flash it to the board, then run monitor tool to view serial output: ``` +idf.py build idf.py -p PORT flash monitor ``` @@ -72,9 +98,11 @@ published under EPL+EDL: http://www.eclipse.org/californium/ This can be found at https://libcoap.net/doc/reference/4.2.0/ ## Troubleshooting -* Please make sure Target Url includes valid `host`, optional `port`, optional `path`, and begins -with `coap://` or `coap+tcp://` for a coap server that supports TCP +* Please make sure Target Url includes valid `host`, optional `port`, +optional `path`, and begins with `coap://`, `coaps://` or `coap+tcp://` +for a coap server that supports TCP (not all do including coap+tcp://californium.eclipse.org). -* libcoap logging can be increased by changing `#define COAP_LOGGING_LEVEL 0` -to `#define COAP_LOGGING_LEVEL 9` +* CoAP logging can be enabled by running 'make menuconfig' and enable debugging + +* Encryption (MbedTLS) can be enabled by running 'make menuconfig' and enable debugging diff --git a/examples/protocols/coap_client/main/CMakeLists.txt b/examples/protocols/coap_client/main/CMakeLists.txt index 90a88c9d3b..eb0d270668 100644 --- a/examples/protocols/coap_client/main/CMakeLists.txt +++ b/examples/protocols/coap_client/main/CMakeLists.txt @@ -1,2 +1,4 @@ +# Embed CA, certificate & key directly into binary idf_component_register(SRCS "coap_client_example_main.c" - INCLUDE_DIRS ".") \ No newline at end of file + INCLUDE_DIRS "." + EMBED_TXTFILES coap_ca.pem coap_client.crt coap_client.key) diff --git a/examples/protocols/coap_client/main/Kconfig.projbuild b/examples/protocols/coap_client/main/Kconfig.projbuild index 929b8cf4fa..f96ac41e4a 100644 --- a/examples/protocols/coap_client/main/Kconfig.projbuild +++ b/examples/protocols/coap_client/main/Kconfig.projbuild @@ -1,9 +1,96 @@ -menu "Example Configuration" +menu "Example CoAP Client Configuration" config TARGET_DOMAIN_URI string "Target Uri" default "coap://californium.eclipse.org" help - Target uri for the example to use. + Target uri for the example to use. Use coaps:// prefix for encrypted traffic + using Pre-Shared Key (PSK) or Public Key Infrastructure (PKI). + + choice MBEDTLS_COAP_ENCRYPTION_MODE + prompt "CoAP Encryption method" + default MBEDTLS_COAP_PKI_NONE + help + If the CoAP information is to be encrypted, the encryption environment + can be set up in one of three ways + + - None defined (will use PKI if coaps:// used) + - Encrypt using defined Pre-Shared Keys (PSK) + - Encrypt using defined Public Key Infrastructure (PKI) + + config MBEDTLS_COAP_NONE + bool "None defined" + + config MBEDTLS_COAP_PSK + bool "Pre-Shared Keys" + + config MBEDTLS_COAP_PKI + bool "PKI Certificates" + + endchoice #MBEDTLS_COAP_ENCRYPTION_MODE + + config COAP_PSK_KEY + string "Preshared Key (PSK) to used in the connection to the CoAP server" + depends on MBEDTLS_COAP_PSK + default "secret-key" + help + The Preshared Key to use to encrypt the communicatons. The same key must be + used at both ends of the CoAP connection, and the CoaP client must request + an URI prefixed with coaps:// instead of coap:// for DTLS to be used. + + config COAP_PSK_IDENTITY + string "PSK Client identity (username)" + depends on MBEDTLS_COAP_PSK + default "coap-client" + help + The identity (or username) to use to identify to the CoAP server which + PSK key to use. + + config MBEDTLS_COAP_DEBUG + bool "Enable CoAP debugging" + default n + help + Enable CoAP debugging functions at compile time for the example code. + + If this option is enabled, call coap_set_log_level() + at runtime in order to enable CoAP debug output via the ESP + log mechanism. + + choice MBEDTLS_COAP_DEBUG_LEVEL + bool "Set CoAP debugging level" + depends on MBEDTLS_COAP_DEBUG + default COAP_LOG_WARNING + help + Set CoAP debugging level + + config COAP_LOG_EMERG + bool "Emergency" + config COAP_LOG_ALERT + bool "Alert" + config COAP_LOG_CRIT + bool "Critical" + config COAP_LOG_ERROR + bool "Error" + config COAP_LOG_WARNING + bool "Warning" + config COAP_LOG_NOTICE + bool "Notice" + config COAP_LOG_INFO + bool "Info" + config COAP_LOG_DEBUG + bool "Debug" + endchoice + + config COAP_LOG_DEFAULT_LEVEL + int + default 0 if !MBEDTLS_COAP_DEBUG + default 0 if COAP_LOG_EMERG + default 1 if COAP_LOG_ALERT + default 2 if COAP_LOG_CRIT + default 3 if COAP_LOG_ERROR + default 4 if COAP_LOG_WARNING + default 5 if COAP_LOG_NOTICE + default 6 if COAP_LOG_INFO + default 7 if COAP_LOG_DEBUG endmenu diff --git a/examples/protocols/coap_client/main/coap_ca.pem b/examples/protocols/coap_client/main/coap_ca.pem new file mode 100644 index 0000000000..1bdf23d94b --- /dev/null +++ b/examples/protocols/coap_client/main/coap_ca.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID3DCCA0WgAwIBAgIJAMnlgL1czsmjMA0GCSqGSIb3DQEBCwUAMIGTMQswCQYD +VQQGEwJGUjEPMA0GA1UECAwGUmFkaXVzMRIwEAYDVQQHDAlTb21ld2hlcmUxFTAT +BgNVBAoMDEV4YW1wbGUgSW5jLjEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBs +ZS5jb20xJjAkBgNVBAMMHUV4YW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4X +DTE3MDYwNzA4MDY0OVoXDTI3MDYwNTA4MDY0OVowgZMxCzAJBgNVBAYTAkZSMQ8w +DQYDVQQIDAZSYWRpdXMxEjAQBgNVBAcMCVNvbWV3aGVyZTEVMBMGA1UECgwMRXhh +bXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLmNvbTEmMCQG +A1UEAwwdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwgZ8wDQYJKoZIhvcN +AQEBBQADgY0AMIGJAoGBALpWR23fn/TmHxsXsHdrydzPSd17fZkc71WsaicgQR66 +1tIVYb22UWGfj9KPM8THMsV74ew4ZkaQ39qvU0iuQIRrKARFHFok+vbaecgWMeWe +vGIqdnmyB9gJYaFOKgtSkfXsu2ddsqdvLYwcDbczrq8X9yEXpN6mnxXeCcPG4F0p +AgMBAAGjggE0MIIBMDAdBgNVHQ4EFgQUgigpdAUpONoDq0pQ3yfxrslCSpcwgcgG +A1UdIwSBwDCBvYAUgigpdAUpONoDq0pQ3yfxrslCSpehgZmkgZYwgZMxCzAJBgNV +BAYTAkZSMQ8wDQYDVQQIDAZSYWRpdXMxEjAQBgNVBAcMCVNvbWV3aGVyZTEVMBMG +A1UECgwMRXhhbXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxl +LmNvbTEmMCQGA1UEAwwdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCCQDJ +5YC9XM7JozAMBgNVHRMEBTADAQH/MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly93 +d3cuZXhhbXBsZS5jb20vZXhhbXBsZV9jYS5jcmwwDQYJKoZIhvcNAQELBQADgYEA +euxOBPInSJRKAIseMxPmAabtAqKNslZSmpG4He3lkKt+HM3jfznUt3psmD7j1hFW +S4l7KXzzajvaGYybDq5N9MqrDjhGn3VXZqOLMUNDL7OQq96TzgqsTBT1dmVSbNlt +PQgiAeKAk3tmH4lRRi9MTBSyJ6I92JYcS5H6Bs4ZwCc= +-----END CERTIFICATE----- diff --git a/examples/protocols/coap_client/main/coap_client.crt b/examples/protocols/coap_client/main/coap_client.crt new file mode 100644 index 0000000000..0e03a1b79b --- /dev/null +++ b/examples/protocols/coap_client/main/coap_client.crt @@ -0,0 +1,70 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 48 (0x30) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=FR, ST=Radius, L=Somewhere, O=Example Inc./emailAddress=admin@example.com, CN=Example Certificate Authority + Validity + Not Before: Jun 7 08:06:49 2017 GMT + Not After : Jun 5 08:06:49 2027 GMT + Subject: C=FR, ST=Radius, O=Example Inc., CN=user@example.com/emailAddress=user@example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:d2:f6:be:72:a5:ab:2e:56:0c:dd:f2:3b:2c:7c: + e0:5d:05:40:af:0c:8c:f3:82:0c:d0:18:34:b4:e3: + 7d:5f:8d:0a:3e:aa:79:02:f9:96:ad:10:00:ec:51: + e9:dc:3f:fb:ea:b0:57:eb:48:c7:ca:ef:e8:05:ab: + ee:3f:66:ba:5c:9e:7f:40:85:9f:25:a0:e0:e3:7c: + cf:b6:e6:31:f5:fd:24:03:c8:f4:fb:d8:a4:f3:92: + 29:05:aa:55:43:80:f7:3e:13:10:43:3a:89:24:be: + d8:01:86:d1:69:73:44:7d:f8:b9:46:2b:6b:51:d0: + 11:31:4b:06:ae:9f:45:fa:12:17:0c:ef:6a:fa:d0: + f7:36:46:eb:2e:db:4e:20:46:01:33:ac:b1:f7:4a: + e6:18:3d:53:22:dc:e8:4a:12:78:11:2f:e4:3b:92: + bd:d7:07:5a:c9:81:5d:48:58:c8:0f:9b:e9:a4:0f: + bb:89:b1:ad:38:07:6f:93:d0:a6:12:56:f9:07:48: + d2:23:2f:a3:a9:93:b0:11:0a:27:4c:48:0a:8d:70: + 41:68:76:7a:dd:bc:54:c3:42:33:b0:7b:f6:ae:1f: + e7:95:5e:11:ca:f2:b4:4b:5c:ba:47:64:f0:f3:d7: + 87:95:7f:93:06:a1:72:c9:81:12:a5:b7:8f:9d:7e: + d1:ef + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Extended Key Usage: + TLS Web Client Authentication + X509v3 CRL Distribution Points: + + Full Name: + URI:http://www.example.com/example_ca.crl + + Signature Algorithm: sha1WithRSAEncryption + 2d:02:bc:7b:88:b8:5c:e1:07:b8:bb:ba:b2:f3:98:14:8f:cb: + b0:21:13:b5:e5:6f:05:4f:92:fa:ac:c0:53:a7:b0:cd:7e:ba: + 87:36:85:25:d7:41:c5:29:84:22:74:af:bf:3e:34:36:d5:24: + 7a:81:e2:1b:54:52:85:6f:76:de:dc:63:98:45:fc:2c:31:fa: + 22:a4:72:3a:8d:d4:6a:2e:de:33:10:41:eb:94:1d:e3:59:cd: + b2:be:ab:f0:b6:20:86:9c:b8:46:ee:c5:64:ba:b6:6c:cc:53: + 44:7a:80:12:77:7c:e7:51:67:91:32:2f:88:9d:93:a8:ef:d6: + cd:de +-----BEGIN CERTIFICATE----- +MIIDTjCCAregAwIBAgIBMDANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UEBhMCRlIx +DzANBgNVBAgMBlJhZGl1czESMBAGA1UEBwwJU29tZXdoZXJlMRUwEwYDVQQKDAxF +eGFtcGxlIEluYy4xIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUuY29tMSYw +JAYDVQQDDB1FeGFtcGxlIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNzA2MDcw +ODA2NDlaFw0yNzA2MDUwODA2NDlaMHExCzAJBgNVBAYTAkZSMQ8wDQYDVQQIDAZS +YWRpdXMxFTATBgNVBAoMDEV4YW1wbGUgSW5jLjEZMBcGA1UEAwwQdXNlckBleGFt +cGxlLmNvbTEfMB0GCSqGSIb3DQEJARYQdXNlckBleGFtcGxlLmNvbTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBANL2vnKlqy5WDN3yOyx84F0FQK8MjPOC +DNAYNLTjfV+NCj6qeQL5lq0QAOxR6dw/++qwV+tIx8rv6AWr7j9mulyef0CFnyWg +4ON8z7bmMfX9JAPI9PvYpPOSKQWqVUOA9z4TEEM6iSS+2AGG0WlzRH34uUYra1HQ +ETFLBq6fRfoSFwzvavrQ9zZG6y7bTiBGATOssfdK5hg9UyLc6EoSeBEv5DuSvdcH +WsmBXUhYyA+b6aQPu4mxrTgHb5PQphJW+QdI0iMvo6mTsBEKJ0xICo1wQWh2et28 +VMNCM7B79q4f55VeEcrytEtcukdk8PPXh5V/kwahcsmBEqW3j51+0e8CAwEAAaNP +ME0wEwYDVR0lBAwwCgYIKwYBBQUHAwIwNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDov +L3d3dy5leGFtcGxlLmNvbS9leGFtcGxlX2NhLmNybDANBgkqhkiG9w0BAQUFAAOB +gQAtArx7iLhc4Qe4u7qy85gUj8uwIRO15W8FT5L6rMBTp7DNfrqHNoUl10HFKYQi +dK+/PjQ21SR6geIbVFKFb3be3GOYRfwsMfoipHI6jdRqLt4zEEHrlB3jWc2yvqvw +tiCGnLhG7sVkurZszFNEeoASd3znUWeRMi+InZOo79bN3g== +-----END CERTIFICATE----- diff --git a/examples/protocols/coap_client/main/coap_client.key b/examples/protocols/coap_client/main/coap_client.key new file mode 100644 index 0000000000..99936e25b7 --- /dev/null +++ b/examples/protocols/coap_client/main/coap_client.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA0va+cqWrLlYM3fI7LHzgXQVArwyM84IM0Bg0tON9X40KPqp5 +AvmWrRAA7FHp3D/76rBX60jHyu/oBavuP2a6XJ5/QIWfJaDg43zPtuYx9f0kA8j0 ++9ik85IpBapVQ4D3PhMQQzqJJL7YAYbRaXNEffi5RitrUdARMUsGrp9F+hIXDO9q ++tD3NkbrLttOIEYBM6yx90rmGD1TItzoShJ4ES/kO5K91wdayYFdSFjID5vppA+7 +ibGtOAdvk9CmElb5B0jSIy+jqZOwEQonTEgKjXBBaHZ63bxUw0IzsHv2rh/nlV4R +yvK0S1y6R2Tw89eHlX+TBqFyyYESpbePnX7R7wIDAQABAoIBAQC5PncO3tBIeMEF +pu007FZq9/DLhP7D2B9+HrMxX0y4uXUUf8aQyS74ukPFP0xV3U1M0BnzfU4KscyQ +Jl+nBoKAT6C3vF15wiGXQAJ4vPuD4Ate03fjKWH2ixJAakhCZR01QbIXBnBkdrvf +401BBjlPUDcIGZo8FbLzEMlGTo84vE9v3Qmkbi+PzPCh2YC+NDmsOcIW1zpmwyYC +ZYCpoWgl4++kqXXn0NGhuaOgB0JLsJOBpx/hOOjBU/wXCKaXZ1vchYqfbvvx2gf2 +WX4P0CiTH1z7MEAHanaZkcnNyxV/oF1EIMY5p0vDDzgrKtppvPOqspjydje03+CE +t0wKGPi5AoGBAPAG2Y4efgwLcoWdPjKZtsHLhDhLJnvxkqnNkzdPnLZojNi8pKkV +/Yu++pPemJZZa4YAp+OnqyEfhcha+HYqKMwRC8t3YrEVOlRQTfW/OoSrp059JIRV +jTvq/u7DdYGJRRgMLUJiEI+7xj1WbTc2EceJAgn0qfKvbvBtVJP0LH1TAoGBAOEA +xZB7SwyX+zDGRTugqMYg+sYobbQHJ7utLyoX+ckeG+sPEjEYLpQQfshET/gwF8ZK +4aILkACx/tna799xCjQdmyyc338NO9WULlY1xF+65WfeaxrtTAsqVikX3p19McRI +ijX8k7Msy3gYWJXev3MCtPT2+g68IgbL/W2wY+l1AoGAT7xGy0Jv5vpqid5pig+s +OYatHrJAT445hXUIQaiNy77Bg0JvhMgMWT8RKMwabl+4K2TOYP8TB0bcf2lQ/pgU +w22qOGYpf+AoZ1fh/hAPlYEcbCOAXQG6kDwJgjGmOGjsbgelhVbkX4smWLv8PgoV +L+7goYQIbNlAhlgbb6b+nIcCgYBB7Zr2Cdpkt0en9ACnRx0M6O7yDziNzqbqzAUM +3XeYYZUmnATlk8NaKTcs8S9JdrYQqTJR6/dm7MDTDt7IZvPpb19fhBvMu5DztPaa +1ihTMI01kStq+WsVvnL+mXrmRJ/HdsXgqcCReKep6eBTEbChP4LMYG3G0YNa4HzC +njO4XQKBgQDRnbqqg2CNTnS94BN2D3uzzELtwsIG6aVCtl09ZsLnGaBKVVDtP6BI +j2hGD7xw4g5JeSPIJU5J03nALTY3hz1JyI7AJCX7+JRtUTX2A8C4mlbeul7ilGaU +A7MFT8GqhjYYa84GzNcA1mK8ynlixpL8+yzTT/8lWInWRBa69SkktA== +-----END RSA PRIVATE KEY----- diff --git a/examples/protocols/coap_client/main/coap_client_example_main.c b/examples/protocols/coap_client/main/coap_client_example_main.c index 921541aef2..067364a736 100644 --- a/examples/protocols/coap_client/main/coap_client_example_main.c +++ b/examples/protocols/coap_client/main/coap_client_example_main.c @@ -7,6 +7,13 @@ CONDITIONS OF ANY KIND, either express or implied. */ +/* + * WARNING + * libcoap is not multi-thread safe, so only this thread must make any coap_*() + * calls. Any external (to this thread) data transmitted in/out via libcoap + * therefore has to be passed in/out by xQueue*() via this thread. + */ + #include #include #include @@ -23,12 +30,36 @@ #include "protocol_examples_common.h" +#if 1 +/* Needed until coap_dtls.h becomes a part of libcoap proper */ +#include "libcoap.h" +#include "coap_dtls.h" +#endif #include "coap.h" #define COAP_DEFAULT_TIME_SEC 5 -/* Set this to 9 to get verbose logging from within libcoap */ -#define COAP_LOGGING_LEVEL 0 +/* The examples use simple Pre-Shared-Key configuration that you can set via + 'make menuconfig'. + + If you'd rather not, just change the below entries to strings with + the config you want - ie #define EXAMPLE_COAP_PSK_KEY "some-agreed-preshared-key" + + Note: PSK will only be used if the URI is prefixed with coaps:// + instead of coap:// and the PSK must be one that the server supports + (potentially associated with the IDENTITY) +*/ +#define EXAMPLE_COAP_PSK_KEY CONFIG_COAP_PSK_KEY +#define EXAMPLE_COAP_PSK_IDENTITY CONFIG_COAP_PSK_IDENTITY + +/* The examples use uri Logging Level that + you can set via 'make menuconfig'. + + If you'd rather not, just change the below entry to a value + that is between 0 and 7 with + the config you want - ie #define EXAMPLE_COAP_LOG_DEFAULT_LEVEL 7 +*/ +#define EXAMPLE_COAP_LOG_DEFAULT_LEVEL CONFIG_COAP_LOG_DEFAULT_LEVEL /* The examples use uri "coap://californium.eclipse.org" that you can set via the project configuration (idf.py menuconfig) @@ -124,17 +155,44 @@ clean_up: resp_wait = 0; } -static void coap_example_task(void *p) +#ifdef CONFIG_MBEDTLS_COAP_PKI + +#ifdef __GNUC__ +#define UNUSED_PARAM __attribute__ ((unused)) +#else /* not a GCC */ +#define UNUSED_PARAM +#endif /* GCC */ + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +static int +verify_cn_callback(const char *cn, + const uint8_t *asn1_public_cert UNUSED_PARAM, + size_t asn1_length UNUSED_PARAM, + coap_session_t *session UNUSED_PARAM, + unsigned depth, + int validated UNUSED_PARAM, + void *arg UNUSED_PARAM +) { + coap_log(LOG_INFO, "CN '%s' presented by server (%s)\n", + cn, depth ? "CA" : "Certificate"); + return 1; +} +#endif /* CONFIG_MBEDTLS_COAP_PKI */ + +static void coap_example_client(void *p) { struct hostent *hp; - struct ip4_addr *ip4_addr; - coap_address_t dst_addr, src_addr; + coap_address_t dst_addr; static coap_uri_t uri; const char* server_uri = COAP_DEFAULT_DEMO_URI; char* phostname = NULL; - coap_set_log_level(COAP_LOGGING_LEVEL); + coap_set_log_level(EXAMPLE_COAP_LOG_DEFAULT_LEVEL); + while (1) { #define BUFSIZE 40 unsigned char _buf[BUFSIZE]; @@ -153,7 +211,7 @@ static void coap_example_task(void *p) if ((uri.scheme==COAP_URI_SCHEME_COAPS && !coap_dtls_is_supported()) || (uri.scheme==COAP_URI_SCHEME_COAPS_TCP && !coap_tls_is_supported())) { - ESP_LOGE(TAG, "CoAP server uri scheme error"); + ESP_LOGE(TAG, "CoAP server uri scheme is not supported"); break; } @@ -172,19 +230,31 @@ static void coap_example_task(void *p) ESP_LOGE(TAG, "DNS lookup failed"); vTaskDelay(1000 / portTICK_PERIOD_MS); free(phostname); - continue; + goto clean_up; + } + { + char tmpbuf[INET6_ADDRSTRLEN]; + coap_address_init(&dst_addr); + switch (hp->h_addrtype) { + case AF_INET: + dst_addr.addr.sin.sin_family = AF_INET; + dst_addr.addr.sin.sin_port = htons(uri.port); + memcpy(&dst_addr.addr.sin.sin_addr, hp->h_addr, sizeof(dst_addr.addr.sin.sin_addr)); + inet_ntop(AF_INET, &dst_addr.addr.sin.sin_addr, tmpbuf, sizeof(tmpbuf)); + ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", tmpbuf); + break; + case AF_INET6: + dst_addr.addr.sin6.sin6_family = AF_INET6; + dst_addr.addr.sin6.sin6_port = htons(uri.port); + memcpy(&dst_addr.addr.sin6.sin6_addr, hp->h_addr, sizeof(dst_addr.addr.sin6.sin6_addr)); + inet_ntop(AF_INET6, &dst_addr.addr.sin6.sin6_addr, tmpbuf, sizeof(tmpbuf)); + ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", tmpbuf); + break; + default: + ESP_LOGE(TAG, "DNS lookup response failed"); + goto clean_up; + } } - - /* Code to print the resolved IP. - - Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */ - ip4_addr = (struct ip4_addr *)hp->h_addr; - ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", inet_ntoa(*ip4_addr)); - - coap_address_init(&src_addr); - src_addr.addr.sin.sin_family = AF_INET; - src_addr.addr.sin.sin_port = htons(0); - src_addr.addr.sin.sin_addr.s_addr = INADDR_ANY; if (uri.path.length) { buflen = BUFSIZE; @@ -222,15 +292,102 @@ static void coap_example_task(void *p) goto clean_up; } - coap_address_init(&dst_addr); - dst_addr.addr.sin.sin_family = AF_INET; - dst_addr.addr.sin.sin_port = htons(uri.port); - dst_addr.addr.sin.sin_addr.s_addr = ip4_addr->addr; + /* + * Note that if the URI starts with just coap:// (not coaps://) the + * session will still be plain text. + * + * coaps+tcp:// is NOT supported by the libcoap->mbedtls interface + * so COAP_URI_SCHEME_COAPS_TCP will have failed in a test above, + * but the code is left in for completeness. + */ + if (uri.scheme==COAP_URI_SCHEME_COAPS || uri.scheme==COAP_URI_SCHEME_COAPS_TCP) { +#ifdef CONFIG_MBEDTLS_COAP_PSK + session = coap_new_client_session_psk(ctx, NULL, &dst_addr, + uri.scheme==COAP_URI_SCHEME_COAPS ? COAP_PROTO_DTLS : COAP_PROTO_TLS, + EXAMPLE_COAP_PSK_IDENTITY, + (const uint8_t*)EXAMPLE_COAP_PSK_KEY, + sizeof(EXAMPLE_COAP_PSK_KEY)-1); +#endif /* CONFIG_MBEDTLS_COAP_PSK */ - session = coap_new_client_session(ctx, &src_addr, &dst_addr, - uri.scheme==COAP_URI_SCHEME_COAP_TCP ? COAP_PROTO_TCP : - uri.scheme==COAP_URI_SCHEME_COAPS_TCP ? COAP_PROTO_TLS : - uri.scheme==COAP_URI_SCHEME_COAPS ? COAP_PROTO_DTLS : COAP_PROTO_UDP); +#ifdef CONFIG_MBEDTLS_COAP_PKI +/* CA cert, taken from coap_ca.pem + Client cert, taken from coap_client.crt + Client key, taken from coap_client.key + + The PEM, CRT and KEY file are examples taken from the wpa2 enterprise + example. + + To embed it in the app binary, the PEM, CRT and KEY file is named + in the component.mk COMPONENT_EMBED_TXTFILES variable. +*/ +extern uint8_t ca_pem_start[] asm("_binary_coap_ca_pem_start"); +extern uint8_t ca_pem_end[] asm("_binary_coap_ca_pem_end"); +extern uint8_t client_crt_start[] asm("_binary_coap_client_crt_start"); +extern uint8_t client_crt_end[] asm("_binary_coap_client_crt_end"); +extern uint8_t client_key_start[] asm("_binary_coap_client_key_start"); +extern uint8_t client_key_end[] asm("_binary_coap_client_key_end"); + unsigned int ca_pem_bytes = ca_pem_end - ca_pem_start; + unsigned int client_crt_bytes = client_crt_end - client_crt_start; + unsigned int client_key_bytes = client_key_end - client_key_start; + coap_dtls_pki_t dtls_pki; + static char client_sni[256]; + + memset (&dtls_pki, 0, sizeof(dtls_pki)); + dtls_pki.version = COAP_DTLS_PKI_SETUP_VERSION; + if (ca_pem_bytes) { + /* + * Add in additional certificate checking. + * This list of enabled can be tuned for the specific + * requirements - see 'man coap_encryption'. + * + * Note: A list of root ca file can be setup separately using + * coap_context_set_pki_root_cas(), but the below is used to + * define what checking actually takes place. + */ + dtls_pki.verify_peer_cert = 1; + dtls_pki.require_peer_cert = 1; + dtls_pki.allow_self_signed = 1; + dtls_pki.allow_expired_certs = 1; + dtls_pki.cert_chain_validation = 1; + dtls_pki.cert_chain_verify_depth = 2; + dtls_pki.check_cert_revocation = 1; + dtls_pki.allow_no_crl = 1; + dtls_pki.allow_expired_crl = 1; + dtls_pki.allow_bad_md_hash = 1; + dtls_pki.allow_short_rsa_length = 1; + dtls_pki.validate_cn_call_back = verify_cn_callback; + dtls_pki.cn_call_back_arg = NULL; + dtls_pki.validate_sni_call_back = NULL; + dtls_pki.sni_call_back_arg = NULL; + memset(client_sni, 0, sizeof(client_sni)); + if (uri.host.length) + memcpy(client_sni, uri.host.s, min(uri.host.length, sizeof(client_sni))); + else + memcpy(client_sni, "localhost", 9); + dtls_pki.client_sni = client_sni; + } + dtls_pki.pki_key.key_type = COAP_PKI_KEY_PEM_BUF; + dtls_pki.pki_key.key.pem_buf.public_cert = client_crt_start; + dtls_pki.pki_key.key.pem_buf.public_cert_len = client_crt_bytes; + dtls_pki.pki_key.key.pem_buf.private_key = client_key_start; + dtls_pki.pki_key.key.pem_buf.private_key_len = client_key_bytes; + dtls_pki.pki_key.key.pem_buf.ca_cert = ca_pem_start; + dtls_pki.pki_key.key.pem_buf.ca_cert_len = ca_pem_bytes; + + session = coap_new_client_session_pki(ctx, NULL, &dst_addr, + uri.scheme==COAP_URI_SCHEME_COAPS ? COAP_PROTO_DTLS : COAP_PROTO_TLS, + &dtls_pki); +#endif /* CONFIG_MBEDTLS_COAP_PKI */ + +#ifdef CONFIG_MBEDTLS_COAP_NONE + session = coap_new_client_session(ctx, NULL, &dst_addr, + uri.scheme==COAP_URI_SCHEME_COAPS ? COAP_PROTO_DTLS : COAP_PROTO_TLS); +#endif /* CONFIG_MBEDTLS_COAP_NONE */ + } else { + session = coap_new_client_session(ctx, NULL, &dst_addr, + uri.scheme==COAP_URI_SCHEME_COAP_TCP ? COAP_PROTO_TCP : + COAP_PROTO_UDP); + } if (!session) { ESP_LOGE(TAG, "coap_new_client_session() failed"); goto clean_up; @@ -272,7 +429,10 @@ clean_up: if (session) coap_session_release(session); if (ctx) coap_free_context(ctx); coap_cleanup(); - /* Only send the request off once */ + /* + * change the following line to something like sleep(2) + * if you want the request to continually be sent + */ break; } @@ -285,11 +445,19 @@ void app_main(void) tcpip_adapter_init(); ESP_ERROR_CHECK(esp_event_loop_create_default()); +#if 0 +/* See https://github.com/Ebiroll/qemu_esp32 for further information */ +#include "emul_ip.h" + if (is_running_qemu()) { + xTaskCreate(task_lwip_init, "task_lwip_init", 2*4096, NULL, 20, NULL); + } + else +#endif /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. * Read "Establishing Wi-Fi or Ethernet Connection" section in * examples/protocols/README.md for more information about this function. */ ESP_ERROR_CHECK(example_connect()); - xTaskCreate(coap_example_task, "coap", 5 * 1024, NULL, 5, NULL); + xTaskCreate(coap_example_client, "coap", 8 * 1024, NULL, 5, NULL); } diff --git a/examples/protocols/coap_client/main/component.mk b/examples/protocols/coap_client/main/component.mk index 0b9d7585e7..50306ea2f9 100644 --- a/examples/protocols/coap_client/main/component.mk +++ b/examples/protocols/coap_client/main/component.mk @@ -3,3 +3,8 @@ # # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) +# embed files from the "certs" directory as binary data symbols +# in the app +COMPONENT_EMBED_TXTFILES := coap_ca.pem +COMPONENT_EMBED_TXTFILES += coap_client.crt +COMPONENT_EMBED_TXTFILES += coap_client.key diff --git a/examples/protocols/coap_server/README.md b/examples/protocols/coap_server/README.md index cf00279a49..60941855f1 100644 --- a/examples/protocols/coap_server/README.md +++ b/examples/protocols/coap_server/README.md @@ -2,14 +2,26 @@ # CoAP server example (See the README.md file in the upper level 'examples' directory for more information about examples.) -This CoAP server example is adaptation of one of the [libcoap](https://github.com/obgm/libcoap) example. +This CoAP server example is very simplified adaptation of one of the +[libcoap](https://github.com/obgm/libcoap) examples. -CoAP server example would startup a daemon task, receive data from CoAP client and transmit data to CoAP client. +CoAP server example will startup a daemon task, receive requests / data from CoAP client and transmit +data to CoAP client. -The Constrained Application Protocol (CoAP) is a specialized web transfer protocol for use with constrained nodes and constrained networks in the Internet of Things. -The protocol is designed for machine-to-machine (M2M) applications such as smart energy and building automation. +If the incoming request requests the use of DTLS (connecting to port 5684), then the CoAP server will +try to establish a DTLS session using the previously defined Pre-Shared Key (PSK) - which +must be the same as the one that the CoAP client is using, or Public Key Infrastructure (PKI) where +the PKI information must match as requested. -please refer to [RFC7252](https://www.rfc-editor.org/rfc/pdfrfc/rfc7252.txt.pdf) for more details. +NOTE: Client sessions trying to use coaps+tcp:// are not currently supported, even though both +libcoap and MbedTLS support it. + +The Constrained Application Protocol (CoAP) is a specialized web transfer protocol for use with +constrained nodes and constrained networks in the Internet of Things. +The protocol is designed for machine-to-machine (M2M) applications such as smart energy and +building automation. + +Please refer to [RFC7252](https://www.rfc-editor.org/rfc/pdfrfc/rfc7252.txt.pdf) for more details. ## How to use example @@ -19,15 +31,29 @@ please refer to [RFC7252](https://www.rfc-editor.org/rfc/pdfrfc/rfc7252.txt.pdf) idf.py menuconfig ``` -* Set default serial port under Serial Flasher config -* Set WiFi SSID under Example Configuration -* Set WiFi Password under Example Configuration +Example Connection Configuration ---> + * Set WiFi SSID under Example Configuration + * Set WiFi Password under Example Configuration +Example CoAP Client Configuration ---> + * Set CoAP Target Uri + * Set encryption method definitions (None, PSK or PKI) + * If PSK Set CoAP Preshared Key to use in connection to the server + * If PSK Set CoAP PSK Client identity (username) + Enable CoAP debugging if required +Component config ---> + mbedTLS ---> + [*] Enable mbedtls certificate expiry check + TLS Key Exchange Methods ---> + [*] Enable pre-shared-key ciphersuites + [*] Enable PSK based ciphersuite modes + [*] Support DTLS protocol (all versions) ### Build and Flash Build the project and flash it to the board, then run monitor tool to view serial output: ``` +idf.py build idf.py -p PORT flash monitor ``` @@ -54,8 +80,8 @@ I (2622) CoAP_server: Connected to AP ... ``` -if a CoAP client query `/Espressif` resource, CoAP server would return `"no data"` -until a CoAP client does a PUT with some data. +If a CoAP client queries the `/Espressif` resource, CoAP server will return `"Hello World!"` +until a CoAP client does a PUT with different data. ## libcoap Documentation This can be found at https://libcoap.net/doc/reference/4.2.0/ @@ -64,5 +90,7 @@ This can be found at https://libcoap.net/doc/reference/4.2.0/ * Please make sure CoAP client fetchs or puts data under path: `/Espressif` or fetches `/.well-known/core` -* libcoap logging can be increased by changing `#define COAP_LOGGING_LEVEL 0` -to `#define COAP_LOGGING_LEVEL 9` +* CoAP logging can be enabled by running 'make menuconfig' and enable debugging + +* Encryption (MbedTLS) can be enabled by running 'make menuconfig' and enable debugging + diff --git a/examples/protocols/coap_server/main/CMakeLists.txt b/examples/protocols/coap_server/main/CMakeLists.txt index c28a7be75e..d4738f6918 100644 --- a/examples/protocols/coap_server/main/CMakeLists.txt +++ b/examples/protocols/coap_server/main/CMakeLists.txt @@ -1,2 +1,3 @@ idf_component_register(SRCS "coap_server_example_main.c" - INCLUDE_DIRS ".") \ No newline at end of file + INCLUDE_DIRS "." + EMBED_TXTFILES coap_ca.pem coap_server.crt coap_server.key) diff --git a/examples/protocols/coap_server/main/Kconfig.projbuild b/examples/protocols/coap_server/main/Kconfig.projbuild new file mode 100644 index 0000000000..bdf3b12305 --- /dev/null +++ b/examples/protocols/coap_server/main/Kconfig.projbuild @@ -0,0 +1,74 @@ +menu "Example CoAP Server Configuration" + + config MBEDTLS_COAP_PSK + bool "Pre-Shared Keys (PSK)" + default n + help + Use Pre-Shared Keys to encrypt the communications between the + CoAP Server and CoAP Client. Both ends need the same + Pre-Shared Key. + + config COAP_PSK_KEY + string "Preshared Key (PSK) to used in the connection from the CoAP client" + depends on MBEDTLS_COAP_PSK + default "secret-key" + help + The Preshared Key to use to encrypt the communicatons. The same key must be + used at both ends of the CoAP connection, and the CoaP client must request + an URI prefixed with coaps:// instead of coap:// for DTLS to be used. + + config MBEDTLS_COAP_PKI + bool "Public Key Infrastructure (PKI)" + default n + help + Use PKI Certificates and Private Keys to encrypt the communications + between the CoAP Server and CoAP Client. + + config MBEDTLS_COAP_DEBUG + bool "Enable CoAP debugging" + default n + help + Enable CoAP debugging functions at compile time for the example code. + + If this option is enabled, call coap_set_log_level() + at runtime in order to enable CoAP debug output via the ESP + log mechanism. + + choice MBEDTLS_COAP_DEBUG_LEVEL + bool "Set CoAP debugging level" + depends on MBEDTLS_COAP_DEBUG + default COAP_LOG_WARNING + help + Set CoAP debugging level + + config COAP_LOG_EMERG + bool "Emergency" + config COAP_LOG_ALERT + bool "Alert" + config COAP_LOG_CRIT + bool "Critical" + config COAP_LOG_ERROR + bool "Error" + config COAP_LOG_WARNING + bool "Warning" + config COAP_LOG_NOTICE + bool "Notice" + config COAP_LOG_INFO + bool "Info" + config COAP_LOG_DEBUG + bool "Debug" + endchoice + + config COAP_LOG_DEFAULT_LEVEL + int + default 0 if !MBEDTLS_COAP_DEBUG + default 0 if COAP_LOG_EMERG + default 1 if COAP_LOG_ALERT + default 2 if COAP_LOG_CRIT + default 3 if COAP_LOG_ERROR + default 4 if COAP_LOG_WARNING + default 5 if COAP_LOG_NOTICE + default 6 if COAP_LOG_INFO + default 7 if COAP_LOG_DEBUG + +endmenu diff --git a/examples/protocols/coap_server/main/coap_ca.pem b/examples/protocols/coap_server/main/coap_ca.pem new file mode 100644 index 0000000000..1bdf23d94b --- /dev/null +++ b/examples/protocols/coap_server/main/coap_ca.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID3DCCA0WgAwIBAgIJAMnlgL1czsmjMA0GCSqGSIb3DQEBCwUAMIGTMQswCQYD +VQQGEwJGUjEPMA0GA1UECAwGUmFkaXVzMRIwEAYDVQQHDAlTb21ld2hlcmUxFTAT +BgNVBAoMDEV4YW1wbGUgSW5jLjEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBs +ZS5jb20xJjAkBgNVBAMMHUV4YW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4X +DTE3MDYwNzA4MDY0OVoXDTI3MDYwNTA4MDY0OVowgZMxCzAJBgNVBAYTAkZSMQ8w +DQYDVQQIDAZSYWRpdXMxEjAQBgNVBAcMCVNvbWV3aGVyZTEVMBMGA1UECgwMRXhh +bXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLmNvbTEmMCQG +A1UEAwwdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwgZ8wDQYJKoZIhvcN +AQEBBQADgY0AMIGJAoGBALpWR23fn/TmHxsXsHdrydzPSd17fZkc71WsaicgQR66 +1tIVYb22UWGfj9KPM8THMsV74ew4ZkaQ39qvU0iuQIRrKARFHFok+vbaecgWMeWe +vGIqdnmyB9gJYaFOKgtSkfXsu2ddsqdvLYwcDbczrq8X9yEXpN6mnxXeCcPG4F0p +AgMBAAGjggE0MIIBMDAdBgNVHQ4EFgQUgigpdAUpONoDq0pQ3yfxrslCSpcwgcgG +A1UdIwSBwDCBvYAUgigpdAUpONoDq0pQ3yfxrslCSpehgZmkgZYwgZMxCzAJBgNV +BAYTAkZSMQ8wDQYDVQQIDAZSYWRpdXMxEjAQBgNVBAcMCVNvbWV3aGVyZTEVMBMG +A1UECgwMRXhhbXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxl +LmNvbTEmMCQGA1UEAwwdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCCQDJ +5YC9XM7JozAMBgNVHRMEBTADAQH/MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly93 +d3cuZXhhbXBsZS5jb20vZXhhbXBsZV9jYS5jcmwwDQYJKoZIhvcNAQELBQADgYEA +euxOBPInSJRKAIseMxPmAabtAqKNslZSmpG4He3lkKt+HM3jfznUt3psmD7j1hFW +S4l7KXzzajvaGYybDq5N9MqrDjhGn3VXZqOLMUNDL7OQq96TzgqsTBT1dmVSbNlt +PQgiAeKAk3tmH4lRRi9MTBSyJ6I92JYcS5H6Bs4ZwCc= +-----END CERTIFICATE----- diff --git a/examples/protocols/coap_server/main/coap_server.crt b/examples/protocols/coap_server/main/coap_server.crt new file mode 100644 index 0000000000..8f1dfcda6c --- /dev/null +++ b/examples/protocols/coap_server/main/coap_server.crt @@ -0,0 +1,70 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 47 (0x2f) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=FR, ST=Radius, L=Somewhere, O=Example Inc./emailAddress=admin@example.com, CN=Example Certificate Authority + Validity + Not Before: Jun 7 08:06:49 2017 GMT + Not After : Jun 5 08:06:49 2027 GMT + Subject: C=FR, ST=Radius, O=Example Inc., CN=Example Server Certificate/emailAddress=admin@example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c9:d8:e2:e0:75:91:83:87:d8:c8:80:c6:20:4d: + e9:14:24:30:98:33:53:fa:56:0e:ec:9a:43:7f:87: + a9:22:94:26:06:c7:ac:b5:d9:ec:55:06:81:b7:0d: + c9:24:51:49:fa:47:fb:4b:4e:fc:ed:75:8a:e1:28: + 32:bc:c5:e0:4c:45:c4:58:60:15:67:1e:6b:40:19: + 3f:f0:ab:92:61:92:2d:71:10:2e:f2:eb:bc:81:2f: + 5a:3b:74:ca:5f:fd:e0:ee:d1:d9:07:6a:6c:20:c0: + 07:88:b4:8b:0f:ad:1e:c9:4f:7c:11:98:37:89:15: + de:24:b1:11:1a:7c:97:4a:cf:f3:c8:cb:79:9e:9c: + c3:71:da:a6:94:97:f5:95:fd:61:06:44:e2:3f:12: + 43:0b:1d:33:48:91:d2:ce:4f:97:a1:ed:6a:30:c7: + 5d:98:b5:6e:0a:b7:4f:d9:03:ec:80:76:09:b0:40: + a1:a1:af:ab:2a:59:c4:0f:56:22:bc:be:14:be:18: + df:10:7d:5d:22:bf:e5:04:77:7a:75:6b:3e:eb:6d: + 20:a1:a7:60:d4:f1:87:9d:9f:60:b9:d3:db:2c:25: + f4:91:4a:f1:d2:40:e5:a1:10:88:a0:41:5a:98:40: + ca:15:d7:e3:e6:3e:c0:6a:d5:46:b2:b4:90:b4:ae: + 3b:e3 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Extended Key Usage: + TLS Web Server Authentication + X509v3 CRL Distribution Points: + + Full Name: + URI:http://www.example.com/example_ca.crl + + Signature Algorithm: sha1WithRSAEncryption + a4:25:21:51:0b:22:6c:63:8d:a9:c1:4f:04:33:69:79:34:f0: + 36:dd:8f:6a:27:5f:07:a2:1d:ef:8b:f0:96:e6:e7:a3:b8:3b: + 85:5e:3f:26:43:8a:8e:95:58:9c:a6:db:9c:51:bf:ea:53:16: + 3e:c1:a8:11:1a:c6:cf:0e:a1:17:18:64:d2:05:f1:c0:9c:a6: + 2b:16:c4:29:54:03:d2:17:bd:15:74:d6:ad:8a:8f:2d:cc:27: + 3b:88:88:f2:ea:d0:a2:cb:e9:42:57:df:26:9f:8a:a2:02:2f: + 35:b6:19:1d:26:43:44:af:12:4b:bc:b9:84:50:02:fd:1d:fa: + 50:e8 +-----BEGIN CERTIFICATE----- +MIIDWTCCAsKgAwIBAgIBLzANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UEBhMCRlIx +DzANBgNVBAgMBlJhZGl1czESMBAGA1UEBwwJU29tZXdoZXJlMRUwEwYDVQQKDAxF +eGFtcGxlIEluYy4xIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUuY29tMSYw +JAYDVQQDDB1FeGFtcGxlIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNzA2MDcw +ODA2NDlaFw0yNzA2MDUwODA2NDlaMHwxCzAJBgNVBAYTAkZSMQ8wDQYDVQQIDAZS +YWRpdXMxFTATBgNVBAoMDEV4YW1wbGUgSW5jLjEjMCEGA1UEAwwaRXhhbXBsZSBT +ZXJ2ZXIgQ2VydGlmaWNhdGUxIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUu +Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAydji4HWRg4fYyIDG +IE3pFCQwmDNT+lYO7JpDf4epIpQmBsestdnsVQaBtw3JJFFJ+kf7S0787XWK4Sgy +vMXgTEXEWGAVZx5rQBk/8KuSYZItcRAu8uu8gS9aO3TKX/3g7tHZB2psIMAHiLSL +D60eyU98EZg3iRXeJLERGnyXSs/zyMt5npzDcdqmlJf1lf1hBkTiPxJDCx0zSJHS +zk+Xoe1qMMddmLVuCrdP2QPsgHYJsEChoa+rKlnED1YivL4UvhjfEH1dIr/lBHd6 +dWs+620goadg1PGHnZ9gudPbLCX0kUrx0kDloRCIoEFamEDKFdfj5j7AatVGsrSQ +tK474wIDAQABo08wTTATBgNVHSUEDDAKBggrBgEFBQcDATA2BgNVHR8ELzAtMCug +KaAnhiVodHRwOi8vd3d3LmV4YW1wbGUuY29tL2V4YW1wbGVfY2EuY3JsMA0GCSqG +SIb3DQEBBQUAA4GBAKQlIVELImxjjanBTwQzaXk08Dbdj2onXweiHe+L8Jbm56O4 +O4VePyZDio6VWJym25xRv+pTFj7BqBEaxs8OoRcYZNIF8cCcpisWxClUA9IXvRV0 +1q2Kjy3MJzuIiPLq0KLL6UJX3yafiqICLzW2GR0mQ0SvEku8uYRQAv0d+lDo +-----END CERTIFICATE----- diff --git a/examples/protocols/coap_server/main/coap_server.key b/examples/protocols/coap_server/main/coap_server.key new file mode 100644 index 0000000000..9b3433273e --- /dev/null +++ b/examples/protocols/coap_server/main/coap_server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAydji4HWRg4fYyIDGIE3pFCQwmDNT+lYO7JpDf4epIpQmBses +tdnsVQaBtw3JJFFJ+kf7S0787XWK4SgyvMXgTEXEWGAVZx5rQBk/8KuSYZItcRAu +8uu8gS9aO3TKX/3g7tHZB2psIMAHiLSLD60eyU98EZg3iRXeJLERGnyXSs/zyMt5 +npzDcdqmlJf1lf1hBkTiPxJDCx0zSJHSzk+Xoe1qMMddmLVuCrdP2QPsgHYJsECh +oa+rKlnED1YivL4UvhjfEH1dIr/lBHd6dWs+620goadg1PGHnZ9gudPbLCX0kUrx +0kDloRCIoEFamEDKFdfj5j7AatVGsrSQtK474wIDAQABAoIBAQC2kGDEPBJdMSW2 +VCLfXRiPixwYzXQLXIMrJWwfkQg9qlmqkDd6U50aWkRA2UswegW7RhfYSZ0i+cmf +VMhvTVpOIlwwwtcY6b5/v1bBy60eaySGuuh79xQMlFO8qynQIMStvUfbGTqrdIRb +9VBB4YeS9T12fILejtTZwv2BQ2dj1Y1SCay6Ri85UzJqSClRKgHISybvVdLNjPvP +0TRFBr57zyjL6WE8teKiKchzQko2u86No5uBCdKGsrAkrsdcR0YqlM/pZxd3VKNm ++eny0k+dZZlvcPxzkzP4hEp9+Rw5rP9/s3s/cCwvuuC5JO32ATBWKCbTvPv/XPDb +MdSJtOshAoGBAPzk0eswkcbFYtpnpBNmBAr1dtAdW1lfjUI2ucMMwt7Wns0P/tt+ +gq6Hi1wTaGP0l/dIECgeHwjtWj31ZJjQtFJ1y/kafxo4o9cA8vCydpdvSZaldAfg +sbLlDTDYzEpelaDIbNQBBXFoC5U9JlBhBsIFCL5Z8ZuIeFPsb7t5wwuHAoGBAMxT +jyWfNm1uNxp1xgCnrRsLPQPVnURrSFAqcHrECqRu3F7sozTN7q/cZViemxPvVDGQ +p9c+9bHwaYvW4trO5qDHJ++gGwm5L52bMAY1VUfeTt67fqrey43XpdmzcTX1V9Uj +QWawPUCSDzFjL1MjfCIejtyYf5ash53vj+T8r/vFAoGAA/OPVB1uKazr3n3AEo2F +gqZTNO1AgCT+EArK3EFWyiSQVqPpV4SihheYFdg3yVgJB9QYbIgL9BfBUTaEW97m +8mLkzP+c/Mvlw3ZAVYJ0V+llPPVY2saoACOUES9SAdd4fwqiqK1baGo3xB0wfBEI +CgAKIu9E1ylKuAT5ufQtGAECgYEAtP/kU5h5N3El4QupTdU7VDSdZTMqsHw0v8cI +gsf9AXKvRmtrnBA8u46KPHmruHoO5CVXeSZtsaXdaaH+rYQQ6yXg67WxnehtFLlv +TmCaXiLBTS9cYvMf8FOyuGnsBLeEietEOTov2G5KhR5uwsAxa2wUc7endor5S9/2 +YQuyvV0CgYALbiFpILd5l1ip65eE6JdA3hfttUbV2j2NSW12ej69vqbeOfaSgNse +uYCcXFsBbQPhNPwA+4d1oCe8SyXZg1f7gE812z2Tyr/3vdVnNZlitoxhsHmGiyS7 +gZdaTYCb78l9z0EBdaCVvA16owEle4SR6f9eCwzSI0WPOUra+x/hrA== +-----END RSA PRIVATE KEY----- diff --git a/examples/protocols/coap_server/main/coap_server_example_main.c b/examples/protocols/coap_server/main/coap_server_example_main.c index eb5e131baa..b2f78bb032 100644 --- a/examples/protocols/coap_server/main/coap_server_example_main.c +++ b/examples/protocols/coap_server/main/coap_server_example_main.c @@ -7,6 +7,13 @@ CONDITIONS OF ANY KIND, either express or implied. */ +/* + * WARNING + * libcoap is not multi-thread safe, so only this thread must make any coap_*() + * calls. Any external (to this thread) data transmitted in/out via libcoap + * therefore has to be passed in/out by xQueue*() via this thread. + */ + #include #include @@ -22,14 +29,39 @@ #include "protocol_examples_common.h" +#if 1 +/* Needed until coap_dtls.h becomes a part of libcoap proper */ +#include "libcoap.h" +#include "coap_dtls.h" +#endif #include "coap.h" -/* Set this to 9 to get verbose logging from within libcoap */ -#define COAP_LOGGING_LEVEL 0 +/* The examples use simple Pre-Shared-Key configuration that you can set via + 'make menuconfig'. + + If you'd rather not, just change the below entries to strings with + the config you want - ie #define EXAMPLE_COAP_PSK_KEY "some-agreed-preshared-key" + + Note: PSK will only be used if the URI is prefixed with coaps:// + instead of coap:// and the PSK must be one that the server supports + (potentially associated with the IDENTITY) +*/ +#define EXAMPLE_COAP_PSK_KEY CONFIG_COAP_PSK_KEY + +/* The examples use CoAP Logging Level that + you can set via 'make menuconfig'. + + If you'd rather not, just change the below entry to a value + that is between 0 and 7 with + the config you want - ie #define EXAMPLE_COAP_LOG_DEFAULT_LEVEL 7 +*/ +#define EXAMPLE_COAP_LOG_DEFAULT_LEVEL CONFIG_COAP_LOG_DEFAULT_LEVEL static char espressif_data[100]; static int espressif_data_len = 0; +#define INITIAL_DATA "Hello World!" + /* * The resource handler */ @@ -59,7 +91,7 @@ hnd_espressif_put(coap_context_t *ctx, coap_resource_notify_observers(resource, NULL); - if (strcmp (espressif_data, "no data") == 0) { + if (strcmp (espressif_data, INITIAL_DATA) == 0) { response->code = COAP_RESPONSE_CODE(201); } else { @@ -70,7 +102,7 @@ hnd_espressif_put(coap_context_t *ctx, (void)coap_get_data(request, &size, &data); if (size == 0) { /* re-init */ - snprintf(espressif_data, sizeof(espressif_data), "no data"); + snprintf(espressif_data, sizeof(espressif_data), INITIAL_DATA); espressif_data_len = strlen(espressif_data); } else { espressif_data_len = size > sizeof (espressif_data) ? sizeof (espressif_data) : size; @@ -88,23 +120,50 @@ hnd_espressif_delete(coap_context_t *ctx, coap_pdu_t *response) { coap_resource_notify_observers(resource, NULL); - snprintf(espressif_data, sizeof(espressif_data), "no data"); + snprintf(espressif_data, sizeof(espressif_data), INITIAL_DATA); espressif_data_len = strlen(espressif_data); response->code = COAP_RESPONSE_CODE(202); } -static void coap_example_thread(void *p) +#ifdef CONFIG_MBEDTLS_COAP_PKI + +#ifdef __GNUC__ +#define UNUSED_PARAM __attribute__ ((unused)) +#else /* not a GCC */ +#define UNUSED_PARAM +#endif /* GCC */ + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +static int +verify_cn_callback(const char *cn, + const uint8_t *asn1_public_cert UNUSED_PARAM, + size_t asn1_length UNUSED_PARAM, + coap_session_t *session UNUSED_PARAM, + unsigned depth, + int validated UNUSED_PARAM, + void *arg UNUSED_PARAM +) { + coap_log(LOG_INFO, "CN '%s' presented by server (%s)\n", + cn, depth ? "CA" : "Certificate"); + return 1; +} +#endif /* CONFIG_MBEDTLS_COAP_PKI */ + +static void coap_example_server(void *p) { coap_context_t *ctx = NULL; - coap_address_t serv_addr; + coap_address_t serv_addr; coap_resource_t *resource = NULL; - snprintf(espressif_data, sizeof(espressif_data), "no data"); + snprintf(espressif_data, sizeof(espressif_data), INITIAL_DATA); espressif_data_len = strlen(espressif_data); - coap_set_log_level(COAP_LOGGING_LEVEL); + coap_set_log_level(EXAMPLE_COAP_LOG_DEFAULT_LEVEL); + while (1) { - coap_endpoint_t *ep_udp = NULL; - coap_endpoint_t *ep_tcp = NULL; + coap_endpoint_t *ep = NULL; unsigned wait_ms; /* Prepare the CoAP server socket */ @@ -117,14 +176,91 @@ static void coap_example_thread(void *p) if (!ctx) { continue; } - ep_udp = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_UDP); - if (!ep_udp) { +#ifdef CONFIG_MBEDTLS_COAP_PSK + /* Need PSK setup before we set up endpoints */ + coap_context_set_psk(ctx, "CoAP", + (const uint8_t*)EXAMPLE_COAP_PSK_KEY, + sizeof(EXAMPLE_COAP_PSK_KEY)-1); +#endif /* CONFIG_MBEDTLS_COAP_PSK */ + +#ifdef CONFIG_MBEDTLS_COAP_PKI +/* CA cert, taken from coap_ca.pem + Server cert, taken from coap_server.crt + Server key, taken from coap_server.key + + The PEM, CRT and KEY file are examples taken from the wpa2 enterprise + example. + + To embed it in the app binary, the PEM, CRT and KEY file is named + in the component.mk COMPONENT_EMBED_TXTFILES variable. +*/ +extern uint8_t ca_pem_start[] asm("_binary_coap_ca_pem_start"); +extern uint8_t ca_pem_end[] asm("_binary_coap_ca_pem_end"); +extern uint8_t server_crt_start[] asm("_binary_coap_server_crt_start"); +extern uint8_t server_crt_end[] asm("_binary_coap_server_crt_end"); +extern uint8_t server_key_start[] asm("_binary_coap_server_key_start"); +extern uint8_t server_key_end[] asm("_binary_coap_server_key_end"); + unsigned int ca_pem_bytes = ca_pem_end - ca_pem_start; + unsigned int server_crt_bytes = server_crt_end - server_crt_start; + unsigned int server_key_bytes = server_key_end - server_key_start; + coap_dtls_pki_t dtls_pki; + + memset (&dtls_pki, 0, sizeof(dtls_pki)); + dtls_pki.version = COAP_DTLS_PKI_SETUP_VERSION; + if (ca_pem_bytes) { + /* + * Add in additional certificate checking. + * This list of enabled can be tuned for the specific + * requirements - see 'man coap_encryption'. + * + * Note: A list of root ca file can be setup separately using + * coap_context_set_pki_root_cas(), but the below is used to + * define what checking actually takes place. + */ + dtls_pki.verify_peer_cert = 1; + dtls_pki.require_peer_cert = 1; + dtls_pki.allow_self_signed = 1; + dtls_pki.allow_expired_certs = 1; + dtls_pki.cert_chain_validation = 1; + dtls_pki.cert_chain_verify_depth = 2; + dtls_pki.check_cert_revocation = 1; + dtls_pki.allow_no_crl = 1; + dtls_pki.allow_expired_crl = 1; + dtls_pki.allow_bad_md_hash = 1; + dtls_pki.allow_short_rsa_length = 1; + dtls_pki.validate_cn_call_back = verify_cn_callback; + dtls_pki.cn_call_back_arg = NULL; + dtls_pki.validate_sni_call_back = NULL; + dtls_pki.sni_call_back_arg = NULL; + } + dtls_pki.pki_key.key_type = COAP_PKI_KEY_PEM_BUF; + dtls_pki.pki_key.key.pem_buf.public_cert = server_crt_start; + dtls_pki.pki_key.key.pem_buf.public_cert_len = server_crt_bytes; + dtls_pki.pki_key.key.pem_buf.private_key = server_key_start; + dtls_pki.pki_key.key.pem_buf.private_key_len = server_key_bytes; + dtls_pki.pki_key.key.pem_buf.ca_cert = ca_pem_start; + dtls_pki.pki_key.key.pem_buf.ca_cert_len = ca_pem_bytes; + + coap_context_set_pki(ctx, &dtls_pki); +#endif /* CONFIG_MBEDTLS_COAP_PKI */ + + ep = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_UDP); + if (!ep) { goto clean_up; } - ep_tcp = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_TCP); - if (!ep_tcp) { + ep = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_TCP); + if (!ep) { goto clean_up; } +#if defined(CONFIG_MBEDTLS_COAP_PSK) || defined(CONFIG_MBEDTLS_COAP_PKI) + if (coap_dtls_is_supported()) { + serv_addr.addr.sin.sin_port = htons(COAPS_DEFAULT_PORT); + ep = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_DTLS); + if (!ep) { + goto clean_up; + } + } +#endif /* CONFIG_MBEDTLS_COAP_PSK CONFIG_MBEDTLS_COAP_PKI */ resource = coap_resource_init(coap_make_str_const("Espressif"), 0); if (!resource) { goto clean_up; @@ -165,11 +301,19 @@ void app_main(void) tcpip_adapter_init(); ESP_ERROR_CHECK(esp_event_loop_create_default()); +#if 0 +/* See https://github.com/Ebiroll/qemu_esp32 for further information */ +#include "emul_ip.h" + if (is_running_qemu()) { + xTaskCreate(task_lwip_init, "task_lwip_init", 2*4096, NULL, 20, NULL); + } + else +#endif /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. * Read "Establishing Wi-Fi or Ethernet Connection" section in * examples/protocols/README.md for more information about this function. */ ESP_ERROR_CHECK(example_connect()); - xTaskCreate(coap_example_thread, "coap", 1024 * 5, NULL, 5, NULL); + xTaskCreate(coap_example_server, "coap", 8 * 1024, NULL, 5, NULL); } diff --git a/examples/protocols/coap_server/main/component.mk b/examples/protocols/coap_server/main/component.mk index 0b9d7585e7..bccdac23fd 100644 --- a/examples/protocols/coap_server/main/component.mk +++ b/examples/protocols/coap_server/main/component.mk @@ -3,3 +3,8 @@ # # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) +# embed files from the "certs" directory as binary data symbols +# in the app +COMPONENT_EMBED_TXTFILES := coap_ca.pem +COMPONENT_EMBED_TXTFILES += coap_server.crt +COMPONENT_EMBED_TXTFILES += coap_server.key From 852c176a408b18e8f4bf2e5af3adb742af5a5a42 Mon Sep 17 00:00:00 2001 From: Mahavir Jain Date: Wed, 31 Jul 2019 16:21:25 +0530 Subject: [PATCH 415/486] coap: add mbedtls in depedency list for CMake build --- components/coap/CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/components/coap/CMakeLists.txt b/components/coap/CMakeLists.txt index 6d7dbb4517..3b2da20ce8 100644 --- a/components/coap/CMakeLists.txt +++ b/components/coap/CMakeLists.txt @@ -21,11 +21,9 @@ set(srcs "libcoap/src/coap_io.c" "port/coap_mbedtls.c") -set(COMPONENT_REQUIRES lwip) - idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "${include_dirs}" - REQUIRES lwip) + REQUIRES lwip mbedtls) # Silence format truncation warning, until it is fixed upstream set_source_files_properties(port/coap_debug.c PROPERTIES COMPILE_FLAGS -Wno-format-truncation) From 10c3b42f71566831d638b7b63850007fd434a2fa Mon Sep 17 00:00:00 2001 From: Mahavir Jain Date: Wed, 31 Jul 2019 16:22:01 +0530 Subject: [PATCH 416/486] coap: kconfig cleanup, have component specific configuration for common options --- components/coap/Kconfig | 74 +++++++++++++++ .../coap_client/main/Kconfig.projbuild | 89 +++---------------- .../coap_server/main/Kconfig.projbuild | 71 +-------------- 3 files changed, 88 insertions(+), 146 deletions(-) create mode 100644 components/coap/Kconfig diff --git a/components/coap/Kconfig b/components/coap/Kconfig new file mode 100644 index 0000000000..ad00334c18 --- /dev/null +++ b/components/coap/Kconfig @@ -0,0 +1,74 @@ +menu "CoAP Configuration" + + choice COAP_MBEDTLS_ENCRYPTION_MODE + prompt "CoAP Encryption method" + default COAP_MBEDTLS_PSK + help + If the CoAP information is to be encrypted, the encryption environment + can be set up in one of two ways (default being Pre-Shared key mode) + + - Encrypt using defined Pre-Shared Keys (PSK if uri includes coaps://) + - Encrypt using defined Public Key Infrastructure (PKI if uri includes coaps://) + + config COAP_MBEDTLS_PSK + select MBEDTLS_SSL_PROTO_DTLS + select MBEDTLS_PSK_MODES + select MBEDTLS_KEY_EXCHANGE_PSK + bool "Pre-Shared Keys" + + config COAP_MBEDTLS_PKI + select MBEDTLS_SSL_PROTO_DTLS + select MBEDTLS_PSK_MODES + select MBEDTLS_KEY_EXCHANGE_PSK + bool "PKI Certificates" + + endchoice #COAP_MBEDTLS_ENCRYPTION_MODE + + config COAP_MBEDTLS_DEBUG + bool "Enable CoAP debugging" + default n + help + Enable CoAP debugging functions at compile time for the example code. + + If this option is enabled, call coap_set_log_level() + at runtime in order to enable CoAP debug output via the ESP + log mechanism. + + choice COAP_MBEDTLS_DEBUG_LEVEL + bool "Set CoAP debugging level" + depends on COAP_MBEDTLS_DEBUG + default COAP_LOG_WARNING + help + Set CoAP debugging level + + config COAP_LOG_EMERG + bool "Emergency" + config COAP_LOG_ALERT + bool "Alert" + config COAP_LOG_CRIT + bool "Critical" + config COAP_LOG_ERROR + bool "Error" + config COAP_LOG_WARNING + bool "Warning" + config COAP_LOG_NOTICE + bool "Notice" + config COAP_LOG_INFO + bool "Info" + config COAP_LOG_DEBUG + bool "Debug" + endchoice + + config COAP_LOG_DEFAULT_LEVEL + int + default 0 if !COAP_MBEDTLS_DEBUG + default 0 if COAP_LOG_EMERG + default 1 if COAP_LOG_ALERT + default 2 if COAP_LOG_CRIT + default 3 if COAP_LOG_ERROR + default 4 if COAP_LOG_WARNING + default 5 if COAP_LOG_NOTICE + default 6 if COAP_LOG_INFO + default 7 if COAP_LOG_DEBUG + +endmenu diff --git a/examples/protocols/coap_client/main/Kconfig.projbuild b/examples/protocols/coap_client/main/Kconfig.projbuild index f96ac41e4a..33b04a7b86 100644 --- a/examples/protocols/coap_client/main/Kconfig.projbuild +++ b/examples/protocols/coap_client/main/Kconfig.projbuild @@ -1,96 +1,27 @@ menu "Example CoAP Client Configuration" - config TARGET_DOMAIN_URI + config EXAMPLE_TARGET_DOMAIN_URI string "Target Uri" - default "coap://californium.eclipse.org" + default "coaps://californium.eclipse.org" help Target uri for the example to use. Use coaps:// prefix for encrypted traffic using Pre-Shared Key (PSK) or Public Key Infrastructure (PKI). - choice MBEDTLS_COAP_ENCRYPTION_MODE - prompt "CoAP Encryption method" - default MBEDTLS_COAP_PKI_NONE - help - If the CoAP information is to be encrypted, the encryption environment - can be set up in one of three ways - - - None defined (will use PKI if coaps:// used) - - Encrypt using defined Pre-Shared Keys (PSK) - - Encrypt using defined Public Key Infrastructure (PKI) - - config MBEDTLS_COAP_NONE - bool "None defined" - - config MBEDTLS_COAP_PSK - bool "Pre-Shared Keys" - - config MBEDTLS_COAP_PKI - bool "PKI Certificates" - - endchoice #MBEDTLS_COAP_ENCRYPTION_MODE - - config COAP_PSK_KEY + config EXAMPLE_COAP_PSK_KEY string "Preshared Key (PSK) to used in the connection to the CoAP server" - depends on MBEDTLS_COAP_PSK - default "secret-key" + depends on COAP_MBEDTLS_PSK + default "sesame" help - The Preshared Key to use to encrypt the communicatons. The same key must be - used at both ends of the CoAP connection, and the CoaP client must request + The Preshared Key to use to encrypt the communicatons. The same key must be + used at both ends of the CoAP connection, and the CoaP client must request an URI prefixed with coaps:// instead of coap:// for DTLS to be used. - config COAP_PSK_IDENTITY + config EXAMPLE_COAP_PSK_IDENTITY string "PSK Client identity (username)" - depends on MBEDTLS_COAP_PSK - default "coap-client" + depends on COAP_MBEDTLS_PSK + default "password" help The identity (or username) to use to identify to the CoAP server which PSK key to use. - config MBEDTLS_COAP_DEBUG - bool "Enable CoAP debugging" - default n - help - Enable CoAP debugging functions at compile time for the example code. - - If this option is enabled, call coap_set_log_level() - at runtime in order to enable CoAP debug output via the ESP - log mechanism. - - choice MBEDTLS_COAP_DEBUG_LEVEL - bool "Set CoAP debugging level" - depends on MBEDTLS_COAP_DEBUG - default COAP_LOG_WARNING - help - Set CoAP debugging level - - config COAP_LOG_EMERG - bool "Emergency" - config COAP_LOG_ALERT - bool "Alert" - config COAP_LOG_CRIT - bool "Critical" - config COAP_LOG_ERROR - bool "Error" - config COAP_LOG_WARNING - bool "Warning" - config COAP_LOG_NOTICE - bool "Notice" - config COAP_LOG_INFO - bool "Info" - config COAP_LOG_DEBUG - bool "Debug" - endchoice - - config COAP_LOG_DEFAULT_LEVEL - int - default 0 if !MBEDTLS_COAP_DEBUG - default 0 if COAP_LOG_EMERG - default 1 if COAP_LOG_ALERT - default 2 if COAP_LOG_CRIT - default 3 if COAP_LOG_ERROR - default 4 if COAP_LOG_WARNING - default 5 if COAP_LOG_NOTICE - default 6 if COAP_LOG_INFO - default 7 if COAP_LOG_DEBUG - endmenu diff --git a/examples/protocols/coap_server/main/Kconfig.projbuild b/examples/protocols/coap_server/main/Kconfig.projbuild index bdf3b12305..19da8165a6 100644 --- a/examples/protocols/coap_server/main/Kconfig.projbuild +++ b/examples/protocols/coap_server/main/Kconfig.projbuild @@ -1,74 +1,11 @@ menu "Example CoAP Server Configuration" - config MBEDTLS_COAP_PSK - bool "Pre-Shared Keys (PSK)" - default n - help - Use Pre-Shared Keys to encrypt the communications between the - CoAP Server and CoAP Client. Both ends need the same - Pre-Shared Key. - - config COAP_PSK_KEY + config EXAMPLE_COAP_PSK_KEY string "Preshared Key (PSK) to used in the connection from the CoAP client" - depends on MBEDTLS_COAP_PSK + depends on COAP_MBEDTLS_PSK default "secret-key" help - The Preshared Key to use to encrypt the communicatons. The same key must be - used at both ends of the CoAP connection, and the CoaP client must request + The Preshared Key to use to encrypt the communicatons. The same key must be + used at both ends of the CoAP connection, and the CoaP client must request an URI prefixed with coaps:// instead of coap:// for DTLS to be used. - - config MBEDTLS_COAP_PKI - bool "Public Key Infrastructure (PKI)" - default n - help - Use PKI Certificates and Private Keys to encrypt the communications - between the CoAP Server and CoAP Client. - - config MBEDTLS_COAP_DEBUG - bool "Enable CoAP debugging" - default n - help - Enable CoAP debugging functions at compile time for the example code. - - If this option is enabled, call coap_set_log_level() - at runtime in order to enable CoAP debug output via the ESP - log mechanism. - - choice MBEDTLS_COAP_DEBUG_LEVEL - bool "Set CoAP debugging level" - depends on MBEDTLS_COAP_DEBUG - default COAP_LOG_WARNING - help - Set CoAP debugging level - - config COAP_LOG_EMERG - bool "Emergency" - config COAP_LOG_ALERT - bool "Alert" - config COAP_LOG_CRIT - bool "Critical" - config COAP_LOG_ERROR - bool "Error" - config COAP_LOG_WARNING - bool "Warning" - config COAP_LOG_NOTICE - bool "Notice" - config COAP_LOG_INFO - bool "Info" - config COAP_LOG_DEBUG - bool "Debug" - endchoice - - config COAP_LOG_DEFAULT_LEVEL - int - default 0 if !MBEDTLS_COAP_DEBUG - default 0 if COAP_LOG_EMERG - default 1 if COAP_LOG_ALERT - default 2 if COAP_LOG_CRIT - default 3 if COAP_LOG_ERROR - default 4 if COAP_LOG_WARNING - default 5 if COAP_LOG_NOTICE - default 6 if COAP_LOG_INFO - default 7 if COAP_LOG_DEBUG - endmenu From a8bfe59bd159e9191f3d83496ddf19ad8cebebf8 Mon Sep 17 00:00:00 2001 From: Mahavir Jain Date: Wed, 31 Jul 2019 16:22:49 +0530 Subject: [PATCH 417/486] coap: refactor examples, stylistic cleanups, move certs to independent dir --- examples/protocols/coap_client/README.md | 19 +- .../protocols/coap_client/main/CMakeLists.txt | 2 +- .../coap_client/main/{ => certs}/coap_ca.pem | 0 .../main/{ => certs}/coap_client.crt | 0 .../main/{ => certs}/coap_client.key | 0 .../main/coap_client_example_main.c | 203 ++++++++---------- .../protocols/coap_client/main/component.mk | 4 +- examples/protocols/coap_server/README.md | 20 +- .../protocols/coap_server/main/CMakeLists.txt | 2 +- .../coap_server/main/{ => certs}/coap_ca.pem | 0 .../main/{ => certs}/coap_server.crt | 0 .../main/{ => certs}/coap_server.key | 0 .../main/coap_server_example_main.c | 196 ++++++++--------- .../protocols/coap_server/main/component.mk | 4 +- 14 files changed, 202 insertions(+), 248 deletions(-) rename examples/protocols/coap_client/main/{ => certs}/coap_ca.pem (100%) rename examples/protocols/coap_client/main/{ => certs}/coap_client.crt (100%) rename examples/protocols/coap_client/main/{ => certs}/coap_client.key (100%) rename examples/protocols/coap_server/main/{ => certs}/coap_ca.pem (100%) rename examples/protocols/coap_server/main/{ => certs}/coap_server.crt (100%) rename examples/protocols/coap_server/main/{ => certs}/coap_server.key (100%) diff --git a/examples/protocols/coap_client/README.md b/examples/protocols/coap_client/README.md index 7c317dddda..a870f9363e 100644 --- a/examples/protocols/coap_client/README.md +++ b/examples/protocols/coap_client/README.md @@ -37,17 +37,12 @@ Example Connection Configuration ---> * Set WiFi Password under Example Configuration Example CoAP Client Configuration ---> * Set CoAP Target Uri - * Set encryption method definitions (None, PSK or PKI) - * If PSK Set CoAP Preshared Key to use in connection to the server - * If PSK Set CoAP PSK Client identity (username) - Enable CoAP debugging if required + * If PSK, Set CoAP Preshared Key to use in connection to the server + * If PSK, Set CoAP PSK Client identity (username) Component config ---> - mbedTLS ---> - [*] Enable mbedtls certificate expiry check - TLS Key Exchange Methods ---> - [*] Enable pre-shared-key ciphersuites - [*] Enable PSK based ciphersuite modes - [*] Support DTLS protocol (all versions) + CoAP Configuration ---> + * Set encryption method definition, PSK (default) or PKI + * Enable CoAP debugging if required ### Build and Flash @@ -103,6 +98,4 @@ optional `path`, and begins with `coap://`, `coaps://` or `coap+tcp://` for a coap server that supports TCP (not all do including coap+tcp://californium.eclipse.org). -* CoAP logging can be enabled by running 'make menuconfig' and enable debugging - -* Encryption (MbedTLS) can be enabled by running 'make menuconfig' and enable debugging +* CoAP logging can be enabled by running 'idf.py menuconfig -> Component config -> CoAP Configuration' and setting appropriate log level diff --git a/examples/protocols/coap_client/main/CMakeLists.txt b/examples/protocols/coap_client/main/CMakeLists.txt index eb0d270668..d64daaee2a 100644 --- a/examples/protocols/coap_client/main/CMakeLists.txt +++ b/examples/protocols/coap_client/main/CMakeLists.txt @@ -1,4 +1,4 @@ # Embed CA, certificate & key directly into binary idf_component_register(SRCS "coap_client_example_main.c" INCLUDE_DIRS "." - EMBED_TXTFILES coap_ca.pem coap_client.crt coap_client.key) + EMBED_TXTFILES certs/coap_ca.pem certs/coap_client.crt certs/coap_client.key) diff --git a/examples/protocols/coap_client/main/coap_ca.pem b/examples/protocols/coap_client/main/certs/coap_ca.pem similarity index 100% rename from examples/protocols/coap_client/main/coap_ca.pem rename to examples/protocols/coap_client/main/certs/coap_ca.pem diff --git a/examples/protocols/coap_client/main/coap_client.crt b/examples/protocols/coap_client/main/certs/coap_client.crt similarity index 100% rename from examples/protocols/coap_client/main/coap_client.crt rename to examples/protocols/coap_client/main/certs/coap_client.crt diff --git a/examples/protocols/coap_client/main/coap_client.key b/examples/protocols/coap_client/main/certs/coap_client.key similarity index 100% rename from examples/protocols/coap_client/main/coap_client.key rename to examples/protocols/coap_client/main/certs/coap_client.key diff --git a/examples/protocols/coap_client/main/coap_client_example_main.c b/examples/protocols/coap_client/main/coap_client_example_main.c index 067364a736..c7223bc0e6 100644 --- a/examples/protocols/coap_client/main/coap_client_example_main.c +++ b/examples/protocols/coap_client/main/coap_client_example_main.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -49,8 +50,8 @@ instead of coap:// and the PSK must be one that the server supports (potentially associated with the IDENTITY) */ -#define EXAMPLE_COAP_PSK_KEY CONFIG_COAP_PSK_KEY -#define EXAMPLE_COAP_PSK_IDENTITY CONFIG_COAP_PSK_IDENTITY +#define EXAMPLE_COAP_PSK_KEY CONFIG_EXAMPLE_COAP_PSK_KEY +#define EXAMPLE_COAP_PSK_IDENTITY CONFIG_EXAMPLE_COAP_PSK_IDENTITY /* The examples use uri Logging Level that you can set via 'make menuconfig'. @@ -65,9 +66,9 @@ you can set via the project configuration (idf.py menuconfig) If you'd rather not, just change the below entries to strings with - the config you want - ie #define COAP_DEFAULT_DEMO_URI "coap://californium.eclipse.org" + the config you want - ie #define COAP_DEFAULT_DEMO_URI "coaps://californium.eclipse.org" */ -#define COAP_DEFAULT_DEMO_URI CONFIG_TARGET_DOMAIN_URI +#define COAP_DEFAULT_DEMO_URI CONFIG_EXAMPLE_TARGET_DOMAIN_URI const static char *TAG = "CoAP_client"; @@ -75,11 +76,30 @@ static int resp_wait = 1; static coap_optlist_t *optlist = NULL; static int wait_ms; +#ifdef CONFIG_COAP_MBEDTLS_PKI +/* CA cert, taken from coap_ca.pem + Client cert, taken from coap_client.crt + Client key, taken from coap_client.key + + The PEM, CRT and KEY file are examples taken from the wpa2 enterprise + example. + + To embed it in the app binary, the PEM, CRT and KEY file is named + in the component.mk COMPONENT_EMBED_TXTFILES variable. + */ +extern uint8_t ca_pem_start[] asm("_binary_coap_ca_pem_start"); +extern uint8_t ca_pem_end[] asm("_binary_coap_ca_pem_end"); +extern uint8_t client_crt_start[] asm("_binary_coap_client_crt_start"); +extern uint8_t client_crt_end[] asm("_binary_coap_client_crt_end"); +extern uint8_t client_key_start[] asm("_binary_coap_client_key_start"); +extern uint8_t client_key_end[] asm("_binary_coap_client_key_end"); +#endif /* CONFIG_COAP_MBEDTLS_PKI */ + static void message_handler(coap_context_t *ctx, coap_session_t *session, - coap_pdu_t *sent, coap_pdu_t *received, - const coap_tid_t id) + coap_pdu_t *sent, coap_pdu_t *received, + const coap_tid_t id) { - unsigned char* data = NULL; + unsigned char *data = NULL; size_t data_len; coap_pdu_t *pdu = NULL; coap_opt_t *block_opt; @@ -106,8 +126,8 @@ static void message_handler(coap_context_t *ctx, coap_session_t *session, /* create pdu with request for next block */ pdu = coap_new_pdu(session); if (!pdu) { - ESP_LOGE(TAG, "coap_new_pdu() failed"); - goto clean_up; + ESP_LOGE(TAG, "coap_new_pdu() failed"); + goto clean_up; } pdu->type = COAP_MESSAGE_CON; pdu->tid = coap_new_message_id(session); @@ -121,7 +141,7 @@ static void message_handler(coap_context_t *ctx, coap_session_t *session, case COAP_OPTION_URI_PATH : case COAP_OPTION_URI_QUERY : coap_add_option(pdu, option->number, option->length, - option->data); + option->data); break; default: ; /* skip other options */ @@ -133,8 +153,8 @@ static void message_handler(coap_context_t *ctx, coap_session_t *session, coap_add_option(pdu, blktype, coap_encode_var_safe(buf, sizeof(buf), - ((coap_opt_block_num(block_opt) + 1) << 4) | - COAP_OPT_BLOCK_SZX(block_opt)), buf); + ((coap_opt_block_num(block_opt) + 1) << 4) | + COAP_OPT_BLOCK_SZX(block_opt)), buf); tid = coap_send(session, pdu); @@ -155,41 +175,31 @@ clean_up: resp_wait = 0; } -#ifdef CONFIG_MBEDTLS_COAP_PKI - -#ifdef __GNUC__ -#define UNUSED_PARAM __attribute__ ((unused)) -#else /* not a GCC */ -#define UNUSED_PARAM -#endif /* GCC */ - -#ifndef min -#define min(a,b) ((a) < (b) ? (a) : (b)) -#endif +#ifdef CONFIG_COAP_MBEDTLS_PKI static int verify_cn_callback(const char *cn, - const uint8_t *asn1_public_cert UNUSED_PARAM, - size_t asn1_length UNUSED_PARAM, - coap_session_t *session UNUSED_PARAM, + const uint8_t *asn1_public_cert, + size_t asn1_length, + coap_session_t *session, unsigned depth, - int validated UNUSED_PARAM, - void *arg UNUSED_PARAM -) { - coap_log(LOG_INFO, "CN '%s' presented by server (%s)\n", - cn, depth ? "CA" : "Certificate"); - return 1; + int validated, + void *arg + ) +{ + coap_log(LOG_INFO, "CN '%s' presented by server (%s)\n", + cn, depth ? "CA" : "Certificate"); + return 1; } -#endif /* CONFIG_MBEDTLS_COAP_PKI */ +#endif /* CONFIG_COAP_MBEDTLS_PKI */ static void coap_example_client(void *p) { struct hostent *hp; - coap_address_t dst_addr; static coap_uri_t uri; - const char* server_uri = COAP_DEFAULT_DEMO_URI; - char* phostname = NULL; + const char *server_uri = COAP_DEFAULT_DEMO_URI; + char *phostname = NULL; coap_set_log_level(EXAMPLE_COAP_LOG_DEFAULT_LEVEL); @@ -209,17 +219,16 @@ static void coap_example_client(void *p) break; } - if ((uri.scheme==COAP_URI_SCHEME_COAPS && !coap_dtls_is_supported()) || - (uri.scheme==COAP_URI_SCHEME_COAPS_TCP && !coap_tls_is_supported())) { + if ((uri.scheme == COAP_URI_SCHEME_COAPS && !coap_dtls_is_supported()) || + (uri.scheme == COAP_URI_SCHEME_COAPS_TCP && !coap_tls_is_supported())) { ESP_LOGE(TAG, "CoAP server uri scheme is not supported"); break; } phostname = (char *)calloc(1, uri.host.length + 1); - if (phostname == NULL) { ESP_LOGE(TAG, "calloc failed"); - continue; + break; } memcpy(phostname, uri.host.s, uri.host.length); @@ -230,12 +239,11 @@ static void coap_example_client(void *p) ESP_LOGE(TAG, "DNS lookup failed"); vTaskDelay(1000 / portTICK_PERIOD_MS); free(phostname); - goto clean_up; + continue; } - { char tmpbuf[INET6_ADDRSTRLEN]; - coap_address_init(&dst_addr); - switch (hp->h_addrtype) { + coap_address_init(&dst_addr); + switch (hp->h_addrtype) { case AF_INET: dst_addr.addr.sin.sin_family = AF_INET; dst_addr.addr.sin.sin_port = htons(uri.port); @@ -253,7 +261,6 @@ static void coap_example_client(void *p) default: ESP_LOGE(TAG, "DNS lookup response failed"); goto clean_up; - } } if (uri.path.length) { @@ -263,9 +270,9 @@ static void coap_example_client(void *p) while (res--) { coap_insert_optlist(&optlist, - coap_new_optlist(COAP_OPTION_URI_PATH, - coap_opt_length(buf), - coap_opt_value(buf))); + coap_new_optlist(COAP_OPTION_URI_PATH, + coap_opt_length(buf), + coap_opt_value(buf))); buf += coap_opt_size(buf); } @@ -278,9 +285,9 @@ static void coap_example_client(void *p) while (res--) { coap_insert_optlist(&optlist, - coap_new_optlist(COAP_OPTION_URI_QUERY, - coap_opt_length(buf), - coap_opt_value(buf))); + coap_new_optlist(COAP_OPTION_URI_QUERY, + coap_opt_length(buf), + coap_opt_value(buf))); buf += coap_opt_size(buf); } @@ -288,8 +295,8 @@ static void coap_example_client(void *p) ctx = coap_new_context(NULL); if (!ctx) { - ESP_LOGE(TAG, "coap_new_context() failed"); - goto clean_up; + ESP_LOGE(TAG, "coap_new_context() failed"); + goto clean_up; } /* @@ -300,32 +307,16 @@ static void coap_example_client(void *p) * so COAP_URI_SCHEME_COAPS_TCP will have failed in a test above, * but the code is left in for completeness. */ - if (uri.scheme==COAP_URI_SCHEME_COAPS || uri.scheme==COAP_URI_SCHEME_COAPS_TCP) { -#ifdef CONFIG_MBEDTLS_COAP_PSK + if (uri.scheme == COAP_URI_SCHEME_COAPS || uri.scheme == COAP_URI_SCHEME_COAPS_TCP) { +#ifdef CONFIG_COAP_MBEDTLS_PSK session = coap_new_client_session_psk(ctx, NULL, &dst_addr, - uri.scheme==COAP_URI_SCHEME_COAPS ? COAP_PROTO_DTLS : COAP_PROTO_TLS, - EXAMPLE_COAP_PSK_IDENTITY, - (const uint8_t*)EXAMPLE_COAP_PSK_KEY, - sizeof(EXAMPLE_COAP_PSK_KEY)-1); -#endif /* CONFIG_MBEDTLS_COAP_PSK */ + uri.scheme == COAP_URI_SCHEME_COAPS ? COAP_PROTO_DTLS : COAP_PROTO_TLS, + EXAMPLE_COAP_PSK_IDENTITY, + (const uint8_t *)EXAMPLE_COAP_PSK_KEY, + sizeof(EXAMPLE_COAP_PSK_KEY) - 1); +#endif /* CONFIG_COAP_MBEDTLS_PSK */ -#ifdef CONFIG_MBEDTLS_COAP_PKI -/* CA cert, taken from coap_ca.pem - Client cert, taken from coap_client.crt - Client key, taken from coap_client.key - - The PEM, CRT and KEY file are examples taken from the wpa2 enterprise - example. - - To embed it in the app binary, the PEM, CRT and KEY file is named - in the component.mk COMPONENT_EMBED_TXTFILES variable. -*/ -extern uint8_t ca_pem_start[] asm("_binary_coap_ca_pem_start"); -extern uint8_t ca_pem_end[] asm("_binary_coap_ca_pem_end"); -extern uint8_t client_crt_start[] asm("_binary_coap_client_crt_start"); -extern uint8_t client_crt_end[] asm("_binary_coap_client_crt_end"); -extern uint8_t client_key_start[] asm("_binary_coap_client_key_start"); -extern uint8_t client_key_end[] asm("_binary_coap_client_key_end"); +#ifdef CONFIG_COAP_MBEDTLS_PKI unsigned int ca_pem_bytes = ca_pem_end - ca_pem_start; unsigned int client_crt_bytes = client_crt_end - client_crt_start; unsigned int client_key_bytes = client_key_end - client_key_start; @@ -360,10 +351,11 @@ extern uint8_t client_key_end[] asm("_binary_coap_client_key_end"); dtls_pki.validate_sni_call_back = NULL; dtls_pki.sni_call_back_arg = NULL; memset(client_sni, 0, sizeof(client_sni)); - if (uri.host.length) - memcpy(client_sni, uri.host.s, min(uri.host.length, sizeof(client_sni))); - else + if (uri.host.length) { + memcpy(client_sni, uri.host.s, MIN(uri.host.length, sizeof(client_sni))); + } else { memcpy(client_sni, "localhost", 9); + } dtls_pki.client_sni = client_sni; } dtls_pki.pki_key.key_type = COAP_PKI_KEY_PEM_BUF; @@ -375,30 +367,25 @@ extern uint8_t client_key_end[] asm("_binary_coap_client_key_end"); dtls_pki.pki_key.key.pem_buf.ca_cert_len = ca_pem_bytes; session = coap_new_client_session_pki(ctx, NULL, &dst_addr, - uri.scheme==COAP_URI_SCHEME_COAPS ? COAP_PROTO_DTLS : COAP_PROTO_TLS, - &dtls_pki); -#endif /* CONFIG_MBEDTLS_COAP_PKI */ - -#ifdef CONFIG_MBEDTLS_COAP_NONE - session = coap_new_client_session(ctx, NULL, &dst_addr, - uri.scheme==COAP_URI_SCHEME_COAPS ? COAP_PROTO_DTLS : COAP_PROTO_TLS); -#endif /* CONFIG_MBEDTLS_COAP_NONE */ + uri.scheme == COAP_URI_SCHEME_COAPS ? COAP_PROTO_DTLS : COAP_PROTO_TLS, + &dtls_pki); +#endif /* CONFIG_COAP_MBEDTLS_PKI */ } else { session = coap_new_client_session(ctx, NULL, &dst_addr, - uri.scheme==COAP_URI_SCHEME_COAP_TCP ? COAP_PROTO_TCP : - COAP_PROTO_UDP); + uri.scheme == COAP_URI_SCHEME_COAP_TCP ? COAP_PROTO_TCP : + COAP_PROTO_UDP); } if (!session) { - ESP_LOGE(TAG, "coap_new_client_session() failed"); - goto clean_up; + ESP_LOGE(TAG, "coap_new_client_session() failed"); + goto clean_up; } coap_register_response_handler(ctx, message_handler); request = coap_new_pdu(session); if (!request) { - ESP_LOGE(TAG, "coap_new_pdu() failed"); - goto clean_up; + ESP_LOGE(TAG, "coap_new_pdu() failed"); + goto clean_up; } request->type = COAP_MESSAGE_CON; request->tid = coap_new_message_id(session); @@ -413,12 +400,12 @@ extern uint8_t client_key_end[] asm("_binary_coap_client_key_end"); while (resp_wait) { int result = coap_run_once(ctx, wait_ms > 1000 ? 1000 : wait_ms); if (result >= 0) { - if (result >= wait_ms) { - ESP_LOGE(TAG, "select timeout"); - break; - } else { - wait_ms -= result; - } + if (result >= wait_ms) { + ESP_LOGE(TAG, "select timeout"); + break; + } else { + wait_ms -= result; + } } } clean_up: @@ -426,8 +413,12 @@ clean_up: coap_delete_optlist(optlist); optlist = NULL; } - if (session) coap_session_release(session); - if (ctx) coap_free_context(ctx); + if (session) { + coap_session_release(session); + } + if (ctx) { + coap_free_context(ctx); + } coap_cleanup(); /* * change the following line to something like sleep(2) @@ -445,14 +436,6 @@ void app_main(void) tcpip_adapter_init(); ESP_ERROR_CHECK(esp_event_loop_create_default()); -#if 0 -/* See https://github.com/Ebiroll/qemu_esp32 for further information */ -#include "emul_ip.h" - if (is_running_qemu()) { - xTaskCreate(task_lwip_init, "task_lwip_init", 2*4096, NULL, 20, NULL); - } - else -#endif /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. * Read "Establishing Wi-Fi or Ethernet Connection" section in * examples/protocols/README.md for more information about this function. diff --git a/examples/protocols/coap_client/main/component.mk b/examples/protocols/coap_client/main/component.mk index 50306ea2f9..51bf0b68c7 100644 --- a/examples/protocols/coap_client/main/component.mk +++ b/examples/protocols/coap_client/main/component.mk @@ -5,6 +5,4 @@ # embed files from the "certs" directory as binary data symbols # in the app -COMPONENT_EMBED_TXTFILES := coap_ca.pem -COMPONENT_EMBED_TXTFILES += coap_client.crt -COMPONENT_EMBED_TXTFILES += coap_client.key +COMPONENT_EMBED_TXTFILES := certs/coap_ca.pem certs/coap_client.crt certs/coap_client.key diff --git a/examples/protocols/coap_server/README.md b/examples/protocols/coap_server/README.md index 60941855f1..9be65ad5a6 100644 --- a/examples/protocols/coap_server/README.md +++ b/examples/protocols/coap_server/README.md @@ -35,18 +35,11 @@ Example Connection Configuration ---> * Set WiFi SSID under Example Configuration * Set WiFi Password under Example Configuration Example CoAP Client Configuration ---> - * Set CoAP Target Uri - * Set encryption method definitions (None, PSK or PKI) - * If PSK Set CoAP Preshared Key to use in connection to the server - * If PSK Set CoAP PSK Client identity (username) - Enable CoAP debugging if required + * If PSK, Set CoAP Preshared Key to use in connection to the server Component config ---> - mbedTLS ---> - [*] Enable mbedtls certificate expiry check - TLS Key Exchange Methods ---> - [*] Enable pre-shared-key ciphersuites - [*] Enable PSK based ciphersuite modes - [*] Support DTLS protocol (all versions) + CoAP Configuration ---> + * Set encryption method definition, PSK (default) or PKI + * Enable CoAP debugging if required ### Build and Flash @@ -90,7 +83,4 @@ This can be found at https://libcoap.net/doc/reference/4.2.0/ * Please make sure CoAP client fetchs or puts data under path: `/Espressif` or fetches `/.well-known/core` -* CoAP logging can be enabled by running 'make menuconfig' and enable debugging - -* Encryption (MbedTLS) can be enabled by running 'make menuconfig' and enable debugging - +* CoAP logging can be enabled by running 'idf.py menuconfig -> Component config -> CoAP Configuration' and setting appropriate log level diff --git a/examples/protocols/coap_server/main/CMakeLists.txt b/examples/protocols/coap_server/main/CMakeLists.txt index d4738f6918..a014088ece 100644 --- a/examples/protocols/coap_server/main/CMakeLists.txt +++ b/examples/protocols/coap_server/main/CMakeLists.txt @@ -1,3 +1,3 @@ idf_component_register(SRCS "coap_server_example_main.c" INCLUDE_DIRS "." - EMBED_TXTFILES coap_ca.pem coap_server.crt coap_server.key) + EMBED_TXTFILES certs/coap_ca.pem certs/coap_server.crt certs/coap_server.key) diff --git a/examples/protocols/coap_server/main/coap_ca.pem b/examples/protocols/coap_server/main/certs/coap_ca.pem similarity index 100% rename from examples/protocols/coap_server/main/coap_ca.pem rename to examples/protocols/coap_server/main/certs/coap_ca.pem diff --git a/examples/protocols/coap_server/main/coap_server.crt b/examples/protocols/coap_server/main/certs/coap_server.crt similarity index 100% rename from examples/protocols/coap_server/main/coap_server.crt rename to examples/protocols/coap_server/main/certs/coap_server.crt diff --git a/examples/protocols/coap_server/main/coap_server.key b/examples/protocols/coap_server/main/certs/coap_server.key similarity index 100% rename from examples/protocols/coap_server/main/coap_server.key rename to examples/protocols/coap_server/main/certs/coap_server.key diff --git a/examples/protocols/coap_server/main/coap_server_example_main.c b/examples/protocols/coap_server/main/coap_server_example_main.c index b2f78bb032..29bf691223 100644 --- a/examples/protocols/coap_server/main/coap_server_example_main.c +++ b/examples/protocols/coap_server/main/coap_server_example_main.c @@ -46,7 +46,7 @@ instead of coap:// and the PSK must be one that the server supports (potentially associated with the IDENTITY) */ -#define EXAMPLE_COAP_PSK_KEY CONFIG_COAP_PSK_KEY +#define EXAMPLE_COAP_PSK_KEY CONFIG_EXAMPLE_COAP_PSK_KEY /* The examples use CoAP Logging Level that you can set via 'make menuconfig'. @@ -57,9 +57,30 @@ */ #define EXAMPLE_COAP_LOG_DEFAULT_LEVEL CONFIG_COAP_LOG_DEFAULT_LEVEL +const static char *TAG = "CoAP_server"; + static char espressif_data[100]; static int espressif_data_len = 0; +#ifdef CONFIG_COAP_MBEDTLS_PKI +/* CA cert, taken from coap_ca.pem + Server cert, taken from coap_server.crt + Server key, taken from coap_server.key + + The PEM, CRT and KEY file are examples taken from the wpa2 enterprise + example. + + To embed it in the app binary, the PEM, CRT and KEY file is named + in the component.mk COMPONENT_EMBED_TXTFILES variable. + */ +extern uint8_t ca_pem_start[] asm("_binary_coap_ca_pem_start"); +extern uint8_t ca_pem_end[] asm("_binary_coap_ca_pem_end"); +extern uint8_t server_crt_start[] asm("_binary_coap_server_crt_start"); +extern uint8_t server_crt_end[] asm("_binary_coap_server_crt_end"); +extern uint8_t server_key_start[] asm("_binary_coap_server_key_start"); +extern uint8_t server_key_end[] asm("_binary_coap_server_key_end"); +#endif /* CONFIG_COAP_MBEDTLS_PKI */ + #define INITIAL_DATA "Hello World!" /* @@ -93,8 +114,7 @@ hnd_espressif_put(coap_context_t *ctx, if (strcmp (espressif_data, INITIAL_DATA) == 0) { response->code = COAP_RESPONSE_CODE(201); - } - else { + } else { response->code = COAP_RESPONSE_CODE(204); } @@ -125,32 +145,23 @@ hnd_espressif_delete(coap_context_t *ctx, response->code = COAP_RESPONSE_CODE(202); } -#ifdef CONFIG_MBEDTLS_COAP_PKI - -#ifdef __GNUC__ -#define UNUSED_PARAM __attribute__ ((unused)) -#else /* not a GCC */ -#define UNUSED_PARAM -#endif /* GCC */ - -#ifndef min -#define min(a,b) ((a) < (b) ? (a) : (b)) -#endif +#ifdef CONFIG_COAP_MBEDTLS_PKI static int verify_cn_callback(const char *cn, - const uint8_t *asn1_public_cert UNUSED_PARAM, - size_t asn1_length UNUSED_PARAM, - coap_session_t *session UNUSED_PARAM, + const uint8_t *asn1_public_cert, + size_t asn1_length, + coap_session_t *session, unsigned depth, - int validated UNUSED_PARAM, - void *arg UNUSED_PARAM -) { - coap_log(LOG_INFO, "CN '%s' presented by server (%s)\n", - cn, depth ? "CA" : "Certificate"); - return 1; + int validated, + void *arg + ) +{ + coap_log(LOG_INFO, "CN '%s' presented by server (%s)\n", + cn, depth ? "CA" : "Certificate"); + return 1; } -#endif /* CONFIG_MBEDTLS_COAP_PKI */ +#endif /* CONFIG_COAP_MBEDTLS_PKI */ static void coap_example_server(void *p) { @@ -174,96 +185,85 @@ static void coap_example_server(void *p) ctx = coap_new_context(NULL); if (!ctx) { - continue; + ESP_LOGE(TAG, "coap_new_context() failed"); + continue; } -#ifdef CONFIG_MBEDTLS_COAP_PSK +#ifdef CONFIG_COAP_MBEDTLS_PSK /* Need PSK setup before we set up endpoints */ coap_context_set_psk(ctx, "CoAP", - (const uint8_t*)EXAMPLE_COAP_PSK_KEY, - sizeof(EXAMPLE_COAP_PSK_KEY)-1); -#endif /* CONFIG_MBEDTLS_COAP_PSK */ + (const uint8_t *)EXAMPLE_COAP_PSK_KEY, + sizeof(EXAMPLE_COAP_PSK_KEY) - 1); +#endif /* CONFIG_COAP_MBEDTLS_PSK */ -#ifdef CONFIG_MBEDTLS_COAP_PKI -/* CA cert, taken from coap_ca.pem - Server cert, taken from coap_server.crt - Server key, taken from coap_server.key +#ifdef CONFIG_COAP_MBEDTLS_PKI + unsigned int ca_pem_bytes = ca_pem_end - ca_pem_start; + unsigned int server_crt_bytes = server_crt_end - server_crt_start; + unsigned int server_key_bytes = server_key_end - server_key_start; + coap_dtls_pki_t dtls_pki; - The PEM, CRT and KEY file are examples taken from the wpa2 enterprise - example. + memset (&dtls_pki, 0, sizeof(dtls_pki)); + dtls_pki.version = COAP_DTLS_PKI_SETUP_VERSION; + if (ca_pem_bytes) { + /* + * Add in additional certificate checking. + * This list of enabled can be tuned for the specific + * requirements - see 'man coap_encryption'. + * + * Note: A list of root ca file can be setup separately using + * coap_context_set_pki_root_cas(), but the below is used to + * define what checking actually takes place. + */ + dtls_pki.verify_peer_cert = 1; + dtls_pki.require_peer_cert = 1; + dtls_pki.allow_self_signed = 1; + dtls_pki.allow_expired_certs = 1; + dtls_pki.cert_chain_validation = 1; + dtls_pki.cert_chain_verify_depth = 2; + dtls_pki.check_cert_revocation = 1; + dtls_pki.allow_no_crl = 1; + dtls_pki.allow_expired_crl = 1; + dtls_pki.allow_bad_md_hash = 1; + dtls_pki.allow_short_rsa_length = 1; + dtls_pki.validate_cn_call_back = verify_cn_callback; + dtls_pki.cn_call_back_arg = NULL; + dtls_pki.validate_sni_call_back = NULL; + dtls_pki.sni_call_back_arg = NULL; + } + dtls_pki.pki_key.key_type = COAP_PKI_KEY_PEM_BUF; + dtls_pki.pki_key.key.pem_buf.public_cert = server_crt_start; + dtls_pki.pki_key.key.pem_buf.public_cert_len = server_crt_bytes; + dtls_pki.pki_key.key.pem_buf.private_key = server_key_start; + dtls_pki.pki_key.key.pem_buf.private_key_len = server_key_bytes; + dtls_pki.pki_key.key.pem_buf.ca_cert = ca_pem_start; + dtls_pki.pki_key.key.pem_buf.ca_cert_len = ca_pem_bytes; - To embed it in the app binary, the PEM, CRT and KEY file is named - in the component.mk COMPONENT_EMBED_TXTFILES variable. -*/ -extern uint8_t ca_pem_start[] asm("_binary_coap_ca_pem_start"); -extern uint8_t ca_pem_end[] asm("_binary_coap_ca_pem_end"); -extern uint8_t server_crt_start[] asm("_binary_coap_server_crt_start"); -extern uint8_t server_crt_end[] asm("_binary_coap_server_crt_end"); -extern uint8_t server_key_start[] asm("_binary_coap_server_key_start"); -extern uint8_t server_key_end[] asm("_binary_coap_server_key_end"); - unsigned int ca_pem_bytes = ca_pem_end - ca_pem_start; - unsigned int server_crt_bytes = server_crt_end - server_crt_start; - unsigned int server_key_bytes = server_key_end - server_key_start; - coap_dtls_pki_t dtls_pki; - - memset (&dtls_pki, 0, sizeof(dtls_pki)); - dtls_pki.version = COAP_DTLS_PKI_SETUP_VERSION; - if (ca_pem_bytes) { - /* - * Add in additional certificate checking. - * This list of enabled can be tuned for the specific - * requirements - see 'man coap_encryption'. - * - * Note: A list of root ca file can be setup separately using - * coap_context_set_pki_root_cas(), but the below is used to - * define what checking actually takes place. - */ - dtls_pki.verify_peer_cert = 1; - dtls_pki.require_peer_cert = 1; - dtls_pki.allow_self_signed = 1; - dtls_pki.allow_expired_certs = 1; - dtls_pki.cert_chain_validation = 1; - dtls_pki.cert_chain_verify_depth = 2; - dtls_pki.check_cert_revocation = 1; - dtls_pki.allow_no_crl = 1; - dtls_pki.allow_expired_crl = 1; - dtls_pki.allow_bad_md_hash = 1; - dtls_pki.allow_short_rsa_length = 1; - dtls_pki.validate_cn_call_back = verify_cn_callback; - dtls_pki.cn_call_back_arg = NULL; - dtls_pki.validate_sni_call_back = NULL; - dtls_pki.sni_call_back_arg = NULL; - } - dtls_pki.pki_key.key_type = COAP_PKI_KEY_PEM_BUF; - dtls_pki.pki_key.key.pem_buf.public_cert = server_crt_start; - dtls_pki.pki_key.key.pem_buf.public_cert_len = server_crt_bytes; - dtls_pki.pki_key.key.pem_buf.private_key = server_key_start; - dtls_pki.pki_key.key.pem_buf.private_key_len = server_key_bytes; - dtls_pki.pki_key.key.pem_buf.ca_cert = ca_pem_start; - dtls_pki.pki_key.key.pem_buf.ca_cert_len = ca_pem_bytes; - - coap_context_set_pki(ctx, &dtls_pki); -#endif /* CONFIG_MBEDTLS_COAP_PKI */ + coap_context_set_pki(ctx, &dtls_pki); +#endif /* CONFIG_COAP_MBEDTLS_PKI */ ep = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_UDP); if (!ep) { - goto clean_up; + ESP_LOGE(TAG, "udp: coap_new_endpoint() failed"); + goto clean_up; } ep = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_TCP); if (!ep) { - goto clean_up; + ESP_LOGE(TAG, "tcp: coap_new_endpoint() failed"); + goto clean_up; } -#if defined(CONFIG_MBEDTLS_COAP_PSK) || defined(CONFIG_MBEDTLS_COAP_PKI) - if (coap_dtls_is_supported()) { +#if defined(CONFIG_COAP_MBEDTLS_PSK) || defined(CONFIG_COAP_MBEDTLS_PKI) + if (coap_dtls_is_supported()) { serv_addr.addr.sin.sin_port = htons(COAPS_DEFAULT_PORT); ep = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_DTLS); if (!ep) { - goto clean_up; + ESP_LOGE(TAG, "dtls: coap_new_endpoint() failed"); + goto clean_up; } } -#endif /* CONFIG_MBEDTLS_COAP_PSK CONFIG_MBEDTLS_COAP_PKI */ +#endif /* CONFIG_COAP_MBEDTLS_PSK CONFIG_COAP_MBEDTLS_PKI */ resource = coap_resource_init(coap_make_str_const("Espressif"), 0); if (!resource) { - goto clean_up; + ESP_LOGE(TAG, "coap_resource_init() failed"); + goto clean_up; } coap_register_handler(resource, COAP_REQUEST_GET, hnd_espressif_get); coap_register_handler(resource, COAP_REQUEST_PUT, hnd_espressif_put); @@ -301,14 +301,6 @@ void app_main(void) tcpip_adapter_init(); ESP_ERROR_CHECK(esp_event_loop_create_default()); -#if 0 -/* See https://github.com/Ebiroll/qemu_esp32 for further information */ -#include "emul_ip.h" - if (is_running_qemu()) { - xTaskCreate(task_lwip_init, "task_lwip_init", 2*4096, NULL, 20, NULL); - } - else -#endif /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. * Read "Establishing Wi-Fi or Ethernet Connection" section in * examples/protocols/README.md for more information about this function. diff --git a/examples/protocols/coap_server/main/component.mk b/examples/protocols/coap_server/main/component.mk index bccdac23fd..d3d1de0b01 100644 --- a/examples/protocols/coap_server/main/component.mk +++ b/examples/protocols/coap_server/main/component.mk @@ -5,6 +5,4 @@ # embed files from the "certs" directory as binary data symbols # in the app -COMPONENT_EMBED_TXTFILES := coap_ca.pem -COMPONENT_EMBED_TXTFILES += coap_server.crt -COMPONENT_EMBED_TXTFILES += coap_server.key +COMPONENT_EMBED_TXTFILES := certs/coap_ca.pem certs/coap_server.crt certs/coap_server.key From 2e8c85d8fff823232af46cc0f353ac170d0971e9 Mon Sep 17 00:00:00 2001 From: kooho <2229179028@qq.com> Date: Thu, 1 Nov 2018 12:23:11 +0800 Subject: [PATCH 418/486] driver(ledc): fixed ledc clock selection bug. --- components/driver/include/driver/ledc.h | 10 ++ components/driver/ledc.c | 111 +++++++++++++----- components/driver/test/test_ledc.c | 9 ++ components/driver/test/test_pcnt.c | 2 + .../internal_communication/main/mesh_light.c | 3 +- .../mesh/manual_networking/main/mesh_light.c | 3 +- .../peripherals/ledc/main/ledc_example_main.c | 3 +- .../peripherals/pcnt/main/pcnt_example_main.c | 1 + 8 files changed, 107 insertions(+), 35 deletions(-) diff --git a/components/driver/include/driver/ledc.h b/components/driver/include/driver/ledc.h index 17875783fb..4d5593abb7 100644 --- a/components/driver/include/driver/ledc.h +++ b/components/driver/include/driver/ledc.h @@ -51,6 +51,13 @@ typedef enum { LEDC_APB_CLK, /*!< LEDC timer clock divided from APB clock (80Mhz) */ } ledc_clk_src_t; +typedef enum { + LEDC_AUTO_CLK, /*!< The driver will automatically select the source clock(REF_TICK or APB) based on the giving resolution and duty parameter when init the timer*/ + LEDC_USE_REF_TICK, /*!< LEDC timer select REF_TICK clock as source clock*/ + LEDC_USE_APB_CLK, /*!< LEDC timer select APB clock as source clock*/ + LEDC_USE_RTC8M_CLK, /*!< LEDC timer select RTC8M_CLK as source clock. Only for low speed channels and this parameter must be the same for all low speed channels*/ +} ledc_clk_cfg_t; + typedef enum { LEDC_TIMER_0 = 0, /*!< LEDC timer 0 */ LEDC_TIMER_1, /*!< LEDC timer 1 */ @@ -125,6 +132,9 @@ typedef struct { }; ledc_timer_t timer_num; /*!< The timer source of channel (0 - 3) */ uint32_t freq_hz; /*!< LEDC timer frequency (Hz) */ + ledc_clk_cfg_t clk_cfg; /*!< Configure LEDC source clock. + For low speed channels and high speed channels, you can specify the source clock using LEDC_USE_REF_TICK, LEDC_USE_APB_CLK or LEDC_AUTO_CLK. + For low speed channels, you can also specify the source clock using LEDC_USE_RTC8M_CLK, in this case, all low speed channel's source clock must be RTC8M_CLK*/ } ledc_timer_config_t; typedef intr_handle_t ledc_isr_handle_t; diff --git a/components/driver/ledc.c b/components/driver/ledc.c index ff992d1474..f82efaf5e3 100644 --- a/components/driver/ledc.c +++ b/components/driver/ledc.c @@ -19,6 +19,7 @@ #include "soc/gpio_periph.h" #include "driver/ledc.h" #include "soc/ledc_periph.h" +#include "soc/rtc.h" #include "esp_log.h" static const char* LEDC_TAG = "ledc"; @@ -51,12 +52,17 @@ static ledc_isr_handle_t s_ledc_fade_isr_handle = NULL; #define LEDC_VAL_NO_CHANGE (-1) #define LEDC_STEP_NUM_MAX (1023) #define LEDC_DUTY_DECIMAL_BIT_NUM (4) +#define DELAY_CLK8M_CLK_SWITCH (5) +#define SLOW_CLK_CYC_CALIBRATE (13) #define LEDC_HPOINT_VAL_MAX (LEDC_HPOINT_HSCH1_V) #define LEDC_FADE_TOO_SLOW_STR "LEDC FADE TOO SLOW" #define LEDC_FADE_TOO_FAST_STR "LEDC FADE TOO FAST" static const char *LEDC_FADE_SERVICE_ERR_STR = "LEDC fade service not installed"; static const char *LEDC_FADE_INIT_ERROR_STR = "LEDC fade channel init error, not enough memory or service not installed"; +//This value will be calibrated when in use. +static uint32_t s_ledc_slow_clk_8M = 0; + static void ledc_ls_timer_update(ledc_mode_t speed_mode, ledc_timer_t timer_sel) { if (speed_mode == LEDC_LOW_SPEED_MODE) { @@ -71,6 +77,23 @@ static IRAM_ATTR void ledc_ls_channel_update(ledc_mode_t speed_mode, ledc_channe } } +//We know that CLK8M is about 8M, but don't know the actual value. So we need to do a calibration. +static bool ledc_slow_clk_calibrate(void) +{ + //Enable CLK8M for LEDC + SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M); + //Waiting for CLK8M to turn on + ets_delay_us(DELAY_CLK8M_CLK_SWITCH); + uint32_t cal_val = rtc_clk_cal(RTC_CAL_8MD256, SLOW_CLK_CYC_CALIBRATE); + if(cal_val == 0) { + ESP_LOGE(LEDC_TAG, "CLK8M_CLK calibration failed"); + return false; + } + s_ledc_slow_clk_8M = 1000000ULL * (1 << RTC_CLK_CAL_FRACT) * 256 / cal_val; + ESP_LOGD(LEDC_TAG, "Calibrate CLK8M_CLK : %d Hz", s_ledc_slow_clk_8M); + return true; +} + static esp_err_t ledc_enable_intr_type(ledc_mode_t speed_mode, uint32_t channel, ledc_intr_type_t type) { LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode"); @@ -219,6 +242,60 @@ esp_err_t ledc_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags, return ret; } +// Setting the LEDC timer divisor with the given source clock, frequency and resolution. +static esp_err_t ledc_set_timer_div(ledc_mode_t speed_mode, ledc_timer_t timer_num, ledc_clk_cfg_t clk_cfg, int freq_hz, int duty_resolution) +{ + uint32_t div_param = 0; + uint32_t precision = ( 0x1 << duty_resolution ); + ledc_clk_src_t timer_clk_src = LEDC_APB_CLK; + + // Calculate the divisor + // User specified source clock(RTC8M_CLK) for low speed channel + if ((speed_mode == LEDC_LOW_SPEED_MODE) && (clk_cfg == LEDC_USE_RTC8M_CLK)) { + if(s_ledc_slow_clk_8M == 0) { + if (ledc_slow_clk_calibrate() == false) { + goto error; + } + } + div_param = ( (uint64_t) s_ledc_slow_clk_8M << 8 ) / freq_hz / precision; + } else { + // Automatically select APB or REF_TICK as the source clock. + if (clk_cfg == LEDC_AUTO_CLK) { + // Try calculating divisor based on LEDC_APB_CLK + div_param = ( (uint64_t) LEDC_APB_CLK_HZ << 8 ) / freq_hz / precision; + if (div_param > LEDC_DIV_NUM_HSTIMER0_V) { + // APB_CLK results in divisor which too high. Try using REF_TICK as clock source. + timer_clk_src = LEDC_REF_TICK; + div_param = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision; + } else if (div_param < 256) { + // divisor is too low + goto error; + } + // User specified source clock(LEDC_APB_CLK_HZ or LEDC_REF_TICK) + } else { + timer_clk_src = (clk_cfg == LEDC_USE_APB_CLK) ? LEDC_APB_CLK : LEDC_REF_TICK; + uint32_t sclk_freq = (clk_cfg == LEDC_USE_APB_CLK) ? LEDC_APB_CLK_HZ : LEDC_REF_CLK_HZ; + div_param = ( (uint64_t) sclk_freq << 8 ) / freq_hz / precision; + } + } + if (div_param < 256 || div_param > LEDC_DIV_NUM_LSTIMER0_V) { + goto error; + } + // For low speed channels, if RTC_8MCLK is used as the source clock, the `slow_clk_sel` register should be cleared, otherwise it should be set. + if (speed_mode == LEDC_LOW_SPEED_MODE) { + LEDC.conf.slow_clk_sel = (clk_cfg == LEDC_USE_RTC8M_CLK) ? 0 : 1; + } + //Set the divisor + ledc_timer_set(speed_mode, timer_num, div_param, duty_resolution, timer_clk_src); + // reset the timer + ledc_timer_rst(speed_mode, timer_num); + return ESP_OK; +error: + ESP_LOGE(LEDC_TAG, "requested frequency and duty resolution can not be achieved, try reducing freq_hz or duty_resolution. div_param=%d", + (uint32_t ) div_param); + return ESP_FAIL; +} + esp_err_t ledc_timer_config(const ledc_timer_config_t* timer_conf) { LEDC_ARG_CHECK(timer_conf != NULL, "timer_conf"); @@ -227,6 +304,7 @@ esp_err_t ledc_timer_config(const ledc_timer_config_t* timer_conf) uint32_t timer_num = timer_conf->timer_num; uint32_t speed_mode = timer_conf->speed_mode; LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode"); + LEDC_ARG_CHECK(!((timer_conf->clk_cfg == LEDC_USE_RTC8M_CLK) && (speed_mode != LEDC_LOW_SPEED_MODE)), "Only low speed channel support RTC8M_CLK"); periph_module_enable(PERIPH_LEDC_MODULE); if (freq_hz == 0 || duty_resolution == 0 || duty_resolution >= LEDC_TIMER_BIT_MAX) { ESP_LOGE(LEDC_TAG, "freq_hz=%u duty_resolution=%u", freq_hz, duty_resolution); @@ -236,38 +314,7 @@ esp_err_t ledc_timer_config(const ledc_timer_config_t* timer_conf) ESP_LOGE(LEDC_TAG, "invalid timer #%u", timer_num); return ESP_ERR_INVALID_ARG; } - esp_err_t ret = ESP_OK; - uint32_t precision = ( 0x1 << duty_resolution ); // 2**depth - // Try calculating divisor based on LEDC_APB_CLK - ledc_clk_src_t timer_clk_src = LEDC_APB_CLK; - // div_param is a Q10.8 fixed point value - uint64_t div_param = ( (uint64_t) LEDC_APB_CLK_HZ << 8 ) / freq_hz / precision; - if (div_param < 256) { - // divisor is too low - ESP_LOGE(LEDC_TAG, "requested frequency and duty resolution can not be achieved, try reducing freq_hz or duty_resolution. div_param=%d", - (uint32_t ) div_param); - ret = ESP_FAIL; - } - if (div_param > LEDC_DIV_NUM_HSTIMER0_V) { - // APB_CLK results in divisor which too high. Try using REF_TICK as clock source. - timer_clk_src = LEDC_REF_TICK; - div_param = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision; - if (div_param < 256 || div_param > LEDC_DIV_NUM_HSTIMER0_V) { - ESP_LOGE(LEDC_TAG, "requested frequency and duty resolution can not be achieved, try increasing freq_hz or duty_resolution. div_param=%d", - (uint32_t ) div_param); - ret = ESP_FAIL; - } - } else { - if (speed_mode == LEDC_LOW_SPEED_MODE) { - //for now, we only select 80mhz for slow clk of LEDC low speed channels. - LEDC.conf.slow_clk_sel = 1; - } - } - // set timer parameters - ledc_timer_set(speed_mode, timer_num, div_param, duty_resolution, timer_clk_src); - // reset timer - ledc_timer_rst(speed_mode, timer_num); - return ret; + return ledc_set_timer_div(timer_num, timer_num, timer_conf->clk_cfg, freq_hz, duty_resolution); } esp_err_t ledc_set_pin(int gpio_num, ledc_mode_t speed_mode, ledc_channel_t ledc_channel) diff --git a/components/driver/test/test_ledc.c b/components/driver/test/test_ledc.c index d0e35851d8..b676c4232a 100644 --- a/components/driver/test/test_ledc.c +++ b/components/driver/test/test_ledc.c @@ -86,6 +86,7 @@ static void timer_frequency_test(ledc_channel_t channel, ledc_timer_bit_t timer_ .bit_num = timer_bit, .timer_num = timer, .freq_hz = 5000, + .clk_cfg = LEDC_AUTO_CLK, }; TEST_ESP_OK(ledc_channel_config(&ledc_ch_config)); TEST_ESP_OK(ledc_timer_config(&ledc_time_config)); @@ -126,6 +127,7 @@ static void timer_duty_test(ledc_channel_t channel, ledc_timer_bit_t timer_bit, .bit_num = timer_bit, .timer_num = timer, .freq_hz = 5000, + .clk_cfg = LEDC_AUTO_CLK, }; TEST_ESP_OK(ledc_channel_config(&ledc_ch_config)); TEST_ESP_OK(ledc_timer_config(&ledc_time_config)); @@ -188,6 +190,7 @@ TEST_CASE("LEDC error log channel and timer config", "[ledc][test_env=UT_T1_LEDC ledc_time_config.duty_resolution = LEDC_TIMER_13_BIT; ledc_time_config.timer_num = LEDC_TIMER_0; ledc_time_config.freq_hz = 5000; + ledc_time_config.clk_cfg = LEDC_AUTO_CLK; ledc_timer_config_t temp_timer_config = ledc_time_config; TEST_ESP_OK(ledc_timer_config(&ledc_time_config)); @@ -228,6 +231,7 @@ TEST_CASE("LEDC normal channel and timer config", "[ledc][test_env=UT_T1_LEDC]") .bit_num = LEDC_TIMER_13_BIT, .timer_num = LEDC_TIMER_0, .freq_hz = 5000, + .clk_cfg = LEDC_AUTO_CLK, }; ledc_timer_config_t temp_time_config = ledc_time_config; @@ -297,6 +301,7 @@ TEST_CASE("LEDC timer set", "[ledc][test_env=UT_T1_LEDC]") .bit_num = 13, .timer_num = LEDC_TIMER_0, .freq_hz = 5000, + .clk_cfg = LEDC_AUTO_CLK, }; TEST_ESP_OK(ledc_timer_config(&ledc_time_config)); @@ -347,6 +352,7 @@ TEST_CASE("LEDC timer pause and resume", "[ledc][test_env=UT_T1_LEDC]") .duty_resolution = LEDC_TIMER_13_BIT, .timer_num = LEDC_TIMER_0, .freq_hz = 5000, + .clk_cfg = LEDC_AUTO_CLK, }; TEST_ESP_OK(ledc_timer_config(&ledc_time_config)); @@ -392,6 +398,7 @@ TEST_CASE("LEDC fade with time(logic analyzer)", "[ledc][ignore]") .duty_resolution = LEDC_TIMER_13_BIT, .timer_num = LEDC_TIMER_0, .freq_hz = 5000, + .clk_cfg = LEDC_AUTO_CLK, }; TEST_ESP_OK(ledc_timer_config(&ledc_time_config)); @@ -429,6 +436,7 @@ TEST_CASE("LEDC fade with step(logic analyzer)", "[ledc][ignore]") .duty_resolution = LEDC_TIMER_13_BIT, .timer_num = LEDC_TIMER_0, .freq_hz = 5000, + .clk_cfg = LEDC_AUTO_CLK, }; TEST_ESP_OK(ledc_timer_config(&ledc_time_config)); @@ -470,6 +478,7 @@ TEST_CASE("LEDC memory test", "[ledc][test_env=UT_T1_LEDC]") .duty_resolution = LEDC_TIMER_13_BIT, .timer_num = LEDC_TIMER_0, .freq_hz = 5000, + .clk_cfg = LEDC_AUTO_CLK, }; TEST_ESP_OK(ledc_timer_config(&ledc_time_config)); diff --git a/components/driver/test/test_pcnt.c b/components/driver/test/test_pcnt.c index ae5656a846..af4e58fa67 100644 --- a/components/driver/test/test_pcnt.c +++ b/components/driver/test/test_pcnt.c @@ -55,6 +55,7 @@ static void produce_pulse(void) .timer_num = LEDC_TIMER_1, .duty_resolution = LEDC_TIMER_10_BIT, .freq_hz = 1, + .clk_cfg = LEDC_AUTO_CLK, }; ledc_timer_config(&ledc_timer); @@ -160,6 +161,7 @@ static void count_mode_test(gpio_num_t ctl_io) .timer_num = LEDC_TIMER_1, .duty_resolution = LEDC_TIMER_10_BIT, .freq_hz = 100, + .clk_cfg = LEDC_AUTO_CLK, }; ledc_timer_config(&ledc_timer); diff --git a/examples/mesh/internal_communication/main/mesh_light.c b/examples/mesh/internal_communication/main/mesh_light.c index 58a66e1527..b1f4c6705c 100644 --- a/examples/mesh/internal_communication/main/mesh_light.c +++ b/examples/mesh/internal_communication/main/mesh_light.c @@ -42,7 +42,8 @@ esp_err_t mesh_light_init(void) .bit_num = LEDC_TIMER_13_BIT, .freq_hz = 5000, .speed_mode = LEDC_HIGH_SPEED_MODE, - .timer_num = LEDC_TIMER_0 + .timer_num = LEDC_TIMER_0, + .clk_cfg = LEDC_AUTO_CLK, }; ledc_timer_config(&ledc_timer); diff --git a/examples/mesh/manual_networking/main/mesh_light.c b/examples/mesh/manual_networking/main/mesh_light.c index 4780503817..e181be41bf 100644 --- a/examples/mesh/manual_networking/main/mesh_light.c +++ b/examples/mesh/manual_networking/main/mesh_light.c @@ -42,7 +42,8 @@ esp_err_t mesh_light_init(void) .bit_num = LEDC_TIMER_13_BIT, .freq_hz = 5000, .speed_mode = LEDC_HIGH_SPEED_MODE, - .timer_num = LEDC_TIMER_0 + .timer_num = LEDC_TIMER_0, + .clk_cfg = LEDC_AUTO_CLK, }; ledc_timer_config(&ledc_timer); diff --git a/examples/peripherals/ledc/main/ledc_example_main.c b/examples/peripherals/ledc/main/ledc_example_main.c index 3a0cd5e97b..88dbe6714e 100644 --- a/examples/peripherals/ledc/main/ledc_example_main.c +++ b/examples/peripherals/ledc/main/ledc_example_main.c @@ -63,7 +63,8 @@ void app_main(void) .duty_resolution = LEDC_TIMER_13_BIT, // resolution of PWM duty .freq_hz = 5000, // frequency of PWM signal .speed_mode = LEDC_HS_MODE, // timer mode - .timer_num = LEDC_HS_TIMER // timer index + .timer_num = LEDC_HS_TIMER, // timer index + .clk_cfg = LEDC_AUTO_CLK, // Auto select the source clock }; // Set configuration of timer0 for high speed channels ledc_timer_config(&ledc_timer); diff --git a/examples/peripherals/pcnt/main/pcnt_example_main.c b/examples/peripherals/pcnt/main/pcnt_example_main.c index 89a3703634..a8d1fb32d7 100644 --- a/examples/peripherals/pcnt/main/pcnt_example_main.c +++ b/examples/peripherals/pcnt/main/pcnt_example_main.c @@ -100,6 +100,7 @@ static void ledc_init(void) ledc_timer.timer_num = LEDC_TIMER_1; ledc_timer.duty_resolution = LEDC_TIMER_10_BIT; ledc_timer.freq_hz = 1; // set output frequency at 1 Hz + ledc_timer.clk_cfg = LEDC_AUTO_CLK; ledc_timer_config(&ledc_timer); // Prepare and then apply the LEDC PWM channel configuration From c93cab858ef0ece164312c9973c582e76c5a8c63 Mon Sep 17 00:00:00 2001 From: Piyush Shah Date: Tue, 6 Aug 2019 19:30:58 +0530 Subject: [PATCH 419/486] httpd_sess_close: Check for session validity before closing If httpd_sess_trigger_close() gets called twice for the same socket, the first httpd_sess_close() cb closes the correct socket, but the second invocation closes the wrong socket which was just accepted and added to the socket db. Checking for the lru counter will help identify this as the counter is set only for requests actually served. --- components/esp_http_server/src/httpd_sess.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/esp_http_server/src/httpd_sess.c b/components/esp_http_server/src/httpd_sess.c index 8109475b4c..9deb6df2fe 100644 --- a/components/esp_http_server/src/httpd_sess.c +++ b/components/esp_http_server/src/httpd_sess.c @@ -378,6 +378,10 @@ static void httpd_sess_close(void *arg) { struct sock_db *sock_db = (struct sock_db *)arg; if (sock_db) { + if (sock_db->lru_counter == 0) { + ESP_LOGD(TAG, "Skipping session close for %d as it seems to be a race condition", sock_db->fd); + return; + } int fd = sock_db->fd; struct httpd_data *hd = (struct httpd_data *) sock_db->handle; httpd_sess_delete(hd, fd); From f3d6a34e7d1de1ef3f2fb0b1c8aade7d6882945c Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 23 May 2019 21:48:08 +0200 Subject: [PATCH 420/486] esp_tls: enable psk verification mode, added mqtt example using psk authentication --- components/esp-tls/Kconfig | 11 ++ components/esp-tls/esp_tls.c | 19 ++- components/esp-tls/esp_tls.h | 15 ++ components/mqtt/esp-mqtt | 2 +- .../tcp_transport/include/esp_transport_ssl.h | 15 ++ components/tcp_transport/transport_ssl.c | 8 + .../protocols/mqtt/ssl_psk/CMakeLists.txt | 10 ++ examples/protocols/mqtt/ssl_psk/Makefile | 9 ++ examples/protocols/mqtt/ssl_psk/README.md | 76 ++++++++++ .../mqtt/ssl_psk/main/CMakeLists.txt | 4 + .../protocols/mqtt/ssl_psk/main/app_main.c | 141 ++++++++++++++++++ .../protocols/mqtt/ssl_psk/main/component.mk | 0 .../protocols/mqtt/ssl_psk/sdkconfig.defaults | 1 + 13 files changed, 309 insertions(+), 2 deletions(-) create mode 100644 examples/protocols/mqtt/ssl_psk/CMakeLists.txt create mode 100644 examples/protocols/mqtt/ssl_psk/Makefile create mode 100644 examples/protocols/mqtt/ssl_psk/README.md create mode 100644 examples/protocols/mqtt/ssl_psk/main/CMakeLists.txt create mode 100644 examples/protocols/mqtt/ssl_psk/main/app_main.c create mode 100644 examples/protocols/mqtt/ssl_psk/main/component.mk create mode 100644 examples/protocols/mqtt/ssl_psk/sdkconfig.defaults diff --git a/components/esp-tls/Kconfig b/components/esp-tls/Kconfig index 3208942717..e31ac8de78 100644 --- a/components/esp-tls/Kconfig +++ b/components/esp-tls/Kconfig @@ -5,5 +5,16 @@ menu "ESP-TLS" help Enable support for creating server side SSL/TLS session + config ESP_TLS_PSK_VERIFICATION + bool "Enable PSK verification" + select MBEDTLS_PSK_MODES + select MBEDTLS_KEY_EXCHANGE_PSK + select MBEDTLS_KEY_EXCHANGE_DHE_PSK + select MBEDTLS_KEY_EXCHANGE_ECDHE_PSK + select MBEDTLS_KEY_EXCHANGE_RSA_PSK + default n + help + Enable support for pre shared key ciphers + endmenu diff --git a/components/esp-tls/esp_tls.c b/components/esp-tls/esp_tls.c index e527873f70..fc5e76754b 100644 --- a/components/esp-tls/esp_tls.c +++ b/components/esp-tls/esp_tls.c @@ -426,6 +426,23 @@ static esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls if (esp_ret != ESP_OK) { return esp_ret; } + mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL); + } else if (cfg->psk_hint_key) { +#if defined(CONFIG_ESP_TLS_PSK_VERIFICATION) + // + // PSK encryption mode is configured only if no certificate supplied and psk pointer not null + ESP_LOGD(TAG, "ssl psk authentication"); + ret = mbedtls_ssl_conf_psk(&tls->conf, cfg->psk_hint_key->key, cfg->psk_hint_key->key_size, + (const unsigned char *)cfg->psk_hint_key->hint, strlen(cfg->psk_hint_key->hint)); + if (ret != 0) { + ESP_LOGE(TAG, "mbedtls_ssl_conf_psk returned -0x%x", -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + return ESP_ERR_MBEDTLS_SSL_CONF_PSK_FAILED; + } +#else + ESP_LOGE(TAG, "psk_hint_key configured but not enabled in menuconfig: Please enable ESP_TLS_PSK_VERIFICATION option"); + return ESP_ERR_INVALID_STATE; +#endif } else { mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE); } @@ -443,7 +460,7 @@ static esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls }; esp_err_t esp_ret = set_pki_context(tls, &pki); if (esp_ret != ESP_OK) { - ESP_LOGE(TAG, "Failed to set server pki context"); + ESP_LOGE(TAG, "Failed to set client pki context"); return esp_ret; } } else if (cfg->clientcert_buf != NULL || cfg->clientkey_buf != NULL) { diff --git a/components/esp-tls/esp_tls.h b/components/esp-tls/esp_tls.h index a026bc4abc..e99770b575 100644 --- a/components/esp-tls/esp_tls.h +++ b/components/esp-tls/esp_tls.h @@ -48,6 +48,7 @@ extern "C" { #define ESP_ERR_MBEDTLS_SSL_WRITE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0E) /*!< mbedtls api returned error */ #define ESP_ERR_MBEDTLS_PK_PARSE_KEY_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0F) /*!< mbedtls api returned failed */ #define ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x10) /*!< mbedtls api returned failed */ +#define ESP_ERR_MBEDTLS_SSL_CONF_PSK_FAILED (ESP_ERR_ESP_TLS_BASE + 0x11) /*!< mbedtls api returned failed */ typedef struct esp_tls_last_error* esp_tls_error_handle_t; @@ -76,6 +77,15 @@ typedef enum esp_tls_role { ESP_TLS_SERVER, } esp_tls_role_t; +/** + * @brief ESP-TLS preshared key and hint structure + */ +typedef struct psk_key_hint { + const uint8_t* key; /*!< key in PSK authentication mode in binary format */ + const size_t key_size; /*!< length of the key */ + const char* hint; /*!< hint in PSK authentication mode in string format */ +} psk_hint_key_t; + /** * @brief ESP-TLS configuration parameters * @@ -159,6 +169,11 @@ typedef struct esp_tls_cfg { If NULL, server certificate CN must match hostname. */ bool skip_common_name; /*!< Skip any validation of server certificate CN field */ + + const psk_hint_key_t* psk_hint_key; /*!< Pointer to PSK hint and key. if not NULL (and certificates are NULL) + then PSK authentication is enabled with configured setup. + Important note: the pointer must be valid for connection */ + } esp_tls_cfg_t; #ifdef CONFIG_ESP_TLS_SERVER diff --git a/components/mqtt/esp-mqtt b/components/mqtt/esp-mqtt index dc37d3a065..117eef2dad 160000 --- a/components/mqtt/esp-mqtt +++ b/components/mqtt/esp-mqtt @@ -1 +1 @@ -Subproject commit dc37d3a065f345a7358b8ff4553db0baceeb8ad6 +Subproject commit 117eef2dad54e0f9e25b3005fcfc18e7695ff29e diff --git a/components/tcp_transport/include/esp_transport_ssl.h b/components/tcp_transport/include/esp_transport_ssl.h index c69749b4b3..a83e93882d 100644 --- a/components/tcp_transport/include/esp_transport_ssl.h +++ b/components/tcp_transport/include/esp_transport_ssl.h @@ -16,6 +16,7 @@ #define _ESP_TRANSPORT_SSL_H_ #include "esp_transport.h" +#include "esp_tls.h" #ifdef __cplusplus extern "C" { @@ -111,6 +112,20 @@ void esp_transport_ssl_set_client_key_data_der(esp_transport_handle_t t, const c */ void esp_transport_ssl_skip_common_name_check(esp_transport_handle_t t); +/** + * @brief Set PSK key and hint for PSK server/client verification in esp-tls component. + * Important notes: + * - This function stores the pointer to data, rather than making a copy. + * So this data must remain valid until after the connection is cleaned up + * - ESP_TLS_PSK_VERIFICATION config option must be enabled in menuconfig + * - certificate verification takes priority so it must not be configured + * to enable PSK method. + * + * @param t ssl transport + * @param[in] psk_hint_key psk key and hint structure defined in esp_tls.h + */ +void esp_transport_ssl_set_psk_key_hint(esp_transport_handle_t t, const psk_hint_key_t* psk_hint_key); + #ifdef __cplusplus } #endif diff --git a/components/tcp_transport/transport_ssl.c b/components/tcp_transport/transport_ssl.c index f8543e92e0..d5b13490ac 100644 --- a/components/tcp_transport/transport_ssl.c +++ b/components/tcp_transport/transport_ssl.c @@ -169,6 +169,14 @@ void esp_transport_ssl_enable_global_ca_store(esp_transport_handle_t t) } } +void esp_transport_ssl_set_psk_key_hint(esp_transport_handle_t t, const psk_hint_key_t* psk_hint_key) +{ + transport_ssl_t *ssl = esp_transport_get_context_data(t); + if (t && ssl) { + ssl->cfg.psk_hint_key = psk_hint_key; + } +} + void esp_transport_ssl_set_cert_data(esp_transport_handle_t t, const char *data, int len) { transport_ssl_t *ssl = esp_transport_get_context_data(t); diff --git a/examples/protocols/mqtt/ssl_psk/CMakeLists.txt b/examples/protocols/mqtt/ssl_psk/CMakeLists.txt new file mode 100644 index 0000000000..77934fa675 --- /dev/null +++ b/examples/protocols/mqtt/ssl_psk/CMakeLists.txt @@ -0,0 +1,10 @@ +# The following four lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +# (Not part of the boilerplate) +# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(mqtt_ssl_psk) diff --git a/examples/protocols/mqtt/ssl_psk/Makefile b/examples/protocols/mqtt/ssl_psk/Makefile new file mode 100644 index 0000000000..24bec17e9d --- /dev/null +++ b/examples/protocols/mqtt/ssl_psk/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# +PROJECT_NAME := mqtt_ssl_psk + +EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common + +include $(IDF_PATH)/make/project.mk diff --git a/examples/protocols/mqtt/ssl_psk/README.md b/examples/protocols/mqtt/ssl_psk/README.md new file mode 100644 index 0000000000..c46688f035 --- /dev/null +++ b/examples/protocols/mqtt/ssl_psk/README.md @@ -0,0 +1,76 @@ +# ESP-MQTT SSL example with PSK verification + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example connects to a local broker configured to PSK authentication + +## How to use example + +### Hardware Required + +This example can be executed on any ESP32 board, the only required interface is WiFi (or ethernet) to connect to a MQTT +broker with preconfigured PSK verification method. + +#### Mosquitto settings +In case of using mosquitto broker, here is how to enable PSK authentication in `mosquitto.config`, +``` +psk_hint hint +psk_file path_to_your_psk_file +allow_anonymous true +``` +Note: Last line enables anonymous mode, as this example does not use mqtt username and password. + +PSK file then has to contain pairs of hints and keys, as shown below: +``` +hint:BAD123 +``` + +Important note: Keys are stored as text hexadecimal values in PSK file, while the example code stores key as plain binary +as required by MQTT API. (See the example source for details: `"BAD123" -> 0xBA, 0xD1, 0x23`) + +### Configure the project + +* Run `make menuconfig` (or `idf.py menuconfig` if using CMake build system) +* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. +* When using Make build system, set `Default serial port` under `Serial flasher config`. + +### Build and Flash + + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +``` +I (2160) example_connect: Ethernet Link Up +I (4650) example_connect: Connected to Ethernet +I (4650) example_connect: IPv4 address: 192.168.0.1 +I (4650) MQTTS_EXAMPLE: [APP] Free memory: 244792 bytes +I (4660) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE +D (4670) MQTT_CLIENT: MQTT client_id=ESP32_c6B4F8 +D (4680) MQTT_CLIENT: Core selection disabled +I (4680) MQTTS_EXAMPLE: Other event id:7 +D (4680) esp-tls: host:192.168.0.2: strlen 13 +D (4700) esp-tls: ssl psk authentication +D (4700) esp-tls: handshake in progress... +D (4720) MQTT_CLIENT: Transport connected to mqtts://192.168.0.2:8883 +I (4720) MQTT_CLIENT: Sending MQTT CONNECT message, type: 1, id: 0000 +D (4720) MQTT_CLIENT: mqtt_message_receive: first byte: 0x20 +D (4730) MQTT_CLIENT: mqtt_message_receive: read "remaining length" byte: 0x2 +D (4730) MQTT_CLIENT: mqtt_message_receive: total message length: 4 (already read: 2) +D (4740) MQTT_CLIENT: mqtt_message_receive: read_len=2 +D (4750) MQTT_CLIENT: mqtt_message_receive: transport_read():4 4 +D (4750) MQTT_CLIENT: Connected +I (4760) MQTTS_EXAMPLE: MQTT_EVENT_CONNECTED +D (4760) MQTT_CLIENT: mqtt_enqueue id: 4837, type=8 successful +D (4770) OUTBOX: ENQUEUE msgid=4837, msg_type=8, len=18, size=18 +D (4770) MQTT_CLIENT: Sent subscribe topic=/topic/qos0, id: 4837, type=8 successful +I (4780) MQTTS_EXAMPLE: sent subscribe successful, msg_id=4837 +D (4790) MQTT_CLIENT: mqtt_enqueue id: 58982, type=8 successful +D (4790) OUTBOX: ENQUEUE msgid=58982, msg_type=8, len=18, size=36 +D (4800) MQTT_CLIENT: Sent subscribe topic=/topic/qos1, id: 58982, type=8 successful +I (4810) MQTTS_EXAMPLE: sent subscribe successful, msg_id=58982 +``` + diff --git a/examples/protocols/mqtt/ssl_psk/main/CMakeLists.txt b/examples/protocols/mqtt/ssl_psk/main/CMakeLists.txt new file mode 100644 index 0000000000..6b03500639 --- /dev/null +++ b/examples/protocols/mqtt/ssl_psk/main/CMakeLists.txt @@ -0,0 +1,4 @@ +set(COMPONENT_SRCS "app_main.c") +set(COMPONENT_ADD_INCLUDEDIRS ".") + +register_component() diff --git a/examples/protocols/mqtt/ssl_psk/main/app_main.c b/examples/protocols/mqtt/ssl_psk/main/app_main.c new file mode 100644 index 0000000000..7a08d17725 --- /dev/null +++ b/examples/protocols/mqtt/ssl_psk/main/app_main.c @@ -0,0 +1,141 @@ +/* MQTT over SSL Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include +#include +#include "esp_wifi.h" +#include "esp_system.h" +#include "nvs_flash.h" +#include "esp_event.h" +#include "tcpip_adapter.h" +#include "protocol_examples_common.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/queue.h" + +#include "lwip/sockets.h" +#include "lwip/dns.h" +#include "lwip/netdb.h" + +#include "esp_log.h" +#include "mqtt_client.h" +#include "esp_tls.h" + +/* + * Add here URI of mqtt broker which supports PSK authentication + */ +#define EXAMPLE_BROKER_URI "mqtts://192.168.0.2" + +static const char *TAG = "MQTTS_EXAMPLE"; + +/* + * Define psk key and hint as defined in mqtt broker + * example for mosquitto server, content of psk_file: + * hint:BAD123 + * + */ +static const uint8_t s_key[] = { 0xBA, 0xD1, 0x23 }; + +static const psk_hint_key_t psk_hint_key = { + .key = s_key, + .key_size = sizeof(s_key), + .hint = "hint" + }; + +static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event) +{ + esp_mqtt_client_handle_t client = event->client; + int msg_id; + // your_context_t *context = event->context; + switch (event->event_id) { + case MQTT_EVENT_CONNECTED: + ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); + msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + + msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + + msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); + ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id); + break; + case MQTT_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); + break; + + case MQTT_EVENT_SUBSCRIBED: + ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); + msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); + ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); + break; + case MQTT_EVENT_UNSUBSCRIBED: + ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); + break; + case MQTT_EVENT_PUBLISHED: + ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); + break; + case MQTT_EVENT_DATA: + ESP_LOGI(TAG, "MQTT_EVENT_DATA"); + printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); + printf("DATA=%.*s\r\n", event->data_len, event->data); + break; + case MQTT_EVENT_ERROR: + ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); + break; + default: + ESP_LOGI(TAG, "Other event id:%d", event->event_id); + break; + } + return ESP_OK; +} + + +static void mqtt_app_start(void) +{ + const esp_mqtt_client_config_t mqtt_cfg = { + .uri = EXAMPLE_BROKER_URI, + .event_handle = mqtt_event_handler, + .psk_hint_key = &psk_hint_key, + }; + + ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); + esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); + esp_mqtt_client_start(client); +} + +void app_main(void) +{ + ESP_LOGI(TAG, "[APP] Startup.."); + ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); + ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version()); + + esp_log_level_set("*", ESP_LOG_INFO); + esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE); + esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE); + esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE); + esp_log_level_set("esp-tls", ESP_LOG_VERBOSE); + esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE); + esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE); + + ESP_ERROR_CHECK(nvs_flash_init()); + tcpip_adapter_init(); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. + * Read "Establishing Wi-Fi or Ethernet Connection" section in + * examples/protocols/README.md for more information about this function. + */ + ESP_ERROR_CHECK(example_connect()); + + mqtt_app_start(); +} diff --git a/examples/protocols/mqtt/ssl_psk/main/component.mk b/examples/protocols/mqtt/ssl_psk/main/component.mk new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/protocols/mqtt/ssl_psk/sdkconfig.defaults b/examples/protocols/mqtt/ssl_psk/sdkconfig.defaults new file mode 100644 index 0000000000..1df83e8f39 --- /dev/null +++ b/examples/protocols/mqtt/ssl_psk/sdkconfig.defaults @@ -0,0 +1 @@ +CONFIG_ESP_TLS_PSK_VERIFICATION=y From 5203a1543996e5ad9aacd33672dda9103c0c8aad Mon Sep 17 00:00:00 2001 From: Mahavir Jain Date: Wed, 7 Aug 2019 11:49:55 +0530 Subject: [PATCH 421/486] esp32_gdbstub: fix build error with esp32-2019r1 toolchain Fixes https://github.com/espressif/esp-idf/issues/3866 --- components/esp32/panic.c | 2 ++ components/esp_gdbstub/src/gdbstub.c | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/components/esp32/panic.c b/components/esp32/panic.c index 4a104f0290..9b56938623 100644 --- a/components/esp32/panic.c +++ b/components/esp32/panic.c @@ -429,6 +429,7 @@ static inline void disableAllWdts(void) TIMERG1.wdt_wprotect = 0; } +#if CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT static void esp_panic_dig_reset(void) __attribute__((noreturn)); static void esp_panic_dig_reset(void) @@ -444,6 +445,7 @@ static void esp_panic_dig_reset(void) ; } } +#endif static void putEntry(uint32_t pc, uint32_t sp) { diff --git a/components/esp_gdbstub/src/gdbstub.c b/components/esp_gdbstub/src/gdbstub.c index fbb3d26bf1..f15be617f2 100644 --- a/components/esp_gdbstub/src/gdbstub.c +++ b/components/esp_gdbstub/src/gdbstub.c @@ -205,12 +205,14 @@ static void handle_H_command(const unsigned char* cmd, int len) } else if (requested_task_index > s_scratch.task_count) { ret = "E00"; } else { - TaskHandle_t handle; + TaskHandle_t handle = NULL; get_task_handle(requested_task_index, &handle); /* FIXME: for the task currently running on the other CPU, extracting the registers from TCB * isn't valid. Need to use some IPC mechanism to obtain the registers of the other CPU */ - esp_gdbstub_tcb_to_regfile(handle, &s_scratch.regfile); + if (handle != NULL) { + esp_gdbstub_tcb_to_regfile(handle, &s_scratch.regfile); + } } esp_gdbstub_send_str_packet(ret); } else { From 80a5bd8e5400b8f3446ba857c786850f257dd37d Mon Sep 17 00:00:00 2001 From: Sagar Bijwe Date: Fri, 2 Aug 2019 14:28:33 +0530 Subject: [PATCH 422/486] wpa_supplicant: Port more crypto functions to use mbedtls Use mbedtls PBKDF2 and SHA1 for faster calculations during four-way handshake. Closes WIFI-1590 --- .../wpa_supplicant/src/crypto/sha1-internal.c | 49 +++++++++++++++- .../wpa_supplicant/src/crypto/sha1-pbkdf2.c | 58 ++++++++++++++++++- 2 files changed, 104 insertions(+), 3 deletions(-) diff --git a/components/wpa_supplicant/src/crypto/sha1-internal.c b/components/wpa_supplicant/src/crypto/sha1-internal.c index 9eb190039e..3bcd88116c 100644 --- a/components/wpa_supplicant/src/crypto/sha1-internal.c +++ b/components/wpa_supplicant/src/crypto/sha1-internal.c @@ -20,11 +20,17 @@ #include "crypto/md5.h" #include "crypto/crypto.h" +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/sha1.h" +#endif + typedef struct SHA1Context SHA1_CTX; void SHA1Transform(u32 state[5], const unsigned char buffer[64]); + +#ifndef USE_MBEDTLS_CRYPTO /** * sha1_vector - SHA-1 hash for data vector * @num_elem: Number of elements in the data vector @@ -45,7 +51,49 @@ sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) SHA1Final(mac, &ctx); return 0; } +#else +/** + * sha1_vector - SHA-1 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 of failure + */ +int +sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + mbedtls_sha1_context ctx; + size_t i; + int ret; + mbedtls_sha1_init( &ctx ); + + if ((ret = mbedtls_sha1_starts_ret( &ctx)) != 0) { + goto exit; + } + + + for (i = 0; i < num_elem; i++) { + if ((ret = mbedtls_sha1_update_ret(&ctx, addr[i], len[i])) != 0) { + goto exit; + } + } + + if ((ret = mbedtls_sha1_finish_ret( &ctx, mac)) != 0) { + goto exit; + } + +exit: + mbedtls_sha1_free( &ctx ); + + if (ret) { + return -1; + } + + return 0; +} +#endif /* ===== start - public domain SHA1 implementation ===== */ @@ -309,5 +357,4 @@ SHA1Final(unsigned char digest[20], SHA1_CTX* context) os_memset(context->count, 0, 8); os_memset(finalcount, 0, 8); } - /* ===== end - public domain SHA1 implementation ===== */ diff --git a/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c b/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c index ec7100142c..b842a57d4e 100644 --- a/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c +++ b/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c @@ -18,10 +18,63 @@ #include "crypto/md5.h" #include "crypto/crypto.h" +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/pkcs5.h" + +/** + * pbkdf2_sha1 - SHA1-based key derivation function (PBKDF2) for IEEE 802.11i + * @passphrase: ASCII passphrase + * @ssid: SSID + * @ssid_len: SSID length in bytes + * @iterations: Number of iterations to run + * @buf: Buffer for the generated key + * @buflen: Length of the buffer in bytes + * Returns: 0 on success, -1 of failure + * + * This function is used to derive PSK for WPA-PSK. For this protocol, + * iterations is set to 4096 and buflen to 32. This function is described in + * IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0. + */ +int +pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, + int iterations, u8 *buf, size_t buflen) +{ + + mbedtls_md_context_t sha1_ctx; + const mbedtls_md_info_t *info_sha1; + int ret; + + mbedtls_md_init( &sha1_ctx ); + + info_sha1 = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ); + if (info_sha1 == NULL) { + ret = -1; + goto exit; + } + + if ((ret = mbedtls_md_setup( &sha1_ctx, info_sha1, 1 ) ) != 0) { + ret = -1; + goto exit; + } + + ret = mbedtls_pkcs5_pbkdf2_hmac( &sha1_ctx, (const unsigned char*) passphrase, os_strlen(passphrase) , (const unsigned char*) ssid, + ssid_len, iterations, 32, buf ); + if (ret != 0) { + ret = -1; + goto exit; + } + +exit: + mbedtls_md_free( &sha1_ctx ); + + return ret; +} +#else + static int pbkdf2_sha1_f(const char *passphrase, const char *ssid, - size_t ssid_len, int iterations, unsigned int count, - u8 *digest) + size_t ssid_len, int iterations, unsigned int count, + u8 *digest) { unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN]; int i, j; @@ -99,3 +152,4 @@ pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, return 0; } +#endif From 07166a6b18003a350d384f421e983a610ecb2a6c Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Tue, 9 Apr 2019 13:20:22 +0800 Subject: [PATCH 423/486] sdio_slave: rewrite the doc and highlight efuse-burning as the default option for 3.3V modules --- .../peripherals/sd_pullup_requirements.rst | 351 ++++++++++++------ .../api-reference/peripherals/sdio_slave.rst | 84 +++-- .../sdio/slave/main/Kconfig.projbuild | 2 +- 3 files changed, 291 insertions(+), 146 deletions(-) diff --git a/docs/en/api-reference/peripherals/sd_pullup_requirements.rst b/docs/en/api-reference/peripherals/sd_pullup_requirements.rst index 3fd76b0a06..658d94ea94 100644 --- a/docs/en/api-reference/peripherals/sd_pullup_requirements.rst +++ b/docs/en/api-reference/peripherals/sd_pullup_requirements.rst @@ -1,153 +1,268 @@ SD Pullup Requirements ====================== -CMD and DATA lines D0-D3 of the slave should be pulled up by 50KOhm resistor +CMD and DATA lines D0-D3 of the slave should be pulled up by 10 kOhm resistor even in 1-bit mode or SPI mode. The pullups of the slave cards should be connected even if they're not connected to the host. -The MTDI strapping pin is incompatible with DAT2 line pull-up by default -when the code flash is 3.3V. See :ref:`mtdi_strapping_pin` below. +The MTDI strapping pin by default is incompatible with DAT2 line pullup when +the flash is 3.3 V. See :ref:`technical_detail_sdio` below. -Pullup inside Official Modules ------------------------------- +.. _existing_issues_official_modules_sdio: -For Espressif official modules, different weak pullups / pulldowns are -connected to CMD, and DATA pins as below. To use these modules, -these pins are required to be pulled up by 50KOhm resistors, since internal -weak pullups are insufficient. +Possible Issues +--------------- -+-----------------------+-----+--------------------------+------+----------------------+------+ -| GPIO | 15 | 2 | 4 | 12 | 13 | -+=======================+=====+==========================+======+======================+======+ -| Name | CMD | DAT0 | DAT1 | DAT2 | DAT3 | -+-----------------------+-----+--------------------------+------+----------------------+------+ -| At startup | WPU | WPD | WPD | PU for 1.8v flash; | WPU | -| | | | | WPD for 3.3v flash | | -+-----------------------+-----+--------------------------+------+----------------------+------+ -| Strapping requirement | | Low to download to flash | | High for 1.8v flash; | | -| | | | | Low for 3.3v flash | | -+-----------------------+-----+--------------------------+------+----------------------+------+ +Here is a list of Espressif chips, official modules and development kits and +the issues they may have during SDIO development. Since the requirements are +for the pullups on the SD bus, the issues should be resolved no matter if it +is a host or slave. Each issue is linked to its solution. The solution for a +specific issue may be different for host and slave. -- WPU: Weak pullup -- WPD: Weak pulldown -- PU: Pullup inside the module +Official modules are usually without the sufficient pullups on all 6 pins, it +is suggested to select one of the development kits for either host or slave +to provide such pullups. -For Wrover modules, they use 1.8v flash, and have pullup on GPIO12 inside. -For Wroom-32 Series, PICO-D4 modules, they use 3.3v flash, and is weakly -pulled down internally. See :ref:`mtdi_strapping_pin` below. +Chips +^^^^^ -Pullup on Official Devkit (WroverKit) --------------------------------------- + - ESP32 (except D2WD, see `ESP32 datasheet `_): + :ref:`sd_pullup_no_pullups`, whether the strapping conflicts with DAT2 is determined + by the flash you are using. Please see :ref:`strapping_conflicts_dat2` if + your flash chip is 3.3 V. -For official Wrover Kit (till version 3), some of the pullups are provided on -the board as the table below. For other devkits that don't have pullups, -please connect them yourselves. + - ESP32-D2WD: + :ref:`sd_pullup_no_pullups`, :ref:`no_pullup_on_gpio12` -+-----------------------+-----+------+------+------+---------+ -| GPIO | 15 | 2 | 4 | 12 | 13 | -+=======================+=====+======+======+======+=========+ -| Name | CMD | DAT0 | DAT1 | DAT2 | DAT3 | -+-----------------------+-----+------+------+------+---------+ -| Pullup on the Kit | PU | PU | PU | | PU & PD | -+-----------------------+-----+------+------+------+---------+ + - ESP32-PICO-D4: + :ref:`sd_pullup_no_pullups`, :ref:`strapping_conflicts_dat2` -- PU: Pullup -- PD: Pulldown +Modules +^^^^^^^ -The DAT3 pullup conflicts with JTAG pulldown in WroverKit v3 and earlier, please -either: + - ESP32-WROOM-32 Series: + Including ESP32-WROOM-32, ESP32-WROOM-32D, ESP32-WROOM-32U and + ESP32-SOLO-1. -1. pull it up by resistor less than 5KOhm (2kOhm suggested) in 4-bit mode. -2. pull it up or drive it high by host or VDD3.3V in 1-bit mode. + :ref:`sd_pullup_no_pullups`, :ref:`strapping_conflicts_dat2`. -.. _mtdi_strapping_pin: + - ESP32-WROVER Series: + Including ESP32-WROVER and ESP32-WROVER-I. -MTDI strapping pin ------------------- + :ref:`sd_pullup_no_pullups`. -MTDI (GPIO12) is used as a bootstrapping pin to select output voltage of an -internal regulator which powers the flash chip (VDD_SDIO). This pin has an -internal pulldown so if left unconnected it will read low at reset (selecting -default 3.3V operation). When adding a pullup to this pin for SD card -operation, consider the following: + - ESP32-WROVER-B Series: + Including ESP32-WROVER-B and ESP32-WROVER-IB. -- For boards which don't use the internal regulator (VDD_SDIO) to power the - flash, GPIO12 can be pulled high. -- For boards which use 1.8V flash chip, GPIO12 needs to be pulled high at - reset. This is fully compatible with SD card operation. -- On boards which use the internal regulator and a 3.3V flash chip, GPIO12 - must be low at reset. This is incompatible with SD card operation. Please - check the table below to see whether your modules/kits use 3.3v flash. + :ref:`sd_pullup_no_pullups`, :ref:`strapping_conflicts_dat2`. -+-----------------+---------------+--------------------------------------+ -| Module | Flash voltage | DAT2 connections | -+=================+===============+======================================+ -| PICO-D4 | 3.3V | Internal PD, change EFUSE and pullup | -+-----------------+ + or disable DAT2 line* + -| Wroom-32 Series | | | -+-----------------+---------------+--------------------------------------+ -| Wrover | 1.8V | Internal PU, pullup suggested | -+-----------------+---------------+--------------------------------------+ +.. _sdio_dev_kits: -Official devkits of different types and version mount different types of -modules, please refer to the table below to see whether your devkit can -support SDIO slave without steps above. +Development Boards +^^^^^^^^^^^^^^^^^^ -+--------------------------+-----------------+---------------+ -| Devkit | Module | Flash voltage | -+==========================+=================+===============+ -| PICO Kit | PICO-D4 | 3.3V | -+--------------------------+-----------------+ (see steps + -| DevKitC | Wroom-32 Series | below) | -+--------------------------+ + + -| WroverKit v2 and earlier | | | -+--------------------------+-----------------+---------------+ -| WroverKit v3 | Wrover | 1.8V | -+--------------------------+-----------------+---------------+ + - ESP32-PICO-KIT: + Including PICO-KIT v4.1, v4.0 and v3. -If your board requires internal regulator with 3.3v output, to make it -compatible with SD pullup, you can either: + :ref:`sd_pullup_no_pullups`, :ref:`strapping_conflicts_dat2`, + :ref:`gpio2_strapping_pin`. - - **In the case using ESP32 host only**, external pullup can be omitted and an - internal pullup can be enabled using a ``gpio_pullup_en(GPIO_NUM_12);`` call. - Most SD cards work fine when an internal pullup on GPIO12 line is enabled. - Note that if ESP32 experiences a power-on reset while the SD card is - sending data, high level on GPIO12 can be latched into the bootstrapping - register, and ESP32 will enter a boot loop until external reset with - correct GPIO12 level is applied. - - **In the case using ESP32 slave in 1-bit mode**, speicfy - ``SDIO_SLAVE_FLAG_DAT2_DISABLED`` in the slave to avoid slave detecting on - DAT2 line. Note the host will not know 4-bit mode is not supported any more - by the standard CCCR register. You have to tell the host use 1-bit only. - - **For ESP32 host or slave**, another option is to burn the flash voltage - selection efuses. This will permanently select 3.3V output voltage for the - internal regulator, and GPIO12 will not be used as a bootstrapping pin. - Then it is safe to connect a pullup resistor to GPIO12. This option is - suggested for production use. NOTE this cannot be reverted once the EFUSE - is burnt. + - ESP32-DevKitC: + Including ESP32-DevKitC v4 and v2. - The following command can be used to program flash voltage selection efuses **to 3.3V**: + :ref:`sd_pullup_no_pullups`, :ref:`strapping_conflicts_dat2`, + :ref:`gpio2_strapping_pin`. - components/esptool_py/esptool/espefuse.py set_flash_voltage 3.3V + - ESP-WROVER-KIT: + v4.1: Have pullups, but :ref:`pullup_conflicts_on_gpio13` , + :ref:`strapping_conflicts_dat2`. - This command will burn the `XPD_SDIO_TIEH`, `XPD_SDIO_FORCE`, and - `XPD_SDIO_REG` efuses. With all three burned to value 1, the internal - VDD_SDIO flash voltage regulator is permanently enabled at 3.3V. See - the technical reference manual for more details. + v3: Have pullups, but :ref:`pullup_conflicts_on_gpio13`. - `espefuse.py` has a `--do-not-confirm` option if running from an automated flashing script. + v2 and v1: Have pullups, but :ref:`pullup_conflicts_on_gpio13`, + :ref:`strapping_conflicts_dat2`, :ref:`gpio2_strapping_pin`. -GPIO2 Strapping pin -------------------- + You can tell the version of your ESP23-WROVER-KIT version from the module + on it: v4.1 are with ESP32-WROVER-B modules, v3 are with ESP32-WROVER + modules, while v2 and v1 are with ESP32-WROOM-32 modules. + + - ESP32-LyraTD-MSC: + :ref:`strapping_conflicts_dat2`. Have pullups. + + - ESP32-LyraT: + Have pullups, but :ref:`pullup_conflicts_on_gpio13` + +Non-Espressif Hosts +^^^^^^^^^^^^^^^^^^^ + +Please make sure that your 3rd party SDIO host has correct pullups for all +the signals. + +Solutions +--------- + +.. _sd_pullup_no_pullups: + +No Pullups +^^^^^^^^^^ + +When developing on boards without pullups, you can either: + +1. If your host and slave are on seperated boards, you can change one of them + to a board with pullups. Please see :ref:`sdio_dev_kits` to find Espressif + official boards with pullups. +2. Connect external pullups to VDD by yourself. Connect these pins without + pullups to the VDD through a 10 kOhm resistor. + +.. _pullup_conflicts_on_gpio13: + +Pullup Conflicts on GPIO13 +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The DAT3 of slave may not be properly pulled up. You can either: + +1. Use 1-bit mode, and tie DAT3 of slave to VDD. +2. Use SPI mode. +3. Remove the pulldown resistors on GPIO13; or pull it up by resistor less + than 5 kOhm (2 kOhm suggested); or pull it up or drive it high by host or + VDD3.3V in 1-bit mode. + +.. _strapping_conflicts_dat2: + +Conflicts Between Bootstrap and SDIO on DAT2 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The strapping requirements conflict with SDIO protocol. See +:ref:`mtdi_strapping_pin` for the details of this issue. You can either: + +1. (Recomended) Burn the flash voltage selection eFuses. This will + permanently select 3.3 V output voltage for the internal regulator, and GPIO12 + will not be used as a bootstrapping pin. Then connect a pullup resistor + to GPIO12. + + .. warning:: Burning eFuse is irreversible. The issue list above may be + out of date. Do make sure the module you are burning is using a 3.3 V flash + according to the information on http://www.espressif.com/. If you burn the + 3.3 V eFuses on an 1.8 V module, the module will get broken. + + Run the command below under your IDF folder: + :: + + components/esptool_py/esptool/espefuse.py set_flash_voltage 3.3V + + This command will burn the `XPD_SDIO_TIEH`, `XPD_SDIO_FORCE`, and + `XPD_SDIO_REG` eFuses. With all three burned to value 1, the internal + VDD_SDIO flash voltage regulator is permanently set to 3.3 V. You will + see the following log if the burning succeeds: + :: + + espefuse.py v2.6 + Connecting.... + + Enable internal flash voltage regulator (VDD_SDIO) to 3.3 V. + The following eFuses are burned: XPD_SDIO_FORCE, XPD_SDIO_REG, XPD_SDIO_TIEH. + This is an irreversible operation. + Type 'BURN' (all capitals) to continue. + BURN + VDD_SDIO setting complete. + + You can also run ``components/esptool_py/esptool/espefuse.py summary`` to + check the status of the eFuses above. + + `espefuse.py` has a ``--do-not-confirm`` option if running from an + automated flashing script. + + See the ESP32 Technical Reference Manual for more details. + +2. **When using 1-bit mode or SPI mode**, DAT2 signal is not needed (though it + still has to be pulled up). If the device works as the host, you can leave + the DAT2 of host floating, and directly connect DAT2 of slave to VDD; or if + the device works as the slave, specify ``SDIO_SLAVE_FLAG_DAT2_DISABLED`` in + the slave app to avoid slave detecting on DAT2 line. Note the host will + not know that 4-bit mode is not supported any more by the standard CCCR + register. You have to forbid the host from using 4-bit mode. + +.. _no_pullup_on_gpio12: + +No Pullup on GPIO12 +^^^^^^^^^^^^^^^^^^^ + +Your module is compatible with the SDIO protocol. Just connect GPIO12 to the +VDD through a 10 kOhm resistor. + +.. _gpio2_strapping_pin: + +Auto-program Not Working (minor issue) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GPIO2 pin is used as a bootstrapping pin, and should be low to enter UART download mode. You may find it unable to enter the UART download mode if you -correctly connect the pullup of SD on GPIO2. For WroverKit v3, there are -dedicated circuits to pulldown the GPIO2 when downloading. For other boards, -one way to do this is to connect GPIO0 and GPIO2 using a jumper, and then the -auto-reset circuit on most development boards will pull GPIO2 low along with -GPIO0, when entering download mode. +correctly connect the pullup of SD on GPIO2. -- Some boards have pulldown and/or LED on GPIO2. LED is usually ok, but - pulldown will interfere with D0 signals and must be removed. Check the - schematic of your development board for anything connected to GPIO2. +Some official kits pull down GPIO2 when downloading. For other boards, you +may try to connect GPIO0 and GPIO2 using a jumper, and then the auto-reset +circuit on most development boards will pull GPIO2 low along with GPIO0, when +entering download mode. (Some boards have pulldown and/or LED on GPIO2. LED +is usually ok, but the pulldown resistor will interfere with D0 signals and +must be removed. Check the schematic of your development board for anything +connected to GPIO2.) + +If the above way is not working, please just turn off the other device and +remove the pullups on GPIO2 when you are programming the slave. + + +.. _technical_detail_sdio: + +Technical Details +----------------- + +.. _mtdi_strapping_pin: + +MTDI Strapping Pin +^^^^^^^^^^^^^^^^^^ + +MTDI (GPIO12) is used as a bootstrapping pin to select output voltage of an +internal regulator which powers the flash chip (VDD_SDIO). This pin has an +internal pulldown so if left unconnected it will read low at startup +(selecting default 3.3 V operation). + +For ESP32-WROVER modules, excluding ESP32-WROVER-B, they use 1.8 V flash, and +have pullup on GPIO12 inside. For other modules, which use 3.3 V flash, have +no pullups on GPIO12, and GPIO12 is weakly pulled down internally. + +When adding a pullup to this pin for SD card operation, consider the +following: + +- For boards which don't use the internal regulator (VDD_SDIO) to power the + flash, GPIO12 can be pulled high. +- For boards which use 1.8 V flash chip, GPIO12 needs to be pulled high at + reset. This is fully compatible with SD card operation. +- On boards which use the internal regulator and a 3.3 V flash chip, GPIO12 + must be low at reset. This is incompatible with SD card operation. Please + check :ref:`existing_issues_official_modules_sdio` to see whether your board + has this issue, and how to solve it. + +Internal Pullups and Strapping Requirements +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It is never recommended to rely on internal weak pullups for SDIO +communications, since internal weak pullups are insufficient. But information +of the strapping requirements and internal pullups may be useful. For +Espressif official modules, different weak pullups / pulldowns are connected +to CMD, and DATA pins as below. + ++-----------------------+-----+--------------------------+------+-----------------------+------+ +| GPIO | 15 | 2 | 4 | 12 | 13 | ++=======================+=====+==========================+======+=======================+======+ +| Name | CMD | DAT0 | DAT1 | DAT2 | DAT3 | ++-----------------------+-----+--------------------------+------+-----------------------+------+ +| At startup | WPU | WPD | WPD | PU for 1.8 V flash; | WPU | +| | | | | WPD for 3.3 V flash | | ++-----------------------+-----+--------------------------+------+-----------------------+------+ +| Strapping requirement | | Low to download to flash | | High for 1.8 V flash; | | +| | | | | Low for 3.3 V flash | | ++-----------------------+-----+--------------------------+------+-----------------------+------+ + +- WPU: Weak pullup +- WPD: Weak pulldown +- PU: Pullup inside the module \ No newline at end of file diff --git a/docs/en/api-reference/peripherals/sdio_slave.rst b/docs/en/api-reference/peripherals/sdio_slave.rst index 163cf11681..cd01a51d7c 100644 --- a/docs/en/api-reference/peripherals/sdio_slave.rst +++ b/docs/en/api-reference/peripherals/sdio_slave.rst @@ -8,42 +8,72 @@ The ESP32 SDIO Card peripherals (Host, Slave) shares two sets of pins as below t The first set is usually occupied by SPI0 bus which is responsible for the SPI flash holding the code to run. This means SDIO slave driver can only runs on the second set of pins while SDIO host is not using it. -+----------+-------+-------+ -| Pin Name | Slot1 | Slot2 | -+ +-------+-------+ -| | GPIO Number | -+==========+=======+=======+ -| CLK | 6 | 14 | -+----------+-------+-------+ -| CMD | 11 | 15 | -+----------+-------+-------+ -| DAT0 | 7 | 2 | -+----------+-------+-------+ -| DAT1 | 8 | 4 | -+----------+-------+-------+ -| DAT2 | 9 | 12 | -+----------+-------+-------+ -| DAT3 | 10 | 13 | -+----------+-------+-------+ - The SDIO slave can run under 3 modes: SPI, 1-bit SD and 4-bit SD modes, which is detected automatically by the hardware. According to the SDIO specification, CMD and DAT0-3 lines should be pulled up no matter in 1-bit, -4-bit or SPI mode. Then the host initialize the slave into SD mode by first -sending CMD0 with DAT3 pin high, while initialize the slave into SPI mode by -sending CMD0 with CS pin (the same pin as DAT3) low. +4-bit or SPI mode. -.. note:: CMD and DATA lines D0-D3 of the card should be pulled up by 50KOhm resistor - even in 1-bit mode or SPI mode. Most official devkits don't meet the pullup - requirements by default, and there are conflicts on strapping pins as well. - Please refer to :doc:`sd_pullup_requirements` to see how to setup your - system correctly. +Connections +^^^^^^^^^^^ + ++----------+---------------+-------+-------+ +| Pin Name | Corresponding | Slot1 | Slot2 | ++ + pins in SPI +-------+-------+ +| | mode | GPIO Number | ++==========+===============+=======+=======+ +| CLK | SCLK | 6 | 14 | ++----------+---------------+-------+-------+ +| CMD | MOSI | 11 | 15 | ++----------+---------------+-------+-------+ +| DAT0 | MISO | 7 | 2 | ++----------+---------------+-------+-------+ +| DAT1 | Interrupt | 8 | 4 | ++----------+---------------+-------+-------+ +| DAT2 | N.C. (pullup) | 9 | 12 | ++----------+---------------+-------+-------+ +| DAT3 | #CS | 10 | 13 | ++----------+---------------+-------+-------+ + +- 1-bit SD mode: Connect CLK, CMD, DAT0, DAT1 pins and the ground. +- 4-bit SD mode: Connect all pins and the ground. +- SPI mode: Connect SCLK, MOSI, MISO, Interrupt, #CS pins and the ground. + +.. note:: Please check if CMD and DATA lines D0-D3 of the card are properly + pulled up by 10 KOhm resistors. This should be ensured even in 1-bit mode + or SPI mode. Most official modules don't offer these pullups internally. + If you are using official development boards, check + :ref:`existing_issues_official_modules_sdio` to see whether your + development boards have such pullups. + +.. note:: Most official modules have conflicts on strapping pins with the + SDIO slave function. If you are using a ESP32 module with 3.3 V flash + inside, you have to burn the EFUSE when you are developing on the module + for the first time. See :ref:`existing_issues_official_modules_sdio` to + see how to make your modules compatible with the SDIO. + + Here is a list for modules/kits with 3.3 V flash: + + - Modules: ESP32-PICO-D4, ESP32-WROOM-32 series (including ESP32-SOLO-1), + ESP32-WROVER-B and ESP32-WROVER-IB + - Kits: ESP32-PICO-KIT, ESP32-DevKitC (till v4), ESP32-WROVER-KIT + (v4.1 (also known as ESP32-WROVER-KIT-VB), v2, v1 (also known as DevKitJ + v1)) + + You can tell the version of your ESP23-WROVER-KIT version from the module + on it: v4.1 are with ESP32-WROVER-B modules, v3 are with ESP32-WROVER + modules, while v2 and v1 are with ESP32-WROOM-32 modules. + +Refer to :doc:`sd_pullup_requirements` for more technical details of the pullups. .. toctree:: :hidden: sd_pullup_requirements +The host initialize the slave into SD mode by first sending CMD0 with DAT3 +pin high, or in SPI mode by sending CMD0 with CS pin (the same pin as DAT3) +low. + After the initialization, the host can enable the 4-bit SD mode by writing CCCR register 0x07 by CMD52. All the bus detection process are handled by the slave peripheral. @@ -97,7 +127,7 @@ SDIO initialization process (Sector 3.1.2 of `SDIO Simplified Specification `_), which is described briefly in :ref:`esp_slave_init`. -However, there's an ESP32-specific upper-level communication protocol upon +Furthermore, there's an ESP32-specific upper-level communication protocol upon the CMD52/CMD53 to Func 1. Please refer to :ref:`esp_slave_protocol_layer`, or example :example:`peripherals/sdio` when programming your host. diff --git a/examples/peripherals/sdio/slave/main/Kconfig.projbuild b/examples/peripherals/sdio/slave/main/Kconfig.projbuild index 82a44877a6..b3485bd3c5 100644 --- a/examples/peripherals/sdio/slave/main/Kconfig.projbuild +++ b/examples/peripherals/sdio/slave/main/Kconfig.projbuild @@ -2,7 +2,7 @@ menu "Example Configuration" config SDIO_DAT2_DISABLED bool "Disable the DAT2 in SDIO slave" - default y + default n help SDIO slave DAT pin is unfortunately the same pin as MTDI, which controls the flash power voltage. For 3.3v flash devkits / modules / From 3fd896fe64fabd72530b2140c4cf19d51111e806 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Wed, 17 Apr 2019 12:40:49 +0800 Subject: [PATCH 424/486] sdio_slave: update version read from CCCR to 2.0 --- components/driver/sdio_slave.c | 1 + 1 file changed, 1 insertion(+) diff --git a/components/driver/sdio_slave.c b/components/driver/sdio_slave.c index 0d639d8029..98e4f4ae40 100644 --- a/components/driver/sdio_slave.c +++ b/components/driver/sdio_slave.c @@ -533,6 +533,7 @@ static inline esp_err_t sdio_slave_hw_init(sdio_slave_config_t *config) SLC.rx_dscr_conf.slc0_token_no_replace = 1; HINF.cfg_data1.highspeed_enable = 1; + HINF.cfg_data1.sdio_ver = 0x232; switch(config->timing) { case SDIO_SLAVE_TIMING_PSEND_PSAMPLE: From ab6ad844b152594d7df7d4e23df3ec8397acc176 Mon Sep 17 00:00:00 2001 From: Mahavir Jain Date: Thu, 8 Aug 2019 13:42:47 +0530 Subject: [PATCH 425/486] mbedtls: use `errno` instead of `SO_ERROR` for getting socket errors As per upgrade notes of lwIP v2.1.0: socket API: according to the standard, SO_ERROR now only returns asynchronous errors. All other/normal/synchronous errors are (and always were) available via 'errno'. LWIP_SOCKET_SET_ERRNO has been removed - 'errno' is always set - and required! Refer: https://www.nongnu.org/lwip/2_1_x/upgrading.html Fixes https://github.com/espressif/esp-azure/issues/51 --- components/mbedtls/port/net_sockets.c | 38 ++++++++------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/components/mbedtls/port/net_sockets.c b/components/mbedtls/port/net_sockets.c index 6d8a1cc550..e64510071e 100644 --- a/components/mbedtls/port/net_sockets.c +++ b/components/mbedtls/port/net_sockets.c @@ -59,16 +59,6 @@ static int net_prepare( void ) return ( 0 ); } -static int mbedtls_net_errno(int fd) -{ - int sock_errno = 0; - u32_t optlen = sizeof(sock_errno); - - getsockopt(fd, SOL_SOCKET, SO_ERROR, &sock_errno, &optlen); - - return sock_errno; -} - /* * Initialize a context */ @@ -204,22 +194,19 @@ int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char * * Note: on a blocking socket this function always returns 0! */ -static int net_would_block( const mbedtls_net_context *ctx, int *errout ) +static int net_would_block( const mbedtls_net_context *ctx ) { - int error = mbedtls_net_errno(ctx->fd); - - if ( errout ) { - *errout = error; - } + int error = errno; /* * Never return 'WOULD BLOCK' on a non-blocking socket */ if ( ( fcntl( ctx->fd, F_GETFL, 0) & O_NONBLOCK ) != O_NONBLOCK ) { + errno = error; return ( 0 ); } - switch ( error ) { + switch ( errno = error ) { #if defined EAGAIN case EAGAIN: #endif @@ -267,7 +254,7 @@ int mbedtls_net_accept( mbedtls_net_context *bind_ctx, } if ( ret < 0 ) { - if ( net_would_block( bind_ctx, NULL ) != 0 ) { + if ( net_would_block( bind_ctx ) != 0 ) { return ( MBEDTLS_ERR_SSL_WANT_READ ); } @@ -347,7 +334,6 @@ int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len ) { int ret; int fd = ((mbedtls_net_context *) ctx)->fd; - int error = 0; if ( fd < 0 ) { return ( MBEDTLS_ERR_NET_INVALID_CONTEXT ); @@ -356,15 +342,15 @@ int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len ) ret = (int) read( fd, buf, len ); if ( ret < 0 ) { - if ( net_would_block( ctx, &error ) != 0 ) { + if ( net_would_block( ctx ) != 0 ) { return ( MBEDTLS_ERR_SSL_WANT_READ ); } - if ( error == EPIPE || error == ECONNRESET ) { + if ( errno == EPIPE || errno == ECONNRESET ) { return ( MBEDTLS_ERR_NET_CONN_RESET ); } - if ( error == EINTR ) { + if ( errno == EINTR ) { return ( MBEDTLS_ERR_SSL_WANT_READ ); } @@ -422,8 +408,6 @@ int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len ) int ret; int fd = ((mbedtls_net_context *) ctx)->fd; - int error = 0; - if ( fd < 0 ) { return ( MBEDTLS_ERR_NET_INVALID_CONTEXT ); } @@ -431,15 +415,15 @@ int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len ) ret = (int) write( fd, buf, len ); if ( ret < 0 ) { - if ( net_would_block( ctx, &error ) != 0 ) { + if ( net_would_block( ctx ) != 0 ) { return ( MBEDTLS_ERR_SSL_WANT_WRITE ); } - if ( error == EPIPE || error == ECONNRESET ) { + if ( errno == EPIPE || errno == ECONNRESET ) { return ( MBEDTLS_ERR_NET_CONN_RESET ); } - if ( error == EINTR ) { + if ( errno == EINTR ) { return ( MBEDTLS_ERR_SSL_WANT_WRITE ); } From e5704ab1a8a5a3b95faaed9256c3c3f6fc179a05 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Fri, 2 Aug 2019 13:04:48 +0800 Subject: [PATCH 426/486] esp_flash: fix the set/get write protection functions Add support for get write protection support, fixed the duplicated set_write_protection link. All the write_protection check in the top layer are removed. The lower levels (chip) should ensure to disable write protection before the operation start. --- components/spi_flash/esp_flash_api.c | 30 +++------------ components/spi_flash/include/esp_flash.h | 2 - .../spi_flash/include/spi_flash_chip_driver.h | 7 +--- .../include/spi_flash_chip_generic.h | 14 ++++++- components/spi_flash/spi_flash_chip_generic.c | 38 +++++++++++-------- components/spi_flash/spi_flash_chip_issi.c | 5 +-- components/spi_flash/test/test_esp_flash.c | 33 +++++++++++++++- 7 files changed, 77 insertions(+), 52 deletions(-) diff --git a/components/spi_flash/esp_flash_api.c b/components/spi_flash/esp_flash_api.c index f064bcbdb0..0e16fc80d2 100644 --- a/components/spi_flash/esp_flash_api.c +++ b/components/spi_flash/esp_flash_api.c @@ -265,23 +265,13 @@ esp_err_t IRAM_ATTR esp_flash_erase_chip(esp_flash_t *chip) { VERIFY_OP(erase_chip); CHECK_WRITE_ADDRESS(chip, 0, chip->size); - bool write_protect = false; esp_err_t err = spiflash_start(chip); if (err != ESP_OK) { return err; } - err = esp_flash_get_chip_write_protect(chip, &write_protect); - - if (err == ESP_OK && write_protect) { - err = ESP_ERR_FLASH_PROTECTED; - } - - if (err == ESP_OK) { - err = chip->chip_drv->erase_chip(chip); - } - + err = chip->chip_drv->erase_chip(chip); return spiflash_end(chip, err); } @@ -292,7 +282,6 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui CHECK_WRITE_ADDRESS(chip, start, len); uint32_t block_erase_size = chip->chip_drv->erase_block == NULL ? 0 : chip->chip_drv->block_erase_size; uint32_t sector_size = chip->chip_drv->sector_size; - bool write_protect = false; if (sector_size == 0 || (block_erase_size % sector_size) != 0) { return ESP_ERR_FLASH_NOT_INITIALISED; @@ -310,16 +299,9 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui return err; } - // Check for write protection on whole chip - if (chip->chip_drv->get_chip_write_protect != NULL) { - err = chip->chip_drv->get_chip_write_protect(chip, &write_protect); - if (err == ESP_OK && write_protect) { - err = ESP_ERR_FLASH_PROTECTED; - } - } - // Check for write protected regions overlapping the erase region - if (err == ESP_OK && chip->chip_drv->get_protected_regions != NULL && chip->chip_drv->num_protectable_regions > 0) { + if (chip->chip_drv->get_protected_regions != NULL && + chip->chip_drv->num_protectable_regions > 0) { uint64_t protected = 0; err = chip->chip_drv->get_protected_regions(chip, &protected); if (err == ESP_OK && protected != 0) { @@ -360,10 +342,10 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui return err; } -esp_err_t IRAM_ATTR esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *write_protected) +esp_err_t IRAM_ATTR esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *out_write_protected) { VERIFY_OP(get_chip_write_protect); - if (write_protected == NULL) { + if (out_write_protected == NULL) { return ESP_ERR_INVALID_ARG; } @@ -372,7 +354,7 @@ esp_err_t IRAM_ATTR esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *wr return err; } - err = chip->chip_drv->get_chip_write_protect(chip, write_protected); + err = chip->chip_drv->get_chip_write_protect(chip, out_write_protected); return spiflash_end(chip, err); } diff --git a/components/spi_flash/include/esp_flash.h b/components/spi_flash/include/esp_flash.h index efcfccc247..4a7c184de4 100644 --- a/components/spi_flash/include/esp_flash.h +++ b/components/spi_flash/include/esp_flash.h @@ -160,8 +160,6 @@ esp_err_t esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *write_protec * @note Correct behaviour of this function depends on the SPI flash chip model and chip_drv in use (via the 'chip->drv' * field). * - * If write protection is enabled, destructive operations will fail with ESP_ERR_FLASH_PROTECTED. - * * Some SPI flash chips may require a power cycle before write protect status can be cleared. Otherwise, * write protection can be removed via a follow-up call to this function. * diff --git a/components/spi_flash/include/spi_flash_chip_driver.h b/components/spi_flash/include/spi_flash_chip_driver.h index fd5c1e4c92..9dd8ffa971 100644 --- a/components/spi_flash/include/spi_flash_chip_driver.h +++ b/components/spi_flash/include/spi_flash_chip_driver.h @@ -90,10 +90,10 @@ struct spi_flash_chip_t { uint32_t block_erase_size; /* Optimal (fastest) block size for multi-sector erases on this chip */ /* Read the write protect status of the entire chip. */ - esp_err_t (*get_chip_write_protect)(esp_flash_t *chip, bool *write_protected); + esp_err_t (*get_chip_write_protect)(esp_flash_t *chip, bool *out_write_protected); /* Set the write protect status of the entire chip. */ - esp_err_t (*set_chip_write_protect)(esp_flash_t *chip, bool write_protect_chip); + esp_err_t (*set_chip_write_protect)(esp_flash_t *chip, bool chip_write_protect); /* Number of individually write protectable regions on this chip. Range 0-63. */ uint8_t num_protectable_regions; @@ -135,9 +135,6 @@ struct spi_flash_chip_t { /* Perform an encrypted write to the chip, using internal flash encryption hardware. */ esp_err_t (*write_encrypted)(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length); - /* Set the write enable flag. This function is called internally by other functions in this structure, before a destructive - operation takes place. */ - esp_err_t (*set_write_protect)(esp_flash_t *chip, bool write_protect); /* Wait for the SPI flash chip to be idle (any write operation to be complete.) This function is both called from the higher-level API functions, and from other functions in this structure. diff --git a/components/spi_flash/include/spi_flash_chip_generic.h b/components/spi_flash/include/spi_flash_chip_generic.h index 676e173111..885bd72e75 100644 --- a/components/spi_flash/include/spi_flash_chip_generic.h +++ b/components/spi_flash/include/spi_flash_chip_generic.h @@ -173,7 +173,19 @@ spi_flash_chip_generic_write_encrypted(esp_flash_t *chip, const void *buffer, ui * - ESP_OK if success * - or other error passed from the ``wait_idle``, ``read_status`` or ``set_write_protect`` function of host driver */ -esp_err_t spi_flash_chip_generic_write_enable(esp_flash_t *chip, bool write_protect); +esp_err_t spi_flash_chip_generic_set_write_protect(esp_flash_t *chip, bool write_protect); + +/** + * @brief Check whether WEL (write enable latch) bit is set in the Status Register read from RDSR (05h). + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param out_write_protect Output of whether the write protect is set. + * + * @return + * - ESP_OK if success + * - or other error passed from the ``read_status`` function of host driver + */ +esp_err_t spi_flash_chip_generic_get_write_protect(esp_flash_t *chip, bool *out_write_protect); /** * @brief Read flash status via the RDSR command (05h) and wait for bit 0 (write diff --git a/components/spi_flash/spi_flash_chip_generic.c b/components/spi_flash/spi_flash_chip_generic.c index 0e80e8eb1d..8bbb9d1374 100644 --- a/components/spi_flash/spi_flash_chip_generic.c +++ b/components/spi_flash/spi_flash_chip_generic.c @@ -82,7 +82,7 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip) { esp_err_t err; - err = chip->chip_drv->set_write_protect(chip, false); + err = chip->chip_drv->set_chip_write_protect(chip, false); if (err == ESP_OK) { err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); } @@ -102,7 +102,7 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip) esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_address) { - esp_err_t err = chip->chip_drv->set_write_protect(chip, false); + esp_err_t err = chip->chip_drv->set_chip_write_protect(chip, false); if (err == ESP_OK) { err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); } @@ -122,7 +122,7 @@ esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_ esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_address) { - esp_err_t err = chip->chip_drv->set_write_protect(chip, false); + esp_err_t err = chip->chip_drv->set_chip_write_protect(chip, false); if (err == ESP_OK) { err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); } @@ -185,7 +185,7 @@ esp_err_t spi_flash_chip_generic_write(esp_flash_t *chip, const void *buffer, ui page_len = page_size - (address % page_size); } - err = chip->chip_drv->set_write_protect(chip, false); + err = chip->chip_drv->set_chip_write_protect(chip, false); if (err == ESP_OK) { err = chip->chip_drv->program_page(chip, buffer, address, page_len); @@ -205,7 +205,7 @@ esp_err_t spi_flash_chip_generic_write_encrypted(esp_flash_t *chip, const void * return ESP_ERR_FLASH_UNSUPPORTED_HOST; // TODO } -esp_err_t spi_flash_chip_generic_write_enable(esp_flash_t *chip, bool write_protect) +esp_err_t spi_flash_chip_generic_set_write_protect(esp_flash_t *chip, bool write_protect) { esp_err_t err = ESP_OK; @@ -215,17 +215,26 @@ esp_err_t spi_flash_chip_generic_write_enable(esp_flash_t *chip, bool write_prot chip->host->set_write_protect(chip->host, write_protect); } + bool wp_read; + err = chip->chip_drv->get_chip_write_protect(chip, &wp_read); + if (err == ESP_OK && wp_read != write_protect) { + // WREN flag has not been set! + err = ESP_ERR_NOT_FOUND; + } + return err; +} + +esp_err_t spi_flash_chip_generic_get_write_protect(esp_flash_t *chip, bool *out_write_protect) +{ + esp_err_t err = ESP_OK; uint8_t status; + assert(out_write_protect!=NULL); err = chip->host->read_status(chip->host, &status); if (err != ESP_OK) { return err; } - if ((status & SR_WREN) == 0) { - // WREN flag has not been set! - err = ESP_ERR_NOT_FOUND; - } - + *out_write_protect = ((status & SR_WREN) == 0); return err; } @@ -329,7 +338,7 @@ esp_err_t spi_flash_common_set_read_mode(esp_flash_t *chip, uint8_t qe_rdsr_comm ESP_EARLY_LOGV(TAG, "set_read_mode: status before 0x%x", sr); if ((sr & qe_sr_bit) == 0) { //some chips needs the write protect to be disabled before writing to Status Register - chip->chip_drv->set_write_protect(chip, false); + chip->chip_drv->set_chip_write_protect(chip, false); sr |= qe_sr_bit; spi_flash_trans_t t = { @@ -354,7 +363,7 @@ esp_err_t spi_flash_common_set_read_mode(esp_flash_t *chip, uint8_t qe_rdsr_comm return ESP_ERR_FLASH_NO_RESPONSE; } - chip->chip_drv->set_write_protect(chip, true); + chip->chip_drv->set_chip_write_protect(chip, true); } } return ESP_OK; @@ -383,8 +392,8 @@ const spi_flash_chip_t esp_flash_chip_generic = { .block_erase_size = 64 * 1024, // TODO: figure out if generic chip-wide protection bits exist across some manufacturers - .get_chip_write_protect = NULL, - .set_chip_write_protect = NULL, + .get_chip_write_protect = spi_flash_chip_generic_get_write_protect, + .set_chip_write_protect = spi_flash_chip_generic_set_write_protect, // Chip write protection regions do not appear to be standardised // at all, this is implemented in chip-specific drivers only. @@ -399,7 +408,6 @@ const spi_flash_chip_t esp_flash_chip_generic = { .page_size = 256, .write_encrypted = spi_flash_chip_generic_write_encrypted, - .set_write_protect = spi_flash_chip_generic_write_enable, .wait_idle = spi_flash_chip_generic_wait_idle, .set_read_mode = spi_flash_chip_generic_set_read_mode, }; diff --git a/components/spi_flash/spi_flash_chip_issi.c b/components/spi_flash/spi_flash_chip_issi.c index d32c3a1929..d0b025637f 100644 --- a/components/spi_flash/spi_flash_chip_issi.c +++ b/components/spi_flash/spi_flash_chip_issi.c @@ -58,8 +58,8 @@ const spi_flash_chip_t esp_flash_chip_issi = { .block_erase_size = 64 * 1024, // TODO: support get/set chip write protect for ISSI flash - .get_chip_write_protect = NULL, - .set_chip_write_protect = NULL, + .get_chip_write_protect = spi_flash_chip_generic_get_write_protect, + .set_chip_write_protect = spi_flash_chip_generic_set_write_protect, // TODO support protected regions on ISSI flash .num_protectable_regions = 0, @@ -73,7 +73,6 @@ const spi_flash_chip_t esp_flash_chip_issi = { .page_size = 256, .write_encrypted = spi_flash_chip_generic_write_encrypted, - .set_write_protect = spi_flash_chip_generic_write_enable, .wait_idle = spi_flash_chip_generic_wait_idle, .set_read_mode = spi_flash_chip_issi_set_read_mode, }; diff --git a/components/spi_flash/test/test_esp_flash.c b/components/spi_flash/test/test_esp_flash.c index 49d144c9c1..19a93c8bf4 100644 --- a/components/spi_flash/test/test_esp_flash.c +++ b/components/spi_flash/test/test_esp_flash.c @@ -366,6 +366,36 @@ TEST_CASE("SPI flash erase large region", "[esp_flash]") #endif } +static void test_write_protection(esp_flash_t* chip) +{ + bool wp = true; + esp_err_t ret = ESP_OK; + ret = esp_flash_get_chip_write_protect(chip, &wp); + TEST_ESP_OK(ret); + + for (int i = 0; i < 4; i ++) { + bool wp_write = !wp; + ret = esp_flash_set_chip_write_protect(chip, wp_write); + TEST_ESP_OK(ret); + + bool wp_read; + ret = esp_flash_get_chip_write_protect(chip, &wp_read); + TEST_ESP_OK(ret); + TEST_ASSERT(wp_read == wp_write); + wp = wp_read; + } +} + +TEST_CASE("Test esp_flash can enable/disable write protetion", "[esp_flash]") +{ + test_write_protection(NULL); +#ifndef SKIP_EXTENDED_CHIP_TEST + setup_new_chip(TEST_SPI_READ_MODE, TEST_SPI_SPEED); + test_write_protection(test_chip); + teardown_test_chip(); +#endif +} + static const uint8_t large_const_buffer[16400] = { 203, // first byte 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, @@ -491,5 +521,4 @@ static void test_write_large_buffer(esp_flash_t *chip, const uint8_t *source, si write_large_buffer(chip, part, source, length); read_and_check(chip, part, source, length); -} - +} \ No newline at end of file From e947522f3875806c61cac46580e35004e049d86a Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Sat, 3 Aug 2019 09:59:10 +0800 Subject: [PATCH 427/486] esp_flash: improve the comments a bit --- components/soc/include/hal/spi_flash_hal.h | 15 +++++--- .../spi_flash/include/memspi_host_driver.h | 2 + .../include/spi_flash_chip_generic.h | 37 +++++++++++-------- components/spi_flash/spi_flash_chip_issi.c | 1 - 4 files changed, 33 insertions(+), 22 deletions(-) diff --git a/components/soc/include/hal/spi_flash_hal.h b/components/soc/include/hal/spi_flash_hal.h index 3a18e4ca5f..bf89c41488 100644 --- a/components/soc/include/hal/spi_flash_hal.h +++ b/components/soc/include/hal/spi_flash_hal.h @@ -88,14 +88,15 @@ esp_err_t spi_flash_hal_device_config(spi_flash_host_driver_t *driver); esp_err_t spi_flash_hal_common_command(spi_flash_host_driver_t *driver, spi_flash_trans_t *trans); /** - * Erase whole flash chip. + * Erase whole flash chip by using the erase chip (C7h) command. * * @param driver The driver context. */ void spi_flash_hal_erase_chip(spi_flash_host_driver_t *driver); /** - * Erase a specific sector by its start address. + * Erase a specific sector by its start address through the sector erase (20h) + * command. * * @param driver The driver context. * @param start_address Start address of the sector to erase. @@ -103,7 +104,8 @@ void spi_flash_hal_erase_chip(spi_flash_host_driver_t *driver); void spi_flash_hal_erase_sector(spi_flash_host_driver_t *driver, uint32_t start_address); /** - * Erase a specific block by its start address. + * Erase a specific 64KB block by its start address through the 64KB block + * erase (D8h) command. * * @param driver The driver context. * @param start_address Start address of the block to erase. @@ -111,7 +113,7 @@ void spi_flash_hal_erase_sector(spi_flash_host_driver_t *driver, uint32_t start_ void spi_flash_hal_erase_block(spi_flash_host_driver_t *driver, uint32_t start_address); /** - * Program a page of the flash. + * Program a page of the flash using the page program (02h) command. * * @param driver The driver context. * @param address Address of the page to program @@ -121,7 +123,8 @@ void spi_flash_hal_erase_block(spi_flash_host_driver_t *driver, uint32_t start_a void spi_flash_hal_program_page(spi_flash_host_driver_t *driver, const void *buffer, uint32_t address, uint32_t length); /** - * Read from the flash. The read command should be set by ``spi_flash_hal_configure_host_read_mode`` before. + * Read from the flash. Call ``spi_flash_hal_configure_host_read_mode`` to + * configure the read command before calling this function. * * @param driver The driver context. * @param buffer Buffer to store the read data @@ -133,7 +136,7 @@ void spi_flash_hal_program_page(spi_flash_host_driver_t *driver, const void *buf esp_err_t spi_flash_hal_read(spi_flash_host_driver_t *driver, void *buffer, uint32_t address, uint32_t read_len); /** - * Enable or disable the write protection of the flash chip. + * @brief Send the write enable (06h) or write disable (04h) command to the flash chip. * * @param driver The driver context. * @param wp true to enable the write protection, otherwise false. diff --git a/components/spi_flash/include/memspi_host_driver.h b/components/spi_flash/include/memspi_host_driver.h index 2347398aa1..434361d970 100644 --- a/components/spi_flash/include/memspi_host_driver.h +++ b/components/spi_flash/include/memspi_host_driver.h @@ -62,6 +62,8 @@ esp_err_t memspi_host_init_pointers(spi_flash_host_driver_t *host, memspi_host_d ******************************************************************************/ /** + * @brief Read the Status Register read from RDSR (05h). + * * High speed implementation of RDID through memspi interface relying on the * ``common_command``. * diff --git a/components/spi_flash/include/spi_flash_chip_generic.h b/components/spi_flash/include/spi_flash_chip_generic.h index 885bd72e75..672ca6550b 100644 --- a/components/spi_flash/include/spi_flash_chip_generic.h +++ b/components/spi_flash/include/spi_flash_chip_generic.h @@ -66,7 +66,7 @@ esp_err_t spi_flash_chip_generic_reset(esp_flash_t *chip); esp_err_t spi_flash_chip_generic_detect_size(esp_flash_t *chip, uint32_t *size); /** - * @brief Erase chip by using the generic erase chip (C7h) command. + * @brief Erase chip by using the generic erase chip command. * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. * @@ -77,7 +77,7 @@ esp_err_t spi_flash_chip_generic_detect_size(esp_flash_t *chip, uint32_t *size); esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip); /** - * @brief Erase sector by using the generic sector erase (20h) command. + * @brief Erase sector by using the generic sector erase command. * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. * @param start_address Start address of the sector to erase @@ -89,7 +89,7 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip); esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_address); /** - * @brief Erase block by using the generic 64KB block erase (D8h) command + * @brief Erase block by the generic 64KB block erase command * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. * @param start_address Start address of the block to erase @@ -114,7 +114,7 @@ esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_a esp_err_t spi_flash_chip_generic_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length); /** - * @brief Perform a page program using the page program (02h) command. + * @brief Perform a page program using the page program command. * * @note Length of each call should not excced the limitation in * ``chip->host->max_write_bytes``. This function is called in @@ -163,7 +163,7 @@ esp_err_t spi_flash_chip_generic_write_encrypted(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length); /** - * @brief Send the write enable (06h) command and verify the expected bit (1) in + * @brief Send the write enable or write disable command and verify the expected bit (1) in * the status register is set. * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. @@ -171,12 +171,13 @@ spi_flash_chip_generic_write_encrypted(esp_flash_t *chip, const void *buffer, ui * * @return * - ESP_OK if success - * - or other error passed from the ``wait_idle``, ``read_status`` or ``set_write_protect`` function of host driver + * - or other error passed from the ``wait_idle``, ``read_status`` or + * ``set_write_protect`` function of host driver */ esp_err_t spi_flash_chip_generic_set_write_protect(esp_flash_t *chip, bool write_protect); /** - * @brief Check whether WEL (write enable latch) bit is set in the Status Register read from RDSR (05h). + * @brief Check whether WEL (write enable latch) bit is set in the Status Register read from RDSR. * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. * @param out_write_protect Output of whether the write protect is set. @@ -188,8 +189,8 @@ esp_err_t spi_flash_chip_generic_set_write_protect(esp_flash_t *chip, bool write esp_err_t spi_flash_chip_generic_get_write_protect(esp_flash_t *chip, bool *out_write_protect); /** - * @brief Read flash status via the RDSR command (05h) and wait for bit 0 (write - * in progress bit) to be cleared. + * @brief Read flash status via the RDSR command and wait for bit 0 (write in + * progress bit) to be cleared. * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. * @param timeout_ms Time to wait before timeout, in ms. @@ -244,13 +245,15 @@ extern const spi_flash_chip_t esp_flash_chip_generic; esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_ms); /** - * @brief Utility function for set_read_mode chip_drv function + * @brief Utility function for set_read_mode chip_drv function. If required, + * set and check the QE bit in the flash chip to enable the QIO/QOUT mode. * - * Most setting of read mode follows a common pattern, except for how to enable Quad I/O modes (QIO/QOUT). - * These use different commands to read/write the status register, and a different bit is set/cleared. + * Most chip QE enable follows a common pattern, though commands to read/write + * the status register may be different, as well as the position of QE bit. * - * This is a generic utility function to implement set_read_mode() for this pattern. Also configures host - * registers via spi_flash_common_configure_host_read_mode(). + * Registers to actually do Quad transtions and command to be sent in reading + * should also be configured via + * spi_flash_chip_generic_config_host_read_mode(). * * @param qe_rdsr_command SPI flash command to read status register * @param qe_wrsr_command SPI flash command to write status register @@ -262,7 +265,11 @@ esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_ esp_err_t spi_flash_common_set_read_mode(esp_flash_t *chip, uint8_t qe_rdsr_command, uint8_t qe_wrsr_command, uint8_t qe_sr_bitwidth, unsigned qe_sr_bit); /** - * @brief Configure the host to use the specified read mode set in the ``chip->read_mode``. + * @brief Configure the host registers to use the specified read mode set in + * the ``chip->read_mode``. + * + * Usually called in chip_drv read() functions before actual reading + * transactions. Also prepare the command to be sent in read functions. * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. * diff --git a/components/spi_flash/spi_flash_chip_issi.c b/components/spi_flash/spi_flash_chip_issi.c index d0b025637f..71684ec195 100644 --- a/components/spi_flash/spi_flash_chip_issi.c +++ b/components/spi_flash/spi_flash_chip_issi.c @@ -57,7 +57,6 @@ const spi_flash_chip_t esp_flash_chip_issi = { .sector_size = 4 * 1024, .block_erase_size = 64 * 1024, - // TODO: support get/set chip write protect for ISSI flash .get_chip_write_protect = spi_flash_chip_generic_get_write_protect, .set_chip_write_protect = spi_flash_chip_generic_set_write_protect, From 08de39c226a85647207e9bf1a87e44ea79e9da26 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Tue, 6 Aug 2019 10:59:48 +0800 Subject: [PATCH 428/486] cmake: check include directories --- tools/cmake/component.cmake | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/tools/cmake/component.cmake b/tools/cmake/component.cmake index 6959af26c2..8de4cc4c19 100644 --- a/tools/cmake/component.cmake +++ b/tools/cmake/component.cmake @@ -232,10 +232,10 @@ function(__component_get_requirements) file(REMOVE ${component_requires_file}) endfunction() -# __component_add_sources, __component_check_target +# __component_add_sources, __component_check_target, __component_add_include_dirs # -# Utility macros for component registration. Adds source files and checks target requirements -# respectively. +# Utility macros for component registration. Adds source files and checks target requirements, +# and adds include directories respectively. macro(__component_add_sources sources) set(sources "") if(__SRCS) @@ -279,6 +279,16 @@ macro(__component_add_sources sources) list(REMOVE_DUPLICATES sources) endmacro() +macro(__component_add_include_dirs lib dirs type) + foreach(dir ${dirs}) + get_filename_component(_dir ${dir} ABSOLUTE BASE_DIR ${CMAKE_CURRENT_LIST_DIR}) + if(NOT IS_DIRECTORY ${_dir}) + message(FATAL_ERROR "Include directory '${_dir}' is not a directory.") + endif() + target_include_directories(${lib} ${type} ${_dir}) + endforeach() +endmacro() + macro(__component_check_target) if(__REQUIRED_IDF_TARGETS) idf_build_get_property(idf_target IDF_TARGET) @@ -324,6 +334,7 @@ macro(__component_set_all_dependencies) endif() endmacro() + # idf_component_get_property # # @brief Retrieve the value of the specified component property @@ -436,16 +447,16 @@ function(idf_component_register) if(sources OR __EMBED_FILES OR __EMBED_TXTFILES) add_library(${component_lib} STATIC ${sources}) __component_set_property(${component_target} COMPONENT_TYPE LIBRARY) - target_include_directories(${component_lib} PUBLIC ${__INCLUDE_DIRS}) - target_include_directories(${component_lib} PRIVATE ${__PRIV_INCLUDE_DIRS}) - target_include_directories(${component_lib} PUBLIC ${config_dir}) + __component_add_include_dirs(${component_lib} "${__INCLUDE_DIRS}" PUBLIC) + __component_add_include_dirs(${component_lib} "${__PRIV_INCLUDE_DIRS}" PRIVATE) + __component_add_include_dirs(${component_lib} "${config_dir}" PUBLIC) set_target_properties(${component_lib} PROPERTIES OUTPUT_NAME ${COMPONENT_NAME}) __ldgen_add_component(${component_lib}) else() add_library(${component_lib} INTERFACE) __component_set_property(${component_target} COMPONENT_TYPE CONFIG_ONLY) - target_include_directories(${component_lib} INTERFACE ${__INCLUDE_DIRS}) - target_include_directories(${component_lib} INTERFACE ${config_dir}) + __component_add_include_dirs(${component_lib} "${__INCLUDE_DIRS}" INTERFACE) + __component_add_include_dirs(${component_lib} "${config_dir}" INTERFACE) endif() # Alias the static/interface library created for linking to external targets. From 4dd2b9edb15246cde9e37ea3d69de6d2fac39483 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Tue, 6 Aug 2019 11:00:37 +0800 Subject: [PATCH 429/486] components: fix incorrect include dir args --- components/esp-tls/CMakeLists.txt | 2 +- components/tcp_transport/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esp-tls/CMakeLists.txt b/components/esp-tls/CMakeLists.txt index f6cc17c801..ea6b61216e 100644 --- a/components/esp-tls/CMakeLists.txt +++ b/components/esp-tls/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register(SRCS "esp_tls.c" INCLUDE_DIRS "." - PRIVATE_INCLUDE_DIRS "private_include" + PRIV_INCLUDE_DIRS "private_include" REQUIRES mbedtls PRIV_REQUIRES lwip nghttp) diff --git a/components/tcp_transport/CMakeLists.txt b/components/tcp_transport/CMakeLists.txt index 9d5028a1b6..fe7e71bf31 100644 --- a/components/tcp_transport/CMakeLists.txt +++ b/components/tcp_transport/CMakeLists.txt @@ -5,5 +5,5 @@ idf_component_register(SRCS "transport.c" "transport_utils.c" "transport_strcasestr.c" INCLUDE_DIRS "include" - PRIVATE_INCLUDE_DIRS "private_include" + PRIV_INCLUDE_DIRS "private_include" REQUIRES lwip esp-tls) From d47288d9db9de027bf77774cce4acbd531244f9d Mon Sep 17 00:00:00 2001 From: Soumesh Banerjee Date: Fri, 9 Aug 2019 10:07:22 +0800 Subject: [PATCH 430/486] :bug: Fix the white space bug in docs Fix only the visual rendering the issue for selection of text still remains and have to be solved by updating the html generator Closes #3208 --- docs/_static/theme_overrides.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/_static/theme_overrides.css b/docs/_static/theme_overrides.css index df1cdd4425..011488e79e 100644 --- a/docs/_static/theme_overrides.css +++ b/docs/_static/theme_overrides.css @@ -40,3 +40,7 @@ a:hover { .logo { width: 240px !important; } + +a.internal::after{ + content: ' '; +} From b413a240cb70c1b9dfa946a368684276a44bd37e Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Mon, 29 Jul 2019 14:31:30 +0800 Subject: [PATCH 431/486] esp_attr: support force_inline --- components/esp32/include/esp_attr.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/esp32/include/esp_attr.h b/components/esp32/include/esp_attr.h index 7a3ec771d1..58fef76c71 100644 --- a/components/esp32/include/esp_attr.h +++ b/components/esp32/include/esp_attr.h @@ -34,6 +34,9 @@ // Forces data to be placed to DMA-capable places #define DMA_ATTR WORD_ALIGNED_ATTR DRAM_ATTR +// Forces a function to be inlined +#define FORCE_INLINE_ATTR static inline __attribute__((always_inline)) + // Forces a string into DRAM instead of flash // Use as ets_printf(DRAM_STR("Hello world!\n")); #define DRAM_STR(str) (__extension__({static const DRAM_ATTR char __c[] = (str); (const char *)&__c;})) @@ -45,7 +48,7 @@ // Forces bss variable into external memory. " #define EXT_RAM_ATTR _SECTION_ATTR_IMPL(".ext_ram.bss", __COUNTER__) #else -#define EXT_RAM_ATTR +#define EXT_RAM_ATTR #endif // Forces data into RTC slow memory. See "docs/deep-sleep-stub.rst" From a97fe5615f7e76b194c3d9328cf66f722b5e3b13 Mon Sep 17 00:00:00 2001 From: chenjianqiang Date: Mon, 15 Jul 2019 14:21:36 +0800 Subject: [PATCH 432/486] feat(timer): refator timer group driver (partly pick) --- components/driver/include/driver/timer.h | 18 +-- components/soc/esp32/include/hal/timer_ll.h | 133 ++++++++++++++++++++ components/soc/include/hal/timer_types.h | 44 +++++++ 3 files changed, 178 insertions(+), 17 deletions(-) create mode 100644 components/soc/esp32/include/hal/timer_ll.h create mode 100644 components/soc/include/hal/timer_types.h diff --git a/components/driver/include/driver/timer.h b/components/driver/include/driver/timer.h index cbf2a5bd23..cdff8a1b43 100644 --- a/components/driver/include/driver/timer.h +++ b/components/driver/include/driver/timer.h @@ -19,6 +19,7 @@ #include "soc/soc.h" #include "soc/timer_periph.h" #include "esp_intr_alloc.h" +#include "hal/timer_types.h" #ifdef __cplusplus extern "C" { @@ -36,15 +37,6 @@ typedef enum { TIMER_GROUP_MAX, } timer_group_t; -/** - * @brief Select a hardware timer from timer groups - */ -typedef enum { - TIMER_0 = 0, /*! Date: Thu, 25 Jul 2019 09:52:36 +0800 Subject: [PATCH 433/486] timer_group: support interrupt LL and some utility functions in ISR --- components/driver/include/driver/timer.h | 72 +++++++++++++++++---- components/driver/timer.c | 53 +++++++++++++-- components/soc/esp32/include/hal/timer_ll.h | 62 +++++++++++++++++- components/soc/include/hal/timer_types.h | 12 ++++ 4 files changed, 178 insertions(+), 21 deletions(-) diff --git a/components/driver/include/driver/timer.h b/components/driver/include/driver/timer.h index cdff8a1b43..6ab7e10958 100644 --- a/components/driver/include/driver/timer.h +++ b/components/driver/include/driver/timer.h @@ -246,9 +246,9 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_ * @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will * be returned here. * - * @note If the intr_alloc_flags value ESP_INTR_FLAG_IRAM is set, - * the handler function must be declared with IRAM_ATTR attribute - * and can only call functions in IRAM or ROM. It cannot call other timer APIs. + * @note If the intr_alloc_flags value ESP_INTR_FLAG_IRAM is set, + * the handler function must be declared with IRAM_ATTR attribute + * and can only call functions in IRAM or ROM. It cannot call other timer APIs. * Use direct register access to configure timers from inside the ISR in this case. * * @return @@ -258,7 +258,7 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_ esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, void (*fn)(void*), void * arg, int intr_alloc_flags, timer_isr_handle_t *handle); /** @brief Initializes and configure the timer. - * + * * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1 * @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1] * @param config Pointer to timer initialization parameters. @@ -284,28 +284,30 @@ esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer /** @brief Enable timer group interrupt, by enable mask * * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1 - * @param en_mask Timer interrupt enable mask. - * Use TIMG_T0_INT_ENA_M to enable t0 interrupt - * Use TIMG_T1_INT_ENA_M to enable t1 interrupt + * @param intr_mask Timer interrupt enable mask. + * - TIMER_INTR_T0: t0 interrupt + * - TIMER_INTR_T1: t1 interrupt + * - TIMER_INTR_WDT: watchdog interrupt * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error */ -esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask); +esp_err_t timer_group_intr_enable(timer_group_t group_num, timer_intr_t intr_mask); /** @brief Disable timer group interrupt, by disable mask * * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1 - * @param disable_mask Timer interrupt disable mask. - * Use TIMG_T0_INT_ENA_M to disable t0 interrupt - * Use TIMG_T1_INT_ENA_M to disable t1 interrupt + * @param intr_mask Timer interrupt disable mask. + * - TIMER_INTR_T0: t0 interrupt + * - TIMER_INTR_T1: t1 interrupt + * - TIMER_INTR_WDT: watchdog interrupt * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error */ -esp_err_t timer_group_intr_disable(timer_group_t group_num, uint32_t disable_mask); +esp_err_t timer_group_intr_disable(timer_group_t group_num, timer_intr_t intr_mask); /** @brief Enable timer interrupt * @@ -329,6 +331,52 @@ esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num); */ esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num); +/** @cond */ +/* Utilities functions that can be used in the ISR */ +/* Preview, don't treat them as stable API. */ + +/** + * Clear interrupt status bit. + */ +void timer_group_intr_clr_in_isr(timer_group_t group_num, timer_idx_t timer_num); + +/** + * Enable alarm. + */ +void timer_group_enable_alarm_in_isr(timer_group_t group_num, timer_idx_t timer_num); + +/** + * Get the current counter value. + */ +uint64_t timer_group_get_counter_value_in_isr(timer_group_t group_num, timer_idx_t timer_num); + +/** + * Set the alarm threshold for the timer. + */ +void timer_group_set_alarm_value_in_isr(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_val); + +/** + * Enable/disable a counter. + */ +void timer_group_set_counter_enable_in_isr(timer_group_t group_num, timer_idx_t timer_num, timer_start_t counter_en); + +/** + * Get the masked interrupt status. + */ +timer_intr_t timer_group_intr_get_in_isr(timer_group_t group_num); + +/** + * Clear interrupt. + */ +void timer_group_clr_intr_sta_in_isr(timer_group_t group_num, timer_intr_t intr_mask); + +/** + * Get auto reload enable status. + */ +bool timer_group_get_auto_reload_in_isr(timer_group_t group_num, timer_idx_t timer_num); + +/** @endcond */ + #ifdef __cplusplus } #endif diff --git a/components/driver/timer.c b/components/driver/timer.c index 6a82d87fa9..67f0fffb32 100644 --- a/components/driver/timer.c +++ b/components/driver/timer.c @@ -19,6 +19,7 @@ #include "freertos/xtensa_api.h" #include "driver/timer.h" #include "driver/periph_ctrl.h" +#include "hal/timer_ll.h" static const char* TIMER_TAG = "timer_group"; #define TIMER_CHECK(a, str, ret_val) \ @@ -35,7 +36,7 @@ static const char* TIMER_TAG = "timer_group"; #define TIMER_SCALE_ERROR "HW TIMER SCALE ERROR" #define TIMER_ALARM_ERROR "HW TIMER ALARM ERROR" #define DIVIDER_RANGE_ERROR "HW TIMER divider outside of [2, 65536] range error" -static timg_dev_t *TG[2] = {&TIMERG0, &TIMERG1}; +DRAM_ATTR static timg_dev_t *TG[2] = {&TIMERG0, &TIMERG1}; static portMUX_TYPE timer_spinlock[TIMER_GROUP_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED}; #define TIMER_ENTER_CRITICAL(mux) portENTER_CRITICAL_SAFE(mux); @@ -171,7 +172,7 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_ return ESP_OK; } -esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, +esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, void (*fn)(void*), void * arg, int intr_alloc_flags, timer_isr_handle_t *handle) { TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG); @@ -253,7 +254,7 @@ esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer return ESP_OK; } -esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask) +esp_err_t timer_group_intr_enable(timer_group_t group_num, timer_intr_t en_mask) { TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&timer_spinlock[group_num]); @@ -262,7 +263,7 @@ esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask) return ESP_OK; } -esp_err_t timer_group_intr_disable(timer_group_t group_num, uint32_t disable_mask) +esp_err_t timer_group_intr_disable(timer_group_t group_num, timer_intr_t disable_mask) { TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&timer_spinlock[group_num]); @@ -275,14 +276,54 @@ esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num) { TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG); TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG); - return timer_group_intr_enable(group_num, BIT(timer_num)); + return timer_group_intr_enable(group_num, TIMER_LL_GET_INTR(timer_num)); } esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num) { TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG); TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG); - return timer_group_intr_disable(group_num, BIT(timer_num)); + return timer_group_intr_disable(group_num, TIMER_LL_GET_INTR(timer_num)); } +timer_intr_t IRAM_ATTR timer_group_intr_get_in_isr(timer_group_t group_num) +{ + return timer_ll_intr_status_get(TG[group_num]); +} +void IRAM_ATTR timer_group_intr_clr_in_isr(timer_group_t group_num, timer_idx_t timer_num) +{ + timer_ll_intr_status_clear(TG[group_num], TIMER_LL_GET_INTR(timer_num)); +} + +void IRAM_ATTR timer_group_enable_alarm_in_isr(timer_group_t group_num, timer_idx_t timer_num) +{ + timer_ll_set_alarm_enable(TG[group_num], timer_num, true); +} + +uint64_t IRAM_ATTR timer_group_get_counter_value_in_isr(timer_group_t group_num, timer_idx_t timer_num) +{ + uint64_t val; + timer_ll_get_counter_value(TG[group_num], timer_num, &val); + return val; +} + +void IRAM_ATTR timer_group_set_alarm_value_in_isr(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_val) +{ + timer_ll_set_alarm_value(TG[group_num], timer_num, alarm_val); +} + +void IRAM_ATTR timer_group_set_counter_enable_in_isr(timer_group_t group_num, timer_idx_t timer_num, timer_start_t counter_en) +{ + timer_ll_set_counter_enable(TG[group_num], timer_num, counter_en); +} + +void IRAM_ATTR timer_group_clr_intr_sta_in_isr(timer_group_t group_num, timer_intr_t intr_mask) +{ + timer_ll_intr_status_clear(TG[group_num], intr_mask); +} + +bool IRAM_ATTR timer_group_get_auto_reload_in_isr(timer_group_t group_num, timer_idx_t timer_num) +{ + return timer_ll_get_auto_reload(TG[group_num], timer_num); +} diff --git a/components/soc/esp32/include/hal/timer_ll.h b/components/soc/esp32/include/hal/timer_ll.h index cc0cd69c52..d74c00ee7b 100644 --- a/components/soc/esp32/include/hal/timer_ll.h +++ b/components/soc/esp32/include/hal/timer_ll.h @@ -24,6 +24,65 @@ extern "C" { #include "hal/timer_types.h" #include "soc/timer_periph.h" +//Helper macro to get corresponding interrupt of a timer +#define TIMER_LL_GET_INTR(TIMER_IDX) ((TIMER_IDX)==TIMER_0? TIMER_INTR_T0: TIMER_INTR_T1) + +#define TIMER_LL_GET_HW(TIMER_GROUP) ((TIMER_GROUP)==0? &TIMERG0: &TIMERG1) + +_Static_assert(TIMER_INTR_T0 == TIMG_T0_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); +_Static_assert(TIMER_INTR_T1 == TIMG_T1_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); +_Static_assert(TIMER_INTR_WDT == TIMG_WDT_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); + +/** + * @brief Enable timer interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param intr_mask Interrupt enable mask + * + * @return None + */ +static inline void timer_ll_intr_enable(timg_dev_t *hw, timer_intr_t intr_mask) +{ + hw->int_ena.val |= intr_mask; +} + +/** + * @brief Disable timer interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param intr_mask Interrupt disable mask + * + * @return None + */ +static inline void timer_ll_intr_disable(timg_dev_t *hw, timer_intr_t intr_mask) +{ + hw->int_ena.val &= (~intr_mask); +} + +/** + * @brief Get timer interrupt status. + * + * @param hw Beginning address of the peripheral registers. + * + * @return Masked interrupt status + */ +static inline timer_intr_t timer_ll_intr_status_get(timg_dev_t *hw) +{ + return hw->int_raw.val; +} + +/** + * @brief Clear timer interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param intr_mask Interrupt mask to clear + * + * @return None + */ +static inline void timer_ll_intr_status_clear(timg_dev_t *hw, timer_intr_t intr_mask) +{ + hw->int_clr_timers.val = intr_mask; +} /** * @brief Get counter vaule from time-base counter @@ -40,8 +99,6 @@ static inline void timer_ll_get_counter_value(timg_dev_t *hw, timer_idx_t timer_ *timer_val = ((uint64_t) hw->hw_timer[timer_num].cnt_high << 32) | (hw->hw_timer[timer_num].cnt_low); } - - /** * @brief Set counter status, enable or disable counter. * @@ -56,7 +113,6 @@ static inline void timer_ll_set_counter_enable(timg_dev_t *hw, timer_idx_t timer hw->hw_timer[timer_num].config.enable = counter_en; } - /** * @brief Get auto reload mode. * diff --git a/components/soc/include/hal/timer_types.h b/components/soc/include/hal/timer_types.h index d555a2115e..f1564eee9d 100644 --- a/components/soc/include/hal/timer_types.h +++ b/components/soc/include/hal/timer_types.h @@ -20,6 +20,8 @@ extern "C" { #include #include +#include + /** * @brief Select a hardware timer from timer groups @@ -39,6 +41,16 @@ typedef enum { } timer_start_t; +/** + * @brief Interrupt types of the timer. + */ +//this is compatible with the value of esp32. +typedef enum { + TIMER_INTR_T0 = BIT(0), /*!< interrupt of timer 0 */ + TIMER_INTR_T1 = BIT(1), /*!< interrupt of timer 1 */ + TIMER_INTR_WDT = BIT(2), /*!< interrupt of watchdog */ +} timer_intr_t; + #ifdef __cplusplus } #endif From feea477023ccaa2ae05014ce083a7350fd04b1ae Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Tue, 30 Jul 2019 17:22:51 +0800 Subject: [PATCH 434/486] timer_group: add LL functions for WDT --- components/soc/esp32/include/hal/timer_ll.h | 96 +++++++++++++++++++++ components/soc/include/hal/timer_types.h | 11 +++ 2 files changed, 107 insertions(+) diff --git a/components/soc/esp32/include/hal/timer_ll.h b/components/soc/esp32/include/hal/timer_ll.h index d74c00ee7b..f4fa09d942 100644 --- a/components/soc/esp32/include/hal/timer_ll.h +++ b/components/soc/esp32/include/hal/timer_ll.h @@ -184,6 +184,102 @@ static inline void timer_ll_get_alarm_enable(timg_dev_t *hw, timer_idx_t timer_n *alarm_en = hw->hw_timer[timer_num].config.alarm_en; } +/* WDT operations */ + +/** + * Unlock/lock the WDT register in case of mis-operations. + * + * @param hw Beginning address of the peripheral registers. + * @param protect true to lock, false to unlock before operations. + */ + +FORCE_INLINE_ATTR void timer_ll_wdt_set_protect(timg_dev_t* hw, bool protect) +{ + hw->wdt_wprotect=(protect? 0: TIMG_WDT_WKEY_VALUE); +} + +/** + * Initialize WDT. + * + * @param hw Beginning address of the peripheral registers. + * + * @note Call ``timer_ll_wdt_set_protect first`` + */ +FORCE_INLINE_ATTR void timer_ll_wdt_init(timg_dev_t* hw) +{ + hw->wdt_config0.sys_reset_length=7; //3.2uS + hw->wdt_config0.cpu_reset_length=7; //3.2uS + //currently only level interrupt is supported + hw->wdt_config0.level_int_en = 1; + hw->wdt_config0.edge_int_en = 0; +} + +FORCE_INLINE_ATTR void timer_ll_wdt_set_tick(timg_dev_t* hw, int tick_time_us) +{ + hw->wdt_config1.clk_prescale=80*tick_time_us; +} + +FORCE_INLINE_ATTR void timer_ll_wdt_feed(timg_dev_t* hw) +{ + hw->wdt_feed = 1; +} + +FORCE_INLINE_ATTR void timer_ll_wdt_set_timeout(timg_dev_t* hw, int stage, uint32_t timeout_tick) +{ + switch (stage) { + case 0: + hw->wdt_config2=timeout_tick; + break; + case 1: + hw->wdt_config3=timeout_tick; + break; + case 2: + hw->wdt_config4=timeout_tick; + break; + case 3: + hw->wdt_config5=timeout_tick; + break; + default: + abort(); + } +} + +_Static_assert(TIMER_WDT_OFF == TIMG_WDT_STG_SEL_OFF, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t"); +_Static_assert(TIMER_WDT_INT == TIMG_WDT_STG_SEL_INT, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t"); +_Static_assert(TIMER_WDT_RESET_CPU == TIMG_WDT_STG_SEL_RESET_CPU, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t"); +_Static_assert(TIMER_WDT_RESET_SYSTEM == TIMG_WDT_STG_SEL_RESET_SYSTEM, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t"); + +FORCE_INLINE_ATTR void timer_ll_wdt_set_timeout_behavior(timg_dev_t* hw, int stage, timer_wdt_behavior_t behavior) +{ + switch (stage) { + case 0: + hw->wdt_config0.stg0 = behavior; + break; + case 1: + hw->wdt_config0.stg1 = behavior; + break; + case 2: + hw->wdt_config0.stg2 = behavior; + break; + case 3: + hw->wdt_config0.stg3 = behavior; + break; + default: + abort(); + } +} + +FORCE_INLINE_ATTR void timer_ll_wdt_set_enable(timg_dev_t* hw, bool enable) +{ + hw->wdt_config0.en = enable; +} + +FORCE_INLINE_ATTR void timer_ll_wdt_flashboot_en(timg_dev_t* hw, bool enable) +{ + hw->wdt_config0.flashboot_mod_en = enable; +} + + #ifdef __cplusplus } #endif diff --git a/components/soc/include/hal/timer_types.h b/components/soc/include/hal/timer_types.h index f1564eee9d..8ab5757f28 100644 --- a/components/soc/include/hal/timer_types.h +++ b/components/soc/include/hal/timer_types.h @@ -51,6 +51,17 @@ typedef enum { TIMER_INTR_WDT = BIT(2), /*!< interrupt of watchdog */ } timer_intr_t; +/** + * @brief Behavior of the watchdog if a stage times out. + */ +//this is compatible with the value of esp32. +typedef enum { + TIMER_WDT_OFF = 0, ///< The stage is turned off + TIMER_WDT_INT = 1, ///< The stage will trigger an interrupt + TIMER_WDT_RESET_CPU = 2, ///< The stage will reset the CPU + TIMER_WDT_RESET_SYSTEM = 3, ///< The stage will reset the whole system +} timer_wdt_behavior_t; + #ifdef __cplusplus } #endif From 264ffbeb14106ae32c7e156e9c3ad0eff737b503 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Wed, 24 Jul 2019 23:18:19 +0800 Subject: [PATCH 435/486] timer_group: use the LL --- components/app_trace/gcov/gcov_rtio.c | 13 +- components/app_trace/test/test_trace.c | 72 +---------- .../bootloader_support/src/bootloader_init.c | 5 +- components/driver/test/test_timer.c | 112 +++++++----------- components/esp32/int_wdt.c | 58 +++++---- components/esp32/panic.c | 43 ++++--- components/esp32/system_api.c | 22 ++-- components/esp32/task_wdt.c | 65 +++++----- components/esp32/test/test_intr_alloc.c | 22 ++-- components/esp32/test/test_reset_reason.c | 5 +- .../include/esp_private/system_internal.h | 2 + components/esp_event/test/test_event.c | 16 +-- components/esp_ringbuf/test/test_ringbuf.c | 4 +- components/freemodbus/port/porttimer.c | 18 ++- components/freemodbus/port/porttimer_m.c | 20 ++-- .../freertos/test/test_freertos_eventgroups.c | 4 +- .../freertos/test/test_freertos_task_notify.c | 12 +- .../freertos/test/test_suspend_scheduler.c | 5 +- .../freertos/test/test_task_suspend_resume.c | 2 +- components/spi_flash/test/test_spi_flash.c | 4 +- .../main/timer_group_example_main.c | 24 ++-- .../sysview_tracing/main/sysview_tracing.c | 29 +---- 22 files changed, 217 insertions(+), 340 deletions(-) diff --git a/components/app_trace/gcov/gcov_rtio.c b/components/app_trace/gcov/gcov_rtio.c index d01d7c6b6b..a6008b4634 100644 --- a/components/app_trace/gcov/gcov_rtio.c +++ b/components/app_trace/gcov/gcov_rtio.c @@ -21,6 +21,7 @@ #include "soc/timer_periph.h" #include "esp_app_trace.h" #include "esp_private/dbg_stubs.h" +#include "hal/timer_ll.h" #if CONFIG_ESP32_GCOV_ENABLE @@ -124,13 +125,13 @@ void esp_gcov_dump(void) #endif while (!esp_apptrace_host_is_connected(ESP_APPTRACE_DEST_TRAX)) { // to avoid complains that task watchdog got triggered for other tasks - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG0.wdt_feed=1; - TIMERG0.wdt_wprotect=0; + timer_ll_wdt_set_protect(&TIMERG0, false); + timer_ll_wdt_feed(&TIMERG0); + timer_ll_wdt_set_protect(&TIMERG0, true); // to avoid reboot on INT_WDT - TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG1.wdt_feed=1; - TIMERG1.wdt_wprotect=0; + timer_ll_wdt_set_protect(&TIMERG1, false); + timer_ll_wdt_feed(&TIMERG1); + timer_ll_wdt_set_protect(&TIMERG1, true); } esp_dbg_stub_gcov_dump_do(); diff --git a/components/app_trace/test/test_trace.c b/components/app_trace/test/test_trace.c index 3037ab4315..2e19e58083 100644 --- a/components/app_trace/test/test_trace.c +++ b/components/app_trace/test/test_trace.c @@ -145,56 +145,16 @@ static void esp_apptrace_test_timer_isr(void *arg) } tim_arg->data.wr_cnt++; - if (tim_arg->group == 0) { - if (tim_arg->id == 0) { - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[0].update = 1; - TIMERG0.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG0.int_clr_timers.t1 = 1; - TIMERG0.hw_timer[1].update = 1; - TIMERG0.hw_timer[1].config.alarm_en = 1; - } - } - if (tim_arg->group == 1) { - if (tim_arg->id == 0) { - TIMERG1.int_clr_timers.t0 = 1; - TIMERG1.hw_timer[0].update = 1; - TIMERG1.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG1.int_clr_timers.t1 = 1; - TIMERG1.hw_timer[1].update = 1; - TIMERG1.hw_timer[1].config.alarm_en = 1; - } - } + timer_group_intr_clr_in_isr(tim_arg->group, tim_arg->id); + timer_group_enable_alarm_in_isr(tim_arg->group, tim_arg->id); } static void esp_apptrace_test_timer_isr_crash(void *arg) { esp_apptrace_test_timer_arg_t *tim_arg = (esp_apptrace_test_timer_arg_t *)arg; - if (tim_arg->group == 0) { - if (tim_arg->id == 0) { - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[0].update = 1; - TIMERG0.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG0.int_clr_timers.t1 = 1; - TIMERG0.hw_timer[1].update = 1; - TIMERG0.hw_timer[1].config.alarm_en = 1; - } - } - if (tim_arg->group == 1) { - if (tim_arg->id == 0) { - TIMERG1.int_clr_timers.t0 = 1; - TIMERG1.hw_timer[0].update = 1; - TIMERG1.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG1.int_clr_timers.t1 = 1; - TIMERG1.hw_timer[1].update = 1; - TIMERG1.hw_timer[1].config.alarm_en = 1; - } - } + timer_group_intr_clr_in_isr(tim_arg->group, tim_arg->id); + timer_group_enable_alarm_in_isr(tim_arg->group, tim_arg->id); if (tim_arg->data.wr_cnt < ESP_APPTRACE_TEST_BLOCKS_BEFORE_CRASH) { uint32_t *ts = (uint32_t *)(tim_arg->data.buf + sizeof(uint32_t)); *ts = (uint32_t)esp_apptrace_test_ts_get();//xthal_get_ccount();//xTaskGetTickCount(); @@ -850,28 +810,8 @@ static void esp_sysview_test_timer_isr(void *arg) //ESP_APPTRACE_TEST_LOGI("tim-%d: IRQ %d/%d\n", tim_arg->id, tim_arg->group, tim_arg->timer); - if (tim_arg->group == 0) { - if (tim_arg->timer == 0) { - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[0].update = 1; - TIMERG0.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG0.int_clr_timers.t1 = 1; - TIMERG0.hw_timer[1].update = 1; - TIMERG0.hw_timer[1].config.alarm_en = 1; - } - } - if (tim_arg->group == 1) { - if (tim_arg->timer == 0) { - TIMERG1.int_clr_timers.t0 = 1; - TIMERG1.hw_timer[0].update = 1; - TIMERG1.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG1.int_clr_timers.t1 = 1; - TIMERG1.hw_timer[1].update = 1; - TIMERG1.hw_timer[1].config.alarm_en = 1; - } - } + timer_group_intr_clr_in_isr(tim_arg->group, tim_arg->id); + timer_group_enable_alarm_in_isr(tim_arg->group, tim_arg->id); } static void esp_sysviewtrace_test_task(void *p) diff --git a/components/bootloader_support/src/bootloader_init.c b/components/bootloader_support/src/bootloader_init.c index 26b8fd0b39..d3196dd855 100644 --- a/components/bootloader_support/src/bootloader_init.c +++ b/components/bootloader_support/src/bootloader_init.c @@ -53,6 +53,7 @@ #include "bootloader_flash_config.h" #include "flash_qio_mode.h" +#include "hal/timer_ll.h" extern int _bss_start; extern int _bss_end; @@ -158,8 +159,8 @@ static esp_err_t bootloader_main(void) /* disable watch dog here */ rtc_wdt_disable(); #endif - REG_SET_FIELD(TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY, TIMG_WDT_WKEY_VALUE); - REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN ); + timer_ll_wdt_set_protect(&TIMERG0, false); + timer_ll_wdt_flashboot_en(&TIMERG0, false); #ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH const uint32_t spiconfig = ets_efuse_get_spiconfig(); diff --git a/components/driver/test/test_timer.c b/components/driver/test/test_timer.c index bc5f3ae750..7aae242eb2 100644 --- a/components/driver/test/test_timer.c +++ b/components/driver/test/test_timer.c @@ -11,68 +11,44 @@ #define TIMER_DELTA 0.001 static bool alarm_flag; -// group0 interruption -static void test_timer_group0_isr(void *para) -{ - int timer_idx = (int) para; - uint64_t timer_val; - double time; - uint64_t alarm_value; - alarm_flag = true; - if (TIMERG0.hw_timer[timer_idx].config.autoreload == 1) { - if (timer_idx == 0) { - TIMERG0.int_clr_timers.t0 = 1; - } else { - TIMERG0.int_clr_timers.t1 = 1; - } - ets_printf("This is TG0 timer[%d] reload-timer alarm!\n", timer_idx); - timer_get_counter_value(TIMER_GROUP_0, timer_idx, &timer_val); - timer_get_counter_time_sec(TIMER_GROUP_0, timer_idx, &time); - ets_printf("time: %.8f S\n", time); - } else { - if (timer_idx == 0) { - TIMERG0.int_clr_timers.t0 = 1; - } else { - TIMERG0.int_clr_timers.t1 = 1; - } - ets_printf("This is TG0 timer[%d] count-up-timer alarm!\n", timer_idx); - timer_get_counter_value(TIMER_GROUP_0, timer_idx, &timer_val); - timer_get_counter_time_sec(TIMER_GROUP_0, timer_idx, &time); - timer_get_alarm_value(TIMER_GROUP_0, timer_idx, &alarm_value); - ets_printf("time: %.8f S\n", time); - double alarm_time = (double) alarm_value / TIMER_SCALE; - ets_printf("alarm_time: %.8f S\n", alarm_time); - } -} +typedef struct { + timer_group_t timer_group; + timer_idx_t timer_idx; +} timer_info_t; -// group1 interruption -static void test_timer_group1_isr(void *para) +#define TIMER_INFO_INIT(TG, TID) {.timer_group = (TG), .timer_idx = (TID),} + +static timer_info_t timer_info[4] = { + TIMER_INFO_INIT(TIMER_GROUP_0, TIMER_0), + TIMER_INFO_INIT(TIMER_GROUP_0, TIMER_1), + TIMER_INFO_INIT(TIMER_GROUP_1, TIMER_0), + TIMER_INFO_INIT(TIMER_GROUP_1, TIMER_1), +}; + +#define GET_TIMER_INFO(TG, TID) (&timer_info[(TG)*2+(TID)]) + +// timer group interruption +static void test_timer_group_isr(void *para) { - int timer_idx = (int) para; + timer_info_t* info = (timer_info_t*) para; + const timer_group_t timer_group = info->timer_group; + const timer_idx_t timer_idx = info->timer_idx; uint64_t timer_val; double time; uint64_t alarm_value; alarm_flag = true; - if (TIMERG1.hw_timer[timer_idx].config.autoreload == 1) { - if (timer_idx == 0) { - TIMERG1.int_clr_timers.t0 = 1; - } else { - TIMERG1.int_clr_timers.t1 = 1; - } - ets_printf("This is TG1 timer[%d] reload-timer alarm!\n", timer_idx); - timer_get_counter_value(TIMER_GROUP_1, timer_idx, &timer_val); - timer_get_counter_time_sec(TIMER_GROUP_1, timer_idx, &time); + if (timer_group_get_auto_reload_in_isr(timer_group, timer_idx)) { + timer_group_intr_clr_in_isr(timer_group, timer_idx); + ets_printf("This is TG%d timer[%d] reload-timer alarm!\n", timer_group, timer_idx); + timer_get_counter_value(timer_group, timer_idx, &timer_val); + timer_get_counter_time_sec(timer_group, timer_idx, &time); ets_printf("time: %.8f S\n", time); } else { - if (timer_idx == 0) { - TIMERG1.int_clr_timers.t0 = 1; - } else { - TIMERG1.int_clr_timers.t1 = 1; - } - ets_printf("This is TG1 timer[%d] count-up-timer alarm!\n", timer_idx); - timer_get_counter_value(TIMER_GROUP_1, timer_idx, &timer_val); - timer_get_counter_time_sec(TIMER_GROUP_1, timer_idx, &time); - timer_get_alarm_value(TIMER_GROUP_1, timer_idx, &alarm_value); + timer_group_intr_clr_in_isr(timer_group, timer_idx); + ets_printf("This is TG%d timer[%d] count-up-timer alarm!\n", timer_group, timer_idx); + timer_get_counter_value(timer_group, timer_idx, &timer_val); + timer_get_counter_time_sec(timer_group, timer_idx, &time); + timer_get_alarm_value(timer_group, timer_idx, &alarm_value); ets_printf("time: %.8f S\n", time); double alarm_time = (double) alarm_value / TIMER_SCALE; ets_printf("alarm_time: %.8f S\n", alarm_time); @@ -86,13 +62,7 @@ static void tg_timer_init(int timer_group, int timer_idx, double alarm_time) timer_set_counter_value(timer_group, timer_idx, 0x0); timer_set_alarm_value(timer_group, timer_idx, alarm_time * TIMER_SCALE); timer_enable_intr(timer_group, timer_idx); - if (timer_group == 0) { - timer_isr_register(timer_group, timer_idx, test_timer_group0_isr, - (void *) timer_idx, ESP_INTR_FLAG_LOWMED, NULL); - } else { - timer_isr_register(timer_group, timer_idx, test_timer_group1_isr, - (void *) timer_idx, ESP_INTR_FLAG_LOWMED, NULL); - } + timer_isr_register(timer_group, timer_idx, test_timer_group_isr, GET_TIMER_INFO(timer_group, timer_idx), ESP_INTR_FLAG_LOWMED, NULL); timer_start(timer_group, timer_idx); } @@ -747,8 +717,8 @@ TEST_CASE("Timer enable timer interrupt", "[hw_timer]") // enable timer_intr0 timer_set_counter_value(TIMER_GROUP_0, TIMER_0, set_timer_val); timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, 1.2 * TIMER_SCALE); - timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group0_isr, - (void *) TIMER_0, ESP_INTR_FLAG_LOWMED, NULL); + timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group_isr, + GET_TIMER_INFO(TIMER_GROUP_0, TIMER_0), ESP_INTR_FLAG_LOWMED, NULL); timer_start(TIMER_GROUP_0, TIMER_0); vTaskDelay(2000 / portTICK_PERIOD_MS); TEST_ASSERT(alarm_flag == true) @@ -765,8 +735,8 @@ TEST_CASE("Timer enable timer interrupt", "[hw_timer]") // enable timer_intr1 timer_set_counter_value(TIMER_GROUP_1, TIMER_1, set_timer_val); timer_set_alarm_value(TIMER_GROUP_1, TIMER_1, 1.2 * TIMER_SCALE); - timer_isr_register(TIMER_GROUP_1, TIMER_1, test_timer_group1_isr, - (void *) TIMER_1, ESP_INTR_FLAG_LOWMED, NULL); + timer_isr_register(TIMER_GROUP_1, TIMER_1, test_timer_group_isr, + GET_TIMER_INFO(TIMER_GROUP_1, TIMER_1), ESP_INTR_FLAG_LOWMED, NULL); timer_start(TIMER_GROUP_1, TIMER_1); vTaskDelay(2000 / portTICK_PERIOD_MS); TEST_ASSERT(alarm_flag == true) @@ -813,23 +783,21 @@ TEST_CASE("Timer enable timer group interrupt", "[hw_timer][ignore]") all_timer_set_alarm_value(1.2); // enable timer group - timer_group_intr_enable(TIMER_GROUP_0, TIMG_T0_INT_ENA_M); - timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group0_isr, - (void *) TIMER_0, ESP_INTR_FLAG_LOWMED, NULL); + timer_group_intr_enable(TIMER_GROUP_0, TIMER_INTR_T0); + timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group_isr, GET_TIMER_INFO(TIMER_GROUP_0, TIMER_0), ESP_INTR_FLAG_LOWMED, NULL); timer_start(TIMER_GROUP_0, TIMER_0); vTaskDelay(2000 / portTICK_PERIOD_MS); TEST_ASSERT(alarm_flag == true); //test enable auto_reload alarm_flag = false; - timer_group_intr_disable(TIMER_GROUP_0, TIMG_T0_INT_ENA_M); + timer_group_intr_disable(TIMER_GROUP_0, TIMER_INTR_T0); timer_start(TIMER_GROUP_0, TIMER_0); vTaskDelay(2000 / portTICK_PERIOD_MS); TEST_ASSERT(alarm_flag == false); - timer_group_intr_enable(TIMER_GROUP_0, TIMG_T0_INT_ENA_M); - timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group0_isr, - (void *) TIMER_0, ESP_INTR_FLAG_LOWMED, NULL); + timer_group_intr_enable(TIMER_GROUP_0, TIMER_INTR_T0); + timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group_isr, GET_TIMER_INFO(TIMER_GROUP_0, TIMER_0), ESP_INTR_FLAG_LOWMED, NULL); timer_start(TIMER_GROUP_0, TIMER_0); vTaskDelay(2000 / portTICK_PERIOD_MS); TEST_ASSERT(alarm_flag == true); diff --git a/components/esp32/int_wdt.c b/components/esp32/int_wdt.c index 8f18f7157e..2bfff80783 100644 --- a/components/esp32/int_wdt.c +++ b/components/esp32/int_wdt.c @@ -30,10 +30,11 @@ #include "driver/timer.h" #include "driver/periph_ctrl.h" #include "esp_int_wdt.h" +#include "hal/timer_ll.h" #if CONFIG_ESP_INT_WDT - +#define TG1_WDT_TICK_US 500 #define WDT_INT_NUM 24 @@ -48,11 +49,15 @@ static void IRAM_ATTR tick_hook(void) { } else { //Only feed wdt if app cpu also ticked. if (int_wdt_app_cpu_ticked) { - TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG1.wdt_config2=CONFIG_ESP_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt - TIMERG1.wdt_config3=CONFIG_ESP_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset - TIMERG1.wdt_feed=1; - TIMERG1.wdt_wprotect=0; + timer_ll_wdt_set_protect(&TIMERG1, false); + //Set timeout before interrupt + timer_ll_wdt_set_timeout(&TIMERG1, 0, + CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/TG1_WDT_TICK_US); + //Set timeout before reset + timer_ll_wdt_set_timeout(&TIMERG1, 1, + 2*CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/TG1_WDT_TICK_US); + timer_ll_wdt_feed(&TIMERG1); + timer_ll_wdt_set_protect(&TIMERG1, true); int_wdt_app_cpu_ticked=false; } } @@ -60,33 +65,36 @@ static void IRAM_ATTR tick_hook(void) { #else static void IRAM_ATTR tick_hook(void) { if (xPortGetCoreID()!=0) return; - TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG1.wdt_config2=CONFIG_ESP_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt - TIMERG1.wdt_config3=CONFIG_ESP_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset - TIMERG1.wdt_feed=1; - TIMERG1.wdt_wprotect=0; + timer_ll_wdt_set_protect(&TIMERG1, false); + //Set timeout before interrupt + timer_ll_wdt_set_timeout(&TIMERG1, 0, CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/TG1_WDT_TICK_US); + //Set timeout before reset + timer_ll_wdt_set_timeout(&TIMERG1, 1, 2*CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/TG1_WDT_TICK_US); + timer_ll_wdt_feed(&TIMERG1); + timer_ll_wdt_set_protect(&TIMERG1, true); } #endif void esp_int_wdt_init(void) { periph_module_enable(PERIPH_TIMG1_MODULE); - TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG1.wdt_config0.sys_reset_length=7; //3.2uS - TIMERG1.wdt_config0.cpu_reset_length=7; //3.2uS - TIMERG1.wdt_config0.level_int_en=1; - TIMERG1.wdt_config0.stg0=TIMG_WDT_STG_SEL_INT; //1st stage timeout: interrupt - TIMERG1.wdt_config0.stg1=TIMG_WDT_STG_SEL_RESET_SYSTEM; //2nd stage timeout: reset system - TIMERG1.wdt_config1.clk_prescale=80*500; //Prescaler: wdt counts in ticks of 0.5mS //The timer configs initially are set to 5 seconds, to make sure the CPU can start up. The tick hook sets //it to their actual value. - TIMERG1.wdt_config2=10000; - TIMERG1.wdt_config3=10000; - TIMERG1.wdt_config0.en=1; - TIMERG1.wdt_feed=1; - TIMERG1.wdt_wprotect=0; - TIMERG1.int_clr_timers.wdt=1; - timer_group_intr_enable(TIMER_GROUP_1, TIMG_WDT_INT_ENA_M); + timer_ll_wdt_set_protect(&TIMERG1, false); + timer_ll_wdt_init(&TIMERG1); + timer_ll_wdt_set_tick(&TIMERG1, TG1_WDT_TICK_US); //Prescaler: wdt counts in ticks of TG1_WDT_TICK_US + //1st stage timeout: interrupt + timer_ll_wdt_set_timeout_behavior(&TIMERG1, 0, TIMER_WDT_INT); + timer_ll_wdt_set_timeout(&TIMERG1, 0, 5*1000*1000/TG1_WDT_TICK_US); + //2nd stage timeout: reset system + timer_ll_wdt_set_timeout_behavior(&TIMERG1, 1, TIMER_WDT_RESET_SYSTEM); + timer_ll_wdt_set_timeout(&TIMERG1, 1, 5*1000*1000/TG1_WDT_TICK_US); + timer_ll_wdt_set_enable(&TIMERG1, true); + timer_ll_wdt_feed(&TIMERG1); + timer_ll_wdt_set_protect(&TIMERG1, true); + + timer_ll_intr_status_clear(&TIMERG1, TIMER_INTR_WDT); + timer_group_intr_enable(TIMER_GROUP_1, TIMER_INTR_WDT); } void esp_int_wdt_cpu_init(void) diff --git a/components/esp32/panic.c b/components/esp32/panic.c index 4a104f0290..b0c6401de9 100644 --- a/components/esp32/panic.c +++ b/components/esp32/panic.c @@ -44,6 +44,8 @@ #include "esp_private/system_internal.h" #include "sdkconfig.h" #include "esp_ota_ops.h" +#include "driver/timer.h" +#include "hal/timer_ll.h" #if CONFIG_SYSVIEW_ENABLE #include "SEGGER_RTT.h" #endif @@ -311,7 +313,7 @@ void panicHandler(XtExcFrame *frame) disableAllWdts(); if (frame->exccause == PANIC_RSN_INTWDT_CPU0 || frame->exccause == PANIC_RSN_INTWDT_CPU1) { - TIMERG1.int_clr_timers.wdt = 1; + timer_group_clr_intr_sta_in_isr(TIMER_GROUP_1, TIMER_INTR_WDT); } #if CONFIG_ESP32_APPTRACE_ENABLE #if CONFIG_SYSVIEW_ENABLE @@ -401,19 +403,21 @@ static void illegal_instruction_helper(XtExcFrame *frame) */ static void reconfigureAllWdts(void) { - TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE; - TIMERG0.wdt_feed = 1; - TIMERG0.wdt_config0.sys_reset_length = 7; //3.2uS - TIMERG0.wdt_config0.cpu_reset_length = 7; //3.2uS - TIMERG0.wdt_config0.stg0 = TIMG_WDT_STG_SEL_RESET_SYSTEM; //1st stage timeout: reset system - TIMERG0.wdt_config1.clk_prescale = 80 * 500; //Prescaler: wdt counts in ticks of 0.5mS - TIMERG0.wdt_config2 = 2000; //1 second before reset - TIMERG0.wdt_config0.en = 1; - TIMERG0.wdt_wprotect = 0; + timer_ll_wdt_set_protect(&TIMERG0, false); + timer_ll_wdt_feed(&TIMERG0); + timer_ll_wdt_init(&TIMERG0); + timer_ll_wdt_set_tick(&TIMERG0, TG0_WDT_TICK_US); //Prescaler: wdt counts in ticks of TG0_WDT_TICK_US + //1st stage timeout: reset system + timer_ll_wdt_set_timeout_behavior(&TIMERG0, 0, TIMER_WDT_RESET_SYSTEM); + //1 second before reset + timer_ll_wdt_set_timeout(&TIMERG0, 0, 1000*1000/TG0_WDT_TICK_US); + timer_ll_wdt_set_enable(&TIMERG0, true); + timer_ll_wdt_set_protect(&TIMERG0, true); + //Disable wdt 1 - TIMERG1.wdt_wprotect = TIMG_WDT_WKEY_VALUE; - TIMERG1.wdt_config0.en = 0; - TIMERG1.wdt_wprotect = 0; + timer_ll_wdt_set_protect(&TIMERG1, false); + timer_ll_wdt_set_enable(&TIMERG1, false); + timer_ll_wdt_set_protect(&TIMERG1, true); } /* @@ -421,12 +425,13 @@ static void reconfigureAllWdts(void) */ static inline void disableAllWdts(void) { - TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE; - TIMERG0.wdt_config0.en = 0; - TIMERG0.wdt_wprotect = 0; - TIMERG1.wdt_wprotect = TIMG_WDT_WKEY_VALUE; - TIMERG1.wdt_config0.en = 0; - TIMERG1.wdt_wprotect = 0; + timer_ll_wdt_set_protect(&TIMERG0, false); + timer_ll_wdt_set_enable(&TIMERG0, false); + timer_ll_wdt_set_protect(&TIMERG0, true); + + timer_ll_wdt_set_protect(&TIMERG1, false); + timer_ll_wdt_set_enable(&TIMERG1, false); + timer_ll_wdt_set_protect(&TIMERG1, true); } static void esp_panic_dig_reset(void) __attribute__((noreturn)); diff --git a/components/esp32/system_api.c b/components/esp32/system_api.c index 570c0997a3..7d3f1a90b1 100644 --- a/components/esp32/system_api.c +++ b/components/esp32/system_api.c @@ -38,6 +38,7 @@ #include "esp_private/system_internal.h" #include "esp_efuse.h" #include "esp_efuse_table.h" +#include "hal/timer_ll.h" static const char* TAG = "system_api"; @@ -204,7 +205,7 @@ esp_err_t esp_read_mac(uint8_t* mac, esp_mac_type_t type) ESP_LOGW(TAG, "incorrect mac type"); break; } - + return ESP_OK; } @@ -281,12 +282,13 @@ void IRAM_ATTR esp_restart_noos(void) esp_dport_access_int_abort(); // Disable TG0/TG1 watchdogs - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG0.wdt_config0.en = 0; - TIMERG0.wdt_wprotect=0; - TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG1.wdt_config0.en = 0; - TIMERG1.wdt_wprotect=0; + timer_ll_wdt_set_protect(&TIMERG0, false); + timer_ll_wdt_set_enable(&TIMERG0, false); + timer_ll_wdt_set_protect(&TIMERG0, true); + + timer_ll_wdt_set_protect(&TIMERG1, false); + timer_ll_wdt_set_enable(&TIMERG1, false); + timer_ll_wdt_set_protect(&TIMERG1, true); // Flush any data left in UART FIFOs uart_tx_wait_idle(0); @@ -307,10 +309,10 @@ void IRAM_ATTR esp_restart_noos(void) WRITE_PERI_REG(GPIO_FUNC5_IN_SEL_CFG_REG, 0x30); // Reset wifi/bluetooth/ethernet/sdio (bb/mac) - DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, + DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, DPORT_BB_RST | DPORT_FE_RST | DPORT_MAC_RST | DPORT_BT_RST | DPORT_BTMAC_RST | DPORT_SDIO_RST | - DPORT_SDIO_HOST_RST | DPORT_EMAC_RST | DPORT_MACPWR_RST | + DPORT_SDIO_HOST_RST | DPORT_EMAC_RST | DPORT_MACPWR_RST | DPORT_RW_BTMAC_RST | DPORT_RW_BTLP_RST); DPORT_REG_WRITE(DPORT_CORE_RST_EN_REG, 0); @@ -370,7 +372,7 @@ static void get_chip_info_esp32(esp_chip_info_t* out_info) { uint32_t reg = REG_READ(EFUSE_BLK0_RDATA3_REG); memset(out_info, 0, sizeof(*out_info)); - + out_info->model = CHIP_ESP32; if ((reg & EFUSE_RD_CHIP_VER_REV1_M) != 0) { out_info->revision = 1; diff --git a/components/esp32/task_wdt.c b/components/esp32/task_wdt.c index 6675a1a98a..c1aa4e9761 100644 --- a/components/esp32/task_wdt.c +++ b/components/esp32/task_wdt.c @@ -34,6 +34,8 @@ #include "driver/periph_ctrl.h" #include "esp_task_wdt.h" #include "esp_private/system_internal.h" +#include "hal/timer_ll.h" + static const char *TAG = "task_wdt"; @@ -107,9 +109,9 @@ static twdt_task_t *find_task_in_twdt_list(TaskHandle_t handle, bool *all_reset) static void reset_hw_timer(void) { //All tasks have reset; time to reset the hardware timer. - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG0.wdt_feed=1; - TIMERG0.wdt_wprotect=0; + timer_ll_wdt_set_protect(&TIMERG0, false); + timer_ll_wdt_feed(&TIMERG0); + timer_ll_wdt_set_protect(&TIMERG0, true); //Clear all has_reset flags in list for (twdt_task_t *task = twdt_config->list; task != NULL; task = task->next){ task->has_reset=false; @@ -137,11 +139,11 @@ static void task_wdt_isr(void *arg) twdt_task_t *twdttask; const char *cpu; //Reset hardware timer so that 2nd stage timeout is not reached (will trigger system reset) - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG0.wdt_feed=1; - TIMERG0.wdt_wprotect=0; + timer_ll_wdt_set_protect(&TIMERG0, false); + timer_ll_wdt_feed(&TIMERG0); + timer_ll_wdt_set_protect(&TIMERG0, true); //Acknowledge interrupt - TIMERG0.int_clr_timers.wdt=1; + timer_group_clr_intr_sta_in_isr(TIMER_GROUP_0, TIMER_INTR_WDT); //We are taking a spinlock while doing I/O (ESP_EARLY_LOGE) here. Normally, that is a pretty //bad thing, possibly (temporarily) hanging up the 2nd core and stopping FreeRTOS. In this case, //something bad already happened and reporting this is considered more important @@ -198,32 +200,33 @@ esp_err_t esp_task_wdt_init(uint32_t timeout, bool panic) //Configure hardware timer periph_module_enable(PERIPH_TIMG0_MODULE); - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; //Disable write protection - TIMERG0.wdt_config0.sys_reset_length=7; //3.2uS - TIMERG0.wdt_config0.cpu_reset_length=7; //3.2uS - TIMERG0.wdt_config0.level_int_en=1; - TIMERG0.wdt_config0.stg0=TIMG_WDT_STG_SEL_INT; //1st stage timeout: interrupt - TIMERG0.wdt_config0.stg1=TIMG_WDT_STG_SEL_RESET_SYSTEM; //2nd stage timeout: reset system - TIMERG0.wdt_config1.clk_prescale=80*500; //Prescaler: wdt counts in ticks of 0.5mS - TIMERG0.wdt_config2=twdt_config->timeout*2000; //Set timeout before interrupt - TIMERG0.wdt_config3=twdt_config->timeout*4000; //Set timeout before reset - TIMERG0.wdt_config0.en=1; - TIMERG0.wdt_feed=1; - TIMERG0.wdt_wprotect=0; //Enable write protection - - }else{ //twdt_config previously initialized + timer_ll_wdt_set_protect(&TIMERG0, false); //Disable write protection + timer_ll_wdt_init(&TIMERG0); + timer_ll_wdt_set_tick(&TIMERG0, TG0_WDT_TICK_US); //Prescaler: wdt counts in ticks of TG0_WDT_TICK_US + //1st stage timeout: interrupt + timer_ll_wdt_set_timeout_behavior(&TIMERG0, 0, TIMER_WDT_INT); + timer_ll_wdt_set_timeout(&TIMERG0, 0, twdt_config->timeout*1000*1000/TG0_WDT_TICK_US); + //2nd stage timeout: reset system + timer_ll_wdt_set_timeout_behavior(&TIMERG0, 1, TIMER_WDT_RESET_SYSTEM); + timer_ll_wdt_set_timeout(&TIMERG0, 1, 2*twdt_config->timeout*1000*1000/TG0_WDT_TICK_US); + timer_ll_wdt_set_enable(&TIMERG0, true); + timer_ll_wdt_feed(&TIMERG0); + timer_ll_wdt_set_protect(&TIMERG0, true); //Enable write protection + } else { //twdt_config previously initialized //Reconfigure task wdt twdt_config->panic = panic; twdt_config->timeout = timeout; //Reconfigure hardware timer - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; //Disable write protection - TIMERG0.wdt_config0.en=0; //Disable timer - TIMERG0.wdt_config2=twdt_config->timeout*2000; //Set timeout before interrupt - TIMERG0.wdt_config3=twdt_config->timeout*4000; //Set timeout before reset - TIMERG0.wdt_config0.en=1; //Renable timer - TIMERG0.wdt_feed=1; //Reset timer - TIMERG0.wdt_wprotect=0; //Enable write protection + timer_ll_wdt_set_protect(&TIMERG0, false); //Disable write protection + timer_ll_wdt_set_enable(&TIMERG0, false); //Disable timer + //Set timeout before interrupt + timer_ll_wdt_set_timeout(&TIMERG0, 0, twdt_config->timeout*1000*1000/TG0_WDT_TICK_US); + //Set timeout before reset + timer_ll_wdt_set_timeout(&TIMERG0, 1, 2*twdt_config->timeout*1000*1000/TG0_WDT_TICK_US); + timer_ll_wdt_set_enable(&TIMERG0, true); //Renable timer + timer_ll_wdt_feed(&TIMERG0); //Reset timer + timer_ll_wdt_set_protect(&TIMERG0, true); //Enable write protection } portEXIT_CRITICAL(&twdt_spinlock); return ESP_OK; @@ -238,9 +241,9 @@ esp_err_t esp_task_wdt_deinit(void) ASSERT_EXIT_CRIT_RETURN((twdt_config->list == NULL), ESP_ERR_INVALID_STATE); //Disable hardware timer - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; //Disable write protection - TIMERG0.wdt_config0.en=0; //Disable timer - TIMERG0.wdt_wprotect=0; //Enable write protection + timer_ll_wdt_set_protect(&TIMERG0, false); //Disable write protection + timer_ll_wdt_set_enable(&TIMERG0, false); //Disable timer + timer_ll_wdt_set_protect(&TIMERG0, true); //Enable write protection ESP_ERROR_CHECK(esp_intr_free(twdt_config->intr_handle)); //Unregister interrupt free(twdt_config); //Free twdt_config diff --git a/components/esp32/test/test_intr_alloc.c b/components/esp32/test/test_intr_alloc.c index 85654c1ae0..b17fb9e83e 100644 --- a/components/esp32/test/test_intr_alloc.c +++ b/components/esp32/test/test_intr_alloc.c @@ -55,24 +55,20 @@ static void timer_isr(void *arg) int timer_idx = (int)arg; count[timer_idx]++; if (timer_idx==0) { - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[0].update=1; - TIMERG0.hw_timer[0].config.alarm_en = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0); + timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_0); } if (timer_idx==1) { - TIMERG0.int_clr_timers.t1 = 1; - TIMERG0.hw_timer[1].update=1; - TIMERG0.hw_timer[1].config.alarm_en = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_1); + timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_1); } if (timer_idx==2) { - TIMERG1.int_clr_timers.t0 = 1; - TIMERG1.hw_timer[0].update=1; - TIMERG1.hw_timer[0].config.alarm_en = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_1, TIMER_0); + timer_group_enable_alarm_in_isr(TIMER_GROUP_1, TIMER_0); } if (timer_idx==3) { - TIMERG1.int_clr_timers.t1 = 1; - TIMERG1.hw_timer[1].update=1; - TIMERG1.hw_timer[1].config.alarm_en = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_1, TIMER_1); + timer_group_enable_alarm_in_isr(TIMER_GROUP_1, TIMER_1); } // ets_printf("int %d\n", timer_idx); } @@ -280,7 +276,7 @@ TEST_CASE("allocate 2 handlers for a same source and remove the later one","[esp r=esp_intr_alloc(ETS_SPI2_INTR_SOURCE, ESP_INTR_FLAG_SHARED, int_handler2, &ctx, &handle2); TEST_ESP_OK(r); SPI2.slave.trans_inten = 1; - + printf("trigger first time.\n"); SPI2.slave.trans_done = 1; diff --git a/components/esp32/test/test_reset_reason.c b/components/esp32/test/test_reset_reason.c index da03e8c1e3..1aed30039e 100644 --- a/components/esp32/test/test_reset_reason.c +++ b/components/esp32/test/test_reset_reason.c @@ -280,11 +280,12 @@ static void timer_group_test_first_stage(void) //Start timer timer_start(TIMER_GROUP_0, TIMER_0); //Waiting for timer_group to generate an interrupt - while( !TIMERG0.int_raw.t0 && loop_cnt++ < 100) { + while( !(timer_group_intr_get_in_isr(TIMER_GROUP_0) & TIMER_INTR_T0) && + loop_cnt++ < 100) { vTaskDelay(200); } //TIMERG0.int_raw.t0 == 1 means an interruption has occurred - TEST_ASSERT_EQUAL(1, TIMERG0.int_raw.t0); + TEST_ASSERT(timer_group_intr_get_in_isr(TIMER_GROUP_0) & TIMER_INTR_T0); esp_restart(); } diff --git a/components/esp_common/include/esp_private/system_internal.h b/components/esp_common/include/esp_private/system_internal.h index e0d95d2f71..8ecef8da9e 100644 --- a/components/esp_common/include/esp_private/system_internal.h +++ b/components/esp_common/include/esp_private/system_internal.h @@ -20,6 +20,8 @@ extern "C" { #include "esp_system.h" +#define TG0_WDT_TICK_US 500 + /** * @brief Internal function to restart PRO and APP CPUs. * diff --git a/components/esp_event/test/test_event.c b/components/esp_event/test/test_event.c index 6560bdc5f5..b375d3f90a 100644 --- a/components/esp_event/test/test_event.c +++ b/components/esp_event/test/test_event.c @@ -30,14 +30,14 @@ static const char* TAG = "test_event"; #define TEST_CONFIG_WAIT_MULTIPLIER 5 -// The initial logging "initializing test" is to ensure mutex allocation is not counted against memory not being freed -// during teardown. +// The initial logging "initializing test" is to ensure mutex allocation is not counted against memory not being freed +// during teardown. #define TEST_SETUP() \ ESP_LOGI(TAG, "initializing test"); \ size_t free_mem_before = heap_caps_get_free_size(MALLOC_CAP_DEFAULT); \ test_setup(); \ s_test_core_id = xPortGetCoreID(); \ - s_test_priority = uxTaskPriorityGet(NULL); + s_test_priority = uxTaskPriorityGet(NULL); #define TEST_TEARDOWN() \ test_teardown(); \ @@ -294,15 +294,11 @@ void IRAM_ATTR test_event_on_timer_alarm(void* para) { /* Retrieve the interrupt status and the counter value from the timer that reported the interrupt */ - TIMERG0.hw_timer[TIMER_0].update = 1; uint64_t timer_counter_value = - ((uint64_t) TIMERG0.hw_timer[TIMER_0].cnt_high) << 32 - | TIMERG0.hw_timer[TIMER_0].cnt_low; - - TIMERG0.int_clr_timers.t0 = 1; + timer_group_get_counter_value_in_isr(TIMER_GROUP_0, TIMER_0); + timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0); timer_counter_value += (uint64_t) (TIMER_INTERVAL0_SEC * TIMER_SCALE); - TIMERG0.hw_timer[TIMER_0].alarm_high = (uint32_t) (timer_counter_value >> 32); - TIMERG0.hw_timer[TIMER_0].alarm_low = (uint32_t) timer_counter_value; + timer_group_set_alarm_value_in_isr(TIMER_GROUP_0, TIMER_0, timer_counter_value); int data = (int) para; // Posting events with data more than 4 bytes should fail. diff --git a/components/esp_ringbuf/test/test_ringbuf.c b/components/esp_ringbuf/test/test_ringbuf.c index 62ca3c9b14..476283a0ba 100644 --- a/components/esp_ringbuf/test/test_ringbuf.c +++ b/components/esp_ringbuf/test/test_ringbuf.c @@ -356,8 +356,8 @@ static int iterations; static void ringbuffer_isr(void *arg) { //Clear timer interrupt - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[xPortGetCoreID()].config.alarm_en = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0); + timer_group_enable_alarm_in_isr(TIMER_GROUP_0, xPortGetCoreID()); //Test sending to buffer from ISR from ISR if (buf_type < NO_OF_RB_TYPES) { diff --git a/components/freemodbus/port/porttimer.c b/components/freemodbus/port/porttimer.c index 4e832ef736..709031d660 100644 --- a/components/freemodbus/port/porttimer.c +++ b/components/freemodbus/port/porttimer.c @@ -64,19 +64,15 @@ static const USHORT usTimerIndex = CONFIG_FMB_TIMER_INDEX; // Modbus Timer index used by stack static const USHORT usTimerGroupIndex = CONFIG_FMB_TIMER_GROUP; // Modbus Timer group index used by stack -static timg_dev_t *MB_TG[2] = {&TIMERG0, &TIMERG1}; - /* ----------------------- Start implementation -----------------------------*/ static void IRAM_ATTR vTimerGroupIsr(void *param) { - // Retrieve the interrupt status and the counter value - // from the timer that reported the interrupt - uint32_t intr_status = MB_TG[usTimerGroupIndex]->int_st_timers.val; - if (intr_status & BIT(usTimerIndex)) { - MB_TG[usTimerGroupIndex]->int_clr_timers.val |= BIT(usTimerIndex); - (void)pxMBPortCBTimerExpired(); // Timer callback function - MB_TG[usTimerGroupIndex]->hw_timer[usTimerIndex].config.alarm_en = TIMER_ALARM_EN; - } + assert((int)param == usTimerIndex); + // Retrieve the counter value from the timer that reported the interrupt + timer_group_intr_clr_in_isr(usTimerGroupIndex, usTimerIndex); + (void)pxMBPortCBTimerExpired(); // Timer callback function + // Enable alarm + timer_group_enable_alarm_in_isr(usTimerGroupIndex, usTimerIndex); } #endif @@ -113,7 +109,7 @@ BOOL xMBPortTimersInit(USHORT usTim1Timerout50us) "failure to set alarm failure, timer_set_alarm_value() returned (0x%x).", (uint32_t)xErr); // Register ISR for timer - xErr = timer_isr_register(usTimerGroupIndex, usTimerIndex, vTimerGroupIsr, NULL, ESP_INTR_FLAG_IRAM, NULL); + xErr = timer_isr_register(usTimerGroupIndex, usTimerIndex, vTimerGroupIsr, (void*)(uint32_t)usTimerIndex, ESP_INTR_FLAG_IRAM, NULL); MB_PORT_CHECK((xErr == ESP_OK), FALSE, "timer set value failure, timer_isr_register() returned (0x%x).", (uint32_t)xErr); diff --git a/components/freemodbus/port/porttimer_m.c b/components/freemodbus/port/porttimer_m.c index 9ba9f52cd2..c2d52281b3 100644 --- a/components/freemodbus/port/porttimer_m.c +++ b/components/freemodbus/port/porttimer_m.c @@ -61,22 +61,16 @@ static USHORT usT35TimeOut50us; static const USHORT usTimerIndex = MB_TIMER_INDEX; // Initialize Modbus Timer index used by stack, static const USHORT usTimerGroupIndex = MB_TIMER_GROUP; // Timer group index used by stack -static timg_dev_t *MB_TG[2] = { &TIMERG0, &TIMERG1 }; - /* ----------------------- static functions ---------------------------------*/ static void IRAM_ATTR vTimerGroupIsr(void *param) { - // Retrieve the interrupt status and the counter value - // from the timer that reported the interrupt - uint32_t intr_status = MB_TG[usTimerGroupIndex]->int_st_timers.val; - if (intr_status & BIT(usTimerIndex)) { - MB_TG[usTimerGroupIndex]->int_clr_timers.val |= BIT(usTimerIndex); - MB_TG[usTimerGroupIndex]->hw_timer[usTimerIndex].update = 1; - (void)pxMBMasterPortCBTimerExpired(); // Timer expired callback function - // Enable alarm - MB_TG[usTimerGroupIndex]->hw_timer[usTimerIndex].config.alarm_en = TIMER_ALARM_EN; - } + assert((int)param == usTimerIndex); + // Retrieve the the counter value from the timer that reported the interrupt + timer_group_intr_clr_in_isr(usTimerGroupIndex, usTimerIndex); + (void)pxMBMasterPortCBTimerExpired(); // Timer expired callback function + // Enable alarm + timer_group_enable_alarm_in_isr(usTimerGroupIndex, usTimerIndex); } /* ----------------------- Start implementation -----------------------------*/ @@ -115,7 +109,7 @@ BOOL xMBMasterPortTimersInit(USHORT usTimeOut50us) (uint32_t)xErr); // Register ISR for timer xErr = timer_isr_register(usTimerGroupIndex, usTimerIndex, - vTimerGroupIsr, NULL, ESP_INTR_FLAG_IRAM, NULL); + vTimerGroupIsr, (void*)(uint32_t)usTimerIndex, ESP_INTR_FLAG_IRAM, NULL); MB_PORT_CHECK((xErr == ESP_OK), FALSE, "timer set value failure, timer_isr_register() returned (0x%x).", (uint32_t)xErr); diff --git a/components/freertos/test/test_freertos_eventgroups.c b/components/freertos/test/test_freertos_eventgroups.c index 9b86f759fb..1a245e2fb8 100644 --- a/components/freertos/test/test_freertos_eventgroups.c +++ b/components/freertos/test/test_freertos_eventgroups.c @@ -138,8 +138,8 @@ static bool test_clear_bits; static void IRAM_ATTR event_group_isr(void *arg) { portBASE_TYPE task_woken = pdFALSE; - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[xPortGetCoreID()].config.alarm_en = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0); + timer_group_enable_alarm_in_isr(TIMER_GROUP_0, xPortGetCoreID()); if(test_set_bits){ xEventGroupSetBitsFromISR(eg, BITS, &task_woken); diff --git a/components/freertos/test/test_freertos_task_notify.c b/components/freertos/test/test_freertos_task_notify.c index 8179cef9b4..226180d8aa 100644 --- a/components/freertos/test/test_freertos_task_notify.c +++ b/components/freertos/test/test_freertos_task_notify.c @@ -97,16 +97,10 @@ static void receiver_task (void* arg){ static void IRAM_ATTR sender_ISR (void *arg) { int curcore = xPortGetCoreID(); - if(curcore == 0){ //Clear timer interrupt - //Clear intr and pause via direct reg access as IRAM ISR cannot access timer APIs - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[0].config.enable = 0; - }else{ - TIMERG0.int_clr_timers.t1 = 1; - TIMERG0.hw_timer[1].config.enable = 0; - } + timer_group_intr_clr_in_isr(TIMER_GROUP_0, curcore); + timer_group_set_counter_enable_in_isr(TIMER_GROUP_0, curcore, TIMER_PAUSE); //Re-enable alarm - TIMERG0.hw_timer[curcore].config.alarm_en = 1; + timer_group_enable_alarm_in_isr(TIMER_GROUP_0, curcore); if(isr_give){ //Test vTaskNotifyGiveFromISR() on same core notifs_sent++; diff --git a/components/freertos/test/test_suspend_scheduler.c b/components/freertos/test/test_suspend_scheduler.c index 9aef2ce7ec..9e7b039ed1 100644 --- a/components/freertos/test/test_suspend_scheduler.c +++ b/components/freertos/test/test_suspend_scheduler.c @@ -20,9 +20,8 @@ static volatile unsigned isr_count; mutex semaphore to wake up another counter task */ static void timer_group0_isr(void *vp_arg) { - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[TIMER_0].update = 1; - TIMERG0.hw_timer[TIMER_0].config.alarm_en = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0); + timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_0); portBASE_TYPE higher_awoken = pdFALSE; isr_count++; xSemaphoreGiveFromISR(isr_semaphore, &higher_awoken); diff --git a/components/freertos/test/test_task_suspend_resume.c b/components/freertos/test/test_task_suspend_resume.c index 7d60de3664..9b7c47cd4e 100644 --- a/components/freertos/test/test_task_suspend_resume.c +++ b/components/freertos/test/test_task_suspend_resume.c @@ -118,7 +118,7 @@ volatile bool timer_isr_fired; void IRAM_ATTR timer_group0_isr(void *vp_arg) { // Clear interrupt - TIMERG0.int_clr_timers.val = TIMERG0.int_st_timers.val; + timer_group_clr_intr_sta_in_isr(TIMER_GROUP_0, TIMER_0|TIMER_1); timer_isr_fired = true; TaskHandle_t handle = vp_arg; diff --git a/components/spi_flash/test/test_spi_flash.c b/components/spi_flash/test/test_spi_flash.c index 0010f86d83..f943723743 100644 --- a/components/spi_flash/test/test_spi_flash.c +++ b/components/spi_flash/test/test_spi_flash.c @@ -108,8 +108,8 @@ typedef struct { static void IRAM_ATTR timer_isr(void* varg) { block_task_arg_t* arg = (block_task_arg_t*) varg; - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[0].config.alarm_en = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0); + timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_0); ets_delay_us(arg->delay_time_us); arg->repeat_count++; } diff --git a/examples/peripherals/timer_group/main/timer_group_example_main.c b/examples/peripherals/timer_group/main/timer_group_example_main.c index 403f9c0a0f..cd1e8cdee8 100644 --- a/examples/peripherals/timer_group/main/timer_group_example_main.c +++ b/examples/peripherals/timer_group/main/timer_group_example_main.c @@ -60,11 +60,8 @@ void IRAM_ATTR timer_group0_isr(void *para) /* Retrieve the interrupt status and the counter value from the timer that reported the interrupt */ - uint32_t intr_status = TIMERG0.int_st_timers.val; - TIMERG0.hw_timer[timer_idx].update = 1; - uint64_t timer_counter_value = - ((uint64_t) TIMERG0.hw_timer[timer_idx].cnt_high) << 32 - | TIMERG0.hw_timer[timer_idx].cnt_low; + timer_intr_t timer_intr = timer_group_intr_get_in_isr(TIMER_GROUP_0); + uint64_t timer_counter_value = timer_group_get_counter_value_in_isr(TIMER_GROUP_0, timer_idx); /* Prepare basic event data that will be then sent back to the main program task */ @@ -75,22 +72,21 @@ void IRAM_ATTR timer_group0_isr(void *para) /* Clear the interrupt and update the alarm time for the timer with without reload */ - if ((intr_status & BIT(timer_idx)) && timer_idx == TIMER_0) { + if (timer_intr & TIMER_INTR_T0) { evt.type = TEST_WITHOUT_RELOAD; - TIMERG0.int_clr_timers.t0 = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0); timer_counter_value += (uint64_t) (TIMER_INTERVAL0_SEC * TIMER_SCALE); - TIMERG0.hw_timer[timer_idx].alarm_high = (uint32_t) (timer_counter_value >> 32); - TIMERG0.hw_timer[timer_idx].alarm_low = (uint32_t) timer_counter_value; - } else if ((intr_status & BIT(timer_idx)) && timer_idx == TIMER_1) { + timer_group_set_alarm_value_in_isr(TIMER_GROUP_0, timer_idx, timer_counter_value); + } else if (timer_intr & TIMER_INTR_T1) { evt.type = TEST_WITH_RELOAD; - TIMERG0.int_clr_timers.t1 = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_1); } else { evt.type = -1; // not supported even type } /* After the alarm has been triggered we need enable it again, so it is triggered the next time */ - TIMERG0.hw_timer[timer_idx].config.alarm_en = TIMER_ALARM_EN; + timer_group_enable_alarm_in_isr(TIMER_GROUP_0, timer_idx); /* Now just send the event data back to the main program task */ xQueueSendFromISR(timer_queue, &evt, NULL); @@ -103,7 +99,7 @@ void IRAM_ATTR timer_group0_isr(void *para) * auto_reload - should the timer auto reload on alarm? * timer_interval_sec - the interval of alarm to set */ -static void example_tg0_timer_init(int timer_idx, +static void example_tg0_timer_init(int timer_idx, bool auto_reload, double timer_interval_sec) { /* Select and initialize basic parameters of the timer */ @@ -123,7 +119,7 @@ static void example_tg0_timer_init(int timer_idx, /* Configure the alarm value and the interrupt on alarm. */ timer_set_alarm_value(TIMER_GROUP_0, timer_idx, timer_interval_sec * TIMER_SCALE); timer_enable_intr(TIMER_GROUP_0, timer_idx); - timer_isr_register(TIMER_GROUP_0, timer_idx, timer_group0_isr, + timer_isr_register(TIMER_GROUP_0, timer_idx, timer_group0_isr, (void *) timer_idx, ESP_INTR_FLAG_IRAM, NULL); timer_start(TIMER_GROUP_0, timer_idx); diff --git a/examples/system/sysview_tracing/main/sysview_tracing.c b/examples/system/sysview_tracing/main/sysview_tracing.c index 3436b4cbcb..32c4562e12 100644 --- a/examples/system/sysview_tracing/main/sysview_tracing.c +++ b/examples/system/sysview_tracing/main/sysview_tracing.c @@ -107,32 +107,6 @@ static void example_timer_init(int timer_group, int timer_idx, uint32_t period) timer_enable_intr(timer_group, timer_idx); } -static void example_timer_rearm(int timer_group, int timer_idx) -{ - if (timer_group == 0) { - if (timer_idx == 0) { - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[0].update = 1; - TIMERG0.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG0.int_clr_timers.t1 = 1; - TIMERG0.hw_timer[1].update = 1; - TIMERG0.hw_timer[1].config.alarm_en = 1; - } - } - if (timer_group == 1) { - if (timer_idx == 0) { - TIMERG1.int_clr_timers.t0 = 1; - TIMERG1.hw_timer[0].update = 1; - TIMERG1.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG1.int_clr_timers.t1 = 1; - TIMERG1.hw_timer[1].update = 1; - TIMERG1.hw_timer[1].config.alarm_en = 1; - } - } -} - static void example_timer_isr(void *arg) { example_event_data_t *tim_arg = (example_event_data_t *)arg; @@ -152,7 +126,8 @@ static void example_timer_isr(void *arg) } } // re-start timer - example_timer_rearm(tim_arg->group, tim_arg->timer); + timer_group_intr_clr_in_isr(tim_arg->group, tim_arg->timer); + timer_group_enable_alarm_in_isr(tim_arg->group, tim_arg->timer); } static void example_task(void *p) From d850a0bd1c7fd96ec7dcf58a13f140124eba3a65 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Thu, 8 Aug 2019 17:49:12 +0800 Subject: [PATCH 436/486] esp_attr: add flag_attr to support enums used as flags --- components/cxx/test/test_cxx.cpp | 28 ++++++++++++++++++++++++ components/esp32/include/esp_attr.h | 24 ++++++++++++++++++++ components/soc/include/hal/timer_types.h | 2 +- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/components/cxx/test/test_cxx.cpp b/components/cxx/test/test_cxx.cpp index 0f5cce3318..0bf92f324b 100644 --- a/components/cxx/test/test_cxx.cpp +++ b/components/cxx/test/test_cxx.cpp @@ -319,3 +319,31 @@ TEST_CASE("can call std::function and bind", "[cxx]") #endif +/* Tests below are done in the compile time, don't actually get run. */ +/* Check whether a enumerator flag can be used in C++ */ + + +template __attribute__((unused)) static void test_binary_operators() +{ + T flag1 = (T)0; + T flag2 = (T)0; + flag1 = ~flag1; + flag1 = flag1 | flag2; + flag1 = flag1 & flag2; + flag1 = flag1 ^ flag2; + flag1 = flag1 >> 2; + flag1 = flag1 << 2; + flag1 |= flag2; + flag1 &= flag2; + flag1 ^= flag2; + flag1 >>= 2; + flag1 <<= 2; +} + +//Add more types here. If any flags cannot pass the build, use FLAG_ATTR in esp_attr.h +#include "hal/timer_types.h" +template void test_binary_operators(); + + + + diff --git a/components/esp32/include/esp_attr.h b/components/esp32/include/esp_attr.h index 58fef76c71..34458948a7 100644 --- a/components/esp32/include/esp_attr.h +++ b/components/esp32/include/esp_attr.h @@ -76,6 +76,30 @@ // Forces to not inline function #define NOINLINE_ATTR __attribute__((noinline)) +// This allows using enum as flags in C++ +// Format: FLAG_ATTR(flag_enum_t) +#ifdef __cplusplus + +#define FLAG_ATTR_IMPL(TYPE, INT_TYPE) \ +constexpr TYPE operator~ (TYPE a) { return (TYPE)~(INT_TYPE)a; } \ +constexpr TYPE operator| (TYPE a, TYPE b) { return (TYPE)((INT_TYPE)a | (INT_TYPE)b); } \ +constexpr TYPE operator& (TYPE a, TYPE b) { return (TYPE)((INT_TYPE)a & (INT_TYPE)b); } \ +constexpr TYPE operator^ (TYPE a, TYPE b) { return (TYPE)((INT_TYPE)a ^ (INT_TYPE)b); } \ +constexpr TYPE operator>> (TYPE a, int b) { return (TYPE)((INT_TYPE)a >> b); } \ +constexpr TYPE operator<< (TYPE a, int b) { return (TYPE)((INT_TYPE)a << b); } \ +TYPE& operator|=(TYPE& a, TYPE b) { a = a | b; return a; } \ +TYPE& operator&=(TYPE& a, TYPE b) { a = a & b; return a; } \ +TYPE& operator^=(TYPE& a, TYPE b) { a = a ^ b; return a; } \ +TYPE& operator>>=(TYPE& a, int b) { a >>= b; return a; } \ +TYPE& operator<<=(TYPE& a, int b) { a <<= b; return a; } + +#define FLAG_ATTR_U32(TYPE) FLAG_ATTR_IMPL(TYPE, uint32_t) +#define FLAG_ATTR FLAG_ATTR_U32 + +#else +#define FLAG_ATTR(TYPE) +#endif + // Implementation for a unique custom section // // This prevents gcc producing "x causes a section type conflict with y" diff --git a/components/soc/include/hal/timer_types.h b/components/soc/include/hal/timer_types.h index 8ab5757f28..e9bcc9985d 100644 --- a/components/soc/include/hal/timer_types.h +++ b/components/soc/include/hal/timer_types.h @@ -40,7 +40,6 @@ typedef enum { TIMER_START = 1, /*! Date: Fri, 9 Aug 2019 16:35:31 +0800 Subject: [PATCH 437/486] cmake: fix encrypted project flash arg file generation --- components/esptool_py/flash_encrypted_project_args.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esptool_py/flash_encrypted_project_args.in b/components/esptool_py/flash_encrypted_project_args.in index db16bc6cdf..a1875e69e1 100644 --- a/components/esptool_py/flash_encrypted_project_args.in +++ b/components/esptool_py/flash_encrypted_project_args.in @@ -1,3 +1,3 @@ --encrypt ${ESPTOOLPY_FLASH_PROJECT_OPTIONS} -$, +$ From b1f657fc656f1784c1d237a4476e8e0db0a19236 Mon Sep 17 00:00:00 2001 From: Sagar Bijwe Date: Thu, 8 Aug 2019 16:02:33 +0530 Subject: [PATCH 438/486] wifi: Avoid recalculating PMK when esp_wifi_set_config is not called Scenarios where this fix is applicable. 1) Every time the system is powered-on/restarted without calling esp_wifi_set_config. 2) esp_wifi_init()/connect()/stop()/deinit() is called multiple times without esp_wifi_set_config. Closes IDFGH-1520 --- components/esp_wifi/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index 8e2ed075db..09ed80c2b0 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit 8e2ed075db7f4d5f942b5ea354070d6273c01638 +Subproject commit 09ed80c2b047ae5bb41ddbfb9be44ec2bc71fedd From 87ebdaa74e84966ed297fa977cd2ed1e70e65ddf Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Fri, 9 Aug 2019 12:30:23 +0800 Subject: [PATCH 439/486] cmake: set component properties --- tools/ci/test_build_system_cmake.sh | 8 ++++++++ tools/cmake/component.cmake | 2 ++ 2 files changed, 10 insertions(+) diff --git a/tools/ci/test_build_system_cmake.sh b/tools/ci/test_build_system_cmake.sh index 5b2828d84a..bbe299b92f 100755 --- a/tools/ci/test_build_system_cmake.sh +++ b/tools/ci/test_build_system_cmake.sh @@ -510,6 +510,14 @@ endmenu\n" >> ${IDF_PATH}/Kconfig; mv CMakeLists.txt.bak CMakeLists.txt rm -rf CMakeLists.txt.bak + print_status "Component properties are set" + clean_build_dir + cp CMakeLists.txt CMakeLists.txt.bak + printf "\nidf_component_get_property(srcs main SRCS)\nmessage(STATUS SRCS:\${srcs})" >> CMakeLists.txt + (idf.py reconfigure | grep "SRCS:$(realpath main/main.c)") || failure "Component properties should be set" + rm -rf CMakeLists.txt + mv CMakeLists.txt.bak CMakeLists.txt + rm -rf CMakeLists.txt.bak print_status "All tests completed" if [ -n "${FAILURES}" ]; then diff --git a/tools/cmake/component.cmake b/tools/cmake/component.cmake index 6959af26c2..21950dee97 100644 --- a/tools/cmake/component.cmake +++ b/tools/cmake/component.cmake @@ -479,6 +479,8 @@ function(idf_component_register) # COMPONENT_TARGET is deprecated but is made available with same function # as COMPONENT_LIB for compatibility. set(COMPONENT_TARGET ${component_lib} PARENT_SCOPE) + + __component_set_properties() endfunction() # From caea2889c808e3844f73388fda7c5cb254c9501e Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 21 May 2019 18:12:42 +1000 Subject: [PATCH 440/486] aes: Add fault injection checks when writing key to hardware Vulnerability reported by LimitedResults under Espressif Bug Bounty Program. --- components/idf_test/include/idf_performance.h | 2 +- components/mbedtls/port/esp32/aes.c | 108 +++++++++++++++--- components/mbedtls/port/include/esp32/aes.h | 6 +- 3 files changed, 92 insertions(+), 24 deletions(-) diff --git a/components/idf_test/include/idf_performance.h b/components/idf_test/include/idf_performance.h index 137c1b74b3..8a952c406b 100644 --- a/components/idf_test/include/idf_performance.h +++ b/components/idf_test/include/idf_performance.h @@ -26,7 +26,7 @@ #define IDF_PERFORMANCE_MAX_ESP32_TIME_SHA1_32KB 5000 #define IDF_PERFORMANCE_MAX_ESP32_TIME_SHA512_32KB 4500 // AES-CBC hardware throughput (accounts for worst-case performance with PSRAM workaround) -#define IDF_PERFORMANCE_MIN_AES_CBC_THROUGHPUT_MBSEC 8.5 +#define IDF_PERFORMANCE_MIN_AES_CBC_THROUGHPUT_MBSEC 8.2 // floating point instructions per divide and per sqrt (configured for worst-case with PSRAM workaround) #define IDF_PERFORMANCE_MAX_ESP32_CYCLES_PER_DIV 70 #define IDF_PERFORMANCE_MAX_ESP32_CYCLES_PER_SQRT 140 diff --git a/components/mbedtls/port/esp32/aes.c b/components/mbedtls/port/esp32/aes.c index 3925f13e47..db8f1bf570 100644 --- a/components/mbedtls/port/esp32/aes.c +++ b/components/mbedtls/port/esp32/aes.c @@ -49,6 +49,11 @@ */ static portMUX_TYPE aes_spinlock = portMUX_INITIALIZER_UNLOCKED; +static inline bool valid_key_length(const esp_aes_context *ctx) +{ + return ctx->key_bytes == 128/8 || ctx->key_bytes == 192/8 || ctx->key_bytes == 256/8; +} + void esp_aes_acquire_hardware( void ) { portENTER_CRITICAL(&aes_spinlock); @@ -93,6 +98,7 @@ int esp_aes_setkey( esp_aes_context *ctx, const unsigned char *key, } ctx->key_bytes = keybits / 8; memcpy(ctx->key, key, ctx->key_bytes); + ctx->key_in_hardware = 0; return 0; } @@ -102,28 +108,47 @@ int esp_aes_setkey( esp_aes_context *ctx, const unsigned char *key, * * Call only while holding esp_aes_acquire_hardware(). */ -static inline void esp_aes_setkey_hardware( esp_aes_context *ctx, int mode) +static void esp_aes_setkey_hardware(esp_aes_context *ctx, int mode) { const uint32_t MODE_DECRYPT_BIT = 4; unsigned mode_reg_base = (mode == ESP_AES_ENCRYPT) ? 0 : MODE_DECRYPT_BIT; + ctx->key_in_hardware = 0; + for (int i = 0; i < ctx->key_bytes/4; ++i) { DPORT_REG_WRITE(AES_KEY_BASE + i * 4, *(((uint32_t *)ctx->key) + i)); + ctx->key_in_hardware += 4; } DPORT_REG_WRITE(AES_MODE_REG, mode_reg_base + ((ctx->key_bytes / 8) - 2)); + + /* Fault injection check: all words of key data should have been written to hardware */ + if (ctx->key_in_hardware < 16 + || ctx->key_in_hardware != ctx->key_bytes) { + abort(); + } } /* Run a single 16 byte block of AES, using the hardware engine. * * Call only while holding esp_aes_acquire_hardware(). */ -static void esp_aes_block(const void *input, void *output) +static int esp_aes_block(esp_aes_context *ctx, const void *input, void *output) { const uint32_t *input_words = (const uint32_t *)input; uint32_t i0, i1, i2, i3; uint32_t *output_words = (uint32_t *)output; + /* If no key is written to hardware yet, either the user hasn't called + mbedtls_aes_setkey_enc/mbedtls_aes_setkey_dec - meaning we also don't + know which mode to use - or a fault skipped the + key write to hardware. Treat this as a fatal error and zero the output block. + */ + if (ctx->key_in_hardware != ctx->key_bytes) { + bzero(output, 16); + return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH; + } + /* Storing i0,i1,i2,i3 in registers not an array helps a lot with optimisations at -Os level */ i0 = input_words[0]; @@ -152,11 +177,14 @@ static void esp_aes_block(const void *input, void *output) Bypassing this check requires at least one additional fault. */ if(i0 == output_words[0] && i1 == output_words[1] && i2 == output_words[2] && i3 == output_words[3]) { - // calling two zeroing functions to narrow the - // window for a double-fault here + // calling zeroing functions to narrow the + // window for a double-fault of the abort step, here memset(output, 0, 16); mbedtls_platform_zeroize(output, 16); + abort(); } + + return 0; } /* @@ -166,11 +194,18 @@ int esp_internal_aes_encrypt( esp_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ) { + int r; + + if (!valid_key_length(ctx)) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); - esp_aes_block(input, output); + r = esp_aes_block(ctx, input, output); esp_aes_release_hardware(); - return 0; + return r; } void esp_aes_encrypt( esp_aes_context *ctx, @@ -188,11 +223,18 @@ int esp_internal_aes_decrypt( esp_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ) { + int r; + + if (!valid_key_length(ctx)) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; esp_aes_setkey_hardware(ctx, ESP_AES_DECRYPT); - esp_aes_block(input, output); + r = esp_aes_block(ctx, input, output); esp_aes_release_hardware(); - return 0; + return r; } void esp_aes_decrypt( esp_aes_context *ctx, @@ -202,7 +244,6 @@ void esp_aes_decrypt( esp_aes_context *ctx, esp_internal_aes_decrypt(ctx, input, output); } - /* * AES-ECB block encryption/decryption */ @@ -211,12 +252,19 @@ int esp_aes_crypt_ecb( esp_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ) { + int r; + + if (!valid_key_length(ctx)) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; esp_aes_setkey_hardware(ctx, mode); - esp_aes_block(input, output); + r = esp_aes_block(ctx, input, output); esp_aes_release_hardware(); - return 0; + return r; } @@ -240,14 +288,19 @@ int esp_aes_crypt_cbc( esp_aes_context *ctx, return ( ERR_ESP_AES_INVALID_INPUT_LENGTH ); } + if (!valid_key_length(ctx)) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; esp_aes_setkey_hardware(ctx, mode); if ( mode == ESP_AES_DECRYPT ) { while ( length > 0 ) { memcpy(temp, input_words, 16); - esp_aes_block(input_words, output_words); + esp_aes_block(ctx, input_words, output_words); for ( i = 0; i < 4; i++ ) { output_words[i] = output_words[i] ^ iv_words[i]; @@ -266,7 +319,7 @@ int esp_aes_crypt_cbc( esp_aes_context *ctx, output_words[i] = input_words[i] ^ iv_words[i]; } - esp_aes_block(output_words, output_words); + esp_aes_block(ctx, output_words, output_words); memcpy( iv_words, output_words, 16 ); input_words += 4; @@ -294,14 +347,19 @@ int esp_aes_crypt_cfb128( esp_aes_context *ctx, int c; size_t n = *iv_off; + if (!valid_key_length(ctx)) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); if ( mode == ESP_AES_DECRYPT ) { while ( length-- ) { if ( n == 0 ) { - esp_aes_block(iv, iv ); + esp_aes_block(ctx, iv, iv); } c = *input++; @@ -313,7 +371,7 @@ int esp_aes_crypt_cfb128( esp_aes_context *ctx, } else { while ( length-- ) { if ( n == 0 ) { - esp_aes_block(iv, iv ); + esp_aes_block(ctx, iv, iv); } iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); @@ -342,13 +400,18 @@ int esp_aes_crypt_cfb8( esp_aes_context *ctx, unsigned char c; unsigned char ov[17]; + if (!valid_key_length(ctx)) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); while ( length-- ) { memcpy( ov, iv, 16 ); - esp_aes_block(iv, iv); + esp_aes_block(ctx, iv, iv); if ( mode == ESP_AES_DECRYPT ) { ov[16] = *input; @@ -382,13 +445,18 @@ int esp_aes_crypt_ctr( esp_aes_context *ctx, int c, i; size_t n = *nc_off; + if (!valid_key_length(ctx)) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); while ( length-- ) { if ( n == 0 ) { - esp_aes_block(nonce_counter, stream_block); + esp_aes_block(ctx, nonce_counter, stream_block); for ( i = 16; i > 0; i-- ) if ( ++nonce_counter[i - 1] != 0 ) { @@ -432,13 +500,17 @@ int esp_aes_crypt_ofb( esp_aes_context *ctx, return( MBEDTLS_ERR_AES_BAD_INPUT_DATA ); } + if (!valid_key_length(ctx)) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + esp_aes_acquire_hardware(); esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); while( length-- ) { if( n == 0 ) { - esp_aes_block( iv, iv ); + esp_aes_block(ctx, iv, iv); } *output++ = *input++ ^ iv[n]; diff --git a/components/mbedtls/port/include/esp32/aes.h b/components/mbedtls/port/include/esp32/aes.h index 962e148066..1071930154 100644 --- a/components/mbedtls/port/include/esp32/aes.h +++ b/components/mbedtls/port/include/esp32/aes.h @@ -41,17 +41,13 @@ extern "C" { /** * \brief AES context structure * - * \note buf is able to hold 32 extra bytes, which can be used: - * - for alignment purposes if VIA padlock is used, and/or - * - to simplify key expansion in the 256-bit case by - * generating an extra round key */ typedef struct { uint8_t key_bytes; + volatile uint8_t key_in_hardware; /* This variable is used for fault injection checks, so marked volatile to avoid optimisation */ uint8_t key[32]; } esp_aes_context; - /** * \brief The AES XTS context-type definition. */ From aa3c988c17b40286734030151f7940ef30f9dcac Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 22 May 2019 10:18:55 +1000 Subject: [PATCH 441/486] sha: Add fault injection checks reading hash digest state Vulnerability reported by LimitedResults under Espressif Bug Bounty Program. --- components/mbedtls/port/esp32/sha.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/components/mbedtls/port/esp32/sha.c b/components/mbedtls/port/esp32/sha.c index 7b7a0f415b..35c52eee3a 100644 --- a/components/mbedtls/port/esp32/sha.c +++ b/components/mbedtls/port/esp32/sha.c @@ -228,6 +228,7 @@ void esp_sha_read_digest_state(esp_sha_type sha_type, void *digest_state) { uint32_t *digest_state_words = NULL; uint32_t *reg_addr_buf = NULL; + uint32_t word_len = sha_length(sha_type)/4; #ifndef NDEBUG { SemaphoreHandle_t *engine_state = sha_get_engine_state(sha_type); @@ -250,15 +251,25 @@ void esp_sha_read_digest_state(esp_sha_type sha_type, void *digest_state) if(sha_type == SHA2_384 || sha_type == SHA2_512) { /* for these ciphers using 64-bit states, swap each pair of words */ DPORT_INTERRUPT_DISABLE(); // Disable interrupt only on current CPU. - for(int i = 0; i < sha_length(sha_type)/4; i += 2) { + for(int i = 0; i < word_len; i += 2) { digest_state_words[i+1] = DPORT_SEQUENCE_REG_READ((uint32_t)®_addr_buf[i]); digest_state_words[i] = DPORT_SEQUENCE_REG_READ((uint32_t)®_addr_buf[i+1]); } DPORT_INTERRUPT_RESTORE(); // restore the previous interrupt level } else { - esp_dport_access_read_buffer(digest_state_words, (uint32_t)®_addr_buf[0], sha_length(sha_type)/4); + esp_dport_access_read_buffer(digest_state_words, (uint32_t)®_addr_buf[0], word_len); } esp_sha_unlock_memory_block(); + + /* Fault injection check: verify SHA engine actually ran, + state is not all zeroes. + */ + for (int i = 0; i < word_len; i++) { + if (digest_state_words[i] != 0) { + return; + } + } + abort(); // SHA peripheral returned all zero state, probably due to fault injection } void esp_sha_block(esp_sha_type sha_type, const void *data_block, bool is_first_block) From 8658b1633c5bc43f50ba4de22b74f84541fa3ae6 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 12 Aug 2019 09:38:44 +1000 Subject: [PATCH 442/486] ci: Temporarily disable NimBLE tests in CI --- .../nimble/blecent/{blecent_test.py => blecent_test_noci.py} | 0 .../bluetooth/nimble/blehr/{blehr_test.py => blehr_test_noci.py} | 0 .../nimble/bleprph/{bleprph_test.py => bleprph_test_noci.py} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename examples/bluetooth/nimble/blecent/{blecent_test.py => blecent_test_noci.py} (100%) rename examples/bluetooth/nimble/blehr/{blehr_test.py => blehr_test_noci.py} (100%) rename examples/bluetooth/nimble/bleprph/{bleprph_test.py => bleprph_test_noci.py} (100%) diff --git a/examples/bluetooth/nimble/blecent/blecent_test.py b/examples/bluetooth/nimble/blecent/blecent_test_noci.py similarity index 100% rename from examples/bluetooth/nimble/blecent/blecent_test.py rename to examples/bluetooth/nimble/blecent/blecent_test_noci.py diff --git a/examples/bluetooth/nimble/blehr/blehr_test.py b/examples/bluetooth/nimble/blehr/blehr_test_noci.py similarity index 100% rename from examples/bluetooth/nimble/blehr/blehr_test.py rename to examples/bluetooth/nimble/blehr/blehr_test_noci.py diff --git a/examples/bluetooth/nimble/bleprph/bleprph_test.py b/examples/bluetooth/nimble/bleprph/bleprph_test_noci.py similarity index 100% rename from examples/bluetooth/nimble/bleprph/bleprph_test.py rename to examples/bluetooth/nimble/bleprph/bleprph_test_noci.py From a40e164988ccc5301c3f525867fa1d5f6ed2fc16 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 31 Jul 2019 11:07:23 +0800 Subject: [PATCH 443/486] doc: Add clarifications Xtensa Core ID and "Core ID" used in FreeRTOS are different Closes https://github.com/espressif/esp-idf/issues/2567 --- components/freertos/include/freertos/portmacro.h | 6 +++++- components/freertos/include/freertos/task.h | 6 +++--- components/freertos/include/freertos/xtensa_context.h | 3 +++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/components/freertos/include/freertos/portmacro.h b/components/freertos/include/freertos/portmacro.h index d5df0b274e..6b09a2ce8b 100644 --- a/components/freertos/include/freertos/portmacro.h +++ b/components/freertos/include/freertos/portmacro.h @@ -136,10 +136,14 @@ typedef unsigned portBASE_TYPE UBaseType_t; /* "mux" data structure (spinlock) */ typedef struct { /* owner field values: - * 0 - Uninitialized (invalid) + * 0 - Uninitialized (invalid) * portMUX_FREE_VAL - Mux is free, can be locked by either CPU * CORE_ID_PRO / CORE_ID_APP - Mux is locked to the particular core * + * Note that for performance reasons we use the full Xtensa CORE ID values + * (CORE_ID_PRO, CORE_ID_APP) and not the 0,1 values which are used in most + * other FreeRTOS code. + * * Any value other than portMUX_FREE_VAL, CORE_ID_PRO, CORE_ID_APP indicates corruption */ uint32_t owner; diff --git a/components/freertos/include/freertos/task.h b/components/freertos/include/freertos/task.h index 3fc06d9e38..8fb6ee22fb 100644 --- a/components/freertos/include/freertos/task.h +++ b/components/freertos/include/freertos/task.h @@ -185,7 +185,7 @@ typedef struct xTASK_STATUS StackType_t *pxStackBase; /*!< Points to the lowest address of the task's stack area. */ uint32_t usStackHighWaterMark; /*!< The minimum amount of stack space that has remained for the task since the task was created. The closer this value is to zero the closer the task has come to overflowing its stack. */ #if configTASKLIST_INCLUDE_COREID - BaseType_t xCoreID; /*!< Core this task is pinned to. This field is present if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID is set. */ + BaseType_t xCoreID; /*!< Core this task is pinned to (0, 1, or -1 for tskNO_AFFINITY). This field is present if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID is set. */ #endif } TaskStatus_t; @@ -324,7 +324,7 @@ is used in assert() statements. */ * * @param xCoreID If the value is tskNO_AFFINITY, the created task is not * pinned to any CPU, and the scheduler can run it on any core available. - * Other values indicate the index number of the CPU which the task should + * Values 0 or 1 indicate the index number of the CPU which the task should * be pinned to. Specifying values larger than (portNUM_PROCESSORS - 1) will * cause the function to fail. * @@ -476,7 +476,7 @@ is used in assert() statements. */ * * @param xCoreID If the value is tskNO_AFFINITY, the created task is not * pinned to any CPU, and the scheduler can run it on any core available. - * Other values indicate the index number of the CPU which the task should + * Values 0 or 1 indicate the index number of the CPU which the task should * be pinned to. Specifying values larger than (portNUM_PROCESSORS - 1) will * cause the function to fail. * diff --git a/components/freertos/include/freertos/xtensa_context.h b/components/freertos/include/freertos/xtensa_context.h index 9e6fe558f5..073a137bce 100644 --- a/components/freertos/include/freertos/xtensa_context.h +++ b/components/freertos/include/freertos/xtensa_context.h @@ -325,6 +325,9 @@ STRUCT_END(XtSolFrame) .endm #endif +/* Note: These are different to xCoreID used in ESP-IDF FreeRTOS, we just use + 0 and 1 which are determined by checking bit 13 (see previous comment) +*/ #define CORE_ID_PRO 0xCDCD #define CORE_ID_APP 0xABAB From 4fe74b8f6471d302cd0f7fa812ce53e2dfa01134 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 12 Aug 2019 11:12:34 +1000 Subject: [PATCH 444/486] freertos: Rename CORE_ID_PRO/CORE_ID_APP macros to CORE_ID_REGVAL_xxx Old values remain for compatibility. As suggested in https://github.com/espressif/esp-idf/issues/2567 --- components/freertos/include/freertos/portmacro.h | 6 +++--- .../freertos/include/freertos/xtensa_context.h | 12 +++++++++--- components/freertos/portmux_impl.h | 2 +- components/freertos/portmux_impl.inc.h | 12 ++++++------ 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/components/freertos/include/freertos/portmacro.h b/components/freertos/include/freertos/portmacro.h index 6b09a2ce8b..d6b2184655 100644 --- a/components/freertos/include/freertos/portmacro.h +++ b/components/freertos/include/freertos/portmacro.h @@ -138,13 +138,13 @@ typedef struct { /* owner field values: * 0 - Uninitialized (invalid) * portMUX_FREE_VAL - Mux is free, can be locked by either CPU - * CORE_ID_PRO / CORE_ID_APP - Mux is locked to the particular core + * CORE_ID_REGVAL_PRO / CORE_ID_REGVAL_APP - Mux is locked to the particular core * * Note that for performance reasons we use the full Xtensa CORE ID values - * (CORE_ID_PRO, CORE_ID_APP) and not the 0,1 values which are used in most + * (CORE_ID_REGVAL_PRO, CORE_ID_REGVAL_APP) and not the 0,1 values which are used in most * other FreeRTOS code. * - * Any value other than portMUX_FREE_VAL, CORE_ID_PRO, CORE_ID_APP indicates corruption + * Any value other than portMUX_FREE_VAL, CORE_ID_REGVAL_PRO, CORE_ID_REGVAL_APP indicates corruption */ uint32_t owner; /* count field: diff --git a/components/freertos/include/freertos/xtensa_context.h b/components/freertos/include/freertos/xtensa_context.h index 073a137bce..120676dad4 100644 --- a/components/freertos/include/freertos/xtensa_context.h +++ b/components/freertos/include/freertos/xtensa_context.h @@ -325,11 +325,17 @@ STRUCT_END(XtSolFrame) .endm #endif -/* Note: These are different to xCoreID used in ESP-IDF FreeRTOS, we just use +/* Note: These are different to xCoreID used in ESP-IDF FreeRTOS, most places use 0 and 1 which are determined by checking bit 13 (see previous comment) */ -#define CORE_ID_PRO 0xCDCD -#define CORE_ID_APP 0xABAB +#define CORE_ID_REGVAL_PRO 0xCDCD +#define CORE_ID_REGVAL_APP 0xABAB + +/* Included for compatibility, recommend using CORE_ID_REGVAL_PRO instead */ +#define CORE_ID_PRO CORE_ID_REGVAL_PRO + +/* Included for compatibility, recommend using CORE_ID_REGVAL_APP instead */ +#define CORE_ID_APP CORE_ID_REGVAL_APP /* ------------------------------------------------------------------------------- diff --git a/components/freertos/portmux_impl.h b/components/freertos/portmux_impl.h index 5aef351b63..691ad01e2f 100644 --- a/components/freertos/portmux_impl.h +++ b/components/freertos/portmux_impl.h @@ -49,7 +49,7 @@ #include "soc/soc_memory_layout.h" /* XOR one core ID with this value to get the other core ID */ -#define CORE_ID_XOR_SWAP (CORE_ID_PRO ^ CORE_ID_APP) +#define CORE_ID_REGVAL_XOR_SWAP (CORE_ID_REGVAL_PRO ^ CORE_ID_REGVAL_APP) diff --git a/components/freertos/portmux_impl.inc.h b/components/freertos/portmux_impl.inc.h index 07a7ce9fe1..908fec1539 100644 --- a/components/freertos/portmux_impl.inc.h +++ b/components/freertos/portmux_impl.inc.h @@ -61,7 +61,7 @@ PORTMUX_AQUIRE_MUX_FN_NAME(portMUX_TYPE *mux, int timeout_cycles) { #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG uint32_t owner = mux->owner; - if (owner != portMUX_FREE_VAL && owner != CORE_ID_PRO && owner != CORE_ID_APP) { + if (owner != portMUX_FREE_VAL && owner != CORE_ID_REGVAL_PRO && owner != CORE_ID_REGVAL_APP) { ets_printf("ERROR: vPortCPUAcquireMutex: mux %p is uninitialized (0x%X)! Called from %s line %d.\n", mux, owner, fnName, line); mux->owner=portMUX_FREE_VAL; } @@ -70,13 +70,13 @@ PORTMUX_AQUIRE_MUX_FN_NAME(portMUX_TYPE *mux, int timeout_cycles) { /* Spin until we own the core */ RSR(PRID, coreID); - /* Note: coreID is the full 32 bit core ID (CORE_ID_PRO/CORE_ID_APP), + /* Note: coreID is the full 32 bit core ID (CORE_ID_REGVAL_PRO/CORE_ID_REGVAL_APP), not the 0/1 value returned by xPortGetCoreID() */ - otherCoreID = CORE_ID_XOR_SWAP ^ coreID; + otherCoreID = CORE_ID_REGVAL_XOR_SWAP ^ coreID; do { - /* mux->owner should be one of portMUX_FREE_VAL, CORE_ID_PRO, - CORE_ID_APP: + /* mux->owner should be one of portMUX_FREE_VAL, CORE_ID_REGVAL_PRO, + CORE_ID_REGVAL_APP: - If portMUX_FREE_VAL, we want to atomically set to 'coreID'. - If "our" coreID, we can drop through immediately. @@ -138,7 +138,7 @@ static inline void PORTMUX_RELEASE_MUX_FN_NAME(portMUX_TYPE *mux) { mux->lastLockedFn=fnName; mux->lastLockedLine=line; uint32_t owner = mux->owner; - if (owner != portMUX_FREE_VAL && owner != CORE_ID_PRO && owner != CORE_ID_APP) { + if (owner != portMUX_FREE_VAL && owner != CORE_ID_REGVAL_PRO && owner != CORE_ID_REGVAL_APP) { ets_printf("ERROR: vPortCPUReleaseMutex: mux %p is invalid (0x%x)!\n", mux, mux->owner); } #endif From 2f56116db2efd457b081c62dc8bcd142d48437d4 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 9 Aug 2019 15:26:49 +1000 Subject: [PATCH 445/486] Cleanup of previous merge commit --- components/bootloader_support/CMakeLists.txt | 2 +- components/bootloader_support/component.mk | 2 + components/driver/include/driver/touch_pad.h | 53 ++++--- components/esp_wifi/src/fast_crypto_ops.c | 158 ------------------- components/spi_flash/spi_flash_os_func_app.c | 6 + components/ulp/ulp_private.h | 21 +++ components/xtensa/CMakeLists.txt | 3 +- 7 files changed, 59 insertions(+), 186 deletions(-) delete mode 100644 components/esp_wifi/src/fast_crypto_ops.c create mode 100644 components/ulp/ulp_private.h diff --git a/components/bootloader_support/CMakeLists.txt b/components/bootloader_support/CMakeLists.txt index 9e945ba189..92b04097e6 100644 --- a/components/bootloader_support/CMakeLists.txt +++ b/components/bootloader_support/CMakeLists.txt @@ -7,7 +7,7 @@ set(srcs "src/esp_image_format.c" "src/flash_partitions.c" "src/flash_qio_mode.c" - "src/${IDF_TARGET}/bootloader_flash_config_${IDF_TARGET}.c" + "src/bootloader_flash_config_${IDF_TARGET}.c" ) if(CONFIG_IDF_TARGET_ESP32) diff --git a/components/bootloader_support/component.mk b/components/bootloader_support/component.mk index 9990ae831c..762099f944 100644 --- a/components/bootloader_support/component.mk +++ b/components/bootloader_support/component.mk @@ -19,6 +19,8 @@ ifndef IS_BOOTLOADER_BUILD COMPONENT_OBJEXCLUDE := src/bootloader_init.o endif +COMPONENT_OBJEXCLUDE += src/bootloader_flash_config_esp32s2beta.o + # # Secure boot signing key support # diff --git a/components/driver/include/driver/touch_pad.h b/components/driver/include/driver/touch_pad.h index aa57eeb65e..e9338467ba 100644 --- a/components/driver/include/driver/touch_pad.h +++ b/components/driver/include/driver/touch_pad.h @@ -14,6 +14,7 @@ #ifndef _DRIVER_TOUCH_PAD_H_ #define _DRIVER_TOUCH_PAD_H_ + #ifdef __cplusplus extern "C" { #endif @@ -309,6 +310,31 @@ esp_err_t touch_pad_isr_deregister(void(*fn)(void *), void *arg); */ esp_err_t touch_pad_get_wakeup_status(touch_pad_t *pad_num); +/** + * @brief Get the touch sensor status, usually used in ISR to decide which pads are 'touched'. + * @return + * - touch status + */ +uint32_t touch_pad_get_status(void); + +/** + * @brief Set touch sensor FSM mode, the test action can be triggered by the timer, + * as well as by the software. + * @param mode FSM mode + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if argument is wrong + */ +esp_err_t touch_pad_set_fsm_mode(touch_fsm_mode_t mode); + +/** + * @brief Get touch sensor FSM mode + * @param mode pointer to accept FSM mode + * @return + * - ESP_OK on success + */ +esp_err_t touch_pad_get_fsm_mode(touch_fsm_mode_t *mode); + #if CONFIG_IDF_TARGET_ESP32 /** @@ -342,7 +368,7 @@ esp_err_t touch_pad_config(touch_pad_t touch_num, uint16_t threshold); * - ESP_OK Success * - ESP_ERR_INVALID_ARG Touch pad parameter error * - ESP_ERR_INVALID_STATE This touch pad hardware connection is error, the value of "touch_value" is 0. - * - ESP_FAIL Touch pad not initialized +p * - ESP_FAIL Touch pad not initialized */ esp_err_t touch_pad_read(touch_pad_t touch_num, uint16_t * touch_value); @@ -513,24 +539,6 @@ esp_err_t touch_pad_get_cnt_mode(touch_pad_t touch_num, touch_cnt_slope_t *slope */ esp_err_t touch_pad_io_init(touch_pad_t touch_num); -/** - * @brief Set touch sensor FSM mode, the test action can be triggered by the timer, - * as well as by the software. - * @param mode FSM mode - * @return - * - ESP_OK on success - * - ESP_ERR_INVALID_ARG if argument is wrong - */ -esp_err_t touch_pad_set_fsm_mode(touch_fsm_mode_t mode); - -/** - * @brief Get touch sensor FSM mode - * @param mode pointer to accept FSM mode - * @return - * - ESP_OK on success - */ -esp_err_t touch_pad_get_fsm_mode(touch_fsm_mode_t *mode); - /** * @brief Trigger a touch sensor measurement, only support in SW mode of FSM * @return @@ -642,13 +650,6 @@ esp_err_t touch_pad_clear_group_mask(uint16_t set1_mask, uint16_t set2_mask, uin */ esp_err_t touch_pad_clear_status(void); -/** - * @brief Get the touch sensor status, usually used in ISR to decide which pads are 'touched'. - * @return - * - touch status - */ -uint32_t touch_pad_get_status(void); - /** * @brief To enable touch pad interrupt * @return diff --git a/components/esp_wifi/src/fast_crypto_ops.c b/components/esp_wifi/src/fast_crypto_ops.c deleted file mode 100644 index b6045f30e2..0000000000 --- a/components/esp_wifi/src/fast_crypto_ops.c +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2015-2017 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 "crypto/common.h" -#include "crypto/aes_wrap.h" -#include "crypto/sha256.h" -#include "crypto/crypto.h" -#include "crypto/md5.h" -#include "crypto/sha1.h" -#include "crypto/aes.h" -#include "crypto/dh_group5.h" -#include "wps/wps.h" -#include "wps/wps_i.h" -#include "wpa2/eap_peer/eap.h" -#include "wpa2/tls/tls.h" -#include "wpa2/eap_peer/eap_methods.h" -#include "wpa2/eap_peer/eap_i.h" -#include "wpa2/eap_peer/eap_common.h" -#include "esp_wifi_crypto_types.h" - -// TODO: fix hardware crypto support for esp32s2beta - IDF-757 - -/* - * The parameters is used to set the cyrpto callback function for station connect when in security mode, - * every callback function can register as fast_xxx or normal one, i.e, fast_aes_wrap or aes_wrap, the - * difference between them is the normal API is calculate by software, the fast one use the hardware - * crypto in it, can be faster than the normal one, so the callback function register in default is which - * we recommend, so as the API in WPS default and WPA2 default. - */ -const wpa_crypto_funcs_t g_wifi_default_wpa_crypto_funcs = { - .size = sizeof(wpa_crypto_funcs_t), - .version = ESP_WIFI_CRYPTO_VERSION, -#if CONFIG_IDF_TARGET_ESP32 - .aes_wrap = (esp_aes_wrap_t)fast_aes_wrap, - .aes_unwrap = (esp_aes_unwrap_t)fast_aes_unwrap, - .hmac_sha256_vector = (esp_hmac_sha256_vector_t)fast_hmac_sha256_vector, - .sha256_prf = (esp_sha256_prf_t)fast_sha256_prf, -#elif CONFIG_IDF_TARGET_ESP32S2BETA - .aes_wrap = (esp_aes_wrap_t)aes_wrap, - .aes_unwrap = (esp_aes_unwrap_t)aes_unwrap, - .hmac_sha256_vector = (esp_hmac_sha256_vector_t)hmac_sha256_vector, - .sha256_prf = (esp_sha256_prf_t)sha256_prf, -#endif - .hmac_md5 = (esp_hmac_md5_t)hmac_md5, - .hamc_md5_vector = (esp_hmac_md5_vector_t)hmac_md5_vector, - .hmac_sha1 = (esp_hmac_sha1_t)hmac_sha1, - .hmac_sha1_vector = (esp_hmac_sha1_vector_t)hmac_sha1_vector, - .sha1_prf = (esp_sha1_prf_t)sha1_prf, - .sha1_vector = (esp_sha1_vector_t)sha1_vector, - .pbkdf2_sha1 = (esp_pbkdf2_sha1_t)pbkdf2_sha1, - .rc4_skip = (esp_rc4_skip_t)rc4_skip, - .md5_vector = (esp_md5_vector_t)md5_vector, - .aes_encrypt = (esp_aes_encrypt_t)aes_encrypt, - .aes_encrypt_init = (esp_aes_encrypt_init_t)aes_encrypt_init, - .aes_encrypt_deinit = (esp_aes_encrypt_deinit_t)aes_encrypt_deinit, - .aes_decrypt = (esp_aes_decrypt_t)aes_decrypt, - .aes_decrypt_init = (esp_aes_decrypt_init_t)aes_decrypt_init, - .aes_decrypt_deinit = (esp_aes_decrypt_deinit_t)aes_decrypt_deinit -}; - -const wps_crypto_funcs_t g_wifi_default_wps_crypto_funcs = { - .size = sizeof(wps_crypto_funcs_t), - .version = ESP_WIFI_CRYPTO_VERSION, -#if CONFIG_IDF_TARGET_ESP32 - .aes_128_encrypt = (esp_aes_128_encrypt_t)fast_aes_128_cbc_encrypt, - .aes_128_decrypt = (esp_aes_128_decrypt_t)fast_aes_128_cbc_decrypt, - .crypto_mod_exp = (esp_crypto_mod_exp_t)fast_crypto_mod_exp, - .hmac_sha256 = (esp_hmac_sha256_t)fast_hmac_sha256, - .hmac_sha256_vector = (esp_hmac_sha256_vector_t)fast_hmac_sha256_vector, - .sha256_vector = (esp_sha256_vector_t)fast_sha256_vector, -#elif CONFIG_IDF_TARGET_ESP32S2BETA - .aes_128_encrypt = (esp_aes_128_encrypt_t)aes_128_cbc_encrypt, - .aes_128_decrypt = (esp_aes_128_decrypt_t)aes_128_cbc_decrypt, - .crypto_mod_exp = (esp_crypto_mod_exp_t)crypto_mod_exp, - .hmac_sha256 = (esp_hmac_sha256_t)hmac_sha256, - .hmac_sha256_vector = (esp_hmac_sha256_vector_t)hmac_sha256_vector, - .sha256_vector = (esp_sha256_vector_t)fast_sha256_vector, -#endif - .uuid_gen_mac_addr = (esp_uuid_gen_mac_addr_t)uuid_gen_mac_addr, - .dh5_free = (esp_dh5_free_t)dh5_free, - .wps_build_assoc_req_ie = (esp_wps_build_assoc_req_ie_t)wps_build_assoc_req_ie, - .wps_build_assoc_resp_ie = (esp_wps_build_assoc_resp_ie_t)wps_build_assoc_resp_ie, - .wps_build_probe_req_ie = (esp_wps_build_probe_req_ie_t)wps_build_probe_req_ie, - .wps_build_public_key = (esp_wps_build_public_key_t)wps_build_public_key, - .wps_enrollee_get_msg = (esp_wps_enrollee_get_msg_t)wps_enrollee_get_msg, - .wps_enrollee_process_msg = (esp_wps_enrollee_process_msg_t)wps_enrollee_process_msg, - .wps_generate_pin = (esp_wps_generate_pin_t)wps_generate_pin, - .wps_is_selected_pin_registrar = (esp_wps_is_selected_pin_registrar_t)wps_is_selected_pin_registrar, - .wps_is_selected_pbc_registrar = (esp_wps_is_selected_pbc_registrar_t)wps_is_selected_pbc_registrar, - .eap_msg_alloc = (esp_eap_msg_alloc_t)eap_msg_alloc -}; - -/* - * What should notice is that the cyrpto hash type function and crypto cipher type function can not register - * as different, i.e, if you use fast_crypto_hash_init, you should use fast_crypto_hash_update and - * fast_crypto_hash_finish for finish hash calculate, rather than call crypto_hash_update and - * crypto_hash_finish, so do crypto_cipher. - */ -const wpa2_crypto_funcs_t g_wifi_default_wpa2_crypto_funcs = { - .size = sizeof(wpa2_crypto_funcs_t), - .version = ESP_WIFI_CRYPTO_VERSION, -#if CONFIG_IDF_TARGET_ESP32 - .crypto_hash_init = (esp_crypto_hash_init_t)fast_crypto_hash_init, - .crypto_hash_update = (esp_crypto_hash_update_t)fast_crypto_hash_update, - .crypto_hash_finish = (esp_crypto_hash_finish_t)fast_crypto_hash_finish, - .crypto_cipher_init = (esp_crypto_cipher_init_t)fast_crypto_cipher_init, - .crypto_cipher_encrypt = (esp_crypto_cipher_encrypt_t)fast_crypto_cipher_encrypt, - .crypto_cipher_decrypt = (esp_crypto_cipher_decrypt_t)fast_crypto_cipher_decrypt, - .crypto_cipher_deinit = (esp_crypto_cipher_deinit_t)fast_crypto_cipher_deinit, - .crypto_mod_exp = (esp_crypto_mod_exp_t)crypto_mod_exp, - .sha256_vector = (esp_sha256_vector_t)fast_sha256_vector, -#elif CONFIG_IDF_TARGET_ESP32S2BETA - .crypto_hash_init = (esp_crypto_hash_init_t)crypto_hash_init, - .crypto_hash_update = (esp_crypto_hash_update_t)crypto_hash_update, - .crypto_hash_finish = (esp_crypto_hash_finish_t)crypto_hash_finish, - .crypto_cipher_init = (esp_crypto_cipher_init_t)crypto_cipher_init, - .crypto_cipher_encrypt = (esp_crypto_cipher_encrypt_t)crypto_cipher_encrypt, - .crypto_cipher_decrypt = (esp_crypto_cipher_decrypt_t)crypto_cipher_decrypt, - .crypto_cipher_deinit = (esp_crypto_cipher_deinit_t)crypto_cipher_deinit, - .crypto_mod_exp = (esp_crypto_mod_exp_t)crypto_mod_exp, - .sha256_vector = (esp_sha256_vector_t)sha256_vector, -#endif - .tls_init = (esp_tls_init_t)tls_init, - .tls_deinit = (esp_tls_deinit_t)tls_deinit, - .eap_peer_blob_init = (esp_eap_peer_blob_init_t)eap_peer_blob_init, - .eap_peer_blob_deinit = (esp_eap_peer_blob_deinit_t)eap_peer_blob_deinit, - .eap_peer_config_init = (esp_eap_peer_config_init_t)eap_peer_config_init, - .eap_peer_config_deinit = (esp_eap_peer_config_deinit_t)eap_peer_config_deinit, - .eap_peer_register_methods = (esp_eap_peer_register_methods_t)eap_peer_register_methods, - .eap_peer_unregister_methods = (esp_eap_peer_unregister_methods_t)eap_peer_unregister_methods, - .eap_deinit_prev_method = (esp_eap_deinit_prev_method_t)eap_deinit_prev_method, - .eap_peer_get_eap_method = (esp_eap_peer_get_eap_method_t)eap_peer_get_eap_method, - .eap_sm_abort = (esp_eap_sm_abort_t)eap_sm_abort, - .eap_sm_build_nak = (esp_eap_sm_build_nak_t)eap_sm_build_nak, - .eap_sm_build_identity_resp = (esp_eap_sm_build_identity_resp_t)eap_sm_build_identity_resp, - .eap_msg_alloc = (esp_eap_msg_alloc_t)eap_msg_alloc -}; - -const mesh_crypto_funcs_t g_wifi_default_mesh_crypto_funcs = { -#if CONFIG_IDF_TARGET_ESP32 - .aes_128_encrypt = (esp_aes_128_encrypt_t)fast_aes_128_cbc_encrypt, - .aes_128_decrypt = (esp_aes_128_decrypt_t)fast_aes_128_cbc_decrypt, -#elif CONFIG_IDF_TARGET_ESP32S2BETA - .aes_128_encrypt = (esp_aes_128_encrypt_t)aes_128_cbc_encrypt, - .aes_128_decrypt = (esp_aes_128_decrypt_t)aes_128_cbc_decrypt, -#endif -}; diff --git a/components/spi_flash/spi_flash_os_func_app.c b/components/spi_flash/spi_flash_os_func_app.c index b2e13c8e44..df4f131abb 100644 --- a/components/spi_flash/spi_flash_os_func_app.c +++ b/components/spi_flash/spi_flash_os_func_app.c @@ -18,6 +18,12 @@ #include "esp_spi_flash.h" //for ``g_flash_guard_default_ops`` #include "esp_flash.h" +#ifdef CONFIG_IDF_TARGET_ESP32 +#include "esp32/rom/ets_sys.h" +#else +#include "esp32s2beta/rom/ets_sys.h" +#endif + /* * OS functions providing delay service and arbitration among chips, and with the cache. * diff --git a/components/ulp/ulp_private.h b/components/ulp/ulp_private.h new file mode 100644 index 0000000000..3d5b281493 --- /dev/null +++ b/components/ulp/ulp_private.h @@ -0,0 +1,21 @@ +// Copyright 2019 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 + +#ifdef CONFIG_ESP32_ULP_COPROC_RESERVE_MEM +#define ULP_RESERVE_MEM CONFIG_ESP32_ULP_COPROC_RESERVE_MEM +#else +#define ULP_RESERVE_MEM CONFIG_ESP32S2_ULP_COPROC_RESERVE_MEM +#endif diff --git a/components/xtensa/CMakeLists.txt b/components/xtensa/CMakeLists.txt index e6bde10c2b..ce33679c27 100644 --- a/components/xtensa/CMakeLists.txt +++ b/components/xtensa/CMakeLists.txt @@ -5,7 +5,8 @@ else() set(priv_requires soc freertos) set(srcs "debug_helpers.c" "debug_helpers_asm.S" - "eri.c") + "eri.c" + "stdatomic.c") if(CONFIG_IDF_TARGET_ESP32) list(APPEND srcs "trax.c") From 8f74271d5d5d4257a07cfce7db6fa713483a6f7d Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 8 Aug 2019 15:27:22 +1000 Subject: [PATCH 446/486] esp_rom: Fail immediately if the wrong SoC's header file is included --- components/bootloader_support/src/bootloader_clock.c | 11 +++++++++-- components/esp_rom/include/esp32/rom/ets_sys.h | 4 ++++ components/esp_rom/include/esp32s2beta/rom/ets_sys.h | 6 ++++++ components/spi_flash/spi_flash_os_func_app.c | 1 - components/spi_flash/spi_flash_os_func_noos.c | 11 ++++++++--- components/wpa_supplicant/src/rsn_supp/wpa.h | 6 ++++++ components/xtensa/debug_helpers.c | 8 +++++++- 7 files changed, 40 insertions(+), 7 deletions(-) diff --git a/components/bootloader_support/src/bootloader_clock.c b/components/bootloader_support/src/bootloader_clock.c index c851295aff..d61f7a9432 100644 --- a/components/bootloader_support/src/bootloader_clock.c +++ b/components/bootloader_support/src/bootloader_clock.c @@ -11,13 +11,20 @@ // 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 "esp32/rom/uart.h" -#include "esp32/rom/rtc.h" +#include "sdkconfig.h" #include "soc/soc.h" #include "soc/rtc.h" #include "soc/dport_reg.h" #include "soc/efuse_periph.h" +#ifdef CONFIG_IDF_TARGET_ESP32 +#include "esp32/rom/uart.h" +#include "esp32/rom/rtc.h" +#else +#include "esp32s2beta/rom/uart.h" +#include "esp32s2beta/rom/rtc.h" +#endif + void bootloader_clock_configure(void) { // ROM bootloader may have put a lot of text into UART0 FIFO. diff --git a/components/esp_rom/include/esp32/rom/ets_sys.h b/components/esp_rom/include/esp32/rom/ets_sys.h index fe1dacbf2a..3485f0d406 100644 --- a/components/esp_rom/include/esp32/rom/ets_sys.h +++ b/components/esp_rom/include/esp32/rom/ets_sys.h @@ -25,6 +25,10 @@ #include "soc/soc.h" #endif +#ifndef CONFIG_IDF_TARGET_ESP32 +#error "This header should only be included when building for ESP32" +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/components/esp_rom/include/esp32s2beta/rom/ets_sys.h b/components/esp_rom/include/esp32s2beta/rom/ets_sys.h index 653ca2826c..f52994ad87 100644 --- a/components/esp_rom/include/esp32s2beta/rom/ets_sys.h +++ b/components/esp_rom/include/esp32s2beta/rom/ets_sys.h @@ -19,6 +19,12 @@ #include "soc/soc.h" +#include "sdkconfig.h" + +#ifndef CONFIG_IDF_TARGET_ESP32S2BETA +#error "This header should only be included when building for esp32s2beta" +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/components/spi_flash/spi_flash_os_func_app.c b/components/spi_flash/spi_flash_os_func_app.c index df4f131abb..7328250eba 100644 --- a/components/spi_flash/spi_flash_os_func_app.c +++ b/components/spi_flash/spi_flash_os_func_app.c @@ -13,7 +13,6 @@ // limitations under the License. #include -#include "esp32/rom/ets_sys.h" #include "esp_attr.h" #include "esp_spi_flash.h" //for ``g_flash_guard_default_ops`` #include "esp_flash.h" diff --git a/components/spi_flash/spi_flash_os_func_noos.c b/components/spi_flash/spi_flash_os_func_noos.c index 4b494279b0..0e4cc34a83 100644 --- a/components/spi_flash/spi_flash_os_func_noos.c +++ b/components/spi_flash/spi_flash_os_func_noos.c @@ -13,12 +13,17 @@ // limitations under the License. #include +#include "sdkconfig.h" #include "esp_flash.h" - -#include "esp32/rom/ets_sys.h" -#include "esp32/rom/cache.h" #include "esp_attr.h" +#ifdef CONFIG_IDF_TARGET_ESP32 +#include "esp32/rom/ets_sys.h" +#include "esp32/rom/cache.h" +#else +#include "esp32s2beta/rom/ets_sys.h" +#include "esp32s2beta/rom/cache.h" +#endif static esp_err_t start(void *arg) { diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.h b/components/wpa_supplicant/src/rsn_supp/wpa.h index c3475eafee..b7c9a3588c 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa.h @@ -15,7 +15,13 @@ #ifndef WPA_H #define WPA_H +#include "sdkconfig.h" + +#ifdef CONFIG_IDF_TARGET_ESP32 #include "esp32/rom/ets_sys.h" +#else +#include "esp32s2beta/rom/ets_sys.h" +#endif #include "utils/common.h" #include "common/defs.h" #include "common/wpa_common.h" diff --git a/components/xtensa/debug_helpers.c b/components/xtensa/debug_helpers.c index 564e6eb159..74f66a6cc4 100644 --- a/components/xtensa/debug_helpers.c +++ b/components/xtensa/debug_helpers.c @@ -12,14 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "sdkconfig.h" #include "esp_types.h" #include "esp_attr.h" #include "esp_err.h" #include "esp_debug_helpers.h" -#include "esp32/rom/ets_sys.h" #include "soc/soc_memory_layout.h" #include "soc/cpu.h" +#ifdef CONFIG_IDF_TARGET_ESP32 +#include "esp32/rom/ets_sys.h" +#else +#include "esp32s2beta/rom/ets_sys.h" +#endif + bool IRAM_ATTR esp_backtrace_get_next_frame(esp_backtrace_frame_t *frame) { //Use frame(i-1)'s BS area located below frame(i)'s sp to get frame(i-1)'s sp and frame(i-2)'s pc From b64551718c3b7ae3776e156943f228e80f57c1c9 Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Mon, 12 Aug 2019 19:45:48 +0800 Subject: [PATCH 447/486] gh_action: converted main.workflow to Actions V2 yml files --- .github/main.workflow | 22 ---------------------- .github/workflows/issue_comment.yml | 16 ++++++++++++++++ .github/workflows/issues.yml | 16 ++++++++++++++++ .github/workflows/pull_request.yml | 16 ++++++++++++++++ 4 files changed, 48 insertions(+), 22 deletions(-) delete mode 100644 .github/main.workflow create mode 100644 .github/workflows/issue_comment.yml create mode 100644 .github/workflows/issues.yml create mode 100644 .github/workflows/pull_request.yml diff --git a/.github/main.workflow b/.github/main.workflow deleted file mode 100644 index d23b686c5c..0000000000 --- a/.github/main.workflow +++ /dev/null @@ -1,22 +0,0 @@ -workflow "Sync issues to JIRA" { - on = "issues" - resolves = ["Sync to JIRA"] -} - -workflow "Sync issue and PR comments to JIRA" { - on = "issue_comment" - resolves = ["Sync to JIRA"] -} - -workflow "Sync PRs to JIRA" { - on = "pull_request" - resolves = ["Sync to JIRA"] -} - -action "Sync to JIRA" { - uses = "espressif/github-actions/sync_issues_to_jira@master" - secrets = ["GITHUB_TOKEN", "JIRA_URL", "JIRA_USER", "JIRA_PASS"] - env = { - JIRA_PROJECT = "IDFGH" - } -} diff --git a/.github/workflows/issue_comment.yml b/.github/workflows/issue_comment.yml new file mode 100644 index 0000000000..16069f1f13 --- /dev/null +++ b/.github/workflows/issue_comment.yml @@ -0,0 +1,16 @@ +on: issue_comment +name: Sync issue and PR comments to JIRA +jobs: + syncToJIRA: + name: Sync to JIRA + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Sync to JIRA + uses: espressif/github-actions/sync_issues_to_jira@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JIRA_PASS: ${{ secrets.JIRA_PASS }} + JIRA_PROJECT: IDFGH + JIRA_URL: ${{ secrets.JIRA_URL }} + JIRA_USER: ${{ secrets.JIRA_USER }} diff --git a/.github/workflows/issues.yml b/.github/workflows/issues.yml new file mode 100644 index 0000000000..3ead596888 --- /dev/null +++ b/.github/workflows/issues.yml @@ -0,0 +1,16 @@ +on: issues +name: Sync issues to JIRA +jobs: + syncToJIRA: + name: Sync to JIRA + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Sync to JIRA + uses: espressif/github-actions/sync_issues_to_jira@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JIRA_PASS: ${{ secrets.JIRA_PASS }} + JIRA_PROJECT: IDFGH + JIRA_URL: ${{ secrets.JIRA_URL }} + JIRA_USER: ${{ secrets.JIRA_USER }} diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 0000000000..324639e08b --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,16 @@ +on: pull_request +name: Sync PRs to JIRA +jobs: + syncToJIRA: + name: Sync to JIRA + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Sync to JIRA + uses: espressif/github-actions/sync_issues_to_jira@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JIRA_PASS: ${{ secrets.JIRA_PASS }} + JIRA_PROJECT: IDFGH + JIRA_URL: ${{ secrets.JIRA_URL }} + JIRA_USER: ${{ secrets.JIRA_USER }} From 0addc0aef1c09bd3b2c6b955e179c44fc144f5f2 Mon Sep 17 00:00:00 2001 From: Luke Bayes Date: Sun, 4 Aug 2019 17:05:03 -0400 Subject: [PATCH 448/486] Added -r flag to pip install command from file Closes https://github.com/espressif/esp-idf/pull/3874 Closes https://github.com/espressif/esp-idf/issues/3915 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 19c9980dd2..4be36b48d3 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ See the Getting Started guide links above for a detailed setup guide. This is a * Install host build dependencies mentioned in Getting Started guide. * Add `tools/` directory to the PATH -* Run `python -m pip install requirements.txt` to install Python dependencies +* Run `python -m pip install -r requirements.txt` to install Python dependencies ## Configuring the Project From f86e82cb63ec820982bc0b8e47a44813773b364a Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Mon, 29 Jul 2019 11:35:00 +0800 Subject: [PATCH 449/486] efuse: update the scheme of getting chip revision --- components/efuse/esp32/esp_efuse_table.c | 11 ++++++- components/efuse/esp32/esp_efuse_table.csv | 15 +++++----- .../efuse/esp32/include/esp_efuse_table.h | 3 +- components/efuse/src/esp_efuse_fields.c | 28 +++++++++++++++-- components/esp32/Kconfig | 28 +++++++++++++++++ components/esp32/cpu_start.c | 12 +++++++- components/esp32/dport_access.c | 8 ++--- components/esp32/include/esp32/dport_access.h | 2 +- components/esp32/system_api.c | 30 +++++++------------ components/esptool_py/esptool | 2 +- .../soc/esp32/include/soc/dport_access.h | 8 ++--- components/soc/esp32/include/soc/soc.h | 2 +- 12 files changed, 106 insertions(+), 43 deletions(-) diff --git a/components/efuse/esp32/esp_efuse_table.c b/components/efuse/esp32/esp_efuse_table.c index 36b54b50ba..e0d4e2d104 100644 --- a/components/efuse/esp32/esp_efuse_table.c +++ b/components/efuse/esp32/esp_efuse_table.c @@ -17,7 +17,7 @@ #include #include "esp_efuse_table.h" -// md5_digest_table 544d434da010ce22f7db1b14d38e1d66 +// md5_digest_table 2e23344575b3d07f01ecb695294e9770 // This file was generated from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY. // If you want to change some fields, you need to change esp_efuse_table.csv file // then run `efuse_common_table` or `efuse_custom_table` command it will generate this file. @@ -151,6 +151,10 @@ static const esp_efuse_desc_t CHIP_VER_REV1[] = { {EFUSE_BLK0, 111, 1}, // EFUSE_RD_CHIP_VER_REV1, }; +static const esp_efuse_desc_t CHIP_VER_REV2[] = { + {EFUSE_BLK0, 180, 1}, // EFUSE_RD_CHIP_VER_REV2, +}; + static const esp_efuse_desc_t XPD_SDIO_REG[] = { {EFUSE_BLK0, 142, 1}, // EFUSE_RD_XPD_SDIO_REG, }; @@ -336,6 +340,11 @@ const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV1[] = { NULL }; +const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV2[] = { + &CHIP_VER_REV2[0], // EFUSE_RD_CHIP_VER_REV2 + NULL +}; + const esp_efuse_desc_t* ESP_EFUSE_XPD_SDIO_REG[] = { &XPD_SDIO_REG[0], // EFUSE_RD_XPD_SDIO_REG NULL diff --git a/components/efuse/esp32/esp_efuse_table.csv b/components/efuse/esp32/esp_efuse_table.csv index 23b28ec47d..1445ac8ae6 100644 --- a/components/efuse/esp32/esp_efuse_table.csv +++ b/components/efuse/esp32/esp_efuse_table.csv @@ -6,7 +6,7 @@ ########################################################################## # *) The value MAX_BLK_LEN depends on CONFIG_EFUSE_MAX_BLK_LEN, will be replaced with "None" - 256. "3/4" - 192. "REPEAT" - 128. # !!!!!!!!!!! # -# After editing this file, run the command manually "make efuse_common_table" or "idf.py efuse_common_table" +# After editing this file, run the command manually "make efuse_common_table" or "idf.py efuse_common_table" # this will generate new source files, next rebuild all the sources. # !!!!!!!!!!! # @@ -36,11 +36,11 @@ ABS_DONE_0, EFUSE_BLK0, 196, 1, Secure boot is enabled for ENCRYPT_FLASH_KEY, EFUSE_BLK1, 0, MAX_BLK_LEN, Flash encrypt. Key. (length = "None" - 256. "3/4" - 192. "REPEAT" - 128) ENCRYPT_CONFIG, EFUSE_BLK0, 188, 4, Flash encrypt. EFUSE_FLASH_CRYPT_CONFIG_M -DISABLE_DL_ENCRYPT, EFUSE_BLK0, 199, 1, Flash encrypt. Disable UART bootloader encryption. EFUSE_DISABLE_DL_ENCRYPT. -DISABLE_DL_DECRYPT, EFUSE_BLK0, 200, 1, Flash encrypt. Disable UART bootloader decryption. EFUSE_DISABLE_DL_DECRYPT. -DISABLE_DL_CACHE, EFUSE_BLK0, 201, 1, Flash encrypt. Disable UART bootloader MMU cache. EFUSE_DISABLE_DL_CACHE. -DISABLE_JTAG, EFUSE_BLK0, 198, 1, Flash encrypt. Disable JTAG. EFUSE_RD_DISABLE_JTAG. -CONSOLE_DEBUG_DISABLE, EFUSE_BLK0, 194, 1, Flash encrypt. Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE. +DISABLE_DL_ENCRYPT, EFUSE_BLK0, 199, 1, Flash encrypt. Disable UART bootloader encryption. EFUSE_DISABLE_DL_ENCRYPT. +DISABLE_DL_DECRYPT, EFUSE_BLK0, 200, 1, Flash encrypt. Disable UART bootloader decryption. EFUSE_DISABLE_DL_DECRYPT. +DISABLE_DL_CACHE, EFUSE_BLK0, 201, 1, Flash encrypt. Disable UART bootloader MMU cache. EFUSE_DISABLE_DL_CACHE. +DISABLE_JTAG, EFUSE_BLK0, 198, 1, Flash encrypt. Disable JTAG. EFUSE_RD_DISABLE_JTAG. +CONSOLE_DEBUG_DISABLE, EFUSE_BLK0, 194, 1, Flash encrypt. Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE. FLASH_CRYPT_CNT, EFUSE_BLK0, 20, 7, Flash encrypt. Flash encryption is enabled if this field has an odd number of bits set. EFUSE_FLASH_CRYPT_CNT. # Write protection # @@ -53,7 +53,7 @@ WR_DIS_BLK3, EFUSE_BLK0, 9, 1, Write protection for EFUSE_B # Read protection # ################### RD_DIS_BLK1, EFUSE_BLK0, 16, 1, Flash encrypt. efuse_key_read_protected. EFUSE_RD_DIS_BLK1 -RD_DIS_BLK2, EFUSE_BLK0, 17, 1, Security boot. efuse_key_read_protected. EFUSE_RD_DIS_BLK2 +RD_DIS_BLK2, EFUSE_BLK0, 17, 1, Security boot. efuse_key_read_protected. EFUSE_RD_DIS_BLK2 RD_DIS_BLK3, EFUSE_BLK0, 18, 1, Read protection for EFUSE_BLK3. EFUSE_RD_DIS_BLK3 # Chip info # @@ -64,6 +64,7 @@ CHIP_VER_PKG, EFUSE_BLK0, 105, 3, EFUSE_RD_CHIP_VER_PKG CHIP_CPU_FREQ_LOW, EFUSE_BLK0, 108, 1, EFUSE_RD_CHIP_CPU_FREQ_LOW CHIP_CPU_FREQ_RATED, EFUSE_BLK0, 109, 1, EFUSE_RD_CHIP_CPU_FREQ_RATED CHIP_VER_REV1, EFUSE_BLK0, 111, 1, EFUSE_RD_CHIP_VER_REV1 +CHIP_VER_REV2, EFUSE_BLK0, 180, 1, EFUSE_RD_CHIP_VER_REV2 XPD_SDIO_REG, EFUSE_BLK0, 142, 1, EFUSE_RD_XPD_SDIO_REG SDIO_TIEH, EFUSE_BLK0, 143, 1, EFUSE_RD_SDIO_TIEH SDIO_FORCE, EFUSE_BLK0, 144, 1, EFUSE_RD_SDIO_FORCE diff --git a/components/efuse/esp32/include/esp_efuse_table.h b/components/efuse/esp32/include/esp_efuse_table.h index 807fb08882..a0137c012f 100644 --- a/components/efuse/esp32/include/esp_efuse_table.h +++ b/components/efuse/esp32/include/esp_efuse_table.h @@ -17,7 +17,7 @@ extern "C" { #endif -// md5_digest_table 544d434da010ce22f7db1b14d38e1d66 +// md5_digest_table 2e23344575b3d07f01ecb695294e9770 // This file was generated from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY. // If you want to change some fields, you need to change esp_efuse_table.csv file // then run `efuse_common_table` or `efuse_custom_table` command it will generate this file. @@ -52,6 +52,7 @@ extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_PKG[]; extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_CPU_FREQ_LOW[]; extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_CPU_FREQ_RATED[]; extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV1[]; +extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV2[]; extern const esp_efuse_desc_t* ESP_EFUSE_XPD_SDIO_REG[]; extern const esp_efuse_desc_t* ESP_EFUSE_SDIO_TIEH[]; extern const esp_efuse_desc_t* ESP_EFUSE_SDIO_FORCE[]; diff --git a/components/efuse/src/esp_efuse_fields.c b/components/efuse/src/esp_efuse_fields.c index 01ed585d89..313bbc6117 100644 --- a/components/efuse/src/esp_efuse_fields.c +++ b/components/efuse/src/esp_efuse_fields.c @@ -23,6 +23,7 @@ #include "esp_log.h" #include "soc/efuse_periph.h" #include "bootloader_random.h" +#include "soc/apb_ctrl_reg.h" const static char *TAG = "efuse"; @@ -31,8 +32,29 @@ const static char *TAG = "efuse"; // Returns chip version from efuse uint8_t esp_efuse_get_chip_ver(void) { - uint8_t chip_ver; - esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV1, &chip_ver, 1); + uint8_t eco_bit0, eco_bit1, eco_bit2; + esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV1, &eco_bit0, 1); + esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV2, &eco_bit1, 1); + eco_bit2 = (REG_READ(APB_CTRL_DATE_REG) & 80000000) >> 31; + uint32_t combine_value = (eco_bit2 << 2) | (eco_bit1 << 1) | eco_bit0; + uint8_t chip_ver = 0; + switch (combine_value) { + case 0: + chip_ver = 0; + break; + case 1: + chip_ver = 1; + break; + case 3: + chip_ver = 2; + break; + case 7: + chip_ver = 3; + break; + default: + chip_ver = 0; + break; + } return chip_ver; } @@ -111,7 +133,7 @@ void esp_efuse_write_random_key(uint32_t blk_wdata0_reg) ESP_LOGV(TAG, "Writing random values to address 0x%08x", blk_wdata0_reg); for (int i = 0; i < 8; i++) { ESP_LOGV(TAG, "EFUSE_BLKx_WDATA%d_REG = 0x%08x", i, buf[i]); - REG_WRITE(blk_wdata0_reg + 4*i, buf[i]); + REG_WRITE(blk_wdata0_reg + 4 * i, buf[i]); } bzero(buf, sizeof(buf)); bzero(raw, sizeof(raw)); diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 847560fe05..d0e9b5da0f 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -1,5 +1,33 @@ menu "ESP32-specific" + choice ESP32_REV_MIN + prompt "Minimum Supported ESP32 Revision" + default ESP32_REV_MIN_0 + help + Minimum revision that ESP-IDF would support. + ESP-IDF performs different strategy on different esp32 revision. + + config ESP32_REV_MIN_0 + bool "Rev 0" + config ESP32_REV_MIN_1 + bool "Rev 1" + config ESP32_REV_MIN_2 + bool "Rev 2" + config ESP32_REV_MIN_3 + bool "Rev 3" + endchoice + + config ESP32_REV_MIN + int + default 0 if ESP32_REV_MIN_0 + default 1 if ESP32_REV_MIN_1 + default 2 if ESP32_REV_MIN_2 + default 3 if ESP32_REV_MIN_3 + + config ESP32_DPORT_WORKAROUND + bool + default "y" if !FREERTOS_UNICORE && ESP32_REV_MIN < 2 + choice ESP32_DEFAULT_CPU_FREQ_MHZ prompt "CPU frequency" default ESP32_DEFAULT_CPU_FREQ_160 diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 1dfa5c2466..7f06aff568 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -204,7 +204,7 @@ void IRAM_ATTR call_start_cpu0(void) abort(); } ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1); - + esp_flash_enc_mode_t mode; mode = esp_get_flash_encryption_mode(); if (mode == ESP_FLASH_ENC_MODE_DEVELOPMENT) { @@ -408,6 +408,16 @@ void start_cpu0_default(void) esp_flash_app_init(); esp_err_t flash_ret = esp_flash_init_default_chip(); assert(flash_ret == ESP_OK); + + uint8_t revision = esp_efuse_get_chip_ver(); + ESP_LOGI(TAG, "Chip Revision: %d", revision); + if (revision > CONFIG_ESP32_REV_MIN) { + ESP_LOGW(TAG, "Chip revision is higher than the one configured in menuconfig. Suggest to upgrade it."); + } else if(revision != CONFIG_ESP32_REV_MIN) { + ESP_LOGE(TAG, "ESP-IDF can't support this chip revision. Modify minimum supported revision in menuconfig"); + abort(); + } + #ifdef CONFIG_PM_ENABLE esp_pm_impl_init(); #ifdef CONFIG_PM_DFS_INIT_AUTO diff --git a/components/esp32/dport_access.c b/components/esp32/dport_access.c index 2c83583350..f2fea2d359 100644 --- a/components/esp32/dport_access.c +++ b/components/esp32/dport_access.c @@ -16,7 +16,7 @@ * DPORT access is used for do protection when dual core access DPORT internal register and APB register via DPORT simultaneously * This function will be initialize after FreeRTOS startup. * When cpu0 want to access DPORT register, it should notify cpu1 enter in high-priority interrupt for be mute. When cpu1 already in high-priority interrupt, - * cpu0 can access DPORT register. Currently, cpu1 will wait for cpu0 finish access and exit high-priority interrupt. + * cpu0 can access DPORT register. Currently, cpu1 will wait for cpu0 finish access and exit high-priority interrupt. */ #include @@ -116,7 +116,7 @@ void IRAM_ATTR esp_dport_access_stall_other_cpu_end(void) { #ifndef CONFIG_FREERTOS_UNICORE int cpu_id = xPortGetCoreID(); - + if (dport_core_state[0] == DPORT_CORE_STATE_IDLE || dport_core_state[1] == DPORT_CORE_STATE_IDLE) { return; @@ -249,7 +249,7 @@ void IRAM_ATTR esp_dport_access_read_buffer(uint32_t *buff_out, uint32_t address */ uint32_t IRAM_ATTR esp_dport_access_reg_read(uint32_t reg) { -#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM) +#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM) return _DPORT_REG_READ(reg); #else uint32_t apb; @@ -295,7 +295,7 @@ uint32_t IRAM_ATTR esp_dport_access_reg_read(uint32_t reg) */ uint32_t IRAM_ATTR esp_dport_access_sequence_reg_read(uint32_t reg) { -#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM) +#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM) return _DPORT_REG_READ(reg); #else uint32_t apb; diff --git a/components/esp32/include/esp32/dport_access.h b/components/esp32/include/esp32/dport_access.h index f91c563e6b..8ea60c4cdb 100644 --- a/components/esp32/include/esp32/dport_access.h +++ b/components/esp32/include/esp32/dport_access.h @@ -33,7 +33,7 @@ uint32_t esp_dport_access_sequence_reg_read(uint32_t reg); //only call in case of panic(). void esp_dport_access_int_abort(void); -#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM) +#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM) #define DPORT_STALL_OTHER_CPU_START() #define DPORT_STALL_OTHER_CPU_END() #define DPORT_INTERRUPT_DISABLE() diff --git a/components/esp32/system_api.c b/components/esp32/system_api.c index 570c0997a3..e5f6649b73 100644 --- a/components/esp32/system_api.c +++ b/components/esp32/system_api.c @@ -204,7 +204,7 @@ esp_err_t esp_read_mac(uint8_t* mac, esp_mac_type_t type) ESP_LOGW(TAG, "incorrect mac type"); break; } - + return ESP_OK; } @@ -307,10 +307,10 @@ void IRAM_ATTR esp_restart_noos(void) WRITE_PERI_REG(GPIO_FUNC5_IN_SEL_CFG_REG, 0x30); // Reset wifi/bluetooth/ethernet/sdio (bb/mac) - DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, + DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, DPORT_BB_RST | DPORT_FE_RST | DPORT_MAC_RST | DPORT_BT_RST | DPORT_BTMAC_RST | DPORT_SDIO_RST | - DPORT_SDIO_HOST_RST | DPORT_EMAC_RST | DPORT_MACPWR_RST | + DPORT_SDIO_HOST_RST | DPORT_EMAC_RST | DPORT_MACPWR_RST | DPORT_RW_BTMAC_RST | DPORT_RW_BTLP_RST); DPORT_REG_WRITE(DPORT_CORE_RST_EN_REG, 0); @@ -366,35 +366,27 @@ const char* esp_get_idf_version(void) return IDF_VER; } -static void get_chip_info_esp32(esp_chip_info_t* out_info) +void esp_chip_info(esp_chip_info_t* out_info) { - uint32_t reg = REG_READ(EFUSE_BLK0_RDATA3_REG); + uint32_t efuse_rd3 = REG_READ(EFUSE_BLK0_RDATA3_REG); memset(out_info, 0, sizeof(*out_info)); - + out_info->model = CHIP_ESP32; - if ((reg & EFUSE_RD_CHIP_VER_REV1_M) != 0) { - out_info->revision = 1; - } - if ((reg & EFUSE_RD_CHIP_VER_DIS_APP_CPU_M) == 0) { + out_info->revision = esp_efuse_get_chip_ver(); + + if ((efuse_rd3 & EFUSE_RD_CHIP_VER_DIS_APP_CPU_M) == 0) { out_info->cores = 2; } else { out_info->cores = 1; } out_info->features = CHIP_FEATURE_WIFI_BGN; - if ((reg & EFUSE_RD_CHIP_VER_DIS_BT_M) == 0) { + if ((efuse_rd3 & EFUSE_RD_CHIP_VER_DIS_BT_M) == 0) { out_info->features |= CHIP_FEATURE_BT | CHIP_FEATURE_BLE; } - int package = (reg & EFUSE_RD_CHIP_VER_PKG_M) >> EFUSE_RD_CHIP_VER_PKG_S; + int package = (efuse_rd3 & EFUSE_RD_CHIP_VER_PKG_M) >> EFUSE_RD_CHIP_VER_PKG_S; if (package == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 || package == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2 || package == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) { out_info->features |= CHIP_FEATURE_EMB_FLASH; } } - -void esp_chip_info(esp_chip_info_t* out_info) -{ - // Only ESP32 is supported now, in the future call one of the - // chip-specific functions based on sdkconfig choice - return get_chip_info_esp32(out_info); -} diff --git a/components/esptool_py/esptool b/components/esptool_py/esptool index 1319c49adb..1a7dbf787e 160000 --- a/components/esptool_py/esptool +++ b/components/esptool_py/esptool @@ -1 +1 @@ -Subproject commit 1319c49adb2fe99d2981151ff781930d6ed62729 +Subproject commit 1a7dbf787e7e504acdeaea074d15a5ccaf87e9e8 diff --git a/components/soc/esp32/include/soc/dport_access.h b/components/soc/esp32/include/soc/dport_access.h index 544560fdfb..fe7e70ebc0 100644 --- a/components/soc/esp32/include/soc/dport_access.h +++ b/components/soc/esp32/include/soc/dport_access.h @@ -48,7 +48,7 @@ extern "C" { // After completing read operations, use DPORT_STALL_OTHER_CPU_END(). // This method uses stall other CPU while reading DPORT registers. // Useful for compatibility, as well as for large consecutive readings. -// This method is slower, but must be used if ROM functions or +// This method is slower, but must be used if ROM functions or // other code is called which accesses DPORT without any other workaround. // *) The pre-readable APB register before reading the DPORT register // helps synchronize the operation of the two CPUs, @@ -73,7 +73,7 @@ extern "C" { */ static inline uint32_t IRAM_ATTR DPORT_REG_READ(uint32_t reg) { -#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM) +#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM) return _DPORT_REG_READ(reg); #else return esp_dport_access_reg_read(reg); @@ -106,7 +106,7 @@ static inline uint32_t IRAM_ATTR DPORT_REG_READ(uint32_t reg) */ static inline uint32_t IRAM_ATTR DPORT_SEQUENCE_REG_READ(uint32_t reg) { -#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM) +#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM) return _DPORT_REG_READ(reg); #else return esp_dport_access_sequence_reg_read(reg); @@ -166,7 +166,7 @@ static inline uint32_t IRAM_ATTR DPORT_SEQUENCE_REG_READ(uint32_t reg) */ static inline uint32_t IRAM_ATTR DPORT_READ_PERI_REG(uint32_t reg) { -#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM) +#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM) return _DPORT_REG_READ(reg); #else return esp_dport_access_reg_read(reg); diff --git a/components/soc/esp32/include/soc/soc.h b/components/soc/esp32/include/soc/soc.h index 5901abca23..419cf49b7f 100644 --- a/components/soc/esp32/include/soc/soc.h +++ b/components/soc/esp32/include/soc/soc.h @@ -108,7 +108,7 @@ #define IS_DPORT_REG(_r) (((_r) >= DR_REG_DPORT_BASE) && (_r) <= DR_REG_DPORT_END) -#if !defined( BOOTLOADER_BUILD ) && !defined( CONFIG_FREERTOS_UNICORE ) && defined( ESP_PLATFORM ) +#if !defined( BOOTLOADER_BUILD ) && defined( CONFIG_ESP32_DPORT_WORKAROUND ) && defined( ESP_PLATFORM ) #define ASSERT_IF_DPORT_REG(_r, OP) TRY_STATIC_ASSERT(!IS_DPORT_REG(_r), (Cannot use OP for DPORT registers use DPORT_##OP)); #else #define ASSERT_IF_DPORT_REG(_r, OP) From b1497f21874dfcc1d6dbadab2132e582fb92cb33 Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Wed, 22 May 2019 20:21:11 +0800 Subject: [PATCH 450/486] exclude rom headers in examples 1. avoid including rom headers directly in examples 2. add common API interface for CRC calculation in esp_common component --- components/driver/include/driver/uart.h | 8 + components/driver/uart.c | 29 +- components/esp_common/include/esp_crc.h | 113 +++ .../bluedroid/ble/blufi/main/blufi_security.c | 6 +- .../peripherals/sdio/slave/main/app_main.c | 1 - .../components/tjpgd/CMakeLists.txt | 4 + .../spi_master/components/tjpgd/component.mk | 3 + .../components/tjpgd/include/tjpgd.h | 88 ++ .../spi_master/components/tjpgd/src/tjpgd.c | 960 ++++++++++++++++++ .../spi_master/main/decode_image.c | 124 ++- .../spi_slave/receiver/main/app_main.c | 1 - .../spi_slave/sender/main/app_main.c | 7 +- .../components/cmd_system/cmd_system.c | 3 +- examples/system/himem/main/himem_test_main.c | 1 - .../main/light_sleep_example_main.c | 4 +- .../wifi/espnow/main/espnow_example_main.c | 7 +- tools/ci/check_examples_rom_header.sh | 19 + tools/ci/config/check.yml | 5 + tools/ci/executable-list.txt | 1 + 19 files changed, 1292 insertions(+), 92 deletions(-) create mode 100644 components/esp_common/include/esp_crc.h create mode 100644 examples/peripherals/spi_master/components/tjpgd/CMakeLists.txt create mode 100644 examples/peripherals/spi_master/components/tjpgd/component.mk create mode 100644 examples/peripherals/spi_master/components/tjpgd/include/tjpgd.h create mode 100644 examples/peripherals/spi_master/components/tjpgd/src/tjpgd.c create mode 100755 tools/ci/check_examples_rom_header.sh diff --git a/components/driver/include/driver/uart.h b/components/driver/include/driver/uart.h index 4bf855c186..f25e21776e 100644 --- a/components/driver/include/driver/uart.h +++ b/components/driver/include/driver/uart.h @@ -841,6 +841,14 @@ esp_err_t uart_set_wakeup_threshold(uart_port_t uart_num, int wakeup_threshold); */ esp_err_t uart_get_wakeup_threshold(uart_port_t uart_num, int* out_wakeup_threshold); +/** + * @brief Wait until UART tx memory empty and the last char send ok (polling mode). + * + * @param uart_num UART number + * + */ +void uart_wait_tx_idle_polling(uart_port_t uart_num); + #ifdef __cplusplus } #endif diff --git a/components/driver/uart.c b/components/driver/uart.c index 3367d1d04a..da215dde01 100644 --- a/components/driver/uart.c +++ b/components/driver/uart.c @@ -81,7 +81,7 @@ typedef struct { intr_handle_t intr_handle; /*!< UART interrupt handle*/ uart_mode_t uart_mode; /*!< UART controller actual mode set by uart_set_mode() */ bool coll_det_flg; /*!< UART collision detection flag */ - + //rx parameters int rx_buffered_len; /*!< UART cached data length */ SemaphoreHandle_t rx_mux; /*!< UART RX data mutex*/ @@ -1007,13 +1007,13 @@ static void uart_rx_intr_handler_default(void *param) UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); uart_reset_rx_fifo(uart_num); // Set collision detection flag - p_uart_obj[uart_num]->coll_det_flg = true; + p_uart_obj[uart_num]->coll_det_flg = true; UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); uart_event.type = UART_EVENT_MAX; } else if(uart_intr_status & UART_TX_DONE_INT_ST_M) { uart_disable_intr_mask_from_isr(uart_num, UART_TX_DONE_INT_ENA_M); uart_clear_intr_status(uart_num, UART_TX_DONE_INT_CLR_M); - // If RS485 half duplex mode is enable then reset FIFO and + // If RS485 half duplex mode is enable then reset FIFO and // reset RTS pin to start receiver driver if (UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX)) { UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); @@ -1489,11 +1489,11 @@ portMUX_TYPE *uart_get_selectlock(void) return &uart_selectlock; } // Set UART mode -esp_err_t uart_set_mode(uart_port_t uart_num, uart_mode_t mode) +esp_err_t uart_set_mode(uart_port_t uart_num, uart_mode_t mode) { UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_ERR_INVALID_STATE); UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); - if ((mode == UART_MODE_RS485_COLLISION_DETECT) || (mode == UART_MODE_RS485_APP_CTRL) + if ((mode == UART_MODE_RS485_COLLISION_DETECT) || (mode == UART_MODE_RS485_APP_CTRL) || (mode == UART_MODE_RS485_HALF_DUPLEX)) { UART_CHECK((UART[uart_num]->conf1.rx_flow_en != 1), "disable hw flowctrl before using RS485 mode", ESP_ERR_INVALID_ARG); @@ -1548,13 +1548,13 @@ esp_err_t uart_set_mode(uart_port_t uart_num, uart_mode_t mode) return ESP_OK; } -esp_err_t uart_set_rx_timeout(uart_port_t uart_num, const uint8_t tout_thresh) +esp_err_t uart_set_rx_timeout(uart_port_t uart_num, const uint8_t tout_thresh) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); UART_CHECK((tout_thresh < 127), "tout_thresh max value is 126", ESP_ERR_INVALID_ARG); UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - // The tout_thresh = 1, defines TOUT interrupt timeout equal to - // transmission time of one symbol (~11 bit) on current baudrate + // The tout_thresh = 1, defines TOUT interrupt timeout equal to + // transmission time of one symbol (~11 bit) on current baudrate if (tout_thresh > 0) { //Hardware issue workaround: when using ref_tick, the rx timeout threshold needs increase to 10 times. //T_ref = T_apb * APB_CLK/(REF_TICK << CLKDIV_FRAG_BIT_WIDTH) @@ -1575,8 +1575,8 @@ esp_err_t uart_get_collision_flag(uart_port_t uart_num, bool* collision_flag) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); UART_CHECK((collision_flag != NULL), "wrong parameter pointer", ESP_ERR_INVALID_ARG); - UART_CHECK((UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX) - || UART_IS_MODE_SET(uart_num, UART_MODE_RS485_COLLISION_DETECT)), + UART_CHECK((UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX) + || UART_IS_MODE_SET(uart_num, UART_MODE_RS485_COLLISION_DETECT)), "wrong mode", ESP_ERR_INVALID_ARG); *collision_flag = p_uart_obj[uart_num]->coll_det_flg; return ESP_OK; @@ -1601,3 +1601,12 @@ esp_err_t uart_get_wakeup_threshold(uart_port_t uart_num, int* out_wakeup_thresh *out_wakeup_threshold = UART[uart_num]->sleep_conf.active_threshold + UART_MIN_WAKEUP_THRESH; return ESP_OK; } + +void uart_wait_tx_idle_polling(uart_port_t uart_num) +{ + uint32_t status; + do { + status = READ_PERI_REG(UART_STATUS_REG(uart_num)); + /* either tx count or state is non-zero */ + } while ((status & (UART_ST_UTX_OUT_M | UART_TXFIFO_CNT_M)) != 0); +} diff --git a/components/esp_common/include/esp_crc.h b/components/esp_common/include/esp_crc.h new file mode 100644 index 0000000000..23a04876ae --- /dev/null +++ b/components/esp_common/include/esp_crc.h @@ -0,0 +1,113 @@ +// Copyright 2015-2019 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 + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "sdkconfig.h" + +#if defined(CONFIG_IDF_TARGET_ESP32) +#include "esp32/rom/crc.h" +#endif + +/******************* Polynomials Used in the CRC APIs **************************** +* CRC-8 x8+x2+x1+1 0x07 +* CRC16-CCITT x16+x12+x5+1 0x1021 +* CRC32 x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x1+1 0x04c11db7 +********************************************************************************/ + +/** +* @brief CRC32 value in little endian. +* +* @param crc: Initial CRC value (result of last calculation or 0 for the first time) +* @param buf: Data buffer that used to calculate the CRC value +* @param len: Length of the data buffer +* @return CRC32 value +*/ +static inline uint32_t esp_crc32_le(uint32_t crc, uint8_t const *buf, uint32_t len) +{ + return crc32_le(crc, buf, len); +} + +/** +* @brief CRC32 value in big endian. +* +* @param crc: Initial CRC value (result of last calculation or 0 for the first time) +* @param buf: Data buffer that used to calculate the CRC value +* @param len: Length of the data buffer +* @return CRC32 value +*/ +static inline uint32_t esp_crc32_be(uint32_t crc, uint8_t const *buf, uint32_t len) +{ + return crc32_be(crc, buf, len); +} + +/** +* @brief CRC16 value in little endian. +* +* @param crc: Initial CRC value (result of last calculation or 0 for the first time) +* @param buf: Data buffer that used to calculate the CRC value +* @param len: Length of the data buffer +* @return CRC16 value +*/ +static inline uint16_t esp_crc16_le(uint16_t crc, uint8_t const *buf, uint32_t len) +{ + return crc16_le(crc, buf, len); +} + +/** +* @brief CRC16 value in big endian. +* +* @param crc: Initial CRC value (result of last calculation or 0 for the first time) +* @param buf: Data buffer that used to calculate the CRC value +* @param len: Length of the data buffer +* @return CRC16 value +*/ +static inline uint16_t esp_crc16_be(uint16_t crc, uint8_t const *buf, uint32_t len) +{ + return crc16_be(crc, buf, len); +} + +/** +* @brief CRC8 value in little endian. +* +* @param crc: Initial CRC value (result of last calculation or 0 for the first time) +* @param buf: Data buffer that used to calculate the CRC value +* @param len: Length of the data buffer +* @return CRC8 value +*/ +static inline uint8_t esp_crc8_le(uint8_t crc, uint8_t const *buf, uint32_t len) +{ + return crc8_le(crc, buf, len); +} + +/** +* @brief CRC8 value in big endian. +* +* @param crc: Initial CRC value (result of last calculation or 0 for the first time) +* @param buf: Data buffer that used to calculate the CRC value +* @param len: Length of the data buffer +* @return CRC8 value +*/ +static inline uint8_t esp_crc8_be(uint8_t crc, uint8_t const *buf, uint32_t len) +{ + return crc8_be(crc, buf, len); +} + +#ifdef __cplusplus +} +#endif diff --git a/examples/bluetooth/bluedroid/ble/blufi/main/blufi_security.c b/examples/bluetooth/bluedroid/ble/blufi/main/blufi_security.c index 64b989e741..f790e58e5b 100644 --- a/examples/bluetooth/bluedroid/ble/blufi/main/blufi_security.c +++ b/examples/bluetooth/bluedroid/ble/blufi/main/blufi_security.c @@ -28,7 +28,7 @@ #include "mbedtls/aes.h" #include "mbedtls/dhm.h" #include "mbedtls/md5.h" -#include "esp32/rom/crc.h" +#include "esp_crc.h" /* The SEC_TYPE_xxx is for self-defined packet data type in the procedure of "BLUFI negotiate key" @@ -124,7 +124,7 @@ void blufi_dh_negotiate_data_handler(uint8_t *data, int len, uint8_t **output_da mbedtls_md5(blufi_sec->share_key, blufi_sec->share_len, blufi_sec->psk); mbedtls_aes_setkey_enc(&blufi_sec->aes, blufi_sec->psk, 128); - + /* alloc output data */ *output_data = &blufi_sec->self_public_key[0]; *output_len = blufi_sec->dhm.len; @@ -178,7 +178,7 @@ int blufi_aes_decrypt(uint8_t iv8, uint8_t *crypt_data, int crypt_len) uint16_t blufi_crc_checksum(uint8_t iv8, uint8_t *data, int len) { /* This iv8 ignore, not used */ - return crc16_be(0, data, len); + return esp_crc16_be(0, data, len); } esp_err_t blufi_security_init(void) diff --git a/examples/peripherals/sdio/slave/main/app_main.c b/examples/peripherals/sdio/slave/main/app_main.c index 147f4aba49..3a6a7c7593 100644 --- a/examples/peripherals/sdio/slave/main/app_main.c +++ b/examples/peripherals/sdio/slave/main/app_main.c @@ -8,7 +8,6 @@ */ #include "driver/sdio_slave.h" #include "esp_log.h" -#include "esp32/rom/lldesc.h" #include "sys/queue.h" #include "soc/soc.h" #include "freertos/task.h" diff --git a/examples/peripherals/spi_master/components/tjpgd/CMakeLists.txt b/examples/peripherals/spi_master/components/tjpgd/CMakeLists.txt new file mode 100644 index 0000000000..cde4d0eed4 --- /dev/null +++ b/examples/peripherals/spi_master/components/tjpgd/CMakeLists.txt @@ -0,0 +1,4 @@ +set(tjpgd_srcs "src/tjpgd.c") + +idf_component_register(SRCS "${tjpgd_srcs}" + INCLUDE_DIRS "include") diff --git a/examples/peripherals/spi_master/components/tjpgd/component.mk b/examples/peripherals/spi_master/components/tjpgd/component.mk new file mode 100644 index 0000000000..24cab8b637 --- /dev/null +++ b/examples/peripherals/spi_master/components/tjpgd/component.mk @@ -0,0 +1,3 @@ +COMPONENT_ADD_INCLUDEDIRS := include + +COMPONENT_SRCDIRS := src diff --git a/examples/peripherals/spi_master/components/tjpgd/include/tjpgd.h b/examples/peripherals/spi_master/components/tjpgd/include/tjpgd.h new file mode 100644 index 0000000000..abb9dd4803 --- /dev/null +++ b/examples/peripherals/spi_master/components/tjpgd/include/tjpgd.h @@ -0,0 +1,88 @@ +/*----------------------------------------------------------------------------/ +/ TJpgDec - Tiny JPEG Decompressor include file (C)ChaN, 2019 +/----------------------------------------------------------------------------*/ +#ifndef DEF_TJPGDEC +#define DEF_TJPGDEC +/*---------------------------------------------------------------------------*/ +/* System Configurations */ + +#define JD_SZBUF 512 /* Size of stream input buffer */ +#define JD_FORMAT 0 /* Output pixel format 0:RGB888 (3 BYTE/pix), 1:RGB565 (1 WORD/pix) */ +#define JD_USE_SCALE 1 /* Use descaling feature for output */ +#define JD_TBLCLIP 1 /* Use table for saturation (might be a bit faster but increases 1K bytes of code size) */ + +/*---------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_WIN32) /* Main development platform */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef short int16_t; +typedef unsigned long uint32_t; +typedef long int32_t; +#else +#include "stdint.h" +#endif + +/* Error code */ +typedef enum { + JDR_OK = 0, /* 0: Succeeded */ + JDR_INTR, /* 1: Interrupted by output function */ + JDR_INP, /* 2: Device error or wrong termination of input stream */ + JDR_MEM1, /* 3: Insufficient memory pool for the image */ + JDR_MEM2, /* 4: Insufficient stream input buffer */ + JDR_PAR, /* 5: Parameter error */ + JDR_FMT1, /* 6: Data format error (may be damaged data) */ + JDR_FMT2, /* 7: Right format but not supported */ + JDR_FMT3 /* 8: Not supported JPEG standard */ +} JRESULT; + + + +/* Rectangular structure */ +typedef struct { + uint16_t left, right, top, bottom; +} JRECT; + + + +/* Decompressor object structure */ +typedef struct JDEC JDEC; +struct JDEC { + uint16_t dctr; /* Number of bytes available in the input buffer */ + uint8_t* dptr; /* Current data read ptr */ + uint8_t* inbuf; /* Bit stream input buffer */ + uint8_t dmsk; /* Current bit in the current read byte */ + uint8_t scale; /* Output scaling ratio */ + uint8_t msx, msy; /* MCU size in unit of block (width, height) */ + uint8_t qtid[3]; /* Quantization table ID of each component */ + int16_t dcv[3]; /* Previous DC element of each component */ + uint16_t nrst; /* Restart inverval */ + uint16_t width, height; /* Size of the input image (pixel) */ + uint8_t* huffbits[2][2]; /* Huffman bit distribution tables [id][dcac] */ + uint16_t* huffcode[2][2]; /* Huffman code word tables [id][dcac] */ + uint8_t* huffdata[2][2]; /* Huffman decoded data tables [id][dcac] */ + int32_t* qttbl[4]; /* Dequantizer tables [id] */ + void* workbuf; /* Working buffer for IDCT and RGB output */ + uint8_t* mcubuf; /* Working buffer for the MCU */ + void* pool; /* Pointer to available memory pool */ + uint16_t sz_pool; /* Size of momory pool (bytes available) */ + uint16_t (*infunc)(JDEC*, uint8_t*, uint16_t);/* Pointer to jpeg stream input function */ + void* device; /* Pointer to I/O device identifiler for the session */ +}; + + + +/* TJpgDec API functions */ +JRESULT jd_prepare (JDEC*, uint16_t(*)(JDEC*,uint8_t*,uint16_t), void*, uint16_t, void*); +JRESULT jd_decomp (JDEC*, uint16_t(*)(JDEC*,void*,JRECT*), uint8_t); + + +#ifdef __cplusplus +} +#endif + +#endif /* _TJPGDEC */ diff --git a/examples/peripherals/spi_master/components/tjpgd/src/tjpgd.c b/examples/peripherals/spi_master/components/tjpgd/src/tjpgd.c new file mode 100644 index 0000000000..dc87fe08e1 --- /dev/null +++ b/examples/peripherals/spi_master/components/tjpgd/src/tjpgd.c @@ -0,0 +1,960 @@ +/*----------------------------------------------------------------------------/ +/ TJpgDec - Tiny JPEG Decompressor R0.01c (C)ChaN, 2019 +/-----------------------------------------------------------------------------/ +/ The TJpgDec is a generic JPEG decompressor module for tiny embedded systems. +/ This is a free software that opened for education, research and commercial +/ developments under license policy of following terms. +/ +/ Copyright (C) 2019, ChaN, all right reserved. +/ +/ * The TJpgDec module is a free software and there is NO WARRANTY. +/ * No restriction on use. You can use, modify and redistribute it for +/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. +/ * Redistributions of source code must retain the above copyright notice. +/ +/-----------------------------------------------------------------------------/ +/ Oct 04, 2011 R0.01 First release. +/ Feb 19, 2012 R0.01a Fixed decompression fails when scan starts with an escape seq. +/ Sep 03, 2012 R0.01b Added JD_TBLCLIP option. +/ Mar 16, 2019 R0.01c Supprted stdint.h. +/----------------------------------------------------------------------------*/ + +#include "tjpgd.h" + + +/*-----------------------------------------------*/ +/* Zigzag-order to raster-order conversion table */ +/*-----------------------------------------------*/ + +#define ZIG(n) Zig[n] + +static const uint8_t Zig[64] = { /* Zigzag-order to raster-order conversion table */ + 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 +}; + + + +/*-------------------------------------------------*/ +/* Input scale factor of Arai algorithm */ +/* (scaled up 16 bits for fixed point operations) */ +/*-------------------------------------------------*/ + +#define IPSF(n) Ipsf[n] + +static const uint16_t Ipsf[64] = { /* See also aa_idct.png */ + (uint16_t)(1.00000*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.17588*8192), (uint16_t)(1.00000*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.27590*8192), + (uint16_t)(1.38704*8192), (uint16_t)(1.92388*8192), (uint16_t)(1.81226*8192), (uint16_t)(1.63099*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.08979*8192), (uint16_t)(0.75066*8192), (uint16_t)(0.38268*8192), + (uint16_t)(1.30656*8192), (uint16_t)(1.81226*8192), (uint16_t)(1.70711*8192), (uint16_t)(1.53636*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.02656*8192), (uint16_t)(0.70711*8192), (uint16_t)(0.36048*8192), + (uint16_t)(1.17588*8192), (uint16_t)(1.63099*8192), (uint16_t)(1.53636*8192), (uint16_t)(1.38268*8192), (uint16_t)(1.17588*8192), (uint16_t)(0.92388*8192), (uint16_t)(0.63638*8192), (uint16_t)(0.32442*8192), + (uint16_t)(1.00000*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.17588*8192), (uint16_t)(1.00000*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.27590*8192), + (uint16_t)(0.78570*8192), (uint16_t)(1.08979*8192), (uint16_t)(1.02656*8192), (uint16_t)(0.92388*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.61732*8192), (uint16_t)(0.42522*8192), (uint16_t)(0.21677*8192), + (uint16_t)(0.54120*8192), (uint16_t)(0.75066*8192), (uint16_t)(0.70711*8192), (uint16_t)(0.63638*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.42522*8192), (uint16_t)(0.29290*8192), (uint16_t)(0.14932*8192), + (uint16_t)(0.27590*8192), (uint16_t)(0.38268*8192), (uint16_t)(0.36048*8192), (uint16_t)(0.32442*8192), (uint16_t)(0.27590*8192), (uint16_t)(0.21678*8192), (uint16_t)(0.14932*8192), (uint16_t)(0.07612*8192) +}; + + + +/*---------------------------------------------*/ +/* Conversion table for fast clipping process */ +/*---------------------------------------------*/ + +#if JD_TBLCLIP + +#define BYTECLIP(v) Clip8[(uint16_t)(v) & 0x3FF] + +static const uint8_t Clip8[1024] = { + /* 0..255 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, + /* 256..511 */ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + /* -512..-257 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* -256..-1 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +#else /* JD_TBLCLIP */ + +inline uint8_t BYTECLIP ( + int16_t val +) +{ + if (val < 0) val = 0; + if (val > 255) val = 255; + + return (uint8_t)val; +} + +#endif + + + +/*-----------------------------------------------------------------------*/ +/* Allocate a memory block from memory pool */ +/*-----------------------------------------------------------------------*/ + +static void* alloc_pool ( /* Pointer to allocated memory block (NULL:no memory available) */ + JDEC* jd, /* Pointer to the decompressor object */ + uint16_t nd /* Number of bytes to allocate */ +) +{ + char *rp = 0; + + + nd = (nd + 3) & ~3; /* Align block size to the word boundary */ + + if (jd->sz_pool >= nd) { + jd->sz_pool -= nd; + rp = (char*)jd->pool; /* Get start of available memory pool */ + jd->pool = (void*)(rp + nd); /* Allocate requierd bytes */ + } + + return (void*)rp; /* Return allocated memory block (NULL:no memory to allocate) */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Create de-quantization and prescaling tables with a DQT segment */ +/*-----------------------------------------------------------------------*/ + +static int create_qt_tbl ( /* 0:OK, !0:Failed */ + JDEC* jd, /* Pointer to the decompressor object */ + const uint8_t* data, /* Pointer to the quantizer tables */ + uint16_t ndata /* Size of input data */ +) +{ + uint16_t i; + uint8_t d, z; + int32_t *pb; + + + while (ndata) { /* Process all tables in the segment */ + if (ndata < 65) return JDR_FMT1; /* Err: table size is unaligned */ + ndata -= 65; + d = *data++; /* Get table property */ + if (d & 0xF0) return JDR_FMT1; /* Err: not 8-bit resolution */ + i = d & 3; /* Get table ID */ + pb = alloc_pool(jd, 64 * sizeof (int32_t));/* Allocate a memory block for the table */ + if (!pb) return JDR_MEM1; /* Err: not enough memory */ + jd->qttbl[i] = pb; /* Register the table */ + for (i = 0; i < 64; i++) { /* Load the table */ + z = ZIG(i); /* Zigzag-order to raster-order conversion */ + pb[z] = (int32_t)((uint32_t)*data++ * IPSF(z)); /* Apply scale factor of Arai algorithm to the de-quantizers */ + } + } + + return JDR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Create huffman code tables with a DHT segment */ +/*-----------------------------------------------------------------------*/ + +static int create_huffman_tbl ( /* 0:OK, !0:Failed */ + JDEC* jd, /* Pointer to the decompressor object */ + const uint8_t* data, /* Pointer to the packed huffman tables */ + uint16_t ndata /* Size of input data */ +) +{ + uint16_t i, j, b, np, cls, num; + uint8_t d, *pb, *pd; + uint16_t hc, *ph; + + + while (ndata) { /* Process all tables in the segment */ + if (ndata < 17) return JDR_FMT1; /* Err: wrong data size */ + ndata -= 17; + d = *data++; /* Get table number and class */ + if (d & 0xEE) return JDR_FMT1; /* Err: invalid class/number */ + cls = d >> 4; num = d & 0x0F; /* class = dc(0)/ac(1), table number = 0/1 */ + pb = alloc_pool(jd, 16); /* Allocate a memory block for the bit distribution table */ + if (!pb) return JDR_MEM1; /* Err: not enough memory */ + jd->huffbits[num][cls] = pb; + for (np = i = 0; i < 16; i++) { /* Load number of patterns for 1 to 16-bit code */ + np += (pb[i] = *data++); /* Get sum of code words for each code */ + } + ph = alloc_pool(jd, (uint16_t)(np * sizeof (uint16_t)));/* Allocate a memory block for the code word table */ + if (!ph) return JDR_MEM1; /* Err: not enough memory */ + jd->huffcode[num][cls] = ph; + hc = 0; + for (j = i = 0; i < 16; i++) { /* Re-build huffman code word table */ + b = pb[i]; + while (b--) ph[j++] = hc++; + hc <<= 1; + } + + if (ndata < np) return JDR_FMT1; /* Err: wrong data size */ + ndata -= np; + pd = alloc_pool(jd, np); /* Allocate a memory block for the decoded data */ + if (!pd) return JDR_MEM1; /* Err: not enough memory */ + jd->huffdata[num][cls] = pd; + for (i = 0; i < np; i++) { /* Load decoded data corresponds to each code ward */ + d = *data++; + if (!cls && d > 11) return JDR_FMT1; + *pd++ = d; + } + } + + return JDR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Extract N bits from input stream */ +/*-----------------------------------------------------------------------*/ + +static int bitext ( /* >=0: extracted data, <0: error code */ + JDEC* jd, /* Pointer to the decompressor object */ + int nbit /* Number of bits to extract (1 to 11) */ +) +{ + uint8_t msk, s, *dp; + uint16_t dc, v, f; + + + msk = jd->dmsk; dc = jd->dctr; dp = jd->dptr; /* Bit mask, number of data available, read ptr */ + s = *dp; v = f = 0; + do { + if (!msk) { /* Next byte? */ + if (!dc) { /* No input data is available, re-fill input buffer */ + dp = jd->inbuf; /* Top of input buffer */ + dc = jd->infunc(jd, dp, JD_SZBUF); + if (!dc) return 0 - (int16_t)JDR_INP; /* Err: read error or wrong stream termination */ + } else { + dp++; /* Next data ptr */ + } + dc--; /* Decrement number of available bytes */ + if (f) { /* In flag sequence? */ + f = 0; /* Exit flag sequence */ + if (*dp != 0) return 0 - (int16_t)JDR_FMT1; /* Err: unexpected flag is detected (may be collapted data) */ + *dp = s = 0xFF; /* The flag is a data 0xFF */ + } else { + s = *dp; /* Get next data byte */ + if (s == 0xFF) { /* Is start of flag sequence? */ + f = 1; continue; /* Enter flag sequence */ + } + } + msk = 0x80; /* Read from MSB */ + } + v <<= 1; /* Get a bit */ + if (s & msk) v++; + msk >>= 1; + nbit--; + } while (nbit); + jd->dmsk = msk; jd->dctr = dc; jd->dptr = dp; + + return (int)v; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Extract a huffman decoded data from input stream */ +/*-----------------------------------------------------------------------*/ + +static int16_t huffext ( /* >=0: decoded data, <0: error code */ + JDEC* jd, /* Pointer to the decompressor object */ + const uint8_t* hbits, /* Pointer to the bit distribution table */ + const uint16_t* hcode, /* Pointer to the code word table */ + const uint8_t* hdata /* Pointer to the data table */ +) +{ + uint8_t msk, s, *dp; + uint16_t dc, v, f, bl, nd; + + + msk = jd->dmsk; dc = jd->dctr; dp = jd->dptr; /* Bit mask, number of data available, read ptr */ + s = *dp; v = f = 0; + bl = 16; /* Max code length */ + do { + if (!msk) { /* Next byte? */ + if (!dc) { /* No input data is available, re-fill input buffer */ + dp = jd->inbuf; /* Top of input buffer */ + dc = jd->infunc(jd, dp, JD_SZBUF); + if (!dc) return 0 - (int16_t)JDR_INP; /* Err: read error or wrong stream termination */ + } else { + dp++; /* Next data ptr */ + } + dc--; /* Decrement number of available bytes */ + if (f) { /* In flag sequence? */ + f = 0; /* Exit flag sequence */ + if (*dp != 0) return 0 - (int16_t)JDR_FMT1; /* Err: unexpected flag is detected (may be collapted data) */ + *dp = s = 0xFF; /* The flag is a data 0xFF */ + } else { + s = *dp; /* Get next data byte */ + if (s == 0xFF) { /* Is start of flag sequence? */ + f = 1; continue; /* Enter flag sequence, get trailing byte */ + } + } + msk = 0x80; /* Read from MSB */ + } + v <<= 1; /* Get a bit */ + if (s & msk) v++; + msk >>= 1; + + for (nd = *hbits++; nd; nd--) { /* Search the code word in this bit length */ + if (v == *hcode++) { /* Matched? */ + jd->dmsk = msk; jd->dctr = dc; jd->dptr = dp; + return *hdata; /* Return the decoded data */ + } + hdata++; + } + bl--; + } while (bl); + + return 0 - (int16_t)JDR_FMT1; /* Err: code not found (may be collapted data) */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Apply Inverse-DCT in Arai Algorithm (see also aa_idct.png) */ +/*-----------------------------------------------------------------------*/ + +static void block_idct ( + int32_t* src, /* Input block data (de-quantized and pre-scaled for Arai Algorithm) */ + uint8_t* dst /* Pointer to the destination to store the block as byte array */ +) +{ + const int32_t M13 = (int32_t)(1.41421*4096), M2 = (int32_t)(1.08239*4096), M4 = (int32_t)(2.61313*4096), M5 = (int32_t)(1.84776*4096); + int32_t v0, v1, v2, v3, v4, v5, v6, v7; + int32_t t10, t11, t12, t13; + uint16_t i; + + /* Process columns */ + for (i = 0; i < 8; i++) { + v0 = src[8 * 0]; /* Get even elements */ + v1 = src[8 * 2]; + v2 = src[8 * 4]; + v3 = src[8 * 6]; + + t10 = v0 + v2; /* Process the even elements */ + t12 = v0 - v2; + t11 = (v1 - v3) * M13 >> 12; + v3 += v1; + t11 -= v3; + v0 = t10 + v3; + v3 = t10 - v3; + v1 = t11 + t12; + v2 = t12 - t11; + + v4 = src[8 * 7]; /* Get odd elements */ + v5 = src[8 * 1]; + v6 = src[8 * 5]; + v7 = src[8 * 3]; + + t10 = v5 - v4; /* Process the odd elements */ + t11 = v5 + v4; + t12 = v6 - v7; + v7 += v6; + v5 = (t11 - v7) * M13 >> 12; + v7 += t11; + t13 = (t10 + t12) * M5 >> 12; + v4 = t13 - (t10 * M2 >> 12); + v6 = t13 - (t12 * M4 >> 12) - v7; + v5 -= v6; + v4 -= v5; + + src[8 * 0] = v0 + v7; /* Write-back transformed values */ + src[8 * 7] = v0 - v7; + src[8 * 1] = v1 + v6; + src[8 * 6] = v1 - v6; + src[8 * 2] = v2 + v5; + src[8 * 5] = v2 - v5; + src[8 * 3] = v3 + v4; + src[8 * 4] = v3 - v4; + + src++; /* Next column */ + } + + /* Process rows */ + src -= 8; + for (i = 0; i < 8; i++) { + v0 = src[0] + (128L << 8); /* Get even elements (remove DC offset (-128) here) */ + v1 = src[2]; + v2 = src[4]; + v3 = src[6]; + + t10 = v0 + v2; /* Process the even elements */ + t12 = v0 - v2; + t11 = (v1 - v3) * M13 >> 12; + v3 += v1; + t11 -= v3; + v0 = t10 + v3; + v3 = t10 - v3; + v1 = t11 + t12; + v2 = t12 - t11; + + v4 = src[7]; /* Get odd elements */ + v5 = src[1]; + v6 = src[5]; + v7 = src[3]; + + t10 = v5 - v4; /* Process the odd elements */ + t11 = v5 + v4; + t12 = v6 - v7; + v7 += v6; + v5 = (t11 - v7) * M13 >> 12; + v7 += t11; + t13 = (t10 + t12) * M5 >> 12; + v4 = t13 - (t10 * M2 >> 12); + v6 = t13 - (t12 * M4 >> 12) - v7; + v5 -= v6; + v4 -= v5; + + dst[0] = BYTECLIP((v0 + v7) >> 8); /* Descale the transformed values 8 bits and output */ + dst[7] = BYTECLIP((v0 - v7) >> 8); + dst[1] = BYTECLIP((v1 + v6) >> 8); + dst[6] = BYTECLIP((v1 - v6) >> 8); + dst[2] = BYTECLIP((v2 + v5) >> 8); + dst[5] = BYTECLIP((v2 - v5) >> 8); + dst[3] = BYTECLIP((v3 + v4) >> 8); + dst[4] = BYTECLIP((v3 - v4) >> 8); + dst += 8; + + src += 8; /* Next row */ + } +} + + + + +/*-----------------------------------------------------------------------*/ +/* Load all blocks in the MCU into working buffer */ +/*-----------------------------------------------------------------------*/ + +static JRESULT mcu_load ( + JDEC* jd /* Pointer to the decompressor object */ +) +{ + int32_t *tmp = (int32_t*)jd->workbuf; /* Block working buffer for de-quantize and IDCT */ + int b, d, e; + uint16_t blk, nby, nbc, i, z, id, cmp; + uint8_t *bp; + const uint8_t *hb, *hd; + const uint16_t *hc; + const int32_t *dqf; + + + nby = jd->msx * jd->msy; /* Number of Y blocks (1, 2 or 4) */ + nbc = 2; /* Number of C blocks (2) */ + bp = jd->mcubuf; /* Pointer to the first block */ + + for (blk = 0; blk < nby + nbc; blk++) { + cmp = (blk < nby) ? 0 : blk - nby + 1; /* Component number 0:Y, 1:Cb, 2:Cr */ + id = cmp ? 1 : 0; /* Huffman table ID of the component */ + + /* Extract a DC element from input stream */ + hb = jd->huffbits[id][0]; /* Huffman table for the DC element */ + hc = jd->huffcode[id][0]; + hd = jd->huffdata[id][0]; + b = huffext(jd, hb, hc, hd); /* Extract a huffman coded data (bit length) */ + if (b < 0) return 0 - b; /* Err: invalid code or input */ + d = jd->dcv[cmp]; /* DC value of previous block */ + if (b) { /* If there is any difference from previous block */ + e = bitext(jd, b); /* Extract data bits */ + if (e < 0) return 0 - e; /* Err: input */ + b = 1 << (b - 1); /* MSB position */ + if (!(e & b)) e -= (b << 1) - 1; /* Restore sign if needed */ + d += e; /* Get current value */ + jd->dcv[cmp] = (int16_t)d; /* Save current DC value for next block */ + } + dqf = jd->qttbl[jd->qtid[cmp]]; /* De-quantizer table ID for this component */ + tmp[0] = d * dqf[0] >> 8; /* De-quantize, apply scale factor of Arai algorithm and descale 8 bits */ + + /* Extract following 63 AC elements from input stream */ + for (i = 1; i < 64; tmp[i++] = 0) ; /* Clear rest of elements */ + hb = jd->huffbits[id][1]; /* Huffman table for the AC elements */ + hc = jd->huffcode[id][1]; + hd = jd->huffdata[id][1]; + i = 1; /* Top of the AC elements */ + do { + b = huffext(jd, hb, hc, hd); /* Extract a huffman coded value (zero runs and bit length) */ + if (b == 0) break; /* EOB? */ + if (b < 0) return 0 - b; /* Err: invalid code or input error */ + z = (uint16_t)b >> 4; /* Number of leading zero elements */ + if (z) { + i += z; /* Skip zero elements */ + if (i >= 64) return JDR_FMT1; /* Too long zero run */ + } + if (b &= 0x0F) { /* Bit length */ + d = bitext(jd, b); /* Extract data bits */ + if (d < 0) return 0 - d; /* Err: input device */ + b = 1 << (b - 1); /* MSB position */ + if (!(d & b)) d -= (b << 1) - 1;/* Restore negative value if needed */ + z = ZIG(i); /* Zigzag-order to raster-order converted index */ + tmp[z] = d * dqf[z] >> 8; /* De-quantize, apply scale factor of Arai algorithm and descale 8 bits */ + } + } while (++i < 64); /* Next AC element */ + + if (JD_USE_SCALE && jd->scale == 3) { + *bp = (uint8_t)((*tmp / 256) + 128); /* If scale ratio is 1/8, IDCT can be ommited and only DC element is used */ + } else { + block_idct(tmp, bp); /* Apply IDCT and store the block to the MCU buffer */ + } + + bp += 64; /* Next block */ + } + + return JDR_OK; /* All blocks have been loaded successfully */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Output an MCU: Convert YCrCb to RGB and output it in RGB form */ +/*-----------------------------------------------------------------------*/ + +static JRESULT mcu_output ( + JDEC* jd, /* Pointer to the decompressor object */ + uint16_t (*outfunc)(JDEC*, void*, JRECT*), /* RGB output function */ + uint16_t x, /* MCU position in the image (left of the MCU) */ + uint16_t y /* MCU position in the image (top of the MCU) */ +) +{ + const int16_t CVACC = (sizeof (int16_t) > 2) ? 1024 : 128; + uint16_t ix, iy, mx, my, rx, ry; + int16_t yy, cb, cr; + uint8_t *py, *pc, *rgb24; + JRECT rect; + + + mx = jd->msx * 8; my = jd->msy * 8; /* MCU size (pixel) */ + rx = (x + mx <= jd->width) ? mx : jd->width - x; /* Output rectangular size (it may be clipped at right/bottom end) */ + ry = (y + my <= jd->height) ? my : jd->height - y; + if (JD_USE_SCALE) { + rx >>= jd->scale; ry >>= jd->scale; + if (!rx || !ry) return JDR_OK; /* Skip this MCU if all pixel is to be rounded off */ + x >>= jd->scale; y >>= jd->scale; + } + rect.left = x; rect.right = x + rx - 1; /* Rectangular area in the frame buffer */ + rect.top = y; rect.bottom = y + ry - 1; + + + if (!JD_USE_SCALE || jd->scale != 3) { /* Not for 1/8 scaling */ + + /* Build an RGB MCU from discrete comopnents */ + rgb24 = (uint8_t*)jd->workbuf; + for (iy = 0; iy < my; iy++) { + pc = jd->mcubuf; + py = pc + iy * 8; + if (my == 16) { /* Double block height? */ + pc += 64 * 4 + (iy >> 1) * 8; + if (iy >= 8) py += 64; + } else { /* Single block height */ + pc += mx * 8 + iy * 8; + } + for (ix = 0; ix < mx; ix++) { + cb = pc[0] - 128; /* Get Cb/Cr component and restore right level */ + cr = pc[64] - 128; + if (mx == 16) { /* Double block width? */ + if (ix == 8) py += 64 - 8; /* Jump to next block if double block heigt */ + pc += ix & 1; /* Increase chroma pointer every two pixels */ + } else { /* Single block width */ + pc++; /* Increase chroma pointer every pixel */ + } + yy = *py++; /* Get Y component */ + + /* Convert YCbCr to RGB */ + *rgb24++ = /* R */ BYTECLIP(yy + ((int16_t)(1.402 * CVACC) * cr) / CVACC); + *rgb24++ = /* G */ BYTECLIP(yy - ((int16_t)(0.344 * CVACC) * cb + (int16_t)(0.714 * CVACC) * cr) / CVACC); + *rgb24++ = /* B */ BYTECLIP(yy + ((int16_t)(1.772 * CVACC) * cb) / CVACC); + } + } + + /* Descale the MCU rectangular if needed */ + if (JD_USE_SCALE && jd->scale) { + uint16_t x, y, r, g, b, s, w, a; + uint8_t *op; + + /* Get averaged RGB value of each square correcponds to a pixel */ + s = jd->scale * 2; /* Bumber of shifts for averaging */ + w = 1 << jd->scale; /* Width of square */ + a = (mx - w) * 3; /* Bytes to skip for next line in the square */ + op = (uint8_t*)jd->workbuf; + for (iy = 0; iy < my; iy += w) { + for (ix = 0; ix < mx; ix += w) { + rgb24 = (uint8_t*)jd->workbuf + (iy * mx + ix) * 3; + r = g = b = 0; + for (y = 0; y < w; y++) { /* Accumulate RGB value in the square */ + for (x = 0; x < w; x++) { + r += *rgb24++; + g += *rgb24++; + b += *rgb24++; + } + rgb24 += a; + } /* Put the averaged RGB value as a pixel */ + *op++ = (uint8_t)(r >> s); + *op++ = (uint8_t)(g >> s); + *op++ = (uint8_t)(b >> s); + } + } + } + + } else { /* For only 1/8 scaling (left-top pixel in each block are the DC value of the block) */ + + /* Build a 1/8 descaled RGB MCU from discrete comopnents */ + rgb24 = (uint8_t*)jd->workbuf; + pc = jd->mcubuf + mx * my; + cb = pc[0] - 128; /* Get Cb/Cr component and restore right level */ + cr = pc[64] - 128; + for (iy = 0; iy < my; iy += 8) { + py = jd->mcubuf; + if (iy == 8) py += 64 * 2; + for (ix = 0; ix < mx; ix += 8) { + yy = *py; /* Get Y component */ + py += 64; + + /* Convert YCbCr to RGB */ + *rgb24++ = /* R */ BYTECLIP(yy + ((int16_t)(1.402 * CVACC) * cr / CVACC)); + *rgb24++ = /* G */ BYTECLIP(yy - ((int16_t)(0.344 * CVACC) * cb + (int16_t)(0.714 * CVACC) * cr) / CVACC); + *rgb24++ = /* B */ BYTECLIP(yy + ((int16_t)(1.772 * CVACC) * cb / CVACC)); + } + } + } + + /* Squeeze up pixel table if a part of MCU is to be truncated */ + mx >>= jd->scale; + if (rx < mx) { + uint8_t *s, *d; + uint16_t x, y; + + s = d = (uint8_t*)jd->workbuf; + for (y = 0; y < ry; y++) { + for (x = 0; x < rx; x++) { /* Copy effective pixels */ + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + s += (mx - rx) * 3; /* Skip truncated pixels */ + } + } + + /* Convert RGB888 to RGB565 if needed */ + if (JD_FORMAT == 1) { + uint8_t *s = (uint8_t*)jd->workbuf; + uint16_t w, *d = (uint16_t*)s; + uint16_t n = rx * ry; + + do { + w = (*s++ & 0xF8) << 8; /* RRRRR----------- */ + w |= (*s++ & 0xFC) << 3; /* -----GGGGGG----- */ + w |= *s++ >> 3; /* -----------BBBBB */ + *d++ = w; + } while (--n); + } + + /* Output the RGB rectangular */ + return outfunc(jd, jd->workbuf, &rect) ? JDR_OK : JDR_INTR; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Process restart interval */ +/*-----------------------------------------------------------------------*/ + +static JRESULT restart ( + JDEC* jd, /* Pointer to the decompressor object */ + uint16_t rstn /* Expected restert sequense number */ +) +{ + uint16_t i, dc; + uint16_t d; + uint8_t *dp; + + + /* Discard padding bits and get two bytes from the input stream */ + dp = jd->dptr; dc = jd->dctr; + d = 0; + for (i = 0; i < 2; i++) { + if (!dc) { /* No input data is available, re-fill input buffer */ + dp = jd->inbuf; + dc = jd->infunc(jd, dp, JD_SZBUF); + if (!dc) return JDR_INP; + } else { + dp++; + } + dc--; + d = (d << 8) | *dp; /* Get a byte */ + } + jd->dptr = dp; jd->dctr = dc; jd->dmsk = 0; + + /* Check the marker */ + if ((d & 0xFFD8) != 0xFFD0 || (d & 7) != (rstn & 7)) { + return JDR_FMT1; /* Err: expected RSTn marker is not detected (may be collapted data) */ + } + + /* Reset DC offset */ + jd->dcv[2] = jd->dcv[1] = jd->dcv[0] = 0; + + return JDR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Analyze the JPEG image and Initialize decompressor object */ +/*-----------------------------------------------------------------------*/ + +#define LDB_WORD(ptr) (uint16_t)(((uint16_t)*((uint8_t*)(ptr))<<8)|(uint16_t)*(uint8_t*)((ptr)+1)) + + +JRESULT jd_prepare ( + JDEC* jd, /* Blank decompressor object */ + uint16_t (*infunc)(JDEC*, uint8_t*, uint16_t), /* JPEG strem input function */ + void* pool, /* Working buffer for the decompression session */ + uint16_t sz_pool, /* Size of working buffer */ + void* dev /* I/O device identifier for the session */ +) +{ + uint8_t *seg, b; + uint16_t marker; + uint32_t ofs; + uint16_t n, i, j, len; + JRESULT rc; + + + if (!pool) return JDR_PAR; + + jd->pool = pool; /* Work memroy */ + jd->sz_pool = sz_pool; /* Size of given work memory */ + jd->infunc = infunc; /* Stream input function */ + jd->device = dev; /* I/O device identifier */ + jd->nrst = 0; /* No restart interval (default) */ + + for (i = 0; i < 2; i++) { /* Nulls pointers */ + for (j = 0; j < 2; j++) { + jd->huffbits[i][j] = 0; + jd->huffcode[i][j] = 0; + jd->huffdata[i][j] = 0; + } + } + for (i = 0; i < 4; jd->qttbl[i++] = 0) ; + + jd->inbuf = seg = alloc_pool(jd, JD_SZBUF); /* Allocate stream input buffer */ + if (!seg) return JDR_MEM1; + + if (jd->infunc(jd, seg, 2) != 2) return JDR_INP;/* Check SOI marker */ + if (LDB_WORD(seg) != 0xFFD8) return JDR_FMT1; /* Err: SOI is not detected */ + ofs = 2; + + for (;;) { + /* Get a JPEG marker */ + if (jd->infunc(jd, seg, 4) != 4) return JDR_INP; + marker = LDB_WORD(seg); /* Marker */ + len = LDB_WORD(seg + 2); /* Length field */ + if (len <= 2 || (marker >> 8) != 0xFF) return JDR_FMT1; + len -= 2; /* Content size excluding length field */ + ofs += 4 + len; /* Number of bytes loaded */ + + switch (marker & 0xFF) { + case 0xC0: /* SOF0 (baseline JPEG) */ + /* Load segment data */ + if (len > JD_SZBUF) return JDR_MEM2; + if (jd->infunc(jd, seg, len) != len) return JDR_INP; + + jd->width = LDB_WORD(seg+3); /* Image width in unit of pixel */ + jd->height = LDB_WORD(seg+1); /* Image height in unit of pixel */ + if (seg[5] != 3) return JDR_FMT3; /* Err: Supports only Y/Cb/Cr format */ + + /* Check three image components */ + for (i = 0; i < 3; i++) { + b = seg[7 + 3 * i]; /* Get sampling factor */ + if (!i) { /* Y component */ + if (b != 0x11 && b != 0x22 && b != 0x21) { /* Check sampling factor */ + return JDR_FMT3; /* Err: Supports only 4:4:4, 4:2:0 or 4:2:2 */ + } + jd->msx = b >> 4; jd->msy = b & 15; /* Size of MCU [blocks] */ + } else { /* Cb/Cr component */ + if (b != 0x11) return JDR_FMT3; /* Err: Sampling factor of Cr/Cb must be 1 */ + } + b = seg[8 + 3 * i]; /* Get dequantizer table ID for this component */ + if (b > 3) return JDR_FMT3; /* Err: Invalid ID */ + jd->qtid[i] = b; + } + break; + + case 0xDD: /* DRI */ + /* Load segment data */ + if (len > JD_SZBUF) return JDR_MEM2; + if (jd->infunc(jd, seg, len) != len) return JDR_INP; + + /* Get restart interval (MCUs) */ + jd->nrst = LDB_WORD(seg); + break; + + case 0xC4: /* DHT */ + /* Load segment data */ + if (len > JD_SZBUF) return JDR_MEM2; + if (jd->infunc(jd, seg, len) != len) return JDR_INP; + + /* Create huffman tables */ + rc = create_huffman_tbl(jd, seg, len); + if (rc) return rc; + break; + + case 0xDB: /* DQT */ + /* Load segment data */ + if (len > JD_SZBUF) return JDR_MEM2; + if (jd->infunc(jd, seg, len) != len) return JDR_INP; + + /* Create de-quantizer tables */ + rc = create_qt_tbl(jd, seg, len); + if (rc) return rc; + break; + + case 0xDA: /* SOS */ + /* Load segment data */ + if (len > JD_SZBUF) return JDR_MEM2; + if (jd->infunc(jd, seg, len) != len) return JDR_INP; + + if (!jd->width || !jd->height) return JDR_FMT1; /* Err: Invalid image size */ + + if (seg[0] != 3) return JDR_FMT3; /* Err: Supports only three color components format */ + + /* Check if all tables corresponding to each components have been loaded */ + for (i = 0; i < 3; i++) { + b = seg[2 + 2 * i]; /* Get huffman table ID */ + if (b != 0x00 && b != 0x11) return JDR_FMT3; /* Err: Different table number for DC/AC element */ + b = i ? 1 : 0; + if (!jd->huffbits[b][0] || !jd->huffbits[b][1]) { /* Check dc/ac huffman table for this component */ + return JDR_FMT1; /* Err: Nnot loaded */ + } + if (!jd->qttbl[jd->qtid[i]]) { /* Check dequantizer table for this component */ + return JDR_FMT1; /* Err: Not loaded */ + } + } + + /* Allocate working buffer for MCU and RGB */ + n = jd->msy * jd->msx; /* Number of Y blocks in the MCU */ + if (!n) return JDR_FMT1; /* Err: SOF0 has not been loaded */ + len = n * 64 * 2 + 64; /* Allocate buffer for IDCT and RGB output */ + if (len < 256) len = 256; /* but at least 256 byte is required for IDCT */ + jd->workbuf = alloc_pool(jd, len); /* and it may occupy a part of following MCU working buffer for RGB output */ + if (!jd->workbuf) return JDR_MEM1; /* Err: not enough memory */ + jd->mcubuf = (uint8_t*)alloc_pool(jd, (uint16_t)((n + 2) * 64)); /* Allocate MCU working buffer */ + if (!jd->mcubuf) return JDR_MEM1; /* Err: not enough memory */ + + /* Pre-load the JPEG data to extract it from the bit stream */ + jd->dptr = seg; jd->dctr = 0; jd->dmsk = 0; /* Prepare to read bit stream */ + if (ofs %= JD_SZBUF) { /* Align read offset to JD_SZBUF */ + jd->dctr = jd->infunc(jd, seg + ofs, (uint16_t)(JD_SZBUF - ofs)); + jd->dptr = seg + ofs - 1; + } + + return JDR_OK; /* Initialization succeeded. Ready to decompress the JPEG image. */ + + case 0xC1: /* SOF1 */ + case 0xC2: /* SOF2 */ + case 0xC3: /* SOF3 */ + case 0xC5: /* SOF5 */ + case 0xC6: /* SOF6 */ + case 0xC7: /* SOF7 */ + case 0xC9: /* SOF9 */ + case 0xCA: /* SOF10 */ + case 0xCB: /* SOF11 */ + case 0xCD: /* SOF13 */ + case 0xCE: /* SOF14 */ + case 0xCF: /* SOF15 */ + case 0xD9: /* EOI */ + return JDR_FMT3; /* Unsuppoted JPEG standard (may be progressive JPEG) */ + + default: /* Unknown segment (comment, exif or etc..) */ + /* Skip segment data */ + if (jd->infunc(jd, 0, len) != len) { /* Null pointer specifies to skip bytes of stream */ + return JDR_INP; + } + } + } +} + + + + +/*-----------------------------------------------------------------------*/ +/* Start to decompress the JPEG picture */ +/*-----------------------------------------------------------------------*/ + +JRESULT jd_decomp ( + JDEC* jd, /* Initialized decompression object */ + uint16_t (*outfunc)(JDEC*, void*, JRECT*), /* RGB output function */ + uint8_t scale /* Output de-scaling factor (0 to 3) */ +) +{ + uint16_t x, y, mx, my; + uint16_t rst, rsc; + JRESULT rc; + + + if (scale > (JD_USE_SCALE ? 3 : 0)) return JDR_PAR; + jd->scale = scale; + + mx = jd->msx * 8; my = jd->msy * 8; /* Size of the MCU (pixel) */ + + jd->dcv[2] = jd->dcv[1] = jd->dcv[0] = 0; /* Initialize DC values */ + rst = rsc = 0; + + rc = JDR_OK; + for (y = 0; y < jd->height; y += my) { /* Vertical loop of MCUs */ + for (x = 0; x < jd->width; x += mx) { /* Horizontal loop of MCUs */ + if (jd->nrst && rst++ == jd->nrst) { /* Process restart interval if enabled */ + rc = restart(jd, rsc++); + if (rc != JDR_OK) return rc; + rst = 1; + } + rc = mcu_load(jd); /* Load an MCU (decompress huffman coded stream and apply IDCT) */ + if (rc != JDR_OK) return rc; + rc = mcu_output(jd, outfunc, x, y); /* Output the MCU (color space conversion, scaling and output) */ + if (rc != JDR_OK) return rc; + } + } + + return rc; +} + + + diff --git a/examples/peripherals/spi_master/main/decode_image.c b/examples/peripherals/spi_master/main/decode_image.c index 4a4b4daed9..179c3deb7a 100644 --- a/examples/peripherals/spi_master/main/decode_image.c +++ b/examples/peripherals/spi_master/main/decode_image.c @@ -7,72 +7,69 @@ CONDITIONS OF ANY KIND, either express or implied. */ - /* -The image used for the effect on the LCD in the SPI master example is stored in flash -as a jpeg file. This file contains the decode_image routine, which uses the tiny JPEG -decoder library in ROM to decode this JPEG into a format that can be sent to the display. +The image used for the effect on the LCD in the SPI master example is stored in flash +as a jpeg file. This file contains the decode_image routine, which uses the tiny JPEG +decoder library to decode this JPEG into a format that can be sent to the display. -Keep in mind that the decoder library cannot handle progressive files (will give +Keep in mind that the decoder library cannot handle progressive files (will give ``Image decoder: jd_prepare failed (8)`` as an error) so make sure to save in the correct format if you want to use a different image file. */ - #include "decode_image.h" -#include "esp32/rom/tjpgd.h" +#include "tjpgd.h" #include "esp_log.h" #include //Reference the binary-included jpeg file -extern const uint8_t image_jpg_start[] asm("_binary_image_jpg_start"); -extern const uint8_t image_jpg_end[] asm("_binary_image_jpg_end"); +extern const uint8_t image_jpg_start[] asm("_binary_image_jpg_start"); +extern const uint8_t image_jpg_end[] asm("_binary_image_jpg_end"); //Define the height and width of the jpeg file. Make sure this matches the actual jpeg //dimensions. #define IMAGE_W 336 #define IMAGE_H 256 - -const char *TAG="ImageDec"; - +const char *TAG = "ImageDec"; //Data that is passed from the decoder function to the infunc/outfunc functions. typedef struct { - const unsigned char *inData; //Pointer to jpeg data - int inPos; //Current position in jpeg data - uint16_t **outData; //Array of IMAGE_H pointers to arrays of IMAGE_W 16-bit pixel values - int outW; //Width of the resulting file - int outH; //Height of the resulting file + const unsigned char *inData; //Pointer to jpeg data + uint16_t inPos; //Current position in jpeg data + uint16_t **outData; //Array of IMAGE_H pointers to arrays of IMAGE_W 16-bit pixel values + int outW; //Width of the resulting file + int outH; //Height of the resulting file } JpegDev; - //Input function for jpeg decoder. Just returns bytes from the inData field of the JpegDev structure. -static UINT infunc(JDEC *decoder, BYTE *buf, UINT len) +static uint16_t infunc(JDEC *decoder, uint8_t *buf, uint16_t len) { //Read bytes from input file - JpegDev *jd=(JpegDev*)decoder->device; - if (buf!=NULL) memcpy(buf, jd->inData+jd->inPos, len); - jd->inPos+=len; + JpegDev *jd = (JpegDev *)decoder->device; + if (buf != NULL) { + memcpy(buf, jd->inData + jd->inPos, len); + } + jd->inPos += len; return len; } //Output function. Re-encodes the RGB888 data from the decoder as big-endian RGB565 and //stores it in the outData array of the JpegDev structure. -static UINT outfunc(JDEC *decoder, void *bitmap, JRECT *rect) +static uint16_t outfunc(JDEC *decoder, void *bitmap, JRECT *rect) { - JpegDev *jd=(JpegDev*)decoder->device; - uint8_t *in=(uint8_t*)bitmap; - for (int y=rect->top; y<=rect->bottom; y++) { - for (int x=rect->left; x<=rect->right; x++) { + JpegDev *jd = (JpegDev *)decoder->device; + uint8_t *in = (uint8_t *)bitmap; + for (int y = rect->top; y <= rect->bottom; y++) { + for (int x = rect->left; x <= rect->right; x++) { //We need to convert the 3 bytes in `in` to a rgb565 value. - uint16_t v=0; - v|=((in[0]>>3)<<11); - v|=((in[1]>>2)<<5); - v|=((in[2]>>3)<<0); + uint16_t v = 0; + v |= ((in[0] >> 3) << 11); + v |= ((in[1] >> 2) << 5); + v |= ((in[2] >> 3) << 0); //The LCD wants the 16-bit value in big-endian, so swap bytes - v=(v>>8)|(v<<8); - jd->outData[y][x]=v; - in+=3; + v = (v >> 8) | (v << 8); + jd->outData[y][x] = v; + in += 3; } } return 1; @@ -82,68 +79,67 @@ static UINT outfunc(JDEC *decoder, void *bitmap, JRECT *rect) #define WORKSZ 3100 //Decode the embedded image into pixel lines that can be used with the rest of the logic. -esp_err_t decode_image(uint16_t ***pixels) +esp_err_t decode_image(uint16_t ***pixels) { - char *work=NULL; + char *work = NULL; int r; JDEC decoder; JpegDev jd; - *pixels=NULL; - esp_err_t ret=ESP_OK; - + *pixels = NULL; + esp_err_t ret = ESP_OK; //Alocate pixel memory. Each line is an array of IMAGE_W 16-bit pixels; the `*pixels` array itself contains pointers to these lines. - *pixels=calloc(IMAGE_H, sizeof(uint16_t*)); - if (*pixels==NULL) { + *pixels = calloc(IMAGE_H, sizeof(uint16_t *)); + if (*pixels == NULL) { ESP_LOGE(TAG, "Error allocating memory for lines"); - ret=ESP_ERR_NO_MEM; + ret = ESP_ERR_NO_MEM; goto err; } - for (int i=0; imagic; crc = buf->crc; buf->crc = 0; - crc_cal = crc16_le(UINT16_MAX, (uint8_t const *)buf, data_len); + crc_cal = esp_crc16_le(UINT16_MAX, (uint8_t const *)buf, data_len); if (crc_cal == crc) { return buf->type; @@ -146,7 +145,7 @@ void example_espnow_data_prepare(example_espnow_send_param_t *send_param) buf->magic = send_param->magic; /* Fill all remaining bytes after the data with random values */ esp_fill_random(buf->payload, send_param->len - sizeof(example_espnow_data_t)); - buf->crc = crc16_le(UINT16_MAX, (uint8_t const *)buf, send_param->len); + buf->crc = esp_crc16_le(UINT16_MAX, (uint8_t const *)buf, send_param->len); } static void example_espnow_task(void *pvParameter) diff --git a/tools/ci/check_examples_rom_header.sh b/tools/ci/check_examples_rom_header.sh new file mode 100755 index 0000000000..131723e0db --- /dev/null +++ b/tools/ci/check_examples_rom_header.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Examples shouldn't include rom headers directly + +output=$(find ${IDF_PATH}/examples -name "*.[chS]" -o -name "*.cpp" -not -path "**/build/**") +files=$(grep ".*include.*rom.*h" ${output} | cut -d ":" -f 1) +found_rom=0 +for file in ${files} +do + echo "${file} contains rom headers!" + found_rom=`expr $found_rom + 1`; +done + +if [ $found_rom -eq 0 ]; then + echo "No rom headers found in examples" + exit 0 +fi + +exit 1 diff --git a/tools/ci/config/check.yml b/tools/ci/config/check.yml index ad4f71290c..7507c47ed4 100644 --- a/tools/ci/config/check.yml +++ b/tools/ci/config/check.yml @@ -42,6 +42,11 @@ check_examples_cmake_make: script: - tools/ci/check_examples_cmake_make.sh +check_examples_rom_header: + extends: .check_job_template_with_filter + script: + - tools/ci/check_examples_rom_header.sh + check_python_style: extends: .check_job_template_with_filter artifacts: diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index 4e580c5a85..bcc257b3d4 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -35,6 +35,7 @@ tools/ci/build_examples_cmake.sh tools/ci/check-executable.sh tools/ci/check-line-endings.sh tools/ci/check_examples_cmake_make.sh +tools/ci/check_examples_rom_header.sh tools/ci/check_idf_version.sh tools/ci/check_ut_cmake_make.sh tools/ci/checkout_project_ref.py From dc9170966b4e8c2a4b6e864fb78099c286ea9f8f Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 8 Aug 2019 15:27:47 +1000 Subject: [PATCH 451/486] freertos: Force UNICORE mode on ESP32S2 --- components/freertos/Kconfig | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index 2fdd3cc558..06461b9198 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -1,9 +1,15 @@ menu "FreeRTOS" - # This is actually also handled in the ESP32 startup code, not only in FreeRTOS. + config FREERTOS_SINGLE_CORE_ONLY + # invisible config item to always select FREERTOS_UNICORE on single core IDF_TARGET + bool + default y + depends on IDF_TARGET_ESP32S2BETA + select FREERTOS_UNICORE + config FREERTOS_UNICORE + # This config variable is also checked in the ESP32 startup code, not only in FreeRTOS. bool "Run FreeRTOS only on first core" - default y if IDF_TARGET_ESP32S2BETA default n help This version of FreeRTOS normally takes control of all cores of From 309376f51ae01bf0dcfa45d5b00a71657c3df7b2 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 8 Aug 2019 15:28:10 +1000 Subject: [PATCH 452/486] spi_flash: Force legacy mode for ESP32-S2 Can be removed once IDF-763 is merged --- .../src/{esp32 => }/bootloader_flash_config_esp32.c | 0 .../bootloader_flash_config_esp32s2beta.c | 0 components/spi_flash/CMakeLists.txt | 13 ++++++++----- components/spi_flash/Kconfig | 9 +++++++++ components/spi_flash/esp32/flash_ops_esp32.c | 4 +--- components/spi_flash/flash_ops.c | 5 +++++ 6 files changed, 23 insertions(+), 8 deletions(-) rename components/bootloader_support/src/{esp32 => }/bootloader_flash_config_esp32.c (100%) rename components/bootloader_support/src/{esp32s2beta => }/bootloader_flash_config_esp32s2beta.c (100%) diff --git a/components/bootloader_support/src/esp32/bootloader_flash_config_esp32.c b/components/bootloader_support/src/bootloader_flash_config_esp32.c similarity index 100% rename from components/bootloader_support/src/esp32/bootloader_flash_config_esp32.c rename to components/bootloader_support/src/bootloader_flash_config_esp32.c diff --git a/components/bootloader_support/src/esp32s2beta/bootloader_flash_config_esp32s2beta.c b/components/bootloader_support/src/bootloader_flash_config_esp32s2beta.c similarity index 100% rename from components/bootloader_support/src/esp32s2beta/bootloader_flash_config_esp32s2beta.c rename to components/bootloader_support/src/bootloader_flash_config_esp32s2beta.c diff --git a/components/spi_flash/CMakeLists.txt b/components/spi_flash/CMakeLists.txt index b73a8362ca..63b19cd968 100644 --- a/components/spi_flash/CMakeLists.txt +++ b/components/spi_flash/CMakeLists.txt @@ -13,13 +13,16 @@ else() "spi_flash_chip_generic.c" "spi_flash_chip_issi.c" ) - if(NOT CONFIG_SPI_FLASH_USE_LEGACY_IMPL) - list(APPEND srcs "esp_flash_api.c" - "esp_flash_spi_init.c" + if (NOT CONFIG_IDF_TARGET_ESP32S2BETA) + # TODO: workaround until ESP32-S2 supports new API, can be always included + list(APPEND srcs "esp_flash_spi_init.c" "memspi_host_driver.c" "spi_flash_os_func_app.c" - "spi_flash_os_func_noos.c" - ) + "spi_flash_os_func_noos.c") + endif() + + if(NOT CONFIG_SPI_FLASH_USE_LEGACY_IMPL) + list(APPEND srcs "esp_flash_api.c") endif() set(priv_requires bootloader_support app_update soc) endif() diff --git a/components/spi_flash/Kconfig b/components/spi_flash/Kconfig index 8a10651ff0..edd8892fc9 100644 --- a/components/spi_flash/Kconfig +++ b/components/spi_flash/Kconfig @@ -77,6 +77,15 @@ menu "SPI Flash driver" bool "Allowed" endchoice + # Force the Legacy implementation to be used on ESP32S2Beta + # + # TODO esp32s2beta: Remove once SPI Flash HAL available on S2 Beta + config SPI_FLASH_FORCE_LEGACY_ESP32S2BETA + bool + default y + depends on IDF_TARGET_ESP32S2BETA + select SPI_FLASH_USE_LEGACY_IMPL + config SPI_FLASH_USE_LEGACY_IMPL bool "Use the legacy implementation before IDF v4.0" default n diff --git a/components/spi_flash/esp32/flash_ops_esp32.c b/components/spi_flash/esp32/flash_ops_esp32.c index 4a33eaa38b..71f9b3dab8 100644 --- a/components/spi_flash/esp32/flash_ops_esp32.c +++ b/components/spi_flash/esp32/flash_ops_esp32.c @@ -12,9 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. #include -#include "esp_spi_flash_chip.h" #include "esp_spi_flash.h" -#include "cache_utils.h" #include "esp32/rom/spi_flash.h" #include "esp32/rom/cache.h" @@ -38,7 +36,7 @@ esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_a { const uint8_t *ssrc = (const uint8_t *)src; esp_rom_spiflash_result_t rc; - rc = spi_flash_unlock(); + rc = esp_rom_spiflash_unlock(); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { return rc; } diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index 0755de72c8..99b2db2371 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -700,3 +700,8 @@ void spi_flash_dump_counters(void) } #endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS + +#if defined(CONFIG_SPI_FLASH_USE_LEGACY_IMPL) && defined(CONFIG_IDF_TARGET_ESP32S2BETA) +// TODO esp32s2beta: Remove once ESP32S2Beta has new SPI Flash API support +esp_flash_t *esp_flash_default_chip = NULL; +#endif From d5f5fadbeef3ca01d3775a25e890efb9b88c54d4 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 8 Aug 2019 15:33:45 +1000 Subject: [PATCH 453/486] bootloader: Include FreeRTOS component for the FREERTOS_UNICORE header, only --- components/bootloader_support/CMakeLists.txt | 3 ++- components/freertos/CMakeLists.txt | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/components/bootloader_support/CMakeLists.txt b/components/bootloader_support/CMakeLists.txt index 92b04097e6..f9ed448ab5 100644 --- a/components/bootloader_support/CMakeLists.txt +++ b/components/bootloader_support/CMakeLists.txt @@ -17,7 +17,8 @@ endif() if(BOOTLOADER_BUILD) set(include_dirs "include" "include_bootloader") - set(priv_requires micro-ecc spi_flash efuse) + # freertos is included just for the CONFIG_FREERTOS_UNICORE macro + set(priv_requires micro-ecc spi_flash efuse freertos) list(APPEND srcs "src/bootloader_init.c" "src/${IDF_TARGET}/bootloader_sha.c" diff --git a/components/freertos/CMakeLists.txt b/components/freertos/CMakeLists.txt index ee6b560392..9826fd8c91 100644 --- a/components/freertos/CMakeLists.txt +++ b/components/freertos/CMakeLists.txt @@ -1,4 +1,10 @@ -set(srcs +if(BOOTLOADER_BUILD) + # bootloader only needs FreeRTOS for config, not for anything else + idf_component_register() + return() +endif() + +set(srcs "croutine.c" "event_groups.c" "FreeRTOS-openocd.c" From eb7ad6ca178e3bf9516de3899bc6d163c44bacfb Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 8 Aug 2019 16:21:34 +1000 Subject: [PATCH 454/486] bootloader: Fix SPI dummy clock settings for ESP32S2-beta --- .../src/bootloader_flash_config_esp32s2beta.c | 74 ++++++++++--------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/components/bootloader_support/src/bootloader_flash_config_esp32s2beta.c b/components/bootloader_support/src/bootloader_flash_config_esp32s2beta.c index 89025a6f9e..f6bea6cf4b 100644 --- a/components/bootloader_support/src/bootloader_flash_config_esp32s2beta.c +++ b/components/bootloader_support/src/bootloader_flash_config_esp32s2beta.c @@ -17,9 +17,9 @@ #include "sdkconfig.h" #include "esp_err.h" #include "esp_log.h" -#include "esp32/rom/gpio.h" -#include "esp32/rom/spi_flash.h" -#include "esp32/rom/efuse.h" +#include "esp32s2beta/rom/gpio.h" +#include "esp32s2beta/rom/spi_flash.h" +#include "esp32s2beta/rom/efuse.h" #include "soc/gpio_periph.h" #include "soc/efuse_reg.h" #include "soc/spi_reg.h" @@ -27,6 +27,12 @@ #include "soc/spi_caps.h" #include "flash_qio_mode.h" #include "bootloader_flash_config.h" +#include "bootloader_common.h" + +#define FLASH_IO_MATRIX_DUMMY_40M 0 +#define FLASH_IO_MATRIX_DUMMY_80M 0 + +#define FLASH_IO_DRIVE_GD_WITH_1V8PSRAM 3 void bootloader_flash_update_id() { @@ -73,42 +79,40 @@ void IRAM_ATTR bootloader_flash_gpio_config(const esp_image_header_t* pfhdr) void IRAM_ATTR bootloader_flash_dummy_config(const esp_image_header_t* pfhdr) { int spi_cache_dummy = 0; - uint32_t modebit = READ_PERI_REG(SPI_CTRL_REG(0)); - if (modebit & SPI_FAST_RD_MODE) { - if (modebit & SPI_FREAD_QUAD) { //SPI mode is QIO - spi_cache_dummy = SPI0_R_QIO_DUMMY_CYCLELEN; - } else if (modebit & SPI_FREAD_DUAL) { //SPI mode is DIO - spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN; - SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_ADDR_BITLEN_V, SPI0_R_DIO_ADDR_BITSLEN, SPI_USR_ADDR_BITLEN_S); - } else if(modebit & (SPI_FREAD_QUAD | SPI_FREAD_DUAL)) { //SPI mode is QOUT or DIO - spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN; - } + int drv = 2; + switch (pfhdr->spi_mode) { + case ESP_IMAGE_SPI_MODE_QIO: + spi_cache_dummy = SPI0_R_QIO_DUMMY_CYCLELEN; + break; + case ESP_IMAGE_SPI_MODE_DIO: + spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN; //qio 3 + break; + case ESP_IMAGE_SPI_MODE_QOUT: + case ESP_IMAGE_SPI_MODE_DOUT: + default: + spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN; + break; } + /* dummy_len_plus values defined in ROM for SPI flash configuration */ extern uint8_t g_rom_spiflash_dummy_len_plus[]; switch (pfhdr->spi_speed) { - case ESP_IMAGE_SPI_SPEED_80M: - g_rom_spiflash_dummy_len_plus[0] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_80M; - g_rom_spiflash_dummy_len_plus[1] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_80M; - break; - case ESP_IMAGE_SPI_SPEED_40M: - g_rom_spiflash_dummy_len_plus[0] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_40M; - g_rom_spiflash_dummy_len_plus[1] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_40M; - break; - case ESP_IMAGE_SPI_SPEED_26M: - case ESP_IMAGE_SPI_SPEED_20M: - g_rom_spiflash_dummy_len_plus[0] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_20M; - g_rom_spiflash_dummy_len_plus[1] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_20M; - break; - default: - break; + case ESP_IMAGE_SPI_SPEED_80M: + g_rom_spiflash_dummy_len_plus[0] = FLASH_IO_MATRIX_DUMMY_80M; + g_rom_spiflash_dummy_len_plus[1] = FLASH_IO_MATRIX_DUMMY_80M; + SET_PERI_REG_BITS(SPI_MEM_USER1_REG(0), SPI_MEM_USR_DUMMY_CYCLELEN_V, spi_cache_dummy + FLASH_IO_MATRIX_DUMMY_80M, + SPI_MEM_USR_DUMMY_CYCLELEN_S); //DUMMY + drv = 3; + break; + case ESP_IMAGE_SPI_SPEED_40M: + g_rom_spiflash_dummy_len_plus[0] = FLASH_IO_MATRIX_DUMMY_40M; + g_rom_spiflash_dummy_len_plus[1] = FLASH_IO_MATRIX_DUMMY_40M; + SET_PERI_REG_BITS(SPI_MEM_USER1_REG(0), SPI_MEM_USR_DUMMY_CYCLELEN_V, spi_cache_dummy + FLASH_IO_MATRIX_DUMMY_40M, + SPI_MEM_USR_DUMMY_CYCLELEN_S); //DUMMY + break; + default: + break; } - -#define FLASH_IO_MATRIX_DUMMY_40M 0 -#define FLASH_IO_MATRIX_DUMMY_80M 0 - - SET_PERI_REG_BITS(SPI_MEM_USER1_REG(0), SPI_MEM_USR_DUMMY_CYCLELEN_V, spi_cache_dummy + FLASH_IO_MATRIX_DUMMY_80M, - SPI_MEM_USR_DUMMY_CYCLELEN_S); //DUMMY - + bootloader_configure_spi_pins(drv); } From 4002c6060a70f7372bcf2b65a6af6c21f8d1a3b8 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 12 Aug 2019 11:04:30 +1000 Subject: [PATCH 455/486] lwip: Enable ethernet for both ESP32 & ESP32-S2Beta (SPI ethernet) --- components/lwip/CMakeLists.txt | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/components/lwip/CMakeLists.txt b/components/lwip/CMakeLists.txt index db2dea2040..df4bb7f3aa 100644 --- a/components/lwip/CMakeLists.txt +++ b/components/lwip/CMakeLists.txt @@ -87,6 +87,7 @@ set(srcs "port/esp32/freertos/sys_arch.c" "port/esp32/netif/dhcp_state.c" "port/esp32/netif/nettestif.c" + "port/esp32/netif/ethernetif.c" "port/esp32/netif/wlanif.c") if(CONFIG_LWIP_PPP_SUPPORT) @@ -123,19 +124,11 @@ if(CONFIG_LWIP_PPP_SUPPORT) "lwip/src/netif/ppp/polarssl/sha1.c") endif() -# Ethernet support for ESP32 only -if (IDF_TARGET_ESP32) - set(priv_requires esp_eth) - list(APPEND srcs "port/esp32/netif/ethernetif.c") -else() - set(priv_requires) -endif() - idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "${include_dirs}" LDFRAGMENTS linker.lf REQUIRES vfs esp_wifi - PRIV_REQUIRES ${priv_requires} tcpip_adapter nvs_flash) + PRIV_REQUIRES ${priv_requires} esp_eth tcpip_adapter nvs_flash) # lots of LWIP source files evaluate macros that check address of stack variables target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-address) From c47e1756f8bc7e8e1d82bc63714f7ff1d2906abe Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 12 Aug 2019 11:59:17 +1000 Subject: [PATCH 456/486] examples: Rename deprecate CONFIG_CONSOLE_UART_NUM macro --- components/soc/esp32s2beta/test/test_rtc_clk.c | 2 +- .../ble_mesh_node/main/ble_mesh_console_main.c | 4 ++-- .../ble_mesh_provisioner/main/ble_mesh_console_main.c | 4 ++-- .../ble_mesh_wifi_coexist/main/ble_mesh_demo_main.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/components/soc/esp32s2beta/test/test_rtc_clk.c b/components/soc/esp32s2beta/test/test_rtc_clk.c index 850c5be9ad..dd99bfcbeb 100644 --- a/components/soc/esp32s2beta/test/test_rtc_clk.c +++ b/components/soc/esp32s2beta/test/test_rtc_clk.c @@ -97,7 +97,7 @@ TEST_CASE("Output 8M XTAL clock to GPIO25", "[rtc_clk][ignore]") static void test_clock_switching(void (*switch_func)(rtc_cpu_freq_t)) { - uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM); + uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); const int test_duration_sec = 10; ref_clock_init(); diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c index 25857bc96d..5dba3a050b 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c @@ -63,11 +63,11 @@ static void initialize_console(void) esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF); /* Install UART driver for interrupt-driven reads and writes */ - ESP_ERROR_CHECK( uart_driver_install(CONFIG_CONSOLE_UART_NUM, + ESP_ERROR_CHECK( uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0) ); /* Tell VFS to use UART driver */ - esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM); + esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM); /* Initialize the console */ esp_console_config_t console_config = { diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c index 4618e14b57..a60f70ee2b 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c @@ -66,11 +66,11 @@ static void initialize_console(void) esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF); /* Install UART driver for interrupt-driven reads and writes */ - ESP_ERROR_CHECK( uart_driver_install(CONFIG_CONSOLE_UART_NUM, + ESP_ERROR_CHECK( uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0) ); /* Tell VFS to use UART driver */ - esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM); + esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM); /* Initialize the console */ esp_console_config_t console_config = { diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/ble_mesh_demo_main.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/ble_mesh_demo_main.c index b68253c382..7080073ec8 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/ble_mesh_demo_main.c +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/ble_mesh_demo_main.c @@ -841,11 +841,11 @@ static void initialize_console(void) esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF); /* Install UART driver for interrupt-driven reads and writes */ - ESP_ERROR_CHECK( uart_driver_install(CONFIG_CONSOLE_UART_NUM, + ESP_ERROR_CHECK( uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0) ); /* Tell VFS to use UART driver */ - esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM); + esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM); /* Initialize the console */ esp_console_config_t console_config = { From 18c5cfadae7d1b5bc7c02bfa87ad1cb6247c5848 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 12 Aug 2019 12:06:07 +1000 Subject: [PATCH 457/486] Fix function prototypes --- .../src/esp32s2beta/flash_encrypt.c | 4 +-- components/bt/host/nimble/nimble | 2 +- components/driver/esp32s2beta/rtc_touchpad.c | 26 +++++++------- components/driver/include/driver/rtc_io.h | 2 +- components/driver/include/driver/touch_pad.h | 22 ++++++------ components/esp32s2beta/brownout.c | 4 +-- components/esp32s2beta/cache_err_int.c | 4 +-- components/esp32s2beta/clk.c | 2 +- components/esp32s2beta/cpu_start.c | 4 +-- components/esp32s2beta/crosscore_int.c | 4 +-- components/esp32s2beta/esp_clk_internal.h | 2 +- .../esp32s2beta/esp_timer_esp32s2beta.c | 14 ++++---- .../include/esp32s2beta/brownout.h | 2 +- .../include/esp32s2beta/cache_err_int.h | 4 +-- .../esp32s2beta/include/esp32s2beta/clk.h | 4 +-- .../esp32s2beta/include/esp32s2beta/spiram.h | 12 +++---- components/esp32s2beta/include/esp_clk.h | 4 +-- .../esp32s2beta/include/esp_intr_alloc.h | 4 +-- components/esp32s2beta/include/esp_sleep.h | 14 ++++---- components/esp32s2beta/include/esp_spiram.h | 12 +++---- components/esp32s2beta/int_wdt.c | 4 +-- components/esp32s2beta/intr_alloc.c | 4 +-- components/esp32s2beta/panic.c | 20 +++++------ components/esp32s2beta/pm_esp32s2beta.c | 18 +++++----- components/esp32s2beta/pm_trace.c | 2 +- components/esp32s2beta/sleep_modes.c | 36 +++++++++---------- components/esp32s2beta/spiram.c | 16 ++++----- components/esp32s2beta/spiram_psram.c | 2 +- components/esp32s2beta/spiram_psram.h | 2 +- components/esp32s2beta/system_api.c | 6 ++-- components/esp32s2beta/task_wdt.c | 8 ++--- .../esp_rom/include/esp32s2beta/rom/cache.h | 12 +++---- .../include/esp32s2beta/rom/spi_flash.h | 4 +-- .../include/esp32s2beta/rom/tbconsole.h | 2 +- components/soc/esp32s2beta/cpu_util.c | 2 +- components/soc/esp32s2beta/include/soc/cpu.h | 8 ++--- components/soc/esp32s2beta/include/soc/rtc.h | 28 +++++++-------- components/soc/esp32s2beta/rtc_clk.c | 24 ++++++------- components/soc/esp32s2beta/rtc_init.c | 2 +- components/soc/esp32s2beta/rtc_pm.c | 8 ++--- components/soc/esp32s2beta/rtc_time.c | 8 ++--- .../soc/esp32s2beta/test/test_rtc_clk.c | 2 +- components/spi_flash/esp32/flash_ops_esp32.c | 4 +-- .../main/temp_sensor_main.c | 4 +-- .../main/esp32s2beta/tp_interrupt_main.c | 2 +- .../main/esp32s2beta/tp_read_main.c | 4 +-- 46 files changed, 189 insertions(+), 189 deletions(-) diff --git a/components/bootloader_support/src/esp32s2beta/flash_encrypt.c b/components/bootloader_support/src/esp32s2beta/flash_encrypt.c index c33a1c0525..5afa4b7e6d 100644 --- a/components/bootloader_support/src/esp32s2beta/flash_encrypt.c +++ b/components/bootloader_support/src/esp32s2beta/flash_encrypt.c @@ -31,7 +31,7 @@ static const char *TAG = "flash_encrypt"; /* Static functions for stages of flash encryption */ static esp_err_t initialise_flash_encryption(void); static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_crypt_wr_dis); -static esp_err_t encrypt_bootloader(); +static esp_err_t encrypt_bootloader(void); static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions); static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition); @@ -184,7 +184,7 @@ static esp_err_t encrypt_flash_contents(uint32_t spi_boot_crypt_cnt, bool flash_ return ESP_OK; } -static esp_err_t encrypt_bootloader() +static esp_err_t encrypt_bootloader(void) { esp_err_t err; uint32_t image_length; diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 7600a6f603..4839d84f61 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 7600a6f60308c77fec755a024d51ab2fb7d11553 +Subproject commit 4839d84f61296b7d7479350ebb92908b0fdb1329 diff --git a/components/driver/esp32s2beta/rtc_touchpad.c b/components/driver/esp32s2beta/rtc_touchpad.c index f31de9e662..0f62e22ea0 100644 --- a/components/driver/esp32s2beta/rtc_touchpad.c +++ b/components/driver/esp32s2beta/rtc_touchpad.c @@ -187,13 +187,13 @@ esp_err_t touch_pad_io_init(touch_pad_t touch_num) return ESP_OK; } -esp_err_t touch_pad_wait_init_done() +esp_err_t touch_pad_wait_init_done(void) { // TODO return ESP_FAIL; } -esp_err_t touch_pad_fsm_start() +esp_err_t touch_pad_fsm_start(void) { RTC_TOUCH_ENTER_CRITICAL(); RTCCNTL.touch_ctrl2.touch_clkgate_en = 1; //enable touch clock for FSM. or force enable. @@ -202,7 +202,7 @@ esp_err_t touch_pad_fsm_start() return ESP_OK; } -esp_err_t touch_pad_fsm_stop() +esp_err_t touch_pad_fsm_stop(void) { RTC_TOUCH_ENTER_CRITICAL(); RTCCNTL.touch_ctrl2.touch_start_en = 0; //stop touch fsm @@ -338,7 +338,7 @@ esp_err_t touch_pad_intr_disable(touch_pad_intr_mask_t int_mask) return ESP_OK; } -uint32_t touch_pad_intr_status_get_mask() +uint32_t touch_pad_intr_status_get_mask(void) { return ((REG_READ(RTC_CNTL_INT_ST_REG) >> (RTC_CNTL_TOUCH_DONE_INT_ST_S)) & TOUCH_PAD_INTR_MASK_ALL); } @@ -354,7 +354,7 @@ esp_err_t touch_pad_config(touch_pad_t touch_num) return ESP_OK; } -esp_err_t touch_pad_init() +esp_err_t touch_pad_init(void) { if (rtc_touch_mux == NULL) { rtc_touch_mux = xSemaphoreCreateMutex(); @@ -372,7 +372,7 @@ esp_err_t touch_pad_init() return ESP_OK; } -esp_err_t touch_pad_deinit() +esp_err_t touch_pad_deinit(void) { RTC_MODULE_CHECK(rtc_touch_mux != NULL, "Touch pad not initialized", ESP_FAIL); xSemaphoreTake(rtc_touch_mux, portMAX_DELAY); @@ -451,7 +451,7 @@ esp_err_t touch_pad_filter_get_config(touch_filter_config_t *filter_info) return ESP_OK; } -esp_err_t touch_pad_filter_enable() +esp_err_t touch_pad_filter_enable(void) { RTC_TOUCH_ENTER_CRITICAL(); RTCCNTL.touch_filter_ctrl.touch_filter_en = 1; @@ -459,7 +459,7 @@ esp_err_t touch_pad_filter_enable() return ESP_OK; } -esp_err_t touch_pad_filter_disable() +esp_err_t touch_pad_filter_disable(void) { RTC_TOUCH_ENTER_CRITICAL(); RTCCNTL.touch_filter_ctrl.touch_filter_en = 0; @@ -467,7 +467,7 @@ esp_err_t touch_pad_filter_disable() return ESP_OK; } -esp_err_t touch_pad_denoise_enable() +esp_err_t touch_pad_denoise_enable(void) { RTC_TOUCH_ENTER_CRITICAL(); RTCCNTL.touch_scan_ctrl.touch_scan_pad_map &= ~(BIT(TOUCH_DENOISE_CHANNEL)); @@ -476,7 +476,7 @@ esp_err_t touch_pad_denoise_enable() return ESP_OK; } -esp_err_t touch_pad_denoise_disable() +esp_err_t touch_pad_denoise_disable(void) { RTC_TOUCH_ENTER_CRITICAL(); RTCCNTL.touch_scan_ctrl.touch_denoise_en = 0; @@ -532,7 +532,7 @@ esp_err_t touch_pad_waterproof_get_config(touch_pad_waterproof_t *waterproof) return ESP_OK; } -esp_err_t touch_pad_waterproof_enable() +esp_err_t touch_pad_waterproof_enable(void) { touch_pad_io_init(TOUCH_SHIELD_CHANNEL); RTC_TOUCH_ENTER_CRITICAL(); @@ -542,7 +542,7 @@ esp_err_t touch_pad_waterproof_enable() return ESP_OK; } -esp_err_t touch_pad_waterproof_disable() +esp_err_t touch_pad_waterproof_disable(void) { RTC_TOUCH_ENTER_CRITICAL(); RTCCNTL.touch_scan_ctrl.touch_shield_pad_en = 0; @@ -671,4 +671,4 @@ esp_err_t touch_pad_get_wakeup_status(touch_pad_t *pad_num) return ESP_ERR_INVALID_ARG; } return ESP_OK; -} \ No newline at end of file +} diff --git a/components/driver/include/driver/rtc_io.h b/components/driver/include/driver/rtc_io.h index 0f1fe8f65b..73ede43419 100644 --- a/components/driver/include/driver/rtc_io.h +++ b/components/driver/include/driver/rtc_io.h @@ -340,7 +340,7 @@ esp_err_t rtc_gpio_sleep_mode_disable(gpio_num_t gpio_num); * Force hold signal is enabled before going into deep sleep for pins which * are used for EXT1 wakeup. */ -esp_err_t rtc_gpio_force_hold_all(); +esp_err_t rtc_gpio_force_hold_all(void); #endif #ifdef __cplusplus diff --git a/components/driver/include/driver/touch_pad.h b/components/driver/include/driver/touch_pad.h index e9338467ba..0382c6a5ce 100644 --- a/components/driver/include/driver/touch_pad.h +++ b/components/driver/include/driver/touch_pad.h @@ -732,14 +732,14 @@ esp_err_t touch_pad_filter_delete(void); * @return * - ESP_OK on success */ -esp_err_t touch_pad_fsm_start(); +esp_err_t touch_pad_fsm_start(void); /** * @brief Stop touch sensor FSM. * @return * - ESP_OK on success */ -esp_err_t touch_pad_fsm_stop(); +esp_err_t touch_pad_fsm_stop(void); /** * @brief Set touch sensor measurement and sleep time @@ -859,7 +859,7 @@ esp_err_t touch_pad_config(touch_pad_t touch_num); * @return * - ESP_OK Success */ -esp_err_t touch_pad_reset(); +esp_err_t touch_pad_reset(void); /** * @brief Check touch sensor measurement status. @@ -878,7 +878,7 @@ bool touch_pad_meas_is_done(void); * @return * - touch channel number */ -touch_pad_t touch_pad_get_scan_curr(); +touch_pad_t touch_pad_get_scan_curr(void); /** * @brief Get the touch sensor interrupt status mask. usually used in ISR to decide interrupt type. @@ -886,7 +886,7 @@ touch_pad_t touch_pad_get_scan_curr(); * @return * - touch intrrupt bit */ -uint32_t touch_pad_intr_status_get_mask(); +uint32_t touch_pad_intr_status_get_mask(void); /** * @brief Enable touch sensor interrupt. @@ -984,7 +984,7 @@ esp_err_t touch_pad_filter_get_config(touch_filter_config_t *filter_info); * @return * - ESP_OK Success */ -esp_err_t touch_pad_filter_enable(); +esp_err_t touch_pad_filter_enable(void); /** * @brief diaable touch sensor filter and detection algorithm. @@ -992,7 +992,7 @@ esp_err_t touch_pad_filter_enable(); * @return * - ESP_OK Success */ -esp_err_t touch_pad_filter_disable(); +esp_err_t touch_pad_filter_disable(void); /** * @brief set parameter of denoise pad (TOUCH_PAD_NUM0). @@ -1025,14 +1025,14 @@ esp_err_t touch_pad_denoise_get_config(touch_pad_denoise_t *denoise); * @return * - ESP_OK Success */ -esp_err_t touch_pad_denoise_enable(); +esp_err_t touch_pad_denoise_enable(void); /** * @brief disable denoise function. * @return * - ESP_OK Success */ -esp_err_t touch_pad_denoise_disable(); +esp_err_t touch_pad_denoise_disable(void); /** * @brief get denoise measure value (TOUCH_PAD_NUM0). @@ -1073,7 +1073,7 @@ esp_err_t touch_pad_waterproof_get_config(touch_pad_waterproof_t *waterproof); * @return * - ESP_OK Success */ -esp_err_t touch_pad_waterproof_enable(); +esp_err_t touch_pad_waterproof_enable(void); /** * @brief Enable parameter of waterproof function. @@ -1085,7 +1085,7 @@ esp_err_t touch_pad_waterproof_enable(); * @return * - ESP_OK Success */ -esp_err_t touch_pad_waterproof_disable(); +esp_err_t touch_pad_waterproof_disable(void); /** * @brief Set parameter of proximity channel. Three proximity sensing channels can be set. diff --git a/components/esp32s2beta/brownout.c b/components/esp32s2beta/brownout.c index 8b5ccdacec..5257e1820c 100644 --- a/components/esp32s2beta/brownout.c +++ b/components/esp32s2beta/brownout.c @@ -31,7 +31,7 @@ #define BROWNOUT_DET_LVL 0 #endif //CONFIG_ESP32S2_BROWNOUT_DET_LVL -static void rtc_brownout_isr_handler() +static void rtc_brownout_isr_handler(void *arg) { /* Normally RTC ISR clears the interrupt flag after the application-supplied * handler returns. Since restart is called here, the flag needs to be @@ -46,7 +46,7 @@ static void rtc_brownout_isr_handler() esp_restart_noos(); } -void esp_brownout_init() +void esp_brownout_init(void) { // TODO: implement brownout threshold configuration for esp32s2beta - IDF-751 diff --git a/components/esp32s2beta/cache_err_int.c b/components/esp32s2beta/cache_err_int.c index 235ee73be1..2b263cc275 100644 --- a/components/esp32s2beta/cache_err_int.c +++ b/components/esp32s2beta/cache_err_int.c @@ -32,7 +32,7 @@ #include "sdkconfig.h" #include "esp32s2beta/dport_access.h" -void esp_cache_err_int_init() +void esp_cache_err_int_init(void) { uint32_t core_id = xPortGetCoreID(); ESP_INTR_DISABLE(ETS_CACHEERR_INUM); @@ -64,7 +64,7 @@ void esp_cache_err_int_init() ESP_INTR_ENABLE(ETS_CACHEERR_INUM); } -int IRAM_ATTR esp_cache_err_get_cpuid() +int IRAM_ATTR esp_cache_err_get_cpuid(void) { return PRO_CPU_NUM; } diff --git a/components/esp32s2beta/clk.c b/components/esp32s2beta/clk.c index fb078195d0..1b58527ad6 100644 --- a/components/esp32s2beta/clk.c +++ b/components/esp32s2beta/clk.c @@ -169,7 +169,7 @@ static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk) esp_clk_slowclk_cal_set(cal_val); } -void rtc_clk_select_rtc_slow_clk() +void rtc_clk_select_rtc_slow_clk(void) { select_rtc_slow_clk(RTC_SLOW_FREQ_32K_XTAL); } diff --git a/components/esp32s2beta/cpu_start.c b/components/esp32s2beta/cpu_start.c index 38c78a9e48..7fdb0f47fe 100644 --- a/components/esp32s2beta/cpu_start.c +++ b/components/esp32s2beta/cpu_start.c @@ -106,7 +106,7 @@ static bool s_spiram_okay=true; * and the app CPU is in reset. We do have a stack, so we can do the initialization in C. */ -void IRAM_ATTR call_start_cpu0() +void IRAM_ATTR call_start_cpu0(void) { RESET_REASON rst_reas; @@ -347,7 +347,7 @@ void start_cpu0_default(void) } #ifdef CONFIG_COMPILER_CXX_EXCEPTIONS -size_t __cxx_eh_arena_size_get() +size_t __cxx_eh_arena_size_get(void) { return CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE; } diff --git a/components/esp32s2beta/crosscore_int.c b/components/esp32s2beta/crosscore_int.c index 66d6c4db92..86282cf8be 100644 --- a/components/esp32s2beta/crosscore_int.c +++ b/components/esp32s2beta/crosscore_int.c @@ -46,7 +46,7 @@ static volatile uint32_t reason[ portNUM_PROCESSORS ]; ToDo: There is a small chance the CPU already has yielded when this ISR is serviced. In that case, it's running the intended task but the ISR will cause it to switch _away_ from it. portYIELD_FROM_ISR will probably just schedule the task again, but have to check that. */ -static inline void IRAM_ATTR esp_crosscore_isr_handle_yield() +static inline void IRAM_ATTR esp_crosscore_isr_handle_yield(void) { portYIELD_FROM_ISR(); } @@ -82,7 +82,7 @@ static void IRAM_ATTR esp_crosscore_isr(void *arg) { //Initialize the crosscore interrupt on this core. Call this once //on each active core. -void esp_crosscore_int_init() { +void esp_crosscore_int_init(void) { portENTER_CRITICAL(&reason_spinlock); reason[xPortGetCoreID()]=0; portEXIT_CRITICAL(&reason_spinlock); diff --git a/components/esp32s2beta/esp_clk_internal.h b/components/esp32s2beta/esp_clk_internal.h index 53af81c284..f1f8964573 100644 --- a/components/esp32s2beta/esp_clk_internal.h +++ b/components/esp32s2beta/esp_clk_internal.h @@ -41,4 +41,4 @@ void esp_perip_clk_init(void); /* Selects an external clock source (32 kHz) for RTC. * Only internal use in unit test. */ -void rtc_clk_select_rtc_slow_clk(); +void rtc_clk_select_rtc_slow_clk(void); diff --git a/components/esp32s2beta/esp_timer_esp32s2beta.c b/components/esp32s2beta/esp_timer_esp32s2beta.c index fcf005ebfc..ff01cfe70a 100644 --- a/components/esp32s2beta/esp_timer_esp32s2beta.c +++ b/components/esp32s2beta/esp_timer_esp32s2beta.c @@ -151,7 +151,7 @@ portMUX_TYPE s_time_update_lock = portMUX_INITIALIZER_UNLOCKED; #define TIMER_IS_AFTER_OVERFLOW(a) (ALARM_OVERFLOW_VAL < (a) && (a) <= FRC_TIMER_LOAD_VALUE(1)) // Check if timer overflow has happened (but was not handled by ISR yet) -static inline bool IRAM_ATTR timer_overflow_happened() +static inline bool IRAM_ATTR timer_overflow_happened(void) { if (s_overflow_happened) { return true; @@ -177,17 +177,17 @@ static inline void IRAM_ATTR timer_count_reload(void) REG_WRITE(FRC_TIMER_LOAD_REG(1), REG_READ(FRC_TIMER_COUNT_REG(1)) - ALARM_OVERFLOW_VAL); } -void esp_timer_impl_lock() +void esp_timer_impl_lock(void) { portENTER_CRITICAL(&s_time_update_lock); } -void esp_timer_impl_unlock() +void esp_timer_impl_unlock(void) { portEXIT_CRITICAL(&s_time_update_lock); } -uint64_t IRAM_ATTR esp_timer_impl_get_time() +uint64_t IRAM_ATTR esp_timer_impl_get_time(void) { uint32_t timer_val; uint64_t time_base; @@ -372,7 +372,7 @@ esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler) return ESP_OK; } -void esp_timer_impl_deinit() +void esp_timer_impl_deinit(void) { esp_intr_disable(s_timer_interrupt_handle); @@ -387,13 +387,13 @@ void esp_timer_impl_deinit() // FIXME: This value is safe for 80MHz APB frequency. // Should be modified to depend on clock frequency. -uint64_t IRAM_ATTR esp_timer_impl_get_min_period_us() +uint64_t IRAM_ATTR esp_timer_impl_get_min_period_us(void) { return 50; } #ifdef ESP_TIMER_DYNAMIC_OVERFLOW_VAL -uint32_t esp_timer_impl_get_overflow_val() +uint32_t esp_timer_impl_get_overflow_val(void) { return s_alarm_overflow_val; } diff --git a/components/esp32s2beta/include/esp32s2beta/brownout.h b/components/esp32s2beta/include/esp32s2beta/brownout.h index 5a0b1aec00..dafba8dd79 100644 --- a/components/esp32s2beta/include/esp32s2beta/brownout.h +++ b/components/esp32s2beta/include/esp32s2beta/brownout.h @@ -16,6 +16,6 @@ #ifndef __ESP_BROWNOUT_H #define __ESP_BROWNOUT_H -void esp_brownout_init(); +void esp_brownout_init(void); #endif \ No newline at end of file diff --git a/components/esp32s2beta/include/esp32s2beta/cache_err_int.h b/components/esp32s2beta/include/esp32s2beta/cache_err_int.h index bcbd63e799..8881291a2d 100644 --- a/components/esp32s2beta/include/esp32s2beta/cache_err_int.h +++ b/components/esp32s2beta/include/esp32s2beta/cache_err_int.h @@ -20,7 +20,7 @@ * to interrupt input number ETS_CACHEERR_INUM (see soc/soc.h). It is called * from the startup code. */ -void esp_cache_err_int_init(); +void esp_cache_err_int_init(void); /** @@ -30,4 +30,4 @@ void esp_cache_err_int_init(); * - APP_CPU_NUM, if APP_CPU has caused cache IA interrupt * - (-1) otherwise */ -int esp_cache_err_get_cpuid(); +int esp_cache_err_get_cpuid(void); diff --git a/components/esp32s2beta/include/esp32s2beta/clk.h b/components/esp32s2beta/include/esp32s2beta/clk.h index 6526aa9272..06ada586bd 100644 --- a/components/esp32s2beta/include/esp32s2beta/clk.h +++ b/components/esp32s2beta/include/esp32s2beta/clk.h @@ -28,7 +28,7 @@ * * @return the calibration value obtained using rtc_clk_cal, at startup time */ -uint32_t esp_clk_slowclk_cal_get(); +uint32_t esp_clk_slowclk_cal_get(void); /** * @brief Update the calibration value of RTC slow clock @@ -72,4 +72,4 @@ int esp_clk_apb_freq(void); * * @return Value or RTC counter, expressed in microseconds */ -uint64_t esp_clk_rtc_time(); +uint64_t esp_clk_rtc_time(void); diff --git a/components/esp32s2beta/include/esp32s2beta/spiram.h b/components/esp32s2beta/include/esp32s2beta/spiram.h index e623eacb97..3ca4e3fa17 100644 --- a/components/esp32s2beta/include/esp32s2beta/spiram.h +++ b/components/esp32s2beta/include/esp32s2beta/spiram.h @@ -26,7 +26,7 @@ * * @return ESP_OK on success */ -esp_err_t esp_spiram_init(); +esp_err_t esp_spiram_init(void); /** * @brief Configure Cache/MMU for access to external SPI RAM. @@ -37,7 +37,7 @@ esp_err_t esp_spiram_init(); * * @attention this function must be called with flash cache disabled. */ -void esp_spiram_init_cache(); +void esp_spiram_init_cache(void); /** @@ -48,13 +48,13 @@ void esp_spiram_init_cache(); * * @return true on success, false on failed memory test */ -bool esp_spiram_test(); +bool esp_spiram_test(void); /** * @brief Add the initialized SPI RAM to the heap allocator. */ -esp_err_t esp_spiram_add_to_heapalloc(); +esp_err_t esp_spiram_add_to_heapalloc(void); /** @@ -62,7 +62,7 @@ esp_err_t esp_spiram_add_to_heapalloc(); * * @return Size in bytes, or 0 if no external RAM chip support compiled in. */ -size_t esp_spiram_get_size(); +size_t esp_spiram_get_size(void); /** @@ -72,7 +72,7 @@ size_t esp_spiram_get_size(); * * This is meant for use from within the SPI flash code. */ -void esp_spiram_writeback_cache(); +void esp_spiram_writeback_cache(void); diff --git a/components/esp32s2beta/include/esp_clk.h b/components/esp32s2beta/include/esp_clk.h index 6526aa9272..06ada586bd 100644 --- a/components/esp32s2beta/include/esp_clk.h +++ b/components/esp32s2beta/include/esp_clk.h @@ -28,7 +28,7 @@ * * @return the calibration value obtained using rtc_clk_cal, at startup time */ -uint32_t esp_clk_slowclk_cal_get(); +uint32_t esp_clk_slowclk_cal_get(void); /** * @brief Update the calibration value of RTC slow clock @@ -72,4 +72,4 @@ int esp_clk_apb_freq(void); * * @return Value or RTC counter, expressed in microseconds */ -uint64_t esp_clk_rtc_time(); +uint64_t esp_clk_rtc_time(void); diff --git a/components/esp32s2beta/include/esp_intr_alloc.h b/components/esp32s2beta/include/esp_intr_alloc.h index 688a2d7496..784e1ba0e3 100644 --- a/components/esp32s2beta/include/esp_intr_alloc.h +++ b/components/esp32s2beta/include/esp_intr_alloc.h @@ -281,13 +281,13 @@ esp_err_t esp_intr_set_in_iram(intr_handle_t handle, bool is_in_iram); /** * @brief Disable interrupts that aren't specifically marked as running from IRAM */ -void esp_intr_noniram_disable(); +void esp_intr_noniram_disable(void); /** * @brief Re-enable interrupts disabled by esp_intr_noniram_disable */ -void esp_intr_noniram_enable(); +void esp_intr_noniram_enable(void); /**@}*/ diff --git a/components/esp32s2beta/include/esp_sleep.h b/components/esp32s2beta/include/esp_sleep.h index 8e50c7e20a..fabdfe5020 100644 --- a/components/esp32s2beta/include/esp_sleep.h +++ b/components/esp32s2beta/include/esp_sleep.h @@ -94,7 +94,7 @@ esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source); * - ESP_OK on success * - ESP_ERR_INVALID_STATE if ULP co-processor is not enabled or if wakeup triggers conflict */ -esp_err_t esp_sleep_enable_ulp_wakeup(); +esp_err_t esp_sleep_enable_ulp_wakeup(void); /** * @brief Enable wakeup by timer @@ -120,7 +120,7 @@ esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us); * - ESP_OK on success * - ESP_ERR_INVALID_STATE if wakeup triggers conflict */ -esp_err_t esp_sleep_enable_touchpad_wakeup(); +esp_err_t esp_sleep_enable_touchpad_wakeup(void); /** * @brief Get the touch pad which caused wakeup @@ -129,7 +129,7 @@ esp_err_t esp_sleep_enable_touchpad_wakeup(); * * @return touch pad which caused wakeup */ -touch_pad_t esp_sleep_get_touchpad_wakeup_status(); +touch_pad_t esp_sleep_get_touchpad_wakeup_status(void); /** * @brief Enable wakeup using a pin @@ -197,7 +197,7 @@ esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t mask, esp_sleep_ext1_wakeup_mode * * @return bit mask, if GPIOn caused wakeup, BIT(n) will be set */ -uint64_t esp_sleep_get_ext1_wakeup_status(); +uint64_t esp_sleep_get_ext1_wakeup_status(void); /** * @brief Set power down mode for an RTC power domain in sleep mode @@ -218,7 +218,7 @@ esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain, * * This function does not return. */ -void esp_deep_sleep_start() __attribute__((noreturn)); +void esp_deep_sleep_start(void) __attribute__((noreturn)); /** * @brief Enter light sleep with the configured wakeup options @@ -227,7 +227,7 @@ void esp_deep_sleep_start() __attribute__((noreturn)); * - ESP_OK on success (returned after wakeup) * - ESP_ERR_INVALID_STATE if WiFi or BT is not stopped */ -esp_err_t esp_light_sleep_start(); +esp_err_t esp_light_sleep_start(void); /** * @brief Enter deep-sleep mode @@ -269,7 +269,7 @@ void system_deep_sleep(uint64_t time_in_us) __attribute__((noreturn, deprecated) * * @return wakeup cause, or ESP_DEEP_SLEEP_WAKEUP_UNDEFINED if reset happened for reason other than deep sleep wakeup */ -esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(); +esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(void); /** diff --git a/components/esp32s2beta/include/esp_spiram.h b/components/esp32s2beta/include/esp_spiram.h index 9663dcddcb..2c3a37eacc 100644 --- a/components/esp32s2beta/include/esp_spiram.h +++ b/components/esp32s2beta/include/esp_spiram.h @@ -25,7 +25,7 @@ * * @return ESP_OK on success */ -esp_err_t esp_spiram_init(); +esp_err_t esp_spiram_init(void); /** * @brief Configure Cache/MMU for access to external SPI RAM. @@ -36,7 +36,7 @@ esp_err_t esp_spiram_init(); * * @attention this function must be called with flash cache disabled. */ -void esp_spiram_init_cache(); +void esp_spiram_init_cache(void); /** @@ -47,13 +47,13 @@ void esp_spiram_init_cache(); * * @return true on success, false on failed memory test */ -bool esp_spiram_test(); +bool esp_spiram_test(void); /** * @brief Add the initialized SPI RAM to the heap allocator. */ -esp_err_t esp_spiram_add_to_heapalloc(); +esp_err_t esp_spiram_add_to_heapalloc(void); /** @@ -61,7 +61,7 @@ esp_err_t esp_spiram_add_to_heapalloc(); * * @return Size in bytes, or 0 if no external RAM chip support compiled in. */ -size_t esp_spiram_get_size(); +size_t esp_spiram_get_size(void); /** @@ -71,7 +71,7 @@ size_t esp_spiram_get_size(); * * This is meant for use from within the SPI flash code. */ -void esp_spiram_writeback_cache(); +void esp_spiram_writeback_cache(void); diff --git a/components/esp32s2beta/int_wdt.c b/components/esp32s2beta/int_wdt.c index e1c13300e6..2515962db3 100644 --- a/components/esp32s2beta/int_wdt.c +++ b/components/esp32s2beta/int_wdt.c @@ -70,7 +70,7 @@ static void IRAM_ATTR tick_hook(void) { #endif -void esp_int_wdt_init() { +void esp_int_wdt_init(void) { periph_module_enable(PERIPH_TIMG1_MODULE); TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; TIMERG1.wdt_config0.sys_reset_length=7; //3.2uS @@ -90,7 +90,7 @@ void esp_int_wdt_init() { timer_group_intr_enable(TIMER_GROUP_1, TIMG_WDT_INT_ENA_M); } -void esp_int_wdt_cpu_init() +void esp_int_wdt_cpu_init(void) { esp_register_freertos_tick_hook_for_cpu(tick_hook, xPortGetCoreID()); ESP_INTR_DISABLE(WDT_INT_NUM); diff --git a/components/esp32s2beta/intr_alloc.c b/components/esp32s2beta/intr_alloc.c index 78b7c776b4..534e4cb0b0 100644 --- a/components/esp32s2beta/intr_alloc.c +++ b/components/esp32s2beta/intr_alloc.c @@ -841,7 +841,7 @@ esp_err_t IRAM_ATTR esp_intr_disable(intr_handle_t handle) } -void IRAM_ATTR esp_intr_noniram_disable() +void IRAM_ATTR esp_intr_noniram_disable(void) { int oldint; int cpu=xPortGetCoreID(); @@ -860,7 +860,7 @@ void IRAM_ATTR esp_intr_noniram_disable() non_iram_int_disabled[cpu]=oldint&non_iram_int_mask[cpu]; } -void IRAM_ATTR esp_intr_noniram_enable() +void IRAM_ATTR esp_intr_noniram_enable(void) { int cpu=xPortGetCoreID(); int intmask=non_iram_int_disabled[cpu]; diff --git a/components/esp32s2beta/panic.c b/components/esp32s2beta/panic.c index d432daed6b..b98cc05822 100644 --- a/components/esp32s2beta/panic.c +++ b/components/esp32s2beta/panic.c @@ -125,7 +125,7 @@ void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, s static bool abort_called; -static __attribute__((noreturn)) inline void invoke_abort() +static __attribute__((noreturn)) inline void invoke_abort(void) { abort_called = true; #if CONFIG_ESP32_APPTRACE_ENABLE @@ -144,7 +144,7 @@ static __attribute__((noreturn)) inline void invoke_abort() } } -void abort() +void abort(void) { #if !CONFIG_ESP32S2_PANIC_SILENT_REBOOT ets_printf("abort() was called at PC 0x%08x on core %d\r\n", (intptr_t)__builtin_return_address(0) - 3, xPortGetCoreID()); @@ -169,11 +169,11 @@ static const char *edesc[] = { #define NUM_EDESCS (sizeof(edesc) / sizeof(char *)) static void commonErrorHandler(XtExcFrame *frame); -static inline void disableAllWdts(); +static inline void disableAllWdts(void); //The fact that we've panic'ed probably means the other CPU is now running wild, possibly //messing up the serial output, so we stall it here. -static void haltOtherCore() +static void haltOtherCore(void) { esp_cpu_stall( xPortGetCoreID() == 0 ? 1 : 0 ); } @@ -349,7 +349,7 @@ void xt_unhandled_exception(XtExcFrame *frame) all watchdogs except the timer group 0 watchdog, and it reconfigures that to reset the chip after one second. */ -static void reconfigureAllWdts() +static void reconfigureAllWdts(void) { TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE; TIMERG0.wdt_feed = 1; @@ -369,7 +369,7 @@ static void reconfigureAllWdts() /* This disables all the watchdogs for when we call the gdbstub. */ -static inline void disableAllWdts() +static inline void disableAllWdts(void) { TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE; TIMERG0.wdt_config0.en = 0; @@ -379,7 +379,7 @@ static inline void disableAllWdts() TIMERG1.wdt_wprotect = 0; } -static void esp_panic_wdt_start() +static void esp_panic_wdt_start(void) { if (REG_GET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN)) { return; @@ -396,7 +396,7 @@ static void esp_panic_wdt_start() WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0); } -void esp_panic_wdt_stop() +void esp_panic_wdt_stop(void) { WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE); WRITE_PERI_REG(RTC_CNTL_WDTFEED_REG, 1); @@ -405,9 +405,9 @@ void esp_panic_wdt_stop() WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0); } -static void esp_panic_dig_reset() __attribute__((noreturn)); +static void esp_panic_dig_reset(void) __attribute__((noreturn)); -static void esp_panic_dig_reset() +static void esp_panic_dig_reset(void) { // make sure all the panic handler output is sent from UART FIFO uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); diff --git a/components/esp32s2beta/pm_esp32s2beta.c b/components/esp32s2beta/pm_esp32s2beta.c index 3646e24ff9..e3e5180af5 100644 --- a/components/esp32s2beta/pm_esp32s2beta.c +++ b/components/esp32s2beta/pm_esp32s2beta.c @@ -146,9 +146,9 @@ static const char* s_mode_names[] = { static const char* TAG = "pm_esp32"; -static void update_ccompare(); +static void update_ccompare(void); static void do_switch(pm_mode_t new_mode); -static void leave_idle(); +static void leave_idle(void); static void on_freq_update(uint32_t old_ticks_per_us, uint32_t ticks_per_us); @@ -242,7 +242,7 @@ esp_err_t esp_pm_configure(const void* vconfig) return ESP_OK; } -static pm_mode_t IRAM_ATTR get_lowest_allowed_mode() +static pm_mode_t IRAM_ATTR get_lowest_allowed_mode(void) { /* TODO: optimize using ffs/clz */ if (s_mode_mask >= BIT(PM_MODE_CPU_MAX)) { @@ -413,7 +413,7 @@ static void IRAM_ATTR do_switch(pm_mode_t new_mode) * would happen without the frequency change. * Assumes that the new_frequency = old_frequency * s_ccount_mul / s_ccount_div. */ -static void IRAM_ATTR update_ccompare() +static void IRAM_ATTR update_ccompare(void) { uint32_t ccount = XTHAL_GET_CCOUNT(); uint32_t ccompare = XTHAL_GET_CCOMPARE(XT_TIMER_INDEX); @@ -427,7 +427,7 @@ static void IRAM_ATTR update_ccompare() } } -static void IRAM_ATTR leave_idle() +static void IRAM_ATTR leave_idle(void) { int core_id = xPortGetCoreID(); if (s_core_idle[core_id]) { @@ -437,7 +437,7 @@ static void IRAM_ATTR leave_idle() } } -void esp_pm_impl_idle_hook() +void esp_pm_impl_idle_hook(void) { int core_id = xPortGetCoreID(); uint32_t state = portENTER_CRITICAL_NESTED(); @@ -449,7 +449,7 @@ void esp_pm_impl_idle_hook() ESP_PM_TRACE_ENTER(IDLE, core_id); } -void esp_pm_impl_waiti() +void esp_pm_impl_waiti(void) { #if CONFIG_FREERTOS_USE_TICKLESS_IDLE int core_id = xPortGetCoreID(); @@ -467,7 +467,7 @@ void esp_pm_impl_waiti() #endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE } -void IRAM_ATTR esp_pm_impl_isr_hook() +void IRAM_ATTR esp_pm_impl_isr_hook(void) { int core_id = xPortGetCoreID(); ESP_PM_TRACE_ENTER(ISR_HOOK, core_id); @@ -563,7 +563,7 @@ void esp_pm_impl_dump_stats(FILE* out) } #endif // WITH_PROFILING -void esp_pm_impl_init() +void esp_pm_impl_init(void) { s_cpu_freq_to_ticks[RTC_CPU_FREQ_XTAL] = rtc_clk_xtal_freq_get(); #ifdef CONFIG_PM_TRACE diff --git a/components/esp32s2beta/pm_trace.c b/components/esp32s2beta/pm_trace.c index b4cebf85fe..cad2e40e2d 100644 --- a/components/esp32s2beta/pm_trace.c +++ b/components/esp32s2beta/pm_trace.c @@ -30,7 +30,7 @@ static const int DRAM_ATTR s_trace_io[] = { BIT(27), BIT(27), // ESP_PM_TRACE_SLEEP }; -void esp_pm_trace_init() +void esp_pm_trace_init(void) { for (size_t i = 0; i < sizeof(s_trace_io)/sizeof(s_trace_io[0]); ++i) { int io = __builtin_ffs(s_trace_io[i]); diff --git a/components/esp32s2beta/sleep_modes.c b/components/esp32s2beta/sleep_modes.c index b6f6c79adb..5e723f755c 100644 --- a/components/esp32s2beta/sleep_modes.c +++ b/components/esp32s2beta/sleep_modes.c @@ -87,10 +87,10 @@ static _lock_t lock_rtc_memory_crc; static const char* TAG = "sleep"; -static uint32_t get_power_down_flags(); -static void ext0_wakeup_prepare(); -static void ext1_wakeup_prepare(); -static void timer_wakeup_prepare(); +static uint32_t get_power_down_flags(void); +static void ext0_wakeup_prepare(void); +static void ext1_wakeup_prepare(void); +static void timer_wakeup_prepare(void); /* Wake from deep sleep stub See esp_deepsleep.h esp_wake_deep_sleep() comments for details. @@ -133,7 +133,7 @@ void esp_deep_sleep(uint64_t time_in_us) esp_deep_sleep_start(); } -static void IRAM_ATTR suspend_uarts() +static void IRAM_ATTR suspend_uarts(void) { for (int i = 0; i < 2; ++i) { REG_SET_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XOFF); @@ -141,7 +141,7 @@ static void IRAM_ATTR suspend_uarts() } } -static void IRAM_ATTR resume_uarts() +static void IRAM_ATTR resume_uarts(void) { for (int i = 0; i < 2; ++i) { REG_CLR_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XOFF); @@ -192,7 +192,7 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags) return result; } -void IRAM_ATTR esp_deep_sleep_start() +void IRAM_ATTR esp_deep_sleep_start(void) { // record current RTC time s_config.rtc_ticks_at_sleep_start = rtc_time_get(); @@ -230,7 +230,7 @@ static void rtc_wdt_enable(int time_ms) WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0); } -static void rtc_wdt_disable() +static void rtc_wdt_disable(void) { WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE); WRITE_PERI_REG(RTC_CNTL_WDTFEED_REG, 1); @@ -268,7 +268,7 @@ static esp_err_t esp_light_sleep_inner(uint32_t pd_flags, return err; } -esp_err_t esp_light_sleep_start() +esp_err_t esp_light_sleep_start(void) { static portMUX_TYPE light_sleep_lock = portMUX_INITIALIZER_UNLOCKED; portENTER_CRITICAL(&light_sleep_lock); @@ -367,7 +367,7 @@ esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source) return ESP_OK; } -esp_err_t esp_sleep_enable_ulp_wakeup() +esp_err_t esp_sleep_enable_ulp_wakeup(void) { return ESP_ERR_NOT_SUPPORTED; } @@ -379,7 +379,7 @@ esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us) return ESP_OK; } -static void timer_wakeup_prepare() +static void timer_wakeup_prepare(void) { uint32_t period = esp_clk_slowclk_cal_get(); int64_t sleep_duration = (int64_t) s_config.sleep_duration - (int64_t) s_config.sleep_time_adjustment; @@ -391,7 +391,7 @@ static void timer_wakeup_prepare() rtc_sleep_set_wakeup_time(s_config.rtc_ticks_at_sleep_start + rtc_count_delta); } -esp_err_t esp_sleep_enable_touchpad_wakeup() +esp_err_t esp_sleep_enable_touchpad_wakeup(void) { if (s_config.wakeup_triggers & (RTC_EXT0_TRIG_EN)) { ESP_LOGE(TAG, "Conflicting wake-up trigger: ext0"); @@ -401,7 +401,7 @@ esp_err_t esp_sleep_enable_touchpad_wakeup() return ESP_OK; } -touch_pad_t esp_sleep_get_touchpad_wakeup_status() +touch_pad_t esp_sleep_get_touchpad_wakeup_status(void) { if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_TOUCHPAD) { return TOUCH_PAD_MAX; @@ -430,7 +430,7 @@ esp_err_t esp_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level) return ESP_OK; } -static void ext0_wakeup_prepare() +static void ext0_wakeup_prepare(void) { int rtc_gpio_num = s_config.ext0_rtc_gpio_num; // Set GPIO to be used for wakeup @@ -472,7 +472,7 @@ esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t mask, esp_sleep_ext1_wakeup_mode return ESP_OK; } -static void ext1_wakeup_prepare() +static void ext1_wakeup_prepare(void) { // Configure all RTC IOs selected as ext1 wakeup inputs uint32_t rtc_gpio_mask = s_config.ext1_rtc_gpio_mask; @@ -508,7 +508,7 @@ static void ext1_wakeup_prepare() s_config.ext1_trigger_mode, RTC_CNTL_EXT_WAKEUP1_LV_S); } -uint64_t esp_sleep_get_ext1_wakeup_status() +uint64_t esp_sleep_get_ext1_wakeup_status(void) { if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_EXT1) { return 0; @@ -529,7 +529,7 @@ uint64_t esp_sleep_get_ext1_wakeup_status() return gpio_mask; } -esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause() +esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(void) { if (rtc_get_reset_reason(0) != DEEPSLEEP_RESET) { return ESP_SLEEP_WAKEUP_UNDEFINED; @@ -561,7 +561,7 @@ esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain, return ESP_OK; } -static uint32_t get_power_down_flags() +static uint32_t get_power_down_flags(void) { // Where needed, convert AUTO options to ON. Later interpret AUTO as OFF. diff --git a/components/esp32s2beta/spiram.c b/components/esp32s2beta/spiram.c index 9cd3c6ba4f..693ab702f1 100644 --- a/components/esp32s2beta/spiram.c +++ b/components/esp32s2beta/spiram.c @@ -68,7 +68,7 @@ static bool spiram_inited=false; true when RAM seems OK, false when test fails. WARNING: Do not run this before the 2nd cpu has been initialized (in a two-core system) or after the heap allocator has taken ownership of the memory. */ -bool esp_spiram_test() +bool esp_spiram_test(void) { volatile int *spiram=(volatile int*)(SOC_EXTRAM_DATA_HIGH - CONFIG_SPIRAM_SIZE); size_t p; @@ -128,7 +128,7 @@ bool esp_spiram_test() #define SPIRAM_MID_BIG_SIZE_MAP_SIZE DRAM0_DRAM1_DPORT_DBUS3_CACHE_SIZE -void IRAM_ATTR esp_spiram_init_cache() +void IRAM_ATTR esp_spiram_init_cache(void) { Cache_Suspend_DCache(); /* map the address from SPIRAM end to the start, map the address in order: DRAM1, DRAM1, DPORT, DBUS3 */ @@ -175,12 +175,12 @@ static uint32_t page0_page = 0xffff; static uint32_t instrcution_in_spiram = 0; static uint32_t rodata_in_spiram = 0; -uint32_t esp_spiram_instruction_access_enabled() +uint32_t esp_spiram_instruction_access_enabled(void) { return instrcution_in_spiram; } -uint32_t esp_spiram_rodata_access_enabled() +uint32_t esp_spiram_rodata_access_enabled(void) { return rodata_in_spiram; } @@ -233,7 +233,7 @@ esp_err_t esp_spiram_enable_rodata_access(void) return ESP_OK; } -esp_err_t esp_spiram_init() +esp_err_t esp_spiram_init(void) { esp_err_t r; r = psram_enable(PSRAM_SPEED, PSRAM_MODE); @@ -256,7 +256,7 @@ esp_err_t esp_spiram_init() } -esp_err_t esp_spiram_add_to_heapalloc() +esp_err_t esp_spiram_add_to_heapalloc(void) { uint32_t size_for_flash = (pages_for_flash << 16); ESP_EARLY_LOGI(TAG, "Adding pool of %dK of external SPI memory to heap allocator", (CONFIG_SPIRAM_SIZE - (pages_for_flash << 16))/1024); @@ -319,7 +319,7 @@ esp_err_t esp_spiram_reserve_dma_pool(size_t size) { return heap_caps_add_region_with_caps(caps, (intptr_t) dma_heap, (intptr_t) dma_heap+size-1); } -size_t esp_spiram_get_size() +size_t esp_spiram_get_size(void) { return CONFIG_SPIRAM_SIZE; } @@ -328,7 +328,7 @@ size_t esp_spiram_get_size() Before flushing the cache, if psram is enabled as a memory-mapped thing, we need to write back the data in the cache to the psram first, otherwise it will get lost. For now, we just read 64/128K of random PSRAM memory to do this. */ -void IRAM_ATTR esp_spiram_writeback_cache() +void IRAM_ATTR esp_spiram_writeback_cache(void) { extern void Cache_WriteBack_All(void); int cache_was_disabled=0; diff --git a/components/esp32s2beta/spiram_psram.c b/components/esp32s2beta/spiram_psram.c index 01168cc6a5..1aa036d105 100644 --- a/components/esp32s2beta/spiram_psram.c +++ b/components/esp32s2beta/spiram_psram.c @@ -698,7 +698,7 @@ static void IRAM_ATTR psram_gpio_config(psram_cache_mode_t mode) PIN_FUNC_SELECT(PERIPHS_IO_MUX_SPICLK_U, FUNC_SPICLK_SPICLK); } -psram_size_t psram_get_size() +psram_size_t psram_get_size(void) { if (PSRAM_IS_32MBIT_VER0(s_psram_id)) { return PSRAM_SIZE_32MBITS; diff --git a/components/esp32s2beta/spiram_psram.h b/components/esp32s2beta/spiram_psram.h index aef1b8d217..53d6500ff9 100644 --- a/components/esp32s2beta/spiram_psram.h +++ b/components/esp32s2beta/spiram_psram.h @@ -53,7 +53,7 @@ typedef enum { * - PSRAM_SIZE_MAX if psram not enabled or not valid * - PSRAM size */ -psram_size_t psram_get_size(); +psram_size_t psram_get_size(void); /** * @brief psram cache enable function diff --git a/components/esp32s2beta/system_api.c b/components/esp32s2beta/system_api.c index 457c4fa68d..c27b9bebfc 100644 --- a/components/esp32s2beta/system_api.c +++ b/components/esp32s2beta/system_api.c @@ -44,7 +44,7 @@ static uint8_t base_mac_addr[6] = { 0 }; #define SHUTDOWN_HANDLERS_NO 2 static shutdown_handler_t shutdown_handlers[SHUTDOWN_HANDLERS_NO]; -void system_init() +void system_init(void) { } @@ -227,7 +227,7 @@ esp_err_t esp_unregister_shutdown_handler(shutdown_handler_t handler) return ESP_ERR_INVALID_STATE; } -void esp_restart_noos() __attribute__ ((noreturn)); +void esp_restart_noos(void) __attribute__ ((noreturn)); void IRAM_ATTR esp_restart(void) { @@ -248,7 +248,7 @@ void IRAM_ATTR esp_restart(void) * core are already stopped. Stalls other core, resets hardware, * triggers restart. */ -void IRAM_ATTR esp_restart_noos() +void IRAM_ATTR esp_restart_noos(void) { // Disable interrupts xt_ints_off(0xFFFFFFFF); diff --git a/components/esp32s2beta/task_wdt.c b/components/esp32s2beta/task_wdt.c index b73a308832..d432112541 100644 --- a/components/esp32s2beta/task_wdt.c +++ b/components/esp32s2beta/task_wdt.c @@ -102,7 +102,7 @@ static twdt_task_t *find_task_in_twdt_list(TaskHandle_t handle, bool *all_reset) * Resets the hardware timer and has_reset flags of each task on the list. * Called within critical */ -static void reset_hw_timer() +static void reset_hw_timer(void) { //All tasks have reset; time to reset the hardware timer. TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; @@ -214,7 +214,7 @@ esp_err_t esp_task_wdt_init(uint32_t timeout, bool panic) return ESP_OK; } -esp_err_t esp_task_wdt_deinit() +esp_err_t esp_task_wdt_deinit(void) { portENTER_CRITICAL(&twdt_spinlock); //TWDT must already be initialized @@ -282,7 +282,7 @@ esp_err_t esp_task_wdt_add(TaskHandle_t handle) return ESP_OK; } -esp_err_t esp_task_wdt_reset() +esp_err_t esp_task_wdt_reset(void) { portENTER_CRITICAL(&twdt_spinlock); //TWDT must already be initialized @@ -370,7 +370,7 @@ esp_err_t esp_task_wdt_status(TaskHandle_t handle) return ESP_ERR_NOT_FOUND; } -void esp_task_wdt_feed() +void esp_task_wdt_feed(void) { portENTER_CRITICAL(&twdt_spinlock); //Return immediately if TWDT has not been initialized diff --git a/components/esp_rom/include/esp32s2beta/rom/cache.h b/components/esp_rom/include/esp32s2beta/rom/cache.h index 234ec3d08c..666053b36c 100644 --- a/components/esp_rom/include/esp32s2beta/rom/cache.h +++ b/components/esp_rom/include/esp32s2beta/rom/cache.h @@ -798,7 +798,7 @@ void Cache_Resume_DCache(uint32_t autoload); * * @return None */ -void Cache_Drom0_Source_ICache(); +void Cache_Drom0_Source_ICache(void); /** * @brief Make Drom0 bus access from DCache. @@ -807,7 +807,7 @@ void Cache_Drom0_Source_ICache(); * * @return None */ -void Cache_Drom0_Source_DCache(); +void Cache_Drom0_Source_DCache(void); /** * @brief Return if Drom0 bus access from ICache. @@ -816,7 +816,7 @@ void Cache_Drom0_Source_DCache(); * * @return uint32_t: 0 for no, other for yes */ -uint32_t Cache_Drom0_Using_ICache(); +uint32_t Cache_Drom0_Using_ICache(void); /** * @brief Return if Drom0 bus access from DCache. @@ -825,7 +825,7 @@ uint32_t Cache_Drom0_Using_ICache(); * * @return uint32_t: 0 for no, other for yes */ -uint32_t Cache_Drom0_Using_DCache(); +uint32_t Cache_Drom0_Using_DCache(void); /** * @brief Get ICache cache line size @@ -834,7 +834,7 @@ uint32_t Cache_Drom0_Using_DCache(); * * @return uint32_t: 16, 32, 64 Byte */ -uint32_t Cache_Get_ICache_Line_Size(); +uint32_t Cache_Get_ICache_Line_Size(void); /** * @brief Get DCache cache line size @@ -843,7 +843,7 @@ uint32_t Cache_Get_ICache_Line_Size(); * * @return uint32_t: 16, 32, 64 Byte */ -uint32_t Cache_Get_DCache_Line_Size(); +uint32_t Cache_Get_DCache_Line_Size(void); /** * @brief Set default mode from boot. diff --git a/components/esp_rom/include/esp32s2beta/rom/spi_flash.h b/components/esp_rom/include/esp32s2beta/rom/spi_flash.h index 120c0fb0ac..130e1cac7c 100644 --- a/components/esp_rom/include/esp32s2beta/rom/spi_flash.h +++ b/components/esp_rom/include/esp32s2beta/rom/spi_flash.h @@ -511,8 +511,8 @@ typedef esp_rom_spiflash_result_t SpiFlashOpResult; SpiFlashOpResult SPI_Encrypt_Write(uint32_t flash_addr, const void* data, uint32_t len); SpiFlashOpResult SPI_Encrypt_Write_Dest(SpiEncryptDest dest, uint32_t flash_addr, const void* data, uint32_t len); -void SPI_Write_Encrypt_Enable(); -void SPI_Write_Encrypt_Disable(); +void SPI_Write_Encrypt_Enable(void); +void SPI_Write_Encrypt_Disable(void); /** @brief Wait until SPI flash write operation is complete * diff --git a/components/esp_rom/include/esp32s2beta/rom/tbconsole.h b/components/esp_rom/include/esp32s2beta/rom/tbconsole.h index 891c2732a5..d6ca069cc7 100644 --- a/components/esp_rom/include/esp32s2beta/rom/tbconsole.h +++ b/components/esp_rom/include/esp32s2beta/rom/tbconsole.h @@ -18,7 +18,7 @@ extern "C" { #endif -void start_tb_console(); +void start_tb_console(void); #ifdef __cplusplus } diff --git a/components/soc/esp32s2beta/cpu_util.c b/components/soc/esp32s2beta/cpu_util.c index dad897d897..ab45ab3b26 100644 --- a/components/soc/esp32s2beta/cpu_util.c +++ b/components/soc/esp32s2beta/cpu_util.c @@ -50,7 +50,7 @@ void IRAM_ATTR esp_cpu_reset(int cpu_id) cpu_id == 0 ? RTC_CNTL_SW_PROCPU_RST_M : RTC_CNTL_SW_APPCPU_RST_M); } -bool IRAM_ATTR esp_cpu_in_ocd_debug_mode() +bool IRAM_ATTR esp_cpu_in_ocd_debug_mode(void) { #if CONFIG_ESP32S2_DEBUG_OCDAWARE int dcr; diff --git a/components/soc/esp32s2beta/include/soc/cpu.h b/components/soc/esp32s2beta/include/soc/cpu.h index 95d7c0dec2..fdde8c91a3 100644 --- a/components/soc/esp32s2beta/include/soc/cpu.h +++ b/components/soc/esp32s2beta/include/soc/cpu.h @@ -29,7 +29,7 @@ /** @brief Read current stack pointer address * */ -static inline void *get_sp() +static inline void *get_sp(void) { void *sp; asm volatile ("mov %0, sp;" : "=r" (sp)); @@ -51,7 +51,7 @@ static inline void cpu_write_itlb(unsigned vpn, unsigned attr) asm volatile ("witlb %1, %0; isync\n" :: "r" (vpn), "r" (attr)); } -static inline void cpu_init_memctl() +static inline void cpu_init_memctl(void) { #if XCHAL_ERRATUM_572 #error "Shouldn't have this errata or need this call on esp32s2beta" @@ -69,7 +69,7 @@ static inline void cpu_init_memctl() * 15 — no access, raise exception */ -static inline void cpu_configure_region_protection() +static inline void cpu_configure_region_protection(void) { const uint32_t pages_to_protect[] = {0x00000000, 0x80000000, 0xa0000000, 0xc0000000, 0xe0000000}; for (int i = 0; i < sizeof(pages_to_protect)/sizeof(pages_to_protect[0]); ++i) { @@ -106,7 +106,7 @@ void esp_cpu_reset(int cpu_id); * @note If "Make exception and panic handlers JTAG/OCD aware" * is disabled, this function always returns false. */ -bool esp_cpu_in_ocd_debug_mode(); +bool esp_cpu_in_ocd_debug_mode(void); /** * @brief Convert the PC register value to its true address diff --git a/components/soc/esp32s2beta/include/soc/rtc.h b/components/soc/esp32s2beta/include/soc/rtc.h index 5f1d6f226a..73d7f4b5d0 100644 --- a/components/soc/esp32s2beta/include/soc/rtc.h +++ b/components/soc/esp32s2beta/include/soc/rtc.h @@ -163,7 +163,7 @@ void rtc_clk_init(rtc_clk_config_t cfg); * * @return XTAL frequency, one of rtc_xtal_freq_t */ -rtc_xtal_freq_t rtc_clk_xtal_freq_get(); +rtc_xtal_freq_t rtc_clk_xtal_freq_get(void); /** * @brief Update XTAL frequency @@ -185,7 +185,7 @@ void rtc_clk_32k_enable(bool en); * @brief Get the state of 32k XTAL oscillator * @return true if 32k XTAL oscillator has been enabled */ -bool rtc_clk_32k_enabled(); +bool rtc_clk_32k_enabled(void); /** * @brief Enable 32k oscillator, configuring it for fast startup time. @@ -221,13 +221,13 @@ void rtc_clk_8m_enable(bool clk_8m_en, bool d256_en); * @brief Get the state of 8 MHz internal oscillator * @return true if the oscillator is enabled */ -bool rtc_clk_8m_enabled(); +bool rtc_clk_8m_enabled(void); /** * @brief Get the state of /256 divider which is applied to 8MHz clock * @return true if the divided output is enabled */ -bool rtc_clk_8md256_enabled(); +bool rtc_clk_8md256_enabled(void); /** * @brief Enable or disable APLL @@ -257,7 +257,7 @@ void rtc_clk_slow_freq_set(rtc_slow_freq_t slow_freq); * @brief Get the RTC_SLOW_CLK source * @return currently selected clock source (one of rtc_slow_freq_t values) */ -rtc_slow_freq_t rtc_clk_slow_freq_get(); +rtc_slow_freq_t rtc_clk_slow_freq_get(void); /** * @brief Get the approximate frequency of RTC_SLOW_CLK, in Hz @@ -271,7 +271,7 @@ rtc_slow_freq_t rtc_clk_slow_freq_get(); * * @return RTC_SLOW_CLK frequency, in Hz */ -uint32_t rtc_clk_slow_freq_get_hz(); +uint32_t rtc_clk_slow_freq_get_hz(void); /** * @brief Select source for RTC_FAST_CLK @@ -283,7 +283,7 @@ void rtc_clk_fast_freq_set(rtc_fast_freq_t fast_freq); * @brief Get the RTC_FAST_CLK source * @return currently selected clock source (one of rtc_fast_freq_t values) */ -rtc_fast_freq_t rtc_clk_fast_freq_get(); +rtc_fast_freq_t rtc_clk_fast_freq_get(void); /** * @brief Switch CPU frequency @@ -327,7 +327,7 @@ void rtc_clk_cpu_freq_set_fast(rtc_cpu_freq_t cpu_freq); * * @return CPU frequency (one of rtc_cpu_freq_t values) */ -rtc_cpu_freq_t rtc_clk_cpu_freq_get(); +rtc_cpu_freq_t rtc_clk_cpu_freq_get(void); /** * @brief Get corresponding frequency value for rtc_cpu_freq_t enum value @@ -362,7 +362,7 @@ void rtc_clk_apb_freq_update(uint32_t apb_freq); * @brief Get the current stored APB frequency. * @return The APB frequency value as last set via rtc_clk_apb_freq_update(), in Hz. */ -uint32_t rtc_clk_apb_freq_get(); +uint32_t rtc_clk_apb_freq_get(void); #define RTC_CLK_CAL_FRACT 19 //!< Number of fractional bits in values returned by rtc_clk_cal @@ -421,11 +421,11 @@ uint64_t rtc_time_slowclk_to_us(uint64_t rtc_cycles, uint32_t period); * * @return current value of RTC counter */ -uint64_t rtc_time_get(); +uint64_t rtc_time_get(void); -uint64_t rtc_light_slp_time_get(); +uint64_t rtc_light_slp_time_get(void); -uint64_t rtc_deep_slp_time_get(); +uint64_t rtc_deep_slp_time_get(void); /** * @brief Busy loop until next RTC_SLOW_CLK cycle @@ -434,7 +434,7 @@ uint64_t rtc_deep_slp_time_get(); * In some cases (e.g. when RTC_SLOW_CLK cycle is very close), it may return * one RTC_SLOW_CLK cycle later. */ -void rtc_clk_wait_for_slow_cycle(); +void rtc_clk_wait_for_slow_cycle(void); /** * @brief Power down flags for rtc_sleep_pd function @@ -647,7 +647,7 @@ typedef struct { * Otherwise, use default values and the level of MTDI bootstrapping pin. * @return currently used VDDSDIO configuration */ -rtc_vddsdio_config_t rtc_vddsdio_get_config(); +rtc_vddsdio_config_t rtc_vddsdio_get_config(void); /** * Set new VDDSDIO configuration using RTC registers. diff --git a/components/soc/esp32s2beta/rtc_clk.c b/components/soc/esp32s2beta/rtc_clk.c index 1d7e0a6fb1..cdbf7d0fd8 100644 --- a/components/soc/esp32s2beta/rtc_clk.c +++ b/components/soc/esp32s2beta/rtc_clk.c @@ -176,7 +176,7 @@ void rtc_clk_32k_bootstrap(uint32_t cycle) CLEAR_PERI_REG_MASK(DPORT_BT_LPCK_DIV_FRAC_REG, DPORT_LPCLK_RTC_EN); } -bool rtc_clk_32k_enabled() +bool rtc_clk_32k_enabled(void) { uint32_t xtal_conf = READ_PERI_REG(RTC_CNTL_EXT_XTL_CONF_REG); /* If xtal xpd is controlled by software */ @@ -211,12 +211,12 @@ void rtc_clk_8m_enable(bool clk_8m_en, bool d256_en) } } -bool rtc_clk_8m_enabled() +bool rtc_clk_8m_enabled(void) { return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M) == 0; } -bool rtc_clk_8md256_enabled() +bool rtc_clk_8md256_enabled(void) { return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV) == 0; } @@ -278,12 +278,12 @@ void rtc_clk_slow_freq_set(rtc_slow_freq_t slow_freq) ets_delay_us(DELAY_SLOW_CLK_SWITCH); } -rtc_slow_freq_t rtc_clk_slow_freq_get() +rtc_slow_freq_t rtc_clk_slow_freq_get(void) { return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL); } -uint32_t rtc_clk_slow_freq_get_hz() +uint32_t rtc_clk_slow_freq_get_hz(void) { switch(rtc_clk_slow_freq_get()) { case RTC_SLOW_FREQ_RTC: return RTC_SLOW_CLK_FREQ_150K; @@ -299,7 +299,7 @@ void rtc_clk_fast_freq_set(rtc_fast_freq_t fast_freq) ets_delay_us(DELAY_FAST_CLK_SWITCH); } -rtc_fast_freq_t rtc_clk_fast_freq_get() +rtc_fast_freq_t rtc_clk_fast_freq_get(void) { return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL); } @@ -446,7 +446,7 @@ void rtc_clk_bbpll_set(rtc_xtal_freq_t xtal_freq, rtc_pll_t pll_freq) /** * Switch to XTAL frequency. Does not disable the PLL. */ -static void rtc_clk_cpu_freq_to_xtal() +static void rtc_clk_cpu_freq_to_xtal(void) { rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get(); ets_update_cpu_frequency(xtal_freq); @@ -586,7 +586,7 @@ void rtc_clk_cpu_freq_set(rtc_cpu_freq_t cpu_freq) s_cur_freq = cpu_freq; } -rtc_cpu_freq_t rtc_clk_cpu_freq_get() +rtc_cpu_freq_t rtc_clk_cpu_freq_get(void) { uint32_t soc_clk_sel = REG_GET_FIELD(SYSCON_SYSCLK_CONF_REG, SYSCON_SOC_CLK_SEL); switch (soc_clk_sel) { @@ -681,7 +681,7 @@ static uint32_t clk_val_to_reg_val(uint32_t val) { return (val & UINT16_MAX) | ((val & UINT16_MAX) << 16); } -rtc_xtal_freq_t rtc_clk_xtal_freq_get() +rtc_xtal_freq_t rtc_clk_xtal_freq_get(void) { /* We may have already written XTAL value into RTC_XTAL_FREQ_REG */ uint32_t xtal_freq_reg = READ_PERI_REG(RTC_XTAL_FREQ_REG); @@ -697,7 +697,7 @@ void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq) WRITE_PERI_REG(RTC_XTAL_FREQ_REG, clk_val_to_reg_val(xtal_freq)); } -static rtc_xtal_freq_t rtc_clk_xtal_freq_estimate() +static rtc_xtal_freq_t rtc_clk_xtal_freq_estimate(void) { /* Enable 8M/256 clock if needed */ const bool clk_8m_enabled = rtc_clk_8m_enabled(); @@ -738,7 +738,7 @@ void rtc_clk_apb_freq_update(uint32_t apb_freq) WRITE_PERI_REG(RTC_APB_FREQ_REG, clk_val_to_reg_val(apb_freq >> 12)); } -uint32_t rtc_clk_apb_freq_get() +uint32_t rtc_clk_apb_freq_get(void) { uint32_t freq_hz = reg_val_to_clk_val(READ_PERI_REG(RTC_APB_FREQ_REG)) << 12; // round to the nearest MHz @@ -848,4 +848,4 @@ void rtc_clk_init(rtc_clk_config_t cfg) /* Name used in libphy.a:phy_chip_v7.o * TODO: update the library to use rtc_clk_xtal_freq_get */ -rtc_xtal_freq_t rtc_get_xtal() __attribute__((alias("rtc_clk_xtal_freq_get"))); +rtc_xtal_freq_t rtc_get_xtal(void) __attribute__((alias("rtc_clk_xtal_freq_get"))); diff --git a/components/soc/esp32s2beta/rtc_init.c b/components/soc/esp32s2beta/rtc_init.c index fa8385d277..cd10e5972d 100644 --- a/components/soc/esp32s2beta/rtc_init.c +++ b/components/soc/esp32s2beta/rtc_init.c @@ -184,7 +184,7 @@ void rtc_init(rtc_config_t cfg) } #endif -rtc_vddsdio_config_t rtc_vddsdio_get_config() +rtc_vddsdio_config_t rtc_vddsdio_get_config(void) { rtc_vddsdio_config_t result; uint32_t sdio_conf_reg = REG_READ(RTC_CNTL_SDIO_CONF_REG); diff --git a/components/soc/esp32s2beta/rtc_pm.c b/components/soc/esp32s2beta/rtc_pm.c index e6dae04351..2f63dc8beb 100644 --- a/components/soc/esp32s2beta/rtc_pm.c +++ b/components/soc/esp32s2beta/rtc_pm.c @@ -31,14 +31,14 @@ typedef enum{ /* These MAC-related functions are defined in the closed source part of * RTC library */ -extern void pm_mac_init(); -extern int pm_check_mac_idle(); -extern void pm_mac_deinit(); +extern void pm_mac_init(void); +extern int pm_check_mac_idle(void); +extern void pm_mac_deinit(void); /* This sleep-related function is called from the closed source part of RTC * library. */ -pm_sw_reject_t pm_set_sleep_mode(pm_sleep_mode_t sleep_mode, void(*pmac_save_params)()) +pm_sw_reject_t pm_set_sleep_mode(pm_sleep_mode_t sleep_mode, void(*pmac_save_params)(void)) { (void) pmac_save_params; /* unused */ diff --git a/components/soc/esp32s2beta/rtc_time.c b/components/soc/esp32s2beta/rtc_time.c index e276341f29..e6d0e139d7 100644 --- a/components/soc/esp32s2beta/rtc_time.c +++ b/components/soc/esp32s2beta/rtc_time.c @@ -126,7 +126,7 @@ uint64_t rtc_time_slowclk_to_us(uint64_t rtc_cycles, uint32_t period) return (rtc_cycles * period) >> RTC_CLK_CAL_FRACT; } -uint64_t rtc_time_get() +uint64_t rtc_time_get(void) { SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE); while (GET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_VALID) == 0) { @@ -138,7 +138,7 @@ uint64_t rtc_time_get() return t; } -uint64_t rtc_light_slp_time_get() +uint64_t rtc_light_slp_time_get(void) { uint64_t t_wake = READ_PERI_REG(RTC_CNTL_TIME_LOW0_REG); t_wake |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME_HIGH0_REG)) << 32; @@ -147,7 +147,7 @@ uint64_t rtc_light_slp_time_get() return (t_wake - t_slp); } -uint64_t rtc_deep_slp_time_get() +uint64_t rtc_deep_slp_time_get(void) { uint64_t t_slp = READ_PERI_REG(RTC_CNTL_TIME_LOW1_REG); t_slp |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME_HIGH1_REG)) << 32; @@ -155,7 +155,7 @@ uint64_t rtc_deep_slp_time_get() return (t_wake - t_slp); } -void rtc_clk_wait_for_slow_cycle() //This function may not by useful any more +void rtc_clk_wait_for_slow_cycle(void) //This function may not by useful any more { SET_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_SLOW_CLK_NEXT_EDGE); while (GET_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_SLOW_CLK_NEXT_EDGE)) { diff --git a/components/soc/esp32s2beta/test/test_rtc_clk.c b/components/soc/esp32s2beta/test/test_rtc_clk.c index dd99bfcbeb..23a9bfe8f4 100644 --- a/components/soc/esp32s2beta/test/test_rtc_clk.c +++ b/components/soc/esp32s2beta/test/test_rtc_clk.c @@ -137,7 +137,7 @@ TEST_CASE("Test fast switching between PLL and XTAL", "[rtc_clk]") #define COUNT_TEST 3 #define TIMEOUT_TEST_MS (5 + CONFIG_ESP32_RTC_CLK_CAL_CYCLES / 16) -void stop_rtc_external_quartz(){ +void stop_rtc_external_quartz(void){ const uint8_t pin_32 = 32; const uint8_t pin_33 = 33; const uint8_t mask_32 = (1 << (pin_32 - 32)); diff --git a/components/spi_flash/esp32/flash_ops_esp32.c b/components/spi_flash/esp32/flash_ops_esp32.c index 71f9b3dab8..77c90c95c0 100644 --- a/components/spi_flash/esp32/flash_ops_esp32.c +++ b/components/spi_flash/esp32/flash_ops_esp32.c @@ -16,7 +16,7 @@ #include "esp32/rom/spi_flash.h" #include "esp32/rom/cache.h" -static inline void IRAM_ATTR spi_flash_guard_start() +static inline void IRAM_ATTR spi_flash_guard_start(void) { const spi_flash_guard_funcs_t *ops = spi_flash_guard_get(); if (ops && ops->start) { @@ -24,7 +24,7 @@ static inline void IRAM_ATTR spi_flash_guard_start() } } -static inline void IRAM_ATTR spi_flash_guard_end() +static inline void IRAM_ATTR spi_flash_guard_end(void) { const spi_flash_guard_funcs_t *ops = spi_flash_guard_get(); if (ops && ops->end) { diff --git a/examples/peripherals/temp_sensor_esp32s2/main/temp_sensor_main.c b/examples/peripherals/temp_sensor_esp32s2/main/temp_sensor_main.c index 70ede5d9a5..32e3bd40e7 100644 --- a/examples/peripherals/temp_sensor_esp32s2/main/temp_sensor_main.c +++ b/examples/peripherals/temp_sensor_esp32s2/main/temp_sensor_main.c @@ -39,14 +39,14 @@ void tempsensor_example(void *arg) vTaskDelete(NULL); } -void app_main() +void app_main(void) { xTaskCreate(tempsensor_example, "temp", 2048, NULL, 5, NULL); } #elif CONFIG_IDF_TARGET_ESP32 -void app_main() +void app_main(void) { printf("ESP32 don't support temperature sensor\n"); } diff --git a/examples/peripherals/touch_pad_interrupt/main/esp32s2beta/tp_interrupt_main.c b/examples/peripherals/touch_pad_interrupt/main/esp32s2beta/tp_interrupt_main.c index a65be4d01c..9d3b1041e0 100644 --- a/examples/peripherals/touch_pad_interrupt/main/esp32s2beta/tp_interrupt_main.c +++ b/examples/peripherals/touch_pad_interrupt/main/esp32s2beta/tp_interrupt_main.c @@ -147,7 +147,7 @@ static void tp_example_read_task(void *pvParameter) } } -void app_main() +void app_main(void) { if (que_touch == NULL) { que_touch = xQueueCreate(TOUCH_BUTTON_NUM, sizeof(touch_event_t)); diff --git a/examples/peripherals/touch_pad_read/main/esp32s2beta/tp_read_main.c b/examples/peripherals/touch_pad_read/main/esp32s2beta/tp_read_main.c index 890a2426a0..d1b2bc97d3 100644 --- a/examples/peripherals/touch_pad_read/main/esp32s2beta/tp_read_main.c +++ b/examples/peripherals/touch_pad_read/main/esp32s2beta/tp_read_main.c @@ -54,7 +54,7 @@ static void tp_example_read_task(void *pvParameter) } } -void app_main() +void app_main(void) { /* Initialize touch pad peripheral. */ touch_pad_init(); @@ -79,4 +79,4 @@ void app_main() /* Start task to read values by pads. */ xTaskCreate(&tp_example_read_task, "touch_pad_read_task", 2048, NULL, 5, NULL); -} \ No newline at end of file +} From 8111b222c8d244ef79bda6b0c1579016f772bc36 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 12 Aug 2019 12:34:35 +1000 Subject: [PATCH 458/486] bt: Update to match master --- components/bt/controller/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib b/components/bt/controller/lib index cc2fd1177d..717f0c6ec7 160000 --- a/components/bt/controller/lib +++ b/components/bt/controller/lib @@ -1 +1 @@ -Subproject commit cc2fd1177d97f1a4b9e0d819035ddf52ba77079d +Subproject commit 717f0c6ec71a016a0b292acffeacf239d007b8ff From 9a3606781f0d1784f1c9b8bf87b9215fecb447e7 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 12 Aug 2019 12:46:55 +1000 Subject: [PATCH 459/486] ci: Lower limit for number of examples (S2 Beta has 81 right now) --- tools/ci/build_examples_cmake.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci/build_examples_cmake.sh b/tools/ci/build_examples_cmake.sh index cc5f3adc00..fae1bfc87b 100755 --- a/tools/ci/build_examples_cmake.sh +++ b/tools/ci/build_examples_cmake.sh @@ -69,7 +69,7 @@ SDKCONFIG_DEFAULTS_CI=sdkconfig.ci EXAMPLE_PATHS=$( get_supported_examples.sh $IDF_TARGET | sed "s#^#${IDF_PATH}\/examples\/#g" | awk '{print $0"/CmakeLists.txt"}' ) NUM_OF_EXAMPLES=$( echo "${EXAMPLE_PATHS}" | wc -l ) # just a plausibility check -[ ${NUM_OF_EXAMPLES} -lt 100 ] && die "NUM_OF_EXAMPLES is bad" +[ ${NUM_OF_EXAMPLES} -lt 80 ] && die "NUM_OF_EXAMPLES is bad" echo "All examples found for target $IDF_TARGET:" echo $EXAMPLE_PATHS From 9a2e29e0687b936e8616093592aa8b10a7181535 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 12 Aug 2019 16:23:46 +1000 Subject: [PATCH 460/486] esp32s2beta: Invert RSA_CONSTANT_TIME_DISABLE_REG to RSA_CONSTANT_TIME_REG --- components/mbedtls/port/esp32s2beta/esp_bignum.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mbedtls/port/esp32s2beta/esp_bignum.c b/components/mbedtls/port/esp32s2beta/esp_bignum.c index 58fdce67a2..4bad12ccdb 100644 --- a/components/mbedtls/port/esp32s2beta/esp_bignum.c +++ b/components/mbedtls/port/esp32s2beta/esp_bignum.c @@ -372,7 +372,7 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi* Z, const mbedtls_mpi* X, const mbedtls_mpi mpi_to_mem_block(RSA_MEM_RB_BLOCK_BASE, Rinv, num_words); DPORT_REG_WRITE(RSA_M_DASH_REG, Mprime); - DPORT_REG_WRITE(RSA_CONSTANT_TIME_DISABLE_REG, 1); + DPORT_REG_WRITE(RSA_CONSTANT_TIME_REG, 0); DPORT_REG_WRITE(RSA_SEARCH_OPEN_REG, 1); DPORT_REG_WRITE(RSA_SEARCH_POS_REG, (y_words * 32) - 1); From bcff8afbba2326e7e0ac095bd924b58698ce3fca Mon Sep 17 00:00:00 2001 From: Xia Xiaotian Date: Mon, 12 Aug 2019 16:49:54 +0800 Subject: [PATCH 461/486] esp_wifi: update esp32s2beta WiFi library --- components/esp_wifi/lib_esp32s2beta | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib_esp32s2beta b/components/esp_wifi/lib_esp32s2beta index f3442ab1f8..402af2133f 160000 --- a/components/esp_wifi/lib_esp32s2beta +++ b/components/esp_wifi/lib_esp32s2beta @@ -1 +1 @@ -Subproject commit f3442ab1f881dd72cbe23ca76c7e318e26342191 +Subproject commit 402af2133f9588e82aab84fd5c9737caa01a272f From f58d2ea34ddcd3b258314c3f760b0e62760b2bae Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 13 Aug 2019 13:38:37 +1000 Subject: [PATCH 462/486] esp32s2: Add SUPPORTED_TARGETS for remaining bluetooth examples --- .../bluetooth/bluedroid/coex/gattc_gatts_coex/CMakeLists.txt | 1 + .../bluetooth/esp_ble_mesh/ble_mesh_client_model/CMakeLists.txt | 1 + .../esp_ble_mesh/ble_mesh_console/ble_mesh_node/CMakeLists.txt | 1 + .../ble_mesh_console/ble_mesh_provisioner/CMakeLists.txt | 1 + .../ble_mesh_fast_prov_client/CMakeLists.txt | 1 + .../ble_mesh_fast_prov_server/CMakeLists.txt | 1 + examples/bluetooth/esp_ble_mesh/ble_mesh_node/CMakeLists.txt | 1 + .../bluetooth/esp_ble_mesh/ble_mesh_provisioner/CMakeLists.txt | 1 + .../fast_prov_vendor_model/CMakeLists.txt | 1 + .../bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/CMakeLists.txt | 1 + examples/bluetooth/nimble/blecent/CMakeLists.txt | 1 + examples/bluetooth/nimble/blehr/CMakeLists.txt | 1 + examples/bluetooth/nimble/blemesh/CMakeLists.txt | 1 + examples/bluetooth/nimble/bleprph/CMakeLists.txt | 1 + tools/ci/build_examples_cmake.sh | 2 +- 15 files changed, 15 insertions(+), 1 deletion(-) diff --git a/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/CMakeLists.txt b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/CMakeLists.txt index f520a3ae27..7f8c072493 100644 --- a/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/CMakeLists.txt +++ b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/CMakeLists.txt @@ -3,4 +3,5 @@ cmake_minimum_required(VERSION 3.5) include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(SUPPORTED_TARGETS esp32) project(gattc_gatts_coex) diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/CMakeLists.txt index f384288f31..d604182bb5 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/CMakeLists.txt @@ -3,4 +3,5 @@ cmake_minimum_required(VERSION 3.5) include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(SUPPORTED_TARGETS esp32) project(ble_mesh_client_model) diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/CMakeLists.txt index 74361e558c..5e425b2aea 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/CMakeLists.txt @@ -3,4 +3,5 @@ cmake_minimum_required(VERSION 3.5) include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(SUPPORTED_TARGETS esp32) project(ble_mesh_console_node) diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/CMakeLists.txt index 6ce28d7d57..14941a14e5 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/CMakeLists.txt @@ -3,4 +3,5 @@ cmake_minimum_required(VERSION 3.5) include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(SUPPORTED_TARGETS esp32) project(ble_mesh_console_provisioner) diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/CMakeLists.txt index 5f9bd92c1c..fb8272bf31 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/CMakeLists.txt @@ -5,4 +5,5 @@ cmake_minimum_required(VERSION 3.5) set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components) include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(SUPPORTED_TARGETS esp32) project(ble_mesh_fast_prov_client) diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/CMakeLists.txt index 56ef44654e..b16b01c888 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/CMakeLists.txt @@ -5,4 +5,5 @@ cmake_minimum_required(VERSION 3.5) set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components) include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(SUPPORTED_TARGETS esp32) project(ble_mesh_fast_prov_server) diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_node/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_node/CMakeLists.txt index d8b91b1efc..6dd3671530 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_node/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_node/CMakeLists.txt @@ -3,4 +3,5 @@ cmake_minimum_required(VERSION 3.5) include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(SUPPORTED_TARGETS esp32) project(ble_mesh_node) diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/CMakeLists.txt index dfffbf786f..503adacea5 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/CMakeLists.txt @@ -3,4 +3,5 @@ cmake_minimum_required(VERSION 3.5) include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(SUPPORTED_TARGETS esp32) project(ble_mesh_provisioner) diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/CMakeLists.txt index cb92f4b374..9ca35d2569 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/CMakeLists.txt @@ -3,4 +3,5 @@ cmake_minimum_required(VERSION 3.5) include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(SUPPORTED_TARGETS esp32) project(fast_prov_vendor_model) diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/CMakeLists.txt index 8933ca7f25..3d18ee56b9 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/CMakeLists.txt @@ -5,4 +5,5 @@ cmake_minimum_required(VERSION 3.5) set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components) include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(SUPPORTED_TARGETS esp32) project(ble_mesh_wifi_coexist) diff --git a/examples/bluetooth/nimble/blecent/CMakeLists.txt b/examples/bluetooth/nimble/blecent/CMakeLists.txt index b3ac70b41a..4df574b9d5 100644 --- a/examples/bluetooth/nimble/blecent/CMakeLists.txt +++ b/examples/bluetooth/nimble/blecent/CMakeLists.txt @@ -3,4 +3,5 @@ cmake_minimum_required(VERSION 3.5) include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(SUPPORTED_TARGETS esp32) project(blecent) diff --git a/examples/bluetooth/nimble/blehr/CMakeLists.txt b/examples/bluetooth/nimble/blehr/CMakeLists.txt index 62f79f5231..6e02bcff33 100644 --- a/examples/bluetooth/nimble/blehr/CMakeLists.txt +++ b/examples/bluetooth/nimble/blehr/CMakeLists.txt @@ -3,4 +3,5 @@ cmake_minimum_required(VERSION 3.5) include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(SUPPORTED_TARGETS esp32) project(blehr) diff --git a/examples/bluetooth/nimble/blemesh/CMakeLists.txt b/examples/bluetooth/nimble/blemesh/CMakeLists.txt index f022ba3d27..6250e13e12 100644 --- a/examples/bluetooth/nimble/blemesh/CMakeLists.txt +++ b/examples/bluetooth/nimble/blemesh/CMakeLists.txt @@ -3,4 +3,5 @@ cmake_minimum_required(VERSION 3.5) include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(SUPPORTED_TARGETS esp32) project(blemesh) diff --git a/examples/bluetooth/nimble/bleprph/CMakeLists.txt b/examples/bluetooth/nimble/bleprph/CMakeLists.txt index 6e3fbcae38..f400e730be 100644 --- a/examples/bluetooth/nimble/bleprph/CMakeLists.txt +++ b/examples/bluetooth/nimble/bleprph/CMakeLists.txt @@ -3,4 +3,5 @@ cmake_minimum_required(VERSION 3.5) include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(SUPPORTED_TARGETS esp32) project(bleprph) diff --git a/tools/ci/build_examples_cmake.sh b/tools/ci/build_examples_cmake.sh index fae1bfc87b..c1fe9a26aa 100755 --- a/tools/ci/build_examples_cmake.sh +++ b/tools/ci/build_examples_cmake.sh @@ -69,7 +69,7 @@ SDKCONFIG_DEFAULTS_CI=sdkconfig.ci EXAMPLE_PATHS=$( get_supported_examples.sh $IDF_TARGET | sed "s#^#${IDF_PATH}\/examples\/#g" | awk '{print $0"/CmakeLists.txt"}' ) NUM_OF_EXAMPLES=$( echo "${EXAMPLE_PATHS}" | wc -l ) # just a plausibility check -[ ${NUM_OF_EXAMPLES} -lt 80 ] && die "NUM_OF_EXAMPLES is bad" +[ ${NUM_OF_EXAMPLES} -lt 50 ] && die "NUM_OF_EXAMPLES is bad" echo "All examples found for target $IDF_TARGET:" echo $EXAMPLE_PATHS From e32d27e7e8287b485f5aca88969ba508de812ef2 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 13 Aug 2019 15:11:46 +1000 Subject: [PATCH 463/486] esp_eth: Add CONFIG_ETH_ENABLED flag to enable/disable ethernet at build time Always enabled by default, as SPI/Ethernet support is enabled by default. --- components/esp_eth/CMakeLists.txt | 42 ++++++++++++------- components/esp_eth/Kconfig | 9 +++- components/lwip/CMakeLists.txt | 5 ++- components/tcpip_adapter/event_handlers.c | 6 +-- components/tcpip_adapter/tcpip_adapter_lwip.c | 11 ++++- 5 files changed, 51 insertions(+), 22 deletions(-) diff --git a/components/esp_eth/CMakeLists.txt b/components/esp_eth/CMakeLists.txt index 3829df1885..3eb2d02a0c 100644 --- a/components/esp_eth/CMakeLists.txt +++ b/components/esp_eth/CMakeLists.txt @@ -1,20 +1,30 @@ -set(esp_eth_srcs "src/esp_eth.c" - "src/esp_eth_phy_dp83848.c" - "src/esp_eth_phy_ip101.c" - "src/esp_eth_phy_lan8720.c" - "src/esp_eth_phy_rtl8201.c") +set(srcs) # If ethernet disabled in Kconfig, this is a config-only component +set(include) +set(linker) -if(CONFIG_ETH_USE_ESP32_EMAC) - list(APPEND esp_eth_srcs "src/esp_eth_mac_esp32.c") +if(CONFIG_ETH_ENABLED) + set(srcs "src/esp_eth.c") + set(include "include") + set(linker "linker.lf") + + if(CONFIG_ETH_USE_ESP32_EMAC) + list(APPEND srcs "src/esp_eth_mac_esp32.c" + "src/esp_eth_phy_dp83848.c" + "src/esp_eth_phy_ip101.c" + "src/esp_eth_phy_lan8720.c" + "src/esp_eth_phy_rtl8201.c" + ) + endif() + + if(CONFIG_ETH_SPI_ETHERNET_DM9051) + list(APPEND srcs "src/esp_eth_mac_dm9051.c" + "src/esp_eth_phy_dm9051.c") + endif() endif() -if(CONFIG_ETH_SPI_ETHERNET_DM9051) - list(APPEND esp_eth_srcs "src/esp_eth_mac_dm9051.c" - "src/esp_eth_phy_dm9051.c") -endif() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS ${include} + LDFRAGMENTS ${linker} + REQUIRES "esp_event" + PRIV_REQUIRES "tcpip_adapter" "driver" "log") -idf_component_register(SRCS "${esp_eth_srcs}" - INCLUDE_DIRS "include" - LDFRAGMENTS "linker.lf" - REQUIRES "esp_event" - PRIV_REQUIRES "tcpip_adapter" "driver" "log") diff --git a/components/esp_eth/Kconfig b/components/esp_eth/Kconfig index 40e7ee36dc..615b8a2e26 100644 --- a/components/esp_eth/Kconfig +++ b/components/esp_eth/Kconfig @@ -1,9 +1,15 @@ menu "Ethernet" + # Invisible item that is enabled if any Ethernet + # selection is made + config ETH_ENABLED + bool + menuconfig ETH_USE_ESP32_EMAC depends on IDF_TARGET_ESP32 bool "Support ESP32 internal EMAC controller" default y + select ETH_ENABLED help ESP32 integrates a 10/100M Ethernet MAC controller. @@ -132,8 +138,9 @@ menu "Ethernet" menuconfig ETH_USE_SPI_ETHERNET bool "Support SPI to Ethernet Module" default y + select ETH_ENABLED help - ESP-IDF can also support some SPI-Ethernet module. + ESP-IDF can also support some SPI-Ethernet modules. if ETH_USE_SPI_ETHERNET menuconfig ETH_SPI_ETHERNET_DM9051 diff --git a/components/lwip/CMakeLists.txt b/components/lwip/CMakeLists.txt index df4bb7f3aa..f32072ee82 100644 --- a/components/lwip/CMakeLists.txt +++ b/components/lwip/CMakeLists.txt @@ -87,7 +87,6 @@ set(srcs "port/esp32/freertos/sys_arch.c" "port/esp32/netif/dhcp_state.c" "port/esp32/netif/nettestif.c" - "port/esp32/netif/ethernetif.c" "port/esp32/netif/wlanif.c") if(CONFIG_LWIP_PPP_SUPPORT) @@ -124,6 +123,10 @@ if(CONFIG_LWIP_PPP_SUPPORT) "lwip/src/netif/ppp/polarssl/sha1.c") endif() +if(CONFIG_ETH_ENABLED) + list(APPEND srcs "port/esp32/netif/ethernetif.c") +endif() + idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "${include_dirs}" LDFRAGMENTS linker.lf diff --git a/components/tcpip_adapter/event_handlers.c b/components/tcpip_adapter/event_handlers.c index 48b7ccc182..299dc990a0 100644 --- a/components/tcpip_adapter/event_handlers.c +++ b/components/tcpip_adapter/event_handlers.c @@ -17,7 +17,7 @@ #include "esp_event.h" #include "esp_wifi.h" #include "esp_private/wifi.h" -#if CONFIG_IDF_TARGET_ESP32 +#if CONFIG_ETH_ENABLED #include "esp_eth.h" #endif #include "esp_err.h" @@ -43,7 +43,7 @@ static void handle_sta_stop(void *arg, esp_event_base_t base, int32_t event_id, static void handle_sta_connected(void *arg, esp_event_base_t base, int32_t event_id, void *data); static void handle_sta_disconnected(void *arg, esp_event_base_t base, int32_t event_id, void *data); static void handle_sta_got_ip(void *arg, esp_event_base_t base, int32_t event_id, void *data); -#if CONFIG_IDF_TARGET_ESP32 +#if CONFIG_ETH_ENABLED static void handle_eth_start(void *arg, esp_event_base_t base, int32_t event_id, void *data); static void handle_eth_stop(void *arg, esp_event_base_t base, int32_t event_id, void *data); static void handle_eth_connected(void *arg, esp_event_base_t base, int32_t event_id, void *data); @@ -266,7 +266,7 @@ esp_err_t tcpip_adapter_clear_default_wifi_handlers(void) return ESP_OK; } -#if CONFIG_IDF_TARGET_ESP32 +#if CONFIG_ETH_ENABLED esp_err_t tcpip_adapter_set_default_eth_handlers(void) { esp_err_t err; diff --git a/components/tcpip_adapter/tcpip_adapter_lwip.c b/components/tcpip_adapter/tcpip_adapter_lwip.c index 237b082a34..35df8cdcfc 100644 --- a/components/tcpip_adapter/tcpip_adapter_lwip.c +++ b/components/tcpip_adapter/tcpip_adapter_lwip.c @@ -16,7 +16,6 @@ #include #include "tcpip_adapter_internal.h" - #if CONFIG_TCPIP_LWIP #include "lwip/inet.h" @@ -32,7 +31,9 @@ #include "lwip/netif.h" #endif #include "netif/wlanif.h" +#ifdef CONFIG_ETH_ENABLED #include "netif/ethernetif.h" +#endif #include "netif/nettestif.h" #include "dhcpserver/dhcpserver.h" @@ -227,8 +228,12 @@ static esp_err_t tcpip_adapter_start(tcpip_adapter_if_t tcpip_if, uint8_t *mac, esp_err_t tcpip_adapter_eth_start(uint8_t *mac, tcpip_adapter_ip_info_t *ip_info, void *args) { +#ifdef CONFIG_ETH_ENABLED esp_netif_init_fn[TCPIP_ADAPTER_IF_ETH] = ethernetif_init; return tcpip_adapter_start(TCPIP_ADAPTER_IF_ETH, mac, ip_info, args); +#else + return ESP_ERR_NOT_SUPPORTED; +#endif } esp_err_t tcpip_adapter_sta_start(uint8_t *mac, tcpip_adapter_ip_info_t *ip_info) @@ -1115,8 +1120,12 @@ static esp_err_t tcpip_adapter_dhcpc_stop_api(tcpip_adapter_api_msg_t *msg) esp_err_t tcpip_adapter_eth_input(void *buffer, uint16_t len, void *eb) { +#ifdef CONFIG_ETH_ENABLED ethernetif_input(esp_netif[TCPIP_ADAPTER_IF_ETH], buffer, len); return ESP_OK; +#else + return ESP_ERR_NOT_SUPPORTED; +#endif } esp_err_t tcpip_adapter_sta_input(void *buffer, uint16_t len, void *eb) From 85c2df060df05a9300a223bcb7ebe206bb7684fc Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 13 Aug 2019 15:15:32 +1000 Subject: [PATCH 464/486] examples: Mark flash encryption & external flash examples as ESP32 only for now --- examples/security/flash_encryption/CMakeLists.txt | 1 + examples/storage/ext_flash_fatfs/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/examples/security/flash_encryption/CMakeLists.txt b/examples/security/flash_encryption/CMakeLists.txt index 27f6bc4e35..33248e978d 100644 --- a/examples/security/flash_encryption/CMakeLists.txt +++ b/examples/security/flash_encryption/CMakeLists.txt @@ -2,5 +2,6 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.5) +set(SUPPORTED_TARGETS esp32) # Flash encryption not currently supported for ESP32-S2beta include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(flash_encryption) diff --git a/examples/storage/ext_flash_fatfs/CMakeLists.txt b/examples/storage/ext_flash_fatfs/CMakeLists.txt index 51f1129ba3..52b78776cd 100644 --- a/examples/storage/ext_flash_fatfs/CMakeLists.txt +++ b/examples/storage/ext_flash_fatfs/CMakeLists.txt @@ -2,5 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.5) +set(SUPPORTED_TARGETS esp32) # external SPI flash driver not currently supported for ESP32-S2beta include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(ext_flash_fatfs) From a3a67a445272f1b57d3f4073c89ec24f6e42e45b Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 13 Aug 2019 16:05:47 +1000 Subject: [PATCH 465/486] nvs_flash: Include xtensa component when building NVS tests on hosts esp_attr.h moved to xtensa component in 61ce86839638f436a3d7938f411d360c54427f41 --- components/nvs_flash/test_nvs_host/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nvs_flash/test_nvs_host/Makefile b/components/nvs_flash/test_nvs_host/Makefile index d509fd6ee3..717e2c5104 100644 --- a/components/nvs_flash/test_nvs_host/Makefile +++ b/components/nvs_flash/test_nvs_host/Makefile @@ -21,7 +21,7 @@ SOURCE_FILES = \ crc.cpp \ main.cpp -CPPFLAGS += -I../include -I../src -I./ -I../../esp_common/include -I../../esp32/include -I ../../mbedtls/mbedtls/include -I ../../spi_flash/include -I ../../soc/include -I ../../../tools/catch -fprofile-arcs -ftest-coverage +CPPFLAGS += -I../include -I../src -I./ -I../../esp_common/include -I../../esp32/include -I ../../mbedtls/mbedtls/include -I ../../spi_flash/include -I ../../soc/include -I ../../xtensa/include -I ../../../tools/catch -fprofile-arcs -ftest-coverage CFLAGS += -fprofile-arcs -ftest-coverage CXXFLAGS += -std=c++11 -Wall -Werror LDFLAGS += -lstdc++ -Wall -fprofile-arcs -ftest-coverage From 75adefe437f59b9f1a557164c01fcbbdeadb2b90 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Tue, 13 Aug 2019 16:01:50 +0800 Subject: [PATCH 466/486] docs: Alphbetically sort toctree This commit sorts the entries of variuos toctrees alphabetically. Indentation was also fixed. The order of some toctrees were not modified if the existing order had some form of suggested reading order. --- docs/en/api-guides/index.rst | 62 ++++++++++---------- docs/en/api-reference/bluetooth/index.rst | 12 ++-- docs/en/api-reference/index.rst | 20 +++---- docs/en/api-reference/network/index.rst | 10 ++-- docs/en/api-reference/peripherals/index.rst | 40 ++++++------- docs/en/api-reference/protocols/index.rst | 22 +++---- docs/en/api-reference/provisioning/index.rst | 8 +-- docs/en/api-reference/storage/index.rst | 20 +++---- docs/en/api-reference/system/index.rst | 44 +++++++------- 9 files changed, 119 insertions(+), 119 deletions(-) diff --git a/docs/en/api-guides/index.rst b/docs/en/api-guides/index.rst index cc762d3b33..fdfd58c984 100644 --- a/docs/en/api-guides/index.rst +++ b/docs/en/api-guides/index.rst @@ -3,35 +3,35 @@ API Guides :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - General Notes - Build System - Build System (Legacy GNU Make) - Error Handling - Fatal Errors - Event Handling - Deep Sleep Wake Stubs - ESP32 Core Dump - Flash Encryption <../security/flash-encryption> - FreeRTOS SMP Changes - Thread Local Storage - High Level Interrupts - JTAG Debugging - Bootloader - Partition Tables - Secure Boot <../security/secure-boot> - ULP Coprocessor - ULP Coprocessor (Legacy GNU Make) - Unit Testing - Unit Testing (Legacy GNU Make) - Application Level Tracing - Console Component - ROM debug console - RF Calibration - WiFi Driver - ESP-MESH - BluFi - External SPI-connected RAM - Linker Script Generation - Tools + Application Level Tracing + BluFi + Bootloader + Build System + Build System (Legacy GNU Make) + Console Component + Deep Sleep Wake Stubs + Error Handling + ESP-MESH + ESP32 Core Dump + Event Handling + External SPI-connected RAM + Fatal Errors + Flash Encryption <../security/flash-encryption> + FreeRTOS SMP Changes + General Notes + High Level Interrupts + JTAG Debugging + Linker Script Generation + Partition Tables + RF Calibration + ROM debug console + Secure Boot <../security/secure-boot> + Thread Local Storage + Tools + ULP Coprocessor (Legacy GNU Make) + ULP Coprocessor + Unit Testing (Legacy GNU Make) + Unit Testing + WiFi Driver diff --git a/docs/en/api-reference/bluetooth/index.rst b/docs/en/api-reference/bluetooth/index.rst index da9f19d65c..d250083586 100644 --- a/docs/en/api-reference/bluetooth/index.rst +++ b/docs/en/api-reference/bluetooth/index.rst @@ -4,13 +4,13 @@ Bluetooth API :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 2 + :maxdepth: 2 - Bluetooth Controller && VHCI - Bluetooth Common - Bluetooth LE - Bluetooth Classic - NimBLE + Bluetooth Controller && VHCI + Bluetooth Common + Bluetooth LE + Bluetooth Classic + NimBLE ESP-IDF currently supports two host stacks. The Bluedroid based stack (default) supports classic Bluetooth as well as BLE. On the other hand, Apache NimBLE based stack is BLE only. For users to make a choice: * For usecases involving classic Bluetooth as well as BLE, Bluedroid should be used. diff --git a/docs/en/api-reference/index.rst b/docs/en/api-reference/index.rst index a083fe82a2..92e57f8cc8 100644 --- a/docs/en/api-reference/index.rst +++ b/docs/en/api-reference/index.rst @@ -4,15 +4,15 @@ API Reference :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 2 + :maxdepth: 2 - Bluetooth - Networking - Peripherals - Protocols - Provisioning - Storage - System - Configuration Options - Error Codes Reference + Bluetooth + Networking + Peripherals + Protocols + Provisioning + Storage + System + Configuration Options + Error Codes Reference diff --git a/docs/en/api-reference/network/index.rst b/docs/en/api-reference/network/index.rst index f555a456c0..cb5c5801b3 100644 --- a/docs/en/api-reference/network/index.rst +++ b/docs/en/api-reference/network/index.rst @@ -7,12 +7,12 @@ Wi-Fi ===== .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - Wi-Fi - Smart Config - ESP-NOW - ESP Mesh + Wi-Fi + Smart Config + ESP-NOW + ESP Mesh Code examples for the Wi-Fi API are provided in the :example:`wifi` directory of ESP-IDF examples. diff --git a/docs/en/api-reference/peripherals/index.rst b/docs/en/api-reference/peripherals/index.rst index b9b85c2033..73c5b42edf 100644 --- a/docs/en/api-reference/peripherals/index.rst +++ b/docs/en/api-reference/peripherals/index.rst @@ -4,26 +4,26 @@ Peripherals API :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - ADC - CAN - DAC - GPIO (including RTC low power I/O) - I2C - I2S - LED Control - MCPWM - Pulse Counter - Remote Control - SDMMC Host - SD SPI Host - SDIO Slave - Sigma-delta Modulation - SPI Master - SPI Slave - Timer - Touch Sensor - UART + ADC + CAN + DAC + GPIO (including RTC low power I/O) + I2C + I2S + LED Control + MCPWM + Pulse Counter + Remote Control + SD SPI Host + SDIO Slave + SDMMC Host + Sigma-delta Modulation + SPI Master + SPI Slave + Timer + Touch Sensor + UART Code examples for this API section are provided in the :example:`peripherals` directory of ESP-IDF examples. diff --git a/docs/en/api-reference/protocols/index.rst b/docs/en/api-reference/protocols/index.rst index c35c954f35..36af219894 100644 --- a/docs/en/api-reference/protocols/index.rst +++ b/docs/en/api-reference/protocols/index.rst @@ -3,18 +3,18 @@ Application Protocols :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - mDNS - ESP-TLS - HTTP Client - Websocket Client - HTTP Server - HTTPS Server - ASIO - ESP-MQTT - Modbus - Local Control + ASIO + ESP-MQTT + ESP-TLS + HTTP Client + HTTP Server + HTTPS Server + Local Control + mDNS + Modbus + Websocket Client Code examples for this API section are provided in the :example:`protocols` directory of ESP-IDF examples. diff --git a/docs/en/api-reference/provisioning/index.rst b/docs/en/api-reference/provisioning/index.rst index 0243ec19f6..c2341ad73a 100644 --- a/docs/en/api-reference/provisioning/index.rst +++ b/docs/en/api-reference/provisioning/index.rst @@ -4,10 +4,10 @@ Provisioning API :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - Unified Provisioning - Protocol Communication - Wi-Fi Provisioning + Protocol Communication + Unified Provisioning + Wi-Fi Provisioning Code examples for this API section are provided in the :example:`provisioning` directory of ESP-IDF examples. diff --git a/docs/en/api-reference/storage/index.rst b/docs/en/api-reference/storage/index.rst index d80e30b56e..23cb38b647 100644 --- a/docs/en/api-reference/storage/index.rst +++ b/docs/en/api-reference/storage/index.rst @@ -2,17 +2,17 @@ Storage API *********** .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - SPI Flash and Partition APIs - SD/SDIO/MMC Driver - Non-Volatile Storage - NVS Partition Generation Utility - Virtual Filesystem - FAT Filesystem - Wear Levelling - SPIFFS Filesystem - Mass Manufacturing Utility + FAT Filesystem + Mass Manufacturing Utility + Non-Volatile Storage + NVS Partition Generation Utility + SD/SDIO/MMC Driver + SPI Flash and Partition APIs + SPIFFS Filesystem + Virtual Filesystem + Wear Levelling Code examples for this API section are provided in the :example:`storage` directory of ESP-IDF examples. diff --git a/docs/en/api-reference/system/index.rst b/docs/en/api-reference/system/index.rst index 1f2c25940f..8faac3a0b3 100644 --- a/docs/en/api-reference/system/index.rst +++ b/docs/en/api-reference/system/index.rst @@ -2,29 +2,29 @@ System API ********** .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - FreeRTOS - FreeRTOS Additions - Heap Memory Allocation - Heap Memory Debugging - Himem (large external SPI RAM) API - Interrupt Allocation - Watchdogs - eFuse Manager - Inter-Processor Call - High Resolution Timer - Logging - Event Loop Library - Application Level Tracing - Power Management - Sleep Modes - Over The Air Updates (OTA) - ESP HTTPS OTA - ESP pthread - Error Codes and Helper Functions - App image format - Miscellaneous System APIs + App image format + Application Level Tracing + eFuse Manager + Error Codes and Helper Functions + ESP HTTPS OTA + ESP pthread + Event Loop Library + FreeRTOS + FreeRTOS Additions + Heap Memory Allocation + Heap Memory Debugging + High Resolution Timer + Himem (large external SPI RAM) API + Inter-Processor Call + Interrupt Allocation + Logging + Miscellaneous System APIs + Over The Air Updates (OTA) + Power Management + Sleep Modes + Watchdogs Code examples for this API section are provided in the :example:`system` directory of ESP-IDF examples. From 0a74227cfa2d6b3a94c75dc05753f91e7d970c10 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 13 Aug 2019 10:09:52 +0200 Subject: [PATCH 467/486] bump version to 4.1 --- components/esp_common/include/esp_idf_version.h | 2 +- make/version.mk | 2 +- tools/cmake/version.cmake | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/esp_common/include/esp_idf_version.h b/components/esp_common/include/esp_idf_version.h index 52601ca8f6..7f982413c3 100644 --- a/components/esp_common/include/esp_idf_version.h +++ b/components/esp_common/include/esp_idf_version.h @@ -21,7 +21,7 @@ extern "C" { /** Major version number (X.x.x) */ #define ESP_IDF_VERSION_MAJOR 4 /** Minor version number (x.X.x) */ -#define ESP_IDF_VERSION_MINOR 0 +#define ESP_IDF_VERSION_MINOR 1 /** Patch version number (x.x.X) */ #define ESP_IDF_VERSION_PATCH 0 diff --git a/make/version.mk b/make/version.mk index 9dcda422af..ce6d886092 100644 --- a/make/version.mk +++ b/make/version.mk @@ -1,3 +1,3 @@ IDF_VERSION_MAJOR := 4 -IDF_VERSION_MINOR := 0 +IDF_VERSION_MINOR := 1 IDF_VERSION_PATCH := 0 diff --git a/tools/cmake/version.cmake b/tools/cmake/version.cmake index 265ab33b7b..07ce0b5821 100644 --- a/tools/cmake/version.cmake +++ b/tools/cmake/version.cmake @@ -1,3 +1,3 @@ set(IDF_VERSION_MAJOR 4) -set(IDF_VERSION_MINOR 0) +set(IDF_VERSION_MINOR 1) set(IDF_VERSION_PATCH 0) From a001998d5283b29ca9a374adf7cef3357b39a03a Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 20 Jun 2019 17:27:29 +0200 Subject: [PATCH 468/486] mdns: fix missing bye packet if services removed with mdns_service_remove_all() or mdns_free() Closes https://github.com/espressif/esp-idf/issues/3660 --- components/mdns/mdns.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 095651634e..4bf5bce4aa 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -1676,9 +1676,7 @@ static void _mdns_send_final_bye(bool include_ip) size_t srv_count = 0; mdns_srv_item_t * a = _mdns_server->services; while (a) { - if (!a->service->instance) { - srv_count++; - } + srv_count++; a = a->next; } if (!srv_count) { @@ -1688,9 +1686,7 @@ static void _mdns_send_final_bye(bool include_ip) size_t i = 0; a = _mdns_server->services; while (a) { - if (!a->service->instance) { - services[i++] = a; - } + services[i++] = a; a = a->next; } _mdns_send_bye(services, srv_count, include_ip); @@ -1699,7 +1695,7 @@ static void _mdns_send_final_bye(bool include_ip) /** * @brief Stop the responder on all services without instance */ -static void _mdns_send_bye_all_pcbs_no_instance(void) +static void _mdns_send_bye_all_pcbs_no_instance(bool include_ip) { size_t srv_count = 0; mdns_srv_item_t * a = _mdns_server->services; @@ -1721,7 +1717,7 @@ static void _mdns_send_bye_all_pcbs_no_instance(void) } a = a->next; } - _mdns_send_bye(services, srv_count, false); + _mdns_send_bye(services, srv_count, include_ip); } /** @@ -3728,14 +3724,14 @@ static void _mdns_execute_action(mdns_action_t * action) action->data.sys_event.event_id, action->data.sys_event.interface); break; case ACTION_HOSTNAME_SET: - _mdns_send_final_bye(true); + _mdns_send_bye_all_pcbs_no_instance(true); free((char*)_mdns_server->hostname); _mdns_server->hostname = action->data.hostname; _mdns_restart_all_pcbs(); break; case ACTION_INSTANCE_SET: - _mdns_send_bye_all_pcbs_no_instance(); + _mdns_send_bye_all_pcbs_no_instance(false); free((char*)_mdns_server->instance); _mdns_server->instance = action->data.instance; _mdns_restart_all_pcbs_no_instance(); From f8b1ef1b14d9392a8356e7d7ce7667f0f383536f Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 14 Aug 2019 10:21:53 +1000 Subject: [PATCH 469/486] ci: kconfig rules: Allow any file starting with KConfig.* to be sourced --- tools/check_kconfigs.py | 7 ++++--- tools/test_check_kconfigs.py | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tools/check_kconfigs.py b/tools/check_kconfigs.py index bdc3953e46..93754b7055 100755 --- a/tools/check_kconfigs.py +++ b/tools/check_kconfigs.py @@ -94,11 +94,12 @@ class SourceChecker(BaseChecker): raise InputError(self.path_in_idf, line_number, '"source" has to been followed by space', line.replace('source', 'source ')) path = m.group(2) + filename = os.path.basename(path) if path in ['$COMPONENT_KCONFIGS_PROJBUILD', '$COMPONENT_KCONFIGS']: pass - elif not path.endswith('/Kconfig.in') and path != 'Kconfig.in': - raise InputError(self.path_in_idf, line_number, "only Kconfig.in can be sourced", - line.replace(path, os.path.join(os.path.dirname(path), 'Kconfig.in'))) + elif not filename.startswith('Kconfig.'): + raise InputError(self.path_in_idf, line_number, "only filenames starting with Kconfig.* can be sourced", + line.replace(path, os.path.join(os.path.dirname(path), 'Kconfig.' + filename))) class LineRuleChecker(BaseChecker): diff --git a/tools/test_check_kconfigs.py b/tools/test_check_kconfigs.py index a38f16ab91..b8541e4a6d 100755 --- a/tools/test_check_kconfigs.py +++ b/tools/test_check_kconfigs.py @@ -80,10 +80,10 @@ class TestSourceChecker(unittest.TestCase, ApplyLine): pass def test_source_file_name(self): - self.expect_error('source "Kconfig.test"', expect='source "Kconfig.in"') - self.expect_error('source "/tmp/Kconfig.test"', expect='source "/tmp/Kconfig.in"') - self.expect_error('source "Kconfig"', expect='source "Kconfig.in"') + self.expect_error('source "notKconfig.test"', expect='source "Kconfig.notKconfig.test"') + self.expect_error('source "Kconfig"', expect='source "Kconfig.Kconfig"') self.expt_success('source "Kconfig.in"') + self.expt_success('source "/tmp/Kconfig.test"') self.expt_success('source "/tmp/Kconfig.in"') self.expect_error('source"Kconfig.in"', expect='source "Kconfig.in"') self.expt_success('source "/tmp/Kconfig.in" # comment') From 2fcbc6aaa5abd644fd7a5ee2c5dc990e31b44cb3 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 14 Aug 2019 11:57:02 +1000 Subject: [PATCH 470/486] esp_eth: KConfig formatting fix --- components/esp_eth/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/esp_eth/Kconfig b/components/esp_eth/Kconfig index 615b8a2e26..65f42ed60e 100644 --- a/components/esp_eth/Kconfig +++ b/components/esp_eth/Kconfig @@ -1,9 +1,9 @@ menu "Ethernet" - # Invisible item that is enabled if any Ethernet - # selection is made - config ETH_ENABLED - bool + # Invisible item that is enabled if any Ethernet + # selection is made + config ETH_ENABLED + bool menuconfig ETH_USE_ESP32_EMAC depends on IDF_TARGET_ESP32 From 74e2e464029a280e71b71a60394a46b79cb27688 Mon Sep 17 00:00:00 2001 From: chenjianqiang Date: Wed, 14 Aug 2019 20:57:30 +0800 Subject: [PATCH 471/486] bugfix(flash): add spi dio address bitlen configure in psram init --- components/esp32/spiram_psram.c | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esp32/spiram_psram.c b/components/esp32/spiram_psram.c index 1ac19a97dc..a5bd92ded9 100644 --- a/components/esp32/spiram_psram.c +++ b/components/esp32/spiram_psram.c @@ -508,6 +508,7 @@ static void IRAM_ATTR psram_gpio_config(psram_io_t *psram_io, psram_cache_mode_t spi_cache_dummy = SPI0_R_QIO_DUMMY_CYCLELEN; } else if (rd_mode_reg & SPI_FREAD_DIO_M) { spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN; + SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_ADDR_BITLEN_V, SPI0_R_DIO_ADDR_BITSLEN, SPI_USR_ADDR_BITLEN_S); } else if (rd_mode_reg & (SPI_FREAD_QUAD_M | SPI_FREAD_DUAL_M)) { spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN; } else { From 4c7b83defc600e4e6d1f7938e92597f494fb9b28 Mon Sep 17 00:00:00 2001 From: Prasad Alatkar Date: Thu, 15 Aug 2019 10:50:30 +0800 Subject: [PATCH 472/486] NimBLE: Fix bug in `protocomm_nimble` chararcteristic access callback Fixes bug in `protocomm_nimble` while writing to characteristic with length greater than MTU value. --- .../src/transports/protocomm_nimble.c | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/components/protocomm/src/transports/protocomm_nimble.c b/components/protocomm/src/transports/protocomm_nimble.c index cbe7bdb8d8..bf0697ba5b 100644 --- a/components/protocomm/src/transports/protocomm_nimble.c +++ b/components/protocomm/src/transports/protocomm_nimble.c @@ -287,7 +287,7 @@ gatt_svr_dsc_access(uint16_t conn_handle, uint16_t attr_handle, struct char *temp_outbuf = strdup(ctxt->dsc->arg); if (temp_outbuf == NULL) { ESP_LOGE(TAG, "Error duplicating user description of characteristic"); - return ESP_ERR_NO_MEM; + return BLE_ATT_ERR_INSUFFICIENT_RES; } ssize_t temp_outlen = strlen(temp_outbuf); @@ -308,6 +308,9 @@ gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle, ssize_t temp_outlen = 0; uint8_t *temp_outbuf = NULL; uint8_t *uuid = NULL; + uint8_t *data_buf = NULL; + uint16_t data_len = 0; + uint16_t data_buf_len = 0; switch (ctxt->op) { case BLE_GATT_ACCESS_OP_READ_CHR: @@ -328,7 +331,7 @@ gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle, uuid = (uint8_t *) calloc(BLE_UUID128_VAL_LENGTH, sizeof(uint8_t)); if (!uuid) { ESP_LOGE(TAG, "Error allocating memory for 128 bit UUID"); - return ESP_ERR_NO_MEM; + return BLE_ATT_ERR_INSUFFICIENT_RES; } rc = ble_uuid_flat(ctxt->chr->uuid, uuid); @@ -338,16 +341,32 @@ gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle, return rc; } - ESP_LOGD(TAG, "Write attempt for uuid = %s, attr_handle = %d, om_len = %d", - ble_uuid_to_str(ctxt->chr->uuid, buf), attr_handle, ctxt->om->om_len); + /* Save the length of entire data */ + data_len = OS_MBUF_PKTLEN(ctxt->om); + ESP_LOGD(TAG, "Write attempt for uuid = %s, attr_handle = %d, data_len = %d", + ble_uuid_to_str(ctxt->chr->uuid, buf), attr_handle, data_len); + + data_buf = calloc(1, data_len); + if (data_buf == NULL) { + ESP_LOGE(TAG, "Error allocating memory for characteristic value"); + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = ble_hs_mbuf_to_flat(ctxt->om, data_buf, data_len, &data_buf_len); + if (rc != 0) { + ESP_LOGE(TAG, "Error getting data from memory buffers"); + return BLE_ATT_ERR_UNLIKELY; + } + ret = protocomm_req_handle(protoble_internal->pc_ble, uuid128_to_handler(uuid), conn_handle, - ctxt->om->om_data, - ctxt->om->om_len, + data_buf, + data_buf_len, &temp_outbuf, &temp_outlen); /* Release the 16 bytes allocated for uuid*/ free(uuid); + free(data_buf); if (ret == ESP_OK) { /* Save data address and length outbuf and outlen internally */ From 6875080b9bcb65e435c23017286fb1a7480b4c41 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Mon, 12 Aug 2019 20:32:14 +0800 Subject: [PATCH 473/486] mbedtls: add source files to appropriate library --- components/mbedtls/CMakeLists.txt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/components/mbedtls/CMakeLists.txt b/components/mbedtls/CMakeLists.txt index b37269f02b..a2d082304c 100644 --- a/components/mbedtls/CMakeLists.txt +++ b/components/mbedtls/CMakeLists.txt @@ -19,18 +19,19 @@ set_property(TARGET mbedtls PROPERTY SOURCES ${src_tls}) set(mbedtls_targets mbedtls mbedcrypto mbedx509) # Add port files to mbedtls targets -target_sources(mbedtls PRIVATE "${COMPONENT_DIR}/port/esp_bignum.c" +target_sources(mbedtls PRIVATE "${COMPONENT_DIR}/port/mbedtls_debug.c" + "${COMPONENT_DIR}/port/net_sockets.c") + +target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/esp_bignum.c" "${COMPONENT_DIR}/port/esp_hardware.c" - "${COMPONENT_PATH}/port/esp_sha.c" + "${COMPONENT_DIR}/port/esp_mem.c" + "${COMPONENT_DIR}/port/esp_sha.c" "${COMPONENT_DIR}/port/esp_sha1.c" "${COMPONENT_DIR}/port/esp_sha256.c" "${COMPONENT_DIR}/port/esp_sha512.c" "${COMPONENT_DIR}/port/esp_timing.c" - "${COMPONENT_DIR}/port/mbedtls_debug.c" - "${COMPONENT_DIR}/port/net_sockets.c" "${COMPONENT_DIR}/port/esp32/aes.c" "${COMPONENT_DIR}/port/esp32/sha.c") -target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/esp_mem.c") foreach(target ${mbedtls_targets}) target_compile_definitions(${target} PUBLIC -DMBEDTLS_CONFIG_FILE="mbedtls/esp_config.h") From 6b16928fbc73d8d78a0efc5e9628bb458ab808cf Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Sun, 11 Aug 2019 20:25:54 +0800 Subject: [PATCH 474/486] docs: build system internals --- docs/en/api-guides/build-system.rst | 174 ++++++++++++++++++---------- 1 file changed, 114 insertions(+), 60 deletions(-) diff --git a/docs/en/api-guides/build-system.rst b/docs/en/api-guides/build-system.rst index 8a28a1e163..2eed1fa5ab 100644 --- a/docs/en/api-guides/build-system.rst +++ b/docs/en/api-guides/build-system.rst @@ -453,68 +453,14 @@ The order of components in the ``BUILD_COMPONENTS`` variable determines other or - Order that :ref:`project_include.cmake` files are included into the project. - Order that the list of header paths is generated for compilation (via ``-I`` argument). (Note that for a given component's source files, only that component's dependency's header paths are passed to the compiler.) -Build Process Internals -======================= - -For full details about CMake_ and CMake commands, see the `CMake v3.5 documentation`_. - -project.cmake contents ----------------------- - -When included from a project CMakeLists file, the ``project.cmake`` file defines some utility modules and global variables and then sets ``IDF_PATH`` if it was not set in the system environment. - -It also defines an overridden custom version of the built-in CMake_ ``project`` function. This function is overridden to add all of the ESP-IDF specific project functionality. - -project function ----------------- - -The custom ``project()`` function performs the following steps: - -- Determines the target (set by ``IDF_TARGET`` environment variable) and saves the target in CMake cache. If the target set in the environment does not match the one in cache, exits with an error. -- Evaluates component dependencies and builds the ``BUILD_COMPONENTS`` list of components to include in the build (see :ref:`above`). -- Finds all components in the project (searching ``COMPONENT_DIRS`` and filtering by ``COMPONENTS`` if this is set). -- Loads the project configuration from the ``sdkconfig`` file and generates a ``sdkconfig.cmake`` file and a ``sdkconfig.h`` header. These define configuration values in CMake and C/C++, respectively. If the project configuration changes, cmake will automatically be re-run to re-generate these files and re-configure the project. -- Sets the `CMAKE_TOOLCHAIN_FILE`_ variable to the correct toolchain file, depending on the target. -- Declares the actual cmake-level project by calling the `CMake project function `_. -- Loads the git version. This includes some magic which will automatically re-run CMake if a new revision is checked out in git. See `File Globbing & Incremental Builds`_. -- Includes :ref:`project_include.cmake` files from any components which have them. -- Adds each component to the build. Each component CMakeLists file calls ``idf_component_register``, calls the CMake `add_library `_ function to add a library and then adds source files, compile options, etc. -- Adds the final app executable to the build. -- Goes back and adds inter-component dependencies between components (ie adding the public header directories of each component to each other component). - -Browse the :idf_file:`/tools/cmake/project.cmake` file and supporting functions in :idf_file:`/tools/cmake/idf_functions.cmake` for more details. - -Debugging CMake ---------------- - -Some tips for debugging the ESP-IDF CMake-based build system: - -- When CMake runs, it prints quite a lot of diagnostic information including lists of components and component paths. -- Running ``cmake -DDEBUG=1`` will produce more verbose diagnostic output from the IDF build system. -- Running ``cmake`` with the ``--trace`` or ``--trace-expand`` options will give a lot of information about control flow. See the `cmake command line documentation`_. - -When included from a project CMakeLists file, the ``project.cmake`` file defines some utility modules and global variables and then sets ``IDF_PATH`` if it was not set in the system environment. - -It also defines an overridden custom version of the built-in CMake_ ``project`` function. This function is overridden to add all of the ESP-IDF specific project functionality. - -.. _warn-undefined-variables: - -Warning On Undefined Variables -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -By default, ``idf.py`` passes the ``--warn-uninitialized`` flag to CMake_ so it will print a warning if an undefined variable is referenced in the build. This can be very useful to find buggy CMake files. - -If you don't want this behaviour, it can be disabled by passing ``--no-warnings`` to ``idf.py``. - -Browse the :idf_file:`/tools/cmake/project.cmake` file and supporting functions in :idf_file:`/tools/cmake/idf_functions.cmake` for more details. Overriding Parts of the Project -------------------------------- +=============================== .. _project_include.cmake: project_include.cmake -^^^^^^^^^^^^^^^^^^^^^ +--------------------- For components that have build requirements which must be evaluated before any component CMakeLists files are evaluated, you can create a file called ``project_include.cmake`` in the @@ -531,7 +477,7 @@ Note that ``project_include.cmake`` isn't necessary for the most common componen Take great care when setting variables or targets in a ``project_include.cmake`` file. As the values are included into the top-level project CMake pass, they can influence or break functionality across all components! KConfig.projbuild -^^^^^^^^^^^^^^^^^ +----------------- This is an equivalent to ``project_include.cmake`` for :ref:`component-configuration` KConfig files. If you want to include configuration options at the top-level of menuconfig, rather than inside the "Component Configuration" sub-menu, then these can be defined in the KConfig.projbuild file alongside the ``CMakeLists.txt`` file. @@ -541,11 +487,41 @@ Take care when adding configuration values in this file, as they will be include ``project_include.cmake`` files are used inside ESP-IDF, for defining project-wide build features such as ``esptool.py`` command line arguments and the ``bootloader`` "special app". Configuration-Only Components -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +============================= Special components which contain no source files, only ``Kconfig.projbuild`` and ``KConfig``, can have a one-line ``CMakeLists.txt`` file which calls the function ``idf_component_register()`` with no arguments specified. This function will include the component in the project build, but no library will be built *and* no header files will be added to any include paths. + +Debugging CMake +=============== + +For full details about CMake_ and CMake commands, see the `CMake v3.5 documentation`_. + +Some tips for debugging the ESP-IDF CMake-based build system: + +- When CMake runs, it prints quite a lot of diagnostic information including lists of components and component paths. +- Running ``cmake -DDEBUG=1`` will produce more verbose diagnostic output from the IDF build system. +- Running ``cmake`` with the ``--trace`` or ``--trace-expand`` options will give a lot of information about control flow. See the `cmake command line documentation`_. + +When included from a project CMakeLists file, the ``project.cmake`` file defines some utility modules and global variables and then sets ``IDF_PATH`` if it was not set in the system environment. + +It also defines an overridden custom version of the built-in CMake_ ``project`` function. This function is overridden to add all of the ESP-IDF specific project functionality. + +.. _warn-undefined-variables: + +Warning On Undefined Variables +------------------------------ + +By default, ``idf.py`` passes the ``--warn-uninitialized`` flag to CMake_ so it will print a warning if an undefined variable is referenced in the build. This can be very useful to find buggy CMake files. + +If you don't want this behaviour, it can be disabled by passing ``--no-warnings`` to ``idf.py``. + +Browse the :idf_file:`/tools/cmake/project.cmake` file and supporting functions in :idf_file:`/tools/cmake/idf_functions.cmake` for more details. + +.. _gnu-make-to-cmake: + + Example Component CMakeLists ============================ @@ -1225,7 +1201,86 @@ Any combination of "load", "set", and "save" can be sent in a single command and .. note:: The configuration server does not re-run CMake to regenerate other build files or metadata files after ``sdkconfig`` is updated. This will happen automatically the next time ``CMake`` or ``idf.py`` is run. -.. _gnu-make-to-cmake: +Build System Internals +======================= + +Build Scripts +------------- + +The listfiles for the ESP-IDF build system reside in :idf:`/tools/cmake`. The modules which implement core build system functionality are as follows: + + - build.cmake - Build related commands i.e. build initialization, retrieving/setting build properties, build processing. + - component.cmake - Component related commands i.e. adding components, retrieving/setting component properties, registering components. + - kconfig.cmake - Generation of configuration files (sdkconfig, sdkconfig.h, sdkconfig.cmake, etc.) from Kconfig files. + - ldgen.cmake - Generation of final linker script from linker fragment files. + - target.cmake - Setting build target and toolchain file. + - utilities.cmake - Miscellaneous helper commands. + + Aside from these files, there are two other important CMake scripts in :idf:`/tools/cmake`: + + - idf.cmake - Sets up the build and includes the core modules listed above. Included in CMake projects in order to access ESP-IDF build system functionality. + - project.cmake - Includes ``idf.cmake`` and provides a custom ``project()`` command that takes care of all the heavy lifting of building an executable. Included in the top-level CMakeLists.txt of standard ESP-IDF projects. + +The rest of the files in :idf:`/tools/cmake` are support or third-party scripts used in the build process. + +Build Process +------------- + +This section describes the standard ESP-IDF application build process. The build process can be broken down roughly into four phases: + +.. blockdiag:: + :scale: 100% + :caption: ESP-IDF Build System Process + :align: center + + blockdiag idf-build-system-process { + Initialization -> Enumeration + Enumeration -> Processing + Processing -> Finalization + } + +Initialization +^^^^^^^^^^^^^^ + This phase sets up necessary parameters for the build. + + - Upon inclusion of ``idf.cmake`` in ``project.cmake``, the following steps are performed: + - Set ``IDF_PATH`` from environment variable or inferred from path to ``project.cmake`` included in the top-level CMakeLists.txt. + - Add :idf:`/tools/cmake` to ``CMAKE_MODULE_PATH`` and include core modules plus the various helper/third-party scripts. + - Set build tools/executables such as default Python interpreter, mconf, etc. + - Get ESP-IDF git revision and store as ``IDF_VER``. + - Set global build specifications i.e. compile options, compile definitions, include directories for all components in the build. + - Add components in :idf:`components` to the build. + - The initial part of the custom ``project()`` command performs the following steps: + - Set ``IDF_TARGET`` from environment variable or CMake cache and the corresponding ``CMAKE_TOOLCHAIN_FILE`` to be used. + - Add components in ``EXTRA_COMPONENTS_DIRS`` to the build. + - Prepare arguments for calling command ``idf_build_process()`` from variables such as ``COMPONENTS``/``EXCLUDE_COMPONENTS``, ``SDKCONFIG``, ``SDKCONFIG_DEFAULTS``. + + The call to ``idf_build_process()`` command marks the end of this phase. + +Enumeration +^^^^^^^^^^^ + This phase builds a final list of components to be processed in the build, and is performed in the first half of ``idf_build_process()``. + + - Retrieve each component's public and private requirements. A child process is created which executes each component's CMakeLists.txt in script mode. The values of ``idf_component_register`` REQUIRES and PRIV_REQUIRES argument is returned to the parent build process. This is called early expansion. The variable ``CMAKE_BUILD_EARLY_EXPANSION`` is defined during this step. + - Recursively include components based on public and private requirements. + +Processing +^^^^^^^^^^ + This phase processes the components in the build, and is the second half of ``idf_build_process()``. + + - Load project configuration from sdkconfig file and generate an sdkconfig.cmake and sdkconfig.h header. These define configuration variables/macros that are accessible from the build scripts and C/C++ source/header files, respectively. + - Include each component's ``project_include.cmake``. + - Add each component as a subdirectory, processing its CMakeLists.txt. The component CMakeLists.txt calls the registration command, ``idf_component_register`` which adds source files, include directories, creates component library, links dependencies, etc. + +Finalization +^^^^^^^^^^^^ + This phase is everything after ``idf_build_process()``. + + - Create executable and link the component libraries to it. + - Generate project metadata files such as project_description.json and display relevant information about the project built. + + +Browse :idf_file:`/tools/cmake/project.cmake` for more details. Migrating from ESP-IDF GNU Make System ====================================== @@ -1269,7 +1324,6 @@ Some features are significantly different or removed in the CMake-based system. - ``COMPONENT_CONFIG_ONLY``: Call ``register_config_only_component()`` instead. See `Configuration-Only Components`_. - ``CFLAGS``, ``CPPFLAGS``, ``CXXFLAGS``: Use equivalent CMake commands instead. See `Controlling Component Compilation`_. - No Default Values ----------------- From 1dd2f3e07b48f94553d2d9796b28555f852b8117 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Sun, 11 Aug 2019 15:47:30 +1000 Subject: [PATCH 475/486] driver: ledc: Fix low/high speed parameter setting Fix regression introduced in 2e8c85d8fff823232af46cc0f353ac170d0971e9 --- components/driver/ledc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/driver/ledc.c b/components/driver/ledc.c index f82efaf5e3..b0e9a3939d 100644 --- a/components/driver/ledc.c +++ b/components/driver/ledc.c @@ -314,7 +314,7 @@ esp_err_t ledc_timer_config(const ledc_timer_config_t* timer_conf) ESP_LOGE(LEDC_TAG, "invalid timer #%u", timer_num); return ESP_ERR_INVALID_ARG; } - return ledc_set_timer_div(timer_num, timer_num, timer_conf->clk_cfg, freq_hz, duty_resolution); + return ledc_set_timer_div(speed_mode, timer_num, timer_conf->clk_cfg, freq_hz, duty_resolution); } esp_err_t ledc_set_pin(int gpio_num, ledc_mode_t speed_mode, ledc_channel_t ledc_channel) From 848465da90555abc7dfdf09333b17b0e7ddde128 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Sun, 11 Aug 2019 15:48:17 +1000 Subject: [PATCH 476/486] driver: Check ledc config result in PCNT tests --- components/driver/test/test_pcnt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/driver/test/test_pcnt.c b/components/driver/test/test_pcnt.c index af4e58fa67..90dc2c4ece 100644 --- a/components/driver/test/test_pcnt.c +++ b/components/driver/test/test_pcnt.c @@ -57,7 +57,7 @@ static void produce_pulse(void) .freq_hz = 1, .clk_cfg = LEDC_AUTO_CLK, }; - ledc_timer_config(&ledc_timer); + ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer)); ledc_channel_config_t ledc_channel = { .speed_mode = LEDC_HIGH_SPEED_MODE, @@ -68,7 +68,7 @@ static void produce_pulse(void) .duty = 100, .hpoint = 0, }; - ledc_channel_config(&ledc_channel); + ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); } static void IRAM_ATTR pcnt_intr_handler(void *arg) From 53e7beb95b0d4421c99b3af184fa801fb92162e4 Mon Sep 17 00:00:00 2001 From: Hrudaynath Dhabe Date: Thu, 15 Aug 2019 21:10:00 +0800 Subject: [PATCH 477/486] esp_https_ota: Added error checking functionalities. Current implimentation of esp_http_ota does not perform any error-checking in the data writing phase calls `esp_ota_get_next_update_partition()` irrespetive of the received state of the image. A few additional error checking mechanism have now been added inside the esp_https_ota which returns the control in case an invalid header is received and a wrapper to the function `esp_http_client_is_complete_data_received()` of `esp_http_client` has been added. --- .../esp_https_ota/include/esp_https_ota.h | 13 ++++++++++++ components/esp_https_ota/src/esp_https_ota.c | 20 ++++++++++++++----- .../main/advanced_https_ota_example.c | 5 +++++ .../main/native_ota_example.c | 5 +++++ 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/components/esp_https_ota/include/esp_https_ota.h b/components/esp_https_ota/include/esp_https_ota.h index 0c8fd06934..7feba8f7ee 100644 --- a/components/esp_https_ota/include/esp_https_ota.h +++ b/components/esp_https_ota/include/esp_https_ota.h @@ -110,6 +110,19 @@ esp_err_t esp_https_ota_begin(esp_https_ota_config_t *ota_config, esp_https_ota_ */ esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle); +/** + * @brief Checks if complete data was received or not + * + * @note This API can be called just before esp_https_ota_finish() to validate if the complete image was indeed received. + * + * @param[in] https_ota_handle pointer to esp_https_ota_handle_t structure + * + * @return + * - false + * - true + */ +bool esp_https_ota_is_complete_data_received(esp_https_ota_handle_t https_ota_handle); + /** * @brief Clean-up HTTPS OTA Firmware upgrade and close HTTPS connection * diff --git a/components/esp_https_ota/src/esp_https_ota.c b/components/esp_https_ota/src/esp_https_ota.c index baba0bbaa4..d2ca501039 100644 --- a/components/esp_https_ota/src/esp_https_ota.c +++ b/components/esp_https_ota/src/esp_https_ota.c @@ -85,17 +85,21 @@ static esp_err_t _http_handle_response_code(esp_http_client_handle_t http_client static esp_err_t _http_connect(esp_http_client_handle_t http_client) { esp_err_t err = ESP_FAIL; - int status_code; + int status_code, header_ret; do { err = esp_http_client_open(http_client, 0); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err)); return err; } - esp_http_client_fetch_headers(http_client); + header_ret = esp_http_client_fetch_headers(http_client); + if (header_ret < 0) { + return header_ret; + } status_code = esp_http_client_get_status_code(http_client); - if (_http_handle_response_code(http_client, status_code) != ESP_OK) { - return ESP_FAIL; + err = _http_handle_response_code(http_client, status_code); + if (err != ESP_OK) { + return err; } } while (process_again(status_code)); return err; @@ -276,6 +280,12 @@ esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle) return ESP_OK; } +bool esp_https_ota_is_complete_data_received(esp_https_ota_handle_t https_ota_handle) +{ + esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle; + return esp_http_client_is_complete_data_received(handle->http_client); +} + esp_err_t esp_https_ota_finish(esp_https_ota_handle_t https_ota_handle) { esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle; @@ -361,4 +371,4 @@ esp_err_t esp_https_ota(const esp_http_client_config_t *config) return ota_finish_err; } return ESP_OK; -} \ No newline at end of file +} diff --git a/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c b/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c index 0387e3e681..aafa488883 100644 --- a/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c +++ b/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c @@ -88,6 +88,11 @@ void advanced_ota_example_task(void *pvParameter) ESP_LOGD(TAG, "Image bytes read: %d", esp_https_ota_get_image_len_read(https_ota_handle)); } + if (esp_https_ota_is_complete_data_received(&https_ota_handle) != true) { + // the OTA image was not completely received and user can customise the response to this situation. + ESP_LOGE(TAG, "Complete data was not received."); + } + ota_end: ota_finish_err = esp_https_ota_finish(https_ota_handle); if ((err == ESP_OK) && (ota_finish_err == ESP_OK)) { diff --git a/examples/system/ota/native_ota_example/main/native_ota_example.c b/examples/system/ota/native_ota_example/main/native_ota_example.c index fc42b7f3b0..9d84cc07c6 100644 --- a/examples/system/ota/native_ota_example/main/native_ota_example.c +++ b/examples/system/ota/native_ota_example/main/native_ota_example.c @@ -182,6 +182,11 @@ static void ota_example_task(void *pvParameter) } } ESP_LOGI(TAG, "Total Write binary data length : %d", binary_file_length); + if (esp_http_client_is_complete_data_received(client) != true) { + ESP_LOGE(TAG, "Error in receiving complete file"); + http_cleanup(client); + task_fatal_error(); + } if (esp_ota_end(update_handle) != ESP_OK) { ESP_LOGE(TAG, "esp_ota_end failed!"); From 74fe282b73a4f5ffaa0cf866c090e9d7212bfc61 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 15 Aug 2019 15:49:46 +0200 Subject: [PATCH 478/486] cmake: check mconf-idf binary version Print a warning if an outdated version of mconf-idf is found in the PATH. --- tools/cmake/kconfig.cmake | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/tools/cmake/kconfig.cmake b/tools/cmake/kconfig.cmake index d1d34234d4..91f17bccec 100644 --- a/tools/cmake/kconfig.cmake +++ b/tools/cmake/kconfig.cmake @@ -30,8 +30,28 @@ function(__kconfig_init) "on the PATH, or an MSYS2 version of gcc on the PATH to build mconf-idf. " "Consult the setup docs for ESP-IDF on Windows.") endif() - elseif(WINPTY) - set(MCONF "\"${WINPTY}\" \"${MCONF}\"") + else() + execute_process(COMMAND "${MCONF}" -v + RESULT_VARIABLE mconf_res + OUTPUT_VARIABLE mconf_out + ERROR_VARIABLE mconf_err) + if(${mconf_res}) + message(WARNING "Failed to detect version of mconf-idf. Return code was ${mconf_res}.") + else() + string(STRIP "${mconf_out}" mconf_out) + set(mconf_expected_ver "mconf-v4.6.0.0-idf-20190628-win32") + if(NOT ${mconf_out} STREQUAL "mconf-idf version ${mconf_expected_ver}") + message(WARNING "Unexpected ${mconf_out}. Expected ${mconf_expected_ver}. " + "Please check the ESP-IDF Getting Started guide for version " + "${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}.${IDF_VERSION_PATCH} " + "to correct this issue") + else() + message(STATUS "${mconf_out}") # prints: mconf-idf version .... + endif() + endif() + if(WINPTY) + set(MCONF "\"${WINPTY}\" \"${MCONF}\"") + endif() endif() endif() From 61a1a468bb557bddb771d29a8f379db5b0741ec7 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 15 Aug 2019 17:51:54 +0200 Subject: [PATCH 479/486] tcp_transport: replace transport_strcasestr with strcasestr esp32-2019r1 toolchain version includes 'strcasestr', so the version provided in tcp_transport component is no longer needed. --- components/tcp_transport/CMakeLists.txt | 1 - .../tcp_transport/transport_strcasestr.c | 57 ------------------- .../tcp_transport/transport_strcasestr.h | 38 ------------- components/tcp_transport/transport_ws.c | 3 +- 4 files changed, 1 insertion(+), 98 deletions(-) delete mode 100644 components/tcp_transport/transport_strcasestr.c delete mode 100644 components/tcp_transport/transport_strcasestr.h diff --git a/components/tcp_transport/CMakeLists.txt b/components/tcp_transport/CMakeLists.txt index fe7e71bf31..db4afb8752 100644 --- a/components/tcp_transport/CMakeLists.txt +++ b/components/tcp_transport/CMakeLists.txt @@ -3,7 +3,6 @@ idf_component_register(SRCS "transport.c" "transport_tcp.c" "transport_ws.c" "transport_utils.c" - "transport_strcasestr.c" INCLUDE_DIRS "include" PRIV_INCLUDE_DIRS "private_include" REQUIRES lwip esp-tls) diff --git a/components/tcp_transport/transport_strcasestr.c b/components/tcp_transport/transport_strcasestr.c deleted file mode 100644 index 80551a4b3b..0000000000 --- a/components/tcp_transport/transport_strcasestr.c +++ /dev/null @@ -1,57 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * The quadratic code is derived from software contributed to Berkeley by - * Chris Torek. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -/* Linear algorithm Copyright (C) 2008 Eric Blake - * Permission to use, copy, modify, and distribute the linear portion of - * software is freely granted, provided that this notice is preserved. - */ -#include "transport_strcasestr.h" -#include -#include - -char *transport_strcasestr(const char *buffer, const char *key) -{ - char c, sc; - size_t len; - - if ((c = *key++) != 0) { - c = tolower((unsigned char)c); - len = strlen(key); - do { - do { - if ((sc = *buffer++) == 0) - return (NULL); - } while ((char)tolower((unsigned char)sc) != c); - } while (strncasecmp(buffer, key, len) != 0); - buffer--; - } - return ((char *)buffer); -} diff --git a/components/tcp_transport/transport_strcasestr.h b/components/tcp_transport/transport_strcasestr.h deleted file mode 100644 index e337d90d51..0000000000 --- a/components/tcp_transport/transport_strcasestr.h +++ /dev/null @@ -1,38 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * The quadratic code is derived from software contributed to Berkeley by - * Chris Torek. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -/* Linear algorithm Copyright (C) 2008 Eric Blake - * Permission to use, copy, modify, and distribute the linear portion of - * software is freely granted, provided that this notice is preserved. - */ - -char *transport_strcasestr(const char *buffer, const char *key); - diff --git a/components/tcp_transport/transport_ws.c b/components/tcp_transport/transport_ws.c index 12aaa3d232..886f2a31e5 100644 --- a/components/tcp_transport/transport_ws.c +++ b/components/tcp_transport/transport_ws.c @@ -8,7 +8,6 @@ #include "esp_transport_tcp.h" #include "esp_transport_ws.h" #include "esp_transport_utils.h" -#include "transport_strcasestr.h" #include "mbedtls/base64.h" #include "mbedtls/sha1.h" @@ -64,7 +63,7 @@ static char *trimwhitespace(const char *str) static char *get_http_header(const char *buffer, const char *key) { - char *found = transport_strcasestr(buffer, key); + char *found = strcasestr(buffer, key); if (found) { found += strlen(key); char *found_end = strstr(found, "\r\n"); From 423fb9573bf6c7516536b7c14cc488312166550d Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 16 Aug 2019 19:24:20 +1000 Subject: [PATCH 480/486] confserver: Fix NamedTemporaryFile use on Windows Can't have the file open twice, so need to close and delete after reopening. --- tools/kconfig_new/confserver.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/kconfig_new/confserver.py b/tools/kconfig_new/confserver.py index 2e0d24ad7e..cddb572c92 100755 --- a/tools/kconfig_new/confserver.py +++ b/tools/kconfig_new/confserver.py @@ -74,12 +74,14 @@ def run_server(kconfig, sdkconfig, sdkconfig_rename, default_version=MAX_PROTOCO sdkconfig_renames = [sdkconfig_rename] if sdkconfig_rename else [] sdkconfig_renames += os.environ.get("COMPONENT_SDKCONFIG_RENAMES", "").split() deprecated_options = confgen.DeprecatedOptions(config.config_prefix, path_rename_files=sdkconfig_renames) - with tempfile.NamedTemporaryFile(mode='w+b') as f_o: + f_o = tempfile.NamedTemporaryFile(mode='w+b', delete=False) + try: with open(sdkconfig, mode='rb') as f_i: f_o.write(f_i.read()) - f_o.flush() - f_o.seek(0) + f_o.close() # need to close as DeprecatedOptions will reopen, and Windows only allows one open file deprecated_options.replace(sdkconfig_in=f_o.name, sdkconfig_out=sdkconfig) + finally: + os.unlink(f_o.name) config.load_config(sdkconfig) print("Server running, waiting for requests on stdin...", file=sys.stderr) From 24f91617d7f0992077cab9d16573ac6fe2a9b9c0 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Fri, 16 Aug 2019 11:24:57 +0800 Subject: [PATCH 481/486] idf_monitor: fix the bug that idf_monitor not blocked when no log printed Inspired by @no1seman, @negativekelvin and @pglen on Github. (In post oder) Resolves https://github.com/espressif/esp-idf/issues/3884 --- tools/idf_monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/idf_monitor.py b/tools/idf_monitor.py index 5320149dbe..2076c012dc 100755 --- a/tools/idf_monitor.py +++ b/tools/idf_monitor.py @@ -490,7 +490,7 @@ class Monitor(object): item = self.cmd_queue.get_nowait() except queue.Empty: try: - item = self.event_queue.get(False, 0.001) + item = self.event_queue.get(True, 0.03) except queue.Empty: continue From 9ec363a25d8c68c18e99027b60f099531cd5885b Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Tue, 6 Aug 2019 17:10:16 +0530 Subject: [PATCH 482/486] wpa_supplicant: Make internally used crypto headers private A lot of internally used crypto headers are publicly includeable in user projects. This leads to bug reports when these headers are incorrectly used or the API's are not used as intended. Move all crypto headers into private crypto src folder, also move crypto_ops into Supplicant to remove dependecy on crypto headers. Closes IDF-476 --- components/esp32/esp_adapter.c | 5 ----- components/esp_wifi/CMakeLists.txt | 1 - components/wpa_supplicant/CMakeLists.txt | 1 + .../wpa_supplicant/include/crypto/wepkey.h | 10 ---------- .../include/esp_supplicant/esp_wpa.h | 5 ++++- components/wpa_supplicant/src/ap/ieee802_1x.c | 1 - components/wpa_supplicant/src/crypto/aes-cbc.c | 4 ++-- .../wpa_supplicant/src/crypto/aes-internal-dec.c | 4 ++-- .../wpa_supplicant/src/crypto/aes-internal-enc.c | 4 ++-- .../wpa_supplicant/src/crypto/aes-internal.c | 4 ++-- .../wpa_supplicant/src/crypto/aes-unwrap.c | 4 ++-- components/wpa_supplicant/src/crypto/aes-wrap.c | 4 ++-- .../wpa_supplicant/{include => src}/crypto/aes.h | 0 components/wpa_supplicant/src/crypto/aes_i.h | 2 +- .../{include => src}/crypto/aes_wrap.h | 0 .../{include => src}/crypto/crypto.h | 0 .../src/crypto/crypto_internal-cipher.c | 6 +++--- .../src/crypto/crypto_internal-modexp.c | 2 +- .../src/crypto/crypto_internal-rsa.c | 2 +- .../wpa_supplicant/src/crypto/crypto_internal.c | 6 +++--- .../wpa_supplicant/src/crypto/crypto_mbedtls.c | 2 +- .../src/crypto}/crypto_ops.c | 16 ++++++++-------- .../wpa_supplicant/src/crypto/des-internal.c | 2 +- components/wpa_supplicant/src/crypto/dh_group5.c | 4 ++-- .../{include => src}/crypto/dh_group5.h | 0 components/wpa_supplicant/src/crypto/dh_groups.c | 6 +++--- .../{include => src}/crypto/dh_groups.h | 0 .../wpa_supplicant/src/crypto/md4-internal.c | 2 +- .../wpa_supplicant/src/crypto/md5-internal.c | 6 +++--- components/wpa_supplicant/src/crypto/md5.c | 4 ++-- .../wpa_supplicant/{include => src}/crypto/md5.h | 0 components/wpa_supplicant/src/crypto/ms_funcs.c | 6 +++--- .../{include => src}/crypto/ms_funcs.h | 0 .../{include => src}/crypto/random.h | 0 components/wpa_supplicant/src/crypto/rc4.c | 2 +- .../wpa_supplicant/src/crypto/sha1-internal.c | 8 ++++---- .../wpa_supplicant/src/crypto/sha1-pbkdf2.c | 6 +++--- components/wpa_supplicant/src/crypto/sha1.c | 4 ++-- .../{include => src}/crypto/sha1.h | 0 .../wpa_supplicant/src/crypto/sha256-internal.c | 4 ++-- components/wpa_supplicant/src/crypto/sha256.c | 4 ++-- .../{include => src}/crypto/sha256.h | 0 .../wpa_supplicant/src/eap_peer/eap_ttls.c | 1 - .../src/esp_supplicant/esp_wpa_main.c | 1 - components/wpa_supplicant/src/rsn_supp/wpa.c | 1 - components/wpa_supplicant/src/wps/wps.c | 2 -- .../wpa_supplicant/src/wps/wps_attr_build.c | 2 +- components/wpa_supplicant/src/wps/wps_common.c | 2 +- 48 files changed, 66 insertions(+), 84 deletions(-) delete mode 100644 components/wpa_supplicant/include/crypto/wepkey.h rename components/wpa_supplicant/{include => src}/crypto/aes.h (100%) rename components/wpa_supplicant/{include => src}/crypto/aes_wrap.h (100%) rename components/wpa_supplicant/{include => src}/crypto/crypto.h (100%) rename components/{esp_wifi/src => wpa_supplicant/src/crypto}/crypto_ops.c (91%) rename components/wpa_supplicant/{include => src}/crypto/dh_group5.h (100%) rename components/wpa_supplicant/{include => src}/crypto/dh_groups.h (100%) rename components/wpa_supplicant/{include => src}/crypto/md5.h (100%) rename components/wpa_supplicant/{include => src}/crypto/ms_funcs.h (100%) rename components/wpa_supplicant/{include => src}/crypto/random.h (100%) rename components/wpa_supplicant/{include => src}/crypto/sha1.h (100%) rename components/wpa_supplicant/{include => src}/crypto/sha256.h (100%) diff --git a/components/esp32/esp_adapter.c b/components/esp32/esp_adapter.c index 0699bf70ca..4fdd5ce65e 100644 --- a/components/esp32/esp_adapter.c +++ b/components/esp32/esp_adapter.c @@ -38,11 +38,6 @@ #include "esp_private/wifi_os_adapter.h" #include "esp_private/wifi.h" #include "esp_phy_init.h" -#include "crypto/md5.h" -#include "crypto/sha1.h" -#include "crypto/crypto.h" -#include "crypto/aes.h" -#include "crypto/dh_group5.h" #include "driver/periph_ctrl.h" #include "nvs.h" #include "os.h" diff --git a/components/esp_wifi/CMakeLists.txt b/components/esp_wifi/CMakeLists.txt index 4994e19dc3..925704f933 100644 --- a/components/esp_wifi/CMakeLists.txt +++ b/components/esp_wifi/CMakeLists.txt @@ -5,7 +5,6 @@ if(NOT CONFIG_ESP32_NO_BLOBS) endif() idf_component_register(SRCS "src/coexist.c" - "src/crypto_ops.c" "src/lib_printf.c" "src/mesh_event.c" "src/phy_init.c" diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index 2b7e14924f..330b94d6c2 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -12,6 +12,7 @@ set(srcs "port/os_xtensa.c" "src/crypto/aes-wrap.c" "src/crypto/bignum.c" "src/crypto/crypto_mbedtls.c" + "src/crypto/crypto_ops.c" "src/crypto/crypto_internal-cipher.c" "src/crypto/crypto_internal-modexp.c" "src/crypto/crypto_internal-rsa.c" diff --git a/components/wpa_supplicant/include/crypto/wepkey.h b/components/wpa_supplicant/include/crypto/wepkey.h deleted file mode 100644 index 32a8cf9b37..0000000000 --- a/components/wpa_supplicant/include/crypto/wepkey.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef WEPKEY_H -#define WEPKEY_H - -#define WEPKEY_64_BYTES 5 -#define WePKEY_128_BYTES 13 - -unsigned int wepkey_64(uint8_t *out, unsigned int size, const char *in, int n); -unsigned int wepkey_128(uint8_t *out, unsigned int size, const char *in, int n); - -#endif /* WEPKEY_H */ \ No newline at end of file diff --git a/components/wpa_supplicant/include/esp_supplicant/esp_wpa.h b/components/wpa_supplicant/include/esp_supplicant/esp_wpa.h index 33f0fe57a4..c7fbcfacbe 100644 --- a/components/wpa_supplicant/include/esp_supplicant/esp_wpa.h +++ b/components/wpa_supplicant/include/esp_supplicant/esp_wpa.h @@ -40,7 +40,10 @@ extern "C" { /** @addtogroup WPA_APIs * @{ */ - +/* Crypto callback functions */ +const wpa_crypto_funcs_t g_wifi_default_wpa_crypto_funcs; +/* Mesh crypto callback functions */ +const mesh_crypto_funcs_t g_wifi_default_mesh_crypto_funcs; /** * @brief Supplicant initialization diff --git a/components/wpa_supplicant/src/ap/ieee802_1x.c b/components/wpa_supplicant/src/ap/ieee802_1x.c index 5b459a7865..62de7f5940 100644 --- a/components/wpa_supplicant/src/ap/ieee802_1x.c +++ b/components/wpa_supplicant/src/ap/ieee802_1x.c @@ -10,7 +10,6 @@ #include "utils/common.h" #include "crypto/crypto.h" -#include "crypto/random.h" #include "common/ieee802_11_defs.h" #include "hostapd.h" #include "ap/sta_info.h" diff --git a/components/wpa_supplicant/src/crypto/aes-cbc.c b/components/wpa_supplicant/src/crypto/aes-cbc.c index 24c5670090..03d7a68ba6 100644 --- a/components/wpa_supplicant/src/crypto/aes-cbc.c +++ b/components/wpa_supplicant/src/crypto/aes-cbc.c @@ -31,8 +31,8 @@ #include "utils/includes.h" #include "utils/common.h" -#include "crypto/aes.h" -#include "crypto/aes_wrap.h" +#include "aes.h" +#include "aes_wrap.h" #ifdef USE_MBEDTLS_CRYPTO #include "mbedtls/aes.h" diff --git a/components/wpa_supplicant/src/crypto/aes-internal-dec.c b/components/wpa_supplicant/src/crypto/aes-internal-dec.c index 5cea5f745f..8c91b5c00e 100644 --- a/components/wpa_supplicant/src/crypto/aes-internal-dec.c +++ b/components/wpa_supplicant/src/crypto/aes-internal-dec.c @@ -24,8 +24,8 @@ #include "utils/includes.h" #include "utils/common.h" -#include "crypto/crypto.h" -#include "crypto/aes_i.h" +#include "crypto.h" +#include "aes_i.h" diff --git a/components/wpa_supplicant/src/crypto/aes-internal-enc.c b/components/wpa_supplicant/src/crypto/aes-internal-enc.c index 5b714fedba..56084e4489 100644 --- a/components/wpa_supplicant/src/crypto/aes-internal-enc.c +++ b/components/wpa_supplicant/src/crypto/aes-internal-enc.c @@ -23,8 +23,8 @@ #include "utils/includes.h" #include "utils/common.h" -#include "crypto/crypto.h" -#include "crypto/aes_i.h" +#include "crypto.h" +#include "aes_i.h" #include "os.h" diff --git a/components/wpa_supplicant/src/crypto/aes-internal.c b/components/wpa_supplicant/src/crypto/aes-internal.c index 537d4034a7..93592f1dc8 100644 --- a/components/wpa_supplicant/src/crypto/aes-internal.c +++ b/components/wpa_supplicant/src/crypto/aes-internal.c @@ -24,8 +24,8 @@ #include "utils/includes.h" #include "utils/common.h" -#include "crypto/crypto.h" -#include "crypto/aes_i.h" +#include "crypto.h" +#include "aes_i.h" /* * rijndael-alg-fst.c diff --git a/components/wpa_supplicant/src/crypto/aes-unwrap.c b/components/wpa_supplicant/src/crypto/aes-unwrap.c index 9f513b0ac5..090c2a9095 100644 --- a/components/wpa_supplicant/src/crypto/aes-unwrap.c +++ b/components/wpa_supplicant/src/crypto/aes-unwrap.c @@ -34,8 +34,8 @@ #ifdef USE_MBEDTLS_CRYPTO #include "mbedtls/aes.h" #else /* USE_MBEDTLS_CRYPTO */ -#include "crypto/aes.h" -#include "crypto/aes_wrap.h" +#include "aes.h" +#include "aes_wrap.h" #endif /* USE_MBEDTLS_CRYPTO */ /** diff --git a/components/wpa_supplicant/src/crypto/aes-wrap.c b/components/wpa_supplicant/src/crypto/aes-wrap.c index 9d180f5222..42e60660b6 100644 --- a/components/wpa_supplicant/src/crypto/aes-wrap.c +++ b/components/wpa_supplicant/src/crypto/aes-wrap.c @@ -25,8 +25,8 @@ #include "utils/includes.h" #include "utils/common.h" -#include "crypto/aes.h" -#include "crypto/aes_wrap.h" +#include "aes.h" +#include "aes_wrap.h" #ifdef USE_MBEDTLS_CRYPTO #include "mbedtls/aes.h" #endif /* USE_MBEDTLS_CRYPTO */ diff --git a/components/wpa_supplicant/include/crypto/aes.h b/components/wpa_supplicant/src/crypto/aes.h similarity index 100% rename from components/wpa_supplicant/include/crypto/aes.h rename to components/wpa_supplicant/src/crypto/aes.h diff --git a/components/wpa_supplicant/src/crypto/aes_i.h b/components/wpa_supplicant/src/crypto/aes_i.h index 290ac423bd..1063422a81 100644 --- a/components/wpa_supplicant/src/crypto/aes_i.h +++ b/components/wpa_supplicant/src/crypto/aes_i.h @@ -15,7 +15,7 @@ #ifndef AES_I_H #define AES_I_H -#include "crypto/aes.h" +#include "aes.h" /* #define FULL_UNROLL */ #define AES_SMALL_TABLES diff --git a/components/wpa_supplicant/include/crypto/aes_wrap.h b/components/wpa_supplicant/src/crypto/aes_wrap.h similarity index 100% rename from components/wpa_supplicant/include/crypto/aes_wrap.h rename to components/wpa_supplicant/src/crypto/aes_wrap.h diff --git a/components/wpa_supplicant/include/crypto/crypto.h b/components/wpa_supplicant/src/crypto/crypto.h similarity index 100% rename from components/wpa_supplicant/include/crypto/crypto.h rename to components/wpa_supplicant/src/crypto/crypto.h diff --git a/components/wpa_supplicant/src/crypto/crypto_internal-cipher.c b/components/wpa_supplicant/src/crypto/crypto_internal-cipher.c index 3fe2412e10..9ca428cfe3 100644 --- a/components/wpa_supplicant/src/crypto/crypto_internal-cipher.c +++ b/components/wpa_supplicant/src/crypto/crypto_internal-cipher.c @@ -23,10 +23,10 @@ #include "utils/common.h" #include "utils/includes.h" -#include "crypto/crypto.h" -#include "crypto/aes.h" +#include "crypto.h" +#include "aes.h" #if defined(CONFIG_DES) || defined(CONFIG_DES3) -#include "crypto/des_i.h" +#include "des_i.h" #endif #ifdef USE_MBEDTLS_CRYPTO #include "mbedtls/aes.h" diff --git a/components/wpa_supplicant/src/crypto/crypto_internal-modexp.c b/components/wpa_supplicant/src/crypto/crypto_internal-modexp.c index f37139ba19..8d9d7fe83d 100644 --- a/components/wpa_supplicant/src/crypto/crypto_internal-modexp.c +++ b/components/wpa_supplicant/src/crypto/crypto_internal-modexp.c @@ -35,7 +35,7 @@ #else /* USE_MBEDTLS_CRYPTO */ #include "bignum.h" #endif /* USE_MBEDTLS_CRYPTO */ -#include "crypto/crypto.h" +#include "crypto.h" #ifdef USE_MBEDTLS_CRYPTO int diff --git a/components/wpa_supplicant/src/crypto/crypto_internal-rsa.c b/components/wpa_supplicant/src/crypto/crypto_internal-rsa.c index de7c8091e9..1d63137fa5 100644 --- a/components/wpa_supplicant/src/crypto/crypto_internal-rsa.c +++ b/components/wpa_supplicant/src/crypto/crypto_internal-rsa.c @@ -7,7 +7,7 @@ */ #include "utils/common.h" -#include "crypto/crypto.h" +#include "crypto.h" #include "utils/includes.h" #include "utils/common.h" diff --git a/components/wpa_supplicant/src/crypto/crypto_internal.c b/components/wpa_supplicant/src/crypto/crypto_internal.c index 4622cfcb89..ca82d0d52b 100644 --- a/components/wpa_supplicant/src/crypto/crypto_internal.c +++ b/components/wpa_supplicant/src/crypto/crypto_internal.c @@ -23,9 +23,9 @@ #include "utils/includes.h" #include "utils/common.h" -#include "crypto/crypto.h" -#include "crypto/sha1_i.h" -#include "crypto/md5_i.h" +#include "crypto.h" +#include "sha1_i.h" +#include "md5_i.h" #ifdef USE_MBEDTLS_CRYPTO #include "mbedtls/sha256.h" #endif diff --git a/components/wpa_supplicant/src/crypto/crypto_mbedtls.c b/components/wpa_supplicant/src/crypto/crypto_mbedtls.c index 315a6834ff..d6a91b5329 100644 --- a/components/wpa_supplicant/src/crypto/crypto_mbedtls.c +++ b/components/wpa_supplicant/src/crypto/crypto_mbedtls.c @@ -19,7 +19,7 @@ #include "utils/includes.h" #include "utils/common.h" -#include "crypto/crypto.h" +#include "crypto.h" #include "mbedtls/ecp.h" #include "mbedtls/entropy.h" diff --git a/components/esp_wifi/src/crypto_ops.c b/components/wpa_supplicant/src/crypto/crypto_ops.c similarity index 91% rename from components/esp_wifi/src/crypto_ops.c rename to components/wpa_supplicant/src/crypto/crypto_ops.c index fdef5ca57e..f46d823dfe 100644 --- a/components/esp_wifi/src/crypto_ops.c +++ b/components/wpa_supplicant/src/crypto/crypto_ops.c @@ -13,14 +13,14 @@ // limitations under the License. #include "utils/common.h" -#include "crypto/aes_wrap.h" -#include "crypto/sha256.h" -#include "crypto/crypto.h" -#include "crypto/md5.h" -#include "crypto/sha1.h" -#include "crypto/aes.h" -#include "crypto/dh_group5.h" -#include "esp_wifi_crypto_types.h" +#include "aes_wrap.h" +#include "sha256.h" +#include "crypto.h" +#include "md5.h" +#include "sha1.h" +#include "aes.h" +#include "esp_wpa.h" + /* * This structure is used to set the cyrpto callback function for station to connect when in security mode. * These functions either call MbedTLS API's if USE_MBEDTLS_CRYPTO flag is set through Kconfig, or native diff --git a/components/wpa_supplicant/src/crypto/des-internal.c b/components/wpa_supplicant/src/crypto/des-internal.c index 7c66412286..077b7d013c 100644 --- a/components/wpa_supplicant/src/crypto/des-internal.c +++ b/components/wpa_supplicant/src/crypto/des-internal.c @@ -12,7 +12,7 @@ #include "utils/includes.h" #include "utils/common.h" -#include "crypto/crypto.h" +#include "crypto.h" //#include "des_i.h" /* diff --git a/components/wpa_supplicant/src/crypto/dh_group5.c b/components/wpa_supplicant/src/crypto/dh_group5.c index 5ae75da2e1..d5adaf24fd 100644 --- a/components/wpa_supplicant/src/crypto/dh_group5.c +++ b/components/wpa_supplicant/src/crypto/dh_group5.c @@ -15,8 +15,8 @@ #include "utils/includes.h" #include "utils/common.h" -#include "crypto/dh_groups.h" -#include "crypto/dh_group5.h" +#include "dh_groups.h" +#include "dh_group5.h" void * diff --git a/components/wpa_supplicant/include/crypto/dh_group5.h b/components/wpa_supplicant/src/crypto/dh_group5.h similarity index 100% rename from components/wpa_supplicant/include/crypto/dh_group5.h rename to components/wpa_supplicant/src/crypto/dh_group5.h diff --git a/components/wpa_supplicant/src/crypto/dh_groups.c b/components/wpa_supplicant/src/crypto/dh_groups.c index e3c7519ece..6f699d9be6 100644 --- a/components/wpa_supplicant/src/crypto/dh_groups.c +++ b/components/wpa_supplicant/src/crypto/dh_groups.c @@ -15,9 +15,9 @@ #include "utils/includes.h" #include "utils/common.h" -#include "crypto/crypto.h" -#include "crypto/random.h" -#include "crypto/dh_groups.h" +#include "crypto.h" +#include "random.h" +#include "dh_groups.h" #include "utils/wpabuf.h" #include "utils/wpa_debug.h" #include "esp_wifi_crypto_types.h" diff --git a/components/wpa_supplicant/include/crypto/dh_groups.h b/components/wpa_supplicant/src/crypto/dh_groups.h similarity index 100% rename from components/wpa_supplicant/include/crypto/dh_groups.h rename to components/wpa_supplicant/src/crypto/dh_groups.h diff --git a/components/wpa_supplicant/src/crypto/md4-internal.c b/components/wpa_supplicant/src/crypto/md4-internal.c index cc988492d3..9c99b7cbe1 100644 --- a/components/wpa_supplicant/src/crypto/md4-internal.c +++ b/components/wpa_supplicant/src/crypto/md4-internal.c @@ -6,7 +6,7 @@ #include "utils/includes.h" #include "utils/common.h" -#include "crypto/crypto.h" +#include "crypto.h" #define MD4_BLOCK_LENGTH 64 #define MD4_DIGEST_LENGTH 16 diff --git a/components/wpa_supplicant/src/crypto/md5-internal.c b/components/wpa_supplicant/src/crypto/md5-internal.c index 3a98b36d49..a6b394006b 100644 --- a/components/wpa_supplicant/src/crypto/md5-internal.c +++ b/components/wpa_supplicant/src/crypto/md5-internal.c @@ -15,9 +15,9 @@ #include "utils/includes.h" #include "utils/common.h" -#include "crypto/md5.h" -#include "crypto/md5_i.h" -#include "crypto/crypto.h" +#include "md5.h" +#include "md5_i.h" +#include "crypto.h" static void MD5Transform(u32 buf[4], u32 const in[16]); diff --git a/components/wpa_supplicant/src/crypto/md5.c b/components/wpa_supplicant/src/crypto/md5.c index 3a05742961..57ec4ea983 100644 --- a/components/wpa_supplicant/src/crypto/md5.c +++ b/components/wpa_supplicant/src/crypto/md5.c @@ -15,8 +15,8 @@ #include "utils/includes.h" #include "utils/common.h" -#include "crypto/md5.h" -#include "crypto/crypto.h" +#include "md5.h" +#include "crypto.h" /** diff --git a/components/wpa_supplicant/include/crypto/md5.h b/components/wpa_supplicant/src/crypto/md5.h similarity index 100% rename from components/wpa_supplicant/include/crypto/md5.h rename to components/wpa_supplicant/src/crypto/md5.h diff --git a/components/wpa_supplicant/src/crypto/ms_funcs.c b/components/wpa_supplicant/src/crypto/ms_funcs.c index 191aa2bcf2..750a4083bd 100644 --- a/components/wpa_supplicant/src/crypto/ms_funcs.c +++ b/components/wpa_supplicant/src/crypto/ms_funcs.c @@ -10,9 +10,9 @@ #include "utils/includes.h" #include "utils/common.h" -#include "crypto/sha1.h" -#include "crypto/ms_funcs.h" -#include "crypto/crypto.h" +#include "sha1.h" +#include "ms_funcs.h" +#include "crypto.h" /** * utf8_to_ucs2 - Convert UTF-8 string to UCS-2 encoding diff --git a/components/wpa_supplicant/include/crypto/ms_funcs.h b/components/wpa_supplicant/src/crypto/ms_funcs.h similarity index 100% rename from components/wpa_supplicant/include/crypto/ms_funcs.h rename to components/wpa_supplicant/src/crypto/ms_funcs.h diff --git a/components/wpa_supplicant/include/crypto/random.h b/components/wpa_supplicant/src/crypto/random.h similarity index 100% rename from components/wpa_supplicant/include/crypto/random.h rename to components/wpa_supplicant/src/crypto/random.h diff --git a/components/wpa_supplicant/src/crypto/rc4.c b/components/wpa_supplicant/src/crypto/rc4.c index aa914dcc72..a014afe6e3 100644 --- a/components/wpa_supplicant/src/crypto/rc4.c +++ b/components/wpa_supplicant/src/crypto/rc4.c @@ -15,7 +15,7 @@ #include "utils/includes.h" #include "utils/common.h" -#include "crypto/crypto.h" +#include "crypto.h" #define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0) diff --git a/components/wpa_supplicant/src/crypto/sha1-internal.c b/components/wpa_supplicant/src/crypto/sha1-internal.c index 3bcd88116c..9210af03fe 100644 --- a/components/wpa_supplicant/src/crypto/sha1-internal.c +++ b/components/wpa_supplicant/src/crypto/sha1-internal.c @@ -15,10 +15,10 @@ #include "utils/includes.h" #include "utils/common.h" -#include "crypto/sha1.h" -#include "crypto/sha1_i.h" -#include "crypto/md5.h" -#include "crypto/crypto.h" +#include "sha1.h" +#include "sha1_i.h" +#include "md5.h" +#include "crypto.h" #ifdef USE_MBEDTLS_CRYPTO #include "mbedtls/sha1.h" diff --git a/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c b/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c index b842a57d4e..79e1bc382c 100644 --- a/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c +++ b/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c @@ -14,9 +14,9 @@ #include "utils/includes.h" #include "utils/common.h" -#include "crypto/sha1.h" -#include "crypto/md5.h" -#include "crypto/crypto.h" +#include "sha1.h" +#include "md5.h" +#include "crypto.h" #ifdef USE_MBEDTLS_CRYPTO #include "mbedtls/pkcs5.h" diff --git a/components/wpa_supplicant/src/crypto/sha1.c b/components/wpa_supplicant/src/crypto/sha1.c index 5b228292b2..27cf58b685 100644 --- a/components/wpa_supplicant/src/crypto/sha1.c +++ b/components/wpa_supplicant/src/crypto/sha1.c @@ -15,8 +15,8 @@ #include "utils/includes.h" #include "utils/common.h" -#include "crypto/sha1.h" -#include "crypto/crypto.h" +#include "sha1.h" +#include "crypto.h" /** diff --git a/components/wpa_supplicant/include/crypto/sha1.h b/components/wpa_supplicant/src/crypto/sha1.h similarity index 100% rename from components/wpa_supplicant/include/crypto/sha1.h rename to components/wpa_supplicant/src/crypto/sha1.h diff --git a/components/wpa_supplicant/src/crypto/sha256-internal.c b/components/wpa_supplicant/src/crypto/sha256-internal.c index df0706b5c1..d6af5b5e9a 100644 --- a/components/wpa_supplicant/src/crypto/sha256-internal.c +++ b/components/wpa_supplicant/src/crypto/sha256-internal.c @@ -33,8 +33,8 @@ #ifdef USE_MBEDTLS_CRYPTO #include "mbedtls/sha256.h" #else /* USE_MBEDTLS_CRYPTO */ -#include "crypto/sha256.h" -#include "crypto/crypto.h" +#include "sha256.h" +#include "crypto.h" #endif /* USE_MBEDTLS_CRYPTO */ #ifdef USE_MBEDTLS_CRYPTO diff --git a/components/wpa_supplicant/src/crypto/sha256.c b/components/wpa_supplicant/src/crypto/sha256.c index 6380897e42..3e955b4d47 100644 --- a/components/wpa_supplicant/src/crypto/sha256.c +++ b/components/wpa_supplicant/src/crypto/sha256.c @@ -30,8 +30,8 @@ #include "utils/includes.h" #include "utils/common.h" -#include "crypto/sha256.h" -#include "crypto/crypto.h" +#include "sha256.h" +#include "crypto.h" /** diff --git a/components/wpa_supplicant/include/crypto/sha256.h b/components/wpa_supplicant/src/crypto/sha256.h similarity index 100% rename from components/wpa_supplicant/include/crypto/sha256.h rename to components/wpa_supplicant/src/crypto/sha256.h diff --git a/components/wpa_supplicant/src/eap_peer/eap_ttls.c b/components/wpa_supplicant/src/eap_peer/eap_ttls.c index fb5515913e..b014dbd395 100644 --- a/components/wpa_supplicant/src/eap_peer/eap_ttls.c +++ b/components/wpa_supplicant/src/eap_peer/eap_ttls.c @@ -10,7 +10,6 @@ #ifdef EAP_TTLS #include "utils/common.h" -#include "crypto/ms_funcs.h" #include "crypto/sha1.h" #include "tls/tls.h" #include "eap_peer/eap.h" diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c index 6f37b18500..51f9e40f46 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c @@ -29,7 +29,6 @@ #include "crypto/crypto.h" #include "crypto/sha1.h" #include "crypto/aes_wrap.h" -#include "crypto/wepkey.h" #include "esp_wifi_driver.h" #include "esp_private/wifi.h" diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.c b/components/wpa_supplicant/src/rsn_supp/wpa.c index 2ce7bbebe5..2f01471264 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -26,7 +26,6 @@ #include "crypto/crypto.h" #include "crypto/sha1.h" #include "crypto/aes_wrap.h" -#include "crypto/wepkey.h" /** * eapol_sm_notify_eap_success - Notification of external EAP success trigger diff --git a/components/wpa_supplicant/src/wps/wps.c b/components/wpa_supplicant/src/wps/wps.c index 1700f0f4b1..b19e187a46 100644 --- a/components/wpa_supplicant/src/wps/wps.c +++ b/components/wpa_supplicant/src/wps/wps.c @@ -14,8 +14,6 @@ #include "utils/wpa_debug.h" #include "common/ieee802_11_defs.h" -#include "crypto/dh_group5.h" - #include "wps/wps_i.h" #include "wps/wps_dev_attr.h" diff --git a/components/wpa_supplicant/src/wps/wps_attr_build.c b/components/wpa_supplicant/src/wps/wps_attr_build.c index bd2aa5e947..437c92b69a 100644 --- a/components/wpa_supplicant/src/wps/wps_attr_build.c +++ b/components/wpa_supplicant/src/wps/wps_attr_build.c @@ -11,9 +11,9 @@ #include "crypto/aes_wrap.h" #include "crypto/crypto.h" -#include "crypto/dh_group5.h" #include "crypto/sha256.h" #include "crypto/random.h" +#include "crypto/dh_group5.h" #include "common/ieee802_11_defs.h" #include "wps/wps_i.h" diff --git a/components/wpa_supplicant/src/wps/wps_common.c b/components/wpa_supplicant/src/wps/wps_common.c index e37a35b273..ead31af3e0 100644 --- a/components/wpa_supplicant/src/wps/wps_common.c +++ b/components/wpa_supplicant/src/wps/wps_common.c @@ -12,9 +12,9 @@ #include "crypto/aes_wrap.h" #include "crypto/crypto.h" -#include "crypto/dh_group5.h" #include "crypto/sha1.h" #include "crypto/sha256.h" +#include "crypto/dh_group5.h" #include "crypto/random.h" #include "wps/wps_i.h" From ab406f8429ac8ca58bc7317915e56b0f7b2fab3b Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Tue, 9 Apr 2019 16:35:58 +0800 Subject: [PATCH 483/486] zh_CN translation of bootloader document --- docs/en/api-guides/bootloader.rst | 1 + docs/zh_CN/api-guides/bootloader.rst | 60 +++++++++++++++++++++++++++- docs/zh_CN/api-guides/index.rst | 2 +- 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/docs/en/api-guides/bootloader.rst b/docs/en/api-guides/bootloader.rst index 2671b353fc..c699ac2fd1 100644 --- a/docs/en/api-guides/bootloader.rst +++ b/docs/en/api-guides/bootloader.rst @@ -1,5 +1,6 @@ Bootloader ===================== +:link_to_translation:`zh_CN:[中文]` Bootloader performs the following functions: diff --git a/docs/zh_CN/api-guides/bootloader.rst b/docs/zh_CN/api-guides/bootloader.rst index 5609a8e308..86ee7efa8a 100644 --- a/docs/zh_CN/api-guides/bootloader.rst +++ b/docs/zh_CN/api-guides/bootloader.rst @@ -1 +1,59 @@ -.. include:: ../../en/api-guides/bootloader.rst \ No newline at end of file +引导加载程序(Bootloader) +========================== +:link_to_translation:`en:[English]` + +引导加载程序(Bootloader)主要执行以下任务: + +1. 内部模块的最小化初始配置; +2. 根据分区表和 ota_data(如果存在)选择需要引导的应用程序(app)分区; +3. 将此应用程序映像加载到 RAM(IRAM 和 DRAM)中,最后把控制权转交给应用程序。 + +引导加载程序位于 Flash 的 `0x1000` 偏移地址处。 + +恢复出厂设置 +------------ +用户可以编写一个基本的工作固件,然后将其加载到工厂分区(factory)中。 + +接下来,通过 OTA(空中升级)更新固件,更新后的固件会被保存到某个 OTA app 分区中,OTA 数据分区也会做相应更新以指示从该分区引导应用程序。 + +如果你希望回滚到出厂固件并清除设置,则需要设置 :ref:`CONFIG_BOOTLOADER_FACTORY_RESET`。 + +出厂重置机制允许将设备重置为出厂模式: + +- 清除一个或多个数据分区。 +- 从工厂分区启动。 + +:ref:`CONFIG_BOOTLOADER_DATA_FACTORY_RESET` - 允许用户选择在恢复出厂设置时需要删除的数据分区。可以通过逗号来分隔多个分区的名字,并适当增加空格以便阅读(例如 "nvs, phy_init, nvs_custom, ...")。请确保此处指定的名称和分区表中的名称相同,且不含有 “app” 类型的分区。 + +:ref:`CONFIG_BOOTLOADER_OTA_DATA_ERASE` - 恢复出厂模式后,设备会从工厂分区启动,OTA 数据分区会被清除。 + +:ref:`CONFIG_BOOTLOADER_NUM_PIN_FACTORY_RESET`- 设置用于触发出厂重置的 GPIO 编号,必须在芯片复位时将此 GPIO 拉低才能触发出厂重置事件。 + +:ref:`CONFIG_BOOTLOADER_HOLD_TIME_GPIO`- 设置进入重置或测试模式所需要的保持时间(默认为 5 秒)。设备复位后,GPIO 必须在这段时间内持续保持低电平,然后才会执行出厂重置或引导测试分区。 + +示例分区表如下:: + + # Name, Type, SubType, Offset, Size, Flags + # 注意,如果你增大了引导加载程序的大小,请确保更新偏移量,避免和其它分区发生重叠 + nvs, data, nvs, 0x9000, 0x4000 + otadata, data, ota, 0xd000, 0x2000 + phy_init, data, phy, 0xf000, 0x1000 + factory, 0, 0, 0x10000, 1M + test, 0, test, , 512K + ota_0, 0, ota_0, , 512K + ota_1, 0, ota_1, , 512K + +从测试固件启动 +-------------- +用户可以编写在生产环境中测试用的特殊固件,然后在需要的时候运行。此时需要在分区表中专门申请一块分区用于保存该测试固件(详情请参阅 :doc:`分区表 `)。如果想要触发测试固件,还需要设置 :ref:`CONFIG_BOOTLOADER_APP_TEST`。 + +:ref:`CONFIG_BOOTLOADER_NUM_PIN_APP_TEST` - 设置引导测试分区的 GPIO 管脚编号,该 GPIO 会被配置为输入模式,并且会使能内部上拉电阻。若想触发测试固件,该 GPIO 必须在芯片复位时拉低。设备重启时如果该 GPIO 没有被激活(即处于高电平状态),那么会加载常规配置的应用程序(可能位于工厂分区或者 OTA 分区)。 + +:ref:`CONFIG_BOOTLOADER_HOLD_TIME_GPIO` - 设置进入重置或测试模式所需要的保持时间(默认为 5 秒)。设备复位后,GPIO 必须在这段时间内持续保持低电平,然后才会执行出厂重置或引导测试分区。 + +自定义引导程序 +-------------- +用户可以重写当前的引导加载程序,具体做法是,复制 `/esp-idf/components/bootloader` 文件夹到项目目录中,然后编辑 `/your_project/components/bootloader/subproject/ain/bootloader_main.c` 文件。 + +在引导加载程序的代码中,用户不可以使用驱动和其他组件提供的函数,如果确实需要,请将该功能的实现部分放在 bootloader 目录中(注意,这会增加引导程序的大小)。监视生成的引导程序的大小是有必要的,因为它可能会与内存中的分区表发生重叠而损坏固件。目前,引导程序被限制在了分区表之前的区域(分区表位于 `0x8000` 地址处)。 + diff --git a/docs/zh_CN/api-guides/index.rst b/docs/zh_CN/api-guides/index.rst index c3a1d10035..c00fa330c0 100644 --- a/docs/zh_CN/api-guides/index.rst +++ b/docs/zh_CN/api-guides/index.rst @@ -18,7 +18,7 @@ API 指南 Thread Local Storage High Level Interrupts JTAG 调试 - Bootloader + 引导加载程序 分区表 Secure Boot <../security/secure-boot> ULP 协处理器 From 685c9cc8672cc716b5ebd6f1cb568a9ccc727001 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 16 Aug 2019 20:59:04 +1000 Subject: [PATCH 484/486] esp32sbeta: Add timer_ll.h --- .../soc/esp32s2beta/include/hal/timer_ll.h | 285 ++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 components/soc/esp32s2beta/include/hal/timer_ll.h diff --git a/components/soc/esp32s2beta/include/hal/timer_ll.h b/components/soc/esp32s2beta/include/hal/timer_ll.h new file mode 100644 index 0000000000..20805337a1 --- /dev/null +++ b/components/soc/esp32s2beta/include/hal/timer_ll.h @@ -0,0 +1,285 @@ +// Copyright 2015-2019 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. + +// The LL layer for Timer Group register operations. +// Note that most of the register operations in this layer are non-atomic operations. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "hal/timer_types.h" +#include "soc/timer_periph.h" + +//Helper macro to get corresponding interrupt of a timer +#define TIMER_LL_GET_INTR(TIMER_IDX) ((TIMER_IDX)==TIMER_0? TIMER_INTR_T0: TIMER_INTR_T1) + +#define TIMER_LL_GET_HW(TIMER_GROUP) ((TIMER_GROUP)==0? &TIMERG0: &TIMERG1) + +_Static_assert(TIMER_INTR_T0 == TIMG_T0_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); +_Static_assert(TIMER_INTR_T1 == TIMG_T1_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); +_Static_assert(TIMER_INTR_WDT == TIMG_WDT_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); + +/** + * @brief Enable timer interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param intr_mask Interrupt enable mask + * + * @return None + */ +static inline void timer_ll_intr_enable(timg_dev_t *hw, timer_intr_t intr_mask) +{ + hw->int_ena.val |= intr_mask; +} + +/** + * @brief Disable timer interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param intr_mask Interrupt disable mask + * + * @return None + */ +static inline void timer_ll_intr_disable(timg_dev_t *hw, timer_intr_t intr_mask) +{ + hw->int_ena.val &= (~intr_mask); +} + +/** + * @brief Get timer interrupt status. + * + * @param hw Beginning address of the peripheral registers. + * + * @return Masked interrupt status + */ +static inline timer_intr_t timer_ll_intr_status_get(timg_dev_t *hw) +{ + return hw->int_raw.val; +} + +/** + * @brief Clear timer interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param intr_mask Interrupt mask to clear + * + * @return None + */ +static inline void timer_ll_intr_status_clear(timg_dev_t *hw, timer_intr_t intr_mask) +{ + hw->int_clr.val = intr_mask; +} + +/** + * @brief Get counter vaule from time-base counter + * + * @param hw Beginning address of the peripheral registers. + * @param timer_num The timer number + * @param timer_val Pointer to accept the counter value + * + * @return None + */ +static inline void timer_ll_get_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *timer_val) +{ + hw->hw_timer[timer_num].update.update = 1; + *timer_val = ((uint64_t) hw->hw_timer[timer_num].cnt_high << 32) | (hw->hw_timer[timer_num].cnt_low); +} + +/** + * @brief Set counter status, enable or disable counter. + * + * @param hw Beginning address of the peripheral registers. + * @param timer_num The timer number + * @param counter_en Counter enable status + * + * @return None + */ +static inline void timer_ll_set_counter_enable(timg_dev_t *hw, timer_idx_t timer_num, timer_start_t counter_en) +{ + hw->hw_timer[timer_num].config.enable = counter_en; +} + +/** + * @brief Get auto reload mode. + * + * @param hw Beginning address of the peripheral registers. + * @param timer_num The timer number + * @param reload Pointer to accept the auto reload mode + * + * @return None + */ +static inline bool timer_ll_get_auto_reload(timg_dev_t *hw, timer_idx_t timer_num) +{ + return hw->hw_timer[timer_num].config.autoreload; +} + +/** + * @brief Set the counter value to trigger the alarm. + * + * @param hw Beginning address of the peripheral registers. + * @param timer_num The timer number + * @param alarm_value Counter value to trigger the alarm + * + * @return None + */ +static inline void timer_ll_set_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t alarm_value) +{ + hw->hw_timer[timer_num].alarm_high = (uint32_t) (alarm_value >> 32); + hw->hw_timer[timer_num].alarm_low = (uint32_t) alarm_value; +} + +/** + * @brief Get the counter value to trigger the alarm. + * + * @param hw Beginning address of the peripheral registers. + * @param timer_num The timer number + * @param alarm_value Pointer to accept the counter value to trigger the alarm + * + * @return None + */ +static inline void timer_ll_get_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *alarm_value) +{ + *alarm_value = ((uint64_t) hw->hw_timer[timer_num].alarm_high << 32) | (hw->hw_timer[timer_num].alarm_low); +} + +/** + * @brief Set the alarm status, enable or disable the alarm. + * + * @param hw Beginning address of the peripheral registers. + * @param timer_num The timer number + * @param alarm_en true to enable, false to disable + * + * @return None + */ +static inline void timer_ll_set_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num, bool alarm_en) +{ + hw->hw_timer[timer_num].config.alarm_en = alarm_en; +} + +/** + * @brief Get the alarm status. + * + * @param hw Beginning address of the peripheral registers. + * @param timer_num The timer number + * @param alarm_en Pointer to accept the alarm status + * + * @return None + */ +static inline void timer_ll_get_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num, bool *alarm_en) +{ + *alarm_en = hw->hw_timer[timer_num].config.alarm_en; +} + +/* WDT operations */ + +/** + * Unlock/lock the WDT register in case of mis-operations. + * + * @param hw Beginning address of the peripheral registers. + * @param protect true to lock, false to unlock before operations. + */ + +FORCE_INLINE_ATTR void timer_ll_wdt_set_protect(timg_dev_t* hw, bool protect) +{ + hw->wdt_wprotect=(protect? 0: TIMG_WDT_WKEY_VALUE); +} + +/** + * Initialize WDT. + * + * @param hw Beginning address of the peripheral registers. + * + * @note Call ``timer_ll_wdt_set_protect first`` + */ +FORCE_INLINE_ATTR void timer_ll_wdt_init(timg_dev_t* hw) +{ + hw->wdt_config0.sys_reset_length=7; //3.2uS + hw->wdt_config0.cpu_reset_length=7; //3.2uS + //currently only level interrupt is supported + hw->wdt_config0.level_int_en = 1; + hw->wdt_config0.edge_int_en = 0; +} + +FORCE_INLINE_ATTR void timer_ll_wdt_set_tick(timg_dev_t* hw, int tick_time_us) +{ + hw->wdt_config1.clk_prescale=80*tick_time_us; +} + +FORCE_INLINE_ATTR void timer_ll_wdt_feed(timg_dev_t* hw) +{ + hw->wdt_feed = 1; +} + +FORCE_INLINE_ATTR void timer_ll_wdt_set_timeout(timg_dev_t* hw, int stage, uint32_t timeout_tick) +{ + switch (stage) { + case 0: + hw->wdt_config2=timeout_tick; + break; + case 1: + hw->wdt_config3=timeout_tick; + break; + case 2: + hw->wdt_config4=timeout_tick; + break; + case 3: + hw->wdt_config5=timeout_tick; + break; + default: + abort(); + } +} + +_Static_assert(TIMER_WDT_OFF == TIMG_WDT_STG_SEL_OFF, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t"); +_Static_assert(TIMER_WDT_INT == TIMG_WDT_STG_SEL_INT, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t"); +_Static_assert(TIMER_WDT_RESET_CPU == TIMG_WDT_STG_SEL_RESET_CPU, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t"); +_Static_assert(TIMER_WDT_RESET_SYSTEM == TIMG_WDT_STG_SEL_RESET_SYSTEM, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t"); + +FORCE_INLINE_ATTR void timer_ll_wdt_set_timeout_behavior(timg_dev_t* hw, int stage, timer_wdt_behavior_t behavior) +{ + switch (stage) { + case 0: + hw->wdt_config0.stg0 = behavior; + break; + case 1: + hw->wdt_config0.stg1 = behavior; + break; + case 2: + hw->wdt_config0.stg2 = behavior; + break; + case 3: + hw->wdt_config0.stg3 = behavior; + break; + default: + abort(); + } +} + +FORCE_INLINE_ATTR void timer_ll_wdt_set_enable(timg_dev_t* hw, bool enable) +{ + hw->wdt_config0.en = enable; +} + +FORCE_INLINE_ATTR void timer_ll_wdt_flashboot_en(timg_dev_t* hw, bool enable) +{ + hw->wdt_config0.flashboot_mod_en = enable; +} + + +#ifdef __cplusplus +} +#endif From 2085845c80a12d96bf60d4d660e37bdd929c8d37 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 19 Aug 2019 15:02:34 +1000 Subject: [PATCH 485/486] freertos: Have ESP32S2-Beta target select FREERTOS_UNICORE directly --- Kconfig | 1 + components/freertos/Kconfig | 7 ------- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/Kconfig b/Kconfig index 2987412361..0fcb5e1e5e 100644 --- a/Kconfig +++ b/Kconfig @@ -38,6 +38,7 @@ mainmenu "Espressif IoT Development Framework Configuration" bool default "y" if IDF_TARGET="esp32s2beta" default "n" + select FREERTOS_UNICORE menu "SDK tool configuration" config SDK_TOOLPREFIX diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index 06461b9198..c6a4d36b31 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -1,12 +1,5 @@ menu "FreeRTOS" - config FREERTOS_SINGLE_CORE_ONLY - # invisible config item to always select FREERTOS_UNICORE on single core IDF_TARGET - bool - default y - depends on IDF_TARGET_ESP32S2BETA - select FREERTOS_UNICORE - config FREERTOS_UNICORE # This config variable is also checked in the ESP32 startup code, not only in FreeRTOS. bool "Run FreeRTOS only on first core" From 80f1c13fd72d8c0f0de60a7bf1f03de6f75c95b6 Mon Sep 17 00:00:00 2001 From: Xia Xiaotian Date: Tue, 20 Aug 2019 14:43:02 +0800 Subject: [PATCH 486/486] esp_wifi: update WiFi library to support esp32s2beta --- components/esp_wifi/lib_esp32 | 2 +- components/esp_wifi/lib_esp32s2beta | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index 09ed80c2b0..75c9095783 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit 09ed80c2b047ae5bb41ddbfb9be44ec2bc71fedd +Subproject commit 75c9095783d095f28c6dab283f314d2b13918713 diff --git a/components/esp_wifi/lib_esp32s2beta b/components/esp_wifi/lib_esp32s2beta index 402af2133f..ef025b8fd5 160000 --- a/components/esp_wifi/lib_esp32s2beta +++ b/components/esp_wifi/lib_esp32s2beta @@ -1 +1 @@ -Subproject commit 402af2133f9588e82aab84fd5c9737caa01a272f +Subproject commit ef025b8fd540f1fc9b6d2665684be033724b46c8